From 375587f4b29039d86880030c6ab9a135e0342567 Mon Sep 17 00:00:00 2001
From: RISCi_ATOM <bob@bobcall.me>
Date: Fri, 16 Dec 2016 23:14:08 -0500
Subject: [PATCH] First git repo commit for the libreCMC project

---
 .gitattributes                                |     1 +
 .gitignore                                    |    26 +
 BSDmakefile                                   |     7 +
 Config.in                                     |    34 +
 LICENSE                                       |   340 +
 Makefile                                      |    96 +
 config/Config-build.in                        |   293 +
 config/Config-devel.in                        |   112 +
 config/Config-images.in                       |   269 +
 config/Config-kernel.in                       |   739 +
 feeds.conf.default                            |     0
 include/autotools.mk                          |   170 +
 include/cmake.mk                              |   109 +
 include/debug.mk                              |    51 +
 include/depends.mk                            |    48 +
 include/device_table.txt                      |     5 +
 include/download.mk                           |   196 +
 include/feeds.mk                              |    56 +
 include/hardening.mk                          |    50 +
 include/host-build.mk                         |   210 +
 include/host.mk                               |    51 +
 include/image-commands.mk                     |   192 +
 include/image-legacy.mk                       |    92 +
 include/image.mk                              |   562 +
 include/kernel-build.mk                       |   177 +
 include/kernel-defaults.mk                    |   184 +
 include/kernel-version.mk                     |    25 +
 include/kernel.mk                             |   244 +
 include/netfilter.mk                          |   376 +
 include/nls.mk                                |    40 +
 include/package-bin.mk                        |    33 +
 include/package-defaults.mk                   |   162 +
 include/package-dumpinfo.mk                   |    91 +
 include/package-ipkg.mk                       |   238 +
 include/package-seccomp.mk                    |    15 +
 include/package.mk                            |   320 +
 include/prereq-build.mk                       |   176 +
 include/prereq.mk                             |   108 +
 include/quilt.mk                              |   171 +
 include/rootfs.mk                             |    80 +
 include/scan.awk                              |    19 +
 include/scan.mk                               |   104 +
 include/scons.mk                              |    23 +
 include/shell.sh                              |    37 +
 include/site/aarch64                          |    30 +
 include/site/aarch64_be                       |    30 +
 include/site/arc                              |    30 +
 include/site/arm                              |    30 +
 include/site/armeb                            |    30 +
 include/site/i386                             |     3 +
 include/site/i486                             |    30 +
 include/site/i686                             |     3 +
 include/site/linux                            |    78 +
 include/site/m68k                             |    28 +
 include/site/mips                             |    30 +
 include/site/mips64                           |    30 +
 include/site/mips64el                         |    30 +
 include/site/mipsel                           |    30 +
 include/site/powerpc                          |    30 +
 include/site/sparc                            |    30 +
 include/site/x86_64                           |    30 +
 include/subdir.mk                             |    92 +
 include/target.mk                             |   306 +
 include/toolchain-build.mk                    |    25 +
 include/toplevel.mk                           |   235 +
 include/uclibc++.mk                           |    16 +
 include/unpack.mk                             |    81 +
 include/verbose.mk                            |    67 +
 include/version.mk                            |   112 +
 package/Makefile                              |   127 +
 package/base-files/Makefile                   |   177 +
 package/base-files/files/bin/board_detect     |    14 +
 package/base-files/files/bin/config_generate  |   437 +
 package/base-files/files/bin/ipcalc.sh        |    71 +
 package/base-files/files/etc/banner           |     9 +
 package/base-files/files/etc/banner.failsafe  |    13 +
 .../files/etc/board.d/99-default_network      |    17 +
 package/base-files/files/etc/device_info      |     4 +
 package/base-files/files/etc/diag.sh          |     4 +
 package/base-files/files/etc/fstab            |     1 +
 package/base-files/files/etc/group            |    10 +
 package/base-files/files/etc/hosts            |     5 +
 .../files/etc/hotplug.d/net/00-sysctl         |     9 +
 package/base-files/files/etc/init.d/boot      |    51 +
 package/base-files/files/etc/init.d/done      |    17 +
 .../base-files/files/etc/init.d/gpio_switch   |    42 +
 package/base-files/files/etc/init.d/led       |   134 +
 package/base-files/files/etc/init.d/sysctl    |    25 +
 .../base-files/files/etc/init.d/sysfixtime    |    34 +
 package/base-files/files/etc/init.d/system    |    50 +
 package/base-files/files/etc/init.d/umount    |     8 +
 .../base-files/files/etc/init.d/urandom_seed  |    12 +
 package/base-files/files/etc/inittab          |     3 +
 .../base-files/files/etc/iproute2/rt_tables   |    12 +
 package/base-files/files/etc/openwrt_release  |     7 +
 package/base-files/files/etc/openwrt_version  |     1 +
 package/base-files/files/etc/os-release       |     1 +
 package/base-files/files/etc/passwd           |     5 +
 package/base-files/files/etc/preinit          |    29 +
 package/base-files/files/etc/profile          |    52 +
 package/base-files/files/etc/protocols        |    57 +
 .../base-files/files/etc/rc.button/failsafe   |     5 +
 package/base-files/files/etc/rc.button/power  |     7 +
 package/base-files/files/etc/rc.button/reset  |    31 +
 package/base-files/files/etc/rc.button/rfkill |    32 +
 package/base-files/files/etc/rc.common        |   145 +
 package/base-files/files/etc/rc.local         |     4 +
 package/base-files/files/etc/services         |   171 +
 package/base-files/files/etc/shadow           |     5 +
 package/base-files/files/etc/shells           |     1 +
 package/base-files/files/etc/sysctl.conf      |    30 +
 .../base-files/files/etc/sysctl.d/local.conf  |     1 +
 package/base-files/files/etc/sysupgrade.conf  |     5 +
 .../files/etc/uci-defaults/10_migrate-shadow  |    12 +
 .../files/etc/uci-defaults/11_migrate-sysctl  |    16 +
 .../etc/uci-defaults/12_network-generate-ula  |    15 +
 .../files/etc/uci-defaults/13_fix_group_user  |    11 +
 package/base-files/files/lib/functions.sh     |   351 +
 .../base-files/files/lib/functions/leds.sh    |    61 +
 .../base-files/files/lib/functions/network.sh |   268 +
 .../base-files/files/lib/functions/preinit.sh |    88 +
 .../base-files/files/lib/functions/service.sh |   103 +
 .../base-files/files/lib/functions/system.sh  |   129 +
 .../files/lib/functions/uci-defaults.sh       |   640 +
 .../files/lib/preinit/02_default_set_state    |     7 +
 .../files/lib/preinit/10_indicate_failsafe    |    18 +
 .../files/lib/preinit/10_indicate_preinit     |   154 +
 .../base-files/files/lib/preinit/10_sysinfo   |    10 +
 .../files/lib/preinit/30_failsafe_wait        |   100 +
 .../files/lib/preinit/40_run_failsafe_hook    |    13 +
 .../lib/preinit/50_indicate_regular_preinit   |    10 +
 .../files/lib/preinit/70_initramfs_test       |    13 +
 .../files/lib/preinit/80_mount_root           |    15 +
 .../files/lib/preinit/81_urandom_seed         |    24 +
 .../files/lib/preinit/99_10_failsafe_login    |    18 +
 .../files/lib/preinit/99_10_run_init          |     9 +
 .../base-files/files/lib/upgrade/common.sh    |   253 +
 .../base-files/files/lib/upgrade/fwtool.sh    |    43 +
 .../lib/upgrade/keep.d/base-files-essential   |    10 +
 package/base-files/files/rom/note             |     3 +
 package/base-files/files/sbin/firstboot       |     3 +
 package/base-files/files/sbin/hotplug-call    |    18 +
 package/base-files/files/sbin/led.sh          |    25 +
 package/base-files/files/sbin/sysupgrade      |   245 +
 package/base-files/files/sbin/urandom_seed    |    20 +
 package/base-files/files/sbin/wifi            |   239 +
 package/base-files/files/usr/lib/os-release   |    17 +
 package/base-files/files/usr/libexec/login.sh |     5 +
 package/base-files/image-config.in            |   324 +
 package/boot/fconfig/Makefile                 |    46 +
 package/boot/grub2/Makefile                   |    84 +
 .../grub2/patches/100-grub_setup_root.patch   |   118 +
 .../boot/grub2/patches/100-musl-compat.patch  |    26 +
 .../grub2/patches/200-fix-gets-removal.patch  |    16 +
 .../grub2/patches/210-fix_serial_rtscts.patch |    14 +
 package/boot/kexec-tools/Config.in            |    31 +
 package/boot/kexec-tools/Makefile             |    87 +
 .../0001-Fix-zlib-lzma-decompression.patch    |   171 +
 ...ly-necessary-quotes-to-result-of-mac.patch |    52 +
 ...r-warning-on-printing-64-bit-integer.patch |    35 +
 .../0004-mips-remove-unused-variable.patch    |    30 +
 ...rning-about-implicit-type-conversion.patch |    30 +
 package/boot/uboot-ar71xx/Makefile            |    95 +
 .../files/board/zyxel/nbg460n/Makefile        |    46 +
 .../files/board/zyxel/nbg460n/config.mk       |     1 +
 .../files/board/zyxel/nbg460n/lowlevel_init.S |    39 +
 .../files/board/zyxel/nbg460n/nbg460n.c       |    96 +
 .../files/board/zyxel/nbg460n/u-boot.lds      |    42 +
 .../files/cpu/mips/ar71xx_serial.c            |   177 +
 .../uboot-ar71xx/files/drivers/net/ag71xx.c   |   809 +
 .../uboot-ar71xx/files/drivers/net/ag71xx.h   |   374 +
 .../files/drivers/net/phy/rtl8366.h           |   188 +
 .../files/drivers/net/phy/rtl8366_mii.c       |   786 +
 .../files/drivers/spi/ar71xx_spi.c            |   191 +
 .../files/include/asm-mips/ar71xx.h           |   515 +
 .../files/include/asm-mips/ar71xx_gpio.h      |    65 +
 .../files/include/configs/nbg460n.h           |   136 +
 ...oot-build-support-using-SOURCE_DATE_.patch |    82 +
 ...le-Reproducible-U-Boot-build-support.patch |    31 +
 .../uboot-ar71xx/patches/001-ar71xx.patch     |    26 +
 .../uboot-ar71xx/patches/002-ar71xx-spi.patch |    11 +
 .../patches/010-enet-ag71xx.patch             |    22 +
 .../patches/011-switch-rtl8366sr.patch        |    28 +
 .../patches/020-freebsd-compat.patch          |    11 +
 .../patches/021-darwin_compat.patch           |    23 +
 .../patches/022-getline_backport.patch        |    21 +
 .../patches/030-no_examples.patch             |    13 +
 .../patches/040-no_extern_inline.patch        |   112 +
 .../patches/041-no_weak_alias.patch           |    12 +
 package/boot/uboot-envtools/Config.in         |     9 +
 package/boot/uboot-envtools/Makefile          |   121 +
 package/boot/uboot-envtools/files/ar71xx      |    72 +
 package/boot/uboot-envtools/files/cns3xxx     |    28 +
 package/boot/uboot-envtools/files/imx6        |    36 +
 package/boot/uboot-envtools/files/ipq         |    29 +
 package/boot/uboot-envtools/files/kirkwood    |    34 +
 package/boot/uboot-envtools/files/lantiq      |    39 +
 package/boot/uboot-envtools/files/mvebu       |    32 +
 package/boot/uboot-envtools/files/mxs         |    26 +
 package/boot/uboot-envtools/files/oxnas       |    28 +
 package/boot/uboot-envtools/files/ramips      |    37 +
 .../uboot-envtools/files/uboot-envtools.sh    |    36 +
 .../uboot-envtools/patches/001-compile.patch  |    13 +
 .../patches/200-fw_env_no_aes.patch           |    38 +
 .../300-support-env-in-ubivol-chardev.patch   |   163 +
 .../patches/400-u-boot-2015.10-stdint.patch   |    13 +
 package/boot/uboot-sunxi/Makefile             |   188 +
 .../patches/001-use-dtc-in-kernel.patch       |    11 +
 .../patches/002-add-olimex-a13-som.patch      |    21 +
 .../003-add-theobroma-a31-pangolin.patch      |   385 +
 .../010-dt-sync-files-with-kernel.patch       |  1403 +
 .../011-dt-sync-dts-files-with-kernel.patch   |  7211 +++++
 .../012-sun6i-fix-clock_twi_onoff.patch       |    38 +
 .../patches/013-enable-realtek-phy.patch      |    24 +
 .../patches/014-fix-gmac-init.patch           |   127 +
 .../015-fix-2nd-usb-ctrler-on-sun47i.patch    |    78 +
 .../patches/016-spl-print-mmc-slot.patch      |    31 +
 ...17-usb-add-support-for-usb3-vbus-pin.patch |    39 +
 ...8-usb-specify-vbus-pins-on-orangepis.patch |    31 +
 ...19-sid-add-efuse-support-for-h3-a83t.patch |    33 +
 ...-boot-display-board-model-on-startup.patch |    23 +
 ...1-sun6i-sync-PLL1-multdiv-with-Boot1.patch |    32 +
 .../093-sun6i-fix-PLL-LDO-voltselect.patch    |    70 +
 .../100-sun6i-alternate-on-UART2.patch        |    16 +
 .../101-sun6i-support-console-on-UART2.patch  |    30 +
 ...2-sunxi-make_CONS_INDEX-configurable.patch |    23 +
 package/boot/uboot-sunxi/uEnv-default.txt     |     6 +
 package/boot/uboot-sunxi/uEnv-pangolin.txt    |     6 +
 package/boot/uboot-xburst/Makefile            |    89 +
 .../0001-qi_lb60-add-nand-spl-support.patch   |   894 +
 ...qi_lb60-add-software-usbboot-support.patch |   916 +
 .../patches/0003-add-mmc-support.patch        |  1664 +
 ...dd-more-boot-options-F1-F2-F3-F4-M-S.patch |   200 +
 .../0005-add-nanonote-lcd-support.patch       |   847 +
 .../patches/0006-enable-silent-console.patch  |    60 +
 package/boot/yamonenv/Makefile                |    40 +
 .../patches/001-yamonenv_mtd_partition.patch  |    11 +
 package/devel/binutils/Makefile               |   125 +
 package/devel/gdb-arc/Makefile                |    94 +
 .../patches/100-no_extern_inline.patch        |    32 +
 .../gdb-arc/patches/110-no_testsuite.patch    |    21 +
 .../120-fix-compile-flag-mismatch.patch       |    11 +
 package/devel/gdb/Makefile                    |    88 +
 .../001-gdb-pr14523-mips-signal-number.patch  |    16 +
 .../gdb/patches/002-remove-arguments.patch    |    16 +
 package/devel/gdb/patches/100-musl_fix.patch  |    53 +
 package/devel/perf/Makefile                   |    79 +
 package/devel/perf/musl-compat.h              |    43 +
 package/devel/perf/musl-include/asm/errno.h   |     8 +
 package/devel/perf/musl-include/string.h      |    18 +
 package/devel/strace/Makefile                 |    67 +
 ...00-workaround--pt-reg-collisions-ppc.patch |    19 +
 package/devel/trace-cmd/Makefile              |    65 +
 .../patches/110-mac80211_tracepoint.patch     |    24 +
 package/devel/valgrind/Makefile               |   179 +
 package/devel/valgrind/files/default.supp     |    42 +
 .../patches/100-fix_configure_check.patch     |    11 +
 .../patches/130-fix_arm_arch_detection.patch  |    17 +
 .../devel/valgrind/patches/200-musl_fix.patch |    45 +
 package/kernel/avila-wdt/Makefile             |    35 +
 package/kernel/avila-wdt/src/Makefile         |     1 +
 package/kernel/avila-wdt/src/avila-wdt.c      |   231 +
 package/kernel/button-hotplug/Makefile        |    50 +
 package/kernel/button-hotplug/src/Kconfig     |     2 +
 package/kernel/button-hotplug/src/Makefile    |     1 +
 .../button-hotplug/src/button-hotplug.c       |   343 +
 package/kernel/gpio-button-hotplug/Makefile   |    45 +
 .../kernel/gpio-button-hotplug/src/Makefile   |     1 +
 .../src/gpio-button-hotplug.c                 |   676 +
 package/kernel/i2c-gpio-custom/Makefile       |    48 +
 package/kernel/i2c-gpio-custom/src/Kconfig    |    10 +
 package/kernel/i2c-gpio-custom/src/Makefile   |     1 +
 .../i2c-gpio-custom/src/i2c-gpio-custom.c     |   202 +
 package/kernel/kmod-sched-cake/Makefile       |    44 +
 package/kernel/linux/Makefile                 |    67 +
 package/kernel/linux/modules/001-depends.mk   |    14 +
 package/kernel/linux/modules/block.mk         |   529 +
 package/kernel/linux/modules/can.mk           |   277 +
 package/kernel/linux/modules/crypto.mk        |   675 +
 package/kernel/linux/modules/firewire.mk      |    74 +
 package/kernel/linux/modules/fs.mk            |   506 +
 package/kernel/linux/modules/hwmon.mk         |   389 +
 package/kernel/linux/modules/i2c.mk           |   251 +
 package/kernel/linux/modules/input.mk         |   209 +
 package/kernel/linux/modules/leds.mk          |   147 +
 package/kernel/linux/modules/lib.mk           |   226 +
 package/kernel/linux/modules/netdevices.mk    |   865 +
 package/kernel/linux/modules/netfilter.mk     |   863 +
 package/kernel/linux/modules/netsupport.mk    |  1061 +
 package/kernel/linux/modules/nls.mk           |   307 +
 package/kernel/linux/modules/other.mk         |  1074 +
 package/kernel/linux/modules/pcmcia.mk        |    74 +
 package/kernel/linux/modules/sound.mk         |   521 +
 package/kernel/linux/modules/spi.mk           |   108 +
 package/kernel/linux/modules/usb.mk           |  1668 +
 package/kernel/linux/modules/video.mk         |   948 +
 package/kernel/linux/modules/virt.mk          |    73 +
 package/kernel/linux/modules/w1.mk            |   192 +
 package/kernel/linux/modules/wpan.mk          |   124 +
 package/kernel/mac80211/Makefile              |   413 +
 .../files/lib/netifd/wireless/mac80211.sh     |   757 +
 .../mac80211/files/lib/wifi/mac80211.sh       |   132 +
 .../kernel/mac80211/files/mac80211.hotplug    |     5 +
 package/kernel/mac80211/files/regdb.txt       |  1307 +
 .../mac80211/patches/000-fix_kconfig.patch    |    14 +
 .../mac80211/patches/001-fix_build.patch      |   167 +
 .../patches/002-change_allconfig.patch        |    64 +
 .../patches/003-remove_bogus_modparams.patch  |    34 +
 .../004-fix_duplicate_skcipher_backport.patch |    11 +
 .../005-backport_skb_get_hash_perturb.patch   |    22 +
 .../mac80211/patches/010-disable_rfkill.patch |    15 +
 .../patches/050-lib80211_option.patch         |    30 +
 .../patches/060-no_local_ssb_bcma.patch       |   132 +
 .../patches/070-ath_common_config.patch       |     9 +
 .../100-remove-cryptoapi-dependencies.patch   |   370 +
 .../110-mac80211_keep_keys_on_stop_ap.patch   |    12 +
 .../120-cfg80211_allow_perm_addr_change.patch |    43 +
 .../130-mac80211-hwsim-hrtimer-clock.patch    |    11 +
 .../patches/150-disable_addr_notifier.patch   |    67 +
 .../201-ath5k-WAR-for-AR71xx-PCI-bug.patch    |    38 +
 .../kernel/mac80211/patches/210-ap_scan.patch |    11 +
 ...using-mac80211-intermediate-software.patch |   953 +
 ...h9k-force-rx_clear-when-disabling-rx.patch |    35 +
 ...etries-for-powersave-response-frames.patch |    96 +
 ...erpret-requested-txpower-in-EIRP-dom.patch |    37 +
 ...0211-add-hdrlen-to-ieee80211_tx_data.patch |   219 +
 ...80211-add-NEED_ALIGNED4_SKBS-hw-flag.patch |   233 +
 ...l-Enable-STBC-and-LDPC-for-VHT-Rates.patch |    81 +
 ...ata-bit-in-PS-buffered-frame-release.patch |    50 +
 ...ntially-stale-EOSP-status-bit-in-int.patch |    22 +
 .../309-ath9k-report-tx-status-on-EOSP.patch  |    19 +
 ...fix-block-ack-window-tracking-issues.patch |   114 +
 ...1-Use-rhltable-instead-of-rhashtable.patch |   275 +
 ...equence-number-allocation-regression.patch |    37 +
 ...w-reset-AHB-WMAC-interface-on-AR91xx.patch |    25 +
 ..._hw-issue-external-reset-for-QCA955x.patch |   125 +
 ...ctral-scan-enable-bit-on-trigger-for.patch |    21 +
 ...implement-temperature-compensation-s.patch |   101 +
 ...-up-mismerge-of-ieee80211_tx_dequeue.patch |    35 +
 ...extra-memcpy-in-A-MSDU-head-creation.patch |    55 +
 .../320-mac80211-fix-A-MSDU-outer-SA-DA.patch |    73 +
 ...allow-using-AP_LINK_PS-with-mac80211.patch |    28 +
 ...211-update-A-MPDU-flag-on-tx-dequeue.patch |    30 +
 ...0211-remove-bogus-skb-vif-assignment.patch |    29 +
 ...-MSDU-aggregation-with-fast-xmit-txq.patch |    34 +
 ...hw_gpio_get-to-return-0-or-1-on-succ.patch |    29 +
 ...-net-add-ath9k-wireless-device-bindi.patch |    67 +
 ...er-to-get-the-string-representation-.patch |    42 +
 ...device-configuration-from-an-OF-node.patch |    85 +
 .../patches/400-ath_move_debug_code.patch     |    30 +
 .../patches/401-ath9k_blink_default.patch     |    11 +
 .../patches/402-ath_regd_optional.patch       |    84 +
 .../patches/403-world_regd_fixup.patch        |    84 +
 .../patches/404-regd_no_assoc_hints.patch     |    19 +
 .../mac80211/patches/405-ath_regd_us.patch    |    26 +
 .../patches/406-ath_relax_default_regd.patch  |    51 +
 .../410-ath9k_allow_adhoc_and_ap.patch        |    10 +
 .../411-ath5k_allow_adhoc_and_ap.patch        |    46 +
 .../patches/420-ath5k_disable_fast_cc.patch   |    18 +
 .../patches/430-add_ath5k_platform.patch      |    33 +
 ...add_platform_eeprom_support_to_ath5k.patch |    56 +
 .../patches/432-ath5k_add_pciids.patch        |    11 +
 .../440-ath5k_channel_bw_debugfs.patch        |   143 +
 .../patches/500-ath9k_eeprom_debugfs.patch    |    65 +
 .../mac80211/patches/501-ath9k_ahb_init.patch |    32 +
 .../510-ath9k_intr_mitigation_tweak.patch     |    18 +
 .../patches/511-ath9k_reduce_rxbuf.patch      |    11 +
 .../patches/512-ath9k_channelbw_debugfs.patch |   125 +
 .../patches/513-ath9k_add_pci_ids.patch       |    30 +
 .../522-mac80211_configure_antenna_gain.patch |   160 +
 .../patches/530-ath9k_extra_leds.patch        |   267 +
 .../531-ath9k_extra_platform_leds.patch       |    71 +
 .../540-ath9k_reduce_ani_interval.patch       |    11 +
 .../patches/541-ath9k_rx_dma_stop_check.patch |    28 +
 .../patches/542-ath9k_debugfs_diag.patch      |   139 +
 .../patches/543-ath9k_entropy_from_adc.patch  |   186 +
 ...544-ath9k-ar933x-usb-hang-workaround.patch |    79 +
 .../patches/545-ath9k_ani_ws_detect.patch     |   155 +
 .../patches/546-ath9k_platform_led_name.patch |    39 +
 .../patches/547-ath9k_led_defstate_fix.patch  |    29 +
 .../patches/548-ath9k_enable_gpio_chip.patch  |   234 +
 .../549-ath9k_enable_gpio_buttons.patch       |   149 +
 ...ne-for-the-EEPROM-eepmisc-endianness.patch |    95 +
 ...hat-the-AR9003-EEPROM-template-value.patch |    78 +
 ...rom_ops-callback-for-retrieving-the-.patch |   117 +
 ...prom_param-EEP_MINOR_REV-with-get_ee.patch |   117 +
 ...k-consistently-use-get_eeprom_rev-ah.patch |   342 +
 ...EPROM-swapping-check-use-the-eepmisc.patch |   128 +
 ...-EEPROM-fields-in-Little-Endian-form.patch |   853 +
 .../557-ath9k-disable-bands-via-dt.patch      |    32 +
 .../patches/560-ath9k_ubnt_uap_plus_hsr.patch |   418 +
 ...700-mwl8k-missing-pci-id-for-WNR854T.patch |    10 +
 .../mac80211/scripts/import-backports.sh      |   109 +
 package/kernel/mmc_over_gpio/Makefile         |    77 +
 .../mmc_over_gpio/files/mmc_over_gpio.config  |     8 +
 .../mmc_over_gpio/files/mmc_over_gpio.init    |    83 +
 package/kernel/om-watchdog/Makefile           |    45 +
 package/kernel/om-watchdog/files/om-watchdog  |    15 +
 .../kernel/om-watchdog/files/om-watchdog.init |    64 +
 package/kernel/rotary-gpio-custom/Makefile    |    48 +
 package/kernel/rotary-gpio-custom/src/Kconfig |     9 +
 .../kernel/rotary-gpio-custom/src/Makefile    |     1 +
 .../src/rotary-gpio-custom.c                  |   193 +
 package/kernel/spi-gpio-custom/Makefile       |    48 +
 package/kernel/spi-gpio-custom/src/Kconfig    |    14 +
 package/kernel/spi-gpio-custom/src/Makefile   |     1 +
 .../spi-gpio-custom/src/spi-gpio-custom.c     |   365 +
 package/kernel/trelay/Makefile                |    49 +
 package/kernel/trelay/files/trelay.config     |     4 +
 package/kernel/trelay/files/trelay.hotplug    |     5 +
 package/kernel/trelay/files/trelay.init       |    32 +
 package/kernel/trelay/src/Makefile            |     1 +
 package/kernel/trelay/src/trelay.c            |   272 +
 package/kernel/w1-gpio-custom/Makefile        |    49 +
 package/kernel/w1-gpio-custom/src/Kconfig     |     4 +
 package/kernel/w1-gpio-custom/src/Makefile    |     1 +
 .../w1-gpio-custom/src/w1-gpio-custom.c       |   190 +
 package/kernel/wrt55agv2-spidevs/Makefile     |    38 +
 package/kernel/wrt55agv2-spidevs/src/Kconfig  |     3 +
 package/kernel/wrt55agv2-spidevs/src/Makefile |     1 +
 .../wrt55agv2-spidevs/src/wrt55agv2_spidevs.c |   114 +
 package/libs/argp-standalone/Makefile         |    48 +
 .../patches/001-throw-in-funcdef.patch        |    79 +
 .../patches/002-no_optimize.patch             |    11 +
 package/libs/cyassl/Config.in                 |    48 +
 package/libs/cyassl/Makefile                  |   138 +
 .../400-additional_compatibility.patch        |    12 +
 package/libs/elfutils/Makefile                |    97 +
 .../patches/002-argp_standalone.patch         |    14 +
 .../elfutils/patches/003-libint-stub.patch    |    49 +
 .../patches/004-maybe-uninitialized.patch     |    11 +
 .../elfutils/patches/004-memcpy_def.patch     |    14 +
 .../patches/005-build_only_libs.patch         |    24 +
 .../elfutils/patches/006-libdw_LIBS.patch     |    11 +
 .../elfutils/patches/100-musl-compat.patch    |   702 +
 .../libs/elfutils/patches/101-no-fts.patch    |   109 +
 package/libs/gettext-full/Makefile            |    93 +
 .../patches/000-relocatable.patch             |    30 +
 .../gettext-full/patches/001-autotools.patch  |    24 +
 .../patches/001-no_examples_and_tests.patch   |    22 +
 .../003-gettext-error_print_progname.patch    |    11 +
 .../patches/100-error_progname.patch          |    10 +
 .../patches/110-error_progname_def.patch      |    11 +
 .../patches/120-uclibc-nolocale.patch         |    11 +
 .../patches/130-format-secuirty.patch         |    59 +
 .../patches/150-disable_libxml_iconv.patch    |    22 +
 package/libs/gettext/Makefile                 |    63 +
 package/libs/gettext/src/LICENSE              |     7 +
 package/libs/gettext/src/include/libintl.h    |    53 +
 package/libs/gettext/src/m4/codeset.m4        |    21 +
 package/libs/gettext/src/m4/gettext.m4        |   383 +
 package/libs/gettext/src/m4/intl.m4           |   294 +
 package/libs/gettext/src/m4/intldir.m4        |    19 +
 package/libs/gettext/src/m4/intlmacosx.m4     |    51 +
 package/libs/gettext/src/m4/lcmessage.m4      |    31 +
 package/libs/gettext/src/m4/nls.m4            |    32 +
 package/libs/gettext/src/m4/po.m4             |   449 +
 package/libs/gmp/Makefile                     |    69 +
 package/libs/libbsd/Makefile                  |    57 +
 .../libbsd/patches/001-aarch64_support.patch  |    19 +
 package/libs/libconfig/Makefile               |    59 +
 package/libs/libevent2/Makefile               |   157 +
 package/libs/libiconv-full/Makefile           |    95 +
 .../patches/100-strip_charsets.patch          |  3438 ++
 .../libiconv-full/patches/101-autotools.patch | 26014 ++++++++++++++++
 .../patches/103-configure_ac_fix.patch        |    31 +
 .../patches/200-work-with-libtool2.patch      |    17 +
 .../patches/300-fortify-source-compat.patch   |    23 +
 package/libs/libiconv/COPYING                 |   504 +
 package/libs/libiconv/COPYRIGHT               |    20 +
 package/libs/libiconv/Makefile                |    79 +
 package/libs/libiconv/src/LICENSE             |     6 +
 package/libs/libiconv/src/iconv.c             |   449 +
 package/libs/libiconv/src/include/charmaps.h  |    80 +
 .../src/include/charmaps/iso-8859-10.h        |    24 +
 .../src/include/charmaps/iso-8859-13.h        |    24 +
 .../src/include/charmaps/iso-8859-14.h        |    25 +
 .../src/include/charmaps/iso-8859-16.h        |    24 +
 .../src/include/charmaps/iso-8859-2.h         |    24 +
 .../src/include/charmaps/iso-8859-3.h         |    24 +
 .../src/include/charmaps/iso-8859-4.h         |    24 +
 .../src/include/charmaps/iso-8859-5.h         |    24 +
 .../src/include/charmaps/iso-8859-6.h         |    24 +
 .../src/include/charmaps/iso-8859-7.h         |    24 +
 .../src/include/charmaps/iso-8859-8.h         |    24 +
 .../src/include/charmaps/iso-8859-9.h         |    24 +
 .../libiconv/src/include/charmaps/koi8-r.h    |    24 +
 .../src/include/charmaps/windows-1250.h       |    24 +
 .../src/include/charmaps/windows-1251.h       |    24 +
 .../src/include/charmaps/windows-1252.h       |    25 +
 .../src/include/charmaps/windows-1253.h       |    24 +
 .../src/include/charmaps/windows-1254.h       |    24 +
 .../src/include/charmaps/windows-1255.h       |    24 +
 .../src/include/charmaps/windows-1256.h       |    24 +
 .../src/include/charmaps/windows-1257.h       |    24 +
 .../src/include/charmaps/windows-1258.h       |    24 +
 .../src/include/charmaps/windows-874.h        |    24 +
 package/libs/libiconv/src/include/iconv.h     |    36 +
 package/libs/libiconv/src/m4/iconv.m4         |   214 +
 package/libs/libjson-c/Makefile               |    57 +
 package/libs/libjson-c/patches/000-libm.patch |    50 +
 package/libs/libmnl/Makefile                  |    77 +
 package/libs/libnetfilter-conntrack/Makefile  |    74 +
 package/libs/libnetfilter-cthelper/Makefile   |    71 +
 package/libs/libnetfilter-cttimeout/Makefile  |    71 +
 package/libs/libnetfilter-log/Makefile        |    74 +
 ...ecessary-pkgconfig-config.status-dep.patch |    25 +
 ...d-remove-unused-lines-in-Makefile.am.patch |    24 +
 ...build-resolve-automake-1.12-warnings.patch |    29 +
 ...e-needed-for-integer-type-definition.patch |    24 +
 ...0005-configure-uclinux-is-also-linux.patch |    27 +
 ...thout-ipulog-option-to-disable-libip.patch |    95 +
 package/libs/libnetfilter-queue/Makefile      |    71 +
 .../patches/100-checksum_computation.patch    |   115 +
 package/libs/libnfnetlink/Makefile            |    71 +
 .../patches/100-missing_include.patch         |    20 +
 package/libs/libnftnl/Makefile                |    74 +
 package/libs/libnl-tiny/Makefile              |    50 +
 package/libs/libnl-tiny/files/libnl-tiny.pc   |    10 +
 package/libs/libnl-tiny/src/Makefile          |    17 +
 package/libs/libnl-tiny/src/attr.c            |   668 +
 package/libs/libnl-tiny/src/cache.c           |   376 +
 package/libs/libnl-tiny/src/cache_mngt.c      |   131 +
 package/libs/libnl-tiny/src/error.c           |   116 +
 package/libs/libnl-tiny/src/genl.c            |   268 +
 package/libs/libnl-tiny/src/genl_ctrl.c       |   380 +
 package/libs/libnl-tiny/src/genl_family.c     |   169 +
 package/libs/libnl-tiny/src/genl_mngt.c       |   193 +
 package/libs/libnl-tiny/src/handlers.c        |   162 +
 .../libnl-tiny/src/include/netlink-generic.h  |    20 +
 .../libnl-tiny/src/include/netlink-local.h    |   158 +
 .../libnl-tiny/src/include/netlink-types.h    |    88 +
 .../libnl-tiny/src/include/netlink/addr.h     |    69 +
 .../libnl-tiny/src/include/netlink/attr.h     |   726 +
 .../src/include/netlink/cache-api.h           |   199 +
 .../libnl-tiny/src/include/netlink/cache.h    |   128 +
 .../libnl-tiny/src/include/netlink/data.h     |    41 +
 .../libnl-tiny/src/include/netlink/errno.h    |    64 +
 .../src/include/netlink/genl/ctrl.h           |    40 +
 .../src/include/netlink/genl/family.h         |   134 +
 .../src/include/netlink/genl/genl.h           |    47 +
 .../src/include/netlink/genl/mngt.h           |    87 +
 .../libnl-tiny/src/include/netlink/handlers.h |   231 +
 .../libnl-tiny/src/include/netlink/list.h     |    88 +
 .../libs/libnl-tiny/src/include/netlink/msg.h |   308 +
 .../src/include/netlink/netlink-compat.h      |    50 +
 .../src/include/netlink/netlink-kernel.h      |   196 +
 .../libnl-tiny/src/include/netlink/netlink.h  |    82 +
 .../src/include/netlink/object-api.h          |   331 +
 .../libnl-tiny/src/include/netlink/object.h   |   164 +
 .../libnl-tiny/src/include/netlink/socket.h   |   231 +
 .../libnl-tiny/src/include/netlink/types.h    |   121 +
 .../libnl-tiny/src/include/netlink/utils.h    |    78 +
 .../libnl-tiny/src/include/netlink/version.h  |    18 +
 package/libs/libnl-tiny/src/include/unl.h     |    47 +
 package/libs/libnl-tiny/src/msg.c             |   566 +
 package/libs/libnl-tiny/src/nl.c              |   720 +
 package/libs/libnl-tiny/src/object.c          |   147 +
 package/libs/libnl-tiny/src/socket.c          |   406 +
 package/libs/libnl-tiny/src/unl.c             |   287 +
 package/libs/libnl/Makefile                   |   132 +
 package/libs/libpcap/Config.in                |    15 +
 package/libs/libpcap/Makefile                 |    97 +
 .../patches/100-debian_shared_lib.patch       |   178 +
 .../102-makefile_disable_manpages.patch       |    73 +
 .../103-makefile_flex_workaround.patch        |    14 +
 .../patches/201-space_optimization.patch      |   159 +
 .../libpcap/patches/202-protocol_api.patch    |   140 +
 .../patches/203-undef_iw_mode_monitor.patch   |    11 +
 package/libs/libreadline/Makefile             |    72 +
 .../patches/001-install_perm.patch            |    11 +
 package/libs/libroxml/Makefile                |    47 +
 package/libs/librpc/Makefile                  |    35 +
 package/libs/libtool/Makefile                 |    52 +
 .../libtool/patches/160-passthrough-ssp.patch |    11 +
 package/libs/libubox/Makefile                 |    99 +
 package/libs/libunwind/Makefile               |    53 +
 .../libunwind/patches/001-disable-tests.patch |    22 +
 .../002-fix-building-getcontext_S.patch       |    19 +
 ...03-fix-missing-ef_reg-defs-with-musl.patch |    47 +
 package/libs/libusb-compat/Makefile           |    53 +
 .../patches/001-fix-musl-stdint.patch         |   185 +
 package/libs/libusb/Makefile                  |    53 +
 package/libs/lzo/Makefile                     |    63 +
 package/libs/mbedtls/Makefile                 |    69 +
 package/libs/mbedtls/patches/200-config.patch |   208 +
 package/libs/ncurses/Makefile                 |   150 +
 .../100-ncurses-5.6-20080112-urxvt.patch      |   175 +
 .../101-ncurses-5.6-20080628-kbs.patch        |    52 +
 .../patches/102-ncurses-5.9-gcc-5.patch       |    44 +
 .../103-fixup-pkg-config-handling.patch       |    85 +
 .../patches/200-fix_missing_include.patch     |    14 +
 package/libs/ncurses/patches/500-cross.patch  |    11 +
 .../libs/ncurses/patches/900-terminfo.patch   |    20 +
 package/libs/nettle/Config.in                 |     9 +
 package/libs/nettle/Makefile                  |    86 +
 package/libs/openssl/Config.in                |    62 +
 package/libs/openssl/Makefile                 |   259 +
 .../libs/openssl/include/crypto/cryptodev.h   |   292 +
 .../patches/110-optimize-for-size.patch       |    15 +
 .../libs/openssl/patches/130-perl-path.patch  |    64 +
 .../openssl/patches/140-makefile-dirs.patch   |    11 +
 .../libs/openssl/patches/150-no_engines.patch |    81 +
 .../patches/160-disable_doc_tests.patch       |    58 +
 .../libs/openssl/patches/170-bash_path.patch  |     8 +
 .../patches/180-fix_link_segfault.patch       |    18 +
 .../patches/190-remove_timestamp_check.patch  |    23 +
 .../openssl/patches/200-parallel_build.patch  |   184 +
 package/libs/polarssl/Makefile                |    74 +
 .../polarssl/patches/200-reduce_config.patch  |   242 +
 package/libs/popt/Makefile                    |    58 +
 package/libs/sysfsutils/Makefile              |    73 +
 .../patches/200-mnt_path_check.patch          |    55 +
 package/libs/toolchain/Makefile               |   578 +
 .../toolchain/eglibc-files/etc/nsswitch.conf  |    13 +
 .../toolchain/glibc-files/etc/nsswitch.conf   |    13 +
 package/libs/uclibc++/Makefile                |   106 +
 package/libs/uclibc++/files/config.default    |    58 +
 .../uclibc++/patches/002-path_to_bash.patch   |    11 +
 .../libs/uclibc++/patches/006-eabi_fix.patch  |    38 +
 .../uclibc++/patches/010-honor-ldflags.patch  |    23 +
 .../uclibc++/patches/020-template-fix.patch   |    22 +
 .../patches/030-memory_corruption_fix.patch   |   114 +
 .../uclibc++/patches/040-delete-c++14.patch   |    20 +
 package/libs/uclient/Makefile                 |    52 +
 package/libs/ustream-ssl/Makefile             |    87 +
 package/libs/zlib/Makefile                    |   104 +
 package/network/config/firewall/Makefile      |    62 +
 .../config/firewall/files/firewall.config     |   194 +
 .../config/firewall/files/firewall.hotplug    |    11 +
 .../config/firewall/files/firewall.init       |    61 +
 .../config/firewall/files/firewall.user       |     7 +
 package/network/config/gre/Makefile           |    65 +
 package/network/config/gre/files/gre.sh       |   266 +
 package/network/config/ipip/Makefile          |    40 +
 package/network/config/ipip/files/ipip.sh     |    93 +
 package/network/config/netifd/Makefile        |    45 +
 .../files/etc/hotplug.d/iface/00-netstate     |     7 +
 .../config/netifd/files/etc/init.d/network    |   151 +
 .../netifd/files/lib/netifd/dhcp.script       |   102 +
 .../netifd/files/lib/netifd/proto/dhcp.sh     |    79 +
 .../config/netifd/files/lib/network/config.sh |    79 +
 .../config/netifd/files/sbin/devstatus        |    12 +
 .../network/config/netifd/files/sbin/ifdown   |     1 +
 .../network/config/netifd/files/sbin/ifstatus |    13 +
 package/network/config/netifd/files/sbin/ifup |    77 +
 .../files/usr/share/udhcpc/default.script     |    57 +
 package/network/config/qos-scripts/Makefile   |    52 +
 .../config/qos-scripts/files/etc/config/qos   |    68 +
 .../files/etc/hotplug.d/iface/10-qos          |     2 +
 .../config/qos-scripts/files/etc/init.d/qos   |    28 +
 .../qos-scripts/files/usr/bin/qos-start       |     4 +
 .../config/qos-scripts/files/usr/bin/qos-stat |    67 +
 .../config/qos-scripts/files/usr/bin/qos-stop |     6 +
 .../qos-scripts/files/usr/lib/qos/generate.sh |   538 +
 .../qos-scripts/files/usr/lib/qos/tcrules.awk |   106 +
 package/network/config/soloscli/Makefile      |    45 +
 .../files/etc/hotplug.d/atm/15-solos-init     |    26 +
 .../soloscli/files/etc/uci-default/solos      |    15 +
 .../config/soloscli/files/solos-log-stats     |    19 +
 .../soloscli/patches/001-no-driver.patch      |    11 +
 .../config/soloscli/patches/002-cflags.patch  |    12 +
 package/network/config/swconfig/Makefile      |    55 +
 .../network/config/swconfig/files/switch.sh   |    15 +
 package/network/config/swconfig/src/Makefile  |    15 +
 package/network/config/swconfig/src/cli.c     |   387 +
 package/network/config/swconfig/src/swlib.c   |   922 +
 package/network/config/swconfig/src/swlib.h   |   269 +
 package/network/config/swconfig/src/uci.c     |   246 +
 package/network/config/vti/Makefile           |    65 +
 package/network/config/vti/files/vti.sh       |   151 +
 package/network/ipv6/6in4/Makefile            |    43 +
 package/network/ipv6/6in4/files/6in4.sh       |   139 +
 package/network/ipv6/6rd/Makefile             |    49 +
 package/network/ipv6/6rd/files/6rd.sh         |   102 +
 package/network/ipv6/6rd/src/6rdcalc.c        |   126 +
 package/network/ipv6/6rd/src/Makefile         |     7 +
 package/network/ipv6/6to4/Makefile            |    43 +
 package/network/ipv6/6to4/files/6to4.sh       |    98 +
 package/network/ipv6/ds-lite/Makefile         |    43 +
 package/network/ipv6/ds-lite/files/dslite.sh  |   106 +
 package/network/ipv6/map/Makefile             |    40 +
 package/network/ipv6/map/files/map.sh         |   221 +
 package/network/ipv6/map/src/CMakeLists.txt   |    26 +
 package/network/ipv6/map/src/mapcalc.c        |   412 +
 package/network/ipv6/odhcp6c/Makefile         |    52 +
 .../network/ipv6/odhcp6c/files/dhcpv6.script  |   219 +
 package/network/ipv6/odhcp6c/files/dhcpv6.sh  |   103 +
 package/network/ipv6/thc-ipv6/Makefile        |    61 +
 .../ipv6/thc-ipv6/patches/100-no-ssl.patch    |     9 +
 package/network/services/authsae/Makefile     |    48 +
 .../authsae/files/lib/wifi/authsae.sh         |    65 +
 .../authsae/patches/100-musl_fix.patch        |    20 +
 package/network/services/dnsmasq/Makefile     |   169 +
 .../network/services/dnsmasq/files/dhcp.conf  |    32 +
 .../services/dnsmasq/files/dnsmasq.conf       |    37 +
 .../services/dnsmasq/files/dnsmasq.init       |   854 +
 .../services/dnsmasq/files/dnsmasqsec.hotplug |    14 +
 .../100-fix-dhcp-no-address-warning.patch     |    47 +
 .../110-ipset-remove-old-kernel-support.patch |   110 +
 ...20-dnsmasq-compile-time-option-NO_ID.patch |   149 +
 ...0-dnssec-improve-timestamp-heuristic.patch |    47 +
 ...0-fix-poll-h-include-warning-on-musl.patch |    18 +
 package/network/services/dropbear/Config.in   |    50 +
 package/network/services/dropbear/Makefile    |   148 +
 .../services/dropbear/files/dropbear.config   |     5 +
 .../services/dropbear/files/dropbear.init     |   196 +
 .../dropbear/patches/100-pubkey_path.patch    |    91 +
 .../dropbear/patches/110-change_user.patch    |    18 +
 .../patches/120-openwrt_options.patch         |    81 +
 .../patches/130-ssh_ignore_x_args.patch       |    11 +
 .../dropbear/patches/140-disable_assert.patch |    15 +
 .../patches/150-dbconvert_standalone.patch    |    14 +
 .../patches/500-set-default-path.patch        |    12 +
 .../600-allow-blank-root-password.patch       |    11 +
 ...610-skip-default-keys-in-custom-runs.patch |    18 +
 package/network/services/ead/Makefile         |    52 +
 package/network/services/ead/src/Makefile     |    33 +
 package/network/services/ead/src/aes.c        |  1061 +
 package/network/services/ead/src/ead-client.c |   433 +
 package/network/services/ead/src/ead-crypt.c  |   179 +
 package/network/services/ead/src/ead-crypt.h  |    21 +
 package/network/services/ead/src/ead-pcap.h   |    71 +
 package/network/services/ead/src/ead.c        |   976 +
 package/network/services/ead/src/ead.h        |   139 +
 package/network/services/ead/src/filter.c     |    25 +
 package/network/services/ead/src/libbridge.h  |    60 +
 .../network/services/ead/src/libbridge_init.c |   127 +
 .../services/ead/src/libbridge_private.h      |    35 +
 package/network/services/ead/src/list.h       |   602 +
 package/network/services/ead/src/passwd       |     3 +
 package/network/services/ead/src/pfc.c        |    54 +
 .../network/services/ead/src/pw_encrypt_md5.c |   646 +
 package/network/services/ead/src/sha1.c       |   104 +
 .../services/ead/src/tinysrp/Makefile.am      |    28 +
 .../services/ead/src/tinysrp/Makefile.in      |   477 +
 .../network/services/ead/src/tinysrp/Notes    |   110 +
 .../services/ead/src/tinysrp/acconfig.h       |     9 +
 .../services/ead/src/tinysrp/acinclude.m4     |    27 +
 .../services/ead/src/tinysrp/aclocal.m4       |   157 +
 package/network/services/ead/src/tinysrp/bn.h |   471 +
 .../network/services/ead/src/tinysrp/bn_add.c |   305 +
 .../network/services/ead/src/tinysrp/bn_asm.c |   382 +
 .../network/services/ead/src/tinysrp/bn_ctx.c |   142 +
 .../network/services/ead/src/tinysrp/bn_div.c |   378 +
 .../network/services/ead/src/tinysrp/bn_exp.c |   395 +
 .../network/services/ead/src/tinysrp/bn_lcl.h |   419 +
 .../network/services/ead/src/tinysrp/bn_lib.c |   576 +
 .../network/services/ead/src/tinysrp/bn_mul.c |   172 +
 .../services/ead/src/tinysrp/bn_prime.h       |   325 +
 .../services/ead/src/tinysrp/bn_shift.c       |   139 +
 .../network/services/ead/src/tinysrp/bn_sqr.c |   160 +
 .../services/ead/src/tinysrp/bn_word.c        |   130 +
 .../services/ead/src/tinysrp/clitest.c        |   110 +
 .../services/ead/src/tinysrp/config.h.in      |    79 +
 .../services/ead/src/tinysrp/configure        |  2421 ++
 .../services/ead/src/tinysrp/configure.in     |    52 +
 .../services/ead/src/tinysrp/install-sh       |   250 +
 .../network/services/ead/src/tinysrp/missing  |   134 +
 .../services/ead/src/tinysrp/mkinstalldirs    |    39 +
 .../services/ead/src/tinysrp/srvtest.c        |   111 +
 .../services/ead/src/tinysrp/stamp-h.in       |     1 +
 .../services/ead/src/tinysrp/t_client.c       |   285 +
 .../services/ead/src/tinysrp/t_client.h       |   148 +
 .../network/services/ead/src/tinysrp/t_conf.c |  1080 +
 .../network/services/ead/src/tinysrp/t_conv.c |   226 +
 .../services/ead/src/tinysrp/t_defines.h      |   169 +
 .../services/ead/src/tinysrp/t_getconf.c      |   118 +
 .../services/ead/src/tinysrp/t_getpass.c      |   191 +
 .../network/services/ead/src/tinysrp/t_math.c |   177 +
 .../network/services/ead/src/tinysrp/t_misc.c |   338 +
 .../network/services/ead/src/tinysrp/t_pw.c   |   262 +
 .../network/services/ead/src/tinysrp/t_pwd.h  |   310 +
 .../network/services/ead/src/tinysrp/t_read.c |    81 +
 .../network/services/ead/src/tinysrp/t_read.h |    55 +
 .../services/ead/src/tinysrp/t_server.c       |   259 +
 .../services/ead/src/tinysrp/t_server.h       |   138 +
 .../network/services/ead/src/tinysrp/t_sha.c  |   166 +
 .../network/services/ead/src/tinysrp/t_sha.h  |    26 +
 .../services/ead/src/tinysrp/t_truerand.c     |   151 +
 .../network/services/ead/src/tinysrp/tconf.c  |   157 +
 .../services/ead/src/tinysrp/tinysrp.c        |   235 +
 .../services/ead/src/tinysrp/tinysrp.h        |    18 +
 .../network/services/ead/src/tinysrp/tpasswd  |     2 +
 .../services/ead/src/tinysrp/tphrase.c        |   354 +
 package/network/services/hostapd/Config.in    |    51 +
 package/network/services/hostapd/Makefile     |   431 +
 .../hostapd/files/hostapd-full.config         |   169 +
 .../hostapd/files/hostapd-mini.config         |   159 +
 .../services/hostapd/files/multicall.c        |    28 +
 .../network/services/hostapd/files/netifd.sh  |   755 +
 .../hostapd/files/wpa_supplicant-full.config  |   406 +
 .../hostapd/files/wpa_supplicant-mini.config  |   401 +
 .../hostapd/files/wpa_supplicant-p2p.config   |   406 +
 .../services/hostapd/files/wps-hotplug.sh     |    11 +
 ...connecting-client-on-connection-lost.patch |    25 +
 .../hostapd/patches/100-daemonize_fix.patch   |    97 +
 .../hostapd/patches/110-no_eapol_fix.patch    |    14 +
 ...120-disable_bridge_packet_workaround.patch |    12 +
 ...emove-duplicated-check-in-nl80211_se.patch |    39 +
 .../hostapd/patches/200-multicall.patch       |   360 +
 .../services/hostapd/patches/300-noscan.patch |    58 +
 .../patches/310-rescan_immediately.patch      |    11 +
 .../hostapd/patches/320-optional_rfkill.patch |    61 +
 .../patches/330-nl80211_fix_set_freq.patch    |    11 +
 .../patches/340-reload_freq_change.patch      |    44 +
 .../patches/350-nl80211_del_beacon_bss.patch  |    72 +
 .../patches/360-ctrl_iface_reload.patch       |   106 +
 .../hostapd/patches/370-ap_sta_support.patch  |   237 +
 .../patches/380-disable_ctrl_iface_mib.patch  |   178 +
 .../patches/390-wpa_ie_cap_workaround.patch   |    56 +
 .../400-wps_single_auth_enc_type.patch        |    22 +
 .../patches/410-limit_debug_messages.patch    |   214 +
 .../patches/420-indicate-features.patch       |    62 +
 .../patches/430-hostapd_cli_ifdef.patch       |    34 +
 .../hostapd/patches/431-wpa_cli_ifdef.patch   |    12 +
 .../hostapd/patches/432-missing-typedef.patch |    10 +
 .../hostapd/patches/450-scan_wait.patch       |    73 +
 ...dd-new-config-params-to-be-used-with.patch |   191 +
 ...-use-new-parameters-during-ibss-join.patch |    59 +
 .../462-wpa_s-support-htmode-param.patch      |   156 +
 .../patches/470-survey_data_fallback.patch    |    45 +
 .../hostapd/patches/600-ubus_support.patch    |   264 +
 .../services/hostapd/src/src/ap/ubus.c        |   536 +
 .../services/hostapd/src/src/ap/ubus.h        |    78 +
 .../hostapd/src/src/utils/build_features.h    |    17 +
 package/network/services/igmpproxy/Makefile   |    59 +
 .../services/igmpproxy/files/igmpproxy.config |    12 +
 .../services/igmpproxy/files/igmpproxy.init   |   134 +
 ...s-with-IP-Router-Alert-option-RFC-21.patch |    79 +
 ...nterface-state-to-disabled-wrt-29458.patch |    43 +
 ...ports-for-downstream-interfaces-wrt-.patch |   164 +
 ...ports-forwarding-to-upstream-interfa.patch |    62 +
 .../patches/010-missing_include.patch         |    10 +
 ...e-downstream-interface-igmp-messages.patch |    19 +
 ...monotic-clock-instead-of-time-of-day.patch |   120 +
 .../patches/200-allow_wildcard_addr.patch     |    24 +
 ...250-fix_multiple_downlink_interfaces.patch |   154 +
 package/network/services/ipset-dns/Makefile   |    61 +
 .../services/ipset-dns/files/ipset-dns.config |    16 +
 .../services/ipset-dns/files/ipset-dns.init   |    57 +
 .../patches/100-simultaneous-ipv4-ipv6.patch  |    57 +
 package/network/services/lldpd/Config.in      |    54 +
 package/network/services/lldpd/Makefile       |   109 +
 .../network/services/lldpd/files/lldpd.config |    15 +
 .../network/services/lldpd/files/lldpd.init   |   121 +
 package/network/services/mdns/Makefile        |    49 +
 .../network/services/mdns/files/mdns.config   |     3 +
 package/network/services/mdns/files/mdns.init |    54 +
 package/network/services/mdns/files/mdns.json |    32 +
 package/network/services/odhcpd/Makefile      |    68 +
 .../services/odhcpd/files/odhcpd-update       |     5 +
 .../services/odhcpd/files/odhcpd.defaults     |    13 +
 .../network/services/odhcpd/files/odhcpd.init |    22 +
 package/network/services/omcproxy/Makefile    |    44 +
 .../services/omcproxy/files/omcproxy.config   |     9 +
 .../services/omcproxy/files/omcproxy.init     |   143 +
 .../services/openvpn-easy-rsa/Makefile        |    60 +
 .../openvpn-easy-rsa/files/easy-rsa.index     |     0
 .../openvpn-easy-rsa/files/easy-rsa.serial    |     1 +
 .../patches/100-run-ootb.patch                |   152 +
 .../network/services/openvpn/Config-nossl.in  |    54 +
 .../services/openvpn/Config-openssl.in        |    66 +
 .../services/openvpn/Config-polarssl.in       |    66 +
 package/network/services/openvpn/Makefile     |   123 +
 .../services/openvpn/files/openvpn.config     |   400 +
 .../services/openvpn/files/openvpn.init       |   159 +
 .../services/openvpn/files/openvpn.upgrade    |     1 +
 .../001-reproducible-remove_DATE.patch        |    10 +
 ...larssl-disable-runtime-version-check.patch |    11 +
 ...ackport_upstream_polarssl_debug_call.patch |    33 +
 .../patches/200-small_build_enable_occ.patch  |    12 +
 package/network/services/ppp/Makefile         |   284 +
 .../services/ppp/files/etc/ppp/chap-secrets   |     1 +
 .../network/services/ppp/files/etc/ppp/filter |    23 +
 .../services/ppp/files/etc/ppp/options        |    10 +
 .../services/ppp/files/etc/ppp/options.pptp   |     7 +
 .../services/ppp/files/etc/ppp/radius.conf    |     8 +
 .../ppp/files/etc/ppp/radius/dictionary       |   253 +
 .../ppp/files/etc/ppp/radius/dictionary.asnet |     3 +
 .../files/etc/ppp/radius/dictionary.microsoft |    80 +
 .../services/ppp/files/etc/ppp/radius/servers |     2 +
 .../services/ppp/files/lib/netifd/ppp-down    |    13 +
 .../services/ppp/files/lib/netifd/ppp-up      |    20 +
 .../services/ppp/files/lib/netifd/ppp6-up     |    27 +
 package/network/services/ppp/files/ppp.sh     |   324 +
 .../ppp/patches/001-honor-ldflags.patch       |    39 +
 .../010-use_target_for_configure.patch        |    24 +
 .../ppp/patches/100-debian_ip-ip_option.patch |    96 +
 .../patches/101-debian_close_dev_ppp.patch    |    28 +
 .../patches/103-debian_fix_link_pidfile.patch |    23 +
 .../ppp/patches/105-debian_demand.patch       |   172 +
 .../patches/106-debian_stripMSdomain.patch    |    47 +
 .../patches/107-debian_pppoatm_wildcard.patch |    25 +
 .../ppp/patches/110-debian_defaultroute.patch |   313 +
 .../120-debian_ipv6_updown_option.patch       |    95 +
 .../121-debian_adaptive_lcp_echo.patch        |    56 +
 .../services/ppp/patches/130-no_cdefs_h.patch |    11 +
 .../patches/131-missing_prototype_macro.patch |    23 +
 .../ppp/patches/132-fix_linux_includes.patch  |    40 +
 .../ppp/patches/133-fix_sha1_include.patch    |    11 +
 .../ppp/patches/140-pppoe_compile_fix.patch   |   101 +
 .../services/ppp/patches/200-makefile.patch   |    49 +
 .../ppp/patches/201-mppe_mppc_1.1.patch       |  1495 +
 .../services/ppp/patches/202-no_strip.patch   |    88 +
 .../services/ppp/patches/203-opt_flags.patch  |    32 +
 .../ppp/patches/204-radius_config.patch       |    72 +
 .../patches/205-no_exponential_timeout.patch  |    29 +
 .../patches/206-compensate_time_change.patch  |    94 +
 .../ppp/patches/207-lcp_mtu_max.patch         |    25 +
 .../ppp/patches/208-fix_status_code.patch     |    24 +
 .../300-filter-pcap-includes-lib.patch        |    20 +
 .../ppp/patches/310-precompile_filter.patch   |   196 +
 .../ppp/patches/320-custom_iface_names.patch  |   135 +
 ...multilink_support_custom_iface_names.patch |   146 +
 .../330-retain_foreign_default_routes.patch   |    22 +
 .../340-populate_default_gateway.patch        |    34 +
 .../patches/400-simplify_kernel_checks.patch  |   154 +
 .../ppp/patches/401-no_record_file.patch      |    39 +
 .../services/ppp/patches/403-no_wtmp.patch    |    25 +
 .../404-remove_obsolete_protocol_names.patch  |   151 +
 .../ppp/patches/405-no_multilink_option.patch |    28 +
 .../ppp/patches/500-add-pptp-plugin.patch     |  3065 ++
 .../ppp/patches/510-pptp_compile_fix.patch    |    11 +
 .../services/ppp/patches/520-uniq.patch       |   269 +
 .../ppp/patches/530-pppoe_send_padt.patch     |    11 +
 .../531-pppoe_no_disconnect_warning.patch     |    14 +
 .../patches/540-save-pppol2tp_fd_str.patch    |    13 +
 .../ppp/patches/550-fix-printer-args.patch    |    11 +
 package/network/services/ppp/utils/pfc.c      |    51 +
 package/network/services/relayd/Makefile      |    46 +
 .../services/relayd/files/relay.hotplug       |     2 +
 .../network/services/relayd/files/relay.init  |   115 +
 package/network/services/samba36/Makefile     |   161 +
 .../services/samba36/files/samba.config       |     6 +
 .../network/services/samba36/files/samba.init |   119 +
 .../services/samba36/files/smb.conf.template  |    28 +
 .../patches/010-patch-cve-2015-5252.patch     |    39 +
 .../patches/011-patch-cve-2015-5296.patch     |    88 +
 .../patches/012-patch-cve-2015-5299.patch     |    93 +
 .../patches/015-patch-cve-2015-7560.patch     |   172 +
 .../patches/020-CVE-preparation-v3-6.patch    |  6824 ++++
 .../021-CVE-preparation-v3-6-addition.patch   |  9515 ++++++
 .../patches/022-CVE-2015-5370-v3-6.patch      |  1791 ++
 .../patches/023-CVE-2016-2110-v3-6.patch      |   255 +
 .../patches/024-CVE-2016-2111-v3-6.patch      |   681 +
 .../patches/025-CVE-2016-2112-v3-6.patch      |   129 +
 .../patches/026-CVE-2016-2115-v3-6.patch      |   256 +
 .../patches/027-CVE-2016-2118-v3-6.patch      |   308 +
 .../samba36/patches/100-configure_fixes.patch |    14 +
 .../samba36/patches/110-multicall.patch       |   119 +
 .../samba36/patches/111-owrt_smbpasswd.patch  |   281 +
 .../patches/120-add_missing_ifdef.patch       |    41 +
 .../patches/200-remove_printer_support.patch  |   346 +
 .../patches/210-remove_ad_support.patch       |    88 +
 .../samba36/patches/220-remove_services.patch |    98 +
 .../patches/230-remove_winreg_support.patch   |   146 +
 .../samba36/patches/240-remove_dfs_api.patch  |    71 +
 .../patches/250-remove_domain_logon.patch     |   213 +
 .../samba36/patches/260-remove_samr.patch     |   162 +
 .../patches/270-remove_registry_backend.patch |    43 +
 .../samba36/patches/280-strip_srvsvc.patch    |   143 +
 .../samba36/patches/290-remove_lsa.patch      |    88 +
 .../patches/300-assert_debug_level.patch      |    11 +
 .../patches/310-remove_error_strings.patch    |   337 +
 .../patches/320-debug_level_checks.patch      |    22 +
 .../patches/330-librpc_default_print.patch    |  8854 ++++++
 package/network/services/uhttpd/Makefile      |   153 +
 .../services/uhttpd/files/ubus.default        |     8 +
 .../services/uhttpd/files/uhttpd.config       |   132 +
 .../network/services/uhttpd/files/uhttpd.init |   187 +
 package/network/utils/arptables/Makefile      |    42 +
 package/network/utils/comgt/Makefile          |   104 +
 package/network/utils/comgt/files/3g.chat     |    12 +
 package/network/utils/comgt/files/3g.sh       |   110 +
 package/network/utils/comgt/files/3g.usb      |    33 +
 .../utils/comgt/files/directip-stop.gcom      |    16 +
 .../network/utils/comgt/files/directip.gcom   |    55 +
 package/network/utils/comgt/files/directip.sh |   114 +
 package/network/utils/comgt/files/evdo.chat   |    17 +
 .../utils/comgt/files/getcardinfo.gcom        |    14 +
 .../network/utils/comgt/files/getcarrier.gcom |    20 +
 .../network/utils/comgt/files/getcnum.gcom    |    20 +
 .../network/utils/comgt/files/getimsi.gcom    |    17 +
 .../utils/comgt/files/getstrength.gcom        |    14 +
 package/network/utils/comgt/files/ncm.json    |    67 +
 package/network/utils/comgt/files/ncm.sh      |   195 +
 .../network/utils/comgt/files/runcommand.gcom |    31 +
 .../network/utils/comgt/files/setmode.gcom    |    26 +
 package/network/utils/comgt/files/setpin.gcom |    55 +
 .../utils/comgt/patches/001-compile_fix.patch |    23 +
 .../utils/comgt/patches/002-termios.patch     |   105 +
 .../utils/comgt/patches/003-no_XCASE.patch    |    20 +
 .../utils/comgt/patches/004-check_tty.patch   |    68 +
 .../network/utils/conntrack-tools/Makefile    |    80 +
 .../conntrack-tools/files/conntrackd.init     |    18 +
 package/network/utils/curl/Config.in          |   159 +
 package/network/utils/curl/Makefile           |   180 +
 .../curl/patches/200-no_docs_tests.patch      |    22 +
 ...larssl-disable-runtime-version-check.patch |    22 +
 package/network/utils/dante/Makefile          |   116 +
 .../dante/patches/200-fix-RTLD_NEXT.patch     |    36 +
 package/network/utils/ebtables/Makefile       |    72 +
 .../utils/ebtables/patches/100-musl_fix.patch |   181 +
 .../patches/200-fix-extension-init.patch      |   249 +
 package/network/utils/iftop/Makefile          |    43 +
 .../iftop/patches/110-fix-mac-display.patch   |    67 +
 package/network/utils/iperf/Makefile          |    56 +
 package/network/utils/iperf3/Makefile         |    49 +
 package/network/utils/iproute2/Makefile       |   148 +
 package/network/utils/iproute2/files/15-teql  |    23 +
 .../utils/iproute2/patches/001-config.patch   |     7 +
 .../iproute2/patches/004-darwin_fixes.patch   |    59 +
 .../utils/iproute2/patches/006-no_sctp.patch  |    18 +
 .../utils/iproute2/patches/007-no_arpd.patch  |    15 +
 .../utils/iproute2/patches/008-no_netem.patch |    11 +
 .../iproute2/patches/010-type_fixes.patch     |   396 +
 .../patches/100-allow_pfifo_fast.patch        |     9 +
 .../iproute2/patches/110-extra-ccopts.patch   |    11 +
 .../iproute2/patches/120-libnetlink-pic.patch |    11 +
 .../patches/130-missing_include.patch         |    20 +
 .../utils/iproute2/patches/300-ip_tiny.patch  |   101 +
 .../patches/900-drop_FAILED_POLICY.patch      |    54 +
 .../910-sanitize_headers_for_musl.patch       |    10 +
 .../patches/911-fix_in_h_include.patch        |    30 +
 .../iproute2/patches/950-add-cake-to-tc.patch |   716 +
 package/network/utils/ipset/Makefile          |    60 +
 package/network/utils/iptables/Makefile       |   558 +
 .../020-iptables-disable-modprobe.patch       |    18 +
 .../patches/030-no-libnfnetlink.patch         |    94 +
 .../iptables/patches/050-optional-xml.patch   |    13 +
 .../iptables/patches/100-bash-location.patch  |     8 +
 .../patches/200-configurable_builtin.patch    |    60 +
 .../iptables/patches/300-musl_fixes.patch     |   127 +
 .../patches/500-add-xt_id-match.patch         |    69 +
 .../iptables/patches/600-shared-libext.patch  |    78 +
 .../700-disable-legacy-revisions.patch        |   108 +
 package/network/utils/iputils/Makefile        |   181 +
 .../utils/iputils/patches/001-iputils.patch   |    14 +
 .../utils/iputils/patches/002-fix-ipv6.patch  |    14 +
 .../iputils/patches/003-fix-makefile.patch    |    18 +
 .../patches/010-ping6_uclibc_resolv.patch     |   200 +
 .../patches/011-ping6_use_gnu_source.patch    |    11 +
 .../iputils/patches/020-include_fixes.patch   |    71 +
 package/network/utils/iw/Makefile             |    57 +
 .../utils/iw/patches/001-nl80211_h_sync.patch |    21 +
 .../utils/iw/patches/120-antenna_gain.patch   |    33 +
 .../utils/iw/patches/200-reduce_size.patch    |   255 +
 package/network/utils/iwcap/Makefile          |    46 +
 package/network/utils/iwcap/src/iwcap.c       |   583 +
 package/network/utils/iwinfo/Makefile         |   124 +
 package/network/utils/linux-atm/Makefile      |   196 +
 .../network/utils/linux-atm/files/atm.hotplug |     1 +
 .../network/utils/linux-atm/files/br2684-up   |     3 +
 .../network/utils/linux-atm/files/br2684ctl   |    81 +
 .../utils/linux-atm/files/br2684ctl_wrap      |     5 +
 .../linux-atm/patches/000-debian_16.patch     |   270 +
 .../linux-atm/patches/200-no_libfl.patch      |   179 +
 .../linux-atm/patches/300-objcopy_path.patch  |    40 +
 .../patches/400-portability_fixes.patch       |    56 +
 .../patches/500-br2684ctl_script.patch        |    63 +
 .../patches/600-fix-format-errors.patch       |    11 +
 package/network/utils/maccalc/Makefile        |    43 +
 package/network/utils/maccalc/src/Makefile    |    14 +
 package/network/utils/maccalc/src/main.c      |   256 +
 package/network/utils/nftables/Makefile       |    44 +
 .../patches/100-disable-doc-generation.patch  |     8 +
 package/network/utils/owipcalc/Makefile       |    44 +
 package/network/utils/owipcalc/src/owipcalc.c |   951 +
 package/network/utils/resolveip/Makefile      |    41 +
 .../network/utils/resolveip/src/resolveip.c   |    98 +
 package/network/utils/rssileds/Makefile       |    44 +
 .../utils/rssileds/files/rssileds.init        |    75 +
 package/network/utils/rssileds/src/rssileds.c |   290 +
 package/network/utils/tcpdump/Makefile        |    90 +
 .../patches/001-remove_pcap_debug.patch       |    23 +
 .../002-remove_static_libpcap_check.patch     |    73 +
 .../tcpdump/patches/100-tcpdump_mini.patch    |   844 +
 package/network/utils/umbim/Makefile          |    46 +
 .../umbim/files/lib/netifd/proto/mbim.sh      |   180 +
 package/network/utils/uqmi/Makefile           |    50 +
 .../utils/uqmi/files/lib/netifd/proto/qmi.sh  |   246 +
 package/network/utils/wireless-tools/Makefile |    92 +
 .../wireless-tools/patches/001-debian.patch   |    35 +
 ...-fix-iwconfig-power-argument-parsing.patch |    13 +
 .../patches/003-we_essential_def.patch        |   359 +
 .../patches/004-increase_iwlist_buffer.patch  |    46 +
 package/network/utils/wpan-tools/Makefile     |    36 +
 package/network/utils/wwan/Makefile           |    45 +
 .../network/utils/wwan/files/data/0421-03a7   |     6 +
 .../network/utils/wwan/files/data/0421-060d   |     6 +
 .../network/utils/wwan/files/data/0421-060e   |     6 +
 .../network/utils/wwan/files/data/0421-0612   |     6 +
 .../network/utils/wwan/files/data/0421-0619   |     6 +
 .../network/utils/wwan/files/data/0421-061e   |     6 +
 .../network/utils/wwan/files/data/0421-0623   |     6 +
 .../network/utils/wwan/files/data/0421-0629   |     6 +
 .../network/utils/wwan/files/data/0421-062d   |     6 +
 .../network/utils/wwan/files/data/0421-062f   |     6 +
 .../network/utils/wwan/files/data/0421-0638   |     6 +
 .../network/utils/wwan/files/data/05c6-0016   |     6 +
 .../network/utils/wwan/files/data/05c6-0023   |     5 +
 .../network/utils/wwan/files/data/05c6-00a0   |     6 +
 .../network/utils/wwan/files/data/05c6-6000   |     5 +
 .../network/utils/wwan/files/data/05c6-9000   |     5 +
 .../network/utils/wwan/files/data/07d1-3e01   |     5 +
 .../network/utils/wwan/files/data/07d1-3e02   |     5 +
 .../network/utils/wwan/files/data/07d1-7e11   |     6 +
 .../network/utils/wwan/files/data/0af0-4005   |     4 +
 .../network/utils/wwan/files/data/0af0-6901   |     5 +
 .../network/utils/wwan/files/data/0af0-7201   |     5 +
 .../network/utils/wwan/files/data/0af0-8120   |     4 +
 .../network/utils/wwan/files/data/0af0-9200   |     5 +
 .../network/utils/wwan/files/data/0b3c-c000   |     4 +
 .../network/utils/wwan/files/data/0b3c-c001   |     4 +
 .../network/utils/wwan/files/data/0b3c-c002   |     4 +
 .../network/utils/wwan/files/data/0b3c-c003   |     5 +
 .../network/utils/wwan/files/data/0b3c-c004   |     4 +
 .../network/utils/wwan/files/data/0b3c-c005   |     4 +
 .../network/utils/wwan/files/data/0b3c-c00a   |     4 +
 .../network/utils/wwan/files/data/0b3c-c00b   |     4 +
 .../network/utils/wwan/files/data/0bdb-1900   |     6 +
 .../network/utils/wwan/files/data/0bdb-1902   |     6 +
 .../network/utils/wwan/files/data/0bdb-190a   |     6 +
 .../network/utils/wwan/files/data/0bdb-190d   |     6 +
 .../network/utils/wwan/files/data/0bdb-1910   |     6 +
 .../network/utils/wwan/files/data/0c88-17da   |     5 +
 .../network/utils/wwan/files/data/0c88-180a   |     5 +
 .../network/utils/wwan/files/data/0f3d-68a2   |     4 +
 .../network/utils/wwan/files/data/0f3d-68aa   |     5 +
 .../network/utils/wwan/files/data/1004-6124   |     6 +
 .../network/utils/wwan/files/data/1004-6141   |     6 +
 .../network/utils/wwan/files/data/1004-6157   |     6 +
 .../network/utils/wwan/files/data/1004-618f   |     5 +
 .../network/utils/wwan/files/data/106c-3711   |     6 +
 .../network/utils/wwan/files/data/106c-3714   |     6 +
 .../network/utils/wwan/files/data/106c-3715   |     6 +
 .../network/utils/wwan/files/data/106c-3716   |     6 +
 .../network/utils/wwan/files/data/106c-3717   |     6 +
 .../network/utils/wwan/files/data/106c-3718   |     4 +
 .../network/utils/wwan/files/data/106c-3721   |     4 +
 .../network/utils/wwan/files/data/1199-0017   |     5 +
 .../network/utils/wwan/files/data/1199-0018   |     5 +
 .../network/utils/wwan/files/data/1199-0019   |     5 +
 .../network/utils/wwan/files/data/1199-0020   |     5 +
 .../network/utils/wwan/files/data/1199-0021   |     5 +
 .../network/utils/wwan/files/data/1199-0022   |     5 +
 .../network/utils/wwan/files/data/1199-0023   |     5 +
 .../network/utils/wwan/files/data/1199-0024   |     5 +
 .../network/utils/wwan/files/data/1199-0025   |     5 +
 .../network/utils/wwan/files/data/1199-0026   |     5 +
 .../network/utils/wwan/files/data/1199-0027   |     5 +
 .../network/utils/wwan/files/data/1199-0028   |     5 +
 .../network/utils/wwan/files/data/1199-0112   |     5 +
 .../network/utils/wwan/files/data/1199-0120   |     5 +
 .../network/utils/wwan/files/data/1199-0218   |     5 +
 .../network/utils/wwan/files/data/1199-0220   |     5 +
 .../network/utils/wwan/files/data/1199-0224   |     5 +
 .../network/utils/wwan/files/data/1199-0301   |     5 +
 .../network/utils/wwan/files/data/1199-6802   |     5 +
 .../network/utils/wwan/files/data/1199-6803   |     5 +
 .../network/utils/wwan/files/data/1199-6804   |     5 +
 .../network/utils/wwan/files/data/1199-6805   |     5 +
 .../network/utils/wwan/files/data/1199-6808   |     5 +
 .../network/utils/wwan/files/data/1199-6809   |     5 +
 .../network/utils/wwan/files/data/1199-6813   |     5 +
 .../network/utils/wwan/files/data/1199-6815   |     5 +
 .../network/utils/wwan/files/data/1199-6816   |     5 +
 .../network/utils/wwan/files/data/1199-6820   |     5 +
 .../network/utils/wwan/files/data/1199-6821   |     5 +
 .../network/utils/wwan/files/data/1199-6822   |     5 +
 .../network/utils/wwan/files/data/1199-6833   |     5 +
 .../network/utils/wwan/files/data/1199-6834   |     5 +
 .../network/utils/wwan/files/data/1199-6835   |     5 +
 .../network/utils/wwan/files/data/1199-6838   |     5 +
 .../network/utils/wwan/files/data/1199-6839   |     5 +
 .../network/utils/wwan/files/data/1199-683a   |     5 +
 .../network/utils/wwan/files/data/1199-683b   |     5 +
 .../network/utils/wwan/files/data/1199-6850   |     5 +
 .../network/utils/wwan/files/data/1199-6851   |     5 +
 .../network/utils/wwan/files/data/1199-6852   |     5 +
 .../network/utils/wwan/files/data/1199-6853   |     5 +
 .../network/utils/wwan/files/data/1199-6855   |     5 +
 .../network/utils/wwan/files/data/1199-6856   |     5 +
 .../network/utils/wwan/files/data/1199-6859   |     5 +
 .../network/utils/wwan/files/data/1199-685a   |     5 +
 .../network/utils/wwan/files/data/1199-6880   |     5 +
 .../network/utils/wwan/files/data/1199-6890   |     5 +
 .../network/utils/wwan/files/data/1199-6891   |     5 +
 .../network/utils/wwan/files/data/1199-6892   |     5 +
 .../network/utils/wwan/files/data/1199-6893   |     5 +
 .../network/utils/wwan/files/data/1199-68a2   |     4 +
 .../network/utils/wwan/files/data/1199-68aa   |     5 +
 .../network/utils/wwan/files/data/12d1-1035   |     5 +
 .../network/utils/wwan/files/data/12d1-1404   |     4 +
 .../network/utils/wwan/files/data/12d1-1406   |     5 +
 .../network/utils/wwan/files/data/12d1-140b   |     5 +
 .../network/utils/wwan/files/data/12d1-140c   |     4 +
 .../network/utils/wwan/files/data/12d1-1412   |     5 +
 .../network/utils/wwan/files/data/12d1-141b   |     5 +
 .../network/utils/wwan/files/data/12d1-1433   |     5 +
 .../network/utils/wwan/files/data/12d1-1436   |     5 +
 .../network/utils/wwan/files/data/12d1-1444   |     5 +
 .../network/utils/wwan/files/data/12d1-144e   |     5 +
 .../network/utils/wwan/files/data/12d1-1464   |     5 +
 .../network/utils/wwan/files/data/12d1-1465   |     5 +
 .../network/utils/wwan/files/data/12d1-1491   |     5 +
 .../network/utils/wwan/files/data/12d1-14a5   |     5 +
 .../network/utils/wwan/files/data/12d1-14a8   |     5 +
 .../network/utils/wwan/files/data/12d1-14ac   |     4 +
 .../network/utils/wwan/files/data/12d1-14ae   |     5 +
 .../network/utils/wwan/files/data/12d1-14c6   |     4 +
 .../network/utils/wwan/files/data/12d1-14c8   |     4 +
 .../network/utils/wwan/files/data/12d1-14c9   |     4 +
 .../network/utils/wwan/files/data/12d1-14ca   |     4 +
 .../network/utils/wwan/files/data/12d1-14cb   |     5 +
 .../network/utils/wwan/files/data/12d1-14cc   |     4 +
 .../network/utils/wwan/files/data/12d1-14cf   |     5 +
 .../network/utils/wwan/files/data/12d1-14d2   |     4 +
 .../network/utils/wwan/files/data/12d1-1506   |     5 +
 .../network/utils/wwan/files/data/12d1-150a   |     4 +
 .../network/utils/wwan/files/data/12d1-150c   |     4 +
 .../network/utils/wwan/files/data/12d1-150f   |     4 +
 .../network/utils/wwan/files/data/12d1-151b   |     4 +
 .../network/utils/wwan/files/data/12d1-151d   |     5 +
 .../network/utils/wwan/files/data/12d1-156c   |     5 +
 .../network/utils/wwan/files/data/12d1-1576   |     4 +
 .../network/utils/wwan/files/data/12d1-1577   |     4 +
 .../network/utils/wwan/files/data/12d1-1578   |     4 +
 .../network/utils/wwan/files/data/12d1-1589   |     4 +
 .../network/utils/wwan/files/data/12d1-1c05   |     5 +
 .../network/utils/wwan/files/data/12d1-1c07   |     5 +
 .../network/utils/wwan/files/data/12d1-1c08   |     5 +
 .../network/utils/wwan/files/data/12d1-1c10   |     5 +
 .../network/utils/wwan/files/data/12d1-1c12   |     5 +
 .../network/utils/wwan/files/data/12d1-1c1e   |     4 +
 .../network/utils/wwan/files/data/12d1-1c1f   |     4 +
 .../network/utils/wwan/files/data/12d1-1c23   |     5 +
 .../network/utils/wwan/files/data/12d1-1f16   |     4 +
 .../network/utils/wwan/files/data/1410-1400   |     5 +
 .../network/utils/wwan/files/data/1410-1410   |     5 +
 .../network/utils/wwan/files/data/1410-1420   |     5 +
 .../network/utils/wwan/files/data/1410-1430   |     5 +
 .../network/utils/wwan/files/data/1410-1450   |     5 +
 .../network/utils/wwan/files/data/1410-2100   |     5 +
 .../network/utils/wwan/files/data/1410-2110   |     5 +
 .../network/utils/wwan/files/data/1410-2120   |     5 +
 .../network/utils/wwan/files/data/1410-2130   |     5 +
 .../network/utils/wwan/files/data/1410-2400   |     5 +
 .../network/utils/wwan/files/data/1410-2410   |     5 +
 .../network/utils/wwan/files/data/1410-2420   |     5 +
 .../network/utils/wwan/files/data/1410-4100   |     5 +
 .../network/utils/wwan/files/data/1410-4400   |     5 +
 .../network/utils/wwan/files/data/1410-6000   |     5 +
 .../network/utils/wwan/files/data/1410-6001   |     5 +
 .../network/utils/wwan/files/data/1410-6002   |     5 +
 .../network/utils/wwan/files/data/1410-6010   |     5 +
 .../network/utils/wwan/files/data/1410-7001   |     5 +
 .../network/utils/wwan/files/data/1410-7003   |     5 +
 .../network/utils/wwan/files/data/1410-7030   |     5 +
 .../network/utils/wwan/files/data/1410-7031   |     6 +
 .../network/utils/wwan/files/data/1410-7041   |     5 +
 .../network/utils/wwan/files/data/1410-7042   |     5 +
 .../network/utils/wwan/files/data/1410-9011   |     4 +
 .../network/utils/wwan/files/data/1410-b001   |     4 +
 .../network/utils/wwan/files/data/1529-3100   |     6 +
 .../network/utils/wwan/files/data/16d5-6202   |     5 +
 .../network/utils/wwan/files/data/16d5-6501   |     5 +
 .../network/utils/wwan/files/data/16d5-6502   |     5 +
 .../network/utils/wwan/files/data/16d5-6603   |     6 +
 .../network/utils/wwan/files/data/16d5-900d   |     6 +
 .../network/utils/wwan/files/data/16d8-5141   |     6 +
 .../network/utils/wwan/files/data/16d8-5533   |     6 +
 .../network/utils/wwan/files/data/16d8-5543   |     6 +
 .../network/utils/wwan/files/data/16d8-5553   |     6 +
 .../network/utils/wwan/files/data/16d8-6002   |     5 +
 .../network/utils/wwan/files/data/16d8-6006   |     5 +
 .../network/utils/wwan/files/data/16d8-6007   |     4 +
 .../network/utils/wwan/files/data/16d8-6008   |     4 +
 .../network/utils/wwan/files/data/16d8-6522   |     6 +
 .../network/utils/wwan/files/data/16d8-6523   |     6 +
 .../network/utils/wwan/files/data/16d8-6532   |     6 +
 .../network/utils/wwan/files/data/16d8-6533   |     6 +
 .../network/utils/wwan/files/data/16d8-6543   |     6 +
 .../network/utils/wwan/files/data/16d8-680a   |     6 +
 .../network/utils/wwan/files/data/19d2-0001   |     5 +
 .../network/utils/wwan/files/data/19d2-0002   |     4 +
 .../network/utils/wwan/files/data/19d2-0015   |     5 +
 .../network/utils/wwan/files/data/19d2-0016   |     5 +
 .../network/utils/wwan/files/data/19d2-0017   |     4 +
 .../network/utils/wwan/files/data/19d2-0018   |     5 +
 .../network/utils/wwan/files/data/19d2-0019   |     4 +
 .../network/utils/wwan/files/data/19d2-0022   |     5 +
 .../network/utils/wwan/files/data/19d2-0024   |     5 +
 .../network/utils/wwan/files/data/19d2-0025   |     4 +
 .../network/utils/wwan/files/data/19d2-0031   |     4 +
 .../network/utils/wwan/files/data/19d2-0033   |     5 +
 .../network/utils/wwan/files/data/19d2-0037   |     5 +
 .../network/utils/wwan/files/data/19d2-0039   |     5 +
 .../network/utils/wwan/files/data/19d2-0042   |     4 +
 .../network/utils/wwan/files/data/19d2-0052   |     4 +
 .../network/utils/wwan/files/data/19d2-0055   |     4 +
 .../network/utils/wwan/files/data/19d2-0057   |     5 +
 .../network/utils/wwan/files/data/19d2-0063   |     4 +
 .../network/utils/wwan/files/data/19d2-0064   |     5 +
 .../network/utils/wwan/files/data/19d2-0066   |     5 +
 .../network/utils/wwan/files/data/19d2-0073   |     5 +
 .../network/utils/wwan/files/data/19d2-0079   |     5 +
 .../network/utils/wwan/files/data/19d2-0082   |     5 +
 .../network/utils/wwan/files/data/19d2-0086   |     5 +
 .../network/utils/wwan/files/data/19d2-0091   |     5 +
 .../network/utils/wwan/files/data/19d2-0094   |     5 +
 .../network/utils/wwan/files/data/19d2-0104   |     4 +
 .../network/utils/wwan/files/data/19d2-0108   |     5 +
 .../network/utils/wwan/files/data/19d2-0116   |     6 +
 .../network/utils/wwan/files/data/19d2-0117   |     5 +
 .../network/utils/wwan/files/data/19d2-0121   |     4 +
 .../network/utils/wwan/files/data/19d2-0124   |     4 +
 .../network/utils/wwan/files/data/19d2-0128   |     5 +
 .../network/utils/wwan/files/data/19d2-0142   |     6 +
 .../network/utils/wwan/files/data/19d2-0143   |     6 +
 .../network/utils/wwan/files/data/19d2-0152   |     5 +
 .../network/utils/wwan/files/data/19d2-0157   |     4 +
 .../network/utils/wwan/files/data/19d2-0167   |     4 +
 .../network/utils/wwan/files/data/19d2-0170   |     6 +
 .../network/utils/wwan/files/data/19d2-0199   |     4 +
 .../network/utils/wwan/files/data/19d2-0257   |     4 +
 .../network/utils/wwan/files/data/19d2-0265   |     4 +
 .../network/utils/wwan/files/data/19d2-0284   |     4 +
 .../network/utils/wwan/files/data/19d2-0326   |     4 +
 .../network/utils/wwan/files/data/19d2-1003   |     6 +
 .../network/utils/wwan/files/data/19d2-1008   |     4 +
 .../network/utils/wwan/files/data/19d2-1010   |     4 +
 .../network/utils/wwan/files/data/19d2-1015   |     6 +
 .../network/utils/wwan/files/data/19d2-1018   |     4 +
 .../network/utils/wwan/files/data/19d2-1172   |     6 +
 .../network/utils/wwan/files/data/19d2-1173   |     6 +
 .../network/utils/wwan/files/data/19d2-1176   |     4 +
 .../network/utils/wwan/files/data/19d2-1177   |     6 +
 .../network/utils/wwan/files/data/19d2-1181   |     6 +
 .../network/utils/wwan/files/data/19d2-1203   |     6 +
 .../network/utils/wwan/files/data/19d2-1208   |     6 +
 .../network/utils/wwan/files/data/19d2-1211   |     6 +
 .../network/utils/wwan/files/data/19d2-1212   |     6 +
 .../network/utils/wwan/files/data/19d2-1217   |     6 +
 .../network/utils/wwan/files/data/19d2-1218   |     6 +
 .../network/utils/wwan/files/data/19d2-1220   |     6 +
 .../network/utils/wwan/files/data/19d2-1222   |     6 +
 .../network/utils/wwan/files/data/19d2-1245   |     4 +
 .../network/utils/wwan/files/data/19d2-1252   |     4 +
 .../network/utils/wwan/files/data/19d2-1254   |     4 +
 .../network/utils/wwan/files/data/19d2-1256   |     4 +
 .../network/utils/wwan/files/data/19d2-1270   |     4 +
 .../network/utils/wwan/files/data/19d2-1401   |     4 +
 .../network/utils/wwan/files/data/19d2-1402   |     4 +
 .../network/utils/wwan/files/data/19d2-1426   |     4 +
 .../network/utils/wwan/files/data/19d2-1512   |     6 +
 .../network/utils/wwan/files/data/19d2-1515   |     6 +
 .../network/utils/wwan/files/data/19d2-1518   |     6 +
 .../network/utils/wwan/files/data/19d2-1519   |     6 +
 .../network/utils/wwan/files/data/19d2-1522   |     6 +
 .../network/utils/wwan/files/data/19d2-1525   |     6 +
 .../network/utils/wwan/files/data/19d2-1527   |     6 +
 .../network/utils/wwan/files/data/19d2-1537   |     6 +
 .../network/utils/wwan/files/data/19d2-1538   |     6 +
 .../network/utils/wwan/files/data/19d2-1544   |     6 +
 .../network/utils/wwan/files/data/19d2-2002   |     4 +
 .../network/utils/wwan/files/data/19d2-2003   |     5 +
 .../network/utils/wwan/files/data/19d2-ffdd   |     5 +
 .../network/utils/wwan/files/data/19d2-ffe4   |     6 +
 .../network/utils/wwan/files/data/19d2-ffe9   |     5 +
 .../network/utils/wwan/files/data/19d2-fff1   |     5 +
 .../network/utils/wwan/files/data/19d2-fffb   |     5 +
 .../network/utils/wwan/files/data/19d2-fffc   |     5 +
 .../network/utils/wwan/files/data/19d2-fffd   |     5 +
 .../network/utils/wwan/files/data/19d2-fffe   |     5 +
 .../network/utils/wwan/files/data/19d2-ffff   |     5 +
 .../network/utils/wwan/files/data/1a8d-1002   |     5 +
 .../network/utils/wwan/files/data/1a8d-1003   |     5 +
 .../network/utils/wwan/files/data/1a8d-1007   |     5 +
 .../network/utils/wwan/files/data/1a8d-1009   |     5 +
 .../network/utils/wwan/files/data/1a8d-100c   |     5 +
 .../network/utils/wwan/files/data/1a8d-100d   |     5 +
 .../network/utils/wwan/files/data/1a8d-2006   |     6 +
 .../network/utils/wwan/files/data/1bbb-0000   |     5 +
 .../network/utils/wwan/files/data/1bbb-0012   |     6 +
 .../network/utils/wwan/files/data/1bbb-0017   |     5 +
 .../network/utils/wwan/files/data/1bbb-0052   |     5 +
 .../network/utils/wwan/files/data/1bbb-00b7   |     5 +
 .../network/utils/wwan/files/data/1bbb-00ca   |     6 +
 .../network/utils/wwan/files/data/1bbb-011e   |     4 +
 .../network/utils/wwan/files/data/1bbb-0203   |     4 +
 .../network/utils/wwan/files/data/1c9e-6060   |     6 +
 .../network/utils/wwan/files/data/1c9e-6061   |     6 +
 .../network/utils/wwan/files/data/1c9e-9000   |     6 +
 .../network/utils/wwan/files/data/1c9e-9603   |     5 +
 .../network/utils/wwan/files/data/1c9e-9605   |     5 +
 .../network/utils/wwan/files/data/1c9e-9607   |     5 +
 .../network/utils/wwan/files/data/1c9e-9801   |     6 +
 .../network/utils/wwan/files/data/1c9e-9900   |     6 +
 .../network/utils/wwan/files/data/1e0e-9000   |     5 +
 .../network/utils/wwan/files/data/1e0e-9100   |     5 +
 .../network/utils/wwan/files/data/1e0e-9200   |     5 +
 .../network/utils/wwan/files/data/1e0e-ce16   |     5 +
 .../network/utils/wwan/files/data/1e0e-cefe   |     6 +
 .../network/utils/wwan/files/data/2001-7d00   |     6 +
 .../network/utils/wwan/files/data/2001-7d01   |     5 +
 .../network/utils/wwan/files/data/2001-7d02   |     5 +
 .../network/utils/wwan/files/data/2001-7d03   |     5 +
 .../network/utils/wwan/files/data/211f-6801   |     5 +
 .../network/utils/wwan/files/data/2357-0201   |     4 +
 .../network/utils/wwan/files/data/2357-0202   |     4 +
 .../network/utils/wwan/files/data/2357-0203   |     4 +
 .../network/utils/wwan/files/data/2357-9000   |     4 +
 .../network/utils/wwan/files/data/413c-8114   |     5 +
 .../network/utils/wwan/files/data/413c-8115   |     5 +
 .../network/utils/wwan/files/data/413c-8116   |     5 +
 .../network/utils/wwan/files/data/413c-8117   |     5 +
 .../network/utils/wwan/files/data/413c-8118   |     5 +
 .../network/utils/wwan/files/data/413c-8128   |     5 +
 .../network/utils/wwan/files/data/413c-8129   |     5 +
 .../network/utils/wwan/files/data/413c-8133   |     5 +
 .../network/utils/wwan/files/data/413c-8134   |     5 +
 .../network/utils/wwan/files/data/413c-8135   |     5 +
 .../network/utils/wwan/files/data/413c-8136   |     5 +
 .../network/utils/wwan/files/data/413c-8137   |     5 +
 .../network/utils/wwan/files/data/413c-8138   |     5 +
 .../network/utils/wwan/files/data/413c-8147   |     6 +
 .../network/utils/wwan/files/data/413c-8180   |     5 +
 .../network/utils/wwan/files/data/413c-8181   |     5 +
 .../network/utils/wwan/files/data/413c-8182   |     5 +
 .../network/utils/wwan/files/data/413c-8186   |     4 +
 .../network/utils/wwan/files/data/413c-8194   |     4 +
 .../network/utils/wwan/files/data/413c-8195   |     4 +
 .../network/utils/wwan/files/data/413c-8196   |     4 +
 .../network/utils/wwan/files/data/413c-819b   |     5 +
 package/network/utils/wwan/files/wwan.sh      |   119 +
 package/network/utils/wwan/files/wwan.usb     |    18 +
 package/network/utils/wwan/files/wwan.usbmisc |    27 +
 package/network/utils/xtables-addons/Makefile |   151 +
 .../002-fix-kernel-version-detection.patch    |    11 +
 .../patches/100-add-rtsp-conntrack.patch      |  1526 +
 .../patches/200-add-lua-packetscript.patch    | 18158 +++++++++++
 .../patches/201-fix-lua-packetscript.patch    |   107 +
 .../patches/300-geoip-endian-detection.patch  |    18 +
 package/system/ca-certificates/Makefile       |    62 +
 package/system/fstools/Makefile               |   110 +
 package/system/fstools/files/fstab.default    |     2 +
 package/system/fstools/files/fstab.init       |    16 +
 package/system/fstools/files/mount.hotplug    |     1 +
 package/system/fstools/files/snapshot         |   111 +
 package/system/fwtool/Makefile                |    47 +
 package/system/fwtool/src/crc32.h             |    48 +
 package/system/fwtool/src/fwimage.h           |    39 +
 package/system/fwtool/src/fwtool.c            |   443 +
 package/system/fwtool/src/utils.h             |   116 +
 package/system/lede-keyring/Makefile          |    40 +
 package/system/mountd/Makefile                |    48 +
 package/system/mountd/files/mountd.config     |     3 +
 package/system/mountd/files/mountd.init       |    22 +
 package/system/mtd/Makefile                   |    49 +
 package/system/mtd/src/Makefile               |    24 +
 package/system/mtd/src/crc32.c                |    95 +
 package/system/mtd/src/crc32.h                |    26 +
 package/system/mtd/src/fis.c                  |   262 +
 package/system/mtd/src/fis.h                  |    14 +
 package/system/mtd/src/imagetag.c             |   410 +
 package/system/mtd/src/jffs2.c                |   366 +
 package/system/mtd/src/jffs2.h                |   216 +
 package/system/mtd/src/linksys_bootcount.c    |   115 +
 package/system/mtd/src/md5.c                  |   307 +
 package/system/mtd/src/md5.h                  |    65 +
 package/system/mtd/src/mtd.c                  |  1027 +
 package/system/mtd/src/mtd.h                  |    32 +
 package/system/mtd/src/seama.c                |   188 +
 package/system/mtd/src/seama.h                |   108 +
 package/system/mtd/src/trx.c                  |   247 +
 package/system/mtd/src/wrgg.c                 |   190 +
 package/system/mtd/src/wrgg.h                 |    20 +
 package/system/opkg/Makefile                  |   198 +
 package/system/opkg/files/20_migrate-feeds    |     9 +
 package/system/opkg/files/customfeeds.conf    |     3 +
 package/system/opkg/files/opkg-key            |    56 +
 package/system/opkg/files/opkg-smime.conf     |     6 +
 package/system/opkg/files/opkg.conf           |     4 +
 .../system/opkg/patches/001-ship-pkg-m4.patch |   168 +
 .../system/opkg/patches/002-no-shave.patch    |    37 +
 .../system/opkg/patches/004-host_cpu.patch    |    20 +
 .../opkg/patches/007-force_static.patch       |    71 +
 .../opkg/patches/009-remove-upgrade-all.patch |    41 +
 .../patches/011-old-config-location.patch     |    12 +
 ...-strip-trailing-conffiles-whitespace.patch |    23 +
 .../opkg/patches/014-errors-to-stderr.patch   |    15 +
 .../opkg/patches/020-avoid_getline.patch      |   317 +
 .../opkg/patches/030-fix-double-free.patch    |    10 +
 .../040-wrap-descriptions-only-on-ttys.patch  |    31 +
 .../050-add-case-insensitive-flag.patch       |   169 +
 .../opkg/patches/060-add-find-command.patch   |    58 +
 .../patches/070-use_gzipped_pkg_list.patch    |   120 +
 .../080-suppress-blank-package-fields.patch   |    16 +
 .../090-suppress-blank-provides-field.patch   |    11 +
 .../opkg/patches/100-add-force-checksum.patch |    85 +
 package/system/opkg/patches/110-upgrade.patch |    50 +
 .../opkg/patches/200-usign_support.patch      |    91 +
 .../patches/210-add-force-signature.patch     |    70 +
 .../patches/220-drop-release-support.patch    |   812 +
 .../opkg/patches/230-drop_md5_support.patch   |   192 +
 .../240-fix-force-checksum-for-sha256.patch   |    31 +
 .../patches/250-add-lists-dir-switch.patch    |    39 +
 .../patches/260-add-print-package-size.patch  |    74 +
 .../opkg/patches/270-fix-use-after-free.patch |    11 +
 ...-prerm-and-postrm-scripts-on-upgrade.patch |    73 +
 package/system/procd/Makefile                 |   156 +
 .../system/procd/files/hotplug-preinit.json   |    18 +
 package/system/procd/files/hotplug.json       |    69 +
 package/system/procd/files/nand-preinit.sh    |    21 +
 package/system/procd/files/nand.sh            |   366 +
 package/system/procd/files/procd.sh           |   460 +
 package/system/procd/files/reload_config      |    15 +
 package/system/rpcd/Makefile                  |    98 +
 package/system/rpcd/files/rpcd.config         |     7 +
 package/system/rpcd/files/rpcd.init           |    21 +
 package/system/ubox/Makefile                  |    49 +
 package/system/ubox/files/log.init            |   100 +
 package/system/ubus/Makefile                  |    80 +
 package/system/uci/Makefile                   |    94 +
 package/system/uci/files/lib/config/uci.sh    |   137 +
 package/system/usign/Makefile                 |    46 +
 package/system/zram-swap/Makefile             |    46 +
 package/system/zram-swap/files/zram.init      |   132 +
 package/utils/admswconfig/Makefile            |    54 +
 package/utils/admswconfig/files/admswconfig   |    68 +
 .../utils/admswconfig/files/admswswitch.sh    |    28 +
 .../admswconfig/patches/001-matrix.patch      |    15 +
 .../admswconfig/patches/002-fix-musl.patch    |    11 +
 package/utils/bsdiff/Makefile                 |    79 +
 package/utils/bsdiff/patches/001-musl.patch   |    84 +
 package/utils/busybox/Config-defaults.in      |  2805 ++
 package/utils/busybox/Config.in               |    26 +
 package/utils/busybox/Makefile                |   121 +
 package/utils/busybox/config/Config.in        |   865 +
 .../utils/busybox/config/archival/Config.in   |   379 +
 .../busybox/config/console-tools/Config.in    |   176 +
 .../utils/busybox/config/coreutils/Config.in  |   987 +
 .../busybox/config/debianutils/Config.in      |    80 +
 .../utils/busybox/config/e2fsprogs/Config.in  |    67 +
 .../config/e2fsprogs/old_e2fsprogs/Config.in  |    69 +
 .../utils/busybox/config/editors/Config.in    |   234 +
 .../utils/busybox/config/findutils/Config.in  |   269 +
 package/utils/busybox/config/init/Config.in   |   199 +
 package/utils/busybox/config/libbb/Config.in  |   273 +
 .../utils/busybox/config/loginutils/Config.in |   338 +
 .../utils/busybox/config/mailutils/Config.in  |    55 +
 .../utils/busybox/config/miscutils/Config.in  |   792 +
 .../utils/busybox/config/modutils/Config.in   |   266 +
 .../utils/busybox/config/networking/Config.in |  1165 +
 .../busybox/config/networking/udhcp/Config.in |   171 +
 .../utils/busybox/config/printutils/Config.in |    26 +
 package/utils/busybox/config/procps/Config.in |   273 +
 package/utils/busybox/config/runit/Config.in  |    84 +
 .../utils/busybox/config/selinux/Config.in    |   124 +
 package/utils/busybox/config/shell/Config.in  |   444 +
 .../utils/busybox/config/sysklogd/Config.in   |   166 +
 .../utils/busybox/config/util-linux/Config.in |   830 +
 .../config/util-linux/volume_id/Config.in     |   312 +
 package/utils/busybox/convert_defaults.pl     |    13 +
 package/utils/busybox/convert_menuconfig.pl   |    76 +
 package/utils/busybox/files/cron              |    38 +
 package/utils/busybox/files/ntpd-hotplug      |     2 +
 package/utils/busybox/files/sysntpd           |    86 +
 .../patches/001-resource_h_include.patch      |    10 +
 ...om-do-not-require-that-to-should-hav.patch |    37 +
 .../busybox/patches/100-trylink_bash.patch    |     8 +
 .../patches/101-gen_build_files_bash.patch    |     8 +
 .../patches/102-trylink_mktemp_fix.patch      |    20 +
 .../patches/110-no_static_libgcc.patch        |    11 +
 .../patches/120-remove_uclibc_rpc_check.patch |    12 +
 .../patches/130-mconf_missing_sigwinch.patch  |    13 +
 .../patches/200-udhcpc_reduce_msgs.patch      |    18 +
 .../patches/201-udhcpc_changed_ifindex.patch  |    15 +
 .../203-udhcpc_renew_no_deconfig.patch        |    10 +
 .../busybox/patches/210-add_netmsg_util.patch |   103 +
 .../busybox/patches/220-add_lock_util.patch   |   182 +
 .../busybox/patches/240-telnetd_intr.patch    |    10 +
 .../busybox/patches/250-date-k-flag.patch     |    91 +
 .../270-libbb_make_unicode_printable.patch    |    20 +
 .../301-ip-link-fix-netlink-msg-size.patch    |    11 +
 .../patches/302-netlink-alignment.patch       |   100 +
 .../303-ip-route-fix-high-table-ids.patch     |   486 +
 package/utils/bzip2/Makefile                  |   106 +
 package/utils/e2fsprogs/Makefile              |   259 +
 package/utils/e2fsprogs/files/e2fsck.conf     |     3 +
 package/utils/e2fsprogs/files/e2fsck.sh       |    38 +
 .../patches/001-com_err_version.patch         |    13 +
 .../patches/002-fix-subst-host-build.patch    |    10 +
 package/utils/f2fs-tools/Makefile             |    90 +
 .../f2fs-tools/patches/001-compile.patch      |    19 +
 .../patches/010-include-byteswap-h.patch      |    10 +
 .../f2fs-tools/patches/020-no_selinux.patch   |    55 +
 package/utils/fbtest/Makefile                 |    39 +
 package/utils/fbtest/src/Makefile             |    14 +
 package/utils/fbtest/src/fbtest.c             |   446 +
 package/utils/fuse/Makefile                   |   101 +
 .../fuse/patches/100-missing_includes.patch   |    10 +
 .../fuse/patches/112-no_break_on_mknod.patch  |    11 +
 ...t_arm64_fuse_kernel_h_clean_includes.patch |    30 +
 package/utils/jsonfilter/Makefile             |    34 +
 package/utils/lua/Makefile                    |   177 +
 .../010-lua-5.1.3-lnum-full-260308.patch      |  3747 +++
 .../patches-host/011-lnum-use-double.patch    |    11 +
 ...2-lnum-fix-ltle-relational-operators.patch |    22 +
 .../patches-host/015-lnum-ppc-compat.patch    |    11 +
 .../030-archindependent-bytecode.patch        |   111 +
 .../lua/patches-host/100-no_readline.patch    |    49 +
 .../010-lua-5.1.3-lnum-full-260308.patch      |  3736 +++
 .../lua/patches/011-lnum-use-double.patch     |    11 +
 ...2-lnum-fix-ltle-relational-operators.patch |    22 +
 .../lua/patches/015-lnum-ppc-compat.patch     |    11 +
 .../utils/lua/patches/020-shared_liblua.patch |   140 +
 .../030-archindependent-bytecode.patch        |   111 +
 .../patches/040-use-symbolic-functions.patch  |    11 +
 .../utils/lua/patches/050-honor-cflags.patch  |    11 +
 .../utils/lua/patches/100-no_readline.patch   |    49 +
 package/utils/lua/patches/200-lua-path.patch  |    15 +
 .../lua/patches/300-opcode_performance.patch  |   363 +
 package/utils/mdadm/Makefile                  |    62 +
 package/utils/mdadm/files/mdadm.config        |     3 +
 package/utils/mdadm/files/mdadm.init          |    34 +
 package/utils/mdadm/patches/000-compile.patch |    11 +
 .../mdadm/patches/100-cross_compile.patch     |    19 +
 .../utils/mdadm/patches/200-reduce_size.patch |    25 +
 package/utils/mtd-utils/Makefile              |    80 +
 .../mtd-utils/patches/010-fix-rpmatch.patch   |    19 +
 .../mtd-utils/patches/100-fix_includes.patch  |    10 +
 .../mtd-utils/patches/130-lzma_jffs2.patch    |  5029 +++
 package/utils/nvram/Makefile                  |    51 +
 package/utils/nvram/files/nvram.init          |    98 +
 package/utils/nvram/src/Makefile              |     7 +
 package/utils/nvram/src/cli.c                 |   246 +
 package/utils/nvram/src/crc.c                 |    69 +
 package/utils/nvram/src/nvram.c               |   540 +
 package/utils/nvram/src/nvram.h               |   123 +
 package/utils/nvram/src/sdinitvals.h          |    30 +
 package/utils/osafeloader/Makefile            |    38 +
 package/utils/osafeloader/src/Makefile        |     7 +
 package/utils/osafeloader/src/md5.c           |   296 +
 package/utils/osafeloader/src/md5.h           |    45 +
 package/utils/osafeloader/src/osafeloader.c   |   263 +
 package/utils/oseama/Makefile                 |    40 +
 package/utils/oseama/src/Makefile             |     7 +
 package/utils/oseama/src/md5.c                |   296 +
 package/utils/oseama/src/md5.h                |    45 +
 package/utils/oseama/src/oseama.c             |   556 +
 package/utils/otrx/Makefile                   |    40 +
 package/utils/otrx/src/Makefile               |     7 +
 package/utils/otrx/src/otrx.c                 |   577 +
 package/utils/px5g-standalone/Makefile        |    36 +
 package/utils/px5g-standalone/src/Makefile    |    14 +
 .../px5g-standalone/src/library/base64.c      |   264 +
 .../px5g-standalone/src/library/bignum.c      |  2010 ++
 .../utils/px5g-standalone/src/library/rsa.c   |   750 +
 .../utils/px5g-standalone/src/library/sha1.c  |   622 +
 .../px5g-standalone/src/library/timing.c      |   265 +
 .../px5g-standalone/src/library/x509write.c   |  1162 +
 .../px5g-standalone/src/polarssl/base64.h     |    93 +
 .../px5g-standalone/src/polarssl/bignum.h     |   437 +
 .../px5g-standalone/src/polarssl/bn_mul.h     |   731 +
 .../px5g-standalone/src/polarssl/config.h     |   329 +
 .../utils/px5g-standalone/src/polarssl/rsa.h  |   309 +
 .../utils/px5g-standalone/src/polarssl/sha1.h |   150 +
 .../px5g-standalone/src/polarssl/timing.h     |    81 +
 .../utils/px5g-standalone/src/polarssl/x509.h |   549 +
 package/utils/px5g-standalone/src/px5g.c      |   213 +
 package/utils/px5g/Makefile                   |    63 +
 package/utils/px5g/px5g.c                     |   289 +
 package/utils/spidev_test/Makefile            |    40 +
 package/utils/spidev_test/src/spidev_test.c   |   318 +
 package/utils/ugps/Makefile                   |    51 +
 package/utils/ugps/files/gps.config           |     3 +
 package/utils/ugps/files/ugps.init            |    24 +
 package/utils/usbmode/Makefile                |    71 +
 package/utils/usbmode/data/12d1-1f16          |     2 +
 package/utils/usbmode/files/usbmode.hotplug   |     1 +
 package/utils/usbmode/files/usbmode.init      |    12 +
 package/utils/usbreset/Makefile               |    39 +
 package/utils/usbreset/src/usbreset.c         |   235 +
 package/utils/usbutils/Makefile               |    61 +
 package/utils/util-linux/Makefile             |   701 +
 .../0001-fix-uClibc-ng-scanf-check.patch      |    34 +
 .../patches/003-fix_pkgconfig_files.patch     |    76 +
 package/utils/xfsprogs/Makefile               |    89 +
 .../patches/001-automake-compat.patch         |    78 +
 .../utils/xfsprogs/patches/100-no_aio.patch   |    19 +
 .../patches/110-uclibc_no_ustat.patch         |    32 +
 .../xfsprogs/patches/120-portability.patch    |    45 +
 .../patches/130-uclibc_no_xattr.patch         |    32 +
 .../utils/xfsprogs/patches/140-no_po.patch    |    19 +
 .../xfsprogs/patches/150-include_fixes.patch  |    72 +
 .../patches/160-format-security.patch         |    29 +
 rules.mk                                      |   401 +
 scripts/arm-magic.sh                          |    42 +
 scripts/brcmImage.pl                          |   162 +
 scripts/bundle-libraries.sh                   |   110 +
 scripts/checkpatch.pl                         |  3490 +++
 scripts/clang-gcc-wrapper                     |    12 +
 scripts/clean-package.sh                      |    24 +
 scripts/cleanfile                             |   176 +
 scripts/cleanpatch                            |   258 +
 scripts/combined-ext-image.sh                 |    61 +
 scripts/combined-image.sh                     |    34 +
 scripts/config.guess                          |  1438 +
 scripts/config.rpath                          |   666 +
 scripts/config.sub                            |  1813 ++
 scripts/config/.gitignore                     |     9 +
 scripts/config/Makefile                       |    52 +
 scripts/config/README                         |     2 +
 scripts/config/conf.c                         |   703 +
 scripts/config/confdata.c                     |  1252 +
 scripts/config/expr.c                         |  1206 +
 scripts/config/expr.h                         |   239 +
 scripts/config/list.h                         |   131 +
 scripts/config/lkc.h                          |   187 +
 scripts/config/lkc_proto.h                    |    53 +
 scripts/config/lxdialog/.gitignore            |     2 +
 scripts/config/lxdialog/check-lxdialog.sh     |    91 +
 scripts/config/lxdialog/checklist.c           |   332 +
 scripts/config/lxdialog/dialog.h              |   257 +
 scripts/config/lxdialog/inputbox.c            |   301 +
 scripts/config/lxdialog/menubox.c             |   437 +
 scripts/config/lxdialog/textbox.c             |   408 +
 scripts/config/lxdialog/util.c                |   713 +
 scripts/config/lxdialog/yesno.c               |   114 +
 scripts/config/mconf.c                        |  1053 +
 scripts/config/menu.c                         |   697 +
 scripts/config/symbol.c                       |  1386 +
 scripts/config/util.c                         |   147 +
 scripts/config/zconf.gperf                    |    49 +
 scripts/config/zconf.hash.c_shipped           |   250 +
 scripts/config/zconf.l                        |   427 +
 scripts/config/zconf.lex.c_shipped            |  2474 ++
 scripts/config/zconf.tab.c_shipped            |  2478 ++
 scripts/config/zconf.y                        |   754 +
 scripts/deptest.sh                            |   211 +
 scripts/diffconfig.sh                         |    16 +
 scripts/dl_cleanup.py                         |   237 +
 scripts/download.pl                           |   268 +
 scripts/env                                   |   226 +
 scripts/ext-toolchain.sh                      |   581 +
 scripts/feeds                                 |   825 +
 scripts/flashing/adam2flash-502T.pl           |   342 +
 scripts/flashing/adam2flash-fritzbox.pl       |   209 +
 scripts/flashing/adam2flash.pl                |   174 +
 scripts/flashing/adsl2mue_flash.pl            |   170 +
 scripts/flashing/flash.sh                     |    66 +
 scripts/flashing/jungo-image.py               |   283 +
 scripts/gen-dependencies.sh                   |    33 +
 scripts/get_source_date_epoch.sh              |    25 +
 scripts/getver.sh                             |    58 +
 scripts/ipkg-build                            |   160 +
 scripts/ipkg-make-index.sh                    |    34 +
 scripts/kconfig.pl                            |   182 +
 scripts/make-ipkg-dir.sh                      |    21 +
 scripts/md5sum                                |     2 +
 scripts/metadata.pm                           |   270 +
 scripts/mkits.sh                              |   117 +
 scripts/om-fwupgradecfg-gen.sh                |    77 +
 scripts/openbsd.sh                            |    24 +
 scripts/package-metadata.pl                   |   662 +
 scripts/pad_image                             |   100 +
 scripts/patch-kernel.sh                       |    54 +
 scripts/patch-specs.sh                        |    90 +
 scripts/portable_date.sh                      |    11 +
 scripts/redboot-script.pl                     |   111 +
 scripts/relink-lib.sh                         |    14 +
 scripts/remote-gdb                            |    89 +
 scripts/rstrip.sh                             |    49 +
 scripts/slugimage.pl                          |  1217 +
 scripts/srecimage.pl                          |    57 +
 scripts/strip-kmod.sh                         |    55 +
 scripts/symlink-tree.sh                       |    51 +
 scripts/sysupgrade-tar.sh                     |    73 +
 scripts/target-metadata.pl                    |   440 +
 scripts/timestamp.pl                          |    69 +
 scripts/ubinize-image.sh                      |   139 +
 scripts/update-package-md5sum                 |    38 +
 target/Config.in                              |   207 +
 target/Makefile                               |    22 +
 target/imagebuilder/Config.in                 |    16 +
 target/imagebuilder/Makefile                  |    88 +
 target/imagebuilder/files/Makefile            |   204 +
 target/imagebuilder/files/repositories.conf   |     4 +
 target/linux/Makefile                         |    13 +
 target/linux/ar71xx/Makefile                  |    24 +
 .../ar71xx/base-files/etc/board.d/01_leds     |   763 +
 .../ar71xx/base-files/etc/board.d/02_network  |   477 +
 .../base-files/etc/board.d/03_gpio_switches   |    32 +
 target/linux/ar71xx/base-files/etc/diag.sh    |   475 +
 .../etc/hotplug.d/firmware/10-ath9k-eeprom    |   147 +
 .../etc/hotplug.d/net/10-ar922x-led-fix       |    51 +
 target/linux/ar71xx/base-files/etc/inittab    |     3 +
 .../uci-defaults/03_network-switchX-migration |   109 +
 .../uci-defaults/03_network-vlan-migration    |    13 +
 .../etc/uci-defaults/04_led_migration         |    90 +
 .../etc/uci-defaults/09_fix-checksum          |    28 +
 .../etc/uci-defaults/09_fix-seama-header      |    17 +
 target/linux/ar71xx/base-files/lib/ar71xx.sh  |  1246 +
 .../lib/preinit/03_preinit_do_ar71xx.sh       |     9 +
 .../lib/preinit/05_set_iface_mac_ar71xx       |    60 +
 .../lib/preinit/05_set_preinit_iface_ar71xx   |    58 +
 .../ar71xx/base-files/lib/upgrade/allnet.sh   |   162 +
 .../ar71xx/base-files/lib/upgrade/dir825.sh   |   165 +
 .../base-files/lib/upgrade/merakinand.sh      |   165 +
 .../ar71xx/base-files/lib/upgrade/openmesh.sh |   233 +
 .../ar71xx/base-files/lib/upgrade/platform.sh |   653 +
 target/linux/ar71xx/base-files/sbin/wget2nand |    85 +
 target/linux/ar71xx/config-4.4                |   443 +
 .../files/arch/mips/ath79/Kconfig.openwrt     |  1803 ++
 .../ar71xx/files/arch/mips/ath79/Makefile     |   228 +
 .../files/arch/mips/ath79/dev-ap9x-pci.c      |   185 +
 .../files/arch/mips/ath79/dev-ap9x-pci.h      |    58 +
 .../ar71xx/files/arch/mips/ath79/dev-dsa.c    |    41 +
 .../ar71xx/files/arch/mips/ath79/dev-dsa.h    |    21 +
 .../ar71xx/files/arch/mips/ath79/dev-eth.c    |  1262 +
 .../ar71xx/files/arch/mips/ath79/dev-eth.h    |    53 +
 .../ar71xx/files/arch/mips/ath79/dev-m25p80.c |   126 +
 .../ar71xx/files/arch/mips/ath79/dev-m25p80.h |    18 +
 .../ar71xx/files/arch/mips/ath79/dev-nfc.c    |   141 +
 .../ar71xx/files/arch/mips/ath79/dev-nfc.h    |    34 +
 .../files/arch/mips/ath79/mach-alfa-ap120c.c  |   147 +
 .../files/arch/mips/ath79/mach-alfa-ap96.c    |   151 +
 .../files/arch/mips/ath79/mach-alfa-nx.c      |   113 +
 .../files/arch/mips/ath79/mach-all0258n.c     |    88 +
 .../files/arch/mips/ath79/mach-all0315n.c     |    85 +
 .../files/arch/mips/ath79/mach-antminer-s1.c  |    98 +
 .../files/arch/mips/ath79/mach-antminer-s3.c  |   103 +
 .../files/arch/mips/ath79/mach-antrouter-r1.c |    98 +
 .../ar71xx/files/arch/mips/ath79/mach-ap113.c |    84 +
 .../ar71xx/files/arch/mips/ath79/mach-ap132.c |   189 +
 .../ar71xx/files/arch/mips/ath79/mach-ap143.c |   142 +
 .../ar71xx/files/arch/mips/ath79/mach-ap147.c |   125 +
 .../ar71xx/files/arch/mips/ath79/mach-ap152.c |   140 +
 .../ar71xx/files/arch/mips/ath79/mach-ap83.c  |   275 +
 .../ar71xx/files/arch/mips/ath79/mach-ap90q.c |   201 +
 .../ar71xx/files/arch/mips/ath79/mach-ap96.c  |   142 +
 .../files/arch/mips/ath79/mach-archer-c7.c    |   302 +
 .../files/arch/mips/ath79/mach-arduino-yun.c  |   157 +
 .../files/arch/mips/ath79/mach-aw-nr580.c     |   107 +
 .../files/arch/mips/ath79/mach-bhr-4grv2.c    |   171 +
 .../arch/mips/ath79/mach-bhu-bxu2000n2-a.c    |   120 +
 .../ar71xx/files/arch/mips/ath79/mach-bsb.c   |    83 +
 .../ar71xx/files/arch/mips/ath79/mach-c55.c   |   132 +
 .../ar71xx/files/arch/mips/ath79/mach-c60.c   |   200 +
 .../files/arch/mips/ath79/mach-cap324.c       |   133 +
 .../files/arch/mips/ath79/mach-cap4200ag.c    |   131 +
 .../files/arch/mips/ath79/mach-carambola2.c   |   105 +
 .../files/arch/mips/ath79/mach-cf-e316n-v2.c  |   462 +
 .../files/arch/mips/ath79/mach-cpe510.c       |   131 +
 .../files/arch/mips/ath79/mach-cpe870.c       |   152 +
 .../files/arch/mips/ath79/mach-cr3000.c       |   161 +
 .../files/arch/mips/ath79/mach-cr5000.c       |   176 +
 .../files/arch/mips/ath79/mach-dap-2695-a1.c  |   191 +
 .../files/arch/mips/ath79/mach-dgl-5500-a1.c  |   150 +
 .../files/arch/mips/ath79/mach-dhp-1565-a1.c  |   170 +
 .../files/arch/mips/ath79/mach-dir-505-a1.c   |   116 +
 .../files/arch/mips/ath79/mach-dir-600-a1.c   |   159 +
 .../files/arch/mips/ath79/mach-dir-615-c1.c   |   135 +
 .../files/arch/mips/ath79/mach-dir-615-i1.c   |   133 +
 .../files/arch/mips/ath79/mach-dir-825-b1.c   |   191 +
 .../files/arch/mips/ath79/mach-dir-825-c1.c   |   241 +
 .../files/arch/mips/ath79/mach-dir-869-a1.c   |   178 +
 .../files/arch/mips/ath79/mach-dlan-hotspot.c |   117 +
 .../arch/mips/ath79/mach-dlan-pro-1200-ac.c   |   190 +
 .../arch/mips/ath79/mach-dlan-pro-500-wp.c    |   203 +
 .../arch/mips/ath79/mach-domywifi-dw33d.c     |   187 +
 .../ar71xx/files/arch/mips/ath79/mach-dr344.c |   184 +
 .../ar71xx/files/arch/mips/ath79/mach-dr531.c |   155 +
 .../files/arch/mips/ath79/mach-dragino2.c     |   136 +
 .../files/arch/mips/ath79/mach-eap120.c       |   126 +
 .../files/arch/mips/ath79/mach-eap300v2.c     |   101 +
 .../files/arch/mips/ath79/mach-eap7660d.c     |   181 +
 .../files/arch/mips/ath79/mach-el-m150.c      |   112 +
 .../files/arch/mips/ath79/mach-el-mini.c      |    86 +
 .../files/arch/mips/ath79/mach-epg5000.c      |   177 +
 .../files/arch/mips/ath79/mach-esr1750.c      |   176 +
 .../files/arch/mips/ath79/mach-esr900.c       |   200 +
 .../files/arch/mips/ath79/mach-ew-dorin.c     |   150 +
 .../files/arch/mips/ath79/mach-f9k1115v2.c    |   189 +
 .../files/arch/mips/ath79/mach-gl-ar150.c     |   125 +
 .../files/arch/mips/ath79/mach-gl-ar300.c     |   103 +
 .../files/arch/mips/ath79/mach-gl-ar300m.c    |   182 +
 .../files/arch/mips/ath79/mach-gl-domino.c    |   136 +
 .../files/arch/mips/ath79/mach-gl-inet.c      |   104 +
 .../files/arch/mips/ath79/mach-gl-mifi.c      |   114 +
 .../arch/mips/ath79/mach-gs-minibox-v1.c      |    85 +
 .../files/arch/mips/ath79/mach-gs-oolite.c    |   103 +
 .../arch/mips/ath79/mach-hiwifi-hc6361.c      |   115 +
 .../files/arch/mips/ath79/mach-hornet-ub.c    |   142 +
 .../files/arch/mips/ath79/mach-ja76pf.c       |   190 +
 .../files/arch/mips/ath79/mach-jwap003.c      |    95 +
 .../files/arch/mips/ath79/mach-jwap230.c      |   158 +
 .../files/arch/mips/ath79/mach-mc-mac1200r.c  |   155 +
 .../ar71xx/files/arch/mips/ath79/mach-mr12.c  |   114 +
 .../ar71xx/files/arch/mips/ath79/mach-mr16.c  |   118 +
 .../files/arch/mips/ath79/mach-mr1750.c       |   171 +
 .../ar71xx/files/arch/mips/ath79/mach-mr18.c  |   297 +
 .../ar71xx/files/arch/mips/ath79/mach-mr600.c |   177 +
 .../ar71xx/files/arch/mips/ath79/mach-mr900.c |   181 +
 .../files/arch/mips/ath79/mach-mynet-n600.c   |   202 +
 .../files/arch/mips/ath79/mach-mynet-n750.c   |   226 +
 .../files/arch/mips/ath79/mach-mynet-rext.c   |   208 +
 .../files/arch/mips/ath79/mach-mzk-w04nu.c    |   124 +
 .../files/arch/mips/ath79/mach-mzk-w300nh.c   |   115 +
 .../files/arch/mips/ath79/mach-nbg460n.c      |   220 +
 .../files/arch/mips/ath79/mach-nbg6716.c      |   380 +
 .../ar71xx/files/arch/mips/ath79/mach-om2p.c  |   226 +
 .../ar71xx/files/arch/mips/ath79/mach-om5p.c  |   218 +
 .../files/arch/mips/ath79/mach-om5pac.c       |   193 +
 .../files/arch/mips/ath79/mach-om5pacv2.c     |   221 +
 .../files/arch/mips/ath79/mach-omy-g1.c       |   123 +
 .../files/arch/mips/ath79/mach-omy-x1.c       |   106 +
 .../files/arch/mips/ath79/mach-onion-omega.c  |    84 +
 .../ar71xx/files/arch/mips/ath79/mach-pb42.c  |    83 +
 .../ar71xx/files/arch/mips/ath79/mach-pb92.c  |    70 +
 .../files/arch/mips/ath79/mach-qihoo-c301.c   |   166 +
 .../ar71xx/files/arch/mips/ath79/mach-r6100.c |   146 +
 .../files/arch/mips/ath79/mach-rb2011.c       |   338 +
 .../ar71xx/files/arch/mips/ath79/mach-rb4xx.c |   470 +
 .../ar71xx/files/arch/mips/ath79/mach-rb750.c |   346 +
 .../ar71xx/files/arch/mips/ath79/mach-rb91x.c |   349 +
 .../ar71xx/files/arch/mips/ath79/mach-rb922.c |   236 +
 .../ar71xx/files/arch/mips/ath79/mach-rb95x.c |   258 +
 .../files/arch/mips/ath79/mach-rbsxtlite.c    |   238 +
 .../files/arch/mips/ath79/mach-rw2458n.c      |    91 +
 .../files/arch/mips/ath79/mach-smart-300.c    |   135 +
 .../files/arch/mips/ath79/mach-som9331.c      |   125 +
 .../mips/ath79/mach-tellstick-znet-lite.c     |   129 +
 .../files/arch/mips/ath79/mach-tew-632brp.c   |   111 +
 .../files/arch/mips/ath79/mach-tew-673gru.c   |   198 +
 .../files/arch/mips/ath79/mach-tew-712br.c    |   153 +
 .../files/arch/mips/ath79/mach-tew-732br.c    |   127 +
 .../files/arch/mips/ath79/mach-tew-823dru.c   |   181 +
 .../files/arch/mips/ath79/mach-tl-mr11u.c     |   183 +
 .../files/arch/mips/ath79/mach-tl-mr13u.c     |   107 +
 .../files/arch/mips/ath79/mach-tl-mr3020.c    |   126 +
 .../files/arch/mips/ath79/mach-tl-mr3x20.c    |   147 +
 .../arch/mips/ath79/mach-tl-wa701nd-v2.c      |   116 +
 .../arch/mips/ath79/mach-tl-wa7210n-v2.c      |   125 +
 .../arch/mips/ath79/mach-tl-wa801nd-v3.c      |   136 +
 .../arch/mips/ath79/mach-tl-wa830re-v2.c      |   132 +
 .../arch/mips/ath79/mach-tl-wa901nd-v2.c      |   104 +
 .../arch/mips/ath79/mach-tl-wa901nd-v4.c      |   112 +
 .../files/arch/mips/ath79/mach-tl-wa901nd.c   |   127 +
 .../files/arch/mips/ath79/mach-tl-wax50re.c   |   313 +
 .../arch/mips/ath79/mach-tl-wdr3320-v2.c      |   146 +
 .../files/arch/mips/ath79/mach-tl-wdr3500.c   |   169 +
 .../files/arch/mips/ath79/mach-tl-wdr4300.c   |   206 +
 .../arch/mips/ath79/mach-tl-wdr6500-v2.c      |   142 +
 .../files/arch/mips/ath79/mach-tl-wpa8630.c   |   172 +
 .../arch/mips/ath79/mach-tl-wr1041n-v2.c      |   138 +
 .../arch/mips/ath79/mach-tl-wr1043nd-v2.c     |   215 +
 .../files/arch/mips/ath79/mach-tl-wr1043nd.c  |   141 +
 .../files/arch/mips/ath79/mach-tl-wr2543n.c   |   156 +
 .../files/arch/mips/ath79/mach-tl-wr703n.c    |   118 +
 .../files/arch/mips/ath79/mach-tl-wr720n-v3.c |   108 +
 .../arch/mips/ath79/mach-tl-wr741nd-v4.c      |   187 +
 .../files/arch/mips/ath79/mach-tl-wr741nd.c   |   130 +
 .../files/arch/mips/ath79/mach-tl-wr802n.c    |    98 +
 .../files/arch/mips/ath79/mach-tl-wr810n.c    |   135 +
 .../files/arch/mips/ath79/mach-tl-wr841n-v8.c |   286 +
 .../files/arch/mips/ath79/mach-tl-wr841n-v9.c |   308 +
 .../files/arch/mips/ath79/mach-tl-wr841n.c    |   140 +
 .../arch/mips/ath79/mach-tl-wr941nd-v6.c      |   149 +
 .../files/arch/mips/ath79/mach-tl-wr941nd.c   |   121 +
 .../files/arch/mips/ath79/mach-tube2h.c       |   118 +
 .../files/arch/mips/ath79/mach-ubnt-unifiac.c |   179 +
 .../files/arch/mips/ath79/mach-ubnt-xm.c      |   718 +
 .../ar71xx/files/arch/mips/ath79/mach-ubnt.c  |   205 +
 .../ar71xx/files/arch/mips/ath79/mach-weio.c  |   140 +
 .../files/arch/mips/ath79/mach-whr-hp-g300n.c |   155 +
 .../files/arch/mips/ath79/mach-wlae-ag300n.c  |   114 +
 .../files/arch/mips/ath79/mach-wlr8100.c      |   205 +
 .../files/arch/mips/ath79/mach-wndap360.c     |   105 +
 .../files/arch/mips/ath79/mach-wndr3700.c     |   172 +
 .../files/arch/mips/ath79/mach-wndr4300.c     |   210 +
 .../files/arch/mips/ath79/mach-wnr2000-v3.c   |   636 +
 .../files/arch/mips/ath79/mach-wnr2000-v4.c   |   214 +
 .../files/arch/mips/ath79/mach-wnr2000.c      |   145 +
 .../files/arch/mips/ath79/mach-wnr2200.c      |   246 +
 .../ar71xx/files/arch/mips/ath79/mach-wp543.c |   109 +
 .../ar71xx/files/arch/mips/ath79/mach-wpe72.c |    97 +
 .../files/arch/mips/ath79/mach-wpj342.c       |   178 +
 .../files/arch/mips/ath79/mach-wpj344.c       |   176 +
 .../files/arch/mips/ath79/mach-wpj531.c       |   143 +
 .../files/arch/mips/ath79/mach-wpj558.c       |   177 +
 .../files/arch/mips/ath79/mach-wrt160nl.c     |   126 +
 .../files/arch/mips/ath79/mach-wrt400n.c      |   161 +
 .../files/arch/mips/ath79/mach-wrtnode2q.c    |   126 +
 .../files/arch/mips/ath79/mach-wzr-450hp2.c   |   221 +
 .../arch/mips/ath79/mach-wzr-hp-ag300h.c      |   205 +
 .../arch/mips/ath79/mach-wzr-hp-g300nh.c      |   279 +
 .../arch/mips/ath79/mach-wzr-hp-g300nh2.c     |   170 +
 .../files/arch/mips/ath79/mach-wzr-hp-g450h.c |   165 +
 .../ar71xx/files/arch/mips/ath79/mach-z1.c    |   164 +
 .../files/arch/mips/ath79/mach-zbt-we1526.c   |   153 +
 .../files/arch/mips/ath79/mach-zcn-1523h.c    |   154 +
 .../ar71xx/files/arch/mips/ath79/machtypes.h  |   291 +
 .../ar71xx/files/arch/mips/ath79/nvram.c      |    80 +
 .../ar71xx/files/arch/mips/ath79/nvram.h      |    19 +
 .../files/arch/mips/ath79/pci-ath9k-fixup.c   |   126 +
 .../files/arch/mips/ath79/pci-ath9k-fixup.h   |     6 +
 .../ar71xx/files/arch/mips/ath79/routerboot.c |   358 +
 .../ar71xx/files/arch/mips/ath79/routerboot.h |    63 +
 .../mips/include/asm/fw/myloader/myloader.h   |    34 +
 .../include/asm/mach-ath79/ag71xx_platform.h  |    66 +
 .../mips/include/asm/mach-ath79/mach-rb750.h  |    84 +
 .../mips/include/asm/mach-ath79/rb4xx_cpld.h  |    48 +
 .../ar71xx/files/drivers/gpio/gpio-latch.c    |   220 +
 .../files/drivers/gpio/gpio-nxp-74hc153.c     |   251 +
 .../ar71xx/files/drivers/leds/leds-nu801.c    |   396 +
 .../ar71xx/files/drivers/leds/leds-rb750.c    |   144 +
 .../files/drivers/leds/leds-wndr3700-usb.c    |    76 +
 .../ar71xx/files/drivers/mtd/cybertan_part.c  |   201 +
 .../files/drivers/mtd/nand/ar934x_nfc.c       |  1502 +
 .../files/drivers/mtd/nand/rb4xx_nand.c       |   305 +
 .../files/drivers/mtd/nand/rb750_nand.c       |   354 +
 .../files/drivers/mtd/nand/rb91x_nand.c       |   377 +
 .../ar71xx/files/drivers/mtd/tplinkpart.c     |   222 +
 .../ar71xx/files/drivers/net/dsa/mv88e6063.c  |   311 +
 .../net/ethernet/atheros/ag71xx/Kconfig       |    33 +
 .../net/ethernet/atheros/ag71xx/Makefile      |    15 +
 .../net/ethernet/atheros/ag71xx/ag71xx.h      |   493 +
 .../ethernet/atheros/ag71xx/ag71xx_ar7240.c   |  1229 +
 .../ethernet/atheros/ag71xx/ag71xx_ar8216.c   |    44 +
 .../ethernet/atheros/ag71xx/ag71xx_debugfs.c  |   287 +
 .../ethernet/atheros/ag71xx/ag71xx_ethtool.c  |   131 +
 .../net/ethernet/atheros/ag71xx/ag71xx_main.c |  1478 +
 .../net/ethernet/atheros/ag71xx/ag71xx_mdio.c |   318 +
 .../net/ethernet/atheros/ag71xx/ag71xx_phy.c  |   235 +
 .../linux/ar71xx/files/drivers/spi/spi-ap83.c |   283 +
 .../ar71xx/files/drivers/spi/spi-rb4xx-cpld.c |   441 +
 .../ar71xx/files/drivers/spi/spi-rb4xx.c      |   507 +
 .../ar71xx/files/drivers/spi/spi-vsc7385.c    |   621 +
 .../ar71xx/files/include/linux/leds-nu801.h   |    38 +
 .../ar71xx/files/include/linux/nxp_74hc153.h  |    24 +
 .../files/include/linux/platform/ar934x_nfc.h |    39 +
 .../include/linux/platform_data/gpio-latch.h  |    14 +
 .../include/linux/platform_data/rb91x_nand.h  |    16 +
 .../ar71xx/files/include/linux/spi/vsc7385.h  |    19 +
 target/linux/ar71xx/files/net/dsa/mv88e6063.c |   294 +
 target/linux/ar71xx/generic/config-default    |     1 +
 .../ar71xx/generic/profiles/00-default.mk     |    18 +
 target/linux/ar71xx/generic/target.mk         |     8 +
 target/linux/ar71xx/image/Makefile            |   109 +
 target/linux/ar71xx/image/generic.mk          |   612 +
 target/linux/ar71xx/image/legacy-devices.mk   |   611 +
 target/linux/ar71xx/image/legacy.mk           |  1065 +
 .../linux/ar71xx/image/lzma-loader/Makefile   |    66 +
 .../ar71xx/image/lzma-loader/src/LzmaDecode.c |   584 +
 .../ar71xx/image/lzma-loader/src/LzmaDecode.h |   113 +
 .../ar71xx/image/lzma-loader/src/LzmaTypes.h  |    45 +
 .../ar71xx/image/lzma-loader/src/Makefile     |   106 +
 .../image/lzma-loader/src/ar71xx_regs.h       |   725 +
 .../ar71xx/image/lzma-loader/src/board.c      |    56 +
 .../ar71xx/image/lzma-loader/src/cache.c      |    43 +
 .../ar71xx/image/lzma-loader/src/cache.h      |    17 +
 .../ar71xx/image/lzma-loader/src/cacheops.h   |    85 +
 .../ar71xx/image/lzma-loader/src/config.h     |    31 +
 .../ar71xx/image/lzma-loader/src/cp0regdef.h  |    39 +
 .../linux/ar71xx/image/lzma-loader/src/head.S |   121 +
 .../ar71xx/image/lzma-loader/src/loader.c     |   264 +
 .../ar71xx/image/lzma-loader/src/loader.lds   |    35 +
 .../ar71xx/image/lzma-loader/src/loader2.lds  |    10 +
 .../image/lzma-loader/src/lzma-data.lds       |     8 +
 .../ar71xx/image/lzma-loader/src/printf.c     |   350 +
 .../ar71xx/image/lzma-loader/src/printf.h     |    18 +
 target/linux/ar71xx/image/nand.mk             |    78 +
 target/linux/ar71xx/image/tp-link.mk          |   855 +
 target/linux/ar71xx/image/ubinize-nbg6716.ini |    24 +
 .../linux/ar71xx/image/ubinize-wndr4300.ini   |    26 +
 target/linux/ar71xx/mikrotik/config-default   |   176 +
 .../ar71xx/mikrotik/profiles/01-minimal.mk    |    17 +
 .../ar71xx/mikrotik/profiles/02-ath5k.mk      |    17 +
 target/linux/ar71xx/mikrotik/target.mk        |     9 +
 target/linux/ar71xx/modules.mk                |    69 +
 target/linux/ar71xx/nand/config-default       |   118 +
 .../linux/ar71xx/nand/profiles/00-default.mk  |    18 +
 target/linux/ar71xx/nand/target.mk            |     7 +
 .../001-revert_spi_device_tree_support.patch  |    83 +
 .../002-add_back_gpio_function_select.patch   |    92 +
 .../004-register_gpio_driver_earlier.patch    |    15 +
 ...Avoid-using-unitialized-reg-variable.patch |    42 +
 ...ath79_ddr_ctrl_init-compatible-for-n.patch |    31 +
 ...egression-in-PCI-window-initializati.patch |    37 +
 ...egister-address-in-ath79_ddr_wb_flus.patch |    23 +
 ...200-MIPS-ath79-fix-ar933x-wmac-reset.patch |    31 +
 .../201-ar913x_wmac_external_reset.patch      |    31 +
 .../202-MIPS-ath79-ar934x-wmac-revision.patch |    11 +
 .../203-MIPS-ath79-fix-restart.patch          |    20 +
 ...-make-chipselect-logic-more-flexible.patch |   199 +
 .../220-add_cpu_feature_overrides.patch       |    28 +
 ...0-MIPS-add-MIPS_MACHINE_NONAME-macro.patch |    21 +
 .../310-lib-add-rle-decompression.patch       |   124 +
 .../401-mtd-physmap-add-lock-unlock.patch     |    94 +
 .../402-mtd-SST39VF6401B-support.patch        |    29 +
 ...mtd_fix_cfi_cmdset_0002_status_check.patch |    69 +
 .../404-mtd-cybertan-trx-parser.patch         |    25 +
 .../405-mtd-tp-link-partition-parser.patch    |    25 +
 ...o-pass-probe-types-via-platform-data.patch |    23 +
 .../408-mtd-redboot_partition_scan.patch      |    44 +
 .../409-mtd-rb4xx_nand_driver.patch           |    21 +
 .../410-mtd-rb750-nand-driver.patch           |    21 +
 ...mtd-cfi_cmdset_0002-force-word-write.patch |    61 +
 ...td-m25p80-zero-partition-parser-data.patch |    10 +
 .../413-mtd-ar934x-nand-driver.patch          |    25 +
 .../414-mtd-rb91x-nand-driver.patch           |    23 +
 .../420-net-ar71xx_mac_driver.patch           |    28 +
 .../423-dsa-add-88e6063-driver.patch          |    24 +
 .../430-drivers-link-spi-before-mtd.patch     |    12 +
 .../431-spi-add-various-flags.patch           |    19 +
 .../432-spi-rb4xx-spi-driver.patch            |    25 +
 .../433-spi-rb4xx-cpld-driver.patch           |    26 +
 .../434-spi-ap83_spi_controller.patch         |    27 +
 .../patches-4.4/435-spi-vsc7385_driver.patch  |    24 +
 .../440-leds-wndr3700-usb-led-driver.patch    |    26 +
 .../441-leds-rb750-led-driver.patch           |    23 +
 ...50-gpio-nxp-74hc153-gpio-chip-driver.patch |    25 +
 ...x164-improve-platform-device-support.patch |   109 +
 .../452-gpio-add-gpio-latch-driver.patch      |    22 +
 ...-spi-bitbang-export-spi_bitbang_bufs.patch |    28 +
 ...1-spi-add-type-field-to-spi_transfer.patch |    23 +
 ...462-mtd-m25p80-set-spi-transfer-type.patch |    15 +
 .../463-spi-ath79-add-fast-flash-read.patch   |   185 +
 .../464-spi-ath79-fix-fast-flash-read.patch   |    35 +
 ...ath79-swizzle-pci-address-for-ar71xx.patch |   111 +
 ...490-usb-ehci-add-quirks-for-qca-socs.patch |   103 +
 .../patches-4.4/500-MIPS-fw-myloader.patch    |    22 +
 ...-mac-argument-to-ath79_register_wmac.patch |    81 +
 ...MIPS-ath79-add-flash-acquire-release.patch |    37 +
 ...IPS-ath79-add-ath79_device_reset_get.patch |    45 +
 ...ath79-add-ath79_gpio_function_select.patch |    39 +
 ...6-MIPS-ath79-prom-parse-redboot-args.patch |    42 +
 ...MIPS-ath79-prom-add-myloader-support.patch |    55 +
 ...S-ath79-prom-image-command-line-hack.patch |    73 +
 ...PS-ath79-process-board-kernel-option.patch |    11 +
 ...S-ath79-init-gpio-pin-of-wmac-device.patch |    14 +
 .../520-MIPS-ath79-enable-UART-function.patch |    18 +
 ...S-ath79-enable-UART-for-early_serial.patch |    61 +
 ...dd-ath79_wmac_register_simple-helper.patch |    21 +
 .../523-MIPS-ath79-OTP-support.patch          |   166 +
 ...add-ath79_wmac_disable_25ghz-helpers.patch |    31 +
 ...525-MIPS-ath79-enable-qca-usb-quirks.patch |   101 +
 ...MIPS-ath79-add-more-register-defines.patch |   455 +
 .../602-MIPS-ath79-add-openwrt-stuff.patch    |    49 +
 .../603-MIPS-ath79-ap121-fixes.patch          |   149 +
 .../604-MIPS-ath79-ap81-fixes.patch           |    84 +
 .../605-MIPS-ath79-db120-fixes.patch          |   204 +
 .../606-MIPS-ath79-pb44-fixes.patch           |   153 +
 .../607-MIPS-ath79-ubnt-xm-fixes.patch        |    14 +
 ...8-MIPS-ath79-ubnt-xm-add-more-boards.patch |    20 +
 .../609-MIPS-ath79-ap136-fixes.patch          |   300 +
 .../611-MIPS-ath79-wdt-timeout.patch          |    25 +
 .../612-MIPS-ath79-set-buffalo-txgain.patch   |    24 +
 ...ath79_wmac_setup_ext_lna_gpio-helper.patch |    76 +
 ...IPS-ath79-ap83-remove-mtd-partitions.patch |    44 +
 ...PS-ath79-add-support-for-QCA953x-SoC.patch |   705 +
 ...PS-ath79-add-support-for-QCA956x-SoC.patch |   717 +
 ...0-MIPS-ath79-fix-chained-irq-disable.patch |   102 +
 ...1-MIPS-ath79-wmac-enable-set-led-pin.patch |    24 +
 ...MIPS-ath79-gpio-enable-set-direction.patch |    32 +
 ...ath79-ar724x-clock-calculation-fixes.patch |    22 +
 ...40-MIPS-ath79-add-QCA955x-wmac-reset.patch |    82 +
 .../700-MIPS-ath79-add-openwrt-Kconfig.patch  |    11 +
 ...MIPS-ath79-add-routerboard-detection.patch |    19 +
 ...d-gpio-func-register-for-QCA955x-SoC.patch |    38 +
 ...0-MIPS-ath79-add-PCI-for-QCA953x-SoC.patch |    44 +
 .../818-MIPS-ath79-add-nu801-led-driver.patch |    26 +
 ...-MIPS-ath79-add_gpio_function2_setup.patch |    67 +
 ...support-for-boot-console-with-arbitr.patch |    76 +
 .../900-mdio_bitbang_ignore_ta_value.patch    |    23 +
 ...-prevent-rescheduling-during-command.patch |    61 +
 .../902-at803x-add-reset-gpio-pdata.patch     |    68 +
 .../910-unaligned_access_hacks.patch          |   931 +
 target/linux/generic/PATCHES                  |    20 +
 target/linux/generic/base-files/init          |     4 +
 target/linux/generic/config-3.18              |  4646 +++
 target/linux/generic/config-4.1               |  4821 +++
 target/linux/generic/config-4.4               |  4825 +++
 .../Documentation/networking/adm6996.txt      |   110 +
 .../files/arch/mips/fw/myloader/Makefile      |     5 +
 .../files/arch/mips/fw/myloader/myloader.c    |    63 +
 .../files/drivers/leds/ledtrig-netdev.c       |   444 +
 .../generic/files/drivers/misc/owl-loader.c   |   246 +
 .../files/drivers/mtd/mtdsplit/Kconfig        |    66 +
 .../files/drivers/mtd/mtdsplit/Makefile       |    11 +
 .../files/drivers/mtd/mtdsplit/mtdsplit.c     |   130 +
 .../files/drivers/mtd/mtdsplit/mtdsplit.h     |    67 +
 .../drivers/mtd/mtdsplit/mtdsplit_brnimage.c  |   104 +
 .../files/drivers/mtd/mtdsplit/mtdsplit_eva.c |    96 +
 .../files/drivers/mtd/mtdsplit/mtdsplit_fit.c |   140 +
 .../drivers/mtd/mtdsplit/mtdsplit_lzma.c      |    96 +
 .../drivers/mtd/mtdsplit/mtdsplit_seama.c     |   110 +
 .../drivers/mtd/mtdsplit/mtdsplit_squashfs.c  |    72 +
 .../drivers/mtd/mtdsplit/mtdsplit_tplink.c    |   169 +
 .../files/drivers/mtd/mtdsplit/mtdsplit_trx.c |   147 +
 .../drivers/mtd/mtdsplit/mtdsplit_uimage.c    |   359 +
 .../drivers/mtd/mtdsplit/mtdsplit_wrgg.c      |   109 +
 .../generic/files/drivers/mtd/myloader.c      |   182 +
 .../generic/files/drivers/net/phy/adm6996.c   |  1215 +
 .../generic/files/drivers/net/phy/adm6996.h   |   186 +
 .../generic/files/drivers/net/phy/ar8216.c    |  2313 ++
 .../generic/files/drivers/net/phy/ar8216.h    |   643 +
 .../generic/files/drivers/net/phy/ar8327.c    |  1443 +
 .../generic/files/drivers/net/phy/ar8327.h    |   319 +
 .../generic/files/drivers/net/phy/b53/Kconfig |    37 +
 .../files/drivers/net/phy/b53/Makefile        |    10 +
 .../files/drivers/net/phy/b53/b53_common.c    |  1526 +
 .../files/drivers/net/phy/b53/b53_mdio.c      |   445 +
 .../files/drivers/net/phy/b53/b53_mmap.c      |   241 +
 .../files/drivers/net/phy/b53/b53_phy_fixup.c |    55 +
 .../files/drivers/net/phy/b53/b53_priv.h      |   331 +
 .../files/drivers/net/phy/b53/b53_regs.h      |   348 +
 .../files/drivers/net/phy/b53/b53_spi.c       |   330 +
 .../files/drivers/net/phy/b53/b53_srab.c      |   378 +
 .../generic/files/drivers/net/phy/ip17xx.c    |  1410 +
 .../generic/files/drivers/net/phy/mvsw61xx.c  |   943 +
 .../generic/files/drivers/net/phy/mvsw61xx.h  |   289 +
 .../generic/files/drivers/net/phy/mvswitch.c  |   433 +
 .../generic/files/drivers/net/phy/mvswitch.h  |   145 +
 .../generic/files/drivers/net/phy/psb6970.c   |   438 +
 .../generic/files/drivers/net/phy/rtl8306.c   |  1060 +
 .../files/drivers/net/phy/rtl8366_smi.c       |  1449 +
 .../files/drivers/net/phy/rtl8366_smi.h       |   152 +
 .../generic/files/drivers/net/phy/rtl8366rb.c |  1496 +
 .../generic/files/drivers/net/phy/rtl8366s.c  |  1148 +
 .../generic/files/drivers/net/phy/rtl8367.c   |  1835 ++
 .../generic/files/drivers/net/phy/rtl8367b.c  |  1602 +
 .../generic/files/drivers/net/phy/swconfig.c  |  1236 +
 .../files/drivers/net/phy/swconfig_leds.c     |   439 +
 target/linux/generic/files/fs/yaffs2/Kconfig  |   171 +
 target/linux/generic/files/fs/yaffs2/Makefile |    18 +
 .../generic/files/fs/yaffs2/NOTE.openwrt      |     4 +
 .../generic/files/fs/yaffs2/yaffs_allocator.c |   357 +
 .../generic/files/fs/yaffs2/yaffs_allocator.h |    30 +
 .../generic/files/fs/yaffs2/yaffs_attribs.c   |   132 +
 .../generic/files/fs/yaffs2/yaffs_attribs.h   |    28 +
 .../generic/files/fs/yaffs2/yaffs_bitmap.c    |    97 +
 .../generic/files/fs/yaffs2/yaffs_bitmap.h    |    33 +
 .../generic/files/fs/yaffs2/yaffs_checkptrw.c |   466 +
 .../generic/files/fs/yaffs2/yaffs_checkptrw.h |    33 +
 .../linux/generic/files/fs/yaffs2/yaffs_ecc.c |   281 +
 .../linux/generic/files/fs/yaffs2/yaffs_ecc.h |    44 +
 .../files/fs/yaffs2/yaffs_getblockinfo.h      |    35 +
 .../generic/files/fs/yaffs2/yaffs_guts.c      |  5140 +++
 .../generic/files/fs/yaffs2/yaffs_guts.h      |  1010 +
 .../generic/files/fs/yaffs2/yaffs_linux.h     |    48 +
 .../generic/files/fs/yaffs2/yaffs_mtdif.c     |   310 +
 .../generic/files/fs/yaffs2/yaffs_mtdif.h     |    25 +
 .../generic/files/fs/yaffs2/yaffs_nameval.c   |   208 +
 .../generic/files/fs/yaffs2/yaffs_nameval.h   |    28 +
 .../generic/files/fs/yaffs2/yaffs_nand.c      |   122 +
 .../generic/files/fs/yaffs2/yaffs_nand.h      |    39 +
 .../files/fs/yaffs2/yaffs_packedtags1.c       |    56 +
 .../files/fs/yaffs2/yaffs_packedtags1.h       |    39 +
 .../files/fs/yaffs2/yaffs_packedtags2.c       |   197 +
 .../files/fs/yaffs2/yaffs_packedtags2.h       |    47 +
 .../generic/files/fs/yaffs2/yaffs_summary.c   |   312 +
 .../generic/files/fs/yaffs2/yaffs_summary.h   |    37 +
 .../files/fs/yaffs2/yaffs_tagscompat.c        |   381 +
 .../files/fs/yaffs2/yaffs_tagscompat.h        |    44 +
 .../files/fs/yaffs2/yaffs_tagsmarshall.c      |   199 +
 .../files/fs/yaffs2/yaffs_tagsmarshall.h      |    22 +
 .../generic/files/fs/yaffs2/yaffs_trace.h     |    57 +
 .../generic/files/fs/yaffs2/yaffs_verify.c    |   529 +
 .../generic/files/fs/yaffs2/yaffs_verify.h    |    43 +
 .../linux/generic/files/fs/yaffs2/yaffs_vfs.c |  3665 +++
 .../generic/files/fs/yaffs2/yaffs_yaffs1.c    |   422 +
 .../generic/files/fs/yaffs2/yaffs_yaffs1.h    |    22 +
 .../generic/files/fs/yaffs2/yaffs_yaffs2.c    |  1532 +
 .../generic/files/fs/yaffs2/yaffs_yaffs2.h    |    39 +
 .../linux/generic/files/fs/yaffs2/yportenv.h  |    85 +
 .../files/include/linux/ar8216_platform.h     |   133 +
 .../files/include/linux/ath5k_platform.h      |    30 +
 .../files/include/linux/ath9k_platform.h      |    61 +
 .../generic/files/include/linux/myloader.h    |   121 +
 .../linux/platform_data/adm6996-gpio.h        |    30 +
 .../files/include/linux/platform_data/b53.h   |    36 +
 .../generic/files/include/linux/routerboot.h  |   106 +
 .../files/include/linux/rt2x00_platform.h     |    23 +
 .../generic/files/include/linux/rtl8366.h     |    40 +
 .../generic/files/include/linux/rtl8367.h     |    60 +
 .../generic/files/include/linux/switch.h      |   179 +
 .../generic/files/include/uapi/linux/switch.h |   119 +
 target/linux/generic/image/Makefile           |    12 +
 .../generic/image/initramfs-base-files.txt    |     9 +
 .../linux/generic/image/lzma-loader/Makefile  |    46 +
 .../image/lzma-loader/src/LzmaDecode.c        |   590 +
 .../image/lzma-loader/src/LzmaDecode.h        |   131 +
 .../generic/image/lzma-loader/src/Makefile    |    68 +
 .../image/lzma-loader/src/decompress.c        |   157 +
 .../image/lzma-loader/src/lzma-copy.lds.in    |    20 +
 .../generic/image/lzma-loader/src/lzma.lds.in |    24 +
 .../generic/image/lzma-loader/src/print.c     |   324 +
 .../generic/image/lzma-loader/src/print.h     |    36 +
 .../generic/image/lzma-loader/src/printf.c    |    35 +
 .../generic/image/lzma-loader/src/printf.h    |    18 +
 .../generic/image/lzma-loader/src/start.S     |   160 +
 .../generic/image/lzma-loader/src/uart16550.c |    86 +
 .../generic/image/lzma-loader/src/uart16550.h |    47 +
 target/linux/generic/image/relocate/Makefile  |    75 +
 .../linux/generic/image/relocate/cacheops.h   |    85 +
 .../linux/generic/image/relocate/cp0regdef.h  |    39 +
 target/linux/generic/image/relocate/head.S    |   159 +
 .../linux/generic/image/relocate/loader.lds   |    16 +
 .../generic/patches-3.18/020-ssb_update.patch |   134 +
 .../generic/patches-3.18/021-ssb_sprom.patch  |    32 +
 .../patches-3.18/025-bcma_backport.patch      |   286 +
 .../patches-3.18/026-bcma-from-3.20.patch     |   527 +
 .../patches-3.18/027-bcma-from-4.1.patch      |   680 +
 .../patches-3.18/028-bcma-from-4.2.patch      |    86 +
 .../patches-3.18/029-bcma-from-4.4.patch      |    26 +
 .../030-backport_bcm47xx_nvram.patch          |    52 +
 ...11-Allow-set-network-namespace-by-fd.patch |    21 +
 .../patches-3.18/031-bcma-from-4.5.patch      |    49 +
 .../patches-3.18/032-bcma-from-4.6.patch      |   716 +
 ...-mtd-bcm47xxpart-backports-from-3.19.patch |    50 +
 ...-mtd-bcm47xxpart-backports-from-3.20.patch |    95 +
 ...GD25Q128B_support_backport_from_3.19.patch |    15 +
 .../044-backport-m25p80-jedec-probe.patch     |    39 +
 .../050-backport_netfilter_rtcache.patch      |   509 +
 ...ting-hash_max-multicast_router-if-in.patch |    99 +
 .../060-mips_decompressor_memmove.patch       |    22 +
 ...gmac-register-napi-before-the-device.patch |    44 +
 ...rqs-only-if-there-is-nothing-to-poll.patch |    30 +
 ...-initialization-on-Northstar-SoCs-co.patch |    40 +
 .../073-bgmac-Clean-warning-messages.patch    |    50 +
 ...ixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch |    76 +
 ...mac-allow-enabling-on-ARCH_BCM_5301X.patch |    28 +
 ...76-net-phy-export-fixed_phy_register.patch |    30 +
 ...scriptor-frame-start-end-definitions.patch |    24 +
 ...gmac-implement-GRO-and-use-build_skb.patch |   189 +
 ...mac-implement-scatter-gather-support.patch |   267 +
 ...gmac-simplify-tx-ring-index-handling.patch |   125 +
 ...rrupts-disabled-as-long-as-there-is-.patch |    87 +
 ...received-skb-headroom-to-NET_SKB_PAD.patch |    66 +
 ...bgmac-simplify-rx-DMA-error-handling.patch |   130 +
 ...gmac-add-check-for-oversized-packets.patch |    27 +
 ...ncrease-rx-ring-size-from-511-to-512.patch |    23 +
 ...7-10-bgmac-simplify-dma-init-cleanup.patch |   184 +
 .../077-11-bgmac-fix-DMA-rx-corruption.patch  |    88 +
 .../077-12-bgmac-drop-ring-num_slots.patch    |   132 +
 ...enable-Ethernet-core-before-using-it.patch |    31 +
 ...fix-MAC-soft-reset-bit-for-corerev-4.patch |    34 +
 ...c-net-fib_trie-when-CONFIG_IP_MULTIP.patch |    46 +
 ...e-balancing-issue-if-new-node-pushes.patch |    72 +
 ...usage-stats-to-be-percpu-instead-of-.patch |   200 +
 ...rie-Make-leaf-and-tnode-more-uniform.patch |   421 +
 ...node_free-and-leaf_free-into-node_fr.patch |   209 +
 ...80-05-fib_trie-Merge-leaf-into-tnode.patch |   928 +
 ...e-fib_table_lookup-to-avoid-wasting-.patch |   343 +
 ...0-07-fib_trie-Optimize-fib_find_node.patch |    64 +
 ...8-fib_trie-Optimize-fib_table_insert.patch |   276 +
 ...meaning-of-pos-to-represent-unchecke.patch |   346 +
 ...igned-long-for-anything-dealing-with.patch |   186 +
 ...Push-rcu_read_lock-unlock-to-callers.patch |   403 +
 ...e-Move-resize-to-after-inflate-halve.patch |   345 +
 ...ctions-should_inflate-and-should_hal.patch |   250 +
 ...signment-of-child-to-parent-down-int.patch |   336 +
 ...tnode-flushing-down-to-inflate-halve.patch |   237 +
 ...-halve-nodes-in-a-more-RCU-friendly-.patch |   345 +
 ...checks-for-index-tnode_child_length-.patch |    95 +
 ...Add-tracking-value-for-suffix-length.patch |   234 +
 ...ex-0ul-n-bits-instead-of-index-n-bit.patch |    52 +
 ...-bug-and-merge-similar-bits-of-infla.patch |   267 +
 ...ck-to-slen-update-on-inflate-halve-f.patch |    61 +
 ...llapse-and-should_collapse-to-resize.patch |   206 +
 ...ty_children-instead-of-counting-empt.patch |    34 +
 ...b_find_alias-to-file-where-it-is-use.patch |    79 +
 ...-Various-clean-ups-for-handling-slen.patch |   116 +
 ...eue-to-die-properly-when-a-PADT-is-r.patch |    89 +
 ...02-pppoe-Lacks-DST-MAC-address-check.patch |    25 +
 ...poe-device-in-pppoe_unbind_sock_work.patch |    28 +
 ..._state-to-PPPOX_ZOMBIE-in-pppoe_disc.patch |    45 +
 ...ppp-remove-PPPOX_ZOMBIE-socket-state.patch |    51 +
 ...ry-corruption-in-padt-work-structure.patch |    82 +
 ...ment-fix-headroom-tests-and-skb-leak.patch |   101 +
 ...ncrease-headroom-on-received-packets.patch |    54 +
 ...layfs-fallback-to-readonly-when-full.patch |   109 +
 ...mtd-spi-nor-add-support-Spansion_S25FL164K |    10 +
 ...-if-the-device-is-processing-a-messa.patch |    47 +
 ...rs-inside-calling-context-for-spi_sy.patch |   184 +
 ...e-message-pump-in-the-worker-kthread.patch |    83 +
 ...ility-of-linux-in.h-with-netinet-in..patch |   146 +
 ...ags-FOLL_WRITE-games-from-__get_user.patch |    90 +
 ...ing_init-new-hook-for-archs-before-m.patch |   182 +
 .../patches-3.18/102-ehci_hcd_ignore_oc.patch |    82 +
 ...ame2-and-add-RENAME_WHITEOUT-support.patch |    86 +
 ...11-jffs2-add-RENAME_EXCHANGE-support.patch |    58 +
 ...ge_allow_receiption_on_disabled_port.patch |    54 +
 .../132-mips_inline_dma_ops.patch             |   688 +
 ...-__arch_swab-16-32-64-when-using-MIP.patch |    53 +
 ...-generic-parsing-of-linux-part-probe.patch |   175 +
 ...limit-scanned-flash-area-on-BCM47XX-.patch |    33 +
 ...part-don-t-fail-because-of-bit-flips.patch |    92 +
 ...ci-make-USB_XHCI_PLATFORM-selectable.patch |    41 +
 ...t_for_moving_ndp_to_end_of_ncm_frame.patch |   228 +
 ...ehci-orion-fix-probe-for-GENERIC_PHY.patch |    35 +
 ...-support-for-Quectel-EC20-Mini-PCIe-.patch |   114 +
 ...-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch |    96 +
 .../patches-3.18/200-fix_localversion.patch   |    11 +
 .../patches-3.18/201-extra_optimization.patch |    14 +
 .../patches-3.18/202-reduce_module_size.patch |    11 +
 .../203-kallsyms_uncompressed.patch           |   108 +
 .../patches-3.18/204-module_strip.patch       |   194 +
 .../205-backtrace_module_info.patch           |    36 +
 .../210-darwin_scripts_include.patch          |  3088 ++
 .../212-byteshift_portability.patch           |    51 +
 .../213-x86_vdso_portability.patch            |    13 +
 .../214-spidev_h_portability.patch            |    11 +
 .../patches-3.18/220-gc_sections.patch        |   531 +
 .../patches-3.18/221-module_exports.patch     |    88 +
 .../230-openwrt_lzma_options.patch            |    58 +
 .../patches-3.18/250-netfilter_depends.patch  |    18 +
 .../patches-3.18/251-sound_kconfig.patch      |    18 +
 .../patches-3.18/252-mv_cesa_depends.patch    |    10 +
 .../patches-3.18/253-ssb_b43_default_on.patch |    29 +
 .../254-textsearch_kconfig_hacks.patch        |    23 +
 .../255-lib80211_kconfig_hacks.patch          |    31 +
 .../256-crypto_add_kconfig_prompts.patch      |    47 +
 .../257-wireless_ext_kconfig_hack.patch       |    22 +
 .../258-netfilter_netlink_kconfig_hack.patch  |    11 +
 .../patches-3.18/259-regmap_dynamic.patch     |    80 +
 .../260-crypto_test_dependencies.patch        |    37 +
 ...libc-specific-inclusion-of-sysinfo.h.patch |    34 +
 ...bc-compat.h-do-not-rely-on-__GLIBC__.patch |    81 +
 ...prevent-redefinition-of-struct-ethhd.patch |    67 +
 .../300-mips_expose_boot_raw.patch            |    39 +
 .../301-mips_image_cmdline_hack.patch         |    28 +
 .../302-mips_no_branch_likely.patch           |    11 +
 .../patches-3.18/304-mips_disable_fpu.patch   |   105 +
 .../patches-3.18/305-mips_module_reloc.patch  |   353 +
 .../306-mips_mem_functions_performance.patch  |    83 +
 .../307-mips_highmem_offset.patch             |    17 +
 .../310-arm_module_unresolved_weak_sym.patch  |    13 +
 .../320-ppc4xx_optimization.patch             |    31 +
 .../321-powerpc_crtsavres_prereq.patch        |    10 +
 ...t-command-line-parameters-from-users.patch |   298 +
 .../400-mtd-add-rootfs-split-support.patch    |   171 +
 ...for-different-partition-parser-types.patch |   113 +
 ...arsers-for-rootfs-and-firmware-split.patch |    72 +
 .../403-mtd-hook-mtdsplit-to-Kbuild.patch     |    22 +
 .../404-mtd-add-more-helper-functions.patch   |   101 +
 ...405-mtd-old-firmware-uimage-splitter.patch |    70 +
 ...406-mtd-old-rootfs-squashfs-splitter.patch |    76 +
 ...rward-declaration-of-struct-mtd_info.patch |    18 +
 .../411-mtd-partial_eraseblock_write.patch    |   142 +
 .../412-mtd-partial_eraseblock_unlock.patch   |    18 +
 .../patches-3.18/420-mtd-redboot_space.patch  |    30 +
 ...30-mtd-add-myloader-partition-parser.patch |    35 +
 ...check-for-bad-blocks-when-calculatin.patch |   100 +
 ...bcm47xxpart-detect-T_Meter-partition.patch |    42 +
 .../patches-3.18/440-block2mtd_init.patch     |   107 +
 .../patches-3.18/441-block2mtd_probe.patch    |   110 +
 ...-to-use-platform-specific-chip-fixup.patch |    37 +
 ...n-code-of-nand_correct_data-function.patch |    11 +
 ...mtd-cfi_cmdset_0002-no-erase_suspend.patch |    11 +
 ...et_0002-add-buffer-write-cmd-timeout.patch |    18 +
 ...add-support-for-Winbond-W25X05-flash.patch |    20 +
 ...support-for-the-Macronix-MX25L512E-S.patch |    21 +
 ...support-for-the-ISSI-SI25CD512-SPI-f.patch |    22 +
 ...mtd-spi-nor-add-macronix-mx25u25635f.patch |    10 +
 .../480-mtd-set-rootfs-to-be-root-dev.patch   |    26 +
 ...mtd-device-named-ubi-or-data-on-boot.patch |    76 +
 ...to-create-ubiblock-device-for-rootfs.patch |    69 +
 ...ting-ubi0-rootfs-in-init-do_mounts.c.patch |    54 +
 ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch |    37 +
 .../494-mtd-ubi-add-EOF-marker-support.patch  |    51 +
 .../500-yaffs-Kbuild-integration.patch        |    18 +
 .../502-yaffs-fix-compat-tags-handling.patch  |   239 +
 ...3-yaffs-add-tags-9bytes-mount-option.patch |   115 +
 .../504-yaffs-3.16-new-fops.patch             |    25 +
 .../530-jffs2_make_lzma_available.patch       |  5142 +++
 .../patches-3.18/531-debloat_lzma.patch       |  1024 +
 .../patches-3.18/532-jffs2_eofdetect.patch    |    56 +
 .../540-crypto-xz-decompression-support.patch |   146 +
 .../541-ubifs-xz-decompression-support.patch  |    92 +
 .../550-ubifs-symlink-xattr-support.patch     |    55 +
 ...fs-fix-default-compression-selection.patch |    29 +
 .../600-netfilter_conntrack_flush.patch       |    86 +
 ...etfilter_match_bypass_default_checks.patch |    84 +
 ...netfilter_match_bypass_default_table.patch |    94 +
 ...netfilter_match_reduce_memory_access.patch |    16 +
 ...-netfilter_optional_tcp_window_check.patch |    36 +
 .../615-netfilter_add_xt_id_match.patch       |    95 +
 .../616-net_optimize_xfrm_calls.patch         |    12 +
 .../patches-3.18/621-sched_act_connmark.patch |   161 +
 .../patches-3.18/630-packet_socket_type.patch |   134 +
 .../640-bridge_no_eap_forward.patch           |    23 +
 .../641-bridge_always_accept_eap.patch        |    17 +
 .../642-bridge_port_isolate.patch             |   107 +
 .../645-bridge_multicast_to_unicast.patch     |   390 +
 .../patches-3.18/650-pppoe_header_pad.patch   |    20 +
 .../651-wireless_mesh_header.patch            |    11 +
 .../653-disable_netlink_trim.patch            |    30 +
 .../patches-3.18/655-increase_skb_pad.patch   |    11 +
 .../656-skb_reduce_truesize-helper.patch      |    41 +
 .../657-qdisc_reduce_truesize.patch           |    63 +
 .../patches-3.18/660-fq_codel_defaults.patch  |    13 +
 .../661-fq_codel_keep_dropped_stats.patch     |    10 +
 .../662-use_fq_codel_by_default.patch         |    95 +
 .../patches-3.18/663-remove_pfifo_fast.patch  |   143 +
 ...Add-support-for-MAP-E-FMRs-mesh-mode.patch |   481 +
 ...urce-specific-default-route-handling.patch |    96 +
 ...ng-with-source-address-failed-policy.patch |   249 +
 ...nes-for-_POLICY_FAILED-until-all-cod.patch |    53 +
 ...T-skip-GRO-for-foreign-MAC-addresses.patch |   160 +
 .../681-NET-add-of_get_mac_address_mtd.patch  |    88 +
 .../generic/patches-3.18/700-swconfig.patch   |    39 +
 .../patches-3.18/701-phy_extension.patch      |    63 +
 .../702-phy_add_aneg_done_function.patch      |    27 +
 ...detach-callback-to-struct-phy_driver.patch |    27 +
 .../704-phy-no-genphy-soft-reset.patch        |    29 +
 ...710-phy-add-mdio_register_board_info.patch |   192 +
 .../patches-3.18/720-phy_adm6996.patch        |    26 +
 .../patches-3.18/721-phy_packets.patch        |   161 +
 .../patches-3.18/722-phy_mvswitch.patch       |    23 +
 .../generic/patches-3.18/723-phy_ip175c.patch |    23 +
 .../generic/patches-3.18/724-phy_ar8216.patch |    24 +
 .../patches-3.18/725-phy_rtl8306.patch        |    23 +
 .../patches-3.18/726-phy_rtl8366.patch        |    45 +
 .../patches-3.18/727-phy-rtl8367.patch        |    23 +
 .../patches-3.18/728-phy-rtl8367b.patch       |    23 +
 .../generic/patches-3.18/729-phy-tantos.patch |    21 +
 .../generic/patches-3.18/730-phy_b53.patch    |    21 +
 .../732-phy-ar8216-led-support.patch          |    13 +
 .../patches-3.18/733-phy_mvsw61xx.patch       |    23 +
 ...-at803x-allow-to-configure-via-pdata.patch |   180 +
 ...net-phy-at803x-fix-at8033-sgmii-mode.patch |    96 +
 .../760-8139cp-fixes-from-4.3.patch           |   365 +
 .../773-bgmac-add-srab-switch.patch           |    72 +
 .../785-hso-support-0af0-9300.patch           |    25 +
 .../810-pci_disable_common_quirks.patch       |    51 +
 .../811-pci_disable_usb_common_quirks.patch   |   101 +
 .../patches-3.18/821-usb-dwc2-dualrole.patch  |   146 +
 .../patches-3.18/831-ledtrig_netdev.patch     |    21 +
 .../patches-3.18/834-ledtrig-libata.patch     |   153 +
 .../generic/patches-3.18/840-rtc7301.patch    |   250 +
 .../patches-3.18/841-rtc_pt7c4338.patch       |   247 +
 .../861-04_spi_gpio_implement_spi_delay.patch |    58 +
 .../patches-3.18/862-gpio_spi_driver.patch    |   373 +
 .../generic/patches-3.18/863-gpiommc.patch    |   844 +
 .../864-gpiommc_configfs_locking.patch        |    58 +
 .../patches-3.18/870-hifn795x_byteswap.patch  |    17 +
 .../880-gateworks_system_controller.patch     |   339 +
 .../890-8250_optional_sysrq.patch             |    24 +
 .../patches-3.18/901-debloat_sock_diag.patch  |    65 +
 .../patches-3.18/902-debloat_proc.patch       |   341 +
 .../patches-3.18/903-debloat_direct_io.patch  |    83 +
 .../patches-3.18/904-debloat_dma_buf.patch    |    44 +
 .../patches-3.18/910-kobject_uevent.patch     |    21 +
 .../911-kobject_add_broadcast_uevent.patch    |    65 +
 .../921-use_preinit_as_init.patch             |    12 +
 ...ays-create-console-node-in-initramfs.patch |    30 +
 .../generic/patches-3.18/930-crashlog.patch   |   276 +
 ...e-filenames-from-deps_initramfs-list.patch |    29 +
 .../980-arm_openwrt_machtypes.patch           |    32 +
 .../generic/patches-3.18/990-gpio_wdt.patch   |   360 +
 .../patches-3.18/995-mangle_bootargs.patch    |    58 +
 .../997-device_tree_cmdline.patch             |    24 +
 ...able_wilink_platform_without_drivers.patch |    15 +
 .../patches-3.18/999-seccomp_log.patch        |    34 +
 ...e-config.detected-into-OUTPUT-direct.patch |    54 +
 ...s-Fix-makefile-generation-under-dash.patch |    27 +
 .../patches-4.1/020-ssb-backport.patch        |   686 +
 .../generic/patches-4.1/021-ssb_sprom.patch   |    32 +
 .../patches-4.1/022-bcma-from-4.2.patch       |    86 +
 .../patches-4.1/023-bcma-from-4.4.patch       |    26 +
 .../patches-4.1/024-bcma-from-4.5.patch       |    49 +
 .../patches-4.1/025-bcma-from-4.6.patch       |   716 +
 .../030-backport_bcm47xx_nvram.patch          |    37 +
 .../040-fs-overlay-fix-stacking.patch         |    33 +
 ...nce-error-output-if-MS_SILENT-is-set.patch |    32 +
 ...ence-early-error-if-MS_SILENT-is-set.patch |    54 +
 .../050-backport_netfilter_rtcache.patch      |   505 +
 .../060-mips_decompressor_memmove.patch       |    22 +
 ...fix-MAC-soft-reset-bit-for-corerev-4.patch |    24 +
 ...bgmac-reset-all-4-GMAC-cores-on-init.patch |    28 +
 ...ment-fix-headroom-tests-and-skb-leak.patch |   101 +
 ...ncrease-headroom-on-received-packets.patch |    54 +
 ...ore-Introduce-a-USB-port-LED-trigger.patch |   464 +
 .../090-m25p80_spi-nor_update_to_4.4rc1.patch |  1129 +
 ...ility-of-linux-in.h-with-netinet-in..patch |   146 +
 ...ags-FOLL_WRITE-games-from-__get_user.patch |    90 +
 .../patches-4.1/102-ehci_hcd_ignore_oc.patch  |    82 +
 ...ame2-and-add-RENAME_WHITEOUT-support.patch |    86 +
 ...11-jffs2-add-RENAME_EXCHANGE-support.patch |    58 +
 ...ge_allow_receiption_on_disabled_port.patch |    54 +
 .../patches-4.1/132-mips_inline_dma_ops.patch |   697 +
 ...-__arch_swab-16-32-64-when-using-MIP.patch |    53 +
 ...-generic-parsing-of-linux-part-probe.patch |   175 +
 ...or-disable-protection-for-Winbond-fl.patch |    35 +
 ...ude-mtd.h-header-for-struct-mtd_info.patch |    38 +
 ...limit-scanned-flash-area-on-BCM47XX-.patch |    33 +
 ...part-don-t-fail-because-of-bit-flips.patch |    92 +
 ...ci-make-USB_XHCI_PLATFORM-selectable.patch |    41 +
 ...t_for_moving_ndp_to_end_of_ncm_frame.patch |   232 +
 ...-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch |    96 +
 .../patches-4.1/200-fix_localversion.patch    |    11 +
 .../patches-4.1/201-extra_optimization.patch  |    14 +
 .../patches-4.1/202-reduce_module_size.patch  |    11 +
 .../203-kallsyms_uncompressed.patch           |   108 +
 .../patches-4.1/204-module_strip.patch        |   194 +
 .../205-backtrace_module_info.patch           |    36 +
 .../210-darwin_scripts_include.patch          |  3088 ++
 .../212-byteshift_portability.patch           |    51 +
 .../214-spidev_h_portability.patch            |    11 +
 .../generic/patches-4.1/220-gc_sections.patch |   536 +
 .../patches-4.1/221-module_exports.patch      |    88 +
 ...ld-Do-not-fail-on-missing-Build-file.patch |    57 +
 .../230-openwrt_lzma_options.patch            |    58 +
 .../patches-4.1/250-netfilter_depends.patch   |    18 +
 .../patches-4.1/251-sound_kconfig.patch       |    18 +
 .../patches-4.1/252-mv_cesa_depends.patch     |    10 +
 .../patches-4.1/253-ssb_b43_default_on.patch  |    29 +
 .../254-textsearch_kconfig_hacks.patch        |    23 +
 .../255-lib80211_kconfig_hacks.patch          |    31 +
 .../256-crypto_add_kconfig_prompts.patch      |    47 +
 .../257-wireless_ext_kconfig_hack.patch       |    22 +
 .../258-netfilter_netlink_kconfig_hack.patch  |    11 +
 .../patches-4.1/259-regmap_dynamic.patch      |    87 +
 .../260-crypto_test_dependencies.patch        |    37 +
 ...libc-specific-inclusion-of-sysinfo.h.patch |    34 +
 ...bc-compat.h-do-not-rely-on-__GLIBC__.patch |    81 +
 ...prevent-redefinition-of-struct-ethhd.patch |    67 +
 .../300-mips_expose_boot_raw.patch            |    39 +
 .../301-mips_image_cmdline_hack.patch         |    28 +
 .../302-mips_no_branch_likely.patch           |    11 +
 .../patches-4.1/304-mips_disable_fpu.patch    |   106 +
 .../patches-4.1/305-mips_module_reloc.patch   |   352 +
 .../306-mips_mem_functions_performance.patch  |    83 +
 .../patches-4.1/307-mips_highmem_offset.patch |    17 +
 .../310-arm_module_unresolved_weak_sym.patch  |    13 +
 .../patches-4.1/320-ppc4xx_optimization.patch |    31 +
 .../321-powerpc_crtsavres_prereq.patch        |    10 +
 ...t-command-line-parameters-from-users.patch |   298 +
 .../400-mtd-add-rootfs-split-support.patch    |   146 +
 ...for-different-partition-parser-types.patch |   113 +
 ...arsers-for-rootfs-and-firmware-split.patch |    72 +
 .../403-mtd-hook-mtdsplit-to-Kbuild.patch     |    22 +
 .../404-mtd-add-more-helper-functions.patch   |   101 +
 ...405-mtd-old-firmware-uimage-splitter.patch |    70 +
 ...rward-declaration-of-struct-mtd_info.patch |    18 +
 .../411-mtd-partial_eraseblock_write.patch    |   142 +
 .../412-mtd-partial_eraseblock_unlock.patch   |    18 +
 .../patches-4.1/420-mtd-redboot_space.patch   |    30 +
 ...30-mtd-add-myloader-partition-parser.patch |    35 +
 ...check-for-bad-blocks-when-calculatin.patch |   100 +
 ...bcm47xxpart-detect-T_Meter-partition.patch |    42 +
 .../patches-4.1/440-block2mtd_init.patch      |   108 +
 .../patches-4.1/441-block2mtd_probe.patch     |    39 +
 ...-to-use-platform-specific-chip-fixup.patch |    37 +
 ...n-code-of-nand_correct_data-function.patch |    11 +
 ...mtd-cfi_cmdset_0002-no-erase_suspend.patch |    11 +
 ...et_0002-add-buffer-write-cmd-timeout.patch |    18 +
 ...25p80-mx-disable-software-protection.patch |    14 +
 .../480-mtd-set-rootfs-to-be-root-dev.patch   |    26 +
 ...mtd-device-named-ubi-or-data-on-boot.patch |    76 +
 ...to-create-ubiblock-device-for-rootfs.patch |    69 +
 ...ting-ubi0-rootfs-in-init-do_mounts.c.patch |    54 +
 ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch |    37 +
 .../494-mtd-ubi-add-EOF-marker-support.patch  |    51 +
 .../500-yaffs-Kbuild-integration.patch        |    18 +
 .../502-yaffs-fix-compat-tags-handling.patch  |   239 +
 ...3-yaffs-add-tags-9bytes-mount-option.patch |   115 +
 .../patches-4.1/504-yaffs-3.16-new-fops.patch |    29 +
 .../505-yaffs-3.19-f_dentry-remove.patch      |    95 +
 .../530-jffs2_make_lzma_available.patch       |  5142 +++
 .../patches-4.1/531-debloat_lzma.patch        |  1024 +
 .../patches-4.1/532-jffs2_eofdetect.patch     |    56 +
 .../540-crypto-xz-decompression-support.patch |   146 +
 .../541-ubifs-xz-decompression-support.patch  |    92 +
 ...fs-fix-default-compression-selection.patch |    29 +
 .../600-netfilter_conntrack_flush.patch       |    86 +
 ...etfilter_match_bypass_default_checks.patch |    84 +
 ...netfilter_match_bypass_default_table.patch |    94 +
 ...netfilter_match_reduce_memory_access.patch |    16 +
 ...-netfilter_optional_tcp_window_check.patch |    36 +
 .../615-netfilter_add_xt_id_match.patch       |    95 +
 .../616-net_optimize_xfrm_calls.patch         |    12 +
 .../patches-4.1/630-packet_socket_type.patch  |   134 +
 .../640-bridge_no_eap_forward.patch           |    23 +
 .../641-bridge_always_accept_eap.patch        |    17 +
 .../patches-4.1/642-bridge_port_isolate.patch |   107 +
 .../645-bridge_multicast_to_unicast.patch     |   397 +
 .../patches-4.1/650-pppoe_header_pad.patch    |    20 +
 .../651-wireless_mesh_header.patch            |    11 +
 .../653-disable_netlink_trim.patch            |    30 +
 .../patches-4.1/655-increase_skb_pad.patch    |    11 +
 .../656-skb_reduce_truesize-helper.patch      |    41 +
 .../657-qdisc_reduce_truesize.patch           |    63 +
 .../patches-4.1/660-fq_codel_defaults.patch   |    13 +
 .../661-fq_codel_keep_dropped_stats.patch     |    10 +
 .../662-use_fq_codel_by_default.patch         |    75 +
 .../patches-4.1/663-remove_pfifo_fast.patch   |   143 +
 .../patches-4.1/664-codel_fix_3_12.patch      |    22 +
 ...Add-support-for-MAP-E-FMRs-mesh-mode.patch |   495 +
 ...ng-with-source-address-failed-policy.patch |   249 +
 ...nes-for-_POLICY_FAILED-until-all-cod.patch |    53 +
 ...T-skip-GRO-for-foreign-MAC-addresses.patch |   160 +
 .../681-NET-add-of_get_mac_address_mtd.patch  |    88 +
 .../generic/patches-4.1/700-swconfig.patch    |    39 +
 .../patches-4.1/701-phy_extension.patch       |    63 +
 .../702-phy_add_aneg_done_function.patch      |    27 +
 ...detach-callback-to-struct-phy_driver.patch |    27 +
 .../704-phy-no-genphy-soft-reset.patch        |    29 +
 ...710-phy-add-mdio_register_board_info.patch |   193 +
 .../generic/patches-4.1/720-phy_adm6996.patch |    26 +
 .../generic/patches-4.1/721-phy_packets.patch |   161 +
 .../patches-4.1/722-phy_mvswitch.patch        |    23 +
 .../generic/patches-4.1/723-phy_ip175c.patch  |    23 +
 .../generic/patches-4.1/724-phy_ar8216.patch  |    24 +
 .../generic/patches-4.1/725-phy_rtl8306.patch |    23 +
 .../generic/patches-4.1/726-phy_rtl8366.patch |    45 +
 .../generic/patches-4.1/727-phy-rtl8367.patch |    23 +
 .../patches-4.1/728-phy-rtl8367b.patch        |    23 +
 .../generic/patches-4.1/729-phy-tantos.patch  |    21 +
 .../generic/patches-4.1/730-phy_b53.patch     |    21 +
 .../732-phy-ar8216-led-support.patch          |    13 +
 .../patches-4.1/733-phy_mvsw61xx.patch        |    23 +
 ...-at803x-allow-to-configure-via-pdata.patch |   180 +
 ...net-phy-at803x-fix-at8033-sgmii-mode.patch |    96 +
 .../760-8139cp-fixes-from-4.3.patch           |   365 +
 .../761-8139cp-fixes-from-4.4.patch           |   103 +
 .../773-bgmac-add-srab-switch.patch           |    72 +
 .../785-hso-support-0af0-9300.patch           |    25 +
 .../810-pci_disable_common_quirks.patch       |    51 +
 .../811-pci_disable_usb_common_quirks.patch   |   101 +
 .../patches-4.1/831-ledtrig_netdev.patch      |    21 +
 .../patches-4.1/834-ledtrig-libata.patch      |   153 +
 .../generic/patches-4.1/840-rtc7301.patch     |   250 +
 .../patches-4.1/841-rtc_pt7c4338.patch        |   247 +
 .../861-04_spi_gpio_implement_spi_delay.patch |    58 +
 .../patches-4.1/862-gpio_spi_driver.patch     |   373 +
 .../generic/patches-4.1/863-gpiommc.patch     |   844 +
 .../864-gpiommc_configfs_locking.patch        |    58 +
 .../patches-4.1/870-hifn795x_byteswap.patch   |    17 +
 .../880-gateworks_system_controller.patch     |   339 +
 .../patches-4.1/890-8250_optional_sysrq.patch |    24 +
 .../patches-4.1/901-debloat_sock_diag.patch   |    65 +
 .../patches-4.1/902-debloat_proc.patch        |   385 +
 .../patches-4.1/903-debloat_direct_io.patch   |    80 +
 .../patches-4.1/904-debloat_dma_buf.patch     |    44 +
 .../patches-4.1/910-kobject_uevent.patch      |    21 +
 .../911-kobject_add_broadcast_uevent.patch    |    65 +
 .../patches-4.1/921-use_preinit_as_init.patch |    12 +
 ...ays-create-console-node-in-initramfs.patch |    30 +
 .../generic/patches-4.1/930-crashlog.patch    |   276 +
 ...e-filenames-from-deps_initramfs-list.patch |    29 +
 .../980-arm_openwrt_machtypes.patch           |    32 +
 .../patches-4.1/995-mangle_bootargs.patch     |    58 +
 .../patches-4.1/997-device_tree_cmdline.patch |    24 +
 ...able_wilink_platform_without_drivers.patch |    15 +
 ...dcode-path-to-awk-in-scripts-ld-vers.patch |    24 +
 .../patches-4.4/020-bcma-from-4.5.patch       |    49 +
 .../patches-4.4/021-bcma-from-4.6.patch       |   761 +
 .../patches-4.4/022-bcma-from-4.8.patch       |    52 +
 .../patches-4.4/023-bcma-from-4.9.patch       |    82 +
 ...l-add-batch-ability-to-fq_codel_drop.patch |   189 +
 ...odel-add-memory-limitation-per-queue.patch |   182 +
 ...fq_codel-fix-memory-limitation-drift.patch |    40 +
 ...35-fq_codel-fix-NET_XMIT_CN-behavior.patch |    70 +
 ...limit-scanned-flash-area-on-BCM47XX-.patch |    35 +
 ...part-don-t-fail-because-of-bit-flips.patch |    93 +
 ...h-use-ioremap_cache-instead-of-KSEG0.patch |   138 +
 ...endency-for-MTD_BCM47XXSFLASH-symbol.patch |    41 +
 ...h-use-uncached-MMIO-access-for-BCM53.patch |    59 +
 ...fix-parsing-first-block-after-aligne.patch |    40 +
 ...mx25l3205d-mx25l6405d-append-SECT_4K.patch |    27 +
 ...80-add-support-for-mmap-read-request.patch |    46 +
 ...nce-error-output-if-MS_SILENT-is-set.patch |    32 +
 ...ence-early-error-if-MS_SILENT-is-set.patch |    54 +
 .../050-backport_netfilter_rtcache.patch      |   531 +
 ...001-ovl-rename-is_merge-to-is_lowest.patch |    72 +
 ...ds-with-the-ones-from-the-superblock.patch |   336 +
 ...1-0005-ovl-proper-cleanup-of-workdir.patch |   131 +
 .../052-01-ubifs-Implement-O_TMPFILE.patch    |    99 +
 ...2-02-ubifs-Implement-RENAME_WHITEOUT.patch |   343 +
 ...2-03-ubifs-Implement-RENAME_EXCHANGE.patch |   267 +
 ...fs-Use-move-variable-in-ubifs_rename.patch |    30 +
 .../060-mips_decompressor_memmove.patch       |    22 +
 ...061-softirq-let-ksoftirqd-do-its-job.patch |    83 +
 ...ac-fix-a-missing-check-for-build_skb.patch |    28 +
 ...ersed-test-of-build_skb-return-value.patch |    22 +
 ...bgmac-clarify-CONFIG_BCMA-dependency.patch |    46 +
 ...-checking-for-BCM4707-BCM53018-chip-.patch |   106 +
 ...port-Ethernet-device-on-BCM47094-SoC.patch |    39 +
 ...enable-Ethernet-core-before-using-it.patch |    31 +
 ...fix-MAC-soft-reset-bit-for-corerev-4.patch |    34 +
 ...device-with-backing-device-structure.patch |    25 +
 ...c-Add-support-for-ethtool-statistics.patch |   175 +
 ...gmac-Maintain-some-netdev-statistics.patch |    68 +
 ...ac-use-phydev-from-struct-net_device.patch |   105 +
 ...-0001-net-bgmac-Fix-SOF-bit-checking.patch |    37 +
 ...c-Start-transmit-queue-in-bgmac_open.patch |    28 +
 ...c-Remove-superflous-netif_carrier_on.patch |    28 +
 ...ac-change-bgmac_-prints-to-dev_-prin.patch |   407 +
 ...t-ethernet-bgmac-add-dma_dev-pointer.patch |   112 +
 ...ac-move-BCMA-MDIO-Phy-code-into-a-se.patch |   676 +
 ...ernet-bgmac-convert-to-feature-flags.patch |   384 +
 ...et-bgmac-Add-platform-device-support.patch |  1260 +
 ...ac-Fix-return-value-check-in-bgmac_p.patch |    26 +
 ...ac-Remove-redundant-dev_err-call-in-.patch |    42 +
 ...versed-check-for-MII-registration-er.patch |    28 +
 ...pport-Ethernet-core-on-BCM53573-SoCs.patch |   161 +
 ...t-clear-when-setting-interface-type-.patch |    31 +
 ...-bgmac-Fix-errant-feature-flag-check.patch |    33 +
 ...pelling-mistake-connecton-connection.patch |    25 +
 ...celerated-read-support-for-spi-flash.patch |   179 +
 ...spi_flash_read-callback-for-MMIO-bas.patch |   157 +
 ...core-let-USB-device-know-device-node.patch |   179 +
 ...usb_alloc_dev-fix-setting-of-portnum.patch |   108 +
 ...vm_-clk_hw_-register-unregister-APIs.patch |   182 +
 ...0002-clk-Add-clk_hw-OF-clk-providers.patch |   234 +
 ...ore-Introduce-a-USB-port-LED-trigger.patch |   465 +
 ...-Use-proper-LED-API-to-fix-potential.patch |    70 +
 ...-Set-of_node-for-created-LED-devices.patch |    53 +
 ...e-IPI-calls-for-CM-indexed-cache-ops.patch |   317 +
 ...4k-Exclude-sibling-CPUs-in-SMP-calls.patch |    37 +
 ...appended-dtb-to-the-end-of-the-kerne.patch |   132 +
 ...e-appended-dtb-address-in-a-variable.patch |   132 +
 .../096-arc-add-model-property-in-dts.patch   |   163 +
 .../097-MIPS-io.h-Define-ioremap_cache.patch  |    29 +
 ...fix-cache-flushing-for-highmem-pages.patch |    31 +
 .../patches-4.4/102-ehci_hcd_ignore_oc.patch  |    82 +
 ...e_mem_map-with-ARCH_PFN_OFFSET-calcu.patch |    86 +
 ...of_scan_flat_dt-before-accessing-ini.patch |    30 +
 ...ame2-and-add-RENAME_WHITEOUT-support.patch |    86 +
 ...11-jffs2-add-RENAME_EXCHANGE-support.patch |    58 +
 ...ge_allow_receiption_on_disabled_port.patch |    54 +
 .../patches-4.4/132-mips_inline_dma_ops.patch |   778 +
 ...-generic-parsing-of-linux-part-probe.patch |   183 +
 ...ude-mtd.h-header-for-struct-mtd_info.patch |    38 +
 ...support-for-ESMT_f25l32qa-and-ESMT_f.patch |    21 +
 ...dget-udc-net2280-add-usb2380-support.patch |   253 +
 ...versed-checks-for-clock-control-flag.patch |    32 +
 .../patches-4.4/200-fix_localversion.patch    |    11 +
 .../patches-4.4/201-extra_optimization.patch  |    18 +
 .../patches-4.4/202-reduce_module_size.patch  |    11 +
 .../203-kallsyms_uncompressed.patch           |   108 +
 .../patches-4.4/204-module_strip.patch        |   194 +
 .../205-backtrace_module_info.patch           |    36 +
 .../patches-4.4/206-mips-disable-vdso.patch   |    21 +
 ...-mips-vdso-dbg-rebuild-after-genvdso.patch |    29 +
 .../210-darwin_scripts_include.patch          |  3088 ++
 .../patches-4.4/211-sign-file-libressl.patch  |    16 +
 .../212-byteshift_portability.patch           |    51 +
 .../214-spidev_h_portability.patch            |    11 +
 .../generic/patches-4.4/220-gc_sections.patch |   536 +
 .../patches-4.4/221-module_exports.patch      |    88 +
 .../patches-4.4/222-arm_zimage_none.patch     |   133 +
 .../230-openwrt_lzma_options.patch            |    58 +
 .../patches-4.4/250-netfilter_depends.patch   |    18 +
 .../patches-4.4/251-sound_kconfig.patch       |    18 +
 .../patches-4.4/252-mv_cesa_depends.patch     |    10 +
 .../patches-4.4/253-ssb_b43_default_on.patch  |    29 +
 .../254-textsearch_kconfig_hacks.patch        |    23 +
 .../255-lib80211_kconfig_hacks.patch          |    31 +
 .../256-crypto_add_kconfig_prompts.patch      |    47 +
 .../257-wireless_ext_kconfig_hack.patch       |    22 +
 .../258-netfilter_netlink_kconfig_hack.patch  |    11 +
 .../patches-4.4/259-regmap_dynamic.patch      |    87 +
 .../260-crypto_test_dependencies.patch        |    48 +
 ...libc-specific-inclusion-of-sysinfo.h.patch |    34 +
 ...bc-compat.h-do-not-rely-on-__GLIBC__.patch |    94 +
 ...prevent-redefinition-of-struct-ethhd.patch |    67 +
 .../patches-4.4/280-rfkill-stubs.patch        |    79 +
 .../300-mips_expose_boot_raw.patch            |    39 +
 .../301-mips_image_cmdline_hack.patch         |    28 +
 .../302-mips_no_branch_likely.patch           |    11 +
 .../patches-4.4/304-mips_disable_fpu.patch    |   106 +
 .../patches-4.4/305-mips_module_reloc.patch   |   352 +
 .../306-mips_mem_functions_performance.patch  |    83 +
 .../patches-4.4/307-mips_highmem_offset.patch |    17 +
 .../patches-4.4/308-mips32r2_tune.patch       |    17 +
 .../310-arm_module_unresolved_weak_sym.patch  |    13 +
 .../patches-4.4/320-ppc4xx_optimization.patch |    31 +
 .../321-powerpc_crtsavres_prereq.patch        |    10 +
 ...t-command-line-parameters-from-users.patch |   298 +
 ...31-arc-remove-dependency-on-DEVTMPFS.patch |    31 +
 .../332-arc-add-OWRTDTB-section.patch         |    82 +
 ...able-unaligned-access-in-kernel-mode.patch |    26 +
 .../400-mtd-add-rootfs-split-support.patch    |   113 +
 ...for-different-partition-parser-types.patch |   113 +
 ...arsers-for-rootfs-and-firmware-split.patch |    71 +
 .../403-mtd-hook-mtdsplit-to-Kbuild.patch     |    22 +
 .../404-mtd-add-more-helper-functions.patch   |   101 +
 ...rward-declaration-of-struct-mtd_info.patch |    18 +
 .../411-mtd-partial_eraseblock_write.patch    |   142 +
 .../412-mtd-partial_eraseblock_unlock.patch   |    18 +
 .../patches-4.4/420-mtd-redboot_space.patch   |    30 +
 ...30-mtd-add-myloader-partition-parser.patch |    35 +
 ...check-for-bad-blocks-when-calculatin.patch |   100 +
 ...bcm47xxpart-detect-T_Meter-partition.patch |    42 +
 .../patches-4.4/440-block2mtd_init.patch      |   108 +
 .../patches-4.4/441-block2mtd_probe.patch     |    39 +
 ...-to-use-platform-specific-chip-fixup.patch |    37 +
 ...n-code-of-nand_correct_data-function.patch |    11 +
 ...mtd-cfi_cmdset_0002-no-erase_suspend.patch |    11 +
 ...et_0002-add-buffer-write-cmd-timeout.patch |    18 +
 ...25p80-mx-disable-software-protection.patch |    14 +
 ...mtd-spi-nor-add-macronix-mx25u25635f.patch |    10 +
 .../476-mtd-spi-nor-add-eon-en25q128.patch    |    10 +
 .../477-mtd-add-spi-nor-add-mx25u3235f.patch  |    10 +
 .../480-mtd-set-rootfs-to-be-root-dev.patch   |    26 +
 ...mtd-device-named-ubi-or-data-on-boot.patch |    76 +
 ...to-create-ubiblock-device-for-rootfs.patch |    69 +
 ...ting-ubi0-rootfs-in-init-do_mounts.c.patch |    54 +
 ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch |    37 +
 .../494-mtd-ubi-add-EOF-marker-support.patch  |    51 +
 .../500-yaffs-Kbuild-integration.patch        |    18 +
 .../502-yaffs-fix-compat-tags-handling.patch  |   239 +
 ...3-yaffs-add-tags-9bytes-mount-option.patch |   115 +
 .../patches-4.4/504-yaffs-3.16-new-fops.patch |    29 +
 .../505-yaffs-3.19-f_dentry-remove.patch      |    95 +
 ...2-using-new-follow_link-and-put_link.patch |    47 +
 .../530-jffs2_make_lzma_available.patch       |  5142 +++
 .../patches-4.4/531-debloat_lzma.patch        |  1024 +
 .../patches-4.4/532-jffs2_eofdetect.patch     |    56 +
 .../540-crypto-xz-decompression-support.patch |   146 +
 .../541-ubifs-xz-decompression-support.patch  |    94 +
 ...fs-fix-default-compression-selection.patch |    29 +
 .../600-netfilter_conntrack_flush.patch       |    86 +
 ...etfilter_match_bypass_default_checks.patch |    84 +
 ...netfilter_match_bypass_default_table.patch |   111 +
 ...netfilter_match_reduce_memory_access.patch |    16 +
 ...-netfilter_optional_tcp_window_check.patch |    36 +
 .../615-netfilter_add_xt_id_match.patch       |    95 +
 .../616-net_optimize_xfrm_calls.patch         |    12 +
 .../patches-4.4/630-packet_socket_type.patch  |   134 +
 .../640-bridge_no_eap_forward.patch           |    23 +
 .../641-bridge_always_accept_eap.patch        |    17 +
 .../patches-4.4/642-bridge_port_isolate.patch |   107 +
 .../645-bridge_multicast_to_unicast.patch     |   420 +
 .../patches-4.4/650-pppoe_header_pad.patch    |    20 +
 .../651-wireless_mesh_header.patch            |    11 +
 .../653-disable_netlink_trim.patch            |    30 +
 .../patches-4.4/655-increase_skb_pad.patch    |    11 +
 .../patches-4.4/660-fq_codel_defaults.patch   |    11 +
 .../661-fq_codel_keep_dropped_stats.patch     |    10 +
 .../662-use_fq_codel_by_default.patch         |    95 +
 .../patches-4.4/663-remove_pfifo_fast.patch   |   142 +
 ...Add-support-for-MAP-E-FMRs-mesh-mode.patch |   496 +
 ...ng-with-source-address-failed-policy.patch |   249 +
 ...nes-for-_POLICY_FAILED-until-all-cod.patch |    53 +
 ...T-skip-GRO-for-foreign-MAC-addresses.patch |   160 +
 .../681-NET-add-of_get_mac_address_mtd.patch  |   128 +
 .../generic/patches-4.4/700-swconfig.patch    |    39 +
 .../patches-4.4/701-phy_extension.patch       |    63 +
 .../702-phy_add_aneg_done_function.patch      |    27 +
 ...detach-callback-to-struct-phy_driver.patch |    27 +
 .../704-phy-no-genphy-soft-reset.patch        |    29 +
 ...710-phy-add-mdio_register_board_info.patch |   193 +
 .../generic/patches-4.4/720-phy_adm6996.patch |    26 +
 .../generic/patches-4.4/721-phy_packets.patch |   161 +
 .../patches-4.4/722-phy_mvswitch.patch        |    23 +
 .../generic/patches-4.4/723-phy_ip175c.patch  |    23 +
 .../generic/patches-4.4/724-phy_ar8216.patch  |    24 +
 .../generic/patches-4.4/725-phy_rtl8306.patch |    23 +
 .../generic/patches-4.4/726-phy_rtl8366.patch |    45 +
 .../generic/patches-4.4/727-phy-rtl8367.patch |    23 +
 .../patches-4.4/728-phy-rtl8367b.patch        |    23 +
 .../generic/patches-4.4/729-phy-tantos.patch  |    21 +
 .../generic/patches-4.4/730-phy_b53.patch     |    21 +
 .../732-phy-ar8216-led-support.patch          |    13 +
 .../patches-4.4/733-phy_mvsw61xx.patch        |    23 +
 ...-at803x-allow-to-configure-via-pdata.patch |   180 +
 ...net-phy-at803x-fix-at8033-sgmii-mode.patch |    96 +
 .../736-at803x-fix-reset-handling.patch       |    43 +
 ...equest-reset-GPIO-only-for-AT8030-PH.patch |    42 +
 ...nly-the-AT8030-needs-a-hardware-rese.patch |    81 +
 ...et-phy-at803x-add-support-for-AT8032.patch |    65 +
 .../773-bgmac-add-srab-switch.patch           |    88 +
 .../785-hso-support-0af0-9300.patch           |    25 +
 .../810-pci_disable_common_quirks.patch       |    51 +
 .../811-pci_disable_usb_common_quirks.patch   |   101 +
 ...ove-annoying-warning-about-bogus-URB.patch |    78 +
 .../patches-4.4/831-ledtrig_netdev.patch      |    21 +
 .../patches-4.4/834-ledtrig-libata.patch      |   153 +
 .../patches-4.4/835-misc-owl_loader.patch     |    31 +
 .../generic/patches-4.4/840-rtc7301.patch     |   250 +
 .../patches-4.4/841-rtc_pt7c4338.patch        |   247 +
 .../861-04_spi_gpio_implement_spi_delay.patch |    58 +
 .../patches-4.4/862-gpio_spi_driver.patch     |   373 +
 .../generic/patches-4.4/863-gpiommc.patch     |   844 +
 .../864-gpiommc_configfs_locking.patch        |    58 +
 .../patches-4.4/870-hifn795x_byteswap.patch   |    17 +
 .../880-gateworks_system_controller.patch     |   339 +
 .../patches-4.4/890-uart_optional_sysrq.patch |    25 +
 .../patches-4.4/901-debloat_sock_diag.patch   |    79 +
 .../patches-4.4/902-debloat_proc.patch        |   385 +
 .../patches-4.4/903-debloat_direct_io.patch   |    80 +
 .../patches-4.4/904-debloat_dma_buf.patch     |    44 +
 .../patches-4.4/910-kobject_uevent.patch      |    21 +
 .../911-kobject_add_broadcast_uevent.patch    |    65 +
 .../patches-4.4/921-use_preinit_as_init.patch |    12 +
 ...ays-create-console-node-in-initramfs.patch |    30 +
 .../generic/patches-4.4/930-crashlog.patch    |   317 +
 ...e-filenames-from-deps_initramfs-list.patch |    29 +
 .../980-arm_openwrt_machtypes.patch           |    32 +
 .../patches-4.4/995-mangle_bootargs.patch     |    58 +
 ...able_wilink_platform_without_drivers.patch |    15 +
 target/linux/sunxi/Makefile                   |    32 +
 .../sunxi/base-files/etc/board.d/02_network   |    26 +
 target/linux/sunxi/base-files/etc/inittab     |     5 +
 .../lib/firmware/brcm/brcmfmac4329-sdio.txt   |    57 +
 .../lib/firmware/brcm/brcmfmac43362-sdio.txt  |    51 +
 .../lib/preinit/01_preinit_sunxi.sh           |     9 +
 .../base-files/lib/preinit/02_b53_hack.sh     |    17 +
 target/linux/sunxi/base-files/lib/sunxi.sh    |   150 +
 target/linux/sunxi/config-4.4                 |   533 +
 target/linux/sunxi/image/Config.in            |     5 +
 target/linux/sunxi/image/Makefile             |   121 +
 .../linux/sunxi/image/gen_sunxi_sdcard_img.sh |    35 +
 target/linux/sunxi/modules.mk                 |   125 +
 ...100-clk-sunxi-add-dram-gates-support.patch |    39 +
 .../101-dt-sun4i-add-dram-gates.patch         |    88 +
 .../102-dt-sun7i-add-dram-gates.patch         |    77 +
 .../103-clk-sunxi-add-h3-clksupport.patch     |   180 +
 .../104-1-dt-sunxi-add-h3-dtsi.patch          |   515 +
 .../104-2-dt-sun8i-add-orangepi-plus.patch    |   111 +
 .../105-phy-use_of_match_node.patch           |   218 +
 .../patches-4.4/106-phy-add-h3-usbphys.patch  |   124 +
 .../107-clk-sunxi-add-h3-usbphy-clocks.patch  |    47 +
 .../110-clk-sunxi-add-ve-for-sun457i.patch    |   226 +
 .../111-1-dt-sun4i-add-ve-clock-module.patch  |    32 +
 .../111-2-dt-sun7i-add-ve-clock-module.patch  |    32 +
 .../115-musb-ignore-vbus-errors.patch         |    26 +
 .../130-pinctrl-sunxi-add-h3-pio.patch        |   568 +
 .../patches-4.4/131-reset-add-h3-resets.patch |    92 +
 .../132-dt-sun8i-add-h3-usbclocks.patch       |    34 +
 ...-sun8i-add-usbphy-usbhost-ctrl-nodes.patch |   123 +
 ...dt-sun8i-orangepiplus-enable-usbhost.patch |    77 +
 .../135-clk-sunxi-fix-signedness-bug.patch    |    25 +
 ...et-add-of_reset_control_get_by_index.patch |   109 +
 .../141-reset-fix-of_reset_control_get.patch  |    39 +
 ...reset-use-ENOTSUPP-instead-of-ENOSYS.patch |    87 +
 ...eset-add-shared-resetcontrol-asserts.patch |   265 +
 ...lat-support-multiple-reset-ctrllines.patch |   127 +
 ...lat-support-multiple-reset-ctrllines.patch |   128 +
 ...50-dt-sun7i-enable-codec-on-pcduino3.patch |    27 +
 .../200-dt-sun7i-add-lamobo-r1.patch          |   330 +
 target/linux/sunxi/profiles/01-default.mk     |    17 +
 target/linux/sunxi/profiles/a10-olinuxino.mk  |    19 +
 target/linux/sunxi/profiles/a13-olimex-som.mk |    18 +
 target/linux/sunxi/profiles/a13-olinuxino.mk  |    18 +
 target/linux/sunxi/profiles/a20-olinuxino.mk  |    33 +
 target/linux/sunxi/profiles/bananapi.mk       |    18 +
 target/linux/sunxi/profiles/bananapro.mk      |    19 +
 target/linux/sunxi/profiles/cubieboard.mk     |    19 +
 target/linux/sunxi/profiles/cubieboard2.mk    |    19 +
 target/linux/sunxi/profiles/cubietruck.mk     |    19 +
 target/linux/sunxi/profiles/lamobo-r1.mk      |    19 +
 target/linux/sunxi/profiles/mele_m9.mk        |    18 +
 target/linux/sunxi/profiles/orangepi_plus.mk  |    18 +
 target/linux/sunxi/profiles/pcduino.mk        |    18 +
 target/linux/sunxi/profiles/pcduino3.mk       |    19 +
 target/linux/uml/Makefile                     |    42 +
 target/linux/uml/README                       |    45 +
 target/linux/uml/base-files/etc/inittab       |     4 +
 target/linux/uml/config/i386                  |   178 +
 target/linux/uml/config/x86_64                |   153 +
 target/linux/uml/image/Makefile               |    24 +
 .../uml/patches-4.4/101-mconsole-exec.patch   |   211 +
 .../patches-4.4/102-pseudo-random-mac.patch   |   124 +
 target/linux/x86/64/config-default            |   271 +
 target/linux/x86/64/profiles/000-Generic.mk   |    15 +
 target/linux/x86/64/target.mk                 |     7 +
 target/linux/x86/Makefile                     |    28 +
 target/linux/x86/base-files/etc/inittab       |     4 +
 .../lib/preinit/15_essential_fs_x86           |     8 +
 .../x86/base-files/lib/preinit/20_check_iso   |     5 +
 .../x86/base-files/lib/preinit/20_sysinfo     |    28 +
 .../x86/base-files/lib/preinit/79_move_config |    17 +
 .../x86/base-files/lib/upgrade/platform.sh    |   163 +
 target/linux/x86/config-4.4                   |   450 +
 target/linux/x86/generic/config-default       |   345 +
 .../linux/x86/generic/profiles/000-Generic.mk |    18 +
 target/linux/x86/generic/target.mk            |    11 +
 target/linux/x86/geode/config-default         |    76 +
 target/linux/x86/geode/target.mk              |    14 +
 target/linux/x86/image/Makefile               |   194 +
 target/linux/x86/image/gen_image_generic.sh   |    37 +
 target/linux/x86/image/grub-early.cfg         |     1 +
 target/linux/x86/image/grub-iso.cfg           |    10 +
 target/linux/x86/image/grub.cfg               |    13 +
 target/linux/x86/legacy/config-default        |   215 +
 .../linux/x86/legacy/profiles/000-Generic.mk  |    18 +
 target/linux/x86/legacy/target.mk             |     7 +
 .../patches-4.4/011-tune_lzma_options.patch   |    22 +
 .../patches-4.4/100-fix_cs5535_clockevt.patch |    12 +
 .../linux/x86/xen_domu/base-files/etc/inittab |     5 +
 .../base-files/lib/preinit/45_mount_xenfs     |    11 +
 target/linux/x86/xen_domu/config-default      |   100 +
 .../x86/xen_domu/profiles/000-Generic.mk      |    15 +
 target/linux/x86/xen_domu/target.mk           |     4 +
 target/linux/xburst/Makefile                  |    25 +
 .../xburst/base-files/etc/board.d/01_system   |    12 +
 .../linux/xburst/base-files/etc/config/fstab  |     6 +
 .../xburst/base-files/etc/config/network      |    13 +
 target/linux/xburst/config-3.18               |   354 +
 target/linux/xburst/image/Makefile            |    51 +
 target/linux/xburst/image/ubinize.cfg         |    14 +
 target/linux/xburst/modules.mk                |    40 +
 ...e-vid-header-instead-of-the-whole-pa.patch |    20 +
 ...-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch |    43 +
 ...-for-subpage-reads-for-NAND_ECC_HW_O.patch |   104 +
 ...y-activation-of-the-DAC-to-work-arou.patch |    33 +
 ...it-the-regulator-register-on-startup.patch |    55 +
 .../006-Add-ili8960-lcd-driver.patch          |   309 +
 ...e-3-wire-spi-mode-for-the-display-fo.patch |    21 +
 target/linux/xburst/qi_lb60/config-default    |    33 +
 target/linux/xburst/qi_lb60/target.mk         |     1 +
 target/sdk/Config.in                          |     9 +
 target/sdk/Makefile                           |   136 +
 target/sdk/convert-config.pl                  |    59 +
 target/sdk/files/Config.in                    |    31 +
 target/sdk/files/Makefile                     |    59 +
 target/sdk/files/README.SDK                   |    11 +
 target/sdk/files/include/prepare.mk           |    17 +
 target/toolchain/Config.in                    |     8 +
 target/toolchain/Makefile                     |    72 +
 target/toolchain/files/README.TOOLCHAIN       |     2 +
 target/toolchain/files/wrapper.sh             |    95 +
 toolchain/Config.in                           |   337 +
 toolchain/Makefile                            |    91 +
 toolchain/binutils/Config.in                  |    32 +
 toolchain/binutils/Config.version             |    17 +
 toolchain/binutils/Makefile                   |   127 +
 .../2.25.1/300-001_ld_makefile_patch.patch    |    22 +
 .../300-012_check_ldrunpath_length.patch      |    20 +
 .../400-mips_no_dynamic_linking_sym.patch     |    18 +
 ...e-default-emulation-for-mips64-linux.patch |    37 +
 .../2.27/300-001_ld_makefile_patch.patch      |    22 +
 .../2.27/300-012_check_ldrunpath_length.patch |    20 +
 .../400-mips_no_dynamic_linking_sym.patch     |    18 +
 ...e-default-emulation-for-mips64-linux.patch |    37 +
 .../arc-2016.03/200-arc-fix-target-mask.patch |    13 +
 toolchain/fortify-headers/Makefile            |    28 +
 toolchain/gcc/Config.in                       |    80 +
 toolchain/gcc/Config.version                  |    13 +
 toolchain/gcc/common.mk                       |   221 +
 toolchain/gcc/files/alternate-arch-cc.in      |     3 +
 toolchain/gcc/final/Makefile                  |    87 +
 toolchain/gcc/initial/Makefile                |    36 +
 toolchain/gcc/minimal/Makefile                |    29 +
 .../001-revert_register_mode_search.patch     |    65 +
 .../patches/5.4.0/002-case_insensitive.patch  |    14 +
 .../gcc/patches/5.4.0/010-documentation.patch |    23 +
 .../patches/5.4.0/020-no-plt-backport.patch   |    28 +
 .../5.4.0/040-fix-mips-ICE-PR-68400.patch     |    23 +
 .../gcc/patches/5.4.0/100-uclibc-conf.patch   |    33 +
 .../gcc/patches/5.4.0/200-musl_config.patch   |   309 +
 .../gcc/patches/5.4.0/201-musl_arm.patch      |    43 +
 .../gcc/patches/5.4.0/202-musl_mips.patch     |    35 +
 .../gcc/patches/5.4.0/203-musl_powerpc.patch  |   209 +
 toolchain/gcc/patches/5.4.0/204-musl_sh.patch |    39 +
 .../gcc/patches/5.4.0/205-musl_x86.patch      |    41 +
 .../gcc/patches/5.4.0/206-musl_aarch64.patch  |    31 +
 .../patches/5.4.0/207-musl_fixincludes.patch  |    30 +
 .../patches/5.4.0/209-musl_libstdc++.patch    |    72 +
 .../gcc/patches/5.4.0/230-musl_libssp.patch   |    13 +
 .../patches/5.4.0/240-musl-libitm-fixes.patch |    61 +
 .../gcc/patches/5.4.0/250-add-musl.patch      |   120 +
 .../5.4.0/260-musl-add-unwind-fix.patch       |    34 +
 .../270-musl-add-powerpc-softfloat-fix.patch  |    24 +
 .../280-musl-disable-ifunc-by-default.patch   |    38 +
 .../300-mips_Os_cpu_rtx_cost_model.patch      |    14 +
 .../5.4.0/800-arm_v5te_no_ldrd_strd.patch     |    11 +
 .../5.4.0/810-arm-softfloat-libgcc.patch      |    25 +
 .../gcc/patches/5.4.0/820-libgcc_pic.patch    |    36 +
 .../5.4.0/830-arm_unbreak_armv4t.patch        |    13 +
 .../5.4.0/840-armv4_pass_fix-v4bx_to_ld.patch |    19 +
 .../patches/5.4.0/850-use_shared_libgcc.patch |    47 +
 .../patches/5.4.0/851-libgcc_no_compat.patch  |    12 +
 .../patches/5.4.0/870-ppc_no_crtsavres.patch  |    11 +
 .../patches/5.4.0/880-no_java_section.patch   |    11 +
 .../patches/5.4.0/900-bad-mips16-crt.patch    |     9 +
 .../gcc/patches/5.4.0/910-mbsd_multi.patch    |   222 +
 .../5.4.0/920-specs_nonfatal_getenv.patch     |    15 +
 .../5.4.0/930-fix-mips-noexecstack.patch      |   111 +
 .../931-fix-MIPS-softfloat-build-issue.patch  |   174 +
 .../5.4.0/940-no-clobber-stamp-bits.patch     |    11 +
 .../5.4.0/950-cpp_file_path_translation.patch |   182 +
 toolchain/gcc/patches/5.4.0/960-go_libm.patch |    11 +
 .../gcc/patches/5.4.0/970-warn_bug.patch      |    11 +
 .../001-revert_register_mode_search.patch     |    65 +
 .../patches/6.2.0/002-case_insensitive.patch  |    14 +
 .../gcc/patches/6.2.0/010-documentation.patch |    23 +
 .../gcc/patches/6.2.0/100-uclibc-conf.patch   |    33 +
 .../gcc/patches/6.2.0/230-musl_libssp.patch   |    13 +
 .../280-musl-disable-ifunc-by-default.patch   |    38 +
 .../300-mips_Os_cpu_rtx_cost_model.patch      |    11 +
 .../6.2.0/800-arm_v5te_no_ldrd_strd.patch     |    11 +
 .../6.2.0/810-arm-softfloat-libgcc.patch      |    25 +
 .../gcc/patches/6.2.0/820-libgcc_pic.patch    |    36 +
 .../6.2.0/830-arm_unbreak_armv4t.patch        |    13 +
 .../6.2.0/840-armv4_pass_fix-v4bx_to_ld.patch |    19 +
 .../patches/6.2.0/850-use_shared_libgcc.patch |    47 +
 .../patches/6.2.0/851-libgcc_no_compat.patch  |    12 +
 .../patches/6.2.0/870-ppc_no_crtsavres.patch  |    11 +
 .../patches/6.2.0/880-no_java_section.patch   |    11 +
 .../patches/6.2.0/900-bad-mips16-crt.patch    |     9 +
 .../gcc/patches/6.2.0/910-mbsd_multi.patch    |   222 +
 .../6.2.0/920-specs_nonfatal_getenv.patch     |    15 +
 .../6.2.0/930-fix-mips-noexecstack.patch      |   111 +
 .../6.2.0/940-no-clobber-stamp-bits.patch     |    11 +
 .../6.2.0/950-cpp_file_path_translation.patch |   182 +
 .../001-revert_register_mode_search.patch     |    65 +
 .../arc-2016.03/002-weak_data_fix.patch       |    42 +
 .../003-universal_initializer.patch           |    94 +
 .../arc-2016.03/004-case_insensitive.patch    |    14 +
 .../arc-2016.03/010-documentation.patch       |    23 +
 .../arc-2016.03/020-no-plt-backport.patch     |    28 +
 .../patches/arc-2016.03/100-uclibc-conf.patch |    33 +
 ...210-disable_libsanitizer_off_t_check.patch |    11 +
 .../arc-2016.03/800-arc-disablelibgmon.patch  |    18 +
 .../patches/arc-2016.03/820-libgcc_pic.patch  |    36 +
 .../arc-2016.03/850-use_shared_libgcc.patch   |    47 +
 .../arc-2016.03/851-libgcc_no_compat.patch    |    12 +
 .../arc-2016.03/860-use_eh_frame.patch        |    42 +
 .../arc-2016.03/870-ppc_no_crtsavres.patch    |    11 +
 .../arc-2016.03/880-no_java_section.patch     |    11 +
 .../patches/arc-2016.03/910-mbsd_multi.patch  |   253 +
 .../920-specs_nonfatal_getenv.patch           |    14 +
 .../940-no-clobber-stamp-bits.patch           |    11 +
 .../950-fix-building-with-gcc6.patch          |   153 +
 toolchain/gdb/Makefile                        |    68 +
 .../patches-arc/100-no_extern_inline.patch    |    32 +
 .../gdb/patches-arc/110-no_testsuite.patch    |    21 +
 .../120-fix-compile-flag-mismatch.patch       |    11 +
 .../gdb/patches/100-no_extern_inline.patch    |    32 +
 toolchain/gdb/patches/110-no_testsuite.patch  |    21 +
 .../120-fix-compile-flag-mismatch.patch       |    11 +
 toolchain/glibc/Config.in                     |    12 +
 toolchain/glibc/Config.version                |    11 +
 toolchain/glibc/Makefile                      |    31 +
 toolchain/glibc/common.mk                     |   107 +
 toolchain/glibc/headers/Makefile              |    28 +
 toolchain/glibc/include/libintl.h             |     6 +
 .../patches/2.24/100-fix_cross_rpcgen.patch   |    52 +
 .../2.24/200-add-dl-search-paths.patch        |    14 +
 toolchain/info.mk                             |     6 +
 toolchain/insight/Makefile                    |    54 +
 .../600-fix-compile-flag-mismatch.patch       |    31 +
 toolchain/kernel-headers/Makefile             |   101 +
 toolchain/musl/Config.version                 |     8 +
 toolchain/musl/Makefile                       |    31 +
 toolchain/musl/common.mk                      |    59 +
 toolchain/musl/include/bits/wordsize.h        |     1 +
 toolchain/musl/include/features.h             |    48 +
 toolchain/musl/include/sgidefs.h              |    73 +
 toolchain/musl/include/sys/cdefs.h            |   378 +
 toolchain/musl/include/sys/glibc-types.h      |    35 +
 toolchain/musl/include/sys/queue.h            |   574 +
 ...ssion-in-tcsetattr-on-all-mips-archs.patch |    67 +
 ...ribute-to-some-function-declarations.patch |   197 +
 .../musl/patches/100-add_glob_onlydir.patch   |    11 +
 .../patches/110-read_timezone_from_fs.patch   |    28 +
 .../patches/200-add_libssp_nonshared.patch    |    50 +
 toolchain/musl/patches/300-relative.patch     |    11 +
 .../patches/400-fix_quoted_timezone.patch     |    11 +
 .../musl/patches/900-iconv_size_hack.patch    |    68 +
 .../musl/patches/901-crypt_size_hack.patch    |    60 +
 toolchain/uClibc/Config.in                    |     6 +
 toolchain/uClibc/Config.version               |     9 +
 toolchain/uClibc/Makefile                     |    41 +
 toolchain/uClibc/common.mk                    |    97 +
 toolchain/uClibc/config/arc                   |    10 +
 toolchain/uClibc/config/archs                 |    10 +
 toolchain/uClibc/config/arm                   |     9 +
 toolchain/uClibc/config/armeb                 |     9 +
 toolchain/uClibc/config/common                |   226 +
 toolchain/uClibc/config/debug                 |     6 +
 toolchain/uClibc/config/i386                  |    21 +
 toolchain/uClibc/config/i686                  |    21 +
 toolchain/uClibc/config/m68k                  |     6 +
 toolchain/uClibc/config/mips                  |    18 +
 toolchain/uClibc/config/mips64                |    18 +
 toolchain/uClibc/config/mips64.32             |    19 +
 toolchain/uClibc/config/mips64.64             |    19 +
 toolchain/uClibc/config/mips64.n32            |    19 +
 toolchain/uClibc/config/mips64el              |    18 +
 toolchain/uClibc/config/mips64el.32           |    19 +
 toolchain/uClibc/config/mips64el.64           |    19 +
 toolchain/uClibc/config/mips64el.n32          |    19 +
 toolchain/uClibc/config/mipsel                |    18 +
 toolchain/uClibc/config/mipsel.cobalt         |    18 +
 toolchain/uClibc/config/powerpc               |     6 +
 toolchain/uClibc/config/powerpc.e500          |     6 +
 toolchain/uClibc/config/sparc                 |     8 +
 toolchain/uClibc/config/sparc.leon            |     8 +
 toolchain/uClibc/config/x86_64                |     6 +
 toolchain/uClibc/headers/Makefile             |    27 +
 toolchain/uClibc/utils/Makefile               |    24 +
 toolchain/wrapper/Makefile                    |    62 +
 toolchain/yasm/Makefile                       |    63 +
 tools/Makefile                                |   143 +
 tools/autoconf/Makefile                       |    37 +
 tools/autoconf/patches/000-relocatable.patch  |   229 +
 tools/autoconf/patches/001-no_emacs_lib.patch |    22 +
 .../patches/002-musl_host_fixup.patch         |    24 +
 tools/automake/Makefile                       |    50 +
 tools/automake/files/aclocal                  |     2 +
 tools/automake/patches/000-relocatable.patch  |    96 +
 ...clocal-skip-not-existing-directories.patch |    15 +
 .../200-do-not-override-silent-rules.patch    |    13 +
 tools/bc/Makefile                             |    21 +
 tools/bc/patches/001-no_doc.patch             |    23 +
 tools/bison/Makefile                          |    30 +
 .../bison/patches/010-intl-stub-compat.patch  |    15 +
 .../bison/patches/100-fix-gets-removal.patch  |    16 +
 tools/bison/scripts/yacc                      |     2 +
 tools/ccache/Makefile                         |    35 +
 tools/ccache/files/ccache_cc                  |     2 +
 tools/ccache/files/ccache_cxx                 |     2 +
 tools/ccache/patches/100-honour-copts.patch   |    12 +
 .../110-disable-assembler-support.patch       |    32 +
 tools/cloog/Makefile                          |    41 +
 tools/cmake/Makefile                          |    29 +
 .../cmake/patches/100-disable_qt_tests.patch  |    31 +
 tools/cmake/patches/110-freebsd-compat.patch  |    39 +
 .../patches/120-alpine_musl-compat.patch      |    17 +
 ...am-libarchive-openssl-compat-headers.patch |   190 +
 ...eam-libarchive-openssl-1.1.x-support.patch |   379 +
 .../150-libarchive-fix-libressl-compat.patch  |    22 +
 tools/coreutils/Makefile                      |    36 +
 tools/dosfstools/Makefile                     |    26 +
 ...64-32-heads-sectors-for-targets-smal.patch |    34 +
 ..._CHECK_LIB-for-iconv-library-linking.patch |    27 +
 tools/e2fsprogs/Makefile                      |    49 +
 .../001-exit_0_on_corrected_errors.patch      |    11 +
 .../patches/002-dont-build-e4defrag.patch     |    11 +
 .../patches/003-openbsd-compat.patch          |    12 +
 .../patches/004-freebsd-compat.patch          |    12 +
 .../e2fsprogs/patches/005-darwin-compat.patch |    22 +
 .../e2fsprogs/patches/010-old-libmagic.patch  |    25 +
 tools/elftosb/Makefile                        |    26 +
 tools/elftosb/patches/001-libm.patch          |    11 +
 .../elftosb/patches/002-fix-header-path.patch |    19 +
 tools/elftosb/patches/003-use-ldflags.patch   |    26 +
 tools/expat/Makefile                          |    25 +
 tools/findutils/Makefile                      |    20 +
 tools/firmware-utils/Makefile                 |    88 +
 tools/firmware-utils/src/add_header.c         |   138 +
 tools/firmware-utils/src/addpattern.c         |   333 +
 tools/firmware-utils/src/asustrx.c            |   256 +
 tools/firmware-utils/src/bcm_tag.h            |    70 +
 tools/firmware-utils/src/bcmalgo.c            |   248 +
 tools/firmware-utils/src/bcmalgo.h            |    83 +
 tools/firmware-utils/src/buffalo-enc.c        |   304 +
 tools/firmware-utils/src/buffalo-lib.c        |   480 +
 tools/firmware-utils/src/buffalo-lib.h        |   121 +
 tools/firmware-utils/src/buffalo-tag.c        |   374 +
 tools/firmware-utils/src/buffalo-tftp.c       |   177 +
 tools/firmware-utils/src/csysimg.h            |    79 +
 tools/firmware-utils/src/cyg_crc.h            |   109 +
 tools/firmware-utils/src/cyg_crc16.c          |   110 +
 tools/firmware-utils/src/cyg_crc32.c          |   172 +
 tools/firmware-utils/src/dgfirmware.c         |   377 +
 tools/firmware-utils/src/dgn3500sum.c         |   167 +
 tools/firmware-utils/src/edimax_fw_header.c   |   386 +
 tools/firmware-utils/src/encode_crc.c         |   151 +
 tools/firmware-utils/src/fix-u-media-header.c |   354 +
 tools/firmware-utils/src/fw.h                 |    70 +
 tools/firmware-utils/src/hcsmakeimage.c       |   181 +
 tools/firmware-utils/src/imagetag.c           |   492 +
 tools/firmware-utils/src/imagetag.ggo         |    46 +
 tools/firmware-utils/src/imagetag_cmdline.c   |  1193 +
 tools/firmware-utils/src/imagetag_cmdline.h   |   275 +
 tools/firmware-utils/src/jcgimage.c           |   403 +
 tools/firmware-utils/src/lzma2eva.c           |   190 +
 tools/firmware-utils/src/makeamitbin.c        |   316 +
 tools/firmware-utils/src/md5.c                |   296 +
 tools/firmware-utils/src/md5.h                |    45 +
 tools/firmware-utils/src/mkbrncmdline.c       |   168 +
 tools/firmware-utils/src/mkbrnimg.c           |   189 +
 tools/firmware-utils/src/mkbuffaloimg.c       |   223 +
 tools/firmware-utils/src/mkcameofw.c          |   433 +
 tools/firmware-utils/src/mkcasfw.c            |  1030 +
 tools/firmware-utils/src/mkchkimg.c           |   327 +
 tools/firmware-utils/src/mkcsysimg.c          |  1157 +
 tools/firmware-utils/src/mkdapimg.c           |   226 +
 tools/firmware-utils/src/mkdcs932.c           |    39 +
 tools/firmware-utils/src/mkdniimg.c           |   208 +
 tools/firmware-utils/src/mkedimaximg.c        |   259 +
 tools/firmware-utils/src/mkfwimage.c          |   471 +
 tools/firmware-utils/src/mkfwimage2.c         |   451 +
 tools/firmware-utils/src/mkheader_gemtek.c    |   211 +
 tools/firmware-utils/src/mkhilinkfw.c         |   323 +
 tools/firmware-utils/src/mkmerakifw-old.c     |   369 +
 tools/firmware-utils/src/mkmerakifw.c         |   320 +
 tools/firmware-utils/src/mkmylofw.c           |  1297 +
 tools/firmware-utils/src/mkplanexfw.c         |   269 +
 tools/firmware-utils/src/mkporayfw.c          |   791 +
 tools/firmware-utils/src/mkrtn56uimg.c        |   294 +
 tools/firmware-utils/src/mksenaofw.c          |   420 +
 tools/firmware-utils/src/mktitanimg.c         |  1040 +
 tools/firmware-utils/src/mktitanimg.h         |   171 +
 tools/firmware-utils/src/mktplinkfw.c         |   885 +
 tools/firmware-utils/src/mktplinkfw2.c        |  1001 +
 tools/firmware-utils/src/mkwrggimg.c          |   283 +
 tools/firmware-utils/src/mkwrgimg.c           |   240 +
 tools/firmware-utils/src/mkzcfw.c             |   408 +
 tools/firmware-utils/src/mkzynfw.c            |  1131 +
 tools/firmware-utils/src/motorola-bin.c       |   227 +
 tools/firmware-utils/src/myloader.h           |   176 +
 tools/firmware-utils/src/nand_ecc.c           |   204 +
 tools/firmware-utils/src/osbridge-crc.c       |   309 +
 tools/firmware-utils/src/oseama.c             |   556 +
 tools/firmware-utils/src/pc1crypt.c           |   361 +
 tools/firmware-utils/src/ptgen.c              |   248 +
 tools/firmware-utils/src/seama.c              |   529 +
 tools/firmware-utils/src/seama.h              |   108 +
 tools/firmware-utils/src/sha1.c               |   443 +
 tools/firmware-utils/src/sha1.h               |    57 +
 tools/firmware-utils/src/spw303v.c            |   243 +
 tools/firmware-utils/src/srec2bin.c           |   524 +
 tools/firmware-utils/src/tplink-safeloader.c  |   783 +
 tools/firmware-utils/src/trx.c                |   418 +
 tools/firmware-utils/src/trx2edips.c          |   171 +
 tools/firmware-utils/src/trx2usr.c            |   186 +
 tools/firmware-utils/src/wrt400n.c            |   336 +
 tools/firmware-utils/src/xorimage.c           |   135 +
 tools/firmware-utils/src/zyimage.c            |   148 +
 tools/firmware-utils/src/zynos.h              |   225 +
 tools/firmware-utils/src/zyxbcm.c             |   260 +
 tools/flex/Makefile                           |    27 +
 .../flex/patches/100-disable-tests-docs.patch |    13 +
 tools/flock/Makefile                          |    25 +
 tools/flock/src/flock.c                       |   342 +
 tools/genext2fs/Makefile                      |    51 +
 tools/genext2fs/patches/100-c99_scanf.patch   |    21 +
 tools/genext2fs/patches/200-autoconf.patch    |    13 +
 .../patches/300-blocksize-creator.patch       |   558 +
 .../genext2fs/patches/400-byteswap_fix.patch  |    44 +
 tools/gengetopt/Makefile                      |    30 +
 .../patches/100-dependency_fix.patch          |    11 +
 .../gengetopt/patches/200-no_docs_tests.patch |    13 +
 tools/gmp/Makefile                            |    35 +
 tools/include/byteswap.h                      |     5 +
 tools/include/elf.h                           |  3007 ++
 tools/include/endian.h                        |    40 +
 tools/include/getline.h                       |    72 +
 tools/include/sys/sysmacros.h                 |    56 +
 tools/isl/Makefile                            |    27 +
 tools/kernel2minor/Makefile                   |    31 +
 tools/libelf/Makefile                         |    51 +
 tools/libressl/Makefile                       |    24 +
 tools/libtool/Makefile                        |    41 +
 tools/libtool/files/libtool-v1.5.patch        |   118 +
 tools/libtool/files/libtool-v2.2.patch        |   123 +
 tools/libtool/files/libtool-v2.4.patch        |   160 +
 tools/libtool/patches/000-relocatable.patch   |   141 +
 .../libtool/patches/001-fix-func_append.patch |    22 +
 tools/libtool/patches/100-libdir-fixes.patch  |    94 +
 ...10-dont-use-target-dir-for-relinking.patch |    20 +
 .../120-strip-unsafe-dirs-for-relinking.patch |    24 +
 tools/libtool/patches/150-trailingslash.patch |    49 +
 .../libtool/patches/160-passthrough-ssp.patch |    12 +
 .../patches/200-openwrt-branding.patch        |   112 +
 tools/lzma-old/Makefile                       |    36 +
 tools/lzma-old/patches/100-lzma_zlib.patch    |   404 +
 tools/lzma-old/patches/110-ranlib.patch       |    10 +
 tools/lzma/Makefile                           |    36 +
 tools/lzma/patches/001-large_files.patch      |    13 +
 tools/lzma/patches/002-lzmp.patch             |  1059 +
 tools/lzma/patches/003-compile_fixes.patch    |    26 +
 tools/lzma/patches/100-static_library.patch   |    70 +
 .../101-move-copyright-to-usage-info.patch    |    20 +
 tools/m4/Makefile                             |    28 +
 tools/m4/patches/100-fix-gets-removal.patch   |    17 +
 tools/make-ext4fs/Makefile                    |    40 +
 tools/missing-macros/Makefile                 |    28 +
 tools/missing-macros/src/README               |   100 +
 tools/missing-macros/src/bin/help2man         |    29 +
 tools/missing-macros/src/bin/makeinfo         |   112 +
 tools/missing-macros/src/m4/as-ac-expand.m4   |    43 +
 .../missing-macros/src/m4/as-compiler-flag.m4 |    62 +
 .../src/m4/as-unaligned-access.m4             |    41 +
 tools/missing-macros/src/m4/as-version.m4     |    71 +
 tools/missing-macros/src/m4/dnet.m4           |   322 +
 .../src/m4/fake-gtk-doc-check.m4              |    13 +
 tools/missing-macros/src/m4/fake-intltool.m4  |    16 +
 tools/missing-macros/src/m4/glibc2.m4         |    30 +
 tools/missing-macros/src/m4/glibc21.m4        |    30 +
 tools/missing-macros/src/m4/intdiv0.m4        |    84 +
 tools/missing-macros/src/m4/intmax.m4         |    33 +
 tools/missing-macros/src/m4/inttypes-pri.m4   |    36 +
 tools/missing-macros/src/m4/inttypes_h.m4     |    26 +
 tools/missing-macros/src/m4/lib-ld.m4         |   110 +
 tools/missing-macros/src/m4/lib-link.m4       |   774 +
 tools/missing-macros/src/m4/lib-prefix.m4     |   224 +
 tools/missing-macros/src/m4/mfx_acc.m4        |   163 +
 tools/missing-macros/src/m4/mfx_cppflags.m4   |    41 +
 tools/missing-macros/src/m4/mfx_limits.m4     |   154 +
 tools/missing-macros/src/m4/progtest.m4       |    92 +
 tools/missing-macros/src/m4/stdint_h.m4       |    26 +
 tools/missing-macros/src/m4/uintmax_t.m4      |    30 +
 tools/missing-macros/src/m4/va_copy.m4        |   111 +
 tools/missing-macros/src/m4/wint_t.m4         |    28 +
 tools/mkimage/Makefile                        |    46 +
 .../patches/010-freebsd-ulong-fix.patch       |    13 +
 .../patches/020-include_compile_fix.patch     |    10 +
 .../030-allow-to-use-different-magic.patch    |    63 +
 tools/mkimage/patches/040-include_order.patch |    11 +
 .../patches/050-image_h_portability.patch     |    31 +
 .../patches/060-remove_kernel_includes.patch  |    35 +
 .../070-socfpgaimage_portability.patch        |    52 +
 .../patches/080-remove_compiler_check.patch   |    16 +
 .../090-reproducible-SOURCE_DATE_EPOCH.patch  |    82 +
 .../mkimage/patches/100-freebsd-compat.patch  |    14 +
 .../patches/200-compiler-support.patch        |   702 +
 .../patches/210-openssl-1.1.x-compat.patch    |    97 +
 tools/mklibs/Makefile                         |    34 +
 tools/mklibs/include/elf.h                    |  2559 ++
 tools/mklibs/patches/001-compile.patch        |     8 +
 .../patches/002-disable_symbol_checks.patch   |    20 +
 tools/mklibs/patches/003-no_copy.patch        |    50 +
 .../mklibs/patches/004-libpthread_link.patch  |    28 +
 tools/mklibs/patches/005-duplicate_syms.patch |    35 +
 tools/mklibs/patches/006-uclibc_init.patch    |    14 +
 tools/mklibs/patches/007-gc_sections.patch    |    11 +
 .../patches/008-uclibc_libgcc_link.patch      |    37 +
 .../009-uclibc_libpthread_symbols.patch       |    63 +
 .../patches/010-remove_STT_GNU_IFUNC.patch    |    20 +
 .../mklibs/patches/011-remove_multiarch.patch |    10 +
 tools/mm-macros/Makefile                      |    31 +
 tools/mpc/Makefile                            |    28 +
 tools/mpfr/Makefile                           |    27 +
 tools/mpfr/patches/001-only_src.patch         |    22 +
 tools/mpfr/patches/100-freebsd-compat.patch   |    10 +
 tools/mtd-utils/Makefile                      |    59 +
 tools/mtd-utils/include/fls.h                 |     2 +
 tools/mtd-utils/include/linux/types.h         |    18 +
 tools/mtd-utils/patches/100-sscanf_fix.patch  |    11 +
 tools/mtd-utils/patches/110-portability.patch |   170 +
 tools/mtd-utils/patches/130-lzma_jffs2.patch  |  5030 +++
 .../patches/134-freebsd_loff_t.patch          |    14 +
 .../patches/135-mkubifs_optional_lzo.patch    |   119 +
 .../patches/136-mkfs.ubifs-xz-support.patch   |   378 +
 ...add-ubigen_write_terminator-function.patch |    89 +
 .../201-ubinize-add-terminator-support.patch  |    77 +
 .../310-add-static-linking-option.patch       |    43 +
 tools/mtools/Makefile                         |    38 +
 tools/mtools/patches/100-compile_fix.patch    |    19 +
 tools/padjffs2/Makefile                       |    36 +
 tools/padjffs2/src/Makefile                   |    15 +
 tools/padjffs2/src/padjffs2.c                 |   210 +
 tools/patch-image/Makefile                    |    28 +
 tools/patch-image/src/patch-cmdline.c         |    85 +
 tools/patch-image/src/patch-dtb.c             |   107 +
 tools/patch/Makefile                          |    23 +
 tools/patchelf/Makefile                       |    26 +
 tools/pkg-config/Makefile                     |    39 +
 tools/pkg-config/files/pkg-config             |     3 +
 ...ppress-string-format-literal-warning.patch |    18 +
 tools/ppl/Makefile                            |    37 +
 .../patches/001-disable-serial-tests.patch    |    44 +
 tools/qemu/Makefile                           |    40 +
 tools/quilt/Makefile                          |    36 +
 tools/quilt/patches/000-relocatable.patch     |   170 +
 tools/quilt/patches/001-fix_compile.patch     |    18 +
 tools/scons/Makefile                          |    35 +
 tools/scons/files/pywrap.sh                   |    15 +
 tools/scons/patches/001-platform_env.patch    |    11 +
 tools/sdimage/Makefile                        |    37 +
 tools/sed/Makefile                            |    43 +
 tools/sed/patches/001-musl_host_fixup.patch   |    24 +
 tools/sparse/Makefile                         |    25 +
 tools/squashfs/Makefile                       |    39 +
 tools/squashfs/patches/100-lzma.patch         |    22 +
 .../patches/110-no_nonstatic_inline.patch     |    11 +
 .../120-add-fixed-timestamp-support.patch     |    79 +
 tools/squashfs4/Makefile                      |    42 +
 tools/squashfs4/patches/100-portability.patch |    40 +
 .../patches/110-allow_static_liblzma.patch    |    30 +
 .../squashfs4/patches/120-cygwin_fixes.patch  |   153 +
 .../squashfs4/patches/150-freebsd_fixes.patch |    10 +
 .../patches/160-expose_lzma_xz_options.patch  |   929 +
 ..._support_for_LZMA_MAGIC_to_unsqashfs.patch |    72 +
 .../patches/180-openbsd_compat.patch          |    24 +
 .../patches/190-no_nonstatic_inline.patch     |    36 +
 .../200-add-fixed-timestamp-option.patch      |    82 +
 tools/sstrip/Makefile                         |    25 +
 tools/sstrip/src/sstrip.c                     |   465 +
 tools/tar/Makefile                            |    30 +
 tools/upslug2/Makefile                        |    36 +
 tools/upslug2/patches/100-libpcap_fix.patch   |   153 +
 .../patches/110-wrt350nv2_support.patch       |   279 +
 tools/upx/Makefile                            |    36 +
 tools/upx/patches/100-lzmaonly.patch          |   156 +
 tools/wrt350nv2-builder/Makefile              |    41 +
 tools/wrt350nv2-builder/src/crypt.h           |   132 +
 tools/wrt350nv2-builder/src/ioapi.c           |   177 +
 tools/wrt350nv2-builder/src/ioapi.h           |    75 +
 tools/wrt350nv2-builder/src/md5.c             |   381 +
 tools/wrt350nv2-builder/src/md5.h             |    91 +
 tools/wrt350nv2-builder/src/upgrade.h         |    77 +
 .../wrt350nv2-builder/src/wrt350nv2-builder.c |  1126 +
 tools/xz/Makefile                             |    40 +
 tools/yaffs2/Makefile                         |    39 +
 tools/yaffs2/patches/100-compile.patch        |   125 +
 tools/yaffs2/patches/110-openbsd-compat.patch |    14 +
 3612 files changed, 607433 insertions(+)
 create mode 100644 .gitattributes
 create mode 100644 .gitignore
 create mode 100644 BSDmakefile
 create mode 100644 Config.in
 create mode 100644 LICENSE
 create mode 100644 Makefile
 create mode 100644 config/Config-build.in
 create mode 100644 config/Config-devel.in
 create mode 100644 config/Config-images.in
 create mode 100644 config/Config-kernel.in
 create mode 100644 feeds.conf.default
 create mode 100644 include/autotools.mk
 create mode 100644 include/cmake.mk
 create mode 100644 include/debug.mk
 create mode 100644 include/depends.mk
 create mode 100644 include/device_table.txt
 create mode 100644 include/download.mk
 create mode 100644 include/feeds.mk
 create mode 100644 include/hardening.mk
 create mode 100644 include/host-build.mk
 create mode 100644 include/host.mk
 create mode 100644 include/image-commands.mk
 create mode 100644 include/image-legacy.mk
 create mode 100644 include/image.mk
 create mode 100644 include/kernel-build.mk
 create mode 100644 include/kernel-defaults.mk
 create mode 100644 include/kernel-version.mk
 create mode 100644 include/kernel.mk
 create mode 100644 include/netfilter.mk
 create mode 100644 include/nls.mk
 create mode 100644 include/package-bin.mk
 create mode 100644 include/package-defaults.mk
 create mode 100644 include/package-dumpinfo.mk
 create mode 100644 include/package-ipkg.mk
 create mode 100644 include/package-seccomp.mk
 create mode 100644 include/package.mk
 create mode 100644 include/prereq-build.mk
 create mode 100644 include/prereq.mk
 create mode 100644 include/quilt.mk
 create mode 100644 include/rootfs.mk
 create mode 100644 include/scan.awk
 create mode 100644 include/scan.mk
 create mode 100644 include/scons.mk
 create mode 100644 include/shell.sh
 create mode 100644 include/site/aarch64
 create mode 100644 include/site/aarch64_be
 create mode 100644 include/site/arc
 create mode 100644 include/site/arm
 create mode 100644 include/site/armeb
 create mode 100644 include/site/i386
 create mode 100644 include/site/i486
 create mode 100644 include/site/i686
 create mode 100644 include/site/linux
 create mode 100644 include/site/m68k
 create mode 100644 include/site/mips
 create mode 100644 include/site/mips64
 create mode 100644 include/site/mips64el
 create mode 100644 include/site/mipsel
 create mode 100644 include/site/powerpc
 create mode 100644 include/site/sparc
 create mode 100644 include/site/x86_64
 create mode 100644 include/subdir.mk
 create mode 100644 include/target.mk
 create mode 100644 include/toolchain-build.mk
 create mode 100644 include/toplevel.mk
 create mode 100644 include/uclibc++.mk
 create mode 100644 include/unpack.mk
 create mode 100644 include/verbose.mk
 create mode 100644 include/version.mk
 create mode 100644 package/Makefile
 create mode 100644 package/base-files/Makefile
 create mode 100755 package/base-files/files/bin/board_detect
 create mode 100755 package/base-files/files/bin/config_generate
 create mode 100755 package/base-files/files/bin/ipcalc.sh
 create mode 100644 package/base-files/files/etc/banner
 create mode 100644 package/base-files/files/etc/banner.failsafe
 create mode 100755 package/base-files/files/etc/board.d/99-default_network
 create mode 100644 package/base-files/files/etc/device_info
 create mode 100644 package/base-files/files/etc/diag.sh
 create mode 100644 package/base-files/files/etc/fstab
 create mode 100644 package/base-files/files/etc/group
 create mode 100644 package/base-files/files/etc/hosts
 create mode 100644 package/base-files/files/etc/hotplug.d/net/00-sysctl
 create mode 100755 package/base-files/files/etc/init.d/boot
 create mode 100755 package/base-files/files/etc/init.d/done
 create mode 100755 package/base-files/files/etc/init.d/gpio_switch
 create mode 100755 package/base-files/files/etc/init.d/led
 create mode 100755 package/base-files/files/etc/init.d/sysctl
 create mode 100755 package/base-files/files/etc/init.d/sysfixtime
 create mode 100755 package/base-files/files/etc/init.d/system
 create mode 100755 package/base-files/files/etc/init.d/umount
 create mode 100755 package/base-files/files/etc/init.d/urandom_seed
 create mode 100644 package/base-files/files/etc/inittab
 create mode 100644 package/base-files/files/etc/iproute2/rt_tables
 create mode 100644 package/base-files/files/etc/openwrt_release
 create mode 100644 package/base-files/files/etc/openwrt_version
 create mode 120000 package/base-files/files/etc/os-release
 create mode 100644 package/base-files/files/etc/passwd
 create mode 100755 package/base-files/files/etc/preinit
 create mode 100644 package/base-files/files/etc/profile
 create mode 100644 package/base-files/files/etc/protocols
 create mode 100755 package/base-files/files/etc/rc.button/failsafe
 create mode 100755 package/base-files/files/etc/rc.button/power
 create mode 100755 package/base-files/files/etc/rc.button/reset
 create mode 100755 package/base-files/files/etc/rc.button/rfkill
 create mode 100755 package/base-files/files/etc/rc.common
 create mode 100644 package/base-files/files/etc/rc.local
 create mode 100644 package/base-files/files/etc/services
 create mode 100644 package/base-files/files/etc/shadow
 create mode 100644 package/base-files/files/etc/shells
 create mode 100644 package/base-files/files/etc/sysctl.conf
 create mode 100644 package/base-files/files/etc/sysctl.d/local.conf
 create mode 100644 package/base-files/files/etc/sysupgrade.conf
 create mode 100644 package/base-files/files/etc/uci-defaults/10_migrate-shadow
 create mode 100644 package/base-files/files/etc/uci-defaults/11_migrate-sysctl
 create mode 100644 package/base-files/files/etc/uci-defaults/12_network-generate-ula
 create mode 100644 package/base-files/files/etc/uci-defaults/13_fix_group_user
 create mode 100755 package/base-files/files/lib/functions.sh
 create mode 100644 package/base-files/files/lib/functions/leds.sh
 create mode 100644 package/base-files/files/lib/functions/network.sh
 create mode 100644 package/base-files/files/lib/functions/preinit.sh
 create mode 100644 package/base-files/files/lib/functions/service.sh
 create mode 100644 package/base-files/files/lib/functions/system.sh
 create mode 100755 package/base-files/files/lib/functions/uci-defaults.sh
 create mode 100644 package/base-files/files/lib/preinit/02_default_set_state
 create mode 100644 package/base-files/files/lib/preinit/10_indicate_failsafe
 create mode 100644 package/base-files/files/lib/preinit/10_indicate_preinit
 create mode 100644 package/base-files/files/lib/preinit/10_sysinfo
 create mode 100644 package/base-files/files/lib/preinit/30_failsafe_wait
 create mode 100644 package/base-files/files/lib/preinit/40_run_failsafe_hook
 create mode 100644 package/base-files/files/lib/preinit/50_indicate_regular_preinit
 create mode 100644 package/base-files/files/lib/preinit/70_initramfs_test
 create mode 100644 package/base-files/files/lib/preinit/80_mount_root
 create mode 100644 package/base-files/files/lib/preinit/81_urandom_seed
 create mode 100644 package/base-files/files/lib/preinit/99_10_failsafe_login
 create mode 100644 package/base-files/files/lib/preinit/99_10_run_init
 create mode 100644 package/base-files/files/lib/upgrade/common.sh
 create mode 100644 package/base-files/files/lib/upgrade/fwtool.sh
 create mode 100644 package/base-files/files/lib/upgrade/keep.d/base-files-essential
 create mode 100644 package/base-files/files/rom/note
 create mode 100755 package/base-files/files/sbin/firstboot
 create mode 100755 package/base-files/files/sbin/hotplug-call
 create mode 100755 package/base-files/files/sbin/led.sh
 create mode 100755 package/base-files/files/sbin/sysupgrade
 create mode 100755 package/base-files/files/sbin/urandom_seed
 create mode 100755 package/base-files/files/sbin/wifi
 create mode 100644 package/base-files/files/usr/lib/os-release
 create mode 100755 package/base-files/files/usr/libexec/login.sh
 create mode 100644 package/base-files/image-config.in
 create mode 100644 package/boot/fconfig/Makefile
 create mode 100644 package/boot/grub2/Makefile
 create mode 100644 package/boot/grub2/patches/100-grub_setup_root.patch
 create mode 100644 package/boot/grub2/patches/100-musl-compat.patch
 create mode 100644 package/boot/grub2/patches/200-fix-gets-removal.patch
 create mode 100644 package/boot/grub2/patches/210-fix_serial_rtscts.patch
 create mode 100644 package/boot/kexec-tools/Config.in
 create mode 100644 package/boot/kexec-tools/Makefile
 create mode 100644 package/boot/kexec-tools/patches/0001-Fix-zlib-lzma-decompression.patch
 create mode 100644 package/boot/kexec-tools/patches/0002-configure.ac-apply-necessary-quotes-to-result-of-mac.patch
 create mode 100644 package/boot/kexec-tools/patches/0003-mips-fix-compiler-warning-on-printing-64-bit-integer.patch
 create mode 100644 package/boot/kexec-tools/patches/0004-mips-remove-unused-variable.patch
 create mode 100644 package/boot/kexec-tools/patches/0005-mips-fix-warning-about-implicit-type-conversion.patch
 create mode 100644 package/boot/uboot-ar71xx/Makefile
 create mode 100644 package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/Makefile
 create mode 100644 package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/config.mk
 create mode 100644 package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/lowlevel_init.S
 create mode 100644 package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/nbg460n.c
 create mode 100644 package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/u-boot.lds
 create mode 100644 package/boot/uboot-ar71xx/files/cpu/mips/ar71xx_serial.c
 create mode 100644 package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c
 create mode 100644 package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h
 create mode 100644 package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h
 create mode 100644 package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c
 create mode 100644 package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c
 create mode 100644 package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx.h
 create mode 100644 package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx_gpio.h
 create mode 100644 package/boot/uboot-ar71xx/files/include/configs/nbg460n.h
 create mode 100644 package/boot/uboot-ar71xx/patches/0001-upstream-Reproducible-U-Boot-build-support-using-SOURCE_DATE_.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/0002-upstream-Makefile-Reproducible-U-Boot-build-support.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/001-ar71xx.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/002-ar71xx-spi.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/010-enet-ag71xx.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/011-switch-rtl8366sr.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/020-freebsd-compat.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/021-darwin_compat.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/022-getline_backport.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/030-no_examples.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/040-no_extern_inline.patch
 create mode 100644 package/boot/uboot-ar71xx/patches/041-no_weak_alias.patch
 create mode 100644 package/boot/uboot-envtools/Config.in
 create mode 100644 package/boot/uboot-envtools/Makefile
 create mode 100644 package/boot/uboot-envtools/files/ar71xx
 create mode 100644 package/boot/uboot-envtools/files/cns3xxx
 create mode 100644 package/boot/uboot-envtools/files/imx6
 create mode 100755 package/boot/uboot-envtools/files/ipq
 create mode 100644 package/boot/uboot-envtools/files/kirkwood
 create mode 100644 package/boot/uboot-envtools/files/lantiq
 create mode 100644 package/boot/uboot-envtools/files/mvebu
 create mode 100644 package/boot/uboot-envtools/files/mxs
 create mode 100644 package/boot/uboot-envtools/files/oxnas
 create mode 100644 package/boot/uboot-envtools/files/ramips
 create mode 100644 package/boot/uboot-envtools/files/uboot-envtools.sh
 create mode 100644 package/boot/uboot-envtools/patches/001-compile.patch
 create mode 100644 package/boot/uboot-envtools/patches/200-fw_env_no_aes.patch
 create mode 100644 package/boot/uboot-envtools/patches/300-support-env-in-ubivol-chardev.patch
 create mode 100644 package/boot/uboot-envtools/patches/400-u-boot-2015.10-stdint.patch
 create mode 100644 package/boot/uboot-sunxi/Makefile
 create mode 100644 package/boot/uboot-sunxi/patches/001-use-dtc-in-kernel.patch
 create mode 100644 package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch
 create mode 100644 package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch
 create mode 100644 package/boot/uboot-sunxi/patches/010-dt-sync-files-with-kernel.patch
 create mode 100644 package/boot/uboot-sunxi/patches/011-dt-sync-dts-files-with-kernel.patch
 create mode 100644 package/boot/uboot-sunxi/patches/012-sun6i-fix-clock_twi_onoff.patch
 create mode 100644 package/boot/uboot-sunxi/patches/013-enable-realtek-phy.patch
 create mode 100644 package/boot/uboot-sunxi/patches/014-fix-gmac-init.patch
 create mode 100644 package/boot/uboot-sunxi/patches/015-fix-2nd-usb-ctrler-on-sun47i.patch
 create mode 100644 package/boot/uboot-sunxi/patches/016-spl-print-mmc-slot.patch
 create mode 100644 package/boot/uboot-sunxi/patches/017-usb-add-support-for-usb3-vbus-pin.patch
 create mode 100644 package/boot/uboot-sunxi/patches/018-usb-specify-vbus-pins-on-orangepis.patch
 create mode 100644 package/boot/uboot-sunxi/patches/019-sid-add-efuse-support-for-h3-a83t.patch
 create mode 100644 package/boot/uboot-sunxi/patches/020-boot-display-board-model-on-startup.patch
 create mode 100644 package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch
 create mode 100644 package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch
 create mode 100644 package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch
 create mode 100644 package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch
 create mode 100644 package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch
 create mode 100644 package/boot/uboot-sunxi/uEnv-default.txt
 create mode 100644 package/boot/uboot-sunxi/uEnv-pangolin.txt
 create mode 100644 package/boot/uboot-xburst/Makefile
 create mode 100644 package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch
 create mode 100644 package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch
 create mode 100644 package/boot/uboot-xburst/patches/0003-add-mmc-support.patch
 create mode 100644 package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch
 create mode 100644 package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch
 create mode 100644 package/boot/uboot-xburst/patches/0006-enable-silent-console.patch
 create mode 100644 package/boot/yamonenv/Makefile
 create mode 100644 package/boot/yamonenv/patches/001-yamonenv_mtd_partition.patch
 create mode 100644 package/devel/binutils/Makefile
 create mode 100644 package/devel/gdb-arc/Makefile
 create mode 100644 package/devel/gdb-arc/patches/100-no_extern_inline.patch
 create mode 100644 package/devel/gdb-arc/patches/110-no_testsuite.patch
 create mode 100644 package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch
 create mode 100644 package/devel/gdb/Makefile
 create mode 100644 package/devel/gdb/patches/001-gdb-pr14523-mips-signal-number.patch
 create mode 100644 package/devel/gdb/patches/002-remove-arguments.patch
 create mode 100644 package/devel/gdb/patches/100-musl_fix.patch
 create mode 100644 package/devel/perf/Makefile
 create mode 100644 package/devel/perf/musl-compat.h
 create mode 100644 package/devel/perf/musl-include/asm/errno.h
 create mode 100644 package/devel/perf/musl-include/string.h
 create mode 100644 package/devel/strace/Makefile
 create mode 100644 package/devel/strace/patches/100-workaround--pt-reg-collisions-ppc.patch
 create mode 100644 package/devel/trace-cmd/Makefile
 create mode 100644 package/devel/trace-cmd/patches/110-mac80211_tracepoint.patch
 create mode 100644 package/devel/valgrind/Makefile
 create mode 100644 package/devel/valgrind/files/default.supp
 create mode 100644 package/devel/valgrind/patches/100-fix_configure_check.patch
 create mode 100644 package/devel/valgrind/patches/130-fix_arm_arch_detection.patch
 create mode 100644 package/devel/valgrind/patches/200-musl_fix.patch
 create mode 100644 package/kernel/avila-wdt/Makefile
 create mode 100644 package/kernel/avila-wdt/src/Makefile
 create mode 100644 package/kernel/avila-wdt/src/avila-wdt.c
 create mode 100644 package/kernel/button-hotplug/Makefile
 create mode 100644 package/kernel/button-hotplug/src/Kconfig
 create mode 100644 package/kernel/button-hotplug/src/Makefile
 create mode 100644 package/kernel/button-hotplug/src/button-hotplug.c
 create mode 100644 package/kernel/gpio-button-hotplug/Makefile
 create mode 100644 package/kernel/gpio-button-hotplug/src/Makefile
 create mode 100644 package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c
 create mode 100644 package/kernel/i2c-gpio-custom/Makefile
 create mode 100644 package/kernel/i2c-gpio-custom/src/Kconfig
 create mode 100644 package/kernel/i2c-gpio-custom/src/Makefile
 create mode 100644 package/kernel/i2c-gpio-custom/src/i2c-gpio-custom.c
 create mode 100644 package/kernel/kmod-sched-cake/Makefile
 create mode 100644 package/kernel/linux/Makefile
 create mode 100644 package/kernel/linux/modules/001-depends.mk
 create mode 100644 package/kernel/linux/modules/block.mk
 create mode 100644 package/kernel/linux/modules/can.mk
 create mode 100644 package/kernel/linux/modules/crypto.mk
 create mode 100644 package/kernel/linux/modules/firewire.mk
 create mode 100644 package/kernel/linux/modules/fs.mk
 create mode 100644 package/kernel/linux/modules/hwmon.mk
 create mode 100644 package/kernel/linux/modules/i2c.mk
 create mode 100644 package/kernel/linux/modules/input.mk
 create mode 100644 package/kernel/linux/modules/leds.mk
 create mode 100644 package/kernel/linux/modules/lib.mk
 create mode 100644 package/kernel/linux/modules/netdevices.mk
 create mode 100644 package/kernel/linux/modules/netfilter.mk
 create mode 100644 package/kernel/linux/modules/netsupport.mk
 create mode 100644 package/kernel/linux/modules/nls.mk
 create mode 100644 package/kernel/linux/modules/other.mk
 create mode 100644 package/kernel/linux/modules/pcmcia.mk
 create mode 100644 package/kernel/linux/modules/sound.mk
 create mode 100644 package/kernel/linux/modules/spi.mk
 create mode 100644 package/kernel/linux/modules/usb.mk
 create mode 100644 package/kernel/linux/modules/video.mk
 create mode 100644 package/kernel/linux/modules/virt.mk
 create mode 100644 package/kernel/linux/modules/w1.mk
 create mode 100644 package/kernel/linux/modules/wpan.mk
 create mode 100644 package/kernel/mac80211/Makefile
 create mode 100644 package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
 create mode 100644 package/kernel/mac80211/files/lib/wifi/mac80211.sh
 create mode 100644 package/kernel/mac80211/files/mac80211.hotplug
 create mode 100644 package/kernel/mac80211/files/regdb.txt
 create mode 100644 package/kernel/mac80211/patches/000-fix_kconfig.patch
 create mode 100644 package/kernel/mac80211/patches/001-fix_build.patch
 create mode 100644 package/kernel/mac80211/patches/002-change_allconfig.patch
 create mode 100644 package/kernel/mac80211/patches/003-remove_bogus_modparams.patch
 create mode 100644 package/kernel/mac80211/patches/004-fix_duplicate_skcipher_backport.patch
 create mode 100644 package/kernel/mac80211/patches/005-backport_skb_get_hash_perturb.patch
 create mode 100644 package/kernel/mac80211/patches/010-disable_rfkill.patch
 create mode 100644 package/kernel/mac80211/patches/050-lib80211_option.patch
 create mode 100644 package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch
 create mode 100644 package/kernel/mac80211/patches/070-ath_common_config.patch
 create mode 100644 package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch
 create mode 100644 package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch
 create mode 100644 package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch
 create mode 100644 package/kernel/mac80211/patches/130-mac80211-hwsim-hrtimer-clock.patch
 create mode 100644 package/kernel/mac80211/patches/150-disable_addr_notifier.patch
 create mode 100644 package/kernel/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch
 create mode 100644 package/kernel/mac80211/patches/210-ap_scan.patch
 create mode 100644 package/kernel/mac80211/patches/300-ath9k-Switch-to-using-mac80211-intermediate-software.patch
 create mode 100644 package/kernel/mac80211/patches/301-ath9k-force-rx_clear-when-disabling-rx.patch
 create mode 100644 package/kernel/mac80211/patches/302-ath9k-limit-retries-for-powersave-response-frames.patch
 create mode 100644 package/kernel/mac80211/patches/303-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch
 create mode 100644 package/kernel/mac80211/patches/304-mac80211-add-hdrlen-to-ieee80211_tx_data.patch
 create mode 100644 package/kernel/mac80211/patches/305-mac80211-add-NEED_ALIGNED4_SKBS-hw-flag.patch
 create mode 100644 package/kernel/mac80211/patches/306-mac80211-minstrel-Enable-STBC-and-LDPC-for-VHT-Rates.patch
 create mode 100644 package/kernel/mac80211/patches/307-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch
 create mode 100644 package/kernel/mac80211/patches/308-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch
 create mode 100644 package/kernel/mac80211/patches/309-ath9k-report-tx-status-on-EOSP.patch
 create mode 100644 package/kernel/mac80211/patches/310-ath9k-fix-block-ack-window-tracking-issues.patch
 create mode 100644 package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch
 create mode 100644 package/kernel/mac80211/patches/313-mac80211-fix-sequence-number-allocation-regression.patch
 create mode 100644 package/kernel/mac80211/patches/314-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch
 create mode 100644 package/kernel/mac80211/patches/315-ath9k_hw-issue-external-reset-for-QCA955x.patch
 create mode 100644 package/kernel/mac80211/patches/316-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch
 create mode 100644 package/kernel/mac80211/patches/317-Revert-ath9k_hw-implement-temperature-compensation-s.patch
 create mode 100644 package/kernel/mac80211/patches/318-mac80211-fix-up-mismerge-of-ieee80211_tx_dequeue.patch
 create mode 100644 package/kernel/mac80211/patches/319-mac80211-avoid-extra-memcpy-in-A-MSDU-head-creation.patch
 create mode 100644 package/kernel/mac80211/patches/320-mac80211-fix-A-MSDU-outer-SA-DA.patch
 create mode 100644 package/kernel/mac80211/patches/321-Revert-mac80211-allow-using-AP_LINK_PS-with-mac80211.patch
 create mode 100644 package/kernel/mac80211/patches/322-mac80211-update-A-MPDU-flag-on-tx-dequeue.patch
 create mode 100644 package/kernel/mac80211/patches/323-mac80211-remove-bogus-skb-vif-assignment.patch
 create mode 100644 package/kernel/mac80211/patches/324-mac80211-fix-A-MSDU-aggregation-with-fast-xmit-txq.patch
 create mode 100644 package/kernel/mac80211/patches/325-ath9k-fix-ath9k_hw_gpio_get-to-return-0-or-1-on-succ.patch
 create mode 100644 package/kernel/mac80211/patches/326-Documentation-dt-net-add-ath9k-wireless-device-bindi.patch
 create mode 100644 package/kernel/mac80211/patches/327-ath9k-add-a-helper-to-get-the-string-representation-.patch
 create mode 100644 package/kernel/mac80211/patches/328-ath9k-parse-the-device-configuration-from-an-OF-node.patch
 create mode 100644 package/kernel/mac80211/patches/400-ath_move_debug_code.patch
 create mode 100644 package/kernel/mac80211/patches/401-ath9k_blink_default.patch
 create mode 100644 package/kernel/mac80211/patches/402-ath_regd_optional.patch
 create mode 100644 package/kernel/mac80211/patches/403-world_regd_fixup.patch
 create mode 100644 package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch
 create mode 100644 package/kernel/mac80211/patches/405-ath_regd_us.patch
 create mode 100644 package/kernel/mac80211/patches/406-ath_relax_default_regd.patch
 create mode 100644 package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
 create mode 100644 package/kernel/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch
 create mode 100644 package/kernel/mac80211/patches/420-ath5k_disable_fast_cc.patch
 create mode 100644 package/kernel/mac80211/patches/430-add_ath5k_platform.patch
 create mode 100644 package/kernel/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch
 create mode 100644 package/kernel/mac80211/patches/432-ath5k_add_pciids.patch
 create mode 100644 package/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch
 create mode 100644 package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
 create mode 100644 package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
 create mode 100644 package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
 create mode 100644 package/kernel/mac80211/patches/511-ath9k_reduce_rxbuf.patch
 create mode 100644 package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
 create mode 100644 package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
 create mode 100644 package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
 create mode 100644 package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
 create mode 100644 package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch
 create mode 100644 package/kernel/mac80211/patches/540-ath9k_reduce_ani_interval.patch
 create mode 100644 package/kernel/mac80211/patches/541-ath9k_rx_dma_stop_check.patch
 create mode 100644 package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
 create mode 100644 package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
 create mode 100644 package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
 create mode 100644 package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch
 create mode 100644 package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch
 create mode 100644 package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch
 create mode 100644 package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
 create mode 100644 package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
 create mode 100644 package/kernel/mac80211/patches/550-ath9k-Add-a-define-for-the-EEPROM-eepmisc-endianness.patch
 create mode 100644 package/kernel/mac80211/patches/551-ath9k-indicate-that-the-AR9003-EEPROM-template-value.patch
 create mode 100644 package/kernel/mac80211/patches/552-ath9k-Add-an-eeprom_ops-callback-for-retrieving-the-.patch
 create mode 100644 package/kernel/mac80211/patches/553-ath9k-replace-eeprom_param-EEP_MINOR_REV-with-get_ee.patch
 create mode 100644 package/kernel/mac80211/patches/554-ath9k-consistently-use-get_eeprom_rev-ah.patch
 create mode 100644 package/kernel/mac80211/patches/555-ath9k-Make-the-EEPROM-swapping-check-use-the-eepmisc.patch
 create mode 100644 package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
 create mode 100644 package/kernel/mac80211/patches/557-ath9k-disable-bands-via-dt.patch
 create mode 100644 package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch
 create mode 100644 package/kernel/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch
 create mode 100755 package/kernel/mac80211/scripts/import-backports.sh
 create mode 100644 package/kernel/mmc_over_gpio/Makefile
 create mode 100644 package/kernel/mmc_over_gpio/files/mmc_over_gpio.config
 create mode 100644 package/kernel/mmc_over_gpio/files/mmc_over_gpio.init
 create mode 100644 package/kernel/om-watchdog/Makefile
 create mode 100644 package/kernel/om-watchdog/files/om-watchdog
 create mode 100644 package/kernel/om-watchdog/files/om-watchdog.init
 create mode 100644 package/kernel/rotary-gpio-custom/Makefile
 create mode 100644 package/kernel/rotary-gpio-custom/src/Kconfig
 create mode 100644 package/kernel/rotary-gpio-custom/src/Makefile
 create mode 100644 package/kernel/rotary-gpio-custom/src/rotary-gpio-custom.c
 create mode 100644 package/kernel/spi-gpio-custom/Makefile
 create mode 100644 package/kernel/spi-gpio-custom/src/Kconfig
 create mode 100644 package/kernel/spi-gpio-custom/src/Makefile
 create mode 100644 package/kernel/spi-gpio-custom/src/spi-gpio-custom.c
 create mode 100644 package/kernel/trelay/Makefile
 create mode 100644 package/kernel/trelay/files/trelay.config
 create mode 100644 package/kernel/trelay/files/trelay.hotplug
 create mode 100644 package/kernel/trelay/files/trelay.init
 create mode 100644 package/kernel/trelay/src/Makefile
 create mode 100644 package/kernel/trelay/src/trelay.c
 create mode 100644 package/kernel/w1-gpio-custom/Makefile
 create mode 100644 package/kernel/w1-gpio-custom/src/Kconfig
 create mode 100644 package/kernel/w1-gpio-custom/src/Makefile
 create mode 100644 package/kernel/w1-gpio-custom/src/w1-gpio-custom.c
 create mode 100644 package/kernel/wrt55agv2-spidevs/Makefile
 create mode 100644 package/kernel/wrt55agv2-spidevs/src/Kconfig
 create mode 100644 package/kernel/wrt55agv2-spidevs/src/Makefile
 create mode 100644 package/kernel/wrt55agv2-spidevs/src/wrt55agv2_spidevs.c
 create mode 100644 package/libs/argp-standalone/Makefile
 create mode 100644 package/libs/argp-standalone/patches/001-throw-in-funcdef.patch
 create mode 100644 package/libs/argp-standalone/patches/002-no_optimize.patch
 create mode 100644 package/libs/cyassl/Config.in
 create mode 100644 package/libs/cyassl/Makefile
 create mode 100644 package/libs/cyassl/patches/400-additional_compatibility.patch
 create mode 100644 package/libs/elfutils/Makefile
 create mode 100644 package/libs/elfutils/patches/002-argp_standalone.patch
 create mode 100644 package/libs/elfutils/patches/003-libint-stub.patch
 create mode 100644 package/libs/elfutils/patches/004-maybe-uninitialized.patch
 create mode 100644 package/libs/elfutils/patches/004-memcpy_def.patch
 create mode 100644 package/libs/elfutils/patches/005-build_only_libs.patch
 create mode 100644 package/libs/elfutils/patches/006-libdw_LIBS.patch
 create mode 100644 package/libs/elfutils/patches/100-musl-compat.patch
 create mode 100644 package/libs/elfutils/patches/101-no-fts.patch
 create mode 100644 package/libs/gettext-full/Makefile
 create mode 100644 package/libs/gettext-full/patches/000-relocatable.patch
 create mode 100644 package/libs/gettext-full/patches/001-autotools.patch
 create mode 100644 package/libs/gettext-full/patches/001-no_examples_and_tests.patch
 create mode 100644 package/libs/gettext-full/patches/003-gettext-error_print_progname.patch
 create mode 100644 package/libs/gettext-full/patches/100-error_progname.patch
 create mode 100644 package/libs/gettext-full/patches/110-error_progname_def.patch
 create mode 100644 package/libs/gettext-full/patches/120-uclibc-nolocale.patch
 create mode 100644 package/libs/gettext-full/patches/130-format-secuirty.patch
 create mode 100644 package/libs/gettext-full/patches/150-disable_libxml_iconv.patch
 create mode 100644 package/libs/gettext/Makefile
 create mode 100644 package/libs/gettext/src/LICENSE
 create mode 100644 package/libs/gettext/src/include/libintl.h
 create mode 100644 package/libs/gettext/src/m4/codeset.m4
 create mode 100644 package/libs/gettext/src/m4/gettext.m4
 create mode 100644 package/libs/gettext/src/m4/intl.m4
 create mode 100644 package/libs/gettext/src/m4/intldir.m4
 create mode 100644 package/libs/gettext/src/m4/intlmacosx.m4
 create mode 100644 package/libs/gettext/src/m4/lcmessage.m4
 create mode 100644 package/libs/gettext/src/m4/nls.m4
 create mode 100644 package/libs/gettext/src/m4/po.m4
 create mode 100644 package/libs/gmp/Makefile
 create mode 100644 package/libs/libbsd/Makefile
 create mode 100644 package/libs/libbsd/patches/001-aarch64_support.patch
 create mode 100644 package/libs/libconfig/Makefile
 create mode 100644 package/libs/libevent2/Makefile
 create mode 100644 package/libs/libiconv-full/Makefile
 create mode 100644 package/libs/libiconv-full/patches/100-strip_charsets.patch
 create mode 100644 package/libs/libiconv-full/patches/101-autotools.patch
 create mode 100644 package/libs/libiconv-full/patches/103-configure_ac_fix.patch
 create mode 100644 package/libs/libiconv-full/patches/200-work-with-libtool2.patch
 create mode 100644 package/libs/libiconv-full/patches/300-fortify-source-compat.patch
 create mode 100644 package/libs/libiconv/COPYING
 create mode 100644 package/libs/libiconv/COPYRIGHT
 create mode 100644 package/libs/libiconv/Makefile
 create mode 100644 package/libs/libiconv/src/LICENSE
 create mode 100644 package/libs/libiconv/src/iconv.c
 create mode 100644 package/libs/libiconv/src/include/charmaps.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-10.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-13.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-14.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-16.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-2.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-3.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-4.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-5.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-6.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-7.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-8.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/iso-8859-9.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/koi8-r.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1250.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1251.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1252.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1253.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1254.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1255.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1256.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1257.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-1258.h
 create mode 100644 package/libs/libiconv/src/include/charmaps/windows-874.h
 create mode 100644 package/libs/libiconv/src/include/iconv.h
 create mode 100644 package/libs/libiconv/src/m4/iconv.m4
 create mode 100644 package/libs/libjson-c/Makefile
 create mode 100644 package/libs/libjson-c/patches/000-libm.patch
 create mode 100644 package/libs/libmnl/Makefile
 create mode 100644 package/libs/libnetfilter-conntrack/Makefile
 create mode 100644 package/libs/libnetfilter-cthelper/Makefile
 create mode 100644 package/libs/libnetfilter-cttimeout/Makefile
 create mode 100644 package/libs/libnetfilter-log/Makefile
 create mode 100644 package/libs/libnetfilter-log/patches/0001-build-remove-unnecessary-pkgconfig-config.status-dep.patch
 create mode 100644 package/libs/libnetfilter-log/patches/0002-build-remove-unused-lines-in-Makefile.am.patch
 create mode 100644 package/libs/libnetfilter-log/patches/0003-build-resolve-automake-1.12-warnings.patch
 create mode 100644 package/libs/libnetfilter-log/patches/0004-Add-include-needed-for-integer-type-definition.patch
 create mode 100644 package/libs/libnetfilter-log/patches/0005-configure-uclinux-is-also-linux.patch
 create mode 100644 package/libs/libnetfilter-log/patches/0006-configure-add-without-ipulog-option-to-disable-libip.patch
 create mode 100644 package/libs/libnetfilter-queue/Makefile
 create mode 100644 package/libs/libnetfilter-queue/patches/100-checksum_computation.patch
 create mode 100644 package/libs/libnfnetlink/Makefile
 create mode 100644 package/libs/libnfnetlink/patches/100-missing_include.patch
 create mode 100644 package/libs/libnftnl/Makefile
 create mode 100644 package/libs/libnl-tiny/Makefile
 create mode 100644 package/libs/libnl-tiny/files/libnl-tiny.pc
 create mode 100644 package/libs/libnl-tiny/src/Makefile
 create mode 100644 package/libs/libnl-tiny/src/attr.c
 create mode 100644 package/libs/libnl-tiny/src/cache.c
 create mode 100644 package/libs/libnl-tiny/src/cache_mngt.c
 create mode 100644 package/libs/libnl-tiny/src/error.c
 create mode 100644 package/libs/libnl-tiny/src/genl.c
 create mode 100644 package/libs/libnl-tiny/src/genl_ctrl.c
 create mode 100644 package/libs/libnl-tiny/src/genl_family.c
 create mode 100644 package/libs/libnl-tiny/src/genl_mngt.c
 create mode 100644 package/libs/libnl-tiny/src/handlers.c
 create mode 100644 package/libs/libnl-tiny/src/include/netlink-generic.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink-local.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink-types.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/addr.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/attr.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/cache-api.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/cache.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/data.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/errno.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/genl/ctrl.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/genl/family.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/genl/genl.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/genl/mngt.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/handlers.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/list.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/msg.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/netlink-compat.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/netlink-kernel.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/netlink.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/object-api.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/object.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/socket.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/types.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/utils.h
 create mode 100644 package/libs/libnl-tiny/src/include/netlink/version.h
 create mode 100644 package/libs/libnl-tiny/src/include/unl.h
 create mode 100644 package/libs/libnl-tiny/src/msg.c
 create mode 100644 package/libs/libnl-tiny/src/nl.c
 create mode 100644 package/libs/libnl-tiny/src/object.c
 create mode 100644 package/libs/libnl-tiny/src/socket.c
 create mode 100644 package/libs/libnl-tiny/src/unl.c
 create mode 100644 package/libs/libnl/Makefile
 create mode 100644 package/libs/libpcap/Config.in
 create mode 100644 package/libs/libpcap/Makefile
 create mode 100644 package/libs/libpcap/patches/100-debian_shared_lib.patch
 create mode 100644 package/libs/libpcap/patches/102-makefile_disable_manpages.patch
 create mode 100644 package/libs/libpcap/patches/103-makefile_flex_workaround.patch
 create mode 100644 package/libs/libpcap/patches/201-space_optimization.patch
 create mode 100644 package/libs/libpcap/patches/202-protocol_api.patch
 create mode 100644 package/libs/libpcap/patches/203-undef_iw_mode_monitor.patch
 create mode 100644 package/libs/libreadline/Makefile
 create mode 100644 package/libs/libreadline/patches/001-install_perm.patch
 create mode 100644 package/libs/libroxml/Makefile
 create mode 100644 package/libs/librpc/Makefile
 create mode 100644 package/libs/libtool/Makefile
 create mode 100644 package/libs/libtool/patches/160-passthrough-ssp.patch
 create mode 100644 package/libs/libubox/Makefile
 create mode 100644 package/libs/libunwind/Makefile
 create mode 100644 package/libs/libunwind/patches/001-disable-tests.patch
 create mode 100644 package/libs/libunwind/patches/002-fix-building-getcontext_S.patch
 create mode 100644 package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch
 create mode 100644 package/libs/libusb-compat/Makefile
 create mode 100644 package/libs/libusb-compat/patches/001-fix-musl-stdint.patch
 create mode 100644 package/libs/libusb/Makefile
 create mode 100644 package/libs/lzo/Makefile
 create mode 100644 package/libs/mbedtls/Makefile
 create mode 100644 package/libs/mbedtls/patches/200-config.patch
 create mode 100644 package/libs/ncurses/Makefile
 create mode 100644 package/libs/ncurses/patches/100-ncurses-5.6-20080112-urxvt.patch
 create mode 100644 package/libs/ncurses/patches/101-ncurses-5.6-20080628-kbs.patch
 create mode 100644 package/libs/ncurses/patches/102-ncurses-5.9-gcc-5.patch
 create mode 100644 package/libs/ncurses/patches/103-fixup-pkg-config-handling.patch
 create mode 100644 package/libs/ncurses/patches/200-fix_missing_include.patch
 create mode 100644 package/libs/ncurses/patches/500-cross.patch
 create mode 100644 package/libs/ncurses/patches/900-terminfo.patch
 create mode 100644 package/libs/nettle/Config.in
 create mode 100644 package/libs/nettle/Makefile
 create mode 100644 package/libs/openssl/Config.in
 create mode 100644 package/libs/openssl/Makefile
 create mode 100644 package/libs/openssl/include/crypto/cryptodev.h
 create mode 100644 package/libs/openssl/patches/110-optimize-for-size.patch
 create mode 100644 package/libs/openssl/patches/130-perl-path.patch
 create mode 100644 package/libs/openssl/patches/140-makefile-dirs.patch
 create mode 100644 package/libs/openssl/patches/150-no_engines.patch
 create mode 100644 package/libs/openssl/patches/160-disable_doc_tests.patch
 create mode 100644 package/libs/openssl/patches/170-bash_path.patch
 create mode 100644 package/libs/openssl/patches/180-fix_link_segfault.patch
 create mode 100644 package/libs/openssl/patches/190-remove_timestamp_check.patch
 create mode 100644 package/libs/openssl/patches/200-parallel_build.patch
 create mode 100644 package/libs/polarssl/Makefile
 create mode 100644 package/libs/polarssl/patches/200-reduce_config.patch
 create mode 100644 package/libs/popt/Makefile
 create mode 100644 package/libs/sysfsutils/Makefile
 create mode 100644 package/libs/sysfsutils/patches/200-mnt_path_check.patch
 create mode 100644 package/libs/toolchain/Makefile
 create mode 100644 package/libs/toolchain/eglibc-files/etc/nsswitch.conf
 create mode 100644 package/libs/toolchain/glibc-files/etc/nsswitch.conf
 create mode 100644 package/libs/uclibc++/Makefile
 create mode 100644 package/libs/uclibc++/files/config.default
 create mode 100644 package/libs/uclibc++/patches/002-path_to_bash.patch
 create mode 100644 package/libs/uclibc++/patches/006-eabi_fix.patch
 create mode 100644 package/libs/uclibc++/patches/010-honor-ldflags.patch
 create mode 100644 package/libs/uclibc++/patches/020-template-fix.patch
 create mode 100644 package/libs/uclibc++/patches/030-memory_corruption_fix.patch
 create mode 100644 package/libs/uclibc++/patches/040-delete-c++14.patch
 create mode 100644 package/libs/uclient/Makefile
 create mode 100644 package/libs/ustream-ssl/Makefile
 create mode 100644 package/libs/zlib/Makefile
 create mode 100644 package/network/config/firewall/Makefile
 create mode 100644 package/network/config/firewall/files/firewall.config
 create mode 100644 package/network/config/firewall/files/firewall.hotplug
 create mode 100755 package/network/config/firewall/files/firewall.init
 create mode 100644 package/network/config/firewall/files/firewall.user
 create mode 100644 package/network/config/gre/Makefile
 create mode 100755 package/network/config/gre/files/gre.sh
 create mode 100644 package/network/config/ipip/Makefile
 create mode 100755 package/network/config/ipip/files/ipip.sh
 create mode 100644 package/network/config/netifd/Makefile
 create mode 100644 package/network/config/netifd/files/etc/hotplug.d/iface/00-netstate
 create mode 100755 package/network/config/netifd/files/etc/init.d/network
 create mode 100755 package/network/config/netifd/files/lib/netifd/dhcp.script
 create mode 100755 package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
 create mode 100755 package/network/config/netifd/files/lib/network/config.sh
 create mode 100755 package/network/config/netifd/files/sbin/devstatus
 create mode 120000 package/network/config/netifd/files/sbin/ifdown
 create mode 100755 package/network/config/netifd/files/sbin/ifstatus
 create mode 100755 package/network/config/netifd/files/sbin/ifup
 create mode 100755 package/network/config/netifd/files/usr/share/udhcpc/default.script
 create mode 100644 package/network/config/qos-scripts/Makefile
 create mode 100644 package/network/config/qos-scripts/files/etc/config/qos
 create mode 100755 package/network/config/qos-scripts/files/etc/hotplug.d/iface/10-qos
 create mode 100755 package/network/config/qos-scripts/files/etc/init.d/qos
 create mode 100755 package/network/config/qos-scripts/files/usr/bin/qos-start
 create mode 100755 package/network/config/qos-scripts/files/usr/bin/qos-stat
 create mode 100755 package/network/config/qos-scripts/files/usr/bin/qos-stop
 create mode 100755 package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
 create mode 100644 package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
 create mode 100644 package/network/config/soloscli/Makefile
 create mode 100644 package/network/config/soloscli/files/etc/hotplug.d/atm/15-solos-init
 create mode 100644 package/network/config/soloscli/files/etc/uci-default/solos
 create mode 100644 package/network/config/soloscli/files/solos-log-stats
 create mode 100644 package/network/config/soloscli/patches/001-no-driver.patch
 create mode 100644 package/network/config/soloscli/patches/002-cflags.patch
 create mode 100644 package/network/config/swconfig/Makefile
 create mode 100644 package/network/config/swconfig/files/switch.sh
 create mode 100644 package/network/config/swconfig/src/Makefile
 create mode 100644 package/network/config/swconfig/src/cli.c
 create mode 100644 package/network/config/swconfig/src/swlib.c
 create mode 100644 package/network/config/swconfig/src/swlib.h
 create mode 100644 package/network/config/swconfig/src/uci.c
 create mode 100644 package/network/config/vti/Makefile
 create mode 100755 package/network/config/vti/files/vti.sh
 create mode 100644 package/network/ipv6/6in4/Makefile
 create mode 100755 package/network/ipv6/6in4/files/6in4.sh
 create mode 100644 package/network/ipv6/6rd/Makefile
 create mode 100644 package/network/ipv6/6rd/files/6rd.sh
 create mode 100644 package/network/ipv6/6rd/src/6rdcalc.c
 create mode 100644 package/network/ipv6/6rd/src/Makefile
 create mode 100644 package/network/ipv6/6to4/Makefile
 create mode 100755 package/network/ipv6/6to4/files/6to4.sh
 create mode 100644 package/network/ipv6/ds-lite/Makefile
 create mode 100755 package/network/ipv6/ds-lite/files/dslite.sh
 create mode 100644 package/network/ipv6/map/Makefile
 create mode 100755 package/network/ipv6/map/files/map.sh
 create mode 100644 package/network/ipv6/map/src/CMakeLists.txt
 create mode 100644 package/network/ipv6/map/src/mapcalc.c
 create mode 100644 package/network/ipv6/odhcp6c/Makefile
 create mode 100755 package/network/ipv6/odhcp6c/files/dhcpv6.script
 create mode 100755 package/network/ipv6/odhcp6c/files/dhcpv6.sh
 create mode 100644 package/network/ipv6/thc-ipv6/Makefile
 create mode 100644 package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch
 create mode 100644 package/network/services/authsae/Makefile
 create mode 100644 package/network/services/authsae/files/lib/wifi/authsae.sh
 create mode 100644 package/network/services/authsae/patches/100-musl_fix.patch
 create mode 100644 package/network/services/dnsmasq/Makefile
 create mode 100644 package/network/services/dnsmasq/files/dhcp.conf
 create mode 100644 package/network/services/dnsmasq/files/dnsmasq.conf
 create mode 100644 package/network/services/dnsmasq/files/dnsmasq.init
 create mode 100644 package/network/services/dnsmasq/files/dnsmasqsec.hotplug
 create mode 100644 package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
 create mode 100644 package/network/services/dnsmasq/patches/110-ipset-remove-old-kernel-support.patch
 create mode 100644 package/network/services/dnsmasq/patches/120-dnsmasq-compile-time-option-NO_ID.patch
 create mode 100644 package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch
 create mode 100644 package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch
 create mode 100644 package/network/services/dropbear/Config.in
 create mode 100644 package/network/services/dropbear/Makefile
 create mode 100644 package/network/services/dropbear/files/dropbear.config
 create mode 100755 package/network/services/dropbear/files/dropbear.init
 create mode 100644 package/network/services/dropbear/patches/100-pubkey_path.patch
 create mode 100644 package/network/services/dropbear/patches/110-change_user.patch
 create mode 100644 package/network/services/dropbear/patches/120-openwrt_options.patch
 create mode 100644 package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
 create mode 100644 package/network/services/dropbear/patches/140-disable_assert.patch
 create mode 100644 package/network/services/dropbear/patches/150-dbconvert_standalone.patch
 create mode 100644 package/network/services/dropbear/patches/500-set-default-path.patch
 create mode 100644 package/network/services/dropbear/patches/600-allow-blank-root-password.patch
 create mode 100644 package/network/services/dropbear/patches/610-skip-default-keys-in-custom-runs.patch
 create mode 100644 package/network/services/ead/Makefile
 create mode 100644 package/network/services/ead/src/Makefile
 create mode 100644 package/network/services/ead/src/aes.c
 create mode 100644 package/network/services/ead/src/ead-client.c
 create mode 100644 package/network/services/ead/src/ead-crypt.c
 create mode 100644 package/network/services/ead/src/ead-crypt.h
 create mode 100644 package/network/services/ead/src/ead-pcap.h
 create mode 100644 package/network/services/ead/src/ead.c
 create mode 100644 package/network/services/ead/src/ead.h
 create mode 100644 package/network/services/ead/src/filter.c
 create mode 100644 package/network/services/ead/src/libbridge.h
 create mode 100644 package/network/services/ead/src/libbridge_init.c
 create mode 100644 package/network/services/ead/src/libbridge_private.h
 create mode 100644 package/network/services/ead/src/list.h
 create mode 100644 package/network/services/ead/src/passwd
 create mode 100644 package/network/services/ead/src/pfc.c
 create mode 100644 package/network/services/ead/src/pw_encrypt_md5.c
 create mode 100644 package/network/services/ead/src/sha1.c
 create mode 100644 package/network/services/ead/src/tinysrp/Makefile.am
 create mode 100644 package/network/services/ead/src/tinysrp/Makefile.in
 create mode 100644 package/network/services/ead/src/tinysrp/Notes
 create mode 100644 package/network/services/ead/src/tinysrp/acconfig.h
 create mode 100644 package/network/services/ead/src/tinysrp/acinclude.m4
 create mode 100644 package/network/services/ead/src/tinysrp/aclocal.m4
 create mode 100644 package/network/services/ead/src/tinysrp/bn.h
 create mode 100644 package/network/services/ead/src/tinysrp/bn_add.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_asm.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_ctx.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_div.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_exp.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_lcl.h
 create mode 100644 package/network/services/ead/src/tinysrp/bn_lib.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_mul.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_prime.h
 create mode 100644 package/network/services/ead/src/tinysrp/bn_shift.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_sqr.c
 create mode 100644 package/network/services/ead/src/tinysrp/bn_word.c
 create mode 100644 package/network/services/ead/src/tinysrp/clitest.c
 create mode 100644 package/network/services/ead/src/tinysrp/config.h.in
 create mode 100755 package/network/services/ead/src/tinysrp/configure
 create mode 100644 package/network/services/ead/src/tinysrp/configure.in
 create mode 100755 package/network/services/ead/src/tinysrp/install-sh
 create mode 100755 package/network/services/ead/src/tinysrp/missing
 create mode 100755 package/network/services/ead/src/tinysrp/mkinstalldirs
 create mode 100644 package/network/services/ead/src/tinysrp/srvtest.c
 create mode 100644 package/network/services/ead/src/tinysrp/stamp-h.in
 create mode 100644 package/network/services/ead/src/tinysrp/t_client.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_client.h
 create mode 100644 package/network/services/ead/src/tinysrp/t_conf.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_conv.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_defines.h
 create mode 100644 package/network/services/ead/src/tinysrp/t_getconf.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_getpass.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_math.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_misc.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_pw.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_pwd.h
 create mode 100644 package/network/services/ead/src/tinysrp/t_read.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_read.h
 create mode 100644 package/network/services/ead/src/tinysrp/t_server.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_server.h
 create mode 100644 package/network/services/ead/src/tinysrp/t_sha.c
 create mode 100644 package/network/services/ead/src/tinysrp/t_sha.h
 create mode 100644 package/network/services/ead/src/tinysrp/t_truerand.c
 create mode 100644 package/network/services/ead/src/tinysrp/tconf.c
 create mode 100644 package/network/services/ead/src/tinysrp/tinysrp.c
 create mode 100644 package/network/services/ead/src/tinysrp/tinysrp.h
 create mode 100644 package/network/services/ead/src/tinysrp/tpasswd
 create mode 100644 package/network/services/ead/src/tinysrp/tphrase.c
 create mode 100644 package/network/services/hostapd/Config.in
 create mode 100644 package/network/services/hostapd/Makefile
 create mode 100644 package/network/services/hostapd/files/hostapd-full.config
 create mode 100644 package/network/services/hostapd/files/hostapd-mini.config
 create mode 100644 package/network/services/hostapd/files/multicall.c
 create mode 100644 package/network/services/hostapd/files/netifd.sh
 create mode 100644 package/network/services/hostapd/files/wpa_supplicant-full.config
 create mode 100644 package/network/services/hostapd/files/wpa_supplicant-mini.config
 create mode 100644 package/network/services/hostapd/files/wpa_supplicant-p2p.config
 create mode 100644 package/network/services/hostapd/files/wps-hotplug.sh
 create mode 100644 package/network/services/hostapd/patches/001-4addr-fix-reconnecting-client-on-connection-lost.patch
 create mode 100644 package/network/services/hostapd/patches/100-daemonize_fix.patch
 create mode 100644 package/network/services/hostapd/patches/110-no_eapol_fix.patch
 create mode 100644 package/network/services/hostapd/patches/120-disable_bridge_packet_workaround.patch
 create mode 100644 package/network/services/hostapd/patches/130-Revert-nl80211-Remove-duplicated-check-in-nl80211_se.patch
 create mode 100644 package/network/services/hostapd/patches/200-multicall.patch
 create mode 100644 package/network/services/hostapd/patches/300-noscan.patch
 create mode 100644 package/network/services/hostapd/patches/310-rescan_immediately.patch
 create mode 100644 package/network/services/hostapd/patches/320-optional_rfkill.patch
 create mode 100644 package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch
 create mode 100644 package/network/services/hostapd/patches/340-reload_freq_change.patch
 create mode 100644 package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch
 create mode 100644 package/network/services/hostapd/patches/360-ctrl_iface_reload.patch
 create mode 100644 package/network/services/hostapd/patches/370-ap_sta_support.patch
 create mode 100644 package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch
 create mode 100644 package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch
 create mode 100644 package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch
 create mode 100644 package/network/services/hostapd/patches/410-limit_debug_messages.patch
 create mode 100644 package/network/services/hostapd/patches/420-indicate-features.patch
 create mode 100644 package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch
 create mode 100644 package/network/services/hostapd/patches/431-wpa_cli_ifdef.patch
 create mode 100644 package/network/services/hostapd/patches/432-missing-typedef.patch
 create mode 100644 package/network/services/hostapd/patches/450-scan_wait.patch
 create mode 100644 package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch
 create mode 100644 package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch
 create mode 100644 package/network/services/hostapd/patches/462-wpa_s-support-htmode-param.patch
 create mode 100644 package/network/services/hostapd/patches/470-survey_data_fallback.patch
 create mode 100644 package/network/services/hostapd/patches/600-ubus_support.patch
 create mode 100644 package/network/services/hostapd/src/src/ap/ubus.c
 create mode 100644 package/network/services/hostapd/src/src/ap/ubus.h
 create mode 100644 package/network/services/hostapd/src/src/utils/build_features.h
 create mode 100644 package/network/services/igmpproxy/Makefile
 create mode 100644 package/network/services/igmpproxy/files/igmpproxy.config
 create mode 100644 package/network/services/igmpproxy/files/igmpproxy.init
 create mode 100644 package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch
 create mode 100644 package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch
 create mode 100644 package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch
 create mode 100644 package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch
 create mode 100644 package/network/services/igmpproxy/patches/010-missing_include.patch
 create mode 100644 package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch
 create mode 100644 package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch
 create mode 100644 package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch
 create mode 100644 package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
 create mode 100644 package/network/services/ipset-dns/Makefile
 create mode 100644 package/network/services/ipset-dns/files/ipset-dns.config
 create mode 100755 package/network/services/ipset-dns/files/ipset-dns.init
 create mode 100644 package/network/services/ipset-dns/patches/100-simultaneous-ipv4-ipv6.patch
 create mode 100644 package/network/services/lldpd/Config.in
 create mode 100644 package/network/services/lldpd/Makefile
 create mode 100644 package/network/services/lldpd/files/lldpd.config
 create mode 100644 package/network/services/lldpd/files/lldpd.init
 create mode 100644 package/network/services/mdns/Makefile
 create mode 100644 package/network/services/mdns/files/mdns.config
 create mode 100644 package/network/services/mdns/files/mdns.init
 create mode 100644 package/network/services/mdns/files/mdns.json
 create mode 100644 package/network/services/odhcpd/Makefile
 create mode 100755 package/network/services/odhcpd/files/odhcpd-update
 create mode 100644 package/network/services/odhcpd/files/odhcpd.defaults
 create mode 100644 package/network/services/odhcpd/files/odhcpd.init
 create mode 100644 package/network/services/omcproxy/Makefile
 create mode 100644 package/network/services/omcproxy/files/omcproxy.config
 create mode 100644 package/network/services/omcproxy/files/omcproxy.init
 create mode 100644 package/network/services/openvpn-easy-rsa/Makefile
 create mode 100644 package/network/services/openvpn-easy-rsa/files/easy-rsa.index
 create mode 100644 package/network/services/openvpn-easy-rsa/files/easy-rsa.serial
 create mode 100644 package/network/services/openvpn-easy-rsa/patches/100-run-ootb.patch
 create mode 100644 package/network/services/openvpn/Config-nossl.in
 create mode 100644 package/network/services/openvpn/Config-openssl.in
 create mode 100644 package/network/services/openvpn/Config-polarssl.in
 create mode 100644 package/network/services/openvpn/Makefile
 create mode 100644 package/network/services/openvpn/files/openvpn.config
 create mode 100644 package/network/services/openvpn/files/openvpn.init
 create mode 100644 package/network/services/openvpn/files/openvpn.upgrade
 create mode 100644 package/network/services/openvpn/patches/001-reproducible-remove_DATE.patch
 create mode 100644 package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch
 create mode 100644 package/network/services/openvpn/patches/101-backport_upstream_polarssl_debug_call.patch
 create mode 100644 package/network/services/openvpn/patches/200-small_build_enable_occ.patch
 create mode 100644 package/network/services/ppp/Makefile
 create mode 100644 package/network/services/ppp/files/etc/ppp/chap-secrets
 create mode 100644 package/network/services/ppp/files/etc/ppp/filter
 create mode 100644 package/network/services/ppp/files/etc/ppp/options
 create mode 100644 package/network/services/ppp/files/etc/ppp/options.pptp
 create mode 100644 package/network/services/ppp/files/etc/ppp/radius.conf
 create mode 100644 package/network/services/ppp/files/etc/ppp/radius/dictionary
 create mode 100644 package/network/services/ppp/files/etc/ppp/radius/dictionary.asnet
 create mode 100644 package/network/services/ppp/files/etc/ppp/radius/dictionary.microsoft
 create mode 100644 package/network/services/ppp/files/etc/ppp/radius/servers
 create mode 100755 package/network/services/ppp/files/lib/netifd/ppp-down
 create mode 100755 package/network/services/ppp/files/lib/netifd/ppp-up
 create mode 100644 package/network/services/ppp/files/lib/netifd/ppp6-up
 create mode 100755 package/network/services/ppp/files/ppp.sh
 create mode 100644 package/network/services/ppp/patches/001-honor-ldflags.patch
 create mode 100644 package/network/services/ppp/patches/010-use_target_for_configure.patch
 create mode 100644 package/network/services/ppp/patches/100-debian_ip-ip_option.patch
 create mode 100644 package/network/services/ppp/patches/101-debian_close_dev_ppp.patch
 create mode 100644 package/network/services/ppp/patches/103-debian_fix_link_pidfile.patch
 create mode 100644 package/network/services/ppp/patches/105-debian_demand.patch
 create mode 100644 package/network/services/ppp/patches/106-debian_stripMSdomain.patch
 create mode 100644 package/network/services/ppp/patches/107-debian_pppoatm_wildcard.patch
 create mode 100644 package/network/services/ppp/patches/110-debian_defaultroute.patch
 create mode 100644 package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch
 create mode 100644 package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch
 create mode 100644 package/network/services/ppp/patches/130-no_cdefs_h.patch
 create mode 100644 package/network/services/ppp/patches/131-missing_prototype_macro.patch
 create mode 100644 package/network/services/ppp/patches/132-fix_linux_includes.patch
 create mode 100644 package/network/services/ppp/patches/133-fix_sha1_include.patch
 create mode 100644 package/network/services/ppp/patches/140-pppoe_compile_fix.patch
 create mode 100644 package/network/services/ppp/patches/200-makefile.patch
 create mode 100644 package/network/services/ppp/patches/201-mppe_mppc_1.1.patch
 create mode 100644 package/network/services/ppp/patches/202-no_strip.patch
 create mode 100644 package/network/services/ppp/patches/203-opt_flags.patch
 create mode 100644 package/network/services/ppp/patches/204-radius_config.patch
 create mode 100644 package/network/services/ppp/patches/205-no_exponential_timeout.patch
 create mode 100644 package/network/services/ppp/patches/206-compensate_time_change.patch
 create mode 100644 package/network/services/ppp/patches/207-lcp_mtu_max.patch
 create mode 100644 package/network/services/ppp/patches/208-fix_status_code.patch
 create mode 100644 package/network/services/ppp/patches/300-filter-pcap-includes-lib.patch
 create mode 100644 package/network/services/ppp/patches/310-precompile_filter.patch
 create mode 100644 package/network/services/ppp/patches/320-custom_iface_names.patch
 create mode 100644 package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch
 create mode 100644 package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
 create mode 100644 package/network/services/ppp/patches/340-populate_default_gateway.patch
 create mode 100644 package/network/services/ppp/patches/400-simplify_kernel_checks.patch
 create mode 100644 package/network/services/ppp/patches/401-no_record_file.patch
 create mode 100644 package/network/services/ppp/patches/403-no_wtmp.patch
 create mode 100644 package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch
 create mode 100644 package/network/services/ppp/patches/405-no_multilink_option.patch
 create mode 100644 package/network/services/ppp/patches/500-add-pptp-plugin.patch
 create mode 100644 package/network/services/ppp/patches/510-pptp_compile_fix.patch
 create mode 100644 package/network/services/ppp/patches/520-uniq.patch
 create mode 100644 package/network/services/ppp/patches/530-pppoe_send_padt.patch
 create mode 100644 package/network/services/ppp/patches/531-pppoe_no_disconnect_warning.patch
 create mode 100644 package/network/services/ppp/patches/540-save-pppol2tp_fd_str.patch
 create mode 100644 package/network/services/ppp/patches/550-fix-printer-args.patch
 create mode 100644 package/network/services/ppp/utils/pfc.c
 create mode 100644 package/network/services/relayd/Makefile
 create mode 100644 package/network/services/relayd/files/relay.hotplug
 create mode 100644 package/network/services/relayd/files/relay.init
 create mode 100644 package/network/services/samba36/Makefile
 create mode 100644 package/network/services/samba36/files/samba.config
 create mode 100755 package/network/services/samba36/files/samba.init
 create mode 100644 package/network/services/samba36/files/smb.conf.template
 create mode 100644 package/network/services/samba36/patches/010-patch-cve-2015-5252.patch
 create mode 100644 package/network/services/samba36/patches/011-patch-cve-2015-5296.patch
 create mode 100644 package/network/services/samba36/patches/012-patch-cve-2015-5299.patch
 create mode 100644 package/network/services/samba36/patches/015-patch-cve-2015-7560.patch
 create mode 100644 package/network/services/samba36/patches/020-CVE-preparation-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/021-CVE-preparation-v3-6-addition.patch
 create mode 100644 package/network/services/samba36/patches/022-CVE-2015-5370-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/023-CVE-2016-2110-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/024-CVE-2016-2111-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/025-CVE-2016-2112-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/026-CVE-2016-2115-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/027-CVE-2016-2118-v3-6.patch
 create mode 100644 package/network/services/samba36/patches/100-configure_fixes.patch
 create mode 100644 package/network/services/samba36/patches/110-multicall.patch
 create mode 100644 package/network/services/samba36/patches/111-owrt_smbpasswd.patch
 create mode 100644 package/network/services/samba36/patches/120-add_missing_ifdef.patch
 create mode 100644 package/network/services/samba36/patches/200-remove_printer_support.patch
 create mode 100644 package/network/services/samba36/patches/210-remove_ad_support.patch
 create mode 100644 package/network/services/samba36/patches/220-remove_services.patch
 create mode 100644 package/network/services/samba36/patches/230-remove_winreg_support.patch
 create mode 100644 package/network/services/samba36/patches/240-remove_dfs_api.patch
 create mode 100644 package/network/services/samba36/patches/250-remove_domain_logon.patch
 create mode 100644 package/network/services/samba36/patches/260-remove_samr.patch
 create mode 100644 package/network/services/samba36/patches/270-remove_registry_backend.patch
 create mode 100644 package/network/services/samba36/patches/280-strip_srvsvc.patch
 create mode 100644 package/network/services/samba36/patches/290-remove_lsa.patch
 create mode 100644 package/network/services/samba36/patches/300-assert_debug_level.patch
 create mode 100644 package/network/services/samba36/patches/310-remove_error_strings.patch
 create mode 100644 package/network/services/samba36/patches/320-debug_level_checks.patch
 create mode 100644 package/network/services/samba36/patches/330-librpc_default_print.patch
 create mode 100644 package/network/services/uhttpd/Makefile
 create mode 100644 package/network/services/uhttpd/files/ubus.default
 create mode 100644 package/network/services/uhttpd/files/uhttpd.config
 create mode 100755 package/network/services/uhttpd/files/uhttpd.init
 create mode 100644 package/network/utils/arptables/Makefile
 create mode 100644 package/network/utils/comgt/Makefile
 create mode 100644 package/network/utils/comgt/files/3g.chat
 create mode 100644 package/network/utils/comgt/files/3g.sh
 create mode 100644 package/network/utils/comgt/files/3g.usb
 create mode 100644 package/network/utils/comgt/files/directip-stop.gcom
 create mode 100644 package/network/utils/comgt/files/directip.gcom
 create mode 100644 package/network/utils/comgt/files/directip.sh
 create mode 100644 package/network/utils/comgt/files/evdo.chat
 create mode 100644 package/network/utils/comgt/files/getcardinfo.gcom
 create mode 100644 package/network/utils/comgt/files/getcarrier.gcom
 create mode 100644 package/network/utils/comgt/files/getcnum.gcom
 create mode 100644 package/network/utils/comgt/files/getimsi.gcom
 create mode 100644 package/network/utils/comgt/files/getstrength.gcom
 create mode 100644 package/network/utils/comgt/files/ncm.json
 create mode 100644 package/network/utils/comgt/files/ncm.sh
 create mode 100644 package/network/utils/comgt/files/runcommand.gcom
 create mode 100644 package/network/utils/comgt/files/setmode.gcom
 create mode 100644 package/network/utils/comgt/files/setpin.gcom
 create mode 100644 package/network/utils/comgt/patches/001-compile_fix.patch
 create mode 100644 package/network/utils/comgt/patches/002-termios.patch
 create mode 100644 package/network/utils/comgt/patches/003-no_XCASE.patch
 create mode 100644 package/network/utils/comgt/patches/004-check_tty.patch
 create mode 100644 package/network/utils/conntrack-tools/Makefile
 create mode 100644 package/network/utils/conntrack-tools/files/conntrackd.init
 create mode 100644 package/network/utils/curl/Config.in
 create mode 100644 package/network/utils/curl/Makefile
 create mode 100644 package/network/utils/curl/patches/200-no_docs_tests.patch
 create mode 100644 package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch
 create mode 100644 package/network/utils/dante/Makefile
 create mode 100644 package/network/utils/dante/patches/200-fix-RTLD_NEXT.patch
 create mode 100644 package/network/utils/ebtables/Makefile
 create mode 100644 package/network/utils/ebtables/patches/100-musl_fix.patch
 create mode 100644 package/network/utils/ebtables/patches/200-fix-extension-init.patch
 create mode 100644 package/network/utils/iftop/Makefile
 create mode 100644 package/network/utils/iftop/patches/110-fix-mac-display.patch
 create mode 100644 package/network/utils/iperf/Makefile
 create mode 100644 package/network/utils/iperf3/Makefile
 create mode 100644 package/network/utils/iproute2/Makefile
 create mode 100644 package/network/utils/iproute2/files/15-teql
 create mode 100644 package/network/utils/iproute2/patches/001-config.patch
 create mode 100644 package/network/utils/iproute2/patches/004-darwin_fixes.patch
 create mode 100644 package/network/utils/iproute2/patches/006-no_sctp.patch
 create mode 100644 package/network/utils/iproute2/patches/007-no_arpd.patch
 create mode 100644 package/network/utils/iproute2/patches/008-no_netem.patch
 create mode 100644 package/network/utils/iproute2/patches/010-type_fixes.patch
 create mode 100644 package/network/utils/iproute2/patches/100-allow_pfifo_fast.patch
 create mode 100644 package/network/utils/iproute2/patches/110-extra-ccopts.patch
 create mode 100644 package/network/utils/iproute2/patches/120-libnetlink-pic.patch
 create mode 100644 package/network/utils/iproute2/patches/130-missing_include.patch
 create mode 100644 package/network/utils/iproute2/patches/300-ip_tiny.patch
 create mode 100644 package/network/utils/iproute2/patches/900-drop_FAILED_POLICY.patch
 create mode 100644 package/network/utils/iproute2/patches/910-sanitize_headers_for_musl.patch
 create mode 100644 package/network/utils/iproute2/patches/911-fix_in_h_include.patch
 create mode 100644 package/network/utils/iproute2/patches/950-add-cake-to-tc.patch
 create mode 100644 package/network/utils/ipset/Makefile
 create mode 100644 package/network/utils/iptables/Makefile
 create mode 100644 package/network/utils/iptables/patches/020-iptables-disable-modprobe.patch
 create mode 100644 package/network/utils/iptables/patches/030-no-libnfnetlink.patch
 create mode 100644 package/network/utils/iptables/patches/050-optional-xml.patch
 create mode 100644 package/network/utils/iptables/patches/100-bash-location.patch
 create mode 100644 package/network/utils/iptables/patches/200-configurable_builtin.patch
 create mode 100644 package/network/utils/iptables/patches/300-musl_fixes.patch
 create mode 100644 package/network/utils/iptables/patches/500-add-xt_id-match.patch
 create mode 100644 package/network/utils/iptables/patches/600-shared-libext.patch
 create mode 100644 package/network/utils/iptables/patches/700-disable-legacy-revisions.patch
 create mode 100644 package/network/utils/iputils/Makefile
 create mode 100644 package/network/utils/iputils/patches/001-iputils.patch
 create mode 100644 package/network/utils/iputils/patches/002-fix-ipv6.patch
 create mode 100644 package/network/utils/iputils/patches/003-fix-makefile.patch
 create mode 100644 package/network/utils/iputils/patches/010-ping6_uclibc_resolv.patch
 create mode 100644 package/network/utils/iputils/patches/011-ping6_use_gnu_source.patch
 create mode 100644 package/network/utils/iputils/patches/020-include_fixes.patch
 create mode 100644 package/network/utils/iw/Makefile
 create mode 100644 package/network/utils/iw/patches/001-nl80211_h_sync.patch
 create mode 100644 package/network/utils/iw/patches/120-antenna_gain.patch
 create mode 100644 package/network/utils/iw/patches/200-reduce_size.patch
 create mode 100644 package/network/utils/iwcap/Makefile
 create mode 100644 package/network/utils/iwcap/src/iwcap.c
 create mode 100644 package/network/utils/iwinfo/Makefile
 create mode 100644 package/network/utils/linux-atm/Makefile
 create mode 100644 package/network/utils/linux-atm/files/atm.hotplug
 create mode 100644 package/network/utils/linux-atm/files/br2684-up
 create mode 100755 package/network/utils/linux-atm/files/br2684ctl
 create mode 100644 package/network/utils/linux-atm/files/br2684ctl_wrap
 create mode 100644 package/network/utils/linux-atm/patches/000-debian_16.patch
 create mode 100644 package/network/utils/linux-atm/patches/200-no_libfl.patch
 create mode 100644 package/network/utils/linux-atm/patches/300-objcopy_path.patch
 create mode 100644 package/network/utils/linux-atm/patches/400-portability_fixes.patch
 create mode 100644 package/network/utils/linux-atm/patches/500-br2684ctl_script.patch
 create mode 100644 package/network/utils/linux-atm/patches/600-fix-format-errors.patch
 create mode 100644 package/network/utils/maccalc/Makefile
 create mode 100644 package/network/utils/maccalc/src/Makefile
 create mode 100644 package/network/utils/maccalc/src/main.c
 create mode 100644 package/network/utils/nftables/Makefile
 create mode 100644 package/network/utils/nftables/patches/100-disable-doc-generation.patch
 create mode 100644 package/network/utils/owipcalc/Makefile
 create mode 100644 package/network/utils/owipcalc/src/owipcalc.c
 create mode 100644 package/network/utils/resolveip/Makefile
 create mode 100644 package/network/utils/resolveip/src/resolveip.c
 create mode 100644 package/network/utils/rssileds/Makefile
 create mode 100644 package/network/utils/rssileds/files/rssileds.init
 create mode 100644 package/network/utils/rssileds/src/rssileds.c
 create mode 100644 package/network/utils/tcpdump/Makefile
 create mode 100644 package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch
 create mode 100644 package/network/utils/tcpdump/patches/002-remove_static_libpcap_check.patch
 create mode 100644 package/network/utils/tcpdump/patches/100-tcpdump_mini.patch
 create mode 100644 package/network/utils/umbim/Makefile
 create mode 100755 package/network/utils/umbim/files/lib/netifd/proto/mbim.sh
 create mode 100644 package/network/utils/uqmi/Makefile
 create mode 100755 package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
 create mode 100644 package/network/utils/wireless-tools/Makefile
 create mode 100644 package/network/utils/wireless-tools/patches/001-debian.patch
 create mode 100644 package/network/utils/wireless-tools/patches/002-fix-iwconfig-power-argument-parsing.patch
 create mode 100644 package/network/utils/wireless-tools/patches/003-we_essential_def.patch
 create mode 100644 package/network/utils/wireless-tools/patches/004-increase_iwlist_buffer.patch
 create mode 100644 package/network/utils/wpan-tools/Makefile
 create mode 100644 package/network/utils/wwan/Makefile
 create mode 100644 package/network/utils/wwan/files/data/0421-03a7
 create mode 100644 package/network/utils/wwan/files/data/0421-060d
 create mode 100644 package/network/utils/wwan/files/data/0421-060e
 create mode 100644 package/network/utils/wwan/files/data/0421-0612
 create mode 100644 package/network/utils/wwan/files/data/0421-0619
 create mode 100644 package/network/utils/wwan/files/data/0421-061e
 create mode 100644 package/network/utils/wwan/files/data/0421-0623
 create mode 100644 package/network/utils/wwan/files/data/0421-0629
 create mode 100644 package/network/utils/wwan/files/data/0421-062d
 create mode 100644 package/network/utils/wwan/files/data/0421-062f
 create mode 100644 package/network/utils/wwan/files/data/0421-0638
 create mode 100644 package/network/utils/wwan/files/data/05c6-0016
 create mode 100644 package/network/utils/wwan/files/data/05c6-0023
 create mode 100644 package/network/utils/wwan/files/data/05c6-00a0
 create mode 100644 package/network/utils/wwan/files/data/05c6-6000
 create mode 100644 package/network/utils/wwan/files/data/05c6-9000
 create mode 100644 package/network/utils/wwan/files/data/07d1-3e01
 create mode 100644 package/network/utils/wwan/files/data/07d1-3e02
 create mode 100644 package/network/utils/wwan/files/data/07d1-7e11
 create mode 100644 package/network/utils/wwan/files/data/0af0-4005
 create mode 100644 package/network/utils/wwan/files/data/0af0-6901
 create mode 100644 package/network/utils/wwan/files/data/0af0-7201
 create mode 100644 package/network/utils/wwan/files/data/0af0-8120
 create mode 100644 package/network/utils/wwan/files/data/0af0-9200
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c000
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c001
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c002
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c003
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c004
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c005
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c00a
 create mode 100644 package/network/utils/wwan/files/data/0b3c-c00b
 create mode 100644 package/network/utils/wwan/files/data/0bdb-1900
 create mode 100644 package/network/utils/wwan/files/data/0bdb-1902
 create mode 100644 package/network/utils/wwan/files/data/0bdb-190a
 create mode 100644 package/network/utils/wwan/files/data/0bdb-190d
 create mode 100644 package/network/utils/wwan/files/data/0bdb-1910
 create mode 100644 package/network/utils/wwan/files/data/0c88-17da
 create mode 100644 package/network/utils/wwan/files/data/0c88-180a
 create mode 100644 package/network/utils/wwan/files/data/0f3d-68a2
 create mode 100644 package/network/utils/wwan/files/data/0f3d-68aa
 create mode 100644 package/network/utils/wwan/files/data/1004-6124
 create mode 100644 package/network/utils/wwan/files/data/1004-6141
 create mode 100644 package/network/utils/wwan/files/data/1004-6157
 create mode 100644 package/network/utils/wwan/files/data/1004-618f
 create mode 100644 package/network/utils/wwan/files/data/106c-3711
 create mode 100644 package/network/utils/wwan/files/data/106c-3714
 create mode 100644 package/network/utils/wwan/files/data/106c-3715
 create mode 100644 package/network/utils/wwan/files/data/106c-3716
 create mode 100644 package/network/utils/wwan/files/data/106c-3717
 create mode 100644 package/network/utils/wwan/files/data/106c-3718
 create mode 100644 package/network/utils/wwan/files/data/106c-3721
 create mode 100644 package/network/utils/wwan/files/data/1199-0017
 create mode 100644 package/network/utils/wwan/files/data/1199-0018
 create mode 100644 package/network/utils/wwan/files/data/1199-0019
 create mode 100644 package/network/utils/wwan/files/data/1199-0020
 create mode 100644 package/network/utils/wwan/files/data/1199-0021
 create mode 100644 package/network/utils/wwan/files/data/1199-0022
 create mode 100644 package/network/utils/wwan/files/data/1199-0023
 create mode 100644 package/network/utils/wwan/files/data/1199-0024
 create mode 100644 package/network/utils/wwan/files/data/1199-0025
 create mode 100644 package/network/utils/wwan/files/data/1199-0026
 create mode 100644 package/network/utils/wwan/files/data/1199-0027
 create mode 100644 package/network/utils/wwan/files/data/1199-0028
 create mode 100644 package/network/utils/wwan/files/data/1199-0112
 create mode 100644 package/network/utils/wwan/files/data/1199-0120
 create mode 100644 package/network/utils/wwan/files/data/1199-0218
 create mode 100644 package/network/utils/wwan/files/data/1199-0220
 create mode 100644 package/network/utils/wwan/files/data/1199-0224
 create mode 100644 package/network/utils/wwan/files/data/1199-0301
 create mode 100644 package/network/utils/wwan/files/data/1199-6802
 create mode 100644 package/network/utils/wwan/files/data/1199-6803
 create mode 100644 package/network/utils/wwan/files/data/1199-6804
 create mode 100644 package/network/utils/wwan/files/data/1199-6805
 create mode 100644 package/network/utils/wwan/files/data/1199-6808
 create mode 100644 package/network/utils/wwan/files/data/1199-6809
 create mode 100644 package/network/utils/wwan/files/data/1199-6813
 create mode 100644 package/network/utils/wwan/files/data/1199-6815
 create mode 100644 package/network/utils/wwan/files/data/1199-6816
 create mode 100644 package/network/utils/wwan/files/data/1199-6820
 create mode 100644 package/network/utils/wwan/files/data/1199-6821
 create mode 100644 package/network/utils/wwan/files/data/1199-6822
 create mode 100644 package/network/utils/wwan/files/data/1199-6833
 create mode 100644 package/network/utils/wwan/files/data/1199-6834
 create mode 100644 package/network/utils/wwan/files/data/1199-6835
 create mode 100644 package/network/utils/wwan/files/data/1199-6838
 create mode 100644 package/network/utils/wwan/files/data/1199-6839
 create mode 100644 package/network/utils/wwan/files/data/1199-683a
 create mode 100644 package/network/utils/wwan/files/data/1199-683b
 create mode 100644 package/network/utils/wwan/files/data/1199-6850
 create mode 100644 package/network/utils/wwan/files/data/1199-6851
 create mode 100644 package/network/utils/wwan/files/data/1199-6852
 create mode 100644 package/network/utils/wwan/files/data/1199-6853
 create mode 100644 package/network/utils/wwan/files/data/1199-6855
 create mode 100644 package/network/utils/wwan/files/data/1199-6856
 create mode 100644 package/network/utils/wwan/files/data/1199-6859
 create mode 100644 package/network/utils/wwan/files/data/1199-685a
 create mode 100644 package/network/utils/wwan/files/data/1199-6880
 create mode 100644 package/network/utils/wwan/files/data/1199-6890
 create mode 100644 package/network/utils/wwan/files/data/1199-6891
 create mode 100644 package/network/utils/wwan/files/data/1199-6892
 create mode 100644 package/network/utils/wwan/files/data/1199-6893
 create mode 100644 package/network/utils/wwan/files/data/1199-68a2
 create mode 100644 package/network/utils/wwan/files/data/1199-68aa
 create mode 100644 package/network/utils/wwan/files/data/12d1-1035
 create mode 100644 package/network/utils/wwan/files/data/12d1-1404
 create mode 100644 package/network/utils/wwan/files/data/12d1-1406
 create mode 100644 package/network/utils/wwan/files/data/12d1-140b
 create mode 100644 package/network/utils/wwan/files/data/12d1-140c
 create mode 100644 package/network/utils/wwan/files/data/12d1-1412
 create mode 100644 package/network/utils/wwan/files/data/12d1-141b
 create mode 100644 package/network/utils/wwan/files/data/12d1-1433
 create mode 100644 package/network/utils/wwan/files/data/12d1-1436
 create mode 100644 package/network/utils/wwan/files/data/12d1-1444
 create mode 100644 package/network/utils/wwan/files/data/12d1-144e
 create mode 100644 package/network/utils/wwan/files/data/12d1-1464
 create mode 100644 package/network/utils/wwan/files/data/12d1-1465
 create mode 100644 package/network/utils/wwan/files/data/12d1-1491
 create mode 100644 package/network/utils/wwan/files/data/12d1-14a5
 create mode 100644 package/network/utils/wwan/files/data/12d1-14a8
 create mode 100644 package/network/utils/wwan/files/data/12d1-14ac
 create mode 100644 package/network/utils/wwan/files/data/12d1-14ae
 create mode 100644 package/network/utils/wwan/files/data/12d1-14c6
 create mode 100644 package/network/utils/wwan/files/data/12d1-14c8
 create mode 100644 package/network/utils/wwan/files/data/12d1-14c9
 create mode 100644 package/network/utils/wwan/files/data/12d1-14ca
 create mode 100644 package/network/utils/wwan/files/data/12d1-14cb
 create mode 100644 package/network/utils/wwan/files/data/12d1-14cc
 create mode 100644 package/network/utils/wwan/files/data/12d1-14cf
 create mode 100644 package/network/utils/wwan/files/data/12d1-14d2
 create mode 100644 package/network/utils/wwan/files/data/12d1-1506
 create mode 100644 package/network/utils/wwan/files/data/12d1-150a
 create mode 100644 package/network/utils/wwan/files/data/12d1-150c
 create mode 100644 package/network/utils/wwan/files/data/12d1-150f
 create mode 100644 package/network/utils/wwan/files/data/12d1-151b
 create mode 100644 package/network/utils/wwan/files/data/12d1-151d
 create mode 100644 package/network/utils/wwan/files/data/12d1-156c
 create mode 100644 package/network/utils/wwan/files/data/12d1-1576
 create mode 100644 package/network/utils/wwan/files/data/12d1-1577
 create mode 100644 package/network/utils/wwan/files/data/12d1-1578
 create mode 100644 package/network/utils/wwan/files/data/12d1-1589
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c05
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c07
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c08
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c10
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c12
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c1e
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c1f
 create mode 100644 package/network/utils/wwan/files/data/12d1-1c23
 create mode 100644 package/network/utils/wwan/files/data/12d1-1f16
 create mode 100644 package/network/utils/wwan/files/data/1410-1400
 create mode 100644 package/network/utils/wwan/files/data/1410-1410
 create mode 100644 package/network/utils/wwan/files/data/1410-1420
 create mode 100644 package/network/utils/wwan/files/data/1410-1430
 create mode 100644 package/network/utils/wwan/files/data/1410-1450
 create mode 100644 package/network/utils/wwan/files/data/1410-2100
 create mode 100644 package/network/utils/wwan/files/data/1410-2110
 create mode 100644 package/network/utils/wwan/files/data/1410-2120
 create mode 100644 package/network/utils/wwan/files/data/1410-2130
 create mode 100644 package/network/utils/wwan/files/data/1410-2400
 create mode 100644 package/network/utils/wwan/files/data/1410-2410
 create mode 100644 package/network/utils/wwan/files/data/1410-2420
 create mode 100644 package/network/utils/wwan/files/data/1410-4100
 create mode 100644 package/network/utils/wwan/files/data/1410-4400
 create mode 100644 package/network/utils/wwan/files/data/1410-6000
 create mode 100644 package/network/utils/wwan/files/data/1410-6001
 create mode 100644 package/network/utils/wwan/files/data/1410-6002
 create mode 100644 package/network/utils/wwan/files/data/1410-6010
 create mode 100644 package/network/utils/wwan/files/data/1410-7001
 create mode 100644 package/network/utils/wwan/files/data/1410-7003
 create mode 100644 package/network/utils/wwan/files/data/1410-7030
 create mode 100644 package/network/utils/wwan/files/data/1410-7031
 create mode 100644 package/network/utils/wwan/files/data/1410-7041
 create mode 100644 package/network/utils/wwan/files/data/1410-7042
 create mode 100644 package/network/utils/wwan/files/data/1410-9011
 create mode 100644 package/network/utils/wwan/files/data/1410-b001
 create mode 100644 package/network/utils/wwan/files/data/1529-3100
 create mode 100644 package/network/utils/wwan/files/data/16d5-6202
 create mode 100644 package/network/utils/wwan/files/data/16d5-6501
 create mode 100644 package/network/utils/wwan/files/data/16d5-6502
 create mode 100644 package/network/utils/wwan/files/data/16d5-6603
 create mode 100644 package/network/utils/wwan/files/data/16d5-900d
 create mode 100644 package/network/utils/wwan/files/data/16d8-5141
 create mode 100644 package/network/utils/wwan/files/data/16d8-5533
 create mode 100644 package/network/utils/wwan/files/data/16d8-5543
 create mode 100644 package/network/utils/wwan/files/data/16d8-5553
 create mode 100644 package/network/utils/wwan/files/data/16d8-6002
 create mode 100644 package/network/utils/wwan/files/data/16d8-6006
 create mode 100644 package/network/utils/wwan/files/data/16d8-6007
 create mode 100644 package/network/utils/wwan/files/data/16d8-6008
 create mode 100644 package/network/utils/wwan/files/data/16d8-6522
 create mode 100644 package/network/utils/wwan/files/data/16d8-6523
 create mode 100644 package/network/utils/wwan/files/data/16d8-6532
 create mode 100644 package/network/utils/wwan/files/data/16d8-6533
 create mode 100644 package/network/utils/wwan/files/data/16d8-6543
 create mode 100644 package/network/utils/wwan/files/data/16d8-680a
 create mode 100644 package/network/utils/wwan/files/data/19d2-0001
 create mode 100644 package/network/utils/wwan/files/data/19d2-0002
 create mode 100644 package/network/utils/wwan/files/data/19d2-0015
 create mode 100644 package/network/utils/wwan/files/data/19d2-0016
 create mode 100644 package/network/utils/wwan/files/data/19d2-0017
 create mode 100644 package/network/utils/wwan/files/data/19d2-0018
 create mode 100644 package/network/utils/wwan/files/data/19d2-0019
 create mode 100644 package/network/utils/wwan/files/data/19d2-0022
 create mode 100644 package/network/utils/wwan/files/data/19d2-0024
 create mode 100644 package/network/utils/wwan/files/data/19d2-0025
 create mode 100644 package/network/utils/wwan/files/data/19d2-0031
 create mode 100644 package/network/utils/wwan/files/data/19d2-0033
 create mode 100644 package/network/utils/wwan/files/data/19d2-0037
 create mode 100644 package/network/utils/wwan/files/data/19d2-0039
 create mode 100644 package/network/utils/wwan/files/data/19d2-0042
 create mode 100644 package/network/utils/wwan/files/data/19d2-0052
 create mode 100644 package/network/utils/wwan/files/data/19d2-0055
 create mode 100644 package/network/utils/wwan/files/data/19d2-0057
 create mode 100644 package/network/utils/wwan/files/data/19d2-0063
 create mode 100644 package/network/utils/wwan/files/data/19d2-0064
 create mode 100644 package/network/utils/wwan/files/data/19d2-0066
 create mode 100644 package/network/utils/wwan/files/data/19d2-0073
 create mode 100644 package/network/utils/wwan/files/data/19d2-0079
 create mode 100644 package/network/utils/wwan/files/data/19d2-0082
 create mode 100644 package/network/utils/wwan/files/data/19d2-0086
 create mode 100644 package/network/utils/wwan/files/data/19d2-0091
 create mode 100644 package/network/utils/wwan/files/data/19d2-0094
 create mode 100644 package/network/utils/wwan/files/data/19d2-0104
 create mode 100644 package/network/utils/wwan/files/data/19d2-0108
 create mode 100644 package/network/utils/wwan/files/data/19d2-0116
 create mode 100644 package/network/utils/wwan/files/data/19d2-0117
 create mode 100644 package/network/utils/wwan/files/data/19d2-0121
 create mode 100644 package/network/utils/wwan/files/data/19d2-0124
 create mode 100644 package/network/utils/wwan/files/data/19d2-0128
 create mode 100644 package/network/utils/wwan/files/data/19d2-0142
 create mode 100644 package/network/utils/wwan/files/data/19d2-0143
 create mode 100644 package/network/utils/wwan/files/data/19d2-0152
 create mode 100644 package/network/utils/wwan/files/data/19d2-0157
 create mode 100644 package/network/utils/wwan/files/data/19d2-0167
 create mode 100644 package/network/utils/wwan/files/data/19d2-0170
 create mode 100644 package/network/utils/wwan/files/data/19d2-0199
 create mode 100644 package/network/utils/wwan/files/data/19d2-0257
 create mode 100644 package/network/utils/wwan/files/data/19d2-0265
 create mode 100644 package/network/utils/wwan/files/data/19d2-0284
 create mode 100644 package/network/utils/wwan/files/data/19d2-0326
 create mode 100644 package/network/utils/wwan/files/data/19d2-1003
 create mode 100644 package/network/utils/wwan/files/data/19d2-1008
 create mode 100644 package/network/utils/wwan/files/data/19d2-1010
 create mode 100644 package/network/utils/wwan/files/data/19d2-1015
 create mode 100644 package/network/utils/wwan/files/data/19d2-1018
 create mode 100644 package/network/utils/wwan/files/data/19d2-1172
 create mode 100644 package/network/utils/wwan/files/data/19d2-1173
 create mode 100644 package/network/utils/wwan/files/data/19d2-1176
 create mode 100644 package/network/utils/wwan/files/data/19d2-1177
 create mode 100644 package/network/utils/wwan/files/data/19d2-1181
 create mode 100644 package/network/utils/wwan/files/data/19d2-1203
 create mode 100644 package/network/utils/wwan/files/data/19d2-1208
 create mode 100644 package/network/utils/wwan/files/data/19d2-1211
 create mode 100644 package/network/utils/wwan/files/data/19d2-1212
 create mode 100644 package/network/utils/wwan/files/data/19d2-1217
 create mode 100644 package/network/utils/wwan/files/data/19d2-1218
 create mode 100644 package/network/utils/wwan/files/data/19d2-1220
 create mode 100644 package/network/utils/wwan/files/data/19d2-1222
 create mode 100644 package/network/utils/wwan/files/data/19d2-1245
 create mode 100644 package/network/utils/wwan/files/data/19d2-1252
 create mode 100644 package/network/utils/wwan/files/data/19d2-1254
 create mode 100644 package/network/utils/wwan/files/data/19d2-1256
 create mode 100644 package/network/utils/wwan/files/data/19d2-1270
 create mode 100644 package/network/utils/wwan/files/data/19d2-1401
 create mode 100644 package/network/utils/wwan/files/data/19d2-1402
 create mode 100644 package/network/utils/wwan/files/data/19d2-1426
 create mode 100644 package/network/utils/wwan/files/data/19d2-1512
 create mode 100644 package/network/utils/wwan/files/data/19d2-1515
 create mode 100644 package/network/utils/wwan/files/data/19d2-1518
 create mode 100644 package/network/utils/wwan/files/data/19d2-1519
 create mode 100644 package/network/utils/wwan/files/data/19d2-1522
 create mode 100644 package/network/utils/wwan/files/data/19d2-1525
 create mode 100644 package/network/utils/wwan/files/data/19d2-1527
 create mode 100644 package/network/utils/wwan/files/data/19d2-1537
 create mode 100644 package/network/utils/wwan/files/data/19d2-1538
 create mode 100644 package/network/utils/wwan/files/data/19d2-1544
 create mode 100644 package/network/utils/wwan/files/data/19d2-2002
 create mode 100644 package/network/utils/wwan/files/data/19d2-2003
 create mode 100644 package/network/utils/wwan/files/data/19d2-ffdd
 create mode 100644 package/network/utils/wwan/files/data/19d2-ffe4
 create mode 100644 package/network/utils/wwan/files/data/19d2-ffe9
 create mode 100644 package/network/utils/wwan/files/data/19d2-fff1
 create mode 100644 package/network/utils/wwan/files/data/19d2-fffb
 create mode 100644 package/network/utils/wwan/files/data/19d2-fffc
 create mode 100644 package/network/utils/wwan/files/data/19d2-fffd
 create mode 100644 package/network/utils/wwan/files/data/19d2-fffe
 create mode 100644 package/network/utils/wwan/files/data/19d2-ffff
 create mode 100644 package/network/utils/wwan/files/data/1a8d-1002
 create mode 100644 package/network/utils/wwan/files/data/1a8d-1003
 create mode 100644 package/network/utils/wwan/files/data/1a8d-1007
 create mode 100644 package/network/utils/wwan/files/data/1a8d-1009
 create mode 100644 package/network/utils/wwan/files/data/1a8d-100c
 create mode 100644 package/network/utils/wwan/files/data/1a8d-100d
 create mode 100644 package/network/utils/wwan/files/data/1a8d-2006
 create mode 100644 package/network/utils/wwan/files/data/1bbb-0000
 create mode 100644 package/network/utils/wwan/files/data/1bbb-0012
 create mode 100644 package/network/utils/wwan/files/data/1bbb-0017
 create mode 100644 package/network/utils/wwan/files/data/1bbb-0052
 create mode 100644 package/network/utils/wwan/files/data/1bbb-00b7
 create mode 100644 package/network/utils/wwan/files/data/1bbb-00ca
 create mode 100644 package/network/utils/wwan/files/data/1bbb-011e
 create mode 100644 package/network/utils/wwan/files/data/1bbb-0203
 create mode 100644 package/network/utils/wwan/files/data/1c9e-6060
 create mode 100644 package/network/utils/wwan/files/data/1c9e-6061
 create mode 100644 package/network/utils/wwan/files/data/1c9e-9000
 create mode 100644 package/network/utils/wwan/files/data/1c9e-9603
 create mode 100644 package/network/utils/wwan/files/data/1c9e-9605
 create mode 100644 package/network/utils/wwan/files/data/1c9e-9607
 create mode 100644 package/network/utils/wwan/files/data/1c9e-9801
 create mode 100644 package/network/utils/wwan/files/data/1c9e-9900
 create mode 100644 package/network/utils/wwan/files/data/1e0e-9000
 create mode 100644 package/network/utils/wwan/files/data/1e0e-9100
 create mode 100644 package/network/utils/wwan/files/data/1e0e-9200
 create mode 100644 package/network/utils/wwan/files/data/1e0e-ce16
 create mode 100644 package/network/utils/wwan/files/data/1e0e-cefe
 create mode 100644 package/network/utils/wwan/files/data/2001-7d00
 create mode 100644 package/network/utils/wwan/files/data/2001-7d01
 create mode 100644 package/network/utils/wwan/files/data/2001-7d02
 create mode 100644 package/network/utils/wwan/files/data/2001-7d03
 create mode 100644 package/network/utils/wwan/files/data/211f-6801
 create mode 100644 package/network/utils/wwan/files/data/2357-0201
 create mode 100644 package/network/utils/wwan/files/data/2357-0202
 create mode 100644 package/network/utils/wwan/files/data/2357-0203
 create mode 100644 package/network/utils/wwan/files/data/2357-9000
 create mode 100644 package/network/utils/wwan/files/data/413c-8114
 create mode 100644 package/network/utils/wwan/files/data/413c-8115
 create mode 100644 package/network/utils/wwan/files/data/413c-8116
 create mode 100644 package/network/utils/wwan/files/data/413c-8117
 create mode 100644 package/network/utils/wwan/files/data/413c-8118
 create mode 100644 package/network/utils/wwan/files/data/413c-8128
 create mode 100644 package/network/utils/wwan/files/data/413c-8129
 create mode 100644 package/network/utils/wwan/files/data/413c-8133
 create mode 100644 package/network/utils/wwan/files/data/413c-8134
 create mode 100644 package/network/utils/wwan/files/data/413c-8135
 create mode 100644 package/network/utils/wwan/files/data/413c-8136
 create mode 100644 package/network/utils/wwan/files/data/413c-8137
 create mode 100644 package/network/utils/wwan/files/data/413c-8138
 create mode 100644 package/network/utils/wwan/files/data/413c-8147
 create mode 100644 package/network/utils/wwan/files/data/413c-8180
 create mode 100644 package/network/utils/wwan/files/data/413c-8181
 create mode 100644 package/network/utils/wwan/files/data/413c-8182
 create mode 100644 package/network/utils/wwan/files/data/413c-8186
 create mode 100644 package/network/utils/wwan/files/data/413c-8194
 create mode 100644 package/network/utils/wwan/files/data/413c-8195
 create mode 100644 package/network/utils/wwan/files/data/413c-8196
 create mode 100644 package/network/utils/wwan/files/data/413c-819b
 create mode 100755 package/network/utils/wwan/files/wwan.sh
 create mode 100644 package/network/utils/wwan/files/wwan.usb
 create mode 100644 package/network/utils/wwan/files/wwan.usbmisc
 create mode 100644 package/network/utils/xtables-addons/Makefile
 create mode 100644 package/network/utils/xtables-addons/patches/002-fix-kernel-version-detection.patch
 create mode 100644 package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
 create mode 100644 package/network/utils/xtables-addons/patches/200-add-lua-packetscript.patch
 create mode 100644 package/network/utils/xtables-addons/patches/201-fix-lua-packetscript.patch
 create mode 100644 package/network/utils/xtables-addons/patches/300-geoip-endian-detection.patch
 create mode 100644 package/system/ca-certificates/Makefile
 create mode 100644 package/system/fstools/Makefile
 create mode 100644 package/system/fstools/files/fstab.default
 create mode 100644 package/system/fstools/files/fstab.init
 create mode 100644 package/system/fstools/files/mount.hotplug
 create mode 100644 package/system/fstools/files/snapshot
 create mode 100644 package/system/fwtool/Makefile
 create mode 100644 package/system/fwtool/src/crc32.h
 create mode 100644 package/system/fwtool/src/fwimage.h
 create mode 100644 package/system/fwtool/src/fwtool.c
 create mode 100644 package/system/fwtool/src/utils.h
 create mode 100644 package/system/lede-keyring/Makefile
 create mode 100644 package/system/mountd/Makefile
 create mode 100644 package/system/mountd/files/mountd.config
 create mode 100755 package/system/mountd/files/mountd.init
 create mode 100644 package/system/mtd/Makefile
 create mode 100644 package/system/mtd/src/Makefile
 create mode 100644 package/system/mtd/src/crc32.c
 create mode 100644 package/system/mtd/src/crc32.h
 create mode 100644 package/system/mtd/src/fis.c
 create mode 100644 package/system/mtd/src/fis.h
 create mode 100644 package/system/mtd/src/imagetag.c
 create mode 100644 package/system/mtd/src/jffs2.c
 create mode 100644 package/system/mtd/src/jffs2.h
 create mode 100644 package/system/mtd/src/linksys_bootcount.c
 create mode 100644 package/system/mtd/src/md5.c
 create mode 100644 package/system/mtd/src/md5.h
 create mode 100644 package/system/mtd/src/mtd.c
 create mode 100644 package/system/mtd/src/mtd.h
 create mode 100644 package/system/mtd/src/seama.c
 create mode 100644 package/system/mtd/src/seama.h
 create mode 100644 package/system/mtd/src/trx.c
 create mode 100644 package/system/mtd/src/wrgg.c
 create mode 100644 package/system/mtd/src/wrgg.h
 create mode 100644 package/system/opkg/Makefile
 create mode 100644 package/system/opkg/files/20_migrate-feeds
 create mode 100644 package/system/opkg/files/customfeeds.conf
 create mode 100755 package/system/opkg/files/opkg-key
 create mode 100644 package/system/opkg/files/opkg-smime.conf
 create mode 100644 package/system/opkg/files/opkg.conf
 create mode 100644 package/system/opkg/patches/001-ship-pkg-m4.patch
 create mode 100644 package/system/opkg/patches/002-no-shave.patch
 create mode 100644 package/system/opkg/patches/004-host_cpu.patch
 create mode 100644 package/system/opkg/patches/007-force_static.patch
 create mode 100644 package/system/opkg/patches/009-remove-upgrade-all.patch
 create mode 100644 package/system/opkg/patches/011-old-config-location.patch
 create mode 100644 package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch
 create mode 100644 package/system/opkg/patches/014-errors-to-stderr.patch
 create mode 100644 package/system/opkg/patches/020-avoid_getline.patch
 create mode 100644 package/system/opkg/patches/030-fix-double-free.patch
 create mode 100644 package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch
 create mode 100644 package/system/opkg/patches/050-add-case-insensitive-flag.patch
 create mode 100644 package/system/opkg/patches/060-add-find-command.patch
 create mode 100644 package/system/opkg/patches/070-use_gzipped_pkg_list.patch
 create mode 100644 package/system/opkg/patches/080-suppress-blank-package-fields.patch
 create mode 100644 package/system/opkg/patches/090-suppress-blank-provides-field.patch
 create mode 100644 package/system/opkg/patches/100-add-force-checksum.patch
 create mode 100644 package/system/opkg/patches/110-upgrade.patch
 create mode 100644 package/system/opkg/patches/200-usign_support.patch
 create mode 100644 package/system/opkg/patches/210-add-force-signature.patch
 create mode 100644 package/system/opkg/patches/220-drop-release-support.patch
 create mode 100644 package/system/opkg/patches/230-drop_md5_support.patch
 create mode 100644 package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch
 create mode 100644 package/system/opkg/patches/250-add-lists-dir-switch.patch
 create mode 100644 package/system/opkg/patches/260-add-print-package-size.patch
 create mode 100644 package/system/opkg/patches/270-fix-use-after-free.patch
 create mode 100644 package/system/opkg/patches/280-call-prerm-and-postrm-scripts-on-upgrade.patch
 create mode 100644 package/system/procd/Makefile
 create mode 100644 package/system/procd/files/hotplug-preinit.json
 create mode 100644 package/system/procd/files/hotplug.json
 create mode 100644 package/system/procd/files/nand-preinit.sh
 create mode 100644 package/system/procd/files/nand.sh
 create mode 100644 package/system/procd/files/procd.sh
 create mode 100644 package/system/procd/files/reload_config
 create mode 100644 package/system/rpcd/Makefile
 create mode 100644 package/system/rpcd/files/rpcd.config
 create mode 100755 package/system/rpcd/files/rpcd.init
 create mode 100644 package/system/ubox/Makefile
 create mode 100644 package/system/ubox/files/log.init
 create mode 100644 package/system/ubus/Makefile
 create mode 100644 package/system/uci/Makefile
 create mode 100644 package/system/uci/files/lib/config/uci.sh
 create mode 100644 package/system/usign/Makefile
 create mode 100644 package/system/zram-swap/Makefile
 create mode 100644 package/system/zram-swap/files/zram.init
 create mode 100644 package/utils/admswconfig/Makefile
 create mode 100644 package/utils/admswconfig/files/admswconfig
 create mode 100644 package/utils/admswconfig/files/admswswitch.sh
 create mode 100644 package/utils/admswconfig/patches/001-matrix.patch
 create mode 100644 package/utils/admswconfig/patches/002-fix-musl.patch
 create mode 100644 package/utils/bsdiff/Makefile
 create mode 100644 package/utils/bsdiff/patches/001-musl.patch
 create mode 100644 package/utils/busybox/Config-defaults.in
 create mode 100644 package/utils/busybox/Config.in
 create mode 100644 package/utils/busybox/Makefile
 create mode 100644 package/utils/busybox/config/Config.in
 create mode 100644 package/utils/busybox/config/archival/Config.in
 create mode 100644 package/utils/busybox/config/console-tools/Config.in
 create mode 100644 package/utils/busybox/config/coreutils/Config.in
 create mode 100644 package/utils/busybox/config/debianutils/Config.in
 create mode 100644 package/utils/busybox/config/e2fsprogs/Config.in
 create mode 100644 package/utils/busybox/config/e2fsprogs/old_e2fsprogs/Config.in
 create mode 100644 package/utils/busybox/config/editors/Config.in
 create mode 100644 package/utils/busybox/config/findutils/Config.in
 create mode 100644 package/utils/busybox/config/init/Config.in
 create mode 100644 package/utils/busybox/config/libbb/Config.in
 create mode 100644 package/utils/busybox/config/loginutils/Config.in
 create mode 100644 package/utils/busybox/config/mailutils/Config.in
 create mode 100644 package/utils/busybox/config/miscutils/Config.in
 create mode 100644 package/utils/busybox/config/modutils/Config.in
 create mode 100644 package/utils/busybox/config/networking/Config.in
 create mode 100644 package/utils/busybox/config/networking/udhcp/Config.in
 create mode 100644 package/utils/busybox/config/printutils/Config.in
 create mode 100644 package/utils/busybox/config/procps/Config.in
 create mode 100644 package/utils/busybox/config/runit/Config.in
 create mode 100644 package/utils/busybox/config/selinux/Config.in
 create mode 100644 package/utils/busybox/config/shell/Config.in
 create mode 100644 package/utils/busybox/config/sysklogd/Config.in
 create mode 100644 package/utils/busybox/config/util-linux/Config.in
 create mode 100644 package/utils/busybox/config/util-linux/volume_id/Config.in
 create mode 100755 package/utils/busybox/convert_defaults.pl
 create mode 100755 package/utils/busybox/convert_menuconfig.pl
 create mode 100755 package/utils/busybox/files/cron
 create mode 100755 package/utils/busybox/files/ntpd-hotplug
 create mode 100755 package/utils/busybox/files/sysntpd
 create mode 100644 package/utils/busybox/patches/001-resource_h_include.patch
 create mode 100644 package/utils/busybox/patches/002-libbb-send_to_from-do-not-require-that-to-should-hav.patch
 create mode 100644 package/utils/busybox/patches/100-trylink_bash.patch
 create mode 100644 package/utils/busybox/patches/101-gen_build_files_bash.patch
 create mode 100644 package/utils/busybox/patches/102-trylink_mktemp_fix.patch
 create mode 100644 package/utils/busybox/patches/110-no_static_libgcc.patch
 create mode 100644 package/utils/busybox/patches/120-remove_uclibc_rpc_check.patch
 create mode 100644 package/utils/busybox/patches/130-mconf_missing_sigwinch.patch
 create mode 100644 package/utils/busybox/patches/200-udhcpc_reduce_msgs.patch
 create mode 100644 package/utils/busybox/patches/201-udhcpc_changed_ifindex.patch
 create mode 100644 package/utils/busybox/patches/203-udhcpc_renew_no_deconfig.patch
 create mode 100644 package/utils/busybox/patches/210-add_netmsg_util.patch
 create mode 100644 package/utils/busybox/patches/220-add_lock_util.patch
 create mode 100644 package/utils/busybox/patches/240-telnetd_intr.patch
 create mode 100644 package/utils/busybox/patches/250-date-k-flag.patch
 create mode 100644 package/utils/busybox/patches/270-libbb_make_unicode_printable.patch
 create mode 100644 package/utils/busybox/patches/301-ip-link-fix-netlink-msg-size.patch
 create mode 100644 package/utils/busybox/patches/302-netlink-alignment.patch
 create mode 100644 package/utils/busybox/patches/303-ip-route-fix-high-table-ids.patch
 create mode 100644 package/utils/bzip2/Makefile
 create mode 100644 package/utils/e2fsprogs/Makefile
 create mode 100644 package/utils/e2fsprogs/files/e2fsck.conf
 create mode 100644 package/utils/e2fsprogs/files/e2fsck.sh
 create mode 100644 package/utils/e2fsprogs/patches/001-com_err_version.patch
 create mode 100644 package/utils/e2fsprogs/patches/002-fix-subst-host-build.patch
 create mode 100644 package/utils/f2fs-tools/Makefile
 create mode 100644 package/utils/f2fs-tools/patches/001-compile.patch
 create mode 100644 package/utils/f2fs-tools/patches/010-include-byteswap-h.patch
 create mode 100644 package/utils/f2fs-tools/patches/020-no_selinux.patch
 create mode 100644 package/utils/fbtest/Makefile
 create mode 100644 package/utils/fbtest/src/Makefile
 create mode 100644 package/utils/fbtest/src/fbtest.c
 create mode 100644 package/utils/fuse/Makefile
 create mode 100644 package/utils/fuse/patches/100-missing_includes.patch
 create mode 100644 package/utils/fuse/patches/112-no_break_on_mknod.patch
 create mode 100644 package/utils/fuse/patches/200-backport_arm64_fuse_kernel_h_clean_includes.patch
 create mode 100644 package/utils/jsonfilter/Makefile
 create mode 100644 package/utils/lua/Makefile
 create mode 100644 package/utils/lua/patches-host/010-lua-5.1.3-lnum-full-260308.patch
 create mode 100644 package/utils/lua/patches-host/011-lnum-use-double.patch
 create mode 100644 package/utils/lua/patches-host/012-lnum-fix-ltle-relational-operators.patch
 create mode 100644 package/utils/lua/patches-host/015-lnum-ppc-compat.patch
 create mode 100644 package/utils/lua/patches-host/030-archindependent-bytecode.patch
 create mode 100644 package/utils/lua/patches-host/100-no_readline.patch
 create mode 100644 package/utils/lua/patches/010-lua-5.1.3-lnum-full-260308.patch
 create mode 100644 package/utils/lua/patches/011-lnum-use-double.patch
 create mode 100644 package/utils/lua/patches/012-lnum-fix-ltle-relational-operators.patch
 create mode 100644 package/utils/lua/patches/015-lnum-ppc-compat.patch
 create mode 100644 package/utils/lua/patches/020-shared_liblua.patch
 create mode 100644 package/utils/lua/patches/030-archindependent-bytecode.patch
 create mode 100644 package/utils/lua/patches/040-use-symbolic-functions.patch
 create mode 100644 package/utils/lua/patches/050-honor-cflags.patch
 create mode 100644 package/utils/lua/patches/100-no_readline.patch
 create mode 100644 package/utils/lua/patches/200-lua-path.patch
 create mode 100644 package/utils/lua/patches/300-opcode_performance.patch
 create mode 100644 package/utils/mdadm/Makefile
 create mode 100644 package/utils/mdadm/files/mdadm.config
 create mode 100644 package/utils/mdadm/files/mdadm.init
 create mode 100644 package/utils/mdadm/patches/000-compile.patch
 create mode 100644 package/utils/mdadm/patches/100-cross_compile.patch
 create mode 100644 package/utils/mdadm/patches/200-reduce_size.patch
 create mode 100644 package/utils/mtd-utils/Makefile
 create mode 100644 package/utils/mtd-utils/patches/010-fix-rpmatch.patch
 create mode 100644 package/utils/mtd-utils/patches/100-fix_includes.patch
 create mode 100644 package/utils/mtd-utils/patches/130-lzma_jffs2.patch
 create mode 100644 package/utils/nvram/Makefile
 create mode 100755 package/utils/nvram/files/nvram.init
 create mode 100644 package/utils/nvram/src/Makefile
 create mode 100644 package/utils/nvram/src/cli.c
 create mode 100644 package/utils/nvram/src/crc.c
 create mode 100644 package/utils/nvram/src/nvram.c
 create mode 100644 package/utils/nvram/src/nvram.h
 create mode 100644 package/utils/nvram/src/sdinitvals.h
 create mode 100644 package/utils/osafeloader/Makefile
 create mode 100644 package/utils/osafeloader/src/Makefile
 create mode 100644 package/utils/osafeloader/src/md5.c
 create mode 100644 package/utils/osafeloader/src/md5.h
 create mode 100644 package/utils/osafeloader/src/osafeloader.c
 create mode 100644 package/utils/oseama/Makefile
 create mode 100644 package/utils/oseama/src/Makefile
 create mode 100644 package/utils/oseama/src/md5.c
 create mode 100644 package/utils/oseama/src/md5.h
 create mode 100644 package/utils/oseama/src/oseama.c
 create mode 100644 package/utils/otrx/Makefile
 create mode 100644 package/utils/otrx/src/Makefile
 create mode 100644 package/utils/otrx/src/otrx.c
 create mode 100644 package/utils/px5g-standalone/Makefile
 create mode 100644 package/utils/px5g-standalone/src/Makefile
 create mode 100644 package/utils/px5g-standalone/src/library/base64.c
 create mode 100644 package/utils/px5g-standalone/src/library/bignum.c
 create mode 100644 package/utils/px5g-standalone/src/library/rsa.c
 create mode 100644 package/utils/px5g-standalone/src/library/sha1.c
 create mode 100644 package/utils/px5g-standalone/src/library/timing.c
 create mode 100644 package/utils/px5g-standalone/src/library/x509write.c
 create mode 100644 package/utils/px5g-standalone/src/polarssl/base64.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/bignum.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/bn_mul.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/config.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/rsa.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/sha1.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/timing.h
 create mode 100644 package/utils/px5g-standalone/src/polarssl/x509.h
 create mode 100644 package/utils/px5g-standalone/src/px5g.c
 create mode 100644 package/utils/px5g/Makefile
 create mode 100644 package/utils/px5g/px5g.c
 create mode 100644 package/utils/spidev_test/Makefile
 create mode 100644 package/utils/spidev_test/src/spidev_test.c
 create mode 100644 package/utils/ugps/Makefile
 create mode 100644 package/utils/ugps/files/gps.config
 create mode 100644 package/utils/ugps/files/ugps.init
 create mode 100644 package/utils/usbmode/Makefile
 create mode 100644 package/utils/usbmode/data/12d1-1f16
 create mode 100644 package/utils/usbmode/files/usbmode.hotplug
 create mode 100755 package/utils/usbmode/files/usbmode.init
 create mode 100644 package/utils/usbreset/Makefile
 create mode 100644 package/utils/usbreset/src/usbreset.c
 create mode 100644 package/utils/usbutils/Makefile
 create mode 100644 package/utils/util-linux/Makefile
 create mode 100644 package/utils/util-linux/patches/0001-fix-uClibc-ng-scanf-check.patch
 create mode 100644 package/utils/util-linux/patches/003-fix_pkgconfig_files.patch
 create mode 100644 package/utils/xfsprogs/Makefile
 create mode 100644 package/utils/xfsprogs/patches/001-automake-compat.patch
 create mode 100644 package/utils/xfsprogs/patches/100-no_aio.patch
 create mode 100644 package/utils/xfsprogs/patches/110-uclibc_no_ustat.patch
 create mode 100644 package/utils/xfsprogs/patches/120-portability.patch
 create mode 100644 package/utils/xfsprogs/patches/130-uclibc_no_xattr.patch
 create mode 100644 package/utils/xfsprogs/patches/140-no_po.patch
 create mode 100644 package/utils/xfsprogs/patches/150-include_fixes.patch
 create mode 100644 package/utils/xfsprogs/patches/160-format-security.patch
 create mode 100644 rules.mk
 create mode 100755 scripts/arm-magic.sh
 create mode 100755 scripts/brcmImage.pl
 create mode 100755 scripts/bundle-libraries.sh
 create mode 100755 scripts/checkpatch.pl
 create mode 100755 scripts/clang-gcc-wrapper
 create mode 100755 scripts/clean-package.sh
 create mode 100755 scripts/cleanfile
 create mode 100755 scripts/cleanpatch
 create mode 100755 scripts/combined-ext-image.sh
 create mode 100644 scripts/combined-image.sh
 create mode 100755 scripts/config.guess
 create mode 100755 scripts/config.rpath
 create mode 100755 scripts/config.sub
 create mode 100644 scripts/config/.gitignore
 create mode 100644 scripts/config/Makefile
 create mode 100644 scripts/config/README
 create mode 100644 scripts/config/conf.c
 create mode 100644 scripts/config/confdata.c
 create mode 100644 scripts/config/expr.c
 create mode 100644 scripts/config/expr.h
 create mode 100644 scripts/config/list.h
 create mode 100644 scripts/config/lkc.h
 create mode 100644 scripts/config/lkc_proto.h
 create mode 100644 scripts/config/lxdialog/.gitignore
 create mode 100644 scripts/config/lxdialog/check-lxdialog.sh
 create mode 100644 scripts/config/lxdialog/checklist.c
 create mode 100644 scripts/config/lxdialog/dialog.h
 create mode 100644 scripts/config/lxdialog/inputbox.c
 create mode 100644 scripts/config/lxdialog/menubox.c
 create mode 100644 scripts/config/lxdialog/textbox.c
 create mode 100644 scripts/config/lxdialog/util.c
 create mode 100644 scripts/config/lxdialog/yesno.c
 create mode 100644 scripts/config/mconf.c
 create mode 100644 scripts/config/menu.c
 create mode 100644 scripts/config/symbol.c
 create mode 100644 scripts/config/util.c
 create mode 100644 scripts/config/zconf.gperf
 create mode 100644 scripts/config/zconf.hash.c_shipped
 create mode 100644 scripts/config/zconf.l
 create mode 100644 scripts/config/zconf.lex.c_shipped
 create mode 100644 scripts/config/zconf.tab.c_shipped
 create mode 100644 scripts/config/zconf.y
 create mode 100755 scripts/deptest.sh
 create mode 100755 scripts/diffconfig.sh
 create mode 100755 scripts/dl_cleanup.py
 create mode 100755 scripts/download.pl
 create mode 100755 scripts/env
 create mode 100755 scripts/ext-toolchain.sh
 create mode 100755 scripts/feeds
 create mode 100755 scripts/flashing/adam2flash-502T.pl
 create mode 100755 scripts/flashing/adam2flash-fritzbox.pl
 create mode 100755 scripts/flashing/adam2flash.pl
 create mode 100755 scripts/flashing/adsl2mue_flash.pl
 create mode 100755 scripts/flashing/flash.sh
 create mode 100755 scripts/flashing/jungo-image.py
 create mode 100755 scripts/gen-dependencies.sh
 create mode 100755 scripts/get_source_date_epoch.sh
 create mode 100755 scripts/getver.sh
 create mode 100755 scripts/ipkg-build
 create mode 100755 scripts/ipkg-make-index.sh
 create mode 100755 scripts/kconfig.pl
 create mode 100755 scripts/make-ipkg-dir.sh
 create mode 100755 scripts/md5sum
 create mode 100644 scripts/metadata.pm
 create mode 100755 scripts/mkits.sh
 create mode 100644 scripts/om-fwupgradecfg-gen.sh
 create mode 100644 scripts/openbsd.sh
 create mode 100755 scripts/package-metadata.pl
 create mode 100755 scripts/pad_image
 create mode 100755 scripts/patch-kernel.sh
 create mode 100755 scripts/patch-specs.sh
 create mode 100755 scripts/portable_date.sh
 create mode 100755 scripts/redboot-script.pl
 create mode 100755 scripts/relink-lib.sh
 create mode 100755 scripts/remote-gdb
 create mode 100755 scripts/rstrip.sh
 create mode 100755 scripts/slugimage.pl
 create mode 100755 scripts/srecimage.pl
 create mode 100755 scripts/strip-kmod.sh
 create mode 100755 scripts/symlink-tree.sh
 create mode 100755 scripts/sysupgrade-tar.sh
 create mode 100755 scripts/target-metadata.pl
 create mode 100755 scripts/timestamp.pl
 create mode 100755 scripts/ubinize-image.sh
 create mode 100755 scripts/update-package-md5sum
 create mode 100644 target/Config.in
 create mode 100644 target/Makefile
 create mode 100644 target/imagebuilder/Config.in
 create mode 100644 target/imagebuilder/Makefile
 create mode 100644 target/imagebuilder/files/Makefile
 create mode 100644 target/imagebuilder/files/repositories.conf
 create mode 100644 target/linux/Makefile
 create mode 100644 target/linux/ar71xx/Makefile
 create mode 100755 target/linux/ar71xx/base-files/etc/board.d/01_leds
 create mode 100755 target/linux/ar71xx/base-files/etc/board.d/02_network
 create mode 100755 target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches
 create mode 100644 target/linux/ar71xx/base-files/etc/diag.sh
 create mode 100644 target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
 create mode 100644 target/linux/ar71xx/base-files/etc/hotplug.d/net/10-ar922x-led-fix
 create mode 100644 target/linux/ar71xx/base-files/etc/inittab
 create mode 100644 target/linux/ar71xx/base-files/etc/uci-defaults/03_network-switchX-migration
 create mode 100644 target/linux/ar71xx/base-files/etc/uci-defaults/03_network-vlan-migration
 create mode 100644 target/linux/ar71xx/base-files/etc/uci-defaults/04_led_migration
 create mode 100644 target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-checksum
 create mode 100644 target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-seama-header
 create mode 100755 target/linux/ar71xx/base-files/lib/ar71xx.sh
 create mode 100644 target/linux/ar71xx/base-files/lib/preinit/03_preinit_do_ar71xx.sh
 create mode 100644 target/linux/ar71xx/base-files/lib/preinit/05_set_iface_mac_ar71xx
 create mode 100644 target/linux/ar71xx/base-files/lib/preinit/05_set_preinit_iface_ar71xx
 create mode 100644 target/linux/ar71xx/base-files/lib/upgrade/allnet.sh
 create mode 100644 target/linux/ar71xx/base-files/lib/upgrade/dir825.sh
 create mode 100644 target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh
 create mode 100644 target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh
 create mode 100755 target/linux/ar71xx/base-files/lib/upgrade/platform.sh
 create mode 100755 target/linux/ar71xx/base-files/sbin/wget2nand
 create mode 100644 target/linux/ar71xx/config-4.4
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/Makefile
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap120c.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap96.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-nx.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-all0258n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-all0315n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s3.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-antrouter-r1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap113.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap132.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap143.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap147.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap152.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap83.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap90q.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ap96.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-arduino-yun.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-aw-nr580.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-bhr-4grv2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-bhu-bxu2000n2-a.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-bsb.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-c55.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-c60.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cap324.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cap4200ag.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-carambola2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cf-e316n-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cpe870.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cr3000.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-cr5000.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dap-2695-a1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dgl-5500-a1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dhp-1565-a1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-505-a1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-600-a1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-c1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-i1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-b1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-c1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dir-869-a1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-hotspot.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-1200-ac.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-500-wp.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-domywifi-dw33d.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dr344.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dr531.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-dragino2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-eap120.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-eap300v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-eap7660d.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-el-m150.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-el-mini.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-epg5000.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-esr1750.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-esr900.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ew-dorin.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-f9k1115v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar150.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300m.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gl-domino.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gl-inet.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gl-mifi.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gs-minibox-v1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-gs-oolite.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-hiwifi-hc6361.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-hornet-ub.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ja76pf.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-jwap003.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-jwap230.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mc-mac1200r.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mr12.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mr16.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mr600.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mr900.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n600.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n750.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-rext.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w04nu.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w300nh.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-nbg460n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-nbg6716.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-om5p.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-om5pac.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-om5pacv2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-omy-g1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-omy-x1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-onion-omega.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-pb42.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-pb92.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-qihoo-c301.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-r6100.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rb2011.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rb4xx.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rb750.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rb922.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rb95x.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rbsxtlite.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-rw2458n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-smart-300.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tellstick-znet-lite.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tew-632brp.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tew-673gru.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tew-712br.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tew-732br.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tew-823dru.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr11u.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr13u.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa701nd-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa7210n-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa801nd-v3.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa830re-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v4.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wax50re.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3320-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3500.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr4300.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr6500-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wpa8630.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1041n-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd-v2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr2543n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr703n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr720n-v3.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd-v4.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr810n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v8.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd-v6.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-tube2h.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-weio.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wlae-ag300n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wlr8100.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wndap360.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wndr3700.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wndr4300.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v3.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v4.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2200.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wp543.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wpe72.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wpj342.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wpj344.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wpj531.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wpj558.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wrt160nl.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wrt400n.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-450hp2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-ag300h.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh2.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g450h.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-z1.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-zbt-we1526.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/mach-zcn-1523h.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/nvram.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/nvram.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/routerboot.c
 create mode 100644 target/linux/ar71xx/files/arch/mips/ath79/routerboot.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/include/asm/fw/myloader/myloader.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/mach-rb750.h
 create mode 100644 target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
 create mode 100644 target/linux/ar71xx/files/drivers/gpio/gpio-latch.c
 create mode 100644 target/linux/ar71xx/files/drivers/gpio/gpio-nxp-74hc153.c
 create mode 100644 target/linux/ar71xx/files/drivers/leds/leds-nu801.c
 create mode 100644 target/linux/ar71xx/files/drivers/leds/leds-rb750.c
 create mode 100644 target/linux/ar71xx/files/drivers/leds/leds-wndr3700-usb.c
 create mode 100644 target/linux/ar71xx/files/drivers/mtd/cybertan_part.c
 create mode 100644 target/linux/ar71xx/files/drivers/mtd/nand/ar934x_nfc.c
 create mode 100644 target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c
 create mode 100644 target/linux/ar71xx/files/drivers/mtd/nand/rb750_nand.c
 create mode 100644 target/linux/ar71xx/files/drivers/mtd/nand/rb91x_nand.c
 create mode 100644 target/linux/ar71xx/files/drivers/mtd/tplinkpart.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/dsa/mv88e6063.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Kconfig
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Makefile
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
 create mode 100644 target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c
 create mode 100644 target/linux/ar71xx/files/drivers/spi/spi-ap83.c
 create mode 100644 target/linux/ar71xx/files/drivers/spi/spi-rb4xx-cpld.c
 create mode 100644 target/linux/ar71xx/files/drivers/spi/spi-rb4xx.c
 create mode 100644 target/linux/ar71xx/files/drivers/spi/spi-vsc7385.c
 create mode 100644 target/linux/ar71xx/files/include/linux/leds-nu801.h
 create mode 100644 target/linux/ar71xx/files/include/linux/nxp_74hc153.h
 create mode 100644 target/linux/ar71xx/files/include/linux/platform/ar934x_nfc.h
 create mode 100644 target/linux/ar71xx/files/include/linux/platform_data/gpio-latch.h
 create mode 100644 target/linux/ar71xx/files/include/linux/platform_data/rb91x_nand.h
 create mode 100644 target/linux/ar71xx/files/include/linux/spi/vsc7385.h
 create mode 100644 target/linux/ar71xx/files/net/dsa/mv88e6063.c
 create mode 100644 target/linux/ar71xx/generic/config-default
 create mode 100644 target/linux/ar71xx/generic/profiles/00-default.mk
 create mode 100644 target/linux/ar71xx/generic/target.mk
 create mode 100644 target/linux/ar71xx/image/Makefile
 create mode 100644 target/linux/ar71xx/image/generic.mk
 create mode 100644 target/linux/ar71xx/image/legacy-devices.mk
 create mode 100644 target/linux/ar71xx/image/legacy.mk
 create mode 100644 target/linux/ar71xx/image/lzma-loader/Makefile
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.c
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/LzmaTypes.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/Makefile
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/ar71xx_regs.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/board.c
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/cache.c
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/cache.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/cacheops.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/config.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/cp0regdef.h
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/head.S
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/loader.c
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/loader.lds
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/loader2.lds
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/lzma-data.lds
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/printf.c
 create mode 100644 target/linux/ar71xx/image/lzma-loader/src/printf.h
 create mode 100644 target/linux/ar71xx/image/nand.mk
 create mode 100644 target/linux/ar71xx/image/tp-link.mk
 create mode 100644 target/linux/ar71xx/image/ubinize-nbg6716.ini
 create mode 100644 target/linux/ar71xx/image/ubinize-wndr4300.ini
 create mode 100644 target/linux/ar71xx/mikrotik/config-default
 create mode 100644 target/linux/ar71xx/mikrotik/profiles/01-minimal.mk
 create mode 100644 target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk
 create mode 100644 target/linux/ar71xx/mikrotik/target.mk
 create mode 100644 target/linux/ar71xx/modules.mk
 create mode 100644 target/linux/ar71xx/nand/config-default
 create mode 100644 target/linux/ar71xx/nand/profiles/00-default.mk
 create mode 100644 target/linux/ar71xx/nand/target.mk
 create mode 100644 target/linux/ar71xx/patches-4.4/001-revert_spi_device_tree_support.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/002-add_back_gpio_function_select.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/100-MIPS-ath79-Avoid-using-unitialized-reg-variable.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/200-MIPS-ath79-fix-ar933x-wmac-reset.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/201-ar913x_wmac_external_reset.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/202-MIPS-ath79-ar934x-wmac-revision.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/203-MIPS-ath79-fix-restart.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/206-spi-ath79-make-chipselect-logic-more-flexible.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/220-add_cpu_feature_overrides.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/300-MIPS-add-MIPS_MACHINE_NONAME-macro.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/310-lib-add-rle-decompression.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/401-mtd-physmap-add-lock-unlock.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/402-mtd-SST39VF6401B-support.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/403-mtd_fix_cfi_cmdset_0002_status_check.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/404-mtd-cybertan-trx-parser.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/405-mtd-tp-link-partition-parser.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/408-mtd-redboot_partition_scan.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/409-mtd-rb4xx_nand_driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/410-mtd-rb750-nand-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/411-mtd-cfi_cmdset_0002-force-word-write.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/413-mtd-ar934x-nand-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/414-mtd-rb91x-nand-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/420-net-ar71xx_mac_driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/423-dsa-add-88e6063-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/430-drivers-link-spi-before-mtd.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/432-spi-rb4xx-spi-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/433-spi-rb4xx-cpld-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/434-spi-ap83_spi_controller.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/435-spi-vsc7385_driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/440-leds-wndr3700-usb-led-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/441-leds-rb750-led-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/450-gpio-nxp-74hc153-gpio-chip-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/451-gpio-74x164-improve-platform-device-support.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/452-gpio-add-gpio-latch-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/470-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/490-usb-ehci-add-quirks-for-qca-socs.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/500-MIPS-fw-myloader.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/501-MIPS-ath79-add-mac-argument-to-ath79_register_wmac.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/503-MIPS-ath79-add-flash-acquire-release.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/504-MIPS-ath79-add-ath79_device_reset_get.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/505-MIPS-ath79-add-ath79_gpio_function_select.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/506-MIPS-ath79-prom-parse-redboot-args.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/507-MIPS-ath79-prom-add-myloader-support.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/508-MIPS-ath79-prom-image-command-line-hack.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/509-MIPS-ath79-process-board-kernel-option.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/510-MIPS-ath79-init-gpio-pin-of-wmac-device.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/520-MIPS-ath79-enable-UART-function.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/521-MIPS-ath79-enable-UART-for-early_serial.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/522-MIPS-ath79-add-ath79_wmac_register_simple-helper.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/523-MIPS-ath79-OTP-support.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/524-MIPS-ath79-add-ath79_wmac_disable_25ghz-helpers.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/525-MIPS-ath79-enable-qca-usb-quirks.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/601-MIPS-ath79-add-more-register-defines.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/602-MIPS-ath79-add-openwrt-stuff.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/603-MIPS-ath79-ap121-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/604-MIPS-ath79-ap81-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/605-MIPS-ath79-db120-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/606-MIPS-ath79-pb44-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/609-MIPS-ath79-ap136-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/611-MIPS-ath79-wdt-timeout.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/612-MIPS-ath79-set-buffalo-txgain.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/613-MIPS-ath79-add-ath79_wmac_setup_ext_lna_gpio-helper.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/615-MIPS-ath79-ap83-remove-mtd-partitions.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/621-MIPS-ath79-add-support-for-QCA956x-SoC.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/630-MIPS-ath79-fix-chained-irq-disable.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/631-MIPS-ath79-wmac-enable-set-led-pin.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/632-MIPS-ath79-gpio-enable-set-direction.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/634-MIPS-ath79-ar724x-clock-calculation-fixes.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/640-MIPS-ath79-add-QCA955x-wmac-reset.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/700-MIPS-ath79-add-openwrt-Kconfig.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/701-MIPS-ath79-add-routerboard-detection.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/739-MIPS-ath79-add-gpio-func-register-for-QCA955x-SoC.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/740-MIPS-ath79-add-PCI-for-QCA953x-SoC.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/818-MIPS-ath79-add-nu801-led-driver.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/820-MIPS-ath79-add_gpio_function2_setup.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/821-serial-core-add-support-for-boot-console-with-arbitr.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/900-mdio_bitbang_ignore_ta_value.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/901-phy-mdio-bitbang-prevent-rescheduling-during-command.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/902-at803x-add-reset-gpio-pdata.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch
 create mode 100644 target/linux/generic/PATCHES
 create mode 100755 target/linux/generic/base-files/init
 create mode 100644 target/linux/generic/config-3.18
 create mode 100644 target/linux/generic/config-4.1
 create mode 100644 target/linux/generic/config-4.4
 create mode 100644 target/linux/generic/files/Documentation/networking/adm6996.txt
 create mode 100644 target/linux/generic/files/arch/mips/fw/myloader/Makefile
 create mode 100644 target/linux/generic/files/arch/mips/fw/myloader/myloader.c
 create mode 100644 target/linux/generic/files/drivers/leds/ledtrig-netdev.c
 create mode 100644 target/linux/generic/files/drivers/misc/owl-loader.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
 create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
 create mode 100644 target/linux/generic/files/drivers/mtd/myloader.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/adm6996.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/adm6996.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/ar8216.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/ar8216.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/ar8327.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/ar8327.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/Kconfig
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/Makefile
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_common.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_regs.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_spi.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/b53/b53_srab.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/ip17xx.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/mvsw61xx.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/mvsw61xx.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/mvswitch.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/mvswitch.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/psb6970.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8306.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366rb.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8366s.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8367.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/rtl8367b.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/swconfig.c
 create mode 100644 target/linux/generic/files/drivers/net/phy/swconfig_leds.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/Kconfig
 create mode 100644 target/linux/generic/files/fs/yaffs2/Makefile
 create mode 100644 target/linux/generic/files/fs/yaffs2/NOTE.openwrt
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_allocator.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_allocator.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_attribs.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_ecc.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_ecc.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_guts.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_guts.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_linux.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nameval.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nameval.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nand.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_nand.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_summary.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_summary.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_trace.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_verify.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_verify.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_vfs.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c
 create mode 100644 target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h
 create mode 100644 target/linux/generic/files/fs/yaffs2/yportenv.h
 create mode 100644 target/linux/generic/files/include/linux/ar8216_platform.h
 create mode 100644 target/linux/generic/files/include/linux/ath5k_platform.h
 create mode 100644 target/linux/generic/files/include/linux/ath9k_platform.h
 create mode 100644 target/linux/generic/files/include/linux/myloader.h
 create mode 100644 target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h
 create mode 100644 target/linux/generic/files/include/linux/platform_data/b53.h
 create mode 100644 target/linux/generic/files/include/linux/routerboot.h
 create mode 100644 target/linux/generic/files/include/linux/rt2x00_platform.h
 create mode 100644 target/linux/generic/files/include/linux/rtl8366.h
 create mode 100644 target/linux/generic/files/include/linux/rtl8367.h
 create mode 100644 target/linux/generic/files/include/linux/switch.h
 create mode 100644 target/linux/generic/files/include/uapi/linux/switch.h
 create mode 100644 target/linux/generic/image/Makefile
 create mode 100644 target/linux/generic/image/initramfs-base-files.txt
 create mode 100644 target/linux/generic/image/lzma-loader/Makefile
 create mode 100644 target/linux/generic/image/lzma-loader/src/LzmaDecode.c
 create mode 100644 target/linux/generic/image/lzma-loader/src/LzmaDecode.h
 create mode 100644 target/linux/generic/image/lzma-loader/src/Makefile
 create mode 100644 target/linux/generic/image/lzma-loader/src/decompress.c
 create mode 100644 target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in
 create mode 100644 target/linux/generic/image/lzma-loader/src/lzma.lds.in
 create mode 100644 target/linux/generic/image/lzma-loader/src/print.c
 create mode 100644 target/linux/generic/image/lzma-loader/src/print.h
 create mode 100644 target/linux/generic/image/lzma-loader/src/printf.c
 create mode 100644 target/linux/generic/image/lzma-loader/src/printf.h
 create mode 100644 target/linux/generic/image/lzma-loader/src/start.S
 create mode 100644 target/linux/generic/image/lzma-loader/src/uart16550.c
 create mode 100644 target/linux/generic/image/lzma-loader/src/uart16550.h
 create mode 100644 target/linux/generic/image/relocate/Makefile
 create mode 100644 target/linux/generic/image/relocate/cacheops.h
 create mode 100644 target/linux/generic/image/relocate/cp0regdef.h
 create mode 100644 target/linux/generic/image/relocate/head.S
 create mode 100644 target/linux/generic/image/relocate/loader.lds
 create mode 100644 target/linux/generic/patches-3.18/020-ssb_update.patch
 create mode 100644 target/linux/generic/patches-3.18/021-ssb_sprom.patch
 create mode 100644 target/linux/generic/patches-3.18/025-bcma_backport.patch
 create mode 100644 target/linux/generic/patches-3.18/026-bcma-from-3.20.patch
 create mode 100644 target/linux/generic/patches-3.18/027-bcma-from-4.1.patch
 create mode 100644 target/linux/generic/patches-3.18/028-bcma-from-4.2.patch
 create mode 100644 target/linux/generic/patches-3.18/029-bcma-from-4.4.patch
 create mode 100644 target/linux/generic/patches-3.18/030-backport_bcm47xx_nvram.patch
 create mode 100644 target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch
 create mode 100644 target/linux/generic/patches-3.18/031-bcma-from-4.5.patch
 create mode 100644 target/linux/generic/patches-3.18/032-bcma-from-4.6.patch
 create mode 100644 target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch
 create mode 100644 target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch
 create mode 100644 target/linux/generic/patches-3.18/043-mtd_GD25Q128B_support_backport_from_3.19.patch
 create mode 100644 target/linux/generic/patches-3.18/044-backport-m25p80-jedec-probe.patch
 create mode 100644 target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch
 create mode 100644 target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch
 create mode 100644 target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch
 create mode 100644 target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch
 create mode 100644 target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch
 create mode 100644 target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch
 create mode 100644 target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch
 create mode 100644 target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch
 create mode 100644 target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch
 create mode 100644 target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch
 create mode 100644 target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch
 create mode 100644 target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch
 create mode 100644 target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch
 create mode 100644 target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch
 create mode 100644 target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch
 create mode 100644 target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch
 create mode 100644 target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch
 create mode 100644 target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch
 create mode 100644 target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch
 create mode 100644 target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch
 create mode 100644 target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch
 create mode 100644 target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch
 create mode 100644 target/linux/generic/patches-3.18/078-bgmac-reset-enable-Ethernet-core-before-using-it.patch
 create mode 100644 target/linux/generic/patches-3.18/079-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
 create mode 100644 target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch
 create mode 100644 target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch
 create mode 100644 target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch
 create mode 100644 target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch
 create mode 100644 target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch
 create mode 100644 target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch
 create mode 100644 target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch
 create mode 100644 target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch
 create mode 100644 target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch
 create mode 100644 target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch
 create mode 100644 target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch
 create mode 100644 target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch
 create mode 100644 target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch
 create mode 100644 target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch
 create mode 100644 target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch
 create mode 100644 target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch
 create mode 100644 target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch
 create mode 100644 target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch
 create mode 100644 target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch
 create mode 100644 target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch
 create mode 100644 target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch
 create mode 100644 target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch
 create mode 100644 target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch
 create mode 100644 target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch
 create mode 100644 target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch
 create mode 100644 target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch
 create mode 100644 target/linux/generic/patches-3.18/081-01-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch
 create mode 100644 target/linux/generic/patches-3.18/081-02-pppoe-Lacks-DST-MAC-address-check.patch
 create mode 100644 target/linux/generic/patches-3.18/081-03-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch
 create mode 100644 target/linux/generic/patches-3.18/081-06-ppp-don-t-set-sk_state-to-PPPOX_ZOMBIE-in-pppoe_disc.patch
 create mode 100644 target/linux/generic/patches-3.18/081-07-ppp-remove-PPPOX_ZOMBIE-socket-state.patch
 create mode 100644 target/linux/generic/patches-3.18/081-08-pppoe-fix-memory-corruption-in-padt-work-structure.patch
 create mode 100644 target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
 create mode 100644 target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch
 create mode 100644 target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch
 create mode 100644 target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K
 create mode 100644 target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch
 create mode 100644 target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
 create mode 100644 target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch
 create mode 100644 target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch
 create mode 100644 target/linux/generic/patches-3.18/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch
 create mode 100644 target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch
 create mode 100644 target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch
 create mode 100644 target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
 create mode 100644 target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch
 create mode 100644 target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch
 create mode 100644 target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch
 create mode 100644 target/linux/generic/patches-3.18/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch
 create mode 100644 target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
 create mode 100644 target/linux/generic/patches-3.18/141-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
 create mode 100644 target/linux/generic/patches-3.18/142-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
 create mode 100644 target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch
 create mode 100644 target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch
 create mode 100644 target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch
 create mode 100644 target/linux/generic/patches-3.18/192-USB-qcserial-Add-support-for-Quectel-EC20-Mini-PCIe-.patch
 create mode 100644 target/linux/generic/patches-3.18/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
 create mode 100644 target/linux/generic/patches-3.18/200-fix_localversion.patch
 create mode 100644 target/linux/generic/patches-3.18/201-extra_optimization.patch
 create mode 100644 target/linux/generic/patches-3.18/202-reduce_module_size.patch
 create mode 100644 target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch
 create mode 100644 target/linux/generic/patches-3.18/204-module_strip.patch
 create mode 100644 target/linux/generic/patches-3.18/205-backtrace_module_info.patch
 create mode 100644 target/linux/generic/patches-3.18/210-darwin_scripts_include.patch
 create mode 100644 target/linux/generic/patches-3.18/212-byteshift_portability.patch
 create mode 100644 target/linux/generic/patches-3.18/213-x86_vdso_portability.patch
 create mode 100644 target/linux/generic/patches-3.18/214-spidev_h_portability.patch
 create mode 100644 target/linux/generic/patches-3.18/220-gc_sections.patch
 create mode 100644 target/linux/generic/patches-3.18/221-module_exports.patch
 create mode 100644 target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch
 create mode 100644 target/linux/generic/patches-3.18/250-netfilter_depends.patch
 create mode 100644 target/linux/generic/patches-3.18/251-sound_kconfig.patch
 create mode 100644 target/linux/generic/patches-3.18/252-mv_cesa_depends.patch
 create mode 100644 target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch
 create mode 100644 target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch
 create mode 100644 target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch
 create mode 100644 target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch
 create mode 100644 target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch
 create mode 100644 target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch
 create mode 100644 target/linux/generic/patches-3.18/259-regmap_dynamic.patch
 create mode 100644 target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch
 create mode 100644 target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
 create mode 100644 target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
 create mode 100644 target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
 create mode 100644 target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch
 create mode 100644 target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch
 create mode 100644 target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch
 create mode 100644 target/linux/generic/patches-3.18/304-mips_disable_fpu.patch
 create mode 100644 target/linux/generic/patches-3.18/305-mips_module_reloc.patch
 create mode 100644 target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch
 create mode 100644 target/linux/generic/patches-3.18/307-mips_highmem_offset.patch
 create mode 100644 target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch
 create mode 100644 target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch
 create mode 100644 target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch
 create mode 100644 target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
 create mode 100644 target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch
 create mode 100644 target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch
 create mode 100644 target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
 create mode 100644 target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch
 create mode 100644 target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch
 create mode 100644 target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch
 create mode 100644 target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch
 create mode 100644 target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
 create mode 100644 target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch
 create mode 100644 target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch
 create mode 100644 target/linux/generic/patches-3.18/420-mtd-redboot_space.patch
 create mode 100644 target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch
 create mode 100644 target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
 create mode 100644 target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
 create mode 100644 target/linux/generic/patches-3.18/440-block2mtd_init.patch
 create mode 100644 target/linux/generic/patches-3.18/441-block2mtd_probe.patch
 create mode 100644 target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
 create mode 100644 target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
 create mode 100644 target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
 create mode 100644 target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
 create mode 100644 target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch
 create mode 100644 target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch
 create mode 100644 target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch
 create mode 100644 target/linux/generic/patches-3.18/475-mtd-spi-nor-add-macronix-mx25u25635f.patch
 create mode 100644 target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch
 create mode 100644 target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
 create mode 100644 target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
 create mode 100644 target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
 create mode 100644 target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
 create mode 100644 target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch
 create mode 100644 target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch
 create mode 100644 target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch
 create mode 100644 target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch
 create mode 100644 target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch
 create mode 100644 target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch
 create mode 100644 target/linux/generic/patches-3.18/531-debloat_lzma.patch
 create mode 100644 target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch
 create mode 100644 target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch
 create mode 100644 target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch
 create mode 100644 target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch
 create mode 100644 target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch
 create mode 100644 target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch
 create mode 100644 target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch
 create mode 100644 target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch
 create mode 100644 target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch
 create mode 100644 target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch
 create mode 100644 target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch
 create mode 100644 target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch
 create mode 100644 target/linux/generic/patches-3.18/621-sched_act_connmark.patch
 create mode 100644 target/linux/generic/patches-3.18/630-packet_socket_type.patch
 create mode 100644 target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch
 create mode 100644 target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch
 create mode 100644 target/linux/generic/patches-3.18/642-bridge_port_isolate.patch
 create mode 100644 target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch
 create mode 100644 target/linux/generic/patches-3.18/650-pppoe_header_pad.patch
 create mode 100644 target/linux/generic/patches-3.18/651-wireless_mesh_header.patch
 create mode 100644 target/linux/generic/patches-3.18/653-disable_netlink_trim.patch
 create mode 100644 target/linux/generic/patches-3.18/655-increase_skb_pad.patch
 create mode 100644 target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch
 create mode 100644 target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch
 create mode 100644 target/linux/generic/patches-3.18/660-fq_codel_defaults.patch
 create mode 100644 target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch
 create mode 100644 target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch
 create mode 100644 target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch
 create mode 100644 target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
 create mode 100644 target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch
 create mode 100644 target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
 create mode 100644 target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
 create mode 100644 target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
 create mode 100644 target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch
 create mode 100644 target/linux/generic/patches-3.18/700-swconfig.patch
 create mode 100644 target/linux/generic/patches-3.18/701-phy_extension.patch
 create mode 100644 target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch
 create mode 100644 target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch
 create mode 100644 target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch
 create mode 100644 target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch
 create mode 100644 target/linux/generic/patches-3.18/720-phy_adm6996.patch
 create mode 100644 target/linux/generic/patches-3.18/721-phy_packets.patch
 create mode 100644 target/linux/generic/patches-3.18/722-phy_mvswitch.patch
 create mode 100644 target/linux/generic/patches-3.18/723-phy_ip175c.patch
 create mode 100644 target/linux/generic/patches-3.18/724-phy_ar8216.patch
 create mode 100644 target/linux/generic/patches-3.18/725-phy_rtl8306.patch
 create mode 100644 target/linux/generic/patches-3.18/726-phy_rtl8366.patch
 create mode 100644 target/linux/generic/patches-3.18/727-phy-rtl8367.patch
 create mode 100644 target/linux/generic/patches-3.18/728-phy-rtl8367b.patch
 create mode 100644 target/linux/generic/patches-3.18/729-phy-tantos.patch
 create mode 100644 target/linux/generic/patches-3.18/730-phy_b53.patch
 create mode 100644 target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch
 create mode 100644 target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch
 create mode 100644 target/linux/generic/patches-3.18/734-net-phy-at803x-allow-to-configure-via-pdata.patch
 create mode 100644 target/linux/generic/patches-3.18/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
 create mode 100644 target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch
 create mode 100644 target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch
 create mode 100644 target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch
 create mode 100644 target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch
 create mode 100644 target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch
 create mode 100644 target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch
 create mode 100644 target/linux/generic/patches-3.18/831-ledtrig_netdev.patch
 create mode 100644 target/linux/generic/patches-3.18/834-ledtrig-libata.patch
 create mode 100644 target/linux/generic/patches-3.18/840-rtc7301.patch
 create mode 100644 target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch
 create mode 100644 target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch
 create mode 100644 target/linux/generic/patches-3.18/862-gpio_spi_driver.patch
 create mode 100644 target/linux/generic/patches-3.18/863-gpiommc.patch
 create mode 100644 target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch
 create mode 100644 target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch
 create mode 100644 target/linux/generic/patches-3.18/880-gateworks_system_controller.patch
 create mode 100644 target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch
 create mode 100644 target/linux/generic/patches-3.18/901-debloat_sock_diag.patch
 create mode 100644 target/linux/generic/patches-3.18/902-debloat_proc.patch
 create mode 100644 target/linux/generic/patches-3.18/903-debloat_direct_io.patch
 create mode 100644 target/linux/generic/patches-3.18/904-debloat_dma_buf.patch
 create mode 100644 target/linux/generic/patches-3.18/910-kobject_uevent.patch
 create mode 100644 target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch
 create mode 100644 target/linux/generic/patches-3.18/921-use_preinit_as_init.patch
 create mode 100644 target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch
 create mode 100644 target/linux/generic/patches-3.18/930-crashlog.patch
 create mode 100644 target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch
 create mode 100644 target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch
 create mode 100644 target/linux/generic/patches-3.18/990-gpio_wdt.patch
 create mode 100644 target/linux/generic/patches-3.18/995-mangle_bootargs.patch
 create mode 100644 target/linux/generic/patches-3.18/997-device_tree_cmdline.patch
 create mode 100644 target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch
 create mode 100644 target/linux/generic/patches-3.18/999-seccomp_log.patch
 create mode 100644 target/linux/generic/patches-4.1/010-perf-tools-Create-config.detected-into-OUTPUT-direct.patch
 create mode 100644 target/linux/generic/patches-4.1/011-perf-tools-Fix-makefile-generation-under-dash.patch
 create mode 100644 target/linux/generic/patches-4.1/020-ssb-backport.patch
 create mode 100644 target/linux/generic/patches-4.1/021-ssb_sprom.patch
 create mode 100644 target/linux/generic/patches-4.1/022-bcma-from-4.2.patch
 create mode 100644 target/linux/generic/patches-4.1/023-bcma-from-4.4.patch
 create mode 100644 target/linux/generic/patches-4.1/024-bcma-from-4.5.patch
 create mode 100644 target/linux/generic/patches-4.1/025-bcma-from-4.6.patch
 create mode 100644 target/linux/generic/patches-4.1/030-backport_bcm47xx_nvram.patch
 create mode 100644 target/linux/generic/patches-4.1/040-fs-overlay-fix-stacking.patch
 create mode 100644 target/linux/generic/patches-4.1/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch
 create mode 100644 target/linux/generic/patches-4.1/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch
 create mode 100644 target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch
 create mode 100644 target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch
 create mode 100644 target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
 create mode 100644 target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch
 create mode 100644 target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
 create mode 100644 target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch
 create mode 100644 target/linux/generic/patches-4.1/082-usb-core-Introduce-a-USB-port-LED-trigger.patch
 create mode 100644 target/linux/generic/patches-4.1/090-m25p80_spi-nor_update_to_4.4rc1.patch
 create mode 100644 target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch
 create mode 100644 target/linux/generic/patches-4.1/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch
 create mode 100644 target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch
 create mode 100644 target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
 create mode 100644 target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch
 create mode 100644 target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch
 create mode 100644 target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch
 create mode 100644 target/linux/generic/patches-4.1/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch
 create mode 100644 target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
 create mode 100644 target/linux/generic/patches-4.1/141-Revert-mtd-spi-nor-disable-protection-for-Winbond-fl.patch
 create mode 100644 target/linux/generic/patches-4.1/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
 create mode 100644 target/linux/generic/patches-4.1/143-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
 create mode 100644 target/linux/generic/patches-4.1/144-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
 create mode 100644 target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch
 create mode 100644 target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch
 create mode 100644 target/linux/generic/patches-4.1/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
 create mode 100644 target/linux/generic/patches-4.1/200-fix_localversion.patch
 create mode 100644 target/linux/generic/patches-4.1/201-extra_optimization.patch
 create mode 100644 target/linux/generic/patches-4.1/202-reduce_module_size.patch
 create mode 100644 target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch
 create mode 100644 target/linux/generic/patches-4.1/204-module_strip.patch
 create mode 100644 target/linux/generic/patches-4.1/205-backtrace_module_info.patch
 create mode 100644 target/linux/generic/patches-4.1/210-darwin_scripts_include.patch
 create mode 100644 target/linux/generic/patches-4.1/212-byteshift_portability.patch
 create mode 100644 target/linux/generic/patches-4.1/214-spidev_h_portability.patch
 create mode 100644 target/linux/generic/patches-4.1/220-gc_sections.patch
 create mode 100644 target/linux/generic/patches-4.1/221-module_exports.patch
 create mode 100644 target/linux/generic/patches-4.1/222-perf-build-Do-not-fail-on-missing-Build-file.patch
 create mode 100644 target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch
 create mode 100644 target/linux/generic/patches-4.1/250-netfilter_depends.patch
 create mode 100644 target/linux/generic/patches-4.1/251-sound_kconfig.patch
 create mode 100644 target/linux/generic/patches-4.1/252-mv_cesa_depends.patch
 create mode 100644 target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch
 create mode 100644 target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch
 create mode 100644 target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch
 create mode 100644 target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch
 create mode 100644 target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch
 create mode 100644 target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch
 create mode 100644 target/linux/generic/patches-4.1/259-regmap_dynamic.patch
 create mode 100644 target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch
 create mode 100644 target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
 create mode 100644 target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
 create mode 100644 target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
 create mode 100644 target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch
 create mode 100644 target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch
 create mode 100644 target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch
 create mode 100644 target/linux/generic/patches-4.1/304-mips_disable_fpu.patch
 create mode 100644 target/linux/generic/patches-4.1/305-mips_module_reloc.patch
 create mode 100644 target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch
 create mode 100644 target/linux/generic/patches-4.1/307-mips_highmem_offset.patch
 create mode 100644 target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch
 create mode 100644 target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch
 create mode 100644 target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch
 create mode 100644 target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
 create mode 100644 target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch
 create mode 100644 target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch
 create mode 100644 target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
 create mode 100644 target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch
 create mode 100644 target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch
 create mode 100644 target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch
 create mode 100644 target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
 create mode 100644 target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch
 create mode 100644 target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch
 create mode 100644 target/linux/generic/patches-4.1/420-mtd-redboot_space.patch
 create mode 100644 target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch
 create mode 100644 target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
 create mode 100644 target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
 create mode 100644 target/linux/generic/patches-4.1/440-block2mtd_init.patch
 create mode 100644 target/linux/generic/patches-4.1/441-block2mtd_probe.patch
 create mode 100644 target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
 create mode 100644 target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
 create mode 100644 target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
 create mode 100644 target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
 create mode 100644 target/linux/generic/patches-4.1/465-m25p80-mx-disable-software-protection.patch
 create mode 100644 target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch
 create mode 100644 target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
 create mode 100644 target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
 create mode 100644 target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
 create mode 100644 target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
 create mode 100644 target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch
 create mode 100644 target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch
 create mode 100644 target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch
 create mode 100644 target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch
 create mode 100644 target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch
 create mode 100644 target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch
 create mode 100644 target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch
 create mode 100644 target/linux/generic/patches-4.1/531-debloat_lzma.patch
 create mode 100644 target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch
 create mode 100644 target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch
 create mode 100644 target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch
 create mode 100644 target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch
 create mode 100644 target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch
 create mode 100644 target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch
 create mode 100644 target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch
 create mode 100644 target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch
 create mode 100644 target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch
 create mode 100644 target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch
 create mode 100644 target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch
 create mode 100644 target/linux/generic/patches-4.1/630-packet_socket_type.patch
 create mode 100644 target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch
 create mode 100644 target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch
 create mode 100644 target/linux/generic/patches-4.1/642-bridge_port_isolate.patch
 create mode 100644 target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch
 create mode 100644 target/linux/generic/patches-4.1/650-pppoe_header_pad.patch
 create mode 100644 target/linux/generic/patches-4.1/651-wireless_mesh_header.patch
 create mode 100644 target/linux/generic/patches-4.1/653-disable_netlink_trim.patch
 create mode 100644 target/linux/generic/patches-4.1/655-increase_skb_pad.patch
 create mode 100644 target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch
 create mode 100644 target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch
 create mode 100644 target/linux/generic/patches-4.1/660-fq_codel_defaults.patch
 create mode 100644 target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch
 create mode 100644 target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch
 create mode 100644 target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch
 create mode 100644 target/linux/generic/patches-4.1/664-codel_fix_3_12.patch
 create mode 100644 target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
 create mode 100644 target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
 create mode 100644 target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
 create mode 100644 target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
 create mode 100644 target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch
 create mode 100644 target/linux/generic/patches-4.1/700-swconfig.patch
 create mode 100644 target/linux/generic/patches-4.1/701-phy_extension.patch
 create mode 100644 target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch
 create mode 100644 target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch
 create mode 100644 target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch
 create mode 100644 target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch
 create mode 100644 target/linux/generic/patches-4.1/720-phy_adm6996.patch
 create mode 100644 target/linux/generic/patches-4.1/721-phy_packets.patch
 create mode 100644 target/linux/generic/patches-4.1/722-phy_mvswitch.patch
 create mode 100644 target/linux/generic/patches-4.1/723-phy_ip175c.patch
 create mode 100644 target/linux/generic/patches-4.1/724-phy_ar8216.patch
 create mode 100644 target/linux/generic/patches-4.1/725-phy_rtl8306.patch
 create mode 100644 target/linux/generic/patches-4.1/726-phy_rtl8366.patch
 create mode 100644 target/linux/generic/patches-4.1/727-phy-rtl8367.patch
 create mode 100644 target/linux/generic/patches-4.1/728-phy-rtl8367b.patch
 create mode 100644 target/linux/generic/patches-4.1/729-phy-tantos.patch
 create mode 100644 target/linux/generic/patches-4.1/730-phy_b53.patch
 create mode 100644 target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch
 create mode 100644 target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch
 create mode 100644 target/linux/generic/patches-4.1/734-net-phy-at803x-allow-to-configure-via-pdata.patch
 create mode 100644 target/linux/generic/patches-4.1/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
 create mode 100644 target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch
 create mode 100644 target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch
 create mode 100644 target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch
 create mode 100644 target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch
 create mode 100644 target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch
 create mode 100644 target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch
 create mode 100644 target/linux/generic/patches-4.1/831-ledtrig_netdev.patch
 create mode 100644 target/linux/generic/patches-4.1/834-ledtrig-libata.patch
 create mode 100644 target/linux/generic/patches-4.1/840-rtc7301.patch
 create mode 100644 target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch
 create mode 100644 target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch
 create mode 100644 target/linux/generic/patches-4.1/862-gpio_spi_driver.patch
 create mode 100644 target/linux/generic/patches-4.1/863-gpiommc.patch
 create mode 100644 target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch
 create mode 100644 target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch
 create mode 100644 target/linux/generic/patches-4.1/880-gateworks_system_controller.patch
 create mode 100644 target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch
 create mode 100644 target/linux/generic/patches-4.1/901-debloat_sock_diag.patch
 create mode 100644 target/linux/generic/patches-4.1/902-debloat_proc.patch
 create mode 100644 target/linux/generic/patches-4.1/903-debloat_direct_io.patch
 create mode 100644 target/linux/generic/patches-4.1/904-debloat_dma_buf.patch
 create mode 100644 target/linux/generic/patches-4.1/910-kobject_uevent.patch
 create mode 100644 target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch
 create mode 100644 target/linux/generic/patches-4.1/921-use_preinit_as_init.patch
 create mode 100644 target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch
 create mode 100644 target/linux/generic/patches-4.1/930-crashlog.patch
 create mode 100644 target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch
 create mode 100644 target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch
 create mode 100644 target/linux/generic/patches-4.1/995-mangle_bootargs.patch
 create mode 100644 target/linux/generic/patches-4.1/997-device_tree_cmdline.patch
 create mode 100644 target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch
 create mode 100644 target/linux/generic/patches-4.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
 create mode 100644 target/linux/generic/patches-4.4/020-bcma-from-4.5.patch
 create mode 100644 target/linux/generic/patches-4.4/021-bcma-from-4.6.patch
 create mode 100644 target/linux/generic/patches-4.4/022-bcma-from-4.8.patch
 create mode 100644 target/linux/generic/patches-4.4/023-bcma-from-4.9.patch
 create mode 100644 target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch
 create mode 100644 target/linux/generic/patches-4.4/033-fq_codel-add-memory-limitation-per-queue.patch
 create mode 100644 target/linux/generic/patches-4.4/034-fq_codel-fix-memory-limitation-drift.patch
 create mode 100644 target/linux/generic/patches-4.4/035-fq_codel-fix-NET_XMIT_CN-behavior.patch
 create mode 100644 target/linux/generic/patches-4.4/040-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
 create mode 100644 target/linux/generic/patches-4.4/041-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
 create mode 100644 target/linux/generic/patches-4.4/042-0001-mtd-bcm47xxsflash-use-ioremap_cache-instead-of-KSEG0.patch
 create mode 100644 target/linux/generic/patches-4.4/042-0002-mtd-add-arch-dependency-for-MTD_BCM47XXSFLASH-symbol.patch
 create mode 100644 target/linux/generic/patches-4.4/042-0003-mtd-bcm47xxsflash-use-uncached-MMIO-access-for-BCM53.patch
 create mode 100644 target/linux/generic/patches-4.4/042-0004-mtd-bcm47xxpart-fix-parsing-first-block-after-aligne.patch
 create mode 100644 target/linux/generic/patches-4.4/043-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
 create mode 100644 target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch
 create mode 100644 target/linux/generic/patches-4.4/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch
 create mode 100644 target/linux/generic/patches-4.4/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch
 create mode 100644 target/linux/generic/patches-4.4/050-backport_netfilter_rtcache.patch
 create mode 100644 target/linux/generic/patches-4.4/051-0001-ovl-rename-is_merge-to-is_lowest.patch
 create mode 100644 target/linux/generic/patches-4.4/051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch
 create mode 100644 target/linux/generic/patches-4.4/051-0005-ovl-proper-cleanup-of-workdir.patch
 create mode 100644 target/linux/generic/patches-4.4/052-01-ubifs-Implement-O_TMPFILE.patch
 create mode 100644 target/linux/generic/patches-4.4/052-02-ubifs-Implement-RENAME_WHITEOUT.patch
 create mode 100644 target/linux/generic/patches-4.4/052-03-ubifs-Implement-RENAME_EXCHANGE.patch
 create mode 100644 target/linux/generic/patches-4.4/052-04-ubifs-Use-move-variable-in-ubifs_rename.patch
 create mode 100644 target/linux/generic/patches-4.4/060-mips_decompressor_memmove.patch
 create mode 100644 target/linux/generic/patches-4.4/061-softirq-let-ksoftirqd-do-its-job.patch
 create mode 100644 target/linux/generic/patches-4.4/070-0001-bgmac-fix-a-missing-check-for-build_skb.patch
 create mode 100644 target/linux/generic/patches-4.4/070-0002-bgmac-Fix-reversed-test-of-build_skb-return-value.patch
 create mode 100644 target/linux/generic/patches-4.4/071-0000-net-bgmac-clarify-CONFIG_BCMA-dependency.patch
 create mode 100644 target/linux/generic/patches-4.4/071-0001-bgmac-add-helper-checking-for-BCM4707-BCM53018-chip-.patch
 create mode 100644 target/linux/generic/patches-4.4/071-0002-bgmac-support-Ethernet-device-on-BCM47094-SoC.patch
 create mode 100644 target/linux/generic/patches-4.4/071-0003-bgmac-reset-enable-Ethernet-core-before-using-it.patch
 create mode 100644 target/linux/generic/patches-4.4/071-0004-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
 create mode 100644 target/linux/generic/patches-4.4/072-0001-bgmac-Bind-net_device-with-backing-device-structure.patch
 create mode 100644 target/linux/generic/patches-4.4/072-0002-bgmac-Add-support-for-ethtool-statistics.patch
 create mode 100644 target/linux/generic/patches-4.4/072-0003-bgmac-Maintain-some-netdev-statistics.patch
 create mode 100644 target/linux/generic/patches-4.4/073-0001-net-ethernet-bgmac-use-phydev-from-struct-net_device.patch
 create mode 100644 target/linux/generic/patches-4.4/074-0001-net-bgmac-Fix-SOF-bit-checking.patch
 create mode 100644 target/linux/generic/patches-4.4/074-0002-net-bgmac-Start-transmit-queue-in-bgmac_open.patch
 create mode 100644 target/linux/generic/patches-4.4/074-0003-net-bgmac-Remove-superflous-netif_carrier_on.patch
 create mode 100644 target/linux/generic/patches-4.4/075-0001-net-ethernet-bgmac-change-bgmac_-prints-to-dev_-prin.patch
 create mode 100644 target/linux/generic/patches-4.4/075-0002-net-ethernet-bgmac-add-dma_dev-pointer.patch
 create mode 100644 target/linux/generic/patches-4.4/075-0003-net-ethernet-bgmac-move-BCMA-MDIO-Phy-code-into-a-se.patch
 create mode 100644 target/linux/generic/patches-4.4/075-0004-net-ethernet-bgmac-convert-to-feature-flags.patch
 create mode 100644 target/linux/generic/patches-4.4/075-0005-net-ethernet-bgmac-Add-platform-device-support.patch
 create mode 100644 target/linux/generic/patches-4.4/076-0001-net-ethernet-bgmac-Fix-return-value-check-in-bgmac_p.patch
 create mode 100644 target/linux/generic/patches-4.4/076-0002-net-ethernet-bgmac-Remove-redundant-dev_err-call-in-.patch
 create mode 100644 target/linux/generic/patches-4.4/076-0004-net-bgmac-fix-reversed-check-for-MII-registration-er.patch
 create mode 100644 target/linux/generic/patches-4.4/077-0001-net-bgmac-support-Ethernet-core-on-BCM53573-SoCs.patch
 create mode 100644 target/linux/generic/patches-4.4/077-0002-net-bgmac-make-it-clear-when-setting-interface-type-.patch
 create mode 100644 target/linux/generic/patches-4.4/077-0003-net-bgmac-Fix-errant-feature-flag-check.patch
 create mode 100644 target/linux/generic/patches-4.4/077-0004-net-bgmac-fix-spelling-mistake-connecton-connection.patch
 create mode 100644 target/linux/generic/patches-4.4/080-spi-introduce-accelerated-read-support-for-spi-flash.patch
 create mode 100644 target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
 create mode 100644 target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch
 create mode 100644 target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch
 create mode 100644 target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch
 create mode 100644 target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch
 create mode 100644 target/linux/generic/patches-4.4/084-0001-usb-core-Introduce-a-USB-port-LED-trigger.patch
 create mode 100644 target/linux/generic/patches-4.4/084-0002-usb-core-usbport-Use-proper-LED-API-to-fix-potential.patch
 create mode 100644 target/linux/generic/patches-4.4/085-0001-leds-leds-gpio-Set-of_node-for-created-LED-devices.patch
 create mode 100644 target/linux/generic/patches-4.4/090-MIPS-c-r4k-Use-IPI-calls-for-CM-indexed-cache-ops.patch
 create mode 100644 target/linux/generic/patches-4.4/091-MIPS-c-r4k-Exclude-sibling-CPUs-in-SMP-calls.patch
 create mode 100644 target/linux/generic/patches-4.4/092-MIPS-ZBOOT-copy-appended-dtb-to-the-end-of-the-kerne.patch
 create mode 100644 target/linux/generic/patches-4.4/093-MIPS-store-the-appended-dtb-address-in-a-variable.patch
 create mode 100644 target/linux/generic/patches-4.4/096-arc-add-model-property-in-dts.patch
 create mode 100644 target/linux/generic/patches-4.4/097-MIPS-io.h-Define-ioremap_cache.patch
 create mode 100644 target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
 create mode 100644 target/linux/generic/patches-4.4/102-ehci_hcd_ignore_oc.patch
 create mode 100644 target/linux/generic/patches-4.4/103-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
 create mode 100644 target/linux/generic/patches-4.4/104-of-Add-check-to-of_scan_flat_dt-before-accessing-ini.patch
 create mode 100644 target/linux/generic/patches-4.4/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
 create mode 100644 target/linux/generic/patches-4.4/111-jffs2-add-RENAME_EXCHANGE-support.patch
 create mode 100644 target/linux/generic/patches-4.4/120-bridge_allow_receiption_on_disabled_port.patch
 create mode 100644 target/linux/generic/patches-4.4/132-mips_inline_dma_ops.patch
 create mode 100644 target/linux/generic/patches-4.4/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
 create mode 100644 target/linux/generic/patches-4.4/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
 create mode 100644 target/linux/generic/patches-4.4/150-mtd-spi-nor-add-support-for-ESMT_f25l32qa-and-ESMT_f.patch
 create mode 100644 target/linux/generic/patches-4.4/160-usb-gadget-udc-net2280-add-usb2380-support.patch
 create mode 100644 target/linux/generic/patches-4.4/170-net-bgmac-fix-reversed-checks-for-clock-control-flag.patch
 create mode 100644 target/linux/generic/patches-4.4/200-fix_localversion.patch
 create mode 100644 target/linux/generic/patches-4.4/201-extra_optimization.patch
 create mode 100644 target/linux/generic/patches-4.4/202-reduce_module_size.patch
 create mode 100644 target/linux/generic/patches-4.4/203-kallsyms_uncompressed.patch
 create mode 100644 target/linux/generic/patches-4.4/204-module_strip.patch
 create mode 100644 target/linux/generic/patches-4.4/205-backtrace_module_info.patch
 create mode 100644 target/linux/generic/patches-4.4/206-mips-disable-vdso.patch
 create mode 100644 target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch
 create mode 100644 target/linux/generic/patches-4.4/210-darwin_scripts_include.patch
 create mode 100644 target/linux/generic/patches-4.4/211-sign-file-libressl.patch
 create mode 100644 target/linux/generic/patches-4.4/212-byteshift_portability.patch
 create mode 100644 target/linux/generic/patches-4.4/214-spidev_h_portability.patch
 create mode 100644 target/linux/generic/patches-4.4/220-gc_sections.patch
 create mode 100644 target/linux/generic/patches-4.4/221-module_exports.patch
 create mode 100644 target/linux/generic/patches-4.4/222-arm_zimage_none.patch
 create mode 100644 target/linux/generic/patches-4.4/230-openwrt_lzma_options.patch
 create mode 100644 target/linux/generic/patches-4.4/250-netfilter_depends.patch
 create mode 100644 target/linux/generic/patches-4.4/251-sound_kconfig.patch
 create mode 100644 target/linux/generic/patches-4.4/252-mv_cesa_depends.patch
 create mode 100644 target/linux/generic/patches-4.4/253-ssb_b43_default_on.patch
 create mode 100644 target/linux/generic/patches-4.4/254-textsearch_kconfig_hacks.patch
 create mode 100644 target/linux/generic/patches-4.4/255-lib80211_kconfig_hacks.patch
 create mode 100644 target/linux/generic/patches-4.4/256-crypto_add_kconfig_prompts.patch
 create mode 100644 target/linux/generic/patches-4.4/257-wireless_ext_kconfig_hack.patch
 create mode 100644 target/linux/generic/patches-4.4/258-netfilter_netlink_kconfig_hack.patch
 create mode 100644 target/linux/generic/patches-4.4/259-regmap_dynamic.patch
 create mode 100644 target/linux/generic/patches-4.4/260-crypto_test_dependencies.patch
 create mode 100644 target/linux/generic/patches-4.4/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
 create mode 100644 target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
 create mode 100644 target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
 create mode 100644 target/linux/generic/patches-4.4/280-rfkill-stubs.patch
 create mode 100644 target/linux/generic/patches-4.4/300-mips_expose_boot_raw.patch
 create mode 100644 target/linux/generic/patches-4.4/301-mips_image_cmdline_hack.patch
 create mode 100644 target/linux/generic/patches-4.4/302-mips_no_branch_likely.patch
 create mode 100644 target/linux/generic/patches-4.4/304-mips_disable_fpu.patch
 create mode 100644 target/linux/generic/patches-4.4/305-mips_module_reloc.patch
 create mode 100644 target/linux/generic/patches-4.4/306-mips_mem_functions_performance.patch
 create mode 100644 target/linux/generic/patches-4.4/307-mips_highmem_offset.patch
 create mode 100644 target/linux/generic/patches-4.4/308-mips32r2_tune.patch
 create mode 100644 target/linux/generic/patches-4.4/310-arm_module_unresolved_weak_sym.patch
 create mode 100644 target/linux/generic/patches-4.4/320-ppc4xx_optimization.patch
 create mode 100644 target/linux/generic/patches-4.4/321-powerpc_crtsavres_prereq.patch
 create mode 100644 target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
 create mode 100644 target/linux/generic/patches-4.4/331-arc-remove-dependency-on-DEVTMPFS.patch
 create mode 100644 target/linux/generic/patches-4.4/332-arc-add-OWRTDTB-section.patch
 create mode 100644 target/linux/generic/patches-4.4/333-arc-enable-unaligned-access-in-kernel-mode.patch
 create mode 100644 target/linux/generic/patches-4.4/400-mtd-add-rootfs-split-support.patch
 create mode 100644 target/linux/generic/patches-4.4/401-mtd-add-support-for-different-partition-parser-types.patch
 create mode 100644 target/linux/generic/patches-4.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
 create mode 100644 target/linux/generic/patches-4.4/403-mtd-hook-mtdsplit-to-Kbuild.patch
 create mode 100644 target/linux/generic/patches-4.4/404-mtd-add-more-helper-functions.patch
 create mode 100644 target/linux/generic/patches-4.4/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
 create mode 100644 target/linux/generic/patches-4.4/411-mtd-partial_eraseblock_write.patch
 create mode 100644 target/linux/generic/patches-4.4/412-mtd-partial_eraseblock_unlock.patch
 create mode 100644 target/linux/generic/patches-4.4/420-mtd-redboot_space.patch
 create mode 100644 target/linux/generic/patches-4.4/430-mtd-add-myloader-partition-parser.patch
 create mode 100644 target/linux/generic/patches-4.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
 create mode 100644 target/linux/generic/patches-4.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
 create mode 100644 target/linux/generic/patches-4.4/440-block2mtd_init.patch
 create mode 100644 target/linux/generic/patches-4.4/441-block2mtd_probe.patch
 create mode 100644 target/linux/generic/patches-4.4/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
 create mode 100644 target/linux/generic/patches-4.4/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
 create mode 100644 target/linux/generic/patches-4.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
 create mode 100644 target/linux/generic/patches-4.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
 create mode 100644 target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch
 create mode 100644 target/linux/generic/patches-4.4/475-mtd-spi-nor-add-macronix-mx25u25635f.patch
 create mode 100644 target/linux/generic/patches-4.4/476-mtd-spi-nor-add-eon-en25q128.patch
 create mode 100644 target/linux/generic/patches-4.4/477-mtd-add-spi-nor-add-mx25u3235f.patch
 create mode 100644 target/linux/generic/patches-4.4/480-mtd-set-rootfs-to-be-root-dev.patch
 create mode 100644 target/linux/generic/patches-4.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
 create mode 100644 target/linux/generic/patches-4.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
 create mode 100644 target/linux/generic/patches-4.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
 create mode 100644 target/linux/generic/patches-4.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
 create mode 100644 target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch
 create mode 100644 target/linux/generic/patches-4.4/500-yaffs-Kbuild-integration.patch
 create mode 100644 target/linux/generic/patches-4.4/502-yaffs-fix-compat-tags-handling.patch
 create mode 100644 target/linux/generic/patches-4.4/503-yaffs-add-tags-9bytes-mount-option.patch
 create mode 100644 target/linux/generic/patches-4.4/504-yaffs-3.16-new-fops.patch
 create mode 100644 target/linux/generic/patches-4.4/505-yaffs-3.19-f_dentry-remove.patch
 create mode 100644 target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch
 create mode 100644 target/linux/generic/patches-4.4/530-jffs2_make_lzma_available.patch
 create mode 100644 target/linux/generic/patches-4.4/531-debloat_lzma.patch
 create mode 100644 target/linux/generic/patches-4.4/532-jffs2_eofdetect.patch
 create mode 100644 target/linux/generic/patches-4.4/540-crypto-xz-decompression-support.patch
 create mode 100644 target/linux/generic/patches-4.4/541-ubifs-xz-decompression-support.patch
 create mode 100644 target/linux/generic/patches-4.4/551-ubifs-fix-default-compression-selection.patch
 create mode 100644 target/linux/generic/patches-4.4/600-netfilter_conntrack_flush.patch
 create mode 100644 target/linux/generic/patches-4.4/610-netfilter_match_bypass_default_checks.patch
 create mode 100644 target/linux/generic/patches-4.4/611-netfilter_match_bypass_default_table.patch
 create mode 100644 target/linux/generic/patches-4.4/612-netfilter_match_reduce_memory_access.patch
 create mode 100644 target/linux/generic/patches-4.4/613-netfilter_optional_tcp_window_check.patch
 create mode 100644 target/linux/generic/patches-4.4/615-netfilter_add_xt_id_match.patch
 create mode 100644 target/linux/generic/patches-4.4/616-net_optimize_xfrm_calls.patch
 create mode 100644 target/linux/generic/patches-4.4/630-packet_socket_type.patch
 create mode 100644 target/linux/generic/patches-4.4/640-bridge_no_eap_forward.patch
 create mode 100644 target/linux/generic/patches-4.4/641-bridge_always_accept_eap.patch
 create mode 100644 target/linux/generic/patches-4.4/642-bridge_port_isolate.patch
 create mode 100644 target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch
 create mode 100644 target/linux/generic/patches-4.4/650-pppoe_header_pad.patch
 create mode 100644 target/linux/generic/patches-4.4/651-wireless_mesh_header.patch
 create mode 100644 target/linux/generic/patches-4.4/653-disable_netlink_trim.patch
 create mode 100644 target/linux/generic/patches-4.4/655-increase_skb_pad.patch
 create mode 100644 target/linux/generic/patches-4.4/660-fq_codel_defaults.patch
 create mode 100644 target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch
 create mode 100644 target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch
 create mode 100644 target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch
 create mode 100644 target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
 create mode 100644 target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
 create mode 100644 target/linux/generic/patches-4.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
 create mode 100644 target/linux/generic/patches-4.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
 create mode 100644 target/linux/generic/patches-4.4/681-NET-add-of_get_mac_address_mtd.patch
 create mode 100644 target/linux/generic/patches-4.4/700-swconfig.patch
 create mode 100644 target/linux/generic/patches-4.4/701-phy_extension.patch
 create mode 100644 target/linux/generic/patches-4.4/702-phy_add_aneg_done_function.patch
 create mode 100644 target/linux/generic/patches-4.4/703-phy-add-detach-callback-to-struct-phy_driver.patch
 create mode 100644 target/linux/generic/patches-4.4/704-phy-no-genphy-soft-reset.patch
 create mode 100644 target/linux/generic/patches-4.4/710-phy-add-mdio_register_board_info.patch
 create mode 100644 target/linux/generic/patches-4.4/720-phy_adm6996.patch
 create mode 100644 target/linux/generic/patches-4.4/721-phy_packets.patch
 create mode 100644 target/linux/generic/patches-4.4/722-phy_mvswitch.patch
 create mode 100644 target/linux/generic/patches-4.4/723-phy_ip175c.patch
 create mode 100644 target/linux/generic/patches-4.4/724-phy_ar8216.patch
 create mode 100644 target/linux/generic/patches-4.4/725-phy_rtl8306.patch
 create mode 100644 target/linux/generic/patches-4.4/726-phy_rtl8366.patch
 create mode 100644 target/linux/generic/patches-4.4/727-phy-rtl8367.patch
 create mode 100644 target/linux/generic/patches-4.4/728-phy-rtl8367b.patch
 create mode 100644 target/linux/generic/patches-4.4/729-phy-tantos.patch
 create mode 100644 target/linux/generic/patches-4.4/730-phy_b53.patch
 create mode 100644 target/linux/generic/patches-4.4/732-phy-ar8216-led-support.patch
 create mode 100644 target/linux/generic/patches-4.4/733-phy_mvsw61xx.patch
 create mode 100644 target/linux/generic/patches-4.4/734-net-phy-at803x-allow-to-configure-via-pdata.patch
 create mode 100644 target/linux/generic/patches-4.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
 create mode 100644 target/linux/generic/patches-4.4/736-at803x-fix-reset-handling.patch
 create mode 100644 target/linux/generic/patches-4.4/737-net-phy-at803x-Request-reset-GPIO-only-for-AT8030-PH.patch
 create mode 100644 target/linux/generic/patches-4.4/738-net-phy-at803x-only-the-AT8030-needs-a-hardware-rese.patch
 create mode 100644 target/linux/generic/patches-4.4/739-net-phy-at803x-add-support-for-AT8032.patch
 create mode 100644 target/linux/generic/patches-4.4/773-bgmac-add-srab-switch.patch
 create mode 100644 target/linux/generic/patches-4.4/785-hso-support-0af0-9300.patch
 create mode 100644 target/linux/generic/patches-4.4/810-pci_disable_common_quirks.patch
 create mode 100644 target/linux/generic/patches-4.4/811-pci_disable_usb_common_quirks.patch
 create mode 100644 target/linux/generic/patches-4.4/821-usb-Remove-annoying-warning-about-bogus-URB.patch
 create mode 100644 target/linux/generic/patches-4.4/831-ledtrig_netdev.patch
 create mode 100644 target/linux/generic/patches-4.4/834-ledtrig-libata.patch
 create mode 100644 target/linux/generic/patches-4.4/835-misc-owl_loader.patch
 create mode 100644 target/linux/generic/patches-4.4/840-rtc7301.patch
 create mode 100644 target/linux/generic/patches-4.4/841-rtc_pt7c4338.patch
 create mode 100644 target/linux/generic/patches-4.4/861-04_spi_gpio_implement_spi_delay.patch
 create mode 100644 target/linux/generic/patches-4.4/862-gpio_spi_driver.patch
 create mode 100644 target/linux/generic/patches-4.4/863-gpiommc.patch
 create mode 100644 target/linux/generic/patches-4.4/864-gpiommc_configfs_locking.patch
 create mode 100644 target/linux/generic/patches-4.4/870-hifn795x_byteswap.patch
 create mode 100644 target/linux/generic/patches-4.4/880-gateworks_system_controller.patch
 create mode 100644 target/linux/generic/patches-4.4/890-uart_optional_sysrq.patch
 create mode 100644 target/linux/generic/patches-4.4/901-debloat_sock_diag.patch
 create mode 100644 target/linux/generic/patches-4.4/902-debloat_proc.patch
 create mode 100644 target/linux/generic/patches-4.4/903-debloat_direct_io.patch
 create mode 100644 target/linux/generic/patches-4.4/904-debloat_dma_buf.patch
 create mode 100644 target/linux/generic/patches-4.4/910-kobject_uevent.patch
 create mode 100644 target/linux/generic/patches-4.4/911-kobject_add_broadcast_uevent.patch
 create mode 100644 target/linux/generic/patches-4.4/921-use_preinit_as_init.patch
 create mode 100644 target/linux/generic/patches-4.4/922-always-create-console-node-in-initramfs.patch
 create mode 100644 target/linux/generic/patches-4.4/930-crashlog.patch
 create mode 100644 target/linux/generic/patches-4.4/970-remove-unsane-filenames-from-deps_initramfs-list.patch
 create mode 100644 target/linux/generic/patches-4.4/980-arm_openwrt_machtypes.patch
 create mode 100644 target/linux/generic/patches-4.4/995-mangle_bootargs.patch
 create mode 100644 target/linux/generic/patches-4.4/998-enable_wilink_platform_without_drivers.patch
 create mode 100644 target/linux/sunxi/Makefile
 create mode 100755 target/linux/sunxi/base-files/etc/board.d/02_network
 create mode 100644 target/linux/sunxi/base-files/etc/inittab
 create mode 100644 target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac4329-sdio.txt
 create mode 100644 target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac43362-sdio.txt
 create mode 100644 target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh
 create mode 100644 target/linux/sunxi/base-files/lib/preinit/02_b53_hack.sh
 create mode 100644 target/linux/sunxi/base-files/lib/sunxi.sh
 create mode 100644 target/linux/sunxi/config-4.4
 create mode 100644 target/linux/sunxi/image/Config.in
 create mode 100644 target/linux/sunxi/image/Makefile
 create mode 100755 target/linux/sunxi/image/gen_sunxi_sdcard_img.sh
 create mode 100644 target/linux/sunxi/modules.mk
 create mode 100644 target/linux/sunxi/patches-4.4/100-clk-sunxi-add-dram-gates-support.patch
 create mode 100644 target/linux/sunxi/patches-4.4/101-dt-sun4i-add-dram-gates.patch
 create mode 100644 target/linux/sunxi/patches-4.4/102-dt-sun7i-add-dram-gates.patch
 create mode 100644 target/linux/sunxi/patches-4.4/103-clk-sunxi-add-h3-clksupport.patch
 create mode 100644 target/linux/sunxi/patches-4.4/104-1-dt-sunxi-add-h3-dtsi.patch
 create mode 100644 target/linux/sunxi/patches-4.4/104-2-dt-sun8i-add-orangepi-plus.patch
 create mode 100644 target/linux/sunxi/patches-4.4/105-phy-use_of_match_node.patch
 create mode 100644 target/linux/sunxi/patches-4.4/106-phy-add-h3-usbphys.patch
 create mode 100644 target/linux/sunxi/patches-4.4/107-clk-sunxi-add-h3-usbphy-clocks.patch
 create mode 100644 target/linux/sunxi/patches-4.4/110-clk-sunxi-add-ve-for-sun457i.patch
 create mode 100644 target/linux/sunxi/patches-4.4/111-1-dt-sun4i-add-ve-clock-module.patch
 create mode 100644 target/linux/sunxi/patches-4.4/111-2-dt-sun7i-add-ve-clock-module.patch
 create mode 100644 target/linux/sunxi/patches-4.4/115-musb-ignore-vbus-errors.patch
 create mode 100644 target/linux/sunxi/patches-4.4/130-pinctrl-sunxi-add-h3-pio.patch
 create mode 100644 target/linux/sunxi/patches-4.4/131-reset-add-h3-resets.patch
 create mode 100644 target/linux/sunxi/patches-4.4/132-dt-sun8i-add-h3-usbclocks.patch
 create mode 100644 target/linux/sunxi/patches-4.4/133-dt-sun8i-add-usbphy-usbhost-ctrl-nodes.patch
 create mode 100644 target/linux/sunxi/patches-4.4/134-dt-sun8i-orangepiplus-enable-usbhost.patch
 create mode 100644 target/linux/sunxi/patches-4.4/135-clk-sunxi-fix-signedness-bug.patch
 create mode 100644 target/linux/sunxi/patches-4.4/140-reset-add-of_reset_control_get_by_index.patch
 create mode 100644 target/linux/sunxi/patches-4.4/141-reset-fix-of_reset_control_get.patch
 create mode 100644 target/linux/sunxi/patches-4.4/142-reset-use-ENOTSUPP-instead-of-ENOSYS.patch
 create mode 100644 target/linux/sunxi/patches-4.4/143-reset-add-shared-resetcontrol-asserts.patch
 create mode 100644 target/linux/sunxi/patches-4.4/144-usb-ehci-plat-support-multiple-reset-ctrllines.patch
 create mode 100644 target/linux/sunxi/patches-4.4/145-usb-ohci-plat-support-multiple-reset-ctrllines.patch
 create mode 100644 target/linux/sunxi/patches-4.4/150-dt-sun7i-enable-codec-on-pcduino3.patch
 create mode 100644 target/linux/sunxi/patches-4.4/200-dt-sun7i-add-lamobo-r1.patch
 create mode 100644 target/linux/sunxi/profiles/01-default.mk
 create mode 100644 target/linux/sunxi/profiles/a10-olinuxino.mk
 create mode 100644 target/linux/sunxi/profiles/a13-olimex-som.mk
 create mode 100644 target/linux/sunxi/profiles/a13-olinuxino.mk
 create mode 100644 target/linux/sunxi/profiles/a20-olinuxino.mk
 create mode 100644 target/linux/sunxi/profiles/bananapi.mk
 create mode 100644 target/linux/sunxi/profiles/bananapro.mk
 create mode 100644 target/linux/sunxi/profiles/cubieboard.mk
 create mode 100644 target/linux/sunxi/profiles/cubieboard2.mk
 create mode 100644 target/linux/sunxi/profiles/cubietruck.mk
 create mode 100644 target/linux/sunxi/profiles/lamobo-r1.mk
 create mode 100644 target/linux/sunxi/profiles/mele_m9.mk
 create mode 100644 target/linux/sunxi/profiles/orangepi_plus.mk
 create mode 100644 target/linux/sunxi/profiles/pcduino.mk
 create mode 100644 target/linux/sunxi/profiles/pcduino3.mk
 create mode 100644 target/linux/uml/Makefile
 create mode 100644 target/linux/uml/README
 create mode 100644 target/linux/uml/base-files/etc/inittab
 create mode 100644 target/linux/uml/config/i386
 create mode 100644 target/linux/uml/config/x86_64
 create mode 100644 target/linux/uml/image/Makefile
 create mode 100644 target/linux/uml/patches-4.4/101-mconsole-exec.patch
 create mode 100644 target/linux/uml/patches-4.4/102-pseudo-random-mac.patch
 create mode 100644 target/linux/x86/64/config-default
 create mode 100644 target/linux/x86/64/profiles/000-Generic.mk
 create mode 100644 target/linux/x86/64/target.mk
 create mode 100644 target/linux/x86/Makefile
 create mode 100644 target/linux/x86/base-files/etc/inittab
 create mode 100644 target/linux/x86/base-files/lib/preinit/15_essential_fs_x86
 create mode 100644 target/linux/x86/base-files/lib/preinit/20_check_iso
 create mode 100644 target/linux/x86/base-files/lib/preinit/20_sysinfo
 create mode 100644 target/linux/x86/base-files/lib/preinit/79_move_config
 create mode 100644 target/linux/x86/base-files/lib/upgrade/platform.sh
 create mode 100644 target/linux/x86/config-4.4
 create mode 100644 target/linux/x86/generic/config-default
 create mode 100644 target/linux/x86/generic/profiles/000-Generic.mk
 create mode 100644 target/linux/x86/generic/target.mk
 create mode 100644 target/linux/x86/geode/config-default
 create mode 100644 target/linux/x86/geode/target.mk
 create mode 100644 target/linux/x86/image/Makefile
 create mode 100755 target/linux/x86/image/gen_image_generic.sh
 create mode 100644 target/linux/x86/image/grub-early.cfg
 create mode 100644 target/linux/x86/image/grub-iso.cfg
 create mode 100644 target/linux/x86/image/grub.cfg
 create mode 100644 target/linux/x86/legacy/config-default
 create mode 100644 target/linux/x86/legacy/profiles/000-Generic.mk
 create mode 100644 target/linux/x86/legacy/target.mk
 create mode 100644 target/linux/x86/patches-4.4/011-tune_lzma_options.patch
 create mode 100644 target/linux/x86/patches-4.4/100-fix_cs5535_clockevt.patch
 create mode 100644 target/linux/x86/xen_domu/base-files/etc/inittab
 create mode 100644 target/linux/x86/xen_domu/base-files/lib/preinit/45_mount_xenfs
 create mode 100644 target/linux/x86/xen_domu/config-default
 create mode 100644 target/linux/x86/xen_domu/profiles/000-Generic.mk
 create mode 100644 target/linux/x86/xen_domu/target.mk
 create mode 100644 target/linux/xburst/Makefile
 create mode 100755 target/linux/xburst/base-files/etc/board.d/01_system
 create mode 100644 target/linux/xburst/base-files/etc/config/fstab
 create mode 100644 target/linux/xburst/base-files/etc/config/network
 create mode 100644 target/linux/xburst/config-3.18
 create mode 100644 target/linux/xburst/image/Makefile
 create mode 100644 target/linux/xburst/image/ubinize.cfg
 create mode 100644 target/linux/xburst/modules.mk
 create mode 100644 target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch
 create mode 100644 target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch
 create mode 100644 target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch
 create mode 100644 target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch
 create mode 100644 target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch
 create mode 100644 target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch
 create mode 100644 target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch
 create mode 100644 target/linux/xburst/qi_lb60/config-default
 create mode 100644 target/linux/xburst/qi_lb60/target.mk
 create mode 100644 target/sdk/Config.in
 create mode 100644 target/sdk/Makefile
 create mode 100755 target/sdk/convert-config.pl
 create mode 100644 target/sdk/files/Config.in
 create mode 100644 target/sdk/files/Makefile
 create mode 100644 target/sdk/files/README.SDK
 create mode 100644 target/sdk/files/include/prepare.mk
 create mode 100644 target/toolchain/Config.in
 create mode 100644 target/toolchain/Makefile
 create mode 100644 target/toolchain/files/README.TOOLCHAIN
 create mode 100755 target/toolchain/files/wrapper.sh
 create mode 100644 toolchain/Config.in
 create mode 100644 toolchain/Makefile
 create mode 100644 toolchain/binutils/Config.in
 create mode 100644 toolchain/binutils/Config.version
 create mode 100644 toolchain/binutils/Makefile
 create mode 100644 toolchain/binutils/patches/2.25.1/300-001_ld_makefile_patch.patch
 create mode 100644 toolchain/binutils/patches/2.25.1/300-012_check_ldrunpath_length.patch
 create mode 100644 toolchain/binutils/patches/2.25.1/400-mips_no_dynamic_linking_sym.patch
 create mode 100644 toolchain/binutils/patches/2.25.1/500-Change-default-emulation-for-mips64-linux.patch
 create mode 100644 toolchain/binutils/patches/2.27/300-001_ld_makefile_patch.patch
 create mode 100644 toolchain/binutils/patches/2.27/300-012_check_ldrunpath_length.patch
 create mode 100644 toolchain/binutils/patches/2.27/400-mips_no_dynamic_linking_sym.patch
 create mode 100644 toolchain/binutils/patches/2.27/500-Change-default-emulation-for-mips64-linux.patch
 create mode 100644 toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch
 create mode 100644 toolchain/fortify-headers/Makefile
 create mode 100644 toolchain/gcc/Config.in
 create mode 100644 toolchain/gcc/Config.version
 create mode 100644 toolchain/gcc/common.mk
 create mode 100644 toolchain/gcc/files/alternate-arch-cc.in
 create mode 100644 toolchain/gcc/final/Makefile
 create mode 100644 toolchain/gcc/initial/Makefile
 create mode 100644 toolchain/gcc/minimal/Makefile
 create mode 100644 toolchain/gcc/patches/5.4.0/001-revert_register_mode_search.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/002-case_insensitive.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/010-documentation.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/020-no-plt-backport.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/040-fix-mips-ICE-PR-68400.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/100-uclibc-conf.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/200-musl_config.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/201-musl_arm.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/202-musl_mips.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/203-musl_powerpc.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/204-musl_sh.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/205-musl_x86.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/206-musl_aarch64.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/207-musl_fixincludes.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/209-musl_libstdc++.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/230-musl_libssp.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/240-musl-libitm-fixes.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/250-add-musl.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/260-musl-add-unwind-fix.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/270-musl-add-powerpc-softfloat-fix.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/280-musl-disable-ifunc-by-default.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/300-mips_Os_cpu_rtx_cost_model.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/800-arm_v5te_no_ldrd_strd.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/810-arm-softfloat-libgcc.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/820-libgcc_pic.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/830-arm_unbreak_armv4t.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/840-armv4_pass_fix-v4bx_to_ld.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/850-use_shared_libgcc.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/851-libgcc_no_compat.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/870-ppc_no_crtsavres.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/880-no_java_section.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/900-bad-mips16-crt.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/910-mbsd_multi.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/920-specs_nonfatal_getenv.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/930-fix-mips-noexecstack.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/931-fix-MIPS-softfloat-build-issue.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/940-no-clobber-stamp-bits.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/950-cpp_file_path_translation.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/960-go_libm.patch
 create mode 100644 toolchain/gcc/patches/5.4.0/970-warn_bug.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/001-revert_register_mode_search.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/002-case_insensitive.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/010-documentation.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/100-uclibc-conf.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/230-musl_libssp.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/280-musl-disable-ifunc-by-default.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/300-mips_Os_cpu_rtx_cost_model.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/800-arm_v5te_no_ldrd_strd.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/810-arm-softfloat-libgcc.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/820-libgcc_pic.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/830-arm_unbreak_armv4t.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/840-armv4_pass_fix-v4bx_to_ld.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/850-use_shared_libgcc.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/851-libgcc_no_compat.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/870-ppc_no_crtsavres.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/880-no_java_section.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/900-bad-mips16-crt.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/910-mbsd_multi.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/920-specs_nonfatal_getenv.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/930-fix-mips-noexecstack.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/940-no-clobber-stamp-bits.patch
 create mode 100644 toolchain/gcc/patches/6.2.0/950-cpp_file_path_translation.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/010-documentation.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch
 create mode 100644 toolchain/gcc/patches/arc-2016.03/950-fix-building-with-gcc6.patch
 create mode 100644 toolchain/gdb/Makefile
 create mode 100644 toolchain/gdb/patches-arc/100-no_extern_inline.patch
 create mode 100644 toolchain/gdb/patches-arc/110-no_testsuite.patch
 create mode 100644 toolchain/gdb/patches-arc/120-fix-compile-flag-mismatch.patch
 create mode 100644 toolchain/gdb/patches/100-no_extern_inline.patch
 create mode 100644 toolchain/gdb/patches/110-no_testsuite.patch
 create mode 100644 toolchain/gdb/patches/120-fix-compile-flag-mismatch.patch
 create mode 100644 toolchain/glibc/Config.in
 create mode 100644 toolchain/glibc/Config.version
 create mode 100644 toolchain/glibc/Makefile
 create mode 100644 toolchain/glibc/common.mk
 create mode 100644 toolchain/glibc/headers/Makefile
 create mode 100644 toolchain/glibc/include/libintl.h
 create mode 100644 toolchain/glibc/patches/2.24/100-fix_cross_rpcgen.patch
 create mode 100644 toolchain/glibc/patches/2.24/200-add-dl-search-paths.patch
 create mode 100644 toolchain/info.mk
 create mode 100644 toolchain/insight/Makefile
 create mode 100644 toolchain/insight/patches/600-fix-compile-flag-mismatch.patch
 create mode 100644 toolchain/kernel-headers/Makefile
 create mode 100644 toolchain/musl/Config.version
 create mode 100644 toolchain/musl/Makefile
 create mode 100644 toolchain/musl/common.mk
 create mode 100644 toolchain/musl/include/bits/wordsize.h
 create mode 100644 toolchain/musl/include/features.h
 create mode 100644 toolchain/musl/include/sgidefs.h
 create mode 100644 toolchain/musl/include/sys/cdefs.h
 create mode 100644 toolchain/musl/include/sys/glibc-types.h
 create mode 100644 toolchain/musl/include/sys/queue.h
 create mode 100644 toolchain/musl/patches/010-fix-regression-in-tcsetattr-on-all-mips-archs.patch
 create mode 100644 toolchain/musl/patches/040-Add-format-attribute-to-some-function-declarations.patch
 create mode 100644 toolchain/musl/patches/100-add_glob_onlydir.patch
 create mode 100644 toolchain/musl/patches/110-read_timezone_from_fs.patch
 create mode 100644 toolchain/musl/patches/200-add_libssp_nonshared.patch
 create mode 100644 toolchain/musl/patches/300-relative.patch
 create mode 100644 toolchain/musl/patches/400-fix_quoted_timezone.patch
 create mode 100644 toolchain/musl/patches/900-iconv_size_hack.patch
 create mode 100644 toolchain/musl/patches/901-crypt_size_hack.patch
 create mode 100644 toolchain/uClibc/Config.in
 create mode 100644 toolchain/uClibc/Config.version
 create mode 100644 toolchain/uClibc/Makefile
 create mode 100644 toolchain/uClibc/common.mk
 create mode 100644 toolchain/uClibc/config/arc
 create mode 100644 toolchain/uClibc/config/archs
 create mode 100644 toolchain/uClibc/config/arm
 create mode 100644 toolchain/uClibc/config/armeb
 create mode 100644 toolchain/uClibc/config/common
 create mode 100644 toolchain/uClibc/config/debug
 create mode 100644 toolchain/uClibc/config/i386
 create mode 100644 toolchain/uClibc/config/i686
 create mode 100644 toolchain/uClibc/config/m68k
 create mode 100644 toolchain/uClibc/config/mips
 create mode 100644 toolchain/uClibc/config/mips64
 create mode 100644 toolchain/uClibc/config/mips64.32
 create mode 100644 toolchain/uClibc/config/mips64.64
 create mode 100644 toolchain/uClibc/config/mips64.n32
 create mode 100644 toolchain/uClibc/config/mips64el
 create mode 100644 toolchain/uClibc/config/mips64el.32
 create mode 100644 toolchain/uClibc/config/mips64el.64
 create mode 100644 toolchain/uClibc/config/mips64el.n32
 create mode 100644 toolchain/uClibc/config/mipsel
 create mode 100644 toolchain/uClibc/config/mipsel.cobalt
 create mode 100644 toolchain/uClibc/config/powerpc
 create mode 100644 toolchain/uClibc/config/powerpc.e500
 create mode 100644 toolchain/uClibc/config/sparc
 create mode 100644 toolchain/uClibc/config/sparc.leon
 create mode 100644 toolchain/uClibc/config/x86_64
 create mode 100644 toolchain/uClibc/headers/Makefile
 create mode 100644 toolchain/uClibc/utils/Makefile
 create mode 100644 toolchain/wrapper/Makefile
 create mode 100644 toolchain/yasm/Makefile
 create mode 100644 tools/Makefile
 create mode 100644 tools/autoconf/Makefile
 create mode 100644 tools/autoconf/patches/000-relocatable.patch
 create mode 100644 tools/autoconf/patches/001-no_emacs_lib.patch
 create mode 100644 tools/autoconf/patches/002-musl_host_fixup.patch
 create mode 100644 tools/automake/Makefile
 create mode 100755 tools/automake/files/aclocal
 create mode 100644 tools/automake/patches/000-relocatable.patch
 create mode 100644 tools/automake/patches/100-aclocal-skip-not-existing-directories.patch
 create mode 100644 tools/automake/patches/200-do-not-override-silent-rules.patch
 create mode 100644 tools/bc/Makefile
 create mode 100644 tools/bc/patches/001-no_doc.patch
 create mode 100644 tools/bison/Makefile
 create mode 100644 tools/bison/patches/010-intl-stub-compat.patch
 create mode 100644 tools/bison/patches/100-fix-gets-removal.patch
 create mode 100755 tools/bison/scripts/yacc
 create mode 100644 tools/ccache/Makefile
 create mode 100755 tools/ccache/files/ccache_cc
 create mode 100755 tools/ccache/files/ccache_cxx
 create mode 100644 tools/ccache/patches/100-honour-copts.patch
 create mode 100644 tools/ccache/patches/110-disable-assembler-support.patch
 create mode 100644 tools/cloog/Makefile
 create mode 100644 tools/cmake/Makefile
 create mode 100644 tools/cmake/patches/100-disable_qt_tests.patch
 create mode 100644 tools/cmake/patches/110-freebsd-compat.patch
 create mode 100644 tools/cmake/patches/120-alpine_musl-compat.patch
 create mode 100644 tools/cmake/patches/130-upstream-libarchive-openssl-compat-headers.patch
 create mode 100644 tools/cmake/patches/140-upstream-libarchive-openssl-1.1.x-support.patch
 create mode 100644 tools/cmake/patches/150-libarchive-fix-libressl-compat.patch
 create mode 100644 tools/coreutils/Makefile
 create mode 100644 tools/dosfstools/Makefile
 create mode 100644 tools/dosfstools/patches/0001-mkfs-Default-to-64-32-heads-sectors-for-targets-smal.patch
 create mode 100644 tools/dosfstools/patches/0002-Switch-to-AC_CHECK_LIB-for-iconv-library-linking.patch
 create mode 100644 tools/e2fsprogs/Makefile
 create mode 100644 tools/e2fsprogs/patches/001-exit_0_on_corrected_errors.patch
 create mode 100644 tools/e2fsprogs/patches/002-dont-build-e4defrag.patch
 create mode 100644 tools/e2fsprogs/patches/003-openbsd-compat.patch
 create mode 100644 tools/e2fsprogs/patches/004-freebsd-compat.patch
 create mode 100644 tools/e2fsprogs/patches/005-darwin-compat.patch
 create mode 100644 tools/e2fsprogs/patches/010-old-libmagic.patch
 create mode 100644 tools/elftosb/Makefile
 create mode 100644 tools/elftosb/patches/001-libm.patch
 create mode 100644 tools/elftosb/patches/002-fix-header-path.patch
 create mode 100644 tools/elftosb/patches/003-use-ldflags.patch
 create mode 100644 tools/expat/Makefile
 create mode 100644 tools/findutils/Makefile
 create mode 100644 tools/firmware-utils/Makefile
 create mode 100644 tools/firmware-utils/src/add_header.c
 create mode 100644 tools/firmware-utils/src/addpattern.c
 create mode 100644 tools/firmware-utils/src/asustrx.c
 create mode 100644 tools/firmware-utils/src/bcm_tag.h
 create mode 100644 tools/firmware-utils/src/bcmalgo.c
 create mode 100644 tools/firmware-utils/src/bcmalgo.h
 create mode 100644 tools/firmware-utils/src/buffalo-enc.c
 create mode 100644 tools/firmware-utils/src/buffalo-lib.c
 create mode 100644 tools/firmware-utils/src/buffalo-lib.h
 create mode 100644 tools/firmware-utils/src/buffalo-tag.c
 create mode 100644 tools/firmware-utils/src/buffalo-tftp.c
 create mode 100644 tools/firmware-utils/src/csysimg.h
 create mode 100644 tools/firmware-utils/src/cyg_crc.h
 create mode 100644 tools/firmware-utils/src/cyg_crc16.c
 create mode 100644 tools/firmware-utils/src/cyg_crc32.c
 create mode 100644 tools/firmware-utils/src/dgfirmware.c
 create mode 100644 tools/firmware-utils/src/dgn3500sum.c
 create mode 100644 tools/firmware-utils/src/edimax_fw_header.c
 create mode 100644 tools/firmware-utils/src/encode_crc.c
 create mode 100644 tools/firmware-utils/src/fix-u-media-header.c
 create mode 100644 tools/firmware-utils/src/fw.h
 create mode 100644 tools/firmware-utils/src/hcsmakeimage.c
 create mode 100644 tools/firmware-utils/src/imagetag.c
 create mode 100644 tools/firmware-utils/src/imagetag.ggo
 create mode 100644 tools/firmware-utils/src/imagetag_cmdline.c
 create mode 100644 tools/firmware-utils/src/imagetag_cmdline.h
 create mode 100644 tools/firmware-utils/src/jcgimage.c
 create mode 100644 tools/firmware-utils/src/lzma2eva.c
 create mode 100644 tools/firmware-utils/src/makeamitbin.c
 create mode 100644 tools/firmware-utils/src/md5.c
 create mode 100644 tools/firmware-utils/src/md5.h
 create mode 100644 tools/firmware-utils/src/mkbrncmdline.c
 create mode 100644 tools/firmware-utils/src/mkbrnimg.c
 create mode 100644 tools/firmware-utils/src/mkbuffaloimg.c
 create mode 100644 tools/firmware-utils/src/mkcameofw.c
 create mode 100644 tools/firmware-utils/src/mkcasfw.c
 create mode 100644 tools/firmware-utils/src/mkchkimg.c
 create mode 100644 tools/firmware-utils/src/mkcsysimg.c
 create mode 100644 tools/firmware-utils/src/mkdapimg.c
 create mode 100644 tools/firmware-utils/src/mkdcs932.c
 create mode 100644 tools/firmware-utils/src/mkdniimg.c
 create mode 100644 tools/firmware-utils/src/mkedimaximg.c
 create mode 100644 tools/firmware-utils/src/mkfwimage.c
 create mode 100644 tools/firmware-utils/src/mkfwimage2.c
 create mode 100644 tools/firmware-utils/src/mkheader_gemtek.c
 create mode 100644 tools/firmware-utils/src/mkhilinkfw.c
 create mode 100644 tools/firmware-utils/src/mkmerakifw-old.c
 create mode 100644 tools/firmware-utils/src/mkmerakifw.c
 create mode 100644 tools/firmware-utils/src/mkmylofw.c
 create mode 100644 tools/firmware-utils/src/mkplanexfw.c
 create mode 100644 tools/firmware-utils/src/mkporayfw.c
 create mode 100644 tools/firmware-utils/src/mkrtn56uimg.c
 create mode 100644 tools/firmware-utils/src/mksenaofw.c
 create mode 100644 tools/firmware-utils/src/mktitanimg.c
 create mode 100644 tools/firmware-utils/src/mktitanimg.h
 create mode 100644 tools/firmware-utils/src/mktplinkfw.c
 create mode 100644 tools/firmware-utils/src/mktplinkfw2.c
 create mode 100644 tools/firmware-utils/src/mkwrggimg.c
 create mode 100644 tools/firmware-utils/src/mkwrgimg.c
 create mode 100644 tools/firmware-utils/src/mkzcfw.c
 create mode 100644 tools/firmware-utils/src/mkzynfw.c
 create mode 100644 tools/firmware-utils/src/motorola-bin.c
 create mode 100644 tools/firmware-utils/src/myloader.h
 create mode 100644 tools/firmware-utils/src/nand_ecc.c
 create mode 100644 tools/firmware-utils/src/osbridge-crc.c
 create mode 100644 tools/firmware-utils/src/oseama.c
 create mode 100644 tools/firmware-utils/src/pc1crypt.c
 create mode 100644 tools/firmware-utils/src/ptgen.c
 create mode 100644 tools/firmware-utils/src/seama.c
 create mode 100644 tools/firmware-utils/src/seama.h
 create mode 100644 tools/firmware-utils/src/sha1.c
 create mode 100644 tools/firmware-utils/src/sha1.h
 create mode 100644 tools/firmware-utils/src/spw303v.c
 create mode 100644 tools/firmware-utils/src/srec2bin.c
 create mode 100644 tools/firmware-utils/src/tplink-safeloader.c
 create mode 100644 tools/firmware-utils/src/trx.c
 create mode 100644 tools/firmware-utils/src/trx2edips.c
 create mode 100644 tools/firmware-utils/src/trx2usr.c
 create mode 100644 tools/firmware-utils/src/wrt400n.c
 create mode 100644 tools/firmware-utils/src/xorimage.c
 create mode 100644 tools/firmware-utils/src/zyimage.c
 create mode 100644 tools/firmware-utils/src/zynos.h
 create mode 100644 tools/firmware-utils/src/zyxbcm.c
 create mode 100644 tools/flex/Makefile
 create mode 100644 tools/flex/patches/100-disable-tests-docs.patch
 create mode 100644 tools/flock/Makefile
 create mode 100644 tools/flock/src/flock.c
 create mode 100644 tools/genext2fs/Makefile
 create mode 100644 tools/genext2fs/patches/100-c99_scanf.patch
 create mode 100644 tools/genext2fs/patches/200-autoconf.patch
 create mode 100644 tools/genext2fs/patches/300-blocksize-creator.patch
 create mode 100644 tools/genext2fs/patches/400-byteswap_fix.patch
 create mode 100644 tools/gengetopt/Makefile
 create mode 100644 tools/gengetopt/patches/100-dependency_fix.patch
 create mode 100644 tools/gengetopt/patches/200-no_docs_tests.patch
 create mode 100644 tools/gmp/Makefile
 create mode 100644 tools/include/byteswap.h
 create mode 100644 tools/include/elf.h
 create mode 100644 tools/include/endian.h
 create mode 100644 tools/include/getline.h
 create mode 100644 tools/include/sys/sysmacros.h
 create mode 100644 tools/isl/Makefile
 create mode 100644 tools/kernel2minor/Makefile
 create mode 100644 tools/libelf/Makefile
 create mode 100644 tools/libressl/Makefile
 create mode 100644 tools/libtool/Makefile
 create mode 100644 tools/libtool/files/libtool-v1.5.patch
 create mode 100644 tools/libtool/files/libtool-v2.2.patch
 create mode 100644 tools/libtool/files/libtool-v2.4.patch
 create mode 100644 tools/libtool/patches/000-relocatable.patch
 create mode 100644 tools/libtool/patches/001-fix-func_append.patch
 create mode 100644 tools/libtool/patches/100-libdir-fixes.patch
 create mode 100644 tools/libtool/patches/110-dont-use-target-dir-for-relinking.patch
 create mode 100644 tools/libtool/patches/120-strip-unsafe-dirs-for-relinking.patch
 create mode 100644 tools/libtool/patches/150-trailingslash.patch
 create mode 100644 tools/libtool/patches/160-passthrough-ssp.patch
 create mode 100644 tools/libtool/patches/200-openwrt-branding.patch
 create mode 100644 tools/lzma-old/Makefile
 create mode 100644 tools/lzma-old/patches/100-lzma_zlib.patch
 create mode 100644 tools/lzma-old/patches/110-ranlib.patch
 create mode 100644 tools/lzma/Makefile
 create mode 100644 tools/lzma/patches/001-large_files.patch
 create mode 100644 tools/lzma/patches/002-lzmp.patch
 create mode 100644 tools/lzma/patches/003-compile_fixes.patch
 create mode 100644 tools/lzma/patches/100-static_library.patch
 create mode 100644 tools/lzma/patches/101-move-copyright-to-usage-info.patch
 create mode 100644 tools/m4/Makefile
 create mode 100644 tools/m4/patches/100-fix-gets-removal.patch
 create mode 100644 tools/make-ext4fs/Makefile
 create mode 100644 tools/missing-macros/Makefile
 create mode 100644 tools/missing-macros/src/README
 create mode 100755 tools/missing-macros/src/bin/help2man
 create mode 100755 tools/missing-macros/src/bin/makeinfo
 create mode 100644 tools/missing-macros/src/m4/as-ac-expand.m4
 create mode 100644 tools/missing-macros/src/m4/as-compiler-flag.m4
 create mode 100644 tools/missing-macros/src/m4/as-unaligned-access.m4
 create mode 100644 tools/missing-macros/src/m4/as-version.m4
 create mode 100644 tools/missing-macros/src/m4/dnet.m4
 create mode 100644 tools/missing-macros/src/m4/fake-gtk-doc-check.m4
 create mode 100644 tools/missing-macros/src/m4/fake-intltool.m4
 create mode 100644 tools/missing-macros/src/m4/glibc2.m4
 create mode 100644 tools/missing-macros/src/m4/glibc21.m4
 create mode 100644 tools/missing-macros/src/m4/intdiv0.m4
 create mode 100644 tools/missing-macros/src/m4/intmax.m4
 create mode 100644 tools/missing-macros/src/m4/inttypes-pri.m4
 create mode 100644 tools/missing-macros/src/m4/inttypes_h.m4
 create mode 100644 tools/missing-macros/src/m4/lib-ld.m4
 create mode 100644 tools/missing-macros/src/m4/lib-link.m4
 create mode 100644 tools/missing-macros/src/m4/lib-prefix.m4
 create mode 100644 tools/missing-macros/src/m4/mfx_acc.m4
 create mode 100644 tools/missing-macros/src/m4/mfx_cppflags.m4
 create mode 100644 tools/missing-macros/src/m4/mfx_limits.m4
 create mode 100644 tools/missing-macros/src/m4/progtest.m4
 create mode 100644 tools/missing-macros/src/m4/stdint_h.m4
 create mode 100644 tools/missing-macros/src/m4/uintmax_t.m4
 create mode 100644 tools/missing-macros/src/m4/va_copy.m4
 create mode 100644 tools/missing-macros/src/m4/wint_t.m4
 create mode 100644 tools/mkimage/Makefile
 create mode 100644 tools/mkimage/patches/010-freebsd-ulong-fix.patch
 create mode 100644 tools/mkimage/patches/020-include_compile_fix.patch
 create mode 100644 tools/mkimage/patches/030-allow-to-use-different-magic.patch
 create mode 100644 tools/mkimage/patches/040-include_order.patch
 create mode 100644 tools/mkimage/patches/050-image_h_portability.patch
 create mode 100644 tools/mkimage/patches/060-remove_kernel_includes.patch
 create mode 100644 tools/mkimage/patches/070-socfpgaimage_portability.patch
 create mode 100644 tools/mkimage/patches/080-remove_compiler_check.patch
 create mode 100644 tools/mkimage/patches/090-reproducible-SOURCE_DATE_EPOCH.patch
 create mode 100644 tools/mkimage/patches/100-freebsd-compat.patch
 create mode 100644 tools/mkimage/patches/200-compiler-support.patch
 create mode 100644 tools/mkimage/patches/210-openssl-1.1.x-compat.patch
 create mode 100644 tools/mklibs/Makefile
 create mode 100644 tools/mklibs/include/elf.h
 create mode 100644 tools/mklibs/patches/001-compile.patch
 create mode 100644 tools/mklibs/patches/002-disable_symbol_checks.patch
 create mode 100644 tools/mklibs/patches/003-no_copy.patch
 create mode 100644 tools/mklibs/patches/004-libpthread_link.patch
 create mode 100644 tools/mklibs/patches/005-duplicate_syms.patch
 create mode 100644 tools/mklibs/patches/006-uclibc_init.patch
 create mode 100644 tools/mklibs/patches/007-gc_sections.patch
 create mode 100644 tools/mklibs/patches/008-uclibc_libgcc_link.patch
 create mode 100644 tools/mklibs/patches/009-uclibc_libpthread_symbols.patch
 create mode 100644 tools/mklibs/patches/010-remove_STT_GNU_IFUNC.patch
 create mode 100644 tools/mklibs/patches/011-remove_multiarch.patch
 create mode 100644 tools/mm-macros/Makefile
 create mode 100644 tools/mpc/Makefile
 create mode 100644 tools/mpfr/Makefile
 create mode 100644 tools/mpfr/patches/001-only_src.patch
 create mode 100644 tools/mpfr/patches/100-freebsd-compat.patch
 create mode 100644 tools/mtd-utils/Makefile
 create mode 100644 tools/mtd-utils/include/fls.h
 create mode 100644 tools/mtd-utils/include/linux/types.h
 create mode 100644 tools/mtd-utils/patches/100-sscanf_fix.patch
 create mode 100644 tools/mtd-utils/patches/110-portability.patch
 create mode 100644 tools/mtd-utils/patches/130-lzma_jffs2.patch
 create mode 100644 tools/mtd-utils/patches/134-freebsd_loff_t.patch
 create mode 100644 tools/mtd-utils/patches/135-mkubifs_optional_lzo.patch
 create mode 100644 tools/mtd-utils/patches/136-mkfs.ubifs-xz-support.patch
 create mode 100644 tools/mtd-utils/patches/200-libubigen-add-ubigen_write_terminator-function.patch
 create mode 100644 tools/mtd-utils/patches/201-ubinize-add-terminator-support.patch
 create mode 100644 tools/mtd-utils/patches/310-add-static-linking-option.patch
 create mode 100644 tools/mtools/Makefile
 create mode 100644 tools/mtools/patches/100-compile_fix.patch
 create mode 100644 tools/padjffs2/Makefile
 create mode 100644 tools/padjffs2/src/Makefile
 create mode 100644 tools/padjffs2/src/padjffs2.c
 create mode 100644 tools/patch-image/Makefile
 create mode 100644 tools/patch-image/src/patch-cmdline.c
 create mode 100644 tools/patch-image/src/patch-dtb.c
 create mode 100644 tools/patch/Makefile
 create mode 100644 tools/patchelf/Makefile
 create mode 100644 tools/pkg-config/Makefile
 create mode 100755 tools/pkg-config/files/pkg-config
 create mode 100644 tools/pkg-config/patches/001-glib-gdate-suppress-string-format-literal-warning.patch
 create mode 100644 tools/ppl/Makefile
 create mode 100644 tools/ppl/patches/001-disable-serial-tests.patch
 create mode 100644 tools/qemu/Makefile
 create mode 100644 tools/quilt/Makefile
 create mode 100644 tools/quilt/patches/000-relocatable.patch
 create mode 100644 tools/quilt/patches/001-fix_compile.patch
 create mode 100644 tools/scons/Makefile
 create mode 100755 tools/scons/files/pywrap.sh
 create mode 100644 tools/scons/patches/001-platform_env.patch
 create mode 100644 tools/sdimage/Makefile
 create mode 100644 tools/sed/Makefile
 create mode 100644 tools/sed/patches/001-musl_host_fixup.patch
 create mode 100644 tools/sparse/Makefile
 create mode 100644 tools/squashfs/Makefile
 create mode 100644 tools/squashfs/patches/100-lzma.patch
 create mode 100644 tools/squashfs/patches/110-no_nonstatic_inline.patch
 create mode 100644 tools/squashfs/patches/120-add-fixed-timestamp-support.patch
 create mode 100644 tools/squashfs4/Makefile
 create mode 100644 tools/squashfs4/patches/100-portability.patch
 create mode 100644 tools/squashfs4/patches/110-allow_static_liblzma.patch
 create mode 100644 tools/squashfs4/patches/120-cygwin_fixes.patch
 create mode 100644 tools/squashfs4/patches/150-freebsd_fixes.patch
 create mode 100644 tools/squashfs4/patches/160-expose_lzma_xz_options.patch
 create mode 100644 tools/squashfs4/patches/170-add_support_for_LZMA_MAGIC_to_unsqashfs.patch
 create mode 100644 tools/squashfs4/patches/180-openbsd_compat.patch
 create mode 100644 tools/squashfs4/patches/190-no_nonstatic_inline.patch
 create mode 100644 tools/squashfs4/patches/200-add-fixed-timestamp-option.patch
 create mode 100644 tools/sstrip/Makefile
 create mode 100644 tools/sstrip/src/sstrip.c
 create mode 100644 tools/tar/Makefile
 create mode 100644 tools/upslug2/Makefile
 create mode 100644 tools/upslug2/patches/100-libpcap_fix.patch
 create mode 100644 tools/upslug2/patches/110-wrt350nv2_support.patch
 create mode 100644 tools/upx/Makefile
 create mode 100644 tools/upx/patches/100-lzmaonly.patch
 create mode 100644 tools/wrt350nv2-builder/Makefile
 create mode 100644 tools/wrt350nv2-builder/src/crypt.h
 create mode 100644 tools/wrt350nv2-builder/src/ioapi.c
 create mode 100644 tools/wrt350nv2-builder/src/ioapi.h
 create mode 100644 tools/wrt350nv2-builder/src/md5.c
 create mode 100644 tools/wrt350nv2-builder/src/md5.h
 create mode 100644 tools/wrt350nv2-builder/src/upgrade.h
 create mode 100644 tools/wrt350nv2-builder/src/wrt350nv2-builder.c
 create mode 100644 tools/xz/Makefile
 create mode 100644 tools/yaffs2/Makefile
 create mode 100644 tools/yaffs2/patches/100-compile.patch
 create mode 100644 tools/yaffs2/patches/110-openbsd-compat.patch

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..fa1385d99a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* -text
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..cd86e34cda
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+*.o
+.DS_Store
+.*.swp
+/env
+/dl
+/.config
+/.config.old
+/bin
+/build_dir
+/staging_dir
+/tmp
+/logs
+/feeds
+/feeds.conf
+/files
+/package/feeds
+/package/openwrt-packages
+key-build*
+*.orig
+*.rej
+*~
+.#*
+*#
+.emacs.desktop*
+TAGS*~
+git-src
diff --git a/BSDmakefile b/BSDmakefile
new file mode 100644
index 0000000000..c6a0425698
--- /dev/null
+++ b/BSDmakefile
@@ -0,0 +1,7 @@
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+world ${.TARGETS}:
+	@gmake $@
diff --git a/Config.in b/Config.in
new file mode 100644
index 0000000000..47391703b5
--- /dev/null
+++ b/Config.in
@@ -0,0 +1,34 @@
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+mainmenu "libreCMC Configuration"
+
+config MODULES
+	option modules
+	bool
+	default y
+
+config HAVE_DOT_CONFIG
+	bool
+	default y
+
+source "target/Config.in"
+
+source "config/Config-images.in"
+
+source "config/Config-build.in"
+
+source "config/Config-devel.in"
+
+source "toolchain/Config.in"
+
+source "target/imagebuilder/Config.in"
+
+source "target/sdk/Config.in"
+
+source "target/toolchain/Config.in"
+
+source "tmp/.config-package.in"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..febb1c8d15
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,96 @@
+# Makefile for OpenWrt
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+TOPDIR:=${CURDIR}
+LC_ALL:=C
+LANG:=C
+TZ:=UTC
+export TOPDIR LC_ALL LANG TZ
+
+empty:=
+space:= $(empty) $(empty)
+$(if $(findstring $(space),$(TOPDIR)),$(error ERROR: The path to the libreCMC directory must not include any spaces))
+
+world:
+
+include $(TOPDIR)/include/host.mk
+
+ifneq ($(OPENWRT_BUILD),1)
+  _SINGLE=export MAKEFLAGS=$(space);
+
+  override OPENWRT_BUILD=1
+  export OPENWRT_BUILD
+  GREP_OPTIONS=
+  export GREP_OPTIONS
+  include $(TOPDIR)/include/debug.mk
+  include $(TOPDIR)/include/depends.mk
+  include $(TOPDIR)/include/toplevel.mk
+else
+  include rules.mk
+  include $(INCLUDE_DIR)/depends.mk
+  include $(INCLUDE_DIR)/subdir.mk
+  include target/Makefile
+  include package/Makefile
+  include tools/Makefile
+  include toolchain/Makefile
+
+$(toolchain/stamp-install): $(tools/stamp-install)
+$(target/stamp-compile): $(toolchain/stamp-install) $(tools/stamp-install) $(BUILD_DIR)/.prepared
+$(package/stamp-compile): $(target/stamp-compile) $(package/stamp-cleanup)
+$(package/stamp-install): $(package/stamp-compile)
+$(target/stamp-install): $(package/stamp-compile) $(package/stamp-install)
+
+printdb:
+	@true
+
+prepare: $(target/stamp-compile)
+
+clean: FORCE
+	rm -rf $(BUILD_DIR) $(STAGING_DIR) $(BIN_DIR) $(OUTPUT_DIR)/packages/$(ARCH_PACKAGES) $(BUILD_LOG_DIR) $(TOPDIR)/staging_dir/packages
+
+dirclean: clean
+	rm -rf $(STAGING_DIR_HOST) $(TOOLCHAIN_DIR) $(BUILD_DIR_HOST) $(BUILD_DIR_TOOLCHAIN)
+	rm -rf $(TMP_DIR)
+
+ifndef DUMP_TARGET_DB
+$(BUILD_DIR)/.prepared: Makefile
+	@mkdir -p $$(dirname $@)
+	@touch $@
+
+tmp/.prereq_packages: .config
+	unset ERROR; \
+	for package in $(sort $(prereq-y) $(prereq-m)); do \
+		$(_SINGLE)$(NO_TRACE_MAKE) -s -r -C package/$$package prereq || ERROR=1; \
+	done; \
+	if [ -n "$$ERROR" ]; then \
+		echo "Package prerequisite check failed."; \
+		false; \
+	fi
+	touch $@
+endif
+
+# check prerequisites before starting to build
+prereq: $(target/stamp-prereq) tmp/.prereq_packages
+	@if [ ! -f "$(INCLUDE_DIR)/site/$(ARCH)" ]; then \
+		echo 'ERROR: Missing site config for architecture "$(ARCH)" !'; \
+		echo '       The missing file will cause configure scripts to fail during compilation.'; \
+		echo '       Please provide a "$(INCLUDE_DIR)/site/$(ARCH)" file and restart the build.'; \
+		exit 1; \
+	fi
+
+checksum: FORCE
+	$(call sha256sums,$(BIN_DIR))
+
+prepare: .config $(tools/stamp-install) $(toolchain/stamp-install)
+world: prepare $(target/stamp-compile) $(package/stamp-compile) $(package/stamp-install) $(target/stamp-install) FORCE
+	$(_SINGLE)$(SUBMAKE) -r package/index
+	$(_SINGLE)$(SUBMAKE) -r checksum
+
+.PHONY: clean dirclean prereq prepare world package/symlinks package/symlinks-install package/symlinks-clean
+
+endif
diff --git a/config/Config-build.in b/config/Config-build.in
new file mode 100644
index 0000000000..7c82e8b3b7
--- /dev/null
+++ b/config/Config-build.in
@@ -0,0 +1,293 @@
+# Copyright (C) 2006-2013 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+menu "Global build settings"
+
+	config ALL_NONSHARED
+		bool "Select all target specific packages by default"
+		default ALL
+
+	config ALL_KMODS
+		bool "Select all kernel module packages by default"
+		default ALL
+
+	config ALL
+		bool "Select all userspace packages by default"
+		default n
+
+	config SIGNED_PACKAGES
+		bool "Cryptographically signed package lists"
+		default y
+
+	comment "General build options"
+
+	config DISPLAY_SUPPORT
+		bool "Show packages that require graphics support (local or remote)"
+		default n
+
+	config BUILD_PATENTED
+		default y
+		bool "Compile with support for patented functionality"
+		help
+		  When this option is disabled, software which provides patented functionality
+		  will not be built.  In case software provides optional support for patented
+		  functionality, this optional support will get disabled for this package.
+
+	config BUILD_NLS
+		default n
+		bool "Compile with full language support"
+		help
+		  When this option is enabled, packages are built with the full versions of
+		  iconv and GNU gettext instead of the default OpenWrt stubs. If uClibc is
+		  used, it is also built with locale support.
+
+	config SHADOW_PASSWORDS
+		bool
+		default y
+
+	config CLEAN_IPKG
+		bool
+		prompt "Remove ipkg/opkg status data files in final images"
+		default n
+		help
+		  This removes all ipkg/opkg status data files from the target directory
+		  before building the root filesystem.
+
+	config COLLECT_KERNEL_DEBUG
+		bool
+		prompt "Collect kernel debug information"
+		select KERNEL_DEBUG_INFO
+		default n
+		help
+		  This collects debugging symbols from the kernel and all compiled modules.
+		  Useful for release builds, so that kernel issues can be debugged offline
+		  later.
+
+	comment "Kernel build options"
+
+	source "config/Config-kernel.in"
+
+	comment "Package build options"
+
+	config DEBUG
+		bool
+		prompt "Compile packages with debugging info"
+		default n
+		help
+		  Adds -g3 to the CFLAGS.
+
+	config IPV6
+		bool
+		prompt "Enable IPv6 support in packages"
+		default y
+		help
+		  Enables IPv6 support in kernel (builtin) and packages.
+
+	config PKG_BUILD_PARALLEL
+		bool
+		prompt "Compile certain packages parallelized"
+		default y
+		help
+		  This adds a -jX option to certain packages that are known to behave well
+		  for parallel build. By default, the package make processes use the main
+		  jobserver, in which case this option only takes effect when you add -jX
+		  to the make command.
+
+		  If you are unsure, select N.
+
+	config PKG_BUILD_USE_JOBSERVER
+		bool
+		prompt "Use top-level make jobserver for packages"
+		depends on PKG_BUILD_PARALLEL
+		default y
+		help
+		  This passes the main make process jobserver fds to package builds,
+		  enabling full parallelization across different packages.
+
+		  Note that disabling this may overcommit CPU resources depending on the
+		  -j level of the main make process, the number of package submake jobs
+		  selected below and the number of actual CPUs present.
+		  Example: If the main make is passed a -j4 and the submake -j
+		  is also set to 4, we may end up with 16 parallel make processes
+		  in the worst case.
+
+	config PKG_BUILD_JOBS
+		int
+		prompt "Number of package submake jobs (2-512)"
+		range 2 512
+		default 2
+		depends on PKG_BUILD_PARALLEL && !PKG_BUILD_USE_JOBSERVER
+		help
+		  The number of jobs (-jX) to pass to packages submake.
+
+	config PKG_DEFAULT_PARALLEL
+		bool
+		prompt "Parallelize the default package build rule (May break build)"
+		depends on PKG_BUILD_PARALLEL
+		depends on BROKEN
+		default n
+		help
+		  Always set the default package build rules to parallel build.
+
+		  WARNING: This may break build or kill your cat, as it builds packages
+		  with multiple jobs that are probably not tested in a parallel build
+		  environment.
+
+		  Only say Y if you don't mind fixing broken packages.  Before reporting
+		  build bugs, set this to N and re-run the build.
+
+	comment "Stripping options"
+
+	choice
+		prompt "Binary stripping method"
+		default USE_STRIP   if EXTERNAL_TOOLCHAIN
+		default USE_STRIP   if USE_GLIBC
+		default USE_SSTRIP
+		help
+		  Select the binary stripping method you wish to use.
+
+		config NO_STRIP
+			bool "none"
+			help
+			  This will install unstripped binaries (useful for native
+			  compiling/debugging).
+
+		config USE_STRIP
+			bool "strip"
+			help
+			  This will install binaries stripped using strip from binutils.
+
+
+		config USE_SSTRIP
+			bool "sstrip"
+			depends on !USE_GLIBC
+			help
+			  This will install binaries stripped using sstrip.
+	endchoice
+
+	config STRIP_ARGS
+		string
+		prompt "Strip arguments"
+		depends on USE_STRIP
+		default "--strip-unneeded --remove-section=.comment --remove-section=.note" if DEBUG
+		default "--strip-all"
+		help
+		  Specifies arguments passed to the strip command when stripping binaries.
+
+	config STRIP_KERNEL_EXPORTS
+		bool "Strip unnecessary exports from the kernel image"
+		help
+		  Reduces kernel size by stripping unused kernel exports from the kernel
+		  image.  Note that this might make the kernel incompatible with any kernel
+		  modules that were not selected at the time the kernel image was created.
+
+	config USE_MKLIBS
+		bool "Strip unnecessary functions from libraries"
+		help
+		  Reduces libraries to only those functions that are necessary for using all
+		  selected packages (including those selected as <M>).  Note that this will
+		  make the system libraries incompatible with most of the packages that are
+		  not selected during the build process.
+
+	choice
+		prompt "Preferred standard C++ library"
+		default USE_LIBSTDCXX if USE_GLIBC
+		default USE_UCLIBCXX
+		help
+		  Select the preferred standard C++ library for all packages that support this.
+
+		config USE_UCLIBCXX
+			bool "uClibc++"
+
+		config USE_LIBSTDCXX
+			bool "libstdc++"
+	endchoice
+
+	comment "Hardening build options"
+
+	config PKG_CHECK_FORMAT_SECURITY
+		bool
+		prompt "Enable gcc format-security"
+		default y
+		help
+		  Add -Wformat -Werror=format-security to the CFLAGS.  You can disable
+		  this per package by adding PKG_CHECK_FORMAT_SECURITY:=0 in the package
+		  Makefile.
+
+	choice
+		prompt "User space Stack-Smashing Protection"
+		depends on USE_MUSL
+		default PKG_CC_STACKPROTECTOR_REGULAR
+		help
+		  Enable GCC Stack Smashing Protection (SSP) for userspace applications
+		config PKG_CC_STACKPROTECTOR_NONE
+			bool "None"
+		config PKG_CC_STACKPROTECTOR_REGULAR
+			bool "Regular"
+			select SSP_SUPPORT if !USE_MUSL
+			depends on KERNEL_CC_STACKPROTECTOR_REGULAR
+		config PKG_CC_STACKPROTECTOR_STRONG
+			bool "Strong"
+			select SSP_SUPPORT if !USE_MUSL
+			depends on !GCC_VERSION_4_8
+			depends on KERNEL_CC_STACKPROTECTOR_STRONG
+	endchoice
+
+	choice
+		prompt "Kernel space Stack-Smashing Protection"
+		default KERNEL_CC_STACKPROTECTOR_REGULAR
+		depends on USE_MUSL || !(x86_64 || i386)
+		help
+		  Enable GCC Stack-Smashing Protection (SSP) for the kernel
+		config KERNEL_CC_STACKPROTECTOR_NONE
+			bool "None"
+		config KERNEL_CC_STACKPROTECTOR_REGULAR
+			bool "Regular"
+		config KERNEL_CC_STACKPROTECTOR_STRONG
+			depends on !GCC_VERSION_4_8
+			bool "Strong"
+	endchoice
+
+	choice
+		prompt "Enable buffer-overflows detection (FORTIFY_SOURCE)"
+		default PKG_FORTIFY_SOURCE_1
+		help
+		  Enable the _FORTIFY_SOURCE macro which introduces additional
+		  checks to detect buffer-overflows in the following standard library
+		  functions: memcpy, mempcpy, memmove, memset, strcpy, stpcpy,
+		  strncpy, strcat, strncat, sprintf, vsprintf, snprintf, vsnprintf,
+		  gets.  "Conservative" (_FORTIFY_SOURCE set to 1) only introduces
+		  checks that shouldn't change the behavior of conforming programs,
+		  while "aggressive" (_FORTIFY_SOURCES set to 2) some more checking is
+		  added, but some conforming programs might fail.
+		config PKG_FORTIFY_SOURCE_NONE
+			bool "None"
+		config PKG_FORTIFY_SOURCE_1
+			bool "Conservative"
+		config PKG_FORTIFY_SOURCE_2
+			bool "Aggressive"
+	endchoice
+
+	choice
+		prompt "Enable RELRO protection"
+		default PKG_RELRO_FULL
+		help
+		  Enable a link-time protection known as RELRO (Relocation Read Only)
+		  which helps to protect from certain type of exploitation techniques
+		  altering the content of some ELF sections. "Partial" RELRO makes the
+		  .dynamic section not writeable after initialization, introducing
+		  almost no performance penalty, while "full" RELRO also marks the GOT
+		  as read-only at the cost of initializing all of it at startup.
+		config PKG_RELRO_NONE
+			bool "None"
+		config PKG_RELRO_PARTIAL
+			bool "Partial"
+		config PKG_RELRO_FULL
+			bool "Full"
+	endchoice
+
+endmenu
diff --git a/config/Config-devel.in b/config/Config-devel.in
new file mode 100644
index 0000000000..938f0b3c9c
--- /dev/null
+++ b/config/Config-devel.in
@@ -0,0 +1,112 @@
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+menuconfig DEVEL
+	bool "Advanced configuration options (for developers)"
+	default n
+
+	config BROKEN
+		bool "Show broken platforms / packages" if DEVEL
+		default n
+
+	config BINARY_FOLDER
+		string "Binary folder" if DEVEL
+		default ""
+		help
+		  Store built firmware images and filesystem images in this directory.
+		  If not set, uses './bin/$(BOARD)'
+
+	config DOWNLOAD_FOLDER
+		string "Download folder" if DEVEL
+		default ""
+		help
+		  Store downloaded source bundles in this directory.
+		  If not set then defaults to './dl', which is removed by operations such as
+		  'git clean -xdf' or 'make distclean'.
+		  This option is useful if you have a low bandwidth Internet connection, and by
+		  setting a path outside the OpenWrt tree downloads will be saved.
+
+	config LOCALMIRROR
+		string "Local mirror for source packages" if DEVEL
+		default ""
+
+	config AUTOREBUILD
+		bool "Automatic rebuild of packages" if DEVEL
+		default y
+		help
+		  Automatically rebuild packages when their files change.
+
+	config BUILD_SUFFIX
+		string "Build suffix to append to the target BUILD_DIR variable" if DEVEL
+		default ""
+		help
+		  Build suffix to append to the BUILD_DIR variable, i.e: './build_dir/{target-build-dir}_$(BUILD_SUFFIX)'.
+		  This allows you to switch to a different .config whilst retaining all the build
+		  objects generated by the first .config
+
+	config TARGET_ROOTFS_DIR
+		string "Override the default TARGET_ROOTFS_DIR variable" if DEVEL
+		default ""
+		help
+		  Override the default TARGET_ROOTFS_DIR variable content $(BUILD_DIR) with
+		  custom path.  Use this option to re-define the location of the target
+		  root filesystem directory.
+
+	config CCACHE
+		bool "Use ccache" if DEVEL
+		default n
+		help
+		  Compiler cache; see http://ccache.samba.org/.
+
+	config EXTERNAL_KERNEL_TREE
+		string "Use external kernel tree" if DEVEL
+		default ""
+
+	config KERNEL_GIT_CLONE_URI
+		string "Enter git repository to clone" if DEVEL
+		default ""
+		help
+		  Enter the full git repository path i.e.:
+		  git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+		  This will create a git clone of the kernel in your build directory.
+
+	config KERNEL_GIT_LOCAL_REPOSITORY
+		string "Enter path to local reference repository" if DEVEL
+		depends on (KERNEL_GIT_CLONE_URI != "")
+		default ""
+		help
+		  Enter a full pathname to a local reference git repository.
+		  In this instance, the --reference option of git clone will
+		  be used thus creating a quick local clone of your repo.
+
+	config KERNEL_GIT_BRANCH
+		string "Enter git branch to clone" if DEVEL
+		depends on (KERNEL_GIT_CLONE_URI != "")
+		default ""
+		help
+		  Enter the branch name to checkout after cloning the git repository.
+		  In this instance, the --branch option of git clone will be used.
+		  If unused, the clone's repository HEAD will be checked-out.
+
+	config BUILD_LOG
+		bool "Enable log files during build process" if DEVEL
+		help
+		  If enabled, log files will be written to the ./log directory.
+
+	config SRC_TREE_OVERRIDE
+		bool "Enable package source tree override" if DEVEL
+		help
+		  If enabled, you can force a package to use a git tree as source
+		  code instead of the normal tarball. Create a symlink 'git-src'
+		  in the package directory, pointing to the .git tree that you want
+		  to pull the source code from.
+
+	config EXTRA_OPTIMIZATION
+		string "Additional compiler options" if DEVEL
+		default "-fno-caller-saves -fno-plt" if !CONFIG_EXTERNAL_TOOLCHAIN && !arc
+		default "-fno-caller-saves"
+		help
+		  Extra target-independent optimizations to use when building for the target.
diff --git a/config/Config-images.in b/config/Config-images.in
new file mode 100644
index 0000000000..3c76c6236e
--- /dev/null
+++ b/config/Config-images.in
@@ -0,0 +1,269 @@
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+menu "Target Images"
+
+	menuconfig TARGET_ROOTFS_INITRAMFS
+		bool "ramdisk"
+		default y if USES_INITRAMFS
+		help
+		  Embed the root filesystem into the kernel (initramfs).
+
+		choice
+			prompt "Compression"
+			default TARGET_INITRAMFS_COMPRESSION_LZMA if TARGET_ar71xx
+			default TARGET_INITRAMFS_COMPRESSION_LZMA if TARGET_ramips
+			default TARGET_INITRAMFS_COMPRESSION_LZMA if TARGET_apm821xx
+			default TARGET_INITRAMFS_COMPRESSION_NONE
+			depends on TARGET_ROOTFS_INITRAMFS
+			help
+			  Select ramdisk compression.
+
+			config TARGET_INITRAMFS_COMPRESSION_NONE
+				bool "none"
+
+			config TARGET_INITRAMFS_COMPRESSION_GZIP
+				bool "gzip"
+
+			config TARGET_INITRAMFS_COMPRESSION_BZIP2
+				bool "bzip2"
+
+			config TARGET_INITRAMFS_COMPRESSION_LZMA
+				bool "lzma"
+
+			config TARGET_INITRAMFS_COMPRESSION_LZO
+				bool "lzo"
+
+			config TARGET_INITRAMFS_COMPRESSION_LZ4
+				bool "lz4"
+
+			config TARGET_INITRAMFS_COMPRESSION_XZ
+				bool "xz"
+		endchoice
+
+		config EXTERNAL_CPIO
+			string
+			prompt "Use external cpio" if TARGET_ROOTFS_INITRAMFS
+			default ""
+			help
+			  Kernel uses specified external cpio as INITRAMFS_SOURCE.
+
+	comment "Root filesystem archives"
+
+	config TARGET_ROOTFS_CPIOGZ
+		bool "cpio.gz"
+		default y if USES_CPIOGZ
+		help
+		  Build a compressed cpio archive of the root filesystem.
+
+	config TARGET_ROOTFS_TARGZ
+		bool "tar.gz"
+		default y if USES_TARGZ
+		help
+		  Build a compressed tar archive of the root filesystem.
+
+	comment "Root filesystem images"
+
+	menuconfig TARGET_ROOTFS_EXT4FS
+		bool "ext4"
+		default y if USES_EXT4
+		help
+		  Build an ext4 root filesystem.
+
+		config TARGET_EXT4_RESERVED_PCT
+			int "Percentage of reserved blocks in root filesystem"
+			depends on TARGET_ROOTFS_EXT4FS
+			default 0
+			help
+			  Select the percentage of reserved blocks in the root filesystem.
+
+		choice
+			prompt "Root filesystem block size"
+			default TARGET_EXT4_BLOCKSIZE_4K
+			depends on TARGET_ROOTFS_EXT4FS
+			help
+			  Select the block size of the root filesystem.
+
+			config TARGET_EXT4_BLOCKSIZE_4K
+				bool "4k"
+
+			config TARGET_EXT4_BLOCKSIZE_2K
+				bool "2k"
+
+			config TARGET_EXT4_BLOCKSIZE_1K
+				bool "1k"
+		endchoice
+
+		config TARGET_EXT4_BLOCKSIZE
+			int
+			default 4096 if TARGET_EXT4_BLOCKSIZE_4K
+			default 2048 if TARGET_EXT4_BLOCKSIZE_2K
+			default 1024 if TARGET_EXT4_BLOCKSIZE_1K
+			depends on TARGET_ROOTFS_EXT4FS
+
+		config TARGET_EXT4_JOURNAL
+			bool "Create a journaling filesystem"
+			depends on TARGET_ROOTFS_EXT4FS
+			default n
+			help
+			  Create an ext4 filesystem with a journal.
+
+	config TARGET_ROOTFS_ISO
+		bool "iso"
+		default n
+		depends on TARGET_x86_generic
+		help
+		  Create a bootable ISO image.
+
+	config TARGET_ROOTFS_JFFS2
+		bool "jffs2"
+		depends on USES_JFFS2
+		help
+		  Build a JFFS2 root filesystem.
+
+	config TARGET_ROOTFS_JFFS2_NAND
+		bool "jffs2 for NAND"
+		default y if USES_JFFS2_NAND
+		depends on USES_JFFS2_NAND
+		help
+		  Build a JFFS2 root filesystem for NAND flash.
+
+	menuconfig TARGET_ROOTFS_SQUASHFS
+		bool "squashfs"
+		default y if USES_SQUASHFS
+		help
+		  Build a squashfs-lzma root filesystem.
+
+		config TARGET_SQUASHFS_BLOCK_SIZE
+			int "Block size (in KiB)"
+			depends on TARGET_ROOTFS_SQUASHFS
+			default 64 if LOW_MEMORY_FOOTPRINT
+			default 256
+
+	menuconfig TARGET_ROOTFS_UBIFS
+		bool "ubifs"
+		default y if USES_UBIFS
+		depends on USES_UBIFS
+		help
+		  Build a UBIFS root filesystem.
+
+		choice
+			prompt "compression"
+			default TARGET_UBIFS_COMPRESSION_ZLIB
+			depends on TARGET_ROOTFS_UBIFS
+			help
+			  Select compression type
+
+			config TARGET_UBIFS_COMPRESSION_NONE
+				bool "none"
+
+			config TARGET_UBIFS_COMPRESSION_LZO
+				bool "lzo"
+
+			config TARGET_UBIFS_COMPRESSION_ZLIB
+				bool "zlib"
+		endchoice
+
+		config TARGET_UBIFS_FREE_SPACE_FIXUP
+			bool "free space fixup" if TARGET_ROOTFS_UBIFS
+			default y
+			help
+			  The filesystem free space has to be fixed up on first mount.
+
+		config TARGET_UBIFS_JOURNAL_SIZE
+			string
+			prompt "journal size" if TARGET_ROOTFS_UBIFS
+			default ""
+
+	config GRUB_IMAGES
+		bool "Build GRUB images (Linux x86 or x86_64 host only)"
+		depends on TARGET_x86
+		depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_ISO || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS
+		select PACKAGE_grub2
+		default y
+
+	config GRUB_CONSOLE
+		bool "Use Console Terminal (in addition to Serial)"
+		depends on GRUB_IMAGES
+		default n if (TARGET_x86_generic_Soekris45xx || TARGET_x86_generic_Soekris48xx || TARGET_x86_net5501 || TARGET_x86_geos || TARGET_x86_alix2)
+		default y
+
+	config GRUB_SERIAL
+		string "Serial port device"
+		depends on GRUB_IMAGES
+		default "hvc0" if TARGET_x86_xen_domu
+		default "ttyS0" if ! TARGET_x86_xen_domu
+
+	config GRUB_BAUDRATE
+		int "Serial port baud rate"
+		depends on GRUB_IMAGES
+		default 38400 if TARGET_x86_generic
+		default 38400 if TARGET_x86_geode
+		default 115200
+
+	config GRUB_BOOTOPTS
+		string "Extra kernel boot options"
+		depends on GRUB_IMAGES
+		default "xencons=hvc" if TARGET_x86_xen_domu
+		help
+		  If you don't know, just leave it blank.
+
+	config GRUB_TIMEOUT
+		string "Seconds to wait before booting the default entry"
+		depends on GRUB_IMAGES
+		default "5"
+		help
+		  If you don't know, 5 seconds is a reasonable default.
+
+	config VDI_IMAGES
+		bool "Build VirtualBox image files (VDI)"
+		depends on TARGET_x86 || TARGET_x86_64
+		select GRUB_IMAGES
+		select TARGET_IMAGES_PAD
+		select PACKAGE_kmod-e1000
+
+	config VMDK_IMAGES
+		bool "Build VMware image files (VMDK)"
+		depends on TARGET_x86 || TARGET_x86_64
+		select GRUB_IMAGES
+		select TARGET_IMAGES_PAD
+		select PACKAGE_kmod-e1000
+
+	config TARGET_IMAGES_PAD
+		bool "Pad images to filesystem size (for JFFS2)"
+		depends on GRUB_IMAGES
+
+	config TARGET_IMAGES_GZIP
+		bool "GZip images"
+		depends on TARGET_IMAGES_PAD || TARGET_ROOTFS_EXT4FS
+		default y
+
+	comment "Image Options"
+
+	source "target/linux/*/image/Config.in"
+
+	config TARGET_KERNEL_PARTSIZE
+		int "Kernel partition size (in MB)"
+		depends on GRUB_IMAGES
+		default 16
+
+	config TARGET_ROOTFS_PARTSIZE
+		int "Root filesystem partition size (in MB)"
+		depends on GRUB_IMAGES || TARGET_ROOTFS_EXT4FS || TARGET_rb532 || TARGET_mvebu || TARGET_uml
+		default 2048 if TARGET_x86
+		default 256 if ! TARGET_x86
+		help
+		  Select the root filesystem partition size.
+
+	config TARGET_ROOTFS_PARTNAME
+		string "Root partition on target device"
+		depends on GRUB_IMAGES
+		help
+		  Override the root partition on the final device. If left empty,
+		  it will be mounted by PARTUUID which makes the kernel find the
+		  appropriate disk automatically.
+
+endmenu
diff --git a/config/Config-kernel.in b/config/Config-kernel.in
new file mode 100644
index 0000000000..d8ca76cf1d
--- /dev/null
+++ b/config/Config-kernel.in
@@ -0,0 +1,739 @@
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+config KERNEL_BUILD_USER
+	string "Custom Kernel Build User Name"
+	default ""
+	help
+	  Sets the Kernel build user string, which for example will be returned
+	  by 'uname -a' on running systems.
+	  If not set, uses system user at build time.
+
+config KERNEL_BUILD_DOMAIN
+	string "Custom Kernel Build Domain Name"
+	default ""
+	help
+	  Sets the Kernel build domain string, which for example will be
+	  returned by 'uname -a' on running systems.
+	  If not set, uses system hostname at build time.
+
+config KERNEL_PRINTK
+	bool "Enable support for printk"
+	default y
+
+config KERNEL_CRASHLOG
+	bool "Crash logging"
+	depends on !(arm || powerpc || sparc || TARGET_uml)
+	default y
+
+config KERNEL_SWAP
+	bool "Support for paging of anonymous memory (swap)"
+	default y
+
+config KERNEL_DEBUG_FS
+	bool "Compile the kernel with debug filesystem enabled"
+	default y
+	help
+	  debugfs is a virtual file system that kernel developers use to put
+	  debugging files into. Enable this option to be able to read and
+	  write to these files. Many common debugging facilities, such as
+	  ftrace, require the existence of debugfs.
+
+config KERNEL_ARM_PMU
+	bool
+	default n
+	depends on (arm || arm64)
+
+config KERNEL_PERF_EVENTS
+	bool
+	default n
+	select KERNEL_ARM_PMU if (arm || arm64)
+
+config KERNEL_PROFILING
+	bool "Compile the kernel with profiling enabled"
+	default n
+	select KERNEL_PERF_EVENTS
+	help
+	  Enable the extended profiling support mechanisms used by profilers such
+	  as OProfile.
+
+config KERNEL_KALLSYMS
+	bool "Compile the kernel with symbol table information"
+	default y if !SMALL_FLASH
+	help
+	  This will give you more information in stack traces from kernel oopses.
+
+config KERNEL_FTRACE
+	bool "Compile the kernel with tracing support"
+	depends on !TARGET_uml
+	default n
+
+config KERNEL_FTRACE_SYSCALLS
+	bool "Trace system calls"
+	depends on KERNEL_FTRACE
+	default n
+
+config KERNEL_ENABLE_DEFAULT_TRACERS
+	bool "Trace process context switches and events"
+	depends on KERNEL_FTRACE
+	default n
+
+config KERNEL_FUNCTION_TRACER
+	bool "Function tracer"
+	depends on KERNEL_FTRACE
+	default n
+
+config KERNEL_FUNCTION_GRAPH_TRACER
+	bool "Function graph tracer"
+	depends on KERNEL_FUNCTION_TRACER
+	default n
+
+config KERNEL_DYNAMIC_FTRACE
+	bool "Enable/disable function tracing dynamically"
+	depends on KERNEL_FUNCTION_TRACER
+	default n
+
+config KERNEL_FUNCTION_PROFILER
+	bool "Function profiler"
+	depends on KERNEL_FUNCTION_TRACER
+	default n
+
+config KERNEL_DEBUG_KERNEL
+	bool
+	default n
+
+config KERNEL_DEBUG_INFO
+	bool "Compile the kernel with debug information"
+	default y
+	select KERNEL_DEBUG_KERNEL
+	help
+	  This will compile your kernel and modules with debug information.
+
+config KERNEL_DEBUG_LL_UART_NONE
+	bool
+	default n
+	depends on arm
+
+config KERNEL_DEBUG_LL
+	bool
+	default n
+	depends on arm
+	select KERNEL_DEBUG_LL_UART_NONE
+	help
+	  ARM low level debugging.
+
+config KERNEL_DYNAMIC_DEBUG
+	bool "Compile the kernel with dynamic printk"
+	select KERNEL_DEBUG_FS
+	default n
+	help
+	  Compiles debug level messages into the kernel, which would not
+	  otherwise be available at runtime. These messages can then be
+	  enabled/disabled based on various levels of scope - per source file,
+	  function, module, format string, and line number. This mechanism
+	  implicitly compiles in all pr_debug() and dev_dbg() calls, which
+	  enlarges the kernel text size by about 2%.
+
+config KERNEL_EARLY_PRINTK
+	bool "Compile the kernel with early printk"
+	default y if TARGET_bcm53xx
+	default n
+	depends on arm
+	select KERNEL_DEBUG_KERNEL
+	select KERNEL_DEBUG_LL if arm
+	help
+	  Compile the kernel with early printk support.  This is only useful for
+	  debugging purposes to send messages over the serial console in early boot.
+	  Enable this to debug early boot problems.
+
+config KERNEL_KPROBES
+	bool "Compile the kernel with kprobes support"
+	default n
+	select KERNEL_FTRACE
+	select KERNEL_PERF_EVENTS
+	help
+	  Compiles the kernel with KPROBES support, which allows you to trap
+	  at almost any kernel address and execute a callback function.
+	  register_kprobe() establishes a probepoint and specifies the
+	  callback. Kprobes is useful for kernel debugging, non-intrusive
+	  instrumentation and testing.
+	  If in doubt, say "N".
+
+config KERNEL_KPROBE_EVENT
+	bool
+	default y if KERNEL_KPROBES
+
+config KERNEL_AIO
+	bool "Compile the kernel with asynchronous IO support"
+	default n
+
+config KERNEL_DIRECT_IO
+	bool "Compile the kernel with direct IO support"
+	default n
+
+config KERNEL_FHANDLE
+	bool "Compile the kernel with support for fhandle syscalls"
+	default n
+
+config KERNEL_FANOTIFY
+	bool "Compile the kernel with modern file notification support"
+	default n
+
+config KERNEL_BLK_DEV_BSG
+	bool "Compile the kernel with SCSI generic v4 support for any block device"
+	default n
+
+config KERNEL_MAGIC_SYSRQ
+	bool "Compile the kernel with SysRq support"
+	default y
+
+config KERNEL_COREDUMP
+	bool
+
+config KERNEL_ELF_CORE
+	bool "Enable process core dump support"
+	select KERNEL_COREDUMP
+	default y
+
+config KERNEL_PROVE_LOCKING
+	bool "Enable kernel lock checking"
+	select KERNEL_DEBUG_KERNEL
+	default n
+
+config KERNEL_PRINTK_TIME
+	bool "Enable printk timestamps"
+	default y
+
+config KERNEL_SLUB_DEBUG
+	bool
+
+config KERNEL_SLUB_DEBUG_ON
+	bool
+
+config KERNEL_SLABINFO
+	select KERNEL_SLUB_DEBUG
+	select KERNEL_SLUB_DEBUG_ON
+	bool "Enable /proc slab debug info"
+
+config KERNEL_PROC_PAGE_MONITOR
+	bool "Enable /proc page monitoring"
+
+config KERNEL_RELAY
+	bool
+
+config KERNEL_KEXEC
+	bool "Enable kexec support"
+
+config USE_RFKILL
+	bool "Enable rfkill support"
+	default RFKILL_SUPPORT
+
+config USE_SPARSE
+	bool "Enable sparse check during kernel build"
+	default n
+
+config KERNEL_DEVTMPFS
+	bool "Compile the kernel with device tmpfs enabled"
+	default n
+	help
+	  devtmpfs is a simple, kernel-managed /dev filesystem. The kernel creates
+	  devices nodes for all registered devices ti simplify boot, but leaves more
+	  complex tasks to userspace (e.g. udev).
+
+if KERNEL_DEVTMPFS
+
+	config KERNEL_DEVTMPFS_MOUNT
+		bool "Automatically mount devtmpfs after root filesystem is mounted"
+		default n
+
+endif
+
+config KERNEL_KEYS
+    bool "Enable kernel access key retention support"
+    default n
+
+config KERNEL_PERSISTENT_KEYRINGS
+    bool "Enable kernel persistent keyrings"
+    depends on KERNEL_KEYS
+    default n
+
+config KERNEL_BIG_KEYS
+    bool "Enable large payload keys on kernel keyrings"
+    depends on KERNEL_KEYS
+    default n
+
+config KERNEL_ENCRYPTED_KEYS
+    tristate "Enable keys with encrypted payloads on kernel keyrings"
+    depends on KERNEL_KEYS
+    default n
+
+#
+# CGROUP support symbols
+#
+
+config KERNEL_CGROUPS
+	bool "Enable kernel cgroups"
+	default n
+
+if KERNEL_CGROUPS
+
+	config KERNEL_CGROUP_DEBUG
+		bool "Example debug cgroup subsystem"
+		default n
+		help
+		  This option enables a simple cgroup subsystem that
+		  exports useful debugging information about the cgroups
+		  framework.
+
+	config KERNEL_FREEZER
+		bool
+		default y if KERNEL_CGROUP_FREEZER
+
+	config KERNEL_CGROUP_FREEZER
+		bool "Freezer cgroup subsystem"
+		default y
+		help
+		  Provides a way to freeze and unfreeze all tasks in a
+		  cgroup.
+
+	config KERNEL_CGROUP_DEVICE
+		bool "Device controller for cgroups"
+		default y
+		help
+		  Provides a cgroup implementing whitelists for devices which
+		  a process in the cgroup can mknod or open.
+
+	config KERNEL_CGROUP_PIDS
+		bool "PIDs cgroup subsystem"
+		default y
+		help
+		  Provides enforcement of process number limits in the scope of a
+		  cgroup.
+
+	config KERNEL_CPUSETS
+		bool "Cpuset support"
+		default n
+		help
+		  This option will let you create and manage CPUSETs which
+		  allow dynamically partitioning a system into sets of CPUs and
+		  Memory Nodes and assigning tasks to run only within those sets.
+		  This is primarily useful on large SMP or NUMA systems.
+
+	config KERNEL_PROC_PID_CPUSET
+		bool "Include legacy /proc/<pid>/cpuset file"
+		default n
+		depends on KERNEL_CPUSETS
+
+	config KERNEL_CGROUP_CPUACCT
+		bool "Simple CPU accounting cgroup subsystem"
+		default n
+		help
+		  Provides a simple Resource Controller for monitoring the
+		  total CPU consumed by the tasks in a cgroup.
+
+	config KERNEL_RESOURCE_COUNTERS
+		bool "Resource counters"
+		default n
+		help
+		  This option enables controller independent resource accounting
+		  infrastructure that works with cgroups.
+
+	config KERNEL_MM_OWNER
+		bool
+		default y if KERNEL_MEMCG
+
+	config KERNEL_MEMCG
+		bool "Memory Resource Controller for Control Groups"
+		default n
+		depends on KERNEL_RESOURCE_COUNTERS || !LINUX_3_18
+		help
+		  Provides a memory resource controller that manages both anonymous
+		  memory and page cache. (See Documentation/cgroups/memory.txt)
+
+		  Note that setting this option increases fixed memory overhead
+		  associated with each page of memory in the system. By this,
+		  20(40)bytes/PAGE_SIZE on 32(64)bit system will be occupied by memory
+		  usage tracking struct at boot. Total amount of this is printed out
+		  at boot.
+
+		  Only enable when you're ok with these tradeoffs and really
+		  sure you need the memory resource controller. Even when you enable
+		  this, you can set "cgroup_disable=memory" at your boot option to
+		  disable memory resource controller and you can avoid overheads
+		  (but lose benefits of memory resource controller).
+
+		  This config option also selects MM_OWNER config option, which
+		  could in turn add some fork/exit overhead.
+
+	config KERNEL_MEMCG_SWAP
+		bool "Memory Resource Controller Swap Extension"
+		default n
+		depends on KERNEL_MEMCG
+		help
+		  Add swap management feature to memory resource controller. When you
+		  enable this, you can limit mem+swap usage per cgroup. In other words,
+		  when you disable this, memory resource controller has no cares to
+		  usage of swap...a process can exhaust all of the swap. This extension
+		  is useful when you want to avoid exhaustion swap but this itself
+		  adds more overheads and consumes memory for remembering information.
+		  Especially if you use 32bit system or small memory system, please
+		  be careful about enabling this. When memory resource controller
+		  is disabled by boot option, this will be automatically disabled and
+		  there will be no overhead from this. Even when you set this config=y,
+		  if boot option "swapaccount=0" is set, swap will not be accounted.
+		  Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page
+		  size is 4096bytes, 512k per 1Gbytes of swap.
+
+	config KERNEL_MEMCG_SWAP_ENABLED
+		bool "Memory Resource Controller Swap Extension enabled by default"
+		default n
+		depends on KERNEL_MEMCG_SWAP
+		help
+		  Memory Resource Controller Swap Extension comes with its price in
+		  a bigger memory consumption. General purpose distribution kernels
+		  which want to enable the feature but keep it disabled by default
+		  and let the user enable it by swapaccount boot command line
+		  parameter should have this option unselected.
+
+		  Those who want to have the feature enabled by default should
+		  select this option (if, for some reason, they need to disable it,
+		  then swapaccount=0 does the trick).
+
+
+	config KERNEL_MEMCG_KMEM
+		bool "Memory Resource Controller Kernel Memory accounting (EXPERIMENTAL)"
+		default n
+		depends on KERNEL_MEMCG
+		help
+		  The Kernel Memory extension for Memory Resource Controller can limit
+		  the amount of memory used by kernel objects in the system. Those are
+		  fundamentally different from the entities handled by the standard
+		  Memory Controller, which are page-based, and can be swapped. Users of
+		  the kmem extension can use it to guarantee that no group of processes
+		  will ever exhaust kernel resources alone.
+
+	config KERNEL_CGROUP_PERF
+		bool "Enable perf_event per-cpu per-container group (cgroup) monitoring"
+		select KERNEL_PERF_EVENTS
+		default n
+		help
+		  This option extends the per-cpu mode to restrict monitoring to
+		  threads which belong to the cgroup specified and run on the
+		  designated cpu.
+
+	menuconfig KERNEL_CGROUP_SCHED
+		bool "Group CPU scheduler"
+		default n
+		help
+		  This feature lets CPU scheduler recognize task groups and control CPU
+		  bandwidth allocation to such task groups. It uses cgroups to group
+		  tasks.
+
+	if KERNEL_CGROUP_SCHED
+
+		config KERNEL_FAIR_GROUP_SCHED
+			bool "Group scheduling for SCHED_OTHER"
+			default n
+
+		config KERNEL_CFS_BANDWIDTH
+			bool "CPU bandwidth provisioning for FAIR_GROUP_SCHED"
+			default n
+			depends on KERNEL_FAIR_GROUP_SCHED
+			help
+			  This option allows users to define CPU bandwidth rates (limits) for
+			  tasks running within the fair group scheduler.  Groups with no limit
+			  set are considered to be unconstrained and will run with no
+			  restriction.
+			  See tip/Documentation/scheduler/sched-bwc.txt for more information.
+
+		config KERNEL_RT_GROUP_SCHED
+			bool "Group scheduling for SCHED_RR/FIFO"
+			default n
+			help
+			  This feature lets you explicitly allocate real CPU bandwidth
+			  to task groups. If enabled, it will also make it impossible to
+			  schedule realtime tasks for non-root users until you allocate
+			  realtime bandwidth for them.
+
+	endif
+
+	config KERNEL_BLK_CGROUP
+		bool "Block IO controller"
+		default y
+		help
+		  Generic block IO controller cgroup interface. This is the common
+		  cgroup interface which should be used by various IO controlling
+		  policies.
+
+		  Currently, CFQ IO scheduler uses it to recognize task groups and
+		  control disk bandwidth allocation (proportional time slice allocation)
+		  to such task groups. It is also used by bio throttling logic in
+		  block layer to implement upper limit in IO rates on a device.
+
+		  This option only enables generic Block IO controller infrastructure.
+		  One needs to also enable actual IO controlling logic/policy. For
+		  enabling proportional weight division of disk bandwidth in CFQ, set
+		  CONFIG_CFQ_GROUP_IOSCHED=y; for enabling throttling policy, set
+		  CONFIG_BLK_DEV_THROTTLING=y.
+
+	config KERNEL_DEBUG_BLK_CGROUP
+		bool "Enable Block IO controller debugging"
+		default n
+		depends on KERNEL_BLK_CGROUP
+		help
+		  Enable some debugging help. Currently it exports additional stat
+		  files in a cgroup which can be useful for debugging.
+
+	config KERNEL_NET_CLS_CGROUP
+		bool "Control Group Classifier"
+		default y
+
+	config KERNEL_NETPRIO_CGROUP
+		bool "Network priority cgroup"
+		default y
+
+endif
+
+#
+# Namespace support symbols
+#
+
+config KERNEL_NAMESPACES
+	bool "Enable kernel namespaces"
+	default n
+
+if KERNEL_NAMESPACES
+
+	config KERNEL_UTS_NS
+		bool "UTS namespace"
+		default y
+		help
+		  In this namespace, tasks see different info provided
+		  with the uname() system call.
+
+	config KERNEL_IPC_NS
+		bool "IPC namespace"
+		default y
+		help
+		  In this namespace, tasks work with IPC ids which correspond to
+		  different IPC objects in different namespaces.
+
+	config KERNEL_USER_NS
+		bool "User namespace (EXPERIMENTAL)"
+		default y
+		help
+		  This allows containers, i.e. vservers, to use user namespaces
+		  to provide different user info for different servers.
+
+	config KERNEL_PID_NS
+		bool "PID Namespaces"
+		default y
+		help
+		  Support process id namespaces. This allows having multiple
+		  processes with the same pid as long as they are in different
+		  pid namespaces. This is a building block of containers.
+
+	config KERNEL_NET_NS
+		bool "Network namespace"
+		default y
+		help
+		  Allow user space to create what appear to be multiple instances
+		  of the network stack.
+
+endif
+
+#
+# LXC related symbols
+#
+
+config KERNEL_LXC_MISC
+	bool "Enable miscellaneous LXC related options"
+	default n
+
+if KERNEL_LXC_MISC
+
+	config KERNEL_DEVPTS_MULTIPLE_INSTANCES
+		bool "Support multiple instances of devpts"
+		default y
+		help
+		  Enable support for multiple instances of devpts filesystem.
+		  If you want to have isolated PTY namespaces (eg: in containers),
+		  say Y here. Otherwise, say N. If enabled, each mount of devpts
+		  filesystem with the '-o newinstance' option will create an
+		  independent PTY namespace.
+
+	config KERNEL_POSIX_MQUEUE
+		bool "POSIX Message Queues"
+		default y
+		help
+		  POSIX variant of message queues is a part of IPC. In POSIX message
+		  queues every message has a priority which decides about succession
+		  of receiving it by a process. If you want to compile and run
+		  programs written e.g. for Solaris with use of its POSIX message
+		  queues (functions mq_*) say Y here.
+
+		  POSIX message queues are visible as a filesystem called 'mqueue'
+		  and can be mounted somewhere if you want to do filesystem
+		  operations on message queues.
+
+endif
+
+config KERNEL_SECCOMP_FILTER
+	bool
+	default n
+
+config KERNEL_SECCOMP
+	bool "Enable seccomp support"
+		depends on !(TARGET_uml)
+		select KERNEL_SECCOMP_FILTER
+		default n
+		help
+		  Build kernel with support for seccomp.
+
+#
+# IPv6 configuration
+#
+
+config KERNEL_IPV6
+	def_bool IPV6
+
+if KERNEL_IPV6
+
+	config KERNEL_IPV6_MULTIPLE_TABLES
+		def_bool y
+
+	config KERNEL_IPV6_SUBTREES
+		def_bool y
+
+	config KERNEL_IPV6_MROUTE
+		def_bool y
+
+	config KERNEL_IPV6_PIMSM_V2
+		def_bool n
+
+endif
+
+#
+# NFS related symbols
+#
+config KERNEL_IP_PNP
+	bool "Compile the kernel with rootfs on NFS"
+	help
+	   If you want to make your kernel boot off a NFS server as root
+	   filesystem, select Y here.
+
+if KERNEL_IP_PNP
+
+	config KERNEL_IP_PNP_DHCP
+		def_bool y
+
+	config KERNEL_IP_PNP_BOOTP
+		def_bool n
+
+	config KERNEL_IP_PNP_RARP
+		def_bool n
+
+	config KERNEL_NFS_FS
+		def_bool y
+
+	config KERNEL_NFS_V2
+		def_bool y
+
+	config KERNEL_NFS_V3
+		def_bool y
+
+	config KERNEL_ROOT_NFS
+		def_bool y
+
+endif
+
+menu "Filesystem ACL and attr support options"
+	config USE_FS_ACL_ATTR
+		bool "Use filesystem ACL and attr support by default"
+		default n
+		help
+		  Make using ACLs (e.g. POSIX ACL, NFSv4 ACL) the default
+		  for kernel and packages, except tmpfs, flash filesystems,
+		  and old NFS.  Also enable userspace extended attribute support
+		  by default.  (OpenWrt already has an expection it will be
+		  present in the kernel).
+
+	config KERNEL_FS_POSIX_ACL
+		bool "Enable POSIX ACL support"
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_BTRFS_FS_POSIX_ACL
+		bool "Enable POSIX ACL for BtrFS Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_EXT4_FS_POSIX_ACL
+		bool "Enable POSIX ACL for Ext4 Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_F2FS_FS_POSIX_ACL
+		bool "Enable POSIX ACL for F2FS Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default n
+
+	config KERNEL_JFFS2_FS_POSIX_ACL
+		bool "Enable POSIX ACL for JFFS2 Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default n
+
+	config KERNEL_TMPFS_POSIX_ACL
+		bool "Enable POSIX ACL for TMPFS Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default n
+
+	config KERNEL_CIFS_ACL
+		bool "Enable CIFS ACLs"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_HFS_FS_POSIX_ACL
+		bool "Enable POSIX ACL for HFS Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_HFSPLUG_FS_POSIX_ACL
+		bool "Enable POSIX ACL for HFS+ Filesystems"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_NFS_ACL_SUPPORT
+		bool "Enable ACLs for NFS"
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_NFS_V3_ACL_SUPPORT
+		bool "Enable ACLs for NFSv3"
+		default n
+
+	config KERNEL_NFSD_V2_ACL_SUPPORT
+		bool "Enable ACLs for NFSDv2"
+		default n
+
+	config KERNEL_NFSD_V3_ACL_SUPPORT
+		bool "Enable ACLs for NFSDv3"
+		default n
+
+	config KERNEL_REISER_FS_POSIX_ACL
+		bool "Enable POSIX ACLs for ReiserFS"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_XFS_POSIX_ACL
+		bool "Enable POSIX ACLs for XFS"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+	config KERNEL_JFS_POSIX_ACL
+		bool "Enable POSIX ACLs for JFS"
+		select KERNEL_FS_POSIX_ACL
+		default y if USE_FS_ACL_ATTR
+
+endmenu
diff --git a/feeds.conf.default b/feeds.conf.default
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/include/autotools.mk b/include/autotools.mk
new file mode 100644
index 0000000000..63edd5bddd
--- /dev/null
+++ b/include/autotools.mk
@@ -0,0 +1,170 @@
+#
+# Copyright (C) 2007-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+autoconf_bool = $(patsubst %,$(if $($(1)),--enable,--disable)-%,$(2))
+
+# delete *.la-files from staging_dir - we can not yet remove respective lines within all package
+# Makefiles, since backfire still uses libtool v1.5.x which (may) require those files
+define libtool_remove_files
+	find $(1) -name '*.la' | $(XARGS) rm -f;
+endef
+
+
+AM_TOOL_PATHS:= \
+	AUTOM4TE=$(STAGING_DIR_HOST)/bin/autom4te \
+	AUTOCONF=$(STAGING_DIR_HOST)/bin/autoconf \
+	AUTOMAKE=$(STAGING_DIR_HOST)/bin/automake \
+	ACLOCAL=$(STAGING_DIR_HOST)/bin/aclocal \
+	AUTOHEADER=$(STAGING_DIR_HOST)/bin/autoheader \
+	LIBTOOLIZE=$(STAGING_DIR_HOST)/bin/libtoolize \
+	LIBTOOL=$(STAGING_DIR_HOST)/bin/libtool \
+	M4=$(STAGING_DIR_HOST)/bin/m4 \
+	AUTOPOINT=true
+
+# 1: build dir
+# 2: remove files
+# 3: automake paths
+# 4: libtool paths
+# 5: extra m4 dirs
+define autoreconf
+	(cd $(1); \
+		$(patsubst %,rm -f %;,$(2)) \
+		$(foreach p,$(3), \
+			if [ -f $(p)/configure.ac ] || [ -f $(p)/configure.in ]; then \
+				[ -d $(p)/autom4te.cache ] && rm -rf autom4te.cache; \
+				[ -e $(p)/config.rpath ] || \
+						ln -s $(SCRIPT_DIR)/config.rpath $(p)/config.rpath; \
+				touch NEWS AUTHORS COPYING ABOUT-NLS ChangeLog; \
+				$(AM_TOOL_PATHS) $(STAGING_DIR_HOST)/bin/autoreconf -v -f -i -s \
+					$(if $(word 2,$(3)),--no-recursive) \
+					-B $(STAGING_DIR_HOST)/share/aclocal \
+					$(patsubst %,-I %,$(5)) \
+					$(patsubst %,-I %,$(4)) $(p) || true; \
+			fi; \
+		) \
+	);
+endef
+
+# 1: build dir
+define patch_libtool
+	@(cd $(1); \
+		for lt in $$$$($$(STAGING_DIR_HOST)/bin/find . -name ltmain.sh); do \
+			lt_version="$$$$($$(STAGING_DIR_HOST)/bin/sed -ne 's,^[[:space:]]*VERSION="\?\([0-9]\.[0-9]\+\).*,\1,p' $$$$lt)"; \
+			case "$$$$lt_version" in \
+				1.5|2.2|2.4) echo "autotools.mk: Found libtool v$$$$lt_version - applying patch to $$$$lt"; \
+					(cd $$$$(dirname $$$$lt) && $$(PATCH) -N -s -p1 < $$(TOPDIR)/tools/libtool/files/libtool-v$$$$lt_version.patch || true) ;; \
+				*) echo "autotools.mk: error: Unsupported libtool version v$$$$lt_version - cannot patch $$$$lt"; exit 1 ;; \
+			esac; \
+		done; \
+	);
+endef
+
+
+PKG_LIBTOOL_PATHS?=$(CONFIGURE_PATH)
+PKG_AUTOMAKE_PATHS?=$(CONFIGURE_PATH)
+PKG_MACRO_PATHS?=m4
+PKG_REMOVE_FILES?=aclocal.m4
+
+Hooks/InstallDev/Post += libtool_remove_files
+
+define autoreconf_target
+  $(strip $(call autoreconf, \
+    $(PKG_BUILD_DIR), $(PKG_REMOVE_FILES), \
+    $(PKG_AUTOMAKE_PATHS), $(PKG_LIBTOOL_PATHS), \
+    $(STAGING_DIR)/host/share/aclocal $(STAGING_DIR)/usr/share/aclocal $(PKG_MACRO_PATHS)))
+endef
+
+define patch_libtool_target
+  $(strip $(call patch_libtool, \
+    $(PKG_BUILD_DIR)))
+endef
+
+define gettext_version_target
+	(cd $(PKG_BUILD_DIR) && \
+		GETTEXT_VERSION=$(shell $(STAGING_DIR)/host/bin/gettext -V | $(STAGING_DIR_HOST)/bin/sed -ne '1s/.*\([0-9]\.[0-9]\{2\}\.[0-9]\).*/\1/p' ) && \
+		$(STAGING_DIR_HOST)/bin/sed \
+			-i $(PKG_BUILD_DIR)/configure.ac \
+			-e "s/AM_GNU_GETTEXT_VERSION(.*)/AM_GNU_GETTEXT_VERSION(\[$$$$GETTEXT_VERSION\])/g" && \
+		$(STAGING_DIR)/host/bin/autopoint --force \
+	);
+endef
+
+ifneq ($(filter gettext-version,$(PKG_FIXUP)),)
+  Hooks/Configure/Pre += gettext_version_target
+ ifeq ($(filter no-autoreconf,$(PKG_FIXUP)),)
+  Hooks/Configure/Pre += autoreconf_target
+ endif
+endif
+
+ifneq ($(filter patch-libtool,$(PKG_FIXUP)),)
+  Hooks/Configure/Pre += patch_libtool_target
+endif
+
+ifneq ($(filter libtool,$(PKG_FIXUP)),)
+  PKG_BUILD_DEPENDS += libtool libintl libiconv
+ ifeq ($(filter no-autoreconf,$(PKG_FIXUP)),)
+  Hooks/Configure/Pre += autoreconf_target
+ endif
+endif
+
+ifneq ($(filter libtool-ucxx,$(PKG_FIXUP)),)
+  PKG_BUILD_DEPENDS += libtool libintl libiconv
+ ifeq ($(filter no-autoreconf,$(PKG_FIXUP)),)
+  Hooks/Configure/Pre += autoreconf_target
+ endif
+endif
+
+ifneq ($(filter autoreconf,$(PKG_FIXUP)),)
+  ifeq ($(filter autoreconf,$(Hooks/Configure/Pre)),)
+    Hooks/Configure/Pre += autoreconf_target
+  endif
+endif
+
+
+HOST_FIXUP?=$(PKG_FIXUP)
+HOST_LIBTOOL_PATHS?=$(if $(PKG_LIBTOOL_PATHS),$(PKG_LIBTOOL_PATHS),.)
+HOST_AUTOMAKE_PATHS?=$(if $(PKG_AUTOMAKE_PATHS),$(PKG_AUTOMAKE_PATHS),.)
+HOST_MACRO_PATHS?=$(if $(PKG_MACRO_PATHS),$(PKG_MACRO_PATHS),m4)
+HOST_REMOVE_FILES?=$(PKG_REMOVE_FILES)
+
+define autoreconf_host
+  $(strip $(call autoreconf, \
+    $(HOST_BUILD_DIR), $(HOST_REMOVE_FILES), \
+    $(HOST_AUTOMAKE_PATHS), $(HOST_LIBTOOL_PATHS), \
+    $(HOST_MACRO_PATHS)))
+endef
+
+define patch_libtool_host
+  $(strip $(call patch_libtool, \
+    $(HOST_BUILD_DIR)))
+endef
+
+ifneq ($(filter patch-libtool,$(PKG_FIXUP)),)
+  Hooks/HostConfigure/Pre += patch_libtool_host
+endif
+
+ifneq ($(filter patch-libtool,$(HOST_FIXUP)),)
+  Hooks/HostConfigure/Pre += $(strip $(call patch_libtool,$(HOST_BUILD_DIR)))
+endif
+
+ifneq ($(filter libtool,$(HOST_FIXUP)),)
+ ifeq ($(filter no-autoreconf,$(HOST_FIXUP)),)
+  Hooks/HostConfigure/Pre += autoreconf_host
+ endif
+endif
+
+ifneq ($(filter libtool-ucxx,$(HOST_FIXUP)),)
+ ifeq ($(filter no-autoreconf,$(HOST_FIXUP)),)
+  Hooks/HostConfigure/Pre += autoreconf_host
+ endif
+endif
+
+ifneq ($(filter autoreconf,$(HOST_FIXUP)),)
+  ifeq ($(filter autoreconf,$(Hooks/HostConfigure/Pre)),)
+    Hooks/HostConfigure/Pre += autoreconf_host
+  endif
+endif
diff --git a/include/cmake.mk b/include/cmake.mk
new file mode 100644
index 0000000000..5f572e9d74
--- /dev/null
+++ b/include/cmake.mk
@@ -0,0 +1,109 @@
+cmake_bool = $(patsubst %,-D%:BOOL=$(if $($(1)),ON,OFF),$(2))
+
+PKG_INSTALL:=1
+
+ifneq ($(findstring c,$(OPENWRT_VERBOSE)),)
+  MAKE_FLAGS+=VERBOSE=1
+endif
+
+CMAKE_BINARY_DIR = $(PKG_BUILD_DIR)$(if $(CMAKE_BINARY_SUBDIR),/$(CMAKE_BINARY_SUBDIR))
+CMAKE_SOURCE_DIR = $(PKG_BUILD_DIR)
+HOST_CMAKE_SOURCE_DIR = $(HOST_BUILD_DIR)
+MAKE_PATH = $(firstword $(CMAKE_BINARY_SUBDIR) .)
+
+ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+  cmake_tool=$(TOOLCHAIN_DIR)/bin/$(1)
+else
+  cmake_tool=$(shell which $(1))
+endif
+
+ifeq ($(CONFIG_CCACHE),)
+ CMAKE_C_COMPILER:=$(call cmake_tool,$(TARGET_CC))
+ CMAKE_CXX_COMPILER:=$(call cmake_tool,$(TARGET_CXX))
+ CMAKE_C_COMPILER_ARG1:=
+ CMAKE_CXX_COMPILER_ARG1:=
+else
+  CCACHE:=$(STAGING_DIR_HOST)/bin/ccache
+  CMAKE_C_COMPILER:=$(CCACHE)
+  CMAKE_C_COMPILER_ARG1:=$(TARGET_CC_NOCACHE)
+  CMAKE_CXX_COMPILER:=$(CCACHE)
+  CMAKE_CXX_COMPILER_ARG1:=$(TARGET_CXX_NOCACHE)
+endif
+CMAKE_AR:=$(call cmake_tool,$(TARGET_AR))
+CMAKE_NM:=$(call cmake_tool,$(TARGET_NM))
+CMAKE_RANLIB:=$(call cmake_tool,$(TARGET_RANLIB))
+
+CMAKE_FIND_ROOT_PATH:=$(STAGING_DIR)/usr;$(TOOLCHAIN_DIR)$(if $(CONFIG_EXTERNAL_TOOLCHAIN),;$(CONFIG_TOOLCHAIN_ROOT))
+CMAKE_HOST_FIND_ROOT_PATH:=$(STAGING_DIR)/host;$(STAGING_DIR_HOST)
+CMAKE_SHARED_LDFLAGS:=-Wl,-Bsymbolic-functions
+
+define Build/Configure/Default
+	mkdir -p $(CMAKE_BINARY_DIR)
+	(cd $(CMAKE_BINARY_DIR); \
+		CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS)" \
+		CXXFLAGS="$(TARGET_CXXFLAGS) $(EXTRA_CXXFLAGS)" \
+		LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS)" \
+		cmake \
+			-DCMAKE_SYSTEM_NAME=Linux \
+			-DCMAKE_SYSTEM_VERSION=1 \
+			-DCMAKE_SYSTEM_PROCESSOR=$(ARCH) \
+			-DCMAKE_BUILD_TYPE=Release \
+			-DCMAKE_C_FLAGS_RELEASE="-DNDEBUG" \
+			-DCMAKE_CXX_FLAGS_RELEASE="-DNDEBUG" \
+			-DCMAKE_C_COMPILER="$(CMAKE_C_COMPILER)" \
+			-DCMAKE_C_COMPILER_ARG1="$(CMAKE_C_COMPILER_ARG1)" \
+			-DCMAKE_CXX_COMPILER="$(CMAKE_CXX_COMPILER)" \
+			-DCMAKE_CXX_COMPILER_ARG1="$(CMAKE_CXX_COMPILER_ARG1)" \
+			-DCMAKE_ASM_COMPILER="$(CMAKE_C_COMPILER)" \
+			-DCMAKE_ASM_COMPILER_ARG1="$(CMAKE_C_COMPILER_ARG1)" \
+			-DCMAKE_EXE_LINKER_FLAGS:STRING="$(TARGET_LDFLAGS)" \
+			-DCMAKE_MODULE_LINKER_FLAGS:STRING="$(TARGET_LDFLAGS) $(CMAKE_SHARED_LDFLAGS)" \
+			-DCMAKE_SHARED_LINKER_FLAGS:STRING="$(TARGET_LDFLAGS) $(CMAKE_SHARED_LDFLAGS)" \
+			-DCMAKE_AR="$(CMAKE_AR)" \
+			-DCMAKE_NM="$(CMAKE_NM)" \
+			-DCMAKE_RANLIB="$(CMAKE_RANLIB)" \
+			-DCMAKE_FIND_ROOT_PATH="$(CMAKE_FIND_ROOT_PATH)" \
+			-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=BOTH \
+			-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
+			-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
+			-DCMAKE_STRIP=: \
+			-DCMAKE_INSTALL_PREFIX=/usr \
+			-DDL_LIBRARY=$(STAGING_DIR) \
+			-DCMAKE_PREFIX_PATH=$(STAGING_DIR) \
+			-DCMAKE_SKIP_RPATH=TRUE  \
+			$(CMAKE_OPTIONS) \
+		$(CMAKE_SOURCE_DIR) \
+	)
+endef
+
+define Build/InstallDev/cmake
+	$(INSTALL_DIR) $(1)
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+endef
+
+Build/InstallDev = $(if $(CMAKE_INSTALL),$(Build/InstallDev/cmake))
+
+define Host/Configure/Default
+	(cd $(HOST_BUILD_DIR); \
+		CFLAGS="$(HOST_CFLAGS)" \
+		CXXFLAGS="$(HOST_CFLAGS)" \
+		LDFLAGS="$(HOST_LDFLAGS)" \
+		cmake \
+			-DCMAKE_BUILD_TYPE=Release \
+			-DCMAKE_C_FLAGS_RELEASE="-DNDEBUG" \
+			-DCMAKE_CXX_FLAGS_RELEASE="-DNDEBUG" \
+			-DCMAKE_EXE_LINKER_FLAGS:STRING="$(HOST_LDFLAGS)" \
+			-DCMAKE_MODULE_LINKER_FLAGS:STRING="$(HOST_LDFLAGS)" \
+			-DCMAKE_SHARED_LINKER_FLAGS:STRING="$(HOST_LDFLAGS)" \
+			-DCMAKE_FIND_ROOT_PATH="$(CMAKE_HOST_FIND_ROOT_PATH)" \
+			-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=BOTH \
+			-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
+			-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
+			-DCMAKE_STRIP=: \
+			-DCMAKE_INSTALL_PREFIX=$(HOST_BUILD_PREFIX) \
+			-DCMAKE_PREFIX_PATH=$(HOST_BUILD_PREFIX) \
+			-DCMAKE_SKIP_RPATH=TRUE  \
+			$(CMAKE_HOST_OPTIONS) \
+		$(HOST_CMAKE_SOURCE_DIR) \
+	)
+endef
diff --git a/include/debug.mk b/include/debug.mk
new file mode 100644
index 0000000000..59a99c0f77
--- /dev/null
+++ b/include/debug.mk
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+# debug flags:
+#
+# d: show subdirectory tree
+# t: show added targets
+# l: show legacy targets
+# r: show autorebuild messages
+# v: verbose (no .SILENCE for common targets)
+
+ifeq ($(DUMP),)
+  ifeq ($(DEBUG),all)
+    build_debug:=dltvr
+  else
+    build_debug:=$(DEBUG)
+  endif
+endif
+
+ifneq ($(DEBUG),)
+
+define debug
+$$(findstring $(2),$$(if $$(DEBUG_SCOPE_DIR),$$(if $$(filter $$(DEBUG_SCOPE_DIR)%,$(1)),$(build_debug)),$(build_debug)))
+endef
+
+define warn
+$$(if $(call debug,$(1),$(2)),$$(warning $(3)))
+endef
+
+define debug_eval
+$$(if $(call debug,$(1),$(2)),$(3))
+endef
+
+define warn_eval
+$(call warn,$(1),$(2),$(3)	$(4))
+$(4)
+endef
+
+else
+
+debug:=
+warn:=
+debug_eval:=
+warn_eval = $(4)
+
+endif
+
diff --git a/include/depends.mk b/include/depends.mk
new file mode 100644
index 0000000000..7135e52c0f
--- /dev/null
+++ b/include/depends.mk
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# define a dependency on a subtree
+# parameters:
+#	1: directories/files
+#	2: directory dependency
+#	3: tempfile for file listings
+#	4: find options
+
+DEP_FINDPARAMS := -x "*/.svn*" -x ".*" -x "*:*" -x "*\!*" -x "* *" -x "*\\\#*" -x "*/.*_check" -x "*/.*.swp"
+
+find_md5=$(SH_FUNC) find $(wildcard $(1)) -type f $(patsubst -x,-and -not -path,$(DEP_FINDPARAMS) $(2)) | md5s
+
+define rdep
+  .PRECIOUS: $(2)
+  .SILENT: $(2)_check
+
+  $(2): $(2)_check
+
+ifneq ($(wildcard $(2)),)
+  $(2)_check::
+	$(if $(3), \
+		$(call find_md5,$(1),$(4)) > $(3).1; \
+		{ [ \! -f "$(3)" ] || diff $(3) $(3).1 >/dev/null; } && \
+	) \
+	{ \
+		[ -f "$(2)_check.1" ] && mv "$(2)_check.1"; \
+	    $(TOPDIR)/scripts/timestamp.pl $(DEP_FINDPARAMS) $(4) -n $(2) $(1) && { \
+			$(call debug_eval,$(SUBDIR),r,echo "No need to rebuild $(2)";) \
+			touch -r "$(2)" "$(2)_check"; \
+		} \
+	} || { \
+		$(call debug_eval,$(SUBDIR),r,echo "Need to rebuild $(2)";) \
+		touch "$(2)_check"; \
+	}
+	$(if $(3), mv $(3).1 $(3))
+else
+  $(2)_check::
+	$(if $(3), rm -f $(3) $(3).1)
+	$(call debug_eval,$(SUBDIR),r,echo "Target $(2) not built")
+endif
+
+endef
+
diff --git a/include/device_table.txt b/include/device_table.txt
new file mode 100644
index 0000000000..f45b158892
--- /dev/null
+++ b/include/device_table.txt
@@ -0,0 +1,5 @@
+# minimal device table file for OpenWrt
+
+#<name>		<type>	<mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
+/dev		d	755	0	0	-	-	-	-	-
+/dev/console	c	600	0	0	5	1	0	0	-
diff --git a/include/download.mk b/include/download.mk
new file mode 100644
index 0000000000..fccd83942f
--- /dev/null
+++ b/include/download.mk
@@ -0,0 +1,196 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+# Copyright (C) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+OPENWRT_GIT = http://git.openwrt.org
+LEDE_GIT = https://git.lede-project.org
+
+DOWNLOAD_RDEP=$(STAMP_PREPARED) $(HOST_STAMP_PREPARED)
+
+# Try to guess the download method from the URL
+define dl_method
+$(strip \
+  $(if $(2),$(2), \
+    $(if $(filter @APACHE/% @GITHUB/% @GNOME/% @GNU/% @KERNEL_LIBRE/% @KERNEL/% @SF/% @SAVANNAH/% ftp://% http://% https://% file://%,$(1)),default, \
+      $(if $(filter git://%,$(1)),git, \
+        $(if $(filter svn://%,$(1)),svn, \
+          $(if $(filter cvs://%,$(1)),cvs, \
+            $(if $(filter hg://%,$(1)),hg, \
+              $(if $(filter sftp://%,$(1)),bzr, \
+                unknown \
+              ) \
+            ) \
+          ) \
+        ) \
+      ) \
+    ) \
+  ) \
+)
+endef
+
+# code for creating tarballs from cvs/svn/git/bzr/hg/darcs checkouts - useful for mirror support
+dl_pack/bz2=$(TAR) --owner=0 --group=0 --sort=name $$$${TAR_TIMESTAMP:+--mtime="$$$$TAR_TIMESTAMP"} -cjf $(1) $(2)
+dl_pack/gz=$(TAR) --owner=0 --group=0 --sort=name $$$${TAR_TIMESTAMP:+--mtime="$$$$TAR_TIMESTAMP"} -c $(2) | gzip -nc > $(1)
+dl_pack/xz=$(TAR) --owner=0 --group=0 --sort=name $$$${TAR_TIMESTAMP:+--mtime="$$$$TAR_TIMESTAMP"} -c $(2) | xz -zc -7e > $(1)
+dl_pack/unknown=echo "ERROR: Unknown pack format for file $(1)"; false
+define dl_pack
+	$(if $(dl_pack/$(call ext,$(1))),$(dl_pack/$(call ext,$(1))),$(dl_pack/unknown))
+endef
+
+define DownloadMethod/unknown
+	@echo "ERROR: No download method available"; false
+endef
+
+define DownloadMethod/default
+	$(SCRIPT_DIR)/download.pl "$(DL_DIR)" "$(FILE)" "$(MD5SUM)" "$(URL_FILE)" $(foreach url,$(URL),"$(url)")
+endef
+
+define wrap_mirror
+$(if $(if $(MIRROR),$(filter-out x,$(MIRROR_MD5SUM))),$(SCRIPT_DIR)/download.pl "$(DL_DIR)" "$(FILE)" "$(MIRROR_MD5SUM)" "" || ( $(1) ),$(1))
+endef
+
+define DownloadMethod/cvs
+	$(call wrap_mirror, \
+		echo "Checking out files from the cvs repository..."; \
+		mkdir -p $(TMP_DIR)/dl && \
+		cd $(TMP_DIR)/dl && \
+		rm -rf $(SUBDIR) && \
+		[ \! -d $(SUBDIR) ] && \
+		cvs -d $(URL) export $(VERSION) $(SUBDIR) && \
+		echo "Packing checkout..." && \
+		$(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \
+		mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/ && \
+		rm -rf $(SUBDIR); \
+	)
+endef
+
+define DownloadMethod/svn
+	$(call wrap_mirror, \
+		echo "Checking out files from the svn repository..."; \
+		mkdir -p $(TMP_DIR)/dl && \
+		cd $(TMP_DIR)/dl && \
+		rm -rf $(SUBDIR) && \
+		[ \! -d $(SUBDIR) ] && \
+		( svn help export | grep -q trust-server-cert && \
+		svn export --non-interactive --trust-server-cert -r$(VERSION) $(URL) $(SUBDIR) || \
+		svn export --non-interactive -r$(VERSION) $(URL) $(SUBDIR) ) && \
+		echo "Packing checkout..." && \
+		export TAR_TIMESTAMP="" && \
+		$(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \
+		mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/ && \
+		rm -rf $(SUBDIR); \
+	)
+endef
+
+define DownloadMethod/git
+	$(call wrap_mirror, \
+		echo "Checking out files from the git repository..."; \
+		mkdir -p $(TMP_DIR)/dl && \
+		cd $(TMP_DIR)/dl && \
+		rm -rf $(SUBDIR) && \
+		[ \! -d $(SUBDIR) ] && \
+		git clone $(OPTS) $(URL) $(SUBDIR) && \
+		(cd $(SUBDIR) && git checkout $(VERSION) && \
+		git submodule update --init --recursive) && \
+		echo "Packing checkout..." && \
+		export TAR_TIMESTAMP=`cd $(SUBDIR) && git log -1 --format='@%ct'` && \
+		rm -rf $(SUBDIR)/.git && \
+		$(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \
+		mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/ && \
+		rm -rf $(SUBDIR); \
+	)
+endef
+
+define DownloadMethod/bzr
+	$(call wrap_mirror, \
+		echo "Checking out files from the bzr repository..."; \
+		mkdir -p $(TMP_DIR)/dl && \
+		cd $(TMP_DIR)/dl && \
+		rm -rf $(SUBDIR) && \
+		[ \! -d $(SUBDIR) ] && \
+		bzr export --per-file-timestamps -r$(VERSION) $(SUBDIR) $(URL) && \
+		echo "Packing checkout..." && \
+		export TAR_TIMESTAMP="" && \
+		$(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \
+		mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/ && \
+		rm -rf $(SUBDIR); \
+	)
+endef
+
+define DownloadMethod/hg
+	$(call wrap_mirror, \
+		echo "Checking out files from the hg repository..."; \
+		mkdir -p $(TMP_DIR)/dl && \
+		cd $(TMP_DIR)/dl && \
+		rm -rf $(SUBDIR) && \
+		[ \! -d $(SUBDIR) ] && \
+		hg clone -r $(VERSION) $(URL) $(SUBDIR) && \
+		export TAR_TIMESTAMP=`cd $(SUBDIR) && hg log --template '@{date}' -l 1` && \
+		find $(SUBDIR) -name .hg | xargs rm -rf && \
+		echo "Packing checkout..." && \
+		$(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \
+		mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/ && \
+		rm -rf $(SUBDIR); \
+	)
+endef
+
+define DownloadMethod/darcs
+	$(call wrap_mirror, \
+		echo "Checking out files from the darcs repository..."; \
+		mkdir -p $(TMP_DIR)/dl && \
+		cd $(TMP_DIR)/dl && \
+		rm -rf $(SUBDIR) && \
+		[ \! -d $(SUBDIR) ] && \
+		darcs get -t $(VERSION) $(URL) $(SUBDIR) && \
+		export TAR_TIMESTAMP=`cd $(SUBDIR) && LC_ALL=C darcs log --last 1 | sed -ne 's!^Date: \+!!p'` && \
+		find $(SUBDIR) -name _darcs | xargs rm -rf && \
+		echo "Packing checkout..." && \
+		$(call dl_pack,$(TMP_DIR)/dl/$(FILE),$(SUBDIR)) && \
+		mv $(TMP_DIR)/dl/$(FILE) $(DL_DIR)/ && \
+		rm -rf $(SUBDIR); \
+	)
+endef
+
+Validate/cvs=VERSION SUBDIR
+Validate/svn=VERSION SUBDIR
+Validate/git=VERSION SUBDIR
+Validate/bzr=VERSION SUBDIR
+Validate/hg=VERSION SUBDIR
+Validate/darcs=VERSION SUBDIR
+
+define Download/Defaults
+  URL:=
+  FILE:=
+  URL_FILE:=
+  PROTO:=
+  MD5SUM:=
+  SUBDIR:=
+  MIRROR:=1
+  MIRROR_MD5SUM:=x
+  VERSION:=
+  OPTS:=
+endef
+
+define Download
+  $(eval $(Download/Defaults))
+  $(eval $(Download/$(1)))
+  $(foreach FIELD,URL FILE $(Validate/$(call dl_method,$(URL),$(PROTO))),
+    ifeq ($($(FIELD)),)
+      $$(error Download/$(1) is missing the $(FIELD) field.)
+    endif
+  )
+
+  $(foreach dep,$(DOWNLOAD_RDEP),
+    $(dep): $(DL_DIR)/$(FILE)
+  )
+  download: $(DL_DIR)/$(FILE)
+
+  $(DL_DIR)/$(FILE):
+	mkdir -p $(DL_DIR)
+	$(call locked,$(if $(DownloadMethod/$(call dl_method,$(URL),$(PROTO))),$(DownloadMethod/$(call dl_method,$(URL),$(PROTO))),$(DownloadMethod/unknown)),$(FILE))
+
+endef
diff --git a/include/feeds.mk b/include/feeds.mk
new file mode 100644
index 0000000000..2ff57e5762
--- /dev/null
+++ b/include/feeds.mk
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+-include $(TMP_DIR)/.packagesubdirs
+
+FEEDS_INSTALLED:=$(notdir $(wildcard $(TOPDIR)/package/feeds/*))
+FEEDS_AVAILABLE:=$(sort $(FEEDS_INSTALLED) $(shell $(SCRIPT_DIR)/feeds list -n))
+FEEDS_ENABLED:=$(foreach feed,$(FEEDS_INSTALLED),$(if $(CONFIG_FEED_$(feed)),$(feed)))
+FEEDS_DISABLED:=$(filter-out $(FEEDS_ENABLED),$(FEEDS_AVAILABLE))
+
+PACKAGE_SUBDIRS=$(PACKAGE_DIR)
+ifneq ($(CONFIG_PER_FEED_REPO),)
+  PACKAGE_SUBDIRS += $(OUTPUT_DIR)/packages/$(ARCH_PACKAGES)/base
+  ifneq ($(CONFIG_PER_FEED_REPO_ADD_DISABLED),)
+    PACKAGE_SUBDIRS += $(foreach FEED,$(FEEDS_AVAILABLE),$(OUTPUT_DIR)/packages/$(ARCH_PACKAGES)/$(FEED))
+  else
+    PACKAGE_SUBDIRS += $(foreach FEED,$(FEEDS_ENABLED),$(OUTPUT_DIR)/packages/$(ARCH_PACKAGES)/$(FEED))
+  endif
+endif
+
+PACKAGE_DIR_ALL := $(TOPDIR)/staging_dir/packages/$(BOARD)
+
+opkg_package_files = $(wildcard \
+	$(foreach dir,$(PACKAGE_SUBDIRS), \
+	  $(foreach pkg,$(1), $(dir)/$(pkg)_*.ipk)))
+
+PKG_CONFIG_DEPENDS += \
+	CONFIG_PER_FEED_REPO \
+	CONFIG_PER_FEED_REPO_ADD_DISABLED \
+	CONFIG_PER_FEED_REPO_ADD_COMMENTED \
+	$(foreach feed,$(FEEDS_INSTALLED),CONFIG_FEED_$(feed))
+
+# 1: package name
+define FeedPackageDir
+$(strip $(if $(CONFIG_PER_FEED_REPO), \
+  $(if $(Package/$(1)/subdir), \
+    $(abspath $(OUTPUT_DIR)/packages/$(ARCH_PACKAGES)/$(Package/$(1)/subdir)), \
+    $(PACKAGE_DIR)), \
+  $(PACKAGE_DIR)))
+endef
+
+# 1: destination file
+define FeedSourcesAppend
+( \
+  echo "src/gz %n_core %U/targets/%S/packages"; \
+  $(strip $(if $(CONFIG_PER_FEED_REPO), \
+	$(foreach feed,base $(FEEDS_ENABLED),echo "src/gz %n_$(feed) %U/packages/%A/$(feed)";) \
+	$(if $(CONFIG_PER_FEED_REPO_ADD_DISABLED), \
+		$(foreach feed,$(FEEDS_DISABLED),echo "$(if $(CONFIG_PER_FEED_REPO_ADD_COMMENTED),# )src/gz %n_$(feed) %U/packages/%A/$(feed)";)))) \
+) >> $(1)
+endef
diff --git a/include/hardening.mk b/include/hardening.mk
new file mode 100644
index 0000000000..c277081c51
--- /dev/null
+++ b/include/hardening.mk
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+PKG_CHECK_FORMAT_SECURITY ?= 1
+PKG_SSP ?= 1
+PKG_FORTIFY_SOURCE ?= 1
+PKG_RELRO ?= 1
+
+ifdef CONFIG_PKG_CHECK_FORMAT_SECURITY
+  ifeq ($(strip $(PKG_CHECK_FORMAT_SECURITY)),1)
+    TARGET_CFLAGS += -Wformat -Werror=format-security
+  endif
+endif
+ifdef CONFIG_PKG_CC_STACKPROTECTOR_REGULAR
+  ifeq ($(strip $(PKG_SSP)),1)
+    TARGET_CFLAGS += -fstack-protector
+  endif
+endif
+ifdef CONFIG_PKG_CC_STACKPROTECTOR_STRONG
+  ifeq ($(strip $(PKG_SSP)),1)
+    TARGET_CFLAGS += -fstack-protector-strong
+  endif
+endif
+ifdef CONFIG_PKG_FORTIFY_SOURCE_1
+  ifeq ($(strip $(PKG_FORTIFY_SOURCE)),1)
+    TARGET_CFLAGS += -D_FORTIFY_SOURCE=1
+  endif
+endif
+ifdef CONFIG_PKG_FORTIFY_SOURCE_2
+  ifeq ($(strip $(PKG_FORTIFY_SOURCE)),1)
+    TARGET_CFLAGS += -D_FORTIFY_SOURCE=2
+  endif
+endif
+ifdef CONFIG_PKG_RELRO_PARTIAL
+  ifeq ($(strip $(PKG_RELRO)),1)
+    TARGET_CFLAGS += -Wl,-z,relro
+    TARGET_LDFLAGS += -zrelro
+  endif
+endif
+ifdef CONFIG_PKG_RELRO_FULL
+  ifeq ($(strip $(PKG_RELRO)),1)
+    TARGET_CFLAGS += -Wl,-z,now -Wl,-z,relro
+    TARGET_LDFLAGS += -znow -zrelro
+  endif
+endif
+
diff --git a/include/host-build.mk b/include/host-build.mk
new file mode 100644
index 0000000000..d353c88b5c
--- /dev/null
+++ b/include/host-build.mk
@@ -0,0 +1,210 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+HOST_BUILD_DIR ?= $(BUILD_DIR_HOST)/$(PKG_NAME)$(if $(PKG_VERSION),-$(PKG_VERSION))
+HOST_INSTALL_DIR ?= $(HOST_BUILD_DIR)/host-install
+HOST_BUILD_PARALLEL ?=
+
+ifneq ($(CONFIG_PKG_BUILD_USE_JOBSERVER),)
+  HOST_MAKE_J:=$(if $(MAKE_JOBSERVER),$(MAKE_JOBSERVER) $(if $(filter 3.% 4.0 4.1,$(MAKE_VERSION)),-j))
+else
+  HOST_MAKE_J:=-j$(CONFIG_PKG_BUILD_JOBS)
+endif
+
+ifeq ($(strip $(HOST_BUILD_PARALLEL)),0)
+HOST_JOBS?=-j1
+else
+HOST_JOBS?=$(if $(HOST_BUILD_PARALLEL)$(CONFIG_PKG_DEFAULT_PARALLEL),\
+	$(if $(CONFIG_PKG_BUILD_PARALLEL),$(HOST_MAKE_J),-j1),-j1)
+endif
+
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/unpack.mk
+include $(INCLUDE_DIR)/depends.mk
+
+BUILD_TYPES += host
+HOST_STAMP_PREPARED=$(HOST_BUILD_DIR)/.prepared$(if $(HOST_QUILT)$(DUMP),,$(shell $(call find_md5,${CURDIR} $(PKG_FILE_DEPENDS),)))
+HOST_STAMP_CONFIGURED:=$(HOST_BUILD_DIR)/.configured
+HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.built
+HOST_BUILD_PREFIX:=$(if $(IS_PACKAGE_BUILD),$(STAGING_DIR_HOSTPKG),$(STAGING_DIR_HOST))
+HOST_STAMP_INSTALLED:=$(HOST_BUILD_PREFIX)/stamp/.$(PKG_NAME)_installed
+
+override MAKEFLAGS=
+
+include $(INCLUDE_DIR)/download.mk
+include $(INCLUDE_DIR)/quilt.mk
+include $(INCLUDE_DIR)/autotools.mk
+
+Host/Patch:=$(Host/Patch/Default)
+ifneq ($(strip $(HOST_UNPACK)),)
+  define Host/Prepare/Default
+	$(HOST_UNPACK)
+	[ ! -d ./src/ ] || $(CP) ./src/* $(HOST_BUILD_DIR)
+	$(Host/Patch)
+  endef
+endif
+
+define Host/Prepare
+  $(call Host/Prepare/Default)
+endef
+
+ifeq ($(HOST_OS),Darwin)
+  HOST_CFLAGS += -I/usr/local/opt/openssl/include
+  HOST_LDFLAGS += -L/usr/local/opt/openssl/lib
+endif
+
+HOST_CONFIGURE_VARS = \
+	CC="$(HOSTCC)" \
+	CFLAGS="$(HOST_CFLAGS)" \
+	CPPFLAGS="$(HOST_CPPFLAGS)" \
+	LDFLAGS="$(HOST_LDFLAGS)" \
+	SHELL="$(SHELL)"
+
+HOST_CONFIGURE_ARGS = \
+	--target=$(GNU_HOST_NAME) \
+	--host=$(GNU_HOST_NAME) \
+	--build=$(GNU_HOST_NAME) \
+	--program-prefix="" \
+	--program-suffix="" \
+	--prefix=$(HOST_BUILD_PREFIX) \
+	--exec-prefix=$(HOST_BUILD_PREFIX) \
+	--sysconfdir=$(HOST_BUILD_PREFIX)/etc \
+	--localstatedir=$(HOST_BUILD_PREFIX)/var \
+	--sbindir=$(HOST_BUILD_PREFIX)/bin
+
+HOST_MAKE_FLAGS =
+
+HOST_CONFIGURE_CMD = $(BASH) ./configure
+
+define Host/Configure/Default
+	$(if $(HOST_CONFIGURE_PARALLEL),+)(cd $(HOST_BUILD_DIR)/$(3); \
+		if [ -x configure ]; then \
+			$(CP) $(SCRIPT_DIR)/config.{guess,sub} $(HOST_BUILD_DIR)/$(3)/ && \
+			$(2) \
+			$(HOST_CONFIGURE_CMD) \
+			$(HOST_CONFIGURE_VARS) \
+			$(HOST_CONFIGURE_ARGS) \
+			$(1); \
+		fi \
+	)
+endef
+
+define Host/Configure
+  $(call Host/Configure/Default)
+endef
+
+define Host/Compile/Default
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) \
+		$(HOST_MAKE_FLAGS) \
+		$(1)
+endef
+
+define Host/Compile
+  $(call Host/Compile/Default)
+endef
+
+define Host/Install/Default
+	$(_SINGLE)$(MAKE) -C $(HOST_BUILD_DIR) install
+endef
+
+define Host/Install
+  $(call Host/Install/Default,$(HOST_BUILD_PREFIX))
+endef
+
+
+ifneq ($(if $(HOST_QUILT),,$(CONFIG_AUTOREBUILD)),)
+  define HostHost/Autoclean
+    $(call rdep,${CURDIR} $(PKG_FILE_DEPENDS),$(HOST_STAMP_PREPARED))
+    $(if $(if $(Host/Compile),$(filter prepare,$(MAKECMDGOALS)),1),,$(call rdep,$(HOST_BUILD_DIR),$(HOST_STAMP_BUILT)))
+  endef
+endif
+
+define Download/default
+  FILE:=$(PKG_SOURCE)
+  URL:=$(PKG_SOURCE_URL)
+  PROTO:=$(PKG_SOURCE_PROTO)
+  SUBDIR:=$(PKG_SOURCE_SUBDIR)
+  VERSION:=$(PKG_SOURCE_VERSION)
+  MD5SUM:=$(PKG_MD5SUM)
+  MIRROR_MD5SUM:=$(PKG_MIRROR_MD5SUM)
+endef
+
+define Host/Exports/Default
+  $(1) : export ACLOCAL_INCLUDE=$$(foreach p,$$(wildcard $$(STAGING_DIR_HOST)/share/aclocal $$(STAGING_DIR_HOST)/share/aclocal-* $(if $(IS_PACKAGE_BUILD),$$(STAGING_DIR)/host/share/aclocal $$(STAGING_DIR)/host/share/aclocal-*)),-I $$(p))
+  $(1) : export STAGING_PREFIX=$$(HOST_BUILD_PREFIX)
+  $(1) : export PKG_CONFIG_PATH=$$(STAGING_DIR_HOST)/lib/pkgconfig:$$(HOST_BUILD_PREFIX)/lib/pkgconfig
+  $(1) : export PKG_CONFIG_LIBDIR=$$(HOST_BUILD_PREFIX)/lib/pkgconfig
+  $(1) : export CCACHE_DIR:=$(STAGING_DIR_HOST)/ccache
+  $(if $(IS_PACKAGE_BUILD),$(1) : export PATH=$$(TARGET_PATH_PKG))
+endef
+Host/Exports=$(Host/Exports/Default)
+
+.NOTPARALLEL:
+
+ifndef DUMP
+  define HostBuild
+  $(if $(HOST_QUILT),$(Host/Quilt))
+  $(if $(if $(PKG_HOST_ONLY),,$(STAMP_PREPARED)),,$(if $(strip $(PKG_SOURCE_URL)),$(call Download,default)))
+  $(if $(DUMP),,$(call HostHost/Autoclean))
+
+  $(HOST_STAMP_PREPARED):
+	@-rm -rf $(HOST_BUILD_DIR)
+	@mkdir -p $(HOST_BUILD_DIR)
+	$(foreach hook,$(Hooks/HostPrepare/Pre),$(call $(hook))$(sep))
+	$(call Host/Prepare)
+	$(foreach hook,$(Hooks/HostPrepare/Post),$(call $(hook))$(sep))
+	touch $$@
+
+  $(call Host/Exports,$(HOST_STAMP_CONFIGURED))
+  $(HOST_STAMP_CONFIGURED): $(HOST_STAMP_PREPARED)
+	$(foreach hook,$(Hooks/HostConfigure/Pre),$(call $(hook))$(sep))
+	$(call Host/Configure)
+	$(foreach hook,$(Hooks/HostConfigure/Post),$(call $(hook))$(sep))
+	touch $$@
+
+  $(call Host/Exports,$(HOST_STAMP_BUILT))
+  $(HOST_STAMP_BUILT): $(HOST_STAMP_CONFIGURED)
+		$(foreach hook,$(Hooks/HostCompile/Pre),$(call $(hook))$(sep))
+		$(call Host/Compile)
+		$(foreach hook,$(Hooks/HostCompile/Post),$(call $(hook))$(sep))
+		touch $$@
+
+  $(call Host/Exports,$(HOST_STAMP_INSTALLED))
+  $(HOST_STAMP_INSTALLED): $(HOST_STAMP_BUILT) $(if $(FORCE_HOST_INSTALL),FORCE)
+		$(call Host/Install,$(HOST_BUILD_PREFIX))
+		$(foreach hook,$(Hooks/HostInstall/Post),$(call $(hook))$(sep))
+		mkdir -p $$(shell dirname $$@)
+		touch $(HOST_STAMP_BUILT)
+		touch $$@
+
+  ifndef STAMP_BUILT
+    prepare: host-prepare
+    compile: host-compile
+    install: host-install
+    clean: host-clean
+    update: host-update
+    refresh: host-refresh
+  endif
+
+  host-prepare: $(HOST_STAMP_PREPARED)
+  host-configure: $(HOST_STAMP_CONFIGURED)
+  host-compile: $(HOST_STAMP_BUILT) $(if $(STAMP_BUILT),$(HOST_STAMP_INSTALLED))
+  host-install: $(HOST_STAMP_INSTALLED)
+  host-clean: FORCE
+	$(call Host/Clean)
+	$(call Host/Uninstall)
+	rm -rf $(HOST_BUILD_DIR) $(HOST_STAMP_INSTALLED) $(HOST_STAMP_BUILT)
+
+  endef
+
+  download:
+  prepare:
+  compile:
+  install:
+  clean:
+
+endif
diff --git a/include/host.mk b/include/host.mk
new file mode 100644
index 0000000000..ec3ae276a4
--- /dev/null
+++ b/include/host.mk
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2007-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+TMP_DIR ?= $(TOPDIR)/tmp
+ifeq ($(if $(TARGET_BUILD),,$(DUMP)),)
+  -include $(TMP_DIR)/.host.mk
+endif
+
+ifneq ($(__host_inc),1)
+__host_inc:=1
+
+export PATH:=$(TOPDIR)/staging_dir/host/bin:$(PATH)
+
+try-run = $(shell set -e; \
+	TMP_F="$(TMP_DIR)/try-run.$$$$.tmp"; \
+	if ($(1)) >/dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi; \
+	rm -f "$$TMP_F"; \
+)
+
+host-cc-option = $(call try-run, \
+	$(HOSTCC) $(HOST_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP_F",$(1),$(2) \
+)
+
+.PRECIOUS: $(TMP_DIR)/.host.mk
+$(TMP_DIR)/.host.mk: $(TOPDIR)/include/host.mk
+	@mkdir -p $(TMP_DIR)
+	@( \
+		HOST_OS=`uname`; \
+		case "$$HOST_OS" in \
+			Linux) HOST_ARCH=`uname -m`;; \
+			Darwin) HOST_ARCH=`uname -m`;; \
+			*) HOST_ARCH=`uname -p`;; \
+		esac; \
+		GNU_HOST_NAME=`gcc -dumpmachine`; \
+		[ -z "$$GNU_HOST_NAME" -o "$$HOST_OS" = "Darwin" ] && \
+			GNU_HOST_NAME=`$(TOPDIR)/scripts/config.guess`; \
+		echo "HOST_OS:=$$HOST_OS" > $@; \
+		echo "HOST_ARCH:=$$HOST_ARCH" >> $@; \
+		echo "GNU_HOST_NAME:=$$GNU_HOST_NAME" >> $@; \
+		if gfind -L /dev/null || find -L /dev/null; then \
+			echo "FIND_L=find -L \$$(1)" >> $@; \
+		else \
+			echo "FIND_L=find \$$(1) -follow" >> $@; \
+		fi \
+	) >/dev/null 2>/dev/null
+
+endif
diff --git a/include/image-commands.mk b/include/image-commands.mk
new file mode 100644
index 0000000000..083a389031
--- /dev/null
+++ b/include/image-commands.mk
@@ -0,0 +1,192 @@
+# Build commands that can be called from Device/* templates
+
+IMAGE_KERNEL = $(word 1,$^)
+IMAGE_ROOTFS = $(word 2,$^)
+
+define Build/uImage
+	mkimage -A $(LINUX_KARCH) \
+		-O linux -T kernel \
+		-C $(1) -a $(KERNEL_LOADADDR) -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
+		-n '$(if $(UIMAGE_NAME),$(UIMAGE_NAME),$(call toupper,$(LINUX_KARCH)) LEDE Linux-$(LINUX_VERSION))' -d $@ $@.new
+	@mv $@.new $@
+endef
+
+define Build/netgear-chk
+	$(STAGING_DIR_HOST)/bin/mkchkimg \
+		-o $@.new \
+		-k $@ \
+		-b $(NETGEAR_BOARD_ID) \
+		-r $(NETGEAR_REGION)
+	mv $@.new $@
+endef
+
+define Build/netgear-dni
+	$(STAGING_DIR_HOST)/bin/mkdniimg \
+		-B $(NETGEAR_BOARD_ID) -v LEDE.$(REVISION) \
+		$(if $(NETGEAR_HW_ID),-H $(NETGEAR_HW_ID)) \
+		-r "$(1)" \
+		-i $@ -o $@.new
+	mv $@.new $@
+endef
+
+define Build/tplink-safeloader
+       -$(STAGING_DIR_HOST)/bin/tplink-safeloader \
+		-B $(TPLINK_BOARD_NAME) \
+		-V $(REVISION) \
+		-k $(IMAGE_KERNEL) \
+		-r $@ \
+		-o $@.new \
+		-j \
+		$(wordlist 2,$(words $(1)),$(1)) \
+		$(if $(findstring sysupgrade,$(word 1,$(1))),-S) && mv $@.new $@ || rm -f $@
+endef
+
+define Build/append-dtb
+	$(call Image/BuildDTB,$(if $(DEVICE_DTS_DIR),$(DEVICE_DTS_DIR),$(DTS_DIR))/$(DEVICE_DTS).dts,$@.dtb)
+	cat $@.dtb >> $@
+endef
+
+define Build/install-dtb
+	$(foreach dts,$(DEVICE_DTS), \
+		$(CP) \
+			$(DTS_DIR)/$(dts).dtb \
+			$(BIN_DIR)/$(IMG_PREFIX)-$(dts).dtb; \
+	)
+endef
+
+define Build/fit
+	$(TOPDIR)/scripts/mkits.sh \
+		-D $(DEVICE_NAME) -o $@.its -k $@ \
+		$(if $(word 2,$(1)),-d $(word 2,$(1))) -C $(word 1,$(1)) \
+		-a $(KERNEL_LOADADDR) -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
+		-A $(ARCH) -v $(LINUX_VERSION)
+	PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $@.its $@.new
+	@mv $@.new $@
+endef
+
+define Build/lzma
+	$(call Build/lzma-no-dict,-lc1 -lp2 -pb2 $(1))
+endef
+
+define Build/lzma-no-dict
+	$(STAGING_DIR_HOST)/bin/lzma e $@ $(1) $@.new
+	@mv $@.new $@
+endef
+
+define Build/gzip
+	gzip -9n -c $@ $(1) > $@.new
+	@mv $@.new $@
+endef
+
+define Build/jffs2
+	rm -rf $(KDIR_TMP)/$(DEVICE_NAME)/jffs2 && \
+		mkdir -p $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/$$(dirname $(1)) && \
+		cp $@ $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/$(1) && \
+		$(STAGING_DIR_HOST)/bin/mkfs.jffs2 --pad \
+			$(if $(CONFIG_BIG_ENDIAN),--big-endian,--little-endian) \
+			--squash-uids -v -e $(patsubst %k,%KiB,$(BLOCKSIZE)) \
+			-o $@.new \
+			-d $(KDIR_TMP)/$(DEVICE_NAME)/jffs2 \
+			2>&1 1>/dev/null | awk '/^.+$$$$/' && \
+		$(STAGING_DIR_HOST)/bin/padjffs2 $@.new -J $(patsubst %k,,$(BLOCKSIZE))
+	-rm -rf $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/
+	@mv $@.new $@
+endef
+
+define Build/kernel-bin
+	rm -f $@
+	cp $< $@
+endef
+
+define Build/patch-cmdline
+	$(STAGING_DIR_HOST)/bin/patch-cmdline $@ '$(CMDLINE)'
+endef
+
+define Build/append-kernel
+	dd if=$(IMAGE_KERNEL) >> $@
+endef
+
+define Build/append-rootfs
+	dd if=$(IMAGE_ROOTFS) >> $@
+endef
+
+define Build/append-ubi
+	sh $(TOPDIR)/scripts/ubinize-image.sh \
+		$(if $(UBOOTENV_IN_UBI),--uboot-env) \
+		$(if $(KERNEL_IN_UBI),--kernel $(IMAGE_KERNEL)) \
+		$(foreach part,$(UBINIZE_PARTS),--part $(part)) \
+		$(IMAGE_ROOTFS) \
+		$@.tmp \
+		-p $(BLOCKSIZE:%k=%KiB) -m $(PAGESIZE) \
+		$(if $(SUBPAGESIZE),-s $(SUBPAGESIZE)) \
+		$(if $(VID_HDR_OFFSET),-O $(VID_HDR_OFFSET)) \
+		$(UBINIZE_OPTS)
+	cat $@.tmp >> $@
+	rm $@.tmp
+endef
+
+define Build/pad-to
+	dd if=$@ of=$@.new bs=$(1) conv=sync
+	mv $@.new $@
+endef
+
+define Build/pad-extra
+	dd if=/dev/zero bs=$(1) count=1 >> $@
+endef
+
+define Build/pad-rootfs
+	$(STAGING_DIR_HOST)/bin/padjffs2 $@ $(1) \
+		$(if $(BLOCKSIZE),$(BLOCKSIZE:%k=%),4 8 16 64 128 256)
+endef
+
+define Build/pad-offset
+	let \
+		size="$$(stat -c%s $@)" \
+		pad="$(subst k,* 1024,$(word 1, $(1)))" \
+		offset="$(subst k,* 1024,$(word 2, $(1)))" \
+		pad="(pad - ((size + offset) % pad)) % pad" \
+		newsize='size + pad'; \
+		dd if=$@ of=$@.new bs=$$newsize count=1 conv=sync
+	mv $@.new $@
+endef
+
+define Build/check-size
+	@[ $$(($(subst k,* 1024,$(subst m, * 1024k,$(1))))) -ge "$$(stat -c%s $@)" ] || { \
+		echo "WARNING: Image file $@ is too big" >&2; \
+		rm -f $@; \
+	}
+endef
+
+define Build/combined-image
+	-sh $(TOPDIR)/scripts/combined-image.sh \
+		"$(IMAGE_KERNEL)" \
+		"$@" \
+		"$@.new"
+	@mv $@.new $@
+endef
+
+define Build/sysupgrade-tar
+	sh $(TOPDIR)/scripts/sysupgrade-tar.sh \
+		--board $(if $(BOARD_NAME),$(BOARD_NAME),$(DEVICE_NAME)) \
+		--kernel $(call param_get_default,kernel,$(1),$(IMAGE_KERNEL)) \
+		--rootfs $(call param_get_default,rootfs,$(1),$(IMAGE_ROOTFS)) \
+		$@
+endef
+
+json_quote=$(subst ','\'',$(subst ",\",$(1)))
+#")')
+metadata_devices=$(if $(1),$(subst "$(space)","$(comma)",$(strip $(foreach v,$(1),"$(call json_quote,$(v))"))))
+metadata_json = \
+	'{ $(if $(IMAGE_METADATA),$(IMAGE_METADATA)$(comma)) \
+		"supported_devices":[$(call metadata_devices,$(1))], \
+		"version": { \
+			"dist": "$(call json_quote,$(VERSION_DIST))", \
+			"version": "$(call json_quote,$(VERSION_NUMBER))", \
+			"revision": "$(call json_quote,$(REVISION))", \
+			"board": "$(call json_quote,$(BOARD))" \
+		} \
+	}'
+
+define Build/append-metadata
+	$(if $(SUPPORTED_DEVICES),echo $(call metadata_json,$(SUPPORTED_DEVICES)) | fwtool -I - $@)
+endef
diff --git a/include/image-legacy.mk b/include/image-legacy.mk
new file mode 100644
index 0000000000..edbee4c831
--- /dev/null
+++ b/include/image-legacy.mk
@@ -0,0 +1,92 @@
+ifneq ($(CONFIG_TARGET_ROOTFS_UBIFS),)
+    define Image/mkfs/ubifs/generate
+	$(CP) ./ubinize$(1).cfg $(KDIR)
+	( cd $(KDIR); \
+		$(STAGING_DIR_HOST)/bin/ubinize \
+		$(if $($(PROFILE)_UBI_OPTS),$($(PROFILE)_UBI_OPTS),$(shell echo $(UBI_OPTS))) \
+		-o $(KDIR)/root$(1).ubi \
+		ubinize$(1).cfg \
+	)
+    endef
+
+    define Image/mkfs/ubifs/legacy
+
+        $(if $($(PROFILE)_UBIFS_OPTS)$(UBIFS_OPTS),
+		$(STAGING_DIR_HOST)/bin/mkfs.ubifs \
+			$(if $($(PROFILE)_UBIFS_OPTS),$($(PROFILE)_UBIFS_OPTS),$(UBIFS_OPTS)) \
+			$(if $(CONFIG_TARGET_UBIFS_FREE_SPACE_FIXUP),--space-fixup) \
+			$(if $(CONFIG_TARGET_UBIFS_COMPRESSION_NONE),--force-compr=none) \
+			$(if $(CONFIG_TARGET_UBIFS_COMPRESSION_LZO),--force-compr=lzo) \
+			$(if $(CONFIG_TARGET_UBIFS_COMPRESSION_ZLIB),--force-compr=zlib) \
+			$(if $(shell echo $(CONFIG_TARGET_UBIFS_JOURNAL_SIZE)),--jrn-size=$(CONFIG_TARGET_UBIFS_JOURNAL_SIZE)) \
+			--squash-uids \
+			-o $(KDIR)/root.ubifs \
+			-d $(TARGET_DIR)
+	)
+	$(call Image/Build,ubifs)
+
+        $(if $($(PROFILE)_UBI_OPTS)$(UBI_OPTS),
+		$(if $(wildcard ./ubinize.cfg),$(call Image/mkfs/ubifs/generate,))
+		$(if $(wildcard ./ubinize-overlay.cfg),$(call Image/mkfs/ubifs/generate,-overlay))
+	)
+	$(if $(wildcard ./ubinize.cfg),$(call Image/Build,ubi))
+    endef
+endif
+
+LegacyDevice/Dump = $(Device/Dump)
+
+define LegacyDevice/Check
+  $(Device/Check/Common)
+  _TARGET_PREPARE := $$(if $$(_PROFILE_SET),legacy-images-prepare,prepare-disabled)
+  _TARGET := $$(if $$(_PROFILE_SET),legacy-images,install-disabled)
+  $$(if $$(_PROFILE_SET),install: legacy-images-make)
+  ifndef IB
+    $$(if $$(_PROFILE_SET),kernel_prepare: legacy-images-prepare-make)
+  endif
+endef
+
+ifdef TARGET_PER_DEVICE_ROOTFS
+  define Image/Build/Profile/Filesystem
+	cp $(KDIR)/root.$(2)+pkg=$(3) $(KDIR)/root.$(2)
+	$(call Image/Build/Profile,$(1),$(2))
+  endef
+else
+  Image/Build/Profile/Filesystem = $(Image/Build/Profile)
+endif
+
+define LegacyDevice/Build
+  $$(_TARGET): legacy-image-$(1)
+  $$(_TARGET_PREPARE): legacy-image-prepare-$(1)
+  .PHONY: legacy-image-prepare-$(1) legacy-image-$(1)
+
+  legacy-image-prepare-$(1):
+	$$(call Image/Prepare/Profile,$(1))
+
+  ifndef IB
+    ifdef CONFIG_TARGET_PER_DEVICE_ROOTFS
+      ROOTFS/$(1) := $(foreach fs,$(TARGET_FILESYSTEMS), \
+        $(KDIR)/root.$(fs)$$(strip $(if $(CONFIG_TARGET_PER_DEVICE_ROOTFS),+pkg=$$(ROOTFS_ID/$(1)))) \
+      )
+
+      $$(ROOTFS/$(1)): target-dir-$$(ROOTFS_ID/$(1))
+      legacy-images-make: $$(if $$(_PROFILE_SET),$$(ROOTFS/$(1)))
+    endif
+  endif
+
+  legacy-image-$(1):
+	$$(call Image/BuildKernel/Profile,$(1))
+	$(foreach fs,$(TARGET_FILESYSTEMS),
+		$$(call Image/Build/Profile/Filesystem,$(1),$(fs),$$(ROOTFS_ID/$(1)))
+	)
+
+endef
+
+define LegacyDevice
+  $(call Device/InitProfile,$(1))
+  $(call Device/Default,$(1))
+  $(call LegacyDevice/Default,$(1))
+  $(call LegacyDevice/$(1),$(1))
+  $(call LegacyDevice/Check,$(1))
+  $(call LegacyDevice/$(if $(DUMP),Dump,Build),$(1))
+
+endef
diff --git a/include/image.mk b/include/image.mk
new file mode 100644
index 0000000000..d1dcdd6bad
--- /dev/null
+++ b/include/image.mk
@@ -0,0 +1,562 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+override TARGET_BUILD=
+include $(INCLUDE_DIR)/prereq.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/version.mk
+include $(INCLUDE_DIR)/image-commands.mk
+
+ifndef IB
+  ifdef CONFIG_TARGET_PER_DEVICE_ROOTFS
+    TARGET_PER_DEVICE_ROOTFS := 1
+  endif
+endif
+
+include $(INCLUDE_DIR)/image-legacy.mk
+
+ifdef TARGET_PER_DEVICE_ROOTFS
+  include $(INCLUDE_DIR)/rootfs.mk
+endif
+
+override MAKE:=$(_SINGLE)$(SUBMAKE)
+override NO_TRACE_MAKE:=$(_SINGLE)$(NO_TRACE_MAKE)
+
+target_params = $(subst +,$(space),$*)
+param_get = $(patsubst $(1)=%,%,$(filter $(1)=%,$(2)))
+param_get_default = $(firstword $(call param_get,$(1),$(2)) $(3))
+param_mangle = $(subst $(space),_,$(strip $(1)))
+param_unmangle = $(subst _,$(space),$(1))
+
+mkfs_packages_id = $(shell echo $(sort $(1)) | md5sum | head -c 8)
+mkfs_target_dir = $(if $(call param_get,pkg,$(1)),$(KDIR)/target-dir-$(call param_get,pkg,$(1)),$(TARGET_DIR))
+
+KDIR=$(KERNEL_BUILD_DIR)
+KDIR_TMP=$(KDIR)/tmp
+DTS_DIR:=$(LINUX_DIR)/arch/$(LINUX_KARCH)/boot/dts
+
+EXTRA_NAME_SANITIZED=$(call sanitize,$(EXTRA_IMAGE_NAME))
+
+IMG_PREFIX:=$(VERSION_DIST_SANITIZED)-$(if $(CONFIG_VERSION_FILENAMES),$(VERSION_NUMBER)-)$(if $(EXTRA_NAME_SANITIZED),$(EXTRA_NAME_SANITIZED)-)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))
+
+MKFS_DEVTABLE_OPT := -D $(INCLUDE_DIR)/device_table.txt
+
+ifneq ($(CONFIG_BIG_ENDIAN),)
+  JFFS2OPTS     :=  --big-endian --squash-uids -v
+else
+  JFFS2OPTS     :=  --little-endian --squash-uids -v
+endif
+
+ifeq ($(CONFIG_JFFS2_RTIME),y)
+  JFFS2OPTS += -X rtime
+endif
+ifeq ($(CONFIG_JFFS2_ZLIB),y)
+  JFFS2OPTS += -X zlib
+endif
+ifeq ($(CONFIG_JFFS2_LZMA),y)
+  JFFS2OPTS += -X lzma --compression-mode=size
+endif
+ifneq ($(CONFIG_JFFS2_RTIME),y)
+  JFFS2OPTS += -x rtime
+endif
+ifneq ($(CONFIG_JFFS2_ZLIB),y)
+  JFFS2OPTS += -x zlib
+endif
+ifneq ($(CONFIG_JFFS2_LZMA),y)
+  JFFS2OPTS += -x lzma
+endif
+
+JFFS2OPTS += $(MKFS_DEVTABLE_OPT)
+
+SQUASHFS_BLOCKSIZE := $(CONFIG_TARGET_SQUASHFS_BLOCK_SIZE)k
+SQUASHFSOPT := -b $(SQUASHFS_BLOCKSIZE)
+SQUASHFSOPT += -p '/dev d 755 0 0' -p '/dev/console c 600 0 0 5 1'
+SQUASHFSCOMP := gzip
+LZMA_XZ_OPTIONS := -Xpreset 9 -Xe -Xlc 0 -Xlp 2 -Xpb 2
+ifeq ($(CONFIG_SQUASHFS_XZ),y)
+  ifneq ($(filter arm x86 powerpc sparc,$(LINUX_KARCH)),)
+    BCJ_FILTER:=-Xbcj $(LINUX_KARCH)
+  endif
+  SQUASHFSCOMP := xz $(LZMA_XZ_OPTIONS) $(BCJ_FILTER)
+endif
+
+JFFS2_BLOCKSIZE ?= 64k 128k
+
+fs-types-$(CONFIG_TARGET_ROOTFS_SQUASHFS) += squashfs
+fs-types-$(CONFIG_TARGET_ROOTFS_JFFS2) += $(addprefix jffs2-,$(JFFS2_BLOCKSIZE))
+fs-types-$(CONFIG_TARGET_ROOTFS_JFFS2_NAND) += $(addprefix jffs2-nand-,$(NAND_BLOCKSIZE))
+fs-types-$(CONFIG_TARGET_ROOTFS_EXT4FS) += ext4
+fs-types-$(CONFIG_TARGET_ROOTFS_ISO) += iso
+fs-types-$(CONFIG_TARGET_ROOTFS_UBIFS) += ubifs
+fs-subtypes-$(CONFIG_TARGET_ROOTFS_JFFS2) += $(addsuffix -raw,$(addprefix jffs2-,$(JFFS2_BLOCKSIZE)))
+
+TARGET_FILESYSTEMS := $(fs-types-y)
+
+FS_64K := $(filter-out jffs2-%,$(TARGET_FILESYSTEMS)) jffs2-64k
+FS_128K := $(filter-out jffs2-%,$(TARGET_FILESYSTEMS)) jffs2-128k
+FS_256K := $(filter-out jffs2-%,$(TARGET_FILESYSTEMS)) jffs2-256k
+
+define add_jffs2_mark
+	echo -ne '\xde\xad\xc0\xde' >> $(1)
+endef
+
+PROFILE_SANITIZED := $(call sanitize,$(PROFILE))
+
+define split_args
+$(foreach data, \
+	$(subst |,$(space),\
+		$(subst $(space),^,$(1))), \
+	$(call $(2),$(strip $(subst ^,$(space),$(data)))))
+endef
+
+define build_cmd
+$(if $(Build/$(word 1,$(1))),,$(error Missing Build/$(word 1,$(1))))
+$(call Build/$(word 1,$(1)),$(wordlist 2,$(words $(1)),$(1)))
+
+endef
+
+define concat_cmd
+$(call split_args,$(1),build_cmd)
+endef
+
+# pad to 4k, 8k, 16k, 64k, 128k, 256k and add jffs2 end-of-filesystem mark
+define prepare_generic_squashfs
+	$(STAGING_DIR_HOST)/bin/padjffs2 $(1) 4 8 16 64 128 256
+endef
+
+define Image/BuildKernel/Initramfs
+	$(call Image/Build/Initramfs)
+endef
+
+define Image/BuildKernel/MkuImage
+	mkimage -A $(ARCH) -O linux -T kernel -C $(1) -a $(2) -e $(3) \
+		-n '$(call toupper,$(ARCH)) LEDE Linux-$(LINUX_VERSION)' -d $(4) $(5)
+endef
+
+define Image/BuildKernel/MkFIT
+	$(TOPDIR)/scripts/mkits.sh \
+		-D $(1) -o $(KDIR)/fit-$(1).its -k $(2) $(if $(3),-d $(3)) -C $(4) -a $(5) -e $(6) \
+		-A $(ARCH) -v $(LINUX_VERSION)
+	PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $(KDIR)/fit-$(1).its $(KDIR)/fit-$(1)$(7).itb
+endef
+
+# $(1) source dts file
+# $(2) target dtb file
+# $(3) extra CPP flags
+# $(4) extra DTC flags
+define Image/BuildDTB
+	$(TARGET_CROSS)cpp -nostdinc -x assembler-with-cpp \
+		-I$(DTS_DIR) \
+		-I$(DTS_DIR)/include \
+		-undef -D__DTS__ $(3) \
+		-o $(2).tmp $(1)
+	$(LINUX_DIR)/scripts/dtc/dtc -O dtb \
+		-i$(dir $(1)) $(4) \
+		-o $(2) $(2).tmp
+	$(RM) $(2).tmp
+endef
+
+define Image/mkfs/jffs2/sub-raw
+	$(STAGING_DIR_HOST)/bin/mkfs.jffs2 \
+		$(2) \
+		-e $(patsubst %k,%KiB,$(1)) \
+		-o $@ -d $(call mkfs_target_dir,$(3)) \
+		-v 2>&1 1>/dev/null | awk '/^.+$$$$/'
+endef
+
+define Image/mkfs/jffs2/sub
+	$(call Image/mkfs/jffs2/sub-raw,$(1),--pad $(2),$(3))
+	$(call add_jffs2_mark,$@)
+endef
+
+define Image/mkfs/jffs2/template
+  Image/mkfs/jffs2-$(1) = $$(call Image/mkfs/jffs2/sub,$(1),$(JFFS2OPTS),$$(1))
+  Image/mkfs/jffs2-$(1)-raw = $$(call Image/mkfs/jffs2/sub-raw,$(1),$(JFFS2OPTS),$$(1))
+
+endef
+
+define Image/mkfs/jffs2-nand/template
+  Image/mkfs/jffs2-nand-$(1) = \
+	$$(call Image/mkfs/jffs2/sub, \
+		$(word 2,$(subst -, ,$(1))), \
+			$(JFFS2OPTS) --no-cleanmarkers --pagesize=$(word 1,$(subst -, ,$(1))),$$(1))
+
+endef
+
+$(eval $(foreach S,$(JFFS2_BLOCKSIZE),$(call Image/mkfs/jffs2/template,$(S))))
+$(eval $(foreach S,$(NAND_BLOCKSIZE),$(call Image/mkfs/jffs2-nand/template,$(S))))
+
+define Image/mkfs/squashfs
+	$(STAGING_DIR_HOST)/bin/mksquashfs4 $(call mkfs_target_dir,$(1)) $@ \
+		-nopad -noappend -root-owned \
+		-comp $(SQUASHFSCOMP) $(SQUASHFSOPT) \
+		-processors $(if $(CONFIG_PKG_BUILD_JOBS),$(CONFIG_PKG_BUILD_JOBS),1) \
+		$(if $(SOURCE_DATE_EPOCH),-fixed-time $(SOURCE_DATE_EPOCH))
+endef
+
+# $(1): board name
+# $(2): rootfs type
+# $(3): kernel image
+ifneq ($(CONFIG_NAND_SUPPORT),)
+   define Image/Build/SysupgradeNAND
+	mkdir -p "$(KDIR_TMP)/sysupgrade-$(1)/"
+	echo "BOARD=$(1)" > "$(KDIR_TMP)/sysupgrade-$(1)/CONTROL"
+	[ -z "$(2)" ] || $(CP) "$(KDIR)/root.$(2)" "$(KDIR_TMP)/sysupgrade-$(1)/root"
+	[ -z "$(3)" ] || $(CP) "$(3)" "$(KDIR_TMP)/sysupgrade-$(1)/kernel"
+	(cd "$(KDIR_TMP)"; $(TAR) cvf \
+		"$(BIN_DIR)/$(IMG_PREFIX)-$(1)-$(2)-sysupgrade.tar" sysupgrade-$(1) \
+			$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
+	)
+   endef
+
+# $(1) board name
+# $(2) ubinize-image options (e.g. --uboot-env and/or --kernel kernelimage)
+# $(3) rootfstype (e.g. squashfs or ubifs)
+# $(4) options to pass-through to ubinize (i.e. $($(PROFILE)_UBI_OPTS)))
+   define Image/Build/UbinizeImage
+	sh $(TOPDIR)/scripts/ubinize-image.sh $(2) \
+		"$(KDIR)/root.$(3)" \
+		"$(KDIR)/$(IMG_PREFIX)-$(1)-$(3)-ubinized.bin" \
+		$(4)
+   endef
+
+endif
+
+define Image/mkfs/ubifs
+	$(STAGING_DIR_HOST)/bin/mkfs.ubifs \
+		$(UBIFS_OPTS) $(call param_unmangle,$(call param_get,fs,$(1))) \
+		$(if $(CONFIG_TARGET_UBIFS_FREE_SPACE_FIXUP),--space-fixup) \
+		$(if $(CONFIG_TARGET_UBIFS_COMPRESSION_NONE),--force-compr=none) \
+		$(if $(CONFIG_TARGET_UBIFS_COMPRESSION_LZO),--force-compr=lzo) \
+		$(if $(CONFIG_TARGET_UBIFS_COMPRESSION_ZLIB),--force-compr=zlib) \
+		$(if $(shell echo $(CONFIG_TARGET_UBIFS_JOURNAL_SIZE)),--jrn-size=$(CONFIG_TARGET_UBIFS_JOURNAL_SIZE)) \
+		--squash-uids \
+		-o $@ -d $(call mkfs_target_dir,$(1))
+endef
+
+E2SIZE=$(shell echo $$(($(CONFIG_TARGET_ROOTFS_PARTSIZE)*1024*1024)))
+
+define Image/mkfs/ext4
+	$(STAGING_DIR_HOST)/bin/make_ext4fs \
+		-l $(E2SIZE) -b $(CONFIG_TARGET_EXT4_BLOCKSIZE) \
+		$(if $(CONFIG_TARGET_EXT4_RESERVED_PCT),-m $(CONFIG_TARGET_EXT4_RESERVED_PCT)) \
+		$(if $(CONFIG_TARGET_EXT4_JOURNAL),,-J) \
+		$(if $(SOURCE_DATE_EPOCH),-T $(SOURCE_DATE_EPOCH)) \
+		$@ $(call mkfs_target_dir,$(1))/
+endef
+
+define Image/Manifest
+	$(STAGING_DIR_HOST)/bin/opkg \
+		--offline-root $(TARGET_DIR) \
+		--add-arch all:100 \
+		--add-arch $(if $(ARCH_PACKAGES),$(ARCH_PACKAGES),$(BOARD)):200 list-installed > \
+		$(BIN_DIR)/$(IMG_PREFIX)$(if $(PROFILE_SANITIZED),-$(PROFILE_SANITIZED)).manifest
+endef
+
+ifdef CONFIG_TARGET_ROOTFS_TARGZ
+  define Image/Build/targz
+	$(TAR) -cp --numeric-owner --owner=0 --group=0 --sort=name \
+		$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
+		-C $(TARGET_DIR)/ . | gzip -9n > $(BIN_DIR)/$(IMG_PREFIX)$(if $(PROFILE_SANITIZED),-$(PROFILE_SANITIZED))-rootfs.tar.gz
+  endef
+endif
+
+ifdef CONFIG_TARGET_ROOTFS_CPIOGZ
+  define Image/Build/cpiogz
+	( cd $(TARGET_DIR); find . | cpio -o -H newc | gzip -9n >$(BIN_DIR)/$(IMG_PREFIX)-rootfs.cpio.gz )
+  endef
+endif
+
+mkfs_packages = $(filter-out @%,$(PACKAGES_$(call param_get,pkg,pkg=$(target_params))))
+mkfs_packages_add = $(filter-out -%,$(mkfs_packages))
+mkfs_packages_remove = $(patsubst -%,%,$(filter -%,$(mkfs_packages)))
+mkfs_cur_target_dir = $(call mkfs_target_dir,pkg=$(target_params))
+
+opkg_target = \
+	$(call opkg,$(mkfs_cur_target_dir)) \
+		-f $(mkfs_cur_target_dir).conf
+
+target-dir-%: FORCE
+	rm -rf $(mkfs_cur_target_dir) $(mkfs_cur_target_dir).opkg
+	$(CP) $(TARGET_DIR_ORIG) $(mkfs_cur_target_dir)
+	-mv $(mkfs_cur_target_dir)/etc/opkg $(mkfs_cur_target_dir).opkg
+	echo 'src default file://$(PACKAGE_DIR_ALL)' > $(mkfs_cur_target_dir).conf
+	$(if $(mkfs_packages_remove), \
+		-$(call opkg,$(mkfs_cur_target_dir)) remove \
+			$(mkfs_packages_remove))
+	$(if $(call opkg_package_files,$(mkfs_packages_add)), \
+		$(opkg_target) update && \
+		$(opkg_target) install \
+			$(call opkg_package_files,$(mkfs_packages_add)))
+	$(call prepare_rootfs,$(mkfs_cur_target_dir))
+	-mv $(mkfs_cur_target_dir).opkg $(mkfs_cur_target_dir)/etc/opkg
+	rm -f $(mkfs_cur_target_dir).conf
+
+$(KDIR)/root.%: kernel_prepare
+	$(call Image/mkfs/$(word 1,$(target_params)),$(target_params))
+
+define Device/InitProfile
+  PROFILES := $(PROFILE)
+  DEVICE_TITLE :=
+  DEVICE_PACKAGES :=
+  DEVICE_DESCRIPTION = Build firmware images for $$(DEVICE_TITLE)
+endef
+
+define Device/Init
+  DEVICE_NAME := $(1)
+  KERNEL:=
+  KERNEL_INITRAMFS = $$(KERNEL)
+  KERNEL_SIZE:=
+  CMDLINE:=
+
+  IMAGES :=
+  IMAGE_PREFIX := $(IMG_PREFIX)-$(1)
+  IMAGE_NAME = $$(IMAGE_PREFIX)-$$(1)-$$(2)
+  KERNEL_PREFIX = $$(IMAGE_PREFIX)
+  KERNEL_SUFFIX := -kernel.bin
+  KERNEL_INITRAMFS_SUFFIX = $$(KERNEL_SUFFIX)
+  KERNEL_IMAGE = $$(KERNEL_PREFIX)$$(KERNEL_SUFFIX)
+  KERNEL_INITRAMFS_PREFIX = $$(IMAGE_PREFIX)-initramfs
+  KERNEL_INITRAMFS_IMAGE = $$(KERNEL_INITRAMFS_PREFIX)$$(KERNEL_INITRAMFS_SUFFIX)
+  KERNEL_INITRAMFS_NAME = $$(KERNEL_NAME)-initramfs
+  KERNEL_INSTALL :=
+  KERNEL_NAME := vmlinux
+  KERNEL_DEPENDS :=
+  KERNEL_SIZE :=
+
+  UBOOTENV_IN_UBI :=
+  KERNEL_IN_UBI :=
+  BLOCKSIZE :=
+  PAGESIZE :=
+  SUBPAGESIZE :=
+  VID_HDR_OFFSET :=
+  UBINIZE_OPTS :=
+  UBINIZE_PARTS :=
+  MKUBIFS_OPTS :=
+
+  FS_OPTIONS/ubifs = $$(MKUBIFS_OPTS)
+
+  DEVICE_DTS :=
+  DEVICE_DTS_DIR :=
+
+  BOARD_NAME :=
+  UIMAGE_NAME :=
+  SUPPORTED_DEVICES :=
+  IMAGE_METADATA :=
+
+  FILESYSTEMS := $(TARGET_FILESYSTEMS)
+endef
+
+DEFAULT_DEVICE_VARS := \
+  DEVICE_NAME KERNEL KERNEL_INITRAMFS KERNEL_SIZE KERNEL_INITRAMFS_IMAGE \
+  DEVICE_DTS DEVICE_DTS_DIR BOARD_NAME CMDLINE \
+  UBOOTENV_IN_UBI KERNEL_IN_UBI \
+  BLOCKSIZE PAGESIZE SUBPAGESIZE VID_HDR_OFFSET \
+  UBINIZE_OPTS UIMAGE_NAME UBINIZE_PARTS \
+  SUPPORTED_DEVICES IMAGE_METADATA
+
+define Device/ExportVar
+  $(1) : $(2):=$$($(2))
+
+endef
+define Device/Export
+  $(foreach var,$(DEVICE_VARS) $(DEFAULT_DEVICE_VARS),$(call Device/ExportVar,$(1),$(var)))
+  $(1) : FILESYSTEM:=$(2)
+endef
+
+ifdef IB
+  DEVICE_CHECK_PROFILE = $(filter $(1),DEVICE_$(PROFILE) $(PROFILE))
+else
+  DEVICE_CHECK_PROFILE = $(CONFIG_TARGET_$(if $(CONFIG_TARGET_MULTI_PROFILE),DEVICE_)$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_$(1))
+endif
+
+DEVICE_EXTRA_PACKAGES = $(call qstrip,$(CONFIG_TARGET_DEVICE_PACKAGES_$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_DEVICE_$(1)))
+
+define merge_packages
+  $(1) :=
+  $(foreach pkg,$(2),
+    $(1) := $$(strip $$(filter-out -$$(patsubst -%,%,$(pkg)) $$(patsubst -%,%,$(pkg)),$$($(1))) $(pkg))
+  )
+endef
+
+define Device/Check/Common
+  _PROFILE_SET = $$(strip $$(foreach profile,$$(PROFILES) DEVICE_$(1),$$(call DEVICE_CHECK_PROFILE,$$(profile))))
+  ifdef TARGET_PER_DEVICE_ROOTFS
+    $$(eval $$(call merge_packages,_PACKAGES,$$(DEVICE_PACKAGES) $$(call DEVICE_EXTRA_PACKAGES,$(1))))
+    ROOTFS_ID/$(1) := $$(if $$(_PROFILE_SET),$$(call mkfs_packages_id,$$(_PACKAGES)))
+    PACKAGES_$$(ROOTFS_ID/$(1)) := $$(_PACKAGES)
+  endif
+endef
+
+define Device/Check
+  $(Device/Check/Common)
+  KDIR_KERNEL_IMAGE := $(KDIR)/$(1)$$(KERNEL_SUFFIX)
+  _TARGET := $$(if $$(_PROFILE_SET),install-images,install-disabled)
+  ifndef IB
+    _COMPILE_TARGET := $$(if $(CONFIG_IB)$$(_PROFILE_SET),compile,compile-disabled)
+  endif
+endef
+
+ifndef IB
+define Device/Build/initramfs
+  $(call Device/Export,$(KDIR)/tmp/$$(KERNEL_INITRAMFS_IMAGE),$(1))
+  $$(_TARGET): $$(if $$(KERNEL_INITRAMFS),$(BIN_DIR)/$$(KERNEL_INITRAMFS_IMAGE))
+
+  $(KDIR)/$$(KERNEL_INITRAMFS_NAME):: image_prepare
+  $(BIN_DIR)/$$(KERNEL_INITRAMFS_IMAGE): $(KDIR)/tmp/$$(KERNEL_INITRAMFS_IMAGE)
+	cp $$^ $$@
+
+  $(KDIR)/tmp/$$(KERNEL_INITRAMFS_IMAGE): $(KDIR)/$$(KERNEL_INITRAMFS_NAME) $(CURDIR)/Makefile $$(KERNEL_DEPENDS)
+	@rm -f $$@
+	$$(call concat_cmd,$$(KERNEL_INITRAMFS))
+endef
+endif
+
+define Device/Build/compile
+  $$(_COMPILE_TARGET): $(KDIR)/$(1)
+  $(eval $(call Device/Export,$(KDIR)/$(1)))
+  $(KDIR)/$(1):
+	$$(call concat_cmd,$(COMPILE/$(1)))
+
+endef
+
+define Device/Build/kernel
+  $(KDIR)/$$(KERNEL_NAME):: image_prepare
+  $$(_TARGET): $$(if $$(KERNEL_INSTALL),$(BIN_DIR)/$$(KERNEL_IMAGE))
+  $(call Device/Export,$$(KDIR_KERNEL_IMAGE),$(1))
+  $(BIN_DIR)/$$(KERNEL_IMAGE): $$(KDIR_KERNEL_IMAGE)
+	cp $$^ $$@
+  ifndef IB
+    ifdef CONFIG_IB
+      install: $$(KDIR_KERNEL_IMAGE)
+    endif
+    $$(KDIR_KERNEL_IMAGE): $(KDIR)/$$(KERNEL_NAME) $(CURDIR)/Makefile $$(KERNEL_DEPENDS)
+	@rm -f $$@
+	$$(call concat_cmd,$$(KERNEL))
+	$$(if $$(KERNEL_SIZE),$$(call Build/check-size,$$(KERNEL_SIZE)))
+  endif
+endef
+
+define Device/Build/image
+  $$(_TARGET): $(BIN_DIR)/$(call IMAGE_NAME,$(1),$(2))
+  $(eval $(call Device/Export,$(KDIR)/tmp/$(call IMAGE_NAME,$(1),$(2)),$(1)))
+  ROOTFS/$(1)/$(3) := \
+	$(KDIR)/root.$(1)$$(strip \
+		$$(if $$(FS_OPTIONS/$(1)),+fs=$$(call param_mangle,$$(FS_OPTIONS/$(1)))) \
+	)$$(strip \
+		$(if $(TARGET_PER_DEVICE_ROOTFS),+pkg=$$(ROOTFS_ID/$(3))) \
+	)
+  ifndef IB
+    $$(ROOTFS/$(1)/$(3)): $(if $(TARGET_PER_DEVICE_ROOTFS),target-dir-$$(ROOTFS_ID/$(3)))
+  endif
+  $(KDIR)/tmp/$(call IMAGE_NAME,$(1),$(2)): $$(KDIR_KERNEL_IMAGE) $$(ROOTFS/$(1)/$(3))
+	@rm -f $$@
+	[ -f $$(word 1,$$^) -a -f $$(word 2,$$^) ]
+	$$(call concat_cmd,$(if $(IMAGE/$(2)/$(1)),$(IMAGE/$(2)/$(1)),$(IMAGE/$(2))))
+
+  .IGNORE: $(BIN_DIR)/$(call IMAGE_NAME,$(1),$(2))
+  $(BIN_DIR)/$(call IMAGE_NAME,$(1),$(2)): $(KDIR)/tmp/$(call IMAGE_NAME,$(1),$(2))
+	cp $$^ $$@
+
+endef
+
+define Device/Build
+  $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(call Device/Build/initramfs,$(1)))
+  $(call Device/Build/kernel,$(1))
+
+  $$(eval $$(foreach compile,$$(COMPILE), \
+    $$(call Device/Build/compile,$$(compile),$(1))))
+
+  $$(eval $$(foreach image,$$(IMAGES), \
+    $$(foreach fs,$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)), \
+      $$(call Device/Build/image,$$(fs),$$(image),$(1)))))
+endef
+
+define Device/DumpInfo
+Target-Profile: DEVICE_$(1)
+Target-Profile-Name: $(DEVICE_TITLE)
+Target-Profile-Packages: $(DEVICE_PACKAGES)
+Target-Profile-Description:
+$(DEVICE_DESCRIPTION)
+@@
+
+endef
+
+define Device/Dump
+$$(eval $$(if $$(DEVICE_TITLE),$$(info $$(call Device/DumpInfo,$(1)))))
+endef
+
+define Device
+  $(call Device/InitProfile,$(1))
+  $(call Device/Init,$(1))
+  $(call Device/Default,$(1))
+  $(call Device/$(1),$(1))
+  $(call Device/Check,$(1))
+  $(call Device/$(if $(DUMP),Dump,Build),$(1))
+
+endef
+
+define BuildImage
+
+  ifneq ($(DUMP),)
+    all: dumpinfo
+    dumpinfo: FORCE
+	@true
+  endif
+
+  download:
+  prepare:
+  compile:
+  clean:
+  legacy-images-prepare:
+  legacy-images:
+  image_prepare:
+
+  ifeq ($(IB),)
+    .PHONY: download prepare compile clean image_prepare kernel_prepare install install-images
+    compile:
+		$(call Build/Compile)
+
+    clean:
+		$(call Build/Clean)
+
+    image_prepare: compile
+		mkdir -p $(BIN_DIR) $(KDIR)/tmp
+		$(call Image/Prepare)
+
+    legacy-images-prepare-make: image_prepare
+		$(MAKE) legacy-images-prepare
+
+  else
+    image_prepare:
+		mkdir -p $(BIN_DIR) $(KDIR)/tmp
+  endif
+
+  kernel_prepare: image_prepare
+	$(call Image/Build/targz)
+	$(call Image/Build/cpiogz)
+	$(call Image/BuildKernel)
+	$(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(if $(IB),,$(call Image/BuildKernel/Initramfs)))
+	$(call Image/InstallKernel)
+
+  $(foreach device,$(TARGET_DEVICES),$(call Device,$(device)))
+  $(foreach device,$(LEGACY_DEVICES),$(call LegacyDevice,$(device)))
+
+  install-images: kernel_prepare $(foreach fs,$(filter-out $(if $(UBIFS_OPTS),,ubifs),$(TARGET_FILESYSTEMS) $(fs-subtypes-y)),$(KDIR)/root.$(fs))
+	$(foreach fs,$(TARGET_FILESYSTEMS),
+		$(call Image/Build,$(fs))
+	)
+
+  legacy-images-make: install-images
+	$(call Image/mkfs/ubifs/legacy)
+	$(MAKE) legacy-images
+
+  install: install-images
+	$(call Image/Manifest)
+
+endef
diff --git a/include/kernel-build.mk b/include/kernel-build.mk
new file mode 100644
index 0000000000..062c458ab7
--- /dev/null
+++ b/include/kernel-build.mk
@@ -0,0 +1,177 @@
+#
+# Copyright (C) 2006-2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/prereq.mk
+include $(INCLUDE_DIR)/depends.mk
+
+ifneq ($(DUMP),1)
+  all: compile
+endif
+
+KERNEL_FILE_DEPENDS=$(GENERIC_PATCH_DIR) $(PATCH_DIR) $(GENERIC_FILES_DIR) $(FILES_DIR)
+STAMP_PREPARED=$(LINUX_DIR)/.prepared$(if $(QUILT)$(DUMP),,_$(shell $(call find_md5,$(KERNEL_FILE_DEPENDS),)))
+STAMP_CONFIGURED:=$(LINUX_DIR)/.configured
+include $(INCLUDE_DIR)/download.mk
+include $(INCLUDE_DIR)/quilt.mk
+include $(INCLUDE_DIR)/kernel-defaults.mk
+
+define Kernel/Prepare
+	$(call Kernel/Prepare/Default)
+endef
+
+define Kernel/Configure
+	$(call Kernel/Configure/Default)
+endef
+
+define Kernel/CompileModules
+	$(call Kernel/CompileModules/Default)
+endef
+
+define Kernel/CompileImage
+	$(call Kernel/CompileImage/Default)
+	$(call Kernel/CompileImage/Initramfs)
+endef
+
+define Kernel/Clean
+	$(call Kernel/Clean/Default)
+endef
+
+define Download/kernel
+  URL:=$(LINUX_SITE)
+  FILE:=$(LINUX_SOURCE)
+  MD5SUM:=$(LINUX_KERNEL_MD5SUM)
+endef
+
+KERNEL_GIT_OPTS:=
+ifneq ($(strip $(CONFIG_KERNEL_GIT_LOCAL_REPOSITORY)),"")
+  KERNEL_GIT_OPTS+=--reference $(CONFIG_KERNEL_GIT_LOCAL_REPOSITORY)
+endif
+
+ifneq ($(strip $(CONFIG_KERNEL_GIT_BRANCH)),"")
+  KERNEL_GIT_OPTS+=--branch $(CONFIG_KERNEL_GIT_BRANCH)
+endif
+
+define Download/git-kernel
+  URL:=$(call qstrip,$(CONFIG_KERNEL_GIT_CLONE_URI))
+  PROTO:=git
+  VERSION:=$(CONFIG_KERNEL_GIT_BRANCH)
+  FILE:=$(LINUX_SOURCE)
+  SUBDIR:=linux-$(KERNEL_PATCHVER)
+  OPTS:=$(KERNEL_GIT_OPTS)
+endef
+
+ifdef CONFIG_COLLECT_KERNEL_DEBUG
+  define Kernel/CollectDebug
+	rm -rf $(KERNEL_BUILD_DIR)/debug
+	mkdir -p $(KERNEL_BUILD_DIR)/debug/modules
+	$(CP) $(LINUX_DIR)/vmlinux $(KERNEL_BUILD_DIR)/debug/
+	-$(CP) \
+		$(STAGING_DIR_ROOT)/lib/modules/$(LINUX_VERSION)/* \
+		$(KERNEL_BUILD_DIR)/debug/modules/
+	$(FIND) $(KERNEL_BUILD_DIR)/debug -type f | $(XARGS) $(KERNEL_CROSS)strip --only-keep-debug
+	$(TAR) c -C $(KERNEL_BUILD_DIR) debug \
+		$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
+		| bzip2 -c -9 > $(BIN_DIR)/kernel-debug.tar.bz2
+  endef
+endif
+
+ifeq ($(DUMP)$(filter prereq clean refresh update,$(MAKECMDGOALS)),)
+  ifneq ($(if $(QUILT),,$(CONFIG_AUTOREBUILD)),)
+    define Kernel/Autoclean
+      $(PKG_BUILD_DIR)/.dep_files: $(STAMP_PREPARED)
+      $(call rdep,$(KERNEL_FILE_DEPENDS),$(STAMP_PREPARED),$(PKG_BUILD_DIR)/.dep_files,-x "*/.dep_*")
+    endef
+  endif
+endif
+
+define BuildKernel
+  $(if $(QUILT),$(Build/Quilt))
+  $(if $(LINUX_SITE),$(call Download,kernel))
+  $(if $(call qstrip,$(CONFIG_KERNEL_GIT_CLONE_URI)),$(call Download,git-kernel))
+
+  .NOTPARALLEL:
+
+  $(Kernel/Autoclean)
+  $(STAMP_PREPARED): $(if $(LINUX_SITE),$(DL_DIR)/$(LINUX_SOURCE))
+	-rm -rf $(KERNEL_BUILD_DIR)
+	-mkdir -p $(KERNEL_BUILD_DIR)
+	$(Kernel/Prepare)
+	touch $$@
+
+  $(KERNEL_BUILD_DIR)/symtab.h: FORCE
+	rm -f $(KERNEL_BUILD_DIR)/symtab.h
+	touch $(KERNEL_BUILD_DIR)/symtab.h
+	+$(MAKE) $(KERNEL_MAKEOPTS) vmlinux
+	find $(LINUX_DIR) $(STAGING_DIR_ROOT)/lib/modules -name \*.ko | \
+		xargs $(TARGET_CROSS)nm | \
+		awk '$$$$1 == "U" { print $$$$2 } ' | \
+		sort -u > $(KERNEL_BUILD_DIR)/mod_symtab.txt
+	$(TARGET_CROSS)nm -n $(LINUX_DIR)/vmlinux.o | grep ' [rR] __ksymtab' | sed -e 's,........ [rR] __ksymtab_,,' > $(KERNEL_BUILD_DIR)/kernel_symtab.txt
+	grep -Ff $(KERNEL_BUILD_DIR)/mod_symtab.txt $(KERNEL_BUILD_DIR)/kernel_symtab.txt > $(KERNEL_BUILD_DIR)/sym_include.txt
+	grep -Fvf $(KERNEL_BUILD_DIR)/mod_symtab.txt $(KERNEL_BUILD_DIR)/kernel_symtab.txt > $(KERNEL_BUILD_DIR)/sym_exclude.txt
+	( \
+		echo '#define SYMTAB_KEEP \'; \
+		cat $(KERNEL_BUILD_DIR)/sym_include.txt | \
+			awk '{print "KEEP(*(___ksymtab+" $$$$1 ")) \\" }'; \
+		echo; \
+		echo '#define SYMTAB_KEEP_GPL \'; \
+		cat $(KERNEL_BUILD_DIR)/sym_include.txt | \
+			awk '{print "KEEP(*(___ksymtab_gpl+" $$$$1 ")) \\" }'; \
+		echo; \
+		echo '#define SYMTAB_DISCARD \'; \
+		cat $(KERNEL_BUILD_DIR)/sym_exclude.txt | \
+			awk '{print "*(___ksymtab+" $$$$1 ") \\" }'; \
+		echo; \
+		echo '#define SYMTAB_DISCARD_GPL \'; \
+		cat $(KERNEL_BUILD_DIR)/sym_exclude.txt | \
+			awk '{print "*(___ksymtab_gpl+" $$$$1 ") \\" }'; \
+		echo; \
+	) > $$@
+
+  $(STAMP_CONFIGURED): $(STAMP_PREPARED) $(LINUX_KCONFIG_LIST) $(TOPDIR)/.config FORCE
+	$(Kernel/Configure)
+	touch $$@
+
+  $(LINUX_DIR)/.modules: $(STAMP_CONFIGURED) $(LINUX_DIR)/.config FORCE
+	$(Kernel/CompileModules)
+	touch $$@
+
+  $(LINUX_DIR)/.image: $(STAMP_CONFIGURED) $(if $(CONFIG_STRIP_KERNEL_EXPORTS),$(KERNEL_BUILD_DIR)/symtab.h) FORCE
+	$(Kernel/CompileImage)
+	$(Kernel/CollectDebug)
+	touch $$@
+	
+  mostlyclean: FORCE
+	$(Kernel/Clean)
+
+  define BuildKernel
+  endef
+
+  download: $(if $(LINUX_SITE),$(DL_DIR)/$(LINUX_SOURCE))
+  prepare: $(STAMP_CONFIGURED)
+  compile: $(LINUX_DIR)/.modules
+	$(MAKE) -C image compile TARGET_BUILD=
+
+  oldconfig menuconfig nconfig: $(STAMP_PREPARED) $(STAMP_CHECKED) FORCE
+	rm -f $(LINUX_DIR)/.config.prev
+	rm -f $(STAMP_CONFIGURED)
+	$(LINUX_RECONF_CMD) > $(LINUX_DIR)/.config
+	$(_SINGLE)$(MAKE) -C $(LINUX_DIR) $(KERNEL_MAKEOPTS) HOST_LOADLIBES="-L$(STAGING_DIR_HOST)/lib -lncurses" $$@
+	$(LINUX_RECONF_DIFF) $(LINUX_DIR)/.config > $(LINUX_RECONFIG_TARGET)
+
+  install: $(LINUX_DIR)/.image
+	+$(MAKE) -C image compile install TARGET_BUILD=
+
+  clean: FORCE
+	rm -rf $(KERNEL_BUILD_DIR)
+
+  image-prereq:
+	@+$(NO_TRACE_MAKE) -s -C image prereq TARGET_BUILD=
+
+  prereq: image-prereq
+
+endef
diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk
new file mode 100644
index 0000000000..a17b489c98
--- /dev/null
+++ b/include/kernel-defaults.mk
@@ -0,0 +1,184 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifneq ($(SOURCE_DATE_EPOCH),)
+  ifndef DUMP
+    KBUILD_BUILD_TIMESTAMP:=$(shell perl -e 'print scalar gmtime($(SOURCE_DATE_EPOCH))')
+  endif
+endif
+
+KERNEL_MAKEOPTS := -C $(LINUX_DIR) \
+	HOSTCFLAGS="$(HOST_CFLAGS) -Wall -Wmissing-prototypes -Wstrict-prototypes" \
+	CROSS_COMPILE="$(KERNEL_CROSS)" \
+	ARCH="$(LINUX_KARCH)" \
+	KBUILD_HAVE_NLS=no \
+	KBUILD_BUILD_USER="$(call qstrip,$(CONFIG_KERNEL_BUILD_USER))" \
+	KBUILD_BUILD_HOST="$(call qstrip,$(CONFIG_KERNEL_BUILD_DOMAIN))" \
+	KBUILD_BUILD_TIMESTAMP="$(KBUILD_BUILD_TIMESTAMP)" \
+	KBUILD_BUILD_VERSION="0" \
+	HOST_LOADLIBES="-L$(STAGING_DIR_HOST)/lib" \
+	CONFIG_SHELL="$(BASH)" \
+	$(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \
+	$(if $(PKG_BUILD_ID),LDFLAGS_MODULE=--build-id=0x$(PKG_BUILD_ID))
+
+ifdef CONFIG_STRIP_KERNEL_EXPORTS
+  KERNEL_MAKEOPTS += \
+	EXTRA_LDSFLAGS="-I$(KERNEL_BUILD_DIR) -include symtab.h"
+endif
+
+INITRAMFS_EXTRA_FILES ?= $(GENERIC_PLATFORM_DIR)/image/initramfs-base-files.txt
+
+ifneq (,$(KERNEL_CC))
+  KERNEL_MAKEOPTS += CC="$(KERNEL_CC)"
+endif
+
+ifdef CONFIG_USE_SPARSE
+  KERNEL_MAKEOPTS += C=1 CHECK=$(STAGING_DIR_HOST)/bin/sparse
+endif
+
+ifneq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"")
+ KERNEL_MAKEOPTS += LOCALVERSION=
+endif
+
+export HOST_EXTRACFLAGS=-I$(STAGING_DIR_HOST)/include
+
+# defined in quilt.mk
+Kernel/Patch:=$(Kernel/Patch/Default)
+
+ifeq ($(strip $(CONFIG_EXTERNAL_KERNEL_TREE)),"")
+  ifeq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"")
+    define Kernel/Prepare/Default
+	xzcat $(DL_DIR)/$(LINUX_SOURCE) | $(TAR) -C $(KERNEL_BUILD_DIR) $(TAR_OPTIONS)
+	$(Kernel/Patch)
+	$(if $(QUILT),touch $(LINUX_DIR)/.quilt_used)
+    endef
+  else
+    define Kernel/Prepare/Default
+	xzcat $(DL_DIR)/$(LINUX_SOURCE) | $(TAR) -C $(KERNEL_BUILD_DIR) $(TAR_OPTIONS)
+    endef
+  endif
+else
+  define Kernel/Prepare/Default
+	mkdir -p $(KERNEL_BUILD_DIR)
+	if [ -d $(LINUX_DIR) ]; then \
+		rmdir $(LINUX_DIR); \
+	fi
+	ln -s $(CONFIG_EXTERNAL_KERNEL_TREE) $(LINUX_DIR)
+  endef
+endif
+
+ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
+  ifeq ($(strip $(CONFIG_EXTERNAL_CPIO)),"")
+    define Kernel/SetInitramfs/PreConfigure
+	grep -v -e INITRAMFS -e CONFIG_RD_ -e CONFIG_BLK_DEV_INITRD $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config
+	echo 'CONFIG_BLK_DEV_INITRD=y' >> $(LINUX_DIR)/.config
+	echo 'CONFIG_INITRAMFS_SOURCE="$(strip $(TARGET_DIR) $(INITRAMFS_EXTRA_FILES))"' >> $(LINUX_DIR)/.config
+    endef
+  else
+    define Kernel/SetInitramfs/PreConfigure
+	grep -v INITRAMFS $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config
+	echo 'CONFIG_INITRAMFS_SOURCE="$(call qstrip,$(CONFIG_EXTERNAL_CPIO))"' >> $(LINUX_DIR)/.config
+    endef
+  endif
+
+  define Kernel/SetInitramfs
+	rm -f $(LINUX_DIR)/.config.prev
+	mv $(LINUX_DIR)/.config $(LINUX_DIR)/.config.old
+	$(call Kernel/SetInitramfs/PreConfigure)
+	echo 'CONFIG_INITRAMFS_ROOT_UID=$(shell id -u)' >> $(LINUX_DIR)/.config
+	echo 'CONFIG_INITRAMFS_ROOT_GID=$(shell id -g)' >> $(LINUX_DIR)/.config
+	echo "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_NONE),CONFIG_INITRAMFS_COMPRESSION_NONE=y,# CONFIG_INITRAMFS_COMPRESSION_NONE is not set)" >> $(LINUX_DIR)/.config
+	echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_GZIP),CONFIG_INITRAMFS_COMPRESSION_GZIP=y\nCONFIG_RD_GZIP=y,# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set\n# CONFIG_RD_GZIP is not set)" >> $(LINUX_DIR)/.config
+	echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_BZIP2),CONFIG_INITRAMFS_COMPRESSION_BZIP2=y\nCONFIG_RD_BZIP2=y,# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set\n# CONFIG_RD_BZIP2 is not set)" >> $(LINUX_DIR)/.config
+	echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZMA),CONFIG_INITRAMFS_COMPRESSION_LZMA=y\nCONFIG_RD_LZMA=y,# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set\n# CONFIG_RD_LZMA is not set)" >> $(LINUX_DIR)/.config
+	echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),CONFIG_INITRAMFS_COMPRESSION_LZO=y\nCONFIG_RD_LZO=y,# CONFIG_INITRAMFS_COMPRESSION_LZO is not set\n# CONFIG_RD_LZO is not set)" >> $(LINUX_DIR)/.config
+	echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_XZ),CONFIG_INITRAMFS_COMPRESSION_XZ=y\nCONFIG_RD_XZ=y,# CONFIG_INITRAMFS_COMPRESSION_XZ is not set\n# CONFIG_RD_XZ is not set)" >> $(LINUX_DIR)/.config
+	echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZ4),CONFIG_INITRAMFS_COMPRESSION_LZ4=y\nCONFIG_RD_LZ4=y,# CONFIG_INITRAMFS_COMPRESSION_LZ4 is not set\n# CONFIG_RD_LZ4 is not set)" >> $(LINUX_DIR)/.config
+  endef
+else
+endif
+
+define Kernel/SetNoInitramfs
+	mv $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.old
+	grep -v INITRAMFS $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set
+	echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set
+endef
+
+define Kernel/Configure/Default
+	rm -f $(LINUX_DIR)/localversion
+	$(LINUX_CONF_CMD) > $(LINUX_DIR)/.config.target
+# copy CONFIG_KERNEL_* settings over to .config.target
+	awk '/^(#[[:space:]]+)?CONFIG_KERNEL/{sub("CONFIG_KERNEL_","CONFIG_");print}' $(TOPDIR)/.config >> $(LINUX_DIR)/.config.target
+	echo "# CONFIG_KALLSYMS_EXTRA_PASS is not set" >> $(LINUX_DIR)/.config.target
+	echo "# CONFIG_KALLSYMS_ALL is not set" >> $(LINUX_DIR)/.config.target
+	echo "CONFIG_KALLSYMS_UNCOMPRESSED=y" >> $(LINUX_DIR)/.config.target
+	$(SCRIPT_DIR)/package-metadata.pl kconfig $(TMP_DIR)/.packageinfo $(TOPDIR)/.config $(KERNEL_PATCHVER) > $(LINUX_DIR)/.config.override
+	$(SCRIPT_DIR)/kconfig.pl 'm+' '+' $(LINUX_DIR)/.config.target /dev/null $(LINUX_DIR)/.config.override > $(LINUX_DIR)/.config.set
+	$(call Kernel/SetNoInitramfs)
+	rm -rf $(KERNEL_BUILD_DIR)/modules
+	cmp -s $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.prev || { \
+		cp $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config; \
+		cp $(LINUX_DIR)/.config.set $(LINUX_DIR)/.config.prev; \
+	}
+	$(_SINGLE) [ -d $(LINUX_DIR)/user_headers ] || $(MAKE) $(KERNEL_MAKEOPTS) INSTALL_HDR_PATH=$(LINUX_DIR)/user_headers headers_install
+	$(SH_FUNC) grep '=[ym]' $(LINUX_DIR)/.config.set | LC_ALL=C sort | md5s > $(LINUX_DIR)/.vermagic
+endef
+
+define Kernel/Configure/Initramfs
+	$(call Kernel/SetInitramfs)
+endef
+
+define Kernel/CompileModules/Default
+	rm -f $(LINUX_DIR)/vmlinux $(LINUX_DIR)/System.map
+	+$(MAKE) $(KERNEL_MAKEOPTS) modules
+endef
+
+OBJCOPY_STRIP = -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id
+
+# AMD64 shares the location with x86
+ifeq ($(LINUX_KARCH),x86_64)
+IMAGES_DIR:=../../x86/boot
+endif
+
+define Kernel/CopyImage
+	cmp -s $(LINUX_DIR)/vmlinux $(KERNEL_BUILD_DIR)/vmlinux$(1).debug || { \
+		$(KERNEL_CROSS)objcopy -O binary $(OBJCOPY_STRIP) -S $(LINUX_DIR)/vmlinux $(LINUX_KERNEL)$(1); \
+		$(KERNEL_CROSS)objcopy $(OBJCOPY_STRIP) -S $(LINUX_DIR)/vmlinux $(KERNEL_BUILD_DIR)/vmlinux$(1).elf; \
+		$(CP) $(LINUX_DIR)/vmlinux $(KERNEL_BUILD_DIR)/vmlinux$(1).debug; \
+		$(foreach k, \
+			$(if $(KERNEL_IMAGES),$(KERNEL_IMAGES),$(filter-out dtbs,$(KERNELNAME))), \
+			$(CP) $(LINUX_DIR)/arch/$(LINUX_KARCH)/boot/$(IMAGES_DIR)/$(k) $(KERNEL_BUILD_DIR)/$(k)$(1); \
+		) \
+	}
+endef
+
+define Kernel/CompileImage/Default
+	rm -f $(TARGET_DIR)/init
+	+$(MAKE) $(KERNEL_MAKEOPTS) $(if $(KERNELNAME),$(KERNELNAME),all) modules
+	$(call Kernel/CopyImage)
+endef
+
+ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+define Kernel/CompileImage/Initramfs
+	$(call Kernel/Configure/Initramfs)
+	$(CP) $(GENERIC_PLATFORM_DIR)/base-files/init $(TARGET_DIR)/init
+	rm -rf $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/usr/initramfs_data.cpio*
+	+$(MAKE) $(KERNEL_MAKEOPTS) $(if $(KERNELNAME),$(KERNELNAME),all) modules
+	$(call Kernel/CopyImage,-initramfs)
+endef
+else
+define Kernel/CompileImage/Initramfs
+endef
+endif
+
+define Kernel/Clean/Default
+	rm -f $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/.configured
+	rm -f $(LINUX_KERNEL)
+	$(_SINGLE)$(MAKE) -C $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION) clean
+endef
+
+
diff --git a/include/kernel-version.mk b/include/kernel-version.mk
new file mode 100644
index 0000000000..f2fa0d0b04
--- /dev/null
+++ b/include/kernel-version.mk
@@ -0,0 +1,25 @@
+# Use the default kernel version if the Makefile doesn't override it
+
+LINUX_RELEASE?=1
+
+LINUX_VERSION-3.18 = .43
+LINUX_VERSION-4.1 = .34
+LINUX_VERSION-4.4 = .36
+
+LINUX_KERNEL_MD5SUM-3.18.43 = b1faeb4a2e1e70ffe061bdbb3452840a
+LINUX_KERNEL_MD5SUM-4.1.34 = fba99f0f4765ebf01033e69518740a3c
+LINUX_KERNEL_MD5SUM-4.4.36 = 505548da130599c866d92105a8b04758
+
+ifdef KERNEL_PATCHVER
+  LINUX_VERSION:=$(KERNEL_PATCHVER)$(strip $(LINUX_VERSION-$(KERNEL_PATCHVER)))
+endif
+
+split_version=$(subst ., ,$(1))
+merge_version=$(subst $(space),.,$(1))
+KERNEL_BASE=$(firstword $(subst -, ,$(LINUX_VERSION)))
+KERNEL=$(call merge_version,$(wordlist 1,2,$(call split_version,$(KERNEL_BASE))))
+KERNEL_PATCHVER ?= $(KERNEL)
+
+# disable the md5sum check for unknown kernel versions
+LINUX_KERNEL_MD5SUM:=$(LINUX_KERNEL_MD5SUM-$(strip $(LINUX_VERSION)))
+LINUX_KERNEL_MD5SUM?=x
diff --git a/include/kernel.mk b/include/kernel.mk
new file mode 100644
index 0000000000..54966da789
--- /dev/null
+++ b/include/kernel.mk
@@ -0,0 +1,244 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(__target_inc),)
+  include $(INCLUDE_DIR)/target.mk
+endif
+
+ifeq ($(DUMP),1)
+  KERNEL?=<KERNEL>
+  BOARD?=<BOARD>
+  LINUX_VERSION?=<LINUX_VERSION>
+  LINUX_VERMAGIC?=<LINUX_VERMAGIC>
+else
+  ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+    export GCC_HONOUR_COPTS=s
+  endif
+
+  LINUX_KMOD_SUFFIX=ko
+
+  ifneq (,$(findstring uml,$(BOARD)))
+    KERNEL_CC?=$(HOSTCC)
+    KERNEL_CROSS?=
+  else
+    KERNEL_CC?=$(TARGET_CC)
+    KERNEL_CROSS?=$(TARGET_CROSS)
+  endif
+
+  ifeq ($(TARGET_BUILD),1)
+    PATCH_DIR ?= $(CURDIR)/patches$(if $(wildcard ./patches-$(KERNEL_PATCHVER)),-$(KERNEL_PATCHVER))
+    FILES_DIR ?= $(foreach dir,$(wildcard $(CURDIR)/files $(CURDIR)/files-$(KERNEL_PATCHVER)),"$(dir)")
+  endif
+  KERNEL_BUILD_DIR ?= $(BUILD_DIR)/linux-$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET))
+  LINUX_DIR ?= $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)
+  LINUX_UAPI_DIR=uapi/
+  LINUX_VERMAGIC:=$(strip $(shell cat $(LINUX_DIR)/.vermagic 2>/dev/null))
+  LINUX_VERMAGIC:=$(if $(LINUX_VERMAGIC),$(LINUX_VERMAGIC),unknown)
+
+  LINUX_UNAME_VERSION:=$(if $(word 3,$(subst ., ,$(KERNEL_BASE))),$(KERNEL_BASE),$(KERNEL_BASE).0)
+  ifneq ($(findstring -rc,$(LINUX_VERSION)),)
+    LINUX_UNAME_VERSION:=$(LINUX_UNAME_VERSION)-$(strip $(lastword $(subst -, ,$(LINUX_VERSION))))
+  endif
+
+  MODULES_SUBDIR:=lib/modules/$(LINUX_UNAME_VERSION)-gnu
+  TARGET_MODULES_DIR := $(LINUX_TARGET_DIR)/$(MODULES_SUBDIR)
+
+  LINUX_KERNEL:=$(KERNEL_BUILD_DIR)/vmlinux
+
+  LINUX_SOURCE:=linux-libre-$(LINUX_VERSION)-gnu.tar.xz
+  TESTING:=$(if $(findstring -rc,$(LINUX_VERSION)),/testing,)
+  ifeq ($(call qstrip,$(CONFIG_EXTERNAL_KERNEL_TREE))$(call qstrip,$(CONFIG_KERNEL_GIT_CLONE_URI)),)
+      LINUX_SITE:=@KERNEL_LIBRE/$(LINUX_VERSION)-gnu$(TESTING)
+  endif
+
+  ifneq ($(TARGET_BUILD),1)
+    PKG_BUILD_DIR ?= $(KERNEL_BUILD_DIR)/$(PKG_NAME)$(if $(PKG_VERSION),-$(PKG_VERSION))
+  endif
+endif
+
+ifneq (,$(findstring uml,$(BOARD)))
+  LINUX_KARCH=um
+else ifneq (,$(findstring $(ARCH) , aarch64 aarch64_be ))
+  LINUX_KARCH := arm64
+else ifneq (,$(findstring $(ARCH) , arceb ))
+  LINUX_KARCH := arc
+else ifneq (,$(findstring $(ARCH) , armeb ))
+  LINUX_KARCH := arm
+else ifneq (,$(findstring $(ARCH) , mipsel mips64 mips64el ))
+  LINUX_KARCH := mips
+else ifneq (,$(findstring $(ARCH) , sh2 sh3 sh4 ))
+  LINUX_KARCH := sh
+else ifneq (,$(findstring $(ARCH) , i386 x86_64 ))
+  LINUX_KARCH := x86
+else
+  LINUX_KARCH := $(ARCH)
+endif
+
+define KernelPackage/Defaults
+  FILES:=
+  AUTOLOAD:=
+  PKGFLAGS+=nonshared
+endef
+
+define ModuleAutoLoad
+	$(SH_FUNC) \
+	export modules=; \
+	probe_module() { \
+		mods="$$$$$$$$1"; \
+		boot="$$$$$$$$2"; \
+		shift 2; \
+		for mod in $(sort $$$$$$$$mods); do \
+			mkdir -p $(2)/etc/modules.d; \
+			echo "$$$$$$$$mod" >> $(2)/etc/modules.d/$(1); \
+		done; \
+		if [ -e $(2)/etc/modules.d/$(1) ]; then \
+			if [ "$$$$$$$$boot" = "1" ]; then \
+				mkdir -p $(2)/etc/modules-boot.d; \
+				ln -s ../modules.d/$(1) $(2)/etc/modules-boot.d/; \
+			fi; \
+			modules="$$$$$$$${modules:+$$$$$$$$modules }$$$$$$$$mods"; \
+		fi; \
+	}; \
+	add_module() { \
+		priority="$$$$$$$$1"; \
+		mods="$$$$$$$$2"; \
+		boot="$$$$$$$$3"; \
+		shift 3; \
+		for mod in $(sort $$$$$$$$mods); do \
+			mkdir -p $(2)/etc/modules.d; \
+			echo "$$$$$$$$mod" >> $(2)/etc/modules.d/$$$$$$$$priority-$(1); \
+		done; \
+		if [ -e $(2)/etc/modules.d/$$$$$$$$priority-$(1) ]; then \
+			if [ "$$$$$$$$boot" = "1" ]; then \
+				mkdir -p $(2)/etc/modules-boot.d; \
+				ln -s ../modules.d/$$$$$$$$priority-$(1) $(2)/etc/modules-boot.d/; \
+			fi; \
+			modules="$$$$$$$${modules:+$$$$$$$$modules }$$$$$$$$priority-$(1)"; \
+		fi; \
+	}; \
+	$(3) \
+	if [ -n "$$$$$$$$modules" ]; then \
+		mkdir -p $(2)/etc/modules.d; \
+		mkdir -p $(2)/CONTROL; \
+		echo "#!/bin/sh" > $(2)/CONTROL/postinst-pkg; \
+		echo "[ -z \"\$$$$$$$$IPKG_INSTROOT\" ] || exit 0" >> $(2)/CONTROL/postinst-pkg; \
+		echo ". /lib/functions.sh" >> $(2)/CONTROL/postinst-pkg; \
+		echo "insert_modules $$$$$$$$modules" >> $(2)/CONTROL/postinst-pkg; \
+		chmod 0755 $(2)/CONTROL/postinst-pkg; \
+	fi
+endef
+
+ifeq ($(DUMP)$(TARGET_BUILD),)
+  -include $(LINUX_DIR)/.config
+endif
+
+define KernelPackage/depends
+  $(STAMP_BUILT): $(LINUX_DIR)/.config
+  define KernelPackage/depends
+  endef
+endef
+
+define KernelPackage
+  NAME:=$(1)
+  $(eval $(call Package/Default))
+  $(eval $(call KernelPackage/Defaults))
+  $(eval $(call KernelPackage/$(1)))
+  $(eval $(call KernelPackage/$(1)/$(BOARD)))
+
+  define Package/kmod-$(1)
+    TITLE:=$(TITLE)
+    SECTION:=kernel
+    CATEGORY:=Kernel modules
+    DESCRIPTION:=$(DESCRIPTION)
+    EXTRA_DEPENDS:=kernel (=$(LINUX_VERSION)-$(LINUX_RELEASE)-$(LINUX_VERMAGIC))
+    VERSION:=$(LINUX_VERSION)$(if $(PKG_VERSION),+$(PKG_VERSION))-$(if $(PKG_RELEASE),$(PKG_RELEASE),$(LINUX_RELEASE))
+    PKGFLAGS:=$(PKGFLAGS)
+    $(call KernelPackage/$(1))
+    $(call KernelPackage/$(1)/$(BOARD))
+  endef
+
+  ifdef KernelPackage/$(1)/conffiles
+    define Package/kmod-$(1)/conffiles
+$(call KernelPackage/$(1)/conffiles)
+    endef
+  endif
+
+  ifdef KernelPackage/$(1)/description
+    define Package/kmod-$(1)/description
+$(call KernelPackage/$(1)/description)
+    endef
+  endif
+
+  ifdef KernelPackage/$(1)/config
+    define Package/kmod-$(1)/config
+$(call KernelPackage/$(1)/config)
+    endef
+  endif
+
+  $(call KernelPackage/depends)
+
+  ifneq ($(if $(filter-out %=y %=n %=m,$(KCONFIG)),$(filter m y,$(foreach c,$(filter-out %=y %=n %=m,$(KCONFIG)),$($(c)))),.),)
+    ifneq ($(strip $(FILES)),)
+      define Package/kmod-$(1)/install
+		  @for mod in $$(call version_filter,$$(FILES)); do \
+			if grep -q "$$$$$$$${mod##$(LINUX_DIR)/}" "$(LINUX_DIR)/modules.builtin"; then \
+				echo "NOTICE: module '$$$$$$$$mod' is built-in."; \
+			elif [ -e $$$$$$$$mod ]; then \
+				mkdir -p $$(1)/$(MODULES_SUBDIR) ; \
+				$(CP) -L $$$$$$$$mod $$(1)/$(MODULES_SUBDIR)/ ; \
+			else \
+				echo "ERROR: module '$$$$$$$$mod' is missing." >&2; \
+				exit 1; \
+			fi; \
+		  done;
+		  $(call ModuleAutoLoad,$(1),$$(1),$(AUTOLOAD))
+		  $(call KernelPackage/$(1)/install,$$(1))
+      endef
+    endif
+  $(if $(CONFIG_PACKAGE_kmod-$(1)),
+    else
+      compile: $(1)-disabled
+      $(1)-disabled:
+		@echo "WARNING: kmod-$(1) is not available in the kernel config - generating empty package" >&2
+
+      define Package/kmod-$(1)/install
+		true
+      endef
+  )
+  endif
+  $$(eval $$(call BuildPackage,kmod-$(1)))
+
+  $$(IPKG_kmod-$(1)): $$(wildcard $$(FILES))
+endef
+
+version_filter=$(if $(findstring @,$(1)),$(shell $(SCRIPT_DIR)/package-metadata.pl version_filter $(KERNEL_PATCHVER) $(1)),$(1))
+
+define AutoLoad
+  add_module "$(1)" "$(call version_filter,$(2))" "$(3)";
+endef
+
+define AutoProbe
+  probe_module "$(call version_filter,$(1))" "$(2)";
+endef
+
+version_field=$(if $(word $(1),$(2)),$(word $(1),$(2)),0)
+kernel_version_merge=$$(( ($(call version_field,1,$(1)) << 24) + ($(call version_field,2,$(1)) << 16) + ($(call version_field,3,$(1)) << 8) + $(call version_field,4,$(1)) ))
+
+ifdef DUMP
+  kernel_version_cmp=
+else
+  kernel_version_cmp=$(shell [ $(call kernel_version_merge,$(call split_version,$(2))) $(1) $(call kernel_version_merge,$(call split_version,$(3))) ] && echo 1 )
+endif
+
+CompareKernelPatchVer=$(if $(call kernel_version_cmp,-$(2),$(1),$(3)),1,0)
+
+kernel_patchver_gt=$(call kernel_version_cmp,-gt,$(KERNEL_PATCHVER),$(1))
+kernel_patchver_ge=$(call kernel_version_cmp,-ge,$(KERNEL_PATCHVER),$(1))
+kernel_patchver_eq=$(call kernel_version_cmp,-eq,$(KERNEL_PATCHVER),$(1))
+kernel_patchver_le=$(call kernel_version_cmp,-le,$(KERNEL_PATCHVER),$(1))
+kernel_patchver_lt=$(call kernel_version_cmp,-lt,$(KERNEL_PATCHVER),$(1))
+
diff --git a/include/netfilter.mk b/include/netfilter.mk
new file mode 100644
index 0000000000..c793ce5ac1
--- /dev/null
+++ b/include/netfilter.mk
@@ -0,0 +1,376 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifneq ($(__inc_netfilter),1)
+__inc_netfilter:=1
+
+ifeq ($(NF_KMOD),1)
+P_V4:=ipv4/netfilter/
+P_V6:=ipv6/netfilter/
+P_XT:=netfilter/
+P_EBT:=bridge/netfilter/
+endif
+
+# 1: variable
+# 2: kconfig symbols
+# 3: file list
+# 4: version dependency
+define nf_add
+ $(if $(4),ifeq ($$(strip $$(call CompareKernelPatchVer,$$(KERNEL_PATCHVER),$(firstword $(4)),$(lastword $(4)))),1))
+  $(1)-$$($(2)) += $(3)
+ $(if $(4),endif)
+ KCONFIG_$(1) = $(filter-out $(2),$(KCONFIG_$(1))) $(2)
+endef
+
+
+# core
+
+# kernel only
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_IP_NF_IPTABLES, $(P_V4)ip_tables),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_NETFILTER_XTABLES, $(P_XT)x_tables),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT,CONFIG_NF_REJECT_IPV4, $(P_V4)nf_reject_ipv4),))
+
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_CORE,CONFIG_NETFILTER_XTABLES, $(P_XT)xt_tcpudp),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_CORE,CONFIG_IP_NF_FILTER, $(P_V4)iptable_filter),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_CORE,CONFIG_IP_NF_MANGLE, $(P_V4)iptable_mangle),))
+
+# userland only
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_CORE,CONFIG_IP_NF_IPTABLES, xt_standard ipt_icmp xt_tcp xt_udp xt_comment xt_id xt_set xt_SET)))
+
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_LIMIT, $(P_XT)xt_limit))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_MAC, $(P_XT)xt_mac))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_MULTIPORT, $(P_XT)xt_multiport))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_COMMENT, $(P_XT)xt_comment))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_ID, $(P_XT)xt_id))
+
+#cluster
+$(eval $(call nf_add,IPT_CLUSTER,CONFIG_NETFILTER_XT_MATCH_CLUSTER, $(P_XT)xt_cluster))
+
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_XT)xt_LOG))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_XT)nf_log_common))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_V4)nf_log_ipv4))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_TCPMSS, $(P_XT)xt_TCPMSS))
+$(eval $(call nf_add,IPT_CORE,CONFIG_IP_NF_TARGET_REJECT, $(P_V4)ipt_REJECT))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_TIME, $(P_XT)xt_time))
+$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MARK, $(P_XT)xt_mark))
+
+# kernel has xt_MARK.ko merged into xt_mark.ko, userspace is still separate
+# userland: xt_MARK.so
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MARK, $(P_XT)xt_MARK)))
+
+
+# conntrack
+
+# kernel only
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK,CONFIG_NF_CONNTRACK, $(P_XT)nf_conntrack),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK,CONFIG_NF_CONNTRACK_RTCACHE, $(P_XT)nf_conntrack_rtcache),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK,CONFIG_NF_DEFRAG_IPV4, $(P_V4)nf_defrag_ipv4),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK,CONFIG_NF_CONNTRACK_IPV4, $(P_V4)nf_conntrack_ipv4),))
+
+$(eval $(call nf_add,IPT_CONNTRACK,CONFIG_NETFILTER_XT_MATCH_STATE, $(P_XT)xt_state))
+$(eval $(call nf_add,IPT_CONNTRACK,CONFIG_IP_NF_RAW, $(P_V4)iptable_raw))
+$(eval $(call nf_add,IPT_CONNTRACK,CONFIG_NETFILTER_XT_TARGET_CT, $(P_XT)xt_CT))
+$(eval $(call nf_add,IPT_CONNTRACK,CONFIG_NETFILTER_XT_MATCH_CONNTRACK, $(P_XT)xt_conntrack))
+
+
+# conntrack-extra
+
+$(eval $(call nf_add,IPT_CONNTRACK_EXTRA,CONFIG_NETFILTER_XT_MATCH_CONNBYTES, $(P_XT)xt_connbytes))
+$(eval $(call nf_add,IPT_CONNTRACK_EXTRA,CONFIG_NETFILTER_XT_MATCH_CONNLIMIT, $(P_XT)xt_connlimit))
+$(eval $(call nf_add,IPT_CONNTRACK_EXTRA,CONFIG_NETFILTER_XT_CONNMARK, $(P_XT)xt_connmark))
+$(eval $(call nf_add,IPT_CONNTRACK_EXTRA,CONFIG_NETFILTER_XT_MATCH_HELPER, $(P_XT)xt_helper))
+$(eval $(call nf_add,IPT_CONNTRACK_EXTRA,CONFIG_NETFILTER_XT_MATCH_RECENT, $(P_XT)xt_recent))
+
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_CONNTRACK_EXTRA,CONFIG_NETFILTER_XT_CONNMARK, $(P_XT)xt_CONNMARK)))
+
+# extra
+
+$(eval $(call nf_add,IPT_EXTRA,CONFIG_NETFILTER_XT_MATCH_ADDRTYPE, $(if $(NF_KMOD),$(P_XT)xt_addrtype,$(P_XT)ipt_addrtype)))
+$(eval $(call nf_add,IPT_EXTRA,CONFIG_NETFILTER_XT_MATCH_OWNER, $(P_XT)xt_owner))
+$(eval $(call nf_add,IPT_EXTRA,CONFIG_NETFILTER_XT_MATCH_PHYSDEV, $(P_XT)xt_physdev))
+$(eval $(call nf_add,IPT_EXTRA,CONFIG_NETFILTER_XT_MATCH_PKTTYPE, $(P_XT)xt_pkttype))
+$(eval $(call nf_add,IPT_EXTRA,CONFIG_NETFILTER_XT_MATCH_QUOTA, $(P_XT)xt_quota))
+
+#$(eval $(call nf_add,IPT_EXTRA,CONFIG_IP_NF_TARGET_ROUTE, $(P_V4)ipt_ROUTE))
+
+
+# filter
+
+$(eval $(call nf_add,IPT_FILTER,CONFIG_NETFILTER_XT_MATCH_STRING, $(P_XT)xt_string))
+
+
+# ipopt
+
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_DSCP, $(P_XT)xt_dscp))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_TARGET_DSCP, $(P_XT)xt_DSCP))
+$(eval $(call nf_add,IPT_HASHLIMIT,CONFIG_NETFILTER_XT_MATCH_HASHLIMIT, $(P_XT)xt_hashlimit))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_LENGTH, $(P_XT)xt_length))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_STATISTIC, $(P_XT)xt_statistic))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_TCPMSS, $(P_XT)xt_tcpmss))
+
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_TARGET_CLASSIFY, $(P_XT)xt_CLASSIFY))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_IP_NF_MATCH_DSCP, $(P_V4)ipt_dscp))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_IP_NF_TARGET_ECN, $(P_V4)ipt_ECN))
+
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_ECN, $(P_XT)xt_ecn))
+
+# userland only
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_DSCP, xt_tos)))
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_TARGET_DSCP, xt_TOS)))
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_HL, ipt_ttl)))
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_TARGET_HL, ipt_TTL)))
+
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_MATCH_HL, $(P_XT)xt_hl))
+$(eval $(call nf_add,IPT_IPOPT,CONFIG_NETFILTER_XT_TARGET_HL, $(P_XT)xt_HL))
+
+# iprange
+$(eval $(call nf_add,IPT_IPRANGE,CONFIG_NETFILTER_XT_MATCH_IPRANGE, $(P_XT)xt_iprange))
+
+#clusterip
+$(eval $(call nf_add,IPT_CLUSTERIP,CONFIG_IP_NF_TARGET_CLUSTERIP, $(P_V4)ipt_CLUSTERIP))
+
+# ipsec
+$(eval $(call nf_add,IPT_IPSEC,CONFIG_IP_NF_MATCH_AH, $(P_V4)ipt_ah))
+$(eval $(call nf_add,IPT_IPSEC,CONFIG_NETFILTER_XT_MATCH_ESP, $(P_XT)xt_esp))
+$(eval $(call nf_add,IPT_IPSEC,CONFIG_NETFILTER_XT_MATCH_POLICY, $(P_XT)xt_policy))
+
+
+# IPv6
+
+# kernel only
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT6,CONFIG_IP6_NF_IPTABLES, $(P_V6)ip6_tables),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_IPT6,CONFIG_NF_REJECT_IPV6, $(P_V6)nf_reject_ipv6),))
+
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK6,CONFIG_NF_DEFRAG_IPV6, $(P_V6)nf_defrag_ipv6),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK6,CONFIG_NF_CONNTRACK_IPV6, $(P_V6)nf_conntrack_ipv6),))
+
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_FILTER, $(P_V6)ip6table_filter),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_MANGLE, $(P_V6)ip6table_mangle),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_QUEUE, $(P_V6)ip6_queue),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_RAW, $(P_V6)ip6table_raw),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_NF_LOG_IPV6, $(P_V6)nf_log_ipv6),))
+
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_IPTABLES, ip6t_icmp6)))
+
+
+$(eval $(call nf_add,IPT_IPV6,CONFIG_IP6_NF_TARGET_LOG, $(P_V6)ip6t_LOG))
+$(eval $(call nf_add,IPT_IPV6,CONFIG_IP6_NF_TARGET_REJECT, $(P_V6)ip6t_REJECT))
+
+# ipv6 extra
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_IPV6HEADER, $(P_V6)ip6t_ipv6header))
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_AH, $(P_V6)ip6t_ah))
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_MH, $(P_V6)ip6t_mh))
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_EUI64, $(P_V6)ip6t_eui64))
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_OPTS, $(P_V6)ip6t_hbh))
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_FRAG, $(P_V6)ip6t_frag))
+$(eval $(call nf_add,IPT_IPV6_EXTRA,CONFIG_IP6_NF_MATCH_RT, $(P_V6)ip6t_rt))
+
+# nat
+
+# kernel only
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_NAT,CONFIG_NF_NAT, $(P_XT)nf_nat),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_NAT,CONFIG_NF_NAT_REDIRECT, $(P_XT)nf_nat_redirect, ge 3.19.0),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_NAT,CONFIG_NF_NAT_IPV4, $(P_V4)nf_nat_ipv4),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_NAT,CONFIG_NF_NAT_MASQUERADE_IPV4, $(P_V4)nf_nat_masquerade_ipv4),))
+
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_NAT6,CONFIG_NF_NAT_IPV6, $(P_V6)nf_nat_ipv6),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NF_NAT6,CONFIG_NF_NAT_MASQUERADE_IPV6, $(P_V6)nf_nat_masquerade_ipv6),))
+
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_NAT,CONFIG_NETFILTER_XT_NAT, $(P_XT)xt_nat),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_NAT,CONFIG_IP_NF_NAT, $(P_V4)iptable_nat),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_NAT6,CONFIG_IP6_NF_NAT, $(P_V6)ip6table_nat),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_NAT6,CONFIG_IP6_NF_TARGET_MASQUERADE, $(P_V6)ip6t_MASQUERADE),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_NAT6,CONFIG_IP6_NF_TARGET_NPT, $(P_V6)ip6t_NPT),))
+
+# userland only
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_NAT,CONFIG_NF_NAT, ipt_SNAT ipt_DNAT)))
+$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_NAT6,CONFIG_IP6_NF_TARGET_NPT, ip6t_DNPT ip6t_SNPT)))
+
+$(eval $(call nf_add,IPT_NAT,CONFIG_IP_NF_TARGET_MASQUERADE, $(P_V4)ipt_MASQUERADE))
+$(eval $(call nf_add,IPT_NAT,CONFIG_IP_NF_TARGET_REDIRECT, $(P_XT)xt_REDIRECT))
+
+
+# nat-extra
+
+$(eval $(call nf_add,IPT_NAT_EXTRA,CONFIG_IP_NF_TARGET_NETMAP, $(P_XT)xt_NETMAP))
+
+
+# nathelper
+
+$(eval $(call nf_add,NF_NATHELPER,CONFIG_NF_CONNTRACK_FTP, $(P_XT)nf_conntrack_ftp))
+$(eval $(call nf_add,NF_NATHELPER,CONFIG_NF_NAT_FTP, $(P_XT)nf_nat_ftp))
+
+
+# nathelper-extra
+
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_BROADCAST, $(P_XT)nf_conntrack_broadcast))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_AMANDA, $(P_XT)nf_conntrack_amanda))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_AMANDA, $(P_XT)nf_nat_amanda))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CT_PROTO_GRE, $(P_XT)nf_conntrack_proto_gre))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_PROTO_GRE, $(P_V4)nf_nat_proto_gre))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_H323, $(P_XT)nf_conntrack_h323))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_H323, $(P_V4)nf_nat_h323))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_PPTP, $(P_XT)nf_conntrack_pptp))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_PPTP, $(P_V4)nf_nat_pptp))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_SIP, $(P_XT)nf_conntrack_sip))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_SIP, $(P_XT)nf_nat_sip))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_SNMP, $(P_XT)nf_conntrack_snmp))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_SNMP_BASIC, $(P_V4)nf_nat_snmp_basic))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_TFTP, $(P_XT)nf_conntrack_tftp))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_TFTP, $(P_XT)nf_nat_tftp))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_CONNTRACK_IRC, $(P_XT)nf_conntrack_irc))
+$(eval $(call nf_add,NF_NATHELPER_EXTRA,CONFIG_NF_NAT_IRC, $(P_XT)nf_nat_irc))
+
+
+# ulog
+
+$(eval $(call nf_add,IPT_ULOG,CONFIG_IP_NF_TARGET_ULOG, $(P_V4)ipt_ULOG))
+
+
+# nflog
+
+$(eval $(call nf_add,IPT_NFLOG,CONFIG_NETFILTER_XT_TARGET_NFLOG, $(P_XT)xt_NFLOG))
+
+
+# nfqueue
+
+$(eval $(call nf_add,IPT_NFQUEUE,CONFIG_NETFILTER_XT_TARGET_NFQUEUE, $(P_XT)xt_NFQUEUE))
+
+
+# debugging
+
+$(eval $(call nf_add,IPT_DEBUG,CONFIG_NETFILTER_XT_TARGET_TRACE, $(P_XT)xt_TRACE))
+
+# tproxy
+
+$(eval $(call nf_add,IPT_TPROXY,CONFIG_NETFILTER_XT_MATCH_SOCKET, $(P_XT)xt_socket))
+$(eval $(call nf_add,IPT_TPROXY,CONFIG_NETFILTER_XT_TARGET_TPROXY, $(P_XT)xt_TPROXY))
+
+# led
+$(eval $(call nf_add,IPT_LED,CONFIG_NETFILTER_XT_TARGET_LED, $(P_XT)xt_LED))
+
+# tee
+
+$(eval $(call nf_add,IPT_TEE,CONFIG_NETFILTER_XT_TARGET_TEE, $(P_XT)xt_TEE))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_TEE,CONFIG_NF_DUP_IPV4, $(P_V4)nf_dup_ipv4, ge 4.3),))
+$(eval $(if $(NF_KMOD),$(call nf_add,IPT_TEE,CONFIG_NF_DUP_IPV6, $(P_V6)nf_dup_ipv6, ge 4.3),))
+
+# u32
+
+$(eval $(call nf_add,IPT_U32,CONFIG_NETFILTER_XT_MATCH_U32, $(P_XT)xt_u32))
+
+
+# netlink
+
+$(eval $(call nf_add,NFNETLINK,CONFIG_NETFILTER_NETLINK, $(P_XT)nfnetlink))
+
+# nflog
+
+$(eval $(call nf_add,NFNETLINK_LOG,CONFIG_NETFILTER_NETLINK_LOG, $(P_XT)nfnetlink_log))
+
+# nfqueue
+
+$(eval $(call nf_add,NFNETLINK_QUEUE,CONFIG_NETFILTER_NETLINK_QUEUE, $(P_XT)nfnetlink_queue))
+
+#
+# ebtables
+#
+
+$(eval $(if $(NF_KMOD),$(call nf_add,EBTABLES,CONFIG_BRIDGE_NF_EBTABLES, $(P_EBT)ebtables),))
+
+# ebtables: tables
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_BROUTE, $(P_EBT)ebtable_broute))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_T_FILTER, $(P_EBT)ebtable_filter))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_T_NAT, $(P_EBT)ebtable_nat))
+
+# ebtables: matches
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_802_3, $(P_EBT)ebt_802_3))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_AMONG, $(P_EBT)ebt_among))
+$(eval $(call nf_add,EBTABLES_IP4,CONFIG_BRIDGE_EBT_ARP, $(P_EBT)ebt_arp))
+$(eval $(call nf_add,EBTABLES_IP4,CONFIG_BRIDGE_EBT_IP, $(P_EBT)ebt_ip))
+$(eval $(call nf_add,EBTABLES_IP6,CONFIG_BRIDGE_EBT_IP6, $(P_EBT)ebt_ip6))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_LIMIT, $(P_EBT)ebt_limit))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_MARK, $(P_EBT)ebt_mark_m))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_PKTTYPE, $(P_EBT)ebt_pkttype))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_STP, $(P_EBT)ebt_stp))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_VLAN, $(P_EBT)ebt_vlan))
+
+# targets
+$(eval $(call nf_add,EBTABLES_IP4,CONFIG_BRIDGE_EBT_ARPREPLY, $(P_EBT)ebt_arpreply))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_MARK_T, $(P_EBT)ebt_mark))
+$(eval $(call nf_add,EBTABLES_IP4,CONFIG_BRIDGE_EBT_DNAT, $(P_EBT)ebt_dnat))
+$(eval $(call nf_add,EBTABLES,CONFIG_BRIDGE_EBT_REDIRECT, $(P_EBT)ebt_redirect))
+$(eval $(call nf_add,EBTABLES_IP4,CONFIG_BRIDGE_EBT_SNAT, $(P_EBT)ebt_snat))
+
+# watchers
+$(eval $(call nf_add,EBTABLES_WATCHERS,CONFIG_BRIDGE_EBT_LOG, $(P_EBT)ebt_log))
+$(eval $(call nf_add,EBTABLES_WATCHERS,CONFIG_BRIDGE_EBT_ULOG, $(P_EBT)ebt_ulog))
+$(eval $(call nf_add,EBTABLES_WATCHERS,CONFIG_BRIDGE_EBT_NFLOG, $(P_EBT)ebt_nflog))
+$(eval $(call nf_add,EBTABLES_WATCHERS,CONFIG_BRIDGE_EBT_NFQUEUE, $(P_EBT)ebt_nfqueue))
+
+# nftables
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NF_TABLES, $(P_XT)nf_tables),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NF_TABLES_INET, $(P_XT)nf_tables_inet),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_EXTHDR, $(P_XT)nft_exthdr),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_META, $(P_XT)nft_meta),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_CT, $(P_XT)nft_ct),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_RBTREE, $(P_XT)nft_rbtree),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_HASH, $(P_XT)nft_hash),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_COUNTER, $(P_XT)nft_counter),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_LOG, $(P_XT)nft_log),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_LIMIT, $(P_XT)nft_limit),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_REJECT, $(P_XT)nft_reject $(P_V4)nft_reject_ipv4 $(P_V6)nft_reject_ipv6),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_REJECT_INET, $(P_XT)nft_reject_inet),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NF_TABLES_IPV4, $(P_V4)nf_tables_ipv4),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_CHAIN_ROUTE_IPV4, $(P_V4)nft_chain_route_ipv4),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NF_TABLES_IPV6, $(P_V6)nf_tables_ipv6),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_CHAIN_ROUTE_IPV6, $(P_V6)nft_chain_route_ipv6),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_CORE,CONFIG_NFT_REDIR, $(P_XT)nft_redir, ge 3.19.0),))
+
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT,CONFIG_NFT_NAT, $(P_XT)nft_nat),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT,CONFIG_NFT_CHAIN_NAT_IPV4, $(P_V4)nft_chain_nat_ipv4),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT,CONFIG_NFT_REDIR_IPV4, $(P_V4)nft_redir_ipv4, ge 3.19.0),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT6,CONFIG_NFT_REDIR_IPV6, $(P_V6)nft_redir_ipv6, ge 3.19.0),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT6,CONFIG_NFT_CHAIN_NAT_IPV6, $(P_V6)nft_chain_nat_ipv6),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT,CONFIG_NFT_MASQ, $(P_XT)nft_masq),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT,CONFIG_NFT_MASQ_IPV4, $(P_V4)nft_masq_ipv4),))
+$(eval $(if $(NF_KMOD),$(call nf_add,NFT_NAT,CONFIG_NFT_MASQ_IPV6, $(P_V6)nft_masq_ipv6),))
+
+# userland only
+IPT_BUILTIN += $(NF_IPT-y) $(NF_IPT-m)
+IPT_BUILTIN += $(IPT_CORE-y) $(IPT_CORE-m)
+IPT_BUILTIN += $(NF_CONNTRACK-y)
+IPT_BUILTIN += $(NF_CONNTRACK6-y)
+IPT_BUILTIN += $(IPT_CONNTRACK-y)
+IPT_BUILTIN += $(IPT_CONNTRACK_EXTRA-y)
+IPT_BUILTIN += $(IPT_EXTRA-y)
+IPT_BUILTIN += $(IPT_FILTER-y)
+IPT_BUILTIN += $(IPT_IPOPT-y)
+IPT_BUILTIN += $(IPT_IPRANGE-y)
+IPT_BUILTIN += $(IPT_CLUSTER-y)
+IPT_BUILTIN += $(IPT_CLUSTERIP-y)
+IPT_BUILTIN += $(IPT_IPSEC-y)
+IPT_BUILTIN += $(IPT_IPV6-y) $(IPT_IPV6-m)
+IPT_BUILTIN += $(NF_NAT-y)
+IPT_BUILTIN += $(NF_NAT6-y)
+IPT_BUILTIN += $(IPT_NAT-y)
+IPT_BUILTIN += $(IPT_NAT6-y)
+IPT_BUILTIN += $(IPT_NAT_EXTRA-y)
+IPT_BUILTIN += $(NF_NATHELPER-y)
+IPT_BUILTIN += $(NF_NATHELPER_EXTRA-y)
+IPT_BUILTIN += $(IPT_ULOG-y)
+IPT_BUILTIN += $(IPT_DEBUG-y)
+IPT_BUILTIN += $(IPT_TPROXY-y)
+IPT_BUILTIN += $(NFNETLINK-y)
+IPT_BUILTIN += $(NFNETLINK_LOG-y)
+IPT_BUILTIN += $(NFNETLINK_QUEUE-y)
+IPT_BUILTIN += $(EBTABLES-y)
+IPT_BUILTIN += $(EBTABLES_IP4-y)
+IPT_BUILTIN += $(EBTABLES_IP6-y)
+IPT_BUILTIN += $(EBTABLES_WATCHERS-y)
+
+endif # __inc_netfilter
diff --git a/include/nls.mk b/include/nls.mk
new file mode 100644
index 0000000000..51463b9f12
--- /dev/null
+++ b/include/nls.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+# iconv full
+ifeq ($(CONFIG_BUILD_NLS),y)
+	ICONV_PREFIX:=$(STAGING_DIR)/usr/lib/libiconv-full
+	ICONV_FULL:=1
+
+	INTL_PREFIX:=$(STAGING_DIR)/usr/lib/libintl-full
+	INTL_FULL:=1
+
+# iconv stub
+else
+	ICONV_PREFIX:=$(STAGING_DIR)/usr/lib/libiconv-stub
+	ICONV_FULL:=
+
+	INTL_PREFIX:=$(STAGING_DIR)/usr/lib/libintl-stub
+	INTL_FULL:=
+endif
+
+PKG_CONFIG_DEPENDS += CONFIG_BUILD_NLS
+PKG_BUILD_DEPENDS += !BUILD_NLS:libiconv !BUILD_NLS:libintl
+
+ICONV_DEPENDS:=+BUILD_NLS:libiconv-full
+ICONV_CFLAGS:=-I$(ICONV_PREFIX)/include
+ICONV_CPPFLAGS:=-I$(ICONV_PREFIX)/include
+ICONV_LDFLAGS:=-L$(ICONV_PREFIX)/lib -Wl,-rpath-link=$(ICONV_PREFIX)/lib
+
+INTL_DEPENDS:=+BUILD_NLS:libintl-full
+INTL_CFLAGS:=-I$(INTL_PREFIX)/include
+INTL_CPPFLAGS:=-I$(INTL_PREFIX)/include
+INTL_LDFLAGS:=-L$(INTL_PREFIX)/lib -Wl,-rpath-link=$(INTL_PREFIX)/lib
+
+TARGET_CFLAGS += $(ICONV_CFLAGS) $(INTL_CFLAGS)
+TARGET_CPPFLAGS += $(ICONV_CPPFLAGS) $(INTL_CPPFLAGS)
+TARGET_LDFLAGS += $(ICONV_LDFLAGS) $(INTL_LDFLAGS)
diff --git a/include/package-bin.mk b/include/package-bin.mk
new file mode 100644
index 0000000000..e5224517f8
--- /dev/null
+++ b/include/package-bin.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2007-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(DUMP),)
+  define BuildTarget/bin
+    ifeq ($(if $(VARIANT),$(BUILD_VARIANT)),$(VARIANT))
+    ifdef Package/$(1)/install
+      ifneq ($(CONFIG_PACKAGE_$(1))$(DEVELOPER),)
+        compile: install-bin-$(1)
+      else
+        compile: $(1)-disabled
+        $(1)-disabled:
+		@echo "WARNING: skipping $(1) -- package not selected" >&2
+      endif
+    endif
+    endif
+
+    install-bin-$(1): $(STAMP_BUILT)
+	  rm -rf $(BIN_DIR)/$(1)
+	  $(INSTALL_DIR) $(BIN_DIR)/$(1)
+	  $(call Package/$(1)/install,$(BIN_DIR)/$(1))
+
+    clean-$(1):
+	  rm -rf $(BIN_DIR)/$(1)
+
+    clean: clean-$(1)
+    .PHONY: install-bin-$(1)
+  endef
+endif
diff --git a/include/package-defaults.mk b/include/package-defaults.mk
new file mode 100644
index 0000000000..487811c0e2
--- /dev/null
+++ b/include/package-defaults.mk
@@ -0,0 +1,162 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+PKG_DEFAULT_DEPENDS = +libc +SSP_SUPPORT:libssp +USE_GLIBC:librt +USE_GLIBC:libpthread
+
+ifneq ($(PKG_NAME),toolchain)
+  PKG_FIXUP_DEPENDS = $(if $(filter kmod-%,$(1)),$(2),$(PKG_DEFAULT_DEPENDS) $(filter-out $(PKG_DEFAULT_DEPENDS),$(2)))
+else
+  PKG_FIXUP_DEPENDS = $(2)
+endif
+
+define Package/Default
+  CONFIGFILE:=
+  SECTION:=opt
+  CATEGORY:=Extra packages
+  DEPENDS:=
+  MDEPENDS:=
+  CONFLICTS:=
+  PROVIDES:=
+  EXTRA_DEPENDS:=
+  MAINTAINER:=$(PKG_MAINTAINER)
+  SOURCE:=$(patsubst $(TOPDIR)/%,%,$(CURDIR))
+  ifneq ($(PKG_VERSION),)
+    ifneq ($(PKG_RELEASE),)
+      VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
+    else
+      VERSION:=$(PKG_VERSION)
+    endif
+  else
+    VERSION:=$(PKG_RELEASE)
+  endif
+  ABI_VERSION:=
+  ifneq ($(PKG_FLAGS),)
+    PKGFLAGS:=$(PKG_FLAGS)
+  else
+    PKGFLAGS:=
+  endif
+  ifneq ($(ARCH_PACKAGES),)
+    PKGARCH:=$(ARCH_PACKAGES)
+  else
+    PKGARCH:=$(BOARD)
+  endif
+  DEFAULT:=
+  MENU:=
+  SUBMENU:=
+  SUBMENUDEP:=
+  TITLE:=
+  KCONFIG:=
+  BUILDONLY:=
+  HIDDEN:=
+  URL:=
+  VARIANT:=
+  DEFAULT_VARIANT:=
+  USERID:=
+endef
+
+Build/Patch:=$(Build/Patch/Default)
+ifneq ($(strip $(PKG_UNPACK)),)
+  define Build/Prepare/Default
+	$(PKG_UNPACK)
+	[ ! -d ./src/ ] || $(CP) ./src/* $(PKG_BUILD_DIR)
+	$(Build/Patch)
+  endef
+endif
+
+EXTRA_CXXFLAGS = $(EXTRA_CFLAGS)
+ifeq ($(CONFIG_BUILD_NLS),y)
+    DISABLE_NLS:=
+else
+    DISABLE_NLS:=--disable-nls
+endif
+
+CONFIGURE_PREFIX:=/usr
+CONFIGURE_ARGS = \
+		--target=$(GNU_TARGET_NAME) \
+		--host=$(GNU_TARGET_NAME) \
+		--build=$(GNU_HOST_NAME) \
+		--program-prefix="" \
+		--program-suffix="" \
+		--prefix=$(CONFIGURE_PREFIX) \
+		--exec-prefix=$(CONFIGURE_PREFIX) \
+		--bindir=$(CONFIGURE_PREFIX)/bin \
+		--sbindir=$(CONFIGURE_PREFIX)/sbin \
+		--libexecdir=$(CONFIGURE_PREFIX)/lib \
+		--sysconfdir=/etc \
+		--datadir=$(CONFIGURE_PREFIX)/share \
+		--localstatedir=/var \
+		--mandir=$(CONFIGURE_PREFIX)/man \
+		--infodir=$(CONFIGURE_PREFIX)/info \
+		$(DISABLE_NLS) \
+		$(DISABLE_LARGEFILE) \
+		$(DISABLE_IPV6)
+
+CONFIGURE_VARS = \
+		$(TARGET_CONFIGURE_OPTS) \
+		CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS)" \
+		CXXFLAGS="$(TARGET_CXXFLAGS) $(EXTRA_CXXFLAGS)" \
+		CPPFLAGS="$(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
+		LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS)" \
+
+CONFIGURE_PATH = .
+CONFIGURE_CMD = ./configure
+
+replace_script=$(FIND) $(1) -name $(2) | $(XARGS) chmod u+w; \
+	       $(FIND) $(1) -name $(2) | $(XARGS) -n1 cp --remove-destination \
+	       $(SCRIPT_DIR)/$(2);
+
+define Build/Configure/Default
+	(cd $(PKG_BUILD_DIR)/$(CONFIGURE_PATH)/$(strip $(3)); \
+	if [ -x $(CONFIGURE_CMD) ]; then \
+		$(call replace_script,$(PKG_BUILD_DIR)/$(3),config.guess) \
+		$(call replace_script,$(PKG_BUILD_DIR)/$(3),config.sub) \
+		$(CONFIGURE_VARS) \
+		$(2) \
+		$(CONFIGURE_CMD) \
+		$(CONFIGURE_ARGS) \
+		$(1); \
+	fi; \
+	)
+endef
+
+MAKE_VARS = \
+	CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
+	CXXFLAGS="$(TARGET_CXXFLAGS) $(EXTRA_CXXFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
+	LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS)"
+
+MAKE_FLAGS = \
+	$(TARGET_CONFIGURE_OPTS) \
+	CROSS="$(TARGET_CROSS)" \
+	ARCH="$(ARCH)"
+
+MAKE_INSTALL_FLAGS = \
+	$(MAKE_FLAGS) \
+	DESTDIR="$(PKG_INSTALL_DIR)"
+
+MAKE_PATH ?= .
+
+define Build/Compile/Default
+	+$(MAKE_VARS) \
+	$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/$(MAKE_PATH) \
+		$(MAKE_FLAGS) \
+		$(1);
+endef
+
+define Build/Install/Default
+	$(MAKE_VARS) \
+	$(MAKE) -C $(PKG_BUILD_DIR)/$(MAKE_PATH) \
+		$(MAKE_INSTALL_FLAGS) \
+		$(if $(1), $(1), install);
+endef
+
+define Build/Dist/Default
+	$(call Build/Compile/Default, DESTDIR="$(PKG_BUILD_DIR)/tmp" CC="$(TARGET_CC)" dist)
+endef
+
+define Build/DistCheck/Default
+	$(call Build/Compile/Default, DESTDIR="$(PKG_BUILD_DIR)/tmp" CC="$(TARGET_CC)" distcheck)
+endef
diff --git a/include/package-dumpinfo.mk b/include/package-dumpinfo.mk
new file mode 100644
index 0000000000..b717c1b472
--- /dev/null
+++ b/include/package-dumpinfo.mk
@@ -0,0 +1,91 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifneq ($(DUMP),)
+
+dumpinfo: FORCE
+
+define Config/template
+Preconfig: $(1)
+Preconfig-Type: $(2)
+Preconfig-Default: $(3)
+Preconfig-Label: $(4)
+
+endef
+
+define Config
+  Preconfig/$(1) = $$(call Config/template,$(1),$(2),$(3),$(4))
+  preconfig_$$(1) += $(1)
+endef
+
+define Dumpinfo/Package
+$(info Package: $(1)
+$(if $(MENU),Menu: $(MENU)
+)$(if $(SUBMENU),Submenu: $(SUBMENU)
+)$(if $(SUBMENUDEP),Submenu-Depends: $(SUBMENUDEP)
+)$(if $(DEFAULT),Default: $(DEFAULT)
+)$(if $(findstring $(PREREQ_CHECK),1),Prereq-Check: 1
+)Version: $(VERSION)
+Depends: $(call PKG_FIXUP_DEPENDS,$(1),$(DEPENDS))
+Conflicts: $(CONFLICTS)
+Menu-Depends: $(MDEPENDS)
+Provides: $(PROVIDES)
+$(if $(VARIANT),Build-Variant: $(VARIANT)
+$(if $(DEFAULT_VARIANT),Default-Variant: $(VARIANT)
+))$(if $(PKG_BUILD_DEPENDS),Build-Depends: $(PKG_BUILD_DEPENDS)
+)$(if $(HOST_BUILD_DEPENDS),Build-Depends/host: $(HOST_BUILD_DEPENDS)
+)$(if $(BUILD_TYPES),Build-Types: $(BUILD_TYPES)
+)Section: $(SECTION)
+Category: $(CATEGORY)
+$(if $(filter nonshared,$(PKGFLAGS)),,Repository: $(if $(FEED),$(FEED),base)
+)Title: $(TITLE)
+Maintainer: $(MAINTAINER)
+$(if $(USERID),Require-User: $(USERID)
+)Source: $(PKG_SOURCE)
+$(if $(PKG_LICENSE),License: $(PKG_LICENSE)
+)$(if $(PKG_LICENSE_FILES),LicenseFiles: $(PKG_LICENSE_FILES)
+)Type: $(if $(Package/$(1)/targets),$(Package/$(1)/targets),$(if $(PKG_TARGETS),$(PKG_TARGETS),ipkg))
+$(if $(KCONFIG),Kernel-Config: $(KCONFIG)
+)$(if $(BUILDONLY),Build-Only: $(BUILDONLY)
+)$(if $(HIDDEN),Hidden: $(HIDDEN)
+)Description: $(if $(Package/$(1)/description),$(Package/$(1)/description),$(TITLE))
+$(if $(URL),$(URL)
+)$(MAINTAINER)
+@@
+$(if $(Package/$(1)/config),Config:
+$(Package/$(1)/config)
+@@
+)$(foreach pc,$(preconfig_$(1)),
+$(Preconfig/$(pc))))
+endef
+
+define Feature/Default
+  TARGET_NAME:=
+  TARGET_TITLE:=
+  PRIORITY:=
+  NAME:=
+endef
+
+define Feature
+  $(eval $(Feature/Default))
+  $(eval $(Feature/$(1)))
+  $(if $(DUMP),$(call Dumpinfo/Feature,$(1)))
+endef
+
+define Dumpinfo/Feature
+$(info Feature: $(TARGET_NAME)_$(1)
+Target-Name: $(TARGET_NAME)
+Target-Title: $(TARGET_TITLE)
+Feature-Name: $(NAME)
+$(if $(PRIORITY),Feature-Priority: $(PRIORITY)
+)Feature-Description:
+$(Feature/$(1)/description)
+@@
+)
+endef
+
+endif
diff --git a/include/package-ipkg.mk b/include/package-ipkg.mk
new file mode 100644
index 0000000000..afd2d4ef7a
--- /dev/null
+++ b/include/package-ipkg.mk
@@ -0,0 +1,238 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifndef DUMP
+  include $(INCLUDE_DIR)/feeds.mk
+endif
+
+# invoke ipkg-build with some default options
+IPKG_BUILD:= \
+  $(SCRIPT_DIR)/ipkg-build -c -o 0 -g 0
+
+IPKG_STATE_DIR:=$(TARGET_DIR)/usr/lib/opkg
+
+# 1: package name
+# 2: variable name
+# 3: variable suffix
+# 4: file is a script
+define BuildIPKGVariable
+ifdef Package/$(1)/$(2)
+  $$(IPKG_$(1)) : VAR_$(2)$(3)=$$(Package/$(1)/$(2))
+  $(call shexport,Package/$(1)/$(2))
+  $(1)_COMMANDS += echo "$$$$$$$$$(call shvar,Package/$(1)/$(2))" > $(2)$(3); $(if $(4),chmod 0755 $(2)$(3);)
+endif
+endef
+
+PARENL :=(
+PARENR :=)
+
+dep_split=$(subst :,$(space),$(1))
+dep_rem=$(subst !,,$(subst $(strip $(PARENL)),,$(subst $(strip $(PARENR)),,$(word 1,$(call dep_split,$(1))))))
+dep_confvar=$(strip $(foreach cond,$(subst ||, ,$(call dep_rem,$(1))),$(CONFIG_$(cond))))
+dep_pos=$(if $(call dep_confvar,$(1)),$(call dep_val,$(1)))
+dep_neg=$(if $(call dep_confvar,$(1)),,$(call dep_val,$(1)))
+dep_if=$(if $(findstring !,$(1)),$(call dep_neg,$(1)),$(call dep_pos,$(1)))
+dep_val=$(word 2,$(call dep_split,$(1)))
+strip_deps=$(strip $(subst +,,$(filter-out @%,$(1))))
+filter_deps=$(foreach dep,$(call strip_deps,$(1)),$(if $(findstring :,$(dep)),$(call dep_if,$(dep)),$(dep)))
+
+define AddDependency
+  $$(if $(1),$$(if $(2),$$(foreach pkg,$(1),$$(IPKG_$$(pkg))): $$(foreach pkg,$(2),$$(IPKG_$$(pkg)))))
+endef
+
+define FixupReverseDependencies
+  DEPS := $$(filter %:$(1),$$(IDEPEND))
+  DEPS := $$(patsubst %:$(1),%,$$(DEPS))
+  DEPS := $$(filter $$(DEPS),$$(IPKGS))
+  $(call AddDependency,$$(DEPS),$(1))
+endef
+
+define FixupDependencies
+  DEPS := $$(filter $(1):%,$$(IDEPEND))
+  DEPS := $$(patsubst $(1):%,%,$$(DEPS))
+  DEPS := $$(filter $$(DEPS),$$(IPKGS))
+  $(call AddDependency,$(1),$$(DEPS))
+endef
+
+ifneq ($(PKG_NAME),toolchain)
+  define CheckDependencies
+	@( \
+		rm -f $(PKG_INFO_DIR)/$(1).missing; \
+		( \
+			export \
+				READELF=$(TARGET_CROSS)readelf \
+				OBJCOPY=$(TARGET_CROSS)objcopy \
+				XARGS="$(XARGS)"; \
+			$(SCRIPT_DIR)/gen-dependencies.sh "$$(IDIR_$(1))"; \
+		) | while read FILE; do \
+			grep -qxF "$$$$FILE" $(PKG_INFO_DIR)/$(1).provides || \
+				echo "$$$$FILE" >> $(PKG_INFO_DIR)/$(1).missing; \
+		done; \
+		if [ -f "$(PKG_INFO_DIR)/$(1).missing" ]; then \
+			echo "Package $(1) is missing dependencies for the following libraries:" >&2; \
+			cat "$(PKG_INFO_DIR)/$(1).missing" >&2; \
+			false; \
+		fi; \
+	)
+  endef
+endif
+
+_addsep=$(word 1,$(1))$(foreach w,$(wordlist 2,$(words $(1)),$(1)),$(strip $(2) $(w)))
+_cleansep=$(subst $(space)$(2)$(space),$(2)$(space),$(1))
+mergelist=$(call _cleansep,$(call _addsep,$(1),$(comma)),$(comma))
+addfield=$(if $(strip $(2)),$(1): $(2))
+_define=define
+_endef=endef
+
+ifeq ($(DUMP),)
+  define BuildTarget/ipkg
+    PDIR_$(1):=$(call FeedPackageDir,$(1))
+    IPKG_$(1):=$$(PDIR_$(1))/$(1)_$(VERSION)_$(PKGARCH).ipk
+    IDIR_$(1):=$(PKG_BUILD_DIR)/ipkg-$(PKGARCH)/$(1)
+    KEEP_$(1):=$(strip $(call Package/$(1)/conffiles))
+
+    ifeq ($(BUILD_VARIANT),$$(if $$(VARIANT),$$(VARIANT),$(BUILD_VARIANT)))
+    ifdef Package/$(1)/install
+      ifneq ($(CONFIG_PACKAGE_$(1))$(DEVELOPER),)
+        IPKGS += $(1)
+        compile: $$(IPKG_$(1)) $(PKG_INFO_DIR)/$(1).provides $(STAGING_DIR_ROOT)/stamp/.$(1)_installed
+        ifneq ($(ABI_VERSION),)
+        compile: $(PKG_INFO_DIR)/$(1).version
+        endif
+      else
+        $(if $(CONFIG_PACKAGE_$(1)),$$(info WARNING: skipping $(1) -- package not selected))
+      endif
+
+      .PHONY: $(PKG_INSTALL_STAMP).$(1)
+      compile: $(PKG_INSTALL_STAMP).$(1)
+      $(PKG_INSTALL_STAMP).$(1):
+			if [ -f $(PKG_INSTALL_STAMP).clean ]; then \
+				rm -f \
+					$(PKG_INSTALL_STAMP) \
+					$(PKG_INSTALL_STAMP).clean; \
+			fi
+      ifeq ($(CONFIG_PACKAGE_$(1)),y)
+			echo "$(1)" >> $(PKG_INSTALL_STAMP)
+      endif
+    endif
+    endif
+
+    DEPENDS:=$(call PKG_FIXUP_DEPENDS,$(1),$(DEPENDS))
+    IDEPEND_$(1):=$$(call filter_deps,$$(DEPENDS))
+    IDEPEND += $$(patsubst %,$(1):%,$$(IDEPEND_$(1)))
+    $(FixupDependencies)
+    $(FixupReverseDependencies)
+
+    $(eval $(call BuildIPKGVariable,$(1),conffiles))
+    $(eval $(call BuildIPKGVariable,$(1),preinst,,1))
+    $(eval $(call BuildIPKGVariable,$(1),postinst,-pkg,1))
+    $(eval $(call BuildIPKGVariable,$(1),prerm,-pkg,1))
+    $(eval $(call BuildIPKGVariable,$(1),postrm,,1))
+
+    $(STAGING_DIR_ROOT)/stamp/.$(1)_installed : export PATH=$$(TARGET_PATH_PKG)
+    $(STAGING_DIR_ROOT)/stamp/.$(1)_installed: $(STAMP_BUILT)
+	rm -rf $(STAGING_DIR_ROOT)/tmp-$(1)
+	mkdir -p $(STAGING_DIR_ROOT)/stamp $(STAGING_DIR_ROOT)/tmp-$(1)
+	$(call Package/$(1)/install,$(STAGING_DIR_ROOT)/tmp-$(1))
+	$(call Package/$(1)/install_lib,$(STAGING_DIR_ROOT)/tmp-$(1))
+	$(call locked,$(CP) $(STAGING_DIR_ROOT)/tmp-$(1)/. $(STAGING_DIR_ROOT)/,root-copy)
+	rm -rf $(STAGING_DIR_ROOT)/tmp-$(1)
+	touch $$@
+
+    $(PKG_INFO_DIR)/$(1).version: $$(IPKG_$(1))
+	echo '$(ABI_VERSION)' | cmp -s - $$@ || \
+		echo '$(ABI_VERSION)' > $$@
+
+    Package/$(1)/DEPENDS := $$(call mergelist,$$(filter-out @%,$$(IDEPEND_$(1))))
+    ifneq ($$(EXTRA_DEPENDS),)
+      Package/$(1)/DEPENDS := $$(EXTRA_DEPENDS)$$(if $$(Package/$(1)/DEPENDS),$$(comma) $$(Package/$(1)/DEPENDS))
+    endif
+
+$(_define) Package/$(1)/CONTROL
+Package: $(1)
+Version: $(VERSION)
+$$(call addfield,Depends,$$(Package/$(1)/DEPENDS)
+)$$(call addfield,Conflicts,$$(call mergelist,$(CONFLICTS))
+)$$(call addfield,Provides,$$(call mergelist,$(PROVIDES))
+)$$(call addfield,Source,$(SOURCE)
+)$$(call addfield,License,$$(PKG_LICENSE)
+)$$(call addfield,LicenseFiles,$$(PKG_LICENSE_FILES)
+)$$(call addfield,Section,$(SECTION)
+)$$(call addfield,Require-User,$(USERID)
+)$(if $(filter hold,$(PKG_FLAGS)),Status: unknown hold not-installed
+)$(if $(filter essential,$(PKG_FLAGS)),Essential: yes
+)$(if $(MAINTAINER),Maintainer: $(MAINTAINER)
+)Architecture: $(PKGARCH)
+Installed-Size: 0
+$(_endef)
+
+    $(PKG_INFO_DIR)/$(1).provides: $$(IPKG_$(1))
+    $$(IPKG_$(1)) : export CONTROL=$$(Package/$(1)/CONTROL)
+    $$(IPKG_$(1)) : export DESCRIPTION=$$(Package/$(1)/description)
+    $$(IPKG_$(1)) : export PATH=$$(TARGET_PATH_PKG)
+    $$(IPKG_$(1)): $(STAMP_BUILT) $(INCLUDE_DIR)/package-ipkg.mk
+	@rm -rf $$(IDIR_$(1)) $$(call opkg_package_files,$(1))
+	mkdir -p $(PACKAGE_DIR) $$(IDIR_$(1))/CONTROL $(PKG_INFO_DIR)
+	$(call Package/$(1)/install,$$(IDIR_$(1)))
+	-find $$(IDIR_$(1)) -name 'CVS' -o -name '.svn' -o -name '.#*' -o -name '*~'| $(XARGS) rm -rf
+	@( \
+		find $$(IDIR_$(1)) -name lib\*.so\* -or -name \*.ko | awk -F/ '{ print $$$$NF }'; \
+		for file in $$(patsubst %,$(PKG_INFO_DIR)/%.provides,$$(IDEPEND_$(1))); do \
+			if [ -f "$$$$file" ]; then \
+				cat $$$$file; \
+			fi; \
+		done; $(Package/$(1)/extra_provides) \
+	) | sort -u > $(PKG_INFO_DIR)/$(1).provides
+	$(if $(PROVIDES),@for pkg in $(PROVIDES); do cp $(PKG_INFO_DIR)/$(1).provides $(PKG_INFO_DIR)/$$$$pkg.provides; done)
+	$(CheckDependencies)
+
+	$(RSTRIP) $$(IDIR_$(1))
+	(cd $$(IDIR_$(1))/CONTROL; \
+		( \
+			echo "$$$$CONTROL"; \
+			printf "Description: "; echo "$$$$DESCRIPTION" | sed -e 's,^[[:space:]]*, ,g'; \
+		) > control; \
+		chmod 644 control; \
+		( \
+			echo "#!/bin/sh"; \
+			echo "[ \"\$$$${IPKG_NO_SCRIPT}\" = \"1\" ] && exit 0"; \
+			echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
+			echo "default_postinst \$$$$0 \$$$$@"; \
+		) > postinst; \
+		( \
+			echo "#!/bin/sh"; \
+			echo ". \$$$${IPKG_INSTROOT}/lib/functions.sh"; \
+			echo "default_prerm \$$$$0 \$$$$@"; \
+		) > prerm; \
+		chmod 0755 postinst prerm; \
+		$($(1)_COMMANDS) \
+	)
+
+    ifneq ($$(KEEP_$(1)),)
+		@( \
+			keepfiles=""; \
+			for x in $$(KEEP_$(1)); do \
+				[ -f "$$(IDIR_$(1))/$$$$x" ] || keepfiles="$$$${keepfiles:+$$$$keepfiles }$$$$x"; \
+			done; \
+			[ -z "$$$$keepfiles" ] || { \
+				mkdir -p $$(IDIR_$(1))/lib/upgrade/keep.d; \
+				for x in $$$$keepfiles; do echo $$$$x >> $$(IDIR_$(1))/lib/upgrade/keep.d/$(1); done; \
+			}; \
+		)
+    endif
+
+	$(INSTALL_DIR) $$(PDIR_$(1))
+	$(IPKG_BUILD) $$(IDIR_$(1)) $$(PDIR_$(1))
+	@[ -f $$(IPKG_$(1)) ]
+
+    $(1)-clean:
+	$$(if $$(call opkg_package_files,$(1)),rm -f $$(call opkg_package_files,$(1)))
+
+    clean: $(1)-clean
+
+  endef
+endif
diff --git a/include/package-seccomp.mk b/include/package-seccomp.mk
new file mode 100644
index 0000000000..fa49617d41
--- /dev/null
+++ b/include/package-seccomp.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+PKG_CONFIG_DEPENDS+= CONFIG_KERNEL_SECCOMP
+
+ifeq ($(CONFIG_KERNEL_SECCOMP),y)
+  define InstallSeccomp
+	$(INSTALL_DIR) $(1)/etc/seccomp
+	$(INSTALL_DATA) $(2) $(1)/etc/seccomp/
+  endef
+endif
diff --git a/include/package.mk b/include/package.mk
new file mode 100644
index 0000000000..99e401e859
--- /dev/null
+++ b/include/package.mk
@@ -0,0 +1,320 @@
+#
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+__package_mk:=1
+
+all: $(if $(DUMP),dumpinfo,compile)
+
+PKG_BUILD_DIR ?= $(BUILD_DIR)/$(PKG_NAME)$(if $(PKG_VERSION),-$(PKG_VERSION))
+PKG_INSTALL_DIR ?= $(PKG_BUILD_DIR)/ipkg-install
+PKG_MD5SUM ?= unknown
+PKG_BUILD_PARALLEL ?=
+PKG_USE_MIPS16 ?= 1
+PKG_IREMAP ?= 1
+
+ifneq ($(CONFIG_PKG_BUILD_USE_JOBSERVER),)
+  MAKE_J:=$(if $(MAKE_JOBSERVER),$(MAKE_JOBSERVER) $(if $(filter 3.% 4.0 4.1,$(MAKE_VERSION)),-j))
+else
+  MAKE_J:=-j$(CONFIG_PKG_BUILD_JOBS)
+endif
+
+ifeq ($(strip $(PKG_BUILD_PARALLEL)),0)
+PKG_JOBS?=-j1
+else
+PKG_JOBS?=$(if $(PKG_BUILD_PARALLEL)$(CONFIG_PKG_DEFAULT_PARALLEL),\
+	$(if $(CONFIG_PKG_BUILD_PARALLEL),$(MAKE_J),-j1),-j1)
+endif
+ifdef CONFIG_USE_MIPS16
+  ifeq ($(strip $(PKG_USE_MIPS16)),1)
+    TARGET_ASFLAGS_DEFAULT = $(filter-out -mips16 -minterlink-mips16,$(TARGET_CFLAGS))
+    TARGET_CFLAGS += -mips16 -minterlink-mips16
+  endif
+endif
+ifeq ($(strip $(PKG_IREMAP)),1)
+  IREMAP_CFLAGS = $(call iremap,$(PKG_BUILD_DIR),$(notdir $(PKG_BUILD_DIR)))
+  TARGET_CFLAGS += $(IREMAP_CFLAGS)
+endif
+
+include $(INCLUDE_DIR)/hardening.mk
+include $(INCLUDE_DIR)/prereq.mk
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/unpack.mk
+include $(INCLUDE_DIR)/depends.mk
+
+find_library_dependencies = $(wildcard $(patsubst %,$(STAGING_DIR)/pkginfo/%.version, \
+	$(filter-out $(BUILD_PACKAGES),$(foreach dep, \
+		$(filter-out @%, $(patsubst +%,%,$(1))), \
+		$(if $(findstring :,$(dep)), \
+			$(word 2,$(subst :,$(space),$(dep))), \
+			$(dep) \
+		) \
+	))))
+
+PKG_DIR_NAME:=$(lastword $(subst /,$(space),$(CURDIR)))
+STAMP_NO_AUTOREBUILD=$(wildcard $(PKG_BUILD_DIR)/.no_autorebuild)
+PREV_STAMP_PREPARED:=$(if $(STAMP_NO_AUTOREBUILD),$(wildcard $(PKG_BUILD_DIR)/.prepared*))
+ifneq ($(PREV_STAMP_PREPARED),)
+  STAMP_PREPARED:=$(PREV_STAMP_PREPARED)
+  CONFIG_AUTOREBUILD:=
+else
+  STAMP_PREPARED=$(PKG_BUILD_DIR)/.prepared$(if $(QUILT)$(DUMP),,_$(shell $(call find_md5,${CURDIR} $(PKG_FILE_DEPENDS),))$(call confvar,$(PKG_PREPARED_DEPENDS)))
+endif
+STAMP_CONFIGURED=$(PKG_BUILD_DIR)/.configured$(if $(DUMP),,_$(call confvar,$(PKG_CONFIG_DEPENDS)))
+STAMP_CONFIGURED_WILDCARD=$(PKG_BUILD_DIR)/.configured_*
+STAMP_BUILT:=$(PKG_BUILD_DIR)/.built
+STAMP_INSTALLED:=$(STAGING_DIR)/stamp/.$(PKG_DIR_NAME)$(if $(BUILD_VARIANT),.$(BUILD_VARIANT),)_installed
+
+STAGING_FILES_LIST:=$(PKG_DIR_NAME)$(if $(BUILD_VARIANT),.$(BUILD_VARIANT),).list
+
+define CleanStaging
+	rm -f $(STAMP_INSTALLED)
+	@-(\
+		cd "$(STAGING_DIR)"; \
+		if [ -f packages/$(STAGING_FILES_LIST) ]; then \
+			cat packages/$(STAGING_FILES_LIST) | xargs -r rm -f 2>/dev/null; \
+		fi; \
+	)
+endef
+
+ifneq ($(if $(CONFIG_SRC_TREE_OVERRIDE),$(wildcard ./git-src)),)
+  USE_GIT_TREE:=1
+  QUILT:=1
+endif
+ifdef USE_SOURCE_DIR
+  QUILT:=1
+endif
+ifneq ($(wildcard $(PKG_BUILD_DIR)/.source_dir),)
+  QUILT:=1
+endif
+
+PKG_INSTALL_STAMP:=$(PKG_INFO_DIR)/$(PKG_DIR_NAME).$(if $(BUILD_VARIANT),$(BUILD_VARIANT),default).install
+
+include $(INCLUDE_DIR)/download.mk
+include $(INCLUDE_DIR)/quilt.mk
+include $(INCLUDE_DIR)/package-defaults.mk
+include $(INCLUDE_DIR)/package-dumpinfo.mk
+include $(INCLUDE_DIR)/package-ipkg.mk
+include $(INCLUDE_DIR)/package-bin.mk
+include $(INCLUDE_DIR)/autotools.mk
+
+override MAKEFLAGS=
+CONFIG_SITE:=$(INCLUDE_DIR)/site/$(ARCH)
+CUR_MAKEFILE:=$(filter-out Makefile,$(firstword $(MAKEFILE_LIST)))
+SUBMAKE:=$(NO_TRACE_MAKE) $(if $(CUR_MAKEFILE),-f $(CUR_MAKEFILE))
+PKG_CONFIG_PATH=$(STAGING_DIR)/usr/lib/pkgconfig:$(STAGING_DIR)/usr/share/pkgconfig
+unexport QUIET CONFIG_SITE
+
+ifeq ($(DUMP)$(filter prereq clean refresh update,$(MAKECMDGOALS)),)
+  ifneq ($(if $(QUILT),,$(CONFIG_AUTOREBUILD)),)
+    define Build/Autoclean
+      $(PKG_BUILD_DIR)/.dep_files: $(STAMP_PREPARED)
+      $(call rdep,${CURDIR} $(PKG_FILE_DEPENDS),$(STAMP_PREPARED),$(PKG_BUILD_DIR)/.dep_files,-x "*/.dep_*")
+      $(if $(filter prepare,$(MAKECMDGOALS)),,$(call rdep,$(PKG_BUILD_DIR),$(STAMP_BUILT),,-x "*/.dep_*" -x "*/ipkg*"))
+    endef
+  endif
+endif
+
+define Download/default
+  FILE:=$(PKG_SOURCE)
+  URL:=$(PKG_SOURCE_URL)
+  SUBDIR:=$(PKG_SOURCE_SUBDIR)
+  PROTO:=$(PKG_SOURCE_PROTO)
+  $(if $(PKG_SOURCE_MIRROR),MIRROR:=$(filter 1,$(PKG_MIRROR)))
+  $(if $(PKG_MIRROR_MD5SUM),MIRROR_MD5SUM:=$(PKG_MIRROR_MD5SUM))
+  VERSION:=$(PKG_SOURCE_VERSION)
+  MD5SUM:=$(PKG_MD5SUM)
+endef
+
+ifdef USE_GIT_TREE
+  define Build/Prepare/Default
+	mkdir -p $(PKG_BUILD_DIR)
+	ln -s $(CURDIR)/git-src $(PKG_BUILD_DIR)/.git
+	( cd $(PKG_BUILD_DIR); git checkout .)
+  endef
+endif
+ifdef USE_SOURCE_DIR
+  define Build/Prepare/Default
+	rm -rf $(PKG_BUILD_DIR)
+	$(if $(wildcard $(USE_SOURCE_DIR)/*),,@echo "Error: USE_SOURCE_DIR=$(USE_SOURCE_DIR) path not found"; false)
+	ln -snf $(USE_SOURCE_DIR) $(PKG_BUILD_DIR)
+	touch $(PKG_BUILD_DIR)/.source_dir
+  endef
+endif
+
+define Build/Exports/Default
+  $(1) : export ACLOCAL_INCLUDE=$$(foreach p,$$(wildcard $$(STAGING_DIR)/usr/share/aclocal $$(STAGING_DIR)/usr/share/aclocal-* $$(STAGING_DIR)/host/share/aclocal $$(STAGING_DIR)/host/share/aclocal-*),-I $$(p))
+  $(1) : export STAGING_PREFIX=$$(STAGING_DIR)/usr
+  $(1) : export PATH=$$(TARGET_PATH_PKG)
+  $(1) : export CONFIG_SITE:=$$(CONFIG_SITE)
+  $(1) : export PKG_CONFIG_PATH:=$$(PKG_CONFIG_PATH)
+  $(1) : export PKG_CONFIG_LIBDIR:=$$(PKG_CONFIG_PATH)
+  $(1) : export CCACHE_DIR:=$(STAGING_DIR)/ccache
+endef
+Build/Exports=$(Build/Exports/Default)
+
+define Build/DefaultTargets
+  $(if $(QUILT),$(Build/Quilt))
+  $(if $(USE_SOURCE_DIR)$(USE_GIT_TREE),,$(if $(strip $(PKG_SOURCE_URL)),$(call Download,default)))
+  $(call Build/Autoclean)
+
+  download:
+	$(foreach hook,$(Hooks/Download),
+		$(call $(hook))$(sep)
+	)
+
+  $(STAMP_PREPARED) : export PATH=$$(TARGET_PATH_PKG)
+  $(STAMP_PREPARED): $(STAMP_PREPARED_DEPENDS)
+	@-rm -rf $(PKG_BUILD_DIR)
+	@mkdir -p $(PKG_BUILD_DIR)
+	$(foreach hook,$(Hooks/Prepare/Pre),$(call $(hook))$(sep))
+	$(Build/Prepare)
+	$(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
+	touch $$@
+
+  $(call Build/Exports,$(STAMP_CONFIGURED))
+  $(STAMP_CONFIGURED): $(STAMP_PREPARED) $(STAMP_CONFIGURED_DEPENDS)
+	$(CleanStaging)
+	$(foreach hook,$(Hooks/Configure/Pre),$(call $(hook))$(sep))
+	$(Build/Configure)
+	$(foreach hook,$(Hooks/Configure/Post),$(call $(hook))$(sep))
+	rm -f $(STAMP_CONFIGURED_WILDCARD)
+	touch $$@
+
+  $(call Build/Exports,$(STAMP_BUILT))
+  $(STAMP_BUILT): $(STAMP_CONFIGURED) $(STAMP_BUILT_DEPENDS)
+	$(foreach hook,$(Hooks/Compile/Pre),$(call $(hook))$(sep))
+	$(Build/Compile)
+	$(foreach hook,$(Hooks/Compile/Post),$(call $(hook))$(sep))
+	$(Build/Install)
+	$(foreach hook,$(Hooks/Install/Post),$(call $(hook))$(sep))
+	touch $$@
+
+  $(STAMP_INSTALLED) : export PATH=$$(TARGET_PATH_PKG)
+  $(STAMP_INSTALLED): $(STAMP_BUILT)
+	rm -rf $(TMP_DIR)/stage-$(PKG_DIR_NAME)
+	mkdir -p $(TMP_DIR)/stage-$(PKG_DIR_NAME)/host $(STAGING_DIR)/packages $(STAGING_DIR_HOST)/packages
+	$(foreach hook,$(Hooks/InstallDev/Pre),\
+		$(call $(hook),$(TMP_DIR)/stage-$(PKG_DIR_NAME),$(TMP_DIR)/stage-$(PKG_DIR_NAME)/host)$(sep)\
+	)
+	$(call Build/InstallDev,$(TMP_DIR)/stage-$(PKG_DIR_NAME),$(TMP_DIR)/stage-$(PKG_DIR_NAME)/host)
+	$(foreach hook,$(Hooks/InstallDev/Post),\
+		$(call $(hook),$(TMP_DIR)/stage-$(PKG_DIR_NAME),$(TMP_DIR)/stage-$(PKG_DIR_NAME)/host)$(sep)\
+	)
+	if [ -f $(STAGING_DIR)/packages/$(STAGING_FILES_LIST) ]; then \
+		$(SCRIPT_DIR)/clean-package.sh \
+			"$(STAGING_DIR)/packages/$(STAGING_FILES_LIST)" \
+			"$(STAGING_DIR)"; \
+	fi
+	if [ -d $(TMP_DIR)/stage-$(PKG_DIR_NAME) ]; then \
+		(cd $(TMP_DIR)/stage-$(PKG_DIR_NAME); find ./ > $(TMP_DIR)/stage-$(PKG_DIR_NAME).files); \
+		$(call locked, \
+			mv $(TMP_DIR)/stage-$(PKG_DIR_NAME).files $(STAGING_DIR)/packages/$(STAGING_FILES_LIST) && \
+			$(CP) $(TMP_DIR)/stage-$(PKG_DIR_NAME)/* $(STAGING_DIR)/; \
+		,staging-dir); \
+	fi
+	rm -rf $(TMP_DIR)/stage-$(PKG_DIR_NAME)
+	touch $$@
+
+  ifdef Build/InstallDev
+    compile: $(STAMP_INSTALLED)
+  endif
+
+  define Build/DefaultTargets
+  endef
+
+  prepare: $(STAMP_PREPARED)
+  configure: $(STAMP_CONFIGURED)
+  dist: $(STAMP_CONFIGURED)
+  distcheck: $(STAMP_CONFIGURED)
+endef
+
+define Build/IncludeOverlay
+  $(eval -include $(wildcard $(TOPDIR)/overlay/*/$(PKG_DIR_NAME).mk))
+  define Build/IncludeOverlay
+  endef
+endef
+
+define BuildPackage
+  $(Build/IncludeOverlay)
+  $(eval $(Package/Default))
+  $(eval $(Package/$(1)))
+
+ifdef DESCRIPTION
+$$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description)
+endif
+
+ifndef Package/$(1)/description
+define Package/$(1)/description
+	$(TITLE)
+endef
+endif
+
+  BUILD_PACKAGES += $(1)
+  $(STAMP_PREPARED): $$(if $(QUILT)$(DUMP),,$(call find_library_dependencies,$(DEPENDS)))
+
+  $(foreach FIELD, TITLE CATEGORY SECTION VERSION,
+    ifeq ($($(FIELD)),)
+      $$(error Package/$(1) is missing the $(FIELD) field)
+    endif
+  )
+
+  $(if $(DUMP), \
+    $(Dumpinfo/Package), \
+    $(foreach target, \
+      $(if $(Package/$(1)/targets),$(Package/$(1)/targets), \
+        $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \
+      ), $(BuildTarget/$(target)) \
+    ) \
+  )
+  $(if $(PKG_HOST_ONLY)$(DUMP),,$(call Build/DefaultTargets,$(1)))
+endef
+
+define pkg_install_files
+	$(foreach install_file,$(1),$(INSTALL_DIR) $(3)/`dirname $(install_file)`; $(INSTALL_DATA) $(2)/$(install_file) $(3)/`dirname $(install_file)`;)
+endef
+
+define pkg_install_bin
+	$(foreach install_apps,$(1),$(INSTALL_DIR) $(3)/`dirname $(install_apps)`; $(INSTALL_BIN) $(2)/$(install_apps) $(3)/`dirname $(install_apps)`;)
+endef
+
+Build/Prepare=$(call Build/Prepare/Default,)
+Build/Configure=$(call Build/Configure/Default,)
+Build/Compile=$(call Build/Compile/Default,)
+Build/Install=$(if $(PKG_INSTALL),$(call Build/Install/Default,))
+Build/Dist=$(call Build/Dist/Default,)
+Build/DistCheck=$(call Build/DistCheck/Default,)
+
+.NOTPARALLEL:
+
+.PHONY: prepare-package-install
+prepare-package-install:
+	@mkdir -p $(PKG_INFO_DIR)
+	@touch $(PKG_INSTALL_STAMP).clean
+	@echo "$(filter-out essential nonshared,$(PKG_FLAGS))" > $(PKG_INSTALL_STAMP).flags
+
+$(PACKAGE_DIR):
+	mkdir -p $@
+	
+dumpinfo:
+download:
+prepare:
+configure:
+compile: prepare-package-install
+install: compile
+
+clean: FORCE
+	$(CleanStaging)
+	$(call Build/UninstallDev,$(STAGING_DIR),$(STAGING_DIR_HOST))
+	$(Build/Clean)
+	rm -f $(STAGING_DIR)/packages/$(STAGING_FILES_LIST) $(STAGING_DIR_HOST)/packages/$(STAGING_FILES_LIST)
+	rm -rf $(PKG_BUILD_DIR)
+
+dist:
+	$(Build/Dist)
+
+distcheck:
+	$(Build/DistCheck)
diff --git a/include/prereq-build.mk b/include/prereq-build.mk
new file mode 100644
index 0000000000..ed652ca9a7
--- /dev/null
+++ b/include/prereq-build.mk
@@ -0,0 +1,176 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/prereq.mk
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+SHELL:=sh
+PKG_NAME:=Build dependency
+
+
+# Required for the toolchain
+$(eval $(call TestHostCommand,working-make, \
+	Please install GNU make v3.81 or later. (This version has bugs), \
+	$(MAKE) -v | grep -E 'Make (3\.8[1-9]|3\.9[0-9]|[4-9]\.)'))
+
+$(eval $(call TestHostCommand,case-sensitive-fs, \
+	LEDE can only be built on a case-sensitive filesystem, \
+	rm -f $(TMP_DIR)/test.*; touch $(TMP_DIR)/test.fs; \
+		test ! -f $(TMP_DIR)/test.FS))
+
+$(eval $(call TestHostCommand,proper-umask, \
+	Please build with umask 022 - other values produce broken packages, \
+	umask | grep -xE 00[012][012]))
+
+$(eval $(call SetupHostCommand,gcc, \
+	Please install the GNU C Compiler (gcc), \
+	$(CC) --version | grep gcc, \
+	gcc --version | grep gcc, \
+	gcc49 --version | grep gcc, \
+	gcc48 --version | grep gcc, \
+	gcc47 --version | grep gcc, \
+	gcc46 --version | grep gcc, \
+	gcc --version | grep Apple.LLVM ))
+
+$(eval $(call TestHostCommand,working-gcc, \
+	Please reinstall the GNU C Compiler - it appears to be broken, \
+	echo 'int main(int argc, char **argv) { return 0; }' | \
+		gcc -x c -o $(TMP_DIR)/a.out -))
+
+$(eval $(call SetupHostCommand,g++, \
+	Please install the GNU C++ Compiler (g++), \
+	$(CXX) --version | grep g++, \
+	g++ --version | grep g++, \
+	g++49 --version | grep g++, \
+	g++48 --version | grep g++, \
+	g++47 --version | grep g++, \
+	g++46 --version | grep g++, \
+	g++ --version | grep Apple.LLVM ))
+
+$(eval $(call TestHostCommand,working-g++, \
+	Please reinstall the GNU C++ Compiler - it appears to be broken, \
+	echo 'int main(int argc, char **argv) { return 0; }' | \
+		g++ -x c++ -o $(TMP_DIR)/a.out - -lstdc++ && \
+		$(TMP_DIR)/a.out))
+
+$(eval $(call TestHostCommand,ncurses, \
+	Please install ncurses. (Missing libncurses.so or ncurses.h), \
+	echo 'int main(int argc, char **argv) { initscr(); return 0; }' | \
+		gcc -include ncurses.h -x c -o $(TMP_DIR)/a.out - -lncurses))
+
+ifeq ($(HOST_OS),Linux)
+  zlib_link_flags := -Wl,-Bstatic -lz -Wl,-Bdynamic
+else
+  zlib_link_flags := -lz
+endif
+
+$(eval $(call TestHostCommand,zlib, \
+	Please install a static zlib. (Missing libz.a or zlib.h), \
+	echo 'int main(int argc, char **argv) { gzdopen(0, "rb"); return 0; }' | \
+		gcc -include zlib.h -x c -o $(TMP_DIR)/a.out - $(zlib_link_flags)))
+
+# Xcode deprecated openssl, MacPorts doesn't work nicely for other packages
+ifneq ($(HOST_OS),Darwin)
+$(eval $(call TestHostCommand,libssl, \
+	Please install the openssl library (with development headers), \
+	echo 'int main(int argc, char **argv) { SSL_library_init(); return 0; }' | \
+		gcc $(HOST_CFLAGS) -include openssl/ssl.h -x c -o $(TMP_DIR)/a.out - -lcrypto -lssl $(HOST_LDFLAGS)))
+endif
+
+$(eval $(call TestHostCommand,perl-thread-queue, \
+	Please install the Perl Thread::Queue module, \
+	perl -MThread::Queue -e 1))
+
+
+$(eval $(call SetupHostCommand,tar,Please install GNU 'tar', \
+	gtar --version 2>&1 | grep GNU, \
+	gnutar --version 2>&1 | grep GNU, \
+	tar --version 2>&1 | grep GNU))
+
+$(eval $(call SetupHostCommand,find,Please install GNU 'find', \
+	gfind --version 2>&1 | grep GNU, \
+	find --version 2>&1 | grep GNU))
+
+$(eval $(call SetupHostCommand,bash,Please install GNU 'bash', \
+	bash --version 2>&1 | grep GNU))
+
+$(eval $(call SetupHostCommand,patch,Please install GNU 'patch', \
+	gpatch --version 2>&1 | grep 'Free Software Foundation', \
+	patch --version 2>&1 | grep 'Free Software Foundation'))
+
+$(eval $(call SetupHostCommand,diff,Please install diffutils, \
+	gdiff --version 2>&1 | grep diff, \
+	diff --version 2>&1 | grep diff))
+
+$(eval $(call SetupHostCommand,cp,Please install GNU fileutils, \
+	gcp --help 2>&1 | grep 'Copy SOURCE', \
+	cp --help 2>&1 | grep 'Copy SOURCE'))
+
+$(eval $(call SetupHostCommand,seq,, \
+	gseq --version, \
+	seq --version))
+
+$(eval $(call SetupHostCommand,awk,Please install GNU 'awk', \
+	gawk --version 2>&1 | grep GNU, \
+	awk --version 2>&1 | grep GNU))
+
+$(eval $(call SetupHostCommand,grep,Please install GNU 'grep', \
+	ggrep --version 2>&1 | grep GNU, \
+	grep --version 2>&1 | grep GNU))
+
+$(eval $(call SetupHostCommand,getopt, \
+	Please install an extended getopt version that supports --long, \
+	gnugetopt -o t --long test -- --test | grep '^ *--test *--', \
+	/usr/local/bin/getopt -o t --long test -- --test | grep '^ *--test *--', \
+	getopt -o t --long test -- --test | grep '^ *--test *--'))
+
+$(eval $(call SetupHostCommand,stat,Cannot find a file stat utility, \
+	gnustat -c%s $(TMP_DIR)/.host.mk, \
+	gstat -c%s $(TMP_DIR)/.host.mk, \
+	stat -c%s $(TMP_DIR)/.host.mk))
+
+$(eval $(call SetupHostCommand,md5sum,, \
+	gmd5sum /dev/null | grep d41d8cd98f00b204e9800998ecf8427e, \
+	md5sum /dev/null | grep d41d8cd98f00b204e9800998ecf8427e, \
+	$(SCRIPT_DIR)/md5sum /dev/null | grep d41d8cd98f00b204e9800998ecf8427e))
+
+$(eval $(call SetupHostCommand,unzip,Please install 'unzip', \
+	unzip 2>&1 | grep zipfile, \
+	unzip))
+
+$(eval $(call SetupHostCommand,bzip2,Please install 'bzip2', \
+	bzip2 --version </dev/null))
+
+$(eval $(call SetupHostCommand,wget,Please install GNU 'wget', \
+	wget --version | grep GNU))
+
+$(eval $(call SetupHostCommand,perl,Please install Perl 5.x, \
+	perl --version | grep "perl.*v5"))
+
+$(eval $(call SetupHostCommand,python,Please install Python 2.x, \
+	python2.7 -V 2>&1 | grep Python, \
+	python2 -V 2>&1 | grep Python, \
+	python -V 2>&1 | grep Python))
+
+$(eval $(call SetupHostCommand,git,Please install Git (git-core) >= 1.7.12.2, \
+	git --exec-path | xargs -I % -- grep -q -- --recursive %/git-submodule))
+
+$(eval $(call SetupHostCommand,file,Please install the 'file' package, \
+	file --version 2>&1 | grep file))
+
+ifneq ($(HOST_OS),Darwin)
+$(eval $(call SetupHostCommand,openssl,Please install the 'openssl' utility, \
+	openssl version | grep '\(OpenSSL\|LibreSSL\)'))
+endif
+
+
+# Install ldconfig stub
+$(eval $(call TestHostCommand,ldconfig-stub,Failed to install stub, \
+	touch $(STAGING_DIR_HOST)/bin/ldconfig && \
+	chmod +x $(STAGING_DIR_HOST)/bin/ldconfig))
diff --git a/include/prereq.mk b/include/prereq.mk
new file mode 100644
index 0000000000..6cb590e360
--- /dev/null
+++ b/include/prereq.mk
@@ -0,0 +1,108 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifneq ($(__prereq_inc),1)
+__prereq_inc:=1
+
+prereq:
+	if [ -f $(TMP_DIR)/.prereq-error ]; then \
+		echo; \
+		cat $(TMP_DIR)/.prereq-error; \
+		rm -f $(TMP_DIR)/.prereq-error; \
+		echo; \
+		false; \
+	fi
+
+.SILENT: prereq
+endif
+
+PREREQ_PREV=
+
+# 1: display name
+# 2: error message
+define Require
+  export PREREQ_CHECK=1
+  ifeq ($$(CHECK_$(1)),)
+    prereq: prereq-$(1)
+
+    prereq-$(1): $(if $(PREREQ_PREV),prereq-$(PREREQ_PREV)) FORCE
+		printf "Checking '$(1)'... "
+		if $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) >/dev/null 2>/dev/null; then \
+			echo 'ok.'; \
+		else \
+			echo 'failed.'; \
+			echo "$(PKG_NAME): $(strip $(2))" >> $(TMP_DIR)/.prereq-error; \
+		fi
+
+    check-$(1): FORCE
+	  $(call Require/$(1))
+    CHECK_$(1):=1
+
+    .SILENT: prereq-$(1) check-$(1)
+    .NOTPARALLEL:
+  endif
+
+  PREREQ_PREV=$(1)
+endef
+
+
+define RequireCommand
+  define Require/$(1)
+    which $(1)
+  endef
+
+  $$(eval $$(call Require,$(1),$(2)))
+endef
+
+define RequireHeader
+  define Require/$(1)
+    [ -e "$(1)" ]
+  endef
+
+  $$(eval $$(call Require,$(1),$(2)))
+endef
+
+define QuoteHostCommand
+'$(subst ','"'"',$(strip $(1)))'
+endef
+
+# 1: display name
+# 2: failure message
+# 3: test
+define TestHostCommand
+  define Require/$(1)
+	($(3)) >/dev/null 2>/dev/null
+  endef
+
+  $$(eval $$(call Require,$(1),$(2)))
+endef
+
+# 1: canonical name
+# 2: failure message
+# 3+: candidates
+define SetupHostCommand
+  define Require/$(1)
+	[ -f "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0; \
+	for cmd in $(call QuoteHostCommand,$(3)) $(call QuoteHostCommand,$(4)) \
+	           $(call QuoteHostCommand,$(5)) $(call QuoteHostCommand,$(6)) \
+	           $(call QuoteHostCommand,$(7)) $(call QuoteHostCommand,$(8)) \
+			   $(call QuoteHostCommand,$(9)); do \
+		if [ -n "$$$$$$$$cmd" ]; then \
+			bin="$$$$$$$$(PATH="$(subst $(space),:,$(filter-out $(STAGING_DIR_HOST)/%,$(subst :,$(space),$(PATH))))" \
+				which "$$$$$$$${cmd%% *}")"; \
+			if [ -x "$$$$$$$$bin" ] && eval "$$$$$$$$cmd" >/dev/null 2>/dev/null; then \
+				mkdir -p "$(STAGING_DIR_HOST)/bin"; \
+				ln -sf "$$$$$$$$bin" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \
+				exit 0; \
+			fi; \
+		fi; \
+	done; \
+	exit 1
+  endef
+
+  $$(eval $$(call Require,$(1),$(if $(2),$(2),Missing $(1) command)))
+endef
diff --git a/include/quilt.mk b/include/quilt.mk
new file mode 100644
index 0000000000..cd392a7c5d
--- /dev/null
+++ b/include/quilt.mk
@@ -0,0 +1,171 @@
+#
+# Copyright (C) 2007-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+ifneq ($(if $(DUMP),1,$(__quilt_inc)),1)
+__quilt_inc:=1
+
+ifeq ($(TARGET_BUILD),1)
+  PKG_BUILD_DIR:=$(LINUX_DIR)
+endif
+PATCH_DIR?=./patches
+FILES_DIR?=./files
+HOST_PATCH_DIR?=$(PATCH_DIR)
+HOST_FILES_DIR?=$(FILES_DIR)
+
+ifeq ($(MAKECMDGOALS),refresh)
+  override QUILT=1
+  override HOST_QUILT=1
+endif
+
+QUILT_CMD:=quilt --quiltrc=-
+
+define filter_series
+sed -e s,\\\#.*,, $(1) | grep -E \[a-zA-Z0-9\]
+endef
+
+define PatchDir/Quilt
+	@mkdir -p "$(1)/patches$(if $(3),/$(patsubst %/,%,$(3)))"
+	@if [ -s "$(2)/series" ]; then \
+		mkdir -p "$(1)/patches/$(3)"; \
+		cp "$(2)/series" "$(1)/patches/$(3)"; \
+	fi
+	@for patch in $$$$( (cd "$(2)" && if [ -f series ]; then $(call filter_series,series); else ls | sort; fi; ) 2>/dev/null ); do ( \
+		cp "$(2)/$$$$patch" "$(1)/patches/$(3)"; \
+		echo "$(3)$$$$patch" >> "$(1)/patches/series"; \
+	); done
+	$(if $(3),@echo $(3) >> "$(1)/patches/.subdirs")
+endef
+
+define PatchDir/Default
+	@if [ -d "$(2)" ] && [ "$$$$(ls $(2) | wc -l)" -gt 0 ]; then \
+		export PATCH="$(PATCH)"; \
+		if [ -s "$(2)/series" ]; then \
+			$(call filter_series,$(2)/series) | xargs -n1 \
+				$(KPATCH) "$(1)" "$(2)"; \
+		else \
+			$(KPATCH) "$(1)" "$(2)"; \
+		fi; \
+	fi
+endef
+
+define PatchDir
+$(call PatchDir/$(if $(strip $(QUILT)),Quilt,Default),$(strip $(1)),$(strip $(2)),$(strip $(3)))
+endef
+
+define HostPatchDir
+$(call PatchDir/$(if $(strip $(HOST_QUILT)),Quilt,Default),$(strip $(1)),$(strip $(2)),$(strip $(3)))
+endef
+
+ifneq ($(PKG_BUILD_DIR),)
+  QUILT?=$(if $(wildcard $(PKG_BUILD_DIR)/.quilt_used),y)
+  ifneq ($(QUILT),)
+    STAMP_CHECKED:=$(PKG_BUILD_DIR)/.quilt_checked
+    override CONFIG_AUTOREBUILD=
+    quilt-check: $(STAMP_CHECKED)
+  endif
+endif
+
+ifneq ($(HOST_BUILD_DIR),)
+  HOST_QUILT?=$(if $(findstring command,$(origin QUILT)),$(QUILT),$(if $(wildcard $(HOST_BUILD_DIR)/.quilt_used),y))
+  ifneq ($(HOST_QUILT),)
+    HOST_STAMP_CHECKED:=$(HOST_BUILD_DIR)/.quilt_checked
+    override CONFIG_AUTOREBUILD=
+    host-quilt-check: $(HOST_STAMP_CHECKED)
+  endif
+endif
+
+define Host/Patch/Default
+	$(if $(HOST_QUILT),rm -rf $(HOST_BUILD_DIR)/patches; mkdir -p $(HOST_BUILD_DIR)/patches)
+	$(call HostPatchDir,$(HOST_BUILD_DIR),$(HOST_PATCH_DIR),)
+	$(if $(HOST_QUILT),touch $(HOST_BUILD_DIR)/.quilt_used)
+endef
+
+define Build/Patch/Default
+	$(if $(QUILT),rm -rf $(PKG_BUILD_DIR)/patches; mkdir -p $(PKG_BUILD_DIR)/patches)
+	$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_DIR),)
+	$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
+endef
+
+kernel_files=$(foreach fdir,$(GENERIC_FILES_DIR) $(FILES_DIR),$(fdir)/.)
+define Kernel/Patch/Default
+	$(if $(QUILT),rm -rf $(PKG_BUILD_DIR)/patches; mkdir -p $(PKG_BUILD_DIR)/patches)
+	$(if $(kernel_files),$(CP) $(kernel_files) $(LINUX_DIR)/)
+	find $(LINUX_DIR)/ -name \*.rej -or -name \*.orig | $(XARGS) rm -f
+	$(call PatchDir,$(PKG_BUILD_DIR),$(GENERIC_PATCH_DIR),generic/)
+	$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_DIR),platform/)
+endef
+
+define Quilt/RefreshDir
+	mkdir -p $(2)
+	-rm -f $(2)/* 2>/dev/null >/dev/null
+	@( \
+		for patch in $$$$($(if $(3),grep "^$(3)",cat) $(1)/patches/series | awk '{print $$$$1}'); do \
+			$(CP) -v "$(1)/patches/$$$$patch" $(2); \
+		done; \
+	)
+endef
+
+define Quilt/Refresh/Host
+	$(call Quilt/RefreshDir,$(HOST_BUILD_DIR),$(PATCH_DIR))
+endef
+
+define Quilt/Refresh/Package
+	$(call Quilt/RefreshDir,$(PKG_BUILD_DIR),$(PATCH_DIR))
+endef
+
+define Quilt/Refresh/Kernel
+	@[ -z "$$(grep -v '^generic/' $(PKG_BUILD_DIR)/patches/series | grep -v '^platform/')" ] || { \
+		echo "All kernel patches must start with either generic/ or platform/"; \
+		false; \
+	}
+	$(call Quilt/RefreshDir,$(PKG_BUILD_DIR),$(GENERIC_PATCH_DIR),generic/)
+	$(call Quilt/RefreshDir,$(PKG_BUILD_DIR),$(PATCH_DIR),platform/)
+endef
+
+define Quilt/Template
+  $($(2)STAMP_CONFIGURED): $($(2)STAMP_CHECKED)
+  $(if $(NO_RECONFIGURE),$($(2)STAMP_BUILT),$($(2)STAMP_CONFIGURED)): FORCE
+  $($(2)STAMP_CHECKED): $($(2)STAMP_PREPARED)
+	if [ -s "$(1)/patches/series" ]; then \
+		(cd "$(1)"; \
+			if $(QUILT_CMD) next >/dev/null 2>&1; then \
+				$(QUILT_CMD) push -a; \
+			else \
+				$(QUILT_CMD) top >/dev/null 2>&1; \
+			fi \
+		); \
+	fi
+	touch "$$@"
+
+  $(3)quilt-check: $($(2)STAMP_PREPARED) FORCE
+	@[ -f "$(1)/.quilt_used" ] || { \
+		echo "The source directory was not unpacked using quilt. Please rebuild with QUILT=1"; \
+		false; \
+	}
+	@[ -f "$(1)/patches/series" ] || { \
+		echo "The source directory contains no quilt patches."; \
+		false; \
+	}
+	@[ -n "$$$$(ls $(1)/patches/series)" -o "$$$$(cat $(1)/patches/series | md5sum)" = "$$(sort $(1)/patches/series | md5sum)" ] || { \
+		echo "The patches are not sorted in the right order. Please fix."; \
+		false; \
+	}
+
+  $(3)refresh: $(3)quilt-check
+	@cd "$(1)"; $(QUILT_CMD) pop -a -f >/dev/null 2>/dev/null
+	@cd "$(1)"; while $(QUILT_CMD) next 2>/dev/null >/dev/null && $(QUILT_CMD) push; do \
+		QUILT_DIFF_OPTS="-p" $(QUILT_CMD) refresh -p ab --no-index --no-timestamps; \
+	done; ! $(QUILT_CMD) next 2>/dev/null >/dev/null
+	$(Quilt/Refresh/$(4))
+	
+  $(3)update: $(3)quilt-check
+	$(Quilt/Refresh/$(4))
+endef
+
+Build/Quilt=$(call Quilt/Template,$(PKG_BUILD_DIR),,,$(if $(TARGET_BUILD),Kernel,Package))
+Host/Quilt=$(call Quilt/Template,$(HOST_BUILD_DIR),HOST_,host-,Host)
+
+endif
diff --git a/include/rootfs.mk b/include/rootfs.mk
new file mode 100644
index 0000000000..90d70a11f2
--- /dev/null
+++ b/include/rootfs.mk
@@ -0,0 +1,80 @@
+include $(INCLUDE_DIR)/feeds.mk
+
+ifdef CONFIG_USE_MKLIBS
+  define mklibs
+	rm -rf $(TMP_DIR)/mklibs-progs $(TMP_DIR)/mklibs-out
+	# first find all programs and add them to the mklibs list
+	find $(STAGING_DIR_ROOT) -type f -perm /100 -exec \
+		file -r -N -F '' {} + | \
+		awk ' /executable.*dynamically/ { print $$1 }' > $(TMP_DIR)/mklibs-progs
+	# find all loadable objects that are not regular libraries and add them to the list as well
+	find $(STAGING_DIR_ROOT) -type f -name \*.so\* -exec \
+		file -r -N -F '' {} + | \
+		awk ' /shared object/ { print $$1 }' > $(TMP_DIR)/mklibs-libs
+	mkdir -p $(TMP_DIR)/mklibs-out
+	$(STAGING_DIR_HOST)/bin/mklibs -D \
+		-d $(TMP_DIR)/mklibs-out \
+		--sysroot $(STAGING_DIR_ROOT) \
+		`cat $(TMP_DIR)/mklibs-libs | sed 's:/*[^/]\+/*$$::' | uniq | sed 's:^$(STAGING_DIR_ROOT):-L :'` \
+		--ldlib $(patsubst $(STAGING_DIR_ROOT)/%,/%,$(firstword $(wildcard \
+			$(foreach name,ld-uClibc.so.* ld-linux.so.* ld-*.so ld-musl-*.so.*, \
+			  $(STAGING_DIR_ROOT)/lib/$(name) \
+			)))) \
+		--target $(REAL_GNU_TARGET_NAME) \
+		`cat $(TMP_DIR)/mklibs-progs $(TMP_DIR)/mklibs-libs` 2>&1
+	$(RSTRIP) $(TMP_DIR)/mklibs-out
+	for lib in `ls $(TMP_DIR)/mklibs-out/*.so.* 2>/dev/null`; do \
+		LIB="$${lib##*/}"; \
+		DEST="`ls "$(1)/lib/$$LIB" "$(1)/usr/lib/$$LIB" 2>/dev/null`"; \
+		[ -n "$$DEST" ] || continue; \
+		echo "Copying stripped library $$lib to $$DEST"; \
+		cp "$$lib" "$$DEST" || exit 1; \
+	done
+  endef
+endif
+
+# where to build (and put) .ipk packages
+opkg = \
+  IPKG_NO_SCRIPT=1 \
+  IPKG_INSTROOT=$(1) \
+  TMPDIR=$(1)/tmp \
+  $(STAGING_DIR_HOST)/bin/opkg \
+	--offline-root $(1) \
+	--force-postinstall \
+	--add-dest root:/ \
+	--add-arch all:100 \
+	--add-arch $(if $(ARCH_PACKAGES),$(ARCH_PACKAGES),$(BOARD)):200
+
+TARGET_DIR_ORIG := $(TARGET_ROOTFS_DIR)/root.orig-$(BOARD)
+
+define prepare_rootfs
+	@if [ -d $(TOPDIR)/files ]; then \
+		$(call file_copy,$(TOPDIR)/files/.,$(1)); \
+	fi
+	@mkdir -p $(1)/etc/rc.d
+	@( \
+		cd $(1); \
+		for script in ./usr/lib/opkg/info/*.postinst; do \
+			IPKG_INSTROOT=$(1) $$(which bash) $$script; \
+			ret=$$?; \
+			if [ $$ret -ne 0 ]; then \
+				echo "postinst script $$script has failed with exit code $$ret" >&2; \
+				exit 1; \
+			fi; \
+		done; \
+		for script in ./etc/init.d/*; do \
+			grep '#!/bin/sh /etc/rc.common' $$script >/dev/null || continue; \
+			IPKG_INSTROOT=$(1) $$(which bash) ./etc/rc.common $$script enable; \
+		done || true \
+	)
+	$(if $(SOURCE_DATE_EPOCH),sed -i "s/Installed-Time: .*/Installed-Time: $(SOURCE_DATE_EPOCH)/" $(1)/usr/lib/opkg/status)
+	@-find $(1) -name CVS   | $(XARGS) rm -rf
+	@-find $(1) -name .svn  | $(XARGS) rm -rf
+	@-find $(1) -name .git  | $(XARGS) rm -rf
+	@-find $(1) -name '.#*' | $(XARGS) rm -f
+	rm -f $(1)/usr/lib/opkg/lists/*
+	rm -f $(1)/usr/lib/opkg/info/*.postinst*
+	rm -f $(1)/usr/lib/opkg/info/*.prerm*
+	$(if $(CONFIG_CLEAN_IPKG),rm -rf $(1)/usr/lib/opkg)
+	$(call mklibs,$(1))
+endef
diff --git a/include/scan.awk b/include/scan.awk
new file mode 100644
index 0000000000..0f02782326
--- /dev/null
+++ b/include/scan.awk
@@ -0,0 +1,19 @@
+BEGIN { FS="/" }
+$1 ~ /^feeds/ { FEEDS[$NF]=$0 }
+$1 !~ /^feeds/ { PKGS[$NF]=$0 }
+END {
+	# Filter-out OpenWrt packages which have a feeds equivalent
+	for (pkg in PKGS)
+		if (pkg in FEEDS) {
+			print PKGS[pkg] > of
+			delete PKGS[pkg]
+		}
+	n = asort(PKGS)
+	for (i=1; i <= n; i++) {
+		print PKGS[i]
+	}
+	n = asort(FEEDS)
+	for (i=1; i <= n; i++){
+		print FEEDS[i]
+	}
+}
diff --git a/include/scan.mk b/include/scan.mk
new file mode 100644
index 0000000000..e6bc0688b7
--- /dev/null
+++ b/include/scan.mk
@@ -0,0 +1,104 @@
+include $(TOPDIR)/include/verbose.mk
+TMP_DIR:=$(TOPDIR)/tmp
+
+all: $(TMP_DIR)/.$(SCAN_TARGET)
+
+include $(TOPDIR)/include/host.mk
+
+SCAN_TARGET ?= packageinfo
+SCAN_NAME ?= package
+SCAN_DIR ?= package
+TARGET_STAMP:=$(TMP_DIR)/info/.files-$(SCAN_TARGET).stamp
+FILELIST:=$(TMP_DIR)/info/.files-$(SCAN_TARGET)-$(SCAN_COOKIE)
+OVERRIDELIST:=$(TMP_DIR)/info/.overrides-$(SCAN_TARGET)-$(SCAN_COOKIE)
+
+ifeq ($(IS_TTY),1)
+  define progress
+	printf "\033[M\r$(1)" >&2;
+  endef
+else
+  define progress
+	:;
+  endef
+endif
+
+define feedname
+$(if $(patsubst feeds/%,,$(1)),,$(word 2,$(subst /, ,$(1))))
+endef
+
+define PackageDir
+  $(TMP_DIR)/.$(SCAN_TARGET): $(TMP_DIR)/info/.$(SCAN_TARGET)-$(1)
+  $(TMP_DIR)/info/.$(SCAN_TARGET)-$(1): $(SCAN_DIR)/$(2)/Makefile $(foreach DEP,$(DEPS_$(SCAN_DIR)/$(2)/Makefile) $(SCAN_DEPS),$(wildcard $(if $(filter /%,$(DEP)),$(DEP),$(SCAN_DIR)/$(2)/$(DEP))))
+	{ \
+		$$(call progress,Collecting $(SCAN_NAME) info: $(SCAN_DIR)/$(2)) \
+		echo Source-Makefile: $(SCAN_DIR)/$(2)/Makefile; \
+		$(if $(3),echo Override: $(3),true); \
+		$(NO_TRACE_MAKE) --no-print-dir -r DUMP=1 FEED="$(call feedname,$(2))" -C $(SCAN_DIR)/$(2) $(SCAN_MAKEOPTS) 2>/dev/null || { \
+			mkdir -p "$(TOPDIR)/logs/$(SCAN_DIR)/$(2)"; \
+			$(NO_TRACE_MAKE) --no-print-dir -r DUMP=1 FEED="$(call feedname,$(2))" -C $(SCAN_DIR)/$(2) $(SCAN_MAKEOPTS) > $(TOPDIR)/logs/$(SCAN_DIR)/$(2)/dump.txt 2>&1; \
+			$$(call progress,ERROR: please fix $(SCAN_DIR)/$(2)/Makefile - see logs/$(SCAN_DIR)/$(2)/dump.txt for details\n) \
+			rm -f $$@; \
+		}; \
+		echo; \
+	} > $$@.tmp
+	mv $$@.tmp $$@
+endef
+
+$(OVERRIDELIST):
+	rm -f $(TMP_DIR)/info/.overrides-$(SCAN_TARGET)-*
+	touch $@
+
+ifeq ($(SCAN_NAME),target)
+  GREP_STRING=BuildTarget
+else
+  GREP_STRING=(Build/DefaultTargets|BuildPackage|.+Package)
+endif
+
+$(FILELIST): $(OVERRIDELIST)
+	rm -f $(TMP_DIR)/info/.files-$(SCAN_TARGET)-*
+	$(call FIND_L, $(SCAN_DIR)) $(SCAN_EXTRA) -mindepth 1 $(if $(SCAN_DEPTH),-maxdepth $(SCAN_DEPTH)) -name Makefile | xargs grep -aHE 'call $(GREP_STRING)' | sed -e 's#^$(SCAN_DIR)/##' -e 's#/Makefile:.*##' | uniq | awk -v of=$(OVERRIDELIST) -f include/scan.awk > $@
+
+$(TMP_DIR)/info/.files-$(SCAN_TARGET).mk: $(FILELIST)
+	( \
+		cat $< | awk '{print "$(SCAN_DIR)/" $$0 "/Makefile" }' | xargs grep -HE '^ *SCAN_DEPS *= *' | awk -F: '{ gsub(/^.*DEPS *= */, "", $$2); print "DEPS_" $$1 "=" $$2 }'; \
+		awk -F/ -v deps="$$DEPS" -v of="$(OVERRIDELIST)" ' \
+		BEGIN { \
+			while (getline < (of)) \
+				override[$$NF]=$$0; \
+			close(of) \
+		} \
+		{ \
+			info=$$0; \
+			gsub(/\//, "_", info); \
+			dir=$$0; \
+			pkg=""; \
+			if($$NF in override) \
+				pkg=override[$$NF]; \
+			print "$$(eval $$(call PackageDir," info "," dir "," pkg "))"; \
+		} ' < $<; \
+		true; \
+	) > $@.tmp
+	mv $@.tmp $@
+
+-include $(TMP_DIR)/info/.files-$(SCAN_TARGET).mk
+
+$(TARGET_STAMP)::
+	+( \
+		$(NO_TRACE_MAKE) $(FILELIST); \
+		MD5SUM=$$(cat $(FILELIST) $(OVERRIDELIST) | (md5sum || md5) 2>/dev/null | awk '{print $$1}'); \
+		[ -f "$@.$$MD5SUM" ] || { \
+			rm -f $@.*; \
+			touch $@.$$MD5SUM; \
+			touch $@; \
+		} \
+	)
+
+$(TMP_DIR)/.$(SCAN_TARGET): $(TARGET_STAMP)
+	$(call progress,Collecting $(SCAN_NAME) info: merging...)
+	-cat $(FILELIST) | awk '{gsub(/\//, "_", $$0);print "$(TMP_DIR)/info/.$(SCAN_TARGET)-" $$0}' | xargs cat > $@ 2>/dev/null
+	$(call progress,Collecting $(SCAN_NAME) info: done)
+	echo
+
+FORCE:
+.PHONY: FORCE
+.NOTPARALLEL:
diff --git a/include/scons.mk b/include/scons.mk
new file mode 100644
index 0000000000..2b76710542
--- /dev/null
+++ b/include/scons.mk
@@ -0,0 +1,23 @@
+export PLATFORM=posix
+
+SCONS_VARS = \
+	CC="$(TARGET_CC_NOCACHE)" \
+	CXX="$(TARGET_CXX_NOCACHE)" \
+	CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS)" \
+	CXXFLAGS="$(TARGET_CXXFLAGS) $(EXTRA_CXXFLAGS)" \
+	CPPFLAGS="$(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
+	LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS)" \
+	DESTDIR="$(PKG_INSTALL_DIR)"
+
+define Build/Configure/Default
+	(cd $(PKG_BUILD_DIR); \
+		$(SCONS_VARS) \
+		scons \
+			prefix=/usr \
+			$(SCONS_OPTIONS) \
+		install \
+	)
+endef
+
+define Build/Compile
+endef
diff --git a/include/shell.sh b/include/shell.sh
new file mode 100644
index 0000000000..6389304c24
--- /dev/null
+++ b/include/shell.sh
@@ -0,0 +1,37 @@
+getvar() {
+	eval "echo \"\${$1}\""
+}
+
+var2file() {
+	local var
+	eval "var=\"\${$1}\""
+	if [ -n "$var" ]; then echo "$var" > "$2"; fi
+}
+
+isset() {
+	local var
+	eval "var=\"\${$1}\""
+	[ -n "$var" ]
+}
+
+trapret() {(
+	local retvals="$1"; shift
+	local cmd="$1"; shift
+	for retval in $(echo $retvals); do
+		local trap_$retval=1
+	done
+	"$cmd" "$@" || {
+		local retval="$?"
+		eval "trapped=\${trap_$retval}"
+		[ -n "$trapped" ] || {
+			return $retval
+		}
+	}
+)}
+
+md5s() {
+	cat "$@" | (
+		md5sum 2>/dev/null ||
+		md5
+	) | awk '{print $1}'
+}
diff --git a/include/site/aarch64 b/include/site/aarch64
new file mode 100644
index 0000000000..c5aa9c5543
--- /dev/null
+++ b/include/site/aarch64
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=8
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=8
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=8
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=8
+ac_cv_sizeof_ssize_t=8
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=8
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=8
diff --git a/include/site/aarch64_be b/include/site/aarch64_be
new file mode 100644
index 0000000000..19e75ab991
--- /dev/null
+++ b/include/site/aarch64_be
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=8
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=8
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=8
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=8
+ac_cv_sizeof_ssize_t=8
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=8
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=8
diff --git a/include/site/arc b/include/site/arc
new file mode 100644
index 0000000000..72a3805c64
--- /dev/null
+++ b/include/site/arc
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/arm b/include/site/arm
new file mode 100644
index 0000000000..72a3805c64
--- /dev/null
+++ b/include/site/arm
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/armeb b/include/site/armeb
new file mode 100644
index 0000000000..a5626a722b
--- /dev/null
+++ b/include/site/armeb
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/i386 b/include/site/i386
new file mode 100644
index 0000000000..78f1557b79
--- /dev/null
+++ b/include/site/i386
@@ -0,0 +1,3 @@
+#!/bin/sh
+. $TOPDIR/include/site/i486
+
diff --git a/include/site/i486 b/include/site/i486
new file mode 100644
index 0000000000..72a3805c64
--- /dev/null
+++ b/include/site/i486
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/i686 b/include/site/i686
new file mode 100644
index 0000000000..78f1557b79
--- /dev/null
+++ b/include/site/i686
@@ -0,0 +1,3 @@
+#!/bin/sh
+. $TOPDIR/include/site/i486
+
diff --git a/include/site/linux b/include/site/linux
new file mode 100644
index 0000000000..b193d25c45
--- /dev/null
+++ b/include/site/linux
@@ -0,0 +1,78 @@
+ac_atomic_add=yes
+ac_atomic_sub=yes
+ac_cv_c_gettext_without_libintl=yes
+ac_cv_c_long_double=no
+ac_cv_conv_longlong_to_float=yes
+ac_cv_file__dev_zero=yes
+ac_cv_func___va_copy=no
+ac_cv_func__exit=yes
+ac_cv_func_bcopy=yes
+ac_cv_func_bzero=yes
+ac_cv_func_bcmp=yes
+ac_cv_func_creal=yes
+ac_cv_func_cimag=yes
+ac_cv_func_fchmod=yes
+ac_cv_func_getaddrinfo=yes
+ac_cv_func_getcwd=yes
+ac_cv_func_getdomainname=yes
+ac_cv_func_getpgrp_void=yes
+ac_cv_func_getpwuid_r=yes
+ac_cv_func_gettimeofday=yes
+ac_cv_func_index=yes
+ac_cv_func_lstat_dereferences_slashed_symlink=yes
+ac_cv_func_lstat_empty_string_bug=no
+ac_cv_func_lstat=yes
+ac_cv_func_malloc_0_nonnull=yes
+ac_cv_func_malloc_works=yes
+ac_cv_func_memcmp_clean=yes
+ac_cv_func_memcmp_working=yes
+ac_cv_func_posix_getgrgid_r=yes
+ac_cv_func_posix_getpwuid_r=yes
+ac_cv_func_psignal=yes
+ac_cv_func_pthread_key_delete=yes
+ac_cv_func_realloc_0_nonnull=yes
+ac_cv_func_realloc_works=yes
+ac_cv_func_rename=yes
+ac_cv_func_rindex=yes
+ac_cv_func_setlocale=yes
+ac_cv_func_setgrent_void=yes
+ac_cv_func_setpgrp_void=yes
+ac_cv_func_setresuid=no
+ac_cv_func_setvbuf_reversed=no
+ac_cv_func_stat_empty_string_bug=no
+ac_cv_func_stat_ignores_trailing_slash=no
+ac_cv_func_strerror=yes
+ac_cv_func_strftime=yes
+ac_cv_func_utimes=yes
+ac_cv_func___adjtimex=yes
+ac_cv_func_va_copy=no
+ac_cv_func_vsnprintf=yes
+ac_cv_have_accrights_in_msghdr=no
+ac_cv_have_broken_snprintf=no
+ac_cv_have_control_in_msghdr=yes
+ac_cv_have_decl_sys_siglist=no
+ac_cv_have_openpty_ctty_bug=yes
+ac_cv_have_space_d_name_in_struct_dirent=yes
+ac_cv_header_netinet_sctp_h=no
+ac_cv_header_netinet_sctp_uio_h=no
+ac_cv_int64_t=yes
+ac_cv_lbl_unaligned_fail=no
+ac_cv_linux_kernel_pppoe=yes
+ac_cv_linux_vers=2
+ac_cv_pack_bitfields_reversed=yes
+ac_cv_path_LDCONFIG=
+ac_cv_regexec_segfault_emptystr=no
+ac_cv_sctp=no
+ac_cv_sys_restartable_syscalls=yes
+ac_cv_time_r_type=POSIX
+ac_cv_type_suseconds_t=yes
+ac_cv_uchar=no
+ac_cv_uint=yes
+ac_cv_uint64_t=yes
+ac_cv_ulong=yes
+ac_cv_ushort=yes
+ac_cv_va_copy=C99
+ac_cv_va_val_copy=yes
+as_cv_unaligned_access=yes
+ac_cv_func_malloc_0_nonnull=yes
+ac_cv_func_realloc_0_nonnull=yes
diff --git a/include/site/m68k b/include/site/m68k
new file mode 100644
index 0000000000..0037600a09
--- /dev/null
+++ b/include/site/m68k
@@ -0,0 +1,28 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/mips b/include/site/mips
new file mode 100644
index 0000000000..a5626a722b
--- /dev/null
+++ b/include/site/mips
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/mips64 b/include/site/mips64
new file mode 100644
index 0000000000..19e75ab991
--- /dev/null
+++ b/include/site/mips64
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=8
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=8
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=8
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=8
+ac_cv_sizeof_ssize_t=8
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=8
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=8
diff --git a/include/site/mips64el b/include/site/mips64el
new file mode 100644
index 0000000000..c5aa9c5543
--- /dev/null
+++ b/include/site/mips64el
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=8
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=8
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=8
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=8
+ac_cv_sizeof_ssize_t=8
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=8
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=8
diff --git a/include/site/mipsel b/include/site/mipsel
new file mode 100644
index 0000000000..72a3805c64
--- /dev/null
+++ b/include/site/mipsel
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/powerpc b/include/site/powerpc
new file mode 100644
index 0000000000..a5626a722b
--- /dev/null
+++ b/include/site/powerpc
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/sparc b/include/site/sparc
new file mode 100644
index 0000000000..a5626a722b
--- /dev/null
+++ b/include/site/sparc
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=no}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=yes}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=4
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=4
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=4
+ac_cv_sizeof_ssize_t=4
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=4
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=4
diff --git a/include/site/x86_64 b/include/site/x86_64
new file mode 100644
index 0000000000..b8d581d448
--- /dev/null
+++ b/include/site/x86_64
@@ -0,0 +1,30 @@
+#!/bin/sh
+. $TOPDIR/include/site/linux
+ac_cv_c_littleendian=${ac_cv_c_littleendian=yes}
+ac_cv_c_bigendian=${ac_cv_c_bigendian=no}
+
+ac_cv_sizeof___int64=0
+ac_cv_sizeof_char=1
+ac_cv_sizeof_int=4
+ac_cv_sizeof_int16_t=2
+ac_cv_sizeof_int32_t=4
+ac_cv_sizeof_int64_t=8
+ac_cv_sizeof_long_int=8
+ac_cv_sizeof_long_long=8
+ac_cv_sizeof_long=8
+ac_cv_sizeof_off_t=8
+ac_cv_sizeof_short_int=2
+ac_cv_sizeof_short=2
+ac_cv_sizeof_size_t=8
+ac_cv_sizeof_ssize_t=8
+ac_cv_sizeof_u_int16_t=2
+ac_cv_sizeof_u_int32_t=4
+ac_cv_sizeof_u_int64_t=8
+ac_cv_sizeof_uint16_t=2
+ac_cv_sizeof_uint32_t=4
+ac_cv_sizeof_uint64_t=8
+ac_cv_sizeof_unsigned_int=4
+ac_cv_sizeof_unsigned_long=8
+ac_cv_sizeof_unsigned_long_long=8
+ac_cv_sizeof_unsigned_short=2
+ac_cv_sizeof_void_p=8
diff --git a/include/subdir.mk b/include/subdir.mk
new file mode 100644
index 0000000000..f4085f9df4
--- /dev/null
+++ b/include/subdir.mk
@@ -0,0 +1,92 @@
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifeq ($(MAKECMDGOALS),prereq)
+  SUBTARGETS:=prereq
+  PREREQ_ONLY:=1
+else
+  SUBTARGETS:=clean download prepare compile install update refresh prereq dist distcheck configure
+endif
+
+subtarget-default = $(filter-out ., \
+	$(if $($(1)/builddirs-$(2)),$($(1)/builddirs-$(2)), \
+	$(if $($(1)/builddirs-default),$($(1)/builddirs-default), \
+	$($(1)/builddirs))))
+
+define subtarget
+  $(call warn_eval,$(1),t,T,$(1)/$(2): $($(1)/) $(foreach bd,$(call subtarget-default,$(1),$(2)),$(1)/$(bd)/$(2)))
+
+endef
+
+define ERROR
+	($(call MESSAGE, $(2)); $(if $(BUILD_LOG), echo "$(2)" >> $(BUILD_LOG_DIR)/$(1)/error.txt))
+endef
+
+lastdir=$(word $(words $(subst /, ,$(1))),$(subst /, ,$(1)))
+diralias=$(if $(findstring $(1),$(call lastdir,$(1))),,$(call lastdir,$(1)))
+
+# 1: subdir
+# 2: target
+# 3: build type
+# 4: build variant
+log_make = \
+	 $(if $(call debug,$(1),v),,@)+ \
+	 $(if $(BUILD_LOG), \
+		set -o pipefail; \
+		mkdir -p $(BUILD_LOG_DIR)/$(1)$(if $(4),/$(4));) \
+	$$(SUBMAKE) -r -C $(1) $(if $(3),$(3)-)$(2) \
+		BUILD_SUBDIR="$(1)" \
+		BUILD_VARIANT="$(4)" \
+		$(if $(BUILD_LOG),SILENT= 2>&1 | tee $(BUILD_LOG_DIR)/$(1)$(if $(4),/$(4))/$(if $(3),$(3)-)$(2).txt)
+
+# Parameters: <subdir>
+define subdir
+  $(call warn,$(1),d,D $(1))
+  $(foreach bd,$($(1)/builddirs),
+    $(call warn,$(1),d,BD $(1)/$(bd))
+    $(foreach target,$(SUBTARGETS),
+      $(foreach btype,$(buildtypes-$(bd)),
+        $(call warn_eval,$(1)/$(bd),t,T,$(1)/$(bd)/$(btype)/$(target): $(if $(QUILT),,$($(1)/$(bd)/$(btype)/$(target)) $(call $(1)//$(btype)/$(target),$(1)/$(bd)/$(btype))))
+		  $(call log_make,$(1)/$(bd),$(target),$(btype),$(filter-out __default,$(variant))) \
+			$(if $(findstring $(bd),$($(1)/builddirs-ignore-$(btype)-$(target))), || $(call ERROR,$(1),   ERROR: $(1)/$(bd) [$(btype)] failed to build.))
+        $(if $(call diralias,$(bd)),$(call warn_eval,$(1)/$(bd),l,T,$(1)/$(call diralias,$(bd))/$(btype)/$(target): $(1)/$(bd)/$(btype)/$(target)))
+      )
+      $(call warn_eval,$(1)/$(bd),t,T,$(1)/$(bd)/$(target): $(if $(QUILT),,$($(1)/$(bd)/$(target)) $(call $(1)//$(target),$(1)/$(bd))))
+        $(foreach variant,$(if $(BUILD_VARIANT),$(BUILD_VARIANT),$(if $(strip $($(1)/$(bd)/variants)),$($(1)/$(bd)/variants),$(if $($(1)/$(bd)/default-variant),$($(1)/$(bd)/default-variant),__default))),
+			$(if $(BUILD_LOG),@mkdir -p $(BUILD_LOG_DIR)/$(1)/$(bd)/$(filter-out __default,$(variant)))
+			$(call log_make,$(1)/$(bd),$(target),,$(filter-out __default,$(variant))) \
+				$(if $(findstring $(bd),$($(1)/builddirs-ignore-$(target))), || $(call ERROR,$(1),   ERROR: $(1)/$(bd) failed to build$(if $(filter-out __default,$(variant)), (build variant: $(variant))).))
+        )
+      $(if $(PREREQ_ONLY)$(DUMP_TARGET_DB),,
+        # aliases
+        $(if $(call diralias,$(bd)),$(call warn_eval,$(1)/$(bd),l,T,$(1)/$(call diralias,$(bd))/$(target): $(1)/$(bd)/$(target)))
+	  )
+	)
+  )
+  $(foreach target,$(SUBTARGETS),$(call subtarget,$(1),$(target)))
+endef
+
+ifndef DUMP_TARGET_DB
+# Parameters: <subdir> <name> <target> <depends> <config options> <stampfile location>
+define stampfile
+  $(1)/stamp-$(3):=$(if $(6),$(6),$(STAGING_DIR))/stamp/.$(2)_$(3)$(5)
+  $$($(1)/stamp-$(3)): $(TMP_DIR)/.build $(4)
+	@+$(SCRIPT_DIR)/timestamp.pl -n $$($(1)/stamp-$(3)) $(1) $(4) || \
+		$(MAKE) $(if $(QUIET),--no-print-directory) $$($(1)/flags-$(3)) $(1)/$(3)
+	@mkdir -p $$$$(dirname $$($(1)/stamp-$(3)))
+	@touch $$($(1)/stamp-$(3))
+
+  $$(if $(call debug,$(1),v),,.SILENT: $$($(1)/stamp-$(3)))
+
+  .PRECIOUS: $$($(1)/stamp-$(3)) # work around a make bug
+
+  $(1)//clean:=$(1)/stamp-$(3)/clean
+  $(1)/stamp-$(3)/clean: FORCE
+	@rm -f $$($(1)/stamp-$(3))
+
+endef
+endif
diff --git a/include/target.mk b/include/target.mk
new file mode 100644
index 0000000000..a8d3b2b249
--- /dev/null
+++ b/include/target.mk
@@ -0,0 +1,306 @@
+#
+# Copyright (C) 2007-2008 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifneq ($(__target_inc),1)
+__target_inc=1
+
+# default device type
+DEVICE_TYPE?=router
+
+# Default packages - the really basic set
+DEFAULT_PACKAGES:=base-files libc libgcc busybox dropbear mtd uci opkg netifd fstools uclient-fetch
+# For nas targets
+DEFAULT_PACKAGES.nas:=block-mount fdisk lsblk mdadm
+# For router targets
+DEFAULT_PACKAGES.router:=dnsmasq iptables ip6tables ppp ppp-mod-pppoe firewall odhcpd odhcp6c
+DEFAULT_PACKAGES.bootloader:=
+
+ifneq ($(DUMP),)
+  all: dumpinfo
+endif
+
+target_conf=$(subst .,_,$(subst -,_,$(subst /,_,$(1))))
+ifeq ($(DUMP),)
+  PLATFORM_DIR:=$(TOPDIR)/target/linux/$(BOARD)
+  SUBTARGET:=$(strip $(foreach subdir,$(patsubst $(PLATFORM_DIR)/%/target.mk,%,$(wildcard $(PLATFORM_DIR)/*/target.mk)),$(if $(CONFIG_TARGET_$(call target_conf,$(BOARD)_$(subdir))),$(subdir))))
+else
+  PLATFORM_DIR:=${CURDIR}
+  ifeq ($(SUBTARGETS),)
+    SUBTARGETS:=$(strip $(patsubst $(PLATFORM_DIR)/%/target.mk,%,$(wildcard $(PLATFORM_DIR)/*/target.mk)))
+  endif
+endif
+
+TARGETID:=$(BOARD)$(if $(SUBTARGET),/$(SUBTARGET))
+PLATFORM_SUBDIR:=$(PLATFORM_DIR)$(if $(SUBTARGET),/$(SUBTARGET))
+
+ifneq ($(TARGET_BUILD),1)
+  ifndef DUMP
+    include $(PLATFORM_DIR)/Makefile
+    ifneq ($(PLATFORM_DIR),$(PLATFORM_SUBDIR))
+      include $(PLATFORM_SUBDIR)/target.mk
+    endif
+  endif
+else
+  ifneq ($(SUBTARGET),)
+    -include ./$(SUBTARGET)/target.mk
+  endif
+endif
+
+# Add device specific packages (here below to allow device type set from subtarget)
+DEFAULT_PACKAGES += $(DEFAULT_PACKAGES.$(DEVICE_TYPE))
+
+filter_packages = $(filter-out -% $(patsubst -%,%,$(filter -%,$(1))),$(1))
+extra_packages = $(if $(filter wpad-mini wpad nas,$(1)),iwinfo)
+
+define ProfileDefault
+  NAME:=
+  PRIORITY:=
+  PACKAGES:=
+endef
+
+ifndef Profile
+define Profile
+  $(eval $(call ProfileDefault))
+  $(eval $(call Profile/$(1)))
+  dumpinfo : $(call shexport,Profile/$(1)/Description)
+  DUMPINFO += \
+	echo "Target-Profile: $(1)"; \
+	$(if $(PRIORITY), echo "Target-Profile-Priority: $(PRIORITY)"; ) \
+	echo "Target-Profile-Name: $(NAME)"; \
+	echo "Target-Profile-Packages: $(PACKAGES) $(call extra_packages,$(DEFAULT_PACKAGES) $(PACKAGES))"; \
+	echo "Target-Profile-Description:"; \
+	echo "$$$$$$$$$(call shvar,Profile/$(1)/Description)"; \
+	echo "@@"; \
+	echo;
+endef
+endif
+
+ifneq ($(PLATFORM_DIR),$(PLATFORM_SUBDIR))
+  define IncludeProfiles
+    -include $(sort $(wildcard $(PLATFORM_DIR)/profiles/*.mk))
+    -include $(sort $(wildcard $(PLATFORM_SUBDIR)/profiles/*.mk))
+  endef
+else
+  define IncludeProfiles
+    -include $(sort $(wildcard $(PLATFORM_DIR)/profiles/*.mk))
+  endef
+endif
+
+PROFILE?=$(call qstrip,$(CONFIG_TARGET_PROFILE))
+
+ifeq ($(TARGET_BUILD),1)
+  ifneq ($(DUMP),)
+    $(eval $(call IncludeProfiles))
+  endif
+endif
+
+ifneq ($(TARGET_BUILD)$(if $(DUMP),,1),)
+  include $(INCLUDE_DIR)/kernel-version.mk
+endif
+
+GENERIC_PLATFORM_DIR := $(TOPDIR)/target/linux/generic
+GENERIC_PATCH_DIR := $(GENERIC_PLATFORM_DIR)/patches$(if $(wildcard $(GENERIC_PLATFORM_DIR)/patches-$(KERNEL_PATCHVER)),-$(KERNEL_PATCHVER))
+GENERIC_FILES_DIR := $(foreach dir,$(wildcard $(GENERIC_PLATFORM_DIR)/files $(GENERIC_PLATFORM_DIR)/files-$(KERNEL_PATCHVER)),"$(dir)")
+
+__config_name_list = $(1)/config-$(KERNEL_PATCHVER) $(1)/config-default
+__config_list = $(firstword $(wildcard $(call __config_name_list,$(1))))
+find_kernel_config=$(if $(__config_list),$(__config_list),$(lastword $(__config_name_list)))
+
+GENERIC_LINUX_CONFIG = $(call find_kernel_config,$(GENERIC_PLATFORM_DIR))
+LINUX_TARGET_CONFIG = $(call find_kernel_config,$(PLATFORM_DIR))
+ifneq ($(PLATFORM_DIR),$(PLATFORM_SUBDIR))
+  LINUX_SUBTARGET_CONFIG = $(call find_kernel_config,$(PLATFORM_SUBDIR))
+endif
+
+# config file list used for compiling
+LINUX_KCONFIG_LIST = $(wildcard $(GENERIC_LINUX_CONFIG) $(LINUX_TARGET_CONFIG) $(LINUX_SUBTARGET_CONFIG) $(TOPDIR)/env/kernel-config)
+
+# default config list for reconfiguring
+# defaults to subtarget if subtarget exists and target does not
+# defaults to target otherwise
+USE_SUBTARGET_CONFIG = $(if $(wildcard $(LINUX_TARGET_CONFIG)),,$(if $(LINUX_SUBTARGET_CONFIG),1))
+
+LINUX_RECONFIG_LIST = $(wildcard $(GENERIC_LINUX_CONFIG) $(LINUX_TARGET_CONFIG) $(if $(USE_SUBTARGET_CONFIG),$(LINUX_SUBTARGET_CONFIG)))
+LINUX_RECONFIG_TARGET = $(if $(USE_SUBTARGET_CONFIG),$(LINUX_SUBTARGET_CONFIG),$(LINUX_TARGET_CONFIG))
+
+# select the config file to be changed by kernel_menuconfig/kernel_oldconfig
+ifeq ($(CONFIG_TARGET),platform)
+  LINUX_RECONFIG_LIST = $(wildcard $(GENERIC_LINUX_CONFIG) $(LINUX_TARGET_CONFIG))
+  LINUX_RECONFIG_TARGET = $(LINUX_TARGET_CONFIG)
+endif
+ifeq ($(CONFIG_TARGET),subtarget)
+  LINUX_RECONFIG_LIST = $(wildcard $(GENERIC_LINUX_CONFIG) $(LINUX_TARGET_CONFIG) $(LINUX_SUBTARGET_CONFIG))
+  LINUX_RECONFIG_TARGET = $(LINUX_SUBTARGET_CONFIG)
+endif
+ifeq ($(CONFIG_TARGET),subtarget_platform)
+  LINUX_RECONFIG_LIST = $(wildcard $(GENERIC_LINUX_CONFIG) $(LINUX_SUBTARGET_CONFIG) $(LINUX_TARGET_CONFIG))
+  LINUX_RECONFIG_TARGET = $(LINUX_TARGET_CONFIG)
+endif
+ifeq ($(CONFIG_TARGET),env)
+  LINUX_RECONFIG_LIST = $(LINUX_KCONFIG_LIST)
+  LINUX_RECONFIG_TARGET = $(TOPDIR)/env/kernel-config
+endif
+
+__linux_confcmd = $(SCRIPT_DIR)/kconfig.pl $(2) $(patsubst %,+,$(wordlist 2,9999,$(1))) $(1)
+
+LINUX_CONF_CMD = $(call __linux_confcmd,$(LINUX_KCONFIG_LIST),)
+LINUX_RECONF_CMD = $(call __linux_confcmd,$(LINUX_RECONFIG_LIST),)
+LINUX_RECONF_DIFF = $(call __linux_confcmd,$(filter-out $(LINUX_RECONFIG_TARGET),$(LINUX_RECONFIG_LIST)),'>')
+
+ifeq ($(DUMP),1)
+  BuildTarget=$(BuildTargets/DumpCurrent)
+
+  CPU_CFLAGS = -Os -pipe
+  ifneq ($(findstring mips,$(ARCH)),)
+    ifneq ($(findstring mips64,$(ARCH)),)
+      CPU_TYPE ?= mips64
+    else
+      CPU_TYPE ?= mips32
+    endif
+    CPU_CFLAGS += -mno-branch-likely
+    CPU_CFLAGS_mips32 = -mips32 -mtune=mips32
+    CPU_CFLAGS_mips32r2 = -mips32r2 -mtune=mips32r2
+    CPU_CFLAGS_mips64 = -mips64 -mtune=mips64 -mabi=64
+    CPU_CFLAGS_24kc = -mips32r2 -mtune=24kc
+    CPU_CFLAGS_74kc = -mips32r2 -mtune=74kc
+    CPU_CFLAGS_octeon = -march=octeon -mabi=64
+  endif
+  ifeq ($(ARCH),i386)
+    CPU_TYPE ?= i486
+    CPU_CFLAGS_i486 = -march=i486
+    CPU_CFLAGS_pentium4 = -march=pentium4
+    CPU_CFLAGS_geode = -march=geode -mmmx -m3dnow
+  endif
+  ifneq ($(findstring arm,$(ARCH)),)
+    CPU_TYPE ?= xscale
+    CPU_CFLAGS_arm920t = -mcpu=arm920t
+    CPU_CFLAGS_arm926ej-s = -mcpu=arm926ej-s
+    CPU_CFLAGS_arm1136j-s = -mcpu=arm1136j-s
+    CPU_CFLAGS_arm1176jzf-s = -mcpu=arm1176jzf-s
+    CPU_CFLAGS_cortex-a5 = -mcpu=cortex-a5
+    CPU_CFLAGS_cortex-a7 = -mcpu=cortex-a7
+    CPU_CFLAGS_cortex-a8 = -mcpu=cortex-a8
+    CPU_CFLAGS_cortex-a9 = -mcpu=cortex-a9
+    CPU_CFLAGS_cortex-a15 = -mcpu=cortex-a15
+    CPU_CFLAGS_cortex-a53 = -mcpu=cortex-a53
+    CPU_CFLAGS_fa526 = -mcpu=fa526
+    CPU_CFLAGS_mpcore = -mcpu=mpcore
+    CPU_CFLAGS_xscale = -mcpu=xscale
+    ifeq ($(CONFIG_SOFT_FLOAT),)
+      CPU_CFLAGS_neon = -mfpu=neon
+      CPU_CFLAGS_vfp = -mfpu=vfp
+      CPU_CFLAGS_vfpv3 = -mfpu=vfpv3-d16
+      CPU_CFLAGS_neon-vfpv4 = -mfpu=neon-vfpv4
+    endif
+  endif
+  ifeq ($(ARCH),powerpc)
+    CPU_CFLAGS_603e:=-mcpu=603e
+    CPU_CFLAGS_8540:=-mcpu=8540
+    CPU_CFLAGS_405:=-mcpu=405
+    CPU_CFLAGS_440:=-mcpu=440
+    CPU_CFLAGS_464fp:=-mcpu=464fp
+  endif
+  ifeq ($(ARCH),sparc)
+    CPU_TYPE = sparc
+    CPU_CFLAGS_ultrasparc = -mcpu=ultrasparc
+  endif
+  ifeq ($(ARCH),aarch64)
+    CPU_TYPE ?= armv8-a
+    CPU_CFLAGS_armv8-a = -mcpu=armv8-a
+    CPU_CFLAGS_cortex-a53 = -mcpu=cortex-a53
+  endif
+  ifeq ($(ARCH),arc)
+    CPU_TYPE ?= arc700
+    CPU_CFLAGS += -matomic
+    CPU_CFLAGS_arc700 = -marc700
+    CPU_CFLAGS_archs = -marchs
+  endif
+  DEFAULT_CFLAGS=$(strip $(CPU_CFLAGS) $(CPU_CFLAGS_$(CPU_TYPE)) $(CPU_CFLAGS_$(CPU_SUBTYPE)))
+
+  ifneq ($(BOARD),)
+    TMP_CONFIG:=$(TMP_DIR)/.kconfig-$(call target_conf,$(TARGETID))
+    $(TMP_CONFIG): $(LINUX_KCONFIG_LIST)
+		$(LINUX_CONF_CMD) > $@ || rm -f $@
+    -include $(TMP_CONFIG)
+    .SILENT: $(TMP_CONFIG)
+    .PRECIOUS: $(TMP_CONFIG)
+
+    ifneq ($(CONFIG_OF),)
+      FEATURES += dt
+    endif
+    ifneq ($(CONFIG_GENERIC_GPIO)$(CONFIG_GPIOLIB),)
+      FEATURES += gpio
+    endif
+    ifneq ($(CONFIG_PCI),)
+      FEATURES += pci
+    endif
+    ifneq ($(CONFIG_PCIEPORTBUS),)
+      FEATURES += pcie
+    endif
+    ifneq ($(CONFIG_USB)$(CONFIG_USB_SUPPORT),)
+      ifneq ($(CONFIG_USB_ARCH_HAS_HCD)$(CONFIG_USB_EHCI_HCD),)
+        FEATURES += usb
+      endif
+    endif
+    ifneq ($(CONFIG_PCMCIA)$(CONFIG_PCCARD),)
+      FEATURES += pcmcia
+    endif
+    ifneq ($(CONFIG_VGA_CONSOLE)$(CONFIG_FB),)
+      FEATURES += display
+    endif
+    ifneq ($(CONFIG_RTC_CLASS),)
+      FEATURES += rtc
+    endif
+    ifneq ($(CONFIG_VIRTIO),)
+      FEATURES += virtio
+    endif
+    FEATURES += $(foreach v,6 7,$(if $(CONFIG_CPU_V$(v)),arm_v$(v)))
+
+    # remove duplicates
+    FEATURES:=$(sort $(FEATURES))
+  endif
+endif
+
+CUR_SUBTARGET:=$(SUBTARGET)
+ifeq ($(SUBTARGETS),)
+  CUR_SUBTARGET := default
+endif
+
+define BuildTargets/DumpCurrent
+  .PHONY: dumpinfo
+  dumpinfo : export DESCRIPTION=$$(Target/Description)
+  dumpinfo:
+	@echo 'Target: $(TARGETID)'; \
+	 echo 'Target-Board: $(BOARD)'; \
+	 echo 'Target-Name: $(BOARDNAME)$(if $(SUBTARGETS),$(if $(SUBTARGET),))'; \
+	 echo 'Target-Arch: $(ARCH)'; \
+	 echo 'Target-Arch-Packages: $(if $(ARCH_PACKAGES),$(ARCH_PACKAGES),$(ARCH)$(if $(CPU_TYPE),_$(CPU_TYPE))$(if $(CPU_SUBTYPE),_$(CPU_SUBTYPE)))'; \
+	 echo 'Target-Features: $(FEATURES)'; \
+	 echo 'Target-Depends: $(DEPENDS)'; \
+	 echo 'Target-Optimization: $(if $(CFLAGS),$(CFLAGS),$(DEFAULT_CFLAGS))'; \
+	 echo 'CPU-Type: $(CPU_TYPE)$(if $(CPU_SUBTYPE),+$(CPU_SUBTYPE))'; \
+	 echo 'Linux-Version: $(LINUX_VERSION)'; \
+	 echo 'Linux-Release: $(LINUX_RELEASE)'; \
+	 echo 'Linux-Kernel-Arch: $(LINUX_KARCH)'; \
+	$(if $(SUBTARGET),,$(if $(DEFAULT_SUBTARGET), echo 'Default-Subtarget: $(DEFAULT_SUBTARGET)'; )) \
+	 echo 'Target-Description:'; \
+	 echo "$$$$DESCRIPTION"; \
+	 echo '@@'; \
+	 echo 'Default-Packages: $(DEFAULT_PACKAGES) $(call extra_packages,$(DEFAULT_PACKAGES))'; \
+	 $(DUMPINFO)
+	$(if $(CUR_SUBTARGET),$(SUBMAKE) -r --no-print-directory -C image -s DUMP=1 SUBTARGET=$(CUR_SUBTARGET))
+	$(if $(SUBTARGET),,@$(foreach SUBTARGET,$(SUBTARGETS),$(SUBMAKE) -s DUMP=1 SUBTARGET=$(SUBTARGET); ))
+endef
+
+include $(INCLUDE_DIR)/kernel.mk
+ifeq ($(TARGET_BUILD),1)
+  include $(INCLUDE_DIR)/kernel-build.mk
+  BuildTarget?=$(BuildKernel)
+endif
+
+endif #__target_inc
diff --git a/include/toolchain-build.mk b/include/toolchain-build.mk
new file mode 100644
index 0000000000..212923a1e6
--- /dev/null
+++ b/include/toolchain-build.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+override CONFIG_AUTOREBUILD=
+
+REAL_STAGING_DIR_HOST:=$(STAGING_DIR_HOST)
+STAGING_DIR_HOST:=$(TOOLCHAIN_DIR)
+BUILD_DIR_HOST:=$(BUILD_DIR_TOOLCHAIN)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_STAMP_PREPARED=$(HOST_BUILD_DIR)/.prepared
+
+define FixupLibdir
+	if [ -d $(1)/lib64 -a \! -L $(1)/lib64 ]; then \
+		mkdir -p $(1)/lib; \
+		mv $(1)/lib64/* $(1)/lib/; \
+		rm -rf $(1)/lib64; \
+	fi
+	ln -sf lib $(1)/lib64
+endef
diff --git a/include/toplevel.mk b/include/toplevel.mk
new file mode 100644
index 0000000000..f31884d3fe
--- /dev/null
+++ b/include/toplevel.mk
@@ -0,0 +1,235 @@
+# Makefile for OpenWrt
+#
+# Copyright (C) 2007-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+PREP_MK= OPENWRT_BUILD= QUIET=0
+
+export IS_TTY=$(shell tty -s && echo 1 || echo 0)
+
+include $(TOPDIR)/include/verbose.mk
+
+ifeq ($(SDK),1)
+  include $(TOPDIR)/include/version.mk
+else
+  REVISION:=$(shell $(TOPDIR)/scripts/getver.sh)
+  SOURCE_DATE_EPOCH:=$(shell $(TOPDIR)/scripts/get_source_date_epoch.sh)
+endif
+
+HOSTCC ?= $(CC)
+export REVISION
+export SOURCE_DATE_EPOCH
+export GIT_CONFIG_PARAMETERS='core.autocrlf=false'
+export MAKE_JOBSERVER=$(filter --jobserver%,$(MAKEFLAGS))
+
+# prevent perforce from messing with the patch utility
+unexport P4PORT P4USER P4CONFIG P4CLIENT
+
+# prevent user defaults for quilt from interfering
+unexport QUILT_PATCHES QUILT_PATCH_OPTS
+
+unexport C_INCLUDE_PATH CROSS_COMPILE ARCH
+
+# prevent distro default LPATH from interfering
+unexport LPATH
+
+# make sure that a predefined CFLAGS variable does not disturb packages
+export CFLAGS=
+export LDFLAGS=
+
+empty:=
+space:= $(empty) $(empty)
+path:=$(subst :,$(space),$(PATH))
+path:=$(filter-out .%,$(path))
+path:=$(subst $(space),:,$(path))
+export PATH:=$(path)
+
+unexport TAR_OPTIONS
+
+ifneq ($(shell $(HOSTCC) 2>&1 | grep clang),)
+  export HOSTCC_REAL?=$(HOSTCC)
+  export HOSTCC_WRAPPER:=$(TOPDIR)/scripts/clang-gcc-wrapper
+else
+  export HOSTCC_WRAPPER:=$(HOSTCC)
+endif
+
+ifeq ($(FORCE),)
+  .config scripts/config/conf scripts/config/mconf: staging_dir/host/.prereq-build
+endif
+
+SCAN_COOKIE?=$(shell echo $$$$)
+export SCAN_COOKIE
+
+SUBMAKE:=umask 022; $(SUBMAKE)
+
+ULIMIT_FIX=_limit=`ulimit -n`; [ "$$_limit" = "unlimited" -o "$$_limit" -ge 1024 ] || ulimit -n 1024;
+
+prepare-mk: FORCE ;
+
+ifdef SDK
+  IGNORE_PACKAGES = linux
+endif
+
+_ignore = $(foreach p,$(IGNORE_PACKAGES),--ignore $(p))
+
+prepare-tmpinfo: FORCE
+	@+$(MAKE) -r -s staging_dir/host/.prereq-build $(PREP_MK)
+	mkdir -p tmp/info
+	$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPS="$(TOPDIR)/include/package*.mk $(TOPDIR)/overlay/*/*.mk" SCAN_DEPTH=5 SCAN_EXTRA=""
+	$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" SCAN_DEPS="image/Makefile profiles/*.mk $(TOPDIR)/include/kernel*.mk $(TOPDIR)/include/target.mk" SCAN_DEPTH=2 SCAN_EXTRA="" SCAN_MAKEOPTS="TARGET_BUILD=1"
+	for type in package target; do \
+		f=tmp/.$${type}info; t=tmp/.config-$${type}.in; \
+		[ "$$t" -nt "$$f" ] || ./scripts/$${type}-metadata.pl $(_ignore) config "$$f" > "$$t" || { rm -f "$$t"; echo "Failed to build $$t"; false; break; }; \
+	done
+	[ tmp/.config-feeds.in -nt tmp/.packagesubdirs ] || ./scripts/feeds feed_config > tmp/.config-feeds.in
+	./scripts/package-metadata.pl mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
+	./scripts/package-metadata.pl subdirs tmp/.packageinfo > tmp/.packagesubdirs || { rm -f tmp/.packagesubdirs; false; }
+	touch $(TOPDIR)/tmp/.build
+
+.config: ./scripts/config/conf $(if $(CONFIG_HAVE_DOT_CONFIG),,prepare-tmpinfo)
+	@+if [ \! -e .config ] || ! grep CONFIG_HAVE_DOT_CONFIG .config >/dev/null; then \
+		[ -e $(HOME)/.openwrt/defconfig ] && cp $(HOME)/.openwrt/defconfig .config; \
+		$(_SINGLE)$(NO_TRACE_MAKE) menuconfig $(PREP_MK); \
+	fi
+
+scripts/config/mconf:
+	@$(_SINGLE)$(SUBMAKE) -s -C scripts/config all CC="$(HOSTCC_WRAPPER)"
+
+$(eval $(call rdep,scripts/config,scripts/config/mconf))
+
+scripts/config/conf:
+	@$(_SINGLE)$(SUBMAKE) -s -C scripts/config conf CC="$(HOSTCC_WRAPPER)"
+
+config: scripts/config/conf prepare-tmpinfo FORCE
+	$< Config.in
+
+config-clean: FORCE
+	$(_SINGLE)$(NO_TRACE_MAKE) -C scripts/config clean
+
+defconfig: scripts/config/conf prepare-tmpinfo FORCE
+	touch .config
+	@if [ ! -s .config -a -e $(HOME)/.openwrt/defconfig ]; then cp $(HOME)/.openwrt/defconfig .config; fi
+	$< --defconfig=.config Config.in
+
+confdefault-y=allyes
+confdefault-m=allmod
+confdefault-n=allno
+confdefault:=$(confdefault-$(CONFDEFAULT))
+
+oldconfig: scripts/config/conf prepare-tmpinfo FORCE
+	$< --$(if $(confdefault),$(confdefault),old)config Config.in
+
+menuconfig: scripts/config/mconf prepare-tmpinfo FORCE
+	if [ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
+		cp $(HOME)/.openwrt/defconfig .config; \
+	fi
+	$< Config.in
+
+prepare_kernel_conf: .config FORCE
+
+ifeq ($(wildcard staging_dir/host/bin/quilt),)
+  prepare_kernel_conf:
+	@+$(SUBMAKE) -r tools/quilt/install
+else
+  prepare_kernel_conf: ;
+endif
+
+kernel_oldconfig: prepare_kernel_conf
+	$(_SINGLE)$(NO_TRACE_MAKE) -C target/linux oldconfig
+
+kernel_menuconfig: prepare_kernel_conf
+	$(_SINGLE)$(NO_TRACE_MAKE) -C target/linux menuconfig
+
+kernel_nconfig: prepare_kernel_conf
+	$(_SINGLE)$(NO_TRACE_MAKE) -C target/linux nconfig
+
+staging_dir/host/.prereq-build: include/prereq-build.mk
+	mkdir -p tmp
+	rm -f tmp/.host.mk
+	@$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prereq-build.mk prereq 2>/dev/null || { \
+		echo "Prerequisite check failed. Use FORCE=1 to override."; \
+		false; \
+	}
+  ifneq ($(realpath $(TOPDIR)/include/prepare.mk),)
+	@$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prepare.mk prepare 2>/dev/null || { \
+		echo "Preparation failed."; \
+		false; \
+	}
+  endif
+	touch $@
+
+printdb: FORCE
+	@$(_SINGLE)$(NO_TRACE_MAKE) -p $@ V=99 DUMP_TARGET_DB=1 2>&1
+
+ifndef SDK
+  DOWNLOAD_DIRS = tools/download toolchain/download package/download target/download
+else
+  DOWNLOAD_DIRS = package/download
+endif
+
+download: .config FORCE
+	@+$(foreach dir,$(DOWNLOAD_DIRS),$(SUBMAKE) $(dir);)
+
+clean dirclean: .config
+	@+$(SUBMAKE) -r $@
+
+prereq:: prepare-tmpinfo .config
+	@+$(NO_TRACE_MAKE) -r -s $@
+
+WARN_PARALLEL_ERROR = $(if $(BUILD_LOG),,$(and $(filter -j,$(MAKEFLAGS)),$(findstring s,$(OPENWRT_VERBOSE))))
+
+ifeq ($(SDK),1)
+
+%::
+	@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
+	@./scripts/config/conf --defconfig=.config Config.in
+	@+$(ULIMIT_FIX) $(SUBMAKE) -r $@
+
+else
+
+%::
+	@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
+	@( \
+		cp .config tmp/.config; \
+		./scripts/config/conf --defconfig=tmp/.config -w tmp/.config Config.in > /dev/null 2>&1; \
+		if ./scripts/kconfig.pl '>' .config tmp/.config | grep -q CONFIG; then \
+			printf "$(_R)WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!$(_N)\n" >&2; \
+		fi \
+	)
+	@+$(ULIMIT_FIX) $(SUBMAKE) -r $@ $(if $(WARN_PARALLEL_ERROR), || { \
+		printf "$(_R)Build failed - please re-run with -j1 to see the real error message$(_N)\n" >&2; \
+		false; \
+	} )
+
+endif
+
+# update all feeds, re-create index files, install symlinks
+package/symlinks:
+	./scripts/feeds update -a
+	./scripts/feeds install -a
+
+# re-create index files, install symlinks
+package/symlinks-install:
+	./scripts/feeds update -i
+	./scripts/feeds install -a
+
+# remove all symlinks, don't touch ./feeds
+package/symlinks-clean:
+	./scripts/feeds uninstall -a
+
+help:
+	cat README
+
+distclean:
+	rm -rf bin build_dir .config* dl feeds key-build* logs package/feeds package/openwrt-packages staging_dir tmp
+	@$(_SINGLE)$(SUBMAKE) -C scripts/config clean
+
+ifeq ($(findstring v,$(DEBUG)),)
+  .SILENT: symlinkclean clean dirclean distclean config-clean download help tmpinfo-clean .config scripts/config/mconf scripts/config/conf menuconfig staging_dir/host/.prereq-build tmp/.prereq-package prepare-tmpinfo
+endif
+.PHONY: help FORCE
+.NOTPARALLEL:
+
diff --git a/include/uclibc++.mk b/include/uclibc++.mk
new file mode 100644
index 0000000000..a1a61f26d4
--- /dev/null
+++ b/include/uclibc++.mk
@@ -0,0 +1,16 @@
+ifndef DUMP
+  ifdef __package_mk
+    $(error uclibc++.mk must be included before package.mk)
+  endif
+endif
+
+PKG_PREPARED_DEPENDS += CONFIG_USE_UCLIBCXX
+CXX_DEPENDS = +USE_UCLIBCXX:uclibcxx +USE_LIBSTDCXX:libstdcpp
+
+ifneq ($(CONFIG_USE_UCLIBCXX),)
+ ifneq ($(CONFIG_CCACHE),)
+  TARGET_CXX_NOCACHE=g++-uc
+ else
+  TARGET_CXX=g++-uc
+ endif
+endif
diff --git a/include/unpack.mk b/include/unpack.mk
new file mode 100644
index 0000000000..3fabf46033
--- /dev/null
+++ b/include/unpack.mk
@@ -0,0 +1,81 @@
+#
+# Copyright (C) 2006-2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+# unpacking files with +s may break on some platforms. this typically emits error code 2
+ifneq ($(HOST_OS),Linux)
+  HOST_TAR:=trapret 2 $(TAR)
+else
+  HOST_TAR:=$(TAR)
+endif
+TAR_CMD=$(HOST_TAR) -C $(1)/.. $(TAR_OPTIONS)
+UNZIP_CMD=unzip -d $(1)/.. $(DL_DIR)/$(PKG_SOURCE)
+
+ifeq ($(PKG_SOURCE),)
+  PKG_UNPACK ?= true
+else
+
+ifeq ($(strip $(UNPACK_CMD)),)
+  ifeq ($(strip $(PKG_CAT)),)
+    # try to autodetect file type
+    EXT:=$(call ext,$(PKG_SOURCE))
+    EXT1:=$(EXT)
+
+    ifeq ($(filter gz tgz,$(EXT)),$(EXT))
+      EXT:=$(call ext,$(PKG_SOURCE:.$(EXT)=))
+      DECOMPRESS_CMD:=gzip -dc $(DL_DIR)/$(PKG_SOURCE) |
+    endif
+    ifeq ($(filter bzip2 bz2 bz tbz2 tbz,$(EXT)),$(EXT))
+      EXT:=$(call ext,$(PKG_SOURCE:.$(EXT)=))
+      DECOMPRESS_CMD:=bzcat $(DL_DIR)/$(PKG_SOURCE) |
+    endif
+    ifeq ($(filter xz txz,$(EXT)),$(EXT))
+      EXT:=$(call ext,$(PKG_SOURCE:.$(EXT)=))
+      DECOMPRESS_CMD:=xzcat $(DL_DIR)/$(PKG_SOURCE) |
+    endif
+    ifeq ($(filter tgz tbz tbz2 txz,$(EXT1)),$(EXT1))
+      EXT:=tar
+    endif
+    DECOMPRESS_CMD ?= cat $(DL_DIR)/$(PKG_SOURCE) |
+    ifeq ($(EXT),tar)
+      UNPACK_CMD=$(DECOMPRESS_CMD) $(TAR_CMD)
+    endif
+    ifeq ($(EXT),cpio)
+      UNPACK_CMD=$(DECOMPRESS_CMD) (cd $(1)/..; cpio -i -d)
+    endif
+    ifeq ($(EXT),zip)
+      UNPACK_CMD=$(UNZIP_CMD)
+    endif
+  endif
+
+  # compatibility code for packages that set PKG_CAT
+  ifeq ($(strip $(UNPACK_CMD)),)
+    # use existing PKG_CAT
+    UNPACK_CMD=$(PKG_CAT) $(DL_DIR)/$(PKG_SOURCE) | $(TAR_CMD)
+    ifeq ($(PKG_CAT),unzip)
+      UNPACK_CMD=$(UNZIP_CMD)
+    endif
+    # replace zcat with $(ZCAT), because some system don't support it properly
+    ifeq ($(PKG_CAT),zcat)
+      UNPACK_CMD=gzip -dc $(DL_DIR)/$(PKG_SOURCE) | $(TAR_CMD)
+    endif
+  endif
+  ifneq ($(strip $(CRLF_WORKAROUND)),)
+    CRLF_CMD := && find $(PKG_BUILD_DIR) -type f -print0 | xargs -0 perl -pi -e 's!\r$$$$!!g'
+  else
+    CRLF_CMD :=
+  endif
+endif
+
+ifdef PKG_BUILD_DIR
+  PKG_UNPACK ?= $(SH_FUNC) $(call UNPACK_CMD,$(PKG_BUILD_DIR)) $(call CRLF_CMD,$(PKG_BUILD_DIR))
+endif
+ifdef HOST_BUILD_DIR
+  HOST_UNPACK ?= $(SH_FUNC) $(call UNPACK_CMD,$(HOST_BUILD_DIR)) $(call CRLF_CMD,$(HOST_BUILD_DIR))
+endif
+
+endif # PKG_SOURCE
+
diff --git a/include/verbose.mk b/include/verbose.mk
new file mode 100644
index 0000000000..b7e43f7430
--- /dev/null
+++ b/include/verbose.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifndef OPENWRT_VERBOSE
+  OPENWRT_VERBOSE:=
+endif
+ifeq ("$(origin V)", "command line")
+  OPENWRT_VERBOSE:=$(V)
+endif
+
+ifeq ($(OPENWRT_VERBOSE),1)
+  OPENWRT_VERBOSE:=w
+endif
+ifeq ($(OPENWRT_VERBOSE),99)
+  OPENWRT_VERBOSE:=s
+endif
+
+ifeq ($(NO_TRACE_MAKE),)
+NO_TRACE_MAKE := $(MAKE) V=s$(OPENWRT_VERBOSE)
+export NO_TRACE_MAKE
+endif
+
+ifeq ($(IS_TTY),1)
+  ifneq ($(strip $(NO_COLOR)),1)
+    _Y:=\\033[33m
+    _R:=\\033[31m
+    _N:=\\033[m
+  endif
+endif
+
+ifeq ($(findstring s,$(OPENWRT_VERBOSE)),)
+  define MESSAGE
+	printf "$(_Y)%s$(_N)\n" "$(1)" >&8
+  endef
+
+  define ERROR_MESSAGE
+	printf "$(_R)%s$(_N)\n" "$(1)" >&8
+  endef
+
+  ifeq ($(QUIET),1)
+    ifneq ($(CURDIR),$(TOPDIR))
+      _DIR:=$(patsubst $(TOPDIR)/%,%,${CURDIR})
+    else
+      _DIR:=
+    endif
+    _NULL:=$(if $(MAKECMDGOALS),$(shell \
+		$(call MESSAGE, make[$(MAKELEVEL)]$(if $(_DIR), -C $(_DIR)) $(MAKECMDGOALS)); \
+    ))
+    SUBMAKE=$(MAKE)
+  else
+    SILENT:=>/dev/null $(if $(findstring w,$(OPENWRT_VERBOSE)),,2>&1)
+    export QUIET:=1
+    SUBMAKE=cmd() { $(SILENT) $(MAKE) -s $$* < /dev/null || { echo "make $$*: build failed. Please re-run make with -j1 V=s to see what's going on"; false; } } 8>&1 9>&2; cmd
+  endif
+
+  .SILENT: $(MAKECMDGOALS)
+else
+  SUBMAKE=$(MAKE) -w
+  define MESSAGE
+    printf "%s\n" "$(1)"
+  endef
+  ERROR_MESSAGE=$(MESSAGE)
+endif
diff --git a/include/version.mk b/include/version.mk
new file mode 100644
index 0000000000..2e89145fab
--- /dev/null
+++ b/include/version.mk
@@ -0,0 +1,112 @@
+#
+# Copyright (C) 2012-2015 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+# Substituted by SDK, do not remove
+# REVISION:=x
+# SOURCE_DATE_EPOCH:=x
+
+RELEASE:=Frivolous Fred
+
+PKG_CONFIG_DEPENDS += \
+	CONFIG_VERSION_BUG_URL \
+	CONFIG_VERSION_NUMBER \
+	CONFIG_VERSION_CODE \
+	CONFIG_VERSION_NICK \
+	CONFIG_VERSION_REPO \
+	CONFIG_VERSION_DIST \
+	CONFIG_VERSION_MANUFACTURER \
+	CONFIG_VERSION_MANUFACTURER_URL \
+	CONFIG_VERSION_PRODUCT \
+	CONFIG_VERSION_SUPPORT_URL \
+	CONFIG_VERSION_HWREV \
+
+qstrip_escape=$(subst ','\'',$(call qstrip,$(1)))
+#'
+
+sanitize = $(call tolower,$(subst _,-,$(subst $(space),-,$(1))))
+
+VERSION_NUMBER:=$(call qstrip_escape,$(CONFIG_VERSION_NUMBER))
+VERSION_NUMBER:=$(if $(VERSION_NUMBER),$(VERSION_NUMBER),v1.4)
+
+VERSION_CODE:=$(call qstrip_escape,$(CONFIG_VERSION_CODE))
+VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),$(REVISION))
+
+VERSION_NICK:=$(call qstrip_escape,$(CONFIG_VERSION_NICK))
+VERSION_NICK:=$(if $(VERSION_NICK),$(VERSION_NICK),$(RELEASE))
+
+VERSION_REPO:=$(call qstrip_escape,$(CONFIG_VERSION_REPO))
+VERSION_REPO:=$(if $(VERSION_REPO),$(VERSION_REPO),https://librecmc.org/librecmc)
+
+VERSION_DIST:=$(call qstrip_escape,$(CONFIG_VERSION_DIST))
+VERSION_DIST:=$(if $(VERSION_DIST),$(VERSION_DIST),libreCMC)
+VERSION_DIST_SANITIZED:=$(call sanitize,$(VERSION_DIST))
+
+VERSION_MANUFACTURER:=$(call qstrip_escape,$(CONFIG_VERSION_MANUFACTURER))
+VERSION_MANUFACTURER:=$(if $(VERSION_MANUFACTURER),$(VERSION_MANUFACTURER),libreCMC)
+
+VERSION_MANUFACTURER_URL:=$(call qstrip_escape,$(CONFIG_VERSION_MANUFACTURER_URL))
+VERSION_MANUFACTURER_URL:=$(if $(VERSION_MANUFACTURER_URL),$(VERSION_MANUFACTURER_URL),https://librecmc.org/librecmc)
+
+VERSION_BUG_URL:=$(call qstrip_escape,$(CONFIG_VERSION_BUG_URL))
+VERSION_BUG_URL:=$(if $(VERSION_BUG_URL),$(VERSION_BUG_URL))
+
+VERSION_SUPPORT_URL:=$(call qstrip_escape,$(CONFIG_VERSION_SUPPORT_URL))
+VERSION_SUPPORT_URL:=$(if $(VERSION_SUPPORT_URL),$(VERSION_SUPPORT_URL))
+
+VERSION_PRODUCT:=$(call qstrip_escape,$(CONFIG_VERSION_PRODUCT))
+VERSION_PRODUCT:=$(if $(VERSION_PRODUCT),$(VERSION_PRODUCT),Generic)
+
+VERSION_HWREV:=$(call qstrip_escape,$(CONFIG_VERSION_HWREV))
+VERSION_HWREV:=$(if $(VERSION_HWREV),$(VERSION_HWREV),v0)
+
+define taint2sym
+$(CONFIG_$(firstword $(subst :, ,$(subst +,,$(subst -,,$(1))))))
+endef
+
+define taint2name
+$(lastword $(subst :, ,$(1)))
+endef
+
+VERSION_TAINT_SPECS := \
+	-ALL_KMODS:no-all \
+	-IPV6:no-ipv6 \
+	+USE_GLIBC:glibc \
+	+USE_MKLIBS:mklibs \
+	+BUSYBOX_CUSTOM:busybox \
+	+OVERRIDE_PKGS:override \
+
+VERSION_TAINTS := $(strip $(foreach taint,$(VERSION_TAINT_SPECS), \
+	$(if $(findstring +,$(taint)), \
+		$(if $(call taint2sym,$(taint)),$(call taint2name,$(taint))), \
+		$(if $(call taint2sym,$(taint)),,$(call taint2name,$(taint))) \
+	)))
+
+PKG_CONFIG_DEPENDS += $(foreach taint,$(VERSION_TAINT_SPECS),$(call taint2sym,$(taint)))
+
+VERSION_SED:=$(SED) 's,%U,$(VERSION_REPO),g' \
+	-e 's,%V,$(VERSION_NUMBER),g' \
+	-e 's,%v,\L$(subst $(space),_,$(VERSION_NUMBER)),g' \
+	-e 's,%C,$(VERSION_CODE),g' \
+	-e 's,%c,\L$(subst $(space),_,$(VERSION_CODE)),g' \
+	-e 's,%N,$(VERSION_NICK),g' \
+	-e 's,%n,\L$(subst $(space),_,$(VERSION_NICK)),g' \
+	-e 's,%D,$(VERSION_DIST),g' \
+	-e 's,%d,\L$(subst $(space),_,$(VERSION_DIST)),g' \
+	-e 's,%R,$(REVISION),g' \
+	-e 's,%T,$(BOARD),g' \
+	-e 's,%S,$(BOARD)/$(if $(SUBTARGET),$(SUBTARGET),generic),g' \
+	-e 's,%A,$(ARCH_PACKAGES),g' \
+	-e 's,%t,$(VERSION_TAINTS),g' \
+	-e 's,%M,$(VERSION_MANUFACTURER),g' \
+	-e 's,%m,$(VERSION_MANUFACTURER_URL),g' \
+	-e 's,%b,$(VERSION_BUG_URL),g' \
+	-e 's,%s,$(VERSION_SUPPORT_URL),g' \
+	-e 's,%P,$(VERSION_PRODUCT),g' \
+	-e 's,%h,$(VERSION_HWREV),g'
+
+VERSION_SED_SCRIPT:=$(subst '\'','\'\\\\\'\'',$(VERSION_SED))
diff --git a/package/Makefile b/package/Makefile
new file mode 100644
index 0000000000..8726e2eae9
--- /dev/null
+++ b/package/Makefile
@@ -0,0 +1,127 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+curdir:=package
+
+include $(INCLUDE_DIR)/rootfs.mk
+
+-include $(TMP_DIR)/.packagedeps
+$(curdir)/builddirs:=$(sort $(package-) $(package-y) $(package-m))
+$(curdir)/builddirs-install:=.
+$(curdir)/builddirs-default:=. $(sort $(package-y) $(package-m))
+$(curdir)/builddirs-prereq:=. $(sort $(prereq-y) $(prereq-m))
+ifneq ($(IGNORE_ERRORS),)
+  package-y-filter := $(package-y)
+  package-m-filter := $(filter-out $(package-y),$(package-m))
+  package-n-filter := $(filter-out $(package-y) $(package-m),$(package-))
+  package-ignore-errors := $(filter n m y,$(IGNORE_ERRORS))
+  package-ignore-errors := $(if $(package-ignore-errors),$(package-ignore-errors),n m)
+  package-ignore-subdirs := $(sort $(foreach m,$(package-ignore-errors),$(package-$(m)-filter)))
+  $(curdir)/builddirs-ignore-download := $(package-ignore-subdirs)
+  $(curdir)/builddirs-ignore-compile := $(package-ignore-subdirs)
+  $(curdir)/builddirs-ignore-host-download := $(package-ignore-subdirs)
+  $(curdir)/builddirs-ignore-host-compile := $(package-ignore-subdirs)
+endif
+
+PACKAGE_INSTALL_FILES:= \
+	$(foreach pkg,$(sort $(package-y)), \
+		$(foreach variant, \
+			$(if $(strip $(package/$(pkg)/variants)), \
+				$(package/$(pkg)/variants), \
+				$(if $(package/$(pkg)/default-variant), \
+					$(package/$(pkg)/default-variant), \
+					default \
+				) \
+			), \
+			$(PKG_INFO_DIR)/$(lastword $(subst /,$(space),$(pkg))).$(variant).install \
+		) \
+	)
+
+$(curdir)/cleanup: $(TMP_DIR)/.build
+	rm -rf $(STAGING_DIR_ROOT)
+
+$(curdir)/merge:
+	rm -rf $(PACKAGE_DIR_ALL)
+	mkdir -p $(PACKAGE_DIR_ALL)
+	-$(foreach pdir,$(PACKAGE_SUBDIRS),$(if $(wildcard $(pdir)/*.ipk),ln -s $(pdir)/*.ipk $(PACKAGE_DIR_ALL);))
+
+$(curdir)/merge-index: $(curdir)/merge
+	(cd $(PACKAGE_DIR_ALL) && $(SCRIPT_DIR)/ipkg-make-index.sh . 2>&1 > Packages; )
+
+$(curdir)/install: $(TMP_DIR)/.build $(curdir)/system/opkg/host/install $(curdir)/merge $(if $(CONFIG_TARGET_PER_DEVICE_ROOTFS),$(curdir)/merge-index)
+	- find $(STAGING_DIR_ROOT) -type d | $(XARGS) chmod 0755
+	rm -rf $(TARGET_DIR) $(TARGET_DIR_ORIG)
+	[ -d $(TARGET_DIR)/tmp ] || mkdir -p $(TARGET_DIR)/tmp
+	$(call opkg,$(TARGET_DIR)) install \
+		$(call opkg_package_files,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null))
+	@for file in $(PACKAGE_INSTALL_FILES); do \
+		[ -s $$file.flags ] || continue; \
+		for flag in `cat $$file.flags`; do \
+			$(call opkg,$(TARGET_DIR)) flag $$flag `cat $$file`; \
+		done; \
+	done || true
+	@-$(MAKE) package/preconfig
+
+	$(CP) $(TARGET_DIR) $(TARGET_DIR_ORIG)
+
+	$(call prepare_rootfs,$(TARGET_DIR))
+
+PASSOPT=""
+PASSARG=""
+ifndef CONFIG_OPKGSMIME_PASSPHRASE
+  ifneq ($(call qstrip,$(CONFIG_OPKGSMIME_PASSFILE)),)
+    PASSOPT="-passin"
+    PASSARG="file:$(call qstrip,$(CONFIG_OPKGSMIME_PASSFILE))"
+  endif
+endif
+
+$(curdir)/index: FORCE
+	@echo Generating package index...
+	@for d in $(PACKAGE_SUBDIRS); do ( \
+		mkdir -p $$d; \
+		cd $$d || continue; \
+		$(SCRIPT_DIR)/ipkg-make-index.sh . 2>&1 > Packages && \
+			gzip -9nc Packages > Packages.gz; \
+	); done
+ifdef CONFIG_SIGNED_PACKAGES
+	@echo Signing package index...
+	@for d in $(PACKAGE_SUBDIRS); do ( \
+		[ -d $$d ] && \
+			cd $$d || continue; \
+		$(STAGING_DIR_HOST)/bin/usign -S -m Packages -s $(BUILD_KEY); \
+	); done
+else
+ifeq ($(call qstrip,$(CONFIG_OPKGSMIME_KEY)),)
+	@echo Signing key has not been configured
+else
+ifeq ($(call qstrip,$(CONFIG_OPKGSMIME_CERT)),)
+	@echo Certificate has not been configured
+else
+	@echo Signing package index...
+	@for d in $(PACKAGE_SUBDIRS); do ( \
+		[ -d $$d ] && \
+			cd $$d || continue; \
+		openssl smime -binary -in Packages.gz \
+			-out Packages.sig -outform PEM -sign \
+			-signer $(CONFIG_OPKGSMIME_CERT) \
+			-inkey $(CONFIG_OPKGSMIME_KEY) \
+			$(PASSOPT) $(PASSARG); \
+	); done
+endif
+endif
+endif
+
+$(curdir)/preconfig:
+
+$(curdir)/flags-install:= -j1
+
+$(eval $(call stampfile,$(curdir),package,prereq,.config))
+$(eval $(call stampfile,$(curdir),package,cleanup,$(TMP_DIR)/.build))
+$(eval $(call stampfile,$(curdir),package,compile,$(TMP_DIR)/.build))
+$(eval $(call stampfile,$(curdir),package,install,$(TMP_DIR)/.build))
+
+$(eval $(call subdir,$(curdir)))
diff --git a/package/base-files/Makefile b/package/base-files/Makefile
new file mode 100644
index 0000000000..5aadd6f833
--- /dev/null
+++ b/package/base-files/Makefile
@@ -0,0 +1,177 @@
+#
+# Copyright (C) 2007-2016 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/version.mk
+
+PKG_NAME:=base-files
+PKG_RELEASE:=171
+PKG_FLAGS:=nonshared
+
+PKG_FILE_DEPENDS:=$(PLATFORM_DIR)/ $(GENERIC_PLATFORM_DIR)/base-files/
+PKG_BUILD_DEPENDS:=usign/host
+PKG_LICENSE:=GPL-2.0
+
+PKG_CONFIG_DEPENDS := CONFIG_SIGNED_PACKAGES CONFIG_TARGET_INIT_PATH CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE
+
+include $(INCLUDE_DIR)/package.mk
+
+ifneq ($(DUMP),1)
+  STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell $(SH_FUNC) echo $(CONFIG_TARGET_INIT_PATH) | md5s)
+  TARGET:=-$(BOARD)
+endif
+
+define Package/base-files
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+netifd +libc +procd +jsonfilter +SIGNED_PACKAGES:usign +SIGNED_PACKAGES:lede-keyring +fstools +fwtool
+  TITLE:=Base filesystem for Lede
+  URL:=http://openwrt.org/
+  VERSION:=$(PKG_RELEASE)-$(REVISION)
+endef
+
+define Package/base-files/conffiles
+/etc/config/network
+/etc/config/system
+/etc/hosts
+/etc/inittab
+/etc/group
+/etc/passwd
+/etc/shadow
+/etc/profile
+/etc/protocols
+/etc/services
+/etc/shells
+/etc/sysctl.conf
+/etc/rc.local
+/etc/sysupgrade.conf
+/etc/config/
+/etc/dropbear/
+/etc/crontabs/
+/etc/sysctl.d/local.conf
+/etc/sysctl.d/
+/etc/iproute2/rt_tables
+$(call $(TARGET)/conffiles)
+endef
+
+define Package/base-files/description
+ This package contains a base filesystem and system scripts for OpenWrt.
+endef
+
+define ImageConfigOptions
+	mkdir -p $(1)/lib/preinit
+	echo 'pi_suppress_stderr="$(CONFIG_TARGET_PREINIT_SUPPRESS_STDERR)"' >$(1)/lib/preinit/00_preinit.conf
+	echo 'fs_failsafe_wait_timeout=$(if $(CONFIG_TARGET_PREINIT_TIMEOUT),$(CONFIG_TARGET_PREINIT_TIMEOUT),2)' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_init_path="$(TARGET_INIT_PATH)"' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_init_env=$(if $(CONFIG_TARGET_INIT_ENV),$(CONFIG_TARGET_INIT_ENV),"")' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_init_cmd=$(if $(CONFIG_TARGET_INIT_CMD),$(CONFIG_TARGET_INIT_CMD),"/sbin/init")' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_init_suppress_stderr="$(CONFIG_TARGET_INIT_SUPPRESS_STDERR)"' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_ifname=$(if $(CONFIG_TARGET_PREINIT_IFNAME),$(CONFIG_TARGET_PREINIT_IFNAME),"")' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_ip=$(if $(CONFIG_TARGET_PREINIT_IP),$(CONFIG_TARGET_PREINIT_IP),"192.168.10.1")' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_netmask=$(if $(CONFIG_TARGET_PREINIT_NETMASK),$(CONFIG_TARGET_PREINIT_NETMASK),"255.255.255.0")' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_broadcast=$(if $(CONFIG_TARGET_PREINIT_BROADCAST),$(CONFIG_TARGET_PREINIT_BROADCAST),"192.168.10.255")' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_preinit_net_messages="$(CONFIG_TARGET_PREINIT_SHOW_NETMSG)"' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_preinit_no_failsafe_netmsg="$(CONFIG_TARGET_PREINIT_SUPPRESS_FAILSAFE_NETMSG)"' >>$(1)/lib/preinit/00_preinit.conf
+	echo 'pi_preinit_no_failsafe="$(CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE)"' >>$(1)/lib/preinit/00_preinit.conf
+endef
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Compile/Default
+
+endef
+Build/Compile = $(Build/Compile/Default)
+
+ifdef CONFIG_SIGNED_PACKAGES
+  define Build/Configure
+	[ -s $(BUILD_KEY) -a -s $(BUILD_KEY).pub ] || \
+		$(STAGING_DIR_HOST)/bin/usign -G -s $(BUILD_KEY) -p $(BUILD_KEY).pub -c "Local build key"
+
+  endef
+
+  define Package/base-files/install-key
+	mkdir -p $(1)/etc/opkg/keys
+	$(CP) $(BUILD_KEY).pub $(1)/etc/opkg/keys/`$(STAGING_DIR_HOST)/bin/usign -F -p $(BUILD_KEY).pub`
+
+  endef
+endif
+
+define Package/base-files/install
+	$(CP) ./files/* $(1)/
+	$(Package/base-files/install-key)
+	if [ -d $(GENERIC_PLATFORM_DIR)/base-files/. ]; then \
+		$(CP) $(GENERIC_PLATFORM_DIR)/base-files/* $(1)/; \
+	fi
+	if [ -d $(PLATFORM_DIR)/base-files/. ]; then \
+		$(CP) $(PLATFORM_DIR)/base-files/* $(1)/; \
+	fi
+	$(if $(filter-out $(PLATFORM_DIR),$(PLATFORM_SUBDIR)), \
+		if [ -d $(PLATFORM_SUBDIR)/base-files/. ]; then \
+			$(CP) $(PLATFORM_SUBDIR)/base-files/* $(1)/; \
+		fi; \
+	)
+
+	$(VERSION_SED) \
+		$(1)/etc/banner \
+		$(1)/etc/openwrt_version \
+		$(1)/usr/lib/os-release
+
+	$(VERSION_SED_SCRIPT) \
+		$(1)/etc/openwrt_release \
+		$(1)/etc/device_info \
+		$(1)/usr/lib/os-release
+
+	$(SED) "s#%PATH%#$(TARGET_INIT_PATH)#g" \
+		$(1)/sbin/hotplug-call \
+		$(1)/etc/preinit \
+		$(1)/etc/profile
+
+	mkdir -p $(1)/CONTROL
+	mkdir -p $(1)/dev
+	mkdir -p $(1)/etc/crontabs
+	mkdir -p $(1)/etc/rc.d
+	mkdir -p $(1)/overlay
+	mkdir -p $(1)/lib/firmware
+	$(if $(LIB_SUFFIX),-$(LN) lib $(1)/lib$(LIB_SUFFIX))
+	mkdir -p $(1)/mnt
+	mkdir -p $(1)/proc
+	mkdir -p $(1)/tmp
+	mkdir -p $(1)/usr/lib
+	$(if $(LIB_SUFFIX),-$(LN) lib $(1)/usr/lib$(LIB_SUFFIX))
+	mkdir -p $(1)/usr/bin
+	mkdir -p $(1)/sys
+	mkdir -p $(1)/www
+	mkdir -p $(1)/root
+	$(LN) /proc/mounts $(1)/etc/mtab
+	rm -f $(1)/var
+	$(LN) /tmp $(1)/var
+	mkdir -p $(1)/etc
+	$(LN) /tmp/resolv.conf /tmp/TZ /tmp/localtime $(1)/etc/
+
+	chmod 0600 $(1)/etc/shadow
+	chmod 1777 $(1)/tmp
+
+	$(call ImageConfigOptions,$(1))
+	$(call Package/base-files/install-target,$(1))
+	for conffile in $(1)/etc/config/*; do \
+		if [ -f "$$$$conffile" ]; then \
+			grep "$$$${conffile##$(1)}" $(1)/CONTROL/conffiles || \
+				echo "$$$${conffile##$(1)}" >> $(1)/CONTROL/conffiles; \
+		fi \
+	done
+endef
+
+ifneq ($(DUMP),1)
+  -include $(PLATFORM_DIR)/base-files.mk
+  -include $(PLATFORM_SUBDIR)/base-files.mk
+endif
+
+$(eval $(call BuildPackage,base-files))
diff --git a/package/base-files/files/bin/board_detect b/package/base-files/files/bin/board_detect
new file mode 100755
index 0000000000..441db6a08f
--- /dev/null
+++ b/package/base-files/files/bin/board_detect
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+CFG=$1
+
+[ -n "$CFG" ] || CFG=/etc/board.json
+
+[ -d "/etc/board.d/" -a ! -s "$CFG" ] && {
+	for a in `ls /etc/board.d/*`; do
+		[ -x $a ] || continue;
+		$(. $a)
+	done
+}
+
+[ -s "$CFG" ] || return 1
diff --git a/package/base-files/files/bin/config_generate b/package/base-files/files/bin/config_generate
new file mode 100755
index 0000000000..63d3b8d60c
--- /dev/null
+++ b/package/base-files/files/bin/config_generate
@@ -0,0 +1,437 @@
+#!/bin/sh
+
+CFG=/etc/board.json
+
+. /usr/share/libubox/jshn.sh
+
+[ -s $CFG ] || /bin/board_detect || exit 1
+[ -s /etc/config/network -a -s /etc/config/system ] && exit 0
+
+generate_static_network() {
+	uci -q batch <<-EOF
+		delete network.loopback
+		set network.loopback='interface'
+		set network.loopback.ifname='lo'
+		set network.loopback.proto='static'
+		set network.loopback.ipaddr='127.0.0.1'
+		set network.loopback.netmask='255.0.0.0'
+		delete network.globals
+		set network.globals='globals'
+		set network.globals.ula_prefix='auto'
+	EOF
+
+	if json_is_a dsl object; then
+		json_select dsl
+			if json_is_a atmbridge object; then
+				json_select atmbridge
+					local vpi vci encaps payload
+					json_get_vars vpi vci encaps payload
+					uci -q batch <<-EOF
+						delete network.atm
+						set network.atm='atm-bridge'
+						set network.atm.vpi='$vpi'
+						set network.atm.vci='$vci'
+						set network.atm.encaps='$encaps'
+						set network.atm.payload='$payload'
+					EOF
+				json_select ..
+			fi
+
+			if json_is_a modem object; then
+				json_select modem
+					local type annex firmware tone xfer_mode
+					json_get_vars type annex firmware tone xfer_mode
+					uci -q batch <<-EOF
+						delete network.dsl
+						set network.dsl='dsl'
+						set network.dsl.annex='$annex'
+						set network.dsl.firmware='$firmware'
+						set network.dsl.tone='$tone'
+						set network.dsl.xfer_mode='$xfer_mode'
+					EOF
+				json_select ..
+			fi
+		json_select ..
+	fi
+}
+
+addr_offset=2
+generate_network() {
+	local ifname macaddr protocol type ipaddr netmask
+
+	json_select network
+		json_select "$1"
+			json_get_vars ifname macaddr protocol ipaddr netmask
+		json_select ..
+	json_select ..
+
+	[ -n "$ifname" ] || return
+
+	# force bridge for multi-interface devices (and lan)
+	case "$1:$ifname" in
+		*\ * | lan:*) type="bridge" ;;
+	esac
+
+	uci -q batch <<-EOF
+		delete network.$1
+		set network.$1='interface'
+		set network.$1.type='$type'
+		set network.$1.ifname='$ifname'
+		set network.$1.proto='none'
+	EOF
+
+	[ -n "$macaddr" ] && uci -q batch <<-EOF
+		delete network.$1_dev
+		set network.$1_dev='device'
+		set network.$1_dev.name='$ifname'
+		set network.$1_dev.macaddr='$macaddr'
+	EOF
+
+	case "$protocol" in
+		static)
+			local ipad
+			case "$1" in
+				lan) ipad=${ipaddr:-"192.168.10.1"} ;;
+				*) ipad=${ipaddr:-"192.168.$((addr_offset++)).1"} ;;
+			esac
+
+			netm=${netmask:-"255.255.255.0"}
+
+			uci -q batch <<-EOF
+				set network.$1.proto='static'
+				set network.$1.ipaddr='$ipad'
+				set network.$1.netmask='$netm'
+				set network.$1.ip6assign='60'
+			EOF
+		;;
+
+		dhcp)
+			# fixup IPv6 slave interface if parent is a bridge
+			[ "$type" = "bridge" ] && ifname="br-$1"
+
+			uci -q batch <<-EOF
+				set network.$1.proto='dhcp'
+				delete network.${1}6
+				set network.${1}6='interface'
+				set network.${1}6.ifname='$ifname'
+				set network.${1}6.proto='dhcpv6'
+			EOF
+		;;
+
+		pppoe)
+			# fixup IPv6 slave interface
+			ifname="pppoe-$1"
+
+			uci -q batch <<-EOF
+				set network.$1.proto='pppoe'
+				set network.$1.username='username'
+				set network.$1.password='password'
+				set network.$1.ipv6='auto'
+				delete network.${1}6
+				set network.${1}6='interface'
+				set network.${1}6.ifname='$ifname'
+				set network.${1}6.proto='dhcpv6'
+			EOF
+		;;
+	esac
+}
+
+generate_switch_vlans_ports() {
+	local switch="$1"
+	local port ports role roles num attr val
+
+	#
+	# autogenerate vlans
+	#
+
+	if json_is_a roles array; then
+		json_get_keys roles roles
+		json_select roles
+
+		for role in $roles; do
+			json_select "$role"
+				json_get_vars ports
+			json_select ..
+
+			uci -q batch <<-EOF
+				add network switch_vlan
+				set network.@switch_vlan[-1].device='$switch'
+				set network.@switch_vlan[-1].vlan='$role'
+				set network.@switch_vlan[-1].ports='$ports'
+			EOF
+		done
+
+		json_select ..
+	fi
+
+
+	#
+	# write port specific settings
+	#
+
+	if json_is_a ports array; then
+		json_get_keys ports ports
+		json_select ports
+
+		for port in $ports; do
+			json_select "$port"
+				json_get_vars num
+
+				if json_is_a attr object; then
+					json_get_keys attr attr
+					json_select attr
+						uci -q batch <<-EOF
+							add network switch_port
+							set network.@switch_port[-1].device='$switch'
+							set network.@switch_port[-1].port=$num
+						EOF
+
+						for attr in $attr; do
+							json_get_var val "$attr"
+							uci -q set network.@switch_port[-1].$attr="$val"
+						done
+					json_select ..
+				fi
+			json_select ..
+		done
+
+		json_select ..
+	fi
+}
+
+generate_switch() {
+	local key="$1"
+	local vlans
+
+	json_select switch
+	json_select "$key"
+	json_get_vars enable reset blinkrate cpu_port
+
+	uci -q batch <<-EOF
+		add network switch
+		set network.@switch[-1].name='$key'
+		set network.@switch[-1].reset='$reset'
+		set network.@switch[-1].enable_vlan='$enable'
+		set network.@switch[-1].blinkrate='$blinkrate'
+	EOF
+
+	generate_switch_vlans_ports "$1"
+
+	json_select ..
+	json_select ..
+}
+
+
+generate_static_system() {
+	uci -q batch <<-EOF
+		delete system.@system[0]
+		add system system
+		set system.@system[-1].hostname='libreCMC'
+		set system.@system[-1].timezone='UTC'
+		set system.@system[-1].ttylogin='0'
+		set system.@system[-1].log_size='64'
+		set system.@system[-1].urandom_seed='0'
+
+		delete system.ntp
+		set system.ntp='timeserver'
+		set system.ntp.enabled='1'
+		set system.ntp.enable_server='0'
+		add_list system.ntp.server='0.lede.pool.ntp.org'
+		add_list system.ntp.server='1.lede.pool.ntp.org'
+		add_list system.ntp.server='2.lede.pool.ntp.org'
+		add_list system.ntp.server='3.lede.pool.ntp.org'
+	EOF
+
+	if json_is_a system object; then
+		json_select system
+			local hostname
+			if json_get_var hostname hostname; then
+				uci -q set "system.@system[-1].hostname=$hostname"
+			fi
+
+			if json_is_a ntpserver array; then
+				local keys key
+				json_get_keys keys ntpserver
+				json_select ntpserver
+					uci -q delete "system.ntp.server"
+
+					for key in $keys; do
+						local server
+						if json_get_var server "$key"; then
+							uci -q add_list "system.ntp.server=$server"
+						fi
+					done
+				json_select ..
+			fi
+		json_select ..
+	fi
+}
+
+generate_rssimon() {
+	local key="$1"
+	local cfg="rssid_$key"
+	local refresh threshold
+
+	json_select rssimon
+	json_select "$key"
+	json_get_vars refresh threshold
+	json_select ..
+	json_select ..
+
+	uci -q batch <<-EOF
+		delete system.$cfg
+		set system.$cfg='rssid'
+		set system.$cfg.dev='$key'
+		set system.$cfg.refresh='$refresh'
+		set system.$cfg.threshold='$threshold'
+	EOF
+}
+
+generate_led() {
+	local key="$1"
+	local cfg="led_$key"
+
+	json_select led
+	json_select "$key"
+	json_get_vars name sysfs type trigger default
+
+	uci -q batch <<-EOF
+		delete system.$cfg
+		set system.$cfg='led'
+		set system.$cfg.name='$name'
+		set system.$cfg.sysfs='$sysfs'
+		set system.$cfg.trigger='$trigger'
+		set system.$cfg.default='$default'
+	EOF
+
+	case "$type" in
+		gpio)
+			local gpio inverted
+			json_get_vars gpio inverted
+			uci -q batch <<-EOF
+				set system.$cfg.trigger='gpio'
+				set system.$cfg.gpio='$gpio'
+				set system.$cfg.inverted='$inverted'
+			EOF
+		;;
+
+		netdev)
+			local device mode
+			json_get_vars device mode
+			uci -q batch <<-EOF
+				set system.$cfg.trigger='netdev'
+				set system.$cfg.mode='$mode'
+				set system.$cfg.dev='$device'
+			EOF
+		;;
+
+		usb)
+			local device
+			json_get_vars device
+			uci -q batch <<-EOF
+				set system.$cfg.trigger='usbdev'
+				set system.$cfg.interval='50'
+				set system.$cfg.dev='$device'
+			EOF
+		;;
+
+		usbport)
+			local ports port
+			json_get_values ports ports
+			uci set system.$cfg.trigger='usbport'
+			for port in $ports; do
+				uci add_list system.$cfg.port=$port
+			done
+		;;
+
+		rssi)
+			local iface minq maxq offset factor
+			json_get_vars iface minq maxq offset factor
+			uci -q batch <<-EOF
+				set system.$cfg.trigger='rssi'
+				set system.$cfg.iface='rssid_$iface'
+				set system.$cfg.minq='$minq'
+				set system.$cfg.maxq='$maxq'
+				set system.$cfg.offset='$offset'
+				set system.$cfg.factor='$factor'
+			EOF
+		;;
+
+		switch)
+			local port_mask speed_mask
+			json_get_vars port_mask speed_mask
+			uci -q batch <<-EOF
+				set system.$cfg.port_mask='$port_mask'
+				set system.$cfg.speed_mask='$speed_mask'
+			EOF
+		;;
+
+		portstate)
+			local port_state
+			json_get_vars port_state
+			uci -q batch <<-EOF
+				set system.$cfg.port_state='$port_state'
+			EOF
+		;;
+
+		timer|oneshot)
+			local delayon delayoff
+			json_get_vars delayon delayoff
+			uci -q batch <<-EOF
+				set system.$cfg.trigger='$type'
+				set system.$cfg.delayon='$delayon'
+				set system.$cfg.delayoff='$delayoff'
+			EOF
+		;;
+	esac
+
+	json_select ..
+	json_select ..
+}
+
+generate_gpioswitch() {
+	local cfg="$1"
+
+	json_select gpioswitch
+		json_select "$cfg"
+			local name pin default
+			json_get_vars name pin default
+			uci -q batch <<-EOF
+				delete system.$cfg
+				set system.$cfg='gpio_switch'
+				set system.$cfg.name='$name'
+				set system.$cfg.gpio_pin='$pin'
+				set system.$cfg.default='$default'
+			EOF
+		json_select ..
+	json_select ..
+}
+
+json_init
+json_load "$(cat ${CFG})"
+
+if [ ! -s /etc/config/network ]; then
+	touch /etc/config/network
+	generate_static_network
+
+	json_get_keys keys network
+	for key in $keys; do generate_network $key; done
+
+	json_get_keys keys switch
+	for key in $keys; do generate_switch $key; done
+fi
+
+if [ ! -s /etc/config/system ]; then
+	touch /etc/config/system
+	generate_static_system
+
+	json_get_keys keys rssimon
+	for key in $keys; do generate_rssimon $key; done
+
+	json_get_keys keys gpioswitch
+	for key in $keys; do generate_gpioswitch $key; done
+
+	json_get_keys keys led
+	for key in $keys; do generate_led $key; done
+fi
+uci commit
diff --git a/package/base-files/files/bin/ipcalc.sh b/package/base-files/files/bin/ipcalc.sh
new file mode 100755
index 0000000000..5d5eac3ea8
--- /dev/null
+++ b/package/base-files/files/bin/ipcalc.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+awk -f - $* <<EOF
+function bitcount(c) {
+	c=and(rshift(c, 1),0x55555555)+and(c,0x55555555)
+	c=and(rshift(c, 2),0x33333333)+and(c,0x33333333)
+	c=and(rshift(c, 4),0x0f0f0f0f)+and(c,0x0f0f0f0f)
+	c=and(rshift(c, 8),0x00ff00ff)+and(c,0x00ff00ff)
+	c=and(rshift(c,16),0x0000ffff)+and(c,0x0000ffff)
+	return c
+}
+
+function ip2int(ip) {
+	for (ret=0,n=split(ip,a,"\."),x=1;x<=n;x++) ret=or(lshift(ret,8),a[x])
+	return ret
+}
+
+function int2ip(ip,ret,x) {
+	ret=and(ip,255)
+	ip=rshift(ip,8)
+	for(;x<3;ret=and(ip,255)"."ret,ip=rshift(ip,8),x++);
+	return ret
+}
+
+function compl32(v) {
+	ret=xor(v, 0xffffffff)
+	return ret
+}
+
+BEGIN {
+	slpos=index(ARGV[1],"/")
+	if (slpos == 0) {
+		ipaddr=ip2int(ARGV[1])
+		dotpos=index(ARGV[2],".")
+		if (dotpos == 0)
+			netmask=compl32(2**(32-int(ARGV[2]))-1)
+		else
+			netmask=ip2int(ARGV[2])
+	} else {
+		ipaddr=ip2int(substr(ARGV[1],0,slpos-1))
+		netmask=compl32(2**(32-int(substr(ARGV[1],slpos+1)))-1)
+		ARGV[4]=ARGV[3]
+		ARGV[3]=ARGV[2]
+	}
+
+	network=and(ipaddr,netmask)
+	broadcast=or(network,compl32(netmask))
+
+	start=or(network,and(ip2int(ARGV[3]),compl32(netmask)))
+	limit=network+1
+	if (start<limit) start=limit
+
+	end=start+ARGV[4]
+	limit=or(network,compl32(netmask))-1
+	if (end>limit) end=limit
+
+	print "IP="int2ip(ipaddr)
+	print "NETMASK="int2ip(netmask)
+	print "BROADCAST="int2ip(broadcast)
+	print "NETWORK="int2ip(network)
+	print "PREFIX="32-bitcount(compl32(netmask))
+
+	# range calculations:
+	# ipcalc <ip> <netmask> <start> <num>
+
+	if (ARGC > 3) {
+		print "START="int2ip(start)
+		print "END="int2ip(end)
+	}
+}
+EOF
diff --git a/package/base-files/files/etc/banner b/package/base-files/files/etc/banner
new file mode 100644
index 0000000000..c4dc4efb81
--- /dev/null
+++ b/package/base-files/files/etc/banner
@@ -0,0 +1,9 @@
+
+                    ____  _____  ____
+  _ _ _            |  __||     ||  __|
+ | (_) |__ _ _ ___ | |   | | | || |
+ | | | '_ \ '_/ -_)| |__ | | | || |__
+ |_|_|_.__/_| \___||____||_|_|_||____|
+ -----------------------------------------
+ %C Version: %V
+
diff --git a/package/base-files/files/etc/banner.failsafe b/package/base-files/files/etc/banner.failsafe
new file mode 100644
index 0000000000..14615e1ef7
--- /dev/null
+++ b/package/base-files/files/etc/banner.failsafe
@@ -0,0 +1,13 @@
+================= FAILSAFE MODE active ================
+special commands:
+* firstboot	     reset settings to factory defaults
+* mount_root	 mount root-partition with config files
+
+after mount_root:
+* passwd			 change root's password
+* /etc/config		    directory with config files
+
+for more help see:
+http://wiki.openwrt.org/doc/howto/generic.failsafe
+=======================================================
+
diff --git a/package/base-files/files/etc/board.d/99-default_network b/package/base-files/files/etc/board.d/99-default_network
new file mode 100755
index 0000000000..d70aa352b9
--- /dev/null
+++ b/package/base-files/files/etc/board.d/99-default_network
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2015 OpenWrt.org
+#
+
+. /lib/functions/uci-defaults.sh
+
+board_config_update
+
+json_is_a network object && exit 0
+
+ucidef_set_interface_lan 'eth0'
+[ -d /sys/class/net/eth1 ] && ucidef_set_interface_wan 'eth1'
+
+board_config_flush
+
+exit 0
diff --git a/package/base-files/files/etc/device_info b/package/base-files/files/etc/device_info
new file mode 100644
index 0000000000..4045e9e027
--- /dev/null
+++ b/package/base-files/files/etc/device_info
@@ -0,0 +1,4 @@
+DEVICE_MANUFACTURER='%M'
+DEVICE_MANUFACTURER_URL='%m'
+DEVICE_PRODUCT='%P'
+DEVICE_REVISION='%h'
diff --git a/package/base-files/files/etc/diag.sh b/package/base-files/files/etc/diag.sh
new file mode 100644
index 0000000000..8726a4398b
--- /dev/null
+++ b/package/base-files/files/etc/diag.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Copyright (C) 2006-2009 OpenWrt.org
+
+set_state() { :; }
diff --git a/package/base-files/files/etc/fstab b/package/base-files/files/etc/fstab
new file mode 100644
index 0000000000..6e9b7baf53
--- /dev/null
+++ b/package/base-files/files/etc/fstab
@@ -0,0 +1 @@
+# <file system> <mount point> <type> <options> <dump> <pass>
diff --git a/package/base-files/files/etc/group b/package/base-files/files/etc/group
new file mode 100644
index 0000000000..d36685139a
--- /dev/null
+++ b/package/base-files/files/etc/group
@@ -0,0 +1,10 @@
+root:x:0:
+daemon:x:1:
+adm:x:4:
+mail:x:8:
+audio:x:29:
+www-data:x:33:
+ftp:x:55:
+users:x:100:
+network:x:101:
+nogroup:x:65534:
diff --git a/package/base-files/files/etc/hosts b/package/base-files/files/etc/hosts
new file mode 100644
index 0000000000..b7713ebcc6
--- /dev/null
+++ b/package/base-files/files/etc/hosts
@@ -0,0 +1,5 @@
+127.0.0.1 localhost
+
+::1     localhost ip6-localhost ip6-loopback
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
diff --git a/package/base-files/files/etc/hotplug.d/net/00-sysctl b/package/base-files/files/etc/hotplug.d/net/00-sysctl
new file mode 100644
index 0000000000..7a71652c44
--- /dev/null
+++ b/package/base-files/files/etc/hotplug.d/net/00-sysctl
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ "$ACTION" = add ]; then
+	for CONF in /etc/sysctl.conf /etc/sysctl.d/*.conf; do
+		[ ! -f "$CONF" ] && continue;
+		sed -ne "/^[[:space:]]*net\..*\.$DEVICENAME\./p" "$CONF" | \
+			sysctl -e -p - | logger -t sysctl
+	done
+fi
diff --git a/package/base-files/files/etc/init.d/boot b/package/base-files/files/etc/init.d/boot
new file mode 100755
index 0000000000..31f245ffc7
--- /dev/null
+++ b/package/base-files/files/etc/init.d/boot
@@ -0,0 +1,51 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006-2011 OpenWrt.org
+
+START=10
+STOP=98
+
+uci_apply_defaults() {
+	. /lib/functions/system.sh
+
+	cd /etc/uci-defaults || return 0
+	files="$(ls)"
+	[ -z "$files" ] && return 0
+	mkdir -p /tmp/.uci
+	for file in $files; do
+		( . "./$(basename $file)" ) && rm -f "$file"
+	done
+	uci commit
+}
+
+boot() {
+	[ -f /proc/mounts ] || /sbin/mount_root
+	[ -f /proc/jffs2_bbc ] && echo "S" > /proc/jffs2_bbc
+	[ -f /proc/net/vlan/config ] && vconfig set_name_type DEV_PLUS_VID_NO_PAD
+
+	mkdir -p /var/run
+	mkdir -p /var/log
+	mkdir -p /var/lock
+	mkdir -p /var/state
+	mkdir -p /var/tmp
+	mkdir -p /tmp/.uci
+	chmod 0700 /tmp/.uci
+	touch /var/log/wtmp
+	touch /var/log/lastlog
+	touch /tmp/resolv.conf.auto
+	ln -sf /tmp/resolv.conf.auto /tmp/resolv.conf
+	grep -q debugfs /proc/filesystems && /bin/mount -o noatime -t debugfs debugfs /sys/kernel/debug
+	[ "$FAILSAFE" = "true" ] && touch /tmp/.failsafe
+
+	/sbin/kmodloader
+
+	[ ! -f /etc/config/wireless ] && {
+		# compat for brcm47xx and mvebu
+		sleep 1
+	}
+
+	/bin/config_generate
+	uci_apply_defaults
+	
+	# temporary hack until configd exists
+	/sbin/reload_config
+}
diff --git a/package/base-files/files/etc/init.d/done b/package/base-files/files/etc/init.d/done
new file mode 100755
index 0000000000..374353a23c
--- /dev/null
+++ b/package/base-files/files/etc/init.d/done
@@ -0,0 +1,17 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+START=95
+boot() {
+	mount_root done
+	rm -f /sysupgrade.tgz
+
+	# process user commands
+	[ -f /etc/rc.local ] && {
+		sh /etc/rc.local
+	}
+
+	# set leds to normal state
+	. /etc/diag.sh
+	set_state done
+}
diff --git a/package/base-files/files/etc/init.d/gpio_switch b/package/base-files/files/etc/init.d/gpio_switch
new file mode 100755
index 0000000000..1f1b44b212
--- /dev/null
+++ b/package/base-files/files/etc/init.d/gpio_switch
@@ -0,0 +1,42 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2015 OpenWrt.org
+
+START=98
+STOP=10
+USE_PROCD=1
+
+
+load_gpio_switch()
+{
+	local name
+	local gpio_pin
+	local value
+
+	config_get gpio_pin "$1" gpio_pin
+	config_get name "$1" name
+	config_get value "$1" value 0
+
+	local gpio_path="/sys/class/gpio/gpio${gpio_pin}"
+	# export GPIO pin for access
+	[ -d "$gpio_path" ] || {
+		echo "$gpio_pin" >/sys/class/gpio/export
+		# we need to wait a bit until the GPIO appears
+		[ -d "$gpio_path" ] || sleep 1
+		echo out >"$gpio_path/direction"
+	}
+	# write 0 or 1 to the "value" field
+	{ [ "$value" = "0" ] && echo "0" || echo "1"; } >"$gpio_path/value"
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "system"
+}
+
+start_service()
+{
+	[ -e /sys/class/gpio/ ] && {
+		config_load system
+		config_foreach load_gpio_switch gpio_switch
+	}
+}
diff --git a/package/base-files/files/etc/init.d/led b/package/base-files/files/etc/init.d/led
new file mode 100755
index 0000000000..7c2a185013
--- /dev/null
+++ b/package/base-files/files/etc/init.d/led
@@ -0,0 +1,134 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2008 OpenWrt.org
+
+START=96
+
+load_led() {
+	local name
+	local sysfs
+	local trigger
+	local dev
+	local ports
+	local mode
+	local default
+	local delayon
+	local delayoff
+	local interval
+
+	config_get sysfs $1 sysfs
+	config_get name $1 name "$sysfs"
+	config_get trigger $1 trigger "none"
+	config_get dev $1 dev
+	config_get ports $1 port
+	config_get mode $1 mode "link"
+	config_get_bool default $1 default "nil"
+	config_get delayon $1 delayon
+	config_get delayoff $1 delayoff
+	config_get interval $1 interval "50"
+	config_get port_state $1 port_state
+	config_get delay $1 delay "150"
+	config_get message $1 message ""
+	config_get gpio $1 gpio "0"
+	config_get inverted $1 inverted "0"
+
+	if [ "$trigger" = "rssi" ]; then
+		# handled by rssileds userspace process
+		return
+	fi
+
+	[ "$trigger" = "usbdev" ] && {
+		# Backward compatibility: translate to the new trigger
+		trigger="usbport"
+		# Translate port of root hub, e.g. 4-1 -> usb4-port1
+		ports=$(echo "$dev" | sed -n 's/^\([0-9]*\)-\([0-9]*\)$/usb\1-port\2/p')
+		# Translate port of extra hub, e.g. 2-2.4 -> 2-2-port4
+		[ -z "$ports" ] && ports=$(echo "$dev" | sed -n 's/\./-port/p')
+	}
+
+	[ -e /sys/class/leds/${sysfs}/brightness ] && {
+		echo "setting up led ${name}"
+
+		printf "%s %s %d\n" \
+			"$sysfs" \
+			"$(sed -ne 's/^.*\[\(.*\)\].*$/\1/p' /sys/class/leds/${sysfs}/trigger)" \
+			"$(cat /sys/class/leds/${sysfs}/brightness)" \
+				>> /var/run/led.state
+
+		[ "$default" = 0 ] &&
+			echo 0 >/sys/class/leds/${sysfs}/brightness
+
+		echo $trigger > /sys/class/leds/${sysfs}/trigger 2> /dev/null
+		ret="$?"
+
+		[ $default = 1 ] &&
+			cat /sys/class/leds/${sysfs}/max_brightness > /sys/class/leds/${sysfs}/brightness
+
+		[ $ret = 0 ] || {
+			echo >&2 "Skipping trigger '$trigger' for led '$name' due to missing kernel module"
+			return 1
+		}
+		case "$trigger" in
+		"netdev")
+			[ -n "$dev" ] && {
+				echo $dev > /sys/class/leds/${sysfs}/device_name
+				echo $mode > /sys/class/leds/${sysfs}/mode
+			}
+			;;
+
+		"timer"|"oneshot")
+			[ -n "$delayon" ] && \
+				echo $delayon > /sys/class/leds/${sysfs}/delay_on
+			[ -n "$delayoff" ] && \
+				echo $delayoff > /sys/class/leds/${sysfs}/delay_off
+			;;
+
+		"usbport")
+			local p
+
+			for p in $ports; do
+				echo 1 > /sys/class/leds/${sysfs}/ports/$p
+			done
+			;;
+
+		"port_state")
+			[ -n "$port_state" ] && \
+				echo $port_state > /sys/class/leds/${sysfs}/port_state
+			;;
+
+		"gpio")
+			echo $gpio > /sys/class/leds/${sysfs}/gpio
+			echo $inverted > /sys/class/leds/${sysfs}/inverted
+			;;
+
+		switch[0-9]*)
+			local port_mask speed_mask
+
+			config_get port_mask $1 port_mask
+			[ -n "$port_mask" ] && \
+				echo $port_mask > /sys/class/leds/${sysfs}/port_mask
+			config_get speed_mask $1 speed_mask
+			[ -n "$speed_mask" ] && \
+				echo $speed_mask > /sys/class/leds/${sysfs}/speed_mask
+			;;
+		esac
+	}
+}
+
+start() {
+	[ -e /sys/class/leds/ ] && {
+		[ -s /var/run/led.state ] && {
+			local led trigger brightness
+			while read led trigger brightness; do
+				[ -e "/sys/class/leds/$led/trigger" ] && \
+					echo "$trigger" > "/sys/class/leds/$led/trigger"
+
+				[ -e "/sys/class/leds/$led/brightness" ] && \
+					echo "$brightness" > "/sys/class/leds/$led/brightness"
+			done < /var/run/led.state
+			rm /var/run/led.state
+		}
+
+		config_load system
+		config_foreach load_led led
+	}
+}
diff --git a/package/base-files/files/etc/init.d/sysctl b/package/base-files/files/etc/init.d/sysctl
new file mode 100755
index 0000000000..3a497fb66c
--- /dev/null
+++ b/package/base-files/files/etc/init.d/sysctl
@@ -0,0 +1,25 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+START=11
+
+set_vm_min_free() {
+	mem="$(grep MemTotal /proc/meminfo  | awk '{print $2}')"
+	if [ "$mem" -gt 65536 ]; then # 128M
+		val=16384
+	elif [ "$mem" -gt 32768 ]; then # 64M
+		val=8192
+	elif [ "$mem" -gt 16384 ]; then # 32M
+		val=1024
+	else
+		return
+	fi
+	sysctl -qw vm.min_free_kbytes="$val"
+}
+
+start() {
+	set_vm_min_free
+	for CONF in /etc/sysctl.conf /etc/sysctl.d/*.conf; do
+		[ -f "$CONF" ] && sysctl -p "$CONF" -e >&-
+	done
+}
diff --git a/package/base-files/files/etc/init.d/sysfixtime b/package/base-files/files/etc/init.d/sysfixtime
new file mode 100755
index 0000000000..aab5b153d0
--- /dev/null
+++ b/package/base-files/files/etc/init.d/sysfixtime
@@ -0,0 +1,34 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2013-2014 OpenWrt.org
+
+START=00
+STOP=90
+
+RTC_DEV=/dev/rtc0
+HWCLOCK=/sbin/hwclock
+
+boot() {
+	start && exit 0
+
+	local maxtime="$(maxtime)"
+	local curtime="$(date +%s)"
+	[ $curtime -lt $maxtime ] && date -s @$maxtime
+}
+
+start() {
+	[ -e "$RTC_DEV" ] && [ -e "$HWCLOCK" ] && $HWCLOCK -s -u -f $RTC_DEV
+}
+
+stop() {
+	[ -e "$RTC_DEV" ] && [ -e "$HWCLOCK" ] && $HWCLOCK -w -u -f $RTC_DEV && \
+		logger -t sysfixtime "saved '$(date)' to $RTC_DEV"
+}
+
+maxtime() {
+	local file newest
+
+	for file in $( find /etc -type f ) ; do
+		[ -z "$newest" -o "$newest" -ot "$file" ] && newest=$file
+	done
+	[ "$newest" ] && date -r "$newest" +%s
+}
diff --git a/package/base-files/files/etc/init.d/system b/package/base-files/files/etc/init.d/system
new file mode 100755
index 0000000000..0d243a8a99
--- /dev/null
+++ b/package/base-files/files/etc/init.d/system
@@ -0,0 +1,50 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2014 OpenWrt.org
+
+START=10
+USE_PROCD=1
+
+validate_system_section()
+{
+	uci_validate_section system system "${1}" \
+		'hostname:string:libreCMC' \
+		'conloglevel:uinteger' \
+		'buffersize:uinteger' \
+		'timezone:string:UTC' \
+		'zonename:string'
+}
+
+system_config() {
+	local cfg="$1"
+
+	local hostname conloglevel buffersize timezone zonename
+
+	validate_system_section "${1}" || {
+		echo "validation failed"
+		return 1
+	}
+
+	echo "$hostname" > /proc/sys/kernel/hostname
+	[ -z "$conloglevel" -a -z "$buffersize" ] || dmesg ${conloglevel:+-n $conloglevel} ${buffersize:+-s $buffersize}
+	echo "$timezone" > /tmp/TZ
+	[ -n "$zonename" ] && [ -f "/usr/share/zoneinfo/$zonename" ] && \
+		ln -sf "/usr/share/zoneinfo/$zonename" /tmp/localtime && rm -f /tmp/TZ
+
+	# apply timezone to kernel
+	date -k
+}
+
+reload_service() {
+	config_load system
+	config_foreach system_config system
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "system"
+	procd_add_validation validate_system_section
+}
+
+start_service() {
+	reload_service
+}
diff --git a/package/base-files/files/etc/init.d/umount b/package/base-files/files/etc/init.d/umount
new file mode 100755
index 0000000000..349b2b3264
--- /dev/null
+++ b/package/base-files/files/etc/init.d/umount
@@ -0,0 +1,8 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+STOP=99
+stop() {
+	sync
+	/bin/umount -a -d -r
+}
diff --git a/package/base-files/files/etc/init.d/urandom_seed b/package/base-files/files/etc/init.d/urandom_seed
new file mode 100755
index 0000000000..17d9c13400
--- /dev/null
+++ b/package/base-files/files/etc/init.d/urandom_seed
@@ -0,0 +1,12 @@
+#!/bin/sh /etc/rc.common
+
+START=99
+USE_PROCD=1
+
+start_service() {
+    procd_open_instance "urandom_seed"
+    procd_set_param command "/sbin/urandom_seed"
+    procd_set_param stdout 1
+    procd_set_param stderr 1
+    procd_close_instance
+}
diff --git a/package/base-files/files/etc/inittab b/package/base-files/files/etc/inittab
new file mode 100644
index 0000000000..9820e7144b
--- /dev/null
+++ b/package/base-files/files/etc/inittab
@@ -0,0 +1,3 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+::askconsole:/usr/libexec/login.sh
diff --git a/package/base-files/files/etc/iproute2/rt_tables b/package/base-files/files/etc/iproute2/rt_tables
new file mode 100644
index 0000000000..5fc09b3c0c
--- /dev/null
+++ b/package/base-files/files/etc/iproute2/rt_tables
@@ -0,0 +1,12 @@
+#
+# reserved values
+#
+128	prelocal
+255	local
+254	main
+253	default
+0	unspec
+#
+# local
+#
+#1	inr.ruhep
diff --git a/package/base-files/files/etc/openwrt_release b/package/base-files/files/etc/openwrt_release
new file mode 100644
index 0000000000..46ad63209f
--- /dev/null
+++ b/package/base-files/files/etc/openwrt_release
@@ -0,0 +1,7 @@
+DISTRIB_ID='%D'
+DISTRIB_RELEASE='%V'
+DISTRIB_REVISION='%R'
+DISTRIB_CODENAME='%n'
+DISTRIB_TARGET='%S'
+DISTRIB_DESCRIPTION='%D %N %V %C'
+DISTRIB_TAINTS='%t'
diff --git a/package/base-files/files/etc/openwrt_version b/package/base-files/files/etc/openwrt_version
new file mode 100644
index 0000000000..48157ed97f
--- /dev/null
+++ b/package/base-files/files/etc/openwrt_version
@@ -0,0 +1 @@
+%C
diff --git a/package/base-files/files/etc/os-release b/package/base-files/files/etc/os-release
new file mode 120000
index 0000000000..c4c75b419c
--- /dev/null
+++ b/package/base-files/files/etc/os-release
@@ -0,0 +1 @@
+../usr/lib/os-release
\ No newline at end of file
diff --git a/package/base-files/files/etc/passwd b/package/base-files/files/etc/passwd
new file mode 100644
index 0000000000..1d06a80361
--- /dev/null
+++ b/package/base-files/files/etc/passwd
@@ -0,0 +1,5 @@
+root:x:0:0:root:/root:/bin/ash
+daemon:*:1:1:daemon:/var:/bin/false
+ftp:*:55:55:ftp:/home/ftp:/bin/false
+network:*:101:101:network:/var:/bin/false
+nobody:*:65534:65534:nobody:/var:/bin/false
diff --git a/package/base-files/files/etc/preinit b/package/base-files/files/etc/preinit
new file mode 100755
index 0000000000..829574f5f1
--- /dev/null
+++ b/package/base-files/files/etc/preinit
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Copyright (C) 2006-2016 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+[ -z "$PREINIT" ] && exec /sbin/init
+
+export PATH="%PATH%"
+
+. /lib/functions.sh
+. /lib/functions/preinit.sh
+. /lib/functions/system.sh
+
+boot_hook_init preinit_essential
+boot_hook_init preinit_main
+boot_hook_init failsafe
+boot_hook_init initramfs
+boot_hook_init preinit_mount_root
+
+for pi_source_file in /lib/preinit/*; do
+	. $pi_source_file
+done
+
+boot_run_hook preinit_essential
+
+pi_mount_skip_next=false
+pi_jffs2_mount_success=false
+pi_failsafe_net_message=false
+
+boot_run_hook preinit_main
diff --git a/package/base-files/files/etc/profile b/package/base-files/files/etc/profile
new file mode 100644
index 0000000000..bb69ffbd3e
--- /dev/null
+++ b/package/base-files/files/etc/profile
@@ -0,0 +1,52 @@
+#!/bin/sh
+[ -f /etc/banner ] && cat /etc/banner
+[ -e /tmp/.failsafe ] && cat /etc/banner.failsafe
+fgrep -sq '/ overlay ro,' /proc/mounts && {
+	echo 'Your JFFS2-partition seems full and overlayfs is mounted read-only.'
+	echo 'Please try to remove files from /overlay/upper/... and reboot!'
+}
+
+export PATH="%PATH%"
+export HOME=$(grep -e "^${USER:-root}:" /etc/passwd | cut -d ":" -f 6)
+export HOME=${HOME:-/root}
+export PS1='\u@\h:\w\$ '
+
+[ "$TERM" = "xterm" ] && export PS1='\[\e]0;\u@\h: \w\a\]'$PS1
+
+[ -x /bin/more ] || alias more=less
+[ -x /usr/bin/vim ] && alias vi=vim || alias vim=vi
+
+alias ll='ls -alF --color=auto'
+
+[ -z "$KSH_VERSION" -o \! -s /etc/mkshrc ] || . /etc/mkshrc
+
+[ -x /usr/bin/arp -o -x /sbin/arp ] || arp() { cat /proc/net/arp; }
+[ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; }
+
+[ -n "$FAILSAFE" ] || {
+	for FILE in /etc/profile.d/*.sh; do
+		[ -e "$FILE" ] && . "$FILE"
+	done
+	unset FILE
+}
+
+if ( grep -qs '^root::' /etc/shadow && \
+     [ -z "$FAILSAFE" ] )
+then
+cat << EOF
+=== WARNING! =====================================
+There is no root password defined on this device!
+Use the "passwd" command to set up a new password
+in order to prevent unauthorized SSH logins.
+--------------------------------------------------
+EOF
+fi
+
+service() {
+	[ -f "/etc/init.d/$1" ] || {
+		echo -n "$1 does not exist. the following services are available :"
+		ls "/etc/init.d"
+		return 1
+	}
+	/etc/init.d/$@
+}
diff --git a/package/base-files/files/etc/protocols b/package/base-files/files/etc/protocols
new file mode 100644
index 0000000000..26bc775ed6
--- /dev/null
+++ b/package/base-files/files/etc/protocols
@@ -0,0 +1,57 @@
+# Internet (IP) protocols
+#
+# Updated from http://www.iana.org/assignments/protocol-numbers and other
+# sources.
+# New protocols will be added on request if they have been officially
+# assigned by IANA and are not historical.
+# If you need a huge list of used numbers please install the nmap package.
+
+ip	0	IP		# internet protocol, pseudo protocol number
+#hopopt	0	HOPOPT		# IPv6 Hop-by-Hop Option [RFC1883]
+icmp	1	ICMP		# internet control message protocol
+igmp	2	IGMP		# Internet Group Management
+ggp	3	GGP		# gateway-gateway protocol
+ipencap	4	IP-ENCAP	# IP encapsulated in IP (officially ``IP'')
+st	5	ST		# ST datagram mode
+tcp	6	TCP		# transmission control protocol
+egp	8	EGP		# exterior gateway protocol
+igp	9	IGP		# any private interior gateway (Cisco)
+pup	12	PUP		# PARC universal packet protocol
+udp	17	UDP		# user datagram protocol
+hmp	20	HMP		# host monitoring protocol
+xns-idp	22	XNS-IDP		# Xerox NS IDP
+rdp	27	RDP		# "reliable datagram" protocol
+iso-tp4	29	ISO-TP4		# ISO Transport Protocol class 4 [RFC905]
+dccp	33	DCCP		# Datagram Congestion Control Protocol [RFC4340]
+xtp	36	XTP		# Xpress Transfer Protocol
+ddp	37	DDP		# Datagram Delivery Protocol
+idpr-cmtp 38	IDPR-CMTP	# IDPR Control Message Transport
+ipv6	41	IPv6		# Internet Protocol, version 6
+ipv6-route 43	IPv6-Route	# Routing Header for IPv6
+ipv6-frag 44	IPv6-Frag	# Fragment Header for IPv6
+idrp	45	IDRP		# Inter-Domain Routing Protocol
+rsvp	46	RSVP		# Reservation Protocol
+gre	47	GRE		# General Routing Encapsulation
+esp	50	IPSEC-ESP	# Encap Security Payload [RFC2046]
+ah	51	IPSEC-AH	# Authentication Header [RFC2402]
+skip	57	SKIP		# SKIP
+ipv6-icmp 58	IPv6-ICMP	# ICMP for IPv6
+ipv6-nonxt 59	IPv6-NoNxt	# No Next Header for IPv6
+ipv6-opts 60	IPv6-Opts	# Destination Options for IPv6
+rspf	73	RSPF CPHB	# Radio Shortest Path First (officially CPHB)
+vmtp	81	VMTP		# Versatile Message Transport
+eigrp	88	EIGRP		# Enhanced Interior Routing Protocol (Cisco)
+ospf	89	OSPFIGP		# Open Shortest Path First IGP
+ax.25	93	AX.25		# AX.25 frames
+ipip	94	IPIP		# IP-within-IP Encapsulation Protocol
+etherip	97	ETHERIP		# Ethernet-within-IP Encapsulation [RFC3378]
+encap	98	ENCAP		# Yet Another IP encapsulation [RFC1241]
+#	99			# any private encryption scheme
+pim	103	PIM		# Protocol Independent Multicast
+ipcomp	108	IPCOMP		# IP Payload Compression Protocol
+vrrp	112	VRRP		# Virtual Router Redundancy Protocol
+l2tp	115	L2TP		# Layer Two Tunneling Protocol [RFC2661]
+isis	124	ISIS		# IS-IS over IPv4
+sctp	132	SCTP		# Stream Control Transmission Protocol
+fc	133	FC		# Fibre Channel
+
diff --git a/package/base-files/files/etc/rc.button/failsafe b/package/base-files/files/etc/rc.button/failsafe
new file mode 100755
index 0000000000..ba958fa885
--- /dev/null
+++ b/package/base-files/files/etc/rc.button/failsafe
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "${TYPE}" = "switch" ] || echo ${BUTTON} > /tmp/failsafe_button
+
+return 0
diff --git a/package/base-files/files/etc/rc.button/power b/package/base-files/files/etc/rc.button/power
new file mode 100755
index 0000000000..c245744172
--- /dev/null
+++ b/package/base-files/files/etc/rc.button/power
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+[ "${ACTION}" = "released" ] || exit 0
+
+exec /sbin/poweroff
+
+return 0
diff --git a/package/base-files/files/etc/rc.button/reset b/package/base-files/files/etc/rc.button/reset
new file mode 100755
index 0000000000..4265767437
--- /dev/null
+++ b/package/base-files/files/etc/rc.button/reset
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+OVERLAY="$( grep ' /overlay ' /proc/mounts )"
+
+case "$ACTION" in
+pressed)
+	[ -z "$OVERLAY" ] && return 0
+
+	return 5
+;;
+timeout)
+	. /etc/diag.sh
+	set_state failsafe
+;;
+released)
+	if [ "$SEEN" -lt 1 ]
+	then
+		echo "REBOOT" > /dev/console
+		sync
+		reboot
+	elif [ "$SEEN" -gt 5 -a -n "$OVERLAY" ]
+	then
+		echo "FACTORY RESET" > /dev/console
+		jffs2reset -y && reboot &
+	fi
+;;
+esac
+
+return 0
diff --git a/package/base-files/files/etc/rc.button/rfkill b/package/base-files/files/etc/rc.button/rfkill
new file mode 100755
index 0000000000..fbdda40ed5
--- /dev/null
+++ b/package/base-files/files/etc/rc.button/rfkill
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+[ "${ACTION}" = "released" -o -n "${TYPE}" ] || exit 0
+
+. /lib/functions.sh
+
+rfkill_state=0
+
+wifi_rfkill_set() {
+	uci set wireless.$1.disabled=$rfkill_state
+}
+
+wifi_rfkill_check() {
+	local disabled
+	config_get disabled $1 disabled
+	[ "$disabled" = "1" ] || rfkill_state=1
+}
+
+config_load wireless
+case "${TYPE}" in
+"switch")
+	[ "${ACTION}" = "released" ] && rfkill_state=1
+	;;
+*)
+	config_foreach wifi_rfkill_check wifi-device
+	;;
+esac
+config_foreach wifi_rfkill_set wifi-device
+uci commit wireless
+wifi up
+
+return 0
diff --git a/package/base-files/files/etc/rc.common b/package/base-files/files/etc/rc.common
new file mode 100755
index 0000000000..95cf956366
--- /dev/null
+++ b/package/base-files/files/etc/rc.common
@@ -0,0 +1,145 @@
+#!/bin/sh
+# Copyright (C) 2006-2012 OpenWrt.org
+
+. $IPKG_INSTROOT/lib/functions.sh
+. $IPKG_INSTROOT/lib/functions/service.sh
+
+initscript=$1
+action=${2:-help}
+shift 2
+
+start() {
+	return 0
+}
+
+stop() {
+	return 0
+}
+
+reload() {
+	return 1
+}
+
+restart() {
+	trap '' TERM
+	stop "$@"
+	start "$@"
+}
+
+boot() {
+	start "$@"
+}
+
+shutdown() {
+	stop
+}
+
+disable() {
+	name="$(basename "${initscript}")"
+	rm -f "$IPKG_INSTROOT"/etc/rc.d/S??$name
+	rm -f "$IPKG_INSTROOT"/etc/rc.d/K??$name
+}
+
+enable() {
+	name="$(basename "${initscript}")"
+	disable
+	[ -n "$START" -o -n "$STOP" ] || {
+		echo "/etc/init.d/$name does not have a START or STOP value"
+		return 1
+	}
+	[ "$START" ] && ln -s "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}"
+	[ "$STOP"  ] && ln -s "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/K${STOP}${name##K[0-9][0-9]}"
+}
+
+enabled() {
+	name="$(basename "${initscript}")"
+	[ -x "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}" ]
+}
+
+depends() {
+	return 0
+}
+
+help() {
+	cat <<EOF
+Syntax: $initscript [command]
+
+Available commands:
+	start	Start the service
+	stop	Stop the service
+	restart	Restart the service
+	reload	Reload configuration files (or restart if that fails)
+	enable	Enable service autostart
+	disable	Disable service autostart
+$EXTRA_HELP
+EOF
+}
+
+# for procd
+start_service() {
+	return 0
+}
+
+stop_service() {
+	return 0
+}
+
+service_triggers() {
+	return 0
+}
+
+service_running() {
+	return 0
+}
+
+${INIT_TRACE:+set -x}
+
+. "$initscript"
+
+[ -n "$USE_PROCD" ] && {
+	EXTRA_COMMANDS="${EXTRA_COMMANDS} running trace"
+
+	. $IPKG_INSTROOT/lib/functions/procd.sh
+	basescript=$(readlink "$initscript")
+	rc_procd() {
+		local method="set"
+		[ -n "$2" ] && method="add"
+		procd_open_service "$(basename ${basescript:-$initscript})" "$initscript"
+		"$@"
+		procd_close_service "$method"
+	}
+
+	start() {
+		rc_procd start_service "$@"
+		if eval "type service_started" 2>/dev/null >/dev/null; then
+			service_started
+		fi
+	}
+
+	trace() {
+		TRACE_SYSCALLS=1
+		start "$@"
+	}
+
+	stop() {
+		stop_service "$@"
+		procd_kill "$(basename ${basescript:-$initscript})" "$1"
+	}
+
+	reload() {
+		if eval "type reload_service" 2>/dev/null >/dev/null; then
+			reload_service "$@"
+		else
+			start
+		fi
+	}
+
+	running() {
+		service_running "$@"
+	}
+}
+
+ALL_COMMANDS="start stop reload restart boot shutdown enable disable enabled depends ${EXTRA_COMMANDS}"
+list_contains ALL_COMMANDS "$action" || action=help
+[ "$action" = "reload" ] && action='eval reload "$@" || restart "$@" && :'
+$action "$@"
diff --git a/package/base-files/files/etc/rc.local b/package/base-files/files/etc/rc.local
new file mode 100644
index 0000000000..56394773c3
--- /dev/null
+++ b/package/base-files/files/etc/rc.local
@@ -0,0 +1,4 @@
+# Put your custom commands here that should be executed once
+# the system init finished. By default this file does nothing.
+
+exit 0
diff --git a/package/base-files/files/etc/services b/package/base-files/files/etc/services
new file mode 100644
index 0000000000..a12853efa0
--- /dev/null
+++ b/package/base-files/files/etc/services
@@ -0,0 +1,171 @@
+echo		7/tcp
+echo		7/udp
+discard		9/tcp
+discard		9/udp
+daytime		13/tcp
+daytime		13/udp
+netstat		15/tcp
+chargen		19/tcp
+chargen		19/udp
+ftp-data	20/tcp
+ftp		21/tcp
+ssh		22/tcp
+ssh		22/udp
+telnet		23/tcp
+smtp		25/tcp
+time		37/tcp
+time		37/udp
+whois		43/tcp
+domain		53/tcp
+domain		53/udp
+bootps		67/tcp
+bootps		67/udp
+bootpc		68/tcp
+bootpc		68/udp
+tftp		69/udp
+finger		79/tcp
+www		80/tcp		http
+kerberos	88/tcp		kerberos5 krb5 kerberos-sec
+kerberos	88/udp		kerberos5 krb5 kerberos-sec
+pop3		110/tcp
+pop3		110/udp
+sunrpc		111/tcp
+sunrpc		111/udp
+auth		113/tcp		ident
+sftp		115/tcp
+nntp		119/tcp
+ntp		123/tcp
+ntp		123/udp
+netbios-ns	137/tcp
+netbios-ns	137/udp
+netbios-dgm	138/tcp
+netbios-dgm	138/udp
+netbios-ssn	139/tcp
+netbios-ssn	139/udp
+imap2		143/tcp		imap
+imap2		143/udp		imap
+snmp		161/tcp
+snmp		161/udp
+snmp-trap	162/tcp		snmptrap
+snmp-trap	162/udp		snmptrap
+xdmcp		177/tcp
+xdmcp		177/udp
+bgp		179/tcp
+bgp		179/udp
+imap3		220/tcp
+imap3		220/udp
+ldap		389/tcp
+ldap		389/udp
+https		443/tcp
+https		443/udp
+microsoft-ds	445/tcp
+microsoft-ds	445/udp
+isakmp		500/tcp
+isakmp		500/udp
+rtsp		554/tcp
+rtsp		554/udp
+ipp		631/tcp
+ipp		631/udp
+syslog		514/udp
+printer		515/tcp		spooler
+dhcpv6-client	546/tcp
+dhcpv6-client	546/udp
+dhcpv6-server	547/tcp
+dhcpv6-server	547/udp
+afpovertcp	548/tcp
+afpovertcp	548/udp
+nntps		563/tcp		snntp
+nntps		563/udp		snntp
+ldaps		636/tcp
+ldaps		636/udp
+tinc		655/tcp
+tinc		655/udp
+rsync		873/tcp
+rsync		873/udp
+ftps-data	989/tcp
+ftps		990/tcp
+imaps		993/tcp
+imaps		993/udp
+ircs		994/tcp
+ircs		994/udp
+pop3s		995/tcp
+pop3s		995/udp
+socks		1080/tcp
+socks		1080/udp
+openvpn		1194/tcp
+openvpn		1194/udp
+l2f		1701/tcp	l2tp
+l2f		1701/udp	l2tp
+radius		1812/tcp
+radius		1812/udp
+radius-acct	1813/tcp	radacct
+radius-acct	1813/udp	radacct
+nfs		2049/tcp
+nfs		2049/udp
+dict		2628/tcp
+dict		2628/udp
+gpsd		2947/tcp
+gpsd		2947/udp
+icpv2		3130/tcp	icp
+icpv2		3130/udp	icp
+mysql		3306/tcp
+mysql		3306/udp
+nut		3493/tcp
+nut		3493/udp
+distcc		3632/tcp
+distcc		3632/udp
+daap		3689/tcp
+daap		3689/udp
+svn		3690/tcp	subversion
+svn		3690/udp	subversion
+epmd		4369/tcp
+epmd		4369/udp
+iax		4569/tcp
+iax		4569/udp
+mtn		4691/tcp
+mtn		4691/udp
+munin		4949/tcp
+sip		5060/tcp
+sip		5060/udp
+sip-tls		5061/tcp
+sip-tls		5061/udp
+xmpp-client	5222/tcp	jabber-client
+xmpp-client	5222/udp	jabber-client
+xmpp-server	5269/tcp	jabber-server
+xmpp-server	5269/udp	jabber-server
+mdns		5353/tcp
+mdns		5353/udp
+postgresql	5432/tcp	postgres
+postgresql	5432/udp	postgres
+x11		6000/tcp
+x11		6000/udp
+mysql-proxy	6446/tcp
+mysql-proxy	6446/udp
+bacula-dir	9101/tcp
+bacula-dir	9101/udp
+bacula-fd	9102/tcp
+bacula-fd	9102/udp
+bacula-sd	9103/tcp
+bacula-sd	9103/udp
+nbd		10809/tcp
+zabbix-agent	10050/tcp
+zabbix-agent	10050/udp
+zabbix-trapper	10051/tcp
+zabbix-trapper	10051/udp
+hkp		11371/tcp
+hkp		11371/udp
+ssmtp		465/tcp		smtps
+spamd		783/tcp
+zebrasrv	2600/tcp
+zebra		2601/tcp
+ripd		2602/tcp
+ripngd		2603/tcp
+ospfd		2604/tcp
+bgpd		2605/tcp
+ospf6d		2606/tcp
+ospfapi		2607/tcp
+isisd		2608/tcp
+sane-port	6566/tcp	sane saned
+ircd		6667/tcp
+git		9418/tcp
+
diff --git a/package/base-files/files/etc/shadow b/package/base-files/files/etc/shadow
new file mode 100644
index 0000000000..4b4154f21f
--- /dev/null
+++ b/package/base-files/files/etc/shadow
@@ -0,0 +1,5 @@
+root::0:0:99999:7:::
+daemon:*:0:0:99999:7:::
+ftp:*:0:0:99999:7:::
+network:*:0:0:99999:7:::
+nobody:*:0:0:99999:7:::
diff --git a/package/base-files/files/etc/shells b/package/base-files/files/etc/shells
new file mode 100644
index 0000000000..006aa38ced
--- /dev/null
+++ b/package/base-files/files/etc/shells
@@ -0,0 +1 @@
+/bin/ash
diff --git a/package/base-files/files/etc/sysctl.conf b/package/base-files/files/etc/sysctl.conf
new file mode 100644
index 0000000000..91a3ac9a02
--- /dev/null
+++ b/package/base-files/files/etc/sysctl.conf
@@ -0,0 +1,30 @@
+kernel.panic=3
+kernel.core_pattern=/tmp/%e.%t.%p.%s.core
+
+net.ipv4.conf.default.arp_ignore=1
+net.ipv4.conf.all.arp_ignore=1
+net.ipv4.ip_forward=1
+net.ipv4.icmp_echo_ignore_broadcasts=1
+net.ipv4.icmp_ignore_bogus_error_responses=1
+net.ipv4.igmp_max_memberships=100
+net.ipv4.tcp_fin_timeout=30
+net.ipv4.tcp_keepalive_time=120
+net.ipv4.tcp_syncookies=1
+net.ipv4.tcp_timestamps=1
+net.ipv4.tcp_sack=1
+net.ipv4.tcp_dsack=1
+
+net.ipv6.conf.default.forwarding=1
+net.ipv6.conf.all.forwarding=1
+
+net.netfilter.nf_conntrack_acct=1
+net.netfilter.nf_conntrack_checksum=0
+net.netfilter.nf_conntrack_max=16384
+net.netfilter.nf_conntrack_tcp_timeout_established=7440
+net.netfilter.nf_conntrack_udp_timeout=60
+net.netfilter.nf_conntrack_udp_timeout_stream=180
+
+# disable bridge firewalling by default
+net.bridge.bridge-nf-call-arptables=0
+net.bridge.bridge-nf-call-ip6tables=0
+net.bridge.bridge-nf-call-iptables=0
diff --git a/package/base-files/files/etc/sysctl.d/local.conf b/package/base-files/files/etc/sysctl.d/local.conf
new file mode 100644
index 0000000000..891da73df8
--- /dev/null
+++ b/package/base-files/files/etc/sysctl.d/local.conf
@@ -0,0 +1 @@
+# local sysctl settings can be stored in this directory
diff --git a/package/base-files/files/etc/sysupgrade.conf b/package/base-files/files/etc/sysupgrade.conf
new file mode 100644
index 0000000000..e06fd5e332
--- /dev/null
+++ b/package/base-files/files/etc/sysupgrade.conf
@@ -0,0 +1,5 @@
+## This file contains files and directories that should
+## be preserved during an upgrade.
+
+# /etc/example.conf
+# /etc/openvpn/
diff --git a/package/base-files/files/etc/uci-defaults/10_migrate-shadow b/package/base-files/files/etc/uci-defaults/10_migrate-shadow
new file mode 100644
index 0000000000..a354844fe4
--- /dev/null
+++ b/package/base-files/files/etc/uci-defaults/10_migrate-shadow
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+ppwd="$(sed -ne '/^root:/s/^root:\([^:]*\):.*$/\1/p' /etc/passwd)"
+spwd="$(sed -ne '/^root:/s/^root:\([^:]*\):.*$/\1/p' /etc/shadow)"
+
+if [ -n "${ppwd#[\!x]}" ] && [ -z "${spwd#[\!x]}" ]; then
+	logger -t migrate-shadow "Moving root password hash into shadow database"
+	sed -i -e "s:^root\:[^\:]*\::root\:x\::"     /etc/passwd
+	sed -i -e "s:^root\:[^\:]*\::root\:$ppwd\::" /etc/shadow
+fi
+
+exit 0
diff --git a/package/base-files/files/etc/uci-defaults/11_migrate-sysctl b/package/base-files/files/etc/uci-defaults/11_migrate-sysctl
new file mode 100644
index 0000000000..464e275779
--- /dev/null
+++ b/package/base-files/files/etc/uci-defaults/11_migrate-sysctl
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+if [ ! -f "/rom/etc/sysctl.conf" ] || cmp -s "/rom/etc/sysctl.conf" "/etc/sysctl.conf"; then
+	exit 0
+fi
+
+fingerprint="$(md5sum /etc/sysctl.conf)"
+fingerprint="${fingerprint%% *}"
+
+if [ "$fingerprint" = "1b05ebb41f72cb84e5510573cd4aca26" ] || \
+   [ "$fingerprint" = "62deb895be1a7f496040187b7c930e4e" ]; then
+	logger -t migrate-sysctl "Updating sysctl.conf to use current defaults"
+	cp "/rom/etc/sysctl.conf" "/etc/sysctl.conf"
+fi
+
+exit 0
diff --git a/package/base-files/files/etc/uci-defaults/12_network-generate-ula b/package/base-files/files/etc/uci-defaults/12_network-generate-ula
new file mode 100644
index 0000000000..8871427c60
--- /dev/null
+++ b/package/base-files/files/etc/uci-defaults/12_network-generate-ula
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+[ "$(uci -q get network.globals.ula_prefix)" != "auto" ] && exit 0
+
+r1=$(dd if=/dev/urandom bs=1 count=1 |hexdump -e '1/1 "%02x"')
+r2=$(dd if=/dev/urandom bs=2 count=1 |hexdump -e '2/1 "%02x"')
+r3=$(dd if=/dev/urandom bs=2 count=1 |hexdump -e '2/1 "%02x"')
+
+uci -q batch <<-EOF >/dev/null
+	set network.globals.ula_prefix=fd$r1:$r2:$r3::/48
+	commit network
+EOF
+
+exit 0
+
diff --git a/package/base-files/files/etc/uci-defaults/13_fix_group_user b/package/base-files/files/etc/uci-defaults/13_fix_group_user
new file mode 100644
index 0000000000..deade5bbd1
--- /dev/null
+++ b/package/base-files/files/etc/uci-defaults/13_fix_group_user
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+for file in `grep Require-User /usr/lib/opkg/info/*.control | cut -d: -f1`; do
+	file="${file##*/}"
+	file="${file%.control}"
+	add_group_and_user "${file}"
+done
+
+exit 0
diff --git a/package/base-files/files/lib/functions.sh b/package/base-files/files/lib/functions.sh
new file mode 100755
index 0000000000..b3bf2213f4
--- /dev/null
+++ b/package/base-files/files/lib/functions.sh
@@ -0,0 +1,351 @@
+#!/bin/sh
+# Copyright (C) 2006-2014 OpenWrt.org
+# Copyright (C) 2006 Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
+# Copyright (C) 2010 Vertical Communications
+
+
+debug () {
+	${DEBUG:-:} "$@"
+}
+
+# newline
+N="
+"
+
+_C=0
+NO_EXPORT=1
+LOAD_STATE=1
+LIST_SEP=" "
+
+append() {
+	local var="$1"
+	local value="$2"
+	local sep="${3:- }"
+
+	eval "export ${NO_EXPORT:+-n} -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\""
+}
+
+list_contains() {
+	local var="$1"
+	local str="$2"
+	local val
+
+	eval "val=\" \${$var} \""
+	[ "${val%% $str *}" != "$val" ]
+}
+
+config_load() {
+	[ -n "$IPKG_INSTROOT" ] && return 0
+	uci_load "$@"
+}
+
+reset_cb() {
+	config_cb() { return 0; }
+	option_cb() { return 0; }
+	list_cb() { return 0; }
+}
+reset_cb
+
+package() {
+	return 0
+}
+
+config () {
+	local cfgtype="$1"
+	local name="$2"
+
+	export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=$(($CONFIG_NUM_SECTIONS + 1))
+	name="${name:-cfg$CONFIG_NUM_SECTIONS}"
+	append CONFIG_SECTIONS "$name"
+	[ -n "$NO_CALLBACK" ] || config_cb "$cfgtype" "$name"
+	export ${NO_EXPORT:+-n} CONFIG_SECTION="$name"
+	export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_TYPE=$cfgtype"
+}
+
+option () {
+	local varname="$1"; shift
+	local value="$*"
+
+	export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_${varname}=$value"
+	[ -n "$NO_CALLBACK" ] || option_cb "$varname" "$*"
+}
+
+list() {
+	local varname="$1"; shift
+	local value="$*"
+	local len
+
+	config_get len "$CONFIG_SECTION" "${varname}_LENGTH" 0
+	[ $len = 0 ] && append CONFIG_LIST_STATE "${CONFIG_SECTION}_${varname}"
+	len=$(($len + 1))
+	config_set "$CONFIG_SECTION" "${varname}_ITEM$len" "$value"
+	config_set "$CONFIG_SECTION" "${varname}_LENGTH" "$len"
+	append "CONFIG_${CONFIG_SECTION}_${varname}" "$value" "$LIST_SEP"
+	list_cb "$varname" "$*"
+}
+
+config_unset() {
+	config_set "$1" "$2" ""
+}
+
+# config_get <variable> <section> <option> [<default>]
+# config_get <section> <option>
+config_get() {
+	case "$3" in
+		"") eval echo "\${CONFIG_${1}_${2}:-\${4}}";;
+		*)  eval export ${NO_EXPORT:+-n} -- "${1}=\${CONFIG_${2}_${3}:-\${4}}";;
+	esac
+}
+
+# config_get_bool <variable> <section> <option> [<default>]
+config_get_bool() {
+	local _tmp
+	config_get _tmp "$2" "$3" "$4"
+	case "$_tmp" in
+		1|on|true|yes|enabled) _tmp=1;;
+		0|off|false|no|disabled) _tmp=0;;
+		*) _tmp="$4";;
+	esac
+	export ${NO_EXPORT:+-n} "$1=$_tmp"
+}
+
+config_set() {
+	local section="$1"
+	local option="$2"
+	local value="$3"
+	local old_section="$CONFIG_SECTION"
+
+	CONFIG_SECTION="$section"
+	option "$option" "$value"
+	CONFIG_SECTION="$old_section"
+}
+
+config_foreach() {
+	local ___function="$1"
+	[ "$#" -ge 1 ] && shift
+	local ___type="$1"
+	[ "$#" -ge 1 ] && shift
+	local section cfgtype
+
+	[ -z "$CONFIG_SECTIONS" ] && return 0
+	for section in ${CONFIG_SECTIONS}; do
+		config_get cfgtype "$section" TYPE
+		[ -n "$___type" -a "x$cfgtype" != "x$___type" ] && continue
+		eval "$___function \"\$section\" \"\$@\""
+	done
+}
+
+config_list_foreach() {
+	[ "$#" -ge 3 ] || return 0
+	local section="$1"; shift
+	local option="$1"; shift
+	local function="$1"; shift
+	local val
+	local len
+	local c=1
+
+	config_get len "${section}" "${option}_LENGTH"
+	[ -z "$len" ] && return 0
+	while [ $c -le "$len" ]; do
+		config_get val "${section}" "${option}_ITEM$c"
+		eval "$function \"\$val\" \"\$@\""
+		c="$(($c + 1))"
+	done
+}
+
+insert_modules() {
+	for m in $*; do
+		if [ -f /etc/modules.d/$m ]; then
+			sed 's/^[^#]/insmod &/' /etc/modules.d/$m | ash 2>&- || :
+		else
+			modprobe $m
+		fi
+	done
+}
+
+default_prerm() {
+	local root="${IPKG_INSTROOT}"
+	local name
+
+	name=$(basename ${1%.*})
+	[ -f "$root/usr/lib/opkg/info/${name}.prerm-pkg" ] && . "$root/usr/lib/opkg/info/${name}.prerm-pkg"
+
+	local shell="$(which bash)"
+	for i in `cat "$root/usr/lib/opkg/info/${name}.list" | grep "^/etc/init.d/"`; do
+		if [ -n "$root" ]; then
+			${shell:-/bin/sh} "$root/etc/rc.common" "$root$i" disable
+		else
+			if [ "$PKG_UPGRADE" != "1" ]; then
+				"$i" disable
+			fi
+			"$i" stop || /bin/true
+		fi
+	done
+}
+
+add_group_and_user() {
+	local pkgname="$1"
+	local rusers="$(sed -ne 's/^Require-User: *//p' $root/usr/lib/opkg/info/${pkgname}.control 2>/dev/null)"
+
+	if [ -n "$rusers" ]; then
+		local tuple oIFS="$IFS"
+		for tuple in $rusers; do
+			local uid gid uname gname
+
+			IFS=":"
+			set -- $tuple; uname="$1"; gname="$2"
+			IFS="="
+			set -- $uname; uname="$1"; uid="$2"
+			set -- $gname; gname="$1"; gid="$2"
+			IFS="$oIFS"
+
+			if [ -n "$gname" ] && [ -n "$gid" ]; then
+				group_exists "$gname" || group_add "$gname" "$gid"
+			elif [ -n "$gname" ]; then
+				group_add_next "$gname"; gid=$?
+			fi
+
+			if [ -n "$uname" ]; then
+				user_exists "$uname" || user_add "$uname" "$uid" "$gid"
+			fi
+
+			if [ -n "$uname" ] && [ -n "$gname" ]; then
+				group_add_user "$gname" "$uname"
+			fi
+
+			unset uid gid uname gname
+		done
+	fi
+}
+
+default_postinst() {
+	local root="${IPKG_INSTROOT}"
+	local pkgname="$(basename ${1%.*})"
+	local ret=0
+
+	add_group_and_user "${pkgname}"
+
+	if [ -f "$root/usr/lib/opkg/info/${pkgname}.postinst-pkg" ]; then
+		( . "$root/usr/lib/opkg/info/${pkgname}.postinst-pkg" )
+		ret=$?
+	fi
+
+	if [ -z "$root" ] && grep -q -s "^/etc/uci-defaults/" "/usr/lib/opkg/info/${pkgname}.list"; then
+		. /lib/functions/system.sh
+		[ -d /tmp/.uci ] || mkdir -p /tmp/.uci
+		for i in $(sed -ne 's!^/etc/uci-defaults/!!p' "/usr/lib/opkg/info/${pkgname}.list"); do (
+			cd /etc/uci-defaults
+			[ -f "$i" ] && . "$i" && rm -f "$i"
+		) done
+		uci commit
+	fi
+
+	[ -n "$root" ] || rm -f /tmp/luci-indexcache 2>/dev/null
+
+	local shell="$(which bash)"
+	for i in $(grep -s "^/etc/init.d/" "$root/usr/lib/opkg/info/${pkgname}.list"); do
+		if [ -n "$root" ]; then
+			${shell:-/bin/sh} "$root/etc/rc.common" "$root$i" enable
+		else
+			if [ "$PKG_UPGRADE" != "1" ]; then
+				"$i" enable
+			fi
+			"$i" start
+		fi
+	done
+
+	return $ret
+}
+
+include() {
+	local file
+
+	for file in $(ls $1/*.sh 2>/dev/null); do
+		. $file
+	done
+}
+
+find_mtd_index() {
+	local PART="$(grep "\"$1\"" /proc/mtd | awk -F: '{print $1}')"
+	local INDEX="${PART##mtd}"
+
+	echo ${INDEX}
+}
+
+find_mtd_part() {
+	local INDEX=$(find_mtd_index "$1")
+	local PREFIX=/dev/mtdblock
+
+	[ -d /dev/mtdblock ] && PREFIX=/dev/mtdblock/
+	echo "${INDEX:+$PREFIX$INDEX}"
+}
+
+group_add() {
+	local name="$1"
+	local gid="$2"
+	local rc
+	[ -f "${IPKG_INSTROOT}/etc/group" ] || return 1
+	[ -n "$IPKG_INSTROOT" ] || lock /var/lock/group
+	echo "${name}:x:${gid}:" >> ${IPKG_INSTROOT}/etc/group
+	rc=$?
+	[ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/group
+	return $rc
+}
+
+group_exists() {
+	grep -qs "^${1}:" ${IPKG_INSTROOT}/etc/group
+}
+
+group_add_next() {
+	local gid gids
+	gid=$(grep -s "^${1}:" ${IPKG_INSTROOT}/etc/group | cut -d: -f3)
+	[ -n "$gid" ] && return $gid
+	gids=$(cat ${IPKG_INSTROOT}/etc/group | cut -d: -f3)
+	gid=100
+	while [ -n "$(echo $gids | grep $gid)" ] ; do
+	        gid=$((gid + 1))
+	done
+	group_add $1 $gid
+	return $gid
+}
+
+group_add_user() {
+	local grp delim=","
+	grp=$(grep -s "^${1}:" ${IPKG_INSTROOT}/etc/group)
+	[ -z "$(echo $grp | cut -d: -f4 | grep $2)" ] || return
+	[ -n "$(echo $grp | grep ":$")" ] && delim=""
+	[ -n "$IPKG_INSTROOT" ] || lock /var/lock/passwd
+	sed -i "s/$grp/$grp$delim$2/g" ${IPKG_INSTROOT}/etc/group
+	[ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/passwd
+}
+
+user_add() {
+	local name="${1}"
+	local uid="${2}"
+	local gid="${3}"
+	local desc="${4:-$1}"
+	local home="${5:-/var/run/$1}"
+	local shell="${6:-/bin/false}"
+	local rc
+	[ -z "$uid" ] && {
+		uids=$(cat ${IPKG_INSTROOT}/etc/passwd | cut -d: -f3)
+		uid=100
+		while [ -n "$(echo $uids | grep $uid)" ] ; do
+		        uid=$((uid + 1))
+		done
+	}
+	[ -z "$gid" ] && gid=$uid
+	[ -f "${IPKG_INSTROOT}/etc/passwd" ] || return 1
+	[ -n "$IPKG_INSTROOT" ] || lock /var/lock/passwd
+	echo "${name}:x:${uid}:${gid}:${desc}:${home}:${shell}" >> ${IPKG_INSTROOT}/etc/passwd
+	echo "${name}:x:0:0:99999:7:::" >> ${IPKG_INSTROOT}/etc/shadow
+	rc=$?
+	[ -n "$IPKG_INSTROOT" ] || lock -u /var/lock/passwd
+	return $rc
+}
+
+user_exists() {
+	grep -qs "^${1}:" ${IPKG_INSTROOT}/etc/passwd
+}
+
+[ -z "$IPKG_INSTROOT" -a -f /lib/config/uci.sh ] && . /lib/config/uci.sh
diff --git a/package/base-files/files/lib/functions/leds.sh b/package/base-files/files/lib/functions/leds.sh
new file mode 100644
index 0000000000..857e7e5392
--- /dev/null
+++ b/package/base-files/files/lib/functions/leds.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Copyright (C) 2013 OpenWrt.org
+
+led_set_attr() {
+	[ -f "/sys/class/leds/$1/$2" ] && echo "$3" > "/sys/class/leds/$1/$2"
+}
+
+led_timer() {
+	led_set_attr $1 "trigger" "timer"
+	led_set_attr $1 "delay_on" "$2"
+	led_set_attr $1 "delay_off" "$3"
+}
+
+led_on() {
+	led_set_attr $1 "trigger" "none"
+	led_set_attr $1 "brightness" 255
+}
+
+led_off() {
+	led_set_attr $1 "trigger" "none"
+	led_set_attr $1 "brightness" 0
+}
+
+status_led_set_timer() {
+	led_timer $status_led "$1" "$2"
+	[ -n "$status_led2" ] && led_timer $status_led2 "$1" "$2"
+}
+
+status_led_set_heartbeat() {
+	led_set_attr $status_led "trigger" "heartbeat"
+}
+
+status_led_on() {
+	led_on $status_led
+	[ -n "$status_led2" ] && led_on $status_led2
+}
+
+status_led_off() {
+	led_off $status_led
+	[ -n "$status_led2" ] && led_off $status_led2
+}
+
+status_led_blink_slow() {
+	led_timer $status_led 1000 1000
+}
+
+status_led_blink_fast() {
+	led_timer $status_led 100 100
+}
+
+status_led_blink_preinit() {
+	led_timer $status_led 100 100
+}
+
+status_led_blink_failsafe() {
+	led_timer $status_led 50 50
+}
+
+status_led_blink_preinit_regular() {
+	led_timer $status_led 200 200
+}
diff --git a/package/base-files/files/lib/functions/network.sh b/package/base-files/files/lib/functions/network.sh
new file mode 100644
index 0000000000..1b0c717204
--- /dev/null
+++ b/package/base-files/files/lib/functions/network.sh
@@ -0,0 +1,268 @@
+# 1: destination variable
+# 2: interface
+# 3: path
+# 4: separator
+# 5: limit
+__network_ifstatus() {
+	local __tmp
+
+	[ -z "$__NETWORK_CACHE" ] && \
+		export __NETWORK_CACHE="$(ubus call network.interface dump)"
+
+	__tmp="$(jsonfilter ${4:+-F "$4"} ${5:+-l "$5"} -s "$__NETWORK_CACHE" -e "$1=@.interface${2:+[@.interface='$2']}$3")"
+
+	[ -z "$__tmp" ] && \
+		unset "$1" && \
+		return 1
+
+	eval "$__tmp"
+}
+
+# determine first IPv4 address of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_ipaddr() {
+	__network_ifstatus "$1" "$2" "['ipv4-address'][0].address";
+}
+
+# determine first IPv6 address of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_ipaddr6() {
+	local __addr
+
+	if __network_ifstatus "__addr" "$2" "['ipv6-address','ipv6-prefix-assignment'][0].address"; then
+		case "$__addr" in
+			*:)	export "$1=${__addr}1" ;;
+			*)	export "$1=${__addr}" ;;
+		esac
+		return 0
+	fi
+
+	unset $1
+	return 1
+}
+
+# determine first IPv4 subnet of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_subnet() {
+	__network_ifstatus "$1" "$2" "['ipv4-address'][0]['address','mask']" "/"
+}
+
+# determine first IPv6 subnet of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_subnet6() {
+	__network_ifstatus "$1" "$2" "['ipv6-address'][0]['address','mask']" "/"
+}
+
+# determine first IPv6 prefix of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_prefix6() {
+	__network_ifstatus "$1" "$2" "['ipv6-prefix'][0]['address','mask']" "/"
+}
+
+# determine all IPv4 addresses of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_ipaddrs() {
+	__network_ifstatus "$1" "$2" "['ipv4-address'][*].address"
+}
+
+# determine all IPv6 addresses of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_ipaddrs6() {
+	local __addr
+	local __list=""
+
+	if __network_ifstatus "__addr" "$2" "['ipv6-address','ipv6-prefix-assignment'][*].address"; then
+		for __addr in $__addr; do
+			case "$__addr" in
+				*:) __list="${__list:+$__list }${__addr}1" ;;
+				*)  __list="${__list:+$__list }${__addr}"  ;;
+			esac
+		done
+
+		export "$1=$__list"
+		return 0
+	fi
+
+	unset "$1"
+	return 1
+}
+
+# determine all IP addresses of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_ipaddrs_all() {
+	local __addr
+	local __list=""
+
+	if __network_ifstatus "__addr" "$2" "['ipv4-address','ipv6-address','ipv6-prefix-assignment'][*].address"; then
+		for __addr in $__addr; do
+			case "$__addr" in
+				*:) __list="${__list:+$__list }${__addr}1" ;;
+				*)  __list="${__list:+$__list }${__addr}"  ;;
+			esac
+		done
+
+		export "$1=$__list"
+		return 0
+	fi
+
+	unset "$1"
+	return 1
+}
+
+# determine all IPv4 subnets of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_subnets() {
+	__network_ifstatus "$1" "$2" "['ipv4-address'][*]['address','mask']" "/ "
+}
+
+# determine all IPv6 subnets of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_subnets6() {
+	local __addr
+	local __list=""
+
+	if __network_ifstatus "__addr" "$2" "['ipv6-address','ipv6-prefix-assignment'][*]['address','mask']" "/ "; then
+		for __addr in $__addr; do
+			case "$__addr" in
+				*:/*) __list="${__list:+$__list }${__addr%/*}1/${__addr##*/}" ;;
+				*)    __list="${__list:+$__list }${__addr}"                   ;;
+			esac
+		done
+
+		export "$1=$__list"
+		return 0
+	fi
+
+	unset "$1"
+	return 1
+}
+
+# determine all IPv6 prefixes of given logical interface
+# 1: destination variable
+# 2: interface
+network_get_prefixes6() {
+	__network_ifstatus "$1" "$2" "['ipv6-prefix'][*]['address','mask']" "/ "
+}
+
+# determine IPv4 gateway of given logical interface
+# 1: destination variable
+# 2: interface
+# 3: consider inactive gateway if "true" (optional)
+network_get_gateway() {
+	__network_ifstatus "$1" "$2" ".route[@.target='0.0.0.0' && !@.table].nexthop" "" 1 && \
+		return 0
+
+	[ "$3" = 1 -o "$3" = "true" ] && \
+		__network_ifstatus "$1" "$2" ".inactive.route[@.target='0.0.0.0' && !@.table].nexthop" "" 1
+}
+
+# determine IPv6 gateway of given logical interface
+# 1: destination variable
+# 2: interface
+# 3: consider inactive gateway if "true" (optional)
+network_get_gateway6() {
+	__network_ifstatus "$1" "$2" ".route[@.target='::' && !@.table].nexthop" "" 1 && \
+		return 0
+
+	[ "$3" = 1 -o "$3" = "true" ] && \
+		__network_ifstatus "$1" "$2" ".inactive.route[@.target='::' && !@.table].nexthop" "" 1
+}
+
+# determine the DNS servers of the given logical interface
+# 1: destination variable
+# 2: interface
+# 3: consider inactive servers if "true" (optional)
+network_get_dnsserver() {
+	__network_ifstatus "$1" "$2" "['dns-server'][*]" && return 0
+
+	[ "$3" = 1 -o "$3" = "true" ] && \
+		__network_ifstatus "$1" "$2" ".inactive['dns-server'][*]"
+}
+
+# determine the domains of the given logical interface
+# 1: destination variable
+# 2: interface
+# 3: consider inactive domains if "true" (optional)
+network_get_dnssearch() {
+	__network_ifstatus "$1" "$2" "['dns-search'][*]" && return 0
+
+	[ "$3" = 1 -o "$3" = "true" ] && \
+		__network_ifstatus "$1" "$2" ".inactive['dns-search'][*]"
+}
+
+
+# 1: destination variable
+# 2: addr
+# 3: inactive
+__network_wan()
+{
+	__network_ifstatus "$1" "" \
+		"[@.route[@.target='$2' && !@.table]].interface" "" 1 && \
+			return 0
+
+	[ "$3" = 1 -o "$3" = "true" ] && \
+		__network_ifstatus "$1" "" \
+			"[@.inactive.route[@.target='$2' && !@.table]].interface" "" 1
+}
+
+# find the logical interface which holds the current IPv4 default route
+# 1: destination variable
+# 2: consider inactive default routes if "true" (optional)
+network_find_wan() { __network_wan "$1" "0.0.0.0" "$2"; }
+
+# find the logical interface which holds the current IPv6 default route
+# 1: destination variable
+# 2: consider inactive dafault routes if "true" (optional)
+network_find_wan6() { __network_wan "$1" "::" "$2"; }
+
+# test whether the given logical interface is running
+# 1: interface
+network_is_up()
+{
+	local __up
+	__network_ifstatus "__up" "$1" ".up" && [ "$__up" = 1 ]
+}
+
+# determine the protocol of the given logical interface
+# 1: destination variable
+# 2: interface
+network_get_protocol() { __network_ifstatus "$1" "$2" ".proto"; }
+
+# determine the layer 3 linux network device of the given logical interface
+# 1: destination variable
+# 2: interface
+network_get_device() { __network_ifstatus "$1" "$2" ".l3_device"; }
+
+# determine the layer 2 linux network device of the given logical interface
+# 1: destination variable
+# 2: interface
+network_get_physdev() { __network_ifstatus "$1" "$2" ".device"; }
+
+# defer netifd actions on the given linux network device
+# 1: device name
+network_defer_device()
+{
+	ubus call network.device set_state \
+		"$(printf '{ "name": "%s", "defer": true }' "$1")" 2>/dev/null
+}
+
+# continue netifd actions on the given linux network device
+# 1: device name
+network_ready_device()
+{
+	ubus call network.device set_state \
+		"$(printf '{ "name": "%s", "defer": false }' "$1")" 2>/dev/null
+}
+
+# flush the internal value cache to force re-reading values from ubus
+network_flush_cache() { unset __NETWORK_CACHE; }
diff --git a/package/base-files/files/lib/functions/preinit.sh b/package/base-files/files/lib/functions/preinit.sh
new file mode 100644
index 0000000000..57862a11f3
--- /dev/null
+++ b/package/base-files/files/lib/functions/preinit.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Copyright (C) 2006-2013 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+boot_hook_splice_start() {
+	export -n PI_HOOK_SPLICE=1
+}
+
+boot_hook_splice_finish() {
+	local hook
+	for hook in $PI_STACK_LIST; do
+		local v; eval "v=\${${hook}_splice:+\$${hook}_splice }$hook"
+		export -n "${hook}=${v% }"
+		export -n "${hook}_splice="
+	done
+	export -n PI_HOOK_SPLICE=
+}
+
+boot_hook_init() {
+	local hook="${1}_hook"
+	export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
+	export -n "$hook="
+}
+
+boot_hook_add() {
+	local hook="${1}_hook${PI_HOOK_SPLICE:+_splice}"
+	local func="${2}"
+
+	[ -n "$func" ] && {
+		local v; eval "v=\$$hook"
+		export -n "$hook=${v:+$v }$func"
+	}
+}
+
+boot_hook_shift() {
+	local hook="${1}_hook"
+	local rvar="${2}"
+
+	local v; eval "v=\$$hook"
+	[ -n "$v" ] && {
+		local first="${v%% *}"
+
+		[ "$v" != "${v#* }" ] && \
+			export -n "$hook=${v#* }" || \
+			export -n "$hook="
+
+		export -n "$rvar=$first"
+		return 0
+	}
+
+	return 1
+}
+
+boot_run_hook() {
+	local hook="$1"
+	local func
+
+	while boot_hook_shift "$hook" func; do
+		local ran; eval "ran=\$PI_RAN_$func"
+		[ -n "$ran" ] || {
+			export -n "PI_RAN_$func=1"
+			$func "$1" "$2"
+		}
+	done
+}
+
+pivot() { # <new_root> <old_root>
+	/bin/mount -o noatime,move /proc $1/proc && \
+	pivot_root $1 $1$2 && {
+		/bin/mount -o noatime,move $2/dev /dev
+		/bin/mount -o noatime,move $2/tmp /tmp
+		/bin/mount -o noatime,move $2/sys /sys 2>&-
+		/bin/mount -o noatime,move $2/overlay /overlay 2>&-
+		return 0
+	}
+}
+
+fopivot() { # <rw_root> <work_dir> <ro_root> <dupe?>
+	/bin/mount -o noatime,lowerdir=/,upperdir=$1,workdir=$2 -t overlay "overlayfs:$1" /mnt
+	pivot /mnt $3
+}
+
+ramoverlay() {
+	mkdir -p /tmp/root
+	/bin/mount -t tmpfs -o noatime,mode=0755 root /tmp/root
+	mkdir -p /tmp/root/root /tmp/root/work
+	fopivot /tmp/root/root /tmp/root/work /rom 1
+}
diff --git a/package/base-files/files/lib/functions/service.sh b/package/base-files/files/lib/functions/service.sh
new file mode 100644
index 0000000000..3d08e1434d
--- /dev/null
+++ b/package/base-files/files/lib/functions/service.sh
@@ -0,0 +1,103 @@
+#
+# service: simple wrapper around start-stop-daemon
+#
+# Usage: service ACTION EXEC ARGS...
+#
+# Action:
+#   -C	check if EXEC is alive
+#   -S	start EXEC, passing it ARGS as its arguments
+#   -K	kill EXEC, sending it a TERM signal if not specified otherwise
+#
+# Environment variables exposed:
+#   SERVICE_DAEMONIZE	run EXEC in background
+#   SERVICE_WRITE_PID	create a pid-file and use it for matching
+#   SERVICE_MATCH_EXEC	use EXEC command-line for matching (default)
+#   SERVICE_MATCH_NAME	use EXEC process name for matching
+#   SERVICE_USE_PID	assume EXEC create its own pid-file and use it for matching
+#   SERVICE_NAME	process name to use (default to EXEC file part)
+#   SERVICE_PID_FILE	pid file to use (default to /var/run/$SERVICE_NAME.pid)
+#   SERVICE_SIG		signal to send when using -K
+#   SERVICE_SIG_RELOAD	default signal used when reloading
+#   SERVICE_SIG_STOP	default signal used when stopping
+#   SERVICE_STOP_TIME	time to wait for a process to stop gracefully before killing it
+#   SERVICE_UID		user EXEC should be run as
+#   SERVICE_GID		group EXEC should be run as
+#
+#   SERVICE_DEBUG	don't do anything, but show what would be done
+#   SERVICE_QUIET	don't print anything
+#
+
+SERVICE_QUIET=1
+SERVICE_SIG_RELOAD="HUP"
+SERVICE_SIG_STOP="TERM"
+SERVICE_STOP_TIME=5
+SERVICE_MATCH_EXEC=1
+
+service() {
+	local ssd
+	local exec
+	local name
+	local start
+	ssd="${SERVICE_DEBUG:+echo }start-stop-daemon${SERVICE_QUIET:+ -q}"
+	case "$1" in
+	  -C)
+		ssd="$ssd -K -t"
+		;;
+	  -S)
+		ssd="$ssd -S${SERVICE_DAEMONIZE:+ -b}${SERVICE_WRITE_PID:+ -m}"
+		start=1
+		;;
+	  -K)
+		ssd="$ssd -K${SERVICE_SIG:+ -s $SERVICE_SIG}"
+		;;
+	  *)
+		echo "service: unknown ACTION '$1'" 1>&2
+		return 1
+	esac
+	shift
+	exec="$1"
+	[ -n "$exec" ] || {
+		echo "service: missing argument" 1>&2
+		return 1
+	}
+	[ -x "$exec" ] || {
+		echo "service: file '$exec' is not executable" 1>&2
+		return 1
+	}
+	name="${SERVICE_NAME:-${exec##*/}}"
+	[ -z "$SERVICE_USE_PID$SERVICE_WRITE_PID$SERVICE_PID_FILE" ] \
+		|| ssd="$ssd -p ${SERVICE_PID_FILE:-/var/run/$name.pid}"
+	[ -z "$SERVICE_MATCH_NAME" ] || ssd="$ssd -n $name"
+	ssd="$ssd${SERVICE_UID:+ -c $SERVICE_UID${SERVICE_GID:+:$SERVICE_GID}}"
+	[ -z "$SERVICE_MATCH_EXEC$start" ] || ssd="$ssd -x $exec"
+	shift
+	$ssd${1:+ -- "$@"}
+}
+
+service_check() {
+	service -C "$@"
+}
+
+service_signal() {
+	SERVICE_SIG="${SERVICE_SIG:-USR1}" service -K "$@"
+}
+
+service_start() {
+	service -S "$@"
+}
+
+service_stop() {
+	local try
+	SERVICE_SIG="${SERVICE_SIG:-$SERVICE_SIG_STOP}" service -K "$@" || return 1
+	while [ $((try++)) -lt $SERVICE_STOP_TIME ]; do
+		service -C "$@" || return 0
+		sleep 1
+	done
+	SERVICE_SIG="KILL" service -K "$@"
+	sleep 1
+	! service -C "$@"
+}
+
+service_reload() {
+	SERVICE_SIG="${SERVICE_SIG:-$SERVICE_SIG_RELOAD}" service -K "$@"
+}
diff --git a/package/base-files/files/lib/functions/system.sh b/package/base-files/files/lib/functions/system.sh
new file mode 100644
index 0000000000..35f6d10fdb
--- /dev/null
+++ b/package/base-files/files/lib/functions/system.sh
@@ -0,0 +1,129 @@
+# Copyright (C) 2006-2013 OpenWrt.org
+
+find_mtd_chardev() {
+	local INDEX=$(find_mtd_index "$1")
+	local PREFIX=/dev/mtd
+
+	[ -d /dev/mtd ] && PREFIX=/dev/mtd/
+	echo "${INDEX:+$PREFIX$INDEX}"
+}
+
+mtd_get_mac_ascii()
+{
+	local mtdname="$1"
+	local key="$2"
+	local part
+	local mac_dirty
+
+	part=$(find_mtd_part "$mtdname")
+	if [ -z "$part" ]; then
+		echo "mtd_get_mac_ascii: partition $mtdname not found!" >&2
+		return
+	fi
+
+	mac_dirty=$(strings "$part" | sed -n 's/^'"$key"'=//p')
+
+	# "canonicalize" mac
+	[ -n "$mac_dirty" ] && macaddr_canonicalize "$mac_dirty"
+}
+
+mtd_get_mac_binary() {
+	local mtdname="$1"
+	local offset="$2"
+	local part
+
+	part=$(find_mtd_part "$mtdname")
+	if [ -z "$part" ]; then
+		echo "mtd_get_mac_binary: partition $mtdname not found!" >&2
+		return
+	fi
+
+	hexdump -v -n 6 -s $offset -e '5/1 "%02x:" 1/1 "%02x"' $part 2>/dev/null
+}
+
+mtd_get_mac_binary_ubi() {
+	local mtdname="$1"
+	local offset="$2"
+
+	. /lib/upgrade/nand.sh
+
+	local ubidev=$(nand_find_ubi $CI_UBIPART)
+	local part=$(nand_find_volume $ubidev $1)
+
+	if [ -z "$part" ]; then
+		echo "mtd_get_mac_binary: ubi volume $mtdname not found!" >&2
+		return
+	fi
+
+	hexdump -v -n 6 -s $offset -e '5/1 "%02x:" 1/1 "%02x"' /dev/$part 2>/dev/null
+}
+
+mtd_get_part_size() {
+	local part_name=$1
+	local first dev size erasesize name
+	while read dev size erasesize name; do
+		name=${name#'"'}; name=${name%'"'}
+		if [ "$name" = "$part_name" ]; then
+			echo $((0x$size))
+			break
+		fi
+	done < /proc/mtd
+}
+
+macaddr_add() {
+	local mac=$1
+	local val=$2
+	local oui=${mac%:*:*:*}
+	local nic=${mac#*:*:*:}
+
+	nic=$(printf "%06x" $((0x${nic//:/} + $val & 0xffffff)) | sed 's/^\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)/\1:\2:\3/')
+	echo $oui:$nic
+}
+
+macaddr_setbit_la()
+{
+	local mac=$1
+
+	printf "%02x:%s" $((0x${mac%%:*} | 0x02)) ${mac#*:}
+}
+
+macaddr_2bin()
+{
+	local mac=$1
+
+	echo -ne \\x${mac//:/\\x}
+}
+
+macaddr_canonicalize()
+{
+	local mac="$1"
+	local canon=""
+
+	mac=$(echo -n $mac | tr -d \")
+	[ ${#mac} -gt 17 ] && return
+	[ -n "${mac//[a-fA-F0-9\.: -]/}" ] && return
+
+	for octet in ${mac//[\.:-]/ }; do
+		case "${#octet}" in
+		1)
+			octet="0${octet}"
+			;;
+		2)
+			;;
+		4)
+			octet="${octet:0:2} ${octet:2:2}"
+			;;
+		12)
+			octet="${octet:0:2} ${octet:2:2} ${octet:4:2} ${octet:6:2} ${octet:8:2} ${octet:10:2}"
+			;;
+		*)
+			return
+			;;
+		esac
+		canon=${canon}${canon:+ }${octet}
+	done
+
+	[ ${#canon} -ne 17 ] && return
+
+	printf "%02x:%02x:%02x:%02x:%02x:%02x" 0x${canon// / 0x} 2>/dev/null
+}
diff --git a/package/base-files/files/lib/functions/uci-defaults.sh b/package/base-files/files/lib/functions/uci-defaults.sh
new file mode 100755
index 0000000000..3500d49baa
--- /dev/null
+++ b/package/base-files/files/lib/functions/uci-defaults.sh
@@ -0,0 +1,640 @@
+#!/bin/ash
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+json_select_array() {
+	local _json_no_warning=1
+
+	json_select "$1"
+	[ $? = 0 ] && return
+
+	json_add_array "$1"
+	json_close_array
+
+	json_select "$1"
+}
+
+json_select_object() {
+	local _json_no_warning=1
+
+	json_select "$1"
+	[ $? = 0 ] && return
+
+	json_add_object "$1"
+	json_close_object
+
+	json_select "$1"
+}
+
+_ucidef_set_interface() {
+	local name="$1"
+	local iface="$2"
+	local proto="$3"
+
+	json_select_object "$name"
+	json_add_string ifname "$iface"
+
+	if ! json_is_a protocol string; then
+		case "$proto" in
+			static|dhcp|none|pppoe) : ;;
+			*)
+				case "$name" in
+					lan) proto="static" ;;
+					wan) proto="dhcp" ;;
+					*) proto="none" ;;
+				esac
+			;;
+		esac
+
+		json_add_string protocol "$proto"
+	fi
+
+	json_select ..
+}
+
+ucidef_set_board_id() {
+	json_select_object model
+	json_add_string id "$1"
+	json_select ..
+}
+
+ucidef_set_model_name() {
+	json_select_object model
+	json_add_string name "$1"
+	json_select ..
+}
+
+ucidef_set_interface_lan() {
+	json_select_object network
+	_ucidef_set_interface lan "$@"
+	json_select ..
+}
+
+ucidef_set_interface_wan() {
+	json_select_object network
+	_ucidef_set_interface wan "$@"
+	json_select ..
+}
+
+ucidef_set_interfaces_lan_wan() {
+	local lan_if="$1"
+	local wan_if="$2"
+
+	json_select_object network
+	_ucidef_set_interface lan "$lan_if"
+	_ucidef_set_interface wan "$wan_if"
+	json_select ..
+}
+
+ucidef_set_interface_raw() {
+	json_select_object network
+	_ucidef_set_interface "$@"
+	json_select ..
+}
+
+_ucidef_add_switch_port() {
+	# inherited: $num $device $need_tag $want_untag $role $index $prev_role
+	# inherited: $n_cpu $n_ports $n_vlan $cpu0 $cpu1 $cpu2 $cpu3 $cpu4 $cpu5
+
+	n_ports=$((n_ports + 1))
+
+	json_select_array ports
+		json_add_object
+			json_add_int num "$num"
+			[ -n "$device"     ] && json_add_string  device     "$device"
+			[ -n "$need_tag"   ] && json_add_boolean need_tag   "$need_tag"
+			[ -n "$want_untag" ] && json_add_boolean want_untag "$want_untag"
+			[ -n "$role"       ] && json_add_string  role       "$role"
+			[ -n "$index"      ] && json_add_int     index      "$index"
+		json_close_object
+	json_select ..
+
+	# record pointer to cpu entry for lookup in _ucidef_finish_switch_roles()
+	[ -n "$device" ] && {
+		export "cpu$n_cpu=$n_ports"
+		n_cpu=$((n_cpu + 1))
+	}
+
+	# create/append object to role list
+	[ -n "$role" ] && {
+		json_select_array roles
+
+		if [ "$role" != "$prev_role" ]; then
+			json_add_object
+				json_add_string role "$role"
+				json_add_string ports "$num"
+			json_close_object
+
+			prev_role="$role"
+			n_vlan=$((n_vlan + 1))
+		else
+			json_select_object "$n_vlan"
+				json_get_var port ports
+				json_add_string ports "$port $num"
+			json_select ..
+		fi
+
+		json_select ..
+	}
+}
+
+_ucidef_finish_switch_roles() {
+	# inherited: $name $n_cpu $n_vlan $cpu0 $cpu1 $cpu2 $cpu3 $cpu4 $cpu5
+	local index role roles num device need_tag want_untag port ports
+
+	json_select switch
+		json_select "$name"
+			json_get_keys roles roles
+		json_select ..
+	json_select ..
+
+	for index in $roles; do
+		eval "port=\$cpu$(((index - 1) % n_cpu))"
+
+		json_select switch
+			json_select "$name"
+				json_select ports
+					json_select "$port"
+						json_get_vars num device need_tag want_untag
+					json_select ..
+				json_select ..
+
+				if [ $n_vlan -gt $n_cpu -o ${need_tag:-0} -eq 1 ]; then
+					num="${num}t"
+					device="${device}.${index}"
+				fi
+
+				json_select roles
+					json_select "$index"
+						json_get_vars role ports
+						json_add_string ports "$ports $num"
+						json_add_string device "$device"
+					json_select ..
+				json_select ..
+			json_select ..
+		json_select ..
+
+		json_select_object network
+			local devices
+
+			json_select_object "$role"
+				# attach previous interfaces (for multi-switch devices)
+				json_get_var devices ifname
+				if ! list_contains devices "$device"; then
+					devices="${devices:+$devices }$device"
+				fi
+			json_select ..
+
+			_ucidef_set_interface "$role" "$devices"
+		json_select ..
+	done
+}
+
+ucidef_add_switch() {
+	local name="$1"; shift
+	local port num role device index need_tag prev_role
+	local cpu0 cpu1 cpu2 cpu3 cpu4 cpu5
+	local n_cpu=0 n_vlan=0 n_ports=0
+
+	json_select_object switch
+		json_select_object "$name"
+			json_add_boolean enable 1
+			json_add_boolean reset 1
+
+			for port in "$@"; do
+				case "$port" in
+					[0-9]*@*)
+						num="${port%%@*}"
+						device="${port##*@}"
+						need_tag=0
+						want_untag=0
+						[ "${num%t}" != "$num" ] && {
+							num="${num%t}"
+							need_tag=1
+						}
+						[ "${num%u}" != "$num" ] && {
+							num="${num%u}"
+							want_untag=1
+						}
+					;;
+					[0-9]*:*:[0-9]*)
+						num="${port%%:*}"
+						index="${port##*:}"
+						role="${port#[0-9]*:}"; role="${role%:*}"
+					;;
+					[0-9]*:*)
+						num="${port%%:*}"
+						role="${port##*:}"
+					;;
+				esac
+
+				if [ -n "$num" ] && [ -n "$device$role" ]; then
+					_ucidef_add_switch_port
+				fi
+
+				unset num device role index need_tag want_untag
+			done
+		json_select ..
+	json_select ..
+
+	_ucidef_finish_switch_roles
+}
+
+ucidef_add_switch_attr() {
+	local name="$1"
+	local key="$2"
+	local val="$3"
+
+	json_select_object switch
+		json_select_object "$name"
+
+		case "$val" in
+			true|false) [ "$val" != "true" ]; json_add_boolean "$key" $? ;;
+			[0-9]) json_add_int "$key" "$val" ;;
+			*) json_add_string "$key" "$val" ;;
+		esac
+
+		json_select ..
+	json_select ..
+}
+
+ucidef_add_switch_port_attr() {
+	local name="$1"
+	local port="$2"
+	local key="$3"
+	local val="$4"
+	local ports i num
+
+	json_select_object switch
+	json_select_object "$name"
+
+	json_get_keys ports ports
+	json_select_array ports
+
+	for i in $ports; do
+		json_select "$i"
+		json_get_var num num
+
+		if [ -n "$num" ] && [ $num -eq $port ]; then
+			json_select_object attr
+
+			case "$val" in
+				true|false) [ "$val" != "true" ]; json_add_boolean "$key" $? ;;
+				[0-9]) json_add_int "$key" "$val" ;;
+				*) json_add_string "$key" "$val" ;;
+			esac
+
+			json_select ..
+		fi
+
+		json_select ..
+	done
+
+	json_select ..
+	json_select ..
+	json_select ..
+}
+
+ucidef_set_interface_macaddr() {
+	local network="$1"
+	local macaddr="$2"
+
+	json_select_object network
+
+	json_select "$network"
+	[ $? -eq 0 ] || {
+		json_select ..
+		return
+	}
+
+	json_add_string macaddr "$macaddr"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_add_atm_bridge() {
+	local vpi="$1"
+	local vci="$2"
+	local encaps="$3"
+	local payload="$4"
+
+	json_select_object dsl
+		json_select_object atmbridge
+			json_add_int vpi "$vpi"
+			json_add_int vci "$vci"
+			json_add_string encaps "$encaps"
+			json_add_string payload "$payload"
+		json_select ..
+	json_select ..
+}
+
+ucidef_add_adsl_modem() {
+	local annex="$1"
+	local firmware="$2"
+
+	json_select_object dsl
+		json_select_object modem
+			json_add_string type "adsl"
+			json_add_string annex "$annex"
+			json_add_string firmware "$firmware"
+		json_select ..
+	json_select ..
+}
+
+ucidef_add_vdsl_modem() {
+	local annex="$1"
+	local tone="$2"
+	local xfer_mode="$3"
+
+	json_select_object dsl
+		json_select_object modem
+			json_add_string type "vdsl"
+			json_add_string annex "$annex"
+			json_add_string tone "$tone"
+			json_add_string xfer_mode "$xfer_mode"
+		json_select ..
+	json_select ..
+}
+
+ucidef_set_led_netdev() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local dev="$4"
+	local mode="${5:-link tx rx}"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string type netdev
+	json_add_string sysfs "$sysfs"
+	json_add_string device "$dev"
+	json_add_string mode "$mode"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_usbdev() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local dev="$4"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string type usb
+	json_add_string sysfs "$sysfs"
+	json_add_string device "$dev"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_usbport() {
+	local obj="$1"
+	local name="$2"
+	local sysfs="$3"
+	shift
+	shift
+	shift
+
+	json_select_object led
+
+	json_select_object "$obj"
+	json_add_string name "$name"
+	json_add_string type usbport
+	json_add_string sysfs "$sysfs"
+	json_select_array ports
+		for port in "$@"; do
+			json_add_string port "$port"
+		done
+	json_select ..
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_wlan() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local trigger="$4"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string type trigger
+	json_add_string sysfs "$sysfs"
+	json_add_string trigger "$trigger"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_switch() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local trigger="$4"
+	local port_mask="$5"
+	local speed_mask="$6"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string type switch
+	json_add_string sysfs "$sysfs"
+	json_add_string trigger "$trigger"
+	json_add_string port_mask "$port_mask"
+	json_add_string speed_mask "$speed_mask"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_portstate() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local port_state="$4"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string type portstate
+	json_add_string sysfs "$sysfs"
+	json_add_string trigger port_state
+	json_add_string port_state "$port_state"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_default() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local default="$4"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string sysfs "$sysfs"
+	json_add_string default "$default"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_gpio() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local gpio="$4"
+	local inverted="$5"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string type gpio
+	json_add_string name "$name"
+	json_add_string sysfs "$sysfs"
+	json_add_string trigger "$trigger"
+	json_add_int gpio "$gpio"
+	json_add_boolean inverted "$inverted"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_ide() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string name "$name"
+	json_add_string sysfs "$sysfs"
+	json_add_string trigger ide-disk
+	json_select ..
+
+	json_select ..
+}
+
+__ucidef_set_led_timer() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local trigger="$4"
+	local delayon="$5"
+	local delayoff="$6"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string type "$trigger"
+	json_add_string name "$name"
+	json_add_string sysfs "$sysfs"
+	json_add_int delayon "$delayon"
+	json_add_int delayoff "$delayoff"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_led_oneshot() {
+	__ucidef_set_led_timer $1 $2 $3 "oneshot" $4 $5
+}
+
+ucidef_set_led_timer() {
+	__ucidef_set_led_timer $1 $2 $3 "timer" $4 $5
+}
+
+ucidef_set_led_rssi() {
+	local cfg="led_$1"
+	local name="$2"
+	local sysfs="$3"
+	local iface="$4"
+	local minq="$5"
+	local maxq="$6"
+	local offset="$7"
+	local factor="$8"
+
+	json_select_object led
+
+	json_select_object "$1"
+	json_add_string type rssi
+	json_add_string name "$name"
+	json_add_string iface "$iface"
+	json_add_string sysfs "$sysfs"
+	json_add_string minq "$minq"
+	json_add_string maxq "$maxq"
+	json_add_string offset "$offset"
+	json_add_string factor "$factor"
+	json_select ..
+
+	json_select ..
+}
+
+ucidef_set_rssimon() {
+	local dev="$1"
+	local refresh="$2"
+	local threshold="$3"
+
+	json_select_object rssimon
+
+	json_select_object "$dev"
+	[ -n "$refresh" ] && json_add_int refresh "$refresh"
+	[ -n "$threshold" ] && json_add_int threshold "$threshold"
+	json_select ..
+
+	json_select ..
+
+}
+
+ucidef_add_gpio_switch() {
+	local cfg="$1"
+	local name="$2"
+	local pin="$3"
+	local default="${4:-0}"
+
+	json_select_object gpioswitch
+		json_select_object "$cfg"
+			json_add_string name "$name"
+			json_add_int pin "$pin"
+			json_add_int default "$default"
+		json_select ..
+	json_select ..
+}
+
+board_config_update() {
+	json_init
+	[ -f ${CFG} ] && json_load "$(cat ${CFG})"
+
+	# auto-initialize model id and name if applicable
+	if ! json_is_a model object; then
+		json_select_object model
+			[ -f "/tmp/sysinfo/board_name" ] && \
+				json_add_string id "$(cat /tmp/sysinfo/board_name)"
+			[ -f "/tmp/sysinfo/model" ] && \
+				json_add_string name "$(cat /tmp/sysinfo/model)"
+		json_select ..
+	fi
+}
+
+board_config_flush() {
+	json_dump -i > /tmp/.board.json
+	mv /tmp/.board.json ${CFG}
+}
diff --git a/package/base-files/files/lib/preinit/02_default_set_state b/package/base-files/files/lib/preinit/02_default_set_state
new file mode 100644
index 0000000000..df43395726
--- /dev/null
+++ b/package/base-files/files/lib/preinit/02_default_set_state
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+define_default_set_state() {
+	. /etc/diag.sh
+}
+
+boot_hook_add preinit_main define_default_set_state
diff --git a/package/base-files/files/lib/preinit/10_indicate_failsafe b/package/base-files/files/lib/preinit/10_indicate_failsafe
new file mode 100644
index 0000000000..27b94c140f
--- /dev/null
+++ b/package/base-files/files/lib/preinit/10_indicate_failsafe
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+# commands for emitting messages to network in failsafe mode
+
+indicate_failsafe_led () {
+	set_state failsafe
+}
+
+indicate_failsafe() {
+	[ "$pi_preinit_no_failsafe" = "y" ] && return
+	echo "- failsafe -"
+	preinit_net_echo "Entering Failsafe!\n"
+	indicate_failsafe_led
+}
+
+boot_hook_add failsafe indicate_failsafe
diff --git a/package/base-files/files/lib/preinit/10_indicate_preinit b/package/base-files/files/lib/preinit/10_indicate_preinit
new file mode 100644
index 0000000000..a30bf34f6e
--- /dev/null
+++ b/package/base-files/files/lib/preinit/10_indicate_preinit
@@ -0,0 +1,154 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+preinit_ip_config() {
+	local netdev vid
+
+	netdev=${1%\.*}
+	vid=${1#*\.}
+
+	if [ "$vid" = "$netdev" ]; then
+		vid=
+	fi
+
+	grep -q "$netdev" /proc/net/dev || return
+
+	if [ -n "$vid" ]; then
+		ip link add link $netdev name $1 type vlan id $vid
+	fi
+
+	ip link set dev $netdev up
+	ip -4 address add $pi_ip/$pi_netmask broadcast $pi_broadcast dev $1
+}
+
+preinit_config_switch() {
+	local role roles ports device enable reset
+
+	local name=$1
+	local lan_if=$2
+
+	json_select switch
+	json_select $name
+
+	json_get_vars enable reset
+
+	if json_is_a roles array; then
+		json_get_keys roles roles
+		json_select roles
+
+		for role in $roles; do
+			json_select "$role"
+			json_get_vars ports device
+			json_select ..
+
+			if [ "$device" = "$lan_if" ]; then
+				swconfig dev $name set reset $reset
+				swconfig dev $name set enable_vlan $enable
+				swconfig dev $name vlan $role set ports "$ports"
+				swconfig dev $name set apply
+			fi
+		done
+
+		json_select ..
+	fi
+
+	json_select ..
+	json_select ..
+}
+
+preinit_config_board() {
+	/bin/board_detect /tmp/board.json
+
+	[ -f "/tmp/board.json" ] || return
+
+	. /usr/share/libubox/jshn.sh
+
+	json_init
+	json_load "$(cat /tmp/board.json)"
+
+	json_select network
+		json_select "lan"
+			json_get_vars ifname
+		json_select ..
+	json_select ..
+
+	[ -n "$ifname" ] || return
+
+	# only use the first one
+	ifname=${ifname%% *}
+
+	if [ -x /sbin/swconfig ]; then
+		# configure the switch, if present
+
+		json_get_keys keys switch
+		for key in $keys; do
+			preinit_config_switch $key $ifname
+		done
+	else
+		# trim any vlan ids
+		ifname=${ifname%\.*}
+	fi
+
+	pi_ifname=$ifname
+
+	preinit_ip_config $pi_ifname
+}
+
+preinit_ip() {
+	# if the preinit interface isn't specified and ifname is set in
+	# preinit.arch use that interface
+	if [ -z "$pi_ifname" ]; then
+		pi_ifname=$ifname
+	fi
+
+	if [ -n "$pi_ifname" ]; then
+		preinit_ip_config $pi_ifname
+	elif [ -d "/etc/board.d/" ]; then
+		preinit_config_board
+	fi
+}
+
+preinit_ip_deconfig() {
+	[ -n "$pi_ifname" ] && grep -q "$pi_ifname" /proc/net/dev && {
+		local netdev vid
+
+		netdev=${pi_ifname%\.*}
+		vid=${pi_ifname#*\.}
+
+		if [ "$vid" = "$netdev" ]; then
+			vid=
+		fi
+
+		ip -4 address flush dev $pi_ifname
+		ip link set dev $netdev down
+
+		if [ -n "$vid" ]; then
+			ip link delete $pi_ifname
+		fi
+	}
+}
+
+preinit_net_echo() {
+	[ -n "$pi_ifname" ] && grep -q "$pi_ifname" /proc/net/dev && {
+		{
+			[ "$pi_preinit_net_messages" = "y" ] || {
+				[ "$pi_failsafe_net_message" = "true" ] &&
+					[ "$pi_preinit_no_failsafe_netmsg" != "y" ]
+			}
+		} && netmsg $pi_broadcast "$1"
+	}
+}
+
+preinit_echo() {
+	preinit_net_echo $1
+	echo $1
+}
+
+pi_indicate_preinit() {
+	preinit_net_echo "Doing Lede Preinit\n"
+	set_state preinit
+}
+
+boot_hook_add preinit_main preinit_ip
+boot_hook_add preinit_main pi_indicate_preinit
diff --git a/package/base-files/files/lib/preinit/10_sysinfo b/package/base-files/files/lib/preinit/10_sysinfo
new file mode 100644
index 0000000000..be1e6aeca9
--- /dev/null
+++ b/package/base-files/files/lib/preinit/10_sysinfo
@@ -0,0 +1,10 @@
+do_sysinfo_generic() {
+	[ -d /proc/device-tree ] || return
+	mkdir -p /tmp/sysinfo
+	[ -e /tmp/sysinfo/board_name ] || \
+		echo "$(strings /proc/device-tree/compatible | head -1)" > /tmp/sysinfo/board_name
+	[ -n /tmp/sysinfo/model -a -e /proc/device-tree/model ] && \
+		echo "$(cat /proc/device-tree/model)" > /tmp/sysinfo/model
+}
+
+boot_hook_add preinit_main do_sysinfo_generic
diff --git a/package/base-files/files/lib/preinit/30_failsafe_wait b/package/base-files/files/lib/preinit/30_failsafe_wait
new file mode 100644
index 0000000000..9a34f2de4c
--- /dev/null
+++ b/package/base-files/files/lib/preinit/30_failsafe_wait
@@ -0,0 +1,100 @@
+#!/bin/sh
+# Copyright (C) 2006-2010 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+fs_wait_for_key () {
+	local timeout=$3
+	local timer
+	local do_keypress
+	local keypress_true="$(mktemp)"
+	local keypress_wait="$(mktemp)"
+	local keypress_sec="$(mktemp)"
+	if [ -z "$keypress_wait" ]; then
+		keypress_wait=/tmp/.keypress_wait
+		touch $keypress_wait
+	fi
+	if [ -z "$keypress_true" ]; then
+		keypress_true=/tmp/.keypress_true
+		touch $keypress_true
+	fi
+	if [ -z "$keypress_sec" ]; then
+		keypress_sec=/tmp/.keypress_sec
+		touch $keypress_sec
+	fi
+
+	trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" INT
+	trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" USR1
+
+	[ -n "$timeout" ] || timeout=1
+	[ $timeout -ge 1 ] || timeout=1
+	timer=$timeout
+	lock $keypress_wait
+	{
+		while [ $timer -gt 0 ]; do
+			echo "$timer" >$keypress_sec
+			timer=$(($timer - 1))
+			sleep 1
+		done
+		lock -u $keypress_wait
+		rm -f $keypress_wait
+	} &
+
+	[ "$pi_preinit_no_failsafe" != "y" ] && echo "Press the [$1] key and hit [enter] $2"
+	echo "Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level"
+	# if we're on the console we wait for input
+	{
+		while [ -r $keypress_wait ]; do
+			timer="$(cat $keypress_sec)"
+
+			[ -n "$timer" ] || timer=1
+			timer="${timer%%\ *}"
+			[ $timer -ge 1 ] || timer=1
+			do_keypress=""
+			{
+				read -t "$timer" do_keypress
+				case "$do_keypress" in
+				$1)
+					echo "true" >$keypress_true
+					;;
+				1 | 2 | 3 | 4)
+					echo "$do_keypress" >/tmp/debug_level
+					;;
+				*)
+					continue;
+					;;
+				esac
+				lock -u $keypress_wait
+				rm -f $keypress_wait
+			}
+		done
+	}
+	lock -w $keypress_wait
+
+	keypressed=1
+	[ "$(cat $keypress_true)" = "true" ] && keypressed=0
+
+	rm -f $keypress_true
+	rm -f $keypress_wait
+	rm -f $keypress_sec
+
+	return $keypressed
+}
+
+failsafe_wait() {
+	FAILSAFE=
+	[ "$pi_preinit_no_failsafe" == "y" ] && {
+		fs_wait_for_key "" "" $fs_failsafe_wait_timeout
+		return
+	}
+	grep -q 'failsafe=' /proc/cmdline && FAILSAFE=true && export FAILSAFE
+	if [ "$FAILSAFE" != "true" ]; then
+		pi_failsafe_net_message=true
+		preinit_net_echo "Please press button now to enter failsafe"
+		pi_failsafe_net_message=false
+		fs_wait_for_key f 'to enter failsafe mode' $fs_failsafe_wait_timeout && FAILSAFE=true
+		[ -f "/tmp/failsafe_button" ] && FAILSAFE=true && echo "- failsafe button "`cat /tmp/failsafe_button`" was pressed -"
+		[ "$FAILSAFE" = "true" ] && export FAILSAFE && touch /tmp/failsafe
+	fi
+}
+
+boot_hook_add preinit_main failsafe_wait
diff --git a/package/base-files/files/lib/preinit/40_run_failsafe_hook b/package/base-files/files/lib/preinit/40_run_failsafe_hook
new file mode 100644
index 0000000000..7301f77349
--- /dev/null
+++ b/package/base-files/files/lib/preinit/40_run_failsafe_hook
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright (C) 2006-2010 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+run_failsafe_hook() {
+    [ "$pi_preinit_no_failsafe" = "y" ] && return
+    if [ "$FAILSAFE" = "true" ]; then
+	boot_run_hook failsafe
+	lock -w /tmp/.failsafe
+    fi
+}
+
+boot_hook_add preinit_main run_failsafe_hook
diff --git a/package/base-files/files/lib/preinit/50_indicate_regular_preinit b/package/base-files/files/lib/preinit/50_indicate_regular_preinit
new file mode 100644
index 0000000000..5b7523f6fd
--- /dev/null
+++ b/package/base-files/files/lib/preinit/50_indicate_regular_preinit
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+indicate_regular_preinit() {
+	preinit_net_echo "Continuing with Regular Preinit\n"
+	set_state preinit_regular
+}
+
+boot_hook_add preinit_main indicate_regular_preinit
diff --git a/package/base-files/files/lib/preinit/70_initramfs_test b/package/base-files/files/lib/preinit/70_initramfs_test
new file mode 100644
index 0000000000..8504e34db0
--- /dev/null
+++ b/package/base-files/files/lib/preinit/70_initramfs_test
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+initramfs_test() {
+	if [ -n "$INITRAMFS" ]; then
+		boot_run_hook initramfs
+		preinit_ip_deconfig
+		break
+	fi
+}
+
+boot_hook_add preinit_main initramfs_test
diff --git a/package/base-files/files/lib/preinit/80_mount_root b/package/base-files/files/lib/preinit/80_mount_root
new file mode 100644
index 0000000000..f3fe788e19
--- /dev/null
+++ b/package/base-files/files/lib/preinit/80_mount_root
@@ -0,0 +1,15 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+do_mount_root() {
+	mount_root
+	boot_run_hook preinit_mount_root
+	[ -f /sysupgrade.tgz ] && {
+		echo "- config restore -"
+		cd /
+		tar xzf /sysupgrade.tgz
+	}
+}
+
+[ "$INITRAMFS" = "1" ] || boot_hook_add preinit_main do_mount_root
diff --git a/package/base-files/files/lib/preinit/81_urandom_seed b/package/base-files/files/lib/preinit/81_urandom_seed
new file mode 100644
index 0000000000..10878f3dc2
--- /dev/null
+++ b/package/base-files/files/lib/preinit/81_urandom_seed
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+log_urandom_seed() {
+    echo "urandom-seed: $1" > /dev/kmsg
+}
+
+_do_urandom_seed() {
+    [ -f "$1" ] || { log_urandom_seed "Seed file not found ($1)"; return; }
+    [ -O "$1" -a -G "$1" -a ! -x "$1" ] || { log_urandom_seed "Wrong owner / permissions for $1"; return; }
+
+    log_urandom_seed "Seeding with $1"
+    cat "$1" > /dev/urandom
+}
+
+do_urandom_seed() {
+    [ -c /dev/urandom ] || { log_urandom_seed "Something is wrong with /dev/urandom"; return; }
+
+    _do_urandom_seed "/etc/urandom.seed"
+
+    SEED="$(uci -q get system.@system[0].urandom_seed)"
+    [ "${SEED:0:1}" == "/" -a "$SEED" != "/etc/urandom.seed" ] && _do_urandom_seed "$SEED"
+}
+
+boot_hook_add preinit_main do_urandom_seed
diff --git a/package/base-files/files/lib/preinit/99_10_failsafe_login b/package/base-files/files/lib/preinit/99_10_failsafe_login
new file mode 100644
index 0000000000..3147cdc5a6
--- /dev/null
+++ b/package/base-files/files/lib/preinit/99_10_failsafe_login
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Copyright (C) 2006-2015 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+failsafe_netlogin () {
+	dropbearkey -t rsa -s 1024 -f /tmp/dropbear_failsafe_host_key
+	dropbear -r /tmp/dropbear_failsafe_host_key <> /dev/null 2>&1
+}
+
+failsafe_shell() {
+	lock /tmp/.failsafe
+	ash --login
+	echo "Please reboot system when done with failsafe network logins"
+	while true; do sleep 1; done
+}
+
+boot_hook_add failsafe failsafe_netlogin
+boot_hook_add failsafe failsafe_shell
diff --git a/package/base-files/files/lib/preinit/99_10_run_init b/package/base-files/files/lib/preinit/99_10_run_init
new file mode 100644
index 0000000000..b4f0ec203d
--- /dev/null
+++ b/package/base-files/files/lib/preinit/99_10_run_init
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+run_init() {
+	preinit_ip_deconfig
+}
+
+boot_hook_add preinit_main run_init
diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
new file mode 100644
index 0000000000..4d0e6d5f17
--- /dev/null
+++ b/package/base-files/files/lib/upgrade/common.sh
@@ -0,0 +1,253 @@
+#!/bin/sh
+
+RAM_ROOT=/tmp/root
+
+[ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; }
+libs() { ldd $* 2>/dev/null | sed -r 's/(.* => )?(.*) .*/\2/'; }
+
+install_file() { # <file> [ <file> ... ]
+	for file in "$@"; do
+		dest="$RAM_ROOT/$file"
+		[ -f $file -a ! -f $dest ] && {
+			dir="$(dirname $dest)"
+			mkdir -p "$dir"
+			cp $file $dest
+		}
+	done
+}
+
+install_bin() { # <file> [ <symlink> ... ]
+	src=$1
+	files=$1
+	[ -x "$src" ] && files="$src $(libs $src)"
+	install_file $files
+	shift
+	for link in "$@"; do {
+		dest="$RAM_ROOT/$link"
+		dir="$(dirname $dest)"
+		mkdir -p "$dir"
+		[ -f "$dest" ] || ln -s $src $dest
+	}; done
+}
+
+supivot() { # <new_root> <old_root>
+	/bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
+	mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
+	/bin/mount -o noatime,move /proc $1/proc && \
+	pivot_root $1 $1$2 || {
+		/bin/umount -l $1 $1
+		return 1
+	}
+
+	/bin/mount -o noatime,move $2/sys /sys
+	/bin/mount -o noatime,move $2/dev /dev
+	/bin/mount -o noatime,move $2/tmp /tmp
+	/bin/mount -o noatime,move $2/overlay /overlay 2>&-
+	return 0
+}
+
+run_ramfs() { # <command> [...]
+	install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount	\
+		/sbin/pivot_root /sbin/reboot /bin/sync /bin/dd	/bin/grep       \
+		/bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd	\
+		/bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump		\
+		/bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
+		/bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir	\
+		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find
+
+	install_bin /bin/uclient-fetch /bin/wget
+	install_bin /sbin/mtd
+	install_bin /sbin/mount_root
+	install_bin /sbin/snapshot
+	install_bin /sbin/snapshot_tool
+	install_bin /usr/sbin/ubiupdatevol
+	install_bin /usr/sbin/ubiattach
+	install_bin /usr/sbin/ubiblock
+	install_bin /usr/sbin/ubiformat
+	install_bin /usr/sbin/ubidetach
+	install_bin /usr/sbin/ubirsvol
+	install_bin /usr/sbin/ubirmvol
+	install_bin /usr/sbin/ubimkvol
+	install_bin /usr/sbin/partx
+	install_bin /usr/sbin/losetup
+	install_bin /usr/sbin/mkfs.ext4
+	for file in $RAMFS_COPY_BIN; do
+		install_bin ${file//:/ }
+	done
+	install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA
+
+	[ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64
+
+	supivot $RAM_ROOT /mnt || {
+		echo "Failed to switch over to ramfs. Please reboot."
+		exit 1
+	}
+
+	/bin/mount -o remount,ro /mnt
+	/bin/umount -l /mnt
+
+	grep /overlay /proc/mounts > /dev/null && {
+		/bin/mount -o noatime,remount,ro /overlay
+		/bin/umount -l /overlay
+	}
+
+	# spawn a new shell from ramdisk to reduce the probability of cache issues
+	exec /bin/busybox ash -c "$*"
+}
+
+kill_remaining() { # [ <signal> ]
+	local sig="${1:-TERM}"
+	echo -n "Sending $sig to remaining processes ... "
+
+	local my_pid=$$
+	local my_ppid=$(cut -d' ' -f4  /proc/$my_pid/stat)
+	local my_ppisupgraded=
+	grep -q upgraded /proc/$my_ppid/cmdline >/dev/null && {
+		local my_ppisupgraded=1
+	}
+	
+	local stat
+	for stat in /proc/[0-9]*/stat; do
+		[ -f "$stat" ] || continue
+
+		local pid name state ppid rest
+		read pid name state ppid rest < $stat
+		name="${name#(}"; name="${name%)}"
+
+		local cmdline
+		read cmdline < /proc/$pid/cmdline
+
+		# Skip kernel threads
+		[ -n "$cmdline" ] || continue
+
+		if [ $$ -eq 1 ] || [ $my_ppid -eq 1 ] && [ -n "$my_ppisupgraded" ]; then
+			# Running as init process, kill everything except me
+			if [ $pid -ne $$ ] && [ $pid -ne $my_ppid ]; then
+				echo -n "$name "
+				kill -$sig $pid 2>/dev/null
+			fi
+		else 
+			case "$name" in
+				# Skip essential services
+				*procd*|*ash*|*init*|*watchdog*|*ssh*|*dropbear*|*telnet*|*login*|*hostapd*|*wpa_supplicant*|*nas*|*relayd*) : ;;
+
+				# Killable process
+				*)
+					if [ $pid -ne $$ ] && [ $ppid -ne $$ ]; then
+						echo -n "$name "
+						kill -$sig $pid 2>/dev/null
+					fi
+				;;
+			esac
+		fi
+	done
+	echo ""
+}
+
+run_hooks() {
+	local arg="$1"; shift
+	for func in "$@"; do
+		eval "$func $arg"
+	done
+}
+
+ask_bool() {
+	local default="$1"; shift;
+	local answer="$default"
+
+	[ "$INTERACTIVE" -eq 1 ] && {
+		case "$default" in
+			0) echo -n "$* (y/N): ";;
+			*) echo -n "$* (Y/n): ";;
+		esac
+		read answer
+		case "$answer" in
+			y*) answer=1;;
+			n*) answer=0;;
+			*) answer="$default";;
+		esac
+	}
+	[ "$answer" -gt 0 ]
+}
+
+v() {
+	[ "$VERBOSE" -ge 1 ] && echo "$@"
+}
+
+rootfs_type() {
+	/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
+}
+
+get_image() { # <source> [ <command> ]
+	local from="$1"
+	local conc="$2"
+	local cmd
+
+	case "$from" in
+		http://*|ftp://*) cmd="wget -O- -q";;
+		*) cmd="cat";;
+	esac
+	if [ -z "$conc" ]; then
+		local magic="$(eval $cmd \"$from\" 2>/dev/null | dd bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
+		case "$magic" in
+			1f8b) conc="zcat";;
+			425a) conc="bzcat";;
+		esac
+	fi
+
+	eval "$cmd \"$from\" 2>/dev/null ${conc:+| $conc}"
+}
+
+get_magic_word() {
+	(get_image "$@" | dd bs=2 count=1 | hexdump -v -n 2 -e '1/1 "%02x"') 2>/dev/null
+}
+
+get_magic_long() {
+	(get_image "$@" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null
+}
+
+jffs2_copy_config() {
+	if grep rootfs_data /proc/mtd >/dev/null; then
+		# squashfs+jffs2
+		mtd -e rootfs_data jffs2write "$CONF_TAR" rootfs_data
+	else
+		# jffs2
+		mtd jffs2write "$CONF_TAR" rootfs
+	fi
+}
+
+# Flash firmware to MTD partition
+#
+# $(1): path to image
+# $(2): (optional) pipe command to extract firmware, e.g. dd bs=n skip=m
+default_do_upgrade() {
+	sync
+	if [ "$SAVE_CONFIG" -eq 1 ]; then
+		get_image "$1" "$2" | mtd $MTD_CONFIG_ARGS -j "$CONF_TAR" write - "${PART_NAME:-image}"
+	else
+		get_image "$1" "$2" | mtd write - "${PART_NAME:-image}"
+	fi
+}
+
+do_upgrade() {
+	v "Performing system upgrade..."
+	if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
+		platform_do_upgrade "$ARGV"
+	else
+		default_do_upgrade "$ARGV"
+	fi
+
+	if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
+		platform_copy_config
+	fi
+
+	v "Upgrade completed"
+	[ -n "$DELAY" ] && sleep "$DELAY"
+	ask_bool 1 "Reboot" && {
+		v "Rebooting system..."
+		umount -a
+		reboot -f
+		sleep 5
+		echo b 2>/dev/null >/proc/sysrq-trigger
+	}
+}
diff --git a/package/base-files/files/lib/upgrade/fwtool.sh b/package/base-files/files/lib/upgrade/fwtool.sh
new file mode 100644
index 0000000000..49f02b7bd9
--- /dev/null
+++ b/package/base-files/files/lib/upgrade/fwtool.sh
@@ -0,0 +1,43 @@
+fwtool_pre_upgrade() {
+	fwtool -q -i /dev/null "$1"
+}
+
+fwtool_check_image() {
+	[ $# -gt 1 ] && return 1
+
+	. /usr/share/libubox/jshn.sh
+
+	if ! fwtool -q -i /tmp/sysupgrade.meta "$1"; then
+		echo "Image metadata not found"
+		[ "$REQUIRE_IMAGE_METADATA" = 1 -a "$FORCE" != 1 ] && {
+			echo "Use sysupgrade -F to override this check when downgrading or flashing to vendor firmware"
+		}
+		[ "$REQUIRE_IMAGE_METADATA" = 1 ] && return 1
+		return 0
+	fi
+
+	json_load "$(cat /tmp/sysupgrade.meta)" || {
+		echo "Invalid image metadata"
+		return 1
+	}
+
+	device="$(cat /tmp/sysinfo/board_name)"
+
+	json_select supported_devices || return 1
+
+	json_get_keys dev_keys
+	for k in $dev_keys; do
+		json_get_var dev "$k"
+		[ "$dev" = "$device" ] && return 0
+	done
+
+	echo "Device $device not supported by this image"
+	echo -n "Supported devices:"
+	for k in $dev_keys; do
+		json_get_var dev "$k"
+		echo -n " $dev"
+	done
+	echo
+
+	return 1
+}
diff --git a/package/base-files/files/lib/upgrade/keep.d/base-files-essential b/package/base-files/files/lib/upgrade/keep.d/base-files-essential
new file mode 100644
index 0000000000..978d4b58bc
--- /dev/null
+++ b/package/base-files/files/lib/upgrade/keep.d/base-files-essential
@@ -0,0 +1,10 @@
+# Essential files that will be always kept
+/etc/hosts
+/etc/inittab
+/etc/group
+/etc/passwd
+/etc/profile
+/etc/shadow
+/etc/shells
+/etc/sysctl.conf
+/etc/rc.local
diff --git a/package/base-files/files/rom/note b/package/base-files/files/rom/note
new file mode 100644
index 0000000000..1746eb0509
--- /dev/null
+++ b/package/base-files/files/rom/note
@@ -0,0 +1,3 @@
+SQUASHFS USERS:
+After firstboot has been run, / will be jffs2 and /rom will be squashfs
+(* except when in failsafe)
diff --git a/package/base-files/files/sbin/firstboot b/package/base-files/files/sbin/firstboot
new file mode 100755
index 0000000000..d9af57d596
--- /dev/null
+++ b/package/base-files/files/sbin/firstboot
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+/sbin/jffs2reset $@
diff --git a/package/base-files/files/sbin/hotplug-call b/package/base-files/files/sbin/hotplug-call
new file mode 100755
index 0000000000..28e957c398
--- /dev/null
+++ b/package/base-files/files/sbin/hotplug-call
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Copyright (C) 2006-2016 OpenWrt.org
+
+export HOTPLUG_TYPE="$1"
+
+. /lib/functions.sh
+
+PATH="%PATH%"
+LOGNAME=root
+USER=root
+export PATH LOGNAME USER
+export DEVICENAME="${DEVPATH##*/}"
+
+[ \! -z "$1" -a -d /etc/hotplug.d/$1 ] && {
+	for script in $(ls /etc/hotplug.d/$1/* 2>&-); do (
+		[ -f $script ] && . $script
+	); done
+}
diff --git a/package/base-files/files/sbin/led.sh b/package/base-files/files/sbin/led.sh
new file mode 100755
index 0000000000..d750f06ea7
--- /dev/null
+++ b/package/base-files/files/sbin/led.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# (C) 2008 openwrt.org
+
+. /lib/functions.sh
+ACTION=$1
+NAME=$2
+do_led() {
+	local name
+	local sysfs
+	config_get name $1 name
+	config_get sysfs $1 sysfs
+	[ "$name" = "$NAME" -o "$sysfs" = "$NAME" -a -e "/sys/class/leds/${sysfs}" ] && {
+		[ "$ACTION" = "set" ] &&
+			echo 1 >/sys/class/leds/${sysfs}/brightness \
+			|| echo 0 >/sys/class/leds/${sysfs}/brightness
+		exit 0
+	}
+}
+
+[ "$1" = "clear" -o "$1" = "set" ] &&
+	[ -n "$2" ] &&{
+		config_load system
+		config_foreach do_led
+		exit 1
+	}
diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
new file mode 100755
index 0000000000..c095ca81c5
--- /dev/null
+++ b/package/base-files/files/sbin/sysupgrade
@@ -0,0 +1,245 @@
+#!/bin/sh
+. /lib/functions.sh
+. /lib/functions/system.sh
+
+# initialize defaults
+RAMFS_COPY_BIN=""	# extra programs for temporary ramfs root
+RAMFS_COPY_DATA=""	# extra data files
+export MTD_CONFIG_ARGS=""
+export INTERACTIVE=0
+export VERBOSE=1
+export SAVE_CONFIG=1
+export SAVE_OVERLAY=0
+export SAVE_PARTITIONS=1
+export DELAY=
+export CONF_IMAGE=
+export CONF_BACKUP_LIST=0
+export CONF_BACKUP=
+export CONF_RESTORE=
+export NEED_IMAGE=
+export HELP=0
+export FORCE=0
+export TEST=0
+
+# parse options
+while [ -n "$1" ]; do
+	case "$1" in
+		-i) export INTERACTIVE=1;;
+		-d) export DELAY="$2"; shift;;
+		-v) export VERBOSE="$(($VERBOSE + 1))";;
+		-q) export VERBOSE="$(($VERBOSE - 1))";;
+		-n) export SAVE_CONFIG=0;;
+		-c) export SAVE_OVERLAY=1;;
+		-p) export SAVE_PARTITIONS=0;;
+		-b|--create-backup) export CONF_BACKUP="$2" NEED_IMAGE=1; shift;;
+		-r|--restore-backup) export CONF_RESTORE="$2" NEED_IMAGE=1; shift;;
+		-l|--list-backup) export CONF_BACKUP_LIST=1; break;;
+		-f) export CONF_IMAGE="$2"; shift;;
+		-F|--force) export FORCE=1;;
+		-T|--test) export TEST=1;;
+		-h|--help) export HELP=1; break;;
+		-*)
+			echo "Invalid option: $1"
+			exit 1
+		;;
+		*) break;;
+	esac
+	shift;
+done
+
+export CONFFILES=/tmp/sysupgrade.conffiles
+export CONF_TAR=/tmp/sysupgrade.tgz
+
+export ARGV="$*"
+export ARGC="$#"
+
+[ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
+	cat <<EOF
+Usage: $0 [<upgrade-option>...] <image file or URL>
+       $0 [-q] [-i] <backup-command> <file>
+
+upgrade-option:
+	-d <delay>   add a delay before rebooting
+	-f <config>  restore configuration from .tar.gz (file or url)
+	-i           interactive mode
+	-c           attempt to preserve all changed files in /etc/
+	-n           do not save configuration over reflash
+	-p           do not attempt to restore the partition table after flash.
+	-T | --test
+	             Verify image and config .tar.gz but do not actually flash.
+	-F | --force
+	             Flash image even if image checks fail, this is dangerous!
+	-q           less verbose
+	-v           more verbose
+	-h | --help  display this help
+
+backup-command:
+	-b | --create-backup <file>
+	             create .tar.gz of files specified in sysupgrade.conf
+	             then exit. Does not flash an image. If file is '-',
+	             i.e. stdout, verbosity is set to 0 (i.e. quiet).
+	-r | --restore-backup <file>
+	             restore a .tar.gz created with sysupgrade -b
+	             then exit. Does not flash an image. If file is '-',
+	             the archive is read from stdin.
+	-l | --list-backup
+	             list the files that would be backed up when calling
+	             sysupgrade -b. Does not create a backup file.
+
+EOF
+	exit 1
+}
+
+[ -n "$ARGV" -a -n "$NEED_IMAGE" ] && {
+	cat <<-EOF
+		-b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
+		Do not specify both -b|-r and a firmware image.
+	EOF
+	exit 1
+}
+
+# prevent messages from clobbering the tarball when using stdout
+[ "$CONF_BACKUP" = "-" ] && export VERBOSE=0
+
+add_uci_conffiles() {
+	local file="$1"
+	( find $(sed -ne '/^[[:space:]]*$/d; /^#/d; p' \
+		/etc/sysupgrade.conf /lib/upgrade/keep.d/* 2>/dev/null) \
+		-type f -o -type l 2>/dev/null;
+	  opkg list-changed-conffiles ) | sort -u > "$file"
+	return 0
+}
+
+add_overlayfiles() {
+	local file="$1"
+	if [ -d /overlay/upper ]; then
+		local overlaydir="/overlay/upper"
+	else
+		local overlaydir="/overlay"
+	fi
+	find $overlaydir/etc/ -type f -o -type l | sed \
+		-e 's,^/overlay\/upper/,/,' \
+		-e 's,^/overlay/,/,' \
+		-e '\,/META_[a-zA-Z0-9]*$,d' \
+		-e '\,/functions.sh$,d' \
+		-e '\,/[^/]*-opkg$,d' \
+	> "$file"
+	return 0
+}
+
+# hooks
+sysupgrade_image_check="fwtool_check_image platform_check_image"
+sysupgrade_pre_upgrade="fwtool_pre_upgrade"
+[ $SAVE_OVERLAY = 0 -o ! -d /overlay/etc ] && \
+	sysupgrade_init_conffiles="add_uci_conffiles" || \
+	sysupgrade_init_conffiles="add_overlayfiles"
+
+include /lib/upgrade
+
+[ "$1" = "nand" ] && nand_upgrade_stage2 $@
+
+do_save_conffiles() {
+	local conf_tar="${1:-$CONF_TAR}"
+
+	[ -z "$(rootfs_type)" ] && {
+		echo "Cannot save config while running from ramdisk."
+		ask_bool 0 "Abort" && exit
+		return 0
+	}
+	run_hooks "$CONFFILES" $sysupgrade_init_conffiles
+	ask_bool 0 "Edit config file list" && vi "$CONFFILES"
+
+	v "Saving config files..."
+	[ "$VERBOSE" -gt 1 ] && TAR_V="v" || TAR_V=""
+	tar c${TAR_V}zf "$conf_tar" -T "$CONFFILES" 2>/dev/null
+
+	rm -f "$CONFFILES"
+}
+
+if [ $CONF_BACKUP_LIST -eq 1 ]; then
+	add_uci_conffiles "$CONFFILES"
+	cat "$CONFFILES"
+	rm -f "$CONFFILES"
+	exit 0
+fi
+
+if [ -n "$CONF_BACKUP" ]; then
+	do_save_conffiles "$CONF_BACKUP"
+	exit $?
+fi
+
+if [ -n "$CONF_RESTORE" ]; then
+	if [ "$CONF_RESTORE" != "-" ] && [ ! -f "$CONF_RESTORE" ]; then
+		echo "Backup archive '$CONF_RESTORE' not found."
+		exit 1
+	fi
+
+	[ "$VERBOSE" -gt 1 ] && TAR_V="v" || TAR_V=""
+	tar -C / -x${TAR_V}zf "$CONF_RESTORE"
+	exit $?
+fi
+
+type platform_check_image >/dev/null 2>/dev/null || {
+	echo "Firmware upgrade is not implemented for this platform."
+	exit 1
+}
+
+for check in $sysupgrade_image_check; do
+	( eval "$check \"\$ARGV\"" ) || {
+		if [ $FORCE -eq 1 ]; then
+			echo "Image check '$check' failed but --force given - will update anyway!"
+			break
+		else
+			echo "Image check '$check' failed."
+			exit 1
+		fi
+	}
+done
+
+if [ -n "$CONF_IMAGE" ]; then
+	case "$(get_magic_word $CONF_IMAGE cat)" in
+		# .gz files
+		1f8b) ;;
+		*)
+			echo "Invalid config file. Please use only .tar.gz files"
+			exit 1
+		;;
+	esac
+	get_image "$CONF_IMAGE" "cat" > "$CONF_TAR"
+	export SAVE_CONFIG=1
+elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
+	[ $TEST -eq 1 ] || do_save_conffiles
+	export SAVE_CONFIG=1
+else
+	export SAVE_CONFIG=0
+fi
+
+if [ $TEST -eq 1 ]; then
+	exit 0
+fi
+
+run_hooks "" $sysupgrade_pre_upgrade
+
+# Some platforms/devices may want different sysupgrade process, e.g. without
+# killing processes yet or calling ubus system upgrade method.
+# This is needed e.g. on NAND devices where we just want to trigger stage1 at
+# this point.
+if type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
+	platform_pre_upgrade "$ARGV"
+fi
+
+ubus call system upgrade
+touch /tmp/sysupgrade
+
+if [ ! -f /tmp/failsafe ] ; then
+	kill_remaining TERM
+	sleep 3
+	kill_remaining KILL
+fi
+
+if [ -n "$(rootfs_type)" ]; then
+	v "Switching to ramdisk..."
+	run_ramfs '. /lib/functions.sh; include /lib/upgrade; do_upgrade'
+else
+	do_upgrade
+fi
diff --git a/package/base-files/files/sbin/urandom_seed b/package/base-files/files/sbin/urandom_seed
new file mode 100755
index 0000000000..16d36574eb
--- /dev/null
+++ b/package/base-files/files/sbin/urandom_seed
@@ -0,0 +1,20 @@
+#!/bin/sh
+set -e
+
+trap '[ "$?" -eq 0 ] || echo "An error occured" >&2' EXIT
+
+save() {
+    touch "$1.tmp"
+    chown root:root "$1.tmp"
+    chmod 600 "$1.tmp"
+    getrandom 512 > "$1.tmp"
+    mv "$1.tmp" "$1"
+    echo "Seed saved ($1)"
+}
+
+SEED="$(uci -q get system.@system[0].urandom_seed || true)"
+[ "${SEED:0:1}" == "/" ] && save "$SEED"
+
+SEED=/etc/urandom.seed
+[ ! -f $SEED ] && save "$SEED"
+true
diff --git a/package/base-files/files/sbin/wifi b/package/base-files/files/sbin/wifi
new file mode 100755
index 0000000000..f2845c82f6
--- /dev/null
+++ b/package/base-files/files/sbin/wifi
@@ -0,0 +1,239 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+usage() {
+	cat <<EOF
+Usage: $0 [down|detect|reload|status]
+enables (default), disables or detects a wifi configuration.
+EOF
+	exit 1
+}
+
+ubus_wifi_cmd() {
+	local cmd="$1"
+	local dev="$2"
+
+	json_init
+	[ -n "$2" ] && json_add_string device "$2"
+	ubus call network.wireless "$1" "$(json_dump)"
+}
+
+find_net_config() {(
+	local vif="$1"
+	local cfg
+	local ifname
+
+	config_get cfg "$vif" network
+
+	[ -z "$cfg" ] && {
+		include /lib/network
+		scan_interfaces
+
+		config_get ifname "$vif" ifname
+
+		cfg="$(find_config "$ifname")"
+	}
+	[ -z "$cfg" ] && return 0
+	echo "$cfg"
+)}
+
+
+bridge_interface() {(
+	local cfg="$1"
+	[ -z "$cfg" ] && return 0
+
+	include /lib/network
+	scan_interfaces
+
+	for cfg in $cfg; do
+		config_get iftype "$cfg" type
+		[ "$iftype" = bridge ] && config_get "$cfg" ifname
+		prepare_interface_bridge "$cfg"
+		return $?
+	done
+)}
+
+prepare_key_wep() {
+	local key="$1"
+	local hex=1
+
+	echo -n "$key" | grep -qE "[^a-fA-F0-9]" && hex=0
+	[ "${#key}" -eq 10 -a $hex -eq 1 ] || \
+	[ "${#key}" -eq 26 -a $hex -eq 1 ] || {
+		[ "${key:0:2}" = "s:" ] && key="${key#s:}"
+		key="$(echo -n "$key" | hexdump -ve '1/1 "%02x" ""')"
+	}
+	echo "$key"
+}
+
+wifi_fixup_hwmode() {
+	local device="$1"
+	local default="$2"
+	local hwmode hwmode_11n
+
+	config_get channel "$device" channel
+	config_get hwmode "$device" hwmode
+	case "$hwmode" in
+		11bg) hwmode=bg;;
+		11a) hwmode=a;;
+		11b) hwmode=b;;
+		11g) hwmode=g;;
+		11n*)
+			hwmode_11n="${hwmode##11n}"
+			case "$hwmode_11n" in
+				a|g) ;;
+				default) hwmode_11n="$default"
+			esac
+			config_set "$device" hwmode_11n "$hwmode_11n"
+		;;
+		*)
+			hwmode=
+			if [ "${channel:-0}" -gt 0 ]; then
+				if [ "${channel:-0}" -gt 14 ]; then
+					hwmode=a
+				else
+					hwmode=g
+				fi
+			else
+				hwmode="$default"
+			fi
+		;;
+	esac
+	config_set "$device" hwmode "$hwmode"
+}
+
+_wifi_updown() {
+	for device in ${2:-$DEVICES}; do (
+		config_get disabled "$device" disabled
+		[ "$disabled" = "1" ] && {
+			echo "'$device' is disabled"
+			set disable
+		}
+		config_get iftype "$device" type
+		if eval "type ${1}_$iftype" 2>/dev/null >/dev/null; then
+			eval "scan_$iftype '$device'"
+			eval "${1}_$iftype '$device'" || echo "$device($iftype): ${1} failed"
+		elif [ ! -f /lib/netifd/wireless/$iftype.sh ]; then
+			echo "$device($iftype): Interface type not supported"
+		fi
+	); done
+}
+
+wifi_updown() {
+	cmd=down
+	[ enable = "$1" ] && {
+		_wifi_updown disable "$2"
+		ubus_wifi_cmd "$cmd" "$2"
+		scan_wifi
+		cmd=up
+	}
+	ubus_wifi_cmd "$cmd" "$2"
+	_wifi_updown "$@"
+}
+
+wifi_reload_legacy() {
+	_wifi_updown "disable" "$1"
+	scan_wifi
+	_wifi_updown "enable" "$1"
+}
+
+wifi_reload() {
+	ubus call network reload
+	wifi_reload_legacy
+}
+
+wifi_config() {
+	[ ! -f /etc/config/wireless ] && touch /etc/config/wireless
+
+	for driver in $DRIVERS; do (
+		if eval "type detect_$driver" 2>/dev/null >/dev/null; then
+			eval "detect_$driver" || echo "$driver: Detect failed" >&2
+		else
+			echo "$driver: Hardware detection not supported" >&2
+		fi
+	); done
+}
+
+start_net() {(
+	local iface="$1"
+	local config="$2"
+	local vifmac="$3"
+
+	[ -f "/var/run/$iface.pid" ] && kill "$(cat /var/run/${iface}.pid)" 2>/dev/null
+	[ -z "$config" ] || {
+		include /lib/network
+		scan_interfaces
+		for config in $config; do
+			setup_interface "$iface" "$config" "" "$vifmac"
+		done
+	}
+)}
+
+set_wifi_up() {
+	local cfg="$1"
+	local ifname="$2"
+	uci_set_state wireless "$cfg" up 1
+	uci_set_state wireless "$cfg" ifname "$ifname"
+}
+
+set_wifi_down() {
+	local cfg="$1"
+	local vifs vif vifstr
+
+	[ -f "/var/run/wifi-${cfg}.pid" ] &&
+		kill "$(cat "/var/run/wifi-${cfg}.pid")" 2>/dev/null
+	uci_revert_state wireless "$cfg"
+	config_get vifs "$cfg" vifs
+	for vif in $vifs; do
+		uci_revert_state wireless "$vif"
+	done
+}
+
+scan_wifi() {
+	local cfgfile="$1"
+	DEVICES=
+	config_cb() {
+		local type="$1"
+		local section="$2"
+
+		# section start
+		case "$type" in
+			wifi-device)
+				append DEVICES "$section"
+				config_set "$section" vifs ""
+				config_set "$section" ht_capab ""
+			;;
+		esac
+
+		# section end
+		config_get TYPE "$CONFIG_SECTION" TYPE
+		case "$TYPE" in
+			wifi-iface)
+				config_get device "$CONFIG_SECTION" device
+				config_get vifs "$device" vifs
+				append vifs "$CONFIG_SECTION"
+				config_set "$device" vifs "$vifs"
+			;;
+		esac
+	}
+	config_load "${cfgfile:-wireless}"
+}
+
+DEVICES=
+DRIVERS=
+include /lib/wifi
+scan_wifi
+
+case "$1" in
+	down) wifi_updown "disable" "$2";;
+	detect) ;;
+	config) wifi_config ;;
+	status) ubus_wifi_cmd "status" "$2";;
+	reload) wifi_reload "$2";;
+	reload_legacy) wifi_reload_legacy "$2";;
+	--help|help) usage;;
+	*) ubus call network reload; wifi_updown "enable" "$2";;
+esac
diff --git a/package/base-files/files/usr/lib/os-release b/package/base-files/files/usr/lib/os-release
new file mode 100644
index 0000000000..79b08d16cf
--- /dev/null
+++ b/package/base-files/files/usr/lib/os-release
@@ -0,0 +1,17 @@
+NAME="%D"
+VERSION="%V, %N"
+ID="%d"
+ID_LIKE="lede openwrt"
+PRETTY_NAME="%D %N %V"
+VERSION_ID="%v"
+HOME_URL="%m"
+BUG_URL="%b"
+SUPPORT_URL="%s"
+BUILD_ID="%R"
+LEDE_BOARD="%S"
+LEDE_TAINTS="%t"
+LEDE_DEVICE_MANUFACTURER="%M"
+LEDE_DEVICE_MANUFACTURER_URL="%m"
+LEDE_DEVICE_PRODUCT="%P"
+LEDE_DEVICE_REVISION="%h"
+LEDE_RELEASE="%D %N %V %C"
diff --git a/package/base-files/files/usr/libexec/login.sh b/package/base-files/files/usr/libexec/login.sh
new file mode 100755
index 0000000000..02ac9c828b
--- /dev/null
+++ b/package/base-files/files/usr/libexec/login.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "$(uci get system.@system[0].ttylogin)" == 1 ] || exec /bin/ash --login
+
+exec /bin/login
diff --git a/package/base-files/image-config.in b/package/base-files/image-config.in
new file mode 100644
index 0000000000..5a7b068fe0
--- /dev/null
+++ b/package/base-files/image-config.in
@@ -0,0 +1,324 @@
+# Copyright (C) 2006-2012 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+menuconfig PREINITOPT
+	bool "Preinit configuration options" if IMAGEOPT
+	default n
+	help
+		These options are used to control the environment used to initialize
+		the system before running init (which typically mean /sbin/init which
+		switches to multiuser mode).
+
+config TARGET_PREINIT_SUPPRESS_STDERR
+	bool "Suppress stderr messages during preinit" if PREINITOPT
+	default y
+	help
+		Sends stderr to null during preinit.  This is the default behaviour
+		in previous versions of OpenWrt.  This also prevents init process
+		itself from displaying stderr, however processes launched by init
+		in multiuser through inittab will use the current terminal (e.g.
+		the ash shell launched by inittab will display stderr).  That's
+		the same behaviour as seen in previous version of OpenWrt.
+
+config TARGET_PREINIT_DISABLE_FAILSAFE
+	bool
+	prompt "Disable failsafe" if PREINITOPT
+	default n
+	help
+		Disable failsafe mode.  While it is very handy while
+		experimenting or developing it really ought to be
+		disabled in production environments as it is a major
+		security loophole.
+
+config TARGET_PREINIT_TIMEOUT
+	int
+	prompt "Failsafe/Debug wait timeout" if PREINITOPT
+	default 2
+	help
+		How long to wait for failsafe mode to be entered or for
+		a debug option to be pressed before continuing with a
+		regular boot.
+
+config TARGET_PREINIT_SHOW_NETMSG
+	bool
+	prompt "Show all preinit network messages" if PREINITOPT
+	default n
+	help
+		Show preinit all network messages (via netmsg broadcast), not only
+		the message indicating to press reset to enter failsafe.  Note that
+		if the architecture doesn't define an interface, and there is no
+		'Preinit network interface' defined, then no messages will be
+		emitted, even if this is set.
+
+config TARGET_PREINIT_SUPPRESS_FAILSAFE_NETMSG
+	bool
+	prompt "Suppress network message indicating failsafe" if ( PREINITOPT && !TARGET_PREINIT_SHOW_NETMSG && !TARGET_PREINIT_DISABLE_FAILSAFE )
+	default n
+	help
+		If "Show all preinit network messages" above is not set, then
+		setting this option suppresses the only message that would be
+		emitted otherwise, name the network message to enter failsafe
+		(via netmsg).
+
+config TARGET_PREINIT_IFNAME
+	string
+	prompt "Preinit network interface" if PREINITOPT
+	default ""
+	help
+		Interface for sending preinit messages to network, and any other
+		default networking in failsafe or preinit.  If empty
+		uses $ifname (if defined in /etc/preinit.arch).
+
+config TARGET_PREINIT_IP
+	string
+	prompt "IP address for preinit network messages" if PREINITOPT
+	default "192.168.10.1"
+	help
+		IP address used to configure interface for preinit network
+		messages, including failsafe messages
+
+config TARGET_PREINIT_NETMASK
+	string
+	prompt "Netmask for preinit network messages" if PREINITOPT
+	default "255.255.255.0"
+	help
+		Netmask used to configure interface for preinit network
+		messages, including failsafes messages
+
+config TARGET_PREINIT_BROADCAST
+	string
+	prompt "Broadcast address for preinit network messages" if PREINITOPT
+	default "192.168.10.255"
+	help
+		Broadcast address to which to send preinit network messages, as
+		as failsafe messages
+
+
+menuconfig INITOPT
+	bool "Init configuration options" if IMAGEOPT
+	default n
+	help
+		These option choose the command that will run as the 'init' command
+		(that is which is responsible for controlling the system once preinit
+		transfers control to it) as well as some options controlling its
+		behaviour.  Normally init is /sbin/init.
+
+	config TARGET_INIT_PATH
+		string
+		prompt "PATH for regular boot" if INITOPT
+		default "/usr/sbin:/usr/bin:/sbin:/bin"
+		help
+			Default PATH used during normal operation
+
+	config TARGET_INIT_ENV
+		string
+		prompt "Environment variables to set when starting init (start with none)" if INITOPT
+		default ""
+		help
+			Should be a space seperated list of variable assignments.  These
+			variables will be present in the environment.  Spaces may not be
+			present (including through expansion) even in a quoted string
+			(env doesn't understanding quoting).
+
+	config TARGET_INIT_CMD
+		string
+		prompt "Init command" if INITOPT
+		default "/sbin/init"
+		help
+			The executable to run as the init process.  Is 'exec'd by
+			preinit (which is the init that the kernel launches on boot).
+
+	config TARGET_INIT_SUPPRESS_STDERR
+		bool
+		prompt "Suppress stderr messages of init" if INITOPT
+		default y
+		help
+			Prevents showing stderr messages for init command if not already
+			suppressed during preinit.  This is the default behaviour in
+			previous versions of OpenWrt.  Removing this does nothing if
+			stderr is suppressed during preinit (which is the default).
+
+
+menuconfig VERSIONOPT
+	bool "Version configuration options" if IMAGEOPT
+	default n
+	help
+		These options allow to override the version information embedded in
+		the /etc/openwrt_version, /etc/openwrt_release, /etc/banner,
+		/etc/opkg.conf, and /etc/os-release files. Usually there is no need
+		to set these, but they're useful for release builds or custom OpenWrt
+		redistributions that should carry custom version tags.
+
+if VERSIONOPT
+
+	config VERSION_DIST
+		string
+		prompt "Release distribution"
+		default "Lede"
+		help
+			This is the name of the release distribution.
+			If unspecified, it defaults to OpenWrt.
+
+	config VERSION_NICK
+		string
+		prompt "Release version nickname"
+		help
+			This is the release codename embedded in the image.
+			If unspecified, it defaults to the name of source branch.
+
+	config VERSION_NUMBER
+		string
+		prompt "Release version number"
+		help
+			This is the release version number embedded in the image.
+			If unspecified, it defaults to CURRENT for the master branch
+			or to ##.##-CURRENT on release branches.
+
+	config VERSION_CODE
+		string
+		prompt "Release version code"
+		help
+			This is the release version code embedded in the image.
+			If unspecified, it defaults to a revision number describing the
+			repository version of the source, e.g. the number of commits
+			since a branch point or a short Git commit ID.
+
+	config VERSION_REPO
+		string
+		prompt "Release repository"
+		default "http://downloads.lede-project.org/snapshots"
+		help
+			This is the repository address embedded in the image, it defaults
+			to the trunk snapshot repo; the url may contain the following placeholders:
+			 %R .. Repository revision ID
+			 %V .. Configured release version number or "CURRENT", uppercase
+			 %v .. Configured release version number or "current", lowercase
+			 %C .. Configured release revision code or value of %R, uppercase
+			 %c .. Configured release revision code or value of %R, lowercase
+			 %N .. Release name, uppercase
+			 %n .. Release name, lowercase
+			 %D .. Distribution name or "Lede", uppercase
+			 %d .. Distribution name or "lede", lowercase
+			 %T .. Target name
+			 %S .. Target/Subtarget name
+			 %A .. Package architecture
+			 %t .. Build taint flags, e.g. "no-all busybox"
+			 %M .. Manufacturer name or "Lede"
+			 %P .. Product name or "Generic"
+			 %h .. Hardware revision or "v0"
+
+	config VERSION_MANUFACTURER
+		string
+		prompt "Manufacturer name"
+		help
+			This is the manufacturer name embedded in /etc/device_info
+			Useful for OEMs building OpenWrt based firmware
+
+	config VERSION_MANUFACTURER_URL
+		string
+		prompt "Manufacturer URL"
+		help
+			This is an URL to the manufacturer's website embedded in /etc/device_info
+			Useful for OEMs building OpenWrt based firmware
+
+	config VERSION_BUG_URL
+		string
+		prompt "Bug reporting URL"
+		help
+			This is an URL to provide users for providing bug reports
+
+	config VERSION_SUPPORT_URL
+		string
+		prompt "Support URL"
+		help
+			This an URL to provide users seeking support
+
+	config VERSION_PRODUCT
+		string
+		prompt "Product name"
+		help
+			This is the product name embedded in /etc/device_info
+			Useful for OEMs building OpenWrt based firmware
+
+	config VERSION_HWREV
+		string
+		prompt "Hardware revision"
+		help
+			This is the hardware revision string embedded in /etc/device_info
+			Useful for OEMs building OpenWrt based firmware
+
+	config VERSION_FILENAMES
+		bool
+		prompt "Version number in filenames"
+		default y
+		help
+			Enable this to include the version number in firmware image, SDK-
+			and Image Builder archive file names
+endif
+
+
+menuconfig PER_FEED_REPO
+	bool "Separate feed repositories" if IMAGEOPT
+	default y
+	help
+		If set, a separate repository is generated within bin/*/packages/
+		for the core packages and each enabled feed.
+
+	config PER_FEED_REPO_ADD_DISABLED
+		bool "Add available but not enabled feeds to opkg.conf"
+		default y
+		depends on PER_FEED_REPO
+		help
+		  Add not installed or disabled feeds from feeds.conf to opkg.conf.
+
+	config PER_FEED_REPO_ADD_COMMENTED
+		bool "Comment out not enabled feeds"
+		default y
+		depends on PER_FEED_REPO && PER_FEED_REPO_ADD_DISABLED
+		help
+		  Add not enabled feeds as commented out source lines to opkg.conf.
+
+source "tmp/.config-feeds.in"
+
+
+menuconfig SMIMEOPT
+	bool "Package signing options" if IMAGEOPT
+        default n
+	help
+		These options configure the signing key and certificate to
+		be used for signing and verifying packages.
+
+	config OPKGSMIME_CERT
+		string
+		prompt "Path to certificate (PEM certificate format)" if SMIMEOPT
+		help
+		  Path to the certificate to use for signature verification
+
+	config OPKGSMIME_KEY
+		string
+		prompt "Path to signing key (PEM private key format)" if SMIMEOPT
+		help
+		  Path to the key to use for signing packages
+
+	config OPKGSMIME_PASSPHRASE
+		bool
+		default y
+		prompt "Wait for a passphrase when signing packages?" if SMIMEOPT
+		help
+		  If this value is set, then the build will pause and request a passphrase
+                  from the command line when signing packages. This SHOULD NOT be used with
+                  automatic builds. If this value is not set, a file can be specified from
+                  which the passphrase will be read.
+
+	config OPKGSMIME_PASSFILE
+		string
+		prompt "Path to a file containing the passphrase" if SMIMEOPT
+                depends on !OPKGSMIME_PASSPHRASE
+		help
+		  Path to a file containing the passphrase for the signing key.
+                  If the signing key is not encrypted and does not require a passphrase,
+                  this option may be left blank.
diff --git a/package/boot/fconfig/Makefile b/package/boot/fconfig/Makefile
new file mode 100644
index 0000000000..077c6e4889
--- /dev/null
+++ b/package/boot/fconfig/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fconfig
+PKG_VERSION:=20080329
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://andrzejekiert.ovh.org/software/fconfig/
+PKG_MD5SUM:=dac355e9f2a0f48c414c52e2034b6346
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/fconfig
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Boot Loaders
+  TITLE:=RedBoot configuration editor
+  URL:=http://andrzejekiert.ovh.org/software.html.en
+endef
+
+define Package/fconfig/description
+	displays and (if writable) also edits the RedBoot configuration.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(call Build/Compile/Default)
+endef
+
+define Package/fconfig/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/fconfig $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,fconfig))
diff --git a/package/boot/grub2/Makefile b/package/boot/grub2/Makefile
new file mode 100644
index 0000000000..02e6637c32
--- /dev/null
+++ b/package/boot/grub2/Makefile
@@ -0,0 +1,84 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=grub
+PKG_VERSION:=2.02~beta2
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://alpha.gnu.org/gnu/grub \
+	http://gnualpha.uib.no/grub/ \
+	http://mirrors.fe.up.pt/pub/gnu-alpha/grub/ \
+	http://www.nic.funet.fi/pub/gnu/alpha/gnu/grub/
+PKG_MD5SUM:=be62932eade308a364ea4bbc91295930
+
+HOST_BUILD_PARALLEL:=1
+PKG_BUILD_DEPENDS:=grub2/host
+
+PKG_SSP:=0
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/grub2
+  CATEGORY:=Boot Loaders
+  SECTION:=boot
+  TITLE:=GRand Unified Bootloader
+  URL:=http://www.gnu.org/software/grub/
+  DEPENDS:=@TARGET_x86||TARGET_x86_64
+endef
+
+define Package/grub2-editenv
+  CATEGORY:=Utilities
+  SECTION:=utils
+  SUBMENU:=Boot Loaders
+  TITLE:=Grub2 Environment editor
+  URL:=http://www.gnu.org/software/grub/
+  DEPENDS:=@TARGET_x86||TARGET_x86_64
+endef
+
+define Package/grub2-editenv/description
+	Edit grub2 environment files.
+endef
+
+HOST_BUILD_PREFIX := $(STAGING_DIR_HOST)
+
+CONFIGURE_ARGS += \
+	--target=$(REAL_GNU_TARGET_NAME) \
+	--disable-werror \
+	--disable-nls \
+	--disable-device-mapper \
+	--disable-libzfs \
+	--disable-grub-mkfont
+
+HOST_CONFIGURE_ARGS += \
+	--target=$(REAL_GNU_TARGET_NAME) \
+	--sbindir="$(STAGING_DIR_HOST)/bin" \
+	--disable-werror \
+	--disable-libzfs \
+	--disable-nls
+
+HOST_MAKE_FLAGS += \
+	TARGET_RANLIB=$(TARGET_RANLIB) \
+	LIBLZMA=$(STAGING_DIR_HOST)/lib/liblzma.a
+
+define Host/Configure
+	$(SED) 's,(RANLIB),(TARGET_RANLIB),' $(HOST_BUILD_DIR)/grub-core/Makefile.in
+	$(Host/Configure/Default)
+endef
+
+define Package/grub2-editenv/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/grub-editenv $(1)/usr/sbin/
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,grub2))
+$(eval $(call BuildPackage,grub2-editenv))
diff --git a/package/boot/grub2/patches/100-grub_setup_root.patch b/package/boot/grub2/patches/100-grub_setup_root.patch
new file mode 100644
index 0000000000..9619c410b8
--- /dev/null
+++ b/package/boot/grub2/patches/100-grub_setup_root.patch
@@ -0,0 +1,118 @@
+--- a/util/grub-setup.c
++++ b/util/grub-setup.c
+@@ -87,6 +87,8 @@ static struct argp_option options[] = {
+    N_("install even if problems are detected"), 0},
+   {"skip-fs-probe",'s',0,      0,
+    N_("do not probe for filesystems in DEVICE"), 0},
++  {"root-device", 'r', N_("DEVICE"), 0,
++   N_("use DEVICE as the root device"), 0},
+   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
+   {"allow-floppy", 'a', 0,      0,
+    /* TRANSLATORS: The potential breakage isn't limited to floppies but it's
+@@ -130,6 +132,7 @@ struct arguments
+   char *core_file;
+   char *dir;
+   char *dev_map;
++  char *root_dev;
+   int  force;
+   int  fs_probe;
+   int allow_floppy;
+@@ -178,6 +181,13 @@ argp_parser (int key, char *arg, struct 
+         arguments->dev_map = xstrdup (arg);
+         break;
+ 
++      case 'r':
++        if (arguments->root_dev)
++          free (arguments->root_dev);
++
++        arguments->root_dev = xstrdup (arg);
++        break;
++
+       case 'f':
+         arguments->force = 1;
+         break;
+@@ -313,7 +323,7 @@ main (int argc, char *argv[])
+   GRUB_SETUP_FUNC (arguments.dir ? : DEFAULT_DIRECTORY,
+ 		   arguments.boot_file ? : DEFAULT_BOOT_FILE,
+ 		   arguments.core_file ? : DEFAULT_CORE_FILE,
+-		   dest_dev, arguments.force,
++		   arguments.root_dev, dest_dev, arguments.force,
+ 		   arguments.fs_probe, arguments.allow_floppy,
+ 		   arguments.add_rs_codes);
+ 
+--- a/util/setup.c
++++ b/util/setup.c
+@@ -247,13 +247,12 @@ identify_partmap (grub_disk_t disk __att
+ void
+ SETUP (const char *dir,
+        const char *boot_file, const char *core_file,
+-       const char *dest, int force,
++       const char *root, const char *dest, int force,
+        int fs_probe, int allow_floppy,
+        int add_rs_codes __attribute__ ((unused))) /* unused on sparc64 */
+ {
+   char *core_path;
+   char *boot_img, *core_img, *boot_path;
+-  char *root = 0;
+   size_t boot_size, core_size;
+ #ifdef GRUB_SETUP_BIOS
+   grub_uint16_t core_sectors;
+@@ -307,7 +306,10 @@ SETUP (const char *dir,
+ 
+   core_dev = dest_dev;
+ 
+-  {
++  if (root)
++    root_dev = grub_device_open(root);
++
++  if (!root_dev) {
+     char **root_devices = grub_guess_root_devices (dir);
+     char **cur;
+     int found = 0;
+@@ -317,6 +319,8 @@ SETUP (const char *dir,
+ 	char *drive;
+ 	grub_device_t try_dev;
+ 
++	if (root_dev)
++	  break;
+ 	drive = grub_util_get_grub_dev (*cur);
+ 	if (!drive)
+ 	  continue;
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -182,13 +182,13 @@ grub_install_get_image_target (const cha
+ void
+ grub_util_bios_setup (const char *dir,
+ 		      const char *boot_file, const char *core_file,
+-		      const char *dest, int force,
++		      const char *root, const char *dest, int force,
+ 		      int fs_probe, int allow_floppy,
+ 		      int add_rs_codes);
+ void
+ grub_util_sparc_setup (const char *dir,
+ 		       const char *boot_file, const char *core_file,
+-		       const char *dest, int force,
++		       const char *root, const char *dest, int force,
+ 		       int fs_probe, int allow_floppy,
+ 		       int add_rs_codes);
+ 
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1660,7 +1660,7 @@ main (int argc, char *argv[])
+ 	/*  Now perform the installation.  */
+ 	if (install_bootsector)
+ 	  grub_util_bios_setup (platdir, "boot.img", "core.img",
+-				install_drive, force,
++				NULL, install_drive, force,
+ 				fs_probe, allow_floppy, add_rs_codes);
+ 	break;
+       }
+@@ -1686,7 +1686,7 @@ main (int argc, char *argv[])
+ 	/*  Now perform the installation.  */
+ 	if (install_bootsector)
+ 	  grub_util_sparc_setup (platdir, "boot.img", "core.img",
+-				 install_device, force,
++				 NULL, install_device, force,
+ 				 fs_probe, allow_floppy,
+ 				 0 /* unused */ );
+ 	break;
diff --git a/package/boot/grub2/patches/100-musl-compat.patch b/package/boot/grub2/patches/100-musl-compat.patch
new file mode 100644
index 0000000000..e3b12be58a
--- /dev/null
+++ b/package/boot/grub2/patches/100-musl-compat.patch
@@ -0,0 +1,26 @@
+--- a/grub-core/osdep/unix/hostdisk.c
++++ b/grub-core/osdep/unix/hostdisk.c
+@@ -48,11 +48,10 @@
+ #ifdef __linux__
+ # include <sys/ioctl.h>         /* ioctl */
+ # include <sys/mount.h>
+-# if !defined(__GLIBC__) || \
+-        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
++# if defined(__UCLIBC__)
+ /* Maybe libc doesn't have large file support.  */
+ #  include <linux/unistd.h>     /* _llseek */
+-# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
++# endif /* __UCLIBC__ */
+ #endif /* __linux__ */
+ 
+ grub_uint64_t
+@@ -79,8 +78,7 @@ grub_util_get_fd_size (grub_util_fd_t fd
+   return st.st_size;
+ }
+ 
+-#if defined(__linux__) && (!defined(__GLIBC__) || \
+-        ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
++#if defined(__linux__) && defined(__UCLIBC__)
+   /* Maybe libc doesn't have large file support.  */
+ int
+ grub_util_fd_seek (grub_util_fd_t fd, grub_uint64_t off)
diff --git a/package/boot/grub2/patches/200-fix-gets-removal.patch b/package/boot/grub2/patches/200-fix-gets-removal.patch
new file mode 100644
index 0000000000..737fb975bf
--- /dev/null
+++ b/package/boot/grub2/patches/200-fix-gets-removal.patch
@@ -0,0 +1,16 @@
+--- a/grub-core/gnulib/stdio.in.h
++++ b/grub-core/gnulib/stdio.in.h
+@@ -695,13 +695,6 @@ _GL_WARN_ON_USE (getline, "getline is un
+ # endif
+ #endif
+ 
+-/* It is very rare that the developer ever has full control of stdin,
+-   so any use of gets warrants an unconditional warning; besides, C11
+-   removed it.  */
+-#undef gets
+-#if HAVE_RAW_DECL_GETS
+-#endif
+-
+ 
+ #if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
+ struct obstack;
diff --git a/package/boot/grub2/patches/210-fix_serial_rtscts.patch b/package/boot/grub2/patches/210-fix_serial_rtscts.patch
new file mode 100644
index 0000000000..d60471c1d1
--- /dev/null
+++ b/package/boot/grub2/patches/210-fix_serial_rtscts.patch
@@ -0,0 +1,14 @@
+--- a/grub-core/term/serial.c
++++ b/grub-core/term/serial.c
+@@ -241,9 +241,9 @@ grub_cmd_serial (grub_extcmd_context_t c
+ 
+   if (state[OPTION_RTSCTS].set)
+     {
+-      if (grub_strcmp (state[OPTION_PARITY].arg, "on") == 0)
++      if (grub_strcmp (state[OPTION_RTSCTS].arg, "on") == 0)
+ 	config.rtscts = 1;
+-      if (grub_strcmp (state[OPTION_PARITY].arg, "off") == 0)
++      else if (grub_strcmp (state[OPTION_RTSCTS].arg, "off") == 0)
+ 	config.rtscts = 0;
+       else
+ 	return grub_error (GRUB_ERR_BAD_ARGUMENT,
diff --git a/package/boot/kexec-tools/Config.in b/package/boot/kexec-tools/Config.in
new file mode 100644
index 0000000000..6c7558f30a
--- /dev/null
+++ b/package/boot/kexec-tools/Config.in
@@ -0,0 +1,31 @@
+menu "Configuration"
+	depends on PACKAGE_kexec-tools
+
+config KEXEC_TOOLS_TARGET_NAME
+	string
+	prompt "Target name for kexec kernel"
+	default EXTRA_TARGET_ARCH_NAME	if powerpc64
+	default ARCH
+	help
+	  Defines the target type of the kernels that kexec deals
+	  with. This should be the target specification of
+	  the kernel you're booting.
+
+config KEXEC_TOOLS_kdump
+	bool
+	prompt "kdump support"
+	default n
+	help
+	  Include the kdump utility.
+
+config KEXEC_ZLIB
+	bool
+	prompt "zlib support"
+	default y
+
+config KEXEC_LZMA
+	bool
+	prompt "lzma support"
+	default n
+
+endmenu
diff --git a/package/boot/kexec-tools/Makefile b/package/boot/kexec-tools/Makefile
new file mode 100644
index 0000000000..6f04bce7be
--- /dev/null
+++ b/package/boot/kexec-tools/Makefile
@@ -0,0 +1,87 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=kexec-tools
+PKG_VERSION:=2.0.9
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/linux/utils/kernel/kexec
+PKG_MD5SUM:=6681319934e22e74c532bd392ccb1bbb
+
+PKG_FIXUP:=autoreconf
+
+PKG_CONFIG_DEPENDS := CONFIG_KEXEC_ZLIB CONFIG_KEXEC_LZMA
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/kexec-tools
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=@KERNEL_KEXEC @armeb||@arm||@i386||@powerpc64||@mipsel||@mips +KEXEC_ZLIB:zlib +KEXEC_LZMA:liblzma
+  TITLE:=Kernel boots kernel
+  URL:=http://kernel.org/pub/linux/kernel/people/horms/kexec-tools/
+  MAINTAINER:=Florian Fainelli <florian@openwrt.org>
+  MENU:=1
+endef
+
+define Package/kexec-tools/description
+ kexec is a set of systems call that allows you to load
+ another kernel from the currently executing Linux kernel.
+endef
+
+define Package/kexec-tools/config
+	source "$(SOURCE)/Config.in"
+endef
+
+KEXEC_TARGET_NAME:=$(call qstrip,$(CONFIG_KEXEC_TOOLS_TARGET_NAME))-linux-$(TARGET_SUFFIX)
+
+CONFIGURE_ARGS = \
+		--target=$(KEXEC_TARGET_NAME) \
+		--host=$(REAL_GNU_TARGET_NAME) \
+		--build=$(GNU_HOST_NAME) \
+		--program-prefix="" \
+		--program-suffix="" \
+		--prefix=/usr \
+		--exec-prefix=/usr \
+		--bindir=/usr/bin \
+		--sbindir=/usr/sbin \
+		--libexecdir=/usr/lib \
+		--sysconfdir=/etc \
+		$(if $(CONFIG_KEXEC_ZLIB),--with,--without)-zlib \
+		$(if $(CONFIG_KEXEC_LZMA),--with,--without)-lzma
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+CONFIGURE_VARS += \
+	BUILD_CC="$(HOSTCC)" \
+	TARGET_CC="$(TARGET_CC)"
+
+kexec-extra-sbin-$(CONFIG_KEXEC_TOOLS_kdump) += kdump
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) DESTDIR="$(PKG_INSTALL_DIR)" all install
+endef
+
+define Package/kexec-tools/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) \
+		$(addprefix $(PKG_INSTALL_DIR)/usr/sbin/, \
+			$(kexec-extra-sbin-y)) \
+		$(kexec-extra-bin-y) \
+		$(PKG_INSTALL_DIR)/usr/sbin/kexec \
+		$(1)/usr/sbin
+
+# make a link for compatability with other distros
+	$(INSTALL_DIR) $(1)/sbin
+	$(LN) ../usr/sbin/kexec $(1)/sbin/kexec
+endef
+
+$(eval $(call BuildPackage,kexec-tools))
diff --git a/package/boot/kexec-tools/patches/0001-Fix-zlib-lzma-decompression.patch b/package/boot/kexec-tools/patches/0001-Fix-zlib-lzma-decompression.patch
new file mode 100644
index 0000000000..06c11ec350
--- /dev/null
+++ b/package/boot/kexec-tools/patches/0001-Fix-zlib-lzma-decompression.patch
@@ -0,0 +1,171 @@
+From d606837b56d46eb7f815b5d85f07fcc3f1555d00 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Sun, 1 Feb 2015 00:10:07 +0800
+Subject: [PATCH 1/5] Fix zlib/lzma decompression.
+
+Let {zlib,lzma}_decompress_file() return NULL if anything wrong happened
+to allow the other method to have a chance to run.
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+Signed-off-by: Simon Horman <horms@verge.net.au>
+---
+ kexec/lzma.c |   33 ++++++++++++++++++++++-----------
+ kexec/zlib.c |   57 +++++++++++++++++++++++++++++++++++----------------------
+ 2 files changed, 57 insertions(+), 33 deletions(-)
+
+diff --git a/kexec/lzma.c b/kexec/lzma.c
+index 939aeb3..5bfccb7 100644
+--- a/kexec/lzma.c
++++ b/kexec/lzma.c
+@@ -162,13 +162,16 @@ char *lzma_decompress_file(const char *filename, off_t *r_size)
+ 	off_t size, allocated;
+ 	ssize_t result;
+ 
+-	if (!filename) {
+-		*r_size = 0;
+-		return 0;
+-	}
++	dbgprintf("Try LZMA decompression.\n");
++
++	*r_size = 0;
++	if (!filename)
++		return NULL;
++
+ 	fp = lzopen(filename, "rb");
+ 	if (fp == 0) {
+-		die("Cannot open `%s'\n", filename);
++		dbgprintf("Cannot open `%s'\n", filename);
++		return NULL;
+ 	}
+ 	size = 0;
+ 	allocated = 65536;
+@@ -183,17 +186,25 @@ char *lzma_decompress_file(const char *filename, off_t *r_size)
+ 			if ((errno == EINTR) || (errno == EAGAIN))
+ 				continue;
+ 
+-			die ("read on %s of %ld bytes failed\n",
+-				filename, (allocated - size) + 0UL);
++			dbgprintf("%s: read on %s of %ld bytes failed\n",
++				__func__, filename, (allocated - size) + 0UL);
++			break;
+ 		}
+ 		size += result;
+-	} while(result > 0);
+-	result = lzclose(fp);
+-	if (result != LZMA_OK) {
+-		die ("Close of %s failed\n", filename);
++	} while (result > 0);
++
++	if (lzclose(fp) != LZMA_OK) {
++		dbgprintf("%s: Close of %s failed\n", __func__, filename);
++		goto fail;
+ 	}
++	if (result < 0)
++		goto fail;
++
+ 	*r_size =  size;
+ 	return buf;
++fail:
++	free(buf);
++	return NULL;
+ }
+ #else
+ char *lzma_decompress_file(const char *UNUSED(filename), off_t *UNUSED(r_size))
+diff --git a/kexec/zlib.c b/kexec/zlib.c
+index d44df12..7170ac3 100644
+--- a/kexec/zlib.c
++++ b/kexec/zlib.c
+@@ -15,29 +15,39 @@
+ #include <ctype.h>
+ #include <zlib.h>
+ 
++static void _gzerror(gzFile fp, int *errnum, const char **errmsg)
++{
++	*errmsg = gzerror(fp, errnum);
++	if (*errnum == Z_ERRNO) {
++		*errmsg = strerror(*errnum);
++	}
++}
++
+ char *zlib_decompress_file(const char *filename, off_t *r_size)
+ {
+ 	gzFile fp;
+ 	int errnum;
+ 	const char *msg;
+ 	char *buf;
+-	off_t size, allocated;
++	off_t size = 0, allocated;
+ 	ssize_t result;
+ 
++	dbgprintf("Try gzip decompression.\n");
++
++	*r_size = 0;
+ 	if (!filename) {
+-		*r_size = 0;
+-		return 0;
++		return NULL;
+ 	}
+ 	fp = gzopen(filename, "rb");
+ 	if (fp == 0) {
+-		msg = gzerror(fp, &errnum);
+-		if (errnum == Z_ERRNO) {
+-			msg = strerror(errno);
+-		}
+-		fprintf(stderr, "Cannot open `%s': %s\n", filename, msg);
++		_gzerror(fp, &errnum, &msg);
++		dbgprintf("Cannot open `%s': %s\n", filename, msg);
++		return NULL;
++	}
++	if (gzdirect(fp)) {
++		/* It's not in gzip format */
+ 		return NULL;
+ 	}
+-	size = 0;
+ 	allocated = 65536;
+ 	buf = xmalloc(allocated);
+ 	do {
+@@ -49,25 +59,28 @@ char *zlib_decompress_file(const char *filename, off_t *r_size)
+ 		if (result < 0) {
+ 			if ((errno == EINTR) || (errno == EAGAIN))
+ 				continue;
+-
+-			msg = gzerror(fp, &errnum);
+-			if (errnum == Z_ERRNO) {
+-				msg = strerror(errno);
+-			}
+-			die ("read on %s of %ld bytes failed: %s\n",
+-				filename, (allocated - size) + 0UL, msg);
++			_gzerror(fp, &errnum, &msg);
++			dbgprintf("Read on %s of %ld bytes failed: %s\n",
++					filename, (allocated - size) + 0UL, msg);
++			size = 0;
++			goto fail;
+ 		}
+ 		size += result;
+ 	} while(result > 0);
++
++fail:
+ 	result = gzclose(fp);
+ 	if (result != Z_OK) {
+-		msg = gzerror(fp, &errnum);
+-		if (errnum == Z_ERRNO) {
+-			msg = strerror(errno);
+-		}
+-		die ("Close of %s failed: %s\n", filename, msg);
++		_gzerror(fp, &errnum, &msg);
++		dbgprintf(" Close of %s failed: %s\n", filename, msg);
++	}
++
++	if (size > 0) {
++		*r_size = size;
++	} else {
++		free(buf);
++		buf = NULL;
+ 	}
+-	*r_size =  size;
+ 	return buf;
+ }
+ #else
+-- 
+1.7.10.4
+
diff --git a/package/boot/kexec-tools/patches/0002-configure.ac-apply-necessary-quotes-to-result-of-mac.patch b/package/boot/kexec-tools/patches/0002-configure.ac-apply-necessary-quotes-to-result-of-mac.patch
new file mode 100644
index 0000000000..aba8af7412
--- /dev/null
+++ b/package/boot/kexec-tools/patches/0002-configure.ac-apply-necessary-quotes-to-result-of-mac.patch
@@ -0,0 +1,52 @@
+From eb20884c9bbc42bdf1ccace4444f3ce72657d7d8 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Tue, 9 Sep 2014 20:15:16 +0800
+Subject: [PATCH 2/5] configure.ac: apply necessary quotes to result of macro
+ expansion.
+
+This can fix the following error when searching for lzma support and
+while at it also apply the practice to other uses of the same pattern.
+
+	checking for lzma_code in -llzma... ./configure: line 4756: ac_fn_c_try_link: command not found
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ configure.ac |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index db93331..c410e90 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -152,22 +152,22 @@ AC_CHECK_PROG([DIRNAME],  dirname,  dirname,  "no", [$PATH])
+ dnl See if I have a usable copy of zlib available
+ if test "$with_zlib" = yes ; then
+ 	AC_CHECK_HEADER(zlib.h,
+-		AC_CHECK_LIB(z, inflateInit_, ,
+-		AC_MSG_NOTICE([zlib support disabled])))
++		[AC_CHECK_LIB(z, inflateInit_, ,
++		AC_MSG_NOTICE([zlib support disabled]))])
+ fi
+ 
+ dnl See if I have a usable copy of lzma available
+ if test "$with_lzma" = yes ; then
+ 	AC_CHECK_HEADER(lzma.h,
+-		AC_CHECK_LIB(lzma, lzma_code, ,
+-		AC_MSG_NOTICE([lzma support disabled])))
++		[AC_CHECK_LIB(lzma, lzma_code, ,
++		AC_MSG_NOTICE([lzma support disabled]))])
+ fi
+ 
+ dnl find Xen control stack libraries
+ if test "$with_xen" = yes ; then
+ 	AC_CHECK_HEADER(xenctrl.h,
+-		AC_CHECK_LIB(xenctrl, xc_kexec_load, ,
+-		AC_MSG_NOTICE([Xen support disabled])))
++		[AC_CHECK_LIB(xenctrl, xc_kexec_load, ,
++		AC_MSG_NOTICE([Xen support disabled]))])
+ fi
+ 
+ dnl ---Sanity checks
+-- 
+1.7.10.4
+
diff --git a/package/boot/kexec-tools/patches/0003-mips-fix-compiler-warning-on-printing-64-bit-integer.patch b/package/boot/kexec-tools/patches/0003-mips-fix-compiler-warning-on-printing-64-bit-integer.patch
new file mode 100644
index 0000000000..f4762e94c5
--- /dev/null
+++ b/package/boot/kexec-tools/patches/0003-mips-fix-compiler-warning-on-printing-64-bit-integer.patch
@@ -0,0 +1,35 @@
+From 89d455d785190203b1d3a8766c8babb8c1688fc3 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Mon, 9 Feb 2015 19:51:25 +0800
+Subject: [PATCH 3/5] mips: fix compiler warning on printing 64-bit integer.
+
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ kexec/arch/mips/crashdump-mips.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kexec/arch/mips/crashdump-mips.c b/kexec/arch/mips/crashdump-mips.c
+index e7840e0..98c9f7c 100644
+--- a/kexec/arch/mips/crashdump-mips.c
++++ b/kexec/arch/mips/crashdump-mips.c
+@@ -22,6 +22,7 @@
+ #include <stdlib.h>
+ #include <errno.h>
+ #include <limits.h>
++#include <inttypes.h>
+ #include <elf.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+@@ -52,7 +53,7 @@ static int get_kernel_paddr(struct crash_elf_info *elf_info)
+ 
+ 	if (parse_iomem_single("Kernel code\n", &start, NULL) == 0) {
+ 		elf_info->kern_paddr_start = start;
+-		dbgprintf("kernel load physical addr start = 0x%lx\n", start);
++		dbgprintf("kernel load physical addr start = 0x%" PRIu64 "\n", start);
+ 		return 0;
+ 	}
+ 
+-- 
+1.7.10.4
+
diff --git a/package/boot/kexec-tools/patches/0004-mips-remove-unused-variable.patch b/package/boot/kexec-tools/patches/0004-mips-remove-unused-variable.patch
new file mode 100644
index 0000000000..8626c41347
--- /dev/null
+++ b/package/boot/kexec-tools/patches/0004-mips-remove-unused-variable.patch
@@ -0,0 +1,30 @@
+From 904e9ae892b0592c916a013869e3be3d830e0155 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Mon, 9 Feb 2015 20:11:04 +0800
+Subject: [PATCH 4/5] mips: remove unused variable.
+
+Fixes the following compilation warning.
+
+	kexec/arch/mips/crashdump-mips.c:151:6: warning: unused variable 'i' [-Wunused-variable]
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ kexec/arch/mips/crashdump-mips.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kexec/arch/mips/crashdump-mips.c b/kexec/arch/mips/crashdump-mips.c
+index 98c9f7c..dc68cb4 100644
+--- a/kexec/arch/mips/crashdump-mips.c
++++ b/kexec/arch/mips/crashdump-mips.c
+@@ -148,7 +148,7 @@ static int exclude_crash_reserve_region(int *nr_ranges)
+ static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+ {
+ 	const char iomem[] = "/proc/iomem";
+-	int i, memory_ranges = 0;
++	int memory_ranges = 0;
+ 	char line[MAX_LINE];
+ 	FILE *fp;
+ 	unsigned long long start, end;
+-- 
+1.7.10.4
+
diff --git a/package/boot/kexec-tools/patches/0005-mips-fix-warning-about-implicit-type-conversion.patch b/package/boot/kexec-tools/patches/0005-mips-fix-warning-about-implicit-type-conversion.patch
new file mode 100644
index 0000000000..008a62dcfd
--- /dev/null
+++ b/package/boot/kexec-tools/patches/0005-mips-fix-warning-about-implicit-type-conversion.patch
@@ -0,0 +1,30 @@
+From 00e75179b3b4b80e6e58d29a2bd948f97682fd00 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Mon, 9 Feb 2015 20:28:14 +0800
+Subject: [PATCH 5/5] mips: fix warning about implicit type conversion.
+
+Fixes the following warning.
+
+	kexec/arch/mips/kexec-elf-mips.c:161:16: warning: assignment makes integer from pointer without a cast [enabled by default]
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ kexec/arch/mips/kexec-elf-mips.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kexec/arch/mips/kexec-elf-mips.c b/kexec/arch/mips/kexec-elf-mips.c
+index a27d986..8a6419a 100644
+--- a/kexec/arch/mips/kexec-elf-mips.c
++++ b/kexec/arch/mips/kexec-elf-mips.c
+@@ -158,7 +158,7 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
+ 	if (info->kexec_flags & KEXEC_ON_CRASH)
+ 		/* In case of crashdump segment[0] is kernel.
+ 		 * Put cmdline just after it. */
+-		cmdline_addr = info->segment[0].mem +
++		cmdline_addr = (unsigned long)info->segment[0].mem +
+ 				info->segment[0].memsz;
+ 	else
+ 		cmdline_addr = 0;
+-- 
+1.7.10.4
+
diff --git a/package/boot/uboot-ar71xx/Makefile b/package/boot/uboot-ar71xx/Makefile
new file mode 100644
index 0000000000..1db2501856
--- /dev/null
+++ b/package/boot/uboot-ar71xx/Makefile
@@ -0,0 +1,95 @@
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=u-boot
+PKG_VERSION:=2010.03
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	https://librecmc.org/librecmc/downloads/sources/archive/v1.2.1/
+	ftp://ftp.denx.de/pub/u-boot
+PKG_MD5SUM:=526e01c8564ab8d1fd2c0e787a014b17
+PKG_TARGETS:=bin
+
+PKG_LICENSE:=GPL-2.0 GPL-2.0+
+PKG_LICENSE_FILES:=Licenses/README
+
+include $(INCLUDE_DIR)/package.mk
+
+define uboot/Default
+  TITLE:=
+  CONFIG:=
+  IMAGE:=
+endef
+
+define uboot/nbg460n_550n_550nh
+  TITLE:=U-boot for the NBG460N/550N/550NH routers
+  DEFAULT:=y if (TARGET_ar71xx_generic_DEVICE_NBG_460N_550N_550NH || TARGET_DEVICE_ar71xx_generic_DEVICE_NBG_460N_550N_550NH || TARGET_ar71xx_generic_Default)
+endef
+
+UBOOTS:=nbg460n_550n_550nh
+
+define Package/uboot/template
+define Package/uboot-ar71xx-$(1)
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  TITLE:=$(2)
+  DEPENDS:=@TARGET_ar71xx_generic
+  URL:=http://www.denx.de/wiki/U-Boot
+  VARIANT:=$(1)
+endef
+endef
+
+define BuildUbootPackage
+	$(eval $(uboot/Default))
+	$(eval $(uboot/$(1)))
+	$(call Package/uboot/template,$(1),$(TITLE))
+endef
+
+
+ifdef BUILD_VARIANT
+$(eval $(call uboot/$(BUILD_VARIANT)))
+UBOOT_CONFIG:=$(if $(CONFIG),$(CONFIG),$(BUILD_VARIANT))
+UBOOT_IMAGE:=$(if $(IMAGE),$(IMAGE),openwrt-$(BOARD)-$(BUILD_VARIANT)-u-boot.bin)
+endif
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+	$(CP) ./files/* $(PKG_BUILD_DIR)
+	find $(PKG_BUILD_DIR) -name .svn | $(XARGS) rm -rf
+endef
+
+define Build/Configure
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(UBOOT_CONFIG)_config
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE=$(TARGET_CROSS)
+endef
+
+define Package/uboot/install/template
+define Package/uboot-ar71xx-$(1)/install
+	$(INSTALL_DIR) $$(1)
+	$(CP) $(PKG_BUILD_DIR)/u-boot.bin $(BIN_DIR)/$(2)
+endef
+endef
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call Package/uboot/install/template,$(u),openwrt-$(BOARD)-$(SUBTARGET)-$(u)-u-boot.bin)) \
+)
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call BuildUbootPackage,$(u))) \
+	$(eval $(call BuildPackage,uboot-ar71xx-$(u))) \
+)
diff --git a/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/Makefile b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/Makefile
new file mode 100644
index 0000000000..b0a385babf
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/Makefile
@@ -0,0 +1,46 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).a
+
+COBJS-y += $(BOARD).o
+SOBJS-y += lowlevel_init.o
+
+SRCS	:= $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS-y))
+SOBJS	:= $(addprefix $(obj),$(SOBJS-y))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
+
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/config.mk b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/config.mk
new file mode 100644
index 0000000000..e042e78bf8
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/config.mk
@@ -0,0 +1 @@
+TEXT_BASE = 0x81E00000
diff --git a/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/lowlevel_init.S b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/lowlevel_init.S
new file mode 100644
index 0000000000..83084c8d48
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/lowlevel_init.S
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+
+
+
+.globl lowlevel_init
+/*
+	All done by Bootbase, nothing to do
+*/
+lowlevel_init:
+    jr ra
+    nop
+
diff --git a/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/nbg460n.c b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/nbg460n.c
new file mode 100644
index 0000000000..03a479d522
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/nbg460n.c
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/reboot.h>
+#include <asm/ar71xx.h>
+#include <asm/ar71xx_gpio.h>
+
+#define NBG460N_WAN_LED			19
+
+phys_size_t initdram(int board_type)
+{
+    return (32*1024*1024);
+}
+
+int checkboard(void)
+{
+	// Set pin 19 to 1, to stop WAN LED blinking
+    ar71xx_setpindir(NBG460N_WAN_LED, 1);
+    ar71xx_setpin(NBG460N_WAN_LED, 1);
+
+    printf("U-boot on Zyxel NBG460N\n");
+    return 0;
+}
+
+void _machine_restart(void)
+{
+	for (;;) {
+		writel((RESET_MODULE_FULL_CHIP | RESET_MODULE_DDR),
+			KSEG1ADDR(AR71XX_RESET_BASE + AR91XX_RESET_REG_RESET_MODULE));
+        readl(KSEG1ADDR(AR71XX_RESET_BASE + AR91XX_RESET_REG_RESET_MODULE));
+	}
+}
+
+int board_eth_init(bd_t *bis)
+{
+    char *phynames[] = {RTL8366_DEVNAME, RTL8366_DEVNAME};
+    u16 phyids[] = {RTL8366_LANPHY_ID, RTL8366_WANPHY_ID};
+    u16 phyfixed[] = {1, 0};
+
+    if (ag71xx_register(bis, phynames, phyids, phyfixed) <= 0)
+        return -1;
+
+	if (rtl8366s_initialize())
+        return -1;
+
+    if (rtl8366_mii_register(bis))
+        return -1;
+		
+    return 0;
+}
+
+int misc_init_r(void) {
+    uint8_t macaddr[6];
+    uint8_t enetaddr[6];
+
+	debug("Testing mac addresses\n");
+	
+    memcpy(macaddr, (uint8_t *) CONFIG_ETHADDR_ADDR, 6);
+
+    if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+        debug("Setting eth0 mac addr to %pM\n", macaddr);
+        eth_setenv_enetaddr("ethaddr", macaddr);
+    }
+
+    if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+		macaddr[5] += 1;
+        debug("Setting eth1 mac addr to %pM\n", macaddr);
+        eth_setenv_enetaddr("eth1addr", macaddr);
+    }
+
+    return 0;
+}
diff --git a/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/u-boot.lds b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/u-boot.lds
new file mode 100644
index 0000000000..8dc2b764c7
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/board/zyxel/nbg460n/u-boot.lds
@@ -0,0 +1,42 @@
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+	. = 0x00000000;
+
+	. = ALIGN(4);
+	.text       :
+	{
+	  *(.text)
+	}
+
+	. = ALIGN(4);
+	.rodata  : { *(.rodata) }
+
+	. = ALIGN(4);
+	.data  : { *(.data) }
+
+	. = ALIGN(4);
+	.sdata  : { *(.sdata) }
+
+	_gp = ALIGN(16);
+
+	__got_start = .;
+	.got  : { *(.got) }
+	__got_end = .;
+
+	.sdata  : { *(.sdata) }
+
+	__u_boot_cmd_start = .;
+	.u_boot_cmd : { *(.u_boot_cmd) }
+	__u_boot_cmd_end = .;
+
+	uboot_end_data = .;
+	num_got_entries = (__got_end - __got_start) >> 2;
+
+	. = ALIGN(4);
+	.sbss  : { *(.sbss) }
+	.bss  : { *(.bss) }
+	uboot_end = .;
+}
diff --git a/package/boot/uboot-ar71xx/files/cpu/mips/ar71xx_serial.c b/package/boot/uboot-ar71xx/files/cpu/mips/ar71xx_serial.c
new file mode 100644
index 0000000000..f093318952
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/cpu/mips/ar71xx_serial.c
@@ -0,0 +1,177 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <config.h>
+#include <asm/ar71xx.h>
+
+#define		REG_SIZE		4
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define         OFS_RCV_BUFFER          (0*REG_SIZE)
+#define         OFS_TRANS_HOLD          (0*REG_SIZE)
+#define         OFS_SEND_BUFFER         (0*REG_SIZE)
+#define         OFS_INTR_ENABLE         (1*REG_SIZE)
+#define         OFS_INTR_ID             (2*REG_SIZE)
+#define         OFS_DATA_FORMAT         (3*REG_SIZE)
+#define         OFS_LINE_CONTROL        (3*REG_SIZE)
+#define         OFS_MODEM_CONTROL       (4*REG_SIZE)
+#define         OFS_RS232_OUTPUT        (4*REG_SIZE)
+#define         OFS_LINE_STATUS         (5*REG_SIZE)
+#define         OFS_MODEM_STATUS        (6*REG_SIZE)
+#define         OFS_RS232_INPUT         (6*REG_SIZE)
+#define         OFS_SCRATCH_PAD         (7*REG_SIZE)
+
+#define         OFS_DIVISOR_LSB         (0*REG_SIZE)
+#define         OFS_DIVISOR_MSB         (1*REG_SIZE)
+
+#define         UART16550_READ(y)   readl(KSEG1ADDR(AR71XX_UART_BASE+y))
+#define         UART16550_WRITE(x, z)  writel(z, KSEG1ADDR((AR71XX_UART_BASE+x)))
+
+void 
+ar71xx_sys_frequency(u32 *cpu_freq, u32 *ddr_freq, u32 *ahb_freq)
+{
+#ifndef CONFIG_AR91XX
+    u32 pll, pll_div, cpu_div, ahb_div, ddr_div, freq;
+
+    pll = readl(KSEG1ADDR(AR71XX_PLL_REG_CPU_CONFIG + AR71XX_PLL_BASE));
+
+    pll_div = 
+        ((pll & AR71XX_PLL_DIV_MASK) >> AR71XX_PLL_DIV_SHIFT) + 1;
+
+    cpu_div = 
+        ((pll & AR71XX_CPU_DIV_MASK) >> AR71XX_CPU_DIV_SHIFT) + 1;
+
+    ddr_div = 
+        ((pll & AR71XX_DDR_DIV_MASK) >> AR71XX_DDR_DIV_SHIFT) + 1;
+
+    ahb_div = 
+       (((pll & AR71XX_AHB_DIV_MASK) >> AR71XX_AHB_DIV_SHIFT) + 1)*2;
+
+    freq = pll_div * 40000000; 
+
+    if (cpu_freq)
+        *cpu_freq = freq/cpu_div;
+
+    if (ddr_freq)
+        *ddr_freq = freq/ddr_div;
+
+    if (ahb_freq)
+        *ahb_freq = (freq/cpu_div)/ahb_div;
+
+#else
+    u32 pll, pll_div, ahb_div, ddr_div, freq;
+
+    pll = readl(KSEG1ADDR(AR91XX_PLL_REG_CPU_CONFIG + AR71XX_PLL_BASE));
+
+    pll_div = 
+        ((pll & AR91XX_PLL_DIV_MASK) >> AR91XX_PLL_DIV_SHIFT);
+
+    ddr_div = 
+        ((pll & AR91XX_DDR_DIV_MASK) >> AR91XX_DDR_DIV_SHIFT) + 1;
+
+    ahb_div = 
+       (((pll & AR91XX_AHB_DIV_MASK) >> AR91XX_AHB_DIV_SHIFT) + 1)*2;
+
+    freq = pll_div * 5000000; 
+
+    if (cpu_freq)
+        *cpu_freq = freq;
+
+    if (ddr_freq)
+        *ddr_freq = freq/ddr_div;
+
+    if (ahb_freq)
+        *ahb_freq = freq/ahb_div;
+#endif
+}
+
+
+int serial_init(void)
+{
+    u32 div;
+    u32 ahb_freq = 100000000;
+
+    ar71xx_sys_frequency  (0, 0, &ahb_freq);  
+    div  = ahb_freq/(16 * CONFIG_BAUDRATE);  
+
+	// enable uart pins
+#ifndef CONFIG_AR91XX
+    writel(AR71XX_GPIO_FUNC_UART_EN, KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_FUNC));
+#else
+	writel(AR91XX_GPIO_FUNC_UART_EN, KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_FUNC));
+#endif
+
+    /* set DIAB bit */
+    UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+    /* set divisor */
+    UART16550_WRITE(OFS_DIVISOR_LSB, (div & 0xff));
+    UART16550_WRITE(OFS_DIVISOR_MSB, ((div >> 8) & 0xff));
+
+    /* clear DIAB bit*/ 
+    UART16550_WRITE(OFS_LINE_CONTROL, 0x00);
+
+    /* set data format */
+    UART16550_WRITE(OFS_DATA_FORMAT, 0x3);
+
+    UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+	return 0;
+}
+
+int serial_tstc (void)
+{
+    return(UART16550_READ(OFS_LINE_STATUS) & 0x1);
+}
+
+int serial_getc(void)
+{
+    while(!serial_tstc());
+
+    return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+void serial_putc(const char byte)
+{
+    if (byte == '\n') serial_putc ('\r');
+
+    while (((UART16550_READ(OFS_LINE_STATUS)) & 0x20) == 0x0);
+    UART16550_WRITE(OFS_SEND_BUFFER, byte);
+}
+
+void serial_setbrg (void)
+{
+}
+
+void serial_puts (const char *s)
+{
+	while (*s)
+	{
+		serial_putc (*s++);
+	}
+}
diff --git a/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c
new file mode 100644
index 0000000000..b3324c0197
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c
@@ -0,0 +1,809 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2010 Michael Kurz <michi.kurz@googlemail.com>
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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 <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+
+#include <asm/ar71xx.h>
+
+#include "ag71xx.h"
+
+#ifdef AG71XX_DEBUG
+#define DBG(fmt,args...)		printf(fmt ,##args)
+#else
+#define DBG(fmt,args...)
+#endif
+
+
+static struct ag71xx agtable[] = {
+	{
+		.mac_base = KSEG1ADDR(AR71XX_GE0_BASE),
+		.mii_ctrl = KSEG1ADDR(AR71XX_MII_BASE + MII_REG_MII0_CTRL),
+		.mii_if = CONFIG_AG71XX_MII0_IIF,
+	} , {
+		.mac_base = KSEG1ADDR(AR71XX_GE1_BASE),
+		.mii_ctrl = KSEG1ADDR(AR71XX_MII_BASE + MII_REG_MII1_CTRL),
+		.mii_if = CONFIG_AG71XX_MII1_IIF,
+	}
+};
+
+static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size)
+{
+	int err;
+	int i;
+	int rsize;
+
+	ring->desc_size = sizeof(struct ag71xx_desc);
+	if (ring->desc_size % (CONFIG_SYS_CACHELINE_SIZE)) {
+		rsize = roundup(ring->desc_size, CONFIG_SYS_CACHELINE_SIZE);
+		DBG("ag71xx: ring %p, desc size %u rounded to %u\n",
+			ring, ring->desc_size,
+			rsize);
+		ring->desc_size = rsize;
+	}
+
+	ring->descs_cpu = (u8 *) malloc((size * ring->desc_size)
+		+ CONFIG_SYS_CACHELINE_SIZE - 1);
+	if (!ring->descs_cpu) {
+		err = -1;
+		goto err;
+	}
+	ring->descs_cpu = (u8 *) UNCACHED_SDRAM((((u32) ring->descs_cpu + 
+		CONFIG_SYS_CACHELINE_SIZE - 1) & ~(CONFIG_SYS_CACHELINE_SIZE - 1)));
+    ring->descs_dma = (u8 *) virt_to_phys(ring->descs_cpu);
+
+	ring->size = size;
+
+	ring->buf = malloc(size * sizeof(*ring->buf));
+	if (!ring->buf) {
+		err = -1;
+		goto err;
+	}
+    memset(ring->buf, 0, size * sizeof(*ring->buf));
+
+	for (i = 0; i < size; i++) {
+		ring->buf[i].desc =
+			(struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size];
+		DBG("ag71xx: ring %p, desc %d at %p\n",
+			ring, i, ring->buf[i].desc);
+	}
+
+	flush_cache( (u32) ring->buf, size * sizeof(*ring->buf));
+	
+	return 0;
+
+ err:
+	return err;
+}
+
+static void ag71xx_ring_tx_init(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->tx_ring;
+	int i;
+
+	for (i = 0; i < AG71XX_TX_RING_SIZE; i++) {
+		ring->buf[i].desc->next = (u32) virt_to_phys((ring->descs_dma +
+			ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE)));
+
+		ring->buf[i].desc->ctrl = DESC_EMPTY;
+		ring->buf[i].skb = NULL;
+	}
+
+	ring->curr = 0;
+}
+
+static void ag71xx_ring_rx_clean(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	int i;
+
+	if (!ring->buf)
+		return;
+
+	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
+	    ring->buf[i].desc->data = (u32) virt_to_phys(NetRxPackets[i]);
+	    flush_cache((u32) NetRxPackets[i], PKTSIZE_ALIGN);
+        ring->buf[i].desc->ctrl = DESC_EMPTY;
+    }
+
+	ring->curr = 0;
+}
+
+static int ag71xx_ring_rx_init(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	unsigned int i;
+
+	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
+		ring->buf[i].desc->next = (u32) virt_to_phys((ring->descs_dma +
+			ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE)));
+
+		DBG("ag71xx: RX desc at %p, next is %08x\n",
+			ring->buf[i].desc,
+			ring->buf[i].desc->next);
+	}
+
+	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
+		ring->buf[i].desc->data = (u32) virt_to_phys(NetRxPackets[i]);
+		ring->buf[i].desc->ctrl = DESC_EMPTY;
+	}
+
+	ring->curr = 0;
+
+	return 0;
+}
+
+static int ag71xx_rings_init(struct ag71xx *ag)
+{
+	int ret;
+
+	ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE);
+	if (ret)
+		return ret;
+
+	ag71xx_ring_tx_init(ag);
+
+	ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE);
+	if (ret)
+		return ret;
+
+	ret = ag71xx_ring_rx_init(ag);
+	return ret;
+}
+
+static void ar71xx_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
+{
+	uint32_t base = KSEG1ADDR(AR71XX_PLL_BASE);
+	u32 t;
+
+	t = readl(base + cfg_reg);
+	t &= ~(3 << shift);
+	t |=  (2 << shift);
+	writel(t, base + cfg_reg);
+	udelay(100);
+
+	writel(pll_val, base + pll_reg);
+
+	t |= (3 << shift);
+	writel(t, base + cfg_reg);
+	udelay(100);
+
+	t &= ~(3 << shift);
+	writel(t, base + cfg_reg);
+	udelay(100);
+
+	debug("ar71xx: pll_reg %#x: %#x\n", (unsigned int)(base + pll_reg),
+       readl(base + pll_reg));
+}
+
+static void ar91xx_set_pll_ge0(int speed)
+{
+	//u32 val = ar71xx_get_eth_pll(0, speed);
+	u32 pll_val;
+
+	switch (speed) {
+	case SPEED_10:
+		pll_val = 0x00441099;
+		break;
+	case SPEED_100:
+		pll_val = 0x13000a44;
+		break;
+	case SPEED_1000:
+		pll_val = 0x1a000000;
+		break;
+	default:
+		BUG();
+	}
+
+	ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH0_INT_CLOCK,
+			 pll_val, AR91XX_ETH0_PLL_SHIFT);
+}
+
+static void ar91xx_set_pll_ge1(int speed)
+{
+	//u32 val = ar71xx_get_eth_pll(1, speed);
+    u32 pll_val;
+
+	switch (speed) {
+	case SPEED_10:
+		pll_val = 0x00441099;
+		break;
+	case SPEED_100:
+		pll_val = 0x13000a44;
+		break;
+	case SPEED_1000:
+		pll_val = 0x1a000000;
+		break;
+	default:
+		BUG();
+	}
+
+	ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH1_INT_CLOCK,
+			 pll_val, AR91XX_ETH1_PLL_SHIFT);
+}
+
+static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
+{
+	u32 t;
+
+	t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16)
+	  | (((u32) mac[3]) << 8) | ((u32) mac[2]);
+
+	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
+
+	t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16);
+	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
+}
+
+static void ag71xx_dma_reset(struct ag71xx *ag)
+{
+	u32 val;
+	int i;
+
+	DBG("%s: txdesc reg: 0x%08x rxdesc reg: 0x%08x\n",
+			ag->dev->name,
+			ag71xx_rr(ag, AG71XX_REG_TX_DESC),
+			ag71xx_rr(ag, AG71XX_REG_RX_DESC));
+	
+	/* stop RX and TX */
+	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+
+	/* clear descriptor addresses */
+	ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0);
+	ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0);
+
+	/* clear pending RX/TX interrupts */
+	for (i = 0; i < 256; i++) {
+		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
+		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
+	}
+
+	/* clear pending errors */
+	ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
+	ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
+
+	val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
+	if (val)
+		printf("%s: unable to clear DMA Rx status: %08x\n",
+			ag->dev->name, val);
+
+	val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
+
+	/* mask out reserved bits */
+	val &= ~0xff000000;
+
+	if (val)
+		printf("%s: unable to clear DMA Tx status: %08x\n",
+			ag->dev->name, val);
+}
+
+static void ag71xx_halt(struct eth_device *dev)
+{
+    struct ag71xx *ag = (struct ag71xx *) dev->priv;
+
+    /* stop RX engine */
+	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+
+	ag71xx_dma_reset(ag);
+}
+
+#define MAX_WAIT        1000
+
+static int ag71xx_send(struct eth_device *dev, volatile void *packet,
+                       int length)
+{
+    struct ag71xx *ag = (struct ag71xx *) dev->priv;
+	struct ag71xx_ring *ring = &ag->tx_ring;
+	struct ag71xx_desc *desc;
+	int i;
+
+	i = ring->curr % AG71XX_TX_RING_SIZE;
+	desc = ring->buf[i].desc;
+
+	if (!ag71xx_desc_empty(desc)) {
+		printf("%s: tx buffer full\n", ag->dev->name);
+		return 1;
+	}
+
+	flush_cache((u32) packet, length);
+    desc->data = (u32) virt_to_phys(packet);
+    desc->ctrl = (length & DESC_PKTLEN_M);
+	
+	DBG("%s: sending %#08x length %#08x\n",
+		ag->dev->name, desc->data, desc->ctrl);
+	
+	ring->curr++;
+	if (ring->curr >= AG71XX_TX_RING_SIZE){
+		ring->curr = 0;
+	}
+	
+	/* enable TX engine */
+	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
+
+    for (i = 0; i < MAX_WAIT; i++)
+    {
+        if (ag71xx_desc_empty(desc))
+            break;
+        udelay(10);
+    }
+    if (i == MAX_WAIT) {
+        printf("%s: tx timed out!\n", ag->dev->name);
+		return -1;
+	}
+	
+	/* disable TX engine */
+	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+	desc->data = 0;
+	desc->ctrl = DESC_EMPTY;
+	
+	return 0;
+}
+
+static int ag71xx_recv(struct eth_device *dev)
+{
+    struct ag71xx *ag = (struct ag71xx *) dev->priv;
+	struct ag71xx_ring *ring = &ag->rx_ring;
+
+    for (;;) {
+		unsigned int i = ring->curr % AG71XX_RX_RING_SIZE;
+		struct ag71xx_desc *desc = ring->buf[i].desc;
+		int pktlen;
+		
+		if (ag71xx_desc_empty(desc))
+			break;
+
+		DBG("%s: rx packets, curr=%u\n", dev->name, ring->curr);
+
+        pktlen = ag71xx_desc_pktlen(desc);
+		pktlen -= ETH_FCS_LEN;
+
+
+		NetReceive(NetRxPackets[i] , pktlen);
+		flush_cache( (u32) NetRxPackets[i], PKTSIZE_ALIGN);
+
+        ring->buf[i].desc->ctrl = DESC_EMPTY;
+		ring->curr++;
+		if (ring->curr >= AG71XX_RX_RING_SIZE){
+			ring->curr = 0;
+		}
+
+    }
+
+	if ((ag71xx_rr(ag, AG71XX_REG_RX_CTRL) & RX_CTRL_RXE) == 0) {
+		/* start RX engine */
+		ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+	}
+	
+	return 0;
+}
+
+#ifdef AG71XX_DEBUG
+static char *ag71xx_speed_str(struct ag71xx *ag)
+{
+	switch (ag->speed) {
+	case SPEED_1000:
+		return "1000";
+	case SPEED_100:
+		return "100";
+	case SPEED_10:
+		return "10";
+	}
+
+	return "?";
+}
+#endif
+
+void ag71xx_link_adjust(struct ag71xx *ag)
+{
+	u32 cfg2;
+	u32 ifctl;
+	u32 fifo5;
+	u32 mii_speed;
+
+	if (!ag->link) {
+		DBG("%s: link down\n", ag->dev->name);
+		return;
+	}
+
+	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
+	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
+	cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
+
+	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
+	ifctl &= ~(MAC_IFCTL_SPEED);
+
+	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
+	fifo5 &= ~FIFO_CFG5_BM;
+
+	switch (ag->speed) {
+	case SPEED_1000:
+		mii_speed =  MII_CTRL_SPEED_1000;
+		cfg2 |= MAC_CFG2_IF_1000;
+		fifo5 |= FIFO_CFG5_BM;
+		break;
+	case SPEED_100:
+		mii_speed = MII_CTRL_SPEED_100;
+		cfg2 |= MAC_CFG2_IF_10_100;
+		ifctl |= MAC_IFCTL_SPEED;
+		break;
+	case SPEED_10:
+		mii_speed = MII_CTRL_SPEED_10;
+		cfg2 |= MAC_CFG2_IF_10_100;
+		break;
+	default:
+		BUG();
+		return;
+	}
+
+    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff);
+
+    if (ag->macNum == 0)
+        ar91xx_set_pll_ge0(ag->speed);
+    else
+        ar91xx_set_pll_ge1(ag->speed);
+
+	ag71xx_mii_ctrl_set_speed(ag, mii_speed);
+
+	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
+	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
+	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
+
+    DBG("%s: link up (%sMbps/%s duplex)\n",
+        ag->dev->name,
+        ag71xx_speed_str(ag),
+        (1 == ag->duplex) ? "Full" : "Half");
+
+	DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
+
+	DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
+
+	DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
+		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
+		ag71xx_mii_ctrl_rr(ag));
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static int ag71xx_getMiiSpeed(struct ag71xx *ag) 
+{
+    uint16_t phyreg, cap;
+
+    if (miiphy_read(ag->phyname, ag->phyid,
+                    PHY_BMSR, &phyreg)) {
+        puts("PHY_BMSR read failed, assuming no link\n");
+        return -1;
+    }
+
+    if ((phyreg & PHY_BMSR_LS) == 0) {
+        return -1;
+    }
+
+    if (miiphy_read(ag->phyname, ag->phyid,
+                PHY_1000BTSR, &phyreg))
+        return -1;
+
+    if (phyreg & PHY_1000BTSR_1000FD) {
+        ag->speed = SPEED_1000;
+        ag->duplex = 1;
+    } else if (phyreg & PHY_1000BTSR_1000HD) {
+        ag->speed = SPEED_1000;
+        ag->duplex = 0;
+    } else {
+        if (miiphy_read(ag->phyname, ag->phyid,
+                PHY_ANAR, &cap))
+            return -1;
+
+        if (miiphy_read(ag->phyname, ag->phyid,
+                PHY_ANLPAR, &phyreg))
+            return -1;
+
+        cap &= phyreg;
+        if (cap & PHY_ANLPAR_TXFD) {
+            ag->speed = SPEED_100;
+            ag->duplex = 1;
+        } else if (cap & PHY_ANLPAR_TX) {
+            ag->speed = SPEED_100;
+            ag->duplex = 0;
+        } else if (cap & PHY_ANLPAR_10FD) {
+            ag->speed = SPEED_10;
+            ag->duplex = 1;
+        } else {
+            ag->speed = SPEED_10;
+            ag->duplex = 0;
+        }
+    }
+	
+	ag->link = 1;
+	
+	return 0;
+}
+#endif
+
+static int ag71xx_hw_start(struct eth_device *dev, bd_t * bd)
+{
+	struct ag71xx *ag = (struct ag71xx *) dev->priv;
+
+	ag71xx_dma_reset(ag);
+
+    ag71xx_ring_rx_clean(ag);
+	ag71xx_ring_tx_init(ag);
+	
+	ag71xx_wr(ag, AG71XX_REG_TX_DESC, 
+				(u32) virt_to_phys(ag->tx_ring.descs_dma));
+	ag71xx_wr(ag, AG71XX_REG_RX_DESC,
+				(u32) virt_to_phys(ag->rx_ring.descs_dma));
+
+	ag71xx_hw_set_macaddr(ag, ag->dev->enetaddr);
+
+    if (ag->phyfixed) {
+        ag->link = 1;
+        ag->duplex = 1;
+        ag->speed = SPEED_1000;
+    } else {
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+		if (ag71xx_getMiiSpeed(ag))
+			return -1;
+#else
+		/* only fixed, without mii */
+		return -1;
+#endif
+
+    }
+    ag71xx_link_adjust(ag);
+	
+	DBG("%s: txdesc reg: %#08x rxdesc reg: %#08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_TX_DESC),
+		ag71xx_rr(ag, AG71XX_REG_RX_DESC));
+	
+	/* start RX engine */
+	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+	
+	return 0;
+}
+
+#define FIFO_CFG0_INIT	(FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
+
+#define FIFO_CFG4_INIT	(FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
+			 FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
+			 FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
+			 FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
+			 FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
+			 FIFO_CFG4_VT)
+
+#define FIFO_CFG5_INIT	(FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
+			 FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
+			 FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
+			 FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
+			 FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
+			 FIFO_CFG5_17 | FIFO_CFG5_SF)
+
+static int ag71xx_hw_init(struct ag71xx *ag)
+{
+    int ret = 0;
+	uint32_t reg;
+	uint32_t mask, mii_type;
+
+    if (ag->macNum == 0) {
+        mask = (RESET_MODULE_GE0_MAC | RESET_MODULE_GE0_PHY);
+        mii_type = 0x13;
+    } else {
+        mask = (RESET_MODULE_GE1_MAC | RESET_MODULE_GE1_PHY);
+        mii_type = 0x11;
+    }
+
+    // mac soft reset
+    ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
+    udelay(20);
+	
+	// device stop
+	reg = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
+	ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, reg | mask);
+	udelay(100 * 1000);
+	
+    // device start
+    reg = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE);
+    ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, reg & ~mask);
+    udelay(100 * 1000);
+
+    /* setup MAC configuration registers */
+    ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, (MAC_CFG1_RXE | MAC_CFG1_TXE));
+
+    ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
+          MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
+
+    /* setup FIFO configuration register 0 */
+    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
+
+    /* setup MII interface type */
+    ag71xx_mii_ctrl_set_if(ag, ag->mii_if);
+
+    /* setup mdio clock divisor */
+    ag71xx_wr(ag, AG71XX_REG_MII_CFG, MII_CFG_CLK_DIV_20);
+	
+	/* setup FIFO configuration registers */
+	ag71xx_sb(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
+    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000);
+    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff);
+    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
+
+    ag71xx_dma_reset(ag);
+
+    ret = ag71xx_rings_init(ag);
+    if (ret)
+        return -1;
+
+	ag71xx_wr(ag, AG71XX_REG_TX_DESC, 
+				(u32) virt_to_phys(ag->tx_ring.descs_dma));
+	ag71xx_wr(ag, AG71XX_REG_RX_DESC,
+				(u32) virt_to_phys(ag->rx_ring.descs_dma));
+		
+	ag71xx_hw_set_macaddr(ag, ag->dev->enetaddr);
+	
+    return 0;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#define AG71XX_MDIO_RETRY	1000
+#define AG71XX_MDIO_DELAY	5
+
+static inline struct ag71xx *ag71xx_name2mac(char *devname)
+{
+    if (strcmp(devname, agtable[0].dev->name) == 0)
+        return &agtable[0];
+    else if (strcmp(devname, agtable[1].dev->name) == 0)
+        return &agtable[1];
+    else
+        return NULL;
+}
+
+static inline void ag71xx_mdio_wr(struct ag71xx *ag, unsigned reg,
+				  u32 value)
+{
+	uint32_t r;
+
+	r = ag->mac_base + reg;
+	writel(value, r);
+
+	/* flush write */
+	(void) readl(r);
+}
+
+static inline u32 ag71xx_mdio_rr(struct ag71xx *ag, unsigned reg)
+{
+	return readl(ag->mac_base + reg);
+}
+
+static int ag71xx_mdio_read(char *devname, unsigned char addr,
+                            unsigned char reg, unsigned short *val)
+{
+	struct ag71xx *ag = ag71xx_name2mac(devname);
+	uint16_t regData;
+	int i;
+
+	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+	ag71xx_mdio_wr(ag, AG71XX_REG_MII_ADDR,
+			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
+	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ);
+
+	i = AG71XX_MDIO_RETRY;
+	while (ag71xx_mdio_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
+		if (i-- == 0) {
+			printf("%s: mii_read timed out\n",
+				ag->dev->name);
+			return -1;
+		}
+		udelay(AG71XX_MDIO_DELAY);
+	}
+
+	regData = (uint16_t) ag71xx_mdio_rr(ag, AG71XX_REG_MII_STATUS) & 0xffff;
+	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+
+	DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, regData);
+
+    if (val)
+        *val = regData;
+
+	return 0;
+}
+
+static int ag71xx_mdio_write(char *devname, unsigned char addr,
+                            unsigned char reg, unsigned short val)
+{
+	struct ag71xx *ag = ag71xx_name2mac(devname);
+	int i;
+
+    if (ag == NULL)
+        return 1;
+
+	DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
+
+	ag71xx_mdio_wr(ag, AG71XX_REG_MII_ADDR,
+			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
+	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CTRL, val);
+
+	i = AG71XX_MDIO_RETRY;
+	while (ag71xx_mdio_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) {
+		if (i-- == 0) {
+			printf("%s: mii_write timed out\n",
+				ag->dev->name);
+			break;
+		}
+		udelay(AG71XX_MDIO_DELAY);
+	}
+
+	return 0;
+}
+#endif
+
+int ag71xx_register(bd_t * bis, char *phyname[], uint16_t phyid[], uint16_t phyfixed[])
+{
+    int i, num = 0;
+    u8 used_ports[MAX_AG71XX_DEVS] = CONFIG_AG71XX_PORTS;
+
+	for (i = 0; i < MAX_AG71XX_DEVS; i++) {
+		/*skip if port is configured not to use */
+		if (used_ports[i] == 0)
+			continue;
+
+		agtable[i].dev = malloc(sizeof(struct eth_device));
+		if (agtable[i].dev == NULL) {
+			puts("malloc failed\n");
+			return 0;
+        }
+		memset(agtable[i].dev, 0, sizeof(struct eth_device));
+		sprintf(agtable[i].dev->name, "eth%d", i);
+
+		agtable[i].dev->iobase = 0;
+		agtable[i].dev->init = ag71xx_hw_start;
+		agtable[i].dev->halt = ag71xx_halt;
+		agtable[i].dev->send = ag71xx_send;
+		agtable[i].dev->recv = ag71xx_recv;
+		agtable[i].dev->priv = (void *) (&agtable[i]);
+		agtable[i].macNum = i;
+		eth_register(agtable[i].dev);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+        if ((phyname == NULL) || (phyid == NULL) || (phyfixed == NULL))
+            return -1;
+
+        agtable[i].phyname = strdup(phyname[i]);
+        agtable[i].phyid = phyid[i];
+        agtable[i].phyfixed = phyfixed[i];
+
+        miiphy_register(agtable[i].dev->name, ag71xx_mdio_read,
+			ag71xx_mdio_write);
+#endif
+
+		if (ag71xx_hw_init(&agtable[i]))
+			continue;
+
+        num++;
+	}
+
+    return num;
+}
diff --git a/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h
new file mode 100644
index 0000000000..edce429749
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h
@@ -0,0 +1,374 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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.
+ */
+
+#ifndef __AG71XX_H
+#define __AG71XX_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#include <asm/ar71xx.h>
+
+// controller has 2 ports
+#define MAX_AG71XX_DEVS 2
+
+#define ETH_FCS_LEN	4
+
+#define SPEED_10        10
+#define SPEED_100       100
+#define SPEED_1000      1000
+
+
+#define AG71XX_INT_ERR	(AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
+#define AG71XX_INT_TX	(AG71XX_INT_TX_PS)
+#define AG71XX_INT_RX	(AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
+
+#define AG71XX_INT_POLL	(AG71XX_INT_RX | AG71XX_INT_TX)
+#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL)
+
+#define AG71XX_TX_FIFO_LEN	2048
+#define AG71XX_TX_MTU_LEN	1536
+#define AG71XX_RX_PKT_RESERVE	64
+#define AG71XX_RX_PKT_SIZE	\
+	(AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN)
+
+#ifndef CONFIG_SYS_RX_ETH_BUFFER
+#define AG71XX_TX_RING_SIZE	4
+#define AG71XX_RX_RING_SIZE	4
+#else
+#define AG71XX_TX_RING_SIZE	CONFIG_SYS_RX_ETH_BUFFER
+#define AG71XX_RX_RING_SIZE	CONFIG_SYS_RX_ETH_BUFFER
+#endif
+
+#define AG71XX_TX_THRES_STOP	(AG71XX_TX_RING_SIZE - 4)
+#define AG71XX_TX_THRES_WAKEUP	\
+		(AG71XX_TX_RING_SIZE - (AG71XX_TX_RING_SIZE / 4))
+
+
+
+
+struct ag71xx_desc {
+	u32	data;
+	u32	ctrl;
+#define DESC_EMPTY	BIT(31)
+#define DESC_MORE	BIT(24)
+#define DESC_PKTLEN_M	0xfff
+	u32	next;
+	u32	pad;
+} __attribute__((aligned(4)));
+
+struct ag71xx_buf {
+	struct sk_buff		*skb;
+	struct ag71xx_desc 	*desc;
+	dma_addr_t		dma_addr;
+	u32			pad;
+};
+
+struct ag71xx_ring {
+	struct ag71xx_buf	*buf;
+	u8			*descs_cpu;
+	u8		    *descs_dma;
+	unsigned int		desc_size;
+	unsigned int		curr;
+	unsigned int		size;
+};
+
+struct ag71xx {
+	uint32_t		    mac_base;
+	uint32_t		    mii_ctrl;
+
+	struct eth_device	*dev;
+
+	struct ag71xx_ring	rx_ring;
+	struct ag71xx_ring	tx_ring;
+
+    char               *phyname;
+    u16                 phyid;
+    u16                 phyfixed;
+	uint32_t	    	link;
+	uint32_t	    	speed;
+	int32_t			    duplex;
+    uint32_t            macNum;
+    uint32_t            mii_if;
+};
+
+void ag71xx_link_adjust(struct ag71xx *ag);
+
+int ag71xx_phy_connect(struct ag71xx *ag);
+void ag71xx_phy_disconnect(struct ag71xx *ag);
+void ag71xx_phy_start(struct ag71xx *ag);
+void ag71xx_phy_stop(struct ag71xx *ag);
+
+static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
+{
+	return ((desc->ctrl & DESC_EMPTY) != 0);
+}
+
+static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc)
+{
+	return (desc->ctrl & DESC_PKTLEN_M);
+}
+
+/* Register offsets */
+#define AG71XX_REG_MAC_CFG1	0x0000
+#define AG71XX_REG_MAC_CFG2	0x0004
+#define AG71XX_REG_MAC_IPG	0x0008
+#define AG71XX_REG_MAC_HDX	0x000c
+#define AG71XX_REG_MAC_MFL	0x0010
+#define AG71XX_REG_MII_CFG	0x0020
+#define AG71XX_REG_MII_CMD	0x0024
+#define AG71XX_REG_MII_ADDR	0x0028
+#define AG71XX_REG_MII_CTRL	0x002c
+#define AG71XX_REG_MII_STATUS	0x0030
+#define AG71XX_REG_MII_IND	0x0034
+#define AG71XX_REG_MAC_IFCTL	0x0038
+#define AG71XX_REG_MAC_ADDR1	0x0040
+#define AG71XX_REG_MAC_ADDR2	0x0044
+#define AG71XX_REG_FIFO_CFG0	0x0048
+#define AG71XX_REG_FIFO_CFG1	0x004c
+#define AG71XX_REG_FIFO_CFG2	0x0050
+#define AG71XX_REG_FIFO_CFG3	0x0054
+#define AG71XX_REG_FIFO_CFG4	0x0058
+#define AG71XX_REG_FIFO_CFG5	0x005c
+#define AG71XX_REG_FIFO_RAM0	0x0060
+#define AG71XX_REG_FIFO_RAM1	0x0064
+#define AG71XX_REG_FIFO_RAM2	0x0068
+#define AG71XX_REG_FIFO_RAM3	0x006c
+#define AG71XX_REG_FIFO_RAM4	0x0070
+#define AG71XX_REG_FIFO_RAM5	0x0074
+#define AG71XX_REG_FIFO_RAM6	0x0078
+#define AG71XX_REG_FIFO_RAM7	0x007c
+
+#define AG71XX_REG_TX_CTRL	0x0180
+#define AG71XX_REG_TX_DESC	0x0184
+#define AG71XX_REG_TX_STATUS	0x0188
+#define AG71XX_REG_RX_CTRL	0x018c
+#define AG71XX_REG_RX_DESC	0x0190
+#define AG71XX_REG_RX_STATUS	0x0194
+#define AG71XX_REG_INT_ENABLE	0x0198
+#define AG71XX_REG_INT_STATUS	0x019c
+
+#define MAC_CFG1_TXE		BIT(0)	/* Tx Enable */
+#define MAC_CFG1_STX		BIT(1)	/* Synchronize Tx Enable */
+#define MAC_CFG1_RXE		BIT(2)	/* Rx Enable */
+#define MAC_CFG1_SRX		BIT(3)	/* Synchronize Rx Enable */
+#define MAC_CFG1_TFC		BIT(4)	/* Tx Flow Control Enable */
+#define MAC_CFG1_RFC		BIT(5)	/* Rx Flow Control Enable */
+#define MAC_CFG1_LB		BIT(8)	/* Loopback mode */
+#define MAC_CFG1_SR		BIT(31)	/* Soft Reset */
+
+#define MAC_CFG2_FDX		BIT(0)
+#define MAC_CFG2_CRC_EN		BIT(1)
+#define MAC_CFG2_PAD_CRC_EN	BIT(2)
+#define MAC_CFG2_LEN_CHECK	BIT(4)
+#define MAC_CFG2_HUGE_FRAME_EN	BIT(5)
+#define MAC_CFG2_IF_1000	BIT(9)
+#define MAC_CFG2_IF_10_100	BIT(8)
+
+#define FIFO_CFG0_WTM		BIT(0)	/* Watermark Module */
+#define FIFO_CFG0_RXS		BIT(1)	/* Rx System Module */
+#define FIFO_CFG0_RXF		BIT(2)	/* Rx Fabric Module */
+#define FIFO_CFG0_TXS		BIT(3)	/* Tx System Module */
+#define FIFO_CFG0_TXF		BIT(4)	/* Tx Fabric Module */
+#define FIFO_CFG0_ALL	(FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
+			| FIFO_CFG0_TXS | FIFO_CFG0_TXF)
+
+#define FIFO_CFG0_ENABLE_SHIFT	8
+
+#define FIFO_CFG4_DE		BIT(0)	/* Drop Event */
+#define FIFO_CFG4_DV		BIT(1)	/* RX_DV Event */
+#define FIFO_CFG4_FC		BIT(2)	/* False Carrier */
+#define FIFO_CFG4_CE		BIT(3)	/* Code Error */
+#define FIFO_CFG4_CR		BIT(4)	/* CRC error */
+#define FIFO_CFG4_LM		BIT(5)	/* Length Mismatch */
+#define FIFO_CFG4_LO		BIT(6)	/* Length out of range */
+#define FIFO_CFG4_OK		BIT(7)	/* Packet is OK */
+#define FIFO_CFG4_MC		BIT(8)	/* Multicast Packet */
+#define FIFO_CFG4_BC		BIT(9)	/* Broadcast Packet */
+#define FIFO_CFG4_DR		BIT(10)	/* Dribble */
+#define FIFO_CFG4_LE		BIT(11)	/* Long Event */
+#define FIFO_CFG4_CF		BIT(12)	/* Control Frame */
+#define FIFO_CFG4_PF		BIT(13)	/* Pause Frame */
+#define FIFO_CFG4_UO		BIT(14)	/* Unsupported Opcode */
+#define FIFO_CFG4_VT		BIT(15)	/* VLAN tag detected */
+#define FIFO_CFG4_FT		BIT(16)	/* Frame Truncated */
+#define FIFO_CFG4_UC		BIT(17)	/* Unicast Packet */
+
+#define FIFO_CFG5_DE		BIT(0)	/* Drop Event */
+#define FIFO_CFG5_DV		BIT(1)	/* RX_DV Event */
+#define FIFO_CFG5_FC		BIT(2)	/* False Carrier */
+#define FIFO_CFG5_CE		BIT(3)	/* Code Error */
+#define FIFO_CFG5_LM		BIT(4)	/* Length Mismatch */
+#define FIFO_CFG5_LO		BIT(5)	/* Length Out of Range */
+#define FIFO_CFG5_OK		BIT(6)	/* Packet is OK */
+#define FIFO_CFG5_MC		BIT(7)	/* Multicast Packet */
+#define FIFO_CFG5_BC		BIT(8)	/* Broadcast Packet */
+#define FIFO_CFG5_DR		BIT(9)	/* Dribble */
+#define FIFO_CFG5_CF		BIT(10)	/* Control Frame */
+#define FIFO_CFG5_PF		BIT(11)	/* Pause Frame */
+#define FIFO_CFG5_UO		BIT(12)	/* Unsupported Opcode */
+#define FIFO_CFG5_VT		BIT(13)	/* VLAN tag detected */
+#define FIFO_CFG5_LE		BIT(14)	/* Long Event */
+#define FIFO_CFG5_FT		BIT(15)	/* Frame Truncated */
+#define FIFO_CFG5_16		BIT(16)	/* unknown */
+#define FIFO_CFG5_17		BIT(17)	/* unknown */
+#define FIFO_CFG5_SF		BIT(18)	/* Short Frame */
+#define FIFO_CFG5_BM		BIT(19)	/* Byte Mode */
+
+#define AG71XX_INT_TX_PS	BIT(0)
+#define AG71XX_INT_TX_UR	BIT(1)
+#define AG71XX_INT_TX_BE	BIT(3)
+#define AG71XX_INT_RX_PR	BIT(4)
+#define AG71XX_INT_RX_OF	BIT(6)
+#define AG71XX_INT_RX_BE	BIT(7)
+
+#define MAC_IFCTL_SPEED		BIT(16)
+
+#define MII_CFG_CLK_DIV_4	0
+#define MII_CFG_CLK_DIV_6	2
+#define MII_CFG_CLK_DIV_8	3
+#define MII_CFG_CLK_DIV_10	4
+#define MII_CFG_CLK_DIV_14	5
+#define MII_CFG_CLK_DIV_20	6
+#define MII_CFG_CLK_DIV_28	7
+#define MII_CFG_RESET		BIT(31)
+
+#define MII_CMD_WRITE		0x0
+#define MII_CMD_READ		0x1
+#define MII_ADDR_SHIFT		8
+#define MII_IND_BUSY		BIT(0)
+#define MII_IND_INVALID		BIT(2)
+
+#define TX_CTRL_TXE		BIT(0)	/* Tx Enable */
+
+#define TX_STATUS_PS		BIT(0)	/* Packet Sent */
+#define TX_STATUS_UR		BIT(1)	/* Tx Underrun */
+#define TX_STATUS_BE		BIT(3)	/* Bus Error */
+
+#define RX_CTRL_RXE		BIT(0)	/* Rx Enable */
+
+#define RX_STATUS_PR		BIT(0)	/* Packet Received */
+#define RX_STATUS_OF		BIT(2)	/* Rx Overflow */
+#define RX_STATUS_BE		BIT(3)	/* Bus Error */
+
+#define MII_CTRL_IF_MASK	3
+#define MII_CTRL_SPEED_SHIFT	4
+#define MII_CTRL_SPEED_MASK	3
+#define MII_CTRL_SPEED_10	0
+#define MII_CTRL_SPEED_100	1
+#define MII_CTRL_SPEED_1000	2
+
+static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
+{
+	__raw_writel(value, ag->mac_base + reg);
+	/* flush write */
+	(void) __raw_readl(ag->mac_base + reg);
+}
+
+static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
+{
+	return __raw_readl(ag->mac_base + reg);
+}
+
+static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
+{
+	uint32_t r;
+
+	r = ag->mac_base + reg;
+	__raw_writel(__raw_readl(r) | mask, r);
+	/* flush write */
+	(void)__raw_readl(r);
+}
+
+static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
+{
+	uint32_t r;
+
+	r = ag->mac_base + reg;
+	__raw_writel(__raw_readl(r) & ~mask, r);
+	/* flush write */
+	(void) __raw_readl(r);
+}
+
+static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
+{
+	ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
+}
+
+static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
+{
+	ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
+}
+
+static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value)
+{
+	__raw_writel(value, ag->mii_ctrl);
+
+	/* flush write */
+	__raw_readl(ag->mii_ctrl);
+}
+
+static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag)
+{
+	return __raw_readl(ag->mii_ctrl);
+}
+
+static void inline ag71xx_mii_ctrl_set_if(struct ag71xx *ag,
+					  unsigned int mii_if)
+{
+	u32 t;
+
+	t = ag71xx_mii_ctrl_rr(ag);
+	t &= ~(MII_CTRL_IF_MASK);
+	t |= (mii_if & MII_CTRL_IF_MASK);
+	ag71xx_mii_ctrl_wr(ag, t);
+}
+
+static void inline ag71xx_mii_ctrl_set_speed(struct ag71xx *ag,
+					     unsigned int speed)
+{
+	u32 t;
+
+	t = ag71xx_mii_ctrl_rr(ag);
+	t &= ~(MII_CTRL_SPEED_MASK << MII_CTRL_SPEED_SHIFT);
+	t |= (speed & MII_CTRL_SPEED_MASK) << MII_CTRL_SPEED_SHIFT;
+	ag71xx_mii_ctrl_wr(ag, t);
+}
+
+#ifdef CONFIG_AG71XX_AR8216_SUPPORT
+void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb);
+int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
+				int pktlen);
+static inline int ag71xx_has_ar8216(struct ag71xx *ag)
+{
+	return ag71xx_get_pdata(ag)->has_ar8216;
+}
+#else
+static inline void ag71xx_add_ar8216_header(struct ag71xx *ag,
+					   struct sk_buff *skb)
+{
+}
+
+static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag,
+					      struct sk_buff *skb,
+					      int pktlen)
+{
+	return 0;
+}
+static inline int ag71xx_has_ar8216(struct ag71xx *ag)
+{
+	return 0;
+}
+#endif
+
+#endif /* _AG71XX_H */
diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h
new file mode 100644
index 0000000000..f0567dd64a
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h
@@ -0,0 +1,188 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef RTL8366_MII_H
+#define RTL8366_MII_H
+
+#define	MII_CONTROL_REG		    0
+#define	MII_STATUS_REG	    	1
+#define	MII_PHY_ID0		        2
+#define	MII_PHY_ID1		        3
+#define	MII_LOCAL_CAP	    	4
+#define	MII_REMOTE_CAP		    5
+#define	MII_EXT_AUTONEG		    6
+#define	MII_LOCAL_NEXT_PAGE	    7
+#define	MII_REMOTE_NEXT_PAGE	8
+#define	MII_GIGA_CONTROL	    9
+#define	MII_GIGA_STATUS		    10
+#define	MII_EXT_STATUS_REG	    15
+
+/* Control register */
+#define	MII_CONTROL_1000MBPS	6
+#define	MII_CONTROL_COLL_TEST	7
+#define	MII_CONTROL_FULLDUPLEX	8
+#define	MII_CONTROL_RENEG	    9
+#define	MII_CONTROL_ISOLATE	    10
+#define	MII_CONTROL_POWERDOWN	11
+#define	MII_CONTROL_AUTONEG	    12
+#define	MII_CONTROL_100MBPS	    13
+#define	MII_CONTROL_LOOPBACK	14
+#define	MII_CONTROL_RESET	    15
+
+/* Status/Extended status register */
+/* Basic status */
+#define	MII_STATUS_CAPABILITY	0
+#define	MII_STATUS_JABBER	    1
+#define	MII_STATUS_LINK_UP	    2
+#define	MII_STATUS_AUTONEG_ABLE	3
+#define	MII_STATUS_REMOTE_FAULT	4
+#define	MII_STATUS_AUTONEG_DONE	5
+#define	MII_STATUS_NO_PREAMBLE	6
+#define	MII_STATUS_RESERVED	    7
+#define	MII_STATUS_EXTENDED	    8
+#define	MII_STATUS_100_T2_HALF	9
+#define	MII_STATUS_100_T2_FULL	10
+#define	MII_STATUS_10_TX_HALF	11
+#define	MII_STATUS_10_TX_FULL	12
+#define	MII_STATUS_100_TX_HALF	13
+#define	MII_STATUS_100_TX_FULL	14
+#define	MII_STATUS_100_T4	    15
+
+#define	MII_GIGA_CONTROL_HALF	8
+#define	MII_GIGA_CONTROL_FULL	9
+#define	MII_GIGA_STATUS_HALF	10
+#define	MII_GIGA_STATUS_FULL	11
+
+/* Extended status */
+#define	MII_STATUS_1000_T_HALF	12
+#define	MII_STATUS_1000_T_FULL	13
+#define	MII_STATUS_1000_X_HALF	14
+#define	MII_STATUS_1000_X_FULL	15
+
+/* Local/Remmote capability register */
+#define	MII_CAP_10BASE_TX	    5
+#define	MII_CAP_10BASE_TX_FULL	6
+#define	MII_CAP_100BASE_TX	    7
+#define	MII_CAP_100BASE_TX_FULL	8
+#define	MII_CAP_100BASE_T4	    9
+#define	MII_CAP_SYMM_PAUSE	    10
+#define	MII_CAP_ASYMM_PAUSE	    11
+#define	MII_CAP_RESERVED	    12
+#define	MII_CAP_REMOTE_FAULT	13
+#define	MII_CAP_ACKNOWLEDGE	    14
+#define	MII_CAP_NEXT_PAGE	    15
+#define	MII_CAP_IEEE_802_3	    0x0001
+
+#define	MII_LINK_MODE_MASK	    0x1f
+
+#define REALTEK_RTL8366_CHIP_ID0    0x001C
+#define REALTEK_RTL8366_CHIP_ID1    0xC940
+#define REALTEK_RTL8366_CHIP_ID1_MP 0xC960
+
+#define REALTEK_MIN_PORT_ID     0
+#define REALTEK_MAX_PORT_ID     5
+#define REALTEK_MIN_PHY_ID      REALTEK_MIN_PORT_ID
+#define REALTEK_MAX_PHY_ID      4
+#define REALTEK_CPU_PORT_ID     REALTEK_MAX_PORT_ID
+#define REALTEK_PHY_PORT_MASK   ((1<<(REALTEK_MAX_PHY_ID+1)) - (1<<REALTEK_MIN_PHY_ID))
+#define REALTEK_CPU_PORT_MASK   (1<<REALTEK_CPU_PORT_ID)
+#define REALTEK_ALL_PORT_MASK   (REALTEK_PHY_PORT_MASK | REALTEK_CPU_PORT_MASK)
+
+/* port ability */
+#define RTL8366S_PORT_ABILITY_BASE			0x0011
+
+/* port vlan control register */
+#define RTL8366S_PORT_VLAN_CTRL_BASE			0x0058
+
+/* port linking status */
+#define RTL8366S_PORT_LINK_STATUS_BASE			0x0060
+#define RTL8366S_PORT_STATUS_SPEED_BIT			0
+#define RTL8366S_PORT_STATUS_SPEED_MSK			0x0003
+#define RTL8366S_PORT_STATUS_DUPLEX_BIT			2
+#define RTL8366S_PORT_STATUS_DUPLEX_MSK			0x0004
+#define RTL8366S_PORT_STATUS_LINK_BIT			4
+#define RTL8366S_PORT_STATUS_LINK_MSK			0x0010
+#define RTL8366S_PORT_STATUS_TXPAUSE_BIT		5
+#define RTL8366S_PORT_STATUS_TXPAUSE_MSK		0x0020
+#define RTL8366S_PORT_STATUS_RXPAUSE_BIT		6
+#define RTL8366S_PORT_STATUS_RXPAUSE_MSK		0x0040
+#define RTL8366S_PORT_STATUS_AN_BIT			7
+#define RTL8366S_PORT_STATUS_AN_MSK			0x0080
+
+/* internal control */
+#define RTL8366S_RESET_CONTROL_REG			0x0100
+#define RTL8366S_RESET_QUEUE_BIT			2
+
+#define RTL8366S_CHIP_ID_REG				0x0105
+
+/* MAC control */
+#define RTL8366S_MAC_FORCE_CTRL0_REG			0x0F04
+#define RTL8366S_MAC_FORCE_CTRL1_REG			0x0F05
+
+
+/* PHY registers control */
+#define RTL8366S_PHY_ACCESS_CTRL_REG			0x8028
+#define RTL8366S_PHY_ACCESS_DATA_REG			0x8029
+
+#define RTL8366S_PHY_CTRL_READ				1
+#define RTL8366S_PHY_CTRL_WRITE				0
+
+#define RTL8366S_PHY_REG_MASK				0x1F
+#define RTL8366S_PHY_PAGE_OFFSET			5
+#define RTL8366S_PHY_PAGE_MASK				(0x7<<5)
+#define RTL8366S_PHY_NO_OFFSET				9
+#define RTL8366S_PHY_NO_MASK				(0x1F<<9)
+
+#define RTL8366S_PHY_NO_MAX				4
+#define RTL8366S_PHY_PAGE_MAX				7
+#define RTL8366S_PHY_ADDR_MAX				31
+
+/* cpu port control reg */
+#define RTL8366S_CPU_CTRL_REG				0x004F
+#define RTL8366S_CPU_DRP_BIT				14
+#define RTL8366S_CPU_DRP_MSK				0x4000
+#define RTL8366S_CPU_INSTAG_BIT				15
+#define RTL8366S_CPU_INSTAG_MSK				0x8000
+
+/* LED registers*/
+#define RTL8366S_LED_BLINK_REG				0x420
+#define RTL8366S_LED_BLINKRATE_BIT			0
+#define RTL8366S_LED_BLINKRATE_MSK			0x0007
+#define RTL8366S_LED_INDICATED_CONF_REG			0x421
+#define RTL8366S_LED_0_1_FORCE_REG			0x422
+#define RTL8366S_LED_2_3_FORCE_REG			0x423
+#define RTL8366S_LEDCONF_LEDFORCE			0x1F
+#define RTL8366S_LED_GROUP_MAX				4
+
+#define RTL8366S_GREEN_FEATURE_REG			0x000A
+#define RTL8366S_GREEN_FEATURE_TX_BIT			3
+#define RTL8366S_GREEN_FEATURE_TX_MSK			0x0008
+#define RTL8366S_GREEN_FEATURE_RX_BIT			4
+#define RTL8366S_GREEN_FEATURE_RX_MSK			0x0010
+
+#define	RTL8366S_MODEL_ID_REG	0x5C
+#define	RTL8366S_REV_ID_REG	0x5D
+#define	RTL8366S_MODEL_8366SR	0x6027
+#define	RTL8366S_MODEL_8366RB	0x5937
+
+#endif
diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c
new file mode 100644
index 0000000000..e3c5316543
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c
@@ -0,0 +1,786 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+#include <net.h>
+#include <netdev.h>
+#include <miiphy.h>
+#include MII_GPIOINCLUDE
+
+#include "rtl8366.h"
+
+#ifdef DEBUG_RTL8366
+	#define DBG(fmt,args...)	printf (fmt ,##args)
+#else
+	#define DBG(fmt,args...)
+#endif
+
+
+//-------------------------------------------------------------------
+// Soft SMI functions
+//-------------------------------------------------------------------
+
+#define DELAY 2
+
+static void smi_init(void)
+{
+    MII_SDAINPUT;
+    MII_SCKINPUT;
+
+	MII_SETSDA(1);
+	MII_SETSCK(1);
+
+    udelay(20);
+}
+
+static void smi_start(void)
+{
+/*
+ * rtl8366 chip needs a extra clock with
+ * SDA high before start condition
+ */
+
+    /* set gpio pins output */
+    MII_SDAOUTPUT;
+    MII_SCKOUTPUT;
+    udelay(DELAY);
+
+    /* set initial state: SCK:0, SDA:1 */
+    MII_SETSCK(0);
+    MII_SETSDA(1);
+    udelay(DELAY);
+
+    /* toggle clock */
+    MII_SETSCK(1);
+    udelay(DELAY);
+    MII_SETSCK(0);
+    udelay(DELAY);
+
+    /* start condition */
+    MII_SETSCK(1);
+    udelay(DELAY);
+    MII_SETSDA(0);
+    udelay(DELAY);
+    MII_SETSCK(0);
+    udelay(DELAY);
+    MII_SETSDA(1);
+}
+
+static void smi_stop(void)
+{
+/*
+ * rtl8366 chip needs a extra clock with
+ * SDA high after stop condition
+ */
+
+    /* stop condition */
+	udelay(DELAY);
+    MII_SETSDA(0);
+    MII_SETSCK(1);
+    udelay(DELAY);
+    MII_SETSDA(1);
+    udelay(DELAY);
+    MII_SETSCK(1);
+    udelay(DELAY);
+    MII_SETSCK(0);
+    udelay(DELAY);
+
+    /* toggle clock */
+    MII_SETSCK(1);
+    udelay(DELAY);
+    MII_SETSCK(0);
+    udelay(DELAY);
+    MII_SETSCK(1);
+
+    /* set gpio pins input */
+    MII_SDAINPUT;
+    MII_SCKINPUT;
+}
+
+static void smi_writeBits(uint32_t data, uint8_t length)
+{
+    uint8_t test;
+
+    for( ; length > 0; length--) {
+        udelay(DELAY);
+
+        /* output data */
+        test = (((data & (1 << (length - 1))) != 0) ? 1 : 0);
+        MII_SETSDA(test);
+        udelay(DELAY);
+
+        /* toogle clock */
+        MII_SETSCK(1);
+        udelay(DELAY);
+        MII_SETSCK(0);
+    }
+}
+
+static uint32_t smi_readBits(uint8_t length)
+{
+    uint32_t ret;
+
+    MII_SDAINPUT;
+
+    for(ret = 0 ; length > 0; length--) {
+        udelay(DELAY);
+
+        ret <<= 1;
+
+        /* toogle clock */
+        MII_SETSCK(1);
+        udelay(DELAY);
+        ret |= MII_GETSDA;
+        MII_SETSCK(0);
+    }
+
+    MII_SDAOUTPUT;
+
+    return ret;
+}
+
+static int smi_waitAck(void)
+{
+    uint32_t retry = 0;
+
+	while (smi_readBits(1)) {
+		if (retry++ == 5)
+			return -1;
+	}
+
+	return 0;
+
+}
+
+static int smi_read(uint32_t reg, uint32_t *data)
+{
+    uint32_t rawData;
+
+    /* send start condition */
+    smi_start();
+    /* send CTRL1 code: 0b1010*/
+    smi_writeBits(0x0a, 4);
+    /* send CTRL2 code: 0b100 */
+    smi_writeBits(0x04, 3);
+    /* send READ command */
+    smi_writeBits(0x01, 1);
+
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+
+    /* send address low */
+    smi_writeBits(reg & 0xFF, 8);
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+    /* send address high */
+    smi_writeBits((reg & 0xFF00) >> 8, 8);
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+
+    /* read data low */
+    rawData = (smi_readBits(8) & 0xFF);
+    /* send ACK */
+    smi_writeBits(0, 1);
+    /* read data high */
+    rawData |= (smi_readBits(8) & 0xFF) << 8;
+    /* send NACK */
+    smi_writeBits(1, 1);
+
+    /* send stop condition */
+    smi_stop();
+
+    if (data)
+        *data = rawData;
+
+    return 0;
+}
+
+static int smi_write(uint32_t reg, uint32_t data)
+{
+    /* send start condition */
+    smi_start();
+    /* send CTRL1 code: 0b1010*/
+    smi_writeBits(0x0a, 4);
+    /* send CTRL2 code: 0b100 */
+    smi_writeBits(0x04, 3);
+    /* send WRITE command */
+    smi_writeBits(0x00, 1);
+
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+
+    /* send address low */
+    smi_writeBits(reg & 0xFF, 8);
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+    /* send address high */
+    smi_writeBits((reg & 0xFF00) >> 8, 8);
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+
+    /* send data low */
+    smi_writeBits(data & 0xFF, 8);
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+    /* send data high */
+    smi_writeBits((data & 0xFF00) >> 8, 8);
+    /* wait for ACK */
+    if (smi_waitAck())
+        return -1;
+
+    /* send stop condition */
+    smi_stop();
+
+    return 0;
+}
+
+
+//-------------------------------------------------------------------
+// Switch register read / write functions
+//-------------------------------------------------------------------
+static int rtl8366_readRegister(uint32_t reg, uint16_t *data)
+{
+    uint32_t regData;
+
+    DBG("rtl8366: read register=%#04x, data=", reg);
+
+    if (smi_read(reg, &regData)) {
+        printf("\nrtl8366 smi read failed!\n");
+        return -1;
+    }
+
+    if (data)
+        *data = regData;
+
+    DBG("%#04x\n", regData);
+
+    return 0;
+}
+
+static int rtl8366_writeRegister(uint32_t reg, uint16_t data)
+{
+    DBG("rtl8366: write register=%#04x, data=%#04x\n", reg, data);
+
+    if (smi_write(reg, data)) {
+        printf("rtl8366 smi write failed!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int rtl8366_setRegisterBit(uint32_t reg, uint32_t bitNum, uint32_t value)
+{
+    uint16_t regData;
+
+    if (bitNum >= 16)
+        return -1;
+
+    if (rtl8366_readRegister(reg, &regData))
+        return -1;
+
+    if (value)
+        regData |= (1 << bitNum);
+    else
+        regData &= ~(1 << bitNum);
+
+    if (rtl8366_writeRegister(reg, regData))
+        return -1;
+
+    return 0;
+}
+
+//-------------------------------------------------------------------
+// MII PHY read / write functions
+//-------------------------------------------------------------------
+static int rtl8366_getPhyReg(uint32_t phyNum, uint32_t reg, uint16_t *data)
+{
+    uint16_t phyAddr, regData;
+
+    if (phyNum > RTL8366S_PHY_NO_MAX) {
+		printf("rtl8366s: invalid phy number!\n");
+		return -1;
+	}
+
+    if (phyNum > RTL8366S_PHY_ADDR_MAX) {
+		printf("rtl8366s: invalid phy register number!\n");
+		return -1;
+	}
+
+	if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG,
+                           RTL8366S_PHY_CTRL_READ))
+        return -1;
+
+    phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET))
+                     | (reg & RTL8366S_PHY_REG_MASK);
+    if (rtl8366_writeRegister(phyAddr, 0))
+        return -1;
+
+    if (rtl8366_readRegister(RTL8366S_PHY_ACCESS_DATA_REG, &regData))
+        return -1;
+
+    if (data)
+        *data = regData;
+
+    return 0;
+}
+
+static int rtl8366_setPhyReg(uint32_t phyNum, uint32_t reg, uint16_t data)
+{
+    uint16_t phyAddr;
+
+    if (phyNum > RTL8366S_PHY_NO_MAX) {
+		printf("rtl8366s: invalid phy number!\n");
+		return -1;
+	}
+
+    if (phyNum > RTL8366S_PHY_ADDR_MAX) {
+		printf("rtl8366s: invalid phy register number!\n");
+		return -1;
+	}
+
+	if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG,
+                           RTL8366S_PHY_CTRL_WRITE))
+        return -1;
+
+    phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET))
+                     | (reg & RTL8366S_PHY_REG_MASK);
+    if (rtl8366_writeRegister(phyAddr, data))
+        return -1;
+
+    return 0;
+}
+
+static int rtl8366_miiread(char *devname, uchar phy_adr, uchar reg, ushort *data)
+{
+    uint16_t regData;
+
+    DBG("rtl8366_miiread: devname=%s, addr=%#02x, reg=%#02x\n",
+          devname, phy_adr, reg);
+
+    if (strcmp(devname, RTL8366_DEVNAME) != 0)
+        return -1;
+
+    if (rtl8366_getPhyReg(phy_adr, reg, &regData)) {
+        printf("rtl8366_miiread: write failed!\n");
+        return -1;
+    }
+
+    if (data)
+        *data = regData;
+
+    return 0;
+}
+
+static int rtl8366_miiwrite(char *devname, uchar phy_adr, uchar reg, ushort data)
+{
+    DBG("rtl8366_miiwrite: devname=%s, addr=%#02x, reg=%#02x, data=%#04x\n",
+          devname, phy_adr, reg, data);
+
+    if (strcmp(devname, RTL8366_DEVNAME) != 0)
+        return -1;
+
+    if (rtl8366_setPhyReg(phy_adr, reg, data)) {
+        printf("rtl8366_miiwrite: write failed!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+int rtl8366_mii_register(bd_t *bis)
+{
+    miiphy_register(strdup(RTL8366_DEVNAME), rtl8366_miiread,
+			rtl8366_miiwrite);
+
+    return 0;
+}
+
+
+//-------------------------------------------------------------------
+// Switch management functions
+//-------------------------------------------------------------------
+
+int rtl8366s_setGreenFeature(uint32_t tx, uint32_t rx)
+{
+    if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG,
+                               RTL8366S_GREEN_FEATURE_TX_BIT, tx))
+        return -1;
+
+    if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG,
+                               RTL8366S_GREEN_FEATURE_RX_BIT, rx))
+        return -1;
+
+    return 0;
+}
+
+int rtl8366s_setPowerSaving(uint32_t phyNum, uint32_t enabled)
+{
+    uint16_t regData;
+
+    if (phyNum > RTL8366S_PHY_NO_MAX)
+        return -1;
+
+    if (rtl8366_getPhyReg(phyNum, 12, &regData))
+        return -1;
+
+    if (enabled)
+        regData |= (1 << 12);
+    else
+        regData &= ~(1 << 12);
+
+    if (rtl8366_setPhyReg(phyNum, 12, regData))
+        return -1;
+
+    return 0;
+}
+
+int rtl8366s_setGreenEthernet(uint32_t greenFeature, uint32_t powerSaving)
+{
+    uint32_t phyNum, i;
+    uint16_t regData;
+
+	const uint16_t greenSettings[][2] =
+	{
+		{0xBE5B,0x3500},
+		{0xBE5C,0xB975},
+		{0xBE5D,0xB9B9},
+		{0xBE77,0xA500},
+		{0xBE78,0x5A78},
+		{0xBE79,0x6478}
+	};
+
+    if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, &regData))
+        return -1;
+
+	switch (regData)
+	{
+		case 0x0000:
+			for (i = 0; i < 6; i++) {
+				if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE))
+					return -1;
+				if (rtl8366_writeRegister(greenSettings[i][0], greenSettings[i][1]))
+					return -1;
+			}
+			break;
+
+		case RTL8366S_MODEL_8366SR:
+			if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE))
+				return -1;
+			if (rtl8366_writeRegister(greenSettings[0][0], greenSettings[0][1]))
+				return -1;
+			break;
+
+		default:
+			printf("rtl8366s_initChip: unsupported chip found!\n");
+			return -1;
+	}
+
+    if (rtl8366s_setGreenFeature(greenFeature, powerSaving))
+        return -1;
+
+    for (phyNum = 0; phyNum <= RTL8366S_PHY_NO_MAX; phyNum++) {
+        if (rtl8366s_setPowerSaving(phyNum, powerSaving))
+            return -1;
+    }
+
+    return 0;
+}
+
+int rtl8366s_setCPUPortMask(uint8_t port, uint32_t enabled)
+{
+	if(port >= 6){
+		printf("rtl8366s_setCPUPortMask: invalid port number\n");
+		return -1;
+	}
+
+	return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, port, enabled);
+}
+
+int rtl8366s_setCPUDisableInsTag(uint32_t enable)
+{
+	return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG,
+		RTL8366S_CPU_INSTAG_BIT, enable);
+}
+
+int rtl8366s_setCPUDropUnda(uint32_t enable)
+{
+	return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG,
+		RTL8366S_CPU_DRP_BIT, enable);
+}
+
+int rtl8366s_setCPUPort(uint8_t port, uint32_t noTag, uint32_t dropUnda)
+{
+	uint32_t i;
+
+	if(port >= 6){
+		printf("rtl8366s_setCPUPort: invalid port number\n");
+		return -1;
+	}
+
+	/* reset register */
+	for(i = 0; i < 6; i++)
+	{
+		if(rtl8366s_setCPUPortMask(i, 0)){
+			printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n");
+			return -1;
+		}
+	}
+
+	if(rtl8366s_setCPUPortMask(port, 1)){
+		printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n");
+		return -1;
+	}
+
+	if(rtl8366s_setCPUDisableInsTag(noTag)){
+		printf("rtl8366s_setCPUPort: rtl8366s_setCPUDisableInsTag fail\n");
+		return -1;
+	}
+
+	if(rtl8366s_setCPUDropUnda(dropUnda)){
+		printf("rtl8366s_setCPUPort: rtl8366s_setCPUDropUnda fail\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int rtl8366s_setLedConfig(uint32_t ledNum, uint8_t config)
+{
+    uint16_t regData;
+
+	if(ledNum >= RTL8366S_LED_GROUP_MAX) {
+		DBG("rtl8366s_setLedConfig: invalid led group\n");
+		return -1;
+	}
+
+    if(config > RTL8366S_LEDCONF_LEDFORCE) {
+		DBG("rtl8366s_setLedConfig: invalid led config\n");
+		return -1;
+	}
+
+	if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, &regData)) {
+        printf("rtl8366s_setLedConfig: failed to get led register!\n");
+        return -1;
+	}
+
+	regData &= ~(0xF << (ledNum * 4));
+	regData |= config << (ledNum * 4);
+
+	if (rtl8366_writeRegister(RTL8366S_LED_INDICATED_CONF_REG, regData)) {
+        printf("rtl8366s_setLedConfig: failed to set led register!\n");
+        return -1;
+	}
+
+	return 0;
+}
+
+int rtl8366s_getLedConfig(uint32_t ledNum, uint8_t *config)
+{
+    uint16_t regData;
+
+	if(ledNum >= RTL8366S_LED_GROUP_MAX) {
+		DBG("rtl8366s_getLedConfig: invalid led group\n");
+		return -1;
+	}
+
+    if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, &regData)) {
+        printf("rtl8366s_getLedConfig: failed to get led register!\n");
+        return -1;
+	}
+
+	if (config)
+        *config = (regData >> (ledNum * 4)) & 0xF;
+
+    return 0;
+}
+
+int rtl8366s_setLedForceValue(uint32_t group0, uint32_t group1,
+                              uint32_t group2, uint32_t group3)
+{
+    uint16_t regData;
+
+    regData = (group0 & 0x3F) | ((group1 & 0x3F) << 6);
+	if (rtl8366_writeRegister(RTL8366S_LED_0_1_FORCE_REG, regData)) {
+        printf("rtl8366s_setLedForceValue: failed to set led register!\n");
+        return -1;
+	}
+
+    regData = (group2 & 0x3F) | ((group3 & 0x3F) << 6);
+	if (rtl8366_writeRegister(RTL8366S_LED_2_3_FORCE_REG, regData)) {
+        printf("rtl8366s_setLedForceValue: failed to set led register!\n");
+        return -1;
+	}
+
+	return 0;
+}
+
+int rtl8366s_initChip(void)
+{
+    uint32_t ledGroup, i = 0;
+    uint16_t regData;
+    uint8_t ledData[RTL8366S_LED_GROUP_MAX];
+	const uint16_t (*chipData)[2];
+
+	const uint16_t chipB[][2] =
+	{
+		{0x0000,	0x0038},{0x8100,	0x1B37},{0xBE2E,	0x7B9F},{0xBE2B,	0xA4C8},
+		{0xBE74,	0xAD14},{0xBE2C,	0xDC00},{0xBE69,	0xD20F},{0xBE3B,	0xB414},
+		{0xBE24,	0x0000},{0xBE23,	0x00A1},{0xBE22,	0x0008},{0xBE21,	0x0120},
+		{0xBE20,	0x1000},{0xBE24,	0x0800},{0xBE24,	0x0000},{0xBE24,	0xF000},
+		{0xBE23,	0xDF01},{0xBE22,	0xDF20},{0xBE21,	0x101A},{0xBE20,	0xA0FF},
+		{0xBE24,	0xF800},{0xBE24,	0xF000},{0x0242,	0x02BF},{0x0245,	0x02BF},
+		{0x0248,	0x02BF},{0x024B,	0x02BF},{0x024E,	0x02BF},{0x0251,	0x02BF},
+		{0x0230,	0x0A32},{0x0233,	0x0A32},{0x0236,	0x0A32},{0x0239,	0x0A32},
+		{0x023C,	0x0A32},{0x023F,	0x0A32},{0x0254,	0x0A3F},{0x0255,	0x0064},
+		{0x0256,	0x0A3F},{0x0257,	0x0064},{0x0258,	0x0A3F},{0x0259,	0x0064},
+		{0x025A,	0x0A3F},{0x025B,	0x0064},{0x025C,	0x0A3F},{0x025D,	0x0064},
+		{0x025E,	0x0A3F},{0x025F,	0x0064},{0x0260,	0x0178},{0x0261,	0x01F4},
+		{0x0262,	0x0320},{0x0263,	0x0014},{0x021D,	0x9249},{0x021E,	0x0000},
+		{0x0100,	0x0004},{0xBE4A,	0xA0B4},{0xBE40,	0x9C00},{0xBE41,	0x501D},
+		{0xBE48,	0x3602},{0xBE47,	0x8051},{0xBE4C,	0x6465},{0x8000,	0x1F00},
+		{0x8001,	0x000C},{0x8008,	0x0000},{0x8007,	0x0000},{0x800C,	0x00A5},
+		{0x8101,	0x02BC},{0xBE53,	0x0005},{0x8E45,	0xAFE8},{0x8013,	0x0005},
+		{0xBE4B,	0x6700},{0x800B,	0x7000},{0xBE09,	0x0E00},
+		{0xFFFF, 0xABCD}
+	};
+
+    const uint16_t chipDefault[][2] =
+    {
+        {0x0242, 0x02BF},{0x0245, 0x02BF},{0x0248, 0x02BF},{0x024B, 0x02BF},
+		{0x024E, 0x02BF},{0x0251, 0x02BF},
+		{0x0254, 0x0A3F},{0x0256, 0x0A3F},{0x0258, 0x0A3F},{0x025A, 0x0A3F},
+		{0x025C, 0x0A3F},{0x025E, 0x0A3F},
+		{0x0263, 0x007C},{0x0100, 0x0004},
+		{0xBE5B, 0x3500},{0x800E, 0x200F},{0xBE1D, 0x0F00},{0x8001, 0x5011},
+		{0x800A, 0xA2F4},{0x800B, 0x17A3},{0xBE4B, 0x17A3},{0xBE41, 0x5011},
+		{0xBE17, 0x2100},{0x8000, 0x8304},{0xBE40, 0x8304},{0xBE4A, 0xA2F4},
+		{0x800C, 0xA8D5},{0x8014, 0x5500},{0x8015, 0x0004},{0xBE4C, 0xA8D5},
+		{0xBE59, 0x0008},{0xBE09, 0x0E00},{0xBE36, 0x1036},{0xBE37, 0x1036},
+		{0x800D, 0x00FF},{0xBE4D, 0x00FF},
+		{0xFFFF, 0xABCD}
+    };
+
+	DBG("rtl8366s_initChip\n");
+
+    /* save current led config and set to led force */
+    for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) {
+        if (rtl8366s_getLedConfig(ledGroup, &ledData[ledGroup]))
+            return -1;
+
+        if (rtl8366s_setLedConfig(ledGroup, RTL8366S_LEDCONF_LEDFORCE))
+            return -1;
+    }
+
+    if (rtl8366s_setLedForceValue(0,0,0,0))
+        return -1;
+
+    if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, &regData))
+        return -1;
+
+	switch (regData)
+	{
+		case 0x0000:
+			chipData = chipB;
+			break;
+
+		case RTL8366S_MODEL_8366SR:
+			chipData = chipDefault;
+			break;
+
+		default:
+			printf("rtl8366s_initChip: unsupported chip found!\n");
+			return -1;
+	}
+
+    DBG("rtl8366s_initChip: found %x chip\n", regData);
+
+    while ((chipData[i][0] != 0xFFFF) && (chipData[i][1] != 0xABCD)) {
+
+        /* phy settings*/
+        if ((chipData[i][0] & 0xBE00) == 0xBE00) {
+            if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG,
+                                      RTL8366S_PHY_CTRL_WRITE))
+                return -1;
+        }
+
+        if (rtl8366_writeRegister(chipData[i][0], chipData[i][1]))
+            return -1;
+
+        i++;
+    }
+
+    /* chip needs some time */
+    udelay(100 * 1000);
+
+    /* restore led config */
+    for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) {
+        if (rtl8366s_setLedConfig(ledGroup, ledData[ledGroup]))
+            return -1;
+    }
+
+    return 0;
+}
+
+int rtl8366s_initialize(void)
+{
+	uint16_t regData;
+
+    DBG("rtl8366s_initialize: start setup\n");
+
+    smi_init();
+
+	rtl8366_readRegister(RTL8366S_CHIP_ID_REG, &regData);
+	DBG("Realtek 8366SR switch ID %#04x\n", regData);
+
+	if (regData != 0x8366) {
+		printf("rtl8366s_initialize: found unsupported switch\n");
+		return -1;
+	}
+
+    if (rtl8366s_initChip()) {
+        printf("rtl8366s_initialize: init chip failed\n");
+        return -1;
+    }
+
+	if (rtl8366s_setGreenEthernet(1, 1)) {
+       printf("rtl8366s_initialize: set green ethernet failed\n");
+       return -1;
+   }
+
+   	/* Set port 5 noTag and don't dropUnda */
+	if (rtl8366s_setCPUPort(5, 1, 0)) {
+		printf("rtl8366s_initialize: set CPU port failed\n");
+		return -1;
+	}
+
+    return 0;
+}
diff --git a/package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c b/package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c
new file mode 100644
index 0000000000..bbe27b16ef
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c
@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <asm/ar71xx.h>
+
+/*-----------------------------------------------------------------------
+ * Definitions
+ */
+
+#ifdef DEBUG_SPI
+#define PRINTD(fmt,args...)	printf (fmt ,##args)
+#else
+#define PRINTD(fmt,args...)
+#endif
+
+struct ar71xx_spi_slave {
+	struct spi_slave slave;
+	unsigned int mode;
+};
+
+static inline struct ar71xx_spi_slave *to_ar71xx_spi(struct spi_slave *slave)
+{
+	return container_of(slave, struct ar71xx_spi_slave, slave);
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Initialization
+ */
+ 
+void spi_init()
+{
+	PRINTD("ar71xx_spi: spi_init");
+
+	// Init SPI Hardware, disable remap, set clock
+	__raw_writel(0x43, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_CTRL));
+	
+	PRINTD(" ---> out\n");
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+		unsigned int max_hz, unsigned int mode)
+{
+	struct ar71xx_spi_slave *ss;
+
+	PRINTD("ar71xx_spi: spi_setup_slave");
+	
+	if ((bus != 0) || (cs > 2))
+		return NULL;
+
+	ss = malloc(sizeof(struct ar71xx_spi_slave));
+	if (!ss)
+		return NULL;
+
+	ss->slave.bus = bus;
+	ss->slave.cs = cs;
+	ss->mode = mode;
+
+	/* TODO: Use max_hz to limit the SCK rate */
+
+	PRINTD(" ---> out\n");
+	
+	return &ss->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct ar71xx_spi_slave *ss = to_ar71xx_spi(slave);
+
+	free(ss);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+		void *din, unsigned long flags)
+{
+	struct ar71xx_spi_slave *ss = to_ar71xx_spi(slave);
+	uint8_t *rx = din;
+	const uint8_t *tx = dout;
+	uint8_t curbyte, curbitlen, restbits;
+	uint32_t bytes = bitlen / 8;
+	uint32_t out;
+	uint32_t in;
+	
+	PRINTD("ar71xx_spi: spi_xfer: slave:%p bitlen:%08x dout:%p din:%p flags:%08x\n", slave, bitlen, dout, din, flags);
+	
+	if (flags & SPI_XFER_BEGIN) {
+		__raw_writel(SPI_FS_GPIO, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_FS));
+		__raw_writel(SPI_IOC_CS_ALL, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC));
+	}
+	
+	restbits = (bitlen % 8);
+	if (restbits != 0)
+		bytes++;
+
+	// enable chip select
+	out = SPI_IOC_CS_ALL & ~(SPI_IOC_CS(slave->cs));
+
+	while (bytes--) {
+		
+		curbyte = 0;
+		if (tx) {
+			curbyte = *tx++;
+		}
+		
+		if (restbits != 0) {
+			curbitlen = restbits;
+			curbyte <<= 8 - restbits;
+		} else {
+			curbitlen = 8;
+		}
+		
+		PRINTD("ar71xx_spi: sending: data:%02x length:%d\n", curbyte, curbitlen);
+		
+		/* clock starts at inactive polarity */
+		for (curbyte <<= (8 - curbitlen); curbitlen; curbitlen--) {
+
+			if (curbyte & (1 << 7))
+				out |= SPI_IOC_DO;
+			else
+				out &= ~(SPI_IOC_DO);
+
+			/* setup MSB (to slave) on trailing edge */
+			__raw_writel(out, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC));
+
+			__raw_writel(out | SPI_IOC_CLK, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC));
+
+			curbyte <<= 1;
+		}
+		
+		in = __raw_readl(KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_RDS));
+		PRINTD("ar71xx_spi: received:%02x\n", in);
+		
+		if (rx) {
+			if (restbits == 0) {
+				*rx++ = in;
+			} else {
+				*rx++ = (in << (8 - restbits));
+			}
+		}
+	}
+	
+	if (flags & SPI_XFER_END) {
+		__raw_writel(SPI_IOC_CS(slave->cs), KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC));
+		__raw_writel(SPI_IOC_CS_ALL, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC));
+		__raw_writel(0, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_FS));
+	}
+
+	PRINTD(" ---> out\n");
+	
+	return 0;
+}
diff --git a/package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx.h b/package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx.h
new file mode 100644
index 0000000000..e8f3f61d27
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx.h
@@ -0,0 +1,515 @@
+/*
+ *  Atheros AR71xx SoC specific definitions
+ *
+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ *  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.
+ */
+
+#ifndef __ASM_MACH_AR71XX_H
+#define __ASM_MACH_AR71XX_H
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+#ifndef __ASSEMBLER__
+
+#define BIT(x)	(1<<(x))
+
+#define AR71XX_PCI_MEM_BASE	0x10000000
+#define AR71XX_PCI_MEM_SIZE	0x08000000
+#define AR71XX_APB_BASE		0x18000000
+#define AR71XX_GE0_BASE		0x19000000
+#define AR71XX_GE0_SIZE		0x01000000
+#define AR71XX_GE1_BASE		0x1a000000
+#define AR71XX_GE1_SIZE		0x01000000
+#define AR71XX_EHCI_BASE	0x1b000000
+#define AR71XX_EHCI_SIZE	0x01000000
+#define AR71XX_OHCI_BASE	0x1c000000
+#define AR71XX_OHCI_SIZE	0x01000000
+#define AR7240_OHCI_BASE	0x1b000000
+#define AR7240_OHCI_SIZE	0x01000000
+#define AR71XX_SPI_BASE		0x1f000000
+#define AR71XX_SPI_SIZE		0x01000000
+
+#define AR71XX_DDR_CTRL_BASE	(AR71XX_APB_BASE + 0x00000000)
+#define AR71XX_DDR_CTRL_SIZE	0x10000
+#define AR71XX_CPU_BASE		(AR71XX_APB_BASE + 0x00010000)
+#define AR71XX_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
+#define AR71XX_UART_SIZE	0x10000
+#define AR71XX_USB_CTRL_BASE	(AR71XX_APB_BASE + 0x00030000)
+#define AR71XX_USB_CTRL_SIZE	0x10000
+#define AR71XX_GPIO_BASE	(AR71XX_APB_BASE + 0x00040000)
+#define AR71XX_GPIO_SIZE	0x10000
+#define AR71XX_PLL_BASE		(AR71XX_APB_BASE + 0x00050000)
+#define AR71XX_PLL_SIZE		0x10000
+#define AR71XX_RESET_BASE	(AR71XX_APB_BASE + 0x00060000)
+#define AR71XX_RESET_SIZE	0x10000
+#define AR71XX_MII_BASE		(AR71XX_APB_BASE + 0x00070000)
+#define AR71XX_MII_SIZE		0x10000
+#define AR71XX_SLIC_BASE	(AR71XX_APB_BASE + 0x00090000)
+#define AR71XX_SLIC_SIZE	0x10000
+#define AR71XX_DMA_BASE		(AR71XX_APB_BASE + 0x000A0000)
+#define AR71XX_DMA_SIZE		0x10000
+#define AR71XX_STEREO_BASE	(AR71XX_APB_BASE + 0x000B0000)
+#define AR71XX_STEREO_SIZE	0x10000
+
+#define AR724X_PCI_CRP_BASE	(AR71XX_APB_BASE + 0x000C0000)
+#define AR724X_PCI_CRP_SIZE	0x100
+
+#define AR724X_PCI_CTRL_BASE	(AR71XX_APB_BASE + 0x000F0000)
+#define AR724X_PCI_CTRL_SIZE	0x100
+
+#define AR91XX_WMAC_BASE	(AR71XX_APB_BASE + 0x000C0000)
+#define AR91XX_WMAC_SIZE	0x30000
+
+#define AR71XX_MEM_SIZE_MIN	0x0200000
+#define AR71XX_MEM_SIZE_MAX	0x10000000
+
+#define AR71XX_CPU_IRQ_BASE	0
+#define AR71XX_MISC_IRQ_BASE	8
+#define AR71XX_MISC_IRQ_COUNT	8
+#define AR71XX_GPIO_IRQ_BASE	16
+#define AR71XX_GPIO_IRQ_COUNT	32
+#define AR71XX_PCI_IRQ_BASE     48
+#define AR71XX_PCI_IRQ_COUNT	8
+
+#define AR71XX_CPU_IRQ_IP2	(AR71XX_CPU_IRQ_BASE + 2)
+#define AR71XX_CPU_IRQ_USB	(AR71XX_CPU_IRQ_BASE + 3)
+#define AR71XX_CPU_IRQ_GE0	(AR71XX_CPU_IRQ_BASE + 4)
+#define AR71XX_CPU_IRQ_GE1	(AR71XX_CPU_IRQ_BASE + 5)
+#define AR71XX_CPU_IRQ_MISC	(AR71XX_CPU_IRQ_BASE + 6)
+#define AR71XX_CPU_IRQ_TIMER	(AR71XX_CPU_IRQ_BASE + 7)
+
+#define AR71XX_MISC_IRQ_TIMER	(AR71XX_MISC_IRQ_BASE + 0)
+#define AR71XX_MISC_IRQ_ERROR	(AR71XX_MISC_IRQ_BASE + 1)
+#define AR71XX_MISC_IRQ_GPIO	(AR71XX_MISC_IRQ_BASE + 2)
+#define AR71XX_MISC_IRQ_UART	(AR71XX_MISC_IRQ_BASE + 3)
+#define AR71XX_MISC_IRQ_WDOG	(AR71XX_MISC_IRQ_BASE + 4)
+#define AR71XX_MISC_IRQ_PERFC	(AR71XX_MISC_IRQ_BASE + 5)
+#define AR71XX_MISC_IRQ_OHCI	(AR71XX_MISC_IRQ_BASE + 6)
+#define AR71XX_MISC_IRQ_DMA	(AR71XX_MISC_IRQ_BASE + 7)
+
+#define AR71XX_GPIO_IRQ(_x)	(AR71XX_GPIO_IRQ_BASE + (_x))
+
+#define AR71XX_PCI_IRQ_DEV0	(AR71XX_PCI_IRQ_BASE + 0)
+#define AR71XX_PCI_IRQ_DEV1	(AR71XX_PCI_IRQ_BASE + 1)
+#define AR71XX_PCI_IRQ_DEV2	(AR71XX_PCI_IRQ_BASE + 2)
+#define AR71XX_PCI_IRQ_CORE	(AR71XX_PCI_IRQ_BASE + 4)
+
+extern u32 ar71xx_ahb_freq;
+extern u32 ar71xx_cpu_freq;
+extern u32 ar71xx_ddr_freq;
+
+enum ar71xx_soc_type {
+	AR71XX_SOC_UNKNOWN,
+	AR71XX_SOC_AR7130,
+	AR71XX_SOC_AR7141,
+	AR71XX_SOC_AR7161,
+	AR71XX_SOC_AR7240,
+	AR71XX_SOC_AR7241,
+	AR71XX_SOC_AR7242,
+	AR71XX_SOC_AR9130,
+	AR71XX_SOC_AR9132
+};
+
+extern enum ar71xx_soc_type ar71xx_soc;
+
+/*
+ * PLL block
+ */
+#define AR71XX_PLL_REG_CPU_CONFIG	0x00
+#define AR71XX_PLL_REG_SEC_CONFIG	0x04
+#define AR71XX_PLL_REG_ETH0_INT_CLOCK	0x10
+#define AR71XX_PLL_REG_ETH1_INT_CLOCK	0x14
+
+#define AR71XX_PLL_DIV_SHIFT		3
+#define AR71XX_PLL_DIV_MASK		0x1f
+#define AR71XX_CPU_DIV_SHIFT		16
+#define AR71XX_CPU_DIV_MASK		0x3
+#define AR71XX_DDR_DIV_SHIFT		18
+#define AR71XX_DDR_DIV_MASK		0x3
+#define AR71XX_AHB_DIV_SHIFT		20
+#define AR71XX_AHB_DIV_MASK		0x7
+
+#define AR71XX_ETH0_PLL_SHIFT		17
+#define AR71XX_ETH1_PLL_SHIFT		19
+
+#define AR724X_PLL_REG_CPU_CONFIG	0x00
+#define AR724X_PLL_REG_PCIE_CONFIG	0x18
+
+#define AR724X_PLL_DIV_SHIFT		0
+#define AR724X_PLL_DIV_MASK		0x3ff
+#define AR724X_PLL_REF_DIV_SHIFT	10
+#define AR724X_PLL_REF_DIV_MASK		0xf
+#define AR724X_AHB_DIV_SHIFT		19
+#define AR724X_AHB_DIV_MASK		0x1
+#define AR724X_DDR_DIV_SHIFT		22
+#define AR724X_DDR_DIV_MASK		0x3
+
+#define AR91XX_PLL_REG_CPU_CONFIG	0x00
+#define AR91XX_PLL_REG_ETH_CONFIG	0x04
+#define AR91XX_PLL_REG_ETH0_INT_CLOCK	0x14
+#define AR91XX_PLL_REG_ETH1_INT_CLOCK	0x18
+
+#define AR91XX_PLL_DIV_SHIFT		0
+#define AR91XX_PLL_DIV_MASK		0x3ff
+#define AR91XX_DDR_DIV_SHIFT		22
+#define AR91XX_DDR_DIV_MASK		0x3
+#define AR91XX_AHB_DIV_SHIFT		19
+#define AR91XX_AHB_DIV_MASK		0x1
+
+#define AR91XX_ETH0_PLL_SHIFT		20
+#define AR91XX_ETH1_PLL_SHIFT		22
+
+// extern void __iomem *ar71xx_pll_base;
+
+// static inline void ar71xx_pll_wr(unsigned reg, u32 val)
+// {
+	// __raw_writel(val, ar71xx_pll_base + reg);
+// }
+
+// static inline u32 ar71xx_pll_rr(unsigned reg)
+// {
+	// return __raw_readl(ar71xx_pll_base + reg);
+// }
+
+/*
+ * USB_CONFIG block
+ */
+#define USB_CTRL_REG_FLADJ	0x00
+#define USB_CTRL_REG_CONFIG	0x04
+
+// extern void __iomem *ar71xx_usb_ctrl_base;
+
+// static inline void ar71xx_usb_ctrl_wr(unsigned reg, u32 val)
+// {
+	// __raw_writel(val, ar71xx_usb_ctrl_base + reg);
+// }
+
+// static inline u32 ar71xx_usb_ctrl_rr(unsigned reg)
+// {
+	// return __raw_readl(ar71xx_usb_ctrl_base + reg);
+// }
+
+/*
+ * GPIO block
+ */
+#define GPIO_REG_OE		0x00
+#define GPIO_REG_IN		0x04
+#define GPIO_REG_OUT		0x08
+#define GPIO_REG_SET		0x0c
+#define GPIO_REG_CLEAR		0x10
+#define GPIO_REG_INT_MODE	0x14
+#define GPIO_REG_INT_TYPE	0x18
+#define GPIO_REG_INT_POLARITY	0x1c
+#define GPIO_REG_INT_PENDING	0x20
+#define GPIO_REG_INT_ENABLE	0x24
+#define GPIO_REG_FUNC		0x28
+
+#define AR71XX_GPIO_FUNC_STEREO_EN	BIT(17)
+#define AR71XX_GPIO_FUNC_SLIC_EN	BIT(16)
+#define AR71XX_GPIO_FUNC_SPI_CS2_EN	BIT(13)
+#define AR71XX_GPIO_FUNC_SPI_CS1_EN	BIT(12)
+#define AR71XX_GPIO_FUNC_UART_EN	BIT(8)
+#define AR71XX_GPIO_FUNC_USB_OC_EN	BIT(4)
+#define AR71XX_GPIO_FUNC_USB_CLK_EN	BIT(0)
+
+#define AR71XX_GPIO_COUNT	16
+
+#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN		BIT(19)
+#define AR724X_GPIO_FUNC_SPI_EN			BIT(18)
+#define AR724X_GPIO_FUNC_SPI_CS_EN2		BIT(14)
+#define AR724X_GPIO_FUNC_SPI_CS_EN1		BIT(13)
+#define AR724X_GPIO_FUNC_CLK_OBS5_EN		BIT(12)
+#define AR724X_GPIO_FUNC_CLK_OBS4_EN		BIT(11)
+#define AR724X_GPIO_FUNC_CLK_OBS3_EN		BIT(10)
+#define AR724X_GPIO_FUNC_CLK_OBS2_EN		BIT(9)
+#define AR724X_GPIO_FUNC_CLK_OBS1_EN		BIT(8)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN	BIT(7)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN	BIT(6)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN	BIT(5)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN	BIT(4)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN	BIT(3)
+#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN	BIT(2)
+#define AR724X_GPIO_FUNC_UART_EN		BIT(1)
+#define AR724X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
+
+#define AR724X_GPIO_COUNT	18
+
+#define AR91XX_GPIO_FUNC_WMAC_LED_EN	BIT(22)
+#define AR91XX_GPIO_FUNC_EXP_PORT_CS_EN	BIT(21)
+#define AR91XX_GPIO_FUNC_I2S_REFCLKEN	BIT(20)
+#define AR91XX_GPIO_FUNC_I2S_MCKEN	BIT(19)
+#define AR91XX_GPIO_FUNC_I2S1_EN	BIT(18)
+#define AR91XX_GPIO_FUNC_I2S0_EN	BIT(17)
+#define AR91XX_GPIO_FUNC_SLIC_EN	BIT(16)
+#define AR91XX_GPIO_FUNC_UART_RTSCTS_EN	BIT(9)
+#define AR91XX_GPIO_FUNC_UART_EN	BIT(8)
+#define AR91XX_GPIO_FUNC_USB_CLK_EN	BIT(4)
+
+#define AR91XX_GPIO_COUNT	22
+
+// extern void __iomem *ar71xx_gpio_base;
+
+// static inline void ar71xx_gpio_wr(unsigned reg, u32 value)
+// {
+	// __raw_writel(value, ar71xx_gpio_base + reg);
+// }
+
+// static inline u32 ar71xx_gpio_rr(unsigned reg)
+// {
+	// return __raw_readl(ar71xx_gpio_base + reg);
+// }
+
+// void ar71xx_gpio_init(void) __init;
+// void ar71xx_gpio_function_enable(u32 mask);
+// void ar71xx_gpio_function_disable(u32 mask);
+// void ar71xx_gpio_function_setup(u32 set, u32 clear);
+
+/*
+ * DDR_CTRL block
+ */
+#define AR71XX_DDR_REG_PCI_WIN0		0x7c
+#define AR71XX_DDR_REG_PCI_WIN1		0x80
+#define AR71XX_DDR_REG_PCI_WIN2		0x84
+#define AR71XX_DDR_REG_PCI_WIN3		0x88
+#define AR71XX_DDR_REG_PCI_WIN4		0x8c
+#define AR71XX_DDR_REG_PCI_WIN5		0x90
+#define AR71XX_DDR_REG_PCI_WIN6		0x94
+#define AR71XX_DDR_REG_PCI_WIN7		0x98
+#define AR71XX_DDR_REG_FLUSH_GE0	0x9c
+#define AR71XX_DDR_REG_FLUSH_GE1	0xa0
+#define AR71XX_DDR_REG_FLUSH_USB	0xa4
+#define AR71XX_DDR_REG_FLUSH_PCI	0xa8
+
+#define AR724X_DDR_REG_FLUSH_GE0	0x7c
+#define AR724X_DDR_REG_FLUSH_GE1	0x80
+#define AR724X_DDR_REG_FLUSH_USB	0x84
+#define AR724X_DDR_REG_FLUSH_PCIE	0x88
+
+#define AR91XX_DDR_REG_FLUSH_GE0	0x7c
+#define AR91XX_DDR_REG_FLUSH_GE1	0x80
+#define AR91XX_DDR_REG_FLUSH_USB	0x84
+#define AR91XX_DDR_REG_FLUSH_WMAC	0x88
+
+#define PCI_WIN0_OFFS	0x10000000
+#define PCI_WIN1_OFFS	0x11000000
+#define PCI_WIN2_OFFS	0x12000000
+#define PCI_WIN3_OFFS	0x13000000
+#define PCI_WIN4_OFFS	0x14000000
+#define PCI_WIN5_OFFS	0x15000000
+#define PCI_WIN6_OFFS	0x16000000
+#define PCI_WIN7_OFFS	0x07000000
+
+// extern void __iomem *ar71xx_ddr_base;
+
+// static inline void ar71xx_ddr_wr(unsigned reg, u32 val)
+// {
+	// __raw_writel(val, ar71xx_ddr_base + reg);
+// }
+
+// static inline u32 ar71xx_ddr_rr(unsigned reg)
+// {
+	// return __raw_readl(ar71xx_ddr_base + reg);
+// }
+
+// void ar71xx_ddr_flush(u32 reg);
+
+/*
+ * PCI block
+ */
+#define AR71XX_PCI_CFG_BASE	(AR71XX_PCI_MEM_BASE + PCI_WIN7_OFFS + 0x10000)
+#define AR71XX_PCI_CFG_SIZE	0x100
+
+#define PCI_REG_CRP_AD_CBE	0x00
+#define PCI_REG_CRP_WRDATA	0x04
+#define PCI_REG_CRP_RDDATA	0x08
+#define PCI_REG_CFG_AD		0x0c
+#define PCI_REG_CFG_CBE		0x10
+#define PCI_REG_CFG_WRDATA	0x14
+#define PCI_REG_CFG_RDDATA	0x18
+#define PCI_REG_PCI_ERR		0x1c
+#define PCI_REG_PCI_ERR_ADDR	0x20
+#define PCI_REG_AHB_ERR		0x24
+#define PCI_REG_AHB_ERR_ADDR	0x28
+
+#define PCI_CRP_CMD_WRITE	0x00010000
+#define PCI_CRP_CMD_READ	0x00000000
+#define PCI_CFG_CMD_READ	0x0000000a
+#define PCI_CFG_CMD_WRITE	0x0000000b
+
+#define PCI_IDSEL_ADL_START	17
+
+#define AR724X_PCI_CFG_BASE	(AR71XX_PCI_MEM_BASE + 0x4000000)
+#define AR724X_PCI_CFG_SIZE	0x1000
+
+#define AR724X_PCI_REG_APP		0x00
+#define AR724X_PCI_REG_RESET		0x18
+#define AR724X_PCI_REG_INT_STATUS	0x4c
+#define AR724X_PCI_REG_INT_MASK		0x50
+
+#define AR724X_PCI_APP_LTSSM_ENABLE	BIT(0)
+#define AR724X_PCI_RESET_LINK_UP	BIT(0)
+
+#define AR724X_PCI_INT_DEV0		BIT(14)
+
+/*
+ * RESET block
+ */
+#define AR71XX_RESET_REG_TIMER			0x00
+#define AR71XX_RESET_REG_TIMER_RELOAD		0x04
+#define AR71XX_RESET_REG_WDOG_CTRL		0x08
+#define AR71XX_RESET_REG_WDOG			0x0c
+#define AR71XX_RESET_REG_MISC_INT_STATUS	0x10
+#define AR71XX_RESET_REG_MISC_INT_ENABLE	0x14
+#define AR71XX_RESET_REG_PCI_INT_STATUS		0x18
+#define AR71XX_RESET_REG_PCI_INT_ENABLE		0x1c
+#define AR71XX_RESET_REG_GLOBAL_INT_STATUS	0x20
+#define AR71XX_RESET_REG_RESET_MODULE		0x24
+#define AR71XX_RESET_REG_PERFC_CTRL		0x2c
+#define AR71XX_RESET_REG_PERFC0			0x30
+#define AR71XX_RESET_REG_PERFC1			0x34
+#define AR71XX_RESET_REG_REV_ID			0x90
+
+#define AR91XX_RESET_REG_GLOBAL_INT_STATUS	0x18
+#define AR91XX_RESET_REG_RESET_MODULE		0x1c
+#define AR91XX_RESET_REG_PERF_CTRL		0x20
+#define AR91XX_RESET_REG_PERFC0			0x24
+#define AR91XX_RESET_REG_PERFC1			0x28
+
+#define AR724X_RESET_REG_RESET_MODULE		0x1c
+
+#define WDOG_CTRL_LAST_RESET		BIT(31)
+#define WDOG_CTRL_ACTION_MASK		3
+#define WDOG_CTRL_ACTION_NONE		0	/* no action */
+#define WDOG_CTRL_ACTION_GPI		1	/* general purpose interrupt */
+#define WDOG_CTRL_ACTION_NMI		2	/* NMI */
+#define WDOG_CTRL_ACTION_FCR		3	/* full chip reset */
+
+#define MISC_INT_DMA			BIT(7)
+#define MISC_INT_OHCI			BIT(6)
+#define MISC_INT_PERFC			BIT(5)
+#define MISC_INT_WDOG			BIT(4)
+#define MISC_INT_UART			BIT(3)
+#define MISC_INT_GPIO			BIT(2)
+#define MISC_INT_ERROR			BIT(1)
+#define MISC_INT_TIMER			BIT(0)
+
+#define PCI_INT_CORE			BIT(4)
+#define PCI_INT_DEV2			BIT(2)
+#define PCI_INT_DEV1			BIT(1)
+#define PCI_INT_DEV0			BIT(0)
+
+#define RESET_MODULE_EXTERNAL		BIT(28)
+#define RESET_MODULE_FULL_CHIP		BIT(24)
+#define RESET_MODULE_AMBA2WMAC		BIT(22)
+#define RESET_MODULE_CPU_NMI		BIT(21)
+#define RESET_MODULE_CPU_COLD		BIT(20)
+#define RESET_MODULE_DMA		BIT(19)
+#define RESET_MODULE_SLIC		BIT(18)
+#define RESET_MODULE_STEREO		BIT(17)
+#define RESET_MODULE_DDR		BIT(16)
+#define RESET_MODULE_GE1_MAC		BIT(13)
+#define RESET_MODULE_GE1_PHY		BIT(12)
+#define RESET_MODULE_USBSUS_OVERRIDE	BIT(10)
+#define RESET_MODULE_GE0_MAC		BIT(9)
+#define RESET_MODULE_GE0_PHY		BIT(8)
+#define RESET_MODULE_USB_OHCI_DLL	BIT(6)
+#define RESET_MODULE_USB_HOST		BIT(5)
+#define RESET_MODULE_USB_PHY		BIT(4)
+#define RESET_MODULE_USB_OHCI_DLL_7240	BIT(3)
+#define RESET_MODULE_PCI_BUS		BIT(1)
+#define RESET_MODULE_PCI_CORE		BIT(0)
+
+#define AR724X_RESET_GE1_MDIO		BIT(23)
+#define AR724X_RESET_GE0_MDIO		BIT(22)
+#define AR724X_RESET_PCIE_PHY_SERIAL	BIT(10)
+#define AR724X_RESET_PCIE_PHY		BIT(7)
+#define AR724X_RESET_PCIE		BIT(6)
+
+#define REV_ID_MAJOR_MASK	0xfff0
+#define REV_ID_MAJOR_AR71XX	0x00a0
+#define REV_ID_MAJOR_AR913X	0x00b0
+#define REV_ID_MAJOR_AR7240	0x00c0
+#define REV_ID_MAJOR_AR7241	0x0100
+#define REV_ID_MAJOR_AR7242	0x1100
+
+#define AR71XX_REV_ID_MINOR_MASK	0x3
+#define AR71XX_REV_ID_MINOR_AR7130	0x0
+#define AR71XX_REV_ID_MINOR_AR7141	0x1
+#define AR71XX_REV_ID_MINOR_AR7161	0x2
+#define AR71XX_REV_ID_REVISION_MASK	0x3
+#define AR71XX_REV_ID_REVISION_SHIFT	2
+
+#define AR91XX_REV_ID_MINOR_MASK	0x3
+#define AR91XX_REV_ID_MINOR_AR9130	0x0
+#define AR91XX_REV_ID_MINOR_AR9132	0x1
+#define AR91XX_REV_ID_REVISION_MASK	0x3
+#define AR91XX_REV_ID_REVISION_SHIFT	2
+
+#define AR724X_REV_ID_REVISION_MASK	0x3
+
+// extern void __iomem *ar71xx_reset_base;
+
+static inline void ar71xx_reset_wr(unsigned reg, u32 val)
+{
+	__raw_writel(val, KSEG1ADDR(AR71XX_RESET_BASE) + reg);
+}
+
+static inline u32 ar71xx_reset_rr(unsigned reg)
+{
+	return __raw_readl(KSEG1ADDR(AR71XX_RESET_BASE) + reg);
+}
+
+// void ar71xx_device_stop(u32 mask);
+// void ar71xx_device_start(u32 mask);
+// int ar71xx_device_stopped(u32 mask);
+
+/*
+ * SPI block
+ */
+#define SPI_REG_FS		0x00	/* Function Select */
+#define SPI_REG_CTRL		0x04	/* SPI Control */
+#define SPI_REG_IOC		0x08	/* SPI I/O Control */
+#define SPI_REG_RDS		0x0c	/* Read Data Shift */
+
+#define SPI_FS_GPIO		BIT(0)	/* Enable GPIO mode */
+
+#define SPI_CTRL_RD		BIT(6)	/* Remap Disable */
+#define SPI_CTRL_DIV_MASK	0x3f
+
+#define SPI_IOC_DO		BIT(0)	/* Data Out pin */
+#define SPI_IOC_CLK		BIT(8)	/* CLK pin */
+#define SPI_IOC_CS(n)		BIT(16 + (n))
+#define SPI_IOC_CS0		SPI_IOC_CS(0)
+#define SPI_IOC_CS1		SPI_IOC_CS(1)
+#define SPI_IOC_CS2		SPI_IOC_CS(2)
+#define SPI_IOC_CS_ALL		(SPI_IOC_CS0 | SPI_IOC_CS1 | SPI_IOC_CS2)
+
+// void ar71xx_flash_acquire(void);
+// void ar71xx_flash_release(void);
+
+/*
+ * MII_CTRL block
+ */
+#define MII_REG_MII0_CTRL	0x00
+#define MII_REG_MII1_CTRL	0x04
+
+#define MII0_CTRL_IF_GMII	0
+#define MII0_CTRL_IF_MII	1
+#define MII0_CTRL_IF_RGMII	2
+#define MII0_CTRL_IF_RMII	3
+
+#define MII1_CTRL_IF_RGMII	0
+#define MII1_CTRL_IF_RMII	1
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __ASM_MACH_AR71XX_H */
diff --git a/package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx_gpio.h b/package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx_gpio.h
new file mode 100644
index 0000000000..c92364b881
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/include/asm-mips/ar71xx_gpio.h
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _AR71XX_GPIO_H
+#define _AR71XX_GPIO_H
+
+#include <common.h>
+#include <asm/ar71xx.h>
+
+static inline void ar71xx_setpin(uint8_t pin, uint8_t state)
+{
+	uint32_t reg = readl(KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_OUT));
+
+	if (state != 0) {
+       reg |= (1 << pin);
+   } else {
+       reg &= ~(1 << pin);
+   }
+
+	writel(reg, KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_OUT));
+	readl(KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_OUT));
+}
+
+static inline uint32_t ar71xx_getpin(uint8_t pin)
+{
+    uint32_t reg = readl(KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_IN));
+    return (((reg & (1 << pin)) != 0) ? 1 : 0);
+}
+
+static inline void ar71xx_setpindir(uint8_t pin, uint8_t direction)
+{
+	uint32_t reg = readl(KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_OE));
+
+	if (direction != 0) {
+        reg |= (1 << pin);
+    } else {
+        reg &= ~(1 << pin);
+    }
+
+	writel(reg, KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_OE));
+	readl(KSEG1ADDR(AR71XX_GPIO_BASE + GPIO_REG_OE));
+}
+
+
+#endif /* AR71XX_GPIO_H */
diff --git a/package/boot/uboot-ar71xx/files/include/configs/nbg460n.h b/package/boot/uboot-ar71xx/files/include/configs/nbg460n.h
new file mode 100644
index 0000000000..dd9b4c38af
--- /dev/null
+++ b/package/boot/uboot-ar71xx/files/include/configs/nbg460n.h
@@ -0,0 +1,136 @@
+/*
+ * (C) Copyright 2010
+ * Michael Kurz <michi.kurz@googlemail.com>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* This file contains the configuration parameters for the zyxel nbg460n board. */
+
+#ifndef _NBG460N_CONFIG_H
+#define _NBG460N_CONFIG_H
+
+#define CONFIG_MIPS32		1  /* MIPS32 CPU core */
+#define CONFIG_AR71XX		1
+#define CONFIG_AR91XX		1
+#define CONFIG_SYS_HZ		1000
+#define CONFIG_SYS_MIPS_TIMER_FREQ (400000000/2)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE		32768
+#define CONFIG_SYS_ICACHE_SIZE		65536
+#define CONFIG_SYS_CACHELINE_SIZE	32
+/* Cache lock for stack */
+#define CONFIG_SYS_INIT_SP_OFFSET	0x1000
+
+#define CONFIG_SYS_MONITOR_BASE	(TEXT_BASE)
+
+#define CONFIG_BAUDRATE		115200
+#define CONFIG_SYS_BAUDRATE_TABLE  {115200}
+
+#define CONFIG_MISC_INIT_R
+
+/* SPI-Flash support */
+#define CONFIG_SPI_FLASH
+#define CONFIG_AR71XX_SPI
+#define CONFIG_SPI_FLASH_MACRONIX
+#define CONFIG_SF_DEFAULT_HZ	25000000
+
+#define CONFIG_ENV_SPI_MAX_HZ	25000000
+#define CONFIG_ENV_SPI_BUS		0
+#define CONFIG_ENV_SPI_CS		0
+
+#define	CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_ADDR			0xbfc20000
+#define CONFIG_ENV_OFFSET		0x20000
+#define CONFIG_ENV_SIZE			0x01000
+#define CONFIG_ENV_SECT_SIZE	0x10000
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#define CONFIG_SYS_MAX_FLASH_SECT 64
+#define CONFIG_SYS_FLASH_BASE	0xbfc00000
+
+/* Net support */
+#define CONFIG_ETHADDR_ADDR     0xbfc0fff8
+#define CONFIG_SYS_RX_ETH_BUFFER  	16
+#define CONFIG_AG71XX
+#define CONFIG_AG71XX_PORTS     { 1, 1 }
+#define CONFIG_AG71XX_MII0_IIF  MII0_CTRL_IF_RGMII
+#define CONFIG_AG71XX_MII1_IIF  MII1_CTRL_IF_RGMII
+#define CONFIG_NET_MULTI
+#define CONFIG_IPADDR			192.168.1.254
+#define CONFIG_SERVERIP			192.168.1.42
+
+/* Switch support */
+#define CONFIG_MII
+#define CONFIG_RTL8366_MII
+#define RTL8366_PIN_SDA 16
+#define RTL8366_PIN_SCK 18
+#define MII_GPIOINCLUDE <asm/ar71xx_gpio.h>
+#define MII_SETSDA(x)   ar71xx_setpin(RTL8366_PIN_SDA, x)
+#define MII_GETSDA      ar71xx_getpin(RTL8366_PIN_SDA)
+#define MII_SETSCK(x)   ar71xx_setpin(RTL8366_PIN_SCK, x)
+#define MII_SDAINPUT    ar71xx_setpindir(RTL8366_PIN_SDA, 0)
+#define MII_SDAOUTPUT   ar71xx_setpindir(RTL8366_PIN_SDA, 1)
+#define MII_SCKINPUT    ar71xx_setpindir(RTL8366_PIN_SCK, 0)
+#define MII_SCKOUTPUT   ar71xx_setpindir(RTL8366_PIN_SCK, 1)
+
+#define CONFIG_BOOTDELAY	3
+#define	CONFIG_BOOTARGS		"console=ttyS0,115200 rootfstype==squashfs,jffs2 noinitrd machtype=NBG460N"
+#define CONFIG_BOOTCOMMAND	"bootm 0xbfc70000"
+#define CONFIG_LZMA
+
+
+/* Commands */
+#define CONFIG_SYS_NO_FLASH
+#include <config_cmd_default.h>
+#undef CONFIG_CMD_BDI
+#undef CONFIG_CMD_FPGA
+#undef CONFIG_CMD_IMI
+#undef CONFIG_CMD_IMLS
+#undef CONFIG_CMD_LOADS
+#define CONFIG_CMD_SF
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_SPI
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_PROMPT		"U-Boot> "
+#define CONFIG_SYS_CBSIZE		256
+#define CONFIG_SYS_MAXARGS		16
+#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP		1
+#define CONFIG_CMDLINE_EDITING	1
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2	"> "
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		ROUND(3 * 0x10000 + 128*1024, 0x1000)
+#define CONFIG_SYS_GBL_DATA_SIZE	128	/* 128 bytes for initial data */
+
+#define CONFIG_SYS_BOOTPARAMS_LEN	128*1024
+
+#define CONFIG_SYS_SDRAM_BASE		0x80000000     /* Cached addr */
+#define	CONFIG_SYS_LOAD_ADDR		0x80060000     /* default load address	*/
+
+#define CONFIG_SYS_MEMTEST_START	0x80000800
+#define CONFIG_SYS_MEMTEST_END		0x81E00000
+
+#endif	/* _NBG460N_CONFIG_H */
diff --git a/package/boot/uboot-ar71xx/patches/0001-upstream-Reproducible-U-Boot-build-support-using-SOURCE_DATE_.patch b/package/boot/uboot-ar71xx/patches/0001-upstream-Reproducible-U-Boot-build-support-using-SOURCE_DATE_.patch
new file mode 100644
index 0000000000..331c1c3662
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/0001-upstream-Reproducible-U-Boot-build-support-using-SOURCE_DATE_.patch
@@ -0,0 +1,82 @@
+From f3f431a712729a1af94d01bd1bfde17a252ff02c Mon Sep 17 00:00:00 2001
+From: Paul Kocialkowski <contact@paulk.fr>
+Date: Sun, 26 Jul 2015 18:48:15 +0200
+Subject: [PATCH] Reproducible U-Boot build support, using SOURCE_DATE_EPOCH
+
+In order to achieve reproducible builds in U-Boot, timestamps that are defined
+at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
+variable allows setting a fixed value for those timestamps.
+
+Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
+built reproducibly. This is the case for e.g. sunxi devices.
+
+However, some other devices might need some more tweaks, especially regarding
+the image generation tools.
+
+Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
+---
+ Makefile              |  7 ++++---
+ README                | 12 ++++++++++++
+ tools/default_image.c | 21 ++++++++++++++++++++-
+ 3 files changed, 36 insertions(+), 4 deletions(-)
+
+--- a/README
++++ b/README
+@@ -2785,6 +2785,18 @@ Low Level (hardware related) configurati
+ 		that is executed before the actual U-Boot. E.g. when
+ 		compiling a NAND SPL.
+ 
++Reproducible builds
++-------------------
++
++In order to achieve reproducible builds, timestamps used in the U-Boot build
++process have to be set to a fixed value.
++
++This is done using the SOURCE_DATE_EPOCH environment variable.
++SOURCE_DATE_EPOCH is to be set on the build host's shell, not as a configuration
++option for U-Boot or an environment variable in U-Boot.
++
++SOURCE_DATE_EPOCH should be set to a number of seconds since the epoch, in UTC.
++
+ Building the Software:
+ ======================
+ 
+--- a/tools/default_image.c
++++ b/tools/default_image.c
+@@ -101,6 +101,9 @@ static void image_set_header (void *ptr,
+ 				struct mkimage_params *params)
+ {
+ 	uint32_t checksum;
++	char *source_date_epoch;
++	struct tm *time_universal;
++	time_t time;
+ 
+ 	image_header_t * hdr = (image_header_t *)ptr;
+ 
+@@ -109,9 +112,25 @@ static void image_set_header (void *ptr,
+ 				sizeof(image_header_t)),
+ 			sbuf->st_size - sizeof(image_header_t));
+ 
++source_date_epoch = getenv("SOURCE_DATE_EPOCH");
++	if (source_date_epoch != NULL) {
++		time = (time_t) strtol(source_date_epoch, NULL, 10);
++
++		time_universal = gmtime(&time);
++		if (time_universal == NULL) {
++			fprintf(stderr, "%s: SOURCE_DATE_EPOCH is not valid\n",
++				__func__);
++			time = 0;
++		} else {
++			time = mktime(time_universal);
++		}
++	} else {
++		time = sbuf->st_mtime;
++	}
++
+ 	/* Build new header */
+ 	image_set_magic (hdr, IH_MAGIC);
+-	image_set_time (hdr, sbuf->st_mtime);
++	image_set_time(hdr, time);
+ 	image_set_size (hdr, sbuf->st_size - sizeof(image_header_t));
+ 	image_set_load (hdr, params->addr);
+ 	image_set_ep (hdr, params->ep);
diff --git a/package/boot/uboot-ar71xx/patches/0002-upstream-Makefile-Reproducible-U-Boot-build-support.patch b/package/boot/uboot-ar71xx/patches/0002-upstream-Makefile-Reproducible-U-Boot-build-support.patch
new file mode 100644
index 0000000000..664a4adb66
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/0002-upstream-Makefile-Reproducible-U-Boot-build-support.patch
@@ -0,0 +1,31 @@
+--- a/Makefile
++++ b/Makefile
+@@ -389,8 +389,26 @@ $(VERSION_FILE):
+ 		@cmp -s $@ $@.tmp && rm -f $@.tmp || mv -f $@.tmp $@
+ 
+ $(TIMESTAMP_FILE):
+-		@date +'#define U_BOOT_DATE "%b %d %C%y"' > $@
+-		@date +'#define U_BOOT_TIME "%T"' >> $@
++	(if test -n "$${SOURCE_DATE_EPOCH}"; then \
++                SOURCE_DATE="@$${SOURCE_DATE_EPOCH}"; \
++                DATE=""; \
++                for date in gdate date.gnu date; do \
++                        $${date} -u -d "$${SOURCE_DATE}" >/dev/null 2>&1 && DATE="$${date}"; \
++                done; \
++                if test -n "$${DATE}"; then \
++                        LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DATE "%b %d %C%y"' > $@; \
++                        LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TIME "%T"' >> $@; \
++                        LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_TZ "%z"' >> $@; \
++                        LC_ALL=C $${DATE} -u -d "$${SOURCE_DATE}" +'#define U_BOOT_DMI_DATE "%m/%d/%Y"' >> $@; \
++                else \
++                        return 42; \
++                fi; \
++        else \
++                LC_ALL=C date +'#define U_BOOT_DATE "%b %d %C%y"'; \
++                LC_ALL=C date +'#define U_BOOT_TIME "%T"'; \
++                LC_ALL=C date +'#define U_BOOT_TZ "%z"'; \
++                LC_ALL=C date +'#define U_BOOT_DMI_DATE "%m/%d/%Y"'; \
++        fi)
+ 
+ gdbtools:
+ 		$(MAKE) -C tools/gdb all || exit 1
diff --git a/package/boot/uboot-ar71xx/patches/001-ar71xx.patch b/package/boot/uboot-ar71xx/patches/001-ar71xx.patch
new file mode 100644
index 0000000000..e862df21e3
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/001-ar71xx.patch
@@ -0,0 +1,26 @@
+--- a/cpu/mips/Makefile
++++ b/cpu/mips/Makefile
+@@ -33,6 +33,7 @@ SOBJS-$(CONFIG_INCA_IP)	+= incaip_wdt.o
+ COBJS-$(CONFIG_INCA_IP)	+= asc_serial.o incaip_clock.o
+ COBJS-$(CONFIG_PURPLE)	+= asc_serial.o
+ COBJS-$(CONFIG_SOC_AU1X00) += au1x00_eth.o au1x00_serial.o au1x00_usb_ohci.o
++COBJS-$(CONFIG_AR71XX)	+= ar71xx_serial.o
+ 
+ SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+ OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+--- a/Makefile
++++ b/Makefile
+@@ -3474,6 +3474,13 @@ qemu_mips_config	: unconfig
+ 	@$(MKCONFIG) -a qemu-mips mips mips qemu-mips
+ 
+ #########################################################################
++## MIPS32 AR71XX (24K)
++#########################################################################
++
++nbg460n_550n_550nh_config : 	unconfig
++	@$(MKCONFIG) -a nbg460n mips mips nbg460n zyxel
++
++#########################################################################
+ ## MIPS64 5Kc
+ #########################################################################
+ 
diff --git a/package/boot/uboot-ar71xx/patches/002-ar71xx-spi.patch b/package/boot/uboot-ar71xx/patches/002-ar71xx-spi.patch
new file mode 100644
index 0000000000..2bb1ba2216
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/002-ar71xx-spi.patch
@@ -0,0 +1,11 @@
+diff -ur u-boot-2010.03/drivers/spi/Makefile u-boot-nbg/drivers/spi/Makefile
+--- u-boot-2010.03/drivers/spi/Makefile	2010-03-31 23:54:39.000000000 +0200
++++ u-boot-nbg/drivers/spi/Makefile	2010-04-15 19:31:27.000000000 +0200
+@@ -25,6 +25,7 @@
+ 
+ LIB	:= $(obj)libspi.a
+ 
++COBJS-$(CONFIG_AR71XX_SPI) += ar71xx_spi.o
+ COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
+ COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
+ COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o
diff --git a/package/boot/uboot-ar71xx/patches/010-enet-ag71xx.patch b/package/boot/uboot-ar71xx/patches/010-enet-ag71xx.patch
new file mode 100644
index 0000000000..ee90e32c7a
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/010-enet-ag71xx.patch
@@ -0,0 +1,22 @@
+diff -ur u-boot-2010.03/drivers/net/Makefile u-boot-nbg/drivers/net/Makefile
+--- u-boot-2010.03/drivers/net/Makefile	2010-03-31 23:54:39.000000000 +0200
++++ u-boot-nbg/drivers/net/Makefile	2010-04-19 23:30:01.000000000 +0200
+@@ -27,6 +27,7 @@
+ 
+ COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o
+ COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
++COBJS-$(CONFIG_AG71XX) += ag71xx.o
+ COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
+ COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o
+ COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o
+diff -ur u-boot-2010.03/include/netdev.h u-boot-nbg/include/netdev.h
+--- u-boot-2010.03/include/netdev.h	2010-03-31 23:54:39.000000000 +0200
++++ u-boot-nbg/include/netdev.h	2010-05-02 11:30:58.000000000 +0200
+@@ -42,6 +42,7 @@
+ 
+ /* Driver initialization prototypes */
+ int au1x00_enet_initialize(bd_t*);
++int ag71xx_register(bd_t * bis, char *phyname[], u16 phyid[], u16 phyfixed[]);
+ int at91emac_register(bd_t *bis, unsigned long iobase);
+ int bfin_EMAC_initialize(bd_t *bis);
+ int cs8900_initialize(u8 dev_num, int base_addr);
diff --git a/package/boot/uboot-ar71xx/patches/011-switch-rtl8366sr.patch b/package/boot/uboot-ar71xx/patches/011-switch-rtl8366sr.patch
new file mode 100644
index 0000000000..5d2ba41eae
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/011-switch-rtl8366sr.patch
@@ -0,0 +1,28 @@
+diff -ur u-boot-2010.03/drivers/net/Makefile u-boot-nbg/drivers/net/Makefile
+--- u-boot-2010.03/drivers/net/Makefile	2010-03-31 23:54:39.000000000 +0200
++++ u-boot-nbg/drivers/net/Makefile	2010-04-19 23:30:01.000000000 +0200
+@@ -65,6 +65,7 @@
+ COBJS-$(CONFIG_DRIVER_RTL8019) += rtl8019.o
+ COBJS-$(CONFIG_RTL8139) += rtl8139.o
+ COBJS-$(CONFIG_RTL8169) += rtl8169.o
++COBJS-$(CONFIG_RTL8366_MII) += phy/rtl8366_mii.o
+ COBJS-$(CONFIG_DRIVER_S3C4510_ETH) += s3c4510b_eth.o
+ COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
+ COBJS-$(CONFIG_SMC91111) += smc91111.o
+diff -ur u-boot-2010.03/include/netdev.h u-boot-nbg/include/netdev.h
+--- u-boot-2010.03/include/netdev.h	2010-03-31 23:54:39.000000000 +0200
++++ u-boot-nbg/include/netdev.h	2010-05-02 11:30:58.000000000 +0200
+@@ -175,5 +175,13 @@
+ 
+ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig);
+ #endif /* CONFIG_MV88E61XX_SWITCH */
++
++#if defined(CONFIG_RTL8366_MII)
++#define RTL8366_DEVNAME         "rtl8366"
++#define RTL8366_WANPHY_ID       4
++#define RTL8366_LANPHY_ID       -1
++int rtl8366_mii_register(bd_t *bis);
++int rtl8366s_initialize(void);
++#endif
+ 
+ #endif /* _NETDEV_H_ */
diff --git a/package/boot/uboot-ar71xx/patches/020-freebsd-compat.patch b/package/boot/uboot-ar71xx/patches/020-freebsd-compat.patch
new file mode 100644
index 0000000000..fee06699c9
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/020-freebsd-compat.patch
@@ -0,0 +1,11 @@
+--- a/include/compiler.h
++++ b/include/compiler.h
+@@ -46,7 +46,7 @@ extern int errno;
+ #ifdef __linux__
+ # include <endian.h>
+ # include <byteswap.h>
+-#elif defined(__MACH__)
++#elif defined(__MACH__) || defined(__FreeBSD__)
+ # include <machine/endian.h>
+ typedef unsigned long ulong;
+ typedef unsigned int  uint;
diff --git a/package/boot/uboot-ar71xx/patches/021-darwin_compat.patch b/package/boot/uboot-ar71xx/patches/021-darwin_compat.patch
new file mode 100644
index 0000000000..dde83d4905
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/021-darwin_compat.patch
@@ -0,0 +1,23 @@
+--- a/config.mk
++++ b/config.mk
+@@ -64,9 +64,17 @@ HOSTSTRIP	= strip
+ #
+ 
+ ifeq ($(HOSTOS),darwin)
+-HOSTCC		= cc
+-HOSTCFLAGS	+= -traditional-cpp
+-HOSTLDFLAGS	+= -multiply_defined suppress
++#get the major and minor product version (e.g. '10' and '6' for Snow Leopard)
++DARWIN_MAJOR_VERSION   = $(shell sw_vers -productVersion | cut -f 1 -d '.')
++DARWIN_MINOR_VERSION   = $(shell sw_vers -productVersion | cut -f 2 -d '.')
++
++before-snow-leopard    = $(shell if [ $(DARWIN_MAJOR_VERSION) -le 10 -a \
++   $(DARWIN_MINOR_VERSION) -le 5 ] ; then echo "$(1)"; else echo "$(2)"; fi ;)
++
++# Snow Leopards build environment has no longer restrictions as described above
++HOSTCC  = $(call before-snow-leopard, "cc", "gcc")
++HOSTCFLAGS += $(call before-snow-leopard, "-traditional-cpp")
++HOSTLDFLAGS    += $(call before-snow-leopard, "-multiply_defined suppress")
+ else
+ HOSTCC		= gcc
+ endif
diff --git a/package/boot/uboot-ar71xx/patches/022-getline_backport.patch b/package/boot/uboot-ar71xx/patches/022-getline_backport.patch
new file mode 100644
index 0000000000..2ce2b614bf
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/022-getline_backport.patch
@@ -0,0 +1,21 @@
+--- a/tools/os_support.c
++++ b/tools/os_support.c
+@@ -23,6 +23,6 @@
+ #ifdef __MINGW32__
+ #include "mingw_support.c"
+ #endif
+-#ifdef __APPLE__
++#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L
+ #include "getline.c"
+ #endif
+--- a/tools/os_support.h
++++ b/tools/os_support.h
+@@ -28,7 +28,7 @@
+ #include "mingw_support.h"
+ #endif
+ 
+-#ifdef __APPLE__
++#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L
+ #include "getline.h"
+ #endif
+ 
diff --git a/package/boot/uboot-ar71xx/patches/030-no_examples.patch b/package/boot/uboot-ar71xx/patches/030-no_examples.patch
new file mode 100644
index 0000000000..65e1289042
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/030-no_examples.patch
@@ -0,0 +1,13 @@
+--- a/Makefile
++++ b/Makefile
+@@ -139,9 +139,7 @@ endif
+ 
+ # The "tools" are needed early, so put this first
+ # Don't include stuff already done in $(LIBS)
+-SUBDIRS	= tools \
+-	  examples/standalone \
+-	  examples/api
++SUBDIRS	= tools
+ 
+ .PHONY : $(SUBDIRS)
+ 
diff --git a/package/boot/uboot-ar71xx/patches/040-no_extern_inline.patch b/package/boot/uboot-ar71xx/patches/040-no_extern_inline.patch
new file mode 100644
index 0000000000..5c01691380
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/040-no_extern_inline.patch
@@ -0,0 +1,112 @@
+--- a/include/asm-mips/io.h
++++ b/include/asm-mips/io.h
+@@ -118,12 +118,12 @@ static inline void set_io_port_base(unsi
+  * Change virtual addresses to physical addresses and vv.
+  * These are trivial on the 1:1 Linux/MIPS mapping
+  */
+-extern inline phys_addr_t virt_to_phys(volatile void * address)
++static inline phys_addr_t virt_to_phys(volatile void * address)
+ {
+ 	return CPHYSADDR(address);
+ }
+ 
+-extern inline void * phys_to_virt(unsigned long address)
++static inline void * phys_to_virt(unsigned long address)
+ {
+ 	return (void *)KSEG0ADDR(address);
+ }
+@@ -131,12 +131,12 @@ extern inline void * phys_to_virt(unsign
+ /*
+  * IO bus memory addresses are also 1:1 with the physical address
+  */
+-extern inline unsigned long virt_to_bus(volatile void * address)
++static inline unsigned long virt_to_bus(volatile void * address)
+ {
+ 	return CPHYSADDR(address);
+ }
+ 
+-extern inline void * bus_to_virt(unsigned long address)
++static inline void * bus_to_virt(unsigned long address)
+ {
+ 	return (void *)KSEG0ADDR(address);
+ }
+@@ -150,12 +150,12 @@ extern unsigned long isa_slot_offset;
+ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+ 
+ #if 0
+-extern inline void *ioremap(unsigned long offset, unsigned long size)
++static inline void *ioremap(unsigned long offset, unsigned long size)
+ {
+ 	return __ioremap(offset, size, _CACHE_UNCACHED);
+ }
+ 
+-extern inline void *ioremap_nocache(unsigned long offset, unsigned long size)
++static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+ {
+ 	return __ioremap(offset, size, _CACHE_UNCACHED);
+ }
+@@ -238,7 +238,7 @@ out:
+  */
+ 
+ #define __OUT1(s) \
+-extern inline void __out##s(unsigned int value, unsigned int port) {
++static inline void __out##s(unsigned int value, unsigned int port) {
+ 
+ #define __OUT2(m) \
+ __asm__ __volatile__ ("s" #m "\t%0,%1(%2)"
+@@ -252,7 +252,7 @@ __OUT1(s##c_p) __OUT2(m) : : "r" (__iosw
+ 	SLOW_DOWN_IO; }
+ 
+ #define __IN1(t,s) \
+-extern __inline__ t __in##s(unsigned int port) { t _v;
++static inline t __in##s(unsigned int port) { t _v;
+ 
+ /*
+  * Required nops will be inserted by the assembler
+@@ -267,7 +267,7 @@ __IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i
+ __IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (mips_io_port_base)); SLOW_DOWN_IO; return __ioswab##w(_v); }
+ 
+ #define __INS1(s) \
+-extern inline void __ins##s(unsigned int port, void * addr, unsigned long count) {
++static inline void __ins##s(unsigned int port, void * addr, unsigned long count) {
+ 
+ #define __INS2(m) \
+ if (count) \
+@@ -295,7 +295,7 @@ __INS1(s##c) __INS2(m) \
+ 	: "$1");}
+ 
+ #define __OUTS1(s) \
+-extern inline void __outs##s(unsigned int port, const void * addr, unsigned long count) {
++static inline void __outs##s(unsigned int port, const void * addr, unsigned long count) {
+ 
+ #define __OUTS2(m) \
+ if (count) \
+--- a/include/asm-mips/system.h
++++ b/include/asm-mips/system.h
+@@ -23,7 +23,7 @@
+ #include <linux/kernel.h>
+ #endif
+ 
+-extern __inline__ void
++static inline void
+ __sti(void)
+ {
+ 	__asm__ __volatile__(
+@@ -47,7 +47,7 @@ __sti(void)
+  * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
+  * no nops at all.
+  */
+-extern __inline__ void
++static inline void
+ __cli(void)
+ {
+ 	__asm__ __volatile__(
+@@ -208,7 +208,7 @@ do { \
+  * For 32 and 64 bit operands we can take advantage of ll and sc.
+  * FIXME: This doesn't work for R3000 machines.
+  */
+-extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
++static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
+ {
+ #ifdef CONFIG_CPU_HAS_LLSC
+ 	unsigned long dummy;
diff --git a/package/boot/uboot-ar71xx/patches/041-no_weak_alias.patch b/package/boot/uboot-ar71xx/patches/041-no_weak_alias.patch
new file mode 100644
index 0000000000..b6f18edff3
--- /dev/null
+++ b/package/boot/uboot-ar71xx/patches/041-no_weak_alias.patch
@@ -0,0 +1,12 @@
+--- a/common/main.c
++++ b/common/main.c
+@@ -47,8 +47,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ /*
+  * Board-specific Platform code can reimplement show_boot_progress () if needed
+  */
+-void inline __show_boot_progress (int val) {}
+-void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
++void __attribute__((weak)) show_boot_progress(int val) {}
+ 
+ #if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
+ extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);		/* for do_reset() prototype */
diff --git a/package/boot/uboot-envtools/Config.in b/package/boot/uboot-envtools/Config.in
new file mode 100644
index 0000000000..8f0078f053
--- /dev/null
+++ b/package/boot/uboot-envtools/Config.in
@@ -0,0 +1,9 @@
+config UBOOT_ENVTOOLS_UBI
+	bool "Support environment in UBI volume"
+	depends on PACKAGE_uboot-envtools
+	default TARGET_oxnas
+	help
+		Add support for reading and writing U-Boot environment
+		stored in UBI volume(s).
+
+		Increases binary size by about 8 kB
diff --git a/package/boot/uboot-envtools/Makefile b/package/boot/uboot-envtools/Makefile
new file mode 100644
index 0000000000..8ded685868
--- /dev/null
+++ b/package/boot/uboot-envtools/Makefile
@@ -0,0 +1,121 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uboot-envtools
+PKG_DISTNAME:=u-boot
+PKG_VERSION:=2015.10-librecmc
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/u-boot-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_DISTNAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=\
+	https://librecmc.org/librecmc/downloads/sources/v1.3.4/ \
+	ftp://ftp.denx.de/pub/u-boot
+PKG_MD5SUM:=5e60d710ce19d2cd20c197ade9bbbc72
+
+PKG_BUILD_DEPENDS:=+fstools
+
+PKG_LICENSE:=GPL-2.0 GPL-2.0+
+PKG_LICENSE_FILES:=Licenses/README
+
+PKG_FLAGS:=nonshared
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/uboot-envtools
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Boot Loaders
+  TITLE:=read/modify U-Boot bootloader environment
+  URL:=http://www.denx.de/wiki/U-Boot
+endef
+
+define Package/uboot-envtools/description
+ This package includes tools to read and modify U-Boot bootloader environment.
+endef
+
+define Package/uboot-envtools/config
+	source "$(SOURCE)/Config.in"
+endef
+
+define Build/Configure
+	touch $(PKG_BUILD_DIR)/include/config.mk
+	touch $(PKG_BUILD_DIR)/include/config.h
+	mkdir -p $(PKG_BUILD_DIR)/include/generated
+	touch $(PKG_BUILD_DIR)/include/generated/autoconf.h
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE="$(TARGET_CROSS)" \
+		TARGET_CFLAGS="$(TARGET_CFLAGS)" \
+		UBI="$(CONFIG_UBOOT_ENVTOOLS_UBI)" \
+		dot-config=0 \
+		HOSTLDFLAGS= \
+		env
+endef
+
+define Package/uboot-envtools/conffiles
+/etc/config/ubootenv
+/etc/fw_env.config
+endef
+
+define Package/uboot-envtools/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/env/fw_printenv $(1)/usr/sbin
+	$(LN) fw_printenv $(1)/usr/sbin/fw_setenv
+	$(INSTALL_DIR) $(1)/lib
+	$(INSTALL_DATA) ./files/uboot-envtools.sh $(1)/lib
+ifneq ($(CONFIG_TARGET_ar71xx),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/ar71xx $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_cns3xxx),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/cns3xxx $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_imx6),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/imx6 $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_ipq806x),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/ipq $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_kirkwood),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/kirkwood $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_lantiq),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/lantiq $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_mvebu),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_BIN) ./files/mvebu $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_mxs),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_BIN) ./files/mxs $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_oxnas),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_BIN) ./files/oxnas $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+ifneq ($(CONFIG_TARGET_ramips),)
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/ramips $(1)/etc/uci-defaults/30_uboot-envtools
+endif
+endef
+
+$(eval $(call BuildPackage,uboot-envtools))
diff --git a/package/boot/uboot-envtools/files/ar71xx b/package/boot/uboot-envtools/files/ar71xx
new file mode 100644
index 0000000000..cf82d2b2de
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ar71xx
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2014 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/ar71xx.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(ar71xx_board_name)
+
+case "$board" in
+alfa-ap120c | \
+all0258n | \
+ap90q | \
+cap324 | \
+cap4200ag | \
+carambola2 | \
+cpe830 | \
+cpe870 | \
+cr3000 | \
+cr5000 | \
+eap300v2 | \
+gl-ar300m | \
+hornet-ub | \
+hornet-ub-x2 | \
+jwap230 | \
+mr1750 | \
+mr1750v2 | \
+mr600 | \
+mr600v2 | \
+mr900 | \
+mr900v2 | \
+nbg6716 | \
+om5p-an | \
+om5p-ac | \
+om5p-acv2 | \
+om5p | \
+tube2h | \
+wndr3700)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000"
+	;;
+alfa-ap96 | \
+all0315n | \
+om2p | \
+om2pv2 | \
+om2p-hs | \
+om2p-hsv2 | \
+om2p-hsv3 | \
+om2p-lc)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x40000"
+	;;
+dr531)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0xf800" "0x10000"
+	;;
+dap-2695-a1 | \
+wzr-hp-ag300h)
+	ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x10000" "0x10000"
+	;;
+qihoo-c301)
+	ubootenv_add_uci_config "/dev/mtd9" "0x0" "0x10000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/cns3xxx b/package/boot/uboot-envtools/files/cns3xxx
new file mode 100644
index 0000000000..a56be15c57
--- /dev/null
+++ b/package/boot/uboot-envtools/files/cns3xxx
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/cns3xxx.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(cns3xxx_board_name)
+
+case "$board" in
+laguna)
+	# Laguna uboot env size/erasesize vary depending on NOR vs SPI FLASH
+	size=$(grep mtd1 /proc/mtd | awk '{print $2}')
+	erasesize=$(grep mtd1 /proc/mtd | awk '{print $3}')
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x$size" "0x$erasesize"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/imx6 b/package/boot/uboot-envtools/files/imx6
new file mode 100644
index 0000000000..d7412b2aaa
--- /dev/null
+++ b/package/boot/uboot-envtools/files/imx6
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2014 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/imx6.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(imx6_board_name)
+
+case "$board" in
+*gw5*)
+	if [ -c /dev/mtd1 ]; then
+		# board boots from NAND
+		ubootenv_add_uci_config /dev/mtd1 0x0 0x20000 0x40000
+		ubootenv_add_uci_config /dev/mtd1 0x80000 0x20000 0x40000
+	else
+		# board boots from microSD
+		ubootenv_add_uci_config /dev/mmcblk0 0xb1400 0x20000 0x20000
+		ubootenv_add_uci_config /dev/mmcblk0 0xd1400 0x20000 0x20000
+	fi
+	;;
+"wandboard")
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x60000" "0x2000" "0x2000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/ipq b/package/boot/uboot-envtools/files/ipq
new file mode 100755
index 0000000000..369f90f2b0
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ipq
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (C) 2016 LEDE
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/ipq806x.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(ipq806x_board_name)
+
+
+case "$board" in
+"ea8500")
+	ubootenv_add_uci_config "/dev/mtd10" "0x0" "0x20000" "0x20000"
+	;;
+"nbg6817")
+	ubootenv_add_uci_config "/dev/mtdblock9" "0x0" "0x10000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/kirkwood b/package/boot/uboot-envtools/files/kirkwood
new file mode 100644
index 0000000000..b4a4d4e1c1
--- /dev/null
+++ b/package/boot/uboot-envtools/files/kirkwood
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Copyright (C) 2012-2014 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/kirkwood.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(kirkwood_board_name)
+
+case "$board" in
+"dockstar" | \
+"guruplug-server-plus" | \
+"ib62x0" | \
+"linksys-viper" | \
+"pogo_e02" | \
+"sheevaplug" | \
+"sheevaplug-esata" )
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
+	;;
+"linksys-audi")
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x4000" "0x4000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/lantiq b/package/boot/uboot-envtools/files/lantiq
new file mode 100644
index 0000000000..a0e0d916be
--- /dev/null
+++ b/package/boot/uboot-envtools/files/lantiq
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/functions/lantiq.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(lantiq_board_name)
+
+case "$board" in
+GIGASX76X)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000" "1"
+	;;
+BTHOMEHUBV2B)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000" "1"
+	;;
+BTHOMEHUBV3A)
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x4000" "0x4000" "1"
+	;;
+P2812HNUF1)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x2000" "0x20000" "1"
+	;;
+WBMR300)
+	idx="$(find_mtd_index ubootconfig)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x2000" "0x1000" "2"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/mvebu b/package/boot/uboot-envtools/files/mvebu
new file mode 100644
index 0000000000..9b826daffc
--- /dev/null
+++ b/package/boot/uboot-envtools/files/mvebu
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Copyright (C) 2014-2016 OpenWrt.org
+# Copyright (C) 2016 LEDE-Project.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/mvebu.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(mvebu_board_name)
+
+case "$board" in
+armada-385-linksys-caiman|armada-385-linksys-cobra|armada-385-linksys-shelby)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x40000"
+	;;
+armada-385-linksys-rango)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
+	;;
+armada-xp-linksys-mamba)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x20000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/mxs b/package/boot/uboot-envtools/files/mxs
new file mode 100644
index 0000000000..ab8b4ef937
--- /dev/null
+++ b/package/boot/uboot-envtools/files/mxs
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/mxs.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(mxs_board_name)
+
+case "$board" in
+duckbill)
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x20000" "0x20000"
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x40000" "0x20000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/oxnas b/package/boot/uboot-envtools/files/oxnas
new file mode 100644
index 0000000000..e560e22fab
--- /dev/null
+++ b/package/boot/uboot-envtools/files/oxnas
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/oxnas.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(oxnas_board_name)
+
+case "$board" in
+akitio | \
+stg212 | \
+kd20)
+	ubootenv_add_uci_config "/dev/ubi0_0" "0x0" "0x4000" "0x1F000" "1"
+	ubootenv_add_uci_config "/dev/ubi0_1" "0x0" "0x4000" "0x1F000" "1"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/ramips b/package/boot/uboot-envtools/files/ramips
new file mode 100644
index 0000000000..f1b669fc0e
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ramips
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/ramips.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(ramips_board_name)
+
+case "$board" in
+all0239-3g | \
+all0256n | \
+all5002)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000"
+	;;
+linkits7688 | \
+linkits7688d | \
+wsr-600 | \
+wsr-1166 | \
+br6425 | \
+miwifi-nano | \
+sk-wb8 | \
+zbt-wg2626)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/uboot-envtools.sh b/package/boot/uboot-envtools/files/uboot-envtools.sh
new file mode 100644
index 0000000000..e21b283677
--- /dev/null
+++ b/package/boot/uboot-envtools/files/uboot-envtools.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+
+ubootenv_add_uci_config() {
+	local dev=$1
+	local offset=$2
+	local envsize=$3
+	local secsize=$4
+	local numsec=$5
+	uci batch <<EOF
+add ubootenv ubootenv
+set ubootenv.@ubootenv[-1].dev='$dev'
+set ubootenv.@ubootenv[-1].offset='$offset'
+set ubootenv.@ubootenv[-1].envsize='$envsize'
+set ubootenv.@ubootenv[-1].secsize='$secsize'
+set ubootenv.@ubootenv[-1].numsec='$numsec'
+EOF
+	uci commit ubootenv
+}
+
+ubootenv_add_app_config() {
+	local dev
+	local offset
+	local envsize
+	local secsize
+	local numsec
+	config_get dev "$1" dev
+	config_get offset "$1" offset
+	config_get envsize "$1" envsize
+	config_get secsize "$1" secsize
+	config_get numsec "$1" numsec
+	echo "$dev $offset $envsize $secsize $numsec" >>/etc/fw_env.config
+}
+
diff --git a/package/boot/uboot-envtools/patches/001-compile.patch b/package/boot/uboot-envtools/patches/001-compile.patch
new file mode 100644
index 0000000000..1705979765
--- /dev/null
+++ b/package/boot/uboot-envtools/patches/001-compile.patch
@@ -0,0 +1,13 @@
+--- a/tools/env/Makefile
++++ b/tools/env/Makefile
+@@ -10,6 +10,10 @@
+ # with "CC" here for the maximum code reuse of scripts/Makefile.host.
+ HOSTCC = $(CC)
+ 
++ifneq ($(TARGET_CFLAGS),)
++HOSTCFLAGS = $(TARGET_CFLAGS)
++endif
++
+ # Compile for a hosted environment on the target
+ HOST_EXTRACFLAGS  = $(patsubst -I%,-idirafter%, $(filter -I%, $(UBOOTINCLUDE))) \
+ 		-idirafter $(srctree)/tools/env \
diff --git a/package/boot/uboot-envtools/patches/200-fw_env_no_aes.patch b/package/boot/uboot-envtools/patches/200-fw_env_no_aes.patch
new file mode 100644
index 0000000000..9c8681ff48
--- /dev/null
+++ b/package/boot/uboot-envtools/patches/200-fw_env_no_aes.patch
@@ -0,0 +1,38 @@
+--- a/tools/env/fw_env.c
++++ b/tools/env/fw_env.c
+@@ -246,7 +246,7 @@ int fw_printenv (int argc, char *argv[])
+ 	int i, n_flag;
+ 	int rc = 0;
+ 
+-	if (argc >= 2 && strcmp(argv[1], "-a") == 0) {
++	if (0 && argc >= 2 && strcmp(argv[1], "-a") == 0) {
+ 		if (argc < 3) {
+ 			fprintf(stderr,
+ 				"## Error: '-a' option requires AES key\n");
+@@ -325,7 +325,7 @@ int fw_printenv (int argc, char *argv[])
+ int fw_env_close(void)
+ {
+ 	int ret;
+-	if (aes_flag) {
++	if (0 && aes_flag) {
+ 		ret = env_aes_cbc_crypt(environment.data, 1);
+ 		if (ret) {
+ 			fprintf(stderr,
+@@ -1223,7 +1223,7 @@ int fw_env_open(void)
+ 
+ 	crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+ 
+-	if (aes_flag) {
++	if (0 && aes_flag) {
+ 		ret = env_aes_cbc_crypt(environment.data, 0);
+ 		if (ret)
+ 			return ret;
+@@ -1280,7 +1280,7 @@ int fw_env_open(void)
+ 
+ 		crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
+ 
+-		if (aes_flag) {
++		if (0 && aes_flag) {
+ 			ret = env_aes_cbc_crypt(redundant->data, 0);
+ 			if (ret)
+ 				return ret;
diff --git a/package/boot/uboot-envtools/patches/300-support-env-in-ubivol-chardev.patch b/package/boot/uboot-envtools/patches/300-support-env-in-ubivol-chardev.patch
new file mode 100644
index 0000000000..75d3804ed4
--- /dev/null
+++ b/package/boot/uboot-envtools/patches/300-support-env-in-ubivol-chardev.patch
@@ -0,0 +1,163 @@
+From 6e2630a0fc872d0db34157972f6dc3941f6d66dd Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 19 May 2014 21:38:01 +0200
+Subject: [PATCH] tools/env: add support for env in ubi volume chardev
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ tools/env/Makefile |  5 ++++
+ tools/env/fw_env.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 71 insertions(+), 10 deletions(-)
+
+--- a/tools/env/Makefile
++++ b/tools/env/Makefile
+@@ -24,6 +24,13 @@ ifeq ($(MTD_VERSION),old)
+ HOST_EXTRACFLAGS += -DMTD_OLD
+ endif
+ 
++ifeq ($(UBI),y)
++HOST_EXTRACFLAGS += -DUBI
++HOST_LOADLIBES = "-Wl,--gc-sections,-lubi-utils"
++else
++HOST_LOADLIBES = "-Wl,--gc-sections"
++endif
++
+ always := fw_printenv
+ hostprogs-y := fw_printenv
+ 
+--- a/tools/env/fw_env.c
++++ b/tools/env/fw_env.c
+@@ -31,6 +31,9 @@
+ # include <mtd/mtd-user.h>
+ #endif
+ 
++#ifdef UBI
++# include <libubi.h>
++#endif
+ #include "fw_env.h"
+ 
+ #include <aes.h>
+@@ -811,6 +814,11 @@ static int flash_write_buf (int dev, int
+ 	off_t top_of_range;	/* end of the last block we may use */
+ 	loff_t blockstart;	/* running start of the current block -
+ 				   MEMGETBADBLOCK needs 64 bits */
++#ifdef UBI
++	libubi_t *libubi = NULL;/* pointer to libubi struct */
++#else
++	void *libubi = NULL;
++#endif
+ 	int rc;
+ 
+ 	/*
+@@ -916,7 +924,30 @@ static int flash_write_buf (int dev, int
+ 			continue;
+ 		}
+ 
+-		if (mtd_type != MTD_ABSENT) {
++#ifdef UBI
++		if (mtd_type == MTD_UBIVOLUME) {
++			struct ubi_vol_info volinfo;
++			libubi = libubi_open();
++			if (libubi)
++				rc = ubi_get_vol_info(libubi,
++					DEVNAME(dev_current), &volinfo);
++			if (libubi && !rc) {
++				erasesize = volinfo.leb_size;
++				int leb = blockstart / erasesize;
++				if (volinfo.type != UBI_STATIC_VOLUME)
++					rc = ubi_leb_change_start(libubi, fd,
++						leb, erasesize);
++				else
++					rc = ubi_update_start(libubi, fd,
++						erasesize);
++			}
++			if (libubi && rc) {
++				libubi_close(libubi);
++				libubi = NULL;
++			}
++		}
++#endif
++		if (!libubi && mtd_type != MTD_ABSENT) {
+ 			erase.start = blockstart;
+ 			ioctl(fd, MEMUNLOCK, &erase);
+ 			/* These do not need an explicit erase cycle */
+@@ -933,7 +964,8 @@ static int flash_write_buf (int dev, int
+ 			fprintf (stderr,
+ 				 "Seek error on %s: %s\n",
+ 				 DEVNAME (dev), strerror (errno));
+-			return -1;
++			processed = -1;
++			goto out;
+ 		}
+ 
+ #ifdef DEBUG
+@@ -943,10 +975,11 @@ static int flash_write_buf (int dev, int
+ 		if (write (fd, data + processed, erasesize) != erasesize) {
+ 			fprintf (stderr, "Write error on %s: %s\n",
+ 				 DEVNAME (dev), strerror (errno));
+-			return -1;
++			processed = -1;
++			goto out;
+ 		}
+ 
+-		if (mtd_type != MTD_ABSENT)
++		if (!libubi && mtd_type != MTD_ABSENT)
+ 			ioctl(fd, MEMLOCK, &erase);
+ 
+ 		processed  += erasesize;
+@@ -957,6 +990,11 @@ static int flash_write_buf (int dev, int
+ 	if (write_total > count)
+ 		free (data);
+ 
++out:
++#ifdef UBI
++	if (libubi)
++		libubi_close(libubi);
++#endif
+ 	return processed;
+ }
+ 
+@@ -1068,12 +1106,8 @@ static int flash_read (int fd)
+ 
+ 	if (S_ISCHR(st.st_mode)) {
+ 		rc = ioctl(fd, MEMGETINFO, &mtdinfo);
+-		if (rc < 0) {
+-			fprintf(stderr, "Cannot get MTD information for %s\n",
+-				DEVNAME(dev_current));
+-			return -1;
+-		}
+-		if (mtdinfo.type != MTD_NORFLASH &&
++		if (!rc &&
++		    mtdinfo.type != MTD_NORFLASH &&
+ 		    mtdinfo.type != MTD_NANDFLASH &&
+ 		    mtdinfo.type != MTD_DATAFLASH &&
+ 		    mtdinfo.type != MTD_UBIVOLUME) {
+@@ -1081,6 +1115,28 @@ static int flash_read (int fd)
+ 				 mtdinfo.type, DEVNAME(dev_current));
+ 			return -1;
+ 		}
++#ifdef UBI
++		if (rc) {
++			libubi_t *libubi;
++			struct ubi_vol_info volinfo;
++			libubi = libubi_open();
++			if (!libubi)
++				return -ENOMEM;
++
++			rc = ubi_get_vol_info(libubi, DEVNAME(dev_current),
++						&volinfo);
++			if (rc) {
++				libubi_close(libubi);
++				return -ENODEV;
++			}
++			memset(&mtdinfo, 0, sizeof(mtdinfo));
++			mtdinfo.type = MTD_UBIVOLUME;
++			mtdinfo.size = volinfo.data_bytes;
++			mtdinfo.erasesize = volinfo.leb_size;
++			mtdinfo.writesize = volinfo.leb_size;
++			libubi_close(libubi);
++		}
++#endif
+ 	} else {
+ 		memset(&mtdinfo, 0, sizeof(mtdinfo));
+ 		mtdinfo.type = MTD_ABSENT;
diff --git a/package/boot/uboot-envtools/patches/400-u-boot-2015.10-stdint.patch b/package/boot/uboot-envtools/patches/400-u-boot-2015.10-stdint.patch
new file mode 100644
index 0000000000..395674fd8b
--- /dev/null
+++ b/package/boot/uboot-envtools/patches/400-u-boot-2015.10-stdint.patch
@@ -0,0 +1,13 @@
+diff -Naur u-boot-2015.10.orig/tools/env/fw_env.c u-boot-2015.10/tools/env/fw_env.c
+--- u-boot-2015.10.orig/tools/env/fw_env.c	2016-06-24 12:42:31.152391850 +0200
++++ u-boot-2015.10/tools/env/fw_env.c	2016-06-24 12:42:59.080391754 +0200
+@@ -21,7 +21,8 @@
+ #include <sys/types.h>
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
+-#include <unistd.h>
++#include <unistd.h>
++#include <stdint.h>
+ 
+ #ifdef MTD_OLD
+ # include <stdint.h>
diff --git a/package/boot/uboot-sunxi/Makefile b/package/boot/uboot-sunxi/Makefile
new file mode 100644
index 0000000000..d411072558
--- /dev/null
+++ b/package/boot/uboot-sunxi/Makefile
@@ -0,0 +1,188 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=u-boot
+PKG_VERSION:=2016.03
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://mirror2.openwrt.org/sources \
+	ftp://ftp.denx.de/pub/u-boot
+
+PKG_MD5SUM:=973c1d896be751321cc3aafa564f64b2
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_LICENSE:=GPL-2.0 GPL-2.0+
+PKG_LICENSE_FILES:=Licenses/README
+
+include $(INCLUDE_DIR)/package.mk
+
+define uboot/Default
+  TITLE:=
+  CONFIG:=
+  IMAGE:=
+endef
+
+define uboot/A10-OLinuXino-Lime
+  TITLE:=U-Boot for the A10 OLinuXino LIME
+endef
+
+define uboot/A13-OLinuXino
+  TITLE:=U-Boot for the A13 OlinuXino
+endef
+
+define uboot/A20-OLinuXino-Lime
+  TITLE:=U-Boot for the A20 OLinuXino LIME
+endef
+
+define uboot/A20-OLinuXino_MICRO
+  TITLE:=U-Boot for A20 OLinuXino MICRO
+endef
+
+define uboot/Bananapi
+  TITLE:=U-Boot for Bananapi
+endef
+
+define uboot/Bananapro
+  TITLE:=U-Boot for Bananapro
+endef
+
+define uboot/Cubieboard
+  TITLE:=U-Boot for Cubieboard
+endef
+
+define uboot/Cubieboard2
+  TITLE:=U-Boot for Cubieboard2
+endef
+
+define uboot/Cubietruck
+  TITLE:=U-Boot for Cubietruck
+endef
+
+define uboot/Hummingbird_A31
+  TITLE:=U-Boot for the Hummingbird A31 board
+endef
+
+define uboot/Mele_M9
+  TITLE:=U-Boot for the Mele M9 (A31)
+endef
+
+define uboot/OLIMEX_A13_SOM
+  TITLE:=U-Boot for the Olimex A13 SOM
+endef
+
+define uboot/Linksprite_pcDuino
+  TITLE:=U-Boot for Linksprite pcDuino
+endef  
+
+define uboot/Linksprite_pcDuino3
+  TITLE:=U-Boot for Linksprite pcDuino3
+endef  
+
+define uboot/Lamobo_R1
+  TITLE:=U-Boot for Lamobo R1
+endef
+
+define uboot/pangolin
+  TITLE:=U-Boot for Theobroma A31-yQ7 devboard
+endef
+
+define uboot/orangepi_plus
+  TITLE:=U-Boot for Orange Pi Plus (H3)
+endef
+
+UBOOTS:= \
+	A10-OLinuXino-Lime \
+	A13-OLinuXino \
+	A20-OLinuXino-Lime \
+	A20-OLinuXino_MICRO \
+	Bananapi \
+	Bananapro \
+	Cubieboard \
+	Cubieboard2 \
+	Cubietruck \
+	Hummingbird_A31 \
+	Mele_M9 \
+	OLIMEX_A13_SOM \
+	Linksprite_pcDuino \
+	Linksprite_pcDuino3 \
+	Lamobo_R1 \
+	orangepi_plus \
+	pangolin
+
+define Package/uboot/template
+define Package/uboot-sunxi-$(1)
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=@TARGET_sunxi
+  TITLE:=$(2)
+  URL:=http://www.denx.de/wiki/U-Boot
+  VARIANT:=$(1)
+  MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>
+endef
+endef
+
+define BuildUBootPackage
+	$(eval $(uboot/Default))
+	$(eval $(uboot/$(1)))
+	$(call Package/uboot/template,$(1),$(TITLE))
+endef
+
+ifdef BUILD_VARIANT
+$(eval $(call uboot/$(BUILD_VARIANT)))
+UBOOT_CONFIG:=$(if $(CONFIG),$(CONFIG),$(BUILD_VARIANT))
+UBOOT_IMAGE:=$(if $(IMAGE),$(IMAGE),openwrt-$(BOARD)-$(BUILD_VARIANT)-u-boot.bin)
+endif
+
+# check if any specialized uEnv bootconfig is required
+ifeq ($(UBOOT_CONFIG),pangolin)
+	UENV:=pangolin
+else
+	UENV:=default
+endif
+
+define Build/Configure
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		USE_PRIVATE_LIBGCC=yes $(UBOOT_CONFIG)_defconfig
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE=$(TARGET_CROSS) \
+		DTCDIR=$(LINUX_DIR)/scripts/dtc/
+endef
+
+define Package/uboot/install/default
+	$(CP) $(PKG_BUILD_DIR)/u-boot.bin \
+		$(KERNEL_BUILD_DIR)/uboot-$(BOARD)-$(1)-u-boot.bin
+	$(CP) $(PKG_BUILD_DIR)/spl/sunxi-spl.bin \
+		$(KERNEL_BUILD_DIR)/uboot-$(BOARD)-$(1)-spl.bin
+	$(CP) $(PKG_BUILD_DIR)/u-boot-sunxi-with-spl.bin \
+		$(KERNEL_BUILD_DIR)/uboot-$(BOARD)-$(1)-u-boot-with-spl.bin
+	$(CP) uEnv-$(UENV).txt \
+		$(KERNEL_BUILD_DIR)/uboot-$(BOARD)-$(1)-uEnv.txt
+	mkimage -C none -A arm -T script -d $(KERNEL_BUILD_DIR)/uboot-$(BOARD)-$(1)-uEnv.txt \
+		$(KERNEL_BUILD_DIR)/uboot-$(BOARD)-$(1)-boot.scr
+endef
+
+define Package/uboot/install/template
+define Package/uboot-sunxi-$(1)/install
+	$(call Package/uboot/install/default,$(2))
+endef
+endef
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call Package/uboot/install/template,$(u),$(u))) \
+)
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call BuildUBootPackage,$(u))) \
+	$(eval $(call BuildPackage,uboot-sunxi-$(u))) \
+)
diff --git a/package/boot/uboot-sunxi/patches/001-use-dtc-in-kernel.patch b/package/boot/uboot-sunxi/patches/001-use-dtc-in-kernel.patch
new file mode 100644
index 0000000000..6471e78656
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/001-use-dtc-in-kernel.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -348,7 +348,7 @@ OBJDUMP		= $(CROSS_COMPILE)objdump
+ AWK		= awk
+ PERL		= perl
+ PYTHON		= python
+-DTC		= dtc
++DTC		= $(DTCDIR)dtc
+ CHECK		= sparse
+ 
+ CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
diff --git a/package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch b/package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch
new file mode 100644
index 0000000000..f29ad12b75
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch
@@ -0,0 +1,21 @@
+--- /dev/null
++++ b/configs/OLIMEX_A13_SOM_defconfig
+@@ -0,0 +1,18 @@
++CONFIG_SPL=y
++CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2"
++CONFIG_DEFAULT_DEVICE_TREE="sun5i-a13-olinuxino"
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_MACH_SUN5I=y
++CONFIG_DRAM_CLK=408
++CONFIG_DRAM_ZQ=123
++CONFIG_DRAM_EMR1=0
++# CONFIG_CMD_IMLS is not set
++# CONFIG_CMD_FLASH is not set
++# CONFIG_CMD_FPGA is not set
++CONFIG_DM_SERIAL=y
++CONFIG_USB=y
++CONFIG_DM_USB=y
++CONFIG_SYS_NS16550=y
++CONFIG_SUNXI_NO_PMIC=y
++CONFIG_USB_EHCI_HCD=y
diff --git a/package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch b/package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch
new file mode 100644
index 0000000000..e5a66d7ebe
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch
@@ -0,0 +1,385 @@
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -152,6 +152,7 @@ dtb-$(CONFIG_MACH_SUN6I) += \
+ 	sun6i-a31-m9.dtb \
+ 	sun6i-a31-mele-a1000g-quad.dtb \
+ 	sun6i-a31-mixtile-loftq.dtb \
++	sun6i-a31-pangolin.dtb \
+ 	sun6i-a31s-cs908.dtb \
+ 	sun6i-a31s-primo81.dtb \
+ 	sun6i-a31s-sinovoip-bpi-m2.dtb
+--- a/arch/arm/dts/sun6i-a31.dtsi
++++ b/arch/arm/dts/sun6i-a31.dtsi
+@@ -643,6 +643,13 @@
+ 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 			};
+ 
++			i2c3_pins_a: i2c3@0 {
++				allwinner,pins = "PB5", "PB6";
++				allwinner,function = "i2c3";
++				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++
+ 			mmc0_pins_a: mmc0@0 {
+ 				allwinner,pins = "PF0", "PF1", "PF2",
+ 						 "PF3", "PF4", "PF5";
+--- /dev/null
++++ b/arch/arm/dts/sun6i-a31-pangolin.dts
+@@ -0,0 +1,292 @@
++/*
++ * Copyright 2015, Theobroma Systems Design und Consulting GmbH
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun6i-a31.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "Theobroma Systems A31 Pangolin";
++	compatible = "tsd,a31-pangolin", "allwinner,sun6i-a31";
++
++	aliases {
++		serial0 = &uart0;
++		serial2 = &uart2;
++		spi0 = &spi0;
++		spi1 = &spi1;
++		spi2 = &spi2;
++		spi3 = &spi3;
++	};
++
++	chosen {
++		stdout-path = "serial2:115200n8";
++	};
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++&ohci2 {
++	status = "okay";
++};
++
++&gmac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&gmac_pins_rgmii_a>;
++	phy = <&phy1>;
++	phy-mode = "rgmii";
++	snps,reset-gpio = <&pio 0 7 GPIO_ACTIVE_LOW>;
++	snps,reset-active-low;
++	snps,reset-delays-us = <0 10000 30000>;
++	status = "okay";
++
++	phy1: ethernet-phy@4 {
++		reg = <4>;
++	};
++};
++
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++};
++
++&i2c3 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c3_pins_a>;
++	status = "okay";
++
++	rtc_twi: rtc@6f {
++	 compatible = "isil,isl1208";
++	 reg = <0x6f>;
++	};
++	fan: fan@18 {
++		compatible = "ti,amc6821";
++		reg = <0x18>;
++		cooling-min-state = <0>;
++		cooling-max-state = <9>;
++		#cooling-cells = <2>;
++	};
++};
++
++&spi0 {
++	status = "okay";
++
++	flash: flash@0 {
++		compatible = "spansion,m25p40";
++		spi-max-frequency = <16000000>;
++		spi-cpol;
++		spi-cpha;
++	};
++};
++
++&spi1 {
++	status = "okay";
++};
++
++&ir {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ir_pins_a>;
++	status = "okay";
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_pangolin>;
++	vmmc-supply = <&reg_vcc3v0>;
++	bus-width = <4>;
++	cd-gpios = <&pio 2 19 GPIO_ACTIVE_LOW>; /* PC19 */
++	status = "okay";
++};
++
++&mmc0_pins_a {
++	/* external pull-ups missing for some pins */
++	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++};
++
++&mmc2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc2_pins_a>;
++	vmmc-supply = <&reg_vcc3v0>;
++	bus-width = <8>;
++	non-removable;
++	status = "okay";
++};
++
++&pio {
++	mmc0_cd_pin_pangolin: mmc0_cd_pin@0 {
++		allwinner,pins = "PC19";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	leds_pins_pangolin: led_pins@0 {
++		allwinner,pins = "PH7", "PC16";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_20_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	mmc2_pins_a: mmc2@0 {
++		allwinner,pins = "PC6","PC7","PC8","PC9","PC10","PC11",
++				"PC12","PC13","PC14","PC15";
++		allwinner,function = "mmc2";
++		allwinner,drive = <SUN4I_PINCTRL_30_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&p2wi {
++	status = "okay";
++
++	axp221: pmic@68 {
++		compatible = "x-powers,axp221";
++		reg = <0x68>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-controller;
++		#interrupt-cells = <1>;
++		dcdc1-supply = <&vcc_3v0>;
++		dcdc5-supply = <&vcc_dram>;
++
++		regulators {
++			x-powers,dcdc-freq = <3000>;
++
++			vcc_3v0: dcdc1 {
++				regulator-always-on;
++				regulator-min-microvolt = <3000000>;
++				regulator-max-microvolt = <3000000>;
++				regulator-name = "vcc-3v0";
++			};
++
++			vdd_cpu: dcdc2 {
++				regulator-always-on;
++				regulator-min-microvolt = <700000>;
++				regulator-max-microvolt = <1320000>;
++				regulator-name = "vdd-cpu";
++			};
++
++			vdd_gpu: dcdc3 {
++				regulator-always-on;
++				regulator-min-microvolt = <700000>;
++				regulator-max-microvolt = <1320000>;
++				regulator-name = "vdd-gpu";
++			};
++
++			vdd_sys_dll: dcdc4 {
++				regulator-always-on;
++				regulator-min-microvolt = <1100000>;
++				regulator-max-microvolt = <1100000>;
++				regulator-name = "vdd-sys-dll";
++			};
++
++			vcc_dram: dcdc5 {
++				regulator-always-on;
++				regulator-min-microvolt = <1500000>;
++				regulator-max-microvolt = <1500000>;
++				regulator-name = "vcc-dram";
++			};
++
++			vcc_wifi: aldo1 {
++				regulator-min-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;
++				regulator-name = "vcc_wifi";
++			};
++
++			avcc: aldo3 {
++				regulator-always-on;
++				regulator-min-microvolt = <3000000>;
++				regulator-max-microvolt = <3000000>;
++				regulator-name = "avcc";
++			};
++		};
++	};
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
++&usb1_vbus_pin_a {
++	allwinner,pins = "PD23";
++};
++
++&reg_usb1_vbus {
++	gpio = <&pio 3 23 GPIO_ACTIVE_HIGH>; /* PD 23 */
++	status = "okay";
++};
++
++&usbphy {
++	status = "okay";
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++};
+--- /dev/null
++++ b/configs/pangolin_defconfig
+@@ -0,0 +1,36 @@
++CONFIG_SUNXI_PANGOLIN=y
++CONFIG_SPL=y
++CONFIG_SYS_EXTRA_OPTIONS="USB_EHCI,SUNXI_GMAC,RGMII"
++CONFIG_DEFAULT_DEVICE_TREE="sun6i-a31-pangolin"
++CONFIG_VIDEO_VGA_VIA_LCD=y
++CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN="PH25"
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_MACH_SUN6I=y
++CONFIG_DRAM_CHANNELS=1
++CONFIG_DRAM_CLK=360
++CONFIG_DRAM_ZQ=70
++CONFIG_AXP_DCDC1_VOLT=3300
++CONFIG_AXP_ALDO1_VOLT=0
++CONFIG_AXP_ALDO2_VOLT=1800
++CONFIG_AXP_ALDO3_VOLT=3000
++CONFIG_AXP_DLDO4_VOLT=3300
++CONFIG_AXP_ELDO1_VOLT=1200
++CONFIG_AXP_ELDO2_VOLT=2500
++CONFIG_AXP_ELDO3_VOLT=3300
++CONFIG_MMC_SUNXI_SLOT_EXTRA=2
++CONFIG_CONS_INDEX=3
++# Vbus gpio for usb1
++CONFIG_USB1_VBUS_PIN=""
++# No Vbus gpio for usb2
++CONFIG_USB2_VBUS_PIN=""
++CONFIG_USB=y
++CONFIG_DM_USB=y
++CONFIG_USB_EHCI=y
++CONFIG_USB_KEYBOARD=y
++CONFIG_DM_ETH=y
++CONFIG_CMD_IMLS=n
++CONFIG_ETH_DESIGNWARE=y
++CONFIG_DM_SPI=y
++CONFIG_DM_SPI_FLASH=y
++CONFIG_SUNXI_SPI=y
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -15,7 +15,6 @@ config SUNXI_GEN_SUN6I
+ 	separate ahb reset control registers, custom pmic bus, new style
+ 	watchdog, etc.
+ 
+-
+ choice
+ 	prompt "Sunxi SoC Variant"
+ 	optional
+@@ -533,6 +532,14 @@ config VIDEO_LCD_PANEL_I2C_SCL
+ 	Set the SCL pin for the LCD i2c interface. This takes a string in the
+ 	format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+ 
++choice
++	prompt "Sunxi Board Variant"
++	optional
++
++config SUNXI_PANGOLIN
++	bool "Theobroma A31 uQ7 Board"
++
++endchoice
+ 
+ # Note only one of these may be selected at a time! But hidden choices are
+ # not supported by Kconfig
diff --git a/package/boot/uboot-sunxi/patches/010-dt-sync-files-with-kernel.patch b/package/boot/uboot-sunxi/patches/010-dt-sync-files-with-kernel.patch
new file mode 100644
index 0000000000..d8fa52c7e5
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/010-dt-sync-files-with-kernel.patch
@@ -0,0 +1,1403 @@
+From 4bb656e9dde2019cb42ac4c27b3a114a801ad127 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 16 Mar 2016 13:41:23 +0100
+Subject: [PATCH] include/dt-bindings: Sync some files with the kernel
+
+This commit syncs the dt-bindings/input/* headers with the kernel (v4.5)
+and adds dt-bindings/clock/sun4i-a10-pll2.h, both are necessary for newer
+sunxi dts files to build.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Reviewed-by: Tom Rini <trini@konsulko.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ include/dt-bindings/clock/sun4i-a10-pll2.h    |  53 ++
+ include/dt-bindings/input/input.h             | 510 +---------------
+ include/dt-bindings/input/linux-event-codes.h | 805 ++++++++++++++++++++++++++
+ 3 files changed, 859 insertions(+), 509 deletions(-)
+ create mode 100644 include/dt-bindings/clock/sun4i-a10-pll2.h
+ create mode 100644 include/dt-bindings/input/linux-event-codes.h
+
+--- /dev/null
++++ b/include/dt-bindings/clock/sun4i-a10-pll2.h
+@@ -0,0 +1,53 @@
++/*
++ * Copyright 2015 Maxime Ripard
++ *
++ * Maxime Ripard <maxime.ripard@free-electrons.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#ifndef __DT_BINDINGS_CLOCK_SUN4I_A10_PLL2_H_
++#define __DT_BINDINGS_CLOCK_SUN4I_A10_PLL2_H_
++
++#define SUN4I_A10_PLL2_1X	0
++#define SUN4I_A10_PLL2_2X	1
++#define SUN4I_A10_PLL2_4X	2
++#define SUN4I_A10_PLL2_8X	3
++
++#endif /* __DT_BINDINGS_CLOCK_SUN4I_A10_PLL2_H_ */
+--- a/include/dt-bindings/input/input.h
++++ b/include/dt-bindings/input/input.h
+@@ -9,515 +9,7 @@
+ #ifndef _DT_BINDINGS_INPUT_INPUT_H
+ #define _DT_BINDINGS_INPUT_INPUT_H
+ 
+-#define KEY_RESERVED		0
+-#define KEY_ESC			1
+-#define KEY_1			2
+-#define KEY_2			3
+-#define KEY_3			4
+-#define KEY_4			5
+-#define KEY_5			6
+-#define KEY_6			7
+-#define KEY_7			8
+-#define KEY_8			9
+-#define KEY_9			10
+-#define KEY_0			11
+-#define KEY_MINUS		12
+-#define KEY_EQUAL		13
+-#define KEY_BACKSPACE		14
+-#define KEY_TAB			15
+-#define KEY_Q			16
+-#define KEY_W			17
+-#define KEY_E			18
+-#define KEY_R			19
+-#define KEY_T			20
+-#define KEY_Y			21
+-#define KEY_U			22
+-#define KEY_I			23
+-#define KEY_O			24
+-#define KEY_P			25
+-#define KEY_LEFTBRACE		26
+-#define KEY_RIGHTBRACE		27
+-#define KEY_ENTER		28
+-#define KEY_LEFTCTRL		29
+-#define KEY_A			30
+-#define KEY_S			31
+-#define KEY_D			32
+-#define KEY_F			33
+-#define KEY_G			34
+-#define KEY_H			35
+-#define KEY_J			36
+-#define KEY_K			37
+-#define KEY_L			38
+-#define KEY_SEMICOLON		39
+-#define KEY_APOSTROPHE		40
+-#define KEY_GRAVE		41
+-#define KEY_LEFTSHIFT		42
+-#define KEY_BACKSLASH		43
+-#define KEY_Z			44
+-#define KEY_X			45
+-#define KEY_C			46
+-#define KEY_V			47
+-#define KEY_B			48
+-#define KEY_N			49
+-#define KEY_M			50
+-#define KEY_COMMA		51
+-#define KEY_DOT			52
+-#define KEY_SLASH		53
+-#define KEY_RIGHTSHIFT		54
+-#define KEY_KPASTERISK		55
+-#define KEY_LEFTALT		56
+-#define KEY_SPACE		57
+-#define KEY_CAPSLOCK		58
+-#define KEY_F1			59
+-#define KEY_F2			60
+-#define KEY_F3			61
+-#define KEY_F4			62
+-#define KEY_F5			63
+-#define KEY_F6			64
+-#define KEY_F7			65
+-#define KEY_F8			66
+-#define KEY_F9			67
+-#define KEY_F10			68
+-#define KEY_NUMLOCK		69
+-#define KEY_SCROLLLOCK		70
+-#define KEY_KP7			71
+-#define KEY_KP8			72
+-#define KEY_KP9			73
+-#define KEY_KPMINUS		74
+-#define KEY_KP4			75
+-#define KEY_KP5			76
+-#define KEY_KP6			77
+-#define KEY_KPPLUS		78
+-#define KEY_KP1			79
+-#define KEY_KP2			80
+-#define KEY_KP3			81
+-#define KEY_KP0			82
+-#define KEY_KPDOT		83
+-
+-#define KEY_ZENKAKUHANKAKU	85
+-#define KEY_102ND		86
+-#define KEY_F11			87
+-#define KEY_F12			88
+-#define KEY_RO			89
+-#define KEY_KATAKANA		90
+-#define KEY_HIRAGANA		91
+-#define KEY_HENKAN		92
+-#define KEY_KATAKANAHIRAGANA	93
+-#define KEY_MUHENKAN		94
+-#define KEY_KPJPCOMMA		95
+-#define KEY_KPENTER		96
+-#define KEY_RIGHTCTRL		97
+-#define KEY_KPSLASH		98
+-#define KEY_SYSRQ		99
+-#define KEY_RIGHTALT		100
+-#define KEY_LINEFEED		101
+-#define KEY_HOME		102
+-#define KEY_UP			103
+-#define KEY_PAGEUP		104
+-#define KEY_LEFT		105
+-#define KEY_RIGHT		106
+-#define KEY_END			107
+-#define KEY_DOWN		108
+-#define KEY_PAGEDOWN		109
+-#define KEY_INSERT		110
+-#define KEY_DELETE		111
+-#define KEY_MACRO		112
+-#define KEY_MUTE		113
+-#define KEY_VOLUMEDOWN		114
+-#define KEY_VOLUMEUP		115
+-#define KEY_POWER		116	/* SC System Power Down */
+-#define KEY_KPEQUAL		117
+-#define KEY_KPPLUSMINUS		118
+-#define KEY_PAUSE		119
+-#define KEY_SCALE		120	/* AL Compiz Scale (Expose) */
+-
+-#define KEY_KPCOMMA		121
+-#define KEY_HANGEUL		122
+-#define KEY_HANGUEL		KEY_HANGEUL
+-#define KEY_HANJA		123
+-#define KEY_YEN			124
+-#define KEY_LEFTMETA		125
+-#define KEY_RIGHTMETA		126
+-#define KEY_COMPOSE		127
+-
+-#define KEY_STOP		128	/* AC Stop */
+-#define KEY_AGAIN		129
+-#define KEY_PROPS		130	/* AC Properties */
+-#define KEY_UNDO		131	/* AC Undo */
+-#define KEY_FRONT		132
+-#define KEY_COPY		133	/* AC Copy */
+-#define KEY_OPEN		134	/* AC Open */
+-#define KEY_PASTE		135	/* AC Paste */
+-#define KEY_FIND		136	/* AC Search */
+-#define KEY_CUT			137	/* AC Cut */
+-#define KEY_HELP		138	/* AL Integrated Help Center */
+-#define KEY_MENU		139	/* Menu (show menu) */
+-#define KEY_CALC		140	/* AL Calculator */
+-#define KEY_SETUP		141
+-#define KEY_SLEEP		142	/* SC System Sleep */
+-#define KEY_WAKEUP		143	/* System Wake Up */
+-#define KEY_FILE		144	/* AL Local Machine Browser */
+-#define KEY_SENDFILE		145
+-#define KEY_DELETEFILE		146
+-#define KEY_XFER		147
+-#define KEY_PROG1		148
+-#define KEY_PROG2		149
+-#define KEY_WWW			150	/* AL Internet Browser */
+-#define KEY_MSDOS		151
+-#define KEY_COFFEE		152	/* AL Terminal Lock/Screensaver */
+-#define KEY_SCREENLOCK		KEY_COFFEE
+-#define KEY_DIRECTION		153
+-#define KEY_CYCLEWINDOWS	154
+-#define KEY_MAIL		155
+-#define KEY_BOOKMARKS		156	/* AC Bookmarks */
+-#define KEY_COMPUTER		157
+-#define KEY_BACK		158	/* AC Back */
+-#define KEY_FORWARD		159	/* AC Forward */
+-#define KEY_CLOSECD		160
+-#define KEY_EJECTCD		161
+-#define KEY_EJECTCLOSECD	162
+-#define KEY_NEXTSONG		163
+-#define KEY_PLAYPAUSE		164
+-#define KEY_PREVIOUSSONG	165
+-#define KEY_STOPCD		166
+-#define KEY_RECORD		167
+-#define KEY_REWIND		168
+-#define KEY_PHONE		169	/* Media Select Telephone */
+-#define KEY_ISO			170
+-#define KEY_CONFIG		171	/* AL Consumer Control Configuration */
+-#define KEY_HOMEPAGE		172	/* AC Home */
+-#define KEY_REFRESH		173	/* AC Refresh */
+-#define KEY_EXIT		174	/* AC Exit */
+-#define KEY_MOVE		175
+-#define KEY_EDIT		176
+-#define KEY_SCROLLUP		177
+-#define KEY_SCROLLDOWN		178
+-#define KEY_KPLEFTPAREN		179
+-#define KEY_KPRIGHTPAREN	180
+-#define KEY_NEW			181	/* AC New */
+-#define KEY_REDO		182	/* AC Redo/Repeat */
+-
+-#define KEY_F13			183
+-#define KEY_F14			184
+-#define KEY_F15			185
+-#define KEY_F16			186
+-#define KEY_F17			187
+-#define KEY_F18			188
+-#define KEY_F19			189
+-#define KEY_F20			190
+-#define KEY_F21			191
+-#define KEY_F22			192
+-#define KEY_F23			193
+-#define KEY_F24			194
+-
+-#define KEY_PLAYCD		200
+-#define KEY_PAUSECD		201
+-#define KEY_PROG3		202
+-#define KEY_PROG4		203
+-#define KEY_DASHBOARD		204	/* AL Dashboard */
+-#define KEY_SUSPEND		205
+-#define KEY_CLOSE		206	/* AC Close */
+-#define KEY_PLAY		207
+-#define KEY_FASTFORWARD		208
+-#define KEY_BASSBOOST		209
+-#define KEY_PRINT		210	/* AC Print */
+-#define KEY_HP			211
+-#define KEY_CAMERA		212
+-#define KEY_SOUND		213
+-#define KEY_QUESTION		214
+-#define KEY_EMAIL		215
+-#define KEY_CHAT		216
+-#define KEY_SEARCH		217
+-#define KEY_CONNECT		218
+-#define KEY_FINANCE		219	/* AL Checkbook/Finance */
+-#define KEY_SPORT		220
+-#define KEY_SHOP		221
+-#define KEY_ALTERASE		222
+-#define KEY_CANCEL		223	/* AC Cancel */
+-#define KEY_BRIGHTNESSDOWN	224
+-#define KEY_BRIGHTNESSUP	225
+-#define KEY_MEDIA		226
+-
+-#define KEY_SWITCHVIDEOMODE	227	/* Cycle between available video
+-					   outputs (Monitor/LCD/TV-out/etc) */
+-#define KEY_KBDILLUMTOGGLE	228
+-#define KEY_KBDILLUMDOWN	229
+-#define KEY_KBDILLUMUP		230
+-
+-#define KEY_SEND		231	/* AC Send */
+-#define KEY_REPLY		232	/* AC Reply */
+-#define KEY_FORWARDMAIL		233	/* AC Forward Msg */
+-#define KEY_SAVE		234	/* AC Save */
+-#define KEY_DOCUMENTS		235
+-
+-#define KEY_BATTERY		236
+-
+-#define KEY_BLUETOOTH		237
+-#define KEY_WLAN		238
+-#define KEY_UWB			239
+-
+-#define KEY_UNKNOWN		240
+-
+-#define KEY_VIDEO_NEXT		241	/* drive next video source */
+-#define KEY_VIDEO_PREV		242	/* drive previous video source */
+-#define KEY_BRIGHTNESS_CYCLE	243	/* brightness up, after max is min */
+-#define KEY_BRIGHTNESS_ZERO	244	/* brightness off, use ambient */
+-#define KEY_DISPLAY_OFF		245	/* display device to off state */
+-
+-#define KEY_WIMAX		246
+-#define KEY_RFKILL		247	/* Key that controls all radios */
+-
+-#define KEY_MICMUTE		248	/* Mute / unmute the microphone */
+-
+-/* Code 255 is reserved for special needs of AT keyboard driver */
+-
+-#define BTN_MISC		0x100
+-#define BTN_0			0x100
+-#define BTN_1			0x101
+-#define BTN_2			0x102
+-#define BTN_3			0x103
+-#define BTN_4			0x104
+-#define BTN_5			0x105
+-#define BTN_6			0x106
+-#define BTN_7			0x107
+-#define BTN_8			0x108
+-#define BTN_9			0x109
+-
+-#define BTN_MOUSE		0x110
+-#define BTN_LEFT		0x110
+-#define BTN_RIGHT		0x111
+-#define BTN_MIDDLE		0x112
+-#define BTN_SIDE		0x113
+-#define BTN_EXTRA		0x114
+-#define BTN_FORWARD		0x115
+-#define BTN_BACK		0x116
+-#define BTN_TASK		0x117
+-
+-#define BTN_JOYSTICK		0x120
+-#define BTN_TRIGGER		0x120
+-#define BTN_THUMB		0x121
+-#define BTN_THUMB2		0x122
+-#define BTN_TOP			0x123
+-#define BTN_TOP2		0x124
+-#define BTN_PINKIE		0x125
+-#define BTN_BASE		0x126
+-#define BTN_BASE2		0x127
+-#define BTN_BASE3		0x128
+-#define BTN_BASE4		0x129
+-#define BTN_BASE5		0x12a
+-#define BTN_BASE6		0x12b
+-#define BTN_DEAD		0x12f
+-
+-#define BTN_GAMEPAD		0x130
+-#define BTN_SOUTH		0x130
+-#define BTN_A			BTN_SOUTH
+-#define BTN_EAST		0x131
+-#define BTN_B			BTN_EAST
+-#define BTN_C			0x132
+-#define BTN_NORTH		0x133
+-#define BTN_X			BTN_NORTH
+-#define BTN_WEST		0x134
+-#define BTN_Y			BTN_WEST
+-#define BTN_Z			0x135
+-#define BTN_TL			0x136
+-#define BTN_TR			0x137
+-#define BTN_TL2			0x138
+-#define BTN_TR2			0x139
+-#define BTN_SELECT		0x13a
+-#define BTN_START		0x13b
+-#define BTN_MODE		0x13c
+-#define BTN_THUMBL		0x13d
+-#define BTN_THUMBR		0x13e
+-
+-#define BTN_DIGI		0x140
+-#define BTN_TOOL_PEN		0x140
+-#define BTN_TOOL_RUBBER		0x141
+-#define BTN_TOOL_BRUSH		0x142
+-#define BTN_TOOL_PENCIL		0x143
+-#define BTN_TOOL_AIRBRUSH	0x144
+-#define BTN_TOOL_FINGER		0x145
+-#define BTN_TOOL_MOUSE		0x146
+-#define BTN_TOOL_LENS		0x147
+-#define BTN_TOOL_QUINTTAP	0x148	/* Five fingers on trackpad */
+-#define BTN_TOUCH		0x14a
+-#define BTN_STYLUS		0x14b
+-#define BTN_STYLUS2		0x14c
+-#define BTN_TOOL_DOUBLETAP	0x14d
+-#define BTN_TOOL_TRIPLETAP	0x14e
+-#define BTN_TOOL_QUADTAP	0x14f	/* Four fingers on trackpad */
+-
+-#define BTN_WHEEL		0x150
+-#define BTN_GEAR_DOWN		0x150
+-#define BTN_GEAR_UP		0x151
+-
+-#define KEY_OK			0x160
+-#define KEY_SELECT		0x161
+-#define KEY_GOTO		0x162
+-#define KEY_CLEAR		0x163
+-#define KEY_POWER2		0x164
+-#define KEY_OPTION		0x165
+-#define KEY_INFO		0x166	/* AL OEM Features/Tips/Tutorial */
+-#define KEY_TIME		0x167
+-#define KEY_VENDOR		0x168
+-#define KEY_ARCHIVE		0x169
+-#define KEY_PROGRAM		0x16a	/* Media Select Program Guide */
+-#define KEY_CHANNEL		0x16b
+-#define KEY_FAVORITES		0x16c
+-#define KEY_EPG			0x16d
+-#define KEY_PVR			0x16e	/* Media Select Home */
+-#define KEY_MHP			0x16f
+-#define KEY_LANGUAGE		0x170
+-#define KEY_TITLE		0x171
+-#define KEY_SUBTITLE		0x172
+-#define KEY_ANGLE		0x173
+-#define KEY_ZOOM		0x174
+-#define KEY_MODE		0x175
+-#define KEY_KEYBOARD		0x176
+-#define KEY_SCREEN		0x177
+-#define KEY_PC			0x178	/* Media Select Computer */
+-#define KEY_TV			0x179	/* Media Select TV */
+-#define KEY_TV2			0x17a	/* Media Select Cable */
+-#define KEY_VCR			0x17b	/* Media Select VCR */
+-#define KEY_VCR2		0x17c	/* VCR Plus */
+-#define KEY_SAT			0x17d	/* Media Select Satellite */
+-#define KEY_SAT2		0x17e
+-#define KEY_CD			0x17f	/* Media Select CD */
+-#define KEY_TAPE		0x180	/* Media Select Tape */
+-#define KEY_RADIO		0x181
+-#define KEY_TUNER		0x182	/* Media Select Tuner */
+-#define KEY_PLAYER		0x183
+-#define KEY_TEXT		0x184
+-#define KEY_DVD			0x185	/* Media Select DVD */
+-#define KEY_AUX			0x186
+-#define KEY_MP3			0x187
+-#define KEY_AUDIO		0x188	/* AL Audio Browser */
+-#define KEY_VIDEO		0x189	/* AL Movie Browser */
+-#define KEY_DIRECTORY		0x18a
+-#define KEY_LIST		0x18b
+-#define KEY_MEMO		0x18c	/* Media Select Messages */
+-#define KEY_CALENDAR		0x18d
+-#define KEY_RED			0x18e
+-#define KEY_GREEN		0x18f
+-#define KEY_YELLOW		0x190
+-#define KEY_BLUE		0x191
+-#define KEY_CHANNELUP		0x192	/* Channel Increment */
+-#define KEY_CHANNELDOWN		0x193	/* Channel Decrement */
+-#define KEY_FIRST		0x194
+-#define KEY_LAST		0x195	/* Recall Last */
+-#define KEY_AB			0x196
+-#define KEY_NEXT		0x197
+-#define KEY_RESTART		0x198
+-#define KEY_SLOW		0x199
+-#define KEY_SHUFFLE		0x19a
+-#define KEY_BREAK		0x19b
+-#define KEY_PREVIOUS		0x19c
+-#define KEY_DIGITS		0x19d
+-#define KEY_TEEN		0x19e
+-#define KEY_TWEN		0x19f
+-#define KEY_VIDEOPHONE		0x1a0	/* Media Select Video Phone */
+-#define KEY_GAMES		0x1a1	/* Media Select Games */
+-#define KEY_ZOOMIN		0x1a2	/* AC Zoom In */
+-#define KEY_ZOOMOUT		0x1a3	/* AC Zoom Out */
+-#define KEY_ZOOMRESET		0x1a4	/* AC Zoom */
+-#define KEY_WORDPROCESSOR	0x1a5	/* AL Word Processor */
+-#define KEY_EDITOR		0x1a6	/* AL Text Editor */
+-#define KEY_SPREADSHEET		0x1a7	/* AL Spreadsheet */
+-#define KEY_GRAPHICSEDITOR	0x1a8	/* AL Graphics Editor */
+-#define KEY_PRESENTATION	0x1a9	/* AL Presentation App */
+-#define KEY_DATABASE		0x1aa	/* AL Database App */
+-#define KEY_NEWS		0x1ab	/* AL Newsreader */
+-#define KEY_VOICEMAIL		0x1ac	/* AL Voicemail */
+-#define KEY_ADDRESSBOOK		0x1ad	/* AL Contacts/Address Book */
+-#define KEY_MESSENGER		0x1ae	/* AL Instant Messaging */
+-#define KEY_DISPLAYTOGGLE	0x1af	/* Turn display (LCD) on and off */
+-#define KEY_SPELLCHECK		0x1b0   /* AL Spell Check */
+-#define KEY_LOGOFF		0x1b1   /* AL Logoff */
+-
+-#define KEY_DOLLAR		0x1b2
+-#define KEY_EURO		0x1b3
+-
+-#define KEY_FRAMEBACK		0x1b4	/* Consumer - transport controls */
+-#define KEY_FRAMEFORWARD	0x1b5
+-#define KEY_CONTEXT_MENU	0x1b6	/* GenDesc - system context menu */
+-#define KEY_MEDIA_REPEAT	0x1b7	/* Consumer - transport control */
+-#define KEY_10CHANNELSUP	0x1b8	/* 10 channels up (10+) */
+-#define KEY_10CHANNELSDOWN	0x1b9	/* 10 channels down (10-) */
+-#define KEY_IMAGES		0x1ba	/* AL Image Browser */
+-
+-#define KEY_DEL_EOL		0x1c0
+-#define KEY_DEL_EOS		0x1c1
+-#define KEY_INS_LINE		0x1c2
+-#define KEY_DEL_LINE		0x1c3
+-
+-#define KEY_FN			0x1d0
+-#define KEY_FN_ESC		0x1d1
+-#define KEY_FN_F1		0x1d2
+-#define KEY_FN_F2		0x1d3
+-#define KEY_FN_F3		0x1d4
+-#define KEY_FN_F4		0x1d5
+-#define KEY_FN_F5		0x1d6
+-#define KEY_FN_F6		0x1d7
+-#define KEY_FN_F7		0x1d8
+-#define KEY_FN_F8		0x1d9
+-#define KEY_FN_F9		0x1da
+-#define KEY_FN_F10		0x1db
+-#define KEY_FN_F11		0x1dc
+-#define KEY_FN_F12		0x1dd
+-#define KEY_FN_1		0x1de
+-#define KEY_FN_2		0x1df
+-#define KEY_FN_D		0x1e0
+-#define KEY_FN_E		0x1e1
+-#define KEY_FN_F		0x1e2
+-#define KEY_FN_S		0x1e3
+-#define KEY_FN_B		0x1e4
+-
+-#define KEY_BRL_DOT1		0x1f1
+-#define KEY_BRL_DOT2		0x1f2
+-#define KEY_BRL_DOT3		0x1f3
+-#define KEY_BRL_DOT4		0x1f4
+-#define KEY_BRL_DOT5		0x1f5
+-#define KEY_BRL_DOT6		0x1f6
+-#define KEY_BRL_DOT7		0x1f7
+-#define KEY_BRL_DOT8		0x1f8
+-#define KEY_BRL_DOT9		0x1f9
+-#define KEY_BRL_DOT10		0x1fa
+-
+-#define KEY_NUMERIC_0		0x200	/* used by phones, remote controls, */
+-#define KEY_NUMERIC_1		0x201	/* and other keypads */
+-#define KEY_NUMERIC_2		0x202
+-#define KEY_NUMERIC_3		0x203
+-#define KEY_NUMERIC_4		0x204
+-#define KEY_NUMERIC_5		0x205
+-#define KEY_NUMERIC_6		0x206
+-#define KEY_NUMERIC_7		0x207
+-#define KEY_NUMERIC_8		0x208
+-#define KEY_NUMERIC_9		0x209
+-#define KEY_NUMERIC_STAR	0x20a
+-#define KEY_NUMERIC_POUND	0x20b
+-
+-#define KEY_CAMERA_FOCUS	0x210
+-#define KEY_WPS_BUTTON		0x211	/* WiFi Protected Setup key */
+-
+-#define KEY_TOUCHPAD_TOGGLE	0x212	/* Request switch touchpad on or off */
+-#define KEY_TOUCHPAD_ON		0x213
+-#define KEY_TOUCHPAD_OFF	0x214
+-
+-#define KEY_CAMERA_ZOOMIN	0x215
+-#define KEY_CAMERA_ZOOMOUT	0x216
+-#define KEY_CAMERA_UP		0x217
+-#define KEY_CAMERA_DOWN		0x218
+-#define KEY_CAMERA_LEFT		0x219
+-#define KEY_CAMERA_RIGHT	0x21a
+-
+-#define KEY_ATTENDANT_ON	0x21b
+-#define KEY_ATTENDANT_OFF	0x21c
+-#define KEY_ATTENDANT_TOGGLE	0x21d	/* Attendant call on or off */
+-#define KEY_LIGHTS_TOGGLE	0x21e	/* Reading light on or off */
+-
+-#define BTN_DPAD_UP		0x220
+-#define BTN_DPAD_DOWN		0x221
+-#define BTN_DPAD_LEFT		0x222
+-#define BTN_DPAD_RIGHT		0x223
++#include "linux-event-codes.h"
+ 
+ #define MATRIX_KEY(row, col, code)	\
+ 	((((row) & 0xFF) << 24) | (((col) & 0xFF) << 16) | ((code) & 0xFFFF))
+--- /dev/null
++++ b/include/dt-bindings/input/linux-event-codes.h
+@@ -0,0 +1,805 @@
++/*
++ * Input event codes
++ *
++ *    *** IMPORTANT ***
++ * This file is not only included from C-code but also from devicetree source
++ * files. As such this file MUST only contain comments and defines.
++ *
++ * Copyright (c) 1999-2002 Vojtech Pavlik
++ * Copyright (c) 2015 Hans de Goede <hdegoede@redhat.com>
++ *
++ * 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.
++ */
++#ifndef _UAPI_INPUT_EVENT_CODES_H
++#define _UAPI_INPUT_EVENT_CODES_H
++
++/*
++ * Device properties and quirks
++ */
++
++#define INPUT_PROP_POINTER		0x00	/* needs a pointer */
++#define INPUT_PROP_DIRECT		0x01	/* direct input devices */
++#define INPUT_PROP_BUTTONPAD		0x02	/* has button(s) under pad */
++#define INPUT_PROP_SEMI_MT		0x03	/* touch rectangle only */
++#define INPUT_PROP_TOPBUTTONPAD		0x04	/* softbuttons at top of pad */
++#define INPUT_PROP_POINTING_STICK	0x05	/* is a pointing stick */
++#define INPUT_PROP_ACCELEROMETER	0x06	/* has accelerometer */
++
++#define INPUT_PROP_MAX			0x1f
++#define INPUT_PROP_CNT			(INPUT_PROP_MAX + 1)
++
++/*
++ * Event types
++ */
++
++#define EV_SYN			0x00
++#define EV_KEY			0x01
++#define EV_REL			0x02
++#define EV_ABS			0x03
++#define EV_MSC			0x04
++#define EV_SW			0x05
++#define EV_LED			0x11
++#define EV_SND			0x12
++#define EV_REP			0x14
++#define EV_FF			0x15
++#define EV_PWR			0x16
++#define EV_FF_STATUS		0x17
++#define EV_MAX			0x1f
++#define EV_CNT			(EV_MAX+1)
++
++/*
++ * Synchronization events.
++ */
++
++#define SYN_REPORT		0
++#define SYN_CONFIG		1
++#define SYN_MT_REPORT		2
++#define SYN_DROPPED		3
++#define SYN_MAX			0xf
++#define SYN_CNT			(SYN_MAX+1)
++
++/*
++ * Keys and buttons
++ *
++ * Most of the keys/buttons are modeled after USB HUT 1.12
++ * (see http://www.usb.org/developers/hidpage).
++ * Abbreviations in the comments:
++ * AC - Application Control
++ * AL - Application Launch Button
++ * SC - System Control
++ */
++
++#define KEY_RESERVED		0
++#define KEY_ESC			1
++#define KEY_1			2
++#define KEY_2			3
++#define KEY_3			4
++#define KEY_4			5
++#define KEY_5			6
++#define KEY_6			7
++#define KEY_7			8
++#define KEY_8			9
++#define KEY_9			10
++#define KEY_0			11
++#define KEY_MINUS		12
++#define KEY_EQUAL		13
++#define KEY_BACKSPACE		14
++#define KEY_TAB			15
++#define KEY_Q			16
++#define KEY_W			17
++#define KEY_E			18
++#define KEY_R			19
++#define KEY_T			20
++#define KEY_Y			21
++#define KEY_U			22
++#define KEY_I			23
++#define KEY_O			24
++#define KEY_P			25
++#define KEY_LEFTBRACE		26
++#define KEY_RIGHTBRACE		27
++#define KEY_ENTER		28
++#define KEY_LEFTCTRL		29
++#define KEY_A			30
++#define KEY_S			31
++#define KEY_D			32
++#define KEY_F			33
++#define KEY_G			34
++#define KEY_H			35
++#define KEY_J			36
++#define KEY_K			37
++#define KEY_L			38
++#define KEY_SEMICOLON		39
++#define KEY_APOSTROPHE		40
++#define KEY_GRAVE		41
++#define KEY_LEFTSHIFT		42
++#define KEY_BACKSLASH		43
++#define KEY_Z			44
++#define KEY_X			45
++#define KEY_C			46
++#define KEY_V			47
++#define KEY_B			48
++#define KEY_N			49
++#define KEY_M			50
++#define KEY_COMMA		51
++#define KEY_DOT			52
++#define KEY_SLASH		53
++#define KEY_RIGHTSHIFT		54
++#define KEY_KPASTERISK		55
++#define KEY_LEFTALT		56
++#define KEY_SPACE		57
++#define KEY_CAPSLOCK		58
++#define KEY_F1			59
++#define KEY_F2			60
++#define KEY_F3			61
++#define KEY_F4			62
++#define KEY_F5			63
++#define KEY_F6			64
++#define KEY_F7			65
++#define KEY_F8			66
++#define KEY_F9			67
++#define KEY_F10			68
++#define KEY_NUMLOCK		69
++#define KEY_SCROLLLOCK		70
++#define KEY_KP7			71
++#define KEY_KP8			72
++#define KEY_KP9			73
++#define KEY_KPMINUS		74
++#define KEY_KP4			75
++#define KEY_KP5			76
++#define KEY_KP6			77
++#define KEY_KPPLUS		78
++#define KEY_KP1			79
++#define KEY_KP2			80
++#define KEY_KP3			81
++#define KEY_KP0			82
++#define KEY_KPDOT		83
++
++#define KEY_ZENKAKUHANKAKU	85
++#define KEY_102ND		86
++#define KEY_F11			87
++#define KEY_F12			88
++#define KEY_RO			89
++#define KEY_KATAKANA		90
++#define KEY_HIRAGANA		91
++#define KEY_HENKAN		92
++#define KEY_KATAKANAHIRAGANA	93
++#define KEY_MUHENKAN		94
++#define KEY_KPJPCOMMA		95
++#define KEY_KPENTER		96
++#define KEY_RIGHTCTRL		97
++#define KEY_KPSLASH		98
++#define KEY_SYSRQ		99
++#define KEY_RIGHTALT		100
++#define KEY_LINEFEED		101
++#define KEY_HOME		102
++#define KEY_UP			103
++#define KEY_PAGEUP		104
++#define KEY_LEFT		105
++#define KEY_RIGHT		106
++#define KEY_END			107
++#define KEY_DOWN		108
++#define KEY_PAGEDOWN		109
++#define KEY_INSERT		110
++#define KEY_DELETE		111
++#define KEY_MACRO		112
++#define KEY_MUTE		113
++#define KEY_VOLUMEDOWN		114
++#define KEY_VOLUMEUP		115
++#define KEY_POWER		116	/* SC System Power Down */
++#define KEY_KPEQUAL		117
++#define KEY_KPPLUSMINUS		118
++#define KEY_PAUSE		119
++#define KEY_SCALE		120	/* AL Compiz Scale (Expose) */
++
++#define KEY_KPCOMMA		121
++#define KEY_HANGEUL		122
++#define KEY_HANGUEL		KEY_HANGEUL
++#define KEY_HANJA		123
++#define KEY_YEN			124
++#define KEY_LEFTMETA		125
++#define KEY_RIGHTMETA		126
++#define KEY_COMPOSE		127
++
++#define KEY_STOP		128	/* AC Stop */
++#define KEY_AGAIN		129
++#define KEY_PROPS		130	/* AC Properties */
++#define KEY_UNDO		131	/* AC Undo */
++#define KEY_FRONT		132
++#define KEY_COPY		133	/* AC Copy */
++#define KEY_OPEN		134	/* AC Open */
++#define KEY_PASTE		135	/* AC Paste */
++#define KEY_FIND		136	/* AC Search */
++#define KEY_CUT			137	/* AC Cut */
++#define KEY_HELP		138	/* AL Integrated Help Center */
++#define KEY_MENU		139	/* Menu (show menu) */
++#define KEY_CALC		140	/* AL Calculator */
++#define KEY_SETUP		141
++#define KEY_SLEEP		142	/* SC System Sleep */
++#define KEY_WAKEUP		143	/* System Wake Up */
++#define KEY_FILE		144	/* AL Local Machine Browser */
++#define KEY_SENDFILE		145
++#define KEY_DELETEFILE		146
++#define KEY_XFER		147
++#define KEY_PROG1		148
++#define KEY_PROG2		149
++#define KEY_WWW			150	/* AL Internet Browser */
++#define KEY_MSDOS		151
++#define KEY_COFFEE		152	/* AL Terminal Lock/Screensaver */
++#define KEY_SCREENLOCK		KEY_COFFEE
++#define KEY_ROTATE_DISPLAY	153	/* Display orientation for e.g. tablets */
++#define KEY_DIRECTION		KEY_ROTATE_DISPLAY
++#define KEY_CYCLEWINDOWS	154
++#define KEY_MAIL		155
++#define KEY_BOOKMARKS		156	/* AC Bookmarks */
++#define KEY_COMPUTER		157
++#define KEY_BACK		158	/* AC Back */
++#define KEY_FORWARD		159	/* AC Forward */
++#define KEY_CLOSECD		160
++#define KEY_EJECTCD		161
++#define KEY_EJECTCLOSECD	162
++#define KEY_NEXTSONG		163
++#define KEY_PLAYPAUSE		164
++#define KEY_PREVIOUSSONG	165
++#define KEY_STOPCD		166
++#define KEY_RECORD		167
++#define KEY_REWIND		168
++#define KEY_PHONE		169	/* Media Select Telephone */
++#define KEY_ISO			170
++#define KEY_CONFIG		171	/* AL Consumer Control Configuration */
++#define KEY_HOMEPAGE		172	/* AC Home */
++#define KEY_REFRESH		173	/* AC Refresh */
++#define KEY_EXIT		174	/* AC Exit */
++#define KEY_MOVE		175
++#define KEY_EDIT		176
++#define KEY_SCROLLUP		177
++#define KEY_SCROLLDOWN		178
++#define KEY_KPLEFTPAREN		179
++#define KEY_KPRIGHTPAREN	180
++#define KEY_NEW			181	/* AC New */
++#define KEY_REDO		182	/* AC Redo/Repeat */
++
++#define KEY_F13			183
++#define KEY_F14			184
++#define KEY_F15			185
++#define KEY_F16			186
++#define KEY_F17			187
++#define KEY_F18			188
++#define KEY_F19			189
++#define KEY_F20			190
++#define KEY_F21			191
++#define KEY_F22			192
++#define KEY_F23			193
++#define KEY_F24			194
++
++#define KEY_PLAYCD		200
++#define KEY_PAUSECD		201
++#define KEY_PROG3		202
++#define KEY_PROG4		203
++#define KEY_DASHBOARD		204	/* AL Dashboard */
++#define KEY_SUSPEND		205
++#define KEY_CLOSE		206	/* AC Close */
++#define KEY_PLAY		207
++#define KEY_FASTFORWARD		208
++#define KEY_BASSBOOST		209
++#define KEY_PRINT		210	/* AC Print */
++#define KEY_HP			211
++#define KEY_CAMERA		212
++#define KEY_SOUND		213
++#define KEY_QUESTION		214
++#define KEY_EMAIL		215
++#define KEY_CHAT		216
++#define KEY_SEARCH		217
++#define KEY_CONNECT		218
++#define KEY_FINANCE		219	/* AL Checkbook/Finance */
++#define KEY_SPORT		220
++#define KEY_SHOP		221
++#define KEY_ALTERASE		222
++#define KEY_CANCEL		223	/* AC Cancel */
++#define KEY_BRIGHTNESSDOWN	224
++#define KEY_BRIGHTNESSUP	225
++#define KEY_MEDIA		226
++
++#define KEY_SWITCHVIDEOMODE	227	/* Cycle between available video
++					   outputs (Monitor/LCD/TV-out/etc) */
++#define KEY_KBDILLUMTOGGLE	228
++#define KEY_KBDILLUMDOWN	229
++#define KEY_KBDILLUMUP		230
++
++#define KEY_SEND		231	/* AC Send */
++#define KEY_REPLY		232	/* AC Reply */
++#define KEY_FORWARDMAIL		233	/* AC Forward Msg */
++#define KEY_SAVE		234	/* AC Save */
++#define KEY_DOCUMENTS		235
++
++#define KEY_BATTERY		236
++
++#define KEY_BLUETOOTH		237
++#define KEY_WLAN		238
++#define KEY_UWB			239
++
++#define KEY_UNKNOWN		240
++
++#define KEY_VIDEO_NEXT		241	/* drive next video source */
++#define KEY_VIDEO_PREV		242	/* drive previous video source */
++#define KEY_BRIGHTNESS_CYCLE	243	/* brightness up, after max is min */
++#define KEY_BRIGHTNESS_AUTO	244	/* Set Auto Brightness: manual
++					  brightness control is off,
++					  rely on ambient */
++#define KEY_BRIGHTNESS_ZERO	KEY_BRIGHTNESS_AUTO
++#define KEY_DISPLAY_OFF		245	/* display device to off state */
++
++#define KEY_WWAN		246	/* Wireless WAN (LTE, UMTS, GSM, etc.) */
++#define KEY_WIMAX		KEY_WWAN
++#define KEY_RFKILL		247	/* Key that controls all radios */
++
++#define KEY_MICMUTE		248	/* Mute / unmute the microphone */
++
++/* Code 255 is reserved for special needs of AT keyboard driver */
++
++#define BTN_MISC		0x100
++#define BTN_0			0x100
++#define BTN_1			0x101
++#define BTN_2			0x102
++#define BTN_3			0x103
++#define BTN_4			0x104
++#define BTN_5			0x105
++#define BTN_6			0x106
++#define BTN_7			0x107
++#define BTN_8			0x108
++#define BTN_9			0x109
++
++#define BTN_MOUSE		0x110
++#define BTN_LEFT		0x110
++#define BTN_RIGHT		0x111
++#define BTN_MIDDLE		0x112
++#define BTN_SIDE		0x113
++#define BTN_EXTRA		0x114
++#define BTN_FORWARD		0x115
++#define BTN_BACK		0x116
++#define BTN_TASK		0x117
++
++#define BTN_JOYSTICK		0x120
++#define BTN_TRIGGER		0x120
++#define BTN_THUMB		0x121
++#define BTN_THUMB2		0x122
++#define BTN_TOP			0x123
++#define BTN_TOP2		0x124
++#define BTN_PINKIE		0x125
++#define BTN_BASE		0x126
++#define BTN_BASE2		0x127
++#define BTN_BASE3		0x128
++#define BTN_BASE4		0x129
++#define BTN_BASE5		0x12a
++#define BTN_BASE6		0x12b
++#define BTN_DEAD		0x12f
++
++#define BTN_GAMEPAD		0x130
++#define BTN_SOUTH		0x130
++#define BTN_A			BTN_SOUTH
++#define BTN_EAST		0x131
++#define BTN_B			BTN_EAST
++#define BTN_C			0x132
++#define BTN_NORTH		0x133
++#define BTN_X			BTN_NORTH
++#define BTN_WEST		0x134
++#define BTN_Y			BTN_WEST
++#define BTN_Z			0x135
++#define BTN_TL			0x136
++#define BTN_TR			0x137
++#define BTN_TL2			0x138
++#define BTN_TR2			0x139
++#define BTN_SELECT		0x13a
++#define BTN_START		0x13b
++#define BTN_MODE		0x13c
++#define BTN_THUMBL		0x13d
++#define BTN_THUMBR		0x13e
++
++#define BTN_DIGI		0x140
++#define BTN_TOOL_PEN		0x140
++#define BTN_TOOL_RUBBER		0x141
++#define BTN_TOOL_BRUSH		0x142
++#define BTN_TOOL_PENCIL		0x143
++#define BTN_TOOL_AIRBRUSH	0x144
++#define BTN_TOOL_FINGER		0x145
++#define BTN_TOOL_MOUSE		0x146
++#define BTN_TOOL_LENS		0x147
++#define BTN_TOOL_QUINTTAP	0x148	/* Five fingers on trackpad */
++#define BTN_TOUCH		0x14a
++#define BTN_STYLUS		0x14b
++#define BTN_STYLUS2		0x14c
++#define BTN_TOOL_DOUBLETAP	0x14d
++#define BTN_TOOL_TRIPLETAP	0x14e
++#define BTN_TOOL_QUADTAP	0x14f	/* Four fingers on trackpad */
++
++#define BTN_WHEEL		0x150
++#define BTN_GEAR_DOWN		0x150
++#define BTN_GEAR_UP		0x151
++
++#define KEY_OK			0x160
++#define KEY_SELECT		0x161
++#define KEY_GOTO		0x162
++#define KEY_CLEAR		0x163
++#define KEY_POWER2		0x164
++#define KEY_OPTION		0x165
++#define KEY_INFO		0x166	/* AL OEM Features/Tips/Tutorial */
++#define KEY_TIME		0x167
++#define KEY_VENDOR		0x168
++#define KEY_ARCHIVE		0x169
++#define KEY_PROGRAM		0x16a	/* Media Select Program Guide */
++#define KEY_CHANNEL		0x16b
++#define KEY_FAVORITES		0x16c
++#define KEY_EPG			0x16d
++#define KEY_PVR			0x16e	/* Media Select Home */
++#define KEY_MHP			0x16f
++#define KEY_LANGUAGE		0x170
++#define KEY_TITLE		0x171
++#define KEY_SUBTITLE		0x172
++#define KEY_ANGLE		0x173
++#define KEY_ZOOM		0x174
++#define KEY_MODE		0x175
++#define KEY_KEYBOARD		0x176
++#define KEY_SCREEN		0x177
++#define KEY_PC			0x178	/* Media Select Computer */
++#define KEY_TV			0x179	/* Media Select TV */
++#define KEY_TV2			0x17a	/* Media Select Cable */
++#define KEY_VCR			0x17b	/* Media Select VCR */
++#define KEY_VCR2		0x17c	/* VCR Plus */
++#define KEY_SAT			0x17d	/* Media Select Satellite */
++#define KEY_SAT2		0x17e
++#define KEY_CD			0x17f	/* Media Select CD */
++#define KEY_TAPE		0x180	/* Media Select Tape */
++#define KEY_RADIO		0x181
++#define KEY_TUNER		0x182	/* Media Select Tuner */
++#define KEY_PLAYER		0x183
++#define KEY_TEXT		0x184
++#define KEY_DVD			0x185	/* Media Select DVD */
++#define KEY_AUX			0x186
++#define KEY_MP3			0x187
++#define KEY_AUDIO		0x188	/* AL Audio Browser */
++#define KEY_VIDEO		0x189	/* AL Movie Browser */
++#define KEY_DIRECTORY		0x18a
++#define KEY_LIST		0x18b
++#define KEY_MEMO		0x18c	/* Media Select Messages */
++#define KEY_CALENDAR		0x18d
++#define KEY_RED			0x18e
++#define KEY_GREEN		0x18f
++#define KEY_YELLOW		0x190
++#define KEY_BLUE		0x191
++#define KEY_CHANNELUP		0x192	/* Channel Increment */
++#define KEY_CHANNELDOWN		0x193	/* Channel Decrement */
++#define KEY_FIRST		0x194
++#define KEY_LAST		0x195	/* Recall Last */
++#define KEY_AB			0x196
++#define KEY_NEXT		0x197
++#define KEY_RESTART		0x198
++#define KEY_SLOW		0x199
++#define KEY_SHUFFLE		0x19a
++#define KEY_BREAK		0x19b
++#define KEY_PREVIOUS		0x19c
++#define KEY_DIGITS		0x19d
++#define KEY_TEEN		0x19e
++#define KEY_TWEN		0x19f
++#define KEY_VIDEOPHONE		0x1a0	/* Media Select Video Phone */
++#define KEY_GAMES		0x1a1	/* Media Select Games */
++#define KEY_ZOOMIN		0x1a2	/* AC Zoom In */
++#define KEY_ZOOMOUT		0x1a3	/* AC Zoom Out */
++#define KEY_ZOOMRESET		0x1a4	/* AC Zoom */
++#define KEY_WORDPROCESSOR	0x1a5	/* AL Word Processor */
++#define KEY_EDITOR		0x1a6	/* AL Text Editor */
++#define KEY_SPREADSHEET		0x1a7	/* AL Spreadsheet */
++#define KEY_GRAPHICSEDITOR	0x1a8	/* AL Graphics Editor */
++#define KEY_PRESENTATION	0x1a9	/* AL Presentation App */
++#define KEY_DATABASE		0x1aa	/* AL Database App */
++#define KEY_NEWS		0x1ab	/* AL Newsreader */
++#define KEY_VOICEMAIL		0x1ac	/* AL Voicemail */
++#define KEY_ADDRESSBOOK		0x1ad	/* AL Contacts/Address Book */
++#define KEY_MESSENGER		0x1ae	/* AL Instant Messaging */
++#define KEY_DISPLAYTOGGLE	0x1af	/* Turn display (LCD) on and off */
++#define KEY_BRIGHTNESS_TOGGLE	KEY_DISPLAYTOGGLE
++#define KEY_SPELLCHECK		0x1b0   /* AL Spell Check */
++#define KEY_LOGOFF		0x1b1   /* AL Logoff */
++
++#define KEY_DOLLAR		0x1b2
++#define KEY_EURO		0x1b3
++
++#define KEY_FRAMEBACK		0x1b4	/* Consumer - transport controls */
++#define KEY_FRAMEFORWARD	0x1b5
++#define KEY_CONTEXT_MENU	0x1b6	/* GenDesc - system context menu */
++#define KEY_MEDIA_REPEAT	0x1b7	/* Consumer - transport control */
++#define KEY_10CHANNELSUP	0x1b8	/* 10 channels up (10+) */
++#define KEY_10CHANNELSDOWN	0x1b9	/* 10 channels down (10-) */
++#define KEY_IMAGES		0x1ba	/* AL Image Browser */
++
++#define KEY_DEL_EOL		0x1c0
++#define KEY_DEL_EOS		0x1c1
++#define KEY_INS_LINE		0x1c2
++#define KEY_DEL_LINE		0x1c3
++
++#define KEY_FN			0x1d0
++#define KEY_FN_ESC		0x1d1
++#define KEY_FN_F1		0x1d2
++#define KEY_FN_F2		0x1d3
++#define KEY_FN_F3		0x1d4
++#define KEY_FN_F4		0x1d5
++#define KEY_FN_F5		0x1d6
++#define KEY_FN_F6		0x1d7
++#define KEY_FN_F7		0x1d8
++#define KEY_FN_F8		0x1d9
++#define KEY_FN_F9		0x1da
++#define KEY_FN_F10		0x1db
++#define KEY_FN_F11		0x1dc
++#define KEY_FN_F12		0x1dd
++#define KEY_FN_1		0x1de
++#define KEY_FN_2		0x1df
++#define KEY_FN_D		0x1e0
++#define KEY_FN_E		0x1e1
++#define KEY_FN_F		0x1e2
++#define KEY_FN_S		0x1e3
++#define KEY_FN_B		0x1e4
++
++#define KEY_BRL_DOT1		0x1f1
++#define KEY_BRL_DOT2		0x1f2
++#define KEY_BRL_DOT3		0x1f3
++#define KEY_BRL_DOT4		0x1f4
++#define KEY_BRL_DOT5		0x1f5
++#define KEY_BRL_DOT6		0x1f6
++#define KEY_BRL_DOT7		0x1f7
++#define KEY_BRL_DOT8		0x1f8
++#define KEY_BRL_DOT9		0x1f9
++#define KEY_BRL_DOT10		0x1fa
++
++#define KEY_NUMERIC_0		0x200	/* used by phones, remote controls, */
++#define KEY_NUMERIC_1		0x201	/* and other keypads */
++#define KEY_NUMERIC_2		0x202
++#define KEY_NUMERIC_3		0x203
++#define KEY_NUMERIC_4		0x204
++#define KEY_NUMERIC_5		0x205
++#define KEY_NUMERIC_6		0x206
++#define KEY_NUMERIC_7		0x207
++#define KEY_NUMERIC_8		0x208
++#define KEY_NUMERIC_9		0x209
++#define KEY_NUMERIC_STAR	0x20a
++#define KEY_NUMERIC_POUND	0x20b
++#define KEY_NUMERIC_A		0x20c	/* Phone key A - HUT Telephony 0xb9 */
++#define KEY_NUMERIC_B		0x20d
++#define KEY_NUMERIC_C		0x20e
++#define KEY_NUMERIC_D		0x20f
++
++#define KEY_CAMERA_FOCUS	0x210
++#define KEY_WPS_BUTTON		0x211	/* WiFi Protected Setup key */
++
++#define KEY_TOUCHPAD_TOGGLE	0x212	/* Request switch touchpad on or off */
++#define KEY_TOUCHPAD_ON		0x213
++#define KEY_TOUCHPAD_OFF	0x214
++
++#define KEY_CAMERA_ZOOMIN	0x215
++#define KEY_CAMERA_ZOOMOUT	0x216
++#define KEY_CAMERA_UP		0x217
++#define KEY_CAMERA_DOWN		0x218
++#define KEY_CAMERA_LEFT		0x219
++#define KEY_CAMERA_RIGHT	0x21a
++
++#define KEY_ATTENDANT_ON	0x21b
++#define KEY_ATTENDANT_OFF	0x21c
++#define KEY_ATTENDANT_TOGGLE	0x21d	/* Attendant call on or off */
++#define KEY_LIGHTS_TOGGLE	0x21e	/* Reading light on or off */
++
++#define BTN_DPAD_UP		0x220
++#define BTN_DPAD_DOWN		0x221
++#define BTN_DPAD_LEFT		0x222
++#define BTN_DPAD_RIGHT		0x223
++
++#define KEY_ALS_TOGGLE		0x230	/* Ambient light sensor */
++
++#define KEY_BUTTONCONFIG		0x240	/* AL Button Configuration */
++#define KEY_TASKMANAGER		0x241	/* AL Task/Project Manager */
++#define KEY_JOURNAL		0x242	/* AL Log/Journal/Timecard */
++#define KEY_CONTROLPANEL		0x243	/* AL Control Panel */
++#define KEY_APPSELECT		0x244	/* AL Select Task/Application */
++#define KEY_SCREENSAVER		0x245	/* AL Screen Saver */
++#define KEY_VOICECOMMAND		0x246	/* Listening Voice Command */
++
++#define KEY_BRIGHTNESS_MIN		0x250	/* Set Brightness to Minimum */
++#define KEY_BRIGHTNESS_MAX		0x251	/* Set Brightness to Maximum */
++
++#define KEY_KBDINPUTASSIST_PREV		0x260
++#define KEY_KBDINPUTASSIST_NEXT		0x261
++#define KEY_KBDINPUTASSIST_PREVGROUP		0x262
++#define KEY_KBDINPUTASSIST_NEXTGROUP		0x263
++#define KEY_KBDINPUTASSIST_ACCEPT		0x264
++#define KEY_KBDINPUTASSIST_CANCEL		0x265
++
++#define BTN_TRIGGER_HAPPY		0x2c0
++#define BTN_TRIGGER_HAPPY1		0x2c0
++#define BTN_TRIGGER_HAPPY2		0x2c1
++#define BTN_TRIGGER_HAPPY3		0x2c2
++#define BTN_TRIGGER_HAPPY4		0x2c3
++#define BTN_TRIGGER_HAPPY5		0x2c4
++#define BTN_TRIGGER_HAPPY6		0x2c5
++#define BTN_TRIGGER_HAPPY7		0x2c6
++#define BTN_TRIGGER_HAPPY8		0x2c7
++#define BTN_TRIGGER_HAPPY9		0x2c8
++#define BTN_TRIGGER_HAPPY10		0x2c9
++#define BTN_TRIGGER_HAPPY11		0x2ca
++#define BTN_TRIGGER_HAPPY12		0x2cb
++#define BTN_TRIGGER_HAPPY13		0x2cc
++#define BTN_TRIGGER_HAPPY14		0x2cd
++#define BTN_TRIGGER_HAPPY15		0x2ce
++#define BTN_TRIGGER_HAPPY16		0x2cf
++#define BTN_TRIGGER_HAPPY17		0x2d0
++#define BTN_TRIGGER_HAPPY18		0x2d1
++#define BTN_TRIGGER_HAPPY19		0x2d2
++#define BTN_TRIGGER_HAPPY20		0x2d3
++#define BTN_TRIGGER_HAPPY21		0x2d4
++#define BTN_TRIGGER_HAPPY22		0x2d5
++#define BTN_TRIGGER_HAPPY23		0x2d6
++#define BTN_TRIGGER_HAPPY24		0x2d7
++#define BTN_TRIGGER_HAPPY25		0x2d8
++#define BTN_TRIGGER_HAPPY26		0x2d9
++#define BTN_TRIGGER_HAPPY27		0x2da
++#define BTN_TRIGGER_HAPPY28		0x2db
++#define BTN_TRIGGER_HAPPY29		0x2dc
++#define BTN_TRIGGER_HAPPY30		0x2dd
++#define BTN_TRIGGER_HAPPY31		0x2de
++#define BTN_TRIGGER_HAPPY32		0x2df
++#define BTN_TRIGGER_HAPPY33		0x2e0
++#define BTN_TRIGGER_HAPPY34		0x2e1
++#define BTN_TRIGGER_HAPPY35		0x2e2
++#define BTN_TRIGGER_HAPPY36		0x2e3
++#define BTN_TRIGGER_HAPPY37		0x2e4
++#define BTN_TRIGGER_HAPPY38		0x2e5
++#define BTN_TRIGGER_HAPPY39		0x2e6
++#define BTN_TRIGGER_HAPPY40		0x2e7
++
++/* We avoid low common keys in module aliases so they don't get huge. */
++#define KEY_MIN_INTERESTING	KEY_MUTE
++#define KEY_MAX			0x2ff
++#define KEY_CNT			(KEY_MAX+1)
++
++/*
++ * Relative axes
++ */
++
++#define REL_X			0x00
++#define REL_Y			0x01
++#define REL_Z			0x02
++#define REL_RX			0x03
++#define REL_RY			0x04
++#define REL_RZ			0x05
++#define REL_HWHEEL		0x06
++#define REL_DIAL		0x07
++#define REL_WHEEL		0x08
++#define REL_MISC		0x09
++#define REL_MAX			0x0f
++#define REL_CNT			(REL_MAX+1)
++
++/*
++ * Absolute axes
++ */
++
++#define ABS_X			0x00
++#define ABS_Y			0x01
++#define ABS_Z			0x02
++#define ABS_RX			0x03
++#define ABS_RY			0x04
++#define ABS_RZ			0x05
++#define ABS_THROTTLE		0x06
++#define ABS_RUDDER		0x07
++#define ABS_WHEEL		0x08
++#define ABS_GAS			0x09
++#define ABS_BRAKE		0x0a
++#define ABS_HAT0X		0x10
++#define ABS_HAT0Y		0x11
++#define ABS_HAT1X		0x12
++#define ABS_HAT1Y		0x13
++#define ABS_HAT2X		0x14
++#define ABS_HAT2Y		0x15
++#define ABS_HAT3X		0x16
++#define ABS_HAT3Y		0x17
++#define ABS_PRESSURE		0x18
++#define ABS_DISTANCE		0x19
++#define ABS_TILT_X		0x1a
++#define ABS_TILT_Y		0x1b
++#define ABS_TOOL_WIDTH		0x1c
++
++#define ABS_VOLUME		0x20
++
++#define ABS_MISC		0x28
++
++#define ABS_MT_SLOT		0x2f	/* MT slot being modified */
++#define ABS_MT_TOUCH_MAJOR	0x30	/* Major axis of touching ellipse */
++#define ABS_MT_TOUCH_MINOR	0x31	/* Minor axis (omit if circular) */
++#define ABS_MT_WIDTH_MAJOR	0x32	/* Major axis of approaching ellipse */
++#define ABS_MT_WIDTH_MINOR	0x33	/* Minor axis (omit if circular) */
++#define ABS_MT_ORIENTATION	0x34	/* Ellipse orientation */
++#define ABS_MT_POSITION_X	0x35	/* Center X touch position */
++#define ABS_MT_POSITION_Y	0x36	/* Center Y touch position */
++#define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
++#define ABS_MT_BLOB_ID		0x38	/* Group a set of packets as a blob */
++#define ABS_MT_TRACKING_ID	0x39	/* Unique ID of initiated contact */
++#define ABS_MT_PRESSURE		0x3a	/* Pressure on contact area */
++#define ABS_MT_DISTANCE		0x3b	/* Contact hover distance */
++#define ABS_MT_TOOL_X		0x3c	/* Center X tool position */
++#define ABS_MT_TOOL_Y		0x3d	/* Center Y tool position */
++
++
++#define ABS_MAX			0x3f
++#define ABS_CNT			(ABS_MAX+1)
++
++/*
++ * Switch events
++ */
++
++#define SW_LID			0x00  /* set = lid shut */
++#define SW_TABLET_MODE		0x01  /* set = tablet mode */
++#define SW_HEADPHONE_INSERT	0x02  /* set = inserted */
++#define SW_RFKILL_ALL		0x03  /* rfkill master switch, type "any"
++					 set = radio enabled */
++#define SW_RADIO		SW_RFKILL_ALL	/* deprecated */
++#define SW_MICROPHONE_INSERT	0x04  /* set = inserted */
++#define SW_DOCK			0x05  /* set = plugged into dock */
++#define SW_LINEOUT_INSERT	0x06  /* set = inserted */
++#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
++#define SW_VIDEOOUT_INSERT	0x08  /* set = inserted */
++#define SW_CAMERA_LENS_COVER	0x09  /* set = lens covered */
++#define SW_KEYPAD_SLIDE		0x0a  /* set = keypad slide out */
++#define SW_FRONT_PROXIMITY	0x0b  /* set = front proximity sensor active */
++#define SW_ROTATE_LOCK		0x0c  /* set = rotate locked/disabled */
++#define SW_LINEIN_INSERT	0x0d  /* set = inserted */
++#define SW_MUTE_DEVICE		0x0e  /* set = device disabled */
++#define SW_MAX			0x0f
++#define SW_CNT			(SW_MAX+1)
++
++/*
++ * Misc events
++ */
++
++#define MSC_SERIAL		0x00
++#define MSC_PULSELED		0x01
++#define MSC_GESTURE		0x02
++#define MSC_RAW			0x03
++#define MSC_SCAN		0x04
++#define MSC_TIMESTAMP		0x05
++#define MSC_MAX			0x07
++#define MSC_CNT			(MSC_MAX+1)
++
++/*
++ * LEDs
++ */
++
++#define LED_NUML		0x00
++#define LED_CAPSL		0x01
++#define LED_SCROLLL		0x02
++#define LED_COMPOSE		0x03
++#define LED_KANA		0x04
++#define LED_SLEEP		0x05
++#define LED_SUSPEND		0x06
++#define LED_MUTE		0x07
++#define LED_MISC		0x08
++#define LED_MAIL		0x09
++#define LED_CHARGING		0x0a
++#define LED_MAX			0x0f
++#define LED_CNT			(LED_MAX+1)
++
++/*
++ * Autorepeat values
++ */
++
++#define REP_DELAY		0x00
++#define REP_PERIOD		0x01
++#define REP_MAX			0x01
++#define REP_CNT			(REP_MAX+1)
++
++/*
++ * Sounds
++ */
++
++#define SND_CLICK		0x00
++#define SND_BELL		0x01
++#define SND_TONE		0x02
++#define SND_MAX			0x07
++#define SND_CNT			(SND_MAX+1)
++
++#endif
diff --git a/package/boot/uboot-sunxi/patches/011-dt-sync-dts-files-with-kernel.patch b/package/boot/uboot-sunxi/patches/011-dt-sync-dts-files-with-kernel.patch
new file mode 100644
index 0000000000..e36f9e3c5a
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/011-dt-sync-dts-files-with-kernel.patch
@@ -0,0 +1,7211 @@
+From 80e5f83c0fc4bf42110cc55ce671ad7ddc7b08a4 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 14 Mar 2016 17:37:09 +0100
+Subject: [PATCH] sunxi: Sync dts files with the upstream kernel
+
+Sync dts files with the upstream kernel including
+changes queued for 4.6:
+
+https://git.kernel.org/cgit/linux/kernel/git/mripard/linux.git/commit/?h=sunxi/dt-for-4.6
+
+Note this adds a number of new unused board dts files. I've asked the
+authors of the kernel commits adding these to submit a matching defconfig
+to u-boot.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ arch/arm/dts/Makefile                              |   8 +-
+ arch/arm/dts/axp22x.dtsi                           | 145 ++++++++++++
+ arch/arm/dts/sun4i-a10-a1000.dts                   |   4 +
+ arch/arm/dts/sun4i-a10-chuwi-v7-cw0825.dts         |  22 ++
+ arch/arm/dts/sun4i-a10-cubieboard.dts              |   4 +
+ arch/arm/dts/sun4i-a10-gemei-g9.dts                |  63 +++++-
+ arch/arm/dts/sun4i-a10-inet1.dts                   |  48 ++++
+ arch/arm/dts/sun4i-a10-inet97fv2.dts               | 127 ++++++++++-
+ arch/arm/dts/sun4i-a10-inet9f-rev03.dts            | 181 +++++++++++++++
+ arch/arm/dts/sun4i-a10-itead-iteaduino-plus.dts    |  86 +------
+ arch/arm/dts/sun4i-a10-jesurun-q5.dts              |  15 ++
+ arch/arm/dts/sun4i-a10-marsboard.dts               |  23 ++
+ arch/arm/dts/sun4i-a10-mk802.dts                   |  37 +++
+ arch/arm/dts/sun4i-a10-olinuxino-lime.dts          |  12 +
+ arch/arm/dts/sun4i-a10-pcduino.dts                 |  58 ++++-
+ arch/arm/dts/sun4i-a10-pcduino2.dts                |  78 +++++++
+ arch/arm/dts/sun4i-a10-pov-protab2-ips9.dts        |  69 ++++++
+ arch/arm/dts/sun4i-a10.dtsi                        | 153 +++++++++++--
+ arch/arm/dts/sun5i-a10s-auxtek-t004.dts            |  14 ++
+ arch/arm/dts/sun5i-a10s-olinuxino-micro.dts        |   2 +-
+ arch/arm/dts/sun5i-a13-empire-electronix-d709.dts  |  19 +-
+ arch/arm/dts/sun5i-a13-inet-98v-rev2.dts           |  26 +--
+ arch/arm/dts/sun5i-a13-utoo-p66.dts                |  30 +++
+ arch/arm/dts/sun5i-q8-common.dtsi                  |  10 +
+ arch/arm/dts/sun5i-r8-chip.dts                     |  47 +++-
+ arch/arm/dts/sun5i.dtsi                            |  31 +++
+ arch/arm/dts/sun6i-a31-colombus.dts                |  24 ++
+ arch/arm/dts/sun6i-a31-hummingbird.dts             | 132 ++++++-----
+ arch/arm/dts/sun6i-a31.dtsi                        |  65 +++++-
+ arch/arm/dts/sun6i-a31s-primo81.dts                | 247 ++++++++++++++++++++-
+ arch/arm/dts/sun6i-a31s-sina31s-core.dtsi          | 142 ++++++++++++
+ arch/arm/dts/sun6i-a31s-sina31s.dts                | 153 +++++++++++++
+ .../arm/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts | 205 +++++++++++++++++
+ arch/arm/dts/sun7i-a20-bananapi.dts                |  78 ++++++-
+ arch/arm/dts/sun7i-a20-cubieboard2.dts             |  23 ++
+ arch/arm/dts/sun7i-a20-cubietruck.dts              |   4 +
+ arch/arm/dts/sun7i-a20-icnova-swac.dts             | 169 ++++++++++++++
+ arch/arm/dts/sun7i-a20-itead-ibox.dts              | 125 +++++++++++
+ arch/arm/dts/sun7i-a20-lamobo-r1.dts               |  10 -
+ arch/arm/dts/sun7i-a20-mk808c.dts                  |  39 ++++
+ arch/arm/dts/sun7i-a20-olimex-som-evb.dts          |  95 ++++++--
+ arch/arm/dts/sun7i-a20-olinuxino-lime.dts          |  12 +
+ arch/arm/dts/sun7i-a20-olinuxino-lime2.dts         |  47 ++++
+ arch/arm/dts/sun7i-a20-olinuxino-micro.dts         |   6 +
+ arch/arm/dts/sun7i-a20-orangepi-mini.dts           |  33 +++
+ arch/arm/dts/sun7i-a20-orangepi.dts                |  29 +++
+ arch/arm/dts/sun7i-a20-pcduino3-nano.dts           |  69 +++++-
+ arch/arm/dts/sun7i-a20-pcduino3.dts                |  58 ++++-
+ arch/arm/dts/sun7i-a20-wexler-tab7200.dts          |  90 +++++++-
+ arch/arm/dts/sun7i-a20-wits-pro-a20-dkt.dts        | 187 +++++++++++++++-
+ arch/arm/dts/sun7i-a20.dtsi                        | 113 +++++++++-
+ arch/arm/dts/sun8i-a23-a33.dtsi                    |  71 ++++--
+ arch/arm/dts/sun8i-a23-gt90h-v4.dts                | 120 +++++++++-
+ arch/arm/dts/sun8i-a23.dtsi                        |  25 +++
+ arch/arm/dts/sun8i-a33-sinlinx-sina33.dts          |  83 ++++++-
+ arch/arm/dts/sun8i-a33.dtsi                        |  45 ++++
+ arch/arm/dts/sun8i-a83t-cubietruck-plus.dts        |  65 ++++++
+ arch/arm/dts/sun8i-a83t.dtsi                       | 125 +++++------
+ arch/arm/dts/sun8i-h3-orangepi-pc.dts              |  69 ++++++
+ arch/arm/dts/sun8i-h3-orangepi-plus.dts            |  63 ++++++
+ arch/arm/dts/sun8i-h3.dtsi                         | 189 +++++++++++-----
+ arch/arm/dts/sun8i-q8-common.dtsi                  |  96 +++++++-
+ arch/arm/dts/sun9i-a80-cubieboard4.dts             |  36 +++
+ arch/arm/dts/sun9i-a80-optimus.dts                 |  48 ++--
+ arch/arm/dts/sun9i-a80.dtsi                        | 204 +++++++++++++++--
+ arch/arm/dts/sunxi-itead-core-common.dtsi          | 136 ++++++++++++
+ arch/arm/dts/sunxi-q8-common.dtsi                  |   6 +
+ 67 files changed, 4351 insertions(+), 497 deletions(-)
+ create mode 100644 arch/arm/dts/axp22x.dtsi
+ create mode 100644 arch/arm/dts/sun4i-a10-pcduino2.dts
+ create mode 100644 arch/arm/dts/sun6i-a31s-sina31s-core.dtsi
+ create mode 100644 arch/arm/dts/sun6i-a31s-sina31s.dts
+ create mode 100644 arch/arm/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+ create mode 100644 arch/arm/dts/sun7i-a20-icnova-swac.dts
+ create mode 100644 arch/arm/dts/sun7i-a20-itead-ibox.dts
+ create mode 100644 arch/arm/dts/sun8i-a83t-cubietruck-plus.dts
+ create mode 100644 arch/arm/dts/sunxi-itead-core-common.dtsi
+
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -126,6 +126,7 @@ dtb-$(CONFIG_MACH_SUN4I) += \
+ 	sun4i-a10-mk802ii.dtb \
+ 	sun4i-a10-olinuxino-lime.dtb \
+ 	sun4i-a10-pcduino.dtb \
++	sun4i-a10-pcduino2.dtb \
+ 	sun4i-a10-pov-protab2-ips9.dtb
+ dtb-$(CONFIG_MACH_SUN5I) += \
+ 	sun5i-a10s-auxtek-t003.dtb \
+@@ -155,7 +156,9 @@ dtb-$(CONFIG_MACH_SUN6I) += \
+ 	sun6i-a31-pangolin.dtb \
+ 	sun6i-a31s-cs908.dtb \
+ 	sun6i-a31s-primo81.dtb \
+-	sun6i-a31s-sinovoip-bpi-m2.dtb
++	sun6i-a31s-sina31s.dtb \
++	sun6i-a31s-sinovoip-bpi-m2.dtb \
++	sun6i-a31s-yones-toptech-bs1078-v2.dtb
+ dtb-$(CONFIG_MACH_SUN7I) += \
+ 	sun7i-a20-ainol-aw1.dtb \
+ 	sun7i-a20-bananapi.dtb \
+@@ -164,6 +167,8 @@ dtb-$(CONFIG_MACH_SUN7I) += \
+ 	sun7i-a20-cubietruck.dtb \
+ 	sun7i-a20-hummingbird.dtb \
+ 	sun7i-a20-i12-tvbox.dtb \
++	sun7i-a20-icnova-swac.dtb \
++	sun7i-a20-itead-ibox.dtb \
+ 	sun7i-a20-lamobo-r1.dtb \
+ 	sun7i-a20-m3.dtb \
+ 	sun7i-a20-m5.dtb \
+@@ -190,6 +195,7 @@ dtb-$(CONFIG_MACH_SUN8I_A33) += \
+ 	sun8i-a33-sinlinx-sina33.dtb
+ dtb-$(CONFIG_MACH_SUN8I_A83T) += \
+ 	sun8i-a83t-allwinner-h8homlet-v2.dtb \
++	sun8i-a83t-cubietruck-plus.dtb \
+ 	sun8i-a83t-sinovoip-bpi-m3.dtb
+ dtb-$(CONFIG_MACH_SUN8I_H3) += \
+ 	sun8i-h3-orangepi-pc.dtb \
+--- /dev/null
++++ b/arch/arm/dts/axp22x.dtsi
+@@ -0,0 +1,145 @@
++/*
++ * Copyright 2015 Chen-Yu Tsai
++ *
++ * Chen-Yu Tsai <wens@csie.org>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/*
++ * AXP221/221s/223 Integrated Power Management Chip
++ * http://www.x-powers.com/product/AXP22X.php
++ * http://dl.linux-sunxi.org/AXP/AXP221%20Datasheet%20V1.2%2020130326%20.pdf
++ */
++
++&axp22x {
++	interrupt-controller;
++	#interrupt-cells = <1>;
++
++	regulators {
++		/* Default work frequency for buck regulators */
++		x-powers,dcdc-freq = <3000>;
++
++		reg_dcdc1: dcdc1 {
++			regulator-name = "dcdc1";
++		};
++
++		reg_dcdc2: dcdc2 {
++			regulator-name = "dcdc2";
++		};
++
++		reg_dcdc3: dcdc3 {
++			regulator-name = "dcdc3";
++		};
++
++		reg_dcdc4: dcdc4 {
++			regulator-name = "dcdc4";
++		};
++
++		reg_dcdc5: dcdc5 {
++			regulator-name = "dcdc5";
++		};
++
++		reg_dc1sw: dc1sw {
++			regulator-name = "dc1sw";
++		};
++
++		reg_dc5ldo: dc5ldo {
++			regulator-name = "dc5ldo";
++		};
++
++		reg_aldo1: aldo1 {
++			regulator-name = "aldo1";
++		};
++
++		reg_aldo2: aldo2 {
++			regulator-name = "aldo2";
++		};
++
++		reg_aldo3: aldo3 {
++			regulator-name = "aldo3";
++		};
++
++		reg_dldo1: dldo1 {
++			regulator-name = "dldo1";
++		};
++
++		reg_dldo2: dldo2 {
++			regulator-name = "dldo2";
++		};
++
++		reg_dldo3: dldo3 {
++			regulator-name = "dldo3";
++		};
++
++		reg_dldo4: dldo4 {
++			regulator-name = "dldo4";
++		};
++
++		reg_eldo1: eldo1 {
++			regulator-name = "eldo1";
++		};
++
++		reg_eldo2: eldo2 {
++			regulator-name = "eldo2";
++		};
++
++		reg_eldo3: eldo3 {
++			regulator-name = "eldo3";
++		};
++
++		reg_ldo_io0: ldo_io0 {
++			regulator-name = "ldo_io0";
++			status = "disabled";
++		};
++
++		reg_ldo_io1: ldo_io1 {
++			regulator-name = "ldo_io1";
++			status = "disabled";
++		};
++
++		reg_rtc_ldo: rtc_ldo {
++			/* RTC_LDO is a fixed, always-on regulator */
++			regulator-always-on;
++			regulator-min-microvolt = <3000000>;
++			regulator-max-microvolt = <3000000>;
++			regulator-name = "rtc_ldo";
++		};
++	};
++};
+--- a/arch/arm/dts/sun4i-a10-a1000.dts
++++ b/arch/arm/dts/sun4i-a10-a1000.dts
+@@ -93,6 +93,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+--- a/arch/arm/dts/sun4i-a10-chuwi-v7-cw0825.dts
++++ b/arch/arm/dts/sun4i-a10-chuwi-v7-cw0825.dts
+@@ -45,6 +45,7 @@
+ #include "sunxi-common-regulators.dtsi"
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
++#include <dt-bindings/interrupt-controller/irq.h>
+ 
+ / {
+ 	model = "Chuwi V7 CW0825";
+@@ -78,6 +79,27 @@
+ 	};
+ };
+ 
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++
++	ft5306de4: touchscreen@38 {
++		compatible = "edt,edt-ft5406";
++		reg = <0x38>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>;
++		touchscreen-size-x = <1024>;
++		touchscreen-size-y = <768>;
++	};
++};
++
+ &lradc {
+ 	vref-supply = <&reg_vcc3v0>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun4i-a10-cubieboard.dts
++++ b/arch/arm/dts/sun4i-a10-cubieboard.dts
+@@ -83,6 +83,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+--- a/arch/arm/dts/sun4i-a10-gemei-g9.dts
++++ b/arch/arm/dts/sun4i-a10-gemei-g9.dts
+@@ -47,6 +47,7 @@
+ #include "sunxi-common-regulators.dtsi"
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
++#include <dt-bindings/interrupt-controller/irq.h>
+ 
+ / {
+ 	model = "Gemei G9 Tablet";
+@@ -64,12 +65,22 @@
+ /*
+  * TODO:
+  *   2x cameras via CSI
+- *   bma250 IRQs
+  *   AXP battery management
+  *   NAND
+  *   OTG
+  *   Touchscreen - gt801_2plus1 @ i2c adapter 2 @ 0x48
+  */
++&codec {
++	/* PH15 controls power to external amplifier (ft2012q) */
++	pinctrl-names = "default";
++	pinctrl-0 = <&codec_pa_pin>;
++	allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>;
++	status = "okay";
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++};
+ 
+ &ehci0 {
+ 	status = "okay";
+@@ -85,15 +96,13 @@
+ 	status = "okay";
+ 
+ 	axp209: pmic@34 {
+-		compatible = "x-powers,axp209";
+ 		reg = <0x34>;
+ 		interrupts = <0>;
+-
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
+ 	};
+ };
+ 
++#include "axp209.dtsi"
++
+ &i2c1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins_a>;
+@@ -103,17 +112,13 @@
+ 	bma250@18 {
+ 		compatible = "bosch,bma250";
+ 		reg = <0x18>;
+-
+-		/*
+-		 * TODO: interrupt pins:
+-		 * int1 - PH00
+-		 * int2 - PI10
+-		 */
++		interrupt-parent = <&pio>;
++		interrupts = <7 0 IRQ_TYPE_EDGE_RISING>; /* PH00 / EINT0 */
+ 	};
+ };
+ 
+ &lradc {
+-	vref-supply = <&reg_vcc3v0>;
++	vref-supply = <&reg_ldo2>;
+ 
+ 	status = "okay";
+ 
+@@ -149,6 +154,40 @@
+ 	status = "okay";
+ };
+ 
++&pio {
++	codec_pa_pin: codec_pa_pin@0 {
++		allwinner,pins = "PH15";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1250000>;
++	regulator-max-microvolt = <1250000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+--- a/arch/arm/dts/sun4i-a10-inet1.dts
++++ b/arch/arm/dts/sun4i-a10-inet1.dts
+@@ -47,6 +47,7 @@
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
++#include <dt-bindings/pwm/pwm.h>
+ 
+ / {
+ 	model = "iNet-1";
+@@ -56,11 +57,25 @@
+ 		serial0 = &uart0;
+ 	};
+ 
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pinctrl-names = "default";
++		pinctrl-0 = <&bl_en_pin_inet>;
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <8>;
++		enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
++	};
++
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+@@ -104,6 +119,19 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c2_pins_a>;
+ 	status = "okay";
++
++	ft5x: touchscreen@38 {
++		compatible = "edt,edt-ft5406";
++		reg = <0x38>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&touchscreen_wake_pin>;
++		wake-gpios = <&pio 1 13 GPIO_ACTIVE_HIGH>; /* PB13 */
++		touchscreen-size-x = <600>;
++		touchscreen-size-y = <1024>;
++		touchscreen-swapped-x-y;
++	};
+ };
+ 
+ &lradc {
+@@ -151,6 +179,20 @@
+ };
+ 
+ &pio {
++	bl_en_pin_inet: bl_en_pin@0 {
++		allwinner,pins = "PH7";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	touchscreen_wake_pin: touchscreen_wake_pin@0 {
++		allwinner,pins = "PB13";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ 		allwinner,pins = "PH4";
+ 		allwinner,function = "gpio_in";
+@@ -166,6 +208,12 @@
+ 	};
+ };
+ 
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm0_pins_a>;
++	status = "okay";
++};
++
+ &reg_dcdc2 {
+ 	regulator-always-on;
+ 	regulator-min-microvolt = <1000000>;
+--- a/arch/arm/dts/sun4i-a10-inet97fv2.dts
++++ b/arch/arm/dts/sun4i-a10-inet97fv2.dts
+@@ -47,6 +47,8 @@
+ #include "sunxi-common-regulators.dtsi"
+ 
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/interrupt-controller/irq.h>
+ 
+ / {
+ 	model = "INet-97F Rev 02";
+@@ -61,8 +63,8 @@
+ 	};
+ };
+ 
+-&ehci0 {
+-	status = "okay";
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
+ };
+ 
+ &ehci1 {
+@@ -75,12 +77,71 @@
+ 	status = "okay";
+ 
+ 	axp209: pmic@34 {
+-		compatible = "x-powers,axp209";
+ 		reg = <0x34>;
+ 		interrupts = <0>;
++	};
++};
++
++#include "axp209.dtsi"
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++
++	ft5406ee8: touchscreen@38 {
++		compatible = "edt,edt-ft5406";
++		reg = <0x38>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>;
++		touchscreen-size-x = <800>;
++		touchscreen-size-y = <480>;
++	};
++};
++
++&lradc {
++	vref-supply = <&reg_ldo2>;
++	status = "okay";
++
++	button@200 {
++		label = "Menu";
++		linux,code = <KEY_MENU>;
++		channel = <0>;
++		voltage = <200000>;
++	};
++
++	button@600 {
++		label = "Volume Up";
++		linux,code = <KEY_VOLUMEUP>;
++		channel = <0>;
++		voltage = <600000>;
++	};
+ 
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
++	button@800 {
++		label = "Volume Down";
++		linux,code = <KEY_VOLUMEDOWN>;
++		channel = <0>;
++		voltage = <800000>;
++	};
++
++	button@1000 {
++		label = "Home";
++		linux,code = <KEY_HOMEPAGE>;
++		channel = <0>;
++		voltage = <1000000>;
++	};
++
++	button@1200 {
++		label = "Esc";
++		linux,code = <KEY_ESC>;
++		channel = <0>;
++		voltage = <1200000>;
+ 	};
+ };
+ 
+@@ -94,15 +155,52 @@
+ 	status = "okay";
+ };
+ 
+-&ohci0 {
++&otg_sram {
+ 	status = "okay";
+ };
+ 
+-&ohci1 {
+-	status = "okay";
++&pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
++		allwinner,pins = "PH5";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
++	};
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
+ };
+ 
+-&reg_usb1_vbus {
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1250000>;
++	regulator-max-microvolt = <1250000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
++&reg_usb0_vbus {
+ 	status = "okay";
+ };
+ 
+@@ -116,8 +214,17 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
+-	usb1_vbus-supply = <&reg_usb1_vbus>;
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+ };
+--- a/arch/arm/dts/sun4i-a10-inet9f-rev03.dts
++++ b/arch/arm/dts/sun4i-a10-inet9f-rev03.dts
+@@ -59,6 +59,159 @@
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
++
++	gpio_keys {
++		compatible = "gpio-keys-polled";
++		pinctrl-names = "default";
++		pinctrl-0 = <&key_pins_inet9f>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		poll-interval = <20>;
++
++		button@0 {
++			label = "Left Joystick Left";
++			linux,code = <ABS_X>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <0xffffffff>; /* -1 */
++			gpios = <&pio 0 6 GPIO_ACTIVE_LOW>; /* PA6 */
++		};
++
++		button@1 {
++			label = "Left Joystick Right";
++			linux,code = <ABS_X>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <1>;
++			gpios = <&pio 0 5 GPIO_ACTIVE_LOW>; /* PA5 */
++		};
++
++		button@2 {
++			label = "Left Joystick Up";
++			linux,code = <ABS_Y>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <0xffffffff>; /* -1 */
++			gpios = <&pio 0 8 GPIO_ACTIVE_LOW>; /* PA8 */
++		};
++
++		button@3 {
++			label = "Left Joystick Down";
++			linux,code = <ABS_Y>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <1>;
++			gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
++		};
++
++		button@4 {
++			label = "Right Joystick Left";
++			linux,code = <ABS_Z>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <0xffffffff>; /* -1 */
++			gpios = <&pio 0 1 GPIO_ACTIVE_LOW>; /* PA1 */
++		};
++
++		button@5 {
++			label = "Right Joystick Right";
++			linux,code = <ABS_Z>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <1>;
++			gpios = <&pio 0 0 GPIO_ACTIVE_LOW>; /* PA0 */
++		};
++
++		button@6 {
++			label = "Right Joystick Up";
++			linux,code = <ABS_RZ>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <0xffffffff>; /* -1 */
++			gpios = <&pio 0 3 GPIO_ACTIVE_LOW>; /* PA3 */
++		};
++
++		button@7 {
++			label = "Right Joystick Down";
++			linux,code = <ABS_RZ>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <1>;
++			gpios = <&pio 0 4 GPIO_ACTIVE_LOW>; /* PA4 */
++		};
++
++		button@8 {
++			label = "DPad Left";
++			linux,code = <ABS_HAT0X>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <0xffffffff>; /* -1 */
++			gpios = <&pio 7 23 GPIO_ACTIVE_LOW>; /* PH23 */
++		};
++
++		button@9 {
++			label = "DPad Right";
++			linux,code = <ABS_HAT0X>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <1>;
++			gpios = <&pio 7 24 GPIO_ACTIVE_LOW>; /* PH24 */
++		};
++
++		button@10 {
++			label = "DPad Up";
++			linux,code = <ABS_HAT0Y>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <0xffffffff>; /* -1 */
++			gpios = <&pio 7 25 GPIO_ACTIVE_LOW>; /* PH25 */
++		};
++
++		button@11 {
++			label = "DPad Down";
++			linux,code = <ABS_HAT0Y>;
++			linux,input-type = <EV_ABS>;
++			linux,input-value = <1>;
++			gpios = <&pio 7 26 GPIO_ACTIVE_LOW>; /* PH26 */
++		};
++
++		button@12 {
++			label = "Button X";
++			linux,code = <BTN_X>;
++			gpios = <&pio 0 16 GPIO_ACTIVE_LOW>; /* PA16 */
++		};
++
++		button@13 {
++			label = "Button Y";
++			linux,code = <BTN_Y>;
++			gpios = <&pio 0 14 GPIO_ACTIVE_LOW>; /* PA14 */
++		};
++
++		button@14 {
++			label = "Button A";
++			linux,code = <BTN_A>;
++			gpios = <&pio 0 17 GPIO_ACTIVE_LOW>; /* PA17 */
++		};
++
++		button@15 {
++			label = "Button B";
++			linux,code = <BTN_B>;
++			gpios = <&pio 0 15 GPIO_ACTIVE_LOW>; /* PA15 */
++		};
++
++		button@16 {
++			label = "Select Button";
++			linux,code = <BTN_SELECT>;
++			gpios = <&pio 0 11 GPIO_ACTIVE_LOW>; /* PA11 */
++		};
++
++		button@17 {
++			label = "Start Button";
++			linux,code = <BTN_START>;
++			gpios = <&pio 0 12 GPIO_ACTIVE_LOW>; /* PA12 */
++		};
++
++		button@18 {
++			label = "Top Left Button";
++			linux,code = <BTN_TL>;
++			gpios = <&pio 7 22 GPIO_ACTIVE_LOW>; /* PH22 */
++		};
++
++		button@19 {
++			label = "Top Right Button";
++			linux,code = <BTN_TR>;
++			gpios = <&pio 0 13 GPIO_ACTIVE_LOW>; /* PA13 */
++		};
++	};
+ };
+ 
+ &cpu0 {
+@@ -86,12 +239,29 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins_a>;
+ 	status = "okay";
++
++	/* Accelerometer */
++	bma250@18 {
++		compatible = "bosch,bma250";
++		reg = <0x18>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 0 IRQ_TYPE_EDGE_RISING>; /* PH0 / EINT0 */
++	};
+ };
+ 
+ &i2c2 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c2_pins_a>;
+ 	status = "okay";
++
++	ft5406ee8: touchscreen@38 {
++		compatible = "edt,edt-ft5406";
++		reg = <0x38>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>;
++		touchscreen-size-x = <800>;
++		touchscreen-size-y = <480>;
++	};
+ };
+ 
+ &lradc {
+@@ -149,6 +319,17 @@
+ };
+ 
+ &pio {
++	key_pins_inet9f: key_pins@0 {
++		allwinner,pins = "PA0", "PA1", "PA3", "PA4",
++				 "PA5", "PA6", "PA8", "PA9",
++				 "PA11", "PA12", "PA13",
++				 "PA14", "PA15", "PA16", "PA17",
++				 "PH22", "PH23", "PH24", "PH25", "PH26";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
+ 	usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ 		allwinner,pins = "PH4";
+ 		allwinner,function = "gpio_in";
+--- a/arch/arm/dts/sun4i-a10-itead-iteaduino-plus.dts
++++ b/arch/arm/dts/sun4i-a10-itead-iteaduino-plus.dts
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright 2015 Josef Gajdusek <atx@atx.name>
++ * Copyright 2015 - Marcus Cooper <codekipper@gmail.com>
+  *
+  * This file is dual-licensed: you can use it either under the terms
+  * of the GPL or the X11 license, at your option. Note that this dual
+@@ -42,22 +43,11 @@
+ 
+ /dts-v1/;
+ #include "sun4i-a10.dtsi"
+-#include "sunxi-common-regulators.dtsi"
+-
+-#include <dt-bindings/gpio/gpio.h>
+-#include <dt-bindings/pinctrl/sun4i-a10.h>
++#include "sunxi-itead-core-common.dtsi"
+ 
+ / {
+ 	model = "Iteaduino Plus A10";
+ 	compatible = "itead,iteaduino-plus-a10", "allwinner,sun4i-a10";
+-
+-	aliases {
+-		serial0 = &uart0;
+-	};
+-
+-	chosen {
+-		stdout-path = "serial0:115200n8";
+-	};
+ };
+ 
+ &ahci {
+@@ -65,18 +55,6 @@
+ 	status = "okay";
+ };
+ 
+-&cpu0 {
+-	cpu-supply = <&reg_dcdc2>;
+-};
+-
+-&ehci0 {
+-	status = "okay";
+-};
+-
+-&ehci1 {
+-	status = "okay";
+-};
+-
+ &emac {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&emac_pins_a>;
+@@ -89,12 +67,7 @@
+ };
+ 
+ &i2c0 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&i2c0_pins_a>;
+-	status = "okay";
+-
+ 	axp209: pmic@34 {
+-		reg = <0x34>;
+ 		interrupts = <0>;
+ 	};
+ };
+@@ -135,68 +108,13 @@
+ 	status = "okay";
+ };
+ 
+-&ohci0 {
+-	status = "okay";
+-};
+-
+-&ohci1 {
+-	status = "okay";
+-};
+-
+ &reg_ahci_5v {
+ 	status = "okay";
+ };
+ 
+-#include "axp209.dtsi"
+-
+-&reg_dcdc2 {
+-	regulator-always-on;
+-	regulator-min-microvolt = <1000000>;
+-	regulator-max-microvolt = <1450000>;
+-	regulator-name = "vdd-cpu";
+-};
+-
+-&reg_dcdc3 {
+-	regulator-always-on;
+-	regulator-min-microvolt = <1000000>;
+-	regulator-max-microvolt = <1400000>;
+-	regulator-name = "vdd-int-dll";
+-};
+-
+-&reg_ldo1 {
+-	regulator-name = "vdd-rtc";
+-};
+-
+-&reg_ldo2 {
+-	regulator-always-on;
+-	regulator-min-microvolt = <3000000>;
+-	regulator-max-microvolt = <3000000>;
+-	regulator-name = "avcc";
+-};
+-
+-&reg_usb1_vbus {
+-	status = "okay";
+-};
+-
+-&reg_usb2_vbus {
+-	status = "okay";
+-};
+-
+ &spi0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&spi0_pins_a>,
+ 		    <&spi0_cs0_pins_a>;
+ 	status = "okay";
+ };
+-
+-&uart0 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&uart0_pins_a>;
+-	status = "okay";
+-};
+-
+-&usbphy {
+-	usb1_vbus-supply = <&reg_usb1_vbus>;
+-	usb2_vbus-supply = <&reg_usb2_vbus>;
+-	status = "okay";
+-};
+--- a/arch/arm/dts/sun4i-a10-jesurun-q5.dts
++++ b/arch/arm/dts/sun4i-a10-jesurun-q5.dts
+@@ -156,6 +156,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	emac_power_pin_q5: emac_power_pin@0 {
+ 		allwinner,pins = "PH19";
+@@ -172,6 +176,11 @@
+ 	};
+ };
+ 
++&reg_usb0_vbus {
++	regulator-boot-on;
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -186,7 +195,13 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "host";
++	status = "okay";
++};
++
+ &usbphy {
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun4i-a10-marsboard.dts
++++ b/arch/arm/dts/sun4i-a10-marsboard.dts
+@@ -91,6 +91,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -154,6 +158,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	led_pins_marsboard: led_pins@0 {
+ 		allwinner,pins = "PB5", "PB6", "PB7", "PB8";
+@@ -161,6 +169,13 @@
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
+ };
+ 
+ &reg_usb1_vbus {
+@@ -184,7 +199,15 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun4i-a10-mk802.dts
++++ b/arch/arm/dts/sun4i-a10-mk802.dts
+@@ -44,6 +44,7 @@
+ #include "sun4i-a10.dtsi"
+ #include "sunxi-common-regulators.dtsi"
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+ / {
+ 	model = "MK802";
+@@ -58,6 +59,10 @@
+ 	};
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -80,7 +85,25 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
++		allwinner,pins = "PH5";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	usb2_vbus_pin_mk802: usb2_vbus_pin@0 {
+ 		allwinner,pins = "PH12";
+ 		allwinner,function = "gpio_out";
+@@ -89,6 +112,10 @@
+ 	};
+ };
+ 
++&reg_usb0_vbus {
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -105,7 +132,17 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
++	usb0_id_det-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_det-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun4i-a10-olinuxino-lime.dts
++++ b/arch/arm/dts/sun4i-a10-olinuxino-lime.dts
+@@ -124,6 +124,18 @@
+ 	};
+ };
+ 
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++
++	eeprom: eeprom@50 {
++		compatible = "atmel,24c16";
++		reg = <0x50>;
++		pagesize = <16>;
++	};
++};
++
+ &mdio {
+ 	status = "okay";
+ 
+--- a/arch/arm/dts/sun4i-a10-pcduino.dts
++++ b/arch/arm/dts/sun4i-a10-pcduino.dts
+@@ -104,6 +104,10 @@
+ 	};
+ };
+ 
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -129,12 +133,8 @@
+ 	status = "okay";
+ 
+ 	axp209: pmic@34 {
+-		compatible = "x-powers,axp209";
+ 		reg = <0x34>;
+ 		interrupts = <0>;
+-
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
+ 	};
+ };
+ 
+@@ -164,6 +164,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	led_pins_pcduino: led_pins@0 {
+ 		allwinner,pins = "PH15", "PH16";
+@@ -178,14 +182,40 @@
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
+ };
+ 
+-&reg_usb1_vbus {
+-	status = "okay";
++#include "axp209.dtsi"
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
+ };
+ 
+-&reg_usb2_vbus {
+-	status = "okay";
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
+ };
+ 
+ &uart0 {
+@@ -194,8 +224,16 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
+-	usb1_vbus-supply = <&reg_usb1_vbus>;
+-	usb2_vbus-supply = <&reg_usb2_vbus>;
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb1_vbus-supply = <&reg_vcc5v0>; /* USB1 VBUS is always on */
++	usb2_vbus-supply = <&reg_vcc5v0>; /* USB2 VBUS is always on */
+ 	status = "okay";
+ };
+--- /dev/null
++++ b/arch/arm/dts/sun4i-a10-pcduino2.dts
+@@ -0,0 +1,78 @@
++/*
++ * Copyright 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/*
++ * The LinkSprite pcDuino2 board is almost identical to the older
++ * LinkSprite pcDuino1 board. The only software visible difference
++ * is that the pcDuino2 board got a USB VBUS voltage regulator, which
++ * is controlled by the PD2 pin (pulled-up by default). Also one of
++ * the USB host ports has been replaced with a USB WIFI chip.
++ */
++
++#include "sun4i-a10-pcduino.dts"
++
++/ {
++	model = "LinkSprite pcDuino2";
++	compatible = "linksprite,a10-pcduino2", "allwinner,sun4i-a10";
++};
++
++&pio {
++	usb2_vbus_pin_pcduino2: usb2_vbus_pin@0 {
++		allwinner,pins = "PD2";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&reg_usb2_vbus {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb2_vbus_pin_pcduino2>;
++	gpio = <&pio 3 2 GPIO_ACTIVE_HIGH>;
++	status = "okay";
++};
++
++&usbphy {
++	usb1_vbus-supply = <&reg_vcc3v3>; /* USB WIFI is always on */
++	usb2_vbus-supply = <&reg_usb2_vbus>;
++	status = "okay";
++};
+--- a/arch/arm/dts/sun4i-a10-pov-protab2-ips9.dts
++++ b/arch/arm/dts/sun4i-a10-pov-protab2-ips9.dts
+@@ -47,6 +47,7 @@
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
++#include <dt-bindings/pwm/pwm.h>
+ 
+ / {
+ 	model = "Point of View Protab2-IPS9";
+@@ -56,11 +57,28 @@
+ 		serial0 = &uart0;
+ 	};
+ 
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pinctrl-names = "default";
++		pinctrl-0 = <&bl_en_pin_protab>;
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <8>;
++		enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
++	};
++
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
+ };
+ 
++&codec {
++	pinctrl-names = "default";
++	pinctrl-0 = <&codec_pa_pin>;
++	allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+@@ -86,12 +104,36 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins_a>;
+ 	status = "okay";
++
++	/* Accelerometer */
++	bma250@18 {
++		compatible = "bosch,bma250";
++		reg = <0x18>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 0 IRQ_TYPE_EDGE_RISING>; /* PH0 / EINT0 */
++	};
+ };
+ 
+ &i2c2 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c2_pins_a>;
+ 	status = "okay";
++
++	pixcir_ts@5c {
++		pinctrl-names = "default";
++		pinctrl-0 = <&touchscreen_pins>;
++		compatible = "pixcir,pixcir_tangoc";
++		reg = <0x5c>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>; /* EINT21 (PH21) */
++		attb-gpio = <&pio 7 21 GPIO_ACTIVE_HIGH>; /* PH21 */
++		enable-gpios = <&pio 0 5 GPIO_ACTIVE_LOW>;
++		wake-gpios = <&pio 1 13 GPIO_ACTIVE_LOW>;
++		touchscreen-size-x = <1024>;
++		touchscreen-size-y = <768>;
++		touchscreen-inverted-x;
++		touchscreen-inverted-y;
++	};
+ };
+ 
+ &lradc {
+@@ -128,6 +170,27 @@
+ };
+ 
+ &pio {
++	bl_en_pin_protab: bl_en_pin@0 {
++		allwinner,pins = "PH7";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	codec_pa_pin: codec_pa_pin@0 {
++		allwinner,pins = "PH15";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	touchscreen_pins: touchscreen_pins@0 {
++		allwinner,pins = "PA5", "PB13";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ 		allwinner,pins = "PH4";
+ 		allwinner,function = "gpio_in";
+@@ -143,6 +206,12 @@
+ 	};
+ };
+ 
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm0_pins_a>;
++	status = "okay";
++};
++
+ &reg_dcdc2 {
+ 	regulator-always-on;
+ 	regulator-min-microvolt = <1000000>;
+--- a/arch/arm/dts/sun4i-a10.dtsi
++++ b/arch/arm/dts/sun4i-a10.dtsi
+@@ -45,6 +45,7 @@
+ 
+ #include <dt-bindings/thermal/thermal.h>
+ 
++#include <dt-bindings/clock/sun4i-a10-pll2.h>
+ #include <dt-bindings/dma/sun4i-a10.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+@@ -65,7 +66,7 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-hdmi";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+-				 <&ahb_gates 44>;
++				 <&ahb_gates 44>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -74,7 +75,8 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+-				 <&ahb_gates 44>, <&ahb_gates 46>;
++				 <&ahb_gates 44>, <&ahb_gates 46>,
++				 <&dram_gates 25>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -83,7 +85,8 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_fe0-de_be0-lcd0";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
+-				 <&ahb_gates 46>;
++				 <&ahb_gates 46>, <&dram_gates 25>,
++				 <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -92,7 +95,8 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_fe0-de_be0-lcd0-tve0";
+ 			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+-				 <&ahb_gates 44>, <&ahb_gates 46>;
++				 <&ahb_gates 44>, <&ahb_gates 46>,
++				 <&dram_gates 25>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 	};
+@@ -195,6 +199,15 @@
+ 			clock-output-names = "pll1";
+ 		};
+ 
++		pll2: clk@01c20008 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-pll2-clk";
++			reg = <0x01c20008 0x8>;
++			clocks = <&osc24M>;
++			clock-output-names = "pll2-1x", "pll2-2x",
++					     "pll2-4x", "pll2-8x";
++		};
++
+ 		pll4: clk@01c20018 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-pll1-clk";
+@@ -241,6 +254,7 @@
+ 			compatible = "allwinner,sun4i-a10-axi-gates-clk";
+ 			reg = <0x01c2005c 0x4>;
+ 			clocks = <&axi>;
++			clock-indices = <0>;
+ 			clock-output-names = "axi_dram";
+ 		};
+ 
+@@ -257,17 +271,36 @@
+ 			compatible = "allwinner,sun4i-a10-ahb-gates-clk";
+ 			reg = <0x01c20060 0x8>;
+ 			clocks = <&ahb>;
++			clock-indices = <0>, <1>,
++					<2>, <3>,
++					<4>, <5>, <6>,
++					<7>, <8>, <9>,
++					<10>, <11>, <12>,
++					<13>, <14>, <16>,
++					<17>, <18>, <20>,
++					<21>, <22>, <23>,
++					<24>, <25>, <26>,
++					<32>, <33>, <34>,
++					<35>, <36>, <37>,
++					<40>, <41>, <43>,
++					<44>, <45>,
++					<46>, <47>,
++					<50>, <52>;
+ 			clock-output-names = "ahb_usb0", "ahb_ehci0",
+-				"ahb_ohci0", "ahb_ehci1", "ahb_ohci1", "ahb_ss",
+-				"ahb_dma", "ahb_bist", "ahb_mmc0", "ahb_mmc1",
+-				"ahb_mmc2", "ahb_mmc3", "ahb_ms", "ahb_nand",
+-				"ahb_sdram", "ahb_ace",	"ahb_emac", "ahb_ts",
+-				"ahb_spi0", "ahb_spi1", "ahb_spi2", "ahb_spi3",
+-				"ahb_pata", "ahb_sata", "ahb_gps", "ahb_ve",
+-				"ahb_tvd", "ahb_tve0", "ahb_tve1", "ahb_lcd0",
+-				"ahb_lcd1", "ahb_csi0", "ahb_csi1", "ahb_hdmi",
+-				"ahb_de_be0", "ahb_de_be1", "ahb_de_fe0",
+-				"ahb_de_fe1", "ahb_mp", "ahb_mali400";
++					     "ahb_ohci0", "ahb_ehci1",
++					     "ahb_ohci1", "ahb_ss", "ahb_dma",
++					     "ahb_bist", "ahb_mmc0", "ahb_mmc1",
++					     "ahb_mmc2", "ahb_mmc3", "ahb_ms",
++					     "ahb_nand", "ahb_sdram", "ahb_ace",
++					     "ahb_emac", "ahb_ts", "ahb_spi0",
++					     "ahb_spi1", "ahb_spi2", "ahb_spi3",
++					     "ahb_pata", "ahb_sata", "ahb_gps",
++					     "ahb_ve", "ahb_tvd", "ahb_tve0",
++					     "ahb_tve1", "ahb_lcd0", "ahb_lcd1",
++					     "ahb_csi0", "ahb_csi1", "ahb_hdmi",
++					     "ahb_de_be0", "ahb_de_be1",
++					     "ahb_de_fe0", "ahb_de_fe1",
++					     "ahb_mp", "ahb_mali400";
+ 		};
+ 
+ 		apb0: apb0@01c20054 {
+@@ -283,9 +316,14 @@
+ 			compatible = "allwinner,sun4i-a10-apb0-gates-clk";
+ 			reg = <0x01c20068 0x4>;
+ 			clocks = <&apb0>;
++			clock-indices = <0>, <1>,
++					<2>, <3>,
++					<5>, <6>,
++					<7>, <10>;
+ 			clock-output-names = "apb0_codec", "apb0_spdif",
+-				"apb0_ac97", "apb0_iis", "apb0_pio", "apb0_ir0",
+-				"apb0_ir1", "apb0_keypad";
++					     "apb0_ac97", "apb0_iis",
++					     "apb0_pio", "apb0_ir0",
++					     "apb0_ir1", "apb0_keypad";
+ 		};
+ 
+ 		apb1: clk@01c20058 {
+@@ -301,12 +339,22 @@
+ 			compatible = "allwinner,sun4i-a10-apb1-gates-clk";
+ 			reg = <0x01c2006c 0x4>;
+ 			clocks = <&apb1>;
++			clock-indices = <0>, <1>,
++					<2>, <4>,
++					<5>, <6>,
++					<7>, <16>,
++					<17>, <18>,
++					<19>, <20>,
++					<21>, <22>,
++					<23>;
+ 			clock-output-names = "apb1_i2c0", "apb1_i2c1",
+-				"apb1_i2c2", "apb1_can", "apb1_scr",
+-				"apb1_ps20", "apb1_ps21", "apb1_uart0",
+-				"apb1_uart1", "apb1_uart2", "apb1_uart3",
+-				"apb1_uart4", "apb1_uart5", "apb1_uart6",
+-				"apb1_uart7";
++					     "apb1_i2c2", "apb1_can",
++					     "apb1_scr", "apb1_ps20",
++					     "apb1_ps21", "apb1_uart0",
++					     "apb1_uart1", "apb1_uart2",
++					     "apb1_uart3", "apb1_uart4",
++					     "apb1_uart5", "apb1_uart6",
++					     "apb1_uart7";
+ 		};
+ 
+ 		nand_clk: clk@01c20080 {
+@@ -446,6 +494,48 @@
+ 			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ 			clock-output-names = "spi3";
+ 		};
++
++		dram_gates: clk@01c20100 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-dram-gates-clk";
++			reg = <0x01c20100 0x4>;
++			clocks = <&pll5 0>;
++			clock-indices = <0>,
++					<1>, <2>,
++					<3>,
++					<4>,
++					<5>, <6>,
++					<15>,
++					<24>, <25>,
++					<26>, <27>,
++					<28>, <29>;
++			clock-output-names = "dram_ve",
++					     "dram_csi0", "dram_csi1",
++					     "dram_ts",
++					     "dram_tvd",
++					     "dram_tve0", "dram_tve1",
++					     "dram_output",
++					     "dram_de_fe1", "dram_de_fe0",
++					     "dram_de_be0", "dram_de_be1",
++					     "dram_de_mp", "dram_ace";
++		};
++
++		ve_clk: clk@01c2013c {
++			#clock-cells = <0>;
++			#reset-cells = <0>;
++			compatible = "allwinner,sun4i-a10-ve-clk";
++			reg = <0x01c2013c 0x4>;
++			clocks = <&pll4>;
++			clock-output-names = "ve";
++		};
++
++		codec_clk: clk@01c20140 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-codec-clk";
++			reg = <0x01c20140 0x4>;
++			clocks = <&pll2 SUN4I_A10_PLL2_1X>;
++			clock-output-names = "codec";
++		};
+ 	};
+ 
+ 	soc@01c00000 {
+@@ -656,6 +746,14 @@
+ 			status = "disabled";
+ 		};
+ 
++		crypto: crypto-engine@01c15000 {
++			compatible = "allwinner,sun4i-a10-crypto";
++			reg = <0x01c15000 0x1000>;
++			interrupts = <86>;
++			clocks = <&ahb_gates 5>, <&ss_clk>;
++			clock-names = "ahb", "mod";
++		};
++
+ 		spi2: spi@01c17000 {
+ 			compatible = "allwinner,sun4i-a10-spi";
+ 			reg = <0x01c17000 0x1000>;
+@@ -961,6 +1059,19 @@
+ 			status = "disabled";
+ 		};
+ 
++		codec: codec@01c22c00 {
++			#sound-dai-cells = <0>;
++			compatible = "allwinner,sun4i-a10-codec";
++			reg = <0x01c22c00 0x40>;
++			interrupts = <30>;
++			clocks = <&apb0_gates 0>, <&codec_clk>;
++			clock-names = "apb", "codec";
++			dmas = <&dma SUN4I_DMA_NORMAL 19>,
++			       <&dma SUN4I_DMA_NORMAL 19>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
+ 		sid: eeprom@01c23800 {
+ 			compatible = "allwinner,sun4i-a10-sid";
+ 			reg = <0x01c23800 0x10>;
+--- a/arch/arm/dts/sun5i-a10s-auxtek-t004.dts
++++ b/arch/arm/dts/sun5i-a10s-auxtek-t004.dts
+@@ -86,6 +86,20 @@
+ 	status = "okay";
+ };
+ 
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++
++	axp152: pmic@30 {
++		compatible = "x-powers,axp152";
++		reg = <0x30>;
++		interrupts = <0>;
++		interrupt-controller;
++		#interrupt-cells = <1>;
++	};
++};
++
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_t004>;
+--- a/arch/arm/dts/sun5i-a10s-olinuxino-micro.dts
++++ b/arch/arm/dts/sun5i-a10s-olinuxino-micro.dts
+@@ -111,7 +111,7 @@
+ 	status = "okay";
+ 
+ 	at24@50 {
+-		compatible = "at,24c16";
++		compatible = "atmel,24c16";
+ 		pagesize = <16>;
+ 		reg = <0x50>;
+ 		read-only;
+--- a/arch/arm/dts/sun5i-a13-empire-electronix-d709.dts
++++ b/arch/arm/dts/sun5i-a13-empire-electronix-d709.dts
+@@ -123,7 +123,7 @@
+ 
+ &mmc0 {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_inet98fv2>;
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_d709>;
+ 	vmmc-supply = <&reg_vcc3v3>;
+ 	bus-width = <4>;
+ 	cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+@@ -131,27 +131,12 @@
+ 	status = "okay";
+ };
+ 
+-&mmc2 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&mmc2_pins_a>;
+-	vmmc-supply = <&reg_vcc3v3>;
+-	bus-width = <8>;
+-	non-removable;
+-	status = "okay";
+-
+-	mmccard: mmccard@0 {
+-		reg = <0>;
+-		compatible = "mmc-card";
+-		broken-hpi;
+-	};
+-};
+-
+ &otg_sram {
+ 	status = "okay";
+ };
+ 
+ &pio {
+-	mmc0_cd_pin_inet98fv2: mmc0_cd_pin@0 {
++	mmc0_cd_pin_d709: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PG0";
+ 		allwinner,function = "gpio_in";
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+--- a/arch/arm/dts/sun5i-a13-inet-98v-rev2.dts
++++ b/arch/arm/dts/sun5i-a13-inet-98v-rev2.dts
+@@ -123,21 +123,6 @@
+ 	status = "okay";
+ };
+ 
+-&mmc2 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&mmc2_pins_a>;
+-	vmmc-supply = <&reg_vcc3v3>;
+-	bus-width = <8>;
+-	non-removable;
+-	status = "okay";
+-
+-	mmccard: mmccard@0 {
+-		reg = <0>;
+-		compatible = "mmc-card";
+-		broken-hpi;
+-	};
+-};
+-
+ &otg_sram {
+ 	status = "okay";
+ };
+@@ -201,11 +186,6 @@
+ 	status = "okay";
+ };
+ 
+-&reg_usb1_vbus {
+-	gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>; /* PG11 */
+-	status = "okay";
+-};
+-
+ &uart1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&uart1_pins_b>;
+@@ -221,16 +201,12 @@
+ 	allwinner,pins = "PG12";
+ };
+ 
+-&usb1_vbus_pin_a {
+-	allwinner,pins = "PG11";
+-};
+-
+ &usbphy {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ 	usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+ 	usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ 	usb0_vbus-supply = <&reg_usb0_vbus>;
+-	usb1_vbus-supply = <&reg_usb1_vbus>;
++	usb1_vbus-supply = <&reg_ldo3>;
+ 	status = "okay";
+ };
+--- a/arch/arm/dts/sun5i-a13-utoo-p66.dts
++++ b/arch/arm/dts/sun5i-a13-utoo-p66.dts
+@@ -47,11 +47,21 @@
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
++#include <dt-bindings/pwm/pwm.h>
+ 
+ / {
+ 	model = "Utoo P66";
+ 	compatible = "utoo,p66", "allwinner,sun5i-a13";
+ 
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		/* Note levels of 10 / 20% result in backlight off */
++		brightness-levels = <0 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <6>;
++		/* TODO: backlight uses axp gpio1 as enable pin */
++	};
++
+ 	i2c_lcd: i2c@0 {
+ 		/* The lcd panel i2c interface is hooked up via gpios */
+ 		compatible = "i2c-gpio";
+@@ -63,6 +73,13 @@
+ 	};
+ };
+ 
++&codec {
++	pinctrl-names = "default";
++	pinctrl-0 = <&codec_pa_pin>;
++	allwinner,pa-gpios = <&pio 6 3 GPIO_ACTIVE_HIGH>; /* PG3 */
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+@@ -158,6 +175,13 @@
+ };
+ 
+ &pio {
++	codec_pa_pin: codec_pa_pin@0 {
++		allwinner,pins = "PG3";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	mmc0_cd_pin_p66: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PG0";
+ 		allwinner,function = "gpio_in";
+@@ -201,6 +225,12 @@
+ 	};
+ };
+ 
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm0_pins>;
++	status = "okay";
++};
++
+ &reg_dcdc2 {
+ 	regulator-always-on;
+ 	regulator-min-microvolt = <1000000>;
+--- a/arch/arm/dts/sun5i-q8-common.dtsi
++++ b/arch/arm/dts/sun5i-q8-common.dtsi
+@@ -41,11 +41,21 @@
+  */
+ #include "sunxi-q8-common.dtsi"
+ 
++#include <dt-bindings/pwm/pwm.h>
++
+ / {
+ 	aliases {
+ 		serial0 = &uart1;
+ 	};
+ 
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <8>;
++		/* TODO: backlight uses axp gpio1 as enable pin */
++	};
++
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
+--- a/arch/arm/dts/sun5i-r8-chip.dts
++++ b/arch/arm/dts/sun5i-r8-chip.dts
+@@ -64,6 +64,26 @@
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
++
++	wifi_reg_on: wifi_reg_on {
++		compatible = "regulator-fixed";
++		pinctrl-names = "default";
++		pinctrl-0 = <&chip_wifi_reg_on_pin>;
++
++		regulator-name = "wifi-reg-on";
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		gpio = <&pio 2 19 GPIO_ACTIVE_HIGH>; /* PC19 */
++		enable-active-high;
++	};
++};
++
++&codec {
++	status = "okay";
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
+ };
+ 
+ &ehci0 {
+@@ -109,10 +129,14 @@
+ 	};
+ };
+ 
++&mmc0_pins_a {
++	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++};
++
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>;
+-	vmmc-supply = <&reg_vcc3v3>;
++	vmmc-supply = <&wifi_reg_on>;
+ 	bus-width = <4>;
+ 	non-removable;
+ 	status = "okay";
+@@ -134,6 +158,13 @@
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
+ 
++	chip_wifi_reg_on_pin: chip_wifi_reg_on_pin@0 {
++		allwinner,pins = "PC19";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	chip_id_det_pin: chip_id_det_pin@0 {
+ 		allwinner,pins = "PG2";
+ 		allwinner,function = "gpio_in";
+@@ -167,6 +198,20 @@
+ 	regulator-always-on;
+ };
+ 
++&reg_ldo3 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vdd-wifi1";
++	regulator-always-on;
++};
++
++&reg_ldo4 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vdd-wifi2";
++	regulator-always-on;
++};
++
+ &reg_ldo5 {
+ 	regulator-min-microvolt = <1800000>;
+ 	regulator-max-microvolt = <1800000>;
+--- a/arch/arm/dts/sun5i.dtsi
++++ b/arch/arm/dts/sun5i.dtsi
+@@ -44,6 +44,7 @@
+ 
+ #include "skeleton.dtsi"
+ 
++#include <dt-bindings/clock/sun4i-a10-pll2.h>
+ #include <dt-bindings/dma/sun4i-a10.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+@@ -102,6 +103,15 @@
+ 			clock-output-names = "pll1";
+ 		};
+ 
++		pll2: clk@01c20008 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun5i-a13-pll2-clk";
++			reg = <0x01c20008 0x8>;
++			clocks = <&osc24M>;
++			clock-output-names = "pll2-1x", "pll2-2x",
++					     "pll2-4x", "pll2-8x";
++		};
++
+ 		pll4: clk@01c20018 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-pll1-clk";
+@@ -285,6 +295,14 @@
+ 			clock-output-names = "usb_ohci0", "usb_phy";
+ 		};
+ 
++		codec_clk: clk@01c20140 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-codec-clk";
++			reg = <0x01c20140 0x4>;
++			clocks = <&pll2 SUN4I_A10_PLL2_1X>;
++			clock-output-names = "codec";
++		};
++
+ 		mbus_clk: clk@01c2015c {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun5i-a13-mbus-clk";
+@@ -571,6 +589,19 @@
+ 			status = "disabled";
+ 		};
+ 
++		codec: codec@01c22c00 {
++			#sound-dai-cells = <0>;
++			compatible = "allwinner,sun4i-a10-codec";
++			reg = <0x01c22c00 0x40>;
++			interrupts = <30>;
++			clocks = <&apb0_gates 0>, <&codec_clk>;
++			clock-names = "apb", "codec";
++			dmas = <&dma SUN4I_DMA_NORMAL 19>,
++			       <&dma SUN4I_DMA_NORMAL 19>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
+ 		sid: eeprom@01c23800 {
+ 			compatible = "allwinner,sun4i-a10-sid";
+ 			reg = <0x01c23800 0x10>;
+--- a/arch/arm/dts/sun6i-a31-colombus.dts
++++ b/arch/arm/dts/sun6i-a31-colombus.dts
+@@ -60,6 +60,16 @@
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
++
++	i2c_lcd: i2c@0 {
++		/* The lcd panel i2c interface is hooked up via gpios */
++		compatible = "i2c-gpio";
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c_lcd_pins>;
++		gpios = <&pio 0 23 GPIO_ACTIVE_HIGH>, /* PA23, sda */
++			<&pio 0 24 GPIO_ACTIVE_HIGH>; /* PA24, scl */
++		i2c-gpio,delay-us = <5>;
++	};
+ };
+ 
+ &ehci1 {
+@@ -94,6 +104,13 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c2_pins_a>;
+ 	status = "okay";
++
++	mma8452: mma8452@1d {
++		compatible = "fsl,mma8452";
++		reg = <0x1d>;
++		interrupt-parent = <&pio>;
++		interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PA9 */
++	};
+ };
+ 
+ &mmc0 {
+@@ -124,6 +141,13 @@
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
++
++	i2c_lcd_pins: i2c_lcd_pin@0 {
++		allwinner,pins = "PA23", "PA24";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
+ };
+ 
+ &reg_usb2_vbus {
+--- a/arch/arm/dts/sun6i-a31-hummingbird.dts
++++ b/arch/arm/dts/sun6i-a31-hummingbird.dts
+@@ -54,6 +54,8 @@
+ 	compatible = "merrii,a31-hummingbird", "allwinner,sun6i-a31";
+ 
+ 	aliases {
++		rtc0 = &pcf8563;
++		rtc1 = &rtc;
+ 		serial0 = &uart0;
+ 	};
+ 
+@@ -67,13 +69,17 @@
+ 	};
+ };
+ 
++&cpu0 {
++	cpu-supply = <&reg_dcdc3>;
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+ 
+ &gmac {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&gmac_pins_rgmii_a>;
++	pinctrl-0 = <&gmac_pins_rgmii_a>, <&gmac_phy_reset_pin_hummingbird>;
+ 	phy = <&phy1>;
+ 	phy-mode = "rgmii";
+ 	snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>;
+@@ -119,7 +125,7 @@
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_hummingbird>;
+-	vmmc-supply = <&vcc_3v0>;
++	vmmc-supply = <&reg_dcdc1>;
+ 	bus-width = <4>;
+ 	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+ 	cd-inverted;
+@@ -134,7 +140,7 @@
+ &mmc1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc1_pins_a>, <&wifi_reset_pin_hummingbird>;
+-	vmmc-supply = <&vcc_wifi>;
++	vmmc-supply = <&reg_aldo1>;
+ 	mmc-pwrseq = <&wifi_pwrseq>;
+ 	bus-width = <4>;
+ 	non-removable;
+@@ -146,6 +152,13 @@
+ };
+ 
+ &pio {
++	gmac_phy_reset_pin_hummingbird: gmac_phy_reset_pin@0 {
++		allwinner,pins = "PA21";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	mmc0_cd_pin_hummingbird: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PA8";
+ 		allwinner,function = "gpio_in";
+@@ -164,70 +177,69 @@
+ &p2wi {
+ 	status = "okay";
+ 
+-	axp221: pmic@68 {
++	axp22x: pmic@68 {
+ 		compatible = "x-powers,axp221";
+ 		reg = <0x68>;
+ 		interrupt-parent = <&nmi_intc>;
+ 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
+-		dcdc1-supply = <&vcc_3v0>;
+-		dcdc5-supply = <&vcc_dram>;
+-
+-		regulators {
+-			x-powers,dcdc-freq = <3000>;
+-
+-			vcc_3v0: dcdc1 {
+-				regulator-always-on;
+-				regulator-min-microvolt = <3000000>;
+-				regulator-max-microvolt = <3000000>;
+-				regulator-name = "vcc-3v0";
+-			};
+-
+-			vdd_cpu: dcdc2 {
+-				regulator-always-on;
+-				regulator-min-microvolt = <700000>;
+-				regulator-max-microvolt = <1320000>;
+-				regulator-name = "vdd-cpu";
+-			};
+-
+-			vdd_gpu: dcdc3 {
+-				regulator-always-on;
+-				regulator-min-microvolt = <700000>;
+-				regulator-max-microvolt = <1320000>;
+-				regulator-name = "vdd-gpu";
+-			};
+-
+-			vdd_sys_dll: dcdc4 {
+-				regulator-always-on;
+-				regulator-min-microvolt = <1100000>;
+-				regulator-max-microvolt = <1100000>;
+-				regulator-name = "vdd-sys-dll";
+-			};
+-
+-			vcc_dram: dcdc5 {
+-				regulator-always-on;
+-				regulator-min-microvolt = <1500000>;
+-				regulator-max-microvolt = <1500000>;
+-				regulator-name = "vcc-dram";
+-			};
+-
+-			vcc_wifi: aldo1 {
+-				regulator-min-microvolt = <3300000>;
+-				regulator-max-microvolt = <3300000>;
+-				regulator-name = "vcc_wifi";
+-			};
+-
+-			avcc: aldo3 {
+-				regulator-always-on;
+-				regulator-min-microvolt = <3000000>;
+-				regulator-max-microvolt = <3000000>;
+-				regulator-name = "avcc";
+-			};
+-		};
+ 	};
+ };
+ 
++#include "axp22x.dtsi"
++
++&reg_aldo1 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-wifi";
++};
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "avcc";
++};
++
++&reg_dc5ldo {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpus";
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-gpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc4 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-sys-dll";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
+ &reg_usb1_vbus {
+ 	gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>; /* PH24 */
+ 	status = "okay";
+--- a/arch/arm/dts/sun6i-a31.dtsi
++++ b/arch/arm/dts/sun6i-a31.dtsi
+@@ -61,7 +61,7 @@
+ 		#size-cells = <1>;
+ 		ranges;
+ 
+-		framebuffer@0 {
++		simplefb_hdmi: framebuffer@0 {
+ 			compatible = "allwinner,simple-framebuffer",
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-hdmi";
+@@ -69,7 +69,7 @@
+ 			status = "disabled";
+ 		};
+ 
+-		framebuffer@1 {
++		simplefb_lcd: framebuffer@1 {
+ 			compatible = "allwinner,simple-framebuffer",
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0";
+@@ -252,6 +252,20 @@
+ 			compatible = "allwinner,sun6i-a31-ahb1-gates-clk";
+ 			reg = <0x01c20060 0x8>;
+ 			clocks = <&ahb1>;
++			clock-indices = <1>, <5>,
++					<6>, <8>, <9>,
++					<10>, <11>, <12>,
++					<13>, <14>,
++					<17>, <18>, <19>,
++					<20>, <21>, <22>,
++					<23>, <24>, <26>,
++					<27>, <29>,
++					<30>, <31>, <32>,
++					<36>, <37>, <40>,
++					<43>, <44>, <45>,
++					<46>, <47>, <50>,
++					<52>, <55>, <56>,
++					<57>, <58>;
+ 			clock-output-names = "ahb1_mipidsi", "ahb1_ss",
+ 					"ahb1_dma", "ahb1_mmc0", "ahb1_mmc1",
+ 					"ahb1_mmc2", "ahb1_mmc3", "ahb1_nand1",
+@@ -281,6 +295,9 @@
+ 			compatible = "allwinner,sun6i-a31-apb1-gates-clk";
+ 			reg = <0x01c20068 0x4>;
+ 			clocks = <&apb1>;
++			clock-indices = <0>, <4>,
++					<5>, <12>,
++					<13>;
+ 			clock-output-names = "apb1_codec", "apb1_digital_mic",
+ 					"apb1_pio", "apb1_daudio0",
+ 					"apb1_daudio1";
+@@ -299,6 +316,10 @@
+ 			compatible = "allwinner,sun6i-a31-apb2-gates-clk";
+ 			reg = <0x01c2006c 0x4>;
+ 			clocks = <&apb2>;
++			clock-indices = <0>, <1>,
++					<2>, <3>, <16>,
++					<17>, <18>, <19>,
++					<20>, <21>;
+ 			clock-output-names = "apb2_i2c0", "apb2_i2c1",
+ 					     "apb2_i2c2", "apb2_i2c3",
+ 					     "apb2_uart0", "apb2_uart1",
+@@ -346,6 +367,14 @@
+ 					     "mmc3_sample";
+ 		};
+ 
++		ss_clk: clk@01c2009c {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-mod0-clk";
++			reg = <0x01c2009c 0x4>;
++			clocks = <&osc24M>, <&pll6 0>;
++			clock-output-names = "ss";
++		};
++
+ 		spi0_clk: clk@01c200a0 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-mod0-clk";
+@@ -384,6 +413,9 @@
+ 			compatible = "allwinner,sun6i-a31-usb-clk";
+ 			reg = <0x01c200cc 0x4>;
+ 			clocks = <&osc24M>;
++			clock-indices = <8>, <9>, <10>,
++					<16>, <17>,
++					<18>;
+ 			clock-output-names = "usb_phy0", "usb_phy1", "usb_phy2",
+ 					     "usb_ohci0", "usb_ohci1",
+ 					     "usb_ohci2";
+@@ -684,6 +716,16 @@
+ 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 			};
+ 
++			mmc3_8bit_emmc_pins: mmc3@1 {
++				allwinner,pins = "PC6", "PC7", "PC8", "PC9",
++						 "PC10", "PC11", "PC12",
++						 "PC13", "PC14", "PC15",
++						 "PC24";
++				allwinner,function = "mmc3";
++				allwinner,drive = <SUN4I_PINCTRL_40_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++
+ 			gmac_pins_mii_a: gmac_mii@0 {
+ 				allwinner,pins = "PA0", "PA1", "PA2", "PA3",
+ 						"PA8", "PA9", "PA11",
+@@ -761,6 +803,13 @@
+ 			reg = <0x01c20ca0 0x20>;
+ 		};
+ 
++		lradc: lradc@01c22800 {
++			compatible = "allwinner,sun4i-a10-lradc-keys";
++			reg = <0x01c22800 0x100>;
++			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++		};
++
+ 		rtp: rtp@01c25000 {
+ 			compatible = "allwinner,sun6i-a31-ts";
+ 			reg = <0x01c25000 0x100>;
+@@ -907,6 +956,16 @@
+ 			#size-cells = <0>;
+ 		};
+ 
++		crypto: crypto-engine@01c15000 {
++			compatible = "allwinner,sun4i-a10-crypto";
++			reg = <0x01c15000 0x1000>;
++			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&ahb1_gates 5>, <&ss_clk>;
++			clock-names = "ahb", "mod";
++			resets = <&ahb1_rst 5>;
++			reset-names = "ahb";
++		};
++
+ 		timer@01c60000 {
+ 			compatible = "allwinner,sun6i-a31-hstimer",
+ 				     "allwinner,sun7i-a20-hstimer";
+@@ -1068,7 +1127,7 @@
+ 			resets = <&apb0_rst 0>;
+ 			gpio-controller;
+ 			interrupt-controller;
+-			#interrupt-cells = <2>;
++			#interrupt-cells = <3>;
+ 			#size-cells = <0>;
+ 			#gpio-cells = <3>;
+ 
+--- a/arch/arm/dts/sun6i-a31s-primo81.dts
++++ b/arch/arm/dts/sun6i-a31s-primo81.dts
+@@ -1,16 +1,57 @@
+ /*
+- * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
++ * Copyright 2014 Siarhei Siamashka <siarhei.siamashka@gmail.com>
++ * Copyright 2015 Karsten Merker <merker@debian.org>
++ * Copyright 2015 Chen-Yu Tsai <wens@csie.org>
+  *
+- * Minimal dts file for the MSI Primo81 for u-boot only
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
+  *
+- * SPDX-License-Identifier:     GPL-2.0+ or X11
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
+  */
+ 
+ /dts-v1/;
+ #include "sun6i-a31s.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+ / {
+-	model = "MSI Primo81";
++	model = "MSI Primo81 tablet";
+ 	compatible = "msi,primo81", "allwinner,sun6i-a31s";
+ 
+ 	aliases {
+@@ -22,8 +63,202 @@
+ 	};
+ };
+ 
+-&uart0 {
++&cpu0 {
++	cpu-supply = <&reg_dcdc3>;
++};
++
++&ehci0 {
++	/* rtl8188etv wifi is connected here */
++	status = "okay";
++};
++
++&i2c0 {
++	/* pull-ups and device VDDIO use AXP221 DLDO3 */
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "failed";
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++
++	ctp@5d {
++		pinctrl-names = "default";
++		pinctrl-0 = <&gt911_int_primo81>;
++		compatible = "goodix,gt911";
++		reg = <0x5d>;
++		interrupt-parent = <&pio>;
++		interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>; /* PA3 */
++		touchscreen-swapped-x-y;
++	};
++};
++
++&i2c2 {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&uart0_pins_a>;
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++
++	accelerometer@1c {
++		pinctrl-names = "default";
++		pinctrl-0 = <&mma8452_int_primo81>;
++		compatible = "fsl,mma8452";
++		reg = <0x1c>;
++		interrupt-parent = <&pio>;
++		interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>; /* PA9 */
++		#io-channel-cells = <1>;
++	};
++};
++
++&lradc {
++	vref-supply = <&reg_aldo3>;
++	status = "okay";
++
++	button@158 {
++		label = "Volume Up";
++		linux,code = <KEY_VOLUMEUP>;
++		channel = <0>;
++		voltage = <158730>;
++	};
++
++	button@349 {
++		label = "Volume Down";
++		linux,code = <KEY_VOLUMEDOWN>;
++		channel = <0>;
++		voltage = <349206>;
++	};
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_primo81>;
++	vmmc-supply = <&reg_dcdc1>;
++	bus-width = <4>;
++	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
++	cd-inverted;
++	status = "okay";
++};
++
++&pio {
++	gt911_int_primo81: gt911_int_pin@0 {
++		allwinner,pins = "PA3";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	mma8452_int_primo81: mma8452_int_pin@0 {
++		allwinner,pins = "PA9";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	mmc0_cd_pin_primo81: mmc0_cd_pin@0 {
++		allwinner,pins = "PA8";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++};
++
++&p2wi {
++	status = "okay";
++
++	axp22x: pmic@68 {
++		compatible = "x-powers,axp221";
++		reg = <0x68>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++#include "axp22x.dtsi"
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "avcc";
++};
++
++&reg_dc1sw {
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-lcd";
++};
++
++&reg_dc5ldo {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpus"; /* This is an educated guess */
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-gpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc4 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-sys-dll";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
++&reg_dldo1 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-wifi";
++};
++
++&reg_dldo3 {
++	regulator-min-microvolt = <2800000>;
++	regulator-max-microvolt = <2800000>;
++	regulator-name = "vddio-csi";
++};
++
++&reg_eldo3 {
++	regulator-min-microvolt = <1080000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-mipi-bridge";
++};
++
++&simplefb_lcd {
++	vcc-lcd-supply = <&reg_dc1sw>;
++	vdd-mipi-bridge-supply = <&reg_eldo3>;
++};
++
++&usb_otg {
++	/* otg support requires support for AXP221 usb-power-supply and GPIO */
++	dr_mode = "host";
++	status = "okay";
++};
++
++&usbphy {
++	usb1_vbus-supply = <&reg_dldo1>;
+ 	status = "okay";
+ };
+--- /dev/null
++++ b/arch/arm/dts/sun6i-a31s-sina31s-core.dtsi
+@@ -0,0 +1,142 @@
++/*
++ * Copyright 2015 Chen-Yu Tsai <wens@csie.org>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun6i-a31s.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "Sinlinx SinA31s Core Board";
++	compatible = "sinlinx,sina31s", "allwinner,sun6i-a31s";
++
++	aliases {
++		serial0 = &uart0;
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc3>;
++};
++
++/* eMMC on core board */
++&mmc3 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc3_8bit_emmc_pins>;
++	vmmc-supply = <&reg_dcdc1>;
++	vqmmc-supply = <&reg_dcdc1>;
++	bus-width = <8>;
++	non-removable;
++	cap-mmc-hw-reset;
++	status = "okay";
++};
++
++/* AXP221s PMIC on core board */
++&p2wi {
++	status = "okay";
++
++	axp22x: pmic@68 {
++		compatible = "x-powers,axp221";
++		reg = <0x68>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++#include "axp22x.dtsi"
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "avcc";
++};
++
++&reg_dc5ldo {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpus";
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-gpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc4 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-sys-dll";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
++/* UART0 pads available on core board */
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
+--- /dev/null
++++ b/arch/arm/dts/sun6i-a31s-sina31s.dts
+@@ -0,0 +1,153 @@
++/*
++ * Copyright 2015 Chen-Yu Tsai <wens@csie.org>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/* The SinA31s development board has the SinA31s core board soldered on */
++#include "sun6i-a31s-sina31s-core.dtsi"
++
++#include <dt-bindings/input/input.h>
++
++/ {
++	model = "Sinlinx SinA31s Development Board";
++	compatible = "sinlinx,sina31s-sdk", "allwinner,sun6i-a31s";
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&led_pin_sina31s>;
++
++		status {
++			label = "sina31s:status:usr";
++			gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; /* PH13 */
++		};
++	};
++};
++
++&ehci0 {
++	/* USB 2.0 4 port hub IC */
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&gmac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&gmac_pins_mii_a>;
++	phy = <&phy1>;
++	phy-mode = "mii";
++	phy-supply = <&reg_dldo1>;
++	status = "okay";
++
++	phy1: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&ir {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ir_pins_a>;
++	status = "okay";
++};
++
++&lradc {
++	vref-supply = <&reg_aldo3>;
++	status = "okay";
++
++	button@158 {
++		label = "Volume Up";
++		linux,code = <KEY_VOLUMEUP>;
++		channel = <0>;
++		voltage = <158730>;
++	};
++
++	button@349 {
++		label = "Volume Down";
++		linux,code = <KEY_VOLUMEDOWN>;
++		channel = <0>;
++		voltage = <349206>;
++	};
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_sina31s>;
++	vmmc-supply = <&reg_dcdc1>;
++	bus-width = <4>;
++	cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */
++	cd-inverted;
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++&pio {
++	led_pin_sina31s: led_pin@0 {
++		allwinner,pins = "PH13";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	mmc0_cd_pin_sina31s: mmc0_cd_pin@0 {
++		allwinner,pins = "PA4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++};
++
++&reg_dldo1 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-gmac-phy";
++};
++
++&usbphy {
++	status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+@@ -0,0 +1,205 @@
++/*
++ * Copyright 2015 Lawrence Yu <lyu@micile.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun6i-a31s.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "Yones TopTech BS1078 v2 Tablet";
++	compatible = "yones-toptech,bs1078-v2", "allwinner,sun6i-a31s";
++
++	aliases {
++		serial0 = &uart0;
++		i2c1 = &i2c1;
++		i2c2 = &i2c2;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++&pio {
++	mmc0_cd_pin_bs1078v2: mmc0_cd_pin@0 {
++		allwinner,pins = "PA8";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bs1078v2>;
++	vmmc-supply = <&reg_vcc3v0>;
++	bus-width = <4>;
++	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
++	cd-inverted;
++	status = "okay";
++};
++
++&mmc0_pins_a {
++	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++};
++
++&p2wi {
++	status = "okay";
++
++	axp22x: pmic@68 {
++		compatible = "x-powers,axp221";
++		reg = <0x68>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++#include "axp22x.dtsi"
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "avcc";
++};
++
++&reg_dc1sw {
++	regulator-name = "vcc-lcd-usb2";
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++};
++
++&reg_dc5ldo {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpus";
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-gpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc4 {
++	regulator-always-on;
++	regulator-min-microvolt = <700000>;
++	regulator-max-microvolt = <1320000>;
++	regulator-name = "vdd-sys-dll";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
++&reg_dldo1 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-wifi";
++};
++
++/* Voltage source for I2C pullup resistors for I2C Bus 0 */
++&reg_dldo3 {
++	regulator-min-microvolt = <2800000>;
++	regulator-max-microvolt = <2800000>;
++	regulator-name = "vddio-csi";
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
++&usbphy {
++	usb1_vbus-supply = <&reg_dldo1>;
++	usb2_vbus-supply = <&reg_dc1sw>;
++	status = "okay";
++};
+--- a/arch/arm/dts/sun7i-a20-bananapi.dts
++++ b/arch/arm/dts/sun7i-a20-bananapi.dts
+@@ -92,6 +92,24 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++	operating-points = <
++		/* kHz	  uV */
++		960000	1400000
++		912000	1400000
++		864000	1350000
++		720000	1250000
++		528000	1150000
++		312000	1100000
++		144000	1050000
++		>;
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -119,13 +137,9 @@
+ 	status = "okay";
+ 
+ 	axp209: pmic@34 {
+-		compatible = "x-powers,axp209";
+ 		reg = <0x34>;
+ 		interrupt-parent = <&nmi_intc>;
+ 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+-
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
+ 	};
+ };
+ 
+@@ -159,7 +173,18 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
+ 	mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PH10";
+ 		allwinner,function = "gpio_in";
+@@ -182,6 +207,37 @@
+ 	};
+ };
+ 
++#include "axp209.dtsi"
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
++&reg_usb0_vbus {
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -216,7 +272,21 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
++&usb_power_supply {
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_power-supply = <&usb_power_supply>;
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-cubieboard2.dts
++++ b/arch/arm/dts/sun7i-a20-cubieboard2.dts
+@@ -84,6 +84,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+@@ -150,6 +154,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	led_pins_cubieboard2: led_pins@0 {
+ 		allwinner,pins = "PH20", "PH21";
+@@ -157,12 +165,24 @@
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
+ };
+ 
+ &reg_ahci_5v {
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ #include "axp209.dtsi"
+ 
+ &reg_dcdc2 {
+@@ -205,6 +225,9 @@
+ };
+ 
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/dts/sun7i-a20-cubietruck.dts
+@@ -101,6 +101,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+--- /dev/null
++++ b/arch/arm/dts/sun7i-a20-icnova-swac.dts
+@@ -0,0 +1,169 @@
++/*
++ * Copyright 2015 Stefan Roese <sr@denx.de>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun7i-a20.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "ICnova-A20 SWAC";
++	compatible = "swac,icnova-a20-swac", "incircuit,icnova-a20", "allwinner,sun7i-a20";
++
++	aliases {
++		serial0 = &uart0;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&gmac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&gmac_pins_mii_a>;
++	phy = <&phy1>;
++	phy-mode = "mii";
++	status = "okay";
++
++	phy1: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++
++	axp209: pmic@34 {
++		reg = <0x34>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
++	vmmc-supply = <&reg_vcc3v3>;
++	bus-width = <4>;
++	cd-gpios = <&pio 8 5 GPIO_ACTIVE_HIGH>; /* PI5 */
++	cd-inverted;
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++#include "axp209.dtsi"
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
++&reg_usb1_vbus {
++	status = "okay";
++};
++
++&reg_usb2_vbus {
++	status = "okay";
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
++&usbphy {
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++	usb2_vbus-supply = <&reg_usb2_vbus>;
++	status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/dts/sun7i-a20-itead-ibox.dts
+@@ -0,0 +1,125 @@
++/*
++ * Copyright 2015 - Marcus Cooper <codekipper@gmail.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun7i-a20.dtsi"
++#include "sunxi-itead-core-common.dtsi"
++
++/ {
++	model = "Itead Ibox A20";
++	compatible = "itead,itead-ibox-a20", "allwinner,sun7i-a20";
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&led_pins_itead_core>;
++
++		green {
++			label = "itead_core:green:usr";
++			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
++			default-state = "on";
++		};
++
++		blue {
++			label = "itead_core:blue:usr";
++			gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>;
++			default-state = "on";
++		};
++	};
++};
++
++&ahci {
++	target-supply = <&reg_ahci_5v>;
++	status = "okay";
++};
++
++&codec {
++	status = "okay";
++};
++
++&gmac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&gmac_pins_mii_a>;
++	phy = <&phy1>;
++	phy-mode = "mii";
++	status = "okay";
++
++	phy1: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&i2c0 {
++	axp209: pmic@34 {
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++&ir0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ir0_rx_pins_a>;
++	status = "okay";
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
++	vmmc-supply = <&reg_vcc3v3>;
++	bus-width = <4>;
++	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
++	cd-inverted;
++	status = "okay";
++};
++
++&pio {
++	led_pins_itead_core: led_pins@0 {
++		allwinner,pins = "PH20","PH21";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_20_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&reg_ahci_5v {
++	status = "okay";
++};
+--- a/arch/arm/dts/sun7i-a20-lamobo-r1.dts
++++ b/arch/arm/dts/sun7i-a20-lamobo-r1.dts
+@@ -97,16 +97,6 @@
+ 
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+-	operating-points = <
+-		/* kHz	  uV */
+-		960000	1400000
+-		912000	1400000
+-		864000	1350000
+-		720000	1250000
+-		528000	1150000
+-		312000	1100000
+-		144000	1050000
+-		>;
+ };
+ 
+ &ehci0 {
+--- a/arch/arm/dts/sun7i-a20-mk808c.dts
++++ b/arch/arm/dts/sun7i-a20-mk808c.dts
+@@ -53,6 +53,7 @@
+ 
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+ / {
+ 	model = "mk808c";
+@@ -68,6 +69,10 @@
+ 	};
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -121,6 +126,30 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
++&pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
++		allwinner,pins = "PH5";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&reg_usb0_vbus {
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -141,7 +170,17 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
++	usb0_id_det-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_det-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-olimex-som-evb.dts
++++ b/arch/arm/dts/sun7i-a20-olimex-som-evb.dts
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright 2015 - Marcus Cooper <codekipper@gmail.com>
++ * Copyright 2015 - Karsten Merker <merker@debian.org>
+  *
+  * This file is dual-licensed: you can use it either under the terms
+  * of the GPL or the X11 license, at your option. Note that this dual
+@@ -45,6 +46,7 @@
+ #include "sunxi-common-regulators.dtsi"
+ 
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+@@ -71,14 +73,6 @@
+ 			default-state = "on";
+ 		};
+ 	};
+-
+-	reg_axp_ipsout: axp_ipsout {
+-		compatible = "regulator-fixed";
+-		regulator-name = "axp-ipsout";
+-		regulator-min-microvolt = <5000000>;
+-		regulator-max-microvolt = <5000000>;
+-		regulator-always-on;
+-	};
+ };
+ 
+ &ahci {
+@@ -94,6 +88,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &gmac {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&gmac_pins_rgmii_a>;
+@@ -118,10 +116,58 @@
+ 	};
+ };
+ 
+-&i2c1 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&i2c1_pins_a>;
++&lradc {
++	vref-supply = <&reg_vcc3v0>;
+ 	status = "okay";
++
++	button@190 {
++		label = "Volume Up";
++		linux,code = <KEY_VOLUMEUP>;
++		channel = <0>;
++		voltage = <190000>;
++	};
++
++	button@390 {
++		label = "Volume Down";
++		linux,code = <KEY_VOLUMEDOWN>;
++		channel = <0>;
++		voltage = <390000>;
++	};
++
++	button@600 {
++		label = "Menu";
++		linux,code = <KEY_MENU>;
++		channel = <0>;
++		voltage = <600000>;
++	};
++
++	button@800 {
++		label = "Search";
++		linux,code = <KEY_SEARCH>;
++		channel = <0>;
++		voltage = <800000>;
++	};
++
++	button@980 {
++		label = "Home";
++		linux,code = <KEY_HOMEPAGE>;
++		channel = <0>;
++		voltage = <980000>;
++	};
++
++	button@1180 {
++		label = "Esc";
++		linux,code = <KEY_ESC>;
++		channel = <0>;
++		voltage = <1180000>;
++	};
++
++	button@1400 {
++		label = "Enter";
++		linux,code = <KEY_ENTER>;
++		channel = <0>;
++		voltage = <1400000>;
++	};
+ };
+ 
+ &mmc0 {
+@@ -134,6 +180,16 @@
+ 	status = "okay";
+ };
+ 
++&mmc3 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olimex_som_evb>;
++	vmmc-supply = <&reg_vcc3v3>;
++	bus-width = <4>;
++	cd-gpios = <&pio 7 0 GPIO_ACTIVE_HIGH>; /* PH0 */
++	cd-inverted;
++	status = "okay";
++};
++
+ &ohci0 {
+ 	status = "okay";
+ };
+@@ -161,15 +217,22 @@
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
+ 
++	mmc3_cd_pin_olimex_som_evb: mmc3_cd_pin@0 {
++		allwinner,pins = "PH0";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
+ 	usb0_id_detect_pin: usb0_id_detect_pin@0 {
+-		allwinner,pins = "PH04";
++		allwinner,pins = "PH4";
+ 		allwinner,function = "gpio_in";
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
+ 
+ 	usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+-		allwinner,pins = "PH05";
++		allwinner,pins = "PH5";
+ 		allwinner,function = "gpio_in";
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+@@ -187,7 +250,7 @@
+ &reg_dcdc2 {
+ 	regulator-always-on;
+ 	regulator-min-microvolt = <1000000>;
+-	regulator-max-microvolt = <1425000>;
++	regulator-max-microvolt = <1400000>;
+ 	regulator-name = "vdd-cpu";
+ };
+ 
+@@ -235,8 +298,8 @@
+ &usbphy {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+-	usb0_id_det-gpios = <&pio 7 04 GPIO_ACTIVE_HIGH>; /* PH04 */
+-	usb0_vbus_det-gpios = <&pio 7 05 GPIO_ACTIVE_HIGH>; /* PH05 */
++	usb0_id_det-gpios = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH04 */
++	usb0_vbus_det-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH05 */
+ 	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+--- a/arch/arm/dts/sun7i-a20-olinuxino-lime.dts
++++ b/arch/arm/dts/sun7i-a20-olinuxino-lime.dts
+@@ -117,6 +117,18 @@
+ 	};
+ };
+ 
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++
++	eeprom: eeprom@50 {
++		compatible = "atmel,24c16";
++		reg = <0x50>;
++		pagesize = <16>;
++	};
++};
++
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+--- a/arch/arm/dts/sun7i-a20-olinuxino-lime2.dts
++++ b/arch/arm/dts/sun7i-a20-olinuxino-lime2.dts
+@@ -170,6 +170,12 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins_a>;
+ 	status = "okay";
++
++	eeprom: eeprom@50 {
++		compatible = "atmel,24c16";
++		reg = <0x50>;
++		pagesize = <16>;
++	};
+ };
+ 
+ &mmc0 {
+@@ -190,6 +196,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
+ 		allwinner,pins = "PC3";
+@@ -204,6 +214,27 @@
+ 		allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
++		allwinner,pins = "PH5";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
++	};
++
++	usb0_vbus_pin_lime2: usb0_vbus_pin@0 {
++		allwinner,pins = "PC17";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
+ };
+ 
+ &reg_ahci_5v {
+@@ -212,6 +243,12 @@
+ 	status = "okay";
+ };
+ 
++&reg_usb0_vbus {
++	pinctrl-0 = <&usb0_vbus_pin_lime2>;
++	gpio = <&pio 2 17 GPIO_ACTIVE_HIGH>;
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -226,7 +263,17 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/dts/sun7i-a20-olinuxino-micro.dts
+@@ -125,6 +125,12 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins_a>;
+ 	status = "okay";
++
++	eeprom: eeprom@50 {
++		compatible = "atmel,24c16";
++		reg = <0x50>;
++		pagesize = <16>;
++	};
+ };
+ 
+ &i2c2 {
+--- a/arch/arm/dts/sun7i-a20-orangepi-mini.dts
++++ b/arch/arm/dts/sun7i-a20-orangepi-mini.dts
+@@ -95,6 +95,10 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -156,7 +160,18 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
+ 	mmc0_cd_pin_orangepi: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PH10";
+ 		allwinner,function = "gpio_in";
+@@ -225,6 +240,10 @@
+ 	regulator-name = "avcc";
+ };
+ 
++&reg_usb0_vbus {
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	pinctrl-0 = <&usb1_vbus_pin_bananapro>;
+ 	gpio = <&pio 7 26 GPIO_ACTIVE_HIGH>; /* PH26 */
+@@ -243,7 +262,21 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
++&usb_power_supply {
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_power-supply = <&usb_power_supply>;
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-orangepi.dts
++++ b/arch/arm/dts/sun7i-a20-orangepi.dts
+@@ -141,7 +141,18 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
+ 	mmc0_cd_pin_orangepi: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PH10";
+ 		allwinner,function = "gpio_in";
+@@ -203,6 +214,10 @@
+ 	regulator-name = "avcc";
+ };
+ 
++&reg_usb0_vbus {
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	pinctrl-0 = <&usb1_vbus_pin_bananapro>;
+ 	gpio = <&pio 7 26 GPIO_ACTIVE_HIGH>; /* PH26 */
+@@ -221,7 +236,21 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
++&usb_power_supply {
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_power-supply = <&usb_power_supply>;
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-pcduino3-nano.dts
++++ b/arch/arm/dts/sun7i-a20-pcduino3-nano.dts
+@@ -82,6 +82,14 @@
+ 	status = "okay";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -108,13 +116,9 @@
+ 	status = "okay";
+ 
+ 	axp209: pmic@34 {
+-		compatible = "x-powers,axp209";
+ 		reg = <0x34>;
+ 		interrupt-parent = <&nmi_intc>;
+ 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+-
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
+ 	};
+ };
+ 
+@@ -142,6 +146,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	ahci_pwr_pin_pcduino3_nano: ahci_pwr_pin@0 {
+ 		allwinner,pins = "PH2";
+@@ -157,8 +165,15 @@
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
+ 
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
+ 	usb1_vbus_pin_pcduino3_nano: usb1_vbus_pin@0 {
+-		allwinner,pins = "PH11";
++		allwinner,pins = "PD2";
+ 		allwinner,function = "gpio_out";
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+@@ -171,13 +186,37 @@
+ 	status = "okay";
+ };
+ 
+-&reg_usb1_vbus {
+-	pinctrl-0 = <&usb1_vbus_pin_pcduino3_nano>;
+-	gpio = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+-	status = "okay";
++#include "axp209.dtsi"
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-pll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
+ };
+ 
+-&reg_usb2_vbus {
++/* A single regulator (U24) powers both USB host ports. */
++&reg_usb1_vbus {
++	pinctrl-0 = <&usb1_vbus_pin_pcduino3_nano>;
++	gpio = <&pio 3 2 GPIO_ACTIVE_HIGH>; /* PD2 */
+ 	status = "okay";
+ };
+ 
+@@ -187,8 +226,16 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+-	usb2_vbus-supply = <&reg_usb2_vbus>;
++	usb2_vbus-supply = <&reg_usb1_vbus>;
+ 	status = "okay";
+ };
+--- a/arch/arm/dts/sun7i-a20-pcduino3.dts
++++ b/arch/arm/dts/sun7i-a20-pcduino3.dts
+@@ -111,6 +111,14 @@
+ 	allwinner,pins = "PH2";
+ };
+ 
++&codec {
++	status = "okay";
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++};
++
+ &ehci0 {
+ 	status = "okay";
+ };
+@@ -137,16 +145,14 @@
+ 	status = "okay";
+ 
+ 	axp209: pmic@34 {
+-		compatible = "x-powers,axp209";
+ 		reg = <0x34>;
+ 		interrupt-parent = <&nmi_intc>;
+ 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+-
+-		interrupt-controller;
+-		#interrupt-cells = <1>;
+ 	};
+ };
+ 
++#include "axp209.dtsi"
++
+ &ir0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&ir0_rx_pins_a>;
+@@ -171,6 +177,10 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
+ &pio {
+ 	led_pins_pcduino3: led_pins@0 {
+ 		allwinner,pins = "PH15", "PH16";
+@@ -185,6 +195,13 @@
+ 		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ 		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
+ };
+ 
+ &reg_ahci_5v {
+@@ -192,6 +209,31 @@
+ 	status = "okay";
+ };
+ 
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-pll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -206,7 +248,15 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-wexler-tab7200.dts
++++ b/arch/arm/dts/sun7i-a20-wexler-tab7200.dts
+@@ -48,6 +48,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pwm/pwm.h>
+ 
+ / {
+ 	model = "Wexler TAB7200";
+@@ -57,11 +58,28 @@
+ 		serial0 = &uart0;
+ 	};
+ 
++	backlight {
++		compatible = "pwm-backlight";
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <8>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&bl_enable_pin>;
++		enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
++	};
++
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
+ };
+ 
++&codec {
++	pinctrl-names = "default";
++	pinctrl-0 = <&codec_pa_pin>;
++	allwinner,pa-gpios = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
+@@ -86,6 +104,8 @@
+ 	};
+ };
+ 
++#include "axp209.dtsi"
++
+ &i2c1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins_a>;
+@@ -96,6 +116,18 @@
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c2_pins_a>;
+ 	status = "okay";
++
++	gt911: touchscreen@5d {
++		compatible = "goodix,gt911";
++		reg = <0x5d>;
++		interrupt-parent = <&pio>;
++		interrupts = <7 21 IRQ_TYPE_EDGE_FALLING>; /* EINT21 (PH21) */
++		pinctrl-names = "default";
++		pinctrl-0 = <&ts_reset_pin>;
++		irq-gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>; /* INT (PH21) */
++		reset-gpios = <&pio 1 13 GPIO_ACTIVE_HIGH>; /* RST (PB13) */
++		touchscreen-swapped-x-y;
++	};
+ };
+ 
+ &lradc {
+@@ -135,7 +167,45 @@
+ 	status = "okay";
+ };
+ 
+-#include "axp209.dtsi"
++&otg_sram {
++	status = "okay";
++};
++
++&pio {
++	bl_enable_pin: bl_enable_pin@0 {
++		allwinner,pins = "PH7";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	codec_pa_pin: codec_pa_pin@0 {
++		allwinner,pins = "PH15";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	ts_reset_pin: ts_reset_pin@0 {
++		allwinner,pins = "PB13";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++};
++
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm0_pins_a>;
++	status = "okay";
++};
+ 
+ &reg_dcdc2 {
+ 	regulator-always-on;
+@@ -162,6 +232,10 @@
+ 	regulator-name = "avcc";
+ };
+ 
++&reg_usb0_vbus {
++	status = "okay";
++};
++
+ &reg_usb1_vbus {
+ 	status = "okay";
+ };
+@@ -176,7 +250,21 @@
+ 	status = "okay";
+ };
+ 
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
++&usb_power_supply {
++	status = "okay";
++};
++
+ &usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_power-supply = <&usb_power_supply>;
++	usb0_vbus-supply = <&reg_usb0_vbus>;
+ 	usb1_vbus-supply = <&reg_usb1_vbus>;
+ 	usb2_vbus-supply = <&reg_usb2_vbus>;
+ 	status = "okay";
+--- a/arch/arm/dts/sun7i-a20-wits-pro-a20-dkt.dts
++++ b/arch/arm/dts/sun7i-a20-wits-pro-a20-dkt.dts
+@@ -1,13 +1,52 @@
+ /*
+- * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
++ * Copyright 2015 Jelle de Jong <jelledejong@powercraft.nl>
+  *
+- * Minimal dts file for the Wits Pro A20 DKT for u-boot only
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
+  *
+- * SPDX-License-Identifier:     GPL-2.0+ or X11
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
+  */
+ 
+ /dts-v1/;
+ #include "sun7i-a20.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/interrupt-controller/irq.h>
+ 
+ / {
+ 	model = "Wits Pro A20 DKT";
+@@ -20,6 +59,17 @@
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
++
++	mmc3_pwrseq: mmc3_pwrseq {
++		compatible = "mmc-pwrseq-simple";
++		pinctrl-names = "default";
++		pinctrl-0 = <&vmmc3_pin_ap6xxx_wl_regon>;
++		reset-gpios = <&pio 7 9 GPIO_ACTIVE_LOW>; /* PH9 WIFI_EN */
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
+ };
+ 
+ &ehci0 {
+@@ -42,6 +92,60 @@
+ 	};
+ };
+ 
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++
++	axp209: pmic@34 {
++		reg = <0x34>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++};
++
++#include "axp209.dtsi"
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
++	vmmc-supply = <&reg_vcc3v3>;
++	bus-width = <4>;
++	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
++	cd-inverted;
++	status = "okay";
++};
++
++&mmc3 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc3_pins_a>;
++	vmmc-supply = <&reg_vcc3v3>;
++	mmc-pwrseq = <&mmc3_pwrseq>;
++	bus-width = <4>;
++	non-removable;
++	status = "okay";
++
++	brcmf: bcrmf@1 {
++		reg = <1>;
++		compatible = "brcm,bcm4329-fmac";
++		interrupt-parent = <&pio>;
++		interrupts = <7 10 IRQ_TYPE_LEVEL_LOW>; /* PH10 / EINT10 */
++		interrupt-names = "host-wake";
++	};
++};
++
+ &ohci0 {
+ 	status = "okay";
+ };
+@@ -50,8 +154,85 @@
+ 	status = "okay";
+ };
+ 
++&otg_sram {
++	status = "okay";
++};
++
++&pio {
++	vmmc3_pin_ap6xxx_wl_regon: vmmc3_pin@0 {
++		allwinner,pins = "PH9";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1450000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
++&reg_usb0_vbus {
++	status = "okay";
++};
++
++&reg_usb1_vbus {
++	status = "okay";
++};
++
++&reg_usb2_vbus {
++	status = "okay";
++};
++
+ &uart0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&uart0_pins_a>;
+ 	status = "okay";
+ };
++
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
++&usb_power_supply {
++	status = "okay";
++};
++
++&usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_power-supply = <&usb_power_supply>;
++	usb0_vbus-supply = <&reg_usb0_vbus>;
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++	usb2_vbus-supply = <&reg_usb2_vbus>;
++	status = "okay";
++};
+--- a/arch/arm/dts/sun7i-a20.dtsi
++++ b/arch/arm/dts/sun7i-a20.dtsi
+@@ -47,6 +47,7 @@
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/thermal/thermal.h>
+ 
++#include <dt-bindings/clock/sun4i-a10-pll2.h>
+ #include <dt-bindings/dma/sun4i-a10.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+@@ -67,7 +68,7 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-hdmi";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+-				 <&ahb_gates 44>;
++				 <&ahb_gates 44>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -75,7 +76,8 @@
+ 			compatible = "allwinner,simple-framebuffer",
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0";
+-			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
++			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
++				 <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -84,7 +86,7 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-tve0";
+ 			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+-				 <&ahb_gates 44>;
++				 <&ahb_gates 44>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 	};
+@@ -107,7 +109,7 @@
+ 				720000	1200000
+ 				528000	1100000
+ 				312000	1000000
+-				144000	900000
++				144000	1000000
+ 				>;
+ 			#cooling-cells = <2>;
+ 			cooling-min-level = <0>;
+@@ -199,6 +201,15 @@
+ 			clock-output-names = "pll1";
+ 		};
+ 
++		pll2: clk@01c20008 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-pll2-clk";
++			reg = <0x01c20008 0x8>;
++			clocks = <&osc24M>;
++			clock-output-names = "pll2-1x", "pll2-2x",
++					     "pll2-4x", "pll2-8x";
++		};
++
+ 		pll4: clk@01c20018 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun7i-a20-pll4-clk";
+@@ -267,6 +278,19 @@
+ 			compatible = "allwinner,sun7i-a20-ahb-gates-clk";
+ 			reg = <0x01c20060 0x8>;
+ 			clocks = <&ahb>;
++			clock-indices = <0>, <1>,
++					<2>, <3>, <4>,
++					<5>, <6>, <7>, <8>,
++					<9>, <10>, <11>, <12>,
++					<13>, <14>, <16>,
++					<17>, <18>, <20>, <21>,
++					<22>, <23>, <25>,
++					<28>, <32>, <33>, <34>,
++					<35>, <36>, <37>, <40>,
++					<41>, <42>, <43>,
++					<44>, <45>, <46>,
++					<47>, <49>, <50>,
++					<52>;
+ 			clock-output-names = "ahb_usb0", "ahb_ehci0",
+ 				"ahb_ohci0", "ahb_ehci1", "ahb_ohci1",
+ 				"ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
+@@ -295,6 +319,10 @@
+ 			compatible = "allwinner,sun7i-a20-apb0-gates-clk";
+ 			reg = <0x01c20068 0x4>;
+ 			clocks = <&apb0>;
++			clock-indices = <0>, <1>,
++					<2>, <3>, <4>,
++					<5>, <6>, <7>,
++					<8>, <10>;
+ 			clock-output-names = "apb0_codec", "apb0_spdif",
+ 				"apb0_ac97", "apb0_iis0", "apb0_iis1",
+ 				"apb0_pio", "apb0_ir0", "apb0_ir1",
+@@ -314,6 +342,12 @@
+ 			compatible = "allwinner,sun7i-a20-apb1-gates-clk";
+ 			reg = <0x01c2006c 0x4>;
+ 			clocks = <&apb1>;
++			clock-indices = <0>, <1>,
++					<2>, <3>, <4>,
++					<5>, <6>, <7>,
++					<15>, <16>, <17>,
++					<18>, <19>, <20>,
++					<21>, <22>, <23>;
+ 			clock-output-names = "apb1_i2c0", "apb1_i2c1",
+ 				"apb1_i2c2", "apb1_i2c3", "apb1_can",
+ 				"apb1_scr", "apb1_ps20", "apb1_ps21",
+@@ -442,6 +476,14 @@
+ 			clock-output-names = "ir1";
+ 		};
+ 
++		keypad_clk: clk@01c200c4 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-mod0-clk";
++			reg = <0x01c200c4 0x4>;
++			clocks = <&osc24M>;
++			clock-output-names = "keypad";
++		};
++
+ 		usb_clk: clk@01c200cc {
+ 			#clock-cells = <1>;
+ 			#reset-cells = <1>;
+@@ -460,6 +502,48 @@
+ 			clock-output-names = "spi3";
+ 		};
+ 
++		dram_gates: clk@01c20100 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-dram-gates-clk";
++			reg = <0x01c20100 0x4>;
++			clocks = <&pll5 0>;
++			clock-indices = <0>,
++					<1>, <2>,
++					<3>,
++					<4>,
++					<5>, <6>,
++					<15>,
++					<24>, <25>,
++					<26>, <27>,
++					<28>, <29>;
++			clock-output-names = "dram_ve",
++					     "dram_csi0", "dram_csi1",
++					     "dram_ts",
++					     "dram_tvd",
++					     "dram_tve0", "dram_tve1",
++					     "dram_output",
++					     "dram_de_fe1", "dram_de_fe0",
++					     "dram_de_be0", "dram_de_be1",
++					     "dram_de_mp", "dram_ace";
++		};
++
++		ve_clk: clk@01c2013c {
++			#clock-cells = <0>;
++			#reset-cells = <0>;
++			compatible = "allwinner,sun4i-a10-ve-clk";
++			reg = <0x01c2013c 0x4>;
++			clocks = <&pll4>;
++			clock-output-names = "ve";
++		};
++
++		codec_clk: clk@01c20140 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-codec-clk";
++			reg = <0x01c20140 0x4>;
++			clocks = <&pll2 SUN4I_A10_PLL2_1X>;
++			clock-output-names = "codec";
++		};
++
+ 		mbus_clk: clk@01c2015c {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun5i-a13-mbus-clk";
+@@ -744,6 +828,14 @@
+ 			status = "disabled";
+ 		};
+ 
++		crypto: crypto-engine@01c15000 {
++			compatible = "allwinner,sun4i-a10-crypto";
++			reg = <0x01c15000 0x1000>;
++			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&ahb_gates 5>, <&ss_clk>;
++			clock-names = "ahb", "mod";
++		};
++
+ 		spi2: spi@01c17000 {
+ 			compatible = "allwinner,sun4i-a10-spi";
+ 			reg = <0x01c17000 0x1000>;
+@@ -1159,6 +1251,19 @@
+ 			status = "disabled";
+ 		};
+ 
++		codec: codec@01c22c00 {
++			#sound-dai-cells = <0>;
++			compatible = "allwinner,sun7i-a20-codec";
++			reg = <0x01c22c00 0x40>;
++			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&apb0_gates 0>, <&codec_clk>;
++			clock-names = "apb", "codec";
++			dmas = <&dma SUN4I_DMA_NORMAL 19>,
++			       <&dma SUN4I_DMA_NORMAL 19>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
+ 		sid: eeprom@01c23800 {
+ 			compatible = "allwinner,sun7i-a20-sid";
+ 			reg = <0x01c23800 0x200>;
+--- a/arch/arm/dts/sun8i-a23-a33.dtsi
++++ b/arch/arm/dts/sun8i-a23-a33.dtsi
+@@ -56,7 +56,7 @@
+ 		#size-cells = <1>;
+ 		ranges;
+ 
+-		framebuffer@0 {
++		simplefb_lcd: framebuffer@0 {
+ 			compatible = "allwinner,simple-framebuffer",
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0";
+@@ -175,27 +175,13 @@
+ 			clock-output-names = "apb1";
+ 		};
+ 
+-		ahb1_gates: clk@01c20060 {
+-			#clock-cells = <1>;
+-			compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
+-			reg = <0x01c20060 0x8>;
+-			clocks = <&ahb1>;
+-			clock-output-names = "ahb1_mipidsi", "ahb1_dma",
+-					"ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
+-					"ahb1_nand", "ahb1_sdram",
+-					"ahb1_hstimer", "ahb1_spi0",
+-					"ahb1_spi1", "ahb1_otg", "ahb1_ehci",
+-					"ahb1_ohci", "ahb1_ve", "ahb1_lcd",
+-					"ahb1_csi", "ahb1_be",	"ahb1_fe",
+-					"ahb1_gpu", "ahb1_spinlock",
+-					"ahb1_drc";
+-		};
+-
+ 		apb1_gates: clk@01c20068 {
+ 			#clock-cells = <1>;
+ 			compatible = "allwinner,sun8i-a23-apb1-gates-clk";
+ 			reg = <0x01c20068 0x4>;
+ 			clocks = <&apb1>;
++			clock-indices = <0>, <5>,
++					<12>, <13>;
+ 			clock-output-names = "apb1_codec", "apb1_pio",
+ 					"apb1_daudio0",	"apb1_daudio1";
+ 		};
+@@ -213,6 +199,10 @@
+ 			compatible = "allwinner,sun8i-a23-apb2-gates-clk";
+ 			reg = <0x01c2006c 0x4>;
+ 			clocks = <&apb2>;
++			clock-indices = <0>, <1>,
++					<2>, <16>,
++					<17>, <18>,
++					<19>, <20>;
+ 			clock-output-names = "apb2_i2c0", "apb2_i2c1",
+ 					"apb2_i2c2", "apb2_uart0",
+ 					"apb2_uart1", "apb2_uart2",
+@@ -391,12 +381,19 @@
+ 				allwinner,pins = "PC5", "PC6", "PC8",
+ 						 "PC9", "PC10", "PC11",
+ 						 "PC12", "PC13", "PC14",
+-						 "PC15";
++						 "PC15", "PC16";
+ 				allwinner,function = "mmc2";
+ 				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 			};
+ 
++			pwm0_pins: pwm0 {
++				allwinner,pins = "PH0";
++				allwinner,function = "pwm0";
++				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++
+ 			i2c0_pins_a: i2c0@0 {
+ 				allwinner,pins = "PH2", "PH3";
+ 				allwinner,function = "i2c0";
+@@ -451,6 +448,14 @@
+ 			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ 		};
+ 
++		pwm: pwm@01c21400 {
++			compatible = "allwinner,sun7i-a20-pwm";
++			reg = <0x01c21400 0xc>;
++			clocks = <&osc24M>;
++			#pwm-cells = <3>;
++			status = "disabled";
++		};
++
+ 		lradc: lradc@01c22800 {
+ 			compatible = "allwinner,sun4i-a10-lradc-keys";
+ 			reg = <0x01c22800 0x100>;
+@@ -574,6 +579,14 @@
+ 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ 		};
+ 
++		nmi_intc: interrupt-controller@01f00c0c {
++			compatible = "allwinner,sun6i-a31-sc-nmi";
++			interrupt-controller;
++			#interrupt-cells = <2>;
++			reg = <0x01f00c0c 0x38>;
++			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
+ 		prcm@01f01400 {
+ 			compatible = "allwinner,sun8i-a23-prcm";
+ 			reg = <0x01f01400 0x200>;
+@@ -642,10 +655,18 @@
+ 			resets = <&apb0_rst 0>;
+ 			gpio-controller;
+ 			interrupt-controller;
++			#interrupt-cells = <3>;
+ 			#address-cells = <1>;
+ 			#size-cells = <0>;
+ 			#gpio-cells = <3>;
+ 
++			r_rsb_pins: r_rsb {
++				allwinner,pins = "PL0", "PL1";
++				allwinner,function = "s_rsb";
++				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++			};
++
+ 			r_uart_pins_a: r_uart@0 {
+ 				allwinner,pins = "PL2", "PL3";
+ 				allwinner,function = "s_uart";
+@@ -653,5 +674,19 @@
+ 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 			};
+ 		};
++
++		r_rsb: rsb@01f03400 {
++			compatible = "allwinner,sun8i-a23-rsb";
++			reg = <0x01f03400 0x400>;
++			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&apb0_gates 3>;
++			clock-frequency = <3000000>;
++			resets = <&apb0_rst 3>;
++			pinctrl-names = "default";
++			pinctrl-0 = <&r_rsb_pins>;
++			status = "disabled";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
+ 	};
+ };
+--- a/arch/arm/dts/sun8i-a23-gt90h-v4.dts
++++ b/arch/arm/dts/sun8i-a23-gt90h-v4.dts
+@@ -47,15 +47,26 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
++#include <dt-bindings/pwm/pwm.h>
+ 
+ / {
+-	model = "Allwinner GT90H Quad Core Tablet (v4)";
+-	compatible = "allwinner,gt90h-v4", "allwinner,sun8i-a33";
++	model = "Allwinner GT90H Dual Core Tablet (v4)";
++	compatible = "allwinner,gt90h-v4", "allwinner,sun8i-a23";
+ 
+ 	aliases {
+ 		serial0 = &r_uart;
+ 	};
+ 
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pinctrl-names = "default";
++		pinctrl-0 = <&bl_en_pin_gt90h>;
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <8>;
++		enable-gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
++	};
++
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
+@@ -106,8 +117,7 @@
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_gt90h>;
+-	/* FIXME this really is aldo1, correct once we've pmic support */
+-	vmmc-supply = <&reg_vcc3v0>;
++	vmmc-supply = <&reg_aldo1>;
+ 	bus-width = <4>;
+ 	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ 	cd-inverted;
+@@ -115,6 +125,13 @@
+ };
+ 
+ &pio {
++	bl_en_pin_gt90h: bl_en_pin@0 {
++		allwinner,pins = "PH6";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	mmc0_cd_pin_gt90h: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PB4";
+ 		allwinner,function = "gpio_in";
+@@ -123,12 +140,106 @@
+ 	};
+ };
+ 
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm0_pins>;
++	status = "okay";
++};
++
++&r_rsb {
++	status = "okay";
++
++	axp22x: pmic@3a3 {
++		compatible = "x-powers,axp223";
++		reg = <0x3a3>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++		eldoin-supply = <&reg_dcdc1>;
++	};
++};
++
+ &r_uart {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&r_uart_pins_a>;
+ 	status = "okay";
+ };
+ 
++#include "axp22x.dtsi"
++
++&reg_aldo1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-io";
++};
++
++&reg_aldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <2350000>;
++	regulator-max-microvolt = <2650000>;
++	regulator-name = "vdd-dll";
++};
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-pll-avcc";
++};
++
++&reg_dc1sw {
++	regulator-name = "vcc-lcd";
++};
++
++&reg_dc5ldo {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpus";
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-sys";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
++&reg_dldo1 {
++	regulator-min-microvolt = <3300000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-wifi";
++};
++
++&reg_rtc_ldo {
++	regulator-name = "vcc-rtc";
++};
++
++&simplefb_lcd {
++	vcc-lcd-supply = <&reg_dc1sw>;
++};
++
+ /*
+  * FIXME for now we only support host mode and rely on u-boot to have
+  * turned on Vbus which is controlled by the axp223 pmic on the board.
+@@ -141,5 +252,6 @@
+ };
+ 
+ &usbphy {
++	usb1_vbus-supply = <&reg_dldo1>;
+ 	status = "okay";
+ };
+--- a/arch/arm/dts/sun8i-a23.dtsi
++++ b/arch/arm/dts/sun8i-a23.dtsi
+@@ -50,6 +50,31 @@
+ 	};
+ 
+ 	clocks {
++		ahb1_gates: clk@01c20060 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
++			reg = <0x01c20060 0x8>;
++			clocks = <&ahb1>;
++			clock-indices = <1>, <6>,
++					<8>, <9>, <10>,
++					<13>, <14>,
++					<19>, <20>,
++					<21>, <24>, <26>,
++					<29>, <32>, <36>,
++					<40>, <44>, <46>,
++					<52>, <53>,
++					<54>, <57>;
++			clock-output-names = "ahb1_mipidsi", "ahb1_dma",
++					"ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
++					"ahb1_nand", "ahb1_sdram",
++					"ahb1_hstimer", "ahb1_spi0",
++					"ahb1_spi1", "ahb1_otg", "ahb1_ehci",
++					"ahb1_ohci", "ahb1_ve", "ahb1_lcd",
++					"ahb1_csi", "ahb1_be",	"ahb1_fe",
++					"ahb1_gpu", "ahb1_msgbox",
++					"ahb1_spinlock", "ahb1_drc";
++		};
++
+ 		mbus_clk: clk@01c2015c {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun8i-a23-mbus-clk";
+--- a/arch/arm/dts/sun8i-a33-sinlinx-sina33.dts
++++ b/arch/arm/dts/sun8i-a33-sinlinx-sina33.dts
+@@ -68,7 +68,7 @@
+ };
+ 
+ &lradc {
+-	vref-supply = <&reg_vcc3v0>;
++	vref-supply = <&reg_dcdc1>;
+ 	status = "okay";
+ 
+ 	button@200 {
+@@ -96,7 +96,7 @@
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_sina33>;
+-	vmmc-supply = <&reg_vcc3v0>;
++	vmmc-supply = <&reg_dcdc1>;
+ 	bus-width = <4>;
+ 	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ 	cd-inverted;
+@@ -106,13 +106,16 @@
+ &mmc2 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc2_8bit_pins>;
+-	vmmc-supply = <&reg_vcc3v0>;
++	vmmc-supply = <&reg_dcdc1>;
+ 	bus-width = <8>;
+ 	non-removable;
++	cap-mmc-hw-reset;
+ 	status = "okay";
+ };
+ 
+ &mmc2_8bit_pins {
++	/* Increase drive strength for DDR modes */
++	allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+ 	/* eMMC is missing pull-ups */
+ 	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+@@ -130,6 +133,80 @@
+ 	};
+ };
+ 
++&r_rsb {
++	status = "okay";
++
++	axp22x: pmic@3a3 {
++		compatible = "x-powers,axp223";
++		reg = <0x3a3>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++		eldoin-supply = <&reg_dcdc1>;
++	};
++};
++
++#include "axp22x.dtsi"
++
++&reg_aldo1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-io";
++};
++
++&reg_aldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <2350000>;
++	regulator-max-microvolt = <2650000>;
++	regulator-name = "vdd-dll";
++};
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-pll-avcc";
++};
++
++&reg_dc5ldo {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpus";
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-sys";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
++&reg_rtc_ldo {
++	regulator-name = "vcc-rtc";
++};
++
+ &uart0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&uart0_pins_b>;
+--- a/arch/arm/dts/sun8i-a33.dtsi
++++ b/arch/arm/dts/sun8i-a33.dtsi
+@@ -72,6 +72,41 @@
+ 			clock-output-names = "pll11";
+ 		};
+ 
++		ahb1_gates: clk@01c20060 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun8i-a33-ahb1-gates-clk";
++			reg = <0x01c20060 0x8>;
++			clocks = <&ahb1>;
++			clock-indices = <1>, <5>,
++				        <6>, <8>, <9>,
++				        <10>, <13>, <14>,
++					<19>, <20>,
++					<21>, <24>, <26>,
++					<29>, <32>, <36>,
++					<40>, <44>, <46>,
++					<52>, <53>,
++					<54>, <57>,
++					<58>;
++			clock-output-names = "ahb1_mipidsi", "ahb1_ss",
++					"ahb1_dma","ahb1_mmc0", "ahb1_mmc1",
++					"ahb1_mmc2", "ahb1_nand", "ahb1_sdram",
++					"ahb1_hstimer", "ahb1_spi0",
++					"ahb1_spi1", "ahb1_otg", "ahb1_ehci",
++					"ahb1_ohci", "ahb1_ve", "ahb1_lcd",
++					"ahb1_csi", "ahb1_be",	"ahb1_fe",
++					"ahb1_gpu", "ahb1_msgbox",
++					"ahb1_spinlock", "ahb1_drc",
++					"ahb1_sat";
++		};
++
++		ss_clk: clk@01c2009c {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-mod0-clk";
++			reg = <0x01c2009c 0x4>;
++			clocks = <&osc24M>, <&pll6 0>;
++			clock-output-names = "ss";
++		};
++
+ 		mbus_clk: clk@01c2015c {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun8i-a23-mbus-clk";
+@@ -82,6 +117,16 @@
+ 	};
+ 
+ 	soc@01c00000 {
++		crypto: crypto-engine@01c15000 {
++			compatible = "allwinner,sun4i-a10-crypto";
++			reg = <0x01c15000 0x1000>;
++			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&ahb1_gates 5>, <&ss_clk>;
++			clock-names = "ahb", "mod";
++			resets = <&ahb1_rst 5>;
++			reset-names = "ahb";
++		};
++
+ 		usb_otg: usb@01c19000 {
+ 			compatible = "allwinner,sun8i-a33-musb";
+ 			reg = <0x01c19000 0x0400>;
+--- /dev/null
++++ b/arch/arm/dts/sun8i-a83t-cubietruck-plus.dts
+@@ -0,0 +1,65 @@
++/*
++ * Copyright 2015 Chen-Yu Tsai
++ *
++ * Chen-Yu Tsai <wens@csie.org>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun8i-a83t.dtsi"
++
++/ {
++	model = "Cubietech Cubietruck Plus";
++	compatible = "cubietech,cubietruck-plus", "allwinner,sun8i-a83t";
++
++	aliases {
++		serial0 = &uart0;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_b>;
++	status = "okay";
++};
+--- a/arch/arm/dts/sun8i-a83t.dtsi
++++ b/arch/arm/dts/sun8i-a83t.dtsi
+@@ -52,12 +52,6 @@
+ / {
+ 	interrupt-parent = <&gic>;
+ 
+-	chosen {
+-		#address-cells = <1>;
+-		#size-cells = <1>;
+-		ranges;
+-	};
+-
+ 	cpus {
+ 		#address-cells = <1>;
+ 		#size-cells = <0>;
+@@ -85,6 +79,7 @@
+ 			device_type = "cpu";
+ 			reg = <3>;
+ 		};
++
+ 		cpu@100 {
+ 			compatible = "arm,cortex-a7";
+ 			device_type = "cpu";
+@@ -96,6 +91,7 @@
+ 			device_type = "cpu";
+ 			reg = <0x101>;
+ 		};
++
+ 		cpu@102 {
+ 			compatible = "arm,cortex-a7";
+ 			device_type = "cpu";
+@@ -109,18 +105,12 @@
+ 		};
+ 	};
+ 
+-	memory {
+-		reg = <0x40000000 0x80000000>;
+-	};
+-
+ 	timer {
+ 		compatible = "arm,armv7-timer";
+-		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+-			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+-			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+-			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+-		clock-frequency = <24000000>;
+-		arm,cpu-registers-not-fw-configured;
++		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+ 	};
+ 
+ 	clocks {
+@@ -128,6 +118,7 @@
+ 		#size-cells = <1>;
+ 		ranges;
+ 
++		/* TODO: PRCM block has a mux for this. */
+ 		osc24M: osc24M_clk {
+ 			#clock-cells = <0>;
+ 			compatible = "fixed-clock";
+@@ -135,36 +126,39 @@
+ 			clock-output-names = "osc24M";
+ 		};
+ 
+-		osc32k: osc32k_clk {
++		/*
++		 * This is called "internal OSC" in some places.
++		 * It is an internal RC-based oscillator.
++		 * TODO: Its controls are in the PRCM block.
++		 */
++		osc16M: osc16M_clk {
+ 			#clock-cells = <0>;
+ 			compatible = "fixed-clock";
+-			clock-frequency = <32768>;
+-			clock-output-names = "osc32k";
++			clock-frequency = <16000000>;
++			clock-output-names = "osc16M";
++		};
++
++		osc16Md512: osc16Md512_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-factor-clock";
++			clock-div = <512>;
++			clock-mult = <1>;
++			clocks = <&osc16M>;
++			clock-output-names = "osc16M-d512";
+ 		};
+ 	};
+ 
+-	soc@01c00000 {
++	soc {
+ 		compatible = "simple-bus";
+ 		#address-cells = <1>;
+ 		#size-cells = <1>;
+ 		ranges;
+ 
+-		gic: interrupt-controller@01c81000 {
+-			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+-			reg = <0x01c81000 0x1000>,
+-			      <0x01c82000 0x1000>,
+-			      <0x01c84000 0x2000>,
+-			      <0x01c86000 0x2000>;
+-			interrupt-controller;
+-			#interrupt-cells = <3>;
+-			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+-		};
+-
+ 		pio: pinctrl@01c20800 {
+ 			compatible = "allwinner,sun8i-a83t-pinctrl";
+ 			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+-			<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+-			<GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ 			reg = <0x01c20800 0x400>;
+ 			clocks = <&osc24M>;
+ 			gpio-controller;
+@@ -172,27 +166,6 @@
+ 			#interrupt-cells = <3>;
+ 			#gpio-cells = <3>;
+ 
+-			i2c0_pins_a: i2c0@0 {
+-				allwinner,pins = "PH0", "PH1";
+-				allwinner,function = "i2c0";
+-				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+-				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+-			};
+-
+-			i2c1_pins_a: i2c1@0 {
+-				allwinner,pins = "PH2", "PH3";
+-				allwinner,function = "i2c1";
+-				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+-				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+-			};
+-
+-			i2c2_pins_a: i2c2@0 {
+-				allwinner,pins = "PH4", "PH5";
+-				allwinner,function = "i2c2";
+-				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+-				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+-			};
+-
+ 			mmc0_pins_a: mmc0@0 {
+ 				allwinner,pins = "PF0", "PF1", "PF2",
+ 						 "PF3", "PF4", "PF5";
+@@ -201,24 +174,6 @@
+ 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ 			};
+ 
+-			mmc1_pins_a: mmc1@0 {
+-				allwinner,pins = "PG0", "PG1", "PG2",
+-						 "PG3", "PG4", "PG5";
+-				allwinner,function = "mmc1";
+-				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+-				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+-			};
+-
+-			mmc2_8bit_pins: mmc2_8bit {
+-				allwinner,pins = "PC5", "PC6", "PC8",
+-						 "PC9", "PC10", "PC11",
+-						 "PC12", "PC13", "PC14",
+-						 "PC15";
+-				allwinner,function = "mmc2";
+-				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+-				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+-			};
+-
+ 			uart0_pins_a: uart0@0 {
+ 				allwinner,pins = "PF2", "PF4";
+ 				allwinner,function = "uart0";
+@@ -234,6 +189,21 @@
+ 			};
+ 		};
+ 
++		timer@01c20c00 {
++			compatible = "allwinner,sun4i-a10-timer";
++			reg = <0x01c20c00 0xa0>;
++			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&osc24M>;
++		};
++
++		watchdog@01c20ca0 {
++			compatible = "allwinner,sun6i-a31-wdt";
++			reg = <0x01c20ca0 0x20>;
++			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&osc24M>;
++		};
++
+ 		uart0: serial@01c28000 {
+ 			compatible = "snps,dw-apb-uart";
+ 			reg = <0x01c28000 0x400>;
+@@ -243,5 +213,16 @@
+ 			clocks = <&osc24M>;
+ 			status = "disabled";
+ 		};
++
++		gic: interrupt-controller@01c81000 {
++			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
++			reg = <0x01c81000 0x1000>,
++			      <0x01c82000 0x1000>,
++			      <0x01c84000 0x2000>,
++			      <0x01c86000 0x2000>;
++			interrupt-controller;
++			#interrupt-cells = <3>;
++			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
++		};
+ 	};
+ };
+--- a/arch/arm/dts/sun8i-h3-orangepi-pc.dts
++++ b/arch/arm/dts/sun8i-h3-orangepi-pc.dts
+@@ -45,6 +45,7 @@
+ #include "sunxi-common-regulators.dtsi"
+ 
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+ / {
+@@ -58,6 +59,43 @@
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&leds_opc>;
++
++		status_led {
++			label = "status:red:user";
++			gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>;
++		};
++	};
++
++	r_leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&leds_r_opc>;
++
++		tx {
++			label = "pwr:green:user";
++			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
++			default-state = "on";
++		};
++	};
++
++	r_gpio_keys {
++		compatible = "gpio-keys";
++		input-name = "sw4";
++
++		pinctrl-names = "default";
++		pinctrl-0 = <&sw_r_opc>;
++
++		sw4@0 {
++			label = "sw4";
++			linux,code = <BTN_0>;
++			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
++		};
++	};
+ };
+ 
+ &ehci1 {
+@@ -72,6 +110,12 @@
+ 	status = "okay";
+ };
+ 
++&ir {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ir_pins_a>;
++	status = "okay";
++};
++
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+@@ -94,6 +138,31 @@
+ 	status = "okay";
+ };
+ 
++&pio {
++	leds_opc: led_pins@0 {
++		allwinner,pins = "PA15";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&r_pio {
++	leds_r_opc: led_pins@0 {
++		allwinner,pins = "PL10";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	sw_r_opc: key_pins@0 {
++		allwinner,pins = "PL03";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
+ &uart0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&uart0_pins_a>;
+--- a/arch/arm/dts/sun8i-h3-orangepi-plus.dts
++++ b/arch/arm/dts/sun8i-h3-orangepi-plus.dts
+@@ -45,6 +45,7 @@
+ #include "sunxi-common-regulators.dtsi"
+ 
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
+ #include <dt-bindings/pinctrl/sun4i-a10.h>
+ 
+ / {
+@@ -70,6 +71,68 @@
+ 		enable-active-high;
+ 		gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
+ 	};
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&leds_opc>;
++
++		status_led {
++			label = "status:red:user";
++			gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>;
++		};
++	};
++
++	r_leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&leds_r_opc>;
++
++		tx {
++			label = "pwr:green:user";
++			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
++			default-state = "on";
++		};
++	};
++
++	r_gpio_keys {
++		compatible = "gpio-keys";
++		input-name = "sw4";
++
++		pinctrl-names = "default";
++		pinctrl-0 = <&sw_r_opc>;
++
++		sw4@0 {
++			label = "sw4";
++			linux,code = <BTN_0>;
++			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
++		};
++	};
++};
++
++&pio {
++	leds_opc: led_pins@0 {
++		allwinner,pins = "PA15";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&r_pio {
++	leds_r_opc: led_pins@0 {
++		allwinner,pins = "PL10";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	sw_r_opc: key_pins@0 {
++		allwinner,pins = "PL03";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
+ };
+ 
+ &ehci1 {
+--- a/arch/arm/dts/sun8i-h3.dtsi
++++ b/arch/arm/dts/sun8i-h3.dtsi
+@@ -83,12 +83,6 @@
+ 			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ 			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ 			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+-		clock-frequency = <24000000>;
+-		arm,cpu-registers-not-fw-configured;
+-	};
+-
+-	memory {
+-		reg = <0x40000000 0x80000000>;
+ 	};
+ 
+ 	clocks {
+@@ -131,15 +125,24 @@
+ 			compatible = "allwinner,sun6i-a31-pll6-clk";
+ 			reg = <0x01c20028 0x4>;
+ 			clocks = <&osc24M>;
+-			clock-output-names = "pll6", "pll6x2", "pll6d2";
++			clock-output-names = "pll6", "pll6x2";
+ 		};
+ 
+-		pll8: clk@01c20044 {
+-			#clock-cells = <1>;
+-			compatible = "allwinner,sun6i-a31-pll6-clk";
+-			reg = <0x01c20044 0x4>;
+-			clocks = <&osc24M>;
+-			clock-output-names = "pll8", "pll8x2";
++		pll6d2: pll6d2_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-factor-clock";
++			clock-div = <2>;
++			clock-mult = <1>;
++			clocks = <&pll6 0>;
++			clock-output-names = "pll6d2";
++		};
++
++		/* dummy clock until pll6 can be reused */
++		pll8: pll8_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-clock";
++			clock-frequency = <1>;
++			clock-output-names = "pll8";
+ 		};
+ 
+ 		cpu: cpu_clk@01c20050 {
+@@ -170,7 +173,7 @@
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun8i-h3-ahb2-clk";
+ 			reg = <0x01c2005c 0x4>;
+-			clocks = <&ahb1>, <&pll6 2>;
++			clocks = <&ahb1>, <&pll6d2>;
+ 			clock-output-names = "ahb2";
+ 		};
+ 
+@@ -213,34 +216,34 @@
+ 					<76>, <77>, <78>,
+ 					<96>, <97>, <98>,
+ 					<112>, <113>,
+-					<114>, <115>, <116>,
+-					<128>, <135>;
+-			clock-output-names = "ahb1_ce", "ahb1_dma", "ahb1_mmc0",
+-					"ahb1_mmc1", "ahb1_mmc2", "ahb1_nand",
+-					"ahb1_sdram", "ahb2_gmac", "ahb1_ts",
+-					"ahb1_hstimer", "ahb1_spi0",
+-					"ahb1_spi1", "ahb1_otg",
+-					"ahb1_otg_ehci0", "ahb1_ehic1",
+-					"ahb1_ehic2", "ahb1_ehic3",
+-					"ahb1_otg_ohci0", "ahb2_ohic1",
+-					"ahb2_ohic2", "ahb2_ohic3", "ahb1_ve",
+-					"ahb1_lcd0", "ahb1_lcd1", "ahb1_deint",
+-					"ahb1_csi", "ahb1_tve", "ahb1_hdmi",
+-					"ahb1_de", "ahb1_gpu", "ahb1_msgbox",
+-					"ahb1_spinlock", "apb1_codec",
+-					"apb1_spdif", "apb1_pio", "apb1_ths",
+-					"apb1_i2s0", "apb1_i2s1", "apb1_i2s2",
+-					"apb2_i2c0", "apb2_i2c1", "apb2_i2c2",
+-					"apb2_uart0", "apb2_uart1",
+-					"apb2_uart2", "apb2_uart3", "apb2_scr",
+-					"ahb1_ephy", "ahb1_dbg";
++					<114>, <115>,
++					<116>, <128>, <135>;
++			clock-output-names = "bus_ce", "bus_dma", "bus_mmc0",
++					     "bus_mmc1", "bus_mmc2", "bus_nand",
++					     "bus_sdram", "bus_gmac", "bus_ts",
++					     "bus_hstimer", "bus_spi0",
++					     "bus_spi1", "bus_otg",
++					     "bus_otg_ehci0", "bus_ehci1",
++					     "bus_ehci2", "bus_ehci3",
++					     "bus_otg_ohci0", "bus_ohci1",
++					     "bus_ohci2", "bus_ohci3", "bus_ve",
++					     "bus_lcd0", "bus_lcd1", "bus_deint",
++					     "bus_csi", "bus_tve", "bus_hdmi",
++					     "bus_de", "bus_gpu", "bus_msgbox",
++					     "bus_spinlock", "bus_codec",
++					     "bus_spdif", "bus_pio", "bus_ths",
++					     "bus_i2s0", "bus_i2s1", "bus_i2s2",
++					     "bus_i2c0", "bus_i2c1", "bus_i2c2",
++					     "bus_uart0", "bus_uart1",
++					     "bus_uart2", "bus_uart3",
++					     "bus_scr", "bus_ephy", "bus_dbg";
+ 		};
+ 
+ 		mmc0_clk: clk@01c20088 {
+ 			#clock-cells = <1>;
+ 			compatible = "allwinner,sun4i-a10-mmc-clk";
+ 			reg = <0x01c20088 0x4>;
+-			clocks = <&osc24M>, <&pll6 0>, <&pll8 0>;
++			clocks = <&osc24M>, <&pll6 0>, <&pll8>;
+ 			clock-output-names = "mmc0",
+ 					     "mmc0_output",
+ 					     "mmc0_sample";
+@@ -250,7 +253,7 @@
+ 			#clock-cells = <1>;
+ 			compatible = "allwinner,sun4i-a10-mmc-clk";
+ 			reg = <0x01c2008c 0x4>;
+-			clocks = <&osc24M>, <&pll6 0>, <&pll8 0>;
++			clocks = <&osc24M>, <&pll6 0>, <&pll8>;
+ 			clock-output-names = "mmc1",
+ 					     "mmc1_output",
+ 					     "mmc1_sample";
+@@ -260,7 +263,7 @@
+ 			#clock-cells = <1>;
+ 			compatible = "allwinner,sun4i-a10-mmc-clk";
+ 			reg = <0x01c20090 0x4>;
+-			clocks = <&osc24M>, <&pll6 0>, <&pll8 0>;
++			clocks = <&osc24M>, <&pll6 0>, <&pll8>;
+ 			clock-output-names = "mmc2",
+ 					     "mmc2_output",
+ 					     "mmc2_sample";
+@@ -285,6 +288,33 @@
+ 			clocks = <&osc24M>, <&pll6 1>, <&pll5>;
+ 			clock-output-names = "mbus";
+ 		};
++
++		apb0: apb0_clk {
++			compatible = "fixed-factor-clock";
++			#clock-cells = <0>;
++			clock-div = <1>;
++			clock-mult = <1>;
++			clocks = <&osc24M>;
++			clock-output-names = "apb0";
++		};
++
++		apb0_gates: clk@01f01428 {
++			compatible = "allwinner,sun8i-h3-apb0-gates-clk",
++				     "allwinner,sun4i-a10-gates-clk";
++			reg = <0x01f01428 0x4>;
++			#clock-cells = <1>;
++			clocks = <&apb0>;
++			clock-indices = <0>, <1>;
++			clock-output-names = "apb0_pio", "apb0_ir";
++		};
++
++		ir_clk: ir_clk@01f01454 {
++			compatible = "allwinner,sun4i-a10-mod0-clk";
++			reg = <0x01f01454 0x4>;
++			#clock-cells = <0>;
++			clocks = <&osc32k>, <&osc24M>;
++			clock-output-names = "ir";
++		};
+ 	};
+ 
+ 	soc {
+@@ -298,7 +328,7 @@
+ 			reg = <0x01c02000 0x1000>;
+ 			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 6>;
+-			resets = <&bus_rst 6>;
++			resets = <&ahb_rst 6>;
+ 			#dma-cells = <1>;
+ 		};
+ 
+@@ -313,7 +343,7 @@
+ 				      "mmc",
+ 				      "output",
+ 				      "sample";
+-			resets = <&bus_rst 8>;
++			resets = <&ahb_rst 8>;
+ 			reset-names = "ahb";
+ 			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ 			status = "disabled";
+@@ -332,7 +362,7 @@
+ 				      "mmc",
+ 				      "output",
+ 				      "sample";
+-			resets = <&bus_rst 9>;
++			resets = <&ahb_rst 9>;
+ 			reset-names = "ahb";
+ 			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+ 			status = "disabled";
+@@ -351,7 +381,7 @@
+ 				      "mmc",
+ 				      "output",
+ 				      "sample";
+-			resets = <&bus_rst 10>;
++			resets = <&ahb_rst 10>;
+ 			reset-names = "ahb";
+ 			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ 			status = "disabled";
+@@ -396,7 +426,7 @@
+ 			reg = <0x01c1b000 0x100>;
+ 			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 25>, <&bus_gates 29>;
+-			resets = <&bus_rst 25>, <&bus_rst 29>;
++			resets = <&ahb_rst 25>, <&ahb_rst 29>;
+ 			phys = <&usbphy 1>;
+ 			phy-names = "usb";
+ 			status = "disabled";
+@@ -408,7 +438,7 @@
+ 			interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 29>, <&bus_gates 25>,
+ 				 <&usb_clk 17>;
+-			resets = <&bus_rst 29>, <&bus_rst 25>;
++			resets = <&ahb_rst 29>, <&ahb_rst 25>;
+ 			phys = <&usbphy 1>;
+ 			phy-names = "usb";
+ 			status = "disabled";
+@@ -419,7 +449,7 @@
+ 			reg = <0x01c1c000 0x100>;
+ 			interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 26>, <&bus_gates 30>;
+-			resets = <&bus_rst 26>, <&bus_rst 30>;
++			resets = <&ahb_rst 26>, <&ahb_rst 30>;
+ 			phys = <&usbphy 2>;
+ 			phy-names = "usb";
+ 			status = "disabled";
+@@ -431,7 +461,7 @@
+ 			interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 30>, <&bus_gates 26>,
+ 				 <&usb_clk 18>;
+-			resets = <&bus_rst 30>, <&bus_rst 26>;
++			resets = <&ahb_rst 30>, <&ahb_rst 26>;
+ 			phys = <&usbphy 2>;
+ 			phy-names = "usb";
+ 			status = "disabled";
+@@ -442,7 +472,7 @@
+ 			reg = <0x01c1d000 0x100>;
+ 			interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 27>, <&bus_gates 31>;
+-			resets = <&bus_rst 27>, <&bus_rst 31>;
++			resets = <&ahb_rst 27>, <&ahb_rst 31>;
+ 			phys = <&usbphy 3>;
+ 			phy-names = "usb";
+ 			status = "disabled";
+@@ -454,7 +484,7 @@
+ 			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ 			clocks = <&bus_gates 31>, <&bus_gates 27>,
+ 				 <&usb_clk 19>;
+-			resets = <&bus_rst 31>, <&bus_rst 27>;
++			resets = <&ahb_rst 31>, <&ahb_rst 27>;
+ 			phys = <&usbphy 3>;
+ 			phy-names = "usb";
+ 			status = "disabled";
+@@ -469,7 +499,7 @@
+ 			gpio-controller;
+ 			#gpio-cells = <3>;
+ 			interrupt-controller;
+-			#interrupt-cells = <2>;
++			#interrupt-cells = <3>;
+ 
+ 			uart0_pins_a: uart0@0 {
+ 				allwinner,pins = "PA4", "PA5";
+@@ -502,10 +532,22 @@
+ 			};
+ 		};
+ 
+-		bus_rst: reset@01c202c0 {
++		ahb_rst: reset@01c202c0 {
+ 			#reset-cells = <1>;
+-			compatible = "allwinner,sun8i-h3-bus-reset";
+-			reg = <0x01c202c0 0x1c>;
++			compatible = "allwinner,sun6i-a31-ahb1-reset";
++			reg = <0x01c202c0 0xc>;
++		};
++
++		apb1_rst: reset@01c202d0 {
++			#reset-cells = <1>;
++			compatible = "allwinner,sun6i-a31-clock-reset";
++			reg = <0x01c202d0 0x4>;
++		};
++
++		apb2_rst: reset@01c202d8 {
++			#reset-cells = <1>;
++			compatible = "allwinner,sun6i-a31-clock-reset";
++			reg = <0x01c202d8 0x4>;
+ 		};
+ 
+ 		timer@01c20c00 {
+@@ -529,7 +571,7 @@
+ 			reg-shift = <2>;
+ 			reg-io-width = <4>;
+ 			clocks = <&bus_gates 112>;
+-			resets = <&bus_rst 144>;
++			resets = <&apb2_rst 16>;
+ 			dmas = <&dma 6>, <&dma 6>;
+ 			dma-names = "rx", "tx";
+ 			status = "disabled";
+@@ -542,7 +584,7 @@
+ 			reg-shift = <2>;
+ 			reg-io-width = <4>;
+ 			clocks = <&bus_gates 113>;
+-			resets = <&bus_rst 145>;
++			resets = <&apb2_rst 17>;
+ 			dmas = <&dma 7>, <&dma 7>;
+ 			dma-names = "rx", "tx";
+ 			status = "disabled";
+@@ -555,7 +597,7 @@
+ 			reg-shift = <2>;
+ 			reg-io-width = <4>;
+ 			clocks = <&bus_gates 114>;
+-			resets = <&bus_rst 146>;
++			resets = <&apb2_rst 18>;
+ 			dmas = <&dma 8>, <&dma 8>;
+ 			dma-names = "rx", "tx";
+ 			status = "disabled";
+@@ -568,7 +610,7 @@
+ 			reg-shift = <2>;
+ 			reg-io-width = <4>;
+ 			clocks = <&bus_gates 115>;
+-			resets = <&bus_rst 147>;
++			resets = <&apb2_rst 19>;
+ 			dmas = <&dma 9>, <&dma 9>;
+ 			dma-names = "rx", "tx";
+ 			status = "disabled";
+@@ -591,5 +633,40 @@
+ 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ 		};
++
++		apb0_reset: reset@01f014b0 {
++			reg = <0x01f014b0 0x4>;
++			compatible = "allwinner,sun6i-a31-clock-reset";
++			#reset-cells = <1>;
++		};
++
++		ir: ir@01f02000 {
++			compatible = "allwinner,sun5i-a13-ir";
++			clocks = <&apb0_gates 1>, <&ir_clk>;
++			clock-names = "apb", "ir";
++			resets = <&apb0_reset 1>;
++			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
++			reg = <0x01f02000 0x40>;
++			status = "disabled";
++		};
++
++		r_pio: pinctrl@01f02c00 {
++			compatible = "allwinner,sun8i-h3-r-pinctrl";
++			reg = <0x01f02c00 0x400>;
++			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&apb0_gates 0>;
++			resets = <&apb0_reset 0>;
++			gpio-controller;
++			#gpio-cells = <3>;
++			interrupt-controller;
++			#interrupt-cells = <3>;
++
++			ir_pins_a: ir@0 {
++				allwinner,pins = "PL11";
++				allwinner,function = "s_cir_rx";
++				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++		};
+ 	};
+ };
+--- a/arch/arm/dts/sun8i-q8-common.dtsi
++++ b/arch/arm/dts/sun8i-q8-common.dtsi
+@@ -41,11 +41,23 @@
+  */
+ #include "sunxi-q8-common.dtsi"
+ 
++#include <dt-bindings/pwm/pwm.h>
++
+ / {
+ 	aliases {
+ 		serial0 = &r_uart;
+ 	};
+ 
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pinctrl-names = "default";
++		pinctrl-0 = <&bl_en_pin_q8>;
++		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
++		brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
++		default-brightness-level = <8>;
++		enable-gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
++	};
++
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
+@@ -54,7 +66,7 @@
+ &mmc0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8>;
+-	vmmc-supply = <&reg_vcc3v0>;
++	vmmc-supply = <&reg_dcdc1>;
+ 	bus-width = <4>;
+ 	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ 	cd-inverted;
+@@ -77,8 +89,90 @@
+ 	};
+ };
+ 
++&r_rsb {
++	status = "okay";
++
++	axp22x: pmic@3a3 {
++		compatible = "x-powers,axp223";
++		reg = <0x3a3>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++		eldoin-supply = <&reg_dcdc1>;
++	};
++};
++
++#include "axp22x.dtsi"
++
++&reg_aldo1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-io";
++};
++
++&reg_aldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <2350000>;
++	regulator-max-microvolt = <2650000>;
++	regulator-name = "vdd-dll";
++};
++
++&reg_aldo3 {
++	regulator-always-on;
++	regulator-min-microvolt = <2700000>;
++	regulator-max-microvolt = <3300000>;
++	regulator-name = "vcc-pll-avcc";
++};
++
++&reg_dc1sw {
++	regulator-name = "vcc-lcd";
++};
++
++&reg_dc5ldo {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpus";
++};
++
++&reg_dcdc1 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "vcc-3v0";
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-sys";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <900000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc5 {
++	regulator-always-on;
++	regulator-min-microvolt = <1500000>;
++	regulator-max-microvolt = <1500000>;
++	regulator-name = "vcc-dram";
++};
++
++&reg_rtc_ldo {
++	regulator-name = "vcc-rtc";
++};
++
+ &r_uart {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&r_uart_pins_a>;
+ 	status = "okay";
+ };
++
++&simplefb_lcd {
++	vcc-lcd-supply = <&reg_dc1sw>;
++};
+--- a/arch/arm/dts/sun9i-a80-cubieboard4.dts
++++ b/arch/arm/dts/sun9i-a80-cubieboard4.dts
+@@ -62,9 +62,31 @@
+ 		stdout-path = "serial0:115200n8";
+ 	};
+ 
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&led_pins_cubieboard4>;
++
++		green {
++			label = "cubieboard4:green:usr";
++			gpios = <&pio 7 17 GPIO_ACTIVE_HIGH>; /* PH17 */
++		};
++
++		red {
++			label = "cubieboard4:red:usr";
++			gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
++		};
++	};
+ };
+ 
+ &pio {
++	led_pins_cubieboard4: led-pins@0 {
++		allwinner,pins = "PH6", "PH17";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
+ 	mmc0_cd_pin_cubieboard4: mmc0_cd_pin@0 {
+ 		allwinner,pins = "PH18";
+ 		allwinner,function = "gpio_in";
+@@ -89,6 +111,20 @@
+ 	vmmc-supply = <&reg_vcc3v0>;
+ 	bus-width = <8>;
+ 	non-removable;
++	cap-mmc-hw-reset;
++	status = "okay";
++};
++
++&mmc2_8bit_pins {
++	/* Increase drive strength for DDR modes */
++	allwinner,drive = <SUN4I_PINCTRL_40_MA>;
++};
++
++&r_ir {
++	status = "okay";
++};
++
++&r_rsb {
+ 	status = "okay";
+ };
+ 
+--- a/arch/arm/dts/sun9i-a80-optimus.dts
++++ b/arch/arm/dts/sun9i-a80-optimus.dts
+@@ -65,7 +65,7 @@
+ 	leds {
+ 		compatible = "gpio-leds";
+ 		pinctrl-names = "default";
+-		pinctrl-0 = <&led_pins_optimus>;
++		pinctrl-0 = <&led_pins_optimus>, <&led_r_pins_optimus>;
+ 
+ 		/* The LED names match those found on the board */
+ 
+@@ -74,7 +74,10 @@
+ 			gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>;
+ 		};
+ 
+-		/* led3 is on PM15, in R_PIO */
++		led3 {
++			label = "optimus:led3:usr";
++			gpios = <&r_pio 1 15 GPIO_ACTIVE_HIGH>; /* PM15 */
++		};
+ 
+ 		led4 {
+ 			label = "optimus:led4:usr";
+@@ -106,17 +109,6 @@
+ 	status = "okay";
+ };
+ 
+-&i2c3 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&i2c3_pins_a>;
+-	status = "okay";
+-};
+-
+-&i2c3_pins_a {
+-	/* Enable internal pull-up */
+-	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+-};
+-
+ &ohci0 {
+ 	status = "okay";
+ };
+@@ -171,30 +163,42 @@
+ 	vmmc-supply = <&reg_vcc3v0>;
+ 	bus-width = <8>;
+ 	non-removable;
++	cap-mmc-hw-reset;
+ 	status = "okay";
+ };
+ 
++&mmc2_8bit_pins {
++	/* Increase drive strength for DDR modes */
++	allwinner,drive = <SUN4I_PINCTRL_40_MA>;
++};
++
+ &reg_usb1_vbus {
+ 	pinctrl-0 = <&usb1_vbus_pin_optimus>;
+ 	gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ 	status = "okay";
+ };
+ 
+-&uart0 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&uart0_pins_a>;
++&r_ir {
+ 	status = "okay";
+ };
+ 
+-&uart4 {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&uart4_pins_a>;
++&r_pio {
++	led_r_pins_optimus: led-pins@1 {
++		allwinner,pins = "PM15";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&r_rsb {
+ 	status = "okay";
+ };
+ 
+-&uart4_pins_a {
+-	/* Enable internal pull-up */
+-	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
+ };
+ 
+ &usbphy1 {
+--- a/arch/arm/dts/sun9i-a80.dtsi
++++ b/arch/arm/dts/sun9i-a80.dtsi
+@@ -128,6 +128,17 @@
+ 		 */
+ 		ranges = <0 0 0 0x20000000>;
+ 
++		/*
++		 * This clock is actually configurable from the PRCM address
++		 * space. The external 24M oscillator can be turned off, and
++		 * the clock switched to an internal 16M RC oscillator. Under
++		 * normal operation there's no reason to do this, and the
++		 * default is to use the external good one, so just model this
++		 * as a fixed clock. Also it is not entirely clear if the
++		 * osc24M mux in the PRCM affects the entire clock tree, which
++		 * would also throw all the PLL clock rates off, or just the
++		 * downstream clocks in the PRCM.
++		 */
+ 		osc24M: osc24M_clk {
+ 			#clock-cells = <0>;
+ 			compatible = "fixed-clock";
+@@ -135,6 +146,13 @@
+ 			clock-output-names = "osc24M";
+ 		};
+ 
++		/*
++		 * The 32k clock is from an external source, normally the
++		 * AC100 codec/RTC chip. This clock is by default enabled
++		 * and clocked at 32768 Hz, from the oscillator connected
++		 * to the AC100. It is configurable, but no such driver or
++		 * bindings exist yet.
++		 */
+ 		osc32k: osc32k_clk {
+ 			#clock-cells = <0>;
+ 			compatible = "fixed-clock";
+@@ -164,6 +182,14 @@
+ 					     "usb_phy2", "usb_hsic_12M";
+ 		};
+ 
++		pll3: clk@06000008 {
++			/* placeholder until implemented */
++			#clock-cells = <0>;
++			compatible = "fixed-clock";
++			clock-rate = <0>;
++			clock-output-names = "pll3";
++		};
++
+ 		pll4: clk@0600000c {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun9i-a80-pll4-clk";
+@@ -277,9 +303,12 @@
+ 			compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
+ 			reg = <0x06000580 0x4>;
+ 			clocks = <&ahb0>;
+-			clock-indices = <0>, <1>, <3>, <5>, <8>, <12>, <13>,
+-					<14>, <15>, <16>, <18>, <20>, <21>,
+-					<22>, <23>;
++			clock-indices = <0>, <1>, <3>,
++					<5>, <8>, <12>,
++					<13>, <14>,
++					<15>, <16>, <18>,
++					<20>, <21>, <22>,
++					<23>;
+ 			clock-output-names = "ahb0_fd", "ahb0_ve", "ahb0_gpu",
+ 					"ahb0_ss", "ahb0_sd", "ahb0_nand1",
+ 					"ahb0_nand0", "ahb0_sdram",
+@@ -293,7 +322,10 @@
+ 			compatible = "allwinner,sun9i-a80-ahb1-gates-clk";
+ 			reg = <0x06000584 0x4>;
+ 			clocks = <&ahb1>;
+-			clock-indices = <0>, <1>, <17>, <21>, <22>, <23>, <24>;
++			clock-indices = <0>, <1>,
++					<17>, <21>,
++					<22>, <23>,
++					<24>;
+ 			clock-output-names = "ahb1_usbotg", "ahb1_usbhci",
+ 					"ahb1_gmac", "ahb1_msgbox",
+ 					"ahb1_spinlock", "ahb1_hstimer",
+@@ -305,8 +337,9 @@
+ 			compatible = "allwinner,sun9i-a80-ahb2-gates-clk";
+ 			reg = <0x06000588 0x4>;
+ 			clocks = <&ahb2>;
+-			clock-indices = <0>, <1>, <2>, <4>, <5>, <7>, <8>,
+-					<11>;
++			clock-indices = <0>, <1>,
++					<2>, <4>, <5>,
++					<7>, <8>, <11>;
+ 			clock-output-names = "ahb2_lcd0", "ahb2_lcd1",
+ 					"ahb2_edp", "ahb2_csi", "ahb2_hdmi",
+ 					"ahb2_de", "ahb2_mp", "ahb2_mipi_dsi";
+@@ -317,8 +350,10 @@
+ 			compatible = "allwinner,sun9i-a80-apb0-gates-clk";
+ 			reg = <0x06000590 0x4>;
+ 			clocks = <&apb0>;
+-			clock-indices = <1>, <5>, <11>, <12>, <13>, <15>,
+-					<17>, <18>, <19>;
++			clock-indices = <1>, <5>,
++					<11>, <12>, <13>,
++					<15>, <17>, <18>,
++					<19>;
+ 			clock-output-names = "apb0_spdif", "apb0_pio",
+ 					"apb0_ac97", "apb0_i2s0", "apb0_i2s1",
+ 					"apb0_lradc", "apb0_gpadc", "apb0_twd",
+@@ -330,14 +365,79 @@
+ 			compatible = "allwinner,sun9i-a80-apb1-gates-clk";
+ 			reg = <0x06000594 0x4>;
+ 			clocks = <&apb1>;
+-			clock-indices = <0>, <1>, <2>, <3>, <4>,
+-					<16>, <17>, <18>, <19>, <20>, <21>;
++			clock-indices = <0>, <1>,
++					<2>, <3>, <4>,
++					<16>, <17>,
++					<18>, <19>,
++					<20>, <21>;
+ 			clock-output-names = "apb1_i2c0", "apb1_i2c1",
+ 					"apb1_i2c2", "apb1_i2c3", "apb1_i2c4",
+ 					"apb1_uart0", "apb1_uart1",
+ 					"apb1_uart2", "apb1_uart3",
+ 					"apb1_uart4", "apb1_uart5";
+ 		};
++
++		cpus_clk: clk@08001410 {
++			compatible = "allwinner,sun9i-a80-cpus-clk";
++			reg = <0x08001410 0x4>;
++			#clock-cells = <0>;
++			clocks = <&osc32k>, <&osc24M>, <&pll4>, <&pll3>;
++			clock-output-names = "cpus";
++		};
++
++		ahbs: ahbs_clk {
++			compatible = "fixed-factor-clock";
++			#clock-cells = <0>;
++			clock-div = <1>;
++			clock-mult = <1>;
++			clocks = <&cpus_clk>;
++			clock-output-names = "ahbs";
++		};
++
++		apbs: clk@0800141c {
++			compatible = "allwinner,sun8i-a23-apb0-clk";
++			reg = <0x0800141c 0x4>;
++			#clock-cells = <0>;
++			clocks = <&ahbs>;
++			clock-output-names = "apbs";
++		};
++
++		apbs_gates: clk@08001428 {
++			compatible = "allwinner,sun9i-a80-apbs-gates-clk";
++			reg = <0x08001428 0x4>;
++			#clock-cells = <1>;
++			clocks = <&apbs>;
++			clock-indices = <0>, <1>,
++					<2>, <3>,
++					<4>, <5>,
++					<6>, <7>,
++					<12>, <13>,
++					<16>, <17>,
++					<18>, <20>;
++			clock-output-names = "apbs_pio", "apbs_ir",
++					"apbs_timer", "apbs_rsb",
++					"apbs_uart", "apbs_1wire",
++					"apbs_i2c0", "apbs_i2c1",
++					"apbs_ps2_0", "apbs_ps2_1",
++					"apbs_dma", "apbs_i2s0",
++					"apbs_i2s1", "apbs_twd";
++		};
++
++		r_1wire_clk: clk@08001450 {
++			reg = <0x08001450 0x4>;
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-mod0-clk";
++			clocks = <&osc32k>, <&osc24M>;
++			clock-output-names = "r_1wire";
++		};
++
++		r_ir_clk: clk@08001454 {
++			reg = <0x08001454 0x4>;
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-mod0-clk";
++			clocks = <&osc32k>, <&osc24M>;
++			clock-output-names = "r_ir";
++		};
+ 	};
+ 
+ 	soc {
+@@ -443,7 +543,7 @@
+ 		};
+ 
+ 		mmc0: mmc@01c0f000 {
+-			compatible = "allwinner,sun5i-a13-mmc";
++			compatible = "allwinner,sun9i-a80-mmc";
+ 			reg = <0x01c0f000 0x1000>;
+ 			clocks = <&mmc_config_clk 0>, <&mmc0_clk 0>,
+ 				 <&mmc0_clk 1>, <&mmc0_clk 2>;
+@@ -457,7 +557,7 @@
+ 		};
+ 
+ 		mmc1: mmc@01c10000 {
+-			compatible = "allwinner,sun5i-a13-mmc";
++			compatible = "allwinner,sun9i-a80-mmc";
+ 			reg = <0x01c10000 0x1000>;
+ 			clocks = <&mmc_config_clk 1>, <&mmc1_clk 0>,
+ 				 <&mmc1_clk 1>, <&mmc1_clk 2>;
+@@ -471,7 +571,7 @@
+ 		};
+ 
+ 		mmc2: mmc@01c11000 {
+-			compatible = "allwinner,sun5i-a13-mmc";
++			compatible = "allwinner,sun9i-a80-mmc";
+ 			reg = <0x01c11000 0x1000>;
+ 			clocks = <&mmc_config_clk 2>, <&mmc2_clk 0>,
+ 				 <&mmc2_clk 1>, <&mmc2_clk 2>;
+@@ -485,7 +585,7 @@
+ 		};
+ 
+ 		mmc3: mmc@01c12000 {
+-			compatible = "allwinner,sun5i-a13-mmc";
++			compatible = "allwinner,sun9i-a80-mmc";
+ 			reg = <0x01c12000 0x1000>;
+ 			clocks = <&mmc_config_clk 3>, <&mmc3_clk 0>,
+ 				 <&mmc3_clk 1>, <&mmc3_clk 2>;
+@@ -582,7 +682,7 @@
+ 			clocks = <&apb0_gates 5>;
+ 			gpio-controller;
+ 			interrupt-controller;
+-			#interrupt-cells = <2>;
++			#interrupt-cells = <3>;
+ 			#size-cells = <0>;
+ 			#gpio-cells = <3>;
+ 
+@@ -604,7 +704,8 @@
+ 			mmc2_8bit_pins: mmc2_8bit {
+ 				allwinner,pins = "PC6", "PC7", "PC8", "PC9",
+ 						 "PC10", "PC11", "PC12",
+-						 "PC13", "PC14", "PC15";
++						 "PC13", "PC14", "PC15",
++						 "PC16";
+ 				allwinner,function = "mmc2";
+ 				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ 				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+@@ -752,14 +853,83 @@
+ 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ 		};
+ 
++		apbs_rst: reset@080014b0 {
++			reg = <0x080014b0 0x4>;
++			compatible = "allwinner,sun6i-a31-clock-reset";
++			#reset-cells = <1>;
++		};
++
++		nmi_intc: interrupt-controller@080015a0 {
++			compatible = "allwinner,sun9i-a80-nmi";
++			interrupt-controller;
++			#interrupt-cells = <2>;
++			reg = <0x080015a0 0xc>;
++			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		r_ir: ir@08002000 {
++			compatible = "allwinner,sun5i-a13-ir";
++			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
++			pinctrl-names = "default";
++			pinctrl-0 = <&r_ir_pins>;
++			clocks = <&apbs_gates 1>, <&r_ir_clk>;
++			clock-names = "apb", "ir";
++			resets = <&apbs_rst 1>;
++			reg = <0x08002000 0x40>;
++			status = "disabled";
++		};
++
+ 		r_uart: serial@08002800 {
+ 			compatible = "snps,dw-apb-uart";
+ 			reg = <0x08002800 0x400>;
+ 			interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ 			reg-shift = <2>;
+ 			reg-io-width = <4>;
+-			clocks = <&osc24M>;
++			clocks = <&apbs_gates 4>;
++			resets = <&apbs_rst 4>;
+ 			status = "disabled";
+ 		};
++
++		r_pio: pinctrl@08002c00 {
++			compatible = "allwinner,sun9i-a80-r-pinctrl";
++			reg = <0x08002c00 0x400>;
++			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&apbs_gates 0>;
++			resets = <&apbs_rst 0>;
++			gpio-controller;
++			interrupt-controller;
++			#address-cells = <1>;
++			#size-cells = <0>;
++			#gpio-cells = <3>;
++
++			r_ir_pins: r_ir {
++				allwinner,pins = "PL6";
++				allwinner,function = "s_cir_rx";
++				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++
++			r_rsb_pins: r_rsb {
++				allwinner,pins = "PN0", "PN1";
++				allwinner,function = "s_rsb";
++				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++			};
++		};
++
++		r_rsb: i2c@08003400 {
++			compatible = "allwinner,sun8i-a23-rsb";
++			reg = <0x08003400 0x400>;
++			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&apbs_gates 3>;
++			clock-frequency = <3000000>;
++			resets = <&apbs_rst 3>;
++			pinctrl-names = "default";
++			pinctrl-0 = <&r_rsb_pins>;
++			status = "disabled";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
+ 	};
+ };
+--- /dev/null
++++ b/arch/arm/dts/sunxi-itead-core-common.dtsi
+@@ -0,0 +1,136 @@
++/*
++ * Copyright 2015 - Marcus Cooper <codekipper@gmail.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#include "sunxi-common-regulators.dtsi"
++
++/ {
++	aliases {
++		serial0 = &uart0;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++
++	axp209: pmic@34 {
++		reg = <0x34>;
++	};
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++#include "axp209.dtsi"
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
++&reg_usb1_vbus {
++	status = "okay";
++};
++
++&reg_usb2_vbus {
++	status = "okay";
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
++&usbphy {
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++	usb2_vbus-supply = <&reg_usb2_vbus>;
++	status = "okay";
++};
+--- a/arch/arm/dts/sunxi-q8-common.dtsi
++++ b/arch/arm/dts/sunxi-q8-common.dtsi
+@@ -75,3 +75,9 @@
+ 		voltage = <400000>;
+ 	};
+ };
++
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm0_pins>;
++	status = "okay";
++};
diff --git a/package/boot/uboot-sunxi/patches/012-sun6i-fix-clock_twi_onoff.patch b/package/boot/uboot-sunxi/patches/012-sun6i-fix-clock_twi_onoff.patch
new file mode 100644
index 0000000000..45416703a4
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/012-sun6i-fix-clock_twi_onoff.patch
@@ -0,0 +1,38 @@
+From 730d2f3a41c5ccae71b5008fffdf697d143be68c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 16 Mar 2016 20:44:51 +0100
+Subject: [PATCH] sunxi: Fix clock_twi_onoff for sun6i
+
+The clock_sun6i.c implementation was not deasserting the reset for
+the regular i2c controllers, this commit fixes this.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ arch/arm/cpu/armv7/sunxi/clock_sun6i.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
++++ b/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
+@@ -100,13 +100,18 @@ int clock_twi_onoff(int port, int state)
+ 		return 0;
+ 	}
+ 
+-	/* set the apb clock gate for twi */
+-	if (state)
++	/* set the apb clock gate and reset for twi */
++	if (state) {
+ 		setbits_le32(&ccm->apb2_gate,
+ 			     CLK_GATE_OPEN << (APB2_GATE_TWI_SHIFT+port));
+-	else
++		setbits_le32(&ccm->apb2_reset_cfg,
++			     1 << (APB2_RESET_TWI_SHIFT + port));
++	} else {
++		clrbits_le32(&ccm->apb2_reset_cfg,
++			     1 << (APB2_RESET_TWI_SHIFT + port));
+ 		clrbits_le32(&ccm->apb2_gate,
+ 			     CLK_GATE_OPEN << (APB2_GATE_TWI_SHIFT+port));
++	}
+ 
+ 	return 0;
+ }
diff --git a/package/boot/uboot-sunxi/patches/013-enable-realtek-phy.patch b/package/boot/uboot-sunxi/patches/013-enable-realtek-phy.patch
new file mode 100644
index 0000000000..47f825c570
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/013-enable-realtek-phy.patch
@@ -0,0 +1,24 @@
+From 1eae8f66ff749409eb96e2f3f3387c56232d0b8a Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 16 Mar 2016 13:46:22 +0100
+Subject: [PATCH] sunxi: Enable realtek phy support
+
+Enable building of drivers/net/phy/realtek.c so that realtek phys
+get properly initialized.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ include/configs/sunxi-common.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -314,6 +314,7 @@ extern int soft_i2c_gpio_scl;
+ #define CONFIG_PHY_GIGE			/* GMAC can use gigabit PHY	*/
+ #define CONFIG_PHY_ADDR		1
+ #define CONFIG_MII			/* MII PHY management		*/
++#define CONFIG_PHY_REALTEK
+ #endif
+ 
+ #ifdef CONFIG_USB_EHCI_HCD
diff --git a/package/boot/uboot-sunxi/patches/014-fix-gmac-init.patch b/package/boot/uboot-sunxi/patches/014-fix-gmac-init.patch
new file mode 100644
index 0000000000..cf511ce773
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/014-fix-gmac-init.patch
@@ -0,0 +1,127 @@
+From fc8991c61c393ce6a9d3dfc97cb56dbbd9e8cbba Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 17 Mar 2016 13:53:03 +0100
+Subject: [PATCH] sunxi: Fix gmac not working due to cpu_eth_init no longer
+ being called
+
+cpu_eth_init is no longer called for dm enabled eth drivers, this
+was causing the sunxi gmac eth controller to no longer work in u-boot.
+
+This commit fixes this by calling the clock, reset and pinmux setup
+function from s_init() and enabling the phy power pin (if any) from
+board_init().
+
+The enabling of phy power cannot be done from s_init because it uses dm
+and dm is not ready yet at this point.
+
+Note that the mdelay is dropped as the phy gets enabled much earlier
+now, so it is no longer needed.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+Tested-by: Karsten Merker <merker@debian.org>
+Tested-by: Michael Haas <haas@computerlinguist.org>
+---
+ arch/arm/cpu/armv7/sunxi/board.c            | 28 +---------------------------
+ arch/arm/include/asm/arch-sunxi/sys_proto.h |  6 +++++-
+ board/sunxi/board.c                         |  5 +++++
+ board/sunxi/gmac.c                          | 14 +-------------
+ 4 files changed, 12 insertions(+), 41 deletions(-)
+
+--- a/arch/arm/cpu/armv7/sunxi/board.c
++++ b/arch/arm/cpu/armv7/sunxi/board.c
+@@ -136,6 +136,7 @@ void s_init(void)
+ 	timer_init();
+ 	gpio_init();
+ 	i2c_init_board();
++	eth_init_board();
+ }
+ 
+ #ifdef CONFIG_SPL_BUILD
+@@ -243,30 +244,3 @@ void enable_caches(void)
+ 	dcache_enable();
+ }
+ #endif
+-
+-#ifdef CONFIG_CMD_NET
+-/*
+- * Initializes on-chip ethernet controllers.
+- * to override, implement board_eth_init()
+- */
+-int cpu_eth_init(bd_t *bis)
+-{
+-	__maybe_unused int rc;
+-
+-#ifdef CONFIG_MACPWR
+-	gpio_request(CONFIG_MACPWR, "macpwr");
+-	gpio_direction_output(CONFIG_MACPWR, 1);
+-	mdelay(200);
+-#endif
+-
+-#ifdef CONFIG_SUNXI_GMAC
+-	rc = sunxi_gmac_initialize(bis);
+-	if (rc < 0) {
+-		printf("sunxi: failed to initialize gmac\n");
+-		return rc;
+-	}
+-#endif
+-
+-	return 0;
+-}
+-#endif
+--- a/arch/arm/include/asm/arch-sunxi/sys_proto.h
++++ b/arch/arm/include/asm/arch-sunxi/sys_proto.h
+@@ -24,6 +24,10 @@ void sdelay(unsigned long);
+ void return_to_fel(uint32_t lr, uint32_t sp);
+ 
+ /* Board / SoC level designware gmac init */
+-int sunxi_gmac_initialize(bd_t *bis);
++#if !defined CONFIG_SPL_BUILD && defined CONFIG_SUNXI_GMAC
++void eth_init_board(void);
++#else
++static inline void eth_init_board(void) {}
++#endif
+ 
+ #endif
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -90,6 +90,11 @@ int board_init(void)
+ 	if (ret)
+ 		return ret;
+ 
++#ifdef CONFIG_MACPWR
++	gpio_request(CONFIG_MACPWR, "macpwr");
++	gpio_direction_output(CONFIG_MACPWR, 1);
++#endif
++
+ 	/* Uses dm gpio code so do this here and not in i2c_init_board() */
+ 	return soft_i2c_board_init();
+ }
+--- a/board/sunxi/gmac.c
++++ b/board/sunxi/gmac.c
+@@ -6,7 +6,7 @@
+ #include <asm/arch/clock.h>
+ #include <asm/arch/gpio.h>
+ 
+-int sunxi_gmac_initialize(bd_t *bis)
++void eth_init_board(void)
+ {
+ 	int pin;
+ 	struct sunxi_ccm_reg *const ccm =
+@@ -79,16 +79,4 @@ int sunxi_gmac_initialize(bd_t *bis)
+ 	for (pin = SUNXI_GPA(26); pin <= SUNXI_GPA(27); pin++)
+ 		sunxi_gpio_set_cfgpin(pin, SUN6I_GPA_GMAC);
+ #endif
+-
+-#ifdef CONFIG_DM_ETH
+-	return 0;
+-#else
+-# ifdef CONFIG_RGMII
+-	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_RGMII);
+-# elif defined CONFIG_GMII
+-	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_GMII);
+-# else
+-	return designware_initialize(SUNXI_GMAC_BASE, PHY_INTERFACE_MODE_MII);
+-# endif
+-#endif
+ }
diff --git a/package/boot/uboot-sunxi/patches/015-fix-2nd-usb-ctrler-on-sun47i.patch b/package/boot/uboot-sunxi/patches/015-fix-2nd-usb-ctrler-on-sun47i.patch
new file mode 100644
index 0000000000..95a77c68d6
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/015-fix-2nd-usb-ctrler-on-sun47i.patch
@@ -0,0 +1,78 @@
+From 948603d4d637a0e04a3214253b911cfc4ed11220 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 21 Mar 2016 14:44:35 +0100
+Subject: [PATCH] sunxi: Fix 2nd usb controller on sun4i/sun7i no longer
+ working
+
+The 2nd usb controller on sun4i/sun7i has its base address 0x8000
+bytes from the 1st one, rather then 0x1000. Also the ahb clk gates
+are interleaved with the ohci clk-gates introducing a hole between
+the clks for usb1 and usb2.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ drivers/usb/host/ehci-sunxi.c | 13 +++++++++++--
+ drivers/usb/host/ohci-sunxi.c | 15 ++++++++++++---
+ 2 files changed, 23 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/ehci-sunxi.c
++++ b/drivers/usb/host/ehci-sunxi.c
+@@ -17,6 +17,14 @@
+ #include <dm.h>
+ #include "ehci.h"
+ 
++#ifdef CONFIG_SUNXI_GEN_SUN4I
++#define BASE_DIST		0x8000
++#define AHB_CLK_DIST		2
++#else
++#define BASE_DIST		0x1000
++#define AHB_CLK_DIST		1
++#endif
++
+ struct ehci_sunxi_priv {
+ 	struct ehci_ctrl ehci;
+ 	int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
+@@ -39,8 +47,9 @@ static int ehci_usb_probe(struct udevice
+ #ifdef CONFIG_MACH_SUN8I_H3
+ 	priv->ahb_gate_mask |= 1 << AHB_GATE_OFFSET_USB_OHCI0;
+ #endif
+-	priv->phy_index = ((u32)hccr - SUNXI_USB1_BASE) / 0x1000 + 1;
+-	priv->ahb_gate_mask <<= priv->phy_index - 1;
++	priv->phy_index = ((u32)hccr - SUNXI_USB1_BASE) / BASE_DIST;
++	priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
++	priv->phy_index++; /* Non otg phys start at 1 */
+ 
+ 	setbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
+ #ifdef CONFIG_SUNXI_GEN_SUN6I
+--- a/drivers/usb/host/ohci-sunxi.c
++++ b/drivers/usb/host/ohci-sunxi.c
+@@ -17,6 +17,14 @@
+ #include <usb.h>
+ #include "ohci.h"
+ 
++#ifdef CONFIG_SUNXI_GEN_SUN4I
++#define BASE_DIST		0x8000
++#define AHB_CLK_DIST		2
++#else
++#define BASE_DIST		0x1000
++#define AHB_CLK_DIST		1
++#endif
++
+ struct ohci_sunxi_priv {
+ 	ohci_t ohci;
+ 	int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
+@@ -42,9 +50,10 @@ static int ohci_usb_probe(struct udevice
+ 	priv->ahb_gate_mask |= 1 << AHB_GATE_OFFSET_USB_EHCI0;
+ #endif
+ 	priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
+-	priv->phy_index = ((u32)regs - (SUNXI_USB1_BASE + 0x400)) / 0x1000 + 1;
+-	priv->ahb_gate_mask <<= priv->phy_index - 1;
+-	priv->usb_gate_mask <<= priv->phy_index - 1;
++	priv->phy_index = ((u32)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
++	priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
++	priv->usb_gate_mask <<= priv->phy_index;
++	priv->phy_index++; /* Non otg phys start at 1 */
+ 
+ 	setbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
+ 	setbits_le32(&ccm->usb_clk_cfg, priv->usb_gate_mask);
diff --git a/package/boot/uboot-sunxi/patches/016-spl-print-mmc-slot.patch b/package/boot/uboot-sunxi/patches/016-spl-print-mmc-slot.patch
new file mode 100644
index 0000000000..04a2af72ee
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/016-spl-print-mmc-slot.patch
@@ -0,0 +1,31 @@
+From 8f10b5c65611e6c15a113bf63289b6696452f90d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 20 Mar 2016 14:17:10 +0100
+Subject: [PATCH] spl: Print from which mmc slot spl is trying to boot
+
+On some sunxi boards (and presumably also non sunxi boards) u-boot can
+be either loaded from a sdcard in a micro-sd slot, or from eMMC.
+
+Print which MMC spl tries to boot from, to help debugging.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Reviewed-by: Tom Rini <trini@konsulko.com>
+---
+ common/spl/spl.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/common/spl/spl.c
++++ b/common/spl/spl.c
+@@ -210,9 +210,9 @@ struct boot_device_name boot_name_table[
+ 	{ BOOT_DEVICE_RAM, "RAM" },
+ #endif
+ #ifdef CONFIG_SPL_MMC_SUPPORT
+-	{ BOOT_DEVICE_MMC1, "MMC" },
+-	{ BOOT_DEVICE_MMC2, "MMC" },
+-	{ BOOT_DEVICE_MMC2_2, "MMC" },
++	{ BOOT_DEVICE_MMC1, "MMC1" },
++	{ BOOT_DEVICE_MMC2, "MMC2" },
++	{ BOOT_DEVICE_MMC2_2, "MMC2_2" },
+ #endif
+ #ifdef CONFIG_SPL_NAND_SUPPORT
+ 	{ BOOT_DEVICE_NAND, "NAND" },
diff --git a/package/boot/uboot-sunxi/patches/017-usb-add-support-for-usb3-vbus-pin.patch b/package/boot/uboot-sunxi/patches/017-usb-add-support-for-usb3-vbus-pin.patch
new file mode 100644
index 0000000000..098fe72035
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/017-usb-add-support-for-usb3-vbus-pin.patch
@@ -0,0 +1,39 @@
+From 60fa63012fcdc3c4ec1497bf5e358f0a90b40949 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 18 Mar 2016 08:42:01 +0100
+Subject: [PATCH] sunxi: Add support for USB vbus pin for USB3
+
+The H3 has USB0 - USB3, add support for having a USB vbus pin for USB3.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ arch/arm/cpu/armv7/sunxi/usb_phy.c | 1 +
+ board/sunxi/Kconfig                | 6 ++++++
+ 2 files changed, 7 insertions(+)
+
+--- a/arch/arm/cpu/armv7/sunxi/usb_phy.c
++++ b/arch/arm/cpu/armv7/sunxi/usb_phy.c
+@@ -76,6 +76,7 @@ static int get_vbus_gpio(int index)
+ 	case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN);
+ 	case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN);
+ 	case 2: return sunxi_name_to_gpio(CONFIG_USB2_VBUS_PIN);
++	case 3: return sunxi_name_to_gpio(CONFIG_USB3_VBUS_PIN);
+ 	}
+ 	return -EINVAL;
+ }
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -341,6 +341,12 @@ config USB2_VBUS_PIN
+ 	---help---
+ 	See USB1_VBUS_PIN help text.
+ 
++config USB3_VBUS_PIN
++	string "Vbus enable pin for usb3 (ehci2)"
++	default ""
++	---help---
++	See USB1_VBUS_PIN help text.
++
+ config I2C0_ENABLE
+ 	bool "Enable I2C/TWI controller 0"
+ 	default y if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
diff --git a/package/boot/uboot-sunxi/patches/018-usb-specify-vbus-pins-on-orangepis.patch b/package/boot/uboot-sunxi/patches/018-usb-specify-vbus-pins-on-orangepis.patch
new file mode 100644
index 0000000000..a216bc9f11
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/018-usb-specify-vbus-pins-on-orangepis.patch
@@ -0,0 +1,31 @@
+From ce0d0926758f631fdd655d438acd32d5935d43a4 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 18 Mar 2016 08:45:21 +0100
+Subject: [PATCH] sunxi: Specify USB vbus pins for orangepi boards
+
+This fixes the USB ports not working on the orangepi_plus and stops us
+from messing with gpio-s which we should not touch on the orangepi_pc.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Ian Campbell <ijc@hellion.org.uk>
+---
+ configs/orangepi_pc_defconfig   | 3 +++
+ configs/orangepi_plus_defconfig | 1 +
+ 2 files changed, 4 insertions(+)
+
+--- a/configs/orangepi_pc_defconfig
++++ b/configs/orangepi_pc_defconfig
+@@ -14,3 +14,6 @@ CONFIG_SPL=y
+ CONFIG_CMD_GPIO=y
+ CONFIG_SY8106A_POWER=y
+ CONFIG_USB_EHCI_HCD=y
++CONFIG_USB1_VBUS_PIN=""
++CONFIG_USB2_VBUS_PIN=""
++CONFIG_USB3_VBUS_PIN=""
+--- a/configs/orangepi_plus_defconfig
++++ b/configs/orangepi_plus_defconfig
+@@ -14,3 +14,4 @@ CONFIG_SPL=y
+ CONFIG_CMD_GPIO=y
+ CONFIG_SY8106A_POWER=y
+ CONFIG_USB_EHCI_HCD=y
++CONFIG_USB1_VBUS_PIN="PG13"
diff --git a/package/boot/uboot-sunxi/patches/019-sid-add-efuse-support-for-h3-a83t.patch b/package/boot/uboot-sunxi/patches/019-sid-add-efuse-support-for-h3-a83t.patch
new file mode 100644
index 0000000000..e7b8cd73df
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/019-sid-add-efuse-support-for-h3-a83t.patch
@@ -0,0 +1,33 @@
+From 70fe24ed93fa90eb407d18a5fc9d9ad85ac9184c Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Wed, 27 Jan 2016 16:34:43 +0800
+Subject: [PATCH] sunxi: Support SID e-fuses on A83T and H3
+
+On the A83T and H3, the SID block is at a different address.
+Furthurmore, the e-fuses are at an offset of 0x200 within the
+hardware's address space.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Acked-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/include/asm/arch-sunxi/cpu_sun4i.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+@@ -82,7 +82,14 @@
+ #define SUNXI_AD_DA_BASE		0x01c22c00
+ #define SUNXI_KEYPAD_BASE		0x01c23000
+ #define SUNXI_TZPC_BASE			0x01c23400
++
++#if defined(CONFIG_MACH_SUN8I_A83T) || defined(CONFIG_MACH_SUN8I_H3)
++/* SID address space starts at 0x01c1400, but e-fuse is at offset 0x200 */
++#define SUNXI_SID_BASE			0x01c14200
++#else
+ #define SUNXI_SID_BASE			0x01c23800
++#endif
++
+ #define SUNXI_SJTAG_BASE		0x01c23c00
+ 
+ #define SUNXI_TP_BASE			0x01c25000
diff --git a/package/boot/uboot-sunxi/patches/020-boot-display-board-model-on-startup.patch b/package/boot/uboot-sunxi/patches/020-boot-display-board-model-on-startup.patch
new file mode 100644
index 0000000000..d49fc97373
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/020-boot-display-board-model-on-startup.patch
@@ -0,0 +1,23 @@
+From 2af25b747340c6c8f6a6b9e27632db577bf4da52 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Mon, 22 Feb 2016 22:55:46 -0700
+Subject: [PATCH] sunxi: Display the board model on start-up
+
+It is useful to know which sunxi board you are booting. Display this on
+start-up to avoid confusion.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+---
+ include/configs/sunxi-common.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -174,6 +174,7 @@
+ 
+ #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
+ #define CONFIG_IDENT_STRING		" Allwinner Technology"
++#define CONFIG_DISPLAY_BOARDINFO
+ 
+ #define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512) KiB */
+ #define CONFIG_ENV_SIZE			(128 << 10)	/* 128 KiB */
diff --git a/package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch b/package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch
new file mode 100644
index 0000000000..a402feb3cd
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch
@@ -0,0 +1,32 @@
+From a58eb20fb80f478038243e9e0f30f6984725e265 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 6 Jan 2015 15:47:18 +0100
+Subject: sun6i: Sync PLL1 multipliers/dividers with Boot1
+
+This change syncs up the multipliers and dividers used to initialize
+PLL1 (i.e. the fast clock driving the ARM cores) with the values used
+in Allwinner's Boot1 on sun6i.
+
+More specifically, the following settings are now used:
+ * up to 768MHz:  mul=2, div=2 (was: mul=1, div=1)
+ * up to 1152MHz: mul=3, div=2 (unchanged)
+ * above 1152MHz: mul=4, div=2 (was: mul=2, div=1)
+
+--- a/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
++++ b/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
+@@ -122,11 +122,12 @@ void clock_set_pll1(unsigned int clk)
+ 	struct sunxi_ccm_reg * const ccm =
+ 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ 	const int p = 0;
+-	int k = 1;
+-	int m = 1;
++	int k = 2;
++	int m = 2;
+ 
+ 	if (clk > 1152000000) {
+-		k = 2;
++		k = 4;
++		m = 2;
+ 	} else if (clk > 768000000) {
+ 		k = 3;
+ 		m = 2;
diff --git a/package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch b/package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch
new file mode 100644
index 0000000000..d200633bc2
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch
@@ -0,0 +1,70 @@
+From b2b385df5095fff80b4655142f58a2a6801e6c80 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 6 Jan 2015 21:26:44 +0100
+Subject: sun6i: Fix and document PLL LDO voltage selection
+
+The PRCM_PLL_CTRL_LDO_OUT_L and PRCM_PLL_CTRL_LDO_OUT_H macros had
+their meaning reversed. This is fixed by this change-set. With this
+changed, the PRCM_PLL_CTRL_LDO_OUT_L(1370) now becomes self-evident
+as setting the voltage to 1.37v (which it had done all along, even
+though stating a different target voltage).
+
+After changing the PLL LDO setting, it will take a little while for
+the voltage output to settle. A sdelay()-based loop waits the same
+order of magnitude as Boot1.
+
+Furthermore, a bit of documentation is added to clarify that the
+required setting for the PLL LDO is 1.37v as per the A31 manual.
+
+--- a/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
++++ b/arch/arm/cpu/armv7/sunxi/clock_sun6i.c
+@@ -24,14 +24,27 @@ void clock_init_safe(void)
+ 	struct sunxi_prcm_reg * const prcm =
+ 		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+ 
+-	/* Set PLL ldo voltage without this PLL6 does not work properly */
++	/* Set PLL ldo voltage without this PLL6 does not work properly.
++	 *
++	 * As the A31 manual states, that "before enable PLL, PLLVDD
++	 * LDO should be set to 1.37v", we need to configure this to 2.5v
++	 * in the "PLL Input Power Select" (0 << 15) and (7 << 16).
++	 */
+ 	clrsetbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK,
+ 			PRCM_PLL_CTRL_LDO_KEY);
+ 	clrsetbits_le32(&prcm->pll_ctrl1, ~PRCM_PLL_CTRL_LDO_KEY_MASK,
+ 		PRCM_PLL_CTRL_LDO_DIGITAL_EN | PRCM_PLL_CTRL_LDO_ANALOG_EN |
+-		PRCM_PLL_CTRL_EXT_OSC_EN | PRCM_PLL_CTRL_LDO_OUT_L(1140));
++		PRCM_PLL_CTRL_EXT_OSC_EN | PRCM_PLL_CTRL_LDO_OUT_L(1370) );
+ 	clrbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK);
+ 
++	/* Give the PLL LDO voltage setting some time to take hold.
++	 * Notes:
++	 *   1) We need to use sdelay() as the timers aren't set up yet.
++	 *   2) The 100k iterations come from Boot1, which spin's for 100k
++	 *      iterations through a loop.
++	 */
++	sdelay(100000);
++
+ 	clock_set_pll1(408000000);
+ 
+ 	writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg);
+--- a/arch/arm/include/asm/arch-sunxi/prcm.h
++++ b/arch/arm/include/asm/arch-sunxi/prcm.h
+@@ -111,13 +111,13 @@
+ #define PRCM_PLL_CTRL_LDO_OUT_MASK \
+ 	__PRCM_PLL_CTRL_LDO_OUT(0x7)
+ /* When using the low voltage 20 mV steps, and high voltage 30 mV steps */
+-#define PRCM_PLL_CTRL_LDO_OUT_L(n) \
+-	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1000) / 20) & 0x7)
+ #define PRCM_PLL_CTRL_LDO_OUT_H(n) \
++	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1000) / 20) & 0x7)
++#define PRCM_PLL_CTRL_LDO_OUT_L(n) \
+ 	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1160) / 30) & 0x7)
+-#define PRCM_PLL_CTRL_LDO_OUT_LV(n) \
+-	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 20) + 1000)
+ #define PRCM_PLL_CTRL_LDO_OUT_HV(n) \
++	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 20) + 1000)
++#define PRCM_PLL_CTRL_LDO_OUT_LV(n) \
+ 	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 30) + 1160)
+ #define PRCM_PLL_CTRL_LDO_KEY (0xa7 << 24)
+ #define PRCM_PLL_CTRL_LDO_KEY_MASK (0xff << 24)
diff --git a/package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch b/package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch
new file mode 100644
index 0000000000..bf5dc66e1a
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch
@@ -0,0 +1,16 @@
+From d7311b6e7cdd1fc0e92665188e650934718cb2b1 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 16 Jun 2015 10:52:01 +0200
+Subject: sun6i: define alternate-function for UART2 on GPG
+
+
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -180,6 +180,7 @@ enum sunxi_gpio_number {
+ #define SUN6I_GPG_SDC1		2
+ #define SUN8I_GPG_SDC1		2
+ #define SUN6I_GPG_TWI3		2
++#define SUN6I_GPG_UART2         2
+ #define SUN5I_GPG_UART1		4
+ 
+ #define SUN4I_GPH_SDC1		5
diff --git a/package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch b/package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch
new file mode 100644
index 0000000000..087074d0c9
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch
@@ -0,0 +1,30 @@
+From c058dfb69136d62f88ae8b121104bdb7ce2df03f Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 16 Jun 2015 10:53:11 +0200
+Subject: ARM: sun6i: Support console on UART2 (GPG6/GPG7)
+
+
+--- a/arch/arm/cpu/armv7/sunxi/board.c
++++ b/arch/arm/cpu/armv7/sunxi/board.c
+@@ -88,6 +88,10 @@ static int gpio_init(void)
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1);
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1);
+ 	sunxi_gpio_set_pull(SUNXI_GPG(4), SUNXI_GPIO_PULL_UP);
++#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN6I)
++	sunxi_gpio_set_cfgpin(SUNXI_GPG(6), SUN6I_GPG_UART2);
++	sunxi_gpio_set_cfgpin(SUNXI_GPG(7), SUN6I_GPG_UART2);
++	sunxi_gpio_set_pull(SUNXI_GPG(7), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I)
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_GPB_UART2);
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2);
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -260,6 +260,8 @@ extern int soft_i2c_gpio_scl;
+ #endif
+ #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN5I)
+ #define OF_STDOUT_PATH		"/soc@01c00000/serial@01c28400:115200"
++#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN6I)
++#define OF_STDOUT_PATH          "/soc@01c00000/serial@01c28800:115200"
+ #elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I)
+ #define OF_STDOUT_PATH		"/soc@01c00000/serial@01c28800:115200"
+ #elif CONFIG_CONS_INDEX == 5 && defined(CONFIG_MACH_SUN8I)
diff --git a/package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch b/package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch
new file mode 100644
index 0000000000..ee1e3c9bfa
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch
@@ -0,0 +1,23 @@
+From 78d5fab8e345b1273ec8c22d06f1a1d27670b518 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 16 Jun 2015 10:59:38 +0200
+Subject: ARM: sunxi: Make CONS_INDEX configurable
+
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -229,6 +229,14 @@ config SYS_BOARD
+ config SYS_SOC
+ 	default "sunxi"
+ 
++config CONS_INDEX
++        int "UART used for console"
++        range 1 5
++        default 1
++        ---help---
++        Defines the UART port used for serial output. It starts at 1 so UART0 is 1,
++        UART1 is 2 and so on.
++
+ config UART0_PORT_F
+ 	bool "UART0 on MicroSD breakout board"
+ 	default n
diff --git a/package/boot/uboot-sunxi/uEnv-default.txt b/package/boot/uboot-sunxi/uEnv-default.txt
new file mode 100644
index 0000000000..e024954516
--- /dev/null
+++ b/package/boot/uboot-sunxi/uEnv-default.txt
@@ -0,0 +1,6 @@
+setenv fdt_high ffffffff
+setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
+setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
+setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd
diff --git a/package/boot/uboot-sunxi/uEnv-pangolin.txt b/package/boot/uboot-sunxi/uEnv-pangolin.txt
new file mode 100644
index 0000000000..9c4fa11220
--- /dev/null
+++ b/package/boot/uboot-sunxi/uEnv-pangolin.txt
@@ -0,0 +1,6 @@
+setenv fdt_high ffffffff
+setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
+setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
+setenv bootargs console=ttyS2,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd
diff --git a/package/boot/uboot-xburst/Makefile b/package/boot/uboot-xburst/Makefile
new file mode 100644
index 0000000000..967780c3d8
--- /dev/null
+++ b/package/boot/uboot-xburst/Makefile
@@ -0,0 +1,89 @@
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=u-boot
+PKG_VERSION:=2012.10-rc2
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	https://librecmc.org/librecmc/downloads/sources/archive/ \
+
+
+PKG_MD5SUM:=ffd6e3795d221bc43c70bed97c919f70
+PKG_TARGETS:=bin
+
+PKG_LICENSE:=GPL-2.0 GPL-2.0+
+PKG_LICENSE_FILES:=Licenses/README
+
+include $(INCLUDE_DIR)/package.mk
+
+define uboot/Default
+  TITLE:=
+  CONFIG:=
+  IMAGE:=
+endef
+
+define uboot/qi_lb60
+  TITLE:=U-boot for the qi_lb60 board
+endef
+
+UBOOTS:=qi_lb60
+
+define Package/uboot/template
+define Package/uboot-xburst-$(1)
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=@TARGET_xburst
+  TITLE:=$(2)
+  URL:=http://www.denx.de/wiki/UBoot/WebHome
+  VARIANT:=$(1)
+endef
+endef
+
+define BuildUbootPackage
+	$(eval $(uboot/Default))
+	$(eval $(uboot/$(1)))
+	$(call Package/uboot/template,$(1),$(TITLE))
+endef
+
+
+ifdef BUILD_VARIANT
+$(eval $(call uboot/$(BUILD_VARIANT)))
+UBOOT_CONFIG:=$(if $(CONFIG),$(CONFIG),$(BUILD_VARIANT))
+UBOOT_IMAGE:=$(if $(IMAGE),$(IMAGE),openwrt-$(BOARD)-$(BUILD_VARIANT)-u-boot.bin)
+endif
+
+define Build/Configure
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(UBOOT_CONFIG)_config
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE=$(TARGET_CROSS)
+endef
+
+define Package/uboot/install/template
+define Package/uboot-xburst-$(1)/install
+	$(CP) $(PKG_BUILD_DIR)/u-boot-xburst.bin $(BIN_DIR)/$(2)
+	rmdir $$(1)
+endef
+endef
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call Package/uboot/install/template,$(u),openwrt-$(BOARD)-$(u)-u-boot.bin)) \
+)
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call BuildUbootPackage,$(u))) \
+	$(eval $(call BuildPackage,uboot-xburst-$(u))) \
+)
diff --git a/package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch b/package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch
new file mode 100644
index 0000000000..e770243528
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch
@@ -0,0 +1,894 @@
+From 0329cf7965956a5a7044827e0ce88ae8d5150e54 Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Fri, 12 Oct 2012 09:46:58 +0800
+Subject: [PATCH 1/6] qi_lb60: add nand spl support
+
+  The JZ4740 CPU can load 8KB from two different addresses:
+   1. the normal area up to 8KB starting from NAND flash address 0x00000000
+   2. the backup area up to 8KB starting from NAND flash address 0x00002000
+
+Signed-off-by: Xiangfu <xiangfu@openmobilefree.net>
+---
+ Makefile                          |   12 +++
+ arch/mips/cpu/xburst/Makefile     |    7 +-
+ arch/mips/cpu/xburst/cpu.c        |    4 +
+ arch/mips/cpu/xburst/jz4740.c     |   82 +++++++----------
+ arch/mips/cpu/xburst/spl/Makefile |   47 ++++++++++
+ arch/mips/cpu/xburst/spl/start.S  |   63 +++++++++++++
+ board/qi/qi_lb60/Makefile         |    4 +
+ board/qi/qi_lb60/qi_lb60-spl.c    |   30 +++++++
+ board/qi/qi_lb60/qi_lb60.c        |    8 +-
+ board/qi/qi_lb60/u-boot-spl.lds   |   61 +++++++++++++
+ drivers/mtd/nand/jz4740_nand.c    |   39 ++++++++-
+ include/configs/qi_lb60.h         |  175 ++++++++++++++++++-------------------
+ 12 files changed, 386 insertions(+), 146 deletions(-)
+ create mode 100644 arch/mips/cpu/xburst/spl/Makefile
+ create mode 100644 arch/mips/cpu/xburst/spl/start.S
+ create mode 100644 board/qi/qi_lb60/qi_lb60-spl.c
+ create mode 100644 board/qi/qi_lb60/u-boot-spl.lds
+
+diff --git a/Makefile b/Makefile
+index 34d9075..a22778e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -393,6 +393,10 @@ ALL-y += $(obj)u-boot-nodtb-tegra.bin
+ endif
+ endif
+ 
++ifeq ($(CPU),xburst)
++ALL-y += $(obj)u-boot-xburst.bin
++endif
++
+ all:		$(ALL-y) $(SUBDIR_EXAMPLES)
+ 
+ $(obj)u-boot.dtb:	$(obj)u-boot
+@@ -506,6 +510,14 @@ $(obj)u-boot-nodtb-tegra.bin:	$(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
+ endif
+ endif
+ 
++ifeq ($(CPU),xburst)
++$(obj)u-boot-xburst.bin:	$(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
++	        dd if=$(obj)spl/u-boot-spl.bin of=$(obj)spl/u-boot-pad.bin conv=sync bs=8192 count=1
++		dd if=$(obj)spl/u-boot-spl.bin of=$(obj)spl/u-boot-pad.bin conv=sync,notrunc oflag=append bs=8192 count=1
++	        tr '\0' '\377' < /dev/zero | dd of=$(obj)spl/u-boot-pad.bin conv=sync,notrunc oflag=append bs=16384 count=1
++	        cat $(obj)spl/u-boot-pad.bin u-boot.bin > $@
++endif
++
+ ifeq ($(CONFIG_SANDBOX),y)
+ GEN_UBOOT = \
+ 		cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
+diff --git a/arch/mips/cpu/xburst/Makefile b/arch/mips/cpu/xburst/Makefile
+index b1f2ae4..ec35e55 100644
+--- a/arch/mips/cpu/xburst/Makefile
++++ b/arch/mips/cpu/xburst/Makefile
+@@ -24,9 +24,12 @@ include $(TOPDIR)/config.mk
+ 
+ LIB	= $(obj)lib$(CPU).o
+ 
++COBJS-y	= cpu.o jz_serial.o
++
++ifneq ($(CONFIG_SPL_BUILD),y)
+ START	= start.o
+-SOBJS-y	=
+-COBJS-y	= cpu.o timer.o jz_serial.o
++COBJS-y += timer.o
++endif
+ 
+ COBJS-$(CONFIG_JZ4740) += jz4740.o
+ 
+diff --git a/arch/mips/cpu/xburst/cpu.c b/arch/mips/cpu/xburst/cpu.c
+index ddcbfaa..1432838 100644
+--- a/arch/mips/cpu/xburst/cpu.c
++++ b/arch/mips/cpu/xburst/cpu.c
+@@ -42,6 +42,8 @@
+ 		:			\
+ 		: "i" (op), "R" (*(unsigned char *)(addr)))
+ 
++#ifndef CONFIG_SPL_BUILD
++
+ void __attribute__((weak)) _machine_restart(void)
+ {
+ 	struct jz4740_wdt *wdt = (struct jz4740_wdt *)JZ4740_WDT_BASE;
+@@ -109,6 +111,8 @@ void invalidate_dcache_range(ulong start_addr, ulong stop)
+ 		cache_op(Hit_Invalidate_D, addr);
+ }
+ 
++#endif
++
+ void flush_icache_all(void)
+ {
+ 	u32 addr, t = 0;
+diff --git a/arch/mips/cpu/xburst/jz4740.c b/arch/mips/cpu/xburst/jz4740.c
+index c0b9817..8816aa3 100644
+--- a/arch/mips/cpu/xburst/jz4740.c
++++ b/arch/mips/cpu/xburst/jz4740.c
+@@ -32,31 +32,19 @@ int disable_interrupts(void)
+ 	return 0;
+ }
+ 
+-/*
+- * PLL output clock = EXTAL * NF / (NR * NO)
+- * NF = FD + 2, NR = RD + 2
+- * NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3)
+- */
+ void pll_init(void)
+ {
+ 	struct jz4740_cpm *cpm = (struct jz4740_cpm *)JZ4740_CPM_BASE;
+ 
+-	register unsigned int cfcr, plcr1;
+-	int n2FR[33] = {
+-		0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+-		7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+-		9
+-	};
+-	int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */
+-	int nf, pllout2;
++	register unsigned int cfcr, plcr;
++	unsigned int nf, pllout2;
+ 
+ 	cfcr =	CPM_CPCCR_CLKOEN |
+-		CPM_CPCCR_PCS |
+-		(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+-		(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+-		(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+-		(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) |
+-		(n2FR[div[4]] << CPM_CPCCR_LDIV_BIT);
++		(0 << CPM_CPCCR_CDIV_BIT) |
++		(2 << CPM_CPCCR_HDIV_BIT) |
++		(2 << CPM_CPCCR_PDIV_BIT) |
++		(2 << CPM_CPCCR_MDIV_BIT) |
++		(2 << CPM_CPCCR_LDIV_BIT);
+ 
+ 	pllout2 = (cfcr & CPM_CPCCR_PCS) ?
+ 		CONFIG_SYS_CPU_SPEED : (CONFIG_SYS_CPU_SPEED / 2);
+@@ -65,15 +53,18 @@ void pll_init(void)
+ 	writel(pllout2 / 48000000 - 1, &cpm->uhccdr);
+ 
+ 	nf = CONFIG_SYS_CPU_SPEED * 2 / CONFIG_SYS_EXTAL;
+-	plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
++	plcr = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
+ 		(0 << CPM_CPPCR_PLLN_BIT) |	/* RD=0, NR=2 */
+ 		(0 << CPM_CPPCR_PLLOD_BIT) |	/* OD=0, NO=1 */
+-		(0x20 << CPM_CPPCR_PLLST_BIT) |	/* PLL stable time */
++		(0x32 << CPM_CPPCR_PLLST_BIT) |	/* PLL stable time */
+ 		CPM_CPPCR_PLLEN;		/* enable PLL */
+ 
+ 	/* init PLL */
+ 	writel(cfcr, &cpm->cpccr);
+-	writel(plcr1, &cpm->cppcr);
++	writel(plcr, &cpm->cppcr);
++
++	while (!(readl(&cpm->cppcr) & CPM_CPPCR_PLLS))
++		;
+ }
+ 
+ void sdram_init(void)
+@@ -92,26 +83,12 @@ void sdram_init(void)
+ 		2 << EMC_DMCR_TCL_BIT	/* CAS latency is 3 */
+ 	};
+ 
+-	int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+-
+ 	cpu_clk = CONFIG_SYS_CPU_SPEED;
+-	mem_clk = cpu_clk * div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()];
++	mem_clk = 84000000;
+ 
+ 	writel(0, &emc->bcr);	/* Disable bus release */
+ 	writew(0, &emc->rtcsr);	/* Disable clock for counting */
+ 
+-	/* Fault DMCR value for mode register setting*/
+-#define SDRAM_ROW0	11
+-#define SDRAM_COL0	8
+-#define SDRAM_BANK40	0
+-
+-	dmcr0 = ((SDRAM_ROW0 - 11) << EMC_DMCR_RA_BIT) |
+-		((SDRAM_COL0 - 8) << EMC_DMCR_CA_BIT) |
+-		(SDRAM_BANK40 << EMC_DMCR_BA_BIT) |
+-		(SDRAM_BW16 << EMC_DMCR_BW_BIT) |
+-		EMC_DMCR_EPIN |
+-		cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+-
+ 	/* Basic DMCR value */
+ 	dmcr = ((SDRAM_ROW - 11) << EMC_DMCR_RA_BIT) |
+ 		((SDRAM_COL - 8) << EMC_DMCR_CA_BIT) |
+@@ -128,31 +105,31 @@ void sdram_init(void)
+ 	if (tmp > 11)
+ 		tmp = 11;
+ 	dmcr |= (tmp - 4) << EMC_DMCR_TRAS_BIT;
+-	tmp = SDRAM_RCD / ns;
+ 
++	tmp = SDRAM_RCD / ns;
+ 	if (tmp > 3)
+ 		tmp = 3;
+ 	dmcr |= tmp << EMC_DMCR_RCD_BIT;
+-	tmp = SDRAM_TPC / ns;
+ 
++	tmp = SDRAM_TPC / ns;
+ 	if (tmp > 7)
+ 		tmp = 7;
+ 	dmcr |= tmp << EMC_DMCR_TPC_BIT;
+-	tmp = SDRAM_TRWL / ns;
+ 
++	tmp = SDRAM_TRWL / ns;
+ 	if (tmp > 3)
+ 		tmp = 3;
+ 	dmcr |= tmp << EMC_DMCR_TRWL_BIT;
+-	tmp = (SDRAM_TRAS + SDRAM_TPC) / ns;
+ 
++	tmp = (SDRAM_TRAS + SDRAM_TPC) / ns;
+ 	if (tmp > 14)
+ 		tmp = 14;
+ 	dmcr |= ((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT;
+ 
+ 	/* SDRAM mode value */
+-	sdmode = EMC_SDMR_BT_SEQ |
+-		 EMC_SDMR_OM_NORMAL |
+-		 EMC_SDMR_BL_4 |
++	sdmode = EMC_SDMR_BT_SEQ	|
++		 EMC_SDMR_OM_NORMAL	|
++		 EMC_SDMR_BL_4		|
+ 		 cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
+ 
+ 	/* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */
+@@ -172,8 +149,8 @@ void sdram_init(void)
+ 	if (tmp > 0xff)
+ 		tmp = 0xff;
+ 	writew(tmp, &emc->rtcor);
++
+ 	writew(0, &emc->rtcnt);
+-	/* Divisor is 64, CKO/64 */
+ 	writew(EMC_RTCSR_CKS_64, &emc->rtcsr);
+ 
+ 	/* Wait for number of auto-refresh cycles */
+@@ -182,13 +159,17 @@ void sdram_init(void)
+ 		;
+ 
+ 	/* Stage 3. Mode Register Set */
++	dmcr0 = (11 << EMC_DMCR_RA_BIT)	|
++		(8 << EMC_DMCR_CA_BIT)	|
++		(0 << EMC_DMCR_BA_BIT)	|
++		EMC_DMCR_EPIN		|
++		(SDRAM_BW16 << EMC_DMCR_BW_BIT) |
++		cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+ 	writel(dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET, &emc->dmcr);
+ 	writeb(0, JZ4740_EMC_SDMR0 | sdmode);
+ 
+ 	/* Set back to basic DMCR value */
+ 	writel(dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET, &emc->dmcr);
+-
+-	/* everything is ok now */
+ }
+ 
+ DECLARE_GLOBAL_DATA_PTR;
+@@ -232,9 +213,10 @@ void rtc_init(void)
+ phys_size_t initdram(int board_type)
+ {
+ 	struct jz4740_emc *emc = (struct jz4740_emc *)JZ4740_EMC_BASE;
+-	u32 dmcr;
+-	u32 rows, cols, dw, banks;
+-	ulong size;
++
++	unsigned int dmcr;
++	unsigned int rows, cols, dw, banks;
++	unsigned long size;
+ 
+ 	dmcr = readl(&emc->dmcr);
+ 	rows = 11 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT);
+diff --git a/arch/mips/cpu/xburst/spl/Makefile b/arch/mips/cpu/xburst/spl/Makefile
+new file mode 100644
+index 0000000..f45e8c8
+--- /dev/null
++++ b/arch/mips/cpu/xburst/spl/Makefile
+@@ -0,0 +1,47 @@
++#
++# Copyright (C) 2011 Xiangfu Liu <xiangfu@openmobilefree.net>
++#
++# See file CREDITS for list of people who contributed to this
++# project.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++# MA 02111-1307 USA
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(CPU).o
++
++START	= start.o
++SOBJS-y	=
++COBJS-y	=
++
++SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
++OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
++START	:= $(addprefix $(obj),$(START))
++
++all:	$(obj).depend $(START) $(LIB)
++
++$(LIB):	$(OBJS)
++	$(call cmd_link_o_target, $(OBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+diff --git a/arch/mips/cpu/xburst/spl/start.S b/arch/mips/cpu/xburst/spl/start.S
+new file mode 100644
+index 0000000..e31c4c8
+--- /dev/null
++++ b/arch/mips/cpu/xburst/spl/start.S
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (c) 2010 Xiangfu Liu <xiangfu@openmobilefree.net>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 3 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <config.h>
++#include <version.h>
++#include <asm/regdef.h>
++#include <asm/mipsregs.h>
++#include <asm/addrspace.h>
++#include <asm/cacheops.h>
++
++#include <asm/jz4740.h>
++
++	.set noreorder
++
++	.globl _start
++	.text
++_start:
++	.word JZ4740_NANDBOOT_CFG /* fetched during NAND Boot */
++reset:
++	/*
++	 * STATUS register
++	 * CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1
++	 */
++	li	t0, 0x0040FC04
++	mtc0	t0, CP0_STATUS
++	/*
++	 * CAUSE register
++	 * IV=1, use the specical interrupt vector (0x200)
++	 */
++	li	t1, 0x00800000
++	mtc0	t1, CP0_CAUSE
++
++	bal     1f
++	 nop
++	.word   _GLOBAL_OFFSET_TABLE_
++1:
++	move    gp, ra
++	lw      t1, 0(ra)
++	move	gp, t1
++
++	la	sp, 0x80004000
++	la	t9, nand_spl_boot
++	j	t9
++	nop
+diff --git a/board/qi/qi_lb60/Makefile b/board/qi/qi_lb60/Makefile
+index 5dae11b..e399246 100644
+--- a/board/qi/qi_lb60/Makefile
++++ b/board/qi/qi_lb60/Makefile
+@@ -22,7 +22,11 @@ include $(TOPDIR)/config.mk
+ 
+ LIB	= $(obj)lib$(BOARD).o
+ 
++ifeq ($(CONFIG_SPL_BUILD),y)
++COBJS	:= $(BOARD)-spl.o
++else
+ COBJS	:= $(BOARD).o
++endif
+ 
+ SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+ OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+diff --git a/board/qi/qi_lb60/qi_lb60-spl.c b/board/qi/qi_lb60/qi_lb60-spl.c
+new file mode 100644
+index 0000000..3fe3fa3
+--- /dev/null
++++ b/board/qi/qi_lb60/qi_lb60-spl.c
+@@ -0,0 +1,30 @@
++/*
++ * Authors: Xiangfu Liu <xiangfu@openmobilefree.cc>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 3 of the License, or (at your option) any later version.
++ */
++
++#include <common.h>
++#include <nand.h>
++#include <asm/io.h>
++#include <asm/jz4740.h>
++
++void nand_spl_boot(void)
++{
++	__gpio_as_sdram_16bit_4720();
++	__gpio_as_uart0();
++	__gpio_jtag_to_uart0();
++
++	serial_init();
++
++	pll_init();
++	sdram_init();
++
++	nand_init();
++
++	puts("\nQi LB60 SPL: Starting U-Boot ...\n");
++	nand_boot();
++}
+diff --git a/board/qi/qi_lb60/qi_lb60.c b/board/qi/qi_lb60/qi_lb60.c
+index d975209..3bd4e2f 100644
+--- a/board/qi/qi_lb60/qi_lb60.c
++++ b/board/qi/qi_lb60/qi_lb60.c
+@@ -1,5 +1,5 @@
+ /*
+- * Authors: Xiangfu Liu <xiangfu@sharism.cc>
++ * Authors: Xiangfu Liu <xiangfu@openmobilefree.net>
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -97,8 +97,10 @@ int board_early_init_f(void)
+ /* U-Boot common routines */
+ int checkboard(void)
+ {
+-	printf("Board: Qi LB60 (Ingenic XBurst Jz4740 SoC, Speed %ld MHz)\n",
+-	       gd->cpu_clk / 1000000);
++	printf("Board: Qi LB60 (Ingenic XBurst Jz4740 SoC)\n");
++	printf(" CPU: %ld\n", gd->cpu_clk);
++	printf(" MEM: %ld\n", gd->mem_clk);
++	printf(" DEV: %ld\n", gd->dev_clk);
+ 
+ 	return 0;
+ }
+diff --git a/board/qi/qi_lb60/u-boot-spl.lds b/board/qi/qi_lb60/u-boot-spl.lds
+new file mode 100644
+index 0000000..930537f
+--- /dev/null
++++ b/board/qi/qi_lb60/u-boot-spl.lds
+@@ -0,0 +1,61 @@
++/*
++ * (C) Copyright 2012 Xiangfu Liu <xiangfu@openmobilefree.net>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradlittlemips", "elf32-tradlittlemips")
++
++OUTPUT_ARCH(mips)
++ENTRY(_start)
++SECTIONS
++{
++	. = 0x80000000;
++	. = ALIGN(4);
++	.text :
++	{
++	  *(.text)
++	}
++
++	. = ALIGN(4);
++	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
++
++	. = ALIGN(4);
++	.data  : { *(.data) }
++
++	. = ALIGN(4);
++	.sdata  : { *(.sdata) }
++
++	_gp = ALIGN(16);
++
++	__got_start = .;
++	.got  : { *(.got) }
++	__got_end = .;
++
++	. = .;
++	__u_boot_cmd_start = .;
++	.u_boot_cmd : { *(.u_boot_cmd) }
++	__u_boot_cmd_end = .;
++
++	uboot_end_data = .;
++	num_got_entries = (__got_end - __got_start) >> 2;
++
++	. = ALIGN(4);
++	.sbss  : { *(.sbss) }
++	.bss  : { *(.bss) }
++	uboot_end = .;
++}
++ASSERT(uboot_end <= 0x80002000, "NAND bootstrap too big");
+diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
+index 3ec34f3..24a4921 100644
+--- a/drivers/mtd/nand/jz4740_nand.c
++++ b/drivers/mtd/nand/jz4740_nand.c
+@@ -15,6 +15,9 @@
+ #include <asm/io.h>
+ #include <asm/jz4740.h>
+ 
++#ifdef CONFIG_SPL_BUILD
++#define printf(s) puts(s)
++#endif
+ #define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000)
+ #define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
+ #define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000)
+@@ -176,7 +179,7 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ 		for (k = 0; k < 9; k++)
+ 			writeb(read_ecc[k], &emc->nfpar[k]);
+ 	}
+-	/* Set PRDY */
++
+ 	writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr);
+ 
+ 	/* Wait for completion */
+@@ -184,7 +187,7 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ 		status = readl(&emc->nfints);
+ 	} while (!(status & EMC_NFINTS_DECF));
+ 
+-	/* disable ecc */
++	/* Disable ECC */
+ 	writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr);
+ 
+ 	/* Check decoding */
+@@ -192,7 +195,7 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ 		return 0;
+ 
+ 	if (status & EMC_NFINTS_UNCOR) {
+-		printf("uncorrectable ecc\n");
++		printf("JZ4740 uncorrectable ECC\n");
+ 		return -1;
+ 	}
+ 
+@@ -230,6 +233,32 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ 	return errcnt;
+ }
+ 
++#ifdef CONFIG_SPL_BUILD
++static void jz_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++	int i;
++	struct nand_chip *this = mtd->priv;
++
++#if (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R3) || \
++	(JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R2)
++	for (i = 0; i < len; i += 2)
++		buf[i] = readw(this->IO_ADDR_R);
++#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R3) || \
++	(JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R2)
++	for (i = 0; i < len; i++)
++		buf[i] = readb(this->IO_ADDR_R);
++#else
++	#error JZ4740_NANDBOOT_CFG not defined or wrong
++#endif
++}
++
++static uint8_t jz_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd->priv;
++	return readb(this->IO_ADDR_R);
++}
++#endif
++
+ /*
+  * Main initialization routine
+  */
+@@ -254,6 +283,10 @@ int board_nand_init(struct nand_chip *nand)
+ 	nand->ecc.size		= CONFIG_SYS_NAND_ECCSIZE;
+ 	nand->ecc.bytes		= CONFIG_SYS_NAND_ECCBYTES;
+ 	nand->ecc.layout	= &qi_lb60_ecclayout_2gb;
++#ifdef CONFIG_SPL_BUILD
++	nand->read_byte		= jz_nand_read_byte;
++	nand->read_buf		= jz_nand_read_buf;
++#endif
+ 	nand->chip_delay	= 50;
+ 	nand->options		= NAND_USE_FLASH_BBT;
+ 
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 4bb5bbc..7bff444 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -1,5 +1,5 @@
+ /*
+- * Authors: Xiangfu Liu <xiangfu.z@gmail.com>
++ * Authors: Xiangfu Liu <xiangfu@openmobilefree.net>
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -14,7 +14,6 @@
+ #define CONFIG_SYS_LITTLE_ENDIAN
+ #define CONFIG_JZSOC		/* Jz SoC */
+ #define CONFIG_JZ4740		/* Jz4740 SoC */
+-#define CONFIG_NAND_JZ4740
+ 
+ #define CONFIG_SYS_CPU_SPEED	336000000	/* CPU clock: 336 MHz */
+ #define CONFIG_SYS_EXTAL	12000000	/* EXTAL freq: 12 MHz */
+@@ -24,24 +23,43 @@
+ #define CONFIG_SYS_UART_BASE	JZ4740_UART0_BASE /* Base of the UART channel */
+ #define CONFIG_BAUDRATE		57600
+ 
++#define CONFIG_BOOTP_MASK	(CONFIG_BOOTP_DEFAUL)
++#define CONFIG_BOOTDELAY	0
++#define CONFIG_BOOTARGS "mem=32M console=tty0 console=ttyS0,57600n8 ubi.mtd=2 rootfstype=ubifs root=ubi0:rootfs rw rootwait"
++#define CONFIG_BOOTCOMMAND	"nand read 0x80600000 0x400000 0x280000;bootm"
++
++/*
++ * Miscellaneous configurable options
++ */
++#define CONFIG_SYS_SDRAM_BASE		0x80000000	/* Cached addr */
++#define CONFIG_SYS_INIT_SP_OFFSET	0x400000
++#define CONFIG_SYS_LOAD_ADDR		0x80600000
++#define CONFIG_SYS_MEMTEST_START	0x80100000
++#define CONFIG_SYS_MEMTEST_END		0x80A00000
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
++
++#define CONFIG_SYS_MALLOC_LEN		(4 * 1024 * 1024)
++#define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
++
++#define CONFIG_SYS_CBSIZE	256 /* Console I/O Buffer Size */
++#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
++
++#define CONFIG_SYS_LONGHELP
++#define CONFIG_SYS_MAXARGS	16
++#define CONFIG_SYS_PROMPT	"NanoNote# "
++
+ #define CONFIG_SKIP_LOWLEVEL_INIT
+ #define CONFIG_BOARD_EARLY_INIT_F
+ #define CONFIG_SYS_NO_FLASH
+ #define CONFIG_SYS_FLASH_BASE	0 /* init flash_base as 0 */
+-#define CONFIG_ENV_OVERWRITE
+-
+-#define CONFIG_BOOTP_MASK	(CONFIG_BOOTP_DEFAUL)
+-#define CONFIG_BOOTDELAY	0
+-#define CONFIG_BOOTARGS		"mem=32M console=tty0 console=ttyS0,57600n8 ubi.mtd=2 rootfstype=ubifs root=ubi0:rootfs rw rootwait"
+-#define CONFIG_BOOTCOMMAND	"nand read 0x80600000 0x400000 0x200000;bootm"
+ 
+ /*
+- * Command line configuration.
++ * Command line configuration
+  */
+ #define CONFIG_CMD_BOOTD	/* bootd			*/
+ #define CONFIG_CMD_CONSOLE	/* coninfo			*/
+ #define CONFIG_CMD_ECHO		/* echo arguments		*/
+-
+ #define CONFIG_CMD_LOADB	/* loadb			*/
+ #define CONFIG_CMD_LOADS	/* loads			*/
+ #define CONFIG_CMD_MEMORY	/* md mm nm mw cp cmp crc base loop mtest */
+@@ -58,45 +76,16 @@
+ #define CONFIG_LOADS_ECHO	1	/* echo on for serial download */
+ 
+ /*
+- * Miscellaneous configurable options
+- */
+-#define CONFIG_SYS_MAXARGS 16
+-#define CONFIG_SYS_LONGHELP
+-#define CONFIG_SYS_PROMPT "NanoNote# "
+-#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */
+-#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+-
+-#define CONFIG_SYS_MALLOC_LEN		(4 * 1024 * 1024)
+-#define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
+-
+-#define CONFIG_SYS_SDRAM_BASE		0x80000000	/* Cached addr */
+-#define CONFIG_SYS_INIT_SP_OFFSET	0x400000
+-#define CONFIG_SYS_LOAD_ADDR		0x80600000
+-#define CONFIG_SYS_MEMTEST_START	0x80100000
+-#define CONFIG_SYS_MEMTEST_END		0x80800000
+-
+-/*
+- * Environment
++ * NAND driver configuration
+  */
+-#define CONFIG_ENV_IS_IN_NAND		/* use NAND for environment vars */
+-
+-#define CONFIG_SYS_NAND_5_ADDR_CYCLE
+-/*
+- * if board nand flash is 1GB, set to 1
+- * if board nand flash is 2GB, set to 2
+- * for change the PAGE_SIZE and BLOCK_SIZE
+- * will delete when there is no 1GB flash
+- */
+-#define NANONOTE_NAND_SIZE	2
+-
+-#define CONFIG_SYS_NAND_PAGE_SIZE	(2048 * NANONOTE_NAND_SIZE)
+-#define CONFIG_SYS_NAND_BLOCK_SIZE	(256 * NANONOTE_NAND_SIZE << 10)
+-/* nand bad block was marked at this page in a block, start from 0 */
++#define CONFIG_NAND_JZ4740
++#define CONFIG_SYS_NAND_PAGE_SIZE	4096
++#define CONFIG_SYS_NAND_BLOCK_SIZE	(512 << 10)
++/* NAND bad block was marked at this page in a block, start from 0 */
+ #define CONFIG_SYS_NAND_BADBLOCK_PAGE	127
+ #define CONFIG_SYS_NAND_PAGE_COUNT	128
+ #define CONFIG_SYS_NAND_BAD_BLOCK_POS	0
+-/* ECC offset position in oob area, default value is 6 if it isn't defined */
+-#define CONFIG_SYS_NAND_ECC_POS		(6 * NANONOTE_NAND_SIZE)
++#define CONFIG_SYS_NAND_ECC_POS		12
+ #define CONFIG_SYS_NAND_ECCSIZE		512
+ #define CONFIG_SYS_NAND_ECCBYTES	9
+ #define CONFIG_SYS_NAND_ECCPOS		\
+@@ -115,10 +104,9 @@
+ #define CONFIG_SYS_ONENAND_BASE		CONFIG_SYS_NAND_BASE
+ #define CONFIG_SYS_MAX_NAND_DEVICE	1
+ #define CONFIG_SYS_NAND_SELECT_DEVICE	1 /* nand driver supports mutipl.*/
+-#define CONFIG_NAND_SPL_TEXT_BASE	0x80000000
+ 
+ /*
+- * IPL (Initial Program Loader, integrated inside CPU)
++ * IPL (Initial Program Loader, integrated inside Ingenic Xburst JZ4740 CPU)
+  * Will load first 8k from NAND (SPL) into cache and execute it from there.
+  *
+  * SPL (Secondary Program Loader)
+@@ -130,77 +118,88 @@
+  * NUB (NAND U-Boot)
+  * This NAND U-Boot (NUB) is a special U-Boot version which can be started
+  * from RAM. Therefore it mustn't (re-)configure the SDRAM controller.
+- *
+  */
++
++/*
++ * NAND SPL configuration
++ */
++#define CONFIG_SPL
++#define CONFIG_SPL_LIBGENERIC_SUPPORT
++#define CONFIG_SPL_LIBCOMMON_SUPPORT
++#define CONFIG_SPL_NAND_LOAD
++#define CONFIG_SPL_NAND_SIMPLE
++#define CONFIG_SPL_NAND_SUPPORT
++#define CONFIG_SPL_TEXT_BASE	0x80000000
++#define CONFIG_SPL_START_S_PATH	"arch/mips/cpu/xburst/spl"
++
++#define CONFIG_SYS_NAND_5_ADDR_CYCLE
++#define CONFIG_SYS_NAND_HW_ECC_OOBFIRST
++#define JZ4740_NANDBOOT_CFG		JZ4740_NANDBOOT_B8R3
++
+ #define CONFIG_SYS_NAND_U_BOOT_DST	0x80100000 /* Load NUB to this addr */
+ #define CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_NAND_U_BOOT_DST
+-/* Start NUB from this addr*/
++					/* Start NUB from this addr */
++#define CONFIG_SYS_NAND_U_BOOT_OFFS (32  << 10) /* Offset of NUB */
++#define CONFIG_SYS_NAND_U_BOOT_SIZE (256 << 10) /* Size of NUB */
+ 
+ /*
+- * Define the partitioning of the NAND chip (only RAM U-Boot is needed here)
++ * Environment configuration
+  */
+-#define CONFIG_SYS_NAND_U_BOOT_OFFS (256 << 10) /* Offset to RAM U-Boot image */
+-#define CONFIG_SYS_NAND_U_BOOT_SIZE (512 << 10) /* Size of RAM U-Boot image */
+-
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_IS_IN_NAND
+ #define CONFIG_ENV_SIZE		(4 << 10)
+ #define CONFIG_ENV_OFFSET	\
+ 	(CONFIG_SYS_NAND_BLOCK_SIZE + CONFIG_SYS_NAND_U_BOOT_SIZE)
+ #define CONFIG_ENV_OFFSET_REDUND \
+ 	(CONFIG_ENV_OFFSET  + CONFIG_SYS_NAND_BLOCK_SIZE)
+ 
+-#define CONFIG_SYS_TEXT_BASE	0x80100000
+-#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_TEXT_BASE
+-
+ /*
+- * SDRAM Info.
++ * CPU cache configuration
+  */
+-#define CONFIG_NR_DRAM_BANKS	1
++#define CONFIG_SYS_DCACHE_SIZE		16384
++#define CONFIG_SYS_ICACHE_SIZE		16384
++#define CONFIG_SYS_CACHELINE_SIZE	32
+ 
+ /*
+- * Cache Configuration
++ * SDRAM configuration
+  */
+-#define CONFIG_SYS_DCACHE_SIZE	16384
+-#define CONFIG_SYS_ICACHE_SIZE	16384
+-#define CONFIG_SYS_CACHELINE_SIZE	32
++#define CONFIG_NR_DRAM_BANKS	1
++
++#define SDRAM_BW16		1	/* Data bus width: 0-32bit, 1-16bit */
++#define SDRAM_BANK4		1	/* Banks each chip: 0-2bank, 1-4bank */
++#define SDRAM_ROW		13	/* Row address: 11 to 13 */
++#define SDRAM_COL		9	/* Column address: 8 to 12 */
++#define SDRAM_CASL		2	/* CAS latency: 2 or 3 */
++#define SDRAM_TRAS		45	/* RAS# Active Time */
++#define SDRAM_RCD		20	/* RAS# to CAS# Delay */
++#define SDRAM_TPC		20	/* RAS# Precharge Time */
++#define SDRAM_TRWL		7	/* Write Latency Time */
++#define SDRAM_TREF		15625	/* Refresh period: 8192 cycles/64ms */
+ 
+ /*
+- * GPIO definition
++ * GPIO configuration
+  */
+-#define GPIO_LCD_CS	(2 * 32 + 21)
+-#define GPIO_AMP_EN	(3 * 32 + 4)
++#define GPIO_LCD_CS		(2 * 32 + 21)
++#define GPIO_AMP_EN		(3 * 32 + 4)
+ 
+-#define GPIO_SDPW_EN	(3 * 32 + 2)
+-#define GPIO_SD_DETECT	(3 * 32 + 0)
++#define GPIO_SDPW_EN		(3 * 32 + 2)
++#define GPIO_SD_DETECT		(3 * 32 + 0)
+ 
+-#define GPIO_BUZZ_PWM	(3 * 32 + 27)
+-#define GPIO_USB_DETECT	(3 * 32 + 28)
++#define GPIO_BUZZ_PWM		(3 * 32 + 27)
++#define GPIO_USB_DETECT		(3 * 32 + 28)
+ 
+-#define GPIO_AUDIO_POP	(1 * 32 + 29)
+-#define GPIO_COB_TEST	(1 * 32 + 30)
++#define GPIO_AUDIO_POP		(1 * 32 + 29)
++#define GPIO_COB_TEST		(1 * 32 + 30)
+ 
+ #define GPIO_KEYOUT_BASE	(2 * 32 + 10)
+-#define GPIO_KEYIN_BASE	(3 * 32 + 18)
+-#define GPIO_KEYIN_8	(3 * 32 + 26)
++#define GPIO_KEYIN_BASE		(3 * 32 + 18)
++#define GPIO_KEYIN_8		(3 * 32 + 26)
+ 
+-#define GPIO_SD_CD_N	GPIO_SD_DETECT		/* SD Card insert detect */
++#define GPIO_SD_CD_N		GPIO_SD_DETECT	/* SD Card insert detect */
+ #define GPIO_SD_VCC_EN_N	GPIO_SDPW_EN	/* SD Card Power Enable */
+ 
+ #define SPEN	GPIO_LCD_CS	/* LCDCS :Serial command enable      */
+ #define SPDA	(2 * 32 + 22)	/* LCDSCL:Serial command clock input */
+ #define SPCK	(2 * 32 + 23)	/* LCDSDA:Serial command data input  */
+ 
+-/* SDRAM paramters */
+-#define SDRAM_BW16		1	/* Data bus width: 0-32bit, 1-16bit */
+-#define SDRAM_BANK4		1	/* Banks each chip: 0-2bank, 1-4bank */
+-#define SDRAM_ROW		13	/* Row address: 11 to 13 */
+-#define SDRAM_COL		9	/* Column address: 8 to 12 */
+-#define SDRAM_CASL		2	/* CAS latency: 2 or 3 */
+-
+-/* SDRAM Timings, unit: ns */
+-#define SDRAM_TRAS		45	/* RAS# Active Time */
+-#define SDRAM_RCD		20	/* RAS# to CAS# Delay */
+-#define SDRAM_TPC		20	/* RAS# Precharge Time */
+-#define SDRAM_TRWL		7	/* Write Latency Time */
+-#define SDRAM_TREF		15625	/* Refresh period: 8192 cycles/64ms */
+-
+ #endif
+-- 
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch b/package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch
new file mode 100644
index 0000000000..feaf297b7c
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch
@@ -0,0 +1,916 @@
+From fa51192b912d296b8eec10f7d44c6c17eb1dd368 Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Fri, 12 Oct 2012 09:47:39 +0800
+Subject: [PATCH 2/6] qi_lb60: add software usbboot support
+
+  JZ4740 CPU have a internal ROM have such kind of code, that make
+  JZ4740 can boot from USB
+
+  usbboot.S can downloads user program from the USB port to internal
+  SRAM and branches to the internal SRAM to execute the program
+
+Signed-off-by: Xiangfu <xiangfu@openmobilefree.net>
+---
+ board/qi/qi_lb60/Makefile      |    1 +
+ board/qi/qi_lb60/qi_lb60-spl.c |   20 +
+ board/qi/qi_lb60/usbboot.S     |  838 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 859 insertions(+)
+ create mode 100644 board/qi/qi_lb60/usbboot.S
+
+diff --git a/board/qi/qi_lb60/Makefile b/board/qi/qi_lb60/Makefile
+index e399246..6dd8c6f 100644
+--- a/board/qi/qi_lb60/Makefile
++++ b/board/qi/qi_lb60/Makefile
+@@ -23,6 +23,7 @@ include $(TOPDIR)/config.mk
+ LIB	= $(obj)lib$(BOARD).o
+ 
+ ifeq ($(CONFIG_SPL_BUILD),y)
++SOBJS	:= usbboot.o
+ COBJS	:= $(BOARD)-spl.o
+ else
+ COBJS	:= $(BOARD).o
+diff --git a/board/qi/qi_lb60/qi_lb60-spl.c b/board/qi/qi_lb60/qi_lb60-spl.c
+index 3fe3fa3..aea459c 100644
+--- a/board/qi/qi_lb60/qi_lb60-spl.c
++++ b/board/qi/qi_lb60/qi_lb60-spl.c
+@@ -12,6 +12,24 @@
+ #include <asm/io.h>
+ #include <asm/jz4740.h>
+ 
++#define KEY_U_OUT       (32 * 2 + 16)
++#define KEY_U_IN        (32 * 3 + 19)
++
++extern void usb_boot(void);
++
++static void check_usb_boot(void)
++{
++	__gpio_as_input(KEY_U_IN);
++	__gpio_enable_pull(KEY_U_IN);
++	__gpio_as_output(KEY_U_OUT);
++	__gpio_clear_pin(KEY_U_OUT);
++
++	if (!__gpio_get_pin(KEY_U_IN)) {
++		puts("[U] pressed, goto USBBOOT mode\n");
++		usb_boot();
++	}
++}
++
+ void nand_spl_boot(void)
+ {
+ 	__gpio_as_sdram_16bit_4720();
+@@ -23,6 +41,8 @@ void nand_spl_boot(void)
+ 	pll_init();
+ 	sdram_init();
+ 
++	check_usb_boot();
++
+ 	nand_init();
+ 
+ 	puts("\nQi LB60 SPL: Starting U-Boot ...\n");
+diff --git a/board/qi/qi_lb60/usbboot.S b/board/qi/qi_lb60/usbboot.S
+new file mode 100644
+index 0000000..c872266
+--- /dev/null
++++ b/board/qi/qi_lb60/usbboot.S
+@@ -0,0 +1,838 @@
++/*
++ *  for jz4740 usb boot
++ *
++ *  Copyright (c) 2009 Author: <jlwei@ingenic.cn>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++    .set noreorder
++    .globl usb_boot
++    .text
++
++/*
++ * Both NAND and USB boot load data to D-Cache first, then transfer
++ * data from D-Cache to I-Cache, and jump to execute the code in I-Cache.
++ * So init caches first and then dispatch to a proper boot routine.
++ */
++
++.macro load_addr reg addr
++	li \reg, 0x80000000
++	addiu \reg, \reg, \addr
++	la $2, usbboot_begin
++	subu \reg, \reg, $2
++.endm
++
++usb_boot:
++	/* Initialize PLL: set ICLK to 84MHz and HCLK to 42MHz. */
++	la	$9, 0xB0000000		/* CPCCR: Clock Control Register */
++	la	$8, 0x42041110		/* I:S:M:P=1:2:2:2 */
++	sw	$8, 0($9)
++
++	la	$9, 0xB0000010		/* CPPCR: PLL Control Register */
++	la	$8, 0x06000120		/* M=12 N=0 D=0 CLK=12*(M+2)/(N+2) */
++	sw	$8, 0($9)
++
++	mtc0	$0, $26		/* CP0_ERRCTL, restore WST reset state */
++	nop
++
++	mtc0	$0, $16			/* CP0_CONFIG */
++	nop
++
++	/* Relocate code to beginning of the ram */
++
++	la $2, usbboot_begin
++	la $3, usbboot_end
++	li $4, 0x80000000
++
++1:
++	lw $5, 0($2)
++	sw $5, 0($4)
++	addiu $2, $2, 4
++	bne $2, $3, 1b
++	addiu $4, $4, 4
++
++	li $2, 0x80000000
++	ori $3, $2, 0
++	addiu $3, $3, usbboot_end
++	la $4, usbboot_begin
++	subu $3, $3, $4
++
++
++2:
++	cache	0x0, 0($2)		/* Index_Invalidate_I */
++	cache	0x1, 0($2)		/* Index_Writeback_Inv_D */
++	addiu	$2, $2, 32
++	subu $4, $3, $2
++	bgtz	$4, 2b
++	nop
++
++	load_addr $3, usb_boot_return
++
++	jr $3
++
++usbboot_begin:
++
++init_caches:
++	li	$2, 3			/* cacheable for kseg0 access */
++	mtc0	$2, $16			/* CP0_CONFIG */
++	nop
++
++	li	$2, 0x20000000		/* enable idx-store-data cache insn */
++	mtc0	$2, $26			/* CP0_ERRCTL */
++
++	ori	$2, $28, 0		/* start address */
++	ori	$3, $2, 0x3fe0		/* end address, total 16KB */
++	mtc0	$0, $28, 0		/* CP0_TAGLO */
++	mtc0	$0, $28, 1		/* CP0_DATALO */
++cache_clear_a_line:
++	cache	0x8, 0($2)		/* Index_Store_Tag_I */
++	cache	0x9, 0($2)		/* Index_Store_Tag_D */
++	bne	$2, $3, cache_clear_a_line
++	addiu	$2, $2, 32		/* increment CACHE_LINE_SIZE */
++
++	ori	$2, $28, 0		/* start address */
++	ori	$3, $2, 0x3fe0		/* end address, total 16KB */
++	la	$4, 0x1ffff000		/* physical address and 4KB page mask */
++cache_alloc_a_line:
++	and	$5, $2, $4
++	ori	$5, $5, 1		/* V bit of the physical tag */
++	mtc0	$5, $28, 0		/* CP0_TAGLO */
++	cache	0x8, 0($2)		/* Index_Store_Tag_I */
++	cache	0x9, 0($2)		/* Index_Store_Tag_D */
++	bne	$2, $3, cache_alloc_a_line
++	addiu	$2, $2, 32		/* increment CACHE_LINE_SIZE */
++
++	nop
++	nop
++	nop
++	/*
++	 * Transfer data from dcache to icache, then jump to icache.
++	 * Input parameters:
++	 * $19: data length in bytes
++	 * $20: jump target address
++	 */
++xfer_d2i:
++
++	ori	$8, $20, 0
++	addu	$9, $8, $19		/* total 16KB */
++
++1:
++	cache	0x0, 0($8)		/* Index_Invalidate_I */
++	cache	0x1, 0($8)		/* Index_Writeback_Inv_D */
++	bne	$8, $9, 1b
++	addiu	$8, $8, 32
++
++	/* flush write-buffer */
++	sync
++
++	/* Invalidate BTB */
++	mfc0	$8, $16, 7		/* CP0_CONFIG */
++	nop
++	ori	$8, 2
++	mtc0	$8, $16, 7
++	nop
++
++	/* Overwrite config to disable ram initalisation */
++	li $2, 0xff
++	sb $2, 20($20)
++
++	jalr	$20
++	nop
++
++icache_return:
++	/* User code can return to here after executing itself in
++	  icache, by jumping to $31. */
++	b	usb_boot_return
++	nop
++
++
++usb_boot_return:
++	/* Enable the USB PHY */
++	la	$9, 0xB0000024		/* CPM_SCR */
++	lw	$8, 0($9)
++	ori	$8, 0x40		/* USBPHY_ENABLE */
++	sw	$8, 0($9)
++
++	/* Initialize USB registers */
++	la	$27, 0xb3040000	/* USB registers base address */
++
++	sb	$0, 0x0b($27)	/* INTRUSBE: disable common USB interrupts */
++	sh	$0, 0x06($27)	/* INTRINE: disable EPIN interrutps */
++	sh	$0, 0x08($27)	/* INTROUTE: disable EPOUT interrutps */
++
++	li	$9, 0x61
++	sb	$9, 0x01($27)	/* POWER: HSENAB | SUSPENDM | SOFTCONN */
++
++	/* Initialize USB states */
++	li	$22, 0			/* set EP0 to IDLE state */
++	li	$23, 1			/* no data stage */
++
++	/* Main loop of polling the usb commands */
++usb_command_loop:
++	lbu	$9, 0x0a($27)		/* read INTRUSB */
++	andi	$9, 0x04		/* check USB_INTR_RESET */
++	beqz	$9, check_intr_ep0in
++	nop
++
++ 	/* 1. Handle USB reset interrupt */
++handle_reset_intr:
++	lbu	$9, 0x01($27)		/* read POWER */
++	andi	$9, 0x10		/* test HS_MODE */
++	bnez	$9, _usb_set_maxpktsize
++	li	$9, 512			/* max packet size of HS mode */
++	li	$9, 64			/* max packet size of FS mode */
++
++_usb_set_maxpktsize:
++	li	$8, 1
++	sb	$8, 0x0e($27)		/* set INDEX 1 */
++
++	sh	$9, 0x10($27)		/* INMAXP */
++	sb	$0, 0x13($27)		/* INCSRH */
++	sh	$9, 0x14($27)		/* OUTMAXP */
++	sb	$0, 0x17($27)		/* OUTCSRH */
++
++_usb_flush_fifo:
++	li	$8, 0x48		/* INCSR_CDT && INCSR_FF */
++	sb	$8, 0x12($27)		/* INCSR */
++	li	$8, 0x90		/* OUTCSR_CDT && OUTCSR_FF */
++	sb	$8, 0x16($27)		/* OUTCSR */
++
++	li	$22, 0			/* set EP0 to IDLE state */
++	li	$23, 1			/* no data stage */
++
++	/* 2. Check and handle EP0 interrupt */
++check_intr_ep0in:
++	lhu	$10, 0x02($27)		/* read INTRIN */
++	andi	$9, $10, 0x1		/* check EP0 interrupt */
++	beqz	$9, check_intr_ep1in
++	nop
++
++handle_ep0_intr:
++	sb	$0, 0x0e($27)		/* set INDEX 0 */
++	lbu	$11, 0x12($27)		/* read CSR0 */
++
++	andi	$9, $11, 0x04		/* check SENTSTALL */
++	beqz	$9, _ep0_setupend
++	nop
++
++_ep0_sentstall:
++	andi	$9, $11, 0xdb
++	sb	$9, 0x12($27)		/* clear SENDSTALL and SENTSTALL */
++	li	$22, 0			/* set EP0 to IDLE state */
++
++_ep0_setupend:
++	andi	$9, $11, 0x10		/* check SETUPEND */
++	beqz	$9, ep0_idle_state
++	nop
++
++	ori	$9, $11, 0x80
++	sb	$9, 0x12($27)		/* set SVDSETUPEND */
++	li	$22, 0			/* set EP0 to IDLE state */
++
++ep0_idle_state:
++	bnez	$22, ep0_tx_state
++	nop
++
++	/* 2.1 Handle EP0 IDLE state interrupt */
++	andi	$9, $11, 0x01		/* check OUTPKTRDY */
++	beqz	$9, check_intr_ep1in
++	nop
++
++	/* Read 8-bytes setup packet from the FIFO */
++	lw	$25, 0x20($27)		/* first word of setup packet */
++	lw	$26, 0x20($27)		/* second word of setup packet */
++
++	andi	$9, $25, 0x60		/* bRequestType & USB_TYPE_MASK */
++	beqz	$9, _ep0_std_req
++	nop
++
++	/* 2.1.1 Vendor-specific setup request */
++_ep0_vend_req:
++	li	$22, 0			/* set EP0 to IDLE state */
++	li	$23, 1			/* NoData = 1 */
++
++	andi	$9, $25, 0xff00		/* check bRequest */
++	srl	$9, $9, 8
++	beqz	$9, __ep0_get_cpu_info
++	sub	$8, $9, 0x1
++	beqz	$8, __ep0_set_data_address
++	sub	$8, $9, 0x2
++	beqz	$8, __ep0_set_data_length
++	sub	$8, $9, 0x3
++	beqz	$8, __ep0_flush_caches
++	sub	$8, $9, 0x4
++	beqz	$8, __ep0_prog_start1
++	sub	$8, $9, 0x5
++	beqz	$8, __ep0_prog_start2
++	nop
++	b	_ep0_idle_state_fini	/* invalid request */
++	nop
++
++__ep0_get_cpu_info:
++	load_addr $20, cpu_info_data	/* data pointer to transfer */
++	li	$21, 8			/* bytes left to transfer */
++	li	$22, 1			/* set EP0 to TX state */
++	li	$23, 0			/* NoData = 0 */
++
++	b	_ep0_idle_state_fini
++	nop
++
++__ep0_set_data_address:
++	li	$9, 0xffff0000
++	and	$9, $25, $9
++	andi	$8, $26, 0xffff
++	or	$20, $9, $8		/* data address of next transfer */
++
++	b	_ep0_idle_state_fini
++	nop
++
++__ep0_set_data_length:
++	li	$9, 0xffff0000
++	and	$9, $25, $9
++	andi	$8, $26, 0xffff
++	or	$21, $9, $8		/* data length of next transfer */
++
++	li	$9, 0x48		/* SVDOUTPKTRDY and DATAEND */
++	sb	$9, 0x12($27)		/* CSR0 */
++
++	/* We must write packet to FIFO before EP1-IN interrupt here. */
++	b	handle_epin1_intr
++	nop
++
++__ep0_flush_caches:
++	/* Flush dcache and invalidate icache. */
++	li	$8, 0x80000000
++	addi	$9, $8, 0x3fe0		/* total 16KB */
++
++1:
++	cache	0x0, 0($8)		/* Index_Invalidate_I */
++	cache	0x1, 0($8)		/* Index_Writeback_Inv_D */
++	bne	$8, $9, 1b
++	addiu	$8, $8, 32
++
++	/* flush write-buffer */
++	sync
++
++	/* Invalidate BTB */
++	mfc0	$8, $16, 7		/* CP0_CONFIG */
++	nop
++	ori	$8, 2
++	mtc0	$8, $16, 7
++	nop
++
++	b	_ep0_idle_state_fini
++	nop
++
++__ep0_prog_start1:
++	li	$9, 0x48		/* SVDOUTPKTRDY and DATAEND */
++	sb	$9, 0x12($27)		/* CSR0 */
++
++	li	$9, 0xffff0000
++	and	$9, $25, $9
++	andi	$8, $26, 0xffff
++	or	$20, $9, $8		/* target address */
++
++	b	xfer_d2i
++	li	$19, 0x2000		/* 16KB data length */
++
++__ep0_prog_start2:
++	li	$9, 0x48		/* SVDOUTPKTRDY and DATAEND */
++	sb	$9, 0x12($27)		/* CSR0 */
++
++	li	$9, 0xffff0000
++	and	$9, $25, $9
++	andi	$8, $26, 0xffff
++	or	$20, $9, $8		/* target address */
++
++	jalr	$20		/* jump, and place the return address in $31 */
++	nop
++
++__ep0_prog_start2_return:
++/* User code can return to here after executing itself, by jumping to $31 */
++	b	usb_boot_return
++	nop
++
++	/* 2.1.2 Standard setup request */
++_ep0_std_req:
++	andi	$12, $25, 0xff00	/* check bRequest */
++	srl	$12, $12, 8
++	sub	$9, $12, 0x05		/* check USB_REQ_SET_ADDRESS */
++	bnez	$9, __ep0_req_set_config
++	nop
++
++	/* Handle USB_REQ_SET_ADDRESS */
++__ep0_req_set_addr:
++	srl	$9, $25, 16		/* get wValue */
++	sb	$9, 0x0($27)		/* set FADDR */
++	li	$23, 1			/* NoData = 1 */
++	b	_ep0_idle_state_fini
++	nop
++
++__ep0_req_set_config:
++	sub	$9, $12, 0x09		/* check USB_REQ_SET_CONFIGURATION */
++	bnez	$9, __ep0_req_get_desc
++	nop
++
++	/* Handle USB_REQ_SET_CONFIGURATION */
++	li	$23, 1			/* NoData = 1 */
++	b	_ep0_idle_state_fini
++	nop
++
++__ep0_req_get_desc:
++	sub	$9, $12, 0x06		/* check USB_REQ_GET_DESCRIPTOR */
++	bnez	$9, _ep0_idle_state_fini
++	li	$23, 1			/* NoData = 1 */
++
++	/* Handle USB_REQ_GET_DESCRIPTOR */
++	li	$23, 0			/* NoData = 0 */
++
++	srl	$9, $25, 24		/* wValue >> 8 */
++	sub	$8, $9, 0x01		/* check USB_DT_DEVICE */
++	beqz	$8, ___ep0_get_dev_desc
++	srl	$21, $26, 16		/* get wLength */
++	sub	$8, $9, 0x02		/* check USB_DT_CONFIG */
++	beqz	$8, ___ep0_get_conf_desc
++	sub	$8, $9, 0x03		/* check USB_DT_STRING */
++	beqz	$8, ___ep0_get_string_desc
++	sub	$8, $9, 0x06		/* check USB_DT_DEVICE_QUALIFIER */
++	beqz	$8, ___ep0_get_dev_qualifier
++	nop
++	b	_ep0_idle_state_fini
++	nop
++
++___ep0_get_dev_desc:
++	load_addr	$20, device_desc	/* data pointer */
++	li	$22, 1			/* set EP0 to TX state */
++	sub	$8, $21, 18
++	blez	$8, _ep0_idle_state_fini /* wLength <= 18 */
++	nop
++	li	$21, 18			/* max length of device_desc */
++	b	_ep0_idle_state_fini
++	nop
++
++___ep0_get_dev_qualifier:
++	load_addr	$20, dev_qualifier	/* data pointer */
++	li	$22, 1			/* set EP0 to TX state */
++	sub	$8, $21, 10
++	blez	$8, _ep0_idle_state_fini /* wLength <= 10 */
++	nop
++	li	$21, 10			/* max length of dev_qualifier */
++	b	_ep0_idle_state_fini
++	nop
++
++___ep0_get_conf_desc:
++	load_addr	$20, config_desc_fs	/* data pointer of FS mode */
++	lbu	$8, 0x01($27)		/* read POWER */
++	andi	$8, 0x10		/* test HS_MODE */
++	beqz	$8, ___ep0_get_conf_desc2
++	nop
++	load_addr $20, config_desc_hs	/* data pointer of HS mode */
++
++___ep0_get_conf_desc2:
++	li	$22, 1			/* set EP0 to TX state */
++	sub	$8, $21, 32
++	blez	$8, _ep0_idle_state_fini /* wLength <= 32 */
++	nop
++	li	$21, 32			/* max length of config_desc */
++	b	_ep0_idle_state_fini
++	nop
++
++___ep0_get_string_desc:
++	li	$22, 1			/* set EP0 to TX state */
++
++	srl	$9, $25, 16		/* wValue & 0xff */
++	andi	$9, 0xff
++
++	sub	$8, $9, 1
++	beqz	$8, ___ep0_get_string_manufacture
++	sub	$8, $9, 2
++	beqz	$8, ___ep0_get_string_product
++	nop
++
++___ep0_get_string_lang_ids:
++	load_addr	$20, string_lang_ids	/* data pointer */
++	b	_ep0_idle_state_fini
++	li	$21, 4			/* data length */
++
++___ep0_get_string_manufacture:
++	load_addr	$20, string_manufacture	/* data pointer */
++	b	_ep0_idle_state_fini
++	li	$21, 16			/* data length */
++
++___ep0_get_string_product:
++	load_addr	$20, string_product	/* data pointer */
++	b	_ep0_idle_state_fini
++	li	$21, 46			/* data length */
++
++_ep0_idle_state_fini:
++	li	$9, 0x40		/* SVDOUTPKTRDY */
++	beqz	$23, _ep0_idle_state_fini2
++	nop
++	ori	$9, $9, 0x08		/* DATAEND */
++_ep0_idle_state_fini2:
++	sb	$9, 0x12($27)		/* CSR0 */
++	beqz	$22, check_intr_ep1in
++	nop
++
++	/* 2.2 Handle EP0 TX state interrupt */
++ep0_tx_state:
++	sub	$9, $22, 1
++	bnez	$9, check_intr_ep1in
++	nop
++
++	sub	$9, $21, 64		/* max packetsize */
++	blez	$9, _ep0_tx_state2	/* data count <= 64 */
++	ori	$19, $21, 0
++	li	$19, 64
++
++_ep0_tx_state2:
++	beqz	$19, _ep0_tx_state3	/* send ZLP */
++	ori	$18, $19, 0		/* record bytes to be transferred */
++	sub	$21, $21, $19		/* decrement data count */
++
++_ep0_fifo_write_loop:
++	lbu	$9, 0($20)		/* read data */
++	sb	$9, 0x20($27)		/* load FIFO */
++	sub	$19, $19, 1		/* decrement counter */
++	bnez	$19, _ep0_fifo_write_loop
++	addi	$20, $20, 1		/* increment data pointer */
++
++	sub	$9, $18, 64		/* max packetsize */
++	beqz	$9, _ep0_tx_state4
++	nop
++
++_ep0_tx_state3:
++	/* transferred bytes < max packetsize */
++	li	$9, 0x0a		/* set INPKTRDY and DATAEND */
++	sb	$9, 0x12($27)		/* CSR0 */
++	li	$22, 0			/* set EP0 to IDLE state */
++	b	check_intr_ep1in
++	nop
++
++_ep0_tx_state4:
++	/* transferred bytes == max packetsize */
++	li	$9, 0x02		/* set INPKTRDY */
++	sb	$9, 0x12($27)		/* CSR0 */
++	b	check_intr_ep1in
++	nop
++
++	/* 3. Check and handle EP1 BULK-IN interrupt */
++check_intr_ep1in:
++	andi	$9, $10, 0x2		/* check EP1 IN interrupt */
++	beqz	$9, check_intr_ep1out
++	nop
++
++handle_epin1_intr:
++	li	$9, 1
++	sb	$9, 0x0e($27)		/* set INDEX 1 */
++	lbu	$9, 0x12($27)		/* read INCSR */
++
++	andi	$8, $9, 0x2		/* check INCSR_FFNOTEMPT */
++	bnez	$8, _epin1_tx_state4
++	nop
++
++_epin1_write_fifo:
++	lhu	$9, 0x10($27)		/* get INMAXP */
++	sub	$8, $21, $9
++	blez	$8, _epin1_tx_state1	/* bytes left <= INMAXP */
++	ori	$19, $21, 0
++	ori	$19, $9, 0
++
++_epin1_tx_state1:
++	beqz	$19, _epin1_tx_state4	/* No data */
++	nop
++
++	sub	$21, $21, $19		/* decrement data count */
++
++	srl	$5, $19, 2		/* # of word */
++	andi	$6, $19, 0x3		/* # of byte */
++	beqz	$5, _epin1_tx_state2
++	nop
++
++_epin1_fifo_write_word:
++	lw	$9, 0($20)		/* read data from source address */
++	sw	$9, 0x24($27)		/* write FIFO */
++	sub	$5, $5, 1		/* decrement counter */
++	bnez	$5, _epin1_fifo_write_word
++	addiu	$20, $20, 4		/* increment dest address */
++
++_epin1_tx_state2:
++	beqz	$6, _epin1_tx_state3
++	nop
++
++_epin1_fifo_write_byte:
++	lbu	$9, 0($20)		/* read data from source address */
++	sb	$9, 0x24($27)		/* write FIFO */
++	sub	$6, $6, 1		/* decrement counter */
++	bnez	$6, _epin1_fifo_write_byte
++	addiu	$20, $20, 1		/* increment dest address */
++
++_epin1_tx_state3:
++	li	$9, 0x1
++	sb	$9, 0x12($27)		/* INCSR, set INPKTRDY */
++
++_epin1_tx_state4:
++	/* 4. Check and handle EP1 BULK-OUT interrupt */
++check_intr_ep1out:
++	lhu	$9, 0x04($27)		/* read INTROUT */
++	andi	$9, 0x2
++	beqz	$9, check_status_next
++	nop
++
++handle_epout1_intr:
++	li	$9, 1
++	sb	$9, 0x0e($27)		/* set INDEX 1 */
++
++	lbu	$9, 0x16($27)		/* read OUTCSR */
++	andi	$9, 0x1			/* check OUTPKTRDY */
++	beqz	$9, check_status_next
++	nop
++
++_epout1_read_fifo:
++	lhu	$19, 0x18($27)		/* read OUTCOUNT */
++	srl	$5, $19, 2		/* # of word */
++	andi	$6, $19, 0x3		/* # of byte */
++	beqz	$5, _epout1_rx_state1
++	nop
++
++_epout1_fifo_read_word:
++	lw	$9, 0x24($27)		/* read FIFO */
++	sw	$9, 0($20)		/* store to dest address */
++	sub	$5, $5, 1		/* decrement counter */
++	bnez	$5, _epout1_fifo_read_word
++	addiu	$20, $20, 4		/* increment dest address */
++
++_epout1_rx_state1:
++	beqz	$6, _epout1_rx_state2
++	nop
++
++_epout1_fifo_read_byte:
++	lbu	$9, 0x24($27)		/* read FIFO */
++	sb	$9, 0($20)		/* store to dest address */
++	sub	$6, $6, 1		/* decrement counter */
++	bnez	$6, _epout1_fifo_read_byte
++	addiu	$20, $20, 1		/* increment dest address */
++
++_epout1_rx_state2:
++	sb	$0, 0x16($27)		/* clear OUTPKTRDY */
++
++check_status_next:
++	b	usb_command_loop
++	nop
++
++/* Device/Configuration/Interface/Endpoint/String Descriptors */
++
++	.align	2
++device_desc:
++	.byte	0x12		/* bLength */
++	.byte	0x01		/* bDescriptorType */
++	.byte	0x00		/* bcdUSB */
++	.byte	0x02		/* bcdUSB */
++	.byte	0x00		/* bDeviceClass */
++	.byte	0x00		/* bDeviceSubClass */
++	.byte	0x00		/* bDeviceProtocol */
++	.byte	0x40		/* bMaxPacketSize0 */
++	.byte	0x1a		/* idVendor */
++	.byte	0x60		/* idVendor */
++	.byte	0x40		/* idProduct */
++	.byte	0x47		/* idProduct */
++	.byte	0x00		/* bcdDevice */
++	.byte	0x01		/* bcdDevice */
++	.byte	0x01		/* iManufacturer */
++	.byte	0x02		/* iProduct */
++	.byte	0x00		/* iSerialNumber */
++	.byte	0x01		/* bNumConfigurations */
++
++	.align	2
++dev_qualifier:
++	.byte	0x0a		/* bLength */
++	.byte	0x06		/* bDescriptorType */
++	.byte	0x00		/* bcdUSB */
++	.byte	0x02		/* bcdUSB */
++	.byte	0x00		/* bDeviceClass */
++	.byte	0x00		/* bDeviceSubClass */
++	.byte	0x00		/* bDeviceProtocol */
++	.byte	0x40		/* bMaxPacketSize0 */
++	.byte	0x01		/* bNumConfigurations */
++	.byte	0x00		/* bRESERVED */
++
++	.align	2
++config_desc_hs:
++	.byte	0x09		/* bLength */
++	.byte	0x02		/* bDescriptorType */
++	.byte	0x20		/* wTotalLength */
++	.byte	0x00		/* wTotalLength */
++	.byte	0x01		/* bNumInterfaces */
++	.byte	0x01		/* bConfigurationValue */
++	.byte	0x00		/* iConfiguration */
++	.byte	0xc0		/* bmAttributes */
++	.byte	0x01		/* MaxPower */
++intf_desc_hs:
++	.byte	0x09		/* bLength */
++	.byte	0x04		/* bDescriptorType */
++	.byte	0x00		/* bInterfaceNumber */
++	.byte	0x00		/* bAlternateSetting */
++	.byte	0x02		/* bNumEndpoints */
++	.byte	0xff		/* bInterfaceClass */
++	.byte	0x00		/* bInterfaceSubClass */
++	.byte	0x50		/* bInterfaceProtocol */
++	.byte	0x00		/* iInterface */
++ep1_desc_hs:
++	.byte	0x07		/* bLength */
++	.byte	0x05		/* bDescriptorType */
++	.byte	0x01		/* bEndpointAddress */
++	.byte	0x02		/* bmAttributes */
++	.byte	0x00		/* wMaxPacketSize */
++	.byte	0x02		/* wMaxPacketSize */
++	.byte	0x00		/* bInterval */
++ep2_desc_hs:
++	.byte	0x07		/* bLength */
++	.byte	0x05		/* bDescriptorType */
++	.byte	0x81		/* bEndpointAddress */
++	.byte	0x02		/* bmAttributes */
++	.byte	0x00		/* wMaxPacketSize */
++	.byte	0x02		/* wMaxPacketSize */
++	.byte	0x00		/* bInterval */
++
++	.align	2
++config_desc_fs:
++	.byte	0x09		/* bLength */
++	.byte	0x02		/* bDescriptorType */
++	.byte	0x20		/* wTotalLength */
++	.byte	0x00		/* wTotalLength */
++	.byte	0x01		/* bNumInterfaces */
++	.byte	0x01		/* bConfigurationValue */
++	.byte	0x00		/* iConfiguration */
++	.byte	0xc0		/* bmAttributes */
++	.byte	0x01		/* MaxPower */
++intf_desc_fs:
++	.byte	0x09		/* bLength */
++	.byte	0x04		/* bDescriptorType */
++	.byte	0x00		/* bInterfaceNumber */
++	.byte	0x00		/* bAlternateSetting */
++	.byte	0x02		/* bNumEndpoints */
++	.byte	0xff		/* bInterfaceClass */
++	.byte	0x00		/* bInterfaceSubClass */
++	.byte	0x50		/* bInterfaceProtocol */
++	.byte	0x00		/* iInterface */
++ep1_desc_fs:
++	.byte	0x07		/* bLength */
++	.byte	0x05		/* bDescriptorType */
++	.byte	0x01		/* bEndpointAddress */
++	.byte	0x02		/* bmAttributes */
++	.byte	0x40		/* wMaxPacketSize */
++	.byte	0x00		/* wMaxPacketSize */
++	.byte	0x00		/* bInterval */
++ep2_desc_fs:
++	.byte	0x07		/* bLength */
++	.byte	0x05		/* bDescriptorType */
++	.byte	0x81		/* bEndpointAddress */
++	.byte	0x02		/* bmAttributes */
++	.byte	0x40		/* wMaxPacketSize */
++	.byte	0x00		/* wMaxPacketSize */
++	.byte	0x00		/* bInterval */
++
++	.align	2
++string_lang_ids:
++	.byte	0x04
++	.byte	0x03
++	.byte	0x09
++	.byte	0x04
++
++	.align	2
++string_manufacture:
++	.byte	0x10
++	.byte	0x03
++	.byte	0x49
++	.byte	0x00
++	.byte	0x6e
++	.byte	0x00
++	.byte	0x67
++	.byte	0x00
++	.byte	0x65
++	.byte	0x00
++	.byte	0x6e
++	.byte	0x00
++	.byte	0x69
++	.byte	0x00
++	.byte	0x63
++	.byte	0x00
++
++	.align	2
++string_product:
++	.byte	0x2e
++	.byte	0x03
++	.byte	0x4a
++	.byte	0x00
++	.byte	0x5a
++	.byte	0x00
++	.byte	0x34
++	.byte	0x00
++	.byte	0x37
++	.byte	0x00
++	.byte	0x34
++	.byte	0x00
++	.byte	0x30
++	.byte	0x00
++	.byte	0x20
++	.byte	0x00
++	.byte	0x55
++	.byte	0x00
++	.byte	0x53
++	.byte	0x00
++	.byte	0x42
++	.byte	0x00
++	.byte	0x20
++	.byte	0x00
++	.byte	0x42
++	.byte	0x00
++	.byte	0x6f
++	.byte	0x00
++	.byte	0x6f
++	.byte	0x00
++	.byte	0x74
++	.byte	0x00
++	.byte	0x20
++	.byte	0x00
++	.byte	0x44
++	.byte	0x00
++	.byte	0x65
++	.byte	0x00
++	.byte	0x76
++	.byte	0x00
++	.byte	0x69
++	.byte	0x00
++	.byte	0x63
++	.byte	0x00
++	.byte	0x65
++	.byte	0x00
++
++	.align	2
++cpu_info_data:
++	.byte	0x4a
++	.byte	0x5a
++	.byte	0x34
++	.byte	0x37
++	.byte	0x34
++	.byte	0x30
++	.byte	0x56
++	.byte	0x31
++usbboot_end:
++
++    .set reorder
+-- 
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0003-add-mmc-support.patch b/package/boot/uboot-xburst/patches/0003-add-mmc-support.patch
new file mode 100644
index 0000000000..e9baa7c373
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0003-add-mmc-support.patch
@@ -0,0 +1,1664 @@
+From bd36739e77669e8df45c38f6acfe2cea511534d9 Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 18:19:41 +0800
+Subject: [PATCH 3/6] add mmc support
+
+---
+ arch/mips/include/asm/jz4740.h |  166 ++++++
+ board/qi/qi_lb60/qi_lb60.c     |    9 +-
+ drivers/mmc/Makefile           |    1 +
+ drivers/mmc/jz_mmc.c           | 1179 ++++++++++++++++++++++++++++++++++++++++
+ drivers/mmc/jz_mmc.h           |  176 ++++++
+ include/configs/qi_lb60.h      |    9 +
+ include/mmc.h                  |   40 ++
+ 7 files changed, 1578 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mmc/jz_mmc.c
+ create mode 100644 drivers/mmc/jz_mmc.h
+
+diff --git a/arch/mips/include/asm/jz4740.h b/arch/mips/include/asm/jz4740.h
+index 7a7cfff..68287fb 100644
+--- a/arch/mips/include/asm/jz4740.h
++++ b/arch/mips/include/asm/jz4740.h
+@@ -1146,5 +1146,171 @@ extern void sdram_init(void);
+ extern void calc_clocks(void);
+ extern void rtc_init(void);
+ 
++/*************************************************************************
++ * MSC
++ *************************************************************************/
++#define REG8(addr)	*((volatile u8 *)(addr))
++#define REG16(addr)	*((volatile u16 *)(addr))
++#define REG32(addr)	*((volatile u32 *)(addr))
++
++#define	CPM_BASE	0xB0000000
++#define CPM_CPCCR	(CPM_BASE+0x00)
++#define CPM_MSCCDR	(CPM_BASE+0x68)
++#define REG_CPM_MSCCDR	REG32(CPM_MSCCDR)
++#define REG_CPM_CPCCR	REG32(CPM_CPCCR)
++
++#define	MSC_BASE	0xB0021000
++
++#define	MSC_STRPCL		(MSC_BASE + 0x000)
++#define	MSC_STAT		(MSC_BASE + 0x004)
++#define	MSC_CLKRT		(MSC_BASE + 0x008)
++#define	MSC_CMDAT		(MSC_BASE + 0x00C)
++#define	MSC_RESTO		(MSC_BASE + 0x010)
++#define	MSC_RDTO		(MSC_BASE + 0x014)
++#define	MSC_BLKLEN		(MSC_BASE + 0x018)
++#define	MSC_NOB			(MSC_BASE + 0x01C)
++#define	MSC_SNOB		(MSC_BASE + 0x020)
++#define	MSC_IMASK		(MSC_BASE + 0x024)
++#define	MSC_IREG		(MSC_BASE + 0x028)
++#define	MSC_CMD			(MSC_BASE + 0x02C)
++#define	MSC_ARG			(MSC_BASE + 0x030)
++#define	MSC_RES			(MSC_BASE + 0x034)
++#define	MSC_RXFIFO		(MSC_BASE + 0x038)
++#define	MSC_TXFIFO		(MSC_BASE + 0x03C)
++
++#define	REG_MSC_STRPCL		REG16(MSC_STRPCL)
++#define	REG_MSC_STAT		REG32(MSC_STAT)
++#define	REG_MSC_CLKRT		REG16(MSC_CLKRT)
++#define	REG_MSC_CMDAT		REG32(MSC_CMDAT)
++#define	REG_MSC_RESTO		REG16(MSC_RESTO)
++#define	REG_MSC_RDTO		REG16(MSC_RDTO)
++#define	REG_MSC_BLKLEN		REG16(MSC_BLKLEN)
++#define	REG_MSC_NOB		REG16(MSC_NOB)
++#define	REG_MSC_SNOB		REG16(MSC_SNOB)
++#define	REG_MSC_IMASK		REG16(MSC_IMASK)
++#define	REG_MSC_IREG		REG16(MSC_IREG)
++#define	REG_MSC_CMD		REG8(MSC_CMD)
++#define	REG_MSC_ARG		REG32(MSC_ARG)
++#define	REG_MSC_RES		REG16(MSC_RES)
++#define	REG_MSC_RXFIFO		REG32(MSC_RXFIFO)
++#define	REG_MSC_TXFIFO		REG32(MSC_TXFIFO)
++
++/* MSC Clock and Control Register (MSC_STRPCL) */
++
++#define MSC_STRPCL_EXIT_MULTIPLE	(1 << 7)
++#define MSC_STRPCL_EXIT_TRANSFER	(1 << 6)
++#define MSC_STRPCL_START_READWAIT	(1 << 5)
++#define MSC_STRPCL_STOP_READWAIT	(1 << 4)
++#define MSC_STRPCL_RESET		(1 << 3)
++#define MSC_STRPCL_START_OP		(1 << 2)
++#define MSC_STRPCL_CLOCK_CONTROL_BIT	0
++#define MSC_STRPCL_CLOCK_CONTROL_MASK	(0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
++  #define MSC_STRPCL_CLOCK_CONTROL_STOP	  (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
++  #define MSC_STRPCL_CLOCK_CONTROL_START  (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
++
++/* MSC Status Register (MSC_STAT) */
++
++#define MSC_STAT_IS_RESETTING		(1 << 15)
++#define MSC_STAT_SDIO_INT_ACTIVE	(1 << 14)
++#define MSC_STAT_PRG_DONE		(1 << 13)
++#define MSC_STAT_DATA_TRAN_DONE		(1 << 12)
++#define MSC_STAT_END_CMD_RES		(1 << 11)
++#define MSC_STAT_DATA_FIFO_AFULL	(1 << 10)
++#define MSC_STAT_IS_READWAIT		(1 << 9)
++#define MSC_STAT_CLK_EN			(1 << 8)
++#define MSC_STAT_DATA_FIFO_FULL		(1 << 7)
++#define MSC_STAT_DATA_FIFO_EMPTY	(1 << 6)
++#define MSC_STAT_CRC_RES_ERR		(1 << 5)
++#define MSC_STAT_CRC_READ_ERROR		(1 << 4)
++#define MSC_STAT_CRC_WRITE_ERROR_BIT	2
++#define MSC_STAT_CRC_WRITE_ERROR_MASK	(0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
++  #define MSC_STAT_CRC_WRITE_ERROR_NO		(0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
++  #define MSC_STAT_CRC_WRITE_ERROR		(1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
++  #define MSC_STAT_CRC_WRITE_ERROR_NOSTS	(2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
++#define MSC_STAT_TIME_OUT_RES		(1 << 1)
++#define MSC_STAT_TIME_OUT_READ		(1 << 0)
++
++/* MSC Bus Clock Control Register (MSC_CLKRT) */
++
++#define	MSC_CLKRT_CLK_RATE_BIT		0
++#define	MSC_CLKRT_CLK_RATE_MASK		(0x7 << MSC_CLKRT_CLK_RATE_BIT)
++  #define MSC_CLKRT_CLK_RATE_DIV_1	  (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_2	  (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_4	  (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_8	  (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_16	  (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_32	  (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_64	  (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
++  #define MSC_CLKRT_CLK_RATE_DIV_128	  (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
++
++/* MSC Command Sequence Control Register (MSC_CMDAT) */
++
++#define	MSC_CMDAT_IO_ABORT	(1 << 11)
++#define	MSC_CMDAT_BUS_WIDTH_BIT	9
++#define	MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
++#define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT)
++#define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT)
++#define	MSC_CMDAT_DMA_EN	(1 << 8)
++#define	MSC_CMDAT_INIT		(1 << 7)
++#define	MSC_CMDAT_BUSY		(1 << 6)
++#define	MSC_CMDAT_STREAM_BLOCK	(1 << 5)
++#define	MSC_CMDAT_WRITE		(1 << 4)
++#define	MSC_CMDAT_READ		(0 << 4)
++#define	MSC_CMDAT_DATA_EN	(1 << 3)
++#define	MSC_CMDAT_RESPONSE_BIT	0
++#define	MSC_CMDAT_RESPONSE_MASK	(0x7 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_NONE	(0x0 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R1	(0x1 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R2	(0x2 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R3	(0x3 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R4	(0x4 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R5	(0x5 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R6	(0x6 << MSC_CMDAT_RESPONSE_BIT)
++
++/* MSC Interrupts Mask Register (MSC_IMASK) */
++#define	MSC_IMASK_SDIO			(1 << 7)
++#define	MSC_IMASK_TXFIFO_WR_REQ		(1 << 6)
++#define	MSC_IMASK_RXFIFO_RD_REQ		(1 << 5)
++#define	MSC_IMASK_END_CMD_RES		(1 << 2)
++#define	MSC_IMASK_PRG_DONE		(1 << 1)
++#define	MSC_IMASK_DATA_TRAN_DONE	(1 << 0)
++
++
++/* MSC Interrupts Status Register (MSC_IREG) */
++#define	MSC_IREG_SDIO			(1 << 7)
++#define	MSC_IREG_TXFIFO_WR_REQ		(1 << 6)
++#define	MSC_IREG_RXFIFO_RD_REQ		(1 << 5)
++#define	MSC_IREG_END_CMD_RES		(1 << 2)
++#define	MSC_IREG_PRG_DONE		(1 << 1)
++#define	MSC_IREG_DATA_TRAN_DONE		(1 << 0)
++
++static __inline__ unsigned int __cpm_get_pllout2(void)
++{
++	if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
++		return __cpm_get_pllout();
++	else
++		return __cpm_get_pllout()/2;
++}
++
++static inline void __cpm_select_msc_clk(int sd)
++{
++	unsigned int pllout2 = __cpm_get_pllout2();
++	unsigned int div = 0;
++
++	if (sd) {
++		div = pllout2 / 24000000;
++	}
++	else {
++		div = pllout2 / 16000000;
++	}
++
++	REG_CPM_MSCCDR = div - 1;
++}
++#define __msc_reset() 						\
++do { 								\
++	REG_MSC_STRPCL = MSC_STRPCL_RESET;			\
++ 	while (REG_MSC_STAT & MSC_STAT_IS_RESETTING);		\
++} while (0)
++
+ #endif	/* !__ASSEMBLY__ */
+ #endif	/* __JZ4740_H__ */
+diff --git a/board/qi/qi_lb60/qi_lb60.c b/board/qi/qi_lb60/qi_lb60.c
+index 3bd4e2f..a2ba648 100644
+--- a/board/qi/qi_lb60/qi_lb60.c
++++ b/board/qi/qi_lb60/qi_lb60.c
+@@ -40,8 +40,13 @@ static void gpio_init(void)
+ 		__gpio_clear_pin(GPIO_KEYOUT_BASE + i);
+ 	}
+ 
+-	__gpio_as_input(GPIO_KEYIN_8);
+-	__gpio_enable_pull(GPIO_KEYIN_8);
++	if (__gpio_get_pin(GPIO_KEYIN_BASE + 2) == 0){
++		printf("[S] pressed, enable UART0\n");
++		__gpio_as_uart0();
++	} else {
++		__gpio_as_input(GPIO_KEYIN_8);
++		__gpio_enable_pull(GPIO_KEYIN_8);
++	}
+ 
+ 	/* enable the TP4, TP5 as UART0 */
+ 	__gpio_jtag_to_uart0();
+diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
+index 565ba6a..3c717b1 100644
+--- a/drivers/mmc/Makefile
++++ b/drivers/mmc/Makefile
+@@ -47,6 +47,7 @@ COBJS-$(CONFIG_SDHCI) += sdhci.o
+ COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+ COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o
+ COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
++COBJS-$(CONFIG_JZ4740_MMC) += jz_mmc.o
+ 
+ COBJS	:= $(COBJS-y)
+ SRCS	:= $(COBJS:.o=.c)
+diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c
+new file mode 100644
+index 0000000..642cecc
+--- /dev/null
++++ b/drivers/mmc/jz_mmc.c
+@@ -0,0 +1,1179 @@
++/*
++ * (C) Copyright 2003
++ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <config.h>
++#include <common.h>
++#include <part.h>
++#include <mmc.h>
++
++#include <asm/io.h>
++#include <asm/jz4740.h>
++#include "jz_mmc.h"
++
++static int sd2_0 = 0;
++static int mmc_ready = 0;
++static int use_4bit;		/* Use 4-bit data bus */
++/*
++ *  MMC Events
++ */
++#define MMC_EVENT_NONE	        0x00	/* No events */
++#define MMC_EVENT_RX_DATA_DONE	0x01	/* Rx data done */
++#define MMC_EVENT_TX_DATA_DONE	0x02	/* Tx data done */
++#define MMC_EVENT_PROG_DONE	0x04	/* Programming is done */
++
++
++#define MMC_IRQ_MASK()				\
++do {						\
++      	REG_MSC_IMASK = 0xffff;			\
++      	REG_MSC_IREG = 0xffff;			\
++} while (0)
++
++/*
++ * GPIO definition
++ */
++#if defined(CONFIG_SAKC)
++
++#define __msc_init_io()				\
++do {						\
++	__gpio_as_input(GPIO_SD_CD_N);		\
++} while (0)
++
++#else
++#define __msc_init_io()				\
++do {						\
++	__gpio_as_output(GPIO_SD_VCC_EN_N);	\
++	__gpio_as_input(GPIO_SD_CD_N);		\
++} while (0)
++
++#define __msc_enable_power()			\
++do {						\
++	__gpio_clear_pin(GPIO_SD_VCC_EN_N);	\
++} while (0)
++
++#define __msc_disable_power()			\
++do {						\
++	__gpio_set_pin(GPIO_SD_VCC_EN_N);	\
++} while (0)
++	
++#endif /* CONFIG_SAKE */
++
++#define __msc_card_detected()			\
++({						\
++	int detected = 1;			\
++	__gpio_as_input(GPIO_SD_CD_N);		\
++	__gpio_disable_pull(GPIO_SD_CD_N);	\
++	if (!__gpio_get_pin(GPIO_SD_CD_N))	\
++		detected = 0;			\
++	detected;				\
++})
++
++/*
++ * Local functions
++ */
++
++extern int
++fat_register_device(block_dev_desc_t *dev_desc, int part_no);
++
++static block_dev_desc_t mmc_dev;
++
++block_dev_desc_t * mmc_get_dev(int dev)
++{
++	return ((block_dev_desc_t *)&mmc_dev);
++}
++
++/* Stop the MMC clock and wait while it happens */
++static inline int jz_mmc_stop_clock(void)
++{
++	int timeout = 1000;
++
++	REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP;
++
++	while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) {
++		timeout--;
++		if (timeout == 0)
++			return MMC_ERROR_TIMEOUT;
++		udelay(1);
++	}
++        return MMC_NO_ERROR;
++}
++
++/* Start the MMC clock and operation */
++static inline int jz_mmc_start_clock(void)
++{
++	REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP;
++	return MMC_NO_ERROR;
++}
++
++static inline u32 jz_mmc_calc_clkrt(int is_sd, u32 rate)
++{
++	u32 clkrt = 0;
++	u32 clk_src = is_sd ? 24000000 : 16000000;
++
++  	while (rate < clk_src) {
++      		clkrt ++;
++      		clk_src >>= 1;
++    	}
++
++	return clkrt;
++}
++
++/* Set the MMC clock frequency */
++void jz_mmc_set_clock(int sd, u32 rate)
++{
++	jz_mmc_stop_clock();
++
++	/* Select clock source of MSC */
++	__cpm_select_msc_clk(sd);
++
++	/* Set clock dividor of MSC */
++	REG_MSC_CLKRT = jz_mmc_calc_clkrt(sd, rate);
++}
++
++static int jz_mmc_check_status(struct mmc_request *request)
++{
++	u32 status = REG_MSC_STAT;
++
++	/* Checking for response or data timeout */
++	if (status & (MSC_STAT_TIME_OUT_RES | MSC_STAT_TIME_OUT_READ)) {
++		printf("MMC/SD timeout, MMC_STAT 0x%x CMD %d\n", status, request->cmd);
++		return MMC_ERROR_TIMEOUT;
++	}
++
++	/* Checking for CRC error */
++	if (status & (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR | MSC_STAT_CRC_RES_ERR)) {
++		printf("MMC/CD CRC error, MMC_STAT 0x%x\n", status);
++		return MMC_ERROR_CRC;
++	}
++
++	return MMC_NO_ERROR;
++}
++
++/* Obtain response to the command and store it to response buffer */
++static void jz_mmc_get_response(struct mmc_request *request)
++{
++	int i;
++	u8 *buf;
++	u32 data;
++
++	debug("fetch response for request %d, cmd %d\n", 
++	      request->rtype, request->cmd);
++
++	buf = request->response;
++	request->result = MMC_NO_ERROR;
++
++	switch (request->rtype) {
++	case RESPONSE_R1: case RESPONSE_R1B: case RESPONSE_R6:
++	case RESPONSE_R3: case RESPONSE_R4: case RESPONSE_R5:
++	{
++		data = REG_MSC_RES;
++		buf[0] = (data >> 8) & 0xff;
++		buf[1] = data & 0xff;
++		data = REG_MSC_RES;
++		buf[2] = (data >> 8) & 0xff;
++		buf[3] = data & 0xff;
++		data = REG_MSC_RES;
++		buf[4] = data & 0xff;
++
++		debug("request %d, response [%02x %02x %02x %02x %02x]\n",
++		      request->rtype, buf[0], buf[1], buf[2], buf[3], buf[4]);
++		break;
++	}
++	case RESPONSE_R2_CID: case RESPONSE_R2_CSD:
++	{
++		for (i = 0; i < 16; i += 2) {
++			data = REG_MSC_RES;
++			buf[i] = (data >> 8) & 0xff;
++			buf[i+1] = data & 0xff;
++		}
++		debug("request %d, response [", request->rtype);
++#if CONFIG_MMC_DEBUG_VERBOSE > 2
++		if (g_mmc_debug >= 3) {
++			int n;
++			for (n = 0; n < 17; n++)
++				printk("%02x ", buf[n]);
++			printk("]\n");
++		}
++#endif
++		break;
++	}
++	case RESPONSE_NONE:
++		debug("No response\n");
++		break;
++
++	default:
++		debug("unhandled response type for request %d\n", request->rtype);
++		break;
++	}
++}
++
++static int jz_mmc_receive_data(struct mmc_request *req)
++{
++	u32  stat, timeout, data, cnt;
++	u8 *buf = req->buffer;
++	u32 wblocklen = (u32)(req->block_len + 3) >> 2; /* length in word */
++
++	timeout = 0x3ffffff;
++
++	while (timeout) {
++		timeout--;
++		stat = REG_MSC_STAT;
++
++		if (stat & MSC_STAT_TIME_OUT_READ)
++			return MMC_ERROR_TIMEOUT;
++		else if (stat & MSC_STAT_CRC_READ_ERROR)
++			return MMC_ERROR_CRC;
++		else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY)
++			 || (stat & MSC_STAT_DATA_FIFO_AFULL)) {
++			/* Ready to read data */
++			break;
++		}
++		udelay(1);
++	}
++	if (!timeout)
++		return MMC_ERROR_TIMEOUT;
++
++	/* Read data from RXFIFO. It could be FULL or PARTIAL FULL */
++	cnt = wblocklen;
++	while (cnt) {
++		data = REG_MSC_RXFIFO;
++		{
++			*buf++ = (u8)(data >> 0);
++			*buf++ = (u8)(data >> 8);
++			*buf++ = (u8)(data >> 16);
++			*buf++ = (u8)(data >> 24);
++		}
++		cnt --;
++		while (cnt && (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY))
++			;
++	}
++	return MMC_NO_ERROR;
++}
++
++static int jz_mmc_transmit_data(struct mmc_request *req)
++{
++#if 0
++	u32 nob = req->nob;
++	u32 wblocklen = (u32)(req->block_len + 3) >> 2; /* length in word */
++	u8 *buf = req->buffer;
++	u32 *wbuf = (u32 *)buf;
++	u32 waligned = (((u32)buf & 0x3) == 0); /* word aligned ? */
++	u32 stat, timeout, data, cnt;
++
++	for (nob; nob >= 1; nob--) {
++		timeout = 0x3FFFFFF;
++
++		while (timeout) {
++			timeout--;
++			stat = REG_MSC_STAT;
++
++			if (stat & (MSC_STAT_CRC_WRITE_ERROR | MSC_STAT_CRC_WRITE_ERROR_NOSTS))
++				return MMC_ERROR_CRC;
++			else if (!(stat & MSC_STAT_DATA_FIFO_FULL)) {
++				/* Ready to write data */
++				break;
++			}
++
++			udelay(1);
++		}
++
++		if (!timeout)
++			return MMC_ERROR_TIMEOUT;
++
++		/* Write data to TXFIFO */
++		cnt = wblocklen;
++		while (cnt) {
++			while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL)
++				;
++
++			if (waligned) {
++				REG_MSC_TXFIFO = *wbuf++;
++			}
++			else {
++				data = *buf++ | (*buf++ << 8) | (*buf++ << 16) | (*buf++ << 24);
++				REG_MSC_TXFIFO = data;
++			}
++
++			cnt--;
++		}
++	}
++#endif
++	return MMC_NO_ERROR;
++}
++
++
++/*
++ * Name:	  int jz_mmc_exec_cmd()
++ * Function:      send command to the card, and get a response
++ * Input:	  struct mmc_request *req	: MMC/SD request
++ * Output:	  0:  right		>0:  error code
++ */
++int jz_mmc_exec_cmd(struct mmc_request *request)
++{
++	u32 cmdat = 0, events = 0;
++	int retval, timeout = 0x3fffff;
++
++	/* Indicate we have no result yet */
++	request->result = MMC_NO_RESPONSE;
++	if (request->cmd == MMC_CIM_RESET) {
++		/* On reset, 1-bit bus width */
++		use_4bit = 0;
++
++		/* Reset MMC/SD controller */
++		__msc_reset();
++
++		/* On reset, drop MMC clock down */
++		jz_mmc_set_clock(0, MMC_CLOCK_SLOW);
++
++		/* On reset, stop MMC clock */
++		jz_mmc_stop_clock();
++	}
++	if (request->cmd == MMC_CMD_SEND_OP_COND) {
++		debug("Have an MMC card\n");
++		/* always use 1bit for MMC */
++		use_4bit = 0;
++	}
++	if (request->cmd == SET_BUS_WIDTH) {
++		if (request->arg == 0x2) {
++			printf("Use 4-bit bus width\n");
++			use_4bit = 1;
++		} else {
++			printf("Use 1-bit bus width\n");
++			use_4bit = 0;
++		}
++	}
++
++	/* stop clock */
++	jz_mmc_stop_clock();
++
++	/* mask all interrupts */
++	REG_MSC_IMASK = 0xffff;
++
++	/* clear status */
++	REG_MSC_IREG = 0xffff;
++
++	/* use 4-bit bus width when possible */
++	if (use_4bit)
++		cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
++
++        /* Set command type and events */
++	switch (request->cmd) {
++	/* MMC core extra command */
++	case MMC_CIM_RESET:
++		cmdat |= MSC_CMDAT_INIT; /* Initialization sequence sent prior to command */
++		break;
++
++	/* bc - broadcast - no response */
++	case MMC_CMD_GO_IDLE_STATE:
++	case MMC_CMD_SET_DSR:
++		break;
++
++	/* bcr - broadcast with response */
++	case MMC_CMD_SEND_OP_COND:
++	case MMC_CMD_ALL_SEND_CID:
++	case MMC_GO_IRQ_STATE:
++		break;
++
++	/* adtc - addressed with data transfer */
++	case MMC_READ_DAT_UNTIL_STOP:
++	case MMC_CMD_READ_SINGLE_BLOCK:
++	case MMC_CMD_READ_MULTIPLE_BLOCK:
++	case SD_CMD_APP_SEND_SCR:
++		cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ;
++		events = MMC_EVENT_RX_DATA_DONE;
++		break;
++
++	case MMC_WRITE_DAT_UNTIL_STOP:
++	case MMC_CMD_WRITE_SINGLE_BLOCK:
++	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
++	case MMC_PROGRAM_CID:
++	case MMC_PROGRAM_CSD:
++	case MMC_SEND_WRITE_PROT:
++	case MMC_GEN_CMD:
++	case MMC_LOCK_UNLOCK:
++		cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE;
++		events = MMC_EVENT_TX_DATA_DONE | MMC_EVENT_PROG_DONE;
++
++		break;
++
++	case MMC_CMD_STOP_TRANSMISSION:
++		events = MMC_EVENT_PROG_DONE;
++		break;
++
++	/* ac - no data transfer */
++	default:
++		break;
++	}
++
++	/* Set response type */
++	switch (request->rtype) {
++	case RESPONSE_NONE:
++		break;
++
++	case RESPONSE_R1B:
++		cmdat |= MSC_CMDAT_BUSY;
++		/*FALLTHRU*/
++	case RESPONSE_R1:
++		cmdat |= MSC_CMDAT_RESPONSE_R1;
++		break;
++	case RESPONSE_R2_CID:
++	case RESPONSE_R2_CSD:
++		cmdat |= MSC_CMDAT_RESPONSE_R2;
++		break;
++	case RESPONSE_R3:
++		cmdat |= MSC_CMDAT_RESPONSE_R3;
++		break;
++	case RESPONSE_R4:
++		cmdat |= MSC_CMDAT_RESPONSE_R4;
++		break;
++	case RESPONSE_R5:
++		cmdat |= MSC_CMDAT_RESPONSE_R5;
++		break;
++	case RESPONSE_R6:
++		cmdat |= MSC_CMDAT_RESPONSE_R6;
++		break;
++	default:
++		break;
++	}
++
++	/* Set command index */
++	if (request->cmd == MMC_CIM_RESET) {
++		REG_MSC_CMD = MMC_CMD_GO_IDLE_STATE;
++	} else {
++		REG_MSC_CMD = request->cmd;
++	}
++
++        /* Set argument */
++	REG_MSC_ARG = request->arg;
++
++	/* Set block length and nob */
++	if (request->cmd == SD_CMD_APP_SEND_SCR) { /* get SCR from DataFIFO */
++		REG_MSC_BLKLEN = 8;
++		REG_MSC_NOB = 1;
++	} else {
++		REG_MSC_BLKLEN = request->block_len;
++		REG_MSC_NOB = request->nob;
++	}
++
++	/* Set command */
++	REG_MSC_CMDAT = cmdat;
++
++	debug("Send cmd %d cmdat: %x arg: %x resp %d\n", request->cmd,
++	      cmdat, request->arg, request->rtype);
++
++        /* Start MMC/SD clock and send command to card */
++	jz_mmc_start_clock();
++
++	/* Wait for command completion */
++	while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES))
++		;
++
++	if (timeout == 0)
++		return MMC_ERROR_TIMEOUT;
++
++	REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear flag */
++
++	/* Check for status */
++	retval = jz_mmc_check_status(request);
++	if (retval) {
++		return retval;
++	}
++
++	/* Complete command with no response */
++	if (request->rtype == RESPONSE_NONE) {
++		return MMC_NO_ERROR;
++	}
++
++	/* Get response */
++	jz_mmc_get_response(request);
++
++	/* Start data operation */
++	if (events & (MMC_EVENT_RX_DATA_DONE | MMC_EVENT_TX_DATA_DONE)) {
++		if (events & MMC_EVENT_RX_DATA_DONE) {
++			if (request->cmd == SD_CMD_APP_SEND_SCR) {
++				/* SD card returns SCR register as data.
++				   MMC core expect it in the response buffer,
++				   after normal response. */
++				request->buffer = (u8 *)((u32)request->response + 5);
++			}
++			jz_mmc_receive_data(request);
++		}
++
++		if (events & MMC_EVENT_TX_DATA_DONE) {
++			jz_mmc_transmit_data(request);
++		}
++
++		/* Wait for Data Done */
++		while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE))
++			;
++		REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */
++	}
++
++	/* Wait for Prog Done event */
++	if (events & MMC_EVENT_PROG_DONE) {
++		while (!(REG_MSC_IREG & MSC_IREG_PRG_DONE))
++			;
++		REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */
++	}
++
++	/* Command completed */
++
++	return MMC_NO_ERROR;			 /* return successfully */
++}
++
++int mmc_block_read(u8 *dst, ulong src, ulong len)
++{
++
++	struct mmc_request request;
++	struct mmc_response_r1 r1;
++	int retval = 0;
++
++	if (len == 0)
++		goto exit;
++
++	mmc_simple_cmd(&request, MMC_CMD_SEND_STATUS, mmcinfo.rca, RESPONSE_R1);
++	retval = mmc_unpack_r1(&request, &r1, 0);
++	if (retval && (retval != MMC_ERROR_STATE_MISMATCH))
++		goto exit;
++
++	mmc_simple_cmd(&request, MMC_CMD_SET_BLOCKLEN, len, RESPONSE_R1);
++	if (retval = mmc_unpack_r1(&request, &r1, 0))
++		goto exit;
++
++	if (!sd2_0)
++		src *= mmcinfo.block_len;
++
++	mmc_send_cmd(&request, MMC_CMD_READ_SINGLE_BLOCK, src, 1, len, RESPONSE_R1, dst);
++	if (retval = mmc_unpack_r1(&request, &r1, 0))
++		goto exit;
++
++exit:
++	return retval;
++}
++
++ulong mmc_bread(int dev_num, ulong blkstart, ulong blkcnt, ulong *dst)
++{
++	if (!mmc_ready) {
++		printf("Please initial the MMC first\n");
++		return -1;
++	}
++
++	int i = 0;
++	ulong dst_tmp = dst;
++ 
++	for (i = 0; i < blkcnt; i++) {
++		if ((mmc_block_read((uchar *)(dst_tmp), blkstart, mmcinfo.block_len)) < 0)
++			return -1;
++
++		dst_tmp += mmcinfo.block_len;
++		blkstart++;
++	}
++ 
++	return i;
++}
++
++int mmc_select_card(void)
++{
++	struct mmc_request request;
++	struct mmc_response_r1 r1;
++	int retval;
++
++	mmc_simple_cmd(&request, MMC_CMD_SELECT_CARD, mmcinfo.rca, RESPONSE_R1B);
++	retval = mmc_unpack_r1(&request, &r1, 0);
++	if (retval) {
++		return retval;
++	}
++
++	if (mmcinfo.sd) {
++		mmc_simple_cmd(&request, MMC_CMD_APP_CMD,  mmcinfo.rca, RESPONSE_R1);
++		retval = mmc_unpack_r1(&request,&r1,0);
++		if (retval) {
++			return retval;
++		}
++#if defined(MMC_BUS_WIDTH_1BIT)		
++		mmc_simple_cmd(&request, SET_BUS_WIDTH, 1, RESPONSE_R1);
++#else
++		mmc_simple_cmd(&request, SET_BUS_WIDTH, 2, RESPONSE_R1);
++#endif
++                retval = mmc_unpack_r1(&request,&r1,0);
++                if (retval) {
++			return retval;
++		}
++	}
++	return 0;
++}
++
++/*
++ * Configure card
++ */
++static void mmc_configure_card(void)
++{
++	u32 rate;
++
++	/* Get card info */
++	if (sd2_0)
++		mmcinfo.block_num = (mmcinfo.csd.c_size + 1) << 10;
++	else
++		mmcinfo.block_num = (mmcinfo.csd.c_size + 1) * (1 << (mmcinfo.csd.c_size_mult + 2));
++
++	mmcinfo.block_len = 1 << mmcinfo.csd.read_bl_len;
++
++	mmc_dev.if_type = IF_TYPE_SD;
++	mmc_dev.part_type = PART_TYPE_DOS;
++	mmc_dev.dev = 0;
++	mmc_dev.lun = 0;
++	mmc_dev.type = 0;
++	mmc_dev.blksz = mmcinfo.block_len;
++	mmc_dev.lba = mmcinfo.block_num;
++	mmc_dev.removable = 0;
++
++	printf("%s Detected: %lu blocks of %lu bytes\n",
++	       sd2_0 == 1 ? "SDHC" : "SD",
++	       mmc_dev.lba,
++	       mmc_dev.blksz);
++
++	/* Fix the clock rate */
++	rate = mmc_tran_speed(mmcinfo.csd.tran_speed);
++	if (rate < MMC_CLOCK_SLOW)
++		rate = MMC_CLOCK_SLOW;
++	if ((mmcinfo.sd == 0) && (rate > MMC_CLOCK_FAST))
++		rate = MMC_CLOCK_FAST;
++        if ((mmcinfo.sd) && (rate > SD_CLOCK_FAST))
++		rate = SD_CLOCK_FAST;
++
++	debug("%s: block_len=%d block_num=%d rate=%d\n", 
++	      __func__, mmcinfo.block_len, mmcinfo.block_num, rate);
++
++	jz_mmc_set_clock(mmcinfo.sd, rate);
++}
++
++/*
++ * State machine routines to initialize card(s)
++ */
++
++/*
++  CIM_SINGLE_CARD_ACQ  (frequency at 400 kHz)
++  --- Must enter from GO_IDLE_STATE ---
++  1. SD_SEND_OP_COND (SD Card) [CMD55] + [CMD41]
++  2. SEND_OP_COND (Full Range) [CMD1]   {optional}
++  3. SEND_OP_COND (Set Range ) [CMD1]
++     If busy, delay and repeat step 2
++  4. ALL_SEND_CID              [CMD2]
++     If timeout, set an error (no cards found)
++  5. SET_RELATIVE_ADDR         [CMD3]
++  6. SEND_CSD                  [CMD9]
++  7. SET_DSR                   [CMD4]    Only call this if (csd.dsr_imp).
++  8. Set clock frequency (check available in csd.tran_speed)
++ */
++
++#define MMC_INIT_DOING   0
++#define MMC_INIT_PASSED  1
++#define MMC_INIT_FAILED  2
++
++static int mmc_init_card_state(struct mmc_request *request)
++{
++	struct mmc_response_r1 r1;
++	struct mmc_response_r3 r3;
++	int retval;
++	int ocr = 0x40300000;
++	int limit_41 = 0;
++
++	switch (request->cmd) {
++	case MMC_CMD_GO_IDLE_STATE: /* No response to parse */
++		if (mmcinfo.sd)
++			mmc_simple_cmd(request, 8, 0x1aa, RESPONSE_R1);
++		else
++			mmc_simple_cmd(request, MMC_CMD_SEND_OP_COND, MMC_OCR_ARG, RESPONSE_R3);
++		break;
++
++	case 8:
++        	retval = mmc_unpack_r1(request,&r1,mmcinfo.state);
++		mmc_simple_cmd(request, MMC_CMD_APP_CMD,  0, RESPONSE_R1);
++		break;
++
++        case MMC_CMD_APP_CMD:
++        	retval = mmc_unpack_r1(request,&r1,mmcinfo.state);
++		if (retval & (limit_41 < 100)) {
++			debug("%s: unable to MMC_APP_CMD error=%d (%s)\n", 
++			      __func__, retval, mmc_result_to_string(retval));
++			limit_41++;
++			mmc_simple_cmd(request, SD_CMD_APP_SEND_OP_COND, ocr, RESPONSE_R3);
++		} else if (limit_41 < 100) {
++			limit_41++;
++			mmc_simple_cmd(request, SD_CMD_APP_SEND_OP_COND, ocr, RESPONSE_R3);
++		} else{
++			/* reset the card to idle*/
++			mmc_simple_cmd(request, MMC_CMD_GO_IDLE_STATE, 0, RESPONSE_NONE);
++			mmcinfo.sd = 0;
++		}
++		break;
++
++        case SD_CMD_APP_SEND_OP_COND:
++                retval = mmc_unpack_r3(request, &r3);
++                if (retval) {
++			debug("%s: try MMC card\n", __func__);
++			mmc_simple_cmd(request, SD_CMD_APP_SEND_OP_COND, MMC_OCR_ARG, RESPONSE_R3);
++			break;
++		}
++
++                debug("%s: read ocr value = 0x%08x\n", __func__, r3.ocr);
++
++		if(!(r3.ocr & MMC_CARD_BUSY || ocr == 0)){
++			udelay(50000);
++			mmc_simple_cmd(request, MMC_CMD_APP_CMD, 0, RESPONSE_R1);
++		} else {
++			mmcinfo.sd = 1; /* SD Card ready */
++			mmcinfo.state = CARD_STATE_READY;
++			mmc_simple_cmd(request, MMC_CMD_ALL_SEND_CID, 0, RESPONSE_R2_CID);
++		}
++		break;
++
++	case MMC_CMD_SEND_OP_COND:
++		retval = mmc_unpack_r3(request, &r3);
++		if (retval) {
++			debug("%s: failed SEND_OP_COND error=%d (%s)\n", 
++			      __func__, retval, mmc_result_to_string(retval));
++			return MMC_INIT_FAILED;
++		}
++
++		debug("%s: read ocr value = 0x%08x\n", __func__, r3.ocr);
++		if (!(r3.ocr & MMC_CARD_BUSY)) {
++	                mmc_simple_cmd(request, MMC_CMD_SEND_OP_COND, MMC_OCR_ARG, RESPONSE_R3);
++		} else {
++		        mmcinfo.sd = 0; /* MMC Card ready */
++			mmcinfo.state = CARD_STATE_READY;
++			mmc_simple_cmd(request, MMC_CMD_ALL_SEND_CID, 0, RESPONSE_R2_CID);
++		}
++		break;
++
++	case MMC_CMD_ALL_SEND_CID: 
++		retval = mmc_unpack_cid( request, &mmcinfo.cid );
++		/*FIXME:ignore CRC error for CMD2/CMD9/CMD10 */
++		if ( retval && (retval != MMC_ERROR_CRC)) {
++			debug("mmc_init_card_state: unable to ALL_SEND_CID error=%d (%s)\n", 
++			      retval, mmc_result_to_string(retval));
++			return MMC_INIT_FAILED;
++		}
++		mmcinfo.state = CARD_STATE_IDENT;
++		if(mmcinfo.sd)
++			mmc_simple_cmd(request, MMC_CMD_SET_RELATIVE_ADDR, 0, RESPONSE_R6);
++                else
++			mmc_simple_cmd(request, MMC_CMD_SET_RELATIVE_ADDR, ID_TO_RCA(mmcinfo.id) << 16, RESPONSE_R1);
++		break;
++
++        case MMC_CMD_SET_RELATIVE_ADDR:
++	        if (mmcinfo.sd)	{
++			retval = mmc_unpack_r6(request, &r1, mmcinfo.state, &mmcinfo.rca);
++			mmcinfo.rca = mmcinfo.rca << 16; 
++			debug("%s: Get RCA from SD: 0x%04x Status: %x\n",
++			      __func__, mmcinfo.rca, r1.status);
++                } else {
++			retval = mmc_unpack_r1(request,&r1,mmcinfo.state);
++			mmcinfo.rca = ID_TO_RCA(mmcinfo.id) << 16;
++	        }
++		if (retval) {
++			debug("%s: unable to SET_RELATIVE_ADDR error=%d (%s)\n", 
++			      __func__, retval, mmc_result_to_string(retval));
++			return MMC_INIT_FAILED;
++		}
++
++		mmcinfo.state = CARD_STATE_STBY;
++                mmc_simple_cmd(request, MMC_CMD_SEND_CSD, mmcinfo.rca, RESPONSE_R2_CSD);
++
++		break;
++
++	case MMC_CMD_SEND_CSD:
++		retval = mmc_unpack_csd(request, &mmcinfo.csd);
++		mmc_ready = 1;
++		/*FIXME:ignore CRC error for CMD2/CMD9/CMD10 */
++	        if (retval && (retval != MMC_ERROR_CRC)) {
++			debug("%s: unable to SEND_CSD error=%d (%s)\n", 
++			      __func__, retval, mmc_result_to_string(retval));
++			return MMC_INIT_FAILED;
++		}
++		if (mmcinfo.csd.dsr_imp) {
++			debug("%s: driver doesn't support setting DSR\n", __func__);
++		}
++		mmc_configure_card();
++		return MMC_INIT_PASSED;
++
++	default:
++		debug("%s: error!  Illegal last cmd %d\n", __func__, request->cmd);
++		return MMC_INIT_FAILED;
++	}
++
++	return MMC_INIT_DOING;
++}
++
++int mmc_init_card(void)
++{
++	struct mmc_request request;
++	int retval;
++
++	mmc_simple_cmd(&request, MMC_CIM_RESET, 0, RESPONSE_NONE); /* reset card */
++	mmc_simple_cmd(&request, MMC_CMD_GO_IDLE_STATE, 0, RESPONSE_NONE);
++	mmcinfo.sd = 1;  /* assuming a SD card */
++
++	while ((retval = mmc_init_card_state(&request)) == MMC_INIT_DOING)
++		;
++
++	if (retval == MMC_INIT_PASSED)
++		return MMC_NO_ERROR;
++	else
++		return MMC_NO_RESPONSE;
++}
++
++int mmc_legacy_init(int verbose)
++{
++	if (!__msc_card_detected())
++		return 1;
++
++	/* Step-1: init GPIO */
++	__gpio_as_msc();
++	__msc_init_io();
++
++	/* Step-2: turn on power of card */
++#if !defined(CONFIG_SAKC)
++	__msc_enable_power();
++#endif
++
++	/* Step-3: Reset MSC Controller. */
++	__msc_reset();
++
++	/* Step-3: mask all IRQs. */
++	MMC_IRQ_MASK();
++
++	/* Step-4: stop MMC/SD clock */
++	jz_mmc_stop_clock();
++	mmc_init_card();
++	mmc_select_card();
++
++	mmc_dev.block_read = mmc_bread;
++	fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */
++
++	return 0;
++}
++
++/*
++ * Debugging functions
++ */
++static char * mmc_result_strings[] = {
++	"NO_RESPONSE",
++	"NO_ERROR",
++	"ERROR_OUT_OF_RANGE",
++	"ERROR_ADDRESS",
++	"ERROR_BLOCK_LEN",
++	"ERROR_ERASE_SEQ",
++	"ERROR_ERASE_PARAM",
++	"ERROR_WP_VIOLATION",
++	"ERROR_CARD_IS_LOCKED",
++	"ERROR_LOCK_UNLOCK_FAILED",
++	"ERROR_COM_CRC",
++	"ERROR_ILLEGAL_COMMAND",
++	"ERROR_CARD_ECC_FAILED",
++	"ERROR_CC",
++	"ERROR_GENERAL",
++	"ERROR_UNDERRUN",
++	"ERROR_OVERRUN",
++	"ERROR_CID_CSD_OVERWRITE",
++	"ERROR_STATE_MISMATCH",
++	"ERROR_HEADER_MISMATCH",
++	"ERROR_TIMEOUT",
++	"ERROR_CRC",
++	"ERROR_DRIVER_FAILURE",
++};
++
++char * mmc_result_to_string(int i)
++{
++	return mmc_result_strings[i+1];
++}
++
++static char * card_state_strings[] = {
++	"empty",
++	"idle",
++	"ready",
++	"ident",
++	"stby",
++	"tran",
++	"data",
++	"rcv",
++	"prg",
++	"dis",
++};
++
++static inline char * card_state_to_string(int i)
++{
++	return card_state_strings[i+1];
++}
++
++/*
++ * Utility functions
++ */
++
++#define PARSE_U32(_buf,_index) \
++	(((u32)_buf[_index]) << 24) | (((u32)_buf[_index+1]) << 16) | \
++        (((u32)_buf[_index+2]) << 8) | ((u32)_buf[_index+3]);
++
++#define PARSE_U16(_buf,_index) \
++	(((u16)_buf[_index]) << 8) | ((u16)_buf[_index+1]);
++
++int mmc_unpack_csd(struct mmc_request *request, struct mmc_csd *csd)
++{
++	u8 *buf = request->response;
++	int num = 0;
++
++	if (request->result)
++		return request->result;
++
++	if (buf[0] != 0x3f)
++		return MMC_ERROR_HEADER_MISMATCH;
++
++	csd->csd_structure = (buf[1] & 0xc0) >> 6;
++	if (csd->csd_structure)
++		sd2_0 = 1;
++	else
++		sd2_0 = 0;
++
++	switch (csd->csd_structure) {
++	case 0 :/* Version 1.01-1.10
++		 * Version 2.00/Standard Capacity */
++		csd->taac               = buf[2];
++		csd->nsac               = buf[3];
++		csd->tran_speed         = buf[4];
++		csd->ccc                = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);
++		csd->read_bl_len        = buf[6] & 0x0f;
++		/* for support 2GB card*/
++		if (csd->read_bl_len >= 10)
++		{
++			num = csd->read_bl_len - 9;
++			csd->read_bl_len = 9;
++		}
++
++		csd->read_bl_partial    = (buf[7] & 0x80) ? 1 : 0;
++		csd->write_blk_misalign = (buf[7] & 0x40) ? 1 : 0;
++		csd->read_blk_misalign  = (buf[7] & 0x20) ? 1 : 0;
++		csd->dsr_imp            = (buf[7] & 0x10) ? 1 : 0;
++		csd->c_size             = ((((u16)buf[7]) & 0x03) << 10) | (((u16)buf[8]) << 2) | (((u16)buf[9]) & 0xc0) >> 6;
++
++		if (num)
++			csd->c_size = csd->c_size << num;
++
++
++		csd->vdd_r_curr_min     = (buf[9] & 0x38) >> 3;
++		csd->vdd_r_curr_max     = buf[9] & 0x07;
++		csd->vdd_w_curr_min     = (buf[10] & 0xe0) >> 5;
++		csd->vdd_w_curr_max     = (buf[10] & 0x1c) >> 2;
++		csd->c_size_mult        = ((buf[10] & 0x03) << 1) | ((buf[11] & 0x80) >> 7);
++		csd->sector_size    = (buf[11] & 0x7c) >> 2;
++		csd->erase_grp_size = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);
++		csd->wp_grp_size        = buf[12] & 0x1f;
++		csd->wp_grp_enable      = (buf[13] & 0x80) ? 1 : 0;
++		csd->default_ecc        = (buf[13] & 0x60) >> 5;
++		csd->r2w_factor         = (buf[13] & 0x1c) >> 2;
++		csd->write_bl_len       = ((buf[13] & 0x03) << 2) | ((buf[14] & 0xc0) >> 6);
++		if (csd->write_bl_len >= 10)
++			csd->write_bl_len = 9;
++
++		csd->write_bl_partial   = (buf[14] & 0x20) ? 1 : 0;
++		csd->file_format_grp    = (buf[15] & 0x80) ? 1 : 0;
++		csd->copy               = (buf[15] & 0x40) ? 1 : 0;
++		csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;
++		csd->tmp_write_protect  = (buf[15] & 0x10) ? 1 : 0;
++		csd->file_format        = (buf[15] & 0x0c) >> 2;
++		csd->ecc                = buf[15] & 0x03;
++		break;
++	case 1 :	/* Version 2.00/High Capacity */
++		csd->taac               = 0;
++		csd->nsac               = 0;
++		csd->tran_speed         = buf[4];
++		csd->ccc                = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);
++
++		csd->read_bl_len        = 9;
++		csd->read_bl_partial    = 0;
++		csd->write_blk_misalign = 0;
++		csd->read_blk_misalign  = 0;
++		csd->dsr_imp            = (buf[7] & 0x10) ? 1 : 0;
++		csd->c_size             = ((((u16)buf[8]) & 0x3f) << 16) | (((u16)buf[9]) << 8) | ((u16)buf[10]) ;
++		csd->sector_size	= 0x7f;
++		csd->erase_grp_size	= 0;
++		csd->wp_grp_size        = 0;
++		csd->wp_grp_enable      = 0;
++		csd->default_ecc        = (buf[13] & 0x60) >> 5;
++		csd->r2w_factor         = 4;/* Unused */
++		csd->write_bl_len       = 9;
++
++		csd->write_bl_partial   = 0;
++		csd->file_format_grp    = 0;
++		csd->copy               = (buf[15] & 0x40) ? 1 : 0;
++		csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;
++		csd->tmp_write_protect  = (buf[15] & 0x10) ? 1 : 0;
++		csd->file_format        = 0;
++		csd->ecc                = buf[15] & 0x03;
++	}
++
++	return 0;
++}
++
++int mmc_unpack_r1(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state)
++{
++	u8 *buf = request->response;
++
++	if (request->result)
++		return request->result;
++
++	r1->cmd    = buf[0];
++	r1->status = PARSE_U32(buf,1);
++
++	debug("mmc_unpack_r1: cmd=%d status=%08x\n", r1->cmd, r1->status);
++
++	if (R1_STATUS(r1->status)) {
++		if (r1->status & R1_OUT_OF_RANGE)       return MMC_ERROR_OUT_OF_RANGE;
++		if (r1->status & R1_ADDRESS_ERROR)      return MMC_ERROR_ADDRESS;
++		if (r1->status & R1_BLOCK_LEN_ERROR)    return MMC_ERROR_BLOCK_LEN;
++		if (r1->status & R1_ERASE_SEQ_ERROR)    return MMC_ERROR_ERASE_SEQ;
++		if (r1->status & R1_ERASE_PARAM)        return MMC_ERROR_ERASE_PARAM;
++		if (r1->status & R1_WP_VIOLATION)       return MMC_ERROR_WP_VIOLATION;
++		/*if (r1->status & R1_CARD_IS_LOCKED)     return MMC_ERROR_CARD_IS_LOCKED; */
++		if (r1->status & R1_LOCK_UNLOCK_FAILED) return MMC_ERROR_LOCK_UNLOCK_FAILED;
++		if (r1->status & R1_COM_CRC_ERROR)      return MMC_ERROR_COM_CRC;
++		if (r1->status & R1_ILLEGAL_COMMAND)    return MMC_ERROR_ILLEGAL_COMMAND;
++		if (r1->status & R1_CARD_ECC_FAILED)    return MMC_ERROR_CARD_ECC_FAILED;
++		if (r1->status & R1_CC_ERROR)           return MMC_ERROR_CC;
++		if (r1->status & R1_ERROR)              return MMC_ERROR_GENERAL;
++		if (r1->status & R1_UNDERRUN)           return MMC_ERROR_UNDERRUN;
++		if (r1->status & R1_OVERRUN)            return MMC_ERROR_OVERRUN;
++		if (r1->status & R1_CID_CSD_OVERWRITE)  return MMC_ERROR_CID_CSD_OVERWRITE;
++	}
++
++	if (buf[0] != request->cmd) 
++		return MMC_ERROR_HEADER_MISMATCH;
++
++	/* This should be last - it's the least dangerous error */
++
++	return 0;
++}
++
++int mmc_unpack_scr(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, u32 *scr)
++{
++        u8 *buf = request->response;
++	if (request->result)
++		return request->result;
++
++        *scr = PARSE_U32(buf, 5); /* Save SCR returned by the SD Card */
++        return mmc_unpack_r1(request, r1, state);
++
++}
++
++int mmc_unpack_r6(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, int *rca)
++{
++	u8 *buf = request->response;
++
++	if (request->result)
++		return request->result;
++
++        *rca = PARSE_U16(buf,1);  /* Save RCA returned by the SD Card */
++
++        *(buf+1) = 0;
++        *(buf+2) = 0;
++
++        return mmc_unpack_r1(request, r1, state);
++}
++
++int mmc_unpack_cid(struct mmc_request *request, struct mmc_cid *cid)
++{
++	int i;
++	u8 *buf = request->response;
++
++	if (request->result) 
++		return request->result;
++
++	cid->mid = buf[1];
++	cid->oid = PARSE_U16(buf,2);
++	for (i = 0 ; i < 5 ; i++)
++		cid->pnm[i] = buf[4+i];
++	cid->pnm[6] = 0;
++	cid->prv = buf[10];
++	cid->psn = PARSE_U32(buf,10);
++	cid->mdt = buf[15];
++
++	printf("Man %02x OEM 0x%04x \"%s\" %d.%d 0x%08x "
++	       "Date %02u/%04u\n",
++	       cid->mid,
++	       cid->oid,
++	       cid->pnm, 
++	       cid->prv >> 4,
++	       cid->prv & 0xf, 
++	       cid->psn,
++	       cid->mdt & 0xf,
++	       (cid->mdt >> 4) + 2000);
++
++	if (buf[0] != 0x3f)
++		return MMC_ERROR_HEADER_MISMATCH;
++      	return 0;
++}
++
++int mmc_unpack_r3(struct mmc_request *request, struct mmc_response_r3 *r3)
++{
++	u8 *buf = request->response;
++
++	if (request->result)
++		return request->result;
++
++	r3->ocr = PARSE_U32(buf,1);
++	debug("mmc_unpack_r3: ocr=%08x\n", r3->ocr);
++
++	if (buf[0] != 0x3f)  return MMC_ERROR_HEADER_MISMATCH;
++	return 0;
++}
++
++#define KBPS 1
++#define MBPS 1000
++
++static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };
++static u32 ts_mul[] = { 0,    1000, 1200, 1300, 1500, 2000, 2500, 3000, 
++			3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };
++
++u32 mmc_tran_speed(u8 ts)
++{
++	u32 rate = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3];
++
++	if (rate <= 0) {
++		debug("%s: error - unrecognized speed 0x%02x\n", __func__, ts);
++		return 1;
++	}
++
++	return rate;
++}
++
++void mmc_send_cmd(struct mmc_request *request, int cmd, u32 arg, 
++		  u16 nob, u16 block_len, enum mmc_rsp_t rtype, u8 *buffer)
++{
++	request->cmd       = cmd;
++	request->arg       = arg;
++	request->rtype     = rtype;
++	request->nob       = nob;
++	request->block_len = block_len;
++	request->buffer    = buffer;
++	request->cnt       = nob * block_len;
++
++	jz_mmc_exec_cmd(request);
++}
+diff --git a/drivers/mmc/jz_mmc.h b/drivers/mmc/jz_mmc.h
+new file mode 100644
+index 0000000..936c514
+--- /dev/null
++++ b/drivers/mmc/jz_mmc.h
+@@ -0,0 +1,176 @@
++/*
++ *  linux/drivers/mmc/jz_mmc.h
++ *
++ *  Author: Vladimir Shebordaev, Igor Oblakov
++ *  Copyright:  MontaVista Software Inc.
++ *
++ *  $Id: jz_mmc.h,v 1.3 2007-06-15 08:04:20 jlwei Exp $
++ *
++ *  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.
++ */
++#ifndef __MMC_JZMMC_H__
++#define __MMC_JZMMC_H__
++
++#define ID_TO_RCA(x) ((x)+1)
++#define MMC_OCR_ARG		0x00ff8000	/* Argument of OCR */
++
++/* Standard MMC/SD clock speeds */
++#define MMC_CLOCK_SLOW    400000      /* 400 kHz for initial setup */
++#define MMC_CLOCK_FAST  20000000      /* 20 MHz for maximum for normal operation */
++#define SD_CLOCK_FAST   24000000      /* 24 MHz for SD Cards */
++
++/* Use negative numbers to disambiguate */
++#define MMC_CIM_RESET            -1
++#define SET_BUS_WIDTH            6    /* ac   [1:0] bus width    R1  */    
++
++#define R1_OUT_OF_RANGE		(1 << 31)	/* er, c */
++#define R1_ADDRESS_ERROR	(1 << 30)	/* erx, c */
++#define R1_BLOCK_LEN_ERROR	(1 << 29)	/* er, c */
++#define R1_ERASE_SEQ_ERROR      (1 << 28)	/* er, c */
++#define R1_ERASE_PARAM		(1 << 27)	/* ex, c */
++#define R1_WP_VIOLATION		(1 << 26)	/* erx, c */
++#define R1_CARD_IS_LOCKED	(1 << 25)	/* sx, a */
++#define R1_LOCK_UNLOCK_FAILED	(1 << 24)	/* erx, c */
++#define R1_COM_CRC_ERROR	(1 << 23)	/* er, b */
++#define R1_ILLEGAL_COMMAND	(1 << 22)	/* er, b */
++#define R1_CARD_ECC_FAILED	(1 << 21)	/* ex, c */
++#define R1_CC_ERROR		(1 << 20)	/* erx, c */
++#define R1_ERROR		(1 << 19)	/* erx, c */
++#define R1_UNDERRUN		(1 << 18)	/* ex, c */
++#define R1_OVERRUN		(1 << 17)	/* ex, c */
++#define R1_CID_CSD_OVERWRITE	(1 << 16)	/* erx, c, CID/CSD overwrite */
++#define R1_WP_ERASE_SKIP	(1 << 15)	/* sx, c */
++#define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
++#define R1_ERASE_RESET		(1 << 13)	/* sr, c */
++#define R1_STATUS(x)            (x & 0xFFFFE000)
++
++#define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
++
++#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
++#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
++
++#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
++#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
++#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
++#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
++#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
++#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
++
++
++enum mmc_result_t {
++	MMC_NO_RESPONSE        = -1,
++	MMC_NO_ERROR           = 0,
++	MMC_ERROR_OUT_OF_RANGE,
++	MMC_ERROR_ADDRESS,
++	MMC_ERROR_BLOCK_LEN,
++	MMC_ERROR_ERASE_SEQ,
++	MMC_ERROR_ERASE_PARAM,
++	MMC_ERROR_WP_VIOLATION,
++	MMC_ERROR_CARD_IS_LOCKED,
++	MMC_ERROR_LOCK_UNLOCK_FAILED,
++	MMC_ERROR_COM_CRC,
++	MMC_ERROR_ILLEGAL_COMMAND,
++	MMC_ERROR_CARD_ECC_FAILED,
++	MMC_ERROR_CC,
++	MMC_ERROR_GENERAL,
++	MMC_ERROR_UNDERRUN,
++	MMC_ERROR_OVERRUN,
++	MMC_ERROR_CID_CSD_OVERWRITE,
++	MMC_ERROR_STATE_MISMATCH,
++	MMC_ERROR_HEADER_MISMATCH,
++	MMC_ERROR_TIMEOUT,
++	MMC_ERROR_CRC,
++	MMC_ERROR_DRIVER_FAILURE,
++};
++
++enum card_state {
++	CARD_STATE_EMPTY = -1,
++	CARD_STATE_IDLE	 = 0,
++	CARD_STATE_READY = 1,
++	CARD_STATE_IDENT = 2,
++	CARD_STATE_STBY	 = 3,
++	CARD_STATE_TRAN	 = 4,
++	CARD_STATE_DATA	 = 5,
++	CARD_STATE_RCV	 = 6,
++	CARD_STATE_PRG	 = 7,
++	CARD_STATE_DIS	 = 8,
++};
++
++enum mmc_rsp_t {
++	RESPONSE_NONE   = 0,
++	RESPONSE_R1     = 1,
++	RESPONSE_R1B    = 2,
++	RESPONSE_R2_CID = 3,
++	RESPONSE_R2_CSD  = 4,
++	RESPONSE_R3      = 5,
++	RESPONSE_R4      = 6,
++	RESPONSE_R5      = 7,
++        RESPONSE_R6      = 8,
++};
++
++struct mmc_response_r1 {
++	u8  cmd;
++	u32 status;
++};
++
++struct mmc_response_r3 {  
++	u32 ocr;
++}; 
++
++/* the information structure of MMC/SD Card */
++struct  mmc_info {
++	int             id;     /* Card index */
++        int             sd;     /* MMC or SD card */
++        int             rca;    /* RCA */
++        u32             scr;    /* SCR 63:32*/
++	int             flags;  /* Ejected, inserted */
++	enum card_state state;  /* empty, ident, ready, whatever */
++
++	/* Card specific information */
++	struct mmc_cid  cid;
++	struct mmc_csd  csd;
++	u32             block_num;
++	u32             block_len;
++	u32             erase_unit;
++};
++
++struct mmc_info mmcinfo;
++
++struct mmc_request {
++	int               index;      /* Slot index - used for CS lines */
++	int               cmd;        /* Command to send */
++	u32               arg;        /* Argument to send */
++	enum mmc_rsp_t    rtype;      /* Response type expected */
++
++	/* Data transfer (these may be modified at the low level) */
++	u16               nob;        /* Number of blocks to transfer*/
++	u16               block_len;  /* Block length */
++	u8               *buffer;     /* Data buffer */
++	u32               cnt;        /* Data length, for PIO */
++
++	/* Results */
++	u8                response[18]; /* Buffer to store response - CRC is optional */
++	enum mmc_result_t result;
++};
++
++char * mmc_result_to_string(int);
++int    mmc_unpack_csd(struct mmc_request *request, struct mmc_csd *csd);
++int    mmc_unpack_r1(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state);
++int    mmc_unpack_r6(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, int *rca);
++int    mmc_unpack_scr(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, u32 *scr);
++int    mmc_unpack_cid(struct mmc_request *request, struct mmc_cid *cid);
++int    mmc_unpack_r3(struct mmc_request *request, struct mmc_response_r3 *r3);
++
++void   mmc_send_cmd(struct mmc_request *request, int cmd, u32 arg, 
++		     u16 nob, u16 block_len, enum mmc_rsp_t rtype, u8 *buffer);
++u32    mmc_tran_speed(u8 ts);
++void   jz_mmc_set_clock(int sd, u32 rate);
++
++static inline void mmc_simple_cmd(struct mmc_request *request, int cmd, u32 arg, enum mmc_rsp_t rtype)
++{
++	mmc_send_cmd( request, cmd, arg, 0, 0, rtype, 0);
++}
++
++#endif /* __MMC_JZMMC_H__ */
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 7bff444..7b33be0 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -31,6 +31,15 @@
+ /*
+  * Miscellaneous configurable options
+  */
++#define CONFIG_JZ4740_MMC
++#define CONFIG_MMC      	1
++#define CONFIG_FAT      	1
++#define CONFIG_DOS_PARTITION	1
++#define CONFIG_CMD_MMC
++#define CONFIG_CMD_FAT
++#define CONFIG_CMD_EXT2
++
++
+ #define CONFIG_SYS_SDRAM_BASE		0x80000000	/* Cached addr */
+ #define CONFIG_SYS_INIT_SP_OFFSET	0x400000
+ #define CONFIG_SYS_LOAD_ADDR		0x80600000
+diff --git a/include/mmc.h b/include/mmc.h
+index a13e2bd..3c4761c 100644
+--- a/include/mmc.h
++++ b/include/mmc.h
+@@ -283,4 +283,44 @@ struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
+ int mmc_legacy_init(int verbose);
+ #endif
+ 
++struct mmc_csd
++{
++	u8	csd_structure:2,
++		spec_vers:4,
++		rsvd1:2;
++	u8	taac;
++	u8	nsac;
++	u8	tran_speed;
++	u16	ccc:12,
++		read_bl_len:4;
++	u32	c_size:22;
++	u64	read_bl_partial:1,
++		write_blk_misalign:1,
++		read_blk_misalign:1,
++		dsr_imp:1,
++		rsvd2:2,
++		vdd_r_curr_min:3,
++		vdd_r_curr_max:3,
++		vdd_w_curr_min:3,
++		vdd_w_curr_max:3,
++		c_size_mult:3,
++		sector_size:5,
++		erase_grp_size:5,
++		wp_grp_size:5,
++		wp_grp_enable:1,
++		default_ecc:2,
++		r2w_factor:3,
++		write_bl_len:4,
++		write_bl_partial:1,
++		rsvd3:5;
++	u8	file_format_grp:1,
++		copy:1,
++		perm_write_protect:1,
++		tmp_write_protect:1,
++		file_format:2,
++		ecc:2;
++	u8	crc:7;
++	u8	one:1;
++};
++
+ #endif /* _MMC_H_ */
+-- 
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch b/package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch
new file mode 100644
index 0000000000..73e03243c3
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch
@@ -0,0 +1,200 @@
+From c52b6168979d03fc31205444c3278c537787472a Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 18:39:55 +0800
+Subject: [PATCH 4/6] add more boot options(F1/F2/F3/F4/M/S)
+
+---
+ arch/mips/include/asm/global_data.h |    3 +++
+ arch/mips/lib/bootm.c               |   17 ++++++++++++++++-
+ board/qi/qi_lb60/qi_lb60.c          |   26 +++++++++++++++++++++++---
+ common/main.c                       |   21 +++++++++++++++++++--
+ include/configs/qi_lb60.h           |   32 ++++++++++++++++++++++++++++++++
+ 5 files changed, 93 insertions(+), 6 deletions(-)
+
+diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
+index 6e2cdc7..cd03d7e 100644
+--- a/arch/mips/include/asm/global_data.h
++++ b/arch/mips/include/asm/global_data.h
+@@ -59,6 +59,9 @@ typedef	struct	global_data {
+ 	unsigned long	env_valid;	/* Checksum of Environment valid? */
+ 	void		**jt;		/* jump table */
+ 	char		env_buf[32];	/* buffer for getenv() before reloc. */
++#if defined(CONFIG_NANONOTE)
++        unsigned long   boot_option;
++#endif
+ } gd_t;
+ 
+ #include <asm-generic/global_data_flags.h>
+diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c
+index 608c1a7..e00416b 100644
+--- a/arch/mips/lib/bootm.c
++++ b/arch/mips/lib/bootm.c
+@@ -47,10 +47,25 @@ int do_bootm_linux(int flag, int argc, char * const argv[],
+ 			bootm_headers_t *images)
+ {
+ 	void (*theKernel) (int, char **, char **, int *);
+-	char *commandline = getenv("bootargs");
++	char *commandline;
+ 	char env_buf[12];
+ 	char *cp;
+ 
++#if defined(CONFIG_NANONOTE)
++        if (gd->boot_option & BOOT_FROM_MEMCARD)
++                commandline = getenv ("bootargsfromsd");
++        else if (gd->boot_option & BOOT_WITH_F1)
++                commandline = getenv ("bootargsf1");
++        else if (gd->boot_option & BOOT_WITH_F2)
++                commandline = getenv ("bootargsf2");
++        else if (gd->boot_option & BOOT_WITH_F3)
++                commandline = getenv ("bootargsf3");
++        else if (gd->boot_option & BOOT_WITH_F4)
++                commandline = getenv ("bootargsf4");
++        else
++#endif
++                commandline = getenv ("bootargs");
++
+ 	if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ 		return 1;
+ 
+diff --git a/board/qi/qi_lb60/qi_lb60.c b/board/qi/qi_lb60/qi_lb60.c
+index a2ba648..d622219 100644
+--- a/board/qi/qi_lb60/qi_lb60.c
++++ b/board/qi/qi_lb60/qi_lb60.c
+@@ -15,7 +15,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ 
+ static void gpio_init(void)
+ {
+-	unsigned int i;
++	unsigned int i, j;
+ 
+ 	/* Initialize NAND Flash Pins */
+ 	__gpio_as_nand();
+@@ -42,14 +42,34 @@ static void gpio_init(void)
+ 
+ 	if (__gpio_get_pin(GPIO_KEYIN_BASE + 2) == 0){
+ 		printf("[S] pressed, enable UART0\n");
++		gd->boot_option |= BOOT_WITH_ENABLE_UART;
+ 		__gpio_as_uart0();
+ 	} else {
+ 		__gpio_as_input(GPIO_KEYIN_8);
+ 		__gpio_enable_pull(GPIO_KEYIN_8);
+ 	}
+ 
+-	/* enable the TP4, TP5 as UART0 */
+-	__gpio_jtag_to_uart0();
++	if (__gpio_get_pin(GPIO_KEYIN_BASE + 3) == 0) {
++		printf("[M] pressed, boot from memory card\n");
++		gd->boot_option |= BOOT_FROM_MEMCARD;
++		__gpio_jtag_to_uart0();
++	}
++
++	for (j = 0; j < 4; j++) {
++		for (i = 0; i < 4; i++)
++			__gpio_set_pin(GPIO_KEYOUT_BASE + i);
++
++		__gpio_clear_pin(GPIO_KEYOUT_BASE + j);
++
++		if (__gpio_get_pin(GPIO_KEYIN_BASE) == 0) {
++			printf("[F%d] pressed", (j + 1));
++			gd->boot_option |= (1 << (j + 2));
++			/* BOOT_WITH_F1	(1 << 2) */
++			/* BOOT_WITH_F2	(1 << 3) */
++			/* BOOT_WITH_F3	(1 << 4) */
++			/* BOOT_WITH_F4	(1 << 5) */
++		}
++	}
+ 
+ 	__gpio_as_output(GPIO_AUDIO_POP);
+ 	__gpio_set_pin(GPIO_AUDIO_POP);
+diff --git a/common/main.c b/common/main.c
+index 9507cec..dbfb7ca 100644
+--- a/common/main.c
++++ b/common/main.c
+@@ -355,7 +355,11 @@ void main_loop (void)
+ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ 	s = getenv ("bootdelay");
+ 	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+-
++#if defined(CONFIG_NANONOTE)
++	DECLARE_GLOBAL_DATA_PTR;
++	if (gd->boot_option & BOOT_WITH_ENABLE_UART)
++		bootdelay = 3;
++# endif
+ 	debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+ 
+ #if defined(CONFIG_MENU_SHOW)
+@@ -379,7 +383,20 @@ void main_loop (void)
+ 	}
+ 	else
+ #endif /* CONFIG_BOOTCOUNT_LIMIT */
+-		s = getenv ("bootcmd");
++#if defined(CONFIG_NANONOTE)
++		if (gd->boot_option & BOOT_FROM_MEMCARD)
++			s = getenv ("bootcmdfromsd");
++		else if (gd->boot_option & BOOT_WITH_F1)
++			s = getenv ("bootcmdf1");
++		else if (gd->boot_option & BOOT_WITH_F2)
++			s = getenv ("bootcmdf2");
++		else if (gd->boot_option & BOOT_WITH_F3)
++			s = getenv ("bootcmdf3");
++		else if (gd->boot_option & BOOT_WITH_F4)
++			s = getenv ("bootcmdf4");
++		else
++#endif
++			s = getenv ("bootcmd");
+ 
+ 	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
+ 
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 7b33be0..52b370c 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -31,6 +31,7 @@
+ /*
+  * Miscellaneous configurable options
+  */
++#define CONFIG_NANONOTE
+ #define CONFIG_JZ4740_MMC
+ #define CONFIG_MMC      	1
+ #define CONFIG_FAT      	1
+@@ -39,6 +40,37 @@
+ #define CONFIG_CMD_FAT
+ #define CONFIG_CMD_EXT2
+ 
++#define CONFIG_CMD_UBIFS
++#define CONFIG_CMD_UBI
++#define CONFIG_MTD_PARTITIONS
++#define CONFIG_MTD_DEVICE
++#define CONFIG_CMD_MTDPARTS
++#define CONFIG_CMD_UBI
++#define CONFIG_CMD_UBIFS
++#define CONFIG_LZO
++#define CONFIG_RBTREE
++
++#define MTDIDS_DEFAULT		"nand0=jz4740-nand"
++#define MTDPARTS_DEFAULT	"mtdparts=jz4740-nand:4M@0(uboot)ro,4M@4M(kernel)ro,512M@8M(rootfs)ro,-(data)ro"
++
++#define BOOT_FROM_MEMCARD	1
++#define BOOT_WITH_ENABLE_UART	(1 << 1)	/* Vaule for global_data.h gd->boot_option */
++#define BOOT_WITH_F1		(1 << 2)
++#define BOOT_WITH_F2		(1 << 3)
++#define BOOT_WITH_F3		(1 << 4)
++#define BOOT_WITH_F4		(1 << 5)
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	"bootcmdfromsd=mmc init; ext2load mmc 0 0x80600000 /boot/uImage; bootm;\0" \
++	"bootargsfromsd=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p1 rw rootwait\0" \
++	"bootcmdf1=mmc init; ext2load mmc 0:1 0x80600000 /boot/uImage; bootm;\0" \
++	"bootargsf1=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p1 rw rootwait\0" \
++	"bootcmdf2=mmc init; ext2load mmc 0:2 0x80600000 /boot/uImage; bootm;\0" \
++	"bootargsf2=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p2 rw rootwait\0" \
++	"bootcmdf3=mmc init; ext2load mmc 0:3 0x80600000 /boot/uImage; bootm;\0" \
++	"bootargsf3=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p3 rw rootwait\0" \
++	"bootcmdf4=mtdparts default;ubi part rootfs;ubifsmount rootfs;ubifsload 0x80600000 /boot/uImage; bootm;\0" \
++	"bootargsf4=mem=32M console=tty0 console=ttyS0,57600n8 ubi.mtd=2 rootfstype=ubifs root=ubi0:rootfs rw rootwait"
+ 
+ #define CONFIG_SYS_SDRAM_BASE		0x80000000	/* Cached addr */
+ #define CONFIG_SYS_INIT_SP_OFFSET	0x400000
+-- 
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch b/package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch
new file mode 100644
index 0000000000..2c550f7205
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch
@@ -0,0 +1,847 @@
+From ca8c5216cfd3ad3fda9867ed2d157ae5a209834b Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 22:05:27 +0800
+Subject: [PATCH 5/6] add nanonote lcd support
+
+---
+ arch/mips/include/asm/global_data.h |    1 +
+ arch/mips/include/asm/jz4740.h      |   90 ++++++++
+ arch/mips/lib/board.c               |    6 +
+ common/lcd.c                        |    9 +-
+ drivers/video/Makefile              |    1 +
+ drivers/video/nanonote_gpm940b0.c   |  400 +++++++++++++++++++++++++++++++++++
+ drivers/video/nanonote_gpm940b0.h   |  135 ++++++++++++
+ include/configs/qi_lb60.h           |    7 +
+ include/lcd.h                       |   52 ++++-
+ 9 files changed, 697 insertions(+), 4 deletions(-)
+ create mode 100644 drivers/video/nanonote_gpm940b0.c
+ create mode 100644 drivers/video/nanonote_gpm940b0.h
+
+diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
+index cd03d7e..7cec2de 100644
+--- a/arch/mips/include/asm/global_data.h
++++ b/arch/mips/include/asm/global_data.h
+@@ -44,6 +44,7 @@ typedef	struct	global_data {
+ 	unsigned long	per_clk;	/* Peripheral bus clock */
+ 	unsigned long	mem_clk;	/* Memory bus clock */
+ 	unsigned long	dev_clk;	/* Device clock */
++        unsigned long   fb_base;        /* base address of framebuffer */
+ 	/* "static data" needed by most of timer.c */
+ 	unsigned long	tbl;
+ 	unsigned long	lastinc;
+diff --git a/arch/mips/include/asm/jz4740.h b/arch/mips/include/asm/jz4740.h
+index 68287fb..13724a2 100644
+--- a/arch/mips/include/asm/jz4740.h
++++ b/arch/mips/include/asm/jz4740.h
+@@ -1312,5 +1312,95 @@ do { 								\
+  	while (REG_MSC_STAT & MSC_STAT_IS_RESETTING);		\
+ } while (0)
+ 
++/*************************************************************************
++ * LCD (LCD Controller)
++ *************************************************************************/
++#define REG32(addr)	*((volatile u32 *)(addr))
++
++#define	CPM_BASE	0xB0000000
++#define CPM_CPCCR	(CPM_BASE+0x00)
++#define REG_CPM_CPCCR	REG32(CPM_CPCCR)
++
++#define	LCD_BASE	0xB3050000
++#define LCD_CFG		(LCD_BASE + 0x00) /* LCD Configure Register */
++#define LCD_VSYNC	(LCD_BASE + 0x04) /* Vertical Synchronize Register */
++#define LCD_HSYNC	(LCD_BASE + 0x08) /* Horizontal Synchronize Register */
++#define LCD_VAT		(LCD_BASE + 0x0c) /* Virtual Area Setting Register */
++#define LCD_DAH		(LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */
++#define LCD_DAV		(LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */
++#define LCD_PS		(LCD_BASE + 0x18) /* PS Signal Setting */
++#define LCD_CLS		(LCD_BASE + 0x1c) /* CLS Signal Setting */
++#define LCD_SPL		(LCD_BASE + 0x20) /* SPL Signal Setting */
++#define LCD_REV		(LCD_BASE + 0x24) /* REV Signal Setting */
++#define LCD_CTRL	(LCD_BASE + 0x30) /* LCD Control Register */
++#define LCD_STATE	(LCD_BASE + 0x34) /* LCD Status Register */
++#define LCD_IID		(LCD_BASE + 0x38) /* Interrupt ID Register */
++#define LCD_DA0		(LCD_BASE + 0x40) /* Descriptor Address Register 0 */
++#define LCD_SA0		(LCD_BASE + 0x44) /* Source Address Register 0 */
++#define LCD_FID0	(LCD_BASE + 0x48) /* Frame ID Register 0 */
++#define LCD_CMD0	(LCD_BASE + 0x4c) /* DMA Command Register 0 */
++#define LCD_DA1		(LCD_BASE + 0x50) /* Descriptor Address Register 1 */
++#define LCD_SA1		(LCD_BASE + 0x54) /* Source Address Register 1 */
++#define LCD_FID1	(LCD_BASE + 0x58) /* Frame ID Register 1 */
++#define LCD_CMD1	(LCD_BASE + 0x5c) /* DMA Command Register 1 */
++
++#define REG_LCD_CFG	REG32(LCD_CFG)
++#define REG_LCD_VSYNC	REG32(LCD_VSYNC)
++#define REG_LCD_HSYNC	REG32(LCD_HSYNC)
++#define REG_LCD_VAT	REG32(LCD_VAT)
++#define REG_LCD_DAH	REG32(LCD_DAH)
++#define REG_LCD_DAV	REG32(LCD_DAV)
++#define REG_LCD_PS	REG32(LCD_PS)
++#define REG_LCD_CLS	REG32(LCD_CLS)
++#define REG_LCD_SPL	REG32(LCD_SPL)
++#define REG_LCD_REV	REG32(LCD_REV)
++#define REG_LCD_CTRL	REG32(LCD_CTRL)
++#define REG_LCD_STATE	REG32(LCD_STATE)
++#define REG_LCD_IID	REG32(LCD_IID)
++#define REG_LCD_DA0	REG32(LCD_DA0)
++#define REG_LCD_SA0	REG32(LCD_SA0)
++#define REG_LCD_FID0	REG32(LCD_FID0)
++#define REG_LCD_CMD0	REG32(LCD_CMD0)
++#define REG_LCD_DA1	REG32(LCD_DA1)
++#define REG_LCD_SA1	REG32(LCD_SA1)
++#define REG_LCD_FID1	REG32(LCD_FID1)
++#define REG_LCD_CMD1	REG32(LCD_CMD1)
++
++#define LCD_CTRL_BPP_BIT	0  /* Bits Per Pixel */
++#define LCD_CTRL_BPP_MASK	(0x07 << LCD_CTRL_BPP_BIT)
++  #define LCD_CTRL_BPP_1	(0 << LCD_CTRL_BPP_BIT) /* 1 bpp */
++  #define LCD_CTRL_BPP_2	(1 << LCD_CTRL_BPP_BIT) /* 2 bpp */
++  #define LCD_CTRL_BPP_4	(2 << LCD_CTRL_BPP_BIT) /* 4 bpp */
++  #define LCD_CTRL_BPP_8	(3 << LCD_CTRL_BPP_BIT) /* 8 bpp */
++  #define LCD_CTRL_BPP_16	(4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */
++  #define LCD_CTRL_BPP_18_24	(5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */
++
++#define LCD_CTRL_BST_BIT	28  /* Burst Length Selection */
++#define LCD_CTRL_BST_MASK	(0x03 << LCD_CTRL_BST_BIT)
++  #define LCD_CTRL_BST_4	(0 << LCD_CTRL_BST_BIT) /* 4-word */
++  #define LCD_CTRL_BST_8	(1 << LCD_CTRL_BST_BIT) /* 8-word */
++  #define LCD_CTRL_BST_16	(2 << LCD_CTRL_BST_BIT) /* 16-word */
++#define LCD_CTRL_RGB565		(0 << 27) /* RGB565 mode */
++#define LCD_CTRL_RGB555		(1 << 27) /* RGB555 mode */
++#define LCD_CTRL_OFUP		(1 << 26) /* Output FIFO underrun protection enable */
++#define LCD_CTRL_FRC_BIT	24  /* STN FRC Algorithm Selection */
++#define LCD_CTRL_FRC_MASK	(0x03 << LCD_CTRL_FRC_BIT)
++  #define LCD_CTRL_FRC_16	(0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */
++  #define LCD_CTRL_FRC_4	(1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */
++  #define LCD_CTRL_FRC_2	(2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */
++
++#define CPM_LPCDR	(CPM_BASE+0x64)
++#define CPM_CLKGR	(CPM_BASE+0x20)
++#define REG_CPM_LPCDR	REG32(CPM_LPCDR)
++#define REG_CPM_CLKGR	REG32(CPM_CLKGR)
++
++#define __cpm_start_tcu()	(REG_CPM_CLKGR &= ~CPM_CLKGR_TCU)
++#define __cpm_stop_lcd()	(REG_CPM_CLKGR |= CPM_CLKGR_LCD)
++#define __cpm_set_pixdiv(v) \
++	(REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT)))
++#define __cpm_set_ldiv(v) \
++	(REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT)))
++#define __cpm_start_lcd()	(REG_CPM_CLKGR &= ~CPM_CLKGR_LCD)
++
+ #endif	/* !__ASSEMBLY__ */
+ #endif	/* __JZ4740_H__ */
+diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c
+index b14b33e..c2e64d9 100644
+--- a/arch/mips/lib/board.c
++++ b/arch/mips/lib/board.c
+@@ -172,6 +172,12 @@ void board_init_f(ulong bootflag)
+ 	addr &= ~(4096 - 1);
+ 	debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
+ 
++#ifdef CONFIG_LCD
++        /* reserve memory for LCD display (always full pages) */
++        addr = lcd_setmem (addr);
++        gd->fb_base = addr;
++#endif /* CONFIG_LCD */
++
+ 	/* Reserve memory for U-Boot code, data & bss
+ 	 * round down to next 16 kB limit
+ 	 */
+diff --git a/common/lcd.c b/common/lcd.c
+index b6be800..af1281a 100644
+--- a/common/lcd.c
++++ b/common/lcd.c
+@@ -263,6 +263,13 @@ static void lcd_drawchars(ushort x, ushort y, uchar *str, int count)
+ 						lcd_color_fg : lcd_color_bg;
+ 				bits <<= 1;
+ 			}
++#elif LCD_BPP == LCD_COLOR32
++                       uint *m = (uint *)d;
++                       for (c=0; c<32; ++c) {
++                               *m++ = (bits & 0x80) ?
++				       lcd_color_fg : lcd_color_bg;
++                               bits <<= 1;
++                       }
+ #endif
+ 		}
+ #if LCD_BPP == LCD_MONOCHROME
+@@ -509,7 +516,7 @@ static inline ushort *configuration_get_cmap(void)
+ 	return (ushort *)&(cp->lcd_cmap[255 * sizeof(ushort)]);
+ #elif defined(CONFIG_ATMEL_LCD)
+ 	return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0));
+-#elif !defined(CONFIG_ATMEL_HLCD) && !defined(CONFIG_EXYNOS_FB)
++#elif !defined(CONFIG_ATMEL_HLCD) && !defined(CONFIG_EXYNOS_FB) && !defined(CONFIG_VIDEO_GPM940B0)
+ 	return panel_info.cmap;
+ #else
+ #if defined(CONFIG_LCD_LOGO)
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index ebb6da8..03625bc 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -50,6 +50,7 @@ COBJS-$(CONFIG_VIDEO_SED13806) += sed13806.o
+ COBJS-$(CONFIG_VIDEO_SM501) += sm501.o
+ COBJS-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
+ COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
++COBJS-$(CONFIG_VIDEO_GPM940B0) += nanonote_gpm940b0.o
+ 
+ COBJS	:= $(sort $(COBJS-y))
+ SRCS	:= $(COBJS:.o=.c)
+diff --git a/drivers/video/nanonote_gpm940b0.c b/drivers/video/nanonote_gpm940b0.c
+new file mode 100644
+index 0000000..11efb72
+--- /dev/null
++++ b/drivers/video/nanonote_gpm940b0.c
+@@ -0,0 +1,400 @@
++/*
++ * JzRISC lcd controller
++ *
++ * Xiangfu Liu <xiangfu@sharism.cc>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <config.h>
++#include <common.h>
++#include <lcd.h>
++
++#include <asm/io.h>               /* virt_to_phys() */
++#include <asm/jz4740.h>
++
++#include "nanonote_gpm940b0.h"
++
++#define align2(n) (n)=((((n)+1)>>1)<<1)
++#define align4(n) (n)=((((n)+3)>>2)<<2)
++#define align8(n) (n)=((((n)+7)>>3)<<3)
++
++struct jzfb_info {
++	unsigned int cfg;	/* panel mode and pin usage etc. */
++	unsigned int w;
++	unsigned int h;
++	unsigned int bpp;	/* bit per pixel */
++	unsigned int fclk;	/* frame clk */
++	unsigned int hsw;	/* hsync width, in pclk */
++	unsigned int vsw;	/* vsync width, in line count */
++	unsigned int elw;	/* end of line, in pclk */
++	unsigned int blw;	/* begin of line, in pclk */
++	unsigned int efw;	/* end of frame, in line count */
++	unsigned int bfw;	/* begin of frame, in line count */
++};
++
++static struct jzfb_info jzfb = {
++	MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N,
++	320, 240, 32, 70, 1, 1, 273, 140, 1, 20
++};
++
++vidinfo_t panel_info = {
++	320, 240, LCD_BPP,
++};
++
++void *lcd_base;
++void *lcd_console_address;
++int lcd_line_length;
++int lcd_color_fg;
++int lcd_color_bg;
++short console_col;
++short console_row;
++
++static int jz_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
++{
++	u_long palette_mem_size;
++	struct jz_fb_info *fbi = &vid->jz_fb;
++	int fb_size = vid->vl_row * (vid->vl_col * NBITS (vid->vl_bpix)) / 8;
++
++	fbi->screen = (u_long)lcdbase;
++	fbi->palette_size = 256;
++	palette_mem_size = fbi->palette_size * sizeof(u16);
++
++	debug("jz_lcd.c palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
++	/* locate palette and descs at end of page following fb */
++	fbi->palette = (u_long)lcdbase + fb_size + PAGE_SIZE - palette_mem_size;
++
++	return 0;
++}
++
++static void jz_lcd_desc_init(vidinfo_t *vid)
++{
++	struct jz_fb_info * fbi;
++	fbi = &vid->jz_fb;
++	fbi->dmadesc_fblow = (struct jz_fb_dma_descriptor *)((unsigned int)fbi->palette - 3*16);
++	fbi->dmadesc_fbhigh = (struct jz_fb_dma_descriptor *)((unsigned int)fbi->palette - 2*16);
++	fbi->dmadesc_palette = (struct jz_fb_dma_descriptor *)((unsigned int)fbi->palette - 1*16);
++
++	#define BYTES_PER_PANEL	 (vid->vl_col * vid->vl_row * NBITS(vid->vl_bpix) / 8)
++
++	/* populate descriptors */
++	fbi->dmadesc_fblow->fdadr = virt_to_phys(fbi->dmadesc_fblow);
++	fbi->dmadesc_fblow->fsadr = virt_to_phys((void *)(fbi->screen + BYTES_PER_PANEL));
++	fbi->dmadesc_fblow->fidr  = 0;
++	fbi->dmadesc_fblow->ldcmd = BYTES_PER_PANEL / 4 ;
++
++	fbi->fdadr1 = virt_to_phys(fbi->dmadesc_fblow); /* only used in dual-panel mode */
++
++	fbi->dmadesc_fbhigh->fsadr = virt_to_phys((void *)fbi->screen);
++	fbi->dmadesc_fbhigh->fidr = 0;
++	fbi->dmadesc_fbhigh->ldcmd =  BYTES_PER_PANEL / 4; /* length in word */
++
++	fbi->dmadesc_palette->fsadr = virt_to_phys((void *)fbi->palette);
++	fbi->dmadesc_palette->fidr  = 0;
++	fbi->dmadesc_palette->ldcmd = (fbi->palette_size * 2)/4 | (1<<28);
++
++	if(NBITS(vid->vl_bpix) < 12) {
++		/* assume any mode with <12 bpp is palette driven */
++		fbi->dmadesc_palette->fdadr = virt_to_phys(fbi->dmadesc_fbhigh);
++		fbi->dmadesc_fbhigh->fdadr = virt_to_phys(fbi->dmadesc_palette);
++		/* flips back and forth between pal and fbhigh */
++		fbi->fdadr0 = virt_to_phys(fbi->dmadesc_palette);
++	} else {
++		/* palette shouldn't be loaded in true-color mode */
++		fbi->dmadesc_fbhigh->fdadr = virt_to_phys((void *)fbi->dmadesc_fbhigh);
++		fbi->fdadr0 = virt_to_phys(fbi->dmadesc_fbhigh); /* no pal just fbhigh */
++	}
++}
++
++static int  jz_lcd_hw_init(vidinfo_t *vid)
++{
++	struct jz_fb_info *fbi = &vid->jz_fb;
++	unsigned int val = 0;
++	unsigned int pclk;
++	unsigned int stnH;
++	int pll_div;
++
++	/* Setting Control register */
++	switch (jzfb.bpp) {
++	case 1:
++		val |= LCD_CTRL_BPP_1;
++		break;
++	case 2:
++		val |= LCD_CTRL_BPP_2;
++		break;
++	case 4:
++		val |= LCD_CTRL_BPP_4;
++		break;
++	case 8:
++		val |= LCD_CTRL_BPP_8;
++		break;
++	case 15:
++		val |= LCD_CTRL_RGB555;
++	case 16:
++		val |= LCD_CTRL_BPP_16;
++		break;
++	case 17 ... 32:
++		val |= LCD_CTRL_BPP_18_24;	/* target is 4bytes/pixel */
++		break;
++
++	default:
++		printf("jz_lcd.c The BPP %d is not supported\n", jzfb.bpp);
++		val |= LCD_CTRL_BPP_16;
++		break;
++	}
++
++	switch (jzfb.cfg & MODE_MASK) {
++	case MODE_STN_MONO_DUAL:
++	case MODE_STN_COLOR_DUAL:
++	case MODE_STN_MONO_SINGLE:
++	case MODE_STN_COLOR_SINGLE:
++		switch (jzfb.bpp) {
++		case 1:
++			/* val |= LCD_CTRL_PEDN; */
++		case 2:
++			val |= LCD_CTRL_FRC_2;
++			break;
++		case 4:
++			val |= LCD_CTRL_FRC_4;
++			break;
++		case 8:
++		default:
++			val |= LCD_CTRL_FRC_16;
++			break;
++		}
++		break;
++	}
++
++	val |= LCD_CTRL_BST_16;		/* Burst Length is 16WORD=64Byte */
++	val |= LCD_CTRL_OFUP;		/* OutFIFO underrun protect */
++
++	switch (jzfb.cfg & MODE_MASK) {
++	case MODE_STN_MONO_DUAL:
++	case MODE_STN_COLOR_DUAL:
++	case MODE_STN_MONO_SINGLE:
++	case MODE_STN_COLOR_SINGLE:
++		switch (jzfb.cfg & STN_DAT_PINMASK) {
++		case STN_DAT_PIN1:
++			/* Do not adjust the hori-param value. */
++			break;
++		case STN_DAT_PIN2:
++			align2(jzfb.hsw);
++			align2(jzfb.elw);
++			align2(jzfb.blw);
++			break;
++		case STN_DAT_PIN4:
++			align4(jzfb.hsw);
++			align4(jzfb.elw);
++			align4(jzfb.blw);
++			break;
++		case STN_DAT_PIN8:
++			align8(jzfb.hsw);
++			align8(jzfb.elw);
++			align8(jzfb.blw);
++			break;
++		}
++		break;
++	}
++
++	REG_LCD_CTRL = val;
++
++	switch (jzfb.cfg & MODE_MASK) {
++	case MODE_STN_MONO_DUAL:
++	case MODE_STN_COLOR_DUAL:
++	case MODE_STN_MONO_SINGLE:
++	case MODE_STN_COLOR_SINGLE:
++		if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) ||
++		    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
++			stnH = jzfb.h >> 1;
++		else
++			stnH = jzfb.h;
++
++		REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
++		REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw);
++
++		/* Screen setting */
++		REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw);
++		REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w);
++		REG_LCD_DAV = (0 << 16) | (stnH);
++
++		/* AC BIAs signal */
++		REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw);
++
++		break;
++
++	case MODE_TFT_GEN:
++	case MODE_TFT_SHARP:
++	case MODE_TFT_CASIO:
++	case MODE_TFT_SAMSUNG:
++	case MODE_8BIT_SERIAL_TFT:
++	case MODE_TFT_18BIT:
++		REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
++		REG_LCD_HSYNC = (0 << 16) | jzfb.hsw;
++		REG_LCD_DAV =((jzfb.vsw+jzfb.bfw) << 16) | (jzfb.vsw +jzfb.bfw+jzfb.h);
++		REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w );
++		REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) \
++			| (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw);
++		break;
++	}
++
++	switch (jzfb.cfg & MODE_MASK) {
++	case MODE_TFT_SAMSUNG:
++	{
++		unsigned int total, tp_s, tp_e, ckv_s, ckv_e;
++		unsigned int rev_s, rev_e, inv_s, inv_e;
++
++		pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *
++			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
++
++		total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;
++		tp_s = jzfb.blw + jzfb.w + 1;
++		tp_e = tp_s + 1;
++		ckv_s = tp_s - pclk/(1000000000/4100);
++		ckv_e = tp_s + total;
++		rev_s = tp_s - 11;	/* -11.5 clk */
++		rev_e = rev_s + total;
++		inv_s = tp_s;
++		inv_e = inv_s + total;
++		REG_LCD_CLS = (tp_s << 16) | tp_e;
++		REG_LCD_PS = (ckv_s << 16) | ckv_e;
++		REG_LCD_SPL = (rev_s << 16) | rev_e;
++		REG_LCD_REV = (inv_s << 16) | inv_e;
++		jzfb.cfg |= STFT_REVHI | STFT_SPLHI;
++		break;
++	}
++	case MODE_TFT_SHARP:
++	{
++		unsigned int total, cls_s, cls_e, ps_s, ps_e;
++		unsigned int spl_s, spl_e, rev_s, rev_e;
++		total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;
++		spl_s = 1;
++		spl_e = spl_s + 1;
++		cls_s = 0;
++		cls_e = total - 60;	/* > 4us (pclk = 80ns) */
++		ps_s = cls_s;
++		ps_e = cls_e;
++		rev_s = total - 40;	/* > 3us (pclk = 80ns) */
++		rev_e = rev_s + total;
++		jzfb.cfg |= STFT_PSHI; 
++		REG_LCD_SPL = (spl_s << 16) | spl_e;
++		REG_LCD_CLS = (cls_s << 16) | cls_e;
++		REG_LCD_PS = (ps_s << 16) | ps_e;
++		REG_LCD_REV = (rev_s << 16) | rev_e;
++		break;
++	}
++	case MODE_TFT_CASIO:
++		break;
++	}
++
++	/* Configure the LCD panel */
++	REG_LCD_CFG = jzfb.cfg;
++
++	/* Timing setting */
++	__cpm_stop_lcd();
++
++	val = jzfb.fclk; /* frame clk */
++	if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) {
++		pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *
++			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
++	} else {
++		/* serial mode: Hsync period = 3*Width_Pixel */
++		pclk = val * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) *
++			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
++	}
++
++	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
++	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
++		pclk = (pclk * 3);
++
++	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
++	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
++	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||
++	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
++		pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4);
++
++	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
++	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
++		pclk >>= 1;
++
++	pll_div = (REG_CPM_CPCCR & CPM_CPCCR_PCS); /* clock source,0:pllout/2 1: pllout */
++	pll_div = pll_div ? 1 : 2;
++	val = (__cpm_get_pllout() / pll_div) / pclk;
++	val--;
++	if (val > 0x1ff) {
++		printf("CPM_LPCDR too large, set it to 0x1ff\n");
++		val = 0x1ff;
++	}
++	__cpm_set_pixdiv(val);
++
++	val = pclk * 3 ;	/* LCDClock > 2.5*Pixclock */
++	if (val > 150000000) {
++		printf("Warning: LCDClock=%d\n, LCDClock must less or equal to 150MHz.\n", val);
++		printf("Change LCDClock to 150MHz\n");
++		val = 150000000;
++	}
++	val = (__cpm_get_pllout() / pll_div) / val;
++	val--;
++	if (val > 0x1f) {
++		printf("CPM_CPCCR.LDIV too large, set it to 0x1f\n");
++		val = 0x1f;
++	}
++	__cpm_set_ldiv( val );
++	REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */
++
++	__cpm_start_lcd();
++	udelay(1000);
++
++	REG_LCD_DA0 = fbi->fdadr0; /* frame descripter*/
++
++	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
++	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
++		REG_LCD_DA1 = fbi->fdadr1; /* frame descripter*/
++
++	return 0;
++}
++
++void lcd_ctrl_init (void *lcdbase)
++{
++	__lcd_display_pin_init();
++	__lcd_display_on() ;
++
++	jz_lcd_init_mem(lcdbase, &panel_info);
++	jz_lcd_desc_init(&panel_info);
++	jz_lcd_hw_init(&panel_info);
++
++}
++
++/*
++ * Before enabled lcd controller, lcd registers should be configured correctly.
++ */
++void lcd_enable (void)
++{
++	REG_LCD_CTRL &= ~(1<<4); /* LCDCTRL.DIS */
++	REG_LCD_CTRL |= 1<<3;    /* LCDCTRL.ENA*/
++}
++
++void lcd_disable (void)
++{
++	REG_LCD_CTRL |= (1<<4);
++}
++
++void lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue)
++{
++}
++
++void lcd_initcolregs (void)
++{
++}
+diff --git a/drivers/video/nanonote_gpm940b0.h b/drivers/video/nanonote_gpm940b0.h
+new file mode 100644
+index 0000000..efe491e
+--- /dev/null
++++ b/drivers/video/nanonote_gpm940b0.h
+@@ -0,0 +1,135 @@
++/*
++ * JzRISC lcd controller
++ *
++ * Xiangfu Liu <xiangfu@sharism.cc>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#ifndef __QI_LB60_GPM940B0_H__
++#define __QI_LB60_GPM940B0_H__
++
++struct lcd_desc{
++	unsigned int next_desc; /* LCDDAx */
++	unsigned int databuf;   /* LCDSAx */
++	unsigned int frame_id;  /* LCDFIDx */ 
++	unsigned int cmd;       /* LCDCMDx */
++};
++
++#define MODE_MASK		0x0f
++#define MODE_TFT_GEN		0x00
++#define MODE_TFT_SHARP		0x01
++#define MODE_TFT_CASIO		0x02
++#define MODE_TFT_SAMSUNG	0x03
++#define MODE_CCIR656_NONINT	0x04
++#define MODE_CCIR656_INT	0x05
++#define MODE_STN_COLOR_SINGLE	0x08
++#define MODE_STN_MONO_SINGLE	0x09
++#define MODE_STN_COLOR_DUAL	0x0a
++#define MODE_STN_MONO_DUAL	0x0b
++#define MODE_8BIT_SERIAL_TFT    0x0c
++
++#define MODE_TFT_18BIT          (1<<7)
++
++#define STN_DAT_PIN1	(0x00 << 4)
++#define STN_DAT_PIN2	(0x01 << 4)
++#define STN_DAT_PIN4	(0x02 << 4)
++#define STN_DAT_PIN8	(0x03 << 4)
++#define STN_DAT_PINMASK	STN_DAT_PIN8
++
++#define STFT_PSHI	(1 << 15)
++#define STFT_CLSHI	(1 << 14)
++#define STFT_SPLHI	(1 << 13)
++#define STFT_REVHI	(1 << 12)
++
++#define SYNC_MASTER	(0 << 16)
++#define SYNC_SLAVE	(1 << 16)
++
++#define DE_P		(0 << 9)
++#define DE_N		(1 << 9)
++
++#define PCLK_P		(0 << 10)
++#define PCLK_N		(1 << 10)
++
++#define HSYNC_P		(0 << 11)
++#define HSYNC_N		(1 << 11)
++
++#define VSYNC_P		(0 << 8)
++#define VSYNC_N		(1 << 8)
++
++#define DATA_NORMAL	(0 << 17)
++#define DATA_INVERSE	(1 << 17)
++
++
++/* Jz LCDFB supported I/O controls. */
++#define FBIOSETBACKLIGHT	0x4688
++#define FBIODISPON		0x4689
++#define FBIODISPOFF		0x468a
++#define FBIORESET		0x468b
++#define FBIOPRINT_REG		0x468c
++
++/*
++ * LCD panel specific definition
++ */
++#define MODE	(0xc9)		/* 8bit serial RGB */
++
++#define __spi_write_reg1(reg, val)		\
++do {						\
++	unsigned char no;			\
++	unsigned short value;			\
++	unsigned char a=reg;			\
++	unsigned char b=val;			\
++	__gpio_set_pin(SPEN);			\
++	__gpio_set_pin(SPCK);			\
++	__gpio_clear_pin(SPDA);			\
++	__gpio_clear_pin(SPEN);			\
++	value=((a<<8)|(b&0xFF));		\
++	for(no=0;no<16;no++)			\
++	{					\
++		__gpio_clear_pin(SPCK);		\
++		if((value&0x8000)==0x8000)	\
++			__gpio_set_pin(SPDA);	\
++		else				\
++			__gpio_clear_pin(SPDA);	\
++		__gpio_set_pin(SPCK);		\
++		value=(value<<1);		\
++	}					\
++	__gpio_set_pin(SPEN);			\
++} while (0)
++
++#define __lcd_display_pin_init()		\
++do {						\
++	__cpm_start_tcu();			\
++	__gpio_as_output(SPEN); /* use SPDA */	\
++	__gpio_as_output(SPCK); /* use SPCK */	\
++	__gpio_as_output(SPDA); /* use SPDA */	\
++} while (0)
++
++#define __lcd_display_on()			\
++do {						\
++	__spi_write_reg1(0x05, 0x1e);		\
++	__spi_write_reg1(0x05, 0x5e);		\
++	__spi_write_reg1(0x07, 0x8d);		\
++	__spi_write_reg1(0x13, 0x01);		\
++	__spi_write_reg1(0x05, 0x5f);		\
++} while (0)
++
++#define __lcd_display_off()			\
++do {						\
++	__spi_write_reg1(0x05, 0x5e);		\
++} while (0)
++
++#endif /* __QI_LB60_GPM940B0_H__ */
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 52b370c..d3e78ad 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -32,6 +32,13 @@
+  * Miscellaneous configurable options
+  */
+ #define CONFIG_NANONOTE
++
++#define CONFIG_LCD
++#define CONFIG_SYS_WHITE_ON_BLACK
++#define LCD_BPP			LCD_COLOR32
++#define CONFIG_VIDEO_GPM940B0
++
++
+ #define CONFIG_JZ4740_MMC
+ #define CONFIG_MMC      	1
+ #define CONFIG_FAT      	1
+diff --git a/include/lcd.h b/include/lcd.h
+index 42070d7..6de5482 100644
+--- a/include/lcd.h
++++ b/include/lcd.h
+@@ -263,8 +263,44 @@ typedef struct vidinfo {
+ 
+ void init_panel_info(vidinfo_t *vid);
+ 
+-#else
++#elif defined(CONFIG_JZSOC)
++/*
++ * LCD controller stucture for JZSOC: JZ4740
++ */
++struct jz_fb_dma_descriptor {
++       u_long  fdadr;          /* Frame descriptor address register */
++       u_long  fsadr;          /* Frame source address register */
++       u_long  fidr;           /* Frame ID register */
++       u_long  ldcmd;          /* Command register */
++};
++
++/*
++ * Jz LCD info
++ */
++struct jz_fb_info {
++
++       u_long  fdadr0; /* physical address of frame/palette descriptor */
++       u_long  fdadr1; /* physical address of frame descriptor */
++
++       /* DMA descriptors */
++       struct  jz_fb_dma_descriptor *  dmadesc_fblow;
++       struct  jz_fb_dma_descriptor *  dmadesc_fbhigh;
++       struct  jz_fb_dma_descriptor *  dmadesc_palette;
++       u_long  screen;         /* address of frame buffer */
++       u_long  palette;        /* address of palette memory */
++       u_int   palette_size;
++};
++typedef struct vidinfo {
++       ushort  vl_col;         /* Number of columns (i.e. 640) */
++       ushort  vl_row;         /* Number of rows (i.e. 480) */
++       u_char  vl_bpix;        /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */
++
++       struct jz_fb_info jz_fb;
++} vidinfo_t;
++
++extern vidinfo_t panel_info;
+ 
++#else
+ typedef struct vidinfo {
+ 	ushort	vl_col;		/* Number of columns (i.e. 160) */
+ 	ushort	vl_row;		/* Number of rows (i.e. 100) */
+@@ -318,6 +354,7 @@ void lcd_show_board_info(void);
+ #define LCD_COLOR4	2
+ #define LCD_COLOR8	3
+ #define LCD_COLOR16	4
++#define LCD_COLOR32	5
+ 
+ /*----------------------------------------------------------------------*/
+ #if defined(CONFIG_LCD_INFO_BELOW_LOGO)
+@@ -369,7 +406,7 @@ void lcd_show_board_info(void);
+ # define CONSOLE_COLOR_GREY	14
+ # define CONSOLE_COLOR_WHITE	15	/* Must remain last / highest	*/
+ 
+-#else
++#elif LCD_BPP == LCD_COLOR16
+ 
+ /*
+  * 16bpp color definitions
+@@ -377,6 +414,15 @@ void lcd_show_board_info(void);
+ # define CONSOLE_COLOR_BLACK	0x0000
+ # define CONSOLE_COLOR_WHITE	0xffff	/* Must remain last / highest	*/
+ 
++#elif LCD_BPP == LCD_COLOR32
++/*
++ * 18,24,32 bpp color definitions
++ */
++# define CONSOLE_COLOR_BLACK   0x00000000
++# define CONSOLE_COLOR_WHITE   0xffffffff /* Must remain last / highest */
++
++#else
++
+ #endif /* color definitions */
+ 
+ /************************************************************************/
+@@ -406,7 +452,7 @@ void lcd_show_board_info(void);
+ #if LCD_BPP == LCD_MONOCHROME
+ # define COLOR_MASK(c)		((c)	  | (c) << 1 | (c) << 2 | (c) << 3 | \
+ 				 (c) << 4 | (c) << 5 | (c) << 6 | (c) << 7)
+-#elif (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16)
++#elif (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16) || (LCD_BPP == LCD_COLOR32)
+ # define COLOR_MASK(c)		(c)
+ #else
+ # error Unsupported LCD BPP.
+-- 
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0006-enable-silent-console.patch b/package/boot/uboot-xburst/patches/0006-enable-silent-console.patch
new file mode 100644
index 0000000000..ebd6a6a7bf
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0006-enable-silent-console.patch
@@ -0,0 +1,60 @@
+From 5eb4d4c598f2806bd1b3d1140e917bfead7851ad Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 23:51:26 +0800
+Subject: [PATCH 6/6] enable silent console
+
+---
+ common/console.c          |   16 ++++++++++++++++
+ include/configs/qi_lb60.h |    2 ++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/common/console.c b/common/console.c
+index 1177f7d..e8a2078 100644
+--- a/common/console.c
++++ b/common/console.c
+@@ -685,6 +685,14 @@ done:
+ 
+ 	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+ 
++#ifdef CONFIG_SILENT_CONSOLE
++	/* Check one more time the contents of the silent environment
++	 * variable, because if the environment is loaded from NAND it was
++	 * not available when console_init_f() was called */
++	if (getenv("silent") != NULL)
++		gd->flags |= GD_FLG_SILENT;
++#endif
++
+ 	stdio_print_current_devices();
+ 
+ #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
+@@ -760,6 +768,14 @@ int console_init_r(void)
+ 
+ 	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+ 
++#ifdef CONFIG_SILENT_CONSOLE
++	/* Check one more time the contents of the silent environment
++	 * variable, because if the environment is loaded from NAND it was
++	 * not available when console_init_f() was called */
++	if (getenv("silent") != NULL)
++		gd->flags |= GD_FLG_SILENT;
++#endif
++
+ 	stdio_print_current_devices();
+ 
+ 	/* Setting environment variables */
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index d3e78ad..a3534ff 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -102,6 +102,8 @@
+ #define CONFIG_SYS_NO_FLASH
+ #define CONFIG_SYS_FLASH_BASE	0 /* init flash_base as 0 */
+ 
++#define CONFIG_SILENT_CONSOLE		1	/* Enable silent console */
++
+ /*
+  * Command line configuration
+  */
+-- 
+1.7.9.5
+
diff --git a/package/boot/yamonenv/Makefile b/package/boot/yamonenv/Makefile
new file mode 100644
index 0000000000..a490f45fe1
--- /dev/null
+++ b/package/boot/yamonenv/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=yamonenv
+PKG_VERSION:=20051022
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)_gruen.4g__$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://downloads.openwrt.org/sources/
+PKG_MD5SUM:=a3e4f24155aa3ba5aa502bc63fdaa6ad
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/yamonenv
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Boot Loaders
+  DEPENDS:=@TARGET_au1000
+  TITLE:=YAMON configuration utility
+  URL:=http://meshcube.org/nylon/stable/sources/
+  MAINTAINER:=Florian Fainelli <florian@openwrt.org>
+endef
+
+define Build/Configure
+endef
+
+define Package/yamonenv/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_BUILD_DIR)/src/$(PKG_NAME) $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,yamonenv))
diff --git a/package/boot/yamonenv/patches/001-yamonenv_mtd_partition.patch b/package/boot/yamonenv/patches/001-yamonenv_mtd_partition.patch
new file mode 100644
index 0000000000..e1def28af5
--- /dev/null
+++ b/package/boot/yamonenv/patches/001-yamonenv_mtd_partition.patch
@@ -0,0 +1,11 @@
+--- a/src/yamonenv.c
++++ b/src/yamonenv.c
+@@ -12,7 +12,7 @@
+ #include <fcntl.h>
+ #include <unistd.h>
+ 
+-#define DEFAULT_YAMON_ENV_FILE   "/dev/mtd/3"
++#define DEFAULT_YAMON_ENV_FILE   "/dev/mtd3"
+ 
+ 
+ // control byte definitions:
diff --git a/package/devel/binutils/Makefile b/package/devel/binutils/Makefile
new file mode 100644
index 0000000000..7a24884a0e
--- /dev/null
+++ b/package/devel/binutils/Makefile
@@ -0,0 +1,125 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=binutils
+PKG_VERSION:=2.27
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL:=@GNU/binutils
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_VERSION:=$(PKG_VERSION)
+PKG_MD5SUM:=2869c9bf3e60ee97c74ac2a6bf4e9d68
+
+PKG_FIXUP:=autoreconf
+PKG_LIBTOOL_PATHS:=. gas bfd opcodes gprof binutils ld libiberty gold intl
+PKG_REMOVE_FILES:=libtool.m4
+PKG_INSTALL:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-3.0+
+PKG_BUILD_PARALLEL:=1
+PKG_USE_MIPS16:=0
+
+include $(INCLUDE_DIR)/nls.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libbfd
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=libbfd
+  DEPENDS:=+zlib $(ICONV_DEPENDS) $(INTL_DEPENDS)
+endef
+
+define Package/libopcodes
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=libbfd
+  DEPENDS:=+libbfd
+endef
+
+define Package/binutils
+  SECTION:=devel
+  CATEGORY:=Development
+  TITLE:=binutils
+  DEPENDS:=+objdump +ar
+endef
+
+define Package/objdump
+  SECTION:=devel
+  CATEGORY:=Development
+  TITLE:=objdump
+  DEPENDS:=+libopcodes
+endef
+
+define Package/ar
+  SECTION:=devel
+  CATEGORY:=Development
+  TITLE:=ar
+  DEPENDS:=+zlib +libbfd
+endef
+
+define Package/binutils/description
+  The Binutils package contains a linker, an assembler, and other tools for handling object files
+endef
+
+TARGET_CFLAGS += $(FPIC) -Wno-unused-value
+
+CONFIGURE_ARGS += \
+	--host=$(REAL_GNU_TARGET_NAME) \
+	--target=$(REAL_GNU_TARGET_NAME) \
+	--enable-shared \
+	--enable-install-libiberty \
+	--enable-install-libbfd
+
+define Build/Install
+	$(call Build/Install/Default)
+	$(MAKE) -C $(PKG_BUILD_DIR)/libiberty \
+		target_header_dir=libiberty \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		MULTIOSDIR="" \
+		install
+endef
+
+define Build/InstallDev
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+endef
+
+define Package/libbfd/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libbfd*.so $(1)/usr/lib/
+endef
+
+define Package/libopcodes/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libopcodes*.so $(1)/usr/lib/
+endef
+
+define Package/objdump/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/objdump $(1)/usr/bin/
+endef
+
+define Package/ar/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/ar $(1)/usr/bin/
+endef
+
+define Package/binutils/install
+	$(INSTALL_DIR) $(1)/usr $(1)/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/ $(1)/usr/
+	mv $(1)/usr/bin/strings $(1)/bin/strings
+	rm -f $(1)/usr/bin/objdump
+	rm -f $(1)/usr/bin/ar
+endef
+
+$(eval $(call BuildPackage,libbfd))
+$(eval $(call BuildPackage,libopcodes))
+$(eval $(call BuildPackage,binutils))
+$(eval $(call BuildPackage,objdump))
+$(eval $(call BuildPackage,ar))
diff --git a/package/devel/gdb-arc/Makefile b/package/devel/gdb-arc/Makefile
new file mode 100644
index 0000000000..c42b108150
--- /dev/null
+++ b/package/devel/gdb-arc/Makefile
@@ -0,0 +1,94 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gdb-arc
+PKG_VERSION:=arc-2016.03-gdb
+PKG_RELEASE:=1
+
+PKG_SOURCE:=gdb-arc-2016.03-gdb.tar.gz
+PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/$(PKG_VERSION)
+PKG_MD5SUM:=775caaf6385c16f20b6f53c0a2b95f79
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/binutils-gdb-arc-2016.03-gdb
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+PKG_LICENSE:=GPL-3.0+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/gdb-arc/Default
+  SECTION:=devel
+  CATEGORY:=Development
+  DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib @arc
+  URL:=http://www.gnu.org/software/gdb/
+endef
+
+define Package/gdb-arc
+$(call Package/gdb-arc/Default)
+  TITLE:=GNU Debugger for ARC
+  DEPENDS+=+libreadline +libncurses +zlib
+endef
+
+define Package/gdb-arc/description
+GDB, the GNU Project debugger, allows you to see what is going on `inside'
+another program while it executes -- or what another program was doing at the
+moment it crashed.
+endef
+
+define Package/gdbserver-arc
+$(call Package/gdb-arc/Default)
+  TITLE:=Remote server for GNU Debugger
+endef
+
+define Package/gdbserver-arc/description
+GDBSERVER is a program that allows you to run GDB on a different machine than the
+one which is running the program being debugged.
+endef
+
+# XXX: add --disable-werror to prevent build failure with arm
+CONFIGURE_ARGS+= \
+	--with-system-readline \
+	--without-expat \
+	--without-lzma \
+	--disable-werror \
+	--disable-binutils \
+	--disable-ld \
+	--disable-gas \
+	--disable-sim
+
+CONFIGURE_VARS+= \
+	ac_cv_search_tgetent="$(TARGET_LDFLAGS) -lncurses -lreadline"
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CPPFLAGS="$(TARGET_CPPFLAGS)" \
+		all
+endef
+
+define Build/Install
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CPPFLAGS="$(TARGET_CPPFLAGS)" \
+		install-gdb
+endef
+
+define Package/gdb-arc/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdb $(1)/usr/bin/
+endef
+
+define Package/gdbserver-arc/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdbserver $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,gdb-arc))
+$(eval $(call BuildPackage,gdbserver-arc))
diff --git a/package/devel/gdb-arc/patches/100-no_extern_inline.patch b/package/devel/gdb-arc/patches/100-no_extern_inline.patch
new file mode 100644
index 0000000000..8c18c6e2e7
--- /dev/null
+++ b/package/devel/gdb-arc/patches/100-no_extern_inline.patch
@@ -0,0 +1,32 @@
+--- a/sim/common/sim-arange.c
++++ b/sim/common/sim-arange.c
+@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a
+   build_search_tree (ar);
+ }
+ 
+-#endif /* DEFINE_NON_INLINE_P */
+-
+-#if DEFINE_INLINE_P
+-
+-SIM_ARANGE_INLINE int
++int
+ sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
+ {
+   ADDR_RANGE_TREE *t = ar->range_tree;
+@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad
+   return 0;
+ }
+ 
+-#endif /* DEFINE_INLINE_P */
++#endif /* DEFINE_NON_INLINE_P */
+--- a/sim/common/sim-arange.h
++++ b/sim/common/sim-arange.h
+@@ -73,7 +73,7 @@ extern void sim_addr_range_delete (ADDR_
+ 
+ /* Return non-zero if ADDR is in range AR, traversing the entire tree.
+    If no range is specified, that is defined to mean "everything".  */
+-SIM_ARANGE_INLINE int
++extern int
+ sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
+ #define ADDR_RANGE_HIT_P(ar, addr) \
+   ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
diff --git a/package/devel/gdb-arc/patches/110-no_testsuite.patch b/package/devel/gdb-arc/patches/110-no_testsuite.patch
new file mode 100644
index 0000000000..1b284ea767
--- /dev/null
+++ b/package/devel/gdb-arc/patches/110-no_testsuite.patch
@@ -0,0 +1,21 @@
+--- a/gdb/configure
++++ b/gdb/configure
+@@ -870,8 +870,7 @@ MAKEINFOFLAGS
+ YACC
+ YFLAGS
+ XMKMF'
+-ac_subdirs_all='testsuite
+-gdbtk
++ac_subdirs_all='gdbtk
+ multi-ice
+ gdbserver'
+ 
+@@ -5610,7 +5610,7 @@ $as_echo "$with_auto_load_safe_path" >&6
+ 
+ 
+ 
+-subdirs="$subdirs testsuite"
++subdirs="$subdirs"
+ 
+ 
+ # Check whether to support alternative target configurations
diff --git a/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch b/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch
new file mode 100644
index 0000000000..c8b41f264a
--- /dev/null
+++ b/package/devel/gdb-arc/patches/120-fix-compile-flag-mismatch.patch
@@ -0,0 +1,11 @@
+--- a/gdb/gdbserver/configure
++++ b/gdb/gdbserver/configure
+@@ -2468,7 +2468,7 @@ $as_echo "$as_me: error: \`$ac_var' was
+       ac_cache_corrupted=: ;;
+     ,);;
+     *)
+-      if test "x$ac_old_val" != "x$ac_new_val"; then
++      if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
+ 	# differences in whitespace do not lead to failure.
+ 	ac_old_val_w=`echo x $ac_old_val`
+ 	ac_new_val_w=`echo x $ac_new_val`
diff --git a/package/devel/gdb/Makefile b/package/devel/gdb/Makefile
new file mode 100644
index 0000000000..92262d9c51
--- /dev/null
+++ b/package/devel/gdb/Makefile
@@ -0,0 +1,88 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gdb
+PKG_VERSION:=7.11.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/gdb
+PKG_MD5SUM:=5aa71522e488e358243917967db87476
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+PKG_LICENSE:=GPL-3.0+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/gdb/Default
+  SECTION:=devel
+  CATEGORY:=Development
+  DEPENDS:=+!USE_MUSL:libthread-db +PACKAGE_zlib:zlib @!arc
+  URL:=http://www.gnu.org/software/gdb/
+endef
+
+define Package/gdb
+$(call Package/gdb/Default)
+  TITLE:=GNU Debugger
+  DEPENDS+=+libreadline +libncurses +zlib
+endef
+
+define Package/gdb/description
+GDB, the GNU Project debugger, allows you to see what is going on `inside'
+another program while it executes -- or what another program was doing at the
+moment it crashed.
+endef
+
+define Package/gdbserver
+$(call Package/gdb/Default)
+  TITLE:=Remote server for GNU Debugger
+endef
+
+define Package/gdbserver/description
+GDBSERVER is a program that allows you to run GDB on a different machine than the
+one which is running the program being debugged.
+endef
+
+# XXX: add --disable-werror to prevent build failure with arm
+CONFIGURE_ARGS+= \
+	--with-system-readline \
+	--without-expat \
+	--without-lzma \
+	--disable-werror
+
+CONFIGURE_VARS+= \
+	ac_cv_search_tgetent="$(TARGET_LDFLAGS) -lncurses -lreadline"
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CPPFLAGS="$(TARGET_CPPFLAGS)" \
+		all
+endef
+
+define Build/Install
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CPPFLAGS="$(TARGET_CPPFLAGS)" \
+		install-gdb
+endef
+
+define Package/gdb/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdb $(1)/usr/bin/
+endef
+
+define Package/gdbserver/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gdbserver $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,gdb))
+$(eval $(call BuildPackage,gdbserver))
diff --git a/package/devel/gdb/patches/001-gdb-pr14523-mips-signal-number.patch b/package/devel/gdb/patches/001-gdb-pr14523-mips-signal-number.patch
new file mode 100644
index 0000000000..417142419a
--- /dev/null
+++ b/package/devel/gdb/patches/001-gdb-pr14523-mips-signal-number.patch
@@ -0,0 +1,16 @@
+See http://sourceware.org/bugzilla/show_bug.cgi?id=14523
+---
+--- a/gdb/common/signals.c
++++ b/gdb/common/signals.c
+@@ -344,6 +344,11 @@ gdb_signal_from_host (int hostsig)
+       else if (64 <= hostsig && hostsig <= 127)
+ 	return (enum gdb_signal)
+ 	  (hostsig - 64 + (int) GDB_SIGNAL_REALTIME_64);
++      else if (hostsig == 128)
++	/* Some platforms, such as Linux MIPS, have NSIG == 128, in which case
++	   signal 128 is the highest realtime signal. There is no constant for
++	   that though. */
++	return GDB_SIGNAL_UNKNOWN;
+       else
+ 	error (_("GDB bug: target.c (gdb_signal_from_host): "
+ 	       "unrecognized real-time signal"));
diff --git a/package/devel/gdb/patches/002-remove-arguments.patch b/package/devel/gdb/patches/002-remove-arguments.patch
new file mode 100644
index 0000000000..a263cb396a
--- /dev/null
+++ b/package/devel/gdb/patches/002-remove-arguments.patch
@@ -0,0 +1,16 @@
+# The additional warnings are causing compile errors on gcc version 4.1.2 as
+# a host compiler.
+
+--- a/sim/igen/configure
++++ b/sim/igen/configure
+@@ -4768,8 +4768,8 @@ build_warnings="-Wall -Wdeclaration-afte
+ -Wpointer-sign \
+ -Wno-unused -Wunused-value -Wunused-function \
+ -Wno-switch -Wno-char-subscripts -Wmissing-prototypes
+--Wdeclaration-after-statement -Wempty-body -Wmissing-parameter-type \
+--Wold-style-declaration -Wold-style-definition"
++-Wdeclaration-after-statement \
++-Wold-style-definition"
+ 
+ # Enable -Wno-format by default when using gcc on mingw since many
+ # GCC versions complain about %I64.
diff --git a/package/devel/gdb/patches/100-musl_fix.patch b/package/devel/gdb/patches/100-musl_fix.patch
new file mode 100644
index 0000000000..09146c5638
--- /dev/null
+++ b/package/devel/gdb/patches/100-musl_fix.patch
@@ -0,0 +1,53 @@
+--- a/gdb/linux-nat.c
++++ b/gdb/linux-nat.c
+@@ -17,6 +17,7 @@
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+ 
++#include "stopcode.h"
+ #include "defs.h"
+ #include "inferior.h"
+ #include "infrun.h"
+@@ -71,6 +72,10 @@
+ #define SPUFS_MAGIC 0x23c9b64e
+ #endif
+ 
++#ifndef __SIGRTMIN
++#define __SIGRTMIN SIGRTMIN
++#endif
++
+ /* This comment documents high-level logic of this file.
+ 
+ Waiting for events in sync mode
+--- /dev/null
++++ b/gdb/stopcode.h
+@@ -0,0 +1,4 @@
++#ifndef W_STOPCODE
++#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
++#endif
++
+--- a/gdb/nat/ppc-linux.h
++++ b/gdb/nat/ppc-linux.h
+@@ -18,7 +18,10 @@
+ #ifndef PPC_LINUX_H
+ #define PPC_LINUX_H 1
+ 
++#define pt_regs __pt_regs
+ #include <asm/ptrace.h>
++#undef pt_regs
++
+ #include <asm/cputable.h>
+ 
+ /* This sometimes isn't defined.  */
+--- a/gdb/gdbserver/linux-ppc-low.c
++++ b/gdb/gdbserver/linux-ppc-low.c
+@@ -21,7 +21,9 @@
+ #include "linux-low.h"
+ 
+ #include <elf.h>
++#define pt_regs __pt_regs
+ #include <asm/ptrace.h>
++#undef pt_regs
+ 
+ #include "nat/ppc-linux.h"
+ 
diff --git a/package/devel/perf/Makefile b/package/devel/perf/Makefile
new file mode 100644
index 0000000000..8ff9bfa5e2
--- /dev/null
+++ b/package/devel/perf/Makefile
@@ -0,0 +1,79 @@
+#
+# Copyright (C) 2011-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=perf
+PKG_VERSION:=$(LINUX_VERSION)
+PKG_RELEASE:=2
+
+PKG_USE_MIPS16:=0
+PKG_BUILD_PARALLEL:=1
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_FLAGS:=nonshared
+
+# Perf's makefile and headers are not relocatable and must be built from the
+# Linux sources directory
+PKG_BUILD_DIR:=$(LINUX_DIR)/tools/perf-$(TARGET_DIR_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/perf
+  SECTION:=devel
+  CATEGORY:=Development
+  DEPENDS:= +libelf1 +libdw +libpthread +librt +objdump @!LINUX_3_18 @!IN_SDK
+  TITLE:=Linux performance monitoring tool
+  VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE)
+  URL:=http://www.kernel.org
+endef
+
+define Package/perf/description
+  perf is the Linux performance monitoring tool
+endef
+
+define Build/Prepare
+	$(CP) $(LINUX_DIR)/tools/perf/* $(PKG_BUILD_DIR)/
+endef
+
+MAKE_FLAGS = \
+	ARCH="$(LINUX_KARCH)" \
+	NO_LIBPERL=1 \
+	NO_LIBPYTHON=1 \
+	NO_NEWT=1 \
+	NO_LZMA=1 \
+	NO_BACKTRACE=1 \
+	NO_LIBNUMA=1 \
+	NO_GTK2=1 \
+	NO_LIBAUDIT=1 \
+	NO_LIBCRYPTO=1 \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	CC="$(TARGET_CC)" \
+	LD="$(TARGET_CROSS)ld" \
+	CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
+	LDFLAGS="$(TARGET_LDFLAGS)" \
+	$(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \
+	WERROR=0 \
+	prefix=/usr
+
+ifdef CONFIG_USE_MUSL
+ MAKE_FLAGS += EXTRA_CFLAGS="-I$(CURDIR)/musl-include -include $(CURDIR)/musl-compat.h -D__UCLIBC__"
+endif
+
+define Build/Compile
+	+$(MAKE_FLAGS) $(MAKE) $(PKG_JOBS) \
+		-C $(PKG_BUILD_DIR) \
+		-f Makefile.perf \
+		--no-print-directory
+endef
+
+define Package/perf/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/perf $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,perf))
diff --git a/package/devel/perf/musl-compat.h b/package/devel/perf/musl-compat.h
new file mode 100644
index 0000000000..83aa00a7c8
--- /dev/null
+++ b/package/devel/perf/musl-compat.h
@@ -0,0 +1,43 @@
+#ifndef __PERF_MUSL_COMPAT_H
+#define __PERF_MUSL_COMPAT_H
+
+#ifndef __ASSEMBLER__
+
+#include <sys/ioctl.h>
+#include <asm/unistd.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#undef _IOWR
+#undef _IOR
+#undef _IOW
+#undef _IOC
+#undef _IO
+
+#define _SC_LEVEL1_DCACHE_LINESIZE -1
+
+static inline long sysconf_wrap(int name)
+{
+	FILE *f;
+	int val;
+
+	switch (name) {
+	case _SC_LEVEL1_DCACHE_LINESIZE:
+		f = fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
+		if (!f)
+			return 0;
+
+		if (fscanf(f, "%d", &val) != 1)
+			return 0;
+
+		fclose(f);
+		return val;
+	default:
+		return sysconf(name);
+	}
+}
+
+#define sysconf(_n) sysconf_wrap(_n)
+
+#endif
+#endif
diff --git a/package/devel/perf/musl-include/asm/errno.h b/package/devel/perf/musl-include/asm/errno.h
new file mode 100644
index 0000000000..8c4b1beb52
--- /dev/null
+++ b/package/devel/perf/musl-include/asm/errno.h
@@ -0,0 +1,8 @@
+#ifndef __MUSL_COMPAT_ASM_ERRNO_H
+#define __MUSL_COMPAT_ASM_ERRNO_H
+
+/* Avoid including different versions of errno.h, the defines (incorrectly)
+ * cause a redefinition error on PowerPC */
+#include <errno.h>
+
+#endif
diff --git a/package/devel/perf/musl-include/string.h b/package/devel/perf/musl-include/string.h
new file mode 100644
index 0000000000..65dc2f1e8f
--- /dev/null
+++ b/package/devel/perf/musl-include/string.h
@@ -0,0 +1,18 @@
+#ifndef __MUSL_COMPAT_STRING_H
+#define __MUSL_COMPAT_STRING_H
+
+#include_next <string.h>
+
+/* Change XSI compliant version into GNU extension hackery */
+static inline char *
+gnu_strerror_r(int err, char *buf, size_t buflen)
+{
+	if (strerror_r(err, buf, buflen))
+		return NULL;
+	return buf;
+}
+#ifdef _GNU_SOURCE
+#define strerror_r gnu_strerror_r
+#endif
+
+#endif
diff --git a/package/devel/strace/Makefile b/package/devel/strace/Makefile
new file mode 100644
index 0000000000..3f50b41a0b
--- /dev/null
+++ b/package/devel/strace/Makefile
@@ -0,0 +1,67 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=strace
+
+PKG_VERSION:=4.14
+PKG_RELEASE:=1
+PKG_MD5SUM:=1e39b5f7583256d7dc21170b9da529ae
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@SF/$(PKG_NAME)
+
+PKG_LICENSE:=BSD-3c
+PKG_LICENSE_FILES:=COPYRIGHT
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_FIXUP:=autoreconf
+PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_strace_libunwind
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+HOST_CFLAGS += -I$(LINUX_DIR)/user_headers/include
+
+CONFIGURE_VARS+= \
+	LDFLAGS_FOR_BUILD="$(HOST_LDFLAGS)" \
+	CPPFLAGS_FOR_BUILD="$(HOST_CPPFLAGS)" \
+	CFLAGS_FOR_BUILD="$(HOST_CFLAGS)" \
+	CC_FOR_BUILD="$(HOST_CC)"
+
+define Package/strace
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=System call tracer
+  DEPENDS:=+PACKAGE_strace_libunwind:libunwind
+  URL:=http://strace.sourceforge.net/
+endef
+
+define Package/strace/description
+A useful diagnostic, instructional, and debugging tool. Allows you to track what
+system calls a program makes while it is running.
+endef
+
+define Package/strace/config
+config PACKAGE_strace_libunwind
+	bool "Enable stack tracing support using libunwind (experimental)"
+	default n
+endef
+
+CONFIGURE_ARGS += --with-libunwind=$(if $(CONFIG_PACKAGE_strace_libunwind),yes,no)
+MAKE_FLAGS := \
+	CCOPT="$(TARGET_CFLAGS)"
+
+define Package/strace/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/strace $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,strace))
diff --git a/package/devel/strace/patches/100-workaround--pt-reg-collisions-ppc.patch b/package/devel/strace/patches/100-workaround--pt-reg-collisions-ppc.patch
new file mode 100644
index 0000000000..5dc1e6713f
--- /dev/null
+++ b/package/devel/strace/patches/100-workaround--pt-reg-collisions-ppc.patch
@@ -0,0 +1,19 @@
+diff --git a/ptrace.h b/ptrace.h
+index ddb46cb..48a54b8 100644
+--- a/ptrace.h
++++ b/ptrace.h
+@@ -55,7 +55,14 @@ extern long ptrace(int, int, char *, long);
+ # define ptrace_peeksiginfo_args XXX_ptrace_peeksiginfo_args
+ #endif
+ 
++#if POWERPC
++#include <linux/types.h>
++#define __ASSEMBLY__
++#endif
+ #include <linux/ptrace.h>
++#if POWERPC
++#undef __ASSEMBLY__
++#endif
+ 
+ #ifdef HAVE_STRUCT_IA64_FPREG
+ # undef ia64_fpreg
diff --git a/package/devel/trace-cmd/Makefile b/package/devel/trace-cmd/Makefile
new file mode 100644
index 0000000000..3571c1c2b7
--- /dev/null
+++ b/package/devel/trace-cmd/Makefile
@@ -0,0 +1,65 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=trace-cmd
+PKG_VERSION:=v2.6
+PKG_RELEASE=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=\
+		https://kernel.googlesource.com/pub/scm/linux/kernel/git/rostedt/trace-cmd \
+		https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=9be5d74805830a291615f2f34a27c903f6a37b1e
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=735b69f61a8c627037dcc01361cdb8415e5ab0ec892fbd731236c444003b0c71
+PKG_INSTALL:=1
+PKG_USE_MIPS16:=0
+PKG_LICENSE:=GPL-2.0
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/trace-cmd
+  SECTION:=devel
+  CATEGORY:=Development
+  TITLE:=Linux trace command line utility
+  DEPENDS:=
+endef
+
+define Package/trace-cmd-extra
+  SECTION:=devel
+  CATEGORY:=Development
+  TITLE:=Extra plugins for trace-cmd
+  DEPENDS:=
+endef
+
+MAKE_FLAGS += \
+	NO_PYTHON=1 \
+	prefix=/usr
+
+PLUGINS_DIR := $(PKG_INSTALL_DIR)/usr/lib/trace-cmd/plugins
+PLUGINS_MAIN := function hrtimer mac80211 sched_switch
+
+TARGET_CFLAGS += --std=gnu99 -D_GNU_SOURCE
+
+define Package/trace-cmd/install
+	$(INSTALL_DIR) $(1)/usr/bin $(1)/usr/lib/trace-cmd/plugins
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/trace-cmd $(1)/usr/bin/
+	$(CP) \
+		$(patsubst %,$(PLUGINS_DIR)/plugin_%.so,$(PLUGINS_MAIN)) \
+		$(1)/usr/lib/trace-cmd/plugins
+endef
+
+define Package/trace-cmd-extra/install
+	$(INSTALL_DIR) $(1)/usr/lib/trace-cmd/plugins
+	$(CP) \
+		$$(patsubst %,$(PLUGINS_DIR)/plugin_%.so, \
+			$$(filter-out $(PLUGINS_MAIN), \
+				$$(patsubst $(PLUGINS_DIR)/plugin_%.so,%, \
+					$$(wildcard $(PLUGINS_DIR)/plugin_*.so)))) \
+		$(1)/usr/lib/trace-cmd/plugins
+endef
+
+$(eval $(call BuildPackage,trace-cmd))
+$(eval $(call BuildPackage,trace-cmd-extra))
diff --git a/package/devel/trace-cmd/patches/110-mac80211_tracepoint.patch b/package/devel/trace-cmd/patches/110-mac80211_tracepoint.patch
new file mode 100644
index 0000000000..e2a68972a3
--- /dev/null
+++ b/package/devel/trace-cmd/patches/110-mac80211_tracepoint.patch
@@ -0,0 +1,24 @@
+--- a/plugin_mac80211.c
++++ b/plugin_mac80211.c
+@@ -179,12 +179,15 @@ static int drv_config(struct trace_seq *
+ 		{ 2, "IDLE" },
+ 		{ 3, "QOS"},
+ 	);
+-	pevent_print_num_field(s, " chan:%d/", event, "center_freq", record, 1);
+-	print_enum(s, event, "channel_type", data,
+-		{ 0, "noht" },
+-		{ 1, "ht20" },
+-		{ 2, "ht40-" },
+-		{ 3, "ht40+" });
++	pevent_print_num_field(s, " chan:%d@", event, "control_freq", record, 1);
++	print_enum(s, event, "chan_width", data,
++		{ 0, "20_noht" },
++		{ 1, "20" },
++		{ 2, "40" },
++		{ 3, "80" },
++		{ 4, "80p80" },
++		{ 5, "160" });
++
+ 	trace_seq_putc(s, ' ');
+ 	SF("power_level");
+ 
diff --git a/package/devel/valgrind/Makefile b/package/devel/valgrind/Makefile
new file mode 100644
index 0000000000..7b19420529
--- /dev/null
+++ b/package/devel/valgrind/Makefile
@@ -0,0 +1,179 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=valgrind
+PKG_VERSION:=3.12.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://valgrind.org/downloads/
+PKG_MD5SUM:=67ca4395b2527247780f36148b084f5743a68ab0c850cb43e4a5b4b012cf76a1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0+
+
+PKG_FIXUP = autoreconf
+PKG_INSTALL := 1
+PKG_BUILD_PARALLEL := 1
+PKG_USE_MIPS16:=0
+PKG_SSP:=0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/valgrind
+  SECTION:=devel
+  CATEGORY:=Development
+  DEPENDS:=@mips||mipsel||i386||x86_64||powerpc||arm_v7 +libpthread +librt
+  TITLE:=debugging and profiling tools for Linux
+  URL:=http://www.valgrind.org
+endef
+
+define Package/valgrind/default
+  $(Package/valgrind)
+  DEPENDS := valgrind
+endef
+
+define Package/valgrind-cachegrind
+  $(Package/valgrind/default)
+  TITLE += (cache profiling)
+endef
+
+define Package/valgrind-callgrind
+  $(Package/valgrind/default)
+  TITLE += (callgraph profiling)
+endef
+
+define Package/valgrind-drd
+  $(Package/valgrind/default)
+  TITLE += (thread error detection)
+endef
+
+define Package/valgrind-massif
+  $(Package/valgrind/default)
+  TITLE += (heap profiling)
+endef
+
+define Package/valgrind-helgrind
+  $(Package/valgrind/default)
+  TITLE += (thread debugging)
+endef
+
+define Package/valgrind-vgdb
+  $(Package/valgrind/default)
+  TITLE += (GDB interface)
+endef
+
+define Package/valgrind/description
+	Valgrind is an award-winning suite of tools for debugging and
+	profiling Linux programs. With the tools that come with Valgrind,
+	you can automatically detect many memory management and threading
+	bugs, avoiding hours of frustrating bug-hunting, making your
+	programs more stable. You can also perform detailed profiling,
+	to speed up and reduce memory use of your programs.
+endef
+
+CPU := $(patsubst x86_64,amd64,$(patsubst x86,i386,$(patsubst um,$(ARCH),$(LINUX_KARCH))))
+
+CONFIGURE_VARS += \
+	UNAME_R=$(LINUX_VERSION)
+
+ifeq ($(ARCH),x86_64)
+	CONFIGURE_ARGS += \
+		--enable-only64bit
+	BITS := 64bit
+else
+	CONFIGURE_ARGS += \
+		--enable-only32bit
+	BITS := 32bit
+endif
+
+CONFIGURE_ARGS += \
+	--enable-tls \
+	--without-x \
+	--without-mpicc \
+	--without-uiout \
+	--disable-valgrindmi \
+	--disable-tui \
+	--disable-valgrindtk \
+	--without-included-gettext \
+	--with-pagesize=4 \
+
+define Package/valgrind/install	
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/valgrind* $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/usr/lib/valgrind
+	$(CP) \
+		./files/default.supp \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/none-* \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/vgpreload_core*.so \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/$(CPU)-*.xml \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/$(BITS)-core*.xml \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/$(BITS)-linux*.xml \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/memcheck-* \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/vgpreload_memcheck*.so \
+		$(1)/usr/lib/valgrind/
+endef
+
+define Package/valgrind-cachegrind/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/cg_* $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/usr/lib/valgrind
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/cachegrind-* \
+		$(1)/usr/lib/valgrind/
+endef
+
+define Package/valgrind-callgrind/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/callgrind* $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/usr/lib/valgrind
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/callgrind-* \
+		$(1)/usr/lib/valgrind/
+endef
+
+define Package/valgrind-drd/install
+	$(INSTALL_DIR) $(1)/usr/lib/valgrind
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/drd-* \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/vgpreload_drd*.so \
+		$(1)/usr/lib/valgrind/
+endef
+
+define Package/valgrind-massif/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/ms_print $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/usr/lib/valgrind
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/massif-* \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/vgpreload_massif*.so \
+		$(1)/usr/lib/valgrind/
+endef
+
+define Package/valgrind-helgrind/install
+	$(INSTALL_DIR) $(1)/usr/lib/valgrind
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/helgrind-* \
+		$(PKG_INSTALL_DIR)/usr/lib/valgrind/vgpreload_helgrind*.so \
+		$(1)/usr/lib/valgrind/
+endef
+
+define Package/valgrind-vgdb/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vgdb $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,valgrind))
+$(eval $(call BuildPackage,valgrind-cachegrind))
+$(eval $(call BuildPackage,valgrind-callgrind))
+$(eval $(call BuildPackage,valgrind-drd))
+$(eval $(call BuildPackage,valgrind-massif))
+$(eval $(call BuildPackage,valgrind-helgrind))
+$(eval $(call BuildPackage,valgrind-vgdb))
diff --git a/package/devel/valgrind/files/default.supp b/package/devel/valgrind/files/default.supp
new file mode 100644
index 0000000000..beff55984c
--- /dev/null
+++ b/package/devel/valgrind/files/default.supp
@@ -0,0 +1,42 @@
+{
+   ld(Addr1)
+   Memcheck:Addr1
+   fun:*
+   obj:/lib/ld-*
+}
+{
+   ld(Addr2)
+   Memcheck:Addr2
+   fun:*
+   obj:/lib/ld-*
+}
+{
+   ld(Addr4)
+   Memcheck:Addr4
+   fun:*
+   obj:/lib/ld-*
+}
+{
+   ld(Cond)
+   Memcheck:Cond
+   fun:*
+   obj:/lib/ld-*
+}
+{
+	strlen(Cond)
+	Memcheck:Cond
+	fun:strlen
+	fun:*
+}
+{
+	strnlen(Cond)
+	Memcheck:Cond
+	fun:strnlen
+	fun:*
+}
+{
+	index(Cond)
+	Memcheck:Cond
+	fun:index
+	fun:*
+}
diff --git a/package/devel/valgrind/patches/100-fix_configure_check.patch b/package/devel/valgrind/patches/100-fix_configure_check.patch
new file mode 100644
index 0000000000..48477a3863
--- /dev/null
+++ b/package/devel/valgrind/patches/100-fix_configure_check.patch
@@ -0,0 +1,11 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -328,7 +328,7 @@ case "${host_os}" in
+         # Ok, this is linux. Check the kernel version
+         AC_MSG_CHECKING([for the kernel version])
+ 
+-        kernel=`uname -r`
++        kernel=${UNAME_R:-`uname -r`}
+ 
+         case "${kernel}" in
+              0.*|1.*|2.0.*|2.1.*|2.2.*|2.3.*|2.4.*|2.5.*) 
diff --git a/package/devel/valgrind/patches/130-fix_arm_arch_detection.patch b/package/devel/valgrind/patches/130-fix_arm_arch_detection.patch
new file mode 100644
index 0000000000..c8d203390c
--- /dev/null
+++ b/package/devel/valgrind/patches/130-fix_arm_arch_detection.patch
@@ -0,0 +1,17 @@
+Description: Fix FTBFS on armhf by correctly detecting the architecture
+Origin: vendor
+Bug-Debian: http://bugs.debian.org/730844
+Author: Alessandro Ghedini <ghedo@debian.org>
+Last-Update: 2013-11-30
+
+--- a/configure.ac
++++ b/configure.ac
+@@ -234,7 +234,7 @@ case "${host_cpu}" in
+         ARCH_MAX="s390x"
+         ;;
+ 
+-     armv7*)
++     arm*)
+ 	AC_MSG_RESULT([ok (${host_cpu})])
+ 	ARCH_MAX="arm"
+ 	;;
diff --git a/package/devel/valgrind/patches/200-musl_fix.patch b/package/devel/valgrind/patches/200-musl_fix.patch
new file mode 100644
index 0000000000..c6e6a6628f
--- /dev/null
+++ b/package/devel/valgrind/patches/200-musl_fix.patch
@@ -0,0 +1,45 @@
+--- a/coregrind/vg_preloaded.c
++++ b/coregrind/vg_preloaded.c
+@@ -57,7 +57,7 @@
+ void VG_NOTIFY_ON_LOAD(freeres)(Vg_FreeresToRun to_run);
+ void VG_NOTIFY_ON_LOAD(freeres)(Vg_FreeresToRun to_run)
+ {
+-#  if !defined(__UCLIBC__) \
++#  if !defined(__UCLIBC__) && defined(__GLIBC__) \
+       && !defined(VGPV_arm_linux_android) \
+       && !defined(VGPV_x86_linux_android) \
+       && !defined(VGPV_mips32_linux_android) \
+--- a/include/pub_tool_redir.h
++++ b/include/pub_tool_redir.h
+@@ -243,7 +243,7 @@
+ /* --- Soname of the standard C library. --- */
+ 
+ #if defined(VGO_linux) || defined(VGO_solaris)
+-#  define  VG_Z_LIBC_SONAME  libcZdsoZa              // libc.so*
++#  define  VG_Z_LIBC_SONAME  libcZdZa                // libc.*
+ 
+ #elif defined(VGO_darwin) && (DARWIN_VERS <= DARWIN_10_6)
+ #  define  VG_Z_LIBC_SONAME  libSystemZdZaZddylib    // libSystem.*.dylib
+@@ -275,7 +275,11 @@
+ /* --- Soname of the pthreads library. --- */
+ 
+ #if defined(VGO_linux)
++# if defined(__GLIBC__) || defined(__UCLIBC__)
+ #  define  VG_Z_LIBPTHREAD_SONAME  libpthreadZdsoZd0     // libpthread.so.0
++# else
++#  define  VG_Z_LIBPTHREAD_SONAME  libcZdZa              // libc.*
++# endif
+ #elif defined(VGO_darwin)
+ #  define  VG_Z_LIBPTHREAD_SONAME  libSystemZdZaZddylib  // libSystem.*.dylib
+ #elif defined(VGO_solaris)
+--- a/configure.ac
++++ b/configure.ac
+@@ -1047,8 +1047,6 @@ case "${GLIBC_VERSION}" in
+ 	;;
+      2.0|2.1|*)
+ 	AC_MSG_RESULT([unsupported version ${GLIBC_VERSION}])
+-	AC_MSG_ERROR([Valgrind requires glibc version 2.2 or later,])
+-	AC_MSG_ERROR([Darwin libc, Bionic libc or Solaris libc])
+ 	;;
+ esac
+ 
diff --git a/package/kernel/avila-wdt/Makefile b/package/kernel/avila-wdt/Makefile
new file mode 100644
index 0000000000..94bda9b8d5
--- /dev/null
+++ b/package/kernel/avila-wdt/Makefile
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=avila-wdt
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/avila-wdt
+  SUBMENU:=Other modules
+  TITLE:=GPIO hardware watchdog driver for modified Avila boards
+  DEPENDS:=@GPIO_SUPPORT @TARGET_ixp4xx
+  FILES:=$(PKG_BUILD_DIR)/avila-wdt.ko
+  AUTOLOAD:=$(call AutoLoad,10,avila-wdt)
+endef
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)"
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,avila-wdt))
diff --git a/package/kernel/avila-wdt/src/Makefile b/package/kernel/avila-wdt/src/Makefile
new file mode 100644
index 0000000000..90d90657ed
--- /dev/null
+++ b/package/kernel/avila-wdt/src/Makefile
@@ -0,0 +1 @@
+obj-m := avila-wdt.o
diff --git a/package/kernel/avila-wdt/src/avila-wdt.c b/package/kernel/avila-wdt/src/avila-wdt.c
new file mode 100644
index 0000000000..22a3d6c7ea
--- /dev/null
+++ b/package/kernel/avila-wdt/src/avila-wdt.c
@@ -0,0 +1,231 @@
+/*
+ * avila-wdt.c 
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * based on:
+ * drivers/char/watchdog/ixp4xx_wdt.c
+ *
+ * Watchdog driver for Intel IXP4xx network processors
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+#include <mach/hardware.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = 20;	/* (secs) Default is 20 seconds */
+static unsigned long wdt_status;
+static atomic_t wdt_counter;
+struct timer_list wdt_timer;
+
+#define	WDT_IN_USE		0
+#define	WDT_OK_TO_CLOSE		1
+#define WDT_RUNNING		2
+
+static void wdt_refresh(unsigned long data)
+{
+	if (test_bit(WDT_RUNNING, &wdt_status)) {
+		if (atomic_dec_and_test(&wdt_counter)) {
+			printk(KERN_WARNING "Avila watchdog expired, expect a reboot soon!\n");
+			clear_bit(WDT_RUNNING, &wdt_status);
+			return;
+		}
+	}
+
+	/* strobe to the watchdog */
+	gpio_line_set(14, IXP4XX_GPIO_HIGH);
+	gpio_line_set(14, IXP4XX_GPIO_LOW);
+
+	mod_timer(&wdt_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static void wdt_enable(void)
+{
+	atomic_set(&wdt_counter, heartbeat * 2);
+
+	/* Disable clock generator output on GPIO 14/15 */
+	*IXP4XX_GPIO_GPCLKR &= ~(1 << 8);
+
+	/* activate GPIO 14 out */
+	gpio_line_config(14, IXP4XX_GPIO_OUT);
+	gpio_line_set(14, IXP4XX_GPIO_LOW);
+
+	if (!test_bit(WDT_RUNNING, &wdt_status))
+		wdt_refresh(0);
+	set_bit(WDT_RUNNING, &wdt_status);
+}
+
+static void wdt_disable(void)
+{
+	/* Re-enable clock generator output on GPIO 14/15 */
+	*IXP4XX_GPIO_GPCLKR |= (1 << 8);
+}
+
+static int avila_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+		return -EBUSY;
+
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+	wdt_enable();
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t
+avila_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+			}
+		}
+		wdt_enable();
+	}
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options	= WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
+			  WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+	.identity	= "Avila Watchdog",
+};
+
+
+static long avila_wdt_ioctl(struct file *file, unsigned int cmd,
+							unsigned long arg)
+{
+	int ret = -ENOTTY;
+	int time;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user((struct watchdog_info *)arg, &ident,
+				   sizeof(ident)) ? -EFAULT : 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wdt_enable();
+		ret = 0;
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, (int *)arg);
+		if (ret)
+			break;
+
+		if (time <= 0 || time > 60) {
+			ret = -EINVAL;
+			break;
+		}
+
+		heartbeat = time;
+		wdt_enable();
+		/* Fall through */
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(heartbeat, (int *)arg);
+		break;
+	}
+	return ret;
+}
+
+static int avila_wdt_release(struct inode *inode, struct file *file)
+{
+	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+		wdt_disable();
+	else
+		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+					"timer will not stop\n");
+	clear_bit(WDT_IN_USE, &wdt_status);
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	return 0;
+}
+
+
+static const struct file_operations avila_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= avila_wdt_write,
+	.unlocked_ioctl	= avila_wdt_ioctl,
+	.open		= avila_wdt_open,
+	.release	= avila_wdt_release,
+};
+
+static struct miscdevice avila_wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR + 1,
+	.name		= "avila_watchdog",
+	.fops		= &avila_wdt_fops,
+};
+
+static int __init avila_wdt_init(void)
+{
+	int ret;
+
+	init_timer(&wdt_timer);
+	wdt_timer.expires = 0;
+	wdt_timer.data = 0;
+	wdt_timer.function = wdt_refresh;
+	ret = misc_register(&avila_wdt_miscdev);
+	if (ret == 0)
+		printk(KERN_INFO "Avila Watchdog Timer: heartbeat %d sec\n",
+			heartbeat);
+	return ret;
+}
+
+static void __exit avila_wdt_exit(void)
+{
+	misc_deregister(&avila_wdt_miscdev);
+	del_timer(&wdt_timer);
+	wdt_disable();
+}
+
+
+module_init(avila_wdt_init);
+module_exit(avila_wdt_exit);
+
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_DESCRIPTION("Gateworks Avila Hardware Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 20s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
diff --git a/package/kernel/button-hotplug/Makefile b/package/kernel/button-hotplug/Makefile
new file mode 100644
index 0000000000..d90d7746f5
--- /dev/null
+++ b/package/kernel/button-hotplug/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=button-hotplug
+PKG_RELEASE:=3
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/button-hotplug
+  SUBMENU:=Other modules
+  TITLE:=Button Hotplug driver
+  DEPENDS:=+kmod-input-core
+  FILES:=$(PKG_BUILD_DIR)/button-hotplug.ko
+  AUTOLOAD:=$(call AutoLoad,30,button-hotplug,1)
+  KCONFIG:=
+endef
+
+define KernelPackage/button-hotplug/description
+  Kernel module to generate button uevent-s from input subsystem events.
+  If your device uses GPIO buttons, see gpio-button-hotplug.
+endef
+
+EXTRA_KCONFIG:= \
+	CONFIG_BUTTON_HOTPLUG=m
+
+EXTRA_CFLAGS:= \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)" \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+	$(EXTRA_KCONFIG)
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,button-hotplug))
diff --git a/package/kernel/button-hotplug/src/Kconfig b/package/kernel/button-hotplug/src/Kconfig
new file mode 100644
index 0000000000..aa292e9c13
--- /dev/null
+++ b/package/kernel/button-hotplug/src/Kconfig
@@ -0,0 +1,2 @@
+config BUTTON_HOTPLUG
+	tristate "Button Hotplug driver"
diff --git a/package/kernel/button-hotplug/src/Makefile b/package/kernel/button-hotplug/src/Makefile
new file mode 100644
index 0000000000..230d604f8c
--- /dev/null
+++ b/package/kernel/button-hotplug/src/Makefile
@@ -0,0 +1 @@
+obj-${CONFIG_BUTTON_HOTPLUG}	+= button-hotplug.o
\ No newline at end of file
diff --git a/package/kernel/button-hotplug/src/button-hotplug.c b/package/kernel/button-hotplug/src/button-hotplug.c
new file mode 100644
index 0000000000..5294a9700d
--- /dev/null
+++ b/package/kernel/button-hotplug/src/button-hotplug.c
@@ -0,0 +1,343 @@
+/*
+ *  Button Hotplug driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  Based on the diag.c - GPIO interface driver for Broadcom boards
+ *    Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
+ *    Copyright (C) 2006-2007 Felix Fietkau <nbd@nbd.name>
+ *    Copyright (C) 2008 Andy Boyett <agb@openwrt.org>
+ *
+ *  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/module.h>
+#include <linux/version.h>
+#include <linux/kmod.h>
+#include <linux/input.h>
+
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/kobject.h>
+
+#define DRV_NAME	"button-hotplug"
+#define DRV_VERSION	"0.4.1"
+#define DRV_DESC	"Button Hotplug driver"
+
+#define BH_SKB_SIZE	2048
+
+#define PFX	DRV_NAME ": "
+
+#undef BH_DEBUG
+
+#ifdef BH_DEBUG
+#define BH_DBG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, DRV_NAME, ##args )
+#else
+#define BH_DBG(fmt, args...) do {} while (0)
+#endif
+
+#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, DRV_NAME, ##args )
+
+#ifndef BIT_MASK
+#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
+#endif
+
+struct bh_priv {
+	unsigned long		*seen;
+	struct input_handle	handle;
+};
+
+struct bh_event {
+	const char		*name;
+	char			*action;
+	unsigned long		seen;
+
+	struct sk_buff		*skb;
+	struct work_struct	work;
+};
+
+struct bh_map {
+	unsigned int	code;
+	const char	*name;
+};
+
+extern u64 uevent_next_seqnum(void);
+
+#define BH_MAP(_code, _name)		\
+	{				\
+		.code = (_code),	\
+		.name = (_name),	\
+	}
+
+static struct bh_map button_map[] = {
+	BH_MAP(BTN_0,		"BTN_0"),
+	BH_MAP(BTN_1,		"BTN_1"),
+	BH_MAP(BTN_2,		"BTN_2"),
+	BH_MAP(BTN_3,		"BTN_3"),
+	BH_MAP(BTN_4,		"BTN_4"),
+	BH_MAP(BTN_5,		"BTN_5"),
+	BH_MAP(BTN_6,		"BTN_6"),
+	BH_MAP(BTN_7,		"BTN_7"),
+	BH_MAP(BTN_8,		"BTN_8"),
+	BH_MAP(BTN_9,		"BTN_9"),
+	BH_MAP(KEY_RESTART,	"reset"),
+	BH_MAP(KEY_POWER,	"power"),
+	BH_MAP(KEY_RFKILL,	"rfkill"),
+	BH_MAP(KEY_WPS_BUTTON,	"wps"),
+	BH_MAP(KEY_WIMAX,	"wwan"),
+};
+
+/* -------------------------------------------------------------------------*/
+
+static int bh_event_add_var(struct bh_event *event, int argv,
+		const char *format, ...)
+{
+	static char buf[128];
+	char *s;
+	va_list args;
+	int len;
+
+	if (argv)
+		return 0;
+
+	va_start(args, format);
+	len = vsnprintf(buf, sizeof(buf), format, args);
+	va_end(args);
+
+	if (len >= sizeof(buf)) {
+		BH_ERR("buffer size too small\n");
+		WARN_ON(1);
+		return -ENOMEM;
+	}
+
+	s = skb_put(event->skb, len + 1);
+	strcpy(s, buf);
+
+	BH_DBG("added variable '%s'\n", s);
+
+	return 0;
+}
+
+static int button_hotplug_fill_event(struct bh_event *event)
+{
+	int ret;
+
+	ret = bh_event_add_var(event, 0, "HOME=%s", "/");
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "PATH=%s",
+					"/sbin:/bin:/usr/sbin:/usr/bin");
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "SUBSYSTEM=%s", "button");
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "ACTION=%s", event->action);
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "BUTTON=%s", event->name);
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "SEEN=%ld", event->seen);
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
+
+	return ret;
+}
+
+static void button_hotplug_work(struct work_struct *work)
+{
+	struct bh_event *event = container_of(work, struct bh_event, work);
+	int ret = 0;
+
+	event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
+	if (!event->skb)
+		goto out_free_event;
+
+	ret = bh_event_add_var(event, 0, "%s@", event->action);
+	if (ret)
+		goto out_free_skb;
+
+	ret = button_hotplug_fill_event(event);
+	if (ret)
+		goto out_free_skb;
+
+	NETLINK_CB(event->skb).dst_group = 1;
+	broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
+
+ out_free_skb:
+	if (ret) {
+		BH_ERR("work error %d\n", ret);
+		kfree_skb(event->skb);
+	}
+ out_free_event:
+	kfree(event);
+}
+
+static int button_hotplug_create_event(const char *name, unsigned long seen,
+		int pressed)
+{
+	struct bh_event *event;
+
+	BH_DBG("create event, name=%s, seen=%lu, pressed=%d\n",
+		name, seen, pressed);
+
+	event = kzalloc(sizeof(*event), GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	event->name = name;
+	event->seen = seen;
+	event->action = pressed ? "pressed" : "released";
+
+	INIT_WORK(&event->work, (void *)(void *)button_hotplug_work);
+	schedule_work(&event->work);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------*/
+
+static int button_get_index(unsigned int code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(button_map); i++)
+		if (button_map[i].code == code)
+			return i;
+
+	return -1;
+}
+static void button_hotplug_event(struct input_handle *handle,
+			   unsigned int type, unsigned int code, int value)
+{
+	struct bh_priv *priv = handle->private;
+	unsigned long seen = jiffies;
+	int btn;
+
+	BH_DBG("event type=%u, code=%u, value=%d\n", type, code, value);
+
+	if (type != EV_KEY)
+		return;
+
+	btn = button_get_index(code);
+	if (btn < 0)
+		return;
+
+	button_hotplug_create_event(button_map[btn].name,
+			(seen - priv->seen[btn]) / HZ, value);
+	priv->seen[btn] = seen;
+}
+
+static int button_hotplug_connect(struct input_handler *handler,
+		struct input_dev *dev, const struct input_device_id *id)
+{
+	struct bh_priv *priv;
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(button_map); i++)
+		if (test_bit(button_map[i].code, dev->keybit))
+			break;
+
+	if (i == ARRAY_SIZE(button_map))
+		return -ENODEV;
+
+	priv = kzalloc(sizeof(*priv) +
+		       (sizeof(unsigned long) * ARRAY_SIZE(button_map)),
+		       GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->seen = (unsigned long *) &priv[1];
+	priv->handle.private = priv;
+	priv->handle.dev = dev;
+	priv->handle.handler = handler;
+	priv->handle.name = DRV_NAME;
+
+	ret = input_register_handle(&priv->handle);
+	if (ret)
+		goto err_free_priv;
+
+	ret = input_open_device(&priv->handle);
+	if (ret)
+		goto err_unregister_handle;
+
+	BH_DBG("connected to %s\n", dev->name);
+
+	return 0;
+
+ err_unregister_handle:
+	input_unregister_handle(&priv->handle);
+
+ err_free_priv:
+	kfree(priv);
+	return ret;
+}
+
+static void button_hotplug_disconnect(struct input_handle *handle)
+{
+	struct bh_priv *priv = handle->private;
+
+	input_close_device(handle);
+	input_unregister_handle(handle);
+
+	kfree(priv);
+}
+
+static const struct input_device_id button_hotplug_ids[] = {
+	{
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_KEY) },
+        },
+	{
+		/* Terminating entry */
+	},
+};
+
+MODULE_DEVICE_TABLE(input, button_hotplug_ids);
+
+static struct input_handler button_hotplug_handler = {
+	.event =	button_hotplug_event,
+	.connect =	button_hotplug_connect,
+	.disconnect =	button_hotplug_disconnect,
+	.name =		DRV_NAME,
+	.id_table =	button_hotplug_ids,
+};
+
+/* -------------------------------------------------------------------------*/
+
+static int __init button_hotplug_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+	ret = input_register_handler(&button_hotplug_handler);
+	if (ret)
+		BH_ERR("unable to register input handler\n");
+
+	return ret;
+}
+module_init(button_hotplug_init);
+
+static void __exit button_hotplug_exit(void)
+{
+	input_unregister_handler(&button_hotplug_handler);
+}
+module_exit(button_hotplug_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/package/kernel/gpio-button-hotplug/Makefile b/package/kernel/gpio-button-hotplug/Makefile
new file mode 100644
index 0000000000..a067adc4e1
--- /dev/null
+++ b/package/kernel/gpio-button-hotplug/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2008-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=gpio-button-hotplug
+PKG_RELEASE:=2
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/gpio-button-hotplug
+  SUBMENU:=Other modules
+  TITLE:=Simple GPIO Button Hotplug driver
+  FILES:=$(PKG_BUILD_DIR)/gpio-button-hotplug.ko
+  AUTOLOAD:=$(call AutoLoad,30,gpio-button-hotplug,1)
+  KCONFIG:=
+endef
+
+define KernelPackage/gpio-button-hotplug/description
+ This is a replacement for the following in-kernel drivers:
+ 1) gpio_keys (KEYBOARD_GPIO)
+ 2) gpio_keys_polled (KEYBOARD_GPIO_POLLED)
+
+ Instead of generating input events (like in-kernel drivers do) it generates
+ uevent-s and broadcasts them. This allows disabling input subsystem which is
+ an overkill for OpenWrt simple needs.
+endef
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)"
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,gpio-button-hotplug))
diff --git a/package/kernel/gpio-button-hotplug/src/Makefile b/package/kernel/gpio-button-hotplug/src/Makefile
new file mode 100644
index 0000000000..e968865631
--- /dev/null
+++ b/package/kernel/gpio-button-hotplug/src/Makefile
@@ -0,0 +1 @@
+obj-m += gpio-button-hotplug.o
diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c
new file mode 100644
index 0000000000..2bd3ff1813
--- /dev/null
+++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c
@@ -0,0 +1,676 @@
+/*
+ *  GPIO Button Hotplug driver
+ *
+ *  Copyright (C) 2012 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  Based on the diag.c - GPIO interface driver for Broadcom boards
+ *    Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
+ *    Copyright (C) 2006-2007 Felix Fietkau <nbd@nbd.name>
+ *    Copyright (C) 2008 Andy Boyett <agb@openwrt.org>
+ *
+ *  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/module.h>
+#include <linux/version.h>
+#include <linux/kmod.h>
+
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/kobject.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio_keys.h>
+
+#define DRV_NAME	"gpio-keys"
+
+#define BH_SKB_SIZE	2048
+
+#define PFX	DRV_NAME ": "
+
+#undef BH_DEBUG
+
+#ifdef BH_DEBUG
+#define BH_DBG(fmt, args...) printk(KERN_DEBUG "%s: " fmt, DRV_NAME, ##args )
+#else
+#define BH_DBG(fmt, args...) do {} while (0)
+#endif
+
+#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, DRV_NAME, ##args )
+
+struct bh_priv {
+	unsigned long		seen;
+};
+
+struct bh_event {
+	const char		*name;
+	unsigned int		type;
+	char			*action;
+	unsigned long		seen;
+
+	struct sk_buff		*skb;
+	struct work_struct	work;
+};
+
+struct bh_map {
+	unsigned int	code;
+	const char	*name;
+};
+
+struct gpio_keys_button_data {
+	struct delayed_work work;
+	struct bh_priv bh;
+	int last_state;
+	int count;
+	int threshold;
+	int can_sleep;
+	struct gpio_keys_button *b;
+};
+
+extern u64 uevent_next_seqnum(void);
+
+#define BH_MAP(_code, _name)		\
+	{				\
+		.code = (_code),	\
+		.name = (_name),	\
+	}
+
+static struct bh_map button_map[] = {
+	BH_MAP(BTN_0,			"BTN_0"),
+	BH_MAP(BTN_1,			"BTN_1"),
+	BH_MAP(BTN_2,			"BTN_2"),
+	BH_MAP(BTN_3,			"BTN_3"),
+	BH_MAP(BTN_4,			"BTN_4"),
+	BH_MAP(BTN_5,			"BTN_5"),
+	BH_MAP(BTN_6,			"BTN_6"),
+	BH_MAP(BTN_7,			"BTN_7"),
+	BH_MAP(BTN_8,			"BTN_8"),
+	BH_MAP(BTN_9,			"BTN_9"),
+	BH_MAP(KEY_BRIGHTNESS_ZERO,	"brightness_zero"),
+	BH_MAP(KEY_CONFIG,		"config"),
+	BH_MAP(KEY_COPY,		"copy"),
+	BH_MAP(KEY_EJECTCD,		"eject"),
+	BH_MAP(KEY_HELP,		"help"),
+	BH_MAP(KEY_LIGHTS_TOGGLE,	"lights_toggle"),
+	BH_MAP(KEY_PHONE,		"phone"),
+	BH_MAP(KEY_POWER,		"power"),
+	BH_MAP(KEY_RESTART,		"reset"),
+	BH_MAP(KEY_RFKILL,		"rfkill"),
+	BH_MAP(KEY_VIDEO,		"video"),
+	BH_MAP(KEY_WIMAX,		"wwan"),
+	BH_MAP(KEY_WLAN,		"wlan"),
+	BH_MAP(KEY_WPS_BUTTON,		"wps"),
+};
+
+/* -------------------------------------------------------------------------*/
+
+static __printf(3, 4)
+int bh_event_add_var(struct bh_event *event, int argv, const char *format, ...)
+{
+	static char buf[128];
+	char *s;
+	va_list args;
+	int len;
+
+	if (argv)
+		return 0;
+
+	va_start(args, format);
+	len = vsnprintf(buf, sizeof(buf), format, args);
+	va_end(args);
+
+	if (len >= sizeof(buf)) {
+		WARN(1, "buffer size too small");
+		return -ENOMEM;
+	}
+
+	s = skb_put(event->skb, len + 1);
+	strcpy(s, buf);
+
+	BH_DBG("added variable '%s'\n", s);
+
+	return 0;
+}
+
+static int button_hotplug_fill_event(struct bh_event *event)
+{
+	int ret;
+
+	ret = bh_event_add_var(event, 0, "HOME=%s", "/");
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "PATH=%s",
+					"/sbin:/bin:/usr/sbin:/usr/bin");
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "SUBSYSTEM=%s", "button");
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "ACTION=%s", event->action);
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "BUTTON=%s", event->name);
+	if (ret)
+		return ret;
+
+	if (event->type == EV_SW) {
+		ret = bh_event_add_var(event, 0, "TYPE=%s", "switch");
+		if (ret)
+			return ret;
+	}
+
+	ret = bh_event_add_var(event, 0, "SEEN=%ld", event->seen);
+	if (ret)
+		return ret;
+
+	ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
+
+	return ret;
+}
+
+static void button_hotplug_work(struct work_struct *work)
+{
+	struct bh_event *event = container_of(work, struct bh_event, work);
+	int ret = 0;
+
+	event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
+	if (!event->skb)
+		goto out_free_event;
+
+	ret = bh_event_add_var(event, 0, "%s@", event->action);
+	if (ret)
+		goto out_free_skb;
+
+	ret = button_hotplug_fill_event(event);
+	if (ret)
+		goto out_free_skb;
+
+	NETLINK_CB(event->skb).dst_group = 1;
+	broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
+
+ out_free_skb:
+	if (ret) {
+		BH_ERR("work error %d\n", ret);
+		kfree_skb(event->skb);
+	}
+ out_free_event:
+	kfree(event);
+}
+
+static int button_hotplug_create_event(const char *name, unsigned int type,
+		unsigned long seen, int pressed)
+{
+	struct bh_event *event;
+
+	BH_DBG("create event, name=%s, seen=%lu, pressed=%d\n",
+		name, seen, pressed);
+
+	event = kzalloc(sizeof(*event), GFP_KERNEL);
+	if (!event)
+		return -ENOMEM;
+
+	event->name = name;
+	event->type = type;
+	event->seen = seen;
+	event->action = pressed ? "pressed" : "released";
+
+	INIT_WORK(&event->work, (void *)(void *)button_hotplug_work);
+	schedule_work(&event->work);
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------*/
+
+static int button_get_index(unsigned int code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(button_map); i++)
+		if (button_map[i].code == code)
+			return i;
+
+	return -1;
+}
+
+static void button_hotplug_event(struct gpio_keys_button_data *data,
+			   unsigned int type, int value)
+{
+	struct bh_priv *priv = &data->bh;
+	unsigned long seen = jiffies;
+	int btn;
+
+	BH_DBG("event type=%u, code=%u, value=%d\n", type, data->b->code, value);
+
+	if ((type != EV_KEY) && (type != EV_SW))
+		return;
+
+	btn = button_get_index(data->b->code);
+	if (btn < 0)
+		return;
+
+	button_hotplug_create_event(button_map[btn].name, type,
+			(seen - priv->seen) / HZ, value);
+	priv->seen = seen;
+}
+
+struct gpio_keys_button_dev {
+	int polled;
+	struct delayed_work work;
+
+	struct device *dev;
+	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_button_data data[0];
+};
+
+static int gpio_button_get_value(struct gpio_keys_button_data *bdata)
+{
+	int val;
+
+	if (bdata->can_sleep)
+		val = !!gpio_get_value_cansleep(bdata->b->gpio);
+	else
+		val = !!gpio_get_value(bdata->b->gpio);
+
+	return val ^ bdata->b->active_low;
+}
+
+static void gpio_keys_polled_check_state(struct gpio_keys_button_data *bdata)
+{
+	int state = gpio_button_get_value(bdata);
+
+	if (state != bdata->last_state) {
+		unsigned int type = bdata->b->type ?: EV_KEY;
+
+		if (bdata->count < bdata->threshold) {
+			bdata->count++;
+			return;
+		}
+
+		if ((bdata->last_state != -1) || (type == EV_SW))
+			button_hotplug_event(bdata, type, state);
+
+		bdata->last_state = state;
+	}
+
+	bdata->count = 0;
+}
+
+static void gpio_keys_polled_queue_work(struct gpio_keys_button_dev *bdev)
+{
+	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	unsigned long delay = msecs_to_jiffies(pdata->poll_interval);
+
+	if (delay >= HZ)
+		delay = round_jiffies_relative(delay);
+	schedule_delayed_work(&bdev->work, delay);
+}
+
+static void gpio_keys_polled_poll(struct work_struct *work)
+{
+	struct gpio_keys_button_dev *bdev =
+		container_of(work, struct gpio_keys_button_dev, work.work);
+	int i;
+
+	for (i = 0; i < bdev->pdata->nbuttons; i++) {
+		struct gpio_keys_button_data *bdata = &bdev->data[i];
+		gpio_keys_polled_check_state(bdata);
+	}
+	gpio_keys_polled_queue_work(bdev);
+}
+
+static void gpio_keys_polled_close(struct gpio_keys_button_dev *bdev)
+{
+	struct gpio_keys_platform_data *pdata = bdev->pdata;
+
+	cancel_delayed_work_sync(&bdev->work);
+
+	if (pdata->disable)
+		pdata->disable(bdev->dev);
+}
+
+static irqreturn_t button_handle_irq(int irq, void *_bdata)
+{
+	struct gpio_keys_button_data *bdata = (struct gpio_keys_button_data *) _bdata;
+
+	button_hotplug_event(bdata, bdata->b->type ?: EV_KEY, gpio_button_get_value(bdata));
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_OF
+static struct gpio_keys_platform_data *
+gpio_keys_get_devtree_pdata(struct device *dev)
+{
+	struct device_node *node, *pp;
+	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_button *button;
+	int error;
+	int nbuttons;
+	int i = 0;
+
+	node = dev->of_node;
+	if (!node)
+		return NULL;
+
+	nbuttons = of_get_child_count(node);
+	if (nbuttons == 0)
+		return NULL;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * (sizeof *button),
+		GFP_KERNEL);
+	if (!pdata) {
+		error = -ENOMEM;
+		goto err_out;
+	}
+
+	pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
+	pdata->nbuttons = nbuttons;
+
+	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+	of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+
+	for_each_child_of_node(node, pp) {
+		enum of_gpio_flags flags;
+
+		if (!of_find_property(pp, "gpios", NULL)) {
+			pdata->nbuttons--;
+			dev_warn(dev, "Found button without gpios\n");
+			continue;
+		}
+
+		button = &pdata->buttons[i++];
+
+		button->gpio = of_get_gpio_flags(pp, 0, &flags);
+		if (button->gpio < 0) {
+			error = button->gpio;
+			if (error != -ENOENT) {
+				if (error != -EPROBE_DEFER)
+					dev_err(dev,
+						"Failed to get gpio flags, error: %d\n",
+						error);
+				return ERR_PTR(error);
+			}
+		} else {
+			button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+		}
+
+		if (of_property_read_u32(pp, "linux,code", &button->code)) {
+			dev_err(dev, "Button without keycode: 0x%x\n",
+				button->gpio);
+			error = -EINVAL;
+			goto err_out;
+		}
+
+		button->desc = of_get_property(pp, "label", NULL);
+
+		if (of_property_read_u32(pp, "linux,input-type", &button->type))
+			button->type = EV_KEY;
+
+		button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+		if (of_property_read_u32(pp, "debounce-interval",
+					&button->debounce_interval))
+			button->debounce_interval = 5;
+	}
+
+	if (pdata->nbuttons == 0) {
+		error = -EINVAL;
+		goto err_out;
+	}
+
+	return pdata;
+
+err_out:
+	return ERR_PTR(error);
+}
+
+static struct of_device_id gpio_keys_of_match[] = {
+	{ .compatible = "gpio-keys", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
+
+static struct of_device_id gpio_keys_polled_of_match[] = {
+	{ .compatible = "gpio-keys-polled", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
+
+#else
+
+static inline struct gpio_keys_platform_data *
+gpio_keys_get_devtree_pdata(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
+static int gpio_keys_button_probe(struct platform_device *pdev,
+		struct gpio_keys_button_dev **_bdev, int polled)
+{
+	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct gpio_keys_button_dev *bdev;
+	struct gpio_keys_button *buttons;
+	int error;
+	int i;
+
+	if (!pdata) {
+		pdata = gpio_keys_get_devtree_pdata(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		if (!pdata) {
+			dev_err(dev, "missing platform data\n");
+			return -EINVAL;
+		}
+		pdev->dev.platform_data = pdata;
+	}
+
+	if (polled && !pdata->poll_interval) {
+		dev_err(dev, "missing poll_interval value\n");
+		return -EINVAL;
+	}
+
+	buttons = devm_kzalloc(dev, pdata->nbuttons * sizeof(struct gpio_keys_button),
+		       GFP_KERNEL);
+	if (!buttons) {
+		dev_err(dev, "no memory for button data\n");
+		return -ENOMEM;
+	}
+	memcpy(buttons, pdata->buttons, pdata->nbuttons * sizeof(struct gpio_keys_button));
+
+	bdev = devm_kzalloc(dev, sizeof(struct gpio_keys_button_dev) +
+		       pdata->nbuttons * sizeof(struct gpio_keys_button_data),
+		       GFP_KERNEL);
+	if (!bdev) {
+		dev_err(dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	bdev->polled = polled;
+
+	for (i = 0; i < pdata->nbuttons; i++) {
+		struct gpio_keys_button *button = &buttons[i];
+		struct gpio_keys_button_data *bdata = &bdev->data[i];
+		unsigned int gpio = button->gpio;
+
+		if (button->wakeup) {
+			dev_err(dev, DRV_NAME "does not support wakeup\n");
+			return -EINVAL;
+		}
+
+		error = devm_gpio_request(dev, gpio,
+				     button->desc ? button->desc : DRV_NAME);
+		if (error) {
+			dev_err(dev, "unable to claim gpio %u, err=%d\n",
+				gpio, error);
+			return error;
+		}
+
+		error = gpio_direction_input(gpio);
+		if (error) {
+			dev_err(dev,
+				"unable to set direction on gpio %u, err=%d\n",
+				gpio, error);
+			return error;
+		}
+
+		bdata->can_sleep = gpio_cansleep(gpio);
+		bdata->last_state = -1;
+
+		if (bdev->polled)
+			bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
+						pdata->poll_interval);
+		else
+			bdata->threshold = 1;
+
+		bdata->b = &pdata->buttons[i];
+	}
+
+	bdev->dev = &pdev->dev;
+	bdev->pdata = pdata;
+	platform_set_drvdata(pdev, bdev);
+
+	*_bdev = bdev;
+
+	return 0;
+}
+
+static int gpio_keys_probe(struct platform_device *pdev)
+{
+	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_button_dev *bdev;
+	int ret, i;
+
+
+	ret = gpio_keys_button_probe(pdev, &bdev, 0);
+
+	if (ret)
+		return ret;
+
+	pdata = pdev->dev.platform_data;
+	for (i = 0; i < pdata->nbuttons; i++) {
+		struct gpio_keys_button *button = &pdata->buttons[i];
+		struct gpio_keys_button_data *bdata = &bdev->data[i];
+
+		if (!button->irq)
+			button->irq = gpio_to_irq(button->gpio);
+		if (button->irq < 0) {
+			dev_err(&pdev->dev, "failed to get irq for gpio:%d\n", button->gpio);
+			continue;
+		}
+
+		ret = devm_request_threaded_irq(&pdev->dev, button->irq, NULL, button_handle_irq,
+						IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+						dev_name(&pdev->dev), bdata);
+		if (ret < 0)
+			dev_err(&pdev->dev, "failed to request irq:%d for gpio:%d\n", button->irq, button->gpio);
+		else
+			dev_dbg(&pdev->dev, "gpio:%d has irq:%d\n", button->gpio, button->irq);
+
+		if (bdata->b->type == EV_SW)
+			button_hotplug_event(bdata, EV_SW, gpio_button_get_value(bdata));
+	}
+
+	return 0;
+}
+
+static int gpio_keys_polled_probe(struct platform_device *pdev)
+{
+	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_button_dev *bdev;
+	int ret;
+	int i;
+
+	ret = gpio_keys_button_probe(pdev, &bdev, 1);
+
+	if (ret)
+		return ret;
+
+	INIT_DELAYED_WORK(&bdev->work, gpio_keys_polled_poll);
+
+	pdata = bdev->pdata;
+
+	if (pdata->enable)
+		pdata->enable(bdev->dev);
+
+	for (i = 0; i < pdata->nbuttons; i++)
+		gpio_keys_polled_check_state(&bdev->data[i]);
+
+	gpio_keys_polled_queue_work(bdev);
+
+	return ret;
+}
+
+static int gpio_keys_remove(struct platform_device *pdev)
+{
+	struct gpio_keys_button_dev *bdev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (bdev->polled)
+		gpio_keys_polled_close(bdev);
+
+	return 0;
+}
+
+static struct platform_driver gpio_keys_driver = {
+	.probe	= gpio_keys_probe,
+	.remove	= gpio_keys_remove,
+	.driver	= {
+		.name	= "gpio-keys",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_keys_of_match),
+	},
+};
+
+static struct platform_driver gpio_keys_polled_driver = {
+	.probe	= gpio_keys_polled_probe,
+	.remove	= gpio_keys_remove,
+	.driver	= {
+		.name	= "gpio-keys-polled",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+	},
+};
+
+static int __init gpio_button_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&gpio_keys_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&gpio_keys_polled_driver);
+	if (ret)
+		platform_driver_unregister(&gpio_keys_driver);
+
+	return ret;
+}
+
+static void __exit gpio_button_exit(void)
+{
+	platform_driver_unregister(&gpio_keys_driver);
+	platform_driver_unregister(&gpio_keys_polled_driver);
+}
+
+module_init(gpio_button_init);
+module_exit(gpio_button_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_DESCRIPTION("Polled GPIO Buttons hotplug driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/package/kernel/i2c-gpio-custom/Makefile b/package/kernel/i2c-gpio-custom/Makefile
new file mode 100644
index 0000000000..fb3f3bf17e
--- /dev/null
+++ b/package/kernel/i2c-gpio-custom/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=i2c-gpio-custom
+PKG_RELEASE:=2
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/i2c-gpio-custom
+  SUBMENU:=I2C support
+  TITLE:=Custom GPIO-based I2C device
+  DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core +kmod-i2c-gpio
+  FILES:=$(PKG_BUILD_DIR)/i2c-gpio-custom.ko
+  KCONFIG:=
+endef
+
+define KernelPackage/i2c-gpio-custom/description
+ Kernel module for register a custom i2c-gpio platform device.
+endef
+
+EXTRA_KCONFIG:= \
+	CONFIG_I2C_GPIO_CUSTOM=m
+
+EXTRA_CFLAGS:= \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)" \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+	$(EXTRA_KCONFIG)
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,i2c-gpio-custom))
diff --git a/package/kernel/i2c-gpio-custom/src/Kconfig b/package/kernel/i2c-gpio-custom/src/Kconfig
new file mode 100644
index 0000000000..e2e3a68d92
--- /dev/null
+++ b/package/kernel/i2c-gpio-custom/src/Kconfig
@@ -0,0 +1,10 @@
+config I2C_GPIO_CUSTOM
+	tristate "Custom GPIO-based I2C driver"
+	depends on GENERIC_GPIO
+	select I2C_GPIO
+	help
+	  This is an I2C driver to register 1 to 4 custom I2C buses using
+	  GPIO lines.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-gpio-custom.
diff --git a/package/kernel/i2c-gpio-custom/src/Makefile b/package/kernel/i2c-gpio-custom/src/Makefile
new file mode 100644
index 0000000000..dcb2e2abe2
--- /dev/null
+++ b/package/kernel/i2c-gpio-custom/src/Makefile
@@ -0,0 +1 @@
+obj-${CONFIG_I2C_GPIO_CUSTOM}	+= i2c-gpio-custom.o
\ No newline at end of file
diff --git a/package/kernel/i2c-gpio-custom/src/i2c-gpio-custom.c b/package/kernel/i2c-gpio-custom/src/i2c-gpio-custom.c
new file mode 100644
index 0000000000..921d290d52
--- /dev/null
+++ b/package/kernel/i2c-gpio-custom/src/i2c-gpio-custom.c
@@ -0,0 +1,202 @@
+/*
+ *  Custom GPIO-based I2C driver
+ *
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ *  The behaviour of this driver can be altered by setting some parameters
+ *  from the insmod command line.
+ *
+ *  The following parameters are adjustable:
+ *
+ *	bus0	These four arguments can be arrays of
+ *	bus1	1-8 unsigned integers as follows:
+ *	bus2
+ *	bus3	<id>,<sda>,<scl>,<udelay>,<timeout>,<sda_od>,<scl_od>,<scl_oo>
+ *
+ *  where:
+ *
+ *  <id>	ID to used as device_id for the corresponding bus (required)
+ *  <sda>	GPIO pin ID to used for SDA (required)
+ *  <scl>	GPIO pin ID to used for SCL (required)
+ *  <udelay>	signal toggle delay.
+ *  <timeout>	clock stretching timeout.
+ *  <sda_od>	SDA is configured as open drain.
+ *  <scl_od>	SCL is configured as open drain.
+ *  <scl_oo>	SCL output drivers cannot be turned off.
+ *
+ *  See include/i2c-gpio.h for more information about the parameters.
+ *
+ *  If this driver is built into the kernel, you can use the following kernel
+ *  command line parameters, with the same values as the corresponding module
+ *  parameters listed above:
+ *
+ *	i2c-gpio-custom.bus0
+ *	i2c-gpio-custom.bus1
+ *	i2c-gpio-custom.bus2
+ *	i2c-gpio-custom.bus3
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c-gpio.h>
+
+#define DRV_NAME	"i2c-gpio-custom"
+#define DRV_DESC	"Custom GPIO-based I2C driver"
+#define DRV_VERSION	"0.1.1"
+
+#define PFX		DRV_NAME ": "
+
+#define BUS_PARAM_ID		0
+#define BUS_PARAM_SDA		1
+#define BUS_PARAM_SCL		2
+#define BUS_PARAM_UDELAY	3
+#define BUS_PARAM_TIMEOUT	4
+#define BUS_PARAM_SDA_OD	5
+#define BUS_PARAM_SCL_OD	6
+#define BUS_PARAM_SCL_OO	7
+
+#define BUS_PARAM_REQUIRED	3
+#define BUS_PARAM_COUNT		8
+#define BUS_COUNT_MAX		4
+
+static unsigned int bus0[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus1[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus2[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus3[BUS_PARAM_COUNT] __initdata;
+
+static unsigned int bus_nump[BUS_COUNT_MAX] __initdata;
+
+#define BUS_PARM_DESC \
+	" config -> id,sda,scl[,udelay,timeout,sda_od,scl_od,scl_oo]"
+
+module_param_array(bus0, uint, &bus_nump[0], 0);
+MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC);
+module_param_array(bus1, uint, &bus_nump[1], 0);
+MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC);
+module_param_array(bus2, uint, &bus_nump[2], 0);
+MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC);
+module_param_array(bus3, uint, &bus_nump[3], 0);
+MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC);
+
+static struct platform_device *devices[BUS_COUNT_MAX];
+static unsigned int nr_devices;
+
+static void i2c_gpio_custom_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < nr_devices; i++)
+		if (devices[i])
+			platform_device_put(devices[i]);
+}
+
+static int __init i2c_gpio_custom_add_one(unsigned int id, unsigned int *params)
+{
+	struct platform_device *pdev;
+	struct i2c_gpio_platform_data pdata;
+	int err;
+
+	if (!bus_nump[id])
+		return 0;
+
+	if (bus_nump[id] < BUS_PARAM_REQUIRED) {
+		printk(KERN_ERR PFX "not enough parameters for bus%d\n", id);
+		err = -EINVAL;
+		goto err;
+	}
+
+	pdev = platform_device_alloc("i2c-gpio", params[BUS_PARAM_ID]);
+	if (!pdev) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	pdata.sda_pin = params[BUS_PARAM_SDA];
+	pdata.scl_pin = params[BUS_PARAM_SCL];
+	pdata.udelay = params[BUS_PARAM_UDELAY];
+	pdata.timeout = params[BUS_PARAM_TIMEOUT];
+	pdata.sda_is_open_drain = params[BUS_PARAM_SDA_OD] != 0;
+	pdata.scl_is_open_drain = params[BUS_PARAM_SCL_OD] != 0;
+	pdata.scl_is_output_only = params[BUS_PARAM_SCL_OO] != 0;
+
+	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+	if (err)
+		goto err_put;
+
+	err = platform_device_add(pdev);
+	if (err)
+		goto err_put;
+
+	devices[nr_devices++] = pdev;
+	return 0;
+
+err_put:
+	platform_device_put(pdev);
+err:
+	return err;
+}
+
+static int __init i2c_gpio_custom_probe(void)
+{
+	int err;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+	err = i2c_gpio_custom_add_one(0, bus0);
+	if (err)
+		goto err;
+
+	err = i2c_gpio_custom_add_one(1, bus1);
+	if (err)
+		goto err;
+
+	err = i2c_gpio_custom_add_one(2, bus2);
+	if (err)
+		goto err;
+
+	err = i2c_gpio_custom_add_one(3, bus3);
+	if (err)
+		goto err;
+
+	if (!nr_devices) {
+		printk(KERN_ERR PFX "no bus parameter(s) specified\n");
+		err = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	i2c_gpio_custom_cleanup();
+	return err;
+}
+
+#ifdef MODULE
+static int __init i2c_gpio_custom_init(void)
+{
+	return i2c_gpio_custom_probe();
+}
+module_init(i2c_gpio_custom_init);
+
+static void __exit i2c_gpio_custom_exit(void)
+{
+	i2c_gpio_custom_cleanup();
+}
+module_exit(i2c_gpio_custom_exit);
+#else
+subsys_initcall(i2c_gpio_custom_probe);
+#endif /* MODULE*/
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org >");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
diff --git a/package/kernel/kmod-sched-cake/Makefile b/package/kernel/kmod-sched-cake/Makefile
new file mode 100644
index 0000000000..b760c2a358
--- /dev/null
+++ b/package/kernel/kmod-sched-cake/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2016 LEDE
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=sched-cake
+PKG_SOURCE_VERSION:=4f62bd17fa34036cb3c8fd4800a709b2734c3de3
+PKG_VERSION:=2016-10-02-$(PKG_SOURCE_VERSION)
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/dtaht/sch_cake.git
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_MIRROR_MD5SUM:=d6fd82607862c16ba5f1007ecfb251eba9e2cc82c55bb3f4aee2fbebf9fa6d2a
+PKG_MAINTAINER:=Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/sched-cake
+  SUBMENU:=Network Support
+  TITLE:=Cake fq_codel/blue derived shaper
+  URL:=https://github.com/dtaht/sch_cake
+  FILES:=$(PKG_BUILD_DIR)/sch_cake.ko
+  AUTOLOAD:=$(call AutoLoad,75,sch_cake)
+  DEPENDS:=+kmod-ipt-conntrack
+endef
+
+include $(INCLUDE_DIR)/kernel-defaults.mk
+
+define KernelPackage/sched-cake/description
+  Common Applications Kept Enhanced fq_codel/blue derived shaper
+endef
+
+define Build/Compile
+	$(MAKE) $(KERNEL_MAKEOPTS) SUBDIRS="$(PKG_BUILD_DIR)" modules
+endef
+
+$(eval $(call KernelPackage,sched-cake))
diff --git a/package/kernel/linux/Makefile b/package/kernel/linux/Makefile
new file mode 100644
index 0000000000..21381c7296
--- /dev/null
+++ b/package/kernel/linux/Makefile
@@ -0,0 +1,67 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=kernel
+PKG_FLAGS:=hold
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/packages
+SCAN_DEPS=modules/*.mk $(TOPDIR)/target/linux/*/modules.mk $(TOPDIR)/include/netfilter.mk
+
+PKG_LICENSE:=GPLv2
+PKG_LICENSE_FILES:=
+
+export SHELL:=/bin/sh
+.ONESHELL:
+.SHELLFLAGS = -ec
+
+include $(INCLUDE_DIR)/package.mk
+
+STAMP_BUILT:=$(STAMP_BUILT)_$(firstword $(shell $(SCRIPT_DIR)/kconfig.pl $(LINUX_DIR)/.config | md5sum))
+
+ifeq ($(DUMP),)
+  -include $(LINUX_DIR)/.config
+endif
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define KernelPackage/depends
+endef
+
+CONFIG_PACKAGE_kernel=y
+define Package/kernel
+  SECTION:=sys
+  CATEGORY:=Kernel
+  DEFAULT:=y
+  TITLE:=Virtual kernel package
+  VERSION:=$(LINUX_VERSION)-$(LINUX_RELEASE)-$(LINUX_VERMAGIC)
+  URL:=http://www.kernel.org/
+  PKG_FLAGS:=nonshared
+endef
+
+define Package/kernel/install
+  # nothing to do
+endef
+
+define Package/kernel/extra_provides
+	sed -e 's,.*/,,' $(LINUX_DIR)/modules.builtin;
+endef
+
+$(eval $(if $(DUMP),,$(call BuildPackage,kernel)))
+
+include $(sort $(wildcard ./modules/*.mk))
+-include $(TOPDIR)/target/linux/*/modules.mk
diff --git a/package/kernel/linux/modules/001-depends.mk b/package/kernel/linux/modules/001-depends.mk
new file mode 100644
index 0000000000..806c3dcfd5
--- /dev/null
+++ b/package/kernel/linux/modules/001-depends.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2010-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define AddDepends/nls
+  DEPENDS+= +kmod-nls-base $(foreach cp,$(1),+kmod-nls-$(cp))
+endef
+
+define AddDepends/rfkill
+  DEPENDS+= +USE_RFKILL:kmod-rfkill $(1)
+endef
diff --git a/package/kernel/linux/modules/block.mk b/package/kernel/linux/modules/block.mk
new file mode 100644
index 0000000000..4d34924649
--- /dev/null
+++ b/package/kernel/linux/modules/block.mk
@@ -0,0 +1,529 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+BLOCK_MENU:=Block Devices
+
+define KernelPackage/aoe
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=ATA over Ethernet support
+  KCONFIG:=CONFIG_ATA_OVER_ETH
+  FILES:=$(LINUX_DIR)/drivers/block/aoe/aoe.ko
+  AUTOLOAD:=$(call AutoLoad,30,aoe)
+endef
+
+define KernelPackage/aoe/description
+ Kernel support for ATA over Ethernet
+endef
+
+$(eval $(call KernelPackage,aoe))
+
+
+define KernelPackage/ata-core
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Serial and Parallel ATA support
+  DEPENDS:=@PCI_SUPPORT||TARGET_sunxi +kmod-scsi-core
+  KCONFIG:=CONFIG_ATA
+  FILES:=$(LINUX_DIR)/drivers/ata/libata.ko
+ifneq ($(wildcard $(LINUX_DIR)/drivers/ata/libahci.ko),)
+  FILES+=$(LINUX_DIR)/drivers/ata/libahci.ko
+endif
+endef
+
+$(eval $(call KernelPackage,ata-core))
+
+
+define AddDepends/ata
+  SUBMENU:=$(BLOCK_MENU)
+  DEPENDS+=kmod-ata-core $(1)
+endef
+
+
+define KernelPackage/ata-ahci
+  TITLE:=AHCI Serial ATA support
+  KCONFIG:=CONFIG_SATA_AHCI
+  FILES:= \
+    $(LINUX_DIR)/drivers/ata/ahci.ko
+  AUTOLOAD:=$(call AutoLoad,41,libahci ahci,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-ahci/description
+ Support for AHCI Serial ATA controllers
+endef
+
+$(eval $(call KernelPackage,ata-ahci))
+
+
+define KernelPackage/ata-ahci-platform
+  TITLE:=AHCI Serial ATA Platform support
+  KCONFIG:=CONFIG_SATA_AHCI_PLATFORM
+  FILES:= \
+    $(LINUX_DIR)/drivers/ata/ahci_platform.ko \
+    $(LINUX_DIR)/drivers/ata/libahci_platform.ko
+  AUTOLOAD:=$(call AutoLoad,40,libahci libahci_platform ahci_platform,1)
+  $(call AddDepends/ata,@TARGET_ipq806x||TARGET_sunxi)
+endef
+
+define KernelPackage/ata-ahci-platform/description
+ Platform support for AHCI Serial ATA controllers
+endef
+
+$(eval $(call KernelPackage,ata-ahci-platform))
+
+
+define KernelPackage/ata-artop
+  TITLE:=ARTOP 6210/6260 PATA support
+  KCONFIG:=CONFIG_PATA_ARTOP
+  FILES:=$(LINUX_DIR)/drivers/ata/pata_artop.ko
+  AUTOLOAD:=$(call AutoLoad,41,pata_artop,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-artop/description
+ PATA support for ARTOP 6210/6260 host controllers
+endef
+
+$(eval $(call KernelPackage,ata-artop))
+
+
+define KernelPackage/ata-imx
+  TITLE:=Freescale i.MX AHCI SATA support
+  DEPENDS:=@TARGET_imx6
+  KCONFIG:=\
+	CONFIG_AHCI_IMX \
+	CONFIG_SATA_AHCI_PLATFORM \
+	CONFIG_PATA_IMX=n
+  FILES:=$(LINUX_DIR)/drivers/ata/ahci_imx.ko
+  AUTOLOAD:=$(call AutoLoad,41,ahci_imx,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-imx/description
+ SATA support for the Freescale i.MX6 SoC's onboard AHCI SATA
+endef
+
+$(eval $(call KernelPackage,ata-imx))
+
+
+define KernelPackage/ata-marvell-sata
+  TITLE:=Marvell Serial ATA support
+  KCONFIG:=CONFIG_SATA_MV
+  FILES:=$(LINUX_DIR)/drivers/ata/sata_mv.ko
+  AUTOLOAD:=$(call AutoLoad,41,sata_mv,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-marvell-sata/description
+ SATA support for marvell chipsets
+endef
+
+$(eval $(call KernelPackage,ata-marvell-sata))
+
+
+define KernelPackage/ata-nvidia-sata
+  TITLE:=Nvidia Serial ATA support
+  KCONFIG:=CONFIG_SATA_NV
+  FILES:=$(LINUX_DIR)/drivers/ata/sata_nv.ko
+  AUTOLOAD:=$(call AutoLoad,41,sata_nv,1)
+  $(call AddDepends/ata)
+endef
+
+$(eval $(call KernelPackage,ata-nvidia-sata))
+
+
+define KernelPackage/ata-pdc202xx-old
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Older Promise PATA controller support
+  DEPENDS:=kmod-ata-core
+  KCONFIG:= \
+       CONFIG_ATA_SFF=y \
+       CONFIG_PATA_PDC_OLD
+  FILES:=$(LINUX_DIR)/drivers/ata/pata_pdc202xx_old.ko
+  AUTOLOAD:=$(call AutoLoad,41,pata_pdc202xx_old,1)
+endef
+
+define KernelPackage/ata-pdc202xx-old/description
+ This option enables support for the Promise 20246, 20262, 20263,
+ 20265 and 20267 adapters
+endef
+
+$(eval $(call KernelPackage,ata-pdc202xx-old))
+
+
+define KernelPackage/ata-piix
+  TITLE:=Intel PIIX PATA/SATA support
+  KCONFIG:=CONFIG_ATA_PIIX
+  FILES:=$(LINUX_DIR)/drivers/ata/ata_piix.ko
+  AUTOLOAD:=$(call AutoLoad,41,ata_piix,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-piix/description
+ SATA support for Intel ICH5/6/7/8 series host controllers and
+ PATA support for Intel ESB/ICH/PIIX3/PIIX4 series host controllers
+endef
+
+$(eval $(call KernelPackage,ata-piix))
+
+
+define KernelPackage/ata-sil
+  TITLE:=Silicon Image SATA support
+  KCONFIG:=CONFIG_SATA_SIL
+  FILES:=$(LINUX_DIR)/drivers/ata/sata_sil.ko
+  AUTOLOAD:=$(call AutoLoad,41,sata_sil,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-sil/description
+ Support for Silicon Image Serial ATA controllers
+endef
+
+$(eval $(call KernelPackage,ata-sil))
+
+
+define KernelPackage/ata-sil24
+  TITLE:=Silicon Image 3124/3132 SATA support
+  KCONFIG:=CONFIG_SATA_SIL24
+  FILES:=$(LINUX_DIR)/drivers/ata/sata_sil24.ko
+  AUTOLOAD:=$(call AutoLoad,41,sata_sil24,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-sil24/description
+ Support for Silicon Image 3124/3132 Serial ATA controllers
+endef
+
+$(eval $(call KernelPackage,ata-sil24))
+
+
+define KernelPackage/ata-via-sata
+  TITLE:=VIA SATA support
+  KCONFIG:=CONFIG_SATA_VIA
+  FILES:=$(LINUX_DIR)/drivers/ata/sata_via.ko
+  AUTOLOAD:=$(call AutoLoad,41,sata_via,1)
+  $(call AddDepends/ata)
+endef
+
+define KernelPackage/ata-via-sata/description
+ This option enables support for VIA Serial ATA
+endef
+
+$(eval $(call KernelPackage,ata-via-sata))
+
+
+define KernelPackage/block2mtd
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Block device MTD emulation
+  KCONFIG:=CONFIG_MTD_BLOCK2MTD
+  FILES:=$(LINUX_DIR)/drivers/mtd/devices/block2mtd.ko
+endef
+
+$(eval $(call KernelPackage,block2mtd))
+
+
+define KernelPackage/dm
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Device Mapper
+  DEPENDS:=+kmod-crypto-manager
+  # All the "=n" are unnecessary, they're only there
+  # to stop the config from asking the question.
+  # MIRROR is M because I've needed it for pvmove.
+  KCONFIG:= \
+	CONFIG_BLK_DEV_MD=n \
+	CONFIG_DM_DEBUG=n \
+	CONFIG_DM_UEVENT=n \
+	CONFIG_DM_DELAY=n \
+	CONFIG_DM_LOG_WRITES=n \
+	CONFIG_DM_MQ_DEFAULT=n \
+	CONFIG_DM_MULTIPATH=n \
+	CONFIG_DM_ZERO=n \
+	CONFIG_DM_SNAPSHOT=n \
+	CONFIG_DM_LOG_USERSPACE=n \
+	CONFIG_MD=y \
+	CONFIG_BLK_DEV_DM \
+	CONFIG_DM_CRYPT \
+	CONFIG_DM_MIRROR
+  FILES:=$(LINUX_DIR)/drivers/md/dm-*.ko
+  AUTOLOAD:=$(call AutoLoad,30,dm-mod dm-log dm-region-hash dm-mirror dm-crypt)
+endef
+
+define KernelPackage/dm/description
+ Kernel module necessary for LVM2 support
+endef
+
+$(eval $(call KernelPackage,dm))
+
+
+define KernelPackage/md-mod
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=MD RAID
+  KCONFIG:= \
+       CONFIG_MD=y \
+       CONFIG_BLK_DEV_MD=m \
+       CONFIG_MD_AUTODETECT=y \
+       CONFIG_MD_FAULTY=n
+  FILES:=$(LINUX_DIR)/drivers/md/md-mod.ko
+  AUTOLOAD:=$(call AutoLoad,27,md-mod)
+endef
+
+define KernelPackage/md-mod/description
+ Kernel RAID md module (md-mod.ko).
+ You will need to select at least one RAID level module below.
+endef
+
+$(eval $(call KernelPackage,md-mod))
+
+
+define KernelPackage/md/Depends
+  SUBMENU:=$(BLOCK_MENU)
+  DEPENDS:=kmod-md-mod $(1)
+endef
+
+
+define KernelPackage/md-linear
+$(call KernelPackage/md/Depends,)
+  TITLE:=RAID Linear Module
+  KCONFIG:=CONFIG_MD_LINEAR
+  FILES:=$(LINUX_DIR)/drivers/md/linear.ko
+  AUTOLOAD:=$(call AutoLoad,28,linear)
+endef
+
+define KernelPackage/md-linear/description
+ RAID "Linear" or "Append" driver module (linear.ko)
+endef
+
+$(eval $(call KernelPackage,md-linear))
+
+
+define KernelPackage/md-raid0
+$(call KernelPackage/md/Depends,)
+  TITLE:=RAID0 Module
+  KCONFIG:=CONFIG_MD_RAID0
+  FILES:=$(LINUX_DIR)/drivers/md/raid0.ko
+  AUTOLOAD:=$(call AutoLoad,28,raid0)
+endef
+
+define KernelPackage/md-raid0/description
+ RAID Level 0 (Striping) driver module (raid0.ko)
+endef
+
+$(eval $(call KernelPackage,md-raid0))
+
+
+define KernelPackage/md-raid1
+$(call KernelPackage/md/Depends,)
+  TITLE:=RAID1 Module
+  KCONFIG:=CONFIG_MD_RAID1
+  FILES:=$(LINUX_DIR)/drivers/md/raid1.ko
+  AUTOLOAD:=$(call AutoLoad,28,raid1)
+endef
+
+define KernelPackage/md-raid1/description
+ RAID Level 1 (Mirroring) driver (raid1.ko)
+endef
+
+$(eval $(call KernelPackage,md-raid1))
+
+
+define KernelPackage/md-raid10
+$(call KernelPackage/md/Depends,)
+  TITLE:=RAID10 Module
+  KCONFIG:=CONFIG_MD_RAID10
+  FILES:=$(LINUX_DIR)/drivers/md/raid10.ko
+  AUTOLOAD:=$(call AutoLoad,28,raid10)
+endef
+
+define KernelPackage/md-raid10/description
+ RAID Level 10 (Mirroring+Striping) driver module (raid10.ko)
+endef
+
+$(eval $(call KernelPackage,md-raid10))
+
+
+define KernelPackage/md-raid456
+$(call KernelPackage/md/Depends,+kmod-lib-raid6 +kmod-lib-xor +LINUX_4_4:kmod-lib-crc32c)
+  TITLE:=RAID Level 456 Driver
+  KCONFIG:= \
+       CONFIG_ASYNC_CORE \
+       CONFIG_ASYNC_MEMCPY \
+       CONFIG_ASYNC_XOR \
+       CONFIG_ASYNC_PQ \
+       CONFIG_ASYNC_RAID6_RECOV \
+       CONFIG_ASYNC_RAID6_TEST=n \
+       CONFIG_MD_RAID456 \
+       CONFIG_MULTICORE_RAID456=n
+  FILES:= \
+	$(LINUX_DIR)/crypto/async_tx/async_tx.ko \
+	$(LINUX_DIR)/crypto/async_tx/async_memcpy.ko \
+	$(LINUX_DIR)/crypto/async_tx/async_xor.ko \
+	$(LINUX_DIR)/crypto/async_tx/async_pq.ko \
+	$(LINUX_DIR)/crypto/async_tx/async_raid6_recov.ko \
+	$(LINUX_DIR)/drivers/md/raid456.ko
+  AUTOLOAD:=$(call AutoLoad,28, async_tx async_memcpy async_xor async_pq async_raid6_recov raid456)
+endef
+
+define KernelPackage/md-raid456/description
+ RAID Level 4,5,6 kernel module (raid456.ko)
+
+ Includes the following modules required by
+ raid456.ko:
+    xor.ko
+    async_tx.ko
+    async_xor.ko
+    async_memcpy.ko
+    async_pq.ko
+    async_raid5_recov.ko
+    raid6_pq.ko
+endef
+
+$(eval $(call KernelPackage,md-raid456))
+
+
+define KernelPackage/md-multipath
+$(call KernelPackage/md/Depends,)
+  TITLE:=MD Multipath Module
+  KCONFIG:=CONFIG_MD_MULTIPATH
+  FILES:=$(LINUX_DIR)/drivers/md/multipath.ko
+  AUTOLOAD:=$(call AutoLoad,29,multipath)
+endef
+
+define KernelPackage/md-multipath/description
+ Multipath driver module (multipath.ko)
+endef
+
+$(eval $(call KernelPackage,md-multipath))
+
+
+define KernelPackage/libsas
+  SUBMENU:=$(BLOCK_MENU)
+  DEPENDS:=@TARGET_x86
+  TITLE:=SAS Domain Transport Attributes
+  KCONFIG:=CONFIG_SCSI_SAS_LIBSAS \
+	CONFIG_SCSI_SAS_ATTRS \
+	CONFIG_SCSI_SAS_ATA=y \
+	CONFIG_SCSI_SAS_HOST_SMP=y \
+	CONFIG_SCSI_SAS_LIBSAS_DEBUG=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/scsi/scsi_transport_sas.ko \
+	$(LINUX_DIR)/drivers/scsi/libsas/libsas.ko
+  AUTOLOAD:=$(call AutoLoad,29,scsi_transport_sas libsas,1)
+endef
+
+define KernelPackage/libsas/description
+ SAS Domain Transport Attributes support
+endef
+
+$(eval $(call KernelPackage,libsas,1))
+
+
+define KernelPackage/loop
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Loopback device support
+  KCONFIG:= \
+	CONFIG_BLK_DEV_LOOP \
+	CONFIG_BLK_DEV_CRYPTOLOOP=n
+  FILES:=$(LINUX_DIR)/drivers/block/loop.ko
+  AUTOLOAD:=$(call AutoLoad,30,loop)
+endef
+
+define KernelPackage/loop/description
+ Kernel module for loopback device support
+endef
+
+$(eval $(call KernelPackage,loop))
+
+
+define KernelPackage/mvsas
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Marvell 88SE6440 SAS/SATA driver
+  DEPENDS:=@TARGET_x86 +kmod-libsas
+  KCONFIG:= \
+	CONFIG_SCSI_MVSAS \
+	CONFIG_SCSI_MVSAS_TASKLET=n
+  FILES:=$(LINUX_DIR)/drivers/scsi/mvsas/mvsas.ko
+  AUTOLOAD:=$(call AutoLoad,40,mvsas,1)
+endef
+
+define KernelPackage/mvsas/description
+ Kernel support for the Marvell SAS SCSI adapters
+endef
+
+$(eval $(call KernelPackage,mvsas))
+
+
+define KernelPackage/nbd
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Network block device support
+  KCONFIG:=CONFIG_BLK_DEV_NBD
+  FILES:=$(LINUX_DIR)/drivers/block/nbd.ko
+  AUTOLOAD:=$(call AutoLoad,30,nbd)
+endef
+
+define KernelPackage/nbd/description
+ Kernel module for network block device support
+endef
+
+$(eval $(call KernelPackage,nbd))
+
+
+define KernelPackage/scsi-core
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=SCSI device support
+  KCONFIG:= \
+	CONFIG_SCSI \
+	CONFIG_BLK_DEV_SD
+  FILES:= \
+	$(LINUX_DIR)/drivers/scsi/scsi_mod.ko \
+	$(LINUX_DIR)/drivers/scsi/sd_mod.ko
+  AUTOLOAD:=$(call AutoLoad,40,scsi_mod sd_mod,1)
+endef
+
+$(eval $(call KernelPackage,scsi-core))
+
+
+define KernelPackage/scsi-generic
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Kernel support for SCSI generic
+  DEPENDS:=+kmod-scsi-core
+  KCONFIG:= \
+	CONFIG_CHR_DEV_SG
+  FILES:= \
+	$(LINUX_DIR)/drivers/scsi/sg.ko
+  AUTOLOAD:=$(call AutoLoad,65,sg)
+endef
+
+$(eval $(call KernelPackage,scsi-generic))
+
+
+define KernelPackage/scsi-cdrom
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Kernel support for CD / DVD drives
+  DEPENDS:=+kmod-scsi-core
+  KCONFIG:= \
+    CONFIG_BLK_DEV_SR \
+    CONFIG_BLK_DEV_SR_VENDOR=n
+  FILES:= \
+    $(LINUX_DIR)/drivers/cdrom/cdrom.ko \
+    $(LINUX_DIR)/drivers/scsi/sr_mod.ko
+  AUTOLOAD:=$(call AutoLoad,45,sr_mod)
+endef
+
+$(eval $(call KernelPackage,scsi-cdrom))
+
+
+define KernelPackage/scsi-tape
+  SUBMENU:=$(BLOCK_MENU)
+  TITLE:=Kernel support for scsi tape drives
+  DEPENDS:=+kmod-scsi-core
+  KCONFIG:= \
+    CONFIG_CHR_DEV_ST
+  FILES:= \
+    $(LINUX_DIR)/drivers/scsi/st.ko
+  AUTOLOAD:=$(call AutoLoad,45,st)
+endef
+
+$(eval $(call KernelPackage,scsi-tape))
diff --git a/package/kernel/linux/modules/can.mk b/package/kernel/linux/modules/can.mk
new file mode 100644
index 0000000000..eeef88a835
--- /dev/null
+++ b/package/kernel/linux/modules/can.mk
@@ -0,0 +1,277 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+CAN_MENU:=CAN Support
+
+define KernelPackage/can
+  SUBMENU:=$(CAN_MENU)
+  TITLE:=CAN bus support
+  KCONFIG:=\
+	CONFIG_CAN=m \
+	CONFIG_CAN_DEV \
+	CONFIG_CAN_CALC_BITTIMING=y \
+	CONFIG_CAN_LEDS=y \
+	CONFIG_CAN_AT91=n \
+	CONFIG_CAN_TI_HECC=n \
+	CONFIG_CAN_MCP251X=n \
+	CONFIG_CAN_BFIN=n \
+	CONFIG_CAN_JANZ_ICAN3=n \
+	CONFIG_PCH_CAN=n \
+	CONFIG_CAN_GRCAN=n \
+	CONFIG_CAN_CC770=n \
+	CONFIG_CAN_MSCAN=n \
+	CONFIG_CAN_SJA1000=n \
+	CONFIG_CAN_SOFTING=n \
+	CONFIG_CAN_XILINXCAN=n \
+	CONFIG_NET_EMATCH_CANID=n \
+	CONFIG_CAN_DEBUG_DEVICES=n
+  FILES:=$(LINUX_DIR)/drivers/net/can/can-dev.ko \
+	 $(LINUX_DIR)/net/can/can.ko
+  AUTOLOAD:=$(call AutoProbe,can can-dev)
+endef
+
+define KernelPackage/can/description
+ Kernel module for CAN bus support.
+endef
+
+$(eval $(call KernelPackage,can))
+
+
+define AddDepends/can
+  SUBMENU:=$(CAN_MENU)
+  DEPENDS+=kmod-can $(1)
+endef
+
+
+define KernelPackage/can-raw
+  TITLE:=Raw CAN Protcol
+  KCONFIG:=CONFIG_CAN_RAW
+  FILES:=$(LINUX_DIR)/net/can/can-raw.ko
+  AUTOLOAD:=$(call AutoProbe,can-raw)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-raw/description
+ The raw CAN protocol option offers access to the CAN bus via
+ the BSD  socket API.
+endef
+
+$(eval $(call KernelPackage,can-raw))
+
+
+define KernelPackage/can-bcm
+  TITLE:=Broadcast Manager CAN Protcol
+  KCONFIG:=CONFIG_CAN_BCM
+  FILES:=$(LINUX_DIR)/net/can/can-bcm.ko
+  AUTOLOAD:=$(call AutoProbe,can-bcm)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-bcm/description
+ The Broadcast Manager offers content filtering, timeout monitoring,
+ sending of RTR frames, and cyclic CAN messages without permanent user
+ interaction.
+endef
+
+$(eval $(call KernelPackage,can-bcm))
+
+
+define KernelPackage/can-gw
+  TITLE:=CAN Gateway/Router
+  KCONFIG:=CONFIG_CAN_GW
+  FILES:=$(LINUX_DIR)/net/can/can-gw.ko
+  AUTOLOAD:=$(call AutoProbe,can-gw)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-gw/description
+ The CAN Gateway/Router is used to route (and modify) CAN frames.
+endef
+
+$(eval $(call KernelPackage,can-gw))
+
+
+define KernelPackage/can-vcan
+  TITLE:=Virtual Local CAN Interface (vcan)
+  KCONFIG:=CONFIG_CAN_VCAN
+  FILES:=$(LINUX_DIR)/drivers/net/can/vcan.ko
+  AUTOLOAD:=$(call AutoProbe,vcan)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-vcan/description
+ Similar to the network loopback devices, vcan offers a
+ virtual local CAN interface.
+endef
+
+$(eval $(call KernelPackage,can-vcan))
+
+
+define KernelPackage/can-slcan
+  TITLE:=Serial / USB serial CAN Adaptors (slcan)
+  KCONFIG:=CONFIG_CAN_SLCAN
+  FILES:=$(LINUX_DIR)/drivers/net/can/slcan.ko
+  AUTOLOAD:=$(call AutoProbe,slcan)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-slcan/description
+ CAN driver for several 'low cost' CAN interfaces that are attached
+ via serial lines or via USB-to-serial adapters using the LAWICEL
+ ASCII protocol.
+endef
+
+$(eval $(call KernelPackage,can-slcan))
+
+
+define KernelPackage/can-flexcan
+  TITLE:=Support for Freescale FLEXCAN based chips
+  KCONFIG:=CONFIG_CAN_FLEXCAN
+  FILES:=$(LINUX_DIR)/drivers/net/can/flexcan.ko
+  AUTOLOAD:=$(call AutoProbe,flexcan)
+  $(call AddDepends/can,@TARGET_imx6)
+endef
+
+define KernelPackage/can-flexcan/description
+ Freescale FLEXCAN CAN bus controller implementation.
+endef
+
+$(eval $(call KernelPackage,can-flexcan))
+
+
+define KernelPackage/can-usb-ems
+  TITLE:=EMS CPC-USB/ARM7 CAN/USB interface
+  KCONFIG:=CONFIG_CAN_EMS_USB
+  FILES:=$(LINUX_DIR)/drivers/net/can/usb/ems_usb.ko
+  AUTOLOAD:=$(call AutoProbe,ems_usb)
+  $(call AddDepends/can,+kmod-usb-core)
+endef
+
+define KernelPackage/can-usb-ems/description
+ This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
+ from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+endef
+
+$(eval $(call KernelPackage,can-usb-ems))
+
+
+define KernelPackage/can-usb-esd
+  TITLE:=ESD USB/2 CAN/USB interface
+  KCONFIG:=CONFIG_CAN_ESD_USB2
+  FILES:=$(LINUX_DIR)/drivers/net/can/usb/esd_usb2.ko
+  AUTOLOAD:=$(call AutoProbe,esd_usb2)
+  $(call AddDepends/can,+kmod-usb-core)
+endef
+
+define KernelPackage/can-usb-esd/description
+ This driver supports the CAN-USB/2 interface
+ from esd electronic system design gmbh (http://www.esd.eu).
+endef
+
+$(eval $(call KernelPackage,can-usb-esd))
+
+
+define KernelPackage/can-usb-kvaser
+  TITLE:=Kvaser CAN/USB interface
+  KCONFIG:=CONFIG_CAN_KVASER_USB
+  FILES:=$(LINUX_DIR)/drivers/net/can/usb/kvaser_usb.ko
+  AUTOLOAD:=$(call AutoProbe,kvaser_usb)
+  $(call AddDepends/can,+kmod-usb-core)
+endef
+
+define KernelPackage/can-usb-kvaser/description
+ This driver adds support for Kvaser CAN/USB devices like Kvaser
+ Leaf Light.
+endef
+
+$(eval $(call KernelPackage,can-usb-kvaser))
+
+
+define KernelPackage/can-usb-peak
+  TITLE:=PEAK PCAN-USB/USB Pro interfaces
+  KCONFIG:=CONFIG_CAN_PEAK_USB
+  FILES:=$(LINUX_DIR)/drivers/net/can/usb/peak_usb/peak_usb.ko
+  AUTOLOAD:=$(call AutoProbe,peak_usb)
+  $(call AddDepends/can,+kmod-usb-core)
+endef
+
+define KernelPackage/can-usb-peak/description
+ This driver supports the PCAN-USB and PCAN-USB Pro adapters
+ from PEAK-System Technik (http://www.peak-system.com).
+endef
+
+$(eval $(call KernelPackage,can-usb-peak))
+
+
+define KernelPackage/can-usb-8dev
+  TITLE:=8 devices USB2CAN interface
+  KCONFIG:=CONFIG_CAN_8DEV_USB
+  FILES:=$(LINUX_DIR)/drivers/net/can/usb/usb_8dev.ko
+  AUTOLOAD:=$(call AutoProbe,usb_8dev)
+  $(call AddDepends/can,+kmod-usb-core)
+endef
+
+define KernelPackage/can-usb-8dev/description
+ This driver supports the USB2CAN interface
+ from 8 devices (http://www.8devices.com).
+endef
+
+$(eval $(call KernelPackage,can-usb-8dev))
+
+
+define KernelPackage/can-c-can
+  TITLE:=BOSCH C_CAN/D_CAN drivers
+  KCONFIG:=CONFIG_CAN_C_CAN
+  FILES:=$(LINUX_DIR)/drivers/net/can/c_can/c_can.ko
+  AUTOLOAD:=$(call AutoProbe,c_can)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-c-can/description
+ This driver adds generic support for the C_CAN/D_CAN chips.
+endef
+
+$(eval $(call KernelPackage,can-c-can))
+
+
+define KernelPackage/can-c-can-platform
+  TITLE:=Platform Bus based BOSCH C_CAN/D_CAN driver
+  KCONFIG:=CONFIG_CAN_C_CAN_PLATFORM
+  DEPENDS:=kmod-can-c-can +LINUX_4_1:kmod-regmap
+  FILES:=$(LINUX_DIR)/drivers/net/can/c_can/c_can_platform.ko
+  AUTOLOAD:=$(call AutoProbe,c_can_platform)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-c-can-platform/description
+ This driver adds support for the C_CAN/D_CAN chips connected
+ to the "platform bus" (Linux abstraction for directly to the
+ processor attached devices) which can be found on various
+ boards from ST Microelectronics (http://www.st.com) like the
+ SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
+ boards like am335x, dm814x, dm813x and dm811x.
+endef
+
+$(eval $(call KernelPackage,can-c-can-platform))
+
+
+define KernelPackage/can-c-can-pci
+  TITLE:=PCI Bus based BOSCH C_CAN/D_CAN driver
+  KCONFIG:=CONFIG_CAN_C_CAN_PCI
+  DEPENDS:=kmod-can-c-can @PCI_SUPPORT
+  FILES:=$(LINUX_DIR)/drivers/net/can/c_can/c_can_pci.ko
+  AUTOLOAD:=$(call AutoProbe,c_can_pci)
+  $(call AddDepends/can)
+endef
+
+define KernelPackage/can-c-can-pci/description
+ This driver adds support for the C_CAN/D_CAN chips connected
+ to the PCI bus.
+endef
+
+$(eval $(call KernelPackage,can-c-can-pci))
+
diff --git a/package/kernel/linux/modules/crypto.mk b/package/kernel/linux/modules/crypto.mk
new file mode 100644
index 0000000000..0a88c3be12
--- /dev/null
+++ b/package/kernel/linux/modules/crypto.mk
@@ -0,0 +1,675 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+CRYPTO_MENU:=Cryptographic API modules
+
+CRYPTO_MODULES = \
+	ALGAPI2=crypto_algapi \
+	BLKCIPHER2=crypto_blkcipher
+
+crypto_confvar=CONFIG_CRYPTO_$(word 1,$(subst =,$(space),$(1)))
+crypto_file=$(LINUX_DIR)/crypto/$(word 2,$(subst =,$(space),$(1))).ko
+crypto_name=$(if $(findstring y,$($(call crypto_confvar,$(1)))),,$(word 2,$(subst =,$(space),$(1))))
+
+define AddDepends/crypto
+  SUBMENU:=$(CRYPTO_MENU)
+  DEPENDS+= $(1)
+endef
+
+define KernelPackage/crypto-aead
+  TITLE:=CryptoAPI AEAD support
+  KCONFIG:= \
+	CONFIG_CRYPTO_AEAD \
+	CONFIG_CRYPTO_AEAD2
+  FILES:=$(LINUX_DIR)/crypto/aead.ko
+  AUTOLOAD:=$(call AutoLoad,09,aead,1)
+  $(call AddDepends/crypto, +LINUX_4_4:kmod-crypto-null)
+endef
+
+$(eval $(call KernelPackage,crypto-aead))
+
+
+define KernelPackage/crypto-hash
+  TITLE:=CryptoAPI hash support
+  KCONFIG:=CONFIG_CRYPTO_HASH
+  FILES:=$(LINUX_DIR)/crypto/crypto_hash.ko
+  AUTOLOAD:=$(call AutoLoad,02,crypto_hash,1)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hash))
+
+
+define KernelPackage/crypto-manager
+  TITLE:=CryptoAPI algorithm manager
+  DEPENDS:=+kmod-crypto-aead +kmod-crypto-hash +kmod-crypto-pcompress
+  KCONFIG:= \
+	CONFIG_CRYPTO_MANAGER \
+	CONFIG_CRYPTO_MANAGER2
+  FILES:=$(LINUX_DIR)/crypto/cryptomgr.ko
+  AUTOLOAD:=$(call AutoLoad,09,cryptomgr,1)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-manager))
+
+
+define KernelPackage/crypto-pcompress
+  TITLE:=CryptoAPI Partial (de)compression operations
+  KCONFIG:= \
+	CONFIG_CRYPTO_PCOMP=y \
+	CONFIG_CRYPTO_PCOMP2
+  FILES:=$(LINUX_DIR)/crypto/pcompress.ko
+  AUTOLOAD:=$(call AutoLoad,09,pcompress)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-pcompress))
+
+
+define KernelPackage/crypto-user
+  TITLE:=CryptoAPI userspace interface
+  DEPENDS:=+kmod-crypto-hash +kmod-crypto-manager
+  KCONFIG:= \
+	CONFIG_CRYPTO_USER_API \
+	CONFIG_CRYPTO_USER_API_HASH \
+	CONFIG_CRYPTO_USER_API_SKCIPHER
+  FILES:= \
+	$(LINUX_DIR)/crypto/af_alg.ko \
+	$(LINUX_DIR)/crypto/algif_hash.ko \
+	$(LINUX_DIR)/crypto/algif_skcipher.ko
+  AUTOLOAD:=$(call AutoLoad,09,af_alg algif_hash algif_skcipher)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-user))
+
+
+define KernelPackage/crypto-wq
+  TITLE:=CryptoAPI work queue handling
+  KCONFIG:=CONFIG_CRYPTO_WORKQUEUE
+  FILES:=$(LINUX_DIR)/crypto/crypto_wq.ko
+  AUTOLOAD:=$(call AutoLoad,09,crypto_wq)
+  $(call AddDepends/crypto)
+endef
+$(eval $(call KernelPackage,crypto-wq))
+
+define KernelPackage/crypto-rng
+  TITLE:=CryptoAPI random number generation
+  DEPENDS:=+kmod-crypto-hash +kmod-crypto-hmac +kmod-crypto-sha256
+  KCONFIG:= \
+	CONFIG_CRYPTO_DRBG \
+	CONFIG_CRYPTO_DRBG_HMAC=y \
+	CONFIG_CRYPTO_DRBG_HASH=n \
+	CONFIG_CRYPTO_DRBG_MENU \
+	CONFIG_CRYPTO_JITTERENTROPY \
+	CONFIG_CRYPTO_RNG2
+  FILES:= \
+	$(LINUX_DIR)/crypto/drbg.ko@ge4.2 \
+	$(LINUX_DIR)/crypto/jitterentropy_rng.ko@ge4.2 \
+	$(LINUX_DIR)/crypto/krng.ko@lt4.2 \
+	$(LINUX_DIR)/crypto/rng.ko
+  AUTOLOAD:=$(call AutoLoad,09,drbg@ge4.2 jitterentropy_rng@ge4.2 krng@lt4.2 rng)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-rng))
+
+
+define KernelPackage/crypto-iv
+  TITLE:=CryptoAPI initialization vectors
+  DEPENDS:=+kmod-crypto-manager +kmod-crypto-rng +kmod-crypto-wq
+  KCONFIG:= CONFIG_CRYPTO_BLKCIPHER2
+  FILES:= \
+	$(LINUX_DIR)/crypto/eseqiv.ko \
+	$(LINUX_DIR)/crypto/chainiv.ko
+  AUTOLOAD:=$(call AutoLoad,10,eseqiv chainiv)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-iv))
+
+
+define KernelPackage/crypto-echainiv
+  TITLE:=Encrypted Chain IV Generator
+  DEPENDS:=+kmod-crypto-aead
+  KCONFIG:=CONFIG_CRYPTO_ECHAINIV
+  FILES:=$(LINUX_DIR)/crypto/echainiv.ko
+  AUTOLOAD:=$(call AutoLoad,09,echainiv)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-echainiv))
+
+
+define KernelPackage/crypto-seqiv
+  TITLE:=CryptoAPI Sequence Number IV Generator
+  DEPENDS:=+kmod-crypto-aead +kmod-crypto-rng
+  KCONFIG:=CONFIG_CRYPTO_SEQIV
+  FILES:=$(LINUX_DIR)/crypto/seqiv.ko
+  AUTOLOAD:=$(call AutoLoad,09,seqiv)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-seqiv))
+
+
+define KernelPackage/crypto-hw-caam
+  TITLE:=Freescale CAAM driver (SEC4)
+  DEPENDS:=@TARGET_imx6||TARGET_mpc85xx +kmod-crypto-aead +kmod-crypto-authenc +kmod-crypto-hash +kmod-random-core
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_FSL_CAAM \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_JR \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_INTC=n \
+	CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/crypto/caam/caam.ko \
+	$(LINUX_DIR)/drivers/crypto/caam/caamalg.ko \
+	$(LINUX_DIR)/drivers/crypto/caam/caamhash.ko \
+	$(LINUX_DIR)/drivers/crypto/caam/caam_jr.ko \
+	$(LINUX_DIR)/drivers/crypto/caam/caamrng.ko
+  AUTOLOAD:=$(call AutoLoad,09,caam caamalg caamhash caam_jr caamrng)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hw-caam))
+
+
+define KernelPackage/crypto-hw-talitos
+  TITLE:=Freescale integrated security engine (SEC) driver
+  DEPENDS:=+kmod-crypto-manager +kmod-crypto-hash +kmod-random-core +kmod-crypto-authenc
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_TALITOS \
+	CONFIG_CRYPTO_DEV_TALITOS1=y \
+	CONFIG_CRYPTO_DEV_TALITOS2=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/crypto/talitos.ko
+  AUTOLOAD:=$(call AutoLoad,09,talitos)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hw-talitos))
+
+
+define KernelPackage/crypto-hw-padlock
+  TITLE:=VIA PadLock ACE with AES/SHA hw crypto module
+  DEPENDS:=+kmod-crypto-manager
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_PADLOCK \
+	CONFIG_CRYPTO_DEV_PADLOCK_AES \
+	CONFIG_CRYPTO_DEV_PADLOCK_SHA
+  FILES:= \
+	$(LINUX_DIR)/drivers/crypto/padlock-aes.ko \
+	$(LINUX_DIR)/drivers/crypto/padlock-sha.ko
+  AUTOLOAD:=$(call AutoLoad,09,padlock-aes padlock-sha)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hw-padlock))
+
+
+define KernelPackage/crypto-hw-ccp
+  TITLE:=AMD Cryptographic Coprocessor
+  DEPENDS:=+kmod-crypto-authenc +kmod-crypto-hash +kmod-crypto-manager +kmod-random-core
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_CCP=y \
+	CONFIG_CRYPTO_DEV_CCP_CRYPTO \
+	CONFIG_CRYPTO_DEV_CCP_DD
+  FILES:= \
+	$(LINUX_DIR)/drivers/crypto/ccp/ccp.ko \
+	$(LINUX_DIR)/drivers/crypto/ccp/ccp-crypto.ko
+  AUTOLOAD:=$(call AutoLoad,09,ccp ccp-crypto)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hw-ccp))
+
+
+define KernelPackage/crypto-hw-geode
+  TITLE:=AMD Geode hardware crypto module
+  DEPENDS:=+kmod-crypto-manager
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_GEODE
+  FILES:=$(LINUX_DIR)/drivers/crypto/geode-aes.ko
+  AUTOLOAD:=$(call AutoLoad,09,geode-aes)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hw-geode))
+
+
+define KernelPackage/crypto-hw-hifn-795x
+  TITLE:=HIFN 795x crypto accelerator
+  DEPENDS:=+kmod-random-core +kmod-crypto-manager
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_HIFN_795X \
+	CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y
+  FILES:=$(LINUX_DIR)/drivers/crypto/hifn_795x.ko
+  AUTOLOAD:=$(call AutoLoad,09,hifn_795x)
+  $(call AddDepends/crypto,+kmod-crypto-des)
+endef
+
+$(eval $(call KernelPackage,crypto-hw-hifn-795x))
+
+
+define KernelPackage/crypto-hw-ppc4xx
+  TITLE:=AMCC PPC4xx hardware crypto module
+  DEPENDS:=@TARGET_ppc40x||TARGET_ppc44x
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_PPC4XX
+  FILES:=$(LINUX_DIR)/drivers/crypto/amcc/crypto4xx.ko
+  AUTOLOAD:=$(call AutoLoad,90,crypto4xx)
+  $(call AddDepends/crypto,+kmod-crypto-manager +kmod-crypto-hash)
+endef
+
+define KernelPackage/crypto-hw-ppc4xx/description
+  Kernel support for the AMCC PPC4xx HW crypto engine.
+endef
+
+$(eval $(call KernelPackage,crypto-hw-ppc4xx))
+
+
+define KernelPackage/crypto-hw-omap
+  TITLE:=TI OMAP hardware crypto modules
+  DEPENDS:=@TARGET_omap
+  KCONFIG:= \
+	CONFIG_CRYPTO_HW=y \
+	CONFIG_CRYPTO_DEV_OMAP_AES \
+	CONFIG_CRYPTO_DEV_OMAP_DES \
+	CONFIG_CRYPTO_DEV_OMAP_SHAM
+ifneq ($(wildcard $(LINUX_DIR)/drivers/crypto/omap-des.ko),)
+  FILES:= \
+	$(LINUX_DIR)/drivers/crypto/omap-aes.ko \
+	$(LINUX_DIR)/drivers/crypto/omap-des.ko \
+	$(LINUX_DIR)/drivers/crypto/omap-sham.ko
+  AUTOLOAD:=$(call AutoLoad,90,omap-aes omap-des omap-sham)
+else
+  FILES:= \
+	$(LINUX_DIR)/drivers/crypto/omap-aes.ko \
+	$(LINUX_DIR)/drivers/crypto/omap-sham.ko
+  AUTOLOAD:=$(call AutoLoad,90,omap-aes omap-sham)
+endif
+  $(call AddDepends/crypto,+kmod-crypto-manager +kmod-crypto-hash)
+endef
+
+define KernelPackage/crypto-hw-omap/description
+  Kernel support for the TI OMAP HW crypto engine.
+endef
+
+$(eval $(call KernelPackage,crypto-hw-omap))
+
+
+define KernelPackage/crypto-authenc
+  TITLE:=Combined mode wrapper for IPsec
+  DEPENDS:=+kmod-crypto-manager +LINUX_4_4:kmod-crypto-null
+  KCONFIG:=CONFIG_CRYPTO_AUTHENC
+  FILES:=$(LINUX_DIR)/crypto/authenc.ko
+  AUTOLOAD:=$(call AutoLoad,09,authenc)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-authenc))
+
+define KernelPackage/crypto-cbc
+  TITLE:=Cipher Block Chaining CryptoAPI module
+  DEPENDS:=+kmod-crypto-manager
+  KCONFIG:=CONFIG_CRYPTO_CBC
+  FILES:=$(LINUX_DIR)/crypto/cbc.ko
+  AUTOLOAD:=$(call AutoLoad,09,cbc)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-cbc))
+
+define KernelPackage/crypto-ctr
+  TITLE:=Counter Mode CryptoAPI module
+  DEPENDS:=+kmod-crypto-manager +kmod-crypto-seqiv +kmod-crypto-iv
+  KCONFIG:=CONFIG_CRYPTO_CTR
+  FILES:=$(LINUX_DIR)/crypto/ctr.ko
+  AUTOLOAD:=$(call AutoLoad,09,ctr)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-ctr))
+
+define KernelPackage/crypto-ccm
+ TITLE:=Support for Counter with CBC MAC (CCM)
+ DEPENDS:=+kmod-crypto-ctr +kmod-crypto-aead
+ KCONFIG:=CONFIG_CRYPTO_CCM
+ FILES:=$(LINUX_DIR)/crypto/ccm.ko
+ AUTOLOAD:=$(call AutoLoad,09,ccm)
+ $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-ccm))
+
+define KernelPackage/crypto-pcbc
+  TITLE:=Propagating Cipher Block Chaining CryptoAPI module
+  DEPENDS:=+kmod-crypto-manager
+  KCONFIG:=CONFIG_CRYPTO_PCBC
+  FILES:=$(LINUX_DIR)/crypto/pcbc.ko
+  AUTOLOAD:=$(call AutoLoad,09,pcbc)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-pcbc))
+
+define KernelPackage/crypto-crc32c
+  TITLE:=CRC32c CRC module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:=CONFIG_CRYPTO_CRC32C
+  FILES:=$(LINUX_DIR)/crypto/crc32c_generic.ko
+  AUTOLOAD:=$(call AutoLoad,04,crc32c_generic,1)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-crc32c))
+
+
+define KernelPackage/crypto-des
+  TITLE:=DES/3DES cipher CryptoAPI module
+  KCONFIG:=CONFIG_CRYPTO_DES
+  FILES:=$(LINUX_DIR)/crypto/des_generic.ko
+  AUTOLOAD:=$(call AutoLoad,09,des_generic)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-des))
+
+
+define KernelPackage/crypto-deflate
+  TITLE:=Deflate compression CryptoAPI module
+  DEPENDS:=+kmod-lib-zlib
+  KCONFIG:=CONFIG_CRYPTO_DEFLATE
+  FILES:=$(LINUX_DIR)/crypto/deflate.ko
+  AUTOLOAD:=$(call AutoLoad,09,deflate)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-deflate))
+
+
+define KernelPackage/crypto-fcrypt
+  TITLE:=FCRYPT cipher CryptoAPI module
+  KCONFIG:=CONFIG_CRYPTO_FCRYPT
+  FILES:=$(LINUX_DIR)/crypto/fcrypt.ko
+  AUTOLOAD:=$(call AutoLoad,09,fcrypt)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-fcrypt))
+
+define KernelPackage/crypto-ecb
+  TITLE:=Electronic CodeBook CryptoAPI module
+  DEPENDS:=+kmod-crypto-manager
+  KCONFIG:=CONFIG_CRYPTO_ECB
+  FILES:=$(LINUX_DIR)/crypto/ecb.ko
+  AUTOLOAD:=$(call AutoLoad,09,ecb)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-ecb))
+
+
+define KernelPackage/crypto-hmac
+  TITLE:=HMAC digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash +kmod-crypto-manager
+  KCONFIG:=CONFIG_CRYPTO_HMAC
+  FILES:=$(LINUX_DIR)/crypto/hmac.ko
+  AUTOLOAD:=$(call AutoLoad,09,hmac)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-hmac))
+
+
+define KernelPackage/crypto-cmac
+  TITLE:=Support for Cipher-based Message Authentication Code (CMAC)
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:=CONFIG_CRYPTO_CMAC
+  FILES:=$(LINUX_DIR)/crypto/cmac.ko
+  AUTOLOAD:=$(call AutoLoad,09,cmac)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-cmac))
+
+
+define KernelPackage/crypto-gcm
+  TITLE:=GCM/GMAC CryptoAPI module
+  DEPENDS:=+kmod-crypto-ctr +kmod-crypto-ghash +kmod-crypto-null
+  KCONFIG:=CONFIG_CRYPTO_GCM
+  FILES:=$(LINUX_DIR)/crypto/gcm.ko
+  AUTOLOAD:=$(call AutoLoad,09,gcm)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-gcm))
+
+
+define KernelPackage/crypto-gf128
+  TITLE:=GF(2^128) multiplication functions CryptoAPI module
+  KCONFIG:=CONFIG_CRYPTO_GF128MUL
+  FILES:=$(LINUX_DIR)/crypto/gf128mul.ko
+  AUTOLOAD:=$(call AutoLoad,09,gf128mul)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-gf128))
+
+
+define KernelPackage/crypto-ghash
+  TITLE:=GHASH digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-gf128 +kmod-crypto-hash
+  KCONFIG:=CONFIG_CRYPTO_GHASH
+  FILES:=$(LINUX_DIR)/crypto/ghash-generic.ko
+  AUTOLOAD:=$(call AutoLoad,09,ghash-generic)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-ghash))
+
+
+define KernelPackage/crypto-md4
+  TITLE:=MD4 digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:=CONFIG_CRYPTO_MD4
+  FILES:=$(LINUX_DIR)/crypto/md4.ko
+  AUTOLOAD:=$(call AutoLoad,09,md4)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-md4))
+
+
+define KernelPackage/crypto-md5
+  TITLE:=MD5 digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:= \
+	CONFIG_CRYPTO_MD5 \
+	CONFIG_CRYPTO_MD5_OCTEON
+  FILES:=$(LINUX_DIR)/crypto/md5.ko
+  AUTOLOAD:=$(call AutoLoad,09,md5)
+  $(call AddDepends/crypto)
+endef
+
+define KernelPackage/crypto-md5/octeon
+  FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-md5.ko
+  AUTOLOAD:=$(call AutoLoad,09,octeon-md5)
+endef
+
+$(eval $(call KernelPackage,crypto-md5))
+
+
+define KernelPackage/crypto-michael-mic
+  TITLE:=Michael MIC keyed digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:=CONFIG_CRYPTO_MICHAEL_MIC
+  FILES:=$(LINUX_DIR)/crypto/michael_mic.ko
+  AUTOLOAD:=$(call AutoLoad,09,michael_mic)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-michael-mic))
+
+
+define KernelPackage/crypto-sha1
+  TITLE:=SHA1 digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:= \
+	CONFIG_CRYPTO_SHA1 \
+	CONFIG_CRYPTO_SHA1_OCTEON
+  FILES:=$(LINUX_DIR)/crypto/sha1_generic.ko
+  AUTOLOAD:=$(call AutoLoad,09,sha1_generic)
+  $(call AddDepends/crypto)
+endef
+
+define KernelPackage/crypto-sha1/octeon
+  FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha1.ko
+  AUTOLOAD:=$(call AutoLoad,09,octeon-sha1)
+endef
+
+$(eval $(call KernelPackage,crypto-sha1))
+
+
+define KernelPackage/crypto-sha256
+  TITLE:=SHA224 SHA256 digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:= \
+	CONFIG_CRYPTO_SHA256 \
+	CONFIG_CRYPTO_SHA256_OCTEON
+  FILES:=$(LINUX_DIR)/crypto/sha256_generic.ko
+  AUTOLOAD:=$(call AutoLoad,09,sha256_generic)
+  $(call AddDepends/crypto)
+endef
+
+define KernelPackage/crypto-sha256/octeon
+  FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha256.ko
+  AUTOLOAD:=$(call AutoLoad,09,octeon-sha256)
+endef
+
+$(eval $(call KernelPackage,crypto-sha256))
+
+
+define KernelPackage/crypto-sha512
+  TITLE:=SHA512 digest CryptoAPI module
+  DEPENDS:=+kmod-crypto-hash
+  KCONFIG:= \
+	CONFIG_CRYPTO_SHA512 \
+	CONFIG_CRYPTO_SHA512_OCTEON
+  FILES:=$(LINUX_DIR)/crypto/sha512_generic.ko
+  AUTOLOAD:=$(call AutoLoad,09,sha512_generic)
+  $(call AddDepends/crypto)
+endef
+
+define KernelPackage/crypto-sha512/octeon
+  FILES+=$(LINUX_DIR)/arch/mips/cavium-octeon/crypto/octeon-sha512.ko
+  AUTOLOAD:=$(call AutoLoad,09,octeon-sha512)
+endef
+
+$(eval $(call KernelPackage,crypto-sha512))
+
+
+define KernelPackage/crypto-misc
+  TITLE:=Other CryptoAPI modules
+  DEPENDS:=+kmod-crypto-manager
+  KCONFIG:= \
+	CONFIG_CRYPTO_ANUBIS \
+	CONFIG_CRYPTO_BLOWFISH \
+	CONFIG_CRYPTO_CAMELLIA \
+	CONFIG_CRYPTO_CAST5 \
+	CONFIG_CRYPTO_CAST6 \
+	CONFIG_CRYPTO_FCRYPT \
+	CONFIG_CRYPTO_KHAZAD \
+	CONFIG_CRYPTO_SERPENT \
+	CONFIG_CRYPTO_TEA \
+	CONFIG_CRYPTO_TGR192 \
+	CONFIG_CRYPTO_TWOFISH \
+	CONFIG_CRYPTO_TWOFISH_COMMON \
+	CONFIG_CRYPTO_TWOFISH_586 \
+	CONFIG_CRYPTO_WP512
+  FILES:= \
+	$(LINUX_DIR)/crypto/anubis.ko \
+	$(LINUX_DIR)/crypto/camellia_generic.ko \
+	$(LINUX_DIR)/crypto/cast_common.ko \
+	$(LINUX_DIR)/crypto/cast5_generic.ko \
+	$(LINUX_DIR)/crypto/cast6_generic.ko \
+	$(LINUX_DIR)/crypto/khazad.ko \
+	$(LINUX_DIR)/crypto/tea.ko \
+	$(LINUX_DIR)/crypto/tgr192.ko \
+	$(LINUX_DIR)/crypto/twofish_common.ko \
+	$(LINUX_DIR)/crypto/wp512.ko \
+	$(LINUX_DIR)/crypto/twofish_generic.ko \
+	$(LINUX_DIR)/crypto/blowfish_common.ko \
+	$(LINUX_DIR)/crypto/blowfish_generic.ko \
+	$(LINUX_DIR)/crypto/serpent_generic.ko
+  $(call AddDepends/crypto)
+endef
+
+ifndef CONFIG_TARGET_x86_64
+  define KernelPackage/crypto-misc/x86
+    FILES+=$(LINUX_DIR)/arch/x86/crypto/twofish-i586.ko
+  endef
+endif
+
+$(eval $(call KernelPackage,crypto-misc))
+
+
+define KernelPackage/crypto-null
+  TITLE:=Null CryptoAPI module
+  KCONFIG:=CONFIG_CRYPTO_NULL
+  FILES:=$(LINUX_DIR)/crypto/crypto_null.ko
+  AUTOLOAD:=$(call AutoLoad,09,crypto_null)
+  $(call AddDepends/crypto, +kmod-crypto-hash)
+endef
+
+$(eval $(call KernelPackage,crypto-null))
+
+
+define KernelPackage/crypto-test
+  TITLE:=Test CryptoAPI module
+  KCONFIG:=CONFIG_CRYPTO_TEST
+  FILES:=$(LINUX_DIR)/crypto/tcrypt.ko
+  $(call AddDepends/crypto,+kmod-crypto-manager)
+endef
+
+$(eval $(call KernelPackage,crypto-test))
+
+
+define KernelPackage/crypto-xts
+  TITLE:=XTS cipher CryptoAPI module
+  DEPENDS:=+kmod-crypto-gf128 +kmod-crypto-manager
+  KCONFIG:=CONFIG_CRYPTO_XTS
+  FILES:=$(LINUX_DIR)/crypto/xts.ko
+  AUTOLOAD:=$(call AutoLoad,09,xts)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-xts))
+
+
+define KernelPackage/crypto-mv-cesa
+  TITLE:=Marvell crypto engine
+  DEPENDS:=+kmod-crypto-manager @TARGET_kirkwood||TARGET_orion
+  KCONFIG:=CONFIG_CRYPTO_DEV_MV_CESA
+  FILES:=$(LINUX_DIR)/drivers/crypto/mv_cesa.ko
+  AUTOLOAD:=$(call AutoLoad,09,mv_cesa)
+  $(call AddDepends/crypto)
+endef
+
+$(eval $(call KernelPackage,crypto-mv-cesa))
diff --git a/package/kernel/linux/modules/firewire.mk b/package/kernel/linux/modules/firewire.mk
new file mode 100644
index 0000000000..18b531a29b
--- /dev/null
+++ b/package/kernel/linux/modules/firewire.mk
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2008-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+FIREWIRE_MENU:=FireWire support
+
+define KernelPackage/firewire
+  SUBMENU:=$(FIREWIRE_MENU)
+  TITLE:=Support for FireWire (new stack)
+  DEPENDS:=@PCI_SUPPORT +kmod-lib-crc-itu-t
+  KCONFIG:=CONFIG_FIREWIRE
+  FILES:=$(LINUX_DIR)/drivers/firewire/firewire-core.ko
+endef
+
+define KernelPackage/firewire/description
+ Kernel support for FireWire (new stack)
+endef
+
+$(eval $(call KernelPackage,firewire))
+
+
+define KernelPackage/firewire-ohci
+  SUBMENU:=$(FIREWIRE_MENU)
+  TITLE:=Support for OHCI-1394 controllers
+  DEPENDS:=kmod-firewire
+  KCONFIG:= \
+	CONFIG_FIREWIRE_OHCI \
+	CONFIG_FIREWIRE_OHCI_DEBUG=n \
+	CONFIG_FIREWIRE_OHCI_REMOTE_DMA=n
+  FILES:=$(LINUX_DIR)/drivers/firewire/firewire-ohci.ko
+  AUTOLOAD:=$(call AutoProbe,firewire-ohci)
+endef
+
+
+define KernelPackage/firewire-ohci/description
+ Kernel support for FireWire OHCI-1394 controllers
+endef
+
+$(eval $(call KernelPackage,firewire-ohci))
+
+
+define KernelPackage/firewire-sbp2
+  SUBMENU:=$(FIREWIRE_MENU)
+  TITLE:=Support for SBP-2 devices over FireWire
+  DEPENDS:=kmod-firewire +kmod-scsi-core
+  KCONFIG:=CONFIG_FIREWIRE_SBP2
+  FILES:=$(LINUX_DIR)/drivers/firewire/firewire-sbp2.ko
+  AUTOLOAD:=$(call AutoProbe,firewire-sbp2)
+endef
+
+define KernelPackage/firewire-sbp2/description
+ Kernel support for SBP-2 devices over FireWire
+endef
+
+$(eval $(call KernelPackage,firewire-sbp2))
+
+
+define KernelPackage/firewire-net
+  SUBMENU:=$(FIREWIRE_MENU)
+  TITLE:=Support for IP networking over FireWire
+  DEPENDS:=kmod-firewire
+  KCONFIG:=CONFIG_FIREWIRE_NET
+  FILES:=$(LINUX_DIR)/drivers/firewire/firewire-net.ko
+  AUTOLOAD:=$(call AutoProbe,firewire-net)
+endef
+
+define KernelPackage/firewire-net/description
+ Kernel support for IPv4 over FireWire
+endef
+
+$(eval $(call KernelPackage,firewire-net))
diff --git a/package/kernel/linux/modules/fs.mk b/package/kernel/linux/modules/fs.mk
new file mode 100644
index 0000000000..ce2408cdc4
--- /dev/null
+++ b/package/kernel/linux/modules/fs.mk
@@ -0,0 +1,506 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+FS_MENU:=Filesystems
+
+define KernelPackage/fs-fscache
+  SUBMENU:=$(FS_MENU)
+  TITLE:=General filesystem local cache manager
+  DEPENDS:=
+  KCONFIG:=\
+	CONFIG_FSCACHE=m \
+	CONFIG_FSCACHE_STATS=y \
+	CONFIG_FSCACHE_HISTOGRAM=n \
+	CONFIG_FSCACHE_DEBUG=n \
+	CONFIG_FSCACHE_OBJECT_LIST=n \
+	CONFIG_CACHEFILES=y \
+	CONFIG_CACHEFILES_DEBUG=n \
+	CONFIG_CACHEFILES_HISTOGRAM=n
+  FILES:=$(LINUX_DIR)/fs/fscache/fscache.ko
+  AUTOLOAD:=$(call AutoLoad,29,fscache)
+endef
+
+$(eval $(call KernelPackage,fs-fscache))
+
+define KernelPackage/fs-9p
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Plan 9 Resource Sharing Support
+  DEPENDS:=+kmod-9pnet
+  KCONFIG:=\
+	CONFIG_9P_FS \
+	CONFIG_9P_FS_POSIX_ACL=n \
+	CONFIG_9P_FS_SECURITY=n \
+	CONFIG_9P_FSCACHE=n
+  FILES:=$(LINUX_DIR)/fs/9p/9p.ko
+  AUTOLOAD:=$(call AutoLoad,30,9p)
+endef
+
+define KernelPackage/fs-9p/description
+  Kernel module for Plan 9 Resource Sharing Support support
+endef
+
+$(eval $(call KernelPackage,fs-9p))
+
+define KernelPackage/fs-afs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Andrew FileSystem client
+  DEFAULT:=n
+  DEPENDS:=+kmod-rxrpc +kmod-dnsresolver +kmod-fs-fscache
+  KCONFIG:=\
+	CONFIG_AFS_FS=m \
+	CONFIG_AFS_DEBUG=n \
+	CONFIG_AFS_FSCACHE=y
+  FILES:=$(LINUX_DIR)/fs/afs/kafs.ko
+  AUTOLOAD:=$(call AutoLoad,30,kafs)
+endef
+
+define KernelPackage/fs-afs/description
+  Kernel module for Andrew FileSystem client support
+endef
+
+$(eval $(call KernelPackage,fs-afs))
+
+define KernelPackage/fs-autofs4
+  SUBMENU:=$(FS_MENU)
+  TITLE:=AUTOFS4 filesystem support
+  KCONFIG:=CONFIG_AUTOFS4_FS
+  FILES:=$(LINUX_DIR)/fs/autofs4/autofs4.ko
+  AUTOLOAD:=$(call AutoLoad,30,autofs4)
+endef
+
+define KernelPackage/fs-autofs4/description
+ Kernel module for AutoFS4 support
+endef
+
+$(eval $(call KernelPackage,fs-autofs4))
+
+
+define KernelPackage/fs-btrfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=BTRFS filesystem support
+  DEPENDS:=+kmod-lib-crc32c +kmod-lib-lzo +kmod-lib-zlib +kmod-lib-raid6 +kmod-lib-xor
+  KCONFIG:=\
+	CONFIG_BTRFS_FS \
+	CONFIG_BTRFS_FS_POSIX_ACL=n \
+	CONFIG_BTRFS_FS_CHECK_INTEGRITY=n
+  FILES:=\
+	$(LINUX_DIR)/fs/btrfs/btrfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,btrfs,1)
+endef
+
+define KernelPackage/fs-btrfs/description
+ Kernel module for BTRFS support
+endef
+
+$(eval $(call KernelPackage,fs-btrfs))
+
+
+define KernelPackage/fs-cifs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=CIFS support
+  KCONFIG:= \
+	CONFIG_CIFS \
+	CONFIG_CIFS_XATTR=y \
+	CONFIG_CIFS_DFS_UPCALL=n \
+	CONFIG_CIFS_UPCALL=n
+  FILES:=$(LINUX_DIR)/fs/cifs/cifs.ko
+  AUTOLOAD:=$(call AutoLoad,30,cifs)
+  $(call AddDepends/nls)
+  DEPENDS+= \
+    +kmod-crypto-hmac \
+    +kmod-crypto-md5 \
+    +kmod-crypto-md4 \
+    +kmod-crypto-des \
+    +kmod-crypto-ecb \
+    +kmod-crypto-sha256
+endef
+
+define KernelPackage/fs-cifs/description
+ Kernel module for CIFS support
+endef
+
+$(eval $(call KernelPackage,fs-cifs))
+
+
+define KernelPackage/fs-configfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Configuration filesystem support
+  KCONFIG:= \
+	CONFIG_CONFIGFS_FS
+  FILES:=$(LINUX_DIR)/fs/configfs/configfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,configfs)
+endef
+
+define KernelPackage/fs-configfs/description
+ Kernel module for configfs support
+endef
+
+$(eval $(call KernelPackage,fs-configfs))
+
+define KernelPackage/fs-cramfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Compressed RAM/ROM filesystem support
+  DEPENDS:=+kmod-lib-zlib
+  KCONFIG:= \
+	CONFIG_CRAMFS
+  FILES:=$(LINUX_DIR)/fs/cramfs/cramfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,cramfs)
+endef
+
+define KernelPackage/fs-cramfs/description
+ Kernel module for cramfs support
+endef
+
+$(eval $(call KernelPackage,fs-cramfs))
+
+define KernelPackage/fs-exportfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=exportfs kernel server support
+  KCONFIG:=CONFIG_EXPORTFS
+  FILES=$(LINUX_DIR)/fs/exportfs/exportfs.ko
+  AUTOLOAD:=$(call AutoLoad,20,exportfs,1)
+endef
+
+define KernelPackage/fs-exportfs/description
+ Kernel module for exportfs. Needed for some other modules.
+endef
+
+$(eval $(call KernelPackage,fs-exportfs))
+
+
+define KernelPackage/fs-ext4
+  SUBMENU:=$(FS_MENU)
+  TITLE:=EXT4 filesystem support
+  DEPENDS := \
+    +kmod-lib-crc16 \
+    +kmod-crypto-hash \
+    +kmod-crypto-crc32c
+  KCONFIG:= \
+	CONFIG_EXT4_FS \
+	CONFIG_EXT4_ENCRYPTION=n \
+	CONFIG_JBD2
+  FILES:= \
+	$(LINUX_DIR)/fs/ext4/ext4.ko \
+	$(LINUX_DIR)/fs/jbd2/jbd2.ko \
+	$(LINUX_DIR)/fs/mbcache.ko
+  AUTOLOAD:=$(call AutoLoad,30,mbcache jbd2 ext4,1)
+endef
+
+define KernelPackage/fs-ext4/description
+ Kernel module for EXT4 filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-ext4))
+
+
+define KernelPackage/fs-f2fs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=F2FS filesystem support
+  KCONFIG:= \
+	CONFIG_F2FS_FS \
+	CONFIG_F2FS_STAT_FS=y \
+	CONFIG_F2FS_FS_XATTR=y \
+	CONFIG_F2FS_FS_POSIX_ACL=n \
+	CONFIG_F2FS_FS_SECURITY=n \
+	CONFIG_F2FS_CHECK_FS=n
+  FILES:=$(LINUX_DIR)/fs/f2fs/f2fs.ko
+  AUTOLOAD:=$(call AutoLoad,30,f2fs,1)
+endef
+
+define KernelPackage/fs-f2fs/description
+ Kernel module for F2FS filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-f2fs))
+
+
+define KernelPackage/fuse
+  SUBMENU:=$(FS_MENU)
+  TITLE:=FUSE (Filesystem in Userspace) support
+  KCONFIG:= CONFIG_FUSE_FS
+  FILES:=$(LINUX_DIR)/fs/fuse/fuse.ko
+  AUTOLOAD:=$(call AutoLoad,80,fuse)
+endef
+
+define KernelPackage/fuse/description
+ Kernel module for userspace filesystem support
+endef
+
+$(eval $(call KernelPackage,fuse))
+
+
+define KernelPackage/fs-hfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=HFS filesystem support
+  KCONFIG:=CONFIG_HFS_FS
+  FILES:=$(LINUX_DIR)/fs/hfs/hfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,hfs)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/fs-hfs/description
+ Kernel module for HFS filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-hfs))
+
+
+define KernelPackage/fs-hfsplus
+  SUBMENU:=$(FS_MENU)
+  TITLE:=HFS+ filesystem support
+  KCONFIG:=CONFIG_HFSPLUS_FS
+  FILES:=$(LINUX_DIR)/fs/hfsplus/hfsplus.ko
+  AUTOLOAD:=$(call AutoLoad,30,hfsplus)
+  $(call AddDepends/nls,utf8)
+endef
+
+define KernelPackage/fs-hfsplus/description
+ Kernel module for HFS+ filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-hfsplus))
+
+
+define KernelPackage/fs-isofs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=ISO9660 filesystem support
+  DEPENDS:=+kmod-lib-zlib
+  KCONFIG:=CONFIG_ISO9660_FS CONFIG_JOLIET=y CONFIG_ZISOFS=n
+  FILES:=$(LINUX_DIR)/fs/isofs/isofs.ko
+  AUTOLOAD:=$(call AutoLoad,30,isofs)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/fs-isofs/description
+ Kernel module for ISO9660 filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-isofs))
+
+
+define KernelPackage/fs-minix
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Minix filesystem support
+  KCONFIG:=CONFIG_MINIX_FS
+  FILES:=$(LINUX_DIR)/fs/minix/minix.ko
+  AUTOLOAD:=$(call AutoLoad,30,minix)
+endef
+
+define KernelPackage/fs-minix/description
+ Kernel module for Minix filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-minix))
+
+
+define KernelPackage/fs-msdos
+  SUBMENU:=$(FS_MENU)
+  TITLE:=MSDOS filesystem support
+  DEPENDS:=+kmod-fs-vfat
+  KCONFIG:=CONFIG_MSDOS_FS
+  FILES:=$(LINUX_DIR)/fs/fat/msdos.ko
+  AUTOLOAD:=$(call AutoLoad,40,msdos)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/fs-msdos/description
+ Kernel module for MSDOS filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-msdos))
+
+
+define KernelPackage/fs-nfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=NFS filesystem support
+  DEPENDS:=+kmod-fs-nfs-common +kmod-dnsresolver
+  KCONFIG:= \
+	CONFIG_NFS_FS \
+	CONFIG_NFS_USE_LEGACY_DNS=n \
+	CONFIG_NFS_USE_NEW_IDMAPPER=n
+  FILES:= \
+	$(LINUX_DIR)/fs/nfs/nfs.ko \
+	$(LINUX_DIR)/fs/nfs/nfsv3.ko
+  AUTOLOAD:=$(call AutoLoad,40,nfs nfsv3)
+endef
+
+define KernelPackage/fs-nfs/description
+ Kernel module for NFS support
+endef
+
+$(eval $(call KernelPackage,fs-nfs))
+
+
+define KernelPackage/fs-nfs-common
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Common NFS filesystem modules
+  KCONFIG:= \
+	CONFIG_LOCKD \
+	CONFIG_SUNRPC \
+	CONFIG_GRACE_PERIOD
+  FILES:= \
+	$(LINUX_DIR)/fs/lockd/lockd.ko \
+	$(LINUX_DIR)/net/sunrpc/sunrpc.ko \
+	$(LINUX_DIR)/fs/nfs_common/grace.ko
+  AUTOLOAD:=$(call AutoLoad,30,grace sunrpc lockd)
+endef
+
+$(eval $(call KernelPackage,fs-nfs-common))
+
+
+define KernelPackage/fs-nfs-common-v4
+  SUBMENU:=$(FS_MENU)
+  TITLE:=Common NFS V4 filesystem modules
+  KCONFIG+=\
+	CONFIG_SUNRPC_GSS\
+	CONFIG_NFS_V4=y\
+	CONFIG_NFSD_V4=y
+  DEPENDS:= @BROKEN
+  FILES+=$(LINUX_DIR)/net/sunrpc/auth_gss/auth_rpcgss.ko
+  AUTOLOAD=$(call AutoLoad,30,auth_rpcgss)
+endef
+
+define KernelPackage/fs-nfs-common-v4/description
+ Kernel modules for NFS V4 & NFSD V4 kernel support
+endef
+
+$(eval $(call KernelPackage,fs-nfs-common-v4))
+
+
+define KernelPackage/fs-nfsd
+  SUBMENU:=$(FS_MENU)
+  TITLE:=NFS kernel server support
+  DEPENDS:=+kmod-fs-nfs-common +kmod-fs-exportfs
+  KCONFIG:= \
+	CONFIG_NFSD \
+	CONFIG_NFSD_FAULT_INJECTION=n
+  FILES:=$(LINUX_DIR)/fs/nfsd/nfsd.ko
+  AUTOLOAD:=$(call AutoLoad,40,nfsd)
+endef
+
+define KernelPackage/fs-nfsd/description
+ Kernel module for NFS kernel server support
+endef
+
+$(eval $(call KernelPackage,fs-nfsd))
+
+
+define KernelPackage/fs-ntfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=NTFS filesystem support
+  KCONFIG:=CONFIG_NTFS_FS
+  FILES:=$(LINUX_DIR)/fs/ntfs/ntfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,ntfs)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/fs-ntfs/description
+ Kernel module for NTFS filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-ntfs))
+
+
+define KernelPackage/fs-reiserfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=ReiserFS filesystem support
+  KCONFIG:=CONFIG_REISERFS_FS \
+	CONFIG_REISERFS_FS_XATTR=y
+  FILES:=$(LINUX_DIR)/fs/reiserfs/reiserfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,reiserfs,1)
+endef
+
+define KernelPackage/fs-reiserfs/description
+ Kernel module for ReiserFS support
+endef
+
+$(eval $(call KernelPackage,fs-reiserfs))
+
+
+define KernelPackage/fs-squashfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=SquashFS 4.0 filesystem support
+  KCONFIG:=CONFIG_SQUASHFS \
+	CONFIG_SQUASHFS_XZ=y
+  FILES:=$(LINUX_DIR)/fs/squashfs/squashfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,squashfs,1)
+endef
+
+define KernelPackage/fs-squashfs/description
+ Kernel module for SquashFS 4.0 support
+endef
+
+$(eval $(call KernelPackage,fs-squashfs))
+
+
+define KernelPackage/fs-udf
+  SUBMENU:=$(FS_MENU)
+  TITLE:=UDF filesystem support
+  KCONFIG:=CONFIG_UDF_FS
+  FILES:=$(LINUX_DIR)/fs/udf/udf.ko
+  AUTOLOAD:=$(call AutoLoad,30,udf)
+  DEPENDS:=+kmod-lib-crc-itu-t
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/fs-udf/description
+ Kernel module for UDF filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-udf))
+
+
+define KernelPackage/fs-vfat
+  SUBMENU:=$(FS_MENU)
+  TITLE:=VFAT filesystem support
+  KCONFIG:= \
+	CONFIG_FAT_FS \
+	CONFIG_VFAT_FS
+  FILES:= \
+	$(LINUX_DIR)/fs/fat/fat.ko \
+	$(LINUX_DIR)/fs/fat/vfat.ko
+  AUTOLOAD:=$(call AutoLoad,30,fat vfat)
+  $(call AddDepends/nls,cp437 iso8859-1 utf8)
+endef
+
+define KernelPackage/fs-vfat/description
+ Kernel module for VFAT filesystem support
+endef
+
+$(eval $(call KernelPackage,fs-vfat))
+
+
+define KernelPackage/fs-xfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=XFS filesystem support
+  KCONFIG:=CONFIG_XFS_FS
+  DEPENDS:= +kmod-fs-exportfs +kmod-lib-crc32c
+  FILES:=$(LINUX_DIR)/fs/xfs/xfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,xfs,1)
+endef
+
+define KernelPackage/fs-xfs/description
+ Kernel module for XFS support
+endef
+
+$(eval $(call KernelPackage,fs-xfs))
+
+
+define KernelPackage/fs-jfs
+  SUBMENU:=$(FS_MENU)
+  TITLE:=JFS filesystem support
+  KCONFIG:=CONFIG_JFS_FS
+  FILES:=$(LINUX_DIR)/fs/jfs/jfs.ko
+  AUTOLOAD:=$(call AutoLoad,30,jfs,1)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/fs-jfs/description
+ Kernel module for JFS support
+endef
+
+$(eval $(call KernelPackage,fs-jfs))
diff --git a/package/kernel/linux/modules/hwmon.mk b/package/kernel/linux/modules/hwmon.mk
new file mode 100644
index 0000000000..56cd0ec995
--- /dev/null
+++ b/package/kernel/linux/modules/hwmon.mk
@@ -0,0 +1,389 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+HWMON_MENU:=Hardware Monitoring Support
+
+define KernelPackage/hwmon-core
+  SUBMENU:=$(HWMON_MENU)
+  TITLE:=Hardware monitoring support
+  KCONFIG:= \
+	CONFIG_HWMON \
+	CONFIG_HWMON_DEBUG_CHIP=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/hwmon/hwmon.ko
+endef
+
+define KernelPackage/hwmon-core/description
+ Kernel modules for hardware monitoring
+endef
+
+$(eval $(call KernelPackage,hwmon-core))
+
+
+define AddDepends/hwmon
+  SUBMENU:=$(HWMON_MENU)
+  DEPENDS:=kmod-hwmon-core $(1)
+endef
+
+define KernelPackage/hwmon-vid
+  TITLE:=VID/VRM/VRD voltage conversion module.
+  KCONFIG:=CONFIG_HWMON_VID
+  FILES:=$(LINUX_DIR)/drivers/hwmon/hwmon-vid.ko
+  AUTOLOAD:=$(call AutoLoad,41,hwmon-vid)
+  $(call AddDepends/hwmon,)
+endef
+
+define KernelPackage/hwmon-vid/description
+ VID/VRM/VRD voltage conversion module for hardware monitoring
+endef
+
+$(eval $(call KernelPackage,hwmon-vid))
+
+
+define KernelPackage/hwmon-adt7410
+  TITLE:=ADT7410 monitoring support
+  KCONFIG:= \
+	CONFIG_SENSORS_ADT7X10 \
+	CONFIG_SENSORS_ADT7410
+  FILES:= \
+	$(LINUX_DIR)/drivers/hwmon/adt7x10.ko \
+	$(LINUX_DIR)/drivers/hwmon/adt7410.ko
+  AUTOLOAD:=$(call AutoLoad,60,adt7x10 adt7410)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-adt7410/description
+ Kernel module for ADT7410/7420 I2C thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-adt7410))
+
+
+define KernelPackage/hwmon-adt7475
+  TITLE:=ADT7473/7475/7476/7490 monitoring support
+  KCONFIG:=CONFIG_SENSORS_ADT7475
+  FILES:=$(LINUX_DIR)/drivers/hwmon/adt7475.ko
+  AUTOLOAD:=$(call AutoProbe,adt7475)
+  $(call AddDepends/hwmon,+kmod-i2c-core +kmod-hwmon-vid)
+endef
+
+define KernelPackage/hwmon-adt7475/description
+ Kernel module for ADT7473/7475/7476/7490 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-adt7475))
+
+
+define KernelPackage/hwmon-ina209
+  TITLE:=INA209 monitoring support
+  KCONFIG:=CONFIG_SENSORS_INA209
+  FILES:=$(LINUX_DIR)/drivers/hwmon/ina209.ko
+  AUTOLOAD:=$(call AutoProbe,ina209)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-ina209/description
+ Kernel module for ina209 dc power monitor chips
+endef
+
+$(eval $(call KernelPackage,hwmon-ina209))
+
+
+define KernelPackage/hwmon-ina2xx
+  TITLE:=INA2XX monitoring support
+  KCONFIG:=CONFIG_SENSORS_INA2XX
+  FILES:=$(LINUX_DIR)/drivers/hwmon/ina2xx.ko
+  AUTOLOAD:=$(call AutoProbe,ina2xx)
+  $(call AddDepends/hwmon,+kmod-i2c-core +LINUX_4_4:kmod-regmap)
+endef
+
+define KernelPackage/hwmon-ina2xx/description
+ Kernel module for ina2xx dc current monitor chips
+endef
+
+$(eval $(call KernelPackage,hwmon-ina2xx))
+
+
+define KernelPackage/hwmon-it87
+  TITLE:=IT87 monitoring support
+  KCONFIG:=CONFIG_SENSORS_IT87
+  FILES:=$(LINUX_DIR)/drivers/hwmon/it87.ko
+  AUTOLOAD:=$(call AutoProbe,it87)
+  $(call AddDepends/hwmon,+kmod-i2c-core +kmod-hwmon-vid +PACKAGE_kmod-thermal:kmod-thermal)
+endef
+
+define KernelPackage/hwmon-it87/description
+ Kernel module for it87 thermal and voltage monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-it87))
+
+define KernelPackage/hwmon-lm63
+  TITLE:=LM63/64 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM63
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm63.ko
+  AUTOLOAD:=$(call AutoProbe,lm63)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-lm63/description
+ Kernel module for lm63 and lm64 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm63))
+
+
+define KernelPackage/hwmon-lm75
+  TITLE:=LM75 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM75
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm75.ko
+  AUTOLOAD:=$(call AutoProbe,lm75)
+  $(call AddDepends/hwmon,+kmod-i2c-core +PACKAGE_kmod-thermal:kmod-thermal)
+endef
+
+define KernelPackage/hwmon-lm75/description
+ Kernel module for lm75 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm75))
+
+
+define KernelPackage/hwmon-lm77
+  TITLE:=LM77 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM77
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm77.ko
+  AUTOLOAD:=$(call AutoProbe,lm77)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-lm77/description
+ Kernel module for LM77 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm77))
+
+
+define KernelPackage/hwmon-lm85
+  TITLE:=LM85 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM85
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm85.ko
+  AUTOLOAD:=$(call AutoProbe,lm85)
+  $(call AddDepends/hwmon,+kmod-i2c-core +kmod-hwmon-vid)
+endef
+
+define KernelPackage/hwmon-lm85/description
+ Kernel module for LM85 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm85))
+
+
+define KernelPackage/hwmon-lm90
+  TITLE:=LM90 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM90
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm90.ko
+  AUTOLOAD:=$(call AutoProbe,lm90)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-lm90/description
+ Kernel module for LM90 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm90))
+
+define KernelPackage/hwmon-lm92
+  TITLE:=LM92 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM92
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm92.ko
+  AUTOLOAD:=$(call AutoProbe,lm92)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-lm92/description
+ Kernel module for LM92 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm92))
+
+define KernelPackage/hwmon-lm95241
+  TITLE:=LM95241 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LM95241
+  FILES:=$(LINUX_DIR)/drivers/hwmon/lm95241.ko
+  AUTOLOAD:=$(call AutoProbe,lm95241)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-lm95241/description
+ Kernel module for LM95241 thermal monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-lm95241))
+
+define KernelPackage/hwmon-ltc4151
+  TITLE:=LTC4151 monitoring support
+  KCONFIG:=CONFIG_SENSORS_LTC4151
+  FILES:=$(LINUX_DIR)/drivers/hwmon/ltc4151.ko
+  AUTOLOAD:=$(call AutoProbe,ltc4151)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-ltc4151/description
+ Kernel module for Linear Technology LTC4151 current and voltage monitor chip
+endef
+
+$(eval $(call KernelPackage,hwmon-ltc4151))
+
+define KernelPackage/hwmon-sht21
+  TITLE:=Sensiron SHT21 and compat. monitoring support
+  KCONFIG:=CONFIG_SENSORS_SHT21
+  FILES:=$(LINUX_DIR)/drivers/hwmon/sht21.ko
+  AUTOLOAD:=$(call AutoProbe,sht21)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-sht21/description
+ Kernel module for Sensirion SHT21 and SHT25 temperature and humidity sensors chip
+endef
+
+$(eval $(call KernelPackage,hwmon-sht21))
+
+define KernelPackage/hwmon-sch5627
+  TITLE:=SMSC SCH5627 monitoring support
+  KCONFIG:=CONFIG_SENSORS_SCH5627
+  FILES:= \
+	$(LINUX_DIR)/drivers/hwmon/sch5627.ko \
+	$(LINUX_DIR)/drivers/hwmon/sch56xx-common.ko
+  AUTOLOAD:=$(call AutoProbe,sch5627)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-sch5627/description
+ SMSC SCH5627 Super I/O chips include complete hardware monitoring
+endef
+
+$(eval $(call KernelPackage,hwmon-sch5627))
+
+define KernelPackage/hwmon-pc87360
+  TITLE:=PC87360 monitoring support
+  KCONFIG:=CONFIG_SENSORS_PC87360
+  FILES:=$(LINUX_DIR)/drivers/hwmon/pc87360.ko
+  AUTOLOAD:=$(call AutoProbe,pc87360)
+  $(call AddDepends/hwmon,@TARGET_x86 +kmod-hwmon-vid)
+endef
+
+define KernelPackage/hwmon-pc87360/description
+ Kernel modules for PC87360 chips
+endef
+
+$(eval $(call KernelPackage,hwmon-pc87360))
+
+
+define KernelPackage/hwmon-w83627hf
+  TITLE:=Winbond W83627HF monitoring support
+  KCONFIG:=CONFIG_SENSORS_W83627HF
+  FILES:=$(LINUX_DIR)/drivers/hwmon/w83627hf.ko
+  AUTOLOAD:=$(call AutoLoad,50,w83627hf)
+  $(call AddDepends/hwmon,@TARGET_x86 +kmod-hwmon-vid)
+endef
+
+define KernelPackage/hwmon-w83627hf/description
+  Kernel module for the Winbond W83627HF chips.
+endef
+
+$(eval $(call KernelPackage,hwmon-w83627hf))
+
+
+define KernelPackage/hwmon-w83793
+  TITLE:=Winbond W83793G/R monitoring support
+  KCONFIG:=CONFIG_SENSORS_W83793
+  FILES:=$(LINUX_DIR)/drivers/hwmon/w83793.ko
+  AUTOLOAD:=$(call AutoProbe,w83793)
+  $(call AddDepends/hwmon,+kmod-i2c-core +kmod-hwmon-vid)
+endef
+
+define KernelPackage/hwmon-w83793/description
+  Kernel module for the Winbond W83793G and W83793R chips.
+endef
+
+$(eval $(call KernelPackage,hwmon-w83793))
+
+
+define KernelPackage/hwmon-gsc
+  TITLE:=Gateworks GSC monitoring support
+  KCONFIG:=CONFIG_SENSORS_GSC
+  FILES:=$(LINUX_DIR)/drivers/hwmon/gsc.ko
+  AUTOLOAD:=$(call AutoLoad,60,gsc)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-gsc/description
+  Kernel module for the Gateworks System Controller chips.
+endef
+
+$(eval $(call KernelPackage,hwmon-gsc))
+
+
+define KernelPackage/hwmon-tmp421
+  TITLE:=TI TMP421 and compatible monitoring support
+  KCONFIG:=CONFIG_SENSORS_TMP421
+  FILES:=$(LINUX_DIR)/drivers/hwmon/tmp421.ko
+  AUTOLOAD:=$(call AutoLoad,60,tmp421)
+  $(call AddDepends/hwmon,+kmod-i2c-core)
+endef
+
+define KernelPackage/hwmon-tmp421/description
+  Kernel module for the Texas Instruments TMP421 and compatible chips.
+endef
+
+$(eval $(call KernelPackage,hwmon-tmp421))
+
+
+define KernelPackage/hwmon-gpiofan
+  TITLE:=Generic GPIO FAN support
+  KCONFIG:=CONFIG_SENSORS_GPIO_FAN
+  FILES:=$(LINUX_DIR)/drivers/hwmon/gpio-fan.ko
+  AUTOLOAD:=$(call AutoLoad,60,gpio-fan)
+  $(call AddDepends/hwmon,+kmod-i2c-core +PACKAGE_kmod-thermal:kmod-thermal)
+endef
+
+define KernelPackage/hwmon-gpiofan/description
+  Kernel module for GPIO controlled FANs
+endef
+
+$(eval $(call KernelPackage,hwmon-gpiofan))
+
+
+define KernelPackage/hwmon-pwmfan
+  TITLE:=Generic PWM FAN support
+  KCONFIG:=CONFIG_SENSORS_PWM_FAN
+  FILES:=$(LINUX_DIR)/drivers/hwmon/pwm-fan.ko
+  AUTOLOAD:=$(call AutoLoad,60,pwm-fan)
+  $(call AddDepends/hwmon, +PACKAGE_kmod-thermal:kmod-thermal)
+endef
+
+define KernelPackage/hwmon-pwmfan/description
+  Kernel module for PWM controlled FANs
+endef
+
+$(eval $(call KernelPackage,hwmon-pwmfan))
+
+
+define KernelPackage/hwmon-k10temp
+  TITLE:=AMD Family 10h+ temperature sensor
+  KCONFIG:=CONFIG_SENSORS_K10TEMP
+  FILES:=$(LINUX_DIR)/drivers/hwmon/k10temp.ko
+  AUTOLOAD:=$(call AutoLoad,60,k10temp)
+  $(call AddDepends/hwmon,@PCI_SUPPORT @TARGET_x86)
+endef
+
+define KernelPackage/hwmon-k10temp/description
+  Thermal sensor support for AMD 10h, 11h, 12h (Llano), 14h (Brazos),
+  15h (Bulldozer/Trinity/Kaveri) and 16h (Kabini/Mullins) CPUs
+endef
+
+$(eval $(call KernelPackage,hwmon-k10temp))
diff --git a/package/kernel/linux/modules/i2c.mk b/package/kernel/linux/modules/i2c.mk
new file mode 100644
index 0000000000..e1c65d493e
--- /dev/null
+++ b/package/kernel/linux/modules/i2c.mk
@@ -0,0 +1,251 @@
+#
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+I2C_MENU:=I2C support
+
+ModuleConfVar=$(word 1,$(subst :,$(space),$(1)))
+ModuleFullPath=$(LINUX_DIR)/$(word 2,$(subst :,$(space),$(1))).ko
+ModuleKconfig=$(foreach mod,$(1),$(call ModuleConfVar,$(mod)))
+ModuleFiles=$(foreach mod,$(1),$(call ModuleFullPath,$(mod)))
+ModuleAuto=$(call AutoLoad,$(1),$(foreach mod,$(2),$(basename $(notdir $(call ModuleFullPath,$(mod))))),$(3))
+
+define i2c_defaults
+  SUBMENU:=$(I2C_MENU)
+  KCONFIG:=$(call ModuleKconfig,$(1))
+  FILES:=$(call ModuleFiles,$(1))
+  AUTOLOAD:=$(call ModuleAuto,$(2),$(1),$(3))
+endef
+
+I2C_CORE_MODULES:= \
+  CONFIG_I2C:drivers/i2c/i2c-core \
+  CONFIG_I2C_CHARDEV:drivers/i2c/i2c-dev
+
+ifeq ($(CONFIG_OF),y)
+  I2C_CORE_MODULES+=CONFIG_OF_I2C:drivers/of/of_i2c@lt3.12
+endif
+
+define KernelPackage/i2c-core
+  $(call i2c_defaults,$(I2C_CORE_MODULES),51)
+  TITLE:=I2C support
+endef
+
+define KernelPackage/i2c-core/description
+ Kernel modules for I2C support
+endef
+
+$(eval $(call KernelPackage,i2c-core))
+
+
+I2C_ALGOBIT_MODULES:= \
+  CONFIG_I2C_ALGOBIT:drivers/i2c/algos/i2c-algo-bit
+
+define KernelPackage/i2c-algo-bit
+  $(call i2c_defaults,$(I2C_ALGOBIT_MODULES),55)
+  TITLE:=I2C bit-banging interfaces
+  DEPENDS:=kmod-i2c-core
+endef
+
+define KernelPackage/i2c-algo-bit/description
+ Kernel modules for I2C bit-banging interfaces
+endef
+
+$(eval $(call KernelPackage,i2c-algo-bit))
+
+
+I2C_ALGOPCA_MODULES:= \
+  CONFIG_I2C_ALGOPCA:drivers/i2c/algos/i2c-algo-pca
+
+define KernelPackage/i2c-algo-pca
+  $(call i2c_defaults,$(I2C_ALGOPCA_MODULES),55)
+  TITLE:=I2C PCA 9564 interfaces
+  DEPENDS:=kmod-i2c-core
+endef
+
+define KernelPackage/i2c-algo-pca/description
+ Kernel modules for I2C PCA 9564 interfaces
+endef
+
+$(eval $(call KernelPackage,i2c-algo-pca))
+
+
+I2C_ALGOPCF_MODULES:= \
+  CONFIG_I2C_ALGOPCF:drivers/i2c/algos/i2c-algo-pcf
+
+define KernelPackage/i2c-algo-pcf
+  $(call i2c_defaults,$(I2C_ALGOPCF_MODULES),55)
+  TITLE:=I2C PCF 8584 interfaces
+  DEPENDS:=kmod-i2c-core
+endef
+
+define KernelPackage/i2c-algo-pcf/description
+ Kernel modules for I2C PCF 8584 interfaces
+endef
+
+$(eval $(call KernelPackage,i2c-algo-pcf))
+
+
+I2C_GPIO_MODULES:= \
+  CONFIG_I2C_GPIO:drivers/i2c/busses/i2c-gpio
+
+define KernelPackage/i2c-gpio
+  $(call i2c_defaults,$(I2C_GPIO_MODULES),59)
+  TITLE:=GPIO-based bitbanging I2C
+  DEPENDS:=@GPIO_SUPPORT +kmod-i2c-algo-bit
+endef
+
+define KernelPackage/i2c-gpio/description
+ Kernel modules for a very simple bitbanging I2C driver utilizing the
+ arch-neutral GPIO API to control the SCL and SDA lines.
+endef
+
+$(eval $(call KernelPackage,i2c-gpio))
+
+I2C_MPC_MODULES:=\
+  CONFIG_I2C_MPC:drivers/i2c/busses/i2c-mpc
+
+define KernelPackage/i2c-mpc
+  $(call i2c_defaults,$(I2C_MPC_MODULES),59)
+  TITLE:=MPC I2C accessors
+  DEPENDS:=@TARGET_mpc52xx||TARGET_mpc83xx||TARGET_mpc85xx +kmod-i2c-core
+endef
+
+define KernelPackage/i2c-mpc/description
+ Kernel module for Freescale MPC52xx MPC83xx MPC85xx I2C accessors
+endef
+
+$(eval $(call KernelPackage,i2c-mpc))
+
+I2C_IBM_IIC_MODULES:=\
+  CONFIG_I2C_IBM_IIC:drivers/i2c/busses/i2c-ibm_iic
+
+define KernelPackage/i2c-ibm-iic
+  $(call i2c_defaults,$(OF_I2C_MODULES),59)
+  TITLE:=IBM PPC 4xx on-chip I2C interface support
+  DEPENDS:=@TARGET_ppc40x||TARGET_ppc4xx +kmod-i2c-core
+endef
+
+define KernelPackage/i2c-ibm-iic/description
+ Kernel module for IIC peripheral found on embedded IBM PPC4xx based systems
+endef
+
+$(eval $(call KernelPackage,i2c-ibm-iic))
+
+I2C_MV64XXX_MODULES:=\
+  CONFIG_I2C_MV64XXX:drivers/i2c/busses/i2c-mv64xxx
+
+define KernelPackage/i2c-mv64xxx
+  $(call i2c_defaults,$(I2C_MV64XXX_MODULES),59)
+  TITLE:=Orion Platform I2C interface support
+  DEPENDS:=@TARGET_kirkwood||TARGET_orion +kmod-i2c-core
+endef
+
+define KernelPackage/i2c-mv64xxx/description
+ Kernel module for I2C interface on the Kirkwood, Orion and Armada XP/370
+ family processors
+endef
+
+$(eval $(call KernelPackage,i2c-mv64xxx))
+
+
+I2C_TINY_USB_MODULES:= \
+  CONFIG_I2C_TINY_USB:drivers/i2c/busses/i2c-tiny-usb
+
+define KernelPackage/i2c-tiny-usb
+  $(call i2c_defaults,$(I2C_TINY_USB_MODULES),59)
+  TITLE:=I2C Tiny USB adaptor
+  DEPENDS:=@USB_SUPPORT kmod-i2c-core +kmod-usb-core
+endef
+
+define KernelPackage/i2c-tiny-usb/description
+ Kernel module for the I2C Tiny USB adaptor developed
+ by Till Harbaum (http://www.harbaum.org/till/i2c_tiny_usb)
+endef
+
+$(eval $(call KernelPackage,i2c-tiny-usb))
+
+
+I2C_PIIX4_MODULES:= \
+  CONFIG_I2C_PIIX4:drivers/i2c/busses/i2c-piix4
+
+define KernelPackage/i2c-piix4
+  $(call i2c_defaults,$(I2C_PIIX4_MODULES),59)
+  TITLE:=Intel PIIX4 and compatible I2C interfaces
+  DEPENDS:=@PCI_SUPPORT @(x86||x86_64) kmod-i2c-core
+endef
+
+define KernelPackage/i2c-piix4/description
+ Support for the Intel PIIX4 family of mainboard I2C interfaces,
+ specifically Intel PIIX4, Intel 440MX, ATI IXP200, ATI IXP300,
+ ATI IXP400, ATI SB600, ATI SB700/SP5100, ATI SB800, AMD Hudson-2,
+ AMD ML, AMD CZ, Serverworks OSB4, Serverworks CSB5,
+ Serverworks CSB6, Serverworks HT-1000, Serverworks HT-1100 and
+ SMSC Victory66.
+endef
+
+$(eval $(call KernelPackage,i2c-piix4))
+
+
+I2C_MUX_MODULES:= \
+  CONFIG_I2C_MUX:drivers/i2c/i2c-mux
+
+define KernelPackage/i2c-mux
+  $(call i2c_defaults,$(I2C_MUX_MODULES),51)
+  TITLE:=I2C bus multiplexing support
+  DEPENDS:=kmod-i2c-core
+endef
+
+define KernelPackage/i2c-mux/description
+ Kernel modules for I2C bus multiplexing support
+endef
+
+$(eval $(call KernelPackage,i2c-mux))
+
+I2C_MUX_GPIO_MODULES:= \
+  CONFIG_I2C_MUX_GPIO:drivers/i2c/muxes/i2c-mux-gpio
+
+define KernelPackage/i2c-mux-gpio
+  $(call i2c_defaults,$(I2C_MUX_GPIO_MODULES),51)
+  TITLE:=GPIO-based I2C mux/switches
+  DEPENDS:=kmod-i2c-mux
+endef
+
+define KernelPackage/i2c-mux-gpio/description
+ Kernel modules for GENERIC_GPIO I2C bus mux/switching devices
+endef
+
+$(eval $(call KernelPackage,i2c-mux-gpio))
+
+I2C_MUX_PCA954x_MODULES:= \
+  CONFIG_I2C_MUX_PCA954x:drivers/i2c/muxes/i2c-mux-pca954x
+
+define KernelPackage/i2c-mux-pca954x
+  $(call i2c_defaults,$(I2C_MUX_PCA954x_MODULES),51)
+  TITLE:=Philips PCA954x I2C mux/switches
+  DEPENDS:=kmod-i2c-mux
+endef
+
+define KernelPackage/i2c-mux-pca954x/description
+ Kernel modules for PCA954x I2C bus mux/switching devices
+endef
+
+$(eval $(call KernelPackage,i2c-mux-pca954x))
+
+
+I2C_MUX_PCA9541_MODULES:= \
+  CONFIG_I2C_MUX_PCA9541:drivers/i2c/muxes/i2c-mux-pca9541
+
+define KernelPackage/i2c-mux-pca9541
+  $(call i2c_defaults,$(I2C_MUX_PCA9541_MODULES),51)
+  TITLE:=Philips PCA9541 I2C mux/switches
+  DEPENDS:=kmod-i2c-mux
+endef
+
+define KernelPackage/i2c-mux-pca9541/description
+ Kernel modules for PCA9541 I2C bus mux/switching devices
+endef
+
+$(eval $(call KernelPackage,i2c-mux-pca9541))
diff --git a/package/kernel/linux/modules/input.mk b/package/kernel/linux/modules/input.mk
new file mode 100644
index 0000000000..e410fe8d0c
--- /dev/null
+++ b/package/kernel/linux/modules/input.mk
@@ -0,0 +1,209 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+INPUT_MODULES_MENU:=Input modules
+
+define KernelPackage/hid
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=HID Devices
+  DEPENDS:=+kmod-input-core +kmod-input-evdev
+  KCONFIG:=CONFIG_HID CONFIG_HIDRAW=y CONFIG_HID_BATTERY_STRENGTH=y
+  FILES:=$(LINUX_DIR)/drivers/hid/hid.ko
+  AUTOLOAD:=$(call AutoLoad,61,hid)
+endef
+
+define KernelPackage/hid/description
+ Kernel modules for HID devices
+endef
+
+$(eval $(call KernelPackage,hid))
+
+define KernelPackage/hid-generic
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Generic HID device support
+  DEPENDS:=+kmod-hid
+  KCONFIG:=CONFIG_HID_GENERIC
+  FILES:=$(LINUX_DIR)/drivers/hid/hid-generic.ko
+  AUTOLOAD:=$(call AutoProbe,hid-generic)
+endef
+
+define KernelPackage/hid/description
+ Kernel modules for generic HID device (e.g. keyboards and mice) support
+endef
+
+$(eval $(call KernelPackage,hid-generic))
+
+define KernelPackage/input-core
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Input device core
+  KCONFIG:=CONFIG_INPUT
+  FILES:=$(LINUX_DIR)/drivers/input/input-core.ko
+endef
+
+define KernelPackage/input-core/description
+ Kernel modules for support of input device
+endef
+
+$(eval $(call KernelPackage,input-core))
+
+
+define KernelPackage/input-evdev
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Input event device
+  DEPENDS:=+kmod-input-core
+  KCONFIG:=CONFIG_INPUT_EVDEV
+  FILES:=$(LINUX_DIR)/drivers/input/evdev.ko
+  AUTOLOAD:=$(call AutoLoad,60,evdev)
+endef
+
+define KernelPackage/input-evdev/description
+ Kernel modules for support of input device events
+endef
+
+$(eval $(call KernelPackage,input-evdev))
+
+
+define KernelPackage/input-gpio-keys
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=GPIO key support
+  DEPENDS:= @GPIO_SUPPORT +kmod-input-core
+  KCONFIG:= \
+	CONFIG_KEYBOARD_GPIO \
+	CONFIG_INPUT_KEYBOARD=y
+  FILES:=$(LINUX_DIR)/drivers/input/keyboard/gpio_keys.ko
+  AUTOLOAD:=$(call AutoProbe,gpio_keys,1)
+endef
+
+define KernelPackage/input-gpio-keys/description
+ This driver implements support for buttons connected
+ to GPIO pins of various CPUs (and some other chips).
+
+ See also gpio-button-hotplug which is an alternative, lower overhead
+ implementation that generates uevents instead of kernel input events.
+endef
+
+$(eval $(call KernelPackage,input-gpio-keys))
+
+
+define KernelPackage/input-gpio-keys-polled
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Polled GPIO key support
+  DEPENDS:=@GPIO_SUPPORT +kmod-input-polldev
+  KCONFIG:= \
+	CONFIG_KEYBOARD_GPIO_POLLED \
+	CONFIG_INPUT_KEYBOARD=y
+  FILES:=$(LINUX_DIR)/drivers/input/keyboard/gpio_keys_polled.ko
+  AUTOLOAD:=$(call AutoProbe,gpio_keys_polled,1)
+endef
+
+define KernelPackage/input-gpio-keys-polled/description
+ Kernel module for support polled GPIO keys input device
+
+ See also gpio-button-hotplug which is an alternative, lower overhead
+ implementation that generates uevents instead of kernel input events.
+endef
+
+$(eval $(call KernelPackage,input-gpio-keys-polled))
+
+
+define KernelPackage/input-gpio-encoder
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=GPIO rotary encoder
+  DEPENDS:=@GPIO_SUPPORT +kmod-input-core
+  KCONFIG:=CONFIG_INPUT_GPIO_ROTARY_ENCODER
+  FILES:=$(LINUX_DIR)/drivers/input/misc/rotary_encoder.ko
+  AUTOLOAD:=$(call AutoProbe,rotary_encoder)
+endef
+
+define KernelPackage/gpio-encoder/description
+ Kernel module to use rotary encoders connected to GPIO pins
+endef
+
+$(eval $(call KernelPackage,input-gpio-encoder))
+
+
+define KernelPackage/input-joydev
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Joystick device support
+  DEPENDS:=+kmod-input-core
+  KCONFIG:=CONFIG_INPUT_JOYDEV
+  FILES:=$(LINUX_DIR)/drivers/input/joydev.ko
+  AUTOLOAD:=$(call AutoProbe,joydev)
+endef
+
+define KernelPackage/input-joydev/description
+ Kernel module for joystick support
+endef
+
+$(eval $(call KernelPackage,input-joydev))
+
+
+define KernelPackage/input-polldev
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Polled Input device support
+  DEPENDS:=+kmod-input-core
+  KCONFIG:=CONFIG_INPUT_POLLDEV
+  FILES:=$(LINUX_DIR)/drivers/input/input-polldev.ko
+endef
+
+define KernelPackage/input-polldev/description
+ Kernel module for support of polled input devices
+endef
+
+$(eval $(call KernelPackage,input-polldev))
+
+
+define KernelPackage/input-matrixkmap
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=Input matrix devices support
+  DEPENDS:=+kmod-input-core
+  KCONFIG:=CONFIG_INPUT_MATRIXKMAP
+  FILES:=$(LINUX_DIR)/drivers/input/matrix-keymap.ko
+  AUTOLOAD:=$(call AutoProbe,matrix-keymap)
+endef
+
+define KernelPackage/input-matrix/description
+ Kernel module support for input matrix devices
+endef
+
+$(eval $(call KernelPackage,input-matrixkmap))
+
+
+define KernelPackage/keyboard-imx
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=IMX keypad support
+  DEPENDS:=@(TARGET_mxs||TARGET_imx6) +kmod-input-matrixkmap
+  KCONFIG:= \
+	CONFIG_KEYBOARD_IMX \
+	CONFIG_INPUT_KEYBOARD=y
+  FILES:=$(LINUX_DIR)/drivers/input/keyboard/imx_keypad.ko
+  AUTOLOAD:=$(call AutoProbe,imx_keypad)
+endef
+
+define KernelPackage/keyboard-imx/description
+ Enable support for IMX keypad port.
+endef
+
+$(eval $(call KernelPackage,keyboard-imx))
+
+
+define KernelPackage/input-uinput
+  SUBMENU:=$(INPUT_MODULES_MENU)
+  TITLE:=user input module
+  DEPENDS:=+kmod-input-core
+  KCONFIG:= \
+	CONFIG_INPUT_MISC=y \
+	CONFIG_INPUT_UINPUT
+  FILES:=$(LINUX_DIR)/drivers/input/misc/uinput.ko
+  AUTOLOAD:=$(call AutoProbe,uinput)
+endef
+
+define KernelPackage/input-uinput/description
+  user input modules needed for bluez
+endef
+
+$(eval $(call KernelPackage,input-uinput))
diff --git a/package/kernel/linux/modules/leds.mk b/package/kernel/linux/modules/leds.mk
new file mode 100644
index 0000000000..51002fb3df
--- /dev/null
+++ b/package/kernel/linux/modules/leds.mk
@@ -0,0 +1,147 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+LEDS_MENU:=LED modules
+
+define KernelPackage/leds-gpio
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=GPIO LED support
+  DEPENDS:= @GPIO_SUPPORT
+  KCONFIG:=CONFIG_LEDS_GPIO
+  FILES:=$(LINUX_DIR)/drivers/leds/leds-gpio.ko
+  AUTOLOAD:=$(call AutoLoad,60,leds-gpio,1)
+endef
+
+define KernelPackage/leds-gpio/description
+ Kernel module for LEDs on GPIO lines
+endef
+
+$(eval $(call KernelPackage,leds-gpio))
+
+LED_TRIGGER_DIR=$(LINUX_DIR)/drivers/leds/trigger
+
+define KernelPackage/ledtrig-heartbeat
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED Heartbeat Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_HEARTBEAT
+  FILES:=$(LED_TRIGGER_DIR)/ledtrig-heartbeat.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-heartbeat)
+endef
+
+define KernelPackage/ledtrig-gpio/description
+ Kernel module that allows LEDs to blink like heart beat
+endef
+
+$(eval $(call KernelPackage,ledtrig-heartbeat))
+
+
+define KernelPackage/ledtrig-gpio
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED GPIO Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_GPIO
+  FILES:=$(LED_TRIGGER_DIR)/ledtrig-gpio.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-gpio)
+endef
+
+define KernelPackage/ledtrig-gpio/description
+ Kernel module that allows LEDs to be controlled by gpio events
+endef
+
+$(eval $(call KernelPackage,ledtrig-gpio))
+
+
+define KernelPackage/ledtrig-netdev
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED NETDEV Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_NETDEV
+  FILES:=$(LINUX_DIR)/drivers/leds/ledtrig-netdev.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-netdev)
+endef
+
+define KernelPackage/ledtrig-netdev/description
+ Kernel module to drive LEDs based on network activity
+endef
+
+$(eval $(call KernelPackage,ledtrig-netdev))
+
+
+define KernelPackage/ledtrig-default-on
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED Default ON Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_DEFAULT_ON
+  FILES:=$(LED_TRIGGER_DIR)/ledtrig-default-on.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-default-on,1)
+endef
+
+define KernelPackage/ledtrig-default-on/description
+ Kernel module that allows LEDs to be initialised in the ON state
+endef
+
+$(eval $(call KernelPackage,ledtrig-default-on))
+
+
+define KernelPackage/ledtrig-timer
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED Timer Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_TIMER
+  FILES:=$(LED_TRIGGER_DIR)/ledtrig-timer.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-timer,1)
+endef
+
+define KernelPackage/ledtrig-timer/description
+ Kernel module that allows LEDs to be controlled by a programmable timer
+ via sysfs
+endef
+
+$(eval $(call KernelPackage,ledtrig-timer))
+
+
+define KernelPackage/ledtrig-transient
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED Transient Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_TRANSIENT
+  FILES:=$(LED_TRIGGER_DIR)/ledtrig-transient.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-transient,1)
+endef
+
+define KernelPackage/ledtrig-transient/description
+ Kernel module that allows LEDs one time activation of a transient state.
+endef
+
+$(eval $(call KernelPackage,ledtrig-transient))
+
+
+define KernelPackage/ledtrig-oneshot
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=LED One-Shot Trigger
+  KCONFIG:=CONFIG_LEDS_TRIGGER_ONESHOT
+  FILES:=$(LED_TRIGGER_DIR)/ledtrig-oneshot.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-oneshot)
+endef
+
+define KernelPackage/ledtrig-oneshot/description
+ Kernel module that allows LEDs to be triggered by sporadic events in
+ one-shot pulses
+endef
+
+$(eval $(call KernelPackage,ledtrig-oneshot))
+
+
+define KernelPackage/leds-pca963x
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=PCA963x LED support
+  DEPENDS:=+kmod-i2c-core
+  KCONFIG:=CONFIG_LEDS_PCA963X
+  FILES:=$(LINUX_DIR)/drivers/leds/leds-pca963x.ko
+  AUTOLOAD:=$(call AutoLoad,60,leds-pca963x,1)
+endef
+
+define KernelPackage/leds-pca963x/description
+ Driver for the NXP PCA963x I2C LED controllers.
+endef
+
+$(eval $(call KernelPackage,leds-pca963x))
diff --git a/package/kernel/linux/modules/lib.mk b/package/kernel/linux/modules/lib.mk
new file mode 100644
index 0000000000..c5148ce487
--- /dev/null
+++ b/package/kernel/linux/modules/lib.mk
@@ -0,0 +1,226 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+LIB_MENU:=Libraries
+
+define KernelPackage/lib-crc-ccitt
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=CRC-CCITT support
+  KCONFIG:=CONFIG_CRC_CCITT
+  FILES:=$(LINUX_DIR)/lib/crc-ccitt.ko
+  AUTOLOAD:=$(call AutoProbe,crc-ccitt)
+endef
+
+define KernelPackage/lib-crc-ccitt/description
+ Kernel module for CRC-CCITT support
+endef
+
+$(eval $(call KernelPackage,lib-crc-ccitt))
+
+
+define KernelPackage/lib-crc-itu-t
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=CRC ITU-T V.41 support
+  KCONFIG:=CONFIG_CRC_ITU_T
+  FILES:=$(LINUX_DIR)/lib/crc-itu-t.ko
+  AUTOLOAD:=$(call AutoProbe,crc-itu-t)
+endef
+
+define KernelPackage/lib-crc-itu-t/description
+ Kernel module for CRC ITU-T V.41 support
+endef
+
+$(eval $(call KernelPackage,lib-crc-itu-t))
+
+
+define KernelPackage/lib-crc7
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=CRC7 support
+  KCONFIG:=CONFIG_CRC7
+  FILES:=$(LINUX_DIR)/lib/crc7.ko
+  AUTOLOAD:=$(call AutoProbe,crc7)
+endef
+
+define KernelPackage/lib-crc7/description
+ Kernel module for CRC7 support
+endef
+
+$(eval $(call KernelPackage,lib-crc7))
+
+
+define KernelPackage/lib-crc8
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=CRC8 support
+  KCONFIG:=CONFIG_CRC8
+  FILES:=$(LINUX_DIR)/lib/crc8.ko
+  AUTOLOAD:=$(call AutoProbe,crc8)
+endef
+
+define KernelPackage/lib-crc8/description
+ Kernel module for CRC8 support
+endef
+
+$(eval $(call KernelPackage,lib-crc8))
+
+
+define KernelPackage/lib-crc16
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=CRC16 support
+  KCONFIG:=CONFIG_CRC16
+  FILES:=$(LINUX_DIR)/lib/crc16.ko
+  AUTOLOAD:=$(call AutoLoad,20,crc16,1)
+endef
+
+define KernelPackage/lib-crc16/description
+ Kernel module for CRC16 support
+endef
+
+$(eval $(call KernelPackage,lib-crc16))
+
+
+define KernelPackage/lib-crc32c
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=CRC32 support
+  KCONFIG:=CONFIG_LIBCRC32C
+  DEPENDS:=+kmod-crypto-crc32c
+  FILES:=$(LINUX_DIR)/lib/libcrc32c.ko
+  AUTOLOAD:=$(call AutoProbe,libcrc32c)
+endef
+
+define KernelPackage/lib-crc32c/description
+ Kernel module for CRC32 support
+endef
+
+$(eval $(call KernelPackage,lib-crc32c))
+
+
+define KernelPackage/lib-lzo
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=LZO support
+  KCONFIG:= \
+	CONFIG_LZO_COMPRESS \
+	CONFIG_LZO_DECOMPRESS
+  HIDDEN:=1
+  FILES:= \
+	$(LINUX_DIR)/lib/lzo/lzo_compress.ko \
+	$(LINUX_DIR)/lib/lzo/lzo_decompress.ko
+  AUTOLOAD:=$(call AutoProbe,lzo_compress lzo_decompress)
+endef
+
+define KernelPackage/lib-lzo/description
+ Kernel module for LZO compression/decompression support
+endef
+
+$(eval $(call KernelPackage,lib-lzo))
+
+
+define KernelPackage/lib-lz4
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=LZ4 support
+  HIDDEN:=1
+  KCONFIG:= \
+	CONFIG_LZ4_COMPRESS \
+	CONFIG_LZ4_DECOMPRESS
+  FILES:= \
+	$(LINUX_DIR)/lib/lz4/lz4_compress.ko \
+	$(LINUX_DIR)/lib/lz4/lz4_decompress.ko
+  AUTOLOAD:=$(call AutoProbe,lz4_compress lz4_decompress)
+endef
+
+define KernelPackage/lib-lz4/description
+ Kernel module for LZ4 compression/decompression support
+endef
+
+$(eval $(call KernelPackage,lib-lz4))
+
+
+define KernelPackage/lib-raid6
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=RAID6 algorithm support
+  HIDDEN:=1
+  KCONFIG:=CONFIG_RAID6_PQ
+  FILES:=$(LINUX_DIR)/lib/raid6/raid6_pq.ko
+  AUTOLOAD:=$(call AutoProbe,raid6_pq)
+endef
+
+define KernelPackage/lib-raid6/description
+ Kernel module for RAID6 algorithms
+endef
+
+$(eval $(call KernelPackage,lib-raid6))
+
+
+define KernelPackage/lib-xor
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=XOR blocks algorithm support
+  HIDDEN:=1
+  KCONFIG:=CONFIG_XOR_BLOCKS
+ifneq ($(wildcard $(LINUX_DIR)/arch/arm/lib/xor-neon.ko),)
+  FILES:= \
+    $(LINUX_DIR)/crypto/xor.ko \
+    $(LINUX_DIR)/arch/arm/lib/xor-neon.ko
+  AUTOLOAD:=$(call AutoProbe,xor-neon xor)
+else
+  FILES:=$(LINUX_DIR)/crypto/xor.ko
+  AUTOLOAD:=$(call AutoProbe,xor)
+endif
+endef
+
+define KernelPackage/lib-xor/description
+ Kernel module for XOR blocks algorithms
+endef
+
+$(eval $(call KernelPackage,lib-xor))
+
+
+define KernelPackage/lib-textsearch
+SUBMENU:=$(LIB_MENU)
+  TITLE:=Textsearch support
+  KCONFIG:= \
+    CONFIG_TEXTSEARCH=y \
+    CONFIG_TEXTSEARCH_KMP \
+    CONFIG_TEXTSEARCH_BM \
+    CONFIG_TEXTSEARCH_FSM
+  FILES:= \
+    $(LINUX_DIR)/lib/ts_kmp.ko \
+    $(LINUX_DIR)/lib/ts_bm.ko \
+    $(LINUX_DIR)/lib/ts_fsm.ko
+  AUTOLOAD:=$(call AutoProbe,ts_kmp ts_bm ts_fsm)
+endef
+
+$(eval $(call KernelPackage,lib-textsearch))
+
+
+define KernelPackage/lib-zlib
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=Zlib support
+  HIDDEN:=1
+  KCONFIG:= \
+    CONFIG_ZLIB_DEFLATE \
+    CONFIG_ZLIB_INFLATE
+  FILES:= \
+    $(LINUX_DIR)/lib/zlib_deflate/zlib_deflate.ko \
+    $(LINUX_DIR)/lib/zlib_inflate/zlib_inflate.ko
+  AUTOLOAD:=$(call AutoProbe,zlib_deflate zlib_inflate)
+endef
+
+$(eval $(call KernelPackage,lib-zlib))
+
+
+define KernelPackage/lib-cordic
+  SUBMENU:=$(LIB_MENU)
+  TITLE:=Cordic function support
+  KCONFIG:=CONFIG_CORDIC
+  FILES:=$(LINUX_DIR)/lib/cordic.ko
+  AUTOLOAD:=$(call AutoProbe,cordic)
+endef
+
+define KernelPackage/lib-cordic/description
+ Kernel module for Cordic function support
+endef
+
+$(eval $(call KernelPackage,lib-cordic))
diff --git a/package/kernel/linux/modules/netdevices.mk b/package/kernel/linux/modules/netdevices.mk
new file mode 100644
index 0000000000..83f3f910e2
--- /dev/null
+++ b/package/kernel/linux/modules/netdevices.mk
@@ -0,0 +1,865 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+NETWORK_DEVICES_MENU:=Network Devices
+
+define KernelPackage/sis190
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=SiS 190 Fast/Gigabit Ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_SIS190
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/sis/sis190.ko
+  AUTOLOAD:=$(call AutoProbe,sis190)
+endef
+
+$(eval $(call KernelPackage,sis190))
+
+
+define KernelPackage/skge
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=SysKonnect Yukon support
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_SKGE \
+	CONFIG_SKGE_DEBUG=n \
+	CONFIG_SKGE_GENESIS=n
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/marvell/skge.ko
+  AUTOLOAD:=$(call AutoProbe,skge)
+endef
+
+$(eval $(call KernelPackage,skge))
+
+
+define KernelPackage/atl2
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Atheros L2 Fast Ethernet support
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_ATL2
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/atlx/atl2.ko
+  AUTOLOAD:=$(call AutoProbe,atl2)
+endef
+
+$(eval $(call KernelPackage,atl2))
+
+
+define KernelPackage/atl1
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Atheros L1 Gigabit Ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_ATL1
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/atlx/atl1.ko
+  AUTOLOAD:=$(call AutoProbe,atl1)
+endef
+
+$(eval $(call KernelPackage,atl1))
+
+
+define KernelPackage/atl1c
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Atheros L1C
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_ATL1C
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/atl1c/atl1c.ko
+  AUTOLOAD:=$(call AutoProbe,atl1c)
+endef
+
+$(eval $(call KernelPackage,atl1c))
+
+
+define KernelPackage/atl1e
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Atheros L1E
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_ATL1E
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/atheros/atl1e/atl1e.ko
+  AUTOLOAD:=$(call AutoProbe,atl1e)
+endef
+
+$(eval $(call KernelPackage,atl1e))
+
+
+define KernelPackage/libphy
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=PHY library
+  KCONFIG:=CONFIG_PHYLIB
+  FILES:=$(LINUX_DIR)/drivers/net/phy/libphy.ko
+  AUTOLOAD:=$(call AutoLoad,15,libphy,1)
+endef
+
+define KernelPackage/libphy/description
+ PHY library
+endef
+
+$(eval $(call KernelPackage,libphy))
+
+define KernelPackage/mii
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=MII library
+  KCONFIG:=CONFIG_MII
+  FILES:=$(LINUX_DIR)/drivers/net/mii.ko
+  AUTOLOAD:=$(call AutoLoad,15,mii,1)
+endef
+
+define KernelPackage/mii/description
+  MII library
+endef
+
+$(eval $(call KernelPackage,mii))
+
+
+define KernelPackage/et131x
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Agere ET131x Gigabit Ethernet driver
+  URL:=http://sourceforge.net/projects/et131x
+  FILES:= \
+	$(LINUX_DIR)/drivers/net/ethernet/agere/et131x.ko
+  KCONFIG:= \
+	CONFIG_ET131X \
+	CONFIG_ET131X_DEBUG=n
+  DEPENDS:=@PCI_SUPPORT +kmod-libphy
+  AUTOLOAD:=$(call AutoProbe,et131x)
+endef
+
+define KernelPackage/et131x/description
+ This package contains the et131x kernel module
+endef
+
+$(eval $(call KernelPackage,et131x))
+
+
+define KernelPackage/gw16083
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Gateworks Ventana Ethernet Expansion Mezzanine driver
+  URL:=http://www.gateworks.com
+  FILES:=$(LINUX_DIR)/drivers/net/phy/gw16083.ko
+  KCONFIG:=CONFIG_GATEWORKS_GW16083
+  DEPENDS:=@TARGET_imx6 @PCI_SUPPORT +kmod-libphy +kmod-igb
+  AUTOLOAD:=$(call AutoLoad,36,gw16083)
+endef
+
+define KernelPackage/gw16083/description
+ This package contains the gw16083 kernel module for supporting the Gateworks
+ Ventana Ethernet Expansion Mezzanine.
+endef
+
+$(eval $(call KernelPackage,gw16083))
+
+
+define KernelPackage/phylib-broadcom
+   SUBMENU:=$(NETWORK_DEVICES_MENU)
+   TITLE:=Broadcom Ethernet PHY library
+   KCONFIG:=CONFIG_BCM_NET_PHYLIB
+   HIDDEN:=1
+   DEPENDS:=+kmod-libphy
+   FILES:=$(LINUX_DIR)/drivers/net/phy/bcm-phy-lib.ko
+   AUTOLOAD:=$(call AutoLoad,17,bcm-phy-lib)
+endef
+
+$(eval $(call KernelPackage,phylib-broadcom))
+
+
+define KernelPackage/phy-broadcom
+   SUBMENU:=$(NETWORK_DEVICES_MENU)
+   TITLE:=Broadcom Ethernet PHY driver
+   KCONFIG:=CONFIG_BROADCOM_PHY
+   DEPENDS:=+kmod-libphy +kmod-phylib-broadcom
+   FILES:=$(LINUX_DIR)/drivers/net/phy/broadcom.ko
+   AUTOLOAD:=$(call AutoLoad,18,broadcom)
+endef
+
+define KernelPackage/phy-broadcom/description
+   Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481,
+   BCM5482 and BCM57780 PHYs.
+endef
+
+$(eval $(call KernelPackage,phy-broadcom))
+
+
+define KernelPackage/swconfig
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=switch configuration API
+  DEPENDS:=+kmod-libphy
+  KCONFIG:=CONFIG_SWCONFIG
+  FILES:=$(LINUX_DIR)/drivers/net/phy/swconfig.ko
+  AUTOLOAD:=$(call AutoLoad,41,swconfig)
+endef
+
+define KernelPackage/swconfig/description
+ Switch configuration API module
+endef
+
+$(eval $(call KernelPackage,swconfig))
+
+define KernelPackage/switch-mvsw61xx
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Marvell 88E61xx switch support
+  DEPENDS:=+kmod-swconfig
+  KCONFIG:=CONFIG_MVSW61XX_PHY
+  FILES:=$(LINUX_DIR)/drivers/net/phy/mvsw61xx.ko
+  AUTOLOAD:=$(call AutoLoad,42,mvsw61xx)
+endef
+
+define KernelPackage/switch-mvsw61xx/description
+ Marvell 88E61xx switch support
+endef
+
+$(eval $(call KernelPackage,switch-mvsw61xx))
+
+define KernelPackage/switch-ip17xx
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=IC+ IP17XX switch support
+  DEPENDS:=+kmod-swconfig
+  KCONFIG:=CONFIG_IP17XX_PHY
+  FILES:=$(LINUX_DIR)/drivers/net/phy/ip17xx.ko
+  AUTOLOAD:=$(call AutoLoad,42,ip17xx)
+endef
+
+define KernelPackage/switch-ip17xx/description
+ IC+ IP175C/IP178C switch support
+endef
+
+$(eval $(call KernelPackage,switch-ip17xx))
+
+
+define KernelPackage/switch-rtl8366-smi
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Realtek RTL8366 SMI switch interface support
+  DEPENDS:=@GPIO_SUPPORT +kmod-swconfig
+  KCONFIG:=CONFIG_RTL8366_SMI
+  FILES:=$(LINUX_DIR)/drivers/net/phy/rtl8366_smi.ko
+  AUTOLOAD:=$(call AutoLoad,42,rtl8366_smi)
+endef
+
+define KernelPackage/switch-rtl8366_smi/description
+  Realtek RTL8366 series SMI switch interface support
+endef
+
+$(eval $(call KernelPackage,switch-rtl8366-smi))
+
+
+define KernelPackage/switch-rtl8366rb
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Realtek RTL8366RB switch support
+  DEPENDS:=+kmod-switch-rtl8366-smi
+  KCONFIG:=CONFIG_RTL8366RB_PHY
+  FILES:=$(LINUX_DIR)/drivers/net/phy/rtl8366rb.ko
+  AUTOLOAD:=$(call AutoLoad,43,rtl8366rb)
+endef
+
+define KernelPackage/switch-rtl8366rb/description
+ Realtek RTL8366RB switch support
+endef
+
+$(eval $(call KernelPackage,switch-rtl8366rb))
+
+
+define KernelPackage/switch-rtl8366s
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Realtek RTL8366S switch support
+  DEPENDS:=+kmod-switch-rtl8366-smi
+  KCONFIG:=CONFIG_RTL8366S_PHY
+  FILES:=$(LINUX_DIR)/drivers/net/phy/rtl8366s.ko
+  AUTOLOAD:=$(call AutoLoad,43,rtl8366s)
+endef
+
+define KernelPackage/switch-rtl8366s/description
+ Realtek RTL8366S switch support
+endef
+
+$(eval $(call KernelPackage,switch-rtl8366s))
+
+
+define KernelPackage/switch-rtl8367b
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Realtek RTL8367R/B switch support
+  DEPENDS:=+kmod-switch-rtl8366-smi
+  KCONFIG:=CONFIG_RTL8367B_PHY
+  FILES:=$(LINUX_DIR)/drivers/net/phy/rtl8367b.ko
+  AUTOLOAD:=$(call AutoLoad,43,rtl8367b)
+endef
+
+define KernelPackage/switch-rtl8367b/description
+ Realtek RTL8367R/B switch support
+endef
+
+$(eval $(call KernelPackage,switch-rtl8367b))
+
+
+define KernelPackage/natsemi
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=National Semiconductor DP8381x series
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_NATSEMI
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/natsemi/natsemi.ko
+  AUTOLOAD:=$(call AutoLoad,20,natsemi)
+endef
+
+define KernelPackage/natsemi/description
+ Kernel modules for National Semiconductor DP8381x series PCI Ethernet
+ adapters.
+endef
+
+$(eval $(call KernelPackage,natsemi))
+
+
+define KernelPackage/r6040
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=RDC Fast-Ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-libphy
+  KCONFIG:=CONFIG_R6040 \
+		CONFIG_R6040_NAPI=y
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/rdc/r6040.ko
+  AUTOLOAD:=$(call AutoProbe,r6040)
+endef
+
+define KernelPackage/r6040/description
+ Kernel modules for RDC Fast-Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,r6040))
+
+
+define KernelPackage/sis900
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=SiS 900 Ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_SIS900
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/sis/sis900.ko
+  AUTOLOAD:=$(call AutoProbe,sis900)
+endef
+
+define KernelPackage/sis900/description
+ Kernel modules for Sis 900 Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,sis900))
+
+
+define KernelPackage/sky2
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=SysKonnect Yukon2 support
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_SKY2
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/marvell/sky2.ko
+  AUTOLOAD:=$(call AutoProbe,sky2)
+endef
+
+define KernelPackage/sky2/description
+  This driver supports Gigabit Ethernet adapters based on the
+  Marvell Yukon 2 chipset:
+  Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
+  88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
+
+  There is companion driver for the older Marvell Yukon and
+  Genesis based adapters: skge.
+endef
+
+$(eval $(call KernelPackage,sky2))
+
+
+define KernelPackage/via-rhine
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Via Rhine ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_VIA_RHINE \
+    CONFIG_VIA_RHINE_MMIO=y
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/via/via-rhine.ko
+  AUTOLOAD:=$(call AutoProbe,via-rhine)
+endef
+
+define KernelPackage/via-rhine/description
+ Kernel modules for Via Rhine Ethernet chipsets
+endef
+
+$(eval $(call KernelPackage,via-rhine))
+
+
+define KernelPackage/via-velocity
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=VIA Velocity Gigabit Ethernet Adapter kernel support
+  DEPENDS:=@TARGET_ixp4xx||TARGET_mpc83xx||PCI_SUPPORT +kmod-lib-crc-ccitt
+  KCONFIG:=CONFIG_VIA_VELOCITY
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/via/via-velocity.ko
+  AUTOLOAD:=$(call AutoProbe,via-velocity)
+endef
+
+define KernelPackage/via-velocity/description
+ Kernel modules for VIA Velocity Gigabit Ethernet chipsets
+endef
+
+$(eval $(call KernelPackage,via-velocity))
+
+
+define KernelPackage/8139too
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=RealTek RTL-8139 PCI Fast Ethernet Adapter kernel support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_8139TOO \
+    CONFIG_8139TOO_PIO=y \
+    CONFIG_8139TOO_TUNE_TWISTER=n \
+    CONFIG_8139TOO_8129=n \
+    CONFIG_8139_OLD_RX_RESET=n
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/realtek/8139too.ko
+  AUTOLOAD:=$(call AutoProbe,8139too)
+endef
+
+define KernelPackage/8139too/description
+ Kernel modules for RealTek RTL-8139 PCI Fast Ethernet adapters
+endef
+
+$(eval $(call KernelPackage,8139too))
+
+
+define KernelPackage/8139cp
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=RealTek RTL-8139C+ PCI Fast Ethernet Adapter kernel support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_8139CP
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/realtek/8139cp.ko
+  AUTOLOAD:=$(call AutoProbe,8139cp)
+endef
+
+define KernelPackage/8139cp/description
+ Kernel module for RealTek RTL-8139C+ PCI Fast Ethernet adapters
+endef
+
+$(eval $(call KernelPackage,8139cp))
+
+
+define KernelPackage/r8169
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=RealTek RTL-8169 PCI Gigabit Ethernet Adapter kernel support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware
+  KCONFIG:=CONFIG_R8169 \
+    CONFIG_R8169_NAPI=y \
+    CONFIG_R8169_VLAN=n
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/realtek/r8169.ko
+  AUTOLOAD:=$(call AutoProbe,r8169)
+endef
+
+define KernelPackage/r8169/description
+ Kernel modules for RealTek RTL-8169 PCI Gigabit Ethernet adapters
+endef
+
+$(eval $(call KernelPackage,r8169))
+
+
+define KernelPackage/ne2k-pci
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=ne2k-pci Ethernet Adapter kernel support
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_NE2K_PCI
+  FILES:= \
+	$(LINUX_DIR)/drivers/net/ethernet/8390/ne2k-pci.ko \
+	$(LINUX_DIR)/drivers/net/ethernet/8390/8390.ko
+  AUTOLOAD:=$(call AutoProbe,8390 ne2k-pci)
+endef
+
+define KernelPackage/ne2k-pci/description
+ Kernel modules for NE2000 PCI Ethernet Adapter kernel
+endef
+
+$(eval $(call KernelPackage,ne2k-pci))
+
+
+define KernelPackage/e1000
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Intel(R) PRO/1000 PCI cards kernel support
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_E1000 \
+    CONFIG_E1000_DISABLE_PACKET_SPLIT=n \
+    CONFIG_E1000_NAPI=y
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/e1000/e1000.ko
+  AUTOLOAD:=$(call AutoLoad,35,e1000)
+endef
+
+define KernelPackage/e1000/description
+ Kernel modules for Intel(R) PRO/1000 PCI Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,e1000))
+
+
+define KernelPackage/e1000e
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Intel(R) PRO/1000 PCIe cards kernel support
+  DEPENDS:=@PCIE_SUPPORT +kmod-ptp
+  KCONFIG:=CONFIG_E1000E
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/e1000e/e1000e.ko
+  AUTOLOAD:=$(call AutoProbe,e1000e)
+endef
+
+define KernelPackage/e1000e/description
+ Kernel modules for Intel(R) PRO/1000 PCIe Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,e1000e))
+
+
+define KernelPackage/igb
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-i2c-core +kmod-i2c-algo-bit +kmod-ptp
+  KCONFIG:=CONFIG_IGB \
+    CONFIG_IGB_HWMON=n \
+    CONFIG_IGB_DCA=n
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/intel/igb/igb.ko
+  AUTOLOAD:=$(call AutoLoad,35,igb)
+endef
+
+define KernelPackage/igb/description
+ Kernel modules for Intel(R) 82575/82576 PCI-Express Gigabit Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,igb))
+
+
+define KernelPackage/b44
+  TITLE:=Broadcom 44xx driver
+  KCONFIG:=CONFIG_B44
+  DEPENDS:=@PCI_SUPPORT @!TARGET_brcm47xx_mips74k +!TARGET_brcm47xx:kmod-ssb +kmod-mii +kmod-libphy
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/broadcom/b44.ko
+  AUTOLOAD:=$(call AutoLoad,19,b44,1)
+endef
+
+define KernelPackage/b44/description
+ Kernel modules for Broadcom 44xx Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,b44))
+
+
+define KernelPackage/3c59x
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=3Com 3c590/3c900 series (592/595/597) Vortex/Boomerang
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_VORTEX
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/3com/3c59x.ko
+  AUTOLOAD:=$(call AutoProbe,3c59x)
+endef
+
+define KernelPackage/3c59x/description
+ This option enables driver support for a large number of 10mbps and
+ 10/100mbps EISA, PCI and PCMCIA 3Com Ethernet adapters:
+ - "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
+ - "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
+ - "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
+ - "Tornado"   (3c905)                                  PCI
+ - "Hurricane" (3c555/3cSOHO)                           PCI
+endef
+
+$(eval $(call KernelPackage,3c59x))
+
+
+define KernelPackage/pcnet32
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=AMD PCnet32 PCI support
+  DEPENDS:=@(PCI_SUPPORT||TARGET_malta) +kmod-mii
+  KCONFIG:=CONFIG_PCNET32
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/amd/pcnet32.ko
+  AUTOLOAD:=$(call AutoProbe,pcnet32)
+endef
+
+define KernelPackage/pcnet32/description
+ Kernel modules for AMD PCnet32 Ethernet adapters
+endef
+
+$(eval $(call KernelPackage,pcnet32))
+
+
+define KernelPackage/tg3
+  TITLE:=Broadcom Tigon3 Gigabit Ethernet
+  KCONFIG:=CONFIG_TIGON3
+  DEPENDS:=+!TARGET_brcm47xx:kmod-libphy +kmod-hwmon-core +kmod-ptp
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/broadcom/tg3.ko
+  AUTOLOAD:=$(call AutoLoad,19,tg3,1)
+endef
+
+define KernelPackage/tg3/description
+ Kernel modules for Broadcom Tigon3 Gigabit Ethernet adapters
+endef
+
+$(eval $(call KernelPackage,tg3))
+
+
+define KernelPackage/hfcpci
+  TITLE:=HFC PCI cards (single port) support for mISDN
+  KCONFIG:=CONFIG_MISDN_HFCPCI
+  DEPENDS:=+kmod-misdn
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  FILES:=$(LINUX_DIR)/drivers/isdn/hardware/mISDN/hfcpci.ko
+  AUTOLOAD:=$(call AutoLoad,31,hfcpci)
+endef
+
+define KernelPackage/hfcpci/description
+ Kernel modules for Cologne AG's HFC pci cards (single port)
+ using the mISDN V2 stack
+endef
+
+$(eval $(call KernelPackage,hfcpci))
+
+
+define KernelPackage/hfcmulti
+  TITLE:=HFC multiport cards (HFC-4S/8S/E1) support for mISDN
+  KCONFIG:=CONFIG_MISDN_HFCMULTI
+  DEPENDS:=+kmod-misdn
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  FILES:=$(LINUX_DIR)/drivers/isdn/hardware/mISDN/hfcmulti.ko
+  AUTOLOAD:=$(call AutoLoad,31,hfcmulti)
+endef
+
+define KernelPackage/hfcmulti/description
+ Kernel modules for Cologne AG's HFC multiport cards (HFC-4S/8S/E1)
+ using the mISDN V2 stack
+endef
+
+$(eval $(call KernelPackage,hfcmulti))
+
+
+define KernelPackage/gigaset
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Siemens Gigaset support for isdn4linux
+  DEPENDS:=@USB_SUPPORT +kmod-isdn4linux +kmod-lib-crc-ccitt +kmod-usb-core
+  URL:=http://gigaset307x.sourceforge.net/
+  KCONFIG:= \
+    CONFIG_ISDN_DRV_GIGASET \
+    CONFIG_GIGASET_BASE \
+    CONFIG_GIGASET_M101 \
+    CONFIG_GIGASET_M105 \
+    CONFIG_GIGASET_UNDOCREQ=y \
+    CONFIG_GIGASET_I4L=y
+  FILES:= \
+    $(LINUX_DIR)/drivers/isdn/gigaset/gigaset.ko \
+    $(LINUX_DIR)/drivers/isdn/gigaset/bas_gigaset.ko \
+    $(LINUX_DIR)/drivers/isdn/gigaset/ser_gigaset.ko \
+    $(LINUX_DIR)/drivers/isdn/gigaset/usb_gigaset.ko
+  AUTOLOAD:=$(call AutoProbe,gigaset bas_gigaset ser_gigaset usb_gigaset)
+endef
+
+define KernelPackage/gigaset/description
+ This driver supports the Siemens Gigaset SX205/255 family of
+ ISDN DECT bases, including the predecessors Gigaset 3070/3075
+ and 4170/4175 and their T-Com versions Sinus 45isdn and Sinus
+ 721X.
+endef
+
+$(eval $(call KernelPackage,gigaset))
+
+
+define KernelPackage/macvlan
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=MAC-VLAN support
+  KCONFIG:=CONFIG_MACVLAN
+  FILES:=$(LINUX_DIR)/drivers/net/macvlan.ko
+  AUTOLOAD:=$(call AutoProbe,macvlan)
+endef
+
+define KernelPackage/macvlan/description
+ A kernel module which allows one to create virtual interfaces that
+ map packets to or from specific MAC addresses to a particular interface
+endef
+
+$(eval $(call KernelPackage,macvlan))
+
+
+define KernelPackage/tulip
+  TITLE:=Tulip family network device support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  KCONFIG:= \
+    CONFIG_NET_TULIP=y \
+    CONFIG_DE2104X \
+    CONFIG_DE2104X_DSL=0 \
+    CONFIG_TULIP \
+    CONFIG_TULIP_MWI=y \
+    CONFIG_TULIP_MMIO=y \
+    CONFIG_TULIP_NAPI=y \
+    CONFIG_TULIP_NAPI_HW_MITIGATION=y \
+    CONFIG_DE4X5=n \
+    CONFIG_WINBOND_840 \
+    CONFIG_DM9102 \
+    CONFIG_ULI526X
+  FILES:= \
+	$(LINUX_DIR)/drivers/net/ethernet/dec/tulip/tulip.ko \
+	$(LINUX_DIR)/drivers/net/ethernet/dec/tulip/de2104x.ko \
+	$(LINUX_DIR)/drivers/net/ethernet/dec/tulip/dmfe.ko \
+	$(LINUX_DIR)/drivers/net/ethernet/dec/tulip/uli526x.ko \
+	$(LINUX_DIR)/drivers/net/ethernet/dec/tulip/winbond-840.ko
+  AUTOLOAD:=$(call AutoProbe,tulip)
+endef
+
+define KernelPackage/tulip/description
+ Kernel modules for the Tulip family of network cards,
+ including DECchip Tulip, DIGITAL EtherWORKS, Winbond W89c840,
+ Davicom DM910x/DM980x and ULi M526x controller support.
+endef
+
+$(eval $(call KernelPackage,tulip))
+
+
+define KernelPackage/solos-pci
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Solos ADSL2+ multiport modem
+  DEPENDS:=@PCI_SUPPORT +kmod-atm
+  KCONFIG:=CONFIG_ATM_SOLOS
+  FILES:=$(LINUX_DIR)/drivers/atm/solos-pci.ko
+  AUTOLOAD:=$(call AutoProbe,solos-pci)
+endef
+
+define KernelPackage/solos-pci/description
+ Kernel module for Traverse Technologies' Solos PCI cards
+ and Geos ADSL2+ x86 motherboard
+endef
+
+$(eval $(call KernelPackage,solos-pci))
+
+
+define KernelPackage/dummy
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Dummy network device
+  KCONFIG:=CONFIG_DUMMY
+  FILES:=$(LINUX_DIR)/drivers/net/dummy.ko
+  AUTOLOAD:=$(call AutoLoad,34,dummy)
+endef
+
+define KernelPackage/dummy/description
+ The dummy network device
+endef
+
+$(eval $(call KernelPackage,dummy))
+
+
+define KernelPackage/ifb
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Intermediate Functional Block support
+  KCONFIG:= \
+	CONFIG_IFB \
+	CONFIG_NET_CLS=y
+  FILES:=$(LINUX_DIR)/drivers/net/ifb.ko
+  AUTOLOAD:=$(call AutoLoad,34,ifb)
+endef
+
+define KernelPackage/ifb/description
+  The Intermediate Functional Block
+endef
+
+$(eval $(call KernelPackage,ifb))
+
+
+define KernelPackage/dm9000
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Davicom 9000 Ethernet support
+  DEPENDS:=@PCI_SUPPORT +kmod-mii
+  KCONFIG:=CONFIG_DM9000 \
+    CONFIG_DM9000_DEBUGLEVEL=4 \
+    CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/davicom/dm9000.ko
+  AUTOLOAD:=$(call AutoLoad,34,dm9000)
+endef
+
+define KernelPackage/dm9000/description
+ Kernel driver for Davicom 9000 Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,dm9000))
+
+
+define KernelPackage/forcedeth
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=nForce Ethernet support
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_FORCEDETH
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/nvidia/forcedeth.ko
+  AUTOLOAD:=$(call AutoProbe,forcedeth)
+endef
+
+define KernelPackage/forcedeth/description
+ Kernel driver for Nvidia Ethernet support
+endef
+
+$(eval $(call KernelPackage,forcedeth))
+
+define KernelPackage/of-mdio
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=OpenFirmware MDIO support
+  DEPENDS:=+kmod-libphy
+  KCONFIG:=CONFIG_OF_MDIO
+  FILES:=$(LINUX_DIR)/drivers/of/of_mdio.ko
+  AUTOLOAD:=$(call AutoLoad,41,of_mdio)
+endef
+
+define KernelPackage/of-mdio/description
+ Kernel driver for OpenFirmware MDIO support
+endef
+
+$(eval $(call KernelPackage,of-mdio))
+
+
+define KernelPackage/fsl-pq-mdio
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Freescale PQ MDIO bus support
+  DEPENDS:=@TARGET_mpc85xx +kmod-of-mdio
+  KCONFIG:=CONFIG_FSL_PQ_MDIO
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/freescale/fsl_pq_mdio.ko
+  AUTOLOAD:=$(call AutoLoad,42,fsl_pq_mdio)
+endef
+
+define KernelPackage/fsl-pq-mdio/description
+ Kernel driver for the Freescale PQ MDIO bus
+endef
+
+$(eval $(call KernelPackage,fsl-pq-mdio))
+
+
+define KernelPackage/gianfar
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Gianfar Ethernet support
+  DEPENDS:=@TARGET_mpc85xx +kmod-fsl-pq-mdio
+  KCONFIG:=CONFIG_GIANFAR
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/freescale/gianfar_driver.ko
+  AUTOLOAD:=$(call AutoProbe,gianfar_driver)
+endef
+
+define KernelPackage/gianfar/description
+ Kernel driver for Freescale Gianfar Ethernet support
+endef
+
+$(eval $(call KernelPackage,gianfar))
+
+
+define KernelPackage/vmxnet3
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=VMware VMXNET3 ethernet driver 
+  DEPENDS:=@PCI_SUPPORT
+  KCONFIG:=CONFIG_VMXNET3
+  FILES:=$(LINUX_DIR)/drivers/net/vmxnet3/vmxnet3.ko
+  AUTOLOAD:=$(call AutoLoad,35,vmxnet3)
+endef
+
+define KernelPackage/vmxnet3/description
+ Kernel modules for VMware VMXNET3 ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,vmxnet3))
+
+
+define KernelPackage/spi-ks8995
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=Micrel/Kendin KS8995 Ethernet switch control
+  FILES:=$(LINUX_DIR)/drivers/net/phy/spi_ks8995.ko
+  KCONFIG:=CONFIG_MICREL_KS8995MA \
+	CONFIG_SPI=y \
+	CONFIG_SPI_MASTER=y
+  AUTOLOAD:=$(call AutoLoad,50,spi_ks8995)
+endef
+
+define KernelPackage/spi-ks8995/description
+  Kernel module for Micrel/Kendin KS8995 ethernet switch
+endef
+
+$(eval $(call KernelPackage,spi-ks8995))
diff --git a/package/kernel/linux/modules/netfilter.mk b/package/kernel/linux/modules/netfilter.mk
new file mode 100644
index 0000000000..c21f58d79b
--- /dev/null
+++ b/package/kernel/linux/modules/netfilter.mk
@@ -0,0 +1,863 @@
+
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+NF_MENU:=Netfilter Extensions
+NF_KMOD:=1
+include $(INCLUDE_DIR)/netfilter.mk
+
+
+define KernelPackage/nf-ipt
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Iptables core
+  KCONFIG:= \
+  	CONFIG_NETFILTER=y \
+	CONFIG_NETFILTER_ADVANCED=y \
+	$(KCONFIG_NF_IPT)
+  FILES:=$(foreach mod,$(NF_IPT-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_IPT-m)))
+endef
+
+$(eval $(call KernelPackage,nf-ipt))
+
+
+define KernelPackage/nf-ipt6
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Ip6tables core
+  KCONFIG:=$(KCONFIG_NF_IPT6)
+  FILES:=$(foreach mod,$(NF_IPT6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_IPT6-m)))
+  DEPENDS:=+kmod-nf-ipt +kmod-nf-conntrack6
+endef
+
+$(eval $(call KernelPackage,nf-ipt6))
+
+
+
+define KernelPackage/ipt-core
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Iptables core
+  KCONFIG:=$(KCONFIG_IPT_CORE)
+  FILES:=$(foreach mod,$(IPT_CORE-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_CORE-m)))
+  DEPENDS:=+kmod-nf-ipt
+endef
+
+define KernelPackage/ipt-core/description
+ Netfilter core kernel modules
+ Includes:
+ - comment
+ - limit
+ - LOG
+ - mac
+ - multiport
+ - REJECT
+ - TCPMSS
+endef
+
+$(eval $(call KernelPackage,ipt-core))
+
+
+define KernelPackage/nf-conntrack
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter connection tracking
+  KCONFIG:= \
+        CONFIG_NETFILTER=y \
+        CONFIG_NETFILTER_ADVANCED=y \
+        CONFIG_NF_CONNTRACK_ZONES=y \
+	$(KCONFIG_NF_CONNTRACK)
+  FILES:=$(foreach mod,$(NF_CONNTRACK-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_CONNTRACK-m)))
+endef
+
+$(eval $(call KernelPackage,nf-conntrack))
+
+
+define KernelPackage/nf-conntrack6
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter IPv6 connection tracking
+  KCONFIG:=$(KCONFIG_NF_CONNTRACK6)
+  DEPENDS:=@IPV6 +kmod-nf-conntrack
+  FILES:=$(foreach mod,$(NF_CONNTRACK6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_CONNTRACK6-m)))
+endef
+
+$(eval $(call KernelPackage,nf-conntrack6))
+
+
+define KernelPackage/nf-nat
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter NAT
+  KCONFIG:=$(KCONFIG_NF_NAT)
+  DEPENDS:=+kmod-nf-conntrack +kmod-nf-ipt
+  FILES:=$(foreach mod,$(NF_NAT-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_NAT-m)))
+endef
+
+$(eval $(call KernelPackage,nf-nat))
+
+
+define KernelPackage/nf-nat6
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter IPV6-NAT
+  KCONFIG:=$(KCONFIG_NF_NAT6)
+  DEPENDS:=+kmod-nf-conntrack6 +kmod-nf-ipt6 +kmod-nf-nat
+  FILES:=$(foreach mod,$(NF_NAT6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_NAT6-m)))
+endef
+
+$(eval $(call KernelPackage,nf-nat6))
+
+
+define AddDepends/ipt
+  SUBMENU:=$(NF_MENU)
+  DEPENDS+= +kmod-ipt-core $(1)
+endef
+
+
+define KernelPackage/ipt-conntrack
+  TITLE:=Basic connection tracking modules
+  KCONFIG:=$(KCONFIG_IPT_CONNTRACK)
+  FILES:=$(foreach mod,$(IPT_CONNTRACK-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_CONNTRACK-m)))
+  $(call AddDepends/ipt,+kmod-nf-conntrack)
+endef
+
+define KernelPackage/ipt-conntrack/description
+ Netfilter (IPv4) kernel modules for connection tracking
+ Includes:
+ - conntrack
+ - defrag
+ - iptables_raw
+ - NOTRACK
+ - state
+endef
+
+$(eval $(call KernelPackage,ipt-conntrack))
+
+
+define KernelPackage/ipt-conntrack-extra
+  TITLE:=Extra connection tracking modules
+  KCONFIG:=$(KCONFIG_IPT_CONNTRACK_EXTRA)
+  FILES:=$(foreach mod,$(IPT_CONNTRACK_EXTRA-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_CONNTRACK_EXTRA-m)))
+  $(call AddDepends/ipt,+kmod-ipt-conntrack)
+endef
+
+define KernelPackage/ipt-conntrack-extra/description
+ Netfilter (IPv4) extra kernel modules for connection tracking
+ Includes:
+ - connbytes
+ - connmark/CONNMARK
+ - conntrack
+ - helper
+ - recent
+endef
+
+$(eval $(call KernelPackage,ipt-conntrack-extra))
+
+
+define KernelPackage/ipt-filter
+  TITLE:=Modules for packet content inspection
+  KCONFIG:=$(KCONFIG_IPT_FILTER)
+  FILES:=$(foreach mod,$(IPT_FILTER-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_FILTER-m)))
+  $(call AddDepends/ipt,+kmod-lib-textsearch +kmod-ipt-conntrack)
+endef
+
+define KernelPackage/ipt-filter/description
+ Netfilter (IPv4) kernel modules for packet content inspection
+ Includes:
+ - string
+endef
+
+$(eval $(call KernelPackage,ipt-filter))
+
+
+define KernelPackage/ipt-ipopt
+  TITLE:=Modules for matching/changing IP packet options
+  KCONFIG:=$(KCONFIG_IPT_IPOPT)
+  FILES:=$(foreach mod,$(IPT_IPOPT-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_IPOPT-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-ipopt/description
+ Netfilter (IPv4) modules for matching/changing IP packet options
+ Includes:
+ - CLASSIFY
+ - dscp/DSCP
+ - ecn/ECN
+ - hl/HL
+ - length
+ - mark/MARK
+ - statistic
+ - tcpmss
+ - time
+ - ttl/TTL
+ - unclean
+endef
+
+$(eval $(call KernelPackage,ipt-ipopt))
+
+
+define KernelPackage/ipt-ipsec
+  TITLE:=Modules for matching IPSec packets
+  KCONFIG:=$(KCONFIG_IPT_IPSEC)
+  FILES:=$(foreach mod,$(IPT_IPSEC-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_IPSEC-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-ipsec/description
+ Netfilter (IPv4) modules for matching IPSec packets
+ Includes:
+ - ah
+ - esp
+ - policy
+endef
+
+$(eval $(call KernelPackage,ipt-ipsec))
+
+IPSET_MODULES:= \
+	ipset/ip_set \
+	ipset/ip_set_bitmap_ip \
+	ipset/ip_set_bitmap_ipmac \
+	ipset/ip_set_bitmap_port \
+	ipset/ip_set_hash_ip \
+	ipset/ip_set_hash_ipmark \
+	ipset/ip_set_hash_ipport \
+	ipset/ip_set_hash_ipportip \
+	ipset/ip_set_hash_ipportnet \
+	ipset/ip_set_hash_mac \
+	ipset/ip_set_hash_netportnet \
+	ipset/ip_set_hash_net \
+	ipset/ip_set_hash_netnet \
+	ipset/ip_set_hash_netport \
+	ipset/ip_set_hash_netiface \
+	ipset/ip_set_list_set \
+	xt_set
+
+define KernelPackage/ipt-ipset
+  SUBMENU:=Netfilter Extensions
+  TITLE:=IPset netfilter modules
+  DEPENDS+= +kmod-ipt-core +kmod-nfnetlink
+  KCONFIG:= \
+	CONFIG_IP_SET \
+	CONFIG_IP_SET_MAX=256 \
+	CONFIG_NETFILTER_XT_SET \
+	CONFIG_IP_SET_BITMAP_IP \
+	CONFIG_IP_SET_BITMAP_IPMAC \
+	CONFIG_IP_SET_BITMAP_PORT \
+	CONFIG_IP_SET_HASH_IP \
+	CONFIG_IP_SET_HASH_IPMARK \
+	CONFIG_IP_SET_HASH_IPPORT \
+	CONFIG_IP_SET_HASH_IPPORTIP \
+	CONFIG_IP_SET_HASH_IPPORTNET \
+	CONFIG_IP_SET_HASH_MAC \
+	CONFIG_IP_SET_HASH_NET \
+	CONFIG_IP_SET_HASH_NETNET \
+	CONFIG_IP_SET_HASH_NETIFACE \
+	CONFIG_IP_SET_HASH_NETPORT \
+	CONFIG_IP_SET_HASH_NETPORTNET \
+	CONFIG_IP_SET_LIST_SET \
+	CONFIG_NET_EMATCH_IPSET=n
+  FILES:=$(foreach mod,$(IPSET_MODULES),$(LINUX_DIR)/net/netfilter/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,49,$(notdir $(IPSET_MODULES)))
+endef
+$(eval $(call KernelPackage,ipt-ipset))
+
+
+define KernelPackage/ipt-nat
+  TITLE:=Basic NAT targets
+  KCONFIG:=$(KCONFIG_IPT_NAT)
+  FILES:=$(foreach mod,$(IPT_NAT-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_NAT-m)))
+  $(call AddDepends/ipt,+kmod-nf-nat)
+endef
+
+define KernelPackage/ipt-nat/description
+ Netfilter (IPv4) kernel modules for basic NAT targets
+ Includes:
+ - MASQUERADE
+endef
+
+$(eval $(call KernelPackage,ipt-nat))
+
+
+define KernelPackage/ipt-nat6
+  TITLE:=IPv6 NAT targets
+  KCONFIG:=$(KCONFIG_IPT_NAT6)
+  FILES:=$(foreach mod,$(IPT_NAT6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,43,$(notdir $(IPT_NAT6-m)))
+  $(call AddDepends/ipt,+kmod-nf-nat6)
+  $(call AddDepends/ipt,+kmod-ipt-conntrack)
+  $(call AddDepends/ipt,+kmod-ipt-nat)
+  $(call AddDepends/ipt,+kmod-ip6tables)
+endef
+
+define KernelPackage/ipt-nat6/description
+ Netfilter (IPv6) kernel modules for NAT targets
+endef
+
+$(eval $(call KernelPackage,ipt-nat6))
+
+
+define KernelPackage/ipt-nat-extra
+  TITLE:=Extra NAT targets
+  KCONFIG:=$(KCONFIG_IPT_NAT_EXTRA)
+  FILES:=$(foreach mod,$(IPT_NAT_EXTRA-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_NAT_EXTRA-m)))
+  $(call AddDepends/ipt,+kmod-ipt-nat)
+endef
+
+define KernelPackage/ipt-nat-extra/description
+ Netfilter (IPv4) kernel modules for extra NAT targets
+ Includes:
+ - NETMAP
+ - REDIRECT
+endef
+
+$(eval $(call KernelPackage,ipt-nat-extra))
+
+
+define KernelPackage/nf-nathelper
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Basic Conntrack and NAT helpers
+  KCONFIG:=$(KCONFIG_NF_NATHELPER)
+  FILES:=$(foreach mod,$(NF_NATHELPER-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_NATHELPER-m)))
+  DEPENDS:=+kmod-nf-nat
+endef
+
+define KernelPackage/nf-nathelper/description
+ Default Netfilter (IPv4) Conntrack and NAT helpers
+ Includes:
+ - ftp
+ - irc
+ - tftp
+endef
+
+$(eval $(call KernelPackage,nf-nathelper))
+
+
+define KernelPackage/nf-nathelper-extra
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Extra Conntrack and NAT helpers
+  KCONFIG:=$(KCONFIG_NF_NATHELPER_EXTRA)
+  FILES:=$(foreach mod,$(NF_NATHELPER_EXTRA-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NF_NATHELPER_EXTRA-m)))
+  DEPENDS:=+kmod-nf-nat +kmod-lib-textsearch
+endef
+
+define KernelPackage/nf-nathelper-extra/description
+ Extra Netfilter (IPv4) Conntrack and NAT helpers
+ Includes:
+ - amanda
+ - h323
+ - mms
+ - pptp
+ - proto_gre
+ - sip
+ - snmp_basic
+ - broadcast
+endef
+
+$(eval $(call KernelPackage,nf-nathelper-extra))
+
+
+define KernelPackage/ipt-ulog
+  TITLE:=Module for user-space packet logging
+  KCONFIG:=$(KCONFIG_IPT_ULOG)
+  FILES:=$(foreach mod,$(IPT_ULOG-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_ULOG-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-ulog/description
+ Netfilter (IPv4) module for user-space packet logging
+ Includes:
+ - ULOG
+endef
+
+$(eval $(call KernelPackage,ipt-ulog))
+
+
+define KernelPackage/ipt-nflog
+  TITLE:=Module for user-space packet logging
+  KCONFIG:=$(KCONFIG_IPT_NFLOG)
+  FILES:=$(foreach mod,$(IPT_NFLOG-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_NFLOG-m)))
+  $(call AddDepends/ipt,+kmod-nfnetlink-log)
+endef
+
+define KernelPackage/ipt-nflog/description
+ Netfilter module for user-space packet logging
+ Includes:
+ - NFLOG
+endef
+
+$(eval $(call KernelPackage,ipt-nflog))
+
+
+define KernelPackage/ipt-nfqueue
+  TITLE:=Module for user-space packet queuing
+  KCONFIG:=$(KCONFIG_IPT_NFQUEUE)
+  FILES:=$(foreach mod,$(IPT_NFQUEUE-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_NFQUEUE-m)))
+  $(call AddDepends/ipt,+kmod-nfnetlink-queue)
+endef
+
+define KernelPackage/ipt-nfqueue/description
+ Netfilter module for user-space packet queuing
+ Includes:
+ - NFQUEUE
+endef
+
+$(eval $(call KernelPackage,ipt-nfqueue))
+
+
+define KernelPackage/ipt-debug
+  TITLE:=Module for debugging/development
+  KCONFIG:=$(KCONFIG_IPT_DEBUG)
+  DEFAULT:=n
+  FILES:=$(foreach mod,$(IPT_DEBUG-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_DEBUG-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-debug/description
+ Netfilter modules for debugging/development of the firewall
+ Includes:
+ - TRACE
+endef
+
+$(eval $(call KernelPackage,ipt-debug))
+
+
+define KernelPackage/ipt-led
+  TITLE:=Module to trigger a LED with a Netfilter rule
+  KCONFIG:=$(KCONFIG_IPT_LED)
+  FILES:=$(foreach mod,$(IPT_LED-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_LED-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-led/description
+ Netfilter target to trigger a LED when a network packet is matched.
+endef
+
+$(eval $(call KernelPackage,ipt-led))
+
+define KernelPackage/ipt-tproxy
+  TITLE:=Transparent proxying support
+  DEPENDS+=+kmod-ipt-conntrack +IPV6:kmod-ip6tables
+  KCONFIG:= \
+  	CONFIG_NETFILTER_XT_MATCH_SOCKET \
+  	CONFIG_NETFILTER_XT_TARGET_TPROXY
+  FILES:= \
+  	$(foreach mod,$(IPT_TPROXY-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_TPROXY-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-tproxy/description
+  Kernel modules for Transparent Proxying
+endef
+
+$(eval $(call KernelPackage,ipt-tproxy))
+
+define KernelPackage/ipt-tee
+  TITLE:=TEE support
+  DEPENDS:=+kmod-ipt-conntrack @!LINUX_4_4
+  KCONFIG:= \
+  	CONFIG_NETFILTER_XT_TARGET_TEE
+  FILES:= \
+  	$(LINUX_DIR)/net/netfilter/xt_TEE.ko \
+  	$(foreach mod,$(IPT_TEE-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir nf_tee $(IPT_TEE-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-tee/description
+  Kernel modules for TEE
+endef
+
+$(eval $(call KernelPackage,ipt-tee))
+
+
+define KernelPackage/ipt-u32
+  TITLE:=U32 support
+  KCONFIG:= \
+  	CONFIG_NETFILTER_XT_MATCH_U32
+  FILES:= \
+  	$(LINUX_DIR)/net/netfilter/xt_u32.ko \
+  	$(foreach mod,$(IPT_U32-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir nf_tee $(IPT_U32-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-u32/description
+  Kernel modules for U32
+endef
+
+$(eval $(call KernelPackage,ipt-u32))
+
+
+define KernelPackage/ipt-iprange
+  TITLE:=Module for matching ip ranges
+  KCONFIG:=$(KCONFIG_IPT_IPRANGE)
+  FILES:=$(foreach mod,$(IPT_IPRANGE-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_IPRANGE-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-iprange/description
+ Netfilter (IPv4) module for matching ip ranges
+ Includes:
+ - iprange
+endef
+
+$(eval $(call KernelPackage,ipt-iprange))
+
+define KernelPackage/ipt-cluster
+  TITLE:=Module for matching cluster
+  KCONFIG:=$(KCONFIG_IPT_CLUSTER)
+  FILES:=$(foreach mod,$(IPT_CLUSTER-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_CLUSTER-m)))
+  $(call AddDepends/ipt)
+endef
+
+define KernelPackage/ipt-cluster/description
+ Netfilter (IPv4/IPv6) module for matching cluster
+ This option allows you to build work-load-sharing clusters of
+ network servers/stateful firewalls without having a dedicated
+ load-balancing router/server/switch. Basically, this match returns
+ true when the packet must be handled by this cluster node. Thus,
+ all nodes see all packets and this match decides which node handles
+ what packets. The work-load sharing algorithm is based on source
+ address hashing.
+
+ This module is usable for ipv4 and ipv6.
+
+ To use it also enable iptables-mod-cluster
+
+ see `iptables -m cluster --help` for more information.
+endef
+
+$(eval $(call KernelPackage,ipt-cluster))
+
+define KernelPackage/ipt-clusterip
+  TITLE:=Module for CLUSTERIP
+  KCONFIG:=$(KCONFIG_IPT_CLUSTERIP)
+  FILES:=$(foreach mod,$(IPT_CLUSTERIP-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_CLUSTERIP-m)))
+  $(call AddDepends/ipt,+kmod-nf-conntrack)
+endef
+
+define KernelPackage/ipt-clusterip/description
+ Netfilter (IPv4-only) module for CLUSTERIP
+ The CLUSTERIP target allows you to build load-balancing clusters of
+ network servers without having a dedicated load-balancing
+ router/server/switch.
+
+ To use it also enable iptables-mod-clusterip
+
+ see `iptables -j CLUSTERIP --help` for more information.
+endef
+
+$(eval $(call KernelPackage,ipt-clusterip))
+
+
+define KernelPackage/ipt-extra
+  TITLE:=Extra modules
+  KCONFIG:=$(KCONFIG_IPT_EXTRA)
+  FILES:=$(foreach mod,$(IPT_EXTRA-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(IPT_EXTRA-m)))
+  $(call AddDepends/ipt,+kmod-br-netfilter)
+endef
+
+define KernelPackage/ipt-extra/description
+ Other Netfilter (IPv4) kernel modules
+ Includes:
+ - addrtype
+ - owner
+ - physdev (if bridge support was enabled in kernel)
+ - pkttype
+ - quota
+endef
+
+$(eval $(call KernelPackage,ipt-extra))
+
+
+define KernelPackage/ip6tables
+  SUBMENU:=$(NF_MENU)
+  TITLE:=IPv6 modules
+  DEPENDS:=+kmod-nf-ipt6 +kmod-ipt-core +kmod-ipt-conntrack
+  KCONFIG:=$(KCONFIG_IPT_IPV6)
+  FILES:=$(foreach mod,$(IPT_IPV6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,42,$(notdir $(IPT_IPV6-m)))
+endef
+
+define KernelPackage/ip6tables/description
+ Netfilter IPv6 firewalling support
+endef
+
+$(eval $(call KernelPackage,ip6tables))
+
+define KernelPackage/ip6tables-extra
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Extra IPv6 modules
+  DEPENDS:=+kmod-ip6tables
+  KCONFIG:=$(KCONFIG_IPT_IPV6_EXTRA)
+  FILES:=$(foreach mod,$(IPT_IPV6_EXTRA-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,43,$(notdir $(IPT_IPV6_EXTRA-m)))
+endef
+
+define KernelPackage/ip6tables-extra/description
+ Netfilter IPv6 extra header matching modules
+endef
+
+$(eval $(call KernelPackage,ip6tables-extra))
+
+ARP_MODULES = arp_tables arpt_mangle arptable_filter
+define KernelPackage/arptables
+  SUBMENU:=$(NF_MENU)
+  TITLE:=ARP firewalling modules
+  DEPENDS:=+kmod-ipt-core
+  FILES:=$(LINUX_DIR)/net/ipv4/netfilter/arp*.ko
+  KCONFIG:=CONFIG_IP_NF_ARPTABLES \
+    CONFIG_IP_NF_ARPFILTER \
+    CONFIG_IP_NF_ARP_MANGLE
+  AUTOLOAD:=$(call AutoProbe,$(ARP_MODULES))
+endef
+
+define KernelPackage/arptables/description
+ Kernel modules for ARP firewalling
+endef
+
+$(eval $(call KernelPackage,arptables))
+
+
+define KernelPackage/br-netfilter
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Bridge netfilter support modules
+  HIDDEN:=1
+  DEPENDS:=+kmod-ipt-core +kmod-bridge
+  FILES:=$(LINUX_DIR)/net/bridge/br_netfilter.ko
+  KCONFIG:=CONFIG_BRIDGE_NETFILTER
+  AUTOLOAD:=$(call AutoProbe,br_netfilter)
+endef
+
+$(eval $(call KernelPackage,br-netfilter))
+
+
+define KernelPackage/ebtables
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Bridge firewalling modules
+  DEPENDS:=+kmod-ipt-core +kmod-bridge +kmod-br-netfilter
+  FILES:=$(foreach mod,$(EBTABLES-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_EBTABLES)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(EBTABLES-m)))
+endef
+
+define KernelPackage/ebtables/description
+  ebtables is a general, extensible frame/packet identification
+  framework. It provides you to do Ethernet
+  filtering/NAT/brouting on the Ethernet bridge.
+endef
+
+$(eval $(call KernelPackage,ebtables))
+
+
+define AddDepends/ebtables
+  SUBMENU:=$(NF_MENU)
+  DEPENDS+=kmod-ebtables $(1)
+endef
+
+
+define KernelPackage/ebtables-ipv4
+  TITLE:=ebtables: IPv4 support
+  FILES:=$(foreach mod,$(EBTABLES_IP4-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_EBTABLES_IP4)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(EBTABLES_IP4-m)))
+  $(call AddDepends/ebtables)
+endef
+
+define KernelPackage/ebtables-ipv4/description
+ This option adds the IPv4 support to ebtables, which allows basic
+ IPv4 header field filtering, ARP filtering as well as SNAT, DNAT targets.
+endef
+
+$(eval $(call KernelPackage,ebtables-ipv4))
+
+
+define KernelPackage/ebtables-ipv6
+  TITLE:=ebtables: IPv6 support
+  FILES:=$(foreach mod,$(EBTABLES_IP6-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_EBTABLES_IP6)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(EBTABLES_IP6-m)))
+  $(call AddDepends/ebtables)
+endef
+
+define KernelPackage/ebtables-ipv6/description
+ This option adds the IPv6 support to ebtables, which allows basic
+ IPv6 header field filtering and target support.
+endef
+
+$(eval $(call KernelPackage,ebtables-ipv6))
+
+
+define KernelPackage/ebtables-watchers
+  TITLE:=ebtables: watchers support
+  FILES:=$(foreach mod,$(EBTABLES_WATCHERS-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_EBTABLES_WATCHERS)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(EBTABLES_WATCHERS-m)))
+  $(call AddDepends/ebtables)
+endef
+
+define KernelPackage/ebtables-watchers/description
+ This option adds the log watchers, that you can use in any rule
+ in any ebtables table.
+endef
+
+$(eval $(call KernelPackage,ebtables-watchers))
+
+
+define KernelPackage/nfnetlink
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netlink-based userspace interface
+  FILES:=$(foreach mod,$(NFNETLINK-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_NFNETLINK)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NFNETLINK-m)))
+endef
+
+define KernelPackage/nfnetlink/description
+ Kernel modules support for a netlink-based userspace interface
+endef
+
+$(eval $(call KernelPackage,nfnetlink))
+
+
+define AddDepends/nfnetlink
+  SUBMENU:=$(NF_MENU)
+  DEPENDS+=+kmod-nfnetlink $(1)
+endef
+
+
+define KernelPackage/nfnetlink-log
+  TITLE:=Netfilter LOG over NFNETLINK interface
+  FILES:=$(foreach mod,$(NFNETLINK_LOG-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_NFNETLINK_LOG)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NFNETLINK_LOG-m)))
+  $(call AddDepends/nfnetlink)
+endef
+
+define KernelPackage/nfnetlink-log/description
+ Kernel modules support for logging packets via NFNETLINK
+ Includes:
+ - NFLOG
+endef
+
+$(eval $(call KernelPackage,nfnetlink-log))
+
+
+define KernelPackage/nfnetlink-queue
+  TITLE:=Netfilter QUEUE over NFNETLINK interface
+  FILES:=$(foreach mod,$(NFNETLINK_QUEUE-m),$(LINUX_DIR)/net/$(mod).ko)
+  KCONFIG:=$(KCONFIG_NFNETLINK_QUEUE)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NFNETLINK_QUEUE-m)))
+  $(call AddDepends/nfnetlink)
+endef
+
+define KernelPackage/nfnetlink-queue/description
+ Kernel modules support for queueing packets via NFNETLINK
+ Includes:
+ - NFQUEUE
+endef
+
+$(eval $(call KernelPackage,nfnetlink-queue))
+
+
+define KernelPackage/nf-conntrack-netlink
+  TITLE:=Connection tracking netlink interface
+  FILES:=$(LINUX_DIR)/net/netfilter/nf_conntrack_netlink.ko
+  KCONFIG:=CONFIG_NF_CT_NETLINK CONFIG_NF_CONNTRACK_EVENTS=y
+  AUTOLOAD:=$(call AutoProbe,nf_conntrack_netlink)
+  $(call AddDepends/nfnetlink,+kmod-ipt-conntrack)
+endef
+
+define KernelPackage/nf-conntrack-netlink/description
+ Kernel modules support for a netlink-based connection tracking
+ userspace interface
+endef
+
+$(eval $(call KernelPackage,nf-conntrack-netlink))
+
+define KernelPackage/ipt-hashlimit
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter hashlimit match
+  DEPENDS:=+kmod-ipt-core
+  KCONFIG:=$(KCONFIG_IPT_HASHLIMIT)
+  FILES:=$(LINUX_DIR)/net/netfilter/xt_hashlimit.ko
+  AUTOLOAD:=$(call AutoProbe,xt_hashlimit)
+  $(call KernelPackage/ipt)
+endef
+
+define KernelPackage/ipt-hashlimit/description
+ Kernel modules support for the hashlimit bucket match module
+endef
+
+$(eval $(call KernelPackage,ipt-hashlimit))
+
+
+define KernelPackage/nft-core
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter nf_tables support
+  DEPENDS:=+kmod-nfnetlink +kmod-nf-conntrack6 +kmod-nf-ipt +kmod-nf-ipt6
+  FILES:=$(foreach mod,$(NFT_CORE-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NFT_CORE-m)))
+  KCONFIG:= \
+	CONFIG_NETFILTER=y \
+	CONFIG_NETFILTER_ADVANCED=y \
+	CONFIG_NFT_COMPAT=n \
+	CONFIG_NFT_QUEUE=n \
+	CONFIG_NF_TABLES_ARP=n \
+	CONFIG_NF_TABLES_BRIDGE=n \
+	$(KCONFIG_NFT_CORE)
+endef
+
+define KernelPackage/nft-core/description
+ Kernel module support for nftables
+endef
+
+$(eval $(call KernelPackage,nft-core))
+
+
+define KernelPackage/nft-nat
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter nf_tables NAT support
+  DEPENDS:=+kmod-nft-core +kmod-nf-nat +kmod-nf-nat6
+  FILES:=$(foreach mod,$(NFT_NAT-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NFT_NAT-m)))
+  KCONFIG:=$(KCONFIG_NFT_NAT)
+endef
+
+$(eval $(call KernelPackage,nft-nat))
+
+
+define KernelPackage/nft-nat6
+  SUBMENU:=$(NF_MENU)
+  TITLE:=Netfilter nf_tables IPv6-NAT support
+  DEPENDS:=+kmod-nft-core +kmod-nf-nat6
+  FILES:=$(foreach mod,$(NFT_NAT6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoProbe,$(notdir $(NFT_NAT6-m)))
+  KCONFIG:=$(KCONFIG_NFT_NAT6)
+endef
+
+$(eval $(call KernelPackage,nft-nat6))
+
diff --git a/package/kernel/linux/modules/netsupport.mk b/package/kernel/linux/modules/netsupport.mk
new file mode 100644
index 0000000000..ef5c5ba848
--- /dev/null
+++ b/package/kernel/linux/modules/netsupport.mk
@@ -0,0 +1,1061 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+NETWORK_SUPPORT_MENU:=Network Support
+
+define KernelPackage/atm
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=ATM support
+  KCONFIG:= \
+	CONFIG_ATM \
+	CONFIG_ATM_BR2684
+  FILES:= \
+	$(LINUX_DIR)/net/atm/atm.ko \
+	$(LINUX_DIR)/net/atm/br2684.ko
+  AUTOLOAD:=$(call AutoLoad,30,atm br2684)
+endef
+
+define KernelPackage/atm/description
+ Kernel modules for ATM support
+endef
+
+$(eval $(call KernelPackage,atm))
+
+
+define KernelPackage/atmtcp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=ATM over TCP
+  DEPENDS:=kmod-atm
+  KCONFIG:=CONFIG_ATM_TCP CONFIG_ATM_DRIVERS=y
+  FILES:=$(LINUX_DIR)/drivers/atm/atmtcp.ko
+  AUTOLOAD:=$(call AutoLoad,40,atmtcp)
+endef
+
+define KernelPackage/atmtcp/description
+ Kernel module for ATM over TCP support
+endef
+
+$(eval $(call KernelPackage,atmtcp))
+
+
+define KernelPackage/appletalk
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Appletalk protocol support
+  DEPENDS:=+PACKAGE_kmod-llc:kmod-llc
+  KCONFIG:= \
+	CONFIG_ATALK \
+	CONFIG_DEV_APPLETALK \
+	CONFIG_IPDDP \
+	CONFIG_IPDDP_ENCAP=y \
+	CONFIG_IPDDP_DECAP=y
+  FILES:= \
+	$(LINUX_DIR)/net/appletalk/appletalk.ko \
+	$(LINUX_DIR)/drivers/net/appletalk/ipddp.ko
+  AUTOLOAD:=$(call AutoLoad,40,appletalk ipddp)
+endef
+
+define KernelPackage/appletalk/description
+ Kernel module for AppleTalk protocol.
+endef
+
+$(eval $(call KernelPackage,appletalk))
+
+
+define KernelPackage/bonding
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Ethernet bonding driver
+  KCONFIG:=CONFIG_BONDING
+  FILES:=$(LINUX_DIR)/drivers/net/bonding/bonding.ko
+  AUTOLOAD:=$(call AutoLoad,40,bonding)
+endef
+
+define KernelPackage/bonding/description
+ Kernel module for NIC bonding.
+endef
+
+$(eval $(call KernelPackage,bonding))
+
+
+define KernelPackage/bridge
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Ethernet bridging support
+  DEPENDS:=+kmod-stp
+  KCONFIG:= \
+	CONFIG_BRIDGE \
+	CONFIG_BRIDGE_IGMP_SNOOPING=y
+  FILES:=$(LINUX_DIR)/net/bridge/bridge.ko
+  AUTOLOAD:=$(call AutoLoad,11,bridge)
+endef
+
+define KernelPackage/bridge/description
+ Kernel module for Ethernet bridging.
+endef
+
+$(eval $(call KernelPackage,bridge))
+
+define KernelPackage/llc
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=ANSI/IEEE 802.2 LLC support
+  KCONFIG:=CONFIG_LLC
+  FILES:= \
+	$(LINUX_DIR)/net/llc/llc.ko \
+	$(LINUX_DIR)/net/802/p8022.ko \
+	$(LINUX_DIR)/net/802/psnap.ko
+  AUTOLOAD:=$(call AutoLoad,09,llc p8022 psnap)
+endef
+
+define KernelPackage/llc/description
+ Kernel module for ANSI/IEEE 802.2 LLC support.
+endef
+
+$(eval $(call KernelPackage,llc))
+
+define KernelPackage/stp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Ethernet Spanning Tree Protocol support
+  DEPENDS:=+kmod-llc
+  KCONFIG:=CONFIG_STP
+  FILES:=$(LINUX_DIR)/net/802/stp.ko
+  AUTOLOAD:=$(call AutoLoad,10,stp)
+endef
+
+define KernelPackage/stp/description
+ Kernel module for Ethernet Spanning Tree Protocol support.
+endef
+
+$(eval $(call KernelPackage,stp))
+
+define KernelPackage/8021q
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=802.1Q VLAN support
+  KCONFIG:=CONFIG_VLAN_8021Q \
+		CONFIG_VLAN_8021Q_GVRP=n
+  FILES:=$(LINUX_DIR)/net/8021q/8021q.ko
+  AUTOLOAD:=$(call AutoLoad,12,8021q)
+endef
+
+define KernelPackage/8021q/description
+ Kernel module for 802.1Q VLAN support
+endef
+
+$(eval $(call KernelPackage,8021q))
+
+
+define KernelPackage/udptunnel4
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPv4 UDP tunneling support
+  KCONFIG:= \
+	CONFIG_NET_UDP_TUNNEL \
+	CONFIG_VXLAN=m
+  HIDDEN:=1
+  FILES:=$(LINUX_DIR)/net/ipv4/udp_tunnel.ko
+  AUTOLOAD:=$(call AutoLoad,32,udp_tunnel)
+endef
+
+
+$(eval $(call KernelPackage,udptunnel4))
+
+define KernelPackage/udptunnel6
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPv6 UDP tunneling support
+  DEPENDS:=@IPV6
+  KCONFIG:= \
+	CONFIG_NET_UDP_TUNNEL \
+	CONFIG_VXLAN=m
+  HIDDEN:=1
+  FILES:=$(LINUX_DIR)/net/ipv6/ip6_udp_tunnel.ko
+  AUTOLOAD:=$(call AutoLoad,32,ip6_udp_tunnel)
+endef
+
+$(eval $(call KernelPackage,udptunnel6))
+
+
+define KernelPackage/vxlan
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Native VXLAN Kernel support
+  DEPENDS:= \
+	+kmod-iptunnel \
+	+kmod-udptunnel4 \
+	+IPV6:kmod-udptunnel6
+  KCONFIG:=CONFIG_VXLAN
+  FILES:=$(LINUX_DIR)/drivers/net/vxlan.ko
+  AUTOLOAD:=$(call AutoLoad,13,vxlan)
+endef
+
+define KernelPackage/vxlan/description
+ Kernel module for supporting VXLAN in the Kernel.
+ Requires Kernel 3.12 or newer.
+endef
+
+$(eval $(call KernelPackage,vxlan))
+
+define KernelPackage/capi
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=CAPI (ISDN) Support
+  KCONFIG:= \
+	CONFIG_ISDN_CAPI \
+	CONFIG_ISDN_CAPI_CAPI20 \
+	CONFIG_ISDN_CAPIFS \
+	CONFIG_ISDN_CAPI_CAPIFS
+  FILES:= \
+	$(LINUX_DIR)/drivers/isdn/capi/kernelcapi.ko \
+	$(LINUX_DIR)/drivers/isdn/capi/capi.ko
+  AUTOLOAD:=$(call AutoLoad,30,kernelcapi capi)
+endef
+
+define KernelPackage/capi/description
+ Kernel module for basic CAPI (ISDN) support
+endef
+
+$(eval $(call KernelPackage,capi))
+
+define KernelPackage/misdn
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=mISDN (ISDN) Support
+  KCONFIG:= \
+	CONFIG_ISDN=y \
+  	CONFIG_MISDN \
+	CONFIG_MISDN_DSP \
+	CONFIG_MISDN_L1OIP
+  FILES:= \
+  	$(LINUX_DIR)/drivers/isdn/mISDN/mISDN_core.ko \
+	$(LINUX_DIR)/drivers/isdn/mISDN/mISDN_dsp.ko \
+	$(LINUX_DIR)/drivers/isdn/mISDN/l1oip.ko
+  AUTOLOAD:=$(call AutoLoad,30,mISDN_core mISDN_dsp l1oip)
+endef
+
+define KernelPackage/misdn/description
+  Modular ISDN driver support
+endef
+
+$(eval $(call KernelPackage,misdn))
+
+
+define KernelPackage/isdn4linux
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Old ISDN4Linux (deprecated)
+  DEPENDS:=+kmod-ppp
+  KCONFIG:= \
+	CONFIG_ISDN=y \
+    CONFIG_ISDN_I4L \
+    CONFIG_ISDN_PPP=y \
+    CONFIG_ISDN_PPP_VJ=y \
+    CONFIG_ISDN_MPP=y \
+    CONFIG_IPPP_FILTER=y \
+    CONFIG_ISDN_PPP_BSDCOMP \
+    CONFIG_ISDN_CAPI_MIDDLEWARE=y \
+    CONFIG_ISDN_CAPI_CAPIFS_BOOL=y \
+    CONFIG_ISDN_AUDIO=y \
+    CONFIG_ISDN_TTY_FAX=y \
+    CONFIG_ISDN_X25=y \
+    CONFIG_ISDN_DIVERSION
+  FILES:= \
+    $(LINUX_DIR)/drivers/isdn/divert/dss1_divert.ko \
+	$(LINUX_DIR)/drivers/isdn/i4l/isdn.ko \
+	$(LINUX_DIR)/drivers/isdn/i4l/isdn_bsdcomp.ko
+  AUTOLOAD:=$(call AutoLoad,40,isdn isdn_bsdcomp dss1_divert)
+endef
+
+define KernelPackage/isdn4linux/description
+  This driver allows you to use an ISDN adapter for networking
+endef
+
+$(eval $(call KernelPackage,isdn4linux))
+
+
+define KernelPackage/ipip
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IP-in-IP encapsulation
+  DEPENDS:=+kmod-iptunnel +kmod-iptunnel4
+  KCONFIG:=CONFIG_NET_IPIP
+  FILES:=$(LINUX_DIR)/net/ipv4/ipip.ko
+  AUTOLOAD:=$(call AutoLoad,32,ipip)
+endef
+
+define KernelPackage/ipip/description
+ Kernel modules for IP-in-IP encapsulation
+endef
+
+$(eval $(call KernelPackage,ipip))
+
+
+IPSEC-m:= \
+	xfrm/xfrm_algo \
+	xfrm/xfrm_ipcomp \
+	xfrm/xfrm_user \
+	key/af_key \
+
+define KernelPackage/ipsec
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPsec related modules (IPv4 and IPv6)
+  DEPENDS:= \
+	+kmod-crypto-authenc +kmod-crypto-cbc +kmod-crypto-deflate \
+	+kmod-crypto-des +kmod-crypto-echainiv +kmod-crypto-hmac \
+	+kmod-crypto-iv +kmod-crypto-md5 +kmod-crypto-sha1
+  KCONFIG:= \
+	CONFIG_NET_KEY \
+	CONFIG_XFRM_USER \
+	CONFIG_INET_IPCOMP \
+	CONFIG_XFRM_IPCOMP
+  FILES:=$(foreach mod,$(IPSEC-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,30,$(notdir $(IPSEC-m)))
+endef
+
+define KernelPackage/ipsec/description
+ Kernel modules for IPsec support in both IPv4 and IPv6.
+ Includes:
+ - af_key
+ - xfrm_algo
+ - xfrm_ipcomp
+ - xfrm_user
+endef
+
+$(eval $(call KernelPackage,ipsec))
+
+
+IPSEC4-m:= \
+	ipv4/ah4 \
+	ipv4/esp4 \
+	ipv4/xfrm4_mode_beet \
+	ipv4/xfrm4_mode_transport \
+	ipv4/xfrm4_mode_tunnel \
+	ipv4/xfrm4_tunnel \
+	ipv4/ipcomp \
+
+define KernelPackage/ipsec4
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPsec related modules (IPv4)
+  DEPENDS:=kmod-ipsec +kmod-iptunnel4
+  KCONFIG:= \
+	CONFIG_INET_AH \
+	CONFIG_INET_ESP \
+	CONFIG_INET_IPCOMP \
+	CONFIG_INET_XFRM_MODE_BEET \
+	CONFIG_INET_XFRM_MODE_TRANSPORT \
+	CONFIG_INET_XFRM_MODE_TUNNEL \
+	CONFIG_INET_XFRM_TUNNEL
+  FILES:=$(foreach mod,$(IPSEC4-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,32,$(notdir $(IPSEC4-m)))
+endef
+
+define KernelPackage/ipsec4/description
+ Kernel modules for IPsec support in IPv4.
+ Includes:
+ - ah4
+ - esp4
+ - ipcomp4
+ - xfrm4_mode_beet
+ - xfrm4_mode_transport
+ - xfrm4_mode_tunnel
+ - xfrm4_tunnel
+endef
+
+$(eval $(call KernelPackage,ipsec4))
+
+
+IPSEC6-m:= \
+	ipv6/ah6 \
+	ipv6/esp6 \
+	ipv6/xfrm6_mode_beet \
+	ipv6/xfrm6_mode_transport \
+	ipv6/xfrm6_mode_tunnel \
+	ipv6/xfrm6_tunnel \
+	ipv6/ipcomp6 \
+
+define KernelPackage/ipsec6
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPsec related modules (IPv6)
+  DEPENDS:=kmod-ipsec +kmod-iptunnel6
+  KCONFIG:= \
+	CONFIG_INET6_AH \
+	CONFIG_INET6_ESP \
+	CONFIG_INET6_IPCOMP \
+	CONFIG_INET6_XFRM_MODE_BEET \
+	CONFIG_INET6_XFRM_MODE_TRANSPORT \
+	CONFIG_INET6_XFRM_MODE_TUNNEL \
+	CONFIG_INET6_XFRM_TUNNEL
+  FILES:=$(foreach mod,$(IPSEC6-m),$(LINUX_DIR)/net/$(mod).ko)
+  AUTOLOAD:=$(call AutoLoad,32,$(notdir $(IPSEC6-m)))
+endef
+
+define KernelPackage/ipsec6/description
+ Kernel modules for IPsec support in IPv6.
+ Includes:
+ - ah6
+ - esp6
+ - ipcomp6
+ - xfrm6_mode_beet
+ - xfrm6_mode_transport
+ - xfrm6_mode_tunnel
+ - xfrm6_tunnel
+endef
+
+$(eval $(call KernelPackage,ipsec6))
+
+
+define KernelPackage/iptunnel
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IP tunnel support
+  HIDDEN:=1
+  KCONFIG:= \
+	CONFIG_NET_IP_TUNNEL
+  FILES:=$(LINUX_DIR)/net/ipv4/ip_tunnel.ko
+  AUTOLOAD:=$(call AutoLoad,31,ip_tunnel)
+endef
+
+define KernelPackage/iptunnel/description
+ Kernel module for generic IP tunnel support
+endef
+
+$(eval $(call KernelPackage,iptunnel))
+
+
+define KernelPackage/ip-vti
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IP VTI (Virtual Tunnel Interface)
+  DEPENDS:=+kmod-iptunnel +kmod-iptunnel4 +kmod-ipsec4
+  KCONFIG:=CONFIG_NET_IPVTI
+  FILES:=$(LINUX_DIR)/net/ipv4/ip_vti.ko
+  AUTOLOAD:=$(call AutoLoad,33,ip_vti)
+endef
+
+define KernelPackage/ip-vti/description
+ Kernel modules for IP VTI (Virtual Tunnel Interface)
+endef
+
+$(eval $(call KernelPackage,ip-vti))
+
+
+define KernelPackage/ip6-vti
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPv6 VTI (Virtual Tunnel Interface)
+  DEPENDS:=+kmod-iptunnel +kmod-ip6-tunnel +kmod-ipsec6
+  KCONFIG:=CONFIG_IPV6_VTI
+  FILES:=$(LINUX_DIR)/net/ipv6/ip6_vti.ko
+  AUTOLOAD:=$(call AutoLoad,33,ip6_vti)
+endef
+
+define KernelPackage/ip6-vti/description
+ Kernel modules for IPv6 VTI (Virtual Tunnel Interface)
+endef
+
+$(eval $(call KernelPackage,ip6-vti))
+
+
+define KernelPackage/iptunnel4
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPv4 tunneling
+  HIDDEN:=1
+  KCONFIG:= \
+	CONFIG_INET_TUNNEL \
+	CONFIG_NET_IPIP=m
+  FILES:=$(LINUX_DIR)/net/ipv4/tunnel4.ko
+  AUTOLOAD:=$(call AutoLoad,31,tunnel4)
+endef
+
+define KernelPackage/iptunnel4/description
+ Kernel modules for IPv4 tunneling
+endef
+
+$(eval $(call KernelPackage,iptunnel4))
+
+
+define KernelPackage/iptunnel6
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPv6 tunneling
+  DEPENDS:=@IPV6
+  KCONFIG:= \
+	CONFIG_INET6_TUNNEL
+  FILES:=$(LINUX_DIR)/net/ipv6/tunnel6.ko
+  AUTOLOAD:=$(call AutoLoad,31,tunnel6)
+endef
+
+define KernelPackage/iptunnel6/description
+ Kernel modules for IPv6 tunneling
+endef
+
+$(eval $(call KernelPackage,iptunnel6))
+
+
+define KernelPackage/sit
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  DEPENDS:=@IPV6 +kmod-iptunnel +kmod-iptunnel4
+  TITLE:=IPv6-in-IPv4 tunnel
+  KCONFIG:=CONFIG_IPV6_SIT \
+	CONFIG_IPV6_SIT_6RD=y
+  FILES:=$(LINUX_DIR)/net/ipv6/sit.ko
+  AUTOLOAD:=$(call AutoLoad,32,sit)
+endef
+
+define KernelPackage/sit/description
+ Kernel modules for IPv6-in-IPv4 tunnelling
+endef
+
+$(eval $(call KernelPackage,sit))
+
+
+define KernelPackage/ip6-tunnel
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IP-in-IPv6 tunnelling
+  DEPENDS:=@IPV6 +kmod-iptunnel6
+  KCONFIG:= CONFIG_IPV6_TUNNEL
+  FILES:=$(LINUX_DIR)/net/ipv6/ip6_tunnel.ko
+  AUTOLOAD:=$(call AutoLoad,32,ip6_tunnel)
+endef
+
+define KernelPackage/ip6-tunnel/description
+ Kernel modules for IPv6-in-IPv6 and IPv4-in-IPv6 tunnelling
+endef
+
+$(eval $(call KernelPackage,ip6-tunnel))
+
+
+define KernelPackage/gre
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=GRE support
+  DEPENDS:=+kmod-iptunnel
+  KCONFIG:=CONFIG_NET_IPGRE CONFIG_NET_IPGRE_DEMUX
+  FILES:=$(LINUX_DIR)/net/ipv4/ip_gre.ko $(LINUX_DIR)/net/ipv4/gre.ko
+  AUTOLOAD:=$(call AutoLoad,39,gre ip_gre)
+endef
+
+define KernelPackage/gre/description
+ Generic Routing Encapsulation support
+endef
+
+$(eval $(call KernelPackage,gre))
+
+
+define KernelPackage/gre6
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=GRE support over IPV6
+  DEPENDS:=@IPV6 +kmod-iptunnel +kmod-ip6-tunnel
+  KCONFIG:=CONFIG_IPV6_GRE
+  FILES:=$(LINUX_DIR)/net/ipv6/ip6_gre.ko
+  AUTOLOAD:=$(call AutoLoad,39,ip6_gre)
+endef
+
+define KernelPackage/gre6/description
+ Generic Routing Encapsulation support over IPv6
+endef
+
+$(eval $(call KernelPackage,gre6))
+
+
+define KernelPackage/tun
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Universal TUN/TAP driver
+  KCONFIG:=CONFIG_TUN
+  FILES:=$(LINUX_DIR)/drivers/net/tun.ko
+  AUTOLOAD:=$(call AutoLoad,30,tun)
+endef
+
+define KernelPackage/tun/description
+ Kernel support for the TUN/TAP tunneling device
+endef
+
+$(eval $(call KernelPackage,tun))
+
+
+define KernelPackage/veth
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Virtual ethernet pair device
+  KCONFIG:=CONFIG_VETH
+  FILES:=$(LINUX_DIR)/drivers/net/veth.ko
+  AUTOLOAD:=$(call AutoLoad,30,veth)
+endef
+
+define KernelPackage/veth/description
+ This device is a local ethernet tunnel. Devices are created in pairs.
+ When one end receives the packet it appears on its pair and vice
+ versa.
+endef
+
+$(eval $(call KernelPackage,veth))
+
+
+define KernelPackage/slhc
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  HIDDEN:=1
+  TITLE:=Serial Line Header Compression
+  DEPENDS:=+kmod-lib-crc-ccitt
+  KCONFIG:=CONFIG_SLHC
+  FILES:=$(LINUX_DIR)/drivers/net/slip/slhc.ko
+endef
+
+$(eval $(call KernelPackage,slhc))
+
+
+define KernelPackage/ppp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPP modules
+  DEPENDS:=+kmod-lib-crc-ccitt +kmod-slhc
+  KCONFIG:= \
+	CONFIG_PPP \
+	CONFIG_PPP_ASYNC
+  FILES:= \
+	$(LINUX_DIR)/drivers/net/ppp/ppp_async.ko \
+	$(LINUX_DIR)/drivers/net/ppp/ppp_generic.ko
+  AUTOLOAD:=$(call AutoProbe,ppp_async)
+endef
+
+define KernelPackage/ppp/description
+ Kernel modules for PPP support
+endef
+
+$(eval $(call KernelPackage,ppp))
+
+
+define KernelPackage/ppp-synctty
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPP sync tty support
+  DEPENDS:=kmod-ppp
+  KCONFIG:=CONFIG_PPP_SYNC_TTY
+  FILES:=$(LINUX_DIR)/drivers/net/ppp/ppp_synctty.ko
+  AUTOLOAD:=$(call AutoProbe,ppp_synctty)
+endef
+
+define KernelPackage/ppp-synctty/description
+ Kernel modules for PPP sync tty support
+endef
+
+$(eval $(call KernelPackage,ppp-synctty))
+
+
+define KernelPackage/pppox
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPPoX helper
+  DEPENDS:=kmod-ppp
+  KCONFIG:=CONFIG_PPPOE
+  FILES:=$(LINUX_DIR)/drivers/net/ppp/pppox.ko
+endef
+
+define KernelPackage/pppox/description
+ Kernel helper module for PPPoE and PPTP support
+endef
+
+$(eval $(call KernelPackage,pppox))
+
+
+define KernelPackage/pppoe
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPPoE support
+  DEPENDS:=kmod-ppp +kmod-pppox
+  KCONFIG:=CONFIG_PPPOE
+  FILES:=$(LINUX_DIR)/drivers/net/ppp/pppoe.ko
+  AUTOLOAD:=$(call AutoProbe,pppoe)
+endef
+
+define KernelPackage/pppoe/description
+ Kernel module for PPPoE (PPP over Ethernet) support
+endef
+
+$(eval $(call KernelPackage,pppoe))
+
+
+define KernelPackage/pppoa
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPPoA support
+  DEPENDS:=kmod-ppp +kmod-atm
+  KCONFIG:=CONFIG_PPPOATM CONFIG_ATM_DRIVERS=y
+  FILES:=$(LINUX_DIR)/net/atm/pppoatm.ko
+  AUTOLOAD:=$(call AutoLoad,40,pppoatm)
+endef
+
+define KernelPackage/pppoa/description
+ Kernel modules for PPPoA (PPP over ATM) support
+endef
+
+$(eval $(call KernelPackage,pppoa))
+
+
+define KernelPackage/pptp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPtP support
+  DEPENDS:=kmod-ppp +kmod-gre +kmod-pppox
+  KCONFIG:=CONFIG_PPTP
+  FILES:=$(LINUX_DIR)/drivers/net/ppp/pptp.ko
+  AUTOLOAD:=$(call AutoProbe,pptp)
+endef
+
+$(eval $(call KernelPackage,pptp))
+
+
+define KernelPackage/pppol2tp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=PPPoL2TP support
+  DEPENDS:=kmod-ppp +kmod-pppox +kmod-l2tp
+  KCONFIG:=CONFIG_PPPOL2TP
+  FILES:=$(LINUX_DIR)/net/l2tp/l2tp_ppp.ko
+  AUTOLOAD:=$(call AutoProbe,l2tp_ppp)
+endef
+
+define KernelPackage/pppol2tp/description
+  Kernel modules for PPPoL2TP (PPP over L2TP) support
+endef
+
+$(eval $(call KernelPackage,pppol2tp))
+
+
+define KernelPackage/ipoa
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=IPoA support
+  DEPENDS:=kmod-atm
+  KCONFIG:=CONFIG_ATM_CLIP
+  FILES:=$(LINUX_DIR)/net/atm/clip.ko
+  AUTOLOAD:=$(call AutoProbe,clip)
+endef
+
+define KernelPackage/ipoa/description
+  Kernel modules for IPoA (IP over ATM) support
+endef
+
+$(eval $(call KernelPackage,ipoa))
+
+
+define KernelPackage/mppe
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Microsoft PPP compression/encryption
+  DEPENDS:=kmod-ppp +kmod-crypto-sha1 +kmod-crypto-ecb
+  KCONFIG:= \
+	CONFIG_PPP_MPPE_MPPC \
+	CONFIG_PPP_MPPE
+  FILES:=$(LINUX_DIR)/drivers/net/ppp/ppp_mppe.ko
+  AUTOLOAD:=$(call AutoProbe,ppp_mppe)
+endef
+
+define KernelPackage/mppe/description
+ Kernel modules for Microsoft PPP compression/encryption
+endef
+
+$(eval $(call KernelPackage,mppe))
+
+
+SCHED_MODULES = $(patsubst $(LINUX_DIR)/net/sched/%.ko,%,$(wildcard $(LINUX_DIR)/net/sched/*.ko))
+SCHED_MODULES_CORE = sch_ingress sch_fq_codel sch_hfsc cls_fw cls_route cls_flow cls_tcindex cls_u32 em_u32 act_mirred act_skbedit
+SCHED_MODULES_FILTER = $(SCHED_MODULES_CORE) act_connmark sch_netem
+SCHED_MODULES_EXTRA = $(filter-out $(SCHED_MODULES_FILTER),$(SCHED_MODULES))
+SCHED_FILES = $(patsubst %,$(LINUX_DIR)/net/sched/%.ko,$(filter $(SCHED_MODULES_CORE),$(SCHED_MODULES)))
+SCHED_FILES_EXTRA = $(patsubst %,$(LINUX_DIR)/net/sched/%.ko,$(SCHED_MODULES_EXTRA))
+
+define KernelPackage/sched-core
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Traffic schedulers
+  KCONFIG:= \
+	CONFIG_NET_SCHED=y \
+	CONFIG_NET_SCH_HFSC \
+	CONFIG_NET_SCH_INGRESS \
+	CONFIG_NET_SCH_FQ_CODEL \
+	CONFIG_NET_CLS=y \
+	CONFIG_NET_CLS_ACT=y \
+	CONFIG_NET_CLS_FLOW \
+	CONFIG_NET_CLS_FW \
+	CONFIG_NET_CLS_ROUTE4 \
+	CONFIG_NET_CLS_TCINDEX \
+	CONFIG_NET_CLS_U32 \
+	CONFIG_NET_ACT_MIRRED \
+	CONFIG_NET_ACT_SKBEDIT \
+	CONFIG_NET_EMATCH=y \
+	CONFIG_NET_EMATCH_U32
+  FILES:=$(SCHED_FILES)
+  AUTOLOAD:=$(call AutoLoad,70, $(SCHED_MODULES_CORE))
+endef
+
+define KernelPackage/sched-core/description
+ Core kernel scheduler support for IP traffic
+endef
+
+$(eval $(call KernelPackage,sched-core))
+
+
+define KernelPackage/sched-connmark
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Traffic shaper conntrack mark support
+  DEPENDS:=+kmod-sched-core +kmod-ipt-core +kmod-ipt-conntrack-extra
+  KCONFIG:=CONFIG_NET_ACT_CONNMARK
+  FILES:=$(LINUX_DIR)/net/sched/act_connmark.ko
+  AUTOLOAD:=$(call AutoLoad,71, act_connmark)
+endef
+$(eval $(call KernelPackage,sched-connmark))
+
+define KernelPackage/sched
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Extra traffic schedulers
+  DEPENDS:=+kmod-sched-core +kmod-ipt-core
+  KCONFIG:= \
+	CONFIG_NET_SCH_CODEL \
+	CONFIG_NET_SCH_DSMARK \
+	CONFIG_NET_SCH_HTB \
+	CONFIG_NET_SCH_FIFO \
+	CONFIG_NET_SCH_GRED \
+	CONFIG_NET_SCH_PRIO \
+	CONFIG_NET_SCH_RED \
+	CONFIG_NET_SCH_TBF \
+	CONFIG_NET_SCH_SFQ \
+	CONFIG_NET_SCH_TEQL \
+	CONFIG_NET_SCH_FQ \
+	CONFIG_NET_SCH_PIE \
+	CONFIG_NET_CLS_BASIC \
+	CONFIG_NET_ACT_POLICE \
+	CONFIG_NET_ACT_IPT \
+	CONFIG_NET_EMATCH_CMP \
+	CONFIG_NET_EMATCH_NBYTE \
+	CONFIG_NET_EMATCH_META \
+	CONFIG_NET_EMATCH_TEXT
+  FILES:=$(SCHED_FILES_EXTRA)
+  AUTOLOAD:=$(call AutoLoad,73, $(SCHED_MODULES_EXTRA))
+endef
+
+define KernelPackage/sched/description
+ Extra kernel schedulers modules for IP traffic
+endef
+
+$(eval $(call KernelPackage,sched))
+
+
+define KernelPackage/ax25
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=AX25 support
+  DEPENDS:=+kmod-lib-crc16
+  KCONFIG:= \
+	CONFIG_HAMRADIO=y \
+	CONFIG_AX25 \
+	CONFIG_MKISS
+  FILES:= \
+	$(LINUX_DIR)/net/ax25/ax25.ko \
+	$(LINUX_DIR)/drivers/net/hamradio/mkiss.ko
+  AUTOLOAD:=$(call AutoLoad,80,ax25 mkiss)
+endef
+
+define KernelPackage/ax25/description
+ Kernel modules for AX25 support
+endef
+
+$(eval $(call KernelPackage,ax25))
+
+
+define KernelPackage/pktgen
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  DEPENDS:=@!TARGET_uml
+  TITLE:=Network packet generator
+  KCONFIG:=CONFIG_NET_PKTGEN
+  FILES:=$(LINUX_DIR)/net/core/pktgen.ko
+  AUTOLOAD:=$(call AutoLoad,99,pktgen)
+endef
+
+define KernelPackage/pktgen/description
+  Kernel modules for the Network Packet Generator
+endef
+
+$(eval $(call KernelPackage,pktgen))
+
+define KernelPackage/l2tp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Layer Two Tunneling Protocol (L2TP)
+  DEPENDS:= \
+	+kmod-udptunnel4 \
+	+IPV6:kmod-udptunnel6
+  KCONFIG:=CONFIG_L2TP \
+	CONFIG_L2TP_V3=y \
+	CONFIG_L2TP_DEBUGFS=n
+  FILES:=$(LINUX_DIR)/net/l2tp/l2tp_core.ko \
+	$(LINUX_DIR)/net/l2tp/l2tp_netlink.ko
+  AUTOLOAD:=$(call AutoLoad,32,l2tp_core l2tp_netlink)
+endef
+
+define KernelPackage/l2tp/description
+ Kernel modules for L2TP V3 Support
+endef
+
+$(eval $(call KernelPackage,l2tp))
+
+
+define KernelPackage/l2tp-eth
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=L2TP ethernet pseudowire support for L2TPv3
+  DEPENDS:=+kmod-l2tp
+  KCONFIG:=CONFIG_L2TP_ETH
+  FILES:=$(LINUX_DIR)/net/l2tp/l2tp_eth.ko
+  AUTOLOAD:=$(call AutoLoad,33,l2tp_eth)
+endef
+
+define KernelPackage/l2tp-eth/description
+ Kernel modules for L2TP ethernet pseudowire support for L2TPv3
+endef
+
+$(eval $(call KernelPackage,l2tp-eth))
+
+define KernelPackage/l2tp-ip
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=L2TP IP encapsulation for L2TPv3
+  DEPENDS:=+kmod-l2tp
+  KCONFIG:=CONFIG_L2TP_IP
+  FILES:= \
+	$(LINUX_DIR)/net/l2tp/l2tp_ip.ko \
+	$(if $(CONFIG_IPV6),$(LINUX_DIR)/net/l2tp/l2tp_ip6.ko)
+  AUTOLOAD:=$(call AutoLoad,33,l2tp_ip $(if $(CONFIG_IPV6),l2tp_ip6))
+endef
+
+define KernelPackage/l2tp-ip/description
+ Kernel modules for L2TP IP encapsulation for L2TPv3
+endef
+
+$(eval $(call KernelPackage,l2tp-ip))
+
+
+define KernelPackage/sctp
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=SCTP protocol kernel support
+  KCONFIG:=\
+     CONFIG_IP_SCTP \
+     CONFIG_SCTP_DBG_MSG=n \
+     CONFIG_SCTP_DBG_OBJCNT=n \
+     CONFIG_SCTP_HMAC_NONE=n \
+     CONFIG_SCTP_HMAC_SHA1=n \
+     CONFIG_SCTP_HMAC_MD5=y \
+     CONFIG_SCTP_COOKIE_HMAC_SHA1=n \
+     CONFIG_SCTP_COOKIE_HMAC_MD5=y \
+     CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=n \
+     CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=n \
+     CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y
+  FILES:= $(LINUX_DIR)/net/sctp/sctp.ko
+  AUTOLOAD:= $(call AutoLoad,32,sctp)
+  DEPENDS:=+kmod-lib-crc32c +kmod-crypto-md5 +kmod-crypto-hmac
+endef
+
+define KernelPackage/sctp/description
+ Kernel modules for SCTP protocol support
+endef
+
+$(eval $(call KernelPackage,sctp))
+
+
+define KernelPackage/netem
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Network emulation functionality
+  DEPENDS:=+kmod-sched
+  KCONFIG:=CONFIG_NET_SCH_NETEM
+  FILES:=$(LINUX_DIR)/net/sched/sch_netem.ko
+  AUTOLOAD:=$(call AutoLoad,99,netem)
+endef
+
+define KernelPackage/netem/description
+  Kernel modules for emulating the properties of wide area networks
+endef
+
+$(eval $(call KernelPackage,netem))
+
+define KernelPackage/slip
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  DEPENDS:=+kmod-slhc
+  TITLE:=SLIP modules
+  KCONFIG:= \
+       CONFIG_SLIP \
+       CONFIG_SLIP_COMPRESSED=y \
+       CONFIG_SLIP_SMART=y \
+       CONFIG_SLIP_MODE_SLIP6=y
+
+  FILES:= \
+       $(LINUX_DIR)/drivers/net/slip/slip.ko
+  AUTOLOAD:=$(call AutoLoad,30,slip)
+endef
+
+define KernelPackage/slip/description
+ Kernel modules for SLIP support
+endef
+
+$(eval $(call KernelPackage,slip))
+
+define KernelPackage/dnsresolver
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=In-kernel DNS Resolver
+  KCONFIG:= CONFIG_DNS_RESOLVER
+  FILES:=$(LINUX_DIR)/net/dns_resolver/dns_resolver.ko
+  AUTOLOAD:=$(call AutoLoad,30,dns_resolver)
+endef
+
+$(eval $(call KernelPackage,dnsresolver))
+
+define KernelPackage/rxrpc
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=AF_RXRPC support
+  HIDDEN:=1
+  KCONFIG:= \
+	CONFIG_AF_RXRPC \
+	CONFIG_RXKAD=m \
+	CONFIG_AF_RXRPC_DEBUG=n
+  FILES:= \
+	$(LINUX_DIR)/net/rxrpc/af-rxrpc.ko \
+	$(LINUX_DIR)/net/rxrpc/rxkad.ko
+  AUTOLOAD:=$(call AutoLoad,30,rxkad af-rxrpc)
+  DEPENDS:= +kmod-crypto-manager +kmod-crypto-pcbc +kmod-crypto-fcrypt
+endef
+
+define KernelPackage/rxrpc/description
+  Kernel support for AF_RXRPC; required for AFS client
+endef
+
+$(eval $(call KernelPackage,rxrpc))
+
+define KernelPackage/mpls
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=MPLS support
+  DEPENDS:=@!(LINUX_3_18||LINUX_4_1)
+  KCONFIG:= \
+	CONFIG_MPLS=y \
+	CONFIG_LWTUNNEL=y \
+	CONFIG_NET_MPLS_GSO=m \
+	CONFIG_MPLS_ROUTING=m \
+	CONFIG_MPLS_IPTUNNEL=m
+  FILES:= \
+	$(LINUX_DIR)/net/mpls/mpls_gso.ko \
+	$(LINUX_DIR)/net/mpls/mpls_iptunnel.ko \
+	$(LINUX_DIR)/net/mpls/mpls_router.ko
+  AUTOLOAD:=$(call AutoLoad,30,mpls_router mpls_iptunnel mpls_gso)
+endef
+
+define KernelPackage/mpls/description
+  Kernel support for MPLS
+endef
+
+$(eval $(call KernelPackage,mpls))
+
+define KernelPackage/9pnet
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Plan 9 Resource Sharing Support (9P2000)
+  DEPENDS:=@VIRTIO_SUPPORT
+  KCONFIG:= \
+	CONFIG_NET_9P \
+	CONFIG_NET_9P_DEBUG=n \
+	CONFIG_NET_9P_VIRTIO
+  FILES:= \
+	$(LINUX_DIR)/net/9p/9pnet.ko \
+	$(LINUX_DIR)/net/9p/9pnet_virtio.ko
+  AUTOLOAD:=$(call AutoLoad,29,9pnet 9pnet_virtio)
+endef
+
+define KernelPackage/9pnet/description
+  Kernel support support for
+  Plan 9 resource sharing via the 9P2000 protocol.
+endef
+
+$(eval $(call KernelPackage,9pnet))
+
+
+define KernelPackage/nlmon
+  SUBMENU:=$(NETWORK_SUPPORT_MENU)
+  TITLE:=Virtual netlink monitoring device
+  KCONFIG:=CONFIG_NLMON
+  FILES:=$(LINUX_DIR)/drivers/net/nlmon.ko
+  AUTOLOAD:=$(call AutoProbe,nlmon)
+endef
+
+define KernelPackage/nlmon/description
+  Kernel module which adds a monitoring device for netlink.
+endef
+
+$(eval $(call KernelPackage,nlmon))
diff --git a/package/kernel/linux/modules/nls.mk b/package/kernel/linux/modules/nls.mk
new file mode 100644
index 0000000000..55c5c1a8a8
--- /dev/null
+++ b/package/kernel/linux/modules/nls.mk
@@ -0,0 +1,307 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define KernelPackage/nls-base
+  SUBMENU:=Native Language Support
+  TITLE:=Native Language Support
+  KCONFIG:=CONFIG_NLS
+  FILES:=$(LINUX_DIR)/fs/nls/nls_base.ko
+endef
+
+define KernelPackage/nls-base/description
+ Kernel module for NLS (Native Language Support)
+endef
+
+$(eval $(call KernelPackage,nls-base))
+
+
+define KernelPackage/nls-cp437
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 437 (United States, Canada)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_437
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp437.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp437)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp437/description
+ Kernel module for NLS Codepage 437 (United States, Canada)
+endef
+
+$(eval $(call KernelPackage,nls-cp437))
+
+
+define KernelPackage/nls-cp775
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 775 (Baltic Rim)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_775
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp775.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp775)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp775/description
+ Kernel module for NLS Codepage 775 (Baltic Rim)
+endef
+
+$(eval $(call KernelPackage,nls-cp775))
+
+
+define KernelPackage/nls-cp850
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 850 (Europe)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_850
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp850.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp850)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp850/description
+ Kernel module for NLS Codepage 850 (Europe)
+endef
+
+$(eval $(call KernelPackage,nls-cp850))
+
+
+define KernelPackage/nls-cp852
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 852 (Europe)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_852
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp852.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp852)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp852/description
+ Kernel module for NLS Codepage 852 (Europe)
+endef
+
+$(eval $(call KernelPackage,nls-cp852))
+
+
+define KernelPackage/nls-cp862
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 862 (Hebrew)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_862
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp862.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp862)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp862/description
+  Kernel module for NLS Codepage 862 (Hebrew)
+endef
+
+$(eval $(call KernelPackage,nls-cp862))
+
+
+define KernelPackage/nls-cp864
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 864 (Arabic)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_864
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp864.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp864)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp864/description
+  Kernel module for NLS Codepage 864 (Arabic)
+endef
+
+$(eval $(call KernelPackage,nls-cp864))
+
+
+define KernelPackage/nls-cp866
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 866 (Cyrillic)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_866
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp866.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp866)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp866/description
+  Kernel module for NLS Codepage 866 (Cyrillic)
+endef
+
+$(eval $(call KernelPackage,nls-cp866))
+
+
+define KernelPackage/nls-cp932
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 932 (Japanese)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_932
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp932.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp932)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp932/description
+  Kernel module for NLS Codepage 932 (Japanese)
+endef
+
+$(eval $(call KernelPackage,nls-cp932))
+
+
+define KernelPackage/nls-cp1250
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 1250 (Eastern Europe)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_1250
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp1250.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp1250)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp1250/description
+ Kernel module for NLS Codepage 1250 (Eastern Europe)
+endef
+
+$(eval $(call KernelPackage,nls-cp1250))
+
+
+define KernelPackage/nls-cp1251
+  SUBMENU:=Native Language Support
+  TITLE:=Codepage 1251 (Russian)
+  KCONFIG:=CONFIG_NLS_CODEPAGE_1251
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp1251.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp1251)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-cp1251/description
+ Kernel module for NLS Codepage 1251 (Russian)
+endef
+
+$(eval $(call KernelPackage,nls-cp1251))
+
+
+define KernelPackage/nls-iso8859-1
+  SUBMENU:=Native Language Support
+  TITLE:=ISO 8859-1 (Latin 1; Western European Languages)
+  KCONFIG:=CONFIG_NLS_ISO8859_1
+  FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-1.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-1)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-iso8859-1/description
+ Kernel module for NLS ISO 8859-1 (Latin 1)
+endef
+
+$(eval $(call KernelPackage,nls-iso8859-1))
+
+
+define KernelPackage/nls-iso8859-2
+  SUBMENU:=Native Language Support
+  TITLE:=ISO 8859-2 (Latin 2; Central European Languages)
+  KCONFIG:=CONFIG_NLS_ISO8859_2
+  FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-2.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-2)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-iso8859-2/description
+ Kernel module for NLS ISO 8859-2 (Latin 2)
+endef
+
+$(eval $(call KernelPackage,nls-iso8859-2))
+
+
+define KernelPackage/nls-iso8859-6
+  SUBMENU:=Native Language Support
+  TITLE:=ISO 8859-6 (Arabic)
+  KCONFIG:=CONFIG_NLS_ISO8859_6
+  FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-6.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-6)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-iso8859-6/description
+ Kernel module for NLS ISO 8859-6 (Arabic)
+endef
+
+$(eval $(call KernelPackage,nls-iso8859-6))
+
+
+define KernelPackage/nls-iso8859-8
+  SUBMENU:=Native Language Support
+  TITLE:=ISO 8859-8, CP1255 (Hebrew)
+  KCONFIG:=CONFIG_NLS_ISO8859_8
+  FILES:=$(LINUX_DIR)/fs/nls/nls_cp1255.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_cp1255)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-iso8859-8/description
+ Kernel module for Hebrew charsets (ISO-8859-8, CP1255)
+endef
+
+$(eval $(call KernelPackage,nls-iso8859-8))
+
+
+define KernelPackage/nls-iso8859-13
+  SUBMENU:=Native Language Support
+  TITLE:=ISO 8859-13 (Latin 7; Baltic)
+  KCONFIG:=CONFIG_NLS_ISO8859_13
+  FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-13.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-13)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-iso8859-13/description
+ Kernel module for NLS ISO 8859-13 (Latin 7; Baltic)
+endef
+
+$(eval $(call KernelPackage,nls-iso8859-13))
+
+
+define KernelPackage/nls-iso8859-15
+  SUBMENU:=Native Language Support
+  TITLE:=ISO 8859-15 (Latin 9; Western, with Euro symbol)
+  KCONFIG:=CONFIG_NLS_ISO8859_15
+  FILES:=$(LINUX_DIR)/fs/nls/nls_iso8859-15.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_iso8859-15)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-iso8859-15/description
+ Kernel module for NLS ISO 8859-15 (Latin 9)
+endef
+
+$(eval $(call KernelPackage,nls-iso8859-15))
+
+
+define KernelPackage/nls-koi8r
+  SUBMENU:=Native Language Support
+  TITLE:=KOI8-R (Russian)
+  KCONFIG:=CONFIG_NLS_KOI8_R
+  FILES:=$(LINUX_DIR)/fs/nls/nls_koi8-r.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_koi8-r)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-koi8r/description
+ Kernel module for NLS KOI8-R (Russian)
+endef
+
+$(eval $(call KernelPackage,nls-koi8r))
+
+
+define KernelPackage/nls-utf8
+  SUBMENU:=Native Language Support
+  TITLE:=UTF-8
+  KCONFIG:=CONFIG_NLS_UTF8
+  FILES:=$(LINUX_DIR)/fs/nls/nls_utf8.ko
+  AUTOLOAD:=$(call AutoLoad,25,nls_utf8)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/nls-utf8/description
+ Kernel module for NLS UTF-8
+endef
+
+$(eval $(call KernelPackage,nls-utf8))
diff --git a/package/kernel/linux/modules/other.mk b/package/kernel/linux/modules/other.mk
new file mode 100644
index 0000000000..e1b1e16d1d
--- /dev/null
+++ b/package/kernel/linux/modules/other.mk
@@ -0,0 +1,1074 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+OTHER_MENU:=Other modules
+
+WATCHDOG_DIR:=watchdog
+
+
+define KernelPackage/6lowpan
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=6LoWPAN shared code
+  KCONFIG:= \
+	CONFIG_6LOWPAN \
+	CONFIG_6LOWPAN_NHC=n
+  FILES:=$(LINUX_DIR)/net/6lowpan/6lowpan.ko
+  AUTOLOAD:=$(call AutoProbe,6lowpan)
+endef
+
+define KernelPackage/6lowpan/description
+  Shared 6lowpan code for IEEE 802.15.4 and Bluetooth.
+endef
+
+$(eval $(call KernelPackage,6lowpan))
+
+
+define KernelPackage/bluetooth
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Bluetooth support
+  DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-crypto-hash +kmod-crypto-ecb +kmod-lib-crc16 +kmod-hid +!LINUX_3_18:kmod-crypto-cmac +LINUX_4_4:kmod-regmap
+  KCONFIG:= \
+	CONFIG_BLUEZ \
+	CONFIG_BLUEZ_L2CAP \
+	CONFIG_BLUEZ_SCO \
+	CONFIG_BLUEZ_RFCOMM \
+	CONFIG_BLUEZ_BNEP \
+	CONFIG_BLUEZ_HCIUART \
+	CONFIG_BLUEZ_HCIUSB \
+	CONFIG_BLUEZ_HIDP \
+	CONFIG_BT \
+	CONFIG_BT_BREDR=y \
+	CONFIG_BT_DEBUGFS=n \
+	CONFIG_BT_L2CAP=y \
+	CONFIG_BT_LE=y \
+	CONFIG_BT_SCO=y \
+	CONFIG_BT_RFCOMM \
+	CONFIG_BT_BNEP \
+	CONFIG_BT_HCIBTUSB \
+	CONFIG_BT_HCIBTUSB_BCM=n \
+	CONFIG_BT_HCIUSB \
+	CONFIG_BT_HCIUART \
+	CONFIG_BT_HCIUART_BCM=n \
+	CONFIG_BT_HCIUART_INTEL=n \
+	CONFIG_BT_HCIUART_H4 \
+	CONFIG_BT_HIDP \
+	CONFIG_HID_SUPPORT=y
+  $(call AddDepends/rfkill)
+  FILES:= \
+	$(LINUX_DIR)/net/bluetooth/bluetooth.ko \
+	$(LINUX_DIR)/net/bluetooth/rfcomm/rfcomm.ko \
+	$(LINUX_DIR)/net/bluetooth/bnep/bnep.ko \
+	$(LINUX_DIR)/net/bluetooth/hidp/hidp.ko \
+	$(LINUX_DIR)/drivers/bluetooth/hci_uart.ko \
+	$(LINUX_DIR)/drivers/bluetooth/btusb.ko
+ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),ge,4.1.0)),1)
+  FILES+= \
+	$(LINUX_DIR)/drivers/bluetooth/btintel.ko
+endif
+  AUTOLOAD:=$(call AutoProbe,bluetooth rfcomm bnep hidp hci_uart btusb)
+endef
+
+define KernelPackage/bluetooth/description
+ Kernel support for Bluetooth devices
+endef
+
+$(eval $(call KernelPackage,bluetooth))
+
+define KernelPackage/ath3k
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=ATH3K Kernel Module support
+  DEPENDS:=+kmod-bluetooth +ar3k-firmware
+  KCONFIG:= \
+	CONFIG_BT_ATH3K \
+	CONFIG_BT_HCIUART_ATH3K=y
+  $(call AddDepends/bluetooth)
+  FILES:= \
+	$(LINUX_DIR)/drivers/bluetooth/ath3k.ko
+  AUTOLOAD:=$(call AutoProbe,ath3k)
+endef
+
+define KernelPackage/ath3k/description
+ Kernel support for ATH3K Module
+endef
+
+$(eval $(call KernelPackage,ath3k))
+
+
+define KernelPackage/bluetooth_6lowpan
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Bluetooth 6LoWPAN support
+  DEPENDS:=+kmod-6lowpan +kmod-bluetooth
+  KCONFIG:=CONFIG_BT_6LOWPAN
+  FILES:=$(LINUX_DIR)/net/bluetooth/bluetooth_6lowpan.ko
+  AUTOLOAD:=$(call AutoProbe,bluetooth_6lowpan)
+endef
+
+define KernelPackage/bluetooth_6lowpan/description
+ Kernel support for 6LoWPAN over Bluetooth Low Energy devices
+endef
+
+$(eval $(call KernelPackage,bluetooth_6lowpan))
+
+
+define KernelPackage/bluetooth-hci-h4p
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=HCI driver with H4 Nokia extensions
+  DEPENDS:=@TARGET_omap24xx +kmod-bluetooth
+  KCONFIG:=CONFIG_BT_HCIH4P
+  FILES:=$(LINUX_DIR)/drivers/bluetooth/hci_h4p/hci_h4p.ko
+  AUTOLOAD:=$(call AutoProbe,hci_h4p)
+endef
+
+define KernelPackage/bluetooth-hci-h4p/description
+ HCI driver with H4 Nokia extensions
+endef
+
+$(eval $(call KernelPackage,bluetooth-hci-h4p))
+
+
+define KernelPackage/dma-buf
+  TITLE:=DMA shared buffer support
+  HIDDEN:=1
+  KCONFIG:=CONFIG_DMA_SHARED_BUFFER
+  FILES:=$(LINUX_DIR)/drivers/dma-buf/dma-shared-buffer.ko
+  AUTOLOAD:=$(call AutoLoad,20,dma-shared-buffer)
+endef
+$(eval $(call KernelPackage,dma-buf))
+
+
+define KernelPackage/eeprom-93cx6
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=EEPROM 93CX6 support
+  KCONFIG:=CONFIG_EEPROM_93CX6
+  FILES:=$(LINUX_DIR)/drivers/misc/eeprom/eeprom_93cx6.ko
+  AUTOLOAD:=$(call AutoLoad,20,eeprom_93cx6)
+endef
+
+define KernelPackage/eeprom-93cx6/description
+ Kernel module for EEPROM 93CX6 support
+endef
+
+$(eval $(call KernelPackage,eeprom-93cx6))
+
+
+define KernelPackage/eeprom-at24
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=EEPROM AT24 support
+  KCONFIG:=CONFIG_EEPROM_AT24
+  DEPENDS:=+kmod-i2c-core
+  FILES:=$(LINUX_DIR)/drivers/misc/eeprom/at24.ko
+  AUTOLOAD:=$(call AutoProbe,at24)
+endef
+
+define KernelPackage/eeprom-at24/description
+ Kernel module for most I2C EEPROMs
+endef
+
+$(eval $(call KernelPackage,eeprom-at24))
+
+
+define KernelPackage/eeprom-at25
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=EEPROM AT25 support
+  KCONFIG:=CONFIG_EEPROM_AT25
+  FILES:=$(LINUX_DIR)/drivers/misc/eeprom/at25.ko
+  AUTOLOAD:=$(call AutoProbe,at25)
+endef
+
+define KernelPackage/eeprom-at25/description
+ Kernel module for most SPI EEPROMs
+endef
+
+$(eval $(call KernelPackage,eeprom-at25))
+
+
+define KernelPackage/gpio-dev
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Generic GPIO char device support
+  DEPENDS:=@GPIO_SUPPORT
+  KCONFIG:=CONFIG_GPIO_DEVICE
+  FILES:=$(LINUX_DIR)/drivers/char/gpio_dev.ko
+  AUTOLOAD:=$(call AutoLoad,40,gpio_dev)
+endef
+
+define KernelPackage/gpio-dev/description
+ Kernel module to allows control of GPIO pins using a character device.
+endef
+
+$(eval $(call KernelPackage,gpio-dev))
+
+
+define KernelPackage/gpio-mcp23s08
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Microchip MCP23xxx I/O expander
+  DEPENDS:=@GPIO_SUPPORT +PACKAGE_kmod-i2c-core:kmod-i2c-core
+  KCONFIG:=CONFIG_GPIO_MCP23S08
+  FILES:=$(LINUX_DIR)/drivers/gpio/gpio-mcp23s08.ko
+  AUTOLOAD:=$(call AutoLoad,40,gpio-mcp23s08)
+endef
+
+define KernelPackage/gpio-mcp23s08/description
+ Kernel module for Microchip MCP23xxx SPI/I2C I/O expander
+endef
+
+$(eval $(call KernelPackage,gpio-mcp23s08))
+
+
+define KernelPackage/gpio-nxp-74hc164
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=NXP 74HC164 GPIO expander support
+  KCONFIG:=CONFIG_GPIO_NXP_74HC164
+  FILES:=$(LINUX_DIR)/drivers/gpio/nxp_74hc164.ko
+  AUTOLOAD:=$(call AutoProbe,nxp_74hc164)
+endef
+
+define KernelPackage/gpio-nxp-74hc164/description
+ Kernel module for NXP 74HC164 GPIO expander
+endef
+
+$(eval $(call KernelPackage,gpio-nxp-74hc164))
+
+define KernelPackage/gpio-pca953x
+  SUBMENU:=$(OTHER_MENU)
+  DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core
+  TITLE:=PCA95xx, TCA64xx, and MAX7310 I/O ports
+  KCONFIG:=CONFIG_GPIO_PCA953X
+  FILES:=$(LINUX_DIR)/drivers/gpio/gpio-pca953x.ko
+  AUTOLOAD:=$(call AutoLoad,55,gpio-pca953x)
+endef
+
+define KernelPackage/gpio-pca953x/description
+ Kernel module for MAX731{0,2,3,5}, PCA6107, PCA953{4-9}, PCA955{4-7},
+ PCA957{4,5} and TCA64{08,16} I2C GPIO expanders
+endef
+
+$(eval $(call KernelPackage,gpio-pca953x))
+
+define KernelPackage/gpio-pcf857x
+  SUBMENU:=$(OTHER_MENU)
+  DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core
+  TITLE:=PCX857x, PCA967x and MAX732X I2C GPIO expanders
+  KCONFIG:=CONFIG_GPIO_PCF857X
+  FILES:=$(LINUX_DIR)/drivers/gpio/gpio-pcf857x.ko
+  AUTOLOAD:=$(call AutoLoad,55,gpio-pcf857x)
+endef
+
+define KernelPackage/gpio-pcf857x/description
+ Kernel module for PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders
+endef
+
+$(eval $(call KernelPackage,gpio-pcf857x))
+
+define KernelPackage/iio-core
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Industrial IO core
+  KCONFIG:= \
+	CONFIG_IIO \
+	CONFIG_IIO_BUFFER=y \
+	CONFIG_IIO_KFIFO_BUF \
+	CONFIG_IIO_TRIGGER=y \
+	CONFIG_IIO_TRIGGERED_BUFFER
+  FILES:= \
+	$(LINUX_DIR)/drivers/iio/industrialio.ko \
+	$(if $(CONFIG_IIO_TRIGGERED_BUFFER),$(LINUX_DIR)/drivers/iio/industrialio-triggered-buffer.ko@lt4.4) \
+	$(if $(CONFIG_IIO_TRIGGERED_BUFFER),$(LINUX_DIR)/drivers/iio/buffer/industrialio-triggered-buffer.ko@ge4.4) \
+	$(LINUX_DIR)/drivers/iio/kfifo_buf.ko@lt4.4 \
+	$(LINUX_DIR)/drivers/iio/buffer/kfifo_buf.ko@ge4.4
+  AUTOLOAD:=$(call AutoLoad,55,industrialio kfifo_buf industrialio-triggered-buffer)
+endef
+
+define KernelPackage/iio-core/description
+ The industrial I/O subsystem provides a unified framework for
+ drivers for many different types of embedded sensors using a
+ number of different physical interfaces (i2c, spi, etc)
+endef
+
+$(eval $(call KernelPackage,iio-core))
+
+
+define KernelPackage/iio-ad799x
+  SUBMENU:=$(OTHER_MENU)
+  DEPENDS:=kmod-i2c-core kmod-iio-core
+  TITLE:=Analog Devices AD799x ADC driver
+  KCONFIG:= \
+	CONFIG_AD799X_RING_BUFFER=y \
+	CONFIG_AD799X
+  FILES:=$(LINUX_DIR)/drivers/iio/adc/ad799x.ko
+  AUTOLOAD:=$(call AutoLoad,56,ad799x)
+endef
+
+define KernelPackage/iio-ad799x/description
+ support for Analog Devices:
+ ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
+ i2c analog to digital converters (ADC).
+endef
+
+$(eval $(call KernelPackage,iio-ad799x))
+
+
+define KernelPackage/iio-dht11
+  SUBMENU:=$(OTHER_MENU)
+  DEPENDS:=kmod-iio-core @GPIO_SUPPORT @USES_DEVICETREE
+  TITLE:=DHT11 (and compatible) humidity and temperature sensors
+  KCONFIG:= \
+	CONFIG_DHT11
+  FILES:=$(LINUX_DIR)/drivers/iio/humidity/dht11.ko
+  AUTOLOAD:=$(call AutoLoad,56,dht11)
+endef
+
+define KernelPackage/iio-dht11/description
+ support for DHT11 and DHT22 digitial humidity and temperature sensors
+ attached at GPIO lines. You will need a custom device tree file to
+ specify the GPIO line to use.
+endef
+
+$(eval $(call KernelPackage,iio-dht11))
+
+
+define KernelPackage/lp
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Parallel port and line printer support
+  KCONFIG:= \
+	CONFIG_PARPORT \
+	CONFIG_PRINTER \
+	CONFIG_PPDEV
+  FILES:= \
+	$(LINUX_DIR)/drivers/parport/parport.ko \
+	$(LINUX_DIR)/drivers/char/lp.ko \
+	$(LINUX_DIR)/drivers/char/ppdev.ko
+  AUTOLOAD:=$(call AutoLoad,50,parport lp ppdev)
+endef
+
+$(eval $(call KernelPackage,lp))
+
+
+define KernelPackage/mmc
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=MMC/SD Card Support
+  KCONFIG:= \
+	CONFIG_MMC \
+	CONFIG_MMC_BLOCK \
+	CONFIG_MMC_DEBUG=n \
+	CONFIG_MMC_UNSAFE_RESUME=n \
+	CONFIG_MMC_BLOCK_BOUNCE=y \
+	CONFIG_MMC_TIFM_SD=n \
+	CONFIG_MMC_WBSD=n \
+	CONFIG_SDIO_UART=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/mmc/core/mmc_core.ko \
+	$(LINUX_DIR)/drivers/mmc/card/mmc_block.ko
+  AUTOLOAD:=$(call AutoProbe,mmc_core mmc_block,1)
+endef
+
+define KernelPackage/mmc/description
+ Kernel support for MMC/SD cards
+endef
+
+$(eval $(call KernelPackage,mmc))
+
+
+define KernelPackage/sdhci
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Secure Digital Host Controller Interface support
+  DEPENDS:=+kmod-mmc
+  KCONFIG:= \
+	CONFIG_MMC_SDHCI \
+	CONFIG_MMC_SDHCI_PLTFM \
+	CONFIG_MMC_SDHCI_PCI=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/mmc/host/sdhci.ko \
+	$(LINUX_DIR)/drivers/mmc/host/sdhci-pltfm.ko
+
+  AUTOLOAD:=$(call AutoProbe,sdhci sdhci-pltfm,1)
+endef
+
+define KernelPackage/sdhci/description
+ Kernel support for SDHCI Hosts
+endef
+
+$(eval $(call KernelPackage,sdhci))
+
+
+define KernelPackage/rfkill
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=RF switch subsystem support
+  DEPENDS:=@USE_RFKILL +kmod-input-core
+  KCONFIG:= \
+    CONFIG_RFKILL_FULL \
+    CONFIG_RFKILL_INPUT=y \
+    CONFIG_RFKILL_LEDS=y
+  FILES:= \
+    $(LINUX_DIR)/net/rfkill/rfkill.ko
+  AUTOLOAD:=$(call AutoLoad,20,rfkill)
+endef
+
+define KernelPackage/rfkill/description
+ Say Y here if you want to have control over RF switches
+ found on many WiFi and Bluetooth cards
+endef
+
+$(eval $(call KernelPackage,rfkill))
+
+
+define KernelPackage/softdog
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Software watchdog driver
+  KCONFIG:=CONFIG_SOFT_WATCHDOG
+  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/softdog.ko
+  AUTOLOAD:=$(call AutoLoad,50,softdog,1)
+endef
+
+define KernelPackage/softdog/description
+ Software watchdog driver
+endef
+
+$(eval $(call KernelPackage,softdog))
+
+
+define KernelPackage/ssb
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Silicon Sonics Backplane glue code
+  DEPENDS:=@PCI_SUPPORT @!TARGET_brcm47xx @!TARGET_brcm63xx
+  KCONFIG:=\
+	CONFIG_SSB \
+	CONFIG_SSB_B43_PCI_BRIDGE=y \
+	CONFIG_SSB_DRIVER_MIPS=n \
+	CONFIG_SSB_DRIVER_PCICORE=y \
+	CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y \
+	CONFIG_SSB_PCIHOST=y \
+	CONFIG_SSB_PCIHOST_POSSIBLE=y \
+	CONFIG_SSB_POSSIBLE=y \
+	CONFIG_SSB_SPROM=y \
+	CONFIG_SSB_SILENT=y
+  FILES:=$(LINUX_DIR)/drivers/ssb/ssb.ko
+  AUTOLOAD:=$(call AutoLoad,18,ssb,1)
+endef
+
+define KernelPackage/ssb/description
+ Silicon Sonics Backplane glue code.
+endef
+
+$(eval $(call KernelPackage,ssb))
+
+
+define KernelPackage/bcma
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=BCMA support
+  DEPENDS:=@PCI_SUPPORT @!TARGET_brcm47xx @!TARGET_bcm53xx
+  KCONFIG:=\
+	CONFIG_BCMA \
+	CONFIG_BCMA_POSSIBLE=y \
+	CONFIG_BCMA_BLOCKIO=y \
+	CONFIG_BCMA_HOST_PCI_POSSIBLE=y \
+	CONFIG_BCMA_HOST_PCI=y \
+	CONFIG_BCMA_HOST_SOC=n \
+	CONFIG_BCMA_DRIVER_MIPS=n \
+	CONFIG_BCMA_DRIVER_PCI_HOSTMODE=n \
+	CONFIG_BCMA_DRIVER_GMAC_CMN=n \
+	CONFIG_BCMA_DEBUG=n
+  FILES:=$(LINUX_DIR)/drivers/bcma/bcma.ko
+  AUTOLOAD:=$(call AutoLoad,29,bcma)
+endef
+
+define KernelPackage/bcma/description
+ Bus driver for Broadcom specific Advanced Microcontroller Bus Architecture
+endef
+
+$(eval $(call KernelPackage,bcma))
+
+
+define KernelPackage/wdt-omap
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=OMAP Watchdog timer
+  DEPENDS:=@(TARGET_omap24xx||TARGET_omap35xx)
+  KCONFIG:=CONFIG_OMAP_WATCHDOG
+  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/omap_wdt.ko
+  AUTOLOAD:=$(call AutoLoad,50,omap_wdt,1)
+endef
+
+define KernelPackage/wdt-omap/description
+ Kernel module for TI omap watchdog timer
+endef
+
+$(eval $(call KernelPackage,wdt-omap))
+
+
+define KernelPackage/wdt-orion
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Marvell Orion Watchdog timer
+  DEPENDS:=@TARGET_orion||TARGET_kirkwood
+  KCONFIG:=CONFIG_ORION_WATCHDOG
+  FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/orion_wdt.ko
+  AUTOLOAD:=$(call AutoLoad,50,orion_wdt,1)
+endef
+
+define KernelPackage/wdt-orion/description
+ Kernel module for Marvell Orion, Kirkwood and Armada XP/370 watchdog timer
+endef
+
+$(eval $(call KernelPackage,wdt-orion))
+
+
+define KernelPackage/rtc-ds1307
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Dallas/Maxim DS1307 (and compatible) RTC support
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_DS1307 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1307.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-ds1307)
+endef
+
+define KernelPackage/rtc-ds1307/description
+ Kernel module for Dallas/Maxim DS1307/DS1337/DS1338/DS1340/DS1388/DS3231,
+ Epson RX-8025 and various other compatible RTC chips connected via I2C.
+endef
+
+$(eval $(call KernelPackage,rtc-ds1307))
+
+
+define KernelPackage/rtc-ds1374
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Dallas/Maxim DS1374 RTC support
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_DS1374 \
+	CONFIG_RTC_DRV_DS1374_WDT=n \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1374.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-ds1374)
+endef
+
+define KernelPackage/rtc-ds1374/description
+ Kernel module for Dallas/Maxim DS1374.
+endef
+
+$(eval $(call KernelPackage,rtc-ds1374))
+
+
+define KernelPackage/rtc-ds1672
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Dallas/Maxim DS1672 RTC support
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_DS1672 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1672.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-ds1672)
+endef
+
+define KernelPackage/rtc-ds1672/description
+ Kernel module for Dallas/Maxim DS1672 RTC.
+endef
+
+$(eval $(call KernelPackage,rtc-ds1672))
+
+
+define KernelPackage/rtc-isl1208
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Intersil ISL1208 RTC support
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_ISL1208 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-isl1208.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-isl1208)
+endef
+
+define KernelPackage/rtc-isl1208/description
+ Kernel module for Intersil ISL1208 RTC.
+endef
+
+$(eval $(call KernelPackage,rtc-isl1208))
+
+
+define KernelPackage/rtc-marvell
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Marvell SoC built-in RTC support
+  DEPENDS:=@RTC_SUPPORT @TARGET_kirkwood||TARGET_orion
+  KCONFIG:=CONFIG_RTC_DRV_MV \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-mv.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-mv)
+endef
+
+define KernelPackage/rtc-marvell/description
+ Kernel module for Marvell SoC built-in RTC.
+endef
+
+$(eval $(call KernelPackage,rtc-marvell))
+
+
+define KernelPackage/rtc-pcf8563
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Philips PCF8563/Epson RTC8564 RTC support
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_PCF8563 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf8563.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-pcf8563)
+endef
+
+define KernelPackage/rtc-pcf8563/description
+ Kernel module for Philips PCF8563 RTC chip.
+ The Epson RTC8564 should work as well.
+endef
+
+$(eval $(call KernelPackage,rtc-pcf8563))
+
+
+define KernelPackage/rtc-pcf2123
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Philips PCF2123 RTC support
+  DEPENDS:=@RTC_SUPPORT
+  KCONFIG:=CONFIG_RTC_DRV_PCF2123 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pcf2123.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-pcf2123)
+endef
+
+define KernelPackage/rtc-pcf2123/description
+ Kernel module for Philips PCF2123 RTC chip
+endef
+
+$(eval $(call KernelPackage,rtc-pcf2123))
+
+define KernelPackage/rtc-pt7c4338
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Pericom PT7C4338 RTC support
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_PT7C4338 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-pt7c4338.ko
+  AUTOLOAD:=$(call AutoProbe,rtc-pt7c4338)
+endef
+
+define KernelPackage/rtc-pt7c4338/description
+ Kernel module for Pericom PT7C4338 i2c RTC chip
+endef
+
+$(eval $(call KernelPackage,rtc-pt7c4338))
+
+define KernelPackage/rtc-snvs
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Freescale SNVS RTC support
+  DEPENDS:=@TARGET_imx6 @RTC_SUPPORT
+  KCONFIG:=CONFIG_RTC_DRV_SNVS \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-snvs.ko
+  AUTOLOAD:=$(call AutoLoad,50,rtc-snvs,1)
+endef
+
+define KernelPackage/rtc-snvs/description
+ Kernel module for Freescale SNVS RTC on chip module
+endef
+
+$(eval $(call KernelPackage,rtc-snvs))
+
+define KernelPackage/rtc-rs5c372a
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A
+  DEPENDS:=@RTC_SUPPORT +kmod-i2c-core
+  KCONFIG:=CONFIG_RTC_DRV_RS5C372 \
+	CONFIG_RTC_CLASS=y
+  FILES:=$(LINUX_DIR)/drivers/rtc/rtc-rs5c372.ko
+  AUTOLOAD:=$(call AutoLoad,50,rtc-rs5c372,1)
+endef
+
+define KernelPackage/rtc-rs5c372a/description
+ Kernel module for Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A RTC on chip module
+endef
+
+$(eval $(call KernelPackage,rtc-rs5c372a))
+
+
+define KernelPackage/mtdtests
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=MTD subsystem tests
+  KCONFIG:=CONFIG_MTD_TESTS
+  FILES:=\
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_nandecctest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_oobtest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_pagetest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_readtest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_speedtest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_stresstest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_subpagetest.ko \
+	$(LINUX_DIR)/drivers/mtd/tests/mtd_torturetest.ko
+endef
+
+define KernelPackage/mtdtests/description
+ Kernel modules for MTD subsystem/driver testing
+endef
+
+$(eval $(call KernelPackage,mtdtests))
+
+
+define KernelPackage/serial-8250
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=8250 UARTs
+  KCONFIG:= CONFIG_SERIAL_8250 \
+	CONFIG_SERIAL_8250_NR_UARTS=16 \
+  	CONFIG_SERIAL_8250_RUNTIME_UARTS=16 \
+  	CONFIG_SERIAL_8250_EXTENDED=y \
+  	CONFIG_SERIAL_8250_MANY_PORTS=y \
+	CONFIG_SERIAL_8250_SHARE_IRQ=y \
+	CONFIG_SERIAL_8250_DETECT_IRQ=n \
+	CONFIG_SERIAL_8250_RSA=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/tty/serial/8250/8250.ko \
+	$(LINUX_DIR)/drivers/tty/serial/8250/8250_base.ko@ge4.4
+endef
+
+define KernelPackage/serial-8250/description
+ Kernel module for 8250 UART based serial ports
+endef
+
+$(eval $(call KernelPackage,serial-8250))
+
+
+define KernelPackage/regmap
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Generic register map support
+  DEPENDS:=+kmod-lib-lzo +kmod-i2c-core
+  KCONFIG:=CONFIG_REGMAP \
+	   CONFIG_REGMAP_MMIO \
+	   CONFIG_REGMAP_SPI \
+	   CONFIG_REGMAP_I2C \
+	   CONFIG_SPI=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/base/regmap/regmap-core.ko \
+	$(LINUX_DIR)/drivers/base/regmap/regmap-i2c.ko \
+	$(LINUX_DIR)/drivers/base/regmap/regmap-mmio.ko \
+	$(if $(CONFIG_SPI),$(LINUX_DIR)/drivers/base/regmap/regmap-spi.ko)
+  AUTOLOAD:=$(call AutoLoad,21,regmap-core regmap-i2c regmap-mmio regmap-spi)
+endef
+
+define KernelPackage/regmap/description
+ Generic register map support
+endef
+
+$(eval $(call KernelPackage,regmap))
+
+define KernelPackage/ikconfig
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Kernel configuration via /proc/config.gz
+  KCONFIG:=CONFIG_IKCONFIG \
+	   CONFIG_IKCONFIG_PROC=y
+  FILES:=$(LINUX_DIR)/kernel/configs.ko
+  AUTOLOAD:=$(call AutoLoad,70,configs)
+endef
+
+define KernelPackage/ikconfig/description
+ Kernel configuration via /proc/config.gz
+endef
+
+$(eval $(call KernelPackage,ikconfig))
+
+
+define KernelPackage/zram
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=ZRAM
+  DEPENDS:=+kmod-lib-lzo +kmod-lib-lz4
+  KCONFIG:= \
+	CONFIG_ZSMALLOC \
+	CONFIG_ZRAM \
+	CONFIG_ZRAM_DEBUG=n \
+	CONFIG_PGTABLE_MAPPING=n \
+	CONFIG_ZSMALLOC_STAT=n \
+	CONFIG_ZRAM_LZ4_COMPRESS=y
+  FILES:= \
+	$(LINUX_DIR)/mm/zsmalloc.ko \
+	$(LINUX_DIR)/drivers/block/zram/zram.ko
+  AUTOLOAD:=$(call AutoLoad,20,zsmalloc zram)
+endef
+
+define KernelPackage/zram/description
+ Compressed RAM block device support
+endef
+
+$(eval $(call KernelPackage,zram))
+
+
+define KernelPackage/mvsdio
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Marvell SDIO support
+  DEPENDS:=@TARGET_orion||TARGET_kirkwood +kmod-mmc
+  KCONFIG:=CONFIG_MMC_MVSDIO
+  FILES:=$(LINUX_DIR)/drivers/mmc/host/mvsdio.ko
+  AUTOLOAD:=$(call AutoProbe,mvsdio)
+endef
+
+define KernelPackage/mvsdio/description
+ Kernel support for the Marvell SDIO controller
+endef
+
+$(eval $(call KernelPackage,mvsdio))
+
+
+define KernelPackage/pps
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=PPS support
+  KCONFIG:=CONFIG_PPS
+  FILES:=$(LINUX_DIR)/drivers/pps/pps_core.ko
+  AUTOLOAD:=$(call AutoLoad,17,pps_core,1)
+endef
+
+define KernelPackage/pps/description
+ PPS (Pulse Per Second) is a special pulse provided by some GPS
+ antennae. Userland can use it to get a high-precision time
+ reference.
+endef
+
+$(eval $(call KernelPackage,pps))
+
+
+define KernelPackage/pps-gpio
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=PPS client using GPIO
+  DEPENDS:=+kmod-pps
+  KCONFIG:=CONFIG_PPS_CLIENT_GPIO
+  FILES:=$(LINUX_DIR)/drivers/pps/clients/pps-gpio.ko
+  AUTOLOAD:=$(call AutoLoad,18,pps-gpio,1)
+endef
+
+define KernelPackage/pps-gpio/description
+ Support for a PPS source using GPIO. To be useful you must
+ also register a platform device specifying the GPIO pin and
+ other options, usually in your board setup.
+endef
+
+$(eval $(call KernelPackage,pps-gpio))
+
+
+define KernelPackage/pps-ldisc
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=PPS line discipline
+  DEPENDS:=+kmod-pps
+  KCONFIG:=CONFIG_PPS_CLIENT_LDISC
+  FILES:=$(LINUX_DIR)/drivers/pps/clients/pps-ldisc.ko
+  AUTOLOAD:=$(call AutoLoad,18,pps-ldisc,1)
+endef
+
+define KernelPackage/pps-ldisc/description
+ Support for a PPS source connected with the CD (Carrier
+ Detect) pin of your serial port.
+endef
+
+$(eval $(call KernelPackage,pps-ldisc))
+
+
+define KernelPackage/ptp
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=PTP clock support
+  DEPENDS:=+kmod-pps
+  KCONFIG:= \
+	CONFIG_PTP_1588_CLOCK \
+	CONFIG_NET_PTP_CLASSIFY=y
+  FILES:=$(LINUX_DIR)/drivers/ptp/ptp.ko
+  AUTOLOAD:=$(call AutoLoad,18,ptp,1)
+endef
+
+define KernelPackage/ptp/description
+ The IEEE 1588 standard defines a method to precisely
+ synchronize distributed clocks over Ethernet networks.
+endef
+
+$(eval $(call KernelPackage,ptp))
+
+
+define KernelPackage/ptp-gianfar
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Freescale Gianfar PTP support
+  DEPENDS:=@TARGET_mpc85xx +kmod-gianfar +kmod-ptp
+  KCONFIG:=CONFIG_PTP_1588_CLOCK_GIANFAR
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/freescale/gianfar_ptp.ko
+  AUTOLOAD:=$(call AutoProbe,gianfar_ptp)
+endef
+
+define KernelPackage/ptp-gianfar/description
+ Kernel module for IEEE 1588 support for Freescale
+ Gianfar Ethernet drivers
+endef
+
+$(eval $(call KernelPackage,ptp-gianfar))
+
+
+define KernelPackage/random-core
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Hardware Random Number Generator Core support
+  KCONFIG:=CONFIG_HW_RANDOM
+  FILES:=$(LINUX_DIR)/drivers/char/hw_random/rng-core.ko
+endef
+
+define KernelPackage/random-core/description
+ Kernel module for the HW random number generator core infrastructure
+endef
+
+$(eval $(call KernelPackage,random-core))
+
+define KernelPackage/random-omap
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Hardware Random Number Generator OMAP support
+  KCONFIG:=CONFIG_HW_RANDOM_OMAP
+  FILES:=$(LINUX_DIR)/drivers/char/hw_random/omap-rng.ko
+  DEPENDS:=@(TARGET_omap24xx||TARGET_omap) +kmod-random-core
+  AUTOLOAD:=$(call AutoProbe,random-omap)
+endef
+
+define KernelPackage/random-omap/description
+ Kernel module for the OMAP Random Number Generator
+ found on OMAP16xx, OMAP2/3/4/5 and AM33xx/AM43xx multimedia processors.
+endef
+
+$(eval $(call KernelPackage,random-omap))
+
+define KernelPackage/thermal
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Generic Thermal sysfs driver
+  DEPENDS:=+kmod-hwmon-core
+  HIDDEN:=1
+  KCONFIG:= \
+	CONFIG_THERMAL \
+	CONFIG_THERMAL_OF=y \
+	CONFIG_CPU_THERMAL=y \
+	CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y \
+	CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE=n \
+	CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=n \
+	CONFIG_THERMAL_GOV_FAIR_SHARE=n \
+	CONFIG_THERMAL_GOV_STEP_WISE=y \
+	CONFIG_THERMAL_GOV_USER_SPACE=n \
+	CONFIG_THERMAL_HWMON=y \
+	CONFIG_THERMAL_EMULATION=n
+  FILES:=$(LINUX_DIR)/drivers/thermal/thermal_sys.ko
+  AUTOLOAD:=$(call AutoProbe,thermal_sys)
+endef
+
+define KernelPackage/thermal/description
+ Generic Thermal Sysfs driver offers a generic mechanism for thermal
+ management. Usually it's made up of one or more thermal zone and cooling
+ device.
+endef
+
+$(eval $(call KernelPackage,thermal))
+
+
+define KernelPackage/thermal-imx
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Temperature sensor driver for Freescale i.MX SoCs
+  DEPENDS:=@TARGET_imx6 +kmod-thermal
+  KCONFIG:= \
+	CONFIG_IMX_THERMAL
+  FILES:=$(LINUX_DIR)/drivers/thermal/imx_thermal.ko
+  AUTOLOAD:=$(call AutoProbe,imx_thermal)
+endef
+
+define KernelPackage/thermal-imx/description
+ Support for Temperature Monitor (TEMPMON) found on Freescale i.MX SoCs.
+ It supports one critical trip point and one passive trip point. The
+ cpufreq is used as the cooling device to throttle CPUs when the
+ passive trip is crossed.
+endef
+
+$(eval $(call KernelPackage,thermal-imx))
+
+
+define KernelPackage/thermal-kirkwood
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Temperature sensor on Marvell Kirkwood SoCs
+  DEPENDS:=@TARGET_kirkwood +kmod-thermal
+  KCONFIG:=CONFIG_KIRKWOOD_THERMAL
+  FILES:=$(LINUX_DIR)/drivers/thermal/kirkwood_thermal.ko
+  AUTOLOAD:=$(call AutoProbe,kirkwood_thermal)
+endef
+
+define KernelPackage/thermal-kirkwood/description
+ Support for the Kirkwood thermal sensor driver into the Linux thermal
+ framework. Only kirkwood 88F6282 and 88F6283 have this sensor.
+endef
+
+$(eval $(call KernelPackage,thermal-kirkwood))
+
+
+define KernelPackage/gpio-beeper
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=GPIO beeper support
+  DEPENDS:=+kmod-input-core
+  KCONFIG:= \
+	CONFIG_INPUT_MISC=y \
+	CONFIG_INPUT_GPIO_BEEPER
+  FILES:= \
+	$(LINUX_DIR)/drivers/input/misc/gpio-beeper.ko
+  AUTOLOAD:=$(call AutoLoad,50,gpio-beeper)
+endef
+
+define KernelPackage/gpio-beeper/description
+ This enables playing beeps through an GPIO-connected buzzer
+endef
+
+$(eval $(call KernelPackage,gpio-beeper))
+
+
+define KernelPackage/echo
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=Line Echo Canceller
+  KCONFIG:=CONFIG_ECHO
+  FILES:=$(LINUX_DIR)/drivers/misc/echo/echo.ko
+  AUTOLOAD:=$(call AutoLoad,50,echo)
+endef
+
+define KernelPackage/echo/description
+ This driver provides line echo cancelling support for mISDN and
+ DAHDI drivers
+endef
+
+$(eval $(call KernelPackage,echo))
+
+
+define KernelPackage/bmp085
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=BMP085/BMP18x pressure sensor
+  DEPENDS:= +kmod-regmap @!LINUX_3_18 @!LINUX_4_1
+  KCONFIG:= CONFIG_BMP085
+  FILES:= $(LINUX_DIR)/drivers/misc/bmp085.ko
+endef
+
+define KernelPackage/bmp085/description
+ This driver adds support for Bosch Sensortec's digital pressure
+ sensors BMP085 and BMP18x.
+endef
+
+$(eval $(call KernelPackage,bmp085))
+
+
+define KernelPackage/bmp085-i2c
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=BMP085/BMP18x pressure sensor I2C
+  DEPENDS:= +kmod-bmp085
+  KCONFIG:= CONFIG_BMP085_I2C
+  FILES:= $(LINUX_DIR)/drivers/misc/bmp085-i2c.ko
+  AUTOLOAD:=$(call AutoProbe,bmp085-i2c)
+endef
+define KernelPackage/bmp085-i2c/description
+ This driver adds support for Bosch Sensortec's digital pressure
+ sensor connected via I2C.
+endef
+
+$(eval $(call KernelPackage,bmp085-i2c))
+
+
+define KernelPackage/bmp085-spi
+  SUBMENU:=$(OTHER_MENU)
+  TITLE:=BMP085/BMP18x pressure sensor SPI
+  DEPENDS:= +kmod-bmp085
+  KCONFIG:= CONFIG_BMP085_SPI
+  FILES:= $(LINUX_DIR)/drivers/misc/bmp085-spi.ko
+  AUTOLOAD:=$(call AutoProbe,bmp085-spi)
+endef
+define KernelPackage/bmp085-spi/description
+ This driver adds support for Bosch Sensortec's digital pressure
+ sensor connected via SPI.
+endef
+
+$(eval $(call KernelPackage,bmp085-spi))
diff --git a/package/kernel/linux/modules/pcmcia.mk b/package/kernel/linux/modules/pcmcia.mk
new file mode 100644
index 0000000000..51668facf0
--- /dev/null
+++ b/package/kernel/linux/modules/pcmcia.mk
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+PCMCIA_MENU:=PCMCIA support
+
+define KernelPackage/pcmcia-core
+  SUBMENU:=$(PCMCIA_MENU)
+  TITLE:=PCMCIA/CardBus support
+  DEPENDS:=@PCMCIA_SUPPORT
+  KCONFIG:= \
+	CONFIG_PCMCIA \
+	CONFIG_CARDBUS \
+	CONFIG_PCCARD \
+	PCMCIA_DEBUG=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/pcmcia/pcmcia_core.ko \
+	$(LINUX_DIR)/drivers/pcmcia/pcmcia.ko
+  AUTOLOAD:=$(call AutoLoad,25,pcmcia_core pcmcia)
+endef
+
+define KernelPackage/pcmcia-core/description
+ Kernel support for PCMCIA/CardBus controllers
+endef
+
+$(eval $(call KernelPackage,pcmcia-core))
+
+define KernelPackage/pcmcia-rsrc
+  SUBMENU:=$(PCMCIA_MENU)
+  TITLE:=PCMCIA resource support
+  DEPENDS:=kmod-pcmcia-core
+  KCONFIG:=CONFIG_PCCARD_NONSTATIC=y
+  FILES:=$(LINUX_DIR)/drivers/pcmcia/pcmcia_rsrc.ko
+  AUTOLOAD:=$(call AutoLoad,26,pcmcia_rsrc)
+endef
+
+define KernelPackage/pcmcia-rsrc/description
+ Kernel support for PCMCIA resource allocation
+endef
+
+$(eval $(call KernelPackage,pcmcia-rsrc))
+
+
+define KernelPackage/pcmcia-yenta
+  SUBMENU:=$(PCMCIA_MENU)
+  TITLE:=yenta socket driver
+  DEPENDS:=kmod-pcmcia-rsrc
+  KCONFIG:=CONFIG_YENTA
+  FILES:=$(LINUX_DIR)/drivers/pcmcia/yenta_socket.ko
+  AUTOLOAD:=$(call AutoLoad,41,pcmcia_rsrc yenta_socket)
+endef
+
+$(eval $(call KernelPackage,pcmcia-yenta))
+
+
+define KernelPackage/pcmcia-serial
+  SUBMENU:=$(PCMCIA_MENU)
+  TITLE:=Serial devices support
+  DEPENDS:=kmod-pcmcia-core +kmod-serial-8250
+  KCONFIG:= \
+	CONFIG_PCMCIA_SERIAL_CS \
+	CONFIG_SERIAL_8250_CS
+    FILES:=$(LINUX_DIR)/drivers/tty/serial/8250/serial_cs.ko
+  AUTOLOAD:=$(call AutoLoad,45,serial_cs)
+endef
+
+define KernelPackage/pcmcia-serial/description
+ Kernel support for PCMCIA/CardBus serial devices
+endef
+
+$(eval $(call KernelPackage,pcmcia-serial))
diff --git a/package/kernel/linux/modules/sound.mk b/package/kernel/linux/modules/sound.mk
new file mode 100644
index 0000000000..de5d8fc2c6
--- /dev/null
+++ b/package/kernel/linux/modules/sound.mk
@@ -0,0 +1,521 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+SOUND_MENU:=Sound Support
+
+# allow targets to override the soundcore stuff
+SOUNDCORE_LOAD ?= \
+	soundcore \
+	snd \
+	snd-hwdep \
+	snd-seq-device \
+	snd-rawmidi \
+	snd-timer \
+	snd-pcm \
+	snd-mixer-oss \
+	snd-pcm-oss \
+	snd-compress
+
+SOUNDCORE_FILES ?= \
+	$(LINUX_DIR)/sound/soundcore.ko \
+	$(LINUX_DIR)/sound/core/snd.ko \
+	$(LINUX_DIR)/sound/core/snd-hwdep.ko \
+	$(LINUX_DIR)/sound/core/seq/snd-seq-device.ko \
+	$(LINUX_DIR)/sound/core/snd-rawmidi.ko \
+	$(LINUX_DIR)/sound/core/snd-timer.ko \
+	$(LINUX_DIR)/sound/core/snd-pcm.ko \
+	$(LINUX_DIR)/sound/core/oss/snd-mixer-oss.ko \
+	$(LINUX_DIR)/sound/core/oss/snd-pcm-oss.ko \
+	$(LINUX_DIR)/sound/core/snd-compress.ko
+
+SOUNDCORE_LOAD += \
+	$(if $(CONFIG_SND_DMAENGINE_PCM),snd-pcm-dmaengine)
+
+SOUNDCORE_FILES += \
+	$(if $(CONFIG_SND_DMAENGINE_PCM),$(LINUX_DIR)/sound/core/snd-pcm-dmaengine.ko)
+
+define KernelPackage/sound-core
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=Sound support
+  DEPENDS:=@AUDIO_SUPPORT +kmod-input-core
+  KCONFIG:= \
+	CONFIG_SOUND \
+	CONFIG_SND \
+	CONFIG_SND_HWDEP \
+	CONFIG_SND_RAWMIDI \
+	CONFIG_SND_TIMER \
+	CONFIG_SND_PCM \
+	CONFIG_SND_PCM_TIMER=y \
+	CONFIG_SND_SEQUENCER \
+	CONFIG_SND_VIRMIDI \
+	CONFIG_SND_SEQ_DUMMY \
+	CONFIG_SND_SEQUENCER_OSS=y \
+	CONFIG_HOSTAUDIO \
+	CONFIG_SND_PCM_OSS \
+	CONFIG_SND_MIXER_OSS \
+	CONFIG_SOUND_OSS_CORE_PRECLAIM=y \
+	CONFIG_SND_COMPRESS_OFFLOAD
+  FILES:=$(SOUNDCORE_FILES)
+  AUTOLOAD:=$(call AutoLoad,30,$(SOUNDCORE_LOAD))
+endef
+
+define KernelPackage/sound-core/uml
+  FILES:= \
+	$(LINUX_DIR)/sound/soundcore.ko \
+	$(LINUX_DIR)/arch/um/drivers/hostaudio.ko
+  AUTOLOAD:=$(call AutoLoad,30,soundcore hostaudio)
+endef
+
+define KernelPackage/sound-core/description
+ Kernel modules for sound support
+endef
+
+$(eval $(call KernelPackage,sound-core))
+
+
+define AddDepends/sound
+  SUBMENU:=$(SOUND_MENU)
+  DEPENDS+=kmod-sound-core $(1) @!TARGET_uml
+endef
+
+
+define KernelPackage/ac97
+  TITLE:=ac97 controller
+  KCONFIG:=CONFIG_SND_AC97_CODEC
+  FILES:= \
+	$(LINUX_DIR)/sound/ac97_bus.ko \
+	$(LINUX_DIR)/sound/pci/ac97/snd-ac97-codec.ko
+  AUTOLOAD:=$(call AutoLoad,35,ac97_bus snd-ac97-codec)
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/ac97/description
+ The ac97 controller
+endef
+
+$(eval $(call KernelPackage,ac97))
+
+
+define KernelPackage/sound-mpu401
+  TITLE:=MPU-401 uart driver
+  KCONFIG:=CONFIG_SND_MPU401_UART
+  FILES:= \
+	$(LINUX_DIR)/sound/drivers/mpu401/snd-mpu401-uart.ko
+  AUTOLOAD:=$(call AutoLoad,35,snd-mpu401-uart)
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-mpu401/description
+ support for MIDI ports compatible with the Roland MPU-401
+ interface in UART mode.
+endef
+
+$(eval $(call KernelPackage,sound-mpu401))
+
+
+define KernelPackage/sound-seq
+  TITLE:=Sequencer support
+  FILES:= \
+	$(LINUX_DIR)/sound/core/seq/snd-seq.ko \
+	$(LINUX_DIR)/sound/core/seq/snd-seq-midi-event.ko \
+	$(LINUX_DIR)/sound/core/seq/snd-seq-midi.ko
+  AUTOLOAD:=$(call AutoLoad,35,snd-seq snd-seq-midi-event snd-seq-midi)
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-seq/description
+ Kernel modules for sequencer support
+endef
+
+$(eval $(call KernelPackage,sound-seq))
+
+
+define KernelPackage/sound-i8x0
+  TITLE:=Intel/SiS/nVidia/AMD/ALi AC97 Controller
+  DEPENDS:=+kmod-ac97
+  KCONFIG:=CONFIG_SND_INTEL8X0
+  FILES:=$(LINUX_DIR)/sound/pci/snd-intel8x0.ko
+  AUTOLOAD:=$(call AutoLoad,36,snd-intel8x0)
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-i8x0/description
+ support for the integrated AC97 sound device on motherboards
+ with Intel/SiS/nVidia/AMD chipsets, or ALi chipsets using
+ the M5455 Audio Controller.
+endef
+
+$(eval $(call KernelPackage,sound-i8x0))
+
+
+define KernelPackage/sound-via82xx
+  TITLE:=VIA 82xx AC97 Controller
+  DEPENDS:=+kmod-ac97 +kmod-sound-mpu401
+  KCONFIG:=CONFIG_SND_VIA82XX
+  FILES:=$(LINUX_DIR)/sound/pci/snd-via82xx.ko
+  AUTOLOAD:=$(call AutoLoad,36,snd-via82xx)
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-via82xx/description
+ support for the integrated AC97 sound device on motherboards
+ with VIA chipsets.
+endef
+
+$(eval $(call KernelPackage,sound-via82xx))
+
+
+define KernelPackage/sound-soc-core
+  TITLE:=SoC sound support
+  DEPENDS:=+kmod-regmap +kmod-ac97
+  KCONFIG:= \
+	CONFIG_SND_SOC \
+	CONFIG_SND_SOC_DMAENGINE_PCM=y \
+	CONFIG_SND_SOC_ALL_CODECS=n
+  FILES:=$(LINUX_DIR)/sound/soc/snd-soc-core.ko
+  AUTOLOAD:=$(call AutoLoad,55, snd-soc-core)
+  $(call AddDepends/sound)
+endef
+
+$(eval $(call KernelPackage,sound-soc-core))
+
+
+define KernelPackage/sound-soc-ac97
+  TITLE:=AC97 Codec support
+  KCONFIG:=CONFIG_SND_SOC_AC97_CODEC
+  FILES:=$(LINUX_DIR)/sound/soc/codecs/snd-soc-ac97.ko
+  AUTOLOAD:=$(call AutoLoad,57,snd-soc-ac97)
+  DEPENDS:=+kmod-ac97 +kmod-sound-soc-core
+  $(call AddDepends/sound)
+endef
+
+$(eval $(call KernelPackage,sound-soc-ac97))
+
+
+define KernelPackage/sound-soc-imx
+  TITLE:=IMX SoC support
+  KCONFIG:=\
+	CONFIG_SND_IMX_SOC \
+	CONFIG_SND_SOC_IMX_AUDMUX \
+	CONFIG_SND_SOC_FSL_SSI \
+	CONFIG_SND_SOC_IMX_PCM_DMA
+  FILES:= \
+	$(LINUX_DIR)/sound/soc/fsl/snd-soc-imx-audmux.ko \
+	$(LINUX_DIR)/sound/soc/fsl/snd-soc-fsl-ssi.ko \
+	$(LINUX_DIR)/sound/soc/fsl/imx-pcm-dma.ko
+  AUTOLOAD:=$(call AutoLoad,56,snd-soc-imx-audmux snd-soc-fsl-ssi snd-soc-imx-pcm)
+  DEPENDS:=@TARGET_imx6 +kmod-sound-soc-core
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-imx/description
+ Support for i.MX6 Platform sound (ssi/audmux/pcm)
+endef
+
+$(eval $(call KernelPackage,sound-soc-imx))
+
+
+define KernelPackage/sound-soc-imx-sgtl5000
+  TITLE:=IMX SoC support for SGTL5000
+  KCONFIG:=CONFIG_SND_SOC_IMX_SGTL5000
+  FILES:=\
+	$(LINUX_DIR)/sound/soc/codecs/snd-soc-sgtl5000.ko \
+	$(LINUX_DIR)/sound/soc/fsl/snd-soc-imx-sgtl5000.ko
+  AUTOLOAD:=$(call AutoLoad,57,snd-soc-sgtl5000 snd-soc-imx-sgtl5000)
+  DEPENDS:=@TARGET_imx6 +kmod-sound-soc-imx
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-imx-sgtl5000/description
+ Support for i.MX6 Platform sound SGTL5000 codec
+endef
+
+$(eval $(call KernelPackage,sound-soc-imx-sgtl5000))
+
+
+define KernelPackage/sound-soc-gw_avila
+  TITLE:=Gateworks Avila SoC sound support
+  KCONFIG:= \
+	CONFIG_SND_GW_AVILA_SOC \
+	CONFIG_SND_GW_AVILA_SOC_PCM \
+	CONFIG_SND_GW_AVILA_SOC_HSS
+  FILES:= \
+	$(LINUX_DIR)/sound/soc/codecs/snd-soc-tlv320aic3x.ko \
+	$(LINUX_DIR)/sound/soc/gw-avila/snd-soc-gw-avila.ko \
+	$(LINUX_DIR)/sound/soc/gw-avila/snd-soc-gw-avila-pcm.ko \
+	$(LINUX_DIR)/sound/soc/gw-avila/snd-soc-gw-avila-hss.ko
+  AUTOLOAD:=$(call AutoLoad,65,snd-soc-tlv320aic3x snd-soc-gw-avila snd-soc-gw-avila-pcm snd-soc-gw-avila-hss)
+  DEPENDS:=@TARGET_ixp4xx +kmod-sound-soc-core
+  $(call AddDepends/sound)
+endef
+
+$(eval $(call KernelPackage,sound-soc-gw_avila))
+
+
+define KernelPackage/pcspkr
+  DEPENDS:=@TARGET_x86 +kmod-input-core
+  TITLE:=PC speaker support
+  KCONFIG:= \
+	CONFIG_SND_PCSP
+  FILES:= \
+	$(LINUX_DIR)/sound/drivers/pcsp/snd-pcsp.ko
+  AUTOLOAD:=$(call AutoLoad,50,snd-pcsp)
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/pcspkr/description
+ This enables sounds (tones) through the pc speaker
+endef
+
+$(eval $(call KernelPackage,pcspkr))
+
+define KernelPackage/sound-dummy
+  $(call AddDepends/sound)
+  TITLE:=Null sound output driver (sink)
+  KCONFIG:= \
+	CONFIG_SND_DUMMY
+  FILES:= \
+	$(LINUX_DIR)/sound/drivers/snd-dummy.ko
+  AUTOLOAD:=$(call AutoLoad,32,snd-dummy)
+endef
+
+define KernelPackage/sound_dummy/description
+ Dummy sound device for Alsa when no hardware present
+endef
+
+$(eval $(call KernelPackage,sound-dummy))
+
+define KernelPackage/sound-hda-core
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Sound Core Support
+  KCONFIG:= \
+	CONFIG_SND_HDA_CORE@ge4.1 \
+	CONFIG_SND_HDA_HWDEP=y \
+	CONFIG_SND_HDA_RECONFIG=n \
+	CONFIG_SND_HDA_INPUT_BEEP=n \
+	CONFIG_SND_HDA_PATCH_LOADER=n \
+	CONFIG_SND_HDA_GENERIC
+  FILES:= \
+	$(LINUX_DIR)/sound/hda/snd-hda-core.ko@ge4.1 \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec.ko \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-generic.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-core@ge4.1 snd-hda-codec snd-hda-codec-generic)
+  $(call AddDepends/sound,+kmod-regmap)
+endef
+
+define KernelPackage/sound-hda-core/description
+ Kernel modules for HD Audio sound support
+endef
+
+$(eval $(call KernelPackage,sound-hda-core))
+
+define KernelPackage/sound-hda-codec-realtek
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:= HD Audio Realtek Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_REALTEK
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-realtek.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-realtek)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-realtek/description
+ Kernel modules for Intel HDA Realtek codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-realtek))
+
+define KernelPackage/sound-hda-codec-cmedia
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio C-Media Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_CMEDIA
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-cmedia.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-cmedia)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-cmedia/description
+ Kernel modules for HD Audio C-Media codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-cmedia))
+
+define KernelPackage/sound-hda-codec-analog
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Analog Devices Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_ANALOG
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-analog.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-analog)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-analog/description
+ Kernel modules for HD Audio Analog Devices codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-analog))
+
+define KernelPackage/sound-hda-codec-idt
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Sigmatel IDT Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_SIGMATEL
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-idt.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-idt)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-idt/description
+ Kernel modules for HD Audio Sigmatel IDT codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-idt))
+
+define KernelPackage/sound-hda-codec-si3054
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Silicon Labs 3054 Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_SI3054
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-si3054.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-si3054)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-si3054/description
+ Kernel modules for HD Audio Silicon Labs 3054 codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-si3054))
+
+define KernelPackage/sound-hda-codec-cirrus
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Cirrus Logic Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_CIRRUS
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-cirrus.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-cirrus)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-cirrus/description
+ Kernel modules for HD Audio Cirrus Logic codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-cirrus))
+
+define KernelPackage/sound-hda-codec-ca0110
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Creative CA0110 Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_CA0110
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-ca0110.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-ca0110)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-ca0110/description
+ Kernel modules for HD Audio Creative CA0110 codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-ca0110))
+
+define KernelPackage/sound-hda-codec-ca0132
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Creative CA0132 Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_CA0132 \
+	CONFIG_SND_HDA_CODEC_CA0132_DSP=n
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-ca0132.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-ca0132)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-ca0132/description
+ Kernel modules for HD Audio Creative CA0132 codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-ca0132))
+
+define KernelPackage/sound-hda-codec-conexant
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Conexant Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_CONEXANT
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-conexant.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-conexant)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-conexant/description
+ Kernel modules for HD Audio Conexant codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-conexant))
+
+define KernelPackage/sound-hda-codec-via
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Via Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_VIA
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-via.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-via)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-via/description
+ Kernel modules for HD Audio VIA codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-via))
+
+define KernelPackage/sound-hda-codec-hdmi
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio HDMI/DisplayPort Codec
+  KCONFIG:= \
+	CONFIG_SND_HDA_CODEC_HDMI
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-codec-hdmi.ko
+  AUTOLOAD:=$(call AutoProbe,snd-hda-codec-hdmi)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-codec-hdmi/description
+ Kernel modules for HD Audio HDMI codec support
+endef
+
+$(eval $(call KernelPackage,sound-hda-codec-hdmi))
+
+define KernelPackage/sound-hda-intel
+  SUBMENU:=$(SOUND_MENU)
+  TITLE:=HD Audio Intel Driver
+  KCONFIG:= \
+	CONFIG_SOUND_PCI \
+	CONFIG_SND_HDA_INTEL
+  FILES:= \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-intel.ko \
+	$(LINUX_DIR)/sound/pci/hda/snd-hda-controller.ko@lt4.4
+  AUTOLOAD:=$(call AutoProbe,snd-hda-controller@lt4.4 snd-hda-intel)
+  $(call AddDepends/sound,kmod-sound-hda-core)
+endef
+
+define KernelPackage/sound-hda-intel/description
+ Kernel modules for HD Audio Intel driver support
+endef
+
+$(eval $(call KernelPackage,sound-hda-intel))
diff --git a/package/kernel/linux/modules/spi.mk b/package/kernel/linux/modules/spi.mk
new file mode 100644
index 0000000000..b16e26ef04
--- /dev/null
+++ b/package/kernel/linux/modules/spi.mk
@@ -0,0 +1,108 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+SPI_MENU:=SPI Support
+
+define KernelPackage/mmc-spi
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=MMC/SD over SPI Support
+  DEPENDS:=+kmod-mmc +kmod-lib-crc-itu-t +kmod-lib-crc7
+  KCONFIG:=CONFIG_MMC_SPI \
+          CONFIG_SPI=y \
+          CONFIG_SPI_MASTER=y
+  FILES:=\
+	$(if $(CONFIG_OF),$(LINUX_DIR)/drivers/mmc/host/of_mmc_spi.ko) \
+	$(LINUX_DIR)/drivers/mmc/host/mmc_spi.ko
+  AUTOLOAD:=$(call AutoProbe,$(if $(CONFIG_OF),of_mmc_spi) mmc_spi)
+endef
+
+define KernelPackage/mmc-spi/description
+ Kernel support for MMC/SD over SPI
+endef
+
+$(eval $(call KernelPackage,mmc-spi))
+
+
+define KernelPackage/spi-bitbang
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=Serial Peripheral Interface bitbanging library
+  KCONFIG:=CONFIG_SPI_BITBANG \
+          CONFIG_SPI=y \
+          CONFIG_SPI_MASTER=y
+  FILES:=$(LINUX_DIR)/drivers/spi/spi-bitbang.ko
+endef
+
+define KernelPackage/spi-bitbang/description
+ This package contains the SPI bitbanging library
+endef
+
+$(eval $(call KernelPackage,spi-bitbang))
+
+
+define KernelPackage/spi-gpio-old
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=Old GPIO based bitbanging SPI controller (DEPRECATED)
+  DEPENDS:=@GPIO_SUPPORT +kmod-spi-bitbang
+  KCONFIG:=CONFIG_SPI_GPIO_OLD
+  FILES:=$(LINUX_DIR)/drivers/spi/spi_gpio_old.ko
+  AUTOLOAD:=$(call AutoProbe,spi_gpio_old)
+endef
+
+define KernelPackage/spi-gpio-old/description
+ This package contains the GPIO based bitbanging SPI controller driver
+endef
+
+$(eval $(call KernelPackage,spi-gpio-old))
+
+
+define KernelPackage/spi-gpio
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=GPIO-based bitbanging SPI Master
+  DEPENDS:=@GPIO_SUPPORT +kmod-spi-bitbang
+  KCONFIG:=CONFIG_SPI_GPIO
+  FILES:=$(LINUX_DIR)/drivers/spi/spi-gpio.ko
+  AUTOLOAD:=$(call AutoProbe,spi-gpio)
+endef
+
+define KernelPackage/spi-gpio/description
+ This package contains the GPIO-based bitbanging SPI Master
+endef
+
+$(eval $(call KernelPackage,spi-gpio))
+
+define KernelPackage/spi-dev
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=User mode SPI device driver
+  KCONFIG:=CONFIG_SPI_SPIDEV \
+          CONFIG_SPI=y \
+          CONFIG_SPI_MASTER=y
+  FILES:=$(LINUX_DIR)/drivers/spi/spidev.ko
+  AUTOLOAD:=$(call AutoProbe,spidev)
+endef
+
+define KernelPackage/spi-dev/description
+ This package contains the user mode SPI device driver
+endef
+
+$(eval $(call KernelPackage,spi-dev))
+
+define KernelPackage/spi-omap-24xx
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=SPI omap 24xx
+  DEPENDS:=@(TARGET_omap24xx||TARGET_omap)
+  KCONFIG:=CONFIG_SPI_OMAP24XX \
+          CONFIG_SPI=y \
+          CONFIG_SPI_MASTER=y
+  FILES:=$(LINUX_DIR)/drivers/spi/spi-omap2-mcspi.ko
+  AUTOLOAD:=$(call AutoProbe,spi-omap2-mcspi)
+endef
+
+define KernelPackage/spi-dev/description
+ This package contains the user mode SPI device driver
+endef
+
+$(eval $(call KernelPackage,spi-omap-24xx))
diff --git a/package/kernel/linux/modules/usb.mk b/package/kernel/linux/modules/usb.mk
new file mode 100644
index 0000000000..3574bec5f7
--- /dev/null
+++ b/package/kernel/linux/modules/usb.mk
@@ -0,0 +1,1668 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+USB_MENU:=USB Support
+
+USBNET_DIR:=net/usb
+USBHID_DIR?=hid/usbhid
+USBINPUT_DIR?=input/misc
+
+define KernelPackage/usb-core
+  SUBMENU:=$(USB_MENU)
+  TITLE:=Support for USB
+  DEPENDS:=@USB_SUPPORT
+  KCONFIG:=CONFIG_USB CONFIG_XPS_USB_HCD_XILINX=n CONFIG_USB_FHCI_HCD=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/core/usbcore.ko \
+	$(LINUX_DIR)/drivers/usb/common/usb-common.ko
+  AUTOLOAD:=$(call AutoLoad,20,usb-common usbcore,1)
+  $(call AddDepends/nls)
+endef
+
+define KernelPackage/usb-core/description
+ Kernel support for USB
+endef
+
+$(eval $(call KernelPackage,usb-core))
+
+
+define AddDepends/usb
+  SUBMENU:=$(USB_MENU)
+  DEPENDS+=+kmod-usb-core $(1)
+endef
+
+
+define KernelPackage/usb-ledtrig-usbport
+  TITLE:=LED trigger for USB ports
+  KCONFIG:=CONFIG_USB_LEDS_TRIGGER_USBPORT
+  DEPENDS:=@!LINUX_3_18
+  FILES:=$(LINUX_DIR)/drivers/usb/core/ledtrig-usbport.ko
+  AUTOLOAD:=$(call AutoLoad,50,ledtrig-usbport)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-ledtrig-usbport/description
+  This driver allows LEDs to be controlled by USB events. Enabling this
+  trigger allows specifying list of USB ports that should turn on LED
+  when some USB device gets connected.
+  If possible it should be prefered over similar ledtrig-usbdev.
+endef
+
+$(eval $(call KernelPackage,usb-ledtrig-usbport))
+
+
+define KernelPackage/usb-musb-hdrc
+  TITLE:=Support for Mentor Graphics silicon dual role USB
+  KCONFIG:= \
+	CONFIG_USB_MUSB_HDRC \
+	CONFIG_USB_INVENTRA_DMA=n \
+	CONFIG_USB_TI_CPPI41_DMA=n \
+	CONFIG_MUSB_PIO_ONLY=y \
+	CONFIG_USB_MUSB_DUAL_ROLE=y \
+	CONFIG_USB_MUSB_GADGET=n \
+	CONFIG_USB_MUSB_HOST=n \
+	CONFIG_USB_MUSB_DEBUG=y
+  DEPENDS:= \
+	@(TARGET_omap||TARGET_omap24xx) +kmod-usb-gadget \
+	+TARGET_omap24xx:kmod-usb-musb-tusb6010
+  FILES:=$(LINUX_DIR)/drivers/usb/musb/musb_hdrc.ko
+  AUTOLOAD:=$(call AutoLoad,46,musb_hdrc)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-musb-hdrc/description
+  Kernel support for Mentor Graphics silicon dual role USB device.
+endef
+
+$(eval $(call KernelPackage,usb-musb-hdrc))
+
+
+define KernelPackage/usb-musb-platformglue
+  TITLE:=MUSB platform glue layer
+  KCONFIG:= \
+	CONFIG_USB_MUSB_TUSB6010=n \
+	CONFIG_USB_MUSB_OMAP2PLUS=n \
+	CONFIG_USB_MUSB_AM35X=n \
+	CONFIG_USB_MUSB_DSPS \
+	CONFIG_USB_MUSB_UX500=n
+  DEPENDS:=@TARGET_omap +kmod-usb-phy-nop +kmod-usb-musb-hdrc +kmod-usb-phy-am335x
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/musb/musb_dsps.ko \
+	$(LINUX_DIR)/drivers/usb/musb/musb_am335x.ko
+  AUTOLOAD:=$(call AutoLoad,45,phy-omap-control musb_dsps musb_am335x)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-musb-platformglue/description
+  MUSB platform glue modules
+endef
+
+$(eval $(call KernelPackage,usb-musb-platformglue))
+
+
+define KernelPackage/usb-musb-tusb6010
+  TITLE:=Support for TUSB 6010
+  KCONFIG:=CONFIG_USB_MUSB_TUSB6010
+  DEPENDS:=@TARGET_omap24xx
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-musb-tusb6010/description
+  TUSB6010 support
+endef
+
+$(eval $(call KernelPackage,usb-musb-tusb6010))
+
+
+define KernelPackage/usb-phy-nop
+  TITLE:=Support for USB NOP transceiver
+  KCONFIG:=CONFIG_NOP_USB_XCEIV
+  HIDDEN:=1
+  FILES:=$(LINUX_DIR)/drivers/usb/phy/phy-generic.ko
+  AUTOLOAD:=$(call AutoLoad,43,phy-generic)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-phy-nop/description
+  Support for USB NOP transceiver
+endef
+
+$(eval $(call KernelPackage,usb-phy-nop))
+
+
+define KernelPackage/usb-phy-am335x
+  TITLE:=Support for AM335x USB PHY
+  KCONFIG:= \
+	CONFIG_AM335X_PHY_USB \
+	CONFIG_AM335X_CONTROL_USB
+  DEPENDS:=@TARGET_omap +kmod-usb-phy-nop
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/phy/phy-am335x.ko \
+	$(LINUX_DIR)/drivers/usb/phy/phy-am335x-control.ko
+  AUTOLOAD:=$(call AutoLoad,44,phy-am335x)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-phy-am335x/description
+  Support for AM335x USB PHY
+endef
+
+$(eval $(call KernelPackage,usb-phy-am335x))
+
+
+define KernelPackage/usb-phy-omap-usb2
+  TITLE:=Support for OMAP2 USB PHY
+  KCONFIG:= \
+	CONFIG_OMAP_USB2 \
+	CONFIG_OMAP_CONTROL_PHY
+  DEPENDS:=@TARGET_omap
+  FILES:= \
+	$(LINUX_DIR)/drivers/phy/phy-omap-usb2.ko \
+	$(LINUX_DIR)/drivers/phy/phy-omap-control.ko
+  AUTOLOAD:=$(call AutoLoad,45,phy-omap-control phy-omap-usb2)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-phy-omap-usb2/description
+  Support for AM335x USB PHY
+endef
+
+$(eval $(call KernelPackage,usb-phy-omap-usb2))
+
+
+define KernelPackage/usb-phy-omap-usb3
+  TITLE:=Support for OMAP USB3 PHY
+  KCONFIG:=CONFIG_OMAP_USB3
+  DEPENDS:=@TARGET_omap +kmod-usb-phy-omap-usb2
+  FILES:=$(LINUX_DIR)/drivers/usb/phy/phy-omap-usb3.ko
+  AUTOLOAD:=$(call AutoLoad,45,phy-omap-usb3)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-phy-omap-usb3/description
+  Support for OMAP USB3 PHY
+endef
+
+$(eval $(call KernelPackage,usb-phy-omap-usb3))
+
+
+define KernelPackage/usb-phy-twl4030
+  TITLE:=Support for TWL4030 OTG PHY
+  KCONFIG:=CONFIG_TWL4030_USB
+  DEPENDS:=@TARGET_omap +kmod-usb-phy-omap-usb2 +kmod-usb-musb-hdrc
+  FILES:=$(LINUX_DIR)/drivers/phy/phy-twl4030-usb.ko
+  AUTOLOAD:=$(call AutoLoad,45,phy-twl4030-usb)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-phy-twl4030/description
+  Support for TWL4030/TWL5030/TPS659x0 OTG PHY
+endef
+
+$(eval $(call KernelPackage,usb-phy-twl4030))
+
+
+define KernelPackage/usb-phy-twl6030
+  TITLE:=Support for TWL6030 OTG PHY
+  KCONFIG:=CONFIG_TWL6030_USB
+  DEPENDS:=@TARGET_omap +kmod-usb-phy-omap-usb2 +kmod-usb-musb-hdrc
+  FILES:=$(LINUX_DIR)/drivers/usb/phy/phy-twl6030-usb.ko
+  AUTOLOAD:=$(call AutoLoad,45,phy-twl6030-usb)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-phy-twl6030/description
+  Support for TWL6030 OTG PHY
+endef
+
+$(eval $(call KernelPackage,usb-phy-twl6030))
+
+
+define KernelPackage/usb-gadget
+  TITLE:=USB Gadget support
+  KCONFIG:=CONFIG_USB_GADGET
+  HIDDEN:=1
+  FILES:=\
+	$(LINUX_DIR)/drivers/usb/gadget/udc/udc-core.ko
+  AUTOLOAD:=$(call AutoLoad,45,udc-core)
+  DEPENDS:=@USB_GADGET_SUPPORT
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-gadget/description
+ Kernel support for USB Gadget mode
+endef
+
+$(eval $(call KernelPackage,usb-gadget))
+
+define KernelPackage/usb-lib-composite
+  TITLE:=USB lib composite
+  KCONFIG:=CONFIG_USB_LIBCOMPOSITE
+  DEPENDS:=+kmod-usb-gadget +kmod-fs-configfs
+  HIDDEN:=1
+  FILES:=$(LINUX_DIR)/drivers/usb/gadget/libcomposite.ko
+  AUTOLOAD:=$(call AutoLoad,50,libcomposite)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-lib-composite/description
+ Lib Composite
+endef
+
+$(eval $(call KernelPackage,usb-lib-composite))
+
+define KernelPackage/usb-gadget-ehci-debug
+  TITLE:=USB EHCI debug port Gadget support
+  KCONFIG:=\
+	CONFIG_USB_G_DBGP \
+	CONFIG_USB_G_DBGP_SERIAL=y \
+	CONFIG_USB_G_DBGP_PRINTK=n
+  DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite +kmod-usb-gadget-serial
+  FILES:=$(LINUX_DIR)/drivers/usb/gadget/legacy/g_dbgp.ko
+  AUTOLOAD:=$(call AutoLoad,52,g_dbgp)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-gadget-ehci-debug/description
+  Kernel support for USB EHCI debug port Gadget.
+endef
+
+$(eval $(call KernelPackage,usb-gadget-ehci-debug))
+
+define KernelPackage/usb-gadget-eth
+  TITLE:=USB Ethernet Gadget support
+  KCONFIG:= \
+	CONFIG_USB_ETH \
+	CONFIG_USB_ETH_RNDIS=y \
+	CONFIG_USB_ETH_EEM=n
+  DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/gadget/function/u_ether.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_ecm.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_ecm_subset.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_rndis.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/legacy/g_ether.ko
+  AUTOLOAD:=$(call AutoLoad,52,usb_f_ecm g_ether)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-gadget-eth/description
+ Kernel support for USB Ethernet Gadget
+endef
+
+$(eval $(call KernelPackage,usb-gadget-eth))
+
+
+define KernelPackage/usb-gadget-serial
+  TITLE:=USB Serial Gadget support
+  KCONFIG:=CONFIG_USB_G_SERIAL
+  DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/gadget/function/u_serial.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_acm.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_obex.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_serial.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/legacy/g_serial.ko
+  AUTOLOAD:=$(call AutoLoad,52,usb_f_acm g_serial)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-gadget-serial/description
+  Kernel support for USB Serial Gadget.
+endef
+
+$(eval $(call KernelPackage,usb-gadget-serial))
+
+define KernelPackage/usb-gadget-mass-storage
+  TITLE:=USB Mass Storage support
+  KCONFIG:=CONFIG_USB_MASS_STORAGE
+  DEPENDS:=+kmod-usb-gadget +kmod-usb-lib-composite
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/gadget/function/usb_f_mass_storage.ko \
+	$(LINUX_DIR)/drivers/usb/gadget/legacy/g_mass_storage.ko
+  AUTOLOAD:=$(call AutoLoad,52,usb_f_mass_storage g_mass_storage)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-gadget-mass-storage/description
+  Kernel support for USB Gadget Mass Storage
+endef
+
+$(eval $(call KernelPackage,usb-gadget-mass-storage))
+
+
+define KernelPackage/usb-uhci
+  TITLE:=Support for UHCI controllers
+  KCONFIG:= \
+	CONFIG_USB_UHCI_ALT \
+	CONFIG_USB_UHCI_HCD
+  FILES:=$(LINUX_DIR)/drivers/usb/host/uhci-hcd.ko
+  AUTOLOAD:=$(call AutoLoad,50,uhci-hcd,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-uhci/description
+ Kernel support for USB UHCI controllers
+endef
+
+$(eval $(call KernelPackage,usb-uhci,1))
+
+
+define KernelPackage/usb-ohci
+  TITLE:=Support for OHCI controllers
+  DEPENDS:= \
+	+TARGET_bcm53xx:kmod-usb-bcma \
+	+TARGET_brcm47xx:kmod-usb-bcma \
+	+TARGET_brcm47xx:kmod-usb-ssb
+  KCONFIG:= \
+	CONFIG_USB_OHCI \
+	CONFIG_USB_OHCI_HCD \
+	CONFIG_USB_OHCI_ATH79=y \
+	CONFIG_USB_OHCI_HCD_AT91=y \
+	CONFIG_USB_OHCI_BCM63XX=y \
+	CONFIG_USB_OCTEON_OHCI=y \
+	CONFIG_USB_OHCI_HCD_OMAP3=y \
+	CONFIG_USB_OHCI_HCD_PLATFORM=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/host/ohci-hcd.ko \
+	$(LINUX_DIR)/drivers/usb/host/ohci-platform.ko
+  ifneq ($(wildcard $(LINUX_DIR)/drivers/usb/host/ohci-at91.ko),)
+    FILES+=$(LINUX_DIR)/drivers/usb/host/ohci-at91.ko
+  endif
+  AUTOLOAD:=$(call AutoLoad,50,ohci-hcd ohci-platform ohci-at91,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-ohci/description
+ Kernel support for USB OHCI controllers
+endef
+
+$(eval $(call KernelPackage,usb-ohci,1))
+
+
+define KernelPackage/usb-ohci-pci
+  TITLE:=Support for PCI OHCI controllers
+  DEPENDS:=@PCI_SUPPORT +kmod-usb-ohci
+  KCONFIG:=CONFIG_USB_OHCI_HCD_PCI
+  FILES:=$(LINUX_DIR)/drivers/usb/host/ohci-pci.ko
+  AUTOLOAD:=$(call AutoLoad,51,ohci-pci,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-ohci-pci/description
+ Kernel support for PCI OHCI controllers
+endef
+
+$(eval $(call KernelPackage,usb-ohci-pci))
+
+
+define KernelPackage/usb2-fsl
+  TITLE:=Support for Freescale USB2 controllers
+  DEPENDS:=@TARGET_mpc85xx
+  HIDDEN:=1
+  KCONFIG:=CONFIG_USB_FSL_MPH_DR_OF
+  FILES:=$(LINUX_DIR)/drivers/usb/host/fsl-mph-dr-of.ko
+  AUTOLOAD:=$(call AutoLoad,39,fsl-mph-dr-of,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb2-fsl/description
+ Kernel support for Freescale USB2 (EHCI) controllers
+endef
+
+$(eval $(call KernelPackage,usb2-fsl))
+
+
+define KernelPackage/usb2-omap
+  TITLE:=Support for USB2 for OMAP
+  DEPENDS:=@TARGET_omap +kmod-usb-phy-nop +kmod-usb-phy-am335x +kmod-usb2
+  KCONFIG:=\
+	CONFIG_MFD_OMAP_USB_HOST=y \
+	CONFIG_USB_EHCI_HCD_OMAP
+  FILES:=$(LINUX_DIR)/drivers/usb/host/ehci-omap.ko
+  AUTOLOAD:=$(call AutoLoad,39,ehci-omap)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb2-omap/description
+ Kernel support for OMAP USB2 (EHCI) controllers
+endef
+
+$(eval $(call KernelPackage,usb2-omap))
+
+define KernelPackage/usb-bcma
+  TITLE:=Support for BCMA USB controllers
+  DEPENDS:=@USB_SUPPORT @TARGET_brcm47xx||TARGET_bcm53xx
+  HIDDEN:=1
+  KCONFIG:=CONFIG_USB_HCD_BCMA
+  FILES:= \
+	$(if $(CONFIG_USB_HCD_BCMA),$(LINUX_DIR)/drivers/usb/host/bcma-hcd.ko)
+  AUTOLOAD:=$(call AutoLoad,19,$(if $(CONFIG_USB_HCD_BCMA),bcma-hcd),1)
+  $(call AddDepends/usb)
+endef
+$(eval $(call KernelPackage,usb-bcma))
+
+define KernelPackage/usb-ssb
+  TITLE:=Support for SSB USB controllers
+  DEPENDS:=@USB_SUPPORT @TARGET_brcm47xx
+  HIDDEN:=1
+  KCONFIG:=CONFIG_USB_HCD_SSB
+  FILES:= \
+	$(if $(CONFIG_USB_HCD_SSB),$(LINUX_DIR)/drivers/usb/host/ssb-hcd.ko)
+  AUTOLOAD:=$(call AutoLoad,19,$(if $(CONFIG_USB_HCD_SSB),ssb-hcd),1)
+  $(call AddDepends/usb)
+endef
+$(eval $(call KernelPackage,usb-ssb))
+
+define KernelPackage/usb2
+  TITLE:=Support for USB2 controllers
+  DEPENDS:=\
+	+TARGET_brcm47xx:kmod-usb-bcma \
+	+TARGET_brcm47xx:kmod-usb-ssb \
+	+TARGET_bcm53xx:kmod-usb-bcma \
+	+TARGET_bcm53xx:kmod-phy-bcm-ns-usb2 \
+	+TARGET_mpc85xx:kmod-usb2-fsl
+  KCONFIG:=\
+	CONFIG_USB_EHCI_HCD \
+	CONFIG_USB_EHCI_ATH79=y \
+	CONFIG_USB_EHCI_BCM63XX=y \
+	CONFIG_USB_IMX21_HCD=y \
+	CONFIG_USB_EHCI_MXC=y \
+	CONFIG_USB_OCTEON_EHCI=y \
+	CONFIG_USB_EHCI_HCD_ORION=y \
+	CONFIG_USB_EHCI_HCD_PLATFORM=y \
+	CONFIG_USB_EHCI_HCD_AT91=y \
+	CONFIG_USB_EHCI_FSL
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/host/ehci-hcd.ko \
+	$(LINUX_DIR)/drivers/usb/host/ehci-platform.ko
+  ifneq ($(wildcard $(LINUX_DIR)/drivers/usb/host/ehci-orion.ko),)
+    FILES+=$(LINUX_DIR)/drivers/usb/host/ehci-orion.ko
+  endif
+  ifneq ($(wildcard $(LINUX_DIR)/drivers/usb/host/ehci-atmel.ko),)
+    FILES+=$(LINUX_DIR)/drivers/usb/host/ehci-atmel.ko
+  endif
+  ifneq ($(wildcard $(LINUX_DIR)/drivers/usb/host/ehci-fsl.ko),)
+    FILES+=$(LINUX_DIR)/drivers/usb/host/ehci-fsl.ko
+  endif
+  AUTOLOAD:=$(call AutoLoad,40,ehci-hcd ehci-platform ehci-orion ehci-atmel ehci-fsl,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb2/description
+ Kernel support for USB2 (EHCI) controllers
+endef
+
+$(eval $(call KernelPackage,usb2))
+
+
+define KernelPackage/usb2-pci
+  TITLE:=Support for PCI USB2 controllers
+  DEPENDS:=@PCI_SUPPORT +kmod-usb2
+  KCONFIG:=CONFIG_USB_EHCI_PCI
+  FILES:=$(LINUX_DIR)/drivers/usb/host/ehci-pci.ko
+  AUTOLOAD:=$(call AutoLoad,42,ehci-pci,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb2-pci/description
+ Kernel support for PCI USB2 (EHCI) controllers
+endef
+
+$(eval $(call KernelPackage,usb2-pci))
+
+
+define KernelPackage/usb-dwc2
+  TITLE:=DWC2 USB controller driver
+  DEPENDS:=+(TARGET_brcm2708||TARGET_at91||TARGET_brcm63xx||TARGET_mxs||TARGET_imx6||TARGET_omap):kmod-usb-gadget
+  KCONFIG:= \
+	CONFIG_USB_DWC2 \
+	CONFIG_USB_DWC2_PCI \
+	CONFIG_USB_DWC2_PLATFORM \
+	CONFIG_USB_DWC2_DEBUG=n \
+	CONFIG_USB_DWC2_VERBOSE=n \
+	CONFIG_USB_DWC2_TRACK_MISSED_SOFS=n \
+	CONFIG_USB_DWC2_DEBUG_PERIODIC=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/dwc2/dwc2.ko \
+	$(LINUX_DIR)/drivers/usb/dwc2/dwc2_platform.ko@lt4.3
+  AUTOLOAD:=$(call AutoLoad,54,dwc2 dwc2_platform@lt4.3,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-dwc2/description
+ This driver provides USB Device Controller support for the
+ Synopsys DesignWare USB OTG Core
+endef
+
+$(eval $(call KernelPackage,usb-dwc2))
+
+
+define KernelPackage/usb-dwc3
+  TITLE:=DWC3 USB controller driver
+  KCONFIG:= \
+	CONFIG_USB_DWC3 \
+	CONFIG_USB_DWC3_HOST=y \
+	CONFIG_USB_DWC3_GADGET=n \
+	CONFIG_USB_DWC3_DUAL_ROLE=n \
+	CONFIG_USB_DWC3_DEBUG=n \
+	CONFIG_USB_DWC3_VERBOSE=n
+  FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3.ko
+  AUTOLOAD:=$(call AutoLoad,54,dwc3,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-dwc3/description
+ This driver provides support for the Dual Role SuperSpeed
+ USB Controller based on the Synopsys DesignWare USB3 IP Core
+endef
+
+$(eval $(call KernelPackage,usb-dwc3))
+
+
+define KernelPackage/usb-acm
+  TITLE:=Support for modems/isdn controllers
+  KCONFIG:=CONFIG_USB_ACM
+  FILES:=$(LINUX_DIR)/drivers/usb/class/cdc-acm.ko
+  AUTOLOAD:=$(call AutoProbe,cdc-acm)
+$(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-acm/description
+ Kernel support for USB ACM devices (modems/isdn controllers)
+endef
+
+$(eval $(call KernelPackage,usb-acm))
+
+
+define KernelPackage/usb-wdm
+  TITLE:=USB Wireless Device Management
+  KCONFIG:=CONFIG_USB_WDM
+  FILES:=$(LINUX_DIR)/drivers/usb/class/cdc-wdm.ko
+  AUTOLOAD:=$(call AutoProbe,cdc-wdm)
+$(call AddDepends/usb)
+$(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-wdm/description
+ USB Wireless Device Management support
+endef
+
+$(eval $(call KernelPackage,usb-wdm))
+
+
+define KernelPackage/usb-audio
+  TITLE:=Support for USB audio devices
+  KCONFIG:= \
+	CONFIG_USB_AUDIO \
+	CONFIG_SND_USB=y \
+	CONFIG_SND_USB_AUDIO
+  $(call AddDepends/usb)
+  $(call AddDepends/sound)
+  FILES:= \
+	$(LINUX_DIR)/sound/usb/snd-usbmidi-lib.ko \
+	$(LINUX_DIR)/sound/usb/snd-usb-audio.ko
+  AUTOLOAD:=$(call AutoProbe,snd-usbmidi-lib snd-usb-audio)
+endef
+
+define KernelPackage/usb-audio/description
+ Kernel support for USB audio devices
+endef
+
+$(eval $(call KernelPackage,usb-audio))
+
+
+define KernelPackage/usb-printer
+  TITLE:=Support for printers
+  KCONFIG:=CONFIG_USB_PRINTER
+  FILES:=$(LINUX_DIR)/drivers/usb/class/usblp.ko
+  AUTOLOAD:=$(call AutoProbe,usblp)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-printer/description
+ Kernel support for USB printers
+endef
+
+$(eval $(call KernelPackage,usb-printer))
+
+
+define KernelPackage/usb-serial
+  TITLE:=Support for USB-to-Serial converters
+  KCONFIG:=CONFIG_USB_SERIAL
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/usbserial.ko
+  AUTOLOAD:=$(call AutoProbe,usbserial)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-serial/description
+ Kernel support for USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial))
+
+
+define AddDepends/usb-serial
+  SUBMENU:=$(USB_MENU)
+  DEPENDS+=kmod-usb-serial $(1)
+endef
+
+
+define KernelPackage/usb-serial-belkin
+  TITLE:=Support for Belkin devices
+  KCONFIG:=CONFIG_USB_SERIAL_BELKIN
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/belkin_sa.ko
+  AUTOLOAD:=$(call AutoProbe,belkin_sa)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-belkin/description
+ Kernel support for Belkin USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-belkin))
+
+
+define KernelPackage/usb-serial-ch341
+  TITLE:=Support for CH341 devices
+  KCONFIG:=CONFIG_USB_SERIAL_CH341
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/ch341.ko
+  AUTOLOAD:=$(call AutoProbe,ch341)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-ch341/description
+ Kernel support for Winchiphead CH341 USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-ch341))
+
+
+define KernelPackage/usb-serial-ftdi
+  TITLE:=Support for FTDI devices
+  KCONFIG:=CONFIG_USB_SERIAL_FTDI_SIO
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/ftdi_sio.ko
+  AUTOLOAD:=$(call AutoProbe,ftdi_sio)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-ftdi/description
+ Kernel support for FTDI USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-ftdi))
+
+
+define KernelPackage/usb-serial-garmin
+  TITLE:=Support for Garmin GPS devices
+  KCONFIG:=CONFIG_USB_SERIAL_GARMIN
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/garmin_gps.ko
+  AUTOLOAD:=$(call AutoProbe,garmin_gps)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-garmin/description
+ Should work with most Garmin GPS devices which have a native USB port.
+endef
+
+$(eval $(call KernelPackage,usb-serial-garmin))
+
+
+define KernelPackage/usb-serial-simple
+  TITLE:=USB Serial Simple (Motorola phone)
+  KCONFIG:=CONFIG_USB_SERIAL_SIMPLE
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/usb-serial-simple.ko
+  AUTOLOAD:=$(call AutoProbe,usb-serial-simple)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-simple/description
+  Kernel support for "very simple devices".
+
+Specifically, it supports:
+	- Suunto ANT+ USB device.
+	- Medtronic CareLink USB device (3.18)
+	- Fundamental Software dongle.
+	- Google USB serial devices (3.19)
+	- HP4x calculators
+	- a number of Motorola phones
+	- Novatel Wireless GPS receivers (3.18)
+	- Siemens USB/MPI adapter.
+	- ViVOtech ViVOpay USB device.
+	- Infineon Modem Flashloader USB interface
+	- ZIO Motherboard USB serial interface
+endef
+
+$(eval $(call KernelPackage,usb-serial-simple))
+
+
+define KernelPackage/usb-serial-ti-usb
+  TITLE:=Support for TI USB 3410/5052
+  KCONFIG:=CONFIG_USB_SERIAL_TI
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/ti_usb_3410_5052.ko
+  AUTOLOAD:=$(call AutoProbe,ti_usb_3410_5052)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-ti-usb/description
+ Kernel support for TI USB 3410/5052 devices
+endef
+
+$(eval $(call KernelPackage,usb-serial-ti-usb))
+
+
+define KernelPackage/usb-serial-ipw
+  TITLE:=Support for IPWireless 3G devices
+  KCONFIG:=CONFIG_USB_SERIAL_IPW
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/ipw.ko
+  AUTOLOAD:=$(call AutoProbe,ipw)
+  $(call AddDepends/usb-serial,+kmod-usb-serial-wwan)
+endef
+
+$(eval $(call KernelPackage,usb-serial-ipw))
+
+
+define KernelPackage/usb-serial-mct
+  TITLE:=Support for Magic Control Tech. devices
+  KCONFIG:=CONFIG_USB_SERIAL_MCT_U232
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/mct_u232.ko
+  AUTOLOAD:=$(call AutoProbe,mct_u232)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-mct/description
+ Kernel support for Magic Control Technology USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-mct))
+
+
+define KernelPackage/usb-serial-mos7720
+  TITLE:=Support for Moschip MOS7720 devices
+  KCONFIG:=CONFIG_USB_SERIAL_MOS7720
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/mos7720.ko
+  AUTOLOAD:=$(call AutoProbe,mos7720)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-mos7720/description
+ Kernel support for Moschip MOS7720 USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-mos7720))
+
+
+define KernelPackage/usb-serial-pl2303
+  TITLE:=Support for Prolific PL2303 devices
+  KCONFIG:=CONFIG_USB_SERIAL_PL2303
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/pl2303.ko
+  AUTOLOAD:=$(call AutoProbe,pl2303)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-pl2303/description
+ Kernel support for Prolific PL2303 USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-pl2303))
+
+
+define KernelPackage/usb-serial-cp210x
+  TITLE:=Support for Silicon Labs cp210x devices
+  KCONFIG:=CONFIG_USB_SERIAL_CP210X
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/cp210x.ko
+  AUTOLOAD:=$(call AutoProbe,cp210x)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-cp210x/description
+ Kernel support for Silicon Labs cp210x USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-cp210x))
+
+
+define KernelPackage/usb-serial-ark3116
+  TITLE:=Support for ArkMicroChips ARK3116 devices
+  KCONFIG:=CONFIG_USB_SERIAL_ARK3116
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/ark3116.ko
+  AUTOLOAD:=$(call AutoProbe,ark3116)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-ark3116/description
+ Kernel support for ArkMicroChips ARK3116 USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-ark3116))
+
+
+define KernelPackage/usb-serial-oti6858
+  TITLE:=Support for Ours Technology OTI6858 devices
+  KCONFIG:=CONFIG_USB_SERIAL_OTI6858
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/oti6858.ko
+  AUTOLOAD:=$(call AutoProbe,oti6858)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-oti6858/description
+ Kernel support for Ours Technology OTI6858 USB-to-Serial converters
+endef
+
+$(eval $(call KernelPackage,usb-serial-oti6858))
+
+
+define KernelPackage/usb-serial-sierrawireless
+  TITLE:=Support for Sierra Wireless devices
+  KCONFIG:=CONFIG_USB_SERIAL_SIERRAWIRELESS
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/sierra.ko
+  AUTOLOAD:=$(call AutoProbe,sierra)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-sierrawireless/description
+ Kernel support for Sierra Wireless devices
+endef
+
+$(eval $(call KernelPackage,usb-serial-sierrawireless))
+
+
+define KernelPackage/usb-serial-visor
+  TITLE:=Support for Handspring Visor devices
+  KCONFIG:=CONFIG_USB_SERIAL_VISOR
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/visor.ko
+  AUTOLOAD:=$(call AutoProbe,visor)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-visor/description
+ Kernel support for Handspring Visor PDAs
+endef
+
+$(eval $(call KernelPackage,usb-serial-visor))
+
+
+define KernelPackage/usb-serial-cypress-m8
+  TITLE:=Support for CypressM8 USB-Serial
+  KCONFIG:=CONFIG_USB_SERIAL_CYPRESS_M8
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/cypress_m8.ko
+  AUTOLOAD:=$(call AutoProbe,cypress_m8)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-cypress-m8/description
+ Kernel support for devices with Cypress M8 USB to Serial chip
+ (for example, the Delorme Earthmate LT-20 GPS)
+ Supported microcontrollers in the CY4601 family are:
+ CY7C63741 CY7C63742 CY7C63743 CY7C64013
+endef
+
+$(eval $(call KernelPackage,usb-serial-cypress-m8))
+
+
+define KernelPackage/usb-serial-keyspan
+  TITLE:=Support for Keyspan USB-to-Serial devices
+  KCONFIG:= \
+	CONFIG_USB_SERIAL_KEYSPAN \
+	CONFIG_USB_SERIAL_KEYSPAN_USA28 \
+	CONFIG_USB_SERIAL_KEYSPAN_USA28X \
+	CONFIG_USB_SERIAL_KEYSPAN_USA28XA \
+	CONFIG_USB_SERIAL_KEYSPAN_USA28XB \
+	CONFIG_USB_SERIAL_KEYSPAN_USA19 \
+	CONFIG_USB_SERIAL_KEYSPAN_USA18X \
+	CONFIG_USB_SERIAL_KEYSPAN_USA19W \
+	CONFIG_USB_SERIAL_KEYSPAN_USA19QW \
+	CONFIG_USB_SERIAL_KEYSPAN_USA19QI \
+	CONFIG_USB_SERIAL_KEYSPAN_MPR \
+	CONFIG_USB_SERIAL_KEYSPAN_USA49W \
+	CONFIG_USB_SERIAL_KEYSPAN_USA49WLC
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/serial/keyspan.ko \
+	$(wildcard $(LINUX_DIR)/drivers/usb/misc/ezusb.ko)
+  AUTOLOAD:=$(call AutoProbe,ezusb keyspan)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-keyspan/description
+ Kernel support for Keyspan USB-to-Serial devices
+endef
+
+$(eval $(call KernelPackage,usb-serial-keyspan))
+
+
+define KernelPackage/usb-serial-wwan
+  TITLE:=Support for GSM and CDMA modems
+  KCONFIG:=CONFIG_USB_SERIAL_WWAN
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/usb_wwan.ko
+  AUTOLOAD:=$(call AutoProbe,usb_wwan)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-wwan/description
+ Kernel support for USB GSM and CDMA modems
+endef
+
+$(eval $(call KernelPackage,usb-serial-wwan))
+
+
+define KernelPackage/usb-serial-option
+  TITLE:=Support for Option HSDPA modems
+  DEPENDS:=+kmod-usb-serial-wwan
+  KCONFIG:=CONFIG_USB_SERIAL_OPTION
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/option.ko
+  AUTOLOAD:=$(call AutoProbe,option)
+  $(call AddDepends/usb-serial)
+endef
+
+define KernelPackage/usb-serial-option/description
+ Kernel support for Option HSDPA modems
+endef
+
+$(eval $(call KernelPackage,usb-serial-option))
+
+
+define KernelPackage/usb-serial-qualcomm
+  TITLE:=Support for Qualcomm USB serial
+  KCONFIG:=CONFIG_USB_SERIAL_QUALCOMM
+  FILES:=$(LINUX_DIR)/drivers/usb/serial/qcserial.ko
+  AUTOLOAD:=$(call AutoProbe,qcserial)
+  $(call AddDepends/usb-serial,+kmod-usb-serial-wwan)
+endef
+
+define KernelPackage/usb-serial-qualcomm/description
+ Kernel support for Qualcomm USB Serial devices (Gobi)
+endef
+
+$(eval $(call KernelPackage,usb-serial-qualcomm))
+
+
+define KernelPackage/usb-storage
+  TITLE:=USB Storage support
+  DEPENDS:= +kmod-scsi-core
+  KCONFIG:=CONFIG_USB_STORAGE
+  FILES:=$(LINUX_DIR)/drivers/usb/storage/usb-storage.ko
+  AUTOLOAD:=$(call AutoProbe,usb-storage,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-storage/description
+ Kernel support for USB Mass Storage devices
+endef
+
+$(eval $(call KernelPackage,usb-storage))
+
+
+define KernelPackage/usb-storage-extras
+  SUBMENU:=$(USB_MENU)
+  TITLE:=Extra drivers for usb-storage
+  DEPENDS:=+kmod-usb-storage
+  KCONFIG:= \
+	CONFIG_USB_STORAGE_ALAUDA \
+	CONFIG_USB_STORAGE_CYPRESS_ATACB \
+	CONFIG_USB_STORAGE_DATAFAB \
+	CONFIG_USB_STORAGE_FREECOM \
+	CONFIG_USB_STORAGE_ISD200 \
+	CONFIG_USB_STORAGE_JUMPSHOT \
+	CONFIG_USB_STORAGE_KARMA \
+	CONFIG_USB_STORAGE_SDDR09 \
+	CONFIG_USB_STORAGE_SDDR55 \
+	CONFIG_USB_STORAGE_USBAT
+  FILES:= \
+	$(LINUX_DIR)/drivers/usb/storage/ums-alauda.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-cypress.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-datafab.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-freecom.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-isd200.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-jumpshot.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-karma.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-sddr09.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-sddr55.ko \
+	$(LINUX_DIR)/drivers/usb/storage/ums-usbat.ko
+  AUTOLOAD:=$(call AutoProbe,ums-alauda ums-cypress ums-datafab \
+				ums-freecom ums-isd200 ums-jumpshot \
+				ums-karma ums-sddr09 ums-sddr55 ums-usbat)
+endef
+
+define KernelPackage/usb-storage-extras/description
+ Say Y here if you want to have some more drivers,
+ such as for SmartMedia card readers
+endef
+
+$(eval $(call KernelPackage,usb-storage-extras))
+
+
+define KernelPackage/usb-atm
+  TITLE:=Support for ATM on USB bus
+  DEPENDS:=+kmod-atm
+  KCONFIG:=CONFIG_USB_ATM
+  FILES:=$(LINUX_DIR)/drivers/usb/atm/usbatm.ko
+  AUTOLOAD:=$(call AutoProbe,usbatm)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-atm/description
+ Kernel support for USB DSL modems
+endef
+
+$(eval $(call KernelPackage,usb-atm))
+
+
+define AddDepends/usb-atm
+  SUBMENU:=$(USB_MENU)
+  DEPENDS+=kmod-usb-atm $(1)
+endef
+
+
+define KernelPackage/usb-atm-speedtouch
+  TITLE:=SpeedTouch USB ADSL modems support
+  KCONFIG:=CONFIG_USB_SPEEDTOUCH
+  FILES:=$(LINUX_DIR)/drivers/usb/atm/speedtch.ko
+  AUTOLOAD:=$(call AutoProbe,speedtch)
+  $(call AddDepends/usb-atm)
+endef
+
+define KernelPackage/usb-atm-speedtouch/description
+ Kernel support for SpeedTouch USB ADSL modems
+endef
+
+$(eval $(call KernelPackage,usb-atm-speedtouch))
+
+
+define KernelPackage/usb-atm-ueagle
+  TITLE:=Eagle 8051 based USB ADSL modems support
+  FILES:=$(LINUX_DIR)/drivers/usb/atm/ueagle-atm.ko
+  KCONFIG:=CONFIG_USB_UEAGLEATM
+  AUTOLOAD:=$(call AutoProbe,ueagle-atm)
+  $(call AddDepends/usb-atm)
+endef
+
+define KernelPackage/usb-atm-ueagle/description
+ Kernel support for Eagle 8051 based USB ADSL modems
+endef
+
+$(eval $(call KernelPackage,usb-atm-ueagle))
+
+
+define KernelPackage/usb-atm-cxacru
+  TITLE:=cxacru
+  FILES:=$(LINUX_DIR)/drivers/usb/atm/cxacru.ko
+  KCONFIG:=CONFIG_USB_CXACRU
+  AUTOLOAD:=$(call AutoProbe,cxacru)
+  $(call AddDepends/usb-atm)
+endef
+
+define KernelPackage/usb-atm-cxacru/description
+ Kernel support for cxacru based USB ADSL modems
+endef
+
+$(eval $(call KernelPackage,usb-atm-cxacru))
+
+
+define KernelPackage/usb-net
+  TITLE:=Kernel modules for USB-to-Ethernet convertors
+  DEPENDS:=+kmod-mii
+  KCONFIG:=CONFIG_USB_USBNET \
+	CONFIG_USB_NET_DRIVERS
+  AUTOLOAD:=$(call AutoProbe,usbnet)
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/usbnet.ko
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-net/description
+ Kernel modules for USB-to-Ethernet convertors
+endef
+
+$(eval $(call KernelPackage,usb-net))
+
+
+define AddDepends/usb-net
+  SUBMENU:=$(USB_MENU)
+  DEPENDS+=kmod-usb-net $(1)
+endef
+
+
+define KernelPackage/usb-net-asix
+  TITLE:=Kernel module for USB-to-Ethernet Asix convertors
+  DEPENDS:=+kmod-libphy
+  KCONFIG:=CONFIG_USB_NET_AX8817X
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/asix.ko
+  AUTOLOAD:=$(call AutoProbe,asix)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-asix/description
+ Kernel module for USB-to-Ethernet Asix convertors
+endef
+
+$(eval $(call KernelPackage,usb-net-asix))
+
+
+define KernelPackage/usb-net-asix-ax88179
+  TITLE:=Kernel module for USB-to-Gigabit-Ethernet Asix convertors
+  DEPENDS:=+kmod-libphy
+  KCONFIG:=CONFIG_USB_NET_AX88179_178A
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/ax88179_178a.ko
+  AUTOLOAD:=$(call AutoProbe,ax88179_178a)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-asix-ax88179/description
+ Kernel module for USB-to-Ethernet ASIX AX88179 based USB 3.0/2.0
+ to Gigabit Ethernet adapters.
+endef
+
+$(eval $(call KernelPackage,usb-net-asix-ax88179))
+
+
+define KernelPackage/usb-net-hso
+  TITLE:=Kernel module for Option USB High Speed Mobile Devices
+  KCONFIG:=CONFIG_USB_HSO
+  FILES:= \
+	$(LINUX_DIR)/drivers/$(USBNET_DIR)/hso.ko
+  AUTOLOAD:=$(call AutoProbe,hso)
+  $(call AddDepends/usb-net)
+  $(call AddDepends/rfkill)
+endef
+
+define KernelPackage/usb-net-hso/description
+ Kernel module for Option USB High Speed Mobile Devices
+endef
+
+$(eval $(call KernelPackage,usb-net-hso))
+
+
+define KernelPackage/usb-net-kaweth
+  TITLE:=Kernel module for USB-to-Ethernet Kaweth convertors
+  KCONFIG:=CONFIG_USB_KAWETH
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/kaweth.ko
+  AUTOLOAD:=$(call AutoProbe,kaweth)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-kaweth/description
+ Kernel module for USB-to-Ethernet Kaweth convertors
+endef
+
+$(eval $(call KernelPackage,usb-net-kaweth))
+
+
+define KernelPackage/usb-net-pegasus
+  TITLE:=Kernel module for USB-to-Ethernet Pegasus convertors
+  KCONFIG:=CONFIG_USB_PEGASUS
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/pegasus.ko
+  AUTOLOAD:=$(call AutoProbe,pegasus)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-pegasus/description
+ Kernel module for USB-to-Ethernet Pegasus convertors
+endef
+
+$(eval $(call KernelPackage,usb-net-pegasus))
+
+
+define KernelPackage/usb-net-mcs7830
+  TITLE:=Kernel module for USB-to-Ethernet MCS7830 convertors
+  KCONFIG:=CONFIG_USB_NET_MCS7830
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/mcs7830.ko
+  AUTOLOAD:=$(call AutoProbe,mcs7830)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-mcs7830/description
+ Kernel module for USB-to-Ethernet MCS7830 convertors
+endef
+
+$(eval $(call KernelPackage,usb-net-mcs7830))
+
+
+define KernelPackage/usb-net-smsc95xx
+  TITLE:=SMSC LAN95XX based USB 2.0 10/100 ethernet devices
+  KCONFIG:=CONFIG_USB_NET_SMSC95XX
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/smsc95xx.ko
+  AUTOLOAD:=$(call AutoProbe,smsc95xx)
+  $(call AddDepends/usb-net, +kmod-lib-crc16)
+endef
+
+define KernelPackage/usb-net-smsc95xx/description
+ Kernel module for SMSC LAN95XX based devices
+endef
+
+$(eval $(call KernelPackage,usb-net-smsc95xx))
+
+
+define KernelPackage/usb-net-dm9601-ether
+  TITLE:=Support for DM9601 ethernet connections
+  KCONFIG:=CONFIG_USB_NET_DM9601
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/dm9601.ko
+  AUTOLOAD:=$(call AutoProbe,dm9601)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-dm9601-ether/description
+ Kernel support for USB DM9601 devices
+endef
+
+$(eval $(call KernelPackage,usb-net-dm9601-ether))
+
+define KernelPackage/usb-net-cdc-ether
+  TITLE:=Support for cdc ethernet connections
+  KCONFIG:=CONFIG_USB_NET_CDCETHER
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/cdc_ether.ko
+  AUTOLOAD:=$(call AutoProbe,cdc_ether)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-cdc-ether/description
+ Kernel support for USB CDC Ethernet devices
+endef
+
+$(eval $(call KernelPackage,usb-net-cdc-ether))
+
+
+define KernelPackage/usb-net-cdc-eem
+  TITLE:=Support for CDC EEM connections
+  KCONFIG:=CONFIG_USB_NET_CDC_EEM
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/cdc_eem.ko
+  AUTOLOAD:=$(call AutoProbe,cdc_eem)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-cdc-eem/description
+ Kernel support for USB CDC EEM
+endef
+
+$(eval $(call KernelPackage,usb-net-cdc-eem))
+
+
+define KernelPackage/usb-net-cdc-subset
+  TITLE:=Support for CDC Ethernet subset connections
+  KCONFIG:= \
+	CONFIG_USB_NET_CDC_SUBSET \
+	CONFIG_USB_ARMLINUX
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/cdc_subset.ko
+  AUTOLOAD:=$(call AutoProbe,cdc_subset)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-cdc-subset/description
+ Kernel support for Simple USB Network Links (CDC Ethernet subset)
+endef
+
+$(eval $(call KernelPackage,usb-net-cdc-subset))
+
+
+define KernelPackage/usb-net-qmi-wwan
+  TITLE:=QMI WWAN driver
+  KCONFIG:=CONFIG_USB_NET_QMI_WWAN
+  FILES:= $(LINUX_DIR)/drivers/$(USBNET_DIR)/qmi_wwan.ko
+  AUTOLOAD:=$(call AutoProbe,qmi_wwan)
+  $(call AddDepends/usb-net,+kmod-usb-wdm)
+endef
+
+define KernelPackage/usb-net-qmi-wwan/description
+ QMI WWAN driver for Qualcomm MSM based 3G and LTE modems
+endef
+
+$(eval $(call KernelPackage,usb-net-qmi-wwan))
+
+
+define KernelPackage/usb-net-rtl8150
+  TITLE:=Kernel module for USB-to-Ethernet Realtek convertors
+  KCONFIG:=CONFIG_USB_RTL8150
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/rtl8150.ko
+  AUTOLOAD:=$(call AutoProbe,rtl8150)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-rtl8150/description
+ Kernel module for USB-to-Ethernet Realtek 8150 convertors
+endef
+
+$(eval $(call KernelPackage,usb-net-rtl8150))
+
+
+define KernelPackage/usb-net-rtl8152
+  TITLE:=Kernel module for USB-to-Ethernet Realtek convertors
+  KCONFIG:=CONFIG_USB_RTL8152
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/r8152.ko
+  AUTOLOAD:=$(call AutoProbe,r8152)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-rtl8152/description
+ Kernel module for USB-to-Ethernet Realtek 8152 USB2.0/3.0 convertors
+endef
+
+$(eval $(call KernelPackage,usb-net-rtl8152))
+
+
+define KernelPackage/usb-net-sr9700
+  TITLE:=Support for CoreChip SR9700 ethernet devices
+  KCONFIG:=CONFIG_USB_NET_SR9700
+  FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/sr9700.ko
+  AUTOLOAD:=$(call AutoProbe,sr9700)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-sr9700/description
+ Kernel module for CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices
+endef
+
+$(eval $(call KernelPackage,usb-net-sr9700))
+
+
+define KernelPackage/usb-net-rndis
+  TITLE:=Support for RNDIS connections
+  KCONFIG:=CONFIG_USB_NET_RNDIS_HOST
+  FILES:= $(LINUX_DIR)/drivers/$(USBNET_DIR)/rndis_host.ko
+  AUTOLOAD:=$(call AutoProbe,rndis_host)
+  $(call AddDepends/usb-net,+kmod-usb-net-cdc-ether)
+endef
+
+define KernelPackage/usb-net-rndis/description
+ Kernel support for RNDIS connections
+endef
+
+$(eval $(call KernelPackage,usb-net-rndis))
+
+
+define KernelPackage/usb-net-cdc-mbim
+  SUBMENU:=$(USB_MENU)
+  TITLE:=Kernel module for MBIM Devices
+  KCONFIG:=CONFIG_USB_NET_CDC_MBIM
+  FILES:= \
+   $(LINUX_DIR)/drivers/$(USBNET_DIR)/cdc_mbim.ko
+  AUTOLOAD:=$(call AutoProbe,cdc_mbim)
+  $(call AddDepends/usb-net,+kmod-usb-wdm +kmod-usb-net-cdc-ncm)
+endef
+
+define KernelPackage/usb-net-cdc-mbim/description
+ Kernel module for Option USB High Speed Mobile Devices
+endef
+
+$(eval $(call KernelPackage,usb-net-cdc-mbim))
+
+
+define KernelPackage/usb-net-cdc-ncm
+  TITLE:=Support for CDC NCM connections
+  KCONFIG:=CONFIG_USB_NET_CDC_NCM
+  FILES:= $(LINUX_DIR)/drivers/$(USBNET_DIR)/cdc_ncm.ko
+  AUTOLOAD:=$(call AutoProbe,cdc_ncm)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-cdc-ncm/description
+ Kernel support for CDC NCM connections
+endef
+
+$(eval $(call KernelPackage,usb-net-cdc-ncm))
+
+
+define KernelPackage/usb-net-huawei-cdc-ncm
+  TITLE:=Support for Huawei CDC NCM connections
+  KCONFIG:=CONFIG_USB_NET_HUAWEI_CDC_NCM
+  FILES:= $(LINUX_DIR)/drivers/$(USBNET_DIR)/huawei_cdc_ncm.ko
+  AUTOLOAD:=$(call AutoProbe,huawei_cdc_ncm)
+  $(call AddDepends/usb-net,+kmod-usb-net-cdc-ncm +kmod-usb-wdm)
+endef
+
+define KernelPackage/usb-net-huawei-cdc-ncm/description
+ Kernel support for Huawei CDC NCM connections
+endef
+
+$(eval $(call KernelPackage,usb-net-huawei-cdc-ncm))
+
+
+define KernelPackage/usb-net-sierrawireless
+  TITLE:=Support for Sierra Wireless devices
+  KCONFIG:=CONFIG_USB_SIERRA_NET
+  FILES:=$(LINUX_DIR)/drivers/net/usb/sierra_net.ko
+  AUTOLOAD:=$(call AutoProbe,sierra_net)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-sierrawireless/description
+ Kernel support for Sierra Wireless devices
+endef
+
+$(eval $(call KernelPackage,usb-net-sierrawireless))
+
+
+define KernelPackage/usb-net-ipheth
+  TITLE:=Apple iPhone USB Ethernet driver
+  KCONFIG:=CONFIG_USB_IPHETH
+  FILES:=$(LINUX_DIR)/drivers/net/usb/ipheth.ko
+  AUTOLOAD:=$(call AutoProbe,ipheth)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-ipheth/description
+ Kernel support for Apple iPhone USB Ethernet driver
+endef
+
+$(eval $(call KernelPackage,usb-net-ipheth))
+
+
+define KernelPackage/usb-net-kalmia
+  TITLE:=Samsung Kalmia based LTE USB modem
+  KCONFIG:=CONFIG_USB_NET_KALMIA
+  FILES:=$(LINUX_DIR)/drivers/net/usb/kalmia.ko
+  AUTOLOAD:=$(call AutoProbe,kalmia)
+  $(call AddDepends/usb-net)
+endef
+
+define KernelPackage/usb-net-kalmia/description
+ Kernel support for Samsung Kalmia based LTE USB modem
+endef
+
+$(eval $(call KernelPackage,usb-net-kalmia))
+
+
+define KernelPackage/usb-hid
+  TITLE:=Support for USB Human Input Devices
+  KCONFIG:=CONFIG_HID_SUPPORT=y CONFIG_USB_HID CONFIG_USB_HIDDEV=y
+  DEPENDS:=+kmod-hid +kmod-hid-generic +kmod-input-evdev
+  FILES:=$(LINUX_DIR)/drivers/$(USBHID_DIR)/usbhid.ko
+  AUTOLOAD:=$(call AutoProbe,usbhid)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-hid/description
+ Kernel support for USB HID devices such as keyboards and mice
+endef
+
+$(eval $(call KernelPackage,usb-hid))
+
+
+define KernelPackage/usb-yealink
+  TITLE:=USB Yealink VOIP phone
+  DEPENDS:=+kmod-input-evdev
+  KCONFIG:=CONFIG_USB_YEALINK CONFIG_INPUT_YEALINK CONFIG_INPUT=m CONFIG_INPUT_MISC=y
+  FILES:=$(LINUX_DIR)/drivers/$(USBINPUT_DIR)/yealink.ko
+  AUTOLOAD:=$(call AutoProbe,yealink)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-yealink/description
+ Kernel support for Yealink VOIP phone
+endef
+
+$(eval $(call KernelPackage,usb-yealink))
+
+
+define KernelPackage/usb-cm109
+  TITLE:=Support for CM109 device
+  DEPENDS:=+kmod-input-evdev
+  KCONFIG:=CONFIG_USB_CM109 CONFIG_INPUT_CM109 CONFIG_INPUT=m CONFIG_INPUT_MISC=y
+  FILES:=$(LINUX_DIR)/drivers/$(USBINPUT_DIR)/cm109.ko
+  AUTOLOAD:=$(call AutoProbe,cm109)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-cm109/description
+ Kernel support for CM109 VOIP phone
+endef
+
+$(eval $(call KernelPackage,usb-cm109))
+
+
+define KernelPackage/usb-test
+  TITLE:=USB Testing Driver
+  DEPENDS:=@DEVEL
+  KCONFIG:=CONFIG_USB_TEST
+  FILES:=$(LINUX_DIR)/drivers/usb/misc/usbtest.ko
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-test/description
+ Kernel support for testing USB Host Controller software
+endef
+
+$(eval $(call KernelPackage,usb-test))
+
+
+define KernelPackage/usbip
+  TITLE := USB-over-IP kernel support
+  KCONFIG:= \
+	CONFIG_USBIP_CORE \
+	CONFIG_USBIP_DEBUG=n
+  FILES:=$(LINUX_DIR)/drivers/usb/usbip/usbip-core.ko
+  AUTOLOAD:=$(call AutoProbe,usbip-core)
+  $(call AddDepends/usb)
+endef
+
+$(eval $(call KernelPackage,usbip))
+
+
+define KernelPackage/usbip-client
+  TITLE := USB-over-IP client driver
+  DEPENDS := +kmod-usbip
+  KCONFIG := CONFIG_USBIP_VHCI_HCD
+  FILES :=$(LINUX_DIR)/drivers/usb/usbip/vhci-hcd.ko
+  AUTOLOAD := $(call AutoProbe,vhci-hcd)
+  $(call AddDepends/usb)
+endef
+
+$(eval $(call KernelPackage,usbip-client))
+
+
+define KernelPackage/usbip-server
+$(call KernelPackage/usbip/Default)
+  TITLE := USB-over-IP host driver
+  DEPENDS := +kmod-usbip
+  KCONFIG := CONFIG_USBIP_HOST
+  FILES :=$(LINUX_DIR)/drivers/usb/usbip/usbip-host.ko
+  AUTOLOAD := $(call AutoProbe,usbip-host)
+  $(call AddDepends/usb)
+endef
+
+$(eval $(call KernelPackage,usbip-server))
+
+
+define KernelPackage/usb-chipidea-imx
+  TITLE:=Support for ChipIdea controllers
+  DEPENDS:=@TARGET_imx6||TARGET_mxs +kmod-usb2 +USB_GADGET_SUPPORT:kmod-usb-gadget
+  KCONFIG:=\
+	CONFIG_USB_CHIPIDEA \
+	CONFIG_USB_CHIPIDEA_HOST=y \
+	CONFIG_USB_CHIPIDEA_UDC=y \
+	CONFIG_USB_CHIPIDEA_DEBUG=y
+  FILES:=\
+	$(LINUX_DIR)/drivers/usb/chipidea/ci_hdrc.ko \
+	$(if $(CONFIG_OF),$(LINUX_DIR)/drivers/usb/chipidea/ci_hdrc_imx.ko) \
+	$(if $(CONFIG_OF),$(LINUX_DIR)/drivers/usb/chipidea/usbmisc_imx.ko)
+  AUTOLOAD:=$(call AutoLoad,51,ci_hdrc $(if $(CONFIG_OF),ci_hdrc_imx usbmisc_imx),1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-chipidea-imx/description
+ Kernel support for USB ChipIdea controllers
+endef
+
+$(eval $(call KernelPackage,usb-chipidea-imx,1))
+
+
+define KernelPackage/usb-mxs-phy
+  TITLE:=Support for Freescale MXS USB PHY
+  DEPENDS:=@TARGET_imx6||TARGET_mxs +TARGET_mxs:kmod-usb-chipidea-imx
+  KCONFIG:=CONFIG_USB_MXS_PHY
+  FILES:=\
+	$(LINUX_DIR)/drivers/usb/phy/phy-mxs-usb.ko
+  AUTOLOAD:=$(call AutoLoad,52,phy-mxs-usb,1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-mxs-phy/description
+ Kernel support for Freescale MXS USB PHY
+endef
+
+$(eval $(call KernelPackage,usb-mxs-phy,1))
+
+
+define KernelPackage/usbmon
+  TITLE:=USB traffic monitor
+  KCONFIG:=CONFIG_USB_MON
+  $(call AddDepends/usb)
+  FILES:=$(LINUX_DIR)/drivers/usb/mon/usbmon.ko
+  AUTOLOAD:=$(call AutoProbe,usbmon)
+endef
+
+define KernelPackage/usbmon/description
+ Kernel support for USB traffic monitoring
+endef
+
+$(eval $(call KernelPackage,usbmon))
+
+XHCI_MODULES := xhci-hcd xhci-pci xhci-plat-hcd
+ifdef CONFIG_TARGET_ramips_mt7621
+  XHCI_MODULES += xhci-mtk
+endif
+XHCI_FILES := $(wildcard $(patsubst %,$(LINUX_DIR)/drivers/usb/host/%.ko,$(XHCI_MODULES)))
+XHCI_AUTOLOAD := $(patsubst $(LINUX_DIR)/drivers/usb/host/%.ko,%,$(XHCI_FILES))
+
+define KernelPackage/usb3
+  TITLE:=Support for USB3 controllers
+  DEPENDS:= \
+	+TARGET_bcm53xx:kmod-usb-bcma \
+	+TARGET_bcm53xx:kmod-phy-bcm-ns-usb3 \
+	+TARGET_omap:kmod-usb-phy-omap-usb3
+  KCONFIG:= \
+	CONFIG_USB_XHCI_HCD \
+	CONFIG_USB_XHCI_PCI \
+	CONFIG_USB_XHCI_PLATFORM \
+	CONFIG_USB_XHCI_MVEBU=y \
+	CONFIG_USB_XHCI_MTK \
+	CONFIG_USB_XHCI_HCD_DEBUGGING=n
+  FILES:= \
+	$(XHCI_FILES)
+  AUTOLOAD:=$(call AutoLoad,54,$(XHCI_AUTOLOAD),1)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb3/description
+ Kernel support for USB3 (XHCI) controllers
+endef
+
+$(eval $(call KernelPackage,usb3))
+
+
+define KernelPackage/usb-net2280
+  TITLE:=Support for NetChip 228x PCI USB peripheral controller
+  KCONFIG:= CONFIG_USB_NET2280
+  DEPENDS:=@PCI_SUPPORT +kmod-usb-gadget
+  FILES:=$(LINUX_DIR)/drivers/usb/gadget/udc/net2280.ko
+  AUTOLOAD:=$(call AutoLoad,46,net2280)
+  $(call AddDepends/usb)
+endef
+
+define KernelPackage/usb-net2280/description
+  Kernel support for NetChip 228x / PLX USB338x PCI USB peripheral controller.
+endef
+
+$(eval $(call KernelPackage,usb-net2280))
+
diff --git a/package/kernel/linux/modules/video.mk b/package/kernel/linux/modules/video.mk
new file mode 100644
index 0000000000..fb85f23223
--- /dev/null
+++ b/package/kernel/linux/modules/video.mk
@@ -0,0 +1,948 @@
+#
+# Copyright (C) 2009 David Cooper <dave@kupesoft.com>
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+VIDEO_MENU:=Video Support
+
+V4L2_DIR=v4l2-core
+V4L2_USB_DIR=usb
+
+#
+# Video Display
+#
+
+define KernelPackage/backlight
+	SUBMENU:=$(VIDEO_MENU)
+	TITLE:=Backlight support
+	DEPENDS:=@DISPLAY_SUPPORT
+	HIDDEN:=1
+	KCONFIG:=CONFIG_BACKLIGHT_CLASS_DEVICE \
+		CONFIG_BACKLIGHT_LCD_SUPPORT=y \
+		CONFIG_LCD_CLASS_DEVICE=n \
+		CONFIG_BACKLIGHT_GENERIC=n \
+		CONFIG_BACKLIGHT_ADP8860=n \
+		CONFIG_BACKLIGHT_ADP8870=n \
+		CONFIG_BACKLIGHT_OT200=n \
+		CONFIG_BACKLIGHT_PM8941_WLED=n
+	FILES:=$(LINUX_DIR)/drivers/video/backlight/backlight.ko
+	AUTOLOAD:=$(call AutoProbe,video backlight)
+endef
+
+define KernelPackage/backlight/description
+	Kernel module for Backlight support.
+endef
+
+$(eval $(call KernelPackage,backlight))
+
+define KernelPackage/backlight-pwm
+	SUBMENU:=$(VIDEO_MENU)
+	TITLE:=PWM Backlight support
+	DEPENDS:=+kmod-backlight
+	KCONFIG:=CONFIG_BACKLIGHT_PWM
+	FILES:=$(LINUX_DIR)/drivers/video/backlight/pwm_bl.ko
+	AUTOLOAD:=$(call AutoProbe,video pwm_bl)
+endef
+
+define KernelPackage/backlight/backlight-pwm
+	Kernel module for PWM based Backlight support.
+endef
+
+$(eval $(call KernelPackage,backlight-pwm))
+
+
+define KernelPackage/fb
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Framebuffer support
+  DEPENDS:=@DISPLAY_SUPPORT
+  KCONFIG:= \
+	CONFIG_FB \
+	CONFIG_FB_MXS=n \
+	CONFIG_FB_SM750=n
+  FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb.ko
+  AUTOLOAD:=$(call AutoLoad,06,fb)
+endef
+
+define KernelPackage/fb/description
+ Kernel support for framebuffers
+endef
+
+define KernelPackage/fb/x86
+  FILES+=$(LINUX_DIR)/arch/x86/video/fbdev.ko
+  AUTOLOAD:=$(call AutoLoad,06,fbdev fb)
+endef
+
+$(eval $(call KernelPackage,fb))
+
+
+define KernelPackage/fbcon
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Framebuffer Console support
+  DEPENDS:=+kmod-fb
+  KCONFIG:= \
+	CONFIG_FRAMEBUFFER_CONSOLE \
+	CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y \
+	CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y \
+	CONFIG_FONTS=y \
+	CONFIG_FONT_8x8=y \
+	CONFIG_FONT_8x16=y \
+	CONFIG_FONT_6x11=n \
+	CONFIG_FONT_7x14=n \
+	CONFIG_FONT_PEARL_8x8=n \
+	CONFIG_FONT_ACORN_8x8=n \
+	CONFIG_FONT_MINI_4x6=n \
+	CONFIG_FONT_6x10=n \
+	CONFIG_FONT_SUN8x16=n \
+	CONFIG_FONT_SUN12x22=n \
+	CONFIG_FONT_10x18=n \
+	CONFIG_VT=y \
+	CONFIG_CONSOLE_TRANSLATIONS=y \
+	CONFIG_VT_CONSOLE=y \
+	CONFIG_VT_HW_CONSOLE_BINDING=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/video/console/bitblit.ko \
+	$(LINUX_DIR)/drivers/video/console/softcursor.ko \
+	$(LINUX_DIR)/drivers/video/console/fbcon.ko \
+	$(LINUX_DIR)/drivers/video/console/fbcon_rotate.ko \
+	$(LINUX_DIR)/drivers/video/console/fbcon_cw.ko \
+	$(LINUX_DIR)/drivers/video/console/fbcon_ud.ko \
+	$(LINUX_DIR)/drivers/video/console/fbcon_ccw.ko \
+	$(LINUX_DIR)/lib/fonts/font.ko
+  AUTOLOAD:=$(call AutoLoad,94,font softcursor tileblit fbcon_cw fbcon_ud fbcon_ccw fbcon_rotate bitblit fbcon)
+endef
+
+define KernelPackage/fbcon/description
+  Kernel support for framebuffer console
+endef
+
+$(eval $(call KernelPackage,fbcon))
+
+define KernelPackage/fb-cfb-fillrect
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Framebuffer software rectangle filling support
+  DEPENDS:=+kmod-fb
+  KCONFIG:=CONFIG_FB_CFB_FILLRECT
+  FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/cfbfillrect.ko
+  AUTOLOAD:=$(call AutoLoad,07,cfbfillrect)
+endef
+
+define KernelPackage/fb-cfb-fillrect/description
+ Kernel support for software rectangle filling
+endef
+
+$(eval $(call KernelPackage,fb-cfb-fillrect))
+
+
+define KernelPackage/fb-cfb-copyarea
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Framebuffer software copy area support
+  DEPENDS:=+kmod-fb
+  KCONFIG:=CONFIG_FB_CFB_COPYAREA
+  FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/cfbcopyarea.ko
+  AUTOLOAD:=$(call AutoLoad,07,cfbcopyarea)
+endef
+
+define KernelPackage/fb-cfb-copyarea/description
+ Kernel support for software copy area
+endef
+
+$(eval $(call KernelPackage,fb-cfb-copyarea))
+
+define KernelPackage/fb-cfb-imgblt
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Framebuffer software image blit support
+  DEPENDS:=+kmod-fb
+  KCONFIG:=CONFIG_FB_CFB_IMAGEBLIT
+  FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/cfbimgblt.ko
+  AUTOLOAD:=$(call AutoLoad,07,cfbimgblt)
+endef
+
+define KernelPackage/fb-cfb-imgblt/description
+ Kernel support for software image blitting
+endef
+
+$(eval $(call KernelPackage,fb-cfb-imgblt))
+
+
+define KernelPackage/fb-sys-fops
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Framebuffer software sys ops support
+  DEPENDS:=+kmod-fb
+  KCONFIG:=CONFIG_FB_SYS_FOPS
+  FILES:=$(LINUX_DIR)/drivers/video/fbdev/core/fb_sys_fops.ko
+  AUTOLOAD:=$(call AutoLoad,07,fbsysfops)
+endef
+
+define KernelPackage/fb-sys-fops/description
+ Kernel support for framebuffer sys ops
+endef
+
+$(eval $(call KernelPackage,fb-sys-fops))
+
+define KernelPackage/drm
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Direct Rendering Manager (DRM) support
+  HIDDEN:=1
+  DEPENDS:=+kmod-dma-buf
+  KCONFIG:=CONFIG_DRM \
+	CONFIG_DRM_FBDEV_EMULATION=n \
+	CONFIG_DRM_LOAD_EDID_FIRMWARE=n \
+	CONFIG_DRM_IMX=n \
+	CONFIG_DRM_PTN3460=n \
+	CONFIG_DRM_PS8622=n \
+	CONFIG_DRM_TDFX=n \
+	CONFIG_DRM_R128=n \
+	CONFIG_DRM_RADEON=n \
+	CONFIG_DRM_AMDGPU=n \
+	CONFIG_DRM_NOUVEAU=n \
+	CONFIG_DRM_MGA=n \
+	CONFIG_DRM_VIA=n \
+	CONFIG_DRM_SAVAGE=n \
+	CONFIG_DRM_VGEM=n \
+	CONFIG_DRM_EXYNOS=n \
+	CONFIG_DRM_VMWGFX=n \
+	CONFIG_DRM_UDL=n \
+	CONFIG_DRM_AST=n \
+	CONFIG_DRM_MGAG200=n \
+	CONFIG_DRM_CIRRUS_QEMU=n \
+	CONFIG_DRM_ARMADA=n \
+	CONFIG_DRM_TILCDC=n \
+	CONFIG_DRM_QXL=n \
+	CONFIG_DRM_BOCHS=n \
+	CONFIG_DRM_FSL_DCU=n \
+	CONFIG_DRM_STI=n \
+	CONFIG_DRM_NXP_PTN3460=n \
+	CONFIG_DRM_PARADE_PS8622=n \
+	CONFIG_DRM_I2C_ADV7511=n \
+	CONFIG_DRM_I2C_CH7006=n \
+	CONFIG_DRM_I2C_SIL164=n \
+	CONFIG_DRM_I2C_NXP_TDA998X=n
+  FILES:=$(LINUX_DIR)/drivers/gpu/drm/drm.ko
+  AUTOLOAD:=$(call AutoLoad,05,drm)
+endef
+
+define KernelPackage/drm/description
+  Direct Rendering Manager (DRM) core support
+endef
+
+$(eval $(call KernelPackage,drm))
+
+define KernelPackage/drm-imx
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Freescale i.MX DRM support
+  DEPENDS:=@TARGET_imx6 +kmod-drm +kmod-fb +kmod-fb-cfb-copyarea +kmod-fb-cfb-imgblt +kmod-fb-cfb-fillrect +kmod-fb-sys-fops
+  KCONFIG:=CONFIG_DRM_IMX \
+	CONFIG_DRM_FBDEV_EMULATION=y \
+	CONFIG_IMX_IPUV3_CORE \
+	CONFIG_RESET_CONTROLLER=y \
+	CONFIG_DRM_IMX_IPUV3 \
+	CONFIG_IMX_IPUV3 \
+	CONFIG_DRM_KMS_HELPER \
+	CONFIG_FB_SYS_FILLRECT \
+	CONFIG_FB_SYS_COPYAREA \
+	CONFIG_FB_SYS_IMAGEBLIT \
+	CONFIG_DRM_KMS_FB_HELPER=y \
+	CONFIG_DRM_GEM_CMA_HELPER=y \
+	CONFIG_DRM_KMS_CMA_HELPER=y \
+	CONFIG_DRM_IMX_FB_HELPER \
+	CONFIG_DRM_IMX_PARALLEL_DISPLAY=n \
+	CONFIG_DRM_IMX_TVE=n \
+	CONFIG_DRM_IMX_LDB=n \
+	CONFIG_DRM_IMX_HDMI=n
+  FILES:= \
+	$(LINUX_DIR)/drivers/gpu/drm/imx/imxdrm.ko \
+	$(LINUX_DIR)/drivers/gpu/ipu-v3/imx-ipu-v3.ko \
+	$(LINUX_DIR)/drivers/gpu/drm/imx/imx-ipuv3-crtc.ko \
+	$(LINUX_DIR)/drivers/video/fbdev/core/syscopyarea.ko \
+	$(LINUX_DIR)/drivers/video/fbdev/core/sysfillrect.ko \
+	$(LINUX_DIR)/drivers/video/fbdev/core/sysimgblt.ko \
+	$(LINUX_DIR)/drivers/gpu/drm/drm_kms_helper.ko
+  AUTOLOAD:=$(call AutoLoad,05,imxdrm imx-ipu-v3 imx-ipuv3-crtc)
+endef
+
+define KernelPackage/drm-imx/description
+  Direct Rendering Manager (DRM) support for Freescale i.MX
+endef
+
+$(eval $(call KernelPackage,drm-imx))
+
+define KernelPackage/drm-imx-hdmi
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Freescale i.MX HDMI DRM support
+  DEPENDS:=+kmod-sound-core kmod-drm-imx
+  KCONFIG:=CONFIG_DRM_IMX_HDMI \
+	CONFIG_DRM_DW_HDMI_AHB_AUDIO
+  FILES:= \
+	$(LINUX_DIR)/drivers/gpu/drm/bridge/dw_hdmi.ko \
+	$(LINUX_DIR)/drivers/gpu/drm/bridge/dw_hdmi-ahb-audio.ko \
+	$(LINUX_DIR)/drivers/gpu/drm/imx/dw_hdmi-imx.ko
+  AUTOLOAD:=$(call AutoLoad,05,dw_hdmi dw_hdmi-ahb-audio.ko dw_hdmi-imx)
+endef
+
+define KernelPackage/drm-imx-hdmi/description
+  Direct Rendering Manager (DRM) support for Freescale i.MX HDMI
+endef
+
+$(eval $(call KernelPackage,drm-imx-hdmi))
+
+define KernelPackage/drm-imx-ldb
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE:=Freescale i.MX LVDS DRM support
+  DEPENDS:=+kmod-backlight kmod-drm-imx
+  KCONFIG:=CONFIG_DRM_IMX_LDB \
+	CONFIG_DRM_PANEL_SIMPLE \
+	CONFIG_DRM_PANEL=y \
+	CONFIG_DRM_PANEL_SAMSUNG_LD9040=n \
+	CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=n \
+	CONFIG_DRM_PANEL_LG_LG4573=n \
+	CONFIG_DRM_PANEL_LD9040=n \
+	CONFIG_DRM_PANEL_S6E8AA0=n
+  FILES:=$(LINUX_DIR)/drivers/gpu/drm/imx/imx-ldb.ko \
+	$(LINUX_DIR)/drivers/gpu/drm/panel/panel-simple.ko
+  AUTOLOAD:=$(call AutoLoad,05,imx-ldb)
+endef
+
+define KernelPackage/drm-imx-ldb/description
+  Direct Rendering Manager (DRM) support for Freescale i.MX LVDS
+endef
+
+$(eval $(call KernelPackage,drm-imx-ldb))
+
+
+#
+# Video Capture
+#
+
+define KernelPackage/video-core
+  SUBMENU:=$(VIDEO_MENU)
+  TITLE=Video4Linux support
+  DEPENDS:=@PCI_SUPPORT||USB_SUPPORT +PACKAGE_kmod-i2c-core:kmod-i2c-core
+  KCONFIG:= \
+	CONFIG_MEDIA_SUPPORT \
+	CONFIG_MEDIA_CAMERA_SUPPORT=y \
+	CONFIG_VIDEO_DEV \
+	CONFIG_VIDEO_V4L1=y \
+	CONFIG_VIDEO_ALLOW_V4L1=y \
+	CONFIG_VIDEO_CAPTURE_DRIVERS=y \
+	CONFIG_V4L_USB_DRIVERS=y \
+	CONFIG_V4L_PCI_DRIVERS=y \
+	CONFIG_V4L_PLATFORM_DRIVERS=y \
+	CONFIG_V4L_ISA_PARPORT_DRIVERS=y
+  FILES:= \
+	$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/v4l2-common.ko \
+	$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/videodev.ko
+  AUTOLOAD:=$(call AutoLoad,60, videodev v4l2-common)
+endef
+
+define KernelPackage/video-core/description
+ Kernel modules for Video4Linux support
+endef
+
+$(eval $(call KernelPackage,video-core))
+
+
+define AddDepends/video
+  SUBMENU:=$(VIDEO_MENU)
+  DEPENDS+=kmod-video-core $(1)
+endef
+
+define AddDepends/camera
+$(AddDepends/video)
+  KCONFIG+=CONFIG_MEDIA_USB_SUPPORT=y \
+	 CONFIG_MEDIA_CAMERA_SUPPORT=y
+endef
+
+
+define KernelPackage/video-videobuf2
+  TITLE:=videobuf2 lib
+  DEPENDS:=+kmod-dma-buf
+  KCONFIG:= \
+	CONFIG_VIDEOBUF2_CORE \
+	CONFIG_VIDEOBUF2_MEMOPS \
+	CONFIG_VIDEOBUF2_VMALLOC
+  FILES:= \
+	$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/videobuf2-core.ko \
+	$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/videobuf2-v4l2.ko@ge4.4 \
+	$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/videobuf2-memops.ko \
+	$(LINUX_DIR)/drivers/media/$(V4L2_DIR)/videobuf2-vmalloc.ko
+  AUTOLOAD:=$(call AutoLoad,65,videobuf2-core videobuf-v4l2@ge4.4 videobuf2-memops videobuf2-vmalloc)
+  $(call AddDepends/video)
+endef
+
+define KernelPackage/video-videobuf2/description
+ Kernel modules that implements three basic types of media buffers.
+endef
+
+$(eval $(call KernelPackage,video-videobuf2))
+
+
+define KernelPackage/video-cpia2
+  TITLE:=CPIA2 video driver
+  DEPENDS:=@USB_SUPPORT +kmod-usb-core
+  KCONFIG:=CONFIG_VIDEO_CPIA2
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/cpia2/cpia2.ko
+  AUTOLOAD:=$(call AutoProbe,cpia2)
+  $(call AddDepends/camera)
+endef
+
+define KernelPackage/video-cpia2/description
+ Kernel modules for supporting CPIA2 USB based cameras
+endef
+
+$(eval $(call KernelPackage,video-cpia2))
+
+
+define KernelPackage/video-pwc
+  TITLE:=Philips USB webcam support
+  DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-video-videobuf2
+  KCONFIG:= \
+	CONFIG_USB_PWC \
+	CONFIG_USB_PWC_DEBUG=n
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/pwc/pwc.ko
+  AUTOLOAD:=$(call AutoProbe,pwc)
+  $(call AddDepends/camera)
+endef
+
+define KernelPackage/video-pwc/description
+ Kernel modules for supporting Philips USB based cameras
+endef
+
+$(eval $(call KernelPackage,video-pwc))
+
+
+define KernelPackage/video-uvc
+  TITLE:=USB Video Class (UVC) support
+  DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-video-videobuf2 +kmod-input-core
+  KCONFIG:= CONFIG_USB_VIDEO_CLASS
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/uvc/uvcvideo.ko
+  AUTOLOAD:=$(call AutoProbe,uvcvideo)
+  $(call AddDepends/camera)
+endef
+
+define KernelPackage/video-uvc/description
+ Kernel modules for supporting USB Video Class (UVC) devices
+endef
+
+$(eval $(call KernelPackage,video-uvc))
+
+
+define KernelPackage/video-gspca-core
+  MENU:=1
+  TITLE:=GSPCA webcam core support framework
+  DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-input-core
+  KCONFIG:=CONFIG_USB_GSPCA
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_main.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_main)
+  $(call AddDepends/camera)
+endef
+
+define KernelPackage/video-gspca-core/description
+ Kernel modules for supporting GSPCA based webcam devices. Note this is just
+ the core of the driver, please select a submodule that supports your webcam.
+endef
+
+$(eval $(call KernelPackage,video-gspca-core))
+
+
+define AddDepends/camera-gspca
+  SUBMENU:=$(VIDEO_MENU)
+  DEPENDS+=kmod-video-gspca-core $(1)
+endef
+
+
+define KernelPackage/video-gspca-conex
+  TITLE:=conex webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_CONEX
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_conex.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_conex)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-conex/description
+ The Conexant Camera Driver (conex) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-conex))
+
+
+define KernelPackage/video-gspca-etoms
+  TITLE:=etoms webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_ETOMS
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_etoms.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_etoms)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-etoms/description
+ The Etoms USB Camera Driver (etoms) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-etoms))
+
+
+define KernelPackage/video-gspca-finepix
+  TITLE:=finepix webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_FINEPIX
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_finepix.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_finepix)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-finepix/description
+ The Fujifilm FinePix USB V4L2 driver (finepix) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-finepix))
+
+
+define KernelPackage/video-gspca-mars
+  TITLE:=mars webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_MARS
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_mars.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_mars)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-mars/description
+ The Mars USB Camera Driver (mars) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-mars))
+
+
+define KernelPackage/video-gspca-mr97310a
+  TITLE:=mr97310a webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_MR97310A
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_mr97310a.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_mr97310a)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-mr97310a/description
+ The Mars-Semi MR97310A USB Camera Driver (mr97310a) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-mr97310a))
+
+
+define KernelPackage/video-gspca-ov519
+  TITLE:=ov519 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_OV519
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_ov519.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_ov519)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-ov519/description
+ The OV519 USB Camera Driver (ov519) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-ov519))
+
+
+define KernelPackage/video-gspca-ov534
+  TITLE:=ov534 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_OV534
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_ov534.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_ov534)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-ov534/description
+ The OV534 USB Camera Driver (ov534) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-ov534))
+
+
+define KernelPackage/video-gspca-ov534-9
+  TITLE:=ov534-9 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_OV534_9
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_ov534_9.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_ov534_9)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-ov534-9/description
+ The OV534-9 USB Camera Driver (ov534_9) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-ov534-9))
+
+
+define KernelPackage/video-gspca-pac207
+  TITLE:=pac207 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_PAC207
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_pac207.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_pac207)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-pac207/description
+ The Pixart PAC207 USB Camera Driver (pac207) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-pac207))
+
+
+define KernelPackage/video-gspca-pac7311
+  TITLE:=pac7311 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_PAC7311
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_pac7311.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_pac7311)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-pac7311/description
+ The Pixart PAC7311 USB Camera Driver (pac7311) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-pac7311))
+
+
+define KernelPackage/video-gspca-se401
+  TITLE:=se401 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SE401
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_se401.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_se401)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-se401/description
+ The SE401 USB Camera Driver kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-se401))
+
+
+define KernelPackage/video-gspca-sn9c20x
+  TITLE:=sn9c20x webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SN9C20X
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_sn9c20x.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_sn9c20x)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-sn9c20x/description
+ The SN9C20X USB Camera Driver (sn9c20x) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-sn9c20x))
+
+
+define KernelPackage/video-gspca-sonixb
+  TITLE:=sonixb webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SONIXB
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_sonixb.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_sonixb)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-sonixb/description
+ The SONIX Bayer USB Camera Driver (sonixb) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-sonixb))
+
+
+define KernelPackage/video-gspca-sonixj
+  TITLE:=sonixj webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SONIXJ
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_sonixj.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_sonixj)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-sonixj/description
+ The SONIX JPEG USB Camera Driver (sonixj) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-sonixj))
+
+
+define KernelPackage/video-gspca-spca500
+  TITLE:=spca500 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SPCA500
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_spca500.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_spca500)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-spca500/description
+ The SPCA500 USB Camera Driver (spca500) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-spca500))
+
+
+define KernelPackage/video-gspca-spca501
+  TITLE:=spca501 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SPCA501
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_spca501.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_spca501)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-spca501/description
+ The SPCA501 USB Camera Driver (spca501) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-spca501))
+
+
+define KernelPackage/video-gspca-spca505
+  TITLE:=spca505 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SPCA505
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_spca505.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_spca505)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-spca505/description
+ The SPCA505 USB Camera Driver (spca505) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-spca505))
+
+
+define KernelPackage/video-gspca-spca506
+  TITLE:=spca506 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SPCA506
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_spca506.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_spca506)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-spca506/description
+ The SPCA506 USB Camera Driver (spca506) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-spca506))
+
+
+define KernelPackage/video-gspca-spca508
+  TITLE:=spca508 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SPCA508
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_spca508.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_spca508)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-spca508/description
+ The SPCA508 USB Camera Driver (spca508) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-spca508))
+
+
+define KernelPackage/video-gspca-spca561
+  TITLE:=spca561 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SPCA561
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_spca561.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_spca561)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-spca561/description
+ The SPCA561 USB Camera Driver (spca561) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-spca561))
+
+
+define KernelPackage/video-gspca-sq905
+  TITLE:=sq905 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SQ905
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_sq905.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_sq905)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-sq905/description
+ The SQ Technologies SQ905 based USB Camera Driver (sq905) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-sq905))
+
+
+define KernelPackage/video-gspca-sq905c
+  TITLE:=sq905c webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SQ905C
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_sq905c.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_sq905c)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-sq905c/description
+ The SQ Technologies SQ905C based USB Camera Driver (sq905c) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-sq905c))
+
+
+define KernelPackage/video-gspca-stk014
+  TITLE:=stk014 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_STK014
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_stk014.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_stk014)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-stk014/description
+ The Syntek DV4000 (STK014) USB Camera Driver (stk014) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-stk014))
+
+
+define KernelPackage/video-gspca-sunplus
+  TITLE:=sunplus webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_SUNPLUS
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_sunplus.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_sunplus)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-sunplus/description
+ The SUNPLUS USB Camera Driver (sunplus) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-sunplus))
+
+
+define KernelPackage/video-gspca-t613
+  TITLE:=t613 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_T613
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_t613.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_t613)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-t613/description
+ The T613 (JPEG Compliance) USB Camera Driver (t613) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-t613))
+
+
+define KernelPackage/video-gspca-tv8532
+  TITLE:=tv8532 webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_TV8532
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_tv8532.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_tv8532)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-tv8532/description
+ The TV8532 USB Camera Driver (tv8532) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-tv8532))
+
+
+define KernelPackage/video-gspca-vc032x
+  TITLE:=vc032x webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_VC032X
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_vc032x.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_vc032x)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-vc032x/description
+ The VC032X USB Camera Driver (vc032x) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-vc032x))
+
+
+define KernelPackage/video-gspca-zc3xx
+  TITLE:=zc3xx webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_ZC3XX
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_zc3xx.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_zc3xx)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-zc3xx/description
+ The ZC3XX USB Camera Driver (zc3xx) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-zc3xx))
+
+
+define KernelPackage/video-gspca-m5602
+  TITLE:=m5602 webcam support
+  KCONFIG:=CONFIG_USB_M5602
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/m5602/gspca_m5602.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_m5602)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-m5602/description
+ The ALi USB m5602 Camera Driver (m5602) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-m5602))
+
+
+define KernelPackage/video-gspca-stv06xx
+  TITLE:=stv06xx webcam support
+  KCONFIG:=CONFIG_USB_STV06XX
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/stv06xx/gspca_stv06xx.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_stv06xx)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-stv06xx/description
+ The STV06XX USB Camera Driver (stv06xx) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-stv06xx))
+
+
+define KernelPackage/video-gspca-gl860
+  TITLE:=gl860 webcam support
+  KCONFIG:=CONFIG_USB_GL860
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gl860/gspca_gl860.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_gl860)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-gl800/description
+ The GL860 USB Camera Driver (gl860) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-gl860))
+
+
+define KernelPackage/video-gspca-jeilinj
+  TITLE:=jeilinj webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_JEILINJ
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_jeilinj.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_jeilinj)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-jeilinj/description
+ The JEILINJ USB Camera Driver (jeilinj) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-jeilinj))
+
+
+define KernelPackage/video-gspca-konica
+  TITLE:=konica webcam support
+  KCONFIG:=CONFIG_USB_GSPCA_KONICA
+  FILES:=$(LINUX_DIR)/drivers/media/$(V4L2_USB_DIR)/gspca/gspca_konica.ko
+  AUTOLOAD:=$(call AutoProbe,gspca_konica)
+  $(call AddDepends/camera-gspca)
+endef
+
+define KernelPackage/video-gspca-konica/description
+ The Konica USB Camera Driver (konica) kernel module
+endef
+
+$(eval $(call KernelPackage,video-gspca-konica))
diff --git a/package/kernel/linux/modules/virt.mk b/package/kernel/linux/modules/virt.mk
new file mode 100644
index 0000000000..a9a0b538ff
--- /dev/null
+++ b/package/kernel/linux/modules/virt.mk
@@ -0,0 +1,73 @@
+#
+# Copyright (C) 2016 Yousong Zhou <yszhou4tech@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+define KernelPackage/irqbypass
+  SUBMENU:=Virtualization
+  TITLE:=IRQ offload/bypass manager
+  KCONFIG:=CONFIG_IRQ_BYPASS_MANAGER
+  HIDDEN:=1
+  FILES:= $(LINUX_DIR)/virt/lib/irqbypass.ko
+  AUTOLOAD:=$(call AutoProbe,irqbypass.ko)
+endef
+$(eval $(call KernelPackage,irqbypass))
+
+
+define KernelPackage/kvm-x86
+  SUBMENU:=Virtualization
+  TITLE:=Kernel-based Virtual Machine (KVM) support
+  DEPENDS:=@TARGET_x86_generic||TARGET_x86_64 +kmod-irqbypass
+  KCONFIG:=\
+	  CONFIG_VIRTUALIZATION=y \
+	  CONFIG_KVM
+  FILES:= $(LINUX_DIR)/arch/$(LINUX_KARCH)/kvm/kvm.ko
+  AUTOLOAD:=$(call AutoProbe,kvm.ko)
+endef
+
+define KernelPackage/kvm-x86/description
+  Support hosting fully virtualized guest machines using hardware
+  virtualization extensions.  You will need a fairly recent
+  processor equipped with virtualization extensions. You will also
+  need to select one or more of the processor modules.
+
+  This module provides access to the hardware capabilities through
+  a character device node named /dev/kvm.
+endef
+
+$(eval $(call KernelPackage,kvm-x86))
+
+
+define KernelPackage/kvm-intel
+  SUBMENU:=Virtualization
+  TITLE:=KVM for Intel processors support
+  DEPENDS:=+kmod-kvm-x86
+  KCONFIG:=CONFIG_KVM_INTEL
+  FILES:= $(LINUX_DIR)/arch/$(LINUX_KARCH)/kvm/kvm-intel.ko
+  AUTOLOAD:=$(call AutoProbe,kvm-intel.ko)
+endef
+
+define KernelPackage/kvm-intel/description
+  Provides support for KVM on Intel processors equipped with the VT
+  extensions.
+endef
+
+$(eval $(call KernelPackage,kvm-intel))
+
+
+define KernelPackage/kvm-amd
+  SUBMENU:=Virtualization
+  TITLE:=KVM for AMD processors support
+  DEPENDS:=+kmod-kvm-x86
+  KCONFIG:=CONFIG_KVM_AMD
+  FILES:= $(LINUX_DIR)/arch/$(LINUX_KARCH)/kvm/kvm-amd.ko
+  AUTOLOAD:=$(call AutoProbe,kvm-amd.ko)
+endef
+
+define KernelPackage/kvm-amd/description
+  Provides support for KVM on AMD processors equipped with the AMD-V
+  (SVM) extensions.
+endef
+
+$(eval $(call KernelPackage,kvm-amd))
diff --git a/package/kernel/linux/modules/w1.mk b/package/kernel/linux/modules/w1.mk
new file mode 100644
index 0000000000..196fe675dc
--- /dev/null
+++ b/package/kernel/linux/modules/w1.mk
@@ -0,0 +1,192 @@
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+W1_MENU:=W1 support
+W1_MASTERS_DIR:=$(LINUX_DIR)/drivers/w1/masters
+W1_SLAVES_DIR:=$(LINUX_DIR)/drivers/w1/slaves
+
+define KernelPackage/w1
+  SUBMENU:=$(W1_MENU)
+  TITLE:=Dallas's 1-wire support
+  KCONFIG:=CONFIG_W1
+  FILES:=$(LINUX_DIR)/drivers/w1/wire.ko
+endef
+
+define KernelPackage/w1/description
+ Kernel module for Dallas's 1-wire support
+endef
+
+$(eval $(call KernelPackage,w1))
+
+
+define AddDepends/w1
+  SUBMENU:=$(W1_MENU)
+  DEPENDS+=kmod-w1 $(1)
+endef
+
+
+#
+# 1-wire masters
+#
+define KernelPackage/w1-master-gpio
+  TITLE:=GPIO 1-wire bus master driver
+  DEPENDS:=@GPIO_SUPPORT
+  KCONFIG:=CONFIG_W1_MASTER_GPIO
+  FILES:=$(W1_MASTERS_DIR)/w1-gpio.ko
+  AUTOLOAD:=$(call AutoProbe,w1-gpio)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-master-gpio/description
+ Kernel module for the GPIO 1-wire bus master driver
+endef
+
+$(eval $(call KernelPackage,w1-master-gpio))
+
+define KernelPackage/w1-master-ds2482
+  TITLE:=DS2482 1-wire i2c bus master driver
+  KCONFIG:=CONFIG_W1_MASTER_DS2482
+  FILES:=$(W1_MASTERS_DIR)/ds2482.ko
+  AUTOLOAD:=$(call AutoProbe,ds2482)
+  $(call AddDepends/w1,+kmod-i2c-core)
+endef
+
+define KernelPackage/w1-master-ds2482/description
+ Kernel module for the DS2482 i2c 1-wire bus master driver
+ NOTE: Init with: echo ds2482 0x18 > /sys/bus/i2c/devices/i2c-0/new_device
+ or use owfs
+endef
+
+$(eval $(call KernelPackage,w1-master-ds2482))
+
+
+define KernelPackage/w1-master-ds2490
+  TITLE:=DS2490 1-wire usb bus master driver
+  DEPENDS:=@USB_SUPPORT +kmod-usb-core
+  KCONFIG:=CONFIG_W1_MASTER_DS2490
+  FILES:=$(W1_MASTERS_DIR)/ds2490.ko
+  AUTOLOAD:=$(call AutoProbe,ds2490)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-master-ds2490/description
+ Kernel module for the DS2490 usb 1-wire bus master driver
+endef
+
+$(eval $(call KernelPackage,w1-master-ds2490))
+
+
+define KernelPackage/w1-master-mxc
+  TITLE:=Freescale MXC 1-wire busmaster
+  DEPENDS:=@(TARGET_mxs||TARGET_imx6)
+  KCONFIG:=CONFIG_W1_MASTER_MXC
+  FILES:=$(W1_MASTERS_DIR)/mxc_w1.ko
+  AUTOLOAD:=$(call AutoProbe,mxc_w1)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-master-mxc/description
+ Kernel module for 1-wire Freescale MXC 1-wire busmaster
+endef
+
+$(eval $(call KernelPackage,w1-master-mxc))
+
+
+#
+# 1-wire slaves
+#
+define KernelPackage/w1-slave-therm
+  TITLE:=Thermal family implementation
+  KCONFIG:=CONFIG_W1_SLAVE_THERM
+  FILES:=$(W1_SLAVES_DIR)/w1_therm.ko
+  AUTOLOAD:=$(call AutoProbe,w1_therm)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-slave-therm/description
+ Kernel module for 1-wire thermal sensors
+endef
+
+$(eval $(call KernelPackage,w1-slave-therm))
+
+
+define KernelPackage/w1-slave-smem
+  TITLE:=Simple 64bit memory family implementation
+  KCONFIG:=CONFIG_W1_SLAVE_SMEM
+  FILES:=$(W1_SLAVES_DIR)/w1_smem.ko
+  AUTOLOAD:=$(call AutoProbe,w1_smem)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-slave-smem/description
+ Kernel module for 1-wire simple 64bit memory rom(ds2401/ds2411/ds1990*)
+endef
+
+$(eval $(call KernelPackage,w1-slave-smem))
+
+define KernelPackage/w1-slave-ds2431
+  TITLE:=DS2431 1kb EEPROM driver
+  KCONFIG:= CONFIG_W1_SLAVE_DS2431
+  FILES:=$(W1_SLAVES_DIR)/w1_ds2431.ko
+  AUTOLOAD:=$(call AutoProbe,w1_ds2431)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-slave-ds2431/description
+ Kernel module for 1-wire 1kb EEPROM (DS2431)
+endef
+
+$(eval $(call KernelPackage,w1-slave-ds2431))
+
+define KernelPackage/w1-slave-ds2433
+  TITLE:=DS2433 4kb EEPROM driver
+  KCONFIG:= \
+	CONFIG_W1_SLAVE_DS2433 \
+	CONFIG_W1_SLAVE_DS2433_CRC=n
+  FILES:=$(W1_SLAVES_DIR)/w1_ds2433.ko
+  AUTOLOAD:=$(call AutoProbe,w1_ds2433)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-slave-ds2433/description
+ Kernel module for 1-wire 4kb EEPROM (DS2433)
+endef
+
+$(eval $(call KernelPackage,w1-slave-ds2433))
+
+
+define KernelPackage/w1-slave-ds2760
+  TITLE:=Dallas 2760 battery monitor chip (HP iPAQ & others)
+  KCONFIG:= \
+	CONFIG_W1_SLAVE_DS2760 \
+	CONFIG_W1_SLAVE_DS2433_CRC=n
+  FILES:=$(W1_SLAVES_DIR)/w1_ds2760.ko
+  AUTOLOAD:=$(call AutoProbe,w1_ds2760)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-slave-ds2760/description
+ Kernel module for 1-wire DS2760 battery monitor chip support
+endef
+
+$(eval $(call KernelPackage,w1-slave-ds2760))
+
+
+define KernelPackage/w1-slave-ds2413
+  TITLE:=DS2413 2 Ch. Addressable Switch
+  KCONFIG:= \
+	CONFIG_W1_SLAVE_DS2413
+  FILES:=$(W1_SLAVES_DIR)/w1_ds2413.ko
+  AUTOLOAD:=$(call AutoProbe,w1_ds2413)
+  $(call AddDepends/w1)
+endef
+
+define KernelPackage/w1-slave-ds2413/description
+ Kernel module for 1-wire DS2413 Dual Channel Addressable Switch support
+endef
+
+$(eval $(call KernelPackage,w1-slave-ds2413))
diff --git a/package/kernel/linux/modules/wpan.mk b/package/kernel/linux/modules/wpan.mk
new file mode 100644
index 0000000000..199044fc33
--- /dev/null
+++ b/package/kernel/linux/modules/wpan.mk
@@ -0,0 +1,124 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+WPAN_MENU:=WPAN 802.15.4 Support
+
+define KernelPackage/ieee802154
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:=IEEE-802.15.4 support
+  DEPENDS:=@!LINUX_3_18
+  KCONFIG:= \
+	CONFIG_IEEE802154 \
+	CONFIG_IEEE802154_SOCKET=y \
+	CONFIG_IEEE802154_NL802154_EXPERIMENTAL=n
+  FILES:= \
+	$(LINUX_DIR)/net/ieee802154/ieee802154.ko \
+	$(LINUX_DIR)/net/ieee802154/ieee802154_socket.ko@ge4.0
+  AUTOLOAD:=$(call AutoLoad,90,ieee802154 ieee802154_socket)
+endef
+
+define KernelPackage/ieee802154/description
+  IEEE Std 802.15.4 defines a low data rate, low power and low
+  complexity short range wireless personal area networks. It was
+  designed to organise networks of sensors, switches, etc automation
+  devices. Maximum allowed data rate is 250 kb/s and typical personal
+  operating space around 10m.
+endef
+
+$(eval $(call KernelPackage,ieee802154))
+
+define KernelPackage/mac802154
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:=MAC-802.15.4 support
+  DEPENDS:=+kmod-ieee802154 +kmod-crypto-aead +kmod-lib-crc-ccitt @!LINUX_3_18
+  KCONFIG:= \
+	CONFIG_MAC802154 \
+	CONFIG_IEEE802154_DRIVERS=y
+  FILES:=$(LINUX_DIR)/net/mac802154/mac802154.ko
+  AUTOLOAD:=$(call AutoLoad,91,mac802154)
+endef
+
+define KernelPackage/mac802154/description
+  This option enables the hardware independent IEEE 802.15.4
+  networking stack for SoftMAC devices (the ones implementing
+  only PHY level of IEEE 802.15.4 standard).
+
+  Note: this implementation is neither certified, nor feature
+  complete! Compatibility with other implementations hasn't
+  been tested yet!
+endef
+
+$(eval $(call KernelPackage,mac802154))
+
+define KernelPackage/fakelb
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:=Fake LR-WPAN driver
+  DEPENDS:=+kmod-mac802154 @!LINUX_3_18
+  KCONFIG:=CONFIG_IEEE802154_FAKELB
+  FILES:=$(LINUX_DIR)/drivers/net/ieee802154/fakelb.ko
+  AUTOLOAD:=$(call AutoLoad,92,fakelb)
+endef
+
+define KernelPackage/fakelb/description
+  Say Y here to enable the fake driver that can emulate a net
+  of several interconnected radio devices.
+endef
+
+$(eval $(call KernelPackage,fakelb))
+
+define KernelPackage/at86rf230
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:=AT86RF230 transceiver driver
+  DEPENDS:=+kmod-mac802154 +kmod-regmap
+  KCONFIG:=CONFIG_IEEE802154_AT86RF230 \
+	CONFIG_IEEE802154_AT86RF230_DEBUGFS=n \
+	CONFIG_SPI=y \
+	CONFIG_SPI_MASTER=y
+  FILES:=$(LINUX_DIR)/drivers/net/ieee802154/at86rf230.ko
+endef
+
+$(eval $(call KernelPackage,at86rf230))
+
+define KernelPackage/mrf24j40
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:=MRF24J40 transceiver driver
+  DEPENDS:=+kmod-mac802154 +kmod-regmap
+  KCONFIG:=CONFIG_IEEE802154_MRF24J40 \
+	CONFIG_SPI=y \
+	CONFIG_SPI_MASTER=y
+  FILES:=$(LINUX_DIR)/drivers/net/ieee802154/mrf24j40.ko
+endef
+
+$(eval $(call KernelPackage,mrf24j40))
+
+define KernelPackage/cc2520
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:=CC2520 transceiver driver
+  DEPENDS:=+kmod-mac802154
+  KCONFIG:=CONFIG_IEEE802154_CC2520 \
+	CONFIG_SPI=y \
+	CONFIG_SPI_MASTER=y
+  FILES:=$(LINUX_DIR)/drivers/net/ieee802154/cc2520.ko
+endef
+
+$(eval $(call KernelPackage,cc2520))
+
+define KernelPackage/ieee802154_6lowpan
+  SUBMENU:=$(WPAN_MENU)
+  TITLE:= 6LoWPAN support over IEEE-802.15.4
+  DEPENDS:=@!LINUX_3_18 +kmod-6lowpan +kmod-ieee802154
+  KCONFIG:=CONFIG_IEEE802154_6LOWPAN
+  FILES:= \
+	$(LINUX_DIR)/net/ieee802154/6lowpan/ieee802154_6lowpan.ko@ge4.0 \
+	$(LINUX_DIR)/net/ieee802154/ieee802154_6lowpan.ko@lt4.0
+  AUTOLOAD:=$(call AutoLoad,91,ieee802154_6lowpan)
+endef
+
+define KernelPackage/ieee802154_6lowpan/description
+ IPv6 compression over IEEE 802.15.4
+endef
+
+$(eval $(call KernelPackage,ieee802154_6lowpan))
diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile
new file mode 100644
index 0000000000..7738a097ca
--- /dev/null
+++ b/package/kernel/mac80211/Makefile
@@ -0,0 +1,413 @@
+#
+# Copyright (C) 2007-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=mac80211
+
+PKG_VERSION:=2016-10-08
+PKG_RELEASE:=1
+PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
+PKG_BACKPORT_VERSION:=
+PKG_MD5SUM:=4f6350e3b75815060bfdf47ef266ad613c7bfea5b7b1dc4552dee69e1bebe4fb
+
+PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
+PKG_BUILD_PARALLEL:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_DRIVERS = \
+	ath ath5k ath9k ath9k-common ath9k-htc \
+	lib80211 \
+	mac80211-hwsim \
+
+
+PKG_CONFIG_DEPENDS:= \
+	CONFIG_PACKAGE_kmod-mac80211 \
+	$(patsubst %,CONFIG_PACKAGE_kmod-%,$(PKG_DRIVERS)) \
+	CONFIG_PACKAGE_MAC80211_DEBUGFS \
+	CONFIG_PACKAGE_MAC80211_MESH \
+	CONFIG_PACKAGE_MAC80211_TRACING \
+	CONFIG_PACKAGE_ATH_DEBUG \
+	CONFIG_PACKAGE_ATH_DFS \
+	CONFIG_ATH9K_SUPPORT_PCOEM \
+	CONFIG_ATH9K_TX99 \
+	CONFIG_ATH_USER_REGD \
+
+include $(INCLUDE_DIR)/package.mk
+
+WMENU:=Wireless Drivers
+
+define KernelPackage/mac80211/Default
+  SUBMENU:=$(WMENU)
+  URL:=https://wireless.wiki.kernel.org/
+  MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+endef
+
+define KernelPackage/cfg80211
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=cfg80211 - wireless configuration API
+  DEPENDS+= +iw
+  FILES:= \
+	$(PKG_BUILD_DIR)/compat/compat.ko \
+	$(PKG_BUILD_DIR)/net/wireless/cfg80211.ko
+endef
+
+define KernelPackage/cfg80211/description
+cfg80211 is the Linux wireless LAN (802.11) configuration API.
+endef
+
+define KernelPackage/mac80211
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=Linux 802.11 Wireless Networking Stack
+  DEPENDS+= +kmod-cfg80211 +hostapd-common
+  KCONFIG:=\
+	CONFIG_AVERAGE=y
+  FILES:= $(PKG_BUILD_DIR)/net/mac80211/mac80211.ko
+  MENU:=1
+endef
+
+define KernelPackage/mac80211/config
+  if PACKAGE_kmod-mac80211
+
+	config PACKAGE_MAC80211_DEBUGFS
+		bool "Export mac80211 internals in DebugFS"
+		select KERNEL_DEBUG_FS
+		default y
+		help
+		  Select this to see extensive information about
+		  the internal state of mac80211 in debugfs.
+
+	config PACKAGE_MAC80211_TRACING
+		bool "Enable tracing (mac80211 and supported drivers)"
+		select KERNEL_FTRACE
+		select KERNEL_ENABLE_DEFAULT_TRACERS
+		default n
+		help
+		  Select this to enable tracing of mac80211 and
+		  related wifi drivers (using trace-cmd).
+
+	config PACKAGE_MAC80211_MESH
+		bool "Enable 802.11s mesh support"
+		default y
+
+  endif
+endef
+
+define KernelPackage/mac80211/description
+Generic IEEE 802.11 Networking Stack (mac80211)
+endef
+
+define KernelPackage/ath/config
+  if PACKAGE_kmod-ath
+	config ATH_USER_REGD
+		bool "Force Atheros drivers to respect the user's regdomain settings"
+		default y
+		help
+		  Atheros' idea of regulatory handling is that the EEPROM of the card defines
+		  the regulatory limits and the user is only allowed to restrict the settings
+		  even further, even if the country allows frequencies or power levels that
+		  are forbidden by the EEPROM settings.
+
+		  Select this option if you want the driver to respect the user's decision about
+		  regulatory settings.
+
+	config PACKAGE_ATH_DEBUG
+		bool "Atheros wireless debugging"
+		help
+		  Say Y, if you want to debug atheros wireless drivers.
+		  Only ath9k & ath10k make use of this.
+
+	config PACKAGE_ATH_DFS
+		bool "Enable DFS support"
+		default y
+		help
+		  Dynamic frequency selection (DFS) is required for most of the 5 GHz band
+		  channels in Europe, US, and Japan.
+
+		  Select this option if you want to use such channels.
+
+  endif
+endef
+
+define KernelPackage/ath
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=Atheros common driver part
+  DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ar71xx||TARGET_ath25 +kmod-mac80211
+  FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath.ko
+  MENU:=1
+endef
+
+define KernelPackage/ath/description
+ This module contains some common parts needed by Atheros Wireless drivers.
+endef
+
+define KernelPackage/ath5k
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=Atheros 5xxx wireless cards support
+  URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath5k
+  DEPENDS+= @PCI_SUPPORT||@TARGET_ath25 +kmod-ath
+  FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath5k/ath5k.ko
+  AUTOLOAD:=$(call AutoProbe,ath5k)
+endef
+
+define KernelPackage/ath5k/description
+ This module adds support for wireless adapters based on
+ Atheros 5xxx chipset.
+endef
+
+define KernelPackage/ath9k-common
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=Atheros 802.11n wireless devices (common code for ath9k and ath9k_htc)
+  URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k
+  HIDDEN:=1
+  DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ar71xx +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT +@KERNEL_RELAY
+  FILES:= \
+	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_common.ko \
+	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_hw.ko
+endef
+
+define KernelPackage/ath9k
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=Atheros 802.11n PCI wireless cards support
+  URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k
+  DEPENDS+= @PCI_SUPPORT||TARGET_ar71xx +kmod-ath9k-common
+  FILES:= \
+	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k.ko
+  AUTOLOAD:=$(call AutoProbe,ath9k)
+endef
+
+define KernelPackage/ath9k/description
+This module adds support for wireless adapters based on
+Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
+endef
+
+define KernelPackage/ath9k/config
+
+	config ATH9K_SUPPORT_PCOEM
+		bool "Support chips used in PC OEM cards"
+		depends on PACKAGE_kmod-ath9k
+
+       config ATH9K_TX99
+               bool "Enable TX99 support"
+               depends on PACKAGE_kmod-ath9k
+
+endef
+
+define KernelPackage/ath9k-htc
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=Atheros 802.11n USB device support
+  URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k
+  DEPENDS+= @USB_SUPPORT +kmod-ath9k-common +kmod-usb-core +ath9k-htc-firmware
+  FILES:= \
+	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_htc.ko
+  AUTOLOAD:=$(call AutoProbe,ath9k_htc)
+endef
+
+define KernelPackage/ath9k-htc/description
+This module adds support for wireless adapters based on
+Atheros USB AR9271 and AR7010 family of chipsets.
+endef
+
+define KernelPackage/lib80211
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=802.11 Networking stack
+  DEPENDS:=+kmod-cfg80211 +kmod-crypto-hash
+  FILES:= \
+	$(PKG_BUILD_DIR)/net/wireless/lib80211.ko \
+	$(PKG_BUILD_DIR)/net/wireless/lib80211_crypt_wep.ko \
+	$(PKG_BUILD_DIR)/net/wireless/lib80211_crypt_ccmp.ko \
+	$(PKG_BUILD_DIR)/net/wireless/lib80211_crypt_tkip.ko
+  AUTOLOAD:=$(call AutoProbe, \
+	lib80211 \
+	lib80211_crypt_wep \
+	lib80211_crypt_ccmp \
+	lib80211_crypt_tkip \
+  )
+endef
+
+define KernelPackage/lib80211/description
+ Kernel modules for 802.11 Networking stack
+ Includes:
+ - lib80211
+ - lib80211_crypt_wep
+ - lib80211_crypt_tkip
+ - lib80211_crytp_ccmp
+endef
+
+
+define KernelPackage/mac80211-hwsim
+  $(call KernelPackage/mac80211/Default)
+  TITLE:=mac80211 HW simulation device
+  DEPENDS+= +kmod-mac80211 +@DRIVER_11N_SUPPORT
+  FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/mac80211_hwsim.ko
+  AUTOLOAD:=$(call AutoProbe,mac80211_hwsim)
+endef
+
+
+config_package=$(if $(CONFIG_PACKAGE_kmod-$(1)),m)
+
+config-y:= \
+	WLAN \
+	NL80211_TESTMODE \
+	CFG80211_WEXT \
+	CFG80211_INTERNAL_REGDB \
+	CFG80211_CERTIFICATION_ONUS \
+	MAC80211_RC_MINSTREL \
+	MAC80211_RC_MINSTREL_HT \
+	MAC80211_RC_MINSTREL_VHT \
+	MAC80211_RC_DEFAULT_MINSTREL \
+	WLAN_VENDOR_ATH \
+
+config-$(call config_package,cfg80211) += CFG80211
+
+config-$(call config_package,mac80211) += MAC80211
+config-$(CONFIG_PACKAGE_MAC80211_MESH) += MAC80211_MESH
+ifdef CONFIG_PACKAGE_MAC80211_DEBUGFS
+  config-y += \
+	CFG80211_DEBUGFS \
+	MAC80211_DEBUGFS \
+	ATH9K_DEBUGFS \
+	ATH9K_HTC_DEBUGFS \
+	CARL9170_DEBUGFS \
+	ATH5K_DEBUG
+endif
+
+ifdef CONFIG_PACKAGE_MAC80211_TRACING
+  config-y += \
+	ATH10K_TRACING \
+	ATH6KL_TRACING \
+	ATH_TRACEPOINTS \
+	WIL6210_TRACING \
+	ATH5K_TRACER \
+	IWLWIFI_DEVICE_TRACING
+endif
+
+config-$(call config_package,lib80211) += LIB80211 LIB80211_CRYPT_WEP LIB80211_CRYPT_CCMP LIB80211_CRYPT_TKIP
+
+config-$(call config_package,ath) += ATH_CARDS ATH_COMMON
+config-$(CONFIG_PACKAGE_ATH_DEBUG) += ATH_DEBUG ATH10K_DEBUG ATH9K_STATION_STATISTICS
+config-$(CONFIG_PACKAGE_ATH_DFS) += ATH9K_DFS_CERTIFIED ATH10K_DFS_CERTIFIED
+
+config-$(call config_package,ath9k) += ATH9K
+config-$(call config_package,ath9k-common) += ATH9K_COMMON
+config-$(CONFIG_TARGET_ar71xx) += ATH9K_AHB
+config-$(CONFIG_PCI) += ATH9K_PCI
+config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD
+config-$(CONFIG_ATH9K_SUPPORT_PCOEM) += ATH9K_PCOEM
+config-$(CONFIG_ATH9K_TX99) += ATH9K_TX99
+
+config-$(call config_package,ath9k-htc) += ATH9K_HTC
+config-$(call config_package,ath10k) += ATH10K ATH10K_PCI
+
+config-$(call config_package,ath5k) += ATH5K
+ifdef CONFIG_TARGET_ath25
+  config-y += ATH5K_AHB
+else
+  config-y += ATH5K_PCI
+endif
+
+config-$(call config_package,carl9170) += CARL9170
+
+config-$(call config_package,mac80211-hwsim) += MAC80211_HWSIM
+
+config-$(CONFIG_LEDS_TRIGGERS) += MAC80211_LEDS
+
+MAKE_OPTS:= -C "$(PKG_BUILD_DIR)" \
+	CROSS_COMPILE="$(KERNEL_CROSS)" \
+	ARCH="$(LINUX_KARCH)" \
+	EXTRA_CFLAGS="-I$(PKG_BUILD_DIR)/include $(IREMAP_CFLAGS)" \
+	KLIB_BUILD="$(LINUX_DIR)" \
+	MODPROBE=true \
+	KLIB=$(TARGET_MODULES_DIR) \
+	KERNEL_SUBLEVEL=$(lastword $(subst ., ,$(KERNEL_PATCHVER))) \
+	KBUILD_LDFLAGS_MODULE_PREREQ=
+
+ifneq ($(findstring c,$(OPENWRT_VERBOSE)),)
+  MAKE_OPTS += V=1
+endif
+
+define ConfigVars
+$(subst $(space),,$(foreach opt,$(config-$(1)),CPTCFG_$(opt)=$(1)
+))
+endef
+
+define mac80211_config
+$(call ConfigVars,m)$(call ConfigVars,y)
+endef
+$(eval $(call shexport,mac80211_config))
+
+define Build/Prepare
+	rm -rf $(PKG_BUILD_DIR)
+	mkdir -p $(PKG_BUILD_DIR)
+	$(PKG_UNPACK)
+	$(Build/Patch)
+	rm -rf \
+		$(PKG_BUILD_DIR)/include/linux/ssb \
+		$(PKG_BUILD_DIR)/include/linux/bcma \
+		$(PKG_BUILD_DIR)/include/net/bluetooth
+
+	rm -f \
+		$(PKG_BUILD_DIR)/include/linux/cordic.h \
+		$(PKG_BUILD_DIR)/include/linux/crc8.h \
+		$(PKG_BUILD_DIR)/include/linux/eeprom_93cx6.h \
+		$(PKG_BUILD_DIR)/include/linux/wl12xx.h \
+		$(PKG_BUILD_DIR)/include/linux/spi/libertas_spi.h \
+		$(PKG_BUILD_DIR)/include/net/ieee80211.h \
+		$(PKG_BUILD_DIR)/backport-include/linux/bcm47xx_nvram.h
+
+	echo 'compat-wireless-$(PKG_VERSION)-$(PKG_RELEASE)-$(REVISION)' > $(PKG_BUILD_DIR)/compat_version
+	$(CP) ./files/regdb.txt $(PKG_BUILD_DIR)/net/wireless/db.txt
+endef
+
+ifneq ($(CONFIG_PACKAGE_kmod-cfg80211)$(CONFIG_PACKAGE_kmod-lib80211),)
+ define Build/Compile/kmod
+	rm -rf $(PKG_BUILD_DIR)/modules
+	+$(MAKE) $(PKG_JOBS) $(MAKE_OPTS) modules
+ endef
+endif
+
+define Build/Configure
+	cmp $(PKG_BUILD_DIR)/include/linux/ath9k_platform.h $(LINUX_DIR)/include/linux/ath9k_platform.h
+	cmp $(PKG_BUILD_DIR)/include/linux/ath5k_platform.h $(LINUX_DIR)/include/linux/ath5k_platform.h
+endef
+
+define Build/Compile
+	$(SH_FUNC) var2file "$(call shvar,mac80211_config)" $(PKG_BUILD_DIR)/.config
+	$(MAKE) $(MAKE_OPTS) allnoconfig
+	$(call Build/Compile/kmod)
+endef
+
+define Build/InstallDev
+	mkdir -p \
+		$(1)/usr/include/mac80211 \
+		$(1)/usr/include/mac80211-backport \
+		$(1)/usr/include/mac80211/ath \
+		$(1)/usr/include/net/mac80211
+	$(CP) $(PKG_BUILD_DIR)/net/mac80211/*.h $(PKG_BUILD_DIR)/include/* $(1)/usr/include/mac80211/
+	$(CP) $(PKG_BUILD_DIR)/backport-include/* $(1)/usr/include/mac80211-backport/
+	$(CP) $(PKG_BUILD_DIR)/net/mac80211/rate.h $(1)/usr/include/net/mac80211/
+	$(CP) $(PKG_BUILD_DIR)/drivers/net/wireless/ath/*.h $(1)/usr/include/mac80211/ath/
+	rm -f $(1)/usr/include/mac80211-backport/linux/module.h
+endef
+
+define KernelPackage/cfg80211/install
+	$(INSTALL_DIR) $(1)/lib/wifi $(1)/lib/netifd/wireless
+	$(INSTALL_DATA) ./files/lib/wifi/mac80211.sh $(1)/lib/wifi
+	$(INSTALL_BIN) ./files/lib/netifd/wireless/mac80211.sh $(1)/lib/netifd/wireless
+endef
+
+$(eval $(call KernelPackage,ath))
+$(eval $(call KernelPackage,ath5k))
+$(eval $(call KernelPackage,ath9k))
+$(eval $(call KernelPackage,ath9k-common))
+$(eval $(call KernelPackage,cfg80211))
+$(eval $(call KernelPackage,lib80211))
+$(eval $(call KernelPackage,mac80211))
+$(eval $(call KernelPackage,mac80211-hwsim))
diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
new file mode 100644
index 0000000000..e3d612e4b2
--- /dev/null
+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
@@ -0,0 +1,757 @@
+#!/bin/sh
+. /lib/netifd/netifd-wireless.sh
+. /lib/netifd/hostapd.sh
+
+init_wireless_driver "$@"
+
+MP_CONFIG_INT="mesh_retry_timeout mesh_confirm_timeout mesh_holding_timeout mesh_max_peer_links
+	       mesh_max_retries mesh_ttl mesh_element_ttl mesh_hwmp_max_preq_retries
+	       mesh_path_refresh_time mesh_min_discovery_timeout mesh_hwmp_active_path_timeout
+	       mesh_hwmp_preq_min_interval mesh_hwmp_net_diameter_traversal_time mesh_hwmp_rootmode
+	       mesh_hwmp_rann_interval mesh_gate_announcements mesh_sync_offset_max_neighor
+	       mesh_rssi_threshold mesh_hwmp_active_path_to_root_timeout mesh_hwmp_root_interval
+	       mesh_hwmp_confirmation_interval mesh_awake_window mesh_plink_timeout"
+MP_CONFIG_BOOL="mesh_auto_open_plinks mesh_fwding"
+MP_CONFIG_STRING="mesh_power_mode"
+
+drv_mac80211_init_device_config() {
+	hostapd_common_add_device_config
+
+	config_add_string path phy 'macaddr:macaddr'
+	config_add_string hwmode
+	config_add_int beacon_int chanbw frag rts
+	config_add_int rxantenna txantenna antenna_gain txpower distance
+	config_add_boolean noscan ht_coex
+	config_add_array ht_capab
+	config_add_array channels
+	config_add_boolean \
+		rxldpc \
+		short_gi_80 \
+		short_gi_160 \
+		tx_stbc_2by1 \
+		su_beamformer \
+		su_beamformee \
+		mu_beamformer \
+		mu_beamformee \
+		vht_txop_ps \
+		htc_vht \
+		rx_antenna_pattern \
+		tx_antenna_pattern
+	config_add_int vht_max_a_mpdu_len_exp vht_max_mpdu vht_link_adapt vht160 rx_stbc tx_stbc
+	config_add_boolean \
+		ldpc \
+		greenfield \
+		short_gi_20 \
+		short_gi_40 \
+		max_amsdu \
+		dsss_cck_40
+}
+
+drv_mac80211_init_iface_config() {
+	hostapd_common_add_bss_config
+
+	config_add_string 'macaddr:macaddr' ifname
+
+	config_add_boolean wds powersave
+	config_add_int maxassoc
+	config_add_int max_listen_int
+	config_add_int dtim_period
+	config_add_int start_disabled
+
+	# mesh
+	config_add_string mesh_id
+	config_add_int $MP_CONFIG_INT
+	config_add_boolean $MP_CONFIG_BOOL
+	config_add_string $MP_CONFIG_STRING
+}
+
+mac80211_add_capabilities() {
+	local __var="$1"; shift
+	local __mask="$1"; shift
+	local __out= oifs
+
+	oifs="$IFS"
+	IFS=:
+	for capab in "$@"; do
+		set -- $capab
+
+		[ "$(($4))" -gt 0 ] || continue
+		[ "$(($__mask & $2))" -eq "$((${3:-$2}))" ] || continue
+		__out="$__out[$1]"
+	done
+	IFS="$oifs"
+
+	export -n -- "$__var=$__out"
+}
+
+mac80211_hostapd_setup_base() {
+	local phy="$1"
+
+	json_select config
+
+	[ "$auto_channel" -gt 0 ] && channel=acs_survey
+	[ "$auto_channel" -gt 0 ] && json_get_values channel_list channels
+
+	json_get_vars noscan ht_coex
+	json_get_values ht_capab_list ht_capab
+
+	ieee80211n=1
+	ht_capab=
+	case "$htmode" in
+		VHT20|HT20) ;;
+		HT40*|VHT40|VHT80|VHT160)
+			case "$hwmode" in
+				a)
+					case "$(( ($channel / 4) % 2 ))" in
+						1) ht_capab="[HT40+]";;
+						0) ht_capab="[HT40-]";;
+					esac
+				;;
+				*)
+					case "$htmode" in
+						HT40+) ht_capab="[HT40+]";;
+						HT40-) ht_capab="[HT40-]";;
+						*)
+							if [ "$channel" -lt 7 ]; then
+								ht_capab="[HT40+]"
+							else
+								ht_capab="[HT40-]"
+							fi
+						;;
+					esac
+				;;
+			esac
+			[ "$auto_channel" -gt 0 ] && ht_capab="[HT40+]"
+		;;
+		*) ieee80211n= ;;
+	esac
+
+	[ -n "$ieee80211n" ] && {
+		append base_cfg "ieee80211n=1" "$N"
+
+		set_default ht_coex 0
+		append base_cfg "ht_coex=$ht_coex" "$N"
+
+		json_get_vars \
+			ldpc:1 \
+			greenfield:0 \
+			short_gi_20:1 \
+			short_gi_40:1 \
+			tx_stbc:1 \
+			rx_stbc:3 \
+			max_amsdu:1 \
+			dsss_cck_40:1
+
+		ht_cap_mask=0
+		for cap in $(iw phy "$phy" info | grep 'Capabilities:' | cut -d: -f2); do
+			ht_cap_mask="$(($ht_cap_mask | $cap))"
+		done
+
+		cap_rx_stbc=$((($ht_cap_mask >> 8) & 3))
+		[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
+		ht_cap_mask="$(( ($ht_cap_mask & ~(0x300)) | ($cap_rx_stbc << 8) ))"
+
+		mac80211_add_capabilities ht_capab_flags $ht_cap_mask \
+			LDPC:0x1::$ldpc \
+			GF:0x10::$greenfield \
+			SHORT-GI-20:0x20::$short_gi_20 \
+			SHORT-GI-40:0x40::$short_gi_40 \
+			TX-STBC:0x80::$tx_stbc \
+			RX-STBC1:0x300:0x100:1 \
+			RX-STBC12:0x300:0x200:1 \
+			RX-STBC123:0x300:0x300:1 \
+			MAX-AMSDU-7935:0x800::$max_amsdu \
+			DSSS_CCK-40:0x1000::$dsss_cck_40
+
+		ht_capab="$ht_capab$ht_capab_flags"
+		[ -n "$ht_capab" ] && append base_cfg "ht_capab=$ht_capab" "$N"
+	}
+
+	# 802.11ac
+	enable_ac=0
+	idx="$channel"
+	case "$htmode" in
+		VHT20) enable_ac=1;;
+		VHT40)
+			case "$(( ($channel / 4) % 2 ))" in
+				1) idx=$(($channel + 2));;
+				0) idx=$(($channel - 2));;
+			esac
+			enable_ac=1
+			append base_cfg "vht_oper_chwidth=0" "$N"
+			append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N"
+		;;
+		VHT80)
+			case "$(( ($channel / 4) % 4 ))" in
+				1) idx=$(($channel + 6));;
+				2) idx=$(($channel + 2));;
+				3) idx=$(($channel - 2));;
+				0) idx=$(($channel - 6));;
+			esac
+			enable_ac=1
+			append base_cfg "vht_oper_chwidth=1" "$N"
+			append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N"
+		;;
+		VHT160)
+			case "$channel" in
+				36|40|44|48|52|56|60|64) idx=50;;
+				100|104|108|112|116|120|124|128) idx=114;;
+			esac
+			enable_ac=1
+			append base_cfg "vht_oper_chwidth=2" "$N"
+			append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N"
+		;;
+	esac
+
+	if [ "$enable_ac" != "0" ]; then
+		json_get_vars \
+			rxldpc:1 \
+			short_gi_80:1 \
+			short_gi_160:1 \
+			tx_stbc_2by1:1 \
+			su_beamformer:1 \
+			su_beamformee:1 \
+			mu_beamformer:1 \
+			mu_beamformee:1 \
+			vht_txop_ps:1 \
+			htc_vht:1 \
+			rx_antenna_pattern:1 \
+			tx_antenna_pattern:1 \
+			vht_max_a_mpdu_len_exp:7 \
+			vht_max_mpdu:11454 \
+			rx_stbc:4 \
+			vht_link_adapt:3 \
+			vht160:2
+
+		append base_cfg "ieee80211ac=1" "$N"
+		vht_cap=0
+		for cap in $(iw phy "$phy" info | awk -F "[()]" '/VHT Capabilities/ { print $2 }'); do
+			vht_cap="$(($vht_cap | $cap))"
+		done
+
+		cap_rx_stbc=$((($vht_cap >> 8) & 7))
+		[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
+		vht_cap="$(( ($vht_cap & ~(0x700)) | ($cap_rx_stbc << 8) ))"
+
+		mac80211_add_capabilities vht_capab $vht_cap \
+			RXLDPC:0x10::$rxldpc \
+			SHORT-GI-80:0x20::$short_gi_80 \
+			SHORT-GI-160:0x40::$short_gi_160 \
+			TX-STBC-2BY1:0x80::$tx_stbc_2by1 \
+			SU-BEAMFORMER:0x800::$su_beamformer \
+			SU-BEAMFORMEE:0x1000::$su_beamformee \
+			MU-BEAMFORMER:0x80000::$mu_beamformer \
+			MU-BEAMFORMEE:0x100000::$mu_beamformee \
+			VHT-TXOP-PS:0x200000::$vht_txop_ps \
+			HTC-VHT:0x400000::$htc_vht \
+			RX-ANTENNA-PATTERN:0x10000000::$rx_antenna_pattern \
+			TX-ANTENNA-PATTERN:0x20000000::$tx_antenna_pattern \
+			RX-STBC-1:0x700:0x100:1 \
+			RX-STBC-12:0x700:0x200:1 \
+			RX-STBC-123:0x700:0x300:1 \
+			RX-STBC-1234:0x700:0x400:1 \
+
+		# supported Channel widths
+		vht160_hw=0
+		[ "$(($vht_cap & 12))" -eq 4 -a 1 -le "$vht160" ] && \
+			vht160_hw=1
+		[ "$(($vht_cap & 12))" -eq 8 -a 2 -le "$vht160" ] && \
+			vht160_hw=2
+		[ "$vht160_hw" = 1 ] && vht_capab="$vht_capab[VHT160]"
+		[ "$vht160_hw" = 2 ] && vht_capab="$vht_capab[VHT160-80PLUS80]"
+
+		# maximum MPDU length
+		vht_max_mpdu_hw=3895
+		[ "$(($vht_cap & 3))" -ge 1 -a 7991 -le "$vht_max_mpdu" ] && \
+			vht_max_mpdu_hw=7991
+		[ "$(($vht_cap & 3))" -ge 2 -a 11454 -le "$vht_max_mpdu" ] && \
+			vht_max_mpdu_hw=11454
+		[ "$vht_max_mpdu_hw" != 3895 ] && \
+			vht_capab="$vht_capab[MAX-MPDU-$vht_max_mpdu_hw]"
+			
+		# maximum A-MPDU length exponent
+		vht_max_a_mpdu_len_exp_hw=0
+		[ "$(($vht_cap & 58720256))" -ge 8388608 -a 1 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=1
+		[ "$(($vht_cap & 58720256))" -ge 16777216 -a 2 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=2
+		[ "$(($vht_cap & 58720256))" -ge 25165824 -a 3 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=3
+		[ "$(($vht_cap & 58720256))" -ge 33554432 -a 4 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=4
+		[ "$(($vht_cap & 58720256))" -ge 41943040 -a 5 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=5
+		[ "$(($vht_cap & 58720256))" -ge 50331648 -a 6 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=6
+		[ "$(($vht_cap & 58720256))" -ge 58720256 -a 7 -le "$vht_max_a_mpdu_len_exp" ] && \
+			vht_max_a_mpdu_len_exp_hw=7
+		vht_capab="$vht_capab[MAX-A-MPDU-LEN-EXP$vht_max_a_mpdu_len_exp_hw]"
+
+		# whether or not the STA supports link adaptation using VHT variant
+		vht_link_adapt_hw=0
+		[ "$(($vht_cap & 201326592))" -ge 134217728 -a 2 -le "$vht_link_adapt" ] && \
+			vht_link_adapt_hw=2
+		[ "$(($vht_cap & 201326592))" -ge 201326592 -a 3 -le "$vht_link_adapt" ] && \
+			vht_link_adapt_hw=3
+		[ "$vht_link_adapt_hw" != 0 ] && \
+			vht_capab="$vht_capab[VHT-LINK-ADAPT-$vht_link_adapt_hw]"
+
+		[ -n "$vht_capab" ] && append base_cfg "vht_capab=$vht_capab" "$N"
+	fi
+
+	hostapd_prepare_device_config "$hostapd_conf_file" nl80211
+	cat >> "$hostapd_conf_file" <<EOF
+${channel:+channel=$channel}
+${channel_list:+chanlist=$channel_list}
+${noscan:+noscan=$noscan}
+$base_cfg
+
+EOF
+	json_select ..
+}
+
+mac80211_hostapd_setup_bss() {
+	local phy="$1"
+	local ifname="$2"
+	local macaddr="$3"
+	local type="$4"
+
+	hostapd_cfg=
+	append hostapd_cfg "$type=$ifname" "$N"
+
+	hostapd_set_bss_options hostapd_cfg "$vif" || return 1
+	json_get_vars wds dtim_period max_listen_int start_disabled
+
+	set_default wds 0
+	set_default start_disabled 0
+
+	[ "$wds" -gt 0 ] && append hostapd_cfg "wds_sta=1" "$N"
+	[ "$staidx" -gt 0 -o "$start_disabled" -eq 1 ] && append hostapd_cfg "start_disabled=1" "$N"
+
+	cat >> /var/run/hostapd-$phy.conf <<EOF
+$hostapd_cfg
+bssid=$macaddr
+${dtim_period:+dtim_period=$dtim_period}
+${max_listen_int:+max_listen_interval=$max_listen_int}
+EOF
+}
+
+mac80211_get_addr() {
+	local phy="$1"
+	local idx="$(($2 + 1))"
+
+	head -n $(($macidx + 1)) /sys/class/ieee80211/${phy}/addresses | tail -n1
+}
+
+mac80211_generate_mac() {
+	local phy="$1"
+	local id="${macidx:-0}"
+
+	local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)"
+	local mask="$(cat /sys/class/ieee80211/${phy}/address_mask)"
+
+	[ "$mask" = "00:00:00:00:00:00" ] && {
+		mask="ff:ff:ff:ff:ff:ff";
+
+		[ "$(wc -l < /sys/class/ieee80211/${phy}/addresses)" -gt 1 ] && {
+			addr="$(mac80211_get_addr "$phy" "$id")"
+			[ -n "$addr" ] && {
+				echo "$addr"
+				return
+			}
+		}
+	}
+
+	local oIFS="$IFS"; IFS=":"; set -- $mask; IFS="$oIFS"
+
+	local mask1=$1
+	local mask6=$6
+
+	local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
+
+	macidx=$(($id + 1))
+	[ "$((0x$mask1))" -gt 0 ] && {
+		b1="0x$1"
+		[ "$id" -gt 0 ] && \
+			b1=$(($b1 ^ ((($id - 1) << 2) | 0x2)))
+		printf "%02x:%s:%s:%s:%s:%s" $b1 $2 $3 $4 $5 $6
+		return
+	}
+
+	[ "$((0x$mask6))" -lt 255 ] && {
+		printf "%s:%s:%s:%s:%s:%02x" $1 $2 $3 $4 $5 $(( 0x$6 ^ $id ))
+		return
+	}
+
+	off2=$(( (0x$6 + $id) / 0x100 ))
+	printf "%s:%s:%s:%s:%02x:%02x" \
+		$1 $2 $3 $4 \
+		$(( (0x$5 + $off2) % 0x100 )) \
+		$(( (0x$6 + $id) % 0x100 ))
+}
+
+find_phy() {
+	[ -n "$phy" -a -d /sys/class/ieee80211/$phy ] && return 0
+	[ -n "$path" ] && {
+		for phy in $(ls /sys/class/ieee80211 2>/dev/null); do
+			case "$(readlink -f /sys/class/ieee80211/$phy/device)" in
+				*$path) return 0;;
+			esac
+		done
+	}
+	[ -n "$macaddr" ] && {
+		for phy in $(ls /sys/class/ieee80211 2>/dev/null); do
+			grep -i -q "$macaddr" "/sys/class/ieee80211/${phy}/macaddress" && return 0
+		done
+	}
+	return 1
+}
+
+mac80211_check_ap() {
+	has_ap=1
+}
+
+mac80211_prepare_vif() {
+	json_select config
+
+	json_get_vars ifname mode ssid wds powersave macaddr
+
+	[ -n "$ifname" ] || ifname="wlan${phy#phy}${if_idx:+-$if_idx}"
+	if_idx=$((${if_idx:-0} + 1))
+
+	set_default wds 0
+	set_default powersave 0
+
+	json_select ..
+
+	[ -n "$macaddr" ] || {
+		macaddr="$(mac80211_generate_mac $phy)"
+		macidx="$(($macidx + 1))"
+	}
+
+	json_add_object data
+	json_add_string ifname "$ifname"
+	json_close_object
+	json_select config
+
+	# It is far easier to delete and create the desired interface
+	case "$mode" in
+		adhoc)
+			iw phy "$phy" interface add "$ifname" type adhoc
+		;;
+		ap)
+			# Hostapd will handle recreating the interface and
+			# subsequent virtual APs belonging to the same PHY
+			if [ -n "$hostapd_ctrl" ]; then
+				type=bss
+			else
+				type=interface
+			fi
+
+			mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
+
+			[ -n "$hostapd_ctrl" ] || {
+				iw phy "$phy" interface add "$ifname" type __ap
+				hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
+			}
+		;;
+		mesh)
+			iw phy "$phy" interface add "$ifname" type mp
+		;;
+		monitor)
+			iw phy "$phy" interface add "$ifname" type monitor
+		;;
+		sta)
+			local wdsflag=
+			staidx="$(($staidx + 1))"
+			[ "$wds" -gt 0 ] && wdsflag="4addr on"
+			iw phy "$phy" interface add "$ifname" type managed $wdsflag
+			[ "$powersave" -gt 0 ] && powersave="on" || powersave="off"
+			iw "$ifname" set power_save "$powersave"
+		;;
+	esac
+
+	case "$mode" in
+		monitor|mesh)
+			[ "$auto_channel" -gt 0 ] || iw dev "$ifname" set channel "$channel" $htmode
+		;;
+	esac
+
+	if [ "$mode" != "ap" ]; then
+		# ALL ap functionality will be passed to hostapd
+		# All interfaces must have unique mac addresses
+		# which can either be explicitly set in the device
+		# section, or automatically generated
+		ip link set dev "$ifname" address "$macaddr"
+	fi
+
+	json_select ..
+}
+
+mac80211_setup_supplicant() {
+	wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1
+	wpa_supplicant_add_network "$ifname"
+	wpa_supplicant_run "$ifname" ${hostapd_ctrl:+-H $hostapd_ctrl}
+}
+
+mac80211_setup_adhoc_htmode() {
+	case "$htmode" in
+		VHT20|HT20) ibss_htmode=HT20;;
+		HT40*|VHT40|VHT160)
+			case "$hwmode" in
+				a)
+					case "$(( ($channel / 4) % 2 ))" in
+						1) ibss_htmode="HT40+" ;;
+						0) ibss_htmode="HT40-";;
+					esac
+				;;
+				*)
+					case "$htmode" in
+						HT40+) ibss_htmode="HT40+";;
+						HT40-) ibss_htmode="HT40-";;
+						*)
+							if [ "$channel" -lt 7 ]; then
+								ibss_htmode="HT40+"
+							else
+								ibss_htmode="HT40-"
+							fi
+						;;
+					esac
+				;;
+			esac
+			[ "$auto_channel" -gt 0 ] && ibss_htmode="HT40+"
+		;;
+		VHT80)
+			ibss_htmode="80MHZ"
+		;;
+		NONE|NOHT)
+			ibss_htmode="NOHT"
+		;;
+		*) ibss_htmode="" ;;
+	esac
+
+}
+
+mac80211_setup_adhoc() {
+	json_get_vars bssid ssid key mcast_rate
+
+	keyspec=
+	[ "$auth_type" = "wep" ] && {
+		set_default key 1
+		case "$key" in
+			[1234])
+				local idx
+				for idx in 1 2 3 4; do
+					json_get_var ikey "key$idx"
+
+					[ -n "$ikey" ] && {
+						ikey="$(($idx - 1)):$(prepare_key_wep "$ikey")"
+						[ $idx -eq $key ] && ikey="d:$ikey"
+						append keyspec "$ikey"
+					}
+				done
+			;;
+			*)
+				append keyspec "d:0:$(prepare_key_wep "$key")"
+			;;
+		esac
+	}
+
+	brstr=
+	for br in $basic_rate_list; do
+		wpa_supplicant_add_rate brstr "$br"
+	done
+
+	mcval=
+	[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
+
+	iw dev "$ifname" ibss join "$ssid" $freq $ibss_htmode fixed-freq $bssid \
+		${beacon_int:+beacon-interval $beacon_int} \
+		${brstr:+basic-rates $brstr} \
+		${mcval:+mcast-rate $mcval} \
+		${keyspec:+keys $keyspec}
+}
+
+mac80211_setup_vif() {
+	local name="$1"
+	local failed
+
+	json_select data
+	json_get_vars ifname
+	json_select ..
+
+	json_select config
+	json_get_vars mode
+	json_get_var vif_txpower txpower
+
+	ip link set dev "$ifname" up || {
+		wireless_setup_vif_failed IFUP_ERROR
+		json_select ..
+		return
+	}
+
+	set_default vif_txpower "$txpower"
+	[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00"
+
+	case "$mode" in
+		mesh)
+			# authsae or wpa_supplicant
+			json_get_vars key
+			if [ -n "$key" ]; then
+				if [ -e "/lib/wifi/authsae.sh" ]; then
+					. /lib/wifi/authsae.sh
+					authsae_start_interface || failed=1
+				else
+					wireless_vif_parse_encryption
+					mac80211_setup_supplicant || failed=1
+				fi
+			else
+				json_get_vars mesh_id mcast_rate
+
+				mcval=
+				[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
+
+				iw dev "$ifname" mesh join "$mesh_id" ${mcval:+mcast-rate $mcval}
+			fi
+
+			for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do
+				json_get_var mp_val "$var"
+				[ -n "$mp_val" ] && iw dev "$ifname" set mesh_param "$var" "$mp_val"
+			done
+		;;
+		adhoc)
+			wireless_vif_parse_encryption
+			mac80211_setup_adhoc_htmode
+			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then
+				mac80211_setup_supplicant || failed=1
+			else
+				mac80211_setup_adhoc
+			fi
+		;;
+		sta)
+			mac80211_setup_supplicant || failed=1
+		;;
+	esac
+
+	json_select ..
+	[ -n "$failed" ] || wireless_add_vif "$name" "$ifname"
+}
+
+get_freq() {
+	local phy="$1"
+	local chan="$2"
+	iw "$phy" info | grep -E -m1 "(\* ${chan:-....} MHz${chan:+|\\[$chan\\]})" | grep MHz | awk '{print $2}'
+}
+
+mac80211_interface_cleanup() {
+	local phy="$1"
+
+	for wdev in $(list_phy_interfaces "$phy"); do
+		ip link set dev "$wdev" down 2>/dev/null
+		iw dev "$wdev" del
+	done
+}
+
+drv_mac80211_cleanup() {
+	hostapd_common_cleanup
+}
+
+drv_mac80211_setup() {
+	json_select config
+	json_get_vars \
+		phy macaddr path \
+		country chanbw distance \
+		txpower antenna_gain \
+		rxantenna txantenna \
+		frag rts beacon_int htmode
+	json_get_values basic_rate_list basic_rate
+	json_select ..
+
+	find_phy || {
+		echo "Could not find PHY for device '$1'"
+		wireless_set_retry 0
+		return 1
+	}
+
+	wireless_set_data phy="$phy"
+	mac80211_interface_cleanup "$phy"
+
+	# convert channel to frequency
+	[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")"
+
+	[ -n "$country" ] && {
+		iw reg get | grep -q "^country $country:" || {
+			iw reg set "$country"
+			sleep 1
+		}
+	}
+
+	hostapd_conf_file="/var/run/hostapd-$phy.conf"
+
+	no_ap=1
+	macidx=0
+	staidx=0
+
+	[ -n "$chanbw" ] && {
+		for file in /sys/kernel/debug/ieee80211/$phy/ath9k/chanbw /sys/kernel/debug/ieee80211/$phy/ath5k/bwmode; do
+			[ -f "$file" ] && echo "$chanbw" > "$file"
+		done
+	}
+
+	set_default rxantenna all
+	set_default txantenna all
+	set_default distance 0
+	set_default antenna_gain 0
+
+	iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1
+	iw phy "$phy" set antenna_gain $antenna_gain
+	iw phy "$phy" set distance "$distance"
+
+	[ -n "$frag" ] && iw phy "$phy" set frag "${frag%%.*}"
+	[ -n "$rts" ] && iw phy "$phy" set rts "${rts%%.*}"
+
+	has_ap=
+	hostapd_ctrl=
+	for_each_interface "ap" mac80211_check_ap
+
+	rm -f "$hostapd_conf_file"
+	[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy"
+
+	for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
+	for_each_interface "ap" mac80211_prepare_vif
+
+	[ -n "$hostapd_ctrl" ] && {
+		/usr/sbin/hostapd -P /var/run/wifi-$phy.pid -B "$hostapd_conf_file"
+		ret="$?"
+		wireless_add_process "$(cat /var/run/wifi-$phy.pid)" "/usr/sbin/hostapd" 1
+		[ "$ret" != 0 ] && {
+			wireless_setup_failed HOSTAPD_START_FAILED
+			return
+		}
+	}
+
+	for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif
+
+	wireless_set_up
+}
+
+list_phy_interfaces() {
+	local phy="$1"
+	if [ -d "/sys/class/ieee80211/${phy}/device/net" ]; then
+		ls "/sys/class/ieee80211/${phy}/device/net" 2>/dev/null;
+	else
+		ls "/sys/class/ieee80211/${phy}/device" 2>/dev/null | grep net: | sed -e 's,net:,,g'
+	fi
+}
+
+drv_mac80211_teardown() {
+	wireless_process_kill_all
+
+	json_select data
+	json_get_vars phy
+	json_select ..
+
+	mac80211_interface_cleanup "$phy"
+}
+
+add_driver mac80211
diff --git a/package/kernel/mac80211/files/lib/wifi/mac80211.sh b/package/kernel/mac80211/files/lib/wifi/mac80211.sh
new file mode 100644
index 0000000000..4bfc7424b2
--- /dev/null
+++ b/package/kernel/mac80211/files/lib/wifi/mac80211.sh
@@ -0,0 +1,132 @@
+#!/bin/sh
+append DRIVERS "mac80211"
+
+lookup_phy() {
+	[ -n "$phy" ] && {
+		[ -d /sys/class/ieee80211/$phy ] && return
+	}
+
+	local devpath
+	config_get devpath "$device" path
+	[ -n "$devpath" ] && {
+		for phy in $(ls /sys/class/ieee80211 2>/dev/null); do
+			case "$(readlink -f /sys/class/ieee80211/$phy/device)" in
+				*$devpath) return;;
+			esac
+		done
+	}
+
+	local macaddr="$(config_get "$device" macaddr | tr 'A-Z' 'a-z')"
+	[ -n "$macaddr" ] && {
+		for _phy in /sys/class/ieee80211/*; do
+			[ -e "$_phy" ] || continue
+
+			[ "$macaddr" = "$(cat ${_phy}/macaddress)" ] || continue
+			phy="${_phy##*/}"
+			return
+		done
+	}
+	phy=
+	return
+}
+
+find_mac80211_phy() {
+	local device="$1"
+
+	config_get phy "$device" phy
+	lookup_phy
+	[ -n "$phy" -a -d "/sys/class/ieee80211/$phy" ] || {
+		echo "PHY for wifi device $1 not found"
+		return 1
+	}
+	config_set "$device" phy "$phy"
+
+	config_get macaddr "$device" macaddr
+	[ -z "$macaddr" ] && {
+		config_set "$device" macaddr "$(cat /sys/class/ieee80211/${phy}/macaddress)"
+	}
+
+	return 0
+}
+
+check_mac80211_device() {
+	config_get phy "$1" phy
+	[ -z "$phy" ] && {
+		find_mac80211_phy "$1" >/dev/null || return 0
+		config_get phy "$1" phy
+	}
+	[ "$phy" = "$dev" ] && found=1
+}
+
+detect_mac80211() {
+	devidx=0
+	config_load wireless
+	while :; do
+		config_get type "radio$devidx" type
+		[ -n "$type" ] || break
+		devidx=$(($devidx + 1))
+	done
+
+	for _dev in /sys/class/ieee80211/*; do
+		[ -e "$_dev" ] || continue
+
+		dev="${_dev##*/}"
+
+		found=0
+		config_foreach check_mac80211_device wifi-device
+		[ "$found" -gt 0 ] && continue
+
+		mode_band="g"
+		channel="11"
+		htmode=""
+		ht_capab=""
+
+		iw phy "$dev" info | grep -q 'Capabilities:' && htmode=HT20
+		iw phy "$dev" info | grep -q '2412 MHz' || { mode_band="a"; channel="36"; }
+
+		vht_cap=$(iw phy "$dev" info | grep -c 'VHT Capabilities')
+		cap_5ghz=$(iw phy "$dev" info | grep -c "Band 2")
+		[ "$vht_cap" -gt 0 -a "$cap_5ghz" -gt 0 ] && {
+			mode_band="a";
+			channel="36"
+			htmode="VHT80"
+		}
+
+		[ -n $htmode ] && ht_capab="set wireless.radio${devidx}.htmode=$htmode"
+
+		if [ -x /usr/bin/readlink -a -h /sys/class/ieee80211/${dev} ]; then
+			path="$(readlink -f /sys/class/ieee80211/${dev}/device)"
+		else
+			path=""
+		fi
+		if [ -n "$path" ]; then
+			path="${path##/sys/devices/}"
+			case "$path" in
+				platform*/pci*) path="${path##platform/}";;
+			esac
+			dev_id="set wireless.radio${devidx}.path='$path'"
+		else
+			dev_id="set wireless.radio${devidx}.macaddr=$(cat /sys/class/ieee80211/${dev}/macaddress)"
+		fi
+
+		uci -q batch <<-EOF
+			set wireless.radio${devidx}=wifi-device
+			set wireless.radio${devidx}.type=mac80211
+			set wireless.radio${devidx}.channel=${channel}
+			set wireless.radio${devidx}.hwmode=11${mode_band}
+			${dev_id}
+			${ht_capab}
+			set wireless.radio${devidx}.disabled=1
+
+			set wireless.default_radio${devidx}=wifi-iface
+			set wireless.default_radio${devidx}.device=radio${devidx}
+			set wireless.default_radio${devidx}.network=lan
+			set wireless.default_radio${devidx}.mode=ap
+			set wireless.default_radio${devidx}.ssid=LEDE
+			set wireless.default_radio${devidx}.encryption=none
+EOF
+		uci -q commit wireless
+
+		devidx=$(($devidx + 1))
+	done
+}
diff --git a/package/kernel/mac80211/files/mac80211.hotplug b/package/kernel/mac80211/files/mac80211.hotplug
new file mode 100644
index 0000000000..b865552661
--- /dev/null
+++ b/package/kernel/mac80211/files/mac80211.hotplug
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "${ACTION}" = "add" ] && {
+	/sbin/wifi config
+}
diff --git a/package/kernel/mac80211/files/regdb.txt b/package/kernel/mac80211/files/regdb.txt
new file mode 100644
index 0000000000..c4a9b2d15f
--- /dev/null
+++ b/package/kernel/mac80211/files/regdb.txt
@@ -0,0 +1,1307 @@
+# This is the world regulatory domain
+country 00:
+	(2402 - 2472 @ 40), (20)
+	# Channel 12 - 13.
+	(2457 - 2482 @ 20), (20), NO-IR, AUTO-BW
+	# Channel 14. Only JP enables this and for 802.11b only
+	(2474 - 2494 @ 20), (20), NO-IR, NO-OFDM
+	# Channel 36 - 48
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	# Channel 52 - 64
+	(5250 - 5330 @ 80), (20), NO-IR, DFS, AUTO-BW
+	# Channel 100 - 144
+	(5490 - 5730 @ 160), (20), NO-IR, DFS
+	# Channel 149 - 165
+	(5735 - 5835 @ 80), (20), NO-IR
+	# IEEE 802.11ad (60GHz), channels 1..3
+	(57240 - 63720 @ 2160), (0)
+
+
+country AD:
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20)
+	(5250 - 5330 @ 80), (20), DFS
+	(5490 - 5710 @ 80), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country AE: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country AF: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+# Source:
+# http://pucanguilla.org/Downloads/January2005-Anguilla%20Table%20of%20Allocations.pdf
+country AI: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country AL: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20.00), AUTO-BW
+	(5250 - 5330 @ 80), (20.00), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27.00), DFS
+
+country AM: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 20), (18)
+	(5250 - 5330 @ 20), (18), DFS
+
+country AN: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country AR: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country AS: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country AT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country AU: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country AW: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country AZ: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (18), AUTO-BW
+	(5250 - 5330 @ 80), (18), DFS, AUTO-BW
+
+country BA: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country BB: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+country BD: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5735 - 5835 @ 80), (30)
+
+country BE: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country BF: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Bulgarian rules as defined by the Communications Regulation Commission in the
+# following documents:
+#
+# Rules for carrying out electronic communications through radio equipment using
+# radio spectrum, which does not need to be individually assigned (the Rules):
+# http://www.crc.bg/files/_bg/Pravila_09_06_2015.pdf
+#
+# List of radio equipment that uses harmonized within the European Union bands
+# and electronic communications terminal equipment (the List):
+# http://www.crc.bg/files/_bg/Spisak_2015.pdf
+#
+# Note: The transmit power limits in the 5250-5350 MHz and 5470-5725 MHz bands
+# can be raised by 3 dBm if TPC is enabled. Refer to BDS EN 301 893 for details.
+country BG: DFS-ETSI
+	# Wideband data transmission systems (WDTS) in the 2.4GHz ISM band, ref:
+	# I.22 of the List, BDS EN 300 328
+	(2402 - 2482 @ 40), (20)
+	# 5 GHz Radio Local Area Networks (RLANs), ref:
+	# II.H01 of the List, BDS EN 301 893
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	# II.H01 of the List, I.54 from the List, BDS EN 301 893
+	(5490 - 5710 @ 160), (27), DFS
+	# Short range devices (SRDs) in the 5725-5875 MHz frequency range, ref:
+	# I.43 of the List, BDS EN 300 440-2, BDS EN 300 440-1
+	(5725 - 5875 @ 80), (14)
+	# 60 GHz Multiple-Gigabit RLAN Systems, ref:
+	# II.H03 of the List, BDS EN 302 567-2
+	(57000 - 66000 @ 2160), (40), NO-OUTDOOR
+
+country BH: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 20), (20)
+	(5250 - 5330 @ 20), (20), DFS
+	(5735 - 5835 @ 20), (20)
+
+country BL: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country BM: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country BN: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (20)
+
+country BO: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5250 - 5330 @ 80), (30), DFS
+	(5735 - 5835 @ 80), (30)
+
+country BR: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country BS: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# http://www.bicma.gov.bt/paper/publication/nrrpart4.pdf
+country BT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country BY: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country BZ: DFS-JP
+	(2402 - 2482 @ 40), (30)
+	(5735 - 5835 @ 80), (30)
+
+country CA: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5600 @ 80), (24), DFS
+	(5650 - 5730 @ 80), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# http://www.art-rca.org
+country CF: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 40), (17)
+	(5250 - 5330 @ 40), (24), DFS
+	(5490 - 5730 @ 40), (24), DFS
+	(5735 - 5835 @ 40), (30)
+
+country CH: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country CI: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country CL: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (20)
+
+country CN: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+	# 60 GHz band channels 1,4: 28dBm, channels 2,3: 44dBm
+	# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
+	(57240 - 59400 @ 2160), (28)
+	(59400 - 63720 @ 2160), (44)
+	(63720 - 65880 @ 2160), (28)
+
+country CO: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country CR: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 20), (17)
+	(5250 - 5330 @ 20), (24), DFS
+	(5490 - 5730 @ 20), (24), DFS
+	(5735 - 5835 @ 20), (30)
+
+# http://www.mincom.gob.cu/?q=marcoregulatorio
+# - Redes Informáticas
+# Resolución 127, 2011 - Reglamento Banda 2,4 GHz.
+country CU: DFS-FCC
+	(2400 - 2483.5 @ 40), (200 mW)
+
+country CX: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country CY: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf
+# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf
+# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is
+# implemented.
+country CZ: DFS-ETSI
+	(2400 - 2483.5 @ 40), (100 mW)
+	(5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (100 mW), NO-OUTDOOR, DFS, AUTO-BW
+	(5470 - 5725 @ 160), (500 mW), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+# Allocation for the 2.4 GHz band (Vfg 10 / 2013, Allgemeinzuteilung von
+# Frequenzen für die Nutzung in lokalen Netzwerken; Wireless Local Area
+# Networks (WLAN-Funkanwendungen).
+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2013_10_WLAN_2,4GHz_pdf.pdf
+#
+# Allocation for the 5 GHz band (Vfg. 7 / 2010, Allgemeinzuteilung von
+# Frequenzen in den Bereichen 5150 MHz - 5350 MHz und 5470 MHz - 5725 MHz für
+# Funkanwendungen zur breitbandigen Datenübertragung, WAS/WLAN („Wireless
+# Access Systems including Wireless Local Area Networks“).
+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2010_07_WLAN_5GHz_pdf.pdf
+# The values for the 5 GHz have been reduced by a factor of 2 (3db) for non TPC
+# devices (in other words: devices with TPC can use twice the tx power of this
+# table). Note that the docs do not require TPC for 5150--5250; the reduction
+# to 100mW thus is not strictly required -- however the conservative 100mW
+# limit is used here as the non-interference with radar and satellite
+# apps relies on the attenuation by the building walls only in the
+# absence of DFS; the neighbour countries have 100mW limit here as well.
+#
+# The ETSI EN 300 440-1 standard for short range devices in the 5 GHz band has
+# been implemented in Germany:
+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2014_69_SRD_pdf.pdf
+#
+# Allocation for the 60 GHz band (Allgemeinzuteilung von Frequenzen im
+# Bereich 57 GHz - 66 GHz für Funkanwendungen für weitbandige
+# Datenübertragungssysteme; „Multiple Gigabit WAS/RLAN Systems (MGWS)“).
+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2011_08_MGWS_pdf.pdf
+
+country DE: DFS-ETSI
+	(2400 - 2483.5 @ 40), (100 mW)
+	(5150 - 5250 @ 80), (100 mW), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (100 mW), NO-OUTDOOR, DFS, AUTO-BW
+	(5470 - 5725 @ 160), (500 mW), DFS
+	# short range devices (ETSI EN 300 440-1)
+	(5725 - 5875 @ 80), (25 mW)
+	# 60 GHz band channels 1-4 (ETSI EN 302 567)
+	(57000 - 66000 @ 2160), (40)
+
+country DK: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+# Source:
+# http://www.ntrcdom.org/index.php?option=com_content&view=category&layout=blog&id=10&Itemid=55
+country DM: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+country DO: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+country DZ: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170.000 - 5250.000 @ 80.000), (23.00), AUTO-BW
+	(5250.000 - 5330.000 @ 80.000), (23.00), DFS, AUTO-BW
+	(5490.000 - 5670.000 @ 160.000), (23.00), DFS
+
+country EC: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 20), (17)
+	(5250 - 5330 @ 20), (24), DFS
+	(5490 - 5730 @ 20), (24), DFS
+	(5735 - 5835 @ 20), (30)
+
+country EE: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country EG: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 40), (20)
+	(5250 - 5330 @ 40), (20), DFS
+
+# Orden IET/787/2013, de 25 de abril, por la que se aprueba
+# el cuadro nacional de atribución de frecuencias.
+# http://www.boe.es/diario_boe/txt.php?id=BOE-A-2013-4845
+#
+# more info at "Cuadro nacional de atribución de frecuencias (CNAF)":
+# http://www.minetur.gob.es/telecomunicaciones/espectro/paginas/cnaf.aspx
+
+country ES: DFS-ETSI
+	(2400 - 2483.5 @ 40), (100 mW)
+	(5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (100 mW), NO-OUTDOOR, DFS, AUTO-BW
+	(5470 - 5725 @ 160), (500 mW), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country ET: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country FI: DFS-ETSI
+	(2400 - 2483.5 @ 40), (20)
+	(5150 - 5250 @ 80), (23), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (20), NO-OUTDOOR, DFS, AUTO-BW
+	(5470 - 5725 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country FM: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country FR: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country GB: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country GD: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country GE: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (18), AUTO-BW
+	(5250 - 5330 @ 80), (18), DFS, AUTO-BW
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country GF: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country GH: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country GL: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country GP: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country GR: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country GT: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+country GU: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 20), (17)
+	(5250 - 5330 @ 20), (24), DFS
+	(5490 - 5730 @ 20), (24), DFS
+	(5735 - 5835 @ 20), (30)
+
+country GY:
+	(2402 - 2482 @ 40), (30)
+	(5735 - 5835 @ 80), (30)
+
+country HK: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country HN: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country HR: DFS-ETSI
+	(2400 - 2483.5 @ 40), (20)
+	(5150 - 5250 @ 80), (23), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (20), NO-OUTDOOR, DFS, AUTO-BW
+	(5470 - 5725 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country HT: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country HU: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country ID: DFS-JP
+	# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
+	(2402 - 2482 @ 20), (20)
+	(5735 - 5815 @ 20), (23)
+
+country IE: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country IL: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (200 mW), NO-OUTDOOR, DFS, AUTO-BW
+
+country IN: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (20)
+
+country IR: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5735 - 5835 @ 80), (30)
+
+country IS: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country IT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country JM: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country JO: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (23)
+	(5735 - 5835 @ 80), (23)
+
+country JP: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(2474 - 2494 @ 20), (20), NO-OFDM
+	(4910 - 4990 @ 40), (23)
+	(5030 - 5090 @ 40), (23)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (23), DFS
+	# 60 GHz band channels 2-4 at 10mW,
+	# ref: http://www.arib.or.jp/english/html/overview/doc/1-STD-T74v1_1.pdf
+	(59000 - 66000 @ 2160), (10 mW)
+
+country KE: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (23)
+	(5490 - 5570 @ 80), (30), DFS
+	(5735 - 5775 @ 40), (23)
+
+country KH: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+# Source
+# http://ntrc.kn/?page_id=7
+country KN: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (30), DFS
+	(5735 - 5815 @ 80), (30)
+
+country KP: DFS-JP
+	(2402 - 2482 @ 20), (20)
+	(5170 - 5250 @ 20), (20)
+	(5250 - 5330 @ 20), (20), DFS
+	(5490 - 5630 @ 20), (30), DFS
+	(5735 - 5815 @ 20), (30)
+
+country KR: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (30), DFS
+	(5735 - 5835 @ 80), (30)
+	# 60 GHz band channels 1-4,
+	# ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99
+	(57000 - 66000 @ 2160), (43)
+
+country KW: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+
+country KY: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country KZ:
+	(2402 - 2482 @ 40), (20)
+
+country LB: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# http://www.ntrc.org.lc/operational_structures.htm
+country LC: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (30), DFS
+	(5735 - 5815 @ 80), (30)
+
+country LI: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country LK: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 20), (17)
+	(5250 - 5330 @ 20), (24), DFS
+	(5490 - 5730 @ 20), (24), DFS
+	(5735 - 5835 @ 20), (30)
+
+# Source:
+# http://lca.org.ls/images/documents/lesotho_national_frequency_allocation_plan.pdf
+country LS: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country LT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country LU: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country LV: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country MA: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+
+country MC: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+# Source:
+# http://www.cnfr.md/index.php?pag=sec&id=117&l=en
+country MD: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+# Source:
+# http://www.cept.org/files/1050/Tools%20and%20Services/EFIS%20-%20ECO%20Frequency%20Information%20System/National%20frequency%20tables/Montenegro%20NAFT%20-%202010.pdf
+country ME: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country MF: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country MH: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country MK: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country MN: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country MO: DFS-FCC
+	(2402 - 2482 @ 40), (23)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (30), DFS
+	(5735 - 5835 @ 80), (30)
+
+country MP: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country MQ: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+# Source:
+# http://www.are.mr/pdfs/telec_freq_TNAbf_2010.pdf
+country MR: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country MT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country MU: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# http://www.cam.gov.mv/docs/tech_standards/TAM-TS-100-2004-WLAN.pdf
+country MV: DFS-ETSI
+	(2400 - 2483.5 @ 40), (100 mW)
+	(5150 - 5250 @ 80), (200 mW), AUTO-BW
+	(5250 - 5350 @ 80), (100 mW), DFS, AUTO-BW
+	(5725 - 5850 @ 80), (100 mW)
+
+country MW: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country MX: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country MY: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5650 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (24)
+
+country NG: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5250 - 5330 @ 80), (30), DFS
+	(5735 - 5835 @ 80), (30)
+
+country NI: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Regulation on the use of frequency space without a license and
+# without notification 2015
+#
+# http://wetten.overheid.nl/BWBR0036378/2015-03-05
+
+country NL: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), NO-OUTDOOR, AUTO-BW
+	(5250 - 5330 @ 80), (20), NO-OUTDOOR, DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# short range devices (ETSI EN 300 440-1)
+	(5725 - 5875 @ 80), (25 mW)
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+# Data from http://www.lovdata.no/dokument/SF/forskrift/2012-01-19-77
+# Power at 5250 - 5350 MHz, 5470 - 5725 MHz and 5815 – 5850 MHz can
+# be doubled if TPC is implemented.
+# Up to 2W (or 4W with TPC) is allowed in the 5725 – 5795 MHz band
+# which has been merged with 5470 - 5725 MHz to allow wide channels
+country NO: DFS-ETSI
+	(2400 - 2483.5 @ 40), (100 mW)
+	(5150 - 5250 @ 80), (200 mW), AUTO-BW
+	(5250 - 5350 @ 80), (100 mW), DFS, AUTO-BW
+	(5470 - 5795 @ 160), (500 mW), DFS
+	(5815 - 5850 @ 35), (2000 mW), DFS
+	(17100 - 17300 @ 200), (100 mW)
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country NP: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (20)
+
+country NZ: DFS-ETSI
+	(2402 - 2482 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country OM: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country PA: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+country PE: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country PF: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country PG: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country PH: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country PK: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5735 - 5835 @ 80), (30)
+
+country PL: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country PM: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country PR: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country PT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country PW: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country PY: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country QA: DFS-JP
+	(2402 - 2482 @ 40), (20)
+	(5735 - 5835 @ 80), (30)
+
+country RE: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country RO: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+
+# Source:
+# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
+country RS: DFS-ETSI
+	(2400 - 2483.5 @ 40), (100 mW)
+	(5150 - 5350 @ 40), (200 mW), NO-OUTDOOR
+	(5470 - 5725 @ 20), (1000 mW), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country RU: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5650 - 5730 @ 80), (30), DFS
+	(5735 - 5835 @ 80), (30)
+	# 60 GHz band channels 1-4, ref: Changes to NLA 124_Order №129_22042015.pdf
+	(57000 - 66000 @ 2160), (40)
+
+country RW: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country SA: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country SE: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country SG: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country SI: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country SK: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+# Source:
+# Regulation N° 2004-005 ART/DG/DRC/D.Rég
+country SN: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country SR: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country SV: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 20), (17)
+	(5250 - 5330 @ 20), (23), DFS
+	(5735 - 5835 @ 20), (30)
+
+country SY:
+	(2402 - 2482 @ 40), (20)
+
+# Source:
+# http://www.telecommission.tc/Spectrum-plan20110324-101210.html
+country TC: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country TD: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country TG: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 40), (20)
+	(5250 - 5330 @ 40), (20), DFS
+	(5490 - 5710 @ 40), (27), DFS
+
+country TH: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country TN: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+
+country TR: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country TT: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# Table of Frequency Allocations of Republic of China (Taiwan) / Nov 2014:
+#   http://www.motc.gov.tw/websitedowndoc?file=post/201411171137330.doc& \
+#      filedisplay=Table+of+radio+frequency+allocation.doc
+# LP0002 Low-power Radio-frequency Devices Technical Regulations / 28 Jun 2011:
+#   http://www.ncc.gov.tw/english/show_file.aspx?table_name=news&file_sn=681
+#   (section 3.10.1, 4.7)
+country TW: DFS-FCC
+	(2400 - 2483.5 @ 40), (30)
+	# Follow US 5.15 ~ 5.25 GHz: 30 dBm for master mode, 23 dBm for clients
+	(5150 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5350 @ 80), (23), DFS, AUTO-BW
+	(5470 - 5725 @ 160), (23), DFS
+	(5725 - 5850 @ 80), (30)
+ 
+country TZ:
+	(2402 - 2482 @ 40), (20)
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874
+# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361
+# (appendix 8)
+# Listed 5GHz range is a lowest common denominator for all related
+# rules in the referenced laws. Such a range is used because of
+# disputable definitions there.
+country UA: DFS-ETSI
+	(2400 - 2483.5 @ 40), (20), NO-OUTDOOR
+	(5150 - 5250 @ 80), (20), NO-OUTDOOR, AUTO-BW
+	(5250 - 5350 @ 80), (20), DFS, NO-OUTDOOR, AUTO-BW
+	(5490 - 5670 @ 160), (20), DFS
+	(5735 - 5835 @ 80), (20)
+	# 60 GHz band channels 1-4, ref: Etsi En 302 567
+	(57000 - 66000 @ 2160), (40)
+
+country UG: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country US: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	# 5.15 ~ 5.25 GHz: 30 dBm for master mode, 23 dBm for clients
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (23), DFS
+	(5735 - 5835 @ 80), (30)
+	# 60g band
+	# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
+	# channels 1,2,3, EIRP=40dBm(43dBm peak)
+	(57240 - 63720 @ 2160), (40)
+
+country UY: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# http://cemc.uz/article/1976/
+country UZ: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+
+# Source:
+# http://www.ntrc.vc/regulations/Jun_2006_Spectrum_Managment_Regulations.pdf
+country VC: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+# Source:
+# Official Gazette (Gaceta Oficial) concerning Unlicensed transmitter use
+# (10 June 2013)
+# http://www.conatel.gob.ve/
+country VE: DFS-FCC
+	(2402 - 2482 @ 40), (30)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (23), DFS, AUTO-BW
+	(5735 - 5835 @ 80), (30)
+
+country VI: DFS-FCC
+	(2402 - 2472 @ 40), (30)
+	(5170 - 5250 @ 80), (24), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country VN: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17)
+	(5250 - 5330 @ 80), (24), DFS
+	(5490 - 5730 @ 80), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+# Source:
+# http://www.trr.vu/attachments/category/130/GURL_for_Short-range_Radiocommunication_Devices2.pdf
+country VU: DFS-FCC
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (17), AUTO-BW
+	(5250 - 5330 @ 80), (24), DFS, AUTO-BW
+	(5490 - 5730 @ 160), (24), DFS
+	(5735 - 5835 @ 80), (30)
+
+country WF: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country WS: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 40), (20)
+	(5250 - 5330 @ 40), (20), DFS
+	(5490 - 5710 @ 40), (27), DFS
+
+country YE:
+	(2402 - 2482 @ 40), (20)
+
+country YT: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
+country ZA: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (30)
+
+country ZW: DFS-ETSI
+	(2402 - 2482 @ 40), (20)
+	(5170 - 5250 @ 80), (20), AUTO-BW
+	(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+	(5490 - 5710 @ 160), (27), DFS
+
diff --git a/package/kernel/mac80211/patches/000-fix_kconfig.patch b/package/kernel/mac80211/patches/000-fix_kconfig.patch
new file mode 100644
index 0000000000..3987aae4f5
--- /dev/null
+++ b/package/kernel/mac80211/patches/000-fix_kconfig.patch
@@ -0,0 +1,14 @@
+--- a/kconf/Makefile
++++ b/kconf/Makefile
+@@ -1,9 +1,9 @@
+-CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
++CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -DKBUILD_NO_NLS
+ 
+ LXDIALOG := lxdialog/checklist.o lxdialog/inputbox.o lxdialog/menubox.o lxdialog/textbox.o lxdialog/util.o lxdialog/yesno.o
+ 
+ conf: conf.o zconf.tab.o
+-mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) -DLOCALE
++mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags)
+ mconf_LDFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ldflags $(CC))
+ mconf: CFLAGS += $(mconf_CFLAGS)
+ 
diff --git a/package/kernel/mac80211/patches/001-fix_build.patch b/package/kernel/mac80211/patches/001-fix_build.patch
new file mode 100644
index 0000000000..402649d2cc
--- /dev/null
+++ b/package/kernel/mac80211/patches/001-fix_build.patch
@@ -0,0 +1,167 @@
+--- a/Makefile
++++ b/Makefile
+@@ -5,7 +5,7 @@
+ ifeq ($(KERNELRELEASE),)
+ 
+ MAKEFLAGS += --no-print-directory
+-SHELL := /bin/bash
++SHELL := /usr/bin/env bash
+ BACKPORT_DIR := $(shell pwd)
+ 
+ KMODDIR ?= updates
+@@ -19,6 +19,7 @@ KLIB_BUILD ?= $(KLIB)/build/
+ KERNEL_CONFIG := $(KLIB_BUILD)/.config
+ KERNEL_MAKEFILE := $(KLIB_BUILD)/Makefile
+ CONFIG_MD5 := $(shell md5sum $(KERNEL_CONFIG) 2>/dev/null | sed 's/\s.*//')
++STAMP_KERNEL_CONFIG := .kernel_config_md5_$(CONFIG_MD5)
+ 
+ export KLIB KLIB_BUILD BACKPORT_DIR KMODDIR KMODPATH_ARG
+ 
+@@ -36,7 +37,8 @@ mrproper:
+ 	@rm -f .kernel_config_md5 Kconfig.versions Kconfig.kernel
+ 	@rm -f backport-include/backport/autoconf.h
+ 
+-.DEFAULT:
++.SILENT: $(STAMP_KERNEL_CONFIG)
++$(STAMP_KERNEL_CONFIG):
+ 	@set -e ; test -f .local-symbols || (						\
+ 	echo "/--------------"								;\
+ 	echo "| You shouldn't run make in the backports tree, but only in"		;\
+@@ -60,57 +62,61 @@ mrproper:
+ 	echo "| (that isn't currently running.)"					;\
+ 	echo "\\--"									;\
+ 	false)
+-	@set -e ; if [ "$$(cat .kernel_config_md5 2>/dev/null)" != "$(CONFIG_MD5)" ]	;\
+-	then 										\
+-		echo -n "Generating local configuration database from kernel ..."	;\
+-		grep -v -f .local-symbols $(KERNEL_CONFIG) | grep = | (			\
+-			while read l ; do						\
+-				if [ "$${l:0:7}" != "CONFIG_" ] ; then			\
+-					continue					;\
+-				fi							;\
+-				l=$${l:7}						;\
+-				n=$${l%%=*}						;\
+-				v=$${l#*=}						;\
+-				if [ "$$v" = "m" ] ; then				\
+-					echo config $$n					;\
+-					echo '    tristate' 				;\
+-				elif [ "$$v" = "y" ] ; then				\
+-					echo config $$n					;\
+-					echo '    bool'					;\
+-				else							\
+-					continue					;\
+-				fi							;\
+-				echo "    default $$v"					;\
+-				echo ""							;\
+-			done								\
+-		) > Kconfig.kernel							;\
+-		kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion |	\
+-			sed 's/^\(\([3-4]\|2\.6\)\.[0-9]\+\).*/\1/;t;d')		;\
+-		test "$$kver" != "" || echo "Kernel version parse failed!"		;\
+-		test "$$kver" != ""							;\
+-		kvers="$$(seq 14 39 | sed 's/^/2.6./')"					;\
+-		kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')"				;\
+-		kvers="$$kvers $$(seq 0 99 | sed 's/^/4./')"				;\
+-		print=0									;\
+-		for v in $$kvers ; do							\
+-			if [ "$$print" = "1" ] ; then					\
+-				echo config KERNEL_$$(echo $$v | tr . _)	;\
+-				echo "    def_bool y"					;\
+-			fi								;\
+-			if [ "$$v" = "$$kver" ] ; then print=1 ; fi			;\
+-		done > Kconfig.versions							;\
+-		# RHEL as well, sadly we need to grep for it				;\
+-		RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | 			\
+-					sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\
+-		RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | 			\
+-					sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\
+-		for v in $$(seq 0 $$RHEL_MINOR) ; do 					\
+-			echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v		;\
+-			echo "    def_bool y"						;\
+-		done >> Kconfig.versions						;\
+-		echo " done."								;\
+-	fi										;\
+-	echo "$(CONFIG_MD5)" > .kernel_config_md5
++	@rm -f .kernel_config_md5_*
++	@touch $@
++
++Kconfig.kernel: $(STAMP_KERNEL_CONFIG) .local-symbols
++	@printf "Generating local configuration database from kernel ..."
++	@grep -v -f .local-symbols $(KERNEL_CONFIG) | grep = | (			\
++		while read l ; do						\
++			if [ "$${l:0:7}" != "CONFIG_" ] ; then			\
++				continue					;\
++			fi							;\
++			l=$${l:7}						;\
++			n=$${l%%=*}						;\
++			v=$${l#*=}						;\
++			if [ "$$v" = "m" ] ; then				\
++				echo config $$n					;\
++				echo '    tristate' 				;\
++			elif [ "$$v" = "y" ] ; then				\
++				echo config $$n					;\
++				echo '    bool'					;\
++			else							\
++				continue					;\
++			fi							;\
++			echo "    default $$v"					;\
++			echo ""							;\
++		done								\
++	) > $@
++	@echo " done."
++
++Kconfig.versions: Kconfig.kernel
++	@kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion |	\
++		sed 's/^\(\([3-4]\|2\.6\)\.[0-9]\+\).*/\1/;t;d')		;\
++	test "$$kver" != "" || echo "Kernel version parse failed!"		;\
++	test "$$kver" != ""							;\
++	kvers="$$(seq 14 39 | sed 's/^/2.6./')"					;\
++	kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')"				;\
++	kvers="$$kvers $$(seq 0 99 | sed 's/^/4./')"				;\
++	print=0									;\
++	for v in $$kvers ; do							\
++		if [ "$$print" = "1" ] ; then					\
++			echo config KERNEL_$$(echo $$v | tr . _)	;\
++			echo "    def_bool y"					;\
++		fi								;\
++		if [ "$$v" = "$$kver" ] ; then print=1 ; fi			;\
++	done > $@
++	@RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | 			\
++				sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\
++	RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | 			\
++				sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\
++	for v in $$(seq 0 $$RHEL_MINOR) ; do 					\
++		echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v		;\
++		echo "    def_bool y"						;\
++	done >> $@
++
++.DEFAULT:
++	@$(MAKE) Kconfig.versions
+ 	@$(MAKE) -f Makefile.real "$@"
+ 
+ .PHONY: defconfig-help
+--- a/Makefile.real
++++ b/Makefile.real
+@@ -59,7 +59,7 @@ defconfig-%::
+ 
+ backport-include/backport/autoconf.h: .config Kconfig.versions Kconfig.kernel
+ 	@$(MAKE) oldconfig
+-	@echo -n "Building backport-include/backport/autoconf.h ..."
++	@printf "Building backport-include/backport/autoconf.h ..."
+ 	@grep -f .local-symbols .config | (				\
+ 		echo "#ifndef COMPAT_AUTOCONF_INCLUDED"			;\
+ 		echo "#define COMPAT_AUTOCONF_INCLUDED"			;\
+@@ -80,7 +80,12 @@ backport-include/backport/autoconf.h: .c
+ 			esac						;\
+ 		done							;\
+ 		echo "#endif /* COMPAT_AUTOCONF_INCLUDED */"		;\
+-	) > backport-include/backport/autoconf.h
++	) > $@.new
++	@if cmp -s $@ $@.new; then \
++		rm -f $@.new; \
++	else \
++		mv $@.new $@; \
++	fi
+ 	@echo " done."
+ 
+ .PHONY: modules
diff --git a/package/kernel/mac80211/patches/002-change_allconfig.patch b/package/kernel/mac80211/patches/002-change_allconfig.patch
new file mode 100644
index 0000000000..bd5bebfa45
--- /dev/null
+++ b/package/kernel/mac80211/patches/002-change_allconfig.patch
@@ -0,0 +1,64 @@
+--- a/kconf/conf.c
++++ b/kconf/conf.c
+@@ -593,40 +593,12 @@ int main(int ac, char **av)
+ 	case oldconfig:
+ 	case listnewconfig:
+ 	case olddefconfig:
+-		conf_read(NULL);
+-		break;
+ 	case allnoconfig:
+ 	case allyesconfig:
+ 	case allmodconfig:
+ 	case alldefconfig:
+ 	case randconfig:
+-		name = getenv("KCONFIG_ALLCONFIG");
+-		if (!name)
+-			break;
+-		if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+-			if (conf_read_simple(name, S_DEF_USER)) {
+-				fprintf(stderr,
+-					_("*** Can't read seed configuration \"%s\"!\n"),
+-					name);
+-				exit(1);
+-			}
+-			break;
+-		}
+-		switch (input_mode) {
+-		case allnoconfig:	name = "allno.config"; break;
+-		case allyesconfig:	name = "allyes.config"; break;
+-		case allmodconfig:	name = "allmod.config"; break;
+-		case alldefconfig:	name = "alldef.config"; break;
+-		case randconfig:	name = "allrandom.config"; break;
+-		default: break;
+-		}
+-		if (conf_read_simple(name, S_DEF_USER) &&
+-		    conf_read_simple("all.config", S_DEF_USER)) {
+-			fprintf(stderr,
+-				_("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
+-				name);
+-			exit(1);
+-		}
++		conf_read(NULL);
+ 		break;
+ 	default:
+ 		break;
+--- a/kconf/confdata.c
++++ b/kconf/confdata.c
+@@ -1169,6 +1169,8 @@ bool conf_set_all_new_symbols(enum conf_
+ 	}
+ 	bool has_changed = false;
+ 
++	sym_clear_all_valid();
++
+ 	for_all_symbols(i, sym) {
+ 		if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
+ 			continue;
+@@ -1212,8 +1214,6 @@ bool conf_set_all_new_symbols(enum conf_
+ 
+ 	}
+ 
+-	sym_clear_all_valid();
+-
+ 	/*
+ 	 * We have different type of choice blocks.
+ 	 * If curr.tri equals to mod then we can select several
diff --git a/package/kernel/mac80211/patches/003-remove_bogus_modparams.patch b/package/kernel/mac80211/patches/003-remove_bogus_modparams.patch
new file mode 100644
index 0000000000..8fa465a7e1
--- /dev/null
+++ b/package/kernel/mac80211/patches/003-remove_bogus_modparams.patch
@@ -0,0 +1,34 @@
+--- a/compat/main.c
++++ b/compat/main.c
+@@ -20,31 +20,6 @@ MODULE_LICENSE("GPL");
+ #error "You need a CPTCFG_VERSION"
+ #endif
+ 
+-static char *backported_kernel_name = CPTCFG_KERNEL_NAME;
+-
+-module_param(backported_kernel_name, charp, 0400);
+-MODULE_PARM_DESC(backported_kernel_name,
+-		 "The kernel tree name that was used for this backport (" CPTCFG_KERNEL_NAME ")");
+-
+-#ifdef BACKPORTS_GIT_TRACKED
+-static char *backports_tracker_id = BACKPORTS_GIT_TRACKED;
+-module_param(backports_tracker_id, charp, 0400);
+-MODULE_PARM_DESC(backports_tracker_id,
+-		 "The version of the tree containing this backport (" BACKPORTS_GIT_TRACKED ")");
+-#else
+-static char *backported_kernel_version = CPTCFG_KERNEL_VERSION;
+-static char *backports_version = CPTCFG_VERSION;
+-
+-module_param(backported_kernel_version, charp, 0400);
+-MODULE_PARM_DESC(backported_kernel_version,
+-		 "The kernel version that was used for this backport (" CPTCFG_KERNEL_VERSION ")");
+-
+-module_param(backports_version, charp, 0400);
+-MODULE_PARM_DESC(backports_version,
+-		 "The git version of the backports tree used to generate this backport (" CPTCFG_VERSION ")");
+-
+-#endif
+-
+ void backport_dependency_symbol(void)
+ {
+ }
diff --git a/package/kernel/mac80211/patches/004-fix_duplicate_skcipher_backport.patch b/package/kernel/mac80211/patches/004-fix_duplicate_skcipher_backport.patch
new file mode 100644
index 0000000000..22819f7ed2
--- /dev/null
+++ b/package/kernel/mac80211/patches/004-fix_duplicate_skcipher_backport.patch
@@ -0,0 +1,11 @@
+--- a/compat/Makefile
++++ b/compat/Makefile
+@@ -36,8 +36,6 @@ compat-$(CPTCFG_KERNEL_4_7) += backport-
+ 
+ compat-$(CPTCFG_BPAUTO_BUILD_CRYPTO_CCM) += crypto-ccm.o
+ compat-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
+-skcipher-objs += crypto-skcipher.o
+-obj-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += skcipher.o
+ compat-$(CPTCFG_BPAUTO_BUILD_WANT_DEV_COREDUMP) += drivers-base-devcoredump.o
+ compat-$(CPTCFG_BPAUTO_RHASHTABLE) += lib-rhashtable.o
+ cordic-objs += lib-cordic.o
diff --git a/package/kernel/mac80211/patches/005-backport_skb_get_hash_perturb.patch b/package/kernel/mac80211/patches/005-backport_skb_get_hash_perturb.patch
new file mode 100644
index 0000000000..29bccc1e99
--- /dev/null
+++ b/package/kernel/mac80211/patches/005-backport_skb_get_hash_perturb.patch
@@ -0,0 +1,22 @@
+--- a/backport-include/linux/skbuff.h
++++ b/backport-include/linux/skbuff.h
+@@ -305,6 +305,19 @@ static inline void skb_free_frag(void *d
+ {
+ 	put_page(virt_to_head_page(data));
+ }
++
++#include <net/flow_keys.h>
++#include <linux/jhash.h>
++
++static inline u32 skb_get_hash_perturb(struct sk_buff *skb, u32 key)
++{
++	struct flow_keys keys;
++
++	skb_flow_dissect(skb, &keys);
++	return jhash_3words((__force u32)keys.dst,
++			    (__force u32)keys.src ^ keys.ip_proto,
++			    (__force u32)keys.ports, key);
++}
+ #endif
+ 
+ #endif /* __BACKPORT_SKBUFF_H */
diff --git a/package/kernel/mac80211/patches/010-disable_rfkill.patch b/package/kernel/mac80211/patches/010-disable_rfkill.patch
new file mode 100644
index 0000000000..2902e498d8
--- /dev/null
+++ b/package/kernel/mac80211/patches/010-disable_rfkill.patch
@@ -0,0 +1,15 @@
+--- a/backport-include/linux/rfkill.h
++++ b/backport-include/linux/rfkill.h
+@@ -2,6 +2,12 @@
+ #define __COMPAT_RFKILL_H
+ #include <linux/version.h>
+ 
++#undef CONFIG_RFKILL
++#undef CONFIG_RFKILL_FULL
++#undef CONFIG_RFKILL_LEDS
++#undef CONFIG_RFKILL_MODULE
++#undef CONFIG_RFKILL_FULL_MODULE
++
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ #include_next <linux/rfkill.h>
+ #else
diff --git a/package/kernel/mac80211/patches/050-lib80211_option.patch b/package/kernel/mac80211/patches/050-lib80211_option.patch
new file mode 100644
index 0000000000..3fc8c05207
--- /dev/null
+++ b/package/kernel/mac80211/patches/050-lib80211_option.patch
@@ -0,0 +1,30 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -171,7 +171,7 @@ config CFG80211_WEXT_EXPORT
+ 	  wext compatibility symbols to be exported.
+ 
+ config LIB80211
+-	tristate
++	tristate "lib80211"
+ 	depends on m
+ 	default n
+ 	help
+@@ -181,15 +181,15 @@ config LIB80211
+ 	  Drivers should select this themselves if needed.
+ 
+ config LIB80211_CRYPT_WEP
+-	tristate
++	tristate "lib80211 WEP support"
+ 	depends on m
+ 
+ config LIB80211_CRYPT_CCMP
+-	tristate
++	tristate "lib80211 CCMP support"
+ 	depends on m
+ 
+ config LIB80211_CRYPT_TKIP
+-	tristate
++	tristate "lib80211 TKIP support"
+ 	depends on m
+ 
+ config LIB80211_DEBUG
diff --git a/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch
new file mode 100644
index 0000000000..4df5ac57f0
--- /dev/null
+++ b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch
@@ -0,0 +1,132 @@
+--- a/.local-symbols
++++ b/.local-symbols
+@@ -477,45 +477,6 @@ USB_IPHETH=
+ USB_SIERRA_NET=
+ USB_VL600=
+ USB_NET_CH9200=
+-SSB_POSSIBLE=
+-SSB=
+-SSB_SPROM=
+-SSB_BLOCKIO=
+-SSB_PCIHOST_POSSIBLE=
+-SSB_PCIHOST=
+-SSB_B43_PCI_BRIDGE=
+-SSB_PCMCIAHOST_POSSIBLE=
+-SSB_PCMCIAHOST=
+-SSB_SDIOHOST_POSSIBLE=
+-SSB_SDIOHOST=
+-SSB_HOST_SOC=
+-SSB_SILENT=
+-SSB_DEBUG=
+-SSB_SERIAL=
+-SSB_DRIVER_PCICORE_POSSIBLE=
+-SSB_DRIVER_PCICORE=
+-SSB_PCICORE_HOSTMODE=
+-SSB_DRIVER_MIPS=
+-SSB_SFLASH=
+-SSB_EMBEDDED=
+-SSB_DRIVER_EXTIF=
+-SSB_DRIVER_GIGE=
+-SSB_DRIVER_GPIO=
+-BCMA_POSSIBLE=
+-BCMA=
+-BCMA_BLOCKIO=
+-BCMA_HOST_PCI_POSSIBLE=
+-BCMA_HOST_PCI=
+-BCMA_HOST_SOC=
+-BCMA_DRIVER_PCI=
+-BCMA_DRIVER_PCI_HOSTMODE=
+-BCMA_DRIVER_MIPS=
+-BCMA_PFLASH=
+-BCMA_SFLASH=
+-BCMA_NFLASH=
+-BCMA_DRIVER_GMAC_CMN=
+-BCMA_DRIVER_GPIO=
+-BCMA_DEBUG=
+ NFC=
+ NFC_DIGITAL=
+ NFC_NCI=
+--- a/drivers/net/wireless/broadcom/b43/main.c
++++ b/drivers/net/wireless/broadcom/b43/main.c
+@@ -2866,7 +2866,7 @@ static struct ssb_device *b43_ssb_gpio_d
+ {
+ 	struct ssb_bus *bus = dev->dev->sdev->bus;
+ 
+-#ifdef CPTCFG_SSB_DRIVER_PCICORE
++#ifdef CONFIG_SSB_DRIVER_PCICORE
+ 	return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
+ #else
+ 	return bus->chipco.dev;
+@@ -4883,7 +4883,7 @@ static int b43_wireless_core_init(struct
+ 	}
+ 	if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
+ 		hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
+-#if defined(CPTCFG_B43_SSB) && defined(CPTCFG_SSB_DRIVER_PCICORE)
++#if defined(CPTCFG_B43_SSB) && defined(CONFIG_SSB_DRIVER_PCICORE)
+ 	if (dev->dev->bus_type == B43_BUS_SSB &&
+ 	    dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+ 	    dev->dev->sdev->bus->pcicore.dev->id.revision <= 10)
+--- a/drivers/net/wireless/broadcom/b43legacy/main.c
++++ b/drivers/net/wireless/broadcom/b43legacy/main.c
+@@ -1937,7 +1937,7 @@ static int b43legacy_gpio_init(struct b4
+ 	if (dev->dev->id.revision >= 2)
+ 		mask  |= 0x0010; /* FIXME: This is redundant. */
+ 
+-#ifdef CPTCFG_SSB_DRIVER_PCICORE
++#ifdef CONFIG_SSB_DRIVER_PCICORE
+ 	pcidev = bus->pcicore.dev;
+ #endif
+ 	gpiodev = bus->chipco.dev ? : pcidev;
+@@ -1956,7 +1956,7 @@ static void b43legacy_gpio_cleanup(struc
+ 	struct ssb_bus *bus = dev->dev->bus;
+ 	struct ssb_device *gpiodev, *pcidev = NULL;
+ 
+-#ifdef CPTCFG_SSB_DRIVER_PCICORE
++#ifdef CONFIG_SSB_DRIVER_PCICORE
+ 	pcidev = bus->pcicore.dev;
+ #endif
+ 	gpiodev = bus->chipco.dev ? : pcidev;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile
+@@ -43,6 +43,6 @@ brcmsmac-y := \
+ 	brcms_trace_events.o \
+ 	debug.o
+ 
+-brcmsmac-$(CPTCFG_BCMA_DRIVER_GPIO) += led.o
++brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o
+ 
+ obj-$(CPTCFG_BRCMSMAC)	+= brcmsmac.o
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
+@@ -22,7 +22,7 @@ struct brcms_led {
+ 	bool active_low;
+ };
+ 
+-#ifdef CPTCFG_BCMA_DRIVER_GPIO
++#ifdef CONFIG_BCMA_DRIVER_GPIO
+ void brcms_led_unregister(struct brcms_info *wl);
+ int brcms_led_register(struct brcms_info *wl);
+ #else
+--- a/Kconfig.sources
++++ b/Kconfig.sources
+@@ -9,9 +9,6 @@ source "$BACKPORT_DIR/drivers/net/wirele
+ source "$BACKPORT_DIR/drivers/net/ethernet/Kconfig"
+ source "$BACKPORT_DIR/drivers/net/usb/Kconfig"
+ 
+-source "$BACKPORT_DIR/drivers/ssb/Kconfig"
+-source "$BACKPORT_DIR/drivers/bcma/Kconfig"
+-
+ source "$BACKPORT_DIR/net/nfc/Kconfig"
+ 
+ source "$BACKPORT_DIR/drivers/media/Kconfig"
+--- a/Makefile.kernel
++++ b/Makefile.kernel
+@@ -38,8 +38,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/
+ obj-$(CPTCFG_WLAN) += drivers/net/wireless/
+ obj-$(CPTCFG_BT) += net/bluetooth/
+ obj-$(CPTCFG_BT) += drivers/bluetooth/
+-obj-$(CPTCFG_SSB) += drivers/ssb/
+-obj-$(CPTCFG_BCMA) += drivers/bcma/
+ obj-$(CPTCFG_ETHERNET) += drivers/net/ethernet/
+ obj-$(CPTCFG_USB_NET_RNDIS_WLAN) += drivers/net/usb/
+ obj-$(CPTCFG_NFC) += net/nfc/
diff --git a/package/kernel/mac80211/patches/070-ath_common_config.patch b/package/kernel/mac80211/patches/070-ath_common_config.patch
new file mode 100644
index 0000000000..41774fe53e
--- /dev/null
+++ b/package/kernel/mac80211/patches/070-ath_common_config.patch
@@ -0,0 +1,9 @@
+--- a/drivers/net/wireless/ath/Kconfig
++++ b/drivers/net/wireless/ath/Kconfig
+@@ -1,5 +1,5 @@
+ config ATH_COMMON
+-	tristate
++	tristate "ath.ko"
+ 	depends on m
+ 
+ config WLAN_VENDOR_ATH
diff --git a/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch b/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch
new file mode 100644
index 0000000000..b65b0bd00e
--- /dev/null
+++ b/package/kernel/mac80211/patches/100-remove-cryptoapi-dependencies.patch
@@ -0,0 +1,370 @@
+--- a/net/mac80211/Kconfig
++++ b/net/mac80211/Kconfig
+@@ -5,8 +5,6 @@ config MAC80211
+ 	depends on CRYPTO
+ 	depends on CRYPTO_ARC4
+ 	depends on CRYPTO_AES
+-	select BPAUTO_CRYPTO_CCM
+-	depends on CRYPTO_GCM
+ 	depends on CRC32
+ 	---help---
+ 	  This option enables the hardware independent IEEE 802.11
+--- a/net/mac80211/Makefile
++++ b/net/mac80211/Makefile
+@@ -16,9 +16,7 @@ mac80211-y := \
+ 	michael.o \
+ 	tkip.o \
+ 	aes_ccm.o \
+-	aes_gcm.o \
+ 	aes_cmac.o \
+-	aes_gmac.o \
+ 	cfg.o \
+ 	ethtool.o \
+ 	rx.o \
+--- a/net/mac80211/aes_ccm.c
++++ b/net/mac80211/aes_ccm.c
+@@ -13,89 +13,132 @@
+ #include <linux/types.h>
+ #include <linux/err.h>
+ #include <crypto/aead.h>
++#include <crypto/aes.h>
+ 
+ #include <net/mac80211.h>
+ #include "key.h"
+ #include "aes_ccm.h"
+ 
+-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
++static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
++			    u8 *a, u8 *b)
++{
++	int i;
++
++	crypto_cipher_encrypt_one(tfm, b, b_0);
++
++	/* Extra Authenticate-only data (always two AES blocks) */
++	for (i = 0; i < AES_BLOCK_SIZE; i++)
++		aad[i] ^= b[i];
++	crypto_cipher_encrypt_one(tfm, b, aad);
++
++	aad += AES_BLOCK_SIZE;
++
++	for (i = 0; i < AES_BLOCK_SIZE; i++)
++		aad[i] ^= b[i];
++	crypto_cipher_encrypt_one(tfm, a, aad);
++
++	/* Mask out bits from auth-only-b_0 */
++	b_0[0] &= 0x07;
++
++	/* S_0 is used to encrypt T (= MIC) */
++	b_0[14] = 0;
++	b_0[15] = 0;
++	crypto_cipher_encrypt_one(tfm, s_0, b_0);
++}
++
++
++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ 			       u8 *data, size_t data_len, u8 *mic,
+ 			       size_t mic_len)
+ {
+-	struct scatterlist sg[3];
++	int i, j, last_len, num_blocks;
++	u8 b[AES_BLOCK_SIZE];
++	u8 s_0[AES_BLOCK_SIZE];
++	u8 e[AES_BLOCK_SIZE];
++	u8 *pos, *cpos;
+ 
+-	char aead_req_data[sizeof(struct aead_request) +
+-			   crypto_aead_reqsize(tfm)]
+-		__aligned(__alignof__(struct aead_request));
+-	struct aead_request *aead_req = (void *) aead_req_data;
++	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
++	last_len = data_len % AES_BLOCK_SIZE;
++	aes_ccm_prepare(tfm, b_0, aad, s_0, b, b);
+ 
+-	memset(aead_req, 0, sizeof(aead_req_data));
++	/* Process payload blocks */
++	pos = data;
++	cpos = data;
++	for (j = 1; j <= num_blocks; j++) {
++		int blen = (j == num_blocks && last_len) ?
++			last_len : AES_BLOCK_SIZE;
+ 
+-	sg_init_table(sg, 3);
+-	sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+-	sg_set_buf(&sg[1], data, data_len);
+-	sg_set_buf(&sg[2], mic, mic_len);
++		/* Authentication followed by encryption */
++		for (i = 0; i < blen; i++)
++			b[i] ^= pos[i];
++		crypto_cipher_encrypt_one(tfm, b, b);
+ 
+-	aead_request_set_tfm(aead_req, tfm);
+-	aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
+-	aead_request_set_ad(aead_req, sg[0].length);
++		b_0[14] = (j >> 8) & 0xff;
++		b_0[15] = j & 0xff;
++		crypto_cipher_encrypt_one(tfm, e, b_0);
++		for (i = 0; i < blen; i++)
++			*cpos++ = *pos++ ^ e[i];
++	}
+ 
+-	crypto_aead_encrypt(aead_req);
++	for (i = 0; i < mic_len; i++)
++		mic[i] = b[i] ^ s_0[i];
+ }
+ 
+-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ 			      u8 *data, size_t data_len, u8 *mic,
+ 			      size_t mic_len)
+ {
+-	struct scatterlist sg[3];
+-	char aead_req_data[sizeof(struct aead_request) +
+-			   crypto_aead_reqsize(tfm)]
+-		__aligned(__alignof__(struct aead_request));
+-	struct aead_request *aead_req = (void *) aead_req_data;
++	int i, j, last_len, num_blocks;
++	u8 *pos, *cpos;
++	u8 a[AES_BLOCK_SIZE];
++	u8 b[AES_BLOCK_SIZE];
++	u8 s_0[AES_BLOCK_SIZE];
+ 
+-	if (data_len == 0)
+-		return -EINVAL;
++	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
++	last_len = data_len % AES_BLOCK_SIZE;
++	aes_ccm_prepare(tfm, b_0, aad, s_0, a, b);
+ 
+-	memset(aead_req, 0, sizeof(aead_req_data));
++	/* Process payload blocks */
++	cpos = data;
++	pos = data;
++	for (j = 1; j <= num_blocks; j++) {
++		int blen = (j == num_blocks && last_len) ?
++			last_len : AES_BLOCK_SIZE;
+ 
+-	sg_init_table(sg, 3);
+-	sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+-	sg_set_buf(&sg[1], data, data_len);
+-	sg_set_buf(&sg[2], mic, mic_len);
++		/* Decryption followed by authentication */
++		b_0[14] = (j >> 8) & 0xff;
++		b_0[15] = j & 0xff;
++		crypto_cipher_encrypt_one(tfm, b, b_0);
++		for (i = 0; i < blen; i++) {
++			*pos = *cpos++ ^ b[i];
++			a[i] ^= *pos++;
++		}
++		crypto_cipher_encrypt_one(tfm, a, a);
++	}
+ 
+-	aead_request_set_tfm(aead_req, tfm);
+-	aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
+-	aead_request_set_ad(aead_req, sg[0].length);
++	for (i = 0; i < mic_len; i++) {
++		if ((mic[i] ^ s_0[i]) != a[i])
++			return -1;
++	}
+ 
+-	return crypto_aead_decrypt(aead_req);
++	return 0;
+ }
+ 
+-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
+-						    size_t key_len,
+-						    size_t mic_len)
++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[],
++						      size_t key_len,
++						      size_t mic_len)
+ {
+-	struct crypto_aead *tfm;
+-	int err;
+-
+-	tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
+-	if (IS_ERR(tfm))
+-		return tfm;
++	struct crypto_cipher *tfm;
+ 
+-	err = crypto_aead_setkey(tfm, key, key_len);
+-	if (err)
+-		goto free_aead;
+-	err = crypto_aead_setauthsize(tfm, mic_len);
+-	if (err)
+-		goto free_aead;
++	tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
++	if (!IS_ERR(tfm))
++		crypto_cipher_setkey(tfm, key, key_len);
+ 
+ 	return tfm;
+-
+-free_aead:
+-	crypto_free_aead(tfm);
+-	return ERR_PTR(err);
+ }
+ 
+-void ieee80211_aes_key_free(struct crypto_aead *tfm)
++
++void ieee80211_aes_key_free(struct crypto_cipher *tfm)
+ {
+-	crypto_free_aead(tfm);
++	crypto_free_cipher(tfm);
+ }
+--- a/net/mac80211/aes_ccm.h
++++ b/net/mac80211/aes_ccm.h
+@@ -12,15 +12,15 @@
+ 
+ #include <linux/crypto.h>
+ 
+-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
+-						    size_t key_len,
+-						    size_t mic_len);
+-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[],
++						      size_t key_len,
++						      size_t mic_len);
++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ 			       u8 *data, size_t data_len, u8 *mic,
+ 			       size_t mic_len);
+-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ 			      u8 *data, size_t data_len, u8 *mic,
+ 			      size_t mic_len);
+-void ieee80211_aes_key_free(struct crypto_aead *tfm);
++void ieee80211_aes_key_free(struct crypto_cipher *tfm);
+ 
+ #endif /* AES_CCM_H */
+--- a/net/mac80211/aes_gcm.h
++++ b/net/mac80211/aes_gcm.h
+@@ -11,12 +11,28 @@
+ 
+ #include <linux/crypto.h>
+ 
+-void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
+-			       u8 *data, size_t data_len, u8 *mic);
+-int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
+-			      u8 *data, size_t data_len, u8 *mic);
+-struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
+-							size_t key_len);
+-void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm);
++static inline void
++ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
++			  u8 *data, size_t data_len, u8 *mic)
++{
++}
++
++static inline int
++ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
++			  u8 *data, size_t data_len, u8 *mic)
++{
++    return -EOPNOTSUPP;
++}
++
++static inline struct crypto_aead *
++ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len)
++{
++    return NULL;
++}
++
++static inline void
++ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
++{
++}
+ 
+ #endif /* AES_GCM_H */
+--- a/net/mac80211/aes_gmac.h
++++ b/net/mac80211/aes_gmac.h
+@@ -11,10 +11,22 @@
+ 
+ #include <linux/crypto.h>
+ 
+-struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
+-						 size_t key_len);
+-int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
+-		       const u8 *data, size_t data_len, u8 *mic);
+-void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm);
++static inline struct crypto_aead *
++ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len)
++{
++	return NULL;
++}
++
++static inline int
++ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
++		   const u8 *data, size_t data_len, u8 *mic)
++{
++	return -EOPNOTSUPP;
++}
++
++static inline void
++ieee80211_aes_gmac_key_free(struct crypto_aead *tfm)
++{
++}
+ 
+ #endif /* AES_GMAC_H */
+--- a/net/mac80211/key.h
++++ b/net/mac80211/key.h
+@@ -88,7 +88,7 @@ struct ieee80211_key {
+ 			 * Management frames.
+ 			 */
+ 			u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
+-			struct crypto_aead *tfm;
++			struct crypto_cipher *tfm;
+ 			u32 replays; /* dot11RSNAStatsCCMPReplays */
+ 		} ccmp;
+ 		struct {
+--- a/net/mac80211/wpa.c
++++ b/net/mac80211/wpa.c
+@@ -304,7 +304,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
+ }
+ 
+ 
+-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
++static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
++				u16 data_len)
+ {
+ 	__le16 mask_fc;
+ 	int a4_included, mgmt;
+@@ -334,14 +335,8 @@ static void ccmp_special_blocks(struct s
+ 	else
+ 		qos_tid = 0;
+ 
+-	/* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
+-	 * mode authentication are not allowed to collide, yet both are derived
+-	 * from this vector b_0. We only set L := 1 here to indicate that the
+-	 * data size can be represented in (L+1) bytes. The CCM layer will take
+-	 * care of storing the data length in the top (L+1) bytes and setting
+-	 * and clearing the other bits as is required to derive the two IVs.
+-	 */
+-	b_0[0] = 0x1;
++	/* First block, b_0 */
++	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
+ 
+ 	/* Nonce: Nonce Flags | A2 | PN
+ 	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
+@@ -349,6 +344,8 @@ static void ccmp_special_blocks(struct s
+ 	b_0[1] = qos_tid | (mgmt << 4);
+ 	memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
+ 	memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
++	/* l(m) */
++	put_unaligned_be16(data_len, &b_0[14]);
+ 
+ 	/* AAD (extra authenticate-only data) / masked 802.11 header
+ 	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
+@@ -460,7 +457,7 @@ static int ccmp_encrypt_skb(struct ieee8
+ 		return 0;
+ 
+ 	pos += IEEE80211_CCMP_HDR_LEN;
+-	ccmp_special_blocks(skb, pn, b_0, aad);
++	ccmp_special_blocks(skb, pn, b_0, aad, len);
+ 	ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
+ 				  skb_put(skb, mic_len), mic_len);
+ 
+@@ -537,7 +534,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
+ 			u8 aad[2 * AES_BLOCK_SIZE];
+ 			u8 b_0[AES_BLOCK_SIZE];
+ 			/* hardware didn't decrypt/verify MIC */
+-			ccmp_special_blocks(skb, pn, b_0, aad);
++			ccmp_special_blocks(skb, pn, b_0, aad, data_len);
+ 
+ 			if (ieee80211_aes_ccm_decrypt(
+ 				    key->u.ccmp.tfm, b_0, aad,
diff --git a/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch b/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch
new file mode 100644
index 0000000000..c42b17de38
--- /dev/null
+++ b/package/kernel/mac80211/patches/110-mac80211_keep_keys_on_stop_ap.patch
@@ -0,0 +1,12 @@
+Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects
+
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1016,7 +1016,6 @@ static int ieee80211_stop_ap(struct wiph
+ 	sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
+ 
+ 	__sta_info_flush(sdata, true);
+-	ieee80211_free_keys(sdata, true);
+ 
+ 	sdata->vif.bss_conf.enable_beacon = false;
+ 	sdata->vif.bss_conf.ssid_len = 0;
diff --git a/package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch b/package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch
new file mode 100644
index 0000000000..ffd8807ccc
--- /dev/null
+++ b/package/kernel/mac80211/patches/120-cfg80211_allow_perm_addr_change.patch
@@ -0,0 +1,43 @@
+--- a/net/wireless/sysfs.c
++++ b/net/wireless/sysfs.c
+@@ -24,18 +24,35 @@ static inline struct cfg80211_registered
+ 	return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
+ }
+ 
+-#define SHOW_FMT(name, fmt, member)					\
++#define SHOW_FMT(name, fmt, member, mode)				\
+ static ssize_t name ## _show(struct device *dev,			\
+ 			      struct device_attribute *attr,		\
+ 			      char *buf)				\
+ {									\
+ 	return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member);	\
+ }									\
+-static DEVICE_ATTR_RO(name)
++static DEVICE_ATTR_##mode(name)
+ 
+-SHOW_FMT(index, "%d", wiphy_idx);
+-SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
+-SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
++static ssize_t macaddress_store(struct device *dev,
++				struct device_attribute *attr,
++				const char *buf, size_t len)
++{
++	u8 mac[ETH_ALEN];
++
++	if (!mac_pton(buf, mac))
++		return -EINVAL;
++
++	if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
++		return -EINVAL;
++
++	memcpy(dev_to_rdev(dev)->wiphy.perm_addr, mac, ETH_ALEN);
++
++	return strnlen(buf, len);
++}
++
++SHOW_FMT(index, "%d", wiphy_idx, RO);
++SHOW_FMT(macaddress, "%pM", wiphy.perm_addr, RW);
++SHOW_FMT(address_mask, "%pM", wiphy.addr_mask, RO);
+ 
+ static ssize_t name_show(struct device *dev,
+ 			 struct device_attribute *attr,
diff --git a/package/kernel/mac80211/patches/130-mac80211-hwsim-hrtimer-clock.patch b/package/kernel/mac80211/patches/130-mac80211-hwsim-hrtimer-clock.patch
new file mode 100644
index 0000000000..29d70343bb
--- /dev/null
+++ b/package/kernel/mac80211/patches/130-mac80211-hwsim-hrtimer-clock.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -2662,7 +2662,7 @@ static int mac80211_hwsim_new_radio(stru
+ 
+ 	tasklet_hrtimer_init(&data->beacon_timer,
+ 			     mac80211_hwsim_beacon,
+-			     CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
++			     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ 
+ 	spin_lock_bh(&hwsim_radio_lock);
+ 	list_add_tail(&data->list, &hwsim_radios);
diff --git a/package/kernel/mac80211/patches/150-disable_addr_notifier.patch b/package/kernel/mac80211/patches/150-disable_addr_notifier.patch
new file mode 100644
index 0000000000..f4cb41cd30
--- /dev/null
+++ b/package/kernel/mac80211/patches/150-disable_addr_notifier.patch
@@ -0,0 +1,67 @@
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -291,7 +291,7 @@ void ieee80211_restart_hw(struct ieee802
+ }
+ EXPORT_SYMBOL(ieee80211_restart_hw);
+ 
+-#ifdef CONFIG_INET
++#ifdef __disabled__CONFIG_INET
+ static int ieee80211_ifa_changed(struct notifier_block *nb,
+ 				 unsigned long data, void *arg)
+ {
+@@ -350,7 +350,7 @@ static int ieee80211_ifa_changed(struct
+ }
+ #endif
+ 
+-#if IS_ENABLED(CONFIG_IPV6)
++#if IS_ENABLED(__disabled__CONFIG_IPV6)
+ static int ieee80211_ifa6_changed(struct notifier_block *nb,
+ 				  unsigned long data, void *arg)
+ {
+@@ -1101,14 +1101,14 @@ int ieee80211_register_hw(struct ieee802
+ 	if (result)
+ 		goto fail_flows;
+ 
+-#ifdef CONFIG_INET
++#ifdef __disabled__CONFIG_INET
+ 	local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
+ 	result = register_inetaddr_notifier(&local->ifa_notifier);
+ 	if (result)
+ 		goto fail_ifa;
+ #endif
+ 
+-#if IS_ENABLED(CONFIG_IPV6)
++#if IS_ENABLED(__disabled__CONFIG_IPV6)
+ 	local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
+ 	result = register_inet6addr_notifier(&local->ifa6_notifier);
+ 	if (result)
+@@ -1117,13 +1117,13 @@ int ieee80211_register_hw(struct ieee802
+ 
+ 	return 0;
+ 
+-#if IS_ENABLED(CONFIG_IPV6)
++#if IS_ENABLED(__disabled__CONFIG_IPV6)
+  fail_ifa6:
+-#ifdef CONFIG_INET
++#ifdef __disabled__CONFIG_INET
+ 	unregister_inetaddr_notifier(&local->ifa_notifier);
+ #endif
+ #endif
+-#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
++#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6)
+  fail_ifa:
+ #endif
+ 	ieee80211_txq_teardown_flows(local);
+@@ -1153,10 +1153,10 @@ void ieee80211_unregister_hw(struct ieee
+ 	tasklet_kill(&local->tx_pending_tasklet);
+ 	tasklet_kill(&local->tasklet);
+ 
+-#ifdef CONFIG_INET
++#ifdef __disabled__CONFIG_INET
+ 	unregister_inetaddr_notifier(&local->ifa_notifier);
+ #endif
+-#if IS_ENABLED(CONFIG_IPV6)
++#if IS_ENABLED(__disabled__CONFIG_IPV6)
+ 	unregister_inet6addr_notifier(&local->ifa6_notifier);
+ #endif
+ 
diff --git a/package/kernel/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch b/package/kernel/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch
new file mode 100644
index 0000000000..21516ffde9
--- /dev/null
+++ b/package/kernel/mac80211/patches/201-ath5k-WAR-for-AR71xx-PCI-bug.patch
@@ -0,0 +1,38 @@
+--- a/drivers/net/wireless/ath/ath5k/initvals.c
++++ b/drivers/net/wireless/ath/ath5k/initvals.c
+@@ -62,8 +62,14 @@ static const struct ath5k_ini ar5210_ini
+ 	{ AR5K_IMR,		0 },
+ 	{ AR5K_IER,		AR5K_IER_DISABLE },
+ 	{ AR5K_BSR,		0, AR5K_INI_READ },
++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
+ 	{ AR5K_TXCFG,		AR5K_DMASIZE_128B },
+ 	{ AR5K_RXCFG,		AR5K_DMASIZE_128B },
++#else
++	/* WAR for AR71xx PCI bug */
++	{ AR5K_TXCFG,		AR5K_DMASIZE_128B },
++	{ AR5K_RXCFG,		AR5K_DMASIZE_4B },
++#endif
+ 	{ AR5K_CFG,		AR5K_INIT_CFG },
+ 	{ AR5K_TOPS,		8 },
+ 	{ AR5K_RXNOFRM,		8 },
+--- a/drivers/net/wireless/ath/ath5k/dma.c
++++ b/drivers/net/wireless/ath/ath5k/dma.c
+@@ -869,10 +869,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah)
+ 	 * guess we can tweak it and see how it goes ;-)
+ 	 */
+ 	if (ah->ah_version != AR5K_AR5210) {
++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
+ 		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+ 			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+ 		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+ 			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
++#else
++		/* WAR for AR71xx PCI bug */
++		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
++			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
++		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
++			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B);
++#endif
+ 	}
+ 
+ 	/* Pre-enable interrupts on 5211/5212*/
diff --git a/package/kernel/mac80211/patches/210-ap_scan.patch b/package/kernel/mac80211/patches/210-ap_scan.patch
new file mode 100644
index 0000000000..94f5f397c9
--- /dev/null
+++ b/package/kernel/mac80211/patches/210-ap_scan.patch
@@ -0,0 +1,11 @@
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2175,7 +2175,7 @@ static int ieee80211_scan(struct wiphy *
+ 		 * the  frames sent while scanning on other channel will be
+ 		 * lost)
+ 		 */
+-		if (sdata->u.ap.beacon &&
++		if (0 && sdata->u.ap.beacon &&
+ 		    (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
+ 		     !(req->flags & NL80211_SCAN_FLAG_AP)))
+ 			return -EOPNOTSUPP;
diff --git a/package/kernel/mac80211/patches/300-ath9k-Switch-to-using-mac80211-intermediate-software.patch b/package/kernel/mac80211/patches/300-ath9k-Switch-to-using-mac80211-intermediate-software.patch
new file mode 100644
index 0000000000..57917c5b45
--- /dev/null
+++ b/package/kernel/mac80211/patches/300-ath9k-Switch-to-using-mac80211-intermediate-software.patch
@@ -0,0 +1,953 @@
+From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
+Date: Fri, 2 Sep 2016 16:00:30 +0200
+Subject: [PATCH] ath9k: Switch to using mac80211 intermediate software
+ queues.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This switches ath9k over to using the mac80211 intermediate software
+queueing mechanism for data packets. It removes the queueing inside the
+driver, except for the retry queue, and instead pulls from mac80211 when
+a packet is needed. The retry queue is used to store a packet that was
+pulled but can't be sent immediately.
+
+The old code path in ath_tx_start that would queue packets has been
+removed completely, as has the qlen limit tunables (since there's no
+longer a queue in the driver to limit).
+
+Based on Tim's original patch set, but reworked quite thoroughly.
+
+Cc: Tim Shepard <shep@alum.mit.edu>
+Cc: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *
+ #define ATH_RXBUF               512
+ #define ATH_TXBUF               512
+ #define ATH_TXBUF_RESERVE       5
+-#define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
+ #define ATH_TXMAXTRY            13
+ #define ATH_MAX_SW_RETRIES      30
+ 
+@@ -145,7 +144,7 @@ int ath_descdma_setup(struct ath_softc *
+ #define BAW_WITHIN(_start, _bawsz, _seqno) \
+ 	((((_seqno) - (_start)) & 4095) < (_bawsz))
+ 
+-#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
++#define ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno)
+ 
+ #define IS_HT_RATE(rate)   (rate & 0x80)
+ #define IS_CCK_RATE(rate)  ((rate >= 0x18) && (rate <= 0x1e))
+@@ -164,7 +163,6 @@ struct ath_txq {
+ 	spinlock_t axq_lock;
+ 	u32 axq_depth;
+ 	u32 axq_ampdu_depth;
+-	bool stopped;
+ 	bool axq_tx_inprogress;
+ 	struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
+ 	u8 txq_headidx;
+@@ -232,7 +230,6 @@ struct ath_buf {
+ 
+ struct ath_atx_tid {
+ 	struct list_head list;
+-	struct sk_buff_head buf_q;
+ 	struct sk_buff_head retry_q;
+ 	struct ath_node *an;
+ 	struct ath_txq *txq;
+@@ -247,13 +244,13 @@ struct ath_atx_tid {
+ 	s8 bar_index;
+ 	bool active;
+ 	bool clear_ps_filter;
++	bool has_queued;
+ };
+ 
+ struct ath_node {
+ 	struct ath_softc *sc;
+ 	struct ieee80211_sta *sta; /* station struct we're part of */
+ 	struct ieee80211_vif *vif; /* interface with which we're associated */
+-	struct ath_atx_tid tid[IEEE80211_NUM_TIDS];
+ 
+ 	u16 maxampdu;
+ 	u8 mpdudensity;
+@@ -276,7 +273,6 @@ struct ath_tx_control {
+ 	struct ath_node *an;
+ 	struct ieee80211_sta *sta;
+ 	u8 paprd;
+-	bool force_channel;
+ };
+ 
+ 
+@@ -293,7 +289,6 @@ struct ath_tx {
+ 	struct ath_descdma txdma;
+ 	struct ath_txq *txq_map[IEEE80211_NUM_ACS];
+ 	struct ath_txq *uapsdq;
+-	u32 txq_max_pending[IEEE80211_NUM_ACS];
+ 	u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
+ };
+ 
+@@ -421,6 +416,22 @@ struct ath_offchannel {
+ 	int duration;
+ };
+ 
++static inline struct ath_atx_tid *
++ath_node_to_tid(struct ath_node *an, u8 tidno)
++{
++	struct ieee80211_sta *sta = an->sta;
++	struct ieee80211_vif *vif = an->vif;
++	struct ieee80211_txq *txq;
++
++	BUG_ON(!vif);
++	if (sta)
++		txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)];
++	else
++		txq = vif->txq;
++
++	return (struct ath_atx_tid *) txq->drv_priv;
++}
++
+ #define case_rtn_string(val) case val: return #val
+ 
+ #define ath_for_each_chanctx(_sc, _ctx)                             \
+@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_soft
+ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ 		      u16 tid, u16 *ssn);
+ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+ 
+ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
+ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
+@@ -585,6 +595,7 @@ void ath9k_release_buffered_frames(struc
+ 				   u16 tids, int nframes,
+ 				   enum ieee80211_frame_release_type reason,
+ 				   bool more_data);
++void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue);
+ 
+ /********/
+ /* VIFs */
+--- a/drivers/net/wireless/ath/ath9k/channel.c
++++ b/drivers/net/wireless/ath/ath9k/channel.c
+@@ -1010,7 +1010,6 @@ static void ath_scan_send_probe(struct a
+ 		goto error;
+ 
+ 	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+-	txctl.force_channel = true;
+ 	if (ath_tx_start(sc->hw, skb, &txctl))
+ 		goto error;
+ 
+@@ -1133,7 +1132,6 @@ ath_chanctx_send_vif_ps_frame(struct ath
+ 	memset(&txctl, 0, sizeof(txctl));
+ 	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+ 	txctl.sta = sta;
+-	txctl.force_channel = true;
+ 	if (ath_tx_start(sc->hw, skb, &txctl)) {
+ 		ieee80211_free_txskb(sc->hw, skb);
+ 		return false;
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_fil
+ 	PR("MPDUs XRetried:  ", xretries);
+ 	PR("Aggregates:      ", a_aggr);
+ 	PR("AMPDUs Queued HW:", a_queued_hw);
+-	PR("AMPDUs Queued SW:", a_queued_sw);
+ 	PR("AMPDUs Completed:", a_completed);
+ 	PR("AMPDUs Retried:  ", a_retries);
+ 	PR("AMPDUs XRetried: ", a_xretries);
+@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc
+ 	seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
+ 	seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
+ 	seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
+-	seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
+-	seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
++	seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
+ 
+ 	ath_txq_unlock(sc, txq);
+ }
+@@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[]
+ 	AMKSTR(d_tx_mpdu_xretries),
+ 	AMKSTR(d_tx_aggregates),
+ 	AMKSTR(d_tx_ampdus_queued_hw),
+-	AMKSTR(d_tx_ampdus_queued_sw),
+ 	AMKSTR(d_tx_ampdus_completed),
+ 	AMKSTR(d_tx_ampdu_retries),
+ 	AMKSTR(d_tx_ampdu_xretries),
+@@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211
+ 	AWDATA(xretries);
+ 	AWDATA(a_aggr);
+ 	AWDATA(a_queued_hw);
+-	AWDATA(a_queued_sw);
+ 	AWDATA(a_completed);
+ 	AWDATA(a_retries);
+ 	AWDATA(a_xretries);
+@@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 				    read_file_xmit);
+ 	debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
+ 				    read_file_queues);
+-	debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+-			   &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
+-	debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+-			   &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
+-	debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+-			   &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
+-	debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+-			   &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
+ 	debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
+ 				    read_file_misc);
+ 	debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
+  * @completed: Total MPDUs (non-aggr) completed
+  * @a_aggr: Total no. of aggregates queued
+  * @a_queued_hw: Total AMPDUs queued to hardware
+- * @a_queued_sw: Total AMPDUs queued to software queues
+  * @a_completed: Total AMPDUs completed
+  * @a_retries: No. of AMPDUs retried (SW)
+  * @a_xretries: No. of AMPDUs dropped due to xretries
+@@ -174,7 +173,6 @@ struct ath_tx_stats {
+ 	u32 xretries;
+ 	u32 a_aggr;
+ 	u32 a_queued_hw;
+-	u32 a_queued_sw;
+ 	u32 a_completed;
+ 	u32 a_retries;
+ 	u32 a_xretries;
+--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
++++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
+@@ -52,8 +52,8 @@ static ssize_t read_file_node_aggr(struc
+ 			 "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
+ 			 "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
+ 
+-	for (tidno = 0, tid = &an->tid[tidno];
+-	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
++	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
++		tid = ath_node_to_tid(an, tidno);
+ 		txq = tid->txq;
+ 		ath_txq_lock(sc, txq);
+ 		if (tid->active) {
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_
+ 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ 		sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
+ 		sc->tx.txq_map[i]->mac80211_qnum = i;
+-		sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
+ 	}
+ 	return 0;
+ }
+@@ -877,6 +876,7 @@ static void ath9k_set_hw_capab(struct at
+ 	hw->max_rate_tries = 10;
+ 	hw->sta_data_size = sizeof(struct ath_node);
+ 	hw->vif_data_size = sizeof(struct ath_vif);
++	hw->txq_data_size = sizeof(struct ath_atx_tid);
+ 	hw->extra_tx_headroom = 4;
+ 
+ 	hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1;
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1902,9 +1902,11 @@ static int ath9k_ampdu_action(struct iee
+ 	bool flush = false;
+ 	int ret = 0;
+ 	struct ieee80211_sta *sta = params->sta;
++	struct ath_node *an = (struct ath_node *)sta->drv_priv;
+ 	enum ieee80211_ampdu_mlme_action action = params->action;
+ 	u16 tid = params->tid;
+ 	u16 *ssn = &params->ssn;
++	struct ath_atx_tid *atid;
+ 
+ 	mutex_lock(&sc->mutex);
+ 
+@@ -1937,9 +1939,9 @@ static int ath9k_ampdu_action(struct iee
+ 		ath9k_ps_restore(sc);
+ 		break;
+ 	case IEEE80211_AMPDU_TX_OPERATIONAL:
+-		ath9k_ps_wakeup(sc);
+-		ath_tx_aggr_resume(sc, sta, tid);
+-		ath9k_ps_restore(sc);
++		atid = ath_node_to_tid(an, tid);
++		atid->baw_size = IEEE80211_MIN_AMPDU_BUF <<
++			        sta->ht_cap.ampdu_factor;
+ 		break;
+ 	default:
+ 		ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
+@@ -2701,4 +2703,5 @@ struct ieee80211_ops ath9k_ops = {
+ 	.sw_scan_start	    = ath9k_sw_scan_start,
+ 	.sw_scan_complete   = ath9k_sw_scan_complete,
+ 	.get_txpower        = ath9k_get_txpower,
++	.wake_tx_queue      = ath9k_wake_tx_queue,
+ };
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -67,6 +67,8 @@ static struct ath_buf *ath_tx_setup_buff
+ 					   struct ath_txq *txq,
+ 					   struct ath_atx_tid *tid,
+ 					   struct sk_buff *skb);
++static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
++			  struct ath_tx_control *txctl);
+ 
+ enum {
+ 	MCS_HT20,
+@@ -137,6 +139,26 @@ static void ath_tx_queue_tid(struct ath_
+ 		list_add_tail(&tid->list, list);
+ }
+ 
++void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
++{
++	struct ath_softc *sc = hw->priv;
++	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++	struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
++	struct ath_txq *txq = tid->txq;
++
++	ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
++		queue->sta ? queue->sta->addr : queue->vif->addr,
++		tid->tidno);
++
++	ath_txq_lock(sc, txq);
++
++	tid->has_queued = true;
++	ath_tx_queue_tid(sc, txq, tid);
++	ath_txq_schedule(sc, txq);
++
++	ath_txq_unlock(sc, txq);
++}
++
+ static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
+ {
+ 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+@@ -164,7 +186,6 @@ static void ath_set_rates(struct ieee802
+ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+ 			     struct sk_buff *skb)
+ {
+-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct ath_frame_info *fi = get_frame_info(skb);
+ 	int q = fi->txq;
+ 
+@@ -175,14 +196,6 @@ static void ath_txq_skb_done(struct ath_
+ 	if (WARN_ON(--txq->pending_frames < 0))
+ 		txq->pending_frames = 0;
+ 
+-	if (txq->stopped &&
+-	    txq->pending_frames < sc->tx.txq_max_pending[q]) {
+-		if (ath9k_is_chanctx_enabled())
+-			ieee80211_wake_queue(sc->hw, info->hw_queue);
+-		else
+-			ieee80211_wake_queue(sc->hw, q);
+-		txq->stopped = false;
+-	}
+ }
+ 
+ static struct ath_atx_tid *
+@@ -192,9 +205,48 @@ ath_get_skb_tid(struct ath_softc *sc, st
+ 	return ATH_AN_2_TID(an, tidno);
+ }
+ 
++static struct sk_buff *
++ath_tid_pull(struct ath_atx_tid *tid)
++{
++	struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv);
++	struct ath_softc *sc = tid->an->sc;
++	struct ieee80211_hw *hw = sc->hw;
++	struct ath_tx_control txctl = {
++		.txq = tid->txq,
++		.sta = tid->an->sta,
++	};
++	struct sk_buff *skb;
++	struct ath_frame_info *fi;
++	int q;
++
++	if (!tid->has_queued)
++		return NULL;
++
++	skb = ieee80211_tx_dequeue(hw, txq);
++	if (!skb) {
++		tid->has_queued = false;
++		return NULL;
++	}
++
++	if (ath_tx_prepare(hw, skb, &txctl)) {
++		ieee80211_free_txskb(hw, skb);
++		return NULL;
++	}
++
++	q = skb_get_queue_mapping(skb);
++	if (tid->txq == sc->tx.txq_map[q]) {
++		fi = get_frame_info(skb);
++		fi->txq = q;
++		++tid->txq->pending_frames;
++	}
++
++	return skb;
++ }
++
++
+ static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
+ {
+-	return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
++	return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
+ }
+ 
+ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
+@@ -203,46 +255,11 @@ static struct sk_buff *ath_tid_dequeue(s
+ 
+ 	skb = __skb_dequeue(&tid->retry_q);
+ 	if (!skb)
+-		skb = __skb_dequeue(&tid->buf_q);
++		skb = ath_tid_pull(tid);
+ 
+ 	return skb;
+ }
+ 
+-/*
+- * ath_tx_tid_change_state:
+- * - clears a-mpdu flag of previous session
+- * - force sequence number allocation to fix next BlockAck Window
+- */
+-static void
+-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
+-{
+-	struct ath_txq *txq = tid->txq;
+-	struct ieee80211_tx_info *tx_info;
+-	struct sk_buff *skb, *tskb;
+-	struct ath_buf *bf;
+-	struct ath_frame_info *fi;
+-
+-	skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
+-		fi = get_frame_info(skb);
+-		bf = fi->bf;
+-
+-		tx_info = IEEE80211_SKB_CB(skb);
+-		tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+-
+-		if (bf)
+-			continue;
+-
+-		bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+-		if (!bf) {
+-			__skb_unlink(skb, &tid->buf_q);
+-			ath_txq_skb_done(sc, txq, skb);
+-			ieee80211_free_txskb(sc->hw, skb);
+-			continue;
+-		}
+-	}
+-
+-}
+-
+ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+ {
+ 	struct ath_txq *txq = tid->txq;
+@@ -883,20 +900,16 @@ static int ath_compute_num_delims(struct
+ 
+ static struct ath_buf *
+ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
+-			struct ath_atx_tid *tid, struct sk_buff_head **q)
++			struct ath_atx_tid *tid)
+ {
+ 	struct ieee80211_tx_info *tx_info;
+ 	struct ath_frame_info *fi;
+-	struct sk_buff *skb;
++	struct sk_buff *skb, *first_skb = NULL;
+ 	struct ath_buf *bf;
+ 	u16 seqno;
+ 
+ 	while (1) {
+-		*q = &tid->retry_q;
+-		if (skb_queue_empty(*q))
+-			*q = &tid->buf_q;
+-
+-		skb = skb_peek(*q);
++		skb = ath_tid_dequeue(tid);
+ 		if (!skb)
+ 			break;
+ 
+@@ -908,7 +921,6 @@ ath_tx_get_tid_subframe(struct ath_softc
+ 			bf->bf_state.stale = false;
+ 
+ 		if (!bf) {
+-			__skb_unlink(skb, *q);
+ 			ath_txq_skb_done(sc, txq, skb);
+ 			ieee80211_free_txskb(sc->hw, skb);
+ 			continue;
+@@ -937,8 +949,20 @@ ath_tx_get_tid_subframe(struct ath_softc
+ 		seqno = bf->bf_state.seqno;
+ 
+ 		/* do not step over block-ack window */
+-		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
++		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
++			__skb_queue_tail(&tid->retry_q, skb);
++
++			/* If there are other skbs in the retry q, they are
++			 * probably within the BAW, so loop immediately to get
++			 * one of them. Otherwise the queue can get stuck. */
++			if (!skb_queue_is_first(&tid->retry_q, skb) &&
++			    !WARN_ON(skb == first_skb)) {
++				if(!first_skb) /* infinite loop prevention */
++					first_skb = skb;
++				continue;
++			}
+ 			break;
++		}
+ 
+ 		if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
+ 			struct ath_tx_status ts = {};
+@@ -946,7 +970,6 @@ ath_tx_get_tid_subframe(struct ath_softc
+ 
+ 			INIT_LIST_HEAD(&bf_head);
+ 			list_add(&bf->list, &bf_head);
+-			__skb_unlink(skb, *q);
+ 			ath_tx_update_baw(sc, tid, seqno);
+ 			ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
+ 			continue;
+@@ -958,11 +981,10 @@ ath_tx_get_tid_subframe(struct ath_softc
+ 	return NULL;
+ }
+ 
+-static bool
++static int
+ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
+ 		 struct ath_atx_tid *tid, struct list_head *bf_q,
+-		 struct ath_buf *bf_first, struct sk_buff_head *tid_q,
+-		 int *aggr_len)
++		 struct ath_buf *bf_first)
+ {
+ #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
+ 	struct ath_buf *bf = bf_first, *bf_prev = NULL;
+@@ -972,12 +994,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s
+ 	struct ieee80211_tx_info *tx_info;
+ 	struct ath_frame_info *fi;
+ 	struct sk_buff *skb;
+-	bool closed = false;
++
+ 
+ 	bf = bf_first;
+ 	aggr_limit = ath_lookup_rate(sc, bf, tid);
+ 
+-	do {
++	while (bf)
++	{
+ 		skb = bf->bf_mpdu;
+ 		fi = get_frame_info(skb);
+ 
+@@ -986,12 +1009,12 @@ ath_tx_form_aggr(struct ath_softc *sc, s
+ 		if (nframes) {
+ 			if (aggr_limit < al + bpad + al_delta ||
+ 			    ath_lookup_legacy(bf) || nframes >= h_baw)
+-				break;
++				goto stop;
+ 
+ 			tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
+ 			if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
+ 			    !(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
+-				break;
++				goto stop;
+ 		}
+ 
+ 		/* add padding for previous frame to aggregation length */
+@@ -1013,20 +1036,18 @@ ath_tx_form_aggr(struct ath_softc *sc, s
+ 			ath_tx_addto_baw(sc, tid, bf);
+ 		bf->bf_state.ndelim = ndelim;
+ 
+-		__skb_unlink(skb, tid_q);
+ 		list_add_tail(&bf->list, bf_q);
+ 		if (bf_prev)
+ 			bf_prev->bf_next = bf;
+ 
+ 		bf_prev = bf;
+ 
+-		bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+-		if (!bf) {
+-			closed = true;
+-			break;
+-		}
+-	} while (ath_tid_has_buffered(tid));
+-
++		bf = ath_tx_get_tid_subframe(sc, txq, tid);
++	}
++	goto finish;
++stop:
++	__skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
++finish:
+ 	bf = bf_first;
+ 	bf->bf_lastbf = bf_prev;
+ 
+@@ -1037,9 +1058,7 @@ ath_tx_form_aggr(struct ath_softc *sc, s
+ 		TX_STAT_INC(txq->axq_qnum, a_aggr);
+ 	}
+ 
+-	*aggr_len = al;
+-
+-	return closed;
++	return al;
+ #undef PADBYTES
+ }
+ 
+@@ -1416,18 +1435,15 @@ static void ath_tx_fill_desc(struct ath_
+ static void
+ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
+ 		  struct ath_atx_tid *tid, struct list_head *bf_q,
+-		  struct ath_buf *bf_first, struct sk_buff_head *tid_q)
++		  struct ath_buf *bf_first)
+ {
+ 	struct ath_buf *bf = bf_first, *bf_prev = NULL;
+-	struct sk_buff *skb;
+ 	int nframes = 0;
+ 
+ 	do {
+ 		struct ieee80211_tx_info *tx_info;
+-		skb = bf->bf_mpdu;
+ 
+ 		nframes++;
+-		__skb_unlink(skb, tid_q);
+ 		list_add_tail(&bf->list, bf_q);
+ 		if (bf_prev)
+ 			bf_prev->bf_next = bf;
+@@ -1436,13 +1452,15 @@ ath_tx_form_burst(struct ath_softc *sc,
+ 		if (nframes >= 2)
+ 			break;
+ 
+-		bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
++		bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ 		if (!bf)
+ 			break;
+ 
+ 		tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
+-		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
++		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
++			__skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+ 			break;
++		}
+ 
+ 		ath_set_rates(tid->an->vif, tid->an->sta, bf);
+ 	} while (1);
+@@ -1453,34 +1471,33 @@ static bool ath_tx_sched_aggr(struct ath
+ {
+ 	struct ath_buf *bf;
+ 	struct ieee80211_tx_info *tx_info;
+-	struct sk_buff_head *tid_q;
+ 	struct list_head bf_q;
+ 	int aggr_len = 0;
+-	bool aggr, last = true;
++	bool aggr;
+ 
+ 	if (!ath_tid_has_buffered(tid))
+ 		return false;
+ 
+ 	INIT_LIST_HEAD(&bf_q);
+ 
+-	bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
++	bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ 	if (!bf)
+ 		return false;
+ 
+ 	tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
+ 	aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
+ 	if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
+-		(!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
++	    (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
++		__skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+ 		*stop = true;
+ 		return false;
+ 	}
+ 
+ 	ath_set_rates(tid->an->vif, tid->an->sta, bf);
+ 	if (aggr)
+-		last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
+-					tid_q, &aggr_len);
++		aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
+ 	else
+-		ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
++		ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
+ 
+ 	if (list_empty(&bf_q))
+ 		return false;
+@@ -1523,9 +1540,6 @@ int ath_tx_aggr_start(struct ath_softc *
+ 		an->mpdudensity = density;
+ 	}
+ 
+-	/* force sequence number allocation for pending frames */
+-	ath_tx_tid_change_state(sc, txtid);
+-
+ 	txtid->active = true;
+ 	*ssn = txtid->seq_start = txtid->seq_next;
+ 	txtid->bar_index = -1;
+@@ -1550,7 +1564,6 @@ void ath_tx_aggr_stop(struct ath_softc *
+ 	ath_txq_lock(sc, txq);
+ 	txtid->active = false;
+ 	ath_tx_flush_tid(sc, txtid);
+-	ath_tx_tid_change_state(sc, txtid);
+ 	ath_txq_unlock_complete(sc, txq);
+ }
+ 
+@@ -1560,14 +1573,12 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ 	struct ath_atx_tid *tid;
+ 	struct ath_txq *txq;
+-	bool buffered;
+ 	int tidno;
+ 
+ 	ath_dbg(common, XMIT, "%s called\n", __func__);
+ 
+-	for (tidno = 0, tid = &an->tid[tidno];
+-	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+-
++	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
++		tid = ath_node_to_tid(an, tidno);
+ 		txq = tid->txq;
+ 
+ 		ath_txq_lock(sc, txq);
+@@ -1577,13 +1588,12 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ 			continue;
+ 		}
+ 
+-		buffered = ath_tid_has_buffered(tid);
++		if (!skb_queue_empty(&tid->retry_q))
++			ieee80211_sta_set_buffered(sta, tid->tidno, true);
+ 
+ 		list_del_init(&tid->list);
+ 
+ 		ath_txq_unlock(sc, txq);
+-
+-		ieee80211_sta_set_buffered(sta, tidno, buffered);
+ 	}
+ }
+ 
+@@ -1596,49 +1606,20 @@ void ath_tx_aggr_wakeup(struct ath_softc
+ 
+ 	ath_dbg(common, XMIT, "%s called\n", __func__);
+ 
+-	for (tidno = 0, tid = &an->tid[tidno];
+-	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+-
++	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
++		tid = ath_node_to_tid(an, tidno);
+ 		txq = tid->txq;
+ 
+ 		ath_txq_lock(sc, txq);
+ 		tid->clear_ps_filter = true;
+-
+ 		if (ath_tid_has_buffered(tid)) {
+ 			ath_tx_queue_tid(sc, txq, tid);
+ 			ath_txq_schedule(sc, txq);
+ 		}
+-
+ 		ath_txq_unlock_complete(sc, txq);
+ 	}
+ }
+ 
+-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
+-			u16 tidno)
+-{
+-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+-	struct ath_atx_tid *tid;
+-	struct ath_node *an;
+-	struct ath_txq *txq;
+-
+-	ath_dbg(common, XMIT, "%s called\n", __func__);
+-
+-	an = (struct ath_node *)sta->drv_priv;
+-	tid = ATH_AN_2_TID(an, tidno);
+-	txq = tid->txq;
+-
+-	ath_txq_lock(sc, txq);
+-
+-	tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
+-
+-	if (ath_tid_has_buffered(tid)) {
+-		ath_tx_queue_tid(sc, txq, tid);
+-		ath_txq_schedule(sc, txq);
+-	}
+-
+-	ath_txq_unlock_complete(sc, txq);
+-}
+-
+ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
+ 				   struct ieee80211_sta *sta,
+ 				   u16 tids, int nframes,
+@@ -1651,7 +1632,6 @@ void ath9k_release_buffered_frames(struc
+ 	struct ieee80211_tx_info *info;
+ 	struct list_head bf_q;
+ 	struct ath_buf *bf_tail = NULL, *bf;
+-	struct sk_buff_head *tid_q;
+ 	int sent = 0;
+ 	int i;
+ 
+@@ -1666,11 +1646,10 @@ void ath9k_release_buffered_frames(struc
+ 
+ 		ath_txq_lock(sc, tid->txq);
+ 		while (nframes > 0) {
+-			bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
++			bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
+ 			if (!bf)
+ 				break;
+ 
+-			__skb_unlink(bf->bf_mpdu, tid_q);
+ 			list_add_tail(&bf->list, &bf_q);
+ 			ath_set_rates(tid->an->vif, tid->an->sta, bf);
+ 			if (bf_isampdu(bf)) {
+@@ -1685,7 +1664,7 @@ void ath9k_release_buffered_frames(struc
+ 			sent++;
+ 			TX_STAT_INC(txq->axq_qnum, a_queued_hw);
+ 
+-			if (an->sta && !ath_tid_has_buffered(tid))
++			if (an->sta && skb_queue_empty(&tid->retry_q))
+ 				ieee80211_sta_set_buffered(an->sta, i, false);
+ 		}
+ 		ath_txq_unlock_complete(sc, tid->txq);
+@@ -1914,13 +1893,7 @@ bool ath_drain_all_txq(struct ath_softc
+ 		if (!ATH_TXQ_SETUP(sc, i))
+ 			continue;
+ 
+-		/*
+-		 * The caller will resume queues with ieee80211_wake_queues.
+-		 * Mark the queue as not stopped to prevent ath_tx_complete
+-		 * from waking the queue too early.
+-		 */
+ 		txq = &sc->tx.txq[i];
+-		txq->stopped = false;
+ 		ath_draintxq(sc, txq);
+ 	}
+ 
+@@ -2319,16 +2292,14 @@ int ath_tx_start(struct ieee80211_hw *hw
+ 	struct ath_softc *sc = hw->priv;
+ 	struct ath_txq *txq = txctl->txq;
+ 	struct ath_atx_tid *tid = NULL;
++	struct ath_node *an = NULL;
+ 	struct ath_buf *bf;
+-	bool queue, skip_uapsd = false, ps_resp;
++	bool ps_resp;
+ 	int q, ret;
+ 
+ 	if (vif)
+ 		avp = (void *)vif->drv_priv;
+ 
+-	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+-		txctl->force_channel = true;
+-
+ 	ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
+ 
+ 	ret = ath_tx_prepare(hw, skb, txctl);
+@@ -2343,63 +2314,18 @@ int ath_tx_start(struct ieee80211_hw *hw
+ 
+ 	q = skb_get_queue_mapping(skb);
+ 
+-	ath_txq_lock(sc, txq);
+-	if (txq == sc->tx.txq_map[q]) {
+-		fi->txq = q;
+-		if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
+-		    !txq->stopped) {
+-			if (ath9k_is_chanctx_enabled())
+-				ieee80211_stop_queue(sc->hw, info->hw_queue);
+-			else
+-				ieee80211_stop_queue(sc->hw, q);
+-			txq->stopped = true;
+-		}
+-	}
+-
+-	queue = ieee80211_is_data_present(hdr->frame_control);
+-
+-	/* If chanctx, queue all null frames while NOA could be there */
+-	if (ath9k_is_chanctx_enabled() &&
+-	    ieee80211_is_nullfunc(hdr->frame_control) &&
+-	    !txctl->force_channel)
+-		queue = true;
+-
+-	/* Force queueing of all frames that belong to a virtual interface on
+-	 * a different channel context, to ensure that they are sent on the
+-	 * correct channel.
+-	 */
+-	if (((avp && avp->chanctx != sc->cur_chan) ||
+-	     sc->cur_chan->stopped) && !txctl->force_channel) {
+-		if (!txctl->an)
+-			txctl->an = &avp->mcast_node;
+-		queue = true;
+-		skip_uapsd = true;
+-	}
+-
+-	if (txctl->an && queue)
+-		tid = ath_get_skb_tid(sc, txctl->an, skb);
+-
+-	if (!skip_uapsd && ps_resp) {
+-		ath_txq_unlock(sc, txq);
++	if (ps_resp)
+ 		txq = sc->tx.uapsdq;
+-		ath_txq_lock(sc, txq);
+-	} else if (txctl->an && queue) {
+-		WARN_ON(tid->txq != txctl->txq);
+-
+-		if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+-			tid->clear_ps_filter = true;
+ 
+-		/*
+-		 * Add this frame to software queue for scheduling later
+-		 * for aggregation.
+-		 */
+-		TX_STAT_INC(txq->axq_qnum, a_queued_sw);
+-		__skb_queue_tail(&tid->buf_q, skb);
+-		if (!txctl->an->sleeping)
+-			ath_tx_queue_tid(sc, txq, tid);
++	if (txctl->sta) {
++		an = (struct ath_node *) sta->drv_priv;
++		tid = ath_get_skb_tid(sc, an, skb);
++	}
+ 
+-		ath_txq_schedule(sc, txq);
+-		goto out;
++	ath_txq_lock(sc, txq);
++	if (txq == sc->tx.txq_map[q]) {
++		fi->txq = q;
++		++txq->pending_frames;
+ 	}
+ 
+ 	bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+@@ -2892,9 +2818,8 @@ void ath_tx_node_init(struct ath_softc *
+ 	struct ath_atx_tid *tid;
+ 	int tidno, acno;
+ 
+-	for (tidno = 0, tid = &an->tid[tidno];
+-	     tidno < IEEE80211_NUM_TIDS;
+-	     tidno++, tid++) {
++	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
++		tid = ath_node_to_tid(an, tidno);
+ 		tid->an        = an;
+ 		tid->tidno     = tidno;
+ 		tid->seq_start = tid->seq_next = 0;
+@@ -2902,11 +2827,14 @@ void ath_tx_node_init(struct ath_softc *
+ 		tid->baw_head  = tid->baw_tail = 0;
+ 		tid->active	   = false;
+ 		tid->clear_ps_filter = true;
+-		__skb_queue_head_init(&tid->buf_q);
++		tid->has_queued  = false;
+ 		__skb_queue_head_init(&tid->retry_q);
+ 		INIT_LIST_HEAD(&tid->list);
+ 		acno = TID_TO_WME_AC(tidno);
+ 		tid->txq = sc->tx.txq_map[acno];
++
++		if (!an->sta)
++			break; /* just one multicast ath_atx_tid */
+ 	}
+ }
+ 
+@@ -2916,9 +2844,8 @@ void ath_tx_node_cleanup(struct ath_soft
+ 	struct ath_txq *txq;
+ 	int tidno;
+ 
+-	for (tidno = 0, tid = &an->tid[tidno];
+-	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+-
++	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
++		tid = ath_node_to_tid(an, tidno);
+ 		txq = tid->txq;
+ 
+ 		ath_txq_lock(sc, txq);
+@@ -2930,6 +2857,9 @@ void ath_tx_node_cleanup(struct ath_soft
+ 		tid->active = false;
+ 
+ 		ath_txq_unlock(sc, txq);
++
++		if (!an->sta)
++			break; /* just one multicast ath_atx_tid */
+ 	}
+ }
+ 
diff --git a/package/kernel/mac80211/patches/301-ath9k-force-rx_clear-when-disabling-rx.patch b/package/kernel/mac80211/patches/301-ath9k-force-rx_clear-when-disabling-rx.patch
new file mode 100644
index 0000000000..098bda7e93
--- /dev/null
+++ b/package/kernel/mac80211/patches/301-ath9k-force-rx_clear-when-disabling-rx.patch
@@ -0,0 +1,35 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sun, 7 Jun 2015 13:53:35 +0200
+Subject: [PATCH] ath9k: force rx_clear when disabling rx
+
+This makes stopping Rx more reliable and should reduce the frequency of
+Rx related DMA stop warnings. Don't use rx_clear in TX99 mode.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -677,13 +677,18 @@ void ath9k_hw_startpcureceive(struct ath
+ 
+ 	ath9k_ani_reset(ah, is_scanning);
+ 
+-	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
++	REG_CLR_BIT(ah, AR_DIAG_SW,
++		    AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR);
+ }
+ EXPORT_SYMBOL(ath9k_hw_startpcureceive);
+ 
+ void ath9k_hw_abortpcurecv(struct ath_hw *ah)
+ {
+-	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
++	u32 reg = AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT;
++
++	if (!config_enabled(CPTCFG_ATH9K_TX99))
++		reg |= AR_DIAG_FORCE_RX_CLEAR;
++	REG_SET_BIT(ah, AR_DIAG_SW, reg);
+ 
+ 	ath9k_hw_disable_mib_counters(ah);
+ }
diff --git a/package/kernel/mac80211/patches/302-ath9k-limit-retries-for-powersave-response-frames.patch b/package/kernel/mac80211/patches/302-ath9k-limit-retries-for-powersave-response-frames.patch
new file mode 100644
index 0000000000..8c19ea22f4
--- /dev/null
+++ b/package/kernel/mac80211/patches/302-ath9k-limit-retries-for-powersave-response-frames.patch
@@ -0,0 +1,96 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Thu, 2 Jul 2015 15:20:56 +0200
+Subject: [PATCH] ath9k: limit retries for powersave response frames
+
+In some cases, the channel might be busy enough that an ath9k AP's
+response to PS-Poll frames might be too slow and the station has already
+gone to sleep. To avoid wasting too much airtime on this, limit the
+number of retries on such frames and ensure that no sample rate gets
+used.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -177,10 +177,25 @@ static void ath_send_bar(struct ath_atx_
+ }
+ 
+ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+-			  struct ath_buf *bf)
++			  struct ath_buf *bf, bool ps)
+ {
++	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
++
++	if (ps) {
++		/* Clear the first rate to avoid using a sample rate for PS frames */
++		info->control.rates[0].idx = -1;
++		info->control.rates[0].count = 0;
++	}
++
+ 	ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
+ 			       ARRAY_SIZE(bf->rates));
++	if (!ps)
++		return;
++
++	if (bf->rates[0].count > 2)
++		bf->rates[0].count = 2;
++
++	bf->rates[1].idx = -1;
+ }
+ 
+ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+@@ -1462,7 +1477,7 @@ ath_tx_form_burst(struct ath_softc *sc,
+ 			break;
+ 		}
+ 
+-		ath_set_rates(tid->an->vif, tid->an->sta, bf);
++		ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
+ 	} while (1);
+ }
+ 
+@@ -1493,7 +1508,7 @@ static bool ath_tx_sched_aggr(struct ath
+ 		return false;
+ 	}
+ 
+-	ath_set_rates(tid->an->vif, tid->an->sta, bf);
++	ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
+ 	if (aggr)
+ 		aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
+ 	else
+@@ -1651,7 +1666,7 @@ void ath9k_release_buffered_frames(struc
+ 				break;
+ 
+ 			list_add_tail(&bf->list, &bf_q);
+-			ath_set_rates(tid->an->vif, tid->an->sta, bf);
++			ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
+ 			if (bf_isampdu(bf)) {
+ 				ath_tx_addto_baw(sc, tid, bf);
+ 				bf->bf_state.bf_type &= ~BUF_AGGR;
+@@ -2343,7 +2358,7 @@ int ath_tx_start(struct ieee80211_hw *hw
+ 	if (txctl->paprd)
+ 		bf->bf_state.bfs_paprd_timestamp = jiffies;
+ 
+-	ath_set_rates(vif, sta, bf);
++	ath_set_rates(vif, sta, bf, ps_resp);
+ 	ath_tx_send_normal(sc, txq, tid, skb);
+ 
+ out:
+@@ -2382,7 +2397,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
+ 			break;
+ 
+ 		bf->bf_lastbf = bf;
+-		ath_set_rates(vif, NULL, bf);
++		ath_set_rates(vif, NULL, bf, false);
+ 		ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
+ 		duration += info.rates[0].PktDuration;
+ 		if (bf_tail)
+@@ -2898,7 +2913,7 @@ int ath9k_tx99_send(struct ath_softc *sc
+ 		return -EINVAL;
+ 	}
+ 
+-	ath_set_rates(sc->tx99_vif, NULL, bf);
++	ath_set_rates(sc->tx99_vif, NULL, bf, false);
+ 
+ 	ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
+ 	ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
diff --git a/package/kernel/mac80211/patches/303-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch b/package/kernel/mac80211/patches/303-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch
new file mode 100644
index 0000000000..57f45c1c93
--- /dev/null
+++ b/package/kernel/mac80211/patches/303-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 14:51:02 +0200
+Subject: [PATCH] Revert "ath9k: interpret requested txpower in EIRP
+ domain"
+
+This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411.
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2910,7 +2910,8 @@ void ath9k_hw_apply_txpower(struct ath_h
+ {
+ 	struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+ 	struct ieee80211_channel *channel;
+-	int chan_pwr, new_pwr;
++	int chan_pwr, new_pwr, max_gain;
++	int ant_gain, ant_reduction = 0;
+ 
+ 	if (!chan)
+ 		return;
+@@ -2918,10 +2919,15 @@ void ath9k_hw_apply_txpower(struct ath_h
+ 	channel = chan->chan;
+ 	chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
+ 	new_pwr = min_t(int, chan_pwr, reg->power_limit);
++	max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
++
++	ant_gain = get_antenna_gain(ah, chan);
++	if (ant_gain > max_gain)
++		ant_reduction = ant_gain - max_gain;
+ 
+ 	ah->eep_ops->set_txpower(ah, chan,
+ 				 ath9k_regd_get_ctl(reg, chan),
+-				 get_antenna_gain(ah, chan), new_pwr, test);
++				 ant_reduction, new_pwr, test);
+ }
+ 
+ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
diff --git a/package/kernel/mac80211/patches/304-mac80211-add-hdrlen-to-ieee80211_tx_data.patch b/package/kernel/mac80211/patches/304-mac80211-add-hdrlen-to-ieee80211_tx_data.patch
new file mode 100644
index 0000000000..72e81ee1b0
--- /dev/null
+++ b/package/kernel/mac80211/patches/304-mac80211-add-hdrlen-to-ieee80211_tx_data.patch
@@ -0,0 +1,219 @@
+From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+Date: Fri, 19 Feb 2016 11:01:49 +0100
+Subject: [PATCH] mac80211: add hdrlen to ieee80211_tx_data
+
+Add hdrlen to ieee80211_tx_data and use this
+when wep/ccmd/tkip. This is preparation for
+aligned4 code.
+
+Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -175,6 +175,7 @@ struct ieee80211_tx_data {
+ 	struct ieee80211_tx_rate rate;
+ 
+ 	unsigned int flags;
++	unsigned int hdrlen;
+ };
+ 
+ 
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -955,7 +955,7 @@ ieee80211_tx_h_fragment(struct ieee80211
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct ieee80211_hdr *hdr = (void *)skb->data;
+ 	int frag_threshold = tx->local->hw.wiphy->frag_threshold;
+-	int hdrlen;
++	int hdrlen = tx->hdrlen;
+ 	int fragnum;
+ 
+ 	/* no matter what happens, tx->skb moves to tx->skbs */
+@@ -976,8 +976,6 @@ ieee80211_tx_h_fragment(struct ieee80211
+ 	if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
+ 		return TX_DROP;
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+-
+ 	/* internal error, why isn't DONTFRAG set? */
+ 	if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
+ 		return TX_DROP;
+@@ -1209,6 +1207,8 @@ ieee80211_tx_prepare(struct ieee80211_su
+ 
+ 	hdr = (struct ieee80211_hdr *) skb->data;
+ 
++	tx->hdrlen = ieee80211_hdrlen(hdr->frame_control);
++
+ 	if (likely(sta)) {
+ 		if (!IS_ERR(sta))
+ 			tx->sta = sta;
+@@ -3414,6 +3414,7 @@ begin:
+ 	tx.local = local;
+ 	tx.skb = skb;
+ 	tx.sdata = vif_to_sdata(info->control.vif);
++	tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control);
+ 
+ 	if (txq->sta)
+ 		tx.sta = container_of(txq->sta, struct sta_info, sta);
+@@ -3584,6 +3585,7 @@ ieee80211_build_data_template(struct iee
+ 	hdr = (void *)skb->data;
+ 	tx.sta = sta_info_get(sdata, hdr->addr1);
+ 	tx.skb = skb;
++	tx.hdrlen = ieee80211_padded_hdrlen(&tx.local->hw, hdr->frame_control);
+ 
+ 	if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) {
+ 		rcu_read_unlock();
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1227,6 +1227,7 @@ void ieee80211_send_auth(struct ieee8021
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct sk_buff *skb;
+ 	struct ieee80211_mgmt *mgmt;
++	unsigned int hdrlen;
+ 	int err;
+ 
+ 	/* 24 + 6 = header + auth_algo + auth_transaction + status_code */
+@@ -1251,8 +1252,10 @@ void ieee80211_send_auth(struct ieee8021
+ 		memcpy(skb_put(skb, extra_len), extra, extra_len);
+ 
+ 	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
++		hdrlen = ieee80211_hdrlen(mgmt->frame_control);
+ 		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+-		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
++		err = ieee80211_wep_encrypt(local, skb, hdrlen, key,
++					    key_len, key_idx);
+ 		WARN_ON(err);
+ 	}
+ 
+--- a/net/mac80211/wep.c
++++ b/net/mac80211/wep.c
+@@ -89,11 +89,11 @@ static void ieee80211_wep_get_iv(struct
+ 
+ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
+ 				struct sk_buff *skb,
++				unsigned int hdrlen,
+ 				int keylen, int keyidx)
+ {
+ 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-	unsigned int hdrlen;
+ 	u8 *newhdr;
+ 
+ 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+@@ -101,7 +101,6 @@ static u8 *ieee80211_wep_add_iv(struct i
+ 	if (WARN_ON(skb_headroom(skb) < IEEE80211_WEP_IV_LEN))
+ 		return NULL;
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ 	newhdr = skb_push(skb, IEEE80211_WEP_IV_LEN);
+ 	memmove(newhdr, newhdr + IEEE80211_WEP_IV_LEN, hdrlen);
+ 
+@@ -160,6 +159,7 @@ int ieee80211_wep_encrypt_data(struct cr
+  */
+ int ieee80211_wep_encrypt(struct ieee80211_local *local,
+ 			  struct sk_buff *skb,
++			  unsigned int hdrlen,
+ 			  const u8 *key, int keylen, int keyidx)
+ {
+ 	u8 *iv;
+@@ -169,7 +169,7 @@ int ieee80211_wep_encrypt(struct ieee802
+ 	if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN))
+ 		return -1;
+ 
+-	iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
++	iv = ieee80211_wep_add_iv(local, skb, hdrlen, keylen, keyidx);
+ 	if (!iv)
+ 		return -1;
+ 
+@@ -306,13 +306,14 @@ static int wep_encrypt_skb(struct ieee80
+ 	struct ieee80211_key_conf *hw_key = info->control.hw_key;
+ 
+ 	if (!hw_key) {
+-		if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
++		if (ieee80211_wep_encrypt(tx->local, skb, tx->hdrlen,
++					  tx->key->conf.key,
+ 					  tx->key->conf.keylen,
+ 					  tx->key->conf.keyidx))
+ 			return -1;
+ 	} else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+ 		   (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
+-		if (!ieee80211_wep_add_iv(tx->local, skb,
++		if (!ieee80211_wep_add_iv(tx->local, skb, tx->hdrlen,
+ 					  tx->key->conf.keylen,
+ 					  tx->key->conf.keyidx))
+ 			return -1;
+--- a/net/mac80211/wep.h
++++ b/net/mac80211/wep.h
+@@ -22,6 +22,7 @@ int ieee80211_wep_encrypt_data(struct cr
+ 				size_t klen, u8 *data, size_t data_len);
+ int ieee80211_wep_encrypt(struct ieee80211_local *local,
+ 			  struct sk_buff *skb,
++			  unsigned int hdrlen,
+ 			  const u8 *key, int keylen, int keyidx);
+ int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
+ 			       size_t klen, u8 *data, size_t data_len);
+--- a/net/mac80211/wpa.c
++++ b/net/mac80211/wpa.c
+@@ -43,7 +43,7 @@ ieee80211_tx_h_michael_mic_add(struct ie
+ 	    skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
+ 		return TX_CONTINUE;
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
++	hdrlen = tx->hdrlen;
+ 	if (skb->len < hdrlen)
+ 		return TX_DROP;
+ 
+@@ -186,7 +186,6 @@ mic_fail_no_key:
+ 
+ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
+ {
+-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ 	struct ieee80211_key *key = tx->key;
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	unsigned int hdrlen;
+@@ -201,7 +200,7 @@ static int tkip_encrypt_skb(struct ieee8
+ 		return 0;
+ 	}
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
++	hdrlen = tx->hdrlen;
+ 	len = skb->len - hdrlen;
+ 
+ 	if (info->control.hw_key)
+@@ -418,7 +417,7 @@ static int ccmp_encrypt_skb(struct ieee8
+ 		return 0;
+ 	}
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
++	hdrlen = tx->hdrlen;
+ 	len = skb->len - hdrlen;
+ 
+ 	if (info->control.hw_key)
+@@ -651,7 +650,7 @@ static int gcmp_encrypt_skb(struct ieee8
+ 		return 0;
+ 	}
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
++	hdrlen = tx->hdrlen;
+ 	len = skb->len - hdrlen;
+ 
+ 	if (info->control.hw_key)
+@@ -791,7 +790,6 @@ static ieee80211_tx_result
+ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
+ 			    struct sk_buff *skb)
+ {
+-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ 	struct ieee80211_key *key = tx->key;
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	int hdrlen;
+@@ -807,8 +805,7 @@ ieee80211_crypto_cs_encrypt(struct ieee8
+ 		     pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC)))
+ 		return TX_DROP;
+ 
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+-
++	hdrlen = tx->hdrlen;
+ 	pos = skb_push(skb, iv_len);
+ 	memmove(pos, pos + iv_len, hdrlen);
+ 
diff --git a/package/kernel/mac80211/patches/305-mac80211-add-NEED_ALIGNED4_SKBS-hw-flag.patch b/package/kernel/mac80211/patches/305-mac80211-add-NEED_ALIGNED4_SKBS-hw-flag.patch
new file mode 100644
index 0000000000..704e7f7815
--- /dev/null
+++ b/package/kernel/mac80211/patches/305-mac80211-add-NEED_ALIGNED4_SKBS-hw-flag.patch
@@ -0,0 +1,233 @@
+From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+Date: Fri, 19 Feb 2016 11:01:50 +0100
+Subject: [PATCH] mac80211: add NEED_ALIGNED4_SKBS hw flag
+
+HW/driver should set NEED_ALIGNED4_SKBS flag in case
+require aligned skbs to four-byte boundaries.
+This affect only TX direction.
+
+Padding is added after ieee80211_hdr, before IV/LLC.
+
+Before we have to do memmove(hdrlen) twice in the
+dirver. Once before we pass this to HW and next
+in tx completion (to be sure monitor will report
+this tx frame correctly).
+
+With this patch we can skip this memmove() and save CPU.
+
+Currently this was tested with ath9k, both hw/sw crypt for
+wep/tkip/ccmp.
+
+Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -2025,6 +2025,9 @@ struct ieee80211_txq {
+  *	drivers, mac80211 packet loss mechanism will not be triggered and driver
+  *	is completely depending on firmware event for station kickout.
+  *
++ * @IEEE80211_HW_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
++ *	Padding will be added after ieee80211_hdr, before IV/LLC.
++ *
+  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
+  */
+ enum ieee80211_hw_flags {
+@@ -2066,6 +2069,7 @@ enum ieee80211_hw_flags {
+ 	IEEE80211_HW_TX_AMSDU,
+ 	IEEE80211_HW_TX_FRAG_LIST,
+ 	IEEE80211_HW_REPORTS_LOW_ACK,
++	IEEE80211_HW_NEEDS_ALIGNED4_SKBS,
+ 
+ 	/* keep last, obviously */
+ 	NUM_IEEE80211_HW_FLAGS
+--- a/net/mac80211/debugfs.c
++++ b/net/mac80211/debugfs.c
+@@ -210,6 +210,7 @@ static const char *hw_flag_names[] = {
+ 	FLAG(TX_AMSDU),
+ 	FLAG(TX_FRAG_LIST),
+ 	FLAG(REPORTS_LOW_ACK),
++	FLAG(NEEDS_ALIGNED4_SKBS),
+ #undef FLAG
+ };
+ 
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1529,6 +1529,29 @@ ieee80211_have_rx_timestamp(struct ieee8
+ 	return false;
+ }
+ 
++static inline unsigned int
++ieee80211_hdr_padsize(struct ieee80211_hw *hw, unsigned int hdrlen)
++{
++	/*
++	 * While hdrlen is already aligned to two-byte boundaries,
++	 * simple check with & 2 will return correct padsize.
++	 */
++	if (ieee80211_hw_check(hw, NEEDS_ALIGNED4_SKBS))
++		return hdrlen & 2;
++	return 0;
++}
++
++static inline unsigned int
++ieee80211_padded_hdrlen(struct ieee80211_hw *hw, __le16 fc)
++{
++	unsigned int hdrlen;
++
++	hdrlen = ieee80211_hdrlen(fc);
++	hdrlen += ieee80211_hdr_padsize(hw, hdrlen);
++
++	return hdrlen;
++}
++
+ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
+ 				     struct ieee80211_rx_status *status,
+ 				     unsigned int mpdu_len,
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -282,7 +282,7 @@ struct ieee80211_fast_tx {
+ 	u8 hdr_len;
+ 	u8 sa_offs, da_offs, pn_offs;
+ 	u8 band;
+-	u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
++	u8 hdr[30 + 2 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
+ 	       sizeof(rfc1042_header)] __aligned(2);
+ 
+ 	struct rcu_head rcu_head;
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -689,9 +689,22 @@ void ieee80211_tx_monitor(struct ieee802
+ 	struct sk_buff *skb2;
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct ieee80211_sub_if_data *sdata;
++	struct ieee80211_hdr *hdr = (void *)skb->data;
+ 	struct net_device *prev_dev = NULL;
++	unsigned int hdrlen, padsize;
+ 	int rtap_len;
+ 
++	/* Remove padding if was added */
++	if (ieee80211_hw_check(&local->hw, NEEDS_ALIGNED4_SKBS)) {
++		hdrlen = ieee80211_hdrlen(hdr->frame_control);
++		padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
++
++		if (padsize && skb->len > hdrlen + padsize) {
++			memmove(skb->data + padsize, skb->data, hdrlen);
++			skb_pull(skb, padsize);
++		}
++	}
++
+ 	/* send frame to monitor interfaces now */
+ 	rtap_len = ieee80211_tx_radiotap_len(info);
+ 	if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
+--- a/net/mac80211/tkip.c
++++ b/net/mac80211/tkip.c
+@@ -201,10 +201,12 @@ void ieee80211_get_tkip_p2k(struct ieee8
+ {
+ 	struct ieee80211_key *key = (struct ieee80211_key *)
+ 			container_of(keyconf, struct ieee80211_key, conf);
++	struct ieee80211_hw *hw = &key->local->hw;
+ 	const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
+ 	struct tkip_ctx *ctx = &key->u.tkip.tx;
+ 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+-	const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
++	const u8 *data = (u8 *)hdr + ieee80211_padded_hdrlen(hw,
++							hdr->frame_control);
+ 	u32 iv32 = get_unaligned_le32(&data[4]);
+ 	u16 iv16 = data[2] | (data[0] << 8);
+ 
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1206,8 +1206,7 @@ ieee80211_tx_prepare(struct ieee80211_su
+ 	info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ 
+ 	hdr = (struct ieee80211_hdr *) skb->data;
+-
+-	tx->hdrlen = ieee80211_hdrlen(hdr->frame_control);
++	tx->hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
+ 
+ 	if (likely(sta)) {
+ 		if (!IS_ERR(sta))
+@@ -2158,7 +2157,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
+ 		goto fail;
+ 
+ 	hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
+-	hdrlen = ieee80211_hdrlen(hdr->frame_control);
++	hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
+ 
+ 	if (skb->len < len_rthdr + hdrlen)
+ 		goto fail;
+@@ -2376,7 +2375,7 @@ static struct sk_buff *ieee80211_build_h
+ 	struct ieee80211_chanctx_conf *chanctx_conf;
+ 	struct ieee80211_sub_if_data *ap_sdata;
+ 	enum nl80211_band band;
+-	int ret;
++	int padsize, ret;
+ 
+ 	if (IS_ERR(sta))
+ 		sta = NULL;
+@@ -2596,6 +2595,9 @@ static struct sk_buff *ieee80211_build_h
+ 		hdrlen += 2;
+ 	}
+ 
++	/* Check aligned4 skb required */
++	padsize = ieee80211_hdr_padsize(&sdata->local->hw, hdrlen);
++
+ 	/*
+ 	 * Drop unicast frames to unauthorised stations unless they are
+ 	 * EAPOL frames from the local station.
+@@ -2676,6 +2678,7 @@ static struct sk_buff *ieee80211_build_h
+ 
+ 	skb_pull(skb, skip_header_bytes);
+ 	head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
++	head_need += padsize;
+ 
+ 	/*
+ 	 * So we need to modify the skb header and hence need a copy of
+@@ -2708,6 +2711,9 @@ static struct sk_buff *ieee80211_build_h
+ 		memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
+ #endif
+ 
++	if (padsize)
++		memset(skb_push(skb, padsize), 0, padsize);
++
+ 	if (ieee80211_is_data_qos(fc)) {
+ 		__le16 *qos_control;
+ 
+@@ -2883,6 +2889,9 @@ void ieee80211_check_fast_xmit(struct st
+ 		fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+ 	}
+ 
++	/* Check aligned4 skb required */
++	build.hdr_len += ieee80211_hdr_padsize(&local->hw, build.hdr_len);
++
+ 	/* We store the key here so there's no point in using rcu_dereference()
+ 	 * but that's fine because the code that changes the pointers will call
+ 	 * this function after doing so. For a single CPU that would be enough,
+@@ -3436,7 +3445,7 @@ begin:
+ 
+ 		if (tx.key &&
+ 		    (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+-			pn_offs = ieee80211_hdrlen(hdr->frame_control);
++			pn_offs = tx.hdrlen;
+ 
+ 		ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
+ 					   tx.key, skb);
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1225,6 +1225,7 @@ void ieee80211_send_auth(struct ieee8021
+ 			 u32 tx_flags)
+ {
+ 	struct ieee80211_local *local = sdata->local;
++	struct ieee80211_hw *hw = &local->hw;
+ 	struct sk_buff *skb;
+ 	struct ieee80211_mgmt *mgmt;
+ 	unsigned int hdrlen;
+@@ -1252,7 +1253,7 @@ void ieee80211_send_auth(struct ieee8021
+ 		memcpy(skb_put(skb, extra_len), extra, extra_len);
+ 
+ 	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+-		hdrlen = ieee80211_hdrlen(mgmt->frame_control);
++		hdrlen = ieee80211_padded_hdrlen(hw, mgmt->frame_control);
+ 		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ 		err = ieee80211_wep_encrypt(local, skb, hdrlen, key,
+ 					    key_len, key_idx);
diff --git a/package/kernel/mac80211/patches/306-mac80211-minstrel-Enable-STBC-and-LDPC-for-VHT-Rates.patch b/package/kernel/mac80211/patches/306-mac80211-minstrel-Enable-STBC-and-LDPC-for-VHT-Rates.patch
new file mode 100644
index 0000000000..6e7ecb9c4d
--- /dev/null
+++ b/package/kernel/mac80211/patches/306-mac80211-minstrel-Enable-STBC-and-LDPC-for-VHT-Rates.patch
@@ -0,0 +1,81 @@
+From: Chaitanya T K <chaitanya.mgit@gmail.com>
+Date: Mon, 27 Jun 2016 15:23:26 +0530
+Subject: [PATCH] mac80211: minstrel: Enable STBC and LDPC for VHT Rates
+
+If peer support reception of STBC and LDPC, enable them for better
+performance.
+
+Signed-off-by: Chaitanya TK <chaitanya.mgit@gmail.com>
+---
+
+--- a/include/linux/ieee80211.h
++++ b/include/linux/ieee80211.h
+@@ -1551,6 +1551,7 @@ struct ieee80211_vht_operation {
+ #define IEEE80211_VHT_CAP_RXSTBC_3				0x00000300
+ #define IEEE80211_VHT_CAP_RXSTBC_4				0x00000400
+ #define IEEE80211_VHT_CAP_RXSTBC_MASK				0x00000700
++#define IEEE80211_VHT_CAP_RXSTBC_SHIFT				8
+ #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE			0x00000800
+ #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE			0x00001000
+ #define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT                  13
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -1166,13 +1166,14 @@ minstrel_ht_update_caps(void *priv, stru
+ 	struct minstrel_ht_sta_priv *msp = priv_sta;
+ 	struct minstrel_ht_sta *mi = &msp->ht;
+ 	struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
+-	u16 sta_cap = sta->ht_cap.cap;
++	u16 ht_cap = sta->ht_cap.cap;
+ 	struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+ 	int use_vht;
+ 	int n_supported = 0;
+ 	int ack_dur;
+ 	int stbc;
+ 	int i;
++	bool ldpc = false;
+ 
+ 	/* fall back to the old minstrel for legacy stations */
+ 	if (!sta->ht_cap.ht_supported)
+@@ -1210,16 +1211,24 @@ minstrel_ht_update_caps(void *priv, stru
+ 	}
+ 	mi->sample_tries = 4;
+ 
+-	/* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */
+ 	if (!use_vht) {
+-		stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
++		stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >>
+ 			IEEE80211_HT_CAP_RX_STBC_SHIFT;
+-		mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+ 
+-		if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+-			mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
++		if (ht_cap & IEEE80211_HT_CAP_LDPC_CODING)
++			ldpc = true;
++	} else {
++		stbc = (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) >>
++			IEEE80211_VHT_CAP_RXSTBC_SHIFT;
++
++		if (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)
++			ldpc = true;
+ 	}
+ 
++	mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
++	if (ldpc)
++		mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
++
+ 	for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+ 		u32 gflags = minstrel_mcs_groups[i].flags;
+ 		int bw, nss;
+@@ -1232,10 +1241,10 @@ minstrel_ht_update_caps(void *priv, stru
+ 
+ 		if (gflags & IEEE80211_TX_RC_SHORT_GI) {
+ 			if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+-				if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
++				if (!(ht_cap & IEEE80211_HT_CAP_SGI_40))
+ 					continue;
+ 			} else {
+-				if (!(sta_cap & IEEE80211_HT_CAP_SGI_20))
++				if (!(ht_cap & IEEE80211_HT_CAP_SGI_20))
+ 					continue;
+ 			}
+ 		}
diff --git a/package/kernel/mac80211/patches/307-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch b/package/kernel/mac80211/patches/307-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch
new file mode 100644
index 0000000000..4fc6dc1ec3
--- /dev/null
+++ b/package/kernel/mac80211/patches/307-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch
@@ -0,0 +1,50 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 28 Aug 2016 13:13:01 +0200
+Subject: [PATCH] ath9k: fix moredata bit in PS buffered frame release
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -1635,6 +1635,22 @@ void ath_tx_aggr_wakeup(struct ath_softc
+ 	}
+ }
+ 
++
++static void
++ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val)
++{
++	struct ieee80211_hdr *hdr;
++	u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA);
++	u16 mask_val = mask * val;
++
++	hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
++	if ((hdr->frame_control & mask) != mask_val) {
++		hdr->frame_control = (hdr->frame_control & ~mask) | mask_val;
++		dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
++			sizeof(*hdr), DMA_TO_DEVICE);
++	}
++}
++
+ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
+ 				   struct ieee80211_sta *sta,
+ 				   u16 tids, int nframes,
+@@ -1665,6 +1681,7 @@ void ath9k_release_buffered_frames(struc
+ 			if (!bf)
+ 				break;
+ 
++			ath9k_set_moredata(sc, bf, true);
+ 			list_add_tail(&bf->list, &bf_q);
+ 			ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
+ 			if (bf_isampdu(bf)) {
+@@ -1688,6 +1705,9 @@ void ath9k_release_buffered_frames(struc
+ 	if (list_empty(&bf_q))
+ 		return;
+ 
++	if (!more_data)
++		ath9k_set_moredata(sc, bf_tail, false);
++
+ 	info = IEEE80211_SKB_CB(bf_tail->bf_mpdu);
+ 	info->flags |= IEEE80211_TX_STATUS_EOSP;
+ 
diff --git a/package/kernel/mac80211/patches/308-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch b/package/kernel/mac80211/patches/308-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch
new file mode 100644
index 0000000000..929da25d75
--- /dev/null
+++ b/package/kernel/mac80211/patches/308-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 28 Aug 2016 13:13:42 +0200
+Subject: [PATCH] ath9k: clear potentially stale EOSP status bit in
+ intermediate queues
+
+Prevents spurious ieee80211_sta_eosp calls.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -945,7 +945,8 @@ ath_tx_get_tid_subframe(struct ath_softc
+ 		bf->bf_lastbf = bf;
+ 
+ 		tx_info = IEEE80211_SKB_CB(skb);
+-		tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
++		tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
++				    IEEE80211_TX_STATUS_EOSP);
+ 
+ 		/*
+ 		 * No aggregation session is running, but there may be frames
diff --git a/package/kernel/mac80211/patches/309-ath9k-report-tx-status-on-EOSP.patch b/package/kernel/mac80211/patches/309-ath9k-report-tx-status-on-EOSP.patch
new file mode 100644
index 0000000000..80a3074a4d
--- /dev/null
+++ b/package/kernel/mac80211/patches/309-ath9k-report-tx-status-on-EOSP.patch
@@ -0,0 +1,19 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 28 Aug 2016 13:23:27 +0200
+Subject: [PATCH] ath9k: report tx status on EOSP
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee802
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct ieee80211_sta *sta = info->status.status_driver_data[0];
+ 
+-	if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
++	if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
++			   IEEE80211_TX_STATUS_EOSP)) {
+ 		ieee80211_tx_status(hw, skb);
+ 		return;
+ 	}
diff --git a/package/kernel/mac80211/patches/310-ath9k-fix-block-ack-window-tracking-issues.patch b/package/kernel/mac80211/patches/310-ath9k-fix-block-ack-window-tracking-issues.patch
new file mode 100644
index 0000000000..2993cbab74
--- /dev/null
+++ b/package/kernel/mac80211/patches/310-ath9k-fix-block-ack-window-tracking-issues.patch
@@ -0,0 +1,114 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 30 Aug 2016 12:44:08 +0200
+Subject: [PATCH] ath9k: fix block-ack window tracking issues
+
+Ensure that a buffer gets tracked as part of the block-ack window as
+soon as it's dequeued from the tid for the first time. Ensure that
+double calls to ath_tx_addto_baw (e.g. on retransmission) don't cause
+any issues.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -62,7 +62,7 @@ static void ath_tx_rc_status(struct ath_
+ 			     struct ath_tx_status *ts, int nframes, int nbad,
+ 			     int txok);
+ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
+-			      int seqno);
++			      struct ath_buf *bf);
+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
+ 					   struct ath_txq *txq,
+ 					   struct ath_atx_tid *tid,
+@@ -300,7 +300,7 @@ static void ath_tx_flush_tid(struct ath_
+ 		}
+ 
+ 		if (fi->baw_tracked) {
+-			ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
++			ath_tx_update_baw(sc, tid, bf);
+ 			sendbar = true;
+ 		}
+ 
+@@ -316,10 +316,15 @@ static void ath_tx_flush_tid(struct ath_
+ }
+ 
+ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
+-			      int seqno)
++			      struct ath_buf *bf)
+ {
++	struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
++	u16 seqno = bf->bf_state.seqno;
+ 	int index, cindex;
+ 
++	if (!fi->baw_tracked)
++		return;
++
+ 	index  = ATH_BA_INDEX(tid->seq_start, seqno);
+ 	cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+ 
+@@ -340,6 +345,9 @@ static void ath_tx_addto_baw(struct ath_
+ 	u16 seqno = bf->bf_state.seqno;
+ 	int index, cindex;
+ 
++	if (fi->baw_tracked)
++		return;
++
+ 	index  = ATH_BA_INDEX(tid->seq_start, seqno);
+ 	cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+ 	__set_bit(cindex, tid->tx_buf);
+@@ -616,7 +624,7 @@ static void ath_tx_complete_aggr(struct
+ 			 * complete the acked-ones/xretried ones; update
+ 			 * block-ack window
+ 			 */
+-			ath_tx_update_baw(sc, tid, seqno);
++			ath_tx_update_baw(sc, tid, bf);
+ 
+ 			if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
+ 				memcpy(tx_info->control.rates, rates, sizeof(rates));
+@@ -646,7 +654,7 @@ static void ath_tx_complete_aggr(struct
+ 				 * run out of tx buf.
+ 				 */
+ 				if (!tbf) {
+-					ath_tx_update_baw(sc, tid, seqno);
++					ath_tx_update_baw(sc, tid, bf);
+ 
+ 					ath_tx_complete_buf(sc, bf, txq,
+ 							    &bf_head, NULL, ts,
+@@ -987,11 +995,14 @@ ath_tx_get_tid_subframe(struct ath_softc
+ 
+ 			INIT_LIST_HEAD(&bf_head);
+ 			list_add(&bf->list, &bf_head);
+-			ath_tx_update_baw(sc, tid, seqno);
++			ath_tx_update_baw(sc, tid, bf);
+ 			ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
+ 			continue;
+ 		}
+ 
++		if (bf_isampdu(bf))
++			ath_tx_addto_baw(sc, tid, bf);
++
+ 		return bf;
+ 	}
+ 
+@@ -1049,8 +1060,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s
+ 		bf->bf_next = NULL;
+ 
+ 		/* link buffers of this frame to the aggregate */
+-		if (!fi->baw_tracked)
+-			ath_tx_addto_baw(sc, tid, bf);
+ 		bf->bf_state.ndelim = ndelim;
+ 
+ 		list_add_tail(&bf->list, bf_q);
+@@ -1686,10 +1695,8 @@ void ath9k_release_buffered_frames(struc
+ 			ath9k_set_moredata(sc, bf, true);
+ 			list_add_tail(&bf->list, &bf_q);
+ 			ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
+-			if (bf_isampdu(bf)) {
+-				ath_tx_addto_baw(sc, tid, bf);
++			if (bf_isampdu(bf))
+ 				bf->bf_state.bf_type &= ~BUF_AGGR;
+-			}
+ 			if (bf_tail)
+ 				bf_tail->bf_next = bf;
+ 
diff --git a/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch b/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch
new file mode 100644
index 0000000000..4c5fff1274
--- /dev/null
+++ b/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch
@@ -0,0 +1,275 @@
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 19 Sep 2016 19:00:10 +0800
+Subject: [PATCH] mac80211: Use rhltable instead of rhashtable
+
+mac80211 currently uses rhashtable with insecure_elasticity set
+to true.  The latter is because of duplicate objects.  What's
+more, mac80211 walks the rhashtable chains by hand which is broken
+as rhashtable may contain multiple tables due to resizing or
+rehashing.
+
+This patch fixes it by converting it to the newly added rhltable
+interface which is designed for use with duplicate objects.
+
+With rhltable a lookup returns a list of objects instead of a
+single one.  This is then fed into the existing for_each_sta_info
+macro.
+
+This patch also deletes the sta_addr_hash function since rhashtable
+defaults to jhash.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1233,7 +1233,7 @@ struct ieee80211_local {
+ 	spinlock_t tim_lock;
+ 	unsigned long num_sta;
+ 	struct list_head sta_list;
+-	struct rhashtable sta_hash;
++	struct rhltable sta_hash;
+ 	struct timer_list sta_cleanup;
+ 	int sta_generation;
+ 
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -4004,7 +4004,7 @@ static void __ieee80211_rx_handle_packet
+ 	__le16 fc;
+ 	struct ieee80211_rx_data rx;
+ 	struct ieee80211_sub_if_data *prev;
+-	struct rhash_head *tmp;
++	struct rhlist_head *tmp;
+ 	int err = 0;
+ 
+ 	fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
+@@ -4047,13 +4047,10 @@ static void __ieee80211_rx_handle_packet
+ 		goto out;
+ 	} else if (ieee80211_is_data(fc)) {
+ 		struct sta_info *sta, *prev_sta;
+-		const struct bucket_table *tbl;
+ 
+ 		prev_sta = NULL;
+ 
+-		tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+-		for_each_sta_info(local, tbl, hdr->addr2, sta, tmp) {
++		for_each_sta_info(local, hdr->addr2, sta, tmp) {
+ 			if (!prev_sta) {
+ 				prev_sta = sta;
+ 				continue;
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -67,12 +67,10 @@
+ 
+ static const struct rhashtable_params sta_rht_params = {
+ 	.nelem_hint = 3, /* start small */
+-	.insecure_elasticity = true, /* Disable chain-length checks. */
+ 	.automatic_shrinking = true,
+ 	.head_offset = offsetof(struct sta_info, hash_node),
+ 	.key_offset = offsetof(struct sta_info, addr),
+ 	.key_len = ETH_ALEN,
+-	.hashfn = sta_addr_hash,
+ 	.max_size = CPTCFG_MAC80211_STA_HASH_MAX_SIZE,
+ };
+ 
+@@ -80,8 +78,8 @@ static const struct rhashtable_params st
+ static int sta_info_hash_del(struct ieee80211_local *local,
+ 			     struct sta_info *sta)
+ {
+-	return rhashtable_remove_fast(&local->sta_hash, &sta->hash_node,
+-				      sta_rht_params);
++	return rhltable_remove(&local->sta_hash, &sta->hash_node,
++			       sta_rht_params);
+ }
+ 
+ static void __cleanup_single_sta(struct sta_info *sta)
+@@ -157,19 +155,22 @@ static void cleanup_single_sta(struct st
+ 	sta_info_free(local, sta);
+ }
+ 
++struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
++					 const u8 *addr)
++{
++	return rhltable_lookup(&local->sta_hash, addr, sta_rht_params);
++}
++
+ /* protected by RCU */
+ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
+ 			      const u8 *addr)
+ {
+ 	struct ieee80211_local *local = sdata->local;
++	struct rhlist_head *tmp;
+ 	struct sta_info *sta;
+-	struct rhash_head *tmp;
+-	const struct bucket_table *tbl;
+ 
+ 	rcu_read_lock();
+-	tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+-	for_each_sta_info(local, tbl, addr, sta, tmp) {
++	for_each_sta_info(local, addr, sta, tmp) {
+ 		if (sta->sdata == sdata) {
+ 			rcu_read_unlock();
+ 			/* this is safe as the caller must already hold
+@@ -190,14 +191,11 @@ struct sta_info *sta_info_get_bss(struct
+ 				  const u8 *addr)
+ {
+ 	struct ieee80211_local *local = sdata->local;
++	struct rhlist_head *tmp;
+ 	struct sta_info *sta;
+-	struct rhash_head *tmp;
+-	const struct bucket_table *tbl;
+ 
+ 	rcu_read_lock();
+-	tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+-	for_each_sta_info(local, tbl, addr, sta, tmp) {
++	for_each_sta_info(local, addr, sta, tmp) {
+ 		if (sta->sdata == sdata ||
+ 		    (sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
+ 			rcu_read_unlock();
+@@ -263,8 +261,8 @@ void sta_info_free(struct ieee80211_loca
+ static int sta_info_hash_add(struct ieee80211_local *local,
+ 			     struct sta_info *sta)
+ {
+-	return rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
+-				      sta_rht_params);
++	return rhltable_insert(&local->sta_hash, &sta->hash_node,
++			       sta_rht_params);
+ }
+ 
+ static void sta_deliver_ps_frames(struct work_struct *wk)
+@@ -453,9 +451,9 @@ static int sta_info_insert_check(struct
+ 		    is_multicast_ether_addr(sta->sta.addr)))
+ 		return -EINVAL;
+ 
+-	/* Strictly speaking this isn't necessary as we hold the mutex, but
+-	 * the rhashtable code can't really deal with that distinction. We
+-	 * do require the mutex for correctness though.
++	/* The RCU read lock is required by rhashtable due to
++	 * asynchronous resize/rehash.  We also require the mutex
++	 * for correctness.
+ 	 */
+ 	rcu_read_lock();
+ 	lockdep_assert_held(&sdata->local->sta_mtx);
+@@ -1043,16 +1041,11 @@ static void sta_info_cleanup(unsigned lo
+ 		  round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
+ }
+ 
+-u32 sta_addr_hash(const void *key, u32 length, u32 seed)
+-{
+-	return jhash(key, ETH_ALEN, seed);
+-}
+-
+ int sta_info_init(struct ieee80211_local *local)
+ {
+ 	int err;
+ 
+-	err = rhashtable_init(&local->sta_hash, &sta_rht_params);
++	err = rhltable_init(&local->sta_hash, &sta_rht_params);
+ 	if (err)
+ 		return err;
+ 
+@@ -1068,7 +1061,7 @@ int sta_info_init(struct ieee80211_local
+ void sta_info_stop(struct ieee80211_local *local)
+ {
+ 	del_timer_sync(&local->sta_cleanup);
+-	rhashtable_destroy(&local->sta_hash);
++	rhltable_destroy(&local->sta_hash);
+ }
+ 
+ 
+@@ -1138,17 +1131,14 @@ struct ieee80211_sta *ieee80211_find_sta
+ 						   const u8 *localaddr)
+ {
+ 	struct ieee80211_local *local = hw_to_local(hw);
++	struct rhlist_head *tmp;
+ 	struct sta_info *sta;
+-	struct rhash_head *tmp;
+-	const struct bucket_table *tbl;
+-
+-	tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+ 
+ 	/*
+ 	 * Just return a random station if localaddr is NULL
+ 	 * ... first in list.
+ 	 */
+-	for_each_sta_info(local, tbl, addr, sta, tmp) {
++	for_each_sta_info(local, addr, sta, tmp) {
+ 		if (localaddr &&
+ 		    !ether_addr_equal(sta->sdata->vif.addr, localaddr))
+ 			continue;
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -455,7 +455,7 @@ struct sta_info {
+ 	/* General information, mostly static */
+ 	struct list_head list, free_list;
+ 	struct rcu_head rcu_head;
+-	struct rhash_head hash_node;
++	struct rhlist_head hash_node;
+ 	u8 addr[ETH_ALEN];
+ 	struct ieee80211_local *local;
+ 	struct ieee80211_sub_if_data *sdata;
+@@ -638,6 +638,9 @@ rcu_dereference_protected_tid_tx(struct
+  */
+ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
+ 
++struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
++					 const u8 *addr);
++
+ /*
+  * Get a STA info, must be under RCU read lock.
+  */
+@@ -647,17 +650,9 @@ struct sta_info *sta_info_get(struct iee
+ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
+ 				  const u8 *addr);
+ 
+-u32 sta_addr_hash(const void *key, u32 length, u32 seed);
+-
+-#define _sta_bucket_idx(_tbl, _a)					\
+-	rht_bucket_index(_tbl, sta_addr_hash(_a, ETH_ALEN, (_tbl)->hash_rnd))
+-
+-#define for_each_sta_info(local, tbl, _addr, _sta, _tmp)		\
+-	rht_for_each_entry_rcu(_sta, _tmp, tbl, 			\
+-			       _sta_bucket_idx(tbl, _addr),		\
+-			       hash_node)				\
+-	/* compare address and run code only if it matches */		\
+-	if (ether_addr_equal(_sta->addr, (_addr)))
++#define for_each_sta_info(local, _addr, _sta, _tmp)			\
++	rhl_for_each_entry_rcu(_sta, _tmp,				\
++			       sta_info_hash_lookup(local, _addr), hash_node)
+ 
+ /*
+  * Get STA info by index, BROKEN!
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -759,8 +759,8 @@ void ieee80211_tx_status(struct ieee8021
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	__le16 fc;
+ 	struct ieee80211_supported_band *sband;
++	struct rhlist_head *tmp;
+ 	struct sta_info *sta;
+-	struct rhash_head *tmp;
+ 	int retry_count;
+ 	int rates_idx;
+ 	bool send_to_cooked;
+@@ -768,7 +768,6 @@ void ieee80211_tx_status(struct ieee8021
+ 	struct ieee80211_bar *bar;
+ 	int shift = 0;
+ 	int tid = IEEE80211_NUM_TIDS;
+-	const struct bucket_table *tbl;
+ 
+ 	rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
+ 
+@@ -777,9 +776,7 @@ void ieee80211_tx_status(struct ieee8021
+ 	sband = local->hw.wiphy->bands[info->band];
+ 	fc = hdr->frame_control;
+ 
+-	tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+-	for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) {
++	for_each_sta_info(local, hdr->addr1, sta, tmp) {
+ 		/* skip wrong virtual interface */
+ 		if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
+ 			continue;
diff --git a/package/kernel/mac80211/patches/313-mac80211-fix-sequence-number-allocation-regression.patch b/package/kernel/mac80211/patches/313-mac80211-fix-sequence-number-allocation-regression.patch
new file mode 100644
index 0000000000..c1548be0d2
--- /dev/null
+++ b/package/kernel/mac80211/patches/313-mac80211-fix-sequence-number-allocation-regression.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 11 Oct 2016 11:24:07 +0200
+Subject: [PATCH] mac80211: fix sequence number allocation regression
+
+The recent commit that moved around TX handlers dropped the sequence
+number allocation at the end of ieee80211_tx_dequeue and calls
+ieee80211_tx_h_sequence instead (for the non-fast-xmit case).
+However, it did not change the fast-xmit sequence allocation condition
+in ieee80211_xmit_fast_finish, which skipped seqno alloc if intermediate
+tx queues are being used.
+
+Drop the now obsolete condition.
+
+Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3212,7 +3212,6 @@ static void ieee80211_xmit_fast_finish(s
+ 				       struct sk_buff *skb)
+ {
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_hdr *hdr = (void *)skb->data;
+ 	u8 tid = IEEE80211_NUM_TIDS;
+ 
+@@ -3224,8 +3223,7 @@ static void ieee80211_xmit_fast_finish(s
+ 	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+ 		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+ 		*ieee80211_get_qos_ctl(hdr) = tid;
+-		if (!ieee80211_get_txq(local, &sdata->vif, &sta->sta, skb))
+-			hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
++		hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
+ 	} else {
+ 		info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+ 		hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
diff --git a/package/kernel/mac80211/patches/314-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch b/package/kernel/mac80211/patches/314-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch
new file mode 100644
index 0000000000..a7bcfa549b
--- /dev/null
+++ b/package/kernel/mac80211/patches/314-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 9 Jul 2016 15:25:24 +0200
+Subject: [PATCH] ath9k_hw: reset AHB-WMAC interface on AR91xx
+
+Should fix a few stability issues
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1394,8 +1394,12 @@ static bool ath9k_hw_set_reset(struct at
+ 	if (!AR_SREV_9100(ah))
+ 		REG_WRITE(ah, AR_RC, 0);
+ 
+-	if (AR_SREV_9100(ah))
++	if (AR_SREV_9100(ah)) {
++		/* Reset the AHB-WMAC interface */
++		if (ah->external_reset)
++			ah->external_reset();
+ 		udelay(50);
++	}
+ 
+ 	return true;
+ }
diff --git a/package/kernel/mac80211/patches/315-ath9k_hw-issue-external-reset-for-QCA955x.patch b/package/kernel/mac80211/patches/315-ath9k_hw-issue-external-reset-for-QCA955x.patch
new file mode 100644
index 0000000000..6a958a4132
--- /dev/null
+++ b/package/kernel/mac80211/patches/315-ath9k_hw-issue-external-reset-for-QCA955x.patch
@@ -0,0 +1,125 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 9 Jul 2016 15:26:44 +0200
+Subject: [PATCH] ath9k_hw: issue external reset for QCA955x
+
+The RTC interface on the SoC needs to be reset along with the rest of
+the WMAC.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1271,39 +1271,56 @@ void ath9k_hw_get_delta_slope_vals(struc
+ 	*coef_exponent = coef_exp - 16;
+ }
+ 
+-/* AR9330 WAR:
+- * call external reset function to reset WMAC if:
+- * - doing a cold reset
+- * - we have pending frames in the TX queues.
+- */
+-static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type)
++static bool ath9k_hw_need_external_reset(struct ath_hw *ah, int type)
+ {
+-	int i, npend = 0;
++	int i;
+ 
+-	for (i = 0; i < AR_NUM_QCU; i++) {
+-		npend = ath9k_hw_numtxpending(ah, i);
+-		if (npend)
+-			break;
++	if (type == ATH9K_RESET_COLD)
++		return true;
++
++	if (AR_SREV_9550(ah))
++		return true;
++
++	/* AR9330 WAR:
++	 * call external reset function to reset WMAC if:
++	 * - doing a cold reset
++	 * - we have pending frames in the TX queues.
++	 */
++	if (AR_SREV_9330(ah)) {
++		for (i = 0; i < AR_NUM_QCU; i++) {
++			if (ath9k_hw_numtxpending(ah, i))
++				return true;
++		}
+ 	}
+ 
+-	if (ah->external_reset &&
+-	    (npend || type == ATH9K_RESET_COLD)) {
+-		int reset_err = 0;
++	return false;
++}
+ 
+-		ath_dbg(ath9k_hw_common(ah), RESET,
+-			"reset MAC via external reset\n");
++static bool ath9k_hw_external_reset(struct ath_hw *ah, int type)
++{
++	int err;
+ 
+-		reset_err = ah->external_reset();
+-		if (reset_err) {
+-			ath_err(ath9k_hw_common(ah),
+-				"External reset failed, err=%d\n",
+-				reset_err);
+-			return false;
+-		}
++	if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type))
++		return true;
+ 
+-		REG_WRITE(ah, AR_RTC_RESET, 1);
++	ath_dbg(ath9k_hw_common(ah), RESET,
++		"reset MAC via external reset\n");
++
++	err = ah->external_reset();
++	if (err) {
++		ath_err(ath9k_hw_common(ah),
++			"External reset failed, err=%d\n", err);
++		return false;
++	}
++
++	if (AR_SREV_9550(ah)) {
++		REG_WRITE(ah, AR_RTC_RESET, 0);
++		udelay(10);
+ 	}
+ 
++	REG_WRITE(ah, AR_RTC_RESET, 1);
++	udelay(10);
++
+ 	return true;
+ }
+ 
+@@ -1356,24 +1373,23 @@ static bool ath9k_hw_set_reset(struct at
+ 			rst_flags |= AR_RTC_RC_MAC_COLD;
+ 	}
+ 
+-	if (AR_SREV_9330(ah)) {
+-		if (!ath9k_hw_ar9330_reset_war(ah, type))
+-			return false;
+-	}
+-
+ 	if (ath9k_hw_mci_is_enabled(ah))
+ 		ar9003_mci_check_gpm_offset(ah);
+ 
+ 	/* DMA HALT added to resolve ar9300 and ar9580 bus error during
+-	 * RTC_RC reg read
++	 * RTC_RC reg read. Also needed for AR9550 external reset
+ 	 */
+-	if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) {
++	if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) {
+ 		REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
+ 		ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK,
+ 			      20 * AH_WAIT_TIMEOUT);
+-		REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
+ 	}
+ 
++	ath9k_hw_external_reset(ah, type);
++
++	if (AR_SREV_9300(ah) || AR_SREV_9580(ah))
++		REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
++
+ 	REG_WRITE(ah, AR_RTC_RC, rst_flags);
+ 
+ 	REGWRITE_BUFFER_FLUSH(ah);
diff --git a/package/kernel/mac80211/patches/316-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch b/package/kernel/mac80211/patches/316-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch
new file mode 100644
index 0000000000..dfe9aae268
--- /dev/null
+++ b/package/kernel/mac80211/patches/316-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch
@@ -0,0 +1,21 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 11 Jul 2016 12:07:40 +0200
+Subject: [PATCH] ath9k_hw: set spectral scan enable bit on trigger for
+ AR9003+
+
+AR9002 code and QCA AR9003+ code do the same.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -1800,6 +1800,8 @@ static void ar9003_hw_spectral_scan_conf
+ 
+ static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
+ {
++	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
++		    AR_PHY_SPECTRAL_SCAN_ENABLE);
+ 	/* Activate spectral scan */
+ 	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ 		    AR_PHY_SPECTRAL_SCAN_ACTIVE);
diff --git a/package/kernel/mac80211/patches/317-Revert-ath9k_hw-implement-temperature-compensation-s.patch b/package/kernel/mac80211/patches/317-Revert-ath9k_hw-implement-temperature-compensation-s.patch
new file mode 100644
index 0000000000..687df35a9e
--- /dev/null
+++ b/package/kernel/mac80211/patches/317-Revert-ath9k_hw-implement-temperature-compensation-s.patch
@@ -0,0 +1,101 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 11 Oct 2016 19:45:41 +0200
+Subject: [PATCH] Revert "ath9k_hw: implement temperature compensation support
+ for AR9003+"
+
+This reverts commit 171f6402e4aa5cd3b8407f82501f7ea21fa54ccc.
+Some users report that this commit causes a regression in performance
+under some conditions.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+@@ -33,7 +33,6 @@ struct coeff {
+ 
+ enum ar9003_cal_types {
+ 	IQ_MISMATCH_CAL = BIT(0),
+-	TEMP_COMP_CAL = BIT(1),
+ };
+ 
+ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
+@@ -59,12 +58,6 @@ static void ar9003_hw_setup_calibration(
+ 		/* Kick-off cal */
+ 		REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
+ 		break;
+-	case TEMP_COMP_CAL:
+-		ath_dbg(common, CALIBRATE,
+-			"starting Temperature Compensation Calibration\n");
+-		REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL);
+-		REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START);
+-		break;
+ 	default:
+ 		ath_err(common, "Invalid calibration type\n");
+ 		break;
+@@ -93,8 +86,7 @@ static bool ar9003_hw_per_calibration(st
+ 		/*
+ 		* Accumulate cal measures for active chains
+ 		*/
+-		if (cur_caldata->calCollect)
+-			cur_caldata->calCollect(ah);
++		cur_caldata->calCollect(ah);
+ 		ah->cal_samples++;
+ 
+ 		if (ah->cal_samples >= cur_caldata->calNumSamples) {
+@@ -107,8 +99,7 @@ static bool ar9003_hw_per_calibration(st
+ 			/*
+ 			* Process accumulated data
+ 			*/
+-			if (cur_caldata->calPostProc)
+-				cur_caldata->calPostProc(ah, numChains);
++			cur_caldata->calPostProc(ah, numChains);
+ 
+ 			/* Calibration has finished. */
+ 			caldata->CalValid |= cur_caldata->calType;
+@@ -323,16 +314,9 @@ static const struct ath9k_percal_data iq
+ 	ar9003_hw_iqcalibrate
+ };
+ 
+-static const struct ath9k_percal_data temp_cal_single_sample = {
+-	TEMP_COMP_CAL,
+-	MIN_CAL_SAMPLES,
+-	PER_MAX_LOG_COUNT,
+-};
+-
+ static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
+ {
+ 	ah->iq_caldata.calData = &iq_cal_single_sample;
+-	ah->temp_caldata.calData = &temp_cal_single_sample;
+ 
+ 	if (AR_SREV_9300_20_OR_LATER(ah)) {
+ 		ah->enabled_cals |= TX_IQ_CAL;
+@@ -340,7 +324,7 @@ static void ar9003_hw_init_cal_settings(
+ 			ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
+ 	}
+ 
+-	ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL;
++	ah->supp_cals = IQ_MISMATCH_CAL;
+ }
+ 
+ #define OFF_UPPER_LT 24
+@@ -1399,9 +1383,6 @@ static void ar9003_hw_init_cal_common(st
+ 	INIT_CAL(&ah->iq_caldata);
+ 	INSERT_CAL(ah, &ah->iq_caldata);
+ 
+-	INIT_CAL(&ah->temp_caldata);
+-	INSERT_CAL(ah, &ah->temp_caldata);
+-
+ 	/* Initialize current pointer to first element in list */
+ 	ah->cal_list_curr = ah->cal_list;
+ 
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -830,7 +830,6 @@ struct ath_hw {
+ 	/* Calibration */
+ 	u32 supp_cals;
+ 	struct ath9k_cal_list iq_caldata;
+-	struct ath9k_cal_list temp_caldata;
+ 	struct ath9k_cal_list adcgain_caldata;
+ 	struct ath9k_cal_list adcdc_caldata;
+ 	struct ath9k_cal_list *cal_list;
diff --git a/package/kernel/mac80211/patches/318-mac80211-fix-up-mismerge-of-ieee80211_tx_dequeue.patch b/package/kernel/mac80211/patches/318-mac80211-fix-up-mismerge-of-ieee80211_tx_dequeue.patch
new file mode 100644
index 0000000000..2e742e4484
--- /dev/null
+++ b/package/kernel/mac80211/patches/318-mac80211-fix-up-mismerge-of-ieee80211_tx_dequeue.patch
@@ -0,0 +1,35 @@
+From: Bob Copeland <me@bobcopeland.com>
+Date: Wed, 12 Oct 2016 08:24:54 -0400
+Subject: [PATCH] mac80211: fix up mismerge of ieee80211_tx_dequeue
+
+Looks like this spinlock wound up on the wrong side of the
+linearize, and I also lost the part that re-enters the loop.
+Fix up to match mac80211-next.
+
+Signed-off-by: Bob Copeland <me@bobcopeland.com>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3457,17 +3457,17 @@ begin:
+ 			skb_queue_splice_tail(&tx.skbs, &txqi->frags);
+ 	}
+ 
+-out:
+-	spin_unlock_bh(&fq->lock);
+-
+ 	if (skb && skb_has_frag_list(skb) &&
+ 	    !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) {
+ 		if (skb_linearize(skb)) {
+ 			ieee80211_free_txskb(&local->hw, skb);
+-			return NULL;
++			goto begin;
+ 		}
+ 	}
+ 
++out:
++	spin_unlock_bh(&fq->lock);
++
+ 	return skb;
+ }
+ EXPORT_SYMBOL(ieee80211_tx_dequeue);
diff --git a/package/kernel/mac80211/patches/319-mac80211-avoid-extra-memcpy-in-A-MSDU-head-creation.patch b/package/kernel/mac80211/patches/319-mac80211-avoid-extra-memcpy-in-A-MSDU-head-creation.patch
new file mode 100644
index 0000000000..fb6bd30243
--- /dev/null
+++ b/package/kernel/mac80211/patches/319-mac80211-avoid-extra-memcpy-in-A-MSDU-head-creation.patch
@@ -0,0 +1,55 @@
+From: Michael Braun <michael-dev@fami-braun.de>
+Date: Sat, 15 Oct 2016 13:28:18 +0200
+Subject: [PATCH] mac80211: avoid extra memcpy in A-MSDU head creation
+
+Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3069,11 +3069,11 @@ static bool ieee80211_amsdu_prepare_head
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct ieee80211_hdr *hdr;
+-	struct ethhdr amsdu_hdr;
++	struct ethhdr *amsdu_hdr;
+ 	int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
+ 	int subframe_len = skb->len - hdr_len;
+ 	void *data;
+-	u8 *qc;
++	u8 *qc, *h_80211_src, *h_80211_dst;
+ 
+ 	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ 		return false;
+@@ -3081,19 +3081,22 @@ static bool ieee80211_amsdu_prepare_head
+ 	if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
+ 		return true;
+ 
+-	if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr),
++	if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr),
+ 					 &subframe_len))
+ 		return false;
+ 
+-	amsdu_hdr.h_proto = cpu_to_be16(subframe_len);
+-	memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN);
+-	memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN);
++	data = skb_push(skb, sizeof(*amsdu_hdr));
++	memmove(data, data + sizeof(*amsdu_hdr), hdr_len);
++	hdr = data;
++	amsdu_hdr = data + hdr_len;
++	/* h_80211_src/dst is addr* field within hdr */
++	h_80211_src = data + fast_tx->sa_offs;
++	h_80211_dst = data + fast_tx->da_offs;
+ 
+-	data = skb_push(skb, sizeof(amsdu_hdr));
+-	memmove(data, data + sizeof(amsdu_hdr), hdr_len);
+-	memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr));
++	amsdu_hdr->h_proto = cpu_to_be16(subframe_len);
++	ether_addr_copy(amsdu_hdr->h_source, h_80211_src);
++	ether_addr_copy(amsdu_hdr->h_dest, h_80211_dst);
+ 
+-	hdr = data;
+ 	qc = ieee80211_get_qos_ctl(hdr);
+ 	*qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ 
diff --git a/package/kernel/mac80211/patches/320-mac80211-fix-A-MSDU-outer-SA-DA.patch b/package/kernel/mac80211/patches/320-mac80211-fix-A-MSDU-outer-SA-DA.patch
new file mode 100644
index 0000000000..7700254cd1
--- /dev/null
+++ b/package/kernel/mac80211/patches/320-mac80211-fix-A-MSDU-outer-SA-DA.patch
@@ -0,0 +1,73 @@
+From: Michael Braun <michael-dev@fami-braun.de>
+Date: Sat, 15 Oct 2016 13:28:19 +0200
+Subject: [PATCH] mac80211: fix A-MSDU outer SA/DA
+
+According to IEEE 802.11-2012 section 8.3.2 table 8-19, the outer SA/DA
+of A-MSDU frames need to be changed depending on FromDS/ToDS values.
+
+Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
+[use ether_addr_copy and add alignment annotations]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1438,7 +1438,7 @@ enum ieee80211_vif_flags {
+ struct ieee80211_vif {
+ 	enum nl80211_iftype type;
+ 	struct ieee80211_bss_conf bss_conf;
+-	u8 addr[ETH_ALEN];
++	u8 addr[ETH_ALEN] __aligned(2);
+ 	bool p2p;
+ 	bool csa_active;
+ 	bool mu_mimo_owner;
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -443,7 +443,7 @@ struct ieee80211_if_managed {
+ 	struct ieee80211_mgd_auth_data *auth_data;
+ 	struct ieee80211_mgd_assoc_data *assoc_data;
+ 
+-	u8 bssid[ETH_ALEN];
++	u8 bssid[ETH_ALEN] __aligned(2);
+ 
+ 	u16 aid;
+ 
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3074,6 +3074,7 @@ static bool ieee80211_amsdu_prepare_head
+ 	int subframe_len = skb->len - hdr_len;
+ 	void *data;
+ 	u8 *qc, *h_80211_src, *h_80211_dst;
++	const u8 *bssid;
+ 
+ 	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ 		return false;
+@@ -3097,6 +3098,28 @@ static bool ieee80211_amsdu_prepare_head
+ 	ether_addr_copy(amsdu_hdr->h_source, h_80211_src);
+ 	ether_addr_copy(amsdu_hdr->h_dest, h_80211_dst);
+ 
++	/* according to IEEE 802.11-2012 8.3.2 table 8-19, the outer SA/DA
++	 * fields needs to be changed to BSSID for A-MSDU frames depending
++	 * on FromDS/ToDS values.
++	 */
++	switch (sdata->vif.type) {
++	case NL80211_IFTYPE_STATION:
++		bssid = sdata->u.mgd.bssid;
++		break;
++	case NL80211_IFTYPE_AP:
++	case NL80211_IFTYPE_AP_VLAN:
++		bssid = sdata->vif.addr;
++		break;
++	default:
++		bssid = NULL;
++	}
++
++	if (bssid && ieee80211_has_fromds(hdr->frame_control))
++		ether_addr_copy(h_80211_src, bssid);
++
++	if (bssid && ieee80211_has_tods(hdr->frame_control))
++		ether_addr_copy(h_80211_dst, bssid);
++
+ 	qc = ieee80211_get_qos_ctl(hdr);
+ 	*qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ 
diff --git a/package/kernel/mac80211/patches/321-Revert-mac80211-allow-using-AP_LINK_PS-with-mac80211.patch b/package/kernel/mac80211/patches/321-Revert-mac80211-allow-using-AP_LINK_PS-with-mac80211.patch
new file mode 100644
index 0000000000..ace20e706b
--- /dev/null
+++ b/package/kernel/mac80211/patches/321-Revert-mac80211-allow-using-AP_LINK_PS-with-mac80211.patch
@@ -0,0 +1,28 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 3 Nov 2016 12:10:34 +0100
+Subject: [PATCH] Revert "mac80211: allow using AP_LINK_PS with
+ mac80211-generated TIM IE"
+
+This reverts commit c68df2e7be0c1238ea3c281fd744a204ef3b15a0.
+
+__sta_info_recalc_tim turns into a no-op if local->ops->set_tim is not
+set. This prevents the beacon TIM bit from being set for all drivers
+that do not implement this op (almost all of them), thus thoroughly
+essential AP mode powersave functionality.
+
+Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Fixes: c68df2e7be0c ("mac80211: allow using AP_LINK_PS with mac80211-generated TIM IE")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -688,7 +688,7 @@ static void __sta_info_recalc_tim(struct
+ 	}
+ 
+ 	/* No need to do anything if the driver does all */
+-	if (!local->ops->set_tim)
++	if (ieee80211_hw_check(&local->hw, AP_LINK_PS))
+ 		return;
+ 
+ 	if (sta->dead)
diff --git a/package/kernel/mac80211/patches/322-mac80211-update-A-MPDU-flag-on-tx-dequeue.patch b/package/kernel/mac80211/patches/322-mac80211-update-A-MPDU-flag-on-tx-dequeue.patch
new file mode 100644
index 0000000000..1898d23584
--- /dev/null
+++ b/package/kernel/mac80211/patches/322-mac80211-update-A-MPDU-flag-on-tx-dequeue.patch
@@ -0,0 +1,30 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 4 Nov 2016 10:13:34 +0100
+Subject: [PATCH] mac80211: update A-MPDU flag on tx dequeue
+
+The sequence number counter is used to derive the starting sequence
+number. Since that counter is updated on tx dequeue, the A-MPDU flag
+needs to be up to date at the tme of dequeue as well.
+
+This patch prevents sending more A-MPDU frames after the session has
+been terminated and also ensures that aggregation starts right after the
+session has been established
+
+Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3462,6 +3462,11 @@ begin:
+ 		goto begin;
+ 	}
+ 
++	if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
++		info->flags |= IEEE80211_TX_CTL_AMPDU;
++	else
++		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
++
+ 	if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
+ 		struct sta_info *sta = container_of(txq->sta, struct sta_info,
+ 						    sta);
diff --git a/package/kernel/mac80211/patches/323-mac80211-remove-bogus-skb-vif-assignment.patch b/package/kernel/mac80211/patches/323-mac80211-remove-bogus-skb-vif-assignment.patch
new file mode 100644
index 0000000000..66449aca2b
--- /dev/null
+++ b/package/kernel/mac80211/patches/323-mac80211-remove-bogus-skb-vif-assignment.patch
@@ -0,0 +1,29 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 4 Nov 2016 10:17:38 +0100
+Subject: [PATCH] mac80211: remove bogus skb vif assignment
+
+The call to ieee80211_txq_enqueue overwrites the vif pointer with the
+codel enqueue time, so setting it just before that call makes no sense.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1500,7 +1500,6 @@ static bool ieee80211_queue_skb(struct i
+ 				struct sta_info *sta,
+ 				struct sk_buff *skb)
+ {
+-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct fq *fq = &local->fq;
+ 	struct ieee80211_vif *vif;
+ 	struct txq_info *txqi;
+@@ -1525,8 +1524,6 @@ static bool ieee80211_queue_skb(struct i
+ 	if (!txqi)
+ 		return false;
+ 
+-	info->control.vif = vif;
+-
+ 	spin_lock_bh(&fq->lock);
+ 	ieee80211_txq_enqueue(local, txqi, skb);
+ 	spin_unlock_bh(&fq->lock);
diff --git a/package/kernel/mac80211/patches/324-mac80211-fix-A-MSDU-aggregation-with-fast-xmit-txq.patch b/package/kernel/mac80211/patches/324-mac80211-fix-A-MSDU-aggregation-with-fast-xmit-txq.patch
new file mode 100644
index 0000000000..579f112f71
--- /dev/null
+++ b/package/kernel/mac80211/patches/324-mac80211-fix-A-MSDU-aggregation-with-fast-xmit-txq.patch
@@ -0,0 +1,34 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 4 Nov 2016 10:18:51 +0100
+Subject: [PATCH] mac80211: fix A-MSDU aggregation with fast-xmit + txq
+
+A-MSDU aggregation alters the QoS header after a frame has been
+enqueued, so it needs to be ready before enqueue and not overwritten
+again afterwards
+
+Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3245,7 +3245,6 @@ static void ieee80211_xmit_fast_finish(s
+ 
+ 	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+ 		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+-		*ieee80211_get_qos_ctl(hdr) = tid;
+ 		hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
+ 	} else {
+ 		info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+@@ -3370,6 +3369,11 @@ static bool ieee80211_xmit_fast(struct i
+ 		      (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
+ 	info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
+ 
++	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
++		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
++		*ieee80211_get_qos_ctl(hdr) = tid;
++	}
++
+ 	__skb_queue_head_init(&tx.skbs);
+ 
+ 	tx.flags = IEEE80211_TX_UNICAST;
diff --git a/package/kernel/mac80211/patches/325-ath9k-fix-ath9k_hw_gpio_get-to-return-0-or-1-on-succ.patch b/package/kernel/mac80211/patches/325-ath9k-fix-ath9k_hw_gpio_get-to-return-0-or-1-on-succ.patch
new file mode 100644
index 0000000000..a966a1690f
--- /dev/null
+++ b/package/kernel/mac80211/patches/325-ath9k-fix-ath9k_hw_gpio_get-to-return-0-or-1-on-succ.patch
@@ -0,0 +1,29 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Tue, 15 Nov 2016 16:08:29 +0100
+Subject: [PATCH] ath9k: fix ath9k_hw_gpio_get() to return 0 or 1 on success
+
+Commit b2d70d4944c1 ("ath9k: make GPIO API to support both of WMAC and
+SOC") refactored ath9k_hw_gpio_get() to support both WMAC and SOC GPIOs,
+changing the return on success from 1 to BIT(gpio). This broke some callers
+like ath_is_rfkill_set().
+
+Instead of fixing all callers, change ath9k_hw_gpio_get() back to only
+return 0 or 1.
+
+Fixes: b2d70d4944c1 ("ath9k: make GPIO API to support both of WMAC and SOC")
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ drivers/net/wireless/ath/ath9k/hw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2812,7 +2812,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah,
+ 		WARN_ON(1);
+ 	}
+ 
+-	return val;
++	return !!val;
+ }
+ EXPORT_SYMBOL(ath9k_hw_gpio_get);
+ 
diff --git a/package/kernel/mac80211/patches/326-Documentation-dt-net-add-ath9k-wireless-device-bindi.patch b/package/kernel/mac80211/patches/326-Documentation-dt-net-add-ath9k-wireless-device-bindi.patch
new file mode 100644
index 0000000000..72a459c9e6
--- /dev/null
+++ b/package/kernel/mac80211/patches/326-Documentation-dt-net-add-ath9k-wireless-device-bindi.patch
@@ -0,0 +1,67 @@
+From b263e0bb9d4585ca3ec04d7257ca5308d21333bb Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Sun, 16 Oct 2016 22:59:05 +0200
+Subject: [PATCH 1/3] Documentation: dt: net: add ath9k wireless device binding
+
+Add documentation how devicetree can be used to configure ath9k based
+devices.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+---
+ .../devicetree/bindings/net/wireless/qca,ath9k.txt | 48 ++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
+@@ -0,0 +1,48 @@
++* Qualcomm Atheros ath9k wireless devices
++
++This node provides properties for configuring the ath9k wireless device. The
++node is expected to be specified as a child node of the PCI controller to
++which the wireless chip is connected.
++
++Required properties:
++- compatible: For PCI and PCIe devices this should be an identifier following
++		the format as defined in "PCI Bus Binding to Open Firmware"
++		Revision 2.1. One of the possible formats is "pciVVVV,DDDD"
++		where VVVV is the PCI vendor ID and DDDD is PCI device ID.
++		Typically QCA's PCI vendor ID 168c is used while the PCI device
++		ID depends on the chipset - see the following (possibly
++		incomplete) list:
++			- 0023 for AR5416
++			- 0024 for AR5418
++			- 0027 for AR9160
++			- 0029 for AR9220 and AR9223
++			- 002a for AR9280 and AR9283
++			- 002b for AR9285
++			- 002c for AR2427
++			- 002d for AR9227
++			- 002e for AR9287
++			- 0030 for AR9380, AR9381 and AR9382
++			- 0032 for AR9485
++			- 0033 for AR9580 and AR9590
++			- 0034 for AR9462
++			- 0036 for AR9565
++			- 0037 for AR9485
++- reg: Address and length of the register set for the device.
++
++Optional properties:
++- qca,no-eeprom: Indicates that there is no physical EEPROM connected to the
++			ath9k wireless chip (in this case the calibration /
++			EEPROM data will be loaded from userspace using the
++			kernel firmware loader).
++- mac-address: See ethernet.txt in the parent directory
++- local-mac-address: See ethernet.txt in the parent directory
++
++
++In this example, the node is defined as child node of the PCI controller:
++&pci0 {
++	wifi@168c,002d {
++		compatible = "pci168c,002d";
++		reg = <0x7000 0 0 0 0x1000>;
++		qca,no-eeprom;
++	};
++};
diff --git a/package/kernel/mac80211/patches/327-ath9k-add-a-helper-to-get-the-string-representation-.patch b/package/kernel/mac80211/patches/327-ath9k-add-a-helper-to-get-the-string-representation-.patch
new file mode 100644
index 0000000000..c191495b84
--- /dev/null
+++ b/package/kernel/mac80211/patches/327-ath9k-add-a-helper-to-get-the-string-representation-.patch
@@ -0,0 +1,42 @@
+From 25b8b2d57def4854558c135228a52326a7d346ad Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Sun, 16 Oct 2016 22:59:06 +0200
+Subject: [PATCH 2/3] ath9k: add a helper to get the string representation of
+ ath_bus_type
+
+This can be used when the ath_bus_type has to be presented in a log
+message or firmware filename.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+---
+ drivers/net/wireless/ath/ath.h  | 6 ++++++
+ drivers/net/wireless/ath/main.c | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -327,4 +327,10 @@ static inline const char *ath_opmode_to_
+ }
+ #endif
+ 
++extern const char *ath_bus_type_strings[];
++static inline const char *ath_bus_type_to_string(enum ath_bus_type bustype)
++{
++	return ath_bus_type_strings[bustype];
++}
++
+ #endif /* ATH_H */
+--- a/drivers/net/wireless/ath/main.c
++++ b/drivers/net/wireless/ath/main.c
+@@ -90,3 +90,10 @@ void ath_printk(const char *level, const
+ 	va_end(args);
+ }
+ EXPORT_SYMBOL(ath_printk);
++
++const char *ath_bus_type_strings[] = {
++	[ATH_PCI] = "pci",
++	[ATH_AHB] = "ahb",
++	[ATH_USB] = "usb",
++};
++EXPORT_SYMBOL(ath_bus_type_strings);
diff --git a/package/kernel/mac80211/patches/328-ath9k-parse-the-device-configuration-from-an-OF-node.patch b/package/kernel/mac80211/patches/328-ath9k-parse-the-device-configuration-from-an-OF-node.patch
new file mode 100644
index 0000000000..b260858d45
--- /dev/null
+++ b/package/kernel/mac80211/patches/328-ath9k-parse-the-device-configuration-from-an-OF-node.patch
@@ -0,0 +1,85 @@
+From cea03be5a848823cb8052e2e7b93cb2249d5f60c Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Sun, 16 Oct 2016 22:59:07 +0200
+Subject: [PATCH 3/3] ath9k: parse the device configuration from an OF node
+
+This allows setting the MAC address and specifying that the firmware
+will be requested from userspace (because there might not be a hardware
+EEPROM connected to the chip) for ath9k based PCI devices using
+the device tree.
+
+There is some out-of-tree code to "convert devicetree to
+ath9k_platform_data" (for example in OpenWrt and LEDE) which becomes
+obsolete with this patch.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+---
+ drivers/net/wireless/ath/ath9k/init.c | 42 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -20,6 +20,8 @@
+ #include <linux/slab.h>
+ #include <linux/ath9k_platform.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_net.h>
+ #include <linux/relay.h>
+ #include <net/ieee80211_radiotap.h>
+ 
+@@ -554,6 +556,42 @@ static int ath9k_init_platform(struct at
+ 	return 0;
+ }
+ 
++static int ath9k_of_init(struct ath_softc *sc)
++{
++	struct device_node *np = sc->dev->of_node;
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath_common *common = ath9k_hw_common(ah);
++	enum ath_bus_type bus_type = common->bus_ops->ath_bus_type;
++	const char *mac;
++	char eeprom_name[100];
++	int ret;
++
++	if (!of_device_is_available(np))
++		return 0;
++
++	ath_dbg(common, CONFIG, "parsing configuration from OF node\n");
++
++	if (of_property_read_bool(np, "qca,no-eeprom")) {
++		/* ath9k-eeprom-<bus>-<id>.bin */
++		scnprintf(eeprom_name, sizeof(eeprom_name),
++			  "ath9k-eeprom-%s-%s.bin",
++			  ath_bus_type_to_string(bus_type), dev_name(ah->dev));
++
++		ret = ath9k_eeprom_request(sc, eeprom_name);
++		if (ret)
++			return ret;
++	}
++
++	mac = of_get_mac_address(np);
++	if (mac)
++		ether_addr_copy(common->macaddr, mac);
++
++	ah->ah_flags &= ~AH_USE_EEPROM;
++	ah->ah_flags |= AH_NO_EEP_SWAP;
++
++	return 0;
++}
++
+ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
+ 			    const struct ath_bus_ops *bus_ops)
+ {
+@@ -610,6 +648,10 @@ static int ath9k_init_softc(u16 devid, s
+ 	if (ret)
+ 		return ret;
+ 
++	ret = ath9k_of_init(sc);
++	if (ret)
++		return ret;
++
+ 	if (ath9k_led_active_high != -1)
+ 		ah->config.led_active_high = ath9k_led_active_high == 1;
+ 
diff --git a/package/kernel/mac80211/patches/400-ath_move_debug_code.patch b/package/kernel/mac80211/patches/400-ath_move_debug_code.patch
new file mode 100644
index 0000000000..72e9a41223
--- /dev/null
+++ b/package/kernel/mac80211/patches/400-ath_move_debug_code.patch
@@ -0,0 +1,30 @@
+--- a/drivers/net/wireless/ath/Makefile
++++ b/drivers/net/wireless/ath/Makefile
+@@ -13,10 +13,10 @@ ath-objs :=	main.o \
+ 		regd.o \
+ 		hw.o \
+ 		key.o \
++		debug.o \
+ 		dfs_pattern_detector.o \
+ 		dfs_pri_detector.o
+ 
+-ath-$(CPTCFG_ATH_DEBUG) += debug.o
+ ath-$(CPTCFG_ATH_TRACEPOINTS) += trace.o
+ 
+ ccflags-y += -D__CHECK_ENDIAN__
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -318,13 +318,6 @@ void _ath_dbg(struct ath_common *common,
+ #endif /* CPTCFG_ATH_DEBUG */
+ 
+ /** Returns string describing opmode, or NULL if unknown mode. */
+-#ifdef CPTCFG_ATH_DEBUG
+ const char *ath_opmode_to_string(enum nl80211_iftype opmode);
+-#else
+-static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode)
+-{
+-	return "UNKNOWN";
+-}
+-#endif
+ 
+ #endif /* ATH_H */
diff --git a/package/kernel/mac80211/patches/401-ath9k_blink_default.patch b/package/kernel/mac80211/patches/401-ath9k_blink_default.patch
new file mode 100644
index 0000000000..4a997f1e0c
--- /dev/null
+++ b/package/kernel/mac80211/patches/401-ath9k_blink_default.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -45,7 +45,7 @@ int ath9k_modparam_nohwcrypt;
+ module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
+ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+ 
+-int ath9k_led_blink;
++int ath9k_led_blink = 1;
+ module_param_named(blink, ath9k_led_blink, int, 0444);
+ MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+ 
diff --git a/package/kernel/mac80211/patches/402-ath_regd_optional.patch b/package/kernel/mac80211/patches/402-ath_regd_optional.patch
new file mode 100644
index 0000000000..7a7c2d4174
--- /dev/null
+++ b/package/kernel/mac80211/patches/402-ath_regd_optional.patch
@@ -0,0 +1,84 @@
+--- a/drivers/net/wireless/ath/regd.c
++++ b/drivers/net/wireless/ath/regd.c
+@@ -116,6 +116,9 @@ static const struct ieee80211_regdomain
+ 
+ static bool dynamic_country_user_possible(struct ath_regulatory *reg)
+ {
++	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
++		return true;
++
+ 	if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
+ 		return true;
+ 
+@@ -188,6 +191,8 @@ static bool dynamic_country_user_possibl
+ 
+ static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)
+ {
++	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
++		return true;
+ 	if (!IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_REG_HINTS))
+ 		return false;
+ 	if (!dynamic_country_user_possible(reg))
+@@ -341,6 +346,9 @@ ath_reg_apply_beaconing_flags(struct wip
+ 	struct ieee80211_channel *ch;
+ 	unsigned int i;
+ 
++	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
++		return;
++
+ 	for (band = 0; band < NUM_NL80211_BANDS; band++) {
+ 		if (!wiphy->bands[band])
+ 			continue;
+@@ -374,6 +382,9 @@ ath_reg_apply_ir_flags(struct wiphy *wip
+ {
+ 	struct ieee80211_supported_band *sband;
+ 
++	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
++		return;
++
+ 	sband = wiphy->bands[NL80211_BAND_2GHZ];
+ 	if (!sband)
+ 		return;
+@@ -402,6 +413,9 @@ static void ath_reg_apply_radar_flags(st
+ 	struct ieee80211_channel *ch;
+ 	unsigned int i;
+ 
++	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
++		return;
++
+ 	if (!wiphy->bands[NL80211_BAND_5GHZ])
+ 		return;
+ 
+@@ -633,6 +647,10 @@ ath_regd_init_wiphy(struct ath_regulator
+ 	const struct ieee80211_regdomain *regd;
+ 
+ 	wiphy->reg_notifier = reg_notifier;
++
++	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
++		return 0;
++
+ 	wiphy->regulatory_flags |= REGULATORY_STRICT_REG |
+ 				   REGULATORY_CUSTOM_REG;
+ 
+--- a/drivers/net/wireless/ath/Kconfig
++++ b/drivers/net/wireless/ath/Kconfig
+@@ -23,6 +23,9 @@ config WLAN_VENDOR_ATH
+ 
+ if WLAN_VENDOR_ATH
+ 
++config ATH_USER_REGD
++	bool "Do not enforce EEPROM regulatory restrictions"
++
+ config ATH_DEBUG
+ 	bool "Atheros wireless debugging"
+ 	---help---
+--- a/.local-symbols
++++ b/.local-symbols
+@@ -127,6 +127,7 @@ ADM8211=
+ ATH_COMMON=
+ WLAN_VENDOR_ATH=
+ ATH_DEBUG=
++ATH_USER_REGD=
+ ATH_TRACEPOINTS=
+ ATH_REG_DYNAMIC_USER_REG_HINTS=
+ ATH_REG_DYNAMIC_USER_CERT_TESTING=
diff --git a/package/kernel/mac80211/patches/403-world_regd_fixup.patch b/package/kernel/mac80211/patches/403-world_regd_fixup.patch
new file mode 100644
index 0000000000..2b04309ce5
--- /dev/null
+++ b/package/kernel/mac80211/patches/403-world_regd_fixup.patch
@@ -0,0 +1,84 @@
+--- a/drivers/net/wireless/ath/regd.c
++++ b/drivers/net/wireless/ath/regd.c
+@@ -43,7 +43,8 @@ static int __ath_regd_init(struct ath_re
+ 					 NL80211_RRF_NO_OFDM)
+ 
+ /* We allow IBSS on these on a case by case basis by regulatory domain */
+-#define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5350+10, 80, 0, 30,\
++#define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\
++				REG_RULE(5260-10, 5350+10, 80, 0, 30,\
+ 					 NL80211_RRF_NO_IR)
+ #define ATH9K_5GHZ_5470_5850	REG_RULE(5470-10, 5850+10, 80, 0, 30,\
+ 					 NL80211_RRF_NO_IR)
+@@ -61,57 +62,56 @@ static int __ath_regd_init(struct ath_re
+ #define ATH9K_5GHZ_NO_MIDBAND	ATH9K_5GHZ_5150_5350, \
+ 				ATH9K_5GHZ_5725_5850
+ 
++#define REGD_RULES(...) \
++	.reg_rules = { __VA_ARGS__ }, \
++	.n_reg_rules = ARRAY_SIZE(((struct ieee80211_reg_rule[]) { __VA_ARGS__ }))
++
+ /* Can be used for:
+  * 0x60, 0x61, 0x62 */
+ static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
+-	.n_reg_rules = 5,
+ 	.alpha2 =  "99",
+-	.reg_rules = {
++	REGD_RULES(
+ 		ATH9K_2GHZ_ALL,
+ 		ATH9K_5GHZ_ALL,
+-	}
++	)
+ };
+ 
+ /* Can be used by 0x63 and 0x65 */
+ static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
+-	.n_reg_rules = 4,
+ 	.alpha2 =  "99",
+-	.reg_rules = {
++	REGD_RULES(
+ 		ATH9K_2GHZ_CH01_11,
+ 		ATH9K_2GHZ_CH12_13,
+ 		ATH9K_5GHZ_NO_MIDBAND,
+-	}
++	)
+ };
+ 
+ /* Can be used by 0x64 only */
+ static const struct ieee80211_regdomain ath_world_regdom_64 = {
+-	.n_reg_rules = 3,
+ 	.alpha2 =  "99",
+-	.reg_rules = {
++	REGD_RULES(
+ 		ATH9K_2GHZ_CH01_11,
+ 		ATH9K_5GHZ_NO_MIDBAND,
+-	}
++	)
+ };
+ 
+ /* Can be used by 0x66 and 0x69 */
+ static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
+-	.n_reg_rules = 3,
+ 	.alpha2 =  "99",
+-	.reg_rules = {
++	REGD_RULES(
+ 		ATH9K_2GHZ_CH01_11,
+ 		ATH9K_5GHZ_ALL,
+-	}
++	)
+ };
+ 
+ /* Can be used by 0x67, 0x68, 0x6A and 0x6C */
+ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
+-	.n_reg_rules = 4,
+ 	.alpha2 =  "99",
+-	.reg_rules = {
++	REGD_RULES(
+ 		ATH9K_2GHZ_CH01_11,
+ 		ATH9K_2GHZ_CH12_13,
+ 		ATH9K_5GHZ_ALL,
+-	}
++	)
+ };
+ 
+ static bool dynamic_country_user_possible(struct ath_regulatory *reg)
diff --git a/package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch b/package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch
new file mode 100644
index 0000000000..1ef55456c5
--- /dev/null
+++ b/package/kernel/mac80211/patches/404-regd_no_assoc_hints.patch
@@ -0,0 +1,19 @@
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -2411,6 +2411,8 @@ void regulatory_hint_country_ie(struct w
+ 	enum environment_cap env = ENVIRON_ANY;
+ 	struct regulatory_request *request = NULL, *lr;
+ 
++	return;
++
+ 	/* IE len must be evenly divisible by 2 */
+ 	if (country_ie_len & 0x01)
+ 		return;
+@@ -2617,6 +2619,7 @@ static void restore_regulatory_settings(
+ 
+ void regulatory_hint_disconnect(void)
+ {
++	return;
+ 	pr_debug("All devices are disconnected, going to restore regulatory settings\n");
+ 	restore_regulatory_settings(false);
+ }
diff --git a/package/kernel/mac80211/patches/405-ath_regd_us.patch b/package/kernel/mac80211/patches/405-ath_regd_us.patch
new file mode 100644
index 0000000000..cc55877809
--- /dev/null
+++ b/package/kernel/mac80211/patches/405-ath_regd_us.patch
@@ -0,0 +1,26 @@
+--- a/drivers/net/wireless/ath/regd_common.h
++++ b/drivers/net/wireless/ath/regd_common.h
+@@ -32,6 +32,7 @@ enum EnumRd {
+ 	FCC2_WORLD = 0x21,
+ 	FCC2_ETSIC = 0x22,
+ 	FCC6_WORLD = 0x23,
++	FCC3_FCCA_2 = 0x2A,
+ 	FRANCE_RES = 0x31,
+ 	FCC3_FCCA = 0x3A,
+ 	FCC3_WORLD = 0x3B,
+@@ -167,6 +168,7 @@ static struct reg_dmn_pair_mapping regDo
+ 	{FCC2_WORLD, CTL_FCC, CTL_ETSI},
+ 	{FCC2_ETSIC, CTL_FCC, CTL_ETSI},
+ 	{FCC3_FCCA, CTL_FCC, CTL_FCC},
++	{FCC3_FCCA_2, CTL_FCC, CTL_FCC},
+ 	{FCC3_WORLD, CTL_FCC, CTL_ETSI},
+ 	{FCC4_FCCA, CTL_FCC, CTL_FCC},
+ 	{FCC5_FCCA, CTL_FCC, CTL_FCC},
+@@ -463,6 +465,7 @@ static struct country_code_to_enum_rd al
+ 	{CTRY_UAE, NULL1_WORLD, "AE"},
+ 	{CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"},
+ 	{CTRY_UNITED_STATES, FCC3_FCCA, "US"},
++	{CTRY_UNITED_STATES, FCC3_FCCA_2, "US"},
+ 	/* This "PS" is for US public safety actually... to support this we
+ 	 * would need to assign new special alpha2 to CRDA db as with the world
+ 	 * regdomain and use another alpha2 */
diff --git a/package/kernel/mac80211/patches/406-ath_relax_default_regd.patch b/package/kernel/mac80211/patches/406-ath_relax_default_regd.patch
new file mode 100644
index 0000000000..5b20b4518e
--- /dev/null
+++ b/package/kernel/mac80211/patches/406-ath_relax_default_regd.patch
@@ -0,0 +1,51 @@
+--- a/drivers/net/wireless/ath/regd.c
++++ b/drivers/net/wireless/ath/regd.c
+@@ -114,6 +114,16 @@ static const struct ieee80211_regdomain
+ 	)
+ };
+ 
++static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
++{
++	return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
++}
++
++static bool is_default_regd(struct ath_regulatory *reg)
++{
++	return ath_regd_get_eepromRD(reg) == CTRY_DEFAULT;
++}
++
+ static bool dynamic_country_user_possible(struct ath_regulatory *reg)
+ {
+ 	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
+@@ -122,6 +132,9 @@ static bool dynamic_country_user_possibl
+ 	if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
+ 		return true;
+ 
++	if (is_default_regd(reg))
++		return true;
++
+ 	switch (reg->country_code) {
+ 	case CTRY_UNITED_STATES:
+ 	case CTRY_JAPAN1:
+@@ -207,11 +220,6 @@ static inline bool is_wwr_sku(u16 regd)
+ 		(regd == WORLD));
+ }
+ 
+-static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
+-{
+-	return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
+-}
+-
+ bool ath_is_world_regd(struct ath_regulatory *reg)
+ {
+ 	return is_wwr_sku(ath_regd_get_eepromRD(reg));
+@@ -651,6 +659,9 @@ ath_regd_init_wiphy(struct ath_regulator
+ 	if (IS_ENABLED(CPTCFG_ATH_USER_REGD))
+ 		return 0;
+ 
++	if (is_default_regd(reg))
++		return 0;
++
+ 	wiphy->regulatory_flags |= REGULATORY_STRICT_REG |
+ 				   REGULATORY_CUSTOM_REG;
+ 
diff --git a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
new file mode 100644
index 0000000000..f3f5e1d779
--- /dev/null
+++ b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
@@ -0,0 +1,10 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -731,6 +731,7 @@ static const struct ieee80211_iface_limi
+ 				 BIT(NL80211_IFTYPE_AP) },
+ 	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ 				 BIT(NL80211_IFTYPE_P2P_GO) },
++	{ .max = 1,	.types = BIT(NL80211_IFTYPE_ADHOC) },
+ };
+ 
+ static const struct ieee80211_iface_limit wds_limits[] = {
diff --git a/package/kernel/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch
new file mode 100644
index 0000000000..2a5ab3d428
--- /dev/null
+++ b/package/kernel/mac80211/patches/411-ath5k_allow_adhoc_and_ap.patch
@@ -0,0 +1,46 @@
+--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+@@ -86,13 +86,8 @@ ath5k_add_interface(struct ieee80211_hw
+ 		goto end;
+ 	}
+ 
+-	/* Don't allow other interfaces if one ad-hoc is configured.
+-	 * TODO: Fix the problems with ad-hoc and multiple other interfaces.
+-	 * We would need to operate the HW in ad-hoc mode to allow TSF updates
+-	 * for the IBSS, but this breaks with additional AP or STA interfaces
+-	 * at the moment. */
+-	if (ah->num_adhoc_vifs ||
+-	    (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
++	/* Don't allow more than one ad-hoc interface */
++	if (ah->num_adhoc_vifs && vif->type == NL80211_IFTYPE_ADHOC) {
+ 		ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n");
+ 		ret = -ELNRNG;
+ 		goto end;
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -1965,7 +1965,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
+ 	}
+ 
+ 	if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +
+-			ah->num_mesh_vifs > 1) ||
++			ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) ||
+ 			ah->opmode == NL80211_IFTYPE_MESH_POINT) {
+ 		u64 tsf = ath5k_hw_get_tsf64(ah);
+ 		u32 tsftu = TSF_TO_TU(tsf);
+@@ -2051,7 +2051,7 @@ ath5k_beacon_update_timers(struct ath5k_
+ 
+ 	intval = ah->bintval & AR5K_BEACON_PERIOD;
+ 	if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs
+-		+ ah->num_mesh_vifs > 1) {
++		+ ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) {
+ 		intval /= ATH_BCBUF;	/* staggered multi-bss beacons */
+ 		if (intval < 15)
+ 			ATH5K_WARN(ah, "intval %u is too low, min 15\n",
+@@ -2518,6 +2518,7 @@ static const struct ieee80211_iface_limi
+ 				 BIT(NL80211_IFTYPE_MESH_POINT) |
+ #endif
+ 				 BIT(NL80211_IFTYPE_AP) },
++	{ .max = 1,	.types = BIT(NL80211_IFTYPE_ADHOC) },
+ };
+ 
+ static const struct ieee80211_iface_combination if_comb = {
diff --git a/package/kernel/mac80211/patches/420-ath5k_disable_fast_cc.patch b/package/kernel/mac80211/patches/420-ath5k_disable_fast_cc.patch
new file mode 100644
index 0000000000..414f49508f
--- /dev/null
+++ b/package/kernel/mac80211/patches/420-ath5k_disable_fast_cc.patch
@@ -0,0 +1,18 @@
+--- a/drivers/net/wireless/ath/ath5k/reset.c
++++ b/drivers/net/wireless/ath/ath5k/reset.c
+@@ -1154,6 +1154,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum
+ 	tsf_lo = 0;
+ 	mode = 0;
+ 
++#if 0
+ 	/*
+ 	 * Sanity check for fast flag
+ 	 * Fast channel change only available
+@@ -1161,6 +1162,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum
+ 	 */
+ 	if (fast && (ah->ah_radio != AR5K_RF2413) &&
+ 	(ah->ah_radio != AR5K_RF5413))
++#endif
+ 		fast = false;
+ 
+ 	/* Disable sleep clock operation
diff --git a/package/kernel/mac80211/patches/430-add_ath5k_platform.patch b/package/kernel/mac80211/patches/430-add_ath5k_platform.patch
new file mode 100644
index 0000000000..b213e2a819
--- /dev/null
+++ b/package/kernel/mac80211/patches/430-add_ath5k_platform.patch
@@ -0,0 +1,33 @@
+--- /dev/null
++++ b/include/linux/ath5k_platform.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (c) 2008 Atheros Communications Inc.
++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (c) 2010 Daniel Golle <daniel.golle@gmail.com>
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef _LINUX_ATH5K_PLATFORM_H
++#define _LINUX_ATH5K_PLATFORM_H
++
++#define ATH5K_PLAT_EEP_MAX_WORDS	2048
++
++struct ath5k_platform_data {
++	u16 *eeprom_data;
++	u8 *macaddr;
++};
++
++#endif /* _LINUX_ATH5K_PLATFORM_H */
diff --git a/package/kernel/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch b/package/kernel/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch
new file mode 100644
index 0000000000..cdc9315cd6
--- /dev/null
+++ b/package/kernel/mac80211/patches/431-add_platform_eeprom_support_to_ath5k.patch
@@ -0,0 +1,56 @@
+--- a/drivers/net/wireless/ath/ath5k/pci.c
++++ b/drivers/net/wireless/ath/ath5k/pci.c
+@@ -21,6 +21,7 @@
+ #include <linux/pci-aspm.h>
+ #include <linux/etherdevice.h>
+ #include <linux/module.h>
++#include <linux/ath5k_platform.h>
+ #include "../ath.h"
+ #include "ath5k.h"
+ #include "debug.h"
+@@ -72,7 +73,7 @@ static void ath5k_pci_read_cachesize(str
+ }
+ 
+ /*
+- * Read from eeprom
++ * Read from eeprom or platform_data
+  */
+ static bool
+ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
+@@ -80,6 +81,19 @@ ath5k_pci_eeprom_read(struct ath_common
+ 	struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
+ 	u32 status, timeout;
+ 
++	struct ath5k_platform_data *pdata = NULL;
++
++	if (ah->pdev)
++		pdata = ah->pdev->dev.platform_data;
++
++	if (pdata && pdata->eeprom_data && pdata->eeprom_data[61] == AR5K_EEPROM_MAGIC_VALUE) {
++		if (offset >= ATH5K_PLAT_EEP_MAX_WORDS)
++			return false;
++
++		*data = pdata->eeprom_data[offset];
++		return true;
++	}
++
+ 	/*
+ 	 * Initialize EEPROM access
+ 	 */
+@@ -123,6 +137,16 @@ static int ath5k_pci_eeprom_read_mac(str
+ 	u16 data;
+ 	int octet;
+ 
++	struct ath5k_platform_data *pdata = NULL;
++
++	if (ah->pdev)
++		pdata = ah->pdev->dev.platform_data;
++
++	if (pdata && pdata->macaddr) {
++		memcpy(mac, pdata->macaddr, ETH_ALEN);
++		return 0;
++	}
++
+ 	AR5K_EEPROM_READ(0x20, data);
+ 
+ 	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
diff --git a/package/kernel/mac80211/patches/432-ath5k_add_pciids.patch b/package/kernel/mac80211/patches/432-ath5k_add_pciids.patch
new file mode 100644
index 0000000000..d82f8001d4
--- /dev/null
+++ b/package/kernel/mac80211/patches/432-ath5k_add_pciids.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath5k/pci.c
++++ b/drivers/net/wireless/ath/ath5k/pci.c
+@@ -48,6 +48,8 @@ static const struct pci_device_id ath5k_
+ 	{ PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+ 	{ PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+ 	{ PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
++	{ PCI_VDEVICE(ATHEROS, 0xff16) }, /* 2413,2414 sx76x on lantiq_danube */
++	{ PCI_VDEVICE(ATHEROS, 0xff1a) }, /* 2417 arv45xx on lantiq_danube */
+ 	{ PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */
+ 	{ 0 }
+ };
diff --git a/package/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch b/package/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch
new file mode 100644
index 0000000000..924b62e0d4
--- /dev/null
+++ b/package/kernel/mac80211/patches/440-ath5k_channel_bw_debugfs.patch
@@ -0,0 +1,143 @@
+This adds a bwmode debugfs file which can be used to set alternate
+channel operating bandwidths.  Only tested with AR5413 and only at
+5 and 20 mhz channels.
+
+Signed-off-by: Pat Erley <pat-lkml at erley.org>
+---
+Other devices will need to be added to the switch in  write_file_bwmode
+
+drivers/net/wireless/ath/ath5k/debug.c |   86 ++++++++++++++++++++++++++++++++
+ 1 files changed, 86 insertions(+), 0 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath5k/debug.c
++++ b/drivers/net/wireless/ath/ath5k/debug.c
+@@ -823,6 +823,97 @@ static const struct file_operations fops
+ 	.llseek = default_llseek,
+ };
+ 
++/* debugfs: bwmode */
++
++static ssize_t read_file_bwmode(struct file *file, char __user *user_buf,
++				   size_t count, loff_t *ppos)
++{
++	struct ath5k_hw *ah = file->private_data;
++	char buf[15];
++	unsigned int len = 0;
++
++	int cur_ah_bwmode = ah->ah_bwmode_debug;
++
++#define print_selected(MODE, LABEL) \
++	if (cur_ah_bwmode == MODE) \
++		len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \
++	else \
++		len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \
++	len += snprintf(buf+len, sizeof(buf)-len, " ");
++
++	print_selected(AR5K_BWMODE_5MHZ, "5");
++	print_selected(AR5K_BWMODE_10MHZ, "10");
++	print_selected(AR5K_BWMODE_DEFAULT, "20");
++	print_selected(AR5K_BWMODE_40MHZ, "40");
++#undef print_selected
++
++	len += snprintf(buf+len, sizeof(buf)-len, "\n");
++
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_bwmode(struct file *file,
++				 const char __user *userbuf,
++				 size_t count, loff_t *ppos)
++{
++	struct ath5k_hw *ah = file->private_data;
++	char buf[3];
++	int bw = 20;
++	int tobwmode = AR5K_BWMODE_DEFAULT;
++
++	if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
++		return -EFAULT;
++
++	/* TODO: Add check for active interface */
++
++	if(strncmp(buf, "5", 1) == 0 ) {
++		tobwmode = AR5K_BWMODE_5MHZ;
++		bw = 5;
++	} else if ( strncmp(buf, "10", 2) == 0 ) {
++		tobwmode = AR5K_BWMODE_10MHZ;
++		bw = 10;
++	} else if ( strncmp(buf, "20", 2) == 0 ) {
++		tobwmode = AR5K_BWMODE_DEFAULT;
++		bw = 20;
++	} else if ( strncmp(buf, "40", 2) == 0 ) {
++		tobwmode = AR5K_BWMODE_40MHZ;
++		bw = 40;
++	} else
++		return -EINVAL;
++
++	ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n",
++		bw, tobwmode);
++
++	switch (ah->ah_radio) {
++	/* TODO: only define radios that actually support 5/10mhz channels */
++	case AR5K_RF5413:
++	case AR5K_RF5110:
++	case AR5K_RF5111:
++	case AR5K_RF5112:
++	case AR5K_RF2413:
++	case AR5K_RF2316:
++	case AR5K_RF2317:
++	case AR5K_RF2425:
++		if(ah->ah_bwmode_debug != tobwmode) {
++			mutex_lock(&ah->lock);
++			ah->ah_bwmode = tobwmode;
++			ah->ah_bwmode_debug = tobwmode;
++			mutex_unlock(&ah->lock);
++		}
++		break;
++	default:
++		return -EOPNOTSUPP;
++	}
++	return count;
++}
++
++static const struct file_operations fops_bwmode = {
++	.read = read_file_bwmode,
++	.write = write_file_bwmode,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
+ 
+ /* debugfs: queues etc */
+ 
+@@ -1010,6 +1101,9 @@ ath5k_debug_init_device(struct ath5k_hw
+ 	debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
+ 			    &fops_beacon);
+ 
++	debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah,
++			    &fops_bwmode);
++
+ 	debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
+ 
+ 	debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1372,6 +1372,7 @@ struct ath5k_hw {
+ 	u8			ah_coverage_class;
+ 	bool			ah_ack_bitrate_high;
+ 	u8			ah_bwmode;
++	u8			ah_bwmode_debug;
+ 	bool			ah_short_slot;
+ 
+ 	/* Antenna Control */
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru
+ 		return -EINVAL;
+ 	}
+ 
++	if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT)
++		ah->ah_bwmode = ah->ah_bwmode_debug;
++
+ 	/*
+ 	 * To switch channels clear any pending DMA operations;
+ 	 * wait long enough for the RX fifo to drain, reset the
diff --git a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
new file mode 100644
index 0000000000..f21eed18c3
--- /dev/null
+++ b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
@@ -0,0 +1,65 @@
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1315,6 +1315,53 @@ void ath9k_deinit_debug(struct ath_softc
+ 	ath9k_cmn_spectral_deinit_debug(&sc->spec_priv);
+ }
+ 
++static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
++			     size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath_common *common = ath9k_hw_common(ah);
++	int bytes = 0;
++	int pos = *ppos;
++	int size = 4096;
++	u16 val;
++	int i;
++
++	if (AR_SREV_9300_20_OR_LATER(ah))
++		size = 16384;
++
++	if (*ppos < 0)
++		return -EINVAL;
++
++	if (count > size - *ppos)
++		count = size - *ppos;
++
++	for (i = *ppos / 2; count > 0; count -= bytes, *ppos += bytes, i++) {
++		void *from = &val;
++
++		if (!common->bus_ops->eeprom_read(common, i, &val))
++			val = 0xffff;
++
++		if (*ppos % 2) {
++			from++;
++			bytes = 1;
++		} else if (count == 1) {
++			bytes = 1;
++		} else {
++			bytes = 2;
++		}
++		copy_to_user(user_buf, from, bytes);
++		user_buf += bytes;
++	}
++	return *ppos - pos;
++}
++
++static const struct file_operations fops_eeprom = {
++	.read = read_file_eeprom,
++	.open = simple_open,
++	.owner = THIS_MODULE
++};
++
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+ 	struct ath_common *common = ath9k_hw_common(ah);
+@@ -1334,6 +1381,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 	ath9k_tx99_init_debug(sc);
+ 	ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy);
+ 
++	debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
++			    &fops_eeprom);
+ 	debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy,
+ 				    read_file_dma);
+ 	debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
diff --git a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
new file mode 100644
index 0000000000..c42bba6b0d
--- /dev/null
+++ b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
@@ -0,0 +1,32 @@
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -1034,23 +1034,23 @@ static int __init ath9k_init(void)
+ {
+ 	int error;
+ 
+-	error = ath_pci_init();
++	error = ath_ahb_init();
+ 	if (error < 0) {
+-		pr_err("No PCI devices found, driver not installed\n");
+ 		error = -ENODEV;
+ 		goto err_out;
+ 	}
+ 
+-	error = ath_ahb_init();
++	error = ath_pci_init();
+ 	if (error < 0) {
++		pr_err("No PCI devices found, driver not installed\n");
+ 		error = -ENODEV;
+-		goto err_pci_exit;
++		goto err_ahb_exit;
+ 	}
+ 
+ 	return 0;
+ 
+- err_pci_exit:
+-	ath_pci_exit();
++ err_ahb_exit:
++	ath_ahb_exit();
+  err_out:
+ 	return error;
+ }
diff --git a/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch b/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
new file mode 100644
index 0000000000..d2a3b96570
--- /dev/null
+++ b/package/kernel/mac80211/patches/510-ath9k_intr_mitigation_tweak.patch
@@ -0,0 +1,18 @@
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -390,13 +390,8 @@ static void ath9k_hw_init_config(struct
+ 
+ 	ah->config.rx_intr_mitigation = true;
+ 
+-	if (AR_SREV_9300_20_OR_LATER(ah)) {
+-		ah->config.rimt_last = 500;
+-		ah->config.rimt_first = 2000;
+-	} else {
+-		ah->config.rimt_last = 250;
+-		ah->config.rimt_first = 700;
+-	}
++	ah->config.rimt_last = 250;
++	ah->config.rimt_first = 500;
+ 
+ 	if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
+ 		ah->config.pll_pwrsave = 7;
diff --git a/package/kernel/mac80211/patches/511-ath9k_reduce_rxbuf.patch b/package/kernel/mac80211/patches/511-ath9k_reduce_rxbuf.patch
new file mode 100644
index 0000000000..15b8d7b86b
--- /dev/null
+++ b/package/kernel/mac80211/patches/511-ath9k_reduce_rxbuf.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -88,7 +88,7 @@ int ath_descdma_setup(struct ath_softc *
+ 		(_l) &= ((_sz) - 1);		\
+ 	} while (0)
+ 
+-#define ATH_RXBUF               512
++#define ATH_RXBUF               256
+ #define ATH_TXBUF               512
+ #define ATH_TXBUF_RESERVE       5
+ #define ATH_TXMAXTRY            13
diff --git a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
new file mode 100644
index 0000000000..c98072bac9
--- /dev/null
+++ b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
@@ -0,0 +1,125 @@
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1362,6 +1362,52 @@ static const struct file_operations fops
+ 	.owner = THIS_MODULE
+ };
+ 
++
++static ssize_t read_file_chan_bw(struct file *file, char __user *user_buf,
++			     size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++	char buf[32];
++	unsigned int len;
++
++	len = sprintf(buf, "0x%08x\n", common->chan_bw);
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_chan_bw(struct file *file, const char __user *user_buf,
++			     size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++	unsigned long chan_bw;
++	char buf[32];
++	ssize_t len;
++
++	len = min(count, sizeof(buf) - 1);
++	if (copy_from_user(buf, user_buf, len))
++		return -EFAULT;
++
++	buf[len] = '\0';
++	if (kstrtoul(buf, 0, &chan_bw))
++		return -EINVAL;
++
++	common->chan_bw = chan_bw;
++	if (!test_bit(ATH_OP_INVALID, &common->op_flags))
++		ath9k_ops.config(sc->hw, IEEE80211_CONF_CHANGE_CHANNEL);
++
++	return count;
++}
++
++static const struct file_operations fops_chanbw = {
++	.read = read_file_chan_bw,
++	.write = write_file_chan_bw,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
++
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+ 	struct ath_common *common = ath9k_hw_common(ah);
+@@ -1383,6 +1429,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 
+ 	debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
+ 			    &fops_eeprom);
++	debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++			    sc, &fops_chanbw);
+ 	debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy,
+ 				    read_file_dma);
+ 	debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -151,6 +151,7 @@ struct ath_common {
+ 	int debug_mask;
+ 	enum ath_device_state state;
+ 	unsigned long op_flags;
++	u32 chan_bw;
+ 
+ 	struct ath_ani ani;
+ 
+--- a/drivers/net/wireless/ath/ath9k/common.c
++++ b/drivers/net/wireless/ath/ath9k/common.c
+@@ -296,11 +296,13 @@ EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_ke
+ /*
+  * Update internal channel flags.
+  */
+-static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
++static void ath9k_cmn_update_ichannel(struct ath_common *common,
++				      struct ath9k_channel *ichan,
+ 				      struct cfg80211_chan_def *chandef)
+ {
+ 	struct ieee80211_channel *chan = chandef->chan;
+ 	u16 flags = 0;
++	int width;
+ 
+ 	ichan->channel = chan->center_freq;
+ 	ichan->chan = chan;
+@@ -308,7 +310,19 @@ static void ath9k_cmn_update_ichannel(st
+ 	if (chan->band == NL80211_BAND_5GHZ)
+ 		flags |= CHANNEL_5GHZ;
+ 
+-	switch (chandef->width) {
++	switch (common->chan_bw) {
++	case 5:
++		width = NL80211_CHAN_WIDTH_5;
++		break;
++	case 10:
++		width = NL80211_CHAN_WIDTH_10;
++		break;
++	default:
++		width = chandef->width;
++		break;
++	}
++
++	switch (width) {
+ 	case NL80211_CHAN_WIDTH_5:
+ 		flags |= CHANNEL_QUARTER;
+ 		break;
+@@ -341,10 +355,11 @@ struct ath9k_channel *ath9k_cmn_get_chan
+ 					    struct cfg80211_chan_def *chandef)
+ {
+ 	struct ieee80211_channel *curchan = chandef->chan;
++	struct ath_common *common = ath9k_hw_common(ah);
+ 	struct ath9k_channel *channel;
+ 
+ 	channel = &ah->channels[curchan->hw_value];
+-	ath9k_cmn_update_ichannel(channel, chandef);
++	ath9k_cmn_update_ichannel(common, channel, chandef);
+ 
+ 	return channel;
+ }
diff --git a/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
new file mode 100644
index 0000000000..78b22e71a9
--- /dev/null
+++ b/package/kernel/mac80211/patches/513-ath9k_add_pci_ids.patch
@@ -0,0 +1,30 @@
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -647,6 +647,7 @@ int ath9k_hw_init(struct ath_hw *ah)
+ 
+ 	/* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */
+ 	switch (ah->hw_version.devid) {
++	case AR9300_DEVID_INVALID:
+ 	case AR5416_DEVID_PCI:
+ 	case AR5416_DEVID_PCIE:
+ 	case AR5416_AR9100_DEVID:
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -36,6 +36,7 @@
+ 
+ #define ATHEROS_VENDOR_ID	0x168c
+ 
++#define AR9300_DEVID_INVALID	0xabcd
+ #define AR5416_DEVID_PCI	0x0023
+ #define AR5416_DEVID_PCIE	0x0024
+ #define AR9160_DEVID_PCI	0x0027
+--- a/drivers/net/wireless/ath/ath9k/pci.c
++++ b/drivers/net/wireless/ath/ath9k/pci.c
+@@ -760,6 +760,7 @@ static const struct pci_device_id ath_pc
+ 	  .driver_data = ATH9K_PCI_BT_ANT_DIV },
+ #endif
+ 
++	{ PCI_VDEVICE(ATHEROS, 0xabcd) }, /* PCI-E  internal chip default ID */
+ 	{ 0 }
+ };
+ 
diff --git a/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
new file mode 100644
index 0000000000..6e4962b09d
--- /dev/null
+++ b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
@@ -0,0 +1,160 @@
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -2562,6 +2562,7 @@ struct cfg80211_nan_func {
+  *	(as advertised by the nl80211 feature flag.)
+  * @get_tx_power: store the current TX power into the dbm variable;
+  *	return 0 if successful
++ * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
+  *
+  * @set_wds_peer: set the WDS peer for a WDS interface
+  *
+@@ -2836,6 +2837,7 @@ struct cfg80211_ops {
+ 				enum nl80211_tx_power_setting type, int mbm);
+ 	int	(*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
+ 				int *dbm);
++	int	(*set_antenna_gain)(struct wiphy *wiphy, int dbi);
+ 
+ 	int	(*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+ 				const u8 *addr);
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1319,6 +1319,7 @@ enum ieee80211_smps_mode {
+  *
+  * @power_level: requested transmit power (in dBm), backward compatibility
+  *	value only that is set to the minimum of all interfaces
++ * @max_antenna_gain: maximum antenna gain adjusted by user config (in dBi)
+  *
+  * @chandef: the channel definition to tune to
+  * @radar_enabled: whether radar detection is enabled
+@@ -1339,6 +1340,7 @@ enum ieee80211_smps_mode {
+ struct ieee80211_conf {
+ 	u32 flags;
+ 	int power_level, dynamic_ps_timeout;
++	int max_antenna_gain;
+ 
+ 	u16 listen_interval;
+ 	u8 ps_dtim_period;
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -1937,6 +1937,9 @@ enum nl80211_commands {
+  * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
+  *	See &enum nl80211_nan_match_attributes.
+  *
++ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
++ *	transmit power to stay within regulatory limits. u32, dBi.
++ *
+  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
+  * @NL80211_ATTR_MAX: highest attribute number currently defined
+  * @__NL80211_ATTR_AFTER_LAST: internal use
+@@ -2336,6 +2339,8 @@ enum nl80211_attrs {
+ 	NL80211_ATTR_NAN_FUNC,
+ 	NL80211_ATTR_NAN_MATCH,
+ 
++	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
++
+ 	/* add attributes here, update the policy in nl80211.c */
+ 
+ 	__NL80211_ATTR_AFTER_LAST,
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2406,6 +2406,19 @@ static int ieee80211_get_tx_power(struct
+ 	return 0;
+ }
+ 
++static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
++{
++	struct ieee80211_local *local = wiphy_priv(wiphy);
++
++	if (dbi < 0)
++		return -EINVAL;
++
++	local->user_antenna_gain = dbi;
++	ieee80211_hw_config(local, 0);
++
++	return 0;
++}
++
+ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
+ 				  const u8 *addr)
+ {
+@@ -3633,6 +3646,7 @@ const struct cfg80211_ops mac80211_confi
+ 	.set_wiphy_params = ieee80211_set_wiphy_params,
+ 	.set_tx_power = ieee80211_set_tx_power,
+ 	.get_tx_power = ieee80211_get_tx_power,
++	.set_antenna_gain = ieee80211_set_antenna_gain,
+ 	.set_wds_peer = ieee80211_set_wds_peer,
+ 	.rfkill_poll = ieee80211_rfkill_poll,
+ 	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1363,6 +1363,7 @@ struct ieee80211_local {
+ 	int dynamic_ps_forced_timeout;
+ 
+ 	int user_power_level; /* in dBm, for all interfaces */
++	int user_antenna_gain; /* in dBi */
+ 
+ 	enum ieee80211_smps_mode smps_mode;
+ 
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -93,7 +93,7 @@ static u32 ieee80211_hw_conf_chan(struct
+ 	struct ieee80211_sub_if_data *sdata;
+ 	struct cfg80211_chan_def chandef = {};
+ 	u32 changed = 0;
+-	int power;
++	int power, max_power;
+ 	u32 offchannel_flag;
+ 
+ 	offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
+@@ -150,6 +150,12 @@ static u32 ieee80211_hw_conf_chan(struct
+ 	}
+ 	rcu_read_unlock();
+ 
++	max_power = chandef.chan->max_reg_power;
++	if (local->user_antenna_gain > 0) {
++		max_power -= local->user_antenna_gain;
++		power = min(power, max_power);
++	}
++
+ 	if (local->hw.conf.power_level != power) {
+ 		changed |= IEEE80211_CONF_CHANGE_POWER;
+ 		local->hw.conf.power_level = power;
+@@ -588,6 +594,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+ 					 IEEE80211_RADIOTAP_MCS_HAVE_BW;
+ 	local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
+ 					 IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
++	local->user_antenna_gain = 0;
+ 	local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+ 	local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
+ 	local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -416,6 +416,7 @@ static const struct nla_policy nl80211_p
+ 	[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
+ 	[NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
+ 	[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
++	[NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
+ };
+ 
+ /* policy for the key attributes */
+@@ -2353,6 +2354,20 @@ static int nl80211_set_wiphy(struct sk_b
+ 		if (result)
+ 			return result;
+ 	}
++
++	if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_GAIN]) {
++		int idx, dbi = 0;
++
++		if (!rdev->ops->set_antenna_gain)
++			return -EOPNOTSUPP;
++
++		idx = NL80211_ATTR_WIPHY_ANTENNA_GAIN;
++		dbi = nla_get_u32(info->attrs[idx]);
++
++		result = rdev->ops->set_antenna_gain(&rdev->wiphy, dbi);
++		if (result)
++			return result;
++	}
+ 
+ 	if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
+ 	    info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) {
diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
new file mode 100644
index 0000000000..46f1dea15b
--- /dev/null
+++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
@@ -0,0 +1,267 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -827,6 +827,9 @@ static inline int ath9k_dump_btcoex(stru
+ #ifdef CPTCFG_MAC80211_LEDS
+ void ath_init_leds(struct ath_softc *sc);
+ void ath_deinit_leds(struct ath_softc *sc);
++int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name,
++			const char *trigger, bool active_low);
++
+ #else
+ static inline void ath_init_leds(struct ath_softc *sc)
+ {
+@@ -963,6 +966,13 @@ void ath_ant_comb_scan(struct ath_softc
+ 
+ #define ATH9K_NUM_CHANCTX  2 /* supports 2 operating channels */
+ 
++struct ath_led {
++	struct list_head list;
++	struct ath_softc *sc;
++	const struct gpio_led *gpio;
++	struct led_classdev cdev;
++};
++
+ struct ath_softc {
+ 	struct ieee80211_hw *hw;
+ 	struct device *dev;
+@@ -1015,9 +1025,8 @@ struct ath_softc {
+ 	spinlock_t chan_lock;
+ 
+ #ifdef CPTCFG_MAC80211_LEDS
+-	bool led_registered;
+-	char led_name[32];
+-	struct led_classdev led_cdev;
++	const char *led_default_trigger;
++	struct list_head leds;
+ #endif
+ 
+ #ifdef CPTCFG_ATH9K_DEBUGFS
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -39,61 +39,111 @@ static void ath_fill_led_pin(struct ath_
+ 		else
+ 			ah->led_pin = ATH_LED_PIN_DEF;
+ 	}
++}
++
++static void ath_led_brightness(struct led_classdev *led_cdev,
++			       enum led_brightness brightness)
++{
++	struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
++	struct ath_softc *sc = led->sc;
++
++	ath9k_ps_wakeup(sc);
++	ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
++			  (brightness != LED_OFF) ^ led->gpio->active_low);
++	ath9k_ps_restore(sc);
++}
++
++static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
++{
++	const struct gpio_led *gpio = led->gpio;
++	int ret;
++
++	led->cdev.name = gpio->name;
++	led->cdev.default_trigger = gpio->default_trigger;
++	led->cdev.brightness_set = ath_led_brightness;
++
++	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
++	if (ret < 0)
++		return ret;
++
++	led->sc = sc;
++	list_add(&led->list, &sc->leds);
+ 
+ 	/* Configure gpio for output */
+-	ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led",
++	ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name,
+ 				  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ 
+-	/* LED off, active low */
+-	ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1);
++	/* LED off */
++	ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
++
++	return 0;
+ }
+ 
+-static void ath_led_brightness(struct led_classdev *led_cdev,
+-			       enum led_brightness brightness)
++int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
++			const char *trigger, bool active_low)
+ {
+-	struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
+-	u32 val = (brightness == LED_OFF);
++	struct ath_led *led;
++	struct gpio_led *gpio;
++	char *_name;
++	int ret;
+ 
+-	if (sc->sc_ah->config.led_active_high)
+-		val = !val;
++	led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
++		      GFP_KERNEL);
++	if (!led)
++		return -ENOMEM;
+ 
+-	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
++	led->gpio = gpio = (struct gpio_led *) (led + 1);
++	_name = (char *) (led->gpio + 1);
++
++	strcpy(_name, name);
++	gpio->name = _name;
++	gpio->gpio = gpio_num;
++	gpio->active_low = active_low;
++	gpio->default_trigger = trigger;
++
++	ret = ath_add_led(sc, led);
++	if (unlikely(ret < 0))
++		kfree(led);
++
++	return ret;
+ }
+ 
+ void ath_deinit_leds(struct ath_softc *sc)
+ {
+-	if (!sc->led_registered)
+-		return;
+-
+-	ath_led_brightness(&sc->led_cdev, LED_OFF);
+-	led_classdev_unregister(&sc->led_cdev);
++	struct ath_led *led;
+ 
+-	ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin);
++	while (!list_empty(&sc->leds)) {
++		led = list_first_entry(&sc->leds, struct ath_led, list);
++		list_del(&led->list);
++		ath_led_brightness(&led->cdev, LED_OFF);
++		led_classdev_unregister(&led->cdev);
++		ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
++		kfree(led);
++	}
+ }
+ 
+ void ath_init_leds(struct ath_softc *sc)
+ {
+-	int ret;
++	char led_name[32];
++	const char *trigger;
++
++	INIT_LIST_HEAD(&sc->leds);
+ 
+ 	if (AR_SREV_9100(sc->sc_ah))
+ 		return;
+ 
+ 	ath_fill_led_pin(sc);
+ 
+-	if (!ath9k_led_blink)
+-		sc->led_cdev.default_trigger =
+-			ieee80211_get_radio_led_name(sc->hw);
+-
+-	snprintf(sc->led_name, sizeof(sc->led_name),
+-		"ath9k-%s", wiphy_name(sc->hw->wiphy));
+-	sc->led_cdev.name = sc->led_name;
+-	sc->led_cdev.brightness_set = ath_led_brightness;
++	snprintf(led_name, sizeof(led_name), "ath9k-%s",
++		 wiphy_name(sc->hw->wiphy));
+ 
+-	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
+-	if (ret < 0)
+-		return;
++	if (ath9k_led_blink)
++		trigger = sc->led_default_trigger;
++	else
++		trigger = ieee80211_get_radio_led_name(sc->hw);
+ 
+-	sc->led_registered = true;
++	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
++			   !sc->sc_ah->config.led_active_high);
+ }
+ #endif
+ 
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -946,7 +946,7 @@ int ath9k_init_device(u16 devid, struct
+ 
+ #ifdef CPTCFG_MAC80211_LEDS
+ 	/* must be initialized before ieee80211_register_hw */
+-	sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
++	sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw,
+ 		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink,
+ 		ARRAY_SIZE(ath9k_tpt_blink));
+ #endif
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1407,6 +1407,61 @@ static const struct file_operations fops
+ 	.llseek = default_llseek,
+ };
+ 
++#ifdef CONFIG_MAC80211_LEDS
++
++static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf,
++				   size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	char buf[32], *str, *name, *c;
++	ssize_t len;
++	unsigned int gpio;
++	bool active_low = false;
++
++	len = min(count, sizeof(buf) - 1);
++	if (copy_from_user(buf, ubuf, len))
++		return -EFAULT;
++
++	buf[len] = '\0';
++	name = strchr(buf, ',');
++	if (!name)
++		return -EINVAL;
++
++	*(name++) = 0;
++	if (!*name)
++		return -EINVAL;
++
++	c = strchr(name, '\n');
++	if (c)
++		*c = 0;
++
++	str = buf;
++	if (*str == '!') {
++		str++;
++		active_low = true;
++	}
++
++	if (kstrtouint(str, 0, &gpio) < 0)
++		return -EINVAL;
++
++	if (gpio >= sc->sc_ah->caps.num_gpio_pins)
++		return -EINVAL;
++
++	if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0)
++		return -EINVAL;
++
++	return count;
++}
++
++static const struct file_operations fops_gpio_led = {
++	.write = write_file_gpio_led,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
++#endif
++
+ 
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+@@ -1431,6 +1486,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 			    &fops_eeprom);
+ 	debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ 			    sc, &fops_chanbw);
++#ifdef CONFIG_MAC80211_LEDS
++	debugfs_create_file("gpio_led", S_IWUSR,
++			   sc->debug.debugfs_phy, sc, &fops_gpio_led);
++#endif
+ 	debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy,
+ 				    read_file_dma);
+ 	debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
diff --git a/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch b/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch
new file mode 100644
index 0000000000..35d8e8bd42
--- /dev/null
+++ b/package/kernel/mac80211/patches/531-ath9k_extra_platform_leds.patch
@@ -0,0 +1,71 @@
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -46,6 +46,9 @@ struct ath9k_platform_data {
+ 	int (*external_reset)(void);
+ 
+ 	bool use_eeprom;
++
++	int num_leds;
++	const struct gpio_led *leds;
+ };
+ 
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -15,6 +15,7 @@
+  */
+ 
+ #include "ath9k.h"
++#include <linux/ath9k_platform.h>
+ 
+ /********************************/
+ /*	 LED functions		*/
+@@ -108,6 +109,24 @@ int ath_create_gpio_led(struct ath_softc
+ 	return ret;
+ }
+ 
++static int ath_create_platform_led(struct ath_softc *sc,
++				   const struct gpio_led *gpio)
++{
++	struct ath_led *led;
++	int ret;
++
++	led = kzalloc(sizeof(*led), GFP_KERNEL);
++	if (!led)
++		return -ENOMEM;
++
++	led->gpio = gpio;
++	ret = ath_add_led(sc, led);
++	if (ret < 0)
++		kfree(led);
++
++	return ret;
++}
++
+ void ath_deinit_leds(struct ath_softc *sc)
+ {
+ 	struct ath_led *led;
+@@ -124,8 +143,10 @@ void ath_deinit_leds(struct ath_softc *s
+ 
+ void ath_init_leds(struct ath_softc *sc)
+ {
++	struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ 	char led_name[32];
+ 	const char *trigger;
++	int i;
+ 
+ 	INIT_LIST_HEAD(&sc->leds);
+ 
+@@ -144,6 +165,12 @@ void ath_init_leds(struct ath_softc *sc)
+ 
+ 	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
+ 			   !sc->sc_ah->config.led_active_high);
++
++	if (!pdata)
++		return;
++
++	for (i = 0; i < pdata->num_leds; i++)
++		ath_create_platform_led(sc, &pdata->leds[i]);
+ }
+ #endif
+ 
diff --git a/package/kernel/mac80211/patches/540-ath9k_reduce_ani_interval.patch b/package/kernel/mac80211/patches/540-ath9k_reduce_ani_interval.patch
new file mode 100644
index 0000000000..e899903478
--- /dev/null
+++ b/package/kernel/mac80211/patches/540-ath9k_reduce_ani_interval.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ath/ath9k/ani.h
++++ b/drivers/net/wireless/ath/ath9k/ani.h
+@@ -42,7 +42,7 @@
+ #define ATH9K_ANI_PERIOD                  300
+ 
+ /* in ms */
+-#define ATH9K_ANI_POLLINTERVAL            1000
++#define ATH9K_ANI_POLLINTERVAL            300
+ 
+ #define ATH9K_SIG_FIRSTEP_SETTING_MIN     0
+ #define ATH9K_SIG_FIRSTEP_SETTING_MAX     20
diff --git a/package/kernel/mac80211/patches/541-ath9k_rx_dma_stop_check.patch b/package/kernel/mac80211/patches/541-ath9k_rx_dma_stop_check.patch
new file mode 100644
index 0000000000..c2d2781559
--- /dev/null
+++ b/package/kernel/mac80211/patches/541-ath9k_rx_dma_stop_check.patch
@@ -0,0 +1,28 @@
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -698,7 +698,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
+ {
+ #define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
+ 	struct ath_common *common = ath9k_hw_common(ah);
+-	u32 mac_status, last_mac_status = 0;
++	u32 mac_status = 0, last_mac_status = 0;
+ 	int i;
+ 
+ 	/* Enable access to the DMA observation bus */
+@@ -728,6 +728,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw
+ 	}
+ 
+ 	if (i == 0) {
++		if (!AR_SREV_9300_20_OR_LATER(ah) &&
++		    (mac_status & 0x700) == 0) {
++			/*
++			 * DMA is idle but the MAC is still stuck
++			 * processing events
++			 */
++			*reset = true;
++			return true;
++		}
++
+ 		ath_err(common,
+ 			"DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
+ 			AH_RX_STOP_DMA_TIMEOUT / 1000,
diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
new file mode 100644
index 0000000000..a820e16c88
--- /dev/null
+++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
@@ -0,0 +1,139 @@
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1463,6 +1463,50 @@ static const struct file_operations fops
+ #endif
+ 
+ 
++static ssize_t read_file_diag(struct file *file, char __user *user_buf,
++			     size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	struct ath_hw *ah = sc->sc_ah;
++	char buf[32];
++	unsigned int len;
++
++	len = sprintf(buf, "0x%08lx\n", ah->diag);
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_diag(struct file *file, const char __user *user_buf,
++			     size_t count, loff_t *ppos)
++{
++	struct ath_softc *sc = file->private_data;
++	struct ath_hw *ah = sc->sc_ah;
++	unsigned long diag;
++	char buf[32];
++	ssize_t len;
++
++	len = min(count, sizeof(buf) - 1);
++	if (copy_from_user(buf, user_buf, len))
++		return -EFAULT;
++
++	buf[len] = '\0';
++	if (kstrtoul(buf, 0, &diag))
++		return -EINVAL;
++
++	ah->diag = diag;
++	ath9k_hw_update_diag(ah);
++
++	return count;
++}
++
++static const struct file_operations fops_diag = {
++	.read = read_file_diag,
++	.write = write_file_diag,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
++
+ int ath9k_init_debug(struct ath_hw *ah)
+ {
+ 	struct ath_common *common = ath9k_hw_common(ah);
+@@ -1490,6 +1534,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 	debugfs_create_file("gpio_led", S_IWUSR,
+ 			   sc->debug.debugfs_phy, sc, &fops_gpio_led);
+ #endif
++	debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
++			    sc, &fops_diag);
+ 	debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy,
+ 				    read_file_dma);
+ 	debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -520,6 +520,12 @@ enum {
+ 	ATH9K_RESET_COLD,
+ };
+ 
++enum {
++	ATH_DIAG_DISABLE_RX,
++	ATH_DIAG_DISABLE_TX,
++	ATH_DIAG_TRIGGER_ERROR,
++};
++
+ struct ath9k_hw_version {
+ 	u32 magic;
+ 	u16 devid;
+@@ -805,6 +811,8 @@ struct ath_hw {
+ 	u32 rfkill_polarity;
+ 	u32 ah_flags;
+ 
++	unsigned long diag;
++
+ 	bool reset_power_on;
+ 	bool htc_reset_init;
+ 
+@@ -1067,6 +1075,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
+ bool ath9k_hw_check_alive(struct ath_hw *ah);
+ 
+ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
++void ath9k_hw_update_diag(struct ath_hw *ah);
+ 
+ /* Generic hw timer primitives */
+ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1837,6 +1837,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
+ }
+ EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
+ 
++void ath9k_hw_update_diag(struct ath_hw *ah)
++{
++	if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag))
++		REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
++	else
++		REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
++
++	if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag))
++		REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
++	else
++		REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK);
++}
++EXPORT_SYMBOL(ath9k_hw_update_diag);
++
+ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+ 		   struct ath9k_hw_cal_data *caldata, bool fastcc)
+ {
+@@ -2045,6 +2059,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ 		ar9003_hw_disable_phy_restart(ah);
+ 
+ 	ath9k_hw_apply_gpio_override(ah);
++	ath9k_hw_update_diag(ah);
+ 
+ 	if (AR_SREV_9565(ah) && common->bt_ant_diversity)
+ 		REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -533,6 +533,11 @@ irqreturn_t ath_isr(int irq, void *dev)
+ 	if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
+ 		return IRQ_HANDLED;
+ 
++	if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) {
++		status |= ATH9K_INT_FATAL;
++		clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag);
++	}
++
+ 	/*
+ 	 * If there are no status bits set, then this interrupt was not
+ 	 * for me (should have been caught above).
diff --git a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
new file mode 100644
index 0000000000..a5977b7413
--- /dev/null
+++ b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
@@ -0,0 +1,186 @@
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -721,6 +721,7 @@ struct ath_spec_scan {
+  * @config_pci_powersave:
+  * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+  *
++ * @get_adc_entropy: get entropy from the raw ADC I/Q output
+  * @spectral_scan_config: set parameters for spectral scan and enable/disable it
+  * @spectral_scan_trigger: trigger a spectral scan run
+  * @spectral_scan_wait: wait for a spectral scan run to finish
+@@ -743,6 +744,7 @@ struct ath_hw_ops {
+ 			struct ath_hw_antcomb_conf *antconf);
+ 	void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+ 			struct ath_hw_antcomb_conf *antconf);
++	void (*get_adc_entropy)(struct ath_hw *ah, u8 *buf, size_t len);
+ 	void (*spectral_scan_config)(struct ath_hw *ah,
+ 				     struct ath_spec_scan *param);
+ 	void (*spectral_scan_trigger)(struct ath_hw *ah);
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -1947,6 +1947,26 @@ void ar9003_hw_init_rate_txpower(struct
+ 	}
+ }
+ 
++static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
++{
++	int i, j;
++
++	REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
++	REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
++	REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
++
++	memset(buf, 0, len);
++	for (i = 0; i < len; i++) {
++		for (j = 0; j < 4; j++) {
++			u32 regval = REG_READ(ah, AR_PHY_TST_ADC);
++
++			buf[i] <<= 2;
++			buf[i] |= (regval & 1) | ((regval & BIT(10)) >> 9);
++			udelay(1);
++		}
++	}
++}
++
+ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
+ {
+ 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+@@ -1983,6 +2003,7 @@ void ar9003_hw_attach_phy_ops(struct ath
+ 	priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+ 	priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
+ 
++	ops->get_adc_entropy = ar9003_hw_get_adc_entropy;
+ 	ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
+ 	ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
+ 	ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -719,7 +719,8 @@ static void ath9k_init_txpower_limits(st
+ 	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+ 		ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ);
+ 
+-	ah->curchan = curchan;
++	if (curchan)
++		ah->curchan = curchan;
+ }
+ 
+ static const struct ieee80211_iface_limit if_limits[] = {
+@@ -906,6 +907,18 @@ static void ath9k_set_hw_capab(struct at
+ 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+ }
+ 
++static void ath_get_initial_entropy(struct ath_softc *sc)
++{
++	struct ath_hw *ah = sc->sc_ah;
++	char buf[256];
++
++	/* reuse last channel initialized by the tx power test */
++	ath9k_hw_reset(ah, ah->curchan, NULL, false);
++
++	ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf));
++	add_device_randomness(buf, sizeof(buf));
++}
++
+ int ath9k_init_device(u16 devid, struct ath_softc *sc,
+ 		    const struct ath_bus_ops *bus_ops)
+ {
+@@ -951,6 +964,8 @@ int ath9k_init_device(u16 devid, struct
+ 		ARRAY_SIZE(ath9k_tpt_blink));
+ #endif
+ 
++	ath_get_initial_entropy(sc);
++
+ 	/* Register with mac80211 */
+ 	error = ieee80211_register_hw(hw);
+ 	if (error)
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -100,6 +100,12 @@ static inline void ath9k_hw_tx99_set_txp
+ 		ath9k_hw_ops(ah)->tx99_set_txpower(ah, power);
+ }
+ 
++static inline void ath9k_hw_get_adc_entropy(struct ath_hw *ah,
++		u8 *buf, size_t len)
++{
++	ath9k_hw_ops(ah)->get_adc_entropy(ah, buf, len);
++}
++
+ #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
+ 
+ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -1322,9 +1322,30 @@ void ar5008_hw_init_rate_txpower(struct
+ 	}
+ }
+ 
++static void ar5008_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
++{
++	int i, j;
++
++	REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
++	REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
++	REG_RMW_FIELD(ah, AR_PHY_TEST2, AR_PHY_TEST2_RX_OBS_SEL, 0);
++
++	memset(buf, 0, len);
++	for (i = 0; i < len; i++) {
++		for (j = 0; j < 4; j++) {
++			u32 regval = REG_READ(ah, AR_PHY_TST_ADC);
++
++			buf[i] <<= 2;
++			buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8);
++			udelay(1);
++		}
++	}
++}
++
+ int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+ {
+ 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
++	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+ 	static const u32 ar5416_cca_regs[6] = {
+ 		AR_PHY_CCA,
+ 		AR_PHY_CH1_CCA,
+@@ -1339,6 +1360,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
+ 	if (ret)
+ 	    return ret;
+ 
++	ops->get_adc_entropy = ar5008_hw_get_adc_entropy;
++
+ 	priv_ops->rf_set_freq = ar5008_hw_set_channel;
+ 	priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
+ 
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+@@ -20,6 +20,12 @@
+ #define PHY_AGC_CLR             0x10000000
+ #define RFSILENT_BB             0x00002000
+ 
++#define AR_PHY_TEST_BBB_OBS_SEL       0x780000
++#define AR_PHY_TEST_BBB_OBS_SEL_S     19
++
++#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23
++#define AR_PHY_TEST_RX_OBS_SEL_BIT5   (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S)
++
+ #define AR_PHY_TURBO                0x9804
+ #define AR_PHY_FC_TURBO_MODE        0x00000001
+ #define AR_PHY_FC_TURBO_SHORT       0x00000002
+@@ -36,6 +42,9 @@
+ 
+ #define AR_PHY_TEST2			0x9808
+ 
++#define AR_PHY_TEST2_RX_OBS_SEL        0x3C00
++#define AR_PHY_TEST2_RX_OBS_SEL_S      10
++
+ #define AR_PHY_TIMING2           0x9810
+ #define AR_PHY_TIMING3           0x9814
+ #define AR_PHY_TIMING3_DSC_MAN   0xFFFE0000
+@@ -393,6 +402,8 @@
+ #define AR_PHY_RFBUS_GRANT       0x9C20
+ #define AR_PHY_RFBUS_GRANT_EN    0x00000001
+ 
++#define AR_PHY_TST_ADC      0x9C24
++
+ #define AR_PHY_CHAN_INFO_GAIN_DIFF             0x9CF4
+ #define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
+ 
diff --git a/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
new file mode 100644
index 0000000000..bb4c121af8
--- /dev/null
+++ b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
@@ -0,0 +1,79 @@
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -246,6 +246,19 @@ void ath9k_hw_get_channel_centers(struct
+ 		centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
+ }
+ 
++static inline void ath9k_hw_disable_pll_lock_detect(struct ath_hw *ah)
++{
++	/* On AR9330 and AR9340 devices, some PHY registers must be
++	 * tuned to gain better stability/performance. These registers
++	 * might be changed while doing wlan reset so the registers must
++	 * be reprogrammed after each reset.
++	 */
++	REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, BIT(20));
++	REG_RMW(ah, AR_PHY_USB_CTRL2,
++		(1 << 21) | (0xf << 22),
++		(1 << 21) | (0x3 << 22));
++}
++
+ /******************/
+ /* Chip Revisions */
+ /******************/
+@@ -1413,6 +1426,9 @@ static bool ath9k_hw_set_reset(struct at
+ 		udelay(50);
+ 	}
+ 
++	if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++		ath9k_hw_disable_pll_lock_detect(ah);
++
+ 	return true;
+ }
+ 
+@@ -1512,6 +1528,9 @@ static bool ath9k_hw_chip_reset(struct a
+ 		ar9003_hw_internal_regulator_apply(ah);
+ 	ath9k_hw_init_pll(ah, chan);
+ 
++	if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++		ath9k_hw_disable_pll_lock_detect(ah);
++
+ 	return true;
+ }
+ 
+@@ -1815,8 +1834,14 @@ static int ath9k_hw_do_fastcc(struct ath
+ 	if (AR_SREV_9271(ah))
+ 		ar9002_hw_load_ani_reg(ah, chan);
+ 
++	if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++		ath9k_hw_disable_pll_lock_detect(ah);
++
+ 	return 0;
+ fail:
++	if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++		ath9k_hw_disable_pll_lock_detect(ah);
++
+ 	return -EINVAL;
+ }
+ 
+@@ -2070,6 +2095,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ 		ath9k_hw_set_radar_params(ah);
+ 	}
+ 
++	if (AR_SREV_9330(ah) || AR_SREV_9340(ah))
++		ath9k_hw_disable_pll_lock_detect(ah);
++
+ 	return 0;
+ }
+ EXPORT_SYMBOL(ath9k_hw_reset);
+--- a/drivers/net/wireless/ath/ath9k/phy.h
++++ b/drivers/net/wireless/ath/ath9k/phy.h
+@@ -48,6 +48,9 @@
+ #define AR_PHY_PLL_CONTROL 0x16180
+ #define AR_PHY_PLL_MODE 0x16184
+ 
++#define AR_PHY_USB_CTRL1	0x16c84
++#define AR_PHY_USB_CTRL2	0x16c88
++
+ enum ath9k_ant_div_comb_lna_conf {
+ 	ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
+ 	ATH_ANT_DIV_COMB_LNA2,
diff --git a/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch b/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch
new file mode 100644
index 0000000000..22a2308a0b
--- /dev/null
+++ b/package/kernel/mac80211/patches/545-ath9k_ani_ws_detect.patch
@@ -0,0 +1,155 @@
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -951,55 +951,6 @@ static bool ar5008_hw_ani_control_new(st
+ 		 * on == 0 means more noise imm
+ 		 */
+ 		u32 on = param ? 1 : 0;
+-		/*
+-		 * make register setting for default
+-		 * (weak sig detect ON) come from INI file
+-		 */
+-		int m1ThreshLow = on ?
+-			aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+-		int m2ThreshLow = on ?
+-			aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+-		int m1Thresh = on ?
+-			aniState->iniDef.m1Thresh : m1Thresh_off;
+-		int m2Thresh = on ?
+-			aniState->iniDef.m2Thresh : m2Thresh_off;
+-		int m2CountThr = on ?
+-			aniState->iniDef.m2CountThr : m2CountThr_off;
+-		int m2CountThrLow = on ?
+-			aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+-		int m1ThreshLowExt = on ?
+-			aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+-		int m2ThreshLowExt = on ?
+-			aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+-		int m1ThreshExt = on ?
+-			aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+-		int m2ThreshExt = on ?
+-			aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+-
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+-			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+-			      m1ThreshLow);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+-			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+-			      m2ThreshLow);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+-			      AR_PHY_SFCORR_M1_THRESH, m1Thresh);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+-			      AR_PHY_SFCORR_M2_THRESH, m2Thresh);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+-			      AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+-			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+-			      m2CountThrLow);
+-
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
+ 
+ 		if (on)
+ 			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -42,20 +42,6 @@ static const int cycpwrThr1_table[] =
+ /* level:  0   1   2   3   4   5   6   7   8  */
+ 	{ -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */
+ 
+-/*
+- * register values to turn OFDM weak signal detection OFF
+- */
+-static const int m1ThreshLow_off = 127;
+-static const int m2ThreshLow_off = 127;
+-static const int m1Thresh_off = 127;
+-static const int m2Thresh_off = 127;
+-static const int m2CountThr_off =  31;
+-static const int m2CountThrLow_off =  63;
+-static const int m1ThreshLowExt_off = 127;
+-static const int m2ThreshLowExt_off = 127;
+-static const int m1ThreshExt_off = 127;
+-static const int m2ThreshExt_off = 127;
+-
+ static const u8 ofdm2pwr[] = {
+ 	ALL_TARGET_LEGACY_6_24,
+ 	ALL_TARGET_LEGACY_6_24,
+@@ -1095,11 +1081,6 @@ static bool ar9003_hw_ani_control(struct
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 	struct ath9k_channel *chan = ah->curchan;
+ 	struct ar5416AniState *aniState = &ah->ani;
+-	int m1ThreshLow, m2ThreshLow;
+-	int m1Thresh, m2Thresh;
+-	int m2CountThr, m2CountThrLow;
+-	int m1ThreshLowExt, m2ThreshLowExt;
+-	int m1ThreshExt, m2ThreshExt;
+ 	s32 value, value2;
+ 
+ 	switch (cmd & ah->ani_function) {
+@@ -1113,61 +1094,6 @@ static bool ar9003_hw_ani_control(struct
+ 		 */
+ 		u32 on = param ? 1 : 0;
+ 
+-		if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
+-			goto skip_ws_det;
+-
+-		m1ThreshLow = on ?
+-			aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+-		m2ThreshLow = on ?
+-			aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+-		m1Thresh = on ?
+-			aniState->iniDef.m1Thresh : m1Thresh_off;
+-		m2Thresh = on ?
+-			aniState->iniDef.m2Thresh : m2Thresh_off;
+-		m2CountThr = on ?
+-			aniState->iniDef.m2CountThr : m2CountThr_off;
+-		m2CountThrLow = on ?
+-			aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+-		m1ThreshLowExt = on ?
+-			aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+-		m2ThreshLowExt = on ?
+-			aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+-		m1ThreshExt = on ?
+-			aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+-		m2ThreshExt = on ?
+-			aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+-
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+-			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+-			      m1ThreshLow);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+-			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+-			      m2ThreshLow);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+-			      AR_PHY_SFCORR_M1_THRESH,
+-			      m1Thresh);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+-			      AR_PHY_SFCORR_M2_THRESH,
+-			      m2Thresh);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+-			      AR_PHY_SFCORR_M2COUNT_THR,
+-			      m2CountThr);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+-			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+-			      m2CountThrLow);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+-			      m1ThreshLowExt);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+-			      m2ThreshLowExt);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M1_THRESH,
+-			      m1ThreshExt);
+-		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+-			      AR_PHY_SFCORR_EXT_M2_THRESH,
+-			      m2ThreshExt);
+-skip_ws_det:
+ 		if (on)
+ 			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+ 				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
diff --git a/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch b/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch
new file mode 100644
index 0000000000..ced72c6c69
--- /dev/null
+++ b/package/kernel/mac80211/patches/546-ath9k_platform_led_name.patch
@@ -0,0 +1,39 @@
+From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Date: Sun, 31 Jan 2016 20:45:57 +0100
+Subject: [PATCH v4 1/8] mac80211: ath9k: enable platform WLAN LED name
+
+Enable platform-supplied WLAN LED name for ath9k device. It replaces generic
+'ath9k-phy*' label with string set during platform initialization.
+
+Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+---
+ drivers/net/wireless/ath/ath9k/gpio.c |   10 +++++++---
+ include/linux/ath9k_platform.h        |    1 +
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -155,8 +155,11 @@ void ath_init_leds(struct ath_softc *sc)
+ 
+ 	ath_fill_led_pin(sc);
+ 
+-	snprintf(led_name, sizeof(led_name), "ath9k-%s",
+-		 wiphy_name(sc->hw->wiphy));
++	if (pdata && pdata->led_name)
++		strncpy(led_name, pdata->led_name, sizeof(led_name));
++	else
++		snprintf(led_name, sizeof(led_name), "ath9k-%s",
++			 wiphy_name(sc->hw->wiphy));
+ 
+ 	if (ath9k_led_blink)
+ 		trigger = sc->led_default_trigger;
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -49,6 +49,7 @@ struct ath9k_platform_data {
+ 
+ 	int num_leds;
+ 	const struct gpio_led *leds;
++	const char *led_name;
+ };
+ 
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch b/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch
new file mode 100644
index 0000000000..5d84cf0c42
--- /dev/null
+++ b/package/kernel/mac80211/patches/547-ath9k_led_defstate_fix.patch
@@ -0,0 +1,29 @@
+From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Date: Sun, 31 Jan 2016 20:48:49 +0100
+Subject: [PATCH v4 2/8] mac80211: ath9k: set default state for platform LEDs
+
+Support default state for platform LEDs connected to ath9k device.
+Now LEDs are correctly set on or off at ath9k module initialization.
+Very useful if power LED is connected to wireless chip.
+
+Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+---
+ gpio.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -74,8 +74,11 @@ static int ath_add_led(struct ath_softc
+ 	ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name,
+ 				  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ 
+-	/* LED off */
+-	ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
++	/* Set default LED state */
++	if (gpio->default_state == LEDS_GPIO_DEFSTATE_ON)
++		ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, !gpio->active_low);
++	else
++		ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
+ 
+ 	return 0;
+ }
diff --git a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
new file mode 100644
index 0000000000..1330dfed8b
--- /dev/null
+++ b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
@@ -0,0 +1,234 @@
+From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Date: Sun, 31 Jan 2016 21:01:31 +0100
+Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO
+
+Enable access to GPIO chip and its pins for Atheros AR92xx
+wireless devices. For now AR9285 and AR9287 are supported.
+
+Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -24,6 +24,7 @@
+ #include <linux/completion.h>
+ #include <linux/time.h>
+ #include <linux/hw_random.h>
++#include <linux/gpio/driver.h>
+ 
+ #include "common.h"
+ #include "debug.h"
+@@ -973,6 +974,14 @@ struct ath_led {
+ 	struct led_classdev cdev;
+ };
+ 
++#ifdef CONFIG_GPIOLIB
++struct ath9k_gpio_chip {
++	struct ath_softc *sc;
++	char label[32];
++	struct gpio_chip gchip;
++};
++#endif
++
+ struct ath_softc {
+ 	struct ieee80211_hw *hw;
+ 	struct device *dev;
+@@ -1027,6 +1036,9 @@ struct ath_softc {
+ #ifdef CPTCFG_MAC80211_LEDS
+ 	const char *led_default_trigger;
+ 	struct list_head leds;
++#ifdef CONFIG_GPIOLIB
++	struct ath9k_gpio_chip *gpiochip;
++#endif
+ #endif
+ 
+ #ifdef CPTCFG_ATH9K_DEBUGFS
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -16,13 +16,135 @@
+ 
+ #include "ath9k.h"
+ #include <linux/ath9k_platform.h>
++#include <linux/gpio.h>
++
++#ifdef CPTCFG_MAC80211_LEDS
++
++#ifdef CONFIG_GPIOLIB
++
++/***************/
++/*  GPIO Chip  */
++/***************/
++
++/* gpio_chip handler : set GPIO to input */
++static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	ath9k_hw_gpio_request_in(gc->sc->sc_ah, offset, "ath9k-gpio");
++
++	return 0;
++}
++
++/* gpio_chip handler : set GPIO to output */
++static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset,
++				     int value)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	ath9k_hw_gpio_request_out(gc->sc->sc_ah, offset, "ath9k-gpio",
++				  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++	ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
++
++	return 0;
++}
++
++/* gpio_chip handler : query GPIO direction (0=out, 1=in) */
++static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++	struct ath_hw *ah = gc->sc->sc_ah;
++
++	return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3);
++}
++
++/* gpio_chip handler : get GPIO pin value */
++static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	return ath9k_hw_gpio_get(gc->sc->sc_ah, offset);
++}
++
++/* gpio_chip handler : set GPIO pin to value */
++static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset,
++			       int value)
++{
++	struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip,
++						  gchip);
++
++	ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value);
++}
++
++/* register GPIO chip */
++static void ath9k_register_gpio_chip(struct ath_softc *sc)
++{
++	struct ath9k_gpio_chip *gc;
++	struct ath_hw *ah = sc->sc_ah;
++
++	gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL);
++	if (!gc)
++		return;
++
++	snprintf(gc->label, sizeof(gc->label), "ath9k-%s",
++		 wiphy_name(sc->hw->wiphy));
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)
++	gc->gchip.parent = sc->dev;
++#else
++	gc->gchip.dev = sc->dev;
++#endif
++	gc->gchip.label = gc->label;
++	gc->gchip.base = -1;	/* determine base automatically */
++	gc->gchip.ngpio = ah->caps.num_gpio_pins;
++	gc->gchip.direction_input = ath9k_gpio_pin_cfg_input;
++	gc->gchip.direction_output = ath9k_gpio_pin_cfg_output;
++	gc->gchip.get_direction = ath9k_gpio_pin_get_dir;
++	gc->gchip.get = ath9k_gpio_pin_get;
++	gc->gchip.set = ath9k_gpio_pin_set;
++
++	if (gpiochip_add(&gc->gchip)) {
++		kfree(gc);
++		return;
++	}
++
++	gc->gchip.owner = NULL;
++	sc->gpiochip = gc;
++	gc->sc = sc;
++}
++
++/* remove GPIO chip */
++static void ath9k_unregister_gpio_chip(struct ath_softc *sc)
++{
++	struct ath9k_gpio_chip *gc = sc->gpiochip;
++
++	if (!gc)
++		return;
++
++	gpiochip_remove(&gc->gchip);
++	kfree(gc);
++	sc->gpiochip = NULL;
++}
++
++#else /* CONFIG_GPIOLIB */
++
++static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
++{
++}
++
++static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc)
++{
++}
++
++#endif /* CONFIG_GPIOLIB */
+ 
+ /********************************/
+ /*	 LED functions		*/
+ /********************************/
+ 
+-#ifdef CPTCFG_MAC80211_LEDS
+-
+ static void ath_fill_led_pin(struct ath_softc *sc)
+ {
+ 	struct ath_hw *ah = sc->sc_ah;
+@@ -80,6 +202,12 @@ static int ath_add_led(struct ath_softc
+ 	else
+ 		ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);
+ 
++#ifdef CONFIG_GPIOLIB
++	/* If there is GPIO chip configured, reserve LED pin */
++	if (sc->gpiochip)
++		gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name);
++#endif
++
+ 	return 0;
+ }
+ 
+@@ -136,12 +264,18 @@ void ath_deinit_leds(struct ath_softc *s
+ 
+ 	while (!list_empty(&sc->leds)) {
+ 		led = list_first_entry(&sc->leds, struct ath_led, list);
++#ifdef CONFIG_GPIOLIB
++		/* If there is GPIO chip configured, free LED pin */
++		if (sc->gpiochip)
++			gpio_free(sc->gpiochip->gchip.base + led->gpio->gpio);
++#endif
+ 		list_del(&led->list);
+ 		ath_led_brightness(&led->cdev, LED_OFF);
+ 		led_classdev_unregister(&led->cdev);
+ 		ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio);
+ 		kfree(led);
+ 	}
++	ath9k_unregister_gpio_chip(sc);
+ }
+ 
+ void ath_init_leds(struct ath_softc *sc)
+@@ -158,6 +292,8 @@ void ath_init_leds(struct ath_softc *sc)
+ 
+ 	ath_fill_led_pin(sc);
+ 
++	ath9k_register_gpio_chip(sc);
++
+ 	if (pdata && pdata->led_name)
+ 		strncpy(led_name, pdata->led_name, sizeof(led_name));
+ 	else
+@@ -178,6 +314,7 @@ void ath_init_leds(struct ath_softc *sc)
+ 	for (i = 0; i < pdata->num_leds; i++)
+ 		ath_create_platform_led(sc, &pdata->leds[i]);
+ }
++
+ #endif
+ 
+ /*******************/
diff --git a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
new file mode 100644
index 0000000000..f86b0152ea
--- /dev/null
+++ b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
@@ -0,0 +1,149 @@
+From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Subject: [PATCH v5 5/8] mac80211: ath9k: enable GPIO buttons
+
+Enable platform-defined GPIO button support for ath9k device.
+Key poller is activated for attached platform buttons.
+Requires ath9k GPIO chip access.
+
+Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -1038,6 +1038,7 @@ struct ath_softc {
+ 	struct list_head leds;
+ #ifdef CONFIG_GPIOLIB
+ 	struct ath9k_gpio_chip *gpiochip;
++	struct platform_device *btnpdev;	/* gpio-keys-polled */
+ #endif
+ #endif
+ 
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -17,6 +17,8 @@
+ #include "ath9k.h"
+ #include <linux/ath9k_platform.h>
+ #include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/gpio_keys.h>
+ 
+ #ifdef CPTCFG_MAC80211_LEDS
+ 
+@@ -129,6 +131,64 @@ static void ath9k_unregister_gpio_chip(s
+ 	sc->gpiochip = NULL;
+ }
+ 
++/******************/
++/*  GPIO Buttons  */
++/******************/
++
++/* add GPIO buttons */
++static void ath9k_init_buttons(struct ath_softc *sc)
++{
++	struct ath9k_platform_data *pdata = sc->dev->platform_data;
++	struct platform_device *pdev;
++	struct gpio_keys_platform_data gkpdata;
++	struct gpio_keys_button *bt;
++	int i;
++
++	if (!sc->gpiochip)
++		return;
++
++	if (!pdata || !pdata->btns || !pdata->num_btns)
++		return;
++
++	bt = devm_kmemdup(sc->dev, pdata->btns,
++			  pdata->num_btns * sizeof(struct gpio_keys_button),
++			  GFP_KERNEL);
++	if (!bt)
++		return;
++
++	for (i = 0; i < pdata->num_btns; i++) {
++		ath9k_hw_gpio_request_in(sc->sc_ah, pdata->btns[i].gpio,
++					 "ath9k-gpio");
++		bt[i].gpio = sc->gpiochip->gchip.base + pdata->btns[i].gpio;
++	}
++
++	memset(&gkpdata, 0, sizeof(struct gpio_keys_platform_data));
++	gkpdata.buttons = bt;
++	gkpdata.nbuttons = pdata->num_btns;
++	gkpdata.poll_interval = pdata->btn_poll_interval;
++
++	pdev = platform_device_register_data(sc->dev, "gpio-keys-polled",
++					     PLATFORM_DEVID_AUTO, &gkpdata,
++					     sizeof(gkpdata));
++	if (!IS_ERR_OR_NULL(pdev))
++		sc->btnpdev = pdev;
++	else {
++		sc->btnpdev = NULL;
++		devm_kfree(sc->dev, bt);
++	}
++}
++
++/* remove GPIO buttons */
++static void ath9k_deinit_buttons(struct ath_softc *sc)
++{
++	if (!sc->gpiochip || !sc->btnpdev)
++		return;
++
++	platform_device_unregister(sc->btnpdev);
++
++	sc->btnpdev = NULL;
++}
++
+ #else /* CONFIG_GPIOLIB */
+ 
+ static inline void ath9k_register_gpio_chip(struct ath_softc *sc)
+@@ -139,6 +199,14 @@ static inline void ath9k_unregister_gpio
+ {
+ }
+ 
++static inline void ath9k_init_buttons(struct ath_softc *sc)
++{
++}
++
++static inline void ath9k_deinit_buttons(struct ath_softc *sc)
++{
++}
++
+ #endif /* CONFIG_GPIOLIB */
+ 
+ /********************************/
+@@ -262,6 +330,7 @@ void ath_deinit_leds(struct ath_softc *s
+ {
+ 	struct ath_led *led;
+ 
++	ath9k_deinit_buttons(sc);
+ 	while (!list_empty(&sc->leds)) {
+ 		led = list_first_entry(&sc->leds, struct ath_led, list);
+ #ifdef CONFIG_GPIOLIB
+@@ -293,6 +362,7 @@ void ath_init_leds(struct ath_softc *sc)
+ 	ath_fill_led_pin(sc);
+ 
+ 	ath9k_register_gpio_chip(sc);
++	ath9k_init_buttons(sc);
+ 
+ 	if (pdata && pdata->led_name)
+ 		strncpy(led_name, pdata->led_name, sizeof(led_name));
+@@ -308,7 +378,7 @@ void ath_init_leds(struct ath_softc *sc)
+ 	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger,
+ 			   !sc->sc_ah->config.led_active_high);
+ 
+-	if (!pdata)
++	if (!pdata || !pdata->leds || !pdata->num_leds)
+ 		return;
+ 
+ 	for (i = 0; i < pdata->num_leds; i++)
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -50,6 +50,10 @@ struct ath9k_platform_data {
+ 	int num_leds;
+ 	const struct gpio_led *leds;
+ 	const char *led_name;
++
++	unsigned num_btns;
++	const struct gpio_keys_button *btns;
++	unsigned btn_poll_interval;
+ };
+ 
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/package/kernel/mac80211/patches/550-ath9k-Add-a-define-for-the-EEPROM-eepmisc-endianness.patch b/package/kernel/mac80211/patches/550-ath9k-Add-a-define-for-the-EEPROM-eepmisc-endianness.patch
new file mode 100644
index 0000000000..a17f95682f
--- /dev/null
+++ b/package/kernel/mac80211/patches/550-ath9k-Add-a-define-for-the-EEPROM-eepmisc-endianness.patch
@@ -0,0 +1,95 @@
+From 9692ab1ff30ae0abc1000d11b2f929b6e2e4cb7f Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:07 +0200
+Subject: [v2 PATCH 1/7] ath9k: Add a #define for the EEPROM "eepmisc" endianness
+ bit
+
+This replaces a magic number with a named #define. Additionally it
+removes two "eeprom format" specific #defines for the "big endianness"
+bit which are the same on all eeprom formats.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 3 ++-
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.h | 1 -
+ drivers/net/wireless/ath/ath9k/eeprom.h        | 4 +++-
+ drivers/net/wireless/ath/ath9k/eeprom_4k.c     | 2 +-
+ drivers/net/wireless/ath/ath9k/eeprom_9287.c   | 2 +-
+ drivers/net/wireless/ath/ath9k/eeprom_def.c    | 2 +-
+ 6 files changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -3468,7 +3468,8 @@ static u32 ath9k_hw_ar9003_dump_eeprom(s
+ 					AR5416_OPFLAGS_N_5G_HT20));
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+-	PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01));
++	PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc &
++				AR5416_EEPMISC_BIG_ENDIAN));
+ 	PR_EEP("RF Silent", pBase->rfSilent);
+ 	PR_EEP("BT option", pBase->blueToothOptions);
+ 	PR_EEP("Device Cap", pBase->deviceCap);
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+@@ -38,7 +38,6 @@
+ #define AR9300_NUM_CTLS_2G           12
+ #define AR9300_NUM_BAND_EDGES_5G     8
+ #define AR9300_NUM_BAND_EDGES_2G     4
+-#define AR9300_EEPMISC_BIG_ENDIAN    0x01
+ #define AR9300_EEPMISC_WOW           0x02
+ #define AR9300_CUSTOMER_DATA_SIZE    20
+ 
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -161,6 +161,9 @@
+ #define AR5416_EEP_TXGAIN_ORIGINAL         0
+ #define AR5416_EEP_TXGAIN_HIGH_POWER       1
+ 
++/* Endianness of EEPROM content */
++#define AR5416_EEPMISC_BIG_ENDIAN          0x01
++
+ #define AR5416_EEP4K_START_LOC                64
+ #define AR5416_EEP4K_NUM_2G_CAL_PIERS         3
+ #define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
+@@ -191,7 +194,6 @@
+ #define AR9287_NUM_CTLS              	12
+ #define AR9287_NUM_BAND_EDGES        	4
+ #define AR9287_PD_GAIN_ICEPTS           1
+-#define AR9287_EEPMISC_BIG_ENDIAN       0x01
+ #define AR9287_EEPMISC_WOW              0x02
+ #define AR9287_MAX_CHAINS               2
+ #define AR9287_ANT_16S                  32
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -154,7 +154,7 @@ static u32 ath9k_hw_4k_dump_eeprom(struc
+ 					AR5416_OPFLAGS_N_5G_HT20));
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+-	PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
++	PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
+ 	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+ 	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+ 	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -150,7 +150,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(s
+ 					AR5416_OPFLAGS_N_5G_HT20));
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+-	PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
++	PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
+ 	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+ 	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+ 	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -232,7 +232,7 @@ static u32 ath9k_hw_def_dump_eeprom(stru
+ 					AR5416_OPFLAGS_N_5G_HT20));
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+-	PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
++	PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
+ 	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+ 	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+ 	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
diff --git a/package/kernel/mac80211/patches/551-ath9k-indicate-that-the-AR9003-EEPROM-template-value.patch b/package/kernel/mac80211/patches/551-ath9k-indicate-that-the-AR9003-EEPROM-template-value.patch
new file mode 100644
index 0000000000..a4a3595531
--- /dev/null
+++ b/package/kernel/mac80211/patches/551-ath9k-indicate-that-the-AR9003-EEPROM-template-value.patch
@@ -0,0 +1,78 @@
+From e88ab4a2649d0fbf675193fb2c176f65375bdd2d Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:08 +0200
+Subject: [v2 PATCH 2/7] ath9k: indicate that the AR9003 EEPROM template values
+ are little endian
+
+The eepMisc field was not set explicitly. The default value of 0 means
+that the values in the EEPROM (template) should be interpreted as little
+endian. However, this is not clear until comparing the AR9003 code with
+the other EEPROM formats.
+To make the code easier to understand we explicitly state that the values
+are little endian - there are no functional changes with this patch.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 10 +++++-----
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.h |  3 +++
+ 2 files changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -53,7 +53,7 @@ static const struct ar9300_eeprom ar9300
+ 		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+ 		.opCapFlags = {
+ 			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+-			.eepMisc = 0,
++			.eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN,
+ 		},
+ 		.rfSilent = 0,
+ 		.blueToothOptions = 0,
+@@ -631,7 +631,7 @@ static const struct ar9300_eeprom ar9300
+ 		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+ 		.opCapFlags = {
+ 			.opFlags = AR5416_OPFLAGS_11A,
+-			.eepMisc = 0,
++			.eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN,
+ 		},
+ 		.rfSilent = 0,
+ 		.blueToothOptions = 0,
+@@ -1210,7 +1210,7 @@ static const struct ar9300_eeprom ar9300
+ 		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+ 		.opCapFlags = {
+ 			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+-			.eepMisc = 0,
++			.eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN,
+ 		},
+ 		.rfSilent = 0,
+ 		.blueToothOptions = 0,
+@@ -1789,7 +1789,7 @@ static const struct ar9300_eeprom ar9300
+ 		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+ 		.opCapFlags = {
+ 			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+-			.eepMisc = 0,
++			.eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN,
+ 		},
+ 		.rfSilent = 0,
+ 		.blueToothOptions = 0,
+@@ -2367,7 +2367,7 @@ static const struct ar9300_eeprom ar9300
+ 		.txrxMask =  0x33, /* 4 bits tx and 4 bits rx */
+ 		.opCapFlags = {
+ 			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+-			.eepMisc = 0,
++			.eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN,
+ 		},
+ 		.rfSilent = 0,
+ 		.blueToothOptions = 0,
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+@@ -69,6 +69,9 @@
+ #define AR9300_BASE_ADDR 0x3ff
+ #define AR9300_BASE_ADDR_512 0x1ff
+ 
++/* AR5416_EEPMISC_BIG_ENDIAN not set indicates little endian */
++#define AR9300_EEPMISC_LITTLE_ENDIAN 0
++
+ #define AR9300_OTP_BASE \
+ 		((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
+ #define AR9300_OTP_STATUS \
diff --git a/package/kernel/mac80211/patches/552-ath9k-Add-an-eeprom_ops-callback-for-retrieving-the-.patch b/package/kernel/mac80211/patches/552-ath9k-Add-an-eeprom_ops-callback-for-retrieving-the-.patch
new file mode 100644
index 0000000000..1b4dd3d134
--- /dev/null
+++ b/package/kernel/mac80211/patches/552-ath9k-Add-an-eeprom_ops-callback-for-retrieving-the-.patch
@@ -0,0 +1,117 @@
+From e8f60fa28e619ad238457ac84fb292541be180d3 Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:09 +0200
+Subject: [v2 PATCH 3/7] ath9k: Add an eeprom_ops callback for retrieving the
+ eepmisc value
+
+This allows deciding if we have to swap the EEPROM data (so it matches
+the system's native endianness) even if no byte-swapping (swab16, based on
+the first two bytes in the EEPROM) is needed.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 +++++++-
+ drivers/net/wireless/ath/ath9k/eeprom.h        | 1 +
+ drivers/net/wireless/ath/ath9k/eeprom_4k.c     | 8 +++++++-
+ drivers/net/wireless/ath/ath9k/eeprom_9287.c   | 8 +++++++-
+ drivers/net/wireless/ath/ath9k/eeprom_def.c    | 8 +++++++-
+ 5 files changed, 29 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -5498,6 +5498,11 @@ unsigned int ar9003_get_paprd_scale_fact
+ 	}
+ }
+ 
++static u8 ar9003_get_eepmisc(struct ath_hw *ah)
++{
++	return ah->eeprom.map4k.baseEepHeader.eepMisc;
++}
++
+ const struct eeprom_ops eep_ar9300_ops = {
+ 	.check_eeprom = ath9k_hw_ar9300_check_eeprom,
+ 	.get_eeprom = ath9k_hw_ar9300_get_eeprom,
+@@ -5508,5 +5513,6 @@ const struct eeprom_ops eep_ar9300_ops =
+ 	.set_board_values = ath9k_hw_ar9300_set_board_values,
+ 	.set_addac = ath9k_hw_ar9300_set_addac,
+ 	.set_txpower = ath9k_hw_ar9300_set_txpower,
+-	.get_spur_channel = ath9k_hw_ar9300_get_spur_channel
++	.get_spur_channel = ath9k_hw_ar9300_get_spur_channel,
++	.get_eepmisc = ar9003_get_eepmisc
+ };
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -655,6 +655,7 @@ struct eeprom_ops {
+ 			   u16 cfgCtl, u8 twiceAntennaReduction,
+ 			   u8 powerLimit, bool test);
+ 	u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
++	u8 (*get_eepmisc)(struct ath_hw *ah);
+ };
+ 
+ void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val);
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -1064,6 +1064,11 @@ static u16 ath9k_hw_4k_get_spur_channel(
+ 	return ah->eeprom.map4k.modalHeader.spurChans[i].spurChan;
+ }
+ 
++static u8 ath9k_hw_4k_get_eepmisc(struct ath_hw *ah)
++{
++	return ah->eeprom.map4k.baseEepHeader.eepMisc;
++}
++
+ const struct eeprom_ops eep_4k_ops = {
+ 	.check_eeprom		= ath9k_hw_4k_check_eeprom,
+ 	.get_eeprom		= ath9k_hw_4k_get_eeprom,
+@@ -1073,5 +1078,6 @@ const struct eeprom_ops eep_4k_ops = {
+ 	.get_eeprom_rev		= ath9k_hw_4k_get_eeprom_rev,
+ 	.set_board_values	= ath9k_hw_4k_set_board_values,
+ 	.set_txpower		= ath9k_hw_4k_set_txpower,
+-	.get_spur_channel	= ath9k_hw_4k_get_spur_channel
++	.get_spur_channel	= ath9k_hw_4k_get_spur_channel,
++	.get_eepmisc		= ath9k_hw_4k_get_eepmisc
+ };
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -986,6 +986,11 @@ static u16 ath9k_hw_ar9287_get_spur_chan
+ 	return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
+ }
+ 
++static u8 ath9k_hw_ar9287_get_eepmisc(struct ath_hw *ah)
++{
++	return ah->eeprom.map9287.baseEepHeader.eepMisc;
++}
++
+ const struct eeprom_ops eep_ar9287_ops = {
+ 	.check_eeprom		= ath9k_hw_ar9287_check_eeprom,
+ 	.get_eeprom		= ath9k_hw_ar9287_get_eeprom,
+@@ -995,5 +1000,6 @@ const struct eeprom_ops eep_ar9287_ops =
+ 	.get_eeprom_rev		= ath9k_hw_ar9287_get_eeprom_rev,
+ 	.set_board_values	= ath9k_hw_ar9287_set_board_values,
+ 	.set_txpower		= ath9k_hw_ar9287_set_txpower,
+-	.get_spur_channel	= ath9k_hw_ar9287_get_spur_channel
++	.get_spur_channel	= ath9k_hw_ar9287_get_spur_channel,
++	.get_eepmisc		= ath9k_hw_ar9287_get_eepmisc
+ };
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -1317,6 +1317,11 @@ static u16 ath9k_hw_def_get_spur_channel
+ 	return ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan;
+ }
+ 
++static u8 ath9k_hw_def_get_eepmisc(struct ath_hw *ah)
++{
++	return ah->eeprom.def.baseEepHeader.eepMisc;
++}
++
+ const struct eeprom_ops eep_def_ops = {
+ 	.check_eeprom		= ath9k_hw_def_check_eeprom,
+ 	.get_eeprom		= ath9k_hw_def_get_eeprom,
+@@ -1327,5 +1332,6 @@ const struct eeprom_ops eep_def_ops = {
+ 	.set_board_values	= ath9k_hw_def_set_board_values,
+ 	.set_addac		= ath9k_hw_def_set_addac,
+ 	.set_txpower		= ath9k_hw_def_set_txpower,
+-	.get_spur_channel	= ath9k_hw_def_get_spur_channel
++	.get_spur_channel	= ath9k_hw_def_get_spur_channel,
++	.get_eepmisc		= ath9k_hw_def_get_eepmisc
+ };
diff --git a/package/kernel/mac80211/patches/553-ath9k-replace-eeprom_param-EEP_MINOR_REV-with-get_ee.patch b/package/kernel/mac80211/patches/553-ath9k-replace-eeprom_param-EEP_MINOR_REV-with-get_ee.patch
new file mode 100644
index 0000000000..277aa6f61c
--- /dev/null
+++ b/package/kernel/mac80211/patches/553-ath9k-replace-eeprom_param-EEP_MINOR_REV-with-get_ee.patch
@@ -0,0 +1,117 @@
+From 9f247f908d5166e16e1cc6a50b0901e0f6733410 Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:10 +0200
+Subject: [v2 PATCH 4/7] ath9k: replace eeprom_param EEP_MINOR_REV with
+ get_eeprom_rev
+
+get_eeprom(ah, EEP_MINOR_REV) and get_eeprom_rev(ah) are both doing the
+same thing: returning the EEPROM revision (12 lowest bits). Make the
+code consistent by using get_eeprom_rev(ah) everywhere.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/ar5008_phy.c  | 2 +-
+ drivers/net/wireless/ath/ath9k/ar9002_hw.c   | 6 ++----
+ drivers/net/wireless/ath/ath9k/eeprom.h      | 1 -
+ drivers/net/wireless/ath/ath9k/eeprom_4k.c   | 5 -----
+ drivers/net/wireless/ath/ath9k/eeprom_9287.c | 6 +-----
+ drivers/net/wireless/ath/ath9k/eeprom_def.c  | 2 --
+ 6 files changed, 4 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -524,7 +524,7 @@ static bool ar5008_hw_set_rf_regs(struct
+ 		return true;
+ 
+ 	/* Setup rf parameters */
+-	eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
++	eepMinorRev = ah->eep_ops->get_eeprom_rev(ah);
+ 
+ 	for (i = 0; i < ah->iniBank6.ia_rows; i++)
+ 		ah->analogBank6Data[i] = INI_RA(&ah->iniBank6, i, modesIndex);
+--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+@@ -108,8 +108,7 @@ static void ar9280_20_hw_init_rxgain_ini
+ {
+ 	u32 rxgain_type;
+ 
+-	if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
+-	    AR5416_EEP_MINOR_VER_17) {
++	if (ah->eep_ops->get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_17) {
+ 		rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
+ 
+ 		if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+@@ -129,8 +128,7 @@ static void ar9280_20_hw_init_rxgain_ini
+ 
+ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type)
+ {
+-	if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
+-	    AR5416_EEP_MINOR_VER_19) {
++	if (ah->eep_ops->get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19) {
+ 		if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+ 			INIT_INI_ARRAY(&ah->iniModesTxGain,
+ 				       ar9280Modes_high_power_tx_gain_9280_2);
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -230,7 +230,6 @@ enum eeprom_param {
+ 	EEP_DB_5,
+ 	EEP_OB_2,
+ 	EEP_DB_2,
+-	EEP_MINOR_REV,
+ 	EEP_TX_MASK,
+ 	EEP_RX_MASK,
+ 	EEP_FSTCLK_5G,
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -254,9 +254,6 @@ static u32 ath9k_hw_4k_get_eeprom(struct
+ 	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ 	struct modal_eep_4k_header *pModal = &eep->modalHeader;
+ 	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+-	u16 ver_minor;
+-
+-	ver_minor = pBase->version & AR5416_EEP_VER_MINOR_MASK;
+ 
+ 	switch (param) {
+ 	case EEP_NFTHRESH_2:
+@@ -279,8 +276,6 @@ static u32 ath9k_hw_4k_get_eeprom(struct
+ 		return pModal->ob_0;
+ 	case EEP_DB_2:
+ 		return pModal->db1_1;
+-	case EEP_MINOR_REV:
+-		return ver_minor;
+ 	case EEP_TX_MASK:
+ 		return pBase->txMask;
+ 	case EEP_RX_MASK:
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -250,9 +250,7 @@ static u32 ath9k_hw_ar9287_get_eeprom(st
+ 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ 	struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+ 	struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
+-	u16 ver_minor;
+-
+-	ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
++	u16 ver_minor = ath9k_hw_ar9287_get_eeprom_rev(ah);
+ 
+ 	switch (param) {
+ 	case EEP_NFTHRESH_2:
+@@ -271,8 +269,6 @@ static u32 ath9k_hw_ar9287_get_eeprom(st
+ 		return pBase->opCapFlags;
+ 	case EEP_RF_SILENT:
+ 		return pBase->rfSilent;
+-	case EEP_MINOR_REV:
+-		return ver_minor;
+ 	case EEP_TX_MASK:
+ 		return pBase->txMask;
+ 	case EEP_RX_MASK:
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -380,8 +380,6 @@ static u32 ath9k_hw_def_get_eeprom(struc
+ 		return pModal[1].ob;
+ 	case EEP_DB_2:
+ 		return pModal[1].db;
+-	case EEP_MINOR_REV:
+-		return AR5416_VER_MASK;
+ 	case EEP_TX_MASK:
+ 		return pBase->txMask;
+ 	case EEP_RX_MASK:
diff --git a/package/kernel/mac80211/patches/554-ath9k-consistently-use-get_eeprom_rev-ah.patch b/package/kernel/mac80211/patches/554-ath9k-consistently-use-get_eeprom_rev-ah.patch
new file mode 100644
index 0000000000..64e70467a3
--- /dev/null
+++ b/package/kernel/mac80211/patches/554-ath9k-consistently-use-get_eeprom_rev-ah.patch
@@ -0,0 +1,342 @@
+From c763af71bcc2f01bd5ef6e65c7c34b46c7235a16 Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:11 +0200
+Subject: [v2 PATCH 5/7] ath9k: consistently use get_eeprom_rev(ah)
+
+The AR5416_VER_MASK macro does the same as get_eeprom_rev, except that
+one has to know the actual EEPROM type (and providing a reference to
+that in a variable named "eep"). Additionally the eeprom_*.c
+implementations used the same shifting logic multiple times to get the
+eeprom revision which was also unnecessary duplication of
+get_eeprom_rev.
+
+Also use the AR5416_EEP_VER_MINOR_MASK macro where needed and introduce
+a similar macro (AR5416_EEP_VER_MAJOR_MASK) for the major version.
+Finally drop AR9287_EEP_VER_MINOR_MASK since it simply duplicates the
+already defined AR5416_EEP_VER_MINOR_MASK.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/eeprom.h      |  4 +--
+ drivers/net/wireless/ath/ath9k/eeprom_4k.c   | 32 ++++++++++------------
+ drivers/net/wireless/ath/ath9k/eeprom_9287.c | 19 +++++++------
+ drivers/net/wireless/ath/ath9k/eeprom_def.c  | 41 +++++++++++++++-------------
+ drivers/net/wireless/ath/ath9k/xmit.c        |  3 +-
+ 5 files changed, 52 insertions(+), 47 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -99,7 +99,6 @@
+ #define FBIN2FREQ(x, y)		((y) ? (2300 + x) : (4800 + 5 * x))
+ #define ath9k_hw_use_flash(_ah)	(!(_ah->ah_flags & AH_USE_EEPROM))
+ 
+-#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
+ #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
+ 				 ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+ #define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \
+@@ -121,6 +120,8 @@
+ 
+ #define AR5416_EEP_NO_BACK_VER       0x1
+ #define AR5416_EEP_VER               0xE
++#define AR5416_EEP_VER_MAJOR_SHIFT   12
++#define AR5416_EEP_VER_MAJOR_MASK    0xF000
+ #define AR5416_EEP_VER_MINOR_MASK    0x0FFF
+ #define AR5416_EEP_MINOR_VER_2       0x2
+ #define AR5416_EEP_MINOR_VER_3       0x3
+@@ -177,7 +178,6 @@
+ #define AR9280_TX_GAIN_TABLE_SIZE 22
+ 
+ #define AR9287_EEP_VER               0xE
+-#define AR9287_EEP_VER_MINOR_MASK    0xFFF
+ #define AR9287_EEP_MINOR_VER_1       0x1
+ #define AR9287_EEP_MINOR_VER_2       0x2
+ #define AR9287_EEP_MINOR_VER_3       0x3
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -20,12 +20,17 @@
+ 
+ static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
+ {
+-	return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF);
++	u16 version = ah->eeprom.map4k.baseEepHeader.version;
++
++	return (version & AR5416_EEP_VER_MAJOR_MASK) >>
++		AR5416_EEP_VER_MAJOR_SHIFT;
+ }
+ 
+ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
+ {
+-	return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
++	u16 version = ah->eeprom.map4k.baseEepHeader.version;
++
++	return version & AR5416_EEP_VER_MINOR_MASK;
+ }
+ 
+ #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+@@ -136,8 +141,8 @@ static u32 ath9k_hw_4k_dump_eeprom(struc
+ 		goto out;
+ 	}
+ 
+-	PR_EEP("Major Version", pBase->version >> 12);
+-	PR_EEP("Minor Version", pBase->version & 0xFFF);
++	PR_EEP("Major Version", ath9k_hw_4k_get_eeprom_ver(ah));
++	PR_EEP("Minor Version", ath9k_hw_4k_get_eeprom_rev(ah));
+ 	PR_EEP("Checksum", pBase->checksum);
+ 	PR_EEP("Length", pBase->length);
+ 	PR_EEP("RegDomain1", pBase->regDmn[0]);
+@@ -314,14 +319,12 @@ static void ath9k_hw_set_4k_power_cal_ta
+ 
+ 	xpdMask = pEepData->modalHeader.xpdGain;
+ 
+-	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-	    AR5416_EEP_MINOR_VER_2) {
++	if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2)
+ 		pdGainOverlap_t2 =
+ 			pEepData->modalHeader.pdGainOverlap;
+-	} else {
++	else
+ 		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ 					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+-	}
+ 
+ 	pCalBChans = pEepData->calFreqPier2G;
+ 	numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS;
+@@ -607,10 +610,8 @@ static void ath9k_hw_4k_set_txpower(stru
+ 
+ 	memset(ratesArray, 0, sizeof(ratesArray));
+ 
+-	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-	    AR5416_EEP_MINOR_VER_2) {
++	if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2)
+ 		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+-	}
+ 
+ 	ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+ 					     &ratesArray[0], cfgCtl,
+@@ -730,8 +731,7 @@ static void ath9k_hw_4k_set_gain(struct
+ 		SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF),
+ 		AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF);
+ 
+-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-	    AR5416_EEP_MINOR_VER_3) {
++	if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) {
+ 		txRxAttenLocal = pModal->txRxAttenCh[0];
+ 
+ 		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+@@ -1009,16 +1009,14 @@ static void ath9k_hw_4k_set_board_values
+ 	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
+ 		      pModal->thresh62);
+ 
+-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-						AR5416_EEP_MINOR_VER_2) {
++	if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) {
+ 		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
+ 			      pModal->txFrameToDataStart);
+ 		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+ 			      pModal->txFrameToPaOn);
+ 	}
+ 
+-	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-						AR5416_EEP_MINOR_VER_3) {
++	if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) {
+ 		if (IS_CHAN_HT40(chan))
+ 			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ 				      AR_PHY_SETTLING_SWITCH,
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -22,12 +22,17 @@
+ 
+ static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
+ {
+-	return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
++	u16 version = ah->eeprom.map9287.baseEepHeader.version;
++
++	return (version & AR5416_EEP_VER_MAJOR_MASK) >>
++		AR5416_EEP_VER_MAJOR_SHIFT;
+ }
+ 
+ static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
+ {
+-	return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
++	u16 version = ah->eeprom.map9287.baseEepHeader.version;
++
++	return version & AR5416_EEP_VER_MINOR_MASK;
+ }
+ 
+ static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
+@@ -132,8 +137,8 @@ static u32 ath9k_hw_ar9287_dump_eeprom(s
+ 		goto out;
+ 	}
+ 
+-	PR_EEP("Major Version", pBase->version >> 12);
+-	PR_EEP("Minor Version", pBase->version & 0xFFF);
++	PR_EEP("Major Version", ath9k_hw_ar9287_get_eeprom_ver(ah));
++	PR_EEP("Minor Version", ath9k_hw_ar9287_get_eeprom_rev(ah));
+ 	PR_EEP("Checksum", pBase->checksum);
+ 	PR_EEP("Length", pBase->length);
+ 	PR_EEP("RegDomain1", pBase->regDmn[0]);
+@@ -383,8 +388,7 @@ static void ath9k_hw_set_ar9287_power_ca
+ 
+ 	xpdMask = pEepData->modalHeader.xpdGain;
+ 
+-	if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+-	    AR9287_EEP_MINOR_VER_2)
++	if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2)
+ 		pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
+ 	else
+ 		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+@@ -733,8 +737,7 @@ static void ath9k_hw_ar9287_set_txpower(
+ 
+ 	memset(ratesArray, 0, sizeof(ratesArray));
+ 
+-	if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+-	    AR9287_EEP_MINOR_VER_2)
++	if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2)
+ 		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ 
+ 	ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -79,12 +79,17 @@ static void ath9k_olc_get_pdadcs(struct
+ 
+ static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah)
+ {
+-	return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF);
++	u16 version = ah->eeprom.def.baseEepHeader.version;
++
++	return (version & AR5416_EEP_VER_MAJOR_MASK) >>
++		AR5416_EEP_VER_MAJOR_SHIFT;
+ }
+ 
+ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
+ {
+-	return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF);
++	u16 version = ah->eeprom.def.baseEepHeader.version;
++
++	return version & AR5416_EEP_VER_MINOR_MASK;
+ }
+ 
+ #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+@@ -214,8 +219,8 @@ static u32 ath9k_hw_def_dump_eeprom(stru
+ 		goto out;
+ 	}
+ 
+-	PR_EEP("Major Version", pBase->version >> 12);
+-	PR_EEP("Minor Version", pBase->version & 0xFFF);
++	PR_EEP("Major Version", ath9k_hw_def_get_eeprom_ver(ah));
++	PR_EEP("Minor Version", ath9k_hw_def_get_eeprom_rev(ah));
+ 	PR_EEP("Checksum", pBase->checksum);
+ 	PR_EEP("Length", pBase->length);
+ 	PR_EEP("RegDomain1", pBase->regDmn[0]);
+@@ -391,27 +396,27 @@ static u32 ath9k_hw_def_get_eeprom(struc
+ 	case EEP_TXGAIN_TYPE:
+ 		return pBase->txGainType;
+ 	case EEP_OL_PWRCTRL:
+-		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
++		if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19)
+ 			return pBase->openLoopPwrCntl ? true : false;
+ 		else
+ 			return false;
+ 	case EEP_RC_CHAIN_MASK:
+-		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
++		if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19)
+ 			return pBase->rcChainMask;
+ 		else
+ 			return 0;
+ 	case EEP_DAC_HPWR_5G:
+-		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
++		if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_20)
+ 			return pBase->dacHiPwrMode_5G;
+ 		else
+ 			return 0;
+ 	case EEP_FRAC_N_5G:
+-		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22)
++		if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_22)
+ 			return pBase->frac_n_5g;
+ 		else
+ 			return 0;
+ 	case EEP_PWR_TABLE_OFFSET:
+-		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21)
++		if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_21)
+ 			return pBase->pwr_table_offset;
+ 		else
+ 			return AR5416_PWR_TABLE_OFFSET_DB;
+@@ -434,7 +439,7 @@ static void ath9k_hw_def_set_gain(struct
+ 				  u8 txRxAttenLocal, int regChainOffset, int i)
+ {
+ 	ENABLE_REG_RMW_BUFFER(ah);
+-	if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
++	if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) {
+ 		txRxAttenLocal = pModal->txRxAttenCh[i];
+ 
+ 		if (AR_SREV_9280_20_OR_LATER(ah)) {
+@@ -603,7 +608,7 @@ static void ath9k_hw_def_set_board_value
+ 			      pModal->thresh62);
+ 	}
+ 
+-	if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
++	if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) {
+ 		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ 			      AR_PHY_TX_END_DATA_START,
+ 			      pModal->txFrameToDataStart);
+@@ -611,7 +616,7 @@ static void ath9k_hw_def_set_board_value
+ 			      pModal->txFrameToPaOn);
+ 	}
+ 
+-	if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
++	if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) {
+ 		if (IS_CHAN_HT40(chan))
+ 			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ 				      AR_PHY_SETTLING_SWITCH,
+@@ -619,13 +624,14 @@ static void ath9k_hw_def_set_board_value
+ 	}
+ 
+ 	if (AR_SREV_9280_20_OR_LATER(ah) &&
+-	    AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
++	    ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19)
+ 		REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL,
+ 			      AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
+ 			      pModal->miscBits);
+ 
+ 
+-	if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) {
++	if (AR_SREV_9280_20(ah) &&
++	    ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_20) {
+ 		if (IS_CHAN_2GHZ(chan))
+ 			REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
+ 					eep->baseEepHeader.dacLpMode);
+@@ -796,8 +802,7 @@ static void ath9k_hw_set_def_power_cal_t
+ 
+ 	pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET);
+ 
+-	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-	    AR5416_EEP_MINOR_VER_2) {
++	if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) {
+ 		pdGainOverlap_t2 =
+ 			pEepData->modalHeader[modalIdx].pdGainOverlap;
+ 	} else {
+@@ -1169,10 +1174,8 @@ static void ath9k_hw_def_set_txpower(str
+ 
+ 	memset(ratesArray, 0, sizeof(ratesArray));
+ 
+-	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+-	    AR5416_EEP_MINOR_VER_2) {
++	if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2)
+ 		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+-	}
+ 
+ 	ath9k_hw_set_def_power_per_rate_table(ah, chan,
+ 					       &ratesArray[0], cfgCtl,
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -1177,8 +1177,9 @@ static u8 ath_get_rate_txpower(struct at
+ 		if (is_40) {
+ 			u8 power_ht40delta;
+ 			struct ar5416_eeprom_def *eep = &ah->eeprom.def;
++			u16 eeprom_rev = ah->eep_ops->get_eeprom_rev(ah);
+ 
+-			if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
++			if (eeprom_rev >= AR5416_EEP_MINOR_VER_2) {
+ 				bool is_2ghz;
+ 				struct modal_eep_header *pmodal;
+ 
diff --git a/package/kernel/mac80211/patches/555-ath9k-Make-the-EEPROM-swapping-check-use-the-eepmisc.patch b/package/kernel/mac80211/patches/555-ath9k-Make-the-EEPROM-swapping-check-use-the-eepmisc.patch
new file mode 100644
index 0000000000..3e3c2ea7a3
--- /dev/null
+++ b/package/kernel/mac80211/patches/555-ath9k-Make-the-EEPROM-swapping-check-use-the-eepmisc.patch
@@ -0,0 +1,128 @@
+From 1f796f9265c10384a274ac330f671ef4ac6d56e5 Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:12 +0200
+Subject: [v2 PATCH 6/7] ath9k: Make the EEPROM swapping check use the eepmisc
+ register
+
+There are two ways of swapping the EEPROM data in the ath9k driver:
+1) swab16 based on the first two EEPROM "magic" bytes (same for all
+   EEPROM formats)
+2) field and EEPROM format specific swab16/swab32 (different for
+   eeprom_def, eeprom_4k and eeprom_9287)
+
+The result of the first check was used to also enable the second swap.
+This behavior seems incorrect, since the data may only be byte-swapped
+(afterwards the data could be in the correct endianness).
+Thus we introduce a separate check based on the "eepmisc" register
+(which is part of the EEPROM data). When bit 0 is set, then the EEPROM
+format specific values are in "big endian". This is also done by the
+FreeBSD kernel, see [0] for example.
+
+This allows us to parse EEPROMs with the "correct" magic bytes but
+swapped EEPROM format specific values. These EEPROMs (mostly found in
+lantiq and broadcom based big endian MIPS based devices) only worked
+due to platform specific "hacks" which swapped the EEPROM so the
+magic was inverted, which also enabled the format specific swapping.
+With this patch the old behavior is still supported, but neither
+recommended nor needed anymore.
+
+[0]
+https://github.com/freebsd/freebsd/blob/50719b56d9ce8d7d4beb53b16e9edb2e9a4a7a18/sys/dev/ath/ath_hal/ah_eeprom_9287.c#L351
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/eeprom.c | 57 ++++++++++++++++++++++++---------
+ 1 file changed, 41 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom.c
+@@ -155,11 +155,19 @@ bool ath9k_hw_nvram_read(struct ath_hw *
+ 	return ret;
+ }
+ 
++#ifdef __BIG_ENDIAN
++#define EXPECTED_EEPMISC_ENDIAN AR5416_EEPMISC_BIG_ENDIAN
++#else
++#define EXPECTED_EEPMISC_ENDIAN 0
++#endif
++
+ int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
+ {
+ 	u16 magic;
+ 	u16 *eepdata;
++	u8 eepmisc;
+ 	int i;
++	bool needs_byteswap = false;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 
+ 	if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+@@ -167,36 +175,53 @@ int ath9k_hw_nvram_swap_data(struct ath_
+ 		return -EIO;
+ 	}
+ 
+-	*swap_needed = false;
+ 	if (swab16(magic) == AR5416_EEPROM_MAGIC) {
++		needs_byteswap = true;
++		ath_dbg(common, EEPROM,
++			"EEPROM needs byte-swapping to correct endianness.\n");
++	} else if (magic != AR5416_EEPROM_MAGIC) {
++		if (ath9k_hw_use_flash(ah)) {
++			ath_dbg(common, EEPROM,
++				"Ignoring invalid EEPROM magic (0x%04x).\n",
++				magic);
++		} else {
++			ath_err(common,
++				"Invalid EEPROM magic (0x%04x).\n", magic);
++			return -EINVAL;
++		}
++	}
++
++	if (needs_byteswap) {
+ 		if (ah->ah_flags & AH_NO_EEP_SWAP) {
+ 			ath_info(common,
+ 				 "Ignoring endianness difference in EEPROM magic bytes.\n");
+ 		} else {
+-			*swap_needed = true;
+-		}
+-	} else if (magic != AR5416_EEPROM_MAGIC) {
+-		if (ath9k_hw_use_flash(ah))
+-			return 0;
++			eepdata = (u16 *)(&ah->eeprom);
+ 
+-		ath_err(common,
+-			"Invalid EEPROM Magic (0x%04x).\n", magic);
+-		return -EINVAL;
++			for (i = 0; i < size; i++)
++				eepdata[i] = swab16(eepdata[i]);
++		}
+ 	}
+ 
+-	eepdata = (u16 *)(&ah->eeprom);
+-
+-	if (*swap_needed) {
+-		ath_dbg(common, EEPROM,
+-			"EEPROM Endianness is not native.. Changing.\n");
++	*swap_needed = false;
+ 
+-		for (i = 0; i < size; i++)
+-			eepdata[i] = swab16(eepdata[i]);
++	eepmisc = ah->eep_ops->get_eepmisc(ah);
++	if ((eepmisc & AR5416_EEPMISC_BIG_ENDIAN) != EXPECTED_EEPMISC_ENDIAN) {
++		if (ah->ah_flags & AH_NO_EEP_SWAP) {
++			ath_info(common,
++				 "Ignoring endianness difference in eepmisc register.\n");
++		} else {
++			*swap_needed = true;
++			ath_dbg(common, EEPROM,
++				"EEPROM needs swapping according to the eepmisc register.\n");
++		}
+ 	}
+ 
+ 	return 0;
+ }
+ 
++#undef EXPECTED_EEPMISC_VAL
++
+ bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
+ {
+ 	u32 i, sum = 0;
diff --git a/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch b/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
new file mode 100644
index 0000000000..04714f8169
--- /dev/null
+++ b/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
@@ -0,0 +1,853 @@
+From 7e1047f3cf8dcdb4825f3c785f7f708d07508096 Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Mon, 3 Oct 2016 00:29:13 +0200
+Subject: [v2 PATCH 7/7] ath9k: define all EEPROM fields in Little Endian format
+
+The ar9300_eeprom logic is already using only 8-bit (endian neutral),
+__le16 and __le32 fields to state explicitly how the values should be
+interpreted.
+All other EEPROM implementations (4k, 9287 and def) were using u16 and
+u32 fields with additional logic to swap the values (read from the
+original EEPROM) so they match the current CPUs endianness.
+
+The EEPROM format defaults to "all values are Little Endian", indicated
+by the absence of the AR5416_EEPMISC_BIG_ENDIAN in the u8 EEPMISC
+register. If we detect that the EEPROM indicates Big Endian mode
+(AR5416_EEPMISC_BIG_ENDIAN is set in the EEPMISC register) then we'll
+swap the values to convert them into Little Endian. This is done by
+activating the EEPMISC based logic in ath9k_hw_nvram_swap_data even if
+AH_NO_EEP_SWAP is set (this makes ath9k behave like the FreeBSD driver,
+which also does not have a flag to enable swapping based on the
+AR5416_EEPMISC_BIG_ENDIAN bit). Before this logic was only used to
+enable swapping when "current CPU endianness != EEPROM endianness".
+
+After changing all relevant fields to __le16 and __le32 sparse was used
+to check that all code which reads any of these fields uses
+le{16,32}_to_cpu.
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+ drivers/net/wireless/ath/ath9k/eeprom.c      |  27 ++-----
+ drivers/net/wireless/ath/ath9k/eeprom.h      |  75 ++++++++++--------
+ drivers/net/wireless/ath/ath9k/eeprom_4k.c   |  94 +++++++++-------------
+ drivers/net/wireless/ath/ath9k/eeprom_9287.c |  98 ++++++++++-------------
+ drivers/net/wireless/ath/ath9k/eeprom_def.c  | 114 ++++++++++++---------------
+ 5 files changed, 174 insertions(+), 234 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom.c
+@@ -155,17 +155,10 @@ bool ath9k_hw_nvram_read(struct ath_hw *
+ 	return ret;
+ }
+ 
+-#ifdef __BIG_ENDIAN
+-#define EXPECTED_EEPMISC_ENDIAN AR5416_EEPMISC_BIG_ENDIAN
+-#else
+-#define EXPECTED_EEPMISC_ENDIAN 0
+-#endif
+-
+ int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
+ {
+ 	u16 magic;
+ 	u16 *eepdata;
+-	u8 eepmisc;
+ 	int i;
+ 	bool needs_byteswap = false;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+@@ -203,25 +196,17 @@ int ath9k_hw_nvram_swap_data(struct ath_
+ 		}
+ 	}
+ 
+-	*swap_needed = false;
+-
+-	eepmisc = ah->eep_ops->get_eepmisc(ah);
+-	if ((eepmisc & AR5416_EEPMISC_BIG_ENDIAN) != EXPECTED_EEPMISC_ENDIAN) {
+-		if (ah->ah_flags & AH_NO_EEP_SWAP) {
+-			ath_info(common,
+-				 "Ignoring endianness difference in eepmisc register.\n");
+-		} else {
+-			*swap_needed = true;
+-			ath_dbg(common, EEPROM,
+-				"EEPROM needs swapping according to the eepmisc register.\n");
+-		}
++	if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) {
++		*swap_needed = true;
++		ath_dbg(common, EEPROM,
++			"Big Endian EEPROM detected according to EEPMISC register.\n");
++	} else {
++		*swap_needed = false;
+ 	}
+ 
+ 	return 0;
+ }
+ 
+-#undef EXPECTED_EEPMISC_VAL
+-
+ bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
+ {
+ 	u32 i, sum = 0;
+--- a/drivers/net/wireless/ath/ath9k/eeprom.h
++++ b/drivers/net/wireless/ath/ath9k/eeprom.h
+@@ -23,6 +23,17 @@
+ #include <net/cfg80211.h>
+ #include "ar9003_eeprom.h"
+ 
++/* helpers to swap EEPROM fields, which are stored as __le16 or __le32. Since
++ * we are 100% sure about it we __force these to u16/u32 for the swab calls to
++ * silence the sparse checks. These macros are used when we have a Big Endian
++ * EEPROM (according to AR5416_EEPMISC_BIG_ENDIAN) and need to convert the
++ * fields to __le16/__le32.
++ */
++#define EEPROM_FIELD_SWAB16(field) \
++	(field = (__force __le16)swab16((__force u16)field))
++#define EEPROM_FIELD_SWAB32(field) \
++	(field = (__force __le32)swab32((__force u32)field))
++
+ #ifdef __BIG_ENDIAN
+ #define AR5416_EEPROM_MAGIC 0x5aa5
+ #else
+@@ -270,19 +281,19 @@ enum ath9k_hal_freq_band {
+ };
+ 
+ struct base_eep_header {
+-	u16 length;
+-	u16 checksum;
+-	u16 version;
++	__le16 length;
++	__le16 checksum;
++	__le16 version;
+ 	u8 opCapFlags;
+ 	u8 eepMisc;
+-	u16 regDmn[2];
++	__le16 regDmn[2];
+ 	u8 macAddr[6];
+ 	u8 rxMask;
+ 	u8 txMask;
+-	u16 rfSilent;
+-	u16 blueToothOptions;
+-	u16 deviceCap;
+-	u32 binBuildNumber;
++	__le16 rfSilent;
++	__le16 blueToothOptions;
++	__le16 deviceCap;
++	__le32 binBuildNumber;
+ 	u8 deviceType;
+ 	u8 pwdclkind;
+ 	u8 fastClk5g;
+@@ -300,33 +311,33 @@ struct base_eep_header {
+ } __packed;
+ 
+ struct base_eep_header_4k {
+-	u16 length;
+-	u16 checksum;
+-	u16 version;
++	__le16 length;
++	__le16 checksum;
++	__le16 version;
+ 	u8 opCapFlags;
+ 	u8 eepMisc;
+-	u16 regDmn[2];
++	__le16 regDmn[2];
+ 	u8 macAddr[6];
+ 	u8 rxMask;
+ 	u8 txMask;
+-	u16 rfSilent;
+-	u16 blueToothOptions;
+-	u16 deviceCap;
+-	u32 binBuildNumber;
++	__le16 rfSilent;
++	__le16 blueToothOptions;
++	__le16 deviceCap;
++	__le32 binBuildNumber;
+ 	u8 deviceType;
+ 	u8 txGainType;
+ } __packed;
+ 
+ 
+ struct spur_chan {
+-	u16 spurChan;
++	__le16 spurChan;
+ 	u8 spurRangeLow;
+ 	u8 spurRangeHigh;
+ } __packed;
+ 
+ struct modal_eep_header {
+-	u32 antCtrlChain[AR5416_MAX_CHAINS];
+-	u32 antCtrlCommon;
++	__le32 antCtrlChain[AR5416_MAX_CHAINS];
++	__le32 antCtrlCommon;
+ 	u8 antennaGainCh[AR5416_MAX_CHAINS];
+ 	u8 switchSettling;
+ 	u8 txRxAttenCh[AR5416_MAX_CHAINS];
+@@ -361,7 +372,7 @@ struct modal_eep_header {
+ 	u8 db_ch1;
+ 	u8 lna_ctl;
+ 	u8 miscBits;
+-	u16 xpaBiasLvlFreq[3];
++	__le16 xpaBiasLvlFreq[3];
+ 	u8 futureModal[6];
+ 
+ 	struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
+@@ -375,8 +386,8 @@ struct calDataPerFreqOpLoop {
+ } __packed;
+ 
+ struct modal_eep_4k_header {
+-	u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
+-	u32 antCtrlCommon;
++	__le32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
++	__le32 antCtrlCommon;
+ 	u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
+ 	u8 switchSettling;
+ 	u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
+@@ -440,19 +451,19 @@ struct modal_eep_4k_header {
+ } __packed;
+ 
+ struct base_eep_ar9287_header {
+-	u16 length;
+-	u16 checksum;
+-	u16 version;
++	__le16 length;
++	__le16 checksum;
++	__le16 version;
+ 	u8 opCapFlags;
+ 	u8 eepMisc;
+-	u16 regDmn[2];
++	__le16 regDmn[2];
+ 	u8 macAddr[6];
+ 	u8 rxMask;
+ 	u8 txMask;
+-	u16 rfSilent;
+-	u16 blueToothOptions;
+-	u16 deviceCap;
+-	u32 binBuildNumber;
++	__le16 rfSilent;
++	__le16 blueToothOptions;
++	__le16 deviceCap;
++	__le32 binBuildNumber;
+ 	u8 deviceType;
+ 	u8 openLoopPwrCntl;
+ 	int8_t pwrTableOffset;
+@@ -462,8 +473,8 @@ struct base_eep_ar9287_header {
+ } __packed;
+ 
+ struct modal_eep_ar9287_header {
+-	u32 antCtrlChain[AR9287_MAX_CHAINS];
+-	u32 antCtrlCommon;
++	__le32 antCtrlChain[AR9287_MAX_CHAINS];
++	__le32 antCtrlCommon;
+ 	int8_t antennaGainCh[AR9287_MAX_CHAINS];
+ 	u8 switchSettling;
+ 	u8 txRxAttenCh[AR9287_MAX_CHAINS];
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -20,7 +20,7 @@
+ 
+ static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
+ {
+-	u16 version = ah->eeprom.map4k.baseEepHeader.version;
++	u16 version = le16_to_cpu(ah->eeprom.map4k.baseEepHeader.version);
+ 
+ 	return (version & AR5416_EEP_VER_MAJOR_MASK) >>
+ 		AR5416_EEP_VER_MAJOR_SHIFT;
+@@ -28,7 +28,7 @@ static int ath9k_hw_4k_get_eeprom_ver(st
+ 
+ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
+ {
+-	u16 version = ah->eeprom.map4k.baseEepHeader.version;
++	u16 version = le16_to_cpu(ah->eeprom.map4k.baseEepHeader.version);
+ 
+ 	return version & AR5416_EEP_VER_MINOR_MASK;
+ }
+@@ -76,8 +76,8 @@ static bool ath9k_hw_4k_fill_eeprom(stru
+ static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size,
+ 				      struct modal_eep_4k_header *modal_hdr)
+ {
+-	PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+-	PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
++	PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
++	PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
+ 	PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+ 	PR_EEP("Switch Settle", modal_hdr->switchSettling);
+ 	PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
+@@ -132,6 +132,7 @@ static u32 ath9k_hw_4k_dump_eeprom(struc
+ {
+ 	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ 	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
++	u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber);
+ 
+ 	if (!dump_base_hdr) {
+ 		len += scnprintf(buf + len, size - len,
+@@ -143,10 +144,10 @@ static u32 ath9k_hw_4k_dump_eeprom(struc
+ 
+ 	PR_EEP("Major Version", ath9k_hw_4k_get_eeprom_ver(ah));
+ 	PR_EEP("Minor Version", ath9k_hw_4k_get_eeprom_rev(ah));
+-	PR_EEP("Checksum", pBase->checksum);
+-	PR_EEP("Length", pBase->length);
+-	PR_EEP("RegDomain1", pBase->regDmn[0]);
+-	PR_EEP("RegDomain2", pBase->regDmn[1]);
++	PR_EEP("Checksum", le16_to_cpu(pBase->checksum));
++	PR_EEP("Length", le16_to_cpu(pBase->length));
++	PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
++	PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
+ 	PR_EEP("TX Mask", pBase->txMask);
+ 	PR_EEP("RX Mask", pBase->rxMask);
+ 	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+@@ -160,9 +161,9 @@ static u32 ath9k_hw_4k_dump_eeprom(struc
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+ 	PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
+-	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+-	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+-	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
++	PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF);
++	PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF);
++	PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF);
+ 	PR_EEP("TX Gain type", pBase->txGainType);
+ 
+ 	len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+@@ -194,54 +195,31 @@ static int ath9k_hw_4k_check_eeprom(stru
+ 		return err;
+ 
+ 	if (need_swap)
+-		el = swab16(eep->baseEepHeader.length);
++		el = swab16((__force u16)eep->baseEepHeader.length);
+ 	else
+-		el = eep->baseEepHeader.length;
++		el = le16_to_cpu(eep->baseEepHeader.length);
+ 
+ 	el = min(el / sizeof(u16), SIZE_EEPROM_4K);
+ 	if (!ath9k_hw_nvram_validate_checksum(ah, el))
+ 		return -EINVAL;
+ 
+ 	if (need_swap) {
+-		u32 integer;
+-		u16 word;
+-
+-		word = swab16(eep->baseEepHeader.length);
+-		eep->baseEepHeader.length = word;
+-
+-		word = swab16(eep->baseEepHeader.checksum);
+-		eep->baseEepHeader.checksum = word;
+-
+-		word = swab16(eep->baseEepHeader.version);
+-		eep->baseEepHeader.version = word;
+-
+-		word = swab16(eep->baseEepHeader.regDmn[0]);
+-		eep->baseEepHeader.regDmn[0] = word;
+-
+-		word = swab16(eep->baseEepHeader.regDmn[1]);
+-		eep->baseEepHeader.regDmn[1] = word;
+-
+-		word = swab16(eep->baseEepHeader.rfSilent);
+-		eep->baseEepHeader.rfSilent = word;
+-
+-		word = swab16(eep->baseEepHeader.blueToothOptions);
+-		eep->baseEepHeader.blueToothOptions = word;
+-
+-		word = swab16(eep->baseEepHeader.deviceCap);
+-		eep->baseEepHeader.deviceCap = word;
+-
+-		integer = swab32(eep->modalHeader.antCtrlCommon);
+-		eep->modalHeader.antCtrlCommon = integer;
+-
+-		for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+-			integer = swab32(eep->modalHeader.antCtrlChain[i]);
+-			eep->modalHeader.antCtrlChain[i] = integer;
+-		}
+-
+-		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+-			word = swab16(eep->modalHeader.spurChans[i].spurChan);
+-			eep->modalHeader.spurChans[i].spurChan = word;
+-		}
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
++		EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon);
++
++		for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++)
++			EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]);
++
++		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
++			EEPROM_FIELD_SWAB16(
++				eep->modalHeader.spurChans[i].spurChan);
+ 	}
+ 
+ 	if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
+@@ -270,13 +248,13 @@ static u32 ath9k_hw_4k_get_eeprom(struct
+ 	case EEP_MAC_MSW:
+ 		return get_unaligned_be16(pBase->macAddr + 4);
+ 	case EEP_REG_0:
+-		return pBase->regDmn[0];
++		return le16_to_cpu(pBase->regDmn[0]);
+ 	case EEP_OP_CAP:
+-		return pBase->deviceCap;
++		return le16_to_cpu(pBase->deviceCap);
+ 	case EEP_OP_MODE:
+ 		return pBase->opCapFlags;
+ 	case EEP_RF_SILENT:
+-		return pBase->rfSilent;
++		return le16_to_cpu(pBase->rfSilent);
+ 	case EEP_OB_2:
+ 		return pModal->ob_0;
+ 	case EEP_DB_2:
+@@ -724,7 +702,7 @@ static void ath9k_hw_4k_set_gain(struct
+ {
+ 	ENABLE_REG_RMW_BUFFER(ah);
+ 	REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0,
+-		pModal->antCtrlChain[0], 0);
++		le32_to_cpu(pModal->antCtrlChain[0]), 0);
+ 
+ 	REG_RMW(ah, AR_PHY_TIMING_CTRL4(0),
+ 		SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+@@ -790,7 +768,7 @@ static void ath9k_hw_4k_set_board_values
+ 	pModal = &eep->modalHeader;
+ 	txRxAttenLocal = 23;
+ 
+-	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
++	REG_WRITE(ah, AR_PHY_SWITCH_COM, le32_to_cpu(pModal->antCtrlCommon));
+ 
+ 	/* Single chain for 4K EEPROM*/
+ 	ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal);
+@@ -1054,7 +1032,7 @@ static void ath9k_hw_4k_set_board_values
+ 
+ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
+ {
+-	return ah->eeprom.map4k.modalHeader.spurChans[i].spurChan;
++	return le16_to_cpu(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan);
+ }
+ 
+ static u8 ath9k_hw_4k_get_eepmisc(struct ath_hw *ah)
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -22,7 +22,7 @@
+ 
+ static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
+ {
+-	u16 version = ah->eeprom.map9287.baseEepHeader.version;
++	u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version);
+ 
+ 	return (version & AR5416_EEP_VER_MAJOR_MASK) >>
+ 		AR5416_EEP_VER_MAJOR_SHIFT;
+@@ -30,7 +30,7 @@ static int ath9k_hw_ar9287_get_eeprom_ve
+ 
+ static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
+ {
+-	u16 version = ah->eeprom.map9287.baseEepHeader.version;
++	u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version);
+ 
+ 	return version & AR5416_EEP_VER_MINOR_MASK;
+ }
+@@ -79,9 +79,9 @@ static bool ath9k_hw_ar9287_fill_eeprom(
+ static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size,
+ 				    struct modal_eep_ar9287_header *modal_hdr)
+ {
+-	PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+-	PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
+-	PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
++	PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
++	PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
++	PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
+ 	PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+ 	PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
+ 	PR_EEP("Switch Settle", modal_hdr->switchSettling);
+@@ -128,6 +128,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(s
+ {
+ 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ 	struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
++	u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber);
+ 
+ 	if (!dump_base_hdr) {
+ 		len += scnprintf(buf + len, size - len,
+@@ -139,10 +140,10 @@ static u32 ath9k_hw_ar9287_dump_eeprom(s
+ 
+ 	PR_EEP("Major Version", ath9k_hw_ar9287_get_eeprom_ver(ah));
+ 	PR_EEP("Minor Version", ath9k_hw_ar9287_get_eeprom_rev(ah));
+-	PR_EEP("Checksum", pBase->checksum);
+-	PR_EEP("Length", pBase->length);
+-	PR_EEP("RegDomain1", pBase->regDmn[0]);
+-	PR_EEP("RegDomain2", pBase->regDmn[1]);
++	PR_EEP("Checksum", le16_to_cpu(pBase->checksum));
++	PR_EEP("Length", le16_to_cpu(pBase->length));
++	PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
++	PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
+ 	PR_EEP("TX Mask", pBase->txMask);
+ 	PR_EEP("RX Mask", pBase->rxMask);
+ 	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+@@ -156,9 +157,9 @@ static u32 ath9k_hw_ar9287_dump_eeprom(s
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+ 	PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
+-	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+-	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+-	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
++	PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF);
++	PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF);
++	PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF);
+ 	PR_EEP("Power Table Offset", pBase->pwrTableOffset);
+ 	PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
+ 
+@@ -182,8 +183,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(s
+ 
+ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
+ {
+-	u32 el, integer;
+-	u16 word;
++	u32 el;
+ 	int i, err;
+ 	bool need_swap;
+ 	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+@@ -193,51 +193,31 @@ static int ath9k_hw_ar9287_check_eeprom(
+ 		return err;
+ 
+ 	if (need_swap)
+-		el = swab16(eep->baseEepHeader.length);
++		el = swab16((__force u16)eep->baseEepHeader.length);
+ 	else
+-		el = eep->baseEepHeader.length;
++		el = le16_to_cpu(eep->baseEepHeader.length);
+ 
+ 	el = min(el / sizeof(u16), SIZE_EEPROM_AR9287);
+ 	if (!ath9k_hw_nvram_validate_checksum(ah, el))
+ 		return -EINVAL;
+ 
+ 	if (need_swap) {
+-		word = swab16(eep->baseEepHeader.length);
+-		eep->baseEepHeader.length = word;
+-
+-		word = swab16(eep->baseEepHeader.checksum);
+-		eep->baseEepHeader.checksum = word;
+-
+-		word = swab16(eep->baseEepHeader.version);
+-		eep->baseEepHeader.version = word;
+-
+-		word = swab16(eep->baseEepHeader.regDmn[0]);
+-		eep->baseEepHeader.regDmn[0] = word;
+-
+-		word = swab16(eep->baseEepHeader.regDmn[1]);
+-		eep->baseEepHeader.regDmn[1] = word;
+-
+-		word = swab16(eep->baseEepHeader.rfSilent);
+-		eep->baseEepHeader.rfSilent = word;
+-
+-		word = swab16(eep->baseEepHeader.blueToothOptions);
+-		eep->baseEepHeader.blueToothOptions = word;
+-
+-		word = swab16(eep->baseEepHeader.deviceCap);
+-		eep->baseEepHeader.deviceCap = word;
+-
+-		integer = swab32(eep->modalHeader.antCtrlCommon);
+-		eep->modalHeader.antCtrlCommon = integer;
+-
+-		for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+-			integer = swab32(eep->modalHeader.antCtrlChain[i]);
+-			eep->modalHeader.antCtrlChain[i] = integer;
+-		}
+-
+-		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+-			word = swab16(eep->modalHeader.spurChans[i].spurChan);
+-			eep->modalHeader.spurChans[i].spurChan = word;
+-		}
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
++		EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon);
++
++		for (i = 0; i < AR9287_MAX_CHAINS; i++)
++			EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]);
++
++		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
++			EEPROM_FIELD_SWAB16(
++				eep->modalHeader.spurChans[i].spurChan);
+ 	}
+ 
+ 	if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER,
+@@ -267,13 +247,13 @@ static u32 ath9k_hw_ar9287_get_eeprom(st
+ 	case EEP_MAC_MSW:
+ 		return get_unaligned_be16(pBase->macAddr + 4);
+ 	case EEP_REG_0:
+-		return pBase->regDmn[0];
++		return le16_to_cpu(pBase->regDmn[0]);
+ 	case EEP_OP_CAP:
+-		return pBase->deviceCap;
++		return le16_to_cpu(pBase->deviceCap);
+ 	case EEP_OP_MODE:
+ 		return pBase->opCapFlags;
+ 	case EEP_RF_SILENT:
+-		return pBase->rfSilent;
++		return le16_to_cpu(pBase->rfSilent);
+ 	case EEP_TX_MASK:
+ 		return pBase->txMask;
+ 	case EEP_RX_MASK:
+@@ -878,13 +858,13 @@ static void ath9k_hw_ar9287_set_board_va
+ 
+ 	pModal = &eep->modalHeader;
+ 
+-	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
++	REG_WRITE(ah, AR_PHY_SWITCH_COM, le32_to_cpu(pModal->antCtrlCommon));
+ 
+ 	for (i = 0; i < AR9287_MAX_CHAINS; i++)	{
+ 		regChainOffset = i * 0x1000;
+ 
+ 		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+-			  pModal->antCtrlChain[i]);
++			  le32_to_cpu(pModal->antCtrlChain[i]));
+ 
+ 		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ 			  (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
+@@ -982,7 +962,9 @@ static void ath9k_hw_ar9287_set_board_va
+ static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
+ 					    u16 i, bool is2GHz)
+ {
+-	return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
++	__le16 spur_ch = ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
++
++	return le16_to_cpu(spur_ch);
+ }
+ 
+ static u8 ath9k_hw_ar9287_get_eepmisc(struct ath_hw *ah)
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -79,7 +79,7 @@ static void ath9k_olc_get_pdadcs(struct
+ 
+ static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah)
+ {
+-	u16 version = ah->eeprom.def.baseEepHeader.version;
++	u16 version = le16_to_cpu(ah->eeprom.def.baseEepHeader.version);
+ 
+ 	return (version & AR5416_EEP_VER_MAJOR_MASK) >>
+ 		AR5416_EEP_VER_MAJOR_SHIFT;
+@@ -87,7 +87,7 @@ static int ath9k_hw_def_get_eeprom_ver(s
+ 
+ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
+ {
+-	u16 version = ah->eeprom.def.baseEepHeader.version;
++	u16 version = le16_to_cpu(ah->eeprom.def.baseEepHeader.version);
+ 
+ 	return version & AR5416_EEP_VER_MINOR_MASK;
+ }
+@@ -135,10 +135,10 @@ static bool ath9k_hw_def_fill_eeprom(str
+ static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
+ 				       struct modal_eep_header *modal_hdr)
+ {
+-	PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
+-	PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
+-	PR_EEP("Chain2 Ant. Control", modal_hdr->antCtrlChain[2]);
+-	PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
++	PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
++	PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
++	PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2]));
++	PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
+ 	PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
+ 	PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
+ 	PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]);
+@@ -194,9 +194,9 @@ static u32 ath9k_def_dump_modal_eeprom(c
+ 	PR_EEP("Chain1 OutputBias", modal_hdr->ob_ch1);
+ 	PR_EEP("Chain1 DriverBias", modal_hdr->db_ch1);
+ 	PR_EEP("LNA Control", modal_hdr->lna_ctl);
+-	PR_EEP("XPA Bias Freq0", modal_hdr->xpaBiasLvlFreq[0]);
+-	PR_EEP("XPA Bias Freq1", modal_hdr->xpaBiasLvlFreq[1]);
+-	PR_EEP("XPA Bias Freq2", modal_hdr->xpaBiasLvlFreq[2]);
++	PR_EEP("XPA Bias Freq0", le16_to_cpu(modal_hdr->xpaBiasLvlFreq[0]));
++	PR_EEP("XPA Bias Freq1", le16_to_cpu(modal_hdr->xpaBiasLvlFreq[1]));
++	PR_EEP("XPA Bias Freq2", le16_to_cpu(modal_hdr->xpaBiasLvlFreq[2]));
+ 
+ 	return len;
+ }
+@@ -206,6 +206,7 @@ static u32 ath9k_hw_def_dump_eeprom(stru
+ {
+ 	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ 	struct base_eep_header *pBase = &eep->baseEepHeader;
++	u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber);
+ 
+ 	if (!dump_base_hdr) {
+ 		len += scnprintf(buf + len, size - len,
+@@ -221,10 +222,10 @@ static u32 ath9k_hw_def_dump_eeprom(stru
+ 
+ 	PR_EEP("Major Version", ath9k_hw_def_get_eeprom_ver(ah));
+ 	PR_EEP("Minor Version", ath9k_hw_def_get_eeprom_rev(ah));
+-	PR_EEP("Checksum", pBase->checksum);
+-	PR_EEP("Length", pBase->length);
+-	PR_EEP("RegDomain1", pBase->regDmn[0]);
+-	PR_EEP("RegDomain2", pBase->regDmn[1]);
++	PR_EEP("Checksum", le16_to_cpu(pBase->checksum));
++	PR_EEP("Length", le16_to_cpu(pBase->length));
++	PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
++	PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
+ 	PR_EEP("TX Mask", pBase->txMask);
+ 	PR_EEP("RX Mask", pBase->rxMask);
+ 	PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+@@ -238,9 +239,9 @@ static u32 ath9k_hw_def_dump_eeprom(stru
+ 	PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
+ 					AR5416_OPFLAGS_N_5G_HT40));
+ 	PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
+-	PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
+-	PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
+-	PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
++	PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF);
++	PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF);
++	PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF);
+ 	PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
+ 
+ 	len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+@@ -273,61 +274,40 @@ static int ath9k_hw_def_check_eeprom(str
+ 		return err;
+ 
+ 	if (need_swap)
+-		el = swab16(eep->baseEepHeader.length);
++		el = swab16((__force u16)eep->baseEepHeader.length);
+ 	else
+-		el = eep->baseEepHeader.length;
++		el = le16_to_cpu(eep->baseEepHeader.length);
+ 
+ 	el = min(el / sizeof(u16), SIZE_EEPROM_DEF);
+ 	if (!ath9k_hw_nvram_validate_checksum(ah, el))
+ 		return -EINVAL;
+ 
+ 	if (need_swap) {
+-		u32 integer, j;
+-		u16 word;
++		u32 j;
+ 
+-		word = swab16(eep->baseEepHeader.length);
+-		eep->baseEepHeader.length = word;
+-
+-		word = swab16(eep->baseEepHeader.checksum);
+-		eep->baseEepHeader.checksum = word;
+-
+-		word = swab16(eep->baseEepHeader.version);
+-		eep->baseEepHeader.version = word;
+-
+-		word = swab16(eep->baseEepHeader.regDmn[0]);
+-		eep->baseEepHeader.regDmn[0] = word;
+-
+-		word = swab16(eep->baseEepHeader.regDmn[1]);
+-		eep->baseEepHeader.regDmn[1] = word;
+-
+-		word = swab16(eep->baseEepHeader.rfSilent);
+-		eep->baseEepHeader.rfSilent = word;
+-
+-		word = swab16(eep->baseEepHeader.blueToothOptions);
+-		eep->baseEepHeader.blueToothOptions = word;
+-
+-		word = swab16(eep->baseEepHeader.deviceCap);
+-		eep->baseEepHeader.deviceCap = word;
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
++		EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
+ 
+ 		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+ 			struct modal_eep_header *pModal =
+ 				&eep->modalHeader[j];
+-			integer = swab32(pModal->antCtrlCommon);
+-			pModal->antCtrlCommon = integer;
++			EEPROM_FIELD_SWAB32(pModal->antCtrlCommon);
+ 
+-			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+-				integer = swab32(pModal->antCtrlChain[i]);
+-				pModal->antCtrlChain[i] = integer;
+-			}
+-			for (i = 0; i < 3; i++) {
+-				word = swab16(pModal->xpaBiasLvlFreq[i]);
+-				pModal->xpaBiasLvlFreq[i] = word;
+-			}
++			for (i = 0; i < AR5416_MAX_CHAINS; i++)
++				EEPROM_FIELD_SWAB32(pModal->antCtrlChain[i]);
+ 
+-			for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+-				word = swab16(pModal->spurChans[i].spurChan);
+-				pModal->spurChans[i].spurChan = word;
+-			}
++			for (i = 0; i < 3; i++)
++				EEPROM_FIELD_SWAB16(pModal->xpaBiasLvlFreq[i]);
++
++			for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
++				EEPROM_FIELD_SWAB16(
++					pModal->spurChans[i].spurChan);
+ 		}
+ 	}
+ 
+@@ -337,7 +317,7 @@ static int ath9k_hw_def_check_eeprom(str
+ 
+ 	/* Enable fixup for AR_AN_TOP2 if necessary */
+ 	if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
+-	    ((eep->baseEepHeader.version & 0xff) > 0x0a) &&
++	    ((le16_to_cpu(eep->baseEepHeader.version) & 0xff) > 0x0a) &&
+ 	    (eep->baseEepHeader.pwdclkind == 0))
+ 		ah->need_an_top2_fixup = true;
+ 
+@@ -370,13 +350,13 @@ static u32 ath9k_hw_def_get_eeprom(struc
+ 	case EEP_MAC_MSW:
+ 		return get_unaligned_be16(pBase->macAddr + 4);
+ 	case EEP_REG_0:
+-		return pBase->regDmn[0];
++		return le16_to_cpu(pBase->regDmn[0]);
+ 	case EEP_OP_CAP:
+-		return pBase->deviceCap;
++		return le16_to_cpu(pBase->deviceCap);
+ 	case EEP_OP_MODE:
+ 		return pBase->opCapFlags;
+ 	case EEP_RF_SILENT:
+-		return pBase->rfSilent;
++		return le16_to_cpu(pBase->rfSilent);
+ 	case EEP_OB_5:
+ 		return pModal[0].ob;
+ 	case EEP_DB_5:
+@@ -490,11 +470,13 @@ static void ath9k_hw_def_set_board_value
+ 	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ 	int i, regChainOffset;
+ 	u8 txRxAttenLocal;
++	u32 antCtrlCommon;
+ 
+ 	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+ 	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
++	antCtrlCommon = le32_to_cpu(pModal->antCtrlCommon);
+ 
+-	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon & 0xffff);
++	REG_WRITE(ah, AR_PHY_SWITCH_COM, antCtrlCommon & 0xffff);
+ 
+ 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ 		if (AR_SREV_9280(ah)) {
+@@ -508,7 +490,7 @@ static void ath9k_hw_def_set_board_value
+ 			regChainOffset = i * 0x1000;
+ 
+ 		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+-			  pModal->antCtrlChain[i]);
++			  le32_to_cpu(pModal->antCtrlChain[i]));
+ 
+ 		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ 			  (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
+@@ -655,7 +637,7 @@ static void ath9k_hw_def_set_board_value
+ static void ath9k_hw_def_set_addac(struct ath_hw *ah,
+ 				   struct ath9k_channel *chan)
+ {
+-#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
++#define XPA_LVL_FREQ(cnt) (le16_to_cpu(pModal->xpaBiasLvlFreq[cnt]))
+ 	struct modal_eep_header *pModal;
+ 	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+ 	u8 biaslevel;
+@@ -1315,7 +1297,9 @@ static void ath9k_hw_def_set_txpower(str
+ 
+ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
+ {
+-	return ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan;
++	__le16 spch = ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan;
++
++	return le16_to_cpu(spch);
+ }
+ 
+ static u8 ath9k_hw_def_get_eepmisc(struct ath_hw *ah)
diff --git a/package/kernel/mac80211/patches/557-ath9k-disable-bands-via-dt.patch b/package/kernel/mac80211/patches/557-ath9k-disable-bands-via-dt.patch
new file mode 100644
index 0000000000..ae447ce1f5
--- /dev/null
+++ b/package/kernel/mac80211/patches/557-ath9k-disable-bands-via-dt.patch
@@ -0,0 +1,32 @@
+--- a/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
++++ b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
+@@ -34,6 +34,14 @@ Optional properties:
+ 			ath9k wireless chip (in this case the calibration /
+ 			EEPROM data will be loaded from userspace using the
+ 			kernel firmware loader).
++- qca,disable-2ghz: Overrides the settings from the EEPROM and disables the
++			2.4GHz band. Setting this property is only needed
++			when the RF circuit does not support the 2.4GHz band
++			while it is enabled nevertheless in the EEPROM.
++- qca,disable-5ghz: Overrides the settings from the EEPROM and disables the
++			5GHz band. Setting this property is only needed when
++			the RF circuit does not support the 5GHz band while
++			it is enabled nevertheless in the EEPROM.
+ - mac-address: See ethernet.txt in the parent directory
+ - local-mac-address: See ethernet.txt in the parent directory
+ 
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -571,6 +571,12 @@ static int ath9k_of_init(struct ath_soft
+ 
+ 	ath_dbg(common, CONFIG, "parsing configuration from OF node\n");
+ 
++	if (of_property_read_bool(np, "qca,disable-2ghz"))
++		ah->disable_2ghz = true;
++
++	if (of_property_read_bool(np, "qca,disable-5ghz"))
++		ah->disable_5ghz = true;
++
+ 	if (of_property_read_bool(np, "qca,no-eeprom")) {
+ 		/* ath9k-eeprom-<bus>-<id>.bin */
+ 		scnprintf(eeprom_name, sizeof(eeprom_name),
diff --git a/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch b/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch
new file mode 100644
index 0000000000..723749259c
--- /dev/null
+++ b/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch
@@ -0,0 +1,418 @@
+--- a/drivers/net/wireless/ath/ath9k/channel.c
++++ b/drivers/net/wireless/ath/ath9k/channel.c
+@@ -15,6 +15,8 @@
+  */
+ 
+ #include "ath9k.h"
++#include <linux/ath9k_platform.h>
++#include "hsr.h"
+ 
+ /* Set/change channels.  If the channel is really being changed, it's done
+  * by reseting the chip.  To accomplish this we must first cleanup any pending
+@@ -22,6 +24,7 @@
+  */
+ static int ath_set_channel(struct ath_softc *sc)
+ {
++	struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 	struct ieee80211_hw *hw = sc->hw;
+@@ -41,6 +44,11 @@ static int ath_set_channel(struct ath_so
+ 	ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
+ 		chan->center_freq, chandef->width);
+ 
++	if (pdata && pdata->ubnt_hsr) {
++		ath9k_hsr_enable(ah, chandef->width, chan->center_freq);
++		ath9k_hsr_status(ah);
++	}
++
+ 	/* update survey stats for the old channel before switching */
+ 	spin_lock_bh(&common->cc_lock);
+ 	ath_update_survey_stats(sc);
+--- /dev/null
++++ b/drivers/net/wireless/ath/ath9k/hsr.c
+@@ -0,0 +1,247 @@
++/*
++ *
++ * The MIT License (MIT)
++ *
++ * Copyright (c) 2015 Kirill Berezin
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ *
++ */
++
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/time.h>
++#include <linux/bitops.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <asm/unaligned.h>
++
++#include "hw.h"
++#include "ath9k.h"
++
++#define HSR_GPIO_CSN 8
++#define HSR_GPIO_CLK 6
++#define HSR_GPIO_DOUT 7
++#define HSR_GPIO_DIN 5
++
++/* delays are in useconds */
++#define HSR_DELAY_HALF_TICK 100
++#define HSR_DELAY_PRE_WRITE 75
++#define HSR_DELAY_FINAL 20000
++#define HSR_DELAY_TRAILING 200
++
++void ath9k_hsr_init(struct ath_hw *ah)
++{
++	ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL);
++	ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL,
++				  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++	ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL,
++				  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++	ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL,
++				  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++
++	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
++	ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
++	ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0);
++
++	udelay(HSR_DELAY_TRAILING);
++}
++
++static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value)
++{
++	struct ath_common *common = ath9k_hw_common(ah);
++	int i;
++	u32 rval = 0;
++
++	udelay(delay);
++
++	ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
++	udelay(HSR_DELAY_HALF_TICK);
++
++	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0);
++	udelay(HSR_DELAY_HALF_TICK);
++
++	for (i = 0; i < 8; ++i) {
++		rval = rval << 1;
++
++		/* pattern is left to right, that is 7-th bit runs first */
++		ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1);
++		udelay(HSR_DELAY_HALF_TICK);
++
++		ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1);
++		udelay(HSR_DELAY_HALF_TICK);
++
++		rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN);
++
++		ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
++		udelay(HSR_DELAY_HALF_TICK);
++	}
++
++	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
++	udelay(HSR_DELAY_HALF_TICK);
++
++	ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n",
++		value, rval, rval > 32 ? rval : '-');
++
++	return rval & 0xff;
++}
++
++static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items)
++{
++	int status = 0;
++	int i = 0;
++	int err;
++
++	/* a preamble */
++	ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
++	status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
++
++	/* clear HSR's reply buffer */
++	if (status) {
++		int loop = 0;
++
++		for (loop = 0; (loop < 42) && status; ++loop)
++			status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE,
++						      0);
++
++		if (loop >= 42) {
++			ATH_DBG_WARN(1,
++				     "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n");
++			return -1;
++		}
++	}
++
++	for (i = 0; (i < items) && (chain[i] != 0); ++i)
++		ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]);
++
++	ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
++	mdelay(HSR_DELAY_FINAL / 1000);
++
++	/* reply */
++	memset(chain, 0, items);
++
++	ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
++	udelay(HSR_DELAY_TRAILING);
++
++	for (i = 0; i < (items - 1); ++i) {
++		u32 ret;
++
++		ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
++		if (ret != 0)
++			chain[i] = (char)ret;
++		else
++			break;
++
++		udelay(HSR_DELAY_TRAILING);
++	}
++
++	if (i <= 1)
++		return 0;
++
++	err = kstrtoint(chain + 1, 10, &i);
++	if (err)
++		return err;
++
++	return i;
++}
++
++int ath9k_hsr_disable(struct ath_hw *ah)
++{
++	char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0};
++	int ret;
++
++	ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
++	if ((ret > 0) && (*cmd == 'B'))
++		return 0;
++
++	return -1;
++}
++
++int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
++{
++	char cmd[10];
++	int ret;
++
++	/* Bandwidth argument is 0 sometimes. Assume default 802.11bgn
++	 * 20MHz on invalid values
++	 */
++	if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40))
++		bw = 20;
++
++	memset(cmd, 0, sizeof(cmd));
++	*cmd = 'b';
++	snprintf(cmd + 1, 3, "%02d", bw);
++
++	ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
++	if ((*cmd != 'B') || (ret != bw)) {
++		ATH_DBG_WARN(1,
++			     "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n",
++			     'b', bw, *cmd, ret);
++		return -1;
++	}
++
++	memset(cmd, 0, sizeof(cmd));
++	*cmd = 'x';
++	ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
++	if (*cmd != 'X') {
++		ATH_DBG_WARN(1,
++			     "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n",
++			     *cmd, ret);
++		return -1;
++	}
++
++	memset(cmd, 0, sizeof(cmd));
++	*cmd = 'm';
++	ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
++	if (*cmd != 'M') {
++		ATH_DBG_WARN(1,
++			     "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n",
++			     *cmd, ret);
++		return  -1;
++	}
++
++	memset(cmd, 0, sizeof(cmd));
++	*cmd = 'f';
++	snprintf(cmd + 1, 6, "%05d", fq);
++	ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
++	if ((*cmd != 'F') && (ret != fq)) {
++		ATH_DBG_WARN(1,
++			     "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n",
++			     *cmd, ret);
++		return -1;
++	}
++
++	return 0;
++}
++
++int ath9k_hsr_status(struct ath_hw *ah)
++{
++	char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0};
++	int ret;
++
++	ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
++	if (*cmd != 'S') {
++		ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd,
++			     ret);
++		return -1;
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/net/wireless/ath/ath9k/hsr.h
+@@ -0,0 +1,48 @@
++/*
++ * The MIT License (MIT)
++ *
++ * Copyright (c) 2015 Kirill Berezin
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++#ifndef HSR_H
++#define HSR_H
++
++#ifdef CPTCFG_ATH9K_UBNTHSR
++
++void ath9k_hsr_init(struct ath_hw *ah);
++int ath9k_hsr_disable(struct ath_hw *ah);
++int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq);
++int ath9k_hsr_status(struct ath_hw *ah);
++
++#else
++static inline void ath9k_hsr_init(struct ath_hw *ah) {}
++
++static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
++{
++	return 0;
++}
++
++static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; }
++static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; }
++
++#endif
++
++#endif /* HSR_H */
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -16,8 +16,10 @@
+ 
+ #include <linux/nl80211.h>
+ #include <linux/delay.h>
++#include <linux/ath9k_platform.h>
+ #include "ath9k.h"
+ #include "btcoex.h"
++#include "hsr.h"
+ 
+ u8 ath9k_parse_mpdudensity(u8 mpdudensity)
+ {
+@@ -652,6 +654,7 @@ void ath_reset_work(struct work_struct *
+ static int ath9k_start(struct ieee80211_hw *hw)
+ {
+ 	struct ath_softc *sc = hw->priv;
++	struct ath9k_platform_data *pdata = sc->dev->platform_data;
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+ 	struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
+@@ -730,6 +733,11 @@ static int ath9k_start(struct ieee80211_
+ 					  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ 	}
+ 
++	if (pdata && pdata->ubnt_hsr) {
++		ath9k_hsr_init(ah);
++		ath9k_hsr_disable(ah);
++	}
++
+ 	/*
+ 	 * Reset key cache to sane defaults (all entries cleared) instead of
+ 	 * semi-random values after suspend/resume.
+--- a/drivers/net/wireless/ath/ath9k/Makefile
++++ b/drivers/net/wireless/ath/ath9k/Makefile
+@@ -16,6 +16,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d
+ ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o
+ ath9k-$(CPTCFG_ATH9K_WOW) += wow.o
+ ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o
++ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o
+ 
+ ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o
+ 
+--- a/include/linux/ath9k_platform.h
++++ b/include/linux/ath9k_platform.h
+@@ -54,6 +54,8 @@ struct ath9k_platform_data {
+ 	unsigned num_btns;
+ 	const struct gpio_keys_button *btns;
+ 	unsigned btn_poll_interval;
++
++	bool ubnt_hsr;
+ };
+ 
+ #endif /* _LINUX_ATH9K_PLATFORM_H */
+--- a/.local-symbols
++++ b/.local-symbols
+@@ -153,6 +153,7 @@ ATH9K_WOW=
+ ATH9K_RFKILL=
+ ATH9K_CHANNEL_CONTEXT=
+ ATH9K_PCOEM=
++ATH9K_UBNTHSR=
+ ATH9K_HTC=
+ ATH9K_HTC_DEBUGFS=
+ ATH9K_HWRNG=
+--- a/drivers/net/wireless/ath/ath9k/Kconfig
++++ b/drivers/net/wireless/ath/ath9k/Kconfig
+@@ -59,6 +59,19 @@ config ATH9K_AHB
+ 	  Say Y, if you have a SoC with a compatible built-in
+ 	  wireless MAC. Say N if unsure.
+ 
++config ATH9K_UBNTHSR
++	bool "Ubiquiti UniFi Outdoor Plus HSR support"
++	depends on ATH9K
++	---help---
++	  This options enables code to control the HSR RF
++	  filter in the receive path of the Ubiquiti UniFi
++	  Outdoor Plus access point.
++
++	  Say Y if you want to use the access point. The
++	  code will only be used if the device is detected,
++	  so it does not harm other setup other than occupying
++	  a bit of memory.
++
+ config ATH9K_DEBUGFS
+ 	bool "Atheros ath9k debugging"
+ 	depends on ATH9K && DEBUG_FS
diff --git a/package/kernel/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch b/package/kernel/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch
new file mode 100644
index 0000000000..a901a44ba4
--- /dev/null
+++ b/package/kernel/mac80211/patches/700-mwl8k-missing-pci-id-for-WNR854T.patch
@@ -0,0 +1,10 @@
+--- a/drivers/net/wireless/marvell/mwl8k.c
++++ b/drivers/net/wireless/marvell/mwl8k.c
+@@ -5681,6 +5681,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
+ MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
+ 
+ static const struct pci_device_id mwl8k_pci_id_table[] = {
++	{ PCI_VDEVICE(MARVELL, 0x2a02), .driver_data = MWL8363, },
+ 	{ PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },
+ 	{ PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, },
+ 	{ PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, },
diff --git a/package/kernel/mac80211/scripts/import-backports.sh b/package/kernel/mac80211/scripts/import-backports.sh
new file mode 100755
index 0000000000..d056eb6d04
--- /dev/null
+++ b/package/kernel/mac80211/scripts/import-backports.sh
@@ -0,0 +1,109 @@
+#!/usr/bin/env bash
+BASE=$1; shift
+
+usage() {
+	echo "Usage: $0 NNN <file>..."
+	exit 1
+}
+
+check_number() {
+	case "$1" in
+		[0-9][0-9][0-9]) return 0;;
+	esac
+	return 1;
+}
+
+patch_header()
+{
+	awk '
+	/^(---|\*\*\*|Index:)[ \t][^ \t]|^diff -/ \
+		{ exit }
+		{ print }
+	'
+}
+
+strip_diffstat()
+{
+	awk '
+	/#? .* \| / \
+		{ eat = eat $0 "\n"
+		  next }
+	/^#? .* files? changed(, .* insertions?\(\+\))?(, .* deletions?\(-\))?/ \
+		{ eat = ""
+		  next }
+		{ print eat $0
+		  eat = "" }
+	'
+}
+
+strip_trailing_whitespace() {
+	sed -e 's:[ '$'\t'']*$::'
+}
+
+fixup_header() {
+	awk '
+		/^From / { next }
+		/^Subject: / {
+			sub("Subject: \\[[^\]]*\\]", "Subject: [PATCH]")
+		}
+		{ print }
+	'
+}
+
+check_number "$BASE" || usage
+
+quilt series > /dev/null || {
+	echo "Not in quilt directory"
+	exit 2
+}
+
+get_next() {
+	NEW=$BASE
+	quilt series | while read CUR; do
+		[ -n "$CUR" ] || break
+		CUR=${CUR%%-*}
+		check_number "$CUR" || continue
+		[ "$CUR" -lt "$NEW" ] && continue
+		[ "$CUR" -ge "$(($BASE + 100))" ] && continue
+		NEW="$(($CUR + 1))"
+		echo $NEW
+	done | tail -n1
+}
+
+CUR=`get_next`
+CUR="${CUR:-$BASE}"
+
+while [ -n "$1" ]; do
+	FILE="$1"; shift
+	NAME="$(basename $FILE)"
+	NAME="${NAME#[0-9]*-}"
+	echo -n "Processing patch $NAME: "
+
+	[ -e "$FILE" ] || {
+		echo "file $FILE not found"
+		exit 1
+	}
+
+	grep -qE "$NAME$" patches/series && {
+		echo "already applied"
+		continue
+	}
+
+	quilt new "$CUR-$NAME" || exit 1
+	patch_header < "$FILE" |
+		strip_diffstat |
+		strip_trailing_whitespace |
+		fixup_header > "patches/$CUR-$NAME"
+
+	quilt fold < "$FILE" || {
+		cp "$FILE" ./cur_patch
+		echo "patch $FILE failed to apply, copied to ./cur_patch"
+		exit 1
+	}
+
+	quilt refresh -p ab --no-index --no-timestamps
+
+	CUR="$(($CUR + 1))"
+done
+
+exit 0
diff --git a/package/kernel/mmc_over_gpio/Makefile b/package/kernel/mmc_over_gpio/Makefile
new file mode 100644
index 0000000000..ada293da10
--- /dev/null
+++ b/package/kernel/mmc_over_gpio/Makefile
@@ -0,0 +1,77 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=mmc-over-gpio
+PKG_RELEASE:=4
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define KernelPackage/mmc-over-gpio
+  SUBMENU:=Other modules
+  DEPENDS:=@GPIO_SUPPORT +kmod-mmc-spi +kmod-spi-gpio-old +kmod-fs-configfs @!LINUX_4_4
+  KCONFIG:=CONFIG_GPIOMMC
+  TITLE:=MMC/SD card over GPIO support
+  FILES:=$(LINUX_DIR)/drivers/mmc/host/gpiommc.ko
+  AUTOLOAD:=$(call AutoProbe,gpiommc)
+  MENU:=1
+endef
+
+define Package/kmod-mmc-over-gpio/config
+	menu "Configuration"
+		depends on PACKAGE_kmod-mmc-over-gpio
+
+	config KMOD_MMC_OVER_GPIO_DI_PIN
+		int "GPIO DI (Data-In) pin"
+		default 1
+
+	config KMOD_MMC_OVER_GPIO_DO_PIN
+		int "GPIO DO (Data-Out) pin"
+		default 3
+
+	config KMOD_MMC_OVER_GPIO_CLK_PIN
+		int "GPIO CLK (Clock) pin"
+		default 4
+
+	config KMOD_MMC_OVER_GPIO_CS_PIN
+		int "GPIO CS (Chip-Select) pin"
+		default 7
+
+	endmenu
+endef
+
+define KernelPackage/mmc-over-gpio/description
+ Support for driving an MMC/SD card over GPIO pins via SPI.
+endef
+
+define KernelPackage/mmc-over-gpio/conffiles
+/etc/config/mmc_over_gpio
+endef
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+endef
+
+define Build/Compile
+endef
+
+define KernelPackage/mmc-over-gpio/install
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_DATA) ./files/mmc_over_gpio.config $(1)/etc/config/mmc_over_gpio
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/mmc_over_gpio.init $(1)/etc/init.d/mmc_over_gpio
+
+	$(SED) 's,@GPIO_DI_PIN@,$(CONFIG_KMOD_MMC_OVER_GPIO_DI_PIN),g' \
+		-e 's,@GPIO_DO_PIN@,$(CONFIG_KMOD_MMC_OVER_GPIO_DO_PIN),g' \
+		-e 's,@GPIO_CLK_PIN@,$(CONFIG_KMOD_MMC_OVER_GPIO_CLK_PIN),g' \
+		-e 's,@GPIO_CS_PIN@,$(CONFIG_KMOD_MMC_OVER_GPIO_CS_PIN),g' \
+		$(1)/etc/config/mmc_over_gpio
+endef
+
+$(eval $(call KernelPackage,mmc-over-gpio))
diff --git a/package/kernel/mmc_over_gpio/files/mmc_over_gpio.config b/package/kernel/mmc_over_gpio/files/mmc_over_gpio.config
new file mode 100644
index 0000000000..23f0084857
--- /dev/null
+++ b/package/kernel/mmc_over_gpio/files/mmc_over_gpio.config
@@ -0,0 +1,8 @@
+config 'mmc_over_gpio'
+	option 'name' 'default'
+	option 'enabled' '0'
+	option 'DI_pin' '@GPIO_DI_PIN@'
+	option 'DO_pin' '@GPIO_DO_PIN@'
+	option 'CLK_pin' '@GPIO_CLK_PIN@'
+	option 'CS_pin' '@GPIO_CS_PIN@'
+	option 'mode' '0'
diff --git a/package/kernel/mmc_over_gpio/files/mmc_over_gpio.init b/package/kernel/mmc_over_gpio/files/mmc_over_gpio.init
new file mode 100644
index 0000000000..121c80398c
--- /dev/null
+++ b/package/kernel/mmc_over_gpio/files/mmc_over_gpio.init
@@ -0,0 +1,83 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2008 OpenWrt.org
+START=90
+
+CONFIGFS_DIR="/config/gpiommc"
+
+# add_device(name, DI_pin, DO_pin, CLK_pin, CS_pin, mode)
+add_device() {
+	local dir="$CONFIGFS_DIR/$1"
+
+	mkdir -p $dir
+	[ $? -eq 0 ] || return 1
+	echo $2 > $dir/gpio_data_in
+	[ $? -eq 0 ] || return 1
+	echo $3 > $dir/gpio_data_out
+	[ $? -eq 0 ] || return 1
+	echo $4 > $dir/gpio_clock
+	[ $? -eq 0 ] || return 1
+	echo $5 > $dir/gpio_chipselect
+	[ $? -eq 0 ] || return 1
+	echo $6 > $dir/spi_mode
+	[ $? -eq 0 ] || return 1
+	# XXX We have more config options available. Use defaults for now.
+
+	echo 1 > $dir/register
+	[ $? -eq 0 ] || return 1
+
+	return 0
+}
+
+# remove_device(name)
+remove_device() {
+	local dir="$CONFIGFS_DIR/$1"
+
+	rmdir $dir
+}
+
+mount_configfs() {
+	# FIXME: This should probably be done somewhere else.
+	mount | grep configfs
+	if [ $? -eq 0 ]; then
+		# already mounted
+		return 0
+	fi
+	mkdir -p /config
+	[ $? -eq 0 ] || return 1
+	mount configfs -t configfs /config
+	[ $? -eq 0 ] || return 1
+
+	return 0
+}
+
+start_service() {
+	local section="$1"
+	config_get "name" "$section" "name"
+	config_get "DI_pin" "$section" "DI_pin"
+	config_get "DO_pin" "$section" "DO_pin"
+	config_get "CLK_pin" "$section" "CLK_pin"
+	config_get "CS_pin" "$section" "CS_pin"
+	config_get "mode" "$section" "mode"
+	config_get_bool "enabled" "$section" "enabled" '1'
+	[ "$enabled" -gt 0 ] && add_device "$name" $DI_pin $DO_pin $CLK_pin $CS_pin $mode &
+}
+
+stop_service() {
+	local section="$1"
+	config_get "name" "$section" "name"
+	remove_device "$name"
+}
+
+start() {
+	# Make sure configfs is mounted
+	mount_configfs
+	[ $? -eq 0 ] || return 1
+
+	config_load "mmc_over_gpio"
+	config_foreach start_service "mmc_over_gpio"
+}
+
+stop() {
+	config_load "mmc_over_gpio"
+	config_foreach stop_service "mmc_over_gpio"
+}
diff --git a/package/kernel/om-watchdog/Makefile b/package/kernel/om-watchdog/Makefile
new file mode 100644
index 0000000000..7d517a11eb
--- /dev/null
+++ b/package/kernel/om-watchdog/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=om-watchdog
+PKG_RELEASE:=1
+PKG_VERSION:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/om-watchdog
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=om watchdog
+  URL:=http://openwrt.org/
+endef
+
+define Package/om-watchdog/description
+ This package contains the hw watchdog script for the OM1P and OM2P device.
+endef
+
+define Build/Prepare
+endef
+
+define Build/Compile
+endef
+
+define Build/Compile
+endef
+
+define Package/om-watchdog/install
+	$(INSTALL_DIR) $(1)/etc/init.d/
+	$(INSTALL_DIR) $(1)/sbin/
+	$(INSTALL_BIN) ./files/om-watchdog.init $(1)/etc/init.d/om-watchdog
+	$(INSTALL_BIN) ./files/om-watchdog $(1)/sbin/om-watchdog
+endef
+
+
+$(eval $(call BuildPackage,om-watchdog))
+
diff --git a/package/kernel/om-watchdog/files/om-watchdog b/package/kernel/om-watchdog/files/om-watchdog
new file mode 100644
index 0000000000..d730c68447
--- /dev/null
+++ b/package/kernel/om-watchdog/files/om-watchdog
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+GPIO=$1
+
+trap "" INT HUP
+
+echo $GPIO > /sys/class/gpio/export
+echo out > /sys/class/gpio/gpio${GPIO}/direction
+
+while true; do
+	echo 1 > /sys/class/gpio/gpio${GPIO}/value
+	sleep 1
+	echo 0 > /sys/class/gpio/gpio${GPIO}/value
+	sleep 180
+done
diff --git a/package/kernel/om-watchdog/files/om-watchdog.init b/package/kernel/om-watchdog/files/om-watchdog.init
new file mode 100644
index 0000000000..4ed178db7e
--- /dev/null
+++ b/package/kernel/om-watchdog/files/om-watchdog.init
@@ -0,0 +1,64 @@
+#!/bin/sh /etc/rc.common
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+
+START=11
+STOP=11
+
+USE_PROCD=1
+NAME=om-watchdog
+PROG=/sbin/om-watchdog
+
+get_gpio() {
+	if [ -r /lib/ar71xx.sh ]; then
+		. /lib/ar71xx.sh
+		local board=$(ar71xx_board_name)
+
+		case "$board" in
+			"om2p" | \
+			"om2p-hs" | \
+			"om2p-hsv2" | \
+			"om2p-hsv3" | \
+			"om5p-acv2")
+				return 12
+				;;
+			"om2pv2" | \
+			"om2p-lc")
+				return 26
+				;;
+			"om5p" | \
+			"om5p-an")
+				return 11
+				;;
+			"om5p-ac")
+				return 17
+				;;
+			"mr600v2")
+				return 15
+				;;
+			"mr900" | \
+			"mr900v2" | \
+			"mr1750" | \
+			"mr1750v2")
+				return 16
+				;;
+		esac
+	else
+		#we assume it is om1p in this case
+		return 3
+	fi
+
+	return 255
+}
+
+start_service() {
+	get_gpio
+	gpio="$?"
+	[ "$gpio" != "255" ] || return
+
+	procd_open_instance
+	procd_set_param command "${PROG}" "${gpio}"
+	procd_set_param respawn
+	procd_close_instance
+}
diff --git a/package/kernel/rotary-gpio-custom/Makefile b/package/kernel/rotary-gpio-custom/Makefile
new file mode 100644
index 0000000000..f338fe7ad0
--- /dev/null
+++ b/package/kernel/rotary-gpio-custom/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=rotary-gpio-custom
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/rotary-gpio-custom
+  SUBMENU:=Other modules
+  TITLE:=Custom GPIO-based rotary encoder device
+  DEPENDS:=@GPIO_SUPPORT +kmod-input-gpio-encoder
+  FILES:=$(PKG_BUILD_DIR)/rotary-gpio-custom.ko
+  KCONFIG:=
+endef
+
+define KernelPackage/rotary-gpio-custom/description
+ Kernel module for register a custom rotary-gpio-encoder platform device.
+endef
+
+EXTRA_KCONFIG:= \
+	CONFIG_ROTARY_GPIO_CUSTOM=m
+
+EXTRA_CFLAGS:= \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)" \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+	$(EXTRA_KCONFIG)
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,rotary-gpio-custom))
diff --git a/package/kernel/rotary-gpio-custom/src/Kconfig b/package/kernel/rotary-gpio-custom/src/Kconfig
new file mode 100644
index 0000000000..b4d55d5354
--- /dev/null
+++ b/package/kernel/rotary-gpio-custom/src/Kconfig
@@ -0,0 +1,9 @@
+config ROTARY_GPIO_CUSTOM
+	tristate "Custom GPIO-based rotary driver"
+	depends on GENERIC_GPIO
+	help
+	  This is a driver to register 1 to 4 custom rotary encoder using
+	  GPIO lines.
+
+	  This support is also available as a module.  If so, the module
+	  will be called rotary-gpio-custom.
diff --git a/package/kernel/rotary-gpio-custom/src/Makefile b/package/kernel/rotary-gpio-custom/src/Makefile
new file mode 100644
index 0000000000..133672687b
--- /dev/null
+++ b/package/kernel/rotary-gpio-custom/src/Makefile
@@ -0,0 +1 @@
+obj-${CONFIG_ROTARY_GPIO_CUSTOM}	+= rotary-gpio-custom.o
diff --git a/package/kernel/rotary-gpio-custom/src/rotary-gpio-custom.c b/package/kernel/rotary-gpio-custom/src/rotary-gpio-custom.c
new file mode 100644
index 0000000000..9a16e45287
--- /dev/null
+++ b/package/kernel/rotary-gpio-custom/src/rotary-gpio-custom.c
@@ -0,0 +1,193 @@
+/*
+ *  Custom GPIO-based rotary driver
+ *
+ *  Copyright (C) 2010 Claudio Mignanti <c.mignanti@gmail.com>
+ *
+ *  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.
+ *
+ *  Strongly based on Custom GPIO-based I2C driver by:
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * ---------------------------------------------------------------------------
+ *
+ *  The behaviour of this driver can be altered by setting some parameters
+ *  from the insmod command line.
+ *
+ *  The following parameters are adjustable:
+ *
+ *	bus0	These four arguments can be arrays of
+ *	bus1	1-8 unsigned integers as follows:
+ *	bus2
+ *	bus3	<id>,<steps>,<axis>,<gpioa>,<gpiob>,<inverted>
+ *
+ *
+ *  If this driver is built into the kernel, you can use the following kernel
+ *  command line parameters, with the same values as the corresponding module
+ *  parameters listed above:
+ *
+ *	rotary-gpio-custom.bus0
+ *	rotary-gpio-custom.bus1
+ *	rotary-gpio-custom.bus2
+ *	rotary-gpio-custom.bus3
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/rotary_encoder.h>
+
+#define DRV_NAME	"rotary-gpio-custom"
+#define DRV_DESC	"Custom GPIO-based rotary driver"
+#define DRV_VERSION	"0.1.0"
+
+#define PFX		DRV_NAME ": "
+
+#define BUS_PARAM_REQUIRED	5
+#define BUS_PARAM_COUNT		6
+#define BUS_COUNT_MAX		4
+
+static unsigned int bus0[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus1[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus2[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus3[BUS_PARAM_COUNT] __initdata;
+
+static unsigned int bus_nump[BUS_COUNT_MAX] __initdata;
+
+#define BUS_PARM_DESC \
+	" config -> id,steps,axis,gpioa,gpiob[,inverted]"
+
+module_param_array(bus0, uint, &bus_nump[0], 0);
+MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC);
+module_param_array(bus1, uint, &bus_nump[1], 0);
+MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC);
+module_param_array(bus2, uint, &bus_nump[2], 0);
+MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC);
+module_param_array(bus3, uint, &bus_nump[3], 0);
+MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC);
+
+static struct platform_device *devices[BUS_COUNT_MAX];
+static unsigned int nr_devices;
+
+static void rotary_gpio_custom_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < nr_devices; i++)
+		if (devices[i])
+			platform_device_put(devices[i]);
+}
+
+static int __init rotary_gpio_custom_add_one(unsigned int id,
+					     unsigned int *params)
+{
+	struct platform_device *pdev;
+	struct rotary_encoder_platform_data pdata;
+	int err;
+
+	if (!bus_nump[id])
+		return 0;
+
+	if (bus_nump[id] < BUS_PARAM_REQUIRED) {
+		printk(KERN_ERR PFX "not enough parameters for bus%d\n", id);
+		err = -EINVAL;
+		goto err;
+	}
+
+	pdev = platform_device_alloc("rotary-gpio", params[0]);
+	if (!pdev) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	pdata.steps = params[1];
+	pdata.axis = params[2];
+	pdata.relative_axis = false;
+	pdata.rollover = false;
+	pdata.gpio_a = params[3];
+	pdata.gpio_b = params[4];
+
+	if (params[5] == 1) {
+		pdata.inverted_a = 1;
+		pdata.inverted_b = 1;
+	} else {
+		pdata.inverted_a = 0;
+		pdata.inverted_b = 0;
+	}
+
+	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+	if (err)
+		goto err_put;
+
+	err = platform_device_add(pdev);
+	if (err)
+		goto err_put;
+
+	devices[nr_devices++] = pdev;
+	return 0;
+
+err_put:
+	platform_device_put(pdev);
+err:
+	return err;
+}
+
+static int __init rotary_gpio_custom_probe(void)
+{
+	int err;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+	err = rotary_gpio_custom_add_one(0, bus0);
+	if (err)
+		goto err;
+
+	err = rotary_gpio_custom_add_one(1, bus1);
+	if (err)
+		goto err;
+
+	err = rotary_gpio_custom_add_one(2, bus2);
+	if (err)
+		goto err;
+
+	err = rotary_gpio_custom_add_one(3, bus3);
+	if (err)
+		goto err;
+
+	if (!nr_devices) {
+		printk(KERN_ERR PFX "no bus parameter(s) specified\n");
+		err = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	rotary_gpio_custom_cleanup();
+	return err;
+}
+
+#ifdef MODULE
+static int __init rotary_gpio_custom_init(void)
+{
+	return rotary_gpio_custom_probe();
+}
+module_init(rotary_gpio_custom_init);
+
+static void __exit rotary_gpio_custom_exit(void)
+{
+	rotary_gpio_custom_cleanup();
+}
+module_exit(rotary_gpio_custom_exit);
+#else
+subsys_initcall(rotary_gpio_custom_probe);
+#endif /* MODULE*/
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org >");
+MODULE_AUTHOR("Claudio Mignanti <c.mignanti@gmail.com>");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
diff --git a/package/kernel/spi-gpio-custom/Makefile b/package/kernel/spi-gpio-custom/Makefile
new file mode 100644
index 0000000000..e6d692db44
--- /dev/null
+++ b/package/kernel/spi-gpio-custom/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=spi-gpio-custom
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/spi-gpio-custom
+  SUBMENU:=SPI Support
+  TITLE:=Custom GPIO-based SPI device
+  DEPENDS:=@GPIO_SUPPORT +kmod-spi-bitbang +kmod-spi-gpio +kmod-spi-dev
+  FILES:=$(PKG_BUILD_DIR)/spi-gpio-custom.ko
+  KCONFIG:=
+endef
+
+define KernelPackage/spi-gpio-custom/description
+ Kernel module for register a custom spi-gpio platform device.
+endef
+
+EXTRA_KCONFIG:= \
+	CONFIG_SPI_GPIO_CUSTOM=m
+
+EXTRA_CFLAGS:= \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)" \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+	$(EXTRA_KCONFIG)
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,spi-gpio-custom))
diff --git a/package/kernel/spi-gpio-custom/src/Kconfig b/package/kernel/spi-gpio-custom/src/Kconfig
new file mode 100644
index 0000000000..5e15f05a7b
--- /dev/null
+++ b/package/kernel/spi-gpio-custom/src/Kconfig
@@ -0,0 +1,14 @@
+config SPI_GPIO_CUSTOM
+	tristate "Custom GPIO-based SPI driver"
+	depends on GENERIC_GPIO
+	select SPI_GPIO
+	help
+	  This is an SPI driver to register 1 to 4 custom SPI buses using
+	  GPIO lines. Each bus can have up to 8 slaves.
+	  The devices will be exposed to userspace as /dev/spidevX.X
+	  
+	  This module is maily intended to interface microcontrollers
+	  and other SPI devices without a specific kernel driver.
+
+	  This support is also available as a module.  If so, the module
+	  will be called spi-gpio-custom.
diff --git a/package/kernel/spi-gpio-custom/src/Makefile b/package/kernel/spi-gpio-custom/src/Makefile
new file mode 100644
index 0000000000..cf8c55f98c
--- /dev/null
+++ b/package/kernel/spi-gpio-custom/src/Makefile
@@ -0,0 +1 @@
+obj-${CONFIG_SPI_GPIO_CUSTOM}	+= spi-gpio-custom.o
\ No newline at end of file
diff --git a/package/kernel/spi-gpio-custom/src/spi-gpio-custom.c b/package/kernel/spi-gpio-custom/src/spi-gpio-custom.c
new file mode 100644
index 0000000000..4c13b56d79
--- /dev/null
+++ b/package/kernel/spi-gpio-custom/src/spi-gpio-custom.c
@@ -0,0 +1,365 @@
+/*
+ *  Custom GPIO-based SPI driver
+ *
+ *  Copyright (C) 2013 Marco Burato <zmaster.adsl@gmail.com>
+ *
+ *  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.
+ *
+ *  Based on i2c-gpio-custom by:
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ * ---------------------------------------------------------------------------
+ *
+ *  The behaviour of this driver can be altered by setting some parameters
+ *  from the insmod command line.
+ *
+ *  The following parameters are adjustable:
+ *
+ *	bus0	These four arguments can be arrays of
+ *	bus1	1-8 unsigned integers as follows:
+ *	bus2
+ *	bus3	<id>,<sck>,<mosi>,<miso>,<mode1>,<maxfreq1>,<cs1>,...
+ *
+ *  where:
+ *
+ *  <id>	ID to used as device_id for the corresponding bus (required)
+ *  <sck>	GPIO pin ID to be used for bus SCK (required)
+ *  <mosi>	GPIO pin ID to be used for bus MOSI (required*)
+ *  <miso>	GPIO pin ID to be used for bus MISO (required*)
+ *  <modeX>	Mode configuration for slave X in the bus (required)
+ *		(see /include/linux/spi/spi.h)
+ *  <maxfreqX>	Maximum clock frequency in Hz for slave X in the bus (required)
+ *  <csX>	GPIO pin ID to be used for slave X CS (required**)
+ *
+ *	Notes:
+ *	*	If a signal is not used (for example there is no MISO) you need
+ *		to set the GPIO pin ID for that signal to an invalid value.
+ *	**	If you only have 1 slave in the bus with no CS, you can omit the
+ *		<cs1> param or set it to an invalid GPIO id to disable it. When
+ *		you have 2 or more slaves, they must all have a valid CS.
+ *
+ *  If this driver is built into the kernel, you can use the following kernel
+ *  command line parameters, with the same values as the corresponding module
+ *  parameters listed above:
+ *
+ *	spi-gpio-custom.bus0
+ *	spi-gpio-custom.bus1
+ *	spi-gpio-custom.bus2
+ *	spi-gpio-custom.bus3
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+
+#define DRV_NAME	"spi-gpio-custom"
+#define DRV_DESC	"Custom GPIO-based SPI driver"
+#define DRV_VERSION	"0.1"
+
+#define PFX		DRV_NAME ": "
+
+#define BUS_PARAM_ID		0
+#define BUS_PARAM_SCK		1
+#define BUS_PARAM_MOSI		2
+#define BUS_PARAM_MISO		3
+#define BUS_PARAM_MODE1		4
+#define BUS_PARAM_MAXFREQ1	5
+#define BUS_PARAM_CS1		6
+
+#define BUS_SLAVE_COUNT_MAX	8
+#define BUS_PARAM_REQUIRED	6
+#define BUS_PARAM_PER_SLAVE	3
+#define BUS_PARAM_COUNT		(4+BUS_PARAM_PER_SLAVE*BUS_SLAVE_COUNT_MAX)
+#define BUS_COUNT_MAX		4
+
+static unsigned int bus0[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus1[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus2[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus3[BUS_PARAM_COUNT] __initdata;
+
+static unsigned int bus_nump[BUS_COUNT_MAX] __initdata;
+
+#define BUS_PARM_DESC \
+	" config -> id,sck,mosi,miso,mode1,maxfreq1[,cs1,mode2,maxfreq2,cs2,...]"
+
+module_param_array(bus0, uint, &bus_nump[0], 0);
+MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC);
+module_param_array(bus1, uint, &bus_nump[1], 0);
+MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC);
+module_param_array(bus2, uint, &bus_nump[2], 0);
+MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC);
+module_param_array(bus3, uint, &bus_nump[3], 0);
+MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC);
+
+static struct platform_device *devices[BUS_COUNT_MAX];
+static unsigned int nr_devices;
+
+static void spi_gpio_custom_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < nr_devices; i++)
+		if (devices[i])
+			platform_device_unregister(devices[i]);
+}
+
+static int __init spi_gpio_custom_get_slave_mode(unsigned int id,
+					  unsigned int *params,
+					  int slave_index)
+{
+	int param_index;
+
+	param_index = BUS_PARAM_MODE1+slave_index*BUS_PARAM_PER_SLAVE;
+	if (param_index >= bus_nump[id])
+		return -1;
+
+	return params[param_index];
+}
+static int __init spi_gpio_custom_get_slave_maxfreq(unsigned int id,
+					     unsigned int *params,
+					     int slave_index)
+{
+	int param_index;
+
+	param_index = BUS_PARAM_MAXFREQ1+slave_index*BUS_PARAM_PER_SLAVE;
+	if (param_index >= bus_nump[id])
+		return -1;
+
+	return params[param_index];
+}
+static int __init spi_gpio_custom_get_slave_cs(unsigned int id,
+					unsigned int *params,
+					int slave_index)
+{
+	int param_index;
+
+	param_index = BUS_PARAM_CS1+slave_index*BUS_PARAM_PER_SLAVE;
+	if (param_index >= bus_nump[id])
+		return -1;
+	if (!gpio_is_valid(params[param_index]))
+		return -1;
+
+	return params[param_index];
+}
+
+static int __init spi_gpio_custom_check_params(unsigned int id, unsigned int *params)
+{
+	int i;
+	struct spi_master *master;
+
+	if (bus_nump[id] < BUS_PARAM_REQUIRED) {
+		printk(KERN_ERR PFX "not enough values for parameter bus%d\n",
+		       id);
+		return -EINVAL;
+	}
+
+	if (bus_nump[id] > (1+BUS_PARAM_CS1)) {
+		/* more than 1 device: check CS GPIOs */
+		for (i = 0; i < BUS_SLAVE_COUNT_MAX; i++) {
+			/* no more slaves? */
+			if (spi_gpio_custom_get_slave_mode(id, params, i) < 0)
+				break;
+
+			if (spi_gpio_custom_get_slave_cs(id, params, i) < 0) {
+				printk(KERN_ERR PFX "invalid/missing CS gpio for slave %d on bus %d\n",
+				       i, params[BUS_PARAM_ID]);
+				return -EINVAL;
+			}
+		}
+	}
+
+	if (!gpio_is_valid(params[BUS_PARAM_SCK])) {
+		printk(KERN_ERR PFX "invalid SCK gpio for bus %d\n",
+		       params[BUS_PARAM_ID]);
+		return -EINVAL;
+	}
+
+	master = spi_busnum_to_master(params[BUS_PARAM_ID]);
+	if (master) {
+		spi_master_put(master);
+		printk(KERN_ERR PFX "bus %d already exists\n",
+		       params[BUS_PARAM_ID]);
+		return -EEXIST;
+	}
+
+	return 0;
+}
+
+static int __init spi_gpio_custom_add_one(unsigned int id, unsigned int *params)
+{
+	struct platform_device *pdev;
+	struct spi_gpio_platform_data pdata;
+	int i;
+	int num_cs;
+	int err;
+	struct spi_master *master;
+	struct spi_device *slave;
+	struct spi_board_info slave_info;
+	int mode, maxfreq, cs;
+
+
+	if (!bus_nump[id])
+		return 0;
+
+	err = spi_gpio_custom_check_params(id, params);
+	if (err)
+		goto err;
+
+	/* Create BUS device node */
+
+	pdev = platform_device_alloc("spi_gpio", params[BUS_PARAM_ID]);
+	if (!pdev) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	num_cs = 0;
+	for (i = 0; i < BUS_SLAVE_COUNT_MAX; i++) {
+		/* no more slaves? */
+		if (spi_gpio_custom_get_slave_mode(id, params, i) < 0)
+			break;
+
+		if (spi_gpio_custom_get_slave_cs(id, params, i) >= 0)
+			num_cs++;
+	}
+	if (num_cs == 0) {
+		/*
+		 * Even if no CS is used, spi modules expect
+		 * at least 1 (unused)
+		 */
+		num_cs = 1;
+	}
+
+	pdata.sck = params[BUS_PARAM_SCK];
+	pdata.mosi = gpio_is_valid(params[BUS_PARAM_MOSI])
+		? params[BUS_PARAM_MOSI]
+		: SPI_GPIO_NO_MOSI;
+	pdata.miso = gpio_is_valid(params[BUS_PARAM_MISO])
+		? params[BUS_PARAM_MISO]
+		: SPI_GPIO_NO_MISO;
+	pdata.num_chipselect = num_cs;
+
+	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+	if (err) {
+		platform_device_put(pdev);
+		goto err;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR PFX "platform_device_add failed with return code %d\n",
+		       err);
+		platform_device_put(pdev);
+		goto err;
+	}
+
+	/* Register SLAVE devices */
+
+	for (i = 0; i < BUS_SLAVE_COUNT_MAX; i++) {
+		mode = spi_gpio_custom_get_slave_mode(id, params, i);
+		maxfreq = spi_gpio_custom_get_slave_maxfreq(id, params, i);
+		cs = spi_gpio_custom_get_slave_cs(id, params, i);
+
+		/* no more slaves? */
+		if (mode < 0)
+			break;
+
+		memset(&slave_info, 0, sizeof(slave_info));
+		strcpy(slave_info.modalias, "spidev");
+		slave_info.controller_data = (void *)((cs >= 0)
+			? cs
+			: SPI_GPIO_NO_CHIPSELECT);
+		slave_info.max_speed_hz = maxfreq;
+		slave_info.bus_num = params[BUS_PARAM_ID];
+		slave_info.chip_select = i;
+		slave_info.mode = mode;
+
+		master = spi_busnum_to_master(params[BUS_PARAM_ID]);
+		if (!master) {
+			printk(KERN_ERR PFX "unable to get master for bus %d\n",
+			       params[BUS_PARAM_ID]);
+			err = -EINVAL;
+			goto err_unregister;
+		}
+		slave = spi_new_device(master, &slave_info);
+		spi_master_put(master);
+		if (!slave) {
+			printk(KERN_ERR PFX "unable to create slave %d for bus %d\n",
+			       i, params[BUS_PARAM_ID]);
+			/* Will most likely fail due to unsupported mode bits */
+			err = -EINVAL;
+			goto err_unregister;
+		}
+	}
+
+	devices[nr_devices++] = pdev;
+
+	return 0;
+
+err_unregister:
+	platform_device_unregister(pdev);
+err:
+	return err;
+}
+
+static int __init spi_gpio_custom_probe(void)
+{
+	int err;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+	err = spi_gpio_custom_add_one(0, bus0);
+	if (err)
+		goto err;
+
+	err = spi_gpio_custom_add_one(1, bus1);
+	if (err)
+		goto err;
+
+	err = spi_gpio_custom_add_one(2, bus2);
+	if (err)
+		goto err;
+
+	err = spi_gpio_custom_add_one(3, bus3);
+	if (err)
+		goto err;
+
+	if (!nr_devices) {
+		printk(KERN_ERR PFX "no bus parameter(s) specified\n");
+		err = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	spi_gpio_custom_cleanup();
+	return err;
+}
+
+#ifdef MODULE
+static int __init spi_gpio_custom_init(void)
+{
+	return spi_gpio_custom_probe();
+}
+module_init(spi_gpio_custom_init);
+
+static void __exit spi_gpio_custom_exit(void)
+{
+	spi_gpio_custom_cleanup();
+}
+module_exit(spi_gpio_custom_exit);
+#else
+subsys_initcall(spi_gpio_custom_probe);
+#endif /* MODULE*/
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Marco Burato <zmaster.adsl@gmail.com>");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
diff --git a/package/kernel/trelay/Makefile b/package/kernel/trelay/Makefile
new file mode 100644
index 0000000000..f95115a7d9
--- /dev/null
+++ b/package/kernel/trelay/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=trelay
+PKG_VERSION:=0.1
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/trelay
+  SUBMENU:=Network Support
+  TITLE:=Trivial Ethernet Relay
+  FILES:=$(PKG_BUILD_DIR)/trelay.ko
+  AUTOLOAD:=$(call AutoLoad,50,trelay)
+endef
+
+define KernelPackage/trelay/description
+trelay relays ethernet packets between two devices (similar to a bridge), but
+without any MAC address checks. This makes it possible to bridge client mode
+or ad-hoc mode wifi devices to ethernet VLANs, assuming the remote end uses
+the same source MAC address as the device that packets are supposed to exit
+from.
+endef
+
+include $(INCLUDE_DIR)/kernel-defaults.mk
+
+define Build/Compile
+	$(MAKE) $(KERNEL_MAKEOPTS) SUBDIRS="$(PKG_BUILD_DIR)" modules
+endef
+
+define KernelPackage/trelay/conffiles
+/etc/config/trelay
+endef
+
+define KernelPackage/trelay/install
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/net $(1)/etc/init.d $(1)/etc/config
+	$(INSTALL_DATA) ./files/trelay.hotplug $(1)/etc/hotplug.d/net/50-trelay
+	$(INSTALL_BIN) ./files/trelay.init $(1)/etc/init.d/trelay
+	$(INSTALL_DATA) ./files/trelay.config $(1)/etc/config/trelay
+endef
+
+$(eval $(call KernelPackage,trelay))
diff --git a/package/kernel/trelay/files/trelay.config b/package/kernel/trelay/files/trelay.config
new file mode 100644
index 0000000000..eb05013056
--- /dev/null
+++ b/package/kernel/trelay/files/trelay.config
@@ -0,0 +1,4 @@
+config trelay
+	option enabled	0
+	option dev1	eth0
+	option dev2	wlan0
diff --git a/package/kernel/trelay/files/trelay.hotplug b/package/kernel/trelay/files/trelay.hotplug
new file mode 100644
index 0000000000..31f7378406
--- /dev/null
+++ b/package/kernel/trelay/files/trelay.hotplug
@@ -0,0 +1,5 @@
+case "$ACTION" in
+	add|register)
+		[ -f /var/run/trelay.active ] && /etc/init.d/trelay start
+	;;
+esac
diff --git a/package/kernel/trelay/files/trelay.init b/package/kernel/trelay/files/trelay.init
new file mode 100644
index 0000000000..e705275e3a
--- /dev/null
+++ b/package/kernel/trelay/files/trelay.init
@@ -0,0 +1,32 @@
+#!/bin/sh /etc/rc.common
+START=80
+
+check_relay() {
+	local cfg="$1"
+
+	config_get_bool enabled "$cfg" enabled 1
+	[ "$enabled" -gt 0 ] || return
+
+	config_get dev1 "$cfg" dev1
+	config_get dev2 "$cfg" dev2
+
+	[ -d "/sys/kernel/debug/trelay/${dev1}-${dev2}" ] && return
+	[ -d "/sys/class/net/${dev1}" -a -d "/sys/class/net/${dev2}" ] || return
+
+	ip link set dev "$dev1" up
+	ip link set dev "$dev2" up
+	echo "${dev1}-${dev2},${dev1},${dev2}" > /sys/kernel/debug/trelay/add
+}
+
+start() {
+	config_load trelay
+	config_foreach check_relay trelay
+	touch /var/run/trelay.active
+}
+
+stop() {
+	rm -f /var/run/trelay.active
+	for relay in /sys/kernel/debug/trelay/*; do
+		[ -d "$relay" ] && echo > "$relay/remove"
+	done
+}
diff --git a/package/kernel/trelay/src/Makefile b/package/kernel/trelay/src/Makefile
new file mode 100644
index 0000000000..e6bde8969b
--- /dev/null
+++ b/package/kernel/trelay/src/Makefile
@@ -0,0 +1 @@
+obj-m   := trelay.o
diff --git a/package/kernel/trelay/src/trelay.c b/package/kernel/trelay/src/trelay.c
new file mode 100644
index 0000000000..581a5cfd2f
--- /dev/null
+++ b/package/kernel/trelay/src/trelay.c
@@ -0,0 +1,272 @@
+/*
+ * trelay.c: Trivial Ethernet Relay
+ *
+ * Copyright (C) 2012 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/debugfs.h>
+
+static LIST_HEAD(trelay_devs);
+static struct dentry *debugfs_dir;
+
+struct trelay {
+	struct list_head list;
+	struct net_device *dev1, *dev2;
+	struct dentry *debugfs;
+	char name[];
+};
+
+rx_handler_result_t trelay_handle_frame(struct sk_buff **pskb)
+{
+	struct net_device *dev;
+	struct sk_buff *skb = *pskb;
+
+	dev = rcu_dereference(skb->dev->rx_handler_data);
+	if (!dev)
+		return RX_HANDLER_PASS;
+
+	if (skb->protocol == htons(ETH_P_PAE))
+		return RX_HANDLER_PASS;
+
+	skb_push(skb, ETH_HLEN);
+	skb->dev = dev;
+	skb_forward_csum(skb);
+	dev_queue_xmit(skb);
+
+	return RX_HANDLER_CONSUMED;
+}
+
+static int trelay_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int trelay_do_remove(struct trelay *tr)
+{
+	list_del(&tr->list);
+
+	dev_put(tr->dev1);
+	dev_put(tr->dev2);
+
+	netdev_rx_handler_unregister(tr->dev1);
+	netdev_rx_handler_unregister(tr->dev2);
+
+	debugfs_remove_recursive(tr->debugfs);
+	kfree(tr);
+
+	return 0;
+}
+
+static struct trelay *trelay_find(struct net_device *dev)
+{
+	struct trelay *tr;
+
+	list_for_each_entry(tr, &trelay_devs, list) {
+		if (tr->dev1 == dev || tr->dev2 == dev)
+			return tr;
+	}
+	return NULL;
+}
+
+static int tr_device_event(struct notifier_block *unused, unsigned long event,
+			   void *ptr)
+{
+	struct net_device *dev = ptr;
+	struct trelay *tr;
+
+	if (event != NETDEV_UNREGISTER)
+		goto out;
+
+	tr = trelay_find(dev);
+	if (!tr)
+		goto out;
+
+	trelay_do_remove(tr);
+
+out:
+	return NOTIFY_DONE;
+}
+
+static ssize_t trelay_remove_write(struct file *file, const char __user *ubuf,
+				   size_t count, loff_t *ppos)
+{
+	struct trelay *tr = file->private_data;
+	int ret;
+
+	rtnl_lock();
+	ret = trelay_do_remove(tr);
+	rtnl_unlock();
+
+	if (ret < 0)
+		 return ret;
+
+	return count;
+}
+
+static const struct file_operations fops_remove = {
+	.owner = THIS_MODULE,
+	.open = trelay_open,
+	.write = trelay_remove_write,
+	.llseek = default_llseek,
+};
+
+
+static int trelay_do_add(char *name, char *devn1, char *devn2)
+{
+	struct net_device *dev1, *dev2;
+	struct trelay *tr, *tr1;
+	int ret;
+
+	tr = kzalloc(sizeof(*tr) + strlen(name) + 1, GFP_KERNEL);
+	if (!tr)
+		return -ENOMEM;
+
+	rtnl_lock();
+	rcu_read_lock();
+
+	ret = -EEXIST;
+	list_for_each_entry(tr1, &trelay_devs, list) {
+		if (!strcmp(tr1->name, name))
+			goto out;
+	}
+
+	ret = -ENOENT;
+	dev1 = dev_get_by_name_rcu(&init_net, devn1);
+	dev2 = dev_get_by_name_rcu(&init_net, devn2);
+	if (!dev1 || !dev2)
+		goto out;
+
+	ret = netdev_rx_handler_register(dev1, trelay_handle_frame, dev2);
+	if (ret < 0)
+		goto out;
+
+	ret = netdev_rx_handler_register(dev2, trelay_handle_frame, dev1);
+	if (ret < 0) {
+		netdev_rx_handler_unregister(dev1);
+		goto out;
+	}
+
+	dev_hold(dev1);
+	dev_hold(dev2);
+
+	strcpy(tr->name, name);
+	tr->dev1 = dev1;
+	tr->dev2 = dev2;
+	list_add_tail(&tr->list, &trelay_devs);
+
+	tr->debugfs = debugfs_create_dir(name, debugfs_dir);
+	debugfs_create_file("remove", S_IWUSR, tr->debugfs, tr, &fops_remove);
+	ret = 0;
+
+out:
+	rcu_read_unlock();
+	rtnl_unlock();
+	if (ret < 0)
+		kfree(tr);
+
+	return ret;
+}
+
+static ssize_t trelay_add_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char buf[256];
+	char *dev1, *dev2, *tmp;
+	ssize_t len, ret;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, ubuf, len))
+		return -EFAULT;
+
+	buf[len] = 0;
+
+	if ((tmp = strchr(buf, '\n')))
+		*tmp = 0;
+
+	dev1 = strchr(buf, ',');
+	if (!dev1)
+		return -EINVAL;
+
+	*(dev1++) = 0;
+
+	dev2 = strchr(dev1, ',');
+	if (!dev2)
+		return -EINVAL;
+
+	*(dev2++) = 0;
+	if (strchr(dev2, ','))
+		return -EINVAL;
+
+	if (!strlen(buf) || !strlen(dev1) || !strlen(dev2))
+		return -EINVAL;
+
+	ret = trelay_do_add(buf, dev1, dev2);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations fops_add = {
+	.owner = THIS_MODULE,
+	.write = trelay_add_write,
+	.llseek = default_llseek,
+};
+
+static struct notifier_block tr_dev_notifier = {
+	.notifier_call = tr_device_event
+};
+
+static int __init trelay_init(void)
+{
+	int ret;
+
+	debugfs_dir = debugfs_create_dir("trelay", NULL);
+	if (!debugfs_dir)
+		return -ENOMEM;
+
+	debugfs_create_file("add", S_IWUSR, debugfs_dir, NULL, &fops_add);
+
+	ret = register_netdevice_notifier(&tr_dev_notifier);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	debugfs_remove_recursive(debugfs_dir);
+	return ret;
+}
+
+static void __exit trelay_exit(void)
+{
+	struct trelay *tr, *tmp;
+
+	unregister_netdevice_notifier(&tr_dev_notifier);
+
+	rtnl_lock();
+	list_for_each_entry_safe(tr, tmp, &trelay_devs, list)
+		trelay_do_remove(tr);
+	rtnl_unlock();
+
+	debugfs_remove_recursive(debugfs_dir);
+}
+
+module_init(trelay_init);
+module_exit(trelay_exit);
+MODULE_LICENSE("GPL");
diff --git a/package/kernel/w1-gpio-custom/Makefile b/package/kernel/w1-gpio-custom/Makefile
new file mode 100644
index 0000000000..67fdc7d15e
--- /dev/null
+++ b/package/kernel/w1-gpio-custom/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2008-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=w1-gpio-custom
+PKG_RELEASE:=3
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/w1-gpio-custom
+  SUBMENU:=W1 support
+  TITLE:=Custom GPIO-based 1-wire device
+  DEPENDS:=kmod-w1 +kmod-w1-master-gpio
+  FILES:=$(PKG_BUILD_DIR)/w1-gpio-custom.ko
+  KCONFIG:=
+endef
+
+define KernelPackage/w1-gpio-custom/description
+ Kernel module to register a custom w1-gpio platform device.
+endef
+
+EXTRA_KCONFIG:= \
+	CONFIG_W1_MASTER_GPIO_CUSTOM=m
+
+EXTRA_CFLAGS:= \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
+	$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG))))
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)" \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
+	$(EXTRA_KCONFIG)
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,w1-gpio-custom))
+
diff --git a/package/kernel/w1-gpio-custom/src/Kconfig b/package/kernel/w1-gpio-custom/src/Kconfig
new file mode 100644
index 0000000000..74b9226c5c
--- /dev/null
+++ b/package/kernel/w1-gpio-custom/src/Kconfig
@@ -0,0 +1,4 @@
+config W1_MASTER_GPIO_CUSTOM
+	tristate "Custom GPIO-based W1 driver"
+	depends on GENERIC_GPIO
+	select W1_GPIO
\ No newline at end of file
diff --git a/package/kernel/w1-gpio-custom/src/Makefile b/package/kernel/w1-gpio-custom/src/Makefile
new file mode 100644
index 0000000000..6a527432c1
--- /dev/null
+++ b/package/kernel/w1-gpio-custom/src/Makefile
@@ -0,0 +1 @@
+obj-${CONFIG_W1_MASTER_GPIO_CUSTOM}	+= w1-gpio-custom.o
\ No newline at end of file
diff --git a/package/kernel/w1-gpio-custom/src/w1-gpio-custom.c b/package/kernel/w1-gpio-custom/src/w1-gpio-custom.c
new file mode 100644
index 0000000000..004c9240ba
--- /dev/null
+++ b/package/kernel/w1-gpio-custom/src/w1-gpio-custom.c
@@ -0,0 +1,190 @@
+/*
+ *  Custom GPIO-based W1 driver
+ *
+ *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *  Copyright (C) 2008 Bifferos <bifferos at yahoo.co.uk>
+ *
+ *  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.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ *  The behaviour of this driver can be altered by setting some parameters
+ *  from the insmod command line.
+ *
+ *  The following parameters are adjustable:
+ *
+ *	bus0	These four arguments must be arrays of
+ *	bus1	3 unsigned integers as follows:
+ *	bus2
+ *	bus3	<id>,<pin>,<od>
+ *
+ *  where:
+ *
+ *  <id>	ID to used as device_id for the corresponding bus (required)
+ *  <sda>	GPIO pin ID of data pin (required)
+ *  <od>	Pin is configured as open drain.
+ *
+ *  See include/w1-gpio.h for more information about the parameters.
+ *
+ *  If this driver is built into the kernel, you can use the following kernel
+ *  command line parameters, with the same values as the corresponding module
+ *  parameters listed above:
+ *
+ *	w1-gpio-custom.bus0
+ *	w1-gpio-custom.bus1
+ *	w1-gpio-custom.bus2
+ *	w1-gpio-custom.bus3
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/w1-gpio.h>
+
+#define DRV_NAME	"w1-gpio-custom"
+#define DRV_DESC	"Custom GPIO-based W1 driver"
+#define DRV_VERSION	"0.1.1"
+
+#define PFX		DRV_NAME ": "
+
+#define BUS_PARAM_ID		0
+#define BUS_PARAM_PIN		1
+#define BUS_PARAM_OD		2
+
+#define BUS_PARAM_REQUIRED	3
+#define BUS_PARAM_COUNT		3
+#define BUS_COUNT_MAX		4
+
+static unsigned int bus0[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus1[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus2[BUS_PARAM_COUNT] __initdata;
+static unsigned int bus3[BUS_PARAM_COUNT] __initdata;
+
+static unsigned int bus_nump[BUS_COUNT_MAX] __initdata;
+
+#define BUS_PARM_DESC " config -> id,pin,od"
+
+module_param_array(bus0, uint, &bus_nump[0], 0);
+MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC);
+module_param_array(bus1, uint, &bus_nump[1], 0);
+MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC);
+module_param_array(bus2, uint, &bus_nump[2], 0);
+MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC);
+module_param_array(bus3, uint, &bus_nump[3], 0);
+MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC);
+
+static struct platform_device *devices[BUS_COUNT_MAX];
+static unsigned int nr_devices;
+
+static void w1_gpio_custom_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < nr_devices; i++)
+		if (devices[i])
+			platform_device_put(devices[i]);
+}
+
+static int __init w1_gpio_custom_add_one(unsigned int id, unsigned int *params)
+{
+	struct platform_device *pdev;
+	struct w1_gpio_platform_data pdata;
+	int err;
+
+	if (!bus_nump[id])
+		return 0;
+
+	if (bus_nump[id] < BUS_PARAM_REQUIRED) {
+		printk(KERN_ERR PFX "not enough parameters for bus%d\n", id);
+		err = -EINVAL;
+		goto err;
+	}
+
+	pdev = platform_device_alloc("w1-gpio", params[BUS_PARAM_ID]);
+	if (!pdev) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	pdata.pin = params[BUS_PARAM_PIN];
+	pdata.is_open_drain = params[BUS_PARAM_OD] ? 1 : 0;
+	pdata.enable_external_pullup = NULL;
+	pdata.ext_pullup_enable_pin = -EINVAL;
+
+	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+	if (err)
+		goto err_put;
+
+	err = platform_device_add(pdev);
+	if (err)
+		goto err_put;
+
+	devices[nr_devices++] = pdev;
+	return 0;
+
+ err_put:
+	platform_device_put(pdev);
+ err:
+	return err;
+}
+
+static int __init w1_gpio_custom_probe(void)
+{
+	int err;
+
+	nr_devices = 0;
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+	err = w1_gpio_custom_add_one(0, bus0);
+	if (err)
+		goto err;
+
+	err = w1_gpio_custom_add_one(1, bus1);
+	if (err)
+		goto err;
+
+	err = w1_gpio_custom_add_one(2, bus2);
+	if (err)
+		goto err;
+
+	err = w1_gpio_custom_add_one(3, bus3);
+	if (err)
+		goto err;
+
+	if (!nr_devices) {
+		printk(KERN_ERR PFX "no bus parameter(s) specified\n");
+		err = -ENODEV;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	w1_gpio_custom_cleanup();
+	return err;
+}
+
+#ifdef MODULE
+static int __init w1_gpio_custom_init(void)
+{
+	return w1_gpio_custom_probe();
+}
+module_init(w1_gpio_custom_init);
+
+static void __exit w1_gpio_custom_exit(void)
+{
+	w1_gpio_custom_cleanup();
+}
+module_exit(w1_gpio_custom_exit);
+#else
+subsys_initcall(w1_gpio_custom_probe);
+#endif /* MODULE*/
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bifferos <bifferos at yahoo.co.uk >");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
diff --git a/package/kernel/wrt55agv2-spidevs/Makefile b/package/kernel/wrt55agv2-spidevs/Makefile
new file mode 100644
index 0000000000..169f6b4da1
--- /dev/null
+++ b/package/kernel/wrt55agv2-spidevs/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=wrt55agv2-spidevs
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/wrt55agv2-spidevs
+  SUBMENU:=Other modules
+  TITLE:=WRT55AG v2 SPI devices support
+  DEPENDS:=@TARGET_ath25 +kmod-spi-gpio-old +kmod-spi-ks8995
+  FILES:=$(PKG_BUILD_DIR)/wrt55agv2_spidevs.ko
+endef
+
+define KernelPackage/wrt55agv2-spidevs/description
+  Kernel module for the SPI devices on the WRT55AG v2 board.
+endef
+
+MAKE_OPTS:= \
+	ARCH="$(LINUX_KARCH)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	SUBDIRS="$(PKG_BUILD_DIR)"
+
+define Build/Compile
+	$(MAKE) -C "$(LINUX_DIR)" \
+		$(MAKE_OPTS) \
+		modules
+endef
+
+$(eval $(call KernelPackage,wrt55agv2-spidevs))
diff --git a/package/kernel/wrt55agv2-spidevs/src/Kconfig b/package/kernel/wrt55agv2-spidevs/src/Kconfig
new file mode 100644
index 0000000000..75e8242be7
--- /dev/null
+++ b/package/kernel/wrt55agv2-spidevs/src/Kconfig
@@ -0,0 +1,3 @@
+config WRT55AGV2_SPIDEVS
+	tristate "SPI device support for the WRT55AG v2 board"
+	depends on SPI && MIPS_ATHEROS
diff --git a/package/kernel/wrt55agv2-spidevs/src/Makefile b/package/kernel/wrt55agv2-spidevs/src/Makefile
new file mode 100644
index 0000000000..76b093930e
--- /dev/null
+++ b/package/kernel/wrt55agv2-spidevs/src/Makefile
@@ -0,0 +1 @@
+obj-m += wrt55agv2_spidevs.o
diff --git a/package/kernel/wrt55agv2-spidevs/src/wrt55agv2_spidevs.c b/package/kernel/wrt55agv2-spidevs/src/wrt55agv2_spidevs.c
new file mode 100644
index 0000000000..dfb7f6abe7
--- /dev/null
+++ b/package/kernel/wrt55agv2-spidevs/src/wrt55agv2_spidevs.c
@@ -0,0 +1,114 @@
+/*
+ * SPI driver for the Linksys WRT55AG v2 board.
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * This file was based on the mmc_over_gpio driver:
+ *	Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ *
+ * 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/platform_device.h>
+#include <linux/spi/spi_gpio_old.h>
+#include <linux/module.h>
+
+#define DRV_NAME	"wrt55agv2-spidevs"
+#define DRV_DESC	"SPI driver for the WRT55AG v2 board"
+#define DRV_VERSION	"0.1.0"
+#define PFX		DRV_NAME ": "
+
+#define GPIO_PIN_MISO	1
+#define GPIO_PIN_CS	2
+#define GPIO_PIN_CLK	3
+#define GPIO_PIN_MOSI	4
+
+static struct platform_device *spi_gpio_dev;
+
+static int __init boardinfo_setup(struct spi_board_info *bi,
+		struct spi_master *master, void *data)
+{
+
+	strlcpy(bi->modalias, "spi-ks8995", sizeof(bi->modalias));
+
+	bi->max_speed_hz = 5000000 /* Hz */;
+	bi->bus_num = master->bus_num;
+	bi->mode = SPI_MODE_0;
+
+	return 0;
+}
+
+static int __init wrt55agv2_spidevs_init(void)
+{
+	struct spi_gpio_platform_data pdata;
+	int err;
+
+	spi_gpio_dev = platform_device_alloc("spi-gpio", 0);
+	if (!spi_gpio_dev) {
+		printk(KERN_ERR PFX "no memory for spi-gpio device\n");
+		return -ENOMEM;
+	}
+
+	memset(&pdata, 0, sizeof(pdata));
+	pdata.pin_miso = GPIO_PIN_MISO;
+	pdata.pin_cs = GPIO_PIN_CS;
+	pdata.pin_clk = GPIO_PIN_CLK;
+	pdata.pin_mosi = GPIO_PIN_MOSI;
+	pdata.cs_activelow = 1;
+	pdata.no_spi_delay = 1;
+	pdata.boardinfo_setup = boardinfo_setup;
+	pdata.boardinfo_setup_data = NULL;
+
+	err = platform_device_add_data(spi_gpio_dev, &pdata, sizeof(pdata));
+	if (err)
+		goto err_free_dev;
+
+	err = platform_device_register(spi_gpio_dev);
+	if (err) {
+		printk(KERN_ERR PFX "unable to register device\n");
+		goto err_free_pdata;
+	}
+
+	return 0;
+
+err_free_pdata:
+	kfree(spi_gpio_dev->dev.platform_data);
+	spi_gpio_dev->dev.platform_data = NULL;
+
+err_free_dev:
+	platform_device_put(spi_gpio_dev);
+	return err;
+}
+
+static void __exit wrt55agv2_spidevs_cleanup(void)
+{
+	if (!spi_gpio_dev)
+		return;
+
+	platform_device_unregister(spi_gpio_dev);
+
+	kfree(spi_gpio_dev->dev.platform_data);
+	spi_gpio_dev->dev.platform_data = NULL;
+	platform_device_put(spi_gpio_dev);
+}
+
+static int __init wrt55agv2_spidevs_modinit(void)
+{
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+	return wrt55agv2_spidevs_init();
+}
+module_init(wrt55agv2_spidevs_modinit);
+
+static void __exit wrt55agv2_spidevs_modexit(void)
+{
+	wrt55agv2_spidevs_cleanup();
+}
+module_exit(wrt55agv2_spidevs_modexit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/package/libs/argp-standalone/Makefile b/package/libs/argp-standalone/Makefile
new file mode 100644
index 0000000000..8cf23fec5e
--- /dev/null
+++ b/package/libs/argp-standalone/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2007-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=argp-standalone
+PKG_VERSION:=1.3
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.lysator.liu.se/~nisse/misc/
+PKG_MD5SUM:=720704bac078d067111b32444e24ba69
+PKG_MAINTAINER:=Ted Hess <thess@kitschensync.net>
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE:=Makefile.am
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/argp-standalone
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Hierarchial argument parsing broken out from glibc
+  URL:=http://www.lysator.liu.se/~nisse/misc/
+endef
+
+define Package/argp-standalone/description
+  GNU libc hierarchial argument parsing library broken out from glibc.
+endef
+
+MAKE_FLAGS += \
+	CFLAGS="$(TARGET_CFLAGS) $(FPIC)"
+
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP)   $(PKG_BUILD_DIR)/argp.h \
+		$(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP)   $(PKG_BUILD_DIR)/libargp.a \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,argp-standalone))
diff --git a/package/libs/argp-standalone/patches/001-throw-in-funcdef.patch b/package/libs/argp-standalone/patches/001-throw-in-funcdef.patch
new file mode 100644
index 0000000000..4a90751e1e
--- /dev/null
+++ b/package/libs/argp-standalone/patches/001-throw-in-funcdef.patch
@@ -0,0 +1,79 @@
+# --- T2-COPYRIGHT-NOTE-BEGIN ---
+# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
+# 
+# T2 SDE: package/.../rng-tools/throw-in-funcdef.patch.argp-standalone
+# Copyright (C) 2006 The T2 SDE Project
+# 
+# More information can be found in the files COPYING and README.
+# 
+# This patch file is dual-licensed. It is available under the license the
+# patched project is licensed under, as long as it is an OpenSource license
+# as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
+# of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+# --- T2-COPYRIGHT-NOTE-END ---
+
+
+No __THROW in function implementation.
+	--jsaw
+
+--- argp-standalone-1.4-test2/argp.h.orig	2006-01-06 02:29:59.000000000 +0100
++++ argp-standalone-1.4-test2/argp.h	2006-01-06 02:41:10.000000000 +0100
+@@ -560,17 +560,17 @@
+ # endif
+ 
+ # ifndef ARGP_EI
+-#  define ARGP_EI extern __inline__
++#  define ARGP_EI extern inline
+ # endif
+ 
+ ARGP_EI void
+-__argp_usage (__const struct argp_state *__state) __THROW
++__argp_usage (__const struct argp_state *__state)
+ {
+   __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE);
+ }
+ 
+ ARGP_EI int
+-__option_is_short (__const struct argp_option *__opt) __THROW
++__option_is_short (__const struct argp_option *__opt)
+ {
+   if (__opt->flags & OPTION_DOC)
+     return 0;
+@@ -582,7 +582,7 @@
+ }
+ 
+ ARGP_EI int
+-__option_is_end (__const struct argp_option *__opt) __THROW
++__option_is_end (__const struct argp_option *__opt)
+ {
+   return !__opt->key && !__opt->name && !__opt->doc && !__opt->group;
+ }
+--- argp-standalone-1.4-test2/argp-parse.c.orig	2006-01-06 02:47:48.000000000 +0100
++++ argp-standalone-1.4-test2/argp-parse.c	2006-01-06 02:48:16.000000000 +0100
+@@ -1290,13 +1290,13 @@
+ /* Defined here, in case a user is not inlining the definitions in
+  * argp.h */
+ void
+-__argp_usage (__const struct argp_state *__state) __THROW
++__argp_usage (__const struct argp_state *__state)
+ {
+   __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE);
+ }
+ 
+ int
+-__option_is_short (__const struct argp_option *__opt) __THROW
++__option_is_short (__const struct argp_option *__opt) 
+ {
+   if (__opt->flags & OPTION_DOC)
+     return 0;
+@@ -1310,7 +1310,7 @@
+ }
+ 
+ int
+-__option_is_end (__const struct argp_option *__opt) __THROW
++__option_is_end (__const struct argp_option *__opt) 
+ {
+   return !__opt->key && !__opt->name && !__opt->doc && !__opt->group;
+ }
diff --git a/package/libs/argp-standalone/patches/002-no_optimize.patch b/package/libs/argp-standalone/patches/002-no_optimize.patch
new file mode 100644
index 0000000000..1da330af70
--- /dev/null
+++ b/package/libs/argp-standalone/patches/002-no_optimize.patch
@@ -0,0 +1,11 @@
+--- a/argp-fmtstream.h
++++ b/argp-fmtstream.h
+@@ -192,7 +192,7 @@ extern void __argp_fmtstream_update (arg
+ extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
+ extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
+ 
+-#ifdef __OPTIMIZE__
++#if 0
+ /* Inline versions of above routines.  */
+ 
+ #if !_LIBC
diff --git a/package/libs/cyassl/Config.in b/package/libs/cyassl/Config.in
new file mode 100644
index 0000000000..371bb564f8
--- /dev/null
+++ b/package/libs/cyassl/Config.in
@@ -0,0 +1,48 @@
+if PACKAGE_libcyassl
+
+config CYASSL_HAS_AES_CCM
+	bool "Include AES-CCM support"
+	default n
+
+config CYASSL_HAS_AES_GCM
+	bool "Include AES-GCM support"
+	default n
+
+config CYASSL_HAS_CHACHA
+	bool "Include ChaCha cipher suite support"
+	default n
+
+config CYASSL_HAS_ECC
+	bool "Include ECC (Elliptic Curve Cryptography) support"
+	default y
+
+config CYASSL_HAS_DH
+	bool "Include DH (Diffie-Hellman) support"
+	default n
+
+config CYASSL_HAS_ARC4
+	bool "Include ARC4 support"
+	default n
+
+config CYASSL_HAS_DES3
+	bool "Include DES3 (Tripple-DES) support"
+	default n
+
+config CYASSL_HAS_PSK
+	bool "Include PKS (Pre Share Key) support"
+	default n
+
+config CYASSL_HAS_DTLS
+	bool "Include DTLS support"
+	default n
+
+config CYASSL_HAS_ECC25519
+	bool "Include ECC Curve 22519 support"
+	depends on CYASSL_HAS_ECC
+	default n
+
+config CYASSL_HAS_POLY_1305
+	bool "Include Poly-1305 support"
+	default n
+
+endif
diff --git a/package/libs/cyassl/Makefile b/package/libs/cyassl/Makefile
new file mode 100644
index 0000000000..3cd8e4cfdf
--- /dev/null
+++ b/package/libs/cyassl/Makefile
@@ -0,0 +1,138 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wolfssl
+PKG_VERSION:=3.9.10
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).zip
+PKG_SOURCE_URL:=https://www.wolfssl.com/
+PKG_MD5SUM:=793921c0db96248be4a369cbfdf0cb7b37ee2be715b8b775b6cd32efe66f494e
+
+PKG_FIXUP:=libtool
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libcyassl
+  SECTION:=libs
+  SUBMENU:=SSL
+  CATEGORY:=Libraries
+  TITLE:=CyaSSL library
+  URL:=http://www.wolfssl.com/
+  MENU:=1
+endef
+
+define Package/libcyassl/description
+CyaSSL is an SSL library optimized for small footprint, both on disk and for
+memory use.
+endef
+
+define Package/libcyassl/config
+	source "$(SOURCE)/Config.in"
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-singlethreaded \
+	--enable-opensslextra \
+	--enable-sni \
+	--enable-stunnel \
+	--disable-examples
+
+ifeq ($(CONFIG_IPV6),y)
+CONFIGURE_ARGS += \
+        --enable-ipv6
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_AES_CCM),y)
+CONFIGURE_ARGS += \
+	--enable-aesccm
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_AES_GCM),y)
+CONFIGURE_ARGS += \
+	--enable-aesgcm
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_CHACHA),y)
+CONFIGURE_ARGS += \
+	--enable-chacha
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_ECC),y)
+CONFIGURE_ARGS += \
+	--enable-ecc \
+	--enable-supportedcurves
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_DH),y)
+CONFIGURE_ARGS += \
+	--enable-dh
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_ARC4),n)
+CONFIGURE_ARGS += \
+	--disable-arc4
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_DES3),y)
+CONFIGURE_ARGS += \
+	--disable-des3
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_PSK),y)
+CONFIGURE_ARGS += \
+	--enable-psk
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_DTLS),y)
+CONFIGURE_ARGS += \
+	--enable-dtls
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_ECC25519),y)
+CONFIGURE_ARGS += \
+	--enable-ecc25519
+endif
+
+ifeq ($(CONFIG_CYASSL_HAS_POLY1305),y)
+CONFIGURE_ARGS += \
+	--enable-poly1305
+endif
+
+#ifneq ($(CONFIG_TARGET_x86),)
+#	CONFIGURE_ARGS += --enable-intelasm
+#endif
+#ifneq ($(CONFIG_TARGET_x86_64),)
+#	CONFIGURE_ARGS += --enable-intelasm
+#endif
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libwolfssl.{so*,la} $(1)/usr/lib/
+	ln -s libwolfssl.so $(1)/usr/lib/libcyassl.so
+	ln -s libwolfssl.la $(1)/usr/lib/libcyassl.la
+
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/*.pc $(1)/usr/lib/pkgconfig
+endef
+
+define Package/libcyassl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libwolfssl.so* $(1)/usr/lib/
+	ln -s libwolfssl.so $(1)/usr/lib/libcyassl.so
+endef
+
+$(eval $(call BuildPackage,libcyassl))
diff --git a/package/libs/cyassl/patches/400-additional_compatibility.patch b/package/libs/cyassl/patches/400-additional_compatibility.patch
new file mode 100644
index 0000000000..1464e9d2a8
--- /dev/null
+++ b/package/libs/cyassl/patches/400-additional_compatibility.patch
@@ -0,0 +1,12 @@
+--- a/cyassl/openssl/ssl.h
++++ b/cyassl/openssl/ssl.h
+@@ -28,6 +28,9 @@
+ #define CYASSL_OPENSSL_H_
+ 
+ #include <cyassl/ssl.h>
++#ifndef HAVE_SNI
++#undef CYASSL_SNI_HOST_NAME
++#endif
+ #include <wolfssl/openssl/ssl.h>
+ 
+ #endif
diff --git a/package/libs/elfutils/Makefile b/package/libs/elfutils/Makefile
new file mode 100644
index 0000000000..46ad1b3d91
--- /dev/null
+++ b/package/libs/elfutils/Makefile
@@ -0,0 +1,97 @@
+#
+# Copyright (C) 2010-2014 OpenWrt.org
+# Copyright (C) 2016 Luiz Angelo Daros de Luca <luizluca@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=elfutils
+PKG_VERSION:=0.167
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://fedorahosted.org/releases/e/l/$(PKG_NAME)/$(PKG_VERSION)
+PKG_MD5SUM:=efc6c2067dfad5646777e93e85222e8f
+PKG_MAINTAINER:=Luiz Angelo Daros de Luca <luizluca@gmail.com>
+PKG_LICENSE:=GPL-3.0+
+PKG_LICENSE_FILES:=COPYING COPYING-GPLV2 COPYING-LGPLV3
+
+PKG_INSTALL:=1
+PKG_USE_MIPS16:=0
+
+PKG_BUILD_DEPENDS:=USE_UCLIBC:argp-standalone USE_MUSL:argp-standalone
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/elfutils/Default
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=ELF manipulation libraries
+  URL:=https://fedorahosted.org/elfutils/
+endef
+
+define Package/libasm
+  $(call Package/elfutils/Default)
+  TITLE+= (libasm)
+  DEPENDS:=libelf1 +libdw
+endef
+
+define Package/libdw
+  $(call Package/elfutils/Default)
+  DEPENDS:=libelf1 +libbz2
+  TITLE+= (libdw)
+endef
+
+define Package/libelf1
+  $(call Package/elfutils/Default)
+  DEPENDS:=$(INTL_DEPENDS) +zlib
+  TITLE+= (libelf)
+endef
+
+ifeq ($(CONFIG_BUILD_NLS),y)
+TARGET_LDFLAGS += "-lintl"
+endif
+
+ifdef CONFIG_USE_UCLIBC
+CONFIGURE_VARS += \
+	LIBS="-largp"
+endif
+
+ifdef CONFIG_USE_MUSL
+CONFIGURE_VARS += \
+	LIBS="-largp"
+endif
+
+CONFIGURE_ARGS += \
+	--without-lzma
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libasm/libasm.{a,so*} $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/libdw/libdw.{a,so*} $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/libelf/libelf.{a,so*} $(1)/usr/lib/
+endef
+
+define Package/libasm/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libasm/libasm.so* $(1)/usr/lib/
+endef
+
+define Package/libdw/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libdw/libdw.so* $(1)/usr/lib/
+endef
+
+define Package/libelf1/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libelf/libelf.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libasm))
+$(eval $(call BuildPackage,libdw))
+$(eval $(call BuildPackage,libelf1))
diff --git a/package/libs/elfutils/patches/002-argp_standalone.patch b/package/libs/elfutils/patches/002-argp_standalone.patch
new file mode 100644
index 0000000000..8e2ca1bc0d
--- /dev/null
+++ b/package/libs/elfutils/patches/002-argp_standalone.patch
@@ -0,0 +1,14 @@
+--- a/lib/color.c
++++ b/lib/color.c
+@@ -131,8 +131,10 @@ valid arguments are:\n\
+   - 'never', 'no', 'none'\n\
+   - 'auto', 'tty', 'if-tty'\n"),
+ 		     program_invocation_short_name, arg);
++          char program_invocation_short_name_nonconst[sizeof(program_invocation_short_name)];
++          strcpy(program_invocation_short_name_nonconst, program_invocation_short_name);
+ 	      argp_help (&color_argp, stderr, ARGP_HELP_SEE,
+-			 program_invocation_short_name);
++			 program_invocation_short_name_nonconst);
+ 	      exit (EXIT_FAILURE);
+ 	    }
+ 	}
diff --git a/package/libs/elfutils/patches/003-libint-stub.patch b/package/libs/elfutils/patches/003-libint-stub.patch
new file mode 100644
index 0000000000..0aa31a86cb
--- /dev/null
+++ b/package/libs/elfutils/patches/003-libint-stub.patch
@@ -0,0 +1,49 @@
+--- a/libelf/libelfP.h
++++ b/libelf/libelfP.h
+@@ -43,6 +43,9 @@
+ #include <stdio.h>
+ #include <string.h>
+ 
++#ifdef _ /* fix libintl-stub */
++#undef _
++#endif
+ /* gettext helper macros.  */
+ #define _(Str) dgettext ("elfutils", Str)
+ 
+--- a/libdw/libdwP.h
++++ b/libdw/libdwP.h
+@@ -36,7 +36,9 @@
+ #include <libdw.h>
+ #include <dwarf.h>
+ 
+-
++#ifdef _ /* fix libintl-stub */
++#undef _
++#endif
+ /* gettext helper macros.  */
+ #define _(Str) dgettext ("elfutils", Str)
+ 
+--- a/libdwfl/libdwflP.h
++++ b/libdwfl/libdwflP.h
+@@ -46,6 +46,9 @@
+ 
+ typedef struct Dwfl_Process Dwfl_Process;
+ 
++#ifdef _ /* fix libintl-stub */
++#undef _
++#endif
+ /* gettext helper macros.  */
+ #define _(Str) dgettext ("elfutils", Str)
+ 
+--- a/libasm/libasmP.h
++++ b/libasm/libasmP.h
+@@ -35,6 +35,9 @@
+ 
+ #include "libdwelf.h"
+ 
++#ifdef _ /* fix libintl-stub */
++#undef _
++#endif
+ /* gettext helper macros.  */
+ #define _(Str) dgettext ("elfutils", Str)
+ 
diff --git a/package/libs/elfutils/patches/004-maybe-uninitialized.patch b/package/libs/elfutils/patches/004-maybe-uninitialized.patch
new file mode 100644
index 0000000000..d0ce85cc86
--- /dev/null
+++ b/package/libs/elfutils/patches/004-maybe-uninitialized.patch
@@ -0,0 +1,11 @@
+--- a/libelf/elf_getarsym.c
++++ b/libelf/elf_getarsym.c
+@@ -167,7 +167,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
+ 
+       /* We have an archive.  The first word in there is the number of
+ 	 entries in the table.  */
+-      uint64_t n;
++      uint64_t n = 0;
+       size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr);
+       if (read_number_entries (&n, elf, &off, index64_p) < 0)
+ 	{
diff --git a/package/libs/elfutils/patches/004-memcpy_def.patch b/package/libs/elfutils/patches/004-memcpy_def.patch
new file mode 100644
index 0000000000..3731592b14
--- /dev/null
+++ b/package/libs/elfutils/patches/004-memcpy_def.patch
@@ -0,0 +1,14 @@
+--- a/libelf/libelf.h
++++ b/libelf/libelf.h
+@@ -108,6 +108,11 @@ typedef struct
+   size_t d_align;		/* Alignment in section.  */
+ } Elf_Data;
+ 
++#ifndef _LIBC
++#ifndef __mempcpy
++#define __mempcpy mempcpy
++#endif
++#endif
+ 
+ /* Commands for `...'.  */
+ typedef enum
diff --git a/package/libs/elfutils/patches/005-build_only_libs.patch b/package/libs/elfutils/patches/005-build_only_libs.patch
new file mode 100644
index 0000000000..7c30efc9fd
--- /dev/null
+++ b/package/libs/elfutils/patches/005-build_only_libs.patch
@@ -0,0 +1,24 @@
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -377,8 +377,7 @@ AM_MAKEFLAGS = --no-print-directory
+ pkginclude_HEADERS = version.h
+ 
+ # Add doc back when we have some real content.
+-SUBDIRS = config m4 lib libelf libebl libdwelf libdwfl libdw libcpu libasm \
+-	  backends src po tests
++SUBDIRS = config m4 lib libelf libebl libdwelf libdwfl libdw libasm
+ 
+ EXTRA_DIST = elfutils.spec GPG-KEY NOTES CONTRIBUTING \
+ 	     COPYING COPYING-GPLV2 COPYING-LGPLV3
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -27,8 +27,7 @@ AM_MAKEFLAGS = --no-print-directory
+ pkginclude_HEADERS = version.h
+ 
+ # Add doc back when we have some real content.
+-SUBDIRS = config m4 lib libelf libebl libdwelf libdwfl libdw libcpu libasm \
+-	  backends src po tests
++SUBDIRS = config m4 lib libelf libebl libdwelf libdwfl libdw libasm
+ 
+ EXTRA_DIST = elfutils.spec GPG-KEY NOTES CONTRIBUTING \
+ 	     COPYING COPYING-GPLV2 COPYING-LGPLV3
diff --git a/package/libs/elfutils/patches/006-libdw_LIBS.patch b/package/libs/elfutils/patches/006-libdw_LIBS.patch
new file mode 100644
index 0000000000..80c20ad5f0
--- /dev/null
+++ b/package/libs/elfutils/patches/006-libdw_LIBS.patch
@@ -0,0 +1,11 @@
+--- a/libdw/Makefile.in
++++ b/libdw/Makefile.in
+@@ -1002,7 +1002,7 @@ libdw.so$(EXEEXT): $(srcdir)/libdw.map l
+ 		-Wl,--enable-new-dtags,-rpath,$(pkglibdir) \
+ 		-Wl,--version-script,$<,--no-undefined \
+ 		-Wl,--whole-archive $(filter-out $<,$^) -Wl,--no-whole-archive\
+-		-ldl -lz $(argp_LDADD) $(zip_LIBS)
++		-ldl -lz $(argp_LDADD) $(zip_LIBS) $(LIBS)
+ 	@$(textrel_check)
+ 	$(AM_V_at)ln -fs $@ $@.$(VERSION)
+ 
diff --git a/package/libs/elfutils/patches/100-musl-compat.patch b/package/libs/elfutils/patches/100-musl-compat.patch
new file mode 100644
index 0000000000..f345c3a9a6
--- /dev/null
+++ b/package/libs/elfutils/patches/100-musl-compat.patch
@@ -0,0 +1,702 @@
+--- a/lib/system.h
++++ b/lib/system.h
+@@ -68,6 +68,16 @@ extern int crc32_file (int fd, uint32_t
+ 
+ #define gettext_noop(Str) Str
+ 
++#ifndef TEMP_FAILURE_RETRY
++#define TEMP_FAILURE_RETRY(expression) \
++  (__extension__							      \
++    ({ long int __result;						      \
++       do __result = (long int) (expression);				      \
++       while (__result == -1L && errno == EINTR);			      \
++       __result; }))
++#endif
++
++#define error(status, errno, ...) err(status, __VA_ARGS__)
+ 
+ static inline ssize_t __attribute__ ((unused))
+ pwrite_retry (int fd, const void *buf, size_t len, off_t off)
+--- a/lib/color.c
++++ b/lib/color.c
+@@ -32,7 +32,7 @@
+ #endif
+ 
+ #include <argp.h>
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ #include <stdlib.h>
+ #include <string.h>
+--- a/lib/xmalloc.c
++++ b/lib/xmalloc.c
+@@ -30,7 +30,7 @@
+ # include <config.h>
+ #endif
+ 
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ #include <stddef.h>
+ #include <stdlib.h>
+--- a/src/addr2line.c
++++ b/src/addr2line.c
+@@ -23,7 +23,7 @@
+ #include <argp.h>
+ #include <assert.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <inttypes.h>
+ #include <libdwfl.h>
+--- a/src/ar.c
++++ b/src/ar.c
+@@ -22,7 +22,7 @@
+ 
+ #include <argp.h>
+ #include <assert.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <libintl.h>
+--- a/src/arlib2.c
++++ b/src/arlib2.c
+@@ -20,7 +20,7 @@
+ # include <config.h>
+ #endif
+ 
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ #include <limits.h>
+ #include <string.h>
+--- a/src/arlib.c
++++ b/src/arlib.c
+@@ -21,7 +21,7 @@
+ #endif
+ 
+ #include <assert.h>
+-#include <error.h>
++#include <err.h>
+ #include <gelf.h>
+ #include <libintl.h>
+ #include <stdio.h>
+--- a/src/elfcmp.c
++++ b/src/elfcmp.c
+@@ -23,7 +23,7 @@
+ #include <argp.h>
+ #include <assert.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <locale.h>
+ #include <libintl.h>
+--- a/src/elflint.c
++++ b/src/elflint.c
+@@ -24,7 +24,7 @@
+ #include <assert.h>
+ #include <byteswap.h>
+ #include <endian.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <inttypes.h>
+--- a/src/findtextrel.c
++++ b/src/findtextrel.c
+@@ -23,7 +23,7 @@
+ #include <argp.h>
+ #include <assert.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <libdw.h>
+--- a/src/nm.c
++++ b/src/nm.c
+@@ -26,7 +26,7 @@
+ #include <ctype.h>
+ #include <dwarf.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <inttypes.h>
+--- a/src/objdump.c
++++ b/src/objdump.c
+@@ -21,7 +21,7 @@
+ #endif
+ 
+ #include <argp.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <inttypes.h>
+ #include <libintl.h>
+--- a/src/ranlib.c
++++ b/src/ranlib.c
+@@ -24,7 +24,7 @@
+ #include <argp.h>
+ #include <assert.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <libintl.h>
+--- a/src/readelf.c
++++ b/src/readelf.c
+@@ -25,7 +25,7 @@
+ #include <ctype.h>
+ #include <dwarf.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <inttypes.h>
+--- a/src/size.c
++++ b/src/size.c
+@@ -21,7 +21,7 @@
+ #endif
+ 
+ #include <argp.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <inttypes.h>
+--- a/src/stack.c
++++ b/src/stack.c
+@@ -18,7 +18,7 @@
+ #include <config.h>
+ #include <assert.h>
+ #include <argp.h>
+-#include <error.h>
++#include <err.h>
+ #include <stdlib.h>
+ #include <inttypes.h>
+ #include <stdio.h>
+--- a/src/strings.c
++++ b/src/strings.c
+@@ -25,7 +25,7 @@
+ #include <ctype.h>
+ #include <endian.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <inttypes.h>
+--- a/src/strip.c
++++ b/src/strip.c
+@@ -24,7 +24,7 @@
+ #include <assert.h>
+ #include <byteswap.h>
+ #include <endian.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <libelf.h>
+--- a/src/unstrip.c
++++ b/src/unstrip.c
+@@ -31,7 +31,7 @@
+ #include <argp.h>
+ #include <assert.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <fnmatch.h>
+ #include <libintl.h>
+--- a/tests/addrscopes.c
++++ b/tests/addrscopes.c
+@@ -25,7 +25,7 @@
+ #include <stdio_ext.h>
+ #include <locale.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ 
+ 
+--- a/tests/allregs.c
++++ b/tests/allregs.c
+@@ -21,7 +21,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <error.h>
++#include <err.h>
+ #include <locale.h>
+ #include <argp.h>
+ #include <assert.h>
+--- a/tests/backtrace.c
++++ b/tests/backtrace.c
+@@ -24,7 +24,7 @@
+ #include <dirent.h>
+ #include <stdlib.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <unistd.h>
+ #include <dwarf.h>
+ #ifdef __linux__
+--- a/tests/backtrace-data.c
++++ b/tests/backtrace-data.c
+@@ -27,7 +27,7 @@
+ #include <dirent.h>
+ #include <stdlib.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <unistd.h>
+ #include <dwarf.h>
+ #if defined(__x86_64__) && defined(__linux__)
+--- a/tests/buildid.c
++++ b/tests/buildid.c
+@@ -23,7 +23,7 @@
+ #include ELFUTILS_HEADER(elf)
+ #include ELFUTILS_HEADER(dwelf)
+ #include <stdio.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <sys/types.h>
+--- a/tests/debugaltlink.c
++++ b/tests/debugaltlink.c
+@@ -23,7 +23,7 @@
+ #include ELFUTILS_HEADER(dw)
+ #include ELFUTILS_HEADER(dwelf)
+ #include <stdio.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <sys/types.h>
+--- a/tests/debuglink.c
++++ b/tests/debuglink.c
+@@ -21,7 +21,7 @@
+ #include <errno.h>
+ #include ELFUTILS_HEADER(dwelf)
+ #include <stdio.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <sys/types.h>
+--- a/tests/dwfl-addr-sect.c
++++ b/tests/dwfl-addr-sect.c
+@@ -23,7 +23,7 @@
+ #include <stdio_ext.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <error.h>
++#include <err.h>
+ #include <locale.h>
+ #include <argp.h>
+ #include ELFUTILS_HEADER(dwfl)
+--- a/tests/dwfl-bug-addr-overflow.c
++++ b/tests/dwfl-bug-addr-overflow.c
+@@ -20,7 +20,7 @@
+ #include <inttypes.h>
+ #include <stdio.h>
+ #include <stdio_ext.h>
+-#include <error.h>
++#include <err.h>
+ #include <locale.h>
+ #include ELFUTILS_HEADER(dwfl)
+ 
+--- a/tests/dwfl-bug-fd-leak.c
++++ b/tests/dwfl-bug-fd-leak.c
+@@ -24,7 +24,7 @@
+ #include <dirent.h>
+ #include <stdlib.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <unistd.h>
+ #include <dwarf.h>
+ 
+--- a/tests/dwfl-bug-getmodules.c
++++ b/tests/dwfl-bug-getmodules.c
+@@ -18,7 +18,7 @@
+ #include <config.h>
+ #include ELFUTILS_HEADER(dwfl)
+ 
+-#include <error.h>
++#include <err.h>
+ 
+ static const Dwfl_Callbacks callbacks =
+   {
+--- a/tests/dwfllines.c
++++ b/tests/dwfllines.c
+@@ -27,7 +27,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <error.h>
++#include <err.h>
+ 
+ int
+ main (int argc, char *argv[])
+--- a/tests/dwflmodtest.c
++++ b/tests/dwflmodtest.c
+@@ -23,7 +23,7 @@
+ #include <stdio_ext.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <error.h>
++#include <err.h>
+ #include <locale.h>
+ #include <argp.h>
+ #include ELFUTILS_HEADER(dwfl)
+--- a/tests/dwfl-report-elf-align.c
++++ b/tests/dwfl-report-elf-align.c
+@@ -20,7 +20,7 @@
+ #include <inttypes.h>
+ #include <stdio.h>
+ #include <stdio_ext.h>
+-#include <error.h>
++#include <err.h>
+ #include <locale.h>
+ #include <string.h>
+ #include <stdlib.h>
+--- a/tests/dwflsyms.c
++++ b/tests/dwflsyms.c
+@@ -25,7 +25,7 @@
+ #include <stdio.h>
+ #include <stdio_ext.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ 
+ static const char *
+--- a/tests/early-offscn.c
++++ b/tests/early-offscn.c
+@@ -19,7 +19,7 @@
+ #endif
+ 
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <stdio.h>
+--- a/tests/ecp.c
++++ b/tests/ecp.c
+@@ -20,7 +20,7 @@
+ #endif
+ 
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <stdlib.h>
+--- a/tests/find-prologues.c
++++ b/tests/find-prologues.c
+@@ -25,7 +25,7 @@
+ #include <stdio_ext.h>
+ #include <locale.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <fnmatch.h>
+ 
+--- a/tests/funcretval.c
++++ b/tests/funcretval.c
+@@ -25,7 +25,7 @@
+ #include <stdio_ext.h>
+ #include <locale.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <fnmatch.h>
+ 
+--- a/tests/funcscopes.c
++++ b/tests/funcscopes.c
+@@ -25,7 +25,7 @@
+ #include <stdio_ext.h>
+ #include <locale.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <fnmatch.h>
+ 
+--- a/tests/line2addr.c
++++ b/tests/line2addr.c
+@@ -26,7 +26,7 @@
+ #include <locale.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <error.h>
++#include <err.h>
+ 
+ 
+ static void
+--- a/tests/low_high_pc.c
++++ b/tests/low_high_pc.c
+@@ -25,7 +25,7 @@
+ #include <stdio_ext.h>
+ #include <locale.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <fnmatch.h>
+ 
+--- a/tests/md5-sha1-test.c
++++ b/tests/md5-sha1-test.c
+@@ -19,7 +19,7 @@
+ #endif
+ 
+ #include <string.h>
+-#include <error.h>
++#include <err.h>
+ 
+ #include "md5.h"
+ #include "sha1.h"
+--- a/tests/rdwrmmap.c
++++ b/tests/rdwrmmap.c
+@@ -19,7 +19,7 @@
+ #endif
+ 
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <stdio.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+--- a/tests/saridx.c
++++ b/tests/saridx.c
+@@ -17,7 +17,7 @@
+ 
+ #include <config.h>
+ 
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <stdio.h>
+--- a/tests/sectiondump.c
++++ b/tests/sectiondump.c
+@@ -18,7 +18,7 @@
+ #include <config.h>
+ 
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <fcntl.h>
+ #include <gelf.h>
+ #include <inttypes.h>
+--- a/tests/varlocs.c
++++ b/tests/varlocs.c
+@@ -25,7 +25,7 @@
+ #include <dwarf.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <error.h>
++#include <err.h>
+ #include <string.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+--- a/libelf/libelf.h
++++ b/libelf/libelf.h
+@@ -29,6 +29,7 @@
+ #ifndef _LIBELF_H
+ #define _LIBELF_H 1
+ 
++#include <fcntl.h>
+ #include <stdint.h>
+ #include <sys/types.h>
+ 
+--- a/libasm/asm_end.c
++++ b/libasm/asm_end.c
+@@ -32,7 +32,7 @@
+ #endif
+ 
+ #include <assert.h>
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+--- a/libasm/asm_newscn.c
++++ b/libasm/asm_newscn.c
+@@ -32,7 +32,7 @@
+ #endif
+ 
+ #include <assert.h>
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ #include <stdlib.h>
+ #include <string.h>
+--- a/libcpu/i386_gendis.c
++++ b/libcpu/i386_gendis.c
+@@ -31,7 +31,7 @@
+ # include <config.h>
+ #endif
+ 
+-#include <error.h>
++#include <err.h>
+ #include <errno.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+--- a/libcpu/i386_lex.c
++++ b/libcpu/i386_lex.c
+@@ -578,7 +578,7 @@ char *i386_text;
+ #endif
+ 
+ #include <ctype.h>
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ 
+ #include <system.h>
+--- a/libcpu/i386_lex.l
++++ b/libcpu/i386_lex.l
+@@ -31,7 +31,7 @@
+ #endif
+ 
+ #include <ctype.h>
+-#include <error.h>
++#include <err.h>
+ #include <libintl.h>
+ 
+ #include <system.h>
+--- a/libcpu/i386_parse.c
++++ b/libcpu/i386_parse.c
+@@ -107,7 +107,7 @@
+ #include <assert.h>
+ #include <ctype.h>
+ #include <errno.h>
+-#include <error.h>
++#include <err.h>
+ #include <inttypes.h>
+ #include <libintl.h>
+ #include <math.h>
+--- a/libdw/libdw_alloc.c
++++ b/libdw/libdw_alloc.c
+@@ -31,7 +31,7 @@
+ # include <config.h>
+ #endif
+ 
+-#include <error.h>
++#include <err.h>
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <sys/param.h>
+@@ -74,5 +74,5 @@ __attribute ((noreturn, visibility ("hid
+ __libdw_oom (void)
+ {
+   while (1)
+-    error (EXIT_FAILURE, ENOMEM, "libdw");
++    err (EXIT_FAILURE, "libdw: out of memory");
+ }
+--- a/libebl/eblopenbackend.c
++++ b/libebl/eblopenbackend.c
+@@ -32,7 +32,7 @@
+ 
+ #include <assert.h>
+ #include <dlfcn.h>
+-#include <error.h>
++#include <err.h>
+ #include <libelfP.h>
+ #include <dwarf.h>
+ #include <stdlib.h>
+--- a/libdwfl/dwfl_error.c
++++ b/libdwfl/dwfl_error.c
+@@ -140,6 +140,7 @@ __libdwfl_seterrno (Dwfl_Error error)
+ const char *
+ dwfl_errmsg (int error)
+ {
++  static __thread char s[64] = "";
+   if (error == 0 || error == -1)
+     {
+       int last_error = global_error;
+@@ -154,7 +155,8 @@ dwfl_errmsg (int error)
+   switch (error &~ 0xffff)
+     {
+     case OTHER_ERROR (ERRNO):
+-      return strerror_r (error & 0xffff, "bad", 0);
++      strerror_r (error & 0xffff, s, sizeof(s));
++      return s;
+     case OTHER_ERROR (LIBELF):
+       return elf_errmsg (error & 0xffff);
+     case OTHER_ERROR (LIBDW):
+--- a/libdwfl/libdwfl.h
++++ b/libdwfl/libdwfl.h
+@@ -31,6 +31,27 @@
+ 
+ #include "libdw.h"
+ #include <stdio.h>
++#include <unistd.h>
++#include <alloca.h>
++#include <string.h>
++
++#ifndef TEMP_FAILURE_RETRY
++#define TEMP_FAILURE_RETRY(expression) \
++  (__extension__                                                              \
++    ({ long int __result;                                                     \
++       do __result = (long int) (expression);                                 \
++       while (__result == -1L && errno == EINTR);                             \
++       __result; }))
++#endif
++
++#ifndef strndupa
++#define strndupa(s, n) \
++	(__extension__ ({const char *__in = (s); \
++			 size_t __len = strnlen (__in, (n)) + 1; \
++			 char *__out = (char *) alloca (__len); \
++			 __out[__len-1] = '\0'; \
++			 (char *) memcpy (__out, __in, __len-1);}))
++#endif
+ 
+ /* Handle for a session using the library.  */
+ typedef struct Dwfl Dwfl;
+--- a/libdwfl/find-debuginfo.c
++++ b/libdwfl/find-debuginfo.c
+@@ -385,7 +385,7 @@ dwfl_standard_find_debuginfo (Dwfl_Modul
+       /* If FILE_NAME is a symlink, the debug file might be associated
+ 	 with the symlink target name instead.  */
+ 
+-      char *canon = canonicalize_file_name (file_name);
++      char *canon = realpath (file_name, NULL);
+       if (canon != NULL && strcmp (file_name, canon))
+ 	fd = find_debuginfo_in_path (mod, canon,
+ 				     debuglink_file, debuglink_crc,
+--- a/libdwfl/dwfl_build_id_find_elf.c
++++ b/libdwfl/dwfl_build_id_find_elf.c
+@@ -94,7 +94,7 @@ __libdwfl_open_by_build_id (Dwfl_Module
+ 	{
+ 	  if (*file_name != NULL)
+ 	    free (*file_name);
+-	  *file_name = canonicalize_file_name (name);
++	  *file_name = realpath (name, NULL);
+ 	  if (*file_name == NULL)
+ 	    {
+ 	      *file_name = name;
+--- a/libelf/elf_getarsym.c
++++ b/libelf/elf_getarsym.c
+@@ -297,7 +297,7 @@ elf_getarsym (Elf *elf, size_t *ptr)
+ 		arsym[cnt].as_off = (*u32)[cnt];
+ 
+ 	      arsym[cnt].as_hash = _dl_elf_hash (str_data);
+-	      str_data = rawmemchr (str_data, '\0') + 1;
++	      str_data = memchr (str_data, '\0', SIZE_MAX) + 1;
+ 	    }
+ 
+ 	  /* At the end a special entry.  */
diff --git a/package/libs/elfutils/patches/101-no-fts.patch b/package/libs/elfutils/patches/101-no-fts.patch
new file mode 100644
index 0000000000..124563c787
--- /dev/null
+++ b/package/libs/elfutils/patches/101-no-fts.patch
@@ -0,0 +1,109 @@
+--- a/libdwfl/argp-std.c
++++ b/libdwfl/argp-std.c
+@@ -52,9 +52,6 @@ static const struct argp_option options[
+   { "linux-process-map", 'M', "FILE", 0,
+     N_("Find addresses in files mapped as read from FILE"
+        " in Linux /proc/PID/maps format"), 0 },
+-  { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
+-  { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
+-    N_("Kernel with all modules"), 0 },
+   { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
+     N_("Search path for separate debuginfo files"), 0 },
+   { NULL, 0, NULL, 0, NULL, 0 }
+@@ -81,15 +78,6 @@ static const Dwfl_Callbacks proc_callbac
+     .find_elf = INTUSE(dwfl_linux_proc_find_elf),
+   };
+ 
+-static const Dwfl_Callbacks kernel_callbacks =
+-  {
+-    .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
+-    .debuginfo_path = &debuginfo_path,
+-
+-    .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
+-    .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
+-  };
+-
+ /* Structure held at state->HOOK.  */
+ struct parse_opt
+ {
+@@ -219,43 +207,6 @@ parse_opt (int key, char *arg, struct ar
+       }
+       break;
+ 
+-    case 'k':
+-      {
+-	struct parse_opt *opt = state->hook;
+-	if (opt->dwfl == NULL)
+-	  {
+-	    Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
+-	    int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
+-	    if (result != 0)
+-	      return fail (dwfl, result, _("cannot load kernel symbols"));
+-	    result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
+-	    if (result != 0)
+-	      /* Non-fatal to have no modules since we do have the kernel.  */
+-	      failure (dwfl, result, _("cannot find kernel modules"));
+-	    opt->dwfl = dwfl;
+-	  }
+-	else
+-	  goto toomany;
+-      }
+-      break;
+-
+-    case 'K':
+-      {
+-	struct parse_opt *opt = state->hook;
+-	if (opt->dwfl == NULL)
+-	  {
+-	    Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+-	    int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
+-								   NULL);
+-	    if (result != 0)
+-	      return fail (dwfl, result, _("cannot find kernel or modules"));
+-	    opt->dwfl = dwfl;
+-	  }
+-	else
+-	  goto toomany;
+-      }
+-      break;
+-
+     case ARGP_KEY_SUCCESS:
+       {
+ 	struct parse_opt *opt = state->hook;
+--- a/libdwfl/Makefile.in
++++ b/libdwfl/Makefile.in
+@@ -120,7 +120,7 @@ am__libdwfl_a_SOURCES_DIST = dwfl_begin.
+ 	dwfl_getmodules.c dwfl_getdwarf.c dwfl_module_getdwarf.c \
+ 	dwfl_module_getelf.c dwfl_validate_address.c argp-std.c \
+ 	find-debuginfo.c dwfl_build_id_find_elf.c \
+-	dwfl_build_id_find_debuginfo.c linux-kernel-modules.c \
++	dwfl_build_id_find_debuginfo.c \
+ 	linux-proc-maps.c dwfl_addrmodule.c dwfl_addrdwarf.c cu.c \
+ 	dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
+ 	dwfl_module_addrdie.c dwfl_addrdie.c lines.c dwfl_lineinfo.c \
+@@ -148,7 +148,7 @@ am_libdwfl_a_OBJECTS = dwfl_begin.$(OBJE
+ 	dwfl_validate_address.$(OBJEXT) argp-std.$(OBJEXT) \
+ 	find-debuginfo.$(OBJEXT) dwfl_build_id_find_elf.$(OBJEXT) \
+ 	dwfl_build_id_find_debuginfo.$(OBJEXT) \
+-	linux-kernel-modules.$(OBJEXT) linux-proc-maps.$(OBJEXT) \
++	linux-proc-maps.$(OBJEXT) \
+ 	dwfl_addrmodule.$(OBJEXT) dwfl_addrdwarf.$(OBJEXT) \
+ 	cu.$(OBJEXT) dwfl_module_nextcu.$(OBJEXT) \
+ 	dwfl_nextcu.$(OBJEXT) dwfl_cumodule.$(OBJEXT) \
+@@ -432,7 +432,7 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_en
+ 	dwfl_getmodules.c dwfl_getdwarf.c dwfl_module_getdwarf.c \
+ 	dwfl_module_getelf.c dwfl_validate_address.c argp-std.c \
+ 	find-debuginfo.c dwfl_build_id_find_elf.c \
+-	dwfl_build_id_find_debuginfo.c linux-kernel-modules.c \
++	dwfl_build_id_find_debuginfo.c \
+ 	linux-proc-maps.c dwfl_addrmodule.c dwfl_addrdwarf.c cu.c \
+ 	dwfl_module_nextcu.c dwfl_nextcu.c dwfl_cumodule.c \
+ 	dwfl_module_addrdie.c dwfl_addrdie.c lines.c dwfl_lineinfo.c \
+@@ -569,7 +569,6 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lines.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link_map.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux-core-attach.Po@am__quote@
+-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux-kernel-modules.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux-pid-attach.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux-proc-maps.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzma.Po@am__quote@
diff --git a/package/libs/gettext-full/Makefile b/package/libs/gettext-full/Makefile
new file mode 100644
index 0000000000..eb4236b774
--- /dev/null
+++ b/package/libs/gettext-full/Makefile
@@ -0,0 +1,93 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gettext-full
+PKG_VERSION:=0.19.8.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=gettext-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/gettext
+PKG_MD5SUM:=df3f5690eaa30fd228537b00cb7b7590
+PKG_BUILD_DIR:=$(BUILD_DIR)/gettext-$(PKG_VERSION)
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/gettext-$(PKG_VERSION)
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-3.0+
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=0
+PKG_BUILD_DEPENDS:=gettext-full/host
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/libintl-full
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=GNU Internationalization library
+  URL:=http://www.gnu.org/software/gettext/
+endef
+
+TARGET_CFLAGS += $(FPIC)
+ifneq ($(HOST_OS),Linux)
+  TARGET_CFLAGS += -I$(STAGING_DIR)/host/include
+endif
+ifdef CONFIG_USE_MUSL
+  TARGET_CFLAGS += -D__UCLIBC__
+endif
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--disable-libasprintf \
+	--disable-rpath \
+	--enable-nls \
+	--disable-java \
+	--disable-native-java \
+	--disable-openmp \
+	--disable-curses \
+	--with-included-gettext \
+	--without-libintl-prefix \
+	--without-libexpat-prefix \
+	--without-emacs
+
+HOST_CONFIGURE_ARGS += \
+	--disable-libasprintf \
+	--disable-rpath \
+	--disable-java \
+	--disable-native-java \
+	--disable-openmp \
+	--without-emacs \
+	--without-libxml2-prefix
+
+
+HOST_CONFIGURE_VARS += \
+	EMACS="no"
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/libintl-full/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libintl.h $(1)/usr/lib/libintl-full/include/
+
+	$(INSTALL_DIR) $(1)/usr/lib/libintl-full/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libintl.{a,so*} $(1)/usr/lib/libintl-full/lib/
+
+	$(INSTALL_DIR) $(1)/usr/share/aclocal
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/aclocal/* $(1)/usr/share/aclocal/
+
+	$(SED) '/read dummy/d' $(STAGING_DIR)/host/bin/gettextize
+endef
+
+define Package/libintl-full/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libintl.so* $(1)/usr/lib/
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,libintl-full))
diff --git a/package/libs/gettext-full/patches/000-relocatable.patch b/package/libs/gettext-full/patches/000-relocatable.patch
new file mode 100644
index 0000000000..c14be72836
--- /dev/null
+++ b/package/libs/gettext-full/patches/000-relocatable.patch
@@ -0,0 +1,30 @@
+--- a/gettext-tools/misc/autopoint.in
++++ b/gettext-tools/misc/autopoint.in
+@@ -27,7 +27,11 @@ archive_version=@ARCHIVE_VERSION@
+ 
+ # Set variables
+ # - gettext_datadir     directory where the data files are stored.
+-prefix="@prefix@"
++if [ -n "$STAGING_DIR" ]; then
++	prefix="$STAGING_DIR/host"
++else
++	prefix="@prefix@"
++fi
+ datarootdir="@datarootdir@"
+ : ${gettext_datadir="@datadir@/gettext"}
+ : ${AUTOM4TE=autom4te}
+--- a/gettext-tools/misc/gettextize.in
++++ b/gettext-tools/misc/gettextize.in
+@@ -27,7 +27,11 @@ archive_version=@ARCHIVE_VERSION@
+ 
+ # Set variables
+ # - gettext_datadir     directory where the data files are stored.
+-prefix="@prefix@"
++if [ -n "$STAGING_DIR" ]; then
++	prefix="$STAGING_DIR/host"
++else
++	prefix="@prefix@"
++fi
+ datarootdir="@datarootdir@"
+ : ${gettext_datadir="@datadir@/gettext"}
+ : ${AUTOM4TE=autom4te}
diff --git a/package/libs/gettext-full/patches/001-autotools.patch b/package/libs/gettext-full/patches/001-autotools.patch
new file mode 100644
index 0000000000..4b1799f520
--- /dev/null
+++ b/package/libs/gettext-full/patches/001-autotools.patch
@@ -0,0 +1,24 @@
+--- a/gettext-runtime/man/Makefile.am
++++ b/gettext-runtime/man/Makefile.am
+@@ -172,8 +172,7 @@ textdomain.3.html: textdomain.3.in
+ bindtextdomain.3.html: bindtextdomain.3.in
+ bind_textdomain_codeset.3.html: bind_textdomain_codeset.3.in
+ 
+-install-html-local:
+-	$(MKDIR_P) $(DESTDIR)$(htmldir)
++install-html: installdirs-html
+ 	for file in $(man_HTML); do \
+ 	  if test -f $$file; then dir=.; else dir=$(srcdir); fi; \
+ 	  $(INSTALL_DATA) $$dir/$$file $(DESTDIR)$(htmldir)/$$file; \
+--- a/gettext-tools/man/Makefile.am
++++ b/gettext-tools/man/Makefile.am
+@@ -153,8 +153,7 @@ recode-sr-latin.1.html: recode-sr-latin.
+ gettextize.1.html: gettextize.1
+ autopoint.1.html: autopoint.1
+ 
+-install-html-local:
+-	$(MKDIR_P) $(DESTDIR)$(htmldir)
++install-html: installdirs-html
+ 	for file in $(man_HTML); do \
+ 	  if test -f $$file; then dir=.; else dir=$(srcdir); fi; \
+ 	  $(INSTALL_DATA) $$dir/$$file $(DESTDIR)$(htmldir)/$$file; \
diff --git a/package/libs/gettext-full/patches/001-no_examples_and_tests.patch b/package/libs/gettext-full/patches/001-no_examples_and_tests.patch
new file mode 100644
index 0000000000..abb1b24239
--- /dev/null
+++ b/package/libs/gettext-full/patches/001-no_examples_and_tests.patch
@@ -0,0 +1,22 @@
+--- a/gettext-runtime/Makefile.am
++++ b/gettext-runtime/Makefile.am
+@@ -29,7 +29,7 @@ SUBDIR_libasprintf = libasprintf
+ else
+ SUBDIR_libasprintf =
+ endif
+-SUBDIRS = doc intl intl-java intl-csharp gnulib-lib $(SUBDIR_libasprintf) src po man m4 tests
++SUBDIRS = intl intl-java intl-csharp gnulib-lib $(SUBDIR_libasprintf) src po m4
+ 
+ EXTRA_DIST = BUGS
+ 
+--- a/gettext-tools/Makefile.am
++++ b/gettext-tools/Makefile.am
+@@ -19,7 +19,7 @@
+ AUTOMAKE_OPTIONS = 1.5 gnu no-dependencies
+ ACLOCAL_AMFLAGS = -I m4 -I ../gettext-runtime/m4 -I ../m4 -I gnulib-m4 -I libgrep/gnulib-m4 -I libgettextpo/gnulib-m4
+ 
+-SUBDIRS = doc intl gnulib-lib libgrep src libgettextpo po projects styles misc man m4 tests gnulib-tests examples its
++SUBDIRS = intl gnulib-lib libgrep src libgettextpo po projects styles misc m4 its
+ 
+ EXTRA_DIST = misc/DISCLAIM
+ MOSTLYCLEANFILES = core *.stackdump
diff --git a/package/libs/gettext-full/patches/003-gettext-error_print_progname.patch b/package/libs/gettext-full/patches/003-gettext-error_print_progname.patch
new file mode 100644
index 0000000000..6698e300af
--- /dev/null
+++ b/package/libs/gettext-full/patches/003-gettext-error_print_progname.patch
@@ -0,0 +1,11 @@
+--- a/gettext-tools/libgettextpo/error.h
++++ b/gettext-tools/libgettextpo/error.h
+@@ -68,7 +68,7 @@ extern void error_at_line (int __status,
+ /* If NULL, error will flush stdout, then print on stderr the program
+    name, a colon and a space.  Otherwise, error will call this
+    function without parameters instead.  */
+-extern DLL_VARIABLE void (*error_print_progname) (void);
++void (*error_print_progname) (void);
+ 
+ /* This variable is incremented each time 'error' is called.  */
+ extern DLL_VARIABLE unsigned int error_message_count;
diff --git a/package/libs/gettext-full/patches/100-error_progname.patch b/package/libs/gettext-full/patches/100-error_progname.patch
new file mode 100644
index 0000000000..38371aeacb
--- /dev/null
+++ b/package/libs/gettext-full/patches/100-error_progname.patch
@@ -0,0 +1,10 @@
+--- a/gettext-runtime/intl/intl-compat.c
++++ b/gettext-runtime/intl/intl-compat.c
+@@ -130,3 +130,7 @@ bind_textdomain_codeset (const char *dom
+ {
+   return libintl_bind_textdomain_codeset (domainname, codeset);
+ }
++
++#ifdef __UCLIBC__
++DLL_EXPORTED void (*error_print_progname)(void) = NULL;
++#endif
diff --git a/package/libs/gettext-full/patches/110-error_progname_def.patch b/package/libs/gettext-full/patches/110-error_progname_def.patch
new file mode 100644
index 0000000000..e47c7de77f
--- /dev/null
+++ b/package/libs/gettext-full/patches/110-error_progname_def.patch
@@ -0,0 +1,11 @@
+--- a/gettext-tools/libgettextpo/error.h
++++ b/gettext-tools/libgettextpo/error.h
+@@ -68,7 +68,7 @@ extern void error_at_line (int __status,
+ /* If NULL, error will flush stdout, then print on stderr the program
+    name, a colon and a space.  Otherwise, error will call this
+    function without parameters instead.  */
+-void (*error_print_progname) (void);
++extern void (*error_print_progname) (void);
+ 
+ /* This variable is incremented each time 'error' is called.  */
+ extern DLL_VARIABLE unsigned int error_message_count;
diff --git a/package/libs/gettext-full/patches/120-uclibc-nolocale.patch b/package/libs/gettext-full/patches/120-uclibc-nolocale.patch
new file mode 100644
index 0000000000..40ca10edd0
--- /dev/null
+++ b/package/libs/gettext-full/patches/120-uclibc-nolocale.patch
@@ -0,0 +1,11 @@
+--- a/gettext-runtime/intl/localename.c
++++ b/gettext-runtime/intl/localename.c
+@@ -2790,7 +2790,7 @@ gl_locale_name_posix (int category, cons
+ {
+   /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
+      On some systems this can be done by the 'setlocale' function itself.  */
+-#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
++#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL && (!defined __UCLIBC__ || defined __UCLIBC_HAS_LOCALE__)
+   return setlocale (category, NULL);
+ #else
+   /* On other systems we ignore what setlocale reports and instead look at the
diff --git a/package/libs/gettext-full/patches/130-format-secuirty.patch b/package/libs/gettext-full/patches/130-format-secuirty.patch
new file mode 100644
index 0000000000..89cb3fbfe0
--- /dev/null
+++ b/package/libs/gettext-full/patches/130-format-secuirty.patch
@@ -0,0 +1,59 @@
+From c7197cad42d6269739f379025c2bec9e474c8027 Mon Sep 17 00:00:00 2001
+From: Tobias Mueller <tobiasmue@gnome.org>
+Date: Sat, 29 Jan 2011 16:31:30 +0100
+Subject: Fixed format string issues by giving static literals, fixes bug
+ 640897
+
+---
+ src/cr-statement.c | 10 +++++-----
+ tests/test2-main.c |  8 +++-----
+ tests/test3-main.c |  8 +++-----
+ 3 files changed, 11 insertions(+), 15 deletions(-)
+
+--- a/gettext-tools/gnulib-lib/libcroco/cr-statement.c
++++ b/gettext-tools/gnulib-lib/libcroco/cr-statement.c
+@@ -2607,7 +2607,7 @@ cr_statement_dump_ruleset (CRStatement *
+         g_return_if_fail (a_fp && a_this);
+         str = cr_statement_ruleset_to_string (a_this, a_indent);
+         if (str) {
+-                fprintf (a_fp, str);
++                fprintf (a_fp, "%s", str);
+                 g_free (str);
+                 str = NULL;
+         }
+@@ -2658,7 +2658,7 @@ cr_statement_dump_charset (CRStatement *
+         str = cr_statement_charset_to_string (a_this,
+                                               a_indent) ;
+         if (str) {
+-                fprintf (a_fp, str) ;
++                fprintf (a_fp, "%s", str) ;
+                 g_free (str) ;
+                 str = NULL ;
+         }
+@@ -2685,7 +2685,7 @@ cr_statement_dump_page (CRStatement * a_
+ 
+         str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
+         if (str) {
+-                fprintf (a_fp, str);
++                fprintf (a_fp, "%s", str);
+                 g_free (str) ;
+                 str = NULL ; 
+         }
+@@ -2711,7 +2711,7 @@ cr_statement_dump_media_rule (CRStatemen
+ 
+         str = cr_statement_media_rule_to_string (a_this, a_indent) ;
+         if (str) {
+-                fprintf (a_fp, str) ;
++                fprintf (a_fp, "%s", str) ;
+                 g_free (str) ;
+                 str = NULL ;
+         }
+@@ -2737,7 +2737,7 @@ cr_statement_dump_import_rule (CRStateme
+ 
+         str = cr_statement_import_rule_to_string (a_this, a_indent) ;
+         if (str) {
+-                fprintf (a_fp, str) ;
++                fprintf (a_fp, "%s", str) ;
+                 g_free (str) ;
+                 str = NULL ;
+         }
diff --git a/package/libs/gettext-full/patches/150-disable_libxml_iconv.patch b/package/libs/gettext-full/patches/150-disable_libxml_iconv.patch
new file mode 100644
index 0000000000..da037fe799
--- /dev/null
+++ b/package/libs/gettext-full/patches/150-disable_libxml_iconv.patch
@@ -0,0 +1,22 @@
+--- a/gettext-tools/gnulib-lib/libxml/xmlversion.in.h
++++ b/gettext-tools/gnulib-lib/libxml/xmlversion.in.h
+@@ -273,7 +273,7 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(i
+  *
+  * Whether iconv support is available
+  */
+-#if 1
++#if 0
+ #define LIBXML_ICONV_ENABLED
+ #endif
+ 
+--- a/gnulib-local/lib/libxml/xmlversion.in.h
++++ b/gnulib-local/lib/libxml/xmlversion.in.h
+@@ -273,7 +273,7 @@ XMLPUBFUN void XMLCALL xmlCheckVersion(i
+  *
+  * Whether iconv support is available
+  */
+-#if 1
++#if 0
+ #define LIBXML_ICONV_ENABLED
+ #endif
+ 
diff --git a/package/libs/gettext/Makefile b/package/libs/gettext/Makefile
new file mode 100644
index 0000000000..b0233309e2
--- /dev/null
+++ b/package/libs/gettext/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gettext
+PKG_RELEASE:=2
+
+PKG_LICENSE:=FSFULLR
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/libintl
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Stub header for the GNU Internationalization library
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/libintl-stub/include
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/include/libintl.h $(1)/usr/lib/libintl-stub/include/
+
+	$(INSTALL_DIR) $(1)/usr/share/aclocal
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/m4/* $(1)/usr/share/aclocal/
+endef
+
+define Host/Prepare
+	mkdir -p $(HOST_BUILD_DIR)
+endef
+
+define Host/Compile
+
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR)/host/include
+	$(INSTALL_DATA) ./src/include/libintl.h $(STAGING_DIR)/host/include/
+
+	$(INSTALL_DIR) $(STAGING_DIR)/host/share/aclocal
+	$(INSTALL_DATA) ./src/m4/* $(STAGING_DIR)/host/share/aclocal/
+endef
+
+define Package/libintl/install
+	$(INSTALL_DIR) $(1)/tmp
+	touch $(1)/tmp/.libintl-placeholder
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,libintl))
diff --git a/package/libs/gettext/src/LICENSE b/package/libs/gettext/src/LICENSE
new file mode 100644
index 0000000000..d1a59b05ec
--- /dev/null
+++ b/package/libs/gettext/src/LICENSE
@@ -0,0 +1,7 @@
+Each source file contains the following message:
+
+Copyright (C) 1995-2010 Free Software Foundation, Inc.
+This file is free software; the Free Software Foundation
+gives unlimited permission to copy and/or distribute it,
+with or without modifications, as long as this notice is preserved.
+
diff --git a/package/libs/gettext/src/include/libintl.h b/package/libs/gettext/src/include/libintl.h
new file mode 100644
index 0000000000..a1157a4453
--- /dev/null
+++ b/package/libs/gettext/src/include/libintl.h
@@ -0,0 +1,53 @@
+/*
+ * This code is lifted from http://permalink.gmane.org/gmane.linux.gentoo.embedded/3218
+ */
+
+#ifndef _LIBINTL_H
+#define _LIBINTL_H      1
+
+#include <locale.h>
+
+/* Undef gettext macros, if any... */
+#undef gettext
+#undef dgettext
+#undef dcgettext
+#undef ngettext
+#undef dngettext
+#undef dcngettext
+#undef textdomain
+#undef bindtextdomain
+#undef bind_textdomain_codeset
+
+/* part of locale.h */
+/* #undef setlocale */
+
+#undef _
+#undef N_
+
+/* Define gettext stubs that map back to the original strings */
+#define gettext(String) (String)
+#define dgettext(Domain, String) (String)
+#define dcgettext(Domain, String, Type) (String)
+
+#define ngettext(Singular, Plural, Count) \
+	((Count) == 1 ? (const char *) (Singular) : (const char *) (Plural))
+
+#define dngettext(Domain, Singular, Plural, Count) \
+	((Count) == 1 ? (const char *) (Singular) : (const char *) (Plural))
+
+#define dcngettext(Domain, Singular, Plural, Count, Category) \
+	((Count) == 1 ? (const char *) (Singular) : (const char *) (Plural))
+
+#define _(String) (String)
+#define N_(String) String
+
+#ifndef _LOCALE_H
+/* #define setlocale(Category, Locale) ((char *)NULL) */
+#endif
+
+/* No-ops for textdomain operations */
+#define bindtextdomain(Domain, Directory) (Domain)
+#define bind_textdomain_codeset(Domain, Codeset) (Codeset)
+#define textdomain(String) (String) ?: "messages"
+
+#endif  /* _LIBINTL_H */
diff --git a/package/libs/gettext/src/m4/codeset.m4 b/package/libs/gettext/src/m4/codeset.m4
new file mode 100644
index 0000000000..a53c04260c
--- /dev/null
+++ b/package/libs/gettext/src/m4/codeset.m4
@@ -0,0 +1,21 @@
+# codeset.m4 serial 4 (gettext-0.18)
+dnl Copyright (C) 2000-2002, 2006, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_LANGINFO_CODESET],
+[
+  AC_CACHE_CHECK([for nl_langinfo and CODESET], [am_cv_langinfo_codeset],
+    [AC_TRY_LINK([#include <langinfo.h>],
+      [char* cs = nl_langinfo(CODESET); return !cs;],
+      [am_cv_langinfo_codeset=yes],
+      [am_cv_langinfo_codeset=no])
+    ])
+  if test $am_cv_langinfo_codeset = yes; then
+    AC_DEFINE([HAVE_LANGINFO_CODESET], [1],
+      [Define if you have <langinfo.h> and nl_langinfo(CODESET).])
+  fi
+])
diff --git a/package/libs/gettext/src/m4/gettext.m4 b/package/libs/gettext/src/m4/gettext.m4
new file mode 100644
index 0000000000..f84e6a5d75
--- /dev/null
+++ b/package/libs/gettext/src/m4/gettext.m4
@@ -0,0 +1,383 @@
+# gettext.m4 serial 63 (gettext-0.18)
+dnl Copyright (C) 1995-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2006, 2008-2010.
+
+dnl Macro to add for using GNU gettext.
+
+dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]).
+dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The
+dnl    default (if it is not specified or empty) is 'no-libtool'.
+dnl    INTLSYMBOL should be 'external' for packages with no intl directory,
+dnl    and 'no-libtool' or 'use-libtool' for packages with an intl directory.
+dnl    If INTLSYMBOL is 'use-libtool', then a libtool library
+dnl    $(top_builddir)/intl/libintl.la will be created (shared and/or static,
+dnl    depending on --{enable,disable}-{shared,static} and on the presence of
+dnl    AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library
+dnl    $(top_builddir)/intl/libintl.a will be created.
+dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext
+dnl    implementations (in libc or libintl) without the ngettext() function
+dnl    will be ignored.  If NEEDSYMBOL is specified and is
+dnl    'need-formatstring-macros', then GNU gettext implementations that don't
+dnl    support the ISO C 99 <inttypes.h> formatstring macros will be ignored.
+dnl INTLDIR is used to find the intl libraries.  If empty,
+dnl    the value `$(top_builddir)/intl/' is used.
+dnl
+dnl The result of the configuration is one of three cases:
+dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled
+dnl    and used.
+dnl    Catalog format: GNU --> install in $(datadir)
+dnl    Catalog extension: .mo after installation, .gmo in source tree
+dnl 2) GNU gettext has been found in the system's C library.
+dnl    Catalog format: GNU --> install in $(datadir)
+dnl    Catalog extension: .mo after installation, .gmo in source tree
+dnl 3) No internationalization, always use English msgid.
+dnl    Catalog format: none
+dnl    Catalog extension: none
+dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur.
+dnl The use of .gmo is historical (it was needed to avoid overwriting the
+dnl GNU format catalogs when building on a platform with an X/Open gettext),
+dnl but we keep it in order not to force irrelevant filename changes on the
+dnl maintainers.
+dnl
+AC_DEFUN([AM_GNU_GETTEXT],
+[
+  dnl Argument checking.
+  ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], ,
+    [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT
+])])])])])
+  ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old],
+    [AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])])
+  ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], ,
+    [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT
+])])])])
+  define([gt_included_intl],
+    ifelse([$1], [external],
+      ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]),
+      [yes]))
+  define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], []))
+  gt_NEEDS_INIT
+  AM_GNU_GETTEXT_NEED([$2])
+
+  AC_REQUIRE([AM_PO_SUBDIRS])dnl
+  ifelse(gt_included_intl, yes, [
+    AC_REQUIRE([AM_INTL_SUBDIR])dnl
+  ])
+
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Sometimes libintl requires libiconv, so first search for libiconv.
+  dnl Ideally we would do this search only after the
+  dnl      if test "$USE_NLS" = "yes"; then
+  dnl        if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then
+  dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT
+  dnl the configure script would need to contain the same shell code
+  dnl again, outside any 'if'. There are two solutions:
+  dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'.
+  dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE.
+  dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not
+  dnl documented, we avoid it.
+  ifelse(gt_included_intl, yes, , [
+    AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+  ])
+
+  dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation.
+  gt_INTL_MACOSX
+
+  dnl Set USE_NLS.
+  AC_REQUIRE([AM_NLS])
+
+  ifelse(gt_included_intl, yes, [
+    BUILD_INCLUDED_LIBINTL=no
+    USE_INCLUDED_LIBINTL=no
+  ])
+  LIBINTL=
+  LTLIBINTL=
+  POSUB=
+
+  dnl Add a version number to the cache macros.
+  case " $gt_needs " in
+    *" need-formatstring-macros "*) gt_api_version=3 ;;
+    *" need-ngettext "*) gt_api_version=2 ;;
+    *) gt_api_version=1 ;;
+  esac
+  gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc"
+  gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl"
+
+  dnl If we use NLS figure out what method
+  if test "$USE_NLS" = "yes"; then
+    gt_use_preinstalled_gnugettext=no
+    ifelse(gt_included_intl, yes, [
+      AC_MSG_CHECKING([whether included gettext is requested])
+      AC_ARG_WITH([included-gettext],
+        [  --with-included-gettext use the GNU gettext library included here],
+        nls_cv_force_use_gnu_gettext=$withval,
+        nls_cv_force_use_gnu_gettext=no)
+      AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext])
+
+      nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+      if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+    ])
+        dnl User does not insist on using GNU NLS library.  Figure out what
+        dnl to use.  If GNU gettext is available we use this.  Else we have
+        dnl to fall back to GNU NLS library.
+
+        if test $gt_api_version -ge 3; then
+          gt_revision_test_code='
+#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
+#endif
+changequote(,)dnl
+typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
+changequote([,])dnl
+'
+        else
+          gt_revision_test_code=
+        fi
+        if test $gt_api_version -ge 2; then
+          gt_expression_test_code=' + * ngettext ("", "", 0)'
+        else
+          gt_expression_test_code=
+        fi
+
+        AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc],
+         [AC_TRY_LINK([#include <libintl.h>
+$gt_revision_test_code
+extern int _nl_msg_cat_cntr;
+extern int *_nl_domain_bindings;],
+            [bindtextdomain ("", "");
+return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings],
+            [eval "$gt_func_gnugettext_libc=yes"],
+            [eval "$gt_func_gnugettext_libc=no"])])
+
+        if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then
+          dnl Sometimes libintl requires libiconv, so first search for libiconv.
+          ifelse(gt_included_intl, yes, , [
+            AM_ICONV_LINK
+          ])
+          dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL
+          dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv])
+          dnl because that would add "-liconv" to LIBINTL and LTLIBINTL
+          dnl even if libiconv doesn't exist.
+          AC_LIB_LINKFLAGS_BODY([intl])
+          AC_CACHE_CHECK([for GNU gettext in libintl],
+            [$gt_func_gnugettext_libintl],
+           [gt_save_CPPFLAGS="$CPPFLAGS"
+            CPPFLAGS="$CPPFLAGS $INCINTL"
+            gt_save_LIBS="$LIBS"
+            LIBS="$LIBS $LIBINTL"
+            dnl Now see whether libintl exists and does not depend on libiconv.
+            AC_TRY_LINK([#include <libintl.h>
+$gt_revision_test_code
+extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);],
+              [bindtextdomain ("", "");
+return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
+              [eval "$gt_func_gnugettext_libintl=yes"],
+              [eval "$gt_func_gnugettext_libintl=no"])
+            dnl Now see whether libintl exists and depends on libiconv.
+            if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then
+              LIBS="$LIBS $LIBICONV"
+              AC_TRY_LINK([#include <libintl.h>
+$gt_revision_test_code
+extern int _nl_msg_cat_cntr;
+extern
+#ifdef __cplusplus
+"C"
+#endif
+const char *_nl_expand_alias (const char *);],
+                [bindtextdomain ("", "");
+return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
+               [LIBINTL="$LIBINTL $LIBICONV"
+                LTLIBINTL="$LTLIBINTL $LTLIBICONV"
+                eval "$gt_func_gnugettext_libintl=yes"
+               ])
+            fi
+            CPPFLAGS="$gt_save_CPPFLAGS"
+            LIBS="$gt_save_LIBS"])
+        fi
+
+        dnl If an already present or preinstalled GNU gettext() is found,
+        dnl use it.  But if this macro is used in GNU gettext, and GNU
+        dnl gettext is already preinstalled in libintl, we update this
+        dnl libintl.  (Cf. the install rule in intl/Makefile.in.)
+        if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \
+           || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \
+                && test "$PACKAGE" != gettext-runtime \
+                && test "$PACKAGE" != gettext-tools; }; then
+          gt_use_preinstalled_gnugettext=yes
+        else
+          dnl Reset the values set by searching for libintl.
+          LIBINTL=
+          LTLIBINTL=
+          INCINTL=
+        fi
+
+    ifelse(gt_included_intl, yes, [
+        if test "$gt_use_preinstalled_gnugettext" != "yes"; then
+          dnl GNU gettext is not found in the C library.
+          dnl Fall back on included GNU gettext library.
+          nls_cv_use_gnu_gettext=yes
+        fi
+      fi
+
+      if test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Mark actions used to generate GNU NLS library.
+        BUILD_INCLUDED_LIBINTL=yes
+        USE_INCLUDED_LIBINTL=yes
+        LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD"
+        LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD"
+        LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'`
+      fi
+
+      CATOBJEXT=
+      if test "$gt_use_preinstalled_gnugettext" = "yes" \
+         || test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Mark actions to use GNU gettext tools.
+        CATOBJEXT=.gmo
+      fi
+    ])
+
+    if test -n "$INTL_MACOSX_LIBS"; then
+      if test "$gt_use_preinstalled_gnugettext" = "yes" \
+         || test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Some extra flags are needed during linking.
+        LIBINTL="$LIBINTL $INTL_MACOSX_LIBS"
+        LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS"
+      fi
+    fi
+
+    if test "$gt_use_preinstalled_gnugettext" = "yes" \
+       || test "$nls_cv_use_gnu_gettext" = "yes"; then
+      AC_DEFINE([ENABLE_NLS], [1],
+        [Define to 1 if translation of program messages to the user's native language
+   is requested.])
+    else
+      USE_NLS=no
+    fi
+  fi
+
+  AC_MSG_CHECKING([whether to use NLS])
+  AC_MSG_RESULT([$USE_NLS])
+  if test "$USE_NLS" = "yes"; then
+    AC_MSG_CHECKING([where the gettext function comes from])
+    if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+      if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then
+        gt_source="external libintl"
+      else
+        gt_source="libc"
+      fi
+    else
+      gt_source="included intl directory"
+    fi
+    AC_MSG_RESULT([$gt_source])
+  fi
+
+  if test "$USE_NLS" = "yes"; then
+
+    if test "$gt_use_preinstalled_gnugettext" = "yes"; then
+      if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then
+        AC_MSG_CHECKING([how to link with libintl])
+        AC_MSG_RESULT([$LIBINTL])
+        AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL])
+      fi
+
+      dnl For backward compatibility. Some packages may be using this.
+      AC_DEFINE([HAVE_GETTEXT], [1],
+       [Define if the GNU gettext() function is already present or preinstalled.])
+      AC_DEFINE([HAVE_DCGETTEXT], [1],
+       [Define if the GNU dcgettext() function is already present or preinstalled.])
+    fi
+
+    dnl We need to process the po/ directory.
+    POSUB=po
+  fi
+
+  ifelse(gt_included_intl, yes, [
+    dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL
+    dnl to 'yes' because some of the testsuite requires it.
+    if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then
+      BUILD_INCLUDED_LIBINTL=yes
+    fi
+
+    dnl Make all variables we use known to autoconf.
+    AC_SUBST([BUILD_INCLUDED_LIBINTL])
+    AC_SUBST([USE_INCLUDED_LIBINTL])
+    AC_SUBST([CATOBJEXT])
+
+    dnl For backward compatibility. Some configure.ins may be using this.
+    nls_cv_header_intl=
+    nls_cv_header_libgt=
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    DATADIRNAME=share
+    AC_SUBST([DATADIRNAME])
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    INSTOBJEXT=.mo
+    AC_SUBST([INSTOBJEXT])
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    GENCAT=gencat
+    AC_SUBST([GENCAT])
+
+    dnl For backward compatibility. Some Makefiles may be using this.
+    INTLOBJS=
+    if test "$USE_INCLUDED_LIBINTL" = yes; then
+      INTLOBJS="\$(GETTOBJS)"
+    fi
+    AC_SUBST([INTLOBJS])
+
+    dnl Enable libtool support if the surrounding package wishes it.
+    INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix
+    AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX])
+  ])
+
+  dnl For backward compatibility. Some Makefiles may be using this.
+  INTLLIBS="$LIBINTL"
+  AC_SUBST([INTLLIBS])
+
+  dnl Make all documented variables known to autoconf.
+  AC_SUBST([LIBINTL])
+  AC_SUBST([LTLIBINTL])
+  AC_SUBST([POSUB])
+])
+
+
+dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized.
+m4_define([gt_NEEDS_INIT],
+[
+  m4_divert_text([DEFAULTS], [gt_needs=])
+  m4_define([gt_NEEDS_INIT], [])
+])
+
+
+dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL])
+AC_DEFUN([AM_GNU_GETTEXT_NEED],
+[
+  m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"])
+])
+
+
+dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version])
+AC_DEFUN([AM_GNU_GETTEXT_VERSION], [])
diff --git a/package/libs/gettext/src/m4/intl.m4 b/package/libs/gettext/src/m4/intl.m4
new file mode 100644
index 0000000000..335b23c20c
--- /dev/null
+++ b/package/libs/gettext/src/m4/intl.m4
@@ -0,0 +1,294 @@
+# intl.m4 serial 17 (gettext-0.18)
+dnl Copyright (C) 1995-2009 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2009.
+
+AC_PREREQ([2.52])
+
+dnl Checks for all prerequisites of the intl subdirectory,
+dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS,
+dnl            USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL.
+AC_DEFUN([AM_INTL_SUBDIR],
+[
+  AC_REQUIRE([AC_PROG_INSTALL])dnl
+  AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake
+  AC_REQUIRE([AC_PROG_CC])dnl
+  AC_REQUIRE([AC_CANONICAL_HOST])dnl
+  AC_REQUIRE([gt_GLIBC2])dnl
+  AC_REQUIRE([AC_PROG_RANLIB])dnl
+  AC_REQUIRE([gl_VISIBILITY])dnl
+  AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl
+  AC_REQUIRE([AC_TYPE_LONG_LONG_INT])dnl
+  AC_REQUIRE([gt_TYPE_WCHAR_T])dnl
+  AC_REQUIRE([gt_TYPE_WINT_T])dnl
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  AC_REQUIRE([gt_TYPE_INTMAX_T])
+  AC_REQUIRE([gt_PRINTF_POSIX])
+  AC_REQUIRE([gl_GLIBC21])dnl
+  AC_REQUIRE([gl_XSIZE])dnl
+  AC_REQUIRE([gl_FCNTL_O_FLAGS])dnl
+  AC_REQUIRE([gt_INTL_MACOSX])dnl
+
+  dnl Support for automake's --enable-silent-rules.
+  case "$enable_silent_rules" in
+    yes) INTL_DEFAULT_VERBOSITY=0;;
+    no)  INTL_DEFAULT_VERBOSITY=1;;
+    *)   INTL_DEFAULT_VERBOSITY=1;;
+  esac
+  AC_SUBST([INTL_DEFAULT_VERBOSITY])
+
+  AC_CHECK_TYPE([ptrdiff_t], ,
+    [AC_DEFINE([ptrdiff_t], [long],
+       [Define as the type of the result of subtracting two pointers, if the system doesn't define it.])
+    ])
+  AC_CHECK_HEADERS([stddef.h stdlib.h string.h])
+  AC_CHECK_FUNCS([asprintf fwprintf newlocale putenv setenv setlocale \
+    snprintf strnlen wcslen wcsnlen mbrtowc wcrtomb])
+
+  dnl Use the _snprintf function only if it is declared (because on NetBSD it
+  dnl is defined as a weak alias of snprintf; we prefer to use the latter).
+  gt_CHECK_DECL(_snprintf, [#include <stdio.h>])
+  gt_CHECK_DECL(_snwprintf, [#include <stdio.h>])
+
+  dnl Use the *_unlocked functions only if they are declared.
+  dnl (because some of them were defined without being declared in Solaris
+  dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built
+  dnl on Solaris 2.5.1 to run on Solaris 2.6).
+  dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13.
+  gt_CHECK_DECL(getc_unlocked, [#include <stdio.h>])
+
+  case $gt_cv_func_printf_posix in
+    *yes) HAVE_POSIX_PRINTF=1 ;;
+    *) HAVE_POSIX_PRINTF=0 ;;
+  esac
+  AC_SUBST([HAVE_POSIX_PRINTF])
+  if test "$ac_cv_func_asprintf" = yes; then
+    HAVE_ASPRINTF=1
+  else
+    HAVE_ASPRINTF=0
+  fi
+  AC_SUBST([HAVE_ASPRINTF])
+  if test "$ac_cv_func_snprintf" = yes; then
+    HAVE_SNPRINTF=1
+  else
+    HAVE_SNPRINTF=0
+  fi
+  AC_SUBST([HAVE_SNPRINTF])
+  if test "$ac_cv_func_newlocale" = yes; then
+    HAVE_NEWLOCALE=1
+  else
+    HAVE_NEWLOCALE=0
+  fi
+  AC_SUBST([HAVE_NEWLOCALE])
+  if test "$ac_cv_func_wprintf" = yes; then
+    HAVE_WPRINTF=1
+  else
+    HAVE_WPRINTF=0
+  fi
+  AC_SUBST([HAVE_WPRINTF])
+
+  AM_LANGINFO_CODESET
+  gt_LC_MESSAGES
+
+  dnl Compilation on mingw and Cygwin needs special Makefile rules, because
+  dnl 1. when we install a shared library, we must arrange to export
+  dnl    auxiliary pointer variables for every exported variable,
+  dnl 2. when we install a shared library and a static library simultaneously,
+  dnl    the include file specifies __declspec(dllimport) and therefore we
+  dnl    must arrange to define the auxiliary pointer variables for the
+  dnl    exported variables _also_ in the static library.
+  if test "$enable_shared" = yes; then
+    case "$host_os" in
+      mingw* | cygwin*) is_woe32dll=yes ;;
+      *) is_woe32dll=no ;;
+    esac
+  else
+    is_woe32dll=no
+  fi
+  WOE32DLL=$is_woe32dll
+  AC_SUBST([WOE32DLL])
+
+  dnl On mingw and Cygwin, we can activate special Makefile rules which add
+  dnl version information to the shared libraries and executables.
+  case "$host_os" in
+    mingw* | cygwin*) is_woe32=yes ;;
+    *) is_woe32=no ;;
+  esac
+  WOE32=$is_woe32
+  AC_SUBST([WOE32])
+  if test $WOE32 = yes; then
+    dnl Check for a program that compiles Windows resource files.
+    AC_CHECK_TOOL([WINDRES], [windres])
+  fi
+
+  dnl Determine whether when creating a library, "-lc" should be passed to
+  dnl libtool or not. On many platforms, it is required for the libtool option
+  dnl -no-undefined to work. On HP-UX, however, the -lc - stored by libtool
+  dnl in the *.la files - makes it impossible to create multithreaded programs,
+  dnl because libtool also reorders the -lc to come before the -pthread, and
+  dnl this disables pthread_create() <http://docs.hp.com/en/1896/pthreads.html>.
+  case "$host_os" in
+    hpux*) LTLIBC="" ;;
+    *)     LTLIBC="-lc" ;;
+  esac
+  AC_SUBST([LTLIBC])
+
+  dnl Rename some macros and functions used for locking.
+  AH_BOTTOM([
+#define __libc_lock_t                   gl_lock_t
+#define __libc_lock_define              gl_lock_define
+#define __libc_lock_define_initialized  gl_lock_define_initialized
+#define __libc_lock_init                gl_lock_init
+#define __libc_lock_lock                gl_lock_lock
+#define __libc_lock_unlock              gl_lock_unlock
+#define __libc_lock_recursive_t                   gl_recursive_lock_t
+#define __libc_lock_define_recursive              gl_recursive_lock_define
+#define __libc_lock_define_initialized_recursive  gl_recursive_lock_define_initialized
+#define __libc_lock_init_recursive                gl_recursive_lock_init
+#define __libc_lock_lock_recursive                gl_recursive_lock_lock
+#define __libc_lock_unlock_recursive              gl_recursive_lock_unlock
+#define glthread_in_use  libintl_thread_in_use
+#define glthread_lock_init_func     libintl_lock_init_func
+#define glthread_lock_lock_func     libintl_lock_lock_func
+#define glthread_lock_unlock_func   libintl_lock_unlock_func
+#define glthread_lock_destroy_func  libintl_lock_destroy_func
+#define glthread_rwlock_init_multithreaded     libintl_rwlock_init_multithreaded
+#define glthread_rwlock_init_func              libintl_rwlock_init_func
+#define glthread_rwlock_rdlock_multithreaded   libintl_rwlock_rdlock_multithreaded
+#define glthread_rwlock_rdlock_func            libintl_rwlock_rdlock_func
+#define glthread_rwlock_wrlock_multithreaded   libintl_rwlock_wrlock_multithreaded
+#define glthread_rwlock_wrlock_func            libintl_rwlock_wrlock_func
+#define glthread_rwlock_unlock_multithreaded   libintl_rwlock_unlock_multithreaded
+#define glthread_rwlock_unlock_func            libintl_rwlock_unlock_func
+#define glthread_rwlock_destroy_multithreaded  libintl_rwlock_destroy_multithreaded
+#define glthread_rwlock_destroy_func           libintl_rwlock_destroy_func
+#define glthread_recursive_lock_init_multithreaded     libintl_recursive_lock_init_multithreaded
+#define glthread_recursive_lock_init_func              libintl_recursive_lock_init_func
+#define glthread_recursive_lock_lock_multithreaded     libintl_recursive_lock_lock_multithreaded
+#define glthread_recursive_lock_lock_func              libintl_recursive_lock_lock_func
+#define glthread_recursive_lock_unlock_multithreaded   libintl_recursive_lock_unlock_multithreaded
+#define glthread_recursive_lock_unlock_func            libintl_recursive_lock_unlock_func
+#define glthread_recursive_lock_destroy_multithreaded  libintl_recursive_lock_destroy_multithreaded
+#define glthread_recursive_lock_destroy_func           libintl_recursive_lock_destroy_func
+#define glthread_once_func            libintl_once_func
+#define glthread_once_singlethreaded  libintl_once_singlethreaded
+#define glthread_once_multithreaded   libintl_once_multithreaded
+])
+])
+
+
+dnl Checks for the core files of the intl subdirectory:
+dnl   dcigettext.c
+dnl   eval-plural.h
+dnl   explodename.c
+dnl   finddomain.c
+dnl   gettextP.h
+dnl   gmo.h
+dnl   hash-string.h hash-string.c
+dnl   l10nflist.c
+dnl   libgnuintl.h.in (except the *printf stuff)
+dnl   loadinfo.h
+dnl   loadmsgcat.c
+dnl   localealias.c
+dnl   log.c
+dnl   plural-exp.h plural-exp.c
+dnl   plural.y
+dnl Used by libglocale.
+AC_DEFUN([gt_INTL_SUBDIR_CORE],
+[
+  AC_REQUIRE([AC_C_INLINE])dnl
+  AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+  AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+  AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+  AC_REQUIRE([AC_FUNC_MMAP])dnl
+  AC_REQUIRE([gt_INTDIV0])dnl
+  AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl
+  AC_REQUIRE([gt_INTTYPES_PRI])dnl
+  AC_REQUIRE([gl_LOCK])dnl
+
+  AC_TRY_LINK(
+    [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }],
+    [],
+    [AC_DEFINE([HAVE_BUILTIN_EXPECT], [1],
+       [Define to 1 if the compiler understands __builtin_expect.])])
+
+  AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h])
+  AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \
+    stpcpy strcasecmp strdup strtoul tsearch uselocale argz_count \
+    argz_stringify argz_next __fsetlocking])
+
+  dnl Use the *_unlocked functions only if they are declared.
+  dnl (because some of them were defined without being declared in Solaris
+  dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built
+  dnl on Solaris 2.5.1 to run on Solaris 2.6).
+  dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13.
+  gt_CHECK_DECL([feof_unlocked], [#include <stdio.h>])
+  gt_CHECK_DECL([fgets_unlocked], [#include <stdio.h>])
+
+  AM_ICONV
+
+  dnl intl/plural.c is generated from intl/plural.y. It requires bison,
+  dnl because plural.y uses bison specific features. It requires at least
+  dnl bison-1.26 because earlier versions generate a plural.c that doesn't
+  dnl compile.
+  dnl bison is only needed for the maintainer (who touches plural.y). But in
+  dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put
+  dnl the rule in general Makefile. Now, some people carelessly touch the
+  dnl files or have a broken "make" program, hence the plural.c rule will
+  dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not
+  dnl present or too old.
+  AC_CHECK_PROGS([INTLBISON], [bison])
+  if test -z "$INTLBISON"; then
+    ac_verc_fail=yes
+  else
+    dnl Found it, now check the version.
+    AC_MSG_CHECKING([version of bison])
+changequote(<<,>>)dnl
+    ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+    case $ac_prog_version in
+      '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+      1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*)
+changequote([,])dnl
+         ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+      *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+    esac
+    AC_MSG_RESULT([$ac_prog_version])
+  fi
+  if test $ac_verc_fail = yes; then
+    INTLBISON=:
+  fi
+])
+
+
+dnl gt_CHECK_DECL(FUNC, INCLUDES)
+dnl Check whether a function is declared.
+AC_DEFUN([gt_CHECK_DECL],
+[
+  AC_CACHE_CHECK([whether $1 is declared], [ac_cv_have_decl_$1],
+    [AC_TRY_COMPILE([$2], [
+#ifndef $1
+  char *p = (char *) $1;
+#endif
+], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)])
+  if test $ac_cv_have_decl_$1 = yes; then
+    gt_value=1
+  else
+    gt_value=0
+  fi
+  AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value],
+    [Define to 1 if you have the declaration of `$1', and to 0 if you don't.])
+])
diff --git a/package/libs/gettext/src/m4/intldir.m4 b/package/libs/gettext/src/m4/intldir.m4
new file mode 100644
index 0000000000..ebae76d361
--- /dev/null
+++ b/package/libs/gettext/src/m4/intldir.m4
@@ -0,0 +1,19 @@
+# intldir.m4 serial 2 (gettext-0.18)
+dnl Copyright (C) 2006, 2009-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+AC_PREREQ([2.52])
+
+dnl Tells the AM_GNU_GETTEXT macro to consider an intl/ directory.
+AC_DEFUN([AM_GNU_GETTEXT_INTL_SUBDIR], [])
diff --git a/package/libs/gettext/src/m4/intlmacosx.m4 b/package/libs/gettext/src/m4/intlmacosx.m4
new file mode 100644
index 0000000000..dd91025962
--- /dev/null
+++ b/package/libs/gettext/src/m4/intlmacosx.m4
@@ -0,0 +1,51 @@
+# intlmacosx.m4 serial 3 (gettext-0.18)
+dnl Copyright (C) 2004-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Checks for special options needed on MacOS X.
+dnl Defines INTL_MACOSX_LIBS.
+AC_DEFUN([gt_INTL_MACOSX],
+[
+  dnl Check for API introduced in MacOS X 10.2.
+  AC_CACHE_CHECK([for CFPreferencesCopyAppValue],
+    [gt_cv_func_CFPreferencesCopyAppValue],
+    [gt_save_LIBS="$LIBS"
+     LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
+     AC_TRY_LINK([#include <CoreFoundation/CFPreferences.h>],
+       [CFPreferencesCopyAppValue(NULL, NULL)],
+       [gt_cv_func_CFPreferencesCopyAppValue=yes],
+       [gt_cv_func_CFPreferencesCopyAppValue=no])
+     LIBS="$gt_save_LIBS"])
+  if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then
+    AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], [1],
+      [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.])
+  fi
+  dnl Check for API introduced in MacOS X 10.3.
+  AC_CACHE_CHECK([for CFLocaleCopyCurrent], [gt_cv_func_CFLocaleCopyCurrent],
+    [gt_save_LIBS="$LIBS"
+     LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
+     AC_TRY_LINK([#include <CoreFoundation/CFLocale.h>], [CFLocaleCopyCurrent();],
+       [gt_cv_func_CFLocaleCopyCurrent=yes],
+       [gt_cv_func_CFLocaleCopyCurrent=no])
+     LIBS="$gt_save_LIBS"])
+  if test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+    AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], [1],
+      [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.])
+  fi
+  INTL_MACOSX_LIBS=
+  if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then
+    INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation"
+  fi
+  AC_SUBST([INTL_MACOSX_LIBS])
+])
diff --git a/package/libs/gettext/src/m4/lcmessage.m4 b/package/libs/gettext/src/m4/lcmessage.m4
new file mode 100644
index 0000000000..1a705431a9
--- /dev/null
+++ b/package/libs/gettext/src/m4/lcmessage.m4
@@ -0,0 +1,31 @@
+# lcmessage.m4 serial 6 (gettext-0.18)
+dnl Copyright (C) 1995-2002, 2004-2005, 2008-2010 Free Software Foundation,
+dnl Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995.
+
+# Check whether LC_MESSAGES is available in <locale.h>.
+
+AC_DEFUN([gt_LC_MESSAGES],
+[
+  AC_CACHE_CHECK([for LC_MESSAGES], [gt_cv_val_LC_MESSAGES],
+    [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+       [gt_cv_val_LC_MESSAGES=yes], [gt_cv_val_LC_MESSAGES=no])])
+  if test $gt_cv_val_LC_MESSAGES = yes; then
+    AC_DEFINE([HAVE_LC_MESSAGES], [1],
+      [Define if your <locale.h> file defines LC_MESSAGES.])
+  fi
+])
diff --git a/package/libs/gettext/src/m4/nls.m4 b/package/libs/gettext/src/m4/nls.m4
new file mode 100644
index 0000000000..003704c4b9
--- /dev/null
+++ b/package/libs/gettext/src/m4/nls.m4
@@ -0,0 +1,32 @@
+# nls.m4 serial 5 (gettext-0.18)
+dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation,
+dnl Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+AC_PREREQ([2.50])
+
+AC_DEFUN([AM_NLS],
+[
+  AC_MSG_CHECKING([whether NLS is requested])
+  dnl Default is enabled NLS
+  AC_ARG_ENABLE([nls],
+    [  --disable-nls           do not use Native Language Support],
+    USE_NLS=$enableval, USE_NLS=yes)
+  AC_MSG_RESULT([$USE_NLS])
+  AC_SUBST([USE_NLS])
+])
diff --git a/package/libs/gettext/src/m4/po.m4 b/package/libs/gettext/src/m4/po.m4
new file mode 100644
index 0000000000..47f36a41a0
--- /dev/null
+++ b/package/libs/gettext/src/m4/po.m4
@@ -0,0 +1,449 @@
+# po.m4 serial 17 (gettext-0.18)
+dnl Copyright (C) 1995-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1995-2000.
+dnl   Bruno Haible <haible@clisp.cons.org>, 2000-2003.
+
+AC_PREREQ([2.50])
+
+dnl Checks for all prerequisites of the po subdirectory.
+AC_DEFUN([AM_PO_SUBDIRS],
+[
+  AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+  AC_REQUIRE([AC_PROG_INSTALL])dnl
+  AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake
+  AC_REQUIRE([AM_NLS])dnl
+
+  dnl Release version of the gettext macros. This is used to ensure that
+  dnl the gettext macros and po/Makefile.in.in are in sync.
+  AC_SUBST([GETTEXT_MACRO_VERSION], [0.18])
+
+  dnl Perform the following tests also if --disable-nls has been given,
+  dnl because they are needed for "make dist" to work.
+
+  dnl Search for GNU msgfmt in the PATH.
+  dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions.
+  dnl The second test excludes FreeBSD msgfmt.
+  AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+    [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
+     (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
+    :)
+  AC_PATH_PROG([GMSGFMT], [gmsgfmt], [$MSGFMT])
+
+  dnl Test whether it is GNU msgfmt >= 0.15.
+changequote(,)dnl
+  case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
+    '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;;
+    *) MSGFMT_015=$MSGFMT ;;
+  esac
+changequote([,])dnl
+  AC_SUBST([MSGFMT_015])
+changequote(,)dnl
+  case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
+    '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;;
+    *) GMSGFMT_015=$GMSGFMT ;;
+  esac
+changequote([,])dnl
+  AC_SUBST([GMSGFMT_015])
+
+  dnl Search for GNU xgettext 0.12 or newer in the PATH.
+  dnl The first test excludes Solaris xgettext and early GNU xgettext versions.
+  dnl The second test excludes FreeBSD xgettext.
+  AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+    [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
+     (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
+    :)
+  dnl Remove leftover from FreeBSD xgettext call.
+  rm -f messages.po
+
+  dnl Test whether it is GNU xgettext >= 0.15.
+changequote(,)dnl
+  case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
+    '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;;
+    *) XGETTEXT_015=$XGETTEXT ;;
+  esac
+changequote([,])dnl
+  AC_SUBST([XGETTEXT_015])
+
+  dnl Search for GNU msgmerge 0.11 or newer in the PATH.
+  AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge,
+    [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :)
+
+  dnl Installation directories.
+  dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we
+  dnl have to define it here, so that it can be used in po/Makefile.
+  test -n "$localedir" || localedir='${datadir}/locale'
+  AC_SUBST([localedir])
+
+  dnl Support for AM_XGETTEXT_OPTION.
+  test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS=
+  AC_SUBST([XGETTEXT_EXTRA_OPTIONS])
+
+  AC_CONFIG_COMMANDS([po-directories], [[
+    for ac_file in $CONFIG_FILES; do
+      # Support "outfile[:infile[:infile...]]"
+      case "$ac_file" in
+        *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+      esac
+      # PO directories have a Makefile.in generated from Makefile.in.in.
+      case "$ac_file" in */Makefile.in)
+        # Adjust a relative srcdir.
+        ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+        ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+        ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+        # In autoconf-2.13 it is called $ac_given_srcdir.
+        # In autoconf-2.50 it is called $srcdir.
+        test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+        case "$ac_given_srcdir" in
+          .)  top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+          /*) top_srcdir="$ac_given_srcdir" ;;
+          *)  top_srcdir="$ac_dots$ac_given_srcdir" ;;
+        esac
+        # Treat a directory as a PO directory if and only if it has a
+        # POTFILES.in file. This allows packages to have multiple PO
+        # directories under different names or in different locations.
+        if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then
+          rm -f "$ac_dir/POTFILES"
+          test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES"
+          cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ 	]*\$/d" -e "s,.*,     $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES"
+          POMAKEFILEDEPS="POTFILES.in"
+          # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend
+          # on $ac_dir but don't depend on user-specified configuration
+          # parameters.
+          if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+            # The LINGUAS file contains the set of available languages.
+            if test -n "$OBSOLETE_ALL_LINGUAS"; then
+              test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+            fi
+            ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+            # Hide the ALL_LINGUAS assigment from automake < 1.5.
+            eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+            POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+          else
+            # The set of available languages was given in configure.in.
+            # Hide the ALL_LINGUAS assigment from automake < 1.5.
+            eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
+          fi
+          # Compute POFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+          # Compute UPDATEPOFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+          # Compute DUMMYPOFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+          # Compute GMOFILES
+          # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+          case "$ac_given_srcdir" in
+            .) srcdirpre= ;;
+            *) srcdirpre='$(srcdir)/' ;;
+          esac
+          POFILES=
+          UPDATEPOFILES=
+          DUMMYPOFILES=
+          GMOFILES=
+          for lang in $ALL_LINGUAS; do
+            POFILES="$POFILES $srcdirpre$lang.po"
+            UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+            DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+            GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+          done
+          # CATALOGS depends on both $ac_dir and the user's LINGUAS
+          # environment variable.
+          INST_LINGUAS=
+          if test -n "$ALL_LINGUAS"; then
+            for presentlang in $ALL_LINGUAS; do
+              useit=no
+              if test "%UNSET%" != "$LINGUAS"; then
+                desiredlanguages="$LINGUAS"
+              else
+                desiredlanguages="$ALL_LINGUAS"
+              fi
+              for desiredlang in $desiredlanguages; do
+                # Use the presentlang catalog if desiredlang is
+                #   a. equal to presentlang, or
+                #   b. a variant of presentlang (because in this case,
+                #      presentlang can be used as a fallback for messages
+                #      which are not translated in the desiredlang catalog).
+                case "$desiredlang" in
+                  "$presentlang"*) useit=yes;;
+                esac
+              done
+              if test $useit = yes; then
+                INST_LINGUAS="$INST_LINGUAS $presentlang"
+              fi
+            done
+          fi
+          CATALOGS=
+          if test -n "$INST_LINGUAS"; then
+            for lang in $INST_LINGUAS; do
+              CATALOGS="$CATALOGS $lang.gmo"
+            done
+          fi
+          test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile"
+          sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile"
+          for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do
+            if test -f "$f"; then
+              case "$f" in
+                *.orig | *.bak | *~) ;;
+                *) cat "$f" >> "$ac_dir/Makefile" ;;
+              esac
+            fi
+          done
+        fi
+        ;;
+      esac
+    done]],
+   [# Capture the value of obsolete ALL_LINGUAS because we need it to compute
+    # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it
+    # from automake < 1.5.
+    eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
+    # Capture the value of LINGUAS because we need it to compute CATALOGS.
+    LINGUAS="${LINGUAS-%UNSET%}"
+   ])
+])
+
+dnl Postprocesses a Makefile in a directory containing PO files.
+AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE],
+[
+  # When this code is run, in config.status, two variables have already been
+  # set:
+  # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in,
+  # - LINGUAS is the value of the environment variable LINGUAS at configure
+  #   time.
+
+changequote(,)dnl
+  # Adjust a relative srcdir.
+  ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
+  ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
+  ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
+  # In autoconf-2.13 it is called $ac_given_srcdir.
+  # In autoconf-2.50 it is called $srcdir.
+  test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
+  case "$ac_given_srcdir" in
+    .)  top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
+    /*) top_srcdir="$ac_given_srcdir" ;;
+    *)  top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  # Find a way to echo strings without interpreting backslash.
+  if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then
+    gt_echo='echo'
+  else
+    if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then
+      gt_echo='printf %s\n'
+    else
+      echo_func () {
+        cat <<EOT
+$*
+EOT
+      }
+      gt_echo='echo_func'
+    fi
+  fi
+
+  # A sed script that extracts the value of VARIABLE from a Makefile.
+  sed_x_variable='
+# Test if the hold space is empty.
+x
+s/P/P/
+x
+ta
+# Yes it was empty. Look if we have the expected variable definition.
+/^[	 ]*VARIABLE[	 ]*=/{
+  # Seen the first line of the variable definition.
+  s/^[	 ]*VARIABLE[	 ]*=//
+  ba
+}
+bd
+:a
+# Here we are processing a line from the variable definition.
+# Remove comment, more precisely replace it with a space.
+s/#.*$/ /
+# See if the line ends in a backslash.
+tb
+:b
+s/\\$//
+# Print the line, without the trailing backslash.
+p
+tc
+# There was no trailing backslash. The end of the variable definition is
+# reached. Clear the hold space.
+s/^.*$//
+x
+bd
+:c
+# A trailing backslash means that the variable definition continues in the
+# next line. Put a nonempty string into the hold space to indicate this.
+s/^.*$/P/
+x
+:d
+'
+changequote([,])dnl
+
+  # Set POTFILES to the value of the Makefile variable POTFILES.
+  sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'`
+  POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"`
+  # Compute POTFILES_DEPS as
+  #   $(foreach file, $(POTFILES), $(top_srcdir)/$(file))
+  POTFILES_DEPS=
+  for file in $POTFILES; do
+    POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file"
+  done
+  POMAKEFILEDEPS=""
+
+  if test -n "$OBSOLETE_ALL_LINGUAS"; then
+    test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
+  fi
+  if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
+    # The LINGUAS file contains the set of available languages.
+    ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
+    POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
+  else
+    # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS.
+    sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'`
+    ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"`
+  fi
+  # Hide the ALL_LINGUAS assigment from automake < 1.5.
+  eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
+  # Compute POFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
+  # Compute UPDATEPOFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
+  # Compute DUMMYPOFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
+  # Compute GMOFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
+  # Compute PROPERTIESFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties)
+  # Compute CLASSFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class)
+  # Compute QMFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm)
+  # Compute MSGFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg)
+  # Compute RESOURCESDLLFILES
+  # as      $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll)
+  case "$ac_given_srcdir" in
+    .) srcdirpre= ;;
+    *) srcdirpre='$(srcdir)/' ;;
+  esac
+  POFILES=
+  UPDATEPOFILES=
+  DUMMYPOFILES=
+  GMOFILES=
+  PROPERTIESFILES=
+  CLASSFILES=
+  QMFILES=
+  MSGFILES=
+  RESOURCESDLLFILES=
+  for lang in $ALL_LINGUAS; do
+    POFILES="$POFILES $srcdirpre$lang.po"
+    UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
+    DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
+    GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
+    PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties"
+    CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class"
+    QMFILES="$QMFILES $srcdirpre$lang.qm"
+    frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+    MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg"
+    frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+    RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll"
+  done
+  # CATALOGS depends on both $ac_dir and the user's LINGUAS
+  # environment variable.
+  INST_LINGUAS=
+  if test -n "$ALL_LINGUAS"; then
+    for presentlang in $ALL_LINGUAS; do
+      useit=no
+      if test "%UNSET%" != "$LINGUAS"; then
+        desiredlanguages="$LINGUAS"
+      else
+        desiredlanguages="$ALL_LINGUAS"
+      fi
+      for desiredlang in $desiredlanguages; do
+        # Use the presentlang catalog if desiredlang is
+        #   a. equal to presentlang, or
+        #   b. a variant of presentlang (because in this case,
+        #      presentlang can be used as a fallback for messages
+        #      which are not translated in the desiredlang catalog).
+        case "$desiredlang" in
+          "$presentlang"*) useit=yes;;
+        esac
+      done
+      if test $useit = yes; then
+        INST_LINGUAS="$INST_LINGUAS $presentlang"
+      fi
+    done
+  fi
+  CATALOGS=
+  JAVACATALOGS=
+  QTCATALOGS=
+  TCLCATALOGS=
+  CSHARPCATALOGS=
+  if test -n "$INST_LINGUAS"; then
+    for lang in $INST_LINGUAS; do
+      CATALOGS="$CATALOGS $lang.gmo"
+      JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties"
+      QTCATALOGS="$QTCATALOGS $lang.qm"
+      frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+      TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg"
+      frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+      CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll"
+    done
+  fi
+
+  sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp"
+  if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then
+    # Add dependencies that cannot be formulated as a simple suffix rule.
+    for lang in $ALL_LINGUAS; do
+      frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
+      cat >> "$ac_file.tmp" <<EOF
+$frobbedlang.msg: $lang.po
+	@echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \
+	\$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+    done
+  fi
+  if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then
+    # Add dependencies that cannot be formulated as a simple suffix rule.
+    for lang in $ALL_LINGUAS; do
+      frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
+      cat >> "$ac_file.tmp" <<EOF
+$frobbedlang/\$(DOMAIN).resources.dll: $lang.po
+	@echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \
+	\$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; }
+EOF
+    done
+  fi
+  if test -n "$POMAKEFILEDEPS"; then
+    cat >> "$ac_file.tmp" <<EOF
+Makefile: $POMAKEFILEDEPS
+EOF
+  fi
+  mv "$ac_file.tmp" "$ac_file"
+])
+
+dnl Initializes the accumulator used by AM_XGETTEXT_OPTION.
+AC_DEFUN([AM_XGETTEXT_OPTION_INIT],
+[
+  XGETTEXT_EXTRA_OPTIONS=
+])
+
+dnl Registers an option to be passed to xgettext in the po subdirectory.
+AC_DEFUN([AM_XGETTEXT_OPTION],
+[
+  AC_REQUIRE([AM_XGETTEXT_OPTION_INIT])
+  XGETTEXT_EXTRA_OPTIONS="$XGETTEXT_EXTRA_OPTIONS $1"
+])
diff --git a/package/libs/gmp/Makefile b/package/libs/gmp/Makefile
new file mode 100644
index 0000000000..5c2d96aa81
--- /dev/null
+++ b/package/libs/gmp/Makefile
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gmp
+PKG_VERSION:=6.1.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)$(PKG_REVISION).tar.xz
+PKG_SOURCE_URL:=@GNU/gmp/
+PKG_MD5SUM:=e70e183609244a332d80529e7e155a35
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+PKG_USE_MIPS16:=0
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libgmp
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=GNU multiprecision arithmetic library
+  URL:=http://gmplib.org/
+endef
+
+define Package/libgmp/description
+	GMP is a free library for arbitrary precision arithmetic, operating on
+	signed integers, rational numbers, and floating point numbers.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+CONFIGURE_VARS += CC="$(TARGET_CROSS)gcc"
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--without-readline \
+	--disable-fft \
+
+define Build/Compile
+	$(call Build/Compile/Default, \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CC="$(TARGET_CC)" \
+		all \
+	)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/gmp* $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libgmp.{a,so*} $(1)/usr/lib/
+endef
+
+define Package/libgmp/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libgmp.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libgmp))
+$(eval $(call HostBuild))
diff --git a/package/libs/libbsd/Makefile b/package/libs/libbsd/Makefile
new file mode 100644
index 0000000000..ca5e76179f
--- /dev/null
+++ b/package/libs/libbsd/Makefile
@@ -0,0 +1,57 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libbsd
+PKG_VERSION:=0.3.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://libbsd.freedesktop.org/releases
+#PKG_MD5SUM:=d0870f2de55d59c1c8419f36e8fac150
+
+PKG_LICENSE:=BSD-4-Clause
+PKG_LICENSE_FILES:=COPYING
+
+include $(INCLUDE_DIR)/package.mk
+
+PKG_INSTALL:=1
+
+define Package/libbsd
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=@USE_GLIBC
+  TITLE:=common BSD library
+endef
+
+define Package/libbsd/description
+ This library provides useful functions commonly found on BSD systems, and lacking on others like GNU systems, thus making it easier to port projects with strong BSD origins, without needing to embed the same code over and over again on each project.
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) \
+		$(1)/lib \
+		$(1)/usr/include
+
+	$(CP) \
+		$(PKG_INSTALL_DIR)/lib/libbsd.so* \
+		$(1)/lib/
+
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/* \
+		$(1)/usr/include/
+
+	( cd $(1)/lib ; $(LN) libbsd.so.$(PKG_VERSION) libbsd.so )
+endef
+
+define Package/libbsd/install
+	$(INSTALL_DIR) \
+		$(1)/lib
+
+	$(CP) \
+		$(PKG_INSTALL_DIR)/lib/libbsd.so* \
+		$(1)/lib/
+
+	( cd $(1)/lib ; $(LN) libbsd.so.$(PKG_VERSION) libbsd.so )
+endef
+
+$(eval $(call BuildPackage,libbsd))
+
diff --git a/package/libs/libbsd/patches/001-aarch64_support.patch b/package/libs/libbsd/patches/001-aarch64_support.patch
new file mode 100644
index 0000000000..62291482c7
--- /dev/null
+++ b/package/libs/libbsd/patches/001-aarch64_support.patch
@@ -0,0 +1,19 @@
+--- a/src/local-elf.h
++++ b/src/local-elf.h
+@@ -165,6 +165,16 @@
+ #endif
+ #define ELF_TARG_DATA	ELFDATA2MSB
+ 
++#elif defined(__aarch64__)
++
++#define ELF_TARG_MACH	EM_AARCH64
++#define ELF_TARG_CLASS	ELFCLASS64
++#ifdef __AARCH64EB__
++#define ELF_TARG_DATA	ELFDATA2MSB
++#else
++#define ELF_TARG_DATA	ELFDATA2LSB
++#endif
++
+ #else
+ 
+ #error Unknown ELF machine type
diff --git a/package/libs/libconfig/Makefile b/package/libs/libconfig/Makefile
new file mode 100644
index 0000000000..18325479cf
--- /dev/null
+++ b/package/libs/libconfig/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2008-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libconfig
+PKG_VERSION:=1.5
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.hyperrealm.com/libconfig
+PKG_MD5SUM:=e31daa390d8e4461c8830512fe2e13ba1a3d6a02a2305a02429eec61e68703f6
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=LGPL-2.1+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libconfig
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Configuration File Library
+  URL:=http://www.hyperrealm.com/libconfig/
+endef
+
+define Package/libconfig/description
+ Libconfig is a simple library for manipulating structured configuration
+ files. This file format is more compact and more readable than XML. And
+ unlike XML, it is type-aware, so it is not necessary to do string
+ parsing in application code.
+
+ Libconfig is very compact -- just 38K for the stripped C shared
+ library (less than one-fourth the size of the expat XML parser library)
+ and 66K for the stripped C++ shared library. This makes it well-suited
+ for memory-constrained systems like handheld devices.
+endef
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--disable-static \
+	--disable-cxx
+
+define Build/InstallDev
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+endef
+
+define Package/libconfig/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libconfig.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libconfig))
diff --git a/package/libs/libevent2/Makefile b/package/libs/libevent2/Makefile
new file mode 100644
index 0000000000..375bc8c888
--- /dev/null
+++ b/package/libs/libevent2/Makefile
@@ -0,0 +1,157 @@
+#
+# Copyright (C) 2011-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libevent2
+PKG_VERSION:=2.0.22
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/libevent-$(PKG_VERSION)-stable
+PKG_SOURCE:=libevent-$(PKG_VERSION)-stable.tar.gz
+PKG_SOURCE_URL:=@SF/levent
+PKG_MD5SUM:=c4c56f986aa985677ca1db89630a2e11
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=BSD-3-Clause
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libevent2/Default
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Event notification
+  URL:=http://www.monkey.org/~provos/libevent/
+endef
+
+define Package/libevent2/Default/description
+	The libevent API provides a mechanism to execute a callback function
+	when a specific event occurs on a file descriptor or after a timeout
+	has been reached. Furthermore, libevent also support callbacks due
+	to signals or regular timeouts.
+
+	libevent is meant to replace the event loop found in event driven
+	network servers. An application just needs to call event_dispatch()
+	and then add or remove events dynamically without having to change
+	the event loop.
+endef
+
+define Package/libevent2
+  $(call Package/libevent2/Default)
+  TITLE+= library (version 2.0)
+endef
+
+define Package/libevent2/description
+	$(call Package/libevent2/Default/description)
+
+	This package contains the libevent shared library historically
+	containing both the core & extra libraries.
+endef
+
+define Package/libevent2-core
+  $(call Package/libevent2/Default)
+  TITLE+= core library (version 2.0)
+endef
+
+define Package/libevent2-core/description
+	$(call Package/libevent2/Default/description)
+
+	This package contains the libevent core shared library for the event,
+	buffer & utility functions.
+endef
+
+define Package/libevent2-extra
+  $(call Package/libevent2/Default)
+  TITLE+= extra library (version 2.0)
+endef
+
+define Package/libevent2-extra/description
+	$(call Package/libevent2/Default/description)
+
+	This package contains the libevent extra shared library for specific
+	protocols including HTTP, DNS & RPC.
+endef
+
+define Package/libevent2-openssl
+  $(call Package/libevent2/Default)
+  TITLE+= OpenSSL library (version 2.0)
+  DEPENDS+=+libopenssl
+endef
+
+define Package/libevent2-openssl/description
+	$(call Package/libevent2/Default/description)
+
+	This package contains the libevent OpenSSL shared library for encrypted
+	bufferevents.
+endef
+
+define Package/libevent2-pthreads
+  $(call Package/libevent2/Default)
+  TITLE+= Pthreads library (version 2.0)
+  DEPENDS+=+libpthread
+endef
+
+define Package/libevent2-pthreads/description
+	$(call Package/libevent2/Default/description)
+
+	This package contains the libevent Pthreads shared library for
+	threading & locking.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--disable-debug-mode
+
+MAKE_FLAGS += \
+	CFLAGS="$(TARGET_CFLAGS)"
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent*.{la,a,so} $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent*-2.0.so* $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libevent*.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libevent2/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent-2.0.so.* $(1)/usr/lib/
+endef
+
+define Package/libevent2-core/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent_core-2.0.so.* $(1)/usr/lib/
+endef
+
+define Package/libevent2-extra/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent_extra-2.0.so.* $(1)/usr/lib/
+endef
+
+define Package/libevent2-openssl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent_openssl-2.0.so.* $(1)/usr/lib/
+endef
+
+define Package/libevent2-pthreads/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libevent_pthreads-2.0.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libevent2))
+$(eval $(call BuildPackage,libevent2-core))
+$(eval $(call BuildPackage,libevent2-extra))
+$(eval $(call BuildPackage,libevent2-openssl))
+$(eval $(call BuildPackage,libevent2-pthreads))
diff --git a/package/libs/libiconv-full/Makefile b/package/libs/libiconv-full/Makefile
new file mode 100644
index 0000000000..4327321e18
--- /dev/null
+++ b/package/libs/libiconv-full/Makefile
@@ -0,0 +1,95 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libiconv-full
+PKG_VERSION:=1.11.1
+PKG_RELEASE:=3
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+PKG_SOURCE:=libiconv-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/libiconv
+PKG_MD5SUM:=d42b97f6ef5dd0ba4469d520ed732fed
+PKG_BUILD_DIR:=$(BUILD_DIR)/libiconv-$(PKG_VERSION)
+PKG_LICENSE:=LGPL-2.0
+PKG_LICENSE_FILES:=COPYING.LIB
+
+PKG_FIXUP:=patch-libtool
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libiconv-full/Default
+  URL:=http://www.gnu.org/software/libiconv/
+  TITLE:=Character set conversion
+endef
+
+define Package/libiconv-full
+  $(call Package/libiconv-full/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= library
+endef
+
+define Package/libcharset
+  $(call Package/libiconv-full/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= library
+endef
+
+define Package/iconv
+  $(call Package/libiconv-full/Default)
+  DEPENDS:=+libiconv-full +libcharset
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE+= utility
+endef
+
+TARGET_CFLAGS += $(FPIC) -DUSE_DOS
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--disable-rpath \
+	--enable-relocatable
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		install
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/libiconv-full/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/iconv.h $(1)/usr/lib/libiconv-full/include/
+
+	$(INSTALL_DIR) $(1)/usr/lib/libiconv-full/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libcharset.{a,so*} $(1)/usr/lib/libiconv-full/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libiconv.{a,so*} $(1)/usr/lib/libiconv-full/lib/
+endef
+
+define Package/libcharset/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libcharset.so* $(1)/usr/lib/
+endef
+
+define Package/libiconv-full/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libiconv.so* $(1)/usr/lib/
+endef
+
+define Package/iconv/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/iconv $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,libcharset))
+$(eval $(call BuildPackage,libiconv-full))
+$(eval $(call BuildPackage,iconv))
diff --git a/package/libs/libiconv-full/patches/100-strip_charsets.patch b/package/libs/libiconv-full/patches/100-strip_charsets.patch
new file mode 100644
index 0000000000..e4f49aec46
--- /dev/null
+++ b/package/libs/libiconv-full/patches/100-strip_charsets.patch
@@ -0,0 +1,3438 @@
+--- a/lib/aliases_dos.h
++++ b/lib/aliases_dos.h
+@@ -2,47 +2,3 @@
+   S(dos_1, "IBM437", ei_cp437 )
+   S(dos_2, "437", ei_cp437 )
+   S(dos_3, "CSPC8CODEPAGE437", ei_cp437 )
+-  S(dos_4, "CP737", ei_cp737 )
+-  S(dos_5, "CP775", ei_cp775 )
+-  S(dos_6, "IBM775", ei_cp775 )
+-  S(dos_7, "CSPC775BALTIC", ei_cp775 )
+-  S(dos_8, "CP852", ei_cp852 )
+-  S(dos_9, "IBM852", ei_cp852 )
+-  S(dos_10, "852", ei_cp852 )
+-  S(dos_11, "CSPCP852", ei_cp852 )
+-  S(dos_12, "CP853", ei_cp853 )
+-  S(dos_13, "CP855", ei_cp855 )
+-  S(dos_14, "IBM855", ei_cp855 )
+-  S(dos_15, "855", ei_cp855 )
+-  S(dos_16, "CSIBM855", ei_cp855 )
+-  S(dos_17, "CP857", ei_cp857 )
+-  S(dos_18, "IBM857", ei_cp857 )
+-  S(dos_19, "857", ei_cp857 )
+-  S(dos_20, "CSIBM857", ei_cp857 )
+-  S(dos_21, "CP858", ei_cp858 )
+-  S(dos_22, "CP860", ei_cp860 )
+-  S(dos_23, "IBM860", ei_cp860 )
+-  S(dos_24, "860", ei_cp860 )
+-  S(dos_25, "CSIBM860", ei_cp860 )
+-  S(dos_26, "CP861", ei_cp861 )
+-  S(dos_27, "IBM861", ei_cp861 )
+-  S(dos_28, "861", ei_cp861 )
+-  S(dos_29, "CP-IS", ei_cp861 )
+-  S(dos_30, "CSIBM861", ei_cp861 )
+-  S(dos_31, "CP863", ei_cp863 )
+-  S(dos_32, "IBM863", ei_cp863 )
+-  S(dos_33, "863", ei_cp863 )
+-  S(dos_34, "CSIBM863", ei_cp863 )
+-  S(dos_35, "CP864", ei_cp864 )
+-  S(dos_36, "IBM864", ei_cp864 )
+-  S(dos_37, "CSIBM864", ei_cp864 )
+-  S(dos_38, "CP865", ei_cp865 )
+-  S(dos_39, "IBM865", ei_cp865 )
+-  S(dos_40, "865", ei_cp865 )
+-  S(dos_41, "CSIBM865", ei_cp865 )
+-  S(dos_42, "CP869", ei_cp869 )
+-  S(dos_43, "IBM869", ei_cp869 )
+-  S(dos_44, "869", ei_cp869 )
+-  S(dos_45, "CP-GR", ei_cp869 )
+-  S(dos_46, "CSIBM869", ei_cp869 )
+-  S(dos_47, "CP1125", ei_cp1125 )
+--- a/lib/aliases.gperf
++++ b/lib/aliases.gperf
+@@ -48,8 +48,6 @@ UCS-2-INTERNAL, ei_ucs2internal
+ UCS-2-SWAPPED, ei_ucs2swapped
+ UCS-4-INTERNAL, ei_ucs4internal
+ UCS-4-SWAPPED, ei_ucs4swapped
+-C99, ei_c99
+-JAVA, ei_java
+ ISO-8859-1, ei_iso8859_1
+ ISO_8859-1, ei_iso8859_1
+ ISO_8859-1:1987, ei_iso8859_1
+@@ -68,285 +66,16 @@ LATIN2, ei_iso8859_2
+ L2, ei_iso8859_2
+ CSISOLATIN2, ei_iso8859_2
+ ISO8859-2, ei_iso8859_2
+-ISO-8859-3, ei_iso8859_3
+-ISO_8859-3, ei_iso8859_3
+-ISO_8859-3:1988, ei_iso8859_3
+-ISO-IR-109, ei_iso8859_3
+-LATIN3, ei_iso8859_3
+-L3, ei_iso8859_3
+-CSISOLATIN3, ei_iso8859_3
+-ISO8859-3, ei_iso8859_3
+-ISO-8859-4, ei_iso8859_4
+-ISO_8859-4, ei_iso8859_4
+-ISO_8859-4:1988, ei_iso8859_4
+-ISO-IR-110, ei_iso8859_4
+-LATIN4, ei_iso8859_4
+-L4, ei_iso8859_4
+-CSISOLATIN4, ei_iso8859_4
+-ISO8859-4, ei_iso8859_4
+-ISO-8859-5, ei_iso8859_5
+-ISO_8859-5, ei_iso8859_5
+-ISO_8859-5:1988, ei_iso8859_5
+-ISO-IR-144, ei_iso8859_5
+-CYRILLIC, ei_iso8859_5
+-CSISOLATINCYRILLIC, ei_iso8859_5
+-ISO8859-5, ei_iso8859_5
+-ISO-8859-6, ei_iso8859_6
+-ISO_8859-6, ei_iso8859_6
+-ISO_8859-6:1987, ei_iso8859_6
+-ISO-IR-127, ei_iso8859_6
+-ECMA-114, ei_iso8859_6
+-ASMO-708, ei_iso8859_6
+-ARABIC, ei_iso8859_6
+-CSISOLATINARABIC, ei_iso8859_6
+-ISO8859-6, ei_iso8859_6
+-ISO-8859-7, ei_iso8859_7
+-ISO_8859-7, ei_iso8859_7
+-ISO_8859-7:1987, ei_iso8859_7
+-ISO_8859-7:2003, ei_iso8859_7
+-ISO-IR-126, ei_iso8859_7
+-ECMA-118, ei_iso8859_7
+-ELOT_928, ei_iso8859_7
+-GREEK8, ei_iso8859_7
+-GREEK, ei_iso8859_7
+-CSISOLATINGREEK, ei_iso8859_7
+-ISO8859-7, ei_iso8859_7
+-ISO-8859-8, ei_iso8859_8
+-ISO_8859-8, ei_iso8859_8
+-ISO_8859-8:1988, ei_iso8859_8
+-ISO-IR-138, ei_iso8859_8
+-HEBREW, ei_iso8859_8
+-CSISOLATINHEBREW, ei_iso8859_8
+-ISO8859-8, ei_iso8859_8
+-ISO-8859-9, ei_iso8859_9
+-ISO_8859-9, ei_iso8859_9
+-ISO_8859-9:1989, ei_iso8859_9
+-ISO-IR-148, ei_iso8859_9
+-LATIN5, ei_iso8859_9
+-L5, ei_iso8859_9
+-CSISOLATIN5, ei_iso8859_9
+-ISO8859-9, ei_iso8859_9
+-ISO-8859-10, ei_iso8859_10
+-ISO_8859-10, ei_iso8859_10
+-ISO_8859-10:1992, ei_iso8859_10
+-ISO-IR-157, ei_iso8859_10
+-LATIN6, ei_iso8859_10
+-L6, ei_iso8859_10
+-CSISOLATIN6, ei_iso8859_10
+-ISO8859-10, ei_iso8859_10
+-ISO-8859-11, ei_iso8859_11
+-ISO_8859-11, ei_iso8859_11
+-ISO8859-11, ei_iso8859_11
+-ISO-8859-13, ei_iso8859_13
+-ISO_8859-13, ei_iso8859_13
+-ISO-IR-179, ei_iso8859_13
+-LATIN7, ei_iso8859_13
+-L7, ei_iso8859_13
+-ISO8859-13, ei_iso8859_13
+-ISO-8859-14, ei_iso8859_14
+-ISO_8859-14, ei_iso8859_14
+-ISO_8859-14:1998, ei_iso8859_14
+-ISO-IR-199, ei_iso8859_14
+-LATIN8, ei_iso8859_14
+-L8, ei_iso8859_14
+-ISO-CELTIC, ei_iso8859_14
+-ISO8859-14, ei_iso8859_14
+ ISO-8859-15, ei_iso8859_15
+ ISO_8859-15, ei_iso8859_15
+ ISO_8859-15:1998, ei_iso8859_15
+ ISO-IR-203, ei_iso8859_15
+ LATIN-9, ei_iso8859_15
+ ISO8859-15, ei_iso8859_15
+-ISO-8859-16, ei_iso8859_16
+-ISO_8859-16, ei_iso8859_16
+-ISO_8859-16:2001, ei_iso8859_16
+-ISO-IR-226, ei_iso8859_16
+-LATIN10, ei_iso8859_16
+-L10, ei_iso8859_16
+-ISO8859-16, ei_iso8859_16
+ KOI8-R, ei_koi8_r
+ CSKOI8R, ei_koi8_r
+-KOI8-U, ei_koi8_u
+-KOI8-RU, ei_koi8_ru
+ CP1250, ei_cp1250
+ WINDOWS-1250, ei_cp1250
+ MS-EE, ei_cp1250
+-CP1251, ei_cp1251
+-WINDOWS-1251, ei_cp1251
+-MS-CYRL, ei_cp1251
+-CP1252, ei_cp1252
+-WINDOWS-1252, ei_cp1252
+-MS-ANSI, ei_cp1252
+-CP1253, ei_cp1253
+-WINDOWS-1253, ei_cp1253
+-MS-GREEK, ei_cp1253
+-CP1254, ei_cp1254
+-WINDOWS-1254, ei_cp1254
+-MS-TURK, ei_cp1254
+-CP1255, ei_cp1255
+-WINDOWS-1255, ei_cp1255
+-MS-HEBR, ei_cp1255
+-CP1256, ei_cp1256
+-WINDOWS-1256, ei_cp1256
+-MS-ARAB, ei_cp1256
+-CP1257, ei_cp1257
+-WINDOWS-1257, ei_cp1257
+-WINBALTRIM, ei_cp1257
+-CP1258, ei_cp1258
+-WINDOWS-1258, ei_cp1258
+-CP850, ei_cp850
+-IBM850, ei_cp850
+-850, ei_cp850
+-CSPC850MULTILINGUAL, ei_cp850
+-CP862, ei_cp862
+-IBM862, ei_cp862
+-862, ei_cp862
+-CSPC862LATINHEBREW, ei_cp862
+-CP866, ei_cp866
+-IBM866, ei_cp866
+-866, ei_cp866
+-CSIBM866, ei_cp866
+-MACROMAN, ei_mac_roman
+-MACINTOSH, ei_mac_roman
+-MAC, ei_mac_roman
+-CSMACINTOSH, ei_mac_roman
+-MACCENTRALEUROPE, ei_mac_centraleurope
+-MACICELAND, ei_mac_iceland
+-MACCROATIAN, ei_mac_croatian
+-MACROMANIA, ei_mac_romania
+-MACCYRILLIC, ei_mac_cyrillic
+-MACUKRAINE, ei_mac_ukraine
+-MACGREEK, ei_mac_greek
+-MACTURKISH, ei_mac_turkish
+-MACHEBREW, ei_mac_hebrew
+-MACARABIC, ei_mac_arabic
+-MACTHAI, ei_mac_thai
+-HP-ROMAN8, ei_hp_roman8
+-ROMAN8, ei_hp_roman8
+-R8, ei_hp_roman8
+-CSHPROMAN8, ei_hp_roman8
+-NEXTSTEP, ei_nextstep
+-ARMSCII-8, ei_armscii_8
+-GEORGIAN-ACADEMY, ei_georgian_academy
+-GEORGIAN-PS, ei_georgian_ps
+-KOI8-T, ei_koi8_t
+-PT154, ei_pt154
+-PTCP154, ei_pt154
+-CP154, ei_pt154
+-CYRILLIC-ASIAN, ei_pt154
+-CSPTCP154, ei_pt154
+-MULELAO-1, ei_mulelao
+-CP1133, ei_cp1133
+-IBM-CP1133, ei_cp1133
+-TIS-620, ei_tis620
+-TIS620, ei_tis620
+-TIS620-0, ei_tis620
+-TIS620.2529-1, ei_tis620
+-TIS620.2533-0, ei_tis620
+-TIS620.2533-1, ei_tis620
+-ISO-IR-166, ei_tis620
+-CP874, ei_cp874
+-WINDOWS-874, ei_cp874
+-VISCII, ei_viscii
+-VISCII1.1-1, ei_viscii
+-CSVISCII, ei_viscii
+-TCVN, ei_tcvn
+-TCVN-5712, ei_tcvn
+-TCVN5712-1, ei_tcvn
+-TCVN5712-1:1993, ei_tcvn
+-JIS_C6220-1969-RO, ei_iso646_jp
+-ISO646-JP, ei_iso646_jp
+-ISO-IR-14, ei_iso646_jp
+-JP, ei_iso646_jp
+-CSISO14JISC6220RO, ei_iso646_jp
+-JIS_X0201, ei_jisx0201
+-JISX0201-1976, ei_jisx0201
+-X0201, ei_jisx0201
+-CSHALFWIDTHKATAKANA, ei_jisx0201
+-JIS_X0208, ei_jisx0208
+-JIS_X0208-1983, ei_jisx0208
+-JIS_X0208-1990, ei_jisx0208
+-JIS0208, ei_jisx0208
+-X0208, ei_jisx0208
+-ISO-IR-87, ei_jisx0208
+-JIS_C6226-1983, ei_jisx0208
+-CSISO87JISX0208, ei_jisx0208
+-JIS_X0212, ei_jisx0212
+-JIS_X0212.1990-0, ei_jisx0212
+-JIS_X0212-1990, ei_jisx0212
+-X0212, ei_jisx0212
+-ISO-IR-159, ei_jisx0212
+-CSISO159JISX02121990, ei_jisx0212
+-GB_1988-80, ei_iso646_cn
+-ISO646-CN, ei_iso646_cn
+-ISO-IR-57, ei_iso646_cn
+-CN, ei_iso646_cn
+-CSISO57GB1988, ei_iso646_cn
+-GB_2312-80, ei_gb2312
+-ISO-IR-58, ei_gb2312
+-CSISO58GB231280, ei_gb2312
+-CHINESE, ei_gb2312
+-ISO-IR-165, ei_isoir165
+-CN-GB-ISOIR165, ei_isoir165
+-KSC_5601, ei_ksc5601
+-KS_C_5601-1987, ei_ksc5601
+-KS_C_5601-1989, ei_ksc5601
+-ISO-IR-149, ei_ksc5601
+-CSKSC56011987, ei_ksc5601
+-KOREAN, ei_ksc5601
+-EUC-JP, ei_euc_jp
+-EUCJP, ei_euc_jp
+-EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE, ei_euc_jp
+-CSEUCPKDFMTJAPANESE, ei_euc_jp
+-SHIFT_JIS, ei_sjis
+-SHIFT-JIS, ei_sjis
+-SJIS, ei_sjis
+-MS_KANJI, ei_sjis
+-CSSHIFTJIS, ei_sjis
+-CP932, ei_cp932
+-ISO-2022-JP, ei_iso2022_jp
+-CSISO2022JP, ei_iso2022_jp
+-ISO-2022-JP-1, ei_iso2022_jp1
+-ISO-2022-JP-2, ei_iso2022_jp2
+-CSISO2022JP2, ei_iso2022_jp2
+-EUC-CN, ei_euc_cn
+-EUCCN, ei_euc_cn
+-GB2312, ei_euc_cn
+-CN-GB, ei_euc_cn
+-CSGB2312, ei_euc_cn
+-GBK, ei_ces_gbk
+-CP936, ei_cp936
+-MS936, ei_cp936
+-WINDOWS-936, ei_cp936
+-GB18030, ei_gb18030
+-ISO-2022-CN, ei_iso2022_cn
+-CSISO2022CN, ei_iso2022_cn
+-ISO-2022-CN-EXT, ei_iso2022_cn_ext
+-HZ, ei_hz
+-HZ-GB-2312, ei_hz
+-EUC-TW, ei_euc_tw
+-EUCTW, ei_euc_tw
+-CSEUCTW, ei_euc_tw
+-BIG5, ei_ces_big5
+-BIG-5, ei_ces_big5
+-BIG-FIVE, ei_ces_big5
+-BIGFIVE, ei_ces_big5
+-CN-BIG5, ei_ces_big5
+-CSBIG5, ei_ces_big5
+-CP950, ei_cp950
+-BIG5-HKSCS:1999, ei_big5hkscs1999
+-BIG5-HKSCS:2001, ei_big5hkscs2001
+-BIG5-HKSCS, ei_big5hkscs2004
+-BIG5HKSCS, ei_big5hkscs2004
+-BIG5-HKSCS:2004, ei_big5hkscs2004
+-EUC-KR, ei_euc_kr
+-EUCKR, ei_euc_kr
+-CSEUCKR, ei_euc_kr
+-CP949, ei_cp949
+-UHC, ei_cp949
+-JOHAB, ei_johab
+-CP1361, ei_johab
+-ISO-2022-KR, ei_iso2022_kr
+-CSISO2022KR, ei_iso2022_kr
+ CHAR, ei_local_char
+ WCHAR_T, ei_local_wchar_t
+--- a/lib/aliases.h
++++ b/lib/aliases.h
+@@ -1,6 +1,6 @@
+ /* ANSI-C code produced by gperf version 3.0.2 */
+ /* Command-line: gperf -m 10 lib/aliases.gperf  */
+-/* Computed positions: -k'1,3-11,$' */
++/* Computed positions: -k'4-7,10,$' */
+ 
+ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+@@ -32,12 +32,12 @@
+ #line 1 "lib/aliases.gperf"
+ struct alias { int name; unsigned int encoding_index; };
+ 
+-#define TOTAL_KEYWORDS 341
++#define TOTAL_KEYWORDS 70
+ #define MIN_WORD_LENGTH 2
+-#define MAX_WORD_LENGTH 45
+-#define MIN_HASH_VALUE 13
+-#define MAX_HASH_VALUE 997
+-/* maximum key range = 985, duplicates = 0 */
++#define MAX_WORD_LENGTH 17
++#define MIN_HASH_VALUE 4
++#define MAX_HASH_VALUE 98
++/* maximum key range = 95, duplicates = 0 */
+ 
+ #ifdef __GNUC__
+ __inline
+@@ -49,38 +49,31 @@ inline
+ static unsigned int
+ aliases_hash (register const char *str, register unsigned int len)
+ {
+-  static const unsigned short asso_values[] =
++  static const unsigned char asso_values[] =
+     {
+-      998, 998, 998, 998, 998, 998, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998, 998, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998, 998, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998, 998, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998,   4, 199, 998,  79,   6,
+-       29,  65,  13,  15,   4,  88,  20,  22, 386, 998,
+-      998, 998, 998, 998, 998,  47, 188, 110,   6,  26,
+-       63,  19,  12,   5, 281, 202,   7, 166,  11,   5,
+-       64, 998,   4,  11,  20, 185, 110, 152, 163,   4,
+-        4, 998, 998, 998, 998,   5, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998, 998, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998, 998, 998, 998, 998, 998,
+-      998, 998, 998, 998, 998, 998, 998, 998
++      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
++      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
++      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
++      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
++      99, 99, 99, 99, 99,  6, 99, 99, 22,  3,
++       2,  2, 17,  3,  2,  7,  3,  2, 99, 99,
++      99, 99, 99, 99, 99,  4, 53,  2, 21,  2,
++      99,  7, 99, 15, 99, 99, 19, 99, 33,  2,
++       4, 99, 11, 26, 17, 99, 99,  3, 26, 99,
++      99, 99, 99, 99, 99, 10, 99, 99, 99, 99,
++      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
++      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
++      99, 99, 99, 99, 99, 99, 99, 99
+     };
+   register int hval = len;
+ 
+   switch (hval)
+     {
+       default:
+-        hval += asso_values[(unsigned char)str[10]];
+-      /*FALLTHROUGH*/
+-      case 10:
+         hval += asso_values[(unsigned char)str[9]];
+       /*FALLTHROUGH*/
+       case 9:
+-        hval += asso_values[(unsigned char)str[8]];
+-      /*FALLTHROUGH*/
+       case 8:
+-        hval += asso_values[(unsigned char)str[7]];
+-      /*FALLTHROUGH*/
+       case 7:
+         hval += asso_values[(unsigned char)str[6]];
+       /*FALLTHROUGH*/
+@@ -94,11 +87,7 @@ aliases_hash (register const char *str,
+         hval += asso_values[(unsigned char)str[3]];
+       /*FALLTHROUGH*/
+       case 3:
+-        hval += asso_values[(unsigned char)str[2]];
+-      /*FALLTHROUGH*/
+       case 2:
+-      case 1:
+-        hval += asso_values[(unsigned char)str[0]];
+         break;
+     }
+   return hval + asso_values[(unsigned char)str[len - 1]];
+@@ -106,1576 +95,306 @@ aliases_hash (register const char *str,
+ 
+ struct stringpool_t
+   {
+-    char stringpool_str13[sizeof("L6")];
+-    char stringpool_str15[sizeof("L1")];
+-    char stringpool_str18[sizeof("HZ")];
+-    char stringpool_str22[sizeof("L4")];
+-    char stringpool_str24[sizeof("L5")];
+-    char stringpool_str26[sizeof("R8")];
+-    char stringpool_str29[sizeof("L8")];
+-    char stringpool_str31[sizeof("866")];
+-    char stringpool_str38[sizeof("L2")];
+-    char stringpool_str42[sizeof("SJIS")];
+-    char stringpool_str43[sizeof("ISO-IR-6")];
+-    char stringpool_str55[sizeof("ISO-IR-166")];
+-    char stringpool_str57[sizeof("LATIN6")];
+-    char stringpool_str61[sizeof("LATIN1")];
+-    char stringpool_str68[sizeof("ISO-IR-14")];
+-    char stringpool_str74[sizeof("L3")];
+-    char stringpool_str75[sizeof("LATIN4")];
+-    char stringpool_str77[sizeof("ISO-IR-165")];
+-    char stringpool_str79[sizeof("LATIN5")];
+-    char stringpool_str80[sizeof("ISO-IR-126")];
+-    char stringpool_str81[sizeof("862")];
+-    char stringpool_str82[sizeof("ISO-IR-144")];
+-    char stringpool_str89[sizeof("LATIN8")];
+-    char stringpool_str91[sizeof("ISO-IR-58")];
+-    char stringpool_str96[sizeof("ISO-IR-148")];
+-    char stringpool_str97[sizeof("L7")];
+-    char stringpool_str98[sizeof("LATIN-9")];
+-    char stringpool_str100[sizeof("ISO-IR-149")];
+-    char stringpool_str102[sizeof("ISO-IR-159")];
+-    char stringpool_str103[sizeof("ISO-IR-226")];
+-    char stringpool_str107[sizeof("LATIN2")];
+-    char stringpool_str108[sizeof("ISO8859-6")];
+-    char stringpool_str109[sizeof("ISO-IR-199")];
+-    char stringpool_str112[sizeof("ISO8859-1")];
+-    char stringpool_str113[sizeof("ISO-8859-6")];
+-    char stringpool_str114[sizeof("ISO_8859-6")];
+-    char stringpool_str115[sizeof("ISO8859-16")];
+-    char stringpool_str116[sizeof("PT154")];
+-    char stringpool_str117[sizeof("ISO-8859-1")];
+-    char stringpool_str118[sizeof("ISO_8859-1")];
+-    char stringpool_str119[sizeof("ISO8859-11")];
+-    char stringpool_str120[sizeof("ISO-8859-16")];
+-    char stringpool_str121[sizeof("ISO_8859-16")];
+-    char stringpool_str123[sizeof("CN")];
+-    char stringpool_str124[sizeof("ISO-8859-11")];
+-    char stringpool_str125[sizeof("ISO_8859-11")];
+-    char stringpool_str126[sizeof("ISO8859-4")];
+-    char stringpool_str128[sizeof("ISO_8859-16:2001")];
+-    char stringpool_str130[sizeof("ISO8859-5")];
+-    char stringpool_str131[sizeof("ISO-8859-4")];
+-    char stringpool_str132[sizeof("ISO_8859-4")];
+-    char stringpool_str133[sizeof("ISO8859-14")];
+-    char stringpool_str134[sizeof("ISO-IR-101")];
+-    char stringpool_str135[sizeof("ISO-8859-5")];
+-    char stringpool_str136[sizeof("ISO_8859-5")];
+-    char stringpool_str137[sizeof("ISO8859-15")];
+-    char stringpool_str138[sizeof("ISO-8859-14")];
+-    char stringpool_str139[sizeof("ISO_8859-14")];
+-    char stringpool_str140[sizeof("ISO8859-8")];
+-    char stringpool_str142[sizeof("ISO-8859-15")];
+-    char stringpool_str143[sizeof("ISO_8859-15")];
+-    char stringpool_str144[sizeof("ISO8859-9")];
+-    char stringpool_str145[sizeof("ISO-8859-8")];
+-    char stringpool_str146[sizeof("ISO_8859-8")];
+-    char stringpool_str147[sizeof("CP866")];
+-    char stringpool_str148[sizeof("ISO-IR-138")];
+-    char stringpool_str149[sizeof("ISO-8859-9")];
+-    char stringpool_str150[sizeof("ISO_8859-9")];
+-    char stringpool_str151[sizeof("ISO_8859-14:1998")];
+-    char stringpool_str153[sizeof("ISO_8859-15:1998")];
+-    char stringpool_str155[sizeof("ELOT_928")];
+-    char stringpool_str156[sizeof("TCVN")];
+-    char stringpool_str157[sizeof("C99")];
+-    char stringpool_str158[sizeof("ISO8859-2")];
+-    char stringpool_str162[sizeof("CP154")];
+-    char stringpool_str163[sizeof("ISO-8859-2")];
+-    char stringpool_str164[sizeof("ISO_8859-2")];
+-    char stringpool_str166[sizeof("ISO-IR-109")];
+-    char stringpool_str168[sizeof("L10")];
+-    char stringpool_str169[sizeof("CHAR")];
+-    char stringpool_str174[sizeof("CP1256")];
+-    char stringpool_str175[sizeof("ISO-IR-179")];
+-    char stringpool_str176[sizeof("ISO646-CN")];
+-    char stringpool_str177[sizeof("ASCII")];
+-    char stringpool_str178[sizeof("CP1251")];
+-    char stringpool_str179[sizeof("LATIN3")];
+-    char stringpool_str181[sizeof("850")];
+-    char stringpool_str183[sizeof("GB2312")];
+-    char stringpool_str185[sizeof("CP819")];
+-    char stringpool_str192[sizeof("CP1254")];
+-    char stringpool_str194[sizeof("CP949")];
+-    char stringpool_str196[sizeof("CP1255")];
+-    char stringpool_str197[sizeof("CP862")];
+-    char stringpool_str198[sizeof("US")];
+-    char stringpool_str203[sizeof("CP1361")];
+-    char stringpool_str206[sizeof("CP1258")];
+-    char stringpool_str207[sizeof("ISO-IR-110")];
+-    char stringpool_str209[sizeof("IBM866")];
+-    char stringpool_str210[sizeof("CP936")];
+-    char stringpool_str211[sizeof("GEORGIAN-PS")];
+-    char stringpool_str214[sizeof("LATIN10")];
+-    char stringpool_str222[sizeof("CHINESE")];
+-    char stringpool_str224[sizeof("CP1252")];
+-    char stringpool_str225[sizeof("LATIN7")];
+-    char stringpool_str226[sizeof("ISO_8859-10:1992")];
+-    char stringpool_str227[sizeof("ISO-IR-57")];
+-    char stringpool_str228[sizeof("TIS620")];
+-    char stringpool_str230[sizeof("ISO8859-3")];
+-    char stringpool_str231[sizeof("UCS-4")];
+-    char stringpool_str232[sizeof("ISO-IR-87")];
+-    char stringpool_str233[sizeof("TIS-620")];
+-    char stringpool_str234[sizeof("ISO-IR-157")];
+-    char stringpool_str235[sizeof("ISO-8859-3")];
+-    char stringpool_str236[sizeof("ISO_8859-3")];
+-    char stringpool_str237[sizeof("ISO8859-13")];
+-    char stringpool_str240[sizeof("CSISOLATIN6")];
+-    char stringpool_str241[sizeof("BIG5")];
+-    char stringpool_str242[sizeof("ISO-8859-13")];
+-    char stringpool_str243[sizeof("ISO_8859-13")];
+-    char stringpool_str244[sizeof("CSISOLATIN1")];
+-    char stringpool_str245[sizeof("KOI8-R")];
+-    char stringpool_str246[sizeof("BIG-5")];
+-    char stringpool_str247[sizeof("IBM819")];
+-    char stringpool_str248[sizeof("ISO-IR-127")];
+-    char stringpool_str249[sizeof("CP874")];
+-    char stringpool_str251[sizeof("ISO646-US")];
+-    char stringpool_str252[sizeof("VISCII")];
+-    char stringpool_str253[sizeof("MS-EE")];
+-    char stringpool_str256[sizeof("MS-ANSI")];
+-    char stringpool_str258[sizeof("CSISOLATIN4")];
+-    char stringpool_str259[sizeof("IBM862")];
+-    char stringpool_str260[sizeof("CP932")];
+-    char stringpool_str261[sizeof("X0212")];
+-    char stringpool_str262[sizeof("CSISOLATIN5")];
+-    char stringpool_str263[sizeof("UCS-2")];
+-    char stringpool_str265[sizeof("ISO8859-10")];
+-    char stringpool_str266[sizeof("MS936")];
+-    char stringpool_str267[sizeof("WCHAR_T")];
+-    char stringpool_str270[sizeof("ISO-8859-10")];
+-    char stringpool_str271[sizeof("ISO_8859-10")];
+-    char stringpool_str272[sizeof("UTF-16")];
+-    char stringpool_str273[sizeof("EUCCN")];
+-    char stringpool_str274[sizeof("ROMAN8")];
+-    char stringpool_str275[sizeof("ISO-IR-203")];
+-    char stringpool_str276[sizeof("ISO8859-7")];
+-    char stringpool_str277[sizeof("KOI8-T")];
+-    char stringpool_str278[sizeof("EUC-CN")];
+-    char stringpool_str279[sizeof("UCS-4LE")];
+-    char stringpool_str280[sizeof("ISO-IR-100")];
+-    char stringpool_str281[sizeof("ISO-8859-7")];
+-    char stringpool_str282[sizeof("ISO_8859-7")];
+-    char stringpool_str283[sizeof("MULELAO-1")];
+-    char stringpool_str284[sizeof("GB_1988-80")];
+-    char stringpool_str288[sizeof("X0201")];
+-    char stringpool_str289[sizeof("ECMA-114")];
+-    char stringpool_str290[sizeof("CSISOLATIN2")];
+-    char stringpool_str291[sizeof("GEORGIAN-ACADEMY")];
+-    char stringpool_str292[sizeof("PTCP154")];
+-    char stringpool_str295[sizeof("UCS-2LE")];
+-    char stringpool_str296[sizeof("CP1253")];
+-    char stringpool_str297[sizeof("UTF-8")];
+-    char stringpool_str298[sizeof("HP-ROMAN8")];
+-    char stringpool_str300[sizeof("CSASCII")];
+-    char stringpool_str303[sizeof("ECMA-118")];
+-    char stringpool_str304[sizeof("UCS-4-INTERNAL")];
+-    char stringpool_str305[sizeof("TCVN5712-1")];
+-    char stringpool_str307[sizeof("KOREAN")];
+-    char stringpool_str308[sizeof("CP850")];
+-    char stringpool_str309[sizeof("MS-CYRL")];
+-    char stringpool_str310[sizeof("CP950")];
+-    char stringpool_str313[sizeof("TIS620-0")];
+-    char stringpool_str316[sizeof("X0208")];
+-    char stringpool_str319[sizeof("GREEK8")];
+-    char stringpool_str320[sizeof("UCS-2-INTERNAL")];
+-    char stringpool_str321[sizeof("TCVN-5712")];
+-    char stringpool_str323[sizeof("CP1133")];
+-    char stringpool_str324[sizeof("CP1250")];
+-    char stringpool_str327[sizeof("ISO-2022-CN")];
+-    char stringpool_str329[sizeof("UTF-16LE")];
+-    char stringpool_str335[sizeof("CYRILLIC-ASIAN")];
+-    char stringpool_str337[sizeof("ISO-10646-UCS-4")];
+-    char stringpool_str340[sizeof("ISO-2022-CN-EXT")];
+-    char stringpool_str342[sizeof("CP1257")];
+-    char stringpool_str345[sizeof("GB_2312-80")];
+-    char stringpool_str347[sizeof("JP")];
+-    char stringpool_str351[sizeof("EUCKR")];
+-    char stringpool_str353[sizeof("ISO-10646-UCS-2")];
+-    char stringpool_str354[sizeof("GB18030")];
+-    char stringpool_str356[sizeof("EUC-KR")];
+-    char stringpool_str357[sizeof("CSKOI8R")];
+-    char stringpool_str358[sizeof("CSBIG5")];
+-    char stringpool_str360[sizeof("CP367")];
+-    char stringpool_str361[sizeof("MACINTOSH")];
+-    char stringpool_str362[sizeof("CSISOLATIN3")];
+-    char stringpool_str363[sizeof("CN-BIG5")];
+-    char stringpool_str366[sizeof("CYRILLIC")];
+-    char stringpool_str369[sizeof("CSVISCII")];
+-    char stringpool_str370[sizeof("IBM850")];
+-    char stringpool_str372[sizeof("MACTHAI")];
+-    char stringpool_str374[sizeof("UNICODE-1-1")];
+-    char stringpool_str376[sizeof("ISO_646.IRV:1991")];
+-    char stringpool_str380[sizeof("US-ASCII")];
+-    char stringpool_str381[sizeof("UTF-32")];
+-    char stringpool_str384[sizeof("CN-GB-ISOIR165")];
+-    char stringpool_str387[sizeof("NEXTSTEP")];
+-    char stringpool_str389[sizeof("MAC")];
+-    char stringpool_str393[sizeof("EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE")];
+-    char stringpool_str394[sizeof("CSISOLATINARABIC")];
+-    char stringpool_str395[sizeof("HZ-GB-2312")];
+-    char stringpool_str397[sizeof("ARMSCII-8")];
+-    char stringpool_str401[sizeof("CSISOLATINHEBREW")];
+-    char stringpool_str405[sizeof("ISO-2022-KR")];
+-    char stringpool_str407[sizeof("WINDOWS-1256")];
+-    char stringpool_str408[sizeof("UHC")];
+-    char stringpool_str409[sizeof("WINDOWS-1251")];
+-    char stringpool_str411[sizeof("MS-HEBR")];
+-    char stringpool_str412[sizeof("ISO-CELTIC")];
+-    char stringpool_str413[sizeof("UTF-32LE")];
+-    char stringpool_str416[sizeof("WINDOWS-1254")];
+-    char stringpool_str418[sizeof("WINDOWS-1255")];
+-    char stringpool_str420[sizeof("SHIFT-JIS")];
+-    char stringpool_str421[sizeof("SHIFT_JIS")];
+-    char stringpool_str422[sizeof("IBM367")];
+-    char stringpool_str423[sizeof("WINDOWS-1258")];
+-    char stringpool_str424[sizeof("CSPTCP154")];
+-    char stringpool_str426[sizeof("GBK")];
+-    char stringpool_str428[sizeof("UNICODELITTLE")];
+-    char stringpool_str432[sizeof("WINDOWS-1252")];
+-    char stringpool_str433[sizeof("UTF-7")];
+-    char stringpool_str435[sizeof("KSC_5601")];
+-    char stringpool_str437[sizeof("ASMO-708")];
+-    char stringpool_str440[sizeof("CSISO2022CN")];
+-    char stringpool_str444[sizeof("BIGFIVE")];
+-    char stringpool_str447[sizeof("WINDOWS-936")];
+-    char stringpool_str448[sizeof("CSUCS4")];
+-    char stringpool_str449[sizeof("BIG-FIVE")];
+-    char stringpool_str453[sizeof("ISO646-JP")];
+-    char stringpool_str456[sizeof("TIS620.2529-1")];
+-    char stringpool_str457[sizeof("CSISOLATINGREEK")];
+-    char stringpool_str459[sizeof("CSISOLATINCYRILLIC")];
+-    char stringpool_str460[sizeof("UCS-4BE")];
+-    char stringpool_str462[sizeof("UNICODE-1-1-UTF-7")];
+-    char stringpool_str465[sizeof("EUCTW")];
+-    char stringpool_str468[sizeof("WINDOWS-1253")];
+-    char stringpool_str469[sizeof("CSHPROMAN8")];
+-    char stringpool_str470[sizeof("EUC-TW")];
+-    char stringpool_str472[sizeof("KS_C_5601-1989")];
+-    char stringpool_str476[sizeof("UCS-2BE")];
+-    char stringpool_str479[sizeof("VISCII1.1-1")];
+-    char stringpool_str480[sizeof("GREEK")];
+-    char stringpool_str482[sizeof("WINDOWS-1250")];
+-    char stringpool_str483[sizeof("CSGB2312")];
+-    char stringpool_str486[sizeof("WINDOWS-874")];
+-    char stringpool_str487[sizeof("CSUNICODE11")];
+-    char stringpool_str489[sizeof("JAVA")];
+-    char stringpool_str491[sizeof("WINDOWS-1257")];
+-    char stringpool_str493[sizeof("CSUNICODE")];
+-    char stringpool_str500[sizeof("CSHALFWIDTHKATAKANA")];
+-    char stringpool_str502[sizeof("CSISO57GB1988")];
+-    char stringpool_str504[sizeof("MACICELAND")];
+-    char stringpool_str509[sizeof("CSIBM866")];
+-    char stringpool_str510[sizeof("UTF-16BE")];
+-    char stringpool_str513[sizeof("ARABIC")];
+-    char stringpool_str514[sizeof("CN-GB")];
+-    char stringpool_str518[sizeof("CSISO2022KR")];
+-    char stringpool_str520[sizeof("CSMACINTOSH")];
+-    char stringpool_str526[sizeof("JIS0208")];
+-    char stringpool_str528[sizeof("MACROMAN")];
+-    char stringpool_str530[sizeof("ISO_8859-4:1988")];
+-    char stringpool_str532[sizeof("ISO_8859-5:1988")];
+-    char stringpool_str535[sizeof("TIS620.2533-1")];
+-    char stringpool_str536[sizeof("ANSI_X3.4-1986")];
+-    char stringpool_str537[sizeof("ISO_8859-8:1988")];
+-    char stringpool_str538[sizeof("KS_C_5601-1987")];
+-    char stringpool_str539[sizeof("CSSHIFTJIS")];
+-    char stringpool_str540[sizeof("HEBREW")];
+-    char stringpool_str541[sizeof("ISO_8859-9:1989")];
+-    char stringpool_str547[sizeof("MACCROATIAN")];
+-    char stringpool_str548[sizeof("ISO-2022-JP-1")];
+-    char stringpool_str550[sizeof("EUCJP")];
+-    char stringpool_str552[sizeof("ANSI_X3.4-1968")];
+-    char stringpool_str555[sizeof("EUC-JP")];
+-    char stringpool_str561[sizeof("CSISO58GB231280")];
+-    char stringpool_str562[sizeof("JIS_C6226-1983")];
+-    char stringpool_str566[sizeof("IBM-CP1133")];
+-    char stringpool_str569[sizeof("MACCENTRALEUROPE")];
+-    char stringpool_str570[sizeof("CSISO159JISX02121990")];
+-    char stringpool_str571[sizeof("ISO-2022-JP-2")];
+-    char stringpool_str573[sizeof("CSUNICODE11UTF7")];
+-    char stringpool_str574[sizeof("UCS-4-SWAPPED")];
+-    char stringpool_str578[sizeof("UNICODEBIG")];
+-    char stringpool_str579[sizeof("CSISO14JISC6220RO")];
+-    char stringpool_str580[sizeof("JIS_C6220-1969-RO")];
+-    char stringpool_str582[sizeof("ISO_8859-3:1988")];
+-    char stringpool_str586[sizeof("CSPC862LATINHEBREW")];
+-    char stringpool_str588[sizeof("BIG5HKSCS")];
+-    char stringpool_str589[sizeof("ISO_8859-6:1987")];
+-    char stringpool_str590[sizeof("UCS-2-SWAPPED")];
+-    char stringpool_str591[sizeof("ISO_8859-1:1987")];
+-    char stringpool_str593[sizeof("BIG5-HKSCS")];
+-    char stringpool_str594[sizeof("UTF-32BE")];
+-    char stringpool_str604[sizeof("ISO-2022-JP")];
+-    char stringpool_str607[sizeof("KOI8-U")];
+-    char stringpool_str608[sizeof("TIS620.2533-0")];
+-    char stringpool_str612[sizeof("KOI8-RU")];
+-    char stringpool_str614[sizeof("ISO_8859-2:1987")];
+-    char stringpool_str618[sizeof("MACROMANIA")];
+-    char stringpool_str641[sizeof("JIS_X0212")];
+-    char stringpool_str648[sizeof("CSEUCKR")];
+-    char stringpool_str649[sizeof("MACCYRILLIC")];
+-    char stringpool_str650[sizeof("ISO_8859-7:2003")];
+-    char stringpool_str651[sizeof("MS-ARAB")];
+-    char stringpool_str657[sizeof("MS-GREEK")];
+-    char stringpool_str666[sizeof("CSKSC56011987")];
+-    char stringpool_str668[sizeof("JIS_X0201")];
+-    char stringpool_str673[sizeof("ISO_8859-7:1987")];
+-    char stringpool_str683[sizeof("CSISO2022JP2")];
+-    char stringpool_str696[sizeof("JIS_X0208")];
+-    char stringpool_str697[sizeof("JISX0201-1976")];
+-    char stringpool_str706[sizeof("JIS_X0212-1990")];
+-    char stringpool_str717[sizeof("CSISO2022JP")];
+-    char stringpool_str721[sizeof("JOHAB")];
+-    char stringpool_str730[sizeof("MS_KANJI")];
+-    char stringpool_str734[sizeof("CSISO87JISX0208")];
+-    char stringpool_str737[sizeof("MACTURKISH")];
+-    char stringpool_str755[sizeof("TCVN5712-1:1993")];
+-    char stringpool_str756[sizeof("JIS_X0208-1983")];
+-    char stringpool_str762[sizeof("CSEUCTW")];
+-    char stringpool_str763[sizeof("MACGREEK")];
+-    char stringpool_str770[sizeof("JIS_X0208-1990")];
+-    char stringpool_str776[sizeof("WINBALTRIM")];
+-    char stringpool_str790[sizeof("MS-TURK")];
+-    char stringpool_str792[sizeof("MACUKRAINE")];
+-    char stringpool_str796[sizeof("MACARABIC")];
+-    char stringpool_str802[sizeof("CSPC850MULTILINGUAL")];
+-    char stringpool_str845[sizeof("MACHEBREW")];
+-    char stringpool_str903[sizeof("JIS_X0212.1990-0")];
+-    char stringpool_str979[sizeof("BIG5-HKSCS:2001")];
+-    char stringpool_str986[sizeof("BIG5-HKSCS:2004")];
+-    char stringpool_str995[sizeof("BIG5-HKSCS:1999")];
+-    char stringpool_str997[sizeof("CSEUCPKDFMTJAPANESE")];
++    char stringpool_str4[sizeof("L2")];
++    char stringpool_str5[sizeof("L1")];
++    char stringpool_str11[sizeof("MS-EE")];
++    char stringpool_str12[sizeof("CP819")];
++    char stringpool_str15[sizeof("UCS-2")];
++    char stringpool_str16[sizeof("IBM819")];
++    char stringpool_str17[sizeof("UTF-8")];
++    char stringpool_str18[sizeof("UTF-32")];
++    char stringpool_str19[sizeof("UTF-16")];
++    char stringpool_str21[sizeof("CP367")];
++    char stringpool_str22[sizeof("ISO8859-2")];
++    char stringpool_str23[sizeof("ISO8859-1")];
++    char stringpool_str24[sizeof("IBM367")];
++    char stringpool_str25[sizeof("UTF-7")];
++    char stringpool_str26[sizeof("CHAR")];
++    char stringpool_str27[sizeof("ISO8859-15")];
++    char stringpool_str28[sizeof("US")];
++    char stringpool_str29[sizeof("ISO-8859-2")];
++    char stringpool_str31[sizeof("ISO-8859-1")];
++    char stringpool_str32[sizeof("ISO-8859-15")];
++    char stringpool_str33[sizeof("ISO_8859-2")];
++    char stringpool_str35[sizeof("ISO_8859-1")];
++    char stringpool_str36[sizeof("ISO_8859-15")];
++    char stringpool_str37[sizeof("KOI8-R")];
++    char stringpool_str38[sizeof("UCS-2LE")];
++    char stringpool_str39[sizeof("UTF-32LE")];
++    char stringpool_str40[sizeof("UTF-16LE")];
++    char stringpool_str41[sizeof("ISO_8859-15:1998")];
++    char stringpool_str43[sizeof("ISO_8859-2:1987")];
++    char stringpool_str44[sizeof("ISO_8859-1:1987")];
++    char stringpool_str45[sizeof("UCS-4")];
++    char stringpool_str47[sizeof("UNICODE-1-1")];
++    char stringpool_str48[sizeof("ISO-IR-6")];
++    char stringpool_str49[sizeof("CSKOI8R")];
++    char stringpool_str50[sizeof("ASCII")];
++    char stringpool_str51[sizeof("UNICODEBIG")];
++    char stringpool_str52[sizeof("ISO-IR-203")];
++    char stringpool_str53[sizeof("UCS-4LE")];
++    char stringpool_str54[sizeof("ISO-IR-101")];
++    char stringpool_str55[sizeof("CP1250")];
++    char stringpool_str56[sizeof("ISO-10646-UCS-2")];
++    char stringpool_str57[sizeof("UNICODE-1-1-UTF-7")];
++    char stringpool_str58[sizeof("LATIN2")];
++    char stringpool_str59[sizeof("UNICODELITTLE")];
++    char stringpool_str60[sizeof("LATIN1")];
++    char stringpool_str61[sizeof("ISO_646.IRV:1991")];
++    char stringpool_str62[sizeof("ISO646-US")];
++    char stringpool_str63[sizeof("CSUNICODE")];
++    char stringpool_str64[sizeof("UCS-2-INTERNAL")];
++    char stringpool_str65[sizeof("LATIN-9")];
++    char stringpool_str66[sizeof("WCHAR_T")];
++    char stringpool_str68[sizeof("CSUCS4")];
++    char stringpool_str69[sizeof("CSUNICODE11")];
++    char stringpool_str70[sizeof("US-ASCII")];
++    char stringpool_str71[sizeof("ISO-10646-UCS-4")];
++    char stringpool_str72[sizeof("UCS-2BE")];
++    char stringpool_str73[sizeof("UTF-32BE")];
++    char stringpool_str74[sizeof("UTF-16BE")];
++    char stringpool_str75[sizeof("ANSI_X3.4-1986")];
++    char stringpool_str76[sizeof("ANSI_X3.4-1968")];
++    char stringpool_str77[sizeof("CSUNICODE11UTF7")];
++    char stringpool_str78[sizeof("UCS-2-SWAPPED")];
++    char stringpool_str79[sizeof("UCS-4-INTERNAL")];
++    char stringpool_str80[sizeof("CSASCII")];
++    char stringpool_str87[sizeof("UCS-4BE")];
++    char stringpool_str88[sizeof("WINDOWS-1250")];
++    char stringpool_str92[sizeof("ISO-IR-100")];
++    char stringpool_str93[sizeof("UCS-4-SWAPPED")];
++    char stringpool_str97[sizeof("CSISOLATIN2")];
++    char stringpool_str98[sizeof("CSISOLATIN1")];
+   };
+ static const struct stringpool_t stringpool_contents =
+   {
+-    "L6",
+-    "L1",
+-    "HZ",
+-    "L4",
+-    "L5",
+-    "R8",
+-    "L8",
+-    "866",
+     "L2",
+-    "SJIS",
+-    "ISO-IR-6",
+-    "ISO-IR-166",
+-    "LATIN6",
+-    "LATIN1",
+-    "ISO-IR-14",
+-    "L3",
+-    "LATIN4",
+-    "ISO-IR-165",
+-    "LATIN5",
+-    "ISO-IR-126",
+-    "862",
+-    "ISO-IR-144",
+-    "LATIN8",
+-    "ISO-IR-58",
+-    "ISO-IR-148",
+-    "L7",
+-    "LATIN-9",
+-    "ISO-IR-149",
+-    "ISO-IR-159",
+-    "ISO-IR-226",
+-    "LATIN2",
+-    "ISO8859-6",
+-    "ISO-IR-199",
++    "L1",
++    "MS-EE",
++    "CP819",
++    "UCS-2",
++    "IBM819",
++    "UTF-8",
++    "UTF-32",
++    "UTF-16",
++    "CP367",
++    "ISO8859-2",
+     "ISO8859-1",
+-    "ISO-8859-6",
+-    "ISO_8859-6",
+-    "ISO8859-16",
+-    "PT154",
+-    "ISO-8859-1",
+-    "ISO_8859-1",
+-    "ISO8859-11",
+-    "ISO-8859-16",
+-    "ISO_8859-16",
+-    "CN",
+-    "ISO-8859-11",
+-    "ISO_8859-11",
+-    "ISO8859-4",
+-    "ISO_8859-16:2001",
+-    "ISO8859-5",
+-    "ISO-8859-4",
+-    "ISO_8859-4",
+-    "ISO8859-14",
+-    "ISO-IR-101",
+-    "ISO-8859-5",
+-    "ISO_8859-5",
++    "IBM367",
++    "UTF-7",
++    "CHAR",
+     "ISO8859-15",
+-    "ISO-8859-14",
+-    "ISO_8859-14",
+-    "ISO8859-8",
++    "US",
++    "ISO-8859-2",
++    "ISO-8859-1",
+     "ISO-8859-15",
++    "ISO_8859-2",
++    "ISO_8859-1",
+     "ISO_8859-15",
+-    "ISO8859-9",
+-    "ISO-8859-8",
+-    "ISO_8859-8",
+-    "CP866",
+-    "ISO-IR-138",
+-    "ISO-8859-9",
+-    "ISO_8859-9",
+-    "ISO_8859-14:1998",
++    "KOI8-R",
++    "UCS-2LE",
++    "UTF-32LE",
++    "UTF-16LE",
+     "ISO_8859-15:1998",
+-    "ELOT_928",
+-    "TCVN",
+-    "C99",
+-    "ISO8859-2",
+-    "CP154",
+-    "ISO-8859-2",
+-    "ISO_8859-2",
+-    "ISO-IR-109",
+-    "L10",
+-    "CHAR",
+-    "CP1256",
+-    "ISO-IR-179",
+-    "ISO646-CN",
+-    "ASCII",
+-    "CP1251",
+-    "LATIN3",
+-    "850",
+-    "GB2312",
+-    "CP819",
+-    "CP1254",
+-    "CP949",
+-    "CP1255",
+-    "CP862",
+-    "US",
+-    "CP1361",
+-    "CP1258",
+-    "ISO-IR-110",
+-    "IBM866",
+-    "CP936",
+-    "GEORGIAN-PS",
+-    "LATIN10",
+-    "CHINESE",
+-    "CP1252",
+-    "LATIN7",
+-    "ISO_8859-10:1992",
+-    "ISO-IR-57",
+-    "TIS620",
+-    "ISO8859-3",
++    "ISO_8859-2:1987",
++    "ISO_8859-1:1987",
+     "UCS-4",
+-    "ISO-IR-87",
+-    "TIS-620",
+-    "ISO-IR-157",
+-    "ISO-8859-3",
+-    "ISO_8859-3",
+-    "ISO8859-13",
+-    "CSISOLATIN6",
+-    "BIG5",
+-    "ISO-8859-13",
+-    "ISO_8859-13",
+-    "CSISOLATIN1",
+-    "KOI8-R",
+-    "BIG-5",
+-    "IBM819",
+-    "ISO-IR-127",
+-    "CP874",
+-    "ISO646-US",
+-    "VISCII",
+-    "MS-EE",
+-    "MS-ANSI",
+-    "CSISOLATIN4",
+-    "IBM862",
+-    "CP932",
+-    "X0212",
+-    "CSISOLATIN5",
+-    "UCS-2",
+-    "ISO8859-10",
+-    "MS936",
+-    "WCHAR_T",
+-    "ISO-8859-10",
+-    "ISO_8859-10",
+-    "UTF-16",
+-    "EUCCN",
+-    "ROMAN8",
++    "UNICODE-1-1",
++    "ISO-IR-6",
++    "CSKOI8R",
++    "ASCII",
++    "UNICODEBIG",
+     "ISO-IR-203",
+-    "ISO8859-7",
+-    "KOI8-T",
+-    "EUC-CN",
+     "UCS-4LE",
+-    "ISO-IR-100",
+-    "ISO-8859-7",
+-    "ISO_8859-7",
+-    "MULELAO-1",
+-    "GB_1988-80",
+-    "X0201",
+-    "ECMA-114",
+-    "CSISOLATIN2",
+-    "GEORGIAN-ACADEMY",
+-    "PTCP154",
+-    "UCS-2LE",
+-    "CP1253",
+-    "UTF-8",
+-    "HP-ROMAN8",
+-    "CSASCII",
+-    "ECMA-118",
+-    "UCS-4-INTERNAL",
+-    "TCVN5712-1",
+-    "KOREAN",
+-    "CP850",
+-    "MS-CYRL",
+-    "CP950",
+-    "TIS620-0",
+-    "X0208",
+-    "GREEK8",
+-    "UCS-2-INTERNAL",
+-    "TCVN-5712",
+-    "CP1133",
++    "ISO-IR-101",
+     "CP1250",
+-    "ISO-2022-CN",
+-    "UTF-16LE",
+-    "CYRILLIC-ASIAN",
+-    "ISO-10646-UCS-4",
+-    "ISO-2022-CN-EXT",
+-    "CP1257",
+-    "GB_2312-80",
+-    "JP",
+-    "EUCKR",
+     "ISO-10646-UCS-2",
+-    "GB18030",
+-    "EUC-KR",
+-    "CSKOI8R",
+-    "CSBIG5",
+-    "CP367",
+-    "MACINTOSH",
+-    "CSISOLATIN3",
+-    "CN-BIG5",
+-    "CYRILLIC",
+-    "CSVISCII",
+-    "IBM850",
+-    "MACTHAI",
+-    "UNICODE-1-1",
+-    "ISO_646.IRV:1991",
+-    "US-ASCII",
+-    "UTF-32",
+-    "CN-GB-ISOIR165",
+-    "NEXTSTEP",
+-    "MAC",
+-    "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE",
+-    "CSISOLATINARABIC",
+-    "HZ-GB-2312",
+-    "ARMSCII-8",
+-    "CSISOLATINHEBREW",
+-    "ISO-2022-KR",
+-    "WINDOWS-1256",
+-    "UHC",
+-    "WINDOWS-1251",
+-    "MS-HEBR",
+-    "ISO-CELTIC",
+-    "UTF-32LE",
+-    "WINDOWS-1254",
+-    "WINDOWS-1255",
+-    "SHIFT-JIS",
+-    "SHIFT_JIS",
+-    "IBM367",
+-    "WINDOWS-1258",
+-    "CSPTCP154",
+-    "GBK",
++    "UNICODE-1-1-UTF-7",
++    "LATIN2",
+     "UNICODELITTLE",
+-    "WINDOWS-1252",
+-    "UTF-7",
+-    "KSC_5601",
+-    "ASMO-708",
+-    "CSISO2022CN",
+-    "BIGFIVE",
+-    "WINDOWS-936",
++    "LATIN1",
++    "ISO_646.IRV:1991",
++    "ISO646-US",
++    "CSUNICODE",
++    "UCS-2-INTERNAL",
++    "LATIN-9",
++    "WCHAR_T",
+     "CSUCS4",
+-    "BIG-FIVE",
+-    "ISO646-JP",
+-    "TIS620.2529-1",
+-    "CSISOLATINGREEK",
+-    "CSISOLATINCYRILLIC",
+-    "UCS-4BE",
+-    "UNICODE-1-1-UTF-7",
+-    "EUCTW",
+-    "WINDOWS-1253",
+-    "CSHPROMAN8",
+-    "EUC-TW",
+-    "KS_C_5601-1989",
+-    "UCS-2BE",
+-    "VISCII1.1-1",
+-    "GREEK",
+-    "WINDOWS-1250",
+-    "CSGB2312",
+-    "WINDOWS-874",
+     "CSUNICODE11",
+-    "JAVA",
+-    "WINDOWS-1257",
+-    "CSUNICODE",
+-    "CSHALFWIDTHKATAKANA",
+-    "CSISO57GB1988",
+-    "MACICELAND",
+-    "CSIBM866",
++    "US-ASCII",
++    "ISO-10646-UCS-4",
++    "UCS-2BE",
++    "UTF-32BE",
+     "UTF-16BE",
+-    "ARABIC",
+-    "CN-GB",
+-    "CSISO2022KR",
+-    "CSMACINTOSH",
+-    "JIS0208",
+-    "MACROMAN",
+-    "ISO_8859-4:1988",
+-    "ISO_8859-5:1988",
+-    "TIS620.2533-1",
+     "ANSI_X3.4-1986",
+-    "ISO_8859-8:1988",
+-    "KS_C_5601-1987",
+-    "CSSHIFTJIS",
+-    "HEBREW",
+-    "ISO_8859-9:1989",
+-    "MACCROATIAN",
+-    "ISO-2022-JP-1",
+-    "EUCJP",
+     "ANSI_X3.4-1968",
+-    "EUC-JP",
+-    "CSISO58GB231280",
+-    "JIS_C6226-1983",
+-    "IBM-CP1133",
+-    "MACCENTRALEUROPE",
+-    "CSISO159JISX02121990",
+-    "ISO-2022-JP-2",
+     "CSUNICODE11UTF7",
+-    "UCS-4-SWAPPED",
+-    "UNICODEBIG",
+-    "CSISO14JISC6220RO",
+-    "JIS_C6220-1969-RO",
+-    "ISO_8859-3:1988",
+-    "CSPC862LATINHEBREW",
+-    "BIG5HKSCS",
+-    "ISO_8859-6:1987",
+     "UCS-2-SWAPPED",
+-    "ISO_8859-1:1987",
+-    "BIG5-HKSCS",
+-    "UTF-32BE",
+-    "ISO-2022-JP",
+-    "KOI8-U",
+-    "TIS620.2533-0",
+-    "KOI8-RU",
+-    "ISO_8859-2:1987",
+-    "MACROMANIA",
+-    "JIS_X0212",
+-    "CSEUCKR",
+-    "MACCYRILLIC",
+-    "ISO_8859-7:2003",
+-    "MS-ARAB",
+-    "MS-GREEK",
+-    "CSKSC56011987",
+-    "JIS_X0201",
+-    "ISO_8859-7:1987",
+-    "CSISO2022JP2",
+-    "JIS_X0208",
+-    "JISX0201-1976",
+-    "JIS_X0212-1990",
+-    "CSISO2022JP",
+-    "JOHAB",
+-    "MS_KANJI",
+-    "CSISO87JISX0208",
+-    "MACTURKISH",
+-    "TCVN5712-1:1993",
+-    "JIS_X0208-1983",
+-    "CSEUCTW",
+-    "MACGREEK",
+-    "JIS_X0208-1990",
+-    "WINBALTRIM",
+-    "MS-TURK",
+-    "MACUKRAINE",
+-    "MACARABIC",
+-    "CSPC850MULTILINGUAL",
+-    "MACHEBREW",
+-    "JIS_X0212.1990-0",
+-    "BIG5-HKSCS:2001",
+-    "BIG5-HKSCS:2004",
+-    "BIG5-HKSCS:1999",
+-    "CSEUCPKDFMTJAPANESE"
++    "UCS-4-INTERNAL",
++    "CSASCII",
++    "UCS-4BE",
++    "WINDOWS-1250",
++    "ISO-IR-100",
++    "UCS-4-SWAPPED",
++    "CSISOLATIN2",
++    "CSISOLATIN1"
+   };
+ #define stringpool ((const char *) &stringpool_contents)
+ 
+ static const struct alias aliases[] =
+   {
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+     {-1}, {-1}, {-1}, {-1},
+-#line 134 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str13, ei_iso8859_10},
+-    {-1},
+-#line 60 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str15, ei_iso8859_1},
+-    {-1}, {-1},
+-#line 325 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str18, ei_hz},
+-    {-1}, {-1}, {-1},
+-#line 84 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str22, ei_iso8859_4},
+-    {-1},
+-#line 126 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str24, ei_iso8859_9},
+-    {-1},
+-#line 226 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str26, ei_hp_roman8},
+-    {-1}, {-1},
+-#line 151 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str29, ei_iso8859_14},
+-    {-1},
+-#line 207 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str31, ei_cp866},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 68 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str38, ei_iso8859_2},
+-    {-1}, {-1}, {-1},
+-#line 303 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str42, ei_sjis},
+-#line 16 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str43, ei_ascii},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1},
+-#line 247 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str55, ei_tis620},
+-    {-1},
+-#line 133 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str57, ei_iso8859_10},
+-    {-1}, {-1}, {-1},
+-#line 59 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str61, ei_iso8859_1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 259 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str68, ei_iso646_jp},
++#line 66 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str4, ei_iso8859_2},
++#line 58 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str5, ei_iso8859_1},
+     {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 76 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str74, ei_iso8859_3},
+-#line 83 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str75, ei_iso8859_4},
+-    {-1},
+-#line 289 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str77, ei_isoir165},
+-    {-1},
+-#line 125 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str79, ei_iso8859_9},
+-#line 107 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str80, ei_iso8859_7},
+-#line 203 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str81, ei_cp862},
+-#line 90 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str82, ei_iso8859_5},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 150 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str89, ei_iso8859_14},
+-    {-1},
+-#line 286 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str91, ei_gb2312},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 124 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str96, ei_iso8859_9},
+-#line 144 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str97, ei_iso8859_13},
+-#line 158 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str98, ei_iso8859_15},
+-    {-1},
+-#line 294 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str100, ei_ksc5601},
+-    {-1},
+-#line 278 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str102, ei_jisx0212},
+-#line 163 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str103, ei_iso8859_16},
+-    {-1}, {-1}, {-1},
+-#line 67 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str107, ei_iso8859_2},
+-#line 102 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str108, ei_iso8859_6},
+-#line 149 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str109, ei_iso8859_14},
++#line 79 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str11, ei_cp1250},
++#line 55 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str12, ei_iso8859_1},
+     {-1}, {-1},
+-#line 62 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str112, ei_iso8859_1},
+-#line 94 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str113, ei_iso8859_6},
+-#line 95 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str114, ei_iso8859_6},
+-#line 166 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str115, ei_iso8859_16},
+-#line 233 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str116, ei_pt154},
+-#line 53 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str117, ei_iso8859_1},
+-#line 54 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str118, ei_iso8859_1},
+-#line 139 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str119, ei_iso8859_11},
+-#line 160 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str120, ei_iso8859_16},
+-#line 161 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str121, ei_iso8859_16},
+-    {-1},
+-#line 283 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str123, ei_iso646_cn},
+-#line 137 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str124, ei_iso8859_11},
+-#line 138 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str125, ei_iso8859_11},
+-#line 86 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str126, ei_iso8859_4},
+-    {-1},
+-#line 162 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str128, ei_iso8859_16},
++#line 24 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str15, ei_ucs2},
++#line 56 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str16, ei_iso8859_1},
++#line 23 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str17, ei_utf8},
++#line 41 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str18, ei_utf32},
++#line 38 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str19, ei_utf16},
+     {-1},
+-#line 93 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str130, ei_iso8859_5},
+-#line 79 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str131, ei_iso8859_4},
++#line 19 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str21, ei_ascii},
++#line 68 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str22, ei_iso8859_2},
++#line 60 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str23, ei_iso8859_1},
++#line 20 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str24, ei_ascii},
++#line 44 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str25, ei_utf7},
+ #line 80 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str132, ei_iso8859_4},
+-#line 153 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str133, ei_iso8859_14},
+-#line 66 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str134, ei_iso8859_2},
+-#line 87 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str135, ei_iso8859_5},
+-#line 88 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str136, ei_iso8859_5},
+-#line 159 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str137, ei_iso8859_15},
+-#line 146 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str138, ei_iso8859_14},
+-#line 147 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str139, ei_iso8859_14},
+-#line 120 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str140, ei_iso8859_8},
+-    {-1},
+-#line 154 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str142, ei_iso8859_15},
+-#line 155 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str143, ei_iso8859_15},
+-#line 128 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str144, ei_iso8859_9},
+-#line 114 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str145, ei_iso8859_8},
+-#line 115 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str146, ei_iso8859_8},
+-#line 205 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str147, ei_cp866},
+-#line 117 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str148, ei_iso8859_8},
+-#line 121 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str149, ei_iso8859_9},
+-#line 122 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str150, ei_iso8859_9},
+-#line 148 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str151, ei_iso8859_14},
+-    {-1},
+-#line 156 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str153, ei_iso8859_15},
+-    {-1},
+-#line 109 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str155, ei_iso8859_7},
+-#line 253 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str156, ei_tcvn},
+-#line 51 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str157, ei_c99},
+-#line 70 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str158, ei_iso8859_2},
+-    {-1}, {-1}, {-1},
+-#line 235 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str162, ei_pt154},
+-#line 63 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str163, ei_iso8859_2},
+-#line 64 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str164, ei_iso8859_2},
+-    {-1},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str26, ei_local_char},
+ #line 74 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str166, ei_iso8859_3},
+-    {-1},
+-#line 165 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str168, ei_iso8859_16},
+-#line 351 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str169, ei_local_char},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 189 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str174, ei_cp1256},
+-#line 142 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str175, ei_iso8859_13},
+-#line 281 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str176, ei_iso646_cn},
+-#line 13 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str177, ei_ascii},
+-#line 174 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str178, ei_cp1251},
+-#line 75 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str179, ei_iso8859_3},
+-    {-1},
+-#line 199 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str181, ei_cp850},
+-    {-1},
+-#line 314 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str183, ei_euc_cn},
+-    {-1},
+-#line 57 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str185, ei_iso8859_1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 183 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str192, ei_cp1254},
+-    {-1},
+-#line 345 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str194, ei_cp949},
+-    {-1},
+-#line 186 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str196, ei_cp1255},
+-#line 201 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str197, ei_cp862},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str27, ei_iso8859_15},
+ #line 21 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str198, ei_ascii},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 348 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str203, ei_johab},
+-    {-1}, {-1},
+-#line 195 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str206, ei_cp1258},
+-#line 82 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str207, ei_iso8859_4},
+-    {-1},
+-#line 206 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str209, ei_cp866},
+-#line 318 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str210, ei_cp936},
+-#line 231 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str211, ei_georgian_ps},
+-    {-1}, {-1},
+-#line 164 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str214, ei_iso8859_16},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 288 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str222, ei_gb2312},
+-    {-1},
+-#line 177 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str224, ei_cp1252},
+-#line 143 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str225, ei_iso8859_13},
+-#line 131 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str226, ei_iso8859_10},
+-#line 282 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str227, ei_iso646_cn},
+-#line 242 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str228, ei_tis620},
+-    {-1},
+-#line 78 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str230, ei_iso8859_3},
+-#line 33 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str231, ei_ucs4},
+-#line 271 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str232, ei_jisx0208},
+-#line 241 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str233, ei_tis620},
+-#line 132 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str234, ei_iso8859_10},
+-#line 71 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str235, ei_iso8859_3},
+-#line 72 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str236, ei_iso8859_3},
+-#line 145 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str237, ei_iso8859_13},
+-    {-1}, {-1},
+-#line 135 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str240, ei_iso8859_10},
+-#line 330 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str241, ei_ces_big5},
+-#line 140 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str242, ei_iso8859_13},
+-#line 141 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str243, ei_iso8859_13},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str28, ei_ascii},
+ #line 61 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str244, ei_iso8859_1},
+-#line 167 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str245, ei_koi8_r},
+-#line 331 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str246, ei_ces_big5},
+-#line 58 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str247, ei_iso8859_1},
+-#line 97 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str248, ei_iso8859_6},
+-#line 248 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str249, ei_cp874},
+-    {-1},
+-#line 14 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str251, ei_ascii},
+-#line 250 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str252, ei_viscii},
+-#line 173 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str253, ei_cp1250},
+-    {-1}, {-1},
+-#line 179 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str256, ei_cp1252},
+-    {-1},
+-#line 85 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str258, ei_iso8859_4},
+-#line 202 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str259, ei_cp862},
+-#line 306 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str260, ei_cp932},
+-#line 277 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str261, ei_jisx0212},
+-#line 127 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str262, ei_iso8859_9},
+-#line 24 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str263, ei_ucs2},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str29, ei_iso8859_2},
+     {-1},
+-#line 136 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str265, ei_iso8859_10},
+-#line 319 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str266, ei_cp936},
+-#line 352 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str267, ei_local_wchar_t},
+-    {-1}, {-1},
+-#line 129 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str270, ei_iso8859_10},
+-#line 130 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str271, ei_iso8859_10},
+-#line 38 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str272, ei_utf16},
+-#line 313 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str273, ei_euc_cn},
+-#line 225 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str274, ei_hp_roman8},
+-#line 157 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str275, ei_iso8859_15},
+-#line 113 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str276, ei_iso8859_7},
+-#line 232 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str277, ei_koi8_t},
+-#line 312 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str278, ei_euc_cn},
+-#line 37 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str279, ei_ucs4le},
+-#line 56 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str280, ei_iso8859_1},
+-#line 103 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str281, ei_iso8859_7},
+-#line 104 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str282, ei_iso8859_7},
+-#line 238 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str283, ei_mulelao},
+-#line 280 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str284, ei_iso646_cn},
+-    {-1}, {-1}, {-1},
+-#line 264 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str288, ei_jisx0201},
+-#line 98 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str289, ei_iso8859_6},
++#line 51 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str31, ei_iso8859_1},
+ #line 69 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str290, ei_iso8859_2},
+-#line 230 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str291, ei_georgian_academy},
+-#line 234 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str292, ei_pt154},
+-    {-1}, {-1},
+-#line 31 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str295, ei_ucs2le},
+-#line 180 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str296, ei_cp1253},
+-#line 23 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str297, ei_utf8},
+-#line 224 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str298, ei_hp_roman8},
+-    {-1},
+-#line 22 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str300, ei_ascii},
+-    {-1}, {-1},
+-#line 108 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str303, ei_iso8859_7},
+-#line 49 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str304, ei_ucs4internal},
+-#line 255 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str305, ei_tcvn},
+-    {-1},
+-#line 296 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str307, ei_ksc5601},
+-#line 197 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str308, ei_cp850},
+-#line 176 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str309, ei_cp1251},
+-#line 336 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str310, ei_cp950},
+-    {-1}, {-1},
+-#line 243 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str313, ei_tis620},
+-    {-1}, {-1},
+-#line 270 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str316, ei_jisx0208},
+-    {-1}, {-1},
+-#line 110 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str319, ei_iso8859_7},
+-#line 47 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str320, ei_ucs2internal},
+-#line 254 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str321, ei_tcvn},
+-    {-1},
+-#line 239 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str323, ei_cp1133},
+-#line 171 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str324, ei_cp1250},
+-    {-1}, {-1},
+-#line 322 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str327, ei_iso2022_cn},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str32, ei_iso8859_15},
++#line 62 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str33, ei_iso8859_2},
+     {-1},
++#line 52 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str35, ei_iso8859_1},
++#line 70 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str36, ei_iso8859_15},
++#line 75 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str37, ei_koi8_r},
++#line 31 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str38, ei_ucs2le},
++#line 43 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str39, ei_utf32le},
+ #line 40 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str329, ei_utf16le},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 236 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str335, ei_pt154},
+-    {-1},
+-#line 34 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str337, ei_ucs4},
+-    {-1}, {-1},
+-#line 324 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str340, ei_iso2022_cn_ext},
+-    {-1},
+-#line 192 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str342, ei_cp1257},
+-    {-1}, {-1},
+-#line 285 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str345, ei_gb2312},
+-    {-1},
+-#line 260 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str347, ei_iso646_jp},
+-    {-1}, {-1}, {-1},
+-#line 343 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str351, ei_euc_kr},
+-    {-1},
+-#line 25 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str353, ei_ucs2},
+-#line 321 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str354, ei_gb18030},
+-    {-1},
+-#line 342 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str356, ei_euc_kr},
+-#line 168 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str357, ei_koi8_r},
+-#line 335 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str358, ei_ces_big5},
+-    {-1},
+-#line 19 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str360, ei_ascii},
+-#line 210 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str361, ei_mac_roman},
+-#line 77 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str362, ei_iso8859_3},
+-#line 334 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str363, ei_ces_big5},
+-    {-1}, {-1},
+-#line 91 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str366, ei_iso8859_5},
+-    {-1}, {-1},
+-#line 252 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str369, ei_viscii},
+-#line 198 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str370, ei_cp850},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str40, ei_utf16le},
++#line 71 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str41, ei_iso8859_15},
+     {-1},
+-#line 223 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str372, ei_mac_thai},
++#line 63 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str43, ei_iso8859_2},
++#line 53 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str44, ei_iso8859_1},
++#line 33 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str45, ei_ucs4},
+     {-1},
+ #line 29 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str374, ei_ucs2be},
+-    {-1},
+-#line 15 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str376, ei_ascii},
+-    {-1}, {-1}, {-1},
+-#line 12 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str380, ei_ascii},
+-#line 41 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str381, ei_utf32},
+-    {-1}, {-1},
+-#line 290 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str384, ei_isoir165},
+-    {-1}, {-1},
+-#line 228 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str387, ei_nextstep},
+-    {-1},
+-#line 211 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str389, ei_mac_roman},
+-    {-1}, {-1}, {-1},
+-#line 299 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str393, ei_euc_jp},
+-#line 101 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str394, ei_iso8859_6},
+-#line 326 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str395, ei_hz},
+-    {-1},
+-#line 229 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str397, ei_armscii_8},
+-    {-1}, {-1}, {-1},
+-#line 119 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str401, ei_iso8859_8},
+-    {-1}, {-1}, {-1},
+-#line 349 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str405, ei_iso2022_kr},
+-    {-1},
+-#line 190 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str407, ei_cp1256},
+-#line 346 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str408, ei_cp949},
+-#line 175 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str409, ei_cp1251},
+-    {-1},
+-#line 188 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str411, ei_cp1255},
+-#line 152 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str412, ei_iso8859_14},
+-#line 43 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str413, ei_utf32le},
+-    {-1}, {-1},
+-#line 184 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str416, ei_cp1254},
+-    {-1},
+-#line 187 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str418, ei_cp1255},
+-    {-1},
+-#line 302 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str420, ei_sjis},
+-#line 301 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str421, ei_sjis},
+-#line 20 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str422, ei_ascii},
+-#line 196 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str423, ei_cp1258},
+-#line 237 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str424, ei_pt154},
+-    {-1},
+-#line 317 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str426, ei_ces_gbk},
+-    {-1},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str47, ei_ucs2be},
++#line 16 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str48, ei_ascii},
++#line 76 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str49, ei_koi8_r},
++#line 13 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str50, ei_ascii},
++#line 28 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str51, ei_ucs2be},
++#line 72 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str52, ei_iso8859_15},
++#line 37 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str53, ei_ucs4le},
++#line 64 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str54, ei_iso8859_2},
++#line 77 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str55, ei_cp1250},
++#line 25 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str56, ei_ucs2},
++#line 45 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str57, ei_utf7},
++#line 65 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str58, ei_iso8859_2},
+ #line 32 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str428, ei_ucs2le},
+-    {-1}, {-1}, {-1},
+-#line 178 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str432, ei_cp1252},
+-#line 44 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str433, ei_utf7},
+-    {-1},
+-#line 291 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str435, ei_ksc5601},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str59, ei_ucs2le},
++#line 57 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str60, ei_iso8859_1},
++#line 15 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str61, ei_ascii},
++#line 14 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str62, ei_ascii},
++#line 26 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str63, ei_ucs2},
++#line 47 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str64, ei_ucs2internal},
++#line 73 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str65, ei_iso8859_15},
++#line 81 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str66, ei_local_wchar_t},
+     {-1},
+-#line 99 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str437, ei_iso8859_6},
+-    {-1}, {-1},
+-#line 323 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str440, ei_iso2022_cn},
+-    {-1}, {-1}, {-1},
+-#line 333 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str444, ei_ces_big5},
+-    {-1}, {-1},
+-#line 320 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str447, ei_cp936},
+ #line 35 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str448, ei_ucs4},
+-#line 332 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str449, ei_ces_big5},
+-    {-1}, {-1}, {-1},
+-#line 258 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str453, ei_iso646_jp},
+-    {-1}, {-1},
+-#line 244 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str456, ei_tis620},
+-#line 112 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str457, ei_iso8859_7},
+-    {-1},
+-#line 92 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str459, ei_iso8859_5},
+-#line 36 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str460, ei_ucs4be},
+-    {-1},
+-#line 45 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str462, ei_utf7},
+-    {-1}, {-1},
+-#line 328 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str465, ei_euc_tw},
+-    {-1}, {-1},
+-#line 181 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str468, ei_cp1253},
+-#line 227 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str469, ei_hp_roman8},
+-#line 327 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str470, ei_euc_tw},
+-    {-1},
+-#line 293 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str472, ei_ksc5601},
+-    {-1}, {-1}, {-1},
+-#line 27 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str476, ei_ucs2be},
+-    {-1}, {-1},
+-#line 251 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str479, ei_viscii},
+-#line 111 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str480, ei_iso8859_7},
+-    {-1},
+-#line 172 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str482, ei_cp1250},
+-#line 316 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str483, ei_euc_cn},
+-    {-1}, {-1},
+-#line 249 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str486, ei_cp874},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str68, ei_ucs4},
+ #line 30 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str487, ei_ucs2be},
+-    {-1},
+-#line 52 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str489, ei_java},
+-    {-1},
+-#line 193 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str491, ei_cp1257},
+-    {-1},
+-#line 26 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str493, ei_ucs2},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 265 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str500, ei_jisx0201},
+-    {-1},
+-#line 284 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str502, ei_iso646_cn},
+-    {-1},
+-#line 214 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str504, ei_mac_iceland},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 208 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str509, ei_cp866},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str69, ei_ucs2be},
++#line 12 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str70, ei_ascii},
++#line 34 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str71, ei_ucs4},
++#line 27 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str72, ei_ucs2be},
++#line 42 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str73, ei_utf32be},
+ #line 39 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str510, ei_utf16be},
+-    {-1}, {-1},
+-#line 100 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str513, ei_iso8859_6},
+-#line 315 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str514, ei_euc_cn},
+-    {-1}, {-1}, {-1},
+-#line 350 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str518, ei_iso2022_kr},
+-    {-1},
+-#line 212 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str520, ei_mac_roman},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 269 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str526, ei_jisx0208},
+-    {-1},
+-#line 209 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str528, ei_mac_roman},
+-    {-1},
+-#line 81 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str530, ei_iso8859_4},
+-    {-1},
+-#line 89 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str532, ei_iso8859_5},
+-    {-1}, {-1},
+-#line 246 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str535, ei_tis620},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str74, ei_utf16be},
+ #line 18 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str536, ei_ascii},
+-#line 116 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str537, ei_iso8859_8},
+-#line 292 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str538, ei_ksc5601},
+-#line 305 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str539, ei_sjis},
+-#line 118 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str540, ei_iso8859_8},
+-#line 123 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str541, ei_iso8859_9},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 215 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str547, ei_mac_croatian},
+-#line 309 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str548, ei_iso2022_jp1},
+-    {-1},
+-#line 298 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str550, ei_euc_jp},
+-    {-1},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str75, ei_ascii},
+ #line 17 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str552, ei_ascii},
+-    {-1}, {-1},
+-#line 297 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str555, ei_euc_jp},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 287 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str561, ei_gb2312},
+-#line 272 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str562, ei_jisx0208},
+-    {-1}, {-1}, {-1},
+-#line 240 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str566, ei_cp1133},
+-    {-1}, {-1},
+-#line 213 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str569, ei_mac_centraleurope},
+-#line 279 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str570, ei_jisx0212},
+-#line 310 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str571, ei_iso2022_jp2},
+-    {-1},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str76, ei_ascii},
+ #line 46 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str573, ei_utf7},
+-#line 50 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str574, ei_ucs4swapped},
+-    {-1}, {-1}, {-1},
+-#line 28 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str578, ei_ucs2be},
+-#line 261 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str579, ei_iso646_jp},
+-#line 257 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str580, ei_iso646_jp},
+-    {-1},
+-#line 73 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str582, ei_iso8859_3},
+-    {-1}, {-1}, {-1},
+-#line 204 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str586, ei_cp862},
+-    {-1},
+-#line 340 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str588, ei_big5hkscs2004},
+-#line 96 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str589, ei_iso8859_6},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str77, ei_utf7},
+ #line 48 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str590, ei_ucs2swapped},
+-#line 55 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str591, ei_iso8859_1},
+-    {-1},
+-#line 339 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str593, ei_big5hkscs2004},
+-#line 42 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str594, ei_utf32be},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 307 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str604, ei_iso2022_jp},
+-    {-1}, {-1},
+-#line 169 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str607, ei_koi8_u},
+-#line 245 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str608, ei_tis620},
+-    {-1}, {-1}, {-1},
+-#line 170 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str612, ei_koi8_ru},
+-    {-1},
+-#line 65 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str614, ei_iso8859_2},
+-    {-1}, {-1}, {-1},
+-#line 216 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str618, ei_mac_romania},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 274 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str641, ei_jisx0212},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 344 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str648, ei_euc_kr},
+-#line 217 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str649, ei_mac_cyrillic},
+-#line 106 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str650, ei_iso8859_7},
+-#line 191 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str651, ei_cp1256},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 182 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str657, ei_cp1253},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 295 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str666, ei_ksc5601},
+-    {-1},
+-#line 262 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str668, ei_jisx0201},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 105 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str673, ei_iso8859_7},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 311 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str683, ei_iso2022_jp2},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1},
+-#line 266 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str696, ei_jisx0208},
+-#line 263 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str697, ei_jisx0201},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 276 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str706, ei_jisx0212},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1},
+-#line 308 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str717, ei_iso2022_jp},
+-    {-1}, {-1}, {-1},
+-#line 347 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str721, ei_johab},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 304 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str730, ei_sjis},
+-    {-1}, {-1}, {-1},
+-#line 273 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str734, ei_jisx0208},
+-    {-1}, {-1},
+-#line 220 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str737, ei_mac_turkish},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 256 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str755, ei_tcvn},
+-#line 267 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str756, ei_jisx0208},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 329 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str762, ei_euc_tw},
+-#line 219 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str763, ei_mac_greek},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 268 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str770, ei_jisx0208},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 194 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str776, ei_cp1257},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1},
+-#line 185 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str790, ei_cp1254},
+-    {-1},
+-#line 218 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str792, ei_mac_ukraine},
+-    {-1}, {-1}, {-1},
+-#line 222 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str796, ei_mac_arabic},
+-    {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 200 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str802, ei_cp850},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str78, ei_ucs2swapped},
++#line 49 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str79, ei_ucs4internal},
++#line 22 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str80, ei_ascii},
+     {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 221 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str845, ei_mac_hebrew},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
++#line 36 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str87, ei_ucs4be},
++#line 78 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str88, ei_cp1250},
+     {-1}, {-1}, {-1},
+-#line 275 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str903, ei_jisx0212},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
++#line 54 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str92, ei_iso8859_1},
++#line 50 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str93, ei_ucs4swapped},
+     {-1}, {-1}, {-1},
+-#line 338 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str979, ei_big5hkscs2001},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 341 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str986, ei_big5hkscs2004},
+-    {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+-#line 337 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str995, ei_big5hkscs1999},
+-    {-1},
+-#line 300 "lib/aliases.gperf"
+-    {(int)(long)&((struct stringpool_t *)0)->stringpool_str997, ei_euc_jp}
++#line 67 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str97, ei_iso8859_2},
++#line 59 "lib/aliases.gperf"
++    {(int)(long)&((struct stringpool_t *)0)->stringpool_str98, ei_iso8859_1}
+   };
+ 
+ #ifdef __GNUC__
+--- a/lib/canonical_dos.h
++++ b/lib/canonical_dos.h
+@@ -1,15 +1 @@
+   (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_0,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_4,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_5,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_8,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_12,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_13,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_17,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_21,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_22,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_26,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_31,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_35,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_38,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_42,
+-  (int)(long)&((struct stringpool2_t *)0)->stringpool_dos_47,
+--- a/lib/canonical.h
++++ b/lib/canonical.h
+@@ -1,107 +1 @@
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str380,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str297,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str263,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str476,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str295,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str231,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str460,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str279,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str272,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str510,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str329,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str381,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str594,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str413,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str433,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str320,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str590,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str304,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str574,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str157,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str489,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str117,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str163,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str235,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str131,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str135,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str113,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str281,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str145,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str149,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str270,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str124,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str242,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str138,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str142,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str120,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str245,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str607,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str612,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str324,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str178,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str224,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str296,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str192,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str196,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str174,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str342,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str206,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str308,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str197,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str147,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str528,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str569,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str504,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str547,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str618,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str649,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str792,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str763,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str737,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str845,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str796,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str372,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str298,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str387,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str397,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str291,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str211,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str277,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str116,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str283,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str323,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str233,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str249,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str252,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str156,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str580,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str668,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str696,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str641,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str284,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str345,
+   (int)(long)&((struct stringpool_t *)0)->stringpool_str77,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str435,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str555,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str421,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str260,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str604,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str548,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str571,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str278,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str426,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str210,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str354,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str327,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str340,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str18,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str470,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str241,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str310,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str995,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str979,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str593,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str356,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str194,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str721,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str405,
+--- a/lib/canonical_local.h
++++ b/lib/canonical_local.h
+@@ -1,2 +1 @@
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str169,
+-  (int)(long)&((struct stringpool_t *)0)->stringpool_str267,
++
+--- a/lib/converters.h
++++ b/lib/converters.h
+@@ -129,161 +129,15 @@ struct conv_struct {
+ #include "ucs2swapped.h"
+ #include "ucs4internal.h"
+ #include "ucs4swapped.h"
+-#include "c99.h"
+-#include "java.h"
+ 
+ /* 8-bit encodings */
+ #include "iso8859_1.h"
+ #include "iso8859_2.h"
+-#include "iso8859_3.h"
+-#include "iso8859_4.h"
+-#include "iso8859_5.h"
+-#include "iso8859_6.h"
+-#include "iso8859_7.h"
+-#include "iso8859_8.h"
+-#include "iso8859_9.h"
+-#include "iso8859_10.h"
+-#include "iso8859_11.h"
+-#include "iso8859_13.h"
+-#include "iso8859_14.h"
+ #include "iso8859_15.h"
+-#include "iso8859_16.h"
+ #include "koi8_r.h"
+-#include "koi8_u.h"
+-#include "koi8_ru.h"
+ #include "cp1250.h"
+-#include "cp1251.h"
+-#include "cp1252.h"
+-#include "cp1253.h"
+-#include "cp1254.h"
+-#include "cp1255.h"
+-#include "cp1256.h"
+-#include "cp1257.h"
+-#include "cp1258.h"
+ #include "cp850.h"
+-#include "cp862.h"
+-#include "cp866.h"
+-#include "mac_roman.h"
+-#include "mac_centraleurope.h"
+-#include "mac_iceland.h"
+-#include "mac_croatian.h"
+-#include "mac_romania.h"
+-#include "mac_cyrillic.h"
+-#include "mac_ukraine.h"
+-#include "mac_greek.h"
+-#include "mac_turkish.h"
+-#include "mac_hebrew.h"
+-#include "mac_arabic.h"
+-#include "mac_thai.h"
+-#include "hp_roman8.h"
+-#include "nextstep.h"
+-#include "armscii_8.h"
+-#include "georgian_academy.h"
+-#include "georgian_ps.h"
+-#include "koi8_t.h"
+-#include "pt154.h"
+-#include "mulelao.h"
+-#include "cp1133.h"
+-#include "tis620.h"
+-#include "cp874.h"
+-#include "viscii.h"
+-#include "tcvn.h"
+-
+-/* CJK character sets [CCS = coded character set] [CJKV.INF chapter 3] */
+-
+-typedef struct {
+-  unsigned short indx; /* index into big table */
+-  unsigned short used; /* bitmask of used entries */
+-} Summary16;
+-
+-#include "iso646_jp.h"
+-#include "jisx0201.h"
+-#include "jisx0208.h"
+-#include "jisx0212.h"
+-
+-#include "iso646_cn.h"
+-#include "gb2312.h"
+-#include "isoir165.h"
+-/*#include "gb12345.h"*/
+-#include "gbk.h"
+-#include "cns11643.h"
+-#include "big5.h"
+-
+-#include "ksc5601.h"
+-#include "johab_hangul.h"
+-
+-/* CJK encodings [CES = character encoding scheme] [CJKV.INF chapter 4] */
+-
+-#include "euc_jp.h"
+-#include "sjis.h"
+-#include "cp932.h"
+-#include "iso2022_jp.h"
+-#include "iso2022_jp1.h"
+-#include "iso2022_jp2.h"
+-
+-#include "euc_cn.h"
+-#include "ces_gbk.h"
+-#include "cp936.h"
+-#include "gb18030.h"
+-#include "iso2022_cn.h"
+-#include "iso2022_cnext.h"
+-#include "hz.h"
+-#include "euc_tw.h"
+-#include "ces_big5.h"
+-#include "cp950.h"
+-#include "big5hkscs1999.h"
+-#include "big5hkscs2001.h"
+-#include "big5hkscs2004.h"
+-
+-#include "euc_kr.h"
+-#include "cp949.h"
+-#include "johab.h"
+-#include "iso2022_kr.h"
+-
+-/* Encodings used by system dependent locales. */
+-
+-#ifdef USE_AIX
+-#include "cp856.h"
+-#include "cp922.h"
+-#include "cp943.h"
+-#include "cp1046.h"
+-#include "cp1124.h"
+-#include "cp1129.h"
+-#include "cp1161.h"
+-#include "cp1162.h"
+-#include "cp1163.h"
+-#endif
+-
+-#ifdef USE_OSF1
+-#include "dec_kanji.h"
+-#include "dec_hanyu.h"
+-#endif
+ 
+ #ifdef USE_DOS
+ #include "cp437.h"
+-#include "cp737.h"
+-#include "cp775.h"
+-#include "cp852.h"
+-#include "cp853.h"
+-#include "cp855.h"
+-#include "cp857.h"
+-#include "cp858.h"
+-#include "cp860.h"
+-#include "cp861.h"
+-#include "cp863.h"
+-#include "cp864.h"
+-#include "cp865.h"
+-#include "cp869.h"
+-#include "cp1125.h"
+-#endif
+-
+-#ifdef USE_EXTRA
+-#include "euc_jisx0213.h"
+-#include "shift_jisx0213.h"
+-#include "iso2022_jp3.h"
+-#include "big5_2003.h"
+-#include "tds565.h"
+-#include "atarist.h"
+-#include "riscos1.h"
+ #endif
+-
+--- a/lib/encodings.def
++++ b/lib/encodings.def
+@@ -161,16 +161,6 @@ DEFENCODING(( "UCS-4-SWAPPED",
+             ucs4swapped,
+             { ucs4swapped_mbtowc, NULL }, { ucs4swapped_wctomb, NULL })
+ 
+-DEFENCODING(( "C99",
+-            ),
+-            c99,
+-            { c99_mbtowc, NULL },         { c99_wctomb, NULL })
+-
+-DEFENCODING(( "JAVA",
+-            ),
+-            java,
+-            { java_mbtowc, NULL },        { java_wctomb, NULL })
+-
+ /* Standard 8-bit encodings */
+ 
+ DEFENCODING(( "ISO-8859-1",             /* IANA */
+@@ -203,148 +193,6 @@ DEFENCODING(( "ISO-8859-2",
+             iso8859_2,
+             { iso8859_2_mbtowc, NULL },   { iso8859_2_wctomb, NULL })
+ 
+-DEFENCODING(( "ISO-8859-3",             /* IANA */
+-              "ISO_8859-3",             /* IANA */
+-              "ISO_8859-3:1988",        /* IANA */
+-              "ISO-IR-109",             /* IANA */
+-              "LATIN3",                 /* IANA */
+-              "L3",                     /* IANA */
+-              "csISOLatin3",            /* IANA */
+-              "ISO8859-3",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_3",                 JDK 1.1 */
+-            /*"CP28593",                   Windows */
+-            ),
+-            iso8859_3,
+-            { iso8859_3_mbtowc, NULL },   { iso8859_3_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-4",             /* IANA */
+-              "ISO_8859-4",             /* IANA */
+-              "ISO_8859-4:1988",        /* IANA */
+-              "ISO-IR-110",             /* IANA */
+-              "LATIN4",                 /* IANA */
+-              "L4",                     /* IANA */
+-              "csISOLatin4",            /* IANA */
+-              "ISO8859-4",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_4",                 JDK 1.1 */
+-            /*"CP28594",                   Windows */
+-            ),
+-            iso8859_4,
+-            { iso8859_4_mbtowc, NULL },   { iso8859_4_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-5",             /* IANA */
+-              "ISO_8859-5",             /* IANA */
+-              "ISO_8859-5:1988",        /* IANA */
+-              "ISO-IR-144",             /* IANA */
+-              "CYRILLIC",               /* IANA */
+-              "csISOLatinCyrillic",     /* IANA */
+-              "ISO8859-5",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_5",                 JDK 1.1 */
+-            /*"CP28595",                   Windows */
+-            ),
+-            iso8859_5,
+-            { iso8859_5_mbtowc, NULL },   { iso8859_5_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-6",             /* IANA */
+-              "ISO_8859-6",             /* IANA */
+-              "ISO_8859-6:1987",        /* IANA */
+-              "ISO-IR-127",             /* IANA */
+-              "ECMA-114",               /* IANA */
+-              "ASMO-708",               /* IANA */
+-              "ARABIC",                 /* IANA */
+-              "csISOLatinArabic",       /* IANA */
+-              "ISO8859-6",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_6",                 JDK 1.1 */
+-            /*"CP28596",                   Windows */
+-            ),
+-            iso8859_6,
+-            { iso8859_6_mbtowc, NULL },   { iso8859_6_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-7",             /* IANA, RFC 1947 */
+-              "ISO_8859-7",             /* IANA */
+-              "ISO_8859-7:1987",        /* IANA */
+-              "ISO_8859-7:2003",
+-              "ISO-IR-126",             /* IANA */
+-              "ECMA-118",               /* IANA */
+-              "ELOT_928",               /* IANA */
+-              "GREEK8",                 /* IANA */
+-              "GREEK",                  /* IANA */
+-              "csISOLatinGreek",        /* IANA */
+-              "ISO8859-7",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_7",                 JDK 1.1 */
+-            /*"CP28597",                   Windows */
+-            ),
+-            iso8859_7,
+-            { iso8859_7_mbtowc, NULL },   { iso8859_7_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-8",             /* IANA */
+-              "ISO_8859-8",             /* IANA */
+-              "ISO_8859-8:1988",        /* IANA */
+-              "ISO-IR-138",             /* IANA */
+-              "HEBREW",                 /* IANA */
+-              "csISOLatinHebrew",       /* IANA */
+-              "ISO8859-8",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_8",                 JDK 1.1 */
+-            /*"CP28598",                   Windows */
+-            /*"CP38598",                   Windows */
+-            ),
+-            iso8859_8,
+-            { iso8859_8_mbtowc, NULL },   { iso8859_8_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-9",             /* IANA */
+-              "ISO_8859-9",             /* IANA */
+-              "ISO_8859-9:1989",        /* IANA */
+-              "ISO-IR-148",             /* IANA */
+-              "LATIN5",                 /* IANA */
+-              "L5",                     /* IANA */
+-              "csISOLatin5",            /* IANA */
+-              "ISO8859-9",              /* X11R6.4, glibc, FreeBSD */
+-            /*"ISO8859_9",                 JDK 1.1 */
+-            /*"CP28599",                   Windows */
+-            ),
+-            iso8859_9,
+-            { iso8859_9_mbtowc, NULL },   { iso8859_9_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-10",            /* IANA */
+-              "ISO_8859-10",
+-              "ISO_8859-10:1992",       /* IANA */
+-              "ISO-IR-157",             /* IANA */
+-              "LATIN6",                 /* IANA */
+-              "L6",                     /* IANA */
+-              "csISOLatin6",            /* IANA */
+-              "ISO8859-10",             /* X11R6.4, glibc, FreeBSD */
+-            ),
+-            iso8859_10,
+-            { iso8859_10_mbtowc, NULL },  { iso8859_10_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-11",            /* glibc */
+-              "ISO_8859-11",
+-              "ISO8859-11",             /* X11R6.7, glibc */
+-            ),
+-            iso8859_11,
+-            { iso8859_11_mbtowc, NULL },  { iso8859_11_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-13",            /* IANA, glibc */
+-              "ISO_8859-13",
+-              "ISO-IR-179",             /* glibc */
+-              "LATIN7",                 /* glibc */
+-              "L7",                     /* glibc */
+-              "ISO8859-13",             /* glibc, FreeBSD */
+-            ),
+-            iso8859_13,
+-            { iso8859_13_mbtowc, NULL },  { iso8859_13_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-8859-14",            /* IANA, glibc */
+-              "ISO_8859-14",            /* IANA */
+-              "ISO_8859-14:1998",       /* IANA, glibc */
+-              "ISO-IR-199",             /* IANA */
+-              "LATIN8",                 /* IANA, glibc */
+-              "L8",                     /* IANA, glibc */
+-              "ISO-CELTIC",             /* IANA */
+-              "ISO8859-14",             /* glibc, FreeBSD */
+-            ),
+-            iso8859_14,
+-            { iso8859_14_mbtowc, NULL },  { iso8859_14_wctomb, NULL })
+-
+ DEFENCODING(( "ISO-8859-15",            /* IANA, glibc */
+               "ISO_8859-15",            /* IANA */
+               "ISO_8859-15:1998",       /* glibc */
+@@ -356,17 +204,6 @@ DEFENCODING(( "ISO-8859-15",
+             iso8859_15,
+             { iso8859_15_mbtowc, NULL },  { iso8859_15_wctomb, NULL })
+ 
+-DEFENCODING(( "ISO-8859-16",            /* IANA */
+-              "ISO_8859-16",            /* IANA */
+-              "ISO_8859-16:2001",       /* IANA */
+-              "ISO-IR-226",             /* IANA */
+-              "LATIN10",                /* IANA */
+-              "L10",                    /* IANA */
+-              "ISO8859-16",             /* glibc, FreeBSD */
+-            ),
+-            iso8859_16,
+-            { iso8859_16_mbtowc, NULL },  { iso8859_16_wctomb, NULL })
+-
+ DEFENCODING(( "KOI8-R",                 /* IANA, RFC 1489, X11R6.4, JDK 1.1 */
+               "csKOI8R",                /* IANA */
+             /*"CP20866",                   Windows */
+@@ -374,16 +211,6 @@ DEFENCODING(( "KOI8-R",
+             koi8_r,
+             { koi8_r_mbtowc, NULL },      { koi8_r_wctomb, NULL })
+ 
+-DEFENCODING(( "KOI8-U",                 /* IANA, RFC 2319 */
+-            ),
+-            koi8_u,
+-            { koi8_u_mbtowc, NULL },      { koi8_u_wctomb, NULL })
+-
+-DEFENCODING(( "KOI8-RU",
+-            ),
+-            koi8_ru,
+-            { koi8_ru_mbtowc, NULL },     { koi8_ru_wctomb, NULL })
+-
+ /* Windows 8-bit encodings */
+ 
+ DEFENCODING(( "CP1250",                 /* JDK 1.1 */
+@@ -393,61 +220,6 @@ DEFENCODING(( "CP1250",
+             cp1250,
+             { cp1250_mbtowc, NULL },      { cp1250_wctomb, NULL })
+ 
+-DEFENCODING(( "CP1251",                 /* JDK 1.1 */
+-              "WINDOWS-1251",           /* IANA */
+-              "MS-CYRL",
+-            ),
+-            cp1251,
+-            { cp1251_mbtowc, NULL },      { cp1251_wctomb, NULL })
+-
+-DEFENCODING(( "CP1252",                 /* JDK 1.1 */
+-              "WINDOWS-1252",           /* IANA */
+-              "MS-ANSI",
+-            ),
+-            cp1252,
+-            { cp1252_mbtowc, NULL },      { cp1252_wctomb, NULL })
+-
+-DEFENCODING(( "CP1253",                 /* JDK 1.1 */
+-              "WINDOWS-1253",           /* IANA */
+-              "MS-GREEK",
+-            ),
+-            cp1253,
+-            { cp1253_mbtowc, NULL },      { cp1253_wctomb, NULL })
+-
+-DEFENCODING(( "CP1254",                 /* JDK 1.1 */
+-              "WINDOWS-1254",           /* IANA */
+-              "MS-TURK",
+-            ),
+-            cp1254,
+-            { cp1254_mbtowc, NULL },      { cp1254_wctomb, NULL })
+-
+-DEFENCODING(( "CP1255",                 /* JDK 1.1 */
+-              "WINDOWS-1255",           /* IANA */
+-              "MS-HEBR",
+-            ),
+-            cp1255,
+-            { cp1255_mbtowc, cp1255_flushwc }, { cp1255_wctomb, NULL })
+-
+-DEFENCODING(( "CP1256",                 /* JDK 1.1 */
+-              "WINDOWS-1256",           /* IANA */
+-              "MS-ARAB",
+-            ),
+-            cp1256,
+-            { cp1256_mbtowc, NULL },      { cp1256_wctomb, NULL })
+-
+-DEFENCODING(( "CP1257",                 /* JDK 1.1 */
+-              "WINDOWS-1257",           /* IANA */
+-              "WINBALTRIM",
+-            ),
+-            cp1257,
+-            { cp1257_mbtowc, NULL },      { cp1257_wctomb, NULL })
+-
+-DEFENCODING(( "CP1258",                 /* JDK 1.1 */
+-              "WINDOWS-1258",           /* IANA */
+-            ),
+-            cp1258,
+-            { cp1258_mbtowc, cp1258_flushwc }, { cp1258_wctomb, NULL })
+-
+ /* DOS 8-bit encodings */
+ 
+ DEFENCODING(( "CP850",                  /* IANA, JDK 1.1 */
+@@ -458,431 +230,3 @@ DEFENCODING(( "CP850",
+             cp850,
+             { cp850_mbtowc, NULL },       { cp850_wctomb, NULL })
+ 
+-DEFENCODING(( "CP862",                  /* IANA, JDK 1.1 */
+-              "IBM862",                 /* IANA */
+-              "862",                    /* IANA */
+-              "csPC862LatinHebrew",     /* IANA */
+-            ),
+-            cp862,
+-            { cp862_mbtowc, NULL },       { cp862_wctomb, NULL })
+-
+-DEFENCODING(( "CP866",                  /* IANA, JDK 1.1 */
+-              "IBM866",                 /* IANA */
+-              "866",                    /* IANA */
+-              "csIBM866",               /* IANA */
+-            ),
+-            cp866,
+-            { cp866_mbtowc, NULL },       { cp866_wctomb, NULL })
+-
+-/* Macintosh 8-bit encodings */
+-
+-DEFENCODING(( "MacRoman",               /* JDK 1.1 */
+-              /* This is the best table for MACINTOSH. The ones */
+-              /* in glibc and FreeBSD-iconv are bad quality. */
+-              "MACINTOSH",              /* IANA */
+-              "MAC",                    /* IANA */
+-              "csMacintosh",            /* IANA */
+-            /*"CP10000",                   Windows */
+-            ),
+-            mac_roman,
+-            { mac_roman_mbtowc, NULL },   { mac_roman_wctomb, NULL })
+-
+-DEFENCODING(( "MacCentralEurope",       /* JDK 1.1 */
+-            /*"CP10029",                   Windows */
+-            ),
+-            mac_centraleurope,
+-            { mac_centraleurope_mbtowc, NULL }, { mac_centraleurope_wctomb, NULL })
+-
+-DEFENCODING(( "MacIceland",             /* JDK 1.1 */
+-            /*"CP10079",                   Windows */
+-            ),
+-            mac_iceland,
+-            { mac_iceland_mbtowc, NULL }, { mac_iceland_wctomb, NULL })
+-
+-DEFENCODING(( "MacCroatian",            /* JDK 1.1 */
+-            /*"CP10082",                   Windows */
+-            ),
+-            mac_croatian,
+-            { mac_croatian_mbtowc, NULL }, { mac_croatian_wctomb, NULL })
+-
+-DEFENCODING(( "MacRomania",             /* JDK 1.1 */
+-            /*"CP10010",                   Windows */
+-            ),
+-            mac_romania,
+-            { mac_romania_mbtowc, NULL }, { mac_romania_wctomb, NULL })
+-
+-DEFENCODING(( "MacCyrillic",            /* JDK 1.1 */
+-            /*"CP10007",                   Windows */
+-            ),
+-            mac_cyrillic,
+-            { mac_cyrillic_mbtowc, NULL }, { mac_cyrillic_wctomb, NULL })
+-
+-DEFENCODING(( "MacUkraine",             /* JDK 1.1 */
+-            /*"CP10017",                   Windows */
+-            ),
+-            mac_ukraine,
+-            { mac_ukraine_mbtowc, NULL }, { mac_ukraine_wctomb, NULL })
+-
+-DEFENCODING(( "MacGreek",               /* JDK 1.1 */
+-            /*"CP10006",                   Windows */
+-            ),
+-            mac_greek,
+-            { mac_greek_mbtowc, NULL },   { mac_greek_wctomb, NULL })
+-
+-DEFENCODING(( "MacTurkish",             /* JDK 1.1 */
+-            /*"CP10081",                   Windows */
+-            ),
+-            mac_turkish,
+-            { mac_turkish_mbtowc, NULL }, { mac_turkish_wctomb, NULL })
+-
+-DEFENCODING(( "MacHebrew",              /* JDK 1.1 */
+-            /*"CP10005",                   Windows */
+-            ),
+-            mac_hebrew,
+-            { mac_hebrew_mbtowc, NULL },  { mac_hebrew_wctomb, NULL })
+-
+-DEFENCODING(( "MacArabic",              /* JDK 1.1 */
+-            /*"CP10004",                   Windows */
+-            ),
+-            mac_arabic,
+-            { mac_arabic_mbtowc, NULL },  { mac_arabic_wctomb, NULL })
+-
+-DEFENCODING(( "MacThai",                /* JDK 1.1 */
+-            /*"CP10021",                   Windows */
+-            ),
+-            mac_thai,
+-            { mac_thai_mbtowc, NULL },    { mac_thai_wctomb, NULL })
+-
+-/* Other platform specific 8-bit encodings */
+-
+-DEFENCODING(( "HP-ROMAN8",              /* IANA, X11R6.4 */
+-              "ROMAN8",                 /* IANA */
+-              "R8",                     /* IANA */
+-              "csHPRoman8",             /* IANA */
+-            ),
+-            hp_roman8,
+-            { hp_roman8_mbtowc, NULL },   { hp_roman8_wctomb, NULL })
+-
+-DEFENCODING(( "NEXTSTEP",
+-            ),
+-            nextstep,
+-            { nextstep_mbtowc, NULL },    { nextstep_wctomb, NULL })
+-
+-/* Regional 8-bit encodings used for a single language */
+-
+-DEFENCODING(( "ARMSCII-8",
+-            ),
+-            armscii_8,
+-            { armscii_8_mbtowc, NULL },   { armscii_8_wctomb, NULL })
+-
+-DEFENCODING(( "GEORGIAN-ACADEMY",
+-            ),
+-            georgian_academy,
+-            { georgian_academy_mbtowc, NULL }, { georgian_academy_wctomb, NULL })
+-
+-DEFENCODING(( "GEORGIAN-PS",
+-            ),
+-            georgian_ps,
+-            { georgian_ps_mbtowc, NULL }, { georgian_ps_wctomb, NULL })
+-
+-DEFENCODING(( "KOI8-T",
+-            ),
+-            koi8_t,
+-            { koi8_t_mbtowc, NULL },      { koi8_t_wctomb, NULL })
+-
+-DEFENCODING(( "PT154",                  /* IANA, glibc */
+-              "PTCP154",                /* IANA */
+-              "CP154",                  /* IANA */
+-              "CYRILLIC-ASIAN",         /* IANA */
+-              "csPTCP154",              /* IANA */
+-            ),
+-            pt154,
+-            { pt154_mbtowc, NULL },       { pt154_wctomb, NULL })
+-
+-DEFENCODING(( "MULELAO-1",
+-            ),
+-            mulelao,
+-            { mulelao_mbtowc, NULL },     { mulelao_wctomb, NULL })
+-
+-DEFENCODING(( "CP1133",
+-              "IBM-CP1133",
+-            ),
+-            cp1133,
+-            { cp1133_mbtowc, NULL },      { cp1133_wctomb, NULL })
+-
+-DEFENCODING(( "TIS-620",                /* IANA */
+-              "TIS620",                 /* glibc */
+-              "TIS620-0",               /* glibc */
+-              "TIS620.2529-1",          /* glibc */
+-              "TIS620.2533-0",          /* glibc */
+-              "TIS620.2533-1",
+-              "ISO-IR-166",             /* glibc */
+-            ),
+-            tis620,
+-            { tis620_mbtowc, NULL },      { tis620_wctomb, NULL })
+-
+-DEFENCODING(( "CP874",                  /* JDK 1.1 */
+-              "WINDOWS-874",
+-            ),
+-            cp874,
+-            { cp874_mbtowc, NULL },       { cp874_wctomb, NULL })
+-
+-DEFENCODING(( "VISCII",                 /* IANA, RFC 1456 */
+-              "VISCII1.1-1",
+-              "csVISCII",               /* IANA */
+-            ),
+-            viscii,
+-            { viscii_mbtowc, NULL },      { viscii_wctomb, NULL })
+-
+-DEFENCODING(( "TCVN",
+-              "TCVN-5712",
+-              "TCVN5712-1",
+-              "TCVN5712-1:1993",
+-            ),
+-            tcvn,
+-            { tcvn_mbtowc, tcvn_flushwc }, { tcvn_wctomb, NULL })
+-
+-/* CJK character sets (not documented) */
+-
+-DEFENCODING(( "JIS_C6220-1969-RO",      /* IANA */
+-              "ISO646-JP",              /* IANA */
+-              "ISO-IR-14",              /* IANA */
+-              "JP",                     /* IANA */
+-              "csISO14JISC6220ro",      /* IANA */
+-            ),
+-            iso646_jp,
+-            { iso646_jp_mbtowc, NULL },   { iso646_jp_wctomb, NULL })
+-
+-DEFENCODING(( "JIS_X0201",              /* IANA */
+-              "JISX0201-1976",
+-              "X0201",                  /* IANA */
+-              "csHalfWidthKatakana",    /* IANA */
+-            /*"JISX0201.1976-0",           X11R6.4 */
+-            /*"JIS0201",                   JDK 1.1 */
+-            ),
+-            jisx0201,
+-            { jisx0201_mbtowc, NULL },    { jisx0201_wctomb, NULL })
+-
+-DEFENCODING(( "JIS_X0208",
+-              "JIS_X0208-1983",         /* IANA */
+-              "JIS_X0208-1990",
+-              "JIS0208",
+-              "X0208",                  /* IANA */
+-              "ISO-IR-87",              /* IANA */
+-              "JIS_C6226-1983",         /* IANA */
+-              "csISO87JISX0208",        /* IANA */
+-            /*"JISX0208.1983-0",           X11R6.4 */
+-            /*"JISX0208.1990-0",           X11R6.4 */
+-            /*"JIS0208",                   JDK 1.1 */
+-            ),
+-            jisx0208,
+-            { jisx0208_mbtowc, NULL },    { jisx0208_wctomb, NULL })
+-
+-DEFENCODING(( "JIS_X0212",
+-              "JIS_X0212.1990-0",
+-              "JIS_X0212-1990",         /* IANA */
+-              "X0212",                  /* IANA */
+-              "ISO-IR-159",             /* IANA */
+-              "csISO159JISX02121990",   /* IANA */
+-            /*"JISX0212.1990-0",           X11R6.4 */
+-            /*"JIS0212",                   JDK 1.1 */
+-            ),
+-            jisx0212,
+-            { jisx0212_mbtowc, NULL },    { jisx0212_wctomb, NULL })
+-
+-DEFENCODING(( "GB_1988-80",             /* IANA */
+-              "ISO646-CN",              /* IANA */
+-              "ISO-IR-57",              /* IANA */
+-              "CN",                     /* IANA */
+-              "csISO57GB1988",          /* IANA */
+-            ),
+-            iso646_cn,
+-            { iso646_cn_mbtowc, NULL },   { iso646_cn_wctomb, NULL })
+-
+-DEFENCODING(( "GB_2312-80",             /* IANA */
+-              "ISO-IR-58",              /* IANA */
+-              "csISO58GB231280",        /* IANA */
+-              "CHINESE",                /* IANA */
+-            /*"GB2312.1980-0",             X11R6.4 */
+-            ),
+-            gb2312,
+-            { gb2312_mbtowc, NULL },      { gb2312_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-IR-165",
+-              "CN-GB-ISOIR165",         /* RFC 1922 */
+-            ),
+-            isoir165,
+-            { isoir165_mbtowc, NULL },    { isoir165_wctomb, NULL })
+-
+-DEFENCODING(( "KSC_5601",               /* IANA */
+-              "KS_C_5601-1987",         /* IANA */
+-              "KS_C_5601-1989",         /* IANA */
+-              "ISO-IR-149",             /* IANA */
+-              "csKSC56011987",          /* IANA */
+-              "KOREAN",                 /* IANA */
+-            /*"KSC5601.1987-0",            X11R6.4 */
+-            /*"KSX1001:1992",              Ken Lunde */
+-            ),
+-            ksc5601,
+-            { ksc5601_mbtowc, NULL },     { ksc5601_wctomb, NULL })
+-
+-/* CJK encodings */
+-
+-DEFENCODING(( "EUC-JP",                 /* IANA */
+-              "EUCJP",                  /* glibc */
+-              "Extended_UNIX_Code_Packed_Format_for_Japanese", /* IANA */
+-              "csEUCPkdFmtJapanese",    /* IANA */
+-            /*"EUC_JP",                    JDK 1.1 */
+-            /*"CP51932",                   Windows */
+-            ),
+-            euc_jp,
+-            { euc_jp_mbtowc, NULL },      { euc_jp_wctomb, NULL })
+-
+-DEFENCODING(( "SHIFT_JIS",              /* IANA */
+-              "SHIFT-JIS",              /* glibc */
+-              "SJIS",                   /* JDK 1.1 */
+-              "MS_KANJI",               /* IANA */
+-              "csShiftJIS",             /* IANA */
+-            ),
+-            sjis,
+-            { sjis_mbtowc, NULL },        { sjis_wctomb, NULL })
+-
+-DEFENCODING(( "CP932",                  /* glibc */
+-            ),
+-            cp932,
+-            { cp932_mbtowc, NULL },       { cp932_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-2022-JP",            /* IANA, RFC 1468 */
+-              "csISO2022JP",            /* IANA */
+-            /*"ISO2022JP",                 JDK 1.1 */
+-            ),
+-            iso2022_jp,
+-            { iso2022_jp_mbtowc, NULL },  { iso2022_jp_wctomb, iso2022_jp_reset })
+-
+-DEFENCODING(( "ISO-2022-JP-1",          /* RFC 2237 */
+-            ),
+-            iso2022_jp1,
+-            { iso2022_jp1_mbtowc, NULL }, { iso2022_jp1_wctomb, iso2022_jp1_reset })
+-
+-DEFENCODING(( "ISO-2022-JP-2",          /* IANA, RFC 1554 */
+-              "csISO2022JP2",           /* IANA */
+-            ),
+-            iso2022_jp2,
+-            { iso2022_jp2_mbtowc, NULL }, { iso2022_jp2_wctomb, iso2022_jp2_reset })
+-
+-DEFENCODING(( "EUC-CN",                 /* glibc */
+-              "EUCCN",                  /* glibc */
+-              "GB2312",                 /* IANA */
+-              "CN-GB",                  /* RFC 1922 */
+-              "csGB2312",               /* IANA */
+-            /*"EUC_CN",                    JDK 1.1 */
+-            /*"CP51936",                   Windows */
+-            ),
+-            euc_cn,
+-            { euc_cn_mbtowc, NULL },      { euc_cn_wctomb, NULL })
+-
+-DEFENCODING(( "GBK",                    /* IANA, JDK 1.1 */
+-            ),
+-            ces_gbk,
+-            { ces_gbk_mbtowc, NULL },     { ces_gbk_wctomb, NULL })
+-
+-DEFENCODING(( "CP936",                  /* IANA */
+-              "MS936",                  /* IANA */
+-              "WINDOWS-936",            /* IANA */
+-            ),
+-            cp936,
+-            { cp936_mbtowc, NULL },       { cp936_wctomb, NULL })
+-
+-DEFENCODING(( "GB18030",                /* IANA, glibc */
+-            /*"CP54936",                   Windows */
+-            ),
+-            gb18030,
+-            { gb18030_mbtowc, NULL },     { gb18030_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-2022-CN",            /* IANA, RFC 1922 */
+-              "csISO2022CN",
+-            /*"ISO2022CN",                 JDK 1.1 */
+-            ),
+-            iso2022_cn,
+-            { iso2022_cn_mbtowc, NULL },  { iso2022_cn_wctomb, iso2022_cn_reset })
+-
+-DEFENCODING(( "ISO-2022-CN-EXT",        /* IANA, RFC 1922 */
+-            ),
+-            iso2022_cn_ext,
+-            { iso2022_cn_ext_mbtowc, NULL }, { iso2022_cn_ext_wctomb, iso2022_cn_ext_reset })
+-
+-DEFENCODING(( "HZ",                     /* RFC 1843 */
+-              "HZ-GB-2312",             /* IANA, RFC 1842 */
+-            ),
+-            hz,
+-            { hz_mbtowc, NULL },          { hz_wctomb, hz_reset })
+-
+-DEFENCODING(( "EUC-TW",                 /* glibc */
+-              "EUCTW",                  /* glibc */
+-              "csEUCTW",
+-            /*"EUC_TW",                    JDK 1.1 */
+-            /*"CP51950",                   Windows */
+-            ),
+-            euc_tw,
+-            { euc_tw_mbtowc, NULL },      { euc_tw_wctomb, NULL })
+-
+-DEFENCODING(( "BIG5",                   /* IANA, JDK 1.1 */
+-              "BIG-5",                  /* glibc */
+-              "BIG-FIVE",               /* glibc */
+-              "BIGFIVE",                /* glibc */
+-              "CN-BIG5",                /* RFC 1922 */
+-              "csBig5",                 /* IANA */
+-            ),
+-            ces_big5,
+-            { ces_big5_mbtowc, NULL },    { ces_big5_wctomb, NULL })
+-
+-DEFENCODING(( "CP950",                  /* JDK 1.1 */
+-            ),
+-            cp950,
+-            { cp950_mbtowc, NULL },       { cp950_wctomb, NULL })
+-
+-DEFENCODING(( "BIG5-HKSCS:1999",
+-            ),
+-            big5hkscs1999,
+-            { big5hkscs1999_mbtowc, big5hkscs1999_flushwc }, { big5hkscs1999_wctomb, big5hkscs1999_reset })
+-
+-DEFENCODING(( "BIG5-HKSCS:2001",
+-            ),
+-            big5hkscs2001,
+-            { big5hkscs2001_mbtowc, big5hkscs2001_flushwc }, { big5hkscs2001_wctomb, big5hkscs2001_reset })
+-
+-DEFENCODING(( "BIG5-HKSCS",             /* IANA */
+-              "BIG5HKSCS",              /* glibc */
+-              "BIG5-HKSCS:2004",
+-            ),
+-            big5hkscs2004,
+-            { big5hkscs2004_mbtowc, big5hkscs2004_flushwc }, { big5hkscs2004_wctomb, big5hkscs2004_reset })
+-
+-DEFENCODING(( "EUC-KR",                 /* IANA, RFC 1557 */
+-              "EUCKR",                  /* glibc */
+-              "csEUCKR",                /* IANA */
+-            /*"EUC_KR",                    JDK 1.1 */
+-            /*"CP51949",                   Windows */
+-            ),
+-            euc_kr,
+-            { euc_kr_mbtowc, NULL },      { euc_kr_wctomb, NULL })
+-
+-DEFENCODING(( "CP949",                  /* JDK 1.1 */
+-              "UHC",                    /* glibc */
+-            ),
+-            cp949,
+-            { cp949_mbtowc, NULL },       { cp949_wctomb, NULL })
+-
+-DEFENCODING(( "JOHAB",                  /* glibc */
+-              "CP1361",                 /* glibc */
+-            ),
+-            johab,
+-            { johab_mbtowc, NULL },       { johab_wctomb, NULL })
+-
+-DEFENCODING(( "ISO-2022-KR",            /* IANA, RFC 1557 */
+-              "csISO2022KR",            /* IANA */
+-            /*"ISO2022KR",                 JDK 1.1 */
+-            ),
+-            iso2022_kr,
+-            { iso2022_kr_mbtowc, NULL },  { iso2022_kr_wctomb, iso2022_kr_reset })
+-
+--- a/lib/encodings_dos.def
++++ b/lib/encodings_dos.def
+@@ -26,102 +26,3 @@ DEFENCODING(( "CP437",
+             cp437,
+             { cp437_mbtowc, NULL },       { cp437_wctomb, NULL })
+ 
+-DEFENCODING(( "CP737",                  /* JDK 1.1 */
+-            ),
+-            cp737,
+-            { cp737_mbtowc, NULL },       { cp737_wctomb, NULL })
+-
+-DEFENCODING(( "CP775",                  /* IANA, JDK 1.1 */
+-              "IBM775",                 /* IANA */
+-              "csPC775Baltic",          /* IANA */
+-            ),
+-            cp775,
+-            { cp775_mbtowc, NULL },       { cp775_wctomb, NULL })
+-
+-DEFENCODING(( "CP852",                  /* IANA, JDK 1.1 */
+-              "IBM852",                 /* IANA */
+-              "852",                    /* IANA */
+-              "csPCp852",               /* IANA */
+-            ),
+-            cp852,
+-            { cp852_mbtowc, NULL },       { cp852_wctomb, NULL })
+-
+-DEFENCODING(( "CP853",
+-            ),
+-            cp853,
+-            { cp853_mbtowc, NULL },       { cp853_wctomb, NULL })
+-
+-DEFENCODING(( "CP855",                  /* IANA, JDK 1.1 */
+-              "IBM855",                 /* IANA */
+-              "855",                    /* IANA */
+-              "csIBM855",               /* IANA */
+-            ),
+-            cp855,
+-            { cp855_mbtowc, NULL },       { cp855_wctomb, NULL })
+-
+-DEFENCODING(( "CP857",                  /* IANA, JDK 1.1 */
+-              "IBM857",                 /* IANA */
+-              "857",                    /* IANA */
+-              "csIBM857",               /* IANA */
+-            ),
+-            cp857,
+-            { cp857_mbtowc, NULL },       { cp857_wctomb, NULL })
+-
+-DEFENCODING(( "CP858",                  /* JDK 1.1.7 */
+-            ),
+-            cp858,
+-            { cp858_mbtowc, NULL },       { cp858_wctomb, NULL })
+-
+-DEFENCODING(( "CP860",                  /* IANA, JDK 1.1 */
+-              "IBM860",                 /* IANA */
+-              "860",                    /* IANA */
+-              "csIBM860",               /* IANA */
+-            ),
+-            cp860,
+-            { cp860_mbtowc, NULL },       { cp860_wctomb, NULL })
+-
+-DEFENCODING(( "CP861",                  /* IANA, JDK 1.1 */
+-              "IBM861",                 /* IANA */
+-              "861",                    /* IANA */
+-              "CP-IS",                  /* IANA */
+-              "csIBM861",               /* IANA */
+-            ),
+-            cp861,
+-            { cp861_mbtowc, NULL },       { cp861_wctomb, NULL })
+-
+-DEFENCODING(( "CP863",                  /* IANA, JDK 1.1 */
+-              "IBM863",                 /* IANA */
+-              "863",                    /* IANA */
+-              "csIBM863",               /* IANA */
+-            ),
+-            cp863,
+-            { cp863_mbtowc, NULL },       { cp863_wctomb, NULL })
+-
+-DEFENCODING(( "CP864",                  /* IANA, JDK 1.1 */
+-              "IBM864",                 /* IANA */
+-              "csIBM864",               /* IANA */
+-            ),
+-            cp864,
+-            { cp864_mbtowc, NULL },       { cp864_wctomb, NULL })
+-
+-DEFENCODING(( "CP865",                  /* IANA, JDK 1.1 */
+-              "IBM865",                 /* IANA */
+-              "865",                    /* IANA */
+-              "csIBM865",               /* IANA */
+-            ),
+-            cp865,
+-            { cp865_mbtowc, NULL },       { cp865_wctomb, NULL })
+-
+-DEFENCODING(( "CP869",                  /* IANA, JDK 1.1 */
+-              "IBM869",                 /* IANA */
+-              "869",                    /* IANA */
+-              "CP-GR",                  /* IANA */
+-              "csIBM869",               /* IANA */
+-            ),
+-            cp869,
+-            { cp869_mbtowc, NULL },       { cp869_wctomb, NULL })
+-
+-DEFENCODING(( "CP1125",                 /* ICU */
+-            ),
+-            cp1125,
+-            { cp1125_mbtowc, NULL },      { cp1125_wctomb, NULL })
+--- a/lib/loop_unicode.h
++++ b/lib/loop_unicode.h
+@@ -24,14 +24,15 @@
+ static int unicode_transliterate (conv_t cd, ucs4_t wc,
+                                   unsigned char* outptr, size_t outleft)
+ {
++/*
+   if (cd->oflags & HAVE_HANGUL_JAMO) {
+-    /* Decompose Hangul into Jamo. Use double-width Jamo (contained
++    /-* Decompose Hangul into Jamo. Use double-width Jamo (contained
+        in all Korean encodings and ISO-2022-JP-2), not half-width Jamo
+-       (contained in Unicode only). */
++       (contained in Unicode only). *-/
+     ucs4_t buf[3];
+     int ret = johab_hangul_decompose(cd,buf,wc);
+     if (ret != RET_ILUNI) {
+-      /* we know 1 <= ret <= 3 */
++      /-* we know 1 <= ret <= 3 *-/
+       state_t backup_state = cd->ostate;
+       unsigned char* backup_outptr = outptr;
+       size_t backup_outleft = outleft;
+@@ -57,9 +58,9 @@ static int unicode_transliterate (conv_t
+     }
+   }
+   {
+-    /* Try to use a variant, but postfix it with
++    /-* Try to use a variant, but postfix it with
+        U+303E IDEOGRAPHIC VARIATION INDICATOR
+-       (cf. Ken Lunde's "CJKV information processing", p. 188). */
++       (cf. Ken Lunde's "CJKV information processing", p. 188). *-/
+     int indx = -1;
+     if (wc == 0x3006)
+       indx = 0;
+@@ -105,20 +106,20 @@ static int unicode_transliterate (conv_t
+     }
+   }
+   if (wc >= 0x2018 && wc <= 0x201a) {
+-    /* Special case for quotation marks 0x2018, 0x2019, 0x201a */
++    /-* Special case for quotation marks 0x2018, 0x2019, 0x201a *-/
+     ucs4_t substitute =
+       (cd->oflags & HAVE_QUOTATION_MARKS
+        ? (wc == 0x201a ? 0x2018 : wc)
+        : (cd->oflags & HAVE_ACCENTS
+-          ? (wc==0x2019 ? 0x00b4 : 0x0060) /* use accents */
+-          : 0x0027 /* use apostrophe */
++          ? (wc==0x2019 ? 0x00b4 : 0x0060) /-* use accents *-/
++          : 0x0027 /-* use apostrophe *-/
+       )  );
+     int outcount = cd->ofuncs.xxx_wctomb(cd,outptr,substitute,outleft);
+     if (outcount != RET_ILUNI)
+       return outcount;
+   }
+   {
+-    /* Use the transliteration table. */
++    /-* Use the transliteration table. *-/
+     int indx = translit_index(wc);
+     if (indx >= 0) {
+       const unsigned int * cp = &translit_data[indx];
+@@ -135,7 +136,7 @@ static int unicode_transliterate (conv_t
+         }
+         sub_outcount = cd->ofuncs.xxx_wctomb(cd,outptr,cp[i],outleft);
+         if (sub_outcount == RET_ILUNI)
+-          /* Recursive transliteration. */
++          /-* Recursive transliteration. *-/
+           sub_outcount = unicode_transliterate(cd,cp[i],outptr,outleft);
+         if (sub_outcount <= RET_ILUNI)
+           goto translit_failed;
+@@ -151,6 +152,7 @@ static int unicode_transliterate (conv_t
+         return RET_TOOSMALL;
+     }
+   }
++*/
+   return RET_ILUNI;
+ }
+ 
diff --git a/package/libs/libiconv-full/patches/101-autotools.patch b/package/libs/libiconv-full/patches/101-autotools.patch
new file mode 100644
index 0000000000..f8fdce56a9
--- /dev/null
+++ b/package/libs/libiconv-full/patches/101-autotools.patch
@@ -0,0 +1,26014 @@
+--- a/libcharset/configure.ac
++++ b/libcharset/configure.ac
+@@ -16,17 +16,17 @@ dnl along with the GNU CHARSET Library;
+ dnl write to the Free Software Foundation, Inc., 51 Franklin Street,
+ dnl Fifth Floor, Boston, MA 02110-1301, USA.
+ 
+-AC_PREREQ(2.13)
++AC_PREREQ(2.61)
++AC_INIT([libcharset],[1.4] )
++AC_CONFIG_SRCDIR([lib/localcharset.c])
+ 
+-PACKAGE=libcharset
+-VERSION=1.4
+-
+-AC_INIT(lib/localcharset.c)
+ AC_CONFIG_AUX_DIR(build-aux)
+ AC_CONFIG_HEADER(config.h)
+ AC_PROG_MAKE_SET
+-AC_SUBST(PACKAGE)
+-AC_SUBST(VERSION)
++dnl AC_SUBST(PACKAGE)
++dnl AC_SUBST(VERSION)
++
++AC_CONFIG_MACRO_DIR([m4])
+ 
+ dnl           checks for basic programs
+ 
+--- a/configure.ac
++++ b/configure.ac
+@@ -24,6 +24,8 @@ AM_INIT_AUTOMAKE(libiconv, 1.11)
+ AC_CONFIG_HEADERS(config.h lib/config.h)
+ AC_PROG_MAKE_SET
+ 
++AC_CONFIG_MACRO_DIR([m4])
++
+ dnl           checks for basic programs
+ 
+ AC_PROG_CC
+--- a/libcharset/m4/libtool.m4
++++ b/libcharset/m4/libtool.m4
+@@ -1,107 +1,186 @@
+ # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+-## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
+-## Free Software Foundation, Inc.
+-## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+-##
+-## This file is free software; the Free Software Foundation gives
+-## unlimited permission to copy and/or distribute it, with or without
+-## modifications, as long as this notice is preserved.
+-
+-# serial 48 AC_PROG_LIBTOOL
+-
+-
+-# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+-# -----------------------------------------------------------
+-# If this macro is not defined by Autoconf, define it here.
+-m4_ifdef([AC_PROVIDE_IFELSE],
+-         [],
+-         [m4_define([AC_PROVIDE_IFELSE],
+-	         [m4_ifdef([AC_PROVIDE_$1],
+-		           [$2], [$3])])])
++#
++#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++#                 2006, 2007, 2008 Free Software Foundation, Inc.
++#   Written by Gordon Matzigkeit, 1996
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++m4_define([_LT_COPYING], [dnl
++#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++#                 2006, 2007, 2008 Free Software Foundation, Inc.
++#   Written by Gordon Matzigkeit, 1996
++#
++#   This file is part of GNU Libtool.
++#
++# GNU Libtool is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# As a special exception to the GNU General Public License,
++# if you distribute this file as part of a program or library that
++# is built using GNU Libtool, you may include this file under the
++# same distribution terms that you use for the rest of that program.
++#
++# GNU Libtool is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GNU Libtool; see the file COPYING.  If not, a copy
++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
++# obtained by writing to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++])
+ 
++# serial 56 LT_INIT
+ 
+-# AC_PROG_LIBTOOL
+-# ---------------
+-AC_DEFUN([AC_PROG_LIBTOOL],
+-[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+-dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+-dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+-  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+-    [AC_LIBTOOL_CXX],
+-    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+-  ])])
+-dnl And a similar setup for Fortran 77 support
+-  AC_PROVIDE_IFELSE([AC_PROG_F77],
+-    [AC_LIBTOOL_F77],
+-    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+-])])
+-
+-dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+-dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+-dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+-  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+-    [AC_LIBTOOL_GCJ],
+-    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+-      [AC_LIBTOOL_GCJ],
+-      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+-	[AC_LIBTOOL_GCJ],
+-      [ifdef([AC_PROG_GCJ],
+-	     [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+-       ifdef([A][M_PROG_GCJ],
+-	     [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+-       ifdef([LT_AC_PROG_GCJ],
+-	     [define([LT_AC_PROG_GCJ],
+-		defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+-])])# AC_PROG_LIBTOOL
+ 
++# LT_PREREQ(VERSION)
++# ------------------
++# Complain and exit if this libtool version is less that VERSION.
++m4_defun([LT_PREREQ],
++[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
++       [m4_default([$3],
++		   [m4_fatal([Libtool version $1 or higher is required],
++		             63)])],
++       [$2])])
+ 
+-# _AC_PROG_LIBTOOL
+-# ----------------
+-AC_DEFUN([_AC_PROG_LIBTOOL],
+-[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+-AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+-AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+-AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
++
++# _LT_CHECK_BUILDDIR
++# ------------------
++# Complain if the absolute build directory name contains unusual characters
++m4_defun([_LT_CHECK_BUILDDIR],
++[case `pwd` in
++  *\ * | *\	*)
++    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
++esac
++])
++
++
++# LT_INIT([OPTIONS])
++# ------------------
++AC_DEFUN([LT_INIT],
++[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
++AC_BEFORE([$0], [LT_LANG])dnl
++AC_BEFORE([$0], [LT_OUTPUT])dnl
++AC_BEFORE([$0], [LTDL_INIT])dnl
++m4_require([_LT_CHECK_BUILDDIR])dnl
++
++dnl Autoconf doesn't catch unexpanded LT_ macros by default:
++m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
++m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
++dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
++dnl unless we require an AC_DEFUNed macro:
++AC_REQUIRE([LTOPTIONS_VERSION])dnl
++AC_REQUIRE([LTSUGAR_VERSION])dnl
++AC_REQUIRE([LTVERSION_VERSION])dnl
++AC_REQUIRE([LTOBSOLETE_VERSION])dnl
++m4_require([_LT_PROG_LTMAIN])dnl
++
++dnl Parse OPTIONS
++_LT_SET_OPTIONS([$0], [$1])
+ 
+ # This can be used to rebuild libtool when needed
+-LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
++LIBTOOL_DEPS="$ltmain"
+ 
+ # Always use our own libtool.
+-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
++LIBTOOL='$(SHELL) $(top_builddir)'
++LIBTOOL="$LIBTOOL/$host_alias-libtool"
+ AC_SUBST(LIBTOOL)dnl
+ 
+-# Prevent multiple expansion
+-define([AC_PROG_LIBTOOL], [])
+-])# _AC_PROG_LIBTOOL
++_LT_SETUP
+ 
++# Only expand once:
++m4_define([LT_INIT])
++])# LT_INIT
++
++# Old names:
++AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
++AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
++dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+ 
+-# AC_LIBTOOL_SETUP
+-# ----------------
+-AC_DEFUN([AC_LIBTOOL_SETUP],
+-[AC_PREREQ(2.50)dnl
+-AC_REQUIRE([AC_ENABLE_SHARED])dnl
+-AC_REQUIRE([AC_ENABLE_STATIC])dnl
+-AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+-AC_REQUIRE([AC_CANONICAL_HOST])dnl
++
++# _LT_CC_BASENAME(CC)
++# -------------------
++# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
++m4_defun([_LT_CC_BASENAME],
++[for cc_temp in $1""; do
++  case $cc_temp in
++    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
++    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
++    \-*) ;;
++    *) break;;
++  esac
++done
++cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
++])
++
++
++# _LT_FILEUTILS_DEFAULTS
++# ----------------------
++# It is okay to use these file commands and assume they have been set
++# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
++m4_defun([_LT_FILEUTILS_DEFAULTS],
++[: ${CP="cp -f"}
++: ${MV="mv -f"}
++: ${RM="rm -f"}
++])# _LT_FILEUTILS_DEFAULTS
++
++
++# _LT_SETUP
++# ---------
++m4_defun([_LT_SETUP],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+ AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++_LT_DECL([], [host_alias], [0], [The host system])dnl
++_LT_DECL([], [host], [0])dnl
++_LT_DECL([], [host_os], [0])dnl
++dnl
++_LT_DECL([], [build_alias], [0], [The build system])dnl
++_LT_DECL([], [build], [0])dnl
++_LT_DECL([], [build_os], [0])dnl
++dnl
+ AC_REQUIRE([AC_PROG_CC])dnl
+-AC_REQUIRE([AC_PROG_LD])dnl
+-AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+-AC_REQUIRE([AC_PROG_NM])dnl
+-
++AC_REQUIRE([LT_PATH_LD])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++dnl
+ AC_REQUIRE([AC_PROG_LN_S])dnl
+-AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+-# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+-AC_REQUIRE([AC_OBJEXT])dnl
+-AC_REQUIRE([AC_EXEEXT])dnl
++test -z "$LN_S" && LN_S="ln -s"
++_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+ dnl
++AC_REQUIRE([LT_CMD_MAX_LEN])dnl
++_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
++_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
++dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_CHECK_SHELL_FEATURES])dnl
++m4_require([_LT_CMD_RELOAD])dnl
++m4_require([_LT_CHECK_MAGIC_METHOD])dnl
++m4_require([_LT_CMD_OLD_ARCHIVE])dnl
++m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
++
++_LT_CONFIG_LIBTOOL_INIT([
++# See if we are running on zsh, and set the options which allow our
++# commands through without removal of \ escapes INIT.
++if test -n "\${ZSH_VERSION+set}" ; then
++   setopt NO_GLOB_SUBST
++fi
++])
++if test -n "${ZSH_VERSION+set}" ; then
++   setopt NO_GLOB_SUBST
++fi
+ 
+-AC_LIBTOOL_SYS_MAX_CMD_LEN
+-AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+-AC_LIBTOOL_OBJDIR
++_LT_CHECK_OBJDIR
+ 
+-AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+-_LT_AC_PROG_ECHO_BACKSLASH
++m4_require([_LT_TAG_COMPILER])dnl
++_LT_PROG_ECHO_BACKSLASH
+ 
+ case $host_os in
+ aix3*)
+@@ -117,6307 +196,6803 @@ esac
+ 
+ # Sed substitution that helps us do robust quoting.  It backslashifies
+ # metacharacters that are still active within double-quoted strings.
+-Xsed='sed -e 1s/^X//'
+-[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
++sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+ 
+ # Same as above, but do not quote variable references.
+-[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
++double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+ 
+ # Sed substitution to delay expansion of an escaped shell variable in a
+ # double_quote_subst'ed string.
+ delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+ 
++# Sed substitution to delay expansion of an escaped single quote.
++delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
++
+ # Sed substitution to avoid accidental globbing in evaled expressions
+ no_glob_subst='s/\*/\\\*/g'
+ 
+-# Constants:
+-rm="rm -f"
+-
+ # Global variables:
+-default_ofile=libtool
++ofile=${host_alias}-libtool
+ can_build_shared=yes
+ 
+ # All known linkers require a `.a' archive for static linking (except MSVC,
+ # which needs '.lib').
+ libext=a
+-ltmain="$ac_aux_dir/ltmain.sh"
+-ofile="$default_ofile"
+-with_gnu_ld="$lt_cv_prog_gnu_ld"
+ 
+-AC_CHECK_TOOL(AR, ar, false)
+-AC_CHECK_TOOL(RANLIB, ranlib, :)
+-AC_CHECK_TOOL(STRIP, strip, :)
++with_gnu_ld="$lt_cv_prog_gnu_ld"
+ 
+ old_CC="$CC"
+ old_CFLAGS="$CFLAGS"
+ 
+ # Set sane defaults for various variables
+-test -z "$AR" && AR=ar
+-test -z "$AR_FLAGS" && AR_FLAGS=cru
+-test -z "$AS" && AS=as
+ test -z "$CC" && CC=cc
+ test -z "$LTCC" && LTCC=$CC
+ test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+-test -z "$DLLTOOL" && DLLTOOL=dlltool
+ test -z "$LD" && LD=ld
+-test -z "$LN_S" && LN_S="ln -s"
+-test -z "$MAGIC_CMD" && MAGIC_CMD=file
+-test -z "$NM" && NM=nm
+-test -z "$SED" && SED=sed
+-test -z "$OBJDUMP" && OBJDUMP=objdump
+-test -z "$RANLIB" && RANLIB=:
+-test -z "$STRIP" && STRIP=:
+ test -z "$ac_objext" && ac_objext=o
+ 
+-# Determine commands to create old-style static archives.
+-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+-old_postinstall_cmds='chmod 644 $oldlib'
+-old_postuninstall_cmds=
+-
+-if test -n "$RANLIB"; then
+-  case $host_os in
+-  openbsd*)
+-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+-    ;;
+-  *)
+-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+-    ;;
+-  esac
+-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+-fi
+-
+ _LT_CC_BASENAME([$compiler])
+ 
+ # Only perform the check for file, if the check method requires it
++test -z "$MAGIC_CMD" && MAGIC_CMD=file
+ case $deplibs_check_method in
+ file_magic*)
+   if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+-    AC_PATH_MAGIC
++    _LT_PATH_MAGIC
+   fi
+   ;;
+ esac
+ 
+-AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+-AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+-enable_win32_dll=yes, enable_win32_dll=no)
+-
+-AC_ARG_ENABLE([libtool-lock],
+-    [AC_HELP_STRING([--disable-libtool-lock],
+-	[avoid locking (might break parallel builds)])])
+-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++# Use C for the default configuration in the libtool script
++LT_SUPPORTED_TAG([CC])
++_LT_LANG_C_CONFIG
++_LT_LANG_DEFAULT_CONFIG
++_LT_CONFIG_COMMANDS
++])# _LT_SETUP
+ 
+-AC_ARG_WITH([pic],
+-    [AC_HELP_STRING([--with-pic],
+-	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+-    [pic_mode="$withval"],
+-    [pic_mode=default])
+-test -z "$pic_mode" && pic_mode=default
+ 
+-# Use C for the default configuration in the libtool script
+-tagname=
+-AC_LIBTOOL_LANG_C_CONFIG
+-_LT_AC_TAGCONFIG
+-])# AC_LIBTOOL_SETUP
++# _LT_PROG_LTMAIN
++# ---------------
++# Note that this code is called both from `configure', and `config.status'
++# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
++# `config.status' has no value for ac_aux_dir unless we are using Automake,
++# so we pass a copy along to make sure it has a sensible value anyway.
++m4_defun([_LT_PROG_LTMAIN],
++[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
++_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
++ltmain="$ac_aux_dir/ltmain.sh"
++])# _LT_PROG_LTMAIN
+ 
+ 
+-# _LT_AC_SYS_COMPILER
+-# -------------------
+-AC_DEFUN([_LT_AC_SYS_COMPILER],
+-[AC_REQUIRE([AC_PROG_CC])dnl
++## ------------------------------------- ##
++## Accumulate code for creating libtool. ##
++## ------------------------------------- ##
++
++# So that we can recreate a full libtool script including additional
++# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
++# in macros and then make a single call at the end using the `libtool'
++# label.
++
++
++# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
++# ----------------------------------------
++# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
++m4_define([_LT_CONFIG_LIBTOOL_INIT],
++[m4_ifval([$1],
++          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
++                     [$1
++])])])
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_INIT])
++
++
++# _LT_CONFIG_LIBTOOL([COMMANDS])
++# ------------------------------
++# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
++m4_define([_LT_CONFIG_LIBTOOL],
++[m4_ifval([$1],
++          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
++                     [$1
++])])])
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
++
++
++# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
++# -----------------------------------------------------
++m4_defun([_LT_CONFIG_SAVE_COMMANDS],
++[_LT_CONFIG_LIBTOOL([$1])
++_LT_CONFIG_LIBTOOL_INIT([$2])
++])
+ 
+-# If no C compiler was specified, use CC.
+-LTCC=${LTCC-"$CC"}
+ 
+-# If no C compiler flags were specified, use CFLAGS.
+-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
++# _LT_FORMAT_COMMENT([COMMENT])
++# -----------------------------
++# Add leading comment marks to the start of each line, and a trailing
++# full-stop to the whole comment if one is not present already.
++m4_define([_LT_FORMAT_COMMENT],
++[m4_ifval([$1], [
++m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
++              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
++)])
+ 
+-# Allow CC to be a program name with arguments.
+-compiler=$CC
+-])# _LT_AC_SYS_COMPILER
+ 
+ 
+-# _LT_CC_BASENAME(CC)
+-# -------------------
+-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+-AC_DEFUN([_LT_CC_BASENAME],
+-[for cc_temp in $1""; do
+-  case $cc_temp in
+-    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+-    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+-    \-*) ;;
+-    *) break;;
+-  esac
+-done
+-cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
++## ------------------------ ##
++## FIXME: Eliminate VARNAME ##
++## ------------------------ ##
++
++
++# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
++# -------------------------------------------------------------------
++# CONFIGNAME is the name given to the value in the libtool script.
++# VARNAME is the (base) name used in the configure script.
++# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
++# VARNAME.  Any other value will be used directly.
++m4_define([_LT_DECL],
++[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
++    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
++	[m4_ifval([$1], [$1], [$2])])
++    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
++    m4_ifval([$4],
++	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
++    lt_dict_add_subkey([lt_decl_dict], [$2],
++	[tagged?], [m4_ifval([$5], [yes], [no])])])
+ ])
+ 
+ 
+-# _LT_COMPILER_BOILERPLATE
+-# ------------------------
+-# Check for compiler boilerplate output or warnings with
+-# the simple compiler test code.
+-AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+-[ac_outfile=conftest.$ac_objext
+-printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+-_lt_compiler_boilerplate=`cat conftest.err`
+-$rm conftest*
+-])# _LT_COMPILER_BOILERPLATE
+-
++# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
++# --------------------------------------------------------
++m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
++
++
++# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
++# ------------------------------------------------
++m4_define([lt_decl_tag_varnames],
++[_lt_decl_filter([tagged?], [yes], $@)])
++
++
++# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
++# ---------------------------------------------------------
++m4_define([_lt_decl_filter],
++[m4_case([$#],
++  [0], [m4_fatal([$0: too few arguments: $#])],
++  [1], [m4_fatal([$0: too few arguments: $#: $1])],
++  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
++  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
++  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
++])
+ 
+-# _LT_LINKER_BOILERPLATE
+-# ----------------------
+-# Check for linker boilerplate output or warnings with
+-# the simple link test code.
+-AC_DEFUN([_LT_LINKER_BOILERPLATE],
+-[ac_outfile=conftest.$ac_objext
+-printf "$lt_simple_link_test_code" >conftest.$ac_ext
+-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+-_lt_linker_boilerplate=`cat conftest.err`
+-$rm conftest*
+-])# _LT_LINKER_BOILERPLATE
+ 
++# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
++# --------------------------------------------------
++m4_define([lt_decl_quote_varnames],
++[_lt_decl_filter([value], [1], $@)])
++
++
++# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
++# ---------------------------------------------------
++m4_define([lt_decl_dquote_varnames],
++[_lt_decl_filter([value], [2], $@)])
++
++
++# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
++# ---------------------------------------------------
++m4_define([lt_decl_varnames_tagged],
++[_$0(m4_quote(m4_default([$1], [[, ]])),
++     m4_quote(m4_if([$2], [],
++		     m4_quote(lt_decl_tag_varnames),
++		  m4_quote(m4_shift($@)))),
++     m4_split(m4_normalize(m4_quote(_LT_TAGS))))])
++m4_define([_lt_decl_varnames_tagged], [lt_combine([$1], [$2], [_], $3)])
++
++
++# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
++# ------------------------------------------------
++m4_define([lt_decl_all_varnames],
++[_$0(m4_quote(m4_default([$1], [[, ]])),
++     m4_if([$2], [],
++	   m4_quote(lt_decl_varnames),
++	m4_quote(m4_shift($@))))[]dnl
++])
++m4_define([_lt_decl_all_varnames],
++[lt_join($@, lt_decl_varnames_tagged([$1],
++			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
++])
+ 
+-# _LT_AC_SYS_LIBPATH_AIX
+-# ----------------------
+-# Links a minimal program and checks the executable
+-# for the system default hardcoded library path. In most cases,
+-# this is /usr/lib:/lib, but when the MPI compilers are used
+-# the location of the communication and MPI libs are included too.
+-# If we don't find anything, use the default library path according
+-# to the aix ld manual.
+-AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+-[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+-aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+-}'`
+-# Check for a 64-bit object if we didn't find anything.
+-if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+-}'`; fi],[])
+-if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+-])# _LT_AC_SYS_LIBPATH_AIX
+ 
++# _LT_CONFIG_STATUS_DECLARE([VARNAME])
++# ------------------------------------
++# Quote a variable value, and forward it to `config.status' so that its
++# declaration there will have the same value as in `configure'.  VARNAME
++# must have a single quote delimited value for this to work.
++m4_define([_LT_CONFIG_STATUS_DECLARE],
++[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`'])
+ 
+-# _LT_AC_SHELL_INIT(ARG)
+-# ----------------------
+-AC_DEFUN([_LT_AC_SHELL_INIT],
+-[ifdef([AC_DIVERSION_NOTICE],
+-	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+-	 [AC_DIVERT_PUSH(NOTICE)])
+-$1
+-AC_DIVERT_POP
+-])# _LT_AC_SHELL_INIT
+ 
++# _LT_CONFIG_STATUS_DECLARATIONS
++# ------------------------------
++# We delimit libtool config variables with single quotes, so when
++# we write them to config.status, we have to be sure to quote all
++# embedded single quotes properly.  In configure, this macro expands
++# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
++#
++#    <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`'
++m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
++[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
++    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+ 
+-# _LT_AC_PROG_ECHO_BACKSLASH
+-# --------------------------
+-# Add some code to the start of the generated configure script which
+-# will find an echo command which doesn't interpret backslashes.
+-AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+-[_LT_AC_SHELL_INIT([
+-# Check that we are running under the correct shell.
+-SHELL=${CONFIG_SHELL-/bin/sh}
+ 
+-case X$ECHO in
+-X*--fallback-echo)
+-  # Remove one level of quotation (which was required for Make).
+-  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+-  ;;
+-esac
++# _LT_LIBTOOL_TAGS
++# ----------------
++# Output comment and list of tags supported by the script
++m4_defun([_LT_LIBTOOL_TAGS],
++[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
++available_tags="_LT_TAGS"dnl
++])
+ 
+-echo=${ECHO-echo}
+-if test "X[$]1" = X--no-reexec; then
+-  # Discard the --no-reexec flag, and continue.
+-  shift
+-elif test "X[$]1" = X--fallback-echo; then
+-  # Avoid inline document here, it may be left over
+-  :
+-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+-  # Yippee, $echo works!
+-  :
+-else
+-  # Restart under the correct shell.
+-  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+-fi
+ 
+-if test "X[$]1" = X--fallback-echo; then
+-  # used as fallback echo
+-  shift
+-  cat <<EOF
+-[$]*
+-EOF
+-  exit 0
+-fi
++# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
++# -----------------------------------
++# Extract the dictionary values for VARNAME (optionally with TAG) and
++# expand to a commented shell variable setting:
++#
++#    # Some comment about what VAR is for.
++#    visible_name=$lt_internal_name
++m4_define([_LT_LIBTOOL_DECLARE],
++[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
++					   [description])))[]dnl
++m4_pushdef([_libtool_name],
++    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
++m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
++    [0], [_libtool_name=[$]$1],
++    [1], [_libtool_name=$lt_[]$1],
++    [2], [_libtool_name=$lt_[]$1],
++    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
++m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
++])
+ 
+-# The HP-UX ksh and POSIX shell print the target directory to stdout
+-# if CDPATH is set.
+-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+ 
+-if test -z "$ECHO"; then
+-if test "X${echo_test_string+set}" != Xset; then
+-# find a string as large as possible, as long as the shell can cope with it
+-  for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+-    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+-    if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+-       echo_test_string=`eval $cmd` &&
+-       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+-    then
+-      break
+-    fi
+-  done
+-fi
++# _LT_LIBTOOL_CONFIG_VARS
++# -----------------------
++# Produce commented declarations of non-tagged libtool config variables
++# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
++# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
++# section) are produced by _LT_LIBTOOL_TAG_VARS.
++m4_defun([_LT_LIBTOOL_CONFIG_VARS],
++[m4_foreach([_lt_var],
++    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
++    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+ 
+-if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+-   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+-   test "X$echo_testing_string" = "X$echo_test_string"; then
+-  :
+-else
+-  # The Solaris, AIX, and Digital Unix default echo programs unquote
+-  # backslashes.  This makes it impossible to quote backslashes using
+-  #   echo "$something" | sed 's/\\/\\\\/g'
+-  #
+-  # So, first we look for a working echo in the user's PATH.
+ 
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-  for dir in $PATH /usr/ucb; do
+-    IFS="$lt_save_ifs"
+-    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+-       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+-       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+-       test "X$echo_testing_string" = "X$echo_test_string"; then
+-      echo="$dir/echo"
+-      break
+-    fi
+-  done
+-  IFS="$lt_save_ifs"
++# _LT_LIBTOOL_TAG_VARS(TAG)
++# -------------------------
++m4_define([_LT_LIBTOOL_TAG_VARS],
++[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
++    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+ 
+-  if test "X$echo" = Xecho; then
+-    # We didn't find a better echo, so look for alternatives.
+-    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+-       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+-       test "X$echo_testing_string" = "X$echo_test_string"; then
+-      # This shell has a builtin print -r that does the trick.
+-      echo='print -r'
+-    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+-	 test "X$CONFIG_SHELL" != X/bin/ksh; then
+-      # If we have ksh, try running configure again with it.
+-      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+-      export ORIGINAL_CONFIG_SHELL
+-      CONFIG_SHELL=/bin/ksh
+-      export CONFIG_SHELL
+-      exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+-    else
+-      # Try using printf.
+-      echo='printf %s\n'
+-      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+-	 echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+-	 test "X$echo_testing_string" = "X$echo_test_string"; then
+-	# Cool, printf works
+-	:
+-      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+-	   test "X$echo_testing_string" = 'X\t' &&
+-	   echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+-	   test "X$echo_testing_string" = "X$echo_test_string"; then
+-	CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+-	export CONFIG_SHELL
+-	SHELL="$CONFIG_SHELL"
+-	export SHELL
+-	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+-      elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+-	   test "X$echo_testing_string" = 'X\t' &&
+-	   echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+-	   test "X$echo_testing_string" = "X$echo_test_string"; then
+-	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+-      else
+-	# maybe with a smaller string...
+-	prev=:
+ 
+-	for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+-	  if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+-	  then
+-	    break
+-	  fi
+-	  prev="$cmd"
+-	done
++# _LT_TAGVAR(VARNAME, [TAGNAME])
++# ------------------------------
++m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+ 
+-	if test "$prev" != 'sed 50q "[$]0"'; then
+-	  echo_test_string=`eval $prev`
+-	  export echo_test_string
+-	  exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+-	else
+-	  # Oops.  We lost completely, so just stick with echo.
+-	  echo=echo
+-	fi
+-      fi
+-    fi
+-  fi
+-fi
+-fi
+ 
+-# Copy echo and quote the copy suitably for passing to libtool from
+-# the Makefile, instead of quoting the original, which is used later.
+-ECHO=$echo
+-if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+-   ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+-fi
++# _LT_CONFIG_COMMANDS
++# -------------------
++# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
++# variables for single and double quote escaping we saved from calls
++# to _LT_DECL, we can put quote escaped variables declarations
++# into `config.status', and then the shell code to quote escape them in
++# for loops in `config.status'.  Finally, any additional code accumulated
++# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
++m4_defun([_LT_CONFIG_COMMANDS],
++[AC_PROVIDE_IFELSE([LT_OUTPUT],
++	dnl If the libtool generation code has been placed in $CONFIG_LT,
++	dnl instead of duplicating it all over again into config.status,
++	dnl then we will have config.status run $CONFIG_LT later, so it
++	dnl needs to know what name is stored there:
++        [AC_CONFIG_COMMANDS([libtool],
++            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
++    dnl If the libtool generation code is destined for config.status,
++    dnl expand the accumulated commands and init code now:
++    [AC_CONFIG_COMMANDS([libtool],
++        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
++])#_LT_CONFIG_COMMANDS
+ 
+-AC_SUBST(ECHO)
+-])])# _LT_AC_PROG_ECHO_BACKSLASH
+ 
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
++[
+ 
+-# _LT_AC_LOCK
+-# -----------
+-AC_DEFUN([_LT_AC_LOCK],
+-[AC_ARG_ENABLE([libtool-lock],
+-    [AC_HELP_STRING([--disable-libtool-lock],
+-	[avoid locking (might break parallel builds)])])
+-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+ 
+-# Some flags need to be propagated to the compiler or linker for good
+-# libtool support.
+-case $host in
+-ia64-*-hpux*)
+-  # Find out which ABI we are using.
+-  echo 'int i;' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-    case `/usr/bin/file conftest.$ac_objext` in
+-    *ELF-32*)
+-      HPUX_IA64_MODE="32"
+-      ;;
+-    *ELF-64*)
+-      HPUX_IA64_MODE="64"
+-      ;;
+-    esac
+-  fi
+-  rm -rf conftest*
+-  ;;
+-*-*-irix6*)
+-  # Find out which ABI we are using.
+-  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-   if test "$lt_cv_prog_gnu_ld" = yes; then
+-    case `/usr/bin/file conftest.$ac_objext` in
+-    *32-bit*)
+-      LD="${LD-ld} -melf32bsmip"
+-      ;;
+-    *N32*)
+-      LD="${LD-ld} -melf32bmipn32"
++sed_quote_subst='$sed_quote_subst'
++double_quote_subst='$double_quote_subst'
++delay_variable_subst='$delay_variable_subst'
++_LT_CONFIG_STATUS_DECLARATIONS
++LTCC='$LTCC'
++LTCFLAGS='$LTCFLAGS'
++compiler='$compiler_DEFAULT'
++
++# Quote evaled strings.
++for var in lt_decl_all_varnames([[ \
++]], lt_decl_quote_varnames); do
++    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
++    *[[\\\\\\\`\\"\\\$]]*)
++      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+       ;;
+-    *64-bit*)
+-      LD="${LD-ld} -melf64bmip"
++    *)
++      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+       ;;
+     esac
+-   else
+-    case `/usr/bin/file conftest.$ac_objext` in
+-    *32-bit*)
+-      LD="${LD-ld} -32"
+-      ;;
+-    *N32*)
+-      LD="${LD-ld} -n32"
++done
++
++# Double-quote double-evaled strings.
++for var in lt_decl_all_varnames([[ \
++]], lt_decl_dquote_varnames); do
++    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
++    *[[\\\\\\\`\\"\\\$]]*)
++      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+       ;;
+-    *64-bit*)
+-      LD="${LD-ld} -64"
++    *)
++      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+       ;;
+     esac
+-   fi
+-  fi
+-  rm -rf conftest*
++done
++
++# Fix-up fallback echo if it was mangled by the above quoting rules.
++case \$lt_ECHO in
++*'\\\[$]0 --fallback-echo"')dnl "
++  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\`
+   ;;
++esac
+ 
+-x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+-  # Find out which ABI we are using.
+-  echo 'int i;' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-    case `/usr/bin/file conftest.o` in
+-    *32-bit*)
+-      case $host in
+-        x86_64-*linux*)
+-          LD="${LD-ld} -m elf_i386"
+-          ;;
+-        ppc64-*linux*|powerpc64-*linux*)
+-          LD="${LD-ld} -m elf32ppclinux"
+-          ;;
+-        s390x-*linux*)
+-          LD="${LD-ld} -m elf_s390"
+-          ;;
+-        sparc64-*linux*)
+-          LD="${LD-ld} -m elf32_sparc"
+-          ;;
+-      esac
+-      ;;
+-    *64-bit*)
+-      case $host in
+-        x86_64-*linux*)
+-          LD="${LD-ld} -m elf_x86_64"
+-          ;;
+-        ppc*-*linux*|powerpc*-*linux*)
+-          LD="${LD-ld} -m elf64ppc"
+-          ;;
+-        s390*-*linux*)
+-          LD="${LD-ld} -m elf64_s390"
+-          ;;
+-        sparc*-*linux*)
+-          LD="${LD-ld} -m elf64_sparc"
+-          ;;
+-      esac
+-      ;;
+-    esac
+-  fi
+-  rm -rf conftest*
+-  ;;
++_LT_OUTPUT_LIBTOOL_INIT
++])
+ 
+-*-*-sco3.2v5*)
+-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+-  SAVE_CFLAGS="$CFLAGS"
+-  CFLAGS="$CFLAGS -belf"
+-  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+-    [AC_LANG_PUSH(C)
+-     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+-     AC_LANG_POP])
+-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+-    CFLAGS="$SAVE_CFLAGS"
+-  fi
+-  ;;
+-sparc*-*solaris*)
+-  # Find out which ABI we are using.
+-  echo 'int i;' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-    case `/usr/bin/file conftest.o` in
+-    *64-bit*)
+-      case $lt_cv_prog_gnu_ld in
+-      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+-      *)    LD="${LD-ld} -64" ;;
+-      esac
+-      ;;
+-    esac
+-  fi
+-  rm -rf conftest*
+-  ;;
+ 
+-AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+-[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+-  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+-  AC_CHECK_TOOL(AS, as, false)
+-  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+-  ;;
+-  ])
+-esac
++# LT_OUTPUT
++# ---------
++# This macro allows early generation of the libtool script (before
++# AC_OUTPUT is called), incase it is used in configure for compilation
++# tests.
++AC_DEFUN([LT_OUTPUT],
++[: ${CONFIG_LT=./config.lt}
++AC_MSG_NOTICE([creating $CONFIG_LT])
++cat >"$CONFIG_LT" <<_LTEOF
++#! $SHELL
++# Generated by $as_me.
++# Run this file to recreate a libtool stub with the current configuration.
++
++lt_cl_silent=false
++SHELL=\${CONFIG_SHELL-$SHELL}
++_LTEOF
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++AS_SHELL_SANITIZE
++_AS_PREPARE
+ 
+-need_locks="$enable_libtool_lock"
++exec AS_MESSAGE_FD>&1
++exec AS_MESSAGE_LOG_FD>>config.log
++{
++  echo
++  AS_BOX([Running $as_me.])
++} >&AS_MESSAGE_LOG_FD
++
++lt_cl_help="\
++\`$as_me' creates a local libtool stub from the current configuration,
++for use in further configure time tests before the real libtool is
++generated.
++
++Usage: $[0] [[OPTIONS]]
++
++  -h, --help      print this help, then exit
++  -V, --version   print version number, then exit
++  -q, --quiet     do not print progress messages
++  -d, --debug     don't remove temporary files
++
++Report bugs to <bug-libtool@gnu.org>."
++
++lt_cl_version="\
++m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
++m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
++configured by $[0], generated by m4_PACKAGE_STRING.
++
++Copyright (C) 2008 Free Software Foundation, Inc.
++This config.lt script is free software; the Free Software Foundation
++gives unlimited permision to copy, distribute and modify it."
+ 
+-])# _LT_AC_LOCK
++while test $[#] != 0
++do
++  case $[1] in
++    --version | --v* | -V )
++      echo "$lt_cl_version"; exit 0 ;;
++    --help | --h* | -h )
++      echo "$lt_cl_help"; exit 0 ;;
++    --debug | --d* | -d )
++      debug=: ;;
++    --quiet | --q* | --silent | --s* | -q )
++      lt_cl_silent=: ;;
+ 
++    -*) AC_MSG_ERROR([unrecognized option: $[1]
++Try \`$[0] --help' for more information.]) ;;
+ 
+-# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+-#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+-# ----------------------------------------------------------------
+-# Check whether the given compiler option works
+-AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+-[AC_REQUIRE([LT_AC_PROG_SED])
+-AC_CACHE_CHECK([$1], [$2],
+-  [$2=no
+-  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+-   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+-   lt_compiler_flag="$3"
+-   # Insert the option either (1) after the last *FLAGS variable, or
+-   # (2) before a word containing "conftest.", or (3) at the end.
+-   # Note that $ac_compile itself does not contain backslashes and begins
+-   # with a dollar sign (not a hyphen), so the echo should work correctly.
+-   # The option is referenced via a variable to avoid confusing sed.
+-   lt_compile=`echo "$ac_compile" | $SED \
+-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+-   -e 's:$: $lt_compiler_flag:'`
+-   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+-   (eval "$lt_compile" 2>conftest.err)
+-   ac_status=$?
+-   cat conftest.err >&AS_MESSAGE_LOG_FD
+-   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+-   if (exit $ac_status) && test -s "$ac_outfile"; then
+-     # The compiler can only warn and ignore the option if not recognized
+-     # So say no if there are warnings other than the usual output.
+-     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+-       $2=yes
+-     fi
+-   fi
+-   $rm conftest*
+-])
++    *) AC_MSG_ERROR([unrecognized argument: $[1]
++Try \`$[0] --help' for more information.]) ;;
++  esac
++  shift
++done
+ 
+-if test x"[$]$2" = xyes; then
+-    ifelse([$5], , :, [$5])
+-else
+-    ifelse([$6], , :, [$6])
++if $lt_cl_silent; then
++  exec AS_MESSAGE_FD>/dev/null
+ fi
+-])# AC_LIBTOOL_COMPILER_OPTION
+-
+-
+-# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+-#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+-# ------------------------------------------------------------
+-# Check whether the given compiler option works
+-AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+-[AC_CACHE_CHECK([$1], [$2],
+-  [$2=no
+-   save_LDFLAGS="$LDFLAGS"
+-   LDFLAGS="$LDFLAGS $3"
+-   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+-     # The linker can only warn and ignore the option if not recognized
+-     # So say no if there are warnings
+-     if test -s conftest.err; then
+-       # Append any errors to the config.log.
+-       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+-       $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+-       if diff conftest.exp conftest.er2 >/dev/null; then
+-         $2=yes
+-       fi
+-     else
+-       $2=yes
+-     fi
+-   fi
+-   $rm conftest*
+-   LDFLAGS="$save_LDFLAGS"
+-])
++_LTEOF
+ 
+-if test x"[$]$2" = xyes; then
+-    ifelse([$4], , :, [$4])
+-else
+-    ifelse([$5], , :, [$5])
++cat >>"$CONFIG_LT" <<_LTEOF
++_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
++_LTEOF
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++AC_MSG_NOTICE([creating $ofile])
++_LT_OUTPUT_LIBTOOL_COMMANDS
++AS_EXIT(0)
++_LTEOF
++chmod +x "$CONFIG_LT"
++
++# configure is writing to config.log, but config.lt does its own redirection,
++# appending to config.log, which fails on DOS, as config.log is still kept
++# open by configure.  Here we exec the FD to /dev/null, effectively closing
++# config.log, so it can be properly (re)opened and appended to by config.lt.
++if test "$no_create" != yes; then
++  lt_cl_success=:
++  test "$silent" = yes &&
++    lt_config_lt_args="$lt_config_lt_args --quiet"
++  exec AS_MESSAGE_LOG_FD>/dev/null
++  $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
++  exec AS_MESSAGE_LOG_FD>>config.log
++  $lt_cl_success || AS_EXIT(1)
+ fi
+-])# AC_LIBTOOL_LINKER_OPTION
+-
++])# LT_OUTPUT
+ 
+-# AC_LIBTOOL_SYS_MAX_CMD_LEN
+-# --------------------------
+-AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+-[# find the maximum length of command line arguments
+-AC_MSG_CHECKING([the maximum length of command line arguments])
+-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+-  i=0
+-  teststring="ABCD"
+ 
+-  case $build_os in
+-  msdosdjgpp*)
+-    # On DJGPP, this test can blow up pretty badly due to problems in libc
+-    # (any single argument exceeding 2000 bytes causes a buffer overrun
+-    # during glob expansion).  Even if it were fixed, the result of this
+-    # check would be larger than it should be.
+-    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+-    ;;
++# _LT_CONFIG(TAG)
++# ---------------
++# If TAG is the built-in tag, create an initial libtool script with a
++# default configuration from the untagged config vars.  Otherwise add code
++# to config.status for appending the configuration named by TAG from the
++# matching tagged config vars.
++m4_defun([_LT_CONFIG],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++_LT_CONFIG_SAVE_COMMANDS([
++  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
++  m4_if(_LT_TAG, [C], [
++    # See if we are running on zsh, and set the options which allow our
++    # commands through without removal of \ escapes.
++    if test -n "${ZSH_VERSION+set}" ; then
++      setopt NO_GLOB_SUBST
++    fi
+ 
+-  gnu*)
+-    # Under GNU Hurd, this test is not required because there is
+-    # no limit to the length of command line arguments.
+-    # Libtool will interpret -1 as no limit whatsoever
+-    lt_cv_sys_max_cmd_len=-1;
+-    ;;
++    cfgfile="${ofile}T"
++    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
++    $RM "$cfgfile"
+ 
+-  cygwin* | mingw*)
+-    # On Win9x/ME, this test blows up -- it succeeds, but takes
+-    # about 5 minutes as the teststring grows exponentially.
+-    # Worse, since 9x/ME are not pre-emptively multitasking,
+-    # you end up with a "frozen" computer, even though with patience
+-    # the test eventually succeeds (with a max line length of 256k).
+-    # Instead, let's just punt: use the minimum linelength reported by
+-    # all of the supported platforms: 8192 (on NT/2K/XP).
+-    lt_cv_sys_max_cmd_len=8192;
+-    ;;
++    cat <<_LT_EOF >> "$cfgfile"
++#! $SHELL
+ 
+-  amigaos*)
+-    # On AmigaOS with pdksh, this test takes hours, literally.
+-    # So we just punt and use a minimum line length of 8192.
+-    lt_cv_sys_max_cmd_len=8192;
+-    ;;
++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
++# NOTE: Changes made to this file will be lost: look at ltmain.sh.
++#
++_LT_COPYING
++_LT_LIBTOOL_TAGS
+ 
+-  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+-    # This has been around since 386BSD, at least.  Likely further.
+-    if test -x /sbin/sysctl; then
+-      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+-    elif test -x /usr/sbin/sysctl; then
+-      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+-    else
+-      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+-    fi
+-    # And add a safety zone
+-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+-    ;;
++# ### BEGIN LIBTOOL CONFIG
++_LT_LIBTOOL_CONFIG_VARS
++_LT_LIBTOOL_TAG_VARS
++# ### END LIBTOOL CONFIG
+ 
+-  interix*)
+-    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+-    lt_cv_sys_max_cmd_len=196608
+-    ;;
++_LT_EOF
+ 
+-  osf*)
+-    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+-    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+-    # nice to cause kernel panics so lets avoid the loop below.
+-    # First set a reasonable default.
+-    lt_cv_sys_max_cmd_len=16384
+-    #
+-    if test -x /sbin/sysconfig; then
+-      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+-        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+-      esac
+-    fi
+-    ;;
+-  sco3.2v5*)
+-    lt_cv_sys_max_cmd_len=102400
+-    ;;
+-  sysv5* | sco5v6* | sysv4.2uw2*)
+-    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+-    if test -n "$kargmax"; then
+-      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ 	]]//'`
+-    else
+-      lt_cv_sys_max_cmd_len=32768
+-    fi
+-    ;;
+-  *)
+-    # If test is not a shell built-in, we'll probably end up computing a
+-    # maximum length that is only half of the actual maximum length, but
+-    # we can't tell.
+-    SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+-    while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+-	       = "XX$teststring") >/dev/null 2>&1 &&
+-	    new_result=`expr "X$teststring" : ".*" 2>&1` &&
+-	    lt_cv_sys_max_cmd_len=$new_result &&
+-	    test $i != 17 # 1/2 MB should be enough
+-    do
+-      i=`expr $i + 1`
+-      teststring=$teststring$teststring
+-    done
+-    teststring=
+-    # Add a significant safety factor because C++ compilers can tack on massive
+-    # amounts of additional arguments before passing them to the linker.
+-    # It appears as though 1/2 is a usable value.
+-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
++  case $host_os in
++  aix3*)
++    cat <<\_LT_EOF >> "$cfgfile"
++# AIX sometimes has problems with the GCC collect2 program.  For some
++# reason, if we set the COLLECT_NAMES environment variable, the problems
++# vanish in a puff of smoke.
++if test "X${COLLECT_NAMES+set}" != Xset; then
++  COLLECT_NAMES=
++  export COLLECT_NAMES
++fi
++_LT_EOF
+     ;;
+   esac
+-])
+-if test -n $lt_cv_sys_max_cmd_len ; then
+-  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+-else
+-  AC_MSG_RESULT(none)
+-fi
+-])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+ 
++  _LT_PROG_LTMAIN
+ 
+-# _LT_AC_CHECK_DLFCN
+-# ------------------
+-AC_DEFUN([_LT_AC_CHECK_DLFCN],
+-[AC_CHECK_HEADERS(dlfcn.h)dnl
+-])# _LT_AC_CHECK_DLFCN
++  # We use sed instead of cat because bash on DJGPP gets confused if
++  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
++  # text mode, it properly converts lines to CR/LF.  This bash problem
++  # is reportedly fixed, but why not run on old versions too?
++  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
++    || (rm -f "$cfgfile"; exit 1)
+ 
++  _LT_PROG_XSI_SHELLFNS
+ 
+-# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+-#                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+-# ---------------------------------------------------------------------
+-AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+-[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+-if test "$cross_compiling" = yes; then :
+-  [$4]
+-else
+-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+-  lt_status=$lt_dlunknown
+-  cat > conftest.$ac_ext <<EOF
+-[#line __oline__ "configure"
+-#include "confdefs.h"
++  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
++    || (rm -f "$cfgfile"; exit 1)
+ 
+-#if HAVE_DLFCN_H
+-#include <dlfcn.h>
+-#endif
++  mv -f "$cfgfile" "$ofile" ||
++    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
++  chmod +x "$ofile"
++],
++[cat <<_LT_EOF >> "$ofile"
+ 
+-#include <stdio.h>
++dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
++dnl in a comment (ie after a #).
++# ### BEGIN LIBTOOL TAG CONFIG: $1
++_LT_LIBTOOL_TAG_VARS(_LT_TAG)
++# ### END LIBTOOL TAG CONFIG: $1
++_LT_EOF
++])dnl /m4_if
++],
++[m4_if([$1], [], [
++    PACKAGE='$PACKAGE'
++    VERSION='$VERSION'
++    TIMESTAMP='$TIMESTAMP'
++    RM='$RM'
++    ofile='$ofile'], [])
++])dnl /_LT_CONFIG_SAVE_COMMANDS
++])# _LT_CONFIG
++
++
++# LT_SUPPORTED_TAG(TAG)
++# ---------------------
++# Trace this macro to discover what tags are supported by the libtool
++# --tag option, using:
++#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
++AC_DEFUN([LT_SUPPORTED_TAG], [])
++
++
++# C support is built-in for now
++m4_define([_LT_LANG_C_enabled], [])
++m4_define([_LT_TAGS], [])
+ 
+-#ifdef RTLD_GLOBAL
+-#  define LT_DLGLOBAL		RTLD_GLOBAL
+-#else
+-#  ifdef DL_GLOBAL
+-#    define LT_DLGLOBAL		DL_GLOBAL
+-#  else
+-#    define LT_DLGLOBAL		0
+-#  endif
+-#endif
+ 
+-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+-   find out it does not work in some platform. */
+-#ifndef LT_DLLAZY_OR_NOW
+-#  ifdef RTLD_LAZY
+-#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+-#  else
+-#    ifdef DL_LAZY
+-#      define LT_DLLAZY_OR_NOW		DL_LAZY
+-#    else
+-#      ifdef RTLD_NOW
+-#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+-#      else
+-#        ifdef DL_NOW
+-#          define LT_DLLAZY_OR_NOW	DL_NOW
+-#        else
+-#          define LT_DLLAZY_OR_NOW	0
+-#        endif
+-#      endif
+-#    endif
+-#  endif
+-#endif
++# LT_LANG(LANG)
++# -------------
++# Enable libtool support for the given language if not already enabled.
++AC_DEFUN([LT_LANG],
++[AC_BEFORE([$0], [LT_OUTPUT])dnl
++m4_case([$1],
++  [C],			[_LT_LANG(C)],
++  [C++],		[_LT_LANG(CXX)],
++  [Java],		[_LT_LANG(GCJ)],
++  [Fortran 77],		[_LT_LANG(F77)],
++  [Fortran],		[_LT_LANG(FC)],
++  [Windows Resource],	[_LT_LANG(RC)],
++  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
++    [_LT_LANG($1)],
++    [m4_fatal([$0: unsupported language: "$1"])])])dnl
++])# LT_LANG
+ 
+-#ifdef __cplusplus
+-extern "C" void exit (int);
+-#endif
+ 
+-void fnord() { int i=42;}
+-int main ()
+-{
+-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+-  int status = $lt_dlunknown;
+-
+-  if (self)
+-    {
+-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+-      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+-      /* dlclose (self); */
+-    }
+-  else
+-    puts (dlerror ());
++# _LT_LANG(LANGNAME)
++# ------------------
++m4_defun([_LT_LANG],
++[m4_ifdef([_LT_LANG_]$1[_enabled], [],
++  [LT_SUPPORTED_TAG([$1])dnl
++  m4_append([_LT_TAGS], [$1 ])dnl
++  m4_define([_LT_LANG_]$1[_enabled], [])dnl
++  _LT_LANG_$1_CONFIG($1)])dnl
++])# _LT_LANG
+ 
+-    exit (status);
+-}]
+-EOF
+-  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+-    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+-    lt_status=$?
+-    case x$lt_status in
+-      x$lt_dlno_uscore) $1 ;;
+-      x$lt_dlneed_uscore) $2 ;;
+-      x$lt_dlunknown|x*) $3 ;;
+-    esac
+-  else :
+-    # compilation failed
+-    $3
+-  fi
+-fi
+-rm -fr conftest*
+-])# _LT_AC_TRY_DLOPEN_SELF
+ 
++# _LT_LANG_DEFAULT_CONFIG
++# -----------------------
++m4_defun([_LT_LANG_DEFAULT_CONFIG],
++[AC_PROVIDE_IFELSE([AC_PROG_CXX],
++  [LT_LANG(CXX)],
++  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
++
++AC_PROVIDE_IFELSE([AC_PROG_F77],
++  [LT_LANG(F77)],
++  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
++
++AC_PROVIDE_IFELSE([AC_PROG_FC],
++  [LT_LANG(FC)],
++  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
++
++dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
++dnl pulling things in needlessly.
++AC_PROVIDE_IFELSE([AC_PROG_GCJ],
++  [LT_LANG(GCJ)],
++  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
++    [LT_LANG(GCJ)],
++    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
++      [LT_LANG(GCJ)],
++      [m4_ifdef([AC_PROG_GCJ],
++	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
++       m4_ifdef([A][M_PROG_GCJ],
++	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
++       m4_ifdef([LT_PROG_GCJ],
++	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
++
++AC_PROVIDE_IFELSE([LT_PROG_RC],
++  [LT_LANG(RC)],
++  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
++])# _LT_LANG_DEFAULT_CONFIG
++
++# Obsolete macros:
++AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
++AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
++AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
++AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
++dnl AC_DEFUN([AC_LIBTOOL_F77], [])
++dnl AC_DEFUN([AC_LIBTOOL_FC], [])
++dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+ 
+-# AC_LIBTOOL_DLOPEN_SELF
+-# ----------------------
+-AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+-[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+-if test "x$enable_dlopen" != xyes; then
+-  enable_dlopen=unknown
+-  enable_dlopen_self=unknown
+-  enable_dlopen_self_static=unknown
+-else
+-  lt_cv_dlopen=no
+-  lt_cv_dlopen_libs=
+ 
+-  case $host_os in
+-  beos*)
+-    lt_cv_dlopen="load_add_on"
+-    lt_cv_dlopen_libs=
+-    lt_cv_dlopen_self=yes
+-    ;;
++# _LT_TAG_COMPILER
++# ----------------
++m4_defun([_LT_TAG_COMPILER],
++[AC_REQUIRE([AC_PROG_CC])dnl
+ 
+-  mingw* | pw32*)
+-    lt_cv_dlopen="LoadLibrary"
+-    lt_cv_dlopen_libs=
+-   ;;
++_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
++_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
++_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
++_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+ 
+-  cygwin*)
+-    lt_cv_dlopen="dlopen"
+-    lt_cv_dlopen_libs=
+-   ;;
++# If no C compiler was specified, use CC.
++LTCC=${LTCC-"$CC"}
+ 
+-  darwin*)
+-  # if libdl is installed we need to link against it
+-    AC_CHECK_LIB([dl], [dlopen],
+-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+-    lt_cv_dlopen="dyld"
+-    lt_cv_dlopen_libs=
+-    lt_cv_dlopen_self=yes
+-    ])
+-   ;;
++# If no C compiler flags were specified, use CFLAGS.
++LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+ 
+-  *)
+-    AC_CHECK_FUNC([shl_load],
+-	  [lt_cv_dlopen="shl_load"],
+-      [AC_CHECK_LIB([dld], [shl_load],
+-	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+-	[AC_CHECK_FUNC([dlopen],
+-	      [lt_cv_dlopen="dlopen"],
+-	  [AC_CHECK_LIB([dl], [dlopen],
+-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+-	    [AC_CHECK_LIB([svld], [dlopen],
+-		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+-	      [AC_CHECK_LIB([dld], [dld_link],
+-		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+-	      ])
+-	    ])
+-	  ])
+-	])
+-      ])
+-    ;;
+-  esac
++# Allow CC to be a program name with arguments.
++compiler=$CC
++])# _LT_TAG_COMPILER
+ 
+-  if test "x$lt_cv_dlopen" != xno; then
+-    enable_dlopen=yes
+-  else
+-    enable_dlopen=no
+-  fi
+ 
+-  case $lt_cv_dlopen in
+-  dlopen)
+-    save_CPPFLAGS="$CPPFLAGS"
+-    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
++# _LT_COMPILER_BOILERPLATE
++# ------------------------
++# Check for compiler boilerplate output or warnings with
++# the simple compiler test code.
++m4_defun([_LT_COMPILER_BOILERPLATE],
++[m4_require([_LT_DECL_SED])dnl
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_compile_test_code" >conftest.$ac_ext
++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_compiler_boilerplate=`cat conftest.err`
++$RM conftest*
++])# _LT_COMPILER_BOILERPLATE
+ 
+-    save_LDFLAGS="$LDFLAGS"
+-    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ 
+-    save_LIBS="$LIBS"
+-    LIBS="$lt_cv_dlopen_libs $LIBS"
++# _LT_LINKER_BOILERPLATE
++# ----------------------
++# Check for linker boilerplate output or warnings with
++# the simple link test code.
++m4_defun([_LT_LINKER_BOILERPLATE],
++[m4_require([_LT_DECL_SED])dnl
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_link_test_code" >conftest.$ac_ext
++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_linker_boilerplate=`cat conftest.err`
++$RM -r conftest*
++])# _LT_LINKER_BOILERPLATE
+ 
+-    AC_CACHE_CHECK([whether a program can dlopen itself],
+-	  lt_cv_dlopen_self, [dnl
+-	  _LT_AC_TRY_DLOPEN_SELF(
+-	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+-	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
++# _LT_REQUIRED_DARWIN_CHECKS
++# -------------------------
++m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
++  case $host_os in
++    rhapsody* | darwin*)
++    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
++    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
++    AC_CHECK_TOOL([LIPO], [lipo], [:])
++    AC_CHECK_TOOL([OTOOL], [otool], [:])
++    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
++    _LT_DECL([], [DSYMUTIL], [1],
++      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
++    _LT_DECL([], [NMEDIT], [1],
++      [Tool to change global to local symbols on Mac OS X])
++    _LT_DECL([], [LIPO], [1],
++      [Tool to manipulate fat objects and archives on Mac OS X])
++    _LT_DECL([], [OTOOL], [1],
++      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
++    _LT_DECL([], [OTOOL64], [1],
++      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
++
++    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
++      [lt_cv_apple_cc_single_mod=no
++      if test -z "${LT_MULTI_MODULE}"; then
++	# By default we will add the -single_module flag. You can override
++	# by either setting the environment variable LT_MULTI_MODULE
++	# non-empty at configure time, or by adding -multi_module to the
++	# link flags.
++	rm -rf libconftest.dylib*
++	echo "int foo(void){return 1;}" > conftest.c
++	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
++	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
++        _lt_result=$?
++	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
++	  lt_cv_apple_cc_single_mod=yes
++	else
++	  cat conftest.err >&AS_MESSAGE_LOG_FD
++	fi
++	rm -rf libconftest.dylib*
++	rm -f conftest.*
++      fi])
++    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
++      [lt_cv_ld_exported_symbols_list],
++      [lt_cv_ld_exported_symbols_list=no
++      save_LDFLAGS=$LDFLAGS
++      echo "_main" > conftest.sym
++      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
++      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
++	[lt_cv_ld_exported_symbols_list=yes],
++	[lt_cv_ld_exported_symbols_list=no])
++	LDFLAGS="$save_LDFLAGS"
+     ])
+-
+-    if test "x$lt_cv_dlopen_self" = xyes; then
+-      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+-      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+-    	  lt_cv_dlopen_self_static, [dnl
+-	  _LT_AC_TRY_DLOPEN_SELF(
+-	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+-	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+-      ])
++    case $host_os in
++    rhapsody* | darwin1.[[012]])
++      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
++    darwin1.*)
++      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++    darwin*) # darwin 5.x on 
++      # if running on 10.5 or later, the deployment target defaults
++      # to the OS version, if on x86, and 10.4, the deployment
++      # target defaults to 10.4. Don't you love it? 
++      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
++	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
++	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++	10.[[012]]*)
++	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++	10.*)
++	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++      esac
++    ;;
++  esac
++    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
++      _lt_dar_single_mod='$single_module'
++    fi
++    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
++      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
++    else
++      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
++    fi
++    if test "$DSYMUTIL" != ":"; then
++      _lt_dsymutil='~$DSYMUTIL $lib || :'
++    else
++      _lt_dsymutil=
+     fi
+-
+-    CPPFLAGS="$save_CPPFLAGS"
+-    LDFLAGS="$save_LDFLAGS"
+-    LIBS="$save_LIBS"
+     ;;
+   esac
++])
+ 
+-  case $lt_cv_dlopen_self in
+-  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+-  *) enable_dlopen_self=unknown ;;
+-  esac
+ 
+-  case $lt_cv_dlopen_self_static in
+-  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+-  *) enable_dlopen_self_static=unknown ;;
+-  esac
+-fi
+-])# AC_LIBTOOL_DLOPEN_SELF
++# _LT_DARWIN_LINKER_FEATURES
++# --------------------------
++# Checks for linker and compiler features on darwin
++m4_defun([_LT_DARWIN_LINKER_FEATURES],
++[
++  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
++  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++  _LT_TAGVAR(hardcode_direct, $1)=no
++  _LT_TAGVAR(hardcode_automatic, $1)=yes
++  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++  _LT_TAGVAR(whole_archive_flag_spec, $1)=''
++  _LT_TAGVAR(link_all_deplibs, $1)=yes
++  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
++  if test "$GCC" = "yes"; then
++    output_verbose_link_cmd=echo
++    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
++    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
++    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
++    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
++    m4_if([$1], [CXX],
++[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
++      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
++      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
++    fi
++],[])
++  else
++  _LT_TAGVAR(ld_shlibs, $1)=no
++  fi
++])
+ 
++# _LT_SYS_MODULE_PATH_AIX
++# -----------------------
++# Links a minimal program and checks the executable
++# for the system default hardcoded library path. In most cases,
++# this is /usr/lib:/lib, but when the MPI compilers are used
++# the location of the communication and MPI libs are included too.
++# If we don't find anything, use the default library path according
++# to the aix ld manual.
++m4_defun([_LT_SYS_MODULE_PATH_AIX],
++[m4_require([_LT_DECL_SED])dnl
++AC_LINK_IFELSE(AC_LANG_PROGRAM,[
++lt_aix_libpath_sed='
++    /Import File Strings/,/^$/ {
++	/^0/ {
++	    s/^0  *\(.*\)$/\1/
++	    p
++	}
++    }'
++aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++# Check for a 64-bit object if we didn't find anything.
++if test -z "$aix_libpath"; then
++  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++fi],[])
++if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
++])# _LT_SYS_MODULE_PATH_AIX
+ 
+-# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+-# ---------------------------------
+-# Check to see if options -c and -o are simultaneously supported by compiler
+-AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+-[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+-  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+-  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+-   $rm -r conftest 2>/dev/null
+-   mkdir conftest
+-   cd conftest
+-   mkdir out
+-   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
+-   lt_compiler_flag="-o out/conftest2.$ac_objext"
+-   # Insert the option either (1) after the last *FLAGS variable, or
+-   # (2) before a word containing "conftest.", or (3) at the end.
+-   # Note that $ac_compile itself does not contain backslashes and begins
+-   # with a dollar sign (not a hyphen), so the echo should work correctly.
+-   lt_compile=`echo "$ac_compile" | $SED \
+-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+-   -e 's:$: $lt_compiler_flag:'`
+-   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+-   (eval "$lt_compile" 2>out/conftest.err)
+-   ac_status=$?
+-   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+-   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+-   then
+-     # The compiler can only warn and ignore the option if not recognized
+-     # So say no if there are warnings
+-     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+-       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+-     fi
+-   fi
+-   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+-   $rm conftest*
+-   # SGI C++ compiler will create directory out/ii_files/ for
+-   # template instantiation
+-   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+-   $rm out/* && rmdir out
+-   cd ..
+-   rmdir conftest
+-   $rm conftest*
+-])
+-])# AC_LIBTOOL_PROG_CC_C_O
++# _LT_SHELL_INIT(ARG)
++# -------------------
++m4_define([_LT_SHELL_INIT],
++[ifdef([AC_DIVERSION_NOTICE],
++	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
++	 [AC_DIVERT_PUSH(NOTICE)])
++$1
++AC_DIVERT_POP
++])# _LT_SHELL_INIT
+ 
+ 
+-# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+-# -----------------------------------------
+-# Check to see if we can do hard links to lock some files if needed
+-AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+-[AC_REQUIRE([_LT_AC_LOCK])dnl
++# _LT_PROG_ECHO_BACKSLASH
++# -----------------------
++# Add some code to the start of the generated configure script which
++# will find an echo command which doesn't interpret backslashes.
++m4_defun([_LT_PROG_ECHO_BACKSLASH],
++[_LT_SHELL_INIT([
++# Check that we are running under the correct shell.
++SHELL=${CONFIG_SHELL-/bin/sh}
+ 
+-hard_links="nottested"
+-if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+-  # do not overwrite the value of need_locks provided by the user
+-  AC_MSG_CHECKING([if we can lock with hard links])
+-  hard_links=yes
+-  $rm conftest*
+-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+-  touch conftest.a
+-  ln conftest.a conftest.b 2>&5 || hard_links=no
+-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+-  AC_MSG_RESULT([$hard_links])
+-  if test "$hard_links" = no; then
+-    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+-    need_locks=warn
+-  fi
++case X$lt_ECHO in
++X*--fallback-echo)
++  # Remove one level of quotation (which was required for Make).
++  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
++  ;;
++esac
++
++ECHO=${lt_ECHO-echo}
++if test "X[$]1" = X--no-reexec; then
++  # Discard the --no-reexec flag, and continue.
++  shift
++elif test "X[$]1" = X--fallback-echo; then
++  # Avoid inline document here, it may be left over
++  :
++elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
++  # Yippee, $ECHO works!
++  :
+ else
+-  need_locks=no
++  # Restart under the correct shell.
++  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+ fi
+-])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+ 
+-
+-# AC_LIBTOOL_OBJDIR
+-# -----------------
+-AC_DEFUN([AC_LIBTOOL_OBJDIR],
+-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+-[rm -f .libs 2>/dev/null
+-mkdir .libs 2>/dev/null
+-if test -d .libs; then
+-  lt_cv_objdir=.libs
+-else
+-  # MS-DOS does not allow filenames that begin with a dot.
+-  lt_cv_objdir=_libs
++if test "X[$]1" = X--fallback-echo; then
++  # used as fallback echo
++  shift
++  cat <<_LT_EOF
++[$]*
++_LT_EOF
++  exit 0
+ fi
+-rmdir .libs 2>/dev/null])
+-objdir=$lt_cv_objdir
+-])# AC_LIBTOOL_OBJDIR
+ 
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+ 
+-# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+-# ----------------------------------------------
+-# Check hardcoding attributes.
+-AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+-[AC_MSG_CHECKING([how to hardcode library paths into programs])
+-_LT_AC_TAGVAR(hardcode_action, $1)=
+-if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+-   test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+-   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+-
+-  # We can hardcode non-existant directories.
+-  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+-     # have to relink, otherwise we might link with an installed library
+-     # when we should be linking with a yet-to-be-installed one
+-     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+-     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+-    # Linking always hardcodes the temporary library directory.
+-    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+-  else
+-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+-    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
++if test -z "$lt_ECHO"; then
++  if test "X${echo_test_string+set}" != Xset; then
++    # find a string as large as possible, as long as the shell can cope with it
++    for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
++      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
++      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
++	 { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
++      then
++        break
++      fi
++    done
+   fi
+-else
+-  # We cannot hardcode anything, or else we can only hardcode existing
+-  # directories.
+-  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+-fi
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+ 
+-if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+-  # Fast installation is not supported
+-  enable_fast_install=no
+-elif test "$shlibpath_overrides_runpath" = yes ||
+-     test "$enable_shared" = no; then
+-  # Fast installation is not necessary
+-  enable_fast_install=needless
+-fi
+-])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
++  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
++     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
++     test "X$echo_testing_string" = "X$echo_test_string"; then
++    :
++  else
++    # The Solaris, AIX, and Digital Unix default echo programs unquote
++    # backslashes.  This makes it impossible to quote backslashes using
++    #   echo "$something" | sed 's/\\/\\\\/g'
++    #
++    # So, first we look for a working echo in the user's PATH.
+ 
++    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++    for dir in $PATH /usr/ucb; do
++      IFS="$lt_save_ifs"
++      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
++         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
++         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
++         test "X$echo_testing_string" = "X$echo_test_string"; then
++        ECHO="$dir/echo"
++        break
++      fi
++    done
++    IFS="$lt_save_ifs"
+ 
+-# AC_LIBTOOL_SYS_LIB_STRIP
+-# ------------------------
+-AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+-[striplib=
+-old_striplib=
+-AC_MSG_CHECKING([whether stripping libraries is possible])
+-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+-  AC_MSG_RESULT([yes])
+-else
+-# FIXME - insert some real tests, host_os isn't really good enough
+-  case $host_os in
+-   darwin*)
+-       if test -n "$STRIP" ; then
+-         striplib="$STRIP -x"
+-         AC_MSG_RESULT([yes])
+-       else
+-  AC_MSG_RESULT([no])
+-fi
+-       ;;
+-   *)
+-  AC_MSG_RESULT([no])
+-    ;;
+-  esac
+-fi
+-])# AC_LIBTOOL_SYS_LIB_STRIP
++    if test "X$ECHO" = Xecho; then
++      # We didn't find a better echo, so look for alternatives.
++      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
++         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
++         test "X$echo_testing_string" = "X$echo_test_string"; then
++        # This shell has a builtin print -r that does the trick.
++        ECHO='print -r'
++      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
++	   test "X$CONFIG_SHELL" != X/bin/ksh; then
++        # If we have ksh, try running configure again with it.
++        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
++        export ORIGINAL_CONFIG_SHELL
++        CONFIG_SHELL=/bin/ksh
++        export CONFIG_SHELL
++        exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
++      else
++        # Try using printf.
++        ECHO='printf %s\n'
++        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
++	   echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
++	   test "X$echo_testing_string" = "X$echo_test_string"; then
++	  # Cool, printf works
++	  :
++        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
++	     test "X$echo_testing_string" = 'X\t' &&
++	     echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
++	     test "X$echo_testing_string" = "X$echo_test_string"; then
++	  CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
++	  export CONFIG_SHELL
++	  SHELL="$CONFIG_SHELL"
++	  export SHELL
++	  ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
++        elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
++	     test "X$echo_testing_string" = 'X\t' &&
++	     echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
++	     test "X$echo_testing_string" = "X$echo_test_string"; then
++	  ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
++        else
++	  # maybe with a smaller string...
++	  prev=:
+ 
++	  for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
++	    if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
++	    then
++	      break
++	    fi
++	    prev="$cmd"
++	  done
+ 
+-# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+-# -----------------------------
+-# PORTME Fill in your ld.so characteristics
+-AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+-[AC_MSG_CHECKING([dynamic linker characteristics])
+-library_names_spec=
+-libname_spec='lib$name'
+-soname_spec=
+-shrext_cmds=".so"
+-postinstall_cmds=
+-postuninstall_cmds=
+-finish_cmds=
+-finish_eval=
+-shlibpath_var=
+-shlibpath_overrides_runpath=unknown
+-version_type=none
+-dynamic_linker="$host_os ld.so"
+-sys_lib_dlsearch_path_spec="/lib /usr/lib"
+-if test "$GCC" = yes; then
+-  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+-  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+-    # if the path contains ";" then we assume it to be the separator
+-    # otherwise default to the standard path separator (i.e. ":") - it is
+-    # assumed that no part of a normal pathname contains ";" but that should
+-    # okay in the real world where ";" in dirpaths is itself problematic.
+-    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+-  else
+-    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
++	  if test "$prev" != 'sed 50q "[$]0"'; then
++	    echo_test_string=`eval $prev`
++	    export echo_test_string
++	    exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
++	  else
++	    # Oops.  We lost completely, so just stick with echo.
++	    ECHO=echo
++	  fi
++        fi
++      fi
++    fi
+   fi
+-else
+-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ fi
+-need_lib_prefix=unknown
+-hardcode_into_libs=no
+ 
+-# when you set need_version to no, make sure it does not cause -set_version
+-# flags to be left without arguments
+-need_version=unknown
++# Copy echo and quote the copy suitably for passing to libtool from
++# the Makefile, instead of quoting the original, which is used later.
++lt_ECHO=$ECHO
++if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
++   lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
++fi
+ 
+-case $host_os in
+-aix3*)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+-  shlibpath_var=LIBPATH
++AC_SUBST(lt_ECHO)
++])
++_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
++_LT_DECL([], [ECHO], [1],
++    [An echo program that does not interpret backslashes])
++])# _LT_PROG_ECHO_BACKSLASH
+ 
+-  # AIX 3 has no versioning support, so we append a major version to the name.
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  ;;
+ 
+-aix4* | aix5*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  hardcode_into_libs=yes
+-  if test "$host_cpu" = ia64; then
+-    # AIX 5 supports IA64
+-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+-    shlibpath_var=LD_LIBRARY_PATH
+-  else
+-    # With GCC up to 2.95.x, collect2 would create an import file
+-    # for dependence libraries.  The import file would start with
+-    # the line `#! .'.  This would cause the generated library to
+-    # depend on `.', always an invalid library.  This was fixed in
+-    # development snapshots of GCC prior to 3.0.
+-    case $host_os in
+-      aix4 | aix4.[[01]] | aix4.[[01]].*)
+-      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+-	   echo ' yes '
+-	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+-	:
+-      else
+-	can_build_shared=no
+-      fi
+-      ;;
++# _LT_ENABLE_LOCK
++# ---------------
++m4_defun([_LT_ENABLE_LOCK],
++[AC_ARG_ENABLE([libtool-lock],
++  [AS_HELP_STRING([--disable-libtool-lock],
++    [avoid locking (might break parallel builds)])])
++test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++
++# Some flags need to be propagated to the compiler or linker for good
++# libtool support.
++case $host in
++ia64-*-hpux*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.$ac_objext` in
++      *ELF-32*)
++	HPUX_IA64_MODE="32"
++	;;
++      *ELF-64*)
++	HPUX_IA64_MODE="64"
++	;;
+     esac
+-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+-    # soname into executable. Probably we can add versioning support to
+-    # collect2, so additional links can be useful in future.
+-    if test "$aix_use_runtimelinking" = yes; then
+-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+-      # instead of lib<name>.a to let people know that these are not
+-      # typical AIX shared libraries.
+-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  fi
++  rm -rf conftest*
++  ;;
++*-*-irix6*)
++  # Find out which ABI we are using.
++  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    if test "$lt_cv_prog_gnu_ld" = yes; then
++      case `/usr/bin/file conftest.$ac_objext` in
++	*32-bit*)
++	  LD="${LD-ld} -melf32bsmip"
++	  ;;
++	*N32*)
++	  LD="${LD-ld} -melf32bmipn32"
++	  ;;
++	*64-bit*)
++	  LD="${LD-ld} -melf64bmip"
++	;;
++      esac
+     else
+-      # We preserve .a as extension for shared libraries through AIX4.2
+-      # and later when we are not doing run time linking.
+-      library_names_spec='${libname}${release}.a $libname.a'
+-      soname_spec='${libname}${release}${shared_ext}$major'
++      case `/usr/bin/file conftest.$ac_objext` in
++	*32-bit*)
++	  LD="${LD-ld} -32"
++	  ;;
++	*N32*)
++	  LD="${LD-ld} -n32"
++	  ;;
++	*64-bit*)
++	  LD="${LD-ld} -64"
++	  ;;
++      esac
+     fi
+-    shlibpath_var=LIBPATH
+   fi
++  rm -rf conftest*
+   ;;
+ 
+-amigaos*)
+-  library_names_spec='$libname.ixlibrary $libname.a'
+-  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+-  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
++x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
++s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.o` in
++      *32-bit*)
++	case $host in
++	  x86_64-*kfreebsd*-gnu)
++	    LD="${LD-ld} -m elf_i386_fbsd"
++	    ;;
++	  x86_64-*linux*)
++	    LD="${LD-ld} -m elf_i386"
++	    ;;
++	  ppc64-*linux*|powerpc64-*linux*)
++	    LD="${LD-ld} -m elf32ppclinux"
++	    ;;
++	  s390x-*linux*)
++	    LD="${LD-ld} -m elf_s390"
++	    ;;
++	  sparc64-*linux*)
++	    LD="${LD-ld} -m elf32_sparc"
++	    ;;
++	esac
++	;;
++      *64-bit*)
++	case $host in
++	  x86_64-*kfreebsd*-gnu)
++	    LD="${LD-ld} -m elf_x86_64_fbsd"
++	    ;;
++	  x86_64-*linux*)
++	    LD="${LD-ld} -m elf_x86_64"
++	    ;;
++	  ppc*-*linux*|powerpc*-*linux*)
++	    LD="${LD-ld} -m elf64ppc"
++	    ;;
++	  s390*-*linux*|s390*-*tpf*)
++	    LD="${LD-ld} -m elf64_s390"
++	    ;;
++	  sparc*-*linux*)
++	    LD="${LD-ld} -m elf64_sparc"
++	    ;;
++	esac
++	;;
++    esac
++  fi
++  rm -rf conftest*
+   ;;
+ 
+-beos*)
+-  library_names_spec='${libname}${shared_ext}'
+-  dynamic_linker="$host_os ld.so"
+-  shlibpath_var=LIBRARY_PATH
++*-*-sco3.2v5*)
++  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
++  SAVE_CFLAGS="$CFLAGS"
++  CFLAGS="$CFLAGS -belf"
++  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
++    [AC_LANG_PUSH(C)
++     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
++     AC_LANG_POP])
++  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
++    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
++    CFLAGS="$SAVE_CFLAGS"
++  fi
+   ;;
+-
+-bsdi[[45]]*)
+-  version_type=linux
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+-  # the default ld.so.conf also contains /usr/contrib/lib and
+-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+-  # libtool to hard-code these into programs
++sparc*-*solaris*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.o` in
++    *64-bit*)
++      case $lt_cv_prog_gnu_ld in
++      yes*) LD="${LD-ld} -m elf64_sparc" ;;
++      *)
++	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
++	  LD="${LD-ld} -64"
++	fi
++	;;
++      esac
++      ;;
++    esac
++  fi
++  rm -rf conftest*
+   ;;
++esac
+ 
+-cygwin* | mingw* | pw32*)
+-  version_type=windows
+-  shrext_cmds=".dll"
+-  need_version=no
+-  need_lib_prefix=no
++need_locks="$enable_libtool_lock"
++])# _LT_ENABLE_LOCK
+ 
+-  case $GCC,$host_os in
+-  yes,cygwin* | yes,mingw* | yes,pw32*)
+-    library_names_spec='$libname.dll.a'
+-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+-    postinstall_cmds='base_file=`basename \${file}`~
+-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+-      dldir=$destdir/`dirname \$dlpath`~
+-      test -d \$dldir || mkdir -p \$dldir~
+-      $install_prog $dir/$dlname \$dldir/$dlname~
+-      chmod a+x \$dldir/$dlname'
+-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+-      dlpath=$dir/\$dldll~
+-       $rm \$dlpath'
+-    shlibpath_overrides_runpath=yes
+ 
+-    case $host_os in
+-    cygwin*)
+-      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+-      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+-      ;;
+-    mingw*)
+-      # MinGW DLLs use traditional 'lib' prefix
+-      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+-      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+-      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+-        # It is most probably a Windows format PATH printed by
+-        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+-        # path with ; separators, and with drive letters. We can handle the
+-        # drive letters (cygwin fileutils understands them), so leave them,
+-        # especially as we might pass files found there to a mingw objdump,
+-        # which wouldn't understand a cygwinified path. Ahh.
+-        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+-      else
+-        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+-      fi
+-      ;;
+-    pw32*)
+-      # pw32 DLLs use 'pw' prefix rather than 'lib'
+-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+-      ;;
+-    esac
+-    ;;
++# _LT_CMD_OLD_ARCHIVE
++# -------------------
++m4_defun([_LT_CMD_OLD_ARCHIVE],
++[AC_CHECK_TOOL(AR, ar, false)
++test -z "$AR" && AR=ar
++test -z "$AR_FLAGS" && AR_FLAGS=cru
++_LT_DECL([], [AR], [1], [The archiver])
++_LT_DECL([], [AR_FLAGS], [1])
++
++AC_CHECK_TOOL(STRIP, strip, :)
++test -z "$STRIP" && STRIP=:
++_LT_DECL([], [STRIP], [1], [A symbol stripping program])
++
++AC_CHECK_TOOL(RANLIB, ranlib, :)
++test -z "$RANLIB" && RANLIB=:
++_LT_DECL([], [RANLIB], [1],
++    [Commands used to install an old-style archive])
++
++# Determine commands to create old-style static archives.
++old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
++old_postinstall_cmds='chmod 644 $oldlib'
++old_postuninstall_cmds=
+ 
++if test -n "$RANLIB"; then
++  case $host_os in
++  openbsd*)
++    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
++    ;;
+   *)
+-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
++    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+     ;;
+   esac
+-  dynamic_linker='Win32 ld.exe'
+-  # FIXME: first we should search . and the directory the executable is in
+-  shlibpath_var=PATH
+-  ;;
++  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
++fi
++_LT_DECL([], [old_postinstall_cmds], [2])
++_LT_DECL([], [old_postuninstall_cmds], [2])
++_LT_TAGDECL([], [old_archive_cmds], [2],
++    [Commands used to build an old-style archive])
++])# _LT_CMD_OLD_ARCHIVE
+ 
+-darwin* | rhapsody*)
+-  dynamic_linker="$host_os dyld"
+-  version_type=darwin
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+-  soname_spec='${libname}${release}${major}$shared_ext'
+-  shlibpath_overrides_runpath=yes
+-  shlibpath_var=DYLD_LIBRARY_PATH
+-  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+-  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+-  if test "$GCC" = yes; then
+-    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+-  else
+-    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+-  fi
+-  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+-  ;;
+ 
+-dgux*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  ;;
++# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
++#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
++# ----------------------------------------------------------------
++# Check whether the given compiler option works
++AC_DEFUN([_LT_COMPILER_OPTION],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_CACHE_CHECK([$1], [$2],
++  [$2=no
++   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
++   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++   lt_compiler_flag="$3"
++   # Insert the option either (1) after the last *FLAGS variable, or
++   # (2) before a word containing "conftest.", or (3) at the end.
++   # Note that $ac_compile itself does not contain backslashes and begins
++   # with a dollar sign (not a hyphen), so the echo should work correctly.
++   # The option is referenced via a variable to avoid confusing sed.
++   lt_compile=`echo "$ac_compile" | $SED \
++   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
++   -e 's:$: $lt_compiler_flag:'`
++   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
++   (eval "$lt_compile" 2>conftest.err)
++   ac_status=$?
++   cat conftest.err >&AS_MESSAGE_LOG_FD
++   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
++   if (exit $ac_status) && test -s "$ac_outfile"; then
++     # The compiler can only warn and ignore the option if not recognized
++     # So say no if there are warnings other than the usual output.
++     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
++     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
++       $2=yes
++     fi
++   fi
++   $RM conftest*
++])
+ 
+-freebsd1*)
+-  dynamic_linker=no
+-  ;;
++if test x"[$]$2" = xyes; then
++    m4_if([$5], , :, [$5])
++else
++    m4_if([$6], , :, [$6])
++fi
++])# _LT_COMPILER_OPTION
+ 
+-kfreebsd*-gnu)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  dynamic_linker='GNU ld.so'
+-  ;;
++# Old name:
++AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+ 
+-freebsd* | dragonfly*)
+-  # DragonFly does not have aout.  When/if they implement a new
+-  # versioning mechanism, adjust this.
+-  if test -x /usr/bin/objformat; then
+-    objformat=`/usr/bin/objformat`
+-  else
+-    case $host_os in
+-    freebsd[[123]]*) objformat=aout ;;
+-    *) objformat=elf ;;
+-    esac
+-  fi
+-  version_type=freebsd-$objformat
+-  case $version_type in
+-    freebsd-elf*)
+-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+-      need_version=no
+-      need_lib_prefix=no
+-      ;;
+-    freebsd-*)
+-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+-      need_version=yes
+-      ;;
+-  esac
+-  shlibpath_var=LD_LIBRARY_PATH
+-  case $host_os in
+-  freebsd2*)
+-    shlibpath_overrides_runpath=yes
+-    ;;
+-  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+-    shlibpath_overrides_runpath=yes
+-    hardcode_into_libs=yes
++
++# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
++#                  [ACTION-SUCCESS], [ACTION-FAILURE])
++# ----------------------------------------------------
++# Check whether the given linker option works
++AC_DEFUN([_LT_LINKER_OPTION],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_CACHE_CHECK([$1], [$2],
++  [$2=no
++   save_LDFLAGS="$LDFLAGS"
++   LDFLAGS="$LDFLAGS $3"
++   echo "$lt_simple_link_test_code" > conftest.$ac_ext
++   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
++     # The linker can only warn and ignore the option if not recognized
++     # So say no if there are warnings
++     if test -s conftest.err; then
++       # Append any errors to the config.log.
++       cat conftest.err 1>&AS_MESSAGE_LOG_FD
++       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
++       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++       if diff conftest.exp conftest.er2 >/dev/null; then
++         $2=yes
++       fi
++     else
++       $2=yes
++     fi
++   fi
++   $RM -r conftest*
++   LDFLAGS="$save_LDFLAGS"
++])
++
++if test x"[$]$2" = xyes; then
++    m4_if([$4], , :, [$4])
++else
++    m4_if([$5], , :, [$5])
++fi
++])# _LT_LINKER_OPTION
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
++
++
++# LT_CMD_MAX_LEN
++#---------------
++AC_DEFUN([LT_CMD_MAX_LEN],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++# find the maximum length of command line arguments
++AC_MSG_CHECKING([the maximum length of command line arguments])
++AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
++  i=0
++  teststring="ABCD"
++
++  case $build_os in
++  msdosdjgpp*)
++    # On DJGPP, this test can blow up pretty badly due to problems in libc
++    # (any single argument exceeding 2000 bytes causes a buffer overrun
++    # during glob expansion).  Even if it were fixed, the result of this
++    # check would be larger than it should be.
++    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+     ;;
+-  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+-  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+-    shlibpath_overrides_runpath=no
+-    hardcode_into_libs=yes
++
++  gnu*)
++    # Under GNU Hurd, this test is not required because there is
++    # no limit to the length of command line arguments.
++    # Libtool will interpret -1 as no limit whatsoever
++    lt_cv_sys_max_cmd_len=-1;
+     ;;
+-  freebsd*) # from 4.6 on
+-    shlibpath_overrides_runpath=yes
+-    hardcode_into_libs=yes
++
++  cygwin* | mingw*)
++    # On Win9x/ME, this test blows up -- it succeeds, but takes
++    # about 5 minutes as the teststring grows exponentially.
++    # Worse, since 9x/ME are not pre-emptively multitasking,
++    # you end up with a "frozen" computer, even though with patience
++    # the test eventually succeeds (with a max line length of 256k).
++    # Instead, let's just punt: use the minimum linelength reported by
++    # all of the supported platforms: 8192 (on NT/2K/XP).
++    lt_cv_sys_max_cmd_len=8192;
+     ;;
+-  esac
+-  ;;
+ 
+-gnu*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  hardcode_into_libs=yes
+-  ;;
++  amigaos*)
++    # On AmigaOS with pdksh, this test takes hours, literally.
++    # So we just punt and use a minimum line length of 8192.
++    lt_cv_sys_max_cmd_len=8192;
++    ;;
+ 
+-hpux9* | hpux10* | hpux11*)
+-  # Give a soname corresponding to the major version so that dld.sl refuses to
+-  # link against other versions.
+-  version_type=sunos
+-  need_lib_prefix=no
+-  need_version=no
+-  case $host_cpu in
+-  ia64*)
+-    shrext_cmds='.so'
+-    hardcode_into_libs=yes
+-    dynamic_linker="$host_os dld.so"
+-    shlibpath_var=LD_LIBRARY_PATH
+-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-    soname_spec='${libname}${release}${shared_ext}$major'
+-    if test "X$HPUX_IA64_MODE" = X32; then
+-      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
++  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
++    # This has been around since 386BSD, at least.  Likely further.
++    if test -x /sbin/sysctl; then
++      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
++    elif test -x /usr/sbin/sysctl; then
++      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+     else
+-      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
++      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+     fi
+-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+-    ;;
+-   hppa*64*)
+-     shrext_cmds='.sl'
+-     hardcode_into_libs=yes
+-     dynamic_linker="$host_os dld.sl"
+-     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+-     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+-     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-     soname_spec='${libname}${release}${shared_ext}$major'
+-     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+-     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+-     ;;
+-   *)
+-    shrext_cmds='.sl'
+-    dynamic_linker="$host_os dld.sl"
+-    shlibpath_var=SHLIB_PATH
+-    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-    soname_spec='${libname}${release}${shared_ext}$major'
++    # And add a safety zone
++    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+     ;;
+-  esac
+-  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+-  postinstall_cmds='chmod 555 $lib'
+-  ;;
+ 
+-interix3*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  ;;
++  interix*)
++    # We know the value 262144 and hardcode it with a safety zone (like BSD)
++    lt_cv_sys_max_cmd_len=196608
++    ;;
+ 
+-irix5* | irix6* | nonstopux*)
+-  case $host_os in
+-    nonstopux*) version_type=nonstopux ;;
+-    *)
+-	if test "$lt_cv_prog_gnu_ld" = yes; then
+-		version_type=linux
+-	else
+-		version_type=irix
+-	fi ;;
+-  esac
+-  need_lib_prefix=no
+-  need_version=no
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+-  case $host_os in
+-  irix5* | nonstopux*)
+-    libsuff= shlibsuff=
++  osf*)
++    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
++    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
++    # nice to cause kernel panics so lets avoid the loop below.
++    # First set a reasonable default.
++    lt_cv_sys_max_cmd_len=16384
++    #
++    if test -x /sbin/sysconfig; then
++      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
++        *1*) lt_cv_sys_max_cmd_len=-1 ;;
++      esac
++    fi
++    ;;
++  sco3.2v5*)
++    lt_cv_sys_max_cmd_len=102400
++    ;;
++  sysv5* | sco5v6* | sysv4.2uw2*)
++    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
++    if test -n "$kargmax"; then
++      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
++    else
++      lt_cv_sys_max_cmd_len=32768
++    fi
+     ;;
+   *)
+-    case $LD in # libtool.m4 will add one of these switches to LD
+-    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+-      libsuff= shlibsuff= libmagic=32-bit;;
+-    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+-      libsuff=32 shlibsuff=N32 libmagic=N32;;
+-    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+-      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+-    *) libsuff= shlibsuff= libmagic=never-match;;
+-    esac
++    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
++    if test -n "$lt_cv_sys_max_cmd_len"; then
++      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
++    else
++      # Make teststring a little bigger before we do anything with it.
++      # a 1K string should be a reasonable start.
++      for i in 1 2 3 4 5 6 7 8 ; do
++        teststring=$teststring$teststring
++      done
++      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
++      # If test is not a shell built-in, we'll probably end up computing a
++      # maximum length that is only half of the actual maximum length, but
++      # we can't tell.
++      while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
++	         = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
++	      test $i != 17 # 1/2 MB should be enough
++      do
++        i=`expr $i + 1`
++        teststring=$teststring$teststring
++      done
++      # Only check the string length outside the loop.
++      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
++      teststring=
++      # Add a significant safety factor because C++ compilers can tack on
++      # massive amounts of additional arguments before passing them to the
++      # linker.  It appears as though 1/2 is a usable value.
++      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
++    fi
+     ;;
+   esac
+-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+-  shlibpath_overrides_runpath=no
+-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+-  hardcode_into_libs=yes
+-  ;;
++])
++if test -n $lt_cv_sys_max_cmd_len ; then
++  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
++else
++  AC_MSG_RESULT(none)
++fi
++max_cmd_len=$lt_cv_sys_max_cmd_len
++_LT_DECL([], [max_cmd_len], [0],
++    [What is the maximum length of a command?])
++])# LT_CMD_MAX_LEN
+ 
+-# No shared lib support for Linux oldld, aout, or coff.
+-linux*oldld* | linux*aout* | linux*coff*)
+-  dynamic_linker=no
+-  ;;
++# Old name:
++AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+ 
+-# This must be Linux ELF.
+-linux*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  # This implies no fast_install, which is unacceptable.
+-  # Some rework will be needed to allow for fast_install
+-  # before this can be enabled.
+-  hardcode_into_libs=yes
+ 
+-  # Append ld.so.conf contents to the search path
+-  if test -f /etc/ld.so.conf; then
+-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+-  fi
++# _LT_HEADER_DLFCN
++# ----------------
++m4_defun([_LT_HEADER_DLFCN],
++[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
++])# _LT_HEADER_DLFCN
+ 
+-  # We used to test for /lib/ld.so.1 and disable shared libraries on
+-  # powerpc, because MkLinux only supported shared libraries with the
+-  # GNU dynamic linker.  Since this was broken with cross compilers,
+-  # most powerpc-linux boxes support dynamic linking these days and
+-  # people can always --disable-shared, the test was removed, and we
+-  # assume the GNU/Linux dynamic linker is in use.
+-  dynamic_linker='GNU/Linux ld.so'
+-  ;;
+ 
+-knetbsd*-gnu)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  dynamic_linker='GNU ld.so'
+-  ;;
++# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
++#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
++# ----------------------------------------------------------------
++m4_defun([_LT_TRY_DLOPEN_SELF],
++[m4_require([_LT_HEADER_DLFCN])dnl
++if test "$cross_compiling" = yes; then :
++  [$4]
++else
++  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
++  lt_status=$lt_dlunknown
++  cat > conftest.$ac_ext <<_LT_EOF
++[#line __oline__ "configure"
++#include "confdefs.h"
+ 
+-netbsd*)
+-  version_type=sunos
+-  need_lib_prefix=no
+-  need_version=no
+-  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+-    dynamic_linker='NetBSD (a.out) ld.so'
+-  else
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-    soname_spec='${libname}${release}${shared_ext}$major'
+-    dynamic_linker='NetBSD ld.elf_so'
+-  fi
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  hardcode_into_libs=yes
+-  ;;
++#if HAVE_DLFCN_H
++#include <dlfcn.h>
++#endif
+ 
+-newsos6)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  ;;
++#include <stdio.h>
+ 
+-nto-qnx*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  ;;
++#ifdef RTLD_GLOBAL
++#  define LT_DLGLOBAL		RTLD_GLOBAL
++#else
++#  ifdef DL_GLOBAL
++#    define LT_DLGLOBAL		DL_GLOBAL
++#  else
++#    define LT_DLGLOBAL		0
++#  endif
++#endif
+ 
+-openbsd*)
+-  version_type=sunos
+-  sys_lib_dlsearch_path_spec="/usr/lib"
+-  need_lib_prefix=no
+-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+-  case $host_os in
+-    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+-    *)                         need_version=no  ;;
+-  esac
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-    case $host_os in
+-      openbsd2.[[89]] | openbsd2.[[89]].*)
+-	shlibpath_overrides_runpath=no
+-	;;
+-      *)
+-	shlibpath_overrides_runpath=yes
+-	;;
+-      esac
++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
++   find out it does not work in some platform. */
++#ifndef LT_DLLAZY_OR_NOW
++#  ifdef RTLD_LAZY
++#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
++#  else
++#    ifdef DL_LAZY
++#      define LT_DLLAZY_OR_NOW		DL_LAZY
++#    else
++#      ifdef RTLD_NOW
++#        define LT_DLLAZY_OR_NOW	RTLD_NOW
++#      else
++#        ifdef DL_NOW
++#          define LT_DLLAZY_OR_NOW	DL_NOW
++#        else
++#          define LT_DLLAZY_OR_NOW	0
++#        endif
++#      endif
++#    endif
++#  endif
++#endif
++
++#ifdef __cplusplus
++extern "C" void exit (int);
++#endif
++
++void fnord() { int i=42;}
++int main ()
++{
++  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
++  int status = $lt_dlunknown;
++
++  if (self)
++    {
++      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
++      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
++      /* dlclose (self); */
++    }
+   else
+-    shlibpath_overrides_runpath=yes
++    puts (dlerror ());
++
++    exit (status);
++}]
++_LT_EOF
++  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
++    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
++    lt_status=$?
++    case x$lt_status in
++      x$lt_dlno_uscore) $1 ;;
++      x$lt_dlneed_uscore) $2 ;;
++      x$lt_dlunknown|x*) $3 ;;
++    esac
++  else :
++    # compilation failed
++    $3
+   fi
+-  ;;
++fi
++rm -fr conftest*
++])# _LT_TRY_DLOPEN_SELF
+ 
+-os2*)
+-  libname_spec='$name'
+-  shrext_cmds=".dll"
+-  need_lib_prefix=no
+-  library_names_spec='$libname${shared_ext} $libname.a'
+-  dynamic_linker='OS/2 ld.exe'
+-  shlibpath_var=LIBPATH
+-  ;;
+ 
+-osf3* | osf4* | osf5*)
+-  version_type=osf
+-  need_lib_prefix=no
+-  need_version=no
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+-  ;;
++# LT_SYS_DLOPEN_SELF
++# ------------------
++AC_DEFUN([LT_SYS_DLOPEN_SELF],
++[m4_require([_LT_HEADER_DLFCN])dnl
++if test "x$enable_dlopen" != xyes; then
++  enable_dlopen=unknown
++  enable_dlopen_self=unknown
++  enable_dlopen_self_static=unknown
++else
++  lt_cv_dlopen=no
++  lt_cv_dlopen_libs=
+ 
+-solaris*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  hardcode_into_libs=yes
+-  # ldd complains unless libraries are executable
+-  postinstall_cmds='chmod +x $lib'
+-  ;;
++  case $host_os in
++  beos*)
++    lt_cv_dlopen="load_add_on"
++    lt_cv_dlopen_libs=
++    lt_cv_dlopen_self=yes
++    ;;
+ 
+-sunos4*)
+-  version_type=sunos
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  if test "$with_gnu_ld" = yes; then
+-    need_lib_prefix=no
+-  fi
+-  need_version=yes
+-  ;;
++  mingw* | pw32*)
++    lt_cv_dlopen="LoadLibrary"
++    lt_cv_dlopen_libs=
++    ;;
+ 
+-sysv4 | sysv4.3*)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  case $host_vendor in
+-    sni)
+-      shlibpath_overrides_runpath=no
+-      need_lib_prefix=no
+-      export_dynamic_flag_spec='${wl}-Blargedynsym'
+-      runpath_var=LD_RUN_PATH
+-      ;;
+-    siemens)
+-      need_lib_prefix=no
+-      ;;
+-    motorola)
+-      need_lib_prefix=no
+-      need_version=no
+-      shlibpath_overrides_runpath=no
+-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+-      ;;
+-  esac
+-  ;;
++  cygwin*)
++    lt_cv_dlopen="dlopen"
++    lt_cv_dlopen_libs=
++    ;;
+ 
+-sysv4*MP*)
+-  if test -d /usr/nec ;then
+-    version_type=linux
+-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+-    soname_spec='$libname${shared_ext}.$major'
+-    shlibpath_var=LD_LIBRARY_PATH
+-  fi
+-  ;;
++  darwin*)
++  # if libdl is installed we need to link against it
++    AC_CHECK_LIB([dl], [dlopen],
++		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
++    lt_cv_dlopen="dyld"
++    lt_cv_dlopen_libs=
++    lt_cv_dlopen_self=yes
++    ])
++    ;;
+ 
+-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+-  version_type=freebsd-elf
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  hardcode_into_libs=yes
+-  if test "$with_gnu_ld" = yes; then
+-    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+-    shlibpath_overrides_runpath=no
++  *)
++    AC_CHECK_FUNC([shl_load],
++	  [lt_cv_dlopen="shl_load"],
++      [AC_CHECK_LIB([dld], [shl_load],
++	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
++	[AC_CHECK_FUNC([dlopen],
++	      [lt_cv_dlopen="dlopen"],
++	  [AC_CHECK_LIB([dl], [dlopen],
++		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
++	    [AC_CHECK_LIB([svld], [dlopen],
++		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
++	      [AC_CHECK_LIB([dld], [dld_link],
++		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
++	      ])
++	    ])
++	  ])
++	])
++      ])
++    ;;
++  esac
++
++  if test "x$lt_cv_dlopen" != xno; then
++    enable_dlopen=yes
+   else
+-    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+-    shlibpath_overrides_runpath=yes
+-    case $host_os in
+-      sco3.2v5*)
+-        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+-	;;
+-    esac
++    enable_dlopen=no
+   fi
+-  sys_lib_dlsearch_path_spec='/usr/lib'
+-  ;;
+-
+-uts4*)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  ;;
+-
+-*)
+-  dynamic_linker=no
+-  ;;
+-esac
+-AC_MSG_RESULT([$dynamic_linker])
+-test "$dynamic_linker" = no && can_build_shared=no
+-
+-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+-if test "$GCC" = yes; then
+-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+-fi
+-])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+-
+ 
+-# _LT_AC_TAGCONFIG
+-# ----------------
+-AC_DEFUN([_LT_AC_TAGCONFIG],
+-[AC_ARG_WITH([tags],
+-    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+-        [include additional configurations @<:@automatic@:>@])],
+-    [tagnames="$withval"])
+-
+-if test -f "$ltmain" && test -n "$tagnames"; then
+-  if test ! -f "${ofile}"; then
+-    AC_MSG_WARN([output file `$ofile' does not exist])
+-  fi
++  case $lt_cv_dlopen in
++  dlopen)
++    save_CPPFLAGS="$CPPFLAGS"
++    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ 
+-  if test -z "$LTCC"; then
+-    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+-    if test -z "$LTCC"; then
+-      AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+-    else
+-      AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+-    fi
+-  fi
+-  if test -z "$LTCFLAGS"; then
+-    eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+-  fi
++    save_LDFLAGS="$LDFLAGS"
++    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ 
+-  # Extract list of available tagged configurations in $ofile.
+-  # Note that this assumes the entire list is on one line.
+-  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
++    save_LIBS="$LIBS"
++    LIBS="$lt_cv_dlopen_libs $LIBS"
+ 
+-  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-  for tagname in $tagnames; do
+-    IFS="$lt_save_ifs"
+-    # Check whether tagname contains only valid characters
+-    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+-    "") ;;
+-    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+-	;;
+-    esac
++    AC_CACHE_CHECK([whether a program can dlopen itself],
++	  lt_cv_dlopen_self, [dnl
++	  _LT_TRY_DLOPEN_SELF(
++	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
++	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
++    ])
+ 
+-    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+-    then
+-      AC_MSG_ERROR([tag name \"$tagname\" already exists])
++    if test "x$lt_cv_dlopen_self" = xyes; then
++      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
++      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
++	  lt_cv_dlopen_self_static, [dnl
++	  _LT_TRY_DLOPEN_SELF(
++	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
++	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
++      ])
+     fi
+ 
+-    # Update the list of available tags.
+-    if test -n "$tagname"; then
+-      echo appending configuration tag \"$tagname\" to $ofile
+-
+-      case $tagname in
+-      CXX)
+-	if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+-	    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+-	    (test "X$CXX" != "Xg++"))) ; then
+-	  AC_LIBTOOL_LANG_CXX_CONFIG
+-	else
+-	  tagname=""
+-	fi
+-	;;
+-
+-      F77)
+-	if test -n "$F77" && test "X$F77" != "Xno"; then
+-	  AC_LIBTOOL_LANG_F77_CONFIG
+-	else
+-	  tagname=""
+-	fi
+-	;;
+-
+-      GCJ)
+-	if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+-	  AC_LIBTOOL_LANG_GCJ_CONFIG
+-	else
+-	  tagname=""
+-	fi
+-	;;
+-
+-      RC)
+-	AC_LIBTOOL_LANG_RC_CONFIG
+-	;;
+-
+-      *)
+-	AC_MSG_ERROR([Unsupported tag name: $tagname])
+-	;;
+-      esac
++    CPPFLAGS="$save_CPPFLAGS"
++    LDFLAGS="$save_LDFLAGS"
++    LIBS="$save_LIBS"
++    ;;
++  esac
+ 
+-      # Append the new tag name to the list of available tags.
+-      if test -n "$tagname" ; then
+-      available_tags="$available_tags $tagname"
+-    fi
+-    fi
+-  done
+-  IFS="$lt_save_ifs"
++  case $lt_cv_dlopen_self in
++  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
++  *) enable_dlopen_self=unknown ;;
++  esac
+ 
+-  # Now substitute the updated list of available tags.
+-  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+-    mv "${ofile}T" "$ofile"
+-    chmod +x "$ofile"
+-  else
+-    rm -f "${ofile}T"
+-    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+-  fi
++  case $lt_cv_dlopen_self_static in
++  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
++  *) enable_dlopen_self_static=unknown ;;
++  esac
+ fi
+-])# _LT_AC_TAGCONFIG
++_LT_DECL([dlopen_support], [enable_dlopen], [0],
++	 [Whether dlopen is supported])
++_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
++	 [Whether dlopen of programs is supported])
++_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
++	 [Whether dlopen of statically linked programs is supported])
++])# LT_SYS_DLOPEN_SELF
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+ 
+ 
+-# AC_LIBTOOL_DLOPEN
+-# -----------------
+-# enable checks for dlopen support
+-AC_DEFUN([AC_LIBTOOL_DLOPEN],
+- [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+-])# AC_LIBTOOL_DLOPEN
++# _LT_COMPILER_C_O([TAGNAME])
++# ---------------------------
++# Check to see if options -c and -o are simultaneously supported by compiler.
++# This macro does not hard code the compiler like AC_PROG_CC_C_O.
++m4_defun([_LT_COMPILER_C_O],
++[m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
++  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
++  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
++   $RM -r conftest 2>/dev/null
++   mkdir conftest
++   cd conftest
++   mkdir out
++   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
++   lt_compiler_flag="-o out/conftest2.$ac_objext"
++   # Insert the option either (1) after the last *FLAGS variable, or
++   # (2) before a word containing "conftest.", or (3) at the end.
++   # Note that $ac_compile itself does not contain backslashes and begins
++   # with a dollar sign (not a hyphen), so the echo should work correctly.
++   lt_compile=`echo "$ac_compile" | $SED \
++   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
++   -e 's:$: $lt_compiler_flag:'`
++   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
++   (eval "$lt_compile" 2>out/conftest.err)
++   ac_status=$?
++   cat out/conftest.err >&AS_MESSAGE_LOG_FD
++   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
++   if (exit $ac_status) && test -s out/conftest2.$ac_objext
++   then
++     # The compiler can only warn and ignore the option if not recognized
++     # So say no if there are warnings
++     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
++     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
++     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
++       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
++     fi
++   fi
++   chmod u+w . 2>&AS_MESSAGE_LOG_FD
++   $RM conftest*
++   # SGI C++ compiler will create directory out/ii_files/ for
++   # template instantiation
++   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
++   $RM out/* && rmdir out
++   cd ..
++   $RM -r conftest
++   $RM conftest*
++])
++_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
++	[Does compiler simultaneously support -c and -o options?])
++])# _LT_COMPILER_C_O
+ 
+-# AC_LIBTOOL_WIN32_DLL
+-# --------------------
+-# declare package support for building win32 DLLs
+-AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+-[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+-])# AC_LIBTOOL_WIN32_DLL
+ 
++# _LT_COMPILER_FILE_LOCKS([TAGNAME])
++# ----------------------------------
++# Check to see if we can do hard links to lock some files if needed
++m4_defun([_LT_COMPILER_FILE_LOCKS],
++[m4_require([_LT_ENABLE_LOCK])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++_LT_COMPILER_C_O([$1])
+ 
+-# AC_ENABLE_SHARED([DEFAULT])
+-# ---------------------------
+-# implement the --enable-shared flag
+-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+-AC_DEFUN([AC_ENABLE_SHARED],
+-[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+-AC_ARG_ENABLE([shared],
+-    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+-	[build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+-    [p=${PACKAGE-default}
+-    case $enableval in
+-    yes) enable_shared=yes ;;
+-    no) enable_shared=no ;;
+-    *)
+-      enable_shared=no
+-      # Look at the argument we got.  We use all the common list separators.
+-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-      for pkg in $enableval; do
+-	IFS="$lt_save_ifs"
+-	if test "X$pkg" = "X$p"; then
+-	  enable_shared=yes
+-	fi
+-      done
+-      IFS="$lt_save_ifs"
+-      ;;
+-    esac],
+-    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+-])# AC_ENABLE_SHARED
+-
+-
+-# AC_DISABLE_SHARED
+-# -----------------
+-# set the default shared flag to --disable-shared
+-AC_DEFUN([AC_DISABLE_SHARED],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-AC_ENABLE_SHARED(no)
+-])# AC_DISABLE_SHARED
+-
+-
+-# AC_ENABLE_STATIC([DEFAULT])
+-# ---------------------------
+-# implement the --enable-static flag
+-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+-AC_DEFUN([AC_ENABLE_STATIC],
+-[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+-AC_ARG_ENABLE([static],
+-    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+-	[build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+-    [p=${PACKAGE-default}
+-    case $enableval in
+-    yes) enable_static=yes ;;
+-    no) enable_static=no ;;
+-    *)
+-     enable_static=no
+-      # Look at the argument we got.  We use all the common list separators.
+-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-      for pkg in $enableval; do
+-	IFS="$lt_save_ifs"
+-	if test "X$pkg" = "X$p"; then
+-	  enable_static=yes
+-	fi
+-      done
+-      IFS="$lt_save_ifs"
+-      ;;
+-    esac],
+-    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+-])# AC_ENABLE_STATIC
+-
+-
+-# AC_DISABLE_STATIC
+-# -----------------
+-# set the default static flag to --disable-static
+-AC_DEFUN([AC_DISABLE_STATIC],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-AC_ENABLE_STATIC(no)
+-])# AC_DISABLE_STATIC
+-
+-
+-# AC_ENABLE_FAST_INSTALL([DEFAULT])
+-# ---------------------------------
+-# implement the --enable-fast-install flag
+-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+-AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+-[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+-AC_ARG_ENABLE([fast-install],
+-    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+-    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+-    [p=${PACKAGE-default}
+-    case $enableval in
+-    yes) enable_fast_install=yes ;;
+-    no) enable_fast_install=no ;;
+-    *)
+-      enable_fast_install=no
+-      # Look at the argument we got.  We use all the common list separators.
+-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-      for pkg in $enableval; do
+-	IFS="$lt_save_ifs"
+-	if test "X$pkg" = "X$p"; then
+-	  enable_fast_install=yes
+-	fi
+-      done
+-      IFS="$lt_save_ifs"
+-      ;;
+-    esac],
+-    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+-])# AC_ENABLE_FAST_INSTALL
+-
+-
+-# AC_DISABLE_FAST_INSTALL
+-# -----------------------
+-# set the default to --disable-fast-install
+-AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-AC_ENABLE_FAST_INSTALL(no)
+-])# AC_DISABLE_FAST_INSTALL
+-
+-
+-# AC_LIBTOOL_PICMODE([MODE])
+-# --------------------------
+-# implement the --with-pic flag
+-# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+-AC_DEFUN([AC_LIBTOOL_PICMODE],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-pic_mode=ifelse($#,1,$1,default)
+-])# AC_LIBTOOL_PICMODE
+-
+-
+-# AC_PROG_EGREP
+-# -------------
+-# This is predefined starting with Autoconf 2.54, so this conditional
+-# definition can be removed once we require Autoconf 2.54 or later.
+-m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+-[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+-   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+-    then ac_cv_prog_egrep='grep -E'
+-    else ac_cv_prog_egrep='egrep'
+-    fi])
+- EGREP=$ac_cv_prog_egrep
+- AC_SUBST([EGREP])
+-])])
+-
+-
+-# AC_PATH_TOOL_PREFIX
+-# -------------------
+-# find a file program which can recognise shared library
+-AC_DEFUN([AC_PATH_TOOL_PREFIX],
+-[AC_REQUIRE([AC_PROG_EGREP])dnl
+-AC_MSG_CHECKING([for $1])
+-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+-[case $MAGIC_CMD in
+-[[\\/*] |  ?:[\\/]*])
+-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+-  ;;
+-*)
+-  lt_save_MAGIC_CMD="$MAGIC_CMD"
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-dnl $ac_dummy forces splitting on constant user-supplied paths.
+-dnl POSIX.2 word splitting is done only on the output of word expansions,
+-dnl not every word.  This closes a longstanding sh security hole.
+-  ac_dummy="ifelse([$2], , $PATH, [$2])"
+-  for ac_dir in $ac_dummy; do
+-    IFS="$lt_save_ifs"
+-    test -z "$ac_dir" && ac_dir=.
+-    if test -f $ac_dir/$1; then
+-      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+-      if test -n "$file_magic_test_file"; then
+-	case $deplibs_check_method in
+-	"file_magic "*)
+-	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+-	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+-	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+-	    $EGREP "$file_magic_regex" > /dev/null; then
+-	    :
+-	  else
+-	    cat <<EOF 1>&2
++hard_links="nottested"
++if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
++  # do not overwrite the value of need_locks provided by the user
++  AC_MSG_CHECKING([if we can lock with hard links])
++  hard_links=yes
++  $RM conftest*
++  ln conftest.a conftest.b 2>/dev/null && hard_links=no
++  touch conftest.a
++  ln conftest.a conftest.b 2>&5 || hard_links=no
++  ln conftest.a conftest.b 2>/dev/null && hard_links=no
++  AC_MSG_RESULT([$hard_links])
++  if test "$hard_links" = no; then
++    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
++    need_locks=warn
++  fi
++else
++  need_locks=no
++fi
++_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
++])# _LT_COMPILER_FILE_LOCKS
+ 
+-*** Warning: the command libtool uses to detect shared libraries,
+-*** $file_magic_cmd, produces output that libtool cannot recognize.
+-*** The result is that libtool may fail to recognize shared libraries
+-*** as such.  This will affect the creation of libtool libraries that
+-*** depend on shared libraries, but programs linked with such libtool
+-*** libraries will work regardless of this problem.  Nevertheless, you
+-*** may want to report the problem to your system manager and/or to
+-*** bug-libtool@gnu.org
+ 
+-EOF
+-	  fi ;;
+-	esac
+-      fi
+-      break
+-    fi
+-  done
+-  IFS="$lt_save_ifs"
+-  MAGIC_CMD="$lt_save_MAGIC_CMD"
+-  ;;
+-esac])
+-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+-if test -n "$MAGIC_CMD"; then
+-  AC_MSG_RESULT($MAGIC_CMD)
++# _LT_CHECK_OBJDIR
++# ----------------
++m4_defun([_LT_CHECK_OBJDIR],
++[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
++[rm -f .libs 2>/dev/null
++mkdir .libs 2>/dev/null
++if test -d .libs; then
++  lt_cv_objdir=.libs
+ else
+-  AC_MSG_RESULT(no)
++  # MS-DOS does not allow filenames that begin with a dot.
++  lt_cv_objdir=_libs
+ fi
+-])# AC_PATH_TOOL_PREFIX
++rmdir .libs 2>/dev/null])
++objdir=$lt_cv_objdir
++_LT_DECL([], [objdir], [0],
++         [The name of the directory that contains temporary libtool files])dnl
++m4_pattern_allow([LT_OBJDIR])dnl
++AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
++  [Define to the sub-directory in which libtool stores uninstalled libraries.])
++])# _LT_CHECK_OBJDIR
+ 
+ 
+-# AC_PATH_MAGIC
+-# -------------
+-# find a file program which can recognise a shared library
+-AC_DEFUN([AC_PATH_MAGIC],
+-[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+-if test -z "$lt_cv_path_MAGIC_CMD"; then
+-  if test -n "$ac_tool_prefix"; then
+-    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
++# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
++# --------------------------------------
++# Check hardcoding attributes.
++m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
++[AC_MSG_CHECKING([how to hardcode library paths into programs])
++_LT_TAGVAR(hardcode_action, $1)=
++if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
++   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
++   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
++
++  # We can hardcode non-existent directories.
++  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
++     # If the only mechanism to avoid hardcoding is shlibpath_var, we
++     # have to relink, otherwise we might link with an installed library
++     # when we should be linking with a yet-to-be-installed one
++     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
++     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
++    # Linking always hardcodes the temporary library directory.
++    _LT_TAGVAR(hardcode_action, $1)=relink
+   else
+-    MAGIC_CMD=:
++    # We can link without hardcoding, and we can hardcode nonexisting dirs.
++    _LT_TAGVAR(hardcode_action, $1)=immediate
+   fi
++else
++  # We cannot hardcode anything, or else we can only hardcode existing
++  # directories.
++  _LT_TAGVAR(hardcode_action, $1)=unsupported
++fi
++AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
++
++if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
++   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
++  # Fast installation is not supported
++  enable_fast_install=no
++elif test "$shlibpath_overrides_runpath" = yes ||
++     test "$enable_shared" = no; then
++  # Fast installation is not necessary
++  enable_fast_install=needless
+ fi
+-])# AC_PATH_MAGIC
++_LT_TAGDECL([], [hardcode_action], [0],
++    [How to hardcode a shared library path into an executable])
++])# _LT_LINKER_HARDCODE_LIBPATH
+ 
+ 
+-# AC_PROG_LD
+-# ----------
+-# find the pathname to the GNU or non-GNU linker
+-AC_DEFUN([AC_PROG_LD],
+-[AC_ARG_WITH([gnu-ld],
+-    [AC_HELP_STRING([--with-gnu-ld],
+-	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+-    [test "$withval" = no || with_gnu_ld=yes],
+-    [with_gnu_ld=no])
+-AC_REQUIRE([LT_AC_PROG_SED])dnl
+-AC_REQUIRE([AC_PROG_CC])dnl
+-AC_REQUIRE([AC_CANONICAL_HOST])dnl
+-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+-ac_prog=ld
+-if test "$GCC" = yes; then
+-  # Check if gcc -print-prog-name=ld gives a path.
+-  AC_MSG_CHECKING([for ld used by $CC])
+-  case $host in
+-  *-*-mingw*)
+-    # gcc leaves a trailing carriage return which upsets mingw
+-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+-  *)
+-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+-  esac
+-  case $ac_prog in
+-    # Accept absolute paths.
+-    [[\\/]]* | ?:[[\\/]]*)
+-      re_direlt='/[[^/]][[^/]]*/\.\./'
+-      # Canonicalize the pathname of ld
+-      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+-      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+-	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+-      done
+-      test -z "$LD" && LD="$ac_prog"
+-      ;;
+-  "")
+-    # If it fails, then pretend we aren't using GCC.
+-    ac_prog=ld
++# _LT_CMD_STRIPLIB
++# ----------------
++m4_defun([_LT_CMD_STRIPLIB],
++[m4_require([_LT_DECL_EGREP])
++striplib=
++old_striplib=
++AC_MSG_CHECKING([whether stripping libraries is possible])
++if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
++  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
++  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
++  AC_MSG_RESULT([yes])
++else
++# FIXME - insert some real tests, host_os isn't really good enough
++  case $host_os in
++  darwin*)
++    if test -n "$STRIP" ; then
++      striplib="$STRIP -x"
++      old_striplib="$STRIP -S"
++      AC_MSG_RESULT([yes])
++    else
++      AC_MSG_RESULT([no])
++    fi
+     ;;
+   *)
+-    # If it is relative, then search for the first ld in PATH.
+-    with_gnu_ld=unknown
++    AC_MSG_RESULT([no])
+     ;;
+   esac
+-elif test "$with_gnu_ld" = yes; then
+-  AC_MSG_CHECKING([for GNU ld])
+-else
+-  AC_MSG_CHECKING([for non-GNU ld])
+ fi
+-AC_CACHE_VAL(lt_cv_path_LD,
+-[if test -z "$LD"; then
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-  for ac_dir in $PATH; do
+-    IFS="$lt_save_ifs"
+-    test -z "$ac_dir" && ac_dir=.
+-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+-      lt_cv_path_LD="$ac_dir/$ac_prog"
+-      # Check to see if the program is GNU ld.  I'd rather use --version,
+-      # but apparently some variants of GNU ld only accept -v.
+-      # Break only if it was the GNU/non-GNU ld that we prefer.
+-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+-      *GNU* | *'with BFD'*)
+-	test "$with_gnu_ld" != no && break
+-	;;
+-      *)
+-	test "$with_gnu_ld" != yes && break
+-	;;
+-      esac
++_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
++_LT_DECL([], [striplib], [1])
++])# _LT_CMD_STRIPLIB
++
++
++# _LT_SYS_DYNAMIC_LINKER([TAG])
++# -----------------------------
++# PORTME Fill in your ld.so characteristics
++m4_defun([_LT_SYS_DYNAMIC_LINKER],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_MSG_CHECKING([dynamic linker characteristics])
++m4_if([$1],
++	[], [
++if test "$GCC" = yes; then
++  case $host_os in
++    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
++    *) lt_awk_arg="/^libraries:/" ;;
++  esac
++  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
++  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
++    # if the path contains ";" then we assume it to be the separator
++    # otherwise default to the standard path separator (i.e. ":") - it is
++    # assumed that no part of a normal pathname contains ";" but that should
++    # okay in the real world where ";" in dirpaths is itself problematic.
++    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
++  else
++    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
++  fi
++  # Ok, now we have the path, separated by spaces, we can step through it
++  # and add multilib dir if necessary.
++  lt_tmp_lt_search_path_spec=
++  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
++  for lt_sys_path in $lt_search_path_spec; do
++    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
++      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
++    else
++      test -d "$lt_sys_path" && \
++	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+     fi
+   done
+-  IFS="$lt_save_ifs"
++  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
++BEGIN {RS=" "; FS="/|\n";} {
++  lt_foo="";
++  lt_count=0;
++  for (lt_i = NF; lt_i > 0; lt_i--) {
++    if ($lt_i != "" && $lt_i != ".") {
++      if ($lt_i == "..") {
++        lt_count++;
++      } else {
++        if (lt_count == 0) {
++          lt_foo="/" $lt_i lt_foo;
++        } else {
++          lt_count--;
++        }
++      }
++    }
++  }
++  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
++  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
++}'`
++  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+ else
+-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
++  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ fi])
+-LD="$lt_cv_path_LD"
+-if test -n "$LD"; then
+-  AC_MSG_RESULT($LD)
+-else
+-  AC_MSG_RESULT(no)
+-fi
+-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+-AC_PROG_LD_GNU
+-])# AC_PROG_LD
++library_names_spec=
++libname_spec='lib$name'
++soname_spec=
++shrext_cmds=".so"
++postinstall_cmds=
++postuninstall_cmds=
++finish_cmds=
++finish_eval=
++shlibpath_var=
++shlibpath_overrides_runpath=unknown
++version_type=none
++dynamic_linker="$host_os ld.so"
++sys_lib_dlsearch_path_spec="/lib /usr/lib"
++need_lib_prefix=unknown
++hardcode_into_libs=no
++
++# when you set need_version to no, make sure it does not cause -set_version
++# flags to be left without arguments
++need_version=unknown
+ 
++case $host_os in
++aix3*)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
++  shlibpath_var=LIBPATH
+ 
+-# AC_PROG_LD_GNU
+-# --------------
+-AC_DEFUN([AC_PROG_LD_GNU],
+-[AC_REQUIRE([AC_PROG_EGREP])dnl
+-AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+-[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+-case `$LD -v 2>&1 </dev/null` in
+-*GNU* | *'with BFD'*)
+-  lt_cv_prog_gnu_ld=yes
++  # AIX 3 has no versioning support, so we append a major version to the name.
++  soname_spec='${libname}${release}${shared_ext}$major'
+   ;;
+-*)
+-  lt_cv_prog_gnu_ld=no
+-  ;;
+-esac])
+-with_gnu_ld=$lt_cv_prog_gnu_ld
+-])# AC_PROG_LD_GNU
+-
+ 
+-# AC_PROG_LD_RELOAD_FLAG
+-# ----------------------
+-# find reload flag for linker
+-#   -- PORTME Some linkers may need a different reload flag.
+-AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+-[AC_CACHE_CHECK([for $LD option to reload object files],
+-  lt_cv_ld_reload_flag,
+-  [lt_cv_ld_reload_flag='-r'])
+-reload_flag=$lt_cv_ld_reload_flag
+-case $reload_flag in
+-"" | " "*) ;;
+-*) reload_flag=" $reload_flag" ;;
+-esac
+-reload_cmds='$LD$reload_flag -o $output$reload_objs'
+-case $host_os in
+-  darwin*)
+-    if test "$GCC" = yes; then
+-      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
++aix[[4-9]]*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  hardcode_into_libs=yes
++  if test "$host_cpu" = ia64; then
++    # AIX 5 supports IA64
++    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
++    shlibpath_var=LD_LIBRARY_PATH
++  else
++    # With GCC up to 2.95.x, collect2 would create an import file
++    # for dependence libraries.  The import file would start with
++    # the line `#! .'.  This would cause the generated library to
++    # depend on `.', always an invalid library.  This was fixed in
++    # development snapshots of GCC prior to 3.0.
++    case $host_os in
++      aix4 | aix4.[[01]] | aix4.[[01]].*)
++      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
++	   echo ' yes '
++	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
++	:
++      else
++	can_build_shared=no
++      fi
++      ;;
++    esac
++    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
++    # soname into executable. Probably we can add versioning support to
++    # collect2, so additional links can be useful in future.
++    if test "$aix_use_runtimelinking" = yes; then
++      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
++      # instead of lib<name>.a to let people know that these are not
++      # typical AIX shared libraries.
++      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     else
+-      reload_cmds='$LD$reload_flag -o $output$reload_objs'
++      # We preserve .a as extension for shared libraries through AIX4.2
++      # and later when we are not doing run time linking.
++      library_names_spec='${libname}${release}.a $libname.a'
++      soname_spec='${libname}${release}${shared_ext}$major'
+     fi
+-    ;;
+-esac
+-])# AC_PROG_LD_RELOAD_FLAG
+-
+-
+-# AC_DEPLIBS_CHECK_METHOD
+-# -----------------------
+-# how to check for library dependencies
+-#  -- PORTME fill in with the dynamic library characteristics
+-AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+-[AC_CACHE_CHECK([how to recognise dependent libraries],
+-lt_cv_deplibs_check_method,
+-[lt_cv_file_magic_cmd='$MAGIC_CMD'
+-lt_cv_file_magic_test_file=
+-lt_cv_deplibs_check_method='unknown'
+-# Need to set the preceding variable on all platforms that support
+-# interlibrary dependencies.
+-# 'none' -- dependencies not supported.
+-# `unknown' -- same as none, but documents that we really don't know.
+-# 'pass_all' -- all dependencies passed with no checks.
+-# 'test_compile' -- check by making test program.
+-# 'file_magic [[regex]]' -- check by looking for files in library path
+-# which responds to the $file_magic_cmd with a given extended regex.
+-# If you have `file' or equivalent on your system and you're not sure
+-# whether `pass_all' will *always* work, you probably want this one.
++    shlibpath_var=LIBPATH
++  fi
++  ;;
+ 
+-case $host_os in
+-aix4* | aix5*)
+-  lt_cv_deplibs_check_method=pass_all
++amigaos*)
++  case $host_cpu in
++  powerpc)
++    # Since July 2007 AmigaOS4 officially supports .so libraries.
++    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    ;;
++  m68k)
++    library_names_spec='$libname.ixlibrary $libname.a'
++    # Create ${libname}_ixlibrary.a entries in /sys/libs.
++    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
++    ;;
++  esac
+   ;;
+ 
+ beos*)
+-  lt_cv_deplibs_check_method=pass_all
++  library_names_spec='${libname}${shared_ext}'
++  dynamic_linker="$host_os ld.so"
++  shlibpath_var=LIBRARY_PATH
+   ;;
+ 
+ bsdi[[45]]*)
+-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+-  lt_cv_file_magic_cmd='/usr/bin/file -L'
+-  lt_cv_file_magic_test_file=/shlib/libc.so
+-  ;;
+-
+-cygwin*)
+-  # func_win32_libid is a shell function defined in ltmain.sh
+-  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+-  lt_cv_file_magic_cmd='func_win32_libid'
++  version_type=linux
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
++  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
++  # the default ld.so.conf also contains /usr/contrib/lib and
++  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
++  # libtool to hard-code these into programs
+   ;;
+ 
+-mingw* | pw32*)
+-  # Base MSYS/MinGW do not provide the 'file' command needed by
+-  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+-  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+-  lt_cv_file_magic_cmd='$OBJDUMP -f'
+-  ;;
++cygwin* | mingw* | pw32*)
++  version_type=windows
++  shrext_cmds=".dll"
++  need_version=no
++  need_lib_prefix=no
+ 
+-darwin* | rhapsody*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
++  case $GCC,$host_os in
++  yes,cygwin* | yes,mingw* | yes,pw32*)
++    library_names_spec='$libname.dll.a'
++    # DLL is installed to $(libdir)/../bin by postinstall_cmds
++    postinstall_cmds='base_file=`basename \${file}`~
++      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
++      dldir=$destdir/`dirname \$dlpath`~
++      test -d \$dldir || mkdir -p \$dldir~
++      $install_prog $dir/$dlname \$dldir/$dlname~
++      chmod a+x \$dldir/$dlname~
++      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
++        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
++      fi'
++    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
++      dlpath=$dir/\$dldll~
++       $RM \$dlpath'
++    shlibpath_overrides_runpath=yes
+ 
+-freebsd* | kfreebsd*-gnu | dragonfly*)
+-  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+-    case $host_cpu in
+-    i*86 )
+-      # Not sure whether the presence of OpenBSD here was a mistake.
+-      # Let's accept both of them until this is cleared up.
+-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+-      lt_cv_file_magic_cmd=/usr/bin/file
+-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
++    case $host_os in
++    cygwin*)
++      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
++      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
++      ;;
++    mingw*)
++      # MinGW DLLs use traditional 'lib' prefix
++      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
++      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
++        # It is most probably a Windows format PATH printed by
++        # mingw gcc, but we are running on Cygwin. Gcc prints its search
++        # path with ; separators, and with drive letters. We can handle the
++        # drive letters (cygwin fileutils understands them), so leave them,
++        # especially as we might pass files found there to a mingw objdump,
++        # which wouldn't understand a cygwinified path. Ahh.
++        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
++      else
++        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
++      fi
++      ;;
++    pw32*)
++      # pw32 DLLs use 'pw' prefix rather than 'lib'
++      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+       ;;
+     esac
+-  else
+-    lt_cv_deplibs_check_method=pass_all
+-  fi
+-  ;;
+-
+-gnu*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-hpux10.20* | hpux11*)
+-  lt_cv_file_magic_cmd=/usr/bin/file
+-  case $host_cpu in
+-  ia64*)
+-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+-    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+-    ;;
+-  hppa*64*)
+-    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+-    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+     ;;
++
+   *)
+-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+-    lt_cv_file_magic_test_file=/usr/lib/libc.sl
++    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+     ;;
+   esac
++  dynamic_linker='Win32 ld.exe'
++  # FIXME: first we should search . and the directory the executable is in
++  shlibpath_var=PATH
+   ;;
+ 
+-interix3*)
+-  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+-  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+-  ;;
+-
+-irix5* | irix6* | nonstopux*)
+-  case $LD in
+-  *-32|*"-32 ") libmagic=32-bit;;
+-  *-n32|*"-n32 ") libmagic=N32;;
+-  *-64|*"-64 ") libmagic=64-bit;;
+-  *) libmagic=never-match;;
+-  esac
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-# This must be Linux ELF.
+-linux*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-netbsd*)
+-  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+-  else
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+-  fi
++darwin* | rhapsody*)
++  dynamic_linker="$host_os dyld"
++  version_type=darwin
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
++  soname_spec='${libname}${release}${major}$shared_ext'
++  shlibpath_overrides_runpath=yes
++  shlibpath_var=DYLD_LIBRARY_PATH
++  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
++m4_if([$1], [],[
++  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
++  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+   ;;
+ 
+-newos6*)
+-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+-  lt_cv_file_magic_cmd=/usr/bin/file
+-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
++dgux*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
+   ;;
+ 
+-nto-qnx*)
+-  lt_cv_deplibs_check_method=unknown
++freebsd1*)
++  dynamic_linker=no
+   ;;
+ 
+-openbsd*)
+-  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
++freebsd* | dragonfly*)
++  # DragonFly does not have aout.  When/if they implement a new
++  # versioning mechanism, adjust this.
++  if test -x /usr/bin/objformat; then
++    objformat=`/usr/bin/objformat`
+   else
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++    case $host_os in
++    freebsd[[123]]*) objformat=aout ;;
++    *) objformat=elf ;;
++    esac
+   fi
+-  ;;
+-
+-osf3* | osf4* | osf5*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-solaris*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-sysv4 | sysv4.3*)
+-  case $host_vendor in
+-  motorola)
+-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+-    ;;
+-  ncr)
+-    lt_cv_deplibs_check_method=pass_all
+-    ;;
+-  sequent)
+-    lt_cv_file_magic_cmd='/bin/file'
+-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
++  version_type=freebsd-$objformat
++  case $version_type in
++    freebsd-elf*)
++      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++      need_version=no
++      need_lib_prefix=no
++      ;;
++    freebsd-*)
++      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
++      need_version=yes
++      ;;
++  esac
++  shlibpath_var=LD_LIBRARY_PATH
++  case $host_os in
++  freebsd2*)
++    shlibpath_overrides_runpath=yes
+     ;;
+-  sni)
+-    lt_cv_file_magic_cmd='/bin/file'
+-    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+-    lt_cv_file_magic_test_file=/lib/libc.so
++  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
++    shlibpath_overrides_runpath=yes
++    hardcode_into_libs=yes
+     ;;
+-  siemens)
+-    lt_cv_deplibs_check_method=pass_all
++  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
++  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
++    shlibpath_overrides_runpath=no
++    hardcode_into_libs=yes
+     ;;
+-  pc)
+-    lt_cv_deplibs_check_method=pass_all
++  *) # from 4.6 on, and DragonFly
++    shlibpath_overrides_runpath=yes
++    hardcode_into_libs=yes
+     ;;
+   esac
+   ;;
+ 
+-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+-  lt_cv_deplibs_check_method=pass_all
++gnu*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  hardcode_into_libs=yes
+   ;;
+-esac
+-])
+-file_magic_cmd=$lt_cv_file_magic_cmd
+-deplibs_check_method=$lt_cv_deplibs_check_method
+-test -z "$deplibs_check_method" && deplibs_check_method=unknown
+-])# AC_DEPLIBS_CHECK_METHOD
+ 
+-
+-# AC_PROG_NM
+-# ----------
+-# find the pathname to a BSD-compatible name lister
+-AC_DEFUN([AC_PROG_NM],
+-[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+-[if test -n "$NM"; then
+-  # Let the user override the test.
+-  lt_cv_path_NM="$NM"
+-else
+-  lt_nm_to_check="${ac_tool_prefix}nm"
+-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then 
+-    lt_nm_to_check="$lt_nm_to_check nm"
+-  fi
+-  for lt_tmp_nm in $lt_nm_to_check; do
+-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+-      IFS="$lt_save_ifs"
+-      test -z "$ac_dir" && ac_dir=.
+-      tmp_nm="$ac_dir/$lt_tmp_nm"
+-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+-	# Check to see if the nm accepts a BSD-compat flag.
+-	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+-	#   nm: unknown option "B" ignored
+-	# Tru64's nm complains that /dev/null is an invalid object file
+-	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+-	*/dev/null* | *'Invalid file or object type'*)
+-	  lt_cv_path_NM="$tmp_nm -B"
+-	  break
+-	  ;;
+-	*)
+-	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+-	  */dev/null*)
+-	    lt_cv_path_NM="$tmp_nm -p"
+-	    break
+-	    ;;
+-	  *)
+-	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+-	    continue # so that we can try to find one that supports BSD flags
+-	    ;;
+-	  esac
+-	  ;;
+-	esac
+-      fi
+-    done
+-    IFS="$lt_save_ifs"
+-  done
+-  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+-fi])
+-NM="$lt_cv_path_NM"
+-])# AC_PROG_NM
+-
+-
+-# AC_CHECK_LIBM
+-# -------------
+-# check for math library
+-AC_DEFUN([AC_CHECK_LIBM],
+-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+-LIBM=
+-case $host in
+-*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+-  # These system don't have libm, or don't need it
+-  ;;
+-*-ncr-sysv4.3*)
+-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+-  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+-  ;;
+-*)
+-  AC_CHECK_LIB(m, cos, LIBM="-lm")
++hpux9* | hpux10* | hpux11*)
++  # Give a soname corresponding to the major version so that dld.sl refuses to
++  # link against other versions.
++  version_type=sunos
++  need_lib_prefix=no
++  need_version=no
++  case $host_cpu in
++  ia64*)
++    shrext_cmds='.so'
++    hardcode_into_libs=yes
++    dynamic_linker="$host_os dld.so"
++    shlibpath_var=LD_LIBRARY_PATH
++    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    if test "X$HPUX_IA64_MODE" = X32; then
++      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
++    else
++      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
++    fi
++    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++    ;;
++  hppa*64*)
++    shrext_cmds='.sl'
++    hardcode_into_libs=yes
++    dynamic_linker="$host_os dld.sl"
++    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
++    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
++    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++    ;;
++  *)
++    shrext_cmds='.sl'
++    dynamic_linker="$host_os dld.sl"
++    shlibpath_var=SHLIB_PATH
++    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    ;;
++  esac
++  # HP-UX runs *really* slowly unless shared libraries are mode 555.
++  postinstall_cmds='chmod 555 $lib'
+   ;;
+-esac
+-])# AC_CHECK_LIBM
+ 
++interix[[3-9]]*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  ;;
+ 
+-# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+-# -----------------------------------
+-# sets LIBLTDL to the link flags for the libltdl convenience library and
+-# LTDLINCL to the include flags for the libltdl header and adds
+-# --enable-ltdl-convenience to the configure arguments.  Note that
+-# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+-# it is assumed to be `libltdl'.  LIBLTDL will be prefixed with
+-# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+-# (note the single quotes!).  If your package is not flat and you're not
+-# using automake, define top_builddir and top_srcdir appropriately in
+-# the Makefiles.
+-AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-  case $enable_ltdl_convenience in
+-  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+-  "") enable_ltdl_convenience=yes
+-      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
++irix5* | irix6* | nonstopux*)
++  case $host_os in
++    nonstopux*) version_type=nonstopux ;;
++    *)
++	if test "$lt_cv_prog_gnu_ld" = yes; then
++		version_type=linux
++	else
++		version_type=irix
++	fi ;;
+   esac
+-  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+-  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+-  # For backwards non-gettext consistent compatibility...
+-  INCLTDL="$LTDLINCL"
+-])# AC_LIBLTDL_CONVENIENCE
+-
+-
+-# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+-# -----------------------------------
+-# sets LIBLTDL to the link flags for the libltdl installable library and
+-# LTDLINCL to the include flags for the libltdl header and adds
+-# --enable-ltdl-install to the configure arguments.  Note that
+-# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+-# and an installed libltdl is not found, it is assumed to be `libltdl'.
+-# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+-# '${top_srcdir}/' (note the single quotes!).  If your package is not
+-# flat and you're not using automake, define top_builddir and top_srcdir
+-# appropriately in the Makefiles.
+-# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+-AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-  AC_CHECK_LIB(ltdl, lt_dlinit,
+-  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+-  [if test x"$enable_ltdl_install" = xno; then
+-     AC_MSG_WARN([libltdl not installed, but installation disabled])
+-   else
+-     enable_ltdl_install=yes
+-   fi
+-  ])
+-  if test x"$enable_ltdl_install" = x"yes"; then
+-    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+-    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+-    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+-  else
+-    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+-    LIBLTDL="-lltdl"
+-    LTDLINCL=
+-  fi
+-  # For backwards non-gettext consistent compatibility...
+-  INCLTDL="$LTDLINCL"
+-])# AC_LIBLTDL_INSTALLABLE
++  need_lib_prefix=no
++  need_version=no
++  soname_spec='${libname}${release}${shared_ext}$major'
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
++  case $host_os in
++  irix5* | nonstopux*)
++    libsuff= shlibsuff=
++    ;;
++  *)
++    case $LD in # libtool.m4 will add one of these switches to LD
++    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
++      libsuff= shlibsuff= libmagic=32-bit;;
++    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
++      libsuff=32 shlibsuff=N32 libmagic=N32;;
++    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
++      libsuff=64 shlibsuff=64 libmagic=64-bit;;
++    *) libsuff= shlibsuff= libmagic=never-match;;
++    esac
++    ;;
++  esac
++  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
++  shlibpath_overrides_runpath=no
++  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
++  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
++  hardcode_into_libs=yes
++  ;;
+ 
++# No shared lib support for Linux oldld, aout, or coff.
++linux*oldld* | linux*aout* | linux*coff*)
++  dynamic_linker=no
++  ;;
+ 
+-# AC_LIBTOOL_CXX
+-# --------------
+-# enable support for C++ libraries
+-AC_DEFUN([AC_LIBTOOL_CXX],
+-[AC_REQUIRE([_LT_AC_LANG_CXX])
+-])# AC_LIBTOOL_CXX
++# This must be Linux ELF.
++linux* | k*bsd*-gnu)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  # Some binutils ld are patched to set DT_RUNPATH
++  save_LDFLAGS=$LDFLAGS
++  save_libdir=$libdir
++  eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
++       LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
++    [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
++       [shlibpath_overrides_runpath=yes])])
++  LDFLAGS=$save_LDFLAGS
++  libdir=$save_libdir
+ 
++  # This implies no fast_install, which is unacceptable.
++  # Some rework will be needed to allow for fast_install
++  # before this can be enabled.
++  hardcode_into_libs=yes
+ 
+-# _LT_AC_LANG_CXX
+-# ---------------
+-AC_DEFUN([_LT_AC_LANG_CXX],
+-[AC_REQUIRE([AC_PROG_CXX])
+-AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+-])# _LT_AC_LANG_CXX
++  # Append ld.so.conf contents to the search path
++  if test -f /etc/ld.so.conf; then
++    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
++    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
++  fi
+ 
+-# _LT_AC_PROG_CXXCPP
+-# ------------------
+-AC_DEFUN([_LT_AC_PROG_CXXCPP],
+-[
+-AC_REQUIRE([AC_PROG_CXX])
+-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+-    (test "X$CXX" != "Xg++"))) ; then
+-  AC_PROG_CXXCPP
+-fi
+-])# _LT_AC_PROG_CXXCPP
+-
+-# AC_LIBTOOL_F77
+-# --------------
+-# enable support for Fortran 77 libraries
+-AC_DEFUN([AC_LIBTOOL_F77],
+-[AC_REQUIRE([_LT_AC_LANG_F77])
+-])# AC_LIBTOOL_F77
+-
+-
+-# _LT_AC_LANG_F77
+-# ---------------
+-AC_DEFUN([_LT_AC_LANG_F77],
+-[AC_REQUIRE([AC_PROG_F77])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+-])# _LT_AC_LANG_F77
+-
+-
+-# AC_LIBTOOL_GCJ
+-# --------------
+-# enable support for GCJ libraries
+-AC_DEFUN([AC_LIBTOOL_GCJ],
+-[AC_REQUIRE([_LT_AC_LANG_GCJ])
+-])# AC_LIBTOOL_GCJ
+-
+-
+-# _LT_AC_LANG_GCJ
+-# ---------------
+-AC_DEFUN([_LT_AC_LANG_GCJ],
+-[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+-  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+-    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+-      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+-	 [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+-	   [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+-])# _LT_AC_LANG_GCJ
+-
+-
+-# AC_LIBTOOL_RC
+-# -------------
+-# enable support for Windows resource files
+-AC_DEFUN([AC_LIBTOOL_RC],
+-[AC_REQUIRE([LT_AC_PROG_RC])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+-])# AC_LIBTOOL_RC
++  # We used to test for /lib/ld.so.1 and disable shared libraries on
++  # powerpc, because MkLinux only supported shared libraries with the
++  # GNU dynamic linker.  Since this was broken with cross compilers,
++  # most powerpc-linux boxes support dynamic linking these days and
++  # people can always --disable-shared, the test was removed, and we
++  # assume the GNU/Linux dynamic linker is in use.
++  dynamic_linker='GNU/Linux ld.so'
++  ;;
+ 
++netbsd*)
++  version_type=sunos
++  need_lib_prefix=no
++  need_version=no
++  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++    dynamic_linker='NetBSD (a.out) ld.so'
++  else
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    dynamic_linker='NetBSD ld.elf_so'
++  fi
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  hardcode_into_libs=yes
++  ;;
+ 
+-# AC_LIBTOOL_LANG_C_CONFIG
+-# ------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+-AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+-[lt_save_CC="$CC"
+-AC_LANG_PUSH(C)
++newsos6)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  ;;
+ 
+-# Source file extension for C test sources.
+-ac_ext=c
++*nto* | *qnx*)
++  version_type=qnx
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  dynamic_linker='ldqnx.so'
++  ;;
+ 
+-# Object file extension for compiled C test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
++openbsd*)
++  version_type=sunos
++  sys_lib_dlsearch_path_spec="/usr/lib"
++  need_lib_prefix=no
++  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
++  case $host_os in
++    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
++    *)				need_version=no  ;;
++  esac
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++    case $host_os in
++      openbsd2.[[89]] | openbsd2.[[89]].*)
++	shlibpath_overrides_runpath=no
++	;;
++      *)
++	shlibpath_overrides_runpath=yes
++	;;
++      esac
++  else
++    shlibpath_overrides_runpath=yes
++  fi
++  ;;
+ 
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="int some_variable = 0;\n"
++os2*)
++  libname_spec='$name'
++  shrext_cmds=".dll"
++  need_lib_prefix=no
++  library_names_spec='$libname${shared_ext} $libname.a'
++  dynamic_linker='OS/2 ld.exe'
++  shlibpath_var=LIBPATH
++  ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code='int main(){return(0);}\n'
++osf3* | osf4* | osf5*)
++  version_type=osf
++  need_lib_prefix=no
++  need_version=no
++  soname_spec='${libname}${release}${shared_ext}$major'
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  shlibpath_var=LD_LIBRARY_PATH
++  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
++  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
++  ;;
+ 
+-_LT_AC_SYS_COMPILER
++rdos*)
++  dynamic_linker=no
++  ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++solaris*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  hardcode_into_libs=yes
++  # ldd complains unless libraries are executable
++  postinstall_cmds='chmod +x $lib'
++  ;;
+ 
+-## CAVEAT EMPTOR:
+-## There is no encapsulation within the following macros, do not change
+-## the running order or otherwise move them around unless you know exactly
+-## what you are doing...
+-AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-AC_LIBTOOL_SYS_LIB_STRIP
+-AC_LIBTOOL_DLOPEN_SELF
+-
+-# Report which library types will actually be built
+-AC_MSG_CHECKING([if libtool supports shared libraries])
+-AC_MSG_RESULT([$can_build_shared])
++sunos4*)
++  version_type=sunos
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  if test "$with_gnu_ld" = yes; then
++    need_lib_prefix=no
++  fi
++  need_version=yes
++  ;;
+ 
+-AC_MSG_CHECKING([whether to build shared libraries])
+-test "$can_build_shared" = "no" && enable_shared=no
++sysv4 | sysv4.3*)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  case $host_vendor in
++    sni)
++      shlibpath_overrides_runpath=no
++      need_lib_prefix=no
++      runpath_var=LD_RUN_PATH
++      ;;
++    siemens)
++      need_lib_prefix=no
++      ;;
++    motorola)
++      need_lib_prefix=no
++      need_version=no
++      shlibpath_overrides_runpath=no
++      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
++      ;;
++  esac
++  ;;
+ 
+-# On AIX, shared libraries and static libraries use the same namespace, and
+-# are all built from PIC.
+-case $host_os in
+-aix3*)
+-  test "$enable_shared" = yes && enable_static=no
+-  if test -n "$RANLIB"; then
+-    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+-    postinstall_cmds='$RANLIB $lib'
++sysv4*MP*)
++  if test -d /usr/nec ;then
++    version_type=linux
++    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
++    soname_spec='$libname${shared_ext}.$major'
++    shlibpath_var=LD_LIBRARY_PATH
+   fi
+   ;;
+ 
+-aix4* | aix5*)
+-  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+-    test "$enable_shared" = yes && enable_static=no
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++  version_type=freebsd-elf
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  hardcode_into_libs=yes
++  if test "$with_gnu_ld" = yes; then
++    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
++  else
++    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
++    case $host_os in
++      sco3.2v5*)
++        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
++	;;
++    esac
+   fi
+-    ;;
+-esac
+-AC_MSG_RESULT([$enable_shared])
+-
+-AC_MSG_CHECKING([whether to build static libraries])
+-# Make sure either enable_shared or enable_static is yes.
+-test "$enable_shared" = yes || enable_static=yes
+-AC_MSG_RESULT([$enable_static])
+-
+-AC_LIBTOOL_CONFIG($1)
+-
+-AC_LANG_POP
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_C_CONFIG
+-
+-
+-# AC_LIBTOOL_LANG_CXX_CONFIG
+-# --------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+-AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+-[AC_LANG_PUSH(C++)
+-AC_REQUIRE([AC_PROG_CXX])
+-AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+-
+-_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-_LT_AC_TAGVAR(always_export_symbols, $1)=no
+-_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_direct, $1)=no
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+-_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+-_LT_AC_TAGVAR(module_cmds, $1)=
+-_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+-_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+-_LT_AC_TAGVAR(no_undefined_flag, $1)=
+-_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+-
+-# Dependencies to place before and after the object being linked:
+-_LT_AC_TAGVAR(predep_objects, $1)=
+-_LT_AC_TAGVAR(postdep_objects, $1)=
+-_LT_AC_TAGVAR(predeps, $1)=
+-_LT_AC_TAGVAR(postdeps, $1)=
+-_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+-
+-# Source file extension for C++ test sources.
+-ac_ext=cpp
+-
+-# Object file extension for compiled C++ test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
+-
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="int some_variable = 0;\n"
++  sys_lib_dlsearch_path_spec='/usr/lib'
++  ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n'
++tpf*)
++  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_name_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  ;;
+ 
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
++uts4*)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++*)
++  dynamic_linker=no
++  ;;
++esac
++AC_MSG_RESULT([$dynamic_linker])
++test "$dynamic_linker" = no && can_build_shared=no
+ 
+-# Allow CC to be a program name with arguments.
+-lt_save_CC=$CC
+-lt_save_LD=$LD
+-lt_save_GCC=$GCC
+-GCC=$GXX
+-lt_save_with_gnu_ld=$with_gnu_ld
+-lt_save_path_LD=$lt_cv_path_LD
+-if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+-  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+-else
+-  $as_unset lt_cv_prog_gnu_ld
++variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
++if test "$GCC" = yes; then
++  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+ fi
+-if test -n "${lt_cv_path_LDCXX+set}"; then
+-  lt_cv_path_LD=$lt_cv_path_LDCXX
+-else
+-  $as_unset lt_cv_path_LD
++ 
++if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
++  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+ fi
+-test -z "${LDCXX+set}" || LD=$LDCXX
+-CC=${CXX-"c++"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
+-
+-# We don't want -fno-exception wen compiling C++ code, so set the
+-# no_builtin_flag separately
+-if test "$GXX" = yes; then
+-  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+-else
+-  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
++  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+ fi
+ 
+-if test "$GXX" = yes; then
+-  # Set up default GNU C++ configuration
+-
+-  AC_PROG_LD
+-
+-  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+-  # archiving commands below assume that GNU ld is being used.
+-  if test "$with_gnu_ld" = yes; then
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-
+-    # If archive_cmds runs LD, not CC, wlarc should be empty
+-    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+-    #     investigate it a little bit more. (MM)
+-    wlarc='${wl}'
+-
+-    # ancient GNU ld didn't support --whole-archive et. al.
+-    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+-	grep 'no-whole-archive' > /dev/null; then
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+-    else
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-    fi
+-  else
+-    with_gnu_ld=no
+-    wlarc=
+-
+-    # A generic and very simple default shared library creation
+-    # command for GNU C++ for the case where it uses the native
+-    # linker, instead of GNU ld.  If possible, this setting should
+-    # overridden to take advantage of the native linker features on
+-    # the platform it is being used on.
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+-  fi
+-
+-  # Commands to make compiler produce verbose output that lists
+-  # what "hidden" libraries, object files and flags are used when
+-  # linking a shared library.
+-  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+-
+-else
+-  GXX=no
+-  with_gnu_ld=no
+-  wlarc=
+-fi
++_LT_DECL([], [variables_saved_for_relink], [1],
++    [Variables whose values should be saved in libtool wrapper scripts and
++    restored at link time])
++_LT_DECL([], [need_lib_prefix], [0],
++    [Do we need the "lib" prefix for modules?])
++_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
++_LT_DECL([], [version_type], [0], [Library versioning type])
++_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
++_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
++_LT_DECL([], [shlibpath_overrides_runpath], [0],
++    [Is shlibpath searched before the hard-coded library search path?])
++_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
++_LT_DECL([], [library_names_spec], [1],
++    [[List of archive names.  First name is the real one, the rest are links.
++    The last name is the one that the linker finds with -lNAME]])
++_LT_DECL([], [soname_spec], [1],
++    [[The coded name of the library, if different from the real name]])
++_LT_DECL([], [postinstall_cmds], [2],
++    [Command to use after installation of a shared archive])
++_LT_DECL([], [postuninstall_cmds], [2],
++    [Command to use after uninstallation of a shared archive])
++_LT_DECL([], [finish_cmds], [2],
++    [Commands used to finish a libtool library installation in a directory])
++_LT_DECL([], [finish_eval], [1],
++    [[As "finish_cmds", except a single script fragment to be evaled but
++    not shown]])
++_LT_DECL([], [hardcode_into_libs], [0],
++    [Whether we should hardcode library paths into libraries])
++_LT_DECL([], [sys_lib_search_path_spec], [2],
++    [Compile-time system search path for libraries])
++_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
++    [Run-time system search path for libraries])
++])# _LT_SYS_DYNAMIC_LINKER
+ 
+-# PORTME: fill in a description of your system's C++ link characteristics
+-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+-_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-case $host_os in
+-  aix3*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  aix4* | aix5*)
+-    if test "$host_cpu" = ia64; then
+-      # On IA64, the linker does run time linking by default, so we don't
+-      # have to do anything special.
+-      aix_use_runtimelinking=no
+-      exp_sym_flag='-Bexport'
+-      no_entry_flag=""
+-    else
+-      aix_use_runtimelinking=no
+ 
+-      # Test if we are trying to use run time linking or normal
+-      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+-      # need to do runtime linking.
+-      case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+-	for ld_flag in $LDFLAGS; do
+-	  case $ld_flag in
+-	  *-brtl*)
+-	    aix_use_runtimelinking=yes
+-	    break
+-	    ;;
+-	  esac
+-	done
+-	;;
+-      esac
+-
+-      exp_sym_flag='-bexport'
+-      no_entry_flag='-bnoentry'
+-    fi
++# _LT_PATH_TOOL_PREFIX(TOOL)
++# --------------------------
++# find a file program which can recognize shared library
++AC_DEFUN([_LT_PATH_TOOL_PREFIX],
++[m4_require([_LT_DECL_EGREP])dnl
++AC_MSG_CHECKING([for $1])
++AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
++[case $MAGIC_CMD in
++[[\\/*] |  ?:[\\/]*])
++  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
++  ;;
++*)
++  lt_save_MAGIC_CMD="$MAGIC_CMD"
++  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++dnl $ac_dummy forces splitting on constant user-supplied paths.
++dnl POSIX.2 word splitting is done only on the output of word expansions,
++dnl not every word.  This closes a longstanding sh security hole.
++  ac_dummy="m4_if([$2], , $PATH, [$2])"
++  for ac_dir in $ac_dummy; do
++    IFS="$lt_save_ifs"
++    test -z "$ac_dir" && ac_dir=.
++    if test -f $ac_dir/$1; then
++      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
++      if test -n "$file_magic_test_file"; then
++	case $deplibs_check_method in
++	"file_magic "*)
++	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
++	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
++	    $EGREP "$file_magic_regex" > /dev/null; then
++	    :
++	  else
++	    cat <<_LT_EOF 1>&2
+ 
+-    # When large executables or shared objects are built, AIX ld can
+-    # have problems creating the table of contents.  If linking a library
+-    # or program results in "error TOC overflow" add -mminimal-toc to
+-    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+-    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+-
+-    _LT_AC_TAGVAR(archive_cmds, $1)=''
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++*** Warning: the command libtool uses to detect shared libraries,
++*** $file_magic_cmd, produces output that libtool cannot recognize.
++*** The result is that libtool may fail to recognize shared libraries
++*** as such.  This will affect the creation of libtool libraries that
++*** depend on shared libraries, but programs linked with such libtool
++*** libraries will work regardless of this problem.  Nevertheless, you
++*** may want to report the problem to your system manager and/or to
++*** bug-libtool@gnu.org
+ 
+-    if test "$GXX" = yes; then
+-      case $host_os in aix4.[[012]]|aix4.[[012]].*)
+-      # We only want to do this on AIX 4.2 and lower, the check
+-      # below for broken collect2 doesn't work under 4.3+
+-	collect2name=`${CC} -print-prog-name=collect2`
+-	if test -f "$collect2name" && \
+-	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+-	then
+-	  # We have reworked collect2
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	else
+-	  # We have old collect2
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+-	  # It fails to find uninstalled libraries when the uninstalled
+-	  # path is not listed in the libpath.  Setting hardcode_minus_L
+-	  # to unsupported forces relinking
+-	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-	fi
+-	;;
+-      esac
+-      shared_flag='-shared'
+-      if test "$aix_use_runtimelinking" = yes; then
+-	shared_flag="$shared_flag "'${wl}-G'
+-      fi
+-    else
+-      # not using gcc
+-      if test "$host_cpu" = ia64; then
+-	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+-	# chokes on -Wl,-G. The following line is correct:
+-	shared_flag='-G'
+-      else
+-	if test "$aix_use_runtimelinking" = yes; then
+-	  shared_flag='${wl}-G'
+-	else
+-	  shared_flag='${wl}-bM:SRE'
+-	fi
++_LT_EOF
++	  fi ;;
++	esac
+       fi
++      break
+     fi
++  done
++  IFS="$lt_save_ifs"
++  MAGIC_CMD="$lt_save_MAGIC_CMD"
++  ;;
++esac])
++MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++if test -n "$MAGIC_CMD"; then
++  AC_MSG_RESULT($MAGIC_CMD)
++else
++  AC_MSG_RESULT(no)
++fi
++_LT_DECL([], [MAGIC_CMD], [0],
++	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
++])# _LT_PATH_TOOL_PREFIX
+ 
+-    # It seems that -bexpall does not export symbols beginning with
+-    # underscore (_), so it is better to generate a list of symbols to export.
+-    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+-    if test "$aix_use_runtimelinking" = yes; then
+-      # Warning - without using the other runtime loading flags (-brtl),
+-      # -berok will link without error, but may produce a broken library.
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+-      # Determine the default libpath from the value encoded in an empty executable.
+-      _LT_AC_SYS_LIBPATH_AIX
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++# Old name:
++AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+ 
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+-     else
+-      if test "$host_cpu" = ia64; then
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+-      else
+-	# Determine the default libpath from the value encoded in an empty executable.
+-	_LT_AC_SYS_LIBPATH_AIX
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-	# Warning - without using the other run time loading flags,
+-	# -berok will link without error, but may produce a broken library.
+-	_LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+-	# Exported symbols can be pulled into shared objects from archives
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+-	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-	# This is similar to how AIX traditionally builds its shared libraries.
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+-      fi
+-    fi
+-    ;;
+ 
+-  beos*)
+-    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+-      # support --undefined.  This deserves some investigation.  FIXME
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-    else
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    fi
+-    ;;
++# _LT_PATH_MAGIC
++# --------------
++# find a file program which can recognize a shared library
++m4_defun([_LT_PATH_MAGIC],
++[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
++if test -z "$lt_cv_path_MAGIC_CMD"; then
++  if test -n "$ac_tool_prefix"; then
++    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
++  else
++    MAGIC_CMD=:
++  fi
++fi
++])# _LT_PATH_MAGIC
+ 
+-  chorus*)
+-    case $cc_basename in
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-    esac
+-    ;;
+ 
+-  cygwin* | mingw* | pw32*)
+-    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+-    # as there is no search path for DLLs.
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+-    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+-
+-    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-      # If the export-symbols file already is a .def file (1st line
+-      # is EXPORTS), use it as is; otherwise, prepend...
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+-	cp $export_symbols $output_objdir/$soname.def;
+-      else
+-	echo EXPORTS > $output_objdir/$soname.def;
+-	cat $export_symbols >> $output_objdir/$soname.def;
+-      fi~
+-      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-    else
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    fi
+-  ;;
+-      darwin* | rhapsody*)
+-        case $host_os in
+-        rhapsody* | darwin1.[[012]])
+-         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+-         ;;
+-       *) # Darwin 1.3 on
+-         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+-           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-         else
+-           case ${MACOSX_DEPLOYMENT_TARGET} in
+-             10.[[012]])
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-               ;;
+-             10.*)
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+-               ;;
+-           esac
+-         fi
+-         ;;
+-        esac
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-
+-    if test "$GXX" = yes ; then
+-      lt_int_apple_cc_single_mod=no
+-      output_verbose_link_cmd='echo'
+-      if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+-       lt_int_apple_cc_single_mod=yes
+-      fi
+-      if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+-       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+-      else
+-          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+-        fi
+-        _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-          if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+-            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          else
+-            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          fi
+-            _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-      else
+-      case $cc_basename in
+-        xlc*)
+-         output_verbose_link_cmd='echo'
+-          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+-          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          ;;
+-       *)
+-         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-          ;;
+-      esac
+-      fi
+-        ;;
++# LT_PATH_LD
++# ----------
++# find the pathname to the GNU or non-GNU linker
++AC_DEFUN([LT_PATH_LD],
++[AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_DECL_EGREP])dnl
+ 
+-  dgux*)
+-    case $cc_basename in
+-      ec++*)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      ghcx*)
+-	# Green Hills C++ Compiler
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-    esac
+-    ;;
+-  freebsd[[12]]*)
+-    # C++ shared libraries reported to be fairly broken before switch to ELF
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  freebsd-elf*)
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    ;;
+-  freebsd* | kfreebsd*-gnu | dragonfly*)
+-    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+-    # conventions
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-    ;;
+-  gnu*)
+-    ;;
+-  hpux9*)
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+-				# but as the default
+-				# location of the library.
+-
+-    case $cc_basename in
+-    CC*)
+-      # FIXME: insert proper C++ library support
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
+-    aCC*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      # Commands to make compiler produce verbose output that lists
+-      # what "hidden" libraries, object files and flags are used when
+-      # linking a shared library.
+-      #
+-      # There doesn't appear to be a way to prevent this compiler from
+-      # explicitly linking system object files so we need to strip them
+-      # from the output so that they don't get included in the library
+-      # dependencies.
+-      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-      ;;
+-    *)
+-      if test "$GXX" = yes; then
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      else
+-        # FIXME: insert proper C++ library support
+-        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
+-    esac
+-    ;;
+-  hpux10*|hpux11*)
+-    if test $with_gnu_ld = no; then
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++AC_ARG_WITH([gnu-ld],
++    [AS_HELP_STRING([--with-gnu-ld],
++	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
++    [test "$withval" = no || with_gnu_ld=yes],
++    [with_gnu_ld=no])dnl
+ 
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+-        ;;
+-      *)
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-        ;;
+-      esac
+-    fi
+-    case $host_cpu in
+-    hppa*64*|ia64*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
+-    *)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+-					      # but as the default
+-					      # location of the library.
++ac_prog=ld
++if test "$GCC" = yes; then
++  # Check if gcc -print-prog-name=ld gives a path.
++  AC_MSG_CHECKING([for ld used by $CC])
++  case $host in
++  *-*-mingw*)
++    # gcc leaves a trailing carriage return which upsets mingw
++    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
++  *)
++    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
++  esac
++  case $ac_prog in
++    # Accept absolute paths.
++    [[\\/]]* | ?:[[\\/]]*)
++      re_direlt='/[[^/]][[^/]]*/\.\./'
++      # Canonicalize the pathname of ld
++      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
++      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
++	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
++      done
++      test -z "$LD" && LD="$ac_prog"
+       ;;
+-    esac
+-
+-    case $cc_basename in
+-      CC*)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      aCC*)
+-	case $host_cpu in
+-	hppa*64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  ;;
+-	ia64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  ;;
+-	esac
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	if test "$GXX" = yes; then
+-	  if test $with_gnu_ld = no; then
+-	    case $host_cpu in
+-	    hppa*64*)
+-	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	      ;;
+-	    ia64*)
+-	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	      ;;
+-	    *)
+-	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	      ;;
+-	    esac
+-	  fi
+-	else
+-	  # FIXME: insert proper C++ library support
+-	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	fi
+-	;;
+-    esac
+-    ;;
+-  interix3*)
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-    # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+-    # Instead, shared libraries are loaded at an image base (0x10000000 by
+-    # default) and relocated if they conflict, which is a slow very memory
+-    # consuming and fragmenting process.  To avoid this, we pick a random,
+-    # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+-    # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+-    ;;
+-  irix5* | irix6*)
+-    case $cc_basename in
+-      CC*)
+-	# SGI C++
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-
+-	# Archives containing C++ object files must be created using
+-	# "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+-	# necessary to make sure instantiated templates are included
+-	# in the archive.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+-	;;
+-      *)
+-	if test "$GXX" = yes; then
+-	  if test "$with_gnu_ld" = no; then
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-	  else
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+-	  fi
+-	fi
+-	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-	;;
+-    esac
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++  "")
++    # If it fails, then pretend we aren't using GCC.
++    ac_prog=ld
+     ;;
+-  linux*)
+-    case $cc_basename in
+-      KCC*)
+-	# Kuck and Associates, Inc. (KAI) C++ Compiler
+-
+-	# KCC will only create a shared library if the output file
+-	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+-	# to its proper name (with version) after linking.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-
+-	# Archives containing C++ object files must be created using
+-	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+-	;;
+-      icpc*)
+-	# Intel C++
+-	with_gnu_ld=yes
+-	# version 8.0 and above of icpc choke on multiply defined symbols
+-	# if we add $predep_objects and $postdep_objects, however 7.1 and
+-	# earlier do not add the objects themselves.
+-	case `$CC -V 2>&1` in
+-	*"Version 7."*)
+-  	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-  	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-	  ;;
+-	*)  # Version 8.0 or newer
+-	  tmp_idyn=
+-	  case $host_cpu in
+-	    ia64*) tmp_idyn=' -i_dynamic';;
+-	  esac
+-  	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-	  ;;
+-	esac
+-	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+-	;;
+-      pgCC*)
+-        # Portland Group C++ compiler
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+-  	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-        ;;
+-      cxx*)
+-	# Compaq C++
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+-
+-	runpath_var=LD_RUN_PATH
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	case `$CC -V 2>&1 | sed 5q` in
+-	*Sun\ C*)
+-	  # Sun C++ 5.9
+-	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-
+-	  # Not sure whether something based on
+-	  # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+-	  # would be better.
+-	  output_verbose_link_cmd='echo'
+-
+-	  # Archives containing C++ object files must be created using
+-	  # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+-	  # necessary to make sure instantiated templates are included
+-	  # in the archive.
+-	  _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+-	  ;;
+-	esac
+-	;;
+-    esac
++  *)
++    # If it is relative, then search for the first ld in PATH.
++    with_gnu_ld=unknown
+     ;;
+-  lynxos*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  m88k*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  mvs*)
+-    case $cc_basename in
+-      cxx*)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
++  esac
++elif test "$with_gnu_ld" = yes; then
++  AC_MSG_CHECKING([for GNU ld])
++else
++  AC_MSG_CHECKING([for non-GNU ld])
++fi
++AC_CACHE_VAL(lt_cv_path_LD,
++[if test -z "$LD"; then
++  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++  for ac_dir in $PATH; do
++    IFS="$lt_save_ifs"
++    test -z "$ac_dir" && ac_dir=.
++    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
++      lt_cv_path_LD="$ac_dir/$ac_prog"
++      # Check to see if the program is GNU ld.  I'd rather use --version,
++      # but apparently some variants of GNU ld only accept -v.
++      # Break only if it was the GNU/non-GNU ld that we prefer.
++      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
++      *GNU* | *'with BFD'*)
++	test "$with_gnu_ld" != no && break
+ 	;;
+       *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
++	test "$with_gnu_ld" != yes && break
+ 	;;
+-    esac
+-    ;;
+-  netbsd*)
+-    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+-      wlarc=
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    fi
+-    # Workaround some broken pre-1.5 toolchains
+-    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+-    ;;
+-  openbsd2*)
+-    # C++ shared libraries are fairly broken
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  openbsd*)
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-    if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++      esac
+     fi
+-    output_verbose_link_cmd='echo'
+-    ;;
+-  osf3*)
+-    case $cc_basename in
+-      KCC*)
+-	# Kuck and Associates, Inc. (KAI) C++ Compiler
+-
+-	# KCC will only create a shared library if the output file
+-	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+-	# to its proper name (with version) after linking.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Archives containing C++ object files must be created using
+-	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+-
+-	;;
+-      RCC*)
+-	# Rational C++ 2.4.1
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      cxx*)
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	  # Commands to make compiler produce verbose output that lists
+-	  # what "hidden" libraries, object files and flags are used when
+-	  # linking a shared library.
+-	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
++  done
++  IFS="$lt_save_ifs"
++else
++  lt_cv_path_LD="$LD" # Let the user override the test with a path.
++fi])
++LD="$lt_cv_path_LD"
++if test -n "$LD"; then
++  AC_MSG_RESULT($LD)
++else
++  AC_MSG_RESULT(no)
++fi
++test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
++_LT_PATH_LD_GNU
++AC_SUBST([LD])
+ 
+-	else
+-	  # FIXME: insert proper C++ library support
+-	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	fi
+-	;;
+-    esac
+-    ;;
+-  osf4* | osf5*)
+-    case $cc_basename in
+-      KCC*)
+-	# Kuck and Associates, Inc. (KAI) C++ Compiler
+-
+-	# KCC will only create a shared library if the output file
+-	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+-	# to its proper name (with version) after linking.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Archives containing C++ object files must be created using
+-	# the KAI C++ compiler.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+-	;;
+-      RCC*)
+-	# Rational C++ 2.4.1
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      cxx*)
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+-	  echo "-hidden">> $lib.exp~
+-	  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version	$verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+-	  $rm $lib.exp'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	 _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	  # Commands to make compiler produce verbose output that lists
+-	  # what "hidden" libraries, object files and flags are used when
+-	  # linking a shared library.
+-	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
++_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
++])# LT_PATH_LD
+ 
+-	else
+-	  # FIXME: insert proper C++ library support
+-	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	fi
+-	;;
+-    esac
+-    ;;
+-  psos*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  sunos4*)
+-    case $cc_basename in
+-      CC*)
+-	# Sun C++ 4.x
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      lcc*)
+-	# Lucid
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-    esac
++# Old names:
++AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
++AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_PROG_LD], [])
++dnl AC_DEFUN([AC_PROG_LD], [])
++
++
++# _LT_PATH_LD_GNU
++#- --------------
++m4_defun([_LT_PATH_LD_GNU],
++[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
++[# I'd rather use --version here, but apparently some GNU lds only accept -v.
++case `$LD -v 2>&1 </dev/null` in
++*GNU* | *'with BFD'*)
++  lt_cv_prog_gnu_ld=yes
++  ;;
++*)
++  lt_cv_prog_gnu_ld=no
++  ;;
++esac])
++with_gnu_ld=$lt_cv_prog_gnu_ld
++])# _LT_PATH_LD_GNU
++
++
++# _LT_CMD_RELOAD
++# --------------
++# find reload flag for linker
++#   -- PORTME Some linkers may need a different reload flag.
++m4_defun([_LT_CMD_RELOAD],
++[AC_CACHE_CHECK([for $LD option to reload object files],
++  lt_cv_ld_reload_flag,
++  [lt_cv_ld_reload_flag='-r'])
++reload_flag=$lt_cv_ld_reload_flag
++case $reload_flag in
++"" | " "*) ;;
++*) reload_flag=" $reload_flag" ;;
++esac
++reload_cmds='$LD$reload_flag -o $output$reload_objs'
++case $host_os in
++  darwin*)
++    if test "$GCC" = yes; then
++      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
++    else
++      reload_cmds='$LD$reload_flag -o $output$reload_objs'
++    fi
+     ;;
+-  solaris*)
+-    case $cc_basename in
+-      CC*)
+-	# Sun C++ 4.2, 5.x and Centerline C++
+-        _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+-	_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-	$CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-	case $host_os in
+-	  solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+-	  *)
+-	    # The C++ compiler is used as linker so we must use $wl
+-	    # flag to pass the commands to the underlying system
+-	    # linker. We must also pass each convience library through
+-	    # to the system linker between allextract/defaultextract.
+-	    # The C++ compiler will combine linker options so we
+-	    # cannot just pass the convience library names through
+-	    # without $wl.
+-	    # Supported since Solaris 2.6 (maybe 2.5.1?)
+-	    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
+-	    ;;
+-	esac
+-	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++esac
++_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl
++_LT_DECL([], [reload_cmds], [2])dnl
++])# _LT_CMD_RELOAD
+ 
+-	output_verbose_link_cmd='echo'
+ 
+-	# Archives containing C++ object files must be created using
+-	# "CC -xar", where "CC" is the Sun C++ compiler.  This is
+-	# necessary to make sure instantiated templates are included
+-	# in the archive.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+-	;;
+-      gcx*)
+-	# Green Hills C++ Compiler
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++# _LT_CHECK_MAGIC_METHOD
++# ----------------------
++# how to check for library dependencies
++#  -- PORTME fill in with the dynamic library characteristics
++m4_defun([_LT_CHECK_MAGIC_METHOD],
++[m4_require([_LT_DECL_EGREP])
++AC_CACHE_CHECK([how to recognize dependent libraries],
++lt_cv_deplibs_check_method,
++[lt_cv_file_magic_cmd='$MAGIC_CMD'
++lt_cv_file_magic_test_file=
++lt_cv_deplibs_check_method='unknown'
++# Need to set the preceding variable on all platforms that support
++# interlibrary dependencies.
++# 'none' -- dependencies not supported.
++# `unknown' -- same as none, but documents that we really don't know.
++# 'pass_all' -- all dependencies passed with no checks.
++# 'test_compile' -- check by making test program.
++# 'file_magic [[regex]]' -- check by looking for files in library path
++# which responds to the $file_magic_cmd with a given extended regex.
++# If you have `file' or equivalent on your system and you're not sure
++# whether `pass_all' will *always* work, you probably want this one.
+ 
+-	# The C++ compiler must be used to create the archive.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+-	;;
+-      *)
+-	# GNU C++ compiler with Solaris linker
+-	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+-	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+-	  if $CC --version | grep -v '^2\.7' > /dev/null; then
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+-	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-		$CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
++case $host_os in
++aix[[4-9]]*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-	    # Commands to make compiler produce verbose output that lists
+-	    # what "hidden" libraries, object files and flags are used when
+-	    # linking a shared library.
+-	    output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+-	  else
+-	    # g++ 2.7 appears to require `-G' NOT `-shared' on this
+-	    # platform.
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+-	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-		$CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
++beos*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-	    # Commands to make compiler produce verbose output that lists
+-	    # what "hidden" libraries, object files and flags are used when
+-	    # linking a shared library.
+-	    output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+-	  fi
++bsdi[[45]]*)
++  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
++  lt_cv_file_magic_cmd='/usr/bin/file -L'
++  lt_cv_file_magic_test_file=/shlib/libc.so
++  ;;
+ 
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+-	fi
+-	;;
+-    esac
+-    ;;
+-  sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+-    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    runpath_var='LD_RUN_PATH'
+-
+-    case $cc_basename in
+-      CC*)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-    esac
+-    ;;
+-  sysv5* | sco3.2v5* | sco5v6*)
+-    # Note: We can NOT use -z defs as we might desire, because we do not
+-    # link with -lc, and that would cause any symbols used from libc to
+-    # always be unresolved, which means just about no library would
+-    # ever link correctly.  If we're not using GNU ld we use -z text
+-    # though, which does catch some bad symbols but isn't as heavy-handed
+-    # as -z defs.
+-    # For security reasons, it is highly recommended that you always
+-    # use absolute paths for naming shared libraries, and exclude the
+-    # DT_RUNPATH tag from executables and libraries.  But doing so
+-    # requires that you compile everything twice, which is a pain.
+-    # So that behaviour is only enabled if SCOABSPATH is set to a
+-    # non-empty value in the environment.  Most likely only useful for
+-    # creating official distributions of packages.
+-    # This is a hack until libtool officially supports absolute path
+-    # names for shared libraries.
+-    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-    _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+-    runpath_var='LD_RUN_PATH'
+-
+-    case $cc_basename in
+-      CC*)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-    esac
+-    ;;
+-  tandem*)
+-    case $cc_basename in
+-      NCC*)
+-	# NonStop-UX NCC 3.20
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
++cygwin*)
++  # func_win32_libid is a shell function defined in ltmain.sh
++  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++  lt_cv_file_magic_cmd='func_win32_libid'
++  ;;
++
++mingw* | pw32*)
++  # Base MSYS/MinGW do not provide the 'file' command needed by
++  # func_win32_libid shell function, so use a weaker test based on 'objdump',
++  # unless we find 'file', for example because we are cross-compiling.
++  if ( file / ) >/dev/null 2>&1; then
++    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++    lt_cv_file_magic_cmd='func_win32_libid'
++  else
++    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
++    lt_cv_file_magic_cmd='$OBJDUMP -f'
++  fi
++  ;;
++
++darwin* | rhapsody*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++freebsd* | dragonfly*)
++  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++    case $host_cpu in
++    i*86 )
++      # Not sure whether the presence of OpenBSD here was a mistake.
++      # Let's accept both of them until this is cleared up.
++      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
++      lt_cv_file_magic_cmd=/usr/bin/file
++      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
++      ;;
+     esac
++  else
++    lt_cv_deplibs_check_method=pass_all
++  fi
++  ;;
++
++gnu*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++hpux10.20* | hpux11*)
++  lt_cv_file_magic_cmd=/usr/bin/file
++  case $host_cpu in
++  ia64*)
++    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
++    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+     ;;
+-  vxworks*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
++  hppa*64*)
++    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
++    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+     ;;
+   *)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
++    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
++    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+     ;;
+-esac
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+-test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
++  esac
++  ;;
+ 
+-_LT_AC_TAGVAR(GCC, $1)="$GXX"
+-_LT_AC_TAGVAR(LD, $1)="$LD"
++interix[[3-9]]*)
++  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
++  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
++  ;;
+ 
+-## CAVEAT EMPTOR:
+-## There is no encapsulation within the following macros, do not change
+-## the running order or otherwise move them around unless you know exactly
+-## what you are doing...
+-AC_LIBTOOL_POSTDEP_PREDEP($1)
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
++irix5* | irix6* | nonstopux*)
++  case $LD in
++  *-32|*"-32 ") libmagic=32-bit;;
++  *-n32|*"-n32 ") libmagic=N32;;
++  *-64|*"-64 ") libmagic=64-bit;;
++  *) libmagic=never-match;;
++  esac
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-AC_LIBTOOL_CONFIG($1)
++# This must be Linux ELF.
++linux* | k*bsd*-gnu)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-AC_LANG_POP
+-CC=$lt_save_CC
+-LDCXX=$LD
+-LD=$lt_save_LD
+-GCC=$lt_save_GCC
+-with_gnu_ldcxx=$with_gnu_ld
+-with_gnu_ld=$lt_save_with_gnu_ld
+-lt_cv_path_LDCXX=$lt_cv_path_LD
+-lt_cv_path_LD=$lt_save_path_LD
+-lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+-lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+-])# AC_LIBTOOL_LANG_CXX_CONFIG
++netbsd*)
++  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++  else
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
++  fi
++  ;;
+ 
+-# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+-# ------------------------------------
+-# Figure out "hidden" library dependencies from verbose
+-# compiler output when linking a shared library.
+-# Parse the compiler output and extract the necessary
+-# objects, libraries and library flags.
+-AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+-dnl we can't use the lt_simple_compile_test_code here,
+-dnl because it contains code intended for an executable,
+-dnl not a library.  It's possible we should let each
+-dnl tag define a new lt_????_link_test_code variable,
+-dnl but it's only used here...
+-ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+-int a;
+-void foo (void) { a = 0; }
+-EOF
+-],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+-class Foo
+-{
+-public:
+-  Foo (void) { a = 0; }
+-private:
+-  int a;
+-};
+-EOF
+-],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+-      subroutine foo
+-      implicit none
+-      integer*4 a
+-      a=0
+-      return
+-      end
+-EOF
+-],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+-public class foo {
+-  private int a;
+-  public void bar (void) {
+-    a = 0;
+-  }
+-};
+-EOF
+-])
+-dnl Parse the compiler output and extract the necessary
+-dnl objects, libraries and library flags.
+-if AC_TRY_EVAL(ac_compile); then
+-  # Parse the compiler output and extract the necessary
+-  # objects, libraries and library flags.
++newos6*)
++  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
++  lt_cv_file_magic_cmd=/usr/bin/file
++  lt_cv_file_magic_test_file=/usr/lib/libnls.so
++  ;;
+ 
+-  # Sentinel used to keep track of whether or not we are before
+-  # the conftest object file.
+-  pre_test_object_deps_done=no
++*nto* | *qnx*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-  # The `*' in the case matches for architectures that use `case' in
+-  # $output_verbose_cmd can trigger glob expansion during the loop
+-  # eval without this substitution.
+-  output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
++openbsd*)
++  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
++  else
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++  fi
++  ;;
+ 
+-  for p in `eval $output_verbose_link_cmd`; do
+-    case $p in
++osf3* | osf4* | osf5*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-    -L* | -R* | -l*)
+-       # Some compilers place space between "-{L,R}" and the path.
+-       # Remove the space.
+-       if test $p = "-L" \
+-	  || test $p = "-R"; then
+-	 prev=$p
+-	 continue
+-       else
+-	 prev=
+-       fi
++rdos*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++solaris*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++sysv4 | sysv4.3*)
++  case $host_vendor in
++  motorola)
++    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
++    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
++    ;;
++  ncr)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
++  sequent)
++    lt_cv_file_magic_cmd='/bin/file'
++    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
++    ;;
++  sni)
++    lt_cv_file_magic_cmd='/bin/file'
++    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
++    lt_cv_file_magic_test_file=/lib/libc.so
++    ;;
++  siemens)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
++  pc)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
++  esac
++  ;;
++
++tpf*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++esac
++])
++file_magic_cmd=$lt_cv_file_magic_cmd
++deplibs_check_method=$lt_cv_deplibs_check_method
++test -z "$deplibs_check_method" && deplibs_check_method=unknown
++
++_LT_DECL([], [deplibs_check_method], [1],
++    [Method to check whether dependent libraries are shared objects])
++_LT_DECL([], [file_magic_cmd], [1],
++    [Command to use when deplibs_check_method == "file_magic"])
++])# _LT_CHECK_MAGIC_METHOD
++
++
++# LT_PATH_NM
++# ----------
++# find the pathname to a BSD- or MS-compatible name lister
++AC_DEFUN([LT_PATH_NM],
++[AC_REQUIRE([AC_PROG_CC])dnl
++AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
++[if test -n "$NM"; then
++  # Let the user override the test.
++  lt_cv_path_NM="$NM"
++else
++  lt_nm_to_check="${ac_tool_prefix}nm"
++  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
++    lt_nm_to_check="$lt_nm_to_check nm"
++  fi
++  for lt_tmp_nm in $lt_nm_to_check; do
++    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
++      IFS="$lt_save_ifs"
++      test -z "$ac_dir" && ac_dir=.
++      tmp_nm="$ac_dir/$lt_tmp_nm"
++      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
++	# Check to see if the nm accepts a BSD-compat flag.
++	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
++	#   nm: unknown option "B" ignored
++	# Tru64's nm complains that /dev/null is an invalid object file
++	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
++	*/dev/null* | *'Invalid file or object type'*)
++	  lt_cv_path_NM="$tmp_nm -B"
++	  break
++	  ;;
++	*)
++	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
++	  */dev/null*)
++	    lt_cv_path_NM="$tmp_nm -p"
++	    break
++	    ;;
++	  *)
++	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
++	    continue # so that we can try to find one that supports BSD flags
++	    ;;
++	  esac
++	  ;;
++	esac
++      fi
++    done
++    IFS="$lt_save_ifs"
++  done
++  : ${lt_cv_path_NM=no}
++fi])
++if test "$lt_cv_path_NM" != "no"; then
++  NM="$lt_cv_path_NM"
++else
++  # Didn't find any BSD compatible name lister, look for dumpbin.
++  AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :)
++  AC_SUBST([DUMPBIN])
++  if test "$DUMPBIN" != ":"; then
++    NM="$DUMPBIN"
++  fi
++fi
++test -z "$NM" && NM=nm
++AC_SUBST([NM])
++_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
++
++AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
++  [lt_cv_nm_interface="BSD nm"
++  echo "int some_variable = 0;" > conftest.$ac_ext
++  (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
++  (eval "$ac_compile" 2>conftest.err)
++  cat conftest.err >&AS_MESSAGE_LOG_FD
++  (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
++  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
++  cat conftest.err >&AS_MESSAGE_LOG_FD
++  (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD)
++  cat conftest.out >&AS_MESSAGE_LOG_FD
++  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
++    lt_cv_nm_interface="MS dumpbin"
++  fi
++  rm -f conftest*])
++])# LT_PATH_NM
++
++# Old names:
++AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
++AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_PROG_NM], [])
++dnl AC_DEFUN([AC_PROG_NM], [])
++
++
++# LT_LIB_M
++# --------
++# check for math library
++AC_DEFUN([LT_LIB_M],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++LIBM=
++case $host in
++*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
++  # These system don't have libm, or don't need it
++  ;;
++*-ncr-sysv4.3*)
++  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
++  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
++  ;;
++*)
++  AC_CHECK_LIB(m, cos, LIBM="-lm")
++  ;;
++esac
++AC_SUBST([LIBM])
++])# LT_LIB_M
++
++# Old name:
++AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_CHECK_LIBM], [])
++
++
++# _LT_COMPILER_NO_RTTI([TAGNAME])
++# -------------------------------
++m4_defun([_LT_COMPILER_NO_RTTI],
++[m4_require([_LT_TAG_COMPILER])dnl
++
++_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++
++if test "$GCC" = yes; then
++  _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
++
++  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
++    lt_cv_prog_compiler_rtti_exceptions,
++    [-fno-rtti -fno-exceptions], [],
++    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
++fi
++_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
++	[Compiler flag to turn off builtin functions])
++])# _LT_COMPILER_NO_RTTI
++
++
++# _LT_CMD_GLOBAL_SYMBOLS
++# ----------------------
++m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++AC_REQUIRE([LT_PATH_LD])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++
++# Check for command to grab the raw symbol name followed by C symbol from nm.
++AC_MSG_CHECKING([command to parse $NM output from $compiler object])
++AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
++[
++# These are sane defaults that work on at least a few old systems.
++# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
++
++# Character class describing NM global symbol codes.
++symcode='[[BCDEGRST]]'
++
++# Regexp to match symbols that can be accessed directly from C.
++sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
++
++# Define system-specific variables.
++case $host_os in
++aix*)
++  symcode='[[BCDT]]'
++  ;;
++cygwin* | mingw* | pw32*)
++  symcode='[[ABCDGISTW]]'
++  ;;
++hpux*)
++  if test "$host_cpu" = ia64; then
++    symcode='[[ABCDEGRST]]'
++  fi
++  ;;
++irix* | nonstopux*)
++  symcode='[[BCDEGRST]]'
++  ;;
++osf*)
++  symcode='[[BCDEGQRST]]'
++  ;;
++solaris*)
++  symcode='[[BDRT]]'
++  ;;
++sco3.2v5*)
++  symcode='[[DT]]'
++  ;;
++sysv4.2uw2*)
++  symcode='[[DT]]'
++  ;;
++sysv5* | sco5v6* | unixware* | OpenUNIX*)
++  symcode='[[ABDT]]'
++  ;;
++sysv4)
++  symcode='[[DFNSTU]]'
++  ;;
++esac
++
++# If we're using GNU nm, then use its standard symbol codes.
++case `$NM -V 2>&1` in
++*GNU* | *'with BFD'*)
++  symcode='[[ABCDGIRSTW]]' ;;
++esac
++
++# Transform an extracted symbol line into a proper C declaration.
++# Some systems (esp. on ia64) link data and code symbols differently,
++# so use this general approach.
++lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
++
++# Transform an extracted symbol line into symbol name and symbol address
++lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
++
++# Handle CRLF in mingw tool chain
++opt_cr=
++case $build_os in
++mingw*)
++  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
++  ;;
++esac
++
++# Try without a prefix underscore, then with it.
++for ac_symprfx in "" "_"; do
++
++  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
++  symxfrm="\\1 $ac_symprfx\\2 \\2"
++
++  # Write the raw and C identifiers.
++  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
++    # Fake it for dumpbin and say T for any non-static function
++    # and D for any global variable.
++    # Also find C++ and __fastcall symbols from MSVC++,
++    # which start with @ or ?.
++    lt_cv_sys_global_symbol_pipe="$AWK ['"\
++"     {last_section=section; section=\$ 3};"\
++"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
++"     \$ 0!~/External *\|/{next};"\
++"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
++"     {if(hide[section]) next};"\
++"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
++"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
++"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
++"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
++"     ' prfx=^$ac_symprfx]"
++  else
++    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
++  fi
++
++  # Check to see that the pipe works correctly.
++  pipe_works=no
++
++  rm -f conftest*
++  cat > conftest.$ac_ext <<_LT_EOF
++#ifdef __cplusplus
++extern "C" {
++#endif
++char nm_test_var;
++void nm_test_func(void);
++void nm_test_func(void){}
++#ifdef __cplusplus
++}
++#endif
++int main(){nm_test_var='a';nm_test_func();return(0);}
++_LT_EOF
++
++  if AC_TRY_EVAL(ac_compile); then
++    # Now try to grab the symbols.
++    nlist=conftest.nm
++    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
++      # Try sorting and uniquifying the output.
++      if sort "$nlist" | uniq > "$nlist"T; then
++	mv -f "$nlist"T "$nlist"
++      else
++	rm -f "$nlist"T
++      fi
++
++      # Make sure that we snagged all the symbols we need.
++      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
++	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
++	  cat <<_LT_EOF > conftest.$ac_ext
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++_LT_EOF
++	  # Now generate the symbol file.
++	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
++
++	  cat <<_LT_EOF >> conftest.$ac_ext
++
++/* The mapping between symbol names and symbols.  */
++const struct {
++  const char *name;
++  void       *address;
++}
++lt__PROGRAM__LTX_preloaded_symbols[[]] =
++{
++  { "@PROGRAM@", (void *) 0 },
++_LT_EOF
++	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
++	  cat <<\_LT_EOF >> conftest.$ac_ext
++  {0, (void *) 0}
++};
++
++/* This works around a problem in FreeBSD linker */
++#ifdef FREEBSD_WORKAROUND
++static const void *lt_preloaded_setup() {
++  return lt__PROGRAM__LTX_preloaded_symbols;
++}
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++_LT_EOF
++	  # Now try linking the two files.
++	  mv conftest.$ac_objext conftstm.$ac_objext
++	  lt_save_LIBS="$LIBS"
++	  lt_save_CFLAGS="$CFLAGS"
++	  LIBS="conftstm.$ac_objext"
++	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
++	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
++	    pipe_works=yes
++	  fi
++	  LIBS="$lt_save_LIBS"
++	  CFLAGS="$lt_save_CFLAGS"
++	else
++	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
++	fi
++      else
++	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
++      fi
++    else
++      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
++    fi
++  else
++    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
++    cat conftest.$ac_ext >&5
++  fi
++  rm -rf conftest* conftst*
+ 
+-       if test "$pre_test_object_deps_done" = no; then
+-	 case $p in
+-	 -L* | -R*)
+-	   # Internal compiler library paths should come after those
+-	   # provided the user.  The postdeps already come after the
+-	   # user supplied libs so there is no need to process them.
+-	   if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+-	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+-	   else
+-	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+-	   fi
+-	   ;;
+-	 # The "-l" case would never come before the object being
+-	 # linked, so don't bother handling this case.
+-	 esac
+-       else
+-	 if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+-	   _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+-	 else
+-	   _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+-	 fi
+-       fi
+-       ;;
++  # Do not use the global_symbol_pipe unless it works.
++  if test "$pipe_works" = yes; then
++    break
++  else
++    lt_cv_sys_global_symbol_pipe=
++  fi
++done
++])
++if test -z "$lt_cv_sys_global_symbol_pipe"; then
++  lt_cv_sys_global_symbol_to_cdecl=
++fi
++if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
++  AC_MSG_RESULT(failed)
++else
++  AC_MSG_RESULT(ok)
++fi
+ 
+-    *.$objext)
+-       # This assumes that the test object file only shows up
+-       # once in the compiler output.
+-       if test "$p" = "conftest.$objext"; then
+-	 pre_test_object_deps_done=yes
+-	 continue
+-       fi
++_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
++    [Take the output of nm and produce a listing of raw symbols and C names])
++_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
++    [Transform the output of nm in a proper C declaration])
++_LT_DECL([global_symbol_to_c_name_address],
++    [lt_cv_sys_global_symbol_to_c_name_address], [1],
++    [Transform the output of nm in a C name address pair])
++_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
++    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
++    [Transform the output of nm in a C name address pair when lib prefix is needed])
++]) # _LT_CMD_GLOBAL_SYMBOLS
+ 
+-       if test "$pre_test_object_deps_done" = no; then
+-	 if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+-	   _LT_AC_TAGVAR(predep_objects, $1)="$p"
+-	 else
+-	   _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+-	 fi
+-       else
+-	 if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+-	   _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+-	 else
+-	   _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+-	 fi
+-       fi
+-       ;;
+ 
+-    *) ;; # Ignore the rest.
++# _LT_COMPILER_PIC([TAGNAME])
++# ---------------------------
++m4_defun([_LT_COMPILER_PIC],
++[m4_require([_LT_TAG_COMPILER])dnl
++_LT_TAGVAR(lt_prog_compiler_wl, $1)=
++_LT_TAGVAR(lt_prog_compiler_pic, $1)=
++_LT_TAGVAR(lt_prog_compiler_static, $1)=
++
++AC_MSG_CHECKING([for $compiler option to produce PIC])
++m4_if([$1], [CXX], [
++  # C++ specific cases for pic, static, wl, etc.
++  if test "$GXX" = yes; then
++    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ 
++    case $host_os in
++    aix*)
++      # All AIX code is PIC.
++      if test "$host_cpu" = ia64; then
++	# AIX 5 now supports IA64 processor
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      fi
++      ;;
++
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++        ;;
++      m68k)
++            # FIXME: we need at least 68020 code to build shared libraries, but
++            # adding the `-m68020' flag to GCC prevents building anything better,
++            # like `-m68040'.
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
++        ;;
++      esac
++      ;;
++
++    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++      # PIC is the default for these OSes.
++      ;;
++    mingw* | cygwin* | os2* | pw32*)
++      # This hack is so that the source file can tell whether it is being
++      # built for inclusion in a dll (and should export symbols for example).
++      # Although the cygwin gcc ignores -fPIC, still need this for old-style
++      # (--disable-auto-import) libraries
++      m4_if([$1], [GCJ], [],
++	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++      ;;
++    darwin* | rhapsody*)
++      # PIC is the default on this platform
++      # Common symbols not allowed in MH_DYLIB files
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
++      ;;
++    *djgpp*)
++      # DJGPP does not support shared libraries at all
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++      ;;
++    interix[[3-9]]*)
++      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++      # Instead, we relocate shared libraries at runtime.
++      ;;
++    sysv4*MP*)
++      if test -d /usr/nec; then
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++      fi
++      ;;
++    hpux*)
++      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++      # not for PA HP-UX.
++      case $host_cpu in
++      hppa*64*|ia64*)
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++	;;
++      esac
++      ;;
++    *qnx* | *nto*)
++      # QNX uses GNU C++, but need to define -shared option too, otherwise
++      # it will coredump.
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++      ;;
++    *)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++      ;;
++    esac
++  else
++    case $host_os in
++      aix[[4-9]]*)
++	# All AIX code is PIC.
++	if test "$host_cpu" = ia64; then
++	  # AIX 5 now supports IA64 processor
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	else
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++	fi
++	;;
++      chorus*)
++	case $cc_basename in
++	cxch68*)
++	  # Green Hills C++ Compiler
++	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
++	  ;;
++	esac
++	;;
++      dgux*)
++	case $cc_basename in
++	  ec++*)
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    ;;
++	  ghcx*)
++	    # Green Hills C++ Compiler
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      freebsd* | dragonfly*)
++	# FreeBSD uses GNU C++
++	;;
++      hpux9* | hpux10* | hpux11*)
++	case $cc_basename in
++	  CC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++	    if test "$host_cpu" != ia64; then
++	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++	    fi
++	    ;;
++	  aCC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++	    case $host_cpu in
++	    hppa*64*|ia64*)
++	      # +Z the default
++	      ;;
++	    *)
++	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++	      ;;
++	    esac
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      interix*)
++	# This is c89, which is MS Visual C++ (no shared libs)
++	# Anyone wants to do a port?
++	;;
++      irix5* | irix6* | nonstopux*)
++	case $cc_basename in
++	  CC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    # CC pic flag -KPIC is the default.
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      linux* | k*bsd*-gnu)
++	case $cc_basename in
++	  KCC*)
++	    # KAI C++ Compiler
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++	    ;;
++	  icpc* | ecpc* )
++	    # Intel C++
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++	    ;;
++	  pgCC* | pgcpp*)
++	    # Portland Group C++ compiler
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    ;;
++	  cxx*)
++	    # Compaq C++
++	    # Make sure the PIC flag is empty.  It appears that all Alpha
++	    # Linux and Compaq Tru64 Unix objects are PIC.
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    ;;
++	  xlc* | xlC*)
++	    # IBM XL 8.0 on PPC
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
++	    ;;
++	  *)
++	    case `$CC -V 2>&1 | sed 5q` in
++	    *Sun\ C*)
++	      # Sun C++ 5.9
++	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++	      ;;
++	    esac
++	    ;;
++	esac
++	;;
++      lynxos*)
++	;;
++      m88k*)
++	;;
++      mvs*)
++	case $cc_basename in
++	  cxx*)
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      netbsd*)
++	;;
++      *qnx* | *nto*)
++        # QNX uses GNU C++, but need to define -shared option too, otherwise
++        # it will coredump.
++        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++        ;;
++      osf3* | osf4* | osf5*)
++	case $cc_basename in
++	  KCC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
++	    ;;
++	  RCC*)
++	    # Rational C++ 2.4.1
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    ;;
++	  cxx*)
++	    # Digital/Compaq C++
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    # Make sure the PIC flag is empty.  It appears that all Alpha
++	    # Linux and Compaq Tru64 Unix objects are PIC.
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      psos*)
++	;;
++      solaris*)
++	case $cc_basename in
++	  CC*)
++	    # Sun C++ 4.2, 5.x and Centerline C++
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++	    ;;
++	  gcx*)
++	    # Green Hills C++ Compiler
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      sunos4*)
++	case $cc_basename in
++	  CC*)
++	    # Sun C++ 4.x
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    ;;
++	  lcc*)
++	    # Lucid
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++	case $cc_basename in
++	  CC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    ;;
++	esac
++	;;
++      tandem*)
++	case $cc_basename in
++	  NCC*)
++	    # NonStop-UX NCC 3.20
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      vxworks*)
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++	;;
+     esac
+-  done
+-
+-  # Clean up.
+-  rm -f a.out a.exe
+-else
+-  echo "libtool.m4: error: problem compiling $1 test program"
+-fi
+-
+-$rm -f confest.$objext
+-
+-# PORTME: override above test on systems where it is broken
+-ifelse([$1],[CXX],
+-[case $host_os in
+-interix3*)
+-  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+-  # hack all around it, let's just trust "g++" to DTRT.
+-  _LT_AC_TAGVAR(predep_objects,$1)=
+-  _LT_AC_TAGVAR(postdep_objects,$1)=
+-  _LT_AC_TAGVAR(postdeps,$1)=
+-  ;;
+-
+-linux*)
+-  case `$CC -V 2>&1 | sed 5q` in
+-  *Sun\ C*)
+-    # Sun C++ 5.9
+-    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+-    ;;
+-  esac
+-  ;;
+-
+-solaris*)
+-  case $cc_basename in
+-  CC*)
+-    # Adding this requires a known-good setup of shared libraries for
+-    # Sun compiler versions before 5.6, else PIC objects from an old
+-    # archive will be linked into the output, leading to subtle bugs.
+-    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+-    ;;
+-  esac
+-  ;;
+-esac
+-])
+-
+-case " $_LT_AC_TAGVAR(postdeps, $1) " in
+-*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+-esac
+-])# AC_LIBTOOL_POSTDEP_PREDEP
+-
+-# AC_LIBTOOL_LANG_F77_CONFIG
+-# --------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+-AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+-[AC_REQUIRE([AC_PROG_F77])
+-AC_LANG_PUSH(Fortran 77)
+-
+-_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-_LT_AC_TAGVAR(always_export_symbols, $1)=no
+-_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_direct, $1)=no
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+-_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+-_LT_AC_TAGVAR(module_cmds, $1)=
+-_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+-_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+-_LT_AC_TAGVAR(no_undefined_flag, $1)=
+-_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+-
+-# Source file extension for f77 test sources.
+-ac_ext=f
+-
+-# Object file extension for compiled f77 test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
+-
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+-
+-# Code to be used in simple link tests
+-lt_simple_link_test_code="      program t\n      end\n"
+-
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
+-
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
+-
+-# Allow CC to be a program name with arguments.
+-lt_save_CC="$CC"
+-CC=${F77-"f77"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
+-
+-AC_MSG_CHECKING([if libtool supports shared libraries])
+-AC_MSG_RESULT([$can_build_shared])
+-
+-AC_MSG_CHECKING([whether to build shared libraries])
+-test "$can_build_shared" = "no" && enable_shared=no
+-
+-# On AIX, shared libraries and static libraries use the same namespace, and
+-# are all built from PIC.
+-case $host_os in
+-aix3*)
+-  test "$enable_shared" = yes && enable_static=no
+-  if test -n "$RANLIB"; then
+-    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+-    postinstall_cmds='$RANLIB $lib'
+   fi
+-  ;;
+-aix4* | aix5*)
+-  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+-    test "$enable_shared" = yes && enable_static=no
+-  fi
+-  ;;
+-esac
+-AC_MSG_RESULT([$enable_shared])
+-
+-AC_MSG_CHECKING([whether to build static libraries])
+-# Make sure either enable_shared or enable_static is yes.
+-test "$enable_shared" = yes || enable_static=yes
+-AC_MSG_RESULT([$enable_static])
+-
+-_LT_AC_TAGVAR(GCC, $1)="$G77"
+-_LT_AC_TAGVAR(LD, $1)="$LD"
+-
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-
+-AC_LIBTOOL_CONFIG($1)
+-
+-AC_LANG_POP
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_F77_CONFIG
+-
+-
+-# AC_LIBTOOL_LANG_GCJ_CONFIG
+-# --------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+-AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+-[AC_LANG_SAVE
+-
+-# Source file extension for Java test sources.
+-ac_ext=java
++],
++[
++  if test "$GCC" = yes; then
++    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ 
+-# Object file extension for compiled Java test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
++    case $host_os in
++      aix*)
++      # All AIX code is PIC.
++      if test "$host_cpu" = ia64; then
++	# AIX 5 now supports IA64 processor
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      fi
++      ;;
+ 
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="class foo {}\n"
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++        ;;
++      m68k)
++            # FIXME: we need at least 68020 code to build shared libraries, but
++            # adding the `-m68020' flag to GCC prevents building anything better,
++            # like `-m68040'.
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
++        ;;
++      esac
++      ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
++    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++      # PIC is the default for these OSes.
++      ;;
+ 
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
++    mingw* | cygwin* | pw32* | os2*)
++      # This hack is so that the source file can tell whether it is being
++      # built for inclusion in a dll (and should export symbols for example).
++      # Although the cygwin gcc ignores -fPIC, still need this for old-style
++      # (--disable-auto-import) libraries
++      m4_if([$1], [GCJ], [],
++	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++      ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++    darwin* | rhapsody*)
++      # PIC is the default on this platform
++      # Common symbols not allowed in MH_DYLIB files
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
++      ;;
+ 
+-# Allow CC to be a program name with arguments.
+-lt_save_CC="$CC"
+-CC=${GCJ-"gcj"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
++    hpux*)
++      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++      # not for PA HP-UX.
++      case $host_cpu in
++      hppa*64*|ia64*)
++	# +Z the default
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++	;;
++      esac
++      ;;
+ 
+-# GCJ did not exist at the time GCC didn't implicitly link libc in.
+-_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
++    interix[[3-9]]*)
++      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++      # Instead, we relocate shared libraries at runtime.
++      ;;
+ 
+-_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++    msdosdjgpp*)
++      # Just because we use GCC doesn't mean we suddenly get shared libraries
++      # on systems that don't support them.
++      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++      enable_shared=no
++      ;;
+ 
+-## CAVEAT EMPTOR:
+-## There is no encapsulation within the following macros, do not change
+-## the running order or otherwise move them around unless you know exactly
+-## what you are doing...
+-AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
++    *nto* | *qnx*)
++      # QNX uses GNU C++, but need to define -shared option too, otherwise
++      # it will coredump.
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++      ;;
+ 
+-AC_LIBTOOL_CONFIG($1)
++    sysv4*MP*)
++      if test -d /usr/nec; then
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++      fi
++      ;;
+ 
+-AC_LANG_RESTORE
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_GCJ_CONFIG
++    *)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++      ;;
++    esac
++  else
++    # PORTME Check for flag to pass linker flags through the system compiler.
++    case $host_os in
++    aix*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      if test "$host_cpu" = ia64; then
++	# AIX 5 now supports IA64 processor
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      else
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++      fi
++      ;;
+ 
++    mingw* | cygwin* | pw32* | os2*)
++      # This hack is so that the source file can tell whether it is being
++      # built for inclusion in a dll (and should export symbols for example).
++      m4_if([$1], [GCJ], [],
++	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++      ;;
+ 
+-# AC_LIBTOOL_LANG_RC_CONFIG
+-# -------------------------
+-# Ensure that the configuration vars for the Windows resource compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+-AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+-[AC_LANG_SAVE
++    hpux9* | hpux10* | hpux11*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++      # not for PA HP-UX.
++      case $host_cpu in
++      hppa*64*|ia64*)
++	# +Z the default
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++	;;
++      esac
++      # Is there a better lt_prog_compiler_static that works with the bundled CC?
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++      ;;
+ 
+-# Source file extension for RC test sources.
+-ac_ext=rc
++    irix5* | irix6* | nonstopux*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      # PIC (with -KPIC) is the default.
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      ;;
+ 
+-# Object file extension for compiled RC test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
++    linux* | k*bsd*-gnu)
++      case $cc_basename in
++      icc* | ecc* | ifort*)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++        ;;
++      pgcc* | pgf77* | pgf90* | pgf95*)
++        # Portland Group compilers (*not* the Pentium gcc compiler,
++	# which looks to be a dead project)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++        ;;
++      ccc*)
++        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++        # All Alpha code is PIC.
++        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++        ;;
++      xl*)
++	# IBM XL C 8.0/Fortran 10.1 on PPC
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
++	;;
++      *)
++	case `$CC -V 2>&1 | sed 5q` in
++	*Sun\ C*)
++	  # Sun C 5.9
++	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	  ;;
++	*Sun\ F*)
++	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
++	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
++	  ;;
++	esac
++	;;
++      esac
++      ;;
+ 
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
++    newsos6)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code="$lt_simple_compile_test_code"
++    *nto* | *qnx*)
++      # QNX uses GNU C++, but need to define -shared option too, otherwise
++      # it will coredump.
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++      ;;
+ 
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
++    osf3* | osf4* | osf5*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      # All OSF/1 code is PIC.
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++    rdos*)
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      ;;
+ 
+-# Allow CC to be a program name with arguments.
+-lt_save_CC="$CC"
+-CC=${RC-"windres"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
+-_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
++    solaris*)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      case $cc_basename in
++      f77* | f90* | f95*)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
++      esac
++      ;;
+ 
+-AC_LIBTOOL_CONFIG($1)
++    sunos4*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
+ 
+-AC_LANG_RESTORE
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_RC_CONFIG
++    sysv4 | sysv4.2uw2* | sysv4.3*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
++
++    sysv4*MP*)
++      if test -d /usr/nec ;then
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      fi
++      ;;
+ 
++    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
+ 
+-# AC_LIBTOOL_CONFIG([TAGNAME])
+-# ----------------------------
+-# If TAGNAME is not passed, then create an initial libtool script
+-# with a default configuration from the untagged config vars.  Otherwise
+-# add code to config.status for appending the configuration named by
+-# TAGNAME from the matching tagged config vars.
+-AC_DEFUN([AC_LIBTOOL_CONFIG],
+-[# The else clause should only fire when bootstrapping the
+-# libtool distribution, otherwise you forgot to ship ltmain.sh
+-# with your package, and you will get complaints that there are
+-# no rules to generate ltmain.sh.
+-if test -f "$ltmain"; then
+-  # See if we are running on zsh, and set the options which allow our commands through
+-  # without removal of \ escapes.
+-  if test -n "${ZSH_VERSION+set}" ; then
+-    setopt NO_GLOB_SUBST
+-  fi
+-  # Now quote all the things that may contain metacharacters while being
+-  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+-  # variables and quote the copies for generation of the libtool script.
+-  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+-    SED SHELL STRIP \
+-    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+-    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+-    deplibs_check_method reload_flag reload_cmds need_locks \
+-    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+-    lt_cv_sys_global_symbol_to_c_name_address \
+-    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+-    old_postinstall_cmds old_postuninstall_cmds \
+-    _LT_AC_TAGVAR(compiler, $1) \
+-    _LT_AC_TAGVAR(CC, $1) \
+-    _LT_AC_TAGVAR(LD, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+-    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+-    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+-    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+-    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+-    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+-    _LT_AC_TAGVAR(predep_objects, $1) \
+-    _LT_AC_TAGVAR(postdep_objects, $1) \
+-    _LT_AC_TAGVAR(predeps, $1) \
+-    _LT_AC_TAGVAR(postdeps, $1) \
+-    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+-    _LT_AC_TAGVAR(archive_cmds, $1) \
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+-    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+-    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+-    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+-    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+-    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+-    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+-    _LT_AC_TAGVAR(module_cmds, $1) \
+-    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+-    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+-    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+-    _LT_AC_TAGVAR(include_expsyms, $1); do
+-
+-    case $var in
+-    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+-    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+-    _LT_AC_TAGVAR(archive_cmds, $1) | \
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+-    _LT_AC_TAGVAR(module_cmds, $1) | \
+-    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+-    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+-    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+-    postinstall_cmds | postuninstall_cmds | \
+-    old_postinstall_cmds | old_postuninstall_cmds | \
+-    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+-      # Double-quote double-evaled strings.
+-      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
++    unicos*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++      ;;
++
++    uts4*)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       ;;
++
+     *)
+-      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
++      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+     esac
+-  done
+-
+-  case $lt_echo in
+-  *'\[$]0 --fallback-echo"')
+-    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
++  fi
++])
++case $host_os in
++  # For platforms which do not support PIC, -DPIC is meaningless:
++  *djgpp*)
++    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     ;;
+-  esac
+-
+-ifelse([$1], [],
+-  [cfgfile="${ofile}T"
+-  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+-  $rm -f "$cfgfile"
+-  AC_MSG_NOTICE([creating $ofile])],
+-  [cfgfile="$ofile"])
+-
+-  cat <<__EOF__ >> "$cfgfile"
+-ifelse([$1], [],
+-[#! $SHELL
++  *)
++    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
++    ;;
++esac
++AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
++_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
++	[How to pass a linker flag through the compiler])
+ 
+-# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+ #
+-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+-# Free Software Foundation, Inc.
+-#
+-# This file is part of GNU Libtool:
+-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
++# Check to make sure the PIC flag actually works.
+ #
+-# This program is distributed in the hope that it will be useful, but
+-# WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-# General Public License for more details.
++if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
++  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
++    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
++    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
++    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
++     "" | " "*) ;;
++     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
++     esac],
++    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
++     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
++fi
++_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
++	[Additional compiler flags for building library objects])
++
+ #
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++# Check to make sure the static flag actually works.
+ #
+-# As a special exception to the GNU General Public License, if you
+-# distribute this file as part of a program that contains a
+-# configuration script generated by Autoconf, you may include it under
+-# the same distribution terms that you use for the rest of that program.
+-
+-# A sed program that does not truncate output.
+-SED=$lt_SED
+-
+-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+-Xsed="$SED -e 1s/^X//"
+-
+-# The HP-UX ksh and POSIX shell print the target directory to stdout
+-# if CDPATH is set.
+-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+-
+-# The names of the tagged configurations supported by this script.
+-available_tags=
+-
+-# ### BEGIN LIBTOOL CONFIG],
+-[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+-
+-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+-
+-# Shell to use when invoking shell scripts.
+-SHELL=$lt_SHELL
+-
+-# Whether or not to build shared libraries.
+-build_libtool_libs=$enable_shared
+-
+-# Whether or not to build static libraries.
+-build_old_libs=$enable_static
+-
+-# Whether or not to add -lc for building shared libraries.
+-build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+-
+-# Whether or not to disallow shared libs when runtime libs are static
+-allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+-
+-# Whether or not to optimize for fast installation.
+-fast_install=$enable_fast_install
+-
+-# The host system.
+-host_alias=$host_alias
+-host=$host
+-host_os=$host_os
++wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
++_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
++  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
++  $lt_tmp_static_flag,
++  [],
++  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
++_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
++	[Compiler flag to prevent dynamic linking])
++])# _LT_COMPILER_PIC
+ 
+-# The build system.
+-build_alias=$build_alias
+-build=$build
+-build_os=$build_os
+ 
+-# An echo program that does not interpret backslashes.
+-echo=$lt_echo
++# _LT_LINKER_SHLIBS([TAGNAME])
++# ----------------------------
++# See if the linker supports building shared libraries.
++m4_defun([_LT_LINKER_SHLIBS],
++[AC_REQUIRE([LT_PATH_LD])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
++m4_if([$1], [CXX], [
++  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++  case $host_os in
++  aix[[4-9]]*)
++    # If we're using GNU nm, then we don't want the "-C" option.
++    # -C means demangle to AIX nm, but means don't demangle with GNU nm
++    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++    else
++      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++    fi
++    ;;
++  pw32*)
++    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
++  ;;
++  cygwin* | mingw*)
++    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
++  ;;
++  *)
++    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++  ;;
++  esac
++  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
++], [
++  runpath_var=
++  _LT_TAGVAR(allow_undefined_flag, $1)=
++  _LT_TAGVAR(always_export_symbols, $1)=no
++  _LT_TAGVAR(archive_cmds, $1)=
++  _LT_TAGVAR(archive_expsym_cmds, $1)=
++  _LT_TAGVAR(compiler_needs_object, $1)=no
++  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
++  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
++  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++  _LT_TAGVAR(hardcode_automatic, $1)=no
++  _LT_TAGVAR(hardcode_direct, $1)=no
++  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
++  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++  _LT_TAGVAR(hardcode_libdir_separator, $1)=
++  _LT_TAGVAR(hardcode_minus_L, $1)=no
++  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++  _LT_TAGVAR(inherit_rpath, $1)=no
++  _LT_TAGVAR(link_all_deplibs, $1)=unknown
++  _LT_TAGVAR(module_cmds, $1)=
++  _LT_TAGVAR(module_expsym_cmds, $1)=
++  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
++  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
++  _LT_TAGVAR(thread_safe_flag_spec, $1)=
++  _LT_TAGVAR(whole_archive_flag_spec, $1)=
++  # include_expsyms should be a list of space-separated symbols to be *always*
++  # included in the symbol list
++  _LT_TAGVAR(include_expsyms, $1)=
++  # exclude_expsyms can be an extended regexp of symbols to exclude
++  # it will be wrapped by ` (' and `)$', so one must not match beginning or
++  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
++  # as well as any symbol that contains `d'.
++  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
++  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
++  # platforms (ab)use it in PIC code, but their linkers get confused if
++  # the symbol is explicitly referenced.  Since portable code cannot
++  # rely on this symbol name, it's probably fine to never include it in
++  # preloaded symbol tables.
++  # Exclude shared library initialization/finalization symbols.
++dnl Note also adjust exclude_expsyms for C++ above.
++  extract_expsyms_cmds=
+ 
+-# The archiver.
+-AR=$lt_AR
+-AR_FLAGS=$lt_AR_FLAGS
++  case $host_os in
++  cygwin* | mingw* | pw32*)
++    # FIXME: the MSVC++ port hasn't been tested in a loooong time
++    # When not using gcc, we currently assume that we are using
++    # Microsoft Visual C++.
++    if test "$GCC" != yes; then
++      with_gnu_ld=no
++    fi
++    ;;
++  interix*)
++    # we just hope/assume this is gcc and not c89 (= MSVC++)
++    with_gnu_ld=yes
++    ;;
++  openbsd*)
++    with_gnu_ld=no
++    ;;
++  esac
+ 
+-# A C compiler.
+-LTCC=$lt_LTCC
++  _LT_TAGVAR(ld_shlibs, $1)=yes
++  if test "$with_gnu_ld" = yes; then
++    # If archive_cmds runs LD, not CC, wlarc should be empty
++    wlarc='${wl}'
+ 
+-# LTCC compiler flags.
+-LTCFLAGS=$lt_LTCFLAGS
++    # Set some defaults for GNU ld with shared library support. These
++    # are reset later if shared libraries are not supported. Putting them
++    # here allows them to be overridden if necessary.
++    runpath_var=LD_RUN_PATH
++    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++    # ancient GNU ld didn't support --whole-archive et. al.
++    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
++      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++    else
++      _LT_TAGVAR(whole_archive_flag_spec, $1)=
++    fi
++    supports_anon_versioning=no
++    case `$LD -v 2>&1` in
++      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
++      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
++      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
++      *\ 2.11.*) ;; # other 2.11 versions
++      *) supports_anon_versioning=yes ;;
++    esac
+ 
+-# A language-specific compiler.
+-CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
++    # See if GNU ld supports shared libraries.
++    case $host_os in
++    aix[[3-9]]*)
++      # On AIX/PPC, the GNU linker is very broken
++      if test "$host_cpu" != ia64; then
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	cat <<_LT_EOF 1>&2
+ 
+-# Is the compiler the GNU C compiler?
+-with_gcc=$_LT_AC_TAGVAR(GCC, $1)
++*** Warning: the GNU linker, at least up to release 2.9.1, is reported
++*** to be unable to reliably create shared libraries on AIX.
++*** Therefore, libtool is disabling shared libraries support.  If you
++*** really care for shared libraries, you may want to modify your PATH
++*** so that a non-GNU linker is found, and then restart.
+ 
+-# An ERE matcher.
+-EGREP=$lt_EGREP
++_LT_EOF
++      fi
++      ;;
+ 
+-# The linker used to build libraries.
+-LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++            _LT_TAGVAR(archive_expsym_cmds, $1)=''
++        ;;
++      m68k)
++            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++            _LT_TAGVAR(hardcode_minus_L, $1)=yes
++        ;;
++      esac
++      ;;
+ 
+-# Whether we need hard or soft links.
+-LN_S=$lt_LN_S
++    beos*)
++      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++	# support --undefined.  This deserves some investigation.  FIXME
++	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# A BSD-compatible nm program.
+-NM=$lt_NM
++    cygwin* | mingw* | pw32*)
++      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
++      # as there is no search path for DLLs.
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      _LT_TAGVAR(always_export_symbols, $1)=no
++      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ 
+-# A symbol stripping program
+-STRIP=$lt_STRIP
++      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++	# If the export-symbols file already is a .def file (1st line
++	# is EXPORTS), use it as is; otherwise, prepend...
++	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++	  cp $export_symbols $output_objdir/$soname.def;
++	else
++	  echo EXPORTS > $output_objdir/$soname.def;
++	  cat $export_symbols >> $output_objdir/$soname.def;
++	fi~
++	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# Used to examine libraries when file_magic_cmd begins "file"
+-MAGIC_CMD=$MAGIC_CMD
++    interix[[3-9]]*)
++      _LT_TAGVAR(hardcode_direct, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++      # Instead, shared libraries are loaded at an image base (0x10000000 by
++      # default) and relocated if they conflict, which is a slow very memory
++      # consuming and fragmenting process.  To avoid this, we pick a random,
++      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
++      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++      ;;
+ 
+-# Used on cygwin: DLL creation program.
+-DLLTOOL="$DLLTOOL"
++    gnu* | linux* | tpf* | k*bsd*-gnu)
++      tmp_diet=no
++      if test "$host_os" = linux-dietlibc; then
++	case $cc_basename in
++	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
++	esac
++      fi
++      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
++	 && test "$tmp_diet" = no
++      then
++	tmp_addflag=
++	tmp_sharedflag='-shared'
++	case $cc_basename,$host_cpu in
++        pgcc*)				# Portland Group C compiler
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	  tmp_addflag=' $pic_flag'
++	  ;;
++	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	  tmp_addflag=' $pic_flag -Mnomain' ;;
++	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
++	  tmp_addflag=' -i_dynamic' ;;
++	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
++	  tmp_addflag=' -i_dynamic -nofor_main' ;;
++	ifc* | ifort*)			# Intel Fortran compiler
++	  tmp_addflag=' -nofor_main' ;;
++	xl[[cC]]*)			# IBM XL C 8.0 on PPC (deal with xlf below)
++	  tmp_sharedflag='-qmkshrobj'
++	  tmp_addflag= ;;
++	esac
++	case `$CC -V 2>&1 | sed 5q` in
++	*Sun\ C*)			# Sun C 5.9
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	  _LT_TAGVAR(compiler_needs_object, $1)=yes
++	  tmp_sharedflag='-G' ;;
++	*Sun\ F*)			# Sun Fortran 8.3
++	  tmp_sharedflag='-G' ;;
++	esac
++	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ 
+-# Used on cygwin: object dumper.
+-OBJDUMP="$OBJDUMP"
++        if test "x$supports_anon_versioning" = xyes; then
++          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++	    echo "local: *; };" >> $output_objdir/$libname.ver~
++	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++        fi
+ 
+-# Used on cygwin: assembler.
+-AS="$AS"
++	case $cc_basename in
++	xlf*)
++	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++	  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
++	  if test "x$supports_anon_versioning" = xyes; then
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++	      echo "local: *; };" >> $output_objdir/$libname.ver~
++	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
++	  fi
++	  ;;
++	esac
++      else
++        _LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# The name of the directory that contains temporary libtool files.
+-objdir=$objdir
++    netbsd*)
++      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
++	wlarc=
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++      fi
++      ;;
+ 
+-# How to create reloadable object files.
+-reload_flag=$lt_reload_flag
+-reload_cmds=$lt_reload_cmds
++    solaris*)
++      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	cat <<_LT_EOF 1>&2
+ 
+-# How to pass a linker flag through the compiler.
+-wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
++*** Warning: The releases 2.8.* of the GNU linker cannot reliably
++*** create shared libraries on Solaris systems.  Therefore, libtool
++*** is disabling shared libraries support.  We urge you to upgrade GNU
++*** binutils to release 2.9.1 or newer.  Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
+ 
+-# Object file suffix (normally "o").
+-objext="$ac_objext"
++_LT_EOF
++      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# Old archive suffix (normally "a").
+-libext="$libext"
++    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
++      case `$LD -v 2>&1` in
++        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	cat <<_LT_EOF 1>&2
+ 
+-# Shared library suffix (normally ".so").
+-shrext_cmds='$shrext_cmds'
++*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
++*** reliably create shared libraries on SCO systems.  Therefore, libtool
++*** is disabling shared libraries support.  We urge you to upgrade GNU
++*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
+ 
+-# Executable file suffix (normally "").
+-exeext="$exeext"
++_LT_EOF
++	;;
++	*)
++	  # For security reasons, it is highly recommended that you always
++	  # use absolute paths for naming shared libraries, and exclude the
++	  # DT_RUNPATH tag from executables and libraries.  But doing so
++	  # requires that you compile everything twice, which is a pain.
++	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++	  else
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	  fi
++	;;
++      esac
++      ;;
+ 
+-# Additional compiler flags for building library objects.
+-pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+-pic_mode=$pic_mode
++    sunos4*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++      wlarc=
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# What is the maximum length of a command?
+-max_cmd_len=$lt_cv_sys_max_cmd_len
++    *)
++      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
++    esac
+ 
+-# Does compiler simultaneously support -c and -o options?
+-compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
++    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
++      runpath_var=
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
++      _LT_TAGVAR(whole_archive_flag_spec, $1)=
++    fi
++  else
++    # PORTME fill in a description of your system's linker (not GNU ld)
++    case $host_os in
++    aix3*)
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      _LT_TAGVAR(always_export_symbols, $1)=yes
++      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
++      # Note: this linker hardcodes the directories in LIBPATH if there
++      # are no directories specified by -L.
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
++	# Neither direct hardcoding nor static linking is supported with a
++	# broken collect2.
++	_LT_TAGVAR(hardcode_direct, $1)=unsupported
++      fi
++      ;;
+ 
+-# Must we lock files when doing compilation?
+-need_locks=$lt_need_locks
++    aix[[4-9]]*)
++      if test "$host_cpu" = ia64; then
++	# On IA64, the linker does run time linking by default, so we don't
++	# have to do anything special.
++	aix_use_runtimelinking=no
++	exp_sym_flag='-Bexport'
++	no_entry_flag=""
++      else
++	# If we're using GNU nm, then we don't want the "-C" option.
++	# -C means demangle to AIX nm, but means don't demangle with GNU nm
++	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++	else
++	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++	fi
++	aix_use_runtimelinking=no
+ 
+-# Do we need the lib prefix for modules?
+-need_lib_prefix=$need_lib_prefix
++	# Test if we are trying to use run time linking or normal
++	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
++	# need to do runtime linking.
++	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
++	  for ld_flag in $LDFLAGS; do
++	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
++	    aix_use_runtimelinking=yes
++	    break
++	  fi
++	  done
++	  ;;
++	esac
+ 
+-# Do we need a version for libraries?
+-need_version=$need_version
++	exp_sym_flag='-bexport'
++	no_entry_flag='-bnoentry'
++      fi
+ 
+-# Whether dlopen is supported.
+-dlopen_support=$enable_dlopen
++      # When large executables or shared objects are built, AIX ld can
++      # have problems creating the table of contents.  If linking a library
++      # or program results in "error TOC overflow" add -mminimal-toc to
++      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
++      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ 
+-# Whether dlopen of programs is supported.
+-dlopen_self=$enable_dlopen_self
++      _LT_TAGVAR(archive_cmds, $1)=''
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+ 
+-# Whether dlopen of statically linked programs is supported.
+-dlopen_self_static=$enable_dlopen_self_static
++      if test "$GCC" = yes; then
++	case $host_os in aix4.[[012]]|aix4.[[012]].*)
++	# We only want to do this on AIX 4.2 and lower, the check
++	# below for broken collect2 doesn't work under 4.3+
++	  collect2name=`${CC} -print-prog-name=collect2`
++	  if test -f "$collect2name" &&
++	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++	  then
++	  # We have reworked collect2
++	  :
++	  else
++	  # We have old collect2
++	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
++	  # It fails to find uninstalled libraries when the uninstalled
++	  # path is not listed in the libpath.  Setting hardcode_minus_L
++	  # to unsupported forces relinking
++	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
++	  fi
++	  ;;
++	esac
++	shared_flag='-shared'
++	if test "$aix_use_runtimelinking" = yes; then
++	  shared_flag="$shared_flag "'${wl}-G'
++	fi
++      else
++	# not using gcc
++	if test "$host_cpu" = ia64; then
++	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++	# chokes on -Wl,-G. The following line is correct:
++	  shared_flag='-G'
++	else
++	  if test "$aix_use_runtimelinking" = yes; then
++	    shared_flag='${wl}-G'
++	  else
++	    shared_flag='${wl}-bM:SRE'
++	  fi
++	fi
++      fi
+ 
+-# Compiler flag to prevent dynamic linking.
+-link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
++      # It seems that -bexpall does not export symbols beginning with
++      # underscore (_), so it is better to generate a list of symbols to export.
++      _LT_TAGVAR(always_export_symbols, $1)=yes
++      if test "$aix_use_runtimelinking" = yes; then
++	# Warning - without using the other runtime loading flags (-brtl),
++	# -berok will link without error, but may produce a broken library.
++	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
++        # Determine the default libpath from the value encoded in an
++        # empty executable.
++        _LT_SYS_MODULE_PATH_AIX
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++      else
++	if test "$host_cpu" = ia64; then
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
++	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
++	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++	else
++	 # Determine the default libpath from the value encoded in an
++	 # empty executable.
++	 _LT_SYS_MODULE_PATH_AIX
++	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++	  # Warning - without using the other run time loading flags,
++	  # -berok will link without error, but may produce a broken library.
++	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
++	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
++	  # Exported symbols can be pulled into shared objects from archives
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
++	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++	  # This is similar to how AIX traditionally builds its shared libraries.
++	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++	fi
++      fi
++      ;;
+ 
+-# Compiler flag to turn off builtin functions.
+-no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++            _LT_TAGVAR(archive_expsym_cmds, $1)=''
++        ;;
++      m68k)
++            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++            _LT_TAGVAR(hardcode_minus_L, $1)=yes
++        ;;
++      esac
++      ;;
+ 
+-# Compiler flag to allow reflexive dlopens.
+-export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
++    bsdi[[45]]*)
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
++      ;;
+ 
+-# Compiler flag to generate shared objects directly from archives.
+-whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
++    cygwin* | mingw* | pw32*)
++      # When not using gcc, we currently assume that we are using
++      # Microsoft Visual C++.
++      # hardcode_libdir_flag_spec is actually meaningless, as there is
++      # no search path for DLLs.
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      # Tell ltmain to make .lib files, not .a files.
++      libext=lib
++      # Tell ltmain to make .dll files, not .so files.
++      shrext_cmds=".dll"
++      # FIXME: Setting linknames here is a bad hack.
++      _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
++      # The linker will automatically build a .lib file if we build a DLL.
++      _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
++      # FIXME: Should let the user specify the lib program.
++      _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
++      _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
++      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++      ;;
+ 
+-# Compiler flag to generate thread-safe objects.
+-thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
++    darwin* | rhapsody*)
++      _LT_DARWIN_LINKER_FEATURES($1)
++      ;;
+ 
+-# Library versioning type.
+-version_type=$version_type
++    dgux*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Format of library name prefix.
+-libname_spec=$lt_libname_spec
++    freebsd1*)
++      _LT_TAGVAR(ld_shlibs, $1)=no
++      ;;
+ 
+-# List of archive names.  First name is the real one, the rest are links.
+-# The last name is the one that the linker finds with -lNAME.
+-library_names_spec=$lt_library_names_spec
++    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
++    # support.  Future versions do this automatically, but an explicit c++rt0.o
++    # does not break anything, and helps significantly (at the cost of a little
++    # extra space).
++    freebsd2.2*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# The coded name of the library, if different from the real name.
+-soname_spec=$lt_soname_spec
++    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
++    freebsd2*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Commands used to build and install an old-style archive.
+-RANLIB=$lt_RANLIB
+-old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+-old_postinstall_cmds=$lt_old_postinstall_cmds
+-old_postuninstall_cmds=$lt_old_postuninstall_cmds
++    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
++    freebsd* | dragonfly*)
++      _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Create an old-style archive from a shared archive.
+-old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
++    hpux9*)
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      _LT_TAGVAR(hardcode_direct, $1)=yes
+ 
+-# Create a temporary old-style archive to link instead of a shared archive.
+-old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
++      # hardcode_minus_L: Not really in the search PATH,
++      # but as the default location of the library.
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++      ;;
+ 
+-# Commands used to build and install a shared archive.
+-archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+-archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+-postinstall_cmds=$lt_postinstall_cmds
+-postuninstall_cmds=$lt_postuninstall_cmds
++    hpux10*)
++      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++      fi
++      if test "$with_gnu_ld" = no; then
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++	_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
++	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
++	_LT_TAGVAR(hardcode_direct, $1)=yes
++	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	# hardcode_minus_L: Not really in the search PATH,
++	# but as the default location of the library.
++	_LT_TAGVAR(hardcode_minus_L, $1)=yes
++      fi
++      ;;
+ 
+-# Commands used to build a loadable module (assumed same as above if empty)
+-module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+-module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
++    hpux11*)
++      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
++	case $host_cpu in
++	hppa*64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	ia64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	esac
++      else
++	case $host_cpu in
++	hppa*64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	ia64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	esac
++      fi
++      if test "$with_gnu_ld" = no; then
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ 
+-# Commands to strip libraries.
+-old_striplib=$lt_old_striplib
+-striplib=$lt_striplib
++	case $host_cpu in
++	hppa*64*|ia64*)
++	  _LT_TAGVAR(hardcode_direct, $1)=no
++	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	  ;;
++	*)
++	  _LT_TAGVAR(hardcode_direct, $1)=yes
++	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ 
+-# Dependencies to place before the objects being linked to create a
+-# shared library.
+-predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
++	  # hardcode_minus_L: Not really in the search PATH,
++	  # but as the default location of the library.
++	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
++	  ;;
++	esac
++      fi
++      ;;
+ 
+-# Dependencies to place after the objects being linked to create a
+-# shared library.
+-postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
++    irix5* | irix6* | nonstopux*)
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++	# Try to use the -exported_symbol ld option, if it does not
++	# work, assume that -exports_file does not work either and
++	# implicitly export all symbols.
++        save_LDFLAGS="$LDFLAGS"
++        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
++        AC_LINK_IFELSE(int foo(void) {},
++          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
++        )
++        LDFLAGS="$save_LDFLAGS"
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
++      fi
++      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      _LT_TAGVAR(inherit_rpath, $1)=yes
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      ;;
+ 
+-# Dependencies to place before the objects being linked to create a
+-# shared library.
+-predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
++    netbsd*)
++      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Dependencies to place after the objects being linked to create a
+-# shared library.
+-postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
++    newsos6)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# The library search path used internally by the compiler when linking
+-# a shared library.
+-compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
++    *nto* | *qnx*)
++      ;;
+ 
+-# Method to check whether dependent libraries are shared objects.
+-deplibs_check_method=$lt_deplibs_check_method
++    openbsd*)
++      if test -f /usr/libexec/ld.so; then
++	_LT_TAGVAR(hardcode_direct, $1)=yes
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	else
++	  case $host_os in
++	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
++	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	     ;;
++	   *)
++	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	     ;;
++	  esac
++	fi
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# Command to use when deplibs_check_method == file_magic.
+-file_magic_cmd=$lt_file_magic_cmd
++    os2*)
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
++      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
++      ;;
+ 
+-# Flag that allows shared libraries with undefined symbols to be built.
+-allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
++    osf3*)
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++      else
++	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++      fi
++      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      ;;
+ 
+-# Flag that forces no undefined symbols.
+-no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
++    osf4* | osf5*)	# as osf3* with the addition of -msym flag
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      else
++	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
++	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+ 
+-# Commands used to finish a libtool library installation in a directory.
+-finish_cmds=$lt_finish_cmds
++	# Both c and cxx compiler support -rpath directly
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++      fi
++      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      ;;
+ 
+-# Same as above, but a single script fragment to be evaled but not shown.
+-finish_eval=$lt_finish_eval
++    solaris*)
++      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
++      if test "$GCC" = yes; then
++	wlarc='${wl}'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++      else
++	case `$CC -V 2>&1` in
++	*"Compilers 5.0"*)
++	  wlarc=''
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
++	  ;;
++	*)
++	  wlarc='${wl}'
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++	  ;;
++	esac
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      case $host_os in
++      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++      *)
++	# The compiler driver will combine and reorder linker options,
++	# but understands `-z linker_flag'.  GCC discards it without `$wl',
++	# but is careful enough not to reorder.
++	# Supported since Solaris 2.6 (maybe 2.5.1?)
++	if test "$GCC" = yes; then
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++	else
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
++	fi
++	;;
++      esac
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      ;;
+ 
+-# Take the output of nm and produce a listing of raw symbols and C names.
+-global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
++    sunos4*)
++      if test "x$host_vendor" = xsequent; then
++	# Use $CC to link under sequent, because it throws in some extra .o
++	# files that make .init and .fini sections work.
++	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Transform the output of nm in a proper C declaration
+-global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
++    sysv4)
++      case $host_vendor in
++	sni)
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
++	;;
++	siemens)
++	  ## LD is ld it makes a PLAMLIB
++	  ## CC just makes a GrossModule.
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
++	  _LT_TAGVAR(hardcode_direct, $1)=no
++        ;;
++	motorola)
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
++	;;
++      esac
++      runpath_var='LD_RUN_PATH'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Transform the output of nm in a C name address pair
+-global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
++    sysv4.3*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
++      ;;
+ 
+-# This is the shared library runtime path variable.
+-runpath_var=$runpath_var
++    sysv4*MP*)
++      if test -d /usr/nec; then
++	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	runpath_var=LD_RUN_PATH
++	hardcode_runpath_var=yes
++	_LT_TAGVAR(ld_shlibs, $1)=yes
++      fi
++      ;;
+ 
+-# This is the shared library path variable.
+-shlibpath_var=$shlibpath_var
++    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      runpath_var='LD_RUN_PATH'
+ 
+-# Is shlibpath searched before the hard-coded library search path?
+-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      fi
++      ;;
+ 
+-# How to hardcode a shared library path into an executable.
+-hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
++    sysv5* | sco3.2v5* | sco5v6*)
++      # Note: We can NOT use -z defs as we might desire, because we do not
++      # link with -lc, and that would cause any symbols used from libc to
++      # always be unresolved, which means just about no library would
++      # ever link correctly.  If we're not using GNU ld we use -z text
++      # though, which does catch some bad symbols but isn't as heavy-handed
++      # as -z defs.
++      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++      runpath_var='LD_RUN_PATH'
+ 
+-# Whether we should hardcode library paths into libraries.
+-hardcode_into_libs=$hardcode_into_libs
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      fi
++      ;;
+ 
+-# Flag to hardcode \$libdir into a binary during linking.
+-# This must work even if \$libdir does not exist.
+-hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
++    uts4*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# If ld is used when linking, flag to hardcode \$libdir into
+-# a binary during linking. This must work even if \$libdir does
+-# not exist.
+-hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
++    *)
++      _LT_TAGVAR(ld_shlibs, $1)=no
++      ;;
++    esac
+ 
+-# Whether we need a single -rpath flag with a separated argument.
+-hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
++    if test x$host_vendor = xsni; then
++      case $host in
++      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
++	;;
++      esac
++    fi
++  fi
++])
++AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
++test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+ 
+-# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+-# resulting binary.
+-hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
++_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+ 
+-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+-# resulting binary.
+-hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
++_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
++_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
++_LT_DECL([], [extract_expsyms_cmds], [2],
++    [The commands to extract the exported symbol list from a shared archive])
+ 
+-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+-# the resulting binary.
+-hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
++#
++# Do we need to explicitly link libc?
++#
++case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
++x|xyes)
++  # Assume -lc should be added
++  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ 
+-# Set to yes if building a shared library automatically hardcodes DIR into the library
+-# and all subsequent libraries and executables linked against it.
+-hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
++  if test "$enable_shared" = yes && test "$GCC" = yes; then
++    case $_LT_TAGVAR(archive_cmds, $1) in
++    *'~'*)
++      # FIXME: we may have to deal with multi-command sequences.
++      ;;
++    '$CC '*)
++      # Test whether the compiler implicitly links with -lc since on some
++      # systems, -lgcc has to come before -lc. If gcc already passes -lc
++      # to ld, don't add -lc before -lgcc.
++      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
++      $RM conftest*
++      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
+-# Variables whose values should be saved in libtool wrapper scripts and
+-# restored at relink time.
+-variables_saved_for_relink="$variables_saved_for_relink"
++      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
++        soname=conftest
++        lib=conftest
++        libobjs=conftest.$ac_objext
++        deplibs=
++        wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
++	pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
++        compiler_flags=-v
++        linker_flags=-v
++        verstring=
++        output_objdir=.
++        libname=conftest
++        lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
++        _LT_TAGVAR(allow_undefined_flag, $1)=
++        if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
++        then
++	  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++        else
++	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++        fi
++        _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
++      else
++        cat conftest.err 1>&5
++      fi
++      $RM conftest*
++      AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)])
++      ;;
++    esac
++  fi
++  ;;
++esac
+ 
+-# Whether libtool must link a program against all its dependency libraries.
+-link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
++_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
++    [Whether or not to add -lc for building shared libraries])
++_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
++    [enable_shared_with_static_runtimes], [0],
++    [Whether or not to disallow shared libs when runtime libs are static])
++_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
++    [Compiler flag to allow reflexive dlopens])
++_LT_TAGDECL([], [whole_archive_flag_spec], [1],
++    [Compiler flag to generate shared objects directly from archives])
++_LT_TAGDECL([], [compiler_needs_object], [1],
++    [Whether the compiler copes with passing no objects directly])
++_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
++    [Create an old-style archive from a shared archive])
++_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
++    [Create a temporary old-style archive to link instead of a shared archive])
++_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
++_LT_TAGDECL([], [archive_expsym_cmds], [2])
++_LT_TAGDECL([], [module_cmds], [2],
++    [Commands used to build a loadable module if different from building
++    a shared archive.])
++_LT_TAGDECL([], [module_expsym_cmds], [2])
++_LT_TAGDECL([], [with_gnu_ld], [1],
++    [Whether we are building with GNU ld or not])
++_LT_TAGDECL([], [allow_undefined_flag], [1],
++    [Flag that allows shared libraries with undefined symbols to be built])
++_LT_TAGDECL([], [no_undefined_flag], [1],
++    [Flag that enforces no undefined symbols])
++_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
++    [Flag to hardcode $libdir into a binary during linking.
++    This must work even if $libdir does not exist])
++_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
++    [[If ld is used when linking, flag to hardcode $libdir into a binary
++    during linking.  This must work even if $libdir does not exist]])
++_LT_TAGDECL([], [hardcode_libdir_separator], [1],
++    [Whether we need a single "-rpath" flag with a separated argument])
++_LT_TAGDECL([], [hardcode_direct], [0],
++    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
++    DIR into the resulting binary])
++_LT_TAGDECL([], [hardcode_direct_absolute], [0],
++    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
++    DIR into the resulting binary and the resulting library dependency is
++    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
++    library is relocated])
++_LT_TAGDECL([], [hardcode_minus_L], [0],
++    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
++    into the resulting binary])
++_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
++    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
++    into the resulting binary])
++_LT_TAGDECL([], [hardcode_automatic], [0],
++    [Set to "yes" if building a shared library automatically hardcodes DIR
++    into the library and all subsequent libraries and executables linked
++    against it])
++_LT_TAGDECL([], [inherit_rpath], [0],
++    [Set to yes if linker adds runtime paths of dependent libraries
++    to runtime path list])
++_LT_TAGDECL([], [link_all_deplibs], [0],
++    [Whether libtool must link a program against all its dependency libraries])
++_LT_TAGDECL([], [fix_srcfile_path], [1],
++    [Fix the shell variable $srcfile for the compiler])
++_LT_TAGDECL([], [always_export_symbols], [0],
++    [Set to "yes" if exported symbols are required])
++_LT_TAGDECL([], [export_symbols_cmds], [2],
++    [The commands to list exported symbols])
++_LT_TAGDECL([], [exclude_expsyms], [1],
++    [Symbols that should not be listed in the preloaded symbols])
++_LT_TAGDECL([], [include_expsyms], [1],
++    [Symbols that must always be exported])
++_LT_TAGDECL([], [prelink_cmds], [2],
++    [Commands necessary for linking programs (against libraries) with templates])
++_LT_TAGDECL([], [file_list_spec], [1],
++    [Specify filename containing input files])
++dnl FIXME: Not yet implemented
++dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
++dnl    [Compiler flag to generate thread safe objects])
++])# _LT_LINKER_SHLIBS
+ 
+-# Compile-time system search path for libraries
+-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+ 
+-# Run-time system search path for libraries
+-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
++# _LT_LANG_C_CONFIG([TAG])
++# ------------------------
++# Ensure that the configuration variables for a C compiler are suitably
++# defined.  These variables are subsequently used by _LT_CONFIG to write
++# the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_C_CONFIG],
++[m4_require([_LT_DECL_EGREP])dnl
++lt_save_CC="$CC"
++AC_LANG_PUSH(C)
+ 
+-# Fix the shell variable \$srcfile for the compiler.
+-fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
++# Source file extension for C test sources.
++ac_ext=c
+ 
+-# Set to yes if exported symbols are required.
+-always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
++# Object file extension for compiled C test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-# The commands to list exported symbols.
+-export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="int some_variable = 0;"
+ 
+-# The commands to extract the exported symbol list from a shared archive.
+-extract_expsyms_cmds=$lt_extract_expsyms_cmds
++# Code to be used in simple link tests
++lt_simple_link_test_code='int main(){return(0);}'
+ 
+-# Symbols that should not be listed in the preloaded symbols.
+-exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
++_LT_TAG_COMPILER
++# Save the default compiler, since it gets overwritten when the other
++# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
++compiler_DEFAULT=$CC
+ 
+-# Symbols that must always be exported.
+-include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
+ 
+-ifelse([$1],[],
+-[# ### END LIBTOOL CONFIG],
+-[# ### END LIBTOOL TAG CONFIG: $tagname])
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++  _LT_COMPILER_NO_RTTI($1)
++  _LT_COMPILER_PIC($1)
++  _LT_COMPILER_C_O($1)
++  _LT_COMPILER_FILE_LOCKS($1)
++  _LT_LINKER_SHLIBS($1)
++  _LT_SYS_DYNAMIC_LINKER($1)
++  _LT_LINKER_HARDCODE_LIBPATH($1)
++  LT_SYS_DLOPEN_SELF
++  _LT_CMD_STRIPLIB
++
++  # Report which library types will actually be built
++  AC_MSG_CHECKING([if libtool supports shared libraries])
++  AC_MSG_RESULT([$can_build_shared])
+ 
+-__EOF__
++  AC_MSG_CHECKING([whether to build shared libraries])
++  test "$can_build_shared" = "no" && enable_shared=no
+ 
+-ifelse([$1],[], [
++  # On AIX, shared libraries and static libraries use the same namespace, and
++  # are all built from PIC.
+   case $host_os in
+   aix3*)
+-    cat <<\EOF >> "$cfgfile"
++    test "$enable_shared" = yes && enable_static=no
++    if test -n "$RANLIB"; then
++      archive_cmds="$archive_cmds~\$RANLIB \$lib"
++      postinstall_cmds='$RANLIB $lib'
++    fi
++    ;;
+ 
+-# AIX sometimes has problems with the GCC collect2 program.  For some
+-# reason, if we set the COLLECT_NAMES environment variable, the problems
+-# vanish in a puff of smoke.
+-if test "X${COLLECT_NAMES+set}" != Xset; then
+-  COLLECT_NAMES=
+-  export COLLECT_NAMES
+-fi
+-EOF
++  aix[[4-9]]*)
++    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++      test "$enable_shared" = yes && enable_static=no
++    fi
+     ;;
+   esac
++  AC_MSG_RESULT([$enable_shared])
+ 
+-  # We use sed instead of cat because bash on DJGPP gets confused if
+-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+-  # text mode, it properly converts lines to CR/LF.  This bash problem
+-  # is reportedly fixed, but why not run on old versions too?
+-  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
++  AC_MSG_CHECKING([whether to build static libraries])
++  # Make sure either enable_shared or enable_static is yes.
++  test "$enable_shared" = yes || enable_static=yes
++  AC_MSG_RESULT([$enable_static])
+ 
+-  mv -f "$cfgfile" "$ofile" || \
+-    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+-  chmod +x "$ofile"
+-])
+-else
+-  # If there is no Makefile yet, we rely on a make rule to execute
+-  # `config.status --recheck' to rerun these tests and create the
+-  # libtool script then.
+-  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+-  if test -f "$ltmain_in"; then
+-    test -f Makefile && make "$ltmain"
+-  fi
++  _LT_CONFIG($1)
+ fi
+-])# AC_LIBTOOL_CONFIG
+-
+-
+-# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+-# -------------------------------------------
+-AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+-[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+-
+-_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++AC_LANG_POP
++CC="$lt_save_CC"
++])# _LT_LANG_C_CONFIG
+ 
+-if test "$GCC" = yes; then
+-  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ 
+-  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+-    lt_cv_prog_compiler_rtti_exceptions,
+-    [-fno-rtti -fno-exceptions], [],
+-    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
++# _LT_PROG_CXX
++# ------------
++# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++
++# compiler, we have our own version here.
++m4_defun([_LT_PROG_CXX],
++[
++pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes])
++AC_PROG_CXX
++if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
++    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
++    (test "X$CXX" != "Xg++"))) ; then
++  AC_PROG_CXXCPP
++else
++  _lt_caught_CXX_error=yes
+ fi
+-])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
++popdef([AC_MSG_ERROR])
++])# _LT_PROG_CXX
+ 
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([_LT_PROG_CXX], [])
+ 
+-# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+-# ---------------------------------
+-AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+-[AC_REQUIRE([AC_CANONICAL_HOST])
+-AC_REQUIRE([AC_PROG_NM])
+-AC_REQUIRE([AC_OBJEXT])
+-# Check for command to grab the raw symbol name followed by C symbol from nm.
+-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+-[
+-# These are sane defaults that work on at least a few old systems.
+-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+-
+-# Character class describing NM global symbol codes.
+-symcode='[[BCDEGRST]]'
+ 
+-# Regexp to match symbols that can be accessed directly from C.
+-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
++# _LT_LANG_CXX_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for a C++ compiler are suitably
++# defined.  These variables are subsequently used by _LT_CONFIG to write
++# the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_CXX_CONFIG],
++[AC_REQUIRE([_LT_PROG_CXX])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_EGREP])dnl
++
++AC_LANG_PUSH(C++)
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(compiler_needs_object, $1)=no
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ 
+-# Transform an extracted symbol line into a proper C declaration
+-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
++# Source file extension for C++ test sources.
++ac_ext=cpp
+ 
+-# Transform an extracted symbol line into symbol name and symbol address
+-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
++# Object file extension for compiled C++ test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-# Define system-specific variables.
+-case $host_os in
+-aix*)
+-  symcode='[[BCDT]]'
+-  ;;
+-cygwin* | mingw* | pw32*)
+-  symcode='[[ABCDGISTW]]'
+-  ;;
+-hpux*) # Its linker distinguishes data from code symbols
+-  if test "$host_cpu" = ia64; then
+-    symcode='[[ABCDEGRST]]'
++# No sense in running all these tests if we already determined that
++# the CXX compiler isn't working.  Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_caught_CXX_error" != yes; then
++  # Code to be used in simple compile tests
++  lt_simple_compile_test_code="int some_variable = 0;"
++
++  # Code to be used in simple link tests
++  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
++
++  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++  _LT_TAG_COMPILER
++
++  # save warnings/boilerplate of simple test code
++  _LT_COMPILER_BOILERPLATE
++  _LT_LINKER_BOILERPLATE
++
++  # Allow CC to be a program name with arguments.
++  lt_save_CC=$CC
++  lt_save_LD=$LD
++  lt_save_GCC=$GCC
++  GCC=$GXX
++  lt_save_with_gnu_ld=$with_gnu_ld
++  lt_save_path_LD=$lt_cv_path_LD
++  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
++    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
++  else
++    $as_unset lt_cv_prog_gnu_ld
+   fi
+-  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+-  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+-  ;;
+-linux*)
+-  if test "$host_cpu" = ia64; then
+-    symcode='[[ABCDGIRSTW]]'
+-    lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+-    lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
++  if test -n "${lt_cv_path_LDCXX+set}"; then
++    lt_cv_path_LD=$lt_cv_path_LDCXX
++  else
++    $as_unset lt_cv_path_LD
+   fi
+-  ;;
+-irix* | nonstopux*)
+-  symcode='[[BCDEGRST]]'
+-  ;;
+-osf*)
+-  symcode='[[BCDEGQRST]]'
+-  ;;
+-solaris*)
+-  symcode='[[BDRT]]'
+-  ;;
+-sco3.2v5*)
+-  symcode='[[DT]]'
+-  ;;
+-sysv4.2uw2*)
+-  symcode='[[DT]]'
+-  ;;
+-sysv5* | sco5v6* | unixware* | OpenUNIX*)
+-  symcode='[[ABDT]]'
+-  ;;
+-sysv4)
+-  symcode='[[DFNSTU]]'
+-  ;;
+-esac
+-
+-# Handle CRLF in mingw tool chain
+-opt_cr=
+-case $build_os in
+-mingw*)
+-  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+-  ;;
+-esac
+-
+-# If we're using GNU nm, then use its standard symbol codes.
+-case `$NM -V 2>&1` in
+-*GNU* | *'with BFD'*)
+-  symcode='[[ABCDGIRSTW]]' ;;
+-esac
+-
+-# Try without a prefix undercore, then with it.
+-for ac_symprfx in "" "_"; do
+-
+-  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+-  symxfrm="\\1 $ac_symprfx\\2 \\2"
+-
+-  # Write the raw and C identifiers.
+-  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ 	]]\($symcode$symcode*\)[[ 	]][[ 	]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+-
+-  # Check to see that the pipe works correctly.
+-  pipe_works=no
+-
+-  rm -f conftest*
+-  cat > conftest.$ac_ext <<EOF
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-char nm_test_var;
+-void nm_test_func(){}
+-#ifdef __cplusplus
+-}
+-#endif
+-int main(){nm_test_var='a';nm_test_func();return(0);}
+-EOF
+-
+-  if AC_TRY_EVAL(ac_compile); then
+-    # Now try to grab the symbols.
+-    nlist=conftest.nm
+-    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+-      # Try sorting and uniquifying the output.
+-      if sort "$nlist" | uniq > "$nlist"T; then
+-	mv -f "$nlist"T "$nlist"
+-      else
+-	rm -f "$nlist"T
+-      fi
+-
+-      # Make sure that we snagged all the symbols we need.
+-      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+-	if grep ' nm_test_func$' "$nlist" >/dev/null; then
+-	  cat <<EOF > conftest.$ac_ext
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+-EOF
+-	  # Now generate the symbol file.
+-	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+-
+-	  cat <<EOF >> conftest.$ac_ext
+-#if defined (__STDC__) && __STDC__
+-# define lt_ptr_t void *
+-#else
+-# define lt_ptr_t char *
+-# define const
+-#endif
+-
+-/* The mapping between symbol names and symbols. */
+-const struct {
+-  const char *name;
+-  lt_ptr_t address;
+-}
+-lt_preloaded_symbols[[]] =
+-{
+-EOF
+-	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+-	  cat <<\EOF >> conftest.$ac_ext
+-  {0, (lt_ptr_t) 0}
+-};
++  test -z "${LDCXX+set}" || LD=$LDCXX
++  CC=${CXX-"c++"}
++  compiler=$CC
++  _LT_TAGVAR(compiler, $1)=$CC
++  _LT_CC_BASENAME([$compiler])
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-EOF
+-	  # Now try linking the two files.
+-	  mv conftest.$ac_objext conftstm.$ac_objext
+-	  lt_save_LIBS="$LIBS"
+-	  lt_save_CFLAGS="$CFLAGS"
+-	  LIBS="conftstm.$ac_objext"
+-	  CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+-	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+-	    pipe_works=yes
+-	  fi
+-	  LIBS="$lt_save_LIBS"
+-	  CFLAGS="$lt_save_CFLAGS"
+-	else
+-	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+-	fi
+-      else
+-	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+-      fi
++  if test -n "$compiler"; then
++    # We don't want -fno-exception when compiling C++ code, so set the
++    # no_builtin_flag separately
++    if test "$GXX" = yes; then
++      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+     else
+-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
++      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+     fi
+-  else
+-    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+-    cat conftest.$ac_ext >&5
+-  fi
+-  rm -f conftest* conftst*
+-
+-  # Do not use the global_symbol_pipe unless it works.
+-  if test "$pipe_works" = yes; then
+-    break
+-  else
+-    lt_cv_sys_global_symbol_pipe=
+-  fi
+-done
+-])
+-if test -z "$lt_cv_sys_global_symbol_pipe"; then
+-  lt_cv_sys_global_symbol_to_cdecl=
+-fi
+-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+-  AC_MSG_RESULT(failed)
+-else
+-  AC_MSG_RESULT(ok)
+-fi
+-]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+ 
++    if test "$GXX" = yes; then
++      # Set up default GNU C++ configuration
+ 
+-# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+-# ---------------------------------------
+-AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+-[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+-_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
++      LT_PATH_LD
+ 
+-AC_MSG_CHECKING([for $compiler option to produce PIC])
+- ifelse([$1],[CXX],[
+-  # C++ specific cases for pic, static, wl, etc.
+-  if test "$GXX" = yes; then
+-    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
++      # Check if GNU C++ uses GNU ld as the underlying linker, since the
++      # archiving commands below assume that GNU ld is being used.
++      if test "$with_gnu_ld" = yes; then
++        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++
++        # If archive_cmds runs LD, not CC, wlarc should be empty
++        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
++        #     investigate it a little bit more. (MM)
++        wlarc='${wl}'
++
++        # ancient GNU ld didn't support --whole-archive et. al.
++        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
++	  $GREP 'no-whole-archive' > /dev/null; then
++          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++        else
++          _LT_TAGVAR(whole_archive_flag_spec, $1)=
++        fi
++      else
++        with_gnu_ld=no
++        wlarc=
+ 
+-    case $host_os in
+-    aix*)
+-      # All AIX code is PIC.
+-      if test "$host_cpu" = ia64; then
+-	# AIX 5 now supports IA64 processor
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      fi
+-      ;;
+-    amigaos*)
+-      # FIXME: we need at least 68020 code to build shared libraries, but
+-      # adding the `-m68020' flag to GCC prevents building anything better,
+-      # like `-m68040'.
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+-      ;;
+-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+-      # PIC is the default for these OSes.
+-      ;;
+-    mingw* | cygwin* | os2* | pw32*)
+-      # This hack is so that the source file can tell whether it is being
+-      # built for inclusion in a dll (and should export symbols for example).
+-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+-      # (--disable-auto-import) libraries
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+-      ;;
+-    darwin* | rhapsody*)
+-      # PIC is the default on this platform
+-      # Common symbols not allowed in MH_DYLIB files
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+-      ;;
+-    *djgpp*)
+-      # DJGPP does not support shared libraries at all
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-      ;;
+-    interix3*)
+-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+-      # Instead, we relocate shared libraries at runtime.
+-      ;;
+-    sysv4*MP*)
+-      if test -d /usr/nec; then
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++        # A generic and very simple default shared library creation
++        # command for GNU C++ for the case where it uses the native
++        # linker, instead of GNU ld.  If possible, this setting should
++        # overridden to take advantage of the native linker features on
++        # the platform it is being used on.
++        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+       fi
+-      ;;
+-    hpux*)
+-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+-      # not for PA HP-UX.
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-	;;
+-      esac
+-      ;;
+-    *)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-      ;;
+-    esac
+-  else
++
++      # Commands to make compiler produce verbose output that lists
++      # what "hidden" libraries, object files and flags are used when
++      # linking a shared library.
++      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++
++    else
++      GXX=no
++      with_gnu_ld=no
++      wlarc=
++    fi
++
++    # PORTME: fill in a description of your system's C++ link characteristics
++    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
++    _LT_TAGVAR(ld_shlibs, $1)=yes
+     case $host_os in
+-      aix4* | aix5*)
+-	# All AIX code is PIC.
+-	if test "$host_cpu" = ia64; then
+-	  # AIX 5 now supports IA64 processor
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      aix3*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
++      aix[[4-9]]*)
++        if test "$host_cpu" = ia64; then
++          # On IA64, the linker does run time linking by default, so we don't
++          # have to do anything special.
++          aix_use_runtimelinking=no
++          exp_sym_flag='-Bexport'
++          no_entry_flag=""
++        else
++          aix_use_runtimelinking=no
++
++          # Test if we are trying to use run time linking or normal
++          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
++          # need to do runtime linking.
++          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
++	    for ld_flag in $LDFLAGS; do
++	      case $ld_flag in
++	      *-brtl*)
++	        aix_use_runtimelinking=yes
++	        break
++	        ;;
++	      esac
++	    done
++	    ;;
++          esac
++
++          exp_sym_flag='-bexport'
++          no_entry_flag='-bnoentry'
++        fi
++
++        # When large executables or shared objects are built, AIX ld can
++        # have problems creating the table of contents.  If linking a library
++        # or program results in "error TOC overflow" add -mminimal-toc to
++        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
++        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
++
++        _LT_TAGVAR(archive_cmds, $1)=''
++        _LT_TAGVAR(hardcode_direct, $1)=yes
++        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++        _LT_TAGVAR(link_all_deplibs, $1)=yes
++        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
++
++        if test "$GXX" = yes; then
++          case $host_os in aix4.[[012]]|aix4.[[012]].*)
++          # We only want to do this on AIX 4.2 and lower, the check
++          # below for broken collect2 doesn't work under 4.3+
++	  collect2name=`${CC} -print-prog-name=collect2`
++	  if test -f "$collect2name" &&
++	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++	  then
++	    # We have reworked collect2
++	    :
++	  else
++	    # We have old collect2
++	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
++	    # It fails to find uninstalled libraries when the uninstalled
++	    # path is not listed in the libpath.  Setting hardcode_minus_L
++	    # to unsupported forces relinking
++	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
++	  fi
++          esac
++          shared_flag='-shared'
++	  if test "$aix_use_runtimelinking" = yes; then
++	    shared_flag="$shared_flag "'${wl}-G'
++	  fi
++        else
++          # not using gcc
++          if test "$host_cpu" = ia64; then
++	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++	  # chokes on -Wl,-G. The following line is correct:
++	  shared_flag='-G'
++          else
++	    if test "$aix_use_runtimelinking" = yes; then
++	      shared_flag='${wl}-G'
++	    else
++	      shared_flag='${wl}-bM:SRE'
++	    fi
++          fi
++        fi
++
++        # It seems that -bexpall does not export symbols beginning with
++        # underscore (_), so it is better to generate a list of symbols to
++	# export.
++        _LT_TAGVAR(always_export_symbols, $1)=yes
++        if test "$aix_use_runtimelinking" = yes; then
++          # Warning - without using the other runtime loading flags (-brtl),
++          # -berok will link without error, but may produce a broken library.
++          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
++          # Determine the default libpath from the value encoded in an empty
++          # executable.
++          _LT_SYS_MODULE_PATH_AIX
++          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++
++          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++        else
++          if test "$host_cpu" = ia64; then
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
++	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
++	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++          else
++	    # Determine the default libpath from the value encoded in an
++	    # empty executable.
++	    _LT_SYS_MODULE_PATH_AIX
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++	    # Warning - without using the other run time loading flags,
++	    # -berok will link without error, but may produce a broken library.
++	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
++	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
++	    # Exported symbols can be pulled into shared objects from archives
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
++	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++	    # This is similar to how AIX traditionally builds its shared
++	    # libraries.
++	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++          fi
++        fi
++        ;;
++
++      beos*)
++	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++	  # support --undefined.  This deserves some investigation.  FIXME
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ 	else
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++	  _LT_TAGVAR(ld_shlibs, $1)=no
+ 	fi
+ 	;;
++
+       chorus*)
+-	case $cc_basename in
+-	cxch68*)
+-	  # Green Hills C++ Compiler
+-	  # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
++        case $cc_basename in
++          *)
++	  # FIXME: insert proper C++ library support
++	  _LT_TAGVAR(ld_shlibs, $1)=no
+ 	  ;;
+-	esac
++        esac
++        ;;
++
++      cygwin* | mingw* | pw32*)
++        # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
++        # as there is no search path for DLLs.
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++        _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++        _LT_TAGVAR(always_export_symbols, $1)=no
++        _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++
++        if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++          # If the export-symbols file already is a .def file (1st line
++          # is EXPORTS), use it as is; otherwise, prepend...
++          _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++	    cp $export_symbols $output_objdir/$soname.def;
++          else
++	    echo EXPORTS > $output_objdir/$soname.def;
++	    cat $export_symbols >> $output_objdir/$soname.def;
++          fi~
++          $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++        else
++          _LT_TAGVAR(ld_shlibs, $1)=no
++        fi
++        ;;
++      darwin* | rhapsody*)
++        _LT_DARWIN_LINKER_FEATURES($1)
+ 	;;
+-       darwin*)
+-         # PIC is the default on this platform
+-         # Common symbols not allowed in MH_DYLIB files
+-         case $cc_basename in
+-           xlc*)
+-           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+-           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-           ;;
+-         esac
+-       ;;
++
+       dgux*)
+-	case $cc_basename in
+-	  ec++*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++        case $cc_basename in
++          ec++*)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	  ghcx*)
++          ghcx*)
+ 	    # Green Hills C++ Compiler
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	  *)
++          *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	esac
+-	;;
+-      freebsd* | kfreebsd*-gnu | dragonfly*)
+-	# FreeBSD uses GNU C++
+-	;;
+-      hpux9* | hpux10* | hpux11*)
+-	case $cc_basename in
+-	  CC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+-	    if test "$host_cpu" != ia64; then
+-	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+-	    fi
++        esac
++        ;;
++
++      freebsd[[12]]*)
++        # C++ shared libraries reported to be fairly broken before
++	# switch to ELF
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
++
++      freebsd-elf*)
++        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++        ;;
++
++      freebsd* | dragonfly*)
++        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
++        # conventions
++        _LT_TAGVAR(ld_shlibs, $1)=yes
++        ;;
++
++      gnu*)
++        ;;
++
++      hpux9*)
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++        _LT_TAGVAR(hardcode_direct, $1)=yes
++        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
++				             # but as the default
++				             # location of the library.
++
++        case $cc_basename in
++          CC*)
++            # FIXME: insert proper C++ library support
++            _LT_TAGVAR(ld_shlibs, $1)=no
++            ;;
++          aCC*)
++            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++            # Commands to make compiler produce verbose output that lists
++            # what "hidden" libraries, object files and flags are used when
++            # linking a shared library.
++            #
++            # There doesn't appear to be a way to prevent this compiler from
++            # explicitly linking system object files so we need to strip them
++            # from the output so that they don't get included in the library
++            # dependencies.
++            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
++            ;;
++          *)
++            if test "$GXX" = yes; then
++              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++            else
++              # FIXME: insert proper C++ library support
++              _LT_TAGVAR(ld_shlibs, $1)=no
++            fi
++            ;;
++        esac
++        ;;
++
++      hpux10*|hpux11*)
++        if test $with_gnu_ld = no; then
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++          case $host_cpu in
++            hppa*64*|ia64*)
++              ;;
++            *)
++	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++              ;;
++          esac
++        fi
++        case $host_cpu in
++          hppa*64*|ia64*)
++            _LT_TAGVAR(hardcode_direct, $1)=no
++            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++            ;;
++          *)
++            _LT_TAGVAR(hardcode_direct, $1)=yes
++            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
++					         # but as the default
++					         # location of the library.
++            ;;
++        esac
++
++        case $cc_basename in
++          CC*)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	  aCC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++          aCC*)
+ 	    case $host_cpu in
+-	    hppa*64*|ia64*)
+-	      # +Z the default
+-	      ;;
+-	    *)
+-	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+-	      ;;
++	      hppa*64*)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	        ;;
++	      ia64*)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	        ;;
++	      *)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	        ;;
+ 	    esac
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ 	    ;;
+-	  *)
++          *)
++	    if test "$GXX" = yes; then
++	      if test $with_gnu_ld = no; then
++	        case $host_cpu in
++	          hppa*64*)
++	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	            ;;
++	          ia64*)
++	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	            ;;
++	          *)
++	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	            ;;
++	        esac
++	      fi
++	    else
++	      # FIXME: insert proper C++ library support
++	      _LT_TAGVAR(ld_shlibs, $1)=no
++	    fi
+ 	    ;;
+-	esac
+-	;;
+-      interix*)
+-	# This is c89, which is MS Visual C++ (no shared libs)
+-	# Anyone wants to do a port?
+-	;;
+-      irix5* | irix6* | nonstopux*)
+-	case $cc_basename in
+-	  CC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-	    # CC pic flag -KPIC is the default.
++        esac
++        ;;
++
++      interix[[3-9]]*)
++	_LT_TAGVAR(hardcode_direct, $1)=no
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++	# Instead, shared libraries are loaded at an image base (0x10000000 by
++	# default) and relocated if they conflict, which is a slow very memory
++	# consuming and fragmenting process.  To avoid this, we pick a random,
++	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++	;;
++      irix5* | irix6*)
++        case $cc_basename in
++          CC*)
++	    # SGI C++
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++
++	    # Archives containing C++ object files must be created using
++	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
++	    # necessary to make sure instantiated templates are included
++	    # in the archive.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ 	    ;;
+-	  *)
++          *)
++	    if test "$GXX" = yes; then
++	      if test "$with_gnu_ld" = no; then
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++	      else
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
++	      fi
++	    fi
++	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+ 	    ;;
+-	esac
+-	;;
+-      linux*)
+-	case $cc_basename in
+-	  KCC*)
+-	    # KAI C++ Compiler
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++        esac
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++        _LT_TAGVAR(inherit_rpath, $1)=yes
++        ;;
++
++      linux* | k*bsd*-gnu)
++        case $cc_basename in
++          KCC*)
++	    # Kuck and Associates, Inc. (KAI) C++ Compiler
++
++	    # KCC will only create a shared library if the output file
++	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
++	    # to its proper name (with version) after linking.
++	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++
++	    # Archives containing C++ object files must be created using
++	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ 	    ;;
+-	  icpc* | ecpc*)
++	  icpc* | ecpc* )
+ 	    # Intel C++
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+-	    ;;
+-	  pgCC*)
+-	    # Portland Group C++ compiler.
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	    ;;
+-	  cxx*)
+-	    # Compaq C++
+-	    # Make sure the PIC flag is empty.  It appears that all Alpha
+-	    # Linux and Compaq Tru64 Unix objects are PIC.
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    with_gnu_ld=yes
++	    # version 8.0 and above of icpc choke on multiply defined symbols
++	    # if we add $predep_objects and $postdep_objects, however 7.1 and
++	    # earlier do not add the objects themselves.
++	    case `$CC -V 2>&1` in
++	      *"Version 7."*)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++		;;
++	      *)  # Version 8.0 or newer
++	        tmp_idyn=
++	        case $host_cpu in
++		  ia64*) tmp_idyn=' -i_dynamic';;
++		esac
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++		;;
++	    esac
++	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ 	    ;;
+-	  *)
+-	    case `$CC -V 2>&1 | sed 5q` in
+-	    *Sun\ C*)
+-	      # Sun C++ 5.9
+-	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++          pgCC* | pgcpp*)
++            # Portland Group C++ compiler
++	    case `$CC -V` in
++	    *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*)
++	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
++		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
++		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++		$RANLIB $oldlib'
++	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
++		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
++		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++	      ;;
++	    *) # Version 6 will use weak symbols
++	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ 	      ;;
+ 	    esac
+-	    ;;
+-	esac
+-	;;
+-      lynxos*)
+-	;;
+-      m88k*)
+-	;;
+-      mvs*)
+-	case $cc_basename in
+-	  cxx*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+-	    ;;
+-	  *)
+-	    ;;
+-	esac
+-	;;
+-      netbsd*)
+-	;;
+-      osf3* | osf4* | osf5*)
+-	case $cc_basename in
+-	  KCC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+-	    ;;
+-	  RCC*)
+-	    # Rational C++ 2.4.1
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-	    ;;
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++            ;;
+ 	  cxx*)
+-	    # Digital/Compaq C++
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    # Make sure the PIC flag is empty.  It appears that all Alpha
+-	    # Linux and Compaq Tru64 Unix objects are PIC.
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-	    ;;
+-	  *)
+-	    ;;
+-	esac
+-	;;
+-      psos*)
+-	;;
+-      solaris*)
+-	case $cc_basename in
+-	  CC*)
+-	    # Sun C++ 4.2, 5.x and Centerline C++
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+-	    ;;
+-	  gcx*)
+-	    # Green Hills C++ Compiler
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+-	    ;;
+-	  *)
+-	    ;;
+-	esac
+-	;;
+-      sunos4*)
+-	case $cc_basename in
+-	  CC*)
+-	    # Sun C++ 4.x
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	    ;;
+-	  lcc*)
+-	    # Lucid
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-	    ;;
+-	  *)
++	    # Compaq C++
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
++
++	    runpath_var=LD_RUN_PATH
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ 	    ;;
+-	esac
+-	;;
+-      tandem*)
+-	case $cc_basename in
+-	  NCC*)
+-	    # NonStop-UX NCC 3.20
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	  xl*)
++	    # IBM XL 8.0 on PPC, with GNU ld
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	    if test "x$supports_anon_versioning" = xyes; then
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++		echo "local: *; };" >> $output_objdir/$libname.ver~
++		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++	    fi
+ 	    ;;
+ 	  *)
++	    case `$CC -V 2>&1 | sed 5q` in
++	    *Sun\ C*)
++	      # Sun C++ 5.9
++	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
++	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
++	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	      _LT_TAGVAR(compiler_needs_object, $1)=yes
++
++	      # Not sure whether something based on
++	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
++	      # would be better.
++	      output_verbose_link_cmd='echo'
++
++	      # Archives containing C++ object files must be created using
++	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
++	      # necessary to make sure instantiated templates are included
++	      # in the archive.
++	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
++	      ;;
++	    esac
+ 	    ;;
+ 	esac
+ 	;;
+-      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+-	case $cc_basename in
+-	  CC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++
++      lynxos*)
++        # FIXME: insert proper C++ library support
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	;;
++
++      m88k*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++	;;
++
++      mvs*)
++        case $cc_basename in
++          cxx*)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++	  *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+ 	esac
+ 	;;
+-      vxworks*)
++
++      netbsd*)
++        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
++	  wlarc=
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	  _LT_TAGVAR(hardcode_direct, $1)=yes
++	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	fi
++	# Workaround some broken pre-1.5 toolchains
++	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ 	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++
++      *nto* | *qnx*)
++        _LT_TAGVAR(ld_shlibs, $1)=yes
+ 	;;
+-    esac
+-  fi
+-],
+-[
+-  if test "$GCC" = yes; then
+-    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ 
+-    case $host_os in
+-      aix*)
+-      # All AIX code is PIC.
+-      if test "$host_cpu" = ia64; then
+-	# AIX 5 now supports IA64 processor
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      fi
+-      ;;
++      openbsd2*)
++        # C++ shared libraries are fairly broken
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	;;
++
++      openbsd*)
++	if test -f /usr/libexec/ld.so; then
++	  _LT_TAGVAR(hardcode_direct, $1)=yes
++	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++	  fi
++	  output_verbose_link_cmd=echo
++	else
++	  _LT_TAGVAR(ld_shlibs, $1)=no
++	fi
++	;;
+ 
+-    amigaos*)
+-      # FIXME: we need at least 68020 code to build shared libraries, but
+-      # adding the `-m68020' flag to GCC prevents building anything better,
+-      # like `-m68040'.
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+-      ;;
++      osf3* | osf4* | osf5*)
++        case $cc_basename in
++          KCC*)
++	    # Kuck and Associates, Inc. (KAI) C++ Compiler
++
++	    # KCC will only create a shared library if the output file
++	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
++	    # to its proper name (with version) after linking.
++	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++	    # Archives containing C++ object files must be created using
++	    # the KAI C++ compiler.
++	    case $host in
++	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
++	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
++	    esac
++	    ;;
++          RCC*)
++	    # Rational C++ 2.4.1
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          cxx*)
++	    case $host in
++	      osf3*)
++	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++		;;
++	      *)
++	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
++	          echo "-hidden">> $lib.exp~
++	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
++	          $RM $lib.exp'
++	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++		;;
++	    esac
+ 
+-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+-      # PIC is the default for these OSes.
+-      ;;
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ 
+-    mingw* | cygwin* | pw32* | os2*)
+-      # This hack is so that the source file can tell whether it is being
+-      # built for inclusion in a dll (and should export symbols for example).
+-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+-      # (--disable-auto-import) libraries
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+-      ;;
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
++	    ;;
++	  *)
++	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
++	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	      case $host in
++	        osf3*)
++	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++		  ;;
++	        *)
++	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++		  ;;
++	      esac
++
++	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++	      # Commands to make compiler produce verbose output that lists
++	      # what "hidden" libraries, object files and flags are used when
++	      # linking a shared library.
++	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++
++	    else
++	      # FIXME: insert proper C++ library support
++	      _LT_TAGVAR(ld_shlibs, $1)=no
++	    fi
++	    ;;
++        esac
++        ;;
+ 
+-    darwin* | rhapsody*)
+-      # PIC is the default on this platform
+-      # Common symbols not allowed in MH_DYLIB files
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+-      ;;
++      psos*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
+ 
+-    interix3*)
+-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+-      # Instead, we relocate shared libraries at runtime.
+-      ;;
++      sunos4*)
++        case $cc_basename in
++          CC*)
++	    # Sun C++ 4.x
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          lcc*)
++	    # Lucid
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++        esac
++        ;;
+ 
+-    msdosdjgpp*)
+-      # Just because we use GCC doesn't mean we suddenly get shared libraries
+-      # on systems that don't support them.
+-      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+-      enable_shared=no
+-      ;;
++      solaris*)
++        case $cc_basename in
++          CC*)
++	    # Sun C++ 4.2, 5.x and Centerline C++
++            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
++	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	    case $host_os in
++	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++	      *)
++		# The compiler driver will combine and reorder linker options,
++		# but understands `-z linker_flag'.
++	        # Supported since Solaris 2.6 (maybe 2.5.1?)
++		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
++	        ;;
++	    esac
++	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+ 
+-    sysv4*MP*)
+-      if test -d /usr/nec; then
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+-      fi
+-      ;;
++	    output_verbose_link_cmd='echo'
+ 
+-    hpux*)
+-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+-      # not for PA HP-UX.
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	# +Z the default
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-	;;
+-      esac
+-      ;;
++	    # Archives containing C++ object files must be created using
++	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
++	    # necessary to make sure instantiated templates are included
++	    # in the archive.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
++	    ;;
++          gcx*)
++	    # Green Hills C++ Compiler
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ 
+-    *)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-      ;;
+-    esac
+-  else
+-    # PORTME Check for flag to pass linker flags through the system compiler.
+-    case $host_os in
+-    aix*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      if test "$host_cpu" = ia64; then
+-	# AIX 5 now supports IA64 processor
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      else
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+-      fi
+-      ;;
+-      darwin*)
+-        # PIC is the default on this platform
+-        # Common symbols not allowed in MH_DYLIB files
+-       case $cc_basename in
+-         xlc*)
+-         _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+-         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-         ;;
+-       esac
+-       ;;
++	    # The C++ compiler must be used to create the archive.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
++	    ;;
++          *)
++	    # GNU C++ compiler with Solaris linker
++	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
++	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
++	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++		  $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++	        # Commands to make compiler produce verbose output that lists
++	        # what "hidden" libraries, object files and flags are used when
++	        # linking a shared library.
++	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++	      else
++	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
++	        # platform.
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++	        # Commands to make compiler produce verbose output that lists
++	        # what "hidden" libraries, object files and flags are used when
++	        # linking a shared library.
++	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++	      fi
++
++	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
++	      case $host_os in
++		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++		*)
++		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++		  ;;
++	      esac
++	    fi
++	    ;;
++        esac
++        ;;
+ 
+-    mingw* | cygwin* | pw32* | os2*)
+-      # This hack is so that the source file can tell whether it is being
+-      # built for inclusion in a dll (and should export symbols for example).
+-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+-      # (--disable-auto-import) libraries
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+-      ;;
++    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      runpath_var='LD_RUN_PATH'
+ 
+-    hpux9* | hpux10* | hpux11*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+-      # not for PA HP-UX.
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	# +Z the default
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+-	;;
++      case $cc_basename in
++        CC*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
+       esac
+-      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+       ;;
+ 
+-    irix5* | irix6* | nonstopux*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      # PIC (with -KPIC) is the default.
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-      ;;
++      sysv5* | sco3.2v5* | sco5v6*)
++	# Note: We can NOT use -z defs as we might desire, because we do not
++	# link with -lc, and that would cause any symbols used from libc to
++	# always be unresolved, which means just about no library would
++	# ever link correctly.  If we're not using GNU ld we use -z text
++	# though, which does catch some bad symbols but isn't as heavy-handed
++	# as -z defs.
++	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
++	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++	_LT_TAGVAR(link_all_deplibs, $1)=yes
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++	runpath_var='LD_RUN_PATH'
+ 
+-    newsos6)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	case $cc_basename in
++          CC*)
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    ;;
++	  *)
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    ;;
++	esac
+       ;;
+ 
+-    linux*)
+-      case $cc_basename in
+-      icc* | ecc*)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+-        ;;
+-      pgcc* | pgf77* | pgf90* | pgf95*)
+-        # Portland Group compilers (*not* the Pentium gcc compiler,
+-	# which looks to be a dead project)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-        ;;
+-      ccc*)
+-        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-        # All Alpha code is PIC.
+-        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      tandem*)
++        case $cc_basename in
++          NCC*)
++	    # NonStop-UX NCC 3.20
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++        esac
+         ;;
+-      como)
+-        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-lopt='
++
++      vxworks*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
+         ;;
++
+       *)
+-        case `$CC -V 2>&1 | sed 5q` in
+-	*Sun\ C*)
+-	  # Sun C 5.9
+-	  _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	  ;;
+-	*Sun\ F*)
+-	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+-	  _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=''
+-	  ;;
+-	esac
+-	;;
+-      esac
+-      ;;
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
++    esac
+ 
+-    osf3* | osf4* | osf5*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      # All OSF/1 code is PIC.
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-      ;;
++    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
++    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+ 
+-    solaris*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      case $cc_basename in
+-      f77* | f90* | f95*)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+-      esac
+-      ;;
++    _LT_TAGVAR(GCC, $1)="$GXX"
++    _LT_TAGVAR(LD, $1)="$LD"
++
++    ## CAVEAT EMPTOR:
++    ## There is no encapsulation within the following macros, do not change
++    ## the running order or otherwise move them around unless you know exactly
++    ## what you are doing...
++    _LT_SYS_HIDDEN_LIBDEPS($1)
++    _LT_COMPILER_PIC($1)
++    _LT_COMPILER_C_O($1)
++    _LT_COMPILER_FILE_LOCKS($1)
++    _LT_LINKER_SHLIBS($1)
++    _LT_SYS_DYNAMIC_LINKER($1)
++    _LT_LINKER_HARDCODE_LIBPATH($1)
++
++    _LT_CONFIG($1)
++  fi # test -n "$compiler"
++
++  CC=$lt_save_CC
++  LDCXX=$LD
++  LD=$lt_save_LD
++  GCC=$lt_save_GCC
++  with_gnu_ld=$lt_save_with_gnu_ld
++  lt_cv_path_LDCXX=$lt_cv_path_LD
++  lt_cv_path_LD=$lt_save_path_LD
++  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
++  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
++fi # test "$_lt_caught_CXX_error" != yes
++
++AC_LANG_POP
++])# _LT_LANG_CXX_CONFIG
++
++
++# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
++# ---------------------------------
++# Figure out "hidden" library dependencies from verbose
++# compiler output when linking a shared library.
++# Parse the compiler output and extract the necessary
++# objects, libraries and library flags.
++m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++# Dependencies to place before and after the object being linked:
++_LT_TAGVAR(predep_objects, $1)=
++_LT_TAGVAR(postdep_objects, $1)=
++_LT_TAGVAR(predeps, $1)=
++_LT_TAGVAR(postdeps, $1)=
++_LT_TAGVAR(compiler_lib_search_path, $1)=
++
++dnl we can't use the lt_simple_compile_test_code here,
++dnl because it contains code intended for an executable,
++dnl not a library.  It's possible we should let each
++dnl tag define a new lt_????_link_test_code variable,
++dnl but it's only used here...
++m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
++int a;
++void foo (void) { a = 0; }
++_LT_EOF
++], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
++class Foo
++{
++public:
++  Foo (void) { a = 0; }
++private:
++  int a;
++};
++_LT_EOF
++], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
++      subroutine foo
++      implicit none
++      integer*4 a
++      a=0
++      return
++      end
++_LT_EOF
++], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
++      subroutine foo
++      implicit none
++      integer a
++      a=0
++      return
++      end
++_LT_EOF
++], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
++public class foo {
++  private int a;
++  public void bar (void) {
++    a = 0;
++  }
++};
++_LT_EOF
++])
++dnl Parse the compiler output and extract the necessary
++dnl objects, libraries and library flags.
++if AC_TRY_EVAL(ac_compile); then
++  # Parse the compiler output and extract the necessary
++  # objects, libraries and library flags.
++
++  # Sentinel used to keep track of whether or not we are before
++  # the conftest object file.
++  pre_test_object_deps_done=no
+ 
+-    sunos4*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++  for p in `eval "$output_verbose_link_cmd"`; do
++    case $p in
+ 
+-    sysv4 | sysv4.2uw2* | sysv4.3*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++    -L* | -R* | -l*)
++       # Some compilers place space between "-{L,R}" and the path.
++       # Remove the space.
++       if test $p = "-L" ||
++          test $p = "-R"; then
++	 prev=$p
++	 continue
++       else
++	 prev=
++       fi
+ 
+-    sysv4*MP*)
+-      if test -d /usr/nec ;then
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      fi
+-      ;;
++       if test "$pre_test_object_deps_done" = no; then
++	 case $p in
++	 -L* | -R*)
++	   # Internal compiler library paths should come after those
++	   # provided the user.  The postdeps already come after the
++	   # user supplied libs so there is no need to process them.
++	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
++	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
++	   else
++	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
++	   fi
++	   ;;
++	 # The "-l" case would never come before the object being
++	 # linked, so don't bother handling this case.
++	 esac
++       else
++	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
++	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
++	 else
++	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
++	 fi
++       fi
++       ;;
+ 
+-    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++    *.$objext)
++       # This assumes that the test object file only shows up
++       # once in the compiler output.
++       if test "$p" = "conftest.$objext"; then
++	 pre_test_object_deps_done=yes
++	 continue
++       fi
+ 
+-    unicos*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+-      ;;
++       if test "$pre_test_object_deps_done" = no; then
++	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
++	   _LT_TAGVAR(predep_objects, $1)="$p"
++	 else
++	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
++	 fi
++       else
++	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
++	   _LT_TAGVAR(postdep_objects, $1)="$p"
++	 else
++	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
++	 fi
++       fi
++       ;;
+ 
+-    uts4*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++    *) ;; # Ignore the rest.
+ 
+-    *)
+-      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+-      ;;
+     esac
+-  fi
+-])
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
++  done
+ 
+-#
+-# Check to make sure the PIC flag actually works.
+-#
+-if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+-  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+-    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+-    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+-     "" | " "*) ;;
+-     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+-     esac],
+-    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
++  # Clean up.
++  rm -f a.out a.exe
++else
++  echo "libtool.m4: error: problem compiling $1 test program"
+ fi
+-case $host_os in
+-  # For platforms which do not support PIC, -DPIC is meaningless:
+-  *djgpp*)
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-    ;;
+-  *)
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+-    ;;
+-esac
+-
+-#
+-# Check to make sure the static flag actually works.
+-#
+-wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
+-AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+-  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+-  $lt_tmp_static_flag,
+-  [],
+-  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+-])
+ 
++$RM -f confest.$objext
+ 
+-# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+-# ------------------------------------
+-# See if the linker supports building shared libraries.
+-AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+-[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+-ifelse([$1],[CXX],[
+-  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+-  case $host_os in
+-  aix4* | aix5*)
+-    # If we're using GNU nm, then we don't want the "-C" option.
+-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+-    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+-      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+-    else
+-      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+-    fi
+-    ;;
+-  pw32*)
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+-  ;;
+-  cygwin* | mingw*)
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+-  ;;
+-  *)
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++# PORTME: override above test on systems where it is broken
++m4_if([$1], [CXX],
++[case $host_os in
++interix[[3-9]]*)
++  # Interix 3.5 installs completely hosed .la files for C++, so rather than
++  # hack all around it, let's just trust "g++" to DTRT.
++  _LT_TAGVAR(predep_objects,$1)=
++  _LT_TAGVAR(postdep_objects,$1)=
++  _LT_TAGVAR(postdeps,$1)=
+   ;;
+-  esac
+-],[
+-  runpath_var=
+-  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+-  _LT_AC_TAGVAR(archive_cmds, $1)=
+-  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+-  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+-  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+-  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+-  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+-  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+-  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+-  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+-  _LT_AC_TAGVAR(module_cmds, $1)=
+-  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+-  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+-  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+-  # include_expsyms should be a list of space-separated symbols to be *always*
+-  # included in the symbol list
+-  _LT_AC_TAGVAR(include_expsyms, $1)=
+-  # exclude_expsyms can be an extended regexp of symbols to exclude
+-  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+-  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+-  # as well as any symbol that contains `d'.
+-  _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+-  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+-  # platforms (ab)use it in PIC code, but their linkers get confused if
+-  # the symbol is explicitly referenced.  Since portable code cannot
+-  # rely on this symbol name, it's probably fine to never include it in
+-  # preloaded symbol tables.
+-  extract_expsyms_cmds=
+-  # Just being paranoid about ensuring that cc_basename is set.
+-  _LT_CC_BASENAME([$compiler])
+-  case $host_os in
+-  cygwin* | mingw* | pw32*)
+-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+-    # When not using gcc, we currently assume that we are using
+-    # Microsoft Visual C++.
+-    if test "$GCC" != yes; then
+-      with_gnu_ld=no
+-    fi
+-    ;;
+-  interix*)
+-    # we just hope/assume this is gcc and not c89 (= MSVC++)
+-    with_gnu_ld=yes
+-    ;;
+-  openbsd*)
+-    with_gnu_ld=no
+-    ;;
+-  esac
+-
+-  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-  if test "$with_gnu_ld" = yes; then
+-    # If archive_cmds runs LD, not CC, wlarc should be empty
+-    wlarc='${wl}'
+-
+-    # Set some defaults for GNU ld with shared library support. These
+-    # are reset later if shared libraries are not supported. Putting them
+-    # here allows them to be overridden if necessary.
+-    runpath_var=LD_RUN_PATH
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-    # ancient GNU ld didn't support --whole-archive et. al.
+-    if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+-      else
+-  	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-    fi
+-    supports_anon_versioning=no
+-    case `$LD -v 2>/dev/null` in
+-      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+-      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+-      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+-      *\ 2.11.*) ;; # other 2.11 versions
+-      *) supports_anon_versioning=yes ;;
+-    esac
+-
+-    # See if GNU ld supports shared libraries.
+-    case $host_os in
+-    aix3* | aix4* | aix5*)
+-      # On AIX/PPC, the GNU linker is very broken
+-      if test "$host_cpu" != ia64; then
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	cat <<EOF 1>&2
+-
+-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+-*** to be unable to reliably create shared libraries on AIX.
+-*** Therefore, libtool is disabling shared libraries support.  If you
+-*** really care for shared libraries, you may want to modify your PATH
+-*** so that a non-GNU linker is found, and then restart.
+-
+-EOF
+-      fi
+-      ;;
+ 
+-    amigaos*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-
+-      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+-      # that the semantics of dynamic libraries on AmigaOS, at least up
+-      # to version 4, is to share data among multiple programs linked
+-      # with the same dynamic library.  Since this doesn't match the
+-      # behavior of shared libraries on other platforms, we can't use
+-      # them.
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
++linux*)
++  case `$CC -V 2>&1 | sed 5q` in
++  *Sun\ C*)
++    # Sun C++ 5.9
+ 
+-    beos*)
+-      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+-	# support --undefined.  This deserves some investigation.  FIXME
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
++    # The more standards-conforming stlport4 library is
++    # incompatible with the Cstd library. Avoid specifying
++    # it if it's in CXXFLAGS. Ignore libCrun as
++    # -library=stlport4 depends on it.
++    case " $CXX $CXXFLAGS " in
++    *" -library=stlport4 "*)
++      solaris_use_stlport4=yes
+       ;;
++    esac
+ 
+-    cygwin* | mingw* | pw32*)
+-      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+-      # as there is no search path for DLLs.
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+-      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+-      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+-
+-      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-	# If the export-symbols file already is a .def file (1st line
+-	# is EXPORTS), use it as is; otherwise, prepend...
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+-	  cp $export_symbols $output_objdir/$soname.def;
+-	else
+-	  echo EXPORTS > $output_objdir/$soname.def;
+-	  cat $export_symbols >> $output_objdir/$soname.def;
+-	fi~
+-	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
++    if test "$solaris_use_stlport4" != yes; then
++      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
++    fi
++    ;;
++  esac
++  ;;
+ 
+-    interix3*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+-      # Instead, shared libraries are loaded at an image base (0x10000000 by
+-      # default) and relocated if they conflict, which is a slow very memory
+-      # consuming and fragmenting process.  To avoid this, we pick a random,
+-      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+-      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++solaris*)
++  case $cc_basename in
++  CC*)
++    # The more standards-conforming stlport4 library is
++    # incompatible with the Cstd library. Avoid specifying
++    # it if it's in CXXFLAGS. Ignore libCrun as
++    # -library=stlport4 depends on it.
++    case " $CXX $CXXFLAGS " in
++    *" -library=stlport4 "*)
++      solaris_use_stlport4=yes
+       ;;
++    esac
+ 
+-    linux*)
+-      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	tmp_addflag=
+-	case $cc_basename,$host_cpu in
+-	pgcc*)				# Portland Group C compiler
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-	  tmp_addflag=' $pic_flag'
+-	  ;;
+-	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-	  tmp_addflag=' $pic_flag -Mnomain' ;;
+-	ecc*,ia64* | icc*,ia64*)		# Intel C compiler on ia64
+-	  tmp_addflag=' -i_dynamic' ;;
+-	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+-	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+-	ifc* | ifort*)			# Intel Fortran compiler
+-	  tmp_addflag=' -nofor_main' ;;
+-	esac
+-	case `$CC -V 2>&1 | sed 5q` in
+-	*Sun\ C*)			# Sun C 5.9
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive /dev/null'
+-	  tmp_sharedflag='-G' ;;
+-	*Sun\ F*)			# Sun Fortran 8.3
+-	  tmp_sharedflag='-G' ;;
+-	*)
+-	  tmp_sharedflag='-shared' ;;
+-	esac
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++    # Adding this requires a known-good setup of shared libraries for
++    # Sun compiler versions before 5.6, else PIC objects from an old
++    # archive will be linked into the output, leading to subtle bugs.
++    if test "$solaris_use_stlport4" != yes; then
++      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
++    fi
++    ;;
++  esac
++  ;;
++esac
++])
+ 
+-	if test $supports_anon_versioning = yes; then
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+-  cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+-  $echo "local: *; };" >> $output_objdir/$libname.ver~
+-	  $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+-	fi
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
++case " $_LT_TAGVAR(postdeps, $1) " in
++*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
++esac
++ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
++if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
++ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
++fi
++_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
++    [The directories searched by this compiler when creating a shared library])
++_LT_TAGDECL([], [predep_objects], [1],
++    [Dependencies to place before and after the objects being linked to
++    create a shared library])
++_LT_TAGDECL([], [postdep_objects], [1])
++_LT_TAGDECL([], [predeps], [1])
++_LT_TAGDECL([], [postdeps], [1])
++_LT_TAGDECL([], [compiler_lib_search_path], [1],
++    [The library search path used internally by the compiler when linking
++    a shared library])
++])# _LT_SYS_HIDDEN_LIBDEPS
++
++
++# _LT_PROG_F77
++# ------------
++# Since AC_PROG_F77 is broken, in that it returns the empty string
++# if there is no fortran compiler, we have our own version here.
++m4_defun([_LT_PROG_F77],
++[
++pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes])
++AC_PROG_F77
++if test -z "$F77" || test "X$F77" = "Xno"; then
++  _lt_disable_F77=yes
++fi
++popdef([AC_MSG_ERROR])
++])# _LT_PROG_F77
+ 
+-    netbsd*)
+-      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+-	wlarc=
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-      fi
+-      ;;
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([_LT_PROG_F77], [])
+ 
+-    solaris*)
+-      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	cat <<EOF 1>&2
+ 
+-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+-*** create shared libraries on Solaris systems.  Therefore, libtool
+-*** is disabling shared libraries support.  We urge you to upgrade GNU
+-*** binutils to release 2.9.1 or newer.  Another option is to modify
+-*** your PATH or compiler configuration so that the native linker is
+-*** used, and then restart.
++# _LT_LANG_F77_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for a Fortran 77 compiler are
++# suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_F77_CONFIG],
++[AC_REQUIRE([_LT_PROG_F77])dnl
++AC_LANG_PUSH(Fortran 77)
+ 
+-EOF
+-      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ 
+-    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+-      case `$LD -v 2>&1` in
+-        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) 
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	cat <<_LT_EOF 1>&2
++# Source file extension for f77 test sources.
++ac_ext=f
+ 
+-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+-*** reliably create shared libraries on SCO systems.  Therefore, libtool
+-*** is disabling shared libraries support.  We urge you to upgrade GNU
+-*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+-*** your PATH or compiler configuration so that the native linker is
+-*** used, and then restart.
++# Object file extension for compiled f77 test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-_LT_EOF
+-	;;
+-	*)
+-	  if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+-	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+-	  else
+-	    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	  fi
+-	;;
+-      esac
+-      ;;
++# No sense in running all these tests if we already determined that
++# the F77 compiler isn't working.  Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_disable_F77" != yes; then
++  # Code to be used in simple compile tests
++  lt_simple_compile_test_code="\
++      subroutine t
++      return
++      end
++"
+ 
+-    sunos4*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+-      wlarc=
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  # Code to be used in simple link tests
++  lt_simple_link_test_code="\
++      program t
++      end
++"
+ 
+-    *)
+-      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
+-    esac
++  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++  _LT_TAG_COMPILER
+ 
+-    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+-      runpath_var=
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-    fi
+-  else
+-    # PORTME fill in a description of your system's linker (not GNU ld)
+-    case $host_os in
+-    aix3*)
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+-      # Note: this linker hardcodes the directories in LIBPATH if there
+-      # are no directories specified by -L.
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+-	# Neither direct hardcoding nor static linking is supported with a
+-	# broken collect2.
+-	_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+-      fi
+-      ;;
++  # save warnings/boilerplate of simple test code
++  _LT_COMPILER_BOILERPLATE
++  _LT_LINKER_BOILERPLATE
++
++  # Allow CC to be a program name with arguments.
++  lt_save_CC="$CC"
++  lt_save_GCC=$GCC
++  CC=${F77-"f77"}
++  compiler=$CC
++  _LT_TAGVAR(compiler, $1)=$CC
++  _LT_CC_BASENAME([$compiler])
++  GCC=$G77
++  if test -n "$compiler"; then
++    AC_MSG_CHECKING([if libtool supports shared libraries])
++    AC_MSG_RESULT([$can_build_shared])
+ 
+-    aix4* | aix5*)
+-      if test "$host_cpu" = ia64; then
+-	# On IA64, the linker does run time linking by default, so we don't
+-	# have to do anything special.
+-	aix_use_runtimelinking=no
+-	exp_sym_flag='-Bexport'
+-	no_entry_flag=""
+-      else
+-	# If we're using GNU nm, then we don't want the "-C" option.
+-	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+-	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+-	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+-	else
+-	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
++    AC_MSG_CHECKING([whether to build shared libraries])
++    test "$can_build_shared" = "no" && enable_shared=no
++
++    # On AIX, shared libraries and static libraries use the same namespace, and
++    # are all built from PIC.
++    case $host_os in
++      aix3*)
++        test "$enable_shared" = yes && enable_static=no
++        if test -n "$RANLIB"; then
++          archive_cmds="$archive_cmds~\$RANLIB \$lib"
++          postinstall_cmds='$RANLIB $lib'
++        fi
++        ;;
++      aix[[4-9]]*)
++	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++	  test "$enable_shared" = yes && enable_static=no
+ 	fi
+-	aix_use_runtimelinking=no
++        ;;
++    esac
++    AC_MSG_RESULT([$enable_shared])
+ 
+-	# Test if we are trying to use run time linking or normal
+-	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+-	# need to do runtime linking.
+-	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+-	  for ld_flag in $LDFLAGS; do
+-  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+-  	    aix_use_runtimelinking=yes
+-  	    break
+-  	  fi
+-	  done
+-	  ;;
+-	esac
++    AC_MSG_CHECKING([whether to build static libraries])
++    # Make sure either enable_shared or enable_static is yes.
++    test "$enable_shared" = yes || enable_static=yes
++    AC_MSG_RESULT([$enable_static])
++
++    _LT_TAGVAR(GCC, $1)="$G77"
++    _LT_TAGVAR(LD, $1)="$LD"
++
++    ## CAVEAT EMPTOR:
++    ## There is no encapsulation within the following macros, do not change
++    ## the running order or otherwise move them around unless you know exactly
++    ## what you are doing...
++    _LT_COMPILER_PIC($1)
++    _LT_COMPILER_C_O($1)
++    _LT_COMPILER_FILE_LOCKS($1)
++    _LT_LINKER_SHLIBS($1)
++    _LT_SYS_DYNAMIC_LINKER($1)
++    _LT_LINKER_HARDCODE_LIBPATH($1)
++
++    _LT_CONFIG($1)
++  fi # test -n "$compiler"
++
++  GCC=$lt_save_GCC
++  CC="$lt_save_CC"
++fi # test "$_lt_disable_F77" != yes
+ 
+-	exp_sym_flag='-bexport'
+-	no_entry_flag='-bnoentry'
+-      fi
++AC_LANG_POP
++])# _LT_LANG_F77_CONFIG
+ 
+-      # When large executables or shared objects are built, AIX ld can
+-      # have problems creating the table of contents.  If linking a library
+-      # or program results in "error TOC overflow" add -mminimal-toc to
+-      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+-      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ 
+-      _LT_AC_TAGVAR(archive_cmds, $1)=''
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++# _LT_PROG_FC
++# -----------
++# Since AC_PROG_FC is broken, in that it returns the empty string
++# if there is no fortran compiler, we have our own version here.
++m4_defun([_LT_PROG_FC],
++[
++pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes])
++AC_PROG_FC
++if test -z "$FC" || test "X$FC" = "Xno"; then
++  _lt_disable_FC=yes
++fi
++popdef([AC_MSG_ERROR])
++])# _LT_PROG_FC
+ 
+-      if test "$GCC" = yes; then
+-	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+-	# We only want to do this on AIX 4.2 and lower, the check
+-	# below for broken collect2 doesn't work under 4.3+
+-	  collect2name=`${CC} -print-prog-name=collect2`
+-	  if test -f "$collect2name" && \
+-  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+-	  then
+-  	  # We have reworked collect2
+-  	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	  else
+-  	  # We have old collect2
+-  	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+-  	  # It fails to find uninstalled libraries when the uninstalled
+-  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+-  	  # to unsupported forces relinking
+-  	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-  	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-  	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-	  fi
+-	  ;;
+-	esac
+-	shared_flag='-shared'
+-	if test "$aix_use_runtimelinking" = yes; then
+-	  shared_flag="$shared_flag "'${wl}-G'
+-	fi
+-      else
+-	# not using gcc
+-	if test "$host_cpu" = ia64; then
+-  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+-  	# chokes on -Wl,-G. The following line is correct:
+-	  shared_flag='-G'
+-	else
+-	  if test "$aix_use_runtimelinking" = yes; then
+-	    shared_flag='${wl}-G'
+-	  else
+-	    shared_flag='${wl}-bM:SRE'
+-	  fi
+-	fi
+-      fi
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([_LT_PROG_FC], [])
+ 
+-      # It seems that -bexpall does not export symbols beginning with
+-      # underscore (_), so it is better to generate a list of symbols to export.
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+-      if test "$aix_use_runtimelinking" = yes; then
+-	# Warning - without using the other runtime loading flags (-brtl),
+-	# -berok will link without error, but may produce a broken library.
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+-       # Determine the default libpath from the value encoded in an empty executable.
+-       _LT_AC_SYS_LIBPATH_AIX
+-       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+-       else
+-	if test "$host_cpu" = ia64; then
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+-	else
+-	 # Determine the default libpath from the value encoded in an empty executable.
+-	 _LT_AC_SYS_LIBPATH_AIX
+-	 _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-	  # Warning - without using the other run time loading flags,
+-	  # -berok will link without error, but may produce a broken library.
+-	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+-	  # Exported symbols can be pulled into shared objects from archives
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+-	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-	  # This is similar to how AIX traditionally builds its shared libraries.
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+-	fi
+-      fi
+-      ;;
+ 
+-    amigaos*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      # see comment about different semantics on the GNU ld section
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
++# _LT_LANG_FC_CONFIG([TAG])
++# -------------------------
++# Ensure that the configuration variables for a Fortran compiler are
++# suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_FC_CONFIG],
++[AC_REQUIRE([_LT_PROG_FC])dnl
++AC_LANG_PUSH(Fortran)
++
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ 
+-    bsdi[[45]]*)
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+-      ;;
++# Source file extension for fc test sources.
++ac_ext=${ac_fc_srcext-f}
+ 
+-    cygwin* | mingw* | pw32*)
+-      # When not using gcc, we currently assume that we are using
+-      # Microsoft Visual C++.
+-      # hardcode_libdir_flag_spec is actually meaningless, as there is
+-      # no search path for DLLs.
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      # Tell ltmain to make .lib files, not .a files.
+-      libext=lib
+-      # Tell ltmain to make .dll files, not .so files.
+-      shrext_cmds=".dll"
+-      # FIXME: Setting linknames here is a bad hack.
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+-      # The linker will automatically build a .lib file if we build a DLL.
+-      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+-      # FIXME: Should let the user specify the lib program.
+-      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+-      _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+-      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+-      ;;
++# Object file extension for compiled fc test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-    darwin* | rhapsody*)
+-      case $host_os in
+-        rhapsody* | darwin1.[[012]])
+-         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+-         ;;
+-       *) # Darwin 1.3 on
+-         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+-           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-         else
+-           case ${MACOSX_DEPLOYMENT_TARGET} in
+-             10.[[012]])
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-               ;;
+-             10.*)
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+-               ;;
+-           esac
+-         fi
+-         ;;
+-      esac
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-    if test "$GCC" = yes ; then
+-    	output_verbose_link_cmd='echo'
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+-      _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-      _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-    else
+-      case $cc_basename in
+-        xlc*)
+-         output_verbose_link_cmd='echo'
+-         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+-         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          ;;
+-       *)
+-         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-          ;;
+-      esac
+-    fi
+-      ;;
++# No sense in running all these tests if we already determined that
++# the FC compiler isn't working.  Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_disable_FC" != yes; then
++  # Code to be used in simple compile tests
++  lt_simple_compile_test_code="\
++      subroutine t
++      return
++      end
++"
+ 
+-    dgux*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  # Code to be used in simple link tests
++  lt_simple_link_test_code="\
++      program t
++      end
++"
+ 
+-    freebsd1*)
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
++  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++  _LT_TAG_COMPILER
+ 
+-    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+-    # support.  Future versions do this automatically, but an explicit c++rt0.o
+-    # does not break anything, and helps significantly (at the cost of a little
+-    # extra space).
+-    freebsd2.2*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  # save warnings/boilerplate of simple test code
++  _LT_COMPILER_BOILERPLATE
++  _LT_LINKER_BOILERPLATE
++
++  # Allow CC to be a program name with arguments.
++  lt_save_CC="$CC"
++  lt_save_GCC=$GCC
++  CC=${FC-"f95"}
++  compiler=$CC
++  GCC=$ac_cv_fc_compiler_gnu
+ 
+-    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+-    freebsd2*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  _LT_TAGVAR(compiler, $1)=$CC
++  _LT_CC_BASENAME([$compiler])
+ 
+-    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+-    freebsd* | kfreebsd*-gnu | dragonfly*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  if test -n "$compiler"; then
++    AC_MSG_CHECKING([if libtool supports shared libraries])
++    AC_MSG_RESULT([$can_build_shared])
+ 
+-    hpux9*)
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
++    AC_MSG_CHECKING([whether to build shared libraries])
++    test "$can_build_shared" = "no" && enable_shared=no
+ 
+-      # hardcode_minus_L: Not really in the search PATH,
+-      # but as the default location of the library.
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      ;;
++    # On AIX, shared libraries and static libraries use the same namespace, and
++    # are all built from PIC.
++    case $host_os in
++      aix3*)
++        test "$enable_shared" = yes && enable_static=no
++        if test -n "$RANLIB"; then
++          archive_cmds="$archive_cmds~\$RANLIB \$lib"
++          postinstall_cmds='$RANLIB $lib'
++        fi
++        ;;
++      aix[[4-9]]*)
++	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++	  test "$enable_shared" = yes && enable_static=no
++	fi
++        ;;
++    esac
++    AC_MSG_RESULT([$enable_shared])
+ 
+-    hpux10*)
+-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+-      fi
+-      if test "$with_gnu_ld" = no; then
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++    AC_MSG_CHECKING([whether to build static libraries])
++    # Make sure either enable_shared or enable_static is yes.
++    test "$enable_shared" = yes || enable_static=yes
++    AC_MSG_RESULT([$enable_static])
++
++    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
++    _LT_TAGVAR(LD, $1)="$LD"
++
++    ## CAVEAT EMPTOR:
++    ## There is no encapsulation within the following macros, do not change
++    ## the running order or otherwise move them around unless you know exactly
++    ## what you are doing...
++    _LT_SYS_HIDDEN_LIBDEPS($1)
++    _LT_COMPILER_PIC($1)
++    _LT_COMPILER_C_O($1)
++    _LT_COMPILER_FILE_LOCKS($1)
++    _LT_LINKER_SHLIBS($1)
++    _LT_SYS_DYNAMIC_LINKER($1)
++    _LT_LINKER_HARDCODE_LIBPATH($1)
++
++    _LT_CONFIG($1)
++  fi # test -n "$compiler"
++
++  GCC=$lt_save_GCC
++  CC="$lt_save_CC"
++fi # test "$_lt_disable_FC" != yes
+ 
+-	_LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++AC_LANG_POP
++])# _LT_LANG_FC_CONFIG
+ 
+-	# hardcode_minus_L: Not really in the search PATH,
+-	# but as the default location of the library.
+-	_LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      fi
+-      ;;
+ 
+-    hpux11*)
+-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+-	case $host_cpu in
+-	hppa*64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	ia64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	esac
+-      else
+-	case $host_cpu in
+-	hppa*64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	ia64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	esac
+-      fi
+-      if test "$with_gnu_ld" = no; then
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++# _LT_LANG_GCJ_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for the GNU Java Compiler compiler
++# are suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_GCJ_CONFIG],
++[AC_REQUIRE([LT_PROG_GCJ])dnl
++AC_LANG_SAVE
+ 
+-	case $host_cpu in
+-	hppa*64*|ia64*)
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-	  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++# Source file extension for Java test sources.
++ac_ext=java
+ 
+-	  # hardcode_minus_L: Not really in the search PATH,
+-	  # but as the default location of the library.
+-	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-	  ;;
+-	esac
+-      fi
+-      ;;
++# Object file extension for compiled Java test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-    irix5* | irix6* | nonstopux*)
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      ;;
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="class foo {}"
+ 
+-    netbsd*)
+-      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# Code to be used in simple link tests
++lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+ 
+-    newsos6)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
++
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
++
++# Allow CC to be a program name with arguments.
++lt_save_CC="$CC"
++lt_save_GCC=$GCC
++GCC=yes
++CC=${GCJ-"gcj"}
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_TAGVAR(LD, $1)="$LD"
++_LT_CC_BASENAME([$compiler])
+ 
+-    openbsd*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      else
+-       case $host_os in
+-	 openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+-	   _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+-	   _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-	   ;;
+-	 *)
+-	   _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+-	   _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	   ;;
+-       esac
+-      fi
+-      ;;
++# GCJ did not exist at the time GCC didn't implicitly link libc in.
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ 
+-    os2*)
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+-      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+-      ;;
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+ 
+-    osf3*)
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-      else
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      ;;
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++  _LT_COMPILER_NO_RTTI($1)
++  _LT_COMPILER_PIC($1)
++  _LT_COMPILER_C_O($1)
++  _LT_COMPILER_FILE_LOCKS($1)
++  _LT_LINKER_SHLIBS($1)
++  _LT_LINKER_HARDCODE_LIBPATH($1)
+ 
+-    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      else
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+-	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
++  _LT_CONFIG($1)
++fi
+ 
+-	# Both c and cxx compiler support -rpath directly
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      ;;
++AC_LANG_RESTORE
+ 
+-    solaris*)
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+-      if test "$GCC" = yes; then
+-	wlarc='${wl}'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+-      else
+-	wlarc=''
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      case $host_os in
+-      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+-      *)
+- 	# The compiler driver will combine linker options so we
+- 	# cannot just pass the convience library names through
+- 	# without $wl, iff we do not link with $LD.
+- 	# Luckily, gcc supports the same syntax we need for Sun Studio.
+- 	# Supported since Solaris 2.6 (maybe 2.5.1?)
+- 	case $wlarc in
+- 	'')
+- 	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+- 	*)
+- 	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+- 	esac ;;
+-      esac
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      ;;
++GCC=$lt_save_GCC
++CC="$lt_save_CC"
++])# _LT_LANG_GCJ_CONFIG
+ 
+-    sunos4*)
+-      if test "x$host_vendor" = xsequent; then
+-	# Use $CC to link under sequent, because it throws in some extra .o
+-	# files that make .init and .fini sections work.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
+ 
+-    sysv4)
+-      case $host_vendor in
+-	sni)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+-	;;
+-	siemens)
+-	  ## LD is ld it makes a PLAMLIB
+-	  ## CC just makes a GrossModule.
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+-	  _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-        ;;
+-	motorola)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+-	;;
+-      esac
+-      runpath_var='LD_RUN_PATH'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# _LT_LANG_RC_CONFIG([TAG])
++# -------------------------
++# Ensure that the configuration variables for the Windows resource compiler
++# are suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_RC_CONFIG],
++[AC_REQUIRE([LT_PROG_RC])dnl
++AC_LANG_SAVE
+ 
+-    sysv4.3*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+-      ;;
++# Source file extension for RC test sources.
++ac_ext=rc
+ 
+-    sysv4*MP*)
+-      if test -d /usr/nec; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-	runpath_var=LD_RUN_PATH
+-	hardcode_runpath_var=yes
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-      fi
+-      ;;
++# Object file extension for compiled RC test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*)
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      runpath_var='LD_RUN_PATH'
++# Code to be used in simple compile tests
++lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+ 
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      fi
+-      ;;
++# Code to be used in simple link tests
++lt_simple_link_test_code="$lt_simple_compile_test_code"
+ 
+-    sysv5* | sco3.2v5* | sco5v6*)
+-      # Note: We can NOT use -z defs as we might desire, because we do not
+-      # link with -lc, and that would cause any symbols used from libc to
+-      # always be unresolved, which means just about no library would
+-      # ever link correctly.  If we're not using GNU ld we use -z text
+-      # though, which does catch some bad symbols but isn't as heavy-handed
+-      # as -z defs.
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+-      runpath_var='LD_RUN_PATH'
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
+ 
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      fi
+-      ;;
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
+ 
+-    uts4*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# Allow CC to be a program name with arguments.
++lt_save_CC="$CC"
++lt_save_GCC=$GCC
++GCC=
++CC=${RC-"windres"}
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_CC_BASENAME([$compiler])
++_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ 
+-    *)
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
+-    esac
+-  fi
+-])
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+-test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
++if test -n "$compiler"; then
++  :
++  _LT_CONFIG($1)
++fi
+ 
+-#
+-# Do we need to explicitly link libc?
+-#
+-case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+-x|xyes)
+-  # Assume -lc should be added
+-  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
++GCC=$lt_save_GCC
++AC_LANG_RESTORE
++CC="$lt_save_CC"
++])# _LT_LANG_RC_CONFIG
+ 
+-  if test "$enable_shared" = yes && test "$GCC" = yes; then
+-    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+-    *'~'*)
+-      # FIXME: we may have to deal with multi-command sequences.
+-      ;;
+-    '$CC '*)
+-      # Test whether the compiler implicitly links with -lc since on some
+-      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+-      # to ld, don't add -lc before -lgcc.
+-      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+-      $rm conftest*
+-      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
+-      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+-        soname=conftest
+-        lib=conftest
+-        libobjs=conftest.$ac_objext
+-        deplibs=
+-        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+-	pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+-        compiler_flags=-v
+-        linker_flags=-v
+-        verstring=
+-        output_objdir=.
+-        libname=conftest
+-        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+-        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+-        then
+-	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-        else
+-	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-        fi
+-        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+-      else
+-        cat conftest.err 1>&5
+-      fi
+-      $rm conftest*
+-      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+-      ;;
+-    esac
+-  fi
+-  ;;
+-esac
+-])# AC_LIBTOOL_PROG_LD_SHLIBS
++# LT_PROG_GCJ
++# -----------
++AC_DEFUN([LT_PROG_GCJ],
++[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
++  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
++    [AC_CHECK_TOOL(GCJ, gcj,)
++      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
++      AC_SUBST(GCJFLAGS)])])[]dnl
++])
+ 
++# Old name:
++AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+ 
+-# _LT_AC_FILE_LTDLL_C
+-# -------------------
+-# Be careful that the start marker always follows a newline.
+-AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+-# /* ltdll.c starts here */
+-# #define WIN32_LEAN_AND_MEAN
+-# #include <windows.h>
+-# #undef WIN32_LEAN_AND_MEAN
+-# #include <stdio.h>
+-#
+-# #ifndef __CYGWIN__
+-# #  ifdef __CYGWIN32__
+-# #    define __CYGWIN__ __CYGWIN32__
+-# #  endif
+-# #endif
+-#
+-# #ifdef __cplusplus
+-# extern "C" {
+-# #endif
+-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+-# #ifdef __cplusplus
+-# }
+-# #endif
+-#
+-# #ifdef __CYGWIN__
+-# #include <cygwin/cygwin_dll.h>
+-# DECLARE_CYGWIN_DLL( DllMain );
+-# #endif
+-# HINSTANCE __hDllInstance_base;
+-#
+-# BOOL APIENTRY
+-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+-# {
+-#   __hDllInstance_base = hInst;
+-#   return TRUE;
+-# }
+-# /* ltdll.c ends here */
+-])# _LT_AC_FILE_LTDLL_C
+ 
++# LT_PROG_RC
++# ----------
++AC_DEFUN([LT_PROG_RC],
++[AC_CHECK_TOOL(RC, windres,)
++])
+ 
+-# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+-# ---------------------------------
+-AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
++# Old name:
++AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_RC], [])
+ 
+ 
+-# old names
+-AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
+-AC_DEFUN([AM_ENABLE_SHARED],  [AC_ENABLE_SHARED($@)])
+-AC_DEFUN([AM_ENABLE_STATIC],  [AC_ENABLE_STATIC($@)])
+-AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+-AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+-AC_DEFUN([AM_PROG_LD],        [AC_PROG_LD])
+-AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
+-
+-# This is just to silence aclocal about the macro not being used
+-ifelse([AC_DISABLE_FAST_INSTALL])
+-
+-AC_DEFUN([LT_AC_PROG_GCJ],
+-[AC_CHECK_TOOL(GCJ, gcj, no)
+-  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+-  AC_SUBST(GCJFLAGS)
++# _LT_DECL_EGREP
++# --------------
++# If we don't have a new enough Autoconf to choose the best grep
++# available, choose the one first in the user's PATH.
++m4_defun([_LT_DECL_EGREP],
++[AC_REQUIRE([AC_PROG_EGREP])dnl
++AC_REQUIRE([AC_PROG_FGREP])dnl
++test -z "$GREP" && GREP=grep
++_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
++_LT_DECL([], [EGREP], [1], [An ERE matcher])
++_LT_DECL([], [FGREP], [1], [A literal string matcher])
++dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
++AC_SUBST([GREP])
+ ])
+ 
+-AC_DEFUN([LT_AC_PROG_RC],
+-[AC_CHECK_TOOL(RC, windres, no)
+-])
+ 
++# _LT_DECL_SED
++# ------------
++# Check for a fully-functional sed program, that truncates
++# as few characters as possible.  Prefer GNU sed if found.
++m4_defun([_LT_DECL_SED],
++[AC_PROG_SED
++test -z "$SED" && SED=sed
++Xsed="$SED -e 1s/^X//"
++_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
++_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
++    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
++])# _LT_DECL_SED
++
++m4_ifndef([AC_PROG_SED], [
+ ############################################################
+ # NOTE: This macro has been submitted for inclusion into   #
+ #  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+ #  a released version of Autoconf we should remove this    #
+ #  macro and use it instead.                               #
+ ############################################################
+-# LT_AC_PROG_SED
+-# --------------
+-# Check for a fully-functional sed program, that truncates
+-# as few characters as possible.  Prefer GNU sed if found.
+-AC_DEFUN([LT_AC_PROG_SED],
++
++m4_defun([AC_PROG_SED],
+ [AC_MSG_CHECKING([for a sed that does not truncate output])
+ AC_CACHE_VAL(lt_cv_path_SED,
+ [# Loop through the user's path and test for sed and gsed.
+@@ -6435,6 +7010,7 @@ do
+     done
+   done
+ done
++IFS=$as_save_IFS
+ lt_ac_max=0
+ lt_ac_count=0
+ # Add /usr/xpg4/bin/sed as it is typically found on Solaris
+@@ -6467,5 +7043,268 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xp
+ done
+ ])
+ SED=$lt_cv_path_SED
++AC_SUBST([SED])
+ AC_MSG_RESULT([$SED])
++])#AC_PROG_SED
++])#m4_ifndef
++
++# Old name:
++AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_SED], [])
++
++
++# _LT_CHECK_SHELL_FEATURES
++# ------------------------
++# Find out whether the shell is Bourne or XSI compatible,
++# or has some other useful features.
++m4_defun([_LT_CHECK_SHELL_FEATURES],
++[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
++# Try some XSI features
++xsi_shell=no
++( _lt_dummy="a/b/c"
++  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
++      = c,a/b,, \
++    && eval 'test $(( 1 + 1 )) -eq 2 \
++    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
++  && xsi_shell=yes
++AC_MSG_RESULT([$xsi_shell])
++_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
++
++AC_MSG_CHECKING([whether the shell understands "+="])
++lt_shell_append=no
++( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
++    >/dev/null 2>&1 \
++  && lt_shell_append=yes
++AC_MSG_RESULT([$lt_shell_append])
++_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
++
++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
++  lt_unset=unset
++else
++  lt_unset=false
++fi
++_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
++
++# test EBCDIC or ASCII
++case `echo X|tr X '\101'` in
++ A) # ASCII based system
++    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
++  lt_SP2NL='tr \040 \012'
++  lt_NL2SP='tr \015\012 \040\040'
++  ;;
++ *) # EBCDIC based system
++  lt_SP2NL='tr \100 \n'
++  lt_NL2SP='tr \r\n \100\100'
++  ;;
++esac
++_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
++_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
++])# _LT_CHECK_SHELL_FEATURES
++
++
++# _LT_PROG_XSI_SHELLFNS
++# ---------------------
++# Bourne and XSI compatible variants of some useful shell functions.
++m4_defun([_LT_PROG_XSI_SHELLFNS],
++[case $xsi_shell in
++  yes)
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_dirname file append nondir_replacement
++# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
++# otherwise set result to NONDIR_REPLACEMENT.
++func_dirname ()
++{
++  case ${1} in
++    */*) func_dirname_result="${1%/*}${2}" ;;
++    *  ) func_dirname_result="${3}" ;;
++  esac
++}
++
++# func_basename file
++func_basename ()
++{
++  func_basename_result="${1##*/}"
++}
++
++# func_dirname_and_basename file append nondir_replacement
++# perform func_basename and func_dirname in a single function
++# call:
++#   dirname:  Compute the dirname of FILE.  If nonempty,
++#             add APPEND to the result, otherwise set result
++#             to NONDIR_REPLACEMENT.
++#             value returned in "$func_dirname_result"
++#   basename: Compute filename of FILE.
++#             value retuned in "$func_basename_result"
++# Implementation must be kept synchronized with func_dirname
++# and func_basename. For efficiency, we do not delegate to
++# those functions but instead duplicate the functionality here.
++func_dirname_and_basename ()
++{
++  case ${1} in
++    */*) func_dirname_result="${1%/*}${2}" ;;
++    *  ) func_dirname_result="${3}" ;;
++  esac
++  func_basename_result="${1##*/}"
++}
++
++# func_stripname prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++func_stripname ()
++{
++  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
++  # positional parameters, so assign one to ordinary parameter first.
++  func_stripname_result=${3}
++  func_stripname_result=${func_stripname_result#"${1}"}
++  func_stripname_result=${func_stripname_result%"${2}"}
++}
++
++# func_opt_split
++func_opt_split ()
++{
++  func_opt_split_opt=${1%%=*}
++  func_opt_split_arg=${1#*=}
++}
++
++# func_lo2o object
++func_lo2o ()
++{
++  case ${1} in
++    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
++    *)    func_lo2o_result=${1} ;;
++  esac
++}
++
++# func_xform libobj-or-source
++func_xform ()
++{
++  func_xform_result=${1%.*}.lo
++}
++
++# func_arith arithmetic-term...
++func_arith ()
++{
++  func_arith_result=$(( $[*] ))
++}
++
++# func_len string
++# STRING may not start with a hyphen.
++func_len ()
++{
++  func_len_result=${#1}
++}
++
++_LT_EOF
++    ;;
++  *) # Bourne compatible functions.
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_dirname file append nondir_replacement
++# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
++# otherwise set result to NONDIR_REPLACEMENT.
++func_dirname ()
++{
++  # Extract subdirectory from the argument.
++  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
++  if test "X$func_dirname_result" = "X${1}"; then
++    func_dirname_result="${3}"
++  else
++    func_dirname_result="$func_dirname_result${2}"
++  fi
++}
++
++# func_basename file
++func_basename ()
++{
++  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
++}
++
++dnl func_dirname_and_basename
++dnl A portable version of this function is already defined in general.m4sh
++dnl so there is no need for it here.
++
++# func_stripname prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++# func_strip_suffix prefix name
++func_stripname ()
++{
++  case ${2} in
++    .*) func_stripname_result=`$ECHO "X${3}" \
++           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
++    *)  func_stripname_result=`$ECHO "X${3}" \
++           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
++  esac
++}
++
++# sed scripts:
++my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
++my_sed_long_arg='1s/^-[[^=]]*=//'
++
++# func_opt_split
++func_opt_split ()
++{
++  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
++  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
++}
++
++# func_lo2o object
++func_lo2o ()
++{
++  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
++}
++
++# func_xform libobj-or-source
++func_xform ()
++{
++  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'`
++}
++
++# func_arith arithmetic-term...
++func_arith ()
++{
++  func_arith_result=`expr "$[@]"`
++}
++
++# func_len string
++# STRING may not start with a hyphen.
++func_len ()
++{
++  func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
++}
++
++_LT_EOF
++esac
++
++case $lt_shell_append in
++  yes)
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_append var value
++# Append VALUE to the end of shell variable VAR.
++func_append ()
++{
++  eval "$[1]+=\$[2]"
++}
++_LT_EOF
++    ;;
++  *)
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_append var value
++# Append VALUE to the end of shell variable VAR.
++func_append ()
++{
++  eval "$[1]=\$$[1]\$[2]"
++}
++
++_LT_EOF
++    ;;
++  esac
+ ])
+--- a/m4/libtool.m4
++++ b/m4/libtool.m4
+@@ -1,107 +1,186 @@
+ # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+-## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
+-## Free Software Foundation, Inc.
+-## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+-##
+-## This file is free software; the Free Software Foundation gives
+-## unlimited permission to copy and/or distribute it, with or without
+-## modifications, as long as this notice is preserved.
+-
+-# serial 48 AC_PROG_LIBTOOL
+-
+-
+-# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+-# -----------------------------------------------------------
+-# If this macro is not defined by Autoconf, define it here.
+-m4_ifdef([AC_PROVIDE_IFELSE],
+-         [],
+-         [m4_define([AC_PROVIDE_IFELSE],
+-	         [m4_ifdef([AC_PROVIDE_$1],
+-		           [$2], [$3])])])
++#
++#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++#                 2006, 2007, 2008 Free Software Foundation, Inc.
++#   Written by Gordon Matzigkeit, 1996
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++m4_define([_LT_COPYING], [dnl
++#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++#                 2006, 2007, 2008 Free Software Foundation, Inc.
++#   Written by Gordon Matzigkeit, 1996
++#
++#   This file is part of GNU Libtool.
++#
++# GNU Libtool is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# As a special exception to the GNU General Public License,
++# if you distribute this file as part of a program or library that
++# is built using GNU Libtool, you may include this file under the
++# same distribution terms that you use for the rest of that program.
++#
++# GNU Libtool is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GNU Libtool; see the file COPYING.  If not, a copy
++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
++# obtained by writing to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++])
+ 
++# serial 56 LT_INIT
+ 
+-# AC_PROG_LIBTOOL
+-# ---------------
+-AC_DEFUN([AC_PROG_LIBTOOL],
+-[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+-dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+-dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+-  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+-    [AC_LIBTOOL_CXX],
+-    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+-  ])])
+-dnl And a similar setup for Fortran 77 support
+-  AC_PROVIDE_IFELSE([AC_PROG_F77],
+-    [AC_LIBTOOL_F77],
+-    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+-])])
+-
+-dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+-dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+-dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+-  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+-    [AC_LIBTOOL_GCJ],
+-    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+-      [AC_LIBTOOL_GCJ],
+-      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+-	[AC_LIBTOOL_GCJ],
+-      [ifdef([AC_PROG_GCJ],
+-	     [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+-       ifdef([A][M_PROG_GCJ],
+-	     [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+-       ifdef([LT_AC_PROG_GCJ],
+-	     [define([LT_AC_PROG_GCJ],
+-		defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+-])])# AC_PROG_LIBTOOL
+ 
++# LT_PREREQ(VERSION)
++# ------------------
++# Complain and exit if this libtool version is less that VERSION.
++m4_defun([LT_PREREQ],
++[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
++       [m4_default([$3],
++		   [m4_fatal([Libtool version $1 or higher is required],
++		             63)])],
++       [$2])])
+ 
+-# _AC_PROG_LIBTOOL
+-# ----------------
+-AC_DEFUN([_AC_PROG_LIBTOOL],
+-[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+-AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+-AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+-AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
++
++# _LT_CHECK_BUILDDIR
++# ------------------
++# Complain if the absolute build directory name contains unusual characters
++m4_defun([_LT_CHECK_BUILDDIR],
++[case `pwd` in
++  *\ * | *\	*)
++    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
++esac
++])
++
++
++# LT_INIT([OPTIONS])
++# ------------------
++AC_DEFUN([LT_INIT],
++[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
++AC_BEFORE([$0], [LT_LANG])dnl
++AC_BEFORE([$0], [LT_OUTPUT])dnl
++AC_BEFORE([$0], [LTDL_INIT])dnl
++m4_require([_LT_CHECK_BUILDDIR])dnl
++
++dnl Autoconf doesn't catch unexpanded LT_ macros by default:
++m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
++m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
++dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
++dnl unless we require an AC_DEFUNed macro:
++AC_REQUIRE([LTOPTIONS_VERSION])dnl
++AC_REQUIRE([LTSUGAR_VERSION])dnl
++AC_REQUIRE([LTVERSION_VERSION])dnl
++AC_REQUIRE([LTOBSOLETE_VERSION])dnl
++m4_require([_LT_PROG_LTMAIN])dnl
++
++dnl Parse OPTIONS
++_LT_SET_OPTIONS([$0], [$1])
+ 
+ # This can be used to rebuild libtool when needed
+-LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
++LIBTOOL_DEPS="$ltmain"
+ 
+ # Always use our own libtool.
+-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
++LIBTOOL='$(SHELL) $(top_builddir)'
++LIBTOOL="$LIBTOOL/$host_alias-libtool"
+ AC_SUBST(LIBTOOL)dnl
+ 
+-# Prevent multiple expansion
+-define([AC_PROG_LIBTOOL], [])
+-])# _AC_PROG_LIBTOOL
++_LT_SETUP
+ 
++# Only expand once:
++m4_define([LT_INIT])
++])# LT_INIT
++
++# Old names:
++AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
++AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
++dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+ 
+-# AC_LIBTOOL_SETUP
+-# ----------------
+-AC_DEFUN([AC_LIBTOOL_SETUP],
+-[AC_PREREQ(2.50)dnl
+-AC_REQUIRE([AC_ENABLE_SHARED])dnl
+-AC_REQUIRE([AC_ENABLE_STATIC])dnl
+-AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+-AC_REQUIRE([AC_CANONICAL_HOST])dnl
++
++# _LT_CC_BASENAME(CC)
++# -------------------
++# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
++m4_defun([_LT_CC_BASENAME],
++[for cc_temp in $1""; do
++  case $cc_temp in
++    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
++    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
++    \-*) ;;
++    *) break;;
++  esac
++done
++cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
++])
++
++
++# _LT_FILEUTILS_DEFAULTS
++# ----------------------
++# It is okay to use these file commands and assume they have been set
++# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
++m4_defun([_LT_FILEUTILS_DEFAULTS],
++[: ${CP="cp -f"}
++: ${MV="mv -f"}
++: ${RM="rm -f"}
++])# _LT_FILEUTILS_DEFAULTS
++
++
++# _LT_SETUP
++# ---------
++m4_defun([_LT_SETUP],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+ AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++_LT_DECL([], [host_alias], [0], [The host system])dnl
++_LT_DECL([], [host], [0])dnl
++_LT_DECL([], [host_os], [0])dnl
++dnl
++_LT_DECL([], [build_alias], [0], [The build system])dnl
++_LT_DECL([], [build], [0])dnl
++_LT_DECL([], [build_os], [0])dnl
++dnl
+ AC_REQUIRE([AC_PROG_CC])dnl
+-AC_REQUIRE([AC_PROG_LD])dnl
+-AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+-AC_REQUIRE([AC_PROG_NM])dnl
+-
++AC_REQUIRE([LT_PATH_LD])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++dnl
+ AC_REQUIRE([AC_PROG_LN_S])dnl
+-AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+-# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+-AC_REQUIRE([AC_OBJEXT])dnl
+-AC_REQUIRE([AC_EXEEXT])dnl
++test -z "$LN_S" && LN_S="ln -s"
++_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+ dnl
++AC_REQUIRE([LT_CMD_MAX_LEN])dnl
++_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
++_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
++dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_CHECK_SHELL_FEATURES])dnl
++m4_require([_LT_CMD_RELOAD])dnl
++m4_require([_LT_CHECK_MAGIC_METHOD])dnl
++m4_require([_LT_CMD_OLD_ARCHIVE])dnl
++m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
++
++_LT_CONFIG_LIBTOOL_INIT([
++# See if we are running on zsh, and set the options which allow our
++# commands through without removal of \ escapes INIT.
++if test -n "\${ZSH_VERSION+set}" ; then
++   setopt NO_GLOB_SUBST
++fi
++])
++if test -n "${ZSH_VERSION+set}" ; then
++   setopt NO_GLOB_SUBST
++fi
+ 
+-AC_LIBTOOL_SYS_MAX_CMD_LEN
+-AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+-AC_LIBTOOL_OBJDIR
++_LT_CHECK_OBJDIR
+ 
+-AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+-_LT_AC_PROG_ECHO_BACKSLASH
++m4_require([_LT_TAG_COMPILER])dnl
++_LT_PROG_ECHO_BACKSLASH
+ 
+ case $host_os in
+ aix3*)
+@@ -117,6307 +196,6803 @@ esac
+ 
+ # Sed substitution that helps us do robust quoting.  It backslashifies
+ # metacharacters that are still active within double-quoted strings.
+-Xsed='sed -e 1s/^X//'
+-[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
++sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+ 
+ # Same as above, but do not quote variable references.
+-[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
++double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+ 
+ # Sed substitution to delay expansion of an escaped shell variable in a
+ # double_quote_subst'ed string.
+ delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+ 
++# Sed substitution to delay expansion of an escaped single quote.
++delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
++
+ # Sed substitution to avoid accidental globbing in evaled expressions
+ no_glob_subst='s/\*/\\\*/g'
+ 
+-# Constants:
+-rm="rm -f"
+-
+ # Global variables:
+-default_ofile=libtool
++ofile=${host_alias}-libtool
+ can_build_shared=yes
+ 
+ # All known linkers require a `.a' archive for static linking (except MSVC,
+ # which needs '.lib').
+ libext=a
+-ltmain="$ac_aux_dir/ltmain.sh"
+-ofile="$default_ofile"
+-with_gnu_ld="$lt_cv_prog_gnu_ld"
+ 
+-AC_CHECK_TOOL(AR, ar, false)
+-AC_CHECK_TOOL(RANLIB, ranlib, :)
+-AC_CHECK_TOOL(STRIP, strip, :)
++with_gnu_ld="$lt_cv_prog_gnu_ld"
+ 
+ old_CC="$CC"
+ old_CFLAGS="$CFLAGS"
+ 
+ # Set sane defaults for various variables
+-test -z "$AR" && AR=ar
+-test -z "$AR_FLAGS" && AR_FLAGS=cru
+-test -z "$AS" && AS=as
+ test -z "$CC" && CC=cc
+ test -z "$LTCC" && LTCC=$CC
+ test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+-test -z "$DLLTOOL" && DLLTOOL=dlltool
+ test -z "$LD" && LD=ld
+-test -z "$LN_S" && LN_S="ln -s"
+-test -z "$MAGIC_CMD" && MAGIC_CMD=file
+-test -z "$NM" && NM=nm
+-test -z "$SED" && SED=sed
+-test -z "$OBJDUMP" && OBJDUMP=objdump
+-test -z "$RANLIB" && RANLIB=:
+-test -z "$STRIP" && STRIP=:
+ test -z "$ac_objext" && ac_objext=o
+ 
+-# Determine commands to create old-style static archives.
+-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+-old_postinstall_cmds='chmod 644 $oldlib'
+-old_postuninstall_cmds=
+-
+-if test -n "$RANLIB"; then
+-  case $host_os in
+-  openbsd*)
+-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+-    ;;
+-  *)
+-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+-    ;;
+-  esac
+-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+-fi
+-
+ _LT_CC_BASENAME([$compiler])
+ 
+ # Only perform the check for file, if the check method requires it
++test -z "$MAGIC_CMD" && MAGIC_CMD=file
+ case $deplibs_check_method in
+ file_magic*)
+   if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+-    AC_PATH_MAGIC
++    _LT_PATH_MAGIC
+   fi
+   ;;
+ esac
+ 
+-AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+-AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+-enable_win32_dll=yes, enable_win32_dll=no)
+-
+-AC_ARG_ENABLE([libtool-lock],
+-    [AC_HELP_STRING([--disable-libtool-lock],
+-	[avoid locking (might break parallel builds)])])
+-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++# Use C for the default configuration in the libtool script
++LT_SUPPORTED_TAG([CC])
++_LT_LANG_C_CONFIG
++_LT_LANG_DEFAULT_CONFIG
++_LT_CONFIG_COMMANDS
++])# _LT_SETUP
+ 
+-AC_ARG_WITH([pic],
+-    [AC_HELP_STRING([--with-pic],
+-	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+-    [pic_mode="$withval"],
+-    [pic_mode=default])
+-test -z "$pic_mode" && pic_mode=default
+ 
+-# Use C for the default configuration in the libtool script
+-tagname=
+-AC_LIBTOOL_LANG_C_CONFIG
+-_LT_AC_TAGCONFIG
+-])# AC_LIBTOOL_SETUP
++# _LT_PROG_LTMAIN
++# ---------------
++# Note that this code is called both from `configure', and `config.status'
++# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
++# `config.status' has no value for ac_aux_dir unless we are using Automake,
++# so we pass a copy along to make sure it has a sensible value anyway.
++m4_defun([_LT_PROG_LTMAIN],
++[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
++_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
++ltmain="$ac_aux_dir/ltmain.sh"
++])# _LT_PROG_LTMAIN
+ 
+ 
+-# _LT_AC_SYS_COMPILER
+-# -------------------
+-AC_DEFUN([_LT_AC_SYS_COMPILER],
+-[AC_REQUIRE([AC_PROG_CC])dnl
++## ------------------------------------- ##
++## Accumulate code for creating libtool. ##
++## ------------------------------------- ##
++
++# So that we can recreate a full libtool script including additional
++# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
++# in macros and then make a single call at the end using the `libtool'
++# label.
++
++
++# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
++# ----------------------------------------
++# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
++m4_define([_LT_CONFIG_LIBTOOL_INIT],
++[m4_ifval([$1],
++          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
++                     [$1
++])])])
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_INIT])
++
++
++# _LT_CONFIG_LIBTOOL([COMMANDS])
++# ------------------------------
++# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
++m4_define([_LT_CONFIG_LIBTOOL],
++[m4_ifval([$1],
++          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
++                     [$1
++])])])
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
++
++
++# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
++# -----------------------------------------------------
++m4_defun([_LT_CONFIG_SAVE_COMMANDS],
++[_LT_CONFIG_LIBTOOL([$1])
++_LT_CONFIG_LIBTOOL_INIT([$2])
++])
+ 
+-# If no C compiler was specified, use CC.
+-LTCC=${LTCC-"$CC"}
+ 
+-# If no C compiler flags were specified, use CFLAGS.
+-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
++# _LT_FORMAT_COMMENT([COMMENT])
++# -----------------------------
++# Add leading comment marks to the start of each line, and a trailing
++# full-stop to the whole comment if one is not present already.
++m4_define([_LT_FORMAT_COMMENT],
++[m4_ifval([$1], [
++m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
++              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
++)])
+ 
+-# Allow CC to be a program name with arguments.
+-compiler=$CC
+-])# _LT_AC_SYS_COMPILER
+ 
+ 
+-# _LT_CC_BASENAME(CC)
+-# -------------------
+-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+-AC_DEFUN([_LT_CC_BASENAME],
+-[for cc_temp in $1""; do
+-  case $cc_temp in
+-    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+-    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+-    \-*) ;;
+-    *) break;;
+-  esac
+-done
+-cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
++## ------------------------ ##
++## FIXME: Eliminate VARNAME ##
++## ------------------------ ##
++
++
++# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
++# -------------------------------------------------------------------
++# CONFIGNAME is the name given to the value in the libtool script.
++# VARNAME is the (base) name used in the configure script.
++# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
++# VARNAME.  Any other value will be used directly.
++m4_define([_LT_DECL],
++[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
++    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
++	[m4_ifval([$1], [$1], [$2])])
++    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
++    m4_ifval([$4],
++	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
++    lt_dict_add_subkey([lt_decl_dict], [$2],
++	[tagged?], [m4_ifval([$5], [yes], [no])])])
+ ])
+ 
+ 
+-# _LT_COMPILER_BOILERPLATE
+-# ------------------------
+-# Check for compiler boilerplate output or warnings with
+-# the simple compiler test code.
+-AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+-[ac_outfile=conftest.$ac_objext
+-printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+-_lt_compiler_boilerplate=`cat conftest.err`
+-$rm conftest*
+-])# _LT_COMPILER_BOILERPLATE
+-
++# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
++# --------------------------------------------------------
++m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
++
++
++# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
++# ------------------------------------------------
++m4_define([lt_decl_tag_varnames],
++[_lt_decl_filter([tagged?], [yes], $@)])
++
++
++# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
++# ---------------------------------------------------------
++m4_define([_lt_decl_filter],
++[m4_case([$#],
++  [0], [m4_fatal([$0: too few arguments: $#])],
++  [1], [m4_fatal([$0: too few arguments: $#: $1])],
++  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
++  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
++  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
++])
+ 
+-# _LT_LINKER_BOILERPLATE
+-# ----------------------
+-# Check for linker boilerplate output or warnings with
+-# the simple link test code.
+-AC_DEFUN([_LT_LINKER_BOILERPLATE],
+-[ac_outfile=conftest.$ac_objext
+-printf "$lt_simple_link_test_code" >conftest.$ac_ext
+-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+-_lt_linker_boilerplate=`cat conftest.err`
+-$rm conftest*
+-])# _LT_LINKER_BOILERPLATE
+ 
++# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
++# --------------------------------------------------
++m4_define([lt_decl_quote_varnames],
++[_lt_decl_filter([value], [1], $@)])
++
++
++# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
++# ---------------------------------------------------
++m4_define([lt_decl_dquote_varnames],
++[_lt_decl_filter([value], [2], $@)])
++
++
++# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
++# ---------------------------------------------------
++m4_define([lt_decl_varnames_tagged],
++[_$0(m4_quote(m4_default([$1], [[, ]])),
++     m4_quote(m4_if([$2], [],
++		     m4_quote(lt_decl_tag_varnames),
++		  m4_quote(m4_shift($@)))),
++     m4_split(m4_normalize(m4_quote(_LT_TAGS))))])
++m4_define([_lt_decl_varnames_tagged], [lt_combine([$1], [$2], [_], $3)])
++
++
++# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
++# ------------------------------------------------
++m4_define([lt_decl_all_varnames],
++[_$0(m4_quote(m4_default([$1], [[, ]])),
++     m4_if([$2], [],
++	   m4_quote(lt_decl_varnames),
++	m4_quote(m4_shift($@))))[]dnl
++])
++m4_define([_lt_decl_all_varnames],
++[lt_join($@, lt_decl_varnames_tagged([$1],
++			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
++])
+ 
+-# _LT_AC_SYS_LIBPATH_AIX
+-# ----------------------
+-# Links a minimal program and checks the executable
+-# for the system default hardcoded library path. In most cases,
+-# this is /usr/lib:/lib, but when the MPI compilers are used
+-# the location of the communication and MPI libs are included too.
+-# If we don't find anything, use the default library path according
+-# to the aix ld manual.
+-AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+-[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+-aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+-}'`
+-# Check for a 64-bit object if we didn't find anything.
+-if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+-}'`; fi],[])
+-if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+-])# _LT_AC_SYS_LIBPATH_AIX
+ 
++# _LT_CONFIG_STATUS_DECLARE([VARNAME])
++# ------------------------------------
++# Quote a variable value, and forward it to `config.status' so that its
++# declaration there will have the same value as in `configure'.  VARNAME
++# must have a single quote delimited value for this to work.
++m4_define([_LT_CONFIG_STATUS_DECLARE],
++[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`'])
+ 
+-# _LT_AC_SHELL_INIT(ARG)
+-# ----------------------
+-AC_DEFUN([_LT_AC_SHELL_INIT],
+-[ifdef([AC_DIVERSION_NOTICE],
+-	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+-	 [AC_DIVERT_PUSH(NOTICE)])
+-$1
+-AC_DIVERT_POP
+-])# _LT_AC_SHELL_INIT
+ 
++# _LT_CONFIG_STATUS_DECLARATIONS
++# ------------------------------
++# We delimit libtool config variables with single quotes, so when
++# we write them to config.status, we have to be sure to quote all
++# embedded single quotes properly.  In configure, this macro expands
++# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
++#
++#    <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`'
++m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
++[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
++    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+ 
+-# _LT_AC_PROG_ECHO_BACKSLASH
+-# --------------------------
+-# Add some code to the start of the generated configure script which
+-# will find an echo command which doesn't interpret backslashes.
+-AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+-[_LT_AC_SHELL_INIT([
+-# Check that we are running under the correct shell.
+-SHELL=${CONFIG_SHELL-/bin/sh}
+ 
+-case X$ECHO in
+-X*--fallback-echo)
+-  # Remove one level of quotation (which was required for Make).
+-  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+-  ;;
+-esac
++# _LT_LIBTOOL_TAGS
++# ----------------
++# Output comment and list of tags supported by the script
++m4_defun([_LT_LIBTOOL_TAGS],
++[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
++available_tags="_LT_TAGS"dnl
++])
+ 
+-echo=${ECHO-echo}
+-if test "X[$]1" = X--no-reexec; then
+-  # Discard the --no-reexec flag, and continue.
+-  shift
+-elif test "X[$]1" = X--fallback-echo; then
+-  # Avoid inline document here, it may be left over
+-  :
+-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+-  # Yippee, $echo works!
+-  :
+-else
+-  # Restart under the correct shell.
+-  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+-fi
+ 
+-if test "X[$]1" = X--fallback-echo; then
+-  # used as fallback echo
+-  shift
+-  cat <<EOF
+-[$]*
+-EOF
+-  exit 0
+-fi
++# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
++# -----------------------------------
++# Extract the dictionary values for VARNAME (optionally with TAG) and
++# expand to a commented shell variable setting:
++#
++#    # Some comment about what VAR is for.
++#    visible_name=$lt_internal_name
++m4_define([_LT_LIBTOOL_DECLARE],
++[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
++					   [description])))[]dnl
++m4_pushdef([_libtool_name],
++    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
++m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
++    [0], [_libtool_name=[$]$1],
++    [1], [_libtool_name=$lt_[]$1],
++    [2], [_libtool_name=$lt_[]$1],
++    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
++m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
++])
+ 
+-# The HP-UX ksh and POSIX shell print the target directory to stdout
+-# if CDPATH is set.
+-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+ 
+-if test -z "$ECHO"; then
+-if test "X${echo_test_string+set}" != Xset; then
+-# find a string as large as possible, as long as the shell can cope with it
+-  for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+-    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+-    if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+-       echo_test_string=`eval $cmd` &&
+-       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+-    then
+-      break
+-    fi
+-  done
+-fi
++# _LT_LIBTOOL_CONFIG_VARS
++# -----------------------
++# Produce commented declarations of non-tagged libtool config variables
++# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
++# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
++# section) are produced by _LT_LIBTOOL_TAG_VARS.
++m4_defun([_LT_LIBTOOL_CONFIG_VARS],
++[m4_foreach([_lt_var],
++    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
++    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+ 
+-if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+-   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+-   test "X$echo_testing_string" = "X$echo_test_string"; then
+-  :
+-else
+-  # The Solaris, AIX, and Digital Unix default echo programs unquote
+-  # backslashes.  This makes it impossible to quote backslashes using
+-  #   echo "$something" | sed 's/\\/\\\\/g'
+-  #
+-  # So, first we look for a working echo in the user's PATH.
+ 
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-  for dir in $PATH /usr/ucb; do
+-    IFS="$lt_save_ifs"
+-    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+-       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+-       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+-       test "X$echo_testing_string" = "X$echo_test_string"; then
+-      echo="$dir/echo"
+-      break
+-    fi
+-  done
+-  IFS="$lt_save_ifs"
++# _LT_LIBTOOL_TAG_VARS(TAG)
++# -------------------------
++m4_define([_LT_LIBTOOL_TAG_VARS],
++[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
++    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+ 
+-  if test "X$echo" = Xecho; then
+-    # We didn't find a better echo, so look for alternatives.
+-    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+-       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+-       test "X$echo_testing_string" = "X$echo_test_string"; then
+-      # This shell has a builtin print -r that does the trick.
+-      echo='print -r'
+-    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+-	 test "X$CONFIG_SHELL" != X/bin/ksh; then
+-      # If we have ksh, try running configure again with it.
+-      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+-      export ORIGINAL_CONFIG_SHELL
+-      CONFIG_SHELL=/bin/ksh
+-      export CONFIG_SHELL
+-      exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+-    else
+-      # Try using printf.
+-      echo='printf %s\n'
+-      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+-	 echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+-	 test "X$echo_testing_string" = "X$echo_test_string"; then
+-	# Cool, printf works
+-	:
+-      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+-	   test "X$echo_testing_string" = 'X\t' &&
+-	   echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+-	   test "X$echo_testing_string" = "X$echo_test_string"; then
+-	CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+-	export CONFIG_SHELL
+-	SHELL="$CONFIG_SHELL"
+-	export SHELL
+-	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+-      elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+-	   test "X$echo_testing_string" = 'X\t' &&
+-	   echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+-	   test "X$echo_testing_string" = "X$echo_test_string"; then
+-	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+-      else
+-	# maybe with a smaller string...
+-	prev=:
+ 
+-	for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+-	  if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+-	  then
+-	    break
+-	  fi
+-	  prev="$cmd"
+-	done
++# _LT_TAGVAR(VARNAME, [TAGNAME])
++# ------------------------------
++m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+ 
+-	if test "$prev" != 'sed 50q "[$]0"'; then
+-	  echo_test_string=`eval $prev`
+-	  export echo_test_string
+-	  exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+-	else
+-	  # Oops.  We lost completely, so just stick with echo.
+-	  echo=echo
+-	fi
+-      fi
+-    fi
+-  fi
+-fi
+-fi
+ 
+-# Copy echo and quote the copy suitably for passing to libtool from
+-# the Makefile, instead of quoting the original, which is used later.
+-ECHO=$echo
+-if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+-   ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+-fi
++# _LT_CONFIG_COMMANDS
++# -------------------
++# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
++# variables for single and double quote escaping we saved from calls
++# to _LT_DECL, we can put quote escaped variables declarations
++# into `config.status', and then the shell code to quote escape them in
++# for loops in `config.status'.  Finally, any additional code accumulated
++# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
++m4_defun([_LT_CONFIG_COMMANDS],
++[AC_PROVIDE_IFELSE([LT_OUTPUT],
++	dnl If the libtool generation code has been placed in $CONFIG_LT,
++	dnl instead of duplicating it all over again into config.status,
++	dnl then we will have config.status run $CONFIG_LT later, so it
++	dnl needs to know what name is stored there:
++        [AC_CONFIG_COMMANDS([libtool],
++            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
++    dnl If the libtool generation code is destined for config.status,
++    dnl expand the accumulated commands and init code now:
++    [AC_CONFIG_COMMANDS([libtool],
++        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
++])#_LT_CONFIG_COMMANDS
+ 
+-AC_SUBST(ECHO)
+-])])# _LT_AC_PROG_ECHO_BACKSLASH
+ 
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
++[
+ 
+-# _LT_AC_LOCK
+-# -----------
+-AC_DEFUN([_LT_AC_LOCK],
+-[AC_ARG_ENABLE([libtool-lock],
+-    [AC_HELP_STRING([--disable-libtool-lock],
+-	[avoid locking (might break parallel builds)])])
+-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+ 
+-# Some flags need to be propagated to the compiler or linker for good
+-# libtool support.
+-case $host in
+-ia64-*-hpux*)
+-  # Find out which ABI we are using.
+-  echo 'int i;' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-    case `/usr/bin/file conftest.$ac_objext` in
+-    *ELF-32*)
+-      HPUX_IA64_MODE="32"
+-      ;;
+-    *ELF-64*)
+-      HPUX_IA64_MODE="64"
+-      ;;
+-    esac
+-  fi
+-  rm -rf conftest*
+-  ;;
+-*-*-irix6*)
+-  # Find out which ABI we are using.
+-  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-   if test "$lt_cv_prog_gnu_ld" = yes; then
+-    case `/usr/bin/file conftest.$ac_objext` in
+-    *32-bit*)
+-      LD="${LD-ld} -melf32bsmip"
+-      ;;
+-    *N32*)
+-      LD="${LD-ld} -melf32bmipn32"
++sed_quote_subst='$sed_quote_subst'
++double_quote_subst='$double_quote_subst'
++delay_variable_subst='$delay_variable_subst'
++_LT_CONFIG_STATUS_DECLARATIONS
++LTCC='$LTCC'
++LTCFLAGS='$LTCFLAGS'
++compiler='$compiler_DEFAULT'
++
++# Quote evaled strings.
++for var in lt_decl_all_varnames([[ \
++]], lt_decl_quote_varnames); do
++    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
++    *[[\\\\\\\`\\"\\\$]]*)
++      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+       ;;
+-    *64-bit*)
+-      LD="${LD-ld} -melf64bmip"
++    *)
++      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+       ;;
+     esac
+-   else
+-    case `/usr/bin/file conftest.$ac_objext` in
+-    *32-bit*)
+-      LD="${LD-ld} -32"
+-      ;;
+-    *N32*)
+-      LD="${LD-ld} -n32"
++done
++
++# Double-quote double-evaled strings.
++for var in lt_decl_all_varnames([[ \
++]], lt_decl_dquote_varnames); do
++    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
++    *[[\\\\\\\`\\"\\\$]]*)
++      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+       ;;
+-    *64-bit*)
+-      LD="${LD-ld} -64"
++    *)
++      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+       ;;
+     esac
+-   fi
+-  fi
+-  rm -rf conftest*
++done
++
++# Fix-up fallback echo if it was mangled by the above quoting rules.
++case \$lt_ECHO in
++*'\\\[$]0 --fallback-echo"')dnl "
++  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\`
+   ;;
++esac
+ 
+-x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+-  # Find out which ABI we are using.
+-  echo 'int i;' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-    case `/usr/bin/file conftest.o` in
+-    *32-bit*)
+-      case $host in
+-        x86_64-*linux*)
+-          LD="${LD-ld} -m elf_i386"
+-          ;;
+-        ppc64-*linux*|powerpc64-*linux*)
+-          LD="${LD-ld} -m elf32ppclinux"
+-          ;;
+-        s390x-*linux*)
+-          LD="${LD-ld} -m elf_s390"
+-          ;;
+-        sparc64-*linux*)
+-          LD="${LD-ld} -m elf32_sparc"
+-          ;;
+-      esac
+-      ;;
+-    *64-bit*)
+-      case $host in
+-        x86_64-*linux*)
+-          LD="${LD-ld} -m elf_x86_64"
+-          ;;
+-        ppc*-*linux*|powerpc*-*linux*)
+-          LD="${LD-ld} -m elf64ppc"
+-          ;;
+-        s390*-*linux*)
+-          LD="${LD-ld} -m elf64_s390"
+-          ;;
+-        sparc*-*linux*)
+-          LD="${LD-ld} -m elf64_sparc"
+-          ;;
+-      esac
+-      ;;
+-    esac
+-  fi
+-  rm -rf conftest*
+-  ;;
++_LT_OUTPUT_LIBTOOL_INIT
++])
+ 
+-*-*-sco3.2v5*)
+-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+-  SAVE_CFLAGS="$CFLAGS"
+-  CFLAGS="$CFLAGS -belf"
+-  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+-    [AC_LANG_PUSH(C)
+-     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+-     AC_LANG_POP])
+-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+-    CFLAGS="$SAVE_CFLAGS"
+-  fi
+-  ;;
+-sparc*-*solaris*)
+-  # Find out which ABI we are using.
+-  echo 'int i;' > conftest.$ac_ext
+-  if AC_TRY_EVAL(ac_compile); then
+-    case `/usr/bin/file conftest.o` in
+-    *64-bit*)
+-      case $lt_cv_prog_gnu_ld in
+-      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+-      *)    LD="${LD-ld} -64" ;;
+-      esac
+-      ;;
+-    esac
+-  fi
+-  rm -rf conftest*
+-  ;;
+ 
+-AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+-[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+-  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+-  AC_CHECK_TOOL(AS, as, false)
+-  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+-  ;;
+-  ])
+-esac
++# LT_OUTPUT
++# ---------
++# This macro allows early generation of the libtool script (before
++# AC_OUTPUT is called), incase it is used in configure for compilation
++# tests.
++AC_DEFUN([LT_OUTPUT],
++[: ${CONFIG_LT=./config.lt}
++AC_MSG_NOTICE([creating $CONFIG_LT])
++cat >"$CONFIG_LT" <<_LTEOF
++#! $SHELL
++# Generated by $as_me.
++# Run this file to recreate a libtool stub with the current configuration.
++
++lt_cl_silent=false
++SHELL=\${CONFIG_SHELL-$SHELL}
++_LTEOF
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++AS_SHELL_SANITIZE
++_AS_PREPARE
+ 
+-need_locks="$enable_libtool_lock"
++exec AS_MESSAGE_FD>&1
++exec AS_MESSAGE_LOG_FD>>config.log
++{
++  echo
++  AS_BOX([Running $as_me.])
++} >&AS_MESSAGE_LOG_FD
++
++lt_cl_help="\
++\`$as_me' creates a local libtool stub from the current configuration,
++for use in further configure time tests before the real libtool is
++generated.
++
++Usage: $[0] [[OPTIONS]]
++
++  -h, --help      print this help, then exit
++  -V, --version   print version number, then exit
++  -q, --quiet     do not print progress messages
++  -d, --debug     don't remove temporary files
++
++Report bugs to <bug-libtool@gnu.org>."
++
++lt_cl_version="\
++m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
++m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
++configured by $[0], generated by m4_PACKAGE_STRING.
++
++Copyright (C) 2008 Free Software Foundation, Inc.
++This config.lt script is free software; the Free Software Foundation
++gives unlimited permision to copy, distribute and modify it."
+ 
+-])# _LT_AC_LOCK
++while test $[#] != 0
++do
++  case $[1] in
++    --version | --v* | -V )
++      echo "$lt_cl_version"; exit 0 ;;
++    --help | --h* | -h )
++      echo "$lt_cl_help"; exit 0 ;;
++    --debug | --d* | -d )
++      debug=: ;;
++    --quiet | --q* | --silent | --s* | -q )
++      lt_cl_silent=: ;;
+ 
++    -*) AC_MSG_ERROR([unrecognized option: $[1]
++Try \`$[0] --help' for more information.]) ;;
+ 
+-# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+-#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+-# ----------------------------------------------------------------
+-# Check whether the given compiler option works
+-AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+-[AC_REQUIRE([LT_AC_PROG_SED])
+-AC_CACHE_CHECK([$1], [$2],
+-  [$2=no
+-  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+-   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+-   lt_compiler_flag="$3"
+-   # Insert the option either (1) after the last *FLAGS variable, or
+-   # (2) before a word containing "conftest.", or (3) at the end.
+-   # Note that $ac_compile itself does not contain backslashes and begins
+-   # with a dollar sign (not a hyphen), so the echo should work correctly.
+-   # The option is referenced via a variable to avoid confusing sed.
+-   lt_compile=`echo "$ac_compile" | $SED \
+-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+-   -e 's:$: $lt_compiler_flag:'`
+-   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+-   (eval "$lt_compile" 2>conftest.err)
+-   ac_status=$?
+-   cat conftest.err >&AS_MESSAGE_LOG_FD
+-   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+-   if (exit $ac_status) && test -s "$ac_outfile"; then
+-     # The compiler can only warn and ignore the option if not recognized
+-     # So say no if there are warnings other than the usual output.
+-     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+-       $2=yes
+-     fi
+-   fi
+-   $rm conftest*
+-])
++    *) AC_MSG_ERROR([unrecognized argument: $[1]
++Try \`$[0] --help' for more information.]) ;;
++  esac
++  shift
++done
+ 
+-if test x"[$]$2" = xyes; then
+-    ifelse([$5], , :, [$5])
+-else
+-    ifelse([$6], , :, [$6])
++if $lt_cl_silent; then
++  exec AS_MESSAGE_FD>/dev/null
+ fi
+-])# AC_LIBTOOL_COMPILER_OPTION
+-
+-
+-# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+-#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+-# ------------------------------------------------------------
+-# Check whether the given compiler option works
+-AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+-[AC_CACHE_CHECK([$1], [$2],
+-  [$2=no
+-   save_LDFLAGS="$LDFLAGS"
+-   LDFLAGS="$LDFLAGS $3"
+-   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+-     # The linker can only warn and ignore the option if not recognized
+-     # So say no if there are warnings
+-     if test -s conftest.err; then
+-       # Append any errors to the config.log.
+-       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+-       $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+-       if diff conftest.exp conftest.er2 >/dev/null; then
+-         $2=yes
+-       fi
+-     else
+-       $2=yes
+-     fi
+-   fi
+-   $rm conftest*
+-   LDFLAGS="$save_LDFLAGS"
+-])
++_LTEOF
+ 
+-if test x"[$]$2" = xyes; then
+-    ifelse([$4], , :, [$4])
+-else
+-    ifelse([$5], , :, [$5])
++cat >>"$CONFIG_LT" <<_LTEOF
++_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
++_LTEOF
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++AC_MSG_NOTICE([creating $ofile])
++_LT_OUTPUT_LIBTOOL_COMMANDS
++AS_EXIT(0)
++_LTEOF
++chmod +x "$CONFIG_LT"
++
++# configure is writing to config.log, but config.lt does its own redirection,
++# appending to config.log, which fails on DOS, as config.log is still kept
++# open by configure.  Here we exec the FD to /dev/null, effectively closing
++# config.log, so it can be properly (re)opened and appended to by config.lt.
++if test "$no_create" != yes; then
++  lt_cl_success=:
++  test "$silent" = yes &&
++    lt_config_lt_args="$lt_config_lt_args --quiet"
++  exec AS_MESSAGE_LOG_FD>/dev/null
++  $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
++  exec AS_MESSAGE_LOG_FD>>config.log
++  $lt_cl_success || AS_EXIT(1)
+ fi
+-])# AC_LIBTOOL_LINKER_OPTION
+-
++])# LT_OUTPUT
+ 
+-# AC_LIBTOOL_SYS_MAX_CMD_LEN
+-# --------------------------
+-AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+-[# find the maximum length of command line arguments
+-AC_MSG_CHECKING([the maximum length of command line arguments])
+-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+-  i=0
+-  teststring="ABCD"
+ 
+-  case $build_os in
+-  msdosdjgpp*)
+-    # On DJGPP, this test can blow up pretty badly due to problems in libc
+-    # (any single argument exceeding 2000 bytes causes a buffer overrun
+-    # during glob expansion).  Even if it were fixed, the result of this
+-    # check would be larger than it should be.
+-    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+-    ;;
++# _LT_CONFIG(TAG)
++# ---------------
++# If TAG is the built-in tag, create an initial libtool script with a
++# default configuration from the untagged config vars.  Otherwise add code
++# to config.status for appending the configuration named by TAG from the
++# matching tagged config vars.
++m4_defun([_LT_CONFIG],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++_LT_CONFIG_SAVE_COMMANDS([
++  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
++  m4_if(_LT_TAG, [C], [
++    # See if we are running on zsh, and set the options which allow our
++    # commands through without removal of \ escapes.
++    if test -n "${ZSH_VERSION+set}" ; then
++      setopt NO_GLOB_SUBST
++    fi
+ 
+-  gnu*)
+-    # Under GNU Hurd, this test is not required because there is
+-    # no limit to the length of command line arguments.
+-    # Libtool will interpret -1 as no limit whatsoever
+-    lt_cv_sys_max_cmd_len=-1;
+-    ;;
++    cfgfile="${ofile}T"
++    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
++    $RM "$cfgfile"
+ 
+-  cygwin* | mingw*)
+-    # On Win9x/ME, this test blows up -- it succeeds, but takes
+-    # about 5 minutes as the teststring grows exponentially.
+-    # Worse, since 9x/ME are not pre-emptively multitasking,
+-    # you end up with a "frozen" computer, even though with patience
+-    # the test eventually succeeds (with a max line length of 256k).
+-    # Instead, let's just punt: use the minimum linelength reported by
+-    # all of the supported platforms: 8192 (on NT/2K/XP).
+-    lt_cv_sys_max_cmd_len=8192;
+-    ;;
++    cat <<_LT_EOF >> "$cfgfile"
++#! $SHELL
+ 
+-  amigaos*)
+-    # On AmigaOS with pdksh, this test takes hours, literally.
+-    # So we just punt and use a minimum line length of 8192.
+-    lt_cv_sys_max_cmd_len=8192;
+-    ;;
++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
++# NOTE: Changes made to this file will be lost: look at ltmain.sh.
++#
++_LT_COPYING
++_LT_LIBTOOL_TAGS
+ 
+-  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+-    # This has been around since 386BSD, at least.  Likely further.
+-    if test -x /sbin/sysctl; then
+-      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+-    elif test -x /usr/sbin/sysctl; then
+-      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+-    else
+-      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+-    fi
+-    # And add a safety zone
+-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+-    ;;
++# ### BEGIN LIBTOOL CONFIG
++_LT_LIBTOOL_CONFIG_VARS
++_LT_LIBTOOL_TAG_VARS
++# ### END LIBTOOL CONFIG
+ 
+-  interix*)
+-    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+-    lt_cv_sys_max_cmd_len=196608
+-    ;;
++_LT_EOF
+ 
+-  osf*)
+-    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+-    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+-    # nice to cause kernel panics so lets avoid the loop below.
+-    # First set a reasonable default.
+-    lt_cv_sys_max_cmd_len=16384
+-    #
+-    if test -x /sbin/sysconfig; then
+-      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+-        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+-      esac
+-    fi
+-    ;;
+-  sco3.2v5*)
+-    lt_cv_sys_max_cmd_len=102400
+-    ;;
+-  sysv5* | sco5v6* | sysv4.2uw2*)
+-    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+-    if test -n "$kargmax"; then
+-      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ 	]]//'`
+-    else
+-      lt_cv_sys_max_cmd_len=32768
+-    fi
+-    ;;
+-  *)
+-    # If test is not a shell built-in, we'll probably end up computing a
+-    # maximum length that is only half of the actual maximum length, but
+-    # we can't tell.
+-    SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+-    while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+-	       = "XX$teststring") >/dev/null 2>&1 &&
+-	    new_result=`expr "X$teststring" : ".*" 2>&1` &&
+-	    lt_cv_sys_max_cmd_len=$new_result &&
+-	    test $i != 17 # 1/2 MB should be enough
+-    do
+-      i=`expr $i + 1`
+-      teststring=$teststring$teststring
+-    done
+-    teststring=
+-    # Add a significant safety factor because C++ compilers can tack on massive
+-    # amounts of additional arguments before passing them to the linker.
+-    # It appears as though 1/2 is a usable value.
+-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
++  case $host_os in
++  aix3*)
++    cat <<\_LT_EOF >> "$cfgfile"
++# AIX sometimes has problems with the GCC collect2 program.  For some
++# reason, if we set the COLLECT_NAMES environment variable, the problems
++# vanish in a puff of smoke.
++if test "X${COLLECT_NAMES+set}" != Xset; then
++  COLLECT_NAMES=
++  export COLLECT_NAMES
++fi
++_LT_EOF
+     ;;
+   esac
+-])
+-if test -n $lt_cv_sys_max_cmd_len ; then
+-  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+-else
+-  AC_MSG_RESULT(none)
+-fi
+-])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+ 
++  _LT_PROG_LTMAIN
+ 
+-# _LT_AC_CHECK_DLFCN
+-# ------------------
+-AC_DEFUN([_LT_AC_CHECK_DLFCN],
+-[AC_CHECK_HEADERS(dlfcn.h)dnl
+-])# _LT_AC_CHECK_DLFCN
++  # We use sed instead of cat because bash on DJGPP gets confused if
++  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
++  # text mode, it properly converts lines to CR/LF.  This bash problem
++  # is reportedly fixed, but why not run on old versions too?
++  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
++    || (rm -f "$cfgfile"; exit 1)
+ 
++  _LT_PROG_XSI_SHELLFNS
+ 
+-# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+-#                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+-# ---------------------------------------------------------------------
+-AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+-[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+-if test "$cross_compiling" = yes; then :
+-  [$4]
+-else
+-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+-  lt_status=$lt_dlunknown
+-  cat > conftest.$ac_ext <<EOF
+-[#line __oline__ "configure"
+-#include "confdefs.h"
++  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
++    || (rm -f "$cfgfile"; exit 1)
+ 
+-#if HAVE_DLFCN_H
+-#include <dlfcn.h>
+-#endif
++  mv -f "$cfgfile" "$ofile" ||
++    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
++  chmod +x "$ofile"
++],
++[cat <<_LT_EOF >> "$ofile"
+ 
+-#include <stdio.h>
++dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
++dnl in a comment (ie after a #).
++# ### BEGIN LIBTOOL TAG CONFIG: $1
++_LT_LIBTOOL_TAG_VARS(_LT_TAG)
++# ### END LIBTOOL TAG CONFIG: $1
++_LT_EOF
++])dnl /m4_if
++],
++[m4_if([$1], [], [
++    PACKAGE='$PACKAGE'
++    VERSION='$VERSION'
++    TIMESTAMP='$TIMESTAMP'
++    RM='$RM'
++    ofile='$ofile'], [])
++])dnl /_LT_CONFIG_SAVE_COMMANDS
++])# _LT_CONFIG
++
++
++# LT_SUPPORTED_TAG(TAG)
++# ---------------------
++# Trace this macro to discover what tags are supported by the libtool
++# --tag option, using:
++#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
++AC_DEFUN([LT_SUPPORTED_TAG], [])
++
++
++# C support is built-in for now
++m4_define([_LT_LANG_C_enabled], [])
++m4_define([_LT_TAGS], [])
+ 
+-#ifdef RTLD_GLOBAL
+-#  define LT_DLGLOBAL		RTLD_GLOBAL
+-#else
+-#  ifdef DL_GLOBAL
+-#    define LT_DLGLOBAL		DL_GLOBAL
+-#  else
+-#    define LT_DLGLOBAL		0
+-#  endif
+-#endif
+ 
+-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+-   find out it does not work in some platform. */
+-#ifndef LT_DLLAZY_OR_NOW
+-#  ifdef RTLD_LAZY
+-#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+-#  else
+-#    ifdef DL_LAZY
+-#      define LT_DLLAZY_OR_NOW		DL_LAZY
+-#    else
+-#      ifdef RTLD_NOW
+-#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+-#      else
+-#        ifdef DL_NOW
+-#          define LT_DLLAZY_OR_NOW	DL_NOW
+-#        else
+-#          define LT_DLLAZY_OR_NOW	0
+-#        endif
+-#      endif
+-#    endif
+-#  endif
+-#endif
++# LT_LANG(LANG)
++# -------------
++# Enable libtool support for the given language if not already enabled.
++AC_DEFUN([LT_LANG],
++[AC_BEFORE([$0], [LT_OUTPUT])dnl
++m4_case([$1],
++  [C],			[_LT_LANG(C)],
++  [C++],		[_LT_LANG(CXX)],
++  [Java],		[_LT_LANG(GCJ)],
++  [Fortran 77],		[_LT_LANG(F77)],
++  [Fortran],		[_LT_LANG(FC)],
++  [Windows Resource],	[_LT_LANG(RC)],
++  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
++    [_LT_LANG($1)],
++    [m4_fatal([$0: unsupported language: "$1"])])])dnl
++])# LT_LANG
+ 
+-#ifdef __cplusplus
+-extern "C" void exit (int);
+-#endif
+ 
+-void fnord() { int i=42;}
+-int main ()
+-{
+-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+-  int status = $lt_dlunknown;
+-
+-  if (self)
+-    {
+-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+-      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+-      /* dlclose (self); */
+-    }
+-  else
+-    puts (dlerror ());
++# _LT_LANG(LANGNAME)
++# ------------------
++m4_defun([_LT_LANG],
++[m4_ifdef([_LT_LANG_]$1[_enabled], [],
++  [LT_SUPPORTED_TAG([$1])dnl
++  m4_append([_LT_TAGS], [$1 ])dnl
++  m4_define([_LT_LANG_]$1[_enabled], [])dnl
++  _LT_LANG_$1_CONFIG($1)])dnl
++])# _LT_LANG
+ 
+-    exit (status);
+-}]
+-EOF
+-  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+-    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+-    lt_status=$?
+-    case x$lt_status in
+-      x$lt_dlno_uscore) $1 ;;
+-      x$lt_dlneed_uscore) $2 ;;
+-      x$lt_dlunknown|x*) $3 ;;
+-    esac
+-  else :
+-    # compilation failed
+-    $3
+-  fi
+-fi
+-rm -fr conftest*
+-])# _LT_AC_TRY_DLOPEN_SELF
+ 
++# _LT_LANG_DEFAULT_CONFIG
++# -----------------------
++m4_defun([_LT_LANG_DEFAULT_CONFIG],
++[AC_PROVIDE_IFELSE([AC_PROG_CXX],
++  [LT_LANG(CXX)],
++  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
++
++AC_PROVIDE_IFELSE([AC_PROG_F77],
++  [LT_LANG(F77)],
++  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
++
++AC_PROVIDE_IFELSE([AC_PROG_FC],
++  [LT_LANG(FC)],
++  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
++
++dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
++dnl pulling things in needlessly.
++AC_PROVIDE_IFELSE([AC_PROG_GCJ],
++  [LT_LANG(GCJ)],
++  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
++    [LT_LANG(GCJ)],
++    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
++      [LT_LANG(GCJ)],
++      [m4_ifdef([AC_PROG_GCJ],
++	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
++       m4_ifdef([A][M_PROG_GCJ],
++	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
++       m4_ifdef([LT_PROG_GCJ],
++	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
++
++AC_PROVIDE_IFELSE([LT_PROG_RC],
++  [LT_LANG(RC)],
++  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
++])# _LT_LANG_DEFAULT_CONFIG
++
++# Obsolete macros:
++AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
++AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
++AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
++AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
++dnl AC_DEFUN([AC_LIBTOOL_F77], [])
++dnl AC_DEFUN([AC_LIBTOOL_FC], [])
++dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+ 
+-# AC_LIBTOOL_DLOPEN_SELF
+-# ----------------------
+-AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+-[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+-if test "x$enable_dlopen" != xyes; then
+-  enable_dlopen=unknown
+-  enable_dlopen_self=unknown
+-  enable_dlopen_self_static=unknown
+-else
+-  lt_cv_dlopen=no
+-  lt_cv_dlopen_libs=
+ 
+-  case $host_os in
+-  beos*)
+-    lt_cv_dlopen="load_add_on"
+-    lt_cv_dlopen_libs=
+-    lt_cv_dlopen_self=yes
+-    ;;
++# _LT_TAG_COMPILER
++# ----------------
++m4_defun([_LT_TAG_COMPILER],
++[AC_REQUIRE([AC_PROG_CC])dnl
+ 
+-  mingw* | pw32*)
+-    lt_cv_dlopen="LoadLibrary"
+-    lt_cv_dlopen_libs=
+-   ;;
++_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
++_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
++_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
++_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+ 
+-  cygwin*)
+-    lt_cv_dlopen="dlopen"
+-    lt_cv_dlopen_libs=
+-   ;;
++# If no C compiler was specified, use CC.
++LTCC=${LTCC-"$CC"}
+ 
+-  darwin*)
+-  # if libdl is installed we need to link against it
+-    AC_CHECK_LIB([dl], [dlopen],
+-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+-    lt_cv_dlopen="dyld"
+-    lt_cv_dlopen_libs=
+-    lt_cv_dlopen_self=yes
+-    ])
+-   ;;
++# If no C compiler flags were specified, use CFLAGS.
++LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+ 
+-  *)
+-    AC_CHECK_FUNC([shl_load],
+-	  [lt_cv_dlopen="shl_load"],
+-      [AC_CHECK_LIB([dld], [shl_load],
+-	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+-	[AC_CHECK_FUNC([dlopen],
+-	      [lt_cv_dlopen="dlopen"],
+-	  [AC_CHECK_LIB([dl], [dlopen],
+-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+-	    [AC_CHECK_LIB([svld], [dlopen],
+-		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+-	      [AC_CHECK_LIB([dld], [dld_link],
+-		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+-	      ])
+-	    ])
+-	  ])
+-	])
+-      ])
+-    ;;
+-  esac
++# Allow CC to be a program name with arguments.
++compiler=$CC
++])# _LT_TAG_COMPILER
+ 
+-  if test "x$lt_cv_dlopen" != xno; then
+-    enable_dlopen=yes
+-  else
+-    enable_dlopen=no
+-  fi
+ 
+-  case $lt_cv_dlopen in
+-  dlopen)
+-    save_CPPFLAGS="$CPPFLAGS"
+-    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
++# _LT_COMPILER_BOILERPLATE
++# ------------------------
++# Check for compiler boilerplate output or warnings with
++# the simple compiler test code.
++m4_defun([_LT_COMPILER_BOILERPLATE],
++[m4_require([_LT_DECL_SED])dnl
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_compile_test_code" >conftest.$ac_ext
++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_compiler_boilerplate=`cat conftest.err`
++$RM conftest*
++])# _LT_COMPILER_BOILERPLATE
+ 
+-    save_LDFLAGS="$LDFLAGS"
+-    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ 
+-    save_LIBS="$LIBS"
+-    LIBS="$lt_cv_dlopen_libs $LIBS"
++# _LT_LINKER_BOILERPLATE
++# ----------------------
++# Check for linker boilerplate output or warnings with
++# the simple link test code.
++m4_defun([_LT_LINKER_BOILERPLATE],
++[m4_require([_LT_DECL_SED])dnl
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_link_test_code" >conftest.$ac_ext
++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_linker_boilerplate=`cat conftest.err`
++$RM -r conftest*
++])# _LT_LINKER_BOILERPLATE
+ 
+-    AC_CACHE_CHECK([whether a program can dlopen itself],
+-	  lt_cv_dlopen_self, [dnl
+-	  _LT_AC_TRY_DLOPEN_SELF(
+-	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+-	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
++# _LT_REQUIRED_DARWIN_CHECKS
++# -------------------------
++m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
++  case $host_os in
++    rhapsody* | darwin*)
++    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
++    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
++    AC_CHECK_TOOL([LIPO], [lipo], [:])
++    AC_CHECK_TOOL([OTOOL], [otool], [:])
++    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
++    _LT_DECL([], [DSYMUTIL], [1],
++      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
++    _LT_DECL([], [NMEDIT], [1],
++      [Tool to change global to local symbols on Mac OS X])
++    _LT_DECL([], [LIPO], [1],
++      [Tool to manipulate fat objects and archives on Mac OS X])
++    _LT_DECL([], [OTOOL], [1],
++      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
++    _LT_DECL([], [OTOOL64], [1],
++      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
++
++    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
++      [lt_cv_apple_cc_single_mod=no
++      if test -z "${LT_MULTI_MODULE}"; then
++	# By default we will add the -single_module flag. You can override
++	# by either setting the environment variable LT_MULTI_MODULE
++	# non-empty at configure time, or by adding -multi_module to the
++	# link flags.
++	rm -rf libconftest.dylib*
++	echo "int foo(void){return 1;}" > conftest.c
++	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
++	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
++        _lt_result=$?
++	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
++	  lt_cv_apple_cc_single_mod=yes
++	else
++	  cat conftest.err >&AS_MESSAGE_LOG_FD
++	fi
++	rm -rf libconftest.dylib*
++	rm -f conftest.*
++      fi])
++    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
++      [lt_cv_ld_exported_symbols_list],
++      [lt_cv_ld_exported_symbols_list=no
++      save_LDFLAGS=$LDFLAGS
++      echo "_main" > conftest.sym
++      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
++      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
++	[lt_cv_ld_exported_symbols_list=yes],
++	[lt_cv_ld_exported_symbols_list=no])
++	LDFLAGS="$save_LDFLAGS"
+     ])
+-
+-    if test "x$lt_cv_dlopen_self" = xyes; then
+-      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+-      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+-    	  lt_cv_dlopen_self_static, [dnl
+-	  _LT_AC_TRY_DLOPEN_SELF(
+-	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+-	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+-      ])
++    case $host_os in
++    rhapsody* | darwin1.[[012]])
++      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
++    darwin1.*)
++      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++    darwin*) # darwin 5.x on 
++      # if running on 10.5 or later, the deployment target defaults
++      # to the OS version, if on x86, and 10.4, the deployment
++      # target defaults to 10.4. Don't you love it? 
++      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
++	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
++	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++	10.[[012]]*)
++	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++	10.*)
++	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++      esac
++    ;;
++  esac
++    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
++      _lt_dar_single_mod='$single_module'
++    fi
++    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
++      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
++    else
++      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
++    fi
++    if test "$DSYMUTIL" != ":"; then
++      _lt_dsymutil='~$DSYMUTIL $lib || :'
++    else
++      _lt_dsymutil=
+     fi
+-
+-    CPPFLAGS="$save_CPPFLAGS"
+-    LDFLAGS="$save_LDFLAGS"
+-    LIBS="$save_LIBS"
+     ;;
+   esac
++])
+ 
+-  case $lt_cv_dlopen_self in
+-  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+-  *) enable_dlopen_self=unknown ;;
+-  esac
+ 
+-  case $lt_cv_dlopen_self_static in
+-  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+-  *) enable_dlopen_self_static=unknown ;;
+-  esac
+-fi
+-])# AC_LIBTOOL_DLOPEN_SELF
++# _LT_DARWIN_LINKER_FEATURES
++# --------------------------
++# Checks for linker and compiler features on darwin
++m4_defun([_LT_DARWIN_LINKER_FEATURES],
++[
++  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
++  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++  _LT_TAGVAR(hardcode_direct, $1)=no
++  _LT_TAGVAR(hardcode_automatic, $1)=yes
++  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++  _LT_TAGVAR(whole_archive_flag_spec, $1)=''
++  _LT_TAGVAR(link_all_deplibs, $1)=yes
++  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
++  if test "$GCC" = "yes"; then
++    output_verbose_link_cmd=echo
++    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
++    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
++    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
++    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
++    m4_if([$1], [CXX],
++[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
++      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
++      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
++    fi
++],[])
++  else
++  _LT_TAGVAR(ld_shlibs, $1)=no
++  fi
++])
+ 
++# _LT_SYS_MODULE_PATH_AIX
++# -----------------------
++# Links a minimal program and checks the executable
++# for the system default hardcoded library path. In most cases,
++# this is /usr/lib:/lib, but when the MPI compilers are used
++# the location of the communication and MPI libs are included too.
++# If we don't find anything, use the default library path according
++# to the aix ld manual.
++m4_defun([_LT_SYS_MODULE_PATH_AIX],
++[m4_require([_LT_DECL_SED])dnl
++AC_LINK_IFELSE(AC_LANG_PROGRAM,[
++lt_aix_libpath_sed='
++    /Import File Strings/,/^$/ {
++	/^0/ {
++	    s/^0  *\(.*\)$/\1/
++	    p
++	}
++    }'
++aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++# Check for a 64-bit object if we didn't find anything.
++if test -z "$aix_libpath"; then
++  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++fi],[])
++if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
++])# _LT_SYS_MODULE_PATH_AIX
+ 
+-# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+-# ---------------------------------
+-# Check to see if options -c and -o are simultaneously supported by compiler
+-AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+-[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+-  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+-  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+-   $rm -r conftest 2>/dev/null
+-   mkdir conftest
+-   cd conftest
+-   mkdir out
+-   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
+-   lt_compiler_flag="-o out/conftest2.$ac_objext"
+-   # Insert the option either (1) after the last *FLAGS variable, or
+-   # (2) before a word containing "conftest.", or (3) at the end.
+-   # Note that $ac_compile itself does not contain backslashes and begins
+-   # with a dollar sign (not a hyphen), so the echo should work correctly.
+-   lt_compile=`echo "$ac_compile" | $SED \
+-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+-   -e 's:$: $lt_compiler_flag:'`
+-   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+-   (eval "$lt_compile" 2>out/conftest.err)
+-   ac_status=$?
+-   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+-   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+-   then
+-     # The compiler can only warn and ignore the option if not recognized
+-     # So say no if there are warnings
+-     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+-       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+-     fi
+-   fi
+-   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+-   $rm conftest*
+-   # SGI C++ compiler will create directory out/ii_files/ for
+-   # template instantiation
+-   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+-   $rm out/* && rmdir out
+-   cd ..
+-   rmdir conftest
+-   $rm conftest*
+-])
+-])# AC_LIBTOOL_PROG_CC_C_O
++# _LT_SHELL_INIT(ARG)
++# -------------------
++m4_define([_LT_SHELL_INIT],
++[ifdef([AC_DIVERSION_NOTICE],
++	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
++	 [AC_DIVERT_PUSH(NOTICE)])
++$1
++AC_DIVERT_POP
++])# _LT_SHELL_INIT
+ 
+ 
+-# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+-# -----------------------------------------
+-# Check to see if we can do hard links to lock some files if needed
+-AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+-[AC_REQUIRE([_LT_AC_LOCK])dnl
++# _LT_PROG_ECHO_BACKSLASH
++# -----------------------
++# Add some code to the start of the generated configure script which
++# will find an echo command which doesn't interpret backslashes.
++m4_defun([_LT_PROG_ECHO_BACKSLASH],
++[_LT_SHELL_INIT([
++# Check that we are running under the correct shell.
++SHELL=${CONFIG_SHELL-/bin/sh}
+ 
+-hard_links="nottested"
+-if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+-  # do not overwrite the value of need_locks provided by the user
+-  AC_MSG_CHECKING([if we can lock with hard links])
+-  hard_links=yes
+-  $rm conftest*
+-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+-  touch conftest.a
+-  ln conftest.a conftest.b 2>&5 || hard_links=no
+-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+-  AC_MSG_RESULT([$hard_links])
+-  if test "$hard_links" = no; then
+-    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+-    need_locks=warn
+-  fi
++case X$lt_ECHO in
++X*--fallback-echo)
++  # Remove one level of quotation (which was required for Make).
++  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
++  ;;
++esac
++
++ECHO=${lt_ECHO-echo}
++if test "X[$]1" = X--no-reexec; then
++  # Discard the --no-reexec flag, and continue.
++  shift
++elif test "X[$]1" = X--fallback-echo; then
++  # Avoid inline document here, it may be left over
++  :
++elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
++  # Yippee, $ECHO works!
++  :
+ else
+-  need_locks=no
++  # Restart under the correct shell.
++  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+ fi
+-])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+ 
+-
+-# AC_LIBTOOL_OBJDIR
+-# -----------------
+-AC_DEFUN([AC_LIBTOOL_OBJDIR],
+-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+-[rm -f .libs 2>/dev/null
+-mkdir .libs 2>/dev/null
+-if test -d .libs; then
+-  lt_cv_objdir=.libs
+-else
+-  # MS-DOS does not allow filenames that begin with a dot.
+-  lt_cv_objdir=_libs
++if test "X[$]1" = X--fallback-echo; then
++  # used as fallback echo
++  shift
++  cat <<_LT_EOF
++[$]*
++_LT_EOF
++  exit 0
+ fi
+-rmdir .libs 2>/dev/null])
+-objdir=$lt_cv_objdir
+-])# AC_LIBTOOL_OBJDIR
+ 
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+ 
+-# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+-# ----------------------------------------------
+-# Check hardcoding attributes.
+-AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+-[AC_MSG_CHECKING([how to hardcode library paths into programs])
+-_LT_AC_TAGVAR(hardcode_action, $1)=
+-if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+-   test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+-   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+-
+-  # We can hardcode non-existant directories.
+-  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+-     # have to relink, otherwise we might link with an installed library
+-     # when we should be linking with a yet-to-be-installed one
+-     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+-     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+-    # Linking always hardcodes the temporary library directory.
+-    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+-  else
+-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+-    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
++if test -z "$lt_ECHO"; then
++  if test "X${echo_test_string+set}" != Xset; then
++    # find a string as large as possible, as long as the shell can cope with it
++    for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
++      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
++      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
++	 { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
++      then
++        break
++      fi
++    done
+   fi
+-else
+-  # We cannot hardcode anything, or else we can only hardcode existing
+-  # directories.
+-  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+-fi
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+ 
+-if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+-  # Fast installation is not supported
+-  enable_fast_install=no
+-elif test "$shlibpath_overrides_runpath" = yes ||
+-     test "$enable_shared" = no; then
+-  # Fast installation is not necessary
+-  enable_fast_install=needless
+-fi
+-])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
++  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
++     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
++     test "X$echo_testing_string" = "X$echo_test_string"; then
++    :
++  else
++    # The Solaris, AIX, and Digital Unix default echo programs unquote
++    # backslashes.  This makes it impossible to quote backslashes using
++    #   echo "$something" | sed 's/\\/\\\\/g'
++    #
++    # So, first we look for a working echo in the user's PATH.
+ 
++    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++    for dir in $PATH /usr/ucb; do
++      IFS="$lt_save_ifs"
++      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
++         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
++         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
++         test "X$echo_testing_string" = "X$echo_test_string"; then
++        ECHO="$dir/echo"
++        break
++      fi
++    done
++    IFS="$lt_save_ifs"
+ 
+-# AC_LIBTOOL_SYS_LIB_STRIP
+-# ------------------------
+-AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+-[striplib=
+-old_striplib=
+-AC_MSG_CHECKING([whether stripping libraries is possible])
+-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+-  AC_MSG_RESULT([yes])
+-else
+-# FIXME - insert some real tests, host_os isn't really good enough
+-  case $host_os in
+-   darwin*)
+-       if test -n "$STRIP" ; then
+-         striplib="$STRIP -x"
+-         AC_MSG_RESULT([yes])
+-       else
+-  AC_MSG_RESULT([no])
+-fi
+-       ;;
+-   *)
+-  AC_MSG_RESULT([no])
+-    ;;
+-  esac
+-fi
+-])# AC_LIBTOOL_SYS_LIB_STRIP
++    if test "X$ECHO" = Xecho; then
++      # We didn't find a better echo, so look for alternatives.
++      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
++         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
++         test "X$echo_testing_string" = "X$echo_test_string"; then
++        # This shell has a builtin print -r that does the trick.
++        ECHO='print -r'
++      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
++	   test "X$CONFIG_SHELL" != X/bin/ksh; then
++        # If we have ksh, try running configure again with it.
++        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
++        export ORIGINAL_CONFIG_SHELL
++        CONFIG_SHELL=/bin/ksh
++        export CONFIG_SHELL
++        exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
++      else
++        # Try using printf.
++        ECHO='printf %s\n'
++        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
++	   echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
++	   test "X$echo_testing_string" = "X$echo_test_string"; then
++	  # Cool, printf works
++	  :
++        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
++	     test "X$echo_testing_string" = 'X\t' &&
++	     echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
++	     test "X$echo_testing_string" = "X$echo_test_string"; then
++	  CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
++	  export CONFIG_SHELL
++	  SHELL="$CONFIG_SHELL"
++	  export SHELL
++	  ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
++        elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
++	     test "X$echo_testing_string" = 'X\t' &&
++	     echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
++	     test "X$echo_testing_string" = "X$echo_test_string"; then
++	  ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
++        else
++	  # maybe with a smaller string...
++	  prev=:
+ 
++	  for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
++	    if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
++	    then
++	      break
++	    fi
++	    prev="$cmd"
++	  done
+ 
+-# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+-# -----------------------------
+-# PORTME Fill in your ld.so characteristics
+-AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+-[AC_MSG_CHECKING([dynamic linker characteristics])
+-library_names_spec=
+-libname_spec='lib$name'
+-soname_spec=
+-shrext_cmds=".so"
+-postinstall_cmds=
+-postuninstall_cmds=
+-finish_cmds=
+-finish_eval=
+-shlibpath_var=
+-shlibpath_overrides_runpath=unknown
+-version_type=none
+-dynamic_linker="$host_os ld.so"
+-sys_lib_dlsearch_path_spec="/lib /usr/lib"
+-if test "$GCC" = yes; then
+-  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+-  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+-    # if the path contains ";" then we assume it to be the separator
+-    # otherwise default to the standard path separator (i.e. ":") - it is
+-    # assumed that no part of a normal pathname contains ";" but that should
+-    # okay in the real world where ";" in dirpaths is itself problematic.
+-    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+-  else
+-    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
++	  if test "$prev" != 'sed 50q "[$]0"'; then
++	    echo_test_string=`eval $prev`
++	    export echo_test_string
++	    exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
++	  else
++	    # Oops.  We lost completely, so just stick with echo.
++	    ECHO=echo
++	  fi
++        fi
++      fi
++    fi
+   fi
+-else
+-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ fi
+-need_lib_prefix=unknown
+-hardcode_into_libs=no
+ 
+-# when you set need_version to no, make sure it does not cause -set_version
+-# flags to be left without arguments
+-need_version=unknown
++# Copy echo and quote the copy suitably for passing to libtool from
++# the Makefile, instead of quoting the original, which is used later.
++lt_ECHO=$ECHO
++if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
++   lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
++fi
+ 
+-case $host_os in
+-aix3*)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+-  shlibpath_var=LIBPATH
++AC_SUBST(lt_ECHO)
++])
++_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
++_LT_DECL([], [ECHO], [1],
++    [An echo program that does not interpret backslashes])
++])# _LT_PROG_ECHO_BACKSLASH
+ 
+-  # AIX 3 has no versioning support, so we append a major version to the name.
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  ;;
+ 
+-aix4* | aix5*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  hardcode_into_libs=yes
+-  if test "$host_cpu" = ia64; then
+-    # AIX 5 supports IA64
+-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+-    shlibpath_var=LD_LIBRARY_PATH
+-  else
+-    # With GCC up to 2.95.x, collect2 would create an import file
+-    # for dependence libraries.  The import file would start with
+-    # the line `#! .'.  This would cause the generated library to
+-    # depend on `.', always an invalid library.  This was fixed in
+-    # development snapshots of GCC prior to 3.0.
+-    case $host_os in
+-      aix4 | aix4.[[01]] | aix4.[[01]].*)
+-      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+-	   echo ' yes '
+-	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+-	:
+-      else
+-	can_build_shared=no
+-      fi
+-      ;;
++# _LT_ENABLE_LOCK
++# ---------------
++m4_defun([_LT_ENABLE_LOCK],
++[AC_ARG_ENABLE([libtool-lock],
++  [AS_HELP_STRING([--disable-libtool-lock],
++    [avoid locking (might break parallel builds)])])
++test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++
++# Some flags need to be propagated to the compiler or linker for good
++# libtool support.
++case $host in
++ia64-*-hpux*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.$ac_objext` in
++      *ELF-32*)
++	HPUX_IA64_MODE="32"
++	;;
++      *ELF-64*)
++	HPUX_IA64_MODE="64"
++	;;
+     esac
+-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+-    # soname into executable. Probably we can add versioning support to
+-    # collect2, so additional links can be useful in future.
+-    if test "$aix_use_runtimelinking" = yes; then
+-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+-      # instead of lib<name>.a to let people know that these are not
+-      # typical AIX shared libraries.
+-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  fi
++  rm -rf conftest*
++  ;;
++*-*-irix6*)
++  # Find out which ABI we are using.
++  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    if test "$lt_cv_prog_gnu_ld" = yes; then
++      case `/usr/bin/file conftest.$ac_objext` in
++	*32-bit*)
++	  LD="${LD-ld} -melf32bsmip"
++	  ;;
++	*N32*)
++	  LD="${LD-ld} -melf32bmipn32"
++	  ;;
++	*64-bit*)
++	  LD="${LD-ld} -melf64bmip"
++	;;
++      esac
+     else
+-      # We preserve .a as extension for shared libraries through AIX4.2
+-      # and later when we are not doing run time linking.
+-      library_names_spec='${libname}${release}.a $libname.a'
+-      soname_spec='${libname}${release}${shared_ext}$major'
++      case `/usr/bin/file conftest.$ac_objext` in
++	*32-bit*)
++	  LD="${LD-ld} -32"
++	  ;;
++	*N32*)
++	  LD="${LD-ld} -n32"
++	  ;;
++	*64-bit*)
++	  LD="${LD-ld} -64"
++	  ;;
++      esac
+     fi
+-    shlibpath_var=LIBPATH
+   fi
++  rm -rf conftest*
+   ;;
+ 
+-amigaos*)
+-  library_names_spec='$libname.ixlibrary $libname.a'
+-  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+-  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
++x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
++s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.o` in
++      *32-bit*)
++	case $host in
++	  x86_64-*kfreebsd*-gnu)
++	    LD="${LD-ld} -m elf_i386_fbsd"
++	    ;;
++	  x86_64-*linux*)
++	    LD="${LD-ld} -m elf_i386"
++	    ;;
++	  ppc64-*linux*|powerpc64-*linux*)
++	    LD="${LD-ld} -m elf32ppclinux"
++	    ;;
++	  s390x-*linux*)
++	    LD="${LD-ld} -m elf_s390"
++	    ;;
++	  sparc64-*linux*)
++	    LD="${LD-ld} -m elf32_sparc"
++	    ;;
++	esac
++	;;
++      *64-bit*)
++	case $host in
++	  x86_64-*kfreebsd*-gnu)
++	    LD="${LD-ld} -m elf_x86_64_fbsd"
++	    ;;
++	  x86_64-*linux*)
++	    LD="${LD-ld} -m elf_x86_64"
++	    ;;
++	  ppc*-*linux*|powerpc*-*linux*)
++	    LD="${LD-ld} -m elf64ppc"
++	    ;;
++	  s390*-*linux*|s390*-*tpf*)
++	    LD="${LD-ld} -m elf64_s390"
++	    ;;
++	  sparc*-*linux*)
++	    LD="${LD-ld} -m elf64_sparc"
++	    ;;
++	esac
++	;;
++    esac
++  fi
++  rm -rf conftest*
+   ;;
+ 
+-beos*)
+-  library_names_spec='${libname}${shared_ext}'
+-  dynamic_linker="$host_os ld.so"
+-  shlibpath_var=LIBRARY_PATH
++*-*-sco3.2v5*)
++  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
++  SAVE_CFLAGS="$CFLAGS"
++  CFLAGS="$CFLAGS -belf"
++  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
++    [AC_LANG_PUSH(C)
++     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
++     AC_LANG_POP])
++  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
++    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
++    CFLAGS="$SAVE_CFLAGS"
++  fi
+   ;;
+-
+-bsdi[[45]]*)
+-  version_type=linux
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+-  # the default ld.so.conf also contains /usr/contrib/lib and
+-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+-  # libtool to hard-code these into programs
++sparc*-*solaris*)
++  # Find out which ABI we are using.
++  echo 'int i;' > conftest.$ac_ext
++  if AC_TRY_EVAL(ac_compile); then
++    case `/usr/bin/file conftest.o` in
++    *64-bit*)
++      case $lt_cv_prog_gnu_ld in
++      yes*) LD="${LD-ld} -m elf64_sparc" ;;
++      *)
++	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
++	  LD="${LD-ld} -64"
++	fi
++	;;
++      esac
++      ;;
++    esac
++  fi
++  rm -rf conftest*
+   ;;
++esac
+ 
+-cygwin* | mingw* | pw32*)
+-  version_type=windows
+-  shrext_cmds=".dll"
+-  need_version=no
+-  need_lib_prefix=no
++need_locks="$enable_libtool_lock"
++])# _LT_ENABLE_LOCK
+ 
+-  case $GCC,$host_os in
+-  yes,cygwin* | yes,mingw* | yes,pw32*)
+-    library_names_spec='$libname.dll.a'
+-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+-    postinstall_cmds='base_file=`basename \${file}`~
+-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+-      dldir=$destdir/`dirname \$dlpath`~
+-      test -d \$dldir || mkdir -p \$dldir~
+-      $install_prog $dir/$dlname \$dldir/$dlname~
+-      chmod a+x \$dldir/$dlname'
+-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+-      dlpath=$dir/\$dldll~
+-       $rm \$dlpath'
+-    shlibpath_overrides_runpath=yes
+ 
+-    case $host_os in
+-    cygwin*)
+-      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+-      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+-      ;;
+-    mingw*)
+-      # MinGW DLLs use traditional 'lib' prefix
+-      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+-      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+-      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+-        # It is most probably a Windows format PATH printed by
+-        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+-        # path with ; separators, and with drive letters. We can handle the
+-        # drive letters (cygwin fileutils understands them), so leave them,
+-        # especially as we might pass files found there to a mingw objdump,
+-        # which wouldn't understand a cygwinified path. Ahh.
+-        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+-      else
+-        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+-      fi
+-      ;;
+-    pw32*)
+-      # pw32 DLLs use 'pw' prefix rather than 'lib'
+-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+-      ;;
+-    esac
+-    ;;
++# _LT_CMD_OLD_ARCHIVE
++# -------------------
++m4_defun([_LT_CMD_OLD_ARCHIVE],
++[AC_CHECK_TOOL(AR, ar, false)
++test -z "$AR" && AR=ar
++test -z "$AR_FLAGS" && AR_FLAGS=cru
++_LT_DECL([], [AR], [1], [The archiver])
++_LT_DECL([], [AR_FLAGS], [1])
++
++AC_CHECK_TOOL(STRIP, strip, :)
++test -z "$STRIP" && STRIP=:
++_LT_DECL([], [STRIP], [1], [A symbol stripping program])
++
++AC_CHECK_TOOL(RANLIB, ranlib, :)
++test -z "$RANLIB" && RANLIB=:
++_LT_DECL([], [RANLIB], [1],
++    [Commands used to install an old-style archive])
++
++# Determine commands to create old-style static archives.
++old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
++old_postinstall_cmds='chmod 644 $oldlib'
++old_postuninstall_cmds=
+ 
++if test -n "$RANLIB"; then
++  case $host_os in
++  openbsd*)
++    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
++    ;;
+   *)
+-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
++    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+     ;;
+   esac
+-  dynamic_linker='Win32 ld.exe'
+-  # FIXME: first we should search . and the directory the executable is in
+-  shlibpath_var=PATH
+-  ;;
++  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
++fi
++_LT_DECL([], [old_postinstall_cmds], [2])
++_LT_DECL([], [old_postuninstall_cmds], [2])
++_LT_TAGDECL([], [old_archive_cmds], [2],
++    [Commands used to build an old-style archive])
++])# _LT_CMD_OLD_ARCHIVE
+ 
+-darwin* | rhapsody*)
+-  dynamic_linker="$host_os dyld"
+-  version_type=darwin
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+-  soname_spec='${libname}${release}${major}$shared_ext'
+-  shlibpath_overrides_runpath=yes
+-  shlibpath_var=DYLD_LIBRARY_PATH
+-  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+-  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+-  if test "$GCC" = yes; then
+-    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
+-  else
+-    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
+-  fi
+-  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+-  ;;
+ 
+-dgux*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  ;;
++# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
++#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
++# ----------------------------------------------------------------
++# Check whether the given compiler option works
++AC_DEFUN([_LT_COMPILER_OPTION],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_CACHE_CHECK([$1], [$2],
++  [$2=no
++   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
++   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++   lt_compiler_flag="$3"
++   # Insert the option either (1) after the last *FLAGS variable, or
++   # (2) before a word containing "conftest.", or (3) at the end.
++   # Note that $ac_compile itself does not contain backslashes and begins
++   # with a dollar sign (not a hyphen), so the echo should work correctly.
++   # The option is referenced via a variable to avoid confusing sed.
++   lt_compile=`echo "$ac_compile" | $SED \
++   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
++   -e 's:$: $lt_compiler_flag:'`
++   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
++   (eval "$lt_compile" 2>conftest.err)
++   ac_status=$?
++   cat conftest.err >&AS_MESSAGE_LOG_FD
++   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
++   if (exit $ac_status) && test -s "$ac_outfile"; then
++     # The compiler can only warn and ignore the option if not recognized
++     # So say no if there are warnings other than the usual output.
++     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
++     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
++       $2=yes
++     fi
++   fi
++   $RM conftest*
++])
+ 
+-freebsd1*)
+-  dynamic_linker=no
+-  ;;
++if test x"[$]$2" = xyes; then
++    m4_if([$5], , :, [$5])
++else
++    m4_if([$6], , :, [$6])
++fi
++])# _LT_COMPILER_OPTION
+ 
+-kfreebsd*-gnu)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  dynamic_linker='GNU ld.so'
+-  ;;
++# Old name:
++AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+ 
+-freebsd* | dragonfly*)
+-  # DragonFly does not have aout.  When/if they implement a new
+-  # versioning mechanism, adjust this.
+-  if test -x /usr/bin/objformat; then
+-    objformat=`/usr/bin/objformat`
+-  else
+-    case $host_os in
+-    freebsd[[123]]*) objformat=aout ;;
+-    *) objformat=elf ;;
+-    esac
+-  fi
+-  version_type=freebsd-$objformat
+-  case $version_type in
+-    freebsd-elf*)
+-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+-      need_version=no
+-      need_lib_prefix=no
+-      ;;
+-    freebsd-*)
+-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+-      need_version=yes
+-      ;;
+-  esac
+-  shlibpath_var=LD_LIBRARY_PATH
+-  case $host_os in
+-  freebsd2*)
+-    shlibpath_overrides_runpath=yes
+-    ;;
+-  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+-    shlibpath_overrides_runpath=yes
+-    hardcode_into_libs=yes
++
++# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
++#                  [ACTION-SUCCESS], [ACTION-FAILURE])
++# ----------------------------------------------------
++# Check whether the given linker option works
++AC_DEFUN([_LT_LINKER_OPTION],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_CACHE_CHECK([$1], [$2],
++  [$2=no
++   save_LDFLAGS="$LDFLAGS"
++   LDFLAGS="$LDFLAGS $3"
++   echo "$lt_simple_link_test_code" > conftest.$ac_ext
++   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
++     # The linker can only warn and ignore the option if not recognized
++     # So say no if there are warnings
++     if test -s conftest.err; then
++       # Append any errors to the config.log.
++       cat conftest.err 1>&AS_MESSAGE_LOG_FD
++       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
++       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++       if diff conftest.exp conftest.er2 >/dev/null; then
++         $2=yes
++       fi
++     else
++       $2=yes
++     fi
++   fi
++   $RM -r conftest*
++   LDFLAGS="$save_LDFLAGS"
++])
++
++if test x"[$]$2" = xyes; then
++    m4_if([$4], , :, [$4])
++else
++    m4_if([$5], , :, [$5])
++fi
++])# _LT_LINKER_OPTION
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
++
++
++# LT_CMD_MAX_LEN
++#---------------
++AC_DEFUN([LT_CMD_MAX_LEN],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++# find the maximum length of command line arguments
++AC_MSG_CHECKING([the maximum length of command line arguments])
++AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
++  i=0
++  teststring="ABCD"
++
++  case $build_os in
++  msdosdjgpp*)
++    # On DJGPP, this test can blow up pretty badly due to problems in libc
++    # (any single argument exceeding 2000 bytes causes a buffer overrun
++    # during glob expansion).  Even if it were fixed, the result of this
++    # check would be larger than it should be.
++    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+     ;;
+-  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+-  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+-    shlibpath_overrides_runpath=no
+-    hardcode_into_libs=yes
++
++  gnu*)
++    # Under GNU Hurd, this test is not required because there is
++    # no limit to the length of command line arguments.
++    # Libtool will interpret -1 as no limit whatsoever
++    lt_cv_sys_max_cmd_len=-1;
+     ;;
+-  freebsd*) # from 4.6 on
+-    shlibpath_overrides_runpath=yes
+-    hardcode_into_libs=yes
++
++  cygwin* | mingw*)
++    # On Win9x/ME, this test blows up -- it succeeds, but takes
++    # about 5 minutes as the teststring grows exponentially.
++    # Worse, since 9x/ME are not pre-emptively multitasking,
++    # you end up with a "frozen" computer, even though with patience
++    # the test eventually succeeds (with a max line length of 256k).
++    # Instead, let's just punt: use the minimum linelength reported by
++    # all of the supported platforms: 8192 (on NT/2K/XP).
++    lt_cv_sys_max_cmd_len=8192;
+     ;;
+-  esac
+-  ;;
+ 
+-gnu*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  hardcode_into_libs=yes
+-  ;;
++  amigaos*)
++    # On AmigaOS with pdksh, this test takes hours, literally.
++    # So we just punt and use a minimum line length of 8192.
++    lt_cv_sys_max_cmd_len=8192;
++    ;;
+ 
+-hpux9* | hpux10* | hpux11*)
+-  # Give a soname corresponding to the major version so that dld.sl refuses to
+-  # link against other versions.
+-  version_type=sunos
+-  need_lib_prefix=no
+-  need_version=no
+-  case $host_cpu in
+-  ia64*)
+-    shrext_cmds='.so'
+-    hardcode_into_libs=yes
+-    dynamic_linker="$host_os dld.so"
+-    shlibpath_var=LD_LIBRARY_PATH
+-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-    soname_spec='${libname}${release}${shared_ext}$major'
+-    if test "X$HPUX_IA64_MODE" = X32; then
+-      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
++  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
++    # This has been around since 386BSD, at least.  Likely further.
++    if test -x /sbin/sysctl; then
++      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
++    elif test -x /usr/sbin/sysctl; then
++      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+     else
+-      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
++      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+     fi
+-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+-    ;;
+-   hppa*64*)
+-     shrext_cmds='.sl'
+-     hardcode_into_libs=yes
+-     dynamic_linker="$host_os dld.sl"
+-     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+-     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+-     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-     soname_spec='${libname}${release}${shared_ext}$major'
+-     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+-     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+-     ;;
+-   *)
+-    shrext_cmds='.sl'
+-    dynamic_linker="$host_os dld.sl"
+-    shlibpath_var=SHLIB_PATH
+-    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-    soname_spec='${libname}${release}${shared_ext}$major'
++    # And add a safety zone
++    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+     ;;
+-  esac
+-  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+-  postinstall_cmds='chmod 555 $lib'
+-  ;;
+ 
+-interix3*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  ;;
++  interix*)
++    # We know the value 262144 and hardcode it with a safety zone (like BSD)
++    lt_cv_sys_max_cmd_len=196608
++    ;;
+ 
+-irix5* | irix6* | nonstopux*)
+-  case $host_os in
+-    nonstopux*) version_type=nonstopux ;;
+-    *)
+-	if test "$lt_cv_prog_gnu_ld" = yes; then
+-		version_type=linux
+-	else
+-		version_type=irix
+-	fi ;;
+-  esac
+-  need_lib_prefix=no
+-  need_version=no
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+-  case $host_os in
+-  irix5* | nonstopux*)
+-    libsuff= shlibsuff=
++  osf*)
++    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
++    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
++    # nice to cause kernel panics so lets avoid the loop below.
++    # First set a reasonable default.
++    lt_cv_sys_max_cmd_len=16384
++    #
++    if test -x /sbin/sysconfig; then
++      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
++        *1*) lt_cv_sys_max_cmd_len=-1 ;;
++      esac
++    fi
++    ;;
++  sco3.2v5*)
++    lt_cv_sys_max_cmd_len=102400
++    ;;
++  sysv5* | sco5v6* | sysv4.2uw2*)
++    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
++    if test -n "$kargmax"; then
++      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
++    else
++      lt_cv_sys_max_cmd_len=32768
++    fi
+     ;;
+   *)
+-    case $LD in # libtool.m4 will add one of these switches to LD
+-    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+-      libsuff= shlibsuff= libmagic=32-bit;;
+-    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+-      libsuff=32 shlibsuff=N32 libmagic=N32;;
+-    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+-      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+-    *) libsuff= shlibsuff= libmagic=never-match;;
+-    esac
++    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
++    if test -n "$lt_cv_sys_max_cmd_len"; then
++      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
++    else
++      # Make teststring a little bigger before we do anything with it.
++      # a 1K string should be a reasonable start.
++      for i in 1 2 3 4 5 6 7 8 ; do
++        teststring=$teststring$teststring
++      done
++      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
++      # If test is not a shell built-in, we'll probably end up computing a
++      # maximum length that is only half of the actual maximum length, but
++      # we can't tell.
++      while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
++	         = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
++	      test $i != 17 # 1/2 MB should be enough
++      do
++        i=`expr $i + 1`
++        teststring=$teststring$teststring
++      done
++      # Only check the string length outside the loop.
++      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
++      teststring=
++      # Add a significant safety factor because C++ compilers can tack on
++      # massive amounts of additional arguments before passing them to the
++      # linker.  It appears as though 1/2 is a usable value.
++      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
++    fi
+     ;;
+   esac
+-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+-  shlibpath_overrides_runpath=no
+-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+-  hardcode_into_libs=yes
+-  ;;
++])
++if test -n $lt_cv_sys_max_cmd_len ; then
++  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
++else
++  AC_MSG_RESULT(none)
++fi
++max_cmd_len=$lt_cv_sys_max_cmd_len
++_LT_DECL([], [max_cmd_len], [0],
++    [What is the maximum length of a command?])
++])# LT_CMD_MAX_LEN
+ 
+-# No shared lib support for Linux oldld, aout, or coff.
+-linux*oldld* | linux*aout* | linux*coff*)
+-  dynamic_linker=no
+-  ;;
++# Old name:
++AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+ 
+-# This must be Linux ELF.
+-linux*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  # This implies no fast_install, which is unacceptable.
+-  # Some rework will be needed to allow for fast_install
+-  # before this can be enabled.
+-  hardcode_into_libs=yes
+ 
+-  # Append ld.so.conf contents to the search path
+-  if test -f /etc/ld.so.conf; then
+-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+-  fi
++# _LT_HEADER_DLFCN
++# ----------------
++m4_defun([_LT_HEADER_DLFCN],
++[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
++])# _LT_HEADER_DLFCN
+ 
+-  # We used to test for /lib/ld.so.1 and disable shared libraries on
+-  # powerpc, because MkLinux only supported shared libraries with the
+-  # GNU dynamic linker.  Since this was broken with cross compilers,
+-  # most powerpc-linux boxes support dynamic linking these days and
+-  # people can always --disable-shared, the test was removed, and we
+-  # assume the GNU/Linux dynamic linker is in use.
+-  dynamic_linker='GNU/Linux ld.so'
+-  ;;
+ 
+-knetbsd*-gnu)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=no
+-  hardcode_into_libs=yes
+-  dynamic_linker='GNU ld.so'
+-  ;;
++# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
++#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
++# ----------------------------------------------------------------
++m4_defun([_LT_TRY_DLOPEN_SELF],
++[m4_require([_LT_HEADER_DLFCN])dnl
++if test "$cross_compiling" = yes; then :
++  [$4]
++else
++  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
++  lt_status=$lt_dlunknown
++  cat > conftest.$ac_ext <<_LT_EOF
++[#line __oline__ "configure"
++#include "confdefs.h"
+ 
+-netbsd*)
+-  version_type=sunos
+-  need_lib_prefix=no
+-  need_version=no
+-  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+-    dynamic_linker='NetBSD (a.out) ld.so'
+-  else
+-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+-    soname_spec='${libname}${release}${shared_ext}$major'
+-    dynamic_linker='NetBSD ld.elf_so'
+-  fi
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  hardcode_into_libs=yes
+-  ;;
++#if HAVE_DLFCN_H
++#include <dlfcn.h>
++#endif
+ 
+-newsos6)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  ;;
++#include <stdio.h>
+ 
+-nto-qnx*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  ;;
++#ifdef RTLD_GLOBAL
++#  define LT_DLGLOBAL		RTLD_GLOBAL
++#else
++#  ifdef DL_GLOBAL
++#    define LT_DLGLOBAL		DL_GLOBAL
++#  else
++#    define LT_DLGLOBAL		0
++#  endif
++#endif
+ 
+-openbsd*)
+-  version_type=sunos
+-  sys_lib_dlsearch_path_spec="/usr/lib"
+-  need_lib_prefix=no
+-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+-  case $host_os in
+-    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+-    *)                         need_version=no  ;;
+-  esac
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-    case $host_os in
+-      openbsd2.[[89]] | openbsd2.[[89]].*)
+-	shlibpath_overrides_runpath=no
+-	;;
+-      *)
+-	shlibpath_overrides_runpath=yes
+-	;;
+-      esac
++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
++   find out it does not work in some platform. */
++#ifndef LT_DLLAZY_OR_NOW
++#  ifdef RTLD_LAZY
++#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
++#  else
++#    ifdef DL_LAZY
++#      define LT_DLLAZY_OR_NOW		DL_LAZY
++#    else
++#      ifdef RTLD_NOW
++#        define LT_DLLAZY_OR_NOW	RTLD_NOW
++#      else
++#        ifdef DL_NOW
++#          define LT_DLLAZY_OR_NOW	DL_NOW
++#        else
++#          define LT_DLLAZY_OR_NOW	0
++#        endif
++#      endif
++#    endif
++#  endif
++#endif
++
++#ifdef __cplusplus
++extern "C" void exit (int);
++#endif
++
++void fnord() { int i=42;}
++int main ()
++{
++  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
++  int status = $lt_dlunknown;
++
++  if (self)
++    {
++      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
++      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
++      /* dlclose (self); */
++    }
+   else
+-    shlibpath_overrides_runpath=yes
++    puts (dlerror ());
++
++    exit (status);
++}]
++_LT_EOF
++  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
++    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
++    lt_status=$?
++    case x$lt_status in
++      x$lt_dlno_uscore) $1 ;;
++      x$lt_dlneed_uscore) $2 ;;
++      x$lt_dlunknown|x*) $3 ;;
++    esac
++  else :
++    # compilation failed
++    $3
+   fi
+-  ;;
++fi
++rm -fr conftest*
++])# _LT_TRY_DLOPEN_SELF
+ 
+-os2*)
+-  libname_spec='$name'
+-  shrext_cmds=".dll"
+-  need_lib_prefix=no
+-  library_names_spec='$libname${shared_ext} $libname.a'
+-  dynamic_linker='OS/2 ld.exe'
+-  shlibpath_var=LIBPATH
+-  ;;
+ 
+-osf3* | osf4* | osf5*)
+-  version_type=osf
+-  need_lib_prefix=no
+-  need_version=no
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+-  ;;
++# LT_SYS_DLOPEN_SELF
++# ------------------
++AC_DEFUN([LT_SYS_DLOPEN_SELF],
++[m4_require([_LT_HEADER_DLFCN])dnl
++if test "x$enable_dlopen" != xyes; then
++  enable_dlopen=unknown
++  enable_dlopen_self=unknown
++  enable_dlopen_self_static=unknown
++else
++  lt_cv_dlopen=no
++  lt_cv_dlopen_libs=
+ 
+-solaris*)
+-  version_type=linux
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  hardcode_into_libs=yes
+-  # ldd complains unless libraries are executable
+-  postinstall_cmds='chmod +x $lib'
+-  ;;
++  case $host_os in
++  beos*)
++    lt_cv_dlopen="load_add_on"
++    lt_cv_dlopen_libs=
++    lt_cv_dlopen_self=yes
++    ;;
+ 
+-sunos4*)
+-  version_type=sunos
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  shlibpath_overrides_runpath=yes
+-  if test "$with_gnu_ld" = yes; then
+-    need_lib_prefix=no
+-  fi
+-  need_version=yes
+-  ;;
++  mingw* | pw32*)
++    lt_cv_dlopen="LoadLibrary"
++    lt_cv_dlopen_libs=
++    ;;
+ 
+-sysv4 | sysv4.3*)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  case $host_vendor in
+-    sni)
+-      shlibpath_overrides_runpath=no
+-      need_lib_prefix=no
+-      export_dynamic_flag_spec='${wl}-Blargedynsym'
+-      runpath_var=LD_RUN_PATH
+-      ;;
+-    siemens)
+-      need_lib_prefix=no
+-      ;;
+-    motorola)
+-      need_lib_prefix=no
+-      need_version=no
+-      shlibpath_overrides_runpath=no
+-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+-      ;;
+-  esac
+-  ;;
++  cygwin*)
++    lt_cv_dlopen="dlopen"
++    lt_cv_dlopen_libs=
++    ;;
+ 
+-sysv4*MP*)
+-  if test -d /usr/nec ;then
+-    version_type=linux
+-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+-    soname_spec='$libname${shared_ext}.$major'
+-    shlibpath_var=LD_LIBRARY_PATH
+-  fi
+-  ;;
++  darwin*)
++  # if libdl is installed we need to link against it
++    AC_CHECK_LIB([dl], [dlopen],
++		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
++    lt_cv_dlopen="dyld"
++    lt_cv_dlopen_libs=
++    lt_cv_dlopen_self=yes
++    ])
++    ;;
+ 
+-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+-  version_type=freebsd-elf
+-  need_lib_prefix=no
+-  need_version=no
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  hardcode_into_libs=yes
+-  if test "$with_gnu_ld" = yes; then
+-    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+-    shlibpath_overrides_runpath=no
++  *)
++    AC_CHECK_FUNC([shl_load],
++	  [lt_cv_dlopen="shl_load"],
++      [AC_CHECK_LIB([dld], [shl_load],
++	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
++	[AC_CHECK_FUNC([dlopen],
++	      [lt_cv_dlopen="dlopen"],
++	  [AC_CHECK_LIB([dl], [dlopen],
++		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
++	    [AC_CHECK_LIB([svld], [dlopen],
++		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
++	      [AC_CHECK_LIB([dld], [dld_link],
++		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
++	      ])
++	    ])
++	  ])
++	])
++      ])
++    ;;
++  esac
++
++  if test "x$lt_cv_dlopen" != xno; then
++    enable_dlopen=yes
+   else
+-    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+-    shlibpath_overrides_runpath=yes
+-    case $host_os in
+-      sco3.2v5*)
+-        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+-	;;
+-    esac
++    enable_dlopen=no
+   fi
+-  sys_lib_dlsearch_path_spec='/usr/lib'
+-  ;;
+-
+-uts4*)
+-  version_type=linux
+-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+-  soname_spec='${libname}${release}${shared_ext}$major'
+-  shlibpath_var=LD_LIBRARY_PATH
+-  ;;
+-
+-*)
+-  dynamic_linker=no
+-  ;;
+-esac
+-AC_MSG_RESULT([$dynamic_linker])
+-test "$dynamic_linker" = no && can_build_shared=no
+-
+-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+-if test "$GCC" = yes; then
+-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+-fi
+-])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+-
+ 
+-# _LT_AC_TAGCONFIG
+-# ----------------
+-AC_DEFUN([_LT_AC_TAGCONFIG],
+-[AC_ARG_WITH([tags],
+-    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+-        [include additional configurations @<:@automatic@:>@])],
+-    [tagnames="$withval"])
+-
+-if test -f "$ltmain" && test -n "$tagnames"; then
+-  if test ! -f "${ofile}"; then
+-    AC_MSG_WARN([output file `$ofile' does not exist])
+-  fi
++  case $lt_cv_dlopen in
++  dlopen)
++    save_CPPFLAGS="$CPPFLAGS"
++    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ 
+-  if test -z "$LTCC"; then
+-    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+-    if test -z "$LTCC"; then
+-      AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+-    else
+-      AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+-    fi
+-  fi
+-  if test -z "$LTCFLAGS"; then
+-    eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+-  fi
++    save_LDFLAGS="$LDFLAGS"
++    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+ 
+-  # Extract list of available tagged configurations in $ofile.
+-  # Note that this assumes the entire list is on one line.
+-  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
++    save_LIBS="$LIBS"
++    LIBS="$lt_cv_dlopen_libs $LIBS"
+ 
+-  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-  for tagname in $tagnames; do
+-    IFS="$lt_save_ifs"
+-    # Check whether tagname contains only valid characters
+-    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+-    "") ;;
+-    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+-	;;
+-    esac
++    AC_CACHE_CHECK([whether a program can dlopen itself],
++	  lt_cv_dlopen_self, [dnl
++	  _LT_TRY_DLOPEN_SELF(
++	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
++	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
++    ])
+ 
+-    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+-    then
+-      AC_MSG_ERROR([tag name \"$tagname\" already exists])
++    if test "x$lt_cv_dlopen_self" = xyes; then
++      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
++      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
++	  lt_cv_dlopen_self_static, [dnl
++	  _LT_TRY_DLOPEN_SELF(
++	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
++	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
++      ])
+     fi
+ 
+-    # Update the list of available tags.
+-    if test -n "$tagname"; then
+-      echo appending configuration tag \"$tagname\" to $ofile
+-
+-      case $tagname in
+-      CXX)
+-	if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+-	    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+-	    (test "X$CXX" != "Xg++"))) ; then
+-	  AC_LIBTOOL_LANG_CXX_CONFIG
+-	else
+-	  tagname=""
+-	fi
+-	;;
+-
+-      F77)
+-	if test -n "$F77" && test "X$F77" != "Xno"; then
+-	  AC_LIBTOOL_LANG_F77_CONFIG
+-	else
+-	  tagname=""
+-	fi
+-	;;
+-
+-      GCJ)
+-	if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+-	  AC_LIBTOOL_LANG_GCJ_CONFIG
+-	else
+-	  tagname=""
+-	fi
+-	;;
+-
+-      RC)
+-	AC_LIBTOOL_LANG_RC_CONFIG
+-	;;
+-
+-      *)
+-	AC_MSG_ERROR([Unsupported tag name: $tagname])
+-	;;
+-      esac
++    CPPFLAGS="$save_CPPFLAGS"
++    LDFLAGS="$save_LDFLAGS"
++    LIBS="$save_LIBS"
++    ;;
++  esac
+ 
+-      # Append the new tag name to the list of available tags.
+-      if test -n "$tagname" ; then
+-      available_tags="$available_tags $tagname"
+-    fi
+-    fi
+-  done
+-  IFS="$lt_save_ifs"
++  case $lt_cv_dlopen_self in
++  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
++  *) enable_dlopen_self=unknown ;;
++  esac
+ 
+-  # Now substitute the updated list of available tags.
+-  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+-    mv "${ofile}T" "$ofile"
+-    chmod +x "$ofile"
+-  else
+-    rm -f "${ofile}T"
+-    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+-  fi
++  case $lt_cv_dlopen_self_static in
++  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
++  *) enable_dlopen_self_static=unknown ;;
++  esac
+ fi
+-])# _LT_AC_TAGCONFIG
++_LT_DECL([dlopen_support], [enable_dlopen], [0],
++	 [Whether dlopen is supported])
++_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
++	 [Whether dlopen of programs is supported])
++_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
++	 [Whether dlopen of statically linked programs is supported])
++])# LT_SYS_DLOPEN_SELF
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+ 
+ 
+-# AC_LIBTOOL_DLOPEN
+-# -----------------
+-# enable checks for dlopen support
+-AC_DEFUN([AC_LIBTOOL_DLOPEN],
+- [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+-])# AC_LIBTOOL_DLOPEN
++# _LT_COMPILER_C_O([TAGNAME])
++# ---------------------------
++# Check to see if options -c and -o are simultaneously supported by compiler.
++# This macro does not hard code the compiler like AC_PROG_CC_C_O.
++m4_defun([_LT_COMPILER_C_O],
++[m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
++  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
++  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
++   $RM -r conftest 2>/dev/null
++   mkdir conftest
++   cd conftest
++   mkdir out
++   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
++   lt_compiler_flag="-o out/conftest2.$ac_objext"
++   # Insert the option either (1) after the last *FLAGS variable, or
++   # (2) before a word containing "conftest.", or (3) at the end.
++   # Note that $ac_compile itself does not contain backslashes and begins
++   # with a dollar sign (not a hyphen), so the echo should work correctly.
++   lt_compile=`echo "$ac_compile" | $SED \
++   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
++   -e 's:$: $lt_compiler_flag:'`
++   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
++   (eval "$lt_compile" 2>out/conftest.err)
++   ac_status=$?
++   cat out/conftest.err >&AS_MESSAGE_LOG_FD
++   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
++   if (exit $ac_status) && test -s out/conftest2.$ac_objext
++   then
++     # The compiler can only warn and ignore the option if not recognized
++     # So say no if there are warnings
++     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
++     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
++     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
++       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
++     fi
++   fi
++   chmod u+w . 2>&AS_MESSAGE_LOG_FD
++   $RM conftest*
++   # SGI C++ compiler will create directory out/ii_files/ for
++   # template instantiation
++   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
++   $RM out/* && rmdir out
++   cd ..
++   $RM -r conftest
++   $RM conftest*
++])
++_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
++	[Does compiler simultaneously support -c and -o options?])
++])# _LT_COMPILER_C_O
+ 
+-# AC_LIBTOOL_WIN32_DLL
+-# --------------------
+-# declare package support for building win32 DLLs
+-AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+-[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+-])# AC_LIBTOOL_WIN32_DLL
+ 
++# _LT_COMPILER_FILE_LOCKS([TAGNAME])
++# ----------------------------------
++# Check to see if we can do hard links to lock some files if needed
++m4_defun([_LT_COMPILER_FILE_LOCKS],
++[m4_require([_LT_ENABLE_LOCK])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++_LT_COMPILER_C_O([$1])
+ 
+-# AC_ENABLE_SHARED([DEFAULT])
+-# ---------------------------
+-# implement the --enable-shared flag
+-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+-AC_DEFUN([AC_ENABLE_SHARED],
+-[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+-AC_ARG_ENABLE([shared],
+-    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+-	[build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+-    [p=${PACKAGE-default}
+-    case $enableval in
+-    yes) enable_shared=yes ;;
+-    no) enable_shared=no ;;
+-    *)
+-      enable_shared=no
+-      # Look at the argument we got.  We use all the common list separators.
+-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-      for pkg in $enableval; do
+-	IFS="$lt_save_ifs"
+-	if test "X$pkg" = "X$p"; then
+-	  enable_shared=yes
+-	fi
+-      done
+-      IFS="$lt_save_ifs"
+-      ;;
+-    esac],
+-    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+-])# AC_ENABLE_SHARED
+-
+-
+-# AC_DISABLE_SHARED
+-# -----------------
+-# set the default shared flag to --disable-shared
+-AC_DEFUN([AC_DISABLE_SHARED],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-AC_ENABLE_SHARED(no)
+-])# AC_DISABLE_SHARED
+-
+-
+-# AC_ENABLE_STATIC([DEFAULT])
+-# ---------------------------
+-# implement the --enable-static flag
+-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+-AC_DEFUN([AC_ENABLE_STATIC],
+-[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+-AC_ARG_ENABLE([static],
+-    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+-	[build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+-    [p=${PACKAGE-default}
+-    case $enableval in
+-    yes) enable_static=yes ;;
+-    no) enable_static=no ;;
+-    *)
+-     enable_static=no
+-      # Look at the argument we got.  We use all the common list separators.
+-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-      for pkg in $enableval; do
+-	IFS="$lt_save_ifs"
+-	if test "X$pkg" = "X$p"; then
+-	  enable_static=yes
+-	fi
+-      done
+-      IFS="$lt_save_ifs"
+-      ;;
+-    esac],
+-    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+-])# AC_ENABLE_STATIC
+-
+-
+-# AC_DISABLE_STATIC
+-# -----------------
+-# set the default static flag to --disable-static
+-AC_DEFUN([AC_DISABLE_STATIC],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-AC_ENABLE_STATIC(no)
+-])# AC_DISABLE_STATIC
+-
+-
+-# AC_ENABLE_FAST_INSTALL([DEFAULT])
+-# ---------------------------------
+-# implement the --enable-fast-install flag
+-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+-AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+-[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+-AC_ARG_ENABLE([fast-install],
+-    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+-    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+-    [p=${PACKAGE-default}
+-    case $enableval in
+-    yes) enable_fast_install=yes ;;
+-    no) enable_fast_install=no ;;
+-    *)
+-      enable_fast_install=no
+-      # Look at the argument we got.  We use all the common list separators.
+-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+-      for pkg in $enableval; do
+-	IFS="$lt_save_ifs"
+-	if test "X$pkg" = "X$p"; then
+-	  enable_fast_install=yes
+-	fi
+-      done
+-      IFS="$lt_save_ifs"
+-      ;;
+-    esac],
+-    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+-])# AC_ENABLE_FAST_INSTALL
+-
+-
+-# AC_DISABLE_FAST_INSTALL
+-# -----------------------
+-# set the default to --disable-fast-install
+-AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-AC_ENABLE_FAST_INSTALL(no)
+-])# AC_DISABLE_FAST_INSTALL
+-
+-
+-# AC_LIBTOOL_PICMODE([MODE])
+-# --------------------------
+-# implement the --with-pic flag
+-# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+-AC_DEFUN([AC_LIBTOOL_PICMODE],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-pic_mode=ifelse($#,1,$1,default)
+-])# AC_LIBTOOL_PICMODE
+-
+-
+-# AC_PROG_EGREP
+-# -------------
+-# This is predefined starting with Autoconf 2.54, so this conditional
+-# definition can be removed once we require Autoconf 2.54 or later.
+-m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+-[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+-   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+-    then ac_cv_prog_egrep='grep -E'
+-    else ac_cv_prog_egrep='egrep'
+-    fi])
+- EGREP=$ac_cv_prog_egrep
+- AC_SUBST([EGREP])
+-])])
+-
+-
+-# AC_PATH_TOOL_PREFIX
+-# -------------------
+-# find a file program which can recognise shared library
+-AC_DEFUN([AC_PATH_TOOL_PREFIX],
+-[AC_REQUIRE([AC_PROG_EGREP])dnl
+-AC_MSG_CHECKING([for $1])
+-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+-[case $MAGIC_CMD in
+-[[\\/*] |  ?:[\\/]*])
+-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+-  ;;
+-*)
+-  lt_save_MAGIC_CMD="$MAGIC_CMD"
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-dnl $ac_dummy forces splitting on constant user-supplied paths.
+-dnl POSIX.2 word splitting is done only on the output of word expansions,
+-dnl not every word.  This closes a longstanding sh security hole.
+-  ac_dummy="ifelse([$2], , $PATH, [$2])"
+-  for ac_dir in $ac_dummy; do
+-    IFS="$lt_save_ifs"
+-    test -z "$ac_dir" && ac_dir=.
+-    if test -f $ac_dir/$1; then
+-      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+-      if test -n "$file_magic_test_file"; then
+-	case $deplibs_check_method in
+-	"file_magic "*)
+-	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+-	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+-	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+-	    $EGREP "$file_magic_regex" > /dev/null; then
+-	    :
+-	  else
+-	    cat <<EOF 1>&2
++hard_links="nottested"
++if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
++  # do not overwrite the value of need_locks provided by the user
++  AC_MSG_CHECKING([if we can lock with hard links])
++  hard_links=yes
++  $RM conftest*
++  ln conftest.a conftest.b 2>/dev/null && hard_links=no
++  touch conftest.a
++  ln conftest.a conftest.b 2>&5 || hard_links=no
++  ln conftest.a conftest.b 2>/dev/null && hard_links=no
++  AC_MSG_RESULT([$hard_links])
++  if test "$hard_links" = no; then
++    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
++    need_locks=warn
++  fi
++else
++  need_locks=no
++fi
++_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
++])# _LT_COMPILER_FILE_LOCKS
+ 
+-*** Warning: the command libtool uses to detect shared libraries,
+-*** $file_magic_cmd, produces output that libtool cannot recognize.
+-*** The result is that libtool may fail to recognize shared libraries
+-*** as such.  This will affect the creation of libtool libraries that
+-*** depend on shared libraries, but programs linked with such libtool
+-*** libraries will work regardless of this problem.  Nevertheless, you
+-*** may want to report the problem to your system manager and/or to
+-*** bug-libtool@gnu.org
+ 
+-EOF
+-	  fi ;;
+-	esac
+-      fi
+-      break
+-    fi
+-  done
+-  IFS="$lt_save_ifs"
+-  MAGIC_CMD="$lt_save_MAGIC_CMD"
+-  ;;
+-esac])
+-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+-if test -n "$MAGIC_CMD"; then
+-  AC_MSG_RESULT($MAGIC_CMD)
++# _LT_CHECK_OBJDIR
++# ----------------
++m4_defun([_LT_CHECK_OBJDIR],
++[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
++[rm -f .libs 2>/dev/null
++mkdir .libs 2>/dev/null
++if test -d .libs; then
++  lt_cv_objdir=.libs
+ else
+-  AC_MSG_RESULT(no)
++  # MS-DOS does not allow filenames that begin with a dot.
++  lt_cv_objdir=_libs
+ fi
+-])# AC_PATH_TOOL_PREFIX
++rmdir .libs 2>/dev/null])
++objdir=$lt_cv_objdir
++_LT_DECL([], [objdir], [0],
++         [The name of the directory that contains temporary libtool files])dnl
++m4_pattern_allow([LT_OBJDIR])dnl
++AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
++  [Define to the sub-directory in which libtool stores uninstalled libraries.])
++])# _LT_CHECK_OBJDIR
+ 
+ 
+-# AC_PATH_MAGIC
+-# -------------
+-# find a file program which can recognise a shared library
+-AC_DEFUN([AC_PATH_MAGIC],
+-[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+-if test -z "$lt_cv_path_MAGIC_CMD"; then
+-  if test -n "$ac_tool_prefix"; then
+-    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
++# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
++# --------------------------------------
++# Check hardcoding attributes.
++m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
++[AC_MSG_CHECKING([how to hardcode library paths into programs])
++_LT_TAGVAR(hardcode_action, $1)=
++if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
++   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
++   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
++
++  # We can hardcode non-existent directories.
++  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
++     # If the only mechanism to avoid hardcoding is shlibpath_var, we
++     # have to relink, otherwise we might link with an installed library
++     # when we should be linking with a yet-to-be-installed one
++     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
++     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
++    # Linking always hardcodes the temporary library directory.
++    _LT_TAGVAR(hardcode_action, $1)=relink
+   else
+-    MAGIC_CMD=:
++    # We can link without hardcoding, and we can hardcode nonexisting dirs.
++    _LT_TAGVAR(hardcode_action, $1)=immediate
+   fi
++else
++  # We cannot hardcode anything, or else we can only hardcode existing
++  # directories.
++  _LT_TAGVAR(hardcode_action, $1)=unsupported
++fi
++AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
++
++if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
++   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
++  # Fast installation is not supported
++  enable_fast_install=no
++elif test "$shlibpath_overrides_runpath" = yes ||
++     test "$enable_shared" = no; then
++  # Fast installation is not necessary
++  enable_fast_install=needless
+ fi
+-])# AC_PATH_MAGIC
++_LT_TAGDECL([], [hardcode_action], [0],
++    [How to hardcode a shared library path into an executable])
++])# _LT_LINKER_HARDCODE_LIBPATH
+ 
+ 
+-# AC_PROG_LD
+-# ----------
+-# find the pathname to the GNU or non-GNU linker
+-AC_DEFUN([AC_PROG_LD],
+-[AC_ARG_WITH([gnu-ld],
+-    [AC_HELP_STRING([--with-gnu-ld],
+-	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+-    [test "$withval" = no || with_gnu_ld=yes],
+-    [with_gnu_ld=no])
+-AC_REQUIRE([LT_AC_PROG_SED])dnl
+-AC_REQUIRE([AC_PROG_CC])dnl
+-AC_REQUIRE([AC_CANONICAL_HOST])dnl
+-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+-ac_prog=ld
+-if test "$GCC" = yes; then
+-  # Check if gcc -print-prog-name=ld gives a path.
+-  AC_MSG_CHECKING([for ld used by $CC])
+-  case $host in
+-  *-*-mingw*)
+-    # gcc leaves a trailing carriage return which upsets mingw
+-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+-  *)
+-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+-  esac
+-  case $ac_prog in
+-    # Accept absolute paths.
+-    [[\\/]]* | ?:[[\\/]]*)
+-      re_direlt='/[[^/]][[^/]]*/\.\./'
+-      # Canonicalize the pathname of ld
+-      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+-      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+-	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+-      done
+-      test -z "$LD" && LD="$ac_prog"
+-      ;;
+-  "")
+-    # If it fails, then pretend we aren't using GCC.
+-    ac_prog=ld
++# _LT_CMD_STRIPLIB
++# ----------------
++m4_defun([_LT_CMD_STRIPLIB],
++[m4_require([_LT_DECL_EGREP])
++striplib=
++old_striplib=
++AC_MSG_CHECKING([whether stripping libraries is possible])
++if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
++  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
++  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
++  AC_MSG_RESULT([yes])
++else
++# FIXME - insert some real tests, host_os isn't really good enough
++  case $host_os in
++  darwin*)
++    if test -n "$STRIP" ; then
++      striplib="$STRIP -x"
++      old_striplib="$STRIP -S"
++      AC_MSG_RESULT([yes])
++    else
++      AC_MSG_RESULT([no])
++    fi
+     ;;
+   *)
+-    # If it is relative, then search for the first ld in PATH.
+-    with_gnu_ld=unknown
++    AC_MSG_RESULT([no])
+     ;;
+   esac
+-elif test "$with_gnu_ld" = yes; then
+-  AC_MSG_CHECKING([for GNU ld])
+-else
+-  AC_MSG_CHECKING([for non-GNU ld])
+ fi
+-AC_CACHE_VAL(lt_cv_path_LD,
+-[if test -z "$LD"; then
+-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-  for ac_dir in $PATH; do
+-    IFS="$lt_save_ifs"
+-    test -z "$ac_dir" && ac_dir=.
+-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+-      lt_cv_path_LD="$ac_dir/$ac_prog"
+-      # Check to see if the program is GNU ld.  I'd rather use --version,
+-      # but apparently some variants of GNU ld only accept -v.
+-      # Break only if it was the GNU/non-GNU ld that we prefer.
+-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+-      *GNU* | *'with BFD'*)
+-	test "$with_gnu_ld" != no && break
+-	;;
+-      *)
+-	test "$with_gnu_ld" != yes && break
+-	;;
+-      esac
++_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
++_LT_DECL([], [striplib], [1])
++])# _LT_CMD_STRIPLIB
++
++
++# _LT_SYS_DYNAMIC_LINKER([TAG])
++# -----------------------------
++# PORTME Fill in your ld.so characteristics
++m4_defun([_LT_SYS_DYNAMIC_LINKER],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_MSG_CHECKING([dynamic linker characteristics])
++m4_if([$1],
++	[], [
++if test "$GCC" = yes; then
++  case $host_os in
++    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
++    *) lt_awk_arg="/^libraries:/" ;;
++  esac
++  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
++  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
++    # if the path contains ";" then we assume it to be the separator
++    # otherwise default to the standard path separator (i.e. ":") - it is
++    # assumed that no part of a normal pathname contains ";" but that should
++    # okay in the real world where ";" in dirpaths is itself problematic.
++    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
++  else
++    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
++  fi
++  # Ok, now we have the path, separated by spaces, we can step through it
++  # and add multilib dir if necessary.
++  lt_tmp_lt_search_path_spec=
++  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
++  for lt_sys_path in $lt_search_path_spec; do
++    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
++      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
++    else
++      test -d "$lt_sys_path" && \
++	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+     fi
+   done
+-  IFS="$lt_save_ifs"
++  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
++BEGIN {RS=" "; FS="/|\n";} {
++  lt_foo="";
++  lt_count=0;
++  for (lt_i = NF; lt_i > 0; lt_i--) {
++    if ($lt_i != "" && $lt_i != ".") {
++      if ($lt_i == "..") {
++        lt_count++;
++      } else {
++        if (lt_count == 0) {
++          lt_foo="/" $lt_i lt_foo;
++        } else {
++          lt_count--;
++        }
++      }
++    }
++  }
++  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
++  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
++}'`
++  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+ else
+-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
++  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ fi])
+-LD="$lt_cv_path_LD"
+-if test -n "$LD"; then
+-  AC_MSG_RESULT($LD)
+-else
+-  AC_MSG_RESULT(no)
+-fi
+-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+-AC_PROG_LD_GNU
+-])# AC_PROG_LD
++library_names_spec=
++libname_spec='lib$name'
++soname_spec=
++shrext_cmds=".so"
++postinstall_cmds=
++postuninstall_cmds=
++finish_cmds=
++finish_eval=
++shlibpath_var=
++shlibpath_overrides_runpath=unknown
++version_type=none
++dynamic_linker="$host_os ld.so"
++sys_lib_dlsearch_path_spec="/lib /usr/lib"
++need_lib_prefix=unknown
++hardcode_into_libs=no
++
++# when you set need_version to no, make sure it does not cause -set_version
++# flags to be left without arguments
++need_version=unknown
+ 
++case $host_os in
++aix3*)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
++  shlibpath_var=LIBPATH
+ 
+-# AC_PROG_LD_GNU
+-# --------------
+-AC_DEFUN([AC_PROG_LD_GNU],
+-[AC_REQUIRE([AC_PROG_EGREP])dnl
+-AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+-[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+-case `$LD -v 2>&1 </dev/null` in
+-*GNU* | *'with BFD'*)
+-  lt_cv_prog_gnu_ld=yes
++  # AIX 3 has no versioning support, so we append a major version to the name.
++  soname_spec='${libname}${release}${shared_ext}$major'
+   ;;
+-*)
+-  lt_cv_prog_gnu_ld=no
+-  ;;
+-esac])
+-with_gnu_ld=$lt_cv_prog_gnu_ld
+-])# AC_PROG_LD_GNU
+-
+ 
+-# AC_PROG_LD_RELOAD_FLAG
+-# ----------------------
+-# find reload flag for linker
+-#   -- PORTME Some linkers may need a different reload flag.
+-AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+-[AC_CACHE_CHECK([for $LD option to reload object files],
+-  lt_cv_ld_reload_flag,
+-  [lt_cv_ld_reload_flag='-r'])
+-reload_flag=$lt_cv_ld_reload_flag
+-case $reload_flag in
+-"" | " "*) ;;
+-*) reload_flag=" $reload_flag" ;;
+-esac
+-reload_cmds='$LD$reload_flag -o $output$reload_objs'
+-case $host_os in
+-  darwin*)
+-    if test "$GCC" = yes; then
+-      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
++aix[[4-9]]*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  hardcode_into_libs=yes
++  if test "$host_cpu" = ia64; then
++    # AIX 5 supports IA64
++    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
++    shlibpath_var=LD_LIBRARY_PATH
++  else
++    # With GCC up to 2.95.x, collect2 would create an import file
++    # for dependence libraries.  The import file would start with
++    # the line `#! .'.  This would cause the generated library to
++    # depend on `.', always an invalid library.  This was fixed in
++    # development snapshots of GCC prior to 3.0.
++    case $host_os in
++      aix4 | aix4.[[01]] | aix4.[[01]].*)
++      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
++	   echo ' yes '
++	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
++	:
++      else
++	can_build_shared=no
++      fi
++      ;;
++    esac
++    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
++    # soname into executable. Probably we can add versioning support to
++    # collect2, so additional links can be useful in future.
++    if test "$aix_use_runtimelinking" = yes; then
++      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
++      # instead of lib<name>.a to let people know that these are not
++      # typical AIX shared libraries.
++      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     else
+-      reload_cmds='$LD$reload_flag -o $output$reload_objs'
++      # We preserve .a as extension for shared libraries through AIX4.2
++      # and later when we are not doing run time linking.
++      library_names_spec='${libname}${release}.a $libname.a'
++      soname_spec='${libname}${release}${shared_ext}$major'
+     fi
+-    ;;
+-esac
+-])# AC_PROG_LD_RELOAD_FLAG
+-
+-
+-# AC_DEPLIBS_CHECK_METHOD
+-# -----------------------
+-# how to check for library dependencies
+-#  -- PORTME fill in with the dynamic library characteristics
+-AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+-[AC_CACHE_CHECK([how to recognise dependent libraries],
+-lt_cv_deplibs_check_method,
+-[lt_cv_file_magic_cmd='$MAGIC_CMD'
+-lt_cv_file_magic_test_file=
+-lt_cv_deplibs_check_method='unknown'
+-# Need to set the preceding variable on all platforms that support
+-# interlibrary dependencies.
+-# 'none' -- dependencies not supported.
+-# `unknown' -- same as none, but documents that we really don't know.
+-# 'pass_all' -- all dependencies passed with no checks.
+-# 'test_compile' -- check by making test program.
+-# 'file_magic [[regex]]' -- check by looking for files in library path
+-# which responds to the $file_magic_cmd with a given extended regex.
+-# If you have `file' or equivalent on your system and you're not sure
+-# whether `pass_all' will *always* work, you probably want this one.
++    shlibpath_var=LIBPATH
++  fi
++  ;;
+ 
+-case $host_os in
+-aix4* | aix5*)
+-  lt_cv_deplibs_check_method=pass_all
++amigaos*)
++  case $host_cpu in
++  powerpc)
++    # Since July 2007 AmigaOS4 officially supports .so libraries.
++    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    ;;
++  m68k)
++    library_names_spec='$libname.ixlibrary $libname.a'
++    # Create ${libname}_ixlibrary.a entries in /sys/libs.
++    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
++    ;;
++  esac
+   ;;
+ 
+ beos*)
+-  lt_cv_deplibs_check_method=pass_all
++  library_names_spec='${libname}${shared_ext}'
++  dynamic_linker="$host_os ld.so"
++  shlibpath_var=LIBRARY_PATH
+   ;;
+ 
+ bsdi[[45]]*)
+-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+-  lt_cv_file_magic_cmd='/usr/bin/file -L'
+-  lt_cv_file_magic_test_file=/shlib/libc.so
+-  ;;
+-
+-cygwin*)
+-  # func_win32_libid is a shell function defined in ltmain.sh
+-  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+-  lt_cv_file_magic_cmd='func_win32_libid'
++  version_type=linux
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
++  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
++  # the default ld.so.conf also contains /usr/contrib/lib and
++  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
++  # libtool to hard-code these into programs
+   ;;
+ 
+-mingw* | pw32*)
+-  # Base MSYS/MinGW do not provide the 'file' command needed by
+-  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+-  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+-  lt_cv_file_magic_cmd='$OBJDUMP -f'
+-  ;;
++cygwin* | mingw* | pw32*)
++  version_type=windows
++  shrext_cmds=".dll"
++  need_version=no
++  need_lib_prefix=no
+ 
+-darwin* | rhapsody*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
++  case $GCC,$host_os in
++  yes,cygwin* | yes,mingw* | yes,pw32*)
++    library_names_spec='$libname.dll.a'
++    # DLL is installed to $(libdir)/../bin by postinstall_cmds
++    postinstall_cmds='base_file=`basename \${file}`~
++      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
++      dldir=$destdir/`dirname \$dlpath`~
++      test -d \$dldir || mkdir -p \$dldir~
++      $install_prog $dir/$dlname \$dldir/$dlname~
++      chmod a+x \$dldir/$dlname~
++      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
++        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
++      fi'
++    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
++      dlpath=$dir/\$dldll~
++       $RM \$dlpath'
++    shlibpath_overrides_runpath=yes
+ 
+-freebsd* | kfreebsd*-gnu | dragonfly*)
+-  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+-    case $host_cpu in
+-    i*86 )
+-      # Not sure whether the presence of OpenBSD here was a mistake.
+-      # Let's accept both of them until this is cleared up.
+-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+-      lt_cv_file_magic_cmd=/usr/bin/file
+-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
++    case $host_os in
++    cygwin*)
++      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
++      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
++      ;;
++    mingw*)
++      # MinGW DLLs use traditional 'lib' prefix
++      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
++      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
++        # It is most probably a Windows format PATH printed by
++        # mingw gcc, but we are running on Cygwin. Gcc prints its search
++        # path with ; separators, and with drive letters. We can handle the
++        # drive letters (cygwin fileutils understands them), so leave them,
++        # especially as we might pass files found there to a mingw objdump,
++        # which wouldn't understand a cygwinified path. Ahh.
++        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
++      else
++        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
++      fi
++      ;;
++    pw32*)
++      # pw32 DLLs use 'pw' prefix rather than 'lib'
++      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+       ;;
+     esac
+-  else
+-    lt_cv_deplibs_check_method=pass_all
+-  fi
+-  ;;
+-
+-gnu*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-hpux10.20* | hpux11*)
+-  lt_cv_file_magic_cmd=/usr/bin/file
+-  case $host_cpu in
+-  ia64*)
+-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+-    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+-    ;;
+-  hppa*64*)
+-    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+-    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+     ;;
++
+   *)
+-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+-    lt_cv_file_magic_test_file=/usr/lib/libc.sl
++    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+     ;;
+   esac
++  dynamic_linker='Win32 ld.exe'
++  # FIXME: first we should search . and the directory the executable is in
++  shlibpath_var=PATH
+   ;;
+ 
+-interix3*)
+-  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+-  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+-  ;;
+-
+-irix5* | irix6* | nonstopux*)
+-  case $LD in
+-  *-32|*"-32 ") libmagic=32-bit;;
+-  *-n32|*"-n32 ") libmagic=N32;;
+-  *-64|*"-64 ") libmagic=64-bit;;
+-  *) libmagic=never-match;;
+-  esac
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-# This must be Linux ELF.
+-linux*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-netbsd*)
+-  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+-  else
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+-  fi
++darwin* | rhapsody*)
++  dynamic_linker="$host_os dyld"
++  version_type=darwin
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
++  soname_spec='${libname}${release}${major}$shared_ext'
++  shlibpath_overrides_runpath=yes
++  shlibpath_var=DYLD_LIBRARY_PATH
++  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
++m4_if([$1], [],[
++  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
++  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+   ;;
+ 
+-newos6*)
+-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+-  lt_cv_file_magic_cmd=/usr/bin/file
+-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
++dgux*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
+   ;;
+ 
+-nto-qnx*)
+-  lt_cv_deplibs_check_method=unknown
++freebsd1*)
++  dynamic_linker=no
+   ;;
+ 
+-openbsd*)
+-  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
++freebsd* | dragonfly*)
++  # DragonFly does not have aout.  When/if they implement a new
++  # versioning mechanism, adjust this.
++  if test -x /usr/bin/objformat; then
++    objformat=`/usr/bin/objformat`
+   else
+-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++    case $host_os in
++    freebsd[[123]]*) objformat=aout ;;
++    *) objformat=elf ;;
++    esac
+   fi
+-  ;;
+-
+-osf3* | osf4* | osf5*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-solaris*)
+-  lt_cv_deplibs_check_method=pass_all
+-  ;;
+-
+-sysv4 | sysv4.3*)
+-  case $host_vendor in
+-  motorola)
+-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+-    ;;
+-  ncr)
+-    lt_cv_deplibs_check_method=pass_all
+-    ;;
+-  sequent)
+-    lt_cv_file_magic_cmd='/bin/file'
+-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
++  version_type=freebsd-$objformat
++  case $version_type in
++    freebsd-elf*)
++      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++      need_version=no
++      need_lib_prefix=no
++      ;;
++    freebsd-*)
++      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
++      need_version=yes
++      ;;
++  esac
++  shlibpath_var=LD_LIBRARY_PATH
++  case $host_os in
++  freebsd2*)
++    shlibpath_overrides_runpath=yes
+     ;;
+-  sni)
+-    lt_cv_file_magic_cmd='/bin/file'
+-    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+-    lt_cv_file_magic_test_file=/lib/libc.so
++  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
++    shlibpath_overrides_runpath=yes
++    hardcode_into_libs=yes
+     ;;
+-  siemens)
+-    lt_cv_deplibs_check_method=pass_all
++  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
++  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
++    shlibpath_overrides_runpath=no
++    hardcode_into_libs=yes
+     ;;
+-  pc)
+-    lt_cv_deplibs_check_method=pass_all
++  *) # from 4.6 on, and DragonFly
++    shlibpath_overrides_runpath=yes
++    hardcode_into_libs=yes
+     ;;
+   esac
+   ;;
+ 
+-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+-  lt_cv_deplibs_check_method=pass_all
++gnu*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  hardcode_into_libs=yes
+   ;;
+-esac
+-])
+-file_magic_cmd=$lt_cv_file_magic_cmd
+-deplibs_check_method=$lt_cv_deplibs_check_method
+-test -z "$deplibs_check_method" && deplibs_check_method=unknown
+-])# AC_DEPLIBS_CHECK_METHOD
+ 
+-
+-# AC_PROG_NM
+-# ----------
+-# find the pathname to a BSD-compatible name lister
+-AC_DEFUN([AC_PROG_NM],
+-[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+-[if test -n "$NM"; then
+-  # Let the user override the test.
+-  lt_cv_path_NM="$NM"
+-else
+-  lt_nm_to_check="${ac_tool_prefix}nm"
+-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then 
+-    lt_nm_to_check="$lt_nm_to_check nm"
+-  fi
+-  for lt_tmp_nm in $lt_nm_to_check; do
+-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+-      IFS="$lt_save_ifs"
+-      test -z "$ac_dir" && ac_dir=.
+-      tmp_nm="$ac_dir/$lt_tmp_nm"
+-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+-	# Check to see if the nm accepts a BSD-compat flag.
+-	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+-	#   nm: unknown option "B" ignored
+-	# Tru64's nm complains that /dev/null is an invalid object file
+-	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+-	*/dev/null* | *'Invalid file or object type'*)
+-	  lt_cv_path_NM="$tmp_nm -B"
+-	  break
+-	  ;;
+-	*)
+-	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+-	  */dev/null*)
+-	    lt_cv_path_NM="$tmp_nm -p"
+-	    break
+-	    ;;
+-	  *)
+-	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+-	    continue # so that we can try to find one that supports BSD flags
+-	    ;;
+-	  esac
+-	  ;;
+-	esac
+-      fi
+-    done
+-    IFS="$lt_save_ifs"
+-  done
+-  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+-fi])
+-NM="$lt_cv_path_NM"
+-])# AC_PROG_NM
+-
+-
+-# AC_CHECK_LIBM
+-# -------------
+-# check for math library
+-AC_DEFUN([AC_CHECK_LIBM],
+-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+-LIBM=
+-case $host in
+-*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+-  # These system don't have libm, or don't need it
+-  ;;
+-*-ncr-sysv4.3*)
+-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+-  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+-  ;;
+-*)
+-  AC_CHECK_LIB(m, cos, LIBM="-lm")
++hpux9* | hpux10* | hpux11*)
++  # Give a soname corresponding to the major version so that dld.sl refuses to
++  # link against other versions.
++  version_type=sunos
++  need_lib_prefix=no
++  need_version=no
++  case $host_cpu in
++  ia64*)
++    shrext_cmds='.so'
++    hardcode_into_libs=yes
++    dynamic_linker="$host_os dld.so"
++    shlibpath_var=LD_LIBRARY_PATH
++    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    if test "X$HPUX_IA64_MODE" = X32; then
++      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
++    else
++      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
++    fi
++    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++    ;;
++  hppa*64*)
++    shrext_cmds='.sl'
++    hardcode_into_libs=yes
++    dynamic_linker="$host_os dld.sl"
++    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
++    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
++    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++    ;;
++  *)
++    shrext_cmds='.sl'
++    dynamic_linker="$host_os dld.sl"
++    shlibpath_var=SHLIB_PATH
++    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    ;;
++  esac
++  # HP-UX runs *really* slowly unless shared libraries are mode 555.
++  postinstall_cmds='chmod 555 $lib'
+   ;;
+-esac
+-])# AC_CHECK_LIBM
+ 
++interix[[3-9]]*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  ;;
+ 
+-# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+-# -----------------------------------
+-# sets LIBLTDL to the link flags for the libltdl convenience library and
+-# LTDLINCL to the include flags for the libltdl header and adds
+-# --enable-ltdl-convenience to the configure arguments.  Note that
+-# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+-# it is assumed to be `libltdl'.  LIBLTDL will be prefixed with
+-# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+-# (note the single quotes!).  If your package is not flat and you're not
+-# using automake, define top_builddir and top_srcdir appropriately in
+-# the Makefiles.
+-AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-  case $enable_ltdl_convenience in
+-  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+-  "") enable_ltdl_convenience=yes
+-      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
++irix5* | irix6* | nonstopux*)
++  case $host_os in
++    nonstopux*) version_type=nonstopux ;;
++    *)
++	if test "$lt_cv_prog_gnu_ld" = yes; then
++		version_type=linux
++	else
++		version_type=irix
++	fi ;;
+   esac
+-  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+-  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+-  # For backwards non-gettext consistent compatibility...
+-  INCLTDL="$LTDLINCL"
+-])# AC_LIBLTDL_CONVENIENCE
+-
+-
+-# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+-# -----------------------------------
+-# sets LIBLTDL to the link flags for the libltdl installable library and
+-# LTDLINCL to the include flags for the libltdl header and adds
+-# --enable-ltdl-install to the configure arguments.  Note that
+-# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+-# and an installed libltdl is not found, it is assumed to be `libltdl'.
+-# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+-# '${top_srcdir}/' (note the single quotes!).  If your package is not
+-# flat and you're not using automake, define top_builddir and top_srcdir
+-# appropriately in the Makefiles.
+-# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+-AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+-  AC_CHECK_LIB(ltdl, lt_dlinit,
+-  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+-  [if test x"$enable_ltdl_install" = xno; then
+-     AC_MSG_WARN([libltdl not installed, but installation disabled])
+-   else
+-     enable_ltdl_install=yes
+-   fi
+-  ])
+-  if test x"$enable_ltdl_install" = x"yes"; then
+-    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+-    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+-    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+-  else
+-    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+-    LIBLTDL="-lltdl"
+-    LTDLINCL=
+-  fi
+-  # For backwards non-gettext consistent compatibility...
+-  INCLTDL="$LTDLINCL"
+-])# AC_LIBLTDL_INSTALLABLE
++  need_lib_prefix=no
++  need_version=no
++  soname_spec='${libname}${release}${shared_ext}$major'
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
++  case $host_os in
++  irix5* | nonstopux*)
++    libsuff= shlibsuff=
++    ;;
++  *)
++    case $LD in # libtool.m4 will add one of these switches to LD
++    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
++      libsuff= shlibsuff= libmagic=32-bit;;
++    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
++      libsuff=32 shlibsuff=N32 libmagic=N32;;
++    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
++      libsuff=64 shlibsuff=64 libmagic=64-bit;;
++    *) libsuff= shlibsuff= libmagic=never-match;;
++    esac
++    ;;
++  esac
++  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
++  shlibpath_overrides_runpath=no
++  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
++  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
++  hardcode_into_libs=yes
++  ;;
+ 
++# No shared lib support for Linux oldld, aout, or coff.
++linux*oldld* | linux*aout* | linux*coff*)
++  dynamic_linker=no
++  ;;
+ 
+-# AC_LIBTOOL_CXX
+-# --------------
+-# enable support for C++ libraries
+-AC_DEFUN([AC_LIBTOOL_CXX],
+-[AC_REQUIRE([_LT_AC_LANG_CXX])
+-])# AC_LIBTOOL_CXX
++# This must be Linux ELF.
++linux* | k*bsd*-gnu)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  # Some binutils ld are patched to set DT_RUNPATH
++  save_LDFLAGS=$LDFLAGS
++  save_libdir=$libdir
++  eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
++       LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
++  AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
++    [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
++       [shlibpath_overrides_runpath=yes])])
++  LDFLAGS=$save_LDFLAGS
++  libdir=$save_libdir
+ 
++  # This implies no fast_install, which is unacceptable.
++  # Some rework will be needed to allow for fast_install
++  # before this can be enabled.
++  hardcode_into_libs=yes
+ 
+-# _LT_AC_LANG_CXX
+-# ---------------
+-AC_DEFUN([_LT_AC_LANG_CXX],
+-[AC_REQUIRE([AC_PROG_CXX])
+-AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+-])# _LT_AC_LANG_CXX
++  # Append ld.so.conf contents to the search path
++  if test -f /etc/ld.so.conf; then
++    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
++    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
++  fi
+ 
+-# _LT_AC_PROG_CXXCPP
+-# ------------------
+-AC_DEFUN([_LT_AC_PROG_CXXCPP],
+-[
+-AC_REQUIRE([AC_PROG_CXX])
+-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+-    (test "X$CXX" != "Xg++"))) ; then
+-  AC_PROG_CXXCPP
+-fi
+-])# _LT_AC_PROG_CXXCPP
+-
+-# AC_LIBTOOL_F77
+-# --------------
+-# enable support for Fortran 77 libraries
+-AC_DEFUN([AC_LIBTOOL_F77],
+-[AC_REQUIRE([_LT_AC_LANG_F77])
+-])# AC_LIBTOOL_F77
+-
+-
+-# _LT_AC_LANG_F77
+-# ---------------
+-AC_DEFUN([_LT_AC_LANG_F77],
+-[AC_REQUIRE([AC_PROG_F77])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+-])# _LT_AC_LANG_F77
+-
+-
+-# AC_LIBTOOL_GCJ
+-# --------------
+-# enable support for GCJ libraries
+-AC_DEFUN([AC_LIBTOOL_GCJ],
+-[AC_REQUIRE([_LT_AC_LANG_GCJ])
+-])# AC_LIBTOOL_GCJ
+-
+-
+-# _LT_AC_LANG_GCJ
+-# ---------------
+-AC_DEFUN([_LT_AC_LANG_GCJ],
+-[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+-  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+-    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+-      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+-	 [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+-	   [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+-])# _LT_AC_LANG_GCJ
+-
+-
+-# AC_LIBTOOL_RC
+-# -------------
+-# enable support for Windows resource files
+-AC_DEFUN([AC_LIBTOOL_RC],
+-[AC_REQUIRE([LT_AC_PROG_RC])
+-_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+-])# AC_LIBTOOL_RC
++  # We used to test for /lib/ld.so.1 and disable shared libraries on
++  # powerpc, because MkLinux only supported shared libraries with the
++  # GNU dynamic linker.  Since this was broken with cross compilers,
++  # most powerpc-linux boxes support dynamic linking these days and
++  # people can always --disable-shared, the test was removed, and we
++  # assume the GNU/Linux dynamic linker is in use.
++  dynamic_linker='GNU/Linux ld.so'
++  ;;
+ 
++netbsd*)
++  version_type=sunos
++  need_lib_prefix=no
++  need_version=no
++  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++    dynamic_linker='NetBSD (a.out) ld.so'
++  else
++    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++    soname_spec='${libname}${release}${shared_ext}$major'
++    dynamic_linker='NetBSD ld.elf_so'
++  fi
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  hardcode_into_libs=yes
++  ;;
+ 
+-# AC_LIBTOOL_LANG_C_CONFIG
+-# ------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+-AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+-[lt_save_CC="$CC"
+-AC_LANG_PUSH(C)
++newsos6)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  ;;
+ 
+-# Source file extension for C test sources.
+-ac_ext=c
++*nto* | *qnx*)
++  version_type=qnx
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  dynamic_linker='ldqnx.so'
++  ;;
+ 
+-# Object file extension for compiled C test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
++openbsd*)
++  version_type=sunos
++  sys_lib_dlsearch_path_spec="/usr/lib"
++  need_lib_prefix=no
++  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
++  case $host_os in
++    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
++    *)				need_version=no  ;;
++  esac
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++    case $host_os in
++      openbsd2.[[89]] | openbsd2.[[89]].*)
++	shlibpath_overrides_runpath=no
++	;;
++      *)
++	shlibpath_overrides_runpath=yes
++	;;
++      esac
++  else
++    shlibpath_overrides_runpath=yes
++  fi
++  ;;
+ 
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="int some_variable = 0;\n"
++os2*)
++  libname_spec='$name'
++  shrext_cmds=".dll"
++  need_lib_prefix=no
++  library_names_spec='$libname${shared_ext} $libname.a'
++  dynamic_linker='OS/2 ld.exe'
++  shlibpath_var=LIBPATH
++  ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code='int main(){return(0);}\n'
++osf3* | osf4* | osf5*)
++  version_type=osf
++  need_lib_prefix=no
++  need_version=no
++  soname_spec='${libname}${release}${shared_ext}$major'
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  shlibpath_var=LD_LIBRARY_PATH
++  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
++  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
++  ;;
+ 
+-_LT_AC_SYS_COMPILER
++rdos*)
++  dynamic_linker=no
++  ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++solaris*)
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  hardcode_into_libs=yes
++  # ldd complains unless libraries are executable
++  postinstall_cmds='chmod +x $lib'
++  ;;
+ 
+-## CAVEAT EMPTOR:
+-## There is no encapsulation within the following macros, do not change
+-## the running order or otherwise move them around unless you know exactly
+-## what you are doing...
+-AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-AC_LIBTOOL_SYS_LIB_STRIP
+-AC_LIBTOOL_DLOPEN_SELF
+-
+-# Report which library types will actually be built
+-AC_MSG_CHECKING([if libtool supports shared libraries])
+-AC_MSG_RESULT([$can_build_shared])
++sunos4*)
++  version_type=sunos
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  if test "$with_gnu_ld" = yes; then
++    need_lib_prefix=no
++  fi
++  need_version=yes
++  ;;
+ 
+-AC_MSG_CHECKING([whether to build shared libraries])
+-test "$can_build_shared" = "no" && enable_shared=no
++sysv4 | sysv4.3*)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  case $host_vendor in
++    sni)
++      shlibpath_overrides_runpath=no
++      need_lib_prefix=no
++      runpath_var=LD_RUN_PATH
++      ;;
++    siemens)
++      need_lib_prefix=no
++      ;;
++    motorola)
++      need_lib_prefix=no
++      need_version=no
++      shlibpath_overrides_runpath=no
++      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
++      ;;
++  esac
++  ;;
+ 
+-# On AIX, shared libraries and static libraries use the same namespace, and
+-# are all built from PIC.
+-case $host_os in
+-aix3*)
+-  test "$enable_shared" = yes && enable_static=no
+-  if test -n "$RANLIB"; then
+-    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+-    postinstall_cmds='$RANLIB $lib'
++sysv4*MP*)
++  if test -d /usr/nec ;then
++    version_type=linux
++    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
++    soname_spec='$libname${shared_ext}.$major'
++    shlibpath_var=LD_LIBRARY_PATH
+   fi
+   ;;
+ 
+-aix4* | aix5*)
+-  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+-    test "$enable_shared" = yes && enable_static=no
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++  version_type=freebsd-elf
++  need_lib_prefix=no
++  need_version=no
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=yes
++  hardcode_into_libs=yes
++  if test "$with_gnu_ld" = yes; then
++    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
++  else
++    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
++    case $host_os in
++      sco3.2v5*)
++        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
++	;;
++    esac
+   fi
+-    ;;
+-esac
+-AC_MSG_RESULT([$enable_shared])
+-
+-AC_MSG_CHECKING([whether to build static libraries])
+-# Make sure either enable_shared or enable_static is yes.
+-test "$enable_shared" = yes || enable_static=yes
+-AC_MSG_RESULT([$enable_static])
+-
+-AC_LIBTOOL_CONFIG($1)
+-
+-AC_LANG_POP
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_C_CONFIG
+-
+-
+-# AC_LIBTOOL_LANG_CXX_CONFIG
+-# --------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+-AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+-[AC_LANG_PUSH(C++)
+-AC_REQUIRE([AC_PROG_CXX])
+-AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+-
+-_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-_LT_AC_TAGVAR(always_export_symbols, $1)=no
+-_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_direct, $1)=no
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+-_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+-_LT_AC_TAGVAR(module_cmds, $1)=
+-_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+-_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+-_LT_AC_TAGVAR(no_undefined_flag, $1)=
+-_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+-
+-# Dependencies to place before and after the object being linked:
+-_LT_AC_TAGVAR(predep_objects, $1)=
+-_LT_AC_TAGVAR(postdep_objects, $1)=
+-_LT_AC_TAGVAR(predeps, $1)=
+-_LT_AC_TAGVAR(postdeps, $1)=
+-_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+-
+-# Source file extension for C++ test sources.
+-ac_ext=cpp
+-
+-# Object file extension for compiled C++ test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
+-
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="int some_variable = 0;\n"
++  sys_lib_dlsearch_path_spec='/usr/lib'
++  ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n'
++tpf*)
++  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
++  version_type=linux
++  need_lib_prefix=no
++  need_version=no
++  library_name_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  shlibpath_var=LD_LIBRARY_PATH
++  shlibpath_overrides_runpath=no
++  hardcode_into_libs=yes
++  ;;
+ 
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
++uts4*)
++  version_type=linux
++  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++  soname_spec='${libname}${release}${shared_ext}$major'
++  shlibpath_var=LD_LIBRARY_PATH
++  ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++*)
++  dynamic_linker=no
++  ;;
++esac
++AC_MSG_RESULT([$dynamic_linker])
++test "$dynamic_linker" = no && can_build_shared=no
+ 
+-# Allow CC to be a program name with arguments.
+-lt_save_CC=$CC
+-lt_save_LD=$LD
+-lt_save_GCC=$GCC
+-GCC=$GXX
+-lt_save_with_gnu_ld=$with_gnu_ld
+-lt_save_path_LD=$lt_cv_path_LD
+-if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+-  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+-else
+-  $as_unset lt_cv_prog_gnu_ld
++variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
++if test "$GCC" = yes; then
++  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+ fi
+-if test -n "${lt_cv_path_LDCXX+set}"; then
+-  lt_cv_path_LD=$lt_cv_path_LDCXX
+-else
+-  $as_unset lt_cv_path_LD
++ 
++if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
++  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+ fi
+-test -z "${LDCXX+set}" || LD=$LDCXX
+-CC=${CXX-"c++"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
+-
+-# We don't want -fno-exception wen compiling C++ code, so set the
+-# no_builtin_flag separately
+-if test "$GXX" = yes; then
+-  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+-else
+-  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
++  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+ fi
+ 
+-if test "$GXX" = yes; then
+-  # Set up default GNU C++ configuration
+-
+-  AC_PROG_LD
+-
+-  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+-  # archiving commands below assume that GNU ld is being used.
+-  if test "$with_gnu_ld" = yes; then
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-
+-    # If archive_cmds runs LD, not CC, wlarc should be empty
+-    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+-    #     investigate it a little bit more. (MM)
+-    wlarc='${wl}'
+-
+-    # ancient GNU ld didn't support --whole-archive et. al.
+-    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+-	grep 'no-whole-archive' > /dev/null; then
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+-    else
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-    fi
+-  else
+-    with_gnu_ld=no
+-    wlarc=
+-
+-    # A generic and very simple default shared library creation
+-    # command for GNU C++ for the case where it uses the native
+-    # linker, instead of GNU ld.  If possible, this setting should
+-    # overridden to take advantage of the native linker features on
+-    # the platform it is being used on.
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+-  fi
+-
+-  # Commands to make compiler produce verbose output that lists
+-  # what "hidden" libraries, object files and flags are used when
+-  # linking a shared library.
+-  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+-
+-else
+-  GXX=no
+-  with_gnu_ld=no
+-  wlarc=
+-fi
++_LT_DECL([], [variables_saved_for_relink], [1],
++    [Variables whose values should be saved in libtool wrapper scripts and
++    restored at link time])
++_LT_DECL([], [need_lib_prefix], [0],
++    [Do we need the "lib" prefix for modules?])
++_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
++_LT_DECL([], [version_type], [0], [Library versioning type])
++_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
++_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
++_LT_DECL([], [shlibpath_overrides_runpath], [0],
++    [Is shlibpath searched before the hard-coded library search path?])
++_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
++_LT_DECL([], [library_names_spec], [1],
++    [[List of archive names.  First name is the real one, the rest are links.
++    The last name is the one that the linker finds with -lNAME]])
++_LT_DECL([], [soname_spec], [1],
++    [[The coded name of the library, if different from the real name]])
++_LT_DECL([], [postinstall_cmds], [2],
++    [Command to use after installation of a shared archive])
++_LT_DECL([], [postuninstall_cmds], [2],
++    [Command to use after uninstallation of a shared archive])
++_LT_DECL([], [finish_cmds], [2],
++    [Commands used to finish a libtool library installation in a directory])
++_LT_DECL([], [finish_eval], [1],
++    [[As "finish_cmds", except a single script fragment to be evaled but
++    not shown]])
++_LT_DECL([], [hardcode_into_libs], [0],
++    [Whether we should hardcode library paths into libraries])
++_LT_DECL([], [sys_lib_search_path_spec], [2],
++    [Compile-time system search path for libraries])
++_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
++    [Run-time system search path for libraries])
++])# _LT_SYS_DYNAMIC_LINKER
+ 
+-# PORTME: fill in a description of your system's C++ link characteristics
+-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+-_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-case $host_os in
+-  aix3*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  aix4* | aix5*)
+-    if test "$host_cpu" = ia64; then
+-      # On IA64, the linker does run time linking by default, so we don't
+-      # have to do anything special.
+-      aix_use_runtimelinking=no
+-      exp_sym_flag='-Bexport'
+-      no_entry_flag=""
+-    else
+-      aix_use_runtimelinking=no
+ 
+-      # Test if we are trying to use run time linking or normal
+-      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+-      # need to do runtime linking.
+-      case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+-	for ld_flag in $LDFLAGS; do
+-	  case $ld_flag in
+-	  *-brtl*)
+-	    aix_use_runtimelinking=yes
+-	    break
+-	    ;;
+-	  esac
+-	done
+-	;;
+-      esac
+-
+-      exp_sym_flag='-bexport'
+-      no_entry_flag='-bnoentry'
+-    fi
++# _LT_PATH_TOOL_PREFIX(TOOL)
++# --------------------------
++# find a file program which can recognize shared library
++AC_DEFUN([_LT_PATH_TOOL_PREFIX],
++[m4_require([_LT_DECL_EGREP])dnl
++AC_MSG_CHECKING([for $1])
++AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
++[case $MAGIC_CMD in
++[[\\/*] |  ?:[\\/]*])
++  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
++  ;;
++*)
++  lt_save_MAGIC_CMD="$MAGIC_CMD"
++  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++dnl $ac_dummy forces splitting on constant user-supplied paths.
++dnl POSIX.2 word splitting is done only on the output of word expansions,
++dnl not every word.  This closes a longstanding sh security hole.
++  ac_dummy="m4_if([$2], , $PATH, [$2])"
++  for ac_dir in $ac_dummy; do
++    IFS="$lt_save_ifs"
++    test -z "$ac_dir" && ac_dir=.
++    if test -f $ac_dir/$1; then
++      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
++      if test -n "$file_magic_test_file"; then
++	case $deplibs_check_method in
++	"file_magic "*)
++	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
++	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
++	    $EGREP "$file_magic_regex" > /dev/null; then
++	    :
++	  else
++	    cat <<_LT_EOF 1>&2
+ 
+-    # When large executables or shared objects are built, AIX ld can
+-    # have problems creating the table of contents.  If linking a library
+-    # or program results in "error TOC overflow" add -mminimal-toc to
+-    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+-    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+-
+-    _LT_AC_TAGVAR(archive_cmds, $1)=''
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++*** Warning: the command libtool uses to detect shared libraries,
++*** $file_magic_cmd, produces output that libtool cannot recognize.
++*** The result is that libtool may fail to recognize shared libraries
++*** as such.  This will affect the creation of libtool libraries that
++*** depend on shared libraries, but programs linked with such libtool
++*** libraries will work regardless of this problem.  Nevertheless, you
++*** may want to report the problem to your system manager and/or to
++*** bug-libtool@gnu.org
+ 
+-    if test "$GXX" = yes; then
+-      case $host_os in aix4.[[012]]|aix4.[[012]].*)
+-      # We only want to do this on AIX 4.2 and lower, the check
+-      # below for broken collect2 doesn't work under 4.3+
+-	collect2name=`${CC} -print-prog-name=collect2`
+-	if test -f "$collect2name" && \
+-	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+-	then
+-	  # We have reworked collect2
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	else
+-	  # We have old collect2
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+-	  # It fails to find uninstalled libraries when the uninstalled
+-	  # path is not listed in the libpath.  Setting hardcode_minus_L
+-	  # to unsupported forces relinking
+-	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-	fi
+-	;;
+-      esac
+-      shared_flag='-shared'
+-      if test "$aix_use_runtimelinking" = yes; then
+-	shared_flag="$shared_flag "'${wl}-G'
+-      fi
+-    else
+-      # not using gcc
+-      if test "$host_cpu" = ia64; then
+-	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+-	# chokes on -Wl,-G. The following line is correct:
+-	shared_flag='-G'
+-      else
+-	if test "$aix_use_runtimelinking" = yes; then
+-	  shared_flag='${wl}-G'
+-	else
+-	  shared_flag='${wl}-bM:SRE'
+-	fi
++_LT_EOF
++	  fi ;;
++	esac
+       fi
++      break
+     fi
++  done
++  IFS="$lt_save_ifs"
++  MAGIC_CMD="$lt_save_MAGIC_CMD"
++  ;;
++esac])
++MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++if test -n "$MAGIC_CMD"; then
++  AC_MSG_RESULT($MAGIC_CMD)
++else
++  AC_MSG_RESULT(no)
++fi
++_LT_DECL([], [MAGIC_CMD], [0],
++	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
++])# _LT_PATH_TOOL_PREFIX
+ 
+-    # It seems that -bexpall does not export symbols beginning with
+-    # underscore (_), so it is better to generate a list of symbols to export.
+-    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+-    if test "$aix_use_runtimelinking" = yes; then
+-      # Warning - without using the other runtime loading flags (-brtl),
+-      # -berok will link without error, but may produce a broken library.
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+-      # Determine the default libpath from the value encoded in an empty executable.
+-      _LT_AC_SYS_LIBPATH_AIX
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++# Old name:
++AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+ 
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+-     else
+-      if test "$host_cpu" = ia64; then
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+-      else
+-	# Determine the default libpath from the value encoded in an empty executable.
+-	_LT_AC_SYS_LIBPATH_AIX
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-	# Warning - without using the other run time loading flags,
+-	# -berok will link without error, but may produce a broken library.
+-	_LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+-	# Exported symbols can be pulled into shared objects from archives
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+-	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-	# This is similar to how AIX traditionally builds its shared libraries.
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+-      fi
+-    fi
+-    ;;
+ 
+-  beos*)
+-    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+-      # support --undefined.  This deserves some investigation.  FIXME
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-    else
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    fi
+-    ;;
++# _LT_PATH_MAGIC
++# --------------
++# find a file program which can recognize a shared library
++m4_defun([_LT_PATH_MAGIC],
++[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
++if test -z "$lt_cv_path_MAGIC_CMD"; then
++  if test -n "$ac_tool_prefix"; then
++    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
++  else
++    MAGIC_CMD=:
++  fi
++fi
++])# _LT_PATH_MAGIC
+ 
+-  chorus*)
+-    case $cc_basename in
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-    esac
+-    ;;
+ 
+-  cygwin* | mingw* | pw32*)
+-    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+-    # as there is no search path for DLLs.
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+-    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+-
+-    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-      # If the export-symbols file already is a .def file (1st line
+-      # is EXPORTS), use it as is; otherwise, prepend...
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+-	cp $export_symbols $output_objdir/$soname.def;
+-      else
+-	echo EXPORTS > $output_objdir/$soname.def;
+-	cat $export_symbols >> $output_objdir/$soname.def;
+-      fi~
+-      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-    else
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    fi
+-  ;;
+-      darwin* | rhapsody*)
+-        case $host_os in
+-        rhapsody* | darwin1.[[012]])
+-         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+-         ;;
+-       *) # Darwin 1.3 on
+-         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+-           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-         else
+-           case ${MACOSX_DEPLOYMENT_TARGET} in
+-             10.[[012]])
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-               ;;
+-             10.*)
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+-               ;;
+-           esac
+-         fi
+-         ;;
+-        esac
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-
+-    if test "$GXX" = yes ; then
+-      lt_int_apple_cc_single_mod=no
+-      output_verbose_link_cmd='echo'
+-      if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+-       lt_int_apple_cc_single_mod=yes
+-      fi
+-      if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+-       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+-      else
+-          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+-        fi
+-        _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-          if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+-            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          else
+-            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          fi
+-            _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-      else
+-      case $cc_basename in
+-        xlc*)
+-         output_verbose_link_cmd='echo'
+-          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+-          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          ;;
+-       *)
+-         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-          ;;
+-      esac
+-      fi
+-        ;;
++# LT_PATH_LD
++# ----------
++# find the pathname to the GNU or non-GNU linker
++AC_DEFUN([LT_PATH_LD],
++[AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_DECL_EGREP])dnl
+ 
+-  dgux*)
+-    case $cc_basename in
+-      ec++*)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      ghcx*)
+-	# Green Hills C++ Compiler
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-    esac
+-    ;;
+-  freebsd[[12]]*)
+-    # C++ shared libraries reported to be fairly broken before switch to ELF
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  freebsd-elf*)
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    ;;
+-  freebsd* | kfreebsd*-gnu | dragonfly*)
+-    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+-    # conventions
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-    ;;
+-  gnu*)
+-    ;;
+-  hpux9*)
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+-				# but as the default
+-				# location of the library.
+-
+-    case $cc_basename in
+-    CC*)
+-      # FIXME: insert proper C++ library support
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
+-    aCC*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      # Commands to make compiler produce verbose output that lists
+-      # what "hidden" libraries, object files and flags are used when
+-      # linking a shared library.
+-      #
+-      # There doesn't appear to be a way to prevent this compiler from
+-      # explicitly linking system object files so we need to strip them
+-      # from the output so that they don't get included in the library
+-      # dependencies.
+-      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-      ;;
+-    *)
+-      if test "$GXX" = yes; then
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      else
+-        # FIXME: insert proper C++ library support
+-        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
+-    esac
+-    ;;
+-  hpux10*|hpux11*)
+-    if test $with_gnu_ld = no; then
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++AC_ARG_WITH([gnu-ld],
++    [AS_HELP_STRING([--with-gnu-ld],
++	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
++    [test "$withval" = no || with_gnu_ld=yes],
++    [with_gnu_ld=no])dnl
+ 
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+-        ;;
+-      *)
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-        ;;
+-      esac
+-    fi
+-    case $host_cpu in
+-    hppa*64*|ia64*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
+-    *)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+-					      # but as the default
+-					      # location of the library.
++ac_prog=ld
++if test "$GCC" = yes; then
++  # Check if gcc -print-prog-name=ld gives a path.
++  AC_MSG_CHECKING([for ld used by $CC])
++  case $host in
++  *-*-mingw*)
++    # gcc leaves a trailing carriage return which upsets mingw
++    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
++  *)
++    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
++  esac
++  case $ac_prog in
++    # Accept absolute paths.
++    [[\\/]]* | ?:[[\\/]]*)
++      re_direlt='/[[^/]][[^/]]*/\.\./'
++      # Canonicalize the pathname of ld
++      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
++      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
++	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
++      done
++      test -z "$LD" && LD="$ac_prog"
+       ;;
+-    esac
+-
+-    case $cc_basename in
+-      CC*)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      aCC*)
+-	case $host_cpu in
+-	hppa*64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  ;;
+-	ia64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  ;;
+-	esac
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	if test "$GXX" = yes; then
+-	  if test $with_gnu_ld = no; then
+-	    case $host_cpu in
+-	    hppa*64*)
+-	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	      ;;
+-	    ia64*)
+-	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	      ;;
+-	    *)
+-	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	      ;;
+-	    esac
+-	  fi
+-	else
+-	  # FIXME: insert proper C++ library support
+-	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	fi
+-	;;
+-    esac
+-    ;;
+-  interix3*)
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-    # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+-    # Instead, shared libraries are loaded at an image base (0x10000000 by
+-    # default) and relocated if they conflict, which is a slow very memory
+-    # consuming and fragmenting process.  To avoid this, we pick a random,
+-    # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+-    # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+-    ;;
+-  irix5* | irix6*)
+-    case $cc_basename in
+-      CC*)
+-	# SGI C++
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-
+-	# Archives containing C++ object files must be created using
+-	# "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+-	# necessary to make sure instantiated templates are included
+-	# in the archive.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+-	;;
+-      *)
+-	if test "$GXX" = yes; then
+-	  if test "$with_gnu_ld" = no; then
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-	  else
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+-	  fi
+-	fi
+-	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-	;;
+-    esac
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++  "")
++    # If it fails, then pretend we aren't using GCC.
++    ac_prog=ld
+     ;;
+-  linux*)
+-    case $cc_basename in
+-      KCC*)
+-	# Kuck and Associates, Inc. (KAI) C++ Compiler
+-
+-	# KCC will only create a shared library if the output file
+-	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+-	# to its proper name (with version) after linking.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-
+-	# Archives containing C++ object files must be created using
+-	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+-	;;
+-      icpc*)
+-	# Intel C++
+-	with_gnu_ld=yes
+-	# version 8.0 and above of icpc choke on multiply defined symbols
+-	# if we add $predep_objects and $postdep_objects, however 7.1 and
+-	# earlier do not add the objects themselves.
+-	case `$CC -V 2>&1` in
+-	*"Version 7."*)
+-  	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-  	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-	  ;;
+-	*)  # Version 8.0 or newer
+-	  tmp_idyn=
+-	  case $host_cpu in
+-	    ia64*) tmp_idyn=' -i_dynamic';;
+-	  esac
+-  	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-	  ;;
+-	esac
+-	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+-	;;
+-      pgCC*)
+-        # Portland Group C++ compiler
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+-  	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-        ;;
+-      cxx*)
+-	# Compaq C++
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+-
+-	runpath_var=LD_RUN_PATH
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	case `$CC -V 2>&1 | sed 5q` in
+-	*Sun\ C*)
+-	  # Sun C++ 5.9
+-	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-
+-	  # Not sure whether something based on
+-	  # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+-	  # would be better.
+-	  output_verbose_link_cmd='echo'
+-
+-	  # Archives containing C++ object files must be created using
+-	  # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+-	  # necessary to make sure instantiated templates are included
+-	  # in the archive.
+-	  _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+-	  ;;
+-	esac
+-	;;
+-    esac
++  *)
++    # If it is relative, then search for the first ld in PATH.
++    with_gnu_ld=unknown
+     ;;
+-  lynxos*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  m88k*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  mvs*)
+-    case $cc_basename in
+-      cxx*)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
++  esac
++elif test "$with_gnu_ld" = yes; then
++  AC_MSG_CHECKING([for GNU ld])
++else
++  AC_MSG_CHECKING([for non-GNU ld])
++fi
++AC_CACHE_VAL(lt_cv_path_LD,
++[if test -z "$LD"; then
++  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++  for ac_dir in $PATH; do
++    IFS="$lt_save_ifs"
++    test -z "$ac_dir" && ac_dir=.
++    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
++      lt_cv_path_LD="$ac_dir/$ac_prog"
++      # Check to see if the program is GNU ld.  I'd rather use --version,
++      # but apparently some variants of GNU ld only accept -v.
++      # Break only if it was the GNU/non-GNU ld that we prefer.
++      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
++      *GNU* | *'with BFD'*)
++	test "$with_gnu_ld" != no && break
+ 	;;
+       *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
++	test "$with_gnu_ld" != yes && break
+ 	;;
+-    esac
+-    ;;
+-  netbsd*)
+-    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+-      wlarc=
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    fi
+-    # Workaround some broken pre-1.5 toolchains
+-    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+-    ;;
+-  openbsd2*)
+-    # C++ shared libraries are fairly broken
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  openbsd*)
+-    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-    if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++      esac
+     fi
+-    output_verbose_link_cmd='echo'
+-    ;;
+-  osf3*)
+-    case $cc_basename in
+-      KCC*)
+-	# Kuck and Associates, Inc. (KAI) C++ Compiler
+-
+-	# KCC will only create a shared library if the output file
+-	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+-	# to its proper name (with version) after linking.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Archives containing C++ object files must be created using
+-	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+-
+-	;;
+-      RCC*)
+-	# Rational C++ 2.4.1
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      cxx*)
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	  # Commands to make compiler produce verbose output that lists
+-	  # what "hidden" libraries, object files and flags are used when
+-	  # linking a shared library.
+-	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
++  done
++  IFS="$lt_save_ifs"
++else
++  lt_cv_path_LD="$LD" # Let the user override the test with a path.
++fi])
++LD="$lt_cv_path_LD"
++if test -n "$LD"; then
++  AC_MSG_RESULT($LD)
++else
++  AC_MSG_RESULT(no)
++fi
++test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
++_LT_PATH_LD_GNU
++AC_SUBST([LD])
+ 
+-	else
+-	  # FIXME: insert proper C++ library support
+-	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	fi
+-	;;
+-    esac
+-    ;;
+-  osf4* | osf5*)
+-    case $cc_basename in
+-      KCC*)
+-	# Kuck and Associates, Inc. (KAI) C++ Compiler
+-
+-	# KCC will only create a shared library if the output file
+-	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+-	# to its proper name (with version) after linking.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Archives containing C++ object files must be created using
+-	# the KAI C++ compiler.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+-	;;
+-      RCC*)
+-	# Rational C++ 2.4.1
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      cxx*)
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+-	  echo "-hidden">> $lib.exp~
+-	  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version	$verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+-	  $rm $lib.exp'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	# Commands to make compiler produce verbose output that lists
+-	# what "hidden" libraries, object files and flags are used when
+-	# linking a shared library.
+-	#
+-	# There doesn't appear to be a way to prevent this compiler from
+-	# explicitly linking system object files so we need to strip them
+-	# from the output so that they don't get included in the library
+-	# dependencies.
+-	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+-	;;
+-      *)
+-	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	 _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-
+-	  # Commands to make compiler produce verbose output that lists
+-	  # what "hidden" libraries, object files and flags are used when
+-	  # linking a shared library.
+-	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
++_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
++])# LT_PATH_LD
+ 
+-	else
+-	  # FIXME: insert proper C++ library support
+-	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	fi
+-	;;
+-    esac
+-    ;;
+-  psos*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-    ;;
+-  sunos4*)
+-    case $cc_basename in
+-      CC*)
+-	# Sun C++ 4.x
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      lcc*)
+-	# Lucid
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-    esac
++# Old names:
++AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
++AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_PROG_LD], [])
++dnl AC_DEFUN([AC_PROG_LD], [])
++
++
++# _LT_PATH_LD_GNU
++#- --------------
++m4_defun([_LT_PATH_LD_GNU],
++[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
++[# I'd rather use --version here, but apparently some GNU lds only accept -v.
++case `$LD -v 2>&1 </dev/null` in
++*GNU* | *'with BFD'*)
++  lt_cv_prog_gnu_ld=yes
++  ;;
++*)
++  lt_cv_prog_gnu_ld=no
++  ;;
++esac])
++with_gnu_ld=$lt_cv_prog_gnu_ld
++])# _LT_PATH_LD_GNU
++
++
++# _LT_CMD_RELOAD
++# --------------
++# find reload flag for linker
++#   -- PORTME Some linkers may need a different reload flag.
++m4_defun([_LT_CMD_RELOAD],
++[AC_CACHE_CHECK([for $LD option to reload object files],
++  lt_cv_ld_reload_flag,
++  [lt_cv_ld_reload_flag='-r'])
++reload_flag=$lt_cv_ld_reload_flag
++case $reload_flag in
++"" | " "*) ;;
++*) reload_flag=" $reload_flag" ;;
++esac
++reload_cmds='$LD$reload_flag -o $output$reload_objs'
++case $host_os in
++  darwin*)
++    if test "$GCC" = yes; then
++      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
++    else
++      reload_cmds='$LD$reload_flag -o $output$reload_objs'
++    fi
+     ;;
+-  solaris*)
+-    case $cc_basename in
+-      CC*)
+-	# Sun C++ 4.2, 5.x and Centerline C++
+-        _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+-	_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-	$CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+-
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-	case $host_os in
+-	  solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+-	  *)
+-	    # The C++ compiler is used as linker so we must use $wl
+-	    # flag to pass the commands to the underlying system
+-	    # linker. We must also pass each convience library through
+-	    # to the system linker between allextract/defaultextract.
+-	    # The C++ compiler will combine linker options so we
+-	    # cannot just pass the convience library names through
+-	    # without $wl.
+-	    # Supported since Solaris 2.6 (maybe 2.5.1?)
+-	    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
+-	    ;;
+-	esac
+-	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++esac
++_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl
++_LT_DECL([], [reload_cmds], [2])dnl
++])# _LT_CMD_RELOAD
+ 
+-	output_verbose_link_cmd='echo'
+ 
+-	# Archives containing C++ object files must be created using
+-	# "CC -xar", where "CC" is the Sun C++ compiler.  This is
+-	# necessary to make sure instantiated templates are included
+-	# in the archive.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+-	;;
+-      gcx*)
+-	# Green Hills C++ Compiler
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++# _LT_CHECK_MAGIC_METHOD
++# ----------------------
++# how to check for library dependencies
++#  -- PORTME fill in with the dynamic library characteristics
++m4_defun([_LT_CHECK_MAGIC_METHOD],
++[m4_require([_LT_DECL_EGREP])
++AC_CACHE_CHECK([how to recognize dependent libraries],
++lt_cv_deplibs_check_method,
++[lt_cv_file_magic_cmd='$MAGIC_CMD'
++lt_cv_file_magic_test_file=
++lt_cv_deplibs_check_method='unknown'
++# Need to set the preceding variable on all platforms that support
++# interlibrary dependencies.
++# 'none' -- dependencies not supported.
++# `unknown' -- same as none, but documents that we really don't know.
++# 'pass_all' -- all dependencies passed with no checks.
++# 'test_compile' -- check by making test program.
++# 'file_magic [[regex]]' -- check by looking for files in library path
++# which responds to the $file_magic_cmd with a given extended regex.
++# If you have `file' or equivalent on your system and you're not sure
++# whether `pass_all' will *always* work, you probably want this one.
+ 
+-	# The C++ compiler must be used to create the archive.
+-	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+-	;;
+-      *)
+-	# GNU C++ compiler with Solaris linker
+-	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+-	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+-	  if $CC --version | grep -v '^2\.7' > /dev/null; then
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+-	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-		$CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
++case $host_os in
++aix[[4-9]]*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-	    # Commands to make compiler produce verbose output that lists
+-	    # what "hidden" libraries, object files and flags are used when
+-	    # linking a shared library.
+-	    output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+-	  else
+-	    # g++ 2.7 appears to require `-G' NOT `-shared' on this
+-	    # platform.
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+-	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-		$CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
++beos*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-	    # Commands to make compiler produce verbose output that lists
+-	    # what "hidden" libraries, object files and flags are used when
+-	    # linking a shared library.
+-	    output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+-	  fi
++bsdi[[45]]*)
++  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
++  lt_cv_file_magic_cmd='/usr/bin/file -L'
++  lt_cv_file_magic_test_file=/shlib/libc.so
++  ;;
+ 
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+-	fi
+-	;;
+-    esac
+-    ;;
+-  sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+-    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    runpath_var='LD_RUN_PATH'
+-
+-    case $cc_basename in
+-      CC*)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-    esac
+-    ;;
+-  sysv5* | sco3.2v5* | sco5v6*)
+-    # Note: We can NOT use -z defs as we might desire, because we do not
+-    # link with -lc, and that would cause any symbols used from libc to
+-    # always be unresolved, which means just about no library would
+-    # ever link correctly.  If we're not using GNU ld we use -z text
+-    # though, which does catch some bad symbols but isn't as heavy-handed
+-    # as -z defs.
+-    # For security reasons, it is highly recommended that you always
+-    # use absolute paths for naming shared libraries, and exclude the
+-    # DT_RUNPATH tag from executables and libraries.  But doing so
+-    # requires that you compile everything twice, which is a pain.
+-    # So that behaviour is only enabled if SCOABSPATH is set to a
+-    # non-empty value in the environment.  Most likely only useful for
+-    # creating official distributions of packages.
+-    # This is a hack until libtool officially supports absolute path
+-    # names for shared libraries.
+-    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-    _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+-    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+-    runpath_var='LD_RUN_PATH'
+-
+-    case $cc_basename in
+-      CC*)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	;;
+-    esac
+-    ;;
+-  tandem*)
+-    case $cc_basename in
+-      NCC*)
+-	# NonStop-UX NCC 3.20
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
+-      *)
+-	# FIXME: insert proper C++ library support
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	;;
++cygwin*)
++  # func_win32_libid is a shell function defined in ltmain.sh
++  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++  lt_cv_file_magic_cmd='func_win32_libid'
++  ;;
++
++mingw* | pw32*)
++  # Base MSYS/MinGW do not provide the 'file' command needed by
++  # func_win32_libid shell function, so use a weaker test based on 'objdump',
++  # unless we find 'file', for example because we are cross-compiling.
++  if ( file / ) >/dev/null 2>&1; then
++    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++    lt_cv_file_magic_cmd='func_win32_libid'
++  else
++    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
++    lt_cv_file_magic_cmd='$OBJDUMP -f'
++  fi
++  ;;
++
++darwin* | rhapsody*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++freebsd* | dragonfly*)
++  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++    case $host_cpu in
++    i*86 )
++      # Not sure whether the presence of OpenBSD here was a mistake.
++      # Let's accept both of them until this is cleared up.
++      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
++      lt_cv_file_magic_cmd=/usr/bin/file
++      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
++      ;;
+     esac
++  else
++    lt_cv_deplibs_check_method=pass_all
++  fi
++  ;;
++
++gnu*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++hpux10.20* | hpux11*)
++  lt_cv_file_magic_cmd=/usr/bin/file
++  case $host_cpu in
++  ia64*)
++    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
++    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+     ;;
+-  vxworks*)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
++  hppa*64*)
++    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
++    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+     ;;
+   *)
+-    # FIXME: insert proper C++ library support
+-    _LT_AC_TAGVAR(ld_shlibs, $1)=no
++    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
++    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+     ;;
+-esac
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+-test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
++  esac
++  ;;
+ 
+-_LT_AC_TAGVAR(GCC, $1)="$GXX"
+-_LT_AC_TAGVAR(LD, $1)="$LD"
++interix[[3-9]]*)
++  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
++  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
++  ;;
+ 
+-## CAVEAT EMPTOR:
+-## There is no encapsulation within the following macros, do not change
+-## the running order or otherwise move them around unless you know exactly
+-## what you are doing...
+-AC_LIBTOOL_POSTDEP_PREDEP($1)
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
++irix5* | irix6* | nonstopux*)
++  case $LD in
++  *-32|*"-32 ") libmagic=32-bit;;
++  *-n32|*"-n32 ") libmagic=N32;;
++  *-64|*"-64 ") libmagic=64-bit;;
++  *) libmagic=never-match;;
++  esac
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-AC_LIBTOOL_CONFIG($1)
++# This must be Linux ELF.
++linux* | k*bsd*-gnu)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-AC_LANG_POP
+-CC=$lt_save_CC
+-LDCXX=$LD
+-LD=$lt_save_LD
+-GCC=$lt_save_GCC
+-with_gnu_ldcxx=$with_gnu_ld
+-with_gnu_ld=$lt_save_with_gnu_ld
+-lt_cv_path_LDCXX=$lt_cv_path_LD
+-lt_cv_path_LD=$lt_save_path_LD
+-lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+-lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+-])# AC_LIBTOOL_LANG_CXX_CONFIG
++netbsd*)
++  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++  else
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
++  fi
++  ;;
+ 
+-# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+-# ------------------------------------
+-# Figure out "hidden" library dependencies from verbose
+-# compiler output when linking a shared library.
+-# Parse the compiler output and extract the necessary
+-# objects, libraries and library flags.
+-AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+-dnl we can't use the lt_simple_compile_test_code here,
+-dnl because it contains code intended for an executable,
+-dnl not a library.  It's possible we should let each
+-dnl tag define a new lt_????_link_test_code variable,
+-dnl but it's only used here...
+-ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+-int a;
+-void foo (void) { a = 0; }
+-EOF
+-],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+-class Foo
+-{
+-public:
+-  Foo (void) { a = 0; }
+-private:
+-  int a;
+-};
+-EOF
+-],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+-      subroutine foo
+-      implicit none
+-      integer*4 a
+-      a=0
+-      return
+-      end
+-EOF
+-],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+-public class foo {
+-  private int a;
+-  public void bar (void) {
+-    a = 0;
+-  }
+-};
+-EOF
+-])
+-dnl Parse the compiler output and extract the necessary
+-dnl objects, libraries and library flags.
+-if AC_TRY_EVAL(ac_compile); then
+-  # Parse the compiler output and extract the necessary
+-  # objects, libraries and library flags.
++newos6*)
++  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
++  lt_cv_file_magic_cmd=/usr/bin/file
++  lt_cv_file_magic_test_file=/usr/lib/libnls.so
++  ;;
+ 
+-  # Sentinel used to keep track of whether or not we are before
+-  # the conftest object file.
+-  pre_test_object_deps_done=no
++*nto* | *qnx*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-  # The `*' in the case matches for architectures that use `case' in
+-  # $output_verbose_cmd can trigger glob expansion during the loop
+-  # eval without this substitution.
+-  output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
++openbsd*)
++  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
++  else
++    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++  fi
++  ;;
+ 
+-  for p in `eval $output_verbose_link_cmd`; do
+-    case $p in
++osf3* | osf4* | osf5*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
+ 
+-    -L* | -R* | -l*)
+-       # Some compilers place space between "-{L,R}" and the path.
+-       # Remove the space.
+-       if test $p = "-L" \
+-	  || test $p = "-R"; then
+-	 prev=$p
+-	 continue
+-       else
+-	 prev=
+-       fi
++rdos*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++solaris*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++
++sysv4 | sysv4.3*)
++  case $host_vendor in
++  motorola)
++    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
++    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
++    ;;
++  ncr)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
++  sequent)
++    lt_cv_file_magic_cmd='/bin/file'
++    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
++    ;;
++  sni)
++    lt_cv_file_magic_cmd='/bin/file'
++    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
++    lt_cv_file_magic_test_file=/lib/libc.so
++    ;;
++  siemens)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
++  pc)
++    lt_cv_deplibs_check_method=pass_all
++    ;;
++  esac
++  ;;
++
++tpf*)
++  lt_cv_deplibs_check_method=pass_all
++  ;;
++esac
++])
++file_magic_cmd=$lt_cv_file_magic_cmd
++deplibs_check_method=$lt_cv_deplibs_check_method
++test -z "$deplibs_check_method" && deplibs_check_method=unknown
++
++_LT_DECL([], [deplibs_check_method], [1],
++    [Method to check whether dependent libraries are shared objects])
++_LT_DECL([], [file_magic_cmd], [1],
++    [Command to use when deplibs_check_method == "file_magic"])
++])# _LT_CHECK_MAGIC_METHOD
++
++
++# LT_PATH_NM
++# ----------
++# find the pathname to a BSD- or MS-compatible name lister
++AC_DEFUN([LT_PATH_NM],
++[AC_REQUIRE([AC_PROG_CC])dnl
++AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
++[if test -n "$NM"; then
++  # Let the user override the test.
++  lt_cv_path_NM="$NM"
++else
++  lt_nm_to_check="${ac_tool_prefix}nm"
++  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
++    lt_nm_to_check="$lt_nm_to_check nm"
++  fi
++  for lt_tmp_nm in $lt_nm_to_check; do
++    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
++      IFS="$lt_save_ifs"
++      test -z "$ac_dir" && ac_dir=.
++      tmp_nm="$ac_dir/$lt_tmp_nm"
++      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
++	# Check to see if the nm accepts a BSD-compat flag.
++	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
++	#   nm: unknown option "B" ignored
++	# Tru64's nm complains that /dev/null is an invalid object file
++	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
++	*/dev/null* | *'Invalid file or object type'*)
++	  lt_cv_path_NM="$tmp_nm -B"
++	  break
++	  ;;
++	*)
++	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
++	  */dev/null*)
++	    lt_cv_path_NM="$tmp_nm -p"
++	    break
++	    ;;
++	  *)
++	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
++	    continue # so that we can try to find one that supports BSD flags
++	    ;;
++	  esac
++	  ;;
++	esac
++      fi
++    done
++    IFS="$lt_save_ifs"
++  done
++  : ${lt_cv_path_NM=no}
++fi])
++if test "$lt_cv_path_NM" != "no"; then
++  NM="$lt_cv_path_NM"
++else
++  # Didn't find any BSD compatible name lister, look for dumpbin.
++  AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :)
++  AC_SUBST([DUMPBIN])
++  if test "$DUMPBIN" != ":"; then
++    NM="$DUMPBIN"
++  fi
++fi
++test -z "$NM" && NM=nm
++AC_SUBST([NM])
++_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
++
++AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
++  [lt_cv_nm_interface="BSD nm"
++  echo "int some_variable = 0;" > conftest.$ac_ext
++  (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
++  (eval "$ac_compile" 2>conftest.err)
++  cat conftest.err >&AS_MESSAGE_LOG_FD
++  (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
++  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
++  cat conftest.err >&AS_MESSAGE_LOG_FD
++  (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD)
++  cat conftest.out >&AS_MESSAGE_LOG_FD
++  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
++    lt_cv_nm_interface="MS dumpbin"
++  fi
++  rm -f conftest*])
++])# LT_PATH_NM
++
++# Old names:
++AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
++AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_PROG_NM], [])
++dnl AC_DEFUN([AC_PROG_NM], [])
++
++
++# LT_LIB_M
++# --------
++# check for math library
++AC_DEFUN([LT_LIB_M],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++LIBM=
++case $host in
++*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
++  # These system don't have libm, or don't need it
++  ;;
++*-ncr-sysv4.3*)
++  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
++  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
++  ;;
++*)
++  AC_CHECK_LIB(m, cos, LIBM="-lm")
++  ;;
++esac
++AC_SUBST([LIBM])
++])# LT_LIB_M
++
++# Old name:
++AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_CHECK_LIBM], [])
++
++
++# _LT_COMPILER_NO_RTTI([TAGNAME])
++# -------------------------------
++m4_defun([_LT_COMPILER_NO_RTTI],
++[m4_require([_LT_TAG_COMPILER])dnl
++
++_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++
++if test "$GCC" = yes; then
++  _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
++
++  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
++    lt_cv_prog_compiler_rtti_exceptions,
++    [-fno-rtti -fno-exceptions], [],
++    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
++fi
++_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
++	[Compiler flag to turn off builtin functions])
++])# _LT_COMPILER_NO_RTTI
++
++
++# _LT_CMD_GLOBAL_SYMBOLS
++# ----------------------
++m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++AC_REQUIRE([LT_PATH_LD])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++
++# Check for command to grab the raw symbol name followed by C symbol from nm.
++AC_MSG_CHECKING([command to parse $NM output from $compiler object])
++AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
++[
++# These are sane defaults that work on at least a few old systems.
++# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
++
++# Character class describing NM global symbol codes.
++symcode='[[BCDEGRST]]'
++
++# Regexp to match symbols that can be accessed directly from C.
++sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
++
++# Define system-specific variables.
++case $host_os in
++aix*)
++  symcode='[[BCDT]]'
++  ;;
++cygwin* | mingw* | pw32*)
++  symcode='[[ABCDGISTW]]'
++  ;;
++hpux*)
++  if test "$host_cpu" = ia64; then
++    symcode='[[ABCDEGRST]]'
++  fi
++  ;;
++irix* | nonstopux*)
++  symcode='[[BCDEGRST]]'
++  ;;
++osf*)
++  symcode='[[BCDEGQRST]]'
++  ;;
++solaris*)
++  symcode='[[BDRT]]'
++  ;;
++sco3.2v5*)
++  symcode='[[DT]]'
++  ;;
++sysv4.2uw2*)
++  symcode='[[DT]]'
++  ;;
++sysv5* | sco5v6* | unixware* | OpenUNIX*)
++  symcode='[[ABDT]]'
++  ;;
++sysv4)
++  symcode='[[DFNSTU]]'
++  ;;
++esac
++
++# If we're using GNU nm, then use its standard symbol codes.
++case `$NM -V 2>&1` in
++*GNU* | *'with BFD'*)
++  symcode='[[ABCDGIRSTW]]' ;;
++esac
++
++# Transform an extracted symbol line into a proper C declaration.
++# Some systems (esp. on ia64) link data and code symbols differently,
++# so use this general approach.
++lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
++
++# Transform an extracted symbol line into symbol name and symbol address
++lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
++
++# Handle CRLF in mingw tool chain
++opt_cr=
++case $build_os in
++mingw*)
++  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
++  ;;
++esac
++
++# Try without a prefix underscore, then with it.
++for ac_symprfx in "" "_"; do
++
++  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
++  symxfrm="\\1 $ac_symprfx\\2 \\2"
++
++  # Write the raw and C identifiers.
++  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
++    # Fake it for dumpbin and say T for any non-static function
++    # and D for any global variable.
++    # Also find C++ and __fastcall symbols from MSVC++,
++    # which start with @ or ?.
++    lt_cv_sys_global_symbol_pipe="$AWK ['"\
++"     {last_section=section; section=\$ 3};"\
++"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
++"     \$ 0!~/External *\|/{next};"\
++"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
++"     {if(hide[section]) next};"\
++"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
++"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
++"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
++"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
++"     ' prfx=^$ac_symprfx]"
++  else
++    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
++  fi
++
++  # Check to see that the pipe works correctly.
++  pipe_works=no
++
++  rm -f conftest*
++  cat > conftest.$ac_ext <<_LT_EOF
++#ifdef __cplusplus
++extern "C" {
++#endif
++char nm_test_var;
++void nm_test_func(void);
++void nm_test_func(void){}
++#ifdef __cplusplus
++}
++#endif
++int main(){nm_test_var='a';nm_test_func();return(0);}
++_LT_EOF
++
++  if AC_TRY_EVAL(ac_compile); then
++    # Now try to grab the symbols.
++    nlist=conftest.nm
++    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
++      # Try sorting and uniquifying the output.
++      if sort "$nlist" | uniq > "$nlist"T; then
++	mv -f "$nlist"T "$nlist"
++      else
++	rm -f "$nlist"T
++      fi
++
++      # Make sure that we snagged all the symbols we need.
++      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
++	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
++	  cat <<_LT_EOF > conftest.$ac_ext
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++_LT_EOF
++	  # Now generate the symbol file.
++	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
++
++	  cat <<_LT_EOF >> conftest.$ac_ext
++
++/* The mapping between symbol names and symbols.  */
++const struct {
++  const char *name;
++  void       *address;
++}
++lt__PROGRAM__LTX_preloaded_symbols[[]] =
++{
++  { "@PROGRAM@", (void *) 0 },
++_LT_EOF
++	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
++	  cat <<\_LT_EOF >> conftest.$ac_ext
++  {0, (void *) 0}
++};
++
++/* This works around a problem in FreeBSD linker */
++#ifdef FREEBSD_WORKAROUND
++static const void *lt_preloaded_setup() {
++  return lt__PROGRAM__LTX_preloaded_symbols;
++}
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++_LT_EOF
++	  # Now try linking the two files.
++	  mv conftest.$ac_objext conftstm.$ac_objext
++	  lt_save_LIBS="$LIBS"
++	  lt_save_CFLAGS="$CFLAGS"
++	  LIBS="conftstm.$ac_objext"
++	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
++	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
++	    pipe_works=yes
++	  fi
++	  LIBS="$lt_save_LIBS"
++	  CFLAGS="$lt_save_CFLAGS"
++	else
++	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
++	fi
++      else
++	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
++      fi
++    else
++      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
++    fi
++  else
++    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
++    cat conftest.$ac_ext >&5
++  fi
++  rm -rf conftest* conftst*
+ 
+-       if test "$pre_test_object_deps_done" = no; then
+-	 case $p in
+-	 -L* | -R*)
+-	   # Internal compiler library paths should come after those
+-	   # provided the user.  The postdeps already come after the
+-	   # user supplied libs so there is no need to process them.
+-	   if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+-	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+-	   else
+-	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+-	   fi
+-	   ;;
+-	 # The "-l" case would never come before the object being
+-	 # linked, so don't bother handling this case.
+-	 esac
+-       else
+-	 if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+-	   _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+-	 else
+-	   _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+-	 fi
+-       fi
+-       ;;
++  # Do not use the global_symbol_pipe unless it works.
++  if test "$pipe_works" = yes; then
++    break
++  else
++    lt_cv_sys_global_symbol_pipe=
++  fi
++done
++])
++if test -z "$lt_cv_sys_global_symbol_pipe"; then
++  lt_cv_sys_global_symbol_to_cdecl=
++fi
++if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
++  AC_MSG_RESULT(failed)
++else
++  AC_MSG_RESULT(ok)
++fi
+ 
+-    *.$objext)
+-       # This assumes that the test object file only shows up
+-       # once in the compiler output.
+-       if test "$p" = "conftest.$objext"; then
+-	 pre_test_object_deps_done=yes
+-	 continue
+-       fi
++_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
++    [Take the output of nm and produce a listing of raw symbols and C names])
++_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
++    [Transform the output of nm in a proper C declaration])
++_LT_DECL([global_symbol_to_c_name_address],
++    [lt_cv_sys_global_symbol_to_c_name_address], [1],
++    [Transform the output of nm in a C name address pair])
++_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
++    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
++    [Transform the output of nm in a C name address pair when lib prefix is needed])
++]) # _LT_CMD_GLOBAL_SYMBOLS
+ 
+-       if test "$pre_test_object_deps_done" = no; then
+-	 if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+-	   _LT_AC_TAGVAR(predep_objects, $1)="$p"
+-	 else
+-	   _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+-	 fi
+-       else
+-	 if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+-	   _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+-	 else
+-	   _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+-	 fi
+-       fi
+-       ;;
+ 
+-    *) ;; # Ignore the rest.
++# _LT_COMPILER_PIC([TAGNAME])
++# ---------------------------
++m4_defun([_LT_COMPILER_PIC],
++[m4_require([_LT_TAG_COMPILER])dnl
++_LT_TAGVAR(lt_prog_compiler_wl, $1)=
++_LT_TAGVAR(lt_prog_compiler_pic, $1)=
++_LT_TAGVAR(lt_prog_compiler_static, $1)=
++
++AC_MSG_CHECKING([for $compiler option to produce PIC])
++m4_if([$1], [CXX], [
++  # C++ specific cases for pic, static, wl, etc.
++  if test "$GXX" = yes; then
++    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ 
++    case $host_os in
++    aix*)
++      # All AIX code is PIC.
++      if test "$host_cpu" = ia64; then
++	# AIX 5 now supports IA64 processor
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      fi
++      ;;
++
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++        ;;
++      m68k)
++            # FIXME: we need at least 68020 code to build shared libraries, but
++            # adding the `-m68020' flag to GCC prevents building anything better,
++            # like `-m68040'.
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
++        ;;
++      esac
++      ;;
++
++    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++      # PIC is the default for these OSes.
++      ;;
++    mingw* | cygwin* | os2* | pw32*)
++      # This hack is so that the source file can tell whether it is being
++      # built for inclusion in a dll (and should export symbols for example).
++      # Although the cygwin gcc ignores -fPIC, still need this for old-style
++      # (--disable-auto-import) libraries
++      m4_if([$1], [GCJ], [],
++	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++      ;;
++    darwin* | rhapsody*)
++      # PIC is the default on this platform
++      # Common symbols not allowed in MH_DYLIB files
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
++      ;;
++    *djgpp*)
++      # DJGPP does not support shared libraries at all
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++      ;;
++    interix[[3-9]]*)
++      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++      # Instead, we relocate shared libraries at runtime.
++      ;;
++    sysv4*MP*)
++      if test -d /usr/nec; then
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++      fi
++      ;;
++    hpux*)
++      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++      # not for PA HP-UX.
++      case $host_cpu in
++      hppa*64*|ia64*)
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++	;;
++      esac
++      ;;
++    *qnx* | *nto*)
++      # QNX uses GNU C++, but need to define -shared option too, otherwise
++      # it will coredump.
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++      ;;
++    *)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++      ;;
++    esac
++  else
++    case $host_os in
++      aix[[4-9]]*)
++	# All AIX code is PIC.
++	if test "$host_cpu" = ia64; then
++	  # AIX 5 now supports IA64 processor
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	else
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++	fi
++	;;
++      chorus*)
++	case $cc_basename in
++	cxch68*)
++	  # Green Hills C++ Compiler
++	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
++	  ;;
++	esac
++	;;
++      dgux*)
++	case $cc_basename in
++	  ec++*)
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    ;;
++	  ghcx*)
++	    # Green Hills C++ Compiler
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      freebsd* | dragonfly*)
++	# FreeBSD uses GNU C++
++	;;
++      hpux9* | hpux10* | hpux11*)
++	case $cc_basename in
++	  CC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++	    if test "$host_cpu" != ia64; then
++	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++	    fi
++	    ;;
++	  aCC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++	    case $host_cpu in
++	    hppa*64*|ia64*)
++	      # +Z the default
++	      ;;
++	    *)
++	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++	      ;;
++	    esac
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      interix*)
++	# This is c89, which is MS Visual C++ (no shared libs)
++	# Anyone wants to do a port?
++	;;
++      irix5* | irix6* | nonstopux*)
++	case $cc_basename in
++	  CC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    # CC pic flag -KPIC is the default.
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      linux* | k*bsd*-gnu)
++	case $cc_basename in
++	  KCC*)
++	    # KAI C++ Compiler
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++	    ;;
++	  icpc* | ecpc* )
++	    # Intel C++
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++	    ;;
++	  pgCC* | pgcpp*)
++	    # Portland Group C++ compiler
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    ;;
++	  cxx*)
++	    # Compaq C++
++	    # Make sure the PIC flag is empty.  It appears that all Alpha
++	    # Linux and Compaq Tru64 Unix objects are PIC.
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    ;;
++	  xlc* | xlC*)
++	    # IBM XL 8.0 on PPC
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
++	    ;;
++	  *)
++	    case `$CC -V 2>&1 | sed 5q` in
++	    *Sun\ C*)
++	      # Sun C++ 5.9
++	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++	      ;;
++	    esac
++	    ;;
++	esac
++	;;
++      lynxos*)
++	;;
++      m88k*)
++	;;
++      mvs*)
++	case $cc_basename in
++	  cxx*)
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      netbsd*)
++	;;
++      *qnx* | *nto*)
++        # QNX uses GNU C++, but need to define -shared option too, otherwise
++        # it will coredump.
++        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++        ;;
++      osf3* | osf4* | osf5*)
++	case $cc_basename in
++	  KCC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
++	    ;;
++	  RCC*)
++	    # Rational C++ 2.4.1
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    ;;
++	  cxx*)
++	    # Digital/Compaq C++
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    # Make sure the PIC flag is empty.  It appears that all Alpha
++	    # Linux and Compaq Tru64 Unix objects are PIC.
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      psos*)
++	;;
++      solaris*)
++	case $cc_basename in
++	  CC*)
++	    # Sun C++ 4.2, 5.x and Centerline C++
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++	    ;;
++	  gcx*)
++	    # Green Hills C++ Compiler
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      sunos4*)
++	case $cc_basename in
++	  CC*)
++	    # Sun C++ 4.x
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    ;;
++	  lcc*)
++	    # Lucid
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++	case $cc_basename in
++	  CC*)
++	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	    ;;
++	esac
++	;;
++      tandem*)
++	case $cc_basename in
++	  NCC*)
++	    # NonStop-UX NCC 3.20
++	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	    ;;
++	  *)
++	    ;;
++	esac
++	;;
++      vxworks*)
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++	;;
+     esac
+-  done
+-
+-  # Clean up.
+-  rm -f a.out a.exe
+-else
+-  echo "libtool.m4: error: problem compiling $1 test program"
+-fi
+-
+-$rm -f confest.$objext
+-
+-# PORTME: override above test on systems where it is broken
+-ifelse([$1],[CXX],
+-[case $host_os in
+-interix3*)
+-  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+-  # hack all around it, let's just trust "g++" to DTRT.
+-  _LT_AC_TAGVAR(predep_objects,$1)=
+-  _LT_AC_TAGVAR(postdep_objects,$1)=
+-  _LT_AC_TAGVAR(postdeps,$1)=
+-  ;;
+-
+-linux*)
+-  case `$CC -V 2>&1 | sed 5q` in
+-  *Sun\ C*)
+-    # Sun C++ 5.9
+-    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+-    ;;
+-  esac
+-  ;;
+-
+-solaris*)
+-  case $cc_basename in
+-  CC*)
+-    # Adding this requires a known-good setup of shared libraries for
+-    # Sun compiler versions before 5.6, else PIC objects from an old
+-    # archive will be linked into the output, leading to subtle bugs.
+-    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+-    ;;
+-  esac
+-  ;;
+-esac
+-])
+-
+-case " $_LT_AC_TAGVAR(postdeps, $1) " in
+-*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+-esac
+-])# AC_LIBTOOL_POSTDEP_PREDEP
+-
+-# AC_LIBTOOL_LANG_F77_CONFIG
+-# --------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+-AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+-[AC_REQUIRE([AC_PROG_F77])
+-AC_LANG_PUSH(Fortran 77)
+-
+-_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-_LT_AC_TAGVAR(always_export_symbols, $1)=no
+-_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_direct, $1)=no
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+-_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+-_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+-_LT_AC_TAGVAR(module_cmds, $1)=
+-_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+-_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+-_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+-_LT_AC_TAGVAR(no_undefined_flag, $1)=
+-_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+-
+-# Source file extension for f77 test sources.
+-ac_ext=f
+-
+-# Object file extension for compiled f77 test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
+-
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+-
+-# Code to be used in simple link tests
+-lt_simple_link_test_code="      program t\n      end\n"
+-
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
+-
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
+-
+-# Allow CC to be a program name with arguments.
+-lt_save_CC="$CC"
+-CC=${F77-"f77"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
+-
+-AC_MSG_CHECKING([if libtool supports shared libraries])
+-AC_MSG_RESULT([$can_build_shared])
+-
+-AC_MSG_CHECKING([whether to build shared libraries])
+-test "$can_build_shared" = "no" && enable_shared=no
+-
+-# On AIX, shared libraries and static libraries use the same namespace, and
+-# are all built from PIC.
+-case $host_os in
+-aix3*)
+-  test "$enable_shared" = yes && enable_static=no
+-  if test -n "$RANLIB"; then
+-    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+-    postinstall_cmds='$RANLIB $lib'
+   fi
+-  ;;
+-aix4* | aix5*)
+-  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+-    test "$enable_shared" = yes && enable_static=no
+-  fi
+-  ;;
+-esac
+-AC_MSG_RESULT([$enable_shared])
+-
+-AC_MSG_CHECKING([whether to build static libraries])
+-# Make sure either enable_shared or enable_static is yes.
+-test "$enable_shared" = yes || enable_static=yes
+-AC_MSG_RESULT([$enable_static])
+-
+-_LT_AC_TAGVAR(GCC, $1)="$G77"
+-_LT_AC_TAGVAR(LD, $1)="$LD"
+-
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+-
+-AC_LIBTOOL_CONFIG($1)
+-
+-AC_LANG_POP
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_F77_CONFIG
+-
+-
+-# AC_LIBTOOL_LANG_GCJ_CONFIG
+-# --------------------------
+-# Ensure that the configuration vars for the C compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+-AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+-[AC_LANG_SAVE
+-
+-# Source file extension for Java test sources.
+-ac_ext=java
++],
++[
++  if test "$GCC" = yes; then
++    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ 
+-# Object file extension for compiled Java test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
++    case $host_os in
++      aix*)
++      # All AIX code is PIC.
++      if test "$host_cpu" = ia64; then
++	# AIX 5 now supports IA64 processor
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      fi
++      ;;
+ 
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code="class foo {}\n"
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++        ;;
++      m68k)
++            # FIXME: we need at least 68020 code to build shared libraries, but
++            # adding the `-m68020' flag to GCC prevents building anything better,
++            # like `-m68040'.
++            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
++        ;;
++      esac
++      ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
++    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++      # PIC is the default for these OSes.
++      ;;
+ 
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
++    mingw* | cygwin* | pw32* | os2*)
++      # This hack is so that the source file can tell whether it is being
++      # built for inclusion in a dll (and should export symbols for example).
++      # Although the cygwin gcc ignores -fPIC, still need this for old-style
++      # (--disable-auto-import) libraries
++      m4_if([$1], [GCJ], [],
++	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++      ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++    darwin* | rhapsody*)
++      # PIC is the default on this platform
++      # Common symbols not allowed in MH_DYLIB files
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
++      ;;
+ 
+-# Allow CC to be a program name with arguments.
+-lt_save_CC="$CC"
+-CC=${GCJ-"gcj"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
++    hpux*)
++      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++      # not for PA HP-UX.
++      case $host_cpu in
++      hppa*64*|ia64*)
++	# +Z the default
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++	;;
++      esac
++      ;;
+ 
+-# GCJ did not exist at the time GCC didn't implicitly link libc in.
+-_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
++    interix[[3-9]]*)
++      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++      # Instead, we relocate shared libraries at runtime.
++      ;;
+ 
+-_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++    msdosdjgpp*)
++      # Just because we use GCC doesn't mean we suddenly get shared libraries
++      # on systems that don't support them.
++      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++      enable_shared=no
++      ;;
+ 
+-## CAVEAT EMPTOR:
+-## There is no encapsulation within the following macros, do not change
+-## the running order or otherwise move them around unless you know exactly
+-## what you are doing...
+-AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+-AC_LIBTOOL_PROG_COMPILER_PIC($1)
+-AC_LIBTOOL_PROG_CC_C_O($1)
+-AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+-AC_LIBTOOL_PROG_LD_SHLIBS($1)
+-AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+-AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
++    *nto* | *qnx*)
++      # QNX uses GNU C++, but need to define -shared option too, otherwise
++      # it will coredump.
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++      ;;
+ 
+-AC_LIBTOOL_CONFIG($1)
++    sysv4*MP*)
++      if test -d /usr/nec; then
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++      fi
++      ;;
+ 
+-AC_LANG_RESTORE
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_GCJ_CONFIG
++    *)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++      ;;
++    esac
++  else
++    # PORTME Check for flag to pass linker flags through the system compiler.
++    case $host_os in
++    aix*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      if test "$host_cpu" = ia64; then
++	# AIX 5 now supports IA64 processor
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      else
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++      fi
++      ;;
+ 
++    mingw* | cygwin* | pw32* | os2*)
++      # This hack is so that the source file can tell whether it is being
++      # built for inclusion in a dll (and should export symbols for example).
++      m4_if([$1], [GCJ], [],
++	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++      ;;
+ 
+-# AC_LIBTOOL_LANG_RC_CONFIG
+-# -------------------------
+-# Ensure that the configuration vars for the Windows resource compiler are
+-# suitably defined.  Those variables are subsequently used by
+-# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+-AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+-AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+-[AC_LANG_SAVE
++    hpux9* | hpux10* | hpux11*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++      # not for PA HP-UX.
++      case $host_cpu in
++      hppa*64*|ia64*)
++	# +Z the default
++	;;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++	;;
++      esac
++      # Is there a better lt_prog_compiler_static that works with the bundled CC?
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++      ;;
+ 
+-# Source file extension for RC test sources.
+-ac_ext=rc
++    irix5* | irix6* | nonstopux*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      # PIC (with -KPIC) is the default.
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      ;;
+ 
+-# Object file extension for compiled RC test sources.
+-objext=o
+-_LT_AC_TAGVAR(objext, $1)=$objext
++    linux* | k*bsd*-gnu)
++      case $cc_basename in
++      icc* | ecc* | ifort*)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++        ;;
++      pgcc* | pgf77* | pgf90* | pgf95*)
++        # Portland Group compilers (*not* the Pentium gcc compiler,
++	# which looks to be a dead project)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++        ;;
++      ccc*)
++        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++        # All Alpha code is PIC.
++        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++        ;;
++      xl*)
++	# IBM XL C 8.0/Fortran 10.1 on PPC
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
++	;;
++      *)
++	case `$CC -V 2>&1 | sed 5q` in
++	*Sun\ C*)
++	  # Sun C 5.9
++	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++	  ;;
++	*Sun\ F*)
++	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
++	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
++	  ;;
++	esac
++	;;
++      esac
++      ;;
+ 
+-# Code to be used in simple compile tests
+-lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
++    newsos6)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
+ 
+-# Code to be used in simple link tests
+-lt_simple_link_test_code="$lt_simple_compile_test_code"
++    *nto* | *qnx*)
++      # QNX uses GNU C++, but need to define -shared option too, otherwise
++      # it will coredump.
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++      ;;
+ 
+-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+-_LT_AC_SYS_COMPILER
++    osf3* | osf4* | osf5*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      # All OSF/1 code is PIC.
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      ;;
+ 
+-# save warnings/boilerplate of simple test code
+-_LT_COMPILER_BOILERPLATE
+-_LT_LINKER_BOILERPLATE
++    rdos*)
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      ;;
+ 
+-# Allow CC to be a program name with arguments.
+-lt_save_CC="$CC"
+-CC=${RC-"windres"}
+-compiler=$CC
+-_LT_AC_TAGVAR(compiler, $1)=$CC
+-_LT_CC_BASENAME([$compiler])
+-_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
++    solaris*)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      case $cc_basename in
++      f77* | f90* | f95*)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
++      *)
++	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
++      esac
++      ;;
+ 
+-AC_LIBTOOL_CONFIG($1)
++    sunos4*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
+ 
+-AC_LANG_RESTORE
+-CC="$lt_save_CC"
+-])# AC_LIBTOOL_LANG_RC_CONFIG
++    sysv4 | sysv4.2uw2* | sysv4.3*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
++
++    sysv4*MP*)
++      if test -d /usr/nec ;then
++	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
++	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      fi
++      ;;
+ 
++    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      ;;
+ 
+-# AC_LIBTOOL_CONFIG([TAGNAME])
+-# ----------------------------
+-# If TAGNAME is not passed, then create an initial libtool script
+-# with a default configuration from the untagged config vars.  Otherwise
+-# add code to config.status for appending the configuration named by
+-# TAGNAME from the matching tagged config vars.
+-AC_DEFUN([AC_LIBTOOL_CONFIG],
+-[# The else clause should only fire when bootstrapping the
+-# libtool distribution, otherwise you forgot to ship ltmain.sh
+-# with your package, and you will get complaints that there are
+-# no rules to generate ltmain.sh.
+-if test -f "$ltmain"; then
+-  # See if we are running on zsh, and set the options which allow our commands through
+-  # without removal of \ escapes.
+-  if test -n "${ZSH_VERSION+set}" ; then
+-    setopt NO_GLOB_SUBST
+-  fi
+-  # Now quote all the things that may contain metacharacters while being
+-  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+-  # variables and quote the copies for generation of the libtool script.
+-  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+-    SED SHELL STRIP \
+-    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+-    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+-    deplibs_check_method reload_flag reload_cmds need_locks \
+-    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+-    lt_cv_sys_global_symbol_to_c_name_address \
+-    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+-    old_postinstall_cmds old_postuninstall_cmds \
+-    _LT_AC_TAGVAR(compiler, $1) \
+-    _LT_AC_TAGVAR(CC, $1) \
+-    _LT_AC_TAGVAR(LD, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+-    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+-    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+-    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+-    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+-    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+-    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+-    _LT_AC_TAGVAR(predep_objects, $1) \
+-    _LT_AC_TAGVAR(postdep_objects, $1) \
+-    _LT_AC_TAGVAR(predeps, $1) \
+-    _LT_AC_TAGVAR(postdeps, $1) \
+-    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+-    _LT_AC_TAGVAR(archive_cmds, $1) \
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+-    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+-    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+-    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+-    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+-    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+-    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+-    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+-    _LT_AC_TAGVAR(module_cmds, $1) \
+-    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+-    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+-    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+-    _LT_AC_TAGVAR(include_expsyms, $1); do
+-
+-    case $var in
+-    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+-    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+-    _LT_AC_TAGVAR(archive_cmds, $1) | \
+-    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+-    _LT_AC_TAGVAR(module_cmds, $1) | \
+-    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+-    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+-    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+-    postinstall_cmds | postuninstall_cmds | \
+-    old_postinstall_cmds | old_postuninstall_cmds | \
+-    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+-      # Double-quote double-evaled strings.
+-      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
++    unicos*)
++      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++      ;;
++
++    uts4*)
++      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       ;;
++
+     *)
+-      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
++      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+     esac
+-  done
+-
+-  case $lt_echo in
+-  *'\[$]0 --fallback-echo"')
+-    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
++  fi
++])
++case $host_os in
++  # For platforms which do not support PIC, -DPIC is meaningless:
++  *djgpp*)
++    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     ;;
+-  esac
+-
+-ifelse([$1], [],
+-  [cfgfile="${ofile}T"
+-  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+-  $rm -f "$cfgfile"
+-  AC_MSG_NOTICE([creating $ofile])],
+-  [cfgfile="$ofile"])
+-
+-  cat <<__EOF__ >> "$cfgfile"
+-ifelse([$1], [],
+-[#! $SHELL
++  *)
++    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
++    ;;
++esac
++AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
++_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
++	[How to pass a linker flag through the compiler])
+ 
+-# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+ #
+-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+-# Free Software Foundation, Inc.
+-#
+-# This file is part of GNU Libtool:
+-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
++# Check to make sure the PIC flag actually works.
+ #
+-# This program is distributed in the hope that it will be useful, but
+-# WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-# General Public License for more details.
++if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
++  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
++    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
++    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
++    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
++     "" | " "*) ;;
++     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
++     esac],
++    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
++     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
++fi
++_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
++	[Additional compiler flags for building library objects])
++
+ #
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++# Check to make sure the static flag actually works.
+ #
+-# As a special exception to the GNU General Public License, if you
+-# distribute this file as part of a program that contains a
+-# configuration script generated by Autoconf, you may include it under
+-# the same distribution terms that you use for the rest of that program.
+-
+-# A sed program that does not truncate output.
+-SED=$lt_SED
+-
+-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+-Xsed="$SED -e 1s/^X//"
+-
+-# The HP-UX ksh and POSIX shell print the target directory to stdout
+-# if CDPATH is set.
+-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+-
+-# The names of the tagged configurations supported by this script.
+-available_tags=
+-
+-# ### BEGIN LIBTOOL CONFIG],
+-[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+-
+-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+-
+-# Shell to use when invoking shell scripts.
+-SHELL=$lt_SHELL
+-
+-# Whether or not to build shared libraries.
+-build_libtool_libs=$enable_shared
+-
+-# Whether or not to build static libraries.
+-build_old_libs=$enable_static
+-
+-# Whether or not to add -lc for building shared libraries.
+-build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+-
+-# Whether or not to disallow shared libs when runtime libs are static
+-allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+-
+-# Whether or not to optimize for fast installation.
+-fast_install=$enable_fast_install
+-
+-# The host system.
+-host_alias=$host_alias
+-host=$host
+-host_os=$host_os
++wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
++_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
++  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
++  $lt_tmp_static_flag,
++  [],
++  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
++_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
++	[Compiler flag to prevent dynamic linking])
++])# _LT_COMPILER_PIC
+ 
+-# The build system.
+-build_alias=$build_alias
+-build=$build
+-build_os=$build_os
+ 
+-# An echo program that does not interpret backslashes.
+-echo=$lt_echo
++# _LT_LINKER_SHLIBS([TAGNAME])
++# ----------------------------
++# See if the linker supports building shared libraries.
++m4_defun([_LT_LINKER_SHLIBS],
++[AC_REQUIRE([LT_PATH_LD])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
++m4_if([$1], [CXX], [
++  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++  case $host_os in
++  aix[[4-9]]*)
++    # If we're using GNU nm, then we don't want the "-C" option.
++    # -C means demangle to AIX nm, but means don't demangle with GNU nm
++    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++    else
++      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++    fi
++    ;;
++  pw32*)
++    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
++  ;;
++  cygwin* | mingw*)
++    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
++  ;;
++  *)
++    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++  ;;
++  esac
++  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
++], [
++  runpath_var=
++  _LT_TAGVAR(allow_undefined_flag, $1)=
++  _LT_TAGVAR(always_export_symbols, $1)=no
++  _LT_TAGVAR(archive_cmds, $1)=
++  _LT_TAGVAR(archive_expsym_cmds, $1)=
++  _LT_TAGVAR(compiler_needs_object, $1)=no
++  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
++  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
++  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++  _LT_TAGVAR(hardcode_automatic, $1)=no
++  _LT_TAGVAR(hardcode_direct, $1)=no
++  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
++  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++  _LT_TAGVAR(hardcode_libdir_separator, $1)=
++  _LT_TAGVAR(hardcode_minus_L, $1)=no
++  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++  _LT_TAGVAR(inherit_rpath, $1)=no
++  _LT_TAGVAR(link_all_deplibs, $1)=unknown
++  _LT_TAGVAR(module_cmds, $1)=
++  _LT_TAGVAR(module_expsym_cmds, $1)=
++  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
++  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
++  _LT_TAGVAR(thread_safe_flag_spec, $1)=
++  _LT_TAGVAR(whole_archive_flag_spec, $1)=
++  # include_expsyms should be a list of space-separated symbols to be *always*
++  # included in the symbol list
++  _LT_TAGVAR(include_expsyms, $1)=
++  # exclude_expsyms can be an extended regexp of symbols to exclude
++  # it will be wrapped by ` (' and `)$', so one must not match beginning or
++  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
++  # as well as any symbol that contains `d'.
++  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
++  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
++  # platforms (ab)use it in PIC code, but their linkers get confused if
++  # the symbol is explicitly referenced.  Since portable code cannot
++  # rely on this symbol name, it's probably fine to never include it in
++  # preloaded symbol tables.
++  # Exclude shared library initialization/finalization symbols.
++dnl Note also adjust exclude_expsyms for C++ above.
++  extract_expsyms_cmds=
+ 
+-# The archiver.
+-AR=$lt_AR
+-AR_FLAGS=$lt_AR_FLAGS
++  case $host_os in
++  cygwin* | mingw* | pw32*)
++    # FIXME: the MSVC++ port hasn't been tested in a loooong time
++    # When not using gcc, we currently assume that we are using
++    # Microsoft Visual C++.
++    if test "$GCC" != yes; then
++      with_gnu_ld=no
++    fi
++    ;;
++  interix*)
++    # we just hope/assume this is gcc and not c89 (= MSVC++)
++    with_gnu_ld=yes
++    ;;
++  openbsd*)
++    with_gnu_ld=no
++    ;;
++  esac
+ 
+-# A C compiler.
+-LTCC=$lt_LTCC
++  _LT_TAGVAR(ld_shlibs, $1)=yes
++  if test "$with_gnu_ld" = yes; then
++    # If archive_cmds runs LD, not CC, wlarc should be empty
++    wlarc='${wl}'
+ 
+-# LTCC compiler flags.
+-LTCFLAGS=$lt_LTCFLAGS
++    # Set some defaults for GNU ld with shared library support. These
++    # are reset later if shared libraries are not supported. Putting them
++    # here allows them to be overridden if necessary.
++    runpath_var=LD_RUN_PATH
++    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++    # ancient GNU ld didn't support --whole-archive et. al.
++    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
++      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++    else
++      _LT_TAGVAR(whole_archive_flag_spec, $1)=
++    fi
++    supports_anon_versioning=no
++    case `$LD -v 2>&1` in
++      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
++      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
++      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
++      *\ 2.11.*) ;; # other 2.11 versions
++      *) supports_anon_versioning=yes ;;
++    esac
+ 
+-# A language-specific compiler.
+-CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
++    # See if GNU ld supports shared libraries.
++    case $host_os in
++    aix[[3-9]]*)
++      # On AIX/PPC, the GNU linker is very broken
++      if test "$host_cpu" != ia64; then
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	cat <<_LT_EOF 1>&2
+ 
+-# Is the compiler the GNU C compiler?
+-with_gcc=$_LT_AC_TAGVAR(GCC, $1)
++*** Warning: the GNU linker, at least up to release 2.9.1, is reported
++*** to be unable to reliably create shared libraries on AIX.
++*** Therefore, libtool is disabling shared libraries support.  If you
++*** really care for shared libraries, you may want to modify your PATH
++*** so that a non-GNU linker is found, and then restart.
+ 
+-# An ERE matcher.
+-EGREP=$lt_EGREP
++_LT_EOF
++      fi
++      ;;
+ 
+-# The linker used to build libraries.
+-LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++            _LT_TAGVAR(archive_expsym_cmds, $1)=''
++        ;;
++      m68k)
++            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++            _LT_TAGVAR(hardcode_minus_L, $1)=yes
++        ;;
++      esac
++      ;;
+ 
+-# Whether we need hard or soft links.
+-LN_S=$lt_LN_S
++    beos*)
++      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++	# support --undefined.  This deserves some investigation.  FIXME
++	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# A BSD-compatible nm program.
+-NM=$lt_NM
++    cygwin* | mingw* | pw32*)
++      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
++      # as there is no search path for DLLs.
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      _LT_TAGVAR(always_export_symbols, $1)=no
++      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ 
+-# A symbol stripping program
+-STRIP=$lt_STRIP
++      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++	# If the export-symbols file already is a .def file (1st line
++	# is EXPORTS), use it as is; otherwise, prepend...
++	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++	  cp $export_symbols $output_objdir/$soname.def;
++	else
++	  echo EXPORTS > $output_objdir/$soname.def;
++	  cat $export_symbols >> $output_objdir/$soname.def;
++	fi~
++	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# Used to examine libraries when file_magic_cmd begins "file"
+-MAGIC_CMD=$MAGIC_CMD
++    interix[[3-9]]*)
++      _LT_TAGVAR(hardcode_direct, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++      # Instead, shared libraries are loaded at an image base (0x10000000 by
++      # default) and relocated if they conflict, which is a slow very memory
++      # consuming and fragmenting process.  To avoid this, we pick a random,
++      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
++      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++      ;;
+ 
+-# Used on cygwin: DLL creation program.
+-DLLTOOL="$DLLTOOL"
++    gnu* | linux* | tpf* | k*bsd*-gnu)
++      tmp_diet=no
++      if test "$host_os" = linux-dietlibc; then
++	case $cc_basename in
++	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
++	esac
++      fi
++      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
++	 && test "$tmp_diet" = no
++      then
++	tmp_addflag=
++	tmp_sharedflag='-shared'
++	case $cc_basename,$host_cpu in
++        pgcc*)				# Portland Group C compiler
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	  tmp_addflag=' $pic_flag'
++	  ;;
++	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	  tmp_addflag=' $pic_flag -Mnomain' ;;
++	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
++	  tmp_addflag=' -i_dynamic' ;;
++	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
++	  tmp_addflag=' -i_dynamic -nofor_main' ;;
++	ifc* | ifort*)			# Intel Fortran compiler
++	  tmp_addflag=' -nofor_main' ;;
++	xl[[cC]]*)			# IBM XL C 8.0 on PPC (deal with xlf below)
++	  tmp_sharedflag='-qmkshrobj'
++	  tmp_addflag= ;;
++	esac
++	case `$CC -V 2>&1 | sed 5q` in
++	*Sun\ C*)			# Sun C 5.9
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	  _LT_TAGVAR(compiler_needs_object, $1)=yes
++	  tmp_sharedflag='-G' ;;
++	*Sun\ F*)			# Sun Fortran 8.3
++	  tmp_sharedflag='-G' ;;
++	esac
++	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ 
+-# Used on cygwin: object dumper.
+-OBJDUMP="$OBJDUMP"
++        if test "x$supports_anon_versioning" = xyes; then
++          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++	    echo "local: *; };" >> $output_objdir/$libname.ver~
++	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++        fi
+ 
+-# Used on cygwin: assembler.
+-AS="$AS"
++	case $cc_basename in
++	xlf*)
++	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++	  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
++	  if test "x$supports_anon_versioning" = xyes; then
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++	      echo "local: *; };" >> $output_objdir/$libname.ver~
++	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
++	  fi
++	  ;;
++	esac
++      else
++        _LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# The name of the directory that contains temporary libtool files.
+-objdir=$objdir
++    netbsd*)
++      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
++	wlarc=
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++      fi
++      ;;
+ 
+-# How to create reloadable object files.
+-reload_flag=$lt_reload_flag
+-reload_cmds=$lt_reload_cmds
++    solaris*)
++      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	cat <<_LT_EOF 1>&2
+ 
+-# How to pass a linker flag through the compiler.
+-wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
++*** Warning: The releases 2.8.* of the GNU linker cannot reliably
++*** create shared libraries on Solaris systems.  Therefore, libtool
++*** is disabling shared libraries support.  We urge you to upgrade GNU
++*** binutils to release 2.9.1 or newer.  Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
+ 
+-# Object file suffix (normally "o").
+-objext="$ac_objext"
++_LT_EOF
++      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# Old archive suffix (normally "a").
+-libext="$libext"
++    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
++      case `$LD -v 2>&1` in
++        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	cat <<_LT_EOF 1>&2
+ 
+-# Shared library suffix (normally ".so").
+-shrext_cmds='$shrext_cmds'
++*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
++*** reliably create shared libraries on SCO systems.  Therefore, libtool
++*** is disabling shared libraries support.  We urge you to upgrade GNU
++*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
+ 
+-# Executable file suffix (normally "").
+-exeext="$exeext"
++_LT_EOF
++	;;
++	*)
++	  # For security reasons, it is highly recommended that you always
++	  # use absolute paths for naming shared libraries, and exclude the
++	  # DT_RUNPATH tag from executables and libraries.  But doing so
++	  # requires that you compile everything twice, which is a pain.
++	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++	  else
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	  fi
++	;;
++      esac
++      ;;
+ 
+-# Additional compiler flags for building library objects.
+-pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+-pic_mode=$pic_mode
++    sunos4*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++      wlarc=
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# What is the maximum length of a command?
+-max_cmd_len=$lt_cv_sys_max_cmd_len
++    *)
++      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
++    esac
+ 
+-# Does compiler simultaneously support -c and -o options?
+-compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
++    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
++      runpath_var=
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
++      _LT_TAGVAR(whole_archive_flag_spec, $1)=
++    fi
++  else
++    # PORTME fill in a description of your system's linker (not GNU ld)
++    case $host_os in
++    aix3*)
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      _LT_TAGVAR(always_export_symbols, $1)=yes
++      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
++      # Note: this linker hardcodes the directories in LIBPATH if there
++      # are no directories specified by -L.
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
++	# Neither direct hardcoding nor static linking is supported with a
++	# broken collect2.
++	_LT_TAGVAR(hardcode_direct, $1)=unsupported
++      fi
++      ;;
+ 
+-# Must we lock files when doing compilation?
+-need_locks=$lt_need_locks
++    aix[[4-9]]*)
++      if test "$host_cpu" = ia64; then
++	# On IA64, the linker does run time linking by default, so we don't
++	# have to do anything special.
++	aix_use_runtimelinking=no
++	exp_sym_flag='-Bexport'
++	no_entry_flag=""
++      else
++	# If we're using GNU nm, then we don't want the "-C" option.
++	# -C means demangle to AIX nm, but means don't demangle with GNU nm
++	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++	else
++	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++	fi
++	aix_use_runtimelinking=no
+ 
+-# Do we need the lib prefix for modules?
+-need_lib_prefix=$need_lib_prefix
++	# Test if we are trying to use run time linking or normal
++	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
++	# need to do runtime linking.
++	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
++	  for ld_flag in $LDFLAGS; do
++	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
++	    aix_use_runtimelinking=yes
++	    break
++	  fi
++	  done
++	  ;;
++	esac
+ 
+-# Do we need a version for libraries?
+-need_version=$need_version
++	exp_sym_flag='-bexport'
++	no_entry_flag='-bnoentry'
++      fi
+ 
+-# Whether dlopen is supported.
+-dlopen_support=$enable_dlopen
++      # When large executables or shared objects are built, AIX ld can
++      # have problems creating the table of contents.  If linking a library
++      # or program results in "error TOC overflow" add -mminimal-toc to
++      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
++      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ 
+-# Whether dlopen of programs is supported.
+-dlopen_self=$enable_dlopen_self
++      _LT_TAGVAR(archive_cmds, $1)=''
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+ 
+-# Whether dlopen of statically linked programs is supported.
+-dlopen_self_static=$enable_dlopen_self_static
++      if test "$GCC" = yes; then
++	case $host_os in aix4.[[012]]|aix4.[[012]].*)
++	# We only want to do this on AIX 4.2 and lower, the check
++	# below for broken collect2 doesn't work under 4.3+
++	  collect2name=`${CC} -print-prog-name=collect2`
++	  if test -f "$collect2name" &&
++	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++	  then
++	  # We have reworked collect2
++	  :
++	  else
++	  # We have old collect2
++	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
++	  # It fails to find uninstalled libraries when the uninstalled
++	  # path is not listed in the libpath.  Setting hardcode_minus_L
++	  # to unsupported forces relinking
++	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
++	  fi
++	  ;;
++	esac
++	shared_flag='-shared'
++	if test "$aix_use_runtimelinking" = yes; then
++	  shared_flag="$shared_flag "'${wl}-G'
++	fi
++      else
++	# not using gcc
++	if test "$host_cpu" = ia64; then
++	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++	# chokes on -Wl,-G. The following line is correct:
++	  shared_flag='-G'
++	else
++	  if test "$aix_use_runtimelinking" = yes; then
++	    shared_flag='${wl}-G'
++	  else
++	    shared_flag='${wl}-bM:SRE'
++	  fi
++	fi
++      fi
+ 
+-# Compiler flag to prevent dynamic linking.
+-link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
++      # It seems that -bexpall does not export symbols beginning with
++      # underscore (_), so it is better to generate a list of symbols to export.
++      _LT_TAGVAR(always_export_symbols, $1)=yes
++      if test "$aix_use_runtimelinking" = yes; then
++	# Warning - without using the other runtime loading flags (-brtl),
++	# -berok will link without error, but may produce a broken library.
++	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
++        # Determine the default libpath from the value encoded in an
++        # empty executable.
++        _LT_SYS_MODULE_PATH_AIX
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++      else
++	if test "$host_cpu" = ia64; then
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
++	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
++	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++	else
++	 # Determine the default libpath from the value encoded in an
++	 # empty executable.
++	 _LT_SYS_MODULE_PATH_AIX
++	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++	  # Warning - without using the other run time loading flags,
++	  # -berok will link without error, but may produce a broken library.
++	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
++	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
++	  # Exported symbols can be pulled into shared objects from archives
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
++	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++	  # This is similar to how AIX traditionally builds its shared libraries.
++	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++	fi
++      fi
++      ;;
+ 
+-# Compiler flag to turn off builtin functions.
+-no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
++    amigaos*)
++      case $host_cpu in
++      powerpc)
++            # see comment about AmigaOS4 .so support
++            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++            _LT_TAGVAR(archive_expsym_cmds, $1)=''
++        ;;
++      m68k)
++            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++            _LT_TAGVAR(hardcode_minus_L, $1)=yes
++        ;;
++      esac
++      ;;
+ 
+-# Compiler flag to allow reflexive dlopens.
+-export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
++    bsdi[[45]]*)
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
++      ;;
+ 
+-# Compiler flag to generate shared objects directly from archives.
+-whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
++    cygwin* | mingw* | pw32*)
++      # When not using gcc, we currently assume that we are using
++      # Microsoft Visual C++.
++      # hardcode_libdir_flag_spec is actually meaningless, as there is
++      # no search path for DLLs.
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      # Tell ltmain to make .lib files, not .a files.
++      libext=lib
++      # Tell ltmain to make .dll files, not .so files.
++      shrext_cmds=".dll"
++      # FIXME: Setting linknames here is a bad hack.
++      _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
++      # The linker will automatically build a .lib file if we build a DLL.
++      _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
++      # FIXME: Should let the user specify the lib program.
++      _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
++      _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
++      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++      ;;
+ 
+-# Compiler flag to generate thread-safe objects.
+-thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
++    darwin* | rhapsody*)
++      _LT_DARWIN_LINKER_FEATURES($1)
++      ;;
+ 
+-# Library versioning type.
+-version_type=$version_type
++    dgux*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Format of library name prefix.
+-libname_spec=$lt_libname_spec
++    freebsd1*)
++      _LT_TAGVAR(ld_shlibs, $1)=no
++      ;;
+ 
+-# List of archive names.  First name is the real one, the rest are links.
+-# The last name is the one that the linker finds with -lNAME.
+-library_names_spec=$lt_library_names_spec
++    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
++    # support.  Future versions do this automatically, but an explicit c++rt0.o
++    # does not break anything, and helps significantly (at the cost of a little
++    # extra space).
++    freebsd2.2*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# The coded name of the library, if different from the real name.
+-soname_spec=$lt_soname_spec
++    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
++    freebsd2*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Commands used to build and install an old-style archive.
+-RANLIB=$lt_RANLIB
+-old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+-old_postinstall_cmds=$lt_old_postinstall_cmds
+-old_postuninstall_cmds=$lt_old_postuninstall_cmds
++    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
++    freebsd* | dragonfly*)
++      _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Create an old-style archive from a shared archive.
+-old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
++    hpux9*)
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      _LT_TAGVAR(hardcode_direct, $1)=yes
+ 
+-# Create a temporary old-style archive to link instead of a shared archive.
+-old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
++      # hardcode_minus_L: Not really in the search PATH,
++      # but as the default location of the library.
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++      ;;
+ 
+-# Commands used to build and install a shared archive.
+-archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+-archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+-postinstall_cmds=$lt_postinstall_cmds
+-postuninstall_cmds=$lt_postuninstall_cmds
++    hpux10*)
++      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++      fi
++      if test "$with_gnu_ld" = no; then
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++	_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
++	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
++	_LT_TAGVAR(hardcode_direct, $1)=yes
++	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	# hardcode_minus_L: Not really in the search PATH,
++	# but as the default location of the library.
++	_LT_TAGVAR(hardcode_minus_L, $1)=yes
++      fi
++      ;;
+ 
+-# Commands used to build a loadable module (assumed same as above if empty)
+-module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+-module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
++    hpux11*)
++      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
++	case $host_cpu in
++	hppa*64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	ia64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	esac
++      else
++	case $host_cpu in
++	hppa*64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	ia64*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	esac
++      fi
++      if test "$with_gnu_ld" = no; then
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ 
+-# Commands to strip libraries.
+-old_striplib=$lt_old_striplib
+-striplib=$lt_striplib
++	case $host_cpu in
++	hppa*64*|ia64*)
++	  _LT_TAGVAR(hardcode_direct, $1)=no
++	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	  ;;
++	*)
++	  _LT_TAGVAR(hardcode_direct, $1)=yes
++	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ 
+-# Dependencies to place before the objects being linked to create a
+-# shared library.
+-predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
++	  # hardcode_minus_L: Not really in the search PATH,
++	  # but as the default location of the library.
++	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
++	  ;;
++	esac
++      fi
++      ;;
+ 
+-# Dependencies to place after the objects being linked to create a
+-# shared library.
+-postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
++    irix5* | irix6* | nonstopux*)
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++	# Try to use the -exported_symbol ld option, if it does not
++	# work, assume that -exports_file does not work either and
++	# implicitly export all symbols.
++        save_LDFLAGS="$LDFLAGS"
++        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
++        AC_LINK_IFELSE(int foo(void) {},
++          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
++        )
++        LDFLAGS="$save_LDFLAGS"
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
++      fi
++      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      _LT_TAGVAR(inherit_rpath, $1)=yes
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      ;;
+ 
+-# Dependencies to place before the objects being linked to create a
+-# shared library.
+-predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
++    netbsd*)
++      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Dependencies to place after the objects being linked to create a
+-# shared library.
+-postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
++    newsos6)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# The library search path used internally by the compiler when linking
+-# a shared library.
+-compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
++    *nto* | *qnx*)
++      ;;
+ 
+-# Method to check whether dependent libraries are shared objects.
+-deplibs_check_method=$lt_deplibs_check_method
++    openbsd*)
++      if test -f /usr/libexec/ld.so; then
++	_LT_TAGVAR(hardcode_direct, $1)=yes
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	else
++	  case $host_os in
++	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
++	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	     ;;
++	   *)
++	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	     ;;
++	  esac
++	fi
++      else
++	_LT_TAGVAR(ld_shlibs, $1)=no
++      fi
++      ;;
+ 
+-# Command to use when deplibs_check_method == file_magic.
+-file_magic_cmd=$lt_file_magic_cmd
++    os2*)
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
++      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
++      ;;
+ 
+-# Flag that allows shared libraries with undefined symbols to be built.
+-allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
++    osf3*)
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++      else
++	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++      fi
++      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      ;;
+ 
+-# Flag that forces no undefined symbols.
+-no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
++    osf4* | osf5*)	# as osf3* with the addition of -msym flag
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++      else
++	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
++	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+ 
+-# Commands used to finish a libtool library installation in a directory.
+-finish_cmds=$lt_finish_cmds
++	# Both c and cxx compiler support -rpath directly
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++      fi
++      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++      ;;
+ 
+-# Same as above, but a single script fragment to be evaled but not shown.
+-finish_eval=$lt_finish_eval
++    solaris*)
++      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
++      if test "$GCC" = yes; then
++	wlarc='${wl}'
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++      else
++	case `$CC -V 2>&1` in
++	*"Compilers 5.0"*)
++	  wlarc=''
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
++	  ;;
++	*)
++	  wlarc='${wl}'
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++	  ;;
++	esac
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      case $host_os in
++      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++      *)
++	# The compiler driver will combine and reorder linker options,
++	# but understands `-z linker_flag'.  GCC discards it without `$wl',
++	# but is careful enough not to reorder.
++	# Supported since Solaris 2.6 (maybe 2.5.1?)
++	if test "$GCC" = yes; then
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++	else
++	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
++	fi
++	;;
++      esac
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      ;;
+ 
+-# Take the output of nm and produce a listing of raw symbols and C names.
+-global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
++    sunos4*)
++      if test "x$host_vendor" = xsequent; then
++	# Use $CC to link under sequent, because it throws in some extra .o
++	# files that make .init and .fini sections work.
++	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
++      fi
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_direct, $1)=yes
++      _LT_TAGVAR(hardcode_minus_L, $1)=yes
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Transform the output of nm in a proper C declaration
+-global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
++    sysv4)
++      case $host_vendor in
++	sni)
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
++	;;
++	siemens)
++	  ## LD is ld it makes a PLAMLIB
++	  ## CC just makes a GrossModule.
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
++	  _LT_TAGVAR(hardcode_direct, $1)=no
++        ;;
++	motorola)
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
++	;;
++      esac
++      runpath_var='LD_RUN_PATH'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# Transform the output of nm in a C name address pair
+-global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
++    sysv4.3*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
++      ;;
+ 
+-# This is the shared library runtime path variable.
+-runpath_var=$runpath_var
++    sysv4*MP*)
++      if test -d /usr/nec; then
++	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	runpath_var=LD_RUN_PATH
++	hardcode_runpath_var=yes
++	_LT_TAGVAR(ld_shlibs, $1)=yes
++      fi
++      ;;
+ 
+-# This is the shared library path variable.
+-shlibpath_var=$shlibpath_var
++    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      runpath_var='LD_RUN_PATH'
+ 
+-# Is shlibpath searched before the hard-coded library search path?
+-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      fi
++      ;;
+ 
+-# How to hardcode a shared library path into an executable.
+-hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
++    sysv5* | sco3.2v5* | sco5v6*)
++      # Note: We can NOT use -z defs as we might desire, because we do not
++      # link with -lc, and that would cause any symbols used from libc to
++      # always be unresolved, which means just about no library would
++      # ever link correctly.  If we're not using GNU ld we use -z text
++      # though, which does catch some bad symbols but isn't as heavy-handed
++      # as -z defs.
++      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
++      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++      _LT_TAGVAR(link_all_deplibs, $1)=yes
++      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++      runpath_var='LD_RUN_PATH'
+ 
+-# Whether we should hardcode library paths into libraries.
+-hardcode_into_libs=$hardcode_into_libs
++      if test "$GCC" = yes; then
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      else
++	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++      fi
++      ;;
+ 
+-# Flag to hardcode \$libdir into a binary during linking.
+-# This must work even if \$libdir does not exist.
+-hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
++    uts4*)
++      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      ;;
+ 
+-# If ld is used when linking, flag to hardcode \$libdir into
+-# a binary during linking. This must work even if \$libdir does
+-# not exist.
+-hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
++    *)
++      _LT_TAGVAR(ld_shlibs, $1)=no
++      ;;
++    esac
+ 
+-# Whether we need a single -rpath flag with a separated argument.
+-hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
++    if test x$host_vendor = xsni; then
++      case $host in
++      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
++	;;
++      esac
++    fi
++  fi
++])
++AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
++test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+ 
+-# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+-# resulting binary.
+-hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
++_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+ 
+-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+-# resulting binary.
+-hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
++_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
++_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
++_LT_DECL([], [extract_expsyms_cmds], [2],
++    [The commands to extract the exported symbol list from a shared archive])
+ 
+-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+-# the resulting binary.
+-hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
++#
++# Do we need to explicitly link libc?
++#
++case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
++x|xyes)
++  # Assume -lc should be added
++  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ 
+-# Set to yes if building a shared library automatically hardcodes DIR into the library
+-# and all subsequent libraries and executables linked against it.
+-hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
++  if test "$enable_shared" = yes && test "$GCC" = yes; then
++    case $_LT_TAGVAR(archive_cmds, $1) in
++    *'~'*)
++      # FIXME: we may have to deal with multi-command sequences.
++      ;;
++    '$CC '*)
++      # Test whether the compiler implicitly links with -lc since on some
++      # systems, -lgcc has to come before -lc. If gcc already passes -lc
++      # to ld, don't add -lc before -lgcc.
++      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
++      $RM conftest*
++      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
+-# Variables whose values should be saved in libtool wrapper scripts and
+-# restored at relink time.
+-variables_saved_for_relink="$variables_saved_for_relink"
++      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
++        soname=conftest
++        lib=conftest
++        libobjs=conftest.$ac_objext
++        deplibs=
++        wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
++	pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
++        compiler_flags=-v
++        linker_flags=-v
++        verstring=
++        output_objdir=.
++        libname=conftest
++        lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
++        _LT_TAGVAR(allow_undefined_flag, $1)=
++        if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
++        then
++	  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++        else
++	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++        fi
++        _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
++      else
++        cat conftest.err 1>&5
++      fi
++      $RM conftest*
++      AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)])
++      ;;
++    esac
++  fi
++  ;;
++esac
+ 
+-# Whether libtool must link a program against all its dependency libraries.
+-link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
++_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
++    [Whether or not to add -lc for building shared libraries])
++_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
++    [enable_shared_with_static_runtimes], [0],
++    [Whether or not to disallow shared libs when runtime libs are static])
++_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
++    [Compiler flag to allow reflexive dlopens])
++_LT_TAGDECL([], [whole_archive_flag_spec], [1],
++    [Compiler flag to generate shared objects directly from archives])
++_LT_TAGDECL([], [compiler_needs_object], [1],
++    [Whether the compiler copes with passing no objects directly])
++_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
++    [Create an old-style archive from a shared archive])
++_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
++    [Create a temporary old-style archive to link instead of a shared archive])
++_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
++_LT_TAGDECL([], [archive_expsym_cmds], [2])
++_LT_TAGDECL([], [module_cmds], [2],
++    [Commands used to build a loadable module if different from building
++    a shared archive.])
++_LT_TAGDECL([], [module_expsym_cmds], [2])
++_LT_TAGDECL([], [with_gnu_ld], [1],
++    [Whether we are building with GNU ld or not])
++_LT_TAGDECL([], [allow_undefined_flag], [1],
++    [Flag that allows shared libraries with undefined symbols to be built])
++_LT_TAGDECL([], [no_undefined_flag], [1],
++    [Flag that enforces no undefined symbols])
++_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
++    [Flag to hardcode $libdir into a binary during linking.
++    This must work even if $libdir does not exist])
++_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
++    [[If ld is used when linking, flag to hardcode $libdir into a binary
++    during linking.  This must work even if $libdir does not exist]])
++_LT_TAGDECL([], [hardcode_libdir_separator], [1],
++    [Whether we need a single "-rpath" flag with a separated argument])
++_LT_TAGDECL([], [hardcode_direct], [0],
++    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
++    DIR into the resulting binary])
++_LT_TAGDECL([], [hardcode_direct_absolute], [0],
++    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
++    DIR into the resulting binary and the resulting library dependency is
++    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
++    library is relocated])
++_LT_TAGDECL([], [hardcode_minus_L], [0],
++    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
++    into the resulting binary])
++_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
++    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
++    into the resulting binary])
++_LT_TAGDECL([], [hardcode_automatic], [0],
++    [Set to "yes" if building a shared library automatically hardcodes DIR
++    into the library and all subsequent libraries and executables linked
++    against it])
++_LT_TAGDECL([], [inherit_rpath], [0],
++    [Set to yes if linker adds runtime paths of dependent libraries
++    to runtime path list])
++_LT_TAGDECL([], [link_all_deplibs], [0],
++    [Whether libtool must link a program against all its dependency libraries])
++_LT_TAGDECL([], [fix_srcfile_path], [1],
++    [Fix the shell variable $srcfile for the compiler])
++_LT_TAGDECL([], [always_export_symbols], [0],
++    [Set to "yes" if exported symbols are required])
++_LT_TAGDECL([], [export_symbols_cmds], [2],
++    [The commands to list exported symbols])
++_LT_TAGDECL([], [exclude_expsyms], [1],
++    [Symbols that should not be listed in the preloaded symbols])
++_LT_TAGDECL([], [include_expsyms], [1],
++    [Symbols that must always be exported])
++_LT_TAGDECL([], [prelink_cmds], [2],
++    [Commands necessary for linking programs (against libraries) with templates])
++_LT_TAGDECL([], [file_list_spec], [1],
++    [Specify filename containing input files])
++dnl FIXME: Not yet implemented
++dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
++dnl    [Compiler flag to generate thread safe objects])
++])# _LT_LINKER_SHLIBS
+ 
+-# Compile-time system search path for libraries
+-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+ 
+-# Run-time system search path for libraries
+-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
++# _LT_LANG_C_CONFIG([TAG])
++# ------------------------
++# Ensure that the configuration variables for a C compiler are suitably
++# defined.  These variables are subsequently used by _LT_CONFIG to write
++# the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_C_CONFIG],
++[m4_require([_LT_DECL_EGREP])dnl
++lt_save_CC="$CC"
++AC_LANG_PUSH(C)
+ 
+-# Fix the shell variable \$srcfile for the compiler.
+-fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
++# Source file extension for C test sources.
++ac_ext=c
+ 
+-# Set to yes if exported symbols are required.
+-always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
++# Object file extension for compiled C test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-# The commands to list exported symbols.
+-export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="int some_variable = 0;"
+ 
+-# The commands to extract the exported symbol list from a shared archive.
+-extract_expsyms_cmds=$lt_extract_expsyms_cmds
++# Code to be used in simple link tests
++lt_simple_link_test_code='int main(){return(0);}'
+ 
+-# Symbols that should not be listed in the preloaded symbols.
+-exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
++_LT_TAG_COMPILER
++# Save the default compiler, since it gets overwritten when the other
++# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
++compiler_DEFAULT=$CC
+ 
+-# Symbols that must always be exported.
+-include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
+ 
+-ifelse([$1],[],
+-[# ### END LIBTOOL CONFIG],
+-[# ### END LIBTOOL TAG CONFIG: $tagname])
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++  _LT_COMPILER_NO_RTTI($1)
++  _LT_COMPILER_PIC($1)
++  _LT_COMPILER_C_O($1)
++  _LT_COMPILER_FILE_LOCKS($1)
++  _LT_LINKER_SHLIBS($1)
++  _LT_SYS_DYNAMIC_LINKER($1)
++  _LT_LINKER_HARDCODE_LIBPATH($1)
++  LT_SYS_DLOPEN_SELF
++  _LT_CMD_STRIPLIB
++
++  # Report which library types will actually be built
++  AC_MSG_CHECKING([if libtool supports shared libraries])
++  AC_MSG_RESULT([$can_build_shared])
+ 
+-__EOF__
++  AC_MSG_CHECKING([whether to build shared libraries])
++  test "$can_build_shared" = "no" && enable_shared=no
+ 
+-ifelse([$1],[], [
++  # On AIX, shared libraries and static libraries use the same namespace, and
++  # are all built from PIC.
+   case $host_os in
+   aix3*)
+-    cat <<\EOF >> "$cfgfile"
++    test "$enable_shared" = yes && enable_static=no
++    if test -n "$RANLIB"; then
++      archive_cmds="$archive_cmds~\$RANLIB \$lib"
++      postinstall_cmds='$RANLIB $lib'
++    fi
++    ;;
+ 
+-# AIX sometimes has problems with the GCC collect2 program.  For some
+-# reason, if we set the COLLECT_NAMES environment variable, the problems
+-# vanish in a puff of smoke.
+-if test "X${COLLECT_NAMES+set}" != Xset; then
+-  COLLECT_NAMES=
+-  export COLLECT_NAMES
+-fi
+-EOF
++  aix[[4-9]]*)
++    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++      test "$enable_shared" = yes && enable_static=no
++    fi
+     ;;
+   esac
++  AC_MSG_RESULT([$enable_shared])
+ 
+-  # We use sed instead of cat because bash on DJGPP gets confused if
+-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+-  # text mode, it properly converts lines to CR/LF.  This bash problem
+-  # is reportedly fixed, but why not run on old versions too?
+-  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
++  AC_MSG_CHECKING([whether to build static libraries])
++  # Make sure either enable_shared or enable_static is yes.
++  test "$enable_shared" = yes || enable_static=yes
++  AC_MSG_RESULT([$enable_static])
+ 
+-  mv -f "$cfgfile" "$ofile" || \
+-    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+-  chmod +x "$ofile"
+-])
+-else
+-  # If there is no Makefile yet, we rely on a make rule to execute
+-  # `config.status --recheck' to rerun these tests and create the
+-  # libtool script then.
+-  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+-  if test -f "$ltmain_in"; then
+-    test -f Makefile && make "$ltmain"
+-  fi
++  _LT_CONFIG($1)
+ fi
+-])# AC_LIBTOOL_CONFIG
+-
+-
+-# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+-# -------------------------------------------
+-AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+-[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+-
+-_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++AC_LANG_POP
++CC="$lt_save_CC"
++])# _LT_LANG_C_CONFIG
+ 
+-if test "$GCC" = yes; then
+-  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ 
+-  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+-    lt_cv_prog_compiler_rtti_exceptions,
+-    [-fno-rtti -fno-exceptions], [],
+-    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
++# _LT_PROG_CXX
++# ------------
++# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++
++# compiler, we have our own version here.
++m4_defun([_LT_PROG_CXX],
++[
++pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes])
++AC_PROG_CXX
++if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
++    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
++    (test "X$CXX" != "Xg++"))) ; then
++  AC_PROG_CXXCPP
++else
++  _lt_caught_CXX_error=yes
+ fi
+-])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
++popdef([AC_MSG_ERROR])
++])# _LT_PROG_CXX
+ 
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([_LT_PROG_CXX], [])
+ 
+-# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+-# ---------------------------------
+-AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+-[AC_REQUIRE([AC_CANONICAL_HOST])
+-AC_REQUIRE([AC_PROG_NM])
+-AC_REQUIRE([AC_OBJEXT])
+-# Check for command to grab the raw symbol name followed by C symbol from nm.
+-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+-[
+-# These are sane defaults that work on at least a few old systems.
+-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+-
+-# Character class describing NM global symbol codes.
+-symcode='[[BCDEGRST]]'
+ 
+-# Regexp to match symbols that can be accessed directly from C.
+-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
++# _LT_LANG_CXX_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for a C++ compiler are suitably
++# defined.  These variables are subsequently used by _LT_CONFIG to write
++# the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_CXX_CONFIG],
++[AC_REQUIRE([_LT_PROG_CXX])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_EGREP])dnl
++
++AC_LANG_PUSH(C++)
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(compiler_needs_object, $1)=no
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ 
+-# Transform an extracted symbol line into a proper C declaration
+-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
++# Source file extension for C++ test sources.
++ac_ext=cpp
+ 
+-# Transform an extracted symbol line into symbol name and symbol address
+-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
++# Object file extension for compiled C++ test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-# Define system-specific variables.
+-case $host_os in
+-aix*)
+-  symcode='[[BCDT]]'
+-  ;;
+-cygwin* | mingw* | pw32*)
+-  symcode='[[ABCDGISTW]]'
+-  ;;
+-hpux*) # Its linker distinguishes data from code symbols
+-  if test "$host_cpu" = ia64; then
+-    symcode='[[ABCDEGRST]]'
++# No sense in running all these tests if we already determined that
++# the CXX compiler isn't working.  Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_caught_CXX_error" != yes; then
++  # Code to be used in simple compile tests
++  lt_simple_compile_test_code="int some_variable = 0;"
++
++  # Code to be used in simple link tests
++  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
++
++  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++  _LT_TAG_COMPILER
++
++  # save warnings/boilerplate of simple test code
++  _LT_COMPILER_BOILERPLATE
++  _LT_LINKER_BOILERPLATE
++
++  # Allow CC to be a program name with arguments.
++  lt_save_CC=$CC
++  lt_save_LD=$LD
++  lt_save_GCC=$GCC
++  GCC=$GXX
++  lt_save_with_gnu_ld=$with_gnu_ld
++  lt_save_path_LD=$lt_cv_path_LD
++  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
++    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
++  else
++    $as_unset lt_cv_prog_gnu_ld
+   fi
+-  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+-  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+-  ;;
+-linux*)
+-  if test "$host_cpu" = ia64; then
+-    symcode='[[ABCDGIRSTW]]'
+-    lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+-    lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
++  if test -n "${lt_cv_path_LDCXX+set}"; then
++    lt_cv_path_LD=$lt_cv_path_LDCXX
++  else
++    $as_unset lt_cv_path_LD
+   fi
+-  ;;
+-irix* | nonstopux*)
+-  symcode='[[BCDEGRST]]'
+-  ;;
+-osf*)
+-  symcode='[[BCDEGQRST]]'
+-  ;;
+-solaris*)
+-  symcode='[[BDRT]]'
+-  ;;
+-sco3.2v5*)
+-  symcode='[[DT]]'
+-  ;;
+-sysv4.2uw2*)
+-  symcode='[[DT]]'
+-  ;;
+-sysv5* | sco5v6* | unixware* | OpenUNIX*)
+-  symcode='[[ABDT]]'
+-  ;;
+-sysv4)
+-  symcode='[[DFNSTU]]'
+-  ;;
+-esac
+-
+-# Handle CRLF in mingw tool chain
+-opt_cr=
+-case $build_os in
+-mingw*)
+-  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+-  ;;
+-esac
+-
+-# If we're using GNU nm, then use its standard symbol codes.
+-case `$NM -V 2>&1` in
+-*GNU* | *'with BFD'*)
+-  symcode='[[ABCDGIRSTW]]' ;;
+-esac
+-
+-# Try without a prefix undercore, then with it.
+-for ac_symprfx in "" "_"; do
+-
+-  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+-  symxfrm="\\1 $ac_symprfx\\2 \\2"
+-
+-  # Write the raw and C identifiers.
+-  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ 	]]\($symcode$symcode*\)[[ 	]][[ 	]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+-
+-  # Check to see that the pipe works correctly.
+-  pipe_works=no
+-
+-  rm -f conftest*
+-  cat > conftest.$ac_ext <<EOF
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-char nm_test_var;
+-void nm_test_func(){}
+-#ifdef __cplusplus
+-}
+-#endif
+-int main(){nm_test_var='a';nm_test_func();return(0);}
+-EOF
+-
+-  if AC_TRY_EVAL(ac_compile); then
+-    # Now try to grab the symbols.
+-    nlist=conftest.nm
+-    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+-      # Try sorting and uniquifying the output.
+-      if sort "$nlist" | uniq > "$nlist"T; then
+-	mv -f "$nlist"T "$nlist"
+-      else
+-	rm -f "$nlist"T
+-      fi
+-
+-      # Make sure that we snagged all the symbols we need.
+-      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+-	if grep ' nm_test_func$' "$nlist" >/dev/null; then
+-	  cat <<EOF > conftest.$ac_ext
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
+-
+-EOF
+-	  # Now generate the symbol file.
+-	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+-
+-	  cat <<EOF >> conftest.$ac_ext
+-#if defined (__STDC__) && __STDC__
+-# define lt_ptr_t void *
+-#else
+-# define lt_ptr_t char *
+-# define const
+-#endif
+-
+-/* The mapping between symbol names and symbols. */
+-const struct {
+-  const char *name;
+-  lt_ptr_t address;
+-}
+-lt_preloaded_symbols[[]] =
+-{
+-EOF
+-	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+-	  cat <<\EOF >> conftest.$ac_ext
+-  {0, (lt_ptr_t) 0}
+-};
++  test -z "${LDCXX+set}" || LD=$LDCXX
++  CC=${CXX-"c++"}
++  compiler=$CC
++  _LT_TAGVAR(compiler, $1)=$CC
++  _LT_CC_BASENAME([$compiler])
+ 
+-#ifdef __cplusplus
+-}
+-#endif
+-EOF
+-	  # Now try linking the two files.
+-	  mv conftest.$ac_objext conftstm.$ac_objext
+-	  lt_save_LIBS="$LIBS"
+-	  lt_save_CFLAGS="$CFLAGS"
+-	  LIBS="conftstm.$ac_objext"
+-	  CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+-	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+-	    pipe_works=yes
+-	  fi
+-	  LIBS="$lt_save_LIBS"
+-	  CFLAGS="$lt_save_CFLAGS"
+-	else
+-	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+-	fi
+-      else
+-	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+-      fi
++  if test -n "$compiler"; then
++    # We don't want -fno-exception when compiling C++ code, so set the
++    # no_builtin_flag separately
++    if test "$GXX" = yes; then
++      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+     else
+-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
++      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+     fi
+-  else
+-    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+-    cat conftest.$ac_ext >&5
+-  fi
+-  rm -f conftest* conftst*
+-
+-  # Do not use the global_symbol_pipe unless it works.
+-  if test "$pipe_works" = yes; then
+-    break
+-  else
+-    lt_cv_sys_global_symbol_pipe=
+-  fi
+-done
+-])
+-if test -z "$lt_cv_sys_global_symbol_pipe"; then
+-  lt_cv_sys_global_symbol_to_cdecl=
+-fi
+-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+-  AC_MSG_RESULT(failed)
+-else
+-  AC_MSG_RESULT(ok)
+-fi
+-]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+ 
++    if test "$GXX" = yes; then
++      # Set up default GNU C++ configuration
+ 
+-# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+-# ---------------------------------------
+-AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+-[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+-_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
++      LT_PATH_LD
+ 
+-AC_MSG_CHECKING([for $compiler option to produce PIC])
+- ifelse([$1],[CXX],[
+-  # C++ specific cases for pic, static, wl, etc.
+-  if test "$GXX" = yes; then
+-    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
++      # Check if GNU C++ uses GNU ld as the underlying linker, since the
++      # archiving commands below assume that GNU ld is being used.
++      if test "$with_gnu_ld" = yes; then
++        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++
++        # If archive_cmds runs LD, not CC, wlarc should be empty
++        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
++        #     investigate it a little bit more. (MM)
++        wlarc='${wl}'
++
++        # ancient GNU ld didn't support --whole-archive et. al.
++        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
++	  $GREP 'no-whole-archive' > /dev/null; then
++          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++        else
++          _LT_TAGVAR(whole_archive_flag_spec, $1)=
++        fi
++      else
++        with_gnu_ld=no
++        wlarc=
+ 
+-    case $host_os in
+-    aix*)
+-      # All AIX code is PIC.
+-      if test "$host_cpu" = ia64; then
+-	# AIX 5 now supports IA64 processor
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      fi
+-      ;;
+-    amigaos*)
+-      # FIXME: we need at least 68020 code to build shared libraries, but
+-      # adding the `-m68020' flag to GCC prevents building anything better,
+-      # like `-m68040'.
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+-      ;;
+-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+-      # PIC is the default for these OSes.
+-      ;;
+-    mingw* | cygwin* | os2* | pw32*)
+-      # This hack is so that the source file can tell whether it is being
+-      # built for inclusion in a dll (and should export symbols for example).
+-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+-      # (--disable-auto-import) libraries
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+-      ;;
+-    darwin* | rhapsody*)
+-      # PIC is the default on this platform
+-      # Common symbols not allowed in MH_DYLIB files
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+-      ;;
+-    *djgpp*)
+-      # DJGPP does not support shared libraries at all
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-      ;;
+-    interix3*)
+-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+-      # Instead, we relocate shared libraries at runtime.
+-      ;;
+-    sysv4*MP*)
+-      if test -d /usr/nec; then
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++        # A generic and very simple default shared library creation
++        # command for GNU C++ for the case where it uses the native
++        # linker, instead of GNU ld.  If possible, this setting should
++        # overridden to take advantage of the native linker features on
++        # the platform it is being used on.
++        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+       fi
+-      ;;
+-    hpux*)
+-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+-      # not for PA HP-UX.
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-	;;
+-      esac
+-      ;;
+-    *)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-      ;;
+-    esac
+-  else
++
++      # Commands to make compiler produce verbose output that lists
++      # what "hidden" libraries, object files and flags are used when
++      # linking a shared library.
++      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++
++    else
++      GXX=no
++      with_gnu_ld=no
++      wlarc=
++    fi
++
++    # PORTME: fill in a description of your system's C++ link characteristics
++    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
++    _LT_TAGVAR(ld_shlibs, $1)=yes
+     case $host_os in
+-      aix4* | aix5*)
+-	# All AIX code is PIC.
+-	if test "$host_cpu" = ia64; then
+-	  # AIX 5 now supports IA64 processor
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++      aix3*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
++      aix[[4-9]]*)
++        if test "$host_cpu" = ia64; then
++          # On IA64, the linker does run time linking by default, so we don't
++          # have to do anything special.
++          aix_use_runtimelinking=no
++          exp_sym_flag='-Bexport'
++          no_entry_flag=""
++        else
++          aix_use_runtimelinking=no
++
++          # Test if we are trying to use run time linking or normal
++          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
++          # need to do runtime linking.
++          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
++	    for ld_flag in $LDFLAGS; do
++	      case $ld_flag in
++	      *-brtl*)
++	        aix_use_runtimelinking=yes
++	        break
++	        ;;
++	      esac
++	    done
++	    ;;
++          esac
++
++          exp_sym_flag='-bexport'
++          no_entry_flag='-bnoentry'
++        fi
++
++        # When large executables or shared objects are built, AIX ld can
++        # have problems creating the table of contents.  If linking a library
++        # or program results in "error TOC overflow" add -mminimal-toc to
++        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
++        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
++
++        _LT_TAGVAR(archive_cmds, $1)=''
++        _LT_TAGVAR(hardcode_direct, $1)=yes
++        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++        _LT_TAGVAR(link_all_deplibs, $1)=yes
++        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
++
++        if test "$GXX" = yes; then
++          case $host_os in aix4.[[012]]|aix4.[[012]].*)
++          # We only want to do this on AIX 4.2 and lower, the check
++          # below for broken collect2 doesn't work under 4.3+
++	  collect2name=`${CC} -print-prog-name=collect2`
++	  if test -f "$collect2name" &&
++	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++	  then
++	    # We have reworked collect2
++	    :
++	  else
++	    # We have old collect2
++	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
++	    # It fails to find uninstalled libraries when the uninstalled
++	    # path is not listed in the libpath.  Setting hardcode_minus_L
++	    # to unsupported forces relinking
++	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
++	  fi
++          esac
++          shared_flag='-shared'
++	  if test "$aix_use_runtimelinking" = yes; then
++	    shared_flag="$shared_flag "'${wl}-G'
++	  fi
++        else
++          # not using gcc
++          if test "$host_cpu" = ia64; then
++	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++	  # chokes on -Wl,-G. The following line is correct:
++	  shared_flag='-G'
++          else
++	    if test "$aix_use_runtimelinking" = yes; then
++	      shared_flag='${wl}-G'
++	    else
++	      shared_flag='${wl}-bM:SRE'
++	    fi
++          fi
++        fi
++
++        # It seems that -bexpall does not export symbols beginning with
++        # underscore (_), so it is better to generate a list of symbols to
++	# export.
++        _LT_TAGVAR(always_export_symbols, $1)=yes
++        if test "$aix_use_runtimelinking" = yes; then
++          # Warning - without using the other runtime loading flags (-brtl),
++          # -berok will link without error, but may produce a broken library.
++          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
++          # Determine the default libpath from the value encoded in an empty
++          # executable.
++          _LT_SYS_MODULE_PATH_AIX
++          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++
++          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++        else
++          if test "$host_cpu" = ia64; then
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
++	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
++	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++          else
++	    # Determine the default libpath from the value encoded in an
++	    # empty executable.
++	    _LT_SYS_MODULE_PATH_AIX
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++	    # Warning - without using the other run time loading flags,
++	    # -berok will link without error, but may produce a broken library.
++	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
++	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
++	    # Exported symbols can be pulled into shared objects from archives
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
++	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++	    # This is similar to how AIX traditionally builds its shared
++	    # libraries.
++	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++          fi
++        fi
++        ;;
++
++      beos*)
++	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++	  # support --undefined.  This deserves some investigation.  FIXME
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ 	else
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++	  _LT_TAGVAR(ld_shlibs, $1)=no
+ 	fi
+ 	;;
++
+       chorus*)
+-	case $cc_basename in
+-	cxch68*)
+-	  # Green Hills C++ Compiler
+-	  # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
++        case $cc_basename in
++          *)
++	  # FIXME: insert proper C++ library support
++	  _LT_TAGVAR(ld_shlibs, $1)=no
+ 	  ;;
+-	esac
++        esac
++        ;;
++
++      cygwin* | mingw* | pw32*)
++        # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
++        # as there is no search path for DLLs.
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++        _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++        _LT_TAGVAR(always_export_symbols, $1)=no
++        _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++
++        if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++          # If the export-symbols file already is a .def file (1st line
++          # is EXPORTS), use it as is; otherwise, prepend...
++          _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++	    cp $export_symbols $output_objdir/$soname.def;
++          else
++	    echo EXPORTS > $output_objdir/$soname.def;
++	    cat $export_symbols >> $output_objdir/$soname.def;
++          fi~
++          $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++        else
++          _LT_TAGVAR(ld_shlibs, $1)=no
++        fi
++        ;;
++      darwin* | rhapsody*)
++        _LT_DARWIN_LINKER_FEATURES($1)
+ 	;;
+-       darwin*)
+-         # PIC is the default on this platform
+-         # Common symbols not allowed in MH_DYLIB files
+-         case $cc_basename in
+-           xlc*)
+-           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+-           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-           ;;
+-         esac
+-       ;;
++
+       dgux*)
+-	case $cc_basename in
+-	  ec++*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++        case $cc_basename in
++          ec++*)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	  ghcx*)
++          ghcx*)
+ 	    # Green Hills C++ Compiler
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	  *)
++          *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	esac
+-	;;
+-      freebsd* | kfreebsd*-gnu | dragonfly*)
+-	# FreeBSD uses GNU C++
+-	;;
+-      hpux9* | hpux10* | hpux11*)
+-	case $cc_basename in
+-	  CC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+-	    if test "$host_cpu" != ia64; then
+-	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+-	    fi
++        esac
++        ;;
++
++      freebsd[[12]]*)
++        # C++ shared libraries reported to be fairly broken before
++	# switch to ELF
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
++
++      freebsd-elf*)
++        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++        ;;
++
++      freebsd* | dragonfly*)
++        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
++        # conventions
++        _LT_TAGVAR(ld_shlibs, $1)=yes
++        ;;
++
++      gnu*)
++        ;;
++
++      hpux9*)
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++        _LT_TAGVAR(hardcode_direct, $1)=yes
++        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
++				             # but as the default
++				             # location of the library.
++
++        case $cc_basename in
++          CC*)
++            # FIXME: insert proper C++ library support
++            _LT_TAGVAR(ld_shlibs, $1)=no
++            ;;
++          aCC*)
++            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++            # Commands to make compiler produce verbose output that lists
++            # what "hidden" libraries, object files and flags are used when
++            # linking a shared library.
++            #
++            # There doesn't appear to be a way to prevent this compiler from
++            # explicitly linking system object files so we need to strip them
++            # from the output so that they don't get included in the library
++            # dependencies.
++            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
++            ;;
++          *)
++            if test "$GXX" = yes; then
++              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++            else
++              # FIXME: insert proper C++ library support
++              _LT_TAGVAR(ld_shlibs, $1)=no
++            fi
++            ;;
++        esac
++        ;;
++
++      hpux10*|hpux11*)
++        if test $with_gnu_ld = no; then
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++          case $host_cpu in
++            hppa*64*|ia64*)
++              ;;
++            *)
++	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++              ;;
++          esac
++        fi
++        case $host_cpu in
++          hppa*64*|ia64*)
++            _LT_TAGVAR(hardcode_direct, $1)=no
++            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++            ;;
++          *)
++            _LT_TAGVAR(hardcode_direct, $1)=yes
++            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
++					         # but as the default
++					         # location of the library.
++            ;;
++        esac
++
++        case $cc_basename in
++          CC*)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+-	  aCC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++          aCC*)
+ 	    case $host_cpu in
+-	    hppa*64*|ia64*)
+-	      # +Z the default
+-	      ;;
+-	    *)
+-	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+-	      ;;
++	      hppa*64*)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	        ;;
++	      ia64*)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	        ;;
++	      *)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	        ;;
+ 	    esac
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ 	    ;;
+-	  *)
++          *)
++	    if test "$GXX" = yes; then
++	      if test $with_gnu_ld = no; then
++	        case $host_cpu in
++	          hppa*64*)
++	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	            ;;
++	          ia64*)
++	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	            ;;
++	          *)
++	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	            ;;
++	        esac
++	      fi
++	    else
++	      # FIXME: insert proper C++ library support
++	      _LT_TAGVAR(ld_shlibs, $1)=no
++	    fi
+ 	    ;;
+-	esac
+-	;;
+-      interix*)
+-	# This is c89, which is MS Visual C++ (no shared libs)
+-	# Anyone wants to do a port?
+-	;;
+-      irix5* | irix6* | nonstopux*)
+-	case $cc_basename in
+-	  CC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-	    # CC pic flag -KPIC is the default.
++        esac
++        ;;
++
++      interix[[3-9]]*)
++	_LT_TAGVAR(hardcode_direct, $1)=no
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++	# Instead, shared libraries are loaded at an image base (0x10000000 by
++	# default) and relocated if they conflict, which is a slow very memory
++	# consuming and fragmenting process.  To avoid this, we pick a random,
++	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
++	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++	;;
++      irix5* | irix6*)
++        case $cc_basename in
++          CC*)
++	    # SGI C++
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++
++	    # Archives containing C++ object files must be created using
++	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
++	    # necessary to make sure instantiated templates are included
++	    # in the archive.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ 	    ;;
+-	  *)
++          *)
++	    if test "$GXX" = yes; then
++	      if test "$with_gnu_ld" = no; then
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++	      else
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
++	      fi
++	    fi
++	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+ 	    ;;
+-	esac
+-	;;
+-      linux*)
+-	case $cc_basename in
+-	  KCC*)
+-	    # KAI C++ Compiler
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++        esac
++        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++        _LT_TAGVAR(inherit_rpath, $1)=yes
++        ;;
++
++      linux* | k*bsd*-gnu)
++        case $cc_basename in
++          KCC*)
++	    # Kuck and Associates, Inc. (KAI) C++ Compiler
++
++	    # KCC will only create a shared library if the output file
++	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
++	    # to its proper name (with version) after linking.
++	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++
++	    # Archives containing C++ object files must be created using
++	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ 	    ;;
+-	  icpc* | ecpc*)
++	  icpc* | ecpc* )
+ 	    # Intel C++
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+-	    ;;
+-	  pgCC*)
+-	    # Portland Group C++ compiler.
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	    ;;
+-	  cxx*)
+-	    # Compaq C++
+-	    # Make sure the PIC flag is empty.  It appears that all Alpha
+-	    # Linux and Compaq Tru64 Unix objects are PIC.
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++	    with_gnu_ld=yes
++	    # version 8.0 and above of icpc choke on multiply defined symbols
++	    # if we add $predep_objects and $postdep_objects, however 7.1 and
++	    # earlier do not add the objects themselves.
++	    case `$CC -V 2>&1` in
++	      *"Version 7."*)
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++		;;
++	      *)  # Version 8.0 or newer
++	        tmp_idyn=
++	        case $host_cpu in
++		  ia64*) tmp_idyn=' -i_dynamic';;
++		esac
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++		;;
++	    esac
++	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ 	    ;;
+-	  *)
+-	    case `$CC -V 2>&1 | sed 5q` in
+-	    *Sun\ C*)
+-	      # Sun C++ 5.9
+-	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++          pgCC* | pgcpp*)
++            # Portland Group C++ compiler
++	    case `$CC -V` in
++	    *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*)
++	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
++		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
++	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
++		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
++		$RANLIB $oldlib'
++	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
++		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
++		rm -rf $tpldir~
++		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
++		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++	      ;;
++	    *) # Version 6 will use weak symbols
++	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ 	      ;;
+ 	    esac
+-	    ;;
+-	esac
+-	;;
+-      lynxos*)
+-	;;
+-      m88k*)
+-	;;
+-      mvs*)
+-	case $cc_basename in
+-	  cxx*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+-	    ;;
+-	  *)
+-	    ;;
+-	esac
+-	;;
+-      netbsd*)
+-	;;
+-      osf3* | osf4* | osf5*)
+-	case $cc_basename in
+-	  KCC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+-	    ;;
+-	  RCC*)
+-	    # Rational C++ 2.4.1
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-	    ;;
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++            ;;
+ 	  cxx*)
+-	    # Digital/Compaq C++
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    # Make sure the PIC flag is empty.  It appears that all Alpha
+-	    # Linux and Compaq Tru64 Unix objects are PIC.
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-	    ;;
+-	  *)
+-	    ;;
+-	esac
+-	;;
+-      psos*)
+-	;;
+-      solaris*)
+-	case $cc_basename in
+-	  CC*)
+-	    # Sun C++ 4.2, 5.x and Centerline C++
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+-	    ;;
+-	  gcx*)
+-	    # Green Hills C++ Compiler
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+-	    ;;
+-	  *)
+-	    ;;
+-	esac
+-	;;
+-      sunos4*)
+-	case $cc_basename in
+-	  CC*)
+-	    # Sun C++ 4.x
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	    ;;
+-	  lcc*)
+-	    # Lucid
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-	    ;;
+-	  *)
++	    # Compaq C++
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
++
++	    runpath_var=LD_RUN_PATH
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+ 	    ;;
+-	esac
+-	;;
+-      tandem*)
+-	case $cc_basename in
+-	  NCC*)
+-	    # NonStop-UX NCC 3.20
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++	  xl*)
++	    # IBM XL 8.0 on PPC, with GNU ld
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++	    if test "x$supports_anon_versioning" = xyes; then
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++		echo "local: *; };" >> $output_objdir/$libname.ver~
++		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++	    fi
+ 	    ;;
+ 	  *)
++	    case `$CC -V 2>&1 | sed 5q` in
++	    *Sun\ C*)
++	      # Sun C++ 5.9
++	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
++	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
++	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
++	      _LT_TAGVAR(compiler_needs_object, $1)=yes
++
++	      # Not sure whether something based on
++	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
++	      # would be better.
++	      output_verbose_link_cmd='echo'
++
++	      # Archives containing C++ object files must be created using
++	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
++	      # necessary to make sure instantiated templates are included
++	      # in the archive.
++	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
++	      ;;
++	    esac
+ 	    ;;
+ 	esac
+ 	;;
+-      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+-	case $cc_basename in
+-	  CC*)
+-	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++
++      lynxos*)
++        # FIXME: insert proper C++ library support
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	;;
++
++      m88k*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++	;;
++
++      mvs*)
++        case $cc_basename in
++          cxx*)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++	  *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
+ 	    ;;
+ 	esac
+ 	;;
+-      vxworks*)
++
++      netbsd*)
++        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
++	  wlarc=
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	  _LT_TAGVAR(hardcode_direct, $1)=yes
++	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	fi
++	# Workaround some broken pre-1.5 toolchains
++	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ 	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++
++      *nto* | *qnx*)
++        _LT_TAGVAR(ld_shlibs, $1)=yes
+ 	;;
+-    esac
+-  fi
+-],
+-[
+-  if test "$GCC" = yes; then
+-    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ 
+-    case $host_os in
+-      aix*)
+-      # All AIX code is PIC.
+-      if test "$host_cpu" = ia64; then
+-	# AIX 5 now supports IA64 processor
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      fi
+-      ;;
++      openbsd2*)
++        # C++ shared libraries are fairly broken
++	_LT_TAGVAR(ld_shlibs, $1)=no
++	;;
++
++      openbsd*)
++	if test -f /usr/libexec/ld.so; then
++	  _LT_TAGVAR(hardcode_direct, $1)=yes
++	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
++	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
++	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++	  fi
++	  output_verbose_link_cmd=echo
++	else
++	  _LT_TAGVAR(ld_shlibs, $1)=no
++	fi
++	;;
+ 
+-    amigaos*)
+-      # FIXME: we need at least 68020 code to build shared libraries, but
+-      # adding the `-m68020' flag to GCC prevents building anything better,
+-      # like `-m68040'.
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+-      ;;
++      osf3* | osf4* | osf5*)
++        case $cc_basename in
++          KCC*)
++	    # Kuck and Associates, Inc. (KAI) C++ Compiler
++
++	    # KCC will only create a shared library if the output file
++	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
++	    # to its proper name (with version) after linking.
++	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++	    # Archives containing C++ object files must be created using
++	    # the KAI C++ compiler.
++	    case $host in
++	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
++	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
++	    esac
++	    ;;
++          RCC*)
++	    # Rational C++ 2.4.1
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          cxx*)
++	    case $host in
++	      osf3*)
++	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++		;;
++	      *)
++	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
++	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
++	          echo "-hidden">> $lib.exp~
++	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
++	          $RM $lib.exp'
++	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++		;;
++	    esac
+ 
+-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+-      # PIC is the default for these OSes.
+-      ;;
++	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ 
+-    mingw* | cygwin* | pw32* | os2*)
+-      # This hack is so that the source file can tell whether it is being
+-      # built for inclusion in a dll (and should export symbols for example).
+-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+-      # (--disable-auto-import) libraries
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+-      ;;
++	    # Commands to make compiler produce verbose output that lists
++	    # what "hidden" libraries, object files and flags are used when
++	    # linking a shared library.
++	    #
++	    # There doesn't appear to be a way to prevent this compiler from
++	    # explicitly linking system object files so we need to strip them
++	    # from the output so that they don't get included in the library
++	    # dependencies.
++	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
++	    ;;
++	  *)
++	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
++	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++	      case $host in
++	        osf3*)
++	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++		  ;;
++	        *)
++	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++		  ;;
++	      esac
++
++	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++	      # Commands to make compiler produce verbose output that lists
++	      # what "hidden" libraries, object files and flags are used when
++	      # linking a shared library.
++	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++
++	    else
++	      # FIXME: insert proper C++ library support
++	      _LT_TAGVAR(ld_shlibs, $1)=no
++	    fi
++	    ;;
++        esac
++        ;;
+ 
+-    darwin* | rhapsody*)
+-      # PIC is the default on this platform
+-      # Common symbols not allowed in MH_DYLIB files
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+-      ;;
++      psos*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
+ 
+-    interix3*)
+-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+-      # Instead, we relocate shared libraries at runtime.
+-      ;;
++      sunos4*)
++        case $cc_basename in
++          CC*)
++	    # Sun C++ 4.x
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          lcc*)
++	    # Lucid
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++        esac
++        ;;
+ 
+-    msdosdjgpp*)
+-      # Just because we use GCC doesn't mean we suddenly get shared libraries
+-      # on systems that don't support them.
+-      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+-      enable_shared=no
+-      ;;
++      solaris*)
++        case $cc_basename in
++          CC*)
++	    # Sun C++ 4.2, 5.x and Centerline C++
++            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
++	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	    case $host_os in
++	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++	      *)
++		# The compiler driver will combine and reorder linker options,
++		# but understands `-z linker_flag'.
++	        # Supported since Solaris 2.6 (maybe 2.5.1?)
++		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
++	        ;;
++	    esac
++	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+ 
+-    sysv4*MP*)
+-      if test -d /usr/nec; then
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+-      fi
+-      ;;
++	    output_verbose_link_cmd='echo'
+ 
+-    hpux*)
+-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+-      # not for PA HP-UX.
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	# +Z the default
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-	;;
+-      esac
+-      ;;
++	    # Archives containing C++ object files must be created using
++	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
++	    # necessary to make sure instantiated templates are included
++	    # in the archive.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
++	    ;;
++          gcx*)
++	    # Green Hills C++ Compiler
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ 
+-    *)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+-      ;;
+-    esac
+-  else
+-    # PORTME Check for flag to pass linker flags through the system compiler.
+-    case $host_os in
+-    aix*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      if test "$host_cpu" = ia64; then
+-	# AIX 5 now supports IA64 processor
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      else
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+-      fi
+-      ;;
+-      darwin*)
+-        # PIC is the default on this platform
+-        # Common symbols not allowed in MH_DYLIB files
+-       case $cc_basename in
+-         xlc*)
+-         _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+-         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-         ;;
+-       esac
+-       ;;
++	    # The C++ compiler must be used to create the archive.
++	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
++	    ;;
++          *)
++	    # GNU C++ compiler with Solaris linker
++	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
++	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
++	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++		  $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++	        # Commands to make compiler produce verbose output that lists
++	        # what "hidden" libraries, object files and flags are used when
++	        # linking a shared library.
++	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++	      else
++	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
++	        # platform.
++	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++	        # Commands to make compiler produce verbose output that lists
++	        # what "hidden" libraries, object files and flags are used when
++	        # linking a shared library.
++	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
++	      fi
++
++	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
++	      case $host_os in
++		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++		*)
++		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++		  ;;
++	      esac
++	    fi
++	    ;;
++        esac
++        ;;
+ 
+-    mingw* | cygwin* | pw32* | os2*)
+-      # This hack is so that the source file can tell whether it is being
+-      # built for inclusion in a dll (and should export symbols for example).
+-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+-      # (--disable-auto-import) libraries
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+-      ;;
++    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++      runpath_var='LD_RUN_PATH'
+ 
+-    hpux9* | hpux10* | hpux11*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+-      # not for PA HP-UX.
+-      case $host_cpu in
+-      hppa*64*|ia64*)
+-	# +Z the default
+-	;;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+-	;;
++      case $cc_basename in
++        CC*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
++	*)
++	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	  ;;
+       esac
+-      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+       ;;
+ 
+-    irix5* | irix6* | nonstopux*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      # PIC (with -KPIC) is the default.
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-      ;;
++      sysv5* | sco3.2v5* | sco5v6*)
++	# Note: We can NOT use -z defs as we might desire, because we do not
++	# link with -lc, and that would cause any symbols used from libc to
++	# always be unresolved, which means just about no library would
++	# ever link correctly.  If we're not using GNU ld we use -z text
++	# though, which does catch some bad symbols but isn't as heavy-handed
++	# as -z defs.
++	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
++	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++	_LT_TAGVAR(link_all_deplibs, $1)=yes
++	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++	runpath_var='LD_RUN_PATH'
+ 
+-    newsos6)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++	case $cc_basename in
++          CC*)
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    ;;
++	  *)
++	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++	    ;;
++	esac
+       ;;
+ 
+-    linux*)
+-      case $cc_basename in
+-      icc* | ecc*)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+-        ;;
+-      pgcc* | pgf77* | pgf90* | pgf95*)
+-        # Portland Group compilers (*not* the Pentium gcc compiler,
+-	# which looks to be a dead project)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-        ;;
+-      ccc*)
+-        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-        # All Alpha code is PIC.
+-        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++      tandem*)
++        case $cc_basename in
++          NCC*)
++	    # NonStop-UX NCC 3.20
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++          *)
++	    # FIXME: insert proper C++ library support
++	    _LT_TAGVAR(ld_shlibs, $1)=no
++	    ;;
++        esac
+         ;;
+-      como)
+-        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-lopt='
++
++      vxworks*)
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
+         ;;
++
+       *)
+-        case `$CC -V 2>&1 | sed 5q` in
+-	*Sun\ C*)
+-	  # Sun C 5.9
+-	  _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-	  ;;
+-	*Sun\ F*)
+-	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+-	  _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-	  _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=''
+-	  ;;
+-	esac
+-	;;
+-      esac
+-      ;;
++        # FIXME: insert proper C++ library support
++        _LT_TAGVAR(ld_shlibs, $1)=no
++        ;;
++    esac
+ 
+-    osf3* | osf4* | osf5*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      # All OSF/1 code is PIC.
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+-      ;;
++    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
++    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+ 
+-    solaris*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      case $cc_basename in
+-      f77* | f90* | f95*)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+-      *)
+-	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+-      esac
+-      ;;
++    _LT_TAGVAR(GCC, $1)="$GXX"
++    _LT_TAGVAR(LD, $1)="$LD"
++
++    ## CAVEAT EMPTOR:
++    ## There is no encapsulation within the following macros, do not change
++    ## the running order or otherwise move them around unless you know exactly
++    ## what you are doing...
++    _LT_SYS_HIDDEN_LIBDEPS($1)
++    _LT_COMPILER_PIC($1)
++    _LT_COMPILER_C_O($1)
++    _LT_COMPILER_FILE_LOCKS($1)
++    _LT_LINKER_SHLIBS($1)
++    _LT_SYS_DYNAMIC_LINKER($1)
++    _LT_LINKER_HARDCODE_LIBPATH($1)
++
++    _LT_CONFIG($1)
++  fi # test -n "$compiler"
++
++  CC=$lt_save_CC
++  LDCXX=$LD
++  LD=$lt_save_LD
++  GCC=$lt_save_GCC
++  with_gnu_ld=$lt_save_with_gnu_ld
++  lt_cv_path_LDCXX=$lt_cv_path_LD
++  lt_cv_path_LD=$lt_save_path_LD
++  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
++  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
++fi # test "$_lt_caught_CXX_error" != yes
++
++AC_LANG_POP
++])# _LT_LANG_CXX_CONFIG
++
++
++# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
++# ---------------------------------
++# Figure out "hidden" library dependencies from verbose
++# compiler output when linking a shared library.
++# Parse the compiler output and extract the necessary
++# objects, libraries and library flags.
++m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++# Dependencies to place before and after the object being linked:
++_LT_TAGVAR(predep_objects, $1)=
++_LT_TAGVAR(postdep_objects, $1)=
++_LT_TAGVAR(predeps, $1)=
++_LT_TAGVAR(postdeps, $1)=
++_LT_TAGVAR(compiler_lib_search_path, $1)=
++
++dnl we can't use the lt_simple_compile_test_code here,
++dnl because it contains code intended for an executable,
++dnl not a library.  It's possible we should let each
++dnl tag define a new lt_????_link_test_code variable,
++dnl but it's only used here...
++m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
++int a;
++void foo (void) { a = 0; }
++_LT_EOF
++], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
++class Foo
++{
++public:
++  Foo (void) { a = 0; }
++private:
++  int a;
++};
++_LT_EOF
++], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
++      subroutine foo
++      implicit none
++      integer*4 a
++      a=0
++      return
++      end
++_LT_EOF
++], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
++      subroutine foo
++      implicit none
++      integer a
++      a=0
++      return
++      end
++_LT_EOF
++], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
++public class foo {
++  private int a;
++  public void bar (void) {
++    a = 0;
++  }
++};
++_LT_EOF
++])
++dnl Parse the compiler output and extract the necessary
++dnl objects, libraries and library flags.
++if AC_TRY_EVAL(ac_compile); then
++  # Parse the compiler output and extract the necessary
++  # objects, libraries and library flags.
++
++  # Sentinel used to keep track of whether or not we are before
++  # the conftest object file.
++  pre_test_object_deps_done=no
+ 
+-    sunos4*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++  for p in `eval "$output_verbose_link_cmd"`; do
++    case $p in
+ 
+-    sysv4 | sysv4.2uw2* | sysv4.3*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++    -L* | -R* | -l*)
++       # Some compilers place space between "-{L,R}" and the path.
++       # Remove the space.
++       if test $p = "-L" ||
++          test $p = "-R"; then
++	 prev=$p
++	 continue
++       else
++	 prev=
++       fi
+ 
+-    sysv4*MP*)
+-      if test -d /usr/nec ;then
+-	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+-	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      fi
+-      ;;
++       if test "$pre_test_object_deps_done" = no; then
++	 case $p in
++	 -L* | -R*)
++	   # Internal compiler library paths should come after those
++	   # provided the user.  The postdeps already come after the
++	   # user supplied libs so there is no need to process them.
++	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
++	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
++	   else
++	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
++	   fi
++	   ;;
++	 # The "-l" case would never come before the object being
++	 # linked, so don't bother handling this case.
++	 esac
++       else
++	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
++	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
++	 else
++	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
++	 fi
++       fi
++       ;;
+ 
+-    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++    *.$objext)
++       # This assumes that the test object file only shows up
++       # once in the compiler output.
++       if test "$p" = "conftest.$objext"; then
++	 pre_test_object_deps_done=yes
++	 continue
++       fi
+ 
+-    unicos*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+-      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+-      ;;
++       if test "$pre_test_object_deps_done" = no; then
++	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
++	   _LT_TAGVAR(predep_objects, $1)="$p"
++	 else
++	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
++	 fi
++       else
++	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
++	   _LT_TAGVAR(postdep_objects, $1)="$p"
++	 else
++	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
++	 fi
++       fi
++       ;;
+ 
+-    uts4*)
+-      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+-      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+-      ;;
++    *) ;; # Ignore the rest.
+ 
+-    *)
+-      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+-      ;;
+     esac
+-  fi
+-])
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
++  done
+ 
+-#
+-# Check to make sure the PIC flag actually works.
+-#
+-if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+-  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+-    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+-    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+-     "" | " "*) ;;
+-     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+-     esac],
+-    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
++  # Clean up.
++  rm -f a.out a.exe
++else
++  echo "libtool.m4: error: problem compiling $1 test program"
+ fi
+-case $host_os in
+-  # For platforms which do not support PIC, -DPIC is meaningless:
+-  *djgpp*)
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+-    ;;
+-  *)
+-    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+-    ;;
+-esac
+-
+-#
+-# Check to make sure the static flag actually works.
+-#
+-wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
+-AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+-  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+-  $lt_tmp_static_flag,
+-  [],
+-  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+-])
+ 
++$RM -f confest.$objext
+ 
+-# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+-# ------------------------------------
+-# See if the linker supports building shared libraries.
+-AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+-[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+-ifelse([$1],[CXX],[
+-  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+-  case $host_os in
+-  aix4* | aix5*)
+-    # If we're using GNU nm, then we don't want the "-C" option.
+-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+-    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+-      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+-    else
+-      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+-    fi
+-    ;;
+-  pw32*)
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+-  ;;
+-  cygwin* | mingw*)
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+-  ;;
+-  *)
+-    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++# PORTME: override above test on systems where it is broken
++m4_if([$1], [CXX],
++[case $host_os in
++interix[[3-9]]*)
++  # Interix 3.5 installs completely hosed .la files for C++, so rather than
++  # hack all around it, let's just trust "g++" to DTRT.
++  _LT_TAGVAR(predep_objects,$1)=
++  _LT_TAGVAR(postdep_objects,$1)=
++  _LT_TAGVAR(postdeps,$1)=
+   ;;
+-  esac
+-],[
+-  runpath_var=
+-  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+-  _LT_AC_TAGVAR(archive_cmds, $1)=
+-  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+-  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+-  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+-  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+-  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+-  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+-  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+-  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+-  _LT_AC_TAGVAR(module_cmds, $1)=
+-  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+-  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+-  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+-  # include_expsyms should be a list of space-separated symbols to be *always*
+-  # included in the symbol list
+-  _LT_AC_TAGVAR(include_expsyms, $1)=
+-  # exclude_expsyms can be an extended regexp of symbols to exclude
+-  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+-  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+-  # as well as any symbol that contains `d'.
+-  _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+-  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+-  # platforms (ab)use it in PIC code, but their linkers get confused if
+-  # the symbol is explicitly referenced.  Since portable code cannot
+-  # rely on this symbol name, it's probably fine to never include it in
+-  # preloaded symbol tables.
+-  extract_expsyms_cmds=
+-  # Just being paranoid about ensuring that cc_basename is set.
+-  _LT_CC_BASENAME([$compiler])
+-  case $host_os in
+-  cygwin* | mingw* | pw32*)
+-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+-    # When not using gcc, we currently assume that we are using
+-    # Microsoft Visual C++.
+-    if test "$GCC" != yes; then
+-      with_gnu_ld=no
+-    fi
+-    ;;
+-  interix*)
+-    # we just hope/assume this is gcc and not c89 (= MSVC++)
+-    with_gnu_ld=yes
+-    ;;
+-  openbsd*)
+-    with_gnu_ld=no
+-    ;;
+-  esac
+-
+-  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-  if test "$with_gnu_ld" = yes; then
+-    # If archive_cmds runs LD, not CC, wlarc should be empty
+-    wlarc='${wl}'
+-
+-    # Set some defaults for GNU ld with shared library support. These
+-    # are reset later if shared libraries are not supported. Putting them
+-    # here allows them to be overridden if necessary.
+-    runpath_var=LD_RUN_PATH
+-    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+-    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+-    # ancient GNU ld didn't support --whole-archive et. al.
+-    if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+-	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+-      else
+-  	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-    fi
+-    supports_anon_versioning=no
+-    case `$LD -v 2>/dev/null` in
+-      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+-      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+-      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+-      *\ 2.11.*) ;; # other 2.11 versions
+-      *) supports_anon_versioning=yes ;;
+-    esac
+-
+-    # See if GNU ld supports shared libraries.
+-    case $host_os in
+-    aix3* | aix4* | aix5*)
+-      # On AIX/PPC, the GNU linker is very broken
+-      if test "$host_cpu" != ia64; then
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	cat <<EOF 1>&2
+-
+-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+-*** to be unable to reliably create shared libraries on AIX.
+-*** Therefore, libtool is disabling shared libraries support.  If you
+-*** really care for shared libraries, you may want to modify your PATH
+-*** so that a non-GNU linker is found, and then restart.
+-
+-EOF
+-      fi
+-      ;;
+ 
+-    amigaos*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-
+-      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+-      # that the semantics of dynamic libraries on AmigaOS, at least up
+-      # to version 4, is to share data among multiple programs linked
+-      # with the same dynamic library.  Since this doesn't match the
+-      # behavior of shared libraries on other platforms, we can't use
+-      # them.
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
++linux*)
++  case `$CC -V 2>&1 | sed 5q` in
++  *Sun\ C*)
++    # Sun C++ 5.9
+ 
+-    beos*)
+-      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+-	# support --undefined.  This deserves some investigation.  FIXME
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
++    # The more standards-conforming stlport4 library is
++    # incompatible with the Cstd library. Avoid specifying
++    # it if it's in CXXFLAGS. Ignore libCrun as
++    # -library=stlport4 depends on it.
++    case " $CXX $CXXFLAGS " in
++    *" -library=stlport4 "*)
++      solaris_use_stlport4=yes
+       ;;
++    esac
+ 
+-    cygwin* | mingw* | pw32*)
+-      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+-      # as there is no search path for DLLs.
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+-      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+-      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+-
+-      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-	# If the export-symbols file already is a .def file (1st line
+-	# is EXPORTS), use it as is; otherwise, prepend...
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+-	  cp $export_symbols $output_objdir/$soname.def;
+-	else
+-	  echo EXPORTS > $output_objdir/$soname.def;
+-	  cat $export_symbols >> $output_objdir/$soname.def;
+-	fi~
+-	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
++    if test "$solaris_use_stlport4" != yes; then
++      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
++    fi
++    ;;
++  esac
++  ;;
+ 
+-    interix3*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+-      # Instead, shared libraries are loaded at an image base (0x10000000 by
+-      # default) and relocated if they conflict, which is a slow very memory
+-      # consuming and fragmenting process.  To avoid this, we pick a random,
+-      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+-      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++solaris*)
++  case $cc_basename in
++  CC*)
++    # The more standards-conforming stlport4 library is
++    # incompatible with the Cstd library. Avoid specifying
++    # it if it's in CXXFLAGS. Ignore libCrun as
++    # -library=stlport4 depends on it.
++    case " $CXX $CXXFLAGS " in
++    *" -library=stlport4 "*)
++      solaris_use_stlport4=yes
+       ;;
++    esac
+ 
+-    linux*)
+-      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	tmp_addflag=
+-	case $cc_basename,$host_cpu in
+-	pgcc*)				# Portland Group C compiler
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-	  tmp_addflag=' $pic_flag'
+-	  ;;
+-	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+-	  tmp_addflag=' $pic_flag -Mnomain' ;;
+-	ecc*,ia64* | icc*,ia64*)		# Intel C compiler on ia64
+-	  tmp_addflag=' -i_dynamic' ;;
+-	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+-	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+-	ifc* | ifort*)			# Intel Fortran compiler
+-	  tmp_addflag=' -nofor_main' ;;
+-	esac
+-	case `$CC -V 2>&1 | sed 5q` in
+-	*Sun\ C*)			# Sun C 5.9
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive /dev/null'
+-	  tmp_sharedflag='-G' ;;
+-	*Sun\ F*)			# Sun Fortran 8.3
+-	  tmp_sharedflag='-G' ;;
+-	*)
+-	  tmp_sharedflag='-shared' ;;
+-	esac
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++    # Adding this requires a known-good setup of shared libraries for
++    # Sun compiler versions before 5.6, else PIC objects from an old
++    # archive will be linked into the output, leading to subtle bugs.
++    if test "$solaris_use_stlport4" != yes; then
++      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
++    fi
++    ;;
++  esac
++  ;;
++esac
++])
+ 
+-	if test $supports_anon_versioning = yes; then
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+-  cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+-  $echo "local: *; };" >> $output_objdir/$libname.ver~
+-	  $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+-	fi
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
++case " $_LT_TAGVAR(postdeps, $1) " in
++*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
++esac
++ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
++if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
++ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
++fi
++_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
++    [The directories searched by this compiler when creating a shared library])
++_LT_TAGDECL([], [predep_objects], [1],
++    [Dependencies to place before and after the objects being linked to
++    create a shared library])
++_LT_TAGDECL([], [postdep_objects], [1])
++_LT_TAGDECL([], [predeps], [1])
++_LT_TAGDECL([], [postdeps], [1])
++_LT_TAGDECL([], [compiler_lib_search_path], [1],
++    [The library search path used internally by the compiler when linking
++    a shared library])
++])# _LT_SYS_HIDDEN_LIBDEPS
++
++
++# _LT_PROG_F77
++# ------------
++# Since AC_PROG_F77 is broken, in that it returns the empty string
++# if there is no fortran compiler, we have our own version here.
++m4_defun([_LT_PROG_F77],
++[
++pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes])
++AC_PROG_F77
++if test -z "$F77" || test "X$F77" = "Xno"; then
++  _lt_disable_F77=yes
++fi
++popdef([AC_MSG_ERROR])
++])# _LT_PROG_F77
+ 
+-    netbsd*)
+-      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+-	wlarc=
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-      fi
+-      ;;
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([_LT_PROG_F77], [])
+ 
+-    solaris*)
+-      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	cat <<EOF 1>&2
+ 
+-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+-*** create shared libraries on Solaris systems.  Therefore, libtool
+-*** is disabling shared libraries support.  We urge you to upgrade GNU
+-*** binutils to release 2.9.1 or newer.  Another option is to modify
+-*** your PATH or compiler configuration so that the native linker is
+-*** used, and then restart.
++# _LT_LANG_F77_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for a Fortran 77 compiler are
++# suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_F77_CONFIG],
++[AC_REQUIRE([_LT_PROG_F77])dnl
++AC_LANG_PUSH(Fortran 77)
+ 
+-EOF
+-      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ 
+-    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+-      case `$LD -v 2>&1` in
+-        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) 
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	cat <<_LT_EOF 1>&2
++# Source file extension for f77 test sources.
++ac_ext=f
+ 
+-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+-*** reliably create shared libraries on SCO systems.  Therefore, libtool
+-*** is disabling shared libraries support.  We urge you to upgrade GNU
+-*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+-*** your PATH or compiler configuration so that the native linker is
+-*** used, and then restart.
++# Object file extension for compiled f77 test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-_LT_EOF
+-	;;
+-	*)
+-	  if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+-	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+-	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+-	  else
+-	    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-	  fi
+-	;;
+-      esac
+-      ;;
++# No sense in running all these tests if we already determined that
++# the F77 compiler isn't working.  Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_disable_F77" != yes; then
++  # Code to be used in simple compile tests
++  lt_simple_compile_test_code="\
++      subroutine t
++      return
++      end
++"
+ 
+-    sunos4*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+-      wlarc=
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  # Code to be used in simple link tests
++  lt_simple_link_test_code="\
++      program t
++      end
++"
+ 
+-    *)
+-      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+-      else
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      fi
+-      ;;
+-    esac
++  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++  _LT_TAG_COMPILER
+ 
+-    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+-      runpath_var=
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+-    fi
+-  else
+-    # PORTME fill in a description of your system's linker (not GNU ld)
+-    case $host_os in
+-    aix3*)
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+-      # Note: this linker hardcodes the directories in LIBPATH if there
+-      # are no directories specified by -L.
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+-	# Neither direct hardcoding nor static linking is supported with a
+-	# broken collect2.
+-	_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+-      fi
+-      ;;
++  # save warnings/boilerplate of simple test code
++  _LT_COMPILER_BOILERPLATE
++  _LT_LINKER_BOILERPLATE
++
++  # Allow CC to be a program name with arguments.
++  lt_save_CC="$CC"
++  lt_save_GCC=$GCC
++  CC=${F77-"f77"}
++  compiler=$CC
++  _LT_TAGVAR(compiler, $1)=$CC
++  _LT_CC_BASENAME([$compiler])
++  GCC=$G77
++  if test -n "$compiler"; then
++    AC_MSG_CHECKING([if libtool supports shared libraries])
++    AC_MSG_RESULT([$can_build_shared])
+ 
+-    aix4* | aix5*)
+-      if test "$host_cpu" = ia64; then
+-	# On IA64, the linker does run time linking by default, so we don't
+-	# have to do anything special.
+-	aix_use_runtimelinking=no
+-	exp_sym_flag='-Bexport'
+-	no_entry_flag=""
+-      else
+-	# If we're using GNU nm, then we don't want the "-C" option.
+-	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+-	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+-	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+-	else
+-	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
++    AC_MSG_CHECKING([whether to build shared libraries])
++    test "$can_build_shared" = "no" && enable_shared=no
++
++    # On AIX, shared libraries and static libraries use the same namespace, and
++    # are all built from PIC.
++    case $host_os in
++      aix3*)
++        test "$enable_shared" = yes && enable_static=no
++        if test -n "$RANLIB"; then
++          archive_cmds="$archive_cmds~\$RANLIB \$lib"
++          postinstall_cmds='$RANLIB $lib'
++        fi
++        ;;
++      aix[[4-9]]*)
++	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++	  test "$enable_shared" = yes && enable_static=no
+ 	fi
+-	aix_use_runtimelinking=no
++        ;;
++    esac
++    AC_MSG_RESULT([$enable_shared])
+ 
+-	# Test if we are trying to use run time linking or normal
+-	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+-	# need to do runtime linking.
+-	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+-	  for ld_flag in $LDFLAGS; do
+-  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+-  	    aix_use_runtimelinking=yes
+-  	    break
+-  	  fi
+-	  done
+-	  ;;
+-	esac
++    AC_MSG_CHECKING([whether to build static libraries])
++    # Make sure either enable_shared or enable_static is yes.
++    test "$enable_shared" = yes || enable_static=yes
++    AC_MSG_RESULT([$enable_static])
++
++    _LT_TAGVAR(GCC, $1)="$G77"
++    _LT_TAGVAR(LD, $1)="$LD"
++
++    ## CAVEAT EMPTOR:
++    ## There is no encapsulation within the following macros, do not change
++    ## the running order or otherwise move them around unless you know exactly
++    ## what you are doing...
++    _LT_COMPILER_PIC($1)
++    _LT_COMPILER_C_O($1)
++    _LT_COMPILER_FILE_LOCKS($1)
++    _LT_LINKER_SHLIBS($1)
++    _LT_SYS_DYNAMIC_LINKER($1)
++    _LT_LINKER_HARDCODE_LIBPATH($1)
++
++    _LT_CONFIG($1)
++  fi # test -n "$compiler"
++
++  GCC=$lt_save_GCC
++  CC="$lt_save_CC"
++fi # test "$_lt_disable_F77" != yes
+ 
+-	exp_sym_flag='-bexport'
+-	no_entry_flag='-bnoentry'
+-      fi
++AC_LANG_POP
++])# _LT_LANG_F77_CONFIG
+ 
+-      # When large executables or shared objects are built, AIX ld can
+-      # have problems creating the table of contents.  If linking a library
+-      # or program results in "error TOC overflow" add -mminimal-toc to
+-      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+-      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+ 
+-      _LT_AC_TAGVAR(archive_cmds, $1)=''
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
++# _LT_PROG_FC
++# -----------
++# Since AC_PROG_FC is broken, in that it returns the empty string
++# if there is no fortran compiler, we have our own version here.
++m4_defun([_LT_PROG_FC],
++[
++pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes])
++AC_PROG_FC
++if test -z "$FC" || test "X$FC" = "Xno"; then
++  _lt_disable_FC=yes
++fi
++popdef([AC_MSG_ERROR])
++])# _LT_PROG_FC
+ 
+-      if test "$GCC" = yes; then
+-	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+-	# We only want to do this on AIX 4.2 and lower, the check
+-	# below for broken collect2 doesn't work under 4.3+
+-	  collect2name=`${CC} -print-prog-name=collect2`
+-	  if test -f "$collect2name" && \
+-  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+-	  then
+-  	  # We have reworked collect2
+-  	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	  else
+-  	  # We have old collect2
+-  	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+-  	  # It fails to find uninstalled libraries when the uninstalled
+-  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+-  	  # to unsupported forces relinking
+-  	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-  	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-  	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+-	  fi
+-	  ;;
+-	esac
+-	shared_flag='-shared'
+-	if test "$aix_use_runtimelinking" = yes; then
+-	  shared_flag="$shared_flag "'${wl}-G'
+-	fi
+-      else
+-	# not using gcc
+-	if test "$host_cpu" = ia64; then
+-  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+-  	# chokes on -Wl,-G. The following line is correct:
+-	  shared_flag='-G'
+-	else
+-	  if test "$aix_use_runtimelinking" = yes; then
+-	    shared_flag='${wl}-G'
+-	  else
+-	    shared_flag='${wl}-bM:SRE'
+-	  fi
+-	fi
+-      fi
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([_LT_PROG_FC], [])
+ 
+-      # It seems that -bexpall does not export symbols beginning with
+-      # underscore (_), so it is better to generate a list of symbols to export.
+-      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+-      if test "$aix_use_runtimelinking" = yes; then
+-	# Warning - without using the other runtime loading flags (-brtl),
+-	# -berok will link without error, but may produce a broken library.
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+-       # Determine the default libpath from the value encoded in an empty executable.
+-       _LT_AC_SYS_LIBPATH_AIX
+-       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+-       else
+-	if test "$host_cpu" = ia64; then
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+-	else
+-	 # Determine the default libpath from the value encoded in an empty executable.
+-	 _LT_AC_SYS_LIBPATH_AIX
+-	 _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+-	  # Warning - without using the other run time loading flags,
+-	  # -berok will link without error, but may produce a broken library.
+-	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+-	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+-	  # Exported symbols can be pulled into shared objects from archives
+-	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+-	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-	  # This is similar to how AIX traditionally builds its shared libraries.
+-	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+-	fi
+-      fi
+-      ;;
+ 
+-    amigaos*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      # see comment about different semantics on the GNU ld section
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
++# _LT_LANG_FC_CONFIG([TAG])
++# -------------------------
++# Ensure that the configuration variables for a Fortran compiler are
++# suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_FC_CONFIG],
++[AC_REQUIRE([_LT_PROG_FC])dnl
++AC_LANG_PUSH(Fortran)
++
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ 
+-    bsdi[[45]]*)
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+-      ;;
++# Source file extension for fc test sources.
++ac_ext=${ac_fc_srcext-f}
+ 
+-    cygwin* | mingw* | pw32*)
+-      # When not using gcc, we currently assume that we are using
+-      # Microsoft Visual C++.
+-      # hardcode_libdir_flag_spec is actually meaningless, as there is
+-      # no search path for DLLs.
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      # Tell ltmain to make .lib files, not .a files.
+-      libext=lib
+-      # Tell ltmain to make .dll files, not .so files.
+-      shrext_cmds=".dll"
+-      # FIXME: Setting linknames here is a bad hack.
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+-      # The linker will automatically build a .lib file if we build a DLL.
+-      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+-      # FIXME: Should let the user specify the lib program.
+-      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+-      _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+-      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+-      ;;
++# Object file extension for compiled fc test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-    darwin* | rhapsody*)
+-      case $host_os in
+-        rhapsody* | darwin1.[[012]])
+-         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+-         ;;
+-       *) # Darwin 1.3 on
+-         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+-           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-         else
+-           case ${MACOSX_DEPLOYMENT_TARGET} in
+-             10.[[012]])
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+-               ;;
+-             10.*)
+-               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+-               ;;
+-           esac
+-         fi
+-         ;;
+-      esac
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+-      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-    if test "$GCC" = yes ; then
+-    	output_verbose_link_cmd='echo'
+-        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+-      _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-      _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-    else
+-      case $cc_basename in
+-        xlc*)
+-         output_verbose_link_cmd='echo'
+-         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+-         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+-          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+-         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+-          ;;
+-       *)
+-         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-          ;;
+-      esac
+-    fi
+-      ;;
++# No sense in running all these tests if we already determined that
++# the FC compiler isn't working.  Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_disable_FC" != yes; then
++  # Code to be used in simple compile tests
++  lt_simple_compile_test_code="\
++      subroutine t
++      return
++      end
++"
+ 
+-    dgux*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  # Code to be used in simple link tests
++  lt_simple_link_test_code="\
++      program t
++      end
++"
+ 
+-    freebsd1*)
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
++  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++  _LT_TAG_COMPILER
+ 
+-    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+-    # support.  Future versions do this automatically, but an explicit c++rt0.o
+-    # does not break anything, and helps significantly (at the cost of a little
+-    # extra space).
+-    freebsd2.2*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  # save warnings/boilerplate of simple test code
++  _LT_COMPILER_BOILERPLATE
++  _LT_LINKER_BOILERPLATE
++
++  # Allow CC to be a program name with arguments.
++  lt_save_CC="$CC"
++  lt_save_GCC=$GCC
++  CC=${FC-"f95"}
++  compiler=$CC
++  GCC=$ac_cv_fc_compiler_gnu
+ 
+-    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+-    freebsd2*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  _LT_TAGVAR(compiler, $1)=$CC
++  _LT_CC_BASENAME([$compiler])
+ 
+-    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+-    freebsd* | kfreebsd*-gnu | dragonfly*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++  if test -n "$compiler"; then
++    AC_MSG_CHECKING([if libtool supports shared libraries])
++    AC_MSG_RESULT([$can_build_shared])
+ 
+-    hpux9*)
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
++    AC_MSG_CHECKING([whether to build shared libraries])
++    test "$can_build_shared" = "no" && enable_shared=no
+ 
+-      # hardcode_minus_L: Not really in the search PATH,
+-      # but as the default location of the library.
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      ;;
++    # On AIX, shared libraries and static libraries use the same namespace, and
++    # are all built from PIC.
++    case $host_os in
++      aix3*)
++        test "$enable_shared" = yes && enable_static=no
++        if test -n "$RANLIB"; then
++          archive_cmds="$archive_cmds~\$RANLIB \$lib"
++          postinstall_cmds='$RANLIB $lib'
++        fi
++        ;;
++      aix[[4-9]]*)
++	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++	  test "$enable_shared" = yes && enable_static=no
++	fi
++        ;;
++    esac
++    AC_MSG_RESULT([$enable_shared])
+ 
+-    hpux10*)
+-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+-      fi
+-      if test "$with_gnu_ld" = no; then
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++    AC_MSG_CHECKING([whether to build static libraries])
++    # Make sure either enable_shared or enable_static is yes.
++    test "$enable_shared" = yes || enable_static=yes
++    AC_MSG_RESULT([$enable_static])
++
++    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
++    _LT_TAGVAR(LD, $1)="$LD"
++
++    ## CAVEAT EMPTOR:
++    ## There is no encapsulation within the following macros, do not change
++    ## the running order or otherwise move them around unless you know exactly
++    ## what you are doing...
++    _LT_SYS_HIDDEN_LIBDEPS($1)
++    _LT_COMPILER_PIC($1)
++    _LT_COMPILER_C_O($1)
++    _LT_COMPILER_FILE_LOCKS($1)
++    _LT_LINKER_SHLIBS($1)
++    _LT_SYS_DYNAMIC_LINKER($1)
++    _LT_LINKER_HARDCODE_LIBPATH($1)
++
++    _LT_CONFIG($1)
++  fi # test -n "$compiler"
++
++  GCC=$lt_save_GCC
++  CC="$lt_save_CC"
++fi # test "$_lt_disable_FC" != yes
+ 
+-	_LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++AC_LANG_POP
++])# _LT_LANG_FC_CONFIG
+ 
+-	# hardcode_minus_L: Not really in the search PATH,
+-	# but as the default location of the library.
+-	_LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      fi
+-      ;;
+ 
+-    hpux11*)
+-      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+-	case $host_cpu in
+-	hppa*64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	ia64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	esac
+-      else
+-	case $host_cpu in
+-	hppa*64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	ia64*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+-	  ;;
+-	esac
+-      fi
+-      if test "$with_gnu_ld" = no; then
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+-	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
++# _LT_LANG_GCJ_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for the GNU Java Compiler compiler
++# are suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_GCJ_CONFIG],
++[AC_REQUIRE([LT_PROG_GCJ])dnl
++AC_LANG_SAVE
+ 
+-	case $host_cpu in
+-	hppa*64*|ia64*)
+-	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-	  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-	  ;;
+-	*)
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-	  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++# Source file extension for Java test sources.
++ac_ext=java
+ 
+-	  # hardcode_minus_L: Not really in the search PATH,
+-	  # but as the default location of the library.
+-	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-	  ;;
+-	esac
+-      fi
+-      ;;
++# Object file extension for compiled Java test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-    irix5* | irix6* | nonstopux*)
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      ;;
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="class foo {}"
+ 
+-    netbsd*)
+-      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# Code to be used in simple link tests
++lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+ 
+-    newsos6)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
++
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
++
++# Allow CC to be a program name with arguments.
++lt_save_CC="$CC"
++lt_save_GCC=$GCC
++GCC=yes
++CC=${GCJ-"gcj"}
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_TAGVAR(LD, $1)="$LD"
++_LT_CC_BASENAME([$compiler])
+ 
+-    openbsd*)
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+-      else
+-       case $host_os in
+-	 openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+-	   _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+-	   _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-	   ;;
+-	 *)
+-	   _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+-	   _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+-	   ;;
+-       esac
+-      fi
+-      ;;
++# GCJ did not exist at the time GCC didn't implicitly link libc in.
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ 
+-    os2*)
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+-      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+-      ;;
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+ 
+-    osf3*)
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-      else
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      ;;
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++  _LT_COMPILER_NO_RTTI($1)
++  _LT_COMPILER_PIC($1)
++  _LT_COMPILER_C_O($1)
++  _LT_COMPILER_FILE_LOCKS($1)
++  _LT_LINKER_SHLIBS($1)
++  _LT_LINKER_HARDCODE_LIBPATH($1)
+ 
+-    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+-      else
+-	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+-	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
++  _LT_CONFIG($1)
++fi
+ 
+-	# Both c and cxx compiler support -rpath directly
+-	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+-      ;;
++AC_LANG_RESTORE
+ 
+-    solaris*)
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+-      if test "$GCC" = yes; then
+-	wlarc='${wl}'
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+-      else
+-	wlarc=''
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+-  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      case $host_os in
+-      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+-      *)
+- 	# The compiler driver will combine linker options so we
+- 	# cannot just pass the convience library names through
+- 	# without $wl, iff we do not link with $LD.
+- 	# Luckily, gcc supports the same syntax we need for Sun Studio.
+- 	# Supported since Solaris 2.6 (maybe 2.5.1?)
+- 	case $wlarc in
+- 	'')
+- 	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+- 	*)
+- 	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+- 	esac ;;
+-      esac
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      ;;
++GCC=$lt_save_GCC
++CC="$lt_save_CC"
++])# _LT_LANG_GCJ_CONFIG
+ 
+-    sunos4*)
+-      if test "x$host_vendor" = xsequent; then
+-	# Use $CC to link under sequent, because it throws in some extra .o
+-	# files that make .init and .fini sections work.
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+-      fi
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
+ 
+-    sysv4)
+-      case $host_vendor in
+-	sni)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+-	;;
+-	siemens)
+-	  ## LD is ld it makes a PLAMLIB
+-	  ## CC just makes a GrossModule.
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+-	  _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+-        ;;
+-	motorola)
+-	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	  _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+-	;;
+-      esac
+-      runpath_var='LD_RUN_PATH'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# _LT_LANG_RC_CONFIG([TAG])
++# -------------------------
++# Ensure that the configuration variables for the Windows resource compiler
++# are suitably defined.  These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_RC_CONFIG],
++[AC_REQUIRE([LT_PROG_RC])dnl
++AC_LANG_SAVE
+ 
+-    sysv4.3*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+-      ;;
++# Source file extension for RC test sources.
++ac_ext=rc
+ 
+-    sysv4*MP*)
+-      if test -d /usr/nec; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-	runpath_var=LD_RUN_PATH
+-	hardcode_runpath_var=yes
+-	_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+-      fi
+-      ;;
++# Object file extension for compiled RC test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
+ 
+-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*)
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      runpath_var='LD_RUN_PATH'
++# Code to be used in simple compile tests
++lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+ 
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      fi
+-      ;;
++# Code to be used in simple link tests
++lt_simple_link_test_code="$lt_simple_compile_test_code"
+ 
+-    sysv5* | sco3.2v5* | sco5v6*)
+-      # Note: We can NOT use -z defs as we might desire, because we do not
+-      # link with -lc, and that would cause any symbols used from libc to
+-      # always be unresolved, which means just about no library would
+-      # ever link correctly.  If we're not using GNU ld we use -z text
+-      # though, which does catch some bad symbols but isn't as heavy-handed
+-      # as -z defs.
+-      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+-      _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+-      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+-      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+-      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+-      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+-      runpath_var='LD_RUN_PATH'
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
+ 
+-      if test "$GCC" = yes; then
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      else
+-	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+-      fi
+-      ;;
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
+ 
+-    uts4*)
+-      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+-      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+-      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+-      ;;
++# Allow CC to be a program name with arguments.
++lt_save_CC="$CC"
++lt_save_GCC=$GCC
++GCC=
++CC=${RC-"windres"}
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_CC_BASENAME([$compiler])
++_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ 
+-    *)
+-      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+-      ;;
+-    esac
+-  fi
+-])
+-AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+-test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
++if test -n "$compiler"; then
++  :
++  _LT_CONFIG($1)
++fi
+ 
+-#
+-# Do we need to explicitly link libc?
+-#
+-case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+-x|xyes)
+-  # Assume -lc should be added
+-  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
++GCC=$lt_save_GCC
++AC_LANG_RESTORE
++CC="$lt_save_CC"
++])# _LT_LANG_RC_CONFIG
+ 
+-  if test "$enable_shared" = yes && test "$GCC" = yes; then
+-    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+-    *'~'*)
+-      # FIXME: we may have to deal with multi-command sequences.
+-      ;;
+-    '$CC '*)
+-      # Test whether the compiler implicitly links with -lc since on some
+-      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+-      # to ld, don't add -lc before -lgcc.
+-      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+-      $rm conftest*
+-      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+ 
+-      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+-        soname=conftest
+-        lib=conftest
+-        libobjs=conftest.$ac_objext
+-        deplibs=
+-        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+-	pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+-        compiler_flags=-v
+-        linker_flags=-v
+-        verstring=
+-        output_objdir=.
+-        libname=conftest
+-        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+-        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+-        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+-        then
+-	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+-        else
+-	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+-        fi
+-        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+-      else
+-        cat conftest.err 1>&5
+-      fi
+-      $rm conftest*
+-      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+-      ;;
+-    esac
+-  fi
+-  ;;
+-esac
+-])# AC_LIBTOOL_PROG_LD_SHLIBS
++# LT_PROG_GCJ
++# -----------
++AC_DEFUN([LT_PROG_GCJ],
++[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
++  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
++    [AC_CHECK_TOOL(GCJ, gcj,)
++      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
++      AC_SUBST(GCJFLAGS)])])[]dnl
++])
+ 
++# Old name:
++AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+ 
+-# _LT_AC_FILE_LTDLL_C
+-# -------------------
+-# Be careful that the start marker always follows a newline.
+-AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+-# /* ltdll.c starts here */
+-# #define WIN32_LEAN_AND_MEAN
+-# #include <windows.h>
+-# #undef WIN32_LEAN_AND_MEAN
+-# #include <stdio.h>
+-#
+-# #ifndef __CYGWIN__
+-# #  ifdef __CYGWIN32__
+-# #    define __CYGWIN__ __CYGWIN32__
+-# #  endif
+-# #endif
+-#
+-# #ifdef __cplusplus
+-# extern "C" {
+-# #endif
+-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+-# #ifdef __cplusplus
+-# }
+-# #endif
+-#
+-# #ifdef __CYGWIN__
+-# #include <cygwin/cygwin_dll.h>
+-# DECLARE_CYGWIN_DLL( DllMain );
+-# #endif
+-# HINSTANCE __hDllInstance_base;
+-#
+-# BOOL APIENTRY
+-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+-# {
+-#   __hDllInstance_base = hInst;
+-#   return TRUE;
+-# }
+-# /* ltdll.c ends here */
+-])# _LT_AC_FILE_LTDLL_C
+ 
++# LT_PROG_RC
++# ----------
++AC_DEFUN([LT_PROG_RC],
++[AC_CHECK_TOOL(RC, windres,)
++])
+ 
+-# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+-# ---------------------------------
+-AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
++# Old name:
++AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_RC], [])
+ 
+ 
+-# old names
+-AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
+-AC_DEFUN([AM_ENABLE_SHARED],  [AC_ENABLE_SHARED($@)])
+-AC_DEFUN([AM_ENABLE_STATIC],  [AC_ENABLE_STATIC($@)])
+-AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+-AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+-AC_DEFUN([AM_PROG_LD],        [AC_PROG_LD])
+-AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
+-
+-# This is just to silence aclocal about the macro not being used
+-ifelse([AC_DISABLE_FAST_INSTALL])
+-
+-AC_DEFUN([LT_AC_PROG_GCJ],
+-[AC_CHECK_TOOL(GCJ, gcj, no)
+-  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+-  AC_SUBST(GCJFLAGS)
++# _LT_DECL_EGREP
++# --------------
++# If we don't have a new enough Autoconf to choose the best grep
++# available, choose the one first in the user's PATH.
++m4_defun([_LT_DECL_EGREP],
++[AC_REQUIRE([AC_PROG_EGREP])dnl
++AC_REQUIRE([AC_PROG_FGREP])dnl
++test -z "$GREP" && GREP=grep
++_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
++_LT_DECL([], [EGREP], [1], [An ERE matcher])
++_LT_DECL([], [FGREP], [1], [A literal string matcher])
++dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
++AC_SUBST([GREP])
+ ])
+ 
+-AC_DEFUN([LT_AC_PROG_RC],
+-[AC_CHECK_TOOL(RC, windres, no)
+-])
+ 
++# _LT_DECL_SED
++# ------------
++# Check for a fully-functional sed program, that truncates
++# as few characters as possible.  Prefer GNU sed if found.
++m4_defun([_LT_DECL_SED],
++[AC_PROG_SED
++test -z "$SED" && SED=sed
++Xsed="$SED -e 1s/^X//"
++_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
++_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
++    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
++])# _LT_DECL_SED
++
++m4_ifndef([AC_PROG_SED], [
+ ############################################################
+ # NOTE: This macro has been submitted for inclusion into   #
+ #  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+ #  a released version of Autoconf we should remove this    #
+ #  macro and use it instead.                               #
+ ############################################################
+-# LT_AC_PROG_SED
+-# --------------
+-# Check for a fully-functional sed program, that truncates
+-# as few characters as possible.  Prefer GNU sed if found.
+-AC_DEFUN([LT_AC_PROG_SED],
++
++m4_defun([AC_PROG_SED],
+ [AC_MSG_CHECKING([for a sed that does not truncate output])
+ AC_CACHE_VAL(lt_cv_path_SED,
+ [# Loop through the user's path and test for sed and gsed.
+@@ -6435,6 +7010,7 @@ do
+     done
+   done
+ done
++IFS=$as_save_IFS
+ lt_ac_max=0
+ lt_ac_count=0
+ # Add /usr/xpg4/bin/sed as it is typically found on Solaris
+@@ -6467,5 +7043,268 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xp
+ done
+ ])
+ SED=$lt_cv_path_SED
++AC_SUBST([SED])
+ AC_MSG_RESULT([$SED])
++])#AC_PROG_SED
++])#m4_ifndef
++
++# Old name:
++AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_SED], [])
++
++
++# _LT_CHECK_SHELL_FEATURES
++# ------------------------
++# Find out whether the shell is Bourne or XSI compatible,
++# or has some other useful features.
++m4_defun([_LT_CHECK_SHELL_FEATURES],
++[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
++# Try some XSI features
++xsi_shell=no
++( _lt_dummy="a/b/c"
++  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
++      = c,a/b,, \
++    && eval 'test $(( 1 + 1 )) -eq 2 \
++    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
++  && xsi_shell=yes
++AC_MSG_RESULT([$xsi_shell])
++_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
++
++AC_MSG_CHECKING([whether the shell understands "+="])
++lt_shell_append=no
++( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
++    >/dev/null 2>&1 \
++  && lt_shell_append=yes
++AC_MSG_RESULT([$lt_shell_append])
++_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
++
++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
++  lt_unset=unset
++else
++  lt_unset=false
++fi
++_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
++
++# test EBCDIC or ASCII
++case `echo X|tr X '\101'` in
++ A) # ASCII based system
++    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
++  lt_SP2NL='tr \040 \012'
++  lt_NL2SP='tr \015\012 \040\040'
++  ;;
++ *) # EBCDIC based system
++  lt_SP2NL='tr \100 \n'
++  lt_NL2SP='tr \r\n \100\100'
++  ;;
++esac
++_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
++_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
++])# _LT_CHECK_SHELL_FEATURES
++
++
++# _LT_PROG_XSI_SHELLFNS
++# ---------------------
++# Bourne and XSI compatible variants of some useful shell functions.
++m4_defun([_LT_PROG_XSI_SHELLFNS],
++[case $xsi_shell in
++  yes)
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_dirname file append nondir_replacement
++# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
++# otherwise set result to NONDIR_REPLACEMENT.
++func_dirname ()
++{
++  case ${1} in
++    */*) func_dirname_result="${1%/*}${2}" ;;
++    *  ) func_dirname_result="${3}" ;;
++  esac
++}
++
++# func_basename file
++func_basename ()
++{
++  func_basename_result="${1##*/}"
++}
++
++# func_dirname_and_basename file append nondir_replacement
++# perform func_basename and func_dirname in a single function
++# call:
++#   dirname:  Compute the dirname of FILE.  If nonempty,
++#             add APPEND to the result, otherwise set result
++#             to NONDIR_REPLACEMENT.
++#             value returned in "$func_dirname_result"
++#   basename: Compute filename of FILE.
++#             value retuned in "$func_basename_result"
++# Implementation must be kept synchronized with func_dirname
++# and func_basename. For efficiency, we do not delegate to
++# those functions but instead duplicate the functionality here.
++func_dirname_and_basename ()
++{
++  case ${1} in
++    */*) func_dirname_result="${1%/*}${2}" ;;
++    *  ) func_dirname_result="${3}" ;;
++  esac
++  func_basename_result="${1##*/}"
++}
++
++# func_stripname prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++func_stripname ()
++{
++  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
++  # positional parameters, so assign one to ordinary parameter first.
++  func_stripname_result=${3}
++  func_stripname_result=${func_stripname_result#"${1}"}
++  func_stripname_result=${func_stripname_result%"${2}"}
++}
++
++# func_opt_split
++func_opt_split ()
++{
++  func_opt_split_opt=${1%%=*}
++  func_opt_split_arg=${1#*=}
++}
++
++# func_lo2o object
++func_lo2o ()
++{
++  case ${1} in
++    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
++    *)    func_lo2o_result=${1} ;;
++  esac
++}
++
++# func_xform libobj-or-source
++func_xform ()
++{
++  func_xform_result=${1%.*}.lo
++}
++
++# func_arith arithmetic-term...
++func_arith ()
++{
++  func_arith_result=$(( $[*] ))
++}
++
++# func_len string
++# STRING may not start with a hyphen.
++func_len ()
++{
++  func_len_result=${#1}
++}
++
++_LT_EOF
++    ;;
++  *) # Bourne compatible functions.
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_dirname file append nondir_replacement
++# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
++# otherwise set result to NONDIR_REPLACEMENT.
++func_dirname ()
++{
++  # Extract subdirectory from the argument.
++  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
++  if test "X$func_dirname_result" = "X${1}"; then
++    func_dirname_result="${3}"
++  else
++    func_dirname_result="$func_dirname_result${2}"
++  fi
++}
++
++# func_basename file
++func_basename ()
++{
++  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
++}
++
++dnl func_dirname_and_basename
++dnl A portable version of this function is already defined in general.m4sh
++dnl so there is no need for it here.
++
++# func_stripname prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++# func_strip_suffix prefix name
++func_stripname ()
++{
++  case ${2} in
++    .*) func_stripname_result=`$ECHO "X${3}" \
++           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
++    *)  func_stripname_result=`$ECHO "X${3}" \
++           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
++  esac
++}
++
++# sed scripts:
++my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
++my_sed_long_arg='1s/^-[[^=]]*=//'
++
++# func_opt_split
++func_opt_split ()
++{
++  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
++  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
++}
++
++# func_lo2o object
++func_lo2o ()
++{
++  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
++}
++
++# func_xform libobj-or-source
++func_xform ()
++{
++  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'`
++}
++
++# func_arith arithmetic-term...
++func_arith ()
++{
++  func_arith_result=`expr "$[@]"`
++}
++
++# func_len string
++# STRING may not start with a hyphen.
++func_len ()
++{
++  func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
++}
++
++_LT_EOF
++esac
++
++case $lt_shell_append in
++  yes)
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_append var value
++# Append VALUE to the end of shell variable VAR.
++func_append ()
++{
++  eval "$[1]+=\$[2]"
++}
++_LT_EOF
++    ;;
++  *)
++    cat << \_LT_EOF >> "$cfgfile"
++
++# func_append var value
++# Append VALUE to the end of shell variable VAR.
++func_append ()
++{
++  eval "$[1]=\$$[1]\$[2]"
++}
++
++_LT_EOF
++    ;;
++  esac
+ ])
diff --git a/package/libs/libiconv-full/patches/103-configure_ac_fix.patch b/package/libs/libiconv-full/patches/103-configure_ac_fix.patch
new file mode 100644
index 0000000000..d57ae84cbf
--- /dev/null
+++ b/package/libs/libiconv-full/patches/103-configure_ac_fix.patch
@@ -0,0 +1,31 @@
+--- /dev/null
++++ b/Makefile.am
+@@ -0,0 +1,2 @@
++ACLOCAL_AMFLAGS = -I m4
++SUBDIRS = .
+--- /dev/null
++++ b/libcharset/Makefile.am
+@@ -0,0 +1 @@
++ACLOCAL_AMFLAGS = -I m4
+--- a/configure.ac
++++ b/configure.ac
+@@ -54,7 +54,7 @@ AC_ISC_POSIX
+ 
+ dnl           checks for installer options
+ 
+-AC_RELOCATABLE
++gl_RELOCATABLE
+ 
+ AC_ARG_ENABLE([extra-encodings],
+   [AC_HELP_STRING([--enable-extra-encodings],
+--- a/libcharset/configure.ac
++++ b/libcharset/configure.ac
+@@ -41,7 +41,7 @@ AC_CANONICAL_HOST
+ 
+ dnl           checks for installer options
+ 
+-AC_RELOCATABLE_LIBRARY
++gl_RELOCATABLE_LIBRARY
+ 
+ dnl           checks for programs
+ 
diff --git a/package/libs/libiconv-full/patches/200-work-with-libtool2.patch b/package/libs/libiconv-full/patches/200-work-with-libtool2.patch
new file mode 100644
index 0000000000..6e31967f3c
--- /dev/null
+++ b/package/libs/libiconv-full/patches/200-work-with-libtool2.patch
@@ -0,0 +1,17 @@
+Make iconv 1.11.x link correctly with libtool2 - argument "-Xcompiler" ensures "-shared" is passed to $(CC) when used as linker. Otherwise $(CC) tries to create an executable and fails while looking for a main()-function
+
+diff -ruN libiconv-1.11.1/lib/Makefile.in libiconv-1.11.1.mod/lib/Makefile.in
+--- libiconv-1.11.1/lib/Makefile.in	2006-07-14 15:18:42.000000000 +0200
++++ libiconv-1.11.1.mod/lib/Makefile.in	2010-12-01 20:47:57.000000000 +0100
+@@ -70,9 +70,9 @@
+ 
+ preloadable_libiconv_linux.so : $(SOURCES)
+ 	if test -n "@GCC@"; then \
+-	  $(LIBTOOL_LINK) $(CC) $(LDFLAGS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) $(DEFS) -fPIC -DPIC -DLIBICONV_PLUG $(SOURCES) -shared -o preloadable_libiconv_linux.so; \
++	  $(LIBTOOL_LINK) $(CC) $(LDFLAGS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) $(DEFS) -fPIC -DPIC -DLIBICONV_PLUG $(SOURCES) -Xcompiler -shared -o preloadable_libiconv_linux.so; \
+ 	else \
+-	  $(LIBTOOL_LINK) $(CC) $(LDFLAGS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) $(DEFS) -KPIC -DPIC -DLIBICONV_PLUG $(SOURCES) -shared -o preloadable_libiconv_linux.so; \
++	  $(LIBTOOL_LINK) $(CC) $(LDFLAGS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) $(DEFS) -KPIC -DPIC -DLIBICONV_PLUG $(SOURCES) -Xcompiler -shared -o preloadable_libiconv_linux.so; \
+ 	fi
+ 
+ preloadable_libiconv_solaris.so : $(SOURCES)
diff --git a/package/libs/libiconv-full/patches/300-fortify-source-compat.patch b/package/libs/libiconv-full/patches/300-fortify-source-compat.patch
new file mode 100644
index 0000000000..e7e92235e5
--- /dev/null
+++ b/package/libs/libiconv-full/patches/300-fortify-source-compat.patch
@@ -0,0 +1,23 @@
+--- a/m4/canonicalize.m4
++++ b/m4/canonicalize.m4
+@@ -11,8 +11,6 @@ AC_DEFUN([gl_CANONICALIZE],
+   AC_CHECK_FUNCS(canonicalize_file_name)
+   if test $ac_cv_func_canonicalize_file_name = no; then
+     AC_LIBOBJ(canonicalize)
+-    AC_DEFINE([realpath], [rpl_realpath],
+-      [Define to a replacement function name for realpath().])
+     gl_PREREQ_CANONICALIZE
+   fi
+ ])
+--- a/configure
++++ b/configure
+@@ -35532,9 +35532,6 @@ done
+   if test $ac_cv_func_canonicalize_file_name = no; then
+     SRCLIBOBJS="$SRCLIBOBJS canonicalize.$ac_objext"
+ 
+-cat >>confdefs.h <<\_ACEOF
+-#define realpath rpl_realpath
+-_ACEOF
+ 
+ 
+ 
diff --git a/package/libs/libiconv/COPYING b/package/libs/libiconv/COPYING
new file mode 100644
index 0000000000..223ede7de3
--- /dev/null
+++ b/package/libs/libiconv/COPYING
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/package/libs/libiconv/COPYRIGHT b/package/libs/libiconv/COPYRIGHT
new file mode 100644
index 0000000000..d228af3550
--- /dev/null
+++ b/package/libs/libiconv/COPYRIGHT
@@ -0,0 +1,20 @@
+Copyright status on all included code:
+
+All files which have no copyright comments are original works
+Copyright (C) 2005-2006 Rich Felker. The decision to exclude such
+comments is intentional, as it should be possible to carry around the
+complete source code on tiny storage media. All public header files
+(include/*) should be treated as Public Domain as they intentionally
+contain no content which can be covered by copyright. Some source
+modules may fall in this category as well. If you believe that a file
+is so trivial that it should be in the Public Domain, please contact
+me and, if I agree, I will explicitly release it from copyright.
+
+Some code has been modified by the OpenWrt project, this includes
+the conversion from char map files to C arrays and the iconv.h header
+file in particular.
+
+The library as a whole is licensed under the GNU LGPL version 2.1.
+See the file COPYING for the text of this license.
+
+The original source can be accessed at svn://svn.mplayerhq.hu/libc/trunk
diff --git a/package/libs/libiconv/Makefile b/package/libs/libiconv/Makefile
new file mode 100644
index 0000000000..0cb7cc7254
--- /dev/null
+++ b/package/libs/libiconv/Makefile
@@ -0,0 +1,79 @@
+#
+# Copyright (C) 2010-2012 OpenWrt.org
+#
+# This Makefile and the code shipped in src/ is free software, licensed
+# under the GNU Lesser General Public License, version 2.1 and later.
+# See src/COPYING for more information.
+#
+# Refer to src/COPYRIGHT for copyright statements on the source files.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libiconv
+PKG_RELEASE:=8
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/libiconv
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Tiny drop-in replacement for the GNU Character set conversion library
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -c $(PKG_BUILD_DIR)/iconv.c -o $(PKG_BUILD_DIR)/iconv.o -I$(PKG_BUILD_DIR)/include $(FPIC)
+	$(TARGET_CROSS)ar rcs $(PKG_BUILD_DIR)/libiconv.a $(PKG_BUILD_DIR)/iconv.o
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/libiconv-stub/lib
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/libiconv.a $(1)/usr/lib/libiconv-stub/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/libiconv-stub/include
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/include/iconv.h $(1)/usr/lib/libiconv-stub/include/
+
+	$(INSTALL_DIR) $(1)/usr/share/aclocal
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/m4/* $(1)/usr/share/aclocal/
+endef
+
+define Package/libiconv/install
+	$(INSTALL_DIR) $(1)/tmp
+	touch $(1)/tmp/.libiconv-placeholder
+endef
+
+define Host/Prepare
+	mkdir -p $(HOST_BUILD_DIR)
+endef
+
+define Host/Configure
+
+endef
+
+define Host/Compile
+	$(HOSTCC) -c src/iconv.c -o $(HOST_BUILD_DIR)/iconv.o -Isrc/include -fPIC
+	ar rcs $(HOST_BUILD_DIR)/libiconv.a $(HOST_BUILD_DIR)/iconv.o
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR)/host/lib
+	$(INSTALL_DATA) $(HOST_BUILD_DIR)/libiconv.a $(STAGING_DIR)/host/lib/
+
+	$(INSTALL_DIR) $(STAGING_DIR)/host/include
+	$(INSTALL_DATA) ./src/include/iconv.h $(STAGING_DIR)/host/include/
+
+	$(INSTALL_DIR) $(STAGING_DIR)/host/share/aclocal
+	$(INSTALL_DATA) ./src/m4/* $(STAGING_DIR)/host/share/aclocal/
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,libiconv))
diff --git a/package/libs/libiconv/src/LICENSE b/package/libs/libiconv/src/LICENSE
new file mode 100644
index 0000000000..b59e7be47c
--- /dev/null
+++ b/package/libs/libiconv/src/LICENSE
@@ -0,0 +1,6 @@
+The source file iconv.m4 contains the following message
+
+Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc.
+This file is free software; the Free Software Foundation
+gives unlimited permission to copy and/or distribute it,
+with or without modifications, as long as this notice is preserved.
diff --git a/package/libs/libiconv/src/iconv.c b/package/libs/libiconv/src/iconv.c
new file mode 100644
index 0000000000..c3cfefa3cc
--- /dev/null
+++ b/package/libs/libiconv/src/iconv.c
@@ -0,0 +1,449 @@
+#include <iconv.h>
+#include <errno.h>
+#include <wchar.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdint.h>
+
+/* builtin charmaps */
+#include "charmaps.h"
+
+/* only 0-7 are valid as dest charset */
+#define UTF_16BE    000
+#define UTF_16LE    001
+#define UTF_32BE    002
+#define UTF_32LE    003
+#define WCHAR_T     004
+#define UTF_8       005
+#define US_ASCII    006
+#define LATIN_1     007
+
+/* additional charsets with algorithmic conversion */
+#define LATIN_9     010
+#define TIS_620     011
+#define JIS_0201    012
+
+/* some programs like php need this */
+int _libiconv_version = _LIBICONV_VERSION;
+
+/* these must match the constants above */
+static const unsigned char charsets[] =
+	"\005" "UTF-8"      "\0"
+	"\004" "WCHAR_T"    "\0"
+	"\000" "UTF-16BE"   "\0"
+	"\001" "UTF-16LE"   "\0"
+	"\002" "UTF-32BE"   "\0"
+	"\003" "UTF-32LE"   "\0"
+	"\006" "ASCII"      "\0"
+	"\006" "US-ASCII"   "\0"
+	"\006" "ISO646-US"  "\0"
+	"\006" "ISO_646.IRV:1991"  "\0"
+	"\006" "ISO-IR-6"   "\0"
+	"\006" "ANSI_X3.4-1968"    "\0"
+	"\006" "ANSI_X3.4-1986"    "\0"
+	"\006" "CP367"      "\0"
+	"\006" "IBM367"     "\0"
+	"\006" "US"         "\0"
+	"\006" "CSASCII"    "\0"
+	"\007" "ISO-8859-1" "\0"
+	"\007" "LATIN1"     "\0"
+	"\010" "ISO-8859-15""\0"
+	"\010" "LATIN9"     "\0"
+	"\011" "ISO-8859-11""\0"
+	"\011" "TIS-620"    "\0"
+	"\012" "JIS-0201"   "\0"
+	"\377";
+
+/* separate identifiers for sbcs/dbcs/etc map type */
+#define UCS2_8BIT   000
+#define UCS3_8BIT   001
+#define EUC         002
+#define EUC_TW      003
+#define SHIFT_JIS   004
+#define BIG5        005
+#define GBK         006
+
+/* FIXME: these are not implemented yet
+// EUC:   A1-FE A1-FE
+// GBK:   81-FE 40-7E,80-FE
+// Big5:  A1-FE 40-7E,A1-FE
+*/
+
+static const unsigned short maplen[] = {
+	[UCS2_8BIT] = 4+ 2* 128,
+	[UCS3_8BIT] = 4+ 3* 128,
+	[EUC]       = 4+ 2* 94*94,
+	[SHIFT_JIS] = 4+ 2* 94*94,
+	[BIG5]      = 4+ 2* 94*157,
+	[GBK]       = 4+ 2* 126*190,
+	[EUC_TW]    = 4+ 2* 2*94*94,
+};
+
+static int find_charmap(const char *name)
+{
+	int i;
+	for (i = 0; i < (sizeof(charmaps) / sizeof(charmaps[0])); i++)
+		if (!strcasecmp(charmaps[i].name, name))
+			return i;
+	return -1;
+}
+
+static int find_charset(const char *name)
+{
+	const unsigned char *s;
+	for (s=charsets; *s<0xff && strcasecmp(s+1, name); s+=strlen(s)+1);
+	return *s;
+}
+
+iconv_t iconv_open(const char *to, const char *from)
+{
+	unsigned f, t;
+	int m;
+
+	if ((t = find_charset(to)) > 8)
+		return -1;
+
+	if ((f = find_charset(from)) < 255)
+		return 0 | (t<<1) | (f<<8);
+
+	if ((m = find_charmap(from)) > -1)
+		return 1 | (t<<1) | (m<<8);
+
+	return -1;
+}
+
+int iconv_close(iconv_t cd)
+{
+	return 0;
+}
+
+static inline wchar_t get_16(const unsigned char *s, int endian)
+{
+	endian &= 1;
+	return s[endian]<<8 | s[endian^1];
+}
+
+static inline void put_16(unsigned char *s, wchar_t c, int endian)
+{
+	endian &= 1;
+	s[endian] = c>>8;
+	s[endian^1] = c;
+}
+
+static inline int utf8enc_wchar(char *outb, wchar_t c)
+{
+	if (c <= 0x7F) {
+		*outb = c;
+		return 1;
+	}
+	else if (c <= 0x7FF) {
+		*outb++ = ((c >>  6) & 0x1F) | 0xC0;
+		*outb++ = ( c        & 0x3F) | 0x80;
+		return 2;
+	}
+	else if (c <= 0xFFFF) {
+		*outb++ = ((c >> 12) & 0x0F) | 0xE0;
+		*outb++ = ((c >>  6) & 0x3F) | 0x80;
+		*outb++ = ( c        & 0x3F) | 0x80;
+		return 3;
+	}
+	else if (c <= 0x10FFFF) {
+		*outb++ = ((c >> 18) & 0x07) | 0xF0;
+		*outb++ = ((c >> 12) & 0x3F) | 0x80;
+		*outb++ = ((c >>  6) & 0x3F) | 0x80;
+		*outb++ = ( c        & 0x3F) | 0x80;
+		return 4;
+	}
+	else {
+		*outb++ = '?';
+		return 1;
+	}
+}
+
+static inline int utf8seq_is_overlong(char *s, int n)
+{
+	switch (n)
+	{
+	case 2:
+		/* 1100000x (10xxxxxx) */
+		return (((*s >> 1) == 0x60) &&
+				((*(s+1) >> 6) == 0x02));
+
+	case 3:
+		/* 11100000 100xxxxx (10xxxxxx) */
+		return ((*s == 0xE0) &&
+				((*(s+1) >> 5) == 0x04) &&
+				((*(s+2) >> 6) == 0x02));
+
+	case 4:
+		/* 11110000 1000xxxx (10xxxxxx 10xxxxxx) */
+		return ((*s == 0xF0) &&
+				((*(s+1) >> 4) == 0x08) &&
+				((*(s+2) >> 6) == 0x02) &&
+				((*(s+3) >> 6) == 0x02));
+	}
+
+	return 0;
+}
+
+static inline int utf8seq_is_surrogate(char *s, int n)
+{
+	return ((n == 3) && (*s == 0xED) && (*(s+1) >= 0xA0) && (*(s+1) <= 0xBF));
+}
+
+static inline int utf8seq_is_illegal(char *s, int n)
+{
+	return ((n == 3) && (*s == 0xEF) && (*(s+1) == 0xBF) &&
+	        (*(s+2) >= 0xBE) && (*(s+2) <= 0xBF));
+}
+
+static inline int utf8dec_wchar(wchar_t *c, unsigned char *in, size_t inb)
+{
+	int i;
+	int n = -1;
+
+	/* trivial char */
+	if (*in <= 0x7F) {
+		*c = *in;
+		return 1;
+	}
+
+	/* find utf8 sequence length */
+	if      ((*in & 0xE0) == 0xC0) n = 2;
+	else if ((*in & 0xF0) == 0xE0) n = 3;
+	else if ((*in & 0xF8) == 0xF0) n = 4;
+	else if ((*in & 0xFC) == 0xF8) n = 5;
+	else if ((*in & 0xFE) == 0xFC) n = 6;
+
+	/* starved? */
+	if (n > inb)
+		return -2;
+
+	/* decode ... */
+	if (n > 1 && n < 5) {
+		/* reject invalid sequences */
+		if (utf8seq_is_overlong(in, n) ||
+			utf8seq_is_surrogate(in, n) ||
+			utf8seq_is_illegal(in, n))
+			return -1;
+
+		/* decode ... */
+		*c = (char)(*in++ & (0x7F >> n));
+
+		for (i = 1; i < n; i++) {
+			/* illegal continuation byte */
+			if (*in < 0x80 || *in > 0xBF)
+				return -1;
+
+			*c = (*c << 6) | (*in++ & 0x3F);
+		}
+
+		return n;
+	}
+
+	/* unmapped sequence (> 4) */
+	return -1;
+}
+
+static inline wchar_t latin9_translit(wchar_t c)
+{
+	/* a number of trivial iso-8859-15 <> utf-8 transliterations */
+	switch (c) {
+	case 0x20AC: return 0xA4; /* Euro */
+	case 0x0160: return 0xA6; /* S caron */
+	case 0x0161: return 0xA8; /* s caron */
+	case 0x017D: return 0xB4; /* Z caron */
+	case 0x017E: return 0xB8; /* z caron */
+	case 0x0152: return 0xBC; /* OE */
+	case 0x0153: return 0xBD; /* oe */
+	case 0x0178: return 0xBE; /* Y diaeresis */
+	default:     return 0xFFFD; /* cannot translate */
+	}
+}
+
+size_t iconv(iconv_t cd, char **in, size_t *inb, char **out, size_t *outb)
+{
+	size_t x=0;
+	unsigned char to = (cd>>1)&127;
+	unsigned char from = 255;
+	const unsigned char *map = 0;
+	char tmp[MB_LEN_MAX];
+	wchar_t c, d;
+	size_t k, l;
+	int err;
+
+	if (!in || !*in || !*inb) return 0;
+
+	if (cd & 1)
+		map = charmaps[cd>>8].map;
+	else
+		from = cd>>8;
+
+	for (; *inb; *in+=l, *inb-=l) {
+		c = *(unsigned char *)*in;
+		l = 1;
+		if (from >= UTF_8 && c < 0x80) goto charok;
+		switch (from) {
+		case WCHAR_T:
+			l = sizeof(wchar_t);
+			if (*inb < l) goto starved;
+			c = *(wchar_t *)*in;
+			break;
+		case UTF_8:
+			l = utf8dec_wchar(&c, *in, *inb);
+			if (!l) l++;
+			else if (l == (size_t)-1) goto ilseq;
+			else if (l == (size_t)-2) goto starved;
+			break;
+		case US_ASCII:
+			goto ilseq;
+		case LATIN_9:
+			if ((unsigned)c - 0xa4 <= 0xbe - 0xa4) {
+				static const unsigned char map[] = {
+					0, 0x60, 0, 0x61, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0x7d, 0, 0, 0, 0x7e, 0, 0, 0,
+					0x52, 0x53, 0x78
+				};
+				if (c == 0xa4) c = 0x20ac;
+				else if (map[c-0xa5]) c = 0x100 | map[c-0xa5];
+			}
+		case LATIN_1:
+			goto charok;
+		case TIS_620:
+			if (c >= 0xa1) c += 0x0e01-0xa1;
+			goto charok;
+		case JIS_0201:
+			if (c >= 0xa1) {
+				if (c <= 0xdf) c += 0xff61-0xa1;
+				else goto ilseq;
+			}
+			goto charok;
+		case UTF_16BE:
+		case UTF_16LE:
+			l = 2;
+			if (*inb < 2) goto starved;
+			c = get_16(*in, from);
+			if ((unsigned)(c-0xdc00) < 0x400) goto ilseq;
+			if ((unsigned)(c-0xd800) < 0x400) {
+				l = 4;
+				if (*inb < 4) goto starved;
+				d = get_16(*in + 2, from);
+				if ((unsigned)(c-0xdc00) >= 0x400) goto ilseq;
+				c = ((c-0xd800)<<10) | (d-0xdc00);
+			}
+			break;
+		case UTF_32BE:
+		case UTF_32LE:
+			l = 4;
+			if (*inb < 4) goto starved;
+			// FIXME
+			// c = get_32(*in, from);
+			break;
+		default:
+			/* only support ascii supersets */
+			if (c < 0x80) break;
+			switch (map[0]) {
+			case UCS2_8BIT:
+				c -= 0x80;
+				break;
+			case EUC:
+				if ((unsigned)c - 0xa1 >= 94) goto ilseq;
+				if ((unsigned)in[0][1] - 0xa1 >= 94) goto ilseq;
+				c = (c-0xa1)*94 + (in[0][1]-0xa1);
+				l = 2;
+				break;
+			case SHIFT_JIS:
+				if ((unsigned)c - 0xa1 <= 0xdf-0xa1) {
+					c += 0xff61-0xa1;
+					goto charok;
+				}
+				// FIXME...
+				l = 2;
+				break;
+			default:
+				goto badf;
+			}
+			c = get_16(map + 4 + 2*c, 0);
+			if (c == 0xffff) goto ilseq;
+			goto charok;
+		}
+
+		if ((unsigned)c - 0xd800 < 0x800 || (unsigned)c >= 0x110000)
+			goto ilseq;
+charok:
+		switch (to) {
+		case WCHAR_T:
+			if (*outb < sizeof(wchar_t)) goto toobig;
+			*(wchar_t *)*out = c;
+			*out += sizeof(wchar_t);
+			*outb -= sizeof(wchar_t);
+			break;
+		case UTF_8:
+			if (*outb < 4) {
+				k = utf8enc_wchar(tmp, c);
+				if (*outb < k) goto toobig;
+				memcpy(*out, tmp, k);
+			} else k = utf8enc_wchar(*out, c);
+			*out += k;
+			*outb -= k;
+			break;
+		case US_ASCII:
+			if (c > 0x7f) c = 0xfffd;
+			/* fall thru and count replacement in latin1 case */
+		case LATIN_9:
+			if (c >= 0x100 && c != 0xfffd)
+				c = latin9_translit(c);
+			/* fall through */
+		case LATIN_1:
+			if (c > 0xff) goto ilseq;
+			if (!*outb) goto toobig;
+			**out = c;
+			++*out;
+			--*outb;
+			break;
+		case UTF_16BE:
+		case UTF_16LE:
+			if (c < 0x10000) {
+				if (*outb < 2) goto toobig;
+				put_16(*out, c, to);
+				*out += 2;
+				*outb -= 2;
+				break;
+			}
+			if (*outb < 4) goto toobig;
+			put_16(*out, (c>>10)|0xd800, to);
+			put_16(*out + 2, (c&0x3ff)|0xdc00, to);
+			*out += 4;
+			*outb -= 4;
+			break;
+		default:
+			goto badf;
+		}
+	}
+	return x;
+ilseq:
+	err = EILSEQ;
+	x = -1;
+	goto end;
+badf:
+	err = EBADF;
+	x = -1;
+	goto end;
+toobig:
+	err = E2BIG;
+	x = -1;
+	goto end;
+starved:
+	err = EINVAL;
+end:
+	errno = err;
+	return x;
+}
diff --git a/package/libs/libiconv/src/include/charmaps.h b/package/libs/libiconv/src/include/charmaps.h
new file mode 100644
index 0000000000..083cd699f1
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps.h
@@ -0,0 +1,80 @@
+#include "charmaps/iso-8859-2.h"
+#include "charmaps/iso-8859-10.h"
+#include "charmaps/windows-874.h"
+#include "charmaps/windows-1250.h"
+#include "charmaps/koi8-r.h"
+
+#ifdef ALL_CHARSETS
+#include "charmaps/iso-8859-3.h"
+#include "charmaps/iso-8859-4.h"
+#include "charmaps/iso-8859-5.h"
+#include "charmaps/iso-8859-6.h"
+#include "charmaps/iso-8859-7.h"
+#include "charmaps/iso-8859-8.h"
+#include "charmaps/iso-8859-9.h"
+#include "charmaps/iso-8859-13.h"
+#include "charmaps/iso-8859-14.h"
+#include "charmaps/iso-8859-16.h"
+#include "charmaps/windows-1251.h"
+#include "charmaps/windows-1252.h"
+#include "charmaps/windows-1253.h"
+#include "charmaps/windows-1254.h"
+#include "charmaps/windows-1255.h"
+#include "charmaps/windows-1256.h"
+#include "charmaps/windows-1257.h"
+#include "charmaps/windows-1258.h"
+#endif
+
+
+struct charmap {
+	const char name[13];
+	const unsigned char *map;
+};
+
+static struct charmap charmaps[] = {
+	{ "ISO-8859-2",   map_iso_8859_2   },
+	{ "ISO-8859-10",  map_iso_8859_10  },
+
+#ifdef ALL_CHARSETS
+	{ "ISO-8859-3",   map_iso_8859_3   },
+	{ "ISO-8859-4",   map_iso_8859_4   },
+	{ "ISO-8859-5",   map_iso_8859_5   },
+	{ "ISO-8859-6",   map_iso_8859_6   },
+	{ "ISO-8859-7",   map_iso_8859_7   },
+	{ "ISO-8859-8",   map_iso_8859_8   },
+	{ "ISO-8859-9",   map_iso_8859_9   },
+	{ "ISO-8859-13",  map_iso_8859_13  },
+	{ "ISO-8859-14",  map_iso_8859_14  },
+	{ "ISO-8859-16",  map_iso_8859_16  },
+#endif
+
+	{ "WINDOWS-874",  map_windows_874  },
+	{ "WINDOWS-1250", map_windows_1250 },
+
+#ifdef ALL_CHARSETS
+	{ "WINDOWS-1251", map_windows_1251 },
+	{ "WINDOWS-1252", map_windows_1252 },
+	{ "WINDOWS-1253", map_windows_1253 },
+	{ "WINDOWS-1254", map_windows_1254 },
+	{ "WINDOWS-1255", map_windows_1255 },
+	{ "WINDOWS-1256", map_windows_1256 },
+	{ "WINDOWS-1257", map_windows_1257 },
+	{ "WINDOWS-1258", map_windows_1258 },
+#endif
+
+	{ "KOI8-R",       map_koi8_r       },
+
+	/* Aliases */
+	{ "LATIN2",       map_iso_8859_2   },
+	{ "LATIN6",       map_iso_8859_10  },
+
+#ifdef ALL_CHARSETS
+	{ "ARABIC",       map_iso_8859_6   },
+	{ "CYRILLIC",     map_iso_8859_5   },
+	{ "GREEK",        map_iso_8859_7   },
+	{ "HEBREW",       map_iso_8859_8   },
+	{ "LATIN3",       map_iso_8859_3   },
+	{ "LATIN4",       map_iso_8859_4   },
+	{ "LATIN5",       map_iso_8859_9   },
+#endif
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-10.h b/package/libs/libiconv/src/include/charmaps/iso-8859-10.h
new file mode 100644
index 0000000000..cb93d027d1
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-10.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_10[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x01, 0x04,
+	0x01, 0x12, 0x01, 0x22, 0x01, 0x2a, 0x01, 0x28, 0x01, 0x36, 0x00, 0xa7,
+	0x01, 0x3b, 0x01, 0x10, 0x01, 0x60, 0x01, 0x66, 0x01, 0x7d, 0x00, 0xad,
+	0x01, 0x6a, 0x01, 0x4a, 0x00, 0xb0, 0x01, 0x05, 0x01, 0x13, 0x01, 0x23,
+	0x01, 0x2b, 0x01, 0x29, 0x01, 0x37, 0x00, 0xb7, 0x01, 0x3c, 0x01, 0x11,
+	0x01, 0x61, 0x01, 0x67, 0x01, 0x7e, 0x20, 0x15, 0x01, 0x6b, 0x01, 0x4b,
+	0x01, 0x00, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x01, 0x2e, 0x01, 0x0c, 0x00, 0xc9, 0x01, 0x18, 0x00, 0xcb,
+	0x01, 0x16, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x01, 0x45,
+	0x01, 0x4c, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x01, 0x68,
+	0x00, 0xd8, 0x01, 0x72, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd,
+	0x00, 0xde, 0x00, 0xdf, 0x01, 0x01, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x01, 0x2f, 0x01, 0x0d, 0x00, 0xe9,
+	0x01, 0x19, 0x00, 0xeb, 0x01, 0x17, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x00, 0xf0, 0x01, 0x46, 0x01, 0x4d, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5,
+	0x00, 0xf6, 0x01, 0x69, 0x00, 0xf8, 0x01, 0x73, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x01, 0x38
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-13.h b/package/libs/libiconv/src/include/charmaps/iso-8859-13.h
new file mode 100644
index 0000000000..b44d1b4346
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-13.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_13[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x20, 0x1d,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x20, 0x1e, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xd8, 0x00, 0xa9, 0x01, 0x56, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xc6, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x20, 0x1c, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xf8, 0x00, 0xb9,
+	0x01, 0x57, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xe6,
+	0x01, 0x04, 0x01, 0x2e, 0x01, 0x00, 0x01, 0x06, 0x00, 0xc4, 0x00, 0xc5,
+	0x01, 0x18, 0x01, 0x12, 0x01, 0x0c, 0x00, 0xc9, 0x01, 0x79, 0x01, 0x16,
+	0x01, 0x22, 0x01, 0x36, 0x01, 0x2a, 0x01, 0x3b, 0x01, 0x60, 0x01, 0x43,
+	0x01, 0x45, 0x00, 0xd3, 0x01, 0x4c, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7,
+	0x01, 0x72, 0x01, 0x41, 0x01, 0x5a, 0x01, 0x6a, 0x00, 0xdc, 0x01, 0x7b,
+	0x01, 0x7d, 0x00, 0xdf, 0x01, 0x05, 0x01, 0x2f, 0x01, 0x01, 0x01, 0x07,
+	0x00, 0xe4, 0x00, 0xe5, 0x01, 0x19, 0x01, 0x13, 0x01, 0x0d, 0x00, 0xe9,
+	0x01, 0x7a, 0x01, 0x17, 0x01, 0x23, 0x01, 0x37, 0x01, 0x2b, 0x01, 0x3c,
+	0x01, 0x61, 0x01, 0x44, 0x01, 0x46, 0x00, 0xf3, 0x01, 0x4d, 0x00, 0xf5,
+	0x00, 0xf6, 0x00, 0xf7, 0x01, 0x73, 0x01, 0x42, 0x01, 0x5b, 0x01, 0x6b,
+	0x00, 0xfc, 0x01, 0x7c, 0x01, 0x7e, 0x20, 0x19
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-14.h b/package/libs/libiconv/src/include/charmaps/iso-8859-14.h
new file mode 100644
index 0000000000..76cead98c7
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-14.h
@@ -0,0 +1,25 @@
+static const unsigned char map_iso_8859_14[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x1e, 0x02,
+	0x1e, 0x03, 0x00, 0xa3, 0x01, 0x0a, 0x01, 0x0b, 0x1e, 0x0a, 0x00, 0xa7,
+	0x1e, 0x80, 0x00, 0xa9, 0x1e, 0x82, 0x1e, 0x0b, 0x1e, 0xf2, 0x00, 0xad,
+	0x00, 0xae, 0x01, 0x78, 0x1e, 0x1e, 0x1e, 0x1f, 0x01, 0x20, 0x01, 0x21,
+	0x1e, 0x40, 0x1e, 0x41, 0x00, 0xb6, 0x1e, 0x56, 0x1e, 0x81, 0x1e, 0x57,
+	0x1e, 0x83, 0x1e, 0x60, 0x1e, 0xf3, 0x1e, 0x84, 0x1e, 0x85, 0x1e, 0x61,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x01, 0x74, 0x00, 0xd1,
+	0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x1e, 0x6a,
+	0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd,
+	0x01, 0x76, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x01, 0x75, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5,
+	0x00, 0xf6, 0x1e, 0x6b, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x00, 0xfd, 0x01, 0x77, 0x00, 0xff
+};
+
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-16.h b/package/libs/libiconv/src/include/charmaps/iso-8859-16.h
new file mode 100644
index 0000000000..4437a41f05
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-16.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_16[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x01, 0x04,
+	0x01, 0x05, 0x01, 0x41, 0x20, 0xac, 0x20, 0x1e, 0x01, 0x60, 0x00, 0xa7,
+	0x01, 0x61, 0x00, 0xa9, 0x02, 0x18, 0x00, 0xab, 0x01, 0x79, 0x00, 0xad,
+	0x01, 0x7a, 0x01, 0x7b, 0x00, 0xb0, 0x00, 0xb1, 0x01, 0x0c, 0x01, 0x42,
+	0x01, 0x7d, 0x20, 0x1d, 0x00, 0xb6, 0x00, 0xb7, 0x01, 0x7e, 0x01, 0x0d,
+	0x02, 0x19, 0x00, 0xbb, 0x01, 0x52, 0x01, 0x53, 0x01, 0x78, 0x01, 0x7c,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x01, 0x02, 0x00, 0xc4, 0x01, 0x06,
+	0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x01, 0x10, 0x01, 0x43,
+	0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x01, 0x50, 0x00, 0xd6, 0x01, 0x5a,
+	0x01, 0x70, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x01, 0x18,
+	0x02, 0x1a, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x01, 0x03,
+	0x00, 0xe4, 0x01, 0x07, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x01, 0x11, 0x01, 0x44, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x01, 0x51,
+	0x00, 0xf6, 0x01, 0x5b, 0x01, 0x71, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x01, 0x19, 0x02, 0x1b, 0x00, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-2.h b/package/libs/libiconv/src/include/charmaps/iso-8859-2.h
new file mode 100644
index 0000000000..631610e17c
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-2.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_2[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x01, 0x04,
+	0x02, 0xd8, 0x01, 0x41, 0x00, 0xa4, 0x01, 0x3d, 0x01, 0x5a, 0x00, 0xa7,
+	0x00, 0xa8, 0x01, 0x60, 0x01, 0x5e, 0x01, 0x64, 0x01, 0x79, 0x00, 0xad,
+	0x01, 0x7d, 0x01, 0x7b, 0x00, 0xb0, 0x01, 0x05, 0x02, 0xdb, 0x01, 0x42,
+	0x00, 0xb4, 0x01, 0x3e, 0x01, 0x5b, 0x02, 0xc7, 0x00, 0xb8, 0x01, 0x61,
+	0x01, 0x5f, 0x01, 0x65, 0x01, 0x7a, 0x02, 0xdd, 0x01, 0x7e, 0x01, 0x7c,
+	0x01, 0x54, 0x00, 0xc1, 0x00, 0xc2, 0x01, 0x02, 0x00, 0xc4, 0x01, 0x39,
+	0x01, 0x06, 0x00, 0xc7, 0x01, 0x0c, 0x00, 0xc9, 0x01, 0x18, 0x00, 0xcb,
+	0x01, 0x1a, 0x00, 0xcd, 0x00, 0xce, 0x01, 0x0e, 0x01, 0x10, 0x01, 0x43,
+	0x01, 0x47, 0x00, 0xd3, 0x00, 0xd4, 0x01, 0x50, 0x00, 0xd6, 0x00, 0xd7,
+	0x01, 0x58, 0x01, 0x6e, 0x00, 0xda, 0x01, 0x70, 0x00, 0xdc, 0x00, 0xdd,
+	0x01, 0x62, 0x00, 0xdf, 0x01, 0x55, 0x00, 0xe1, 0x00, 0xe2, 0x01, 0x03,
+	0x00, 0xe4, 0x01, 0x3a, 0x01, 0x07, 0x00, 0xe7, 0x01, 0x0d, 0x00, 0xe9,
+	0x01, 0x19, 0x00, 0xeb, 0x01, 0x1b, 0x00, 0xed, 0x00, 0xee, 0x01, 0x0f,
+	0x01, 0x11, 0x01, 0x44, 0x01, 0x48, 0x00, 0xf3, 0x00, 0xf4, 0x01, 0x51,
+	0x00, 0xf6, 0x00, 0xf7, 0x01, 0x59, 0x01, 0x6f, 0x00, 0xfa, 0x01, 0x71,
+	0x00, 0xfc, 0x00, 0xfd, 0x01, 0x63, 0x02, 0xd9
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-3.h b/package/libs/libiconv/src/include/charmaps/iso-8859-3.h
new file mode 100644
index 0000000000..cd76d59c65
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-3.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_3[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x01, 0x26,
+	0x02, 0xd8, 0x00, 0xa3, 0x00, 0xa4, 0xff, 0xff, 0x01, 0x24, 0x00, 0xa7,
+	0x00, 0xa8, 0x01, 0x30, 0x01, 0x5e, 0x01, 0x1e, 0x01, 0x34, 0x00, 0xad,
+	0xff, 0xff, 0x01, 0x7b, 0x00, 0xb0, 0x01, 0x27, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x01, 0x25, 0x00, 0xb7, 0x00, 0xb8, 0x01, 0x31,
+	0x01, 0x5f, 0x01, 0x1f, 0x01, 0x35, 0x00, 0xbd, 0xff, 0xff, 0x01, 0x7c,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0xff, 0xff, 0x00, 0xc4, 0x01, 0x0a,
+	0x01, 0x08, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0xff, 0xff, 0x00, 0xd1,
+	0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x01, 0x20, 0x00, 0xd6, 0x00, 0xd7,
+	0x01, 0x1c, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x01, 0x6c,
+	0x01, 0x5c, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0xff, 0xff,
+	0x00, 0xe4, 0x01, 0x0b, 0x01, 0x09, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0xff, 0xff, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x01, 0x21,
+	0x00, 0xf6, 0x00, 0xf7, 0x01, 0x1d, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x01, 0x6d, 0x01, 0x5d, 0x02, 0xd9
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-4.h b/package/libs/libiconv/src/include/charmaps/iso-8859-4.h
new file mode 100644
index 0000000000..5db2f77807
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-4.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_4[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x01, 0x04,
+	0x01, 0x38, 0x01, 0x56, 0x00, 0xa4, 0x01, 0x28, 0x01, 0x3b, 0x00, 0xa7,
+	0x00, 0xa8, 0x01, 0x60, 0x01, 0x12, 0x01, 0x22, 0x01, 0x66, 0x00, 0xad,
+	0x01, 0x7d, 0x00, 0xaf, 0x00, 0xb0, 0x01, 0x05, 0x02, 0xdb, 0x01, 0x57,
+	0x00, 0xb4, 0x01, 0x29, 0x01, 0x3c, 0x02, 0xc7, 0x00, 0xb8, 0x01, 0x61,
+	0x01, 0x13, 0x01, 0x23, 0x01, 0x67, 0x01, 0x4a, 0x01, 0x7e, 0x01, 0x4b,
+	0x01, 0x00, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x01, 0x2e, 0x01, 0x0c, 0x00, 0xc9, 0x01, 0x18, 0x00, 0xcb,
+	0x01, 0x16, 0x00, 0xcd, 0x00, 0xce, 0x01, 0x2a, 0x01, 0x10, 0x01, 0x45,
+	0x01, 0x4c, 0x01, 0x36, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7,
+	0x00, 0xd8, 0x01, 0x72, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x01, 0x68,
+	0x01, 0x6a, 0x00, 0xdf, 0x01, 0x01, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x01, 0x2f, 0x01, 0x0d, 0x00, 0xe9,
+	0x01, 0x19, 0x00, 0xeb, 0x01, 0x17, 0x00, 0xed, 0x00, 0xee, 0x01, 0x2b,
+	0x01, 0x11, 0x01, 0x46, 0x01, 0x4d, 0x01, 0x37, 0x00, 0xf4, 0x00, 0xf5,
+	0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x01, 0x73, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x01, 0x69, 0x01, 0x6b, 0x02, 0xd9
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-5.h b/package/libs/libiconv/src/include/charmaps/iso-8859-5.h
new file mode 100644
index 0000000000..d9fe684a34
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-5.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_5[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x04, 0x01,
+	0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07,
+	0x04, 0x08, 0x04, 0x09, 0x04, 0x0a, 0x04, 0x0b, 0x04, 0x0c, 0x00, 0xad,
+	0x04, 0x0e, 0x04, 0x0f, 0x04, 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13,
+	0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, 0x18, 0x04, 0x19,
+	0x04, 0x1a, 0x04, 0x1b, 0x04, 0x1c, 0x04, 0x1d, 0x04, 0x1e, 0x04, 0x1f,
+	0x04, 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25,
+	0x04, 0x26, 0x04, 0x27, 0x04, 0x28, 0x04, 0x29, 0x04, 0x2a, 0x04, 0x2b,
+	0x04, 0x2c, 0x04, 0x2d, 0x04, 0x2e, 0x04, 0x2f, 0x04, 0x30, 0x04, 0x31,
+	0x04, 0x32, 0x04, 0x33, 0x04, 0x34, 0x04, 0x35, 0x04, 0x36, 0x04, 0x37,
+	0x04, 0x38, 0x04, 0x39, 0x04, 0x3a, 0x04, 0x3b, 0x04, 0x3c, 0x04, 0x3d,
+	0x04, 0x3e, 0x04, 0x3f, 0x04, 0x40, 0x04, 0x41, 0x04, 0x42, 0x04, 0x43,
+	0x04, 0x44, 0x04, 0x45, 0x04, 0x46, 0x04, 0x47, 0x04, 0x48, 0x04, 0x49,
+	0x04, 0x4a, 0x04, 0x4b, 0x04, 0x4c, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x4f,
+	0x21, 0x16, 0x04, 0x51, 0x04, 0x52, 0x04, 0x53, 0x04, 0x54, 0x04, 0x55,
+	0x04, 0x56, 0x04, 0x57, 0x04, 0x58, 0x04, 0x59, 0x04, 0x5a, 0x04, 0x5b,
+	0x04, 0x5c, 0x00, 0xa7, 0x04, 0x5e, 0x04, 0x5f
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-6.h b/package/libs/libiconv/src/include/charmaps/iso-8859-6.h
new file mode 100644
index 0000000000..820020fd91
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-6.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_6[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0x00, 0xa4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x0c, 0x00, 0xad,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x06, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x1f,
+	0xff, 0xff, 0x06, 0x21, 0x06, 0x22, 0x06, 0x23, 0x06, 0x24, 0x06, 0x25,
+	0x06, 0x26, 0x06, 0x27, 0x06, 0x28, 0x06, 0x29, 0x06, 0x2a, 0x06, 0x2b,
+	0x06, 0x2c, 0x06, 0x2d, 0x06, 0x2e, 0x06, 0x2f, 0x06, 0x30, 0x06, 0x31,
+	0x06, 0x32, 0x06, 0x33, 0x06, 0x34, 0x06, 0x35, 0x06, 0x36, 0x06, 0x37,
+	0x06, 0x38, 0x06, 0x39, 0x06, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0x06, 0x40, 0x06, 0x41, 0x06, 0x42, 0x06, 0x43,
+	0x06, 0x44, 0x06, 0x45, 0x06, 0x46, 0x06, 0x47, 0x06, 0x48, 0x06, 0x49,
+	0x06, 0x4a, 0x06, 0x4b, 0x06, 0x4c, 0x06, 0x4d, 0x06, 0x4e, 0x06, 0x4f,
+	0x06, 0x50, 0x06, 0x51, 0x06, 0x52, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-7.h b/package/libs/libiconv/src/include/charmaps/iso-8859-7.h
new file mode 100644
index 0000000000..174f9d3cbc
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-7.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_7[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x20, 0x18,
+	0x20, 0x19, 0x00, 0xa3, 0x20, 0xac, 0x20, 0xaf, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x03, 0x7a, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0xff, 0xff, 0x20, 0x15, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x03, 0x84, 0x03, 0x85, 0x03, 0x86, 0x00, 0xb7, 0x03, 0x88, 0x03, 0x89,
+	0x03, 0x8a, 0x00, 0xbb, 0x03, 0x8c, 0x00, 0xbd, 0x03, 0x8e, 0x03, 0x8f,
+	0x03, 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95,
+	0x03, 0x96, 0x03, 0x97, 0x03, 0x98, 0x03, 0x99, 0x03, 0x9a, 0x03, 0x9b,
+	0x03, 0x9c, 0x03, 0x9d, 0x03, 0x9e, 0x03, 0x9f, 0x03, 0xa0, 0x03, 0xa1,
+	0xff, 0xff, 0x03, 0xa3, 0x03, 0xa4, 0x03, 0xa5, 0x03, 0xa6, 0x03, 0xa7,
+	0x03, 0xa8, 0x03, 0xa9, 0x03, 0xaa, 0x03, 0xab, 0x03, 0xac, 0x03, 0xad,
+	0x03, 0xae, 0x03, 0xaf, 0x03, 0xb0, 0x03, 0xb1, 0x03, 0xb2, 0x03, 0xb3,
+	0x03, 0xb4, 0x03, 0xb5, 0x03, 0xb6, 0x03, 0xb7, 0x03, 0xb8, 0x03, 0xb9,
+	0x03, 0xba, 0x03, 0xbb, 0x03, 0xbc, 0x03, 0xbd, 0x03, 0xbe, 0x03, 0xbf,
+	0x03, 0xc0, 0x03, 0xc1, 0x03, 0xc2, 0x03, 0xc3, 0x03, 0xc4, 0x03, 0xc5,
+	0x03, 0xc6, 0x03, 0xc7, 0x03, 0xc8, 0x03, 0xc9, 0x03, 0xca, 0x03, 0xcb,
+	0x03, 0xcc, 0x03, 0xcd, 0x03, 0xce, 0xff, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-8.h b/package/libs/libiconv/src/include/charmaps/iso-8859-8.h
new file mode 100644
index 0000000000..66d4a5ec1f
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-8.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_8[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0xff, 0xff,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x00, 0xd7, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x00, 0xf7, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x17, 0x05, 0xd0, 0x05, 0xd1, 0x05, 0xd2, 0x05, 0xd3,
+	0x05, 0xd4, 0x05, 0xd5, 0x05, 0xd6, 0x05, 0xd7, 0x05, 0xd8, 0x05, 0xd9,
+	0x05, 0xda, 0x05, 0xdb, 0x05, 0xdc, 0x05, 0xdd, 0x05, 0xde, 0x05, 0xdf,
+	0x05, 0xe0, 0x05, 0xe1, 0x05, 0xe2, 0x05, 0xe3, 0x05, 0xe4, 0x05, 0xe5,
+	0x05, 0xe6, 0x05, 0xe7, 0x05, 0xe8, 0x05, 0xe9, 0x05, 0xea, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x0e, 0x20, 0x0f, 0xff, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/iso-8859-9.h b/package/libs/libiconv/src/include/charmaps/iso-8859-9.h
new file mode 100644
index 0000000000..f1a8646062
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/iso-8859-9.h
@@ -0,0 +1,24 @@
+static const unsigned char map_iso_8859_9[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83,
+	0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89,
+	0x00, 0x8a, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f,
+	0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95,
+	0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b,
+	0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x01, 0x1e, 0x00, 0xd1,
+	0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7,
+	0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x01, 0x30,
+	0x01, 0x5e, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x01, 0x1f, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5,
+	0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x01, 0x31, 0x01, 0x5f, 0x00, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/koi8-r.h b/package/libs/libiconv/src/include/charmaps/koi8-r.h
new file mode 100644
index 0000000000..c2453a5319
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/koi8-r.h
@@ -0,0 +1,24 @@
+static const unsigned char map_koi8_r[] = {
+	0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x25, 0x02, 0x25, 0x0c, 0x25, 0x10,
+	0x25, 0x14, 0x25, 0x18, 0x25, 0x1c, 0x25, 0x24, 0x25, 0x2c, 0x25, 0x34,
+	0x25, 0x3c, 0x25, 0x80, 0x25, 0x84, 0x25, 0x88, 0x25, 0x8c, 0x25, 0x90,
+	0x25, 0x91, 0x25, 0x92, 0x25, 0x93, 0x23, 0x20, 0x25, 0xa0, 0x22, 0x19,
+	0x22, 0x1a, 0x22, 0x48, 0x22, 0x64, 0x22, 0x65, 0x00, 0xa0, 0x23, 0x21,
+	0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xf7, 0x25, 0x50, 0x25, 0x51,
+	0x25, 0x52, 0x04, 0x51, 0x25, 0x53, 0x25, 0x54, 0x25, 0x55, 0x25, 0x56,
+	0x25, 0x57, 0x25, 0x58, 0x25, 0x59, 0x25, 0x5a, 0x25, 0x5b, 0x25, 0x5c,
+	0x25, 0x5d, 0x25, 0x5e, 0x25, 0x5f, 0x25, 0x60, 0x25, 0x61, 0x04, 0x01,
+	0x25, 0x62, 0x25, 0x63, 0x25, 0x64, 0x25, 0x65, 0x25, 0x66, 0x25, 0x67,
+	0x25, 0x68, 0x25, 0x69, 0x25, 0x6a, 0x25, 0x6b, 0x25, 0x6c, 0x00, 0xa9,
+	0x04, 0x4e, 0x04, 0x30, 0x04, 0x31, 0x04, 0x46, 0x04, 0x34, 0x04, 0x35,
+	0x04, 0x44, 0x04, 0x33, 0x04, 0x45, 0x04, 0x38, 0x04, 0x39, 0x04, 0x3a,
+	0x04, 0x3b, 0x04, 0x3c, 0x04, 0x3d, 0x04, 0x3e, 0x04, 0x3f, 0x04, 0x4f,
+	0x04, 0x40, 0x04, 0x41, 0x04, 0x42, 0x04, 0x43, 0x04, 0x36, 0x04, 0x32,
+	0x04, 0x4c, 0x04, 0x4b, 0x04, 0x37, 0x04, 0x48, 0x04, 0x4d, 0x04, 0x49,
+	0x04, 0x47, 0x04, 0x4a, 0x04, 0x2e, 0x04, 0x10, 0x04, 0x11, 0x04, 0x26,
+	0x04, 0x14, 0x04, 0x15, 0x04, 0x24, 0x04, 0x13, 0x04, 0x25, 0x04, 0x18,
+	0x04, 0x19, 0x04, 0x1a, 0x04, 0x1b, 0x04, 0x1c, 0x04, 0x1d, 0x04, 0x1e,
+	0x04, 0x1f, 0x04, 0x2f, 0x04, 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23,
+	0x04, 0x16, 0x04, 0x12, 0x04, 0x2c, 0x04, 0x2b, 0x04, 0x17, 0x04, 0x28,
+	0x04, 0x2d, 0x04, 0x29, 0x04, 0x27, 0x04, 0x2a
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1250.h b/package/libs/libiconv/src/include/charmaps/windows-1250.h
new file mode 100644
index 0000000000..8e4723e48d
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1250.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1250[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0xff, 0xff,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0xff, 0xff, 0x20, 0x30,
+	0x01, 0x60, 0x20, 0x39, 0x01, 0x5a, 0x01, 0x64, 0x01, 0x7d, 0x01, 0x79,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0xff, 0xff, 0x21, 0x22, 0x01, 0x61, 0x20, 0x3a,
+	0x01, 0x5b, 0x01, 0x65, 0x01, 0x7e, 0x01, 0x7a, 0x00, 0xa0, 0x02, 0xc7,
+	0x02, 0xd8, 0x01, 0x41, 0x00, 0xa4, 0x01, 0x04, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x01, 0x5e, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x01, 0x7b, 0x00, 0xb0, 0x00, 0xb1, 0x02, 0xdb, 0x01, 0x42,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x01, 0x05,
+	0x01, 0x5f, 0x00, 0xbb, 0x01, 0x3d, 0x02, 0xdd, 0x01, 0x3e, 0x01, 0x7c,
+	0x01, 0x54, 0x00, 0xc1, 0x00, 0xc2, 0x01, 0x02, 0x00, 0xc4, 0x01, 0x39,
+	0x01, 0x06, 0x00, 0xc7, 0x01, 0x0c, 0x00, 0xc9, 0x01, 0x18, 0x00, 0xcb,
+	0x01, 0x1a, 0x00, 0xcd, 0x00, 0xce, 0x01, 0x0e, 0x01, 0x10, 0x01, 0x43,
+	0x01, 0x47, 0x00, 0xd3, 0x00, 0xd4, 0x01, 0x50, 0x00, 0xd6, 0x00, 0xd7,
+	0x01, 0x58, 0x01, 0x6e, 0x00, 0xda, 0x01, 0x70, 0x00, 0xdc, 0x00, 0xdd,
+	0x01, 0x62, 0x00, 0xdf, 0x01, 0x55, 0x00, 0xe1, 0x00, 0xe2, 0x01, 0x03,
+	0x00, 0xe4, 0x01, 0x3a, 0x01, 0x07, 0x00, 0xe7, 0x01, 0x0d, 0x00, 0xe9,
+	0x01, 0x19, 0x00, 0xeb, 0x01, 0x1b, 0x00, 0xed, 0x00, 0xee, 0x01, 0x0f,
+	0x01, 0x11, 0x01, 0x44, 0x01, 0x48, 0x00, 0xf3, 0x00, 0xf4, 0x01, 0x51,
+	0x00, 0xf6, 0x00, 0xf7, 0x01, 0x59, 0x01, 0x6f, 0x00, 0xfa, 0x01, 0x71,
+	0x00, 0xfc, 0x00, 0xfd, 0x01, 0x63, 0x02, 0xd9
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1251.h b/package/libs/libiconv/src/include/charmaps/windows-1251.h
new file mode 100644
index 0000000000..e278850727
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1251.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1251[] = {
+	0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x04, 0x03, 0x20, 0x1a, 0x04, 0x53,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0x20, 0xac, 0x20, 0x30,
+	0x04, 0x09, 0x20, 0x39, 0x04, 0x0a, 0x04, 0x0c, 0x04, 0x0b, 0x04, 0x0f,
+	0x04, 0x52, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0xff, 0xff, 0x21, 0x22, 0x04, 0x59, 0x20, 0x3a,
+	0x04, 0x5a, 0x04, 0x5c, 0x04, 0x5b, 0x04, 0x5f, 0x00, 0xa0, 0x04, 0x0e,
+	0x04, 0x5e, 0x04, 0x08, 0x00, 0xa4, 0x04, 0x90, 0x00, 0xa6, 0x00, 0xa7,
+	0x04, 0x01, 0x00, 0xa9, 0x04, 0x04, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x04, 0x07, 0x00, 0xb0, 0x00, 0xb1, 0x04, 0x06, 0x04, 0x56,
+	0x04, 0x91, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x04, 0x51, 0x21, 0x16,
+	0x04, 0x54, 0x00, 0xbb, 0x04, 0x58, 0x04, 0x05, 0x04, 0x55, 0x04, 0x57,
+	0x04, 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15,
+	0x04, 0x16, 0x04, 0x17, 0x04, 0x18, 0x04, 0x19, 0x04, 0x1a, 0x04, 0x1b,
+	0x04, 0x1c, 0x04, 0x1d, 0x04, 0x1e, 0x04, 0x1f, 0x04, 0x20, 0x04, 0x21,
+	0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27,
+	0x04, 0x28, 0x04, 0x29, 0x04, 0x2a, 0x04, 0x2b, 0x04, 0x2c, 0x04, 0x2d,
+	0x04, 0x2e, 0x04, 0x2f, 0x04, 0x30, 0x04, 0x31, 0x04, 0x32, 0x04, 0x33,
+	0x04, 0x34, 0x04, 0x35, 0x04, 0x36, 0x04, 0x37, 0x04, 0x38, 0x04, 0x39,
+	0x04, 0x3a, 0x04, 0x3b, 0x04, 0x3c, 0x04, 0x3d, 0x04, 0x3e, 0x04, 0x3f,
+	0x04, 0x40, 0x04, 0x41, 0x04, 0x42, 0x04, 0x43, 0x04, 0x44, 0x04, 0x45,
+	0x04, 0x46, 0x04, 0x47, 0x04, 0x48, 0x04, 0x49, 0x04, 0x4a, 0x04, 0x4b,
+	0x04, 0x4c, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x4f
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1252.h b/package/libs/libiconv/src/include/charmaps/windows-1252.h
new file mode 100644
index 0000000000..a6dad8a05a
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1252.h
@@ -0,0 +1,25 @@
+static const unsigned char map_windows_1252[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0x01, 0x92,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0x02, 0xc6, 0x20, 0x30,
+	0x01, 0x60, 0x20, 0x39, 0x01, 0x52, 0xff, 0xff, 0x01, 0x7d, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0x02, 0xdc, 0x21, 0x22, 0x01, 0x61, 0x20, 0x3a,
+	0x01, 0x53, 0xff, 0xff, 0x01, 0x7e, 0x01, 0x78, 0x00, 0xa0, 0x00, 0xa1,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1,
+	0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7,
+	0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd,
+	0x00, 0xde, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x00, 0xf0, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5,
+	0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00, 0xff
+};
+
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1253.h b/package/libs/libiconv/src/include/charmaps/windows-1253.h
new file mode 100644
index 0000000000..b0bdf1eb36
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1253.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1253[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0x01, 0x92,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0xff, 0xff, 0x20, 0x30,
+	0xff, 0xff, 0x20, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0xff, 0xff, 0x21, 0x22, 0xff, 0xff, 0x20, 0x3a,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xa0, 0x03, 0x85,
+	0x03, 0x86, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0xff, 0xff, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x20, 0x15, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x03, 0x84, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x03, 0x88, 0x03, 0x89,
+	0x03, 0x8a, 0x00, 0xbb, 0x03, 0x8c, 0x00, 0xbd, 0x03, 0x8e, 0x03, 0x8f,
+	0x03, 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95,
+	0x03, 0x96, 0x03, 0x97, 0x03, 0x98, 0x03, 0x99, 0x03, 0x9a, 0x03, 0x9b,
+	0x03, 0x9c, 0x03, 0x9d, 0x03, 0x9e, 0x03, 0x9f, 0x03, 0xa0, 0x03, 0xa1,
+	0xff, 0xff, 0x03, 0xa3, 0x03, 0xa4, 0x03, 0xa5, 0x03, 0xa6, 0x03, 0xa7,
+	0x03, 0xa8, 0x03, 0xa9, 0x03, 0xaa, 0x03, 0xab, 0x03, 0xac, 0x03, 0xad,
+	0x03, 0xae, 0x03, 0xaf, 0x03, 0xb0, 0x03, 0xb1, 0x03, 0xb2, 0x03, 0xb3,
+	0x03, 0xb4, 0x03, 0xb5, 0x03, 0xb6, 0x03, 0xb7, 0x03, 0xb8, 0x03, 0xb9,
+	0x03, 0xba, 0x03, 0xbb, 0x03, 0xbc, 0x03, 0xbd, 0x03, 0xbe, 0x03, 0xbf,
+	0x03, 0xc0, 0x03, 0xc1, 0x03, 0xc2, 0x03, 0xc3, 0x03, 0xc4, 0x03, 0xc5,
+	0x03, 0xc6, 0x03, 0xc7, 0x03, 0xc8, 0x03, 0xc9, 0x03, 0xca, 0x03, 0xcb,
+	0x03, 0xcc, 0x03, 0xcd, 0x03, 0xce, 0xff, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1254.h b/package/libs/libiconv/src/include/charmaps/windows-1254.h
new file mode 100644
index 0000000000..be22600797
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1254.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1254[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0x01, 0x92,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0x02, 0xc6, 0x20, 0x30,
+	0x01, 0x60, 0x20, 0x39, 0x01, 0x52, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0x02, 0xdc, 0x21, 0x22, 0x01, 0x61, 0x20, 0x3a,
+	0x01, 0x53, 0xff, 0xff, 0xff, 0xff, 0x01, 0x78, 0x00, 0xa0, 0x00, 0xa1,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x01, 0x1e, 0x00, 0xd1,
+	0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7,
+	0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x01, 0x30,
+	0x01, 0x5e, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x01, 0x1f, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf5,
+	0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x01, 0x31, 0x01, 0x5f, 0x00, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1255.h b/package/libs/libiconv/src/include/charmaps/windows-1255.h
new file mode 100644
index 0000000000..28bf513d46
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1255.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1255[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0x01, 0x92,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0x02, 0xc6, 0x20, 0x30,
+	0xff, 0xff, 0x20, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0x02, 0xdc, 0x21, 0x22, 0xff, 0xff, 0x20, 0x3a,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xa0, 0x00, 0xa1,
+	0x00, 0xa2, 0x00, 0xa3, 0x20, 0xaa, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x00, 0xd7, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x00, 0xf7, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf,
+	0x05, 0xb0, 0x05, 0xb1, 0x05, 0xb2, 0x05, 0xb3, 0x05, 0xb4, 0x05, 0xb5,
+	0x05, 0xb6, 0x05, 0xb7, 0x05, 0xb8, 0x05, 0xb9, 0xff, 0xff, 0x05, 0xbb,
+	0x05, 0xbc, 0x05, 0xbd, 0x05, 0xbe, 0x05, 0xbf, 0x05, 0xc0, 0x05, 0xc1,
+	0x05, 0xc2, 0x05, 0xc3, 0x05, 0xf0, 0x05, 0xf1, 0x05, 0xf2, 0x05, 0xf3,
+	0x05, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0x05, 0xd0, 0x05, 0xd1, 0x05, 0xd2, 0x05, 0xd3,
+	0x05, 0xd4, 0x05, 0xd5, 0x05, 0xd6, 0x05, 0xd7, 0x05, 0xd8, 0x05, 0xd9,
+	0x05, 0xda, 0x05, 0xdb, 0x05, 0xdc, 0x05, 0xdd, 0x05, 0xde, 0x05, 0xdf,
+	0x05, 0xe0, 0x05, 0xe1, 0x05, 0xe2, 0x05, 0xe3, 0x05, 0xe4, 0x05, 0xe5,
+	0x05, 0xe6, 0x05, 0xe7, 0x05, 0xe8, 0x05, 0xe9, 0x05, 0xea, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x0e, 0x20, 0x0f, 0xff, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1256.h b/package/libs/libiconv/src/include/charmaps/windows-1256.h
new file mode 100644
index 0000000000..fbca315eff
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1256.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1256[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0x06, 0x7e, 0x20, 0x1a, 0x01, 0x92,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0x02, 0xc6, 0x20, 0x30,
+	0x06, 0x79, 0x20, 0x39, 0x01, 0x52, 0x06, 0x86, 0x06, 0x98, 0x06, 0x88,
+	0x06, 0xaf, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0x06, 0xa9, 0x21, 0x22, 0x06, 0x91, 0x20, 0x3a,
+	0x01, 0x53, 0x20, 0x0c, 0x20, 0x0d, 0x06, 0xba, 0x00, 0xa0, 0x06, 0x0c,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x06, 0xbe, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x06, 0x1b, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x06, 0x1f,
+	0x06, 0xc1, 0x06, 0x21, 0x06, 0x22, 0x06, 0x23, 0x06, 0x24, 0x06, 0x25,
+	0x06, 0x26, 0x06, 0x27, 0x06, 0x28, 0x06, 0x29, 0x06, 0x2a, 0x06, 0x2b,
+	0x06, 0x2c, 0x06, 0x2d, 0x06, 0x2e, 0x06, 0x2f, 0x06, 0x30, 0x06, 0x31,
+	0x06, 0x32, 0x06, 0x33, 0x06, 0x34, 0x06, 0x35, 0x06, 0x36, 0x00, 0xd7,
+	0x06, 0x37, 0x06, 0x38, 0x06, 0x39, 0x06, 0x3a, 0x06, 0x40, 0x06, 0x41,
+	0x06, 0x42, 0x06, 0x43, 0x00, 0xe0, 0x06, 0x44, 0x00, 0xe2, 0x06, 0x45,
+	0x06, 0x46, 0x06, 0x47, 0x06, 0x48, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x06, 0x49, 0x06, 0x4a, 0x00, 0xee, 0x00, 0xef,
+	0x06, 0x4b, 0x06, 0x4c, 0x06, 0x4d, 0x06, 0x4e, 0x00, 0xf4, 0x06, 0x4f,
+	0x06, 0x50, 0x00, 0xf7, 0x06, 0x51, 0x00, 0xf9, 0x06, 0x52, 0x00, 0xfb,
+	0x00, 0xfc, 0x20, 0x0e, 0x20, 0x0f, 0x06, 0xd2
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1257.h b/package/libs/libiconv/src/include/charmaps/windows-1257.h
new file mode 100644
index 0000000000..69d4474bc2
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1257.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1257[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0xff, 0xff,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0xff, 0xff, 0x20, 0x30,
+	0xff, 0xff, 0x20, 0x39, 0xff, 0xff, 0x00, 0xa8, 0x02, 0xc7, 0x00, 0xb8,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0xff, 0xff, 0x21, 0x22, 0xff, 0xff, 0x20, 0x3a,
+	0xff, 0xff, 0x00, 0xaf, 0x02, 0xdb, 0xff, 0xff, 0x00, 0xa0, 0xff, 0xff,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0xff, 0xff, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xd8, 0x00, 0xa9, 0x01, 0x56, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xc6, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xf8, 0x00, 0xb9,
+	0x01, 0x57, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xe6,
+	0x01, 0x04, 0x01, 0x2e, 0x01, 0x00, 0x01, 0x06, 0x00, 0xc4, 0x00, 0xc5,
+	0x01, 0x18, 0x01, 0x12, 0x01, 0x0c, 0x00, 0xc9, 0x01, 0x79, 0x01, 0x16,
+	0x01, 0x22, 0x01, 0x36, 0x01, 0x2a, 0x01, 0x3b, 0x01, 0x60, 0x01, 0x43,
+	0x01, 0x45, 0x00, 0xd3, 0x01, 0x4c, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd7,
+	0x01, 0x72, 0x01, 0x41, 0x01, 0x5a, 0x01, 0x6a, 0x00, 0xdc, 0x01, 0x7b,
+	0x01, 0x7d, 0x00, 0xdf, 0x01, 0x05, 0x01, 0x2f, 0x01, 0x01, 0x01, 0x07,
+	0x00, 0xe4, 0x00, 0xe5, 0x01, 0x19, 0x01, 0x13, 0x01, 0x0d, 0x00, 0xe9,
+	0x01, 0x7a, 0x01, 0x17, 0x01, 0x23, 0x01, 0x37, 0x01, 0x2b, 0x01, 0x3c,
+	0x01, 0x61, 0x01, 0x44, 0x01, 0x46, 0x00, 0xf3, 0x01, 0x4d, 0x00, 0xf5,
+	0x00, 0xf6, 0x00, 0xf7, 0x01, 0x73, 0x01, 0x42, 0x01, 0x5b, 0x01, 0x6b,
+	0x00, 0xfc, 0x01, 0x7c, 0x01, 0x7e, 0x02, 0xd9
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-1258.h b/package/libs/libiconv/src/include/charmaps/windows-1258.h
new file mode 100644
index 0000000000..5bbd737aec
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-1258.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_1258[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0x20, 0x1a, 0x01, 0x92,
+	0x20, 0x1e, 0x20, 0x26, 0x20, 0x20, 0x20, 0x21, 0x02, 0xc6, 0x20, 0x30,
+	0xff, 0xff, 0x20, 0x39, 0x01, 0x52, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0x02, 0xdc, 0x21, 0x22, 0xff, 0xff, 0x20, 0x3a,
+	0x01, 0x53, 0xff, 0xff, 0xff, 0xff, 0x01, 0x78, 0x00, 0xa0, 0x00, 0xa1,
+	0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7,
+	0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xad,
+	0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3,
+	0x00, 0xb4, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9,
+	0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbf,
+	0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x01, 0x02, 0x00, 0xc4, 0x00, 0xc5,
+	0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb,
+	0x03, 0x00, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x01, 0x10, 0x00, 0xd1,
+	0x03, 0x09, 0x00, 0xd3, 0x00, 0xd4, 0x01, 0xa0, 0x00, 0xd6, 0x00, 0xd7,
+	0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x01, 0xaf,
+	0x03, 0x03, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x01, 0x03,
+	0x00, 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9,
+	0x00, 0xea, 0x00, 0xeb, 0x03, 0x01, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef,
+	0x01, 0x11, 0x00, 0xf1, 0x03, 0x23, 0x00, 0xf3, 0x00, 0xf4, 0x01, 0xa1,
+	0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xfb,
+	0x00, 0xfc, 0x01, 0xb0, 0x20, 0xab, 0x00, 0xff
+};
diff --git a/package/libs/libiconv/src/include/charmaps/windows-874.h b/package/libs/libiconv/src/include/charmaps/windows-874.h
new file mode 100644
index 0000000000..5749280a5e
--- /dev/null
+++ b/package/libs/libiconv/src/include/charmaps/windows-874.h
@@ -0,0 +1,24 @@
+static const unsigned char map_windows_874[] = {
+	0x00, 0x00, 0x00, 0x00, 0x20, 0xac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1c, 0x20, 0x1d, 0x20, 0x22,
+	0x20, 0x13, 0x20, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xa0, 0x0e, 0x01,
+	0x0e, 0x02, 0x0e, 0x03, 0x0e, 0x04, 0x0e, 0x05, 0x0e, 0x06, 0x0e, 0x07,
+	0x0e, 0x08, 0x0e, 0x09, 0x0e, 0x0a, 0x0e, 0x0b, 0x0e, 0x0c, 0x0e, 0x0d,
+	0x0e, 0x0e, 0x0e, 0x0f, 0x0e, 0x10, 0x0e, 0x11, 0x0e, 0x12, 0x0e, 0x13,
+	0x0e, 0x14, 0x0e, 0x15, 0x0e, 0x16, 0x0e, 0x17, 0x0e, 0x18, 0x0e, 0x19,
+	0x0e, 0x1a, 0x0e, 0x1b, 0x0e, 0x1c, 0x0e, 0x1d, 0x0e, 0x1e, 0x0e, 0x1f,
+	0x0e, 0x20, 0x0e, 0x21, 0x0e, 0x22, 0x0e, 0x23, 0x0e, 0x24, 0x0e, 0x25,
+	0x0e, 0x26, 0x0e, 0x27, 0x0e, 0x28, 0x0e, 0x29, 0x0e, 0x2a, 0x0e, 0x2b,
+	0x0e, 0x2c, 0x0e, 0x2d, 0x0e, 0x2e, 0x0e, 0x2f, 0x0e, 0x30, 0x0e, 0x31,
+	0x0e, 0x32, 0x0e, 0x33, 0x0e, 0x34, 0x0e, 0x35, 0x0e, 0x36, 0x0e, 0x37,
+	0x0e, 0x38, 0x0e, 0x39, 0x0e, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x0e, 0x3f, 0x0e, 0x40, 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x43,
+	0x0e, 0x44, 0x0e, 0x45, 0x0e, 0x46, 0x0e, 0x47, 0x0e, 0x48, 0x0e, 0x49,
+	0x0e, 0x4a, 0x0e, 0x4b, 0x0e, 0x4c, 0x0e, 0x4d, 0x0e, 0x4e, 0x0e, 0x4f,
+	0x0e, 0x50, 0x0e, 0x51, 0x0e, 0x52, 0x0e, 0x53, 0x0e, 0x54, 0x0e, 0x55,
+	0x0e, 0x56, 0x0e, 0x57, 0x0e, 0x58, 0x0e, 0x59, 0x0e, 0x5a, 0x0e, 0x5b,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
diff --git a/package/libs/libiconv/src/include/iconv.h b/package/libs/libiconv/src/include/iconv.h
new file mode 100644
index 0000000000..8767be42ee
--- /dev/null
+++ b/package/libs/libiconv/src/include/iconv.h
@@ -0,0 +1,36 @@
+#ifndef _LIBICONV_H
+#define _LIBICONV_H 1
+
+#define _LIBICONV_VERSION 0x010B    /* version number: (major<<8) + minor */
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int _libiconv_version; /* Likewise */
+
+typedef long iconv_t;
+
+#define iconv_open libiconv_open
+#define iconv libiconv
+#define iconv_close libiconv_close
+
+extern iconv_t
+iconv_open(const char *tocode, const char *fromcode);
+
+extern size_t
+iconv(iconv_t cd, char **inbuf, size_t *inbytesleft,
+                  char **outbuf, size_t *outbytesleft);
+
+extern int
+iconv_close(iconv_t cd);
+
+#define libiconv_set_relocation_prefix(...) do {} while(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBICONV_H */
diff --git a/package/libs/libiconv/src/m4/iconv.m4 b/package/libs/libiconv/src/m4/iconv.m4
new file mode 100644
index 0000000000..e2041b9b49
--- /dev/null
+++ b/package/libs/libiconv/src/m4/iconv.m4
@@ -0,0 +1,214 @@
+# iconv.m4 serial 11 (gettext-0.18.1)
+dnl Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
+[
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([iconv])
+])
+
+AC_DEFUN([AM_ICONV_LINK],
+[
+  dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+  dnl those with the standalone portable GNU libiconv installed).
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+
+  dnl Add $INCICONV to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed libiconv and not disabled its use
+  dnl via --without-libiconv-prefix, he wants to use it. The first
+  dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+  am_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
+
+  AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [
+    am_cv_func_iconv="no, consider installing GNU libiconv"
+    am_cv_lib_iconv=no
+    AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+      [iconv_t cd = iconv_open("","");
+       iconv(cd,NULL,NULL,NULL,NULL);
+       iconv_close(cd);],
+      [am_cv_func_iconv=yes])
+    if test "$am_cv_func_iconv" != yes; then
+      am_save_LIBS="$LIBS"
+      LIBS="$LIBS $LIBICONV"
+      AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+        [iconv_t cd = iconv_open("","");
+         iconv(cd,NULL,NULL,NULL,NULL);
+         iconv_close(cd);],
+        [am_cv_lib_iconv=yes]
+        [am_cv_func_iconv=yes])
+      LIBS="$am_save_LIBS"
+    fi
+  ])
+  if test "$am_cv_func_iconv" = yes; then
+    AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [
+      dnl This tests against bugs in AIX 5.1, HP-UX 11.11, Solaris 10.
+      am_save_LIBS="$LIBS"
+      if test $am_cv_lib_iconv = yes; then
+        LIBS="$LIBS $LIBICONV"
+      fi
+      AC_TRY_RUN([
+#include <iconv.h>
+#include <string.h>
+int main ()
+{
+  /* Test against AIX 5.1 bug: Failures are not distinguishable from successful
+     returns.  */
+  {
+    iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
+    if (cd_utf8_to_88591 != (iconv_t)(-1))
+      {
+        static const char input[] = "\342\202\254"; /* EURO SIGN */
+        char buf[10];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_utf8_to_88591,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if (res == 0)
+          return 1;
+      }
+  }
+  /* Test against Solaris 10 bug: Failures are not distinguishable from
+     successful returns.  */
+  {
+    iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646");
+    if (cd_ascii_to_88591 != (iconv_t)(-1))
+      {
+        static const char input[] = "\263";
+        char buf[10];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_ascii_to_88591,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if (res == 0)
+          return 1;
+      }
+  }
+#if 0 /* This bug could be worked around by the caller.  */
+  /* Test against HP-UX 11.11 bug: Positive return value instead of 0.  */
+  {
+    iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
+    if (cd_88591_to_utf8 != (iconv_t)(-1))
+      {
+        static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
+        char buf[50];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_88591_to_utf8,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if ((int)res > 0)
+          return 1;
+      }
+  }
+#endif
+  /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
+     provided.  */
+  if (/* Try standardized names.  */
+      iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
+      /* Try IRIX, OSF/1 names.  */
+      && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
+      /* Try AIX names.  */
+      && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
+      /* Try HP-UX names.  */
+      && iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
+    return 1;
+  return 0;
+}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no],
+        [case "$host_os" in
+           aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
+           *)            am_cv_func_iconv_works="guessing yes" ;;
+         esac])
+      LIBS="$am_save_LIBS"
+    ])
+    case "$am_cv_func_iconv_works" in
+      *no) am_func_iconv=no am_cv_lib_iconv=no ;;
+      *)   am_func_iconv=yes ;;
+    esac
+  else
+    am_func_iconv=no am_cv_lib_iconv=no
+  fi
+  if test "$am_func_iconv" = yes; then
+    AC_DEFINE([HAVE_ICONV], [1],
+      [Define if you have the iconv() function and it works.])
+  fi
+  if test "$am_cv_lib_iconv" = yes; then
+    AC_MSG_CHECKING([how to link with libiconv])
+    AC_MSG_RESULT([$LIBICONV])
+  else
+    dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
+    dnl either.
+    CPPFLAGS="$am_save_CPPFLAGS"
+    LIBICONV=
+    LTLIBICONV=
+  fi
+  AC_SUBST([LIBICONV])
+  AC_SUBST([LTLIBICONV])
+])
+
+dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to
+dnl avoid warnings like
+dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
+dnl This is tricky because of the way 'aclocal' is implemented:
+dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN.
+dnl   Otherwise aclocal's initial scan pass would miss the macro definition.
+dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions.
+dnl   Otherwise aclocal would emit many "Use of uninitialized value $1"
+dnl   warnings.
+m4_define([gl_iconv_AC_DEFUN],
+  m4_version_prereq([2.64],
+    [[AC_DEFUN_ONCE(
+        [$1], [$2])]],
+    [[AC_DEFUN(
+        [$1], [$2])]]))
+gl_iconv_AC_DEFUN([AM_ICONV],
+[
+  AM_ICONV_LINK
+  if test "$am_cv_func_iconv" = yes; then
+    AC_MSG_CHECKING([for iconv declaration])
+    AC_CACHE_VAL([am_cv_proto_iconv], [
+      AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"])
+      am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+    am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+    AC_MSG_RESULT([
+         $am_cv_proto_iconv])
+    AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1],
+      [Define as const if the declaration of iconv() needs const.])
+  fi
+])
diff --git a/package/libs/libjson-c/Makefile b/package/libs/libjson-c/Makefile
new file mode 100644
index 0000000000..51cc645045
--- /dev/null
+++ b/package/libs/libjson-c/Makefile
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=json-c
+PKG_VERSION:=0.12.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-nodoc.tar.gz
+PKG_SOURCE_URL:=https://s3.amazonaws.com/json-c_releases/releases/
+PKG_MD5SUM:=5b91ab230d9b6b0ee20fc19cf25094f5
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=COPYING
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+TARGET_CFLAGS += $(FPIC)
+
+define Package/libjson-c
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=javascript object notation
+  URL:=http://oss.metaparadigm.com/json-c/
+endef
+
+define Package/libjson-c/description
+ This package contains a library for javascript object notation backends.
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/json-c $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libjson-c.{a,so*} $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/json-c.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libjson-c/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libjson-c.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libjson-c))
diff --git a/package/libs/libjson-c/patches/000-libm.patch b/package/libs/libjson-c/patches/000-libm.patch
new file mode 100644
index 0000000000..45adb0597f
--- /dev/null
+++ b/package/libs/libjson-c/patches/000-libm.patch
@@ -0,0 +1,50 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -43,12 +43,6 @@
+ AC_FUNC_MALLOC
+ AC_FUNC_REALLOC
+ AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
+-AC_CHECK_DECLS([INFINITY], [], [], [[#include <math.h>]])
+-AC_CHECK_DECLS([nan], [], [], [[#include <math.h>]])
+-AC_CHECK_DECLS([isnan], [], [], [[#include <math.h>]])
+-AC_CHECK_DECLS([isinf], [], [], [[#include <math.h>]])
+-AC_CHECK_DECLS([_isnan], [], [], [[#include <float.h>]])
+-AC_CHECK_DECLS([_finite], [], [], [[#include <float.h>]])
+ 
+ #check if .section.gnu.warning accepts long strings (for __warn_references)
+ AC_LANG_PUSH([C])
+--- a/math_compat.h
++++ b/math_compat.h
+@@ -1,28 +1,9 @@
+ #ifndef __math_compat_h
+ #define __math_compat_h
+ 
+-/* Define isnan and isinf on Windows/MSVC */
+-
+-#ifndef HAVE_DECL_ISNAN
+-# ifdef HAVE_DECL__ISNAN
+-#include <float.h>
+-#define isnan(x) _isnan(x)
+-# endif
+-#endif
+-
+-#ifndef HAVE_DECL_ISINF
+-# ifdef HAVE_DECL__FINITE
+-#include <float.h>
+-#define isinf(x) (!_finite(x))
+-# endif
+-#endif
+-
+-#ifndef HAVE_DECL_NAN
+-#error This platform does not have nan()
+-#endif
+-
+-#ifndef HAVE_DECL_INFINITY
+-#error This platform does not have INFINITY
+-#endif
++#undef isnan
++#define isnan(x) __builtin_isnan(x)
++#undef isinf
++#define isinf(x) __builtin_isinf(x)
+ 
+ #endif
diff --git a/package/libs/libmnl/Makefile b/package/libs/libmnl/Makefile
new file mode 100644
index 0000000000..9f8d9ac139
--- /dev/null
+++ b/package/libs/libmnl/Makefile
@@ -0,0 +1,77 @@
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libmnl
+PKG_VERSION:=1.0.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/libmnl/files \
+	ftp://ftp.netfilter.org/pub/libmnl
+PKG_MD5SUM:=171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+PKG_LICENSE:=LGPL-2.1+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libmnl
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Minimalistic user-space library for Netlink
+  URL:=http://www.netfilter.org/projects/libmnl/
+endef
+
+define Package/libmnl/description
+ libmnl is a minimalistic user-space library oriented to Netlink developers.
+ There are a lot of common tasks in parsing, validating, constructing of
+ both the Netlink header and TLVs that are repetitive and easy to get wrong.
+ This library aims to provide simple helpers that allows you to re-use code
+ and to avoid re-inventing the wheel. The main features of this library are:
+ .
+ * Small: the shared library requires around 30KB for an x86-based computer.
+ .
+ * Simple: this library avoids complexity and elaborated abstractions that
+   tend to hide Netlink details.
+ .
+ * Easy to use: the library simplifies the work for Netlink-wise developers.
+   It provides functions to make socket handling, message building, validating,
+   parsing and sequence tracking, easier.
+ .
+ * Easy to re-use: you can use the library to build your own abstraction layer
+   on top of this library.
+ .
+ * Decoupling: the interdependency of the main bricks that compose the library
+   is reduced, i.e. the library provides many helpers, but the programmer is not
+   forced to use them.
+endef
+
+CONFIGURE_ARGS+= \
+	--enable-shared \
+	--enable-static \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libmnl $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libmnl.{a,so*} $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libmnl.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libmnl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libmnl.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libmnl))
diff --git a/package/libs/libnetfilter-conntrack/Makefile b/package/libs/libnetfilter-conntrack/Makefile
new file mode 100644
index 0000000000..96da6f9773
--- /dev/null
+++ b/package/libs/libnetfilter-conntrack/Makefile
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnetfilter_conntrack
+PKG_VERSION:=1.0.6
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/libnetfilter_conntrack/files/ \
+	ftp://ftp.netfilter.org/pub/libnetfilter_conntrack/
+PKG_MD5SUM:=efcc08021284e75f4d96d3581c5155a11f08fd63316b1938cbcb269c87f37feb
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnetfilter-conntrack
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libnfnetlink +kmod-nf-conntrack-netlink +libmnl
+  TITLE:=API to the in-kernel connection tracking state table
+  URL:=http://www.netfilter.org/projects/libnetfilter_conntrack/
+endef
+
+define Package/libnetfilter-conntrack/description
+ libnetfilter_conntrack is a userspace library providing a programming
+ interface (API) to the in-kernel connection tracking state table. The
+ library libnetfilter_conntrack has been previously known as
+ libnfnetlink_conntrack and libctnetlink. This library is currently
+ used by conntrack-tools among many other applications.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnetfilter_conntrack
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnetfilter_conntrack/*.h \
+		$(1)/usr/include/libnetfilter_conntrack/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_conntrack.{so*,a,la} \
+		$(1)/usr/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnetfilter_conntrack.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnetfilter-conntrack/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_conntrack.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnetfilter-conntrack))
diff --git a/package/libs/libnetfilter-cthelper/Makefile b/package/libs/libnetfilter-cthelper/Makefile
new file mode 100644
index 0000000000..84a77645bd
--- /dev/null
+++ b/package/libs/libnetfilter-cthelper/Makefile
@@ -0,0 +1,71 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnetfilter_cthelper
+PKG_VERSION:=1.0.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/libnetfilter_cthelper/files/ \
+	ftp://ftp.netfilter.org/pub/libnetfilter_cthelper/
+PKG_MD5SUM:=b2efab1a3a198a5add448960ba011acd
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnetfilter-cthelper
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libmnl
+  TITLE:=API to the in-kernel connection tracking helper infrastructure
+  URL:=http://www.netfilter.org/projects/libnetfilter_cthelper/
+endef
+
+define Package/libnetfilter-cthelper/description
+ libnetfilter_cthelper is a userspace library providing a programming
+ interface (API) to the in-kernel connection tracking helpers. 
+ This library is currently used by conntrack-tools.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnetfilter_cthelper
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnetfilter_cthelper/*.h \
+		$(1)/usr/include/libnetfilter_cthelper/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_cthelper.{so*,a,la} \
+		$(1)/usr/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnetfilter_cthelper.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnetfilter-cthelper/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_cthelper.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnetfilter-cthelper))
diff --git a/package/libs/libnetfilter-cttimeout/Makefile b/package/libs/libnetfilter-cttimeout/Makefile
new file mode 100644
index 0000000000..d065d2631b
--- /dev/null
+++ b/package/libs/libnetfilter-cttimeout/Makefile
@@ -0,0 +1,71 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnetfilter_cttimeout
+PKG_VERSION:=1.0.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/libnetfilter_cttimeout/files/ \
+	ftp://ftp.netfilter.org/pub/libnetfilter_cttimeout/
+PKG_MD5SUM:=7697437fc9ebb6f6b83df56a633db7f9
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnetfilter-cttimeout
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libmnl
+  TITLE:=API to the in-kernel connection tracking timeout infrastructure
+  URL:=http://www.netfilter.org/projects/libnetfilter_cttimeout/
+endef
+
+define Package/libnetfilter-cttimeout/description
+ libnetfilter_cttimeout is a userspace library providing a programming
+ interface (API) to the in-kernel connection tracking timeout handling.
+ This library is currently used by conntrack-tools.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnetfilter_cttimeout
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnetfilter_cttimeout/*.h \
+		$(1)/usr/include/libnetfilter_cttimeout/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_cttimeout.{so*,a,la} \
+		$(1)/usr/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnetfilter_cttimeout.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnetfilter-cttimeout/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_cttimeout.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnetfilter-cttimeout))
diff --git a/package/libs/libnetfilter-log/Makefile b/package/libs/libnetfilter-log/Makefile
new file mode 100644
index 0000000000..51838fb6dd
--- /dev/null
+++ b/package/libs/libnetfilter-log/Makefile
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnetfilter_log
+PKG_VERSION:=1.0.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/libnetfilter_log/files/ \
+	ftp://ftp.netfilter.org/pub/libnetfilter_log/
+PKG_MD5SUM:=2a4bb0654ae675a52d2e8d1c06090b94
+PKG_MAINTAINER:=Yousong Zhou <yszhou4tech@gmail.com>
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnetfilter-log
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libnfnetlink +kmod-nfnetlink-log +libmnl
+  TITLE:=API to receive to-be-logged packets from the kernel nfnetlink_log subsystem
+  URL:=http://www.netfilter.org/projects/libnetfilter_log/
+endef
+
+define Package/libnetfilter-log/description
+ libnetfilter_log is a userspace library providing interface to packets that
+ have been logged by the kernel packet filter. It is is part of a system that
+ deprecates the old syslog/dmesg based packet logging. This library has been
+ previously known as libnfnetlink_log.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared \
+	--without-ipulog \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnetfilter_log
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnetfilter_log/*.h \
+		$(1)/usr/include/libnetfilter_log/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_log.{so*,a,la} \
+		$(1)/usr/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnetfilter_log.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnetfilter-log/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_log.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnetfilter-log))
diff --git a/package/libs/libnetfilter-log/patches/0001-build-remove-unnecessary-pkgconfig-config.status-dep.patch b/package/libs/libnetfilter-log/patches/0001-build-remove-unnecessary-pkgconfig-config.status-dep.patch
new file mode 100644
index 0000000000..c9b325b4da
--- /dev/null
+++ b/package/libs/libnetfilter-log/patches/0001-build-remove-unnecessary-pkgconfig-config.status-dep.patch
@@ -0,0 +1,25 @@
+From 8858b8eacd1385f99796ead78b3a7157c5e93121 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Sun, 24 Jun 2012 14:57:14 +0200
+Subject: [PATCH 1/6] build: remove unnecessary pkgconfig->config.status
+ dependency
+
+The flags obtained from pkgconfig are in essence preprocessor ones.
+
+Signed-off-by: Jan Engelhardt <jengelh@inai.de>
+---
+ Make_global.am |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Make_global.am b/Make_global.am
+index b7dab7b..a4e9bd9 100644
+--- a/Make_global.am
++++ b/Make_global.am
+@@ -1,2 +1,2 @@
+-AM_CPPFLAGS = -I${top_srcdir}/include
+-AM_CFLAGS = -Wall ${LIBNFNETLINK_CFLAGS}
++AM_CPPFLAGS = -I${top_srcdir}/include ${LIBNFNETLINK_CFLAGS}
++AM_CFLAGS = -Wall
+-- 
+1.7.10.4
+
diff --git a/package/libs/libnetfilter-log/patches/0002-build-remove-unused-lines-in-Makefile.am.patch b/package/libs/libnetfilter-log/patches/0002-build-remove-unused-lines-in-Makefile.am.patch
new file mode 100644
index 0000000000..ce47198ff6
--- /dev/null
+++ b/package/libs/libnetfilter-log/patches/0002-build-remove-unused-lines-in-Makefile.am.patch
@@ -0,0 +1,24 @@
+From fee63b81ee432d0b3e03ffcf9f54cda99476f267 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Sun, 24 Jun 2012 14:57:48 +0200
+Subject: [PATCH 2/6] build: remove unused lines in Makefile.am
+
+Signed-off-by: Jan Engelhardt <jengelh@inai.de>
+---
+ Makefile.am |    2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index b758e56..9a1cbcb 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,6 +1,4 @@
+-AM_CPPFLAGS = -I$(top_srcdir)/include
+ SUBDIRS	= include src utils
+-LINKOPTS = -lnfnetlink
+ 
+ ACLOCAL_AMFLAGS = -I m4
+ 
+-- 
+1.7.10.4
+
diff --git a/package/libs/libnetfilter-log/patches/0003-build-resolve-automake-1.12-warnings.patch b/package/libs/libnetfilter-log/patches/0003-build-resolve-automake-1.12-warnings.patch
new file mode 100644
index 0000000000..77cb1b4921
--- /dev/null
+++ b/package/libs/libnetfilter-log/patches/0003-build-resolve-automake-1.12-warnings.patch
@@ -0,0 +1,29 @@
+From 1aa23946431ac593568ccac0e0b6925e7dfd7bd3 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Mon, 8 Oct 2012 15:15:07 +0200
+Subject: [PATCH 3/6] build: resolve automake-1.12 warnings
+
+am/ltlibrary.am: warning: 'libnetfilter_log.la': linking libtool
+libraries using a non-POSIX archiver requires 'AM_PROG_AR' in
+'configure.ac'
+
+Signed-off-by: Jan Engelhardt <jengelh@inai.de>
+---
+ configure.ac |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/configure.ac b/configure.ac
+index fe6e75f..e6e1317 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -7,6 +7,7 @@ AC_CONFIG_MACRO_DIR([m4])
+ 
+ AM_INIT_AUTOMAKE([-Wall foreign subdir-objects
+ 	tar-pax no-dist-gzip dist-bzip2 1.6])
++m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+ 
+ dnl kernel style compile messages
+ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+-- 
+1.7.10.4
+
diff --git a/package/libs/libnetfilter-log/patches/0004-Add-include-needed-for-integer-type-definition.patch b/package/libs/libnetfilter-log/patches/0004-Add-include-needed-for-integer-type-definition.patch
new file mode 100644
index 0000000000..78578750bf
--- /dev/null
+++ b/package/libs/libnetfilter-log/patches/0004-Add-include-needed-for-integer-type-definition.patch
@@ -0,0 +1,24 @@
+From 7529487f70e244cd31ef84b037b1c32749c134a7 Mon Sep 17 00:00:00 2001
+From: Eric Leblond <eric@regit.org>
+Date: Sun, 4 Nov 2012 09:29:44 +0100
+Subject: [PATCH 4/6] Add include needed for integer type definition.
+
+---
+ include/libnetfilter_log/libnetfilter_log.h |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/libnetfilter_log/libnetfilter_log.h b/include/libnetfilter_log/libnetfilter_log.h
+index 6b0d3b0..a1331de 100644
+--- a/include/libnetfilter_log/libnetfilter_log.h
++++ b/include/libnetfilter_log/libnetfilter_log.h
+@@ -9,6 +9,7 @@
+ #ifndef __LIBNETFILTER_LOG_H
+ #define __LIBNETFILTER_LOG_H
+ 
++#include <sys/types.h>
+ #include <libnetfilter_log/linux_nfnetlink_log.h>
+ 
+ struct nflog_handle;
+-- 
+1.7.10.4
+
diff --git a/package/libs/libnetfilter-log/patches/0005-configure-uclinux-is-also-linux.patch b/package/libs/libnetfilter-log/patches/0005-configure-uclinux-is-also-linux.patch
new file mode 100644
index 0000000000..ff78bb3ea1
--- /dev/null
+++ b/package/libs/libnetfilter-log/patches/0005-configure-uclinux-is-also-linux.patch
@@ -0,0 +1,27 @@
+From 2f22d3c4453135c27873b9014e9dc5b5712804df Mon Sep 17 00:00:00 2001
+From: Gustavo Zacarias <gustavo@zacarias.com.ar>
+Date: Tue, 10 Sep 2013 16:23:31 -0300
+Subject: [PATCH 5/6] configure: uclinux is also linux
+
+Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+ configure.ac |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index e6e1317..189a753 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -20,7 +20,7 @@ AC_PROG_INSTALL
+ AC_PROG_LN_S
+ 
+ case "$host" in 
+-*-*-linux*) ;;
++*-*-linux* | *-*-uclinux*) ;;
+ *) AC_MSG_ERROR([Linux only, dude!]);;
+ esac
+ 
+-- 
+1.7.10.4
+
diff --git a/package/libs/libnetfilter-log/patches/0006-configure-add-without-ipulog-option-to-disable-libip.patch b/package/libs/libnetfilter-log/patches/0006-configure-add-without-ipulog-option-to-disable-libip.patch
new file mode 100644
index 0000000000..839f81bbbd
--- /dev/null
+++ b/package/libs/libnetfilter-log/patches/0006-configure-add-without-ipulog-option-to-disable-libip.patch
@@ -0,0 +1,95 @@
+From a1b392b4156db984ab2b695a4a70d113f70cb9b8 Mon Sep 17 00:00:00 2001
+From: Matthieu Crapet <Matthieu.Crapet@ingenico.com>
+Date: Wed, 5 Feb 2014 14:18:57 +0100
+Subject: [PATCH 6/6] configure: add --without-ipulog option to disable
+ libipulog build
+
+This is a compat library used for netfilter ULOG target.
+ULOG only works with IPv4. NFLOG has replaced ULOG.
+
+Signed-off-by: Matthieu Crapet <Matthieu.Crapet@ingenico.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+ configure.ac                         |    5 +++++
+ include/libnetfilter_log/Makefile.am |    5 ++++-
+ src/Makefile.am                      |    6 +++++-
+ utils/Makefile.am                    |    7 +++++--
+ 4 files changed, 19 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 189a753..88ff7ab 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -24,6 +24,11 @@ case "$host" in
+ *) AC_MSG_ERROR([Linux only, dude!]);;
+ esac
+ 
++AC_ARG_WITH([ipulog],
++  AC_HELP_STRING([--without-ipulog], [don't build libipulog compat library]),
++  [ipulog_skip=1], [ipulog_skip=0])
++AM_CONDITIONAL([BUILD_IPULOG], [test $ipulog_skip = 0])
++
+ dnl Dependencies
+ PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 0.0.41])
+ 
+diff --git a/include/libnetfilter_log/Makefile.am b/include/libnetfilter_log/Makefile.am
+index fe934f1..fde1d60 100644
+--- a/include/libnetfilter_log/Makefile.am
++++ b/include/libnetfilter_log/Makefile.am
+@@ -1,3 +1,6 @@
+ 
+-pkginclude_HEADERS = libnetfilter_log.h libipulog.h linux_nfnetlink_log.h
++pkginclude_HEADERS = libnetfilter_log.h linux_nfnetlink_log.h
+ 
++if BUILD_IPULOG
++pkginclude_HEADERS += libipulog.h
++endif
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 10a66e2..33933a4 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -22,14 +22,18 @@ LIBVERSION=2:0:1
+ 
+ include ${top_srcdir}/Make_global.am
+ 
+-lib_LTLIBRARIES = libnetfilter_log.la libnetfilter_log_libipulog.la
++lib_LTLIBRARIES = libnetfilter_log.la
+ 
+ libnetfilter_log_la_LDFLAGS = -Wc,-nostartfiles -lnfnetlink	\
+ 			      -version-info $(LIBVERSION)
+ libnetfilter_log_la_SOURCES = libnetfilter_log.c 
+ libnetfilter_log_la_LIBADD  = ${LIBNFNETLINK_LIBS}
+ 
++if BUILD_IPULOG
++lib_LTLIBRARIES += libnetfilter_log_libipulog.la
++
+ libnetfilter_log_libipulog_la_LDFLAGS = -Wc,-nostartfiles	\
+ 					-version-info 1:0:0
+ libnetfilter_log_libipulog_la_LIBADD = libnetfilter_log.la
+ libnetfilter_log_libipulog_la_SOURCES = libipulog_compat.c
++endif
+diff --git a/utils/Makefile.am b/utils/Makefile.am
+index ae64c90..f961b6c 100644
+--- a/utils/Makefile.am
++++ b/utils/Makefile.am
+@@ -1,12 +1,15 @@
+ include ${top_srcdir}/Make_global.am
+ 
+-check_PROGRAMS = nfulnl_test ulog_test
++check_PROGRAMS = nfulnl_test
+ 
+ nfulnl_test_SOURCES = nfulnl_test.c
+ nfulnl_test_LDADD = ../src/libnetfilter_log.la
+ nfulnl_test_LDFLAGS = -dynamic
+ 
++if BUILD_IPULOG
++check_PROGRAMS += ulog_test
++
+ ulog_test_SOURCES = ulog_test.c
+ ulog_test_LDADD = ../src/libnetfilter_log_libipulog.la ../src/libnetfilter_log.la
+ ulog_test_LDFLAGS = -dynamic
+-
++endif
+-- 
+1.7.10.4
+
diff --git a/package/libs/libnetfilter-queue/Makefile b/package/libs/libnetfilter-queue/Makefile
new file mode 100644
index 0000000000..fb54c86e5d
--- /dev/null
+++ b/package/libs/libnetfilter-queue/Makefile
@@ -0,0 +1,71 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnetfilter_queue
+PKG_VERSION:=2016-07-03
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=http://git.netfilter.org/libnetfilter_queue
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=981025e103d887fb6a9c9bb49c74ec323108d098
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnetfilter-queue
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libmnl +libnfnetlink
+  TITLE:=API to the in-kernel connection tracking queue infrastructure
+  URL:=http://www.netfilter.org/projects/libnetfilter_queue/
+endef
+
+define Package/libnetfilter-queue/description
+ libnetfilter_queue is a userspace library providing a programming
+ interface (API) to the in-kernel connection tracking state table.
+ This library is currently used by conntrack-tools.
+endef
+
+TARGET_CFLAGS += $(FPIC) -D_GNU_SOURCE=1
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnetfilter_queue
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnetfilter_queue/*.h \
+		$(1)/usr/include/libnetfilter_queue/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_queue.{so*,a,la} \
+		$(1)/usr/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnetfilter_queue.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnetfilter-queue/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnetfilter_queue.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnetfilter-queue))
diff --git a/package/libs/libnetfilter-queue/patches/100-checksum_computation.patch b/package/libs/libnetfilter-queue/patches/100-checksum_computation.patch
new file mode 100644
index 0000000000..81faffe82e
--- /dev/null
+++ b/package/libs/libnetfilter-queue/patches/100-checksum_computation.patch
@@ -0,0 +1,115 @@
+--- a/src/extra/checksum.c
++++ b/src/extra/checksum.c
+@@ -11,6 +11,7 @@
+ 
+ #include <stdio.h>
+ #include <stdbool.h>
++#include <endian.h>
+ #include <arpa/inet.h>
+ #include <netinet/ip.h>
+ #include <netinet/ip6.h>
+@@ -26,8 +27,13 @@ uint16_t nfq_checksum(uint32_t sum, uint16_t *buf, int size)
+ 		sum += *buf++;
+ 		size -= sizeof(uint16_t);
+ 	}
+-	if (size)
+-		sum += *(uint8_t *)buf;
++	if (size) {
++#if __BYTE_ORDER == __BIG_ENDIAN
++		sum += (uint16_t)*(uint8_t *)buf << 8;
++#else
++		sum += (uint16_t)*(uint8_t *)buf;
++#endif
++	}
+ 
+ 	sum = (sum >> 16) + (sum & 0xffff);
+ 	sum += (sum >>16);
+@@ -35,7 +41,7 @@ uint16_t nfq_checksum(uint32_t sum, uint16_t *buf, int size)
+ 	return (uint16_t)(~sum);
+ }
+ 
+-uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph)
++uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph, uint16_t protocol_id)
+ {
+ 	uint32_t sum = 0;
+ 	uint32_t iph_len = iph->ihl*4;
+@@ -46,13 +52,13 @@ uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph)
+ 	sum += (iph->saddr) & 0xFFFF;
+ 	sum += (iph->daddr >> 16) & 0xFFFF;
+ 	sum += (iph->daddr) & 0xFFFF;
+-	sum += htons(IPPROTO_TCP);
++	sum += htons(protocol_id);
+ 	sum += htons(len);
+ 
+ 	return nfq_checksum(sum, (uint16_t *)payload, len);
+ }
+ 
+-uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr)
++uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr, uint16_t protocol_id)
+ {
+ 	uint32_t sum = 0;
+ 	uint32_t hdr_len = (uint32_t *)transport_hdr - (uint32_t *)ip6h;
+@@ -68,7 +74,7 @@ uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr)
+ 		sum += (ip6h->ip6_dst.s6_addr16[i] >> 16) & 0xFFFF;
+ 		sum += (ip6h->ip6_dst.s6_addr16[i]) & 0xFFFF;
+ 	}
+-	sum += htons(IPPROTO_TCP);
++	sum += htons(protocol_id);
+ 	sum += htons(ip6h->ip6_plen);
+ 
+ 	return nfq_checksum(sum, (uint16_t *)payload, len);
+diff --git a/src/extra/tcp.c b/src/extra/tcp.c
+index d1cd79d..a66f392 100644
+--- a/src/extra/tcp.c
++++ b/src/extra/tcp.c
+@@ -96,7 +96,7 @@ nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
+ {
+ 	/* checksum field in header needs to be zero for calculation. */
+ 	tcph->check = 0;
+-	tcph->check = nfq_checksum_tcpudp_ipv4(iph);
++	tcph->check = nfq_checksum_tcpudp_ipv4(iph, IPPROTO_TCP);
+ }
+ EXPORT_SYMBOL(nfq_tcp_compute_checksum_ipv4);
+ 
+@@ -110,7 +110,7 @@ nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
+ {
+ 	/* checksum field in header needs to be zero for calculation. */
+ 	tcph->check = 0;
+-	tcph->check = nfq_checksum_tcpudp_ipv6(ip6h, tcph);
++	tcph->check = nfq_checksum_tcpudp_ipv6(ip6h, tcph, IPPROTO_TCP);
+ }
+ EXPORT_SYMBOL(nfq_tcp_compute_checksum_ipv6);
+ 
+--- a/src/extra/udp.c
++++ b/src/extra/udp.c
+@@ -96,7 +96,7 @@ nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph)
+ {
+ 	/* checksum field in header needs to be zero for calculation. */
+ 	udph->check = 0;
+-	udph->check = nfq_checksum_tcpudp_ipv4(iph);
++	udph->check = nfq_checksum_tcpudp_ipv4(iph, IPPROTO_UDP);
+ }
+ EXPORT_SYMBOL(nfq_udp_compute_checksum_ipv4);
+ 
+@@ -115,7 +115,7 @@ nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h)
+ {
+ 	/* checksum field in header needs to be zero for calculation. */
+ 	udph->check = 0;
+-	udph->check = nfq_checksum_tcpudp_ipv6(ip6h, udph);
++	udph->check = nfq_checksum_tcpudp_ipv6(ip6h, udph, IPPROTO_UDP);
+ }
+ EXPORT_SYMBOL(nfq_udp_compute_checksum_ipv6);
+ 
+--- a/src/internal.h
++++ b/src/internal.h
+@@ -15,8 +15,8 @@ struct iphdr;
+ struct ip6_hdr;
+ 
+ uint16_t nfq_checksum(uint32_t sum, uint16_t *buf, int size);
+-uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph);
+-uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr);
++uint16_t nfq_checksum_tcpudp_ipv4(struct iphdr *iph, uint16_t protocol_id);
++uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr, uint16_t protocol_id);
+ 
+ struct pkt_buff {
+ 	uint8_t *mac_header;
diff --git a/package/libs/libnfnetlink/Makefile b/package/libs/libnfnetlink/Makefile
new file mode 100644
index 0000000000..6f4974f66d
--- /dev/null
+++ b/package/libs/libnfnetlink/Makefile
@@ -0,0 +1,71 @@
+#
+# Copyright (C) 2007-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnfnetlink
+PKG_VERSION:=1.0.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/libnfnetlink/files/ \
+	ftp://ftp.netfilter.org/pub/libnfnetlink/ \
+	http://mirrors.evolva.ro/netfilter.org/libnfnetlink/
+PKG_MD5SUM:=98927583d2016a9fb1936fed992e2c5e
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0+
+
+PKG_FIXUP:=autoreconf
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnfnetlink
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=A low-level library for netfilter related kernel/userspace communication
+  URL:=http://netfilter.org/projects/libnfnetlink/
+endef
+
+define Package/libnfnetlink/description
+ libnfnetlink is is the low-level library for netfilter related kernel/userspace communication.
+ It provides a generic messaging infrastructure for in-kernel netfilter subsystems
+ (such as nfnetlink_log, nfnetlink_queue, nfnetlink_conntrack) and their respective users
+ and/or management tools in userspace.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnfnetlink
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnfnetlink/{libnfnetlink,linux_nfnetlink,linux_nfnetlink_compat}.h \
+		$(1)/usr/include/libnfnetlink/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnfnetlink.{a,so*} \
+		$(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnfnetlink.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnfnetlink/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnfnetlink.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnfnetlink))
diff --git a/package/libs/libnfnetlink/patches/100-missing_include.patch b/package/libs/libnfnetlink/patches/100-missing_include.patch
new file mode 100644
index 0000000000..163307d895
--- /dev/null
+++ b/package/libs/libnfnetlink/patches/100-missing_include.patch
@@ -0,0 +1,20 @@
+--- a/include/libnfnetlink/libnfnetlink.h
++++ b/include/libnfnetlink/libnfnetlink.h
+@@ -15,6 +15,7 @@
+ #define aligned_u64 unsigned long long __attribute__((aligned(8)))
+ #endif
+ 
++#include <sys/types.h>
+ #include <sys/socket.h>	/* for sa_family_t */
+ #include <linux/netlink.h>
+ #include <libnfnetlink/linux_nfnetlink.h>
+--- a/include/libnfnetlink/linux_nfnetlink.h
++++ b/include/libnfnetlink/linux_nfnetlink.h
+@@ -1,6 +1,6 @@
+ #ifndef _NFNETLINK_H
+ #define _NFNETLINK_H
+-#include <linux/types.h>
++#include <sys/types.h>
+ #include <libnfnetlink/linux_nfnetlink_compat.h>
+ 
+ enum nfnetlink_groups {
diff --git a/package/libs/libnftnl/Makefile b/package/libs/libnftnl/Makefile
new file mode 100644
index 0000000000..be9500e423
--- /dev/null
+++ b/package/libs/libnftnl/Makefile
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnftnl
+PKG_VERSION:=1.0.6
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL:=git://git.netfilter.org/libnftnl
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=libnftnl-1.0.6
+PKG_MIRROR_MD5SUM:=c9e066e3fd29951cbe96d2898b4d6cdcfe802b3a4f09f8273a508e7a0a20a357
+PKG_MAINTAINER:=Steven Barth <steven@midlink.org>
+PKG_LICENSE:=GPL-2.0+
+
+PKG_FIXUP:=autoreconf
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnftnl
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libmnl
+  TITLE:=Low-level netlink library for the nf_tables subsystem
+  URL:=http://www.netfilter.org/projects/libnftnl
+endef
+
+define Package/libnftnl/description
+ libnftnl is a userspace library providing a low-level netlink
+ programming interface (API) to the in-kernel nf_tables subsystem.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-static \
+	--enable-shared \
+	--without-json-parsing \
+	--without-xml-parsing \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnftnl
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include/libnftnl/*.h \
+		$(1)/usr/include/libnftnl/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnftnl.{so*,a,la} \
+		$(1)/usr/lib/
+
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libnftnl.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnftnl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libnftnl.so.* \
+		$(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnftnl))
diff --git a/package/libs/libnl-tiny/Makefile b/package/libs/libnl-tiny/Makefile
new file mode 100644
index 0000000000..cabbb08421
--- /dev/null
+++ b/package/libs/libnl-tiny/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnl-tiny
+PKG_VERSION:=0.1
+PKG_RELEASE:=5
+
+PKG_LICENSE:=LGPL-2.1
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnl-tiny
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=netlink socket library
+endef
+
+define Package/libnl-tiny/description
+ This package contains a stripped down version of libnl
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		CFLAGS="$(TARGET_CFLAGS)" \
+		all
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig $(1)/usr/include/libnl-tiny
+	$(CP) $(PKG_BUILD_DIR)/include/* $(1)/usr/include/libnl-tiny
+	$(CP) $(PKG_BUILD_DIR)/libnl-tiny.so $(1)/usr/lib/
+	$(CP) ./files/libnl-tiny.pc $(1)/usr/lib/pkgconfig
+endef
+
+define Package/libnl-tiny/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libnl-tiny.so $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnl-tiny))
diff --git a/package/libs/libnl-tiny/files/libnl-tiny.pc b/package/libs/libnl-tiny/files/libnl-tiny.pc
new file mode 100644
index 0000000000..af79cd301e
--- /dev/null
+++ b/package/libs/libnl-tiny/files/libnl-tiny.pc
@@ -0,0 +1,10 @@
+prefix=/usr
+exec_prefix=/usr
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/libnl-tiny
+
+Name: libnl-tiny
+Description: Convenience library for netlink sockets
+Version: 2.0
+Libs: -L${libdir} -lnl-tiny
+Cflags: -I${includedir}
diff --git a/package/libs/libnl-tiny/src/Makefile b/package/libs/libnl-tiny/src/Makefile
new file mode 100644
index 0000000000..6f37160a8c
--- /dev/null
+++ b/package/libs/libnl-tiny/src/Makefile
@@ -0,0 +1,17 @@
+CC=gcc
+WFLAGS=-Wall
+CFLAGS=-O2
+INCLUDES=-Iinclude
+
+LIBNAME=libnl-tiny.so
+
+all: $(LIBNAME)
+
+%.o: %.c
+	$(CC) $(WFLAGS) -c -o $@ $(INCLUDES) $(CFLAGS) $<
+
+LIBNL_OBJ=nl.o handlers.o msg.o attr.o cache.o cache_mngt.o object.o socket.o error.o
+GENL_OBJ=genl.o genl_family.o genl_ctrl.o genl_mngt.o unl.o
+
+$(LIBNAME): $(LIBNL_OBJ) $(GENL_OBJ)
+	$(CC) $(CFLAGS) -Wl,-Bsymbolic-functions -shared -o $@ $^
diff --git a/package/libs/libnl-tiny/src/attr.c b/package/libs/libnl-tiny/src/attr.c
new file mode 100644
index 0000000000..e0f50611cf
--- /dev/null
+++ b/package/libs/libnl-tiny/src/attr.c
@@ -0,0 +1,668 @@
+/*
+ * lib/attr.c		Netlink Attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <netlink/attr.h>
+#include <netlink/msg.h>
+#include <linux/socket.h>
+
+/**
+ * @ingroup msg
+ * @defgroup attr Attributes
+ * Netlink Attributes Construction/Parsing Interface
+ *
+ * \section attr_sec Netlink Attributes
+ * Netlink attributes allow for data chunks of arbitary length to be
+ * attached to a netlink message. Each attribute is encoded with a
+ * type and length field, both 16 bits, stored in the attribute header
+ * preceding the attribute data. The main advantage of using attributes
+ * over packing everything into the family header is that the interface
+ * stays extendable as new attributes can supersede old attributes while
+ * remaining backwards compatible. Also attributes can be defined optional
+ * thus avoiding the transmission of unnecessary empty data blocks.
+ * Special nested attributes allow for more complex data structures to
+ * be transmitted, e.g. trees, lists, etc.
+ *
+ * While not required, netlink attributes typically follow the family
+ * header of a netlink message and must be properly aligned to NLA_ALIGNTO:
+ * @code
+ *   +----------------+- - -+---------------+- - -+------------+- - -+
+ *   | Netlink Header | Pad | Family Header | Pad | Attributes | Pad |
+ *   +----------------+- - -+---------------+- - -+------------+- - -+
+ * @endcode
+ *
+ * The actual attributes are chained together each separately aligned to
+ * NLA_ALIGNTO. The position of an attribute is defined based on the
+ * length field of the preceding attributes:
+ * @code
+ *   +-------------+- - -+-------------+- - -+------
+ *   | Attribute 1 | Pad | Attribute 2 | Pad | ...
+ *   +-------------+- - -+-------------+- - -+------
+ *   nla_next(attr1)------^
+ * @endcode
+ *
+ * The attribute itself consists of the attribute header followed by
+ * the actual payload also aligned to NLA_ALIGNTO. The function nla_data()
+ * returns a pointer to the start of the payload while nla_len() returns
+ * the length of the payload in bytes.
+ *
+ * \b Note: Be aware, NLA_ALIGNTO equals to 4 bytes, therefore it is not
+ * safe to dereference any 64 bit data types directly.
+ *
+ * @code
+ *    <----------- nla_total_size(payload) ----------->
+ *    <-------- nla_attr_size(payload) --------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   nla_data(nla)-------------^
+ *                             <- nla_len(nla) ->
+ * @endcode
+ *
+ * @subsection attr_datatypes Attribute Data Types
+ * A number of basic data types are supported to simplify access and
+ * validation of netlink attributes. This data type information is
+ * not encoded in the attribute, both the kernel and userspace part
+ * are required to share this information on their own.
+ *
+ * One of the major advantages of these basic types is the automatic
+ * validation of each attribute based on an attribute policy. The
+ * validation covers most of the checks required to safely use
+ * attributes and thus keeps the individual sanity check to a minimum.
+ *
+ * Never access attribute payload without ensuring basic validation
+ * first, attributes may:
+ * - not be present even though required
+ * - contain less actual payload than expected
+ * - fake a attribute length which exceeds the end of the message
+ * - contain unterminated character strings
+ *
+ * Policies are defined as array of the struct nla_policy. The array is
+ * indexed with the attribute type, therefore the array must be sized
+ * accordingly.
+ * @code
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ * 	[ATTR_FOO] = { .type = ..., .minlen = ..., .maxlen = ... },
+ * };
+ *
+ * err = nla_validate(attrs, attrlen, ATTR_MAX, &my_policy);
+ * @endcode
+ *
+ * Some basic validations are performed on every attribute, regardless of type.
+ * - If the attribute type exceeds the maximum attribute type specified or
+ *   the attribute type is lesser-or-equal than zero, the attribute will
+ *   be silently ignored.
+ * - If the payload length falls below the \a minlen value the attribute
+ *   will be rejected.
+ * - If \a maxlen is non-zero and the payload length exceeds the \a maxlen
+ *   value the attribute will be rejected.
+ *
+ *
+ * @par Unspecific Attribute (NLA_UNSPEC)
+ * This is the standard type if no type is specified. It is used for
+ * binary data of arbitary length. Typically this attribute carries
+ * a binary structure or a stream of bytes.
+ * @par
+ * @code
+ * // In this example, we will assume a binary structure requires to
+ * // be transmitted. The definition of the structure will typically
+ * // go into a header file available to both the kernel and userspace
+ * // side.
+ * //
+ * // Note: Be careful when putting 64 bit data types into a structure.
+ * // The attribute payload is only aligned to 4 bytes, dereferencing
+ * // the member may fail.
+ * struct my_struct {
+ *     int a;
+ *     int b;
+ * };
+ *
+ * // The validation function will not enforce an exact length match to
+ * // allow structures to grow as required. Note: While it is allowed
+ * // to add members to the end of the structure, changing the order or
+ * // inserting members in the middle of the structure will break your
+ * // binary interface.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_MY_STRICT] = { .type = NLA_UNSPEC,
+ *                          .minlen = sizeof(struct my_struct) },
+ *
+ * // The binary structure is appened to the message using nla_put()
+ * struct my_struct foo = { .a = 1, .b = 2 };
+ * nla_put(msg, ATTR_MY_STRUCT, sizeof(foo), &foo);
+ *
+ * // On the receiving side, a pointer to the structure pointing inside
+ * // the message payload is returned by nla_get().
+ * if (attrs[ATTR_MY_STRUCT])
+ *     struct my_struct *foo = nla_get(attrs[ATTR_MY_STRUCT]);
+ * @endcode
+ *
+ * @par Integers (NLA_U8, NLA_U16, NLA_U32, NLA_U64)
+ * Integers come in different sizes from 8 bit to 64 bit. However, since the
+ * payload length is aligned to 4 bytes, integers smaller than 32 bit are
+ * only useful to enforce the maximum range of values.
+ * @par
+ * \b Note: There is no difference made between signed and unsigned integers.
+ * The validation only enforces the minimal payload length required to store
+ * an integer of specified type.
+ * @par
+ * @code
+ * // Even though possible, it does not make sense to specify .minlen or
+ * // .maxlen for integer types. The data types implies the corresponding
+ * // minimal payload length.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_FOO] = { .type = NLA_U32 },
+ *
+ * // Numeric values can be appended directly using the respective
+ * // nla_put_uxxx() function
+ * nla_put_u32(msg, ATTR_FOO, 123);
+ *
+ * // Same for the receiving side.
+ * if (attrs[ATTR_FOO])
+ *     uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
+ * @endcode
+ *
+ * @par Character string (NLA_STRING)
+ * This data type represents a NUL terminated character string of variable
+ * length. For binary data streams the type NLA_UNSPEC is recommended.
+ * @par
+ * @code
+ * // Enforce a NUL terminated character string of at most 4 characters
+ * // including the NUL termination.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_BAR] = { .type = NLA_STRING, maxlen = 4 },
+ *
+ * // nla_put_string() creates a string attribute of the necessary length
+ * // and appends it to the message including the NUL termination.
+ * nla_put_string(msg, ATTR_BAR, "some text");
+ *
+ * // It is safe to use the returned character string directly if the
+ * // attribute has been validated as the validation enforces the proper
+ * // termination of the string.
+ * if (attrs[ATTR_BAR])
+ *     char *text = nla_get_string(attrs[ATTR_BAR]);
+ * @endcode
+ *
+ * @par Flag (NLA_FLAG)
+ * This attribute type may be used to indicate the presence of a flag. The
+ * attribute is only valid if the payload length is zero. The presence of
+ * the attribute header indicates the presence of the flag.
+ * @par
+ * @code
+ * // This attribute type is special as .minlen and .maxlen have no effect.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_FLAG] = { .type = NLA_FLAG },
+ *
+ * // nla_put_flag() appends a zero sized attribute to the message.
+ * nla_put_flag(msg, ATTR_FLAG);
+ *
+ * // There is no need for a receival function, the presence is the value.
+ * if (attrs[ATTR_FLAG])
+ *     // flag is present
+ * @endcode
+ *
+ * @par Micro Seconds (NLA_MSECS)
+ *
+ * @par Nested Attribute (NLA_NESTED)
+ * Attributes can be nested and put into a container to create groups, lists
+ * or to construct trees of attributes. Nested attributes are often used to
+ * pass attributes to a subsystem where the top layer has no knowledge of the
+ * configuration possibilities of each subsystem.
+ * @par
+ * \b Note: When validating the attributes using nlmsg_validate() or
+ * nlmsg_parse() it will only affect the top level attributes. Each
+ * level of nested attributes must be validated seperately using
+ * nla_parse_nested() or nla_validate().
+ * @par
+ * @code
+ * // The minimal length policy may be used to enforce the presence of at
+ * // least one attribute.
+ * static struct nla_policy my_policy[ATTR_MAX+1] = {
+ *     [ATTR_OPTS] = { .type = NLA_NESTED, minlen = NLA_HDRLEN },
+ *
+ * // Nested attributes are constructed by enclosing the attributes
+ * // to be nested with calls to nla_nest_start() respetively nla_nest_end().
+ * struct nlattr *opts = nla_nest_start(msg, ATTR_OPTS);
+ * nla_put_u32(msg, ATTR_FOO, 123);
+ * nla_put_string(msg, ATTR_BAR, "some text");
+ * nla_nest_end(msg, opts);
+ *
+ * // Various methods exist to parse nested attributes, the easiest being
+ * // nla_parse_nested() which also allows validation in the same step.
+ * if (attrs[ATTR_OPTS]) {
+ *     struct nlattr *nested[ATTR_MAX+1];
+ *
+ *     nla_parse_nested(nested, ATTR_MAX, attrs[ATTR_OPTS], &policy);
+ *
+ *     if (nested[ATTR_FOO])
+ *         uint32_t foo = nla_get_u32(nested[ATTR_FOO]);
+ * }
+ * @endcode
+ *
+ * @subsection attr_exceptions Exception Based Attribute Construction
+ * Often a large number of attributes are added to a message in a single
+ * function. In order to simplify error handling, a second set of
+ * construction functions exist which jump to a error label when they
+ * fail instead of returning an error code. This second set consists
+ * of macros which are named after their error code based counterpart
+ * except that the name is written all uppercase.
+ *
+ * All of the macros jump to the target \c nla_put_failure if they fail.
+ * @code
+ * void my_func(struct nl_msg *msg)
+ * {
+ *     NLA_PUT_U32(msg, ATTR_FOO, 10);
+ *     NLA_PUT_STRING(msg, ATTR_BAR, "bar");
+ *
+ *     return 0;
+ *
+ * nla_put_failure:
+ *     return -NLE_NOMEM;
+ * }
+ * @endcode
+ *
+ * @subsection attr_examples Examples
+ * @par Example 1.1 Constructing a netlink message with attributes.
+ * @code
+ * struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu)
+ * {
+ *     struct nl_msg *msg;
+ *     struct nlattr *info, *vlan;
+ *     struct ifinfomsg ifi = {
+ *         .ifi_family = AF_INET,
+ *         .ifi_index = ifindex,
+ *     };
+ *
+ *     // Allocate a new netlink message, type=RTM_SETLINK, flags=NLM_F_ECHO
+ *     if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_ECHO)))
+ *         return NULL;
+ *
+ *     // Append the family specific header (struct ifinfomsg)
+ *     if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+ *         goto nla_put_failure
+ *
+ *     // Append a 32 bit integer attribute to carry the MTU
+ *     NLA_PUT_U32(msg, IFLA_MTU, mtu);
+ *
+ *     // Append a unspecific attribute to carry the link layer address
+ *     NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr);
+ *
+ *     // Append a container for nested attributes to carry link information
+ *     if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
+ *         goto nla_put_failure;
+ *
+ *     // Put a string attribute into the container
+ *     NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan");
+ *
+ *     // Append another container inside the open container to carry
+ *     // vlan specific attributes
+ *     if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA)))
+ *         goto nla_put_failure;
+ *
+ *     // add vlan specific info attributes here...
+ *
+ *     // Finish nesting the vlan attributes and close the second container.
+ *     nla_nest_end(msg, vlan);
+ *
+ *     // Finish nesting the link info attribute and close the first container.
+ *     nla_nest_end(msg, info);
+ *
+ *     return msg;
+ *
+ * // If any of the construction macros fails, we end up here.
+ * nla_put_failure:
+ *     nlmsg_free(msg);
+ *     return NULL;
+ * }
+ * @endcode
+ *
+ * @par Example 2.1 Parsing a netlink message with attributes.
+ * @code
+ * int parse_message(struct nl_msg *msg)
+ * {
+ *     // The policy defines two attributes: a 32 bit integer and a container
+ *     // for nested attributes.
+ *     struct nla_policy attr_policy[ATTR_MAX+1] = {
+ *         [ATTR_FOO] = { .type = NLA_U32 },
+ *         [ATTR_BAR] = { .type = NLA_NESTED },
+ *     };
+ *     struct nlattr *attrs[ATTR_MAX+1];
+ *     int err;
+ *
+ *     // The nlmsg_parse() function will make sure that the message contains
+ *     // enough payload to hold the header (struct my_hdr), validates any
+ *     // attributes attached to the messages and stores a pointer to each
+ *     // attribute in the attrs[] array accessable by attribute type.
+ *     if ((err = nlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs,
+ *                            ATTR_MAX, attr_policy)) < 0)
+ *         goto errout;
+ *
+ *     if (attrs[ATTR_FOO]) {
+ *         // It is safe to directly access the attribute payload without
+ *         // any further checks since nlmsg_parse() enforced the policy.
+ *         uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
+ *     }
+ *
+ *     if (attrs[ATTR_BAR]) {
+ *         struct nlattr *nested[NESTED_MAX+1];
+ *
+ *         // Attributes nested in a container can be parsed the same way
+ *         // as top level attributes.
+ *         if ((err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR],
+ *                                     nested_policy)) < 0)
+ *             goto errout;
+ *
+ *         // Process nested attributes here.
+ *     }
+ *
+ *     err = 0;
+ * errout:
+ *     return err;
+ * }
+ * @endcode
+ *
+ * @{
+ */
+
+/**
+ * @name Attribute Size Calculation
+ * @{
+ */
+
+/** @} */
+
+/**
+ * @name Parsing Attributes
+ * @{
+ */
+
+/**
+ * Check if the attribute header and payload can be accessed safely.
+ * @arg nla		Attribute of any kind.
+ * @arg remaining	Number of bytes remaining in attribute stream.
+ *
+ * Verifies that the header and payload do not exceed the number of
+ * bytes left in the attribute stream. This function must be called
+ * before access the attribute header or payload when iterating over
+ * the attribute stream using nla_next().
+ *
+ * @return True if the attribute can be accessed safely, false otherwise.
+ */
+int nla_ok(const struct nlattr *nla, int remaining)
+{
+	return remaining >= sizeof(*nla) &&
+	       nla->nla_len >= sizeof(*nla) &&
+	       nla->nla_len <= remaining;
+}
+
+/**
+ * Return next attribute in a stream of attributes.
+ * @arg nla		Attribute of any kind.
+ * @arg remaining	Variable to count remaining bytes in stream.
+ *
+ * Calculates the offset to the next attribute based on the attribute
+ * given. The attribute provided is assumed to be accessible, the
+ * caller is responsible to use nla_ok() beforehand. The offset (length
+ * of specified attribute including padding) is then subtracted from
+ * the remaining bytes variable and a pointer to the next attribute is
+ * returned.
+ *
+ * nla_next() can be called as long as remainig is >0.
+ *
+ * @return Pointer to next attribute.
+ */
+struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+	int totlen = NLA_ALIGN(nla->nla_len);
+
+	*remaining -= totlen;
+	return (struct nlattr *) ((char *) nla + totlen);
+}
+
+static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
+	[NLA_U8]	= sizeof(uint8_t),
+	[NLA_U16]	= sizeof(uint16_t),
+	[NLA_U32]	= sizeof(uint32_t),
+	[NLA_U64]	= sizeof(uint64_t),
+	[NLA_STRING]	= 1,
+};
+
+static int validate_nla(struct nlattr *nla, int maxtype,
+			struct nla_policy *policy)
+{
+	struct nla_policy *pt;
+	int minlen = 0, type = nla_type(nla);
+
+	if (type <= 0 || type > maxtype)
+		return 0;
+
+	pt = &policy[type];
+
+	if (pt->type > NLA_TYPE_MAX)
+		BUG();
+
+	if (pt->minlen)
+		minlen = pt->minlen;
+	else if (pt->type != NLA_UNSPEC)
+		minlen = nla_attr_minlen[pt->type];
+
+	if (pt->type == NLA_FLAG && nla_len(nla) > 0)
+		return -NLE_RANGE;
+
+	if (nla_len(nla) < minlen)
+		return -NLE_RANGE;
+
+	if (pt->maxlen && nla_len(nla) > pt->maxlen)
+		return -NLE_RANGE;
+
+	if (pt->type == NLA_STRING) {
+		char *data = nla_data(nla);
+		if (data[nla_len(nla) - 1] != '\0')
+			return -NLE_INVAL;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Create attribute index based on a stream of attributes.
+ * @arg tb		Index array to be filled (maxtype+1 elements).
+ * @arg maxtype		Maximum attribute type expected and accepted.
+ * @arg head		Head of attribute stream.
+ * @arg len		Length of attribute stream.
+ * @arg policy		Attribute validation policy.
+ *
+ * Iterates over the stream of attributes and stores a pointer to each
+ * attribute in the index array using the attribute type as index to
+ * the array. Attribute with a type greater than the maximum type
+ * specified will be silently ignored in order to maintain backwards
+ * compatibility. If \a policy is not NULL, the attribute will be
+ * validated using the specified policy.
+ *
+ * @see nla_validate
+ * @return 0 on success or a negative error code.
+ */
+int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+	      struct nla_policy *policy)
+{
+	struct nlattr *nla;
+	int rem, err;
+
+	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+	nla_for_each_attr(nla, head, len, rem) {
+		int type = nla_type(nla);
+
+		if (type == 0) {
+			fprintf(stderr, "Illegal nla->nla_type == 0\n");
+			continue;
+		}
+
+		if (type <= maxtype) {
+			if (policy) {
+				err = validate_nla(nla, maxtype, policy);
+				if (err < 0)
+					goto errout;
+			}
+
+			tb[type] = nla;
+		}
+	}
+
+	if (rem > 0)
+		fprintf(stderr, "netlink: %d bytes leftover after parsing "
+		       "attributes.\n", rem);
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * Validate a stream of attributes.
+ * @arg head		Head of attributes stream.
+ * @arg len		Length of attributes stream.
+ * @arg maxtype		Maximum attribute type expected and accepted.
+ * @arg policy		Validation policy.
+ *
+ * Iterates over the stream of attributes and validates each attribute
+ * one by one using the specified policy. Attributes with a type greater
+ * than the maximum type specified will be silently ignored in order to
+ * maintain backwards compatibility.
+ *
+ * See \ref attr_datatypes for more details on what kind of validation
+ * checks are performed on each attribute data type.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nla_validate(struct nlattr *head, int len, int maxtype,
+		 struct nla_policy *policy)
+{
+	struct nlattr *nla;
+	int rem, err;
+
+	nla_for_each_attr(nla, head, len, rem) {
+		err = validate_nla(nla, maxtype, policy);
+		if (err < 0)
+			goto errout;
+	}
+
+	err = 0;
+errout:
+	return err;
+}
+
+/**
+ * Find a single attribute in a stream of attributes.
+ * @arg head		Head of attributes stream.
+ * @arg len		Length of attributes stream.
+ * @arg attrtype	Attribute type to look for.
+ *
+ * Iterates over the stream of attributes and compares each type with
+ * the type specified. Returns the first attribute which matches the
+ * type.
+ *
+ * @return Pointer to attribute found or NULL.
+ */
+struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
+{
+	struct nlattr *nla;
+	int rem;
+
+	nla_for_each_attr(nla, head, len, rem)
+		if (nla_type(nla) == attrtype)
+			return nla;
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Unspecific Attribute
+ * @{
+ */
+
+/**
+ * Reserve space for a attribute.
+ * @arg msg		Netlink Message.
+ * @arg attrtype	Attribute Type.
+ * @arg attrlen		Length of payload.
+ *
+ * Reserves room for a attribute in the specified netlink message and
+ * fills in the attribute header (type, length). Returns NULL if there
+ * is unsuficient space for the attribute.
+ *
+ * Any padding between payload and the start of the next attribute is
+ * zeroed out.
+ *
+ * @return Pointer to start of attribute or NULL on failure.
+ */
+struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
+{
+	struct nlattr *nla;
+	int tlen;
+	
+	tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
+
+	if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size)
+		return NULL;
+
+	nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+	nla->nla_type = attrtype;
+	nla->nla_len = nla_attr_size(attrlen);
+
+	memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
+	msg->nm_nlh->nlmsg_len = tlen;
+
+	NL_DBG(2, "msg %p: Reserved %d bytes at offset +%td for attr %d "
+		  "nlmsg_len=%d\n", msg, attrlen,
+		  (void *) nla - nlmsg_data(msg->nm_nlh),
+		  attrtype, msg->nm_nlh->nlmsg_len);
+
+	return nla;
+}
+
+/**
+ * Add a unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg datalen		Length of data to be used as payload.
+ * @arg data		Pointer to data to be used as attribute payload.
+ *
+ * Reserves room for a unspecific attribute and copies the provided data
+ * into the message as payload of the attribute. Returns an error if there
+ * is insufficient space for the attribute.
+ *
+ * @see nla_reserve
+ * @return 0 on success or a negative error code.
+ */
+int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
+{
+	struct nlattr *nla;
+
+	nla = nla_reserve(msg, attrtype, datalen);
+	if (!nla)
+		return -NLE_NOMEM;
+
+	memcpy(nla_data(nla), data, datalen);
+	NL_DBG(2, "msg %p: Wrote %d bytes at offset +%td for attr %d\n",
+	       msg, datalen, (void *) nla - nlmsg_data(msg->nm_nlh), attrtype);
+
+	return 0;
+}
+
+
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/cache.c b/package/libs/libnl-tiny/src/cache.c
new file mode 100644
index 0000000000..56a1280b53
--- /dev/null
+++ b/package/libs/libnl-tiny/src/cache.c
@@ -0,0 +1,376 @@
+/*
+ * lib/cache.c		Caching Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cache_mngt
+ * @defgroup cache Cache
+ *
+ * @code
+ *   Cache Management             |    | Type Specific Cache Operations
+ *                                      
+ *                                |    | +----------------+ +------------+
+ *                                       | request update | | msg_parser |
+ *                                |    | +----------------+ +------------+
+ *                                     +- - - - -^- - - - - - - -^- -|- - - -
+ *    nl_cache_update:            |              |               |   |
+ *          1) --------- co_request_update ------+               |   |
+ *                                |                              |   |
+ *          2) destroy old cache     +----------- pp_cb ---------|---+
+ *                                |  |                           |
+ *          3) ---------- nl_recvmsgs ----------+   +- cb_valid -+
+ *             +--------------+   |  |          |   |
+ *             | nl_cache_add |<-----+   + - - -v- -|- - - - - - - - - - -
+ *             +--------------+   |      | +-------------+
+ *                                         | nl_recvmsgs |
+ *                                |      | +-----|-^-----+
+ *                                           +---v-|---+
+ *                                |      |   | nl_recv |
+ *                                           +---------+
+ *                                |      |                 Core Netlink
+ * @endcode
+ * 
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/utils.h>
+
+/**
+ * @name Cache Creation/Deletion
+ * @{
+ */
+
+/**
+ * Allocate an empty cache
+ * @arg ops		cache operations to base the cache on
+ * 
+ * @return A newly allocated and initialized cache.
+ */
+struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops)
+{
+	struct nl_cache *cache;
+
+	cache = calloc(1, sizeof(*cache));
+	if (!cache)
+		return NULL;
+
+	nl_init_list_head(&cache->c_items);
+	cache->c_ops = ops;
+
+	NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
+
+	return cache;
+}
+
+int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock,
+			    struct nl_cache **result)
+{
+	struct nl_cache *cache;
+	int err;
+	
+	if (!(cache = nl_cache_alloc(ops)))
+		return -NLE_NOMEM;
+
+	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+		nl_cache_free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
+/**
+ * Clear a cache.
+ * @arg cache		cache to clear
+ *
+ * Removes all elements of a cache.
+ */
+void nl_cache_clear(struct nl_cache *cache)
+{
+	struct nl_object *obj, *tmp;
+
+	NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
+
+	nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
+		nl_cache_remove(obj);
+}
+
+/**
+ * Free a cache.
+ * @arg cache		Cache to free.
+ *
+ * Removes all elements of a cache and frees all memory.
+ *
+ * @note Use this function if you are working with allocated caches.
+ */
+void nl_cache_free(struct nl_cache *cache)
+{
+	if (!cache)
+		return;
+
+	nl_cache_clear(cache);
+	NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
+	free(cache);
+}
+
+/** @} */
+
+/**
+ * @name Cache Modifications
+ * @{
+ */
+
+static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
+{
+	obj->ce_cache = cache;
+
+	nl_list_add_tail(&obj->ce_list, &cache->c_items);
+	cache->c_nitems++;
+
+	NL_DBG(1, "Added %p to cache %p <%s>.\n",
+	       obj, cache, nl_cache_name(cache));
+
+	return 0;
+}
+
+/**
+ * Add object to a cache.
+ * @arg cache		Cache to add object to
+ * @arg obj		Object to be added to the cache
+ *
+ * Adds the given object to the specified cache. The object is cloned
+ * if it has been added to another cache already.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
+{
+	struct nl_object *new;
+
+	if (cache->c_ops->co_obj_ops != obj->ce_ops)
+		return -NLE_OBJ_MISMATCH;
+
+	if (!nl_list_empty(&obj->ce_list)) {
+		new = nl_object_clone(obj);
+		if (!new)
+			return -NLE_NOMEM;
+	} else {
+		nl_object_get(obj);
+		new = obj;
+	}
+
+	return __cache_add(cache, new);
+}
+
+/**
+ * Removes an object from a cache.
+ * @arg obj		Object to remove from its cache
+ *
+ * Removes the object \c obj from the cache it is assigned to, since
+ * an object can only be assigned to one cache at a time, the cache
+ * must ne be passed along with it.
+ */
+void nl_cache_remove(struct nl_object *obj)
+{
+	struct nl_cache *cache = obj->ce_cache;
+
+	if (cache == NULL)
+		return;
+
+	nl_list_del(&obj->ce_list);
+	obj->ce_cache = NULL;
+	nl_object_put(obj);
+	cache->c_nitems--;
+
+	NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
+	       obj, cache, nl_cache_name(cache));
+}
+
+/** @} */
+
+/**
+ * @name Synchronization
+ * @{
+ */
+
+/**
+ * Request a full dump from the kernel to fill a cache
+ * @arg sk		Netlink socket.
+ * @arg cache		Cache subjected to be filled.
+ *
+ * Send a dumping request to the kernel causing it to dump all objects
+ * related to the specified cache to the netlink socket.
+ *
+ * Use nl_cache_pickup() to read the objects from the socket and fill them
+ * into a cache.
+ */
+int nl_cache_request_full_dump(struct nl_sock *sk, struct nl_cache *cache)
+{
+	NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n",
+	          cache, nl_cache_name(cache));
+
+	if (cache->c_ops->co_request_update == NULL)
+		return -NLE_OPNOTSUPP;
+
+	return cache->c_ops->co_request_update(cache, sk);
+}
+
+/** @cond SKIP */
+struct update_xdata {
+	struct nl_cache_ops *ops;
+	struct nl_parser_param *params;
+};
+
+static int update_msg_parser(struct nl_msg *msg, void *arg)
+{
+	struct update_xdata *x = arg;
+	
+	return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
+}
+/** @endcond */
+
+int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
+		   struct nl_parser_param *param)
+{
+	int err;
+	struct nl_cb *cb;
+	struct update_xdata x = {
+		.ops = cache->c_ops,
+		.params = param,
+	};
+
+	NL_DBG(1, "Picking up answer for cache %p <%s>...\n",
+		  cache, nl_cache_name(cache));
+
+	cb = nl_cb_clone(sk->s_cb);
+	if (cb == NULL)
+		return -NLE_NOMEM;
+
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
+
+	err = nl_recvmsgs(sk, cb);
+	if (err < 0)
+		NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
+		       "%d: %s", cache, nl_cache_name(cache),
+		       err, nl_geterror(err));
+
+	nl_cb_put(cb);
+
+	return err;
+}
+
+static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
+{
+	return nl_cache_add((struct nl_cache *) p->pp_arg, c);
+}
+
+/**
+ * Pickup a netlink dump response and put it into a cache.
+ * @arg sk		Netlink socket.
+ * @arg cache		Cache to put items into.
+ *
+ * Waits for netlink messages to arrive, parses them and puts them into
+ * the specified cache.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
+{
+	struct nl_parser_param p = {
+		.pp_cb = pickup_cb,
+		.pp_arg = cache,
+	};
+
+	return __cache_pickup(sk, cache, &p);
+}
+
+
+/** @} */
+
+/**
+ * @name Parsing
+ * @{
+ */
+
+/** @cond SKIP */
+int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+		   struct nlmsghdr *nlh, struct nl_parser_param *params)
+{
+	int i, err;
+
+	if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize))
+		return -NLE_MSG_TOOSHORT;
+
+	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) {
+		if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) {
+			err = ops->co_msg_parser(ops, who, nlh, params);
+			if (err != -NLE_OPNOTSUPP)
+				goto errout;
+		}
+	}
+
+
+	err = -NLE_MSGTYPE_NOSUPPORT;
+errout:
+	return err;
+}
+/** @endcond */
+
+/**
+ * Parse a netlink message and add it to the cache.
+ * @arg cache		cache to add element to
+ * @arg msg		netlink message
+ *
+ * Parses a netlink message by calling the cache specific message parser
+ * and adds the new element to the cache.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
+{
+	struct nl_parser_param p = {
+		.pp_cb = pickup_cb,
+		.pp_arg = cache,
+	};
+
+	return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/**
+ * (Re)fill a cache with the contents in the kernel.
+ * @arg sk		Netlink socket.
+ * @arg cache		cache to update
+ *
+ * Clears the specified cache and fills it with the current state in
+ * the kernel.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
+{
+	int err;
+
+	err = nl_cache_request_full_dump(sk, cache);
+	if (err < 0)
+		return err;
+
+	NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
+	       cache, nl_cache_name(cache));
+	nl_cache_clear(cache);
+
+	return nl_cache_pickup(sk, cache);
+}
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/cache_mngt.c b/package/libs/libnl-tiny/src/cache_mngt.c
new file mode 100644
index 0000000000..8adbe51b0a
--- /dev/null
+++ b/package/libs/libnl-tiny/src/cache_mngt.c
@@ -0,0 +1,131 @@
+/*
+ * lib/cache_mngt.c	Cache Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup cache_mngt Caching
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+
+static struct nl_cache_ops *cache_ops;
+
+/**
+ * @name Cache Operations Sets
+ * @{
+ */
+
+/**
+ * Lookup the set cache operations of a certain cache type
+ * @arg name		name of the cache type
+ *
+ * @return The cache operations or NULL if no operations
+ *         have been registered under the specified name.
+ */
+struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
+{
+	struct nl_cache_ops *ops;
+
+	for (ops = cache_ops; ops; ops = ops->co_next)
+		if (!strcmp(ops->co_name, name))
+			return ops;
+
+	return NULL;
+}
+
+/**
+ * Associate a message type to a set of cache operations
+ * @arg protocol		netlink protocol
+ * @arg msgtype			netlink message type
+ *
+ * Associates the specified netlink message type with
+ * a registered set of cache operations.
+ *
+ * @return The cache operations or NULL if no association
+ *         could be made.
+ */
+struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
+{
+	int i;
+	struct nl_cache_ops *ops;
+
+	for (ops = cache_ops; ops; ops = ops->co_next) {
+		if (ops->co_protocol != protocol)
+			continue;
+
+		for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+			if (ops->co_msgtypes[i].mt_id == msgtype)
+				return ops;
+	}
+
+	return NULL;
+}
+
+/**
+ * Register a set of cache operations
+ * @arg ops		cache operations
+ *
+ * Called by users of caches to announce the avaibility of
+ * a certain cache type.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_mngt_register(struct nl_cache_ops *ops)
+{
+	if (!ops->co_name || !ops->co_obj_ops)
+		return -NLE_INVAL;
+
+	if (nl_cache_ops_lookup(ops->co_name))
+		return -NLE_EXIST;
+
+	ops->co_next = cache_ops;
+	cache_ops = ops;
+
+	NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
+
+	return 0;
+}
+
+/**
+ * Unregister a set of cache operations
+ * @arg ops		cache operations
+ *
+ * Called by users of caches to announce a set of
+ * cache operations is no longer available. The
+ * specified cache operations must have been registered
+ * previously using nl_cache_mngt_register()
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
+{
+	struct nl_cache_ops *t, **tp;
+
+	for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
+		if (t == ops)
+			break;
+
+	if (!t)
+		return -NLE_NOCACHE;
+
+	NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
+
+	*tp = t->co_next;
+	return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/error.c b/package/libs/libnl-tiny/src/error.c
new file mode 100644
index 0000000000..e8ee47459e
--- /dev/null
+++ b/package/libs/libnl-tiny/src/error.c
@@ -0,0 +1,116 @@
+/*
+ * lib/error.c		Error Handling
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+
+static const char *errmsg[NLE_MAX+1] = {
+[NLE_SUCCESS]		= "Success",
+[NLE_FAILURE]		= "Unspecific failure",
+[NLE_INTR]		= "Interrupted system call",
+[NLE_BAD_SOCK]		= "Bad socket",
+[NLE_AGAIN]		= "Try again",
+[NLE_NOMEM]		= "Out of memory",
+[NLE_EXIST]		= "Object exists",
+[NLE_INVAL]		= "Invalid input data or parameter",
+[NLE_RANGE]		= "Input data out of range",
+[NLE_MSGSIZE]		= "Message size not sufficient",
+[NLE_OPNOTSUPP]		= "Operation not supported",
+[NLE_AF_NOSUPPORT]	= "Address family not supported",
+[NLE_OBJ_NOTFOUND]	= "Object not found",
+[NLE_NOATTR]		= "Attribute not available",
+[NLE_MISSING_ATTR]	= "Missing attribute",
+[NLE_AF_MISMATCH]	= "Address family mismatch",
+[NLE_SEQ_MISMATCH]	= "Message sequence number mismatch",
+[NLE_MSG_OVERFLOW]	= "Kernel reported message overflow",
+[NLE_MSG_TRUNC]		= "Kernel reported truncated message",
+[NLE_NOADDR]		= "Invalid address for specified address family",
+[NLE_SRCRT_NOSUPPORT]	= "Source based routing not supported",
+[NLE_MSG_TOOSHORT]	= "Netlink message is too short",
+[NLE_MSGTYPE_NOSUPPORT]	= "Netlink message type is not supported",
+[NLE_OBJ_MISMATCH]	= "Object type does not match cache",
+[NLE_NOCACHE]		= "Unknown or invalid cache type",
+[NLE_BUSY]		= "Object busy",
+[NLE_PROTO_MISMATCH]	= "Protocol mismatch",
+[NLE_NOACCESS]		= "No Access",
+[NLE_PERM]		= "Operation not permitted",
+[NLE_PKTLOC_FILE]	= "Unable to open packet location file",
+[NLE_PARSE_ERR]		= "Unable to parse object",
+[NLE_NODEV]		= "No such device",
+[NLE_IMMUTABLE]		= "Immutable attribute",
+[NLE_DUMP_INTR]		= "Dump inconsistency detected, interrupted",
+};
+
+/**
+ * Return error message for an error code
+ * @return error message
+ */
+const char *nl_geterror(int error)
+{
+	error = abs(error);
+
+	if (error > NLE_MAX)
+		error = NLE_FAILURE;
+
+	return errmsg[error];
+}
+
+/**
+ * Print a libnl error message
+ * @arg s		error message prefix
+ *
+ * Prints the error message of the call that failed last.
+ *
+ * If s is not NULL and *s is not a null byte the argument
+ * string is printed, followed by a colon and a blank. Then
+ * the error message and a new-line.
+ */
+void nl_perror(int error, const char *s)
+{
+	if (s && *s)
+		fprintf(stderr, "%s: %s\n", s, nl_geterror(error));
+	else
+		fprintf(stderr, "%s\n", nl_geterror(error));
+}
+
+int nl_syserr2nlerr(int error)
+{
+	error = abs(error);
+
+	switch (error) {
+	case EBADF:		return NLE_BAD_SOCK;
+	case EADDRINUSE:	return NLE_EXIST;
+	case EEXIST:		return NLE_EXIST;
+	case EADDRNOTAVAIL:	return NLE_NOADDR;
+	case ESRCH:		/* fall through */
+	case ENOENT:		return NLE_OBJ_NOTFOUND;
+	case EINTR:		return NLE_INTR;
+	case EAGAIN:		return NLE_AGAIN;
+	case ENOTSOCK:		return NLE_BAD_SOCK;
+	case ENOPROTOOPT:	return NLE_INVAL;
+	case EFAULT:		return NLE_INVAL;
+	case EACCES:		return NLE_NOACCESS;
+	case EINVAL:		return NLE_INVAL;
+	case ENOBUFS:		return NLE_NOMEM;
+	case ENOMEM:		return NLE_NOMEM;
+	case EAFNOSUPPORT:	return NLE_AF_NOSUPPORT;
+	case EPROTONOSUPPORT:	return NLE_PROTO_MISMATCH;
+	case EOPNOTSUPP:	return NLE_OPNOTSUPP;
+	case EPERM:		return NLE_PERM;
+	case EBUSY:		return NLE_BUSY;
+	case ERANGE:		return NLE_RANGE;
+	case ENODEV:		return NLE_NODEV;
+	default:		return NLE_FAILURE;
+	}
+}
+
+/** @} */
+
diff --git a/package/libs/libnl-tiny/src/genl.c b/package/libs/libnl-tiny/src/genl.c
new file mode 100644
index 0000000000..055be919e1
--- /dev/null
+++ b/package/libs/libnl-tiny/src/genl.c
@@ -0,0 +1,268 @@
+/*
+ * lib/genl/genl.c		Generic Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup genl Generic Netlink
+ *
+ * @par Message Format
+ * @code
+ *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * |           Header           | Pad |       Payload       | Pad |
+ * |      struct nlmsghdr       |     |                     |     |
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * @endcode
+ * @code
+ *  <-------- GENL_HDRLEN -------> <--- hdrlen -->
+ *                                 <------- genlmsg_len(ghdr) ------>
+ * +------------------------+- - -+---------------+- - -+------------+
+ * | Generic Netlink Header | Pad | Family Header | Pad | Attributes |
+ * |    struct genlmsghdr   |     |               |     |            |
+ * +------------------------+- - -+---------------+- - -+------------+
+ * genlmsg_data(ghdr)--------------^                     ^
+ * genlmsg_attrdata(ghdr, hdrlen)-------------------------
+ * @endcode
+ *
+ * @par Example
+ * @code
+ * #include <netlink/netlink.h>
+ * #include <netlink/genl/genl.h>
+ * #include <netlink/genl/ctrl.h>
+ *
+ * struct nl_sock *sock;
+ * struct nl_msg *msg;
+ * int family;
+ *
+ * // Allocate a new netlink socket
+ * sock = nl_socket_alloc();
+ *
+ * // Connect to generic netlink socket on kernel side
+ * genl_connect(sock);
+ *
+ * // Ask kernel to resolve family name to family id
+ * family = genl_ctrl_resolve(sock, "generic_netlink_family_name");
+ *
+ * // Construct a generic netlink by allocating a new message, fill in
+ * // the header and append a simple integer attribute.
+ * msg = nlmsg_alloc();
+ * genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO,
+ *             CMD_FOO_GET, FOO_VERSION);
+ * nla_put_u32(msg, ATTR_FOO, 123);
+ *
+ * // Send message over netlink socket
+ * nl_send_auto_complete(sock, msg);
+ *
+ * // Free message
+ * nlmsg_free(msg);
+ *
+ * // Prepare socket to receive the answer by specifying the callback
+ * // function to be called for valid messages.
+ * nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
+ *
+ * // Wait for the answer and receive it
+ * nl_recvmsgs_default(sock);
+ *
+ * static int parse_cb(struct nl_msg *msg, void *arg)
+ * {
+ *     struct nlmsghdr *nlh = nlmsg_hdr(msg);
+ *     struct nlattr *attrs[ATTR_MAX+1];
+ *
+ *     // Validate message and parse attributes
+ *     genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy);
+ *
+ *     if (attrs[ATTR_FOO]) {
+ *         uint32_t value = nla_get_u32(attrs[ATTR_FOO]);
+ *         ...
+ *     }
+ *
+ *     return 0;
+ * }
+ * @endcode
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/utils.h>
+
+/**
+ * @name Socket Creating
+ * @{
+ */
+
+int genl_connect(struct nl_sock *sk)
+{
+	return nl_connect(sk, NETLINK_GENERIC);
+}
+
+/** @} */
+
+/**
+ * @name Sending
+ * @{
+ */
+
+/**
+ * Send trivial generic netlink message
+ * @arg sk		Netlink socket.
+ * @arg family		Generic netlink family
+ * @arg cmd		Command
+ * @arg version		Version
+ * @arg flags		Additional netlink message flags.
+ *
+ * Fills out a routing netlink request message and sends it out
+ * using nl_send_simple().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_send_simple(struct nl_sock *sk, int family, int cmd,
+		     int version, int flags)
+{
+	struct genlmsghdr hdr = {
+		.cmd = cmd,
+		.version = version,
+	};
+
+	return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
+}
+
+/** @} */
+
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
+{
+	struct genlmsghdr *ghdr;
+
+	if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
+		return 0;
+
+	ghdr = nlmsg_data(nlh);
+	if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
+		return 0;
+
+	return 1;
+}
+
+int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+		   struct nla_policy *policy)
+{
+	struct genlmsghdr *ghdr;
+
+	if (!genlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	ghdr = nlmsg_data(nlh);
+	return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
+			    genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
+}
+
+int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+		  int maxtype, struct nla_policy *policy)
+{
+	struct genlmsghdr *ghdr;
+
+	if (!genlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	ghdr = nlmsg_data(nlh);
+	return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
+			 genlmsg_attrlen(ghdr, hdrlen), policy);
+}
+
+/**
+ * Get head of message payload
+ * @arg gnlh	genetlink messsage header
+ */
+void *genlmsg_data(const struct genlmsghdr *gnlh)
+{
+	return ((unsigned char *) gnlh + GENL_HDRLEN);
+}
+
+/**
+ * Get lenght of message payload
+ * @arg gnlh	genetlink message header
+ */
+int genlmsg_len(const struct genlmsghdr *gnlh)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
+							NLMSG_HDRLEN);
+	return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+/**
+ * Get head of attribute data
+ * @arg gnlh	generic netlink message header
+ * @arg hdrlen	length of family specific header
+ */
+struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
+{
+	return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen);
+}
+
+/**
+ * Get length of attribute data
+ * @arg gnlh	generic netlink message header
+ * @arg hdrlen	length of family specific header
+ */
+int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
+{
+	return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/** @} */
+
+/**
+ * @name Message Building
+ * @{
+ */
+
+/**
+ * Add generic netlink header to netlink message
+ * @arg msg		netlink message
+ * @arg pid		netlink process id or NL_AUTO_PID
+ * @arg seq		sequence number of message or NL_AUTO_SEQ
+ * @arg family		generic netlink family
+ * @arg hdrlen		length of user specific header
+ * @arg flags		message flags
+ * @arg cmd		generic netlink command
+ * @arg version		protocol version
+ *
+ * Returns pointer to user specific header.
+ */
+void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
+		  int hdrlen, int flags, uint8_t cmd, uint8_t version)
+{
+	struct nlmsghdr *nlh;
+	struct genlmsghdr hdr = {
+		.cmd = cmd,
+		.version = version,
+	};
+
+	nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags);
+	if (nlh == NULL)
+		return NULL;
+
+	memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
+	NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
+	       msg, cmd, version);
+
+	return nlmsg_data(nlh) + GENL_HDRLEN;
+}
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/genl_ctrl.c b/package/libs/libnl-tiny/src/genl_ctrl.c
new file mode 100644
index 0000000000..0045459b2f
--- /dev/null
+++ b/package/libs/libnl-tiny/src/genl_ctrl.c
@@ -0,0 +1,380 @@
+/*
+ * lib/genl/ctrl.c		Generic Netlink Controller
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup genl_mngt
+ * @defgroup ctrl Controller
+ * @brief
+ *
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define CTRL_VERSION		0x0001
+
+static struct nl_cache_ops genl_ctrl_ops;
+/** @endcond */
+
+static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+	return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
+				CTRL_VERSION, NLM_F_DUMP);
+}
+
+static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
+	[CTRL_ATTR_FAMILY_ID]	= { .type = NLA_U16 },
+	[CTRL_ATTR_FAMILY_NAME]	= { .type = NLA_STRING,
+				    .maxlen = GENL_NAMSIZ },
+	[CTRL_ATTR_VERSION]	= { .type = NLA_U32 },
+	[CTRL_ATTR_HDRSIZE]	= { .type = NLA_U32 },
+	[CTRL_ATTR_MAXATTR]	= { .type = NLA_U32 },
+	[CTRL_ATTR_OPS]		= { .type = NLA_NESTED },
+	[CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
+	[CTRL_ATTR_OP_ID]	= { .type = NLA_U32 },
+	[CTRL_ATTR_OP_FLAGS]	= { .type = NLA_U32 },
+};
+
+static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
+	[CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
+	[CTRL_ATTR_MCAST_GRP_ID]   = { .type = NLA_U32 },
+};
+
+static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
+			   struct genl_info *info, void *arg)
+{
+	struct genl_family *family;
+	struct nl_parser_param *pp = arg;
+	int err;
+
+	family = genl_family_alloc();
+	if (family == NULL) {
+		err = -NLE_NOMEM;
+		goto errout;
+	}
+
+	if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
+		err = -NLE_MISSING_ATTR;
+		goto errout;
+	}
+
+	if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
+		err = -NLE_MISSING_ATTR;
+		goto errout;
+	}
+
+	family->ce_msgtype = info->nlh->nlmsg_type;
+	genl_family_set_id(family,
+			   nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
+	genl_family_set_name(family,
+		     nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
+
+	if (info->attrs[CTRL_ATTR_VERSION]) {
+		uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
+		genl_family_set_version(family, version);
+	}
+
+	if (info->attrs[CTRL_ATTR_HDRSIZE]) {
+		uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
+		genl_family_set_hdrsize(family, hdrsize);
+	}
+
+	if (info->attrs[CTRL_ATTR_MAXATTR]) {
+		uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
+		genl_family_set_maxattr(family, maxattr);
+	}
+
+	if (info->attrs[CTRL_ATTR_OPS]) {
+		struct nlattr *nla, *nla_ops;
+		int remaining;
+
+		nla_ops = info->attrs[CTRL_ATTR_OPS];
+		nla_for_each_nested(nla, nla_ops, remaining) {
+			struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
+			int flags = 0, id;
+
+			err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
+					       family_op_policy);
+			if (err < 0)
+				goto errout;
+
+			if (tb[CTRL_ATTR_OP_ID] == NULL) {
+				err = -NLE_MISSING_ATTR;
+				goto errout;
+			}
+			
+			id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
+
+			if (tb[CTRL_ATTR_OP_FLAGS])
+				flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
+
+			err = genl_family_add_op(family, id, flags);
+			if (err < 0)
+				goto errout;
+
+		}
+	}
+
+	if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
+		struct nlattr *nla, *nla_grps;
+		int remaining;
+
+		nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS];
+		nla_for_each_nested(nla, nla_grps, remaining) {
+			struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
+			int id;
+			const char * name;
+
+			err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
+					       family_grp_policy);
+			if (err < 0)
+				goto errout;
+
+			if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
+				err = -NLE_MISSING_ATTR;
+				goto errout;
+			}
+			id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+
+			if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
+				err = -NLE_MISSING_ATTR;
+				goto errout;
+			}
+			name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+
+			err = genl_family_add_grp(family, id, name);
+			if (err < 0)
+				goto errout;
+		}
+
+	}
+
+	err = pp->pp_cb((struct nl_object *) family, pp);
+errout:
+	genl_family_put(family);
+	return err;
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+	return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
+}
+
+/**
+ * Look up generic netlink family by id in the provided cache.
+ * @arg cache		Generic netlink family cache.
+ * @arg id		Family identifier.
+ *
+ * Searches through the cache looking for a registered family
+ * matching the specified identifier. The caller will own a
+ * reference on the returned object which needs to be given
+ * back after usage using genl_family_put().
+ *
+ * @return Generic netlink family object or NULL if no match was found.
+ */
+struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
+{
+	struct genl_family *fam;
+
+	if (cache->c_ops != &genl_ctrl_ops)
+		BUG();
+
+	nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
+		if (fam->gf_id == id) {
+			nl_object_get((struct nl_object *) fam);
+			return fam;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * @name Resolver
+ * @{
+ */
+
+/**
+ * Look up generic netlink family by family name in the provided cache.
+ * @arg cache		Generic netlink family cache.
+ * @arg name		Family name.
+ *
+ * Searches through the cache looking for a registered family
+ * matching the specified name. The caller will own a reference
+ * on the returned object which needs to be given back after
+ * usage using genl_family_put().
+ *
+ * @return Generic netlink family object or NULL if no match was found.
+ */
+struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
+					    const char *name)
+{
+	struct genl_family *fam;
+
+	if (cache->c_ops != &genl_ctrl_ops)
+		BUG();
+
+	nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
+		if (!strcmp(name, fam->gf_name)) {
+			nl_object_get((struct nl_object *) fam);
+			return fam;
+		}
+	}
+
+	return NULL;
+}
+
+/** @} */
+
+/**
+ * Resolve generic netlink family name to its identifier
+ * @arg sk		Netlink socket.
+ * @arg name		Name of generic netlink family
+ *
+ * Resolves the generic netlink family name to its identifer and returns
+ * it.
+ *
+ * @return A positive identifier or a negative error code.
+ */
+int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
+{
+	struct nl_cache *cache;
+	struct genl_family *family;
+	int err;
+
+	if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
+		return err;
+
+	family = genl_ctrl_search_by_name(cache, name);
+	if (family == NULL) {
+		err = -NLE_OBJ_NOTFOUND;
+		goto errout;
+	}
+
+	err = genl_family_get_id(family);
+	genl_family_put(family);
+errout:
+	nl_cache_free(cache);
+
+	return err;
+}
+
+static int genl_ctrl_grp_by_name(const struct genl_family *family,
+				const char *grp_name)
+{
+	struct genl_family_grp *grp;
+
+	nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
+		if (!strcmp(grp->name, grp_name)) {
+			return grp->id;
+		}
+	}
+
+	return -NLE_OBJ_NOTFOUND;
+}
+
+int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
+	const char *grp_name)
+{
+	struct nl_cache *cache;
+	struct genl_family *family;
+	int err;
+
+	if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
+		return err;
+
+	family = genl_ctrl_search_by_name(cache, family_name);
+	if (family == NULL) {
+		err = -NLE_OBJ_NOTFOUND;
+		goto errout;
+	}
+
+	err = genl_ctrl_grp_by_name(family, grp_name);
+	genl_family_put(family);
+errout:
+	nl_cache_free(cache);
+
+	return err;
+}
+
+/** @} */
+
+static struct genl_cmd genl_cmds[] = {
+	{
+		.c_id		= CTRL_CMD_NEWFAMILY,
+		.c_name		= "NEWFAMILY" ,
+		.c_maxattr	= CTRL_ATTR_MAX,
+		.c_attr_policy	= ctrl_policy,
+		.c_msg_parser	= ctrl_msg_parser,
+	},
+	{
+		.c_id		= CTRL_CMD_DELFAMILY,
+		.c_name		= "DELFAMILY" ,
+	},
+	{
+		.c_id		= CTRL_CMD_GETFAMILY,
+		.c_name		= "GETFAMILY" ,
+	},
+	{
+		.c_id		= CTRL_CMD_NEWOPS,
+		.c_name		= "NEWOPS" ,
+	},
+	{
+		.c_id		= CTRL_CMD_DELOPS,
+		.c_name		= "DELOPS" ,
+	},
+};
+
+static struct genl_ops genl_ops = {
+	.o_cmds			= genl_cmds,
+	.o_ncmds		= ARRAY_SIZE(genl_cmds),
+};
+
+/** @cond SKIP */
+extern struct nl_object_ops genl_family_ops;
+/** @endcond */
+
+static struct nl_cache_ops genl_ctrl_ops = {
+	.co_name		= "genl/family",
+	.co_hdrsize		= GENL_HDRSIZE(0),
+	.co_msgtypes		= GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
+	.co_genl		= &genl_ops,
+	.co_protocol		= NETLINK_GENERIC,
+	.co_request_update      = ctrl_request_update,
+	.co_obj_ops		= &genl_family_ops,
+};
+
+static void __init ctrl_init(void)
+{
+	genl_register(&genl_ctrl_ops);
+}
+
+static void __exit ctrl_exit(void)
+{
+	genl_unregister(&genl_ctrl_ops);
+}
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/genl_family.c b/package/libs/libnl-tiny/src/genl_family.c
new file mode 100644
index 0000000000..221acfa1a7
--- /dev/null
+++ b/package/libs/libnl-tiny/src/genl_family.c
@@ -0,0 +1,169 @@
+/*
+ * lib/genl/family.c		Generic Netlink Family
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup genl
+ * @defgroup genl_family Generic Netlink Family
+ * @brief
+ *
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/utils.h>
+
+struct nl_object_ops genl_family_ops;
+/** @endcond */
+
+static void family_constructor(struct nl_object *c)
+{
+	struct genl_family *family = (struct genl_family *) c;
+
+	nl_init_list_head(&family->gf_ops);
+	nl_init_list_head(&family->gf_mc_grps);
+}
+
+static void family_free_data(struct nl_object *c)
+{
+	struct genl_family *family = (struct genl_family *) c;
+	struct genl_family_op *ops, *tmp;
+	struct genl_family_grp *grp, *t_grp;
+
+	if (family == NULL)
+		return;
+
+	nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) {
+		nl_list_del(&ops->o_list);
+		free(ops);
+	}
+
+	nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) {
+		nl_list_del(&grp->list);
+		free(grp);
+	}
+
+}
+
+static int family_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+	struct genl_family *dst = nl_object_priv(_dst);
+	struct genl_family *src = nl_object_priv(_src);
+	struct genl_family_op *ops;
+	struct genl_family_grp *grp;
+	int err;
+
+	nl_list_for_each_entry(ops, &src->gf_ops, o_list) {
+		err = genl_family_add_op(dst, ops->o_id, ops->o_flags);
+		if (err < 0)
+			return err;
+	}
+
+	nl_list_for_each_entry(grp, &src->gf_mc_grps, list) {
+		err = genl_family_add_grp(dst, grp->id, grp->name);
+		if (err < 0)
+			return err;
+	}
+
+	
+	return 0;
+}
+
+static int family_compare(struct nl_object *_a, struct nl_object *_b,
+			  uint32_t attrs, int flags)
+{
+	struct genl_family *a = (struct genl_family *) _a;
+	struct genl_family *b = (struct genl_family *) _b;
+	int diff = 0;
+
+#define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR)
+
+	diff |= FAM_DIFF(ID,		a->gf_id != b->gf_id);
+	diff |= FAM_DIFF(VERSION,	a->gf_version != b->gf_version);
+	diff |= FAM_DIFF(HDRSIZE,	a->gf_hdrsize != b->gf_hdrsize);
+	diff |= FAM_DIFF(MAXATTR,	a->gf_maxattr != b->gf_maxattr);
+	diff |= FAM_DIFF(NAME,		strcmp(a->gf_name, b->gf_name));
+
+#undef FAM_DIFF
+
+	return diff;
+}
+
+
+/**
+ * @name Family Object
+ * @{
+ */
+
+struct genl_family *genl_family_alloc(void)
+{
+	return (struct genl_family *) nl_object_alloc(&genl_family_ops);
+}
+
+void genl_family_put(struct genl_family *family)
+{
+	nl_object_put((struct nl_object *) family);
+}
+
+/** @} */
+
+
+int genl_family_add_op(struct genl_family *family, int id, int flags)
+{
+	struct genl_family_op *op;
+
+	op = calloc(1, sizeof(*op));
+	if (op == NULL)
+		return -NLE_NOMEM;
+
+	op->o_id = id;
+	op->o_flags = flags;
+
+	nl_list_add_tail(&op->o_list, &family->gf_ops);
+	family->ce_mask |= FAMILY_ATTR_OPS;
+
+	return 0;
+}
+
+int genl_family_add_grp(struct genl_family *family, uint32_t id,
+			const char *name)
+{
+	struct genl_family_grp *grp;
+
+	grp = calloc(1, sizeof(*grp));
+	if (grp == NULL)
+		return -NLE_NOMEM;
+
+	grp->id = id;
+	strncpy(grp->name, name, GENL_NAMSIZ - 1);
+
+	nl_list_add_tail(&grp->list, &family->gf_mc_grps);
+
+	return 0;
+}
+
+/** @} */
+
+/** @cond SKIP */
+struct nl_object_ops genl_family_ops = {
+	.oo_name		= "genl/family",
+	.oo_size		= sizeof(struct genl_family),
+	.oo_constructor		= family_constructor,
+	.oo_free_data		= family_free_data,
+	.oo_clone		= family_clone,
+	.oo_compare		= family_compare,
+	.oo_id_attrs		= FAMILY_ATTR_ID,
+};
+/** @endcond */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/genl_mngt.c b/package/libs/libnl-tiny/src/genl_mngt.c
new file mode 100644
index 0000000000..246521f696
--- /dev/null
+++ b/package/libs/libnl-tiny/src/genl_mngt.c
@@ -0,0 +1,193 @@
+/*
+ * lib/genl/mngt.c		Generic Netlink Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup genl
+ * @defgroup genl_mngt Management
+ *
+ * @par 1) Registering a generic netlink module
+ * @code
+ * #include <netlink/genl/mngt.h>
+ *
+ * // First step is to define all the commands being used in
+ * // particular generic netlink family. The ID and name are
+ * // mandatory to be filled out. A callback function and
+ * // most the attribute policy that comes with it must be
+ * // defined for commands expected to be issued towards
+ * // userspace.
+ * static struct genl_cmd foo_cmds[] = {
+ * 	{
+ * 		.c_id		= FOO_CMD_NEW,
+ * 		.c_name		= "NEWFOO" ,
+ * 		.c_maxattr	= FOO_ATTR_MAX,
+ * 		.c_attr_policy	= foo_policy,
+ * 		.c_msg_parser	= foo_msg_parser,
+ * 	},
+ * 	{
+ * 		.c_id		= FOO_CMD_DEL,
+ * 		.c_name		= "DELFOO" ,
+ * 	},
+ * };
+ *
+ * // The list of commands must then be integrated into a
+ * // struct genl_ops serving as handle for this particular
+ * // family.
+ * static struct genl_ops my_genl_ops = {
+ * 	.o_cmds			= foo_cmds,
+ * 	.o_ncmds		= ARRAY_SIZE(foo_cmds),
+ * };
+ *
+ * // Using the above struct genl_ops an arbitary number of
+ * // cache handles can be associated to it.
+ * //
+ * // The macro GENL_HDRSIZE() must be used to specify the
+ * // length of the header to automatically take headers on
+ * // generic layers into account.
+ * //
+ * // The macro GENL_FAMILY() is used to represent the generic
+ * // netlink family id.
+ * static struct nl_cache_ops genl_foo_ops = {
+ * 	.co_name		= "genl/foo",
+ * 	.co_hdrsize		= GENL_HDRSIZE(sizeof(struct my_hdr)),
+ * 	.co_msgtypes		= GENL_FAMILY(GENL_ID_GENERATE, "foo"),
+ * 	.co_genl		= &my_genl_ops,
+ * 	.co_protocol		= NETLINK_GENERIC,
+ * 	.co_request_update      = foo_request_update,
+ * 	.co_obj_ops		= &genl_foo_ops,
+ * };
+ *
+ * // Finally each cache handle for a generic netlink family
+ * // must be registered using genl_register().
+ * static void __init foo_init(void)
+ * {
+ * 	genl_register(&genl_foo_ops);
+ * }
+ *
+ * // ... respectively unregsted again.
+ * static void __exit foo_exit(void)
+ * {
+ * 	genl_unregister(&genl_foo_ops);
+ * }
+ * @endcode
+ * @{
+ */
+
+#include <netlink-generic.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/utils.h>
+
+static NL_LIST_HEAD(genl_ops_list);
+
+static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+			   struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+	int i, err;
+	struct genlmsghdr *ghdr;
+	struct genl_cmd *cmd;
+
+	ghdr = nlmsg_data(nlh);
+
+	if (ops->co_genl == NULL)
+		BUG();
+
+	for (i = 0; i < ops->co_genl->o_ncmds; i++) {
+		cmd = &ops->co_genl->o_cmds[i];
+		if (cmd->c_id == ghdr->cmd)
+			goto found;
+	}
+
+	err = -NLE_MSGTYPE_NOSUPPORT;
+	goto errout;
+
+found:
+	if (cmd->c_msg_parser == NULL)
+		err = -NLE_OPNOTSUPP;
+	else {
+		struct nlattr *tb[cmd->c_maxattr + 1];
+		struct genl_info info = {
+			.who = who,
+			.nlh = nlh,
+			.genlhdr = ghdr,
+			.userhdr = genlmsg_data(ghdr),
+			.attrs = tb,
+		};
+
+		err = nlmsg_parse(nlh, ops->co_hdrsize, tb, cmd->c_maxattr,
+				  cmd->c_attr_policy);
+		if (err < 0)
+			goto errout;
+
+		err = cmd->c_msg_parser(ops, cmd, &info, pp);
+	}
+errout:
+	return err;
+
+}
+
+/**
+ * @name Register/Unregister
+ * @{
+ */
+
+/**
+ * Register generic netlink operations
+ * @arg ops		cache operations
+ */
+int genl_register(struct nl_cache_ops *ops)
+{
+	int err;
+
+	if (ops->co_protocol != NETLINK_GENERIC) {
+		err = -NLE_PROTO_MISMATCH;
+		goto errout;
+	}
+
+	if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
+		err = -NLE_INVAL;
+		goto errout;
+	}
+
+	if (ops->co_genl == NULL) {
+		err = -NLE_INVAL;
+		goto errout;
+	}
+
+	ops->co_genl->o_cache_ops = ops;
+	ops->co_genl->o_name = ops->co_msgtypes[0].mt_name;
+	ops->co_genl->o_family = ops->co_msgtypes[0].mt_id;
+	ops->co_msg_parser = genl_msg_parser;
+
+	/* FIXME: check for dup */
+
+	nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list);
+
+	err = nl_cache_mngt_register(ops);
+errout:
+	return err;
+}
+
+/**
+ * Unregister generic netlink operations
+ * @arg ops		cache operations
+ */
+void genl_unregister(struct nl_cache_ops *ops)
+{
+	nl_cache_mngt_unregister(ops);
+	nl_list_del(&ops->co_genl->o_list);
+}
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/handlers.c b/package/libs/libnl-tiny/src/handlers.c
new file mode 100644
index 0000000000..12ebda5207
--- /dev/null
+++ b/package/libs/libnl-tiny/src/handlers.c
@@ -0,0 +1,162 @@
+/*
+ * lib/handlers.c	default netlink message handlers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup cb Callbacks/Customization
+ *
+ * @details
+ * @par 1) Setting up a callback set
+ * @code
+ * // Allocate a callback set and initialize it to the verbose default set
+ * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE);
+ *
+ * // Modify the set to call my_func() for all valid messages
+ * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
+ *
+ * // Set the error message handler to the verbose default implementation
+ * // and direct it to print all errors to the given file descriptor.
+ * FILE *file = fopen(...);
+ * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/msg.h>
+#include <netlink/handlers.h>
+
+/**
+ * @name Callback Handle Management
+ * @{
+ */
+
+/**
+ * Allocate a new callback handle
+ * @arg kind		callback kind to be used for initialization
+ * @return Newly allocated callback handle or NULL
+ */
+struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
+{
+	int i;
+	struct nl_cb *cb;
+
+	if (kind < 0 || kind > NL_CB_KIND_MAX)
+		return NULL;
+
+	cb = calloc(1, sizeof(*cb));
+	if (!cb)
+		return NULL;
+
+	cb->cb_refcnt = 1;
+
+	for (i = 0; i <= NL_CB_TYPE_MAX; i++)
+		nl_cb_set(cb, i, kind, NULL, NULL);
+
+	nl_cb_err(cb, kind, NULL, NULL);
+
+	return cb;
+}
+
+/**
+ * Clone an existing callback handle
+ * @arg orig		original callback handle
+ * @return Newly allocated callback handle being a duplicate of
+ *         orig or NULL
+ */
+struct nl_cb *nl_cb_clone(struct nl_cb *orig)
+{
+	struct nl_cb *cb;
+	
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!cb)
+		return NULL;
+
+	memcpy(cb, orig, sizeof(*orig));
+	cb->cb_refcnt = 1;
+
+	return cb;
+}
+
+void nl_cb_put(struct nl_cb *cb)
+{
+	if (!cb)
+		return;
+
+	cb->cb_refcnt--;
+
+	if (cb->cb_refcnt < 0)
+		BUG();
+
+	if (cb->cb_refcnt <= 0)
+		free(cb);
+}
+
+/** @} */
+
+/**
+ * @name Callback Setup
+ * @{
+ */
+
+/**
+ * Set up a callback 
+ * @arg cb		callback set
+ * @arg type		callback to modify
+ * @arg kind		kind of implementation
+ * @arg func		callback function (NL_CB_CUSTOM)
+ * @arg arg		argument passed to callback
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
+	      nl_recvmsg_msg_cb_t func, void *arg)
+{
+	if (type < 0 || type > NL_CB_TYPE_MAX)
+		return -NLE_RANGE;
+
+	if (kind < 0 || kind > NL_CB_KIND_MAX)
+		return -NLE_RANGE;
+
+	if (kind == NL_CB_CUSTOM) {
+		cb->cb_set[type] = func;
+		cb->cb_args[type] = arg;
+	}
+
+	return 0;
+}
+
+/**
+ * Set up an error callback
+ * @arg cb		callback set
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passed to callback function
+ */
+int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
+	      nl_recvmsg_err_cb_t func, void *arg)
+{
+	if (kind < 0 || kind > NL_CB_KIND_MAX)
+		return -NLE_RANGE;
+
+	if (kind == NL_CB_CUSTOM) {
+		cb->cb_err = func;
+		cb->cb_err_arg = arg;
+	}
+
+	return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/include/netlink-generic.h b/package/libs/libnl-tiny/src/include/netlink-generic.h
new file mode 100644
index 0000000000..10aa2f01bb
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink-generic.h
@@ -0,0 +1,20 @@
+/*
+ * netlink-generic.h	Local Generic Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_PRIV_H_
+#define NETLINK_GENL_PRIV_H_
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+
+#define GENL_HDRSIZE(hdrlen) (GENL_HDRLEN + (hdrlen))
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink-local.h b/package/libs/libnl-tiny/src/include/netlink-local.h
new file mode 100644
index 0000000000..330100e805
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink-local.h
@@ -0,0 +1,158 @@
+/*
+ * netlink-local.h		Local Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LOCAL_H_
+#define NETLINK_LOCAL_H_
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <limits.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+#include <linux/types.h>
+
+/* local header copies */
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
+#include <linux/gen_stats.h>
+
+#include <netlink/netlink.h>
+#include <netlink/handlers.h>
+#include <netlink/cache.h>
+#include <netlink/object-api.h>
+#include <netlink/cache-api.h>
+#include <netlink-types.h>
+
+struct trans_tbl {
+	int i;
+	const char *a;
+};
+
+#define __ADD(id, name) { .i = id, .a = #name },
+
+struct trans_list {
+	int i;
+	char *a;
+	struct nl_list_head list;
+};
+
+#define NL_DEBUG	1
+
+#define NL_DBG(LVL,FMT,ARG...) \
+	do {} while (0)
+
+#define BUG()                            \
+	do {                                 \
+		fprintf(stderr, "BUG: %s:%d\n",  \
+			__FILE__, __LINE__);         \
+		assert(0);	\
+	} while (0)
+
+extern int __nl_read_num_str_file(const char *path,
+				  int (*cb)(long, const char *));
+
+extern int __trans_list_add(int, const char *, struct nl_list_head *);
+extern void __trans_list_clear(struct nl_list_head *);
+
+extern char *__type2str(int, char *, size_t, struct trans_tbl *, size_t);
+extern int __str2type(const char *, struct trans_tbl *, size_t);
+
+extern char *__list_type2str(int, char *, size_t, struct nl_list_head *);
+extern int __list_str2type(const char *, struct nl_list_head *);
+
+extern char *__flags2str(int, char *, size_t, struct trans_tbl *, size_t);
+extern int __str2flags(const char *, struct trans_tbl *, size_t);
+
+extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);
+
+#ifdef disabled
+static inline struct nl_cache *dp_cache(struct nl_object *obj)
+{
+	if (obj->ce_cache == NULL)
+		return nl_cache_mngt_require(obj->ce_ops->oo_name);
+
+	return obj->ce_cache;
+}
+#endif
+
+static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
+{
+	return cb->cb_set[type](msg, cb->cb_args[type]);
+}
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define __init __attribute__ ((constructor))
+#define __exit __attribute__ ((destructor))
+#undef __deprecated
+#define __deprecated __attribute__ ((deprecated))
+
+#define min(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x > _y ? _x : _y; })
+
+extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
+			  struct nlmsghdr *, struct nl_parser_param *);
+
+
+static inline char *nl_cache_name(struct nl_cache *cache)
+{
+	return cache->c_ops ? cache->c_ops->co_name : "unknown";
+}
+
+#define GENL_FAMILY(id, name) \
+	{ \
+		{ id, NL_ACT_UNSPEC, name }, \
+		END_OF_MSGTYPES_LIST, \
+	}
+
+static inline int wait_for_ack(struct nl_sock *sk)
+{
+	if (sk->s_flags & NL_NO_AUTO_ACK)
+		return 0;
+	else
+		return nl_wait_for_ack(sk);
+}
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink-types.h b/package/libs/libnl-tiny/src/include/netlink-types.h
new file mode 100644
index 0000000000..65f7f6c0b8
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink-types.h
@@ -0,0 +1,88 @@
+/*
+ * netlink-types.h	Netlink Types (Private)
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LOCAL_TYPES_H_
+#define NETLINK_LOCAL_TYPES_H_
+
+#include <netlink/list.h>
+
+struct nl_cache_ops;
+struct nl_sock;
+struct nl_object;
+
+struct nl_cache
+{
+	struct nl_list_head	c_items;
+	int			c_nitems;
+	int                     c_iarg1;
+	int                     c_iarg2;
+	struct nl_cache_ops *   c_ops;
+};
+
+struct nl_cache_assoc
+{
+	struct nl_cache *	ca_cache;
+	change_func_t		ca_change;
+};
+
+struct nl_cache_mngr
+{
+	int			cm_protocol;
+	int			cm_flags;
+	int			cm_nassocs;
+	struct nl_sock *	cm_handle;
+	struct nl_cache_assoc *	cm_assocs;
+};
+
+struct nl_parser_param;
+
+#define LOOSE_COMPARISON	1
+
+
+struct nl_data
+{
+	size_t			d_size;
+	void *			d_data;
+};
+
+struct nl_addr
+{
+	int			a_family;
+	unsigned int		a_maxsize;
+	unsigned int		a_len;
+	int			a_prefixlen;
+	int			a_refcnt;
+	char			a_addr[0];
+};
+
+#define IFQDISCSIZ	32
+
+#define GENL_OP_HAS_POLICY	1
+#define GENL_OP_HAS_DOIT	2
+#define GENL_OP_HAS_DUMPIT	4
+
+struct genl_family_grp {
+	struct genl_family	*family;	/* private */
+	struct nl_list_head	list;		/* private */
+	char			name[GENL_NAMSIZ];
+	u_int32_t		id;
+};
+
+struct genl_family_op
+{
+	uint32_t		o_id;
+	uint32_t		o_flags;
+
+	struct nl_list_head	o_list;
+};
+
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/addr.h b/package/libs/libnl-tiny/src/include/netlink/addr.h
new file mode 100644
index 0000000000..cc3d201f97
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/addr.h
@@ -0,0 +1,69 @@
+/*
+ * netlink/addr.h		Abstract Address
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ADDR_H_
+#define NETLINK_ADDR_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_addr;
+
+/* Creation */
+extern struct nl_addr *	nl_addr_alloc(size_t);
+extern struct nl_addr *	nl_addr_alloc_attr(struct nlattr *, int);
+extern struct nl_addr *	nl_addr_build(int, void *, size_t);
+extern int		nl_addr_parse(const char *, int, struct nl_addr **);
+extern struct nl_addr *	nl_addr_clone(struct nl_addr *);
+
+/* Destroyage */
+extern void		nl_addr_destroy(struct nl_addr *);
+
+/* Usage Management */
+extern struct nl_addr *	nl_addr_get(struct nl_addr *);
+extern void		nl_addr_put(struct nl_addr *);
+extern int		nl_addr_shared(struct nl_addr *);
+
+extern int		nl_addr_cmp(struct nl_addr *, struct nl_addr *);
+extern int		nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
+extern int		nl_addr_iszero(struct nl_addr *);
+extern int		nl_addr_valid(char *, int);
+extern int      	nl_addr_guess_family(struct nl_addr *);
+extern int		nl_addr_fill_sockaddr(struct nl_addr *,
+					      struct sockaddr *, socklen_t *);
+extern int		nl_addr_info(struct nl_addr *, struct addrinfo **);
+extern int		nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen);
+
+/* Access Functions */
+extern void		nl_addr_set_family(struct nl_addr *, int);
+extern int		nl_addr_get_family(struct nl_addr *);
+extern int		nl_addr_set_binary_addr(struct nl_addr *, void *,
+						size_t);
+extern void *		nl_addr_get_binary_addr(struct nl_addr *);
+extern unsigned int	nl_addr_get_len(struct nl_addr *);
+extern void		nl_addr_set_prefixlen(struct nl_addr *, int);
+extern unsigned int	nl_addr_get_prefixlen(struct nl_addr *);
+
+/* Address Family Translations */
+extern char *		nl_af2str(int, char *, size_t);
+extern int		nl_str2af(const char *);
+
+/* Translations to Strings */
+extern char *		nl_addr2str(struct nl_addr *, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/attr.h b/package/libs/libnl-tiny/src/include/netlink/attr.h
new file mode 100644
index 0000000000..3b56a82dc6
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/attr.h
@@ -0,0 +1,726 @@
+/*
+ * netlink/attr.h		Netlink Attributes
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ATTR_H_
+#define NETLINK_ATTR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+#include <netlink/addr.h>
+#include <netlink/data.h>
+#include <netlink/msg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_msg;
+
+/**
+ * @name Basic Attribute Data Types
+ * @{
+ */
+
+ /**
+  * @ingroup attr
+  * Basic attribute data types
+  *
+  * See \ref attr_datatypes for more details.
+  */
+enum {
+	NLA_UNSPEC,	/**< Unspecified type, binary data chunk */
+	NLA_U8,		/**< 8 bit integer */
+	NLA_U16,	/**< 16 bit integer */
+	NLA_U32,	/**< 32 bit integer */
+	NLA_U64,	/**< 64 bit integer */
+	NLA_STRING,	/**< NUL terminated character string */
+	NLA_FLAG,	/**< Flag */
+	NLA_MSECS,	/**< Micro seconds (64bit) */
+	NLA_NESTED,	/**< Nested attributes */
+	__NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+/** @} */
+
+/**
+ * @ingroup attr
+ * Attribute validation policy.
+ *
+ * See \ref attr_datatypes for more details.
+ */
+struct nla_policy {
+	/** Type of attribute or NLA_UNSPEC */
+	uint16_t	type;
+
+	/** Minimal length of payload required */
+	uint16_t	minlen;
+
+	/** Maximal length of payload allowed */
+	uint16_t	maxlen;
+};
+
+/* Attribute parsing */
+extern int		nla_ok(const struct nlattr *, int);
+extern struct nlattr *	nla_next(const struct nlattr *, int *);
+extern int		nla_parse(struct nlattr **, int, struct nlattr *,
+				  int, struct nla_policy *);
+extern int		nla_validate(struct nlattr *, int, int,
+				     struct nla_policy *);
+extern struct nlattr *	nla_find(struct nlattr *, int, int);
+
+/* Unspecific attribute */
+extern struct nlattr *	nla_reserve(struct nl_msg *, int, int);
+extern int		nla_put(struct nl_msg *, int, int, const void *);
+
+/**
+ * nlmsg_find_attr - find a specific attribute in a netlink message
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of familiy specific header
+ * @arg attrtype	type of attribute to look for
+ *
+ * Returns the first attribute which matches the specified type.
+ */
+static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
+{
+	return nla_find(nlmsg_attrdata(nlh, hdrlen),
+			nlmsg_attrlen(nlh, hdrlen), attrtype);
+}
+
+
+/**
+ * Return size of attribute whithout padding.
+ * @arg payload		Payload length of attribute.
+ *
+ * @code
+ *    <-------- nla_attr_size(payload) --------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ * @endcode
+ *
+ * @return Size of attribute in bytes without padding.
+ */
+static inline int nla_attr_size(int payload)
+{
+	return NLA_HDRLEN + payload;
+}
+
+/**
+ * Return size of attribute including padding.
+ * @arg payload		Payload length of attribute.
+ *
+ * @code
+ *    <----------- nla_total_size(payload) ----------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ * @endcode
+ *
+ * @return Size of attribute in bytes.
+ */
+static inline int nla_total_size(int payload)
+{
+	return NLA_ALIGN(nla_attr_size(payload));
+}
+
+/**
+ * Return length of padding at the tail of the attribute.
+ * @arg payload		Payload length of attribute.
+ *
+ * @code
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *                                                <--->  
+ * @endcode
+ *
+ * @return Length of padding in bytes.
+ */
+static inline int nla_padlen(int payload)
+{
+	return nla_total_size(payload) - nla_attr_size(payload);
+}
+
+/**
+ * Return type of the attribute.
+ * @arg nla		Attribute.
+ *
+ * @return Type of attribute.
+ */
+static inline int nla_type(const struct nlattr *nla)
+{
+	return nla->nla_type & NLA_TYPE_MASK;
+}
+
+/**
+ * Return pointer to the payload section.
+ * @arg nla		Attribute.
+ *
+ * @return Pointer to start of payload section.
+ */
+static inline void *nla_data(const struct nlattr *nla)
+{
+	return (char *) nla + NLA_HDRLEN;
+}
+
+/**
+ * Return length of the payload .
+ * @arg nla		Attribute
+ *
+ * @return Length of payload in bytes.
+ */
+static inline int nla_len(const struct nlattr *nla)
+{
+	return nla->nla_len - NLA_HDRLEN;
+}
+
+/**
+ * Copy attribute payload to another memory area.
+ * @arg dest		Pointer to destination memory area.
+ * @arg src		Attribute
+ * @arg count		Number of bytes to copy at most.
+ *
+ * Note: The number of bytes copied is limited by the length of
+ *       the attribute payload.
+ *
+ * @return The number of bytes copied to dest.
+ */
+static inline int nla_memcpy(void *dest, struct nlattr *src, int count)
+{
+	int minlen;
+
+	if (!src)
+		return 0;
+	
+	minlen = min_t(int, count, nla_len(src));
+	memcpy(dest, nla_data(src), minlen);
+
+	return minlen;
+}
+
+
+/**
+ * Add abstract data as unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg data		Abstract data object.
+ *
+ * Equivalent to nla_put() except that the length of the payload is
+ * derived from the abstract data object.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data)
+{
+	return nla_put(msg, attrtype, nl_data_get_size(data),
+		       nl_data_get(data));
+}
+
+/**
+ * Add abstract address as unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg addr		Abstract address object.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr)
+{
+	return nla_put(msg, attrtype, nl_addr_get_len(addr),
+		       nl_addr_get_binary_addr(addr));
+}
+
+/** @} */
+
+/**
+ * @name Integer Attributes
+ */
+
+/**
+ * Add 8 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint8_t), &value);
+}
+
+/**
+ * Return value of 8 bit integer attribute.
+ * @arg nla		8 bit integer attribute
+ *
+ * @return Payload as 8 bit integer.
+ */
+static inline uint8_t nla_get_u8(struct nlattr *nla)
+{
+	return *(uint8_t *) nla_data(nla);
+}
+
+/**
+ * Add 16 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint16_t), &value);
+}
+
+/**
+ * Return payload of 16 bit integer attribute.
+ * @arg nla		16 bit integer attribute
+ *
+ * @return Payload as 16 bit integer.
+ */
+static inline uint16_t nla_get_u16(struct nlattr *nla)
+{
+	return *(uint16_t *) nla_data(nla);
+}
+
+/**
+ * Add 32 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+
+/**
+ * Return payload of 32 bit integer attribute.
+ * @arg nla		32 bit integer attribute.
+ *
+ * @return Payload as 32 bit integer.
+ */
+static inline uint32_t nla_get_u32(struct nlattr *nla)
+{
+	return *(uint32_t *) nla_data(nla);
+}
+
+/**
+ * Add 64 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint64_t), &value);
+}
+
+/**
+ * Return payload of u64 attribute
+ * @arg nla		u64 netlink attribute
+ *
+ * @return Payload as 64 bit integer.
+ */
+static inline uint64_t nla_get_u64(struct nlattr *nla)
+{
+	uint64_t tmp;
+
+	nla_memcpy(&tmp, nla, sizeof(tmp));
+
+	return tmp;
+}
+
+/**
+ * Add string attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg str		NUL terminated string.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
+{
+	return nla_put(msg, attrtype, strlen(str) + 1, str);
+}
+
+/**
+ * Return payload of string attribute.
+ * @arg nla		String attribute.
+ *
+ * @return Pointer to attribute payload.
+ */
+static inline char *nla_get_string(struct nlattr *nla)
+{
+	return (char *) nla_data(nla);
+}
+
+static inline char *nla_strdup(struct nlattr *nla)
+{
+	return strdup(nla_get_string(nla));
+}
+
+/** @} */
+
+/**
+ * @name Flag Attribute
+ */
+
+/**
+ * Add flag netlink attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_flag(struct nl_msg *msg, int attrtype)
+{
+	return nla_put(msg, attrtype, 0, NULL);
+}
+
+/**
+ * Return true if flag attribute is set.
+ * @arg nla		Flag netlink attribute.
+ *
+ * @return True if flag is set, otherwise false.
+ */
+static inline int nla_get_flag(struct nlattr *nla)
+{
+	return !!nla;
+}
+
+/** @} */
+
+/**
+ * @name Microseconds Attribute
+ */
+
+/**
+ * Add a msecs netlink attribute to a netlink message
+ * @arg n		netlink message
+ * @arg attrtype	attribute type
+ * @arg msecs 		number of msecs
+ */
+static inline int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs)
+{
+	return nla_put_u64(n, attrtype, msecs);
+}
+
+/**
+ * Return payload of msecs attribute
+ * @arg nla		msecs netlink attribute
+ *
+ * @return the number of milliseconds.
+ */
+static inline unsigned long nla_get_msecs(struct nlattr *nla)
+{
+	return nla_get_u64(nla);
+}
+
+/**
+ * Add nested attributes to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg nested		Message containing attributes to be nested.
+ *
+ * Takes the attributes found in the \a nested message and appends them
+ * to the message \a msg nested in a container of the type \a attrtype.
+ * The \a nested message may not have a family specific header.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
+{
+	return nla_put(msg, attrtype, nlmsg_len(nested->nm_nlh),
+		       nlmsg_data(nested->nm_nlh));
+}
+
+/**
+ * Start a new level of nested attributes.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type of container.
+ *
+ * @return Pointer to container attribute.
+ */
+static inline struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
+{
+	struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+
+	if (nla_put(msg, attrtype, 0, NULL) < 0)
+		return NULL;
+
+	return start;
+}
+
+/**
+ * Finalize nesting of attributes.
+ * @arg msg		Netlink message.
+ * @arg start		Container attribute as returned from nla_nest_start().
+ *
+ * Corrects the container attribute header to include the appeneded attributes.
+ *
+ * @return 0
+ */
+static inline int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+{
+	start->nla_len = (unsigned char *) nlmsg_tail(msg->nm_nlh) -
+				(unsigned char *) start;
+	return 0;
+}
+
+/**
+ * Create attribute index based on nested attribute
+ * @arg tb		Index array to be filled (maxtype+1 elements).
+ * @arg maxtype		Maximum attribute type expected and accepted.
+ * @arg nla		Nested Attribute.
+ * @arg policy		Attribute validation policy.
+ *
+ * Feeds the stream of attributes nested into the specified attribute
+ * to nla_parse().
+ *
+ * @see nla_parse
+ * @return 0 on success or a negative error code.
+ */
+static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
+		     struct nla_policy *policy)
+{
+	return nla_parse(tb, maxtype, (struct nlattr *)nla_data(nla), nla_len(nla), policy);
+}
+
+/**
+ * Compare attribute payload with memory area.
+ * @arg nla		Attribute.
+ * @arg data		Memory area to compare to.
+ * @arg size		Number of bytes to compare.
+ *
+ * @see memcmp(3)
+ * @return An integer less than, equal to, or greater than zero.
+ */
+static inline int nla_memcmp(const struct nlattr *nla, const void *data, size_t size)
+{
+	int d = nla_len(nla) - size;
+
+	if (d == 0)
+		d = memcmp(nla_data(nla), data, size);
+
+	return d;
+}
+
+/**
+ * Compare string attribute payload with string
+ * @arg nla		Attribute of type NLA_STRING.
+ * @arg str		NUL terminated string.
+ *
+ * @see strcmp(3)
+ * @return An integer less than, equal to, or greater than zero.
+ */
+static inline int nla_strcmp(const struct nlattr *nla, const char *str)
+{
+	int len = strlen(str) + 1;
+	int d = nla_len(nla) - len;
+
+	if (d == 0)
+		d = memcmp(nla_data(nla), str, len);
+
+	return d;
+}
+
+/**
+ * Copy string attribute payload to a buffer.
+ * @arg dst		Pointer to destination buffer.
+ * @arg nla		Attribute of type NLA_STRING.
+ * @arg dstsize		Size of destination buffer in bytes.
+ *
+ * Copies at most dstsize - 1 bytes to the destination buffer.
+ * The result is always a valid NUL terminated string. Unlike
+ * strlcpy the destination buffer is always padded out.
+ *
+ * @return The length of string attribute without the terminating NUL.
+ */
+static inline size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
+{
+	size_t srclen = (size_t)nla_len(nla);
+	char *src = (char*)nla_data(nla);
+
+	if (srclen > 0 && src[srclen - 1] == '\0')
+		srclen--;
+
+	if (dstsize > 0) {
+		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
+
+		memset(dst, 0, dstsize);
+		memcpy(dst, src, len);
+	}
+
+	return srclen;
+}
+
+
+/**
+ * @name Attribute Construction (Exception Based)
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Add unspecific attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg attrlen		Length of attribute payload.
+ * @arg data		Head of attribute payload.
+ */
+#define NLA_PUT(msg, attrtype, attrlen, data) \
+	do { \
+		if (nla_put(msg, attrtype, attrlen, data) < 0) \
+			goto nla_put_failure; \
+	} while(0)
+
+/**
+ * @ingroup attr
+ * Add atomic type attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg type		Atomic type.
+ * @arg attrtype	Attribute type.
+ * @arg value		Head of attribute payload.
+ */
+#define NLA_PUT_TYPE(msg, type, attrtype, value) \
+	do { \
+		type __tmp = value; \
+		NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \
+	} while(0)
+
+/**
+ * Add 8 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U8(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
+
+/**
+ * Add 16 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U16(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
+
+/**
+ * Add 32 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U32(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
+
+/**
+ * Add 64 bit integer attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		Numeric value.
+ */
+#define NLA_PUT_U64(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
+
+/**
+ * Add string attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg value		NUL terminated character string.
+ */
+#define NLA_PUT_STRING(msg, attrtype, value) \
+	NLA_PUT(msg, attrtype, strlen(value) + 1, value)
+
+/**
+ * Add flag attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ */
+#define NLA_PUT_FLAG(msg, attrtype) \
+	NLA_PUT(msg, attrtype, 0, NULL)
+
+/**
+ * Add msecs attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg msecs		Numeric value in micro seconds.
+ */
+#define NLA_PUT_MSECS(msg, attrtype, msecs) \
+	NLA_PUT_U64(msg, attrtype, msecs)
+
+/**
+ * Add address attribute to netlink message.
+ * @arg msg		Netlink message.
+ * @arg attrtype	Attribute type.
+ * @arg addr		Abstract address object.
+ */
+#define NLA_PUT_ADDR(msg, attrtype, addr) \
+	NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \
+		nl_addr_get_binary_addr(addr))
+
+/** @} */
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of attributes
+ * @arg pos	loop counter, set to current attribute
+ * @arg head	head of attribute stream
+ * @arg len	length of attribute stream
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr(pos, head, len, rem) \
+	for (pos = head, rem = len; \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of nested attributes
+ * @arg pos	loop counter, set to current attribute
+ * @arg nla	attribute containing the nested attributes
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_nested(pos, nla, rem) \
+	for (pos = (struct nlattr *)nla_data(nla), rem = nla_len(nla); \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/cache-api.h b/package/libs/libnl-tiny/src/include/netlink/cache-api.h
new file mode 100644
index 0000000000..22fc449d1b
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/cache-api.h
@@ -0,0 +1,199 @@
+/*
+ * netlink/cache-api.h		Caching API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CACHE_API_H_
+#define NETLINK_CACHE_API_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup cache
+ * @defgroup cache_api Cache Implementation
+ * @brief
+ *
+ * @par 1) Cache Definition
+ * @code
+ * struct nl_cache_ops my_cache_ops = {
+ * 	.co_name		= "route/link",
+ * 	.co_protocol		= NETLINK_ROUTE,
+ * 	.co_hdrsize		= sizeof(struct ifinfomsg),
+ * 	.co_obj_ops		= &my_obj_ops,
+ * };
+ * @endcode
+ *
+ * @par 2) 
+ * @code
+ * // The simplest way to fill a cache is by providing a request-update
+ * // function which must trigger a complete dump on the kernel-side of
+ * // whatever the cache covers.
+ * static int my_request_update(struct nl_cache *cache,
+ * 				struct nl_sock *socket)
+ * {
+ * 	// In this example, we request a full dump of the interface table
+ * 	return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
+ * }
+ *
+ * // The resulting netlink messages sent back will be fed into a message
+ * // parser one at a time. The message parser has to extract all relevant
+ * // information from the message and create an object reflecting the
+ * // contents of the message and pass it on to the parser callback function
+ * // provide which will add the object to the cache.
+ * static int my_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ * 			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
+ * {
+ * 	struct my_obj *obj;
+ *
+ * 	obj = my_obj_alloc();
+ * 	obj->ce_msgtype = nlh->nlmsg_type;
+ *
+ * 	// Parse the netlink message and continue creating the object.
+ *
+ * 	err = pp->pp_cb((struct nl_object *) obj, pp);
+ * 	if (err < 0)
+ * 		goto errout;
+ * }
+ *
+ * struct nl_cache_ops my_cache_ops = {
+ * 	...
+ * 	.co_request_update	= my_request_update,
+ * 	.co_msg_parser		= my_msg_parser,
+ * };
+ * @endcode
+ *
+ * @par 3) Notification based Updates
+ * @code
+ * // Caches can be kept up-to-date based on notifications if the kernel
+ * // sends out notifications whenever an object is added/removed/changed.
+ * //
+ * // It is trivial to support this, first a list of groups needs to be
+ * // defined which are required to join in order to receive all necessary
+ * // notifications. The groups are separated by address family to support
+ * // the common situation where a separate group is used for each address
+ * // family. If there is only one group, simply specify AF_UNSPEC.
+ * static struct nl_af_group addr_groups[] = {
+ * 	{ AF_INET,	RTNLGRP_IPV4_IFADDR },
+ * 	{ AF_INET6,	RTNLGRP_IPV6_IFADDR },
+ * 	{ END_OF_GROUP_LIST },
+ * };
+ *
+ * // In order for the caching system to know the meaning of each message
+ * // type it requires a table which maps each supported message type to
+ * // a cache action, e.g. RTM_NEWADDR means address has been added or
+ * // updated, RTM_DELADDR means address has been removed.
+ * static struct nl_cache_ops rtnl_addr_ops = {
+ * 	...
+ * 	.co_msgtypes		= {
+ * 					{ RTM_NEWADDR, NL_ACT_NEW, "new" },
+ * 					{ RTM_DELADDR, NL_ACT_DEL, "del" },
+ * 					{ RTM_GETADDR, NL_ACT_GET, "get" },
+ * 					END_OF_MSGTYPES_LIST,
+ * 				},
+ * 	.co_groups		= addr_groups,
+ * };
+ *
+ * // It is now possible to keep the cache up-to-date using the cache manager.
+ * @endcode
+ * @{
+ */
+
+enum {
+	NL_ACT_UNSPEC,
+	NL_ACT_NEW,
+	NL_ACT_DEL,
+	NL_ACT_GET,
+	NL_ACT_SET,
+	NL_ACT_CHANGE,
+	__NL_ACT_MAX,
+};
+
+#define NL_ACT_MAX (__NL_ACT_MAX - 1)
+
+#define END_OF_MSGTYPES_LIST	{ -1, -1, NULL }
+
+/**
+ * Message type to cache action association
+ */
+struct nl_msgtype
+{
+	/** Netlink message type */
+	int			mt_id;
+
+	/** Cache action to take */
+	int			mt_act;
+
+	/** Name of operation for human-readable printing */
+	char *			mt_name;
+};
+
+/**
+ * Address family to netlink group association
+ */
+struct nl_af_group
+{
+	/** Address family */
+	int			ag_family;
+
+	/** Netlink group identifier */
+	int			ag_group;
+};
+
+#define END_OF_GROUP_LIST AF_UNSPEC, 0
+
+struct nl_parser_param
+{
+	int             (*pp_cb)(struct nl_object *, struct nl_parser_param *);
+	void *            pp_arg;
+};
+
+/**
+ * Cache Operations
+ */
+struct nl_cache_ops
+{
+	char  *			co_name;
+
+	int			co_hdrsize;
+	int			co_protocol;
+	struct nl_af_group *	co_groups;
+	
+	/**
+	 * Called whenever an update of the cache is required. Must send
+	 * a request message to the kernel requesting a complete dump.
+	 */
+	int   (*co_request_update)(struct nl_cache *, struct nl_sock *);
+
+	/**
+	 * Called whenever a message was received that needs to be parsed.
+	 * Must parse the message and call the paser callback function
+	 * (nl_parser_param) provided via the argument.
+	 */
+	int   (*co_msg_parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+			       struct nlmsghdr *, struct nl_parser_param *);
+
+	struct nl_object_ops *	co_obj_ops;
+
+	struct nl_cache_ops *co_next;
+	struct nl_cache *co_major_cache;
+	struct genl_ops *	co_genl;
+	struct nl_msgtype	co_msgtypes[];
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/cache.h b/package/libs/libnl-tiny/src/include/netlink/cache.h
new file mode 100644
index 0000000000..09719f3a74
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/cache.h
@@ -0,0 +1,128 @@
+/*
+ * netlink/cache.h		Caching Module
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CACHE_H_
+#define NETLINK_CACHE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/cache-api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache;
+
+typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int);
+
+/* Access Functions */
+extern int			nl_cache_nitems(struct nl_cache *);
+extern int			nl_cache_nitems_filter(struct nl_cache *,
+						       struct nl_object *);
+extern struct nl_cache_ops *	nl_cache_get_ops(struct nl_cache *);
+extern struct nl_object *	nl_cache_get_first(struct nl_cache *);
+extern struct nl_object *	nl_cache_get_last(struct nl_cache *);
+extern struct nl_object *	nl_cache_get_next(struct nl_object *);
+extern struct nl_object *	nl_cache_get_prev(struct nl_object *);
+
+extern struct nl_cache *	nl_cache_alloc(struct nl_cache_ops *);
+extern int			nl_cache_alloc_and_fill(struct nl_cache_ops *,
+							struct nl_sock *,
+							struct nl_cache **);
+extern int			nl_cache_alloc_name(const char *,
+						    struct nl_cache **);
+extern struct nl_cache *	nl_cache_subset(struct nl_cache *,
+						struct nl_object *);
+extern void			nl_cache_clear(struct nl_cache *);
+extern void			nl_cache_free(struct nl_cache *);
+
+/* Cache modification */
+extern int			nl_cache_add(struct nl_cache *,
+					     struct nl_object *);
+extern int			nl_cache_parse_and_add(struct nl_cache *,
+						       struct nl_msg *);
+extern void			nl_cache_remove(struct nl_object *);
+extern int			nl_cache_refill(struct nl_sock *,
+						struct nl_cache *);
+extern int			nl_cache_pickup(struct nl_sock *,
+						struct nl_cache *);
+extern int			nl_cache_resync(struct nl_sock *,
+						struct nl_cache *,
+						change_func_t);
+extern int			nl_cache_include(struct nl_cache *,
+						 struct nl_object *,
+						 change_func_t);
+
+/* General */
+extern int			nl_cache_is_empty(struct nl_cache *);
+extern void			nl_cache_mark_all(struct nl_cache *);
+
+/* Dumping */
+extern void			nl_cache_dump(struct nl_cache *,
+					      struct nl_dump_params *);
+extern void			nl_cache_dump_filter(struct nl_cache *,
+						     struct nl_dump_params *,
+						     struct nl_object *);
+
+/* Iterators */
+#ifdef disabled
+extern void			nl_cache_foreach(struct nl_cache *,
+						 void (*cb)(struct nl_object *,
+							    void *),
+						 void *arg);
+extern void			nl_cache_foreach_filter(struct nl_cache *,
+							struct nl_object *,
+							void (*cb)(struct
+								   nl_object *,
+								   void *),
+							void *arg);
+#endif
+
+/* --- cache management --- */
+
+/* Cache type management */
+extern struct nl_cache_ops *	nl_cache_ops_lookup(const char *);
+extern struct nl_cache_ops *	nl_cache_ops_associate(int, int);
+extern struct nl_msgtype *	nl_msgtype_lookup(struct nl_cache_ops *, int);
+extern void			nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *);
+extern int			nl_cache_mngt_register(struct nl_cache_ops *);
+extern int			nl_cache_mngt_unregister(struct nl_cache_ops *);
+
+/* Global cache provisioning/requiring */
+extern void			nl_cache_mngt_provide(struct nl_cache *);
+extern void			nl_cache_mngt_unprovide(struct nl_cache *);
+extern struct nl_cache *	nl_cache_mngt_require(const char *);
+
+struct nl_cache_mngr;
+
+#define NL_AUTO_PROVIDE		1
+
+extern int			nl_cache_mngr_alloc(struct nl_sock *,
+						    int, int,
+						    struct nl_cache_mngr **);
+extern int			nl_cache_mngr_add(struct nl_cache_mngr *,
+						  const char *,
+						  change_func_t,
+						  struct nl_cache **);
+extern int			nl_cache_mngr_get_fd(struct nl_cache_mngr *);
+extern int			nl_cache_mngr_poll(struct nl_cache_mngr *,
+						   int);
+extern int			nl_cache_mngr_data_ready(struct nl_cache_mngr *);
+extern void			nl_cache_mngr_free(struct nl_cache_mngr *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/data.h b/package/libs/libnl-tiny/src/include/netlink/data.h
new file mode 100644
index 0000000000..071159ee5b
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/data.h
@@ -0,0 +1,41 @@
+/*
+ * netlink/data.h	Abstract Data
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DATA_H_
+#define NETLINK_DATA_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_data;
+
+/* General */
+extern struct nl_data *	nl_data_alloc(void *, size_t);
+extern struct nl_data * nl_data_alloc_attr(struct nlattr *);
+extern struct nl_data *	nl_data_clone(struct nl_data *);
+extern int		nl_data_append(struct nl_data *, void *, size_t);
+extern void		nl_data_free(struct nl_data *);
+
+/* Access Functions */
+extern void *		nl_data_get(struct nl_data *);
+extern size_t		nl_data_get_size(struct nl_data *);
+
+/* Misc */
+extern int		nl_data_cmp(struct nl_data *, struct nl_data *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/errno.h b/package/libs/libnl-tiny/src/include/netlink/errno.h
new file mode 100644
index 0000000000..f8b5130c22
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/errno.h
@@ -0,0 +1,64 @@
+/*
+ * netlink/errno.h		Error Numbers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ERRNO_H_
+#define NETLINK_ERRNO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NLE_SUCCESS		0
+#define NLE_FAILURE		1
+#define NLE_INTR		2
+#define NLE_BAD_SOCK		3
+#define NLE_AGAIN		4
+#define NLE_NOMEM		5
+#define NLE_EXIST		6
+#define NLE_INVAL		7
+#define NLE_RANGE		8
+#define NLE_MSGSIZE		9
+#define NLE_OPNOTSUPP		10
+#define NLE_AF_NOSUPPORT	11
+#define NLE_OBJ_NOTFOUND	12
+#define NLE_NOATTR		13
+#define NLE_MISSING_ATTR	14
+#define NLE_AF_MISMATCH		15
+#define NLE_SEQ_MISMATCH	16
+#define NLE_MSG_OVERFLOW	17
+#define NLE_MSG_TRUNC		18
+#define NLE_NOADDR		19
+#define NLE_SRCRT_NOSUPPORT	20
+#define NLE_MSG_TOOSHORT	21
+#define NLE_MSGTYPE_NOSUPPORT	22
+#define NLE_OBJ_MISMATCH	23
+#define NLE_NOCACHE		24
+#define NLE_BUSY		25
+#define NLE_PROTO_MISMATCH	26
+#define NLE_NOACCESS		27
+#define NLE_PERM		28
+#define NLE_PKTLOC_FILE		29
+#define NLE_PARSE_ERR		30
+#define NLE_NODEV		31
+#define NLE_IMMUTABLE		32
+#define NLE_DUMP_INTR		33
+
+#define NLE_MAX			NLE_DUMP_INTR
+
+extern const char *	nl_geterror(int);
+extern void		nl_perror(int, const char *);
+extern int		nl_syserr2nlerr(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/genl/ctrl.h b/package/libs/libnl-tiny/src/include/netlink/genl/ctrl.h
new file mode 100644
index 0000000000..26a0a9967b
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/genl/ctrl.h
@@ -0,0 +1,40 @@
+/*
+ * netlink/genl/ctrl.h		Generic Netlink Controller
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_CTRL_H_
+#define NETLINK_GENL_CTRL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct genl_family;
+
+extern int			genl_ctrl_alloc_cache(struct nl_sock *,
+						      struct nl_cache **);
+extern struct genl_family *	genl_ctrl_search(struct nl_cache *, int);
+extern struct genl_family *	genl_ctrl_search_by_name(struct nl_cache *,
+							 const char *);
+extern int			genl_ctrl_resolve(struct nl_sock *,
+						  const char *);
+extern int 			genl_ctrl_resolve_grp(struct nl_sock *sk,
+						      const char *family,
+						      const char *grp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/genl/family.h b/package/libs/libnl-tiny/src/include/netlink/genl/family.h
new file mode 100644
index 0000000000..8a1a38ba25
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/genl/family.h
@@ -0,0 +1,134 @@
+/*
+ * netlink/genl/family.h	Generic Netlink Family
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_FAMILY_H_
+#define NETLINK_GENL_FAMILY_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond SKIP */
+#define FAMILY_ATTR_ID		0x01
+#define FAMILY_ATTR_NAME	0x02
+#define FAMILY_ATTR_VERSION	0x04
+#define FAMILY_ATTR_HDRSIZE	0x08
+#define FAMILY_ATTR_MAXATTR	0x10
+#define FAMILY_ATTR_OPS		0x20
+
+
+struct genl_family
+{
+	NLHDR_COMMON
+
+	uint16_t		gf_id;
+	char 			gf_name[GENL_NAMSIZ];
+	uint32_t		gf_version;
+	uint32_t		gf_hdrsize;
+	uint32_t		gf_maxattr;
+
+	struct nl_list_head	gf_ops;
+	struct nl_list_head	gf_mc_grps;
+};
+
+
+extern struct genl_family *	genl_family_alloc(void);
+extern void			genl_family_put(struct genl_family *);
+
+extern int			genl_family_add_op(struct genl_family *,
+						   int, int);
+extern int 			genl_family_add_grp(struct genl_family *,
+					uint32_t , const char *);
+
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+static inline unsigned int genl_family_get_id(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_ID)
+		return family->gf_id;
+	else
+		return 0;
+}
+
+static inline void genl_family_set_id(struct genl_family *family, unsigned int id)
+{
+	family->gf_id = id;
+	family->ce_mask |= FAMILY_ATTR_ID;
+}
+
+static inline char *genl_family_get_name(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_NAME)
+		return family->gf_name;
+	else
+		return NULL;
+}
+
+static inline void genl_family_set_name(struct genl_family *family, const char *name)
+{
+	strncpy(family->gf_name, name, GENL_NAMSIZ-1);
+	family->ce_mask |= FAMILY_ATTR_NAME;
+}
+
+static inline uint8_t genl_family_get_version(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_VERSION)
+		return family->gf_version;
+	else
+		return 0;
+}
+
+static inline void genl_family_set_version(struct genl_family *family, uint8_t version)
+{
+	family->gf_version = version;
+	family->ce_mask |= FAMILY_ATTR_VERSION;
+}
+
+static inline uint32_t genl_family_get_hdrsize(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
+		return family->gf_hdrsize;
+	else
+		return 0;
+}
+
+static inline void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
+{
+	family->gf_hdrsize = hdrsize;
+	family->ce_mask |= FAMILY_ATTR_HDRSIZE;
+}
+
+static inline uint32_t genl_family_get_maxattr(struct genl_family *family)
+{
+	if (family->ce_mask & FAMILY_ATTR_MAXATTR)
+		return family->gf_maxattr;
+	else
+		return family->gf_maxattr;
+}
+
+static inline void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
+{
+	family->gf_maxattr = maxattr;
+	family->ce_mask |= FAMILY_ATTR_MAXATTR;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/genl/genl.h b/package/libs/libnl-tiny/src/include/netlink/genl/genl.h
new file mode 100644
index 0000000000..3f3340cfdc
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/genl/genl.h
@@ -0,0 +1,47 @@
+/*
+ * netlink/genl/genl.h		Generic Netlink
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_H_
+#define NETLINK_GENL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int		genl_connect(struct nl_sock *);
+
+extern int		genl_send_simple(struct nl_sock *, int, int,
+					 int, int);
+
+extern void *		genlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+				    int, int, int, uint8_t, uint8_t);
+
+extern int		genlmsg_valid_hdr(struct nlmsghdr *, int);
+extern int		genlmsg_validate(struct nlmsghdr *, int, int,
+					 struct nla_policy *);
+extern int		genlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+				      int, struct nla_policy *);
+extern void *		genlmsg_data(const struct genlmsghdr *);
+extern int		genlmsg_len(const struct genlmsghdr *);
+extern struct nlattr *	genlmsg_attrdata(const struct genlmsghdr *, int);
+extern int		genlmsg_attrlen(const struct genlmsghdr *, int);
+
+extern char *		genl_op2name(int, int, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/genl/mngt.h b/package/libs/libnl-tiny/src/include/netlink/genl/mngt.h
new file mode 100644
index 0000000000..8b0244f2cc
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/genl/mngt.h
@@ -0,0 +1,87 @@
+/*
+ * netlink/genl/mngt.h		Generic Netlink Management
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_MNGT_H_
+#define NETLINK_GENL_MNGT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache_ops;
+
+struct genl_info
+{
+	struct sockaddr_nl *    who;
+	struct nlmsghdr *       nlh;
+	struct genlmsghdr *     genlhdr;
+	void *                  userhdr;
+	struct nlattr **        attrs;
+};
+
+/**
+ * @ingroup genl_mngt
+ * Generic Netlink Command
+ */
+struct genl_cmd
+{
+	/** Unique command identifier */
+	int			c_id;
+
+	/** Name/description of command */
+	char *			c_name;
+
+	/**
+	 * Maximum attribute identifier, must be provided if
+	 * a message parser is available.
+	 */
+	int			c_maxattr;
+
+	int		      (*c_msg_parser)(struct nl_cache_ops *,
+					      struct genl_cmd *,
+					      struct genl_info *, void *);
+
+	/**
+	 * Attribute validation policy (optional)
+	 */
+	struct nla_policy *	c_attr_policy;
+};
+
+/**
+ * @ingroup genl_mngt
+ * Generic Netlink Operations
+ */
+struct genl_ops
+{
+	int			o_family;
+	int			o_id;
+	char *			o_name;
+	struct nl_cache_ops *	o_cache_ops;
+	struct genl_cmd	*	o_cmds;
+	int			o_ncmds;
+
+	/* linked list of all genl cache operations */
+	struct nl_list_head	o_list;
+};
+
+
+extern int		genl_register(struct nl_cache_ops *);
+extern void		genl_unregister(struct nl_cache_ops *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/handlers.h b/package/libs/libnl-tiny/src/include/netlink/handlers.h
new file mode 100644
index 0000000000..f5c933d0d7
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/handlers.h
@@ -0,0 +1,231 @@
+/*
+ * netlink/handlers.c	default netlink message handlers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_HANDLERS_H_
+#define NETLINK_HANDLERS_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netlink/netlink-compat.h>
+#include <netlink/netlink-kernel.h>
+#include <netlink/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nl_msg;
+struct nl_cb;
+/**
+ * @name Callback Typedefs
+ * @{
+ */
+
+/**
+ * nl_recvmsgs() callback for message processing customization
+ * @ingroup cb
+ * @arg msg		netlink message being processed
+ * @arg arg		argument passwd on through caller
+ */
+typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
+
+/**
+ * nl_recvmsgs() callback for error message processing customization
+ * @ingroup cb
+ * @arg nla		netlink address of the peer
+ * @arg nlerr		netlink error message being processed
+ * @arg arg		argument passed on through caller
+ */
+typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla,
+				   struct nlmsgerr *nlerr, void *arg);
+
+/** @} */
+
+/**
+ * Callback actions
+ * @ingroup cb
+ */
+enum nl_cb_action {
+	/** Proceed with wathever would come next */
+	NL_OK,
+	/** Skip this message */
+	NL_SKIP,
+	/** Stop parsing altogether and discard remaining messages */
+	NL_STOP,
+};
+
+/**
+ * Callback kinds
+ * @ingroup cb
+ */
+enum nl_cb_kind {
+	/** Default handlers (quiet) */
+	NL_CB_DEFAULT,
+	/** Verbose default handlers (error messages printed) */
+	NL_CB_VERBOSE,
+	/** Debug handlers for debugging */
+	NL_CB_DEBUG,
+	/** Customized handler specified by the user */
+	NL_CB_CUSTOM,
+	__NL_CB_KIND_MAX,
+};
+
+#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1)
+
+/**
+ * Callback types
+ * @ingroup cb
+ */
+enum nl_cb_type {
+	/** Message is valid */
+	NL_CB_VALID,
+	/** Last message in a series of multi part messages received */
+	NL_CB_FINISH,
+	/** Report received that data was lost */
+	NL_CB_OVERRUN,
+	/** Message wants to be skipped */
+	NL_CB_SKIPPED,
+	/** Message is an acknowledge */
+	NL_CB_ACK,
+	/** Called for every message received */
+	NL_CB_MSG_IN,
+	/** Called for every message sent out except for nl_sendto() */
+	NL_CB_MSG_OUT,
+	/** Message is malformed and invalid */
+	NL_CB_INVALID,
+	/** Called instead of internal sequence number checking */
+	NL_CB_SEQ_CHECK,
+	/** Sending of an acknowledge message has been requested */
+	NL_CB_SEND_ACK,
+	__NL_CB_TYPE_MAX,
+};
+
+#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1)
+
+struct nl_cb
+{
+	nl_recvmsg_msg_cb_t	cb_set[NL_CB_TYPE_MAX+1];
+	void *			cb_args[NL_CB_TYPE_MAX+1];
+	
+	nl_recvmsg_err_cb_t	cb_err;
+	void *			cb_err_arg;
+
+	/** May be used to replace nl_recvmsgs with your own implementation
+	 * in all internal calls to nl_recvmsgs. */
+	int			(*cb_recvmsgs_ow)(struct nl_sock *,
+						  struct nl_cb *);
+
+	/** Overwrite internal calls to nl_recv, must return the number of
+	 * octets read and allocate a buffer for the received data. */
+	int			(*cb_recv_ow)(struct nl_sock *,
+					      struct sockaddr_nl *,
+					      unsigned char **,
+					      struct ucred **);
+
+	/** Overwrites internal calls to nl_send, must send the netlink
+	 * message. */
+	int			(*cb_send_ow)(struct nl_sock *,
+					      struct nl_msg *);
+
+	int			cb_refcnt;
+};
+
+
+extern struct nl_cb *	nl_cb_alloc(enum nl_cb_kind);
+extern struct nl_cb *	nl_cb_clone(struct nl_cb *);
+extern void		nl_cb_put(struct nl_cb *);
+
+extern int  nl_cb_set(struct nl_cb *, enum nl_cb_type, enum nl_cb_kind,
+		      nl_recvmsg_msg_cb_t, void *);
+extern int  nl_cb_err(struct nl_cb *, enum nl_cb_kind, nl_recvmsg_err_cb_t,
+		      void *);
+
+static inline struct nl_cb *nl_cb_get(struct nl_cb *cb)
+{
+	cb->cb_refcnt++;
+
+	return cb;
+}
+
+/**
+ * Set up a all callbacks
+ * @arg cb		callback set
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passwd to callback function
+ *
+ * @return 0 on success or a negative error code
+ */
+static inline int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
+		  nl_recvmsg_msg_cb_t func, void *arg)
+{
+	int i, err;
+
+	for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
+		err = nl_cb_set(cb,(enum nl_cb_type)i, kind, func, arg);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+
+/**
+ * @name Overwriting
+ * @{
+ */
+
+/**
+ * Overwrite internal calls to nl_recvmsgs()
+ * @arg cb		callback set
+ * @arg func		replacement callback for nl_recvmsgs()
+ */
+static inline void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
+			      int (*func)(struct nl_sock *, struct nl_cb *))
+{
+	cb->cb_recvmsgs_ow = func;
+}
+
+/**
+ * Overwrite internal calls to nl_recv()
+ * @arg cb		callback set
+ * @arg func		replacement callback for nl_recv()
+ */
+static inline void nl_cb_overwrite_recv(struct nl_cb *cb,
+			  int (*func)(struct nl_sock *, struct sockaddr_nl *,
+				      unsigned char **, struct ucred **))
+{
+	cb->cb_recv_ow = func;
+}
+
+/**
+ * Overwrite internal calls to nl_send()
+ * @arg cb		callback set
+ * @arg func		replacement callback for nl_send()
+ */
+static inline void nl_cb_overwrite_send(struct nl_cb *cb,
+			  int (*func)(struct nl_sock *, struct nl_msg *))
+{
+	cb->cb_send_ow = func;
+}
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/list.h b/package/libs/libnl-tiny/src/include/netlink/list.h
new file mode 100644
index 0000000000..c6876a77f7
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/list.h
@@ -0,0 +1,88 @@
+/*
+ * netlink/list.h	Netlink List Utilities
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LIST_H_
+#define NETLINK_LIST_H_
+
+struct nl_list_head
+{
+	struct nl_list_head *	next;
+	struct nl_list_head *	prev;
+};
+
+
+static inline void __nl_list_add(struct nl_list_head *obj,
+				 struct nl_list_head *prev,
+				 struct nl_list_head *next)
+{
+	prev->next = obj;
+	obj->prev = prev;
+	next->prev = obj;
+	obj->next = next;
+}
+
+static inline void nl_list_add_tail(struct nl_list_head *obj,
+				    struct nl_list_head *head)
+{
+	__nl_list_add(obj, head->prev, head);
+}
+
+static inline void nl_list_add_head(struct nl_list_head *obj,
+				    struct nl_list_head *head)
+{
+	__nl_list_add(obj, head, head->next);
+}
+
+static inline void nl_list_del(struct nl_list_head *obj)
+{
+	obj->next->prev = obj->prev;
+	obj->prev->next = obj->next;
+}
+
+static inline int nl_list_empty(struct nl_list_head *head)
+{
+	return head->next == head;
+}
+
+#define nl_container_of(ptr, type, member) ({			\
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+        (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
+
+#define nl_list_entry(ptr, type, member) \
+	nl_container_of(ptr, type, member)
+
+#define nl_list_at_tail(pos, head, member) \
+	((pos)->member.next == (head))
+
+#define nl_list_at_head(pos, head, member) \
+	((pos)->member.prev == (head))
+
+#define NL_LIST_HEAD(name) \
+	struct nl_list_head name = { &(name), &(name) }
+
+#define nl_list_first_entry(head, type, member)			\
+	nl_list_entry((head)->next, type, member)
+
+#define nl_list_for_each_entry(pos, head, member)				\
+	for (pos = nl_list_entry((head)->next, typeof(*pos), member);	\
+	     &(pos)->member != (head); 	\
+	     (pos) = nl_list_entry((pos)->member.next, typeof(*(pos)), member))
+
+#define nl_list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = nl_list_entry((head)->next, typeof(*pos), member),	\
+		n = nl_list_entry(pos->member.next, typeof(*pos), member);	\
+	     &(pos)->member != (head); 					\
+	     pos = n, n = nl_list_entry(n->member.next, typeof(*n), member))
+
+#define nl_init_list_head(head) \
+	do { (head)->next = (head); (head)->prev = (head); } while (0)
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/msg.h b/package/libs/libnl-tiny/src/include/netlink/msg.h
new file mode 100644
index 0000000000..b3e2b0b2b9
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/msg.h
@@ -0,0 +1,308 @@
+/*
+ * netlink/msg.c		Netlink Messages Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_MSG_H_
+#define NETLINK_MSG_H_
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nla_policy;
+
+#define NL_DONTPAD	0
+
+/**
+ * @ingroup msg
+ * @brief
+ * Will cause the netlink pid to be set to the pid assigned to
+ * the netlink handle (socket) just before sending the message off.
+ * @note Requires the use of nl_send_auto_complete()!
+ */
+#define NL_AUTO_PID	0
+
+/**
+ * @ingroup msg
+ * @brief
+ * May be used to refer to a sequence number which should be
+ * automatically set just before sending the message off.
+ * @note Requires the use of nl_send_auto_complete()!
+ */
+#define NL_AUTO_SEQ	0
+
+#define NL_MSG_CRED_PRESENT 1
+
+struct nl_msg
+{
+	int			nm_protocol;
+	int			nm_flags;
+	struct sockaddr_nl	nm_src;
+	struct sockaddr_nl	nm_dst;
+	struct ucred		nm_creds;
+	struct nlmsghdr *	nm_nlh;
+	size_t			nm_size;
+	int			nm_refcnt;
+};
+
+
+struct nl_msg;
+struct nl_tree;
+struct ucred;
+
+/* message parsing */
+extern int		  nlmsg_ok(const struct nlmsghdr *, int);
+extern struct nlmsghdr *  nlmsg_next(struct nlmsghdr *, int *);
+extern int		  nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+				      int, struct nla_policy *);
+extern int		  nlmsg_validate(struct nlmsghdr *, int, int,
+					 struct nla_policy *);
+
+extern struct nl_msg *	  nlmsg_alloc(void);
+extern struct nl_msg *	  nlmsg_alloc_size(size_t);
+extern struct nl_msg *	  nlmsg_alloc_simple(int, int);
+extern void		  nlmsg_set_default_size(size_t);
+extern struct nl_msg *	  nlmsg_inherit(struct nlmsghdr *);
+extern struct nl_msg *	  nlmsg_convert(struct nlmsghdr *);
+extern void *		  nlmsg_reserve(struct nl_msg *, size_t, int);
+extern int		  nlmsg_append(struct nl_msg *, void *, size_t, int);
+
+extern struct nlmsghdr *  nlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+				    int, int, int);
+extern void		  nlmsg_free(struct nl_msg *);
+
+extern int		  nl_msg_parse(struct nl_msg *,
+				       void (*cb)(struct nl_object *, void *),
+				       void *);
+
+extern void		nl_msg_dump(struct nl_msg *, FILE *);
+
+/**
+ * length of netlink message not including padding
+ * @arg payload		length of message payload
+ */
+static inline int nlmsg_msg_size(int payload)
+{
+	return NLMSG_HDRLEN + payload;
+}
+
+/**
+ * length of netlink message including padding
+ * @arg payload		length of message payload
+ */
+static inline int nlmsg_total_size(int payload)
+{
+	return NLMSG_ALIGN(nlmsg_msg_size(payload));
+}
+
+/**
+ * length of padding at the message's tail
+ * @arg payload		length of message payload
+ */
+static inline int nlmsg_padlen(int payload)
+{
+	return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
+}
+
+/**
+ * head of message payload
+ * @arg nlh		netlink messsage header
+ */
+static inline void *nlmsg_data(const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_HDRLEN;
+}
+
+static inline void *nlmsg_tail(const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
+}
+
+/**
+ * length of message payload
+ * @arg nlh		netlink message header
+ */
+static inline int nlmsg_len(const struct nlmsghdr *nlh)
+{
+	return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+/**
+ * head of attributes data
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of family specific header
+ */
+static inline struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
+{
+	unsigned char *data = (unsigned char*)nlmsg_data(nlh);
+	return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
+}
+
+/**
+ * length of attributes data
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of family specific header
+ */
+static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
+{
+	return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
+}
+
+static inline int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
+{
+	if (nlh->nlmsg_len < (uint)nlmsg_msg_size(hdrlen))
+		return 0;
+
+	return 1;
+}
+
+
+static inline void nlmsg_set_proto(struct nl_msg *msg, int protocol)
+{
+	msg->nm_protocol = protocol;
+}
+
+static inline int nlmsg_get_proto(struct nl_msg *msg)
+{
+	return msg->nm_protocol;
+}
+
+static inline size_t nlmsg_get_max_size(struct nl_msg *msg)
+{
+	return msg->nm_size;
+}
+
+static inline void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
+{
+	memcpy(&msg->nm_src, addr, sizeof(*addr));
+}
+
+static inline struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
+{
+	return &msg->nm_src;
+}
+
+static inline void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
+{
+	memcpy(&msg->nm_dst, addr, sizeof(*addr));
+}
+
+static inline struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
+{
+	return &msg->nm_dst;
+}
+
+static inline void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
+{
+	memcpy(&msg->nm_creds, creds, sizeof(*creds));
+	msg->nm_flags |= NL_MSG_CRED_PRESENT;
+}
+
+static inline struct ucred *nlmsg_get_creds(struct nl_msg *msg)
+{
+	if (msg->nm_flags & NL_MSG_CRED_PRESENT)
+		return &msg->nm_creds;
+	return NULL;
+}
+
+/**
+ * Return actual netlink message
+ * @arg n		netlink message
+ * 
+ * Returns the actual netlink message casted to the type of the netlink
+ * message header.
+ * 
+ * @return A pointer to the netlink message.
+ */
+static inline struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
+{
+	return n->nm_nlh;
+}
+
+/**
+ * Acquire a reference on a netlink message
+ * @arg msg		message to acquire reference from
+ */
+static inline void nlmsg_get(struct nl_msg *msg)
+{
+	msg->nm_refcnt++;
+}
+
+/**
+ * Expand maximum payload size of a netlink message
+ * @arg n		Netlink message.
+ * @arg newlen		New maximum payload size.
+ *
+ * Reallocates the payload section of a netlink message and increases
+ * the maximum payload size of the message.
+ *
+ * @note Any pointers pointing to old payload block will be stale and
+ *       need to be refetched. Therfore, do not expand while constructing
+ *       nested attributes or while reserved data blocks are held.
+ *
+ * @return 0 on success or a negative error code.
+ */
+static inline int nlmsg_expand(struct nl_msg *n, size_t newlen)
+{
+	void *tmp;
+
+	if (newlen <= n->nm_size)
+		return -NLE_INVAL;
+
+	tmp = realloc(n->nm_nlh, newlen);
+	if (tmp == NULL)
+		return -NLE_NOMEM;
+
+	n->nm_nlh = (struct nlmsghdr*)tmp;
+	n->nm_size = newlen;
+
+	return 0;
+}
+
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * @ingroup msg
+ * Iterate over a stream of attributes in a message
+ * @arg pos	loop counter, set to current attribute
+ * @arg nlh	netlink message header
+ * @arg hdrlen	length of family header
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \
+	nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \
+			  nlmsg_attrlen(nlh, hdrlen), rem)
+
+/**
+ * Iterate over a stream of messages
+ * @arg pos	loop counter, set to current message
+ * @arg head	head of message stream
+ * @arg len	length of message stream
+ * @arg rem	initialized to len, holds bytes currently remaining in stream
+ */
+#define nlmsg_for_each_msg(pos, head, len, rem) \
+	for (pos = head, rem = len; \
+	     nlmsg_ok(pos, rem); \
+	     pos = nlmsg_next(pos, &(rem)))
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/netlink-compat.h b/package/libs/libnl-tiny/src/include/netlink/netlink-compat.h
new file mode 100644
index 0000000000..17ec9fc8d1
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/netlink-compat.h
@@ -0,0 +1,50 @@
+/*
+ * netlink/netlink-compat.h	Netlink Compatability
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_COMPAT_H_
+#define NETLINK_COMPAT_H_
+
+#if !defined _LINUX_SOCKET_H && !defined _BITS_SOCKADDR_H
+typedef unsigned short  sa_family_t;
+#endif
+
+#ifndef IFNAMSIZ 
+/** Maximum length of a interface name */
+#define IFNAMSIZ 16
+#endif
+
+/* patch 2.4.x if_arp */
+#ifndef ARPHRD_INFINIBAND
+#define ARPHRD_INFINIBAND 32
+#endif
+
+/* patch 2.4.x eth header file */
+#ifndef ETH_P_MPLS_UC
+#define ETH_P_MPLS_UC  0x8847 
+#endif
+
+#ifndef ETH_P_MPLS_MC
+#define ETH_P_MPLS_MC   0x8848
+#endif
+
+#ifndef  ETH_P_EDP2
+#define ETH_P_EDP2      0x88A2
+#endif
+
+#ifndef ETH_P_HDLC
+#define ETH_P_HDLC      0x0019 
+#endif
+
+#ifndef AF_LLC
+#define AF_LLC		26
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/netlink-kernel.h b/package/libs/libnl-tiny/src/include/netlink/netlink-kernel.h
new file mode 100644
index 0000000000..a0f5535664
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/netlink-kernel.h
@@ -0,0 +1,196 @@
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+/**
+ * Netlink socket address
+ * @ingroup nl
+ */
+struct sockaddr_nl
+{
+	/** socket family (AF_NETLINK) */
+	sa_family_t     nl_family;
+
+	/** Padding (unused) */
+	unsigned short  nl_pad;
+
+	/** Unique process ID  */
+	uint32_t        nl_pid;
+
+	/** Multicast group subscriptions */
+	uint32_t        nl_groups;
+};
+
+/**
+ * Netlink message header
+ * @ingroup msg
+ */
+struct nlmsghdr
+{
+	/**
+	 * Length of message including header.
+	 */
+	uint32_t	nlmsg_len;
+
+	/**
+	 * Message type (content type)
+	 */
+	uint16_t	nlmsg_type;
+
+	/**
+	 * Message flags
+	 */
+	uint16_t	nlmsg_flags;
+
+	/**
+	 * Sequence number
+	 */
+	uint32_t	nlmsg_seq;
+
+	/**
+	 * Netlink PID of the proccess sending the message.
+	 */
+	uint32_t	nlmsg_pid;
+};
+
+/**
+ * @name Standard message flags
+ * @{
+ */
+
+/**
+ * Must be set on all request messages (typically from user space to
+ * kernel space).
+ * @ingroup msg
+ */
+#define NLM_F_REQUEST		1
+
+/**
+ * Indicates the message is part of a multipart message terminated
+ * by NLMSG_DONE.
+ */
+#define NLM_F_MULTI		2
+
+/**
+ * Request for an acknowledgment on success.
+ */
+#define NLM_F_ACK		4
+
+/**
+ * Echo this request
+ */
+#define NLM_F_ECHO		8
+
+/** @} */
+
+/**
+ * @name Additional message flags for GET requests
+ * @{
+ */
+
+/**
+ * Return the complete table instead of a single entry.
+ * @ingroup msg
+ */
+#define NLM_F_ROOT	0x100
+
+/**
+ * Return all entries matching criteria passed in message content.
+ */
+#define NLM_F_MATCH	0x200
+
+/**
+ * Return an atomic snapshot of the table being referenced. This
+ * may require special privileges because it has the potential to
+ * interrupt service in the FE for a longer time.
+ */
+#define NLM_F_ATOMIC	0x400
+
+/**
+ * Dump all entries
+ */
+#define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
+
+/** @} */
+
+/**
+ * @name Additional messsage flags for NEW requests
+ * @{
+ */
+
+/**
+ * Replace existing matching config object with this request.
+ * @ingroup msg
+ */
+#define NLM_F_REPLACE	0x100
+
+/**
+ * Don't replace the config object if it already exists.
+ */
+#define NLM_F_EXCL	0x200
+
+/**
+ * Create config object if it doesn't already exist.
+ */
+#define NLM_F_CREATE	0x400
+
+/**
+ * Add to the end of the object list.
+ */
+#define NLM_F_APPEND	0x800
+
+/** @} */
+
+/**
+ * @name Standard Message types
+ * @{
+ */
+
+/**
+ * No operation, message must be ignored
+ * @ingroup msg
+ */
+#define NLMSG_NOOP		0x1
+
+/**
+ * The message signals an error and the payload contains a nlmsgerr
+ * structure. This can be looked at as a NACK and typically it is
+ * from FEC to CPC.
+ */
+#define NLMSG_ERROR		0x2
+
+/**
+ * Message terminates a multipart message.
+ */
+#define NLMSG_DONE		0x3
+
+/**
+ * The message signals that data got lost
+ */
+#define NLMSG_OVERRUN		0x4
+
+/**
+ * Lower limit of reserved message types
+ */
+#define NLMSG_MIN_TYPE		0x10
+
+/** @} */
+
+/**
+ * Netlink error message
+ * @ingroup msg
+ */
+struct nlmsgerr
+{
+	/** Error code (errno number) */
+	int		error;
+
+	/** Original netlink message causing the error */
+	struct nlmsghdr	msg;
+};
+
+struct nl_pktinfo
+{
+	__u32	group;
+};
+
+#endif	/* __LINUX_NETLINK_H */
diff --git a/package/libs/libnl-tiny/src/include/netlink/netlink.h b/package/libs/libnl-tiny/src/include/netlink/netlink.h
new file mode 100644
index 0000000000..c333c503dd
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/netlink.h
@@ -0,0 +1,82 @@
+/*
+ * netlink/netlink.h		Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_NETLINK_H_
+#define NETLINK_NETLINK_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <netlink/netlink-compat.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <netlink/version.h>
+#include <netlink/errno.h>
+#include <netlink/types.h>
+#include <netlink/handlers.h>
+#include <netlink/socket.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int nl_debug;
+extern struct nl_dump_params nl_debug_dp;
+
+/* Connection Management */
+extern int			nl_connect(struct nl_sock *, int);
+extern void			nl_close(struct nl_sock *);
+
+/* Send */
+extern int			nl_sendto(struct nl_sock *, void *, size_t);
+extern int			nl_sendmsg(struct nl_sock *, struct nl_msg *,
+					   struct msghdr *);
+extern int			nl_send(struct nl_sock *, struct nl_msg *);
+extern int			nl_send_auto_complete(struct nl_sock *,
+						      struct nl_msg *);
+extern int			nl_send_simple(struct nl_sock *, int, int,
+					       void *, size_t);
+
+/* Receive */
+extern int			nl_recv(struct nl_sock *,
+					struct sockaddr_nl *, unsigned char **,
+					struct ucred **);
+extern int			nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb);
+
+extern int			nl_wait_for_ack(struct nl_sock *);
+
+/* Netlink Family Translations */
+extern char *			nl_nlfamily2str(int, char *, size_t);
+extern int			nl_str2nlfamily(const char *);
+
+/**
+ * Receive a set of message from a netlink socket using handlers in nl_sock.
+ * @arg sk		Netlink socket.
+ *
+ * Calls nl_recvmsgs() with the handlers configured in the netlink socket.
+ */
+static inline int nl_recvmsgs_default(struct nl_sock *sk)
+{
+	return nl_recvmsgs(sk, sk->s_cb);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/object-api.h b/package/libs/libnl-tiny/src/include/netlink/object-api.h
new file mode 100644
index 0000000000..8a44fe9012
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/object-api.h
@@ -0,0 +1,331 @@
+/*
+ * netlink/object-api.c		Object API
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_OBJECT_API_H_
+#define NETLINK_OBJECT_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup object
+ * @defgroup object_api Object API
+ * @brief
+ *
+ * @par 1) Object Definition
+ * @code
+ * // Define your object starting with the common object header
+ * struct my_obj {
+ * 	NLHDR_COMMON
+ * 	int		my_data;
+ * };
+ *
+ * // Fill out the object operations structure
+ * struct nl_object_ops my_ops = {
+ * 	.oo_name	= "my_obj",
+ * 	.oo_size	= sizeof(struct my_obj),
+ * };
+ *
+ * // At this point the object can be allocated, you may want to provide a
+ * // separate _alloc() function to ease allocting objects of this kind.
+ * struct nl_object *obj = nl_object_alloc(&my_ops);
+ *
+ * // And release it again...
+ * nl_object_put(obj);
+ * @endcode
+ *
+ * @par 2) Allocating additional data
+ * @code
+ * // You may require to allocate additional data and store it inside
+ * // object, f.e. assuming there is a field `ptr'.
+ * struct my_obj {
+ * 	NLHDR_COMMON
+ * 	void *		ptr;
+ * };
+ *
+ * // And at some point you may assign allocated data to this field:
+ * my_obj->ptr = calloc(1, ...);
+ *
+ * // In order to not introduce any memory leaks you have to release
+ * // this data again when the last reference is given back.
+ * static void my_obj_free_data(struct nl_object *obj)
+ * {
+ * 	struct my_obj *my_obj = nl_object_priv(obj);
+ *
+ * 	free(my_obj->ptr);
+ * }
+ *
+ * // Also when the object is cloned, you must ensure for your pointer
+ * // stay valid even if one of the clones is freed by either making
+ * // a clone as well or increase the reference count.
+ * static int my_obj_clone(struct nl_object *src, struct nl_object *dst)
+ * {
+ * 	struct my_obj *my_src = nl_object_priv(src);
+ * 	struct my_obj *my_dst = nl_object_priv(dst);
+ *
+ * 	if (src->ptr) {
+ * 		dst->ptr = calloc(1, ...);
+ * 		memcpy(dst->ptr, src->ptr, ...);
+ * 	}
+ * }
+ *
+ * struct nl_object_ops my_ops = {
+ * 	...
+ * 	.oo_free_data	= my_obj_free_data,
+ * 	.oo_clone	= my_obj_clone,
+ * };
+ * @endcode
+ *
+ * @par 3) Object Dumping
+ * @code
+ * static int my_obj_dump_detailed(struct nl_object *obj,
+ * 				   struct nl_dump_params *params)
+ * {
+ * 	struct my_obj *my_obj = nl_object_priv(obj);
+ *
+ * 	// It is absolutely essential to use nl_dump() when printing
+ *	// any text to make sure the dumping parameters are respected.
+ * 	nl_dump(params, "Obj Integer: %d\n", my_obj->my_int);
+ *
+ * 	// Before we can dump the next line, make sure to prefix
+ *	// this line correctly.
+ * 	nl_new_line(params);
+ *
+ * 	// You may also split a line into multiple nl_dump() calls.
+ * 	nl_dump(params, "String: %s ", my_obj->my_string);
+ * 	nl_dump(params, "String-2: %s\n", my_obj->another_string);
+ * }
+ *
+ * struct nl_object_ops my_ops = {
+ * 	...
+ * 	.oo_dump[NL_DUMP_FULL]	= my_obj_dump_detailed,
+ * };
+ * @endcode
+ *
+ * @par 4) Object Attributes
+ * @code
+ * // The concept of object attributes is optional but can ease the typical
+ * // case of objects that have optional attributes, e.g. a route may have a
+ * // nexthop assigned but it is not required to.
+ *
+ * // The first step to define your object specific bitmask listing all
+ * // attributes
+ * #define MY_ATTR_FOO		(1<<0)
+ * #define MY_ATTR_BAR		(1<<1)
+ *
+ * // When assigning an optional attribute to the object, make sure
+ * // to mark its availability.
+ * my_obj->foo = 123123;
+ * my_obj->ce_mask |= MY_ATTR_FOO;
+ *
+ * // At any time you may use this mask to check for the availability
+ * // of the attribute, e.g. while dumping
+ * if (my_obj->ce_mask & MY_ATTR_FOO)
+ * 	nl_dump(params, "foo %d ", my_obj->foo);
+ *
+ * // One of the big advantages of this concept is that it allows for
+ * // standardized comparisons which make it trivial for caches to
+ * // identify unique objects by use of unified comparison functions.
+ * // In order for it to work, your object implementation must provide
+ * // a comparison function and define a list of attributes which
+ * // combined together make an object unique.
+ *
+ * static int my_obj_compare(struct nl_object *_a, struct nl_object *_b,
+ * 			     uint32_t attrs, int flags)
+ * {
+ * 	struct my_obj *a = nl_object_priv(_a):
+ * 	struct my_obj *b = nl_object_priv(_b):
+ * 	int diff = 0;
+ *
+ * 	// We help ourselves in defining our own DIFF macro which will
+ *	// call ATTR_DIFF() on both objects which will make sure to only
+ *	// compare the attributes if required.
+ * 	#define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR)
+ *
+ * 	// Call our own diff macro for each attribute to build a bitmask
+ *	// representing the attributes which mismatch.
+ * 	diff |= MY_DIFF(FOO, a->foo != b->foo)
+ * 	diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar))
+ *
+ * 	return diff;
+ * }
+ *
+ * // In order to identify identical objects with differing attributes
+ * // you must specify the attributes required to uniquely identify
+ * // your object. Make sure to not include too many attributes, this
+ * // list is used when caches look for an old version of an object.
+ * struct nl_object_ops my_ops = {
+ * 	...
+ * 	.oo_id_attrs		= MY_ATTR_FOO,
+ * 	.oo_compare		= my_obj_compare,
+ * };
+ * @endcode
+ * @{
+ */
+
+/**
+ * Common Object Header
+ *
+ * This macro must be included as first member in every object
+ * definition to allow objects to be cached.
+ */
+#define NLHDR_COMMON				\
+	int			ce_refcnt;	\
+	struct nl_object_ops *	ce_ops;		\
+	struct nl_cache *	ce_cache;	\
+	struct nl_list_head	ce_list;	\
+	int			ce_msgtype;	\
+	int			ce_flags;	\
+	uint32_t		ce_mask;
+
+/**
+ * Return true if attribute is available in both objects
+ * @arg A		an object
+ * @arg B		another object
+ * @arg ATTR		attribute bit
+ *
+ * @return True if the attribute is available, otherwise false is returned.
+ */
+#define AVAILABLE(A, B, ATTR)	(((A)->ce_mask & (B)->ce_mask) & (ATTR))
+
+/**
+ * Return true if attributes mismatch
+ * @arg A		an object
+ * @arg B		another object
+ * @arg ATTR		attribute bit
+ * @arg EXPR		Comparison expression
+ *
+ * This function will check if the attribute in question is available
+ * in both objects, if not this will count as a mismatch.
+ *
+ * If available the function will execute the expression which must
+ * return true if the attributes mismatch.
+ *
+ * @return True if the attribute mismatch, or false if they match.
+ */
+#define ATTR_MISMATCH(A, B, ATTR, EXPR)	(!AVAILABLE(A, B, ATTR) || (EXPR))
+
+/**
+ * Return attribute bit if attribute does not match
+ * @arg LIST		list of attributes to be compared
+ * @arg ATTR		attribute bit
+ * @arg A		an object
+ * @arg B		another object
+ * @arg EXPR		Comparison expression
+ *
+ * This function will check if the attribute in question is available
+ * in both objects, if not this will count as a mismatch.
+ *
+ * If available the function will execute the expression which must
+ * return true if the attributes mismatch.
+ *
+ * In case the attributes mismatch, the attribute is returned, otherwise
+ * 0 is returned.
+ *
+ * @code
+ * diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo);
+ * @endcode
+ */
+#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
+({	int diff = 0; \
+	if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \
+		diff = ATTR; \
+	diff; })
+
+/**
+ * Object Operations
+ */
+struct nl_object;
+struct nl_object_ops
+{
+	/**
+	 * Unique name of object type
+	 *
+	 * Must be in the form family/name, e.g. "route/addr"
+	 */
+	char *		oo_name;
+
+	/** Size of object including its header */
+	size_t		oo_size;
+
+	/* List of attributes needed to uniquely identify the object */
+	uint32_t	oo_id_attrs;
+
+	/**
+	 * Constructor function
+	 *
+	 * Will be called when a new object of this type is allocated.
+	 * Can be used to initialize members such as lists etc.
+	 */
+	void  (*oo_constructor)(struct nl_object *);
+
+	/**
+	 * Destructor function
+	 *
+	 * Will be called when an object is freed. Must free all
+	 * resources which may have been allocated as part of this
+	 * object.
+	 */
+	void  (*oo_free_data)(struct nl_object *);
+
+	/**
+	 * Cloning function
+	 *
+	 * Will be called when an object needs to be cloned. Please
+	 * note that the generic object code will make an exact
+	 * copy of the object first, therefore you only need to take
+	 * care of members which require reference counting etc.
+	 *
+	 * May return a negative error code to abort cloning.
+	 */
+	int  (*oo_clone)(struct nl_object *, struct nl_object *);
+
+	/**
+	 * Dumping functions
+	 *
+	 * Will be called when an object is dumped. The implementations
+	 * have to use nl_dump(), nl_dump_line(), and nl_new_line() to
+	 * dump objects.
+	 *
+	 * The functions must return the number of lines printed.
+	 */
+	void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *,
+				       struct nl_dump_params *);
+
+	/**
+	 * Comparison function
+	 *
+	 * Will be called when two objects of the same type are
+	 * compared. It takes the two objects in question, an object
+	 * specific bitmask defining which attributes should be
+	 * compared and flags to control the behaviour.
+	 *
+	 * The function must return a bitmask with the relevant bit
+	 * set for each attribute that mismatches.
+	 */
+	int   (*oo_compare)(struct nl_object *, struct nl_object *,
+			    uint32_t, int);
+
+
+	char *(*oo_attrs2str)(int, char *, size_t);
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/object.h b/package/libs/libnl-tiny/src/include/netlink/object.h
new file mode 100644
index 0000000000..8aabe7bb12
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/object.h
@@ -0,0 +1,164 @@
+/*
+ * netlink/object.c	Generic Cacheable Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_OBJECT_H_
+#define NETLINK_OBJECT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/object-api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NL_OBJ_MARK		1
+
+struct nl_cache;
+struct nl_object;
+struct nl_object_ops;
+
+struct nl_object
+{
+	NLHDR_COMMON
+};
+
+#define OBJ_CAST(ptr)		((struct nl_object *) (ptr))
+
+/* General */
+extern struct nl_object *	nl_object_alloc(struct nl_object_ops *);
+extern void			nl_object_free(struct nl_object *);
+extern struct nl_object *	nl_object_clone(struct nl_object *obj);
+
+#ifdef disabled
+
+extern int			nl_object_alloc_name(const char *,
+						     struct nl_object **);
+extern void			nl_object_dump(struct nl_object *,
+					       struct nl_dump_params *);
+
+extern uint32_t			nl_object_diff(struct nl_object *,
+					       struct nl_object *);
+extern int			nl_object_match_filter(struct nl_object *,
+						       struct nl_object *);
+extern int			nl_object_identical(struct nl_object *,
+						    struct nl_object *);
+extern char *			nl_object_attrs2str(struct nl_object *,
+						    uint32_t attrs, char *buf,
+						    size_t);
+#endif
+/**
+ * Check whether this object is used by multiple users
+ * @arg obj		object to check
+ * @return true or false
+ */
+static inline int nl_object_shared(struct nl_object *obj)
+{
+	return obj->ce_refcnt > 1;
+}
+
+
+static inline void nl_object_get(struct nl_object *obj)
+{
+	obj->ce_refcnt++;
+}
+
+static inline void nl_object_put(struct nl_object *obj)
+{
+	if (!obj)
+		return;
+
+	obj->ce_refcnt--;
+
+	if (obj->ce_refcnt <= 0)
+		nl_object_free(obj);
+}
+
+
+/**
+ * @name Marks
+ * @{
+ */
+
+/**
+ * Add mark to object
+ * @arg obj		Object to mark
+ */
+static inline void nl_object_mark(struct nl_object *obj)
+{
+	obj->ce_flags |= NL_OBJ_MARK;
+}
+
+/**
+ * Remove mark from object
+ * @arg obj		Object to unmark
+ */
+static inline void nl_object_unmark(struct nl_object *obj)
+{
+	obj->ce_flags &= ~NL_OBJ_MARK;
+}
+
+/**
+ * Return true if object is marked
+ * @arg obj		Object to check
+ * @return true if object is marked, otherwise false
+ */
+static inline int nl_object_is_marked(struct nl_object *obj)
+{
+	return (obj->ce_flags & NL_OBJ_MARK);
+}
+
+/** @} */
+
+#ifdef disabled
+/**
+ * Return list of attributes present in an object
+ * @arg obj		an object
+ * @arg buf		destination buffer
+ * @arg len		length of destination buffer
+ *
+ * @return destination buffer.
+ */
+static inline char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
+{
+	return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
+}
+#endif
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+static inline int nl_object_get_refcnt(struct nl_object *obj)
+{
+	return obj->ce_refcnt;
+}
+
+static inline struct nl_cache *nl_object_get_cache(struct nl_object *obj)
+{
+	return obj->ce_cache;
+}
+
+static inline void *		nl_object_priv(struct nl_object *obj)
+{
+	return obj;
+}
+
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/socket.h b/package/libs/libnl-tiny/src/include/netlink/socket.h
new file mode 100644
index 0000000000..bcb934c50b
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/socket.h
@@ -0,0 +1,231 @@
+/*
+ * netlink/socket.h		Netlink Socket
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_SOCKET_H_
+#define NETLINK_SOCKET_H_
+
+#include <netlink/types.h>
+#include <netlink/handlers.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NL_SOCK_BUFSIZE_SET	(1<<0)
+#define NL_SOCK_PASSCRED	(1<<1)
+#define NL_OWN_PORT		(1<<2)
+#define NL_MSG_PEEK		(1<<3)
+#define NL_NO_AUTO_ACK		(1<<4)
+
+struct nl_cb;
+struct nl_sock
+{
+	struct sockaddr_nl	s_local;
+	struct sockaddr_nl	s_peer;
+	int			s_fd;
+	int			s_proto;
+	unsigned int		s_seq_next;
+	unsigned int		s_seq_expect;
+	int			s_flags;
+	struct nl_cb *		s_cb;
+};
+
+
+extern struct nl_sock *	nl_socket_alloc(void);
+extern struct nl_sock *	nl_socket_alloc_cb(struct nl_cb *);
+extern void		nl_socket_free(struct nl_sock *);
+
+extern void		nl_socket_set_local_port(struct nl_sock *, uint32_t);
+
+extern int		nl_socket_add_memberships(struct nl_sock *, int, ...);
+extern int		nl_socket_drop_memberships(struct nl_sock *, int, ...);
+
+extern int		nl_socket_set_buffer_size(struct nl_sock *, int, int);
+extern int		nl_socket_set_passcred(struct nl_sock *, int);
+extern int		nl_socket_recv_pktinfo(struct nl_sock *, int);
+
+extern void		nl_socket_disable_seq_check(struct nl_sock *);
+
+extern int		nl_socket_set_nonblocking(struct nl_sock *);
+
+/**
+ * Use next sequence number
+ * @arg sk		Netlink socket.
+ *
+ * Uses the next available sequence number and increases the counter
+ * by one for subsequent calls.
+ *
+ * @return Unique serial sequence number
+ */
+static inline unsigned int nl_socket_use_seq(struct nl_sock *sk)
+{
+	return sk->s_seq_next++;
+}
+
+/**
+ * Disable automatic request for ACK
+ * @arg sk		Netlink socket.
+ *
+ * The default behaviour of a socket is to request an ACK for
+ * each message sent to allow for the caller to synchronize to
+ * the completion of the netlink operation. This function
+ * disables this behaviour and will result in requests being
+ * sent which will not have the NLM_F_ACK flag set automatically.
+ * However, it is still possible for the caller to set the
+ * NLM_F_ACK flag explicitely.
+ */
+static inline void nl_socket_disable_auto_ack(struct nl_sock *sk)
+{
+	sk->s_flags |= NL_NO_AUTO_ACK;
+}
+
+/**
+ * Enable automatic request for ACK (default)
+ * @arg sk		Netlink socket.
+ * @see nl_socket_disable_auto_ack
+ */
+static inline void nl_socket_enable_auto_ack(struct nl_sock *sk)
+{
+	sk->s_flags &= ~NL_NO_AUTO_ACK;
+}
+
+/**
+ * @name Source Idenficiation
+ * @{
+ */
+
+static inline uint32_t nl_socket_get_local_port(struct nl_sock *sk)
+{
+	return sk->s_local.nl_pid;
+}
+
+/**
+ * Join multicast groups (deprecated)
+ * @arg sk		Netlink socket.
+ * @arg groups		Bitmask of groups to join.
+ *
+ * This function defines the old way of joining multicast group which
+ * has to be done prior to calling nl_connect(). It works on any kernel
+ * version but is very limited as only 32 groups can be joined.
+ */
+static inline void nl_join_groups(struct nl_sock *sk, int groups)
+{
+	sk->s_local.nl_groups |= groups;
+}
+
+/**
+ * @name Peer Identfication
+ * @{
+ */
+
+static inline uint32_t nl_socket_get_peer_port(struct nl_sock *sk)
+{
+	return sk->s_peer.nl_pid;
+}
+
+static inline void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port)
+{
+	sk->s_peer.nl_pid = port;
+}
+
+/** @} */
+
+/**
+ * @name File Descriptor
+ * @{
+ */
+
+static inline int nl_socket_get_fd(struct nl_sock *sk)
+{
+	return sk->s_fd;
+}
+
+/**
+ * Enable use of MSG_PEEK when reading from socket
+ * @arg sk		Netlink socket.
+ */
+static inline void nl_socket_enable_msg_peek(struct nl_sock *sk)
+{
+	sk->s_flags |= NL_MSG_PEEK;
+}
+
+/**
+ * Disable use of MSG_PEEK when reading from socket
+ * @arg sk		Netlink socket.
+ */
+static inline void nl_socket_disable_msg_peek(struct nl_sock *sk)
+{
+	sk->s_flags &= ~NL_MSG_PEEK;
+}
+
+static inline uint32_t nl_socket_get_peer_groups(struct nl_sock *sk)
+{
+	return sk->s_peer.nl_groups;
+}
+
+static inline void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups)
+{
+	sk->s_peer.nl_groups = groups;
+}
+
+/**
+ * @name Callback Handler
+ * @{
+ */
+
+static inline struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
+{
+	return nl_cb_get(sk->s_cb);
+}
+
+static inline void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
+{
+	nl_cb_put(sk->s_cb);
+	sk->s_cb = nl_cb_get(cb);
+}
+
+/**
+ * Modify the callback handler associated to the socket
+ * @arg sk		Netlink socket.
+ * @arg type		which type callback to set
+ * @arg kind		kind of callback
+ * @arg func		callback function
+ * @arg arg		argument to be passwd to callback function
+ *
+ * @see nl_cb_set
+ */
+static inline int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type,
+			enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
+			void *arg)
+{
+	return nl_cb_set(sk->s_cb, type, kind, func, arg);
+}
+
+/** @} */
+
+static inline int nl_socket_add_membership(struct nl_sock *sk, int group)
+{
+	return nl_socket_add_memberships(sk, group, 0);
+}
+
+
+static inline int nl_socket_drop_membership(struct nl_sock *sk, int group)
+{
+	return nl_socket_drop_memberships(sk, group, 0);
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/types.h b/package/libs/libnl-tiny/src/include/netlink/types.h
new file mode 100644
index 0000000000..de81ace11e
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/types.h
@@ -0,0 +1,121 @@
+/*
+ * netlink/netlink-types.h	Netlink Types
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_TYPES_H_
+#define __NETLINK_TYPES_H_
+
+#include <stdio.h>
+
+/**
+ * Dumping types (dp_type)
+ * @ingroup utils
+ */
+enum nl_dump_type {
+	NL_DUMP_LINE,		/**< Dump object briefly on one line */
+	NL_DUMP_DETAILS,	/**< Dump all attributes but no statistics */
+	NL_DUMP_STATS,		/**< Dump all attributes including statistics */
+	NL_DUMP_ENV,		/**< Dump all attribtues as env variables */
+	__NL_DUMP_MAX,
+};
+#define NL_DUMP_MAX (__NL_DUMP_MAX - 1)
+
+/**
+ * Dumping parameters
+ * @ingroup utils
+ */
+struct nl_dump_params
+{
+	/**
+	 * Specifies the type of dump that is requested.
+	 */
+	enum nl_dump_type	dp_type;
+
+	/**
+	 * Specifies the number of whitespaces to be put in front
+	 * of every new line (indentation).
+	 */
+	int			dp_prefix;
+
+	/**
+	 * Causes the cache index to be printed for each element.
+	 */
+	int			dp_print_index;
+
+	/**
+	 * Causes each element to be prefixed with the message type.
+	 */
+	int			dp_dump_msgtype;
+
+	/**
+	 * A callback invoked for output
+	 *
+	 * Passed arguments are:
+	 *  - dumping parameters
+	 *  - string to append to the output
+	 */
+	void			(*dp_cb)(struct nl_dump_params *, char *);
+
+	/**
+	 * A callback invoked for every new line, can be used to
+	 * customize the indentation.
+	 *
+	 * Passed arguments are:
+	 *  - dumping parameters
+	 *  - line number starting from 0
+	 */
+	void			(*dp_nl_cb)(struct nl_dump_params *, int);
+
+	/**
+	 * User data pointer, can be used to pass data to callbacks.
+	 */
+	void			*dp_data;
+
+	/**
+	 * File descriptor the dumping output should go to
+	 */
+	FILE *			dp_fd;
+
+	/**
+	 * Alternatively the output may be redirected into a buffer
+	 */
+	char *			dp_buf;
+
+	/**
+	 * Length of the buffer dp_buf
+	 */
+	size_t			dp_buflen;
+
+	/**
+	 * PRIVATE
+	 * Set if a dump was performed prior to the actual dump handler.
+	 */
+	int			dp_pre_dump;
+
+	/**
+	 * PRIVATE
+	 * Owned by the current caller
+	 */
+	int			dp_ivar;
+
+	unsigned int		dp_line;
+};
+
+#ifndef __GNUC__
+#define __extension__
+#endif
+
+#define min_t(type,x,y) \
+	__extension__({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+	__extension__({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/utils.h b/package/libs/libnl-tiny/src/include/netlink/utils.h
new file mode 100644
index 0000000000..480bab6186
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/utils.h
@@ -0,0 +1,78 @@
+/*
+ * netlink/utils.h		Utility Functions
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_UTILS_H_
+#define NETLINK_UTILS_H_
+
+#include <netlink/netlink.h>
+#include <netlink/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Probability Constants
+ * @{
+ */
+
+/**
+ * Lower probability limit
+ * @ingroup utils
+ */
+#define NL_PROB_MIN 0x0
+
+/**
+ * Upper probability limit
+ * @ingroup utils
+ */
+#define NL_PROB_MAX 0xffffffff
+
+/** @} */
+
+/* unit pretty-printing */
+extern double	nl_cancel_down_bytes(unsigned long long, char **);
+extern double	nl_cancel_down_bits(unsigned long long, char **);
+extern double	nl_cancel_down_us(uint32_t, char **);
+
+/* generic unit translations */
+extern long	nl_size2int(const char *);
+extern long	nl_prob2int(const char *);
+
+/* time translations */
+extern int	nl_get_hz(void);
+extern uint32_t	nl_us2ticks(uint32_t);
+extern uint32_t	nl_ticks2us(uint32_t);
+extern int	nl_str2msec(const char *, uint64_t *);
+extern char *	nl_msec2str(uint64_t, char *, size_t);
+
+/* link layer protocol translations */
+extern char *	nl_llproto2str(int, char *, size_t);
+extern int	nl_str2llproto(const char *);
+
+/* ethernet protocol translations */
+extern char *	nl_ether_proto2str(int, char *, size_t);
+extern int	nl_str2ether_proto(const char *);
+
+/* IP protocol translations */
+extern char *	nl_ip_proto2str(int, char *, size_t);
+extern int	nl_str2ip_proto(const char *);
+
+/* Dumping helpers */
+extern void	nl_new_line(struct nl_dump_params *);
+extern void	nl_dump(struct nl_dump_params *, const char *, ...);
+extern void	nl_dump_line(struct nl_dump_params *, const char *, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/netlink/version.h b/package/libs/libnl-tiny/src/include/netlink/version.h
new file mode 100644
index 0000000000..6a316d4933
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/netlink/version.h
@@ -0,0 +1,18 @@
+/*
+ * netlink/version.h	Compile Time Versioning Information
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_VERSION_H_
+#define NETLINK_VERSION_H_
+
+#define LIBNL_STRING "libnl"
+#define LIBNL_VERSION "2.0"
+
+#endif
diff --git a/package/libs/libnl-tiny/src/include/unl.h b/package/libs/libnl-tiny/src/include/unl.h
new file mode 100644
index 0000000000..4fe7dc745d
--- /dev/null
+++ b/package/libs/libnl-tiny/src/include/unl.h
@@ -0,0 +1,47 @@
+#ifndef __UNL_H
+#define __UNL_H
+
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <stdbool.h>
+
+struct unl {
+	struct nl_sock *sock;
+	struct nl_cache *cache;
+	struct genl_family *family;
+	char *family_name;
+	int hdrlen;
+	bool loop_done;
+};
+
+int unl_genl_init(struct unl *unl, const char *family);
+void unl_free(struct unl *unl);
+
+typedef int (*unl_cb)(struct nl_msg *, void *);
+
+struct nl_msg *unl_genl_msg(struct unl *unl, int cmd, bool dump);
+int unl_genl_request(struct unl *unl, struct nl_msg *msg, unl_cb handler, void *arg);
+int unl_genl_request_single(struct unl *unl, struct nl_msg *msg, struct nl_msg **dest);
+void unl_genl_loop(struct unl *unl, unl_cb handler, void *arg);
+
+int unl_genl_multicast_id(struct unl *unl, const char *name);
+int unl_genl_subscribe(struct unl *unl, const char *name);
+int unl_genl_unsubscribe(struct unl *unl, const char *name);
+
+int unl_nl80211_phy_lookup(const char *name);
+int unl_nl80211_wdev_to_phy(struct unl *unl, int wdev);
+struct nl_msg *unl_nl80211_phy_msg(struct unl *unl, int phy, int cmd, bool dump);
+struct nl_msg *unl_nl80211_vif_msg(struct unl *unl, int dev, int cmd, bool dump);
+
+static inline void unl_loop_done(struct unl *unl)
+{
+	unl->loop_done = true;
+}
+
+static inline struct nlattr *unl_find_attr(struct unl *unl, struct nl_msg *msg, int attr)
+{
+	return nlmsg_find_attr(nlmsg_hdr(msg), unl->hdrlen, attr);
+}
+
+#endif
diff --git a/package/libs/libnl-tiny/src/msg.c b/package/libs/libnl-tiny/src/msg.c
new file mode 100644
index 0000000000..e84c281fc9
--- /dev/null
+++ b/package/libs/libnl-tiny/src/msg.c
@@ -0,0 +1,566 @@
+/*
+ * lib/msg.c		Netlink Messages Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup msg Messages
+ * Netlink Message Construction/Parsing Interface
+ * 
+ * The following information is partly extracted from RFC3549
+ * (ftp://ftp.rfc-editor.org/in-notes/rfc3549.txt)
+ *
+ * @par Message Format
+ * Netlink messages consist of a byte stream with one or multiple
+ * Netlink headers and an associated payload.  If the payload is too big
+ * to fit into a single message it, can be split over multiple Netlink
+ * messages, collectively called a multipart message.  For multipart
+ * messages, the first and all following headers have the \c NLM_F_MULTI
+ * Netlink header flag set, except for the last header which has the
+ * Netlink header type \c NLMSG_DONE.
+ *
+ * @par
+ * The Netlink message header (\link nlmsghdr struct nlmsghdr\endlink) is shown below.
+ * @code   
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Length                             |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |            Type              |           Flags              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      Sequence Number                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      Process ID (PID)                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * @endcode
+ *
+ * @par
+ * The netlink message header and payload must be aligned properly:
+ * @code
+ *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * |           Header           | Pad |       Payload       | Pad |
+ * |      struct nlmsghdr       |     |                     |     |
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * @endcode
+ * @par
+ * Message Format:
+ * @code
+ *    <--- nlmsg_total_size(payload)  --->
+ *    <-- nlmsg_msg_size(payload) ->
+ *   +----------+- - -+-------------+- - -+-------- - -
+ *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr
+ *   +----------+- - -+-------------+- - -+-------- - -
+ *   nlmsg_data(nlh)---^                   ^
+ *   nlmsg_next(nlh)-----------------------+
+ * @endcode
+ * @par
+ * The payload may consist of arbitary data but may have strict
+ * alignment and formatting rules depening on the specific netlink
+ * families.
+ * @par
+ * @code
+ *    <---------------------- nlmsg_len(nlh) --------------------->
+ *    <------ hdrlen ------>       <- nlmsg_attrlen(nlh, hdrlen) ->
+ *   +----------------------+- - -+--------------------------------+
+ *   |     Family Header    | Pad |           Attributes           |
+ *   +----------------------+- - -+--------------------------------+
+ *   nlmsg_attrdata(nlh, hdrlen)---^
+ * @endcode
+ * @par The ACK Netlink Message
+ * This message is actually used to denote both an ACK and a NACK.
+ * Typically, the direction is from FEC to CPC (in response to an ACK
+ * request message).  However, the CPC should be able to send ACKs back
+ * to FEC when requested.
+ * @code
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Netlink message header                  |
+ * |                       type = NLMSG_ERROR                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                          Error code                           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       OLD Netlink message header              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * @endcode
+ *
+ * @par Example
+ * @code
+ * // Various methods exist to create/allocate a new netlink
+ * // message. 
+ * //
+ * // nlmsg_alloc() will allocate an empty netlink message with
+ * // a maximum payload size which defaults to the page size of
+ * // the system. This default size can be modified using the
+ * // function nlmsg_set_default_size().
+ * struct nl_msg *msg = nlmsg_alloc();
+ *
+ * // Very often, the message type and message flags are known
+ * // at allocation time while the other fields are auto generated:
+ * struct nl_msg *msg = nlmsg_alloc_simple(MY_TYPE, MY_FLAGS);
+ *
+ * // Alternatively an existing netlink message header can be used
+ * // to inherit the header values:
+ * struct nlmsghdr hdr = {
+ * 	.nlmsg_type = MY_TYPE,
+ * 	.nlmsg_flags = MY_FLAGS,
+ * };
+ * struct nl_msg *msg = nlmsg_inherit(&hdr);
+ *
+ * // Last but not least, netlink messages received from netlink sockets
+ * // can be converted into nl_msg objects using nlmsg_convert(). This
+ * // will create a message with a maximum payload size which equals the
+ * // length of the existing netlink message, therefore no more data can
+ * // be appened without calling nlmsg_expand() first.
+ * struct nl_msg *msg = nlmsg_convert(nlh_from_nl_sock);
+ *
+ * // Payload may be added to the message via nlmsg_append(). The fourth
+ * // parameter specifies the number of alignment bytes the data should
+ * // be padding with at the end. Common values are 0 to disable it or
+ * // NLMSG_ALIGNTO to ensure proper netlink message padding.
+ * nlmsg_append(msg, &mydata, sizeof(mydata), 0);
+ *
+ * // Sometimes it may be necessary to reserve room for data but defer
+ * // the actual copying to a later point, nlmsg_reserve() can be used
+ * // for this purpose:
+ * void *data = nlmsg_reserve(msg, sizeof(mydata), NLMSG_ALIGNTO);
+ *
+ * // Attributes may be added using the attributes interface.
+ *
+ * // After successful use of the message, the memory must be freed
+ * // using nlmsg_free()
+ * nlmsg_free(msg);
+ * @endcode
+ * 
+ * @par 4) Parsing messages
+ * @code
+ * int n;
+ * unsigned char *buf;
+ * struct nlmsghdr *hdr;
+ *
+ * n = nl_recv(handle, NULL, &buf);
+ * 
+ * hdr = (struct nlmsghdr *) buf;
+ * while (nlmsg_ok(hdr, n)) {
+ * 	// Process message here...
+ * 	hdr = nlmsg_next(hdr, &n);
+ * }
+ * @endcode
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/cache.h>
+#include <netlink/attr.h>
+#include <netlink/msg.h>
+#include <linux/socket.h>
+
+static size_t default_msg_size;
+
+static void __init init_msg_size(void)
+{
+	default_msg_size = getpagesize();
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+//** @} */
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+/**
+ * check if the netlink message fits into the remaining bytes
+ * @arg nlh		netlink message header
+ * @arg remaining	number of bytes remaining in message stream
+ */
+int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
+{
+	return (remaining >= sizeof(struct nlmsghdr) &&
+		nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
+		nlh->nlmsg_len <= remaining);
+}
+
+/**
+ * next netlink message in message stream
+ * @arg nlh		netlink message header
+ * @arg remaining	number of bytes remaining in message stream
+ *
+ * @returns the next netlink message in the message stream and
+ * decrements remaining by the size of the current message.
+ */
+struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
+{
+	int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
+
+	*remaining -= totlen;
+
+	return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
+}
+
+/**
+ * parse attributes of a netlink message
+ * @arg nlh		netlink message header
+ * @arg hdrlen		length of family specific header
+ * @arg tb		destination array with maxtype+1 elements
+ * @arg maxtype		maximum attribute type to be expected
+ * @arg policy		validation policy
+ *
+ * See nla_parse()
+ */
+int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+		int maxtype, struct nla_policy *policy)
+{
+	if (!nlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
+			 nlmsg_attrlen(nlh, hdrlen), policy);
+}
+
+/**
+ * nlmsg_validate - validate a netlink message including attributes
+ * @arg nlh		netlinket message header
+ * @arg hdrlen		length of familiy specific header
+ * @arg maxtype		maximum attribute type to be expected
+ * @arg policy		validation policy
+ */
+int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+		   struct nla_policy *policy)
+{
+	if (!nlmsg_valid_hdr(nlh, hdrlen))
+		return -NLE_MSG_TOOSHORT;
+
+	return nla_validate(nlmsg_attrdata(nlh, hdrlen),
+			    nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
+}
+
+/** @} */
+
+/**
+ * @name Message Building/Access
+ * @{
+ */
+
+static struct nl_msg *__nlmsg_alloc(size_t len)
+{
+	struct nl_msg *nm;
+
+	nm = calloc(1, sizeof(*nm));
+	if (!nm)
+		goto errout;
+
+	nm->nm_refcnt = 1;
+
+	nm->nm_nlh = malloc(len);
+	if (!nm->nm_nlh)
+		goto errout;
+
+	memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
+
+	nm->nm_protocol = -1;
+	nm->nm_size = len;
+	nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
+
+	NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
+
+	return nm;
+errout:
+	free(nm);
+	return NULL;
+}
+
+/**
+ * Allocate a new netlink message with the default maximum payload size.
+ *
+ * Allocates a new netlink message without any further payload. The
+ * maximum payload size defaults to PAGESIZE or as otherwise specified
+ * with nlmsg_set_default_size().
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_alloc(void)
+{
+	return __nlmsg_alloc(default_msg_size);
+}
+
+/**
+ * Allocate a new netlink message with maximum payload size specified.
+ */
+struct nl_msg *nlmsg_alloc_size(size_t max)
+{
+	return __nlmsg_alloc(max);
+}
+
+/**
+ * Allocate a new netlink message and inherit netlink message header
+ * @arg hdr		Netlink message header template
+ *
+ * Allocates a new netlink message and inherits the original message
+ * header. If \a hdr is not NULL it will be used as a template for
+ * the netlink message header, otherwise the header is left blank.
+ * 
+ * @return Newly allocated netlink message or NULL
+ */
+struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
+{
+	struct nl_msg *nm;
+
+	nm = nlmsg_alloc();
+	if (nm && hdr) {
+		struct nlmsghdr *new = nm->nm_nlh;
+
+		new->nlmsg_type = hdr->nlmsg_type;
+		new->nlmsg_flags = hdr->nlmsg_flags;
+		new->nlmsg_seq = hdr->nlmsg_seq;
+		new->nlmsg_pid = hdr->nlmsg_pid;
+	}
+
+	return nm;
+}
+
+/**
+ * Allocate a new netlink message
+ * @arg nlmsgtype	Netlink message type
+ * @arg flags		Message flags.
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
+{
+	struct nl_msg *msg;
+	struct nlmsghdr nlh = {
+		.nlmsg_type = nlmsgtype,
+		.nlmsg_flags = flags,
+	};
+
+	msg = nlmsg_inherit(&nlh);
+	if (msg)
+		NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
+
+	return msg;
+}
+
+/**
+ * Set the default maximum message payload size for allocated messages
+ * @arg max		Size of payload in bytes.
+ */
+void nlmsg_set_default_size(size_t max)
+{
+	if (max < nlmsg_total_size(0))
+		max = nlmsg_total_size(0);
+
+	default_msg_size = max;
+}
+
+/**
+ * Convert a netlink message received from a netlink socket to a nl_msg
+ * @arg hdr		Netlink message received from netlink socket.
+ *
+ * Allocates a new netlink message and copies all of the data pointed to
+ * by \a hdr into the new message object.
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
+{
+	struct nl_msg *nm;
+
+	nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
+	if (!nm)
+		goto errout;
+
+	memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
+
+	return nm;
+errout:
+	nlmsg_free(nm);
+	return NULL;
+}
+
+/**
+ * Reserve room for additional data in a netlink message
+ * @arg n		netlink message
+ * @arg len		length of additional data to reserve room for
+ * @arg pad		number of bytes to align data to
+ *
+ * Reserves room for additional data at the tail of the an
+ * existing netlink message. Eventual padding required will
+ * be zeroed out.
+ *
+ * @return Pointer to start of additional data tailroom or NULL.
+ */
+void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
+{
+	void *buf = n->nm_nlh;
+	size_t nlmsg_len = n->nm_nlh->nlmsg_len;
+	size_t tlen;
+
+	tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
+
+	if ((tlen + nlmsg_len) > n->nm_size)
+		return NULL;
+
+	buf += nlmsg_len;
+	n->nm_nlh->nlmsg_len += tlen;
+
+	if (tlen > len)
+		memset(buf + len, 0, tlen - len);
+
+	NL_DBG(2, "msg %p: Reserved %zu bytes, pad=%d, nlmsg_len=%d\n",
+		  n, len, pad, n->nm_nlh->nlmsg_len);
+
+	return buf;
+}
+
+/**
+ * Append data to tail of a netlink message
+ * @arg n		netlink message
+ * @arg data		data to add
+ * @arg len		length of data
+ * @arg pad		Number of bytes to align data to.
+ *
+ * Extends the netlink message as needed and appends the data of given
+ * length to the message. 
+ *
+ * @return 0 on success or a negative error code
+ */
+int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
+{
+	void *tmp;
+
+	tmp = nlmsg_reserve(n, len, pad);
+	if (tmp == NULL)
+		return -NLE_NOMEM;
+
+	memcpy(tmp, data, len);
+	NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
+
+	return 0;
+}
+
+/**
+ * Add a netlink message header to a netlink message
+ * @arg n		netlink message
+ * @arg pid		netlink process id or NL_AUTO_PID
+ * @arg seq		sequence number of message or NL_AUTO_SEQ
+ * @arg type		message type
+ * @arg payload		length of message payload
+ * @arg flags		message flags
+ *
+ * Adds or overwrites the netlink message header in an existing message
+ * object. If \a payload is greater-than zero additional room will be
+ * reserved, f.e. for family specific headers. It can be accesed via
+ * nlmsg_data().
+ *
+ * @return A pointer to the netlink message header or NULL.
+ */
+struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
+			   int type, int payload, int flags)
+{
+	struct nlmsghdr *nlh;
+
+	if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
+		BUG();
+
+	nlh = (struct nlmsghdr *) n->nm_nlh;
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_flags = flags;
+	nlh->nlmsg_pid = pid;
+	nlh->nlmsg_seq = seq;
+
+	NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
+		  "seq=%d\n", n, type, flags, pid, seq);
+
+	if (payload > 0 &&
+	    nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
+		return NULL;
+
+	return nlh;
+}
+
+/**
+ * Release a reference from an netlink message
+ * @arg msg		message to release reference from
+ *
+ * Frees memory after the last reference has been released.
+ */
+void nlmsg_free(struct nl_msg *msg)
+{
+	if (!msg)
+		return;
+
+	msg->nm_refcnt--;
+	NL_DBG(4, "Returned message reference %p, %d remaining\n",
+	       msg, msg->nm_refcnt);
+
+	if (msg->nm_refcnt < 0)
+		BUG();
+
+	if (msg->nm_refcnt <= 0) {
+		free(msg->nm_nlh);
+		free(msg);
+		NL_DBG(2, "msg %p: Freed\n", msg);
+	}
+}
+
+/** @} */
+
+/**
+ * @name Direct Parsing
+ * @{
+ */
+
+/** @cond SKIP */
+struct dp_xdata {
+	void (*cb)(struct nl_object *, void *);
+	void *arg;
+};
+/** @endcond */
+
+static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
+{
+	struct dp_xdata *x = p->pp_arg;
+
+	x->cb(obj, x->arg);
+	return 0;
+}
+
+int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
+		 void *arg)
+{
+	struct nl_cache_ops *ops;
+	struct nl_parser_param p = {
+		.pp_cb = parse_cb
+	};
+	struct dp_xdata x = {
+		.cb = cb,
+		.arg = arg,
+	};
+
+	ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
+				     nlmsg_hdr(msg)->nlmsg_type);
+	if (ops == NULL)
+		return -NLE_MSGTYPE_NOSUPPORT;
+	p.pp_arg = &x;
+
+	return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/nl.c b/package/libs/libnl-tiny/src/nl.c
new file mode 100644
index 0000000000..2fb866eca9
--- /dev/null
+++ b/package/libs/libnl-tiny/src/nl.c
@@ -0,0 +1,720 @@
+/*
+ * lib/nl.c		Core Netlink Interface
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup core Core
+ *
+ * @details
+ * @par 1) Connecting the socket
+ * @code
+ * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
+ * nl_connect(sk, NETLINK_ROUTE);
+ * @endcode
+ *
+ * @par 2) Sending data
+ * @code
+ * // The most rudimentary method is to use nl_sendto() simply pushing
+ * // a piece of data to the other netlink peer. This method is not
+ * // recommended.
+ * const char buf[] = { 0x01, 0x02, 0x03, 0x04 };
+ * nl_sendto(sk, buf, sizeof(buf));
+ *
+ * // A more comfortable interface is nl_send() taking a pointer to
+ * // a netlink message.
+ * struct nl_msg *msg = my_msg_builder();
+ * nl_send(sk, nlmsg_hdr(msg));
+ *
+ * // nl_sendmsg() provides additional control over the sendmsg() message
+ * // header in order to allow more specific addressing of multiple peers etc.
+ * struct msghdr hdr = { ... };
+ * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr);
+ *
+ * // You're probably too lazy to fill out the netlink pid, sequence number
+ * // and message flags all the time. nl_send_auto_complete() automatically
+ * // extends your message header as needed with an appropriate sequence
+ * // number, the netlink pid stored in the netlink socket and the message
+ * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket)
+ * nl_send_auto_complete(sk, nlmsg_hdr(msg));
+ *
+ * // Simple protocols don't require the complex message construction interface
+ * // and may favour nl_send_simple() to easly send a bunch of payload
+ * // encapsulated in a netlink message header.
+ * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf));
+ * @endcode
+ *
+ * @par 3) Receiving data
+ * @code
+ * // nl_recv() receives a single message allocating a buffer for the message
+ * // content and gives back the pointer to you.
+ * struct sockaddr_nl peer;
+ * unsigned char *msg;
+ * nl_recv(sk, &peer, &msg);
+ *
+ * // nl_recvmsgs() receives a bunch of messages until the callback system
+ * // orders it to state, usually after receving a compolete multi part
+ * // message series.
+ * nl_recvmsgs(sk, my_callback_configuration);
+ *
+ * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback
+ * // configuration stored in the socket.
+ * nl_recvmsgs_default(sk);
+ *
+ * // In case you want to wait for the ACK to be recieved that you requested
+ * // with your latest message, you can call nl_wait_for_ack()
+ * nl_wait_for_ack(sk);
+ * @endcode
+ *
+ * @par 4) Closing
+ * @code
+ * // Close the socket first to release kernel memory
+ * nl_close(sk);
+ * @endcode
+ * 
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+/**
+ * @name Connection Management
+ * @{
+ */
+
+/**
+ * Create and connect netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg protocol	Netlink protocol to use.
+ *
+ * Creates a netlink socket using the specified protocol, binds the socket
+ * and issues a connection attempt.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_connect(struct nl_sock *sk, int protocol)
+{
+	int err;
+	socklen_t addrlen;
+
+	sk->s_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
+	if (sk->s_fd < 0) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
+		err = nl_socket_set_buffer_size(sk, 0, 0);
+		if (err < 0)
+			goto errout;
+	}
+
+	err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
+		   sizeof(sk->s_local));
+	if (err < 0) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	addrlen = sizeof(sk->s_local);
+	err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
+			  &addrlen);
+	if (err < 0) {
+		err = -nl_syserr2nlerr(errno);
+		goto errout;
+	}
+
+	if (addrlen != sizeof(sk->s_local)) {
+		err = -NLE_NOADDR;
+		goto errout;
+	}
+
+	if (sk->s_local.nl_family != AF_NETLINK) {
+		err = -NLE_AF_NOSUPPORT;
+		goto errout;
+	}
+
+	sk->s_proto = protocol;
+
+	return 0;
+errout:
+	close(sk->s_fd);
+	sk->s_fd = -1;
+
+	return err;
+}
+
+/**
+ * Close/Disconnect netlink socket.
+ * @arg sk		Netlink socket.
+ */
+void nl_close(struct nl_sock *sk)
+{
+	if (sk->s_fd >= 0) {
+		close(sk->s_fd);
+		sk->s_fd = -1;
+	}
+
+	sk->s_proto = 0;
+}
+
+/** @} */
+
+/**
+ * @name Send
+ * @{
+ */
+
+/**
+ * Send raw data over netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg buf		Data buffer.
+ * @arg size		Size of data buffer.
+ * @return Number of characters written on success or a negative error code.
+ */
+int nl_sendto(struct nl_sock *sk, void *buf, size_t size)
+{
+	int ret;
+
+	ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *)
+		     &sk->s_peer, sizeof(sk->s_peer));
+	if (ret < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return ret;
+}
+
+/**
+ * Send netlink message with control over sendmsg() message header.
+ * @arg sk		Netlink socket.
+ * @arg msg		Netlink message to be sent.
+ * @arg hdr		Sendmsg() message header.
+ * @return Number of characters sent on sucess or a negative error code.
+ */
+int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
+{
+	struct nl_cb *cb;
+	int ret;
+
+	struct iovec iov = {
+		.iov_base = (void *) nlmsg_hdr(msg),
+		.iov_len = nlmsg_hdr(msg)->nlmsg_len,
+	};
+
+	hdr->msg_iov = &iov;
+	hdr->msg_iovlen = 1;
+
+	nlmsg_set_src(msg, &sk->s_local);
+
+	cb = sk->s_cb;
+	if (cb->cb_set[NL_CB_MSG_OUT])
+		if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK)
+			return 0;
+
+	ret = sendmsg(sk->s_fd, hdr, 0);
+	if (ret < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return ret;
+}
+
+
+/**
+ * Send netlink message.
+ * @arg sk		Netlink socket.
+ * @arg msg		Netlink message to be sent.
+ * @see nl_sendmsg()
+ * @return Number of characters sent on success or a negative error code.
+ */
+int nl_send(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct sockaddr_nl *dst;
+	struct ucred *creds;
+	
+	struct msghdr hdr = {
+		.msg_name = (void *) &sk->s_peer,
+		.msg_namelen = sizeof(struct sockaddr_nl),
+	};
+
+	/* Overwrite destination if specified in the message itself, defaults
+	 * to the peer address of the socket.
+	 */
+	dst = nlmsg_get_dst(msg);
+	if (dst->nl_family == AF_NETLINK)
+		hdr.msg_name = dst;
+
+	/* Add credentials if present. */
+	creds = nlmsg_get_creds(msg);
+	if (creds != NULL) {
+		char buf[CMSG_SPACE(sizeof(struct ucred))];
+		struct cmsghdr *cmsg;
+
+		hdr.msg_control = buf;
+		hdr.msg_controllen = sizeof(buf);
+
+		cmsg = CMSG_FIRSTHDR(&hdr);
+		cmsg->cmsg_level = SOL_SOCKET;
+		cmsg->cmsg_type = SCM_CREDENTIALS;
+		cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+		memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
+	}
+
+	return nl_sendmsg(sk, msg, &hdr);
+}
+
+/**
+ * Send netlink message and check & extend header values as needed.
+ * @arg sk		Netlink socket.
+ * @arg msg		Netlink message to be sent.
+ *
+ * Checks the netlink message \c nlh for completness and extends it
+ * as required before sending it out. Checked fields include pid,
+ * sequence nr, and flags.
+ *
+ * @see nl_send()
+ * @return Number of characters sent or a negative error code.
+ */
+int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct nlmsghdr *nlh;
+	struct nl_cb *cb = sk->s_cb;
+
+	nlh = nlmsg_hdr(msg);
+	if (nlh->nlmsg_pid == 0)
+		nlh->nlmsg_pid = sk->s_local.nl_pid;
+
+	if (nlh->nlmsg_seq == 0)
+		nlh->nlmsg_seq = sk->s_seq_next++;
+
+	if (msg->nm_protocol == -1)
+		msg->nm_protocol = sk->s_proto;
+	
+	nlh->nlmsg_flags |= NLM_F_REQUEST;
+
+	if (!(sk->s_flags & NL_NO_AUTO_ACK))
+		nlh->nlmsg_flags |= NLM_F_ACK;
+
+	if (cb->cb_send_ow)
+		return cb->cb_send_ow(sk, msg);
+	else
+		return nl_send(sk, msg);
+}
+
+/**
+ * Send simple netlink message using nl_send_auto_complete()
+ * @arg sk		Netlink socket.
+ * @arg type		Netlink message type.
+ * @arg flags		Netlink message flags.
+ * @arg buf		Data buffer.
+ * @arg size		Size of data buffer.
+ *
+ * Builds a netlink message with the specified type and flags and
+ * appends the specified data as payload to the message.
+ *
+ * @see nl_send_auto_complete()
+ * @return Number of characters sent on success or a negative error code.
+ */
+int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf,
+		   size_t size)
+{
+	int err;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc_simple(type, flags);
+	if (!msg)
+		return -NLE_NOMEM;
+
+	if (buf && size) {
+		err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
+		if (err < 0)
+			goto errout;
+	}
+	
+
+	err = nl_send_auto_complete(sk, msg);
+errout:
+	nlmsg_free(msg);
+
+	return err;
+}
+
+/** @} */
+
+/**
+ * @name Receive
+ * @{
+ */
+
+/**
+ * Receive data from netlink socket
+ * @arg sk		Netlink socket.
+ * @arg nla		Destination pointer for peer's netlink address.
+ * @arg buf		Destination pointer for message content.
+ * @arg creds		Destination pointer for credentials.
+ *
+ * Receives a netlink message, allocates a buffer in \c *buf and
+ * stores the message content. The peer's netlink address is stored
+ * in \c *nla. The caller is responsible for freeing the buffer allocated
+ * in \c *buf if a positive value is returned.  Interrupted system calls
+ * are handled by repeating the read. The input buffer size is determined
+ * by peeking before the actual read is done.
+ *
+ * A non-blocking sockets causes the function to return immediately with
+ * a return value of 0 if no data is available.
+ *
+ * @return Number of octets read, 0 on EOF or a negative error code.
+ */
+int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
+	    unsigned char **buf, struct ucred **creds)
+{
+	int n;
+	int flags = 0;
+	static int page_size = 0;
+	struct iovec iov;
+	struct msghdr msg = {
+		.msg_name = (void *) nla,
+		.msg_namelen = sizeof(struct sockaddr_nl),
+		.msg_iov = &iov,
+		.msg_iovlen = 1,
+		.msg_control = NULL,
+		.msg_controllen = 0,
+		.msg_flags = 0,
+	};
+	struct cmsghdr *cmsg;
+
+	if (sk->s_flags & NL_MSG_PEEK)
+		flags |= MSG_PEEK;
+
+	if (page_size == 0)
+		page_size = getpagesize() * 4;
+
+	iov.iov_len = page_size;
+	iov.iov_base = *buf = malloc(iov.iov_len);
+
+	if (sk->s_flags & NL_SOCK_PASSCRED) {
+		msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
+		msg.msg_control = calloc(1, msg.msg_controllen);
+	}
+retry:
+
+	n = recvmsg(sk->s_fd, &msg, flags);
+	if (!n)
+		goto abort;
+	else if (n < 0) {
+		if (errno == EINTR) {
+			NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
+			goto retry;
+		} else if (errno == EAGAIN) {
+			NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
+			goto abort;
+		} else {
+			free(msg.msg_control);
+			free(*buf);
+			return -nl_syserr2nlerr(errno);
+		}
+	}
+
+	if (iov.iov_len < n ||
+	    msg.msg_flags & MSG_TRUNC) {
+		/* Provided buffer is not long enough, enlarge it
+		 * and try again. */
+		iov.iov_len *= 2;
+		iov.iov_base = *buf = realloc(*buf, iov.iov_len);
+		goto retry;
+	} else if (msg.msg_flags & MSG_CTRUNC) {
+		msg.msg_controllen *= 2;
+		msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
+		goto retry;
+	} else if (flags != 0) {
+		/* Buffer is big enough, do the actual reading */
+		flags = 0;
+		goto retry;
+	}
+
+	if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
+		free(msg.msg_control);
+		free(*buf);
+		return -NLE_NOADDR;
+	}
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_CREDENTIALS) {
+			*creds = calloc(1, sizeof(struct ucred));
+			memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
+			break;
+		}
+	}
+
+	free(msg.msg_control);
+	return n;
+
+abort:
+	free(msg.msg_control);
+	free(*buf);
+	return 0;
+}
+
+#define NL_CB_CALL(cb, type, msg) \
+do { \
+	err = nl_cb_call(cb, type, msg); \
+	switch (err) { \
+	case NL_OK: \
+		err = 0; \
+		break; \
+	case NL_SKIP: \
+		goto skip; \
+	case NL_STOP: \
+		goto stop; \
+	default: \
+		goto out; \
+	} \
+} while (0)
+
+static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+	int n, err = 0, multipart = 0;
+	unsigned char *buf = NULL;
+	struct nlmsghdr *hdr;
+	struct sockaddr_nl nla = {0};
+	struct nl_msg *msg = NULL;
+	struct ucred *creds = NULL;
+
+continue_reading:
+	NL_DBG(3, "Attempting to read from %p\n", sk);
+	if (cb->cb_recv_ow)
+		n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
+	else
+		n = nl_recv(sk, &nla, &buf, &creds);
+
+	if (n <= 0)
+		return n;
+
+	NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n);
+
+	hdr = (struct nlmsghdr *) buf;
+	while (nlmsg_ok(hdr, n)) {
+		NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk);
+
+		nlmsg_free(msg);
+		msg = nlmsg_convert(hdr);
+		if (!msg) {
+			err = -NLE_NOMEM;
+			goto out;
+		}
+
+		nlmsg_set_proto(msg, sk->s_proto);
+		nlmsg_set_src(msg, &nla);
+		if (creds)
+			nlmsg_set_creds(msg, creds);
+
+		/* Raw callback is the first, it gives the most control
+		 * to the user and he can do his very own parsing. */
+		if (cb->cb_set[NL_CB_MSG_IN])
+			NL_CB_CALL(cb, NL_CB_MSG_IN, msg);
+
+		/* Sequence number checking. The check may be done by
+		 * the user, otherwise a very simple check is applied
+		 * enforcing strict ordering */
+		if (cb->cb_set[NL_CB_SEQ_CHECK])
+			NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
+		else if (hdr->nlmsg_seq != sk->s_seq_expect) {
+			if (cb->cb_set[NL_CB_INVALID])
+				NL_CB_CALL(cb, NL_CB_INVALID, msg);
+			else {
+				err = -NLE_SEQ_MISMATCH;
+				goto out;
+			}
+		}
+
+		if (hdr->nlmsg_type == NLMSG_DONE ||
+		    hdr->nlmsg_type == NLMSG_ERROR ||
+		    hdr->nlmsg_type == NLMSG_NOOP ||
+		    hdr->nlmsg_type == NLMSG_OVERRUN) {
+			/* We can't check for !NLM_F_MULTI since some netlink
+			 * users in the kernel are broken. */
+			sk->s_seq_expect++;
+			NL_DBG(3, "recvmsgs(%p): Increased expected " \
+			       "sequence number to %d\n",
+			       sk, sk->s_seq_expect);
+		}
+
+		if (hdr->nlmsg_flags & NLM_F_MULTI)
+			multipart = 1;
+	
+		/* Other side wishes to see an ack for this message */
+		if (hdr->nlmsg_flags & NLM_F_ACK) {
+			if (cb->cb_set[NL_CB_SEND_ACK])
+				NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
+			else {
+				/* FIXME: implement */
+			}
+		}
+
+		/* messages terminates a multpart message, this is
+		 * usually the end of a message and therefore we slip
+		 * out of the loop by default. the user may overrule
+		 * this action by skipping this packet. */
+		if (hdr->nlmsg_type == NLMSG_DONE) {
+			multipart = 0;
+			if (cb->cb_set[NL_CB_FINISH])
+				NL_CB_CALL(cb, NL_CB_FINISH, msg);
+		}
+
+		/* Message to be ignored, the default action is to
+		 * skip this message if no callback is specified. The
+		 * user may overrule this action by returning
+		 * NL_PROCEED. */
+		else if (hdr->nlmsg_type == NLMSG_NOOP) {
+			if (cb->cb_set[NL_CB_SKIPPED])
+				NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
+			else
+				goto skip;
+		}
+
+		/* Data got lost, report back to user. The default action is to
+		 * quit parsing. The user may overrule this action by retuning
+		 * NL_SKIP or NL_PROCEED (dangerous) */
+		else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
+			if (cb->cb_set[NL_CB_OVERRUN])
+				NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
+			else {
+				err = -NLE_MSG_OVERFLOW;
+				goto out;
+			}
+		}
+
+		/* Message carries a nlmsgerr */
+		else if (hdr->nlmsg_type == NLMSG_ERROR) {
+			struct nlmsgerr *e = nlmsg_data(hdr);
+
+			if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) {
+				/* Truncated error message, the default action
+				 * is to stop parsing. The user may overrule
+				 * this action by returning NL_SKIP or
+				 * NL_PROCEED (dangerous) */
+				if (cb->cb_set[NL_CB_INVALID])
+					NL_CB_CALL(cb, NL_CB_INVALID, msg);
+				else {
+					err = -NLE_MSG_TRUNC;
+					goto out;
+				}
+			} else if (e->error) {
+				/* Error message reported back from kernel. */
+				if (cb->cb_err) {
+					err = cb->cb_err(&nla, e,
+							   cb->cb_err_arg);
+					if (err < 0)
+						goto out;
+					else if (err == NL_SKIP)
+						goto skip;
+					else if (err == NL_STOP) {
+						err = -nl_syserr2nlerr(e->error);
+						goto out;
+					}
+				} else {
+					err = -nl_syserr2nlerr(e->error);
+					goto out;
+				}
+			} else if (cb->cb_set[NL_CB_ACK])
+				NL_CB_CALL(cb, NL_CB_ACK, msg);
+		} else {
+			/* Valid message (not checking for MULTIPART bit to
+			 * get along with broken kernels. NL_SKIP has no
+			 * effect on this.  */
+			if (cb->cb_set[NL_CB_VALID])
+				NL_CB_CALL(cb, NL_CB_VALID, msg);
+		}
+skip:
+		err = 0;
+		hdr = nlmsg_next(hdr, &n);
+	}
+	
+	nlmsg_free(msg);
+	free(buf);
+	free(creds);
+	buf = NULL;
+	msg = NULL;
+	creds = NULL;
+
+	if (multipart) {
+		/* Multipart message not yet complete, continue reading */
+		goto continue_reading;
+	}
+stop:
+	err = 0;
+out:
+	nlmsg_free(msg);
+	free(buf);
+	free(creds);
+
+	return err;
+}
+
+/**
+ * Receive a set of messages from a netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg cb		set of callbacks to control behaviour.
+ *
+ * Repeatedly calls nl_recv() or the respective replacement if provided
+ * by the application (see nl_cb_overwrite_recv()) and parses the
+ * received data as netlink messages. Stops reading if one of the
+ * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.
+ *
+ * A non-blocking sockets causes the function to return immediately if
+ * no data is available.
+ *
+ * @return 0 on success or a negative error code from nl_recv().
+ */
+int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+	if (cb->cb_recvmsgs_ow)
+		return cb->cb_recvmsgs_ow(sk, cb);
+	else
+		return recvmsgs(sk, cb);
+}
+
+
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+	return NL_STOP;
+}
+
+/**
+ * Wait for ACK.
+ * @arg sk		Netlink socket.
+ * @pre The netlink socket must be in blocking state.
+ *
+ * Waits until an ACK is received for the latest not yet acknowledged
+ * netlink message.
+ */
+int nl_wait_for_ack(struct nl_sock *sk)
+{
+	int err;
+	struct nl_cb *cb;
+
+	cb = nl_cb_clone(sk->s_cb);
+	if (cb == NULL)
+		return -NLE_NOMEM;
+
+	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
+	err = nl_recvmsgs(sk, cb);
+	nl_cb_put(cb);
+
+	return err;
+}
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/object.c b/package/libs/libnl-tiny/src/object.c
new file mode 100644
index 0000000000..384bacdc6c
--- /dev/null
+++ b/package/libs/libnl-tiny/src/object.c
@@ -0,0 +1,147 @@
+/*
+ * lib/object.c		Generic Cacheable Object
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cache
+ * @defgroup object Object
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/utils.h>
+
+static inline struct nl_object_ops *obj_ops(struct nl_object *obj)
+{
+	if (!obj->ce_ops)
+		BUG();
+
+	return obj->ce_ops;
+}
+
+/**
+ * @name Object Creation/Deletion
+ * @{
+ */
+
+/**
+ * Allocate a new object of kind specified by the operations handle
+ * @arg ops		cache operations handle
+ * @return The new object or NULL
+ */
+struct nl_object *nl_object_alloc(struct nl_object_ops *ops)
+{
+	struct nl_object *new;
+
+	if (ops->oo_size < sizeof(*new))
+		BUG();
+
+	new = calloc(1, ops->oo_size);
+	if (!new)
+		return NULL;
+
+	new->ce_refcnt = 1;
+	nl_init_list_head(&new->ce_list);
+
+	new->ce_ops = ops;
+	if (ops->oo_constructor)
+		ops->oo_constructor(new);
+
+	NL_DBG(4, "Allocated new object %p\n", new);
+
+	return new;
+}
+
+struct nl_derived_object {
+	NLHDR_COMMON
+	char data;
+};
+
+/**
+ * Allocate a new object and copy all data from an existing object
+ * @arg obj		object to inherite data from
+ * @return The new object or NULL.
+ */
+struct nl_object *nl_object_clone(struct nl_object *obj)
+{
+	struct nl_object *new;
+	struct nl_object_ops *ops = obj_ops(obj);
+	int doff = offsetof(struct nl_derived_object, data);
+	int size;
+
+	new = nl_object_alloc(ops);
+	if (!new)
+		return NULL;
+
+	size = ops->oo_size - doff;
+	if (size < 0)
+		BUG();
+
+	new->ce_ops = obj->ce_ops;
+	new->ce_msgtype = obj->ce_msgtype;
+
+	if (size)
+		memcpy((void *)new + doff, (void *)obj + doff, size);
+
+	if (ops->oo_clone) {
+		if (ops->oo_clone(new, obj) < 0) {
+			nl_object_free(new);
+			return NULL;
+		}
+	} else if (size && ops->oo_free_data)
+		BUG();
+
+	return new;
+}
+
+/**
+ * Free a cacheable object
+ * @arg obj		object to free
+ *
+ * @return 0 or a negative error code.
+ */
+void nl_object_free(struct nl_object *obj)
+{
+	struct nl_object_ops *ops = obj_ops(obj);
+
+	if (obj->ce_refcnt > 0)
+		NL_DBG(1, "Warning: Freeing object in use...\n");
+
+	if (obj->ce_cache)
+		nl_cache_remove(obj);
+
+	if (ops->oo_free_data)
+		ops->oo_free_data(obj);
+
+	free(obj);
+
+	NL_DBG(4, "Freed object %p\n", obj);
+}
+
+/** @} */
+
+/**
+ * @name Reference Management
+ * @{
+ */
+
+/** @} */
+
+/**
+ * @name Utillities
+ * @{
+ */
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/socket.c b/package/libs/libnl-tiny/src/socket.c
new file mode 100644
index 0000000000..1429825e63
--- /dev/null
+++ b/package/libs/libnl-tiny/src/socket.c
@@ -0,0 +1,406 @@
+/*
+ * lib/socket.c		Netlink Socket
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup socket Socket
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+static uint32_t used_ports_map[32];
+
+static uint32_t generate_local_port(void)
+{
+	int i, n;
+	uint32_t pid = getpid() & 0x3FFFFF;
+
+	for (i = 0; i < 32; i++) {
+		if (used_ports_map[i] == 0xFFFFFFFF)
+			continue;
+
+		for (n = 0; n < 32; n++) {
+			if (1UL & (used_ports_map[i] >> n))
+				continue;
+
+			used_ports_map[i] |= (1UL << n);
+			n += (i * 32);
+
+			/* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
+			 * to, i.e. 1024 unique ports per application. */
+			return pid + (n << 22);
+
+		}
+	}
+
+	/* Out of sockets in our own PID namespace, what to do? FIXME */
+	return UINT_MAX;
+}
+
+static void release_local_port(uint32_t port)
+{
+	int nr;
+
+	if (port == UINT_MAX)
+		return;
+	
+	nr = port >> 22;
+	used_ports_map[nr / 32] &= ~(1 << nr % 32);
+}
+
+/**
+ * @name Allocation
+ * @{
+ */
+
+static struct nl_sock *__alloc_socket(struct nl_cb *cb)
+{
+	struct nl_sock *sk;
+
+	sk = calloc(1, sizeof(*sk));
+	if (!sk)
+		return NULL;
+
+	sk->s_fd = -1;
+	sk->s_cb = cb;
+	sk->s_local.nl_family = AF_NETLINK;
+	sk->s_peer.nl_family = AF_NETLINK;
+	sk->s_seq_expect = sk->s_seq_next = time(0);
+	sk->s_local.nl_pid = generate_local_port();
+	if (sk->s_local.nl_pid == UINT_MAX) {
+		nl_socket_free(sk);
+		return NULL;
+	}
+
+	return sk;
+}
+
+/**
+ * Allocate new netlink socket
+ *
+ * @return Newly allocated netlink socket or NULL.
+ */
+struct nl_sock *nl_socket_alloc(void)
+{
+	struct nl_cb *cb;
+	
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!cb)
+		return NULL;
+
+	return __alloc_socket(cb);
+}
+
+/**
+ * Allocate new socket with custom callbacks
+ * @arg cb		Callback handler
+ *
+ * The reference to the callback handler is taken into account
+ * automatically, it is released again upon calling nl_socket_free().
+ *
+ *@return Newly allocted socket handle or NULL.
+ */
+struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
+{
+	if (cb == NULL)
+		BUG();
+
+	return __alloc_socket(nl_cb_get(cb));
+}
+
+/**
+ * Free a netlink socket.
+ * @arg sk		Netlink socket.
+ */
+void nl_socket_free(struct nl_sock *sk)
+{
+	if (!sk)
+		return;
+
+	if (sk->s_fd >= 0)
+		close(sk->s_fd);
+
+	if (!(sk->s_flags & NL_OWN_PORT))
+		release_local_port(sk->s_local.nl_pid);
+
+	nl_cb_put(sk->s_cb);
+	free(sk);
+}
+
+/** @} */
+
+/**
+ * @name Sequence Numbers
+ * @{
+ */
+
+static int noop_seq_check(struct nl_msg *msg, void *arg)
+{
+	return NL_OK;
+}
+
+
+/**
+ * Disable sequence number checking.
+ * @arg sk		Netlink socket.
+ *
+ * Disables checking of sequence numbers on the netlink socket This is
+ * required to allow messages to be processed which were not requested by
+ * a preceding request message, e.g. netlink events.
+ *
+ * @note This function modifies the NL_CB_SEQ_CHECK configuration in
+ * the callback handle associated with the socket.
+ */
+void nl_socket_disable_seq_check(struct nl_sock *sk)
+{
+	nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK,
+		  NL_CB_CUSTOM, noop_seq_check, NULL);
+}
+
+/** @} */
+
+/**
+ * Set local port of socket
+ * @arg sk		Netlink socket.
+ * @arg port		Local port identifier
+ *
+ * Assigns a local port identifier to the socket. If port is 0
+ * a unique port identifier will be generated automatically.
+ */
+void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
+{
+	if (port == 0) {
+		port = generate_local_port(); 
+		sk->s_flags &= ~NL_OWN_PORT;
+	} else  {
+		if (!(sk->s_flags & NL_OWN_PORT))
+			release_local_port(sk->s_local.nl_pid);
+		sk->s_flags |= NL_OWN_PORT;
+	}
+
+	sk->s_local.nl_pid = port;
+}
+
+/** @} */
+
+/**
+ * @name Group Subscriptions
+ * @{
+ */
+
+/**
+ * Join groups
+ * @arg sk		Netlink socket
+ * @arg group		Group identifier
+ *
+ * Joins the specified groups using the modern socket option which
+ * is available since kernel version 2.6.14. It allows joining an
+ * almost arbitary number of groups without limitation.  The list
+ * of groups has to be terminated by 0 (%NFNLGRP_NONE).
+ *
+ * Make sure to use the correct group definitions as the older
+ * bitmask definitions for nl_join_groups() are likely to still
+ * be present for backward compatibility reasons.
+ *
+ * @return 0 on sucess or a negative error code.
+ */
+int nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
+{
+	int err;
+	va_list ap;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	va_start(ap, group);
+
+	while (group != 0) {
+		if (group < 0)
+			return -NLE_INVAL;
+
+		err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+						 &group, sizeof(group));
+		if (err < 0)
+			return -nl_syserr2nlerr(errno);
+
+		group = va_arg(ap, int);
+	}
+
+	va_end(ap);
+
+	return 0;
+}
+
+/**
+ * Leave groups
+ * @arg sk		Netlink socket
+ * @arg group		Group identifier
+ *
+ * Leaves the specified groups using the modern socket option
+ * which is available since kernel version 2.6.14. The list of groups
+ * has to terminated by 0 (%NFNLGRP_NONE).
+ *
+ * @see nl_socket_add_membership
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...)
+{
+	int err;
+	va_list ap;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	va_start(ap, group);
+
+	while (group != 0) {
+		if (group < 0)
+			return -NLE_INVAL;
+
+		err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+						 &group, sizeof(group));
+		if (err < 0)
+			return -nl_syserr2nlerr(errno);
+
+		group = va_arg(ap, int);
+	}
+
+	va_end(ap);
+
+	return 0;
+}
+
+
+/** @} */
+
+/**
+ * Set file descriptor of socket to non-blocking state
+ * @arg sk		Netlink socket.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_set_nonblocking(struct nl_sock *sk)
+{
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return 0;
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Set socket buffer size of netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg rxbuf		New receive socket buffer size in bytes.
+ * @arg txbuf		New transmit socket buffer size in bytes.
+ *
+ * Sets the socket buffer size of a netlink socket to the specified
+ * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
+ * good default value.
+ *
+ * @note It is not required to call this function prior to nl_connect().
+ * @return 0 on sucess or a negative error code.
+ */
+int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
+{
+	int err;
+
+	if (rxbuf <= 0)
+		rxbuf = 32768;
+
+	if (txbuf <= 0)
+		txbuf = 32768;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+	
+	err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
+			 &txbuf, sizeof(txbuf));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
+			 &rxbuf, sizeof(rxbuf));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	sk->s_flags |= NL_SOCK_BUFSIZE_SET;
+
+	return 0;
+}
+
+/**
+ * Enable/disable credential passing on netlink socket.
+ * @arg sk		Netlink socket.
+ * @arg state		New state (0 - disabled, 1 - enabled)
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_socket_set_passcred(struct nl_sock *sk, int state)
+{
+	int err;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
+			 &state, sizeof(state));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	if (state)
+		sk->s_flags |= NL_SOCK_PASSCRED;
+	else
+		sk->s_flags &= ~NL_SOCK_PASSCRED;
+
+	return 0;
+}
+
+/**
+ * Enable/disable receival of additional packet information
+ * @arg sk		Netlink socket.
+ * @arg state		New state (0 - disabled, 1 - enabled)
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
+{
+	int err;
+
+	if (sk->s_fd == -1)
+		return -NLE_BAD_SOCK;
+
+	err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
+			 &state, sizeof(state));
+	if (err < 0)
+		return -nl_syserr2nlerr(errno);
+
+	return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/package/libs/libnl-tiny/src/unl.c b/package/libs/libnl-tiny/src/unl.c
new file mode 100644
index 0000000000..33c020ea13
--- /dev/null
+++ b/package/libs/libnl-tiny/src/unl.c
@@ -0,0 +1,287 @@
+#define _GNU_SOURCE
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/nl80211.h>
+
+#include "unl.h"
+
+static int unl_init(struct unl *unl)
+{
+	unl->sock = nl_socket_alloc();
+	if (!unl->sock)
+		return -1;
+
+	return 0;
+}
+
+int unl_genl_init(struct unl *unl, const char *family)
+{
+	memset(unl, 0, sizeof(*unl));
+
+	if (unl_init(unl))
+		goto error_out;
+
+	unl->hdrlen = NLMSG_ALIGN(sizeof(struct genlmsghdr));
+	unl->family_name = strdup(family);
+	if (!unl->family_name)
+		goto error;
+
+	if (genl_connect(unl->sock))
+		goto error;
+
+	if (genl_ctrl_alloc_cache(unl->sock, &unl->cache))
+		goto error;
+
+	unl->family = genl_ctrl_search_by_name(unl->cache, family);
+	if (!unl->family)
+		goto error;
+
+	return 0;
+
+error:
+	unl_free(unl);
+error_out:
+	return -1;
+}
+
+void unl_free(struct unl *unl)
+{
+	if (unl->family_name)
+		free(unl->family_name);
+
+	if (unl->sock)
+		nl_socket_free(unl->sock);
+
+	if (unl->cache)
+		nl_cache_free(unl->cache);
+
+	memset(unl, 0, sizeof(*unl));
+}
+
+static int
+ack_handler(struct nl_msg *msg, void *arg)
+{
+	int *err = arg;
+	*err = 0;
+	return NL_STOP;
+}
+
+static int
+finish_handler(struct nl_msg *msg, void *arg)
+{
+	int *err = arg;
+	*err = 0;
+	return NL_SKIP;
+}
+
+static int
+error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+	int *ret = arg;
+	*ret = err->error;
+	return NL_SKIP;
+}
+
+struct nl_msg *unl_genl_msg(struct unl *unl, int cmd, bool dump)
+{
+	struct nl_msg *msg;
+	int flags = 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto out;
+
+	if (dump)
+		flags |= NLM_F_DUMP;
+
+	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ,
+		    genl_family_get_id(unl->family), 0, flags, cmd, 0);
+
+out:
+	return msg;
+}
+
+int unl_genl_request(struct unl *unl, struct nl_msg *msg, unl_cb handler, void *arg)
+{
+	struct nl_cb *cb;
+	int err;
+
+	cb = nl_cb_alloc(NL_CB_CUSTOM);
+	err = nl_send_auto_complete(unl->sock, msg);
+	if (err < 0)
+		goto out;
+
+	err = 1;
+	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+	if (handler)
+		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handler, arg);
+
+	while (err > 0)
+		nl_recvmsgs(unl->sock, cb);
+
+out:
+	nlmsg_free(msg);
+	nl_cb_put(cb);
+	return err;
+}
+
+static int request_single_cb(struct nl_msg *msg, void *arg)
+{
+	struct nl_msg **dest = arg;
+
+	if (!*dest) {
+		nlmsg_get(msg);
+		*dest = msg;
+	}
+	return NL_SKIP;
+}
+
+int unl_genl_request_single(struct unl *unl, struct nl_msg *msg, struct nl_msg **dest)
+{
+	*dest = NULL;
+	return unl_genl_request(unl, msg, request_single_cb, dest);
+}
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+	return NL_OK;
+}
+
+void unl_genl_loop(struct unl *unl, unl_cb handler, void *arg)
+{
+	struct nl_cb *cb;
+
+	cb = nl_cb_alloc(NL_CB_CUSTOM);
+	unl->loop_done = false;
+	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handler, arg);
+
+	while (!unl->loop_done)
+		nl_recvmsgs(unl->sock, cb);
+
+	nl_cb_put(cb);
+}
+
+int unl_genl_multicast_id(struct unl *unl, const char *name)
+{
+	struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
+	struct nlattr *groups, *group;
+	struct nl_msg *msg;
+	int ctrlid;
+	int ret = -1;
+	int rem;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	ctrlid = genl_ctrl_resolve(unl->sock, "nlctrl");
+	genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
+	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, unl->family_name);
+	unl_genl_request_single(unl, msg, &msg);
+	if (!msg)
+		return -1;
+
+	groups = unl_find_attr(unl, msg, CTRL_ATTR_MCAST_GROUPS);
+	if (!groups)
+		goto nla_put_failure;
+
+	nla_for_each_nested(group, groups, rem) {
+		const char *gn;
+
+		nla_parse(tb, CTRL_ATTR_MCAST_GRP_MAX, nla_data(group),
+			  nla_len(group), NULL);
+
+		if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
+		    !tb[CTRL_ATTR_MCAST_GRP_ID])
+			continue;
+
+		gn = nla_data(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+		if (strcmp(gn, name) != 0)
+			continue;
+
+		ret = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+		break;
+	}
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+int unl_genl_subscribe(struct unl *unl, const char *name)
+{
+	int mcid;
+
+	mcid = unl_genl_multicast_id(unl, name);
+	if (mcid < 0)
+		return mcid;
+
+	return nl_socket_add_membership(unl->sock, mcid);
+}
+
+int unl_genl_unsubscribe(struct unl *unl, const char *name)
+{
+	int mcid;
+
+	mcid = unl_genl_multicast_id(unl, name);
+	if (mcid < 0)
+		return mcid;
+
+	return nl_socket_drop_membership(unl->sock, mcid);
+}
+
+int unl_nl80211_phy_lookup(const char *name)
+{
+	char buf[32];
+	int fd, pos;
+
+	snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
+
+	fd = open(buf, O_RDONLY);
+	if (fd < 0)
+		return -1;
+	pos = read(fd, buf, sizeof(buf) - 1);
+	if (pos < 0) {
+		close(fd);
+		return -1;
+	}
+	buf[pos] = '\0';
+	close(fd);
+	return atoi(buf);
+}
+
+int unl_nl80211_wdev_to_phy(struct unl *unl, int wdev)
+{
+	struct nl_msg *msg;
+	struct nlattr *attr;
+	int ret = -1;
+
+	msg = unl_genl_msg(unl, NL80211_CMD_GET_INTERFACE, false);
+	if (!msg)
+		return -1;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
+	if (unl_genl_request_single(unl, msg, &msg) < 0)
+		return -1;
+
+	attr = unl_find_attr(unl, msg, NL80211_ATTR_WIPHY);
+	if (!attr)
+		goto out;
+
+	ret = nla_get_u32(attr);
+out:
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
diff --git a/package/libs/libnl/Makefile b/package/libs/libnl/Makefile
new file mode 100644
index 0000000000..86ef044a17
--- /dev/null
+++ b/package/libs/libnl/Makefile
@@ -0,0 +1,132 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libnl
+PKG_VERSION:=3.2.28
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/thom311/libnl/releases/download/libnl3_2_28
+PKG_MD5SUM:=cd608992c656e8f6e3ab6c1391b162a5a51c49336b9219f7f390e61fc5437c41
+PKG_LICENSE:=LGPL-2.1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnl/default
+  SECTION:=libs
+  CATEGORY:=Libraries
+  URL:=http://www.infradead.org/~tgr/libnl/
+endef
+
+define Package/libnl-core
+$(call Package/libnl/default)
+  TITLE:=Core Netlink Library
+  DEPENDS:=+libpthread
+endef
+
+define Package/libnl-genl
+$(call Package/libnl/default)
+  TITLE:=Generic Netlink Library
+  DEPENDS:=+libnl-core
+endef
+
+define Package/libnl-route
+$(call Package/libnl/default)
+  TITLE:=Routing Netlink Library
+  DEPENDS:=+libnl-core
+endef
+
+define Package/libnl-nf
+$(call Package/libnl/default)
+  TITLE:=Netfilter Netlink Library
+  DEPENDS:=+libnl-route
+endef
+
+define Package/libnl
+$(call Package/libnl/default)
+  TITLE:=Full Netlink Library
+  DEPENDS:=+libnl-genl +libnl-route +libnl-nf
+endef
+
+define Package/libnl-core/description
+ Common code for all netlink libraries
+endef
+
+define Package/libnl-genl/description
+ Generic Netlink Library Functions
+endef
+
+define Package/libnl-route/description
+ Routing Netlink Library Functions
+endef
+
+define Package/libnl-nf/description
+ Netfilter Netlink Library Functions
+endef
+
+define Package/libnl/description
+ Socket handling, connection management, sending and receiving of data,
+ message construction and parsing, object caching system, etc.
+endef
+
+TARGET_CFLAGS += -ffunction-sections $(FPIC)
+
+define Build/Compile
+	$(call Build/Compile/Default)
+	make -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		install
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/libnl3 $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libnl3/* $(1)/usr/include/libnl3/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/* $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/*.pc $(1)/usr/lib/pkgconfig
+
+	# Copy symlinks
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-3.so $(1)/usr/lib/libnl.so
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-genl-3.so $(1)/usr/lib/libnl-genl.so
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-nf-3.so $(1)/usr/lib/libnl-nf.so
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-route-3.so $(1)/usr/lib/libnl-route.so
+endef
+
+define Package/libnl-core/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-3.so* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-3.so $(1)/usr/lib/libnl.so
+endef
+
+define Package/libnl-genl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-genl-3.so* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-genl-3.so $(1)/usr/lib/libnl-genl.so
+endef
+
+define Package/libnl-route/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-route-3.so* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-route-3.so $(1)/usr/lib/libnl-route.so
+endef
+
+define Package/libnl-nf/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-nf-3.so* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnl-nf-3.so $(1)/usr/lib/libnl-nf.so
+endef
+
+define Package/libnl/install
+	:
+endef
+
+$(eval $(call BuildPackage,libnl-core))
+$(eval $(call BuildPackage,libnl-genl))
+$(eval $(call BuildPackage,libnl-route))
+$(eval $(call BuildPackage,libnl-nf))
+$(eval $(call BuildPackage,libnl))
diff --git a/package/libs/libpcap/Config.in b/package/libs/libpcap/Config.in
new file mode 100644
index 0000000000..5fee75a595
--- /dev/null
+++ b/package/libs/libpcap/Config.in
@@ -0,0 +1,15 @@
+menu "Configuration"
+	depends on PACKAGE_libpcap
+
+config PCAP_HAS_USB
+	bool "Include USB support"
+	depends on PACKAGE_kmod-usb-core
+	default n
+
+config PCAP_HAS_BT
+	bool "Include bluetooth support"
+	depends on PACKAGE_kmod-bluetooth
+	depends on BROKEN
+	default n
+
+endmenu
diff --git a/package/libs/libpcap/Makefile b/package/libs/libpcap/Makefile
new file mode 100644
index 0000000000..08fab24fde
--- /dev/null
+++ b/package/libs/libpcap/Makefile
@@ -0,0 +1,97 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libpcap
+PKG_VERSION:=1.7.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.tcpdump.org/release/
+PKG_MD5SUM:=b2e13142bbaba857ab1c6894aedaf547
+PKG_FIXUP:=patch-libtool
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=BSD-3-Clause
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/libpcap
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Low-level packet capture library
+  URL:=http://www.tcpdump.org/
+  MENU:=1
+endef
+
+define Package/libpcap/description
+This package contains a system-independent library for user-level network packet
+capture.
+endef
+
+define Package/libpcap/config
+	source "$(SOURCE)/Config.in"
+endef
+
+TARGET_CFLAGS += \
+	-ffunction-sections \
+	-fdata-sections
+
+CONFIGURE_VARS += \
+	ac_cv_linux_vers=$(LINUX_VERSION) \
+	ac_cv_header_libusb_1_0_libusb_h=no \
+	ac_cv_netfilter_can_compile=no
+
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--disable-yydebug \
+	--with-pcap=linux \
+	--without-septel \
+	--without-dag \
+	--without-libnl \
+	--without-snf \
+	--disable-can \
+	--disable-canusb \
+	--disable-dbus \
+	--disable-bluetooth
+
+ifeq ($(CONFIG_IPV6),y)
+CONFIGURE_ARGS += \
+	--enable-ipv6
+endif
+
+MAKE_FLAGS += \
+	CCOPT="$(TARGET_CFLAGS) -I$(BUILD_DIR)/linux/include"
+
+define Build/Configure
+	$(call Build/Configure/Default)
+	$(if $(CONFIG_PCAP_HAS_USB),,$(SED) '/^#define PCAP_SUPPORT_USB/D' $(PKG_BUILD_DIR)/config.h)
+	$(if $(CONFIG_PCAP_HAS_USB),,$(SED) 's/pcap-usb-linux.c *//' $(PKG_BUILD_DIR)/Makefile)
+	$(if $(CONFIG_PCAP_HAS_BT),,$(SED) '/^#define PCAP_SUPPORT_BT/D' $(PKG_BUILD_DIR)/config.h)
+	$(if $(CONFIG_PCAP_HAS_BT),,$(SED) 's/pcap-bt-linux.c *//' $(PKG_BUILD_DIR)/Makefile)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/pcap* $(1)/usr/include/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcap.{a,so*} $(1)/usr/lib/
+endef
+
+define Package/libpcap/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libpcap.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libpcap))
diff --git a/package/libs/libpcap/patches/100-debian_shared_lib.patch b/package/libs/libpcap/patches/100-debian_shared_lib.patch
new file mode 100644
index 0000000000..9ed6793f94
--- /dev/null
+++ b/package/libs/libpcap/patches/100-debian_shared_lib.patch
@@ -0,0 +1,178 @@
+Debian-specific modifications to the upstream Makefile.in to
+build a shared library.
+
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -38,6 +38,14 @@ mandir = @mandir@
+ srcdir = @srcdir@
+ VPATH = @srcdir@
+ 
++# some defines for shared library compilation
++MAJ=1.3
++LIBVERSION=$(MAJ).0
++LIBNAME=pcap
++LIBRARY=lib$(LIBNAME).a
++SOLIBRARY=lib$(LIBNAME).so
++SHAREDLIB=$(SOLIBRARY).$(LIBVERSION)
++
+ #
+ # You shouldn't need to edit anything below.
+ #
+@@ -62,7 +70,8 @@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@
+ PROG=libpcap
+ 
+ # Standard CFLAGS
+-FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
++FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) $(CPPFLAGS)
++CFLAGS_SHARED = -shared -Wl,-soname,$(SOLIBRARY).$(MAJ)
+ 
+ INSTALL = @INSTALL@
+ INSTALL_PROGRAM = @INSTALL_PROGRAM@
+@@ -82,7 +91,11 @@ YACC = @V_YACC@
+ # problem if you don't own the file but can write to the directory.
+ .c.o:
+ 	@rm -f $@
+-	$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
++	$(CC) $(FULL_CFLAGS) -c -o $@ $(srcdir)/$*.c
++
++%_pic.o: %.c
++	@rm -f $@
++	$(CC) -fPIC $(FULL_CFLAGS) -c -o $@ $(srcdir)/$*.c
+ 
+ PSRC =	pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@
+ FSRC =  fad-@V_FINDALLDEVS@.c
+@@ -98,6 +111,7 @@ SRC =	$(PSRC) $(FSRC) $(CSRC) $(SSRC) $(
+ # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot
+ # hack the extra indirection
+ OBJ =	$(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(SSRC:.c=.o) $(GENSRC:.c=.o) $(LIBOBJS)
++OBJ_PIC = $(PSRC:.c=_pic.o) $(FSRC:.c=_pic.o) $(CSRC:.c=_pic.o) $(SSRC:.c=_pic.o) $(GENSRC:.c=_pic.o)
+ PUBHDR = \
+ 	pcap.h \
+ 	pcap-bpf.h \
+@@ -153,7 +167,7 @@ TAGFILES = \
+ 
+ CLEANFILES = $(OBJ) libpcap.* $(TESTS) \
+ 	$(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENSRC) $(GENHDR) \
+-	lex.yy.c pcap-config
++	lex.yy.c pcap-config $(OBJ_PIC)
+ 
+ MAN1 = pcap-config.1
+ 
+@@ -365,7 +379,7 @@ libpcap.a: $(OBJ)
+ 	$(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS)
+ 	$(RANLIB) $@
+ 
+-shared: libpcap.$(DYEXT)
++shared: $(SHAREDLIB)
+ 
+ libpcap.so: $(OBJ)
+ 	@rm -f $@
+@@ -443,6 +457,13 @@ libpcap.shareda: $(OBJ)
+ #
+ libpcap.none:
+ 
++$(SHAREDLIB): $(OBJ_PIC)
++	-@rm -f $@
++	-@rm -f $(SOLIBRARY) $(SOLIBRARY).$(MAJ)
++	$(CC) $(CFLAGS_SHARED) $(LDFLAGS) -o $(SHAREDLIB) $(OBJ_PIC) -lc $(LIBS)
++	ln -s $(SHAREDLIB) $(SOLIBRARY).$(MAJ)
++	ln -s $(SOLIBRARY).$(MAJ) $(SOLIBRARY)
++
+ scanner.c: $(srcdir)/scanner.l
+ 	@rm -f $@ $@.bottom
+ 	$(srcdir)/runlex.sh $(LEX) -o$@ $<
+@@ -453,6 +474,9 @@ scanner.c: $(srcdir)/scanner.l
+ scanner.o: scanner.c tokdefs.h
+ 	$(CC) $(FULL_CFLAGS) -c scanner.c
+ 
++scanner_pic.o: scanner.c tokdefs.h
++	$(CC) -fPIC $(FULL_CFLAGS) -o $@ -c scanner.c
++
+ pcap.o: version.h
+ 
+ tokdefs.h: grammar.c
+@@ -466,9 +490,16 @@ grammar.o: grammar.c
+ 	@rm -f $@
+ 	$(CC) $(FULL_CFLAGS) -Dyylval=pcap_lval -c grammar.c
+ 
++grammar_pic.o: grammar.c
++	@rm -f $@
++	$(CC) -fPIC $(FULL_CFLAGS) -Dyylval=pcap_lval -o $@ -c grammar.c
++
+ version.o: version.c
+ 	$(CC) $(FULL_CFLAGS) -c version.c
+ 
++version_pic.o: version.c
++	$(CC) -fPIC $(FULL_CFLAGS) -c version.c -o $@
++
+ snprintf.o: $(srcdir)/missing/snprintf.c
+ 	$(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c
+ 
+@@ -506,6 +537,9 @@ bpf_filter.c: $(srcdir)/bpf/net/bpf_filt
+ bpf_filter.o: bpf_filter.c
+ 	$(CC) $(FULL_CFLAGS) -c bpf_filter.c
+ 
++bpf_filter_pic.o: bpf_filter.c
++	$(CC) -fPIC $(FULL_CFLAGS) -c bpf_filter.c -o $@
++
+ #
+ # Generate the pcap-config script.
+ #
+@@ -622,14 +656,12 @@ install: install-shared install-archive
+ 		    $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done
+ 
+ install-shared: install-shared-$(DYEXT)
+-install-shared-so: libpcap.so
++install-shared-so: $(SHAREDLIB)
+ 	[ -d $(DESTDIR)$(libdir) ] || \
+ 	    (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir))
+-	VER=`cat $(srcdir)/VERSION`; \
+-	MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \
+-	$(INSTALL_PROGRAM) libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$VER; \
+-	ln -sf libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \
+-	ln -sf libpcap.so.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.so
++	$(INSTALL_DATA) $(SHAREDLIB) $(DESTDIR)$(libdir)/
++	ln -sf $(SHAREDLIB) $(DESTDIR)$(libdir)/$(SOLIBRARY).$(MAJ)
++	ln -sf $(SOLIBRARY).$(MAJ) $(DESTDIR)$(libdir)/$(SOLIBRARY)
+ install-shared-dylib: libpcap.dylib
+ 	[ -d $(DESTDIR)$(libdir) ] || \
+ 	    (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir))
+--- a/aclocal.m4
++++ b/aclocal.m4
+@@ -438,7 +438,7 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT,
+ 			esac
+ 			;;
+ 		    esac
+-		    V_CCOPT="$V_CCOPT $PIC_OPT"
++		    V_CCOPT="$V_CCOPT"
+ 		    V_SONAME_OPT="-Wl,-soname,"
+ 		    V_RPATH_OPT="-Wl,-rpath,"
+ 		    ;;
+@@ -501,7 +501,7 @@ AC_DEFUN(AC_LBL_SHLIBS_INIT,
+ 		    #
+ 		    # "cc" is GCC.
+ 		    #
+-		    V_CCOPT="$V_CCOPT -fpic"
++		    V_CCOPT="$V_CCOPT"
+ 		    V_SHLIB_CMD="\$(CC)"
+ 		    V_SHLIB_OPT="-shared"
+ 		    V_SONAME_OPT="-Wl,-soname,"
+--- a/pcap-config.in
++++ b/pcap-config.in
+@@ -36,16 +36,6 @@ do
+ 	esac
+ 	shift
+ done
+-if [ "$V_RPATH_OPT" != "" ]
+-then
+-	#
+-	# If libdir isn't /usr/lib, add it to the run-time linker path.
+-	#
+-	if [ "$libdir" != "/usr/lib" ]
+-	then
+-		RPATH=$V_RPATH_OPT$libdir
+-	fi
+-fi
+ if [ "$static" = 1 ]
+ then
+ 	#
diff --git a/package/libs/libpcap/patches/102-makefile_disable_manpages.patch b/package/libs/libpcap/patches/102-makefile_disable_manpages.patch
new file mode 100644
index 0000000000..59b903c413
--- /dev/null
+++ b/package/libs/libpcap/patches/102-makefile_disable_manpages.patch
@@ -0,0 +1,73 @@
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -590,70 +590,12 @@ install: install-shared install-archive
+ 	    (mkdir -p $(DESTDIR)$(includedir); chmod 755 $(DESTDIR)$(includedir))
+ 	[ -d $(DESTDIR)$(includedir)/pcap ] || \
+ 	    (mkdir -p $(DESTDIR)$(includedir)/pcap; chmod 755 $(DESTDIR)$(includedir)/pcap)
+-	[ -d $(DESTDIR)$(mandir)/man1 ] || \
+-	    (mkdir -p $(DESTDIR)$(mandir)/man1; chmod 755 $(DESTDIR)$(mandir)/man1)
+-	[ -d $(DESTDIR)$(mandir)/man3 ] || \
+-	    (mkdir -p $(DESTDIR)$(mandir)/man3; chmod 755 $(DESTDIR)$(mandir)/man3)
+-	[ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \
+-	    (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@)
+-	[ -d $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@ ] || \
+-	    (mkdir -p $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@)
+ 	for i in $(PUBHDR); do \
+ 		$(INSTALL_DATA) $(srcdir)/$$i \
+ 		    $(DESTDIR)$(includedir)/$$i; done
+ 	[ -d $(DESTDIR)$(bindir) ] || \
+ 	    (mkdir -p $(DESTDIR)$(bindir); chmod 755 $(DESTDIR)$(bindir))
+ 	$(INSTALL_PROGRAM) pcap-config $(DESTDIR)$(bindir)/pcap-config
+-	for i in $(MAN1); do \
+-		$(INSTALL_DATA) $(srcdir)/$$i \
+-		    $(DESTDIR)$(mandir)/man1/$$i; done
+-	for i in $(MAN3PCAP_NOEXPAND); do \
+-		$(INSTALL_DATA) $(srcdir)/$$i \
+-		    $(DESTDIR)$(mandir)/man3/$$i; done
+-	for i in $(MAN3PCAP_EXPAND:.in=); do \
+-		$(INSTALL_DATA) $$i \
+-		    $(DESTDIR)$(mandir)/man3/$$i; done
+-	(cd $(DESTDIR)$(mandir)/man3 && \
+-	rm -f pcap_datalink_val_to_description.3pcap && \
+-	$(LN_S) pcap_datalink_val_to_name.3pcap \
+-		 pcap_datalink_val_to_description.3pcap && \
+-	rm -f pcap_dump_fopen.3pcap && \
+-	$(LN_S) pcap_dump_open.3pcap pcap_dump_fopen.3pcap && \
+-	rm -f pcap_freealldevs.3pcap && \
+-	$(LN_S) pcap_findalldevs.3pcap pcap_freealldevs.3pcap && \
+-	rm -f pcap_perror.3pcap && \
+-	$(LN_S) pcap_geterr.3pcap pcap_perror.3pcap && \
+-	rm -f pcap_sendpacket.3pcap && \
+-	$(LN_S) pcap_inject.3pcap pcap_sendpacket.3pcap && \
+-	rm -f pcap_free_datalinks.3pcap && \
+-	$(LN_S) pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap && \
+-	rm -f pcap_free_tstamp_types.3pcap && \
+-	$(LN_S) pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap && \
+-	rm -f pcap_dispatch.3pcap && \
+-	$(LN_S) pcap_loop.3pcap pcap_dispatch.3pcap && \
+-	rm -f pcap_minor_version.3pcap && \
+-	$(LN_S) pcap_major_version.3pcap pcap_minor_version.3pcap && \
+-	rm -f pcap_next.3pcap && \
+-	$(LN_S) pcap_next_ex.3pcap pcap_next.3pcap && \
+-	rm -f pcap_open_dead_with_tstamp_precision.3pcap && \
+-	$(LN_S) pcap_open_dead.3pcap \
+-		 pcap_open_dead_with_tstamp_precision.3pcap && \
+-	rm -f pcap_open_offline_with_tstamp_precision.3pcap && \
+-	$(LN_S) pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap && \
+-	rm -f pcap_fopen_offline.3pcap && \
+-	$(LN_S) pcap_open_offline.3pcap pcap_fopen_offline.3pcap && \
+-	rm -f pcap_fopen_offline_with_tstamp_precision.3pcap && \
+-	$(LN_S) pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap && \
+-	rm -f pcap_tstamp_type_val_to_description.3pcap && \
+-	$(LN_S) pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap && \
+-	rm -f pcap_getnonblock.3pcap && \
+-	$(LN_S) pcap_setnonblock.3pcap pcap_getnonblock.3pcap)
+-	for i in $(MANFILE); do \
+-		$(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \
+-		    $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done
+-	for i in $(MANMISC); do \
+-		$(INSTALL_DATA) `echo $$i | sed 's/.manmisc.in/.manmisc/'` \
+-		    $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done
+ 
+ install-shared: install-shared-$(DYEXT)
+ install-shared-so: libpcap.so
diff --git a/package/libs/libpcap/patches/103-makefile_flex_workaround.patch b/package/libs/libpcap/patches/103-makefile_flex_workaround.patch
new file mode 100644
index 0000000000..a7ab9ad054
--- /dev/null
+++ b/package/libs/libpcap/patches/103-makefile_flex_workaround.patch
@@ -0,0 +1,14 @@
+
+	Copyright (C) 2006 Markus Wigge
+
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -57,7 +57,7 @@ LN_S = @LN_S@
+ MKDEP = @MKDEP@
+ CCOPT = @V_CCOPT@
+ INCLS = -I. @V_INCLS@
+-DEFS = @DEFS@ @V_DEFS@
++DEFS = -D_BSD_SOURCE @DEFS@ @V_DEFS@
+ ADDLOBJS = @ADDLOBJS@
+ ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@
+ LIBS = @LIBS@
diff --git a/package/libs/libpcap/patches/201-space_optimization.patch b/package/libs/libpcap/patches/201-space_optimization.patch
new file mode 100644
index 0000000000..f331a18357
--- /dev/null
+++ b/package/libs/libpcap/patches/201-space_optimization.patch
@@ -0,0 +1,159 @@
+--- a/gencode.c
++++ b/gencode.c
+@@ -543,20 +543,6 @@ pcap_compile_nopcap(int snaplen_arg, int
+ }
+ 
+ /*
+- * Clean up a "struct bpf_program" by freeing all the memory allocated
+- * in it.
+- */
+-void
+-pcap_freecode(struct bpf_program *program)
+-{
+-	program->bf_len = 0;
+-	if (program->bf_insns != NULL) {
+-		free((char *)program->bf_insns);
+-		program->bf_insns = NULL;
+-	}
+-}
+-
+-/*
+  * Backpatch the blocks in 'list' to 'target'.  The 'sense' field indicates
+  * which of the jt and jf fields has been resolved and which is a pointer
+  * back to another unresolved block (or nil).  At least one of the fields
+--- a/pcap.c
++++ b/pcap.c
+@@ -1087,6 +1087,59 @@ static const u_char charmap[] = {
+ 	(u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
+ };
+ 
++/*
++ * Clean up a "struct bpf_program" by freeing all the memory allocated
++ * in it.
++ */
++void
++pcap_freecode(struct bpf_program *program)
++{
++	program->bf_len = 0;
++	if (program->bf_insns != NULL) {
++		free((char *)program->bf_insns);
++		program->bf_insns = NULL;
++	}
++}
++
++/*
++ * Make a copy of a BPF program and put it in the "fcode" member of
++ * a "pcap_t".
++ *
++ * If we fail to allocate memory for the copy, fill in the "errbuf"
++ * member of the "pcap_t" with an error message, and return -1;
++ * otherwise, return 0.
++ */
++int
++install_bpf_program(pcap_t *p, struct bpf_program *fp)
++{
++	size_t prog_size;
++
++	/*
++	 * Validate the program.
++	 */
++	if (!bpf_validate(fp->bf_insns, fp->bf_len)) {
++		snprintf(p->errbuf, sizeof(p->errbuf),
++			"BPF program is not valid");
++		return (-1);
++	}
++
++	/*
++	 * Free up any already installed program.
++	 */
++	pcap_freecode(&p->fcode);
++
++	prog_size = sizeof(*fp->bf_insns) * fp->bf_len;
++	p->fcode.bf_len = fp->bf_len;
++	p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);
++	if (p->fcode.bf_insns == NULL) {
++		snprintf(p->errbuf, sizeof(p->errbuf),
++			 "malloc: %s", pcap_strerror(errno));
++		return (-1);
++	}
++	memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size);
++	return (0);
++}
++
+ int
+ pcap_strcasecmp(const char *s1, const char *s2)
+ {
+--- a/optimize.c
++++ b/optimize.c
+@@ -2203,45 +2203,6 @@ icode_to_fcode(struct block *root, u_int
+ 	return fp;
+ }
+ 
+-/*
+- * Make a copy of a BPF program and put it in the "fcode" member of
+- * a "pcap_t".
+- *
+- * If we fail to allocate memory for the copy, fill in the "errbuf"
+- * member of the "pcap_t" with an error message, and return -1;
+- * otherwise, return 0.
+- */
+-int
+-install_bpf_program(pcap_t *p, struct bpf_program *fp)
+-{
+-	size_t prog_size;
+-
+-	/*
+-	 * Validate the program.
+-	 */
+-	if (!bpf_validate(fp->bf_insns, fp->bf_len)) {
+-		snprintf(p->errbuf, sizeof(p->errbuf),
+-			"BPF program is not valid");
+-		return (-1);
+-	}
+-
+-	/*
+-	 * Free up any already installed program.
+-	 */
+-	pcap_freecode(&p->fcode);
+-
+-	prog_size = sizeof(*fp->bf_insns) * fp->bf_len;
+-	p->fcode.bf_len = fp->bf_len;
+-	p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);
+-	if (p->fcode.bf_insns == NULL) {
+-		snprintf(p->errbuf, sizeof(p->errbuf),
+-			 "malloc: %s", pcap_strerror(errno));
+-		return (-1);
+-	}
+-	memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size);
+-	return (0);
+-}
+-
+ #ifdef BDEBUG
+ static void
+ dot_dump_node(struct block *block, struct bpf_program *prog, FILE *out)
+--- a/pcap-common.c
++++ b/pcap-common.c
+@@ -1372,14 +1372,23 @@ swap_pseudo_headers(int linktype, struct
+ 	switch (linktype) {
+ 
+ 	case DLT_USB_LINUX:
++#ifndef PCAP_SUPPORT_USB
++		return;
++#endif
+ 		swap_linux_usb_header(hdr, data, 0);
+ 		break;
+ 
+ 	case DLT_USB_LINUX_MMAPPED:
++#ifndef PCAP_SUPPORT_USB
++		return;
++#endif
+ 		swap_linux_usb_header(hdr, data, 1);
+ 		break;
+ 
+ 	case DLT_NFLOG:
++#ifndef PCAP_SUPPORT_NETFILTER
++		return;
++#endif
+ 		swap_nflog_header(hdr, data);
+ 		break;
+ 	}
diff --git a/package/libs/libpcap/patches/202-protocol_api.patch b/package/libs/libpcap/patches/202-protocol_api.patch
new file mode 100644
index 0000000000..d0c32a5e22
--- /dev/null
+++ b/package/libs/libpcap/patches/202-protocol_api.patch
@@ -0,0 +1,140 @@
+--- a/pcap-linux.c
++++ b/pcap-linux.c
+@@ -414,7 +414,7 @@ static int	iface_get_id(int fd, const ch
+ static int	iface_get_mtu(int fd, const char *device, char *ebuf);
+ static int 	iface_get_arptype(int fd, const char *device, char *ebuf);
+ #ifdef HAVE_PF_PACKET_SOCKETS
+-static int 	iface_bind(int fd, int ifindex, char *ebuf);
++static int 	iface_bind(int fd, int ifindex, char *ebuf, unsigned short proto);
+ #ifdef IW_MODE_MONITOR
+ static int	has_wext(int sock_fd, const char *device, char *ebuf);
+ #endif /* IW_MODE_MONITOR */
+@@ -1028,7 +1028,7 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
+ 	 * (We assume that if we have Wireless Extensions support
+ 	 * we also have PF_PACKET support.)
+ 	 */
+-	sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
++	sock_fd = socket(PF_PACKET, SOCK_RAW, p->opt.proto);
+ 	if (sock_fd == -1) {
+ 		(void)snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ 		    "socket: %s", pcap_strerror(errno));
+@@ -1337,6 +1337,9 @@ pcap_activate_linux(pcap_t *handle)
+ 	handle->read_op = pcap_read_linux;
+ 	handle->stats_op = pcap_stats_linux;
+ 
++	if (handle->opt.proto < 0)
++		handle->opt.proto = (int) htons(ETH_P_ALL);
++
+ 	/*
+ 	 * The "any" device is a special device which causes us not
+ 	 * to bind to a particular device and thus to look at all
+@@ -3160,8 +3163,8 @@ activate_new(pcap_t *handle)
+ 	 * try a SOCK_RAW socket for the raw interface.
+ 	 */
+ 	sock_fd = is_any_device ?
+-		socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)) :
+-		socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
++		socket(PF_PACKET, SOCK_DGRAM, handle->opt.proto) :
++		socket(PF_PACKET, SOCK_RAW, handle->opt.proto);
+ 
+ 	if (sock_fd == -1) {
+ 		if (errno == EINVAL || errno == EAFNOSUPPORT) {
+@@ -3279,7 +3282,7 @@ activate_new(pcap_t *handle)
+ 				return PCAP_ERROR;
+ 			}
+ 			sock_fd = socket(PF_PACKET, SOCK_DGRAM,
+-			    htons(ETH_P_ALL));
++			    handle->opt.proto);
+ 			if (sock_fd == -1) {
+ 				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ 				    "socket: %s", pcap_strerror(errno));
+@@ -3343,7 +3346,7 @@ activate_new(pcap_t *handle)
+ 		}
+ 
+ 		if ((err = iface_bind(sock_fd, handlep->ifindex,
+-		    handle->errbuf)) != 1) {
++		    handle->errbuf, handle->opt.proto)) != 1) {
+ 		    	close(sock_fd);
+ 			if (err < 0)
+ 				return err;
+@@ -5050,7 +5053,7 @@ iface_get_id(int fd, const char *device,
+  *  or a PCAP_ERROR_ value on a hard error.
+  */
+ static int
+-iface_bind(int fd, int ifindex, char *ebuf)
++iface_bind(int fd, int ifindex, char *ebuf, unsigned short proto)
+ {
+ 	struct sockaddr_ll	sll;
+ 	int			err;
+@@ -5059,7 +5062,7 @@ iface_bind(int fd, int ifindex, char *eb
+ 	memset(&sll, 0, sizeof(sll));
+ 	sll.sll_family		= AF_PACKET;
+ 	sll.sll_ifindex		= ifindex;
+-	sll.sll_protocol	= htons(ETH_P_ALL);
++	sll.sll_protocol	= proto;
+ 
+ 	if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) {
+ 		if (errno == ENETDOWN) {
+@@ -6049,7 +6052,7 @@ activate_old(pcap_t *handle)
+ 
+ 	/* Open the socket */
+ 
+-	handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
++	handle->fd = socket(PF_INET, SOCK_PACKET, handle->opt.proto);
+ 	if (handle->fd == -1) {
+ 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ 			 "socket: %s", pcap_strerror(errno));
+--- a/pcap.c
++++ b/pcap.c
+@@ -562,6 +562,7 @@ pcap_create_common(const char *source, c
+ 	p->opt.promisc = 0;
+ 	p->opt.rfmon = 0;
+ 	p->opt.immediate = 0;
++	p->opt.proto = -1;
+ 	p->opt.tstamp_type = -1;	/* default to not setting time stamp type */
+ 	p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO;
+ 
+@@ -725,6 +726,15 @@ pcap_get_tstamp_precision(pcap_t *p)
+ }
+ 
+ int
++pcap_set_protocol(pcap_t *p, unsigned short proto)
++{
++	if (pcap_check_activated(p))
++		return PCAP_ERROR_ACTIVATED;
++	p->opt.proto = proto;
++	return 0;
++}
++
++int
+ pcap_activate(pcap_t *p)
+ {
+ 	int status;
+--- a/pcap/pcap.h
++++ b/pcap/pcap.h
+@@ -66,6 +66,7 @@ extern "C" {
+ #define PCAP_VERSION_MINOR 4
+ 
+ #define PCAP_ERRBUF_SIZE 256
++#define HAS_PROTO_EXTENSION
+ 
+ /*
+  * Compatibility for systems that have a bpf.h that
+@@ -283,6 +284,7 @@ int	pcap_set_timeout(pcap_t *, int);
+ int	pcap_set_tstamp_type(pcap_t *, int);
+ int	pcap_set_immediate_mode(pcap_t *, int);
+ int	pcap_set_buffer_size(pcap_t *, int);
++int	pcap_set_protocol(pcap_t *, unsigned short);
+ int	pcap_set_tstamp_precision(pcap_t *, int);
+ int	pcap_get_tstamp_precision(pcap_t *);
+ int	pcap_activate(pcap_t *);
+--- a/pcap-int.h
++++ b/pcap-int.h
+@@ -109,6 +109,7 @@ struct pcap_opt {
+ 	char	*source;
+ 	int	timeout;	/* timeout for buffering */
+ 	int	buffer_size;
++	int	proto;      /* protocol for packet socket (linux) */
+ 	int	promisc;
+ 	int	rfmon;		/* monitor mode */
+ 	int	immediate;	/* immediate mode - deliver packets as soon as they arrive */
diff --git a/package/libs/libpcap/patches/203-undef_iw_mode_monitor.patch b/package/libs/libpcap/patches/203-undef_iw_mode_monitor.patch
new file mode 100644
index 0000000000..f847a5e754
--- /dev/null
+++ b/package/libs/libpcap/patches/203-undef_iw_mode_monitor.patch
@@ -0,0 +1,11 @@
+--- a/pcap-linux.c
++++ b/pcap-linux.c
+@@ -254,6 +254,8 @@
+ typedef int		socklen_t;
+ #endif
+ 
++#undef IW_MODE_MONITOR
++
+ #ifndef MSG_TRUNC
+ /*
+  * This is being compiled on a system that lacks MSG_TRUNC; define it
diff --git a/package/libs/libreadline/Makefile b/package/libs/libreadline/Makefile
new file mode 100644
index 0000000000..5b0ca8314d
--- /dev/null
+++ b/package/libs/libreadline/Makefile
@@ -0,0 +1,72 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=readline
+PKG_VERSION:=7.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/readline
+PKG_MD5SUM:=750d437185286f40a369e1e4f4764eda932b9459b5ec9a731628393dd3d32334
+
+PKG_LICENSE:=GPL-3.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_BUILD_PARALLEL:=1
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libreadline
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Command lines edition library
+  URL:=http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
+  ABI_VERSION:=$(PKG_VERSION)
+endef
+
+define Package/libreadline/description
+	The Readline library provides a set of functions for use by applications 
+	that allow users to edit command lines as they are typed in. Both Emacs 
+	and vi editing modes are available. The Readline library includes 
+	additional functions to maintain a list of previously-entered command 
+	lines, to recall and perhaps reedit those lines, and perform csh-like 
+	history expansion on previous commands.
+endef
+
+# prevent "autoreconf" from removing "aclocal.m4"
+PKG_REMOVE_FILES:=
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--with-curses \
+
+CONFIGURE_VARS += \
+	bash_cv_wcwidth_broken=no \
+	bash_cv_func_sigsetjmp=yes \
+
+TARGET_CPPFLAGS:=-I. -I.. $(TARGET_CPPFLAGS)
+
+TARGET_CFLAGS += $(FPIC)
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/readline $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib{history,readline}.{a,so,so.7,so.7.0} $(1)/usr/lib/
+endef
+
+define Package/libreadline/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib{history,readline}.{so,so.7,so.7.0} $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libreadline))
diff --git a/package/libs/libreadline/patches/001-install_perm.patch b/package/libs/libreadline/patches/001-install_perm.patch
new file mode 100644
index 0000000000..951ff73e5b
--- /dev/null
+++ b/package/libs/libreadline/patches/001-install_perm.patch
@@ -0,0 +1,11 @@
+--- a/support/shlib-install
++++ b/support/shlib-install
+@@ -73,7 +73,7 @@ fi
+ case "$host_os" in
+ hpux*|darwin*|macosx*|linux*|solaris2*)
+ 	if [ -z "$uninstall" ]; then
+-		chmod 555 ${INSTALLDIR}/${LIBNAME}
++		chmod +x ${INSTALLDIR}/${LIBNAME}
+ 	fi ;;
+ cygwin*|mingw*)
+ 	IMPLIBNAME=`echo ${LIBNAME} \
diff --git a/package/libs/libroxml/Makefile b/package/libs/libroxml/Makefile
new file mode 100644
index 0000000000..dcbe610490
--- /dev/null
+++ b/package/libs/libroxml/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libroxml
+PKG_VERSION:=2.3.0
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://download.libroxml.net/pool/v2.x
+PKG_MD5SUM:=a975f91be150f7a19168a45ce15769ca
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=LGPL-2.1+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libroxml
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Minimum, easy-to-use, C implementation for xml file parsing
+  URL:=http://www.libroxml.net/
+endef
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--disable-roxml
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+endef
+
+define Package/libroxml/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libroxml.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libroxml))
diff --git a/package/libs/librpc/Makefile b/package/libs/librpc/Makefile
new file mode 100644
index 0000000000..b3dcd47c89
--- /dev/null
+++ b/package/libs/librpc/Makefile
@@ -0,0 +1,35 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=librpc
+PKG_VERSION:=2015-11-04
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/librpc-uclibc.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=a921e3ded051746f9f7cd5e5a312fb6771716aac
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=d8da52536d34c6116ac8c261cbfc5999ae48b88e304ebf24a8cb14a43e53a3d9
+CMAKE_INSTALL:=1
+PKG_USE_MIPS16:=0
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/librpc
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=uClibc RPC library
+endef
+
+define Package/librpc/install
+	$(INSTALL_DIR) $(1)/lib/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/librpc.so $(1)/lib/
+endef
+
+$(eval $(call BuildPackage,librpc))
diff --git a/package/libs/libtool/Makefile b/package/libs/libtool/Makefile
new file mode 100644
index 0000000000..47b8907c23
--- /dev/null
+++ b/package/libs/libtool/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libtool
+PKG_VERSION:=2.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/libtool
+PKG_MD5SUM:=afcce660d3dc54c63a0a5ba3cf05272239dc3c54bbeba20f6bad250f9dc007ae
+
+PKG_LICENSE:=GPL-2.0+
+PKG_LICENSE_FILES:=COPYING
+
+PKG_BUILD_PARALLEL:=0
+
+include $(INCLUDE_DIR)/package.mk
+
+CONFIGURE_PREFIX=$(STAGING_DIR)/host
+export GLOBAL_LIBDIR=$(STAGING_DIR)/usr/lib
+
+define Package/libltdl
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=A generic dynamic object loading library
+  URL:=http://www.gnu.org/software/libtool/
+endef
+
+define Build/InstallDev
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		bindir="$(2)/bin" \
+		datadir="$(2)/share" \
+		prefix="$(2)" \
+		exec_prefix="$(2)" \
+		install
+	$(INSTALL_DIR) $(1)/usr/lib $(1)/usr/include
+	mv $(2)/lib/* $(1)/usr/lib/
+	mv $(2)/include/* $(1)/usr/include/
+endef
+
+define Package/libltdl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libltdl/.libs/libltdl.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libltdl))
diff --git a/package/libs/libtool/patches/160-passthrough-ssp.patch b/package/libs/libtool/patches/160-passthrough-ssp.patch
new file mode 100644
index 0000000000..6fcbe68000
--- /dev/null
+++ b/package/libs/libtool/patches/160-passthrough-ssp.patch
@@ -0,0 +1,11 @@
+--- a/libltdl/config/ltmain.m4sh
++++ b/libltdl/config/ltmain.m4sh
+@@ -5051,7 +5051,7 @@ func_mode_link ()
+       # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+-      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++      -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+         func_quote_for_eval "$arg"
+ 	arg="$func_quote_for_eval_result"
+         func_append compile_command " $arg"
diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile
new file mode 100644
index 0000000000..4fe875184d
--- /dev/null
+++ b/package/libs/libubox/Makefile
@@ -0,0 +1,99 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libubox
+PKG_VERSION:=2016-11-29
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/libubox.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=77a629375d7387a33a59509d9d751a8798134cab
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=686a0078da3ada68fc9d39f62df07be52589afce79969ec4039f38f85ccedd3c
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_DEPENDS:=lua
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/libubox
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Basic utility library
+  ABI_VERSION:=$(PKG_VERSION)
+  DEPENDS:=
+endef
+
+define Package/libblobmsg-json
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=blobmsg <-> json conversion library
+  DEPENDS:=+libjson-c +libubox
+endef
+
+define Package/jshn
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libjson-c +libubox +libblobmsg-json
+  TITLE:=JSON SHell Notation
+endef
+
+define Package/jshn/description
+  Library for parsing and generating JSON from shell scripts
+endef
+
+define Package/libjson-script
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libubox
+  TITLE:=Minimalistic JSON based scripting engine
+endef
+
+define Package/libubox-lua
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libubox +liblua
+  TITLE:=Lua binding for the OpenWrt Basic utility library
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+CMAKE_OPTIONS = \
+	-DLUAPATH=/usr/lib/lua
+
+define Package/libubox/install
+	$(INSTALL_DIR) $(1)/lib/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libubox.so $(1)/lib/
+endef
+
+define Package/libblobmsg-json/install
+	$(INSTALL_DIR) $(1)/lib/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libblobmsg_json.so $(1)/lib/
+endef
+
+define Package/jshn/install
+	$(INSTALL_DIR) $(1)/usr/bin $(1)/usr/share/libubox
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/jshn $(1)/usr/bin
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libubox/jshn.sh $(1)/usr/share/libubox
+endef
+
+define Package/libjson-script/install
+	$(INSTALL_DIR) $(1)/lib/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libjson_script.so $(1)/lib/
+endef
+
+define Package/libubox-lua/install
+	$(INSTALL_DIR) $(1)/usr/lib/lua
+	$(CP) $(PKG_BUILD_DIR)/lua/uloop.so $(1)/usr/lib/lua/
+endef
+
+$(eval $(call BuildPackage,libubox))
+$(eval $(call BuildPackage,libblobmsg-json))
+$(eval $(call BuildPackage,jshn))
+$(eval $(call BuildPackage,libjson-script))
+$(eval $(call BuildPackage,libubox-lua))
diff --git a/package/libs/libunwind/Makefile b/package/libs/libunwind/Makefile
new file mode 100644
index 0000000000..6cec8a7345
--- /dev/null
+++ b/package/libs/libunwind/Makefile
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2008-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libunwind
+PKG_VERSION:=1.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SAVANNAH/$(PKG_NAME)
+PKG_MD5SUM:=fb4ea2f6fbbe45bf032cd36e586883ce
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+PKG_LICENSE:=X11
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_MAINTAINER:=Yousong Zhou <yszhou4tech@gmail.com>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libunwind
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=The libunwind project
+  URL:=http://www.nongnu.org/libunwind/
+  DEPENDS:=@(mips||mipsel||powerpc||i386||x86_64)
+endef
+
+define Package/libunwind/description
+  Libunwind defines a portable and efficient C programming interface (API) to determine the call-chain of a program.
+endef
+
+CONFIGURE_ARGS += --enable-minidebuginfo=no
+
+define Package/libunwind/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libunwin*.so* $(1)/usr/lib/
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libunwin*.so* $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/* $(1)/usr/lib/pkgconfig/
+endef
+
+$(eval $(call BuildPackage,libunwind))
diff --git a/package/libs/libunwind/patches/001-disable-tests.patch b/package/libs/libunwind/patches/001-disable-tests.patch
new file mode 100644
index 0000000000..9700fea477
--- /dev/null
+++ b/package/libs/libunwind/patches/001-disable-tests.patch
@@ -0,0 +1,22 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -36,7 +36,7 @@
+ 
+ nodist_include_HEADERS = include/libunwind-common.h
+ 
+-SUBDIRS = src tests doc
++SUBDIRS = src doc
+ 
+ noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h	\
+ 	include/compiler.h include/libunwind_i.h include/mempool.h	\
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -313,7 +313,7 @@
+ 	$(am__append_7) $(am__append_8) $(am__append_9) \
+ 	$(am__append_10)
+ nodist_include_HEADERS = include/libunwind-common.h
+-SUBDIRS = src tests doc
++SUBDIRS = src doc
+ noinst_HEADERS = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h	\
+ 	include/compiler.h include/libunwind_i.h include/mempool.h	\
+ 	include/remote.h						\
diff --git a/package/libs/libunwind/patches/002-fix-building-getcontext_S.patch b/package/libs/libunwind/patches/002-fix-building-getcontext_S.patch
new file mode 100644
index 0000000000..10b1dd1d90
--- /dev/null
+++ b/package/libs/libunwind/patches/002-fix-building-getcontext_S.patch
@@ -0,0 +1,19 @@
+diff -uprN a/src/mips/getcontext.S b/src/mips/getcontext.S
+--- a/src/mips/getcontext.S	2012-10-06 12:54:38.000000000 +0800
++++ b/src/mips/getcontext.S	2016-06-08 13:35:25.033051679 +0800
+@@ -24,12 +24,12 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+ 
+ #include "offsets.h"
+-#include <endian.h>
+ 
+ 	.text
++	.set nomips16
+ 
+ #if _MIPS_SIM == _ABIO32
+-# if __BYTE_ORDER == __BIG_ENDIAN
++# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ #  define OFFSET 4
+ # else
+ #  define OFFSET 0
+
diff --git a/package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch b/package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch
new file mode 100644
index 0000000000..465abb4ce0
--- /dev/null
+++ b/package/libs/libunwind/patches/003-fix-missing-ef_reg-defs-with-musl.patch
@@ -0,0 +1,47 @@
+diff -uprN a/include/libunwind-mips.h b/include/libunwind-mips.h
+--- a/include/libunwind-mips.h	2012-10-06 12:54:38.000000000 +0800
++++ b/include/libunwind-mips.h	2016-06-08 13:55:55.029436442 +0800
+@@ -111,6 +111,42 @@ typedef enum
+   }
+ mips_regnum_t;
+ 
++#ifndef __GLIBC__
++#include <sys/reg.h>
++
++/* musl as of 1.1.14 does not export these */
++#define EF_REG0			6
++#define EF_REG1			7
++#define EF_REG2			8
++#define EF_REG3			9
++#define EF_REG4			10
++#define EF_REG5			11
++#define EF_REG6			12
++#define EF_REG7			13
++#define EF_REG8			14
++#define EF_REG9			15
++#define EF_REG10		16
++#define EF_REG11		17
++#define EF_REG12		18
++#define EF_REG13		19
++#define EF_REG14		20
++#define EF_REG15		21
++#define EF_REG16		22
++#define EF_REG17		23
++#define EF_REG18		24
++#define EF_REG19		25
++#define EF_REG20		26
++#define EF_REG21		27
++#define EF_REG22		28
++#define EF_REG23		29
++#define EF_REG24		30
++#define EF_REG25		31
++#define EF_REG28		34
++#define EF_REG29		35
++#define EF_REG30		36
++#define EF_REG31		37
++#endif
++
+ typedef enum
+   {
+     UNW_MIPS_ABI_O32,
+
diff --git a/package/libs/libusb-compat/Makefile b/package/libs/libusb-compat/Makefile
new file mode 100644
index 0000000000..fe92c3fd6d
--- /dev/null
+++ b/package/libs/libusb-compat/Makefile
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2010-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libusb-compat
+PKG_VERSION:=0.1.4
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=@SF/libusb
+PKG_MD5SUM:=2ca521fffadd0c28fdf174e6ec73865b
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=LGPL-2.1
+
+PKG_MAINTAINER := Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libusb-compat
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=libusb-0.1 compatibility library
+  DEPENDS:=+libusb-1.0
+  URL:=http://libusb.wiki.sourceforge.net/
+endef
+
+define Package/libusb-compat/description
+  libusb is a C library that gives applications easy access to USB devices on
+  many different operating systems.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+	$(INSTALL_DIR) $(2)/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/libusb-config $(2)/bin/
+endef
+
+define Package/libusb-compat/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libusb-0.1.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libusb-compat))
diff --git a/package/libs/libusb-compat/patches/001-fix-musl-stdint.patch b/package/libs/libusb-compat/patches/001-fix-musl-stdint.patch
new file mode 100644
index 0000000000..333bc090cc
--- /dev/null
+++ b/package/libs/libusb-compat/patches/001-fix-musl-stdint.patch
@@ -0,0 +1,185 @@
+--- a/libusb/usb.h
++++ b/libusb/usb.h
+@@ -27,6 +27,7 @@
+ 
+ #include <unistd.h>
+ #include <stdlib.h>
++#include <stdint.h>
+ #include <limits.h>
+ 
+ #include <dirent.h>
+@@ -78,40 +79,40 @@
+ 
+ /* All standard descriptors have these 2 fields in common */
+ struct usb_descriptor_header {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
+ };
+ 
+ /* String descriptor */
+ struct usb_string_descriptor {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
+-	u_int16_t wData[1];
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
++	uint16_t wData[1];
+ };
+ 
+ /* HID descriptor */
+ struct usb_hid_descriptor {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
+-	u_int16_t bcdHID;
+-	u_int8_t  bCountryCode;
+-	u_int8_t  bNumDescriptors;
+-	/* u_int8_t  bReportDescriptorType; */
+-	/* u_int16_t wDescriptorLength; */
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
++	uint16_t bcdHID;
++	uint8_t  bCountryCode;
++	uint8_t  bNumDescriptors;
++	/* uint8_t  bReportDescriptorType; */
++	/* uint16_t wDescriptorLength; */
+ 	/* ... */
+ };
+ 
+ /* Endpoint descriptor */
+ #define USB_MAXENDPOINTS	32
+ struct usb_endpoint_descriptor {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
+-	u_int8_t  bEndpointAddress;
+-	u_int8_t  bmAttributes;
+-	u_int16_t wMaxPacketSize;
+-	u_int8_t  bInterval;
+-	u_int8_t  bRefresh;
+-	u_int8_t  bSynchAddress;
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
++	uint8_t  bEndpointAddress;
++	uint8_t  bmAttributes;
++	uint16_t wMaxPacketSize;
++	uint8_t  bInterval;
++	uint8_t  bRefresh;
++	uint8_t  bSynchAddress;
+ 
+ 	unsigned char *extra;	/* Extra descriptors */
+ 	int extralen;
+@@ -129,15 +130,15 @@ struct usb_endpoint_descriptor {
+ /* Interface descriptor */
+ #define USB_MAXINTERFACES	32
+ struct usb_interface_descriptor {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
+-	u_int8_t  bInterfaceNumber;
+-	u_int8_t  bAlternateSetting;
+-	u_int8_t  bNumEndpoints;
+-	u_int8_t  bInterfaceClass;
+-	u_int8_t  bInterfaceSubClass;
+-	u_int8_t  bInterfaceProtocol;
+-	u_int8_t  iInterface;
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
++	uint8_t  bInterfaceNumber;
++	uint8_t  bAlternateSetting;
++	uint8_t  bNumEndpoints;
++	uint8_t  bInterfaceClass;
++	uint8_t  bInterfaceSubClass;
++	uint8_t  bInterfaceProtocol;
++	uint8_t  iInterface;
+ 
+ 	struct usb_endpoint_descriptor *endpoint;
+ 
+@@ -155,14 +156,14 @@ struct usb_interface {
+ /* Configuration descriptor information.. */
+ #define USB_MAXCONFIG		8
+ struct usb_config_descriptor {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
+-	u_int16_t wTotalLength;
+-	u_int8_t  bNumInterfaces;
+-	u_int8_t  bConfigurationValue;
+-	u_int8_t  iConfiguration;
+-	u_int8_t  bmAttributes;
+-	u_int8_t  MaxPower;
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
++	uint16_t wTotalLength;
++	uint8_t  bNumInterfaces;
++	uint8_t  bConfigurationValue;
++	uint8_t  iConfiguration;
++	uint8_t  bmAttributes;
++	uint8_t  MaxPower;
+ 
+ 	struct usb_interface *interface;
+ 
+@@ -172,28 +173,28 @@ struct usb_config_descriptor {
+ 
+ /* Device descriptor */
+ struct usb_device_descriptor {
+-	u_int8_t  bLength;
+-	u_int8_t  bDescriptorType;
+-	u_int16_t bcdUSB;
+-	u_int8_t  bDeviceClass;
+-	u_int8_t  bDeviceSubClass;
+-	u_int8_t  bDeviceProtocol;
+-	u_int8_t  bMaxPacketSize0;
+-	u_int16_t idVendor;
+-	u_int16_t idProduct;
+-	u_int16_t bcdDevice;
+-	u_int8_t  iManufacturer;
+-	u_int8_t  iProduct;
+-	u_int8_t  iSerialNumber;
+-	u_int8_t  bNumConfigurations;
++	uint8_t  bLength;
++	uint8_t  bDescriptorType;
++	uint16_t bcdUSB;
++	uint8_t  bDeviceClass;
++	uint8_t  bDeviceSubClass;
++	uint8_t  bDeviceProtocol;
++	uint8_t  bMaxPacketSize0;
++	uint16_t idVendor;
++	uint16_t idProduct;
++	uint16_t bcdDevice;
++	uint8_t  iManufacturer;
++	uint8_t  iProduct;
++	uint8_t  iSerialNumber;
++	uint8_t  bNumConfigurations;
+ };
+ 
+ struct usb_ctrl_setup {
+-	u_int8_t  bRequestType;
+-	u_int8_t  bRequest;
+-	u_int16_t wValue;
+-	u_int16_t wIndex;
+-	u_int16_t wLength;
++	uint8_t  bRequestType;
++	uint8_t  bRequest;
++	uint16_t wValue;
++	uint16_t wIndex;
++	uint16_t wLength;
+ };
+ 
+ /*
+@@ -254,7 +255,7 @@ struct usb_device {
+ 
+   void *dev;		/* Darwin support */
+ 
+-  u_int8_t devnum;
++  uint8_t devnum;
+ 
+   unsigned char num_children;
+   struct usb_device **children;
+@@ -266,7 +267,7 @@ struct usb_bus {
+   char dirname[PATH_MAX + 1];
+ 
+   struct usb_device *devices;
+-  u_int32_t location;
++  uint32_t location;
+ 
+   struct usb_device *root_dev;
+ };
diff --git a/package/libs/libusb/Makefile b/package/libs/libusb/Makefile
new file mode 100644
index 0000000000..1b1edeef37
--- /dev/null
+++ b/package/libs/libusb/Makefile
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2010-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libusb
+PKG_VERSION:=1.0.20
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=@SF/$(PKG_NAME)
+PKG_MD5SUM:=1d4eb194eaaa2bcfbba28102768c7dbf
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=0
+PKG_LICENSE:=LGPL-2.1
+
+PKG_MAINTAINER := Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libusb-1.0
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=A library for accessing Linux USB devices
+  DEPENDS:=+libpthread +librt
+  URL:=http://libusb.wiki.sourceforge.net/
+endef
+
+define Package/libusb-1.0/description
+  libusb is a C library that gives applications easy access to USB devices on
+  many different operating systems.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+CONFIGURE_ARGS += \
+	--disable-udev \
+	--disable-log
+
+define Build/InstallDev
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+endef
+
+define Package/libusb-1.0/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libusb*.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libusb-1.0))
diff --git a/package/libs/lzo/Makefile b/package/libs/lzo/Makefile
new file mode 100644
index 0000000000..d4e5e72bb5
--- /dev/null
+++ b/package/libs/lzo/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lzo
+PKG_VERSION:=2.09
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.oberhumer.com/opensource/lzo/download/
+PKG_MD5SUM:=c7ffc9a103afe2d1bba0b015e7aa887f
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+PKG_LICENSE:=GPL-2.0+
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/liblzo
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=A real-time data compression library
+  URL:=http://www.oberhumer.com/opensource/lzo/
+endef
+
+define Package/liblzo/description
+ LZO is a data compression library which is suitable for data de-/compression
+ in real-time. This means it favours speed over compression ratio.
+endef
+
+define Build/Configure
+	$(call Build/Configure/Default, \
+		--enable-shared \
+		--enable-static \
+	)
+endef
+
+TARGET_CFLAGS += $(FPIC)
+MAKE_FLAGS += CFLAGS_O="$(TARGET_CFLAGS)"
+
+ifeq ($(CONFIG_i386)$(CONFIG_x86_64),)
+  TARGET_CFLAGS += -DLZO_CFG_NO_UNALIGNED=1
+endif
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/lzo $(1)/usr/include/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/liblzo2.{a,so*} $(1)/usr/lib/
+endef
+
+define Package/liblzo/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/liblzo2.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,liblzo))
diff --git a/package/libs/mbedtls/Makefile b/package/libs/mbedtls/Makefile
new file mode 100644
index 0000000000..7b5096715d
--- /dev/null
+++ b/package/libs/mbedtls/Makefile
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2011-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mbedtls
+PKG_VERSION:=2.4.0
+PKG_RELEASE:=1
+PKG_USE_MIPS16:=0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-gpl.tgz
+PKG_SOURCE_URL:=https://tls.mbed.org/download/
+PKG_MD5SUM:=80eff0e0028f969355d6e34ffdd3dbf4eb2a9367b07ff2f3f70e6d75beee9e3f
+
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/mbedtls/Default
+  SUBMENU:=SSL
+  TITLE:=Embedded SSL
+  URL:=https://tls.mbed.org
+endef
+
+define Package/mbedtls/Default/description
+The aim of the mbedtls project is to provide a quality, open-source
+cryptographic library written in C and targeted at embedded systems.
+endef
+
+define Package/libmbedtls
+$(call Package/mbedtls/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= (library)
+  ABI_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
+endef
+
+define Package/libmbedtls/description
+$(call Package/mbedtls/Default/description)
+This package contains the mbedtls library.
+endef
+
+PKG_INSTALL:=1
+
+CMAKE_OPTIONS += \
+	-DCMAKE_BUILD_TYPE:String="Release" \
+	-DUSE_SHARED_MBEDTLS_LIBRARY:Bool=ON \
+	-DENABLE_TESTING:Bool=OFF \
+	-DENABLE_PROGRAMS:Bool=OFF \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/mbedtls $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib*.so* $(1)/usr/lib/
+endef
+
+define Package/libmbedtls/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib*.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libmbedtls))
diff --git a/package/libs/mbedtls/patches/200-config.patch b/package/libs/mbedtls/patches/200-config.patch
new file mode 100644
index 0000000000..8a3531f858
--- /dev/null
+++ b/package/libs/mbedtls/patches/200-config.patch
@@ -0,0 +1,208 @@
+--- a/include/mbedtls/config.h
++++ b/include/mbedtls/config.h
+@@ -191,7 +191,7 @@
+  *
+  * Uncomment to get errors on using deprecated functions.
+  */
+-//#define MBEDTLS_DEPRECATED_REMOVED
++#define MBEDTLS_DEPRECATED_REMOVED
+ 
+ /* \} name SECTION: System support */
+ 
+@@ -347,7 +347,7 @@
+  *
+  * Enable Cipher Feedback mode (CFB) for symmetric ciphers.
+  */
+-#define MBEDTLS_CIPHER_MODE_CFB
++//#define MBEDTLS_CIPHER_MODE_CFB
+ 
+ /**
+  * \def MBEDTLS_CIPHER_MODE_CTR
+@@ -441,13 +441,13 @@
+  *
+  * Comment macros to disable the curve and functions for it
+  */
+-#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+-#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
++//#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
++//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+ #define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ #define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+ #define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+-#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+-#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
++//#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
++//#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+ #define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+ #define MBEDTLS_ECP_DP_BP256R1_ENABLED
+ #define MBEDTLS_ECP_DP_BP384R1_ENABLED
+@@ -523,7 +523,7 @@
+  *      MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+  *      MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA
+  */
+-#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
++//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
+ 
+ /**
+  * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+@@ -568,7 +568,7 @@
+  *      MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+  *      MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+  */
+-#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
++//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
+ 
+ /**
+  * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+@@ -622,7 +622,7 @@
+  *      MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+  *      MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+  */
+-#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
++//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+ 
+ /**
+  * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+@@ -695,7 +695,7 @@
+  *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+  *      MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+  */
+-#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
++//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+ 
+ /**
+  * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+@@ -719,7 +719,7 @@
+  *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
+  *      MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
+  */
+-#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
++//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+ 
+ /**
+  * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+@@ -885,7 +885,7 @@
+  *
+  * Comment this macro to disable support for external private RSA keys.
+  */
+-#define MBEDTLS_PK_RSA_ALT_SUPPORT
++//#define MBEDTLS_PK_RSA_ALT_SUPPORT
+ 
+ /**
+  * \def MBEDTLS_PKCS1_V15
+@@ -917,14 +917,14 @@
+  * Uncomment this macro to disable the use of CRT in RSA.
+  *
+  */
+-//#define MBEDTLS_RSA_NO_CRT
++#define MBEDTLS_RSA_NO_CRT
+ 
+ /**
+  * \def MBEDTLS_SELF_TEST
+  *
+  * Enable the checkup functions (*_self_test).
+  */
+-#define MBEDTLS_SELF_TEST
++//#define MBEDTLS_SELF_TEST
+ 
+ /**
+  * \def MBEDTLS_SHA256_SMALLER
+@@ -940,7 +940,7 @@
+  *
+  * Uncomment to enable the smaller implementation of SHA256.
+  */
+-//#define MBEDTLS_SHA256_SMALLER
++#define MBEDTLS_SHA256_SMALLER
+ 
+ /**
+  * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES
+@@ -1265,7 +1265,7 @@
+  *
+  * Comment this macro to disable support for truncated HMAC in SSL
+  */
+-#define MBEDTLS_SSL_TRUNCATED_HMAC
++//#define MBEDTLS_SSL_TRUNCATED_HMAC
+ 
+ /**
+  * \def MBEDTLS_THREADING_ALT
+@@ -1501,7 +1501,7 @@
+  *      MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+  *      MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
+  */
+-#define MBEDTLS_ARC4_C
++//#define MBEDTLS_ARC4_C
+ 
+ /**
+  * \def MBEDTLS_ASN1_PARSE_C
+@@ -1566,7 +1566,7 @@
+  *
+  * Module:  library/blowfish.c
+  */
+-#define MBEDTLS_BLOWFISH_C
++//#define MBEDTLS_BLOWFISH_C
+ 
+ /**
+  * \def MBEDTLS_CAMELLIA_C
+@@ -1621,7 +1621,7 @@
+  *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+  *      MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+  */
+-#define MBEDTLS_CAMELLIA_C
++//#define MBEDTLS_CAMELLIA_C
+ 
+ /**
+  * \def MBEDTLS_CCM_C
+@@ -1635,7 +1635,7 @@
+  * This module enables the AES-CCM ciphersuites, if other requisites are
+  * enabled as well.
+  */
+-#define MBEDTLS_CCM_C
++//#define MBEDTLS_CCM_C
+ 
+ /**
+  * \def MBEDTLS_CERTS_C
+@@ -1647,7 +1647,7 @@
+  *
+  * This module is used for testing (ssl_client/server).
+  */
+-#define MBEDTLS_CERTS_C
++//#define MBEDTLS_CERTS_C
+ 
+ /**
+  * \def MBEDTLS_CIPHER_C
+@@ -1700,7 +1700,7 @@
+  *
+  * This module provides debugging functions.
+  */
+-#define MBEDTLS_DEBUG_C
++//#define MBEDTLS_DEBUG_C
+ 
+ /**
+  * \def MBEDTLS_DES_C
+@@ -1740,7 +1740,7 @@
+  * This module is used by the following key exchanges:
+  *      DHE-RSA, DHE-PSK
+  */
+-#define MBEDTLS_DHM_C
++//#define MBEDTLS_DHM_C
+ 
+ /**
+  * \def MBEDTLS_ECDH_C
+@@ -2158,7 +2158,7 @@
+  * Caller:  library/mbedtls_md.c
+  *
+  */
+-#define MBEDTLS_RIPEMD160_C
++//#define MBEDTLS_RIPEMD160_C
+ 
+ /**
+  * \def MBEDTLS_RSA_C
+@@ -2468,7 +2468,7 @@
+  * Module:  library/xtea.c
+  * Caller:
+  */
+-#define MBEDTLS_XTEA_C
++//#define MBEDTLS_XTEA_C
+ 
+ /* \} name SECTION: mbed TLS modules */
+ 
diff --git a/package/libs/ncurses/Makefile b/package/libs/ncurses/Makefile
new file mode 100644
index 0000000000..3d869ea18a
--- /dev/null
+++ b/package/libs/ncurses/Makefile
@@ -0,0 +1,150 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ncurses
+PKG_VERSION:=5.9
+PKG_RELEASE:=4
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/ncurses
+PKG_MD5SUM:=8cb9c412e5f2d96bc6f459aa8c6282a1
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=README
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+PKG_BUILD_DEPENDS:=ncurses/host
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/terminfo
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Terminal Info Database (ncurses)
+  URL:=http://www.gnu.org/software/ncurses/
+endef
+
+define Package/libncursesw
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Terminal handling library (Unicode)
+  URL:=http://www.gnu.org/software/ncurses/
+  PROVIDES:=libncurses
+  DEPENDS:= +terminfo
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-echo \
+	--enable-const \
+	--enable-overwrite \
+	--enable-pc-files \
+	--disable-rpath \
+	--without-ada \
+	--without-debug \
+	--without-manpages \
+	--without-profile \
+	--without-progs \
+	--without-tests \
+	--disable-big-core \
+	--disable-home-terminfo \
+	--with-normal \
+	--with-shared \
+	--with-terminfo-dirs=/usr/share/terminfo \
+	--with-default-terminfo-dir=/usr/share/terminfo \
+	--enable-widec \
+	--with-build-cppflags=-D_GNU_SOURCE
+
+HOST_CONFIGURE_ARGS += \
+	--without-cxx \
+	--without-cxx-binding \
+	--without-ada \
+	--without-debug \
+	--without-manpages \
+	--without-profile \
+	--without-tests \
+	--without-curses-h
+
+
+ifeq ($(HOST_OS),FreeBSD)
+	CONFIGURE_ARGS +=
+		--with-terminfo=/usr/share/terminfo.db 
+endif
+
+MAKE_FLAGS += \
+	BUILD_CC="$(HOSTCC)" \
+	HOSTCC="$(HOSTCC)" \
+	HOSTCCFLAGS="" \
+	PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig \
+	libs
+
+define Build/Install/Default
+	$(MAKE_VARS) \
+	$(MAKE) -C $(PKG_BUILD_DIR)/$(MAKE_PATH) \
+		$(MAKE_INSTALL_FLAGS) \
+		$(1) install.libs install.data;
+endef
+
+define Package/terminfo/install
+	echo ""
+ifneq ($(HOST_OS),FreeBSD)
+	$(INSTALL_DIR) $(1)/usr/share/terminfo
+	(cd $(PKG_INSTALL_DIR)/usr/share/terminfo; \
+		for dir in ??; do \
+			[ -d "$$$$dir" ] || continue; \
+			mv $$$$dir $$$$(echo -ne "\x$$$$dir"); \
+		done \
+	)
+	for file in a/ansi d/dumb l/linux r/rxvt r/rxvt-unicode s/screen v/vt100 v/vt102 x/xterm x/xterm-color x/xterm-256color; do \
+		$(INSTALL_DIR) $(1)/usr/share/terminfo/`dirname $$$$file`; \
+		$(CP) $(PKG_INSTALL_DIR)/usr/share/terminfo/$$$$file \
+			$(1)/usr/share/terminfo/$$$$file; \
+	done
+endif
+endef
+
+define Package/libncursesw/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	for lib in ncurses panel menu form; do \
+		$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib$$$${lib}w.so* $(1)/usr/lib/; \
+		ln -s lib$$$${lib}w.so $(1)/usr/lib/lib$$$${lib}.so; \
+	done
+endef
+
+define Build/InstallDev
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)
+	for lib in ncurses panel menu form; do \
+		ln -s lib$$$${lib}w.so $(1)/usr/lib/lib$$$${lib}.so; \
+	done
+	ln -s . $(1)/usr/include/ncursesw
+	$(TARGET_CROSS)ar rc $(1)/usr/lib/libtinfo.a
+	$(INSTALL_DIR) $(2)/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/ncursesw5-config $(2)/bin/
+	$(SED) 's,^\(prefix\|exec_prefix\)=.*,\1=$(STAGING_DIR)/usr,g' -e 's/$$$$INCS //g' \
+		$(2)/bin/ncursesw5-config
+	ln -sf $(STAGING_DIR)/host/bin/ncursesw5-config $(1)/usr/bin/ncursesw5-config
+endef
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) libs
+	$(MAKE) -C $(HOST_BUILD_DIR)/progs tic
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/progs/tic $(STAGING_DIR_HOST)/bin/tic
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,terminfo))
+$(eval $(call BuildPackage,libncursesw))
diff --git a/package/libs/ncurses/patches/100-ncurses-5.6-20080112-urxvt.patch b/package/libs/ncurses/patches/100-ncurses-5.6-20080112-urxvt.patch
new file mode 100644
index 0000000000..20a6b43c15
--- /dev/null
+++ b/package/libs/ncurses/patches/100-ncurses-5.6-20080112-urxvt.patch
@@ -0,0 +1,175 @@
+--- a/misc/terminfo.src
++++ b/misc/terminfo.src
+@@ -4208,6 +4208,172 @@ rxvt-cygwin-native|rxvt terminal emulato
+ rxvt-16color|xterm with 16 colors like aixterm,
+ 	ncv#32, use=ibm+16color, use=rxvt,
+ 
++# rxvt-unicode
++# http://cvs.schmorp.de/rxvt-unicode/doc/etc/rxvt-unicode.terminfo?revision=1.20
++# From: Thomas Dickey <dickey@clark.net> 04 Oct 1997
++# Updated: Özgür Kesim <kesim@math.fu-berlin.de> 02 Nov 1997
++# Updated: Marc Lehmann <pcg@goof.com>, 17 Feb 2005
++rxvt-unicode|rxvt-unicode terminal (X Window System),
++	am,
++	bce,
++	eo,
++	km,
++	msgr,
++	xenl,
++	hs,
++	cols#80,
++	it#8,
++	lines#24,
++	acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~-A.B+C\,D0EhFiG,
++	bel=^G,
++	blink=\E[5m,
++	bold=\E[1m,
++	civis=\E[?25l,
++	clear=\E[H\E[2J,
++	cnorm=\E[?25h,
++	cr=^M,
++	csr=\E[%i%p1%d;%p2%dr,
++	cub=\E[%p1%dD,
++	cub1=^H,
++	cud=\E[%p1%dB,
++	cud1=^J,
++	cuf=\E[%p1%dC,
++	cuf1=\E[C,
++	cup=\E[%i%p1%d;%p2%dH,
++	cuu=\E[%p1%dA,
++	cuu1=\E[A,
++	cvvis=\E[?25h,
++	dch=\E[%p1%dP,
++	dch1=\E[P,
++	dl=\E[%p1%dM,
++	dl1=\E[M,
++	ed=\E[J,
++	el=\E[K,
++	el1=\E[1K,
++	flash=\E[?5h$<20/>\E[?5l,
++	home=\E[H,
++	hpa=\E[%i%p1%dG,
++	ht=^I,
++	hts=\EH,
++	ich=\E[%p1%d@,
++	ich1=\E[@,
++	il=\E[%p1%dL,
++	il1=\E[L,
++	ind=^J,
++	is1=\E[?47l\E=\E[?1l,
++	is2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l,
++	kDC=\E[3$,
++	kIC=\E2$,
++	kEND=\E[8$,
++	kHOM=\E[7$,
++	kLFT=\E[d,
++	kNXT=\E[6$,
++	kPRV=\E[5$,
++	kRIT=\E[c,
++	kbs=\177,
++	ka1=\EOw,
++	ka3=\EOy,
++	kb2=\EOu,
++	kc1=\EOq,
++	kc3=\EOs,
++	kcbt=\E[Z,
++	kcub1=\E[D,
++	kcud1=\E[B,
++	kcuf1=\E[C,
++	kcuu1=\E[A,
++	kdch1=\E[3~,
++	kel=\E[8\^,
++	kend=\E[8~,
++	kent=\EOM,
++	kf1=\E[11~,
++	kf10=\E[21~,
++	kf11=\E[23~,
++	kf12=\E[24~,
++	kf13=\E[25~,
++	kf14=\E[26~,
++	kf15=\E[28~,
++	kf16=\E[29~,
++	kf17=\E[31~,
++	kf18=\E[32~,
++	kf19=\E[33~,
++	kf2=\E[12~,
++	kf20=\E[34~,
++	kf3=\E[13~,
++	kf4=\E[14~,
++	kf5=\E[15~,
++	kf6=\E[17~,
++	kf7=\E[18~,
++	kf8=\E[19~,
++	kf9=\E[20~,
++	kfnd=\E[1~,
++	khome=\E[7~,
++	kich1=\E[2~,
++	kmous=\E[M,
++	knp=\E[6~,
++	kpp=\E[5~,
++	kslt=\E[4~,
++	rc=\E8,
++	rev=\E[7m,
++	ri=\EM,
++	rmso=\E[27m,
++	rmul=\E[24m,
++	rs1=\Ec,
++	rs2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l\E>,
++	sgr0=\E[m\017,
++	enacs=,
++	smacs=\E(0,
++	rmacs=\E(B,
++	smso=\E[7m,
++	smul=\E[4m,
++	tbc=\E[3g,
++	vpa=\E[%i%p1%dd,
++	colors#88,
++	pairs#256,
++	btns#5,
++	lm#0,
++	ccc,
++	npc,
++	mc5i,
++	ncv#0,
++	mir,
++	xon,
++	bw,
++	ech=\E[%p1%dX,
++	mc0=\E[i,
++	mc4=\E[4i,
++	mc5=\E[5i,
++	sitm=\E[3m,
++	ritm=\E[23m,
++	smam=\E[?7h,
++	rmam=\E[?7l,
++	smir=\E[4h,
++	rmir=\E[4l,
++	smcup=\E[?1049h,
++	rmcup=\E[r\E[?1049l,
++	smkx=\E=,
++	rmkx=\E>,
++	indn=\E[%p1%dS,
++	rin=\E[%p1%dT,
++	sgr=\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m%?%p9%t\E(0%e\E(B%;,
++	op=\E[39;49m,
++	setaf=\E[38;5;%p1%dm,
++	setab=\E[48;5;%p1%dm,
++	setf=%?%p1%{7}%>%t\E[38;5;%p1%dm%e\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m%;,
++	setb=%?%p1%{7}%>%t\E[48;5;%p1%dm%e\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m%;,
++	initc=\E]4;%p1%d;rgb\:%p2%{65535}%*%{1000}%/%4.4X/%p3%{65535}%*%{1000}%/%4.4X/%p4%{65535}%*%{1000}%/%4.4X\E\\,
++	sc=\E7,
++	s0ds=\E(B,
++	s1ds=\E(0,
++	s2ds=\E*B,
++	s3ds=\E+B,
++	u6=\E[%i%d;%dR,
++	u7=\E[6n,
++	u8=\E[?1;2c,
++	u9=\E[c,
++	tsl=\E]2;,
++	fsl=\007,
++	dsl=\E]2;\007,
++
+ # mrxvt 0.5.4
+ #
+ # mrxvt is based on rxvt 2.7.11, but has by default XTERM_FKEYS defined, which
diff --git a/package/libs/ncurses/patches/101-ncurses-5.6-20080628-kbs.patch b/package/libs/ncurses/patches/101-ncurses-5.6-20080628-kbs.patch
new file mode 100644
index 0000000000..779fa44bd2
--- /dev/null
+++ b/package/libs/ncurses/patches/101-ncurses-5.6-20080628-kbs.patch
@@ -0,0 +1,52 @@
+--- a/misc/terminfo.src
++++ b/misc/terminfo.src
+@@ -3274,6 +3274,7 @@ xterm-xfree86|xterm terminal emulator (X
+ # This version reflects the current xterm features.
+ xterm-new|modern xterm terminal emulator,
+ 	npc,
++	kbs=\177,
+ 	indn=\E[%p1%dS, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H,
+ 	kIC=\E[2;2~, kNXT=\E[6;2~, kPRV=\E[5;2~, kb2=\EOE,
+ 	kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+@@ -4061,6 +4062,7 @@ mlterm-256color|mlterm 3.0 with xterm 25
+ rxvt-basic|rxvt terminal base (X Window System),
+ 	OTbs, am, bce, eo, mir, msgr, xenl, xon, XT,
+ 	cols#80, it#8, lines#24,
++	kbs=\177,
+ 	acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+ 	bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l,
+ 	clear=\E[H\E[2J, cnorm=\E[?25h, cr=^M,
+@@ -4071,7 +4073,7 @@ rxvt-basic|rxvt terminal base (X Window
+ 	enacs=\E(B\E)0, flash=\E[?5h\E[?5l, home=\E[H, ht=^I,
+ 	hts=\EH, ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L,
+ 	ind=^J, is1=\E[?47l\E=\E[?1l,
+-	is2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l, kbs=^H,
++	is2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l,
+ 	kcbt=\E[Z, kmous=\E[M, rc=\E8, rev=\E[7m, ri=\EM, rmacs=^O,
+ 	rmcup=\E[2J\E[?47l\E8, rmir=\E[4l, rmkx=\E>, rmso=\E[27m,
+ 	rmul=\E[24m,
+@@ -4840,6 +4842,7 @@ eterm-color|Emacs term.el terminal emula
+ screen|VT 100/ANSI X3.64 virtual terminal,
+ 	OTbs, OTpt, am, km, mir, msgr, xenl, G0,
+ 	colors#8, cols#80, it#8, lines#24, ncv@, pairs#64, U8#1,
++	kbs=\177,
+ 	acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+ 	bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
+ 	clear=\E[H\E[J, cnorm=\E[34h\E[?25h, cr=^M,
+@@ -4849,7 +4852,7 @@ screen|VT 100/ANSI X3.64 virtual termina
+ 	cvvis=\E[34l, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM,
+ 	dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K, enacs=\E(B\E)0,
+ 	flash=\Eg, home=\E[H, ht=^I, hts=\EH, ich=\E[%p1%d@,
+-	il=\E[%p1%dL, il1=\E[L, ind=^J, is2=\E)0, kbs=^H, kcbt=\E[Z,
++	il=\E[%p1%dL, il1=\E[L, ind=^J, is2=\E)0, kcbt=\E[Z,
+ 	kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+ 	kdch1=\E[3~, kend=\E[4~, kf1=\EOP, kf10=\E[21~,
+ 	kf11=\E[23~, kf12=\E[24~, kf2=\EOQ, kf3=\EOR, kf4=\EOS,
+@@ -4955,6 +4958,7 @@ screen.xterm-r6|screen customized for X1
+ # on Solaris because Sun's curses implementation gets confused.
+ screen.teraterm|disable ncv in teraterm,
+ 	ncv#127,
++	kbs=^H,
+ 	acsc=+\020\,\021-\030.^Y0\333`\004a\261f\370g\361h\260i\316j\331k\277l\332m\300n\305o~p\304q\304r\304s_t\303u\264v\301w\302x\263y\363z\362{\343|\330}\234~\376,
+ 	use=screen+fkeys, use=screen,
+ # Other terminals
diff --git a/package/libs/ncurses/patches/102-ncurses-5.9-gcc-5.patch b/package/libs/ncurses/patches/102-ncurses-5.9-gcc-5.patch
new file mode 100644
index 0000000000..5e33492bf5
--- /dev/null
+++ b/package/libs/ncurses/patches/102-ncurses-5.9-gcc-5.patch
@@ -0,0 +1,44 @@
+https://bugs.gentoo.org/545114
+
+extracted from the upstream change (which had many unrelated commits in one)
+
+From 97bb4678dc03e753290b39bbff30ba2825df9517 Mon Sep 17 00:00:00 2001
+From: "Thomas E. Dickey" <dickey@invisible-island.net>
+Date: Sun, 7 Dec 2014 03:10:09 +0000
+Subject: [PATCH] ncurses 5.9 - patch 20141206
+
++ modify MKlib_gen.sh to work around change in development version of
+  gcc introduced here:
+	  https://gcc.gnu.org/ml/gcc-patches/2014-06/msg02185.html
+	  https://gcc.gnu.org/ml/gcc-patches/2014-07/msg00236.html
+  (reports by Marcus Shawcroft, Maohui Lei).
+
+--- a/ncurses/base/MKlib_gen.sh
++++ b/ncurses/base/MKlib_gen.sh
+@@ -437,11 +437,22 @@ sed -n -f $ED1 \
+ 	-e 's/gen_$//' \
+ 	-e 's/  / /g' >>$TMP
+ 
++cat >$ED1 <<EOF
++s/  / /g
++s/^ //
++s/ $//
++s/P_NCURSES_BOOL/NCURSES_BOOL/g
++EOF
++
++# A patch discussed here:
++#	https://gcc.gnu.org/ml/gcc-patches/2014-06/msg02185.html
++# introduces spurious #line markers.  Work around that by ignoring the system's
++# attempt to define "bool" and using our own symbol here.
++sed -e 's/bool/P_NCURSES_BOOL/g' $TMP > $ED2
++cat $ED2 >$TMP
++
+ $preprocessor $TMP 2>/dev/null \
+-| sed \
+-	-e 's/  / /g' \
+-	-e 's/^ //' \
+-	-e 's/_Bool/NCURSES_BOOL/g' \
++| sed -f $ED1 \
+ | $AWK -f $AW2 \
+ | sed -f $ED3 \
+ | sed \
diff --git a/package/libs/ncurses/patches/103-fixup-pkg-config-handling.patch b/package/libs/ncurses/patches/103-fixup-pkg-config-handling.patch
new file mode 100644
index 0000000000..85b2296ce4
--- /dev/null
+++ b/package/libs/ncurses/patches/103-fixup-pkg-config-handling.patch
@@ -0,0 +1,85 @@
+Change handling of PKG_CONFIG_LIBDIR
+
+When PKG_CONFIG_LIBDIR was unset in the environment, the configure
+script was deducing the PKG_CONFIG_LIBDIR from the location of the
+pkg-config binary, which doesn't make a lot of sense, and isn't done
+by other autotools based packages.
+
+Also, the configure script was checking that the directory really
+exists. This forced to create the directory *and* provide an absolute
+path in PKG_CONFIG_LIBDIR, which didn't play well with the fact that
+at installation time, PKG_CONFIG_LIBDIR is suffixed to DESTDIR, which
+means that we got two times the staging directory location.
+
+This patch fixes both of those issues. Also, since ncurses uses a fork
+of autoconf 2.13, we can't simply use _AUTORECONF=YES, so we also fix
+the configure script in this patch.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+
+--- a/configure
++++ b/configure
+@@ -3623,27 +3623,20 @@ echo $ECHO_N "checking if we should inst
+ 
+ 	# Leave this as something that can be overridden in the environment.
+ 	if test -z "$PKG_CONFIG_LIBDIR" ; then
+-		PKG_CONFIG_LIBDIR=`echo "$PKG_CONFIG" | sed -e 's,/[^/]*/[^/]*$,,'`/lib/pkgconfig
++		PKG_CONFIG_LIBDIR="/usr/lib/pkgconfig"
+ 	fi
++
+ 	PKG_CONFIG_LIBDIR=`echo "$PKG_CONFIG_LIBDIR" | sed -e 's/^://' -e 's/:.*//'`
+-	if test -n "$PKG_CONFIG_LIBDIR" && test -d "$PKG_CONFIG_LIBDIR" ; then
+ 
+-# Check whether --enable-pc-files or --disable-pc-files was given.
+-if test "${enable_pc_files+set}" = set; then
+-  enableval="$enable_pc_files"
+-  enable_pc_files=$enableval
+-else
+-  enable_pc_files=no
+-fi;
+-		echo "$as_me:3638: result: $enable_pc_files" >&5
+-echo "${ECHO_T}$enable_pc_files" >&6
++        # Check whether --enable-pc-files or --disable-pc-files was given.
++	if test "${enable_pc_files+set}" = set; then
++	    enableval="$enable_pc_files"
++	    enable_pc_files=$enableval
+ 	else
+-		echo "$as_me:3641: result: no" >&5
+-echo "${ECHO_T}no" >&6
+-		{ echo "$as_me:3643: WARNING: did not find library $PKG_CONFIG_LIBDIR" >&5
+-echo "$as_me: WARNING: did not find library $PKG_CONFIG_LIBDIR" >&2;}
+-		enable_pc_files=no
+-	fi
++	    enable_pc_files=no
++	fi;
++	echo "$as_me:3638: result: $enable_pc_files" >&5
++	echo "${ECHO_T}$enable_pc_files" >&6
+ fi
+ 
+ echo "$as_me:3649: checking if we should assume mixed-case filenames" >&5
+--- a/configure.in
++++ b/configure.in
+@@ -174,20 +174,14 @@ if test "$PKG_CONFIG" != no ; then
+ 
+ 	# Leave this as something that can be overridden in the environment.
+ 	if test -z "$PKG_CONFIG_LIBDIR" ; then
+-		PKG_CONFIG_LIBDIR=`echo "$PKG_CONFIG" | sed -e 's,/[[^/]]*/[[^/]]*$,,'`/lib/pkgconfig
++		PKG_CONFIG_LIBDIR="/usr/lib/pkgconfig"
+ 	fi
+ 	PKG_CONFIG_LIBDIR=`echo "$PKG_CONFIG_LIBDIR" | sed -e 's/^://' -e 's/:.*//'`
+-	if test -n "$PKG_CONFIG_LIBDIR" && test -d "$PKG_CONFIG_LIBDIR" ; then
+-		AC_ARG_ENABLE(pc-files,
++	AC_ARG_ENABLE(pc-files,
+ 			[  --enable-pc-files       generate and install .pc files for pkg-config],
+ 			[enable_pc_files=$enableval],
+ 			[enable_pc_files=no])
+-		AC_MSG_RESULT($enable_pc_files)
+-	else
+-		AC_MSG_RESULT(no)
+-		AC_MSG_WARN(did not find library $PKG_CONFIG_LIBDIR)
+-		enable_pc_files=no
+-	fi
++	AC_MSG_RESULT($enable_pc_files)
+ fi
+ AC_SUBST(PKG_CONFIG_LIBDIR)
+ 
diff --git a/package/libs/ncurses/patches/200-fix_missing_include.patch b/package/libs/ncurses/patches/200-fix_missing_include.patch
new file mode 100644
index 0000000000..4616c4fb70
--- /dev/null
+++ b/package/libs/ncurses/patches/200-fix_missing_include.patch
@@ -0,0 +1,14 @@
+--- a/ncurses/curses.priv.h
++++ b/ncurses/curses.priv.h
+@@ -55,6 +55,11 @@ extern "C" {
+ 
+ #include <ncurses_cfg.h>
+ 
++#if NEED_WCHAR_H
++#include <stdarg.h>
++#include <wchar.h>
++#endif
++
+ #if USE_RCS_IDS
+ #define MODULE_ID(id) static const char Ident[] = id;
+ #else
diff --git a/package/libs/ncurses/patches/500-cross.patch b/package/libs/ncurses/patches/500-cross.patch
new file mode 100644
index 0000000000..976a3cba2a
--- /dev/null
+++ b/package/libs/ncurses/patches/500-cross.patch
@@ -0,0 +1,11 @@
+--- a/aclocal.m4
++++ b/aclocal.m4
+@@ -5137,7 +5137,7 @@ CF_EOF
+ 			EXTRA_LDFLAGS="${cf_ld_rpath_opt}\${libdir} $EXTRA_LDFLAGS"
+ 		fi
+ 		CF_SHARED_SONAME
+-		MK_SHARED_LIB='${CC} ${CFLAGS} -shared -Wl,-soname,'$cf_cv_shared_soname',-stats,-lc -o $[@]'
++		MK_SHARED_LIB='${CC} ${CFLAGS} -shared -Wl,-soname,'$cf_shared_soname',-stats,$(LDFLAGS) -lc -o $[@]'
+ 		;;
+ 	openbsd[[2-9]].*) #(vi
+ 		if test "$DFT_LWR_MODEL" = "shared" ; then
diff --git a/package/libs/ncurses/patches/900-terminfo.patch b/package/libs/ncurses/patches/900-terminfo.patch
new file mode 100644
index 0000000000..487a341ba9
--- /dev/null
+++ b/package/libs/ncurses/patches/900-terminfo.patch
@@ -0,0 +1,20 @@
+--- a/misc/terminfo.src
++++ b/misc/terminfo.src
+@@ -3947,12 +3947,11 @@ konsole-xf3x|KDE console window with key
+ # The value for kbs reflects local customization rather than the settings used
+ # for XFree86 xterm.
+ konsole-xf4x|KDE console window with keyboard for XFree86 4.x xterm,
+-	kend=\EOF, khome=\EOH, use=konsole+pcfkeys,
+-	use=konsole-vt100,
+-# Konsole does not implement shifted cursor-keys.
+-konsole+pcfkeys|konsole subset of xterm+pcfkeys,
+-	kLFT@, kRIT@, kcbt=\E[Z, kind@, kri@, kDN@, kUP@, use=xterm+pcc2,
+-	use=xterm+pcf0,
++	kend=\EOF, kf1=\EOP, kf13=\EO2P, kf14=\EO2Q, kf15=\EO2R,
++	kf16=\EO2S, kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~,
++	kf2=\EOQ, kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~,
++	kf23=\E[23;2~, kf24=\E[24;2~, kf3=\EOR, kf4=\EOS,
++	khome=\EOH, use=konsole-vt100,
+ # KDE's "vt100" keyboard has no relationship to any terminal that DEC made, but
+ # it is still useful for deriving the other entries.
+ konsole-vt100|KDE console window with vt100 (sic) keyboard,
diff --git a/package/libs/nettle/Config.in b/package/libs/nettle/Config.in
new file mode 100644
index 0000000000..0d4806ab3a
--- /dev/null
+++ b/package/libs/nettle/Config.in
@@ -0,0 +1,9 @@
+# nettle avanced configuration
+
+menu "Configuration"
+	depends on PACKAGE_libnettle
+
+config LIBNETTLE_MINI
+	bool "use mini-gmp instead of gmp; the library will be much smaller at a 10x performance penalty. Note that this option may have side effects to programs that link to both nettle and gmp."
+
+endmenu
diff --git a/package/libs/nettle/Makefile b/package/libs/nettle/Makefile
new file mode 100644
index 0000000000..5a8c3b12eb
--- /dev/null
+++ b/package/libs/nettle/Makefile
@@ -0,0 +1,86 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=nettle
+PKG_VERSION:=3.3
+PKG_RELEASE:=1
+PKG_USE_MIPS16:=0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/nettle
+PKG_MD5SUM:=46942627d5d0ca11720fec18d81fc38f7ef837ea4197c1f630e71ce0d470b11e
+
+PKG_LICENSE:=GPL-2.0+
+PKG_LICENSE_FILES:=COPYING
+PKG_BUILD_PARALLEL:=0
+
+PKG_CONFIG_DEPENDS := CONFIG_LIBNETTLE_MINI
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libnettle
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=GNU crypto library
+  URL:=http://www.lysator.liu.se/~nisse/nettle/
+  DEPENDS+= +!LIBNETTLE_MINI:libgmp
+endef
+
+define Package/libnettle/config
+	source "$(SOURCE)/Config.in"
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-fat \
+	--disable-openssl \
+	--disable-documentation \
+	--enable-static
+
+ifeq ($(CONFIG_LIBNETTLE_MINI),y)
+CONFIGURE_ARGS += --enable-mini-gmp
+endif
+
+ifeq ($(CONFIG_CPU_SUBTYPE),neon)
+CONFIGURE_ARGS += \
+	--enable-arm-neon
+endif
+
+define Build/Compile
+	$(call Build/Compile/Default, \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CC="$(TARGET_CC)" \
+		libnettle.so libhogweed.so
+	+$(MAKE) -i $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		install)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/nettle
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/nettle/*.h $(1)/usr/include/nettle/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnettle.{a,so*} $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libhogweed.{a,so*} $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/nettle.pc \
+		$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/hogweed.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libnettle/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libnettle.so.* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libhogweed.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libnettle))
diff --git a/package/libs/openssl/Config.in b/package/libs/openssl/Config.in
new file mode 100644
index 0000000000..dbcd11abfc
--- /dev/null
+++ b/package/libs/openssl/Config.in
@@ -0,0 +1,62 @@
+if PACKAGE_libopenssl
+
+config OPENSSL_WITH_EC
+	bool
+	default y
+	prompt "Enable elliptic curve support"
+
+config OPENSSL_WITH_EC2M
+        bool
+        depends on OPENSSL_WITH_EC
+        prompt "Enable ec2m support"
+
+config OPENSSL_WITH_SSL3
+	bool
+	default n
+	prompt "Enable sslv3 support"
+
+config OPENSSL_WITH_DEPRECATED
+	bool
+	default y
+	prompt "Include deprecated APIs"
+
+config OPENSSL_WITH_DTLS
+	bool
+	default n
+	prompt "Enable DTLS support"
+
+config OPENSSL_WITH_COMPRESSION
+	bool
+	default n
+	prompt "Enable compression support"
+
+config OPENSSL_WITH_NPN
+	bool
+	default y
+	prompt "Enable NPN support"
+
+config OPENSSL_WITH_PSK
+	bool
+	default y
+	prompt "Enable PSK support"
+
+config OPENSSL_WITH_SRP
+	bool
+	default y
+	prompt "Enable SRP support"
+
+config OPENSSL_ENGINE_DIGEST
+	bool
+	depends on OPENSSL_ENGINE_CRYPTO
+	prompt "Digests acceleration support"
+
+config OPENSSL_HARDWARE_SUPPORT
+	bool
+	default n
+	prompt "Enable hardware support"
+
+endif
+
+config OPENSSL_ENGINE_CRYPTO
+	bool
+	prompt "Crypto acceleration support" if PACKAGE_libopenssl
diff --git a/package/libs/openssl/Makefile b/package/libs/openssl/Makefile
new file mode 100644
index 0000000000..a09c148f7b
--- /dev/null
+++ b/package/libs/openssl/Makefile
@@ -0,0 +1,259 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=openssl
+PKG_BASE:=1.0.2
+PKG_BUGFIX:=j
+PKG_VERSION:=$(PKG_BASE)$(PKG_BUGFIX)
+PKG_RELEASE:=1
+PKG_USE_MIPS16:=0
+
+PKG_BUILD_PARALLEL:=0
+
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.openssl.org/source/ \
+	ftp://ftp.openssl.org/source/ \
+	http://www.openssl.org/source/old/$(PKG_BASE)/ \
+	ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.openssl.org/source \
+	ftp://ftp.sunet.se/pub/security/tools/net/openssl/source/
+PKG_MD5SUM:=e7aff292be21c259c6af26469c7a9b3ba26e9abaaffd325e3dccc9785256c431
+
+PKG_LICENSE:=OpenSSL
+PKG_LICENSE_FILES:=LICENSE
+PKG_CONFIG_DEPENDS:= \
+	CONFIG_OPENSSL_ENGINE_CRYPTO \
+	CONFIG_OPENSSL_ENGINE_DIGEST \
+	CONFIG_OPENSSL_WITH_EC \
+	CONFIG_OPENSSL_WITH_EC2M \
+	CONFIG_OPENSSL_WITH_SSL3 \
+	CONFIG_OPENSSL_HARDWARE_SUPPORT \
+	CONFIG_OPENSSL_WITH_DEPRECATED \
+	CONFIG_OPENSSL_WITH_DTLS \
+	CONFIG_OPENSSL_WITH_COMPRESSION \
+	CONFIG_OPENSSL_WITH_NPN \
+	CONFIG_OPENSSL_WITH_PSK \
+	CONFIG_OPENSSL_WITH_SRP
+
+include $(INCLUDE_DIR)/package.mk
+
+ifneq ($(CONFIG_CCACHE),)
+HOSTCC=$(HOSTCC_NOCACHE)
+HOSTCXX=$(HOSTCXX_NOCACHE)
+endif
+
+define Package/openssl/Default
+  TITLE:=Open source SSL toolkit
+  URL:=http://www.openssl.org/
+endef
+
+define Package/libopenssl/config
+source "$(SOURCE)/Config.in"
+endef
+
+define Package/openssl/Default/description
+The OpenSSL Project is a collaborative effort to develop a robust,
+commercial-grade, full-featured, and Open Source toolkit implementing the Secure
+Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) protocols as well
+as a full-strength general purpose cryptography library.
+endef
+
+define Package/libopenssl
+$(call Package/openssl/Default)
+  SECTION:=libs
+  SUBMENU:=SSL
+  CATEGORY:=Libraries
+  DEPENDS:=+OPENSSL_WITH_COMPRESSION:zlib
+  TITLE+= (libraries)
+  ABI_VERSION:=$(PKG_VERSION)
+  MENU:=1
+endef
+
+define Package/libopenssl/description
+$(call Package/openssl/Default/description)
+This package contains the OpenSSL shared libraries, needed by other programs.
+endef
+
+define Package/openssl-util
+  $(call Package/openssl/Default)
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libopenssl
+  TITLE+= (utility)
+endef
+
+define Package/openssl-util/conffiles
+/etc/ssl/openssl.cnf
+endef
+
+define Package/openssl-util/description
+$(call Package/openssl/Default/description)
+This package contains the OpenSSL command-line utility.
+endef
+
+
+OPENSSL_NO_CIPHERS:= no-idea no-md2 no-mdc2 no-rc5 no-sha0 no-camellia no-krb5 \
+ no-whrlpool no-whirlpool no-seed no-jpake
+OPENSSL_OPTIONS:= shared no-err no-sse2 no-ssl2 no-ssl2-method no-heartbeats
+
+ifdef CONFIG_OPENSSL_ENGINE_CRYPTO
+  OPENSSL_OPTIONS += -DHAVE_CRYPTODEV
+  ifdef CONFIG_OPENSSL_ENGINE_DIGEST
+    OPENSSL_OPTIONS += -DUSE_CRYPTODEV_DIGESTS
+  endif
+else
+  OPENSSL_OPTIONS += no-engines
+endif
+
+ifndef CONFIG_OPENSSL_WITH_EC
+  OPENSSL_OPTIONS += no-ec
+endif
+
+ifndef CONFIG_OPENSSL_WITH_EC2M
+  OPENSSL_OPTIONS += no-ec2m
+endif
+
+ifndef CONFIG_OPENSSL_WITH_SSL3
+  OPENSSL_OPTIONS += no-ssl3 no-ssl3-method
+endif
+
+ifndef CONFIG_OPENSSL_HARDWARE_SUPPORT
+  OPENSSL_OPTIONS += no-hw
+endif
+
+ifndef CONFIG_OPENSSL_WITH_DEPRECATED
+  OPENSSL_OPTIONS += no-deprecated
+endif
+
+ifndef CONFIG_OPENSSL_WITH_DTLS
+  OPENSSL_OPTIONS += no-dtls
+endif
+
+ifdef CONFIG_OPENSSL_WITH_COMPRESSION
+  OPENSSL_OPTIONS += zlib-dynamic
+else
+  OPENSSL_OPTIONS += no-comp
+endif
+
+ifndef CONFIG_OPENSSL_WITH_NPN
+  OPENSSL_OPTIONS += no-nextprotoneg
+endif
+
+ifndef CONFIG_OPENSSL_WITH_PSK
+  OPENSSL_OPTIONS += no-psk
+endif
+
+ifndef CONFIG_OPENSSL_WITH_SRP
+  OPENSSL_OPTIONS += no-srp
+endif
+
+ifeq ($(CONFIG_x86_64),y)
+  OPENSSL_TARGET:=linux-x86_64-openwrt
+  OPENSSL_MAKEFLAGS += LIBDIR=lib
+else
+  OPENSSL_OPTIONS+=no-sse2
+  ifeq ($(CONFIG_mips)$(CONFIG_mipsel),y)
+    OPENSSL_TARGET:=linux-mips-openwrt
+  else ifeq ($(CONFIG_arm)$(CONFIG_armeb),y)
+    OPENSSL_TARGET:=linux-armv4-openwrt
+  else
+    OPENSSL_TARGET:=linux-generic-openwrt
+    OPENSSL_OPTIONS+=no-perlasm
+  endif
+endif
+
+STAMP_CONFIGURED := $(STAMP_CONFIGURED)_$(subst $(space),_,$(OPENSSL_OPTIONS))
+
+define Build/Configure
+	[ -f $(STAMP_CONFIGURED) ] || { \
+		rm -f $(PKG_BUILD_DIR)/*.so.* $(PKG_BUILD_DIR)/*.a; \
+		find $(PKG_BUILD_DIR) -name \*.o | xargs rm -f; \
+	}
+	(cd $(PKG_BUILD_DIR); \
+		./Configure $(OPENSSL_TARGET) \
+			--prefix=/usr \
+			--openssldir=/etc/ssl \
+			$(TARGET_CPPFLAGS) \
+			$(TARGET_LDFLAGS) -ldl \
+			-DOPENSSL_SMALL_FOOTPRINT \
+			$(OPENSSL_NO_CIPHERS) \
+			$(OPENSSL_OPTIONS) \
+	)
+	# XXX: OpenSSL "make depend" will look for installed headers before its own,
+	# so remove installed stuff first
+	-$(SUBMAKE) -j1 clean-staging
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		MAKEDEPPROG="$(TARGET_CROSS)gcc" \
+		OPENWRT_OPTIMIZATION_FLAGS="$(TARGET_CFLAGS)" \
+		$(OPENSSL_MAKEFLAGS) \
+		depend
+endef
+
+TARGET_CFLAGS += $(FPIC) -I$(CURDIR)/include -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		ASFLAGS="$(TARGET_ASFLAGS) -I$(PKG_BUILD_DIR)/crypto -c" \
+		AR="$(TARGET_CROSS)ar r" \
+		RANLIB="$(TARGET_CROSS)ranlib" \
+		OPENWRT_OPTIMIZATION_FLAGS="$(TARGET_CFLAGS)" \
+		$(OPENSSL_MAKEFLAGS) \
+		all
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		ASFLAGS="$(TARGET_ASFLAGS) -I$(PKG_BUILD_DIR)/crypto -c" \
+		AR="$(TARGET_CROSS)ar r" \
+		RANLIB="$(TARGET_CROSS)ranlib" \
+		OPENWRT_OPTIMIZATION_FLAGS="$(TARGET_CFLAGS)" \
+		$(OPENSSL_MAKEFLAGS) \
+		build-shared
+	# Work around openssl build bug to link libssl.so with libcrypto.so.
+	-rm $(PKG_BUILD_DIR)/libssl.so.*.*.*
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		OPENWRT_OPTIMIZATION_FLAGS="$(TARGET_CFLAGS)" \
+		$(OPENSSL_MAKEFLAGS) \
+		do_linux-shared
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \
+		$(OPENSSL_MAKEFLAGS) \
+		install
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/openssl $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib{crypto,ssl}.{a,so*} $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/{openssl,libcrypto,libssl}.pc $(1)/usr/lib/pkgconfig/
+	[ -n "$(TARGET_LDFLAGS)" ] && $(SED) 's#$(TARGET_LDFLAGS)##g' $(1)/usr/lib/pkgconfig/{openssl,libcrypto,libssl}.pc || true
+endef
+
+define Package/libopenssl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libcrypto.so.* $(1)/usr/lib/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libssl.so.* $(1)/usr/lib/
+endef
+
+define Package/openssl-util/install
+	$(INSTALL_DIR) $(1)/etc/ssl
+	$(CP) $(PKG_INSTALL_DIR)/etc/ssl/openssl.cnf $(1)/etc/ssl/
+	$(INSTALL_DIR) $(1)/etc/ssl/certs
+	$(INSTALL_DIR) $(1)/etc/ssl/private
+	chmod 0700 $(1)/etc/ssl/private
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/openssl $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,libopenssl))
+$(eval $(call BuildPackage,openssl-util))
diff --git a/package/libs/openssl/include/crypto/cryptodev.h b/package/libs/openssl/include/crypto/cryptodev.h
new file mode 100644
index 0000000000..7fb9c7dcda
--- /dev/null
+++ b/package/libs/openssl/include/crypto/cryptodev.h
@@ -0,0 +1,292 @@
+/* This is a source compatible implementation with the original API of
+ * cryptodev by Angelos D. Keromytis, found at openbsd cryptodev.h.
+ * Placed under public domain */
+
+#ifndef L_CRYPTODEV_H
+#define L_CRYPTODEV_H
+
+#include <linux/types.h>
+#ifndef __KERNEL__
+#define __user
+#endif
+
+/* API extensions for linux */
+#define CRYPTO_HMAC_MAX_KEY_LEN		512
+#define CRYPTO_CIPHER_MAX_KEY_LEN	64
+
+/* All the supported algorithms
+ */
+enum cryptodev_crypto_op_t {
+	CRYPTO_DES_CBC = 1,
+	CRYPTO_3DES_CBC = 2,
+	CRYPTO_BLF_CBC = 3,
+	CRYPTO_CAST_CBC = 4,
+	CRYPTO_SKIPJACK_CBC = 5,
+	CRYPTO_MD5_HMAC = 6,
+	CRYPTO_SHA1_HMAC = 7,
+	CRYPTO_RIPEMD160_HMAC = 8,
+	CRYPTO_MD5_KPDK = 9,
+	CRYPTO_SHA1_KPDK = 10,
+	CRYPTO_RIJNDAEL128_CBC = 11,
+	CRYPTO_AES_CBC = CRYPTO_RIJNDAEL128_CBC,
+	CRYPTO_ARC4 = 12,
+	CRYPTO_MD5 = 13,
+	CRYPTO_SHA1 = 14,
+	CRYPTO_DEFLATE_COMP = 15,
+	CRYPTO_NULL = 16,
+	CRYPTO_LZS_COMP = 17,
+	CRYPTO_SHA2_256_HMAC = 18,
+	CRYPTO_SHA2_384_HMAC = 19,
+	CRYPTO_SHA2_512_HMAC = 20,
+	CRYPTO_AES_CTR = 21,
+	CRYPTO_AES_XTS = 22,
+	CRYPTO_AES_ECB = 23,
+	CRYPTO_AES_GCM = 50,
+
+	CRYPTO_CAMELLIA_CBC = 101,
+	CRYPTO_RIPEMD160,
+	CRYPTO_SHA2_224,
+	CRYPTO_SHA2_256,
+	CRYPTO_SHA2_384,
+	CRYPTO_SHA2_512,
+	CRYPTO_SHA2_224_HMAC,
+	CRYPTO_ALGORITHM_ALL, /* Keep updated - see below */
+};
+
+#define	CRYPTO_ALGORITHM_MAX	(CRYPTO_ALGORITHM_ALL - 1)
+
+/* Values for ciphers */
+#define DES_BLOCK_LEN		8
+#define DES3_BLOCK_LEN		8
+#define RIJNDAEL128_BLOCK_LEN	16
+#define AES_BLOCK_LEN		RIJNDAEL128_BLOCK_LEN
+#define CAMELLIA_BLOCK_LEN      16
+#define BLOWFISH_BLOCK_LEN	8
+#define SKIPJACK_BLOCK_LEN	8
+#define CAST128_BLOCK_LEN	8
+
+/* the maximum of the above */
+#define EALG_MAX_BLOCK_LEN	16
+
+/* Values for hashes/MAC */
+#define AALG_MAX_RESULT_LEN		64
+
+/* maximum length of verbose alg names (depends on CRYPTO_MAX_ALG_NAME) */
+#define CRYPTODEV_MAX_ALG_NAME		64
+
+#define HASH_MAX_LEN 64
+
+/* input of CIOCGSESSION */
+struct session_op {
+	/* Specify either cipher or mac
+	 */
+	__u32	cipher;		/* cryptodev_crypto_op_t */
+	__u32	mac;		/* cryptodev_crypto_op_t */
+
+	__u32	keylen;
+	__u8	__user *key;
+	__u32	mackeylen;
+	__u8	__user *mackey;
+
+	__u32	ses;		/* session identifier */
+};
+
+struct session_info_op {
+	__u32 ses;		/* session identifier */
+
+	/* verbose names for the requested ciphers */
+	struct alg_info {
+		char cra_name[CRYPTODEV_MAX_ALG_NAME];
+		char cra_driver_name[CRYPTODEV_MAX_ALG_NAME];
+	} cipher_info, hash_info;
+
+	__u16	alignmask;	/* alignment constraints */
+	__u32   flags;          /* SIOP_FLAGS_* */
+};
+
+/* If this flag is set then this algorithm uses
+ * a driver only available in kernel (software drivers,
+ * or drivers based on instruction sets do not set this flag).
+ *
+ * If multiple algorithms are involved (as in AEAD case), then
+ * if one of them is kernel-driver-only this flag will be set.
+ */
+#define SIOP_FLAG_KERNEL_DRIVER_ONLY 1
+
+#define	COP_ENCRYPT	0
+#define COP_DECRYPT	1
+
+/* input of CIOCCRYPT */
+struct crypt_op {
+	__u32	ses;		/* session identifier */
+	__u16	op;		/* COP_ENCRYPT or COP_DECRYPT */
+	__u16	flags;		/* see COP_FLAG_* */
+	__u32	len;		/* length of source data */
+	__u8	__user *src;	/* source data */
+	__u8	__user *dst;	/* pointer to output data */
+	/* pointer to output data for hash/MAC operations */
+	__u8	__user *mac;
+	/* initialization vector for encryption operations */
+	__u8	__user *iv;
+};
+
+/* input of CIOCAUTHCRYPT */
+struct crypt_auth_op {
+	__u32	ses;		/* session identifier */
+	__u16	op;		/* COP_ENCRYPT or COP_DECRYPT */
+	__u16	flags;		/* see COP_FLAG_AEAD_* */
+	__u32	len;		/* length of source data */
+	__u32	auth_len;	/* length of auth data */
+	__u8	__user *auth_src;	/* authenticated-only data */
+
+	/* The current implementation is more efficient if data are
+	 * encrypted in-place (src==dst). */
+	__u8	__user *src;	/* data to be encrypted and authenticated */
+	__u8	__user *dst;	/* pointer to output data. Must have
+	                         * space for tag. For TLS this should be at least 
+	                         * len + tag_size + block_size for padding */
+
+	__u8    __user *tag;    /* where the tag will be copied to. TLS mode
+                                 * doesn't use that as tag is copied to dst.
+                                 * SRTP mode copies tag there. */
+	__u32	tag_len;	/* the length of the tag. Use zero for digest size or max tag. */
+
+	/* initialization vector for encryption operations */
+	__u8	__user *iv;
+	__u32   iv_len;
+};
+
+/* In plain AEAD mode the following are required:
+ *  flags   : 0
+ *  iv      : the initialization vector (12 bytes)
+ *  auth_len: the length of the data to be authenticated
+ *  auth_src: the data to be authenticated
+ *  len     : length of data to be encrypted
+ *  src     : the data to be encrypted
+ *  dst     : space to hold encrypted data. It must have
+ *            at least a size of len + tag_size.
+ *  tag_size: the size of the desired authentication tag or zero to use
+ *            the maximum tag output.
+ *
+ * Note tag isn't being used because the Linux AEAD interface
+ * copies the tag just after data.
+ */
+
+/* In TLS mode (used for CBC ciphers that required padding) 
+ * the following are required:
+ *  flags   : COP_FLAG_AEAD_TLS_TYPE
+ *  iv      : the initialization vector
+ *  auth_len: the length of the data to be authenticated only
+ *  len     : length of data to be encrypted
+ *  auth_src: the data to be authenticated
+ *  src     : the data to be encrypted
+ *  dst     : space to hold encrypted data (preferably in-place). It must have
+ *            at least a size of len + tag_size + blocksize.
+ *  tag_size: the size of the desired authentication tag or zero to use
+ *            the default mac output.
+ *
+ * Note that the padding used is the minimum padding.
+ */
+
+/* In SRTP mode the following are required:
+ *  flags   : COP_FLAG_AEAD_SRTP_TYPE
+ *  iv      : the initialization vector
+ *  auth_len: the length of the data to be authenticated. This must
+ *            include the SRTP header + SRTP payload (data to be encrypted) + rest
+ *            
+ *  len     : length of data to be encrypted
+ *  auth_src: pointer the data to be authenticated. Should point at the same buffer as src.
+ *  src     : pointer to the data to be encrypted.
+ *  dst     : This is mandatory to be the same as src (in-place only).
+ *  tag_size: the size of the desired authentication tag or zero to use
+ *            the default mac output.
+ *  tag     : Pointer to an address where the authentication tag will be copied.
+ */
+
+
+/* struct crypt_op flags */
+
+#define COP_FLAG_NONE		(0 << 0) /* totally no flag */
+#define COP_FLAG_UPDATE		(1 << 0) /* multi-update hash mode */
+#define COP_FLAG_FINAL		(1 << 1) /* multi-update final hash mode */
+#define COP_FLAG_WRITE_IV	(1 << 2) /* update the IV during operation */
+#define COP_FLAG_NO_ZC		(1 << 3) /* do not zero-copy */
+#define COP_FLAG_AEAD_TLS_TYPE  (1 << 4) /* authenticate and encrypt using the 
+                                          * TLS protocol rules */
+#define COP_FLAG_AEAD_SRTP_TYPE  (1 << 5) /* authenticate and encrypt using the 
+                                           * SRTP protocol rules */
+#define COP_FLAG_RESET		(1 << 6) /* multi-update reset the state.
+                                          * should be used in combination
+                                          * with COP_FLAG_UPDATE */
+
+
+/* Stuff for bignum arithmetic and public key
+ * cryptography - not supported yet by linux
+ * cryptodev.
+ */
+
+#define	CRYPTO_ALG_FLAG_SUPPORTED	1
+#define	CRYPTO_ALG_FLAG_RNG_ENABLE	2
+#define	CRYPTO_ALG_FLAG_DSA_SHA		4
+
+struct crparam {
+	__u8	*crp_p;
+	__u32	crp_nbits;
+};
+
+#define CRK_MAXPARAM	8
+
+/* input of CIOCKEY */
+struct crypt_kop {
+	__u32	crk_op;		/* cryptodev_crk_op_t */
+	__u32	crk_status;
+	__u16	crk_iparams;
+	__u16	crk_oparams;
+	__u32	crk_pad1;
+	struct crparam	crk_param[CRK_MAXPARAM];
+};
+
+enum cryptodev_crk_op_t {
+	CRK_MOD_EXP = 0,
+	CRK_MOD_EXP_CRT = 1,
+	CRK_DSA_SIGN = 2,
+	CRK_DSA_VERIFY = 3,
+	CRK_DH_COMPUTE_KEY = 4,
+	CRK_ALGORITHM_ALL
+};
+
+#define CRK_ALGORITHM_MAX	(CRK_ALGORITHM_ALL-1)
+
+/* features to be queried with CIOCASYMFEAT ioctl
+ */
+#define CRF_MOD_EXP		(1 << CRK_MOD_EXP)
+#define CRF_MOD_EXP_CRT		(1 << CRK_MOD_EXP_CRT)
+#define CRF_DSA_SIGN		(1 << CRK_DSA_SIGN)
+#define CRF_DSA_VERIFY		(1 << CRK_DSA_VERIFY)
+#define CRF_DH_COMPUTE_KEY	(1 << CRK_DH_COMPUTE_KEY)
+
+
+/* ioctl's. Compatible with old linux cryptodev.h
+ */
+#define CRIOGET         _IOWR('c', 101, __u32)
+#define CIOCGSESSION    _IOWR('c', 102, struct session_op)
+#define CIOCFSESSION    _IOW('c', 103, __u32)
+#define CIOCCRYPT       _IOWR('c', 104, struct crypt_op)
+#define CIOCKEY         _IOWR('c', 105, struct crypt_kop)
+#define CIOCASYMFEAT    _IOR('c', 106, __u32)
+#define CIOCGSESSINFO	_IOWR('c', 107, struct session_info_op)
+
+/* to indicate that CRIOGET is not required in linux
+ */
+#define CRIOGET_NOT_NEEDED 1
+
+/* additional ioctls for AEAD */
+#define CIOCAUTHCRYPT   _IOWR('c', 109, struct crypt_auth_op)
+
+/* additional ioctls for asynchronous operation.
+ * These are conditionally enabled since version 1.6.
+ */
+#define CIOCASYNCCRYPT    _IOW('c', 110, struct crypt_op)
+#define CIOCASYNCFETCH    _IOR('c', 111, struct crypt_op)
+
+#endif /* L_CRYPTODEV_H */
diff --git a/package/libs/openssl/patches/110-optimize-for-size.patch b/package/libs/openssl/patches/110-optimize-for-size.patch
new file mode 100644
index 0000000000..172184228e
--- /dev/null
+++ b/package/libs/openssl/patches/110-optimize-for-size.patch
@@ -0,0 +1,15 @@
+--- a/Configure
++++ b/Configure
+@@ -468,6 +468,12 @@ my %table=(
+ "linux-alpha-ccc","ccc:-fast -readonly_strings -DL_ENDIAN::-D_REENTRANT:::SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_PTR DES_RISC1 DES_UNROLL:${alpha_asm}",
+ "linux-alpha+bwx-ccc","ccc:-fast -readonly_strings -DL_ENDIAN::-D_REENTRANT:::SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_PTR DES_RISC1 DES_UNROLL:${alpha_asm}",
+ 
++# OpenWrt targets
++"linux-armv4-openwrt","gcc:-DTERMIOS \$(OPENWRT_OPTIMIZATION_FLAGS) -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-x86_64-openwrt",	"gcc:-m64 -DL_ENDIAN -DTERMIOS \$(OPENWRT_OPTIMIZATION_FLAGS) -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
++"linux-mips-openwrt","gcc:-DTERMIOS \$(OPENWRT_OPTIMIZATION_FLAGS) -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-generic-openwrt","gcc:-DTERMIOS \$(OPENWRT_OPTIMIZATION_FLAGS) -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++
+ # Android: linux-* but without pointers to headers and libs.
+ "android","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+ "android-x86","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
diff --git a/package/libs/openssl/patches/130-perl-path.patch b/package/libs/openssl/patches/130-perl-path.patch
new file mode 100644
index 0000000000..2dbdc76010
--- /dev/null
+++ b/package/libs/openssl/patches/130-perl-path.patch
@@ -0,0 +1,64 @@
+--- a/Configure
++++ b/Configure
+@@ -1,4 +1,4 @@
+-:
++#!/usr/bin/perl
+ eval 'exec perl -S $0 ${1+"$@"}'
+     if $running_under_some_shell;
+ ##
+--- a/tools/c_rehash.in
++++ b/tools/c_rehash.in
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl
++#!/usr/bin/perl
+ 
+ # Perl c_rehash script, scan all files in a directory
+ # and add symbolic links to their hash values.
+--- a/util/clean-depend.pl
++++ b/util/clean-depend.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ # Clean the dependency list in a makefile of standard includes...
+ # Written by Ben Laurie <ben@algroup.co.uk> 19 Jan 1999
+ 
+--- a/util/mkdef.pl
++++ b/util/mkdef.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ #
+ # generate a .def file
+ #
+--- a/util/mkerr.pl
++++ b/util/mkerr.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ 
+ my $config = "crypto/err/openssl.ec";
+ my $hprefix = "openssl/";
+--- a/util/mkstack.pl
++++ b/util/mkstack.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ 
+ # This is a utility that searches out "DECLARE_STACK_OF()"
+ # declarations in .h and .c files, and updates/creates/replaces
+--- a/util/pod2man.pl
++++ b/util/pod2man.pl
+@@ -1,4 +1,4 @@
+-: #!/usr/bin/perl-5.005
++#!/usr/bin/perl
+     eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+ 	if $running_under_some_shell;
+ 
+--- a/util/selftest.pl
++++ b/util/selftest.pl
+@@ -1,4 +1,4 @@
+-#!/usr/local/bin/perl -w
++#!/usr/bin/perl
+ #
+ # Run the test suite and generate a report
+ #
diff --git a/package/libs/openssl/patches/140-makefile-dirs.patch b/package/libs/openssl/patches/140-makefile-dirs.patch
new file mode 100644
index 0000000000..83c412f444
--- /dev/null
+++ b/package/libs/openssl/patches/140-makefile-dirs.patch
@@ -0,0 +1,11 @@
+--- a/Makefile.org
++++ b/Makefile.org
+@@ -137,7 +137,7 @@ FIPSCANLIB=
+ 
+ BASEADDR=
+ 
+-DIRS=   crypto ssl engines apps test tools
++DIRS=   crypto ssl apps
+ ENGDIRS= ccgost
+ SHLIBDIRS= crypto ssl
+ 
diff --git a/package/libs/openssl/patches/150-no_engines.patch b/package/libs/openssl/patches/150-no_engines.patch
new file mode 100644
index 0000000000..274ecbe0a5
--- /dev/null
+++ b/package/libs/openssl/patches/150-no_engines.patch
@@ -0,0 +1,81 @@
+--- a/Configure
++++ b/Configure
+@@ -2114,6 +2114,11 @@ EOF
+ 	close(OUT);
+   }
+   
++# ugly hack to disable engines
++if($target eq "mingwx") {
++	system("sed -e s/^LIB/XLIB/g -i engines/Makefile");
++}
++
+ print <<EOF;
+ 
+ Configured for $target.
+--- a/util/libeay.num
++++ b/util/libeay.num
+@@ -2075,7 +2075,6 @@ PKCS7_ATTR_SIGN_it
+ UI_add_error_string                     2633	EXIST::FUNCTION:
+ KRB5_CHECKSUM_free                      2634	EXIST::FUNCTION:
+ OCSP_REQUEST_get_ext                    2635	EXIST::FUNCTION:
+-ENGINE_load_ubsec                       2636	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ ENGINE_register_all_digests             2637	EXIST::FUNCTION:ENGINE
+ PKEY_USAGE_PERIOD_it                    2638	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+ PKEY_USAGE_PERIOD_it                    2638	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+@@ -2549,7 +2548,6 @@ OCSP_RESPONSE_new
+ AES_set_encrypt_key                     3024	EXIST::FUNCTION:AES
+ OCSP_resp_count                         3025	EXIST::FUNCTION:
+ KRB5_CHECKSUM_new                       3026	EXIST::FUNCTION:
+-ENGINE_load_cswift                      3027	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ OCSP_onereq_get0_id                     3028	EXIST::FUNCTION:
+ ENGINE_set_default_ciphers              3029	EXIST::FUNCTION:ENGINE
+ NOTICEREF_it                            3030	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+@@ -2580,7 +2578,6 @@ ASN1_primitive_free
+ i2d_EXTENDED_KEY_USAGE                  3052	EXIST::FUNCTION:
+ i2d_OCSP_SIGNATURE                      3053	EXIST::FUNCTION:
+ asn1_enc_save                           3054	EXIST::FUNCTION:
+-ENGINE_load_nuron                       3055	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ _ossl_old_des_pcbc_encrypt              3056	EXIST::FUNCTION:DES
+ PKCS12_MAC_DATA_it                      3057	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+ PKCS12_MAC_DATA_it                      3057	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+@@ -2604,7 +2601,6 @@ asn1_get_choice_selector
+ i2d_KRB5_CHECKSUM                       3072	EXIST::FUNCTION:
+ ENGINE_set_table_flags                  3073	EXIST::FUNCTION:ENGINE
+ AES_options                             3074	EXIST::FUNCTION:AES
+-ENGINE_load_chil                        3075	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ OCSP_id_cmp                             3076	EXIST::FUNCTION:
+ OCSP_BASICRESP_new                      3077	EXIST::FUNCTION:
+ OCSP_REQUEST_get_ext_by_NID             3078	EXIST::FUNCTION:
+@@ -2671,7 +2667,6 @@ OCSP_CRLID_it
+ OCSP_CRLID_it                           3127	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+ i2d_KRB5_AUTHENTBODY                    3128	EXIST::FUNCTION:
+ OCSP_REQUEST_get_ext_count              3129	EXIST::FUNCTION:
+-ENGINE_load_atalla                      3130	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ X509_NAME_it                            3131	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+ X509_NAME_it                            3131	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
+ USERNOTICE_it                           3132	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+@@ -2766,8 +2761,6 @@ DES_read_2passwords
+ DES_read_password                       3207	EXIST::FUNCTION:DES
+ UI_UTIL_read_pw                         3208	EXIST::FUNCTION:
+ UI_UTIL_read_pw_string                  3209	EXIST::FUNCTION:
+-ENGINE_load_aep                         3210	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+-ENGINE_load_sureware                    3211	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ OPENSSL_add_all_algorithms_noconf       3212	EXIST:!VMS:FUNCTION:
+ OPENSSL_add_all_algo_noconf             3212	EXIST:VMS:FUNCTION:
+ OPENSSL_add_all_algorithms_conf         3213	EXIST:!VMS:FUNCTION:
+@@ -2776,7 +2769,6 @@ OPENSSL_load_builtin_modules
+ AES_ofb128_encrypt                      3215	EXIST::FUNCTION:AES
+ AES_ctr128_encrypt                      3216	EXIST::FUNCTION:AES
+ AES_cfb128_encrypt                      3217	EXIST::FUNCTION:AES
+-ENGINE_load_4758cca                     3218	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ _ossl_096_des_random_seed               3219	EXIST::FUNCTION:DES
+ EVP_aes_256_ofb                         3220	EXIST::FUNCTION:AES
+ EVP_aes_192_ofb                         3221	EXIST::FUNCTION:AES
+@@ -3111,7 +3103,6 @@ EC_GFp_nist_method
+ STORE_meth_set_modify_fn                3530	NOEXIST::FUNCTION:
+ STORE_method_set_modify_function        3530	NOEXIST::FUNCTION:
+ STORE_parse_attrs_next                  3531	NOEXIST::FUNCTION:
+-ENGINE_load_padlock                     3532	EXIST::FUNCTION:ENGINE,STATIC_ENGINE
+ EC_GROUP_set_curve_name                 3533	EXIST::FUNCTION:EC
+ X509_CERT_PAIR_it                       3534	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
+ X509_CERT_PAIR_it                       3534	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
diff --git a/package/libs/openssl/patches/160-disable_doc_tests.patch b/package/libs/openssl/patches/160-disable_doc_tests.patch
new file mode 100644
index 0000000000..0fd1fa19dd
--- /dev/null
+++ b/package/libs/openssl/patches/160-disable_doc_tests.patch
@@ -0,0 +1,58 @@
+--- a/Makefile
++++ b/Makefile
+@@ -139,7 +139,7 @@ FIPSCANLIB=
+ 
+ BASEADDR=0xFB00000
+ 
+-DIRS=   crypto ssl engines apps test tools
++DIRS=   crypto ssl engines apps tools
+ ENGDIRS= ccgost
+ SHLIBDIRS= crypto ssl
+ 
+@@ -157,7 +157,7 @@ SDIRS=  \
+ 
+ # tests to perform.  "alltests" is a special word indicating that all tests
+ # should be performed.
+-TESTS = alltests
++TESTS =
+ 
+ MAKEFILE= Makefile
+ 
+@@ -171,7 +171,7 @@ SHELL=/bin/sh
+ 
+ TOP=    .
+ ONEDIRS=out tmp
+-EDIRS=  times doc bugs util include certs ms shlib mt demos perl sf dep VMS
++EDIRS=  times bugs util include certs ms shlib mt demos perl sf dep VMS
+ WDIRS=  windows
+ LIBS=   libcrypto.a libssl.a
+ SHARED_CRYPTO=libcrypto$(SHLIB_EXT)
+@@ -275,7 +275,7 @@ reflect:
+ 
+ sub_all: build_all
+ 
+-build_all: build_libs build_apps build_tests build_tools
++build_all: build_libs build_apps build_tools
+ 
+ build_libs: build_libcrypto build_libssl openssl.pc
+ 
+@@ -533,7 +533,7 @@ dist:
+ 	@$(MAKE) SDIRS='$(SDIRS)' clean
+ 	@$(MAKE) TAR='$(TAR)' TARFLAGS='$(TARFLAGS)' $(DISTTARVARS) tar
+ 
+-install: all install_docs install_sw
++install: all install_sw
+ 
+ install_sw:
+ 	@$(PERL) $(TOP)/util/mkdir-p.pl $(INSTALL_PREFIX)$(INSTALLTOP)/bin \
+--- a/Makefile.org
++++ b/Makefile.org
+@@ -531,7 +531,7 @@ dist:
+ 	@$(MAKE) SDIRS='$(SDIRS)' clean
+ 	@$(MAKE) TAR='$(TAR)' TARFLAGS='$(TARFLAGS)' $(DISTTARVARS) tar
+ 
+-install: all install_docs install_sw
++install: all install_sw
+ 
+ install_sw:
+ 	@$(PERL) $(TOP)/util/mkdir-p.pl $(INSTALL_PREFIX)$(INSTALLTOP)/bin \
diff --git a/package/libs/openssl/patches/170-bash_path.patch b/package/libs/openssl/patches/170-bash_path.patch
new file mode 100644
index 0000000000..c29b59afdd
--- /dev/null
+++ b/package/libs/openssl/patches/170-bash_path.patch
@@ -0,0 +1,8 @@
+--- a/util/domd
++++ b/util/domd
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/env bash
+ # Do a makedepend, only leave out the standard headers
+ # Written by Ben Laurie <ben@algroup.co.uk> 19 Jan 1999
+ 
diff --git a/package/libs/openssl/patches/180-fix_link_segfault.patch b/package/libs/openssl/patches/180-fix_link_segfault.patch
new file mode 100644
index 0000000000..3e36beb49c
--- /dev/null
+++ b/package/libs/openssl/patches/180-fix_link_segfault.patch
@@ -0,0 +1,18 @@
+--- a/Makefile.shared
++++ b/Makefile.shared
+@@ -95,7 +95,6 @@ LINK_APP=	\
+     LDCMD="$${LDCMD:-$(CC)}"; LDFLAGS="$${LDFLAGS:-$(CFLAGS)}"; \
+     LIBPATH=`for x in $$LIBDEPS; do echo $$x; done | sed -e 's/^ *-L//;t' -e d | uniq`; \
+     LIBPATH=`echo $$LIBPATH | sed -e 's/ /:/g'`; \
+-    LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \
+     $${LDCMD} $${LDFLAGS} -o $${APPNAME:=$(APPNAME)} $(OBJECTS) $${LIBDEPS} )
+ 
+ LINK_SO=	\
+@@ -105,7 +104,6 @@ LINK_SO=	\
+     SHAREDFLAGS="$${SHAREDFLAGS:-$(CFLAGS) $(SHARED_LDFLAGS)}"; \
+     LIBPATH=`for x in $$LIBDEPS; do echo $$x; done | sed -e 's/^ *-L//;t' -e d | uniq`; \
+     LIBPATH=`echo $$LIBPATH | sed -e 's/ /:/g'`; \
+-    LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \
+     $${SHAREDCMD} $${SHAREDFLAGS} \
+ 	-o $$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX \
+ 	$$ALLSYMSFLAGS $$SHOBJECTS $$NOALLSYMSFLAGS $$LIBDEPS \
diff --git a/package/libs/openssl/patches/190-remove_timestamp_check.patch b/package/libs/openssl/patches/190-remove_timestamp_check.patch
new file mode 100644
index 0000000000..4620bf90a6
--- /dev/null
+++ b/package/libs/openssl/patches/190-remove_timestamp_check.patch
@@ -0,0 +1,23 @@
+--- a/Makefile.org
++++ b/Makefile.org
+@@ -185,7 +185,7 @@ TARFILE=        ../$(NAME).tar
+ EXHEADER=       e_os2.h
+ HEADER=         e_os.h
+ 
+-all: Makefile build_all
++all: build_all
+ 
+ # as we stick to -e, CLEARENV ensures that local variables in lower
+ # Makefiles remain local and variable. $${VAR+VAR} is tribute to Korn
+@@ -403,11 +403,6 @@ openssl.pc: Makefile
+ 	    echo 'Version: '$(VERSION); \
+ 	    echo 'Requires: libssl libcrypto' ) > openssl.pc
+ 
+-Makefile: Makefile.org Configure config
+-	@echo "Makefile is older than Makefile.org, Configure or config."
+-	@echo "Reconfigure the source tree (via './config' or 'perl Configure'), please."
+-	@false
+-
+ libclean:
+ 	rm -f *.map *.so *.so.* *.dylib *.dll engines/*.so engines/*.dll engines/*.dylib *.a engines/*.a */lib */*/lib
+ 
diff --git a/package/libs/openssl/patches/200-parallel_build.patch b/package/libs/openssl/patches/200-parallel_build.patch
new file mode 100644
index 0000000000..276800378d
--- /dev/null
+++ b/package/libs/openssl/patches/200-parallel_build.patch
@@ -0,0 +1,184 @@
+--- a/Makefile.org
++++ b/Makefile.org
+@@ -281,17 +281,17 @@ build_libcrypto: build_crypto build_engi
+ build_libssl: build_ssl libssl.pc
+ 
+ build_crypto:
+-	@dir=crypto; target=all; $(BUILD_ONE_CMD)
++	+@dir=crypto; target=all; $(BUILD_ONE_CMD)
+ build_ssl: build_crypto
+-	@dir=ssl; target=all; $(BUILD_ONE_CMD)
++	+@dir=ssl; target=all; $(BUILD_ONE_CMD)
+ build_engines: build_crypto
+-	@dir=engines; target=all; $(BUILD_ONE_CMD)
++	+@dir=engines; target=all; $(BUILD_ONE_CMD)
+ build_apps: build_libs
+-	@dir=apps; target=all; $(BUILD_ONE_CMD)
++	+@dir=apps; target=all; $(BUILD_ONE_CMD)
+ build_tests: build_libs
+-	@dir=test; target=all; $(BUILD_ONE_CMD)
++	+@dir=test; target=all; $(BUILD_ONE_CMD)
+ build_tools: build_libs
+-	@dir=tools; target=all; $(BUILD_ONE_CMD)
++	+@dir=tools; target=all; $(BUILD_ONE_CMD)
+ 
+ all_testapps: build_libs build_testapps
+ build_testapps:
+@@ -464,7 +464,7 @@ update: errors stacks util/libeay.num ut
+ 	@set -e; target=update; $(RECURSIVE_BUILD_CMD)
+ 
+ depend:
+-	@set -e; target=depend; $(RECURSIVE_BUILD_CMD)
++	+@set -e; target=depend; $(RECURSIVE_BUILD_CMD)
+ 
+ lint:
+ 	@set -e; target=lint; $(RECURSIVE_BUILD_CMD)
+@@ -526,9 +526,9 @@ dist:
+ 	@$(MAKE) SDIRS='$(SDIRS)' clean
+ 	@$(MAKE) TAR='$(TAR)' TARFLAGS='$(TARFLAGS)' $(DISTTARVARS) tar
+ 
+-install: all install_sw
++install: install_sw
+ 
+-install_sw:
++install_dirs:
+ 	@$(PERL) $(TOP)/util/mkdir-p.pl $(INSTALL_PREFIX)$(INSTALLTOP)/bin \
+ 		$(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR) \
+ 		$(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines \
+@@ -537,12 +537,19 @@ install_sw:
+ 		$(INSTALL_PREFIX)$(OPENSSLDIR)/misc \
+ 		$(INSTALL_PREFIX)$(OPENSSLDIR)/certs \
+ 		$(INSTALL_PREFIX)$(OPENSSLDIR)/private
++	@$(PERL) $(TOP)/util/mkdir-p.pl \
++		$(INSTALL_PREFIX)$(MANDIR)/man1 \
++		$(INSTALL_PREFIX)$(MANDIR)/man3 \
++		$(INSTALL_PREFIX)$(MANDIR)/man5 \
++		$(INSTALL_PREFIX)$(MANDIR)/man7
++
++install_sw: install_dirs
+ 	@set -e; headerlist="$(EXHEADER)"; for i in $$headerlist;\
+ 	do \
+ 	(cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
+ 	chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
+ 	done;
+-	@set -e; target=install; $(RECURSIVE_BUILD_CMD)
++	+@set -e; target=install; $(RECURSIVE_BUILD_CMD)
+ 	@set -e; liblist="$(LIBS)"; for i in $$liblist ;\
+ 	do \
+ 		if [ -f "$$i" ]; then \
+@@ -626,12 +633,7 @@ install_html_docs:
+ 		done; \
+ 	done
+ 
+-install_docs:
+-	@$(PERL) $(TOP)/util/mkdir-p.pl \
+-		$(INSTALL_PREFIX)$(MANDIR)/man1 \
+-		$(INSTALL_PREFIX)$(MANDIR)/man3 \
+-		$(INSTALL_PREFIX)$(MANDIR)/man5 \
+-		$(INSTALL_PREFIX)$(MANDIR)/man7
++install_docs: install_dirs
+ 	@pod2man="`cd ./util; ./pod2mantest $(PERL)`"; \
+ 	here="`pwd`"; \
+ 	filecase=; \
+--- a/Makefile.shared
++++ b/Makefile.shared
+@@ -120,6 +120,7 @@ SYMLINK_SO=	\
+ 			done; \
+ 		fi; \
+ 		if [ -n "$$SHLIB_SOVER" ]; then \
++			[ -e "$$SHLIB$$SHLIB_SUFFIX" ] || \
+ 			( $(SET_X); rm -f $$SHLIB$$SHLIB_SUFFIX; \
+ 			  ln -s $$prev $$SHLIB$$SHLIB_SUFFIX ); \
+ 		fi; \
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -85,11 +85,11 @@ testapps:
+ 	@if [ -z "$(THIS)" ]; then $(MAKE) -f $(TOP)/Makefile reflect THIS=$@; fi
+ 
+ subdirs:
+-	@target=all; $(RECURSIVE_MAKE)
++	+@target=all; $(RECURSIVE_MAKE)
+ 
+ files:
+ 	$(PERL) $(TOP)/util/files.pl "CPUID_OBJ=$(CPUID_OBJ)" Makefile >> $(TOP)/MINFO
+-	@target=files; $(RECURSIVE_MAKE)
++	+@target=files; $(RECURSIVE_MAKE)
+ 
+ links:
+ 	@$(PERL) $(TOP)/util/mklink.pl ../include/openssl $(EXHEADER)
+@@ -100,7 +100,7 @@ links:
+ # lib: $(LIB): are splitted to avoid end-less loop
+ lib:	$(LIB)
+ 	@touch lib
+-$(LIB):	$(LIBOBJ)
++$(LIB):	$(LIBOBJ) | subdirs
+ 	$(AR) $(LIB) $(LIBOBJ)
+ 	test -z "$(FIPSLIBDIR)" || $(AR) $(LIB) $(FIPSLIBDIR)fipscanister.o
+ 	$(RANLIB) $(LIB) || echo Never mind.
+@@ -111,7 +111,7 @@ shared: buildinf.h lib subdirs
+ 	fi
+ 
+ libs:
+-	@target=lib; $(RECURSIVE_MAKE)
++	+@target=lib; $(RECURSIVE_MAKE)
+ 
+ install:
+ 	@[ -n "$(INSTALLTOP)" ] # should be set by top Makefile...
+@@ -120,7 +120,7 @@ install:
+ 	(cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
+ 	chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
+ 	done;
+-	@target=install; $(RECURSIVE_MAKE)
++	+@target=install; $(RECURSIVE_MAKE)
+ 
+ lint:
+ 	@target=lint; $(RECURSIVE_MAKE)
+--- a/engines/Makefile
++++ b/engines/Makefile
+@@ -72,7 +72,7 @@ top:
+ 
+ all:	lib subdirs
+ 
+-lib:	$(LIBOBJ)
++lib:	$(LIBOBJ) | subdirs
+ 	@if [ -n "$(SHARED_LIBS)" ]; then \
+ 		set -e; \
+ 		for l in $(LIBNAMES); do \
+@@ -89,7 +89,7 @@ lib:	$(LIBOBJ)
+ 
+ subdirs:
+ 	echo $(EDIRS)
+-	@target=all; $(RECURSIVE_MAKE)
++	+@target=all; $(RECURSIVE_MAKE)
+ 
+ files:
+ 	$(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
+@@ -128,7 +128,7 @@ install:
+ 			  mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx ); \
+ 		done; \
+ 	fi
+-	@target=install; $(RECURSIVE_MAKE)
++	+@target=install; $(RECURSIVE_MAKE)
+ 
+ tags:
+ 	ctags $(SRC)
+--- a/test/Makefile
++++ b/test/Makefile
+@@ -144,7 +144,7 @@ install:
+ tags:
+ 	ctags $(SRC)
+ 
+-tests:	exe apps $(TESTS)
++tests:	exe $(TESTS)
+ 
+ apps:
+ 	@(cd ..; $(MAKE) DIRS=apps all)
+@@ -577,7 +577,7 @@ $(DTLSTEST)$(EXE_EXT): $(DTLSTEST).o ssl
+ #	fi
+ 
+ dummytest$(EXE_EXT): dummytest.o $(DLIBCRYPTO)
+-	@target=dummytest; $(BUILD_CMD)
++	+@target=dummytest; $(BUILD_CMD)
+ 
+ # DO NOT DELETE THIS LINE -- make depend depends on it.
+ 
diff --git a/package/libs/polarssl/Makefile b/package/libs/polarssl/Makefile
new file mode 100644
index 0000000000..52c91dcca6
--- /dev/null
+++ b/package/libs/polarssl/Makefile
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2011-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=polarssl
+SRC_PKG_NAME:=mbedtls
+PKG_VERSION:=1.3.18
+PKG_RELEASE:=1
+PKG_USE_MIPS16:=0
+
+PKG_SOURCE:=$(SRC_PKG_NAME)-$(PKG_VERSION)-gpl.tgz
+PKG_SOURCE_URL:=https://tls.mbed.org/download/
+PKG_MD5SUM:=a229217182e024847deba3cb70bdd17e5ff4ffd9ff306cbbccfdbdff41950ea1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(SRC_PKG_NAME)-$(PKG_VERSION)
+
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/polarssl/Default
+  SUBMENU:=SSL
+  TITLE:=Embedded SSL
+  URL:=http://polarssl.org/
+endef
+
+define Package/polarssl/Default/description
+The aim of the PolarSSL project is to provide a quality, open-source
+cryptographic library written in C and targeted at embedded systems.
+endef
+
+define Package/libpolarssl
+$(call Package/polarssl/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= (library)
+  ABI_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
+endef
+
+define Package/libpolarssl/description
+$(call Package/polarssl/Default/description)
+This package contains the PolarSSL library.
+endef
+
+PKG_INSTALL:=1
+
+CMAKE_OPTIONS += \
+	-DCMAKE_BUILD_TYPE:String="Release" \
+	-DUSE_SHARED_MBEDTLS_LIBRARY:Bool=ON \
+	-DENABLE_TESTING:Bool=OFF \
+	-DENABLE_PROGRAMS:Bool=OFF \
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/polarssl $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libmbedtls.so.* $(1)/usr/lib/
+	$(LN) libmbedtls.so.$(PKG_VERSION) $(1)/usr/lib/libpolarssl.so
+endef
+
+define Package/libpolarssl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libmbedtls.so.* $(1)/usr/lib/
+	$(LN) libmbedtls.so.$(PKG_VERSION) $(1)/usr/lib/libpolarssl.so
+endef
+
+$(eval $(call BuildPackage,libpolarssl))
diff --git a/package/libs/polarssl/patches/200-reduce_config.patch b/package/libs/polarssl/patches/200-reduce_config.patch
new file mode 100644
index 0000000000..491ecec388
--- /dev/null
+++ b/package/libs/polarssl/patches/200-reduce_config.patch
@@ -0,0 +1,242 @@
+--- a/include/polarssl/config.h
++++ b/include/polarssl/config.h
+@@ -432,8 +432,8 @@
+  * Requires: POLARSSL_HMAC_DRBG_C
+  *
+  * Comment this macro to disable deterministic ECDSA.
+- */
+ #define POLARSSL_ECDSA_DETERMINISTIC
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED
+@@ -454,8 +454,8 @@
+  *      TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+  *      TLS_PSK_WITH_3DES_EDE_CBC_SHA
+  *      TLS_PSK_WITH_RC4_128_SHA
+- */
+ #define POLARSSL_KEY_EXCHANGE_PSK_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED
+@@ -478,8 +478,8 @@
+  *      TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+  *      TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
+  *      TLS_DHE_PSK_WITH_RC4_128_SHA
+- */
+ #define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+@@ -498,8 +498,8 @@
+  *      TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
+  *      TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
+  *      TLS_ECDHE_PSK_WITH_RC4_128_SHA
+- */
+ #define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED
+@@ -523,8 +523,8 @@
+  *      TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
+  *      TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
+  *      TLS_RSA_PSK_WITH_RC4_128_SHA
+- */
+ #define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_RSA_ENABLED
+@@ -602,8 +602,8 @@
+  *      TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+  *      TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+  *      TLS_ECDHE_RSA_WITH_RC4_128_SHA
+- */
+ #define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+@@ -626,8 +626,8 @@
+  *      TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+  *      TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+  *      TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+- */
+ #define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+@@ -650,8 +650,8 @@
+  *      TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+  *      TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+  *      TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+- */
+ #define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED
+@@ -674,8 +674,8 @@
+  *      TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384
+  *      TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
+  *      TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
+- */
+ #define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED
++ */
+ 
+ /**
+  * \def POLARSSL_PK_PARSE_EC_EXTENDED
+@@ -835,8 +835,8 @@
+  * \def POLARSSL_SELF_TEST
+  *
+  * Enable the checkup functions (*_self_test).
+- */
+ #define POLARSSL_SELF_TEST
++ */
+ 
+ /**
+  * \def POLARSSL_SSL_ALL_ALERT_MESSAGES
+@@ -1139,8 +1139,8 @@
+  * Requires: POLARSSL_VERSION_C
+  *
+  * Comment this to disable run-time checking and save ROM space
+- */
+ #define POLARSSL_VERSION_FEATURES
++ */
+ 
+ /**
+  * \def POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3
+@@ -1469,8 +1469,8 @@
+  *      TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
+  *      TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
+  *      TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
+- */
+ #define POLARSSL_CAMELLIA_C
++ */
+ 
+ /**
+  * \def POLARSSL_CCM_C
+@@ -1497,8 +1497,8 @@
+  * Requires: POLARSSL_PEM_PARSE_C
+  *
+  * This module is used for testing (ssl_client/server).
+- */
+ #define POLARSSL_CERTS_C
++ */
+ 
+ /**
+  * \def POLARSSL_CIPHER_C
+@@ -1537,8 +1537,8 @@
+  *          library/ssl_tls.c
+  *
+  * This module provides debugging functions.
+- */
+ #define POLARSSL_DEBUG_C
++ */
+ 
+ /**
+  * \def POLARSSL_DES_C
+@@ -1593,8 +1593,8 @@
+  *      ECDHE-ECDSA, ECDHE-RSA, DHE-PSK
+  *
+  * Requires: POLARSSL_ECP_C
+- */
+ #define POLARSSL_ECDH_C
++ */
+ 
+ /**
+  * \def POLARSSL_ECDSA_C
+@@ -1608,8 +1608,8 @@
+  *      ECDHE-ECDSA
+  *
+  * Requires: POLARSSL_ECP_C, POLARSSL_ASN1_WRITE_C, POLARSSL_ASN1_PARSE_C
+- */
+ #define POLARSSL_ECDSA_C
++ */
+ 
+ /**
+  * \def POLARSSL_ECP_C
+@@ -1621,8 +1621,8 @@
+  *          library/ecdsa.c
+  *
+  * Requires: POLARSSL_BIGNUM_C and at least one POLARSSL_ECP_DP_XXX_ENABLED
+- */
+ #define POLARSSL_ECP_C
++ */
+ 
+ /**
+  * \def POLARSSL_ENTROPY_C
+@@ -1698,8 +1698,8 @@
+  * Requires: POLARSSL_MD_C
+  *
+  * Uncomment to enable the HMAC_DRBG random number geerator.
+- */
+ #define POLARSSL_HMAC_DRBG_C
++ */
+ 
+ /**
+  * \def POLARSSL_MD_C
+@@ -1825,8 +1825,8 @@
+  * Requires: POLARSSL_HAVE_ASM
+  *
+  * This modules adds support for the VIA PadLock on x86.
+- */
+ #define POLARSSL_PADLOCK_C
++ */
+ 
+ /**
+  * \def POLARSSL_PBKDF2_C
+@@ -1991,8 +1991,8 @@
+  * Module:  library/ripemd160.c
+  * Caller:  library/md.c
+  *
+- */
+ #define POLARSSL_RIPEMD160_C
++ */
+ 
+ /**
+  * \def POLARSSL_RSA_C
+@@ -2071,8 +2071,8 @@
+  * Caller:
+  *
+  * Requires: POLARSSL_SSL_CACHE_C
+- */
+ #define POLARSSL_SSL_CACHE_C
++ */
+ 
+ /**
+  * \def POLARSSL_SSL_CLI_C
+@@ -2148,8 +2148,8 @@
+  * Caller:  library/havege.c
+  *
+  * This module is used by the HAVEGE random number generator.
+- */
+ #define POLARSSL_TIMING_C
++ */
+ 
+ /**
+  * \def POLARSSL_VERSION_C
+@@ -2159,8 +2159,8 @@
+  * Module:  library/version.c
+  *
+  * This module provides run-time version information.
+- */
+ #define POLARSSL_VERSION_C
++ */
+ 
+ /**
+  * \def POLARSSL_X509_USE_C
+@@ -2269,8 +2269,8 @@
+  *
+  * Module:  library/xtea.c
+  * Caller:
+- */
+ #define POLARSSL_XTEA_C
++ */
+ 
+ /* \} name SECTION: mbed TLS modules */
+ 
diff --git a/package/libs/popt/Makefile b/package/libs/popt/Makefile
new file mode 100644
index 0000000000..598f0778b6
--- /dev/null
+++ b/package/libs/popt/Makefile
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=popt
+PKG_VERSION:=1.16
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://rpm5.org/files/popt/
+PKG_MD5SUM:=3743beefa3dd6247a73f8f7a32c14c33
+PKG_LICENSE:=MIT
+
+PKG_FIXUP:=autoreconf
+PKG_REMOVE_FILES:=autogen.sh aclocal.m4
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+TARGET_CFLAGS += $(FPIC)
+
+define Package/libpopt
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=A command line option parsing library
+  URL:=http://rpm5.org/files/popt/
+endef
+
+define Build/Configure
+	$(call Build/Configure/Default, \
+		--enable-shared \
+		--enable-static \
+	)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/popt.h $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libpopt.{a,so*} $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/popt.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libpopt/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libpopt.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libpopt))
+
diff --git a/package/libs/sysfsutils/Makefile b/package/libs/sysfsutils/Makefile
new file mode 100644
index 0000000000..67b43868ec
--- /dev/null
+++ b/package/libs/sysfsutils/Makefile
@@ -0,0 +1,73 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=sysfsutils
+PKG_VERSION:=2.1.0
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/linux-diag
+PKG_MD5SUM:=14e7dcd0436d2f49aa403f67e1ef7ddc
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=COPYING cmd/GPL lib/LGPL
+
+PKG_FIXUP:=autoreconf
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libsysfs
+  SECTION:=libs
+  CATEGORY:=Libraries
+  SUBMENU:=Filesystem
+  TITLE:=Sysfs library
+  URL:=http://linux-diag.sourceforge.net/Sysfsutils.html
+endef
+
+define Package/sysfsutils
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Filesystem
+  DEPENDS:=+libsysfs
+  TITLE:=System Utilities Based on Sysfs
+  URL:=http://linux-diag.sourceforge.net/Sysfsutils.html
+endef
+
+define Package/libsysfs/description
+The library's purpose is to provide a consistant and stable interface for
+querying system device information exposed through sysfs.
+endef
+
+define Package/sysfsutils/description
+A utility built upon libsysfs that lists devices by bus, class, and topology.
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/sysfs $(1)/usr/include/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libsysfs.{a,so*,la} $(1)/usr/lib/
+endef
+
+define Package/libsysfs/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libsysfs.so* $(1)/usr/lib/
+endef
+
+define Package/sysfsutils/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/systool $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,libsysfs))
+$(eval $(call BuildPackage,sysfsutils))
diff --git a/package/libs/sysfsutils/patches/200-mnt_path_check.patch b/package/libs/sysfsutils/patches/200-mnt_path_check.patch
new file mode 100644
index 0000000000..8710578c5b
--- /dev/null
+++ b/package/libs/sysfsutils/patches/200-mnt_path_check.patch
@@ -0,0 +1,55 @@
+--- a/lib/sysfs_utils.c
++++ b/lib/sysfs_utils.c
+@@ -22,6 +22,7 @@
+  */
+ #include "libsysfs.h"
+ #include "sysfs.h"
++#include <mntent.h>
+ 
+ /**
+  * sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
+@@ -53,6 +54,9 @@ int sysfs_get_mnt_path(char *mnt_path, s
+ {
+ 	static char sysfs_path[SYSFS_PATH_MAX] = "";
+ 	const char *sysfs_path_env;
++	FILE *mnt;
++	struct mntent *mntent;
++	int ret;
+ 
+ 	if (len == 0 || mnt_path == NULL)
+ 		return -1;
+@@ -64,12 +68,31 @@ int sysfs_get_mnt_path(char *mnt_path, s
+ 		if (sysfs_path_env != NULL) {
+ 			safestrcpymax(mnt_path, sysfs_path_env, len);
+ 			sysfs_remove_trailing_slash(mnt_path);
+-			return 0;
++		} else {
++			safestrcpymax(mnt_path, SYSFS_MNT_PATH, len);
+ 		}
+-		safestrcpymax(mnt_path, SYSFS_MNT_PATH, len);
+ 	}
+ 
+-	return 0;
++	/* check that mount point is indeed mounted */
++	ret = -1;
++	if ((mnt = setmntent(SYSFS_PROC_MNTS, "r")) == NULL) {
++		dprintf("Error getting mount information\n");
++		return -1;
++	}
++	while ((mntent = getmntent(mnt)) != NULL) {
++		if (strcmp(mntent->mnt_type, SYSFS_FSTYPE_NAME) == 0 &&
++			strcmp(mntent->mnt_dir, mnt_path) == 0) {
++			ret = 0;
++			break;
++		}
++	}
++	
++	endmntent(mnt);
++
++	if (ret < 0)
++		errno = ENOENT;
++
++	return ret;
+ }
+ 
+ /**
diff --git a/package/libs/toolchain/Makefile b/package/libs/toolchain/Makefile
new file mode 100644
index 0000000000..0101b81a31
--- /dev/null
+++ b/package/libs/toolchain/Makefile
@@ -0,0 +1,578 @@
+#
+# Copyright (C) 2007-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+PKG_NAME:=toolchain
+PKG_RELEASE:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-3.0-with-GCC-exception
+
+PKG_FLAGS:=hold essential nonshared
+
+include $(INCLUDE_DIR)/package.mk
+
+ifneq ($(DUMP),1)
+  LIBGCC_VERSION:=$(GCC_VERSION)
+else
+  LIBC_VERSION:=<LIBC_VERSION>
+  LIBGCC_VERSION:=<LIBGCC_VERSION>
+endif
+
+define Package/gcc/Default
+  SECTION:=libs
+  CATEGORY:=Base system
+  URL:=http://gcc.gnu.org/
+  VERSION:=$(LIBGCC_VERSION)-$(PKG_RELEASE)
+endef
+
+define Package/libgcc
+$(call Package/gcc/Default)
+  TITLE:=GCC support library
+endef
+
+define Package/libgcc/config
+	menu "Configuration"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libgcc
+
+	config LIBGCC_ROOT_DIR
+		string
+		prompt "libgcc shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libgcc
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBGCC_FILE_SPEC
+		string
+		prompt "libgcc shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libgcc
+		default "./lib/libgcc_s.so.*"
+
+	endmenu
+endef
+
+define Package/libatomic
+$(call Package/gcc/Default)
+  DEPENDS:=+libgcc
+  TITLE:=Atomic support library
+endef
+
+define Package/libatomic/config
+	menu "Configuration"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libatomic
+
+	config LIBATOMIC_ROOT_DIR
+		string
+		prompt "libatomic shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libatomic
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBATOMIC_FILE_SPEC
+		string
+		prompt "libatomic shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libatomic
+		default "./lib/libatomic.so.*"
+
+	endmenu
+endef
+
+define Package/libssp
+$(call Package/gcc/Default)
+  DEPENDS+=@SSP_SUPPORT
+  TITLE:=GCC support library
+endef
+
+define Package/libssp/config
+	menu "Configuration"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libssp
+
+	config LIBSSP_ROOT_DIR
+		string
+		prompt "libssp shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libssp
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBSSP_FILE_SPEC
+		string
+		prompt "libssp shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libssp
+		default "./lib/libssp.so.*"
+
+	endmenu
+endef
+
+
+define Package/libstdcpp
+$(call Package/gcc/Default)
+  NAME:=libstdc++
+  TITLE:=GNU Standard C++ Library v3
+endef
+
+define Package/libstdcpp/config
+	menu "Configuration"
+	depends on EXTERNAL_TOOLCHAIN && PACKAGE_libstdcpp
+
+	config LIBSTDCPP_ROOT_DIR
+		string
+		prompt "libstdcpp shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libstdcpp
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBSTDCPP_FILE_SPEC
+		string
+		prompt "libstdc++ shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libstdcpp
+		default "./lib/libstdc++.so.*"
+
+	endmenu
+endef
+
+
+define Package/libc/Default
+  SECTION:=libs
+  CATEGORY:=Base system
+  VERSION:=$(LIBC_VERSION)-$(PKG_RELEASE)
+  DEPENDS:=+libgcc
+  URL:=$(LIBC_URL)
+endef
+
+
+define Package/libc
+$(call Package/libc/Default)
+  TITLE:=C library
+endef
+
+define Package/libc/config
+	menu "Configuration"
+	depends on EXTERNAL_TOOLCHAIN && PACKAGE_libc
+
+	config LIBC_ROOT_DIR
+		string
+		prompt "libc shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libc
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBC_FILE_SPEC
+		string
+		prompt "libc shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libc
+		default "./lib/ld{-*.so,-linux*.so.*} ./lib/lib{anl,c,cidn,crypt,dl,m,nsl,nss_dns,nss_files,resolv,util}{-*.so,.so.*}"
+
+	endmenu
+endef
+
+
+define Package/libpthread
+$(call Package/libc/Default)
+  TITLE:=POSIX thread library
+endef
+
+define Package/libpthread/config
+	menu "Configuration"
+	depends on EXTERNAL_TOOLCHAIN && PACKAGE_libpthread
+
+	config LIBPTHREAD_ROOT_DIR
+		string
+		prompt "libpthread shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libpthread
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBPTHREAD_FILE_SPEC
+		string
+		prompt "libpthread shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libpthread
+		default "./lib/libpthread{-*.so,.so.*}"
+
+	endmenu
+endef
+
+
+define Package/libthread-db
+$(call Package/libc/Default)
+  DEPENDS:=@!USE_MUSL
+  TITLE:=POSIX thread library debugging support
+endef
+
+define Package/librt
+$(call Package/libc/Default)
+  TITLE:=POSIX.1b RealTime extension library
+  DEPENDS:=+libpthread
+endef
+
+define Package/librt/config
+	menu "Configuration"
+	depends on EXTERNAL_TOOLCHAIN && PACKAGE_librt
+
+	config LIBRT_ROOT_DIR
+		string
+		prompt "librt shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_librt
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBRT_FILE_SPEC
+		string
+		prompt "librt shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_librt
+		default "./lib/librt{-*.so,.so.*}"
+
+	endmenu
+endef
+
+
+define Package/libgfortran
+$(call Package/gcc/Default)
+  TITLE:=GFortran support library
+  DEPENDS+=@INSTALL_GFORTRAN
+endef
+
+define Package/libgfortran/config
+	menu "Configuration"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libgfortran
+
+	config LIBGFORTRAN_ROOT_DIR
+		string
+		prompt "libgfortran shared library base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libgfortran
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LIBGFORTRAN_FILE_SPEC
+		string
+		prompt "libgfortran shared library files (use wildcards)"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_libgfortran
+		default "./usr/lib/libgfortran.so.*"
+
+	endmenu
+endef
+
+define Package/ldd
+$(call Package/libc/Default)
+  DEPENDS:=@!USE_MUSL
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=LDD trace utility
+endef
+
+define Package/ldd/config
+	menu "Configuration"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_ldd
+
+	config LDD_ROOT_DIR
+		string
+		prompt "ldd trace utility base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_ldd
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LDD_FILE_SPEC
+		string
+		prompt "ldd trace utility file"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_ldd
+		default "./usr/bin/ldd"
+
+	endmenu
+endef
+
+
+define Package/ldconfig
+$(call Package/libc/Default)
+  DEPENDS:=@!USE_MUSL
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Shared library path configuration
+endef
+
+define Package/ldconfig/config
+	menu "Configuration"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_ldconfig
+
+	config LDCONFIG_ROOT_DIR
+		string
+		prompt "ldconfig base directory"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_ldconfig
+		default TOOLCHAIN_ROOT  if !NATIVE_TOOLCHAIN
+		default "/"  if NATIVE_TOOLCHAIN
+
+	config LDCONFIG_FILE_SPEC
+		string
+		prompt "ldconfig file"
+		depends on EXTERNAL_TOOLCHAIN && PACKAGE_ldconfig
+		default "./sbin/ldconfig"
+
+	endmenu
+endef
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+endef
+
+LIBGCC_A=$(lastword $(wildcard $(TOOLCHAIN_DIR)/lib/gcc/*/*/libgcc_pic.a))
+LIBGCC_MAP=$(lastword $(wildcard $(TOOLCHAIN_DIR)/lib/gcc/*/*/libgcc.map))
+LIBGCC_SO=$(lastword $(wildcard $(TOOLCHAIN_DIR)/lib/libgcc_s.so.*))
+
+define Build/Compile/uClibc
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/libuClibc-*.so \
+		$(TOOLCHAIN_DIR)/lib/libcrypt-*.so \
+		$(TOOLCHAIN_DIR)/lib/libm-*.so \
+		$(TOOLCHAIN_DIR)/lib/libpthread-*.so \
+		$(PKG_BUILD_DIR)/
+endef
+ifneq ($(LIBGCC_SO),)
+    define Build/Compile/libgcc
+	$(CP) $(LIBGCC_SO) $(PKG_BUILD_DIR)/
+    endef
+endif
+
+define Build/Compile/Default
+	$(call Build/Compile/libgcc)
+	$(call Build/Compile/$(LIBC))
+endef
+Build/Compile = $(Build/Compile/Default)
+
+ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+
+  define Package/libgcc/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) $(TOOLCHAIN_DIR)/lib/libgcc_s.so.* $(1)/lib/
+  endef
+
+  define Package/libatomic/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) $(TOOLCHAIN_DIR)/lib/libatomic.so.* $(1)/lib/
+  endef
+
+  define Package/libgfortran/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(TOOLCHAIN_DIR)/lib/libgfortran.so.* $(1)/usr/lib/
+  endef
+
+  define Package/libssp/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) $(TOOLCHAIN_DIR)/lib/libssp.so.* $(1)/lib/
+  endef
+
+  define Package/libstdcpp/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(TOOLCHAIN_DIR)/lib/libstdc++.so.* $(1)/usr/lib/
+  endef
+
+  define Package/glibc/install
+	$(CP) ./glibc-files/* $(1)/
+	rm -f $(1)/etc/localtime
+	$(LN) /tmp/localtime $(1)/etc/localtime
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/ld*.so.* \
+		$(TOOLCHAIN_DIR)/lib/ld-$(LIBC_SO_VERSION).so \
+		$(1)/lib/
+	for file in libanl libc libcidn libcrypt libdl libm libnsl libnss_dns libnss_files libresolv libutil; do \
+		for file in $(TOOLCHAIN_DIR)/lib/$$$$file.so.* $(TOOLCHAIN_DIR)/lib/$$$$file-$(LIBC_SO_VERSION).so; do \
+			if [ -e "$$$$file" ]; then \
+				$(CP) $$$$file $(1)/lib/; \
+			fi; \
+		done; \
+	done
+  endef
+
+  define Package/uClibc/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/ld*-uClibc.so.* \
+		$(TOOLCHAIN_DIR)/lib/ld*-uClibc-$(LIBC_SO_VERSION).so \
+		$(1)/lib/
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/libc.so.* \
+		$(TOOLCHAIN_DIR)/lib/libuClibc-$(LIBC_SO_VERSION).so \
+		$(1)/lib/
+	for file in libcrypt libdl libm libutil; do \
+		$(CP) \
+			$(TOOLCHAIN_DIR)/lib/$$$$file.so.* \
+			$(TOOLCHAIN_DIR)/lib/$$$$file-$(LIBC_SO_VERSION).so \
+			$(1)/lib/; \
+	done
+
+	$(CP) \
+		$(PKG_BUILD_DIR)/libuClibc-* \
+		$(PKG_BUILD_DIR)/libm-* \
+		$(PKG_BUILD_DIR)/libcrypt-* \
+		$(1)/lib/
+  endef
+
+  LD_MUSL_NAME = $(notdir $(firstword $(wildcard $(TOOLCHAIN_DIR)/lib/libc.so*)))
+
+  define Package/musl/install
+	$(INSTALL_DIR) $(1)/lib $(1)/usr/bin
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/ld-musl-*.so* \
+		$(1)/lib/
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/libc.so* \
+		$(1)/lib/
+	$(LN) ../../lib/$(LD_MUSL_NAME) $(1)/usr/bin/ldd
+  endef
+
+  define Package/libc/install
+    $(call Package/$(LIBC)/install,$1)
+  endef
+
+  define Package/libc/install_lib
+	$(CP) $(filter-out %/libdl_pic.a %/libpthread_pic.a %/libresolv_pic.a,$(wildcard $(TOOLCHAIN_DIR)/lib/lib*.a)) $(1)/lib/
+	$(if $(wildcard $(TOOLCHAIN_DIR)/lib/libc_so.a),$(CP) $(TOOLCHAIN_DIR)/lib/libc_so.a $(1)/lib/libc_pic.a)
+	$(if $(LIBGCC_MAP), \
+		$(CP) $(LIBGCC_A) $(1)/lib/libgcc_s_pic.a; \
+		$(CP) $(LIBGCC_MAP) $(1)/lib/libgcc_s_pic.map \
+	)
+  endef
+
+  define Package/libpthread/install
+	$(INSTALL_DIR) $(1)/lib
+  ifneq ($(CONFIG_USE_MUSL),y)
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/libpthread.so.* \
+		$(TOOLCHAIN_DIR)/lib/libpthread-$(LIBC_SO_VERSION).so \
+		$(1)/lib/
+  endif
+  endef
+
+  define Package/libthread-db/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/libthread_db.so.* $(1)/lib
+  ifeq ($(CONFIG_USE_UCLIBC),y)
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/libthread_db-$(LIBC_SO_VERSION).so \
+		$(1)/lib/
+  endif
+  endef
+
+  define Package/libpthread/install_lib
+	$(if $(wildcard $(TOOLCHAIN_DIR)/lib/libpthread_so.a),$(CP) $(TOOLCHAIN_DIR)/lib/libpthread_so.a $(1)/lib/libpthread_pic.a)
+  endef
+
+  define Package/librt/install
+	$(INSTALL_DIR) $(1)/lib
+  ifneq ($(CONFIG_USE_MUSL),y)
+	$(CP) \
+		$(TOOLCHAIN_DIR)/lib/librt.so.* \
+		$(TOOLCHAIN_DIR)/lib/librt-$(LIBC_SO_VERSION).so \
+		$(1)/lib/
+  endif
+  endef
+
+  define Package/ldd/install
+	$(INSTALL_DIR) $(1)/usr/bin/
+	$(CP) $(TOOLCHAIN_DIR)/bin/ldd $(1)/usr/bin/
+  endef
+
+  define Package/ldconfig/install
+	$(INSTALL_DIR) $(1)/sbin/
+	$(CP) $(TOOLCHAIN_DIR)/sbin/ldconfig $(1)/sbin/
+  endef
+
+else
+
+  define Package/libgcc/install
+	for file in $(call qstrip,$(CONFIG_LIBGCC_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBGCC_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/libgfortran/install
+	for file in $(call qstrip,$(CONFIG_LIBGFORTRAN_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBGFORTRAN_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done
+  endef
+
+  define Package/libssp/install
+	for file in $(call qstrip,$(CONFIG_LIBSSP_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBSSP_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/libstdcpp/install
+	for file in $(call qstrip,$(CONFIG_LIBSTDCPP_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBSTDCPP_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/libc/install
+	for file in $(call qstrip,$(CONFIG_LIBC_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBC_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/libpthread/install
+	for file in $(call qstrip,$(CONFIG_LIBPTHREAD_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBPTHREAD_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/librt/install
+	for file in $(call qstrip,$(CONFIG_LIBRT_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBRT_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/libatomic/install
+	for file in $(call qstrip,$(CONFIG_LIBATOMIC_FILE_SPEC)); do \
+		$(INSTALL_DIR) $(1)/lib ; \
+		$(CP) $(call qstrip,$(CONFIG_LIBATOMIC_ROOT_DIR))/$$$$file $(1)/lib/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/ldd/install
+	for file in $(call qstrip,$(CONFIG_LDD_FILE_SPEC)); do \
+		dir=`dirname $$$$file` ; \
+		$(INSTALL_DIR) $(1)/$$$$dir ; \
+		$(CP) $(call qstrip,$(CONFIG_LDD_ROOT_DIR))/$$$$file $(1)/$$$$dir/ ; \
+	done ; \
+	exit 0
+  endef
+
+  define Package/ldconfig/install
+	for file in $(call qstrip,$(CONFIG_LDCONFIG_FILE_SPEC)); do \
+		dir=`dirname $$$$file` ; \
+		$(INSTALL_DIR) $(1)/$$$$dir ; \
+		$(CP) $(call qstrip,$(CONFIG_LDCONFIG_ROOT_DIR))/$$$$file $(1)/$$$$dir/ ; \
+	done ; \
+	exit 0
+  endef
+
+endif
+
+$(eval $(call BuildPackage,libc))
+$(eval $(call BuildPackage,libgcc))
+$(eval $(call BuildPackage,libatomic))
+$(eval $(call BuildPackage,libssp))
+$(eval $(call BuildPackage,libstdcpp))
+$(eval $(call BuildPackage,libpthread))
+$(eval $(call BuildPackage,libthread-db))
+$(eval $(call BuildPackage,librt))
+$(eval $(call BuildPackage,libgfortran))
+$(eval $(call BuildPackage,ldd))
+$(eval $(call BuildPackage,ldconfig))
diff --git a/package/libs/toolchain/eglibc-files/etc/nsswitch.conf b/package/libs/toolchain/eglibc-files/etc/nsswitch.conf
new file mode 100644
index 0000000000..981c425da6
--- /dev/null
+++ b/package/libs/toolchain/eglibc-files/etc/nsswitch.conf
@@ -0,0 +1,13 @@
+passwd:files
+shadow:files
+group:files
+hosts:dns files
+bootparams:files
+ethers:files
+netmasks:files
+networks:files
+protocols:files
+rpc:files
+services:files
+automount:files
+aliases:files
diff --git a/package/libs/toolchain/glibc-files/etc/nsswitch.conf b/package/libs/toolchain/glibc-files/etc/nsswitch.conf
new file mode 100644
index 0000000000..981c425da6
--- /dev/null
+++ b/package/libs/toolchain/glibc-files/etc/nsswitch.conf
@@ -0,0 +1,13 @@
+passwd:files
+shadow:files
+group:files
+hosts:dns files
+bootparams:files
+ethers:files
+netmasks:files
+networks:files
+protocols:files
+rpc:files
+services:files
+automount:files
+aliases:files
diff --git a/package/libs/uclibc++/Makefile b/package/libs/uclibc++/Makefile
new file mode 100644
index 0000000000..c386550292
--- /dev/null
+++ b/package/libs/uclibc++/Makefile
@@ -0,0 +1,106 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+# Copyright (c) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uclibc++
+PKG_VERSION:=0.2.4
+PKG_RELEASE:=3
+
+PKG_SOURCE:=uClibc++-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://cxx.uclibc.org/src/
+PKG_MD5SUM:=394c119363dd8b469fb898442a6764b8
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/uClibc++-$(PKG_VERSION)
+PKG_BUILD_PARALLEL:=1
+PKG_USE_MIPS16:=0
+PKG_LICENSE:=LGPL-2.1+
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/uclibcxx
+  NAME:=uclibc++
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=C++ library for embedded systems
+  URL:=http://cxx.uclibc.org/src/
+endef
+
+UCLIBC_TARGET_ARCH:=$(shell echo $(ARCH) | sed -e s'/-.*//' \
+	-e 's/i.86/i386/' \
+	-e 's/sparc.*/sparc/' \
+	-e 's/m68k.*/m68k/' \
+	-e 's/ppc/powerpc/g' \
+	-e 's/v850.*/v850/g' \
+	-e 's/sh64/sh/' \
+	-e 's/sh[234].*/sh/' \
+	-e 's/mips.*/mips/' \
+	-e 's/mipsel.*/mips/' \
+)
+
+TARGET_CFLAGS += $(FPIC)
+
+ifneq ($(CONFIG_CCACHE),)
+TARGET_CXX=$(TARGET_CXX_NOCACHE)
+endif
+
+ifeq ($(CONFIG_USE_MUSL),y)
+SSP_LIB=-lssp_nonshared
+endif
+
+MAKE_FLAGS:= \
+	TOPDIR="$(PKG_BUILD_DIR)/" \
+	$(TARGET_CONFIGURE_OPTS) \
+	CPU_CFLAGS="$(TARGET_CFLAGS)" \
+	CROSS="$(TARGET_CROSS)" \
+	LDFLAGS="-Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc -Wl,-z,defs $(TARGET_LDFLAGS)" \
+	CP="$(CP)" \
+	GEN_LIBS="-lc $(LIBGCC_S) $(SSP_LIB)" \
+	GEN_CFLAGS="-std=gnu++98 -nostdinc++" \
+	check_as_needed=
+
+# check_as_needed overrides dependency on libgcc_s
+
+define Build/Prepare
+	$(PKG_UNPACK)
+	$(SED) 's/\r$$$$//' $(PKG_BUILD_DIR)/include/unwind-cxx.h
+	$(Build/Patch)
+endef
+
+define Build/Configure
+	if [ -f ./files/config.$(UCLIBC_TARGET_ARCH) ]; then \
+		cp ./files/config.$(UCLIBC_TARGET_ARCH) $(PKG_BUILD_DIR)/.config; \
+	else \
+		cp ./files/config.default $(PKG_BUILD_DIR)/.config; \
+	fi
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(2)/bin $(1)/usr/include/uClibc++ $(1)/usr/lib
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/bin/g++-uc $(TOOLCHAIN_DIR)/bin/
+	$(CP) $(PKG_INSTALL_DIR)/include/* $(1)/usr/include/uClibc++/
+	$(CP) $(PKG_INSTALL_DIR)/lib/libuClibc++*.{a,so}* $(1)/usr/lib/
+	$(SED) 's!\(^\|[[:space:]]\)-[IL]$(TOOLCHAIN_DIR)/[^[:space:]]*!!g' $(TOOLCHAIN_DIR)/bin/g++-uc
+	$(SED) 's|-I/include/|-I$$$${STAGING_DIR:-$(STAGING_DIR)}/usr/include/uClibc++/|g' $(TOOLCHAIN_DIR)/bin/g++-uc
+	$(SED) 's|-L/lib/|-L$$$${STAGING_DIR:-$(STAGING_DIR)}/lib/|g' $(TOOLCHAIN_DIR)/bin/g++-uc
+# add another wrapper which links against both uClibc++ and libstdc++
+	$(INSTALL_BIN) $(TOOLCHAIN_DIR)/bin/g++-uc $(TOOLCHAIN_DIR)/bin/g++-uc+std
+	$(SED) 's|^WRAPPER_INCLUDEDIR=.*||g' $(TOOLCHAIN_DIR)/bin/g++-uc+std
+	$(SED) 's|-luClibc++|-Wl,-Bdynamic,-luClibc++,-Bstatic,-lstdc++,-Bdynamic|g' $(TOOLCHAIN_DIR)/bin/g++-uc+std
+	$(SED) 's|-nostdinc++||g' $(TOOLCHAIN_DIR)/bin/g++-uc+std
+endef
+
+define Package/uclibcxx/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libuClibc++.so.* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/lib/libuClibc++-*.so $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,uclibcxx))
diff --git a/package/libs/uclibc++/files/config.default b/package/libs/uclibc++/files/config.default
new file mode 100644
index 0000000000..944e1a6cfb
--- /dev/null
+++ b/package/libs/uclibc++/files/config.default
@@ -0,0 +1,58 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Target Features and Options
+#
+UCLIBCXX_HAS_FLOATS=y
+# UCLIBCXX_HAS_LONG_DOUBLE is not set
+# UCLIBCXX_HAS_TLS is not set
+WARNINGS="-Wall"
+BUILD_EXTRA_LIBRARIES=""
+HAVE_DOT_CONFIG=y
+
+#
+# String and I/O Stream Support
+#
+UCLIBCXX_HAS_WCHAR=y
+UCLIBCXX_IOSTREAM_BUFSIZE=32
+UCLIBCXX_HAS_LFS=y
+UCLIBCXX_SUPPORT_CDIR=y
+UCLIBCXX_SUPPORT_CIN=y
+UCLIBCXX_SUPPORT_COUT=y
+UCLIBCXX_SUPPORT_CERR=y
+UCLIBCXX_SUPPORT_CLOG=y
+UCLIBCXX_SUPPORT_WCIN=y
+UCLIBCXX_SUPPORT_WCOUT=y
+UCLIBCXX_SUPPORT_WCERR=y
+UCLIBCXX_SUPPORT_WCLOG=y
+
+#
+# STL and Code Expansion
+#
+UCLIBCXX_STL_BUFFER_SIZE=32
+UCLIBCXX_CODE_EXPANSION=y
+UCLIBCXX_EXPAND_CONSTRUCTORS_DESTRUCTORS=y
+UCLIBCXX_EXPAND_STRING_CHAR=y
+UCLIBCXX_EXPAND_VECTOR_BASIC=y
+UCLIBCXX_EXPAND_IOS_CHAR=y
+UCLIBCXX_EXPAND_STREAMBUF_CHAR=y
+UCLIBCXX_EXPAND_ISTREAM_CHAR=y
+UCLIBCXX_EXPAND_OSTREAM_CHAR=y
+UCLIBCXX_EXPAND_FSTREAM_CHAR=y
+UCLIBCXX_EXPAND_SSTREAM_CHAR=y
+
+#
+# Library Installation Options
+#
+UCLIBCXX_RUNTIME_PREFIX=""
+UCLIBCXX_RUNTIME_INCLUDE_SUBDIR="/include"
+UCLIBCXX_RUNTIME_LIB_SUBDIR="/lib"
+UCLIBCXX_RUNTIME_BIN_SUBDIR="/bin"
+UCLIBCXX_EXCEPTION_SUPPORT=y
+IMPORT_LIBSUP=y
+# IMPORT_LIBGCC_EH is not set
+BUILD_STATIC_LIB=y
+# BUILD_ONLY_STATIC_LIB is not set
+# DODEBUG is not set
diff --git a/package/libs/uclibc++/patches/002-path_to_bash.patch b/package/libs/uclibc++/patches/002-path_to_bash.patch
new file mode 100644
index 0000000000..26d88ee4dd
--- /dev/null
+++ b/package/libs/uclibc++/patches/002-path_to_bash.patch
@@ -0,0 +1,11 @@
+--- a/bin/Makefile
++++ b/bin/Makefile
+@@ -13,7 +13,7 @@ install:
+ 	$(INSTALL) -m 755 $(WRAPPER) $(PREFIX)$(UCLIBCXX_RUNTIME_BINDIR)
+ 
+ $(WRAPPER): Makefile
+-	echo '#!/bin/sh' > $@
++	echo '#!/usr/bin/env bash' > $@
+ 	echo '' >> $@
+ 	echo 'WRAPPER_INCLUDEDIR="$${WRAPPER_INCLUDEDIR:=-I$(UCLIBCXX_RUNTIME_INCLUDEDIR)}"' >> $@
+ 	echo 'WRAPPER_LIBDIR="$${WRAPPER_LIBDIR:=-L$(UCLIBCXX_RUNTIME_LIBDIR)}"' >> $@
diff --git a/package/libs/uclibc++/patches/006-eabi_fix.patch b/package/libs/uclibc++/patches/006-eabi_fix.patch
new file mode 100644
index 0000000000..893c2d60b6
--- /dev/null
+++ b/package/libs/uclibc++/patches/006-eabi_fix.patch
@@ -0,0 +1,38 @@
+--- a/include/typeinfo
++++ b/include/typeinfo
+@@ -44,6 +44,7 @@ namespace __cxxabiv1
+   class __class_type_info;
+ } // namespace __cxxabiv1
+ 
++#ifndef __GXX_MERGED_TYPEINFO_NAMES
+ #if !__GXX_WEAK__
+   // If weak symbols are not supported, typeinfo names are not merged.
+   #define __GXX_MERGED_TYPEINFO_NAMES 0
+@@ -51,6 +52,7 @@ namespace __cxxabiv1
+   // On platforms that support weak symbols, typeinfo names are merged.
+   #define __GXX_MERGED_TYPEINFO_NAMES 1
+ #endif
++#endif
+ 
+ namespace std 
+ {
+--- a/include/unwind-cxx.h
++++ b/include/unwind-cxx.h
+@@ -173,6 +173,7 @@ extern std::unexpected_handler __unexpec
+ 
+ // This is the exception class we report -- "GNUCC++\0".
+ const _Unwind_Exception_Class __gxx_exception_class
++#ifndef __ARM_EABI_UNWINDER__
+ = ((((((((_Unwind_Exception_Class) 'G' 
+ 	 << 8 | (_Unwind_Exception_Class) 'N')
+ 	<< 8 | (_Unwind_Exception_Class) 'U')
+@@ -181,6 +182,9 @@ const _Unwind_Exception_Class __gxx_exce
+      << 8 | (_Unwind_Exception_Class) '+')
+     << 8 | (_Unwind_Exception_Class) '+')
+    << 8 | (_Unwind_Exception_Class) '\0');
++#else
++= "GNUC++";
++#endif
+ 
+ // GNU C++ personality routine, Version 0.
+ extern "C" _Unwind_Reason_Code __gxx_personality_v0
diff --git a/package/libs/uclibc++/patches/010-honor-ldflags.patch b/package/libs/uclibc++/patches/010-honor-ldflags.patch
new file mode 100644
index 0000000000..b1050cb1bd
--- /dev/null
+++ b/package/libs/uclibc++/patches/010-honor-ldflags.patch
@@ -0,0 +1,23 @@
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -3,9 +3,9 @@ include $(TOPDIR)Rules.mak
+ 
+ WR_CXX := WRAPPER_INCLUDEDIR=-I$(TOPDIR)include $(TOPDIR)bin/g++-uc
+ 
+-LDFLAGS += -nodefaultlibs -shared -Wl,-soname,$(SHARED_MAJORNAME) $(BUILD_EXTRA_LIBRARIES)
++EXTRA_LDFLAGS += -nodefaultlibs -shared -Wl,-soname,$(SHARED_MAJORNAME) $(BUILD_EXTRA_LIBRARIES)
+ ifneq ($(DODEBUG),y)
+-LDFLAGS += -Wl,-s
++EXTRA_LDFLAGS += -Wl,-s
+ endif
+ 
+ SRCS =	$(wildcard *.cpp)
+@@ -60,7 +60,7 @@ $(LIBNAME).a: libgcc_eh libsupc $(EXOBJS
+ 	$(RANLIB) $@
+ 
+ $(SHARED_FULLNAME): libgcc_eh libsupc $(EXOBJS)
+-	$(CC) $(LDFLAGS) -o $@ $(EXOBJS) $(SUPOBJS) $(GCCOBJS) $(LIBS)
++	$(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) -o $@ $(EXOBJS) $(SUPOBJS) $(GCCOBJS) $(LIBS)
+ 	$(LN) $@ $(SHARED_MAJORNAME)
+ 	$(LN) $(SHARED_MAJORNAME) $(LIBNAME).so
+ 
diff --git a/package/libs/uclibc++/patches/020-template-fix.patch b/package/libs/uclibc++/patches/020-template-fix.patch
new file mode 100644
index 0000000000..f7cc09e140
--- /dev/null
+++ b/package/libs/uclibc++/patches/020-template-fix.patch
@@ -0,0 +1,22 @@
+--- a/include/ostream
++++ b/include/ostream
+@@ -294,7 +294,7 @@ namespace std {
+ #endif
+ #endif
+ 
+-	template <class charT,class traits = char_traits<charT> >
++	template <class charT,class traits>
+ 		class _UCXXEXPORT basic_ostream<charT,traits>::sentry
+ 	{
+ 		bool ok;
+--- a/include/istream
++++ b/include/istream
+@@ -340,7 +340,7 @@ namespace std{
+ 
+ 	};
+ 
+-	template <class charT,class traits = char_traits<charT> > class _UCXXEXPORT basic_istream<charT,traits>::sentry {
++	template <class charT,class traits> class _UCXXEXPORT basic_istream<charT,traits>::sentry {
+ 		bool ok;
+ 	public:
+ 		explicit _UCXXEXPORT sentry(basic_istream<charT,traits>& os, bool noskipws = false){
diff --git a/package/libs/uclibc++/patches/030-memory_corruption_fix.patch b/package/libs/uclibc++/patches/030-memory_corruption_fix.patch
new file mode 100644
index 0000000000..e34efdbb15
--- /dev/null
+++ b/package/libs/uclibc++/patches/030-memory_corruption_fix.patch
@@ -0,0 +1,114 @@
+From 1dc865b8bbb3911abc8ce53c7ae8a59dc90f6fc3 Mon Sep 17 00:00:00 2001
+From: Ivan Kold <pixus.ru@gmail.com>
+Date: Thu, 3 Mar 2016 12:56:30 -0800
+Subject: [PATCH] Fix throw statement causing memory corruption
+
+The __cxxabiv1::__cxa_throw in the GCC's libsupc++ expects
+sizeof(__cxa_refcounted_exception) bytes be allocated before
+exception object.
+uClibc++ allocates only sizeof(__cxa_exception) before an
+exception object.
+The __cxxabiv1::__cxa_throw writes in memory before allocated:
+// gcc-5.2.0/libstdc++-v3/libsupc++/eh_throw.cc:69
+__cxa_refcounted_exception *header
+  = __get_refcounted_exception_header_from_obj (obj);
+header->referenceCount = 1;
+
+Signed-off-by: Ivan Kold <pixus.ru@gmail.com>
+---
+ include/unwind-cxx.h | 34 +++++++++++++++++++++++++++++++++-
+ src/eh_alloc.cpp     |  8 ++++----
+ 2 files changed, 37 insertions(+), 5 deletions(-)
+
+--- a/include/unwind-cxx.h
++++ b/include/unwind-cxx.h
+@@ -1,5 +1,5 @@
+ // -*- C++ -*- Exception handling and frame unwind runtime interface routines.
+-// Copyright (C) 2001 Free Software Foundation, Inc.
++// Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ //
+ // This file is part of GCC.
+ //
+@@ -13,6 +13,10 @@
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ // GNU General Public License for more details.
+ //
++// Under Section 7 of GPL version 3, you are granted additional
++// permissions described in the GCC Runtime Library Exception, version
++// 3.1, as published by the Free Software Foundation.
++//
+ // You should have received a copy of the GNU General Public License
+ // along with GCC; see the file COPYING.  If not, write to
+ // the Free Software Foundation, 59 Temple Place - Suite 330,
+@@ -40,6 +44,12 @@
+ #include <cstddef>
+ #include "unwind.h"
+ 
++// Original unwind-cxx.h also includes bits/atomic_word.h which is CPU-specific, 
++// but always defines _Atomic_word as typedef int .
++// Only thing that differs is memory-barrier macroses.
++typedef int _Atomic_word;
++
++
+ #pragma GCC visibility push(default)
+ 
+ namespace __cxxabiv1
+@@ -79,6 +89,13 @@ struct __cxa_exception
+   _Unwind_Exception unwindHeader;
+ };
+ 
++struct __cxa_refcounted_exception
++{
++  // Manage this header.
++  _Atomic_word referenceCount;
++  // __cxa_exception must be last, and no padding can be after it.
++  __cxa_exception exc;
++};
+ 
+ // A dependent C++ exception object consists of a header, which is a wrapper
+ // around an unwind object header with additional C++ specific information,
+@@ -210,6 +227,21 @@ __get_exception_header_from_ue (_Unwind_
+   return reinterpret_cast<__cxa_exception *>(exc + 1) - 1;
+ }
+ 
++// Acquire the C++ refcounted exception header from the C++ object.
++static inline __cxa_refcounted_exception *
++__get_refcounted_exception_header_from_obj (void *ptr)
++{
++  return reinterpret_cast<__cxa_refcounted_exception *>(ptr) - 1;
++}
++
++// Acquire the C++ refcounted exception header from the generic exception
++// header.
++static inline __cxa_refcounted_exception *
++__get_refcounted_exception_header_from_ue (_Unwind_Exception *exc)
++{
++  return reinterpret_cast<__cxa_refcounted_exception *>(exc + 1) - 1;
++}
++
+ } /* namespace __cxxabiv1 */
+ 
+ #pragma GCC visibility pop
+--- a/src/eh_alloc.cpp
++++ b/src/eh_alloc.cpp
+@@ -30,16 +30,16 @@ extern "C" void * __cxa_allocate_excepti
+ 	void *retval;
+ 	//The sizeof crap is required by Itanium ABI because we need to provide space for
+ 	//accounting information which is implementaion (gcc) specified
+-	retval = malloc (thrown_size + sizeof(__cxa_exception));
++	retval = malloc (thrown_size + sizeof(__cxa_refcounted_exception));
+ 	if (0 == retval){
+ 		std::terminate();
+ 	}
+-	memset (retval, 0, sizeof(__cxa_exception));
+-	return (void *)((unsigned char *)retval + sizeof(__cxa_exception));
++	memset (retval, 0, sizeof(__cxa_refcounted_exception));
++	return (void *)((unsigned char *)retval + sizeof(__cxa_refcounted_exception));
+ }
+ 
+ extern "C" void __cxa_free_exception(void *vptr) throw(){
+-	free( (char *)(vptr) - sizeof(__cxa_exception) );
++	free( (char *)(vptr) - sizeof(__cxa_refcounted_exception) );
+ }
+ 
+ 
diff --git a/package/libs/uclibc++/patches/040-delete-c++14.patch b/package/libs/uclibc++/patches/040-delete-c++14.patch
new file mode 100644
index 0000000000..f48a78f0a4
--- /dev/null
+++ b/package/libs/uclibc++/patches/040-delete-c++14.patch
@@ -0,0 +1,20 @@
+--- a/src/del_op.cpp
++++ b/src/del_op.cpp
+@@ -24,3 +24,7 @@
+ _UCXXEXPORT void operator delete(void* ptr) throw(){
+ 	free(ptr);
+ }
++
++_UCXXEXPORT void operator delete(void* ptr, size_t size) throw(){
++	free(ptr);
++}
+--- a/src/del_opv.cpp
++++ b/src/del_opv.cpp
+@@ -24,3 +24,7 @@
+ _UCXXEXPORT void operator delete[](void * ptr) throw(){
+ 	free(ptr);
+ }
++
++_UCXXEXPORT void operator delete[](void * ptr, size_t size) throw(){
++	free(ptr);
++}
diff --git a/package/libs/uclient/Makefile b/package/libs/uclient/Makefile
new file mode 100644
index 0000000000..d3af9e1c29
--- /dev/null
+++ b/package/libs/uclient/Makefile
@@ -0,0 +1,52 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uclient
+PKG_VERSION:=2016-07-30
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/uclient.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=ccb314db2e99463de15eed9d7626360d82aec4d2
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=8cbe8e34bbbd849b46b18f41629b8b3548d1eb3d2517fb473b7068c7b1fbe6da
+CMAKE_INSTALL:=1
+
+PKG_BUILD_DEPENDS:=ustream-ssl
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/libuclient
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=HTTP/1.1 client library
+  ABI_VERSION:=$(PKG_VERSION)
+  DEPENDS:=+libubox
+endef
+
+define Package/uclient-fetch
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Tiny wget replacement using libuclient
+  DEPENDS:=+libuclient
+endef
+
+define Package/libuclient/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libuclient.so $(1)/usr/lib/
+endef
+
+define Package/uclient-fetch/install
+	$(INSTALL_DIR) $(1)/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/uclient-fetch $(1)/bin/
+	ln -s uclient-fetch $(1)/bin/wget
+endef
+
+$(eval $(call BuildPackage,libuclient))
+$(eval $(call BuildPackage,uclient-fetch))
diff --git a/package/libs/ustream-ssl/Makefile b/package/libs/ustream-ssl/Makefile
new file mode 100644
index 0000000000..ba022b8fc7
--- /dev/null
+++ b/package/libs/ustream-ssl/Makefile
@@ -0,0 +1,87 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ustream-ssl
+PKG_VERSION:=2016-07-02
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/ustream-ssl.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=ec80adaa1b47f28d426fa19c692011ce60b992d6
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=701f8728b90d4fc141ca086bbd7802cfae42aaa64ace83debb8c27111b921a34
+CMAKE_INSTALL:=1
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_SOURCE_SUBDIR)
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/libustream/default
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=ustream SSL Library
+  DEPENDS:=+libubox
+  ABI_VERSION:=$(PKG_VERSION)
+endef
+
+define Package/libustream-openssl
+  $(Package/libustream/default)
+  TITLE += (openssl)
+  DEPENDS += +PACKAGE_libustream-openssl:libopenssl
+  VARIANT:=openssl
+endef
+
+define Package/libustream-cyassl
+  $(Package/libustream/default)
+  TITLE += (cyassl)
+  DEPENDS += +PACKAGE_libustream-cyassl:libcyassl
+  VARIANT:=cyassl
+endef
+
+define Package/libustream-polarssl
+  $(Package/libustream/default)
+  TITLE += (polarssl)
+  DEPENDS += +libpolarssl
+  VARIANT:=polarssl
+  DEFAULT_VARIANT:=1
+endef
+
+define Package/libustream-mbedtls
+  $(Package/libustream/default)
+  TITLE += (mbedtls)
+  DEPENDS += +libmbedtls
+  VARIANT:=mbedtls
+  DEFAULT_VARIANT:=1
+endef
+
+ifeq ($(BUILD_VARIANT),cyassl)
+  TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/cyassl -DHAVE_SNI
+  CMAKE_OPTIONS += -DCYASSL=on
+endif
+ifeq ($(BUILD_VARIANT),polarssl)
+  CMAKE_OPTIONS += -DPOLARSSL=on
+endif
+ifeq ($(BUILD_VARIANT),mbedtls)
+  CMAKE_OPTIONS += -DMBEDTLS=on
+endif
+
+define Package/libustream/default/install
+	$(INSTALL_DIR) $(1)/lib/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libustream-ssl.so $(1)/lib/
+endef
+
+Package/libustream-openssl/install = $(Package/libustream/default/install)
+Package/libustream-cyassl/install = $(Package/libustream/default/install)
+Package/libustream-polarssl/install = $(Package/libustream/default/install)
+Package/libustream-mbedtls/install = $(Package/libustream/default/install)
+
+$(eval $(call BuildPackage,libustream-polarssl))
+$(eval $(call BuildPackage,libustream-mbedtls))
+$(eval $(call BuildPackage,libustream-cyassl))
+$(eval $(call BuildPackage,libustream-openssl))
diff --git a/package/libs/zlib/Makefile b/package/libs/zlib/Makefile
new file mode 100644
index 0000000000..5993cbc29e
--- /dev/null
+++ b/package/libs/zlib/Makefile
@@ -0,0 +1,104 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=zlib
+PKG_VERSION:=1.2.8
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.zlib.net @SF/libpng
+PKG_MD5SUM:=44d667c142d7cda120332623eab69f40
+
+PKG_LICENSE:=Zlib
+PKG_LICENSE_FILES:=README
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/zlib
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Library implementing the deflate compression method
+  URL:=http://www.zlib.net/
+endef
+
+define Package/zlib-dev
+  SECTION:=devel
+  CATEGORY:=Development
+  SUBMENU:=Libraries
+  DEPENDS:=zlib
+  TITLE:=Development files for the zlib library
+endef
+
+define Package/zlib/description
+ zlib is a lossless data-compression library.
+ This package includes the shared library.
+endef
+
+define Package/zlib-dev/description
+ zlib is a lossless data-compression library.
+ This package includes the development support files.
+endef
+
+define Build/Configure
+	(cd $(PKG_BUILD_DIR); \
+		$(TARGET_CONFIGURE_OPTS) \
+		LDSHARED="$(TARGET_CC) -shared -Wl,-soname,libz.so.1" \
+		CFLAGS="$(TARGET_CFLAGS) $(FPIC)" \
+		./configure \
+			--prefix=/usr \
+			--shared \
+			--uname=Linux \
+	);
+endef
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		CFLAGS="$(TARGET_CFLAGS)" \
+		libz.a libz.so.$(PKG_VERSION)
+	mkdir -p $(PKG_INSTALL_DIR)
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		install
+endef
+
+define Build/InstallDev
+	mkdir -p $(1)/usr/include
+	$(CP)	$(PKG_INSTALL_DIR)/usr/include/z{conf,lib}.h \
+		$(1)/usr/include/
+	mkdir -p $(1)/usr/lib
+	$(CP)	$(PKG_INSTALL_DIR)/usr/lib/libz.{a,so*} \
+		$(1)/usr/lib/
+	mkdir -p $(1)/usr/lib/pkgconfig
+	$(CP)	$(PKG_INSTALL_DIR)/usr/lib/pkgconfig/zlib.pc \
+		$(1)/usr/lib/pkgconfig/
+endef
+
+# libz.so is needed for openssl (zlib-dynamic)
+define Package/zlib/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libz.so $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libz.so.* $(1)/usr/lib/
+endef
+
+define Package/zlib-dev/install
+	$(INSTALL_DIR) $(1)/usr/include
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/include/zconf.h \
+	  $(1)/usr/include/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/include/zlib.h \
+	  $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libz.a $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/zlib.pc \
+	  $(1)/usr/lib/pkgconfig/
+endef
+
+$(eval $(call BuildPackage,zlib))
+$(eval $(call BuildPackage,zlib-dev))
diff --git a/package/network/config/firewall/Makefile b/package/network/config/firewall/Makefile
new file mode 100644
index 0000000000..24b2e05569
--- /dev/null
+++ b/package/network/config/firewall/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+# Copyright (C) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=firewall
+PKG_VERSION:=2016-11-07
+PKG_RELEASE:=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/firewall3.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=0367860636aa55e9ee064709ec2814906e1f246b
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=1a087c92c73c3736dd19445d2f470abc2c1eb623956ddd55284c2e6a733198ce
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=ISC
+
+PKG_CONFIG_DEPENDS := CONFIG_IPV6
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/firewall
+  SECTION:=net
+  CATEGORY:=Base system
+  TITLE:=OpenWrt C Firewall
+  DEPENDS:=+libubox +libubus +libuci +libip4tc +IPV6:libip6tc +libxtables +kmod-ipt-core +kmod-ipt-conntrack +kmod-ipt-nat
+endef
+
+define Package/firewall/description
+ This package provides a config-compatible C implementation of the UCI firewall.
+endef
+
+define Package/firewall/conffiles
+/etc/config/firewall
+/etc/firewall.user
+endef
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+CMAKE_OPTIONS += $(if $(CONFIG_IPV6),,-DDISABLE_IPV6=1)
+
+define Package/firewall/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/firewall3 $(1)/sbin/fw3
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/firewall.init $(1)/etc/init.d/firewall
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
+	$(INSTALL_DATA) ./files/firewall.hotplug $(1)/etc/hotplug.d/iface/20-firewall
+	$(INSTALL_DIR) $(1)/etc/config/
+	$(INSTALL_DATA) ./files/firewall.config $(1)/etc/config/firewall
+	$(INSTALL_DIR) $(1)/etc/
+	$(INSTALL_DATA) ./files/firewall.user $(1)/etc/firewall.user
+endef
+
+$(eval $(call BuildPackage,firewall))
diff --git a/package/network/config/firewall/files/firewall.config b/package/network/config/firewall/files/firewall.config
new file mode 100644
index 0000000000..749dbecb97
--- /dev/null
+++ b/package/network/config/firewall/files/firewall.config
@@ -0,0 +1,194 @@
+config defaults
+	option syn_flood	1
+	option input		ACCEPT
+	option output		ACCEPT
+	option forward		REJECT
+# Uncomment this line to disable ipv6 rules
+#	option disable_ipv6	1
+
+config zone
+	option name		lan
+	list   network		'lan'
+	option input		ACCEPT
+	option output		ACCEPT
+	option forward		ACCEPT
+
+config zone
+	option name		wan
+	list   network		'wan'
+	list   network		'wan6'
+	option input		REJECT
+	option output		ACCEPT
+	option forward		REJECT
+	option masq		1
+	option mtu_fix		1
+
+config forwarding
+	option src		lan
+	option dest		wan
+
+# We need to accept udp packets on port 68,
+# see https://dev.openwrt.org/ticket/4108
+config rule
+	option name		Allow-DHCP-Renew
+	option src		wan
+	option proto		udp
+	option dest_port	68
+	option target		ACCEPT
+	option family		ipv4
+
+# Allow IPv4 ping
+config rule
+	option name		Allow-Ping
+	option src		wan
+	option proto		icmp
+	option icmp_type	echo-request
+	option family		ipv4
+	option target		ACCEPT
+
+config rule
+	option name		Allow-IGMP
+	option src		wan
+	option proto		igmp
+	option family		ipv4
+	option target		ACCEPT
+
+# Allow DHCPv6 replies
+# see https://dev.openwrt.org/ticket/10381
+config rule
+	option name		Allow-DHCPv6
+	option src		wan
+	option proto		udp
+	option src_ip		fc00::/6
+	option dest_ip		fc00::/6
+	option dest_port	546
+	option family		ipv6
+	option target		ACCEPT
+
+config rule
+	option name		Allow-MLD
+	option src		wan
+	option proto		icmp
+	option src_ip		fe80::/10
+	list icmp_type		'130/0'
+	list icmp_type		'131/0'
+	list icmp_type		'132/0'
+	list icmp_type		'143/0'
+	option family		ipv6
+	option target		ACCEPT
+
+# Allow essential incoming IPv6 ICMP traffic
+config rule
+	option name		Allow-ICMPv6-Input
+	option src		wan
+	option proto	icmp
+	list icmp_type		echo-request
+	list icmp_type		echo-reply
+	list icmp_type		destination-unreachable
+	list icmp_type		packet-too-big
+	list icmp_type		time-exceeded
+	list icmp_type		bad-header
+	list icmp_type		unknown-header-type
+	list icmp_type		router-solicitation
+	list icmp_type		neighbour-solicitation
+	list icmp_type		router-advertisement
+	list icmp_type		neighbour-advertisement
+	option limit		1000/sec
+	option family		ipv6
+	option target		ACCEPT
+
+# Allow essential forwarded IPv6 ICMP traffic
+config rule
+	option name		Allow-ICMPv6-Forward
+	option src		wan
+	option dest		*
+	option proto		icmp
+	list icmp_type		echo-request
+	list icmp_type		echo-reply
+	list icmp_type		destination-unreachable
+	list icmp_type		packet-too-big
+	list icmp_type		time-exceeded
+	list icmp_type		bad-header
+	list icmp_type		unknown-header-type
+	option limit		1000/sec
+	option family		ipv6
+	option target		ACCEPT
+
+# include a file with users custom iptables rules
+config include
+	option path /etc/firewall.user
+
+
+### EXAMPLE CONFIG SECTIONS
+# do not allow a specific ip to access wan
+#config rule
+#	option src		lan
+#	option src_ip	192.168.45.2
+#	option dest		wan
+#	option proto	tcp
+#	option target	REJECT
+
+# block a specific mac on wan
+#config rule
+#	option dest		wan
+#	option src_mac	00:11:22:33:44:66
+#	option target	REJECT
+
+# block incoming ICMP traffic on a zone
+#config rule
+#	option src		lan
+#	option proto	ICMP
+#	option target	DROP
+
+# port redirect port coming in on wan to lan
+#config redirect
+#	option src			wan
+#	option src_dport	80
+#	option dest			lan
+#	option dest_ip		192.168.16.235
+#	option dest_port	80
+#	option proto		tcp
+
+# port redirect of remapped ssh port (22001) on wan
+#config redirect
+#	option src		wan
+#	option src_dport	22001
+#	option dest		lan
+#	option dest_port	22
+#	option proto		tcp
+
+# allow IPsec/ESP and ISAKMP passthrough
+config rule
+	option src		wan
+	option dest		lan
+	option proto		esp
+	option target		ACCEPT
+
+config rule
+	option src		wan
+	option dest		lan
+	option dest_port	500
+	option proto		udp
+	option target		ACCEPT
+
+### FULL CONFIG SECTIONS
+#config rule
+#	option src		lan
+#	option src_ip	192.168.45.2
+#	option src_mac	00:11:22:33:44:55
+#	option src_port	80
+#	option dest		wan
+#	option dest_ip	194.25.2.129
+#	option dest_port	120
+#	option proto	tcp
+#	option target	REJECT
+
+#config redirect
+#	option src		lan
+#	option src_ip	192.168.45.2
+#	option src_mac	00:11:22:33:44:55
+#	option src_port		1024
+#	option src_dport	80
+#	option dest_ip	194.25.2.129
+#	option dest_port	120
+#	option proto	tcp
diff --git a/package/network/config/firewall/files/firewall.hotplug b/package/network/config/firewall/files/firewall.hotplug
new file mode 100644
index 0000000000..f1eab001d4
--- /dev/null
+++ b/package/network/config/firewall/files/firewall.hotplug
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+[ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0
+[ "$ACTION" = ifupdate -a -z "$IFUPDATE_ADDRESSES" -a -z "$IFUPDATE_DATA" ] && exit 0
+
+/etc/init.d/firewall enabled || exit 0
+
+fw3 -q network "$INTERFACE" >/dev/null || exit 0
+
+logger -t firewall "Reloading firewall due to $ACTION of $INTERFACE ($DEVICE)"
+fw3 -q reload
diff --git a/package/network/config/firewall/files/firewall.init b/package/network/config/firewall/files/firewall.init
new file mode 100755
index 0000000000..ee3ed1a283
--- /dev/null
+++ b/package/network/config/firewall/files/firewall.init
@@ -0,0 +1,61 @@
+#!/bin/sh /etc/rc.common
+
+START=19
+USE_PROCD=1
+QUIET=""
+
+validate_firewall_redirect()
+{
+	uci_validate_section firewall redirect "${1}" \
+		'proto:or(uinteger, string)' \
+		'src:string' \
+		'src_ip:cidr' \
+		'src_dport:or(port, portrange)' \
+		'dest:string' \
+		'dest_ip:cidr' \
+		'dest_port:or(port, portrange)' \
+		'target:or("SNAT", "DNAT")'
+}
+
+validate_firewall_rule()
+{
+	uci_validate_section firewall rule "${1}" \
+		'proto:or(uinteger, string)' \
+		'src:string' \
+		'dest:string' \
+		'src_port:or(port, portrange)' \
+		'dest_port:or(port, portrange)' \
+		'target:string'
+}
+
+service_triggers() {
+	procd_add_reload_trigger firewall	
+
+	procd_open_validate
+	validate_firewall_redirect
+	validate_firewall_rule
+	procd_close_validate
+}
+
+restart() {
+	fw3 restart
+}
+
+start_service() {
+	fw3 ${QUIET} start
+}
+
+stop_service() {
+	fw3 flush
+}
+
+reload_service() {
+	fw3 reload
+}
+
+boot() {
+	# Be silent on boot, firewall might be started by hotplug already,
+	# so don't complain in syslog.
+	QUIET=-q
+	start
+}
diff --git a/package/network/config/firewall/files/firewall.user b/package/network/config/firewall/files/firewall.user
new file mode 100644
index 0000000000..6f799063f5
--- /dev/null
+++ b/package/network/config/firewall/files/firewall.user
@@ -0,0 +1,7 @@
+# This file is interpreted as shell script.
+# Put your custom iptables rules here, they will
+# be executed with each firewall (re-)start.
+
+# Internal uci firewall chains are flushed and recreated on reload, so
+# put custom rules into the root chains e.g. INPUT or FORWARD or into the
+# special user chains, e.g. input_wan_rule or postrouting_lan_rule.
diff --git a/package/network/config/gre/Makefile b/package/network/config/gre/Makefile
new file mode 100644
index 0000000000..2e05ffca6f
--- /dev/null
+++ b/package/network/config/gre/Makefile
@@ -0,0 +1,65 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gre
+PKG_VERSION:=1
+PKG_RELEASE:=4
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/gre/Default
+  SECTION:=net
+  CATEGORY:=Network
+  MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
+endef
+
+define Package/gre
+$(call Package/gre/Default)
+  TITLE:=Generic Routing Encapsulation config support
+endef
+
+define Package/gre/description
+ Generic Routing Encapsulation config support (IPv4 and IPv6) in /etc/config/network.
+endef
+
+define Package/grev4
+$(call Package/gre/Default)
+  TITLE:=Generic Routing Encapsulation (IPv4) config support
+  DEPENDS:=@(PACKAGE_gre) +kmod-gre +resolveip
+endef
+
+define Package/grev4/description
+ Generic Routing Encapsulation config support (IPv4) in /etc/config/network.
+endef
+
+define Package/grev6
+$(call Package/gre/Default)
+  TITLE:=Generic Routing Encapsulation (IPv6) config support
+  DEPENDS:=@(PACKAGE_gre) @IPV6 +kmod-gre6 +resolveip
+endef
+
+define Package/grev6/description
+ Generic Routing Encapsulation config support (IPv6) in /etc/config/network.
+endef
+
+define Build/Compile
+endef
+
+define Build/Configure
+endef
+
+define Package/gre/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/gre.sh $(1)/lib/netifd/proto/gre.sh
+endef
+
+$(eval $(call BuildPackage,gre))
+$(eval $(call BuildPackage,grev4))
+$(eval $(call BuildPackage,grev6))
diff --git a/package/network/config/gre/files/gre.sh b/package/network/config/gre/files/gre.sh
new file mode 100755
index 0000000000..3f472c4473
--- /dev/null
+++ b/package/network/config/gre/files/gre.sh
@@ -0,0 +1,266 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+gre_generic_setup() {
+	local cfg="$1"
+	local mode="$2"
+	local local="$3"
+	local remote="$4"
+	local link="$5"
+	local mtu ttl tos zone ikey okey icsum ocsum iseqno oseqno multicast
+	json_get_vars mtu ttl tos zone ikey okey icsum ocsum iseqno oseqno multicast
+
+	[ -z "$zone" ] && zone="wan"
+	[ -z "$multicast" ] && multicast=1
+
+	proto_init_update "$link" 1
+
+	proto_add_tunnel
+	json_add_string mode "$mode"
+	json_add_int mtu "${mtu:-1280}"
+	[ -n "$df" ] && json_add_boolean df "$df"
+	json_add_int ttl "${ttl:-64}"
+	[ -n "$tos" ] && json_add_string tos "$tos"
+	json_add_boolean multicast "$multicast"
+	json_add_string local "$local"
+	json_add_string remote "$remote"
+	[ -n "$tunlink" ] && json_add_string link "$tunlink"
+	json_add_string info "${ikey:-0},${okey:-0},${icsum:-0},${ocsum:-0},${iseqno:-0},${oseqno:-0}"
+	proto_close_tunnel
+
+	proto_add_data
+	[ -n "$zone" ] && json_add_string zone "$zone"
+	proto_close_data
+
+	proto_send_update "$cfg"
+}
+
+gre_setup() {
+	local cfg="$1"
+	local mode="$2"
+	local remoteip
+
+	local ipaddr peeraddr
+	json_get_vars df ipaddr peeraddr tunlink
+
+	[ -z "$peeraddr" ] && {
+		proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
+		proto_block_restart "$cfg"
+		exit
+	}
+
+	remoteip=$(resolveip -t 10 -4 "$peeraddr")
+
+	if [ -z "$remoteip" ]; then
+		proto_notify_error "$cfg" "PEER_RESOLVE_FAIL"
+		exit
+	fi
+
+	for ip in $remoteip; do
+		peeraddr=$ip
+		break
+	done
+
+	( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+
+	[ -z "$ipaddr" ] && {
+		local wanif="$tunlink"
+		if [ -z $wanif ] && ! network_find_wan wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			exit
+		fi
+
+		if ! network_get_ipaddr ipaddr "$wanif"; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			exit
+		fi
+	}
+
+	[ -z "$df" ] && df="1"
+
+	gre_generic_setup $cfg $mode $ipaddr $peeraddr "gre-$cfg"
+}
+
+proto_gre_setup() {
+	local cfg="$1"
+
+	gre_setup $cfg "greip"
+}
+
+proto_gretap_setup() {
+	local cfg="$1"
+
+	local network
+	json_get_vars network
+
+	gre_setup $cfg "gretapip"
+
+	json_init
+	json_add_string name "gre-$cfg"
+	json_add_boolean link-ext 0
+	json_close_object
+
+	for i in $network; do
+		ubus call network.interface."$i" add_device "$(json_dump)"
+	done
+}
+
+grev6_setup() {
+	local cfg="$1"
+	local mode="$2"
+	local remoteip6
+
+	local ip6addr peer6addr weakif
+	json_get_vars ip6addr peer6addr tunlink weakif
+
+	[ -z "$peer6addr" ] && {
+		proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
+		proto_block_restart "$cfg"
+		exit
+	}
+
+	remoteip6=$(resolveip -t 10 -6 "$peer6addr")
+
+	if [ -z "$remoteip6" ]; then
+		proto_notify_error "$cfg" "PEER_RESOLVE_FAIL"
+		exit
+	fi
+
+	for ip6 in $remoteip6; do
+		peer6addr=$ip6
+		break
+	done
+
+	( proto_add_host_dependency "$cfg" "$peer6addr" "$tunlink" )
+
+	[ -z "$ip6addr" ] && {
+		local wanif="$tunlink"
+		if [ -z $wanif ] && ! network_find_wan6 wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			exit
+		fi
+
+		if ! network_get_ipaddr6 ip6addr "$wanif"; then
+			[ -z "$weakif" ] && weakif="lan"
+			if ! network_get_ipaddr6 ip6addr "$weakif"; then
+				proto_notify_error "$cfg" "NO_WAN_LINK"
+				exit
+			fi
+		fi
+	}
+
+	gre_generic_setup $cfg $mode $ip6addr $peer6addr "grev6-$cfg"
+}
+
+proto_grev6_setup() {
+	local cfg="$1"
+
+	grev6_setup $cfg "greip6"
+}
+
+proto_grev6tap_setup() {
+	local cfg="$1"
+
+	local network
+	json_get_vars network
+
+	grev6_setup $cfg "gretapip6"
+
+	json_init
+	json_add_string name "grev6-$cfg"
+	json_add_boolean link-ext 0
+	json_close_object
+
+	for i in $network; do
+		ubus call network.interface."$i" add_device "$(json_dump)"
+	done
+}
+
+gretap_generic_teardown() {
+	local network
+	json_get_vars network
+
+	json_init
+	json_add_string name "$1"
+	json_add_boolean link-ext 0
+	json_close_object
+
+	for i in $network; do
+		ubus call network.interface."$i" remove_device "$(json_dump)"
+	done
+}
+
+proto_gre_teardown() {
+	local cfg="$1"
+}
+
+proto_gretap_teardown() {
+	local cfg="$1"
+
+	gretap_generic_teardown "gre-$cfg"
+}
+
+proto_grev6_teardown() {
+	local cfg="$1"
+}
+
+proto_grev6tap_teardown() {
+	local cfg="$1"
+
+	gretap_generic_teardown "grev6-$cfg"
+}
+
+gre_generic_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_int "mtu"
+	proto_config_add_int "ttl"
+	proto_config_add_string "tos"
+	proto_config_add_string "tunlink"
+	proto_config_add_string "zone"
+	proto_config_add_int "ikey"
+	proto_config_add_int "okey"
+	proto_config_add_boolean "icsum"
+	proto_config_add_boolean "ocsum"
+	proto_config_add_boolean "iseqno"
+	proto_config_add_boolean "oseqno"
+	proto_config_add_boolean "multicast"
+}
+
+proto_gre_init_config() {
+	gre_generic_init_config
+	proto_config_add_string "ipaddr"
+	proto_config_add_string "peeraddr"
+	proto_config_add_boolean "df"
+}
+
+proto_gretap_init_config() {
+	proto_gre_init_config
+	proto_config_add_string "network"
+}
+
+proto_grev6_init_config() {
+	gre_generic_init_config
+	proto_config_add_string "ip6addr"
+	proto_config_add_string "peer6addr"
+	proto_config_add_string "weakif"
+}
+
+proto_grev6tap_init_config() {
+	proto_grev6_init_config
+	proto_config_add_string "network"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	[ -f /lib/modules/$(uname -r)/gre.ko ] && add_protocol gre
+	[ -f /lib/modules/$(uname -r)/gre.ko ] && add_protocol gretap
+	[ -f /lib/modules/$(uname -r)/ip6_gre.ko ] && add_protocol grev6
+	[ -f /lib/modules/$(uname -r)/ip6_gre.ko ] && add_protocol grev6tap
+}
diff --git a/package/network/config/ipip/Makefile b/package/network/config/ipip/Makefile
new file mode 100644
index 0000000000..9bdb13c6bc
--- /dev/null
+++ b/package/network/config/ipip/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ipip
+PKG_VERSION:=1
+PKG_RELEASE:=2
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ipip
+  SECTION:=net
+  CATEGORY:=Network
+  MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
+  TITLE:=IP in IP Tunnel config support
+  DEPENDS:= +kmod-ipip +resolveip
+endef
+
+define Package/ipip/description
+ IP in IP Tunnel config support in /etc/config/network.
+endef
+
+define Build/Compile
+endef
+
+define Build/Configure
+endef
+
+define Package/ipip/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/ipip.sh $(1)/lib/netifd/proto/ipip.sh
+endef
+
+$(eval $(call BuildPackage,ipip))
diff --git a/package/network/config/ipip/files/ipip.sh b/package/network/config/ipip/files/ipip.sh
new file mode 100755
index 0000000000..f1c94d6eed
--- /dev/null
+++ b/package/network/config/ipip/files/ipip.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_ipip_setup() {
+	local cfg="$1"
+	local remoteip
+
+	local df ipaddr peeraddr tunlink ttl tos zone mtu
+	json_get_vars df ipaddr peeraddr tunlink ttl tos zone mtu
+
+	[ -z "$peeraddr" ] && {
+		proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
+		proto_block_restart "$cfg"
+		return
+	}
+
+	remoteip=$(resolveip -t 10 -4 "$peeraddr")
+
+	if [ -z "$remoteip" ]; then
+		proto_notify_error "$cfg" "PEER_RESOLVE_FAIL"
+		return
+	fi
+
+	for ip in $remoteip; do
+		peeraddr=$ip
+		break
+	done
+
+	( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+
+	[ -z "$ipaddr" ] && {
+		local wanif="$tunlink"
+		if [ -z $wanif ] && ! network_find_wan wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+
+		if ! network_get_ipaddr ipaddr "$wanif"; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+	}
+
+	[ -z "$zone" ] && zone="wan"
+
+	proto_init_update "ipip-$cfg" 1
+
+	proto_add_tunnel
+	json_add_string mode "ipip"
+	json_add_int mtu "${mtu:-1280}"
+	json_add_int ttl "${ttl:-64}"
+	[ -n "$tos" ] && json_add_string tos "$tos"
+	json_add_string local "$ipaddr"
+	json_add_string remote "$peeraddr"
+	[ -n "$tunlink" ] && json_add_string link "$tunlink"
+	json_add_boolean df "${df:-1}"
+
+	proto_close_tunnel
+
+	proto_add_data
+	[ -n "$zone" ] && json_add_string zone "$zone"
+	proto_close_data
+
+	proto_send_update "$cfg"
+}
+
+proto_ipip_teardown() {
+	local cfg="$1"
+}
+
+proto_ipip_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_int "mtu"
+	proto_config_add_int "ttl"
+	proto_config_add_string "tos"
+	proto_config_add_string "tunlink"
+	proto_config_add_string "zone"
+	proto_config_add_string "ipaddr"
+	proto_config_add_string "peeraddr"
+	proto_config_add_boolean "df"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol ipip
+}
diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile
new file mode 100644
index 0000000000..0261bf3575
--- /dev/null
+++ b/package/network/config/netifd/Makefile
@@ -0,0 +1,45 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=netifd
+PKG_VERSION:=2016-11-21
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/netifd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=153a12143b9fef4b5d3c3a6597f6fe967a17c9d7
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=5d4126e26a88102bc06d36564b204a989a42a1e4aadf6b2776e123fd3f8883f7
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/netifd
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox
+  TITLE:=OpenWrt Network Interface Configuration Daemon
+endef
+
+TARGET_CFLAGS += \
+	-I$(STAGING_DIR)/usr/include/libnl-tiny \
+	-I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS += \
+	-DLIBNL_LIBS=-lnl-tiny \
+	-DDEBUG=1
+
+define Package/netifd/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/netifd $(1)/sbin/
+	$(CP) ./files/* $(1)/
+	$(CP) $(PKG_BUILD_DIR)/scripts/* $(1)/lib/netifd/
+endef
+
+$(eval $(call BuildPackage,netifd))
diff --git a/package/network/config/netifd/files/etc/hotplug.d/iface/00-netstate b/package/network/config/netifd/files/etc/hotplug.d/iface/00-netstate
new file mode 100644
index 0000000000..023025cd1a
--- /dev/null
+++ b/package/network/config/netifd/files/etc/hotplug.d/iface/00-netstate
@@ -0,0 +1,7 @@
+[ ifup = "$ACTION" ] && {
+	uci_toggle_state network "$INTERFACE" up 1
+	[ -n "$DEVICE" ] && {
+		uci_toggle_state network "$INTERFACE" device "$(uci -q get network.$INTERFACE.ifname)"
+		uci_toggle_state network "$INTERFACE" ifname "$DEVICE"
+	}
+}
diff --git a/package/network/config/netifd/files/etc/init.d/network b/package/network/config/netifd/files/etc/init.d/network
new file mode 100755
index 0000000000..bdadbbce6d
--- /dev/null
+++ b/package/network/config/netifd/files/etc/init.d/network
@@ -0,0 +1,151 @@
+#!/bin/sh /etc/rc.common
+
+START=20
+STOP=90
+
+USE_PROCD=1
+
+init_switch() {
+	setup_switch() { return 0; }
+
+	include /lib/network
+	setup_switch
+}
+
+start_service() {
+	init_switch
+
+	procd_open_instance
+	procd_set_param command /sbin/netifd
+	procd_set_param respawn
+	procd_set_param watch network.interface
+	[ -e /proc/sys/kernel/core_pattern ] && {
+		procd_set_param limits core="unlimited"
+	}
+	procd_close_instance
+}
+
+reload_service() {
+	init_switch
+	ubus call network reload
+	/sbin/wifi reload_legacy
+}
+
+stop() {
+	/sbin/wifi down
+	procd_kill network ''
+}
+
+service_running() {
+	ubus -t 30 wait_for network.interface
+	/sbin/wifi reload_legacy
+}
+
+validate_atm_bridge_section()
+{
+	uci_validate_section network "atm-bridge" "${1}" \
+		'unit:uinteger:0' \
+		'vci:range(32, 65535):35' \
+		'vpi:range(0, 255):8' \
+		'atmdev:uinteger:0' \
+		'encaps:or("llc", "vc"):llc' \
+		'payload:or("bridged", "routed"):bridged'
+}
+
+validate_route_section()
+{
+	uci_validate_section network route "${1}" \
+		'interface:string' \
+		'target:cidr4' \
+		'netmask:netmask4' \
+		'gateway:ip4addr' \
+		'metric:uinteger' \
+		'mtu:uinteger' \
+		'table:or(range(0,65535),string)'
+}
+
+validate_route6_section()
+{
+	uci_validate_section network route6 "${1}" \
+		'interface:string' \
+		'target:cidr6' \
+		'gateway:ip6addr' \
+		'metric:uinteger' \
+		'mtu:uinteger' \
+		'table:or(range(0,65535),string)'
+}
+
+validate_rule_section()
+{
+	uci_validate_section network rule "${1}" \
+		'in:string' \
+		'out:string' \
+		'src:cidr4' \
+		'dest:cidr4' \
+		'tos:range(0,31)' \
+		'mark:string' \
+		'invert:bool' \
+		'lookup:or(range(0,65535),string)' \
+		'goto:range(0,65535)' \
+		'action:or("prohibit", "unreachable", "blackhole", "throw")'
+}
+
+validate_rule6_section()
+{
+	uci_validate_section network rule6 "${1}" \
+		'in:string' \
+		'out:string' \
+		'src:cidr6' \
+		'dest:cidr6' \
+		'tos:range(0,31)' \
+		'mark:string' \
+		'invert:bool' \
+		'lookup:or(range(0,65535),string)' \
+		'goto:range(0,65535)' \
+		'action:or("prohibit", "unreachable", "blackhole", "throw")'
+}
+
+validate_switch_section()
+{
+	uci_validate_section network switch "${1}" \
+		'name:string' \
+		'enable:bool' \
+		'enable_vlan:bool' \
+		'reset:bool'
+}
+
+validate_switch_vlan()
+{
+	uci_validate_section network switch_vlan "${1}" \
+		'device:string' \
+		'vlan:uinteger' \
+		'ports:list(ports)'
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger network wireless
+
+	procd_open_validate
+	validate_atm_bridge_section
+	validate_route_section
+	validate_route6_section
+	validate_rule_section
+	validate_rule6_section
+	validate_switch_section
+	validate_switch_vlan
+	procd_close_validate
+}
+
+restart() {
+	ifdown -a
+	sleep 1
+	trap '' TERM
+	stop "$@"
+	start "$@"
+}
+
+shutdown() {
+	ifdown -a
+	sleep 1
+}
diff --git a/package/network/config/netifd/files/lib/netifd/dhcp.script b/package/network/config/netifd/files/lib/netifd/dhcp.script
new file mode 100755
index 0000000000..b3a61e2750
--- /dev/null
+++ b/package/network/config/netifd/files/lib/netifd/dhcp.script
@@ -0,0 +1,102 @@
+#!/bin/sh
+[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1
+
+. /lib/functions.sh
+. /lib/netifd/netifd-proto.sh
+
+set_classless_routes() {
+	local max=128
+	while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do
+		proto_add_ipv4_route "${1%%/*}" "${1##*/}" "$2" "$ip"
+		max=$(($max-1))
+		shift 2
+	done
+}
+
+setup_interface () {
+	proto_init_update "*" 1
+	proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
+	# TODO: apply $broadcast
+
+	for i in $router; do
+		proto_add_ipv4_route "$i" 32 "" "$ip"
+		proto_add_ipv4_route 0.0.0.0 0 "$i" "$ip"
+
+		for r in $CUSTOMROUTES; do
+			proto_add_ipv4_route "${r%%/*}" "${r##*/}" "$i" "$ip"
+		done
+	done
+
+	# CIDR STATIC ROUTES (rfc3442)
+	[ -n "$staticroutes" ] && set_classless_routes $staticroutes
+	[ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes
+
+	for dns in $dns; do
+		proto_add_dns_server "$dns"
+	done
+	for domain in $domain; do
+		proto_add_dns_search "$domain"
+	done
+
+	proto_add_data
+	[ -n "$ZONE" ]     && json_add_string zone "$ZONE"
+	[ -n "$ntpsrv" ]   && json_add_string ntpserver "$ntpsrv"
+	[ -n "$timesvr" ]  && json_add_string timeserver "$timesvr"
+	[ -n "$hostname" ] && json_add_string hostname "$hostname"
+	[ -n "$message" ]  && json_add_string message "$message"
+	[ -n "$timezone" ] && json_add_int timezone "$timezone"
+	[ -n "$lease" ]    && json_add_int leasetime "$lease"
+	proto_close_data
+
+	proto_send_update "$INTERFACE"
+
+
+	if [ "$IFACE6RD" != 0 -a -n "$ip6rd" ]; then
+		local v4mask="${ip6rd%% *}"
+		ip6rd="${ip6rd#* }"
+		local ip6rdprefixlen="${ip6rd%% *}"
+		ip6rd="${ip6rd#* }"
+		local ip6rdprefix="${ip6rd%% *}"
+		ip6rd="${ip6rd#* }"
+		local ip6rdbr="${ip6rd%% *}"
+
+		[ -n "$ZONE" ] || ZONE=$(fw3 -q network $INTERFACE)
+		[ -z "$IFACE6RD" -o "$IFACE6RD" = 1 ] && IFACE6RD=${INTERFACE}_6
+
+		json_init
+		json_add_string name "$IFACE6RD"
+		json_add_string ifname "@$INTERFACE"
+		json_add_string proto "6rd"
+		json_add_string peeraddr "$ip6rdbr"
+		json_add_int ip4prefixlen "$v4mask"
+		json_add_string ip6prefix "$ip6rdprefix"
+		json_add_int ip6prefixlen "$ip6rdprefixlen"
+		json_add_string tunlink "$INTERFACE"
+		[ -n "$IFACE6RD_DELEGATE" ] && json_add_boolean delegate "$IFACE6RD_DELEGATE"
+		[ -n "$ZONE6RD" ] || ZONE6RD=$ZONE
+		[ -n "$ZONE6RD" ] && json_add_string zone "$ZONE6RD"
+		[ -n "$MTU6RD" ] && json_add_string mtu "$MTU6RD"
+		json_close_object
+
+		ubus call network add_dynamic "$(json_dump)"
+	fi
+}
+
+deconfig_interface() {
+	proto_init_update "*" 0
+	proto_send_update "$INTERFACE"
+}
+
+case "$1" in
+	deconfig)
+		deconfig_interface
+	;;
+	renew|bound)
+		setup_interface
+	;;
+esac
+
+# user rules
+[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user "$@"
+
+exit 0
diff --git a/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
new file mode 100755
index 0000000000..ea02d68bb4
--- /dev/null
+++ b/package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. ../netifd-proto.sh
+init_proto "$@"
+
+proto_dhcp_init_config() {
+	renew_handler=1
+
+	proto_config_add_string 'ipaddr:ipaddr'
+	proto_config_add_string 'hostname:hostname'
+	proto_config_add_string clientid
+	proto_config_add_string vendorid
+	proto_config_add_boolean 'broadcast:bool'
+	proto_config_add_boolean 'release:bool'
+	proto_config_add_string 'reqopts:list(string)'
+	proto_config_add_string iface6rd
+	proto_config_add_string sendopts
+	proto_config_add_boolean delegate
+	proto_config_add_string zone6rd
+	proto_config_add_string zone
+	proto_config_add_string mtu6rd
+	proto_config_add_string customroutes
+	proto_config_add_boolean classlessroute
+}
+
+proto_dhcp_setup() {
+	local config="$1"
+	local iface="$2"
+
+	local ipaddr hostname clientid vendorid broadcast release reqopts iface6rd sendopts delegate zone6rd zone mtu6rd customroutes classlessroute
+	json_get_vars ipaddr hostname clientid vendorid broadcast release reqopts iface6rd sendopts delegate zone6rd zone mtu6rd customroutes classlessroute
+
+	local opt dhcpopts
+	for opt in $reqopts; do
+		append dhcpopts "-O $opt"
+	done
+
+	for opt in $sendopts; do
+		append dhcpopts "-x $opt"
+	done
+
+	[ "$broadcast" = 1 ] && broadcast="-B" || broadcast=
+	[ "$release" = 1 ] && release="-R" || release=
+	[ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}" || clientid="-C"
+	[ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd"
+	[ "$iface6rd" != 0 -a -f /lib/netifd/proto/6rd.sh ] && append dhcpopts "-O 212"
+	[ -n "$zone6rd" ] && proto_export "ZONE6RD=$zone6rd"
+	[ -n "$zone" ] && proto_export "ZONE=$zone"
+	[ -n "$mtu6rd" ] && proto_export "MTU6RD=$mtu6rd"
+	[ -n "$customroutes" ] && proto_export "CUSTOMROUTES=$customroutes"
+	[ "$delegate" = "0" ] && proto_export "IFACE6RD_DELEGATE=0"
+	# Request classless route option (see RFC 3442) by default
+	[ "$classlessroute" = "0" ] || append dhcpopts "-O 121"
+
+	proto_export "INTERFACE=$config"
+	proto_run_command "$config" udhcpc \
+		-p /var/run/udhcpc-$iface.pid \
+		-s /lib/netifd/dhcp.script \
+		-f -t 0 -i "$iface" \
+		${ipaddr:+-r $ipaddr} \
+		${hostname:+-x "hostname:$hostname"} \
+		${vendorid:+-V "$vendorid"} \
+		$clientid $broadcast $release $dhcpopts
+}
+
+proto_dhcp_renew() {
+	local interface="$1"
+	# SIGUSR1 forces udhcpc to renew its lease
+	local sigusr1="$(kill -l SIGUSR1)"
+	[ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1
+}
+
+proto_dhcp_teardown() {
+	local interface="$1"
+	proto_kill_command "$interface"
+}
+
+add_protocol dhcp
diff --git a/package/network/config/netifd/files/lib/network/config.sh b/package/network/config/netifd/files/lib/network/config.sh
new file mode 100755
index 0000000000..9128971dab
--- /dev/null
+++ b/package/network/config/netifd/files/lib/network/config.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+# Copyright (C) 2011 OpenWrt.org
+
+. /usr/share/libubox/jshn.sh
+
+find_config() {
+	local device="$1"
+	local ifdev ifl3dev ifobj
+	for ifobj in `ubus list network.interface.\*`; do
+		interface="${ifobj##network.interface.}"
+		(
+			json_load "$(ifstatus $interface)"
+			json_get_var ifdev device
+			json_get_var ifl3dev l3_device
+			if [[ "$device" = "$ifdev" ]] || [[ "$device" = "$ifl3dev" ]]; then
+				echo "$interface"
+				exit 0
+			else
+				exit 1
+			fi
+		) && return
+	done
+}
+
+unbridge() {
+	return
+}
+
+ubus_call() {
+	json_init
+	local _data="$(ubus -S call "$1" "$2")"
+	[ -z "$_data" ] && return 1
+	json_load "$_data"
+	return 0
+}
+
+
+fixup_interface() {
+	local config="$1"
+	local ifname type device l3dev
+
+	config_get type "$config" type
+	config_get ifname "$config" ifname
+	config_get device "$config" device "$ifname"
+	[ "bridge" = "$type" ] && ifname="br-$config"
+	config_set "$config" device "$ifname"
+	ubus_call "network.interface.$config" status || return 0
+	json_get_var l3dev l3_device
+	[ -n "$l3dev" ] && ifname="$l3dev"
+	json_init
+	config_set "$config" ifname "$ifname"
+	config_set "$config" device "$device"
+}
+
+scan_interfaces() {
+	config_load network
+	config_foreach fixup_interface interface
+}
+
+prepare_interface_bridge() {
+	local config="$1"
+
+	[ -n "$config" ] || return 0
+	ubus call network.interface."$config" prepare
+}
+
+setup_interface() {
+	local iface="$1"
+	local config="$2"
+
+	[ -n "$config" ] || return 0
+	ubus call network.interface."$config" add_device "{ \"name\": \"$iface\" }"
+}
+
+do_sysctl() {
+	[ -n "$2" ] && \
+		sysctl -n -e -w "$1=$2" >/dev/null || \
+		sysctl -n -e "$1"
+}
diff --git a/package/network/config/netifd/files/sbin/devstatus b/package/network/config/netifd/files/sbin/devstatus
new file mode 100755
index 0000000000..3c35b26a41
--- /dev/null
+++ b/package/network/config/netifd/files/sbin/devstatus
@@ -0,0 +1,12 @@
+#!/bin/sh
+. /usr/share/libubox/jshn.sh
+DEVICE="$1"
+
+[ -n "$DEVICE" ] || {
+	echo "Usage: $0 <device>"
+	exit 1
+}
+
+json_init
+json_add_string name "$DEVICE"
+ubus call network.device status "$(json_dump)"
diff --git a/package/network/config/netifd/files/sbin/ifdown b/package/network/config/netifd/files/sbin/ifdown
new file mode 120000
index 0000000000..a0e5c176a3
--- /dev/null
+++ b/package/network/config/netifd/files/sbin/ifdown
@@ -0,0 +1 @@
+ifup
\ No newline at end of file
diff --git a/package/network/config/netifd/files/sbin/ifstatus b/package/network/config/netifd/files/sbin/ifstatus
new file mode 100755
index 0000000000..8a951e6e15
--- /dev/null
+++ b/package/network/config/netifd/files/sbin/ifstatus
@@ -0,0 +1,13 @@
+#!/bin/sh
+INTERFACE="$1"
+
+[ -n "$INTERFACE" ] || {
+	echo "Usage: $0 <interface>"
+	exit 1
+}
+
+ubus -S list "network.interface.$INTERFACE" >/dev/null || {
+	echo "Interface $INTERFACE not found"
+	exit 1
+}
+ubus call network.interface status "{ \"interface\" : \"$INTERFACE\" }"
diff --git a/package/network/config/netifd/files/sbin/ifup b/package/network/config/netifd/files/sbin/ifup
new file mode 100755
index 0000000000..5515b91f76
--- /dev/null
+++ b/package/network/config/netifd/files/sbin/ifup
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+ifup_all=
+setup_wifi=
+
+if_call() {
+	local interface="$1"
+	for mode in $modes; do
+		ubus call network.interface $mode "{ \"interface\" : \"$interface\" }"
+	done
+}
+
+case "$0" in
+	*ifdown) modes=down;;
+	*ifup)
+		modes="down up"
+		setup_wifi=1
+	;;
+	*) echo "Invalid command: $0";;
+esac
+
+while :; do
+	case "$1" in
+		-a)
+			ifup_all=1
+			shift
+		;;
+		-w)
+			setup_wifi=
+			shift
+		;;
+		*)
+			break
+		;;
+	esac
+done
+
+[ "$modes" = "down up" ] && ubus call network reload
+if [ -n "$ifup_all" ]; then
+	for interface in `ubus -S list 'network.interface.*'`; do
+		if_call "${interface##network.interface.}"
+	done
+	[ -n "$setup_wifi" ] && /sbin/wifi up
+	exit
+else
+	ubus -S list "network.interface.$1" > /dev/null || {
+		echo "Interface $1 not found"
+		exit
+	}
+	if_call "$1"
+fi
+
+if [ -n "$setup_wifi" ] && grep -sq config /etc/config/wireless; then
+	. /lib/functions.sh
+
+	find_related_radios() {
+		local wdev wnet
+		config_get wdev "$1" device
+		config_get wnet "$1" network
+
+		if [ -n "$wdev" ]; then
+			for wnet in $wnet; do
+				if [ "$wnet" = "$network" ]; then
+					append radio_devs "$wdev" "$N"
+				fi
+			done
+		fi
+	}
+
+	network="$1"
+	config_load wireless
+	config_foreach find_related_radios wifi-iface
+
+	for dev in $(echo "$radio_devs" | sort -u); do
+		/sbin/wifi up "$dev"
+	done
+fi
diff --git a/package/network/config/netifd/files/usr/share/udhcpc/default.script b/package/network/config/netifd/files/usr/share/udhcpc/default.script
new file mode 100755
index 0000000000..ac765a6363
--- /dev/null
+++ b/package/network/config/netifd/files/usr/share/udhcpc/default.script
@@ -0,0 +1,57 @@
+#!/bin/sh
+[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1
+
+set_classless_routes() {
+	local max=128
+	local type
+	while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do
+		[ ${1##*/} -eq 32 ] && type=host || type=net
+		echo "udhcpc: adding route for $type $1 via $2"
+		route add -$type "$1" gw "$2" dev "$interface"
+		max=$(($max-1))
+		shift 2
+	done
+}
+
+setup_interface() {
+	echo "udhcpc: ifconfig $interface $ip netmask ${subnet:-255.255.255.0} broadcast ${broadcast:-+}"
+	ifconfig $interface $ip netmask ${subnet:-255.255.255.0} broadcast ${broadcast:-+}
+
+	[ -n "$router" ] && [ "$router" != "0.0.0.0" ] && [ "$router" != "255.255.255.255" ] && {
+		echo "udhcpc: setting default routers: $router"
+
+		local valid_gw=""
+		for i in $router ; do
+			route add default gw $i dev $interface
+			valid_gw="${valid_gw:+$valid_gw|}$i"
+		done
+		
+		eval $(route -n | awk '
+			/^0.0.0.0\W{9}('$valid_gw')\W/ {next}
+			/^0.0.0.0/ {print "route del -net "$1" gw "$2";"}
+		')
+	}
+
+	# CIDR STATIC ROUTES (rfc3442)
+	[ -n "$staticroutes" ] && set_classless_routes $staticroutes
+	[ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes
+}
+
+
+applied=
+case "$1" in
+	deconfig)
+		ifconfig "$interface" 0.0.0.0
+	;;
+	renew)
+		setup_interface update
+	;;
+	bound)
+		setup_interface ifup
+	;;
+esac
+
+# user rules
+[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user
+
+exit 0
diff --git a/package/network/config/qos-scripts/Makefile b/package/network/config/qos-scripts/Makefile
new file mode 100644
index 0000000000..1b43ba1d30
--- /dev/null
+++ b/package/network/config/qos-scripts/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=qos-scripts
+PKG_VERSION:=1.3.0
+PKG_RELEASE:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/qos-scripts
+  SECTION:=utils
+  CATEGORY:=Base system
+  DEPENDS:=+tc +kmod-sched-core +kmod-sched-connmark +kmod-ifb +iptables +iptables-mod-ipopt +iptables-mod-conntrack-extra
+  TITLE:=QoS scripts
+  PKGARCH:=all
+endef
+
+define Package/qos-scripts/description
+ A set of scripts that abstract QoS configuration into a simple 
+ configuration file supporting stanzas that specify any number of QoS 
+ entries.
+endef
+
+define Package/qos-scripts/conffiles
+/etc/config/qos
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/qos-scripts/install
+	$(INSTALL_DIR) $(1)
+	$(CP) ./files/* $(1)/
+endef
+
+$(eval $(call BuildPackage,qos-scripts))
diff --git a/package/network/config/qos-scripts/files/etc/config/qos b/package/network/config/qos-scripts/files/etc/config/qos
new file mode 100644
index 0000000000..44e988a67a
--- /dev/null
+++ b/package/network/config/qos-scripts/files/etc/config/qos
@@ -0,0 +1,68 @@
+# QoS configuration for OpenWrt
+
+# INTERFACES:
+config interface wan
+	option classgroup  "Default"
+	option enabled      0
+	option upload       128
+	option download     1024
+
+# RULES:
+config classify
+	option target       "Priority"
+	option ports        "22,53"
+	option comment      "ssh, dns"
+config classify
+	option target       "Normal"
+	option proto        "tcp"
+	option ports        "20,21,25,80,110,443,993,995"
+	option comment      "ftp, smtp, http(s), imap"
+config classify
+	option target       "Express"
+	option ports        "5190"
+	option comment      "AOL, iChat, ICQ"
+config default
+	option target       "Express"
+	option proto        "udp"
+	option pktsize      "-500"
+config reclassify
+	option target       "Priority"
+	option proto        "icmp"
+config default
+	option target       "Bulk"
+	option portrange    "1024-65535"
+
+
+# Don't change the stuff below unless you
+# really know what it means :)
+
+config classgroup "Default"
+	option classes      "Priority Express Normal Bulk"
+	option default      "Normal"
+
+
+config class "Priority"
+	option packetsize  400
+	option avgrate     10
+	option priority    20
+config class "Priority_down"
+	option packetsize  1000
+	option avgrate     10
+
+
+config class "Express"
+	option packetsize  1000
+	option avgrate     50
+	option priority    10
+
+config class "Normal"
+	option packetsize  1500
+	option packetdelay 100
+	option avgrate     10
+	option priority    5
+config class "Normal_down"
+	option avgrate     20
+
+config class "Bulk"
+	option avgrate     1
+	option packetdelay 200
diff --git a/package/network/config/qos-scripts/files/etc/hotplug.d/iface/10-qos b/package/network/config/qos-scripts/files/etc/hotplug.d/iface/10-qos
new file mode 100755
index 0000000000..0ced29ac7e
--- /dev/null
+++ b/package/network/config/qos-scripts/files/etc/hotplug.d/iface/10-qos
@@ -0,0 +1,2 @@
+#!/bin/sh
+[ "$ACTION" = ifup ] && /etc/init.d/qos enabled && /usr/lib/qos/generate.sh interface "$INTERFACE" | sh
diff --git a/package/network/config/qos-scripts/files/etc/init.d/qos b/package/network/config/qos-scripts/files/etc/init.d/qos
new file mode 100755
index 0000000000..712d906f03
--- /dev/null
+++ b/package/network/config/qos-scripts/files/etc/init.d/qos
@@ -0,0 +1,28 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+START=50
+USE_PROCD=1
+
+validate_qos_section()
+{
+	uci_validate_section qos interface "${1}" \
+		'enabled:bool' \
+		'upload:uinteger' \
+		'download:uinteger'
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "qos"
+	procd_add_validation validate_qos_section
+	qos-start
+}
+
+start_service() {
+	qos-start
+}
+
+reload_service() {
+	qos-start
+}
diff --git a/package/network/config/qos-scripts/files/usr/bin/qos-start b/package/network/config/qos-scripts/files/usr/bin/qos-start
new file mode 100755
index 0000000000..261ffb42b0
--- /dev/null
+++ b/package/network/config/qos-scripts/files/usr/bin/qos-start
@@ -0,0 +1,4 @@
+#!/bin/sh
+qos-stop 
+/usr/lib/qos/generate.sh all | sh
+
diff --git a/package/network/config/qos-scripts/files/usr/bin/qos-stat b/package/network/config/qos-scripts/files/usr/bin/qos-stat
new file mode 100755
index 0000000000..cbbf8e8de8
--- /dev/null
+++ b/package/network/config/qos-scripts/files/usr/bin/qos-stat
@@ -0,0 +1,67 @@
+#!/bin/sh
+# Copyright (C) 2011 OpenWrt.org
+
+. /lib/functions.sh
+
+include /lib/network
+
+get_ifname() {
+	local interface="$1"
+	local cfgt
+
+	scan_interfaces
+	config_get cfgt "$interface" TYPE
+	[ "$cfgt" = "interface" ] && config_get "$interface" ifname
+}
+
+config_cb() {
+	config_get TYPE "$CONFIG_SECTION" TYPE
+	[ "interface" = "$TYPE" ] && {
+		config_get device "$CONFIG_SECTION" ifname
+		[ -z "$device" ] && device="$(get_ifname ${CONFIG_SECTION})"
+		config_set "$CONFIG_SECTION" device "$device"
+	}
+}
+
+config_load qos
+
+print_comments() {
+	echo ''
+	echo '# Interface: '"$1"
+	echo '# Direction: '"$2"
+	echo '# Stats:     '"$3"
+	echo ''
+}	
+
+get_device() {
+	( config_load network; scan_interfaces; config_get "$1" ifname )
+}
+
+interface_stats() {
+	local interface="$1"
+	local device
+
+	device="$(get_device "$interface")"
+	[ -z "$device" ] && config_get device "$interface" device
+	config_get_bool enabled "$interface" enabled 1
+	[ -z "$device" -o 1 -ne "$enabled" ] && {
+		return 1
+	}
+	config_get_bool halfduplex "$interface" halfduplex 0
+
+	if [ 1 -ne "$halfduplex" ]; then
+		unset halfduplex
+		print_comments "$interface" "Egress" "Start"
+		tc -s class show dev "$device"
+		print_comments "$interface" "Egress" "End"
+		id="root"
+	else
+		id=""
+	fi
+
+	print_comments "$interface" "Ingress${halfduplex:+/Egress}" "Start"
+	tc -s class show dev "$(tc filter show dev $device $id | grep mirred | sed -e 's,.*\(ifb.*\)).*,\1,')"
+	print_comments "$interface" "Ingress${halfduplex:+/Egress}" "End"
+}
+
+[ -z "$1" ] && config_foreach interface_stats interface || interface_stats "$1"
diff --git a/package/network/config/qos-scripts/files/usr/bin/qos-stop b/package/network/config/qos-scripts/files/usr/bin/qos-stop
new file mode 100755
index 0000000000..7f654d8587
--- /dev/null
+++ b/package/network/config/qos-scripts/files/usr/bin/qos-stop
@@ -0,0 +1,6 @@
+#!/bin/sh
+for iface in $(tc qdisc show | grep -E '(hfsc|ingress)' | awk '{print $5}'); do
+	tc qdisc del dev "$iface" ingress 2>&- >&-
+	tc qdisc del dev "$iface" root 2>&- >&-
+done
+/usr/lib/qos/generate.sh firewall stop | sh
diff --git a/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh b/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
new file mode 100755
index 0000000000..285617c0d7
--- /dev/null
+++ b/package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
@@ -0,0 +1,538 @@
+#!/bin/sh
+[ -e /lib/functions.sh ] && . /lib/functions.sh || . ./functions.sh
+[ -x /sbin/modprobe ] && {
+	insmod="modprobe"
+	rmmod="$insmod -r"
+} || {
+	insmod="insmod"
+	rmmod="rmmod"
+}
+
+add_insmod() {
+	eval "export isset=\${insmod_$1}"
+	case "$isset" in
+		1) ;;
+		*) {
+			[ "$2" ] && append INSMOD "$rmmod $1 >&- 2>&-" "$N"
+			append INSMOD "$insmod $* >&- 2>&-" "$N"; export insmod_$1=1
+		};;
+	esac
+}
+
+[ -e /etc/config/network ] && {
+	# only try to parse network config on openwrt
+
+	find_ifname() {(
+		reset_cb
+		include /lib/network
+		scan_interfaces
+		config_get "$1" ifname
+	)}
+} || {
+	find_ifname() {
+		echo "Interface not found."
+		exit 1
+	}
+}
+
+parse_matching_rule() {
+	local var="$1"
+	local section="$2"
+	local options="$3"
+	local prefix="$4"
+	local suffix="$5"
+	local proto="$6"
+	local mport=""
+	local ports=""
+
+	append "$var" "$prefix" "$N"
+	for option in $options; do
+		case "$option" in
+			proto) config_get value "$section" proto; proto="${proto:-$value}";;
+		esac
+	done
+	config_get type "$section" TYPE
+	case "$type" in
+		classify) unset pkt; append "$var" "-m mark --mark 0/0x0f";;
+		default) pkt=1; append "$var" "-m mark --mark 0/0xf0";;
+		reclassify) pkt=1;;
+	esac
+	append "$var" "${proto:+-p $proto}"
+	for option in $options; do
+		config_get value "$section" "$option"
+		
+		case "$pkt:$option" in
+			*:srchost)
+				append "$var" "-s $value"
+			;;
+			*:dsthost)
+				append "$var" "-d $value"
+			;;
+			*:ports|*:srcports|*:dstports)
+				value="$(echo "$value" | sed -e 's,-,:,g')"
+				lproto=${lproto:-tcp}
+				case "$proto" in
+					""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} -m multiport";;
+					*) unset "$var"; return 0;;
+				esac
+				case "$option" in
+					ports)
+						config_set "$section" srcports ""
+						config_set "$section" dstports ""
+						config_set "$section" portrange ""
+						append "$var" "--ports $value"
+					;;
+					srcports)
+						config_set "$section" ports ""
+						config_set "$section" dstports ""
+						config_set "$section" portrange ""
+						append "$var" "--sports $value"
+					;;
+					dstports)
+						config_set "$section" ports ""
+						config_set "$section" srcports ""
+						config_set "$section" portrange ""
+						append "$var" "--dports $value"
+					;;
+				esac
+				ports=1
+			;;
+			*:portrange)
+				config_set "$section" ports ""
+				config_set "$section" srcports ""
+				config_set "$section" dstports ""
+				value="$(echo "$value" | sed -e 's,-,:,g')"
+				case "$proto" in
+					""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} --sport $value --dport $value";;
+					*) unset "$var"; return 0;;
+				esac
+				ports=1
+			;;
+			*:connbytes)
+				value="$(echo "$value" | sed -e 's,-,:,g')"
+				add_insmod xt_connbytes
+				append "$var" "-m connbytes --connbytes $value --connbytes-dir both --connbytes-mode bytes"
+			;;
+			*:comment)
+				add_insmod xt_comment
+				append "$var" "-m comment --comment '$value'"
+			;;
+			*:tos)
+                                add_insmod xt_dscp
+                                case "$value" in
+                                        !*) append "$var" "-m tos ! --tos $value";;
+                                        *) append "$var" "-m tos --tos $value"
+                                esac
+                        ;;
+			*:dscp)
+                                add_insmod xt_dscp
+				dscp_option="--dscp"
+                                [ -z "${value%%[EBCA]*}" ] && dscp_option="--dscp-class"
+				case "$value" in
+                                       	!*) append "$var" "-m dscp ! $dscp_option $value";;
+                                       	*) append "$var" "-m dscp $dscp_option $value"
+                                esac
+                        ;;
+			*:direction)
+				value="$(echo "$value" | sed -e 's,-,:,g')"
+				if [ "$value" = "out" ]; then
+					append "$var" "-o $device"
+				elif [ "$value" = "in" ]; then
+					append "$var" "-i $device"
+				fi
+			;;
+			*:srciface)
+				append "$var" "-i $value"
+			;;
+			1:pktsize)
+				value="$(echo "$value" | sed -e 's,-,:,g')"
+				add_insmod xt_length
+				append "$var" "-m length --length $value"
+			;;
+			1:limit)
+				add_insmod xt_limit
+				append "$var" "-m limit --limit $value"
+			;;
+			1:tcpflags)
+				case "$proto" in
+					tcp) append "$var" "-m tcp --tcp-flags ALL $value";;
+					*) unset $var; return 0;;
+				esac
+			;;
+			1:mark)
+				config_get class "${value##!}" classnr
+				[ -z "$class" ] && continue;
+				case "$value" in
+					!*) append "$var" "-m mark ! --mark $class/0x0f";;
+					*) append "$var" "-m mark --mark $class/0x0f";;
+				esac
+			;;
+			1:TOS)
+				add_insmod xt_DSCP
+				config_get TOS "$rule" 'TOS'
+				suffix="-j TOS --set-tos "${TOS:-"Normal-Service"}
+			;;
+			1:DSCP)
+				add_insmod xt_DSCP
+				config_get DSCP "$rule" 'DSCP'
+				[ -z "${DSCP%%[EBCA]*}" ] && set_value="--set-dscp-class $DSCP" \
+				|| set_value="--set-dscp $DSCP"
+				suffix="-j DSCP $set_value"
+			;;
+		esac
+	done
+	append "$var" "$suffix"
+	case "$ports:$proto" in
+		1:)	parse_matching_rule "$var" "$section" "$options" "$prefix" "$suffix" "udp";;
+	esac
+}
+
+config_cb() {
+	option_cb() {
+		return 0
+	}
+
+	# Section start
+	case "$1" in
+		interface)
+			config_set "$2" "classgroup" "Default"
+			config_set "$2" "upload" "128"
+		;;
+		classify|default|reclassify)
+			option_cb() {
+				append options "$1"
+			}
+		;;
+	esac
+
+    # Section end
+	config_get TYPE "$CONFIG_SECTION" TYPE
+	case "$TYPE" in
+		interface)
+			config_get_bool enabled "$CONFIG_SECTION" enabled 1
+			[ 1 -eq "$enabled" ] || return 0
+			config_get classgroup "$CONFIG_SECTION" classgroup
+			config_set "$CONFIG_SECTION" ifbdev "$C"
+			C=$(($C+1))
+			append INTERFACES "$CONFIG_SECTION"
+			config_set "$classgroup" enabled 1
+			config_get device "$CONFIG_SECTION" device
+			[ -z "$device" ] && {
+				device="$(find_ifname ${CONFIG_SECTION})"
+				config_set "$CONFIG_SECTION" device "$device"
+			}
+		;;
+		classgroup) append CG "$CONFIG_SECTION";;
+		classify|default|reclassify)
+			case "$TYPE" in
+				classify) var="ctrules";;
+				*) var="rules";;
+			esac
+			config_get target "$CONFIG_SECTION" target
+			config_set "$CONFIG_SECTION" options "$options"
+			append "$var" "$CONFIG_SECTION"
+			unset options
+		;;
+	esac
+}
+
+
+enum_classes() {
+	local c="0"
+	config_get classes "$1" classes
+	config_get default "$1" default
+	for class in $classes; do
+		c="$(($c + 1))"
+		config_set "${class}" classnr $c
+		case "$class" in
+			$default) class_default=$c;;
+		esac
+	done
+	class_default="${class_default:-$c}"
+}
+
+cls_var() {
+	local varname="$1"
+	local class="$2"
+	local name="$3"
+	local type="$4"
+	local default="$5"
+	local tmp tmp1 tmp2
+	config_get tmp1 "$class" "$name"
+	config_get tmp2 "${class}_${type}" "$name"
+	tmp="${tmp2:-$tmp1}"
+	tmp="${tmp:-$tmp2}"
+	export ${varname}="${tmp:-$default}"
+}
+
+tcrules() {
+	_dir=/usr/lib/qos
+	[ -e $_dir/tcrules.awk ] || _dir=.
+	echo "$cstr" | awk \
+		-v device="$dev" \
+		-v linespeed="$rate" \
+		-v direction="$dir" \
+		-f $_dir/tcrules.awk
+}
+
+start_interface() {
+	local iface="$1"
+	local num_ifb="$2"
+	config_get device "$iface" device
+	config_get_bool enabled "$iface" enabled 1
+	[ -z "$device" -o 1 -ne "$enabled" ] && {
+		return 1 
+	}
+	config_get upload "$iface" upload
+	config_get_bool halfduplex "$iface" halfduplex
+	config_get download "$iface" download
+	config_get classgroup "$iface" classgroup
+	config_get_bool overhead "$iface" overhead 0
+	
+	download="${download:-${halfduplex:+$upload}}"
+	enum_classes "$classgroup"
+	for dir in ${halfduplex:-up} ${download:+down}; do
+		case "$dir" in
+			up)
+				[ "$overhead" = 1 ] && upload=$(($upload * 98 / 100 - (15 * 128 / $upload)))
+				dev="$device"
+				rate="$upload"
+				dl_mode=""
+				prefix="cls"
+			;;
+			down)
+				[ "$(ls -d /proc/sys/net/ipv4/conf/ifb* 2>&- | wc -l)" -ne "$num_ifb" ] && add_insmod ifb numifbs="$num_ifb"
+				config_get ifbdev "$iface" ifbdev
+				[ "$overhead" = 1 ] && download=$(($download * 98 / 100 - (80 * 1024 / $download)))
+				dev="ifb$ifbdev"
+				rate="$download"
+				dl_mode=1
+				prefix="d_cls"
+			;;
+			*) continue;;
+		esac
+		cstr=
+		for class in $classes; do
+			cls_var pktsize "$class" packetsize $dir 1500
+			cls_var pktdelay "$class" packetdelay $dir 0
+			cls_var maxrate "$class" limitrate $dir 100
+			cls_var prio "$class" priority $dir 1
+			cls_var avgrate "$class" avgrate $dir 0
+			cls_var qdisc "$class" qdisc $dir ""
+			cls_var filter "$class" filter $dir ""
+			config_get classnr "$class" classnr
+			append cstr "$classnr:$prio:$avgrate:$pktsize:$pktdelay:$maxrate:$qdisc:$filter" "$N"
+		done
+		append ${prefix}q "$(tcrules)" "$N"
+		export dev_${dir}="ifconfig $dev up >&- 2>&-
+tc qdisc del dev $dev root >&- 2>&-
+tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0
+tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit"
+	done
+	[ -n "$download" ] && {
+		add_insmod cls_u32
+		add_insmod em_u32
+		add_insmod act_connmark
+		add_insmod act_mirred
+		add_insmod sch_ingress
+	}
+	if [ -n "$halfduplex" ]; then
+		export dev_up="tc qdisc del dev $device root >&- 2>&-
+tc qdisc add dev $device root handle 1: hfsc
+tc filter add dev $device parent 1: prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb$ifbdev"
+	elif [ -n "$download" ]; then
+		append dev_${dir} "tc qdisc del dev $device ingress >&- 2>&-
+tc qdisc add dev $device ingress
+tc filter add dev $device parent ffff: prio 1 u32 match u32 0 0 flowid 1:1 action connmark action mirred egress redirect dev ifb$ifbdev" "$N"
+	fi
+	add_insmod cls_fw
+	add_insmod sch_hfsc
+	add_insmod sch_fq_codel
+
+	cat <<EOF
+${INSMOD:+$INSMOD$N}${dev_up:+$dev_up
+$clsq
+}${ifbdev:+$dev_down
+$d_clsq
+$d_clsl
+$d_clsf
+}
+EOF
+	unset INSMOD clsq clsf clsl d_clsq d_clsl d_clsf dev_up dev_down
+}
+
+start_interfaces() {
+	local C="$1"
+	for iface in $INTERFACES; do
+		start_interface "$iface" "$C"
+	done
+}
+
+add_rules() {
+	local var="$1"
+	local rules="$2"
+	local prefix="$3"
+	
+	for rule in $rules; do
+		unset iptrule
+		config_get target "$rule" target
+		config_get target "$target" classnr
+		config_get options "$rule" options
+
+		## If we want to override the TOS field, let's clear the DSCP field first.
+		[ ! -z "$(echo $options | grep 'TOS')" ] && {
+			s_options=${options%%TOS}
+			add_insmod xt_DSCP
+			parse_matching_rule iptrule "$rule" "$s_options" "$prefix" "-j DSCP --set-dscp 0"
+			append "$var" "$iptrule" "$N"
+			unset iptrule
+		}
+
+		target=$(($target | ($target << 4)))
+		parse_matching_rule iptrule "$rule" "$options" "$prefix" "-j MARK --set-mark $target/0xff"
+		append "$var" "$iptrule" "$N"
+	done
+}
+
+start_cg() {
+	local cg="$1"
+	local iptrules
+	local pktrules
+	local sizerules
+	enum_classes "$cg"
+	for command in $iptables; do
+		add_rules iptrules "$ctrules" "$command -w -t mangle -A qos_${cg}_ct"
+	done
+	config_get classes "$cg" classes
+	for class in $classes; do
+		config_get mark "$class" classnr
+		config_get maxsize "$class" maxsize
+		[ -z "$maxsize" -o -z "$mark" ] || {
+			add_insmod xt_length
+			for command in $iptables; do
+				append pktrules "$command -w -t mangle -A qos_${cg} -m mark --mark $mark/0x0f -m length --length $maxsize: -j MARK --set-mark 0/0xff" "$N"
+			done
+		}
+	done
+	for command in $iptables; do
+		add_rules pktrules "$rules" "$command -w -t mangle -A qos_${cg}"
+	done
+	for iface in $INTERFACES; do
+		config_get classgroup "$iface" classgroup
+		config_get device "$iface" device
+		config_get ifbdev "$iface" ifbdev
+		config_get upload "$iface" upload
+		config_get download "$iface" download
+		config_get halfduplex "$iface" halfduplex
+		download="${download:-${halfduplex:+$upload}}"
+		for command in $iptables; do
+			append up "$command -w -t mangle -A OUTPUT -o $device -j qos_${cg}" "$N"
+			append up "$command -w -t mangle -A FORWARD -o $device -j qos_${cg}" "$N"
+		done
+	done
+	cat <<EOF
+$INSMOD
+EOF
+  
+for command in $iptables; do
+	cat <<EOF
+	$command -w -t mangle -N qos_${cg} 
+	$command -w -t mangle -N qos_${cg}_ct
+EOF
+done
+cat <<EOF
+	${iptrules:+${iptrules}${N}}
+EOF
+for command in $iptables; do
+	cat <<EOF
+	$command -w -t mangle -A qos_${cg}_ct -j CONNMARK --save-mark --mask 0xff
+	$command -w -t mangle -A qos_${cg} -j CONNMARK --restore-mark --mask 0x0f
+	$command -w -t mangle -A qos_${cg} -m mark --mark 0/0x0f -j qos_${cg}_ct
+EOF
+done
+cat <<EOF
+$pktrules
+EOF
+for command in $iptables; do
+	cat <<EOF
+	$command -w -t mangle -A qos_${cg} -j CONNMARK --save-mark --mask 0xff
+EOF
+done
+cat <<EOF
+$up$N${down:+${down}$N}
+EOF
+	unset INSMOD
+}
+
+start_firewall() {
+	add_insmod xt_multiport
+	add_insmod xt_CONNMARK
+	stop_firewall
+	for group in $CG; do
+		start_cg $group
+	done
+}
+
+stop_firewall() {
+	# Builds up a list of iptables commands to flush the qos_* chains,
+	# remove rules referring to them, then delete them
+
+	# Print rules in the mangle table, like iptables-save
+	for command in $iptables; do
+		$command -w -t mangle -S |
+			# Find rules for the qos_* chains
+			grep -E '(^-N qos_|-j qos_)' |
+			# Exclude rules in qos_* chains (inter-qos_* refs)
+			grep -v '^-A qos_' |
+			# Replace -N with -X and hold, with -F and print
+			# Replace -A with -D
+			# Print held lines at the end (note leading newline)
+			sed -e '/^-N/{s/^-N/-X/;H;s/^-X/-F/}' \
+				-e 's/^-A/-D/' \
+				-e '${p;g}' |
+			# Make into proper iptables calls
+			# Note:  awkward in previous call due to hold space usage
+			sed -n -e "s/^./${command} -w -t mangle &/p"
+	done
+}
+
+C="0"
+INTERFACES=""
+[ -e ./qos.conf ] && {
+	. ./qos.conf
+	config_cb
+} || config_load qos
+
+C="0"
+for iface in $INTERFACES; do
+	export C="$(($C + 1))"
+done
+
+[ -x /usr/sbin/ip6tables ] && {
+	iptables="ip6tables iptables"
+} || {
+	iptables="iptables"
+}
+
+case "$1" in
+	all)
+		start_interfaces "$C"
+		start_firewall
+	;;
+	interface)
+		start_interface "$2" "$C"
+	;;
+	interfaces)
+		start_interfaces
+	;;
+	firewall)
+		case "$2" in
+			stop)
+				stop_firewall
+			;;
+			start|"")
+				start_firewall
+			;;
+		esac
+	;;
+esac
diff --git a/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk b/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
new file mode 100644
index 0000000000..21df391054
--- /dev/null
+++ b/package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
@@ -0,0 +1,106 @@
+BEGIN {
+	dmax=100
+	if (!(linespeed > 0)) linespeed = 128
+	FS=":"
+	n = 0
+}
+
+($1 != "") {
+	n++
+	class[n] = $1
+	prio[n] = $2
+	avgrate[n] = ($3 * linespeed / 100)
+	pktsize[n] = $4
+	delay[n] = $5
+	maxrate[n] = ($6 * linespeed / 100)
+	qdisc[n] = $7
+	filter[n] = $8
+}
+
+END {
+	allocated = 0
+	maxdelay = 0
+
+	for (i = 1; i <= n; i++) {
+		# set defaults
+		if (!(pktsize[i] > 0)) pktsize[i] = 1500
+		if (!(prio[i] > 0)) prio[i] = 1
+
+		allocated += avgrate[i]
+		sum_prio += prio[i]
+		if ((avgrate[i] > 0) && !(delay[i] > 0)) {
+			sum_rtprio += prio[i]
+		}
+	}
+
+	# allocation of m1 in rt classes:
+	# sum(d * m1) must not exceed dmax * (linespeed - allocated)
+	dmax = 0
+	for (i = 1; i <= n; i++) {
+		if (avgrate[i] > 0) {
+			rtm2[i] = avgrate[i]
+			if (delay[i] > 0) {
+				d[i] = delay[i]
+			} else {
+				d[i] = 2 * pktsize[i] * 1000 / (linespeed * 1024)
+				if (d[i] > dmax) dmax = d[i]
+			}
+		}
+	}
+
+	ds_avail = dmax * (linespeed - allocated)
+	for (i = 1; i <= n; i++) {
+		lsm1[i] = 0
+		rtm1[i] = 0
+		lsm2[i] = linespeed * prio[i] / sum_prio
+		if ((avgrate[i] > 0) && (d[i] > 0)) {
+			if (!(delay[i] > 0)) {
+				ds = ds_avail * prio[i] / sum_rtprio
+				ds_avail -= ds
+				rtm1[i] = rtm2[i] + ds/d[i]
+			}
+			lsm1[i] = rtm1[i]
+		}
+		else {
+			d[i] = 0
+		}
+	}
+
+	# main qdisc
+	for (i = 1; i <= n; i++) {
+		printf "tc class add dev "device" parent 1:1 classid 1:"class[i]"0 hfsc"
+		if (rtm1[i] > 0) {
+			printf " rt m1 " int(rtm1[i]) "kbit d " int(d[i] * 1000) "us m2 " int(rtm2[i])"kbit"
+		}
+		printf " ls m1 " int(lsm1[i]) "kbit d " int(d[i] * 1000) "us m2 " int(lsm2[i]) "kbit"
+		print " ul rate " int(maxrate[i]) "kbit"
+	}
+
+	# leaf qdisc
+	avpkt = 1200
+	for (i = 1; i <= n; i++) {
+		print "tc qdisc add dev "device" parent 1:"class[i]"0 handle "class[i]"00: fq_codel limit 800 quantum 300 noecn"
+	}
+
+	# filter rule
+	for (i = 1; i <= n; i++) {
+		filter_cmd = "tc filter add dev "device" parent 1: prio %d handle %s fw flowid 1:%d0\n";
+		if (direction == "up") {
+			filter_1 = sprintf("0x%x0/0xf0", class[i])
+			filter_2 = sprintf("0x0%x/0x0f", class[i])
+		} else {
+			filter_1 = sprintf("0x0%x/0x0f", class[i])
+			filter_2 = sprintf("0x%x0/0xf0", class[i])
+		}
+
+		printf filter_cmd, class[i] * 2, filter_1, class[i]
+		printf filter_cmd, class[i] * 2 + 1, filter_2, class[i]
+
+		filterc=1
+		if (filter[i] != "") {
+			print " tc filter add dev "device" parent "class[i]"00: handle "filterc"0 "filter[i]
+			filterc=filterc+1
+		}
+	}
+}
+
diff --git a/package/network/config/soloscli/Makefile b/package/network/config/soloscli/Makefile
new file mode 100644
index 0000000000..12bc15eaca
--- /dev/null
+++ b/package/network/config/soloscli/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=soloscli
+PKG_VERSION:=1.04
+PKG_RELEASE:=1
+
+PKG_SOURCE:=solos-pci-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/openadsl
+PKG_MD5SUM:=c398866de3c059b14eb953c89d698124
+PKG_LICENSE:=GPL-2.0
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/solos-pci-$(PKG_VERSION)
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/soloscli
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Configuration utility for Solos ADSL2+ modems
+  DEPENDS:=+kmod-solos-pci
+  URL:=http://sourceforge.net/projects/openadsl
+endef
+
+define Package/soloscli/description
+  This package contains the soloscli utility
+  for interrogating Traverse Technologies' Solos ADSL2+ modems.
+endef
+
+define Package/soloscli/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/soloscli/soloscli $(1)/usr/bin/
+	$(INSTALL_BIN) ./files/solos-log-stats $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/atm
+	$(INSTALL_DATA) ./files/etc/hotplug.d/atm/15-solos-init $(1)/etc/hotplug.d/atm/
+endef
+
+$(eval $(call BuildPackage,soloscli))
diff --git a/package/network/config/soloscli/files/etc/hotplug.d/atm/15-solos-init b/package/network/config/soloscli/files/etc/hotplug.d/atm/15-solos-init
new file mode 100644
index 0000000000..36d13ea5a0
--- /dev/null
+++ b/package/network/config/soloscli/files/etc/hotplug.d/atm/15-solos-init
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+dialog() {
+	local tag="$(echo "$1" | cut -d= -f1)"
+	local value="$(echo "$1" | cut -d= -f2-)"
+	local response
+	
+	response="$(soloscli -s "$port" "$tag" "$value")"
+	[ $? -ne 0 ] && {
+		logger "soloscli($port): $tag '$value' returns $response"
+	}
+}
+
+if [ "$ACTION" = "add" ]; then
+	include /lib/network
+	scan_interfaces
+
+	case $DEVICENAME in
+	solos-pci[0-3])
+		port="${DEVICENAME#solos-pci}"
+		device="solos${port}"
+
+		config_list_foreach wan "$device" dialog
+		;;
+	esac
+fi
diff --git a/package/network/config/soloscli/files/etc/uci-default/solos b/package/network/config/soloscli/files/etc/uci-default/solos
new file mode 100644
index 0000000000..7f69da62c6
--- /dev/null
+++ b/package/network/config/soloscli/files/etc/uci-default/solos
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+uci batch <<__EOF__
+
+delete network.wan.solos0
+
+add_list network.wan.solos0="ActivateLine=Abort"
+add_list network.wan.solos0="Retrain=EnableAll"
+add_list network.wan.solos0="DetectNoise=Enable"
+add_list network.wan.solos0="BisMCapability=Disable"
+add_list network.wan.solos0="BisACapability=Disable"
+add_list network.wan.solos0="ActivateLine=Start"
+
+commit network
+__EOF__
diff --git a/package/network/config/soloscli/files/solos-log-stats b/package/network/config/soloscli/files/solos-log-stats
new file mode 100644
index 0000000000..2b75ee30cd
--- /dev/null
+++ b/package/network/config/soloscli/files/solos-log-stats
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+cd /sys/class/atm/ || exit 1
+
+for PORT in solos-pci* ; do
+
+    RXRATE=`cat $PORT/parameters/RxBitRate`
+    TXRATE=`cat $PORT/parameters/TxBitRate`
+    RXSNR=`cat $PORT/parameters/LocalSNRMargin | sed "s/ dB//"`
+    TXSNR=`cat $PORT/parameters/RemoteSNRMargin | sed "s/ dB//"`
+    RXERR=`cat $PORT/parameters/RSUnCorrectedErrorsDn`
+    TXERR=`cat $PORT/parameters/RSUnCorrectedErrorsUp`
+    RXFEC=`cat $PORT/parameters/RSCorrectedErrorsDn`
+    TXFEC=`cat $PORT/parameters/RSCorrectedErrorsUp`
+
+    echo "$RXRATE $RXSNR $RXERR $RXFEC / $TXRATE $TXSNR $TXERR $TXFEC" |
+       logger -t $PORT
+done
+
diff --git a/package/network/config/soloscli/patches/001-no-driver.patch b/package/network/config/soloscli/patches/001-no-driver.patch
new file mode 100644
index 0000000000..95588aa056
--- /dev/null
+++ b/package/network/config/soloscli/patches/001-no-driver.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -11,7 +11,7 @@ else
+ KDIR	?= /lib/modules/$(shell uname -r)/build
+ PWD	:= $(shell pwd)
+ 
+-all: soloscli driver
++all: soloscli
+ 
+ soloscli: soloscli/soloscli
+ 
diff --git a/package/network/config/soloscli/patches/002-cflags.patch b/package/network/config/soloscli/patches/002-cflags.patch
new file mode 100644
index 0000000000..a7d6a86020
--- /dev/null
+++ b/package/network/config/soloscli/patches/002-cflags.patch
@@ -0,0 +1,12 @@
+--- a/soloscli/Makefile
++++ b/soloscli/Makefile
+@@ -4,9 +4,6 @@
+ # Last Mod: 2009-06-16
+ #
+ 
+-CC=gcc
+-CFLAGS=-Wall
+-
+ soloscli: soloscli.c soloscli.h
+ 
+ clean:
diff --git a/package/network/config/swconfig/Makefile b/package/network/config/swconfig/Makefile
new file mode 100644
index 0000000000..d1c8fd7b5e
--- /dev/null
+++ b/package/network/config/swconfig/Makefile
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2008-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=swconfig
+PKG_RELEASE:=11
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/swconfig
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libuci +libnl-tiny
+  TITLE:=Switch configuration utility
+endef
+
+TARGET_CPPFLAGS := \
+	-D_GNU_SOURCE \
+	-I$(STAGING_DIR)/usr/include/libnl-tiny \
+	-I$(PKG_BUILD_DIR) \
+	$(TARGET_CPPFLAGS) \
+	-I$(LINUX_DIR)/user_headers/include
+
+define Build/Compile
+	CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		LIBS="$(TARGET_LDFLAGS) -lnl-tiny -lm -luci"
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_BUILD_DIR)/swlib.h $(1)/usr/include/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libsw.so $(1)/usr/lib/
+endef
+
+define Package/swconfig/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/lib/network
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/swconfig $(1)/sbin/swconfig
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/libsw.so $(1)/lib
+	$(INSTALL_DATA) ./files/switch.sh $(1)/lib/network/
+endef
+
+$(eval $(call BuildPackage,swconfig))
diff --git a/package/network/config/swconfig/files/switch.sh b/package/network/config/swconfig/files/switch.sh
new file mode 100644
index 0000000000..74d259073f
--- /dev/null
+++ b/package/network/config/swconfig/files/switch.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# Copyright (C) 2009 OpenWrt.org
+
+setup_switch_dev() {
+	local name
+	config_get name "$1" name
+	name="${name:-$1}"
+	[ -d "/sys/class/net/$name" ] && ip link set dev "$name" up
+	swconfig dev "$name" load network
+}
+
+setup_switch() {
+	config_load network
+	config_foreach setup_switch_dev switch
+}
diff --git a/package/network/config/swconfig/src/Makefile b/package/network/config/swconfig/src/Makefile
new file mode 100644
index 0000000000..1176bf0e40
--- /dev/null
+++ b/package/network/config/swconfig/src/Makefile
@@ -0,0 +1,15 @@
+ifndef CFLAGS
+CFLAGS = -O2 -g -I ../src
+endif
+LIBS=-lnl -lnl-genl
+
+all: swconfig
+
+%.o: %.c
+	$(CC) $(CFLAGS) -fPIC -c -o $@ $^
+
+libsw.so: swlib.o
+	$(CC) $(CFLAGS) -fPIC -shared -o $@ swlib.o
+
+swconfig: libsw.so cli.o uci.o
+	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -L./ -lsw
diff --git a/package/network/config/swconfig/src/cli.c b/package/network/config/swconfig/src/cli.c
new file mode 100644
index 0000000000..eab6c64742
--- /dev/null
+++ b/package/network/config/swconfig/src/cli.c
@@ -0,0 +1,387 @@
+/*
+ * swconfig.c: Switch configuration utility
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2010 Martin Mares <mj@ucw.cz>
+ *
+ * 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 Foundatio.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <uci.h>
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/switch.h>
+#include "swlib.h"
+
+enum {
+	CMD_NONE,
+	CMD_GET,
+	CMD_SET,
+	CMD_LOAD,
+	CMD_HELP,
+	CMD_SHOW,
+	CMD_PORTMAP,
+};
+
+static void
+print_attrs(const struct switch_attr *attr)
+{
+	int i = 0;
+	while (attr) {
+		const char *type;
+		switch(attr->type) {
+			case SWITCH_TYPE_INT:
+				type = "int";
+				break;
+			case SWITCH_TYPE_STRING:
+				type = "string";
+				break;
+			case SWITCH_TYPE_PORTS:
+				type = "ports";
+				break;
+			case SWITCH_TYPE_NOVAL:
+				type = "none";
+				break;
+			default:
+				type = "unknown";
+				break;
+		}
+		printf("\tAttribute %d (%s): %s (%s)\n", ++i, type, attr->name, attr->description);
+		attr = attr->next;
+	}
+}
+
+static void
+list_attributes(struct switch_dev *dev)
+{
+	printf("%s: %s(%s), ports: %d (cpu @ %d), vlans: %d\n", dev->dev_name, dev->alias, dev->name, dev->ports, dev->cpu_port, dev->vlans);
+	printf("     --switch\n");
+	print_attrs(dev->ops);
+	printf("     --vlan\n");
+	print_attrs(dev->vlan_ops);
+	printf("     --port\n");
+	print_attrs(dev->port_ops);
+}
+
+static const char *
+speed_str(int speed)
+{
+	switch (speed) {
+	case 10:
+		return "10baseT";
+	case 100:
+		return "100baseT";
+	case 1000:
+		return "1000baseT";
+	default:
+		break;
+	}
+
+	return "unknown";
+}
+
+static void
+print_attr_val(const struct switch_attr *attr, const struct switch_val *val)
+{
+	struct switch_port_link *link;
+	int i;
+
+	switch (attr->type) {
+	case SWITCH_TYPE_INT:
+		printf("%d", val->value.i);
+		break;
+	case SWITCH_TYPE_STRING:
+		printf("%s", val->value.s);
+		break;
+	case SWITCH_TYPE_PORTS:
+		for(i = 0; i < val->len; i++) {
+			printf("%d%s ",
+				val->value.ports[i].id,
+				(val->value.ports[i].flags &
+				 SWLIB_PORT_FLAG_TAGGED) ? "t" : "");
+		}
+		break;
+	case SWITCH_TYPE_LINK:
+		link = val->value.link;
+		if (link->link)
+			printf("port:%d link:up speed:%s %s-duplex %s%s%s%s%s",
+				val->port_vlan,
+				speed_str(link->speed),
+				link->duplex ? "full" : "half",
+				link->tx_flow ? "txflow " : "",
+				link->rx_flow ? "rxflow " : "",
+				link->eee & SWLIB_LINK_FLAG_EEE_100BASET ? "eee100 " : "",
+				link->eee & SWLIB_LINK_FLAG_EEE_1000BASET ? "eee1000 " : "",
+				link->aneg ? "auto" : "");
+		else
+			printf("port:%d link:down", val->port_vlan);
+		break;
+	default:
+		printf("?unknown-type?");
+	}
+}
+
+static void
+show_attrs(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
+{
+	while (attr) {
+		if (attr->type != SWITCH_TYPE_NOVAL) {
+			printf("\t%s: ", attr->name);
+			if (swlib_get_attr(dev, attr, val) < 0)
+				printf("???");
+			else
+				print_attr_val(attr, val);
+			putchar('\n');
+		}
+		attr = attr->next;
+	}
+}
+
+static void
+show_global(struct switch_dev *dev)
+{
+	struct switch_val val;
+
+	printf("Global attributes:\n");
+	show_attrs(dev, dev->ops, &val);
+}
+
+static void
+show_port(struct switch_dev *dev, int port)
+{
+	struct switch_val val;
+
+	printf("Port %d:\n", port);
+	val.port_vlan = port;
+	show_attrs(dev, dev->port_ops, &val);
+}
+
+static void
+show_vlan(struct switch_dev *dev, int vlan, bool all)
+{
+	struct switch_val val;
+	struct switch_attr *attr;
+
+	val.port_vlan = vlan;
+
+	if (all) {
+		attr = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, "ports");
+		if (swlib_get_attr(dev, attr, &val) < 0)
+			return;
+
+		if (!val.len)
+			return;
+	}
+
+	printf("VLAN %d:\n", vlan);
+	show_attrs(dev, dev->vlan_ops, &val);
+}
+
+static void
+print_usage(void)
+{
+	printf("swconfig list\n");
+	printf("swconfig dev <dev> [port <port>|vlan <vlan>] (help|set <key> <value>|get <key>|load <config>|show)\n");
+	exit(1);
+}
+
+static void
+swconfig_load_uci(struct switch_dev *dev, const char *name)
+{
+	struct uci_context *ctx;
+	struct uci_package *p = NULL;
+	int ret = -1;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return;
+
+	uci_load(ctx, name, &p);
+	if (!p) {
+		uci_perror(ctx, "Failed to load config file: ");
+		goto out;
+	}
+
+	ret = swlib_apply_from_uci(dev, p);
+	if (ret < 0)
+		fprintf(stderr, "Failed to apply configuration for switch '%s'\n", dev->dev_name);
+
+out:
+	uci_free_context(ctx);
+	exit(ret);
+}
+
+int main(int argc, char **argv)
+{
+	int retval = 0;
+	struct switch_dev *dev;
+	struct switch_attr *a;
+	struct switch_val val;
+	int i;
+
+	int cmd = CMD_NONE;
+	char *cdev = NULL;
+	int cport = -1;
+	int cvlan = -1;
+	char *ckey = NULL;
+	char *cvalue = NULL;
+	char *csegment = NULL;
+
+	if((argc == 2) && !strcmp(argv[1], "list")) {
+		swlib_list();
+		return 0;
+	}
+
+	if(argc < 4)
+		print_usage();
+
+	if(strcmp(argv[1], "dev"))
+		print_usage();
+
+	cdev = argv[2];
+
+	for(i = 3; i < argc; i++)
+	{
+		char *arg = argv[i];
+		if (cmd != CMD_NONE) {
+			print_usage();
+		} else if (!strcmp(arg, "port") && i+1 < argc) {
+			cport = atoi(argv[++i]);
+		} else if (!strcmp(arg, "vlan") && i+1 < argc) {
+			cvlan = atoi(argv[++i]);
+		} else if (!strcmp(arg, "help")) {
+			cmd = CMD_HELP;
+		} else if (!strcmp(arg, "set") && i+1 < argc) {
+			cmd = CMD_SET;
+			ckey = argv[++i];
+			if (i+1 < argc)
+				cvalue = argv[++i];
+		} else if (!strcmp(arg, "get") && i+1 < argc) {
+			cmd = CMD_GET;
+			ckey = argv[++i];
+		} else if (!strcmp(arg, "load") && i+1 < argc) {
+			if ((cport >= 0) || (cvlan >= 0))
+				print_usage();
+			cmd = CMD_LOAD;
+			ckey = argv[++i];
+		} else if (!strcmp(arg, "portmap")) {
+			if (i + 1 < argc)
+				csegment = argv[++i];
+			cmd = CMD_PORTMAP;
+		} else if (!strcmp(arg, "show")) {
+			cmd = CMD_SHOW;
+		} else {
+			print_usage();
+		}
+	}
+
+	if (cmd == CMD_NONE)
+		print_usage();
+	if (cport > -1 && cvlan > -1)
+		print_usage();
+
+	dev = swlib_connect(cdev);
+	if (!dev) {
+		fprintf(stderr, "Failed to connect to the switch. Use the \"list\" command to see which switches are available.\n");
+		return 1;
+	}
+
+	swlib_scan(dev);
+
+	if (cmd == CMD_GET || cmd == CMD_SET) {
+		if(cport > -1)
+			a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_PORT, ckey);
+		else if(cvlan > -1)
+			a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, ckey);
+		else
+			a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, ckey);
+
+		if(!a)
+		{
+			fprintf(stderr, "Unknown attribute \"%s\"\n", ckey);
+			retval = -1;
+			goto out;
+		}
+	}
+
+	switch(cmd)
+	{
+	case CMD_SET:
+		if ((a->type != SWITCH_TYPE_NOVAL) &&
+				(cvalue == NULL))
+			print_usage();
+
+		if(cvlan > -1)
+			cport = cvlan;
+
+		retval = swlib_set_attr_string(dev, a, cport, cvalue);
+		if (retval < 0)
+		{
+			nl_perror(-retval, "Failed to set attribute");
+			goto out;
+		}
+		break;
+	case CMD_GET:
+		if(cvlan > -1)
+			val.port_vlan = cvlan;
+		if(cport > -1)
+			val.port_vlan = cport;
+		retval = swlib_get_attr(dev, a, &val);
+		if (retval < 0)
+		{
+			nl_perror(-retval, "Failed to get attribute");
+			goto out;
+		}
+		print_attr_val(a, &val);
+		putchar('\n');
+		break;
+	case CMD_LOAD:
+		swconfig_load_uci(dev, ckey);
+		break;
+	case CMD_HELP:
+		list_attributes(dev);
+		break;
+	case CMD_PORTMAP:
+		swlib_print_portmap(dev, csegment);
+		break;
+	case CMD_SHOW:
+		if (cport >= 0 || cvlan >= 0) {
+			if (cport >= 0)
+				show_port(dev, cport);
+			else
+				show_vlan(dev, cvlan, false);
+		} else {
+			show_global(dev);
+			for (i=0; i < dev->ports; i++)
+				show_port(dev, i);
+			for (i=0; i < dev->vlans; i++)
+				show_vlan(dev, i, true);
+		}
+		break;
+	}
+
+out:
+	swlib_free_all(dev);
+	return retval;
+}
diff --git a/package/network/config/swconfig/src/swlib.c b/package/network/config/swconfig/src/swlib.c
new file mode 100644
index 0000000000..e6e9aead47
--- /dev/null
+++ b/package/network/config/swconfig/src/swlib.c
@@ -0,0 +1,922 @@
+/*
+ * swlib.c: Switch configuration API (user space part)
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/switch.h>
+#include "swlib.h"
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+
+//#define DEBUG 1
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+static struct nl_sock *handle;
+static struct nl_cache *cache;
+static struct genl_family *family;
+static struct nlattr *tb[SWITCH_ATTR_MAX + 1];
+static int refcount = 0;
+
+static struct nla_policy port_policy[SWITCH_ATTR_MAX] = {
+	[SWITCH_PORT_ID] = { .type = NLA_U32 },
+	[SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
+};
+
+static struct nla_policy portmap_policy[SWITCH_PORTMAP_MAX] = {
+	[SWITCH_PORTMAP_SEGMENT] = { .type = NLA_STRING },
+	[SWITCH_PORTMAP_VIRT] = { .type = NLA_U32 },
+};
+
+static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = {
+	[SWITCH_LINK_FLAG_LINK] = { .type = NLA_FLAG },
+	[SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG },
+	[SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG },
+	[SWITCH_LINK_SPEED] = { .type = NLA_U32 },
+	[SWITCH_LINK_FLAG_EEE_100BASET] = { .type = NLA_FLAG },
+	[SWITCH_LINK_FLAG_EEE_1000BASET] = { .type = NLA_FLAG },
+};
+
+static inline void *
+swlib_alloc(size_t size)
+{
+	void *ptr;
+
+	ptr = malloc(size);
+	if (!ptr)
+		goto done;
+	memset(ptr, 0, size);
+
+done:
+	return ptr;
+}
+
+static int
+wait_handler(struct nl_msg *msg, void *arg)
+{
+	int *finished = arg;
+
+	*finished = 1;
+	return NL_STOP;
+}
+
+/* helper function for performing netlink requests */
+static int
+swlib_call(int cmd, int (*call)(struct nl_msg *, void *),
+		int (*data)(struct nl_msg *, void *), void *arg)
+{
+	struct nl_msg *msg;
+	struct nl_cb *cb = NULL;
+	int finished;
+	int flags = 0;
+	int err;
+
+	msg = nlmsg_alloc();
+	if (!msg) {
+		fprintf(stderr, "Out of memory!\n");
+		exit(1);
+	}
+
+	if (!data)
+		flags |= NLM_F_DUMP;
+
+	genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family), 0, flags, cmd, 0);
+	if (data) {
+		if (data(msg, arg) < 0)
+			goto nla_put_failure;
+	}
+
+	cb = nl_cb_alloc(NL_CB_CUSTOM);
+	if (!cb) {
+		fprintf(stderr, "nl_cb_alloc failed.\n");
+		exit(1);
+	}
+
+	err = nl_send_auto_complete(handle, msg);
+	if (err < 0) {
+		fprintf(stderr, "nl_send_auto_complete failed: %d\n", err);
+		goto out;
+	}
+
+	finished = 0;
+
+	if (call)
+		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, call, arg);
+
+	if (data)
+		nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
+	else
+		nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
+
+	err = nl_recvmsgs(handle, cb);
+	if (err < 0) {
+		goto out;
+	}
+
+	if (!finished)
+		err = nl_wait_for_ack(handle);
+
+out:
+	if (cb)
+		nl_cb_put(cb);
+nla_put_failure:
+	nlmsg_free(msg);
+	return err;
+}
+
+static int
+send_attr(struct nl_msg *msg, void *arg)
+{
+	struct switch_val *val = arg;
+	struct switch_attr *attr = val->attr;
+
+	NLA_PUT_U32(msg, SWITCH_ATTR_ID, attr->dev->id);
+	NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, attr->id);
+	switch(attr->atype) {
+	case SWLIB_ATTR_GROUP_PORT:
+		NLA_PUT_U32(msg, SWITCH_ATTR_OP_PORT, val->port_vlan);
+		break;
+	case SWLIB_ATTR_GROUP_VLAN:
+		NLA_PUT_U32(msg, SWITCH_ATTR_OP_VLAN, val->port_vlan);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int
+store_port_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
+{
+	struct nlattr *p;
+	int ports = val->attr->dev->ports;
+	int err = 0;
+	int remaining;
+
+	if (!val->value.ports)
+		val->value.ports = malloc(sizeof(struct switch_port) * ports);
+
+	nla_for_each_nested(p, nla, remaining) {
+		struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
+		struct switch_port *port;
+
+		if (val->len >= ports)
+			break;
+
+		err = nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, p, port_policy);
+		if (err < 0)
+			goto out;
+
+		if (!tb[SWITCH_PORT_ID])
+			continue;
+
+		port = &val->value.ports[val->len];
+		port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
+		port->flags = 0;
+		if (tb[SWITCH_PORT_FLAG_TAGGED])
+			port->flags |= SWLIB_PORT_FLAG_TAGGED;
+
+		val->len++;
+	}
+
+out:
+	return err;
+}
+
+static int
+store_link_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
+{
+	struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1];
+	struct switch_port_link *link;
+	int err = 0;
+
+	if (!val->value.link)
+		val->value.link = malloc(sizeof(struct switch_port_link));
+
+	err = nla_parse_nested(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy);
+	if (err < 0)
+		goto out;
+
+	link = val->value.link;
+	link->link = !!tb[SWITCH_LINK_FLAG_LINK];
+	link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX];
+	link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG];
+	link->tx_flow = !!tb[SWITCH_LINK_FLAG_TX_FLOW];
+	link->rx_flow = !!tb[SWITCH_LINK_FLAG_RX_FLOW];
+	link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]);
+	link->eee = 0;
+	if (tb[SWITCH_LINK_FLAG_EEE_100BASET])
+		link->eee |= SWLIB_LINK_FLAG_EEE_100BASET;
+	if (tb[SWITCH_LINK_FLAG_EEE_1000BASET])
+		link->eee |= SWLIB_LINK_FLAG_EEE_1000BASET;
+
+out:
+	return err;
+}
+
+static int
+store_val(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct switch_val *val = arg;
+
+	if (!val)
+		goto error;
+
+	if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
+			genlmsg_attrlen(gnlh, 0), NULL) < 0) {
+		goto error;
+	}
+
+	if (tb[SWITCH_ATTR_OP_VALUE_INT])
+		val->value.i = nla_get_u32(tb[SWITCH_ATTR_OP_VALUE_INT]);
+	else if (tb[SWITCH_ATTR_OP_VALUE_STR])
+		val->value.s = strdup(nla_get_string(tb[SWITCH_ATTR_OP_VALUE_STR]));
+	else if (tb[SWITCH_ATTR_OP_VALUE_PORTS])
+		val->err = store_port_val(msg, tb[SWITCH_ATTR_OP_VALUE_PORTS], val);
+	else if (tb[SWITCH_ATTR_OP_VALUE_LINK])
+		val->err = store_link_val(msg, tb[SWITCH_ATTR_OP_VALUE_LINK], val);
+
+	val->err = 0;
+	return 0;
+
+error:
+	return NL_SKIP;
+}
+
+int
+swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
+{
+	int cmd;
+	int err;
+
+	switch(attr->atype) {
+	case SWLIB_ATTR_GROUP_GLOBAL:
+		cmd = SWITCH_CMD_GET_GLOBAL;
+		break;
+	case SWLIB_ATTR_GROUP_PORT:
+		cmd = SWITCH_CMD_GET_PORT;
+		break;
+	case SWLIB_ATTR_GROUP_VLAN:
+		cmd = SWITCH_CMD_GET_VLAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	memset(&val->value, 0, sizeof(val->value));
+	val->len = 0;
+	val->attr = attr;
+	val->err = -EINVAL;
+	err = swlib_call(cmd, store_val, send_attr, val);
+	if (!err)
+		err = val->err;
+
+	return err;
+}
+
+static int
+send_attr_ports(struct nl_msg *msg, struct switch_val *val)
+{
+	struct nlattr *n;
+	int i;
+
+	/* TODO implement multipart? */
+	if (val->len == 0)
+		goto done;
+	n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_PORTS);
+	if (!n)
+		goto nla_put_failure;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *port = &val->value.ports[i];
+		struct nlattr *np;
+
+		np = nla_nest_start(msg, SWITCH_ATTR_PORT);
+		if (!np)
+			goto nla_put_failure;
+
+		NLA_PUT_U32(msg, SWITCH_PORT_ID, port->id);
+		if (port->flags & SWLIB_PORT_FLAG_TAGGED)
+			NLA_PUT_FLAG(msg, SWITCH_PORT_FLAG_TAGGED);
+
+		nla_nest_end(msg, np);
+	}
+	nla_nest_end(msg, n);
+done:
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int
+send_attr_link(struct nl_msg *msg, struct switch_val *val)
+{
+	struct switch_port_link *link = val->value.link;
+	struct nlattr *n;
+
+	n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_LINK);
+	if (!n)
+		goto nla_put_failure;
+
+	if (link->duplex)
+		NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_DUPLEX);
+	if (link->aneg)
+		NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_ANEG);
+	NLA_PUT_U32(msg, SWITCH_LINK_SPEED, link->speed);
+
+	nla_nest_end(msg, n);
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int
+send_attr_val(struct nl_msg *msg, void *arg)
+{
+	struct switch_val *val = arg;
+	struct switch_attr *attr = val->attr;
+
+	if (send_attr(msg, arg))
+		goto nla_put_failure;
+
+	switch(attr->type) {
+	case SWITCH_TYPE_NOVAL:
+		break;
+	case SWITCH_TYPE_INT:
+		NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val->value.i);
+		break;
+	case SWITCH_TYPE_STRING:
+		if (!val->value.s)
+			goto nla_put_failure;
+		NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val->value.s);
+		break;
+	case SWITCH_TYPE_PORTS:
+		if (send_attr_ports(msg, val) < 0)
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_LINK:
+		if (send_attr_link(msg, val))
+			goto nla_put_failure;
+		break;
+	default:
+		goto nla_put_failure;
+	}
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+int
+swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
+{
+	int cmd;
+
+	switch(attr->atype) {
+	case SWLIB_ATTR_GROUP_GLOBAL:
+		cmd = SWITCH_CMD_SET_GLOBAL;
+		break;
+	case SWLIB_ATTR_GROUP_PORT:
+		cmd = SWITCH_CMD_SET_PORT;
+		break;
+	case SWLIB_ATTR_GROUP_VLAN:
+		cmd = SWITCH_CMD_SET_VLAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val->attr = attr;
+	return swlib_call(cmd, NULL, send_attr_val, val);
+}
+
+enum {
+	CMD_NONE,
+	CMD_DUPLEX,
+	CMD_ANEG,
+	CMD_SPEED,
+};
+
+int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *a, int port_vlan, const char *str)
+{
+	struct switch_port *ports;
+	struct switch_port_link *link;
+	struct switch_val val;
+	char *ptr;
+	int cmd = CMD_NONE;
+
+	memset(&val, 0, sizeof(val));
+	val.port_vlan = port_vlan;
+	switch(a->type) {
+	case SWITCH_TYPE_INT:
+		val.value.i = atoi(str);
+		break;
+	case SWITCH_TYPE_STRING:
+		val.value.s = (char *)str;
+		break;
+	case SWITCH_TYPE_PORTS:
+		ports = alloca(sizeof(struct switch_port) * dev->ports);
+		memset(ports, 0, sizeof(struct switch_port) * dev->ports);
+		val.len = 0;
+		ptr = (char *)str;
+		while(ptr && *ptr)
+		{
+			while(*ptr && isspace(*ptr))
+				ptr++;
+
+			if (!*ptr)
+				break;
+
+			if (!isdigit(*ptr))
+				return -1;
+
+			if (val.len >= dev->ports)
+				return -1;
+
+			ports[val.len].flags = 0;
+			ports[val.len].id = strtoul(ptr, &ptr, 10);
+			while(*ptr && !isspace(*ptr)) {
+				if (*ptr == 't')
+					ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED;
+				else
+					return -1;
+
+				ptr++;
+			}
+			if (*ptr)
+				ptr++;
+			val.len++;
+		}
+		val.value.ports = ports;
+		break;
+	case SWITCH_TYPE_LINK:
+		link = malloc(sizeof(struct switch_port_link));
+		memset(link, 0, sizeof(struct switch_port_link));
+		ptr = (char *)str;
+		for (ptr = strtok(ptr," "); ptr; ptr = strtok(NULL, " ")) {
+			switch (cmd) {
+			case CMD_NONE:
+				if (!strcmp(ptr, "duplex"))
+					cmd = CMD_DUPLEX;
+				else if (!strcmp(ptr, "autoneg"))
+					cmd = CMD_ANEG;
+				else if (!strcmp(ptr, "speed"))
+					cmd = CMD_SPEED;
+				else
+					fprintf(stderr, "Unsupported option %s\n", ptr);
+				break;
+			case CMD_DUPLEX:
+				if (!strcmp(ptr, "half"))
+					link->duplex = 0;
+				else if (!strcmp(ptr, "full"))
+					link->duplex = 1;
+				else
+					fprintf(stderr, "Unsupported value %s\n", ptr);
+				cmd = CMD_NONE;
+				break;
+			case CMD_ANEG:
+				if (!strcmp(ptr, "on"))
+					link->aneg = 1;
+				else if (!strcmp(ptr, "off"))
+					link->aneg = 0;
+				else
+					fprintf(stderr, "Unsupported value %s\n", ptr);
+				cmd = CMD_NONE;
+				break;
+			case CMD_SPEED:
+				link->speed = atoi(ptr);
+				cmd = CMD_NONE;
+				break;
+			}
+		}
+		val.value.link = link;
+		break;
+	case SWITCH_TYPE_NOVAL:
+		if (str && !strcmp(str, "0"))
+			return 0;
+
+		break;
+	default:
+		return -1;
+	}
+	return swlib_set_attr(dev, a, &val);
+}
+
+
+struct attrlist_arg {
+	int id;
+	int atype;
+	struct switch_dev *dev;
+	struct switch_attr *prev;
+	struct switch_attr **head;
+};
+
+static int
+add_id(struct nl_msg *msg, void *arg)
+{
+	struct attrlist_arg *l = arg;
+
+	NLA_PUT_U32(msg, SWITCH_ATTR_ID, l->id);
+
+	return 0;
+nla_put_failure:
+	return -1;
+}
+
+static int
+add_attr(struct nl_msg *msg, void *ptr)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct attrlist_arg *arg = ptr;
+	struct switch_attr *new;
+
+	if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
+			genlmsg_attrlen(gnlh, 0), NULL) < 0)
+		goto done;
+
+	new = swlib_alloc(sizeof(struct switch_attr));
+	if (!new)
+		goto done;
+
+	new->dev = arg->dev;
+	new->atype = arg->atype;
+	if (arg->prev) {
+		arg->prev->next = new;
+	} else {
+		arg->prev = *arg->head;
+	}
+	*arg->head = new;
+	arg->head = &new->next;
+
+	if (tb[SWITCH_ATTR_OP_ID])
+		new->id = nla_get_u32(tb[SWITCH_ATTR_OP_ID]);
+	if (tb[SWITCH_ATTR_OP_TYPE])
+		new->type = nla_get_u32(tb[SWITCH_ATTR_OP_TYPE]);
+	if (tb[SWITCH_ATTR_OP_NAME])
+		new->name = strdup(nla_get_string(tb[SWITCH_ATTR_OP_NAME]));
+	if (tb[SWITCH_ATTR_OP_DESCRIPTION])
+		new->description = strdup(nla_get_string(tb[SWITCH_ATTR_OP_DESCRIPTION]));
+
+done:
+	return NL_SKIP;
+}
+
+int
+swlib_scan(struct switch_dev *dev)
+{
+	struct attrlist_arg arg;
+
+	if (dev->ops || dev->port_ops || dev->vlan_ops)
+		return 0;
+
+	arg.atype = SWLIB_ATTR_GROUP_GLOBAL;
+	arg.dev = dev;
+	arg.id = dev->id;
+	arg.prev = NULL;
+	arg.head = &dev->ops;
+	swlib_call(SWITCH_CMD_LIST_GLOBAL, add_attr, add_id, &arg);
+
+	arg.atype = SWLIB_ATTR_GROUP_PORT;
+	arg.prev = NULL;
+	arg.head = &dev->port_ops;
+	swlib_call(SWITCH_CMD_LIST_PORT, add_attr, add_id, &arg);
+
+	arg.atype = SWLIB_ATTR_GROUP_VLAN;
+	arg.prev = NULL;
+	arg.head = &dev->vlan_ops;
+	swlib_call(SWITCH_CMD_LIST_VLAN, add_attr, add_id, &arg);
+
+	return 0;
+}
+
+struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
+		enum swlib_attr_group atype, const char *name)
+{
+	struct switch_attr *head;
+
+	if (!name || !dev)
+		return NULL;
+
+	switch(atype) {
+	case SWLIB_ATTR_GROUP_GLOBAL:
+		head = dev->ops;
+		break;
+	case SWLIB_ATTR_GROUP_PORT:
+		head = dev->port_ops;
+		break;
+	case SWLIB_ATTR_GROUP_VLAN:
+		head = dev->vlan_ops;
+		break;
+	}
+	while(head) {
+		if (!strcmp(name, head->name))
+			return head;
+		head = head->next;
+	}
+
+	return NULL;
+}
+
+static void
+swlib_priv_free(void)
+{
+	if (family)
+		nl_object_put((struct nl_object*)family);
+	if (cache)
+		nl_cache_free(cache);
+	if (handle)
+		nl_socket_free(handle);
+	family = NULL;
+	handle = NULL;
+	cache = NULL;
+}
+
+static int
+swlib_priv_init(void)
+{
+	int ret;
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		DPRINTF("Failed to create handle\n");
+		goto err;
+	}
+
+	if (genl_connect(handle)) {
+		DPRINTF("Failed to connect to generic netlink\n");
+		goto err;
+	}
+
+	ret = genl_ctrl_alloc_cache(handle, &cache);
+	if (ret < 0) {
+		DPRINTF("Failed to allocate netlink cache\n");
+		goto err;
+	}
+
+	family = genl_ctrl_search_by_name(cache, "switch");
+	if (!family) {
+		DPRINTF("Switch API not present\n");
+		goto err;
+	}
+	return 0;
+
+err:
+	swlib_priv_free();
+	return -EINVAL;
+}
+
+struct swlib_scan_arg {
+	const char *name;
+	struct switch_dev *head;
+	struct switch_dev *ptr;
+};
+
+static int
+add_port_map(struct switch_dev *dev, struct nlattr *nla)
+{
+	struct nlattr *p;
+	int err = 0, idx = 0;
+	int remaining;
+
+	dev->maps = malloc(sizeof(struct switch_portmap) * dev->ports);
+	if (!dev->maps)
+		return -1;
+	memset(dev->maps, 0, sizeof(struct switch_portmap) * dev->ports);
+
+	nla_for_each_nested(p, nla, remaining) {
+		struct nlattr *tb[SWITCH_PORTMAP_MAX+1];
+
+		if (idx >= dev->ports)
+			continue;
+
+		err = nla_parse_nested(tb, SWITCH_PORTMAP_MAX, p, portmap_policy);
+		if (err < 0)
+			continue;
+
+
+		if (tb[SWITCH_PORTMAP_SEGMENT] && tb[SWITCH_PORTMAP_VIRT]) {
+			dev->maps[idx].segment = strdup(nla_get_string(tb[SWITCH_PORTMAP_SEGMENT]));
+			dev->maps[idx].virt = nla_get_u32(tb[SWITCH_PORTMAP_VIRT]);
+		}
+		idx++;
+	}
+
+out:
+	return err;
+}
+
+
+static int
+add_switch(struct nl_msg *msg, void *arg)
+{
+	struct swlib_scan_arg *sa = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct switch_dev *dev;
+	const char *name;
+	const char *alias;
+
+	if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
+		goto done;
+
+	if (!tb[SWITCH_ATTR_DEV_NAME])
+		goto done;
+
+	name = nla_get_string(tb[SWITCH_ATTR_DEV_NAME]);
+	alias = nla_get_string(tb[SWITCH_ATTR_ALIAS]);
+
+	if (sa->name && (strcmp(name, sa->name) != 0) && (strcmp(alias, sa->name) != 0))
+		goto done;
+
+	dev = swlib_alloc(sizeof(struct switch_dev));
+	if (!dev)
+		goto done;
+
+	strncpy(dev->dev_name, name, IFNAMSIZ - 1);
+	dev->alias = strdup(alias);
+	if (tb[SWITCH_ATTR_ID])
+		dev->id = nla_get_u32(tb[SWITCH_ATTR_ID]);
+	if (tb[SWITCH_ATTR_NAME])
+		dev->name = strdup(nla_get_string(tb[SWITCH_ATTR_NAME]));
+	if (tb[SWITCH_ATTR_PORTS])
+		dev->ports = nla_get_u32(tb[SWITCH_ATTR_PORTS]);
+	if (tb[SWITCH_ATTR_VLANS])
+		dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]);
+	if (tb[SWITCH_ATTR_CPU_PORT])
+		dev->cpu_port = nla_get_u32(tb[SWITCH_ATTR_CPU_PORT]);
+	if (tb[SWITCH_ATTR_PORTMAP])
+		add_port_map(dev, tb[SWITCH_ATTR_PORTMAP]);
+
+	if (!sa->head) {
+		sa->head = dev;
+		sa->ptr = dev;
+	} else {
+		sa->ptr->next = dev;
+		sa->ptr = dev;
+	}
+
+	refcount++;
+done:
+	return NL_SKIP;
+}
+
+static int
+list_switch(struct nl_msg *msg, void *arg)
+{
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+	if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
+		goto done;
+
+	if (!tb[SWITCH_ATTR_DEV_NAME] || !tb[SWITCH_ATTR_NAME])
+		goto done;
+
+	printf("Found: %s - %s\n", nla_get_string(tb[SWITCH_ATTR_DEV_NAME]),
+		nla_get_string(tb[SWITCH_ATTR_ALIAS]));
+
+done:
+	return NL_SKIP;
+}
+
+void
+swlib_list(void)
+{
+	if (swlib_priv_init() < 0)
+		return;
+	swlib_call(SWITCH_CMD_GET_SWITCH, list_switch, NULL, NULL);
+	swlib_priv_free();
+}
+
+void
+swlib_print_portmap(struct switch_dev *dev, char *segment)
+{
+	int i;
+
+	if (segment) {
+		if (!strcmp(segment, "cpu")) {
+			printf("%d ", dev->cpu_port);
+		} else if (!strcmp(segment, "disabled")) {
+			for (i = 0; i < dev->ports; i++)
+				if (!dev->maps[i].segment)
+					printf("%d ", i);
+		} else for (i = 0; i < dev->ports; i++) {
+			if (dev->maps[i].segment && !strcmp(dev->maps[i].segment, segment))
+				printf("%d ", i);
+		}
+	} else {
+		printf("%s - %s\n", dev->dev_name, dev->name);
+		for (i = 0; i < dev->ports; i++)
+			if (i == dev->cpu_port)
+				printf("port%d:\tcpu\n", i);
+			else if (dev->maps[i].segment)
+				printf("port%d:\t%s.%d\n", i, dev->maps[i].segment, dev->maps[i].virt);
+			else
+				printf("port%d:\tdisabled\n", i);
+	}
+}
+
+struct switch_dev *
+swlib_connect(const char *name)
+{
+	struct swlib_scan_arg arg;
+
+	if (!refcount) {
+		if (swlib_priv_init() < 0)
+			return NULL;
+	};
+
+	arg.head = NULL;
+	arg.ptr = NULL;
+	arg.name = name;
+	swlib_call(SWITCH_CMD_GET_SWITCH, add_switch, NULL, &arg);
+
+	if (!refcount)
+		swlib_priv_free();
+
+	return arg.head;
+}
+
+static void
+swlib_free_attributes(struct switch_attr **head)
+{
+	struct switch_attr *a = *head;
+	struct switch_attr *next;
+
+	while (a) {
+		next = a->next;
+		free(a->name);
+		free(a->description);
+		free(a);
+		a = next;
+	}
+	*head = NULL;
+}
+
+static void
+swlib_free_port_map(struct switch_dev *dev)
+{
+	int i;
+
+	if (!dev || !dev->maps)
+		return;
+
+	for (i = 0; i < dev->ports; i++)
+		free(dev->maps[i].segment);
+	free(dev->maps);
+}
+
+void
+swlib_free(struct switch_dev *dev)
+{
+	swlib_free_attributes(&dev->ops);
+	swlib_free_attributes(&dev->port_ops);
+	swlib_free_attributes(&dev->vlan_ops);
+	swlib_free_port_map(dev);
+	free(dev->name);
+	free(dev->alias);
+	free(dev);
+
+	if (--refcount == 0)
+		swlib_priv_free();
+}
+
+void
+swlib_free_all(struct switch_dev *dev)
+{
+	struct switch_dev *p;
+
+	while (dev) {
+		p = dev->next;
+		swlib_free(dev);
+		dev = p;
+	}
+}
diff --git a/package/network/config/swconfig/src/swlib.h b/package/network/config/swconfig/src/swlib.h
new file mode 100644
index 0000000000..3826a5e340
--- /dev/null
+++ b/package/network/config/swconfig/src/swlib.h
@@ -0,0 +1,269 @@
+/*
+ * swlib.h: Switch configuration API (user space part)
+ *
+ * Copyright (C) 2008-2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+
+Usage of the library functions:
+
+  The main datastructure for a switch is the struct switch_device
+  To get started, you first need to use switch_connect() to probe
+  for switches and allocate an instance of this struct.
+
+  There are two possible usage modes:
+    dev = switch_connect("eth0");
+      - this call will look for a switch registered for the linux device
+  	  "eth0" and only allocate a switch_device for this particular switch.
+
+    dev = switch_connect(NULL)
+      - this will return one switch_device struct for each available
+  	  switch. The switch_device structs are chained with by ->next pointer
+
+  Then to query a switch for all available attributes, use:
+    swlib_scan(dev);
+
+  All allocated datastructures for the switch_device struct can be freed with
+    swlib_free(dev);
+  or
+    swlib_free_all(dev);
+
+  The latter traverses a whole chain of switch_device structs and frees them all
+
+  Switch attributes (struct switch_attr) are divided into three groups:
+    dev->ops:
+      - global settings
+    dev->port_ops:
+      - per-port settings
+    dev->vlan_ops:
+      - per-vlan settings
+
+  switch_lookup_attr() is a small helper function to locate attributes
+  by name.
+
+  switch_set_attr() and switch_get_attr() can alter or request the values
+  of attributes.
+
+Usage of the switch_attr struct:
+
+  ->atype: attribute group, one of:
+    - SWLIB_ATTR_GROUP_GLOBAL
+    - SWLIB_ATTR_GROUP_VLAN
+    - SWLIB_ATTR_GROUP_PORT
+
+  ->id: identifier for the attribute
+
+  ->type: data type, one of:
+    - SWITCH_TYPE_INT
+    - SWITCH_TYPE_STRING
+    - SWITCH_TYPE_PORT
+
+  ->name: short name of the attribute
+  ->description: longer description
+  ->next: pointer to the next attribute of the current group
+
+
+Usage of the switch_val struct:
+
+  When setting attributes, following members of the struct switch_val need
+  to be set up:
+
+    ->len (for attr->type == SWITCH_TYPE_PORT)
+    ->port_vlan:
+      - port number (for attr->atype == SWLIB_ATTR_GROUP_PORT), or:
+      - vlan number (for attr->atype == SWLIB_ATTR_GROUP_VLAN)
+    ->value.i (for attr->type == SWITCH_TYPE_INT)
+    ->value.s (for attr->type == SWITCH_TYPE_STRING)
+      - owned by the caller, not stored in the library internally
+    ->value.ports (for attr->type == SWITCH_TYPE_PORT)
+      - must point to an array of at lest val->len * sizeof(struct switch_port)
+
+  When getting string attributes, val->value.s must be freed by the caller
+  When getting port list attributes, an internal static buffer is used,
+  which changes from call to call.
+
+ */
+
+#ifndef __SWLIB_H
+#define __SWLIB_H
+
+enum swlib_attr_group {
+	SWLIB_ATTR_GROUP_GLOBAL,
+	SWLIB_ATTR_GROUP_VLAN,
+	SWLIB_ATTR_GROUP_PORT,
+};
+
+enum swlib_port_flags {
+	SWLIB_PORT_FLAG_TAGGED = (1 << 0),
+};
+
+enum swlib_link_flags {
+	SWLIB_LINK_FLAG_EEE_100BASET = (1 << 0),
+	SWLIB_LINK_FLAG_EEE_1000BASET = (1 << 1),
+};
+
+struct switch_dev;
+struct switch_attr;
+struct switch_port;
+struct switch_port_map;
+struct switch_port_link;
+struct switch_val;
+struct uci_package;
+
+struct switch_dev {
+	int id;
+	char dev_name[IFNAMSIZ];
+	char *name;
+	char *alias;
+	int ports;
+	int vlans;
+	int cpu_port;
+	struct switch_attr *ops;
+	struct switch_attr *port_ops;
+	struct switch_attr *vlan_ops;
+	struct switch_portmap *maps;
+	struct switch_dev *next;
+	void *priv;
+};
+
+struct switch_val {
+	struct switch_attr *attr;
+	int len;
+	int err;
+	int port_vlan;
+	union {
+		char *s;
+		int i;
+		struct switch_port *ports;
+		struct switch_port_link *link;
+	} value;
+};
+
+struct switch_attr {
+	struct switch_dev *dev;
+	int atype;
+	int id;
+	int type;
+	char *name;
+	char *description;
+	struct switch_attr *next;
+};
+
+struct switch_port {
+	unsigned int id;
+	unsigned int flags;
+};
+
+struct switch_portmap {
+	unsigned int virt;
+	char *segment;
+};
+
+struct switch_port_link {
+	int link:1;
+	int duplex:1;
+	int aneg:1;
+	int tx_flow:1;
+	int rx_flow:1;
+	int speed;
+	/* in ethtool adv_t format */
+	uint32_t eee;
+};
+
+/**
+ * swlib_list: list all switches
+ */
+void swlib_list(void);
+
+/**
+ * swlib_print_portmap: get portmap
+ * @dev: switch device struct
+ */
+void swlib_print_portmap(struct switch_dev *dev, char *segment);
+
+/**
+ * swlib_connect: connect to the switch through netlink
+ * @name: name of the ethernet interface,
+ *
+ * if name is NULL, it connect and builds a chain of all switches
+ */
+struct switch_dev *swlib_connect(const char *name);
+
+/**
+ * swlib_free: free all dynamically allocated data for the switch connection
+ * @dev: switch device struct
+ *
+ * all members of a switch device chain (generated by swlib_connect(NULL))
+ * must be freed individually
+ */
+void swlib_free(struct switch_dev *dev);
+
+/**
+ * swlib_free_all: run swlib_free on all devices in the chain
+ * @dev: switch device struct
+ */
+void swlib_free_all(struct switch_dev *dev);
+
+/**
+ * swlib_scan: probe the switch driver for available commands/attributes
+ * @dev: switch device struct
+ */
+int swlib_scan(struct switch_dev *dev);
+
+/**
+ * swlib_lookup_attr: look up a switch attribute
+ * @dev: switch device struct
+ * @type: global, port or vlan
+ * @name: name of the attribute
+ */
+struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
+		enum swlib_attr_group atype, const char *name);
+
+/**
+ * swlib_set_attr: set the value for an attribute
+ * @dev: switch device struct
+ * @attr: switch attribute struct
+ * @val: attribute value pointer
+ * returns 0 on success
+ */
+int swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr,
+		struct switch_val *val);
+
+/**
+ * swlib_set_attr_string: set the value for an attribute with type conversion
+ * @dev: switch device struct
+ * @attr: switch attribute struct
+ * @port_vlan: port or vlan (if applicable)
+ * @str: string value
+ * returns 0 on success
+ */
+int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *attr,
+		int port_vlan, const char *str);
+
+/**
+ * swlib_get_attr: get the value for an attribute
+ * @dev: switch device struct
+ * @attr: switch attribute struct
+ * @val: attribute value pointer
+ * returns 0 on success
+ * for string attributes, the result string must be freed by the caller
+ */
+int swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr,
+		struct switch_val *val);
+
+/**
+ * swlib_apply_from_uci: set up the switch from a uci configuration
+ * @dev: switch device struct
+ * @p: uci package which contains the desired global config
+ */
+int swlib_apply_from_uci(struct switch_dev *dev, struct uci_package *p);
+
+#endif
diff --git a/package/network/config/swconfig/src/uci.c b/package/network/config/swconfig/src/uci.c
new file mode 100644
index 0000000000..b541b71646
--- /dev/null
+++ b/package/network/config/swconfig/src/uci.c
@@ -0,0 +1,246 @@
+/*
+ * uci.c: UCI binding for the switch configuration utility
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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 Foundatio.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <uci.h>
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/switch.h>
+#include "swlib.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+struct swlib_setting {
+	struct switch_attr *attr;
+	const char *name;
+	int port_vlan;
+	const char *val;
+	struct swlib_setting *next;
+};
+
+struct swlib_setting early_settings[] = {
+	{ .name = "reset", .val = "1" },
+	{ .name = "enable_vlan", .val = "1" },
+};
+
+static struct swlib_setting *settings;
+static struct swlib_setting **head;
+
+static bool swlib_match_name(struct switch_dev *dev, const char *name)
+{
+	return (strcmp(name, dev->dev_name) == 0 ||
+		strcmp(name, dev->alias) == 0);
+}
+
+static int
+swlib_map_settings(struct switch_dev *dev, int type, int port_vlan, struct uci_section *s)
+{
+	struct swlib_setting *setting;
+	struct switch_attr *attr;
+	struct uci_element *e;
+	struct uci_option *o;
+
+	uci_foreach_element(&s->options, e) {
+		o = uci_to_option(e);
+
+		if (o->type != UCI_TYPE_STRING)
+			continue;
+
+		if (!strcmp(e->name, "device"))
+			continue;
+
+		/* map early settings */
+		if (type == SWLIB_ATTR_GROUP_GLOBAL) {
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
+				if (strcmp(e->name, early_settings[i].name) != 0)
+					continue;
+
+				early_settings[i].val = o->v.string;
+				goto skip;
+			}
+		}
+
+		attr = swlib_lookup_attr(dev, type, e->name);
+		if (!attr)
+			continue;
+
+		setting = malloc(sizeof(struct swlib_setting));
+		memset(setting, 0, sizeof(struct swlib_setting));
+		setting->attr = attr;
+		setting->port_vlan = port_vlan;
+		setting->val = o->v.string;
+		*head = setting;
+		head = &setting->next;
+skip:
+		continue;
+	}
+}
+
+int swlib_apply_from_uci(struct switch_dev *dev, struct uci_package *p)
+{
+	struct switch_attr *attr;
+	struct uci_element *e;
+	struct uci_section *s;
+	struct uci_option *o;
+	struct uci_ptr ptr;
+	struct switch_val val;
+	int i;
+
+	settings = NULL;
+	head = &settings;
+
+	uci_foreach_element(&p->sections, e) {
+		struct uci_element *n;
+
+		s = uci_to_section(e);
+
+		if (strcmp(s->type, "switch") != 0)
+			continue;
+
+		uci_foreach_element(&s->options, n) {
+			struct uci_option *o = uci_to_option(n);
+
+			if (strcmp(n->name, "name") != 0)
+				continue;
+
+			if (o->type != UCI_TYPE_STRING)
+				continue;
+
+			if (swlib_match_name(dev, o->v.string))
+				goto found;
+
+			break;
+		}
+
+		if (!swlib_match_name(dev, e->name))
+			continue;
+
+		goto found;
+	}
+
+	/* not found */
+	return -1;
+
+found:
+	/* look up available early options, which need to be taken care
+	 * of in the correct order */
+	for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
+		early_settings[i].attr = swlib_lookup_attr(dev,
+			SWLIB_ATTR_GROUP_GLOBAL, early_settings[i].name);
+	}
+	swlib_map_settings(dev, SWLIB_ATTR_GROUP_GLOBAL, 0, s);
+
+	/* look for port or vlan sections */
+	uci_foreach_element(&p->sections, e) {
+		struct uci_element *os;
+		s = uci_to_section(e);
+
+		if (!strcmp(s->type, "switch_port")) {
+			char *devn, *port, *port_err = NULL;
+			int port_n;
+
+			uci_foreach_element(&s->options, os) {
+				o = uci_to_option(os);
+				if (o->type != UCI_TYPE_STRING)
+					continue;
+
+				if (!strcmp(os->name, "device")) {
+					devn = o->v.string;
+					if (!swlib_match_name(dev, devn))
+						devn = NULL;
+				} else if (!strcmp(os->name, "port")) {
+					port = o->v.string;
+				}
+			}
+			if (!devn || !port || !port[0])
+				continue;
+
+			port_n = strtoul(port, &port_err, 0);
+			if (port_err && port_err[0])
+				continue;
+
+			swlib_map_settings(dev, SWLIB_ATTR_GROUP_PORT, port_n, s);
+		} else if (!strcmp(s->type, "switch_vlan")) {
+			char *devn, *vlan, *vlan_err = NULL;
+			int vlan_n;
+
+			uci_foreach_element(&s->options, os) {
+				o = uci_to_option(os);
+				if (o->type != UCI_TYPE_STRING)
+					continue;
+
+				if (!strcmp(os->name, "device")) {
+					devn = o->v.string;
+					if (!swlib_match_name(dev, devn))
+						devn = NULL;
+				} else if (!strcmp(os->name, "vlan")) {
+					vlan = o->v.string;
+				}
+			}
+			if (!devn || !vlan || !vlan[0])
+				continue;
+
+			vlan_n = strtoul(vlan, &vlan_err, 0);
+			if (vlan_err && vlan_err[0])
+				continue;
+
+			swlib_map_settings(dev, SWLIB_ATTR_GROUP_VLAN, vlan_n, s);
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
+		struct swlib_setting *st = &early_settings[i];
+		if (!st->attr || !st->val)
+			continue;
+		swlib_set_attr_string(dev, st->attr, st->port_vlan, st->val);
+
+	}
+
+	while (settings) {
+		struct swlib_setting *st = settings;
+
+		swlib_set_attr_string(dev, st->attr, st->port_vlan, st->val);
+		st = st->next;
+		free(settings);
+		settings = st;
+	}
+
+	/* Apply the config */
+	attr = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, "apply");
+	if (!attr)
+		return 0;
+
+	memset(&val, 0, sizeof(val));
+	swlib_set_attr(dev, attr, &val);
+
+	return 0;
+}
diff --git a/package/network/config/vti/Makefile b/package/network/config/vti/Makefile
new file mode 100644
index 0000000000..7cf0ee913d
--- /dev/null
+++ b/package/network/config/vti/Makefile
@@ -0,0 +1,65 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=vti
+PKG_VERSION:=1
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/vti/Default
+  SECTION:=net
+  CATEGORY:=Network
+  MAINTAINER:=Andre Valentin <avalentin@marcant.net>
+endef
+
+define Package/vti
+$(call Package/vti/Default)
+  TITLE:=Virtual IPsec Tunnel Interface config support
+endef
+
+define Package/vti/description
+ Virtual IPsec Tunnel Interface config support (IPv4 and IPv6) in /etc/config/network.
+endef
+
+define Package/vtiv4
+$(call Package/vti/Default)
+  TITLE:=Virtual IPsec Tunnel Interface (IPv4) config support
+  DEPENDS:=@(PACKAGE_vti) +kmod-ip-vti
+endef
+
+define Package/vtiv4/description
+ Virtual IPsec Tunnel Interface config support (IPv4) in /etc/config/network.
+endef
+
+define Package/vtiv6
+$(call Package/vti/Default)
+  TITLE:=Virtual IPsec Tunnel Interface (IPv6) config support
+  DEPENDS:=@(PACKAGE_vti) @IPV6 +kmod-ip6-vti
+endef
+
+define Package/vtiv6/description
+ Virtual IPsec Tunnel Interface config support (IPv6) in /etc/config/network.
+endef
+
+define Build/Compile
+endef
+
+define Build/Configure
+endef
+
+define Package/vti/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/vti.sh $(1)/lib/netifd/proto/vti.sh
+endef
+
+$(eval $(call BuildPackage,vti))
+$(eval $(call BuildPackage,vtiv4))
+$(eval $(call BuildPackage,vtiv6))
diff --git a/package/network/config/vti/files/vti.sh b/package/network/config/vti/files/vti.sh
new file mode 100755
index 0000000000..763fd4ee32
--- /dev/null
+++ b/package/network/config/vti/files/vti.sh
@@ -0,0 +1,151 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+vti_generic_setup() {
+	local cfg="$1"
+	local mode="$2"
+	local local="$3"
+	local remote="$4"
+	local link="$5"
+	local mtu zone ikey
+	json_get_vars mtu zone ikey okey
+
+	[ -z "$zone" ] && zone="wan"
+
+	proto_init_update "$link" 1
+
+	proto_add_tunnel
+	json_add_string mode "$mode"
+	json_add_int mtu "${mtu:-1280}"
+	json_add_string local "$local"
+	json_add_string remote "$remote"
+	[ -n "$tunlink" ] && json_add_string link "$tunlink"
+	json_add_string info "${ikey:-0},${okey:-0}"
+	proto_close_tunnel
+
+	proto_add_data
+	[ -n "$zone" ] && json_add_string zone "$zone"
+	proto_close_data
+
+	proto_send_update "$cfg"
+}
+
+vti_setup() {
+	local cfg="$1"
+	local mode="$2"
+
+	local ipaddr peeraddr
+	json_get_vars df ipaddr peeraddr tunlink
+
+	[ -z "$peeraddr" ] && {
+		proto_notify_error "$cfg" "MISSING_ADDRESS"
+		proto_block_restart "$cfg"
+		exit
+	}
+
+	( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+
+	[ -z "$ipaddr" ] && {
+		local wanif="$tunlink"
+		if [ -z $wanif ] && ! network_find_wan wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			exit
+		fi
+
+		if ! network_get_ipaddr ipaddr "$wanif"; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			exit
+		fi
+	}
+
+	vti_generic_setup $cfg $mode $ipaddr $peeraddr "vti-$cfg"
+}
+
+proto_vti_setup() {
+	local cfg="$1"
+
+	vti_setup $cfg "vtiip"
+}
+
+vti6_setup() {
+	local cfg="$1"
+	local mode="$2"
+
+	local ip6addr peer6addr weakif
+	json_get_vars ip6addr peer6addr tunlink weakif
+
+	[ -z "$peer6addr" ] && {
+		proto_notify_error "$cfg" "MISSING_ADDRESS"
+		proto_block_restart "$cfg"
+		exit
+	}
+
+	( proto_add_host_dependency "$cfg" "$peer6addr" "$tunlink" )
+
+	[ -z "$ip6addr" ] && {
+		local wanif="$tunlink"
+		if [ -z $wanif ] && ! network_find_wan6 wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			exit
+		fi
+
+		if ! network_get_ipaddr6 ip6addr "$wanif"; then
+			[ -z "$weakif" ] && weakif="lan"
+			if ! network_get_ipaddr6 ip6addr "$weakif"; then
+				proto_notify_error "$cfg" "NO_WAN_LINK"
+				exit
+			fi
+		fi
+	}
+
+	vti_generic_setup $cfg $mode $ip6addr $peer6addr "vti6-$cfg"
+}
+
+proto_vti6_setup() {
+	local cfg="$1"
+
+	vti6_setup $cfg "vtiip6"
+}
+
+proto_vti_teardown() {
+	local cfg="$1"
+}
+
+proto_vti6_teardown() {
+	local cfg="$1"
+}
+
+vti_generic_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_int "mtu"
+	proto_config_add_string "tunlink"
+	proto_config_add_string "zone"
+	proto_config_add_int "ikey"
+	proto_config_add_int "okey"
+}
+
+proto_vti_init_config() {
+	vti_generic_init_config
+	proto_config_add_string "ipaddr"
+	proto_config_add_string "peeraddr"
+}
+
+proto_vti6_init_config() {
+	vti_generic_init_config
+	proto_config_add_string "ip6addr"
+	proto_config_add_string "peer6addr"
+	proto_config_add_string "weakif"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	[ -f /lib/modules/$(uname -r)/ip_vti.ko ] && add_protocol vti
+	[ -f /lib/modules/$(uname -r)/ip6_vti.ko ] && add_protocol vti6
+}
diff --git a/package/network/ipv6/6in4/Makefile b/package/network/ipv6/6in4/Makefile
new file mode 100644
index 0000000000..34227ce9ef
--- /dev/null
+++ b/package/network/ipv6/6in4/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2010-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=6in4
+PKG_VERSION:=24
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/6in4
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@IPV6 +kmod-sit +uclient-fetch
+  TITLE:=IPv6-in-IPv4 configuration support
+  MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+  PKGARCH:=all
+endef
+
+define Package/6in4/description
+Provides support for 6in4 tunnels in /etc/config/network.
+Refer to http://wiki.openwrt.org/doc/uci/network for
+configuration details.
+endef
+
+define Build/Compile
+endef
+
+define Build/Configure
+endef
+
+define Package/6in4/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/6in4.sh $(1)/lib/netifd/proto/6in4.sh
+endef
+
+$(eval $(call BuildPackage,6in4))
diff --git a/package/network/ipv6/6in4/files/6in4.sh b/package/network/ipv6/6in4/files/6in4.sh
new file mode 100755
index 0000000000..45d8ab75ad
--- /dev/null
+++ b/package/network/ipv6/6in4/files/6in4.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+# 6in4.sh - IPv6-in-IPv4 tunnel backend
+# Copyright (c) 2010-2015 OpenWrt.org
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_6in4_update() {
+	sh -c '
+		timeout=5
+
+		(while [ $((timeout--)) -gt 0 ]; do
+			sleep 1
+			kill -0 $$ || exit 0
+		done; kill -9 $$) 2>/dev/null &
+
+		exec "$@"
+	' "$1" "$@"
+}
+
+proto_6in4_setup() {
+	local cfg="$1"
+	local iface="$2"
+	local link="6in4-$cfg"
+
+	local mtu ttl tos ipaddr peeraddr ip6addr ip6prefix tunlink tunnelid username password updatekey
+	json_get_vars mtu ttl tos ipaddr peeraddr ip6addr ip6prefix tunlink tunnelid username password updatekey
+
+	[ -z "$peeraddr" ] && {
+		proto_notify_error "$cfg" "MISSING_ADDRESS"
+		proto_block_restart "$cfg"
+		return
+	}
+
+	( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+
+	[ -z "$ipaddr" ] && {
+		local wanif="$tunlink"
+		if [ -z "$wanif" ] && ! network_find_wan wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+
+		if ! network_get_ipaddr ipaddr "$wanif"; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+	}
+
+	proto_init_update "$link" 1
+
+	[ -n "$ip6addr" ] && {
+		local local6="${ip6addr%%/*}"
+		local mask6="${ip6addr##*/}"
+		[[ "$local6" = "$mask6" ]] && mask6=
+		proto_add_ipv6_address "$local6" "$mask6"
+		proto_add_ipv6_route "::" 0 "" "" "" "$local6/$mask6"
+	}
+
+	[ -n "$ip6prefix" ] && {
+		proto_add_ipv6_prefix "$ip6prefix"
+		proto_add_ipv6_route "::" 0 "" "" "" "$ip6prefix"
+	}
+
+	proto_add_tunnel
+	json_add_string mode sit
+	json_add_int mtu "${mtu:-1280}"
+	json_add_int ttl "${ttl:-64}"
+	[ -n "$tos" ] && json_add_string tos "$tos"
+	json_add_string local "$ipaddr"
+	json_add_string remote "$peeraddr"
+	[ -n "$tunlink" ] && json_add_string link "$tunlink"
+	proto_close_tunnel
+
+	proto_send_update "$cfg"
+
+	[ -n "$tunnelid" -a -n "$username" -a \( -n "$password" -o -n "$updatekey" \) ] && {
+		[ -n "$updatekey" ] && password="$updatekey"
+
+		local http="http"
+		local urlget="uclient-fetch"
+		local urlget_opts="-qO-"
+		local ca_path="${SSL_CERT_DIR-/etc/ssl/certs}"
+
+		[ -f /lib/libustream-ssl.so ] && http=https
+		[ "$http" = "https" -a -z "$(find $ca_path -name "*.0" 2>/dev/null)" ] && {
+			urlget_opts="$urlget_opts --no-check-certificate"
+		}
+
+		local url="$http://ipv4.tunnelbroker.net/nic/update?hostname=$tunnelid"
+		local try=0
+		local max=3
+
+		(
+			set -o pipefail
+			while [ $((++try)) -le $max ]; do
+				if proto_6in4_update $urlget $urlget_opts --user="$username" --password="$password" "$url" 2>&1 | \
+					sed -e 's,^Killed$,timeout,' -e "s,^,update $try/$max: ," | \
+					logger -t "$link";
+				then
+					logger -t "$link" "updated"
+					return 0
+				fi
+				sleep 5
+			done
+			logger -t "$link" "update failed"
+		)
+	}
+}
+
+proto_6in4_teardown() {
+	local cfg="$1"
+}
+
+proto_6in4_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_string "ipaddr"
+	proto_config_add_string "ip6addr"
+	proto_config_add_string "ip6prefix"
+	proto_config_add_string "peeraddr"
+	proto_config_add_string "tunlink"
+	proto_config_add_string "tunnelid"
+	proto_config_add_string "username"
+	proto_config_add_string "password"
+	proto_config_add_string "updatekey"
+	proto_config_add_int "mtu"
+	proto_config_add_int "ttl"
+	proto_config_add_string "tos"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol 6in4
+}
diff --git a/package/network/ipv6/6rd/Makefile b/package/network/ipv6/6rd/Makefile
new file mode 100644
index 0000000000..899c0f13f2
--- /dev/null
+++ b/package/network/ipv6/6rd/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2010-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=6rd
+PKG_VERSION:=9
+PKG_RELEASE:=2
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/6rd
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@IPV6 +kmod-sit
+  TITLE:=6rd configuration support
+  MAINTAINER:=Steven Barth <cyrus@openwrt.org>
+  PKGARCH:=all
+endef
+
+define Package/6rd/description
+Provides support for 6rd tunnels in /etc/config/network.
+Refer to http://wiki.openwrt.org/doc/uci/network for
+configuration details.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall" \
+		LDFLAGS="$(TARGET_LDFLAGS)"
+endef
+
+define Package/6rd/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/6rdcalc $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/6rd.sh $(1)/lib/netifd/proto/6rd.sh
+endef
+
+$(eval $(call BuildPackage,6rd))
diff --git a/package/network/ipv6/6rd/files/6rd.sh b/package/network/ipv6/6rd/files/6rd.sh
new file mode 100644
index 0000000000..62d35b6994
--- /dev/null
+++ b/package/network/ipv6/6rd/files/6rd.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+# 6rd.sh - IPv6-in-IPv4 tunnel backend
+# Copyright (c) 2010-2012 OpenWrt.org
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_6rd_setup() {
+	local cfg="$1"
+	local iface="$2"
+	local link="6rd-$cfg"
+
+	local mtu df ttl tos ipaddr peeraddr ip6prefix ip6prefixlen ip4prefixlen tunlink zone
+	json_get_vars mtu df ttl tos ipaddr peeraddr ip6prefix ip6prefixlen ip4prefixlen tunlink zone
+
+	[ -z "$ip6prefix" -o -z "$peeraddr" ] && {
+		proto_notify_error "$cfg" "MISSING_ADDRESS"
+		proto_block_restart "$cfg"
+		return
+	}
+
+	( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
+
+	[ -z "$ipaddr" ] && {
+		local wanif="$tunlink"
+		if [ -z $wanif ] && ! network_find_wan wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+
+		if ! network_get_ipaddr ipaddr "$wanif"; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+	}
+
+	# Determine the relay prefix.
+	local ip4prefixlen="${ip4prefixlen:-0}"
+	local ip4prefix=$(ipcalc.sh "$ipaddr/$ip4prefixlen" | grep NETWORK)
+	ip4prefix="${ip4prefix#NETWORK=}"
+
+	# Determine our IPv6 address.
+	local ip6subnet=$(6rdcalc "$ip6prefix/$ip6prefixlen" "$ipaddr/$ip4prefixlen")
+	local ip6addr="${ip6subnet%%::*}::1"
+
+	# Determine the IPv6 prefix
+	local ip6lanprefix="$ip6subnet/$(($ip6prefixlen + 32 - $ip4prefixlen))"
+
+	proto_init_update "$link" 1
+	proto_add_ipv6_address "$ip6addr" "$ip6prefixlen"
+	proto_add_ipv6_prefix "$ip6lanprefix"
+
+	proto_add_ipv6_route "::" 0 "::$peeraddr" 4096 "" "$ip6addr/$ip6prefixlen"
+	proto_add_ipv6_route "::" 0 "::$peeraddr" 4096 "" "$ip6lanprefix"
+
+	proto_add_tunnel
+	json_add_string mode sit
+	json_add_int mtu "${mtu:-1280}"
+	json_add_boolean df "${df:-1}"
+	json_add_int ttl "${ttl:-64}"
+	[ -n "$tos" ] && json_add_string tos "$tos"
+	json_add_string local "$ipaddr"
+	json_add_string 6rd-prefix "$ip6prefix/$ip6prefixlen"
+	json_add_string 6rd-relay-prefix "$ip4prefix/$ip4prefixlen"
+	[ -n "$tunlink" ] && json_add_string link "$tunlink"
+	proto_close_tunnel
+
+	proto_add_data
+	[ -n "$zone" ] && json_add_string zone "$zone"
+	proto_close_data
+
+	proto_send_update "$cfg"
+}
+
+proto_6rd_teardown() {
+	local cfg="$1"
+}
+
+proto_6rd_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_int "mtu"
+	proto_config_add_boolean "df"
+	proto_config_add_int "ttl"
+	proto_config_add_string "tos"
+	proto_config_add_string "ipaddr"
+	proto_config_add_string "peeraddr"
+	proto_config_add_string "ip6prefix"
+	proto_config_add_string "ip6prefixlen"
+	proto_config_add_string "ip4prefixlen"
+	proto_config_add_string "tunlink"
+	proto_config_add_string "zone"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol 6rd
+}
diff --git a/package/network/ipv6/6rd/src/6rdcalc.c b/package/network/ipv6/6rd/src/6rdcalc.c
new file mode 100644
index 0000000000..87bc397006
--- /dev/null
+++ b/package/network/ipv6/6rd/src/6rdcalc.c
@@ -0,0 +1,126 @@
+/*
+ * Utility used to calculate the 6rd subnet.
+ *
+ * Copyright 2012, Stéphan Kochen <stephan@kochen.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define INET_PREFIXSTRLEN (INET_ADDRSTRLEN+3)
+#define INET6_PREFIXSTRLEN (INET6_ADDRSTRLEN+4)
+
+static void print_usage()
+{
+	fprintf(stderr, "Usage: 6rdcalc <v6 prefix>/<mask> <v4 address>/<mask>\n");
+	exit(1);
+}
+
+static void print_error()
+{
+	fprintf(stderr, "%s", strerror(errno));
+	exit(1);
+}
+
+static void parse_str(int af, char *str, void *addr, unsigned long *mask)
+{
+	int ret;
+	char *slash;
+
+	/* Split the address at the slash. */
+	if ((slash = strchr(str, '/')) == NULL)
+		print_usage();
+	*slash = '\0';
+
+	/* Parse the address. */
+	if ((ret = inet_pton(af, str, addr)) != 1) {
+		if (ret == 0)
+			print_usage();
+		else
+			print_error();
+	}
+
+	/* Parse the mask. */
+	*mask = strtoul(slash+1, NULL, 10);
+	if ((af == AF_INET  && *mask >  32) ||
+		(af == AF_INET6 && *mask > 128))
+		print_usage();
+}
+
+int main(int argc, const char **argv)
+{
+	char v6str[INET6_PREFIXSTRLEN], v4str[INET_PREFIXSTRLEN];
+	struct in6_addr v6;
+	struct in_addr v4;
+	unsigned long v6it, v4it, mask;
+	unsigned char *byte4, *byte6;
+	unsigned char bit4, bit6;
+
+	/* Check parameters. */
+	if (argc != 3)
+		print_usage();
+
+	/* Parse the v6 address. */
+	strncpy(v6str, argv[1], INET6_PREFIXSTRLEN);
+	v6str[INET6_PREFIXSTRLEN-1] = '\0';
+	parse_str(AF_INET6, v6str, &v6, &v6it);
+
+	/* Parse the v4 address */
+	strncpy(v4str, argv[2], INET_PREFIXSTRLEN);
+	v6str[INET_PREFIXSTRLEN-1] = '\0';
+	parse_str(AF_INET, v4str, &v4, &v4it);
+
+	/* Check if the combined mask is within bounds. */
+	mask = (32 - v4it) + v6it;
+	if (mask > 128)
+		print_usage();
+
+	/* Combine the addresses. */
+	while (v4it < 32) {
+		byte6 = (unsigned char *)(&v6.s6_addr) + (v6it >> 3);
+		byte4 = (unsigned char *)(&v4.s_addr)  + (v4it >> 3);
+		bit6 = 128 >> (v6it & 0x07);
+		bit4 = 128 >> (v4it & 0x07);
+
+		if (*byte4 & bit4)
+			*byte6 |= bit6;
+		else
+			*byte6 &= ~bit6;
+
+		v4it++; v6it++;
+	}
+
+	/* Clear remaining bits. */
+	while (v6it < 128) {
+		byte6 = (unsigned char *)(&v6.s6_addr) + (v6it >> 3);
+		bit6 = 128 >> (v6it & 0x07);
+
+		*byte6 &= ~bit6;
+
+		v6it++;
+	}
+
+	/* Print the subnet prefix. */
+	if (inet_ntop(AF_INET6, &v6, v6str, sizeof(v6str)) == NULL)
+		print_error();
+	printf("%s/%lu\n", v6str, mask);
+	return 0;
+}
diff --git a/package/network/ipv6/6rd/src/Makefile b/package/network/ipv6/6rd/src/Makefile
new file mode 100644
index 0000000000..2881d43589
--- /dev/null
+++ b/package/network/ipv6/6rd/src/Makefile
@@ -0,0 +1,7 @@
+all: 6rdcalc
+
+6rdcalc: 6rdcalc.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+
+clean:
+	rm -f 6rdcalc
diff --git a/package/network/ipv6/6to4/Makefile b/package/network/ipv6/6to4/Makefile
new file mode 100644
index 0000000000..20605f6588
--- /dev/null
+++ b/package/network/ipv6/6to4/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2010-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=6to4
+PKG_VERSION:=12
+PKG_RELEASE:=2
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/6to4
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@IPV6 +kmod-sit
+  TITLE:=IPv6-to-IPv4 configuration support
+  MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+  PKGARCH:=all
+endef
+
+define Package/6to4/description
+Provides support for 6to4 tunnels in /etc/config/network.
+Refer to http://wiki.openwrt.org/doc/uci/network for
+configuration details.
+endef
+
+define Build/Compile
+endef
+
+define Build/Configure
+endef
+
+define Package/6to4/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/6to4.sh $(1)/lib/netifd/proto/6to4.sh
+endef
+
+$(eval $(call BuildPackage,6to4))
diff --git a/package/network/ipv6/6to4/files/6to4.sh b/package/network/ipv6/6to4/files/6to4.sh
new file mode 100755
index 0000000000..a5d0567af1
--- /dev/null
+++ b/package/network/ipv6/6to4/files/6to4.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+# 6to4.sh - IPv6-in-IPv4 tunnel backend
+# Copyright (c) 2010-2012 OpenWrt.org
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+find_6to4_prefix() {
+	local ip4="$1"
+	local oIFS="$IFS"; IFS="."; set -- $ip4; IFS="$oIFS"
+
+	printf "2002:%02x%02x:%02x%02x\n" $1 $2 $3 $4
+}
+
+test_6to4_rfc1918()
+{
+	local oIFS="$IFS"; IFS="."; set -- $1; IFS="$oIFS"
+	[ $1 -eq  10 ] && return 0
+	[ $1 -eq 192 ] && [ $2 -eq 168 ] && return 0
+	[ $1 -eq 172 ] && [ $2 -ge  16 ] && [ $2 -le  31 ] && return 0
+
+	# RFC 6598
+	[ $1 -eq 100 ] && [ $2 -ge  64 ] && [ $2 -le 127 ] && return 0
+
+	return 1
+}
+
+proto_6to4_setup() {
+	local cfg="$1"
+	local iface="$2"
+	local link="6to4-$cfg"
+
+	local mtu ttl tos ipaddr
+	json_get_vars mtu ttl tos ipaddr
+
+	( proto_add_host_dependency "$cfg" 0.0.0.0 )
+
+	local wanif
+	if ! network_find_wan wanif; then
+		proto_notify_error "$cfg" "NO_WAN_LINK"
+		return
+	fi
+
+	[ -z "$ipaddr" ] && {
+		if ! network_get_ipaddr ipaddr "$wanif"; then
+			proto_notify_error "$cfg" "NO_WAN_ADDRESS"
+			return
+		fi
+	}
+
+	test_6to4_rfc1918 "$ipaddr" && {
+		proto_notify_error "$cfg" "INVALID_LOCAL_ADDRESS"
+		return
+	}
+
+	# find our local prefix
+	local prefix6=$(find_6to4_prefix "$ipaddr")
+	local local6="$prefix6::1"
+
+	proto_init_update "$link" 1
+	proto_add_ipv6_address "$local6" 16
+	proto_add_ipv6_prefix "$prefix6::/48"
+
+	proto_add_ipv6_route "::" 0 "::192.88.99.1" "" "" "$local6/16"
+	proto_add_ipv6_route "::" 0 "::192.88.99.1" "" "" "$prefix6::/48"
+
+	proto_add_tunnel
+	json_add_string mode sit
+	json_add_int mtu "${mtu:-1280}"
+	json_add_int ttl "${ttl:-64}"
+	[ -n "$tos" ] && json_add_string tos "$tos"
+	json_add_string local "$ipaddr"
+	proto_close_tunnel
+
+	proto_send_update "$cfg"
+}
+
+proto_6to4_teardown() {
+	local cfg="$1"
+}
+
+proto_6to4_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_string "ipaddr"
+	proto_config_add_int "mtu"
+	proto_config_add_int "ttl"
+	proto_config_add_string "tos"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol 6to4
+}
diff --git a/package/network/ipv6/ds-lite/Makefile b/package/network/ipv6/ds-lite/Makefile
new file mode 100644
index 0000000000..58e7156b95
--- /dev/null
+++ b/package/network/ipv6/ds-lite/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ds-lite
+PKG_VERSION:=7
+PKG_RELEASE:=2
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ds-lite
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@IPV6 +kmod-ip6-tunnel +resolveip
+  TITLE:=Dual-Stack Lite (DS-Lite) configuration support
+  MAINTAINER:=Steven Barth <steven@midlink.org>
+  PKGARCH:=all
+endef
+
+define Package/ds-lite/description
+Provides support for Dual-Stack Lite in /etc/config/network.
+Refer to http://wiki.openwrt.org/doc/uci/network for
+configuration details.
+endef
+
+define Build/Compile
+endef
+
+define Build/Configure
+endef
+
+define Package/ds-lite/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/dslite.sh $(1)/lib/netifd/proto/dslite.sh
+endef
+
+$(eval $(call BuildPackage,ds-lite))
diff --git a/package/network/ipv6/ds-lite/files/dslite.sh b/package/network/ipv6/ds-lite/files/dslite.sh
new file mode 100755
index 0000000000..2485a424dc
--- /dev/null
+++ b/package/network/ipv6/ds-lite/files/dslite.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+# dslite.sh - IPv4-in-IPv6 tunnel backend
+# Copyright (c) 2013 OpenWrt.org
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_dslite_setup() {
+	local cfg="$1"
+	local iface="$2"
+	local link="ds-$cfg"
+	local remoteip6
+
+	local mtu ttl peeraddr ip6addr tunlink zone weakif
+	json_get_vars mtu ttl peeraddr ip6addr tunlink zone weakif
+
+	[ -z "$peeraddr" ] && {
+		proto_notify_error "$cfg" "MISSING_ADDRESS"
+		proto_block_restart "$cfg"
+		return
+	}
+
+	( proto_add_host_dependency "$cfg" "::" "$tunlink" )
+
+	remoteip6=$(resolveip -6 "$peeraddr")
+	if [ -z "$remoteip6" ]; then
+		sleep 3
+		remoteip6=$(resolveip -6 "$peeraddr")
+		if [ -z "$remoteip6" ]; then
+			proto_notify_error "$cfg" "AFTR_DNS_FAIL"
+			return
+		fi
+	fi
+
+	for ip6 in $remoteip6; do
+		peeraddr=$ip6
+		break
+	done
+
+	[ -z "$ip6addr" ] && {
+		local wanif="$tunlink"
+		if [ -z "$wanif" ] && ! network_find_wan6 wanif; then
+			proto_notify_error "$cfg" "NO_WAN_LINK"
+			return
+		fi
+
+		if ! network_get_ipaddr6 ip6addr "$wanif"; then
+			[ -z "$weakif" ] && weakif="lan"
+			if ! network_get_ipaddr6 ip6addr "$weakif"; then
+				proto_notify_error "$cfg" "NO_WAN_LINK"
+				return
+			fi
+		fi
+	}
+
+	proto_init_update "$link" 1
+	proto_add_ipv4_route "0.0.0.0" 0
+	proto_add_ipv4_address "192.0.0.2" "" "" "192.0.0.1"
+
+	proto_add_tunnel
+	json_add_string mode ipip6
+	json_add_int mtu "${mtu:-1280}"
+	json_add_int ttl "${ttl:-64}"
+	json_add_string local "$ip6addr"
+	json_add_string remote "$peeraddr"
+	[ -n "$tunlink" ] && json_add_string link "$tunlink"
+	proto_close_tunnel
+
+	proto_add_data
+	[ -n "$zone" ] && json_add_string zone "$zone"
+
+	json_add_array firewall
+	  json_add_object ""
+	    json_add_string type nat
+	    json_add_string target ACCEPT
+	  json_close_object
+	json_close_array
+	proto_close_data
+
+	proto_send_update "$cfg"
+}
+
+proto_dslite_teardown() {
+	local cfg="$1"
+}
+
+proto_dslite_init_config() {
+	no_device=1             
+	available=1
+
+	proto_config_add_string "ip6addr"
+	proto_config_add_string "peeraddr"
+	proto_config_add_string "tunlink"
+	proto_config_add_int "mtu"
+	proto_config_add_int "ttl"
+	proto_config_add_string "zone"
+	proto_config_add_string "weakif"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+        add_protocol dslite
+}
diff --git a/package/network/ipv6/map/Makefile b/package/network/ipv6/map/Makefile
new file mode 100644
index 0000000000..8cc1afeda1
--- /dev/null
+++ b/package/network/ipv6/map/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2014-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=map
+PKG_VERSION:=4
+PKG_RELEASE:=5
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/map
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@IPV6 +kmod-ip6-tunnel +libubox +libubus +iptables-mod-conntrack-extra
+  TITLE:=MAP-E and Lightweight 4over6 configuration support
+  MAINTAINER:=Steven Barth <steven@midlink.org>
+endef
+
+define Package/map/description
+ Provides support for MAP-E (draft-ietf-softwire-map) and
+ Lightweight 4over6 (draft-ietf-softwire-lw4over6) in /etc/config/network.
+ Refer to http://wiki.openwrt.org/doc/uci/network for
+ configuration details.
+endef
+
+define Package/map/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/map.sh $(1)/lib/netifd/proto/map.sh
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mapcalc $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,map))
diff --git a/package/network/ipv6/map/files/map.sh b/package/network/ipv6/map/files/map.sh
new file mode 100755
index 0000000000..98a493dd57
--- /dev/null
+++ b/package/network/ipv6/map/files/map.sh
@@ -0,0 +1,221 @@
+#!/bin/sh
+# map.sh - IPv4-in-IPv6 tunnel backend
+#
+# Author: Steven Barth <cyrus@openwrt.org>
+# Copyright (c) 2014 cisco Systems, Inc.
+#
+# 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
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_map_setup() {
+	local cfg="$1"
+	local iface="$2"
+	local link="map-$cfg"
+
+	# uncomment for legacy MAP0 mode
+	#export LEGACY=1
+
+	local type mtu ttl tunlink zone
+	local rule ipaddr ip4prefixlen ip6prefix ip6prefixlen peeraddr ealen psidlen psid offset
+	json_get_vars type mtu ttl tunlink zone
+	json_get_vars rule ipaddr ip4prefixlen ip6prefix ip6prefixlen peeraddr ealen psidlen psid offset
+
+	[ -z "$zone" ] && zone="wan"
+	[ -z "$type" ] && type="map-e"
+	[ -z "$ip4prefixlen" ] && ip4prefixlen=32
+
+	( proto_add_host_dependency "$cfg" "::" "$tunlink" )
+
+	# fixme: handle RA/DHCPv6 address race for LW
+	[ "$type" = lw4o6 ] && sleep 5
+
+	if [ -z "$rule" ]; then
+		rule="type=$type,ipv6prefix=$ip6prefix,prefix6len=$ip6prefixlen,ipv4prefix=$ipaddr,prefix4len=$ip4prefixlen"
+		[ -n "$psid" ] && rule="$rule,psid=$psid"
+		[ -n "$psidlen" ] && rule="$rule,psidlen=$psidlen"
+		[ -n "$offset" ] && rule="$rule,offset=$offset"
+		[ -n "$ealen" ] && rule="$rule,ealen=$ealen"
+		if [ "$type" = "map-t" ]; then
+			rule="$rule,dmr=$peeraddr"
+		else
+			rule="$rule,br=$peeraddr"
+		fi
+	fi
+
+	echo "rule=$rule" > /tmp/map-$cfg.rules
+	RULE_DATA=$(mapcalc ${tunlink:-\*} $rule)
+	if [ "$?" != 0 ]; then
+		proto_notify_error "$cfg" "INVALID_MAP_RULE"
+		proto_block_restart "$cfg"
+		return
+	fi
+
+	echo "$RULE_DATA" >> /tmp/map-$cfg.rules
+	eval $RULE_DATA
+
+	if [ -z "$RULE_BMR" ]; then
+		proto_notify_error "$cfg" "NO_MATCHING_PD"
+		proto_block_restart "$cfg"
+		return
+	fi
+
+	k=$RULE_BMR
+	if [ "$type" = "lw4o6" -o "$type" = "map-e" ]; then
+		proto_init_update "$link" 1
+		proto_add_ipv4_address $(eval "echo \$RULE_${k}_IPV4ADDR") "" "" ""
+
+		proto_add_tunnel
+		json_add_string mode ipip6
+		json_add_int mtu "${mtu:-1280}"
+		json_add_int ttl "${ttl:-64}"
+		json_add_string local $(eval "echo \$RULE_${k}_IPV6ADDR")
+		json_add_string remote $(eval "echo \$RULE_${k}_BR")
+		json_add_string link $(eval "echo \$RULE_${k}_PD6IFACE")
+
+		if [ "$type" = "map-e" ]; then
+			json_add_array "fmrs"
+				for i in $(seq $RULE_COUNT); do
+					[ "$(eval "echo \$RULE_${i}_FMR")" != 1 ] && continue
+					fmr="$(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")"
+					fmr="$fmr,$(eval "echo \$RULE_${i}_IPV4PREFIX")/$(eval "echo \$RULE_${i}_PREFIX4LEN")"
+					fmr="$fmr,$(eval "echo \$RULE_${i}_EALEN"),$(eval "echo \$RULE_${i}_OFFSET")"
+					json_add_string "" "$fmr"
+				done
+			json_close_array
+		fi
+
+		proto_close_tunnel
+	elif [ "$type" = "map-t" -a -f "/proc/net/nat46/control" ]; then
+		proto_init_update "$link" 1
+		local style="MAP"
+		[ "$LEGACY" = 1 ] && style="MAP0"
+
+		echo add $link > /proc/net/nat46/control
+		local cfgstr="local.style $style local.v4 $(eval "echo \$RULE_${k}_IPV4PREFIX")/$(eval "echo \$RULE_${k}_PREFIX4LEN")"
+		cfgstr="$cfgstr local.v6 $(eval "echo \$RULE_${k}_IPV6PREFIX")/$(eval "echo \$RULE_${k}_PREFIX6LEN")"
+		cfgstr="$cfgstr local.ea-len $(eval "echo \$RULE_${k}_EALEN") local.psid-offset $(eval "echo \$RULE_${k}_OFFSET")"
+		cfgstr="$cfgstr remote.v4 0.0.0.0/0 remote.v6 $(eval "echo \$RULE_${k}_DMR") remote.style RFC6052 remote.ea-len 0 remote.psid-offset 0"
+		echo config $link $cfgstr > /proc/net/nat46/control
+
+		for i in $(seq $RULE_COUNT); do
+			[ "$(eval "echo \$RULE_${i}_FMR")" != 1 ] && continue
+			local cfgstr="remote.style $style remote.v4 $(eval "echo \$RULE_${i}_IPV4PREFIX")/$(eval "echo \$RULE_${i}_PREFIX4LEN")"
+			cfgstr="$cfgstr remote.v6 $(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")"
+			cfgstr="$cfgstr remote.ea-len $(eval "echo \$RULE_${i}_EALEN") remote.psid-offset $(eval "echo \$RULE_${i}_OFFSET")"
+			echo insert $link $cfgstr > /proc/net/nat46/control
+		done
+	else
+		proto_notify_error "$cfg" "UNSUPPORTED_TYPE"
+		proto_block_restart "$cfg"
+	fi
+
+	proto_add_ipv4_route "0.0.0.0" 0
+	proto_add_data
+	[ "$zone" != "-" ] && json_add_string zone "$zone"
+
+	json_add_array firewall
+	  if [ -z "$(eval "echo \$RULE_${k}_PORTSETS")" ]; then
+	    json_add_object ""
+	      json_add_string type nat
+	      json_add_string target SNAT
+	      json_add_string family inet
+	      json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
+	    json_close_object
+	  else
+	    for portset in $(eval "echo \$RULE_${k}_PORTSETS"); do
+              for proto in icmp tcp udp; do
+	        json_add_object ""
+	          json_add_string type nat
+	          json_add_string target SNAT
+	          json_add_string family inet
+	          json_add_string proto "$proto"
+                  json_add_boolean connlimit_ports 1
+                  json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
+                  json_add_string snat_port "$portset"
+	        json_close_object
+              done
+	    done
+	  fi
+	  if [ "$type" = "map-t" ]; then
+	  	json_add_object ""
+	  		json_add_string type rule
+	  		json_add_string family inet6
+	  		json_add_string proto all
+	  		json_add_string direction in
+			json_add_string dest "$zone"
+			json_add_string src "$zone"
+	  		json_add_string src_ip $(eval "echo \$RULE_${k}_IPV6ADDR")
+	  		json_add_string target ACCEPT
+	  	json_close_object
+	  	json_add_object ""
+	  		json_add_string type rule
+	  		json_add_string family inet6
+	  		json_add_string proto all
+	  		json_add_string direction out
+			json_add_string dest "$zone"
+			json_add_string src "$zone"
+	  		json_add_string dest_ip $(eval "echo \$RULE_${k}_IPV6ADDR")
+	  		json_add_string target ACCEPT
+	  	json_close_object
+		proto_add_ipv6_route $(eval "echo \$RULE_${k}_IPV6ADDR") 128
+	  fi
+	json_close_array
+	proto_close_data
+
+	proto_send_update "$cfg"
+
+	if [ "$type" = "lw4o6" -o "$type" = "map-e" ]; then
+		json_init
+		json_add_string name "${cfg}_"
+		json_add_string ifname "@$(eval "echo \$RULE_${k}_PD6IFACE")"
+		json_add_string proto "static"
+		json_add_array ip6addr
+		json_add_string "" "$(eval "echo \$RULE_${k}_IPV6ADDR")"
+		json_close_array
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	fi
+}
+
+proto_map_teardown() {
+	local cfg="$1"
+	ifdown "${cfg}_"
+	rm -f /tmp/map-$cfg.rules
+}
+
+proto_map_init_config() {
+	no_device=1
+	available=1
+
+	proto_config_add_string "rule"
+	proto_config_add_string "ipaddr"
+	proto_config_add_int "ip4prefixlen"
+	proto_config_add_string "ip6prefix"
+	proto_config_add_int "ip6prefixlen"
+	proto_config_add_string "peeraddr"
+	proto_config_add_int "psidlen"
+	proto_config_add_int "psid"
+	proto_config_add_int "offset"
+
+	proto_config_add_string "tunlink"
+	proto_config_add_int "mtu"
+	proto_config_add_int "ttl"
+	proto_config_add_string "zone"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+        add_protocol map
+}
diff --git a/package/network/ipv6/map/src/CMakeLists.txt b/package/network/ipv6/map/src/CMakeLists.txt
new file mode 100644
index 0000000000..2cbeb2c261
--- /dev/null
+++ b/package/network/ipv6/map/src/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 2.8.1)
+
+project(mapcalc C)
+
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -std=c99")
+
+add_definitions(-D_GNU_SOURCE -Wall -Wno-gnu -Wextra)
+
+add_executable(mapcalc mapcalc.c)
+target_link_libraries(mapcalc ubus ubox)
+
+install(TARGETS mapcalc DESTINATION sbin/)
+
+
+# Packaging rules
+set(CPACK_PACKAGE_VERSION "1")
+set(CPACK_PACKAGE_CONTACT "Steven Barth <steven@midlink.org>")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "hnetd")
+set(CPACK_GENERATOR "DEB;RPM;STGZ")
+set(CPACK_STRIP_FILES true)
+
+SET(CPACK_DEBIAN_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION})
+set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}")
+
+include(CPack)
diff --git a/package/network/ipv6/map/src/mapcalc.c b/package/network/ipv6/map/src/mapcalc.c
new file mode 100644
index 0000000000..648840d9b6
--- /dev/null
+++ b/package/network/ipv6/map/src/mapcalc.c
@@ -0,0 +1,412 @@
+/*
+ * mapcalc - MAP parameter calculation
+ *
+ * Author: Steven Barth <cyrus@openwrt.org>
+ * Copyright (c) 2014-2015 cisco Systems, Inc.
+ * Copyright (c) 2015 Steven Barth <cyrus@openwrt.org>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <libubus.h>
+#include <libubox/utils.h>
+
+
+struct blob_attr *dump = NULL;
+
+enum {
+	DUMP_ATTR_INTERFACE,
+	DUMP_ATTR_MAX
+};
+
+static const struct blobmsg_policy dump_attrs[DUMP_ATTR_MAX] = {
+	[DUMP_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+
+enum {
+	IFACE_ATTR_INTERFACE,
+	IFACE_ATTR_PREFIX,
+	IFACE_ATTR_ADDRESS,
+	IFACE_ATTR_MAX,
+};
+
+static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
+	[IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
+	[IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY },
+	[IFACE_ATTR_ADDRESS] = { .name = "ipv6-address", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+
+enum {
+	PREFIX_ATTR_ADDRESS,
+	PREFIX_ATTR_MASK,
+	PREFIX_ATTR_MAX,
+};
+
+static const struct blobmsg_policy prefix_attrs[PREFIX_ATTR_MAX] = {
+	[PREFIX_ATTR_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING },
+	[PREFIX_ATTR_MASK] = { .name = "mask", .type = BLOBMSG_TYPE_INT32 },
+};
+
+static int bmemcmp(const void *av, const void *bv, size_t bits)
+{
+	const uint8_t *a = av, *b = bv;
+	size_t bytes = bits / 8;
+	bits %= 8;
+
+	int res = memcmp(a, b, bytes);
+	if (res == 0 && bits > 0)
+		res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits));
+
+	return res;
+}
+
+static void bmemcpy(void *av, const void *bv, size_t bits)
+{
+	uint8_t *a = av;
+	const uint8_t *b = bv;
+
+	size_t bytes = bits / 8;
+	bits %= 8;
+	memcpy(a, b, bytes);
+
+	if (bits > 0) {
+		uint8_t mask = (1 << (8 - bits)) - 1;
+		a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]);
+	}
+}
+
+static void bmemcpys64(void *av, const void *bv, size_t frombits, size_t nbits)
+{
+	uint64_t buf = 0;
+	const uint8_t *b = bv;
+	size_t frombyte = frombits / 8, tobyte = (frombits + nbits) / 8;
+
+	memcpy(&buf, &b[frombyte], tobyte - frombyte + 1);
+	buf = cpu_to_be64(be64_to_cpu(buf) << (frombits % 8));
+
+	bmemcpy(av, &buf, nbits);
+}
+
+static void handle_dump(struct ubus_request *req __attribute__((unused)),
+		int type __attribute__((unused)), struct blob_attr *msg)
+{
+	struct blob_attr *tb[DUMP_ATTR_INTERFACE];
+	blobmsg_parse(dump_attrs, DUMP_ATTR_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[DUMP_ATTR_INTERFACE])
+		return;
+
+	dump = blob_memdup(tb[DUMP_ATTR_INTERFACE]);
+}
+
+static void match_prefix(int *pdlen, struct in6_addr *pd, struct blob_attr *cur,
+		const struct in6_addr *ipv6prefix, int prefix6len, bool lw4o6)
+{
+	struct blob_attr *d;
+	unsigned drem;
+
+	if (!cur || blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, NULL))
+		return;
+
+	blobmsg_for_each_attr(d, cur, drem) {
+		struct blob_attr *ptb[PREFIX_ATTR_MAX];
+		blobmsg_parse(prefix_attrs, PREFIX_ATTR_MAX, ptb,
+				blobmsg_data(d), blobmsg_data_len(d));
+
+		if (!ptb[PREFIX_ATTR_ADDRESS] || !ptb[PREFIX_ATTR_MASK])
+			continue;
+
+		struct in6_addr prefix = IN6ADDR_ANY_INIT;
+		int mask = blobmsg_get_u32(ptb[PREFIX_ATTR_MASK]);
+		inet_pton(AF_INET6, blobmsg_get_string(ptb[PREFIX_ATTR_ADDRESS]), &prefix);
+
+		// lw4over6 /128-address-as-PD matching madness workaround
+		if (lw4o6 && mask == 128)
+			mask = 64;
+
+		if (*pdlen < mask && mask >= prefix6len &&
+				!bmemcmp(&prefix, ipv6prefix, prefix6len)) {
+			bmemcpy(pd, &prefix, mask);
+			*pdlen = mask;
+		} else if (lw4o6 && *pdlen < prefix6len && mask < prefix6len &&
+				!bmemcmp(&prefix, ipv6prefix, mask)) {
+			bmemcpy(pd, ipv6prefix, prefix6len);
+			*pdlen = prefix6len;
+		}
+	}
+}
+
+enum {
+	OPT_TYPE,
+	OPT_FMR,
+	OPT_EALEN,
+	OPT_PREFIX4LEN,
+	OPT_PREFIX6LEN,
+	OPT_IPV6PREFIX,
+	OPT_IPV4PREFIX,
+	OPT_OFFSET,
+	OPT_PSIDLEN,
+	OPT_PSID,
+	OPT_BR,
+	OPT_DMR,
+	OPT_PD,
+	OPT_PDLEN,
+	OPT_MAX
+};
+
+static char *const token[] = {
+	[OPT_TYPE] = "type",
+	[OPT_FMR] = "fmr",
+	[OPT_EALEN] = "ealen",
+	[OPT_PREFIX4LEN] = "prefix4len",
+	[OPT_PREFIX6LEN] = "prefix6len",
+	[OPT_IPV6PREFIX] = "ipv6prefix",
+	[OPT_IPV4PREFIX] = "ipv4prefix",
+	[OPT_OFFSET] = "offset",
+	[OPT_PSIDLEN] = "psidlen",
+	[OPT_PSID] = "psid",
+	[OPT_BR] = "br",
+	[OPT_DMR] = "dmr",
+	[OPT_PD] = "pd",
+	[OPT_PDLEN] = "pdlen",
+	[OPT_MAX] = NULL
+};
+
+
+int main(int argc, char *argv[])
+{
+	int status = 0;
+	const char *iface = argv[1];
+
+	const char *legacy_env = getenv("LEGACY");
+	bool legacy = legacy_env && atoi(legacy_env);
+
+
+	if (argc < 3) {
+		fprintf(stderr, "Usage: %s <interface|*> <rule1> [rule2] [...]\n", argv[0]);
+		return 1;
+	}
+
+	uint32_t network_interface;
+	struct ubus_context *ubus = ubus_connect(NULL);
+	if (ubus) {
+		ubus_lookup_id(ubus, "network.interface", &network_interface);
+		ubus_invoke(ubus, network_interface, "dump", NULL, handle_dump, NULL, 5000);
+	}
+
+	int rulecnt = 0;
+	for (int i = 2; i < argc; ++i) {
+		bool lw4o6 = false;
+		bool fmr = false;
+		int ealen = -1;
+		int addr4len = 32;
+		int prefix4len = 32;
+		int prefix6len = -1;
+		int pdlen = -1;
+		struct in_addr ipv4prefix = {INADDR_ANY};
+		struct in_addr ipv4addr = {INADDR_ANY};
+		struct in6_addr ipv6addr = IN6ADDR_ANY_INIT;
+		struct in6_addr ipv6prefix = IN6ADDR_ANY_INIT;
+		struct in6_addr pd = IN6ADDR_ANY_INIT;
+		int offset = -1;
+		int psidlen = -1;
+		int psid = -1;
+		uint16_t psid16 = 0;
+		const char *dmr = NULL;
+		const char *br = NULL;
+
+		for (char *rule = strdup(argv[i]); *rule; ) {
+			char *value;
+			int intval;
+			int idx = getsubopt(&rule, token, &value);
+			errno = 0;
+
+			if (idx == OPT_TYPE) {
+				lw4o6 = (value && !strcmp(value, "lw4o6"));
+			} else if (idx == OPT_FMR) {
+				fmr = true;
+			} else if (idx == OPT_EALEN && (intval = strtoul(value, NULL, 0)) <= 48 && !errno) {
+				ealen = intval;
+			} else if (idx == OPT_PREFIX4LEN && (intval = strtoul(value, NULL, 0)) <= 32 && !errno) {
+				prefix4len = intval;
+			} else if (idx == OPT_PREFIX6LEN && (intval = strtoul(value, NULL, 0)) <= 128 && !errno) {
+				prefix6len = intval;
+			} else if (idx == OPT_IPV4PREFIX && inet_pton(AF_INET, value, &ipv4prefix) == 1) {
+				// dummy
+			} else if (idx == OPT_IPV6PREFIX && inet_pton(AF_INET6, value, &ipv6prefix) == 1) {
+				// dummy
+			} else if (idx == OPT_PD && inet_pton(AF_INET6, value, &pd) == 1) {
+				// dummy
+			} else if (idx == OPT_OFFSET && (intval = strtoul(value, NULL, 0)) <= 16 && !errno) {
+				offset = intval;
+			} else if (idx == OPT_PSIDLEN && (intval = strtoul(value, NULL, 0)) <= 16 && !errno) {
+				psidlen = intval;
+			} else if (idx == OPT_PDLEN && (intval = strtoul(value, NULL, 0)) <= 128 && !errno) {
+				pdlen = intval;
+			} else if (idx == OPT_PSID && (intval = strtoul(value, NULL, 0)) <= 65535 && !errno) {
+				psid = intval;
+			} else if (idx == OPT_DMR) {
+				dmr = value;
+			} else if (idx == OPT_BR) {
+				br = value;
+			} else {
+				if (idx == -1 || idx >= OPT_MAX)
+					fprintf(stderr, "Skipped invalid option: %s\n", value);
+				else
+					fprintf(stderr, "Skipped invalid value %s for option %s\n",
+							value, token[idx]);
+			}
+		}
+
+		if (offset < 0)
+			offset = (lw4o6) ? 0 : (legacy) ? 4 : 6;
+
+		// LW4over6 doesn't have an EALEN and has no psid-autodetect
+		if (lw4o6) {
+			if (psidlen < 0)
+				psidlen = 0;
+
+			ealen = psidlen;
+		}
+
+		// Find PD
+		if (pdlen < 0) {
+			struct blob_attr *c;
+			unsigned rem;
+			blobmsg_for_each_attr(c, dump, rem) {
+				struct blob_attr *tb[IFACE_ATTR_MAX];
+				blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c));
+
+				if (!tb[IFACE_ATTR_INTERFACE] || (strcmp(argv[1], "*") && strcmp(argv[1],
+						blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]))))
+					continue;
+
+				match_prefix(&pdlen, &pd, tb[IFACE_ATTR_PREFIX], &ipv6prefix, prefix6len, lw4o6);
+
+				if (lw4o6)
+					match_prefix(&pdlen, &pd, tb[IFACE_ATTR_ADDRESS], &ipv6prefix, prefix6len, lw4o6);
+
+				if (pdlen >= 0) {
+					iface = blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]);
+					break;
+				}
+			}
+		}
+
+		if (ealen < 0 && pdlen >= 0)
+			ealen = pdlen - prefix6len;
+
+		if (psidlen <= 0) {
+			psidlen = ealen - (32 - prefix4len);
+			psid = -1;
+		}
+
+		if (psid < 0 && psidlen <= 16 && psidlen >= 0 && pdlen >= 0 && ealen >= psidlen) {
+			bmemcpys64(&psid16, &pd, prefix6len + ealen - psidlen, psidlen);
+			psid = be16_to_cpu(psid16);
+		}
+
+		psid = psid >> (16 - psidlen);
+		psid16 = cpu_to_be16(psid);
+		psid = psid << (16 - psidlen);
+
+		if (prefix4len < 0 || prefix6len < 0 || ealen < 0 || ealen < psidlen) {
+			fprintf(stderr, "Skipping invalid or incomplete rule: %s\n", argv[i]);
+			status = 1;
+			continue;
+		}
+
+		if ((pdlen >= 0 || ealen == psidlen) && ealen >= psidlen) {
+			bmemcpys64(&ipv4addr, &pd, prefix6len, ealen - psidlen);
+			ipv4addr.s_addr = htonl(ntohl(ipv4addr.s_addr) >> prefix4len);
+			bmemcpy(&ipv4addr, &ipv4prefix, prefix4len);
+
+			if (prefix4len + ealen < 32)
+				addr4len = prefix4len + ealen;
+		}
+
+		if (pdlen < 0 && !fmr) {
+			fprintf(stderr, "Skipping non-FMR without matching PD: %s\n", argv[i]);
+			status = 1;
+			continue;
+		} else if (pdlen >= 0) {
+			size_t v4offset = (legacy) ? 9 : 10;
+			memcpy(&ipv6addr.s6_addr[v4offset], &ipv4addr, 4);
+			memcpy(&ipv6addr.s6_addr[v4offset + 4], &psid16, 2);
+			bmemcpy(&ipv6addr, &pd, pdlen);
+		}
+
+		++rulecnt;
+		char ipv4addrbuf[INET_ADDRSTRLEN];
+		char ipv4prefixbuf[INET_ADDRSTRLEN];
+		char ipv6prefixbuf[INET6_ADDRSTRLEN];
+		char ipv6addrbuf[INET6_ADDRSTRLEN];
+		char pdbuf[INET6_ADDRSTRLEN];
+
+		inet_ntop(AF_INET, &ipv4addr, ipv4addrbuf, sizeof(ipv4addrbuf));
+		inet_ntop(AF_INET, &ipv4prefix, ipv4prefixbuf, sizeof(ipv4prefixbuf));
+		inet_ntop(AF_INET6, &ipv6prefix, ipv6prefixbuf, sizeof(ipv6prefixbuf));
+		inet_ntop(AF_INET6, &ipv6addr, ipv6addrbuf, sizeof(ipv6addrbuf));
+		inet_ntop(AF_INET6, &pd, pdbuf, sizeof(pdbuf));
+
+		printf("RULE_%d_FMR=%d\n", rulecnt, fmr);
+		printf("RULE_%d_EALEN=%d\n", rulecnt, ealen);
+		printf("RULE_%d_PSIDLEN=%d\n", rulecnt, psidlen);
+		printf("RULE_%d_OFFSET=%d\n", rulecnt, offset);
+		printf("RULE_%d_PREFIX4LEN=%d\n", rulecnt, prefix4len);
+		printf("RULE_%d_PREFIX6LEN=%d\n", rulecnt, prefix6len);
+		printf("RULE_%d_IPV4PREFIX=%s\n", rulecnt, ipv4prefixbuf);
+		printf("RULE_%d_IPV6PREFIX=%s\n", rulecnt, ipv6prefixbuf);
+
+		if (pdlen >= 0) {
+			printf("RULE_%d_IPV6PD=%s\n", rulecnt, pdbuf);
+			printf("RULE_%d_PD6LEN=%d\n", rulecnt, pdlen);
+			printf("RULE_%d_PD6IFACE=%s\n", rulecnt, iface);
+			printf("RULE_%d_IPV6ADDR=%s\n", rulecnt, ipv6addrbuf);
+			printf("RULE_BMR=%d\n", rulecnt);
+		}
+
+		if (ipv4addr.s_addr) {
+			printf("RULE_%d_IPV4ADDR=%s\n", rulecnt, ipv4addrbuf);
+			printf("RULE_%d_ADDR4LEN=%d\n", rulecnt, addr4len);
+		}
+
+
+		if (psidlen > 0 && psid >= 0) {
+			printf("RULE_%d_PORTSETS='", rulecnt);
+			for (int k = (offset) ? 1 : 0; k < (1 << offset); ++k) {
+				int start = (k << (16 - offset)) | (psid >> offset);
+				int end = start + (1 << (16 - offset - psidlen)) - 1;
+
+				if (start == 0)
+					start = 1;
+
+				if (start <= end)
+					printf("%d-%d ", start, end);
+			}
+			printf("'\n");
+		}
+
+		if (dmr)
+			printf("RULE_%d_DMR=%s\n", rulecnt, dmr);
+
+		if (br)
+			printf("RULE_%d_BR=%s\n", rulecnt, br);
+	}
+
+	printf("RULE_COUNT=%d\n", rulecnt);
+	return status;
+}
diff --git a/package/network/ipv6/odhcp6c/Makefile b/package/network/ipv6/odhcp6c/Makefile
new file mode 100644
index 0000000000..9b50e21e4d
--- /dev/null
+++ b/package/network/ipv6/odhcp6c/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2012-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=odhcp6c
+PKG_VERSION:=2016-06-30
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL:=https://github.com/sbyx/odhcp6c.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=7533a6243dc3ac5a747cf6ccbc4d0539dafd3e07
+PKG_MIRROR_MD5SUM:=faaa26d09039c3133626f67a01b07b9922fea105e6566c44e78350fce51fa2b8
+PKG_MAINTAINER:=Steven Barth <steven@midlink.org>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+ifneq ($(CONFIG_PACKAGE_odhcp6c_ext_cer_id),0)
+  CMAKE_OPTIONS += -DEXT_CER_ID=$(CONFIG_PACKAGE_odhcp6c_ext_cer_id)
+endif
+
+define Package/odhcp6c
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Embedded DHCPv6-client for OpenWrt
+  DEPENDS:=@IPV6
+endef
+
+define Package/odhcp6c/config
+  config PACKAGE_odhcp6c_ext_cer_id
+    int "CER-ID Extension ID (0 = disabled)"
+    depends on PACKAGE_odhcp6c
+    default 0
+endef
+
+define Package/odhcp6c/install
+	$(INSTALL_DIR) $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/odhcp6c $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/dhcpv6.sh $(1)/lib/netifd/proto/dhcpv6.sh
+	$(INSTALL_BIN) ./files/dhcpv6.script $(1)/lib/netifd/
+endef
+
+$(eval $(call BuildPackage,odhcp6c))
diff --git a/package/network/ipv6/odhcp6c/files/dhcpv6.script b/package/network/ipv6/odhcp6c/files/dhcpv6.script
new file mode 100755
index 0000000000..46980cb57d
--- /dev/null
+++ b/package/network/ipv6/odhcp6c/files/dhcpv6.script
@@ -0,0 +1,219 @@
+#!/bin/sh
+[ -z "$2" ] && echo "Error: should be run by odhcpc6c" && exit 1
+. /lib/functions.sh
+. /lib/netifd/netifd-proto.sh
+
+setup_interface () {
+	local device="$1"
+	local prefsig=""
+	local addrsig=""
+	proto_init_update "*" 1
+
+	# Merge RA-DNS
+	for radns in $RA_DNS; do
+		local duplicate=0
+		for dns in $RDNSS; do
+			[ "$radns" = "$dns" ] && duplicate=1
+		done
+		[ "$duplicate" = 0 ] && RDNSS="$RDNSS $radns"
+	done
+
+	for dns in $RDNSS; do
+		proto_add_dns_server "$dns"
+	done
+
+	for radomain in $RA_DOMAINS; do
+		local duplicate=0
+		for domain in $DOMAINS; do
+			[ "$radomain" = "$domain" ] && duplicate=1
+		done
+		[ "$duplicate" = 0 ] && DOMAINS="$DOMAINS $radomain"
+	done
+
+	for domain in $DOMAINS; do
+		proto_add_dns_search "$domain"
+	done
+
+	for prefix in $PREFIXES; do
+		proto_add_ipv6_prefix "$prefix"
+		prefsig="$prefsig ${prefix%%,*}"
+		local entry="${prefix#*/}"
+		entry="${entry#*,}"
+		entry="${entry#*,}"
+		local valid="${entry%%,*}"
+
+		if [ -z "$RA_ADDRESSES" -a -z "$RA_ROUTES" -a \
+				-z "$RA_DNS" -a "$FAKE_ROUTES" = 1 ]; then
+			RA_ROUTES="::/0,$SERVER,$valid,4096"
+		fi
+	done
+
+	[ -n "$USERPREFIX" ] && proto_add_ipv6_prefix "$USERPREFIX"
+
+	# Merge addresses
+	for entry in $RA_ADDRESSES; do
+		local duplicate=0
+		local addr="${entry%%/*}"
+		for dentry in $ADDRESSES; do
+			local daddr="${dentry%%/*}"
+			[ "$addr" = "$daddr" ] && duplicate=1
+		done
+		[ "$duplicate" = "0" ] && ADDRESSES="$ADDRESSES $entry"
+	done
+
+	for entry in $ADDRESSES; do
+		local addr="${entry%%/*}"
+		entry="${entry#*/}"
+		local mask="${entry%%,*}"
+		entry="${entry#*,}"
+		local preferred="${entry%%,*}"
+		entry="${entry#*,}"
+		local valid="${entry%%,*}"
+
+		proto_add_ipv6_address "$addr" "$mask" "$preferred" "$valid" 1
+		addrsig="$addrsig $addr/$mask"
+
+		if [ -z "$RA_ADDRESSES" -a -z "$RA_ROUTES" -a \
+				-z "$RA_DNS" -a "$FAKE_ROUTES" = 1 ]; then
+			RA_ROUTES="::/0,$SERVER,$valid,4096"
+		fi
+
+		# RFC 7278
+		if [ "$mask" -eq 64 -a -z "$PREFIXES" -a -n "$EXTENDPREFIX" ]; then
+			proto_add_ipv6_prefix "$addr/$mask,$preferred,$valid"
+		fi
+	done
+
+	for entry in $RA_ROUTES; do
+		local duplicate=$NOSOURCEFILTER
+		local addr="${entry%%/*}"
+		entry="${entry#*/}"
+		local mask="${entry%%,*}"
+		entry="${entry#*,}"
+		local gw="${entry%%,*}"
+		entry="${entry#*,}"
+		local valid="${entry%%,*}"
+		entry="${entry#*,}"
+		local metric="${entry%%,*}"
+
+		for xentry in $RA_ROUTES; do
+			local xprefix="${xentry%%,*}"
+			xentry="${xentry#*,}"
+			local xgw="${xentry%%,*}"
+
+			[ -n "$gw" -a -z "$xgw" -a "$addr/$mask" = "$xprefix" ] && duplicate=1
+		done
+
+		if [ -z "$gw" -o "$duplicate" = 1 ]; then
+			proto_add_ipv6_route "$addr" "$mask" "$gw" "$metric" "$valid"
+		else
+			for prefix in $PREFIXES $ADDRESSES; do
+				local paddr="${prefix%%,*}"
+				proto_add_ipv6_route "$addr" "$mask" "$gw" "$metric" "$valid" "$paddr"
+			done
+		fi
+	done
+
+	proto_add_data
+	[ -n "$CER" ] && json_add_string cer "$CER"
+	[ -n "$PASSTHRU" ] && json_add_string passthru "$PASSTHRU"
+	[ -n "$ZONE" ] && json_add_string zone "$ZONE"
+	proto_close_data
+
+	proto_send_update "$INTERFACE"
+
+	MAPTYPE=""
+	MAPRULE=""
+
+	if [ -n "$MAPE" -a -f /lib/netifd/proto/map.sh ]; then
+		MAPTYPE="map-e"
+		MAPRULE="$MAPE"
+	elif [ -n "$MAPT" -a -f /lib/netifd/proto/map.sh -a -f /proc/net/nat46/control ]; then
+		MAPTYPE="map-t"
+		MAPRULE="$MAPT"
+	elif [ -n "$LW4O6" -a -f /lib/netifd/proto/map.sh ]; then
+		MAPTYPE="lw4o6"
+		MAPRULE="$LW4O6"
+	fi
+
+	[ -n "$ZONE" ] || ZONE=$(fw3 -q network $INTERFACE 2>/dev/null)
+
+	if [ "$IFACE_MAP" != 0 -a -n "$MAPTYPE" -a -n "$MAPRULE" ]; then
+		[ -z "$IFACE_MAP" -o "$IFACE_MAP" = 1 ] && IFACE_MAP=${INTERFACE}_4
+		json_init
+		json_add_string name "$IFACE_MAP"
+		json_add_string ifname "@$INTERFACE"
+		json_add_string proto map
+		json_add_string type "$MAPTYPE"
+		json_add_string _prefsig "$prefsig"
+		[ "$MAPTYPE" = lw4o6 ] && json_add_string _addrsig "$addrsig"
+		json_add_string rule "$MAPRULE"
+		json_add_string tunlink "$INTERFACE"
+		[ -n "$ZONE_MAP" ] || ZONE_MAP=$ZONE
+		[ -n "$ZONE_MAP" ] && json_add_string zone "$ZONE_MAP"
+		[ -n "$IFACE_MAP_DELEGATE" ] && json_add_boolean delegate "$IFACE_MAP_DELEGATE"
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	elif [ -n "$AFTR" -a "$IFACE_DSLITE" != 0 -a -f /lib/netifd/proto/dslite.sh ]; then
+		[ -z "$IFACE_DSLITE" -o "$IFACE_DSLITE" = 1 ] && IFACE_DSLITE=${INTERFACE}_4
+		json_init
+		json_add_string name "$IFACE_DSLITE"
+		json_add_string ifname "@$INTERFACE"
+		json_add_string proto "dslite"
+		json_add_string peeraddr "$AFTR"
+		json_add_string tunlink "$INTERFACE"
+		[ -n "$ZONE_DSLITE" ] || ZONE_DSLITE=$ZONE
+		[ -n "$ZONE_DSLITE" ] && json_add_string zone "$ZONE_DSLITE"
+		[ -n "$IFACE_DSLITE_DELEGATE" ] && json_add_boolean delegate "$IFACE_DSLITE_DELEGATE"
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	elif [ "$IFACE_464XLAT" != 0 -a -f /lib/netifd/proto/464xlat.sh ]; then
+		[ -z "$IFACE_464XLAT" -o "$IFACE_464XLAT" = 1 ] && IFACE_464XLAT=${INTERFACE}_4
+		json_init
+		json_add_string name "$IFACE_464XLAT"
+		json_add_string ifname "@$INTERFACE"
+		json_add_string proto "464xlat"
+		json_add_string tunlink "$INTERFACE"
+		json_add_string _addrsig "$addrsig"
+		[ -n "$ZONE_464XLAT" ] || ZONE_464XLAT=$ZONE
+		[ -n "$ZONE_464XLAT" ] && json_add_string zone "$ZONE_464XLAT"
+		[ -n "$IFACE_464XLAT_DELEGATE" ] && json_add_boolean delegate "$IFACE_464XLAT_DELEGATE"
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	fi
+
+	# Apply IPv6 / ND configuration
+	HOPLIMIT=$(cat /proc/sys/net/ipv6/conf/$device/hop_limit)
+	[ -n "$RA_HOPLIMIT" -a -n "$HOPLIMIT" ] && [ "$RA_HOPLIMIT" -gt "$HOPLIMIT" ] && echo "$RA_HOPLIMIT" > /proc/sys/net/ipv6/conf/$device/hop_limit
+	[ -n "$RA_MTU" ] && [ "$RA_MTU" -ge 1280 ] && echo "$RA_MTU" > /proc/sys/net/ipv6/conf/$device/mtu 2>/dev/null
+	[ -n "$RA_REACHABLE" ] && [ "$RA_REACHABLE" -gt 0 ] && echo "$RA_REACHABLE" > /proc/sys/net/ipv6/neigh/$device/base_reachable_time_ms
+	[ -n "$RA_RETRANSMIT" ] && [ "$RA_RETRANSMIT" -gt 0 ] && echo "$RA_RETRANSMIT" > /proc/sys/net/ipv6/neigh/$device/retrans_time_ms
+
+	# TODO: $SNTP_IP $SIP_IP $SNTP_FQDN $SIP_DOMAIN
+}
+
+teardown_interface() {
+	proto_init_update "*" 0
+	proto_send_update "$INTERFACE"
+}
+
+case "$2" in
+	bound)
+		teardown_interface "$1"
+		setup_interface "$1"
+	;;
+	informed|updated|rebound)
+		setup_interface "$1"
+	;;
+	ra-updated)
+		[ -n "$ADDRESSES$RA_ADDRESSES$PREFIXES$USERPREFIX" ] && setup_interface "$1"
+	;;
+	started|stopped|unbound)
+		teardown_interface "$1"
+	;;
+esac
+
+# user rules
+[ -f /etc/odhcp6c.user ] && . /etc/odhcp6c.user
+
+exit 0
diff --git a/package/network/ipv6/odhcp6c/files/dhcpv6.sh b/package/network/ipv6/odhcp6c/files/dhcpv6.sh
new file mode 100755
index 0000000000..6c47399916
--- /dev/null
+++ b/package/network/ipv6/odhcp6c/files/dhcpv6.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. ../netifd-proto.sh
+init_proto "$@"
+
+proto_dhcpv6_init_config() {
+	renew_handler=1
+
+	proto_config_add_string 'reqaddress:or("try","force","none")'
+	proto_config_add_string 'reqprefix:or("auto","no",range(0, 64))'
+	proto_config_add_string clientid
+	proto_config_add_string 'reqopts:list(uinteger)'
+	proto_config_add_string 'noslaaconly:bool'
+	proto_config_add_string 'forceprefix:bool'
+	proto_config_add_string 'extendprefix:bool'
+	proto_config_add_string 'norelease:bool'
+	proto_config_add_string 'ip6prefix:ip6addr'
+	proto_config_add_string iface_dslite
+	proto_config_add_string zone_dslite
+	proto_config_add_string iface_map
+	proto_config_add_string zone_map
+	proto_config_add_string iface_464xlat
+	proto_config_add_string zone_464xlat
+	proto_config_add_string zone
+	proto_config_add_string 'ifaceid:ip6addr'
+	proto_config_add_string "userclass"
+	proto_config_add_string "vendorclass"
+	proto_config_add_boolean delegate
+	proto_config_add_int "soltimeout"
+	proto_config_add_boolean fakeroutes
+	proto_config_add_boolean sourcefilter
+}
+
+proto_dhcpv6_setup() {
+	local config="$1"
+	local iface="$2"
+
+	local reqaddress reqprefix clientid reqopts noslaaconly forceprefix extendprefix norelease ip6prefix iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass delegate zone_dslite zone_map zone_464xlat zone soltimeout fakeroutes sourcefilter
+	json_get_vars reqaddress reqprefix clientid reqopts noslaaconly forceprefix extendprefix norelease ip6prefix iface_dslite iface_map iface_464xlat ifaceid userclass vendorclass delegate zone_dslite zone_map zone_464xlat zone soltimeout fakeroutes sourcefilter
+
+
+	# Configure
+	local opts=""
+	[ -n "$reqaddress" ] && append opts "-N$reqaddress"
+
+	[ -z "$reqprefix" -o "$reqprefix" = "auto" ] && reqprefix=0
+	[ "$reqprefix" != "no" ] && append opts "-P$reqprefix"
+
+	[ -n "$clientid" ] && append opts "-c$clientid"
+
+	[ "$noslaaconly" = "1" ] && append opts "-S"
+
+	[ "$forceprefix" = "1" ] && append opts "-F"
+
+	[ "$norelease" = "1" ] && append opts "-k"
+
+	[ -n "$ifaceid" ] && append opts "-i$ifaceid"
+
+	[ -n "$vendorclass" ] && append opts "-V$vendorclass"
+
+	[ -n "$userclass" ] && append opts "-u$userclass"
+
+	for opt in $reqopts; do
+		append opts "-r$opt"
+	done
+
+	append opts "-t${soltimeout:-120}"
+
+	[ -n "$ip6prefix" ] && proto_export "USERPREFIX=$ip6prefix"
+	[ -n "$iface_dslite" ] && proto_export "IFACE_DSLITE=$iface_dslite"
+	[ -n "$iface_map" ] && proto_export "IFACE_MAP=$iface_map"
+	[ -n "$iface_464xlat" ] && proto_export "IFACE_464XLAT=$iface_464xlat"
+	[ "$delegate" = "0" ] && proto_export "IFACE_DSLITE_DELEGATE=0"
+	[ "$delegate" = "0" ] && proto_export "IFACE_MAP_DELEGATE=0"
+	[ -n "$zone_dslite" ] && proto_export "ZONE_DSLITE=$zone_dslite"
+	[ -n "$zone_map" ] && proto_export "ZONE_MAP=$zone_map"
+	[ -n "$zone_464xlat" ] && proto_export "ZONE_464XLAT=$zone_464xlat"
+	[ -n "$zone" ] && proto_export "ZONE=$zone"
+	[ "$fakeroutes" != "0" ] && proto_export "FAKE_ROUTES=1"
+	[ "$sourcefilter" = "0" ] && proto_export "NOSOURCEFILTER=1"
+	[ "$extendprefix" = "1" ] && proto_export "EXTENDPREFIX=1"
+
+	proto_export "INTERFACE=$config"
+	proto_run_command "$config" odhcp6c \
+		-s /lib/netifd/dhcpv6.script \
+		$opts $iface
+}
+
+proto_dhcpv6_renew() {
+	local interface="$1"
+	# SIGUSR1 forces odhcp6c to renew its lease
+	local sigusr1="$(kill -l SIGUSR1)"
+	[ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1
+}
+
+proto_dhcpv6_teardown() {
+	local interface="$1"
+	proto_kill_command "$interface"
+}
+
+add_protocol dhcpv6
+
diff --git a/package/network/ipv6/thc-ipv6/Makefile b/package/network/ipv6/thc-ipv6/Makefile
new file mode 100644
index 0000000000..563afa4f81
--- /dev/null
+++ b/package/network/ipv6/thc-ipv6/Makefile
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2009-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=thc-ipv6
+PKG_VERSION:=2.7
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-3.0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://freeworld.thc.org/releases/
+PKG_MD5SUM:=2975dd54be35b68c140eb2a6b8ef5e59
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+include $(INCLUDE_DIR)/package.mk
+
+THC_APPLETS := \
+	address6 alive6 covert_send6 covert_send6d denial6 detect-new-ip6     \
+	detect_sniffer6 dnsdict6 dnsrevenum6 dos-new-ip6                      \
+	dump_router6 exploit6 fake_advertise6 fake_dhcps6 fake_dns6d          \
+	fake_dnsupdate6 fake_mipv6 fake_mld26 fake_mld6 fake_mldrouter6       \
+	fake_router26 fake_router6 fake_solicitate6 flood_advertise6          \
+	flood_dhcpc6 flood_mld26 flood_mld6 flood_mldrouter6 flood_router26   \
+	flood_router6 flood_solicitate6 fragmentation6 fuzz_ip6 fuzz_dhcpc6   \
+	fuzz_dhcps6 implementation6 implementation6d inverse_lookup6          \
+	kill_router6 ndpexhaust6 node_query6 parasite6 passive_discovery6     \
+	randicmp6 redir6 rsmurf6 sendpees6 sendpeesmp6 smurf6 thcping6        \
+	toobig6 trace6
+
+THC_DEPENDS_dnsdict6 := +libpthread
+THC_DEPENDS_thcping6 := +librt
+
+define BuildTool
+  define Package/thc-ipv6-$(subst _,-,$(1))
+    TITLE:=THC-IPv6 $(1) utility
+    SECTION:=net
+    CATEGORY:=Network
+    DEPENDS:=+libpcap $(THC_DEPENDS_$(1))
+    URL:=http://freeworld.thc.org/
+    SUBMENU:=THC-IPv6 attack and analyzing toolkit
+  endef
+
+  define Package/thc-ipv6-$(subst _,-,$(1))/description
+    This package contains the $(1) utility of the THC-IPv6 toolkit.
+  endef
+
+  define Package/thc-ipv6-$(subst _,-,$(1))/install
+	$(INSTALL_DIR) $$(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(1) $$(1)/usr/sbin/$(1)
+  endef
+
+  $$(eval $$(call BuildPackage,thc-ipv6-$(subst _,-,$(1))))
+endef
+
+$(foreach a,$(THC_APPLETS),$(eval $(call BuildTool,$(a))))
diff --git a/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch b/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch
new file mode 100644
index 0000000000..1ef1f66be8
--- /dev/null
+++ b/package/network/ipv6/thc-ipv6/patches/100-no-ssl.patch
@@ -0,0 +1,9 @@
+--- a/Makefile
++++ b/Makefile
+@@ -1,5 +1,5 @@
+ # Comment out if openssl-dev is not present
+-HAVE_SSL=yes
++#HAVE_SSL=yes
+ 
+ CC=gcc
+ #CFLAGS=-g
diff --git a/package/network/services/authsae/Makefile b/package/network/services/authsae/Makefile
new file mode 100644
index 0000000000..8096107dc9
--- /dev/null
+++ b/package/network/services/authsae/Makefile
@@ -0,0 +1,48 @@
+
+# Copyright (C) 2007-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=authsae
+PKG_VERSION:=2014-06-09
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/cozybit/authsae.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=8531ab158910a525d4bcbb3ad02c08342f6987f2
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=aa208688570fc6b8b16d9b70e3644208e851dbd3a90f52843aa44c9043b4fbbb
+
+PKG_BUILD_PARALLEL:=1
+CMAKE_INSTALL:=1
+
+CMAKE_OPTIONS += -DSYSCONF_INSTALL_DIR=/etc
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=BSD-4-Clause
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/authsae
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=80211s mesh security
+  DEPENDS:=+libopenssl +libconfig +libnl-tiny +@OPENSSL_WITH_EC
+endef
+
+TARGET_CFLAGS += -D_GNU_SOURCE
+
+define Package/authsae/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin
+	$(INSTALL_DIR) $(1)/lib/wifi
+	$(INSTALL_DATA) ./files/lib/wifi/authsae.sh $(1)/lib/wifi/
+endef
+
+$(eval $(call BuildPackage,authsae))
diff --git a/package/network/services/authsae/files/lib/wifi/authsae.sh b/package/network/services/authsae/files/lib/wifi/authsae.sh
new file mode 100644
index 0000000000..75be48e473
--- /dev/null
+++ b/package/network/services/authsae/files/lib/wifi/authsae.sh
@@ -0,0 +1,65 @@
+authsae_start_interface() {
+	local mcast_rate
+	local mesh_htmode
+	local mesh_band
+	local authsae_conf_file="/var/run/authsae-$ifname.cfg"
+	local ret=1
+
+	json_get_vars mcast_rate mesh_id
+	set_default mcast_rate "12000"
+
+	case "$htmode" in
+		HT20|HT40+|HT40-) mesh_htmode="$htmode";;
+		*) mesh_htmode="none";;
+	esac
+
+	case "$hwmode" in
+		*g*) mesh_band=11g;;
+		*a*) mesh_band=11a;;
+	esac
+
+	if [ "$mcast_rate" -gt 1000 ]; then
+		# authsae only allows integers as rates and not things like 5.5
+		mcval=$(($mcast_rate / 1000))
+	else
+		# compat: to still support mbit/s rates
+		mcval="$mcast_rate"
+	fi
+
+	cat > "$authsae_conf_file" <<EOF
+authsae:
+{
+ sae:
+  {
+    debug = 0;
+    password = "$key";
+    group = [19, 26, 21, 25, 20];
+    blacklist = 5;
+    thresh = 5;
+    lifetime = 3600;
+  };
+ meshd:
+  {
+    meshid = "$mesh_id";
+    interface = "$ifname";
+    passive = 0;
+    debug = 0;
+    mediaopt = 1;
+    band = "$mesh_band";
+    channel = $channel;
+    htmode = "$mesh_htmode";
+    mcast-rate = $mcval;
+  };
+};
+EOF
+
+	/usr/bin/meshd-nl80211 -i "$ifname" -s "$mesh_id" -c "$authsae_conf_file" </dev/null >/dev/null 2>/dev/null &
+	authsae_pid="$!"
+	ret="$?"
+
+	echo $authsae_pid > /var/run/authsae-$ifname.pid
+	wireless_add_process "$authsae_pid" "/usr/bin/meshd-nl80211" 1
+
+	[ "$ret" != 0 ] && wireless_setup_vif_failed AUTHSAE_FAILED
+	return $ret
+}
diff --git a/package/network/services/authsae/patches/100-musl_fix.patch b/package/network/services/authsae/patches/100-musl_fix.patch
new file mode 100644
index 0000000000..19d2d9b72f
--- /dev/null
+++ b/package/network/services/authsae/patches/100-musl_fix.patch
@@ -0,0 +1,20 @@
+--- a/linux/mon.c
++++ b/linux/mon.c
+@@ -44,7 +44,6 @@
+ #include <signal.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+-#include <sys/sysctl.h>
+ #include <sys/queue.h>
+ #include <netinet/in.h>
+ #include <net/if.h>
+--- a/linux/meshd.c
++++ b/linux/meshd.c
+@@ -44,7 +44,6 @@
+ #include <signal.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+-#include <sys/sysctl.h>
+ #include <sys/queue.h>
+ #include <netinet/in.h>
+ #include <net/if.h>
diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
new file mode 100644
index 0000000000..861cda7fbe
--- /dev/null
+++ b/package/network/services/dnsmasq/Makefile
@@ -0,0 +1,169 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dnsmasq
+PKG_VERSION:=2.76
+PKG_RELEASE:=5
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
+PKG_MD5SUM:=00f5ee66b4e4b7f14538bf62ae3c9461
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6 \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/dnsmasq/Default
+  SECTION:=net
+  CATEGORY:=Base system
+  TITLE:=DNS and DHCP server
+  URL:=http://www.thekelleys.org.uk/dnsmasq/
+  USERID:=dnsmasq=453:dnsmasq=453
+endef
+
+define Package/dnsmasq
+$(call Package/dnsmasq/Default)
+  VARIANT:=nodhcpv6
+endef
+
+define Package/dnsmasq-dhcpv6
+$(call Package/dnsmasq/Default)
+  TITLE += (with DHCPv6 support)
+  DEPENDS:=@IPV6
+  VARIANT:=dhcpv6
+endef
+
+define Package/dnsmasq-full
+$(call Package/dnsmasq/Default)
+  TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Conntrack, NO_ID enabled by default)
+  DEPENDS:=+PACKAGE_dnsmasq_full_dnssec:libnettle \
+	+PACKAGE_dnsmasq_full_ipset:kmod-ipt-ipset \
+	+PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack
+  VARIANT:=full
+endef
+
+define Package/dnsmasq/description
+  It is intended to provide coupled DNS and DHCP service to a LAN.
+endef
+
+define Package/dnsmasq-dhcpv6/description
+$(call Package/dnsmasq/description)
+
+This is a variant with DHCPv6 support
+endef
+
+define Package/dnsmasq-full/description
+$(call Package/dnsmasq/description)
+
+This is a fully configurable variant with DHCPv6, DNSSEC, Authoritative DNS and
+IPset, Conntrack support & NO_ID enabled by default.
+endef
+
+define Package/dnsmasq/conffiles
+/etc/config/dhcp
+/etc/dnsmasq.conf
+endef
+
+define Package/dnsmasq-full/config
+	if PACKAGE_dnsmasq-full
+	config PACKAGE_dnsmasq_full_dhcpv6
+		bool "Build with DHCPv6 support."
+		depends on IPV6
+		default y
+	config PACKAGE_dnsmasq_full_dnssec
+		bool "Build with DNSSEC support."
+		default y
+	config PACKAGE_dnsmasq_full_auth
+		bool "Build with the facility to act as an authoritative DNS server."
+		default y
+	config PACKAGE_dnsmasq_full_ipset
+		bool "Build with IPset support."
+		default y
+	config PACKAGE_dnsmasq_full_conntrack
+		bool "Build with Conntrack support."
+		default y
+	config PACKAGE_dnsmasq_full_noid
+		bool "Build with NO_ID. (hide *.bind pseudo domain)"
+		default y
+	config PACKAGE_dnsmasq_full_broken_rtc
+		bool "Build with HAVE_BROKEN_RTC."
+		default n
+	endif
+endef
+
+Package/dnsmasq-dhcpv6/conffiles = $(Package/dnsmasq/conffiles)
+Package/dnsmasq-full/conffiles = $(Package/dnsmasq/conffiles)
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+COPTS = $(if $(CONFIG_IPV6),,-DNO_IPV6)
+
+ifeq ($(BUILD_VARIANT),nodhcpv6)
+	COPTS += -DNO_DHCP6
+endif
+
+ifeq ($(BUILD_VARIANT),full)
+	COPTS += $(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcpv6),,-DNO_DHCP6) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec),-DHAVE_DNSSEC) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth),,-DNO_AUTH) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset),,-DNO_IPSET) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack),-DHAVE_CONNTRACK,) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid),-DNO_ID,) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc),-DHAVE_BROKEN_RTC)
+	COPTS += $(if $(CONFIG_LIBNETTLE_MINI),-DNO_GMP,)
+else
+	COPTS += -DNO_AUTH -DNO_IPSET -DNO_ID
+endif
+
+MAKE_FLAGS := \
+	$(TARGET_CONFIGURE_OPTS) \
+	CFLAGS="$(TARGET_CFLAGS)" \
+	LDFLAGS="$(TARGET_LDFLAGS)" \
+	COPTS="$(COPTS)" \
+	PREFIX="/usr"
+
+define Package/dnsmasq/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/dnsmasq $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_DATA) ./files/dhcp.conf $(1)/etc/config/dhcp
+	$(INSTALL_DATA) ./files/dnsmasq.conf $(1)/etc/dnsmasq.conf
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/dnsmasq.init $(1)/etc/init.d/dnsmasq
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/ntp
+	$(INSTALL_DATA) ./files/dnsmasqsec.hotplug $(1)/etc/hotplug.d/ntp/25-dnsmasqsec
+endef
+
+Package/dnsmasq-dhcpv6/install = $(Package/dnsmasq/install)
+
+define Package/dnsmasq-full/install
+$(call Package/dnsmasq/install,$(1))
+ifneq ($(CONFIG_PACKAGE_dnsmasq_full_dnssec),)
+	$(INSTALL_DIR) $(1)/usr/share/dnsmasq
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/trust-anchors.conf $(1)/usr/share/dnsmasq
+endif
+endef
+
+$(eval $(call BuildPackage,dnsmasq))
+$(eval $(call BuildPackage,dnsmasq-dhcpv6))
+$(eval $(call BuildPackage,dnsmasq-full))
diff --git a/package/network/services/dnsmasq/files/dhcp.conf b/package/network/services/dnsmasq/files/dhcp.conf
new file mode 100644
index 0000000000..362b90a293
--- /dev/null
+++ b/package/network/services/dnsmasq/files/dhcp.conf
@@ -0,0 +1,32 @@
+config dnsmasq
+	option domainneeded	1
+	option boguspriv	1
+	option filterwin2k	0  # enable for dial on demand
+	option localise_queries	1
+	option rebind_protection 1  # disable if upstream must serve RFC1918 addresses
+	option rebind_localhost 1  # enable for RBL checking and similar services
+	#list rebind_domain example.lan  # whitelist RFC1918 responses for domains
+	option local	'/lan/'
+	option domain	'lan'
+	option expandhosts	1
+	option nonegcache	0
+	option authoritative	1
+	option readethers	1
+	option leasefile	'/tmp/dhcp.leases'
+	option resolvfile	'/tmp/resolv.conf.auto'
+	#list server		'/mycompany.local/1.2.3.4'
+	#option nonwildcard	1
+	#list interface		br-lan
+	#list notinterface	lo
+	#list bogusnxdomain     '64.94.110.11'
+	option localservice	1  # disable to allow DNS requests from non-local subnets
+
+config dhcp lan
+	option interface	lan
+	option start 	100
+	option limit	150
+	option leasetime	12h
+
+config dhcp wan
+	option interface	wan
+	option ignore	1
diff --git a/package/network/services/dnsmasq/files/dnsmasq.conf b/package/network/services/dnsmasq/files/dnsmasq.conf
new file mode 100644
index 0000000000..bf5816be56
--- /dev/null
+++ b/package/network/services/dnsmasq/files/dnsmasq.conf
@@ -0,0 +1,37 @@
+# Change the following lines if you want dnsmasq to serve SRV
+# records.
+# You may add multiple srv-host lines.
+# The fields are <name>,<target>,<port>,<priority>,<weight>
+
+# A SRV record sending LDAP for the example.com domain to
+# ldapserver.example.com port 289
+#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
+
+# Two SRV records for LDAP, each with different priorities
+#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
+#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
+
+# A SRV record indicating that there is no LDAP server for the domain
+# example.com
+#srv-host=_ldap._tcp.example.com
+
+# The following line shows how to make dnsmasq serve an arbitrary PTR
+# record. This is useful for DNS-SD.
+# The fields are <name>,<target>
+#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
+
+# Change the following lines to enable dnsmasq to serve TXT records.
+# These are used for things like SPF and zeroconf.
+# The fields are <name>,<text>,<text>...
+
+#Example SPF.
+#txt-record=example.com,"v=spf1 a -all"
+
+#Example zeroconf
+#txt-record=_http._tcp.example.com,name=value,paper=A4
+
+# Provide an alias for a "local" DNS name. Note that this _only_ works
+# for targets which are names from DHCP or /etc/hosts. Give host
+# "bert" another name, bertrand
+# The fields are <cname>,<target>
+#cname=bertand,bert
diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init
new file mode 100644
index 0000000000..eebf5c76c8
--- /dev/null
+++ b/package/network/services/dnsmasq/files/dnsmasq.init
@@ -0,0 +1,854 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2007-2012 OpenWrt.org
+
+START=19
+
+USE_PROCD=1
+PROG=/usr/sbin/dnsmasq
+
+ADD_LOCAL_DOMAIN=1
+ADD_LOCAL_HOSTNAME=1
+
+BASECONFIGFILE="/var/etc/dnsmasq.conf"
+BASEHOSTFILE="/tmp/hosts/dhcp"
+BASETIMESTAMPFILE="/etc/dnsmasq.time"
+TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf"
+TIMEVALIDFILE="/var/state/dnsmasqsec"
+BASEDHCPSTAMPFILE="/var/run/dnsmasq"
+
+xappend() {
+	local value="$1"
+
+	echo "${value#--}" >> $CONFIGFILE_TMP
+}
+
+hex_to_hostid() {
+        local var="$1"
+        local hex="${2#0x}"     # strip optional "0x" prefix
+
+        if [ -n "${hex//[0-9a-fA-F]/}" ]; then
+                # is invalid hex literal
+                return 1
+        fi
+
+        # convert into host id
+        export "$var=$(
+                printf "%0x:%0x"  \
+                        $(((0x$hex >> 16) % 65536)) \
+                        $(( 0x$hex        % 65536))
+        )"
+
+        return 0
+}
+
+dhcp_calc() {
+	local ip="$1"
+	local res=0
+
+	while [ -n "$ip" ]; do
+		part="${ip%%.*}"
+		res="$(($res * 256))"
+		res="$(($res + $part))"
+		[ "${ip%.*}" != "$ip" ] && ip="${ip#*.}" || ip=
+	done
+	echo "$res"
+}
+
+dhcp_check() {
+	local ifname="$1"
+	local stamp="${BASEDHCPSTAMPFILE_CFG}.${ifname}.dhcp"
+	local rv=0
+
+	[ -s "$stamp" ] && return $(cat "$stamp")
+
+	# If there's no carrier yet, skip this interface.
+	# The init script will be called again once the link is up
+	case "$(devstatus "$ifname" | jsonfilter -e @.carrier)" in
+		false) return 1;;
+	esac
+
+	udhcpc -n -q -s /bin/true -t 1 -i "$ifname" >&- && rv=1 || rv=0
+
+	[ $rv -eq 1 ] && \
+		logger -t dnsmasq \
+			"found already running DHCP-server on interface '$ifname'" \
+			"refusing to start, use 'option force 1' to override"
+
+	echo $rv > "$stamp"
+	return $rv
+}
+
+log_once() {
+	pidof dnsmasq >/dev/null || \
+		logger -t dnsmasq "$@"
+}
+
+append_bool() {
+	local section="$1"
+	local option="$2"
+	local value="$3"
+	local _loctmp
+	config_get_bool _loctmp "$section" "$option" 0
+	[ $_loctmp -gt 0 ] && xappend "$value"
+}
+
+append_parm() {
+	local section="$1"
+	local option="$2"
+	local switch="$3"
+	local default="$4"
+	local _loctmp
+	config_get _loctmp "$section" "$option" "$default"
+	[ -z "$_loctmp" ] && return 0
+	xappend "$switch=$_loctmp"
+}
+
+append_server() {
+	xappend "--server=$1"
+}
+
+append_address() {
+	xappend "--address=$1"
+}
+
+append_ipset() {
+	xappend "--ipset=$1"
+}
+
+append_interface() {
+	network_get_device ifname "$1" || return
+	xappend "--interface=$ifname"
+}
+
+append_notinterface() {
+	network_get_device ifname "$1" || return
+	xappend "--except-interface=$ifname"
+}
+
+append_addnhosts() {
+	xappend "--addn-hosts=$1"
+}
+
+append_bogusnxdomain() {
+	xappend "--bogus-nxdomain=$1"
+}
+
+append_pxe_service() {
+	xappend "--pxe-service=$1"
+}
+
+filter_dnsmasq() {
+	local cfg="$1" func="$2" match_cfg="$3" found_cfg
+
+	# use entry when no instance entry set, or if it matches
+	config_get found_cfg "$cfg" "instance"
+	if [ -z "$found_cfg" -o "$found_cfg" = "$match_cfg" ]; then
+		$func $cfg
+	fi
+}
+
+dhcp_subscrid_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get subscriberid "$cfg" subscriberid
+	[ -n "$subscriberid" ] || return 0
+
+	xappend "--dhcp-subscrid=$networkid,$subscriberid"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+dhcp_remoteid_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get remoteid "$cfg" remoteid
+	[ -n "$remoteid" ] || return 0
+
+	xappend "--dhcp-remoteid=$networkid,$remoteid"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+dhcp_circuitid_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get circuitid "$cfg" circuitid
+	[ -n "$circuitid" ] || return 0
+
+	xappend "--dhcp-circuitid=$networkid,$circuitid"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+dhcp_userclass_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get userclass "$cfg" userclass
+	[ -n "$userclass" ] || return 0
+
+	xappend "--dhcp-userclass=$networkid,$userclass"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+dhcp_vendorclass_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get vendorclass "$cfg" vendorclass
+	[ -n "$vendorclass" ] || return 0
+
+	xappend "--dhcp-vendorclass=$networkid,$vendorclass"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+dhcp_match_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get match "$cfg" match
+	[ -n "$match" ] || return 0
+
+	xappend "--dhcp-match=$networkid,$match"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+dhcp_host_add() {
+	local cfg="$1"
+
+	config_get_bool force "$cfg" force 0
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] && dhcp_option_add "$cfg" "$networkid" "$force"
+
+	config_get_bool enable "$cfg" enable 1
+	[ "$enable" = "0" ] && return 0
+
+	config_get name "$cfg" name
+	config_get ip "$cfg" ip
+	[ -n "$ip" -o -n "$name" ] || return 0
+
+	config_get_bool dns "$cfg" dns 0
+	[ "$dns" = "1" -a -n "$ip" -a -n "$name" ] && {
+		echo "$ip $name${DOMAIN:+.$DOMAIN}" >> $HOSTFILE
+	}
+
+	config_get mac "$cfg" mac
+	if [ -n "$mac" ]; then
+		# --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap
+		macs=""
+		for m in $mac; do append macs "$m" ","; done
+	else
+		# --dhcp-host=lap,192.168.0.199
+		[ -n "$name" ] || return 0
+		macs="$name"
+		name=""
+	fi
+
+	config_get tag "$cfg" tag
+
+	if [ "$DHCPv6CAPABLE" -eq 1 ]; then
+		config_get hostid "$cfg" hostid
+		if [ -n "$hostid" ]; then
+			hex_to_hostid hostid "$hostid"
+		fi
+	fi
+
+	config_get_bool broadcast "$cfg" broadcast 0
+	[ "$broadcast" = "0" ] && broadcast=
+
+	config_get leasetime "$cfg" leasetime
+
+	xappend "--dhcp-host=$macs${networkid:+,net:$networkid}${broadcast:+,set:needs-broadcast}${tag:+,set:$tag}${ip:+,$ip${hostid:+,[::$hostid]}}${name:+,$name}${leasetime:+,$leasetime}"
+}
+
+dhcp_tag_add() {
+	local cfg="$1"
+
+	tag="$cfg"
+
+	[ -n "$tag" ] || return 0
+
+	config_get_bool force "$cfg" force 0
+	[ "$force" = "0" ] && force=
+
+	config_get option "$cfg" dhcp_option
+	for o in $option; do
+		xappend "--dhcp-option${force:+-force}=tag:$tag,$o"
+	done
+}
+
+dhcp_mac_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || return 0
+
+	config_get mac "$cfg" mac
+	[ -n "$mac" ] || return 0
+
+	xappend "--dhcp-mac=$networkid,$mac"
+
+	dhcp_option_add "$cfg" "$networkid"
+}
+
+dhcp_boot_add() {
+	local cfg="$1"
+
+	config_get networkid "$cfg" networkid
+
+	config_get filename "$cfg" filename
+	[ -n "$filename" ] || return 0
+
+	config_get servername "$cfg" servername
+	config_get serveraddress "$cfg" serveraddress
+
+	[ -n "$serveraddress" -a ! -n "$servername" ] && return 0
+
+	xappend "--dhcp-boot=${networkid:+net:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}"
+
+	config_get_bool force "$cfg" force 0
+
+	dhcp_option_add "$cfg" "$networkid" "$force"
+}
+
+
+dhcp_add() {
+	local cfg="$1"
+	config_get net "$cfg" interface
+	[ -n "$net" ] || return 0
+
+	config_get dhcpv4 "$cfg" dhcpv4
+	[ "$dhcpv4" != "disabled" ] || return 0
+
+	config_get networkid "$cfg" networkid
+	[ -n "$networkid" ] || networkid="$net"
+
+	network_get_subnet subnet "$net" || return 0
+	network_get_device ifname "$net" || return 0
+	network_get_protocol proto "$net" || return 0
+
+	[ "$cachelocal" = "0" ] && network_get_dnsserver dnsserver "$net" && {
+		DNS_SERVERS="$DNS_SERVERS $dnsserver"
+	}
+
+	append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && return 0
+
+	# Do not support non-static interfaces for now
+	[ static = "$proto" ] || return 0
+
+	# Override interface netmask with dhcp config if applicable
+	config_get netmask "$cfg" netmask "${subnet##*/}"
+
+	#check for an already active dhcp server on the interface, unless 'force' is set
+	config_get_bool force "$cfg" force 0
+	[ $force -gt 0 ] || dhcp_check "$ifname" || return 0
+
+	config_get start "$cfg" start
+	config_get limit "$cfg" limit
+	config_get leasetime "$cfg" leasetime
+	config_get options "$cfg" options
+	config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1
+
+	leasetime="${leasetime:-12h}"
+	start="$(dhcp_calc "${start:-100}")"
+	limit="${limit:-150}"
+	[ "$limit" -gt 0 ] && limit=$((limit-1))
+	eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)"
+	if [ "$dynamicdhcp" = "0" ]; then END="static"; fi
+	xappend "--dhcp-range=$networkid,$START,$END,$NETMASK,$leasetime${options:+ $options}"
+
+	dhcp_option_add "$cfg" "$networkid"
+}
+
+dhcp_option_add() {
+	local cfg="$1"
+	local networkid="$2"
+	local force="$3"
+
+	[ "$force" = "0" ] && force=
+
+	config_get dhcp_option "$cfg" dhcp_option
+	for o in $dhcp_option; do
+		xappend "--dhcp-option${force:+-force}=${networkid:+$networkid,}$o"
+	done
+
+}
+
+dhcp_domain_add() {
+	local cfg="$1"
+	local ip name names record
+
+	config_get names "$cfg" name "$2"
+	[ -n "$names" ] || return 0
+
+	config_get ip "$cfg" ip "$3"
+	[ -n "$ip" ] || return 0
+
+	for name in $names; do
+		record="${record:+$record }$name"
+	done
+
+	echo "$ip $record" >> $HOSTFILE
+}
+
+dhcp_srv_add() {
+	local cfg="$1"
+
+	config_get srv "$cfg" srv
+	[ -n "$srv" ] || return 0
+
+	config_get target "$cfg" target
+	[ -n "$target" ] || return 0
+
+	config_get port "$cfg" port
+	[ -n "$port" ] || return 0
+
+	config_get class "$cfg" class
+	config_get weight "$cfg" weight
+
+	local service="$srv,$target,$port${class:+,$class${weight:+,$weight}}"
+
+	xappend "--srv-host=$service"
+}
+
+dhcp_mx_add() {
+	local cfg="$1"
+	local domain relay pref
+
+	config_get domain "$cfg" domain
+	[ -n "$domain" ] || return 0
+
+	config_get relay "$cfg" relay
+	[ -n "$relay" ] || return 0
+
+	config_get pref "$cfg" pref 0
+
+	local service="$domain,$relay,$pref"
+
+	xappend "--mx-host=$service"
+}
+
+dhcp_cname_add() {
+	local cfg="$1"
+	local cname target
+
+	config_get cname "$cfg" cname
+	[ -n "$cname" ] || return 0
+
+	config_get target "$cfg" target
+	[ -n "$target" ] || return 0
+
+	xappend "--cname=${cname},${target}"
+}
+
+dhcp_hostrecord_add() {
+	local cfg="$1"
+	local names addresses record val
+
+	config_get names "$cfg" name "$2"
+	if [ -z "$names" ]; then
+		return 0
+	fi
+
+	config_get addresses "$cfg" ip "$3"
+	if [ -z "$addresses" ]; then
+		return 0
+	fi
+
+	for val in $names $addresses; do
+		record="${record:+$record,}$val"
+	done
+
+	xappend "--host-record=$record"
+}
+
+dhcp_relay_add() {
+	local cfg="$1"
+	local local_addr server_addr interface
+
+	config_get local_addr "$cfg" local_addr
+	[ -n "$local_addr" ] || return 0
+
+	config_get server_addr "$cfg" server_addr
+	[ -n "$server_addr" ] || return 0
+
+	config_get interface "$cfg" interface
+	if [ -z "$interface" ]; then
+		xappend "--dhcp-relay=$local_addr,$server_addr"
+	else
+		xappend "--dhcp-relay=$local_addr,$server_addr,$interface"
+	fi
+}
+
+dnsmasq_start()
+{
+	local cfg="$1" disabled
+
+	config_get_bool disabled "$cfg" disabled 0
+	[ "$disabled" -gt 0 ] && return 0
+
+	# reset list of DOMAINS and DNS servers (for each dnsmasq instance)
+	DNS_SERVERS=""
+	DOMAIN=""
+	CONFIGFILE="${BASECONFIGFILE}.${cfg}"
+	CONFIGFILE_TMP="${CONFIGFILE}.$$"
+	HOSTFILE="${BASEHOSTFILE}.${cfg}"
+	TIMESTAMPFILE="${BASETIMESTAMPFILE}.${cfg}"
+	BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}"
+
+	# before we can call xappend
+	mkdir -p /var/run/dnsmasq/
+	mkdir -p $(dirname $CONFIGFILE)
+	mkdir -p $(dirname $HOSTFILE)
+	mkdir -p /var/lib/misc
+	chown dnsmasq:dnsmasq /var/run/dnsmasq
+
+	[ -f "$TIMESTAMPFILE" ] && rm -f "$TIMESTAMPFILE"
+
+	echo "# auto-generated config file from /etc/config/dhcp" > $CONFIGFILE_TMP
+	echo "# auto-generated config file from /etc/config/dhcp" > $HOSTFILE
+
+	# if we did this last, we could override auto-generated config
+	[ -f /etc/dnsmasq.conf ] && {
+		xappend "--conf-file=/etc/dnsmasq.conf"
+	}
+
+	$PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0
+
+	append_bool "$cfg" authoritative "--dhcp-authoritative"
+	append_bool "$cfg" nodaemon "--no-daemon"
+	append_bool "$cfg" domainneeded "--domain-needed"
+	append_bool "$cfg" filterwin2k "--filterwin2k"
+	append_bool "$cfg" nohosts "--no-hosts"
+	append_bool "$cfg" nonegcache "--no-negcache"
+	append_bool "$cfg" strictorder "--strict-order"
+	append_bool "$cfg" logqueries "--log-queries=extra"
+	append_bool "$cfg" noresolv "--no-resolv"
+	append_bool "$cfg" localise_queries "--localise-queries"
+	append_bool "$cfg" readethers "--read-ethers"
+	append_bool "$cfg" dbus "--enable-dbus"
+	append_bool "$cfg" boguspriv "--bogus-priv"
+	append_bool "$cfg" expandhosts "--expand-hosts"
+	config_get tftp_root "$cfg" "tftp_root"
+	[ -d "$tftp_root" ] && append_bool "$cfg" enable_tftp "--enable-tftp"
+	append_bool "$cfg" tftp_no_fail "--tftp-no-fail"
+	append_bool "$cfg" nonwildcard "--bind-dynamic"
+	append_bool "$cfg" fqdn "--dhcp-fqdn"
+	append_bool "$cfg" proxydnssec "--proxy-dnssec"
+	append_bool "$cfg" localservice "--local-service"
+	append_bool "$cfg" logdhcp "--log-dhcp"
+	append_bool "$cfg" quietdhcp "--quiet-dhcp"
+	append_bool "$cfg" sequential_ip "--dhcp-sequential-ip"
+	append_bool "$cfg" allservers "--all-servers"
+	append_bool "$cfg" noping "--no-ping"
+
+	append_parm "$cfg" dhcpscript "--dhcp-script"
+	append_parm "$cfg" cachesize "--cache-size"
+	append_parm "$cfg" dnsforwardmax "--dns-forward-max"
+	append_parm "$cfg" port "--port"
+	append_parm "$cfg" ednspacket_max "--edns-packet-max"
+	append_parm "$cfg" dhcpleasemax "--dhcp-lease-max"
+	append_parm "$cfg" "queryport" "--query-port"
+	append_parm "$cfg" "minport" "--min-port"
+	append_parm "$cfg" "maxport" "--max-port"
+	append_parm "$cfg" "domain" "--domain"
+	append_parm "$cfg" "local" "--server"
+	config_list_foreach "$cfg" "server" append_server
+	config_list_foreach "$cfg" "address" append_address
+	config_list_foreach "$cfg" "ipset" append_ipset
+	config_list_foreach "$cfg" "interface" append_interface
+	config_list_foreach "$cfg" "notinterface" append_notinterface
+	config_list_foreach "$cfg" "addnhosts" append_addnhosts
+	config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain
+	append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases"
+	append_parm "$cfg" "resolvfile" "--resolv-file" "/tmp/resolv.conf.auto"
+	append_parm "$cfg" "serversfile" "--servers-file"
+	append_parm "$cfg" "tftp_root" "--tftp-root"
+	append_parm "$cfg" "dhcp_boot" "--dhcp-boot"
+	append_parm "$cfg" "local_ttl" "--local-ttl"
+	append_parm "$cfg" "pxe_prompt" "--pxe-prompt"
+	config_list_foreach "$cfg" "pxe_service" append_pxe_service
+	config_get DOMAIN "$cfg" domain
+
+	config_get_bool ADD_LOCAL_DOMAIN "$cfg" add_local_domain 1
+	config_get_bool ADD_LOCAL_HOSTNAME "$cfg" add_local_hostname 1
+
+	config_get_bool readethers "$cfg" readethers
+	[ "$readethers" = "1" -a \! -e "/etc/ethers" ] && touch /etc/ethers
+
+	config_get resolvfile $cfg resolvfile
+	config_get dhcpscript $cfg dhcpscript
+
+	config_get leasefile $cfg leasefile "/tmp/dhcp.leases"
+	[ -n "$leasefile" -a \! -e "$leasefile" ] && touch "$leasefile"
+	config_get_bool cachelocal "$cfg" cachelocal 1
+
+	config_get_bool noresolv "$cfg" noresolv 0
+	if [ "$noresolv" != "1" ]; then
+		config_get resolvfile "$cfg" resolvfile "/tmp/resolv.conf.auto"
+		# So jail doesn't complain if file missing
+		[ -n "$resolvfile" -a \! -e "$resolvfile" ] && touch "$resolvfile"
+	fi
+
+	config_get hostsfile "$cfg" dhcphostsfile
+	[ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile"
+
+	local rebind
+	config_get_bool rebind "$cfg" rebind_protection 1
+	[ $rebind -gt 0 ] && {
+		log_once \
+			"DNS rebinding protection is active," \
+			"will discard upstream RFC1918 responses!"
+		xappend "--stop-dns-rebind"
+
+		local rebind_localhost
+		config_get_bool rebind_localhost "$cfg" rebind_localhost 0
+		[ $rebind_localhost -gt 0 ] && {
+			log_once "Allowing 127.0.0.0/8 responses"
+			xappend "--rebind-localhost-ok"
+		}
+
+		append_rebind_domain() {
+			log_once "Allowing RFC1918 responses for domain $1"
+			xappend "--rebind-domain-ok=$1"
+		}
+
+		config_list_foreach "$cfg" rebind_domain append_rebind_domain
+	}
+
+	config_get_bool dnssec "$cfg" dnssec 0
+	[ "$dnssec" -gt 0 ] && {
+		xappend "--conf-file=$TRUSTANCHORSFILE"
+		xappend "--dnssec"
+		[ -x /etc/init.d/sysntpd ] && {
+			/etc/init.d/sysntpd enabled
+			[ "$?" -ne 0 -o "$(uci_get system.ntp.enabled)" = "1" ] && {
+				[ -f "$TIMEVALIDFILE" ] || xappend "--dnssec-no-timecheck"
+			}
+		}
+		append_bool "$cfg" dnsseccheckunsigned "--dnssec-check-unsigned"
+	}
+
+	config_get addmac "$cfg" addmac 0
+	[ "$addmac" != "0" ] && {
+		[ "$addmac" = "1" ] && addmac=
+		xappend "--add-mac${addmac:+="$addmac"}"
+	}
+
+	dhcp_option_add "$cfg" "" 0
+
+	xappend "--dhcp-broadcast=tag:needs-broadcast"
+
+	xappend "--addn-hosts=$HOSTFILE"
+
+	config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d"
+	[ ! -d "$dnsmasqconfdir" ] && mkdir -p $dnsmasqconfdir
+	xappend "--conf-dir=$dnsmasqconfdir"
+	xappend "--user=dnsmasq"
+	xappend "--group=dnsmasq"
+	echo >> $CONFIGFILE_TMP
+
+	config_get_bool enable_tftp "$cfg" enable_tftp 0
+	[ "$enable_tftp" -gt 0 ] && {
+		config_get tftp_root "$cfg" tftp_root
+		append EXTRA_MOUNT $tftp_root
+	}
+
+	config_foreach filter_dnsmasq host dhcp_host_add "$cfg"
+	echo >> $CONFIGFILE_TMP
+	config_foreach filter_dnsmasq boot dhcp_boot_add "$cfg"
+	config_foreach filter_dnsmasq mac dhcp_mac_add "$cfg"
+	config_foreach filter_dnsmasq tag dhcp_tag_add "$cfg"
+	config_foreach filter_dnsmasq vendorclass dhcp_vendorclass_add "$cfg"
+	config_foreach filter_dnsmasq userclass dhcp_userclass_add "$cfg"
+	config_foreach filter_dnsmasq circuitid dhcp_circuitid_add "$cfg"
+	config_foreach filter_dnsmasq remoteid dhcp_remoteid_add "$cfg"
+	config_foreach filter_dnsmasq subscrid dhcp_subscrid_add "$cfg"
+	config_foreach filter_dnsmasq match dhcp_match_add "$cfg"
+	config_foreach filter_dnsmasq domain dhcp_domain_add "$cfg"
+	config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg"
+	config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg"
+
+	# add own hostname
+	[ $ADD_LOCAL_HOSTNAME -eq 1 ] && {
+		local lanaddr lanaddr6
+		local ulaprefix="$(uci_get network @globals[0] ula_prefix)"
+		local hostname="$(uci_get system @system[0] hostname Lede)"
+
+		network_get_ipaddr lanaddr "lan" && {
+			dhcp_domain_add "" "$hostname" "$lanaddr"
+		}
+
+		[ -n "$ulaprefix" ] && network_get_ipaddrs6 lanaddr6 "lan" && {
+			for lanaddr6 in $lanaddr6; do
+				case "$lanaddr6" in
+					"${ulaprefix%%:/*}"*)
+						dhcp_domain_add "" "$hostname" "$lanaddr6"
+					;;
+				esac
+			done
+		}
+	}
+
+	echo >> $CONFIGFILE_TMP
+	config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg"
+	config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg"
+	echo >> $CONFIGFILE_TMP
+
+	config_get odhcpd_is_active odhcpd maindhcp
+	if [ "$odhcpd_is_active" != "1" ]; then
+		config_foreach filter_dnsmasq dhcp dhcp_add "$cfg"
+	fi
+
+	echo >> $CONFIGFILE_TMP
+	config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg"
+	echo >> $CONFIGFILE_TMP
+
+	echo >> $CONFIGFILE_TMP
+	mv -f $CONFIGFILE_TMP $CONFIGFILE
+
+	[ "$resolvfile" = "/tmp/resolv.conf.auto" ] && {
+		rm -f /tmp/resolv.conf
+		[ $ADD_LOCAL_DOMAIN -eq 1 ] && [ -n "$DOMAIN" ] && {
+			echo "search $DOMAIN" >> /tmp/resolv.conf
+		}
+		DNS_SERVERS="$DNS_SERVERS 127.0.0.1"
+		for DNS_SERVER in $DNS_SERVERS ; do
+			echo "nameserver $DNS_SERVER" >> /tmp/resolv.conf
+		done
+	}
+
+	procd_open_instance $cfg
+	procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid
+	procd_set_param file $CONFIGFILE
+	procd_set_param respawn
+
+	local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf"
+	if [ ! -r "$dnsmasqconffile" ]; then
+		dnsmasqconffile=/etc/dnsmasq.conf
+	fi
+
+	procd_add_jail dnsmasq ubus log
+	procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvfile $dhcpscript /etc/hosts /etc/ethers $EXTRA_MOUNT
+	procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
+
+	procd_close_instance
+}
+
+dnsmasq_stop()
+{
+	local cfg="$1"
+
+	config_get resolvfile "$cfg" "resolvfile"
+
+	#relink /tmp/resolve.conf only for main instance
+	[ "$resolvfile" = "/tmp/resolv.conf.auto" ] && {
+		[ -f /tmp/resolv.conf ] && {
+			rm -f /tmp/resolv.conf
+			ln -s "$resolvfile" /tmp/resolv.conf
+		}
+	}
+
+	rm -f ${BASEDHCPSTAMPFILE}.${cfg}.*.dhcp
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "dhcp" "system"
+	procd_add_raw_trigger "interface.*" 2000 /etc/init.d/dnsmasq reload
+}
+
+boot()
+{
+	BOOT=1
+	start "$@"
+}
+
+start_service() {
+	local instance="$1"
+	local instance_found=0
+
+	[ -n "$BOOT" ] && return
+
+	. /lib/functions/network.sh
+
+	config_cb() {
+		local type="$1"
+		local name="$2"
+		if [ "$type" = "dnsmasq" ]; then
+			if [ -n "$instance" -a "$instance" = "$name" ]; then
+				instance_found=1
+			fi
+		fi
+	}
+
+	config_load dhcp
+
+	if [ -n "$instance" ]; then
+		[ "$instance_found" -gt 0 ] || return
+		dnsmasq_start "$instance"
+	else
+		config_foreach dnsmasq_start dnsmasq
+	fi
+}
+
+reload_service() {
+	rc_procd start_service "$@"
+	killall -HUP dnsmasq
+	return 0
+}
+
+stop_service() {
+	local instance="$1"
+	local instance_found=0
+
+	config_cb() {
+		local type="$1"
+		local name="$2"
+		if [ "$type" = "dnsmasq" ]; then
+			if [ -n "$instance" -a "$instance" = "$name" ]; then
+				instance_found=1
+			fi
+		fi
+	}
+
+	config_load dhcp
+
+	if [ -n "$instance" ]; then
+		[ "$instance_found" -gt 0 ] || return
+		dnsmasq_stop "$instance"
+	else
+		config_foreach dnsmasq_stop dnsmasq
+	fi
+}
diff --git a/package/network/services/dnsmasq/files/dnsmasqsec.hotplug b/package/network/services/dnsmasq/files/dnsmasqsec.hotplug
new file mode 100644
index 0000000000..5c69314bd9
--- /dev/null
+++ b/package/network/services/dnsmasq/files/dnsmasqsec.hotplug
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+TIMEVALIDFILE="/var/state/dnsmasqsec"
+
+[ "$ACTION" = stratum ] || exit 0
+
+[ -f "$TIMEVALIDFILE" ] || {
+	echo "ntpd says time is valid" >$TIMEVALIDFILE
+	/etc/init.d/dnsmasq enabled && {
+		pid=$(pidof dnsmasq)
+		[ "$(readlink /proc/$pid/exe)" = "/usr/sbin/dnsmasq" ] && kill -SIGHUP $pid \
+		|| /etc/init.d/dnsmasq restart
+	}
+}
diff --git a/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch b/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
new file mode 100644
index 0000000000..5fc62ffab3
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/100-fix-dhcp-no-address-warning.patch
@@ -0,0 +1,47 @@
+--- a/src/dhcp.c
++++ b/src/dhcp.c
+@@ -147,7 +147,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+   ssize_t sz; 
+   int iface_index = 0, unicast_dest = 0, is_inform = 0;
+   int rcvd_iface_index;
+-  struct in_addr iface_addr;
++  struct in_addr iface_addr, *addrp = NULL;
+   struct iface_param parm;
+ #ifdef HAVE_LINUX_NETWORK
+   struct arpreq arp_req;
+@@ -277,11 +277,9 @@ void dhcp_packet(time_t now, int pxe_fd)
+     {
+       ifr.ifr_addr.sa_family = AF_INET;
+       if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
+-	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+-      else
+ 	{
+-	  my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
+-	  return;
++	  addrp = &iface_addr;
++	  iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+ 	}
+       
+       for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+@@ -300,7 +298,7 @@ void dhcp_packet(time_t now, int pxe_fd)
+       parm.relay_local.s_addr = 0;
+       parm.ind = iface_index;
+       
+-      if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
++      if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, NULL))
+ 	{
+ 	  /* If we failed to match the primary address of the interface, see if we've got a --listen-address
+ 	     for a secondary */
+@@ -320,6 +318,12 @@ void dhcp_packet(time_t now, int pxe_fd)
+ 	  complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
+ 	}    
+       
++      if (!addrp)
++        {
++          my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
++          return;
++        }
++
+       if (!iface_enumerate(AF_INET, &parm, complete_context))
+ 	return;
+ 
diff --git a/package/network/services/dnsmasq/patches/110-ipset-remove-old-kernel-support.patch b/package/network/services/dnsmasq/patches/110-ipset-remove-old-kernel-support.patch
new file mode 100644
index 0000000000..61b09d5b2c
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/110-ipset-remove-old-kernel-support.patch
@@ -0,0 +1,110 @@
+--- a/src/ipset.c
++++ b/src/ipset.c
+@@ -22,7 +22,6 @@
+ #include <errno.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+-#include <sys/utsname.h>
+ #include <arpa/inet.h>
+ #include <linux/version.h>
+ #include <linux/netlink.h>
+@@ -72,7 +71,7 @@ struct my_nfgenmsg {
+ 
+ #define NL_ALIGN(len) (((len)+3) & ~(3))
+ static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
+-static int ipset_sock, old_kernel;
++static int ipset_sock;
+ static char *buffer;
+ 
+ static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
+@@ -87,25 +86,7 @@ static inline void add_attr(struct nlmsg
+ 
+ void ipset_init(void)
+ {
+-  struct utsname utsname;
+-  int version;
+-  char *split;
+-  
+-  if (uname(&utsname) < 0)
+-    die(_("failed to find kernel version: %s"), NULL, EC_MISC);
+-  
+-  split = strtok(utsname.release, ".");
+-  version = (split ? atoi(split) : 0);
+-  split = strtok(NULL, ".");
+-  version = version * 256 + (split ? atoi(split) : 0);
+-  split = strtok(NULL, ".");
+-  version = version * 256 + (split ? atoi(split) : 0);
+-  old_kernel = (version < KERNEL_VERSION(2,6,32));
+-  
+-  if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
+-    return;
+-  
+-  if (!old_kernel && 
++  if ( 
+       (buffer = safe_malloc(BUFF_SZ)) &&
+       (ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
+       (bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
+@@ -168,62 +149,16 @@ static int new_add_to_ipset(const char *
+ }
+ 
+ 
+-static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
+-{
+-  socklen_t size;
+-  struct ip_set_req_adt_get {
+-    unsigned op;
+-    unsigned version;
+-    union {
+-      char name[IPSET_MAXNAMELEN];
+-      uint16_t index;
+-    } set;
+-    char typename[IPSET_MAXNAMELEN];
+-  } req_adt_get;
+-  struct ip_set_req_adt {
+-    unsigned op;
+-    uint16_t index;
+-    uint32_t ip;
+-  } req_adt;
+-  
+-  if (strlen(setname) >= sizeof(req_adt_get.set.name)) 
+-    {
+-      errno = ENAMETOOLONG;
+-      return -1;
+-    }
+-  
+-  req_adt_get.op = 0x10;
+-  req_adt_get.version = 3;
+-  strcpy(req_adt_get.set.name, setname);
+-  size = sizeof(req_adt_get);
+-  if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
+-    return -1;
+-  req_adt.op = remove ? 0x102 : 0x101;
+-  req_adt.index = req_adt_get.set.index;
+-  req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
+-  if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
+-    return -1;
+-  
+-  return 0;
+-}
+-
+-
+-
+ int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
+ {
+   int af = AF_INET;
+ 
+ #ifdef HAVE_IPV6
+   if (flags & F_IPV6)
+-    {
+       af = AF_INET6;
+-      /* old method only supports IPv4 */
+-      if (old_kernel)
+-	return -1;
+-    }
+ #endif
+   
+-  return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
++  return new_add_to_ipset(setname, ipaddr, af, remove);
+ }
+ 
+ #endif
diff --git a/package/network/services/dnsmasq/patches/120-dnsmasq-compile-time-option-NO_ID.patch b/package/network/services/dnsmasq/patches/120-dnsmasq-compile-time-option-NO_ID.patch
new file mode 100644
index 0000000000..152d1a7fa9
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/120-dnsmasq-compile-time-option-NO_ID.patch
@@ -0,0 +1,149 @@
+From f6bea86c78ba9efbd01da3dd2fb18764ec806290 Mon Sep 17 00:00:00 2001
+From: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+Date: Wed, 7 Sep 2016 09:35:07 +0100
+Subject: [PATCH] dnsmasq: compile time option NO_ID
+
+Some consider it good practice to obscure software version numbers to
+clients.  Compiling with -DNO_ID removes the *.bind info structure.
+This includes: version, author, copyright, cachesize, cache insertions,
+evictions, misses & hits, auth & servers.
+
+Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+---
+ src/cache.c   | 2 ++
+ src/config.h  | 5 +++++
+ src/dnsmasq.h | 4 ++++
+ src/option.c  | 8 ++++++--
+ src/rfc1035.c | 3 ++-
+ 5 files changed, 19 insertions(+), 3 deletions(-)
+
+--- a/src/cache.c
++++ b/src/cache.c
+@@ -1290,6 +1290,7 @@ void cache_add_dhcp_entry(char *host_nam
+ }
+ #endif
+ 
++#ifndef NO_ID
+ int cache_make_stat(struct txt_record *t)
+ { 
+   static char *buff = NULL;
+@@ -1385,6 +1386,7 @@ int cache_make_stat(struct txt_record *t
+   *buff = len;
+   return 1;
+ }
++#endif
+ 
+ /* There can be names in the cache containing control chars, don't 
+    mess up logging or open security holes. */
+--- a/src/config.h
++++ b/src/config.h
+@@ -120,6 +120,8 @@ HAVE_LOOP
+ HAVE_INOTIFY
+    use the Linux inotify facility to efficiently re-read configuration files.
+ 
++NO_ID
++   Don't report *.bind CHAOS info to clients.
+ NO_IPV6
+ NO_TFTP
+ NO_DHCP
+@@ -434,6 +436,9 @@ static char *compile_opts =
+ "no-"
+ #endif
+ "DNSSEC "
++#ifdef NO_ID
++"no-ID "
++#endif
+ #ifndef HAVE_LOOP
+ "no-"
+ #endif
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -286,6 +286,7 @@ struct naptr {
+   struct naptr *next;
+ };
+ 
++#ifndef NO_ID
+ #define TXT_STAT_CACHESIZE     1
+ #define TXT_STAT_INSERTS       2
+ #define TXT_STAT_EVICTIONS     3
+@@ -293,6 +294,7 @@ struct naptr {
+ #define TXT_STAT_HITS          5
+ #define TXT_STAT_AUTH          6
+ #define TXT_STAT_SERVERS       7
++#endif
+ 
+ struct txt_record {
+   char *name;
+@@ -1078,7 +1080,9 @@ void cache_add_dhcp_entry(char *host_nam
+ struct in_addr a_record_from_hosts(char *name, time_t now);
+ void cache_unhash_dhcp(void);
+ void dump_cache(time_t now);
++#ifndef NO_ID
+ int cache_make_stat(struct txt_record *t);
++#endif
+ char *cache_get_name(struct crec *crecp);
+ char *cache_get_cname_target(struct crec *crecp);
+ struct crec *cache_enumerate(int init);
+--- a/src/option.c
++++ b/src/option.c
+@@ -657,7 +657,8 @@ static int atoi_check8(char *a, int *res
+   return 1;
+ }
+ #endif
+-	
++
++#ifndef NO_ID
+ static void add_txt(char *name, char *txt, int stat)
+ {
+   struct txt_record *r = opt_malloc(sizeof(struct txt_record));
+@@ -670,13 +671,14 @@ static void add_txt(char *name, char *tx
+       *(r->txt) = len;
+       memcpy((r->txt)+1, txt, len);
+     }
+-  
++
+   r->stat = stat;
+   r->name = opt_string_alloc(name);
+   r->next = daemon->txt;
+   daemon->txt = r;
+   r->class = C_CHAOS;
+ }
++#endif
+ 
+ static void do_usage(void)
+ {
+@@ -4515,6 +4517,7 @@ void read_opts(int argc, char **argv, ch
+   daemon->soa_expiry = SOA_EXPIRY;
+   daemon->max_port = MAX_PORT;
+ 
++#ifndef NO_ID
+   add_txt("version.bind", "dnsmasq-" VERSION, 0 );
+   add_txt("authors.bind", "Simon Kelley", 0);
+   add_txt("copyright.bind", COPYRIGHT, 0);
+@@ -4527,6 +4530,7 @@ void read_opts(int argc, char **argv, ch
+   add_txt("auth.bind", NULL, TXT_STAT_AUTH);
+ #endif
+   add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
++#endif
+ 
+   while (1) 
+     {
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1264,6 +1264,7 @@ size_t answer_request(struct dns_header
+ 		      unsigned long ttl = daemon->local_ttl;
+ 		      int ok = 1;
+ 		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
++#ifndef NO_ID
+ 		      /* Dynamically generate stat record */
+ 		      if (t->stat != 0)
+ 			{
+@@ -1271,7 +1272,7 @@ size_t answer_request(struct dns_header
+ 			  if (!cache_make_stat(t))
+ 			    ok = 0;
+ 			}
+-		      
++#endif
+ 		      if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+ 						    ttl, NULL,
+ 						    T_TXT, t->class, "t", t->len, t->txt))
diff --git a/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch b/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch
new file mode 100644
index 0000000000..ca5a806696
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/210-dnssec-improve-timestamp-heuristic.patch
@@ -0,0 +1,47 @@
+From 79e60e145f8a595bca5a784c00b437216d51de68 Mon Sep 17 00:00:00 2001
+From: Steven Barth <steven@midlink.org>
+Date: Mon, 13 Apr 2015 09:45:20 +0200
+Subject: [PATCH] dnssec: improve timestamp heuristic
+
+Signed-off-by: Steven Barth <steven@midlink.org>
+---
+ src/dnssec.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -462,17 +462,24 @@ static time_t timestamp_time;
+ int setup_timestamp(void)
+ {
+   struct stat statbuf;
++  time_t now;
++  time_t base = 1420070400; /* 1-1-2015 */
+   
+   daemon->back_to_the_future = 0;
+   
+   if (!daemon->timestamp_file)
+     return 0;
++
++  now = time(NULL);
++
++  if (!stat("/proc/self/exe", &statbuf) && difftime(statbuf.st_mtime, base) > 0)
++    base = statbuf.st_mtime;
+   
+   if (stat(daemon->timestamp_file, &statbuf) != -1)
+     {
+       timestamp_time = statbuf.st_mtime;
+     check_and_exit:
+-      if (difftime(timestamp_time, time(0)) <=  0)
++      if (difftime(now, base) >= 0 && difftime(timestamp_time, now) <= 0)
+ 	{
+ 	  /* time already OK, update timestamp, and do key checking from the start. */
+ 	  if (utime(daemon->timestamp_file, NULL) == -1)
+@@ -493,7 +500,7 @@ int setup_timestamp(void)
+ 
+ 	  close(fd);
+ 	  
+-	  timestamp_time = timbuf.actime = timbuf.modtime = 1420070400; /* 1-1-2015 */
++	  timestamp_time = timbuf.actime = timbuf.modtime = base;
+ 	  if (utime(daemon->timestamp_file, &timbuf) == 0)
+ 	    goto check_and_exit;
+ 	}
diff --git a/package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch b/package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch
new file mode 100644
index 0000000000..19300f7d66
--- /dev/null
+++ b/package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch
@@ -0,0 +1,18 @@
+dnsmasq: fix warning with poll.h include on musl
+
+Warning is:
+  #warning redirecting incorrect #include <sys/poll.h> to <poll.h>
+
+Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -82,7 +82,7 @@ typedef unsigned long long u64;
+ #if defined(HAVE_SOLARIS_NETWORK)
+ #  include <sys/sockio.h>
+ #endif
+-#include <sys/poll.h>
++#include <poll.h>
+ #include <sys/wait.h>
+ #include <sys/time.h>
+ #include <sys/un.h>
diff --git a/package/network/services/dropbear/Config.in b/package/network/services/dropbear/Config.in
new file mode 100644
index 0000000000..7c2edd79f2
--- /dev/null
+++ b/package/network/services/dropbear/Config.in
@@ -0,0 +1,50 @@
+menu "Configuration"
+	depends on PACKAGE_dropbear
+
+config DROPBEAR_CURVE25519
+	bool "Curve25519 support"
+	default y
+	help
+		This enables the following key exchange algorithm:
+		  curve25519-sha256@libssh.org
+
+		Increases binary size by about 13 kB uncompressed (MIPS).
+
+config DROPBEAR_ECC
+	bool "Elliptic curve cryptography (ECC)"
+	default n
+	help
+		Enables elliptic curve cryptography (ECC) support in key exchange and public key
+		authentication.
+
+		Key exchange algorithms:
+		  ecdh-sha2-nistp256
+		  ecdh-sha2-nistp384
+		  ecdh-sha2-nistp521
+
+		Public key algorithms:
+		  ecdsa-sha2-nistp256
+		  ecdsa-sha2-nistp384
+		  ecdsa-sha2-nistp521
+
+		Does not generate ECC host keys by default (ECC key exchange will not be used,
+		only ECC public key auth).
+
+		Increases binary size by about 23 kB (MIPS).
+
+config DROPBEAR_UTMP
+	bool "Utmp support"
+	default n
+	depends on BUSYBOX_CONFIG_FEATURE_UTMP
+	help
+		This enables dropbear utmp support, the file /var/run/utmp is used to
+		track who is currently logged in.
+
+config DROPBEAR_PUTUTLINE
+	bool "Pututline support"
+	default n
+	depends on DROPBEAR_UTMP
+	help
+		Dropbear will use pututline() to write the utmp structure into the utmp file.
+
+endmenu
diff --git a/package/network/services/dropbear/Makefile b/package/network/services/dropbear/Makefile
new file mode 100644
index 0000000000..41c66dd43c
--- /dev/null
+++ b/package/network/services/dropbear/Makefile
@@ -0,0 +1,148 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dropbear
+PKG_VERSION:=2016.74
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://matt.ucc.asn.au/dropbear/releases/ \
+	https://dropbear.nl/mirror/releases/
+PKG_MD5SUM:=9ad0172731e0f16623937804643b5bd8
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
+
+PKG_BUILD_PARALLEL:=1
+PKG_USE_MIPS16:=0
+
+PKG_CONFIG_DEPENDS:=CONFIG_TARGET_INIT_PATH CONFIG_DROPBEAR_ECC CONFIG_DROPBEAR_CURVE25519
+
+include $(INCLUDE_DIR)/package.mk
+
+ifneq ($(DUMP),1)
+  STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell $(SH_FUNC) echo $(CONFIG_TARGET_INIT_PATH) | md5s)
+endif
+
+define Package/dropbear/Default
+  URL:=http://matt.ucc.asn.au/dropbear/
+endef
+
+define Package/dropbear/config
+	source "$(SOURCE)/Config.in"
+endef
+
+define Package/dropbear
+  $(call Package/dropbear/Default)
+  SECTION:=net
+  CATEGORY:=Base system
+  TITLE:=Small SSH2 client/server
+endef
+
+define Package/dropbear/description
+ A small SSH2 server/client designed for small memory environments.
+endef
+
+define Package/dropbear/conffiles
+/etc/dropbear/dropbear_rsa_host_key
+/etc/config/dropbear 
+endef
+
+define Package/dropbearconvert
+  $(call Package/dropbear/Default)
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Utility for converting SSH keys
+endef
+
+CONFIGURE_ARGS += \
+	--disable-pam \
+	--enable-openpty \
+	--enable-syslog \
+	--disable-lastlog \
+	--disable-utmpx \
+	$(if $(CONFIG_DROPBEAR_UTMP),,--disable-utmp) \
+	--disable-wtmp \
+	--disable-wtmpx \
+	--disable-loginfunc \
+	$(if $(CONFIG_DROPBEAR_PUTUTLINE),,--disable-pututline) \
+	--disable-pututxline \
+	--disable-zlib \
+	--enable-bundled-libtom
+
+TARGET_CFLAGS += -DDEFAULT_PATH=\\\"$(CONFIG_TARGET_INIT_PATH)\\\" -DARGTYPE=3 -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+define Build/Configure
+	$(Build/Configure/Default)
+
+	$(SED) 's,^#define DEFAULT_PATH .*$$$$,#define DEFAULT_PATH "$(CONFIG_TARGET_INIT_PATH)",g' \
+		$(PKG_BUILD_DIR)/options.h
+
+	awk 'BEGIN { rc = 1 } \
+	     /'DROPBEAR_CURVE25519'/ { $$$$0 = "$(if $(CONFIG_DROPBEAR_CURVE25519),,// )#define 'DROPBEAR_CURVE25519'"; rc = 0 } \
+	     { print } \
+	     END { exit(rc) }' $(PKG_BUILD_DIR)/options.h \
+	     >$(PKG_BUILD_DIR)/options.h.new && \
+	mv $(PKG_BUILD_DIR)/options.h.new $(PKG_BUILD_DIR)/options.h
+
+	# Enforce that all replacements are made, otherwise options.h has changed
+	# format and this logic is broken.
+	for OPTION in DROPBEAR_ECDSA DROPBEAR_ECDH; do \
+	  awk 'BEGIN { rc = 1 } \
+	       /'$$$$OPTION'/ { $$$$0 = "$(if $(CONFIG_DROPBEAR_ECC),,// )#define '$$$$OPTION'"; rc = 0 } \
+	       { print } \
+	       END { exit(rc) }' $(PKG_BUILD_DIR)/options.h \
+	       >$(PKG_BUILD_DIR)/options.h.new && \
+	  mv $(PKG_BUILD_DIR)/options.h.new $(PKG_BUILD_DIR)/options.h || exit 1; \
+	done
+
+	# remove protocol idented software version number
+	$(SED) 's,^#define LOCAL_IDENT .*$$$$,#define LOCAL_IDENT "SSH-2.0-dropbear",g' \
+		$(PKG_BUILD_DIR)/sysoptions.h
+
+	# Enforce rebuild of svr-chansession.c
+	rm -f $(PKG_BUILD_DIR)/svr-chansession.o
+endef
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		PROGRAMS="dropbear dbclient dropbearkey scp" \
+		MULTI=1 SCPPROGRESS=1
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		PROGRAMS="dropbearconvert"
+endef
+
+define Package/dropbear/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/dropbearmulti $(1)/usr/sbin/dropbear
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(LN) ../sbin/dropbear $(1)/usr/bin/scp
+	$(LN) ../sbin/dropbear $(1)/usr/bin/ssh
+	$(LN) ../sbin/dropbear $(1)/usr/bin/dbclient
+	$(LN) ../sbin/dropbear $(1)/usr/bin/dropbearkey
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_DATA) ./files/dropbear.config $(1)/etc/config/dropbear
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/dropbear.init $(1)/etc/init.d/dropbear
+	$(INSTALL_DIR) $(1)/usr/lib/opkg/info
+	$(INSTALL_DIR) $(1)/etc/dropbear
+	touch $(1)/etc/dropbear/dropbear_rsa_host_key
+endef
+
+define Package/dropbearconvert/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/dropbearconvert $(1)/usr/bin/dropbearconvert
+endef
+
+$(eval $(call BuildPackage,dropbear))
+$(eval $(call BuildPackage,dropbearconvert))
diff --git a/package/network/services/dropbear/files/dropbear.config b/package/network/services/dropbear/files/dropbear.config
new file mode 100644
index 0000000000..2139ba0bbe
--- /dev/null
+++ b/package/network/services/dropbear/files/dropbear.config
@@ -0,0 +1,5 @@
+config dropbear
+	option PasswordAuth 'on'
+	option RootPasswordAuth 'on'
+	option Port         '22'
+#	option BannerFile   '/etc/banner'
diff --git a/package/network/services/dropbear/files/dropbear.init b/package/network/services/dropbear/files/dropbear.init
new file mode 100755
index 0000000000..c5210cde81
--- /dev/null
+++ b/package/network/services/dropbear/files/dropbear.init
@@ -0,0 +1,196 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006-2010 OpenWrt.org
+# Copyright (C) 2006 Carlos Sobrinho
+
+START=50
+STOP=50
+
+USE_PROCD=1
+PROG=/usr/sbin/dropbear
+NAME=dropbear
+PIDCOUNT=0
+EXTRA_COMMANDS="killclients"
+EXTRA_HELP="	killclients Kill ${NAME} processes except servers and yourself"
+
+append_ports()
+{
+	local ipaddrs="$1"
+	local port="$2"
+
+	[ -z "$ipaddrs" ] && {
+		procd_append_param command -p "$port"
+		return
+	}
+
+	for addr in $ipaddrs; do
+		procd_append_param command -p "$addr:$port"
+	done
+}
+
+validate_section_dropbear()
+{
+	uci_validate_section dropbear dropbear "${1}" \
+		'PasswordAuth:bool:1' \
+		'enable:bool:1' \
+		'Interface:string' \
+		'GatewayPorts:bool:0' \
+		'RootPasswordAuth:bool:1' \
+		'RootLogin:bool:1' \
+		'rsakeyfile:file' \
+		'BannerFile:file' \
+		'Port:list(port):22' \
+		'SSHKeepAlive:uinteger:300' \
+		'IdleTimeout:uinteger:0' \
+		'mdns:bool:1'
+}
+
+dropbear_instance()
+{
+	local PasswordAuth enable Interface GatewayPorts \
+		RootPasswordAuth RootLogin rsakeyfile \
+		BannerFile Port SSHKeepAlive IdleTimeout \
+		mdns ipaddrs
+
+	validate_section_dropbear "${1}" || {
+		echo "validation failed"
+		return 1
+	}
+
+	[ -n "${Interface}" ] && {
+		network_get_ipaddrs_all ipaddrs "${Interface}" || {
+			echo "interface ${Interface} has no physdev or physdev has no suitable ip"
+			return 1
+		}
+	}
+
+	[ "${enable}" = "0" ] && return 1
+	PIDCOUNT="$(( ${PIDCOUNT} + 1))"
+	local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
+
+	procd_open_instance
+	procd_set_param command "$PROG" -F -P "$pid_file"
+	[ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s
+	[ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a
+	[ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g
+	[ "${RootLogin}" -eq 0 ] && procd_append_param command -w
+	[ -n "${rsakeyfile}" ] && procd_append_param command -r "${rsakeyfile}"
+	[ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
+	append_ports "${ipaddrs}" "${Port}"
+	[ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
+	[ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
+	[ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear"
+	procd_set_param respawn
+	procd_close_instance
+}
+
+keygen()
+{
+	for keytype in rsa; do
+		# check for keys
+		key=dropbear/dropbear_${keytype}_host_key
+		[ -f /tmp/$key -o -s /etc/$key ] || {
+			# generate missing keys
+			mkdir -p /tmp/dropbear
+			[ -x /usr/bin/dropbearkey ] && {
+				/usr/bin/dropbearkey -t $keytype -f /tmp/$key 2>&- >&- && exec /etc/rc.common "$initscript" start
+			} &
+		exit 0
+		}
+	done
+
+	lock /tmp/.switch2jffs
+	mkdir -p /etc/dropbear
+	mv /tmp/dropbear/dropbear_* /etc/dropbear/
+	lock -u /tmp/.switch2jffs
+	chown root /etc/dropbear
+	chmod 0700 /etc/dropbear
+}
+
+load_interfaces()
+{
+	config_get interface "$1" Interface
+	interfaces=" ${interface} ${interfaces}"
+}
+
+start_service()
+{
+	[ -s /etc/dropbear/dropbear_rsa_host_key ] || keygen
+
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+
+	config_load "${NAME}"
+	config_foreach dropbear_instance dropbear
+}
+
+service_triggers()
+{
+	local interfaces
+
+	procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload
+
+	config_load "${NAME}"
+	config_foreach load_interfaces dropbear
+
+	[ -n "${interfaces}" ] & {
+		for n in $interfaces ; do
+			procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload
+		done
+	}
+
+	procd_add_validation validate_section_dropbear
+}
+
+killclients()
+{
+	local ignore=''
+	local server
+	local pid
+
+	# if this script is run from inside a client session, then ignore that session
+	pid="$$"
+	while [ "${pid}" -ne 0 ]
+	 do
+		# get parent process id
+		pid=`cut -d ' ' -f 4 "/proc/${pid}/stat"`
+		[ "${pid}" -eq 0 ] && break
+
+		# check if client connection
+		grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" && {
+			append ignore "${pid}"
+			break
+		}
+	done
+
+	# get all server pids that should be ignored
+	for server in `cat /var/run/${NAME}.*.pid`
+	 do
+		append ignore "${server}"
+	done
+
+	# get all running pids and kill client connections
+	local skip
+	for pid in `pidof "${NAME}"`
+	 do
+		# check if correct program, otherwise process next pid
+		grep -F -q -e "${PROG}" "/proc/${pid}/cmdline" || {
+			continue
+		}
+
+		# check if pid should be ignored (servers, ourself)
+		skip=0
+		for server in ${ignore}
+		 do
+			if [ "${pid}" = "${server}" ]
+			 then
+				skip=1
+				break
+			fi
+		done
+		[ "${skip}" -ne 0 ] && continue
+
+		# kill process
+		echo "${initscript}: Killing ${pid}..."
+		kill -KILL ${pid}
+	done
+}
diff --git a/package/network/services/dropbear/patches/100-pubkey_path.patch b/package/network/services/dropbear/patches/100-pubkey_path.patch
new file mode 100644
index 0000000000..41fdc1adab
--- /dev/null
+++ b/package/network/services/dropbear/patches/100-pubkey_path.patch
@@ -0,0 +1,91 @@
+--- a/svr-authpubkey.c
++++ b/svr-authpubkey.c
+@@ -218,17 +218,21 @@ static int checkpubkey(char* algo, unsig
+ 		goto out;
+ 	}
+ 
+-	/* we don't need to check pw and pw_dir for validity, since
+-	 * its been done in checkpubkeyperms. */
+-	len = strlen(ses.authstate.pw_dir);
+-	/* allocate max required pathname storage,
+-	 * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
+-	filename = m_malloc(len + 22);
+-	snprintf(filename, len + 22, "%s/.ssh/authorized_keys", 
+-				ses.authstate.pw_dir);
+-
+-	/* open the file */
+-	authfile = fopen(filename, "r");
++	if (ses.authstate.pw_uid != 0) {
++		/* we don't need to check pw and pw_dir for validity, since
++		 * its been done in checkpubkeyperms. */
++		len = strlen(ses.authstate.pw_dir);
++		/* allocate max required pathname storage,
++		 * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
++		filename = m_malloc(len + 22);
++		snprintf(filename, len + 22, "%s/.ssh/authorized_keys", 
++		         ses.authstate.pw_dir);
++
++		/* open the file */
++		authfile = fopen(filename, "r");
++	} else {
++		authfile = fopen("/etc/dropbear/authorized_keys","r");
++	}
+ 	if (authfile == NULL) {
+ 		goto out;
+ 	}
+@@ -381,26 +385,35 @@ static int checkpubkeyperms() {
+ 		goto out;
+ 	}
+ 
+-	/* allocate max required pathname storage,
+-	 * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
+-	filename = m_malloc(len + 22);
+-	strncpy(filename, ses.authstate.pw_dir, len+1);
+-
+-	/* check ~ */
+-	if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+-		goto out;
+-	}
+-
+-	/* check ~/.ssh */
+-	strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
+-	if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+-		goto out;
+-	}
+-
+-	/* now check ~/.ssh/authorized_keys */
+-	strncat(filename, "/authorized_keys", 16);
+-	if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+-		goto out;
++	if (ses.authstate.pw_uid == 0) {
++		if (checkfileperm("/etc/dropbear") != DROPBEAR_SUCCESS) {
++			goto out;
++		}
++		if (checkfileperm("/etc/dropbear/authorized_keys") != DROPBEAR_SUCCESS) {
++			goto out;
++		}
++	} else {
++		/* allocate max required pathname storage,
++		 * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
++		filename = m_malloc(len + 22);
++		strncpy(filename, ses.authstate.pw_dir, len+1);
++
++		/* check ~ */
++		if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
++			goto out;
++		}
++
++		/* check ~/.ssh */
++		strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
++		if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
++			goto out;
++		}
++
++		/* now check ~/.ssh/authorized_keys */
++		strncat(filename, "/authorized_keys", 16);
++		if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
++			goto out;
++		}
+ 	}
+ 
+ 	/* file looks ok, return success */
diff --git a/package/network/services/dropbear/patches/110-change_user.patch b/package/network/services/dropbear/patches/110-change_user.patch
new file mode 100644
index 0000000000..4b5c1cb51b
--- /dev/null
+++ b/package/network/services/dropbear/patches/110-change_user.patch
@@ -0,0 +1,18 @@
+--- a/svr-chansession.c
++++ b/svr-chansession.c
+@@ -922,12 +922,12 @@ static void execchild(void *user_data) {
+ 	/* We can only change uid/gid as root ... */
+ 	if (getuid() == 0) {
+ 
+-		if ((setgid(ses.authstate.pw_gid) < 0) ||
++		if ((ses.authstate.pw_gid != 0) && ((setgid(ses.authstate.pw_gid) < 0) ||
+ 			(initgroups(ses.authstate.pw_name, 
+-						ses.authstate.pw_gid) < 0)) {
++						ses.authstate.pw_gid) < 0))) {
+ 			dropbear_exit("Error changing user group");
+ 		}
+-		if (setuid(ses.authstate.pw_uid) < 0) {
++		if ((ses.authstate.pw_uid != 0) && (setuid(ses.authstate.pw_uid) < 0)) {
+ 			dropbear_exit("Error changing user");
+ 		}
+ 	} else {
diff --git a/package/network/services/dropbear/patches/120-openwrt_options.patch b/package/network/services/dropbear/patches/120-openwrt_options.patch
new file mode 100644
index 0000000000..f16aaf001e
--- /dev/null
+++ b/package/network/services/dropbear/patches/120-openwrt_options.patch
@@ -0,0 +1,81 @@
+--- a/options.h
++++ b/options.h
+@@ -41,7 +41,7 @@
+  * Both of these flags can be defined at once, don't compile without at least
+  * one of them. */
+ #define NON_INETD_MODE
+-#define INETD_MODE
++/*#define INETD_MODE*/
+ 
+ /* Setting this disables the fast exptmod bignum code. It saves ~5kB, but is
+  * perhaps 20% slower for pubkey operations (it is probably worth experimenting
+@@ -81,7 +81,7 @@ much traffic. */
+ 
+ /* Enable "Netcat mode" option. This will forward standard input/output
+  * to a remote TCP-forwarded connection */
+-#define ENABLE_CLI_NETCAT
++/*#define ENABLE_CLI_NETCAT*/
+ 
+ /* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
+ #define ENABLE_USER_ALGO_LIST
+@@ -91,16 +91,16 @@ much traffic. */
+  * Including multiple keysize variants the same cipher 
+  * (eg AES256 as well as AES128) will result in a minimal size increase.*/
+ #define DROPBEAR_AES128
+-#define DROPBEAR_3DES
++/*#define DROPBEAR_3DES*/
+ #define DROPBEAR_AES256
+ /* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
+ /*#define DROPBEAR_BLOWFISH*/
+-#define DROPBEAR_TWOFISH256
+-#define DROPBEAR_TWOFISH128
++/*#define DROPBEAR_TWOFISH256*/
++/*#define DROPBEAR_TWOFISH128*/
+ 
+ /* Enable CBC mode for ciphers. This has security issues though
+  * is the most compatible with older SSH implementations */
+-#define DROPBEAR_ENABLE_CBC_MODE
++/*#define DROPBEAR_ENABLE_CBC_MODE*/
+ 
+ /* Enable "Counter Mode" for ciphers. This is more secure than normal
+  * CBC mode against certain attacks. It is recommended for security
+@@ -131,9 +131,9 @@ If you test it please contact the Dropbe
+  * If you disable MD5, Dropbear will fall back to SHA1 fingerprints,
+  * which are not the standard form. */
+ #define DROPBEAR_SHA1_HMAC
+-#define DROPBEAR_SHA1_96_HMAC
+-#define DROPBEAR_SHA2_256_HMAC
+-#define DROPBEAR_SHA2_512_HMAC
++/*#define DROPBEAR_SHA1_96_HMAC*/
++/*#define DROPBEAR_SHA2_256_HMAC*/
++/*#define DROPBEAR_SHA2_512_HMAC*/
+ #define DROPBEAR_MD5_HMAC
+ 
+ /* You can also disable integrity. Don't bother disabling this if you're
+@@ -146,7 +146,7 @@ If you test it please contact the Dropbe
+  * Removing either of these won't save very much space.
+  * SSH2 RFC Draft requires dss, recommends rsa */
+ #define DROPBEAR_RSA
+-#define DROPBEAR_DSS
++/*#define DROPBEAR_DSS*/
+ /* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
+  * code (either ECDSA or ECDH) increases binary size - around 30kB
+  * on x86-64 */
+@@ -194,7 +194,7 @@ If you test it please contact the Dropbe
+ 
+ /* Whether to print the message of the day (MOTD). This doesn't add much code
+  * size */
+-#define DO_MOTD
++/*#define DO_MOTD*/
+ 
+ /* The MOTD file path */
+ #ifndef MOTD_FILENAME
+@@ -242,7 +242,7 @@ Homedir is prepended unless path begins
+  * note that it will be provided for all "hidden" client-interactive
+  * style prompts - if you want something more sophisticated, use 
+  * SSH_ASKPASS instead. Comment out this var to remove this functionality.*/
+-#define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD"
++/*#define DROPBEAR_PASSWORD_ENV "DROPBEAR_PASSWORD"*/
+ 
+ /* Define this (as well as ENABLE_CLI_PASSWORD_AUTH) to allow the use of
+  * a helper program for the ssh client. The helper program should be
diff --git a/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
new file mode 100644
index 0000000000..ab09c2f3dc
--- /dev/null
+++ b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
@@ -0,0 +1,11 @@
+--- a/cli-runopts.c
++++ b/cli-runopts.c
+@@ -296,6 +296,8 @@ void cli_getopts(int argc, char ** argv)
+ 					debug_trace = 1;
+ 					break;
+ #endif
++				case 'x':
++					break;
+ 				case 'F':
+ 				case 'e':
+ #ifndef ENABLE_USER_ALGO_LIST
diff --git a/package/network/services/dropbear/patches/140-disable_assert.patch b/package/network/services/dropbear/patches/140-disable_assert.patch
new file mode 100644
index 0000000000..78b54acfa0
--- /dev/null
+++ b/package/network/services/dropbear/patches/140-disable_assert.patch
@@ -0,0 +1,15 @@
+--- a/dbutil.h
++++ b/dbutil.h
+@@ -78,7 +78,11 @@ int m_str_to_uint(const char* str, unsig
+ #define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
+ 
+ /* Dropbear assertion */
+-#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
++#ifndef DROPBEAR_ASSERT_ENABLED
++#define DROPBEAR_ASSERT_ENABLED 0
++#endif
++
++#define dropbear_assert(X) do { if (DROPBEAR_ASSERT_ENABLED && !(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
+ 
+ /* Returns 0 if a and b have the same contents */
+ int constant_time_memcmp(const void* a, const void *b, size_t n);
diff --git a/package/network/services/dropbear/patches/150-dbconvert_standalone.patch b/package/network/services/dropbear/patches/150-dbconvert_standalone.patch
new file mode 100644
index 0000000000..ccc2cb7925
--- /dev/null
+++ b/package/network/services/dropbear/patches/150-dbconvert_standalone.patch
@@ -0,0 +1,14 @@
+--- a/options.h
++++ b/options.h
+@@ -5,6 +5,11 @@
+ #ifndef DROPBEAR_OPTIONS_H_
+ #define DROPBEAR_OPTIONS_H_
+ 
++#if !defined(DROPBEAR_CLIENT) && !defined(DROPBEAR_SERVER)
++#define DROPBEAR_SERVER
++#define DROPBEAR_CLIENT
++#endif
++
+ /* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
+  * parts are to allow for commandline -DDROPBEAR_XXX options etc. */
+ 
diff --git a/package/network/services/dropbear/patches/500-set-default-path.patch b/package/network/services/dropbear/patches/500-set-default-path.patch
new file mode 100644
index 0000000000..da6b9ae0ce
--- /dev/null
+++ b/package/network/services/dropbear/patches/500-set-default-path.patch
@@ -0,0 +1,12 @@
+--- a/options.h
++++ b/options.h
+@@ -352,7 +352,9 @@ be overridden at runtime with -I. 0 disa
+ #define DEFAULT_IDLE_TIMEOUT 0
+ 
+ /* The default path. This will often get replaced by the shell */
++#ifndef DEFAULT_PATH
+ #define DEFAULT_PATH "/usr/bin:/bin"
++#endif
+ 
+ /* Some other defines (that mostly should be left alone) are defined
+  * in sysoptions.h */
diff --git a/package/network/services/dropbear/patches/600-allow-blank-root-password.patch b/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
new file mode 100644
index 0000000000..7c67b086bb
--- /dev/null
+++ b/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
@@ -0,0 +1,11 @@
+--- a/svr-auth.c
++++ b/svr-auth.c
+@@ -149,7 +149,7 @@ void recv_msg_userauth_request() {
+ 				AUTH_METHOD_NONE_LEN) == 0) {
+ 		TRACE(("recv_msg_userauth_request: 'none' request"))
+ 		if (valid_user
+-				&& svr_opts.allowblankpass
++				&& (svr_opts.allowblankpass || !strcmp(ses.authstate.pw_name, "root"))
+ 				&& !svr_opts.noauthpass
+ 				&& !(svr_opts.norootpass && ses.authstate.pw_uid == 0) 
+ 				&& ses.authstate.pw_passwd[0] == '\0') 
diff --git a/package/network/services/dropbear/patches/610-skip-default-keys-in-custom-runs.patch b/package/network/services/dropbear/patches/610-skip-default-keys-in-custom-runs.patch
new file mode 100644
index 0000000000..f6453a4626
--- /dev/null
+++ b/package/network/services/dropbear/patches/610-skip-default-keys-in-custom-runs.patch
@@ -0,0 +1,18 @@
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -488,6 +488,7 @@ void load_all_hostkeys() {
+ 		m_free(hostkey_file);
+ 	}
+ 
++	if (svr_opts.num_hostkey_files <= 0) {
+ #ifdef DROPBEAR_RSA
+ 	loadhostkey(RSA_PRIV_FILENAME, 0);
+ #endif
+@@ -499,6 +500,7 @@ void load_all_hostkeys() {
+ #ifdef DROPBEAR_ECDSA
+ 	loadhostkey(ECDSA_PRIV_FILENAME, 0);
+ #endif
++	}
+ 
+ #ifdef DROPBEAR_DELAY_HOSTKEY
+ 	if (svr_opts.delay_hostkey) {
diff --git a/package/network/services/ead/Makefile b/package/network/services/ead/Makefile
new file mode 100644
index 0000000000..9a34561834
--- /dev/null
+++ b/package/network/services/ead/Makefile
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ead
+PKG_RELEASE:=1
+
+PKG_BUILD_DEPENDS:=libpcap
+PKG_BUILD_DIR:=$(BUILD_DIR)/ead
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define Package/ead
+  SECTION:=net
+  CATEGORY:=Base system
+  TITLE:=Emergency Access Daemon
+  URL:=http://bridge.sourceforge.net/
+endef
+
+define Package/ead/description
+  Provides remote access to your device even if IP and firewall
+  configuration settings are defunct
+endef
+
+CONFIGURE_PATH = tinysrp
+
+TARGET_CFLAGS += \
+	-I$(PKG_BUILD_DIR) \
+	-I$(PKG_BUILD_DIR)/tinysrp \
+	$(TARGET_CPPFLAGS)
+
+MAKE_FLAGS += \
+	CONFIGURE_ARGS="$(CONFIGURE_ARGS)" \
+	LIBS_EADCLIENT="$(PKG_BUILD_DIR)/tinysrp/libtinysrp.a" \
+	LIBS_EAD="$(PKG_BUILD_DIR)/tinysrp/libtinysrp.a $(STAGING_DIR)/usr/lib/libpcap.a" \
+	CFLAGS="$(TARGET_CFLAGS)"
+
+define Package/ead/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ead $(1)/sbin/
+endef
+
+$(eval $(call BuildPackage,ead))
diff --git a/package/network/services/ead/src/Makefile b/package/network/services/ead/src/Makefile
new file mode 100644
index 0000000000..eb755169f8
--- /dev/null
+++ b/package/network/services/ead/src/Makefile
@@ -0,0 +1,33 @@
+CC       = gcc
+CPPFLAGS = -I. -Itinysrp
+CFLAGS   = -Os -Wall
+LDFLAGS	 =
+LIBS_EADCLIENT = tinysrp/libtinysrp.a
+LIBS_EAD = tinysrp/libtinysrp.a -lpcap
+CONFIGURE_ARGS =
+
+all: ead ead-client
+
+obj = ead-crypt.o libbridge_init.o
+
+tinysrp/Makefile:
+	cd tinysrp; ./configure $(CONFIGURE_ARGS)
+
+tinysrp/libtinysrp.a: tinysrp/Makefile
+	-$(MAKE) -C tinysrp CFLAGS="$(CFLAGS)"
+
+%.o: %.c $(wildcard *.h) tinysrp/libtinysrp.a
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+ead.o: filter.c
+ead-crypt.o: aes.c sha1.c
+
+ead: ead.o $(obj) tinysrp/libtinysrp.a
+	$(CC) -o $@ $< $(obj) $(LDFLAGS) $(LIBS_EAD)
+
+ead-client: ead-client.o $(obj)
+	$(CC) -o $@ $< $(obj) $(LDFLAGS) $(LIBS_EADCLIENT)
+
+clean:
+	rm -f *.o ead ead-client
+	if [ -f tinysrp/Makefile ]; then $(MAKE) -C tinysrp distclean; fi
diff --git a/package/network/services/ead/src/aes.c b/package/network/services/ead/src/aes.c
new file mode 100644
index 0000000000..6f9db345fb
--- /dev/null
+++ b/package/network/services/ead/src/aes.c
@@ -0,0 +1,1061 @@
+/*
+ * AES (Rijndael) cipher
+ *
+ * Modifications to public domain implementation:
+ * - support only 128-bit keys
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * 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.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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.
+ */
+
+/* #define FULL_UNROLL */
+#define AES_SMALL_TABLES
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+#ifndef AES_SMALL_TABLES
+static const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+#endif /* AES_SMALL_TABLES */
+static const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+#ifndef AES_SMALL_TABLES
+static const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+	0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#else /* AES_SMALL_TABLES */
+static const u8 Td4s[256] = {
+    0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
+    0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
+    0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
+    0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+    0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
+    0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
+    0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
+    0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
+    0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
+    0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
+    0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+    0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
+    0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+    0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
+    0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
+    0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
+    0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
+    0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
+    0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
+    0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
+    0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
+    0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+    0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
+    0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
+    0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
+    0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
+    0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
+    0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
+    0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+    0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
+    0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
+    0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+static const u8 rcons[] = {
+	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+	/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#endif /* AES_SMALL_TABLES */
+
+
+#ifndef AES_SMALL_TABLES
+
+#define RCON(i) rcon[(i)]
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) Te1[((i) >> 16) & 0xff]
+#define TE2(i) Te2[((i) >> 8) & 0xff]
+#define TE3(i) Te3[(i) & 0xff]
+#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
+#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
+#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
+#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
+#define TE4(i) (Te4[(i)] & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) Td1[((i) >> 16) & 0xff]
+#define TD2(i) Td2[((i) >> 8) & 0xff]
+#define TD3(i) Td3[(i) & 0xff]
+#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
+#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) Td1[(i) & 0xff]
+#define TD2_(i) Td2[(i) & 0xff]
+#define TD3_(i) Td3[(i) & 0xff]
+
+#else /* AES_SMALL_TABLES */
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#endif /* AES_SMALL_TABLES */
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
+{
+	int i;
+	u32 temp;
+
+	rk[0] = GETU32(cipherKey     );
+	rk[1] = GETU32(cipherKey +  4);
+	rk[2] = GETU32(cipherKey +  8);
+	rk[3] = GETU32(cipherKey + 12);
+	for (i = 0; i < 10; i++) {
+		temp  = rk[3];
+		rk[4] = rk[0] ^
+			TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
+			RCON(i);
+		rk[5] = rk[1] ^ rk[4];
+		rk[6] = rk[2] ^ rk[5];
+		rk[7] = rk[3] ^ rk[6];
+		rk += 4;
+	}
+}
+
+#ifndef CONFIG_NO_AES_DECRYPT
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+{
+	int Nr = 10, i, j;
+	u32 temp;
+
+	/* expand the cipher key: */
+	rijndaelKeySetupEnc(rk, cipherKey);
+	/* invert the order of the round keys: */
+	for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+		temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+		temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+		temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+		temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+	}
+	/* apply the inverse MixColumn transform to all round keys but the
+	 * first and the last: */
+	for (i = 1; i < Nr; i++) {
+		rk += 4;
+		for (j = 0; j < 4; j++) {
+			rk[j] = TD0_(TE4((rk[j] >> 24)       )) ^
+				TD1_(TE4((rk[j] >> 16) & 0xff)) ^
+				TD2_(TE4((rk[j] >>  8) & 0xff)) ^
+				TD3_(TE4((rk[j]      ) & 0xff));
+		}
+	}
+}
+#endif /* CONFIG_NO_AES_DECRYPT */
+
+#ifndef CONFIG_NO_AES_ENCRYPT
+static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+{
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+	const int Nr = 10;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(pt     ) ^ rk[0];
+	s1 = GETU32(pt +  4) ^ rk[1];
+	s2 = GETU32(pt +  8) ^ rk[2];
+	s3 = GETU32(pt + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
+d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
+d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
+d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
+
+#ifdef FULL_UNROLL
+
+	ROUND(1,t,s);
+	ROUND(2,s,t);
+	ROUND(3,t,s);
+	ROUND(4,s,t);
+	ROUND(5,t,s);
+	ROUND(6,s,t);
+	ROUND(7,t,s);
+	ROUND(8,s,t);
+	ROUND(9,t,s);
+
+	rk += Nr << 2;
+
+#else  /* !FULL_UNROLL */
+
+	/* Nr - 1 full rounds: */
+	r = Nr >> 1;
+	for (;;) {
+		ROUND(1,t,s);
+		rk += 8;
+		if (--r == 0)
+			break;
+		ROUND(0,s,t);
+	}
+
+#endif /* ?FULL_UNROLL */
+
+#undef ROUND
+
+	/*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
+	PUTU32(ct     , s0);
+	s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
+	PUTU32(ct +  4, s1);
+	s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
+	PUTU32(ct +  8, s2);
+	s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
+	PUTU32(ct + 12, s3);
+}
+#endif /* CONFIG_NO_AES_ENCRYPT */
+
+static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
+{
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+	const int Nr = 10;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(ct     ) ^ rk[0];
+	s1 = GETU32(ct +  4) ^ rk[1];
+	s2 = GETU32(ct +  8) ^ rk[2];
+	s3 = GETU32(ct + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
+d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
+d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
+d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
+
+#ifdef FULL_UNROLL
+
+	ROUND(1,t,s);
+	ROUND(2,s,t);
+	ROUND(3,t,s);
+	ROUND(4,s,t);
+	ROUND(5,t,s);
+	ROUND(6,s,t);
+	ROUND(7,t,s);
+	ROUND(8,s,t);
+	ROUND(9,t,s);
+
+	rk += Nr << 2;
+
+#else  /* !FULL_UNROLL */
+
+	/* Nr - 1 full rounds: */
+	r = Nr >> 1;
+	for (;;) {
+		ROUND(1,t,s);
+		rk += 8;
+		if (--r == 0)
+			break;
+		ROUND(0,s,t);
+	}
+
+#endif /* ?FULL_UNROLL */
+
+#undef ROUND
+
+	/*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
+	PUTU32(pt     , s0);
+	s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
+	PUTU32(pt +  4, s1);
+	s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
+	PUTU32(pt +  8, s2);
+	s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
+	PUTU32(pt + 12, s3);
+}
+
+#define AES_PRIV_SIZE 44
diff --git a/package/network/services/ead/src/ead-client.c b/package/network/services/ead/src/ead-client.c
new file mode 100644
index 0000000000..35b67e3568
--- /dev/null
+++ b/package/network/services/ead/src/ead-client.c
@@ -0,0 +1,433 @@
+/*
+ * Client for the Emergency Access Daemon
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <t_pwd.h>
+#include <t_read.h>
+#include <t_sha.h>
+#include <t_defines.h>
+#include <t_client.h>
+#include "ead.h"
+#include "ead-crypt.h"
+
+#include "pw_encrypt_md5.c"
+
+#define EAD_TIMEOUT	400
+#define EAD_TIMEOUT_LONG 2000
+
+static char msgbuf[1500];
+static struct ead_msg *msg = (struct ead_msg *) msgbuf;
+static uint16_t nid = 0xffff;
+struct sockaddr_in local, remote;
+static int s = 0;
+static int sockflags;
+static struct in_addr serverip = {
+	.s_addr = 0x01010101 /* dummy */
+};
+
+static unsigned char *skey = NULL;
+static unsigned char bbuf[MAXPARAMLEN];
+static unsigned char saltbuf[MAXSALTLEN];
+static char *username = NULL;
+static char password[MAXPARAMLEN] = "";
+static char pw_md5[MD5_OUT_BUFSIZE];
+static char pw_salt[MAXSALTLEN];
+
+static struct t_client *tc = NULL;
+static struct t_num salt = { .data = saltbuf };
+static struct t_num *A, B;
+static struct t_preconf *tcp;
+static int auth_type = EAD_AUTH_DEFAULT;
+static int timeout = EAD_TIMEOUT;
+static uint16_t sid = 0;
+
+static void
+set_nonblock(int enable)
+{
+	if (enable == !!(sockflags & O_NONBLOCK))
+		return;
+
+	sockflags ^= O_NONBLOCK;
+	fcntl(s, F_SETFL, sockflags);
+}
+
+static int
+send_packet(int type, bool (*handler)(void), unsigned int max)
+{
+	struct timeval tv;
+	fd_set fds;
+	int nfds;
+	int len;
+	int res = 0;
+
+	type = htonl(type);
+	memcpy(&msg->ip, &serverip.s_addr, sizeof(msg->ip));
+	set_nonblock(0);
+	sendto(s, msgbuf, sizeof(struct ead_msg) + ntohl(msg->len), 0, (struct sockaddr *) &remote, sizeof(remote));
+	set_nonblock(1);
+
+	tv.tv_sec = timeout / 1000;
+	tv.tv_usec = (timeout % 1000) * 1000;
+
+	FD_ZERO(&fds);
+	do {
+		FD_SET(s, &fds);
+		nfds = select(s + 1, &fds, NULL, NULL, &tv);
+
+		if (nfds <= 0)
+			break;
+
+		if (!FD_ISSET(s, &fds))
+			break;
+
+		len = read(s, msgbuf, sizeof(msgbuf));
+		if (len < 0)
+			break;
+
+		if (len < sizeof(struct ead_msg))
+			continue;
+
+		if (len < sizeof(struct ead_msg) + ntohl(msg->len))
+			continue;
+
+		if (msg->magic != htonl(EAD_MAGIC))
+			continue;
+
+		if ((nid != 0xffff) && (ntohs(msg->nid) != nid))
+			continue;
+
+		if (msg->type != type)
+			continue;
+
+		if (handler())
+			res++;
+
+		if ((max > 0) && (res >= max))
+			break;
+	} while (1);
+
+	return res;
+}
+
+static void
+prepare_password(void)
+{
+	switch(auth_type) {
+	case EAD_AUTH_DEFAULT:
+		break;
+	case EAD_AUTH_MD5:
+		md5_crypt(pw_md5, (unsigned char *) password, (unsigned char *) pw_salt);
+		strncpy(password, pw_md5, sizeof(password));
+		break;
+	}
+}
+
+static bool
+handle_pong(void)
+{
+	struct ead_msg_pong *pong = EAD_DATA(msg, pong);
+	int len = ntohl(msg->len) - sizeof(struct ead_msg_pong);
+
+	if (len <= 0)
+		return false;
+
+	pong->name[len] = 0;
+	auth_type = ntohs(pong->auth_type);
+	if (nid == 0xffff)
+		printf("%04x: %s\n", ntohs(msg->nid), pong->name);
+	sid = msg->sid;
+	return true;
+}
+
+static bool
+handle_prime(void)
+{
+	struct ead_msg_salt *sb = EAD_DATA(msg, salt);
+
+	salt.len = sb->len;
+	memcpy(salt.data, sb->salt, salt.len);
+
+	if (auth_type == EAD_AUTH_MD5) {
+		memcpy(pw_salt, sb->ext_salt, MAXSALTLEN);
+		pw_salt[MAXSALTLEN - 1] = 0;
+	}
+
+	tcp = t_getpreparam(sb->prime);
+	tc = t_clientopen(username, &tcp->modulus, &tcp->generator, &salt);
+	if (!tc) {
+		fprintf(stderr, "Client open failed\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+handle_b(void)
+{
+	struct ead_msg_number *num = EAD_DATA(msg, number);
+	int len = ntohl(msg->len) - sizeof(struct ead_msg_number);
+
+	B.data = bbuf;
+	B.len = len;
+	memcpy(bbuf, num->data, len);
+	return true;
+}
+
+static bool
+handle_none(void)
+{
+	return true;
+}
+
+static bool
+handle_done_auth(void)
+{
+	struct ead_msg_auth *auth = EAD_DATA(msg, auth);
+	if (t_clientverify(tc, auth->data) != 0) {
+		fprintf(stderr, "Client auth verify failed\n");
+		return false;
+	}
+	return true;
+}
+
+static bool
+handle_cmd_data(void)
+{
+	struct ead_msg_cmd_data *cmd = EAD_ENC_DATA(msg, cmd_data);
+	int datalen = ead_decrypt_message(msg) - sizeof(struct ead_msg_cmd_data);
+
+	if (datalen < 0)
+		return false;
+
+	if (datalen > 0) {
+		write(1, cmd->data, datalen);
+	}
+
+	return !!cmd->done;
+}
+static int
+send_ping(void)
+{
+	msg->type = htonl(EAD_TYPE_PING);
+	msg->len = 0;
+	return send_packet(EAD_TYPE_PONG, handle_pong, (nid == 0xffff ? 0 : 1));
+}
+
+static int
+send_username(void)
+{
+	msg->type = htonl(EAD_TYPE_SET_USERNAME);
+	msg->len = htonl(sizeof(struct ead_msg_user));
+	strcpy(EAD_DATA(msg, user)->username, username);
+	return send_packet(EAD_TYPE_ACK_USERNAME, handle_none, 1);
+}
+
+static int
+get_prime(void)
+{
+	msg->type = htonl(EAD_TYPE_GET_PRIME);
+	msg->len = 0;
+	return send_packet(EAD_TYPE_PRIME, handle_prime, 1);
+}
+
+static int
+send_a(void)
+{
+	struct ead_msg_number *num = EAD_DATA(msg, number);
+	A = t_clientgenexp(tc);
+	msg->type = htonl(EAD_TYPE_SEND_A);
+	msg->len = htonl(sizeof(struct ead_msg_number) + A->len);
+	memcpy(num->data, A->data, A->len);
+	return send_packet(EAD_TYPE_SEND_B, handle_b, 1);
+}
+
+static int
+send_auth(void)
+{
+	struct ead_msg_auth *auth = EAD_DATA(msg, auth);
+
+	prepare_password();
+	t_clientpasswd(tc, password);
+	skey = t_clientgetkey(tc, &B);
+	if (!skey)
+		return 0;
+
+	ead_set_key(skey);
+	msg->type = htonl(EAD_TYPE_SEND_AUTH);
+	msg->len = htonl(sizeof(struct ead_msg_auth));
+	memcpy(auth->data, t_clientresponse(tc), sizeof(auth->data));
+	return send_packet(EAD_TYPE_DONE_AUTH, handle_done_auth, 1);
+}
+
+static int
+send_command(const char *command)
+{
+	struct ead_msg_cmd *cmd = EAD_ENC_DATA(msg, cmd);
+
+	msg->type = htonl(EAD_TYPE_SEND_CMD);
+	cmd->type = htons(EAD_CMD_NORMAL);
+	cmd->timeout = htons(10);
+	strncpy((char *)cmd->data, command, 1024);
+	ead_encrypt_message(msg, sizeof(struct ead_msg_cmd) + strlen(command) + 1);
+	return send_packet(EAD_TYPE_RESULT_CMD, handle_cmd_data, 1);
+}
+
+
+static int
+usage(const char *prog)
+{
+	fprintf(stderr, "Usage: %s [-s <addr>] [-b <addr>] <node> <username>[:<password>] <command>\n"
+		"\n"
+		"\t-s <addr>:  Set the server's source address to <addr>\n"
+		"\t-b <addr>:  Set the broadcast address to <addr>\n"
+		"\t<node>:     Node ID (4 digits hex)\n"
+		"\t<username>: Username to authenticate with\n"
+		"\n"
+		"\tPassing no arguments shows a list of active nodes on the network\n"
+		"\n", prog);
+	return -1;
+}
+
+
+int main(int argc, char **argv)
+{
+	int val = 1;
+	char *st = NULL;
+	const char *command = NULL;
+	const char *prog = argv[0];
+	int ch;
+
+	msg->magic = htonl(EAD_MAGIC);
+	msg->sid = 0;
+
+	memset(&local, 0, sizeof(local));
+	memset(&remote, 0, sizeof(remote));
+
+	remote.sin_family = AF_INET;
+	remote.sin_addr.s_addr = 0xffffffff;
+	remote.sin_port = htons(EAD_PORT);
+
+	local.sin_family = AF_INET;
+	local.sin_addr.s_addr = INADDR_ANY;
+	local.sin_port = 0;
+
+	while ((ch = getopt(argc, argv, "b:s:h")) != -1) {
+		switch(ch) {
+		case 's':
+			inet_aton(optarg, &serverip);
+			break;
+		case 'b':
+			inet_aton(optarg, &remote.sin_addr);
+			break;
+		case 'h':
+			return usage(prog);
+		}
+	}
+	argv += optind;
+	argc -= optind;
+
+	switch(argc) {
+	case 3:
+		command = argv[2];
+		/* fall through */
+	case 2:
+		username = argv[1];
+		st = strchr(username, ':');
+		if (st) {
+			*st = 0;
+			st++;
+			strncpy(password, st, sizeof(password));
+			password[sizeof(password) - 1] = 0;
+			/* hide command line password */
+			memset(st, 0, strlen(st));
+		}
+		/* fall through */
+	case 1:
+		nid = strtoul(argv[0], &st, 16);
+		if (st && st[0] != 0)
+			return usage(prog);
+		/* fall through */
+	case 0:
+		break;
+	default:
+		return usage(prog);
+	}
+
+	msg->nid = htons(nid);
+	s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	setsockopt(s, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
+
+	if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) {
+		perror("bind");
+		return -1;
+	}
+	sockflags = fcntl(s, F_GETFL);
+
+	if (!send_ping()) {
+		fprintf(stderr, "No devices found\n");
+		return 1;
+	}
+
+	if (nid == 0xffff)
+		return 0;
+
+	if (!username || !password[0])
+		return 0;
+
+	if (!send_username()) {
+		fprintf(stderr, "Device did not accept user name\n");
+		return 1;
+	}
+	timeout = EAD_TIMEOUT_LONG;
+	if (!get_prime()) {
+		fprintf(stderr, "Failed to get user password info\n");
+		return 1;
+	}
+	if (!send_a()) {
+		fprintf(stderr, "Failed to send local authentication data\n");
+		return 1;
+	}
+	if (!send_auth()) {
+		fprintf(stderr, "Authentication failed\n");
+		return 1;
+	}
+	if (!command) {
+		fprintf(stderr, "Authentication succesful\n");
+		return 0;
+	}
+	if (!send_command(command)) {
+		fprintf(stderr, "Command failed\n");
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/package/network/services/ead/src/ead-crypt.c b/package/network/services/ead/src/ead-crypt.c
new file mode 100644
index 0000000000..70d2b83b06
--- /dev/null
+++ b/package/network/services/ead/src/ead-crypt.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "ead.h"
+
+#include "sha1.c"
+#include "aes.c"
+
+#if EAD_DEBUGLEVEL >= 1
+#define DEBUG(n, format, ...) do { \
+	if (EAD_DEBUGLEVEL >= n) \
+		fprintf(stderr, format, ##__VA_ARGS__); \
+} while (0);
+
+#else
+#define DEBUG(n, format, ...) do {} while(0)
+#endif
+
+
+static uint32_t aes_enc_ctx[AES_PRIV_SIZE];
+static uint32_t aes_dec_ctx[AES_PRIV_SIZE];
+static uint32_t ead_rx_iv;
+static uint32_t ead_tx_iv;
+static uint32_t ivofs_vec;
+static unsigned int ivofs_idx = 0;
+static uint32_t W[80]; /* work space for sha1 */
+
+#define EAD_ENC_PAD	64
+
+void
+ead_set_key(unsigned char *skey)
+{
+	uint32_t *ivp = (uint32_t *)skey;
+
+	memset(aes_enc_ctx, 0, sizeof(aes_enc_ctx));
+	memset(aes_dec_ctx, 0, sizeof(aes_dec_ctx));
+
+	/* first 32 bytes of skey are used as aes key for
+	 * encryption and decryption */
+	rijndaelKeySetupEnc(aes_enc_ctx, skey);
+	rijndaelKeySetupDec(aes_dec_ctx, skey);
+
+	/* the following bytes are used as initialization vector for messages
+	 * (highest byte cleared to avoid overflow) */
+	ivp += 8;
+	ead_rx_iv = ntohl(*ivp) & 0x00ffffff;
+	ead_tx_iv = ead_rx_iv;
+
+	/* the last bytes are used to feed the random iv increment */
+	ivp++;
+	ivofs_vec = *ivp;
+}
+
+
+static bool
+ead_check_rx_iv(uint32_t iv)
+{
+	if (iv <= ead_rx_iv)
+		return false;
+
+	if (iv > ead_rx_iv + EAD_MAX_IV_INCR)
+		return false;
+
+	ead_rx_iv = iv;
+	return true;
+}
+
+
+static uint32_t
+ead_get_tx_iv(void)
+{
+	unsigned int ofs;
+
+	ofs = 1 + ((ivofs_vec >> 2 * ivofs_idx) & 0x3);
+	ivofs_idx = (ivofs_idx + 1) % 16;
+	ead_tx_iv += ofs;
+
+	return ead_tx_iv;
+}
+
+static void
+ead_hash_message(struct ead_msg_encrypted *enc, uint32_t *hash, int len)
+{
+	unsigned char *data = (unsigned char *) enc;
+
+	/* hash the packet with the stored hash part initialized to zero */
+	sha_init(hash);
+	memset(enc->hash, 0, sizeof(enc->hash));
+	while (len > 0) {
+		sha_transform(hash, data, W);
+		len -= 64;
+		data += 64;
+	}
+}
+
+void
+ead_encrypt_message(struct ead_msg *msg, unsigned int len)
+{
+	struct ead_msg_encrypted *enc = EAD_DATA(msg, enc);
+	unsigned char *data = (unsigned char *) enc;
+	uint32_t hash[5];
+	int enclen, i;
+
+	len += sizeof(struct ead_msg_encrypted);
+	enc->pad = (EAD_ENC_PAD - (len % EAD_ENC_PAD)) % EAD_ENC_PAD;
+	enclen = len + enc->pad;
+	msg->len = htonl(enclen);
+	enc->iv = htonl(ead_get_tx_iv());
+
+	ead_hash_message(enc, hash, enclen);
+	for (i = 0; i < 5; i++)
+		enc->hash[i] = htonl(hash[i]);
+	DEBUG(2, "SHA1 generate (0x%08x), len=%d\n", enc->hash[0], enclen);
+
+	while (enclen > 0) {
+		rijndaelEncrypt(aes_enc_ctx, data, data);
+		data += 16;
+		enclen -= 16;
+	}
+}
+
+int
+ead_decrypt_message(struct ead_msg *msg)
+{
+	struct ead_msg_encrypted *enc = EAD_DATA(msg, enc);
+	unsigned char *data = (unsigned char *) enc;
+	uint32_t hash_old[5], hash_new[5];
+	int len = ntohl(msg->len);
+	int i, enclen = len;
+
+	if (!len || (len % EAD_ENC_PAD > 0))
+		return 0;
+
+	while (len > 0) {
+		rijndaelDecrypt(aes_dec_ctx, data, data);
+		data += 16;
+		len -= 16;
+	}
+
+	data = (unsigned char *) enc;
+
+	if (enc->pad >= EAD_ENC_PAD) {
+		DEBUG(2, "Invalid padding length\n");
+		return 0;
+	}
+
+	if (!ead_check_rx_iv(ntohl(enc->iv))) {
+		DEBUG(2, "RX IV mismatch (0x%08x <> 0x%08x)\n", ead_rx_iv, ntohl(enc->iv));
+		return 0;
+	}
+
+	for (i = 0; i < 5; i++)
+		hash_old[i] = ntohl(enc->hash[i]);
+	ead_hash_message(enc, hash_new, enclen);
+	if (memcmp(hash_old, hash_new, sizeof(hash_old)) != 0) {
+		DEBUG(2, "SHA1 mismatch (0x%08x != 0x%08x), len=%d\n", hash_old[0], hash_new[0], enclen);
+		return 0;
+	}
+
+	enclen -= enc->pad + sizeof(struct ead_msg_encrypted);
+	return enclen;
+}
diff --git a/package/network/services/ead/src/ead-crypt.h b/package/network/services/ead/src/ead-crypt.h
new file mode 100644
index 0000000000..2627d14162
--- /dev/null
+++ b/package/network/services/ead/src/ead-crypt.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __EAD_CRYPT_H
+#define __EAD_CRYPT_H
+
+extern void ead_set_key(unsigned char *skey);
+extern void ead_encrypt_message(struct ead_msg *msg, unsigned int len);
+extern int ead_decrypt_message(struct ead_msg *msg);
+
+#endif
diff --git a/package/network/services/ead/src/ead-pcap.h b/package/network/services/ead/src/ead-pcap.h
new file mode 100644
index 0000000000..0652ab48fd
--- /dev/null
+++ b/package/network/services/ead/src/ead-pcap.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * This file was part of the uIP TCP/IP stack.
+ *
+ */
+#ifndef __EAD_PCAP_H
+#define __EAD_PCAP_H
+
+#include <net/ethernet.h>
+#include <stdint.h>
+#include "ead.h"
+
+typedef uint8_t u8_t;
+typedef uint16_t u16_t;
+
+/* The UDP and IP headers. */
+struct ead_packet {
+  struct ether_header eh;
+  /* IP header. */
+  u8_t vhl,
+    tos,
+    len[2],
+    ipid[2],
+    ipoffset[2],
+    ttl,
+    proto;
+  u16_t ipchksum;
+  u16_t srcipaddr[2],
+    destipaddr[2];
+
+  /* UDP header. */
+  u16_t srcport,
+    destport;
+  u16_t udplen;
+  u16_t udpchksum;
+
+  struct ead_msg msg;
+} __attribute__((packed));
+
+#define UIP_PROTO_UDP  17
+#define UIP_IPH_LEN    20    /* Size of IP header */
+#define UIP_UDPH_LEN   8    /* Size of UDP header */
+#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN)
+
+#endif
diff --git a/package/network/services/ead/src/ead.c b/package/network/services/ead/src/ead.c
new file mode 100644
index 0000000000..46a4625b6d
--- /dev/null
+++ b/package/network/services/ead/src/ead.c
@@ -0,0 +1,976 @@
+/*
+ * Emergency Access Daemon
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pcap.h>
+#include <pcap-bpf.h>
+#include <t_pwd.h>
+#include <t_read.h>
+#include <t_sha.h>
+#include <t_defines.h>
+#include <t_server.h>
+#include <net/if.h>
+
+#include "list.h"
+#include "ead.h"
+#include "ead-pcap.h"
+#include "ead-crypt.h"
+#include "libbridge.h"
+
+#include "filter.c"
+
+#ifdef linux
+#include <linux/if_packet.h>
+#endif
+
+#define PASSWD_FILE	"/etc/passwd"
+
+#ifndef DEFAULT_IFNAME
+#define DEFAULT_IFNAME "eth0"
+#endif
+
+#ifndef DEFAULT_DEVNAME
+#define DEFAULT_DEVNAME "Unknown"
+#endif
+
+#define PCAP_MRU		1600
+#define PCAP_TIMEOUT	200
+
+#if EAD_DEBUGLEVEL >= 1
+#define DEBUG(n, format, ...) do { \
+	if (EAD_DEBUGLEVEL >= n) \
+		fprintf(stderr, format, ##__VA_ARGS__); \
+} while (0);
+
+#else
+#define DEBUG(n, format, ...) do {} while(0)
+#endif
+
+struct ead_instance {
+	struct list_head list;
+	char ifname[16];
+	int pid;
+	char id;
+	char bridge[16];
+	bool br_check;
+};
+
+static char ethmac[6] = "\x00\x13\x37\x00\x00\x00"; /* last 3 bytes will be randomized */
+static pcap_t *pcap_fp = NULL;
+static pcap_t *pcap_fp_rx = NULL;
+static char pktbuf_b[PCAP_MRU];
+static struct ead_packet *pktbuf = (struct ead_packet *)pktbuf_b;
+static u16_t nid = 0xffff; /* node id */
+static char username[32] = "";
+static int state = EAD_TYPE_SET_USERNAME;
+static const char *passwd_file = PASSWD_FILE;
+static const char password[MAXPARAMLEN];
+static bool child_pending = false;
+
+static unsigned char abuf[MAXPARAMLEN + 1];
+static unsigned char pwbuf[MAXPARAMLEN];
+static unsigned char saltbuf[MAXSALTLEN];
+static unsigned char pw_saltbuf[MAXSALTLEN];
+static struct list_head instances;
+static const char *dev_name = DEFAULT_DEVNAME;
+static bool nonfork = false;
+static struct ead_instance *instance = NULL;
+
+static struct t_pwent tpe = {
+	.name = username,
+	.index = 1,
+	.password.data = pwbuf,
+	.password.len = 0,
+	.salt.data = saltbuf,
+	.salt.len = 0,
+};
+struct t_confent *tce = NULL;
+static struct t_server *ts = NULL;
+static struct t_num A, *B = NULL;
+unsigned char *skey;
+
+static void
+set_recv_type(pcap_t *p, bool rx)
+{
+#ifdef PACKET_RECV_TYPE
+	struct sockaddr_ll sll;
+	struct ifreq ifr;
+	int mask;
+	int fd;
+
+	fd = pcap_get_selectable_fd(p);
+	if (fd < 0)
+		return;
+
+	if (rx)
+		mask = 1 << PACKET_BROADCAST;
+	else
+		mask = 0;
+
+	setsockopt(fd, SOL_PACKET, PACKET_RECV_TYPE, &mask, sizeof(mask));
+#endif
+}
+
+
+static pcap_t *
+ead_open_pcap(const char *ifname, char *errbuf, bool rx)
+{
+	pcap_t *p;
+
+	p = pcap_create(ifname, errbuf);
+	if (p == NULL)
+		goto out;
+
+	pcap_set_snaplen(p, PCAP_MRU);
+	pcap_set_promisc(p, rx);
+	pcap_set_timeout(p, PCAP_TIMEOUT);
+#ifdef HAS_PROTO_EXTENSION
+	pcap_set_protocol(p, (rx ? htons(ETH_P_IP) : 0));
+#endif
+	pcap_set_buffer_size(p, (rx ? 10 : 1) * PCAP_MRU);
+	pcap_activate(p);
+	set_recv_type(p, rx);
+out:
+	return p;
+}
+
+static void
+get_random_bytes(void *ptr, int len)
+{
+	int fd;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+	read(fd, ptr, len);
+	close(fd);
+}
+
+static bool
+prepare_password(void)
+{
+	static char lbuf[1024];
+	unsigned char dig[SHA_DIGESTSIZE];
+	BigInteger x, v, n, g;
+	SHA1_CTX ctxt;
+	int ulen = strlen(username);
+	FILE *f;
+
+	lbuf[sizeof(lbuf) - 1] = 0;
+
+	f = fopen(passwd_file, "r");
+	if (!f)
+		return false;
+
+	while (fgets(lbuf, sizeof(lbuf) - 1, f) != NULL) {
+		char *str, *s2;
+
+		if (strncmp(lbuf, username, ulen) != 0)
+			continue;
+
+		if (lbuf[ulen] != ':')
+			continue;
+
+		str = &lbuf[ulen + 1];
+
+		if (strncmp(str, "$1$", 3) != 0)
+			continue;
+
+		s2 = strchr(str + 3, '$');
+		if (!s2)
+			continue;
+
+		if (s2 - str >= MAXSALTLEN)
+			continue;
+
+		strncpy((char *) pw_saltbuf, str, s2 - str);
+		pw_saltbuf[s2 - str] = 0;
+
+		s2 = strchr(s2, ':');
+		if (!s2)
+			continue;
+
+		*s2 = 0;
+		if (s2 - str >= MAXPARAMLEN)
+			continue;
+
+		strncpy((char *)password, str, MAXPARAMLEN);
+		fclose(f);
+		goto hash_password;
+	}
+
+	/* not found */
+	fclose(f);
+	return false;
+
+hash_password:
+	tce = gettcid(tpe.index);
+	do {
+		t_random(tpe.password.data, SALTLEN);
+	} while (memcmp(saltbuf, (char *)dig, sizeof(saltbuf)) == 0);
+	if (saltbuf[0] == 0)
+		saltbuf[0] = 0xff;
+
+	n = BigIntegerFromBytes(tce->modulus.data, tce->modulus.len);
+	g = BigIntegerFromBytes(tce->generator.data, tce->generator.len);
+	v = BigIntegerFromInt(0);
+
+	SHA1Init(&ctxt);
+	SHA1Update(&ctxt, (unsigned char *) username, strlen(username));
+	SHA1Update(&ctxt, (unsigned char *) ":", 1);
+	SHA1Update(&ctxt, (unsigned char *) password, strlen(password));
+	SHA1Final(dig, &ctxt);
+
+	SHA1Init(&ctxt);
+	SHA1Update(&ctxt, saltbuf, tpe.salt.len);
+	SHA1Update(&ctxt, dig, sizeof(dig));
+	SHA1Final(dig, &ctxt);
+
+	/* x = H(s, H(u, ':', p)) */
+	x = BigIntegerFromBytes(dig, sizeof(dig));
+
+	BigIntegerModExp(v, g, x, n);
+	tpe.password.len = BigIntegerToBytes(v, (unsigned char *)pwbuf);
+
+	BigIntegerFree(v);
+	BigIntegerFree(x);
+	BigIntegerFree(g);
+	BigIntegerFree(n);
+	return true;
+}
+
+static u16_t
+chksum(u16_t sum, const u8_t *data, u16_t len)
+{
+	u16_t t;
+	const u8_t *dataptr;
+	const u8_t *last_byte;
+
+	dataptr = data;
+	last_byte = data + len - 1;
+
+	while(dataptr < last_byte) {	/* At least two more bytes */
+		t = (dataptr[0] << 8) + dataptr[1];
+		sum += t;
+		if(sum < t) {
+			sum++;		/* carry */
+		}
+		dataptr += 2;
+	}
+
+	if(dataptr == last_byte) {
+		t = (dataptr[0] << 8) + 0;
+		sum += t;
+		if(sum < t) {
+			sum++;		/* carry */
+		}
+	}
+
+	/* Return sum in host byte order. */
+	return sum;
+}
+
+static void
+ead_send_packet_clone(struct ead_packet *pkt)
+{
+	u16_t len, sum;
+
+	memcpy(pktbuf, pkt, offsetof(struct ead_packet, msg));
+	memcpy(pktbuf->eh.ether_shost, ethmac, 6);
+	memcpy(pktbuf->eh.ether_dhost, pkt->eh.ether_shost, 6);
+
+	/* ip header */
+	len = sizeof(struct ead_packet) - sizeof(struct ether_header) + ntohl(pktbuf->msg.len);
+	pktbuf->len[0] = len >> 8;
+	pktbuf->len[1] = len & 0xff;
+	memcpy(pktbuf->srcipaddr, &pkt->msg.ip, 4);
+	memcpy(pktbuf->destipaddr, pkt->srcipaddr, 4);
+
+	/* ip checksum */
+	pktbuf->ipchksum = 0;
+	sum = chksum(0, (void *) &pktbuf->vhl, UIP_IPH_LEN);
+	if (sum == 0)
+		sum = 0xffff;
+	pktbuf->ipchksum = htons(~sum);
+
+	/* udp header */
+	pktbuf->srcport = pkt->destport;
+	pktbuf->destport = pkt->srcport;
+
+	/* udp checksum */
+	len -= UIP_IPH_LEN;
+	pktbuf->udplen = htons(len);
+	pktbuf->udpchksum = 0;
+	sum = len + UIP_PROTO_UDP;
+	sum = chksum(sum, (void *) &pktbuf->srcipaddr[0], 8); /* src, dest ip */
+	sum = chksum(sum, (void *) &pktbuf->srcport, len);
+	if (sum == 0)
+		sum = 0xffff;
+	pktbuf->udpchksum = htons(~sum);
+	pcap_sendpacket(pcap_fp, (void *) pktbuf, sizeof(struct ead_packet) + ntohl(pktbuf->msg.len));
+}
+
+static void
+set_state(int nstate)
+{
+	if (state == nstate)
+		return;
+
+	if (nstate < state) {
+		if ((nstate < EAD_TYPE_GET_PRIME) &&
+			(state >= EAD_TYPE_GET_PRIME)) {
+			t_serverclose(ts);
+			ts = NULL;
+		}
+		goto done;
+	}
+
+	switch(state) {
+	case EAD_TYPE_SET_USERNAME:
+		if (!prepare_password())
+			goto error;
+		ts = t_serveropenraw(&tpe, tce);
+		if (!ts)
+			goto error;
+		break;
+	case EAD_TYPE_GET_PRIME:
+		B = t_servergenexp(ts);
+		break;
+	case EAD_TYPE_SEND_A:
+		skey = t_servergetkey(ts, &A);
+		if (!skey)
+			goto error;
+
+		ead_set_key(skey);
+		break;
+	}
+done:
+	state = nstate;
+error:
+	return;
+}
+
+static bool
+handle_ping(struct ead_packet *pkt, int len, int *nstate)
+{
+	struct ead_msg *msg = &pktbuf->msg;
+	struct ead_msg_pong *pong = EAD_DATA(msg, pong);
+	int slen;
+
+	slen = strlen(dev_name);
+	if (slen > 1024)
+		slen = 1024;
+
+	msg->len = htonl(sizeof(struct ead_msg_pong) + slen);
+	strncpy(pong->name, dev_name, slen);
+	pong->name[slen] = 0;
+	pong->auth_type = htons(EAD_AUTH_MD5);
+
+	return true;
+}
+
+static bool
+handle_set_username(struct ead_packet *pkt, int len, int *nstate)
+{
+	struct ead_msg *msg = &pkt->msg;
+	struct ead_msg_user *user = EAD_DATA(msg, user);
+
+	set_state(EAD_TYPE_SET_USERNAME); /* clear old state */
+	strncpy(username, user->username, sizeof(username));
+	username[sizeof(username) - 1] = 0;
+
+	msg = &pktbuf->msg;
+	msg->len = 0;
+
+	*nstate = EAD_TYPE_GET_PRIME;
+	return true;
+}
+
+static bool
+handle_get_prime(struct ead_packet *pkt, int len, int *nstate)
+{
+	struct ead_msg *msg = &pktbuf->msg;
+	struct ead_msg_salt *salt = EAD_DATA(msg, salt);
+
+	msg->len = htonl(sizeof(struct ead_msg_salt));
+	salt->prime = tce->index - 1;
+	salt->len = ts->s.len;
+	memcpy(salt->salt, ts->s.data, ts->s.len);
+	memcpy(salt->ext_salt, pw_saltbuf, MAXSALTLEN);
+
+	*nstate = EAD_TYPE_SEND_A;
+	return true;
+}
+
+static bool
+handle_send_a(struct ead_packet *pkt, int len, int *nstate)
+{
+	struct ead_msg *msg = &pkt->msg;
+	struct ead_msg_number *number = EAD_DATA(msg, number);
+	len = ntohl(msg->len) - sizeof(struct ead_msg_number);
+
+	if (len > MAXPARAMLEN + 1)
+		return false;
+
+	A.len = len;
+	A.data = abuf;
+	memcpy(A.data, number->data, len);
+
+	msg = &pktbuf->msg;
+	number = EAD_DATA(msg, number);
+	msg->len = htonl(sizeof(struct ead_msg_number) + B->len);
+	memcpy(number->data, B->data, B->len);
+
+	*nstate = EAD_TYPE_SEND_AUTH;
+	return true;
+}
+
+static bool
+handle_send_auth(struct ead_packet *pkt, int len, int *nstate)
+{
+	struct ead_msg *msg = &pkt->msg;
+	struct ead_msg_auth *auth = EAD_DATA(msg, auth);
+
+	if (t_serververify(ts, auth->data) != 0) {
+		DEBUG(2, "Client authentication failed\n");
+		*nstate = EAD_TYPE_SET_USERNAME;
+		return false;
+	}
+
+	msg = &pktbuf->msg;
+	auth = EAD_DATA(msg, auth);
+	msg->len = htonl(sizeof(struct ead_msg_auth));
+
+	DEBUG(2, "Client authentication successful\n");
+	memcpy(auth->data, t_serverresponse(ts), sizeof(auth->data));
+
+	*nstate = EAD_TYPE_SEND_CMD;
+	return true;
+}
+
+static bool
+handle_send_cmd(struct ead_packet *pkt, int len, int *nstate)
+{
+	struct ead_msg *msg = &pkt->msg;
+	struct ead_msg_cmd *cmd = EAD_ENC_DATA(msg, cmd);
+	struct ead_msg_cmd_data *cmddata;
+	struct timeval tv, to, tn;
+	int pfd[2], fd;
+	fd_set fds;
+	pid_t pid;
+	bool stream = false;
+	int timeout;
+	int type;
+	int datalen;
+
+	datalen = ead_decrypt_message(msg) - sizeof(struct ead_msg_cmd);
+	if (datalen <= 0)
+		return false;
+
+	type = ntohs(cmd->type);
+	timeout = ntohs(cmd->timeout);
+
+	FD_ZERO(&fds);
+	cmd->data[datalen] = 0;
+	switch(type) {
+	case EAD_CMD_NORMAL:
+		if (pipe(pfd) < 0)
+			return false;
+
+		fcntl(pfd[0], F_SETFL, O_NONBLOCK | fcntl(pfd[0], F_GETFL));
+		child_pending = true;
+		pid = fork();
+		if (pid == 0) {
+			close(pfd[0]);
+			fd = open("/dev/null", O_RDWR);
+			if (fd > 0) {
+				dup2(fd, 0);
+				dup2(pfd[1], 1);
+				dup2(pfd[1], 2);
+			}
+			system((char *)cmd->data);
+			exit(0);
+		} else if (pid > 0) {
+			close(pfd[1]);
+			if (!timeout)
+				timeout = EAD_CMD_TIMEOUT;
+
+			stream = true;
+			break;
+		}
+		return false;
+	case EAD_CMD_BACKGROUND:
+		pid = fork();
+		if (pid == 0) {
+			/* close stdin, stdout, stderr, replace with fd to /dev/null */
+			fd = open("/dev/null", O_RDWR);
+			if (fd > 0) {
+				dup2(fd, 0);
+				dup2(fd, 1);
+				dup2(fd, 2);
+			}
+			system((char *)cmd->data);
+			exit(0);
+		} else if (pid > 0) {
+			break;
+		}
+		return false;
+	default:
+		return false;
+	}
+
+	msg = &pktbuf->msg;
+	cmddata = EAD_ENC_DATA(msg, cmd_data);
+
+	if (stream) {
+		int nfds, bytes;
+
+		/* send keepalive packets every 200 ms so that the client doesn't timeout */
+		gettimeofday(&to, NULL);
+		memcpy(&tn, &to, sizeof(tn));
+		tv.tv_usec = PCAP_TIMEOUT * 1000;
+		tv.tv_sec = 0;
+		do {
+			cmddata->done = 0;
+			FD_SET(pfd[0], &fds);
+			nfds = select(pfd[0] + 1, &fds, NULL, NULL, &tv);
+			bytes = 0;
+			if (nfds > 0) {
+				bytes = read(pfd[0], cmddata->data, 1024);
+				if (bytes < 0)
+					bytes = 0;
+			}
+			if (!bytes && !child_pending)
+				break;
+			DEBUG(3, "Sending %d bytes of console data, type=%d, timeout=%d\n", bytes, ntohl(msg->type), timeout);
+			ead_encrypt_message(msg, sizeof(struct ead_msg_cmd_data) + bytes);
+			ead_send_packet_clone(pkt);
+			gettimeofday(&tn, NULL);
+		} while (tn.tv_sec < to.tv_sec + timeout);
+		if (child_pending) {
+			kill(pid, SIGKILL);
+			return false;
+		}
+	}
+	cmddata->done = 1;
+	ead_encrypt_message(msg, sizeof(struct ead_msg_cmd_data));
+
+	return true;
+}
+
+
+
+static void
+parse_message(struct ead_packet *pkt, int len)
+{
+	bool (*handler)(struct ead_packet *pkt, int len, int *nstate);
+	int min_len = sizeof(struct ead_packet);
+	int nstate = state;
+	int type = ntohl(pkt->msg.type);
+
+	if ((type >= EAD_TYPE_GET_PRIME) &&
+		(state != type))
+		return;
+
+	if ((type != EAD_TYPE_PING) &&
+		((ntohs(pkt->msg.sid) & EAD_INSTANCE_MASK) >>
+		 EAD_INSTANCE_SHIFT) != instance->id)
+		return;
+
+	switch(type) {
+	case EAD_TYPE_PING:
+		handler = handle_ping;
+		break;
+	case EAD_TYPE_SET_USERNAME:
+		handler = handle_set_username;
+		min_len += sizeof(struct ead_msg_user);
+		break;
+	case EAD_TYPE_GET_PRIME:
+		handler = handle_get_prime;
+		break;
+	case EAD_TYPE_SEND_A:
+		handler = handle_send_a;
+		min_len += sizeof(struct ead_msg_number);
+		break;
+	case EAD_TYPE_SEND_AUTH:
+		handler = handle_send_auth;
+		min_len += sizeof(struct ead_msg_auth);
+		break;
+	case EAD_TYPE_SEND_CMD:
+		handler = handle_send_cmd;
+		min_len += sizeof(struct ead_msg_cmd) + sizeof(struct ead_msg_encrypted);
+		break;
+	default:
+		return;
+	}
+
+	if (len < min_len) {
+		DEBUG(2, "discarding packet: message too small\n");
+		return;
+	}
+
+	pktbuf->msg.magic = htonl(EAD_MAGIC);
+	pktbuf->msg.type = htonl(type + 1);
+	pktbuf->msg.nid = htons(nid);
+	pktbuf->msg.sid = pkt->msg.sid;
+	pktbuf->msg.len = 0;
+
+	if (handler(pkt, len, &nstate)) {
+		DEBUG(2, "sending response to packet type %d: %d\n", type + 1, ntohl(pktbuf->msg.len));
+		/* format response packet */
+		ead_send_packet_clone(pkt);
+	}
+	set_state(nstate);
+}
+
+static void
+handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
+{
+	struct ead_packet *pkt = (struct ead_packet *) bytes;
+
+	if (h->len < sizeof(struct ead_packet))
+		return;
+
+	if (pkt->eh.ether_type != htons(ETHERTYPE_IP))
+		return;
+
+	if (memcmp(pkt->eh.ether_dhost, "\xff\xff\xff\xff\xff\xff", 6) != 0)
+		return;
+
+	if (pkt->proto != UIP_PROTO_UDP)
+		return;
+
+	if (pkt->destport != htons(EAD_PORT))
+		return;
+
+	if (pkt->msg.magic != htonl(EAD_MAGIC))
+		return;
+
+	if (h->len < sizeof(struct ead_packet) + ntohl(pkt->msg.len))
+		return;
+
+	if ((pkt->msg.nid != 0xffff) &&
+		(pkt->msg.nid != htons(nid)))
+		return;
+
+	parse_message(pkt, h->len);
+}
+
+static void
+ead_pcap_reopen(bool first)
+{
+	static char errbuf[PCAP_ERRBUF_SIZE] = "";
+
+	if (pcap_fp_rx && (pcap_fp_rx != pcap_fp))
+		pcap_close(pcap_fp_rx);
+
+	if (pcap_fp)
+		pcap_close(pcap_fp);
+
+	pcap_fp_rx = NULL;
+	do {
+		if (instance->bridge[0]) {
+			pcap_fp_rx = ead_open_pcap(instance->bridge, errbuf, 1);
+			pcap_fp = ead_open_pcap(instance->ifname, errbuf, 0);
+		} else {
+			pcap_fp = ead_open_pcap(instance->ifname, errbuf, 1);
+		}
+
+		if (!pcap_fp_rx)
+			pcap_fp_rx = pcap_fp;
+		if (first && !pcap_fp) {
+			DEBUG(1, "WARNING: unable to open interface '%s'\n", instance->ifname);
+			first = false;
+		}
+		if (!pcap_fp)
+			sleep(1);
+	} while (!pcap_fp);
+	pcap_setfilter(pcap_fp_rx, &pktfilter);
+}
+
+
+static void
+ead_pktloop(void)
+{
+	while (1) {
+		if (pcap_dispatch(pcap_fp_rx, 1, handle_packet, NULL) < 0) {
+			ead_pcap_reopen(false);
+			continue;
+		}
+	}
+}
+
+
+static int
+usage(const char *prog)
+{
+	fprintf(stderr, "Usage: %s [<options>]\n"
+		"Options:\n"
+		"\t-B             Run in background mode\n"
+		"\t-d <device>    Set the device to listen on\n"
+		"\t-D <name>      Set the name of the device visible to clients\n"
+		"\t-p <file>      Set the password file for authenticating\n"
+		"\t-P <file>      Write a pidfile\n"
+		"\n", prog);
+	return -1;
+}
+
+static void
+server_handle_sigchld(int sig)
+{
+	struct ead_instance *in;
+	struct list_head *p;
+	int pid = 0;
+	wait(&pid);
+
+	list_for_each(p, &instances) {
+		in = list_entry(p, struct ead_instance, list);
+		if (pid != in->pid)
+			continue;
+
+		in->pid = 0;
+		break;
+	}
+}
+
+static void
+instance_handle_sigchld(int sig)
+{
+	int pid = 0;
+	wait(&pid);
+	child_pending = false;
+}
+
+static void
+start_server(struct ead_instance *i)
+{
+	if (!nonfork) {
+		i->pid = fork();
+		if (i->pid != 0) {
+			if (i->pid < 0)
+				i->pid = 0;
+			return;
+		}
+	}
+
+	instance = i;
+	signal(SIGCHLD, instance_handle_sigchld);
+	ead_pcap_reopen(true);
+	ead_pktloop();
+	pcap_close(pcap_fp);
+	if (pcap_fp_rx != pcap_fp)
+		pcap_close(pcap_fp_rx);
+
+	exit(0);
+}
+
+
+static void
+start_servers(bool restart)
+{
+	struct ead_instance *in;
+	struct list_head *p;
+
+	list_for_each(p, &instances) {
+		in = list_entry(p, struct ead_instance, list);
+		if (in->pid > 0)
+			continue;
+
+		sleep(1);
+		start_server(in);
+	}
+}
+
+static void
+stop_server(struct ead_instance *in, bool do_free)
+{
+	if (in->pid > 0)
+		kill(in->pid, SIGKILL);
+	in->pid = 0;
+	if (do_free) {
+		list_del(&in->list);
+		free(in);
+	}
+}
+
+static void
+server_handle_sigint(int sig)
+{
+	struct ead_instance *in;
+	struct list_head *p, *tmp;
+
+	list_for_each_safe(p, tmp, &instances) {
+		in = list_entry(p, struct ead_instance, list);
+		stop_server(in, true);
+	}
+	exit(1);
+}
+
+static int
+check_bridge_port(const char *br, const char *port, void *arg)
+{
+	struct ead_instance *in;
+	struct list_head *p;
+
+	list_for_each(p, &instances) {
+		in = list_entry(p, struct ead_instance, list);
+
+		if (strcmp(in->ifname, port) != 0)
+			continue;
+
+		in->br_check = true;
+		if (strcmp(in->bridge, br) == 0)
+			break;
+
+		strncpy(in->bridge, br, sizeof(in->bridge));
+		DEBUG(2, "assigning port %s to bridge %s\n", in->ifname, in->bridge);
+		stop_server(in, false);
+	}
+	return 0;
+}
+
+static int
+check_bridge(const char *name, void *arg)
+{
+	br_foreach_port(name, check_bridge_port, arg);
+	return 0;
+}
+
+static void
+check_all_interfaces(void)
+{
+	struct ead_instance *in;
+	struct list_head *p;
+
+	br_foreach_bridge(check_bridge, NULL);
+
+	/* look for interfaces that are no longer part of a bridge */
+	list_for_each(p, &instances) {
+		in = list_entry(p, struct ead_instance, list);
+
+		if (in->br_check) {
+			in->br_check = false;
+		} else if (in->bridge[0]) {
+			DEBUG(2, "removing port %s from bridge %s\n", in->ifname, in->bridge);
+			in->bridge[0] = 0;
+			stop_server(in, false);
+		}
+	}
+}
+
+
+int main(int argc, char **argv)
+{
+	struct ead_instance *in;
+	struct timeval tv;
+	const char *pidfile = NULL;
+	bool background = false;
+	int n_iface = 0;
+	int fd, ch;
+
+	if (argc == 1)
+		return usage(argv[0]);
+
+	INIT_LIST_HEAD(&instances);
+	while ((ch = getopt(argc, argv, "Bd:D:fhp:P:")) != -1) {
+		switch(ch) {
+		case 'B':
+			background = true;
+			break;
+		case 'f':
+			nonfork = true;
+			break;
+		case 'h':
+			return usage(argv[0]);
+		case 'd':
+			in = malloc(sizeof(struct ead_instance));
+			memset(in, 0, sizeof(struct ead_instance));
+			INIT_LIST_HEAD(&in->list);
+			strncpy(in->ifname, optarg, sizeof(in->ifname) - 1);
+			list_add(&in->list, &instances);
+			in->id = n_iface++;
+			break;
+		case 'D':
+			dev_name = optarg;
+			break;
+		case 'p':
+			passwd_file = optarg;
+			break;
+		case 'P':
+			pidfile = optarg;
+			break;
+		}
+	}
+	signal(SIGCHLD, server_handle_sigchld);
+	signal(SIGINT, server_handle_sigint);
+	signal(SIGTERM, server_handle_sigint);
+	signal(SIGKILL, server_handle_sigint);
+
+	if (!n_iface) {
+		fprintf(stderr, "Error: ead needs at least one interface\n");
+		return -1;
+	}
+
+	if (background) {
+		if (fork() > 0)
+			exit(0);
+
+		fd = open("/dev/null", O_RDWR);
+		dup2(fd, 0);
+		dup2(fd, 1);
+		dup2(fd, 2);
+	}
+
+	if (pidfile) {
+		char pid[8];
+		int len;
+
+		unlink(pidfile);
+		fd = open(pidfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
+		if (fd > 0) {
+			len = sprintf(pid, "%d\n", getpid());
+			write(fd, pid, len);
+			close(fd);
+		}
+	}
+
+	/* randomize the mac address */
+	get_random_bytes(ethmac + 3, 3);
+	nid = *(((u16_t *) ethmac) + 2);
+
+	start_servers(false);
+	br_init();
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	while (1) {
+		check_all_interfaces();
+		start_servers(true);
+		sleep(1);
+	}
+	br_shutdown();
+
+	return 0;
+}
diff --git a/package/network/services/ead/src/ead.h b/package/network/services/ead/src/ead.h
new file mode 100644
index 0000000000..515ac21bdb
--- /dev/null
+++ b/package/network/services/ead/src/ead.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __EAD_H
+#define __EAD_H
+
+#define EAD_DEBUGLEVEL	1
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifndef MAXSALTLEN
+#define MAXSALTLEN 32
+#endif
+
+#define EAD_PORT	56026UL
+#define EAD_MAGIC	3671771902UL
+#define EAD_CMD_TIMEOUT	10
+
+#define EAD_MAX_IV_INCR	128
+
+/* request/response types */
+/* response id == request id + 1 */
+enum ead_type {
+	EAD_TYPE_PING,
+	EAD_TYPE_PONG,
+
+	EAD_TYPE_SET_USERNAME,
+	EAD_TYPE_ACK_USERNAME,
+
+	EAD_TYPE_GET_PRIME,
+	EAD_TYPE_PRIME,
+
+	EAD_TYPE_SEND_A,
+	EAD_TYPE_SEND_B,
+
+	EAD_TYPE_SEND_AUTH,
+	EAD_TYPE_DONE_AUTH,
+
+	EAD_TYPE_SEND_CMD,
+	EAD_TYPE_RESULT_CMD,
+
+	EAD_TYPE_LAST
+};
+
+enum ead_auth_type {
+	EAD_AUTH_DEFAULT,
+	EAD_AUTH_MD5
+};
+
+enum ead_cmd_type {
+	EAD_CMD_NORMAL,
+	EAD_CMD_BACKGROUND,
+	EAD_CMD_LAST
+};
+
+struct ead_msg_pong {
+	uint16_t auth_type;
+	char name[];
+} __attribute__((packed));
+
+struct ead_msg_number {
+	uint8_t id;
+	unsigned char data[];
+} __attribute__((packed));
+
+struct ead_msg_salt {
+	uint8_t prime;
+	uint8_t len;
+	unsigned char salt[MAXSALTLEN];
+	unsigned char ext_salt[MAXSALTLEN];
+} __attribute__((packed));
+
+struct ead_msg_user {
+	char username[32];
+} __attribute__((packed));
+
+struct ead_msg_auth {
+	unsigned char data[20];
+} __attribute__((packed));
+
+struct ead_msg_cmd {
+	uint8_t type;
+	uint16_t timeout;
+	unsigned char data[];
+} __attribute__((packed));
+
+struct ead_msg_cmd_data {
+	uint8_t done;
+	unsigned char data[];
+} __attribute__((packed));
+
+struct ead_msg_encrypted {
+	uint32_t hash[5];
+	uint32_t iv;
+	uint8_t pad;
+	union {
+		struct ead_msg_cmd cmd;
+		struct ead_msg_cmd_data cmd_data;
+	} data[];
+} __attribute__((packed));
+
+
+#define EAD_DATA(_msg, _type) (&((_msg)->data[0]._type))
+#define EAD_ENC_DATA(_msg, _type) (&((_msg)->data[0].enc.data[0]._type))
+
+/* for ead_msg::sid */
+#define EAD_INSTANCE_MASK	0xf000
+#define EAD_INSTANCE_SHIFT	12
+
+struct ead_msg {
+	uint32_t magic;
+	uint32_t len;
+	uint32_t type;
+	uint16_t nid; /* node id */
+	uint16_t sid; /* session id */
+	uint32_t ip; /* source ip for responses from the server */
+	union {
+		struct ead_msg_pong pong;
+		struct ead_msg_user user;
+		struct ead_msg_number number;
+		struct ead_msg_auth auth;
+		struct ead_msg_salt salt;
+		struct ead_msg_encrypted enc;
+	} data[];
+} __attribute__((packed));
+
+
+#endif
diff --git a/package/network/services/ead/src/filter.c b/package/network/services/ead/src/filter.c
new file mode 100644
index 0000000000..0759dc330f
--- /dev/null
+++ b/package/network/services/ead/src/filter.c
@@ -0,0 +1,25 @@
+/* precompiled expression: udp and dst port 56026 */
+
+static struct bpf_insn pktfilter_insns[] = {
+	{ .code = 0x0028, .jt = 0x00, .jf = 0x00, .k = 0x0000000c },
+	{ .code = 0x0015, .jt = 0x00, .jf = 0x04, .k = 0x000086dd },
+	{ .code = 0x0030, .jt = 0x00, .jf = 0x00, .k = 0x00000014 },
+	{ .code = 0x0015, .jt = 0x00, .jf = 0x0b, .k = 0x00000011 },
+	{ .code = 0x0028, .jt = 0x00, .jf = 0x00, .k = 0x00000038 },
+	{ .code = 0x0015, .jt = 0x08, .jf = 0x09, .k = 0x0000dada },
+	{ .code = 0x0015, .jt = 0x00, .jf = 0x08, .k = 0x00000800 },
+	{ .code = 0x0030, .jt = 0x00, .jf = 0x00, .k = 0x00000017 },
+	{ .code = 0x0015, .jt = 0x00, .jf = 0x06, .k = 0x00000011 },
+	{ .code = 0x0028, .jt = 0x00, .jf = 0x00, .k = 0x00000014 },
+	{ .code = 0x0045, .jt = 0x04, .jf = 0x00, .k = 0x00001fff },
+	{ .code = 0x00b1, .jt = 0x00, .jf = 0x00, .k = 0x0000000e },
+	{ .code = 0x0048, .jt = 0x00, .jf = 0x00, .k = 0x00000010 },
+	{ .code = 0x0015, .jt = 0x00, .jf = 0x01, .k = 0x0000dada },
+	{ .code = 0x0006, .jt = 0x00, .jf = 0x00, .k = 0x000005dc },
+	{ .code = 0x0006, .jt = 0x00, .jf = 0x00, .k = 0x00000000 },
+};
+
+static struct bpf_program pktfilter = {
+	.bf_len = 16,
+	.bf_insns = pktfilter_insns,
+};
diff --git a/package/network/services/ead/src/libbridge.h b/package/network/services/ead/src/libbridge.h
new file mode 100644
index 0000000000..d7bbdc4162
--- /dev/null
+++ b/package/network/services/ead/src/libbridge.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LIBBRIDGE_H
+#define _LIBBRIDGE_H
+
+#ifdef linux
+
+int br_init(void);
+void br_shutdown(void);
+
+int br_foreach_port(const char *brname,
+		    int (*iterator)(const char *br, const char *port, void *arg),
+		    void *arg);
+
+int br_foreach_bridge(int (*iterator)(const char *, void *), void *arg);
+
+#else
+
+static inline int br_init(void)
+{
+	return 0;
+}
+
+static inline void br_shutdown(void)
+{
+}
+
+static inline int
+br_foreach_port(const char *brname,
+		    int (*iterator)(const char *br, const char *port, void *arg),
+		    void *arg)
+{
+	return 0;
+}
+
+static inline int
+br_foreach_bridge(int (*iterator)(const char *, void *), void *arg)
+{
+	return 0;
+}
+
+#endif
+
+#endif
diff --git a/package/network/services/ead/src/libbridge_init.c b/package/network/services/ead/src/libbridge_init.c
new file mode 100644
index 0000000000..687ef62113
--- /dev/null
+++ b/package/network/services/ead/src/libbridge_init.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef linux
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/in6.h>
+#include <linux/if_bridge.h>
+
+#include "libbridge.h"
+#include "libbridge_private.h"
+
+static int br_socket_fd = -1;
+
+int br_init(void)
+{
+	if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
+		return errno;
+	return 0;
+}
+
+void br_shutdown(void)
+{
+	close(br_socket_fd);
+	br_socket_fd = -1;
+}
+
+/* If /sys/class/net/XXX/bridge exists then it must be a bridge */
+static int isbridge(const struct dirent *entry)
+{
+	char path[SYSFS_PATH_MAX];
+	struct stat st;
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", entry->d_name);
+	return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
+}
+
+/*
+ * New interface uses sysfs to find bridges
+ */
+static int new_foreach_bridge(int (*iterator)(const char *name, void *),
+			      void *arg)
+{
+	struct dirent **namelist;
+	int i, count = 0;
+
+	count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
+	if (count < 0)
+		return -1;
+
+	for (i = 0; i < count; i++) {
+		if (iterator(namelist[i]->d_name, arg))
+			break;
+	}
+
+	for (i = 0; i < count; i++)
+		free(namelist[i]);
+	free(namelist);
+
+	return count;
+}
+
+/*
+ * Go over all bridges and call iterator function.
+ * if iterator returns non-zero then stop.
+ */
+int br_foreach_bridge(int (*iterator)(const char *, void *), void *arg)
+{
+	return new_foreach_bridge(iterator, arg);
+}
+
+/*
+ * Iterate over all ports in bridge (using sysfs).
+ */
+int br_foreach_port(const char *brname,
+		    int (*iterator)(const char *br, const char *port, void *arg),
+		    void *arg)
+{
+	int i, count;
+	struct dirent **namelist;
+	char path[SYSFS_PATH_MAX];
+
+	snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brif", brname);
+	count = scandir(path, &namelist, 0, alphasort);
+
+	for (i = 0; i < count; i++) {
+		if (namelist[i]->d_name[0] == '.'
+		    && (namelist[i]->d_name[1] == '\0'
+			|| (namelist[i]->d_name[1] == '.'
+			    && namelist[i]->d_name[2] == '\0')))
+			continue;
+
+		if (iterator(brname, namelist[i]->d_name, arg))
+			break;
+	}
+	for (i = 0; i < count; i++)
+		free(namelist[i]);
+	free(namelist);
+
+	return count;
+}
+
+#endif
diff --git a/package/network/services/ead/src/libbridge_private.h b/package/network/services/ead/src/libbridge_private.h
new file mode 100644
index 0000000000..38fd60ed9b
--- /dev/null
+++ b/package/network/services/ead/src/libbridge_private.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2000 Lennert Buytenhek
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LIBBRIDGE_PRIVATE_H
+#define _LIBBRIDGE_PRIVATE_H
+
+#include <linux/sockios.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/if_bridge.h>
+
+#define MAX_BRIDGES	1024
+#define MAX_PORTS	1024
+
+#define SYSFS_CLASS_NET "/sys/class/net/"
+#define SYSFS_PATH_MAX	256
+
+#define dprintf(fmt,arg...)
+
+#endif
diff --git a/package/network/services/ead/src/list.h b/package/network/services/ead/src/list.h
new file mode 100644
index 0000000000..ac429c862f
--- /dev/null
+++ b/package/network/services/ead/src/list.h
@@ -0,0 +1,602 @@
+/* GPL v2, adapted from the Linux kernel */
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#ifndef container_of
+#define container_of(ptr, type, member) (			\
+	(type *)( (char *)ptr - offsetof(type,member) ))
+#endif
+
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = NULL;
+	entry->prev = NULL;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+				struct list_head *new)
+{
+	new->next = old->next;
+	new->next->prev = new;
+	new->prev = old->prev;
+	new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+					struct list_head *new)
+{
+	list_replace(old, new);
+	INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+				const struct list_head *head)
+{
+	return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+				 struct list_head *head)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+	struct list_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); \
+        	pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+	for (pos = (head)->prev, n = pos->prev; \
+	     pos != (head); \
+	     pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)		\
+	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     &pos->member != (head);	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) 			\
+	for (; &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
+		n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) 			\
+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
+	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
+		n = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+	h->next = NULL;
+	h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+	return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+		next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	__hlist_del(n);
+	n->next = NULL;
+	n->pprev = NULL;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+	if (!hlist_unhashed(n)) {
+		__hlist_del(n);
+		INIT_HLIST_NODE(n);
+	}
+}
+
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+					struct hlist_node *next)
+{
+	n->pprev = next->pprev;
+	n->next = next;
+	next->pprev = &n->next;
+	*(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+					struct hlist_node *next)
+{
+	next->next = n->next;
+	n->next = next;
+	next->pprev = &n->next;
+
+	if(next->next)
+		next->next->pprev  = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos; pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos; pos = n)
+
+/**
+ * hlist_for_each_entry	- iterate over list of given type
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)			 \
+	for (pos = (head)->first; pos &&				 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)		\
+	for (pos = (pos)->next; pos &&					\
+	     ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});   \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)			 \
+	for (; pos &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @n:		another &struct hlist_node to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) 		 \
+	for (pos = (head)->first;					 \
+	     pos && ({ n = pos->next; 1; }) && 				 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = n)
+
+#endif
diff --git a/package/network/services/ead/src/passwd b/package/network/services/ead/src/passwd
new file mode 100644
index 0000000000..eee7a89486
--- /dev/null
+++ b/package/network/services/ead/src/passwd
@@ -0,0 +1,3 @@
+root:$1$MCGAgYw.$Ip1GcyeUliId3wzVcKR/e/:0:0:root:/root:/bin/ash
+nobody:*:65534:65534:nobody:/var:/bin/false
+daemon:*:65534:65534:daemon:/var:/bin/false
diff --git a/package/network/services/ead/src/pfc.c b/package/network/services/ead/src/pfc.c
new file mode 100644
index 0000000000..e53cbd1524
--- /dev/null
+++ b/package/network/services/ead/src/pfc.c
@@ -0,0 +1,54 @@
+/*
+ * Small pcap precompiler
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pcap.h>
+
+int main (int argc, char ** argv)
+{
+	struct bpf_program filter;
+	pcap_t *pc;
+	int i;
+
+	if (argc != 2)
+	{
+		printf ("Usage: %s <expression>\n", argv[0]);
+		return 1;
+	}
+
+	pc = pcap_open_dead(DLT_EN10MB, 1500);
+	if (pcap_compile(pc, &filter, argv[1], 1, 0) != 0) {
+		printf("error in active-filter expression: %s\n", pcap_geterr(pc));
+		return 1;
+	}
+
+	printf("/* precompiled expression: %s */\n\n"
+		"static struct bpf_insn pktfilter_insns[] = {\n",
+		argv[1]);
+
+	for (i = 0; i < filter.bf_len; i++) {
+		struct bpf_insn *in = &filter.bf_insns[i];
+		printf("\t{ .code = 0x%04x, .jt = 0x%02x, .jf = 0x%02x, .k = 0x%08x },\n", in->code, in->jt, in->jf, in->k);
+	}
+	printf("};\n\n"
+		"static struct bpf_program pktfilter = {\n"
+		"\t.bf_len = %d,\n"
+		"\t.bf_insns = pktfilter_insns,\n"
+		"};\n", filter.bf_len);
+	return 0;
+
+}
diff --git a/package/network/services/ead/src/pw_encrypt_md5.c b/package/network/services/ead/src/pw_encrypt_md5.c
new file mode 100644
index 0000000000..bc9f249fda
--- /dev/null
+++ b/package/network/services/ead/src/pw_encrypt_md5.c
@@ -0,0 +1,646 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
+ *
+ * This code is the same as the code published by RSA Inc.  It has been
+ * edited for clarity and style only.
+ *
+ * ----------------------------------------------------------------------------
+ * The md5_crypt() function was taken from freeBSD's libcrypt and contains
+ * this license:
+ *    "THE BEER-WARE LICENSE" (Revision 42):
+ *     <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ *     can do whatever you want with this stuff. If we meet some day, and you think
+ *     this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ *
+ * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
+ *
+ * ----------------------------------------------------------------------------
+ * On April 19th, 2001 md5_crypt() was modified to make it reentrant
+ * by Erik Andersen <andersen@uclibc.org>
+ *
+ *
+ * June 28, 2001             Manuel Novoa III
+ *
+ * "Un-inlined" code using loops and static const tables in order to
+ * reduce generated code size (on i386 from approx 4k to approx 2.5k).
+ *
+ * June 29, 2001             Manuel Novoa III
+ *
+ * Completely removed static PADDING array.
+ *
+ * Reintroduced the loop unrolling in MD5_Transform and added the
+ * MD5_SIZE_OVER_SPEED option for configurability.  Define below as:
+ *       0    fully unrolled loops
+ *       1    partially unrolled (4 ops per loop)
+ *       2    no unrolling -- introduces the need to swap 4 variables (slow)
+ *       3    no unrolling and all 4 loops merged into one with switch
+ *               in each loop (glacial)
+ * On i386, sizes are roughly (-Os -fno-builtin):
+ *     0: 3k     1: 2.5k     2: 2.2k     3: 2k
+ *
+ *
+ * Since SuSv3 does not require crypt_r, modified again August 7, 2002
+ * by Erik Andersen to remove reentrance stuff...
+ */
+
+static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+/*
+ * Valid values are  1 (fastest/largest) to 3 (smallest/slowest).
+ */
+#define MD5_SIZE_OVER_SPEED 3
+
+/**********************************************************************/
+
+/* MD5 context. */
+struct MD5Context {
+	uint32_t state[4];	/* state (ABCD) */
+	uint32_t count[2];	/* number of bits, modulo 2^64 (lsb first) */
+	unsigned char buffer[64];	/* input buffer */
+};
+
+static void __md5_Init(struct MD5Context *);
+static void __md5_Update(struct MD5Context *, const unsigned char *, unsigned int);
+static void __md5_Pad(struct MD5Context *);
+static void __md5_Final(unsigned char [16], struct MD5Context *);
+static void __md5_Transform(uint32_t [4], const unsigned char [64]);
+
+
+#define MD5_MAGIC_STR "$1$"
+#define MD5_MAGIC_LEN (sizeof(MD5_MAGIC_STR) - 1)
+static const unsigned char __md5__magic[] = MD5_MAGIC_STR;
+
+
+#ifdef i386
+#define __md5_Encode memcpy
+#define __md5_Decode memcpy
+#else /* i386 */
+
+/*
+ * __md5_Encodes input (uint32_t) into output (unsigned char). Assumes len is
+ * a multiple of 4.
+ */
+static void
+__md5_Encode(unsigned char *output, uint32_t *input, unsigned int len)
+{
+	unsigned int i, j;
+
+	for (i = 0, j = 0; j < len; i++, j += 4) {
+		output[j] = input[i];
+		output[j+1] = (input[i] >> 8);
+		output[j+2] = (input[i] >> 16);
+		output[j+3] = (input[i] >> 24);
+	}
+}
+
+/*
+ * __md5_Decodes input (unsigned char) into output (uint32_t). Assumes len is
+ * a multiple of 4.
+ */
+static void
+__md5_Decode(uint32_t *output, const unsigned char *input, unsigned int len)
+{
+	unsigned int i, j;
+
+	for (i = 0, j = 0; j < len; i++, j += 4)
+		output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
+		    (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
+}
+#endif /* i386 */
+
+/* F, G, H and I are basic MD5 functions. */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/*
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+	(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+	(a) = ROTATE_LEFT((a), (s)); \
+	(a) += (b); \
+	}
+#define GG(a, b, c, d, x, s, ac) { \
+	(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+	(a) = ROTATE_LEFT((a), (s)); \
+	(a) += (b); \
+	}
+#define HH(a, b, c, d, x, s, ac) { \
+	(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+	(a) = ROTATE_LEFT((a), (s)); \
+	(a) += (b); \
+	}
+#define II(a, b, c, d, x, s, ac) { \
+	(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+	(a) = ROTATE_LEFT((a), (s)); \
+	(a) += (b); \
+	}
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context. */
+static void __md5_Init(struct MD5Context *context)
+{
+	context->count[0] = context->count[1] = 0;
+
+	/* Load magic initialization constants.  */
+	context->state[0] = 0x67452301;
+	context->state[1] = 0xefcdab89;
+	context->state[2] = 0x98badcfe;
+	context->state[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+static void __md5_Update(struct MD5Context *context, const unsigned char *input, unsigned int inputLen)
+{
+	unsigned int i, idx, partLen;
+
+	/* Compute number of bytes mod 64 */
+	idx = (context->count[0] >> 3) & 0x3F;
+
+	/* Update number of bits */
+	context->count[0] += (inputLen << 3);
+	if (context->count[0] < (inputLen << 3))
+		context->count[1]++;
+	context->count[1] += (inputLen >> 29);
+
+	partLen = 64 - idx;
+
+	/* Transform as many times as possible. */
+	if (inputLen >= partLen) {
+		memcpy(&context->buffer[idx], input, partLen);
+		__md5_Transform(context->state, context->buffer);
+
+		for (i = partLen; i + 63 < inputLen; i += 64)
+			__md5_Transform(context->state, &input[i]);
+
+		idx = 0;
+	} else
+		i = 0;
+
+	/* Buffer remaining input */
+	memcpy(&context->buffer[idx], &input[i], inputLen - i);
+}
+
+/*
+ * MD5 padding. Adds padding followed by original length.
+ */
+static void __md5_Pad(struct MD5Context *context)
+{
+	unsigned char bits[8];
+	unsigned int idx, padLen;
+	unsigned char PADDING[64];
+
+	memset(PADDING, 0, sizeof(PADDING));
+	PADDING[0] = 0x80;
+
+	/* Save number of bits */
+	__md5_Encode(bits, context->count, 8);
+
+	/* Pad out to 56 mod 64. */
+	idx = (context->count[0] >> 3) & 0x3f;
+	padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+	__md5_Update(context, PADDING, padLen);
+
+	/* Append length (before padding) */
+	__md5_Update(context, bits, 8);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation, writing the
+ * the message digest and zeroizing the context.
+ */
+static void __md5_Final(unsigned char digest[16], struct MD5Context *context)
+{
+	/* Do padding. */
+	__md5_Pad(context);
+
+	/* Store state in digest */
+	__md5_Encode(digest, context->state, 16);
+
+	/* Zeroize sensitive information. */
+	memset(context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void __md5_Transform(uint32_t state[4], const unsigned char block[64])
+{
+	uint32_t a, b, c, d, x[16];
+#if MD5_SIZE_OVER_SPEED > 1
+	uint32_t temp;
+	const unsigned char *ps;
+
+	static const unsigned char S[] = {
+		7, 12, 17, 22,
+		5, 9, 14, 20,
+		4, 11, 16, 23,
+		6, 10, 15, 21
+	};
+#endif /* MD5_SIZE_OVER_SPEED > 1 */
+
+#if MD5_SIZE_OVER_SPEED > 0
+	const uint32_t *pc;
+	const unsigned char *pp;
+	int i;
+
+	static const uint32_t C[] = {
+								/* round 1 */
+		0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+		0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+		0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+		0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+								/* round 2 */
+		0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+		0xd62f105d, 0x2441453,  0xd8a1e681, 0xe7d3fbc8,
+		0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+		0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+								/* round 3 */
+		0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+		0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+		0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+		0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+								/* round 4 */
+		0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+		0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+		0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+		0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+	};
+
+	static const unsigned char P[] = {
+		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
+		1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
+		5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
+		0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9  /* 4 */
+	};
+
+#endif /* MD5_SIZE_OVER_SPEED > 0 */
+
+	__md5_Decode(x, block, 64);
+
+	a = state[0]; b = state[1]; c = state[2]; d = state[3];
+
+#if MD5_SIZE_OVER_SPEED > 2
+	pc = C; pp = P; ps = S - 4;
+
+	for (i = 0; i < 64; i++) {
+		if ((i & 0x0f) == 0) ps += 4;
+		temp = a;
+		switch (i>>4) {
+			case 0:
+				temp += F(b, c, d);
+				break;
+			case 1:
+				temp += G(b, c, d);
+				break;
+			case 2:
+				temp += H(b, c, d);
+				break;
+			case 3:
+				temp += I(b, c, d);
+				break;
+		}
+		temp += x[*pp++] + *pc++;
+		temp = ROTATE_LEFT(temp, ps[i & 3]);
+		temp += b;
+		a = d; d = c; c = b; b = temp;
+	}
+#elif MD5_SIZE_OVER_SPEED > 1
+	pc = C; pp = P; ps = S;
+
+	/* Round 1 */
+	for (i = 0; i < 16; i++) {
+		FF(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+		temp = d; d = c; c = b; b = a; a = temp;
+	}
+
+	/* Round 2 */
+	ps += 4;
+	for (; i < 32; i++) {
+		GG(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+		temp = d; d = c; c = b; b = a; a = temp;
+	}
+	/* Round 3 */
+	ps += 4;
+	for (; i < 48; i++) {
+		HH(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+		temp = d; d = c; c = b; b = a; a = temp;
+	}
+
+	/* Round 4 */
+	ps += 4;
+	for (; i < 64; i++) {
+		II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
+		temp = d; d = c; c = b; b = a; a = temp;
+	}
+#elif MD5_SIZE_OVER_SPEED > 0
+	pc = C; pp = P;
+
+	/* Round 1 */
+	for (i = 0; i < 4; i++) {
+		FF(a, b, c, d, x[*pp],  7, *pc); pp++; pc++;
+		FF(d, a, b, c, x[*pp], 12, *pc); pp++; pc++;
+		FF(c, d, a, b, x[*pp], 17, *pc); pp++; pc++;
+		FF(b, c, d, a, x[*pp], 22, *pc); pp++; pc++;
+	}
+
+	/* Round 2 */
+	for (i = 0; i < 4; i++) {
+		GG(a, b, c, d, x[*pp],  5, *pc); pp++; pc++;
+		GG(d, a, b, c, x[*pp],  9, *pc); pp++; pc++;
+		GG(c, d, a, b, x[*pp], 14, *pc); pp++; pc++;
+		GG(b, c, d, a, x[*pp], 20, *pc); pp++; pc++;
+	}
+	/* Round 3 */
+	for (i = 0; i < 4; i++) {
+		HH(a, b, c, d, x[*pp],  4, *pc); pp++; pc++;
+		HH(d, a, b, c, x[*pp], 11, *pc); pp++; pc++;
+		HH(c, d, a, b, x[*pp], 16, *pc); pp++; pc++;
+		HH(b, c, d, a, x[*pp], 23, *pc); pp++; pc++;
+	}
+
+	/* Round 4 */
+	for (i = 0; i < 4; i++) {
+		II(a, b, c, d, x[*pp],  6, *pc); pp++; pc++;
+		II(d, a, b, c, x[*pp], 10, *pc); pp++; pc++;
+		II(c, d, a, b, x[*pp], 15, *pc); pp++; pc++;
+		II(b, c, d, a, x[*pp], 21, *pc); pp++; pc++;
+	}
+#else
+	/* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+	FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+	FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+	FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+	FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+	FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+	FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+	FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+	FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+	FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+	FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+	FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+	FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+	FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+	FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+	FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+	FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+	/* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+	GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+	GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+	GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+	GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+	GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+	GG(d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+	GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+	GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+	GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+	GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+	GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+	GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+	GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+	GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+	GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+	GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+	/* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+	HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+	HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+	HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+	HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+	HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+	HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+	HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+	HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+	HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+	HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+	HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+	HH(b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+	HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+	HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+	HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+	HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+	/* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+	II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+	II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+	II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+	II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+	II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+	II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+	II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+	II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+	II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+	II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+	II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+	II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+	II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+	II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+	II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+	II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+#endif
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+
+	/* Zeroize sensitive information. */
+	memset(x, 0, sizeof(x));
+}
+
+
+static char*
+__md5_to64(char *s, unsigned v, int n)
+{
+	while (--n >= 0) {
+		*s++ = ascii64[v & 0x3f];
+		v >>= 6;
+	}
+	return s;
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+#define MD5_OUT_BUFSIZE 36
+static char *
+md5_crypt(char passwd[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
+{
+	const unsigned char *sp, *ep;
+	char *p;
+	unsigned char final[17];	/* final[16] exists only to aid in looping */
+	int sl, pl, i, pw_len;
+	struct MD5Context ctx, ctx1;
+
+	/* Refine the Salt first */
+	sp = salt;
+
+	sp += MD5_MAGIC_LEN;
+
+	/* It stops at the first '$', max 8 chars */
+	for (ep = sp; *ep && *ep != '$' && ep < (sp+8); ep++)
+		continue;
+
+	/* get the length of the true salt */
+	sl = ep - sp;
+
+	__md5_Init(&ctx);
+
+	/* The password first, since that is what is most unknown */
+	pw_len = strlen((char*)pw);
+	__md5_Update(&ctx, pw, pw_len);
+
+	/* Then our magic string */
+	__md5_Update(&ctx, __md5__magic, MD5_MAGIC_LEN);
+
+	/* Then the raw salt */
+	__md5_Update(&ctx, sp, sl);
+
+	/* Then just as many characters of the MD5(pw, salt, pw) */
+	__md5_Init(&ctx1);
+	__md5_Update(&ctx1, pw, pw_len);
+	__md5_Update(&ctx1, sp, sl);
+	__md5_Update(&ctx1, pw, pw_len);
+	__md5_Final(final, &ctx1);
+	for (pl = pw_len; pl > 0; pl -= 16)
+		__md5_Update(&ctx, final, pl > 16 ? 16 : pl);
+
+	/* Don't leave anything around in vm they could use. */
+//TODO: the above comment seems to be wrong. final is used later.
+	memset(final, 0, sizeof(final));
+
+	/* Then something really weird... */
+	for (i = pw_len; i; i >>= 1) {
+		__md5_Update(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
+	}
+
+	/* Now make the output string */
+	passwd[0] = '$';
+	passwd[1] = '1';
+	passwd[2] = '$';
+	strncpy(passwd + 3, (char*)sp, sl);
+	passwd[sl + 3] = '$';
+
+	__md5_Final(final, &ctx);
+
+	/*
+	 * and now, just to make sure things don't run too fast
+	 * On a 60 Mhz Pentium this takes 34 msec, so you would
+	 * need 30 seconds to build a 1000 entry dictionary...
+	 */
+	for (i = 0; i < 1000; i++) {
+		__md5_Init(&ctx1);
+		if (i & 1)
+			__md5_Update(&ctx1, pw, pw_len);
+		else
+			__md5_Update(&ctx1, final, 16);
+
+		if (i % 3)
+			__md5_Update(&ctx1, sp, sl);
+
+		if (i % 7)
+			__md5_Update(&ctx1, pw, pw_len);
+
+		if (i & 1)
+			__md5_Update(&ctx1, final, 16);
+		else
+			__md5_Update(&ctx1, pw, pw_len);
+		__md5_Final(final, &ctx1);
+	}
+
+	p = passwd + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
+
+	/* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
+	final[16] = final[5];
+	for (i = 0; i < 5; i++) {
+		unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
+		p = __md5_to64(p, l, 4);
+	}
+	p = __md5_to64(p, final[11], 2);
+	*p = '\0';
+
+	/* Don't leave anything around in vm they could use. */
+	memset(final, 0, sizeof(final));
+
+	return passwd;
+}
+
+#undef MD5_SIZE_OVER_SPEED
+#undef MD5_MAGIC_STR
+#undef MD5_MAGIC_LEN
+#undef __md5_Encode
+#undef __md5_Decode
+#undef F
+#undef G
+#undef H
+#undef I
+#undef ROTATE_LEFT
+#undef FF
+#undef GG
+#undef HH
+#undef II
+#undef S11
+#undef S12
+#undef S13
+#undef S14
+#undef S21
+#undef S22
+#undef S23
+#undef S24
+#undef S31
+#undef S32
+#undef S33
+#undef S34
+#undef S41
+#undef S42
+#undef S43
+#undef S44
diff --git a/package/network/services/ead/src/sha1.c b/package/network/services/ead/src/sha1.c
new file mode 100644
index 0000000000..3683a7da71
--- /dev/null
+++ b/package/network/services/ead/src/sha1.c
@@ -0,0 +1,104 @@
+/*
+ * SHA transform algorithm, originally taken from code written by
+ * Peter Gutmann, and placed in the public domain.
+ */
+
+static  uint32_t
+rol32(uint32_t word, int shift)
+{
+	return (word << shift) | (word >> (32 - shift));
+}
+
+/* The SHA f()-functions.  */
+
+#define f1(x,y,z)   (z ^ (x & (y ^ z)))		/* x ? y : z */
+#define f2(x,y,z)   (x ^ y ^ z)			/* XOR */
+#define f3(x,y,z)   ((x & y) + (z & (x ^ y)))	/* majority */
+
+/* The SHA Mysterious Constants */
+
+#define K1  0x5A827999L			/* Rounds  0-19: sqrt(2) * 2^30 */
+#define K2  0x6ED9EBA1L			/* Rounds 20-39: sqrt(3) * 2^30 */
+#define K3  0x8F1BBCDCL			/* Rounds 40-59: sqrt(5) * 2^30 */
+#define K4  0xCA62C1D6L			/* Rounds 60-79: sqrt(10) * 2^30 */
+
+/**
+ * sha_transform - single block SHA1 transform
+ *
+ * @digest: 160 bit digest to update
+ * @data:   512 bits of data to hash
+ * @W:      80 words of workspace (see note)
+ *
+ * This function generates a SHA1 digest for a single 512-bit block.
+ * Be warned, it does not handle padding and message digest, do not
+ * confuse it with the full FIPS 180-1 digest algorithm for variable
+ * length messages.
+ *
+ * Note: If the hash is security sensitive, the caller should be sure
+ * to clear the workspace. This is left to the caller to avoid
+ * unnecessary clears between chained hashing operations.
+ */
+static void sha_transform(uint32_t *digest, const unsigned char *in, uint32_t *W)
+{
+	uint32_t a, b, c, d, e, t, i;
+
+	for (i = 0; i < 16; i++) {
+		int ofs = 4 * i;
+
+		/* word load/store may be unaligned here, so use bytes instead */
+		W[i] =
+			(in[ofs+0] << 24) |
+			(in[ofs+1] << 16) |
+			(in[ofs+2] << 8) |
+			 in[ofs+3];
+	}
+
+	for (i = 0; i < 64; i++)
+		W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1);
+
+	a = digest[0];
+	b = digest[1];
+	c = digest[2];
+	d = digest[3];
+	e = digest[4];
+
+	for (i = 0; i < 20; i++) {
+		t = f1(b, c, d) + K1 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	for (; i < 40; i ++) {
+		t = f2(b, c, d) + K2 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	for (; i < 60; i ++) {
+		t = f3(b, c, d) + K3 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	for (; i < 80; i ++) {
+		t = f2(b, c, d) + K4 + rol32(a, 5) + e + W[i];
+		e = d; d = c; c = rol32(b, 30); b = a; a = t;
+	}
+
+	digest[0] += a;
+	digest[1] += b;
+	digest[2] += c;
+	digest[3] += d;
+	digest[4] += e;
+}
+
+/**
+ * sha_init - initialize the vectors for a SHA1 digest
+ * @buf: vector to initialize
+ */
+static void sha_init(uint32_t *buf)
+{
+	buf[0] = 0x67452301;
+	buf[1] = 0xefcdab89;
+	buf[2] = 0x98badcfe;
+	buf[3] = 0x10325476;
+	buf[4] = 0xc3d2e1f0;
+}
+
diff --git a/package/network/services/ead/src/tinysrp/Makefile.am b/package/network/services/ead/src/tinysrp/Makefile.am
new file mode 100644
index 0000000000..a8f899fe2c
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/Makefile.am
@@ -0,0 +1,28 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+noinst_HEADERS = t_client.h t_pwd.h t_server.h t_sha.h \
+  bn.h bn_lcl.h bn_prime.h t_defines.h t_read.h
+
+include_HEADERS = tinysrp.h
+
+lib_LIBRARIES = libtinysrp.a
+
+CFLAGS = -O2 @signed@
+
+libtinysrp_a_SOURCES = \
+  tinysrp.c t_client.c t_getconf.c t_conv.c t_getpass.c t_sha.c t_math.c \
+  t_misc.c t_pw.c t_read.c t_server.c t_truerand.c \
+  bn_add.c bn_ctx.c bn_div.c bn_exp.c bn_mul.c bn_word.c bn_asm.c bn_lib.c \
+  bn_shift.c bn_sqr.c
+
+noinst_PROGRAMS = srvtest clitest
+srvtest_SOURCES = srvtest.c
+clitest_SOURCES = clitest.c
+
+bin_PROGRAMS = tconf tphrase
+tconf_SOURCES = tconf.c t_conf.c
+tphrase_SOURCES = tphrase.c
+
+LDADD = libtinysrp.a
+
+EXTRA_DIST = tpasswd Notes
diff --git a/package/network/services/ead/src/tinysrp/Makefile.in b/package/network/services/ead/src/tinysrp/Makefile.in
new file mode 100644
index 0000000000..4701cd5238
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/Makefile.in
@@ -0,0 +1,477 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+signed = @signed@
+
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+noinst_HEADERS = t_client.h t_pwd.h t_server.h t_sha.h   bn.h bn_lcl.h bn_prime.h t_defines.h t_read.h
+
+
+include_HEADERS = tinysrp.h
+
+lib_LIBRARIES = libtinysrp.a
+
+CFLAGS = -O2 @signed@
+
+libtinysrp_a_SOURCES =    tinysrp.c t_client.c t_getconf.c t_conv.c t_getpass.c t_sha.c t_math.c   t_misc.c t_pw.c t_read.c t_server.c t_truerand.c   bn_add.c bn_ctx.c bn_div.c bn_exp.c bn_mul.c bn_word.c bn_asm.c bn_lib.c   bn_shift.c bn_sqr.c
+
+
+noinst_PROGRAMS = srvtest clitest
+srvtest_SOURCES = srvtest.c
+clitest_SOURCES = clitest.c
+
+bin_PROGRAMS = tconf tphrase
+tconf_SOURCES = tconf.c t_conf.c
+tphrase_SOURCES = tphrase.c
+
+LDADD = libtinysrp.a
+
+EXTRA_DIST = tpasswd Notes
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(lib_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I.
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libtinysrp_a_LIBADD = 
+libtinysrp_a_OBJECTS =  tinysrp.o t_client.o t_getconf.o t_conv.o \
+t_getpass.o t_sha.o t_math.o t_misc.o t_pw.o t_read.o t_server.o \
+t_truerand.o bn_add.o bn_ctx.o bn_div.o bn_exp.o bn_mul.o bn_word.o \
+bn_asm.o bn_lib.o bn_shift.o bn_sqr.o
+AR = ar
+PROGRAMS =  $(bin_PROGRAMS) $(noinst_PROGRAMS)
+
+tconf_OBJECTS =  tconf.o t_conf.o
+tconf_LDADD = $(LDADD)
+tconf_DEPENDENCIES =  libtinysrp.a
+tconf_LDFLAGS = 
+tphrase_OBJECTS =  tphrase.o
+tphrase_LDADD = $(LDADD)
+tphrase_DEPENDENCIES =  libtinysrp.a
+tphrase_LDFLAGS = 
+srvtest_OBJECTS =  srvtest.o
+srvtest_LDADD = $(LDADD)
+srvtest_DEPENDENCIES =  libtinysrp.a
+srvtest_LDFLAGS = 
+clitest_OBJECTS =  clitest.o
+clitest_LDADD = $(LDADD)
+clitest_DEPENDENCIES =  libtinysrp.a
+clitest_LDFLAGS = 
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS =  $(include_HEADERS) $(noinst_HEADERS)
+
+DIST_COMMON =  ./stamp-h.in Makefile.am Makefile.in acconfig.h \
+acinclude.m4 aclocal.m4 config.h.in configure configure.in install-sh \
+missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libtinysrp_a_SOURCES) $(tconf_SOURCES) $(tphrase_SOURCES) $(srvtest_SOURCES) $(clitest_SOURCES)
+OBJECTS = $(libtinysrp_a_OBJECTS) $(tconf_OBJECTS) $(tphrase_OBJECTS) $(srvtest_OBJECTS) $(clitest_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in  acinclude.m4
+	cd $(srcdir) && $(ACLOCAL)
+
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+	cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+	@if test ! -f $@; then \
+		rm -f stamp-h; \
+		$(MAKE) stamp-h; \
+	else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES= CONFIG_HEADERS=config.h \
+	     $(SHELL) ./config.status
+	@echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+	@if test ! -f $@; then \
+		rm -f $(srcdir)/stamp-h.in; \
+		$(MAKE) $(srcdir)/stamp-h.in; \
+	else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+	cd $(top_srcdir) && $(AUTOHEADER)
+	@echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+	-rm -f config.h
+
+maintainer-clean-hdr:
+
+mostlyclean-libLIBRARIES:
+
+clean-libLIBRARIES:
+	-test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
+
+distclean-libLIBRARIES:
+
+maintainer-clean-libLIBRARIES:
+
+install-libLIBRARIES: $(lib_LIBRARIES)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(libdir)
+	@list='$(lib_LIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p"; \
+	    $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p; \
+	  else :; fi; \
+	done
+	@$(POST_INSTALL)
+	@list='$(lib_LIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo " $(RANLIB) $(DESTDIR)$(libdir)/$$p"; \
+	    $(RANLIB) $(DESTDIR)$(libdir)/$$p; \
+	  else :; fi; \
+	done
+
+uninstall-libLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	list='$(lib_LIBRARIES)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(libdir)/$$p; \
+	done
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.S.o:
+	$(COMPILE) -c $<
+
+mostlyclean-compile:
+	-rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+	-rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libtinysrp.a: $(libtinysrp_a_OBJECTS) $(libtinysrp_a_DEPENDENCIES)
+	-rm -f libtinysrp.a
+	$(AR) cru libtinysrp.a $(libtinysrp_a_OBJECTS) $(libtinysrp_a_LIBADD)
+	$(RANLIB) libtinysrp.a
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+	-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    echo "  $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+	     $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+	done
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+	-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+tconf: $(tconf_OBJECTS) $(tconf_DEPENDENCIES)
+	@rm -f tconf
+	$(LINK) $(tconf_LDFLAGS) $(tconf_OBJECTS) $(tconf_LDADD) $(LIBS)
+
+tphrase: $(tphrase_OBJECTS) $(tphrase_DEPENDENCIES)
+	@rm -f tphrase
+	$(LINK) $(tphrase_LDFLAGS) $(tphrase_OBJECTS) $(tphrase_LDADD) $(LIBS)
+
+srvtest: $(srvtest_OBJECTS) $(srvtest_DEPENDENCIES)
+	@rm -f srvtest
+	$(LINK) $(srvtest_LDFLAGS) $(srvtest_OBJECTS) $(srvtest_LDADD) $(LIBS)
+
+clitest: $(clitest_OBJECTS) $(clitest_DEPENDENCIES)
+	@rm -f clitest
+	$(LINK) $(clitest_LDFLAGS) $(clitest_OBJECTS) $(clitest_LDADD) $(LIBS)
+
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(includedir)
+	@list='$(include_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+	  echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \
+	  $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	list='$(include_HEADERS)'; for p in $$list; do \
+	  rm -f $(DESTDIR)$(includedir)/$$p; \
+	done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	here=`pwd` && cd $(srcdir) \
+	  && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)'; \
+	unique=`for i in $$list; do echo $$i; done | \
+	  awk '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+	  || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+	-rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	-rm -rf $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+	mkdir $(distdir)/=build
+	mkdir $(distdir)/=inst
+	dc_install_base=`cd $(distdir)/=inst && pwd`; \
+	cd $(distdir)/=build \
+	  && ../configure --srcdir=.. --prefix=$$dc_install_base \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist
+	-rm -rf $(distdir)
+	@banner="$(distdir).tar.gz is ready for distribution"; \
+	dashes=`echo "$$banner" | sed s/./=/g`; \
+	echo "$$dashes"; \
+	echo "$$banner"; \
+	echo "$$dashes"
+dist: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+dist-all: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+distdir: $(DISTFILES)
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+	-chmod 777 $(distdir)
+	@for file in $(DISTFILES); do \
+	  d=$(srcdir); \
+	  if test -d $$d/$$file; then \
+	    cp -pr $$d/$$file $(distdir)/$$file; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+	    || cp -p $$d/$$file $(distdir)/$$file || :; \
+	  fi; \
+	done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+all-recursive-am: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-libLIBRARIES install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am: install-includeHEADERS
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-libLIBRARIES uninstall-binPROGRAMS \
+		uninstall-includeHEADERS
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(HEADERS) config.h
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+	$(mkinstalldirs)  $(DESTDIR)$(libdir) $(DESTDIR)$(bindir) \
+		$(DESTDIR)$(includedir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+	-rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-hdr mostlyclean-libLIBRARIES \
+		mostlyclean-compile mostlyclean-binPROGRAMS \
+		mostlyclean-noinstPROGRAMS mostlyclean-tags \
+		mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-hdr clean-libLIBRARIES clean-compile clean-binPROGRAMS \
+		clean-noinstPROGRAMS clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-hdr distclean-libLIBRARIES distclean-compile \
+		distclean-binPROGRAMS distclean-noinstPROGRAMS \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+	-rm -f config.status
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-libLIBRARIES \
+		maintainer-clean-compile maintainer-clean-binPROGRAMS \
+		maintainer-clean-noinstPROGRAMS maintainer-clean-tags \
+		maintainer-clean-generic distclean-am
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+	-rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+mostlyclean-libLIBRARIES distclean-libLIBRARIES clean-libLIBRARIES \
+maintainer-clean-libLIBRARIES uninstall-libLIBRARIES \
+install-libLIBRARIES mostlyclean-compile distclean-compile \
+clean-compile maintainer-clean-compile mostlyclean-binPROGRAMS \
+distclean-binPROGRAMS clean-binPROGRAMS maintainer-clean-binPROGRAMS \
+uninstall-binPROGRAMS install-binPROGRAMS mostlyclean-noinstPROGRAMS \
+distclean-noinstPROGRAMS clean-noinstPROGRAMS \
+maintainer-clean-noinstPROGRAMS uninstall-includeHEADERS \
+install-includeHEADERS tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
+installcheck-am installcheck all-recursive-am install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/package/network/services/ead/src/tinysrp/Notes b/package/network/services/ead/src/tinysrp/Notes
new file mode 100644
index 0000000000..a8620aa700
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/Notes
@@ -0,0 +1,110 @@
+t_* stuff is from the srp 1.7.1 dist
+bn_* stuff is from openssl 0.9.6
+
+(The 7 in libtinysrp's version number reflects the srp version.)
+
+Licensing and copyright for srp and openssl are as indicated in the relevant
+source files.  Everything else here is GPL, including the tinysrp protocol.
+
+Changelog since initial release:
+
+0.7.4   more robust terminal modes in t_getpass
+	a potential buffer overflow in tinysrp
+0.7.5   uninitialized pointer bug in tconf
+
+Changes from the base srp and openssl distributions:
+
+I've removed everything that's not needed for client/server operations, and
+all the bn_* stuff that's only used for prime generation has been moved to
+t_conf.c, which isn't part of the library anymore.  Also, all the routines
+used for passphrase file maintenance have been moved to tphrase.c.
+
+The library has been optimized (a bit) for space instead of speed.  Since
+authentication is usually only done once, this isn't a big problem.  Modern
+CPUs are plenty fast for this task, and even 100 MHz CPUs are fine.  If you
+really need the speed, get the regular distributions.
+
+Note that if the server sends the client a prime that the client doesn't
+know about, the client MUST test for primality.  Since this is pretty
+expensive, and takes 30 seconds on a 100 MHz machine, and uses lots of code,
+I've removed that ability from the client.  So only KNOWN primes can be
+used.  You can still generate new ones with tconf, but you have to install
+them in the table of known primes (pre_params) in t_getconf.c that's common
+to the client and server, and recompile.  The configuration file is gone.
+
+The default prime (the last entry in the table) is 1024 bits; there are
+others with more bits but they will be correspondingly slower.
+
+The default tpasswd file (which is an ascii file that may be editted with a
+regular text editor) contains two users: moo (passphrase "glub glub") and
+"new user" (passphrase "this is a test").  Passphrases may be added or
+changed with tphrase; you can also change the user's prime.  To delete a
+user, edit the tpasswd file and remove that line.  The tpasswd file's
+default name is DEFAULT_PASSWD in t_pwd.h.  Note that you can't change a
+user's username by editting the file: the username is encoded in the
+verifier.  If you change a username you must set a new passphrase with
+tphrase.
+
+Here is an example session, using the supplied srvtest and clitest.  First,
+start both programs in different windows, and enter the user names.  Normally,
+the client would send the username to the server.  Server lines are marked
+with S>, client lines with C>.
+
+S> % srvtest
+S> Enter username: moo
+S> index (to client): 5
+S> salt (to client): 19AI0Hc9jEkdFc
+
+C> % clitest
+C> Enter username: moo
+C> Enter index (from server): 5
+C> Enter salt (from server): 19AI0Hc9jEkdFc
+
+The server reports the index and salt values used for that user.  They
+are sent over the network to the client.  (Simulate this by cutting and
+pasting from one window to the other.)
+
+C> A (to server): 5wCDXRxLIv/zLazYfKupV/OY3BlhTZuJ71wVgI0HcL1kSJEpkMuWF.xEz/BV2wlJl7vk5Eoz9KMS1ccnaatsVP5D6CBm7UA.yVB59EQFN0dNBirvX29NAFdtdMsMppo5tHRy987XjJWrWSLpeibq6emr.gP8nYyX75GQqSiMY1j
+C> Enter password:
+
+S> Enter A (from client): 5wCDXRxLIv/zLazYfKupV/OY3BlhTZuJ71wVgI0HcL1kSJEpkMuWF.xEz/BV2wlJl7vk5Eoz9KMS1ccnaatsVP5D6CBm7UA.yVB59EQFN0dNBirvX29NAFdtdMsMppo5tHRy987XjJWrWSLpeibq6emr.gP8nYyX75GQqSiMY1j
+
+Now the client calculates A and sends it to the server, and while the
+server is munching on that, the client gets the password from the user.
+
+S> B (to client): 9dcCpulxQAbaDXI0NHWY6B.QH6B9fsoXs/x/5SCNBNJm/6H6bYfbVrwNmdquhLZjYMvpcgGc2mBYqL77RNfw1kVQo17//GfsByECBIjRnrAn02ffX9Y/llJcfscAQiii0hyZhJf9PT5wE7pC7WUjIgSqckIZ0JLNDbSr7fJcrgw
+S> Session key: ebbcf3a45c968defdcfff6e144ad8d4f5412167c9716e79cbf7cacfe18257947ad46fa5d6418a1fd
+
+The server now calculates B and sends it to the client.  The session key
+is not sent -- it is a shared secret that can be used for encryption.
+
+C> Enter B (from server): 9dcCpulxQAbaDXI0NHWY6B.QH6B9fsoXs/x/5SCNBNJm/6H6bYfbVrwNmdquhLZjYMvpcgGc2mBYqL77RNfw1kVQo17//GfsByECBIjRnrAn02ffX9Y/llJcfscAQiii0hyZhJf9PT5wE7pC7WUjIgSqckIZ0JLNDbSr7fJcrgw
+C> Session key: ebbcf3a45c968defdcfff6e144ad8d4f5412167c9716e79cbf7cacfe18257947ad46fa5d6418a1fd
+C> Response (to server): b9ea99094a176c4be28eb469982066cc7146d180
+
+The client uses the B value to calculate its own copy of the shared secret
+session key, and sends a response to the server proving that it does know
+the correct key.
+
+S> Enter response (from client): b9ea99094a176c4be28eb469982066cc7146d180
+S> Authentication successful.
+S> Response (to client): cd46c839ccad2d0c76f3ca1905ae8ceda8d1c1dc
+
+The server authenticates the client.  (You're in!)
+
+C> Enter server response: cd46c839ccad2d0c76f3ca1905ae8ceda8d1c1dc
+C> Server authentication successful.
+
+The client authenticates the server (prevents server spoofing in the case
+where the session key isn't used to encrypt the channel -- a spoofed server
+might just respond with random values and _pretend_ to authenticate the
+client; but the spoofed server won't know the session key and this check
+catches that).
+
+Final note:
+
+Remember that many breaches of security involve buggy software, such as
+servers susceptible to buffer overflow exploits that totally bypass any
+passphrase, secure or not.  If an attacker roots your client, or the server,
+no form of authentication will work.  Consider MAC-based schemes if this
+worries you.
diff --git a/package/network/services/ead/src/tinysrp/acconfig.h b/package/network/services/ead/src/tinysrp/acconfig.h
new file mode 100644
index 0000000000..b74aed08f3
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/acconfig.h
@@ -0,0 +1,9 @@
+#undef SHA1HANDSOFF
+
+#undef POSIX_TERMIOS
+
+#undef POSIX_SIGTYPE
+
+#undef VERSION
+
+#undef volatile
diff --git a/package/network/services/ead/src/tinysrp/acinclude.m4 b/package/network/services/ead/src/tinysrp/acinclude.m4
new file mode 100644
index 0000000000..e0d0d04df5
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/acinclude.m4
@@ -0,0 +1,27 @@
+dnl
+dnl check for signal type
+dnl
+dnl AC_RETSIGTYPE isn't quite right, but almost.
+dnl
+define(TYPE_SIGNAL,[
+AC_MSG_CHECKING([POSIX signal handlers])
+AC_CACHE_VAL(cv_has_posix_signals,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();], [],
+cv_has_posix_signals=yes, cv_has_posix_signals=no)])
+AC_MSG_RESULT($cv_has_posix_signals)
+if test $cv_has_posix_signals = yes; then
+   AC_DEFINE(RETSIGTYPE, void, [Return type is void])
+   AC_DEFINE(POSIX_SIGTYPE, [], [Have POSIX signals])
+else
+  if test $ac_cv_type_signal = void; then
+     AC_DEFINE(RETSIGTYPE, void, [Return type is void])
+  else
+     AC_DEFINE(RETSIGTYPE, int, [Return type is int])
+  fi
+fi])dnl
diff --git a/package/network/services/ead/src/tinysrp/aclocal.m4 b/package/network/services/ead/src/tinysrp/aclocal.m4
new file mode 100644
index 0000000000..703fce4b77
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/aclocal.m4
@@ -0,0 +1,157 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4a
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+dnl
+dnl check for signal type
+dnl
+dnl AC_RETSIGTYPE isn't quite right, but almost.
+dnl
+define(TYPE_SIGNAL,[
+AC_MSG_CHECKING([POSIX signal handlers])
+AC_CACHE_VAL(cv_has_posix_signals,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();], [],
+cv_has_posix_signals=yes, cv_has_posix_signals=no)])
+AC_MSG_RESULT($cv_has_posix_signals)
+if test $cv_has_posix_signals = yes; then
+   AC_DEFINE(RETSIGTYPE, void, [Return type is void])
+   AC_DEFINE(POSIX_SIGTYPE, [], [Have POSIX signals])
+else
+  if test $ac_cv_type_signal = void; then
+     AC_DEFINE(RETSIGTYPE, void, [Return type is void])
+  else
+     AC_DEFINE(RETSIGTYPE, int, [Return type is int])
+  fi
+fi])dnl
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+dnl We require 2.13 because we rely on SHELL being computed by configure.
+AC_PREREQ([2.13])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
diff --git a/package/network/services/ead/src/tinysrp/bn.h b/package/network/services/ead/src/tinysrp/bn.h
new file mode 100644
index 0000000000..0144dd9617
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn.h
@@ -0,0 +1,471 @@
+/* crypto/bn/bn.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BN_H
+#define HEADER_BN_H
+
+#include <stdio.h> /* FILE */
+#include "config.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef VMS
+#undef BN_LLONG /* experimental, so far... */
+#endif
+
+#undef BN_MUL_COMBA
+#undef BN_SQR_COMBA
+#undef BN_RECURSION
+#undef RECP_MUL_MOD
+#undef MONT_MUL_MOD
+
+#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG_LONG == 8
+# if SIZEOF_LONG == 4
+#  define THIRTY_TWO_BIT
+# else
+#  define SIXTY_FOUR_BIT_LONG
+# endif
+#else
+# if SIZEOF_LONG == 4
+#  define THIRTY_TWO_BIT
+# endif
+#endif
+
+#undef BN_LLONG
+
+/* assuming long is 64bit - this is the DEC Alpha
+ * unsigned long long is only 64 bits :-(, don't define
+ * BN_LLONG for the DEC Alpha */
+#ifdef SIXTY_FOUR_BIT_LONG
+#define BN_ULLONG       unsigned long long
+#define BN_ULONG        unsigned long
+#define BN_LONG         long
+#define BN_BITS         128
+#define BN_BYTES        8
+#define BN_BITS2        64
+#define BN_BITS4        32
+#define BN_MASK         (0xffffffffffffffffffffffffffffffffLL)
+#define BN_MASK2        (0xffffffffffffffffL)
+#define BN_MASK2l       (0xffffffffL)
+#define BN_MASK2h       (0xffffffff00000000L)
+#define BN_MASK2h1      (0xffffffff80000000L)
+#define BN_TBIT         (0x8000000000000000L)
+#define BN_DEC_CONV     (10000000000000000000UL)
+#define BN_DEC_FMT1     "%lu"
+#define BN_DEC_FMT2     "%019lu"
+#define BN_DEC_NUM      19
+#endif
+
+/* This is where the long long data type is 64 bits, but long is 32.
+ * For machines where there are 64bit registers, this is the mode to use.
+ * IRIX, on R4000 and above should use this mode, along with the relevant
+ * assembler code :-).  Do NOT define BN_LLONG.
+ */
+#ifdef SIXTY_FOUR_BIT
+#undef BN_LLONG
+#undef BN_ULLONG
+#define BN_ULONG        unsigned long long
+#define BN_LONG         long long
+#define BN_BITS         128
+#define BN_BYTES        8
+#define BN_BITS2        64
+#define BN_BITS4        32
+#define BN_MASK2        (0xffffffffffffffffLL)
+#define BN_MASK2l       (0xffffffffL)
+#define BN_MASK2h       (0xffffffff00000000LL)
+#define BN_MASK2h1      (0xffffffff80000000LL)
+#define BN_TBIT         (0x8000000000000000LL)
+#define BN_DEC_CONV     (10000000000000000000LL)
+#define BN_DEC_FMT1     "%llu"
+#define BN_DEC_FMT2     "%019llu"
+#define BN_DEC_NUM      19
+#endif
+
+#ifdef THIRTY_TWO_BIT
+#if defined(WIN32) && !defined(__GNUC__)
+#define BN_ULLONG       unsigned _int64
+#else
+#define BN_ULLONG       unsigned long long
+#endif
+#define BN_ULONG        unsigned long
+#define BN_LONG         long
+#define BN_BITS         64
+#define BN_BYTES        4
+#define BN_BITS2        32
+#define BN_BITS4        16
+#ifdef WIN32
+/* VC++ doesn't like the LL suffix */
+#define BN_MASK         (0xffffffffffffffffL)
+#else
+#define BN_MASK         (0xffffffffffffffffLL)
+#endif
+#define BN_MASK2        (0xffffffffL)
+#define BN_MASK2l       (0xffff)
+#define BN_MASK2h1      (0xffff8000L)
+#define BN_MASK2h       (0xffff0000L)
+#define BN_TBIT         (0x80000000L)
+#define BN_DEC_CONV     (1000000000L)
+#define BN_DEC_FMT1     "%lu"
+#define BN_DEC_FMT2     "%09lu"
+#define BN_DEC_NUM      9
+#endif
+
+#ifdef SIXTEEN_BIT
+#ifndef BN_DIV2W
+#define BN_DIV2W
+#endif
+#define BN_ULLONG       unsigned long
+#define BN_ULONG        unsigned short
+#define BN_LONG         short
+#define BN_BITS         32
+#define BN_BYTES        2
+#define BN_BITS2        16
+#define BN_BITS4        8
+#define BN_MASK         (0xffffffff)
+#define BN_MASK2        (0xffff)
+#define BN_MASK2l       (0xff)
+#define BN_MASK2h1      (0xff80)
+#define BN_MASK2h       (0xff00)
+#define BN_TBIT         (0x8000)
+#define BN_DEC_CONV     (100000)
+#define BN_DEC_FMT1     "%u"
+#define BN_DEC_FMT2     "%05u"
+#define BN_DEC_NUM      5
+#endif
+
+#ifdef EIGHT_BIT
+#ifndef BN_DIV2W
+#define BN_DIV2W
+#endif
+#define BN_ULLONG       unsigned short
+#define BN_ULONG        unsigned char
+#define BN_LONG         char
+#define BN_BITS         16
+#define BN_BYTES        1
+#define BN_BITS2        8
+#define BN_BITS4        4
+#define BN_MASK         (0xffff)
+#define BN_MASK2        (0xff)
+#define BN_MASK2l       (0xf)
+#define BN_MASK2h1      (0xf8)
+#define BN_MASK2h       (0xf0)
+#define BN_TBIT         (0x80)
+#define BN_DEC_CONV     (100)
+#define BN_DEC_FMT1     "%u"
+#define BN_DEC_FMT2     "%02u"
+#define BN_DEC_NUM      2
+#endif
+
+#define BN_DEFAULT_BITS 1280
+
+#ifdef BIGNUM
+#undef BIGNUM
+#endif
+
+#define BN_FLG_MALLOCED         0x01
+#define BN_FLG_STATIC_DATA      0x02
+#define BN_FLG_FREE             0x8000  /* used for debuging */
+#define BN_set_flags(b,n)       ((b)->flags|=(n))
+#define BN_get_flags(b,n)       ((b)->flags&(n))
+
+typedef struct bignum_st
+	{
+	BN_ULONG *d;    /* Pointer to an array of 'BN_BITS2' bit chunks. */
+	int top;        /* Index of last used d +1. */
+	/* The next are internal book keeping for bn_expand. */
+	int dmax;       /* Size of the d array. */
+	int neg;        /* one if the number is negative */
+	int flags;
+	} BIGNUM;
+
+/* Used for temp variables */
+#define BN_CTX_NUM      12
+#define BN_CTX_NUM_POS  12
+typedef struct bignum_ctx
+	{
+	int tos;
+	BIGNUM bn[BN_CTX_NUM];
+	int flags;
+	int depth;
+	int pos[BN_CTX_NUM_POS];
+	int too_many;
+	} BN_CTX;
+
+/* Used for montgomery multiplication */
+typedef struct bn_mont_ctx_st
+	{
+	int ri;        /* number of bits in R */
+	BIGNUM RR;     /* used to convert to montgomery form */
+	BIGNUM N;      /* The modulus */
+	BIGNUM Ni;     /* R*(1/R mod N) - N*Ni = 1
+			* (Ni is only stored for bignum algorithm) */
+	BN_ULONG n0;   /* least significant word of Ni */
+	int flags;
+	} BN_MONT_CTX;
+
+/* Used for reciprocal division/mod functions
+ * It cannot be shared between threads
+ */
+typedef struct bn_recp_ctx_st
+	{
+	BIGNUM N;       /* the divisor */
+	BIGNUM Nr;      /* the reciprocal */
+	int num_bits;
+	int shift;
+	int flags;
+	} BN_RECP_CTX;
+
+#define BN_to_montgomery(r,a,mont,ctx)  BN_mod_mul_montgomery(\
+	r,a,&((mont)->RR),(mont),ctx)
+
+#define BN_prime_checks 0 /* default: select number of iterations
+			     based on the size of the number */
+
+/* number of Miller-Rabin iterations for an error rate  of less than 2^-80
+ * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook
+ * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996];
+ * original paper: Damgaard, Landrock, Pomerance: Average case error estimates
+ * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */
+#define BN_prime_checks_for_size(b) ((b) >= 1300 ?  2 : \
+				(b) >=  850 ?  3 : \
+				(b) >=  650 ?  4 : \
+				(b) >=  550 ?  5 : \
+				(b) >=  450 ?  6 : \
+				(b) >=  400 ?  7 : \
+				(b) >=  350 ?  8 : \
+				(b) >=  300 ?  9 : \
+				(b) >=  250 ? 12 : \
+				(b) >=  200 ? 15 : \
+				(b) >=  150 ? 18 : \
+				/* b >= 100 */ 27)
+
+#define BN_num_bytes(a) ((BN_num_bits(a)+7)/8)
+#define BN_is_word(a,w) (((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w)))
+#define BN_is_zero(a)   (((a)->top == 0) || BN_is_word(a,0))
+#define BN_is_one(a)    (BN_is_word((a),1))
+#define BN_is_odd(a)    (((a)->top > 0) && ((a)->d[0] & 1))
+#define BN_one(a)       (BN_set_word((a),1))
+#define BN_zero(a)      (BN_set_word((a),0))
+
+BIGNUM *BN_value_one(void);
+char *  BN_options(void);
+BN_CTX *BN_CTX_new(void);
+void    BN_CTX_init(BN_CTX *c);
+void    BN_CTX_free(BN_CTX *c);
+void    BN_CTX_start(BN_CTX *ctx);
+BIGNUM *BN_CTX_get(BN_CTX *ctx);
+void    BN_CTX_end(BN_CTX *ctx);
+int     BN_rand(BIGNUM *rnd, int bits, int top,int bottom);
+int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom);
+int     BN_num_bits(const BIGNUM *a);
+int     BN_num_bits_word(BN_ULONG);
+BIGNUM *BN_new(void);
+void    BN_init(BIGNUM *);
+void    BN_clear_free(BIGNUM *a);
+BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b);
+BIGNUM *BN_bin2bn(const unsigned char *s,int len,BIGNUM *ret);
+int     BN_bn2bin(const BIGNUM *a, unsigned char *to);
+int     BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int     BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int     BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int     BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int     BN_mod(BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx);
+int     BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
+	       BN_CTX *ctx);
+int     BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
+int     BN_sqr(BIGNUM *r, BIGNUM *a,BN_CTX *ctx);
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w);
+BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w);
+int     BN_mul_word(BIGNUM *a, BN_ULONG w);
+int     BN_add_word(BIGNUM *a, BN_ULONG w);
+int     BN_sub_word(BIGNUM *a, BN_ULONG w);
+int     BN_set_word(BIGNUM *a, BN_ULONG w);
+BN_ULONG BN_get_word(BIGNUM *a);
+int     BN_cmp(const BIGNUM *a, const BIGNUM *b);
+void    BN_free(BIGNUM *a);
+int     BN_is_bit_set(const BIGNUM *a, int n);
+int     BN_lshift(BIGNUM *r, const BIGNUM *a, int n);
+int     BN_lshift1(BIGNUM *r, BIGNUM *a);
+int     BN_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p,BN_CTX *ctx);
+int     BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
+		   const BIGNUM *m,BN_CTX *ctx);
+int     BN_mod_exp_mont(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
+			const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int     BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
+			const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int     BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	const BIGNUM *m,BN_CTX *ctx);
+int     BN_mask_bits(BIGNUM *a,int n);
+int     BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+int     BN_reciprocal(BIGNUM *r, BIGNUM *m, int len, BN_CTX *ctx);
+int     BN_rshift(BIGNUM *r, BIGNUM *a, int n);
+int     BN_rshift1(BIGNUM *r, BIGNUM *a);
+void    BN_clear(BIGNUM *a);
+BIGNUM *BN_dup(const BIGNUM *a);
+int     BN_ucmp(const BIGNUM *a, const BIGNUM *b);
+int     BN_set_bit(BIGNUM *a, int n);
+int     BN_clear_bit(BIGNUM *a, int n);
+int     BN_gcd(BIGNUM *r,BIGNUM *in_a,BIGNUM *in_b,BN_CTX *ctx);
+BIGNUM *BN_mod_inverse(BIGNUM *ret,BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
+BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe,BIGNUM *add,
+		BIGNUM *rem,void (*callback)(int,int,void *),void *cb_arg);
+int     BN_is_prime(const BIGNUM *p,int nchecks,
+		void (*callback)(int,int,void *),
+		BN_CTX *ctx,void *cb_arg);
+int     BN_is_prime_fasttest(const BIGNUM *p,int nchecks,
+		void (*callback)(int,int,void *),BN_CTX *ctx,void *cb_arg,
+		int do_trial_division);
+
+BN_MONT_CTX *BN_MONT_CTX_new(void );
+void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
+int BN_mod_mul_montgomery(BIGNUM *r,BIGNUM *a,BIGNUM *b,BN_MONT_CTX *mont,
+			  BN_CTX *ctx);
+int BN_from_montgomery(BIGNUM *r,BIGNUM *a,BN_MONT_CTX *mont,BN_CTX *ctx);
+void BN_MONT_CTX_free(BN_MONT_CTX *mont);
+int BN_MONT_CTX_set(BN_MONT_CTX *mont,const BIGNUM *modulus,BN_CTX *ctx);
+BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to,BN_MONT_CTX *from);
+
+void BN_set_params(int mul,int high,int low,int mont);
+int BN_get_params(int which); /* 0, mul, 1 high, 2 low, 3 mont */
+
+void    BN_RECP_CTX_init(BN_RECP_CTX *recp);
+BN_RECP_CTX *BN_RECP_CTX_new(void);
+void    BN_RECP_CTX_free(BN_RECP_CTX *recp);
+int     BN_RECP_CTX_set(BN_RECP_CTX *recp,const BIGNUM *rdiv,BN_CTX *ctx);
+int     BN_mod_mul_reciprocal(BIGNUM *r, BIGNUM *x, BIGNUM *y,
+		BN_RECP_CTX *recp,BN_CTX *ctx);
+int     BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+			const BIGNUM *m, BN_CTX *ctx);
+int     BN_div_recp(BIGNUM *dv, BIGNUM *rem, BIGNUM *m,
+		BN_RECP_CTX *recp, BN_CTX *ctx);
+
+/* library internal functions */
+
+#define bn_expand(a,bits) ((((((bits+BN_BITS2-1))/BN_BITS2)) <= (a)->dmax)?\
+	(a):bn_expand2((a),(bits)/BN_BITS2+1))
+#define bn_wexpand(a,words) (((words) <= (a)->dmax)?(a):bn_expand2((a),(words)))
+BIGNUM *bn_expand2(BIGNUM *a, int words);
+
+#define bn_fix_top(a) \
+	{ \
+	BN_ULONG *ftl; \
+	if ((a)->top > 0) \
+		{ \
+		for (ftl= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) \
+		if (*(ftl--)) break; \
+		} \
+	}
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w);
+BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w);
+void     bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num);
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
+BN_ULONG bn_add_words(BN_ULONG *rp, BN_ULONG *ap, BN_ULONG *bp,int num);
+BN_ULONG bn_sub_words(BN_ULONG *rp, BN_ULONG *ap, BN_ULONG *bp,int num);
+
+#ifdef BN_DEBUG
+  void bn_dump1(FILE *o, const char *a, BN_ULONG *b,int n);
+# define bn_print(a) {fprintf(stderr, #a "="); BN_print_fp(stderr,a); \
+   fprintf(stderr,"\n");}
+# define bn_dump(a,n) bn_dump1(stderr,#a,a,n);
+#else
+# define bn_print(a)
+# define bn_dump(a,b)
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+
+/* Error codes for the BN functions. */
+
+/* Function codes. */
+#define BN_F_BN_CTX_GET                                  116
+#define BN_F_BN_CTX_NEW                                  106
+#define BN_F_BN_DIV                                      107
+#define BN_F_BN_EXPAND2                                  108
+#define BN_F_BN_MOD_EXP2_MONT                            118
+#define BN_F_BN_MOD_EXP_MONT                             109
+#define BN_F_BN_MOD_EXP_MONT_WORD                        117
+#define BN_F_BN_MOD_INVERSE                              110
+#define BN_F_BN_MOD_MUL_RECIPROCAL                       111
+#define BN_F_BN_MPI2BN                                   112
+#define BN_F_BN_NEW                                      113
+#define BN_F_BN_RAND                                     114
+#define BN_F_BN_USUB                                     115
+
+/* Reason codes. */
+#define BN_R_ARG2_LT_ARG3                                100
+#define BN_R_BAD_RECIPROCAL                              101
+#define BN_R_CALLED_WITH_EVEN_MODULUS                    102
+#define BN_R_DIV_BY_ZERO                                 103
+#define BN_R_ENCODING_ERROR                              104
+#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA                105
+#define BN_R_INVALID_LENGTH                              106
+#define BN_R_NOT_INITIALIZED                             107
+#define BN_R_NO_INVERSE                                  108
+#define BN_R_TOO_MANY_TEMPORARY_VARIABLES                109
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
diff --git a/package/network/services/ead/src/tinysrp/bn_add.c b/package/network/services/ead/src/tinysrp/bn_add.c
new file mode 100644
index 0000000000..aae4f2b938
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_add.c
@@ -0,0 +1,305 @@
+/* crypto/bn/bn_add.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "bn_lcl.h"
+
+/* r can == a or b */
+int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
+	{
+	const BIGNUM *tmp;
+
+	bn_check_top(a);
+	bn_check_top(b);
+
+	/*  a +  b      a+b
+	 *  a + -b      a-b
+	 * -a +  b      b-a
+	 * -a + -b      -(a+b)
+	 */
+	if (a->neg ^ b->neg)
+		{
+		/* only one is negative */
+		if (a->neg)
+			{ tmp=a; a=b; b=tmp; }
+
+		/* we are now a - b */
+
+		if (BN_ucmp(a,b) < 0)
+			{
+			if (!BN_usub(r,b,a)) return(0);
+			r->neg=1;
+			}
+		else
+			{
+			if (!BN_usub(r,a,b)) return(0);
+			r->neg=0;
+			}
+		return(1);
+		}
+
+	if (a->neg) /* both are neg */
+		r->neg=1;
+	else
+		r->neg=0;
+
+	if (!BN_uadd(r,a,b)) return(0);
+	return(1);
+	}
+
+/* unsigned add of b to a, r must be large enough */
+int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
+	{
+	register int i;
+	int max,min;
+	BN_ULONG *ap,*bp,*rp,carry,t1;
+	const BIGNUM *tmp;
+
+	bn_check_top(a);
+	bn_check_top(b);
+
+	if (a->top < b->top)
+		{ tmp=a; a=b; b=tmp; }
+	max=a->top;
+	min=b->top;
+
+	if (bn_wexpand(r,max+1) == NULL)
+		return(0);
+
+	r->top=max;
+
+
+	ap=a->d;
+	bp=b->d;
+	rp=r->d;
+	carry=0;
+
+	carry=bn_add_words(rp,ap,bp,min);
+	rp+=min;
+	ap+=min;
+	bp+=min;
+	i=min;
+
+	if (carry)
+		{
+		while (i < max)
+			{
+			i++;
+			t1= *(ap++);
+			if ((*(rp++)=(t1+1)&BN_MASK2) >= t1)
+				{
+				carry=0;
+				break;
+				}
+			}
+		if ((i >= max) && carry)
+			{
+			*(rp++)=1;
+			r->top++;
+			}
+		}
+	if (rp != ap)
+		{
+		for (; i<max; i++)
+			*(rp++)= *(ap++);
+		}
+	/* memcpy(rp,ap,sizeof(*ap)*(max-i));*/
+	return(1);
+	}
+
+/* unsigned subtraction of b from a, a must be larger than b. */
+int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
+	{
+	int max,min;
+	register BN_ULONG t1,t2,*ap,*bp,*rp;
+	int i,carry;
+#if defined(IRIX_CC_BUG) && !defined(LINT)
+	int dummy;
+#endif
+
+	bn_check_top(a);
+	bn_check_top(b);
+
+	if (a->top < b->top) /* hmm... should not be happening */
+		{
+		return(0);
+		}
+
+	max=a->top;
+	min=b->top;
+	if (bn_wexpand(r,max) == NULL) return(0);
+
+	ap=a->d;
+	bp=b->d;
+	rp=r->d;
+
+#if 1
+	carry=0;
+	for (i=0; i<min; i++)
+		{
+		t1= *(ap++);
+		t2= *(bp++);
+		if (carry)
+			{
+			carry=(t1 <= t2);
+			t1=(t1-t2-1)&BN_MASK2;
+			}
+		else
+			{
+			carry=(t1 < t2);
+			t1=(t1-t2)&BN_MASK2;
+			}
+#if defined(IRIX_CC_BUG) && !defined(LINT)
+		dummy=t1;
+#endif
+		*(rp++)=t1&BN_MASK2;
+		}
+#else
+	carry=bn_sub_words(rp,ap,bp,min);
+	ap+=min;
+	bp+=min;
+	rp+=min;
+	i=min;
+#endif
+	if (carry) /* subtracted */
+		{
+		while (i < max)
+			{
+			i++;
+			t1= *(ap++);
+			t2=(t1-1)&BN_MASK2;
+			*(rp++)=t2;
+			if (t1 > t2) break;
+			}
+		}
+#if 0
+	memcpy(rp,ap,sizeof(*rp)*(max-i));
+#else
+	if (rp != ap)
+		{
+		for (;;)
+			{
+			if (i++ >= max) break;
+			rp[0]=ap[0];
+			if (i++ >= max) break;
+			rp[1]=ap[1];
+			if (i++ >= max) break;
+			rp[2]=ap[2];
+			if (i++ >= max) break;
+			rp[3]=ap[3];
+			rp+=4;
+			ap+=4;
+			}
+		}
+#endif
+
+	r->top=max;
+	bn_fix_top(r);
+	return(1);
+	}
+
+int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)
+	{
+	int max;
+	int add=0,neg=0;
+	const BIGNUM *tmp;
+
+	bn_check_top(a);
+	bn_check_top(b);
+
+	/*  a -  b      a-b
+	 *  a - -b      a+b
+	 * -a -  b      -(a+b)
+	 * -a - -b      b-a
+	 */
+	if (a->neg)
+		{
+		if (b->neg)
+			{ tmp=a; a=b; b=tmp; }
+		else
+			{ add=1; neg=1; }
+		}
+	else
+		{
+		if (b->neg) { add=1; neg=0; }
+		}
+
+	if (add)
+		{
+		if (!BN_uadd(r,a,b)) return(0);
+		r->neg=neg;
+		return(1);
+		}
+
+	/* We are actually doing a - b :-) */
+
+	max=(a->top > b->top)?a->top:b->top;
+	if (bn_wexpand(r,max) == NULL) return(0);
+	if (BN_ucmp(a,b) < 0)
+		{
+		if (!BN_usub(r,b,a)) return(0);
+		r->neg=1;
+		}
+	else
+		{
+		if (!BN_usub(r,a,b)) return(0);
+		r->neg=0;
+		}
+	return(1);
+	}
+
diff --git a/package/network/services/ead/src/tinysrp/bn_asm.c b/package/network/services/ead/src/tinysrp/bn_asm.c
new file mode 100644
index 0000000000..b24c9af7c4
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_asm.c
@@ -0,0 +1,382 @@
+/* crypto/bn/bn_asm.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef BN_DEBUG
+# undef NDEBUG /* avoid conflicting definitions */
+# define NDEBUG
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include "bn_lcl.h"
+
+#if defined(BN_LLONG) || defined(BN_UMULT_HIGH)
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
+	{
+	BN_ULONG c1=0;
+
+	assert(num >= 0);
+	if (num <= 0) return(c1);
+
+	while (num&~3)
+		{
+		mul_add(rp[0],ap[0],w,c1);
+		mul_add(rp[1],ap[1],w,c1);
+		mul_add(rp[2],ap[2],w,c1);
+		mul_add(rp[3],ap[3],w,c1);
+		ap+=4; rp+=4; num-=4;
+		}
+	if (num)
+		{
+		mul_add(rp[0],ap[0],w,c1); if (--num==0) return c1;
+		mul_add(rp[1],ap[1],w,c1); if (--num==0) return c1;
+		mul_add(rp[2],ap[2],w,c1); return c1;
+		}
+
+	return(c1);
+	}
+
+BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
+	{
+	BN_ULONG c1=0;
+
+	assert(num >= 0);
+	if (num <= 0) return(c1);
+
+	while (num&~3)
+		{
+		mul(rp[0],ap[0],w,c1);
+		mul(rp[1],ap[1],w,c1);
+		mul(rp[2],ap[2],w,c1);
+		mul(rp[3],ap[3],w,c1);
+		ap+=4; rp+=4; num-=4;
+		}
+	if (num)
+		{
+		mul(rp[0],ap[0],w,c1); if (--num == 0) return c1;
+		mul(rp[1],ap[1],w,c1); if (--num == 0) return c1;
+		mul(rp[2],ap[2],w,c1);
+		}
+	return(c1);
+	}
+
+void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
+	{
+	assert(n >= 0);
+	if (n <= 0) return;
+	while (n&~3)
+		{
+		sqr(r[0],r[1],a[0]);
+		sqr(r[2],r[3],a[1]);
+		sqr(r[4],r[5],a[2]);
+		sqr(r[6],r[7],a[3]);
+		a+=4; r+=8; n-=4;
+		}
+	if (n)
+		{
+		sqr(r[0],r[1],a[0]); if (--n == 0) return;
+		sqr(r[2],r[3],a[1]); if (--n == 0) return;
+		sqr(r[4],r[5],a[2]);
+		}
+	}
+
+#else /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
+	{
+	BN_ULONG c=0;
+	BN_ULONG bl,bh;
+
+	assert(num >= 0);
+	if (num <= 0) return((BN_ULONG)0);
+
+	bl=LBITS(w);
+	bh=HBITS(w);
+
+	for (;;)
+		{
+		mul_add(rp[0],ap[0],bl,bh,c);
+		if (--num == 0) break;
+		mul_add(rp[1],ap[1],bl,bh,c);
+		if (--num == 0) break;
+		mul_add(rp[2],ap[2],bl,bh,c);
+		if (--num == 0) break;
+		mul_add(rp[3],ap[3],bl,bh,c);
+		if (--num == 0) break;
+		ap+=4;
+		rp+=4;
+		}
+	return(c);
+	}
+
+BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
+	{
+	BN_ULONG carry=0;
+	BN_ULONG bl,bh;
+
+	assert(num >= 0);
+	if (num <= 0) return((BN_ULONG)0);
+
+	bl=LBITS(w);
+	bh=HBITS(w);
+
+	for (;;)
+		{
+		mul(rp[0],ap[0],bl,bh,carry);
+		if (--num == 0) break;
+		mul(rp[1],ap[1],bl,bh,carry);
+		if (--num == 0) break;
+		mul(rp[2],ap[2],bl,bh,carry);
+		if (--num == 0) break;
+		mul(rp[3],ap[3],bl,bh,carry);
+		if (--num == 0) break;
+		ap+=4;
+		rp+=4;
+		}
+	return(carry);
+	}
+
+void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
+	{
+	assert(n >= 0);
+	if (n <= 0) return;
+	for (;;)
+		{
+		sqr64(r[0],r[1],a[0]);
+		if (--n == 0) break;
+
+		sqr64(r[2],r[3],a[1]);
+		if (--n == 0) break;
+
+		sqr64(r[4],r[5],a[2]);
+		if (--n == 0) break;
+
+		sqr64(r[6],r[7],a[3]);
+		if (--n == 0) break;
+
+		a+=4;
+		r+=8;
+		}
+	}
+
+#endif /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */
+
+#if defined(BN_LLONG) && defined(BN_DIV2W)
+
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
+	{
+	return((BN_ULONG)(((((BN_ULLONG)h)<<BN_BITS2)|l)/(BN_ULLONG)d));
+	}
+
+#else
+
+/* Divide h,l by d and return the result. */
+/* I need to test this some more :-( */
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
+	{
+	BN_ULONG dh,dl,q,ret=0,th,tl,t;
+	int i,count=2;
+
+	if (d == 0) return(BN_MASK2);
+
+	i=BN_num_bits_word(d);
+	assert((i == BN_BITS2) || (h > (BN_ULONG)1<<i));
+
+	i=BN_BITS2-i;
+	if (h >= d) h-=d;
+
+	if (i)
+		{
+		d<<=i;
+		h=(h<<i)|(l>>(BN_BITS2-i));
+		l<<=i;
+		}
+	dh=(d&BN_MASK2h)>>BN_BITS4;
+	dl=(d&BN_MASK2l);
+	for (;;)
+		{
+		if ((h>>BN_BITS4) == dh)
+			q=BN_MASK2l;
+		else
+			q=h/dh;
+
+		th=q*dh;
+		tl=dl*q;
+		for (;;)
+			{
+			t=h-th;
+			if ((t&BN_MASK2h) ||
+				((tl) <= (
+					(t<<BN_BITS4)|
+					((l&BN_MASK2h)>>BN_BITS4))))
+				break;
+			q--;
+			th-=dh;
+			tl-=dl;
+			}
+		t=(tl>>BN_BITS4);
+		tl=(tl<<BN_BITS4)&BN_MASK2h;
+		th+=t;
+
+		if (l < tl) th++;
+		l-=tl;
+		if (h < th)
+			{
+			h+=d;
+			q--;
+			}
+		h-=th;
+
+		if (--count == 0) break;
+
+		ret=q<<BN_BITS4;
+		h=((h<<BN_BITS4)|(l>>BN_BITS4))&BN_MASK2;
+		l=(l&BN_MASK2l)<<BN_BITS4;
+		}
+	ret|=q;
+	return(ret);
+	}
+#endif /* !defined(BN_LLONG) && defined(BN_DIV2W) */
+
+#ifdef BN_LLONG
+BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
+	{
+	BN_ULLONG ll=0;
+
+	assert(n >= 0);
+	if (n <= 0) return((BN_ULONG)0);
+
+	for (;;)
+		{
+		ll+=(BN_ULLONG)a[0]+b[0];
+		r[0]=(BN_ULONG)ll&BN_MASK2;
+		ll>>=BN_BITS2;
+		if (--n <= 0) break;
+
+		ll+=(BN_ULLONG)a[1]+b[1];
+		r[1]=(BN_ULONG)ll&BN_MASK2;
+		ll>>=BN_BITS2;
+		if (--n <= 0) break;
+
+		ll+=(BN_ULLONG)a[2]+b[2];
+		r[2]=(BN_ULONG)ll&BN_MASK2;
+		ll>>=BN_BITS2;
+		if (--n <= 0) break;
+
+		ll+=(BN_ULLONG)a[3]+b[3];
+		r[3]=(BN_ULONG)ll&BN_MASK2;
+		ll>>=BN_BITS2;
+		if (--n <= 0) break;
+
+		a+=4;
+		b+=4;
+		r+=4;
+		}
+	return((BN_ULONG)ll);
+	}
+#else /* !BN_LLONG */
+BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
+	{
+	BN_ULONG c,l,t;
+
+	assert(n >= 0);
+	if (n <= 0) return((BN_ULONG)0);
+
+	c=0;
+	for (;;)
+		{
+		t=a[0];
+		t=(t+c)&BN_MASK2;
+		c=(t < c);
+		l=(t+b[0])&BN_MASK2;
+		c+=(l < t);
+		r[0]=l;
+		if (--n <= 0) break;
+
+		t=a[1];
+		t=(t+c)&BN_MASK2;
+		c=(t < c);
+		l=(t+b[1])&BN_MASK2;
+		c+=(l < t);
+		r[1]=l;
+		if (--n <= 0) break;
+
+		t=a[2];
+		t=(t+c)&BN_MASK2;
+		c=(t < c);
+		l=(t+b[2])&BN_MASK2;
+		c+=(l < t);
+		r[2]=l;
+		if (--n <= 0) break;
+
+		t=a[3];
+		t=(t+c)&BN_MASK2;
+		c=(t < c);
+		l=(t+b[3])&BN_MASK2;
+		c+=(l < t);
+		r[3]=l;
+		if (--n <= 0) break;
+
+		a+=4;
+		b+=4;
+		r+=4;
+		}
+	return((BN_ULONG)c);
+	}
+#endif /* !BN_LLONG */
diff --git a/package/network/services/ead/src/tinysrp/bn_ctx.c b/package/network/services/ead/src/tinysrp/bn_ctx.c
new file mode 100644
index 0000000000..20a6605ab8
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_ctx.c
@@ -0,0 +1,142 @@
+/* crypto/bn/bn_ctx.c */
+/* Written by Ulf Moeller for the OpenSSL project. */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project.  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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef BN_CTX_DEBUG
+# undef NDEBUG /* avoid conflicting definitions */
+# define NDEBUG
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <bn.h>
+
+
+BN_CTX *BN_CTX_new(void)
+	{
+	BN_CTX *ret;
+
+	ret=(BN_CTX *)malloc(sizeof(BN_CTX));
+	if (ret == NULL)
+		{
+		return(NULL);
+		}
+
+	BN_CTX_init(ret);
+	ret->flags=BN_FLG_MALLOCED;
+	return(ret);
+	}
+
+void BN_CTX_init(BN_CTX *ctx)
+	{
+	int i;
+	ctx->tos = 0;
+	ctx->flags = 0;
+	ctx->depth = 0;
+	ctx->too_many = 0;
+	for (i = 0; i < BN_CTX_NUM; i++)
+		BN_init(&(ctx->bn[i]));
+	}
+
+void BN_CTX_free(BN_CTX *ctx)
+	{
+	int i;
+
+	if (ctx == NULL) return;
+	assert(ctx->depth == 0);
+
+	for (i=0; i < BN_CTX_NUM; i++)
+		BN_clear_free(&(ctx->bn[i]));
+	if (ctx->flags & BN_FLG_MALLOCED)
+		free(ctx);
+	}
+
+void BN_CTX_start(BN_CTX *ctx)
+	{
+	if (ctx->depth < BN_CTX_NUM_POS)
+		ctx->pos[ctx->depth] = ctx->tos;
+	ctx->depth++;
+	}
+
+BIGNUM *BN_CTX_get(BN_CTX *ctx)
+	{
+	if (ctx->depth > BN_CTX_NUM_POS || ctx->tos >= BN_CTX_NUM)
+		{
+		if (!ctx->too_many)
+			{
+			/* disable error code until BN_CTX_end is called: */
+			ctx->too_many = 1;
+			}
+		return NULL;
+		}
+	return (&(ctx->bn[ctx->tos++]));
+	}
+
+void BN_CTX_end(BN_CTX *ctx)
+	{
+	if (ctx == NULL) return;
+	assert(ctx->depth > 0);
+	if (ctx->depth == 0)
+		/* should never happen, but we can tolerate it if not in
+		 * debug mode (could be a 'goto err' in the calling function
+		 * before BN_CTX_start was reached) */
+		BN_CTX_start(ctx);
+
+	ctx->too_many = 0;
+	ctx->depth--;
+	if (ctx->depth < BN_CTX_NUM_POS)
+		ctx->tos = ctx->pos[ctx->depth];
+	}
diff --git a/package/network/services/ead/src/tinysrp/bn_div.c b/package/network/services/ead/src/tinysrp/bn_div.c
new file mode 100644
index 0000000000..fd21913d1e
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_div.c
@@ -0,0 +1,378 @@
+/* crypto/bn/bn_div.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "bn_lcl.h"
+
+#define NO_ASM
+
+/* The old slow way */
+#if 0
+int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
+	   BN_CTX *ctx)
+	{
+	int i,nm,nd;
+	int ret = 0;
+	BIGNUM *D;
+
+	bn_check_top(m);
+	bn_check_top(d);
+	if (BN_is_zero(d))
+		{
+		return(0);
+		}
+
+	if (BN_ucmp(m,d) < 0)
+		{
+		if (rem != NULL)
+			{ if (BN_copy(rem,m) == NULL) return(0); }
+		if (dv != NULL) BN_zero(dv);
+		return(1);
+		}
+
+	BN_CTX_start(ctx);
+	D = BN_CTX_get(ctx);
+	if (dv == NULL) dv = BN_CTX_get(ctx);
+	if (rem == NULL) rem = BN_CTX_get(ctx);
+	if (D == NULL || dv == NULL || rem == NULL)
+		goto end;
+
+	nd=BN_num_bits(d);
+	nm=BN_num_bits(m);
+	if (BN_copy(D,d) == NULL) goto end;
+	if (BN_copy(rem,m) == NULL) goto end;
+
+	/* The next 2 are needed so we can do a dv->d[0]|=1 later
+	 * since BN_lshift1 will only work once there is a value :-) */
+	BN_zero(dv);
+	bn_wexpand(dv,1);
+	dv->top=1;
+
+	if (!BN_lshift(D,D,nm-nd)) goto end;
+	for (i=nm-nd; i>=0; i--)
+		{
+		if (!BN_lshift1(dv,dv)) goto end;
+		if (BN_ucmp(rem,D) >= 0)
+			{
+			dv->d[0]|=1;
+			if (!BN_usub(rem,rem,D)) goto end;
+			}
+/* CAN IMPROVE (and have now :=) */
+		if (!BN_rshift1(D,D)) goto end;
+		}
+	rem->neg=BN_is_zero(rem)?0:m->neg;
+	dv->neg=m->neg^d->neg;
+	ret = 1;
+ end:
+	BN_CTX_end(ctx);
+	return(ret);
+	}
+
+#else
+
+#if !defined(NO_ASM) && !defined(NO_INLINE_ASM) && !defined(PEDANTIC) && !defined(BN_DIV3W)
+# if defined(__GNUC__) && __GNUC__>=2
+#  if defined(__i386)
+   /*
+    * There were two reasons for implementing this template:
+    * - GNU C generates a call to a function (__udivdi3 to be exact)
+    *   in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to
+    *   understand why...);
+    * - divl doesn't only calculate quotient, but also leaves
+    *   remainder in %edx which we can definitely use here:-)
+    *
+    *                                   <appro@fy.chalmers.se>
+    */
+#  define bn_div_words(n0,n1,d0)                \
+	({  asm volatile (                      \
+		"divl   %4"                     \
+		: "=a"(q), "=d"(rem)            \
+		: "a"(n1), "d"(n0), "g"(d0)     \
+		: "cc");                        \
+	    q;                                  \
+	})
+#  define REMAINDER_IS_ALREADY_CALCULATED
+#  endif /* __<cpu> */
+# endif /* __GNUC__ */
+#endif /* NO_ASM */
+
+int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
+	   BN_CTX *ctx)
+	{
+	int norm_shift,i,j,loop;
+	BIGNUM *tmp,wnum,*snum,*sdiv,*res;
+	BN_ULONG *resp,*wnump;
+	BN_ULONG d0,d1;
+	int num_n,div_n;
+
+	bn_check_top(num);
+	bn_check_top(divisor);
+
+	if (BN_is_zero(divisor))
+		{
+		return(0);
+		}
+
+	if (BN_ucmp(num,divisor) < 0)
+		{
+		if (rm != NULL)
+			{ if (BN_copy(rm,num) == NULL) return(0); }
+		if (dv != NULL) BN_zero(dv);
+		return(1);
+		}
+
+	BN_CTX_start(ctx);
+	tmp=BN_CTX_get(ctx);
+	tmp->neg=0;
+	snum=BN_CTX_get(ctx);
+	sdiv=BN_CTX_get(ctx);
+	if (dv == NULL)
+		res=BN_CTX_get(ctx);
+	else    res=dv;
+	if (res == NULL) goto err;
+
+	/* First we normalise the numbers */
+	norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2);
+	BN_lshift(sdiv,divisor,norm_shift);
+	sdiv->neg=0;
+	norm_shift+=BN_BITS2;
+	BN_lshift(snum,num,norm_shift);
+	snum->neg=0;
+	div_n=sdiv->top;
+	num_n=snum->top;
+	loop=num_n-div_n;
+
+	/* Lets setup a 'window' into snum
+	 * This is the part that corresponds to the current
+	 * 'area' being divided */
+	BN_init(&wnum);
+	wnum.d=  &(snum->d[loop]);
+	wnum.top= div_n;
+	wnum.dmax= snum->dmax+1; /* a bit of a lie */
+
+	/* Get the top 2 words of sdiv */
+	/* i=sdiv->top; */
+	d0=sdiv->d[div_n-1];
+	d1=(div_n == 1)?0:sdiv->d[div_n-2];
+
+	/* pointer to the 'top' of snum */
+	wnump= &(snum->d[num_n-1]);
+
+	/* Setup to 'res' */
+	res->neg= (num->neg^divisor->neg);
+	if (!bn_wexpand(res,(loop+1))) goto err;
+	res->top=loop;
+	resp= &(res->d[loop-1]);
+
+	/* space for temp */
+	if (!bn_wexpand(tmp,(div_n+1))) goto err;
+
+	if (BN_ucmp(&wnum,sdiv) >= 0)
+		{
+		if (!BN_usub(&wnum,&wnum,sdiv)) goto err;
+		*resp=1;
+		res->d[res->top-1]=1;
+		}
+	else
+		res->top--;
+	resp--;
+
+	for (i=0; i<loop-1; i++)
+		{
+		BN_ULONG q,l0;
+#ifdef BN_DIV3W
+		q=bn_div_3_words(wnump,d1,d0);
+#else
+		BN_ULONG n0,n1,rem=0;
+
+		n0=wnump[0];
+		n1=wnump[-1];
+		if (n0 == d0)
+			q=BN_MASK2;
+		else                    /* n0 < d0 */
+			{
+#ifdef BN_LLONG
+			BN_ULLONG t2;
+
+#if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
+			q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0);
+#else
+			q=bn_div_words(n0,n1,d0);
+#endif
+
+#ifndef REMAINDER_IS_ALREADY_CALCULATED
+			/*
+			 * rem doesn't have to be BN_ULLONG. The least we
+			 * know it's less that d0, isn't it?
+			 */
+			rem=(n1-q*d0)&BN_MASK2;
+#endif
+			t2=(BN_ULLONG)d1*q;
+
+			for (;;)
+				{
+				if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2]))
+					break;
+				q--;
+				rem += d0;
+				if (rem < d0) break; /* don't let rem overflow */
+				t2 -= d1;
+				}
+#else /* !BN_LLONG */
+			BN_ULONG t2l,t2h,ql,qh;
+
+			q=bn_div_words(n0,n1,d0);
+#ifndef REMAINDER_IS_ALREADY_CALCULATED
+			rem=(n1-q*d0)&BN_MASK2;
+#endif
+
+#ifdef BN_UMULT_HIGH
+			t2l = d1 * q;
+			t2h = BN_UMULT_HIGH(d1,q);
+#else
+			t2l=LBITS(d1); t2h=HBITS(d1);
+			ql =LBITS(q);  qh =HBITS(q);
+			mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */
+#endif
+
+			for (;;)
+				{
+				if ((t2h < rem) ||
+					((t2h == rem) && (t2l <= wnump[-2])))
+					break;
+				q--;
+				rem += d0;
+				if (rem < d0) break; /* don't let rem overflow */
+				if (t2l < d1) t2h--; t2l -= d1;
+				}
+#endif /* !BN_LLONG */
+			}
+#endif /* !BN_DIV3W */
+
+		l0=bn_mul_words(tmp->d,sdiv->d,div_n,q);
+		wnum.d--; wnum.top++;
+		tmp->d[div_n]=l0;
+		for (j=div_n+1; j>0; j--)
+			if (tmp->d[j-1]) break;
+		tmp->top=j;
+
+		j=wnum.top;
+		BN_sub(&wnum,&wnum,tmp);
+
+		snum->top=snum->top+wnum.top-j;
+
+		if (wnum.neg)
+			{
+			q--;
+			j=wnum.top;
+			BN_add(&wnum,&wnum,sdiv);
+			snum->top+=wnum.top-j;
+			}
+		*(resp--)=q;
+		wnump--;
+		}
+	if (rm != NULL)
+		{
+		BN_rshift(rm,snum,norm_shift);
+		rm->neg=num->neg;
+		}
+	BN_CTX_end(ctx);
+	return(1);
+err:
+	BN_CTX_end(ctx);
+	return(0);
+	}
+
+#endif
+
+/* rem != m */
+int BN_mod(BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
+	{
+#if 0 /* The old slow way */
+	int i,nm,nd;
+	BIGNUM *dv;
+
+	if (BN_ucmp(m,d) < 0)
+		return((BN_copy(rem,m) == NULL)?0:1);
+
+	BN_CTX_start(ctx);
+	dv=BN_CTX_get(ctx);
+
+	if (!BN_copy(rem,m)) goto err;
+
+	nm=BN_num_bits(rem);
+	nd=BN_num_bits(d);
+	if (!BN_lshift(dv,d,nm-nd)) goto err;
+	for (i=nm-nd; i>=0; i--)
+		{
+		if (BN_cmp(rem,dv) >= 0)
+			{
+			if (!BN_sub(rem,rem,dv)) goto err;
+			}
+		if (!BN_rshift1(dv,dv)) goto err;
+		}
+	BN_CTX_end(ctx);
+	return(1);
+ err:
+	BN_CTX_end(ctx);
+	return(0);
+#else
+	return(BN_div(NULL,rem,m,d,ctx));
+#endif
+	}
+
diff --git a/package/network/services/ead/src/tinysrp/bn_exp.c b/package/network/services/ead/src/tinysrp/bn_exp.c
new file mode 100644
index 0000000000..09afb79f6d
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_exp.c
@@ -0,0 +1,395 @@
+/* crypto/bn/bn_exp.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project.  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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+
+#include <stdio.h>
+#include "bn_lcl.h"
+
+#define TABLE_SIZE      32
+
+/* slow but works */
+int BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
+	{
+	BIGNUM *t;
+	int r=0;
+
+	bn_check_top(a);
+	bn_check_top(b);
+	bn_check_top(m);
+
+	BN_CTX_start(ctx);
+	if ((t = BN_CTX_get(ctx)) == NULL) goto err;
+	if (a == b)
+		{ if (!BN_sqr(t,a,ctx)) goto err; }
+	else
+		{ if (!BN_mul(t,a,b,ctx)) goto err; }
+	if (!BN_mod(ret,t,m,ctx)) goto err;
+	r=1;
+err:
+	BN_CTX_end(ctx);
+	return(r);
+	}
+
+int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
+	       BN_CTX *ctx)
+	{
+	int ret;
+
+	bn_check_top(a);
+	bn_check_top(p);
+	bn_check_top(m);
+
+#ifdef MONT_MUL_MOD
+	/* I have finally been able to take out this pre-condition of
+	 * the top bit being set.  It was caused by an error in BN_div
+	 * with negatives.  There was also another problem when for a^b%m
+	 * a >= m.  eay 07-May-97 */
+/*      if ((m->d[m->top-1]&BN_TBIT) && BN_is_odd(m)) */
+
+	if (BN_is_odd(m))
+		{
+		if (a->top == 1)
+			{
+			BN_ULONG A = a->d[0];
+			ret=BN_mod_exp_mont_word(r,A,p,m,ctx,NULL);
+			}
+		else
+			ret=BN_mod_exp_mont(r,a,p,m,ctx,NULL);
+		}
+	else
+#endif
+#ifdef RECP_MUL_MOD
+		{ ret=BN_mod_exp_recp(r,a,p,m,ctx); }
+#else
+		{ ret=BN_mod_exp_simple(r,a,p,m,ctx); }
+#endif
+
+	return(ret);
+	}
+
+
+#ifdef RECP_MUL_MOD
+int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+		    const BIGNUM *m, BN_CTX *ctx)
+	{
+	int i,j,bits,ret=0,wstart,wend,window,wvalue;
+	int start=1,ts=0;
+	BIGNUM *aa;
+	BIGNUM val[TABLE_SIZE];
+	BN_RECP_CTX recp;
+
+	bits=BN_num_bits(p);
+
+	if (bits == 0)
+		{
+		BN_one(r);
+		return(1);
+		}
+
+	BN_CTX_start(ctx);
+	if ((aa = BN_CTX_get(ctx)) == NULL) goto err;
+
+	BN_RECP_CTX_init(&recp);
+	if (BN_RECP_CTX_set(&recp,m,ctx) <= 0) goto err;
+
+	BN_init(&(val[0]));
+	ts=1;
+
+	if (!BN_mod(&(val[0]),a,m,ctx)) goto err;               /* 1 */
+
+	window = BN_window_bits_for_exponent_size(bits);
+	if (window > 1)
+		{
+		if (!BN_mod_mul_reciprocal(aa,&(val[0]),&(val[0]),&recp,ctx))
+			goto err;                               /* 2 */
+		j=1<<(window-1);
+		for (i=1; i<j; i++)
+			{
+			BN_init(&val[i]);
+			if (!BN_mod_mul_reciprocal(&(val[i]),&(val[i-1]),aa,&recp,ctx))
+				goto err;
+			}
+		ts=i;
+		}
+
+	start=1;        /* This is used to avoid multiplication etc
+			 * when there is only the value '1' in the
+			 * buffer. */
+	wvalue=0;       /* The 'value' of the window */
+	wstart=bits-1;  /* The top bit of the window */
+	wend=0;         /* The bottom bit of the window */
+
+	if (!BN_one(r)) goto err;
+
+	for (;;)
+		{
+		if (BN_is_bit_set(p,wstart) == 0)
+			{
+			if (!start)
+				if (!BN_mod_mul_reciprocal(r,r,r,&recp,ctx))
+				goto err;
+			if (wstart == 0) break;
+			wstart--;
+			continue;
+			}
+		/* We now have wstart on a 'set' bit, we now need to work out
+		 * how bit a window to do.  To do this we need to scan
+		 * forward until the last set bit before the end of the
+		 * window */
+		j=wstart;
+		wvalue=1;
+		wend=0;
+		for (i=1; i<window; i++)
+			{
+			if (wstart-i < 0) break;
+			if (BN_is_bit_set(p,wstart-i))
+				{
+				wvalue<<=(i-wend);
+				wvalue|=1;
+				wend=i;
+				}
+			}
+
+		/* wend is the size of the current window */
+		j=wend+1;
+		/* add the 'bytes above' */
+		if (!start)
+			for (i=0; i<j; i++)
+				{
+				if (!BN_mod_mul_reciprocal(r,r,r,&recp,ctx))
+					goto err;
+				}
+
+		/* wvalue will be an odd number < 2^window */
+		if (!BN_mod_mul_reciprocal(r,r,&(val[wvalue>>1]),&recp,ctx))
+			goto err;
+
+		/* move the 'window' down further */
+		wstart-=wend+1;
+		wvalue=0;
+		start=0;
+		if (wstart < 0) break;
+		}
+	ret=1;
+err:
+	BN_CTX_end(ctx);
+	for (i=0; i<ts; i++)
+		BN_clear_free(&(val[i]));
+	BN_RECP_CTX_free(&recp);
+	return(ret);
+	}
+#else
+
+/* The old fallback, simple version :-) */
+int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	     const BIGNUM *m, BN_CTX *ctx)
+	{
+	int i,j,bits,ret=0,wstart,wend,window,wvalue,ts=0;
+	int start=1;
+	BIGNUM *d;
+	BIGNUM val[TABLE_SIZE];
+
+	bits=BN_num_bits(p);
+
+	if (bits == 0)
+		{
+		BN_one(r);
+		return(1);
+		}
+
+	BN_CTX_start(ctx);
+	if ((d = BN_CTX_get(ctx)) == NULL) goto err;
+
+	BN_init(&(val[0]));
+	ts=1;
+	if (!BN_mod(&(val[0]),a,m,ctx)) goto err;               /* 1 */
+
+	window = BN_window_bits_for_exponent_size(bits);
+	if (window > 1)
+		{
+		if (!BN_mod_mul(d,&(val[0]),&(val[0]),m,ctx))
+			goto err;                               /* 2 */
+		j=1<<(window-1);
+		for (i=1; i<j; i++)
+			{
+			BN_init(&(val[i]));
+			if (!BN_mod_mul(&(val[i]),&(val[i-1]),d,m,ctx))
+				goto err;
+			}
+		ts=i;
+		}
+
+	start=1;        /* This is used to avoid multiplication etc
+			 * when there is only the value '1' in the
+			 * buffer. */
+	wvalue=0;       /* The 'value' of the window */
+	wstart=bits-1;  /* The top bit of the window */
+	wend=0;         /* The bottom bit of the window */
+
+	if (!BN_one(r)) goto err;
+
+	for (;;)
+		{
+		if (BN_is_bit_set(p,wstart) == 0)
+			{
+			if (!start)
+				if (!BN_mod_mul(r,r,r,m,ctx))
+				goto err;
+			if (wstart == 0) break;
+			wstart--;
+			continue;
+			}
+		/* We now have wstart on a 'set' bit, we now need to work out
+		 * how bit a window to do.  To do this we need to scan
+		 * forward until the last set bit before the end of the
+		 * window */
+		j=wstart;
+		wvalue=1;
+		wend=0;
+		for (i=1; i<window; i++)
+			{
+			if (wstart-i < 0) break;
+			if (BN_is_bit_set(p,wstart-i))
+				{
+				wvalue<<=(i-wend);
+				wvalue|=1;
+				wend=i;
+				}
+			}
+
+		/* wend is the size of the current window */
+		j=wend+1;
+		/* add the 'bytes above' */
+		if (!start)
+			for (i=0; i<j; i++)
+				{
+				if (!BN_mod_mul(r,r,r,m,ctx))
+					goto err;
+				}
+
+		/* wvalue will be an odd number < 2^window */
+		if (!BN_mod_mul(r,r,&(val[wvalue>>1]),m,ctx))
+			goto err;
+
+		/* move the 'window' down further */
+		wstart-=wend+1;
+		wvalue=0;
+		start=0;
+		if (wstart < 0) break;
+		}
+	ret=1;
+err:
+	BN_CTX_end(ctx);
+	for (i=0; i<ts; i++)
+		BN_clear_free(&(val[i]));
+	return(ret);
+	}
+#endif
diff --git a/package/network/services/ead/src/tinysrp/bn_lcl.h b/package/network/services/ead/src/tinysrp/bn_lcl.h
new file mode 100644
index 0000000000..129ad658af
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_lcl.h
@@ -0,0 +1,419 @@
+/* crypto/bn/bn_lcl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project.  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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_BN_LCL_H
+#define HEADER_BN_LCL_H
+
+#include <bn.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * BN_window_bits_for_exponent_size -- macro for sliding window mod_exp functions
+ *
+ *
+ * For window size 'w' (w >= 2) and a random 'b' bits exponent,
+ * the number of multiplications is a constant plus on average
+ *
+ *    2^(w-1) + (b-w)/(w+1);
+ *
+ * here  2^(w-1)  is for precomputing the table (we actually need
+ * entries only for windows that have the lowest bit set), and
+ * (b-w)/(w+1)  is an approximation for the expected number of
+ * w-bit windows, not counting the first one.
+ *
+ * Thus we should use
+ *
+ *    w >= 6  if        b > 671
+ *     w = 5  if  671 > b > 239
+ *     w = 4  if  239 > b >  79
+ *     w = 3  if   79 > b >  23
+ *    w <= 2  if   23 > b
+ *
+ * (with draws in between).  Very small exponents are often selected
+ * with low Hamming weight, so we use  w = 1  for b <= 23.
+ */
+#if 1
+#define BN_window_bits_for_exponent_size(b) \
+		((b) > 671 ? 6 : \
+		 (b) > 239 ? 5 : \
+		 (b) >  79 ? 4 : \
+		 (b) >  23 ? 3 : 1)
+#else
+/* Old SSLeay/OpenSSL table.
+ * Maximum window size was 5, so this table differs for b==1024;
+ * but it coincides for other interesting values (b==160, b==512).
+ */
+#define BN_window_bits_for_exponent_size(b) \
+		((b) > 255 ? 5 : \
+		 (b) > 127 ? 4 : \
+		 (b) >  17 ? 3 : 1)
+#endif
+
+
+
+/* Pentium pro 16,16,16,32,64 */
+/* Alpha       16,16,16,16.64 */
+#define BN_MULL_SIZE_NORMAL                     (16) /* 32 */
+#define BN_MUL_RECURSIVE_SIZE_NORMAL            (16) /* 32 less than */
+#define BN_SQR_RECURSIVE_SIZE_NORMAL            (16) /* 32 */
+#define BN_MUL_LOW_RECURSIVE_SIZE_NORMAL        (32) /* 32 */
+#define BN_MONT_CTX_SET_SIZE_WORD               (64) /* 32 */
+
+#if !defined(NO_ASM) && !defined(NO_INLINE_ASM) && !defined(PEDANTIC)
+/*
+ * BN_UMULT_HIGH section.
+ *
+ * No, I'm not trying to overwhelm you when stating that the
+ * product of N-bit numbers is 2*N bits wide:-) No, I don't expect
+ * you to be impressed when I say that if the compiler doesn't
+ * support 2*N integer type, then you have to replace every N*N
+ * multiplication with 4 (N/2)*(N/2) accompanied by some shifts
+ * and additions which unavoidably results in severe performance
+ * penalties. Of course provided that the hardware is capable of
+ * producing 2*N result... That's when you normally start
+ * considering assembler implementation. However! It should be
+ * pointed out that some CPUs (most notably Alpha, PowerPC and
+ * upcoming IA-64 family:-) provide *separate* instruction
+ * calculating the upper half of the product placing the result
+ * into a general purpose register. Now *if* the compiler supports
+ * inline assembler, then it's not impossible to implement the
+ * "bignum" routines (and have the compiler optimize 'em)
+ * exhibiting "native" performance in C. That's what BN_UMULT_HIGH
+ * macro is about:-)
+ *
+ *                                      <appro@fy.chalmers.se>
+ */
+# if defined(__alpha) && (defined(SIXTY_FOUR_BIT_LONG) || defined(SIXTY_FOUR_BIT))
+#  if defined(__DECC)
+#   include <c_asm.h>
+#   define BN_UMULT_HIGH(a,b)   (BN_ULONG)asm("umulh %a0,%a1,%v0",(a),(b))
+#  elif defined(__GNUC__)
+#   define BN_UMULT_HIGH(a,b)   ({      \
+	register BN_ULONG ret;          \
+	asm ("umulh     %1,%2,%0"       \
+	     : "=r"(ret)                \
+	     : "r"(a), "r"(b));         \
+	ret;                    })
+#  endif        /* compiler */
+# elif defined(_ARCH_PPC) && defined(__64BIT__) && defined(SIXTY_FOUR_BIT_LONG)
+#  if defined(__GNUC__)
+#   define BN_UMULT_HIGH(a,b)   ({      \
+	register BN_ULONG ret;          \
+	asm ("mulhdu    %0,%1,%2"       \
+	     : "=r"(ret)                \
+	     : "r"(a), "r"(b));         \
+	ret;                    })
+#  endif        /* compiler */
+# endif         /* cpu */
+#endif          /* NO_ASM */
+
+/*************************************************************
+ * Using the long long type
+ */
+#define Lw(t)    (((BN_ULONG)(t))&BN_MASK2)
+#define Hw(t)    (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
+
+/* This is used for internal error checking and is not normally used */
+#ifdef BN_DEBUG
+# include <assert.h>
+# define bn_check_top(a) assert ((a)->top >= 0 && (a)->top <= (a)->dmax);
+#else
+# define bn_check_top(a)
+#endif
+
+/* This macro is to add extra stuff for development checking */
+#ifdef BN_DEBUG
+#define bn_set_max(r) ((r)->max=(r)->top,BN_set_flags((r),BN_FLG_STATIC_DATA))
+#else
+#define bn_set_max(r)
+#endif
+
+/* These macros are used to 'take' a section of a bignum for read only use */
+#define bn_set_low(r,a,n) \
+	{ \
+	(r)->top=((a)->top > (n))?(n):(a)->top; \
+	(r)->d=(a)->d; \
+	(r)->neg=(a)->neg; \
+	(r)->flags|=BN_FLG_STATIC_DATA; \
+	bn_set_max(r); \
+	}
+
+#define bn_set_high(r,a,n) \
+	{ \
+	if ((a)->top > (n)) \
+		{ \
+		(r)->top=(a)->top-n; \
+		(r)->d= &((a)->d[n]); \
+		} \
+	else \
+		(r)->top=0; \
+	(r)->neg=(a)->neg; \
+	(r)->flags|=BN_FLG_STATIC_DATA; \
+	bn_set_max(r); \
+	}
+
+#ifdef BN_LLONG
+#define mul_add(r,a,w,c) { \
+	BN_ULLONG t; \
+	t=(BN_ULLONG)w * (a) + (r) + (c); \
+	(r)= Lw(t); \
+	(c)= Hw(t); \
+	}
+
+#define mul(r,a,w,c) { \
+	BN_ULLONG t; \
+	t=(BN_ULLONG)w * (a) + (c); \
+	(r)= Lw(t); \
+	(c)= Hw(t); \
+	}
+
+#define sqr(r0,r1,a) { \
+	BN_ULLONG t; \
+	t=(BN_ULLONG)(a)*(a); \
+	(r0)=Lw(t); \
+	(r1)=Hw(t); \
+	}
+
+#elif defined(BN_UMULT_HIGH)
+#define mul_add(r,a,w,c) {              \
+	BN_ULONG high,low,ret,tmp=(a);  \
+	ret =  (r);                     \
+	high=  BN_UMULT_HIGH(w,tmp);    \
+	ret += (c);                     \
+	low =  (w) * tmp;               \
+	(c) =  (ret<(c))?1:0;           \
+	(c) += high;                    \
+	ret += low;                     \
+	(c) += (ret<low)?1:0;           \
+	(r) =  ret;                     \
+	}
+
+#define mul(r,a,w,c)    {               \
+	BN_ULONG high,low,ret,ta=(a);   \
+	low =  (w) * ta;                \
+	high=  BN_UMULT_HIGH(w,ta);     \
+	ret =  low + (c);               \
+	(c) =  high;                    \
+	(c) += (ret<low)?1:0;           \
+	(r) =  ret;                     \
+	}
+
+#define sqr(r0,r1,a)    {               \
+	BN_ULONG tmp=(a);               \
+	(r0) = tmp * tmp;               \
+	(r1) = BN_UMULT_HIGH(tmp,tmp);  \
+	}
+
+#else
+/*************************************************************
+ * No long long type
+ */
+
+#define LBITS(a)        ((a)&BN_MASK2l)
+#define HBITS(a)        (((a)>>BN_BITS4)&BN_MASK2l)
+#define L2HBITS(a)      ((BN_ULONG)((a)&BN_MASK2l)<<BN_BITS4)
+
+#define LLBITS(a)       ((a)&BN_MASKl)
+#define LHBITS(a)       (((a)>>BN_BITS2)&BN_MASKl)
+#define LL2HBITS(a)     ((BN_ULLONG)((a)&BN_MASKl)<<BN_BITS2)
+
+#define mul64(l,h,bl,bh) \
+	{ \
+	BN_ULONG m,m1,lt,ht; \
+ \
+	lt=l; \
+	ht=h; \
+	m =(bh)*(lt); \
+	lt=(bl)*(lt); \
+	m1=(bl)*(ht); \
+	ht =(bh)*(ht); \
+	m=(m+m1)&BN_MASK2; if (m < m1) ht+=L2HBITS(1L); \
+	ht+=HBITS(m); \
+	m1=L2HBITS(m); \
+	lt=(lt+m1)&BN_MASK2; if (lt < m1) ht++; \
+	(l)=lt; \
+	(h)=ht; \
+	}
+
+#define sqr64(lo,ho,in) \
+	{ \
+	BN_ULONG l,h,m; \
+ \
+	h=(in); \
+	l=LBITS(h); \
+	h=HBITS(h); \
+	m =(l)*(h); \
+	l*=l; \
+	h*=h; \
+	h+=(m&BN_MASK2h1)>>(BN_BITS4-1); \
+	m =(m&BN_MASK2l)<<(BN_BITS4+1); \
+	l=(l+m)&BN_MASK2; if (l < m) h++; \
+	(lo)=l; \
+	(ho)=h; \
+	}
+
+#define mul_add(r,a,bl,bh,c) { \
+	BN_ULONG l,h; \
+ \
+	h= (a); \
+	l=LBITS(h); \
+	h=HBITS(h); \
+	mul64(l,h,(bl),(bh)); \
+ \
+	/* non-multiply part */ \
+	l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
+	(c)=(r); \
+	l=(l+(c))&BN_MASK2; if (l < (c)) h++; \
+	(c)=h&BN_MASK2; \
+	(r)=l; \
+	}
+
+#define mul(r,a,bl,bh,c) { \
+	BN_ULONG l,h; \
+ \
+	h= (a); \
+	l=LBITS(h); \
+	h=HBITS(h); \
+	mul64(l,h,(bl),(bh)); \
+ \
+	/* non-multiply part */ \
+	l+=(c); if ((l&BN_MASK2) < (c)) h++; \
+	(c)=h&BN_MASK2; \
+	(r)=l&BN_MASK2; \
+	}
+#endif /* !BN_LLONG */
+
+void bn_mul_normal(BN_ULONG *r,BN_ULONG *a,int na,BN_ULONG *b,int nb);
+void bn_mul_comba8(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b);
+void bn_mul_comba4(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b);
+void bn_sqr_normal(BN_ULONG *r, BN_ULONG *a, int n, BN_ULONG *tmp);
+void bn_sqr_comba8(BN_ULONG *r,BN_ULONG *a);
+void bn_sqr_comba4(BN_ULONG *r,BN_ULONG *a);
+int bn_cmp_words(BN_ULONG *a,BN_ULONG *b,int n);
+void bn_mul_recursive(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b,int n2,BN_ULONG *t);
+void bn_mul_part_recursive(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b,
+	int tn, int n,BN_ULONG *t);
+void bn_sqr_recursive(BN_ULONG *r,BN_ULONG *a, int n2, BN_ULONG *t);
+void bn_mul_low_normal(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b, int n);
+void bn_mul_low_recursive(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b,int n2,
+	BN_ULONG *t);
+void bn_mul_high(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b,BN_ULONG *l,int n2,
+	BN_ULONG *t);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/package/network/services/ead/src/tinysrp/bn_lib.c b/package/network/services/ead/src/tinysrp/bn_lib.c
new file mode 100644
index 0000000000..cfa0d75665
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_lib.c
@@ -0,0 +1,576 @@
+/* crypto/bn/bn_lib.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef BN_DEBUG
+# undef NDEBUG /* avoid conflicting definitions */
+# define NDEBUG
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bn_lcl.h"
+
+const char *BN_version="Big Number";
+
+/* For a 32 bit machine
+ * 2 -   4 ==  128
+ * 3 -   8 ==  256
+ * 4 -  16 ==  512
+ * 5 -  32 == 1024
+ * 6 -  64 == 2048
+ * 7 - 128 == 4096
+ * 8 - 256 == 8192
+ */
+static int bn_limit_bits=0;
+static int bn_limit_num=8;        /* (1<<bn_limit_bits) */
+static int bn_limit_bits_low=0;
+static int bn_limit_num_low=8;    /* (1<<bn_limit_bits_low) */
+static int bn_limit_bits_high=0;
+static int bn_limit_num_high=8;   /* (1<<bn_limit_bits_high) */
+static int bn_limit_bits_mont=0;
+static int bn_limit_num_mont=8;   /* (1<<bn_limit_bits_mont) */
+
+int BN_num_bits_word(BN_ULONG l)
+	{
+	static const char bits[256]={
+		0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
+		5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+		6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+		6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+		7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+		7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+		7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+		7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+		};
+
+#if defined(SIXTY_FOUR_BIT_LONG)
+	if (l & 0xffffffff00000000L)
+		{
+		if (l & 0xffff000000000000L)
+			{
+			if (l & 0xff00000000000000L)
+				{
+				return(bits[(int)(l>>56)]+56);
+				}
+			else    return(bits[(int)(l>>48)]+48);
+			}
+		else
+			{
+			if (l & 0x0000ff0000000000L)
+				{
+				return(bits[(int)(l>>40)]+40);
+				}
+			else    return(bits[(int)(l>>32)]+32);
+			}
+		}
+	else
+#else
+#ifdef SIXTY_FOUR_BIT
+	if (l & 0xffffffff00000000LL)
+		{
+		if (l & 0xffff000000000000LL)
+			{
+			if (l & 0xff00000000000000LL)
+				{
+				return(bits[(int)(l>>56)]+56);
+				}
+			else    return(bits[(int)(l>>48)]+48);
+			}
+		else
+			{
+			if (l & 0x0000ff0000000000LL)
+				{
+				return(bits[(int)(l>>40)]+40);
+				}
+			else    return(bits[(int)(l>>32)]+32);
+			}
+		}
+	else
+#endif
+#endif
+		{
+#if defined(THIRTY_TWO_BIT) || defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG)
+		if (l & 0xffff0000L)
+			{
+			if (l & 0xff000000L)
+				return(bits[(int)(l>>24L)]+24);
+			else    return(bits[(int)(l>>16L)]+16);
+			}
+		else
+#endif
+			{
+#if defined(SIXTEEN_BIT) || defined(THIRTY_TWO_BIT) || defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG)
+			if (l & 0xff00L)
+				return(bits[(int)(l>>8)]+8);
+			else
+#endif
+				return(bits[(int)(l   )]  );
+			}
+		}
+	}
+
+int BN_num_bits(const BIGNUM *a)
+	{
+	BN_ULONG l;
+	int i;
+
+	bn_check_top(a);
+
+	if (a->top == 0) return(0);
+	l=a->d[a->top-1];
+	assert(l != 0);
+	i=(a->top-1)*BN_BITS2;
+	return(i+BN_num_bits_word(l));
+	}
+
+void BN_clear_free(BIGNUM *a)
+	{
+	int i;
+
+	if (a == NULL) return;
+	if (a->d != NULL)
+		{
+		memset(a->d,0,a->dmax*sizeof(a->d[0]));
+		if (!(BN_get_flags(a,BN_FLG_STATIC_DATA)))
+			free(a->d);
+		}
+	i=BN_get_flags(a,BN_FLG_MALLOCED);
+	memset(a,0,sizeof(BIGNUM));
+	if (i)
+		free(a);
+	}
+
+void BN_free(BIGNUM *a)
+	{
+	if (a == NULL) return;
+	if ((a->d != NULL) && !(BN_get_flags(a,BN_FLG_STATIC_DATA)))
+		free(a->d);
+	a->flags|=BN_FLG_FREE; /* REMOVE? */
+	if (a->flags & BN_FLG_MALLOCED)
+		free(a);
+	}
+
+void BN_init(BIGNUM *a)
+	{
+	memset(a,0,sizeof(BIGNUM));
+	}
+
+BIGNUM *BN_new(void)
+	{
+	BIGNUM *ret;
+
+	if ((ret=(BIGNUM *)malloc(sizeof(BIGNUM))) == NULL)
+		{
+		return(NULL);
+		}
+	ret->flags=BN_FLG_MALLOCED;
+	ret->top=0;
+	ret->neg=0;
+	ret->dmax=0;
+	ret->d=NULL;
+	return(ret);
+	}
+
+/* This is an internal function that should not be used in applications.
+ * It ensures that 'b' has enough room for a 'words' word number number.
+ * It is mostly used by the various BIGNUM routines. If there is an error,
+ * NULL is returned. If not, 'b' is returned. */
+
+BIGNUM *bn_expand2(BIGNUM *b, int words)
+	{
+	BN_ULONG *A,*a;
+	const BN_ULONG *B;
+	int i;
+
+	bn_check_top(b);
+
+	if (words > b->dmax)
+		{
+		bn_check_top(b);
+		if (BN_get_flags(b,BN_FLG_STATIC_DATA))
+			{
+			return(NULL);
+			}
+		a=A=(BN_ULONG *)malloc(sizeof(BN_ULONG)*(words+1));
+		if (A == NULL)
+			{
+			return(NULL);
+			}
+#if 1
+		B=b->d;
+		/* Check if the previous number needs to be copied */
+		if (B != NULL)
+			{
+#if 0
+			/* This lot is an unrolled loop to copy b->top
+			 * BN_ULONGs from B to A
+			 */
+/*
+ * I have nothing against unrolling but it's usually done for
+ * several reasons, namely:
+ * - minimize percentage of decision making code, i.e. branches;
+ * - avoid cache trashing;
+ * - make it possible to schedule loads earlier;
+ * Now let's examine the code below. The cornerstone of C is
+ * "programmer is always right" and that's what we love it for:-)
+ * For this very reason C compilers have to be paranoid when it
+ * comes to data aliasing and assume the worst. Yeah, but what
+ * does it mean in real life? This means that loop body below will
+ * be compiled to sequence of loads immediately followed by stores
+ * as compiler assumes the worst, something in A==B+1 style. As a
+ * result CPU pipeline is going to starve for incoming data. Secondly
+ * if A and B happen to share same cache line such code is going to
+ * cause severe cache trashing. Both factors have severe impact on
+ * performance of modern CPUs and this is the reason why this
+ * particular piece of code is #ifdefed away and replaced by more
+ * "friendly" version found in #else section below. This comment
+ * also applies to BN_copy function.
+ *
+ *                                      <appro@fy.chalmers.se>
+ */
+			for (i=b->top&(~7); i>0; i-=8)
+				{
+				A[0]=B[0]; A[1]=B[1]; A[2]=B[2]; A[3]=B[3];
+				A[4]=B[4]; A[5]=B[5]; A[6]=B[6]; A[7]=B[7];
+				A+=8;
+				B+=8;
+				}
+			switch (b->top&7)
+				{
+			case 7:
+				A[6]=B[6];
+			case 6:
+				A[5]=B[5];
+			case 5:
+				A[4]=B[4];
+			case 4:
+				A[3]=B[3];
+			case 3:
+				A[2]=B[2];
+			case 2:
+				A[1]=B[1];
+			case 1:
+				A[0]=B[0];
+			case 0:
+				/* I need the 'case 0' entry for utrix cc.
+				 * If the optimizer is turned on, it does the
+				 * switch table by doing
+				 * a=top&7
+				 * a--;
+				 * goto jump_table[a];
+				 * If top is 0, this makes us jump to 0xffffffc
+				 * which is rather bad :-(.
+				 * eric 23-Apr-1998
+				 */
+				;
+				}
+#else
+			for (i=b->top>>2; i>0; i--,A+=4,B+=4)
+				{
+				/*
+				 * The fact that the loop is unrolled
+				 * 4-wise is a tribute to Intel. It's
+				 * the one that doesn't have enough
+				 * registers to accomodate more data.
+				 * I'd unroll it 8-wise otherwise:-)
+				 *
+				 *              <appro@fy.chalmers.se>
+				 */
+				BN_ULONG a0,a1,a2,a3;
+				a0=B[0]; a1=B[1]; a2=B[2]; a3=B[3];
+				A[0]=a0; A[1]=a1; A[2]=a2; A[3]=a3;
+				}
+			switch (b->top&3)
+				{
+				case 3: A[2]=B[2];
+				case 2: A[1]=B[1];
+				case 1: A[0]=B[0];
+				case 0: ; /* ultrix cc workaround, see above */
+				}
+#endif
+			free(b->d);
+			}
+
+		b->d=a;
+		b->dmax=words;
+
+		/* Now need to zero any data between b->top and b->max */
+
+		A= &(b->d[b->top]);
+		for (i=(b->dmax - b->top)>>3; i>0; i--,A+=8)
+			{
+			A[0]=0; A[1]=0; A[2]=0; A[3]=0;
+			A[4]=0; A[5]=0; A[6]=0; A[7]=0;
+			}
+		for (i=(b->dmax - b->top)&7; i>0; i--,A++)
+			A[0]=0;
+#else
+			memset(A,0,sizeof(BN_ULONG)*(words+1));
+			memcpy(A,b->d,sizeof(b->d[0])*b->top);
+			b->d=a;
+			b->max=words;
+#endif
+
+/*              memset(&(p[b->max]),0,((words+1)-b->max)*sizeof(BN_ULONG)); */
+/*      { int i; for (i=b->max; i<words+1; i++) p[i]=i;} */
+
+		}
+	return(b);
+	}
+
+BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
+	{
+	int i;
+	BN_ULONG *A;
+	const BN_ULONG *B;
+
+	bn_check_top(b);
+
+	if (a == b) return(a);
+	if (bn_wexpand(a,b->top) == NULL) return(NULL);
+
+#if 1
+	A=a->d;
+	B=b->d;
+	for (i=b->top>>2; i>0; i--,A+=4,B+=4)
+		{
+		BN_ULONG a0,a1,a2,a3;
+		a0=B[0]; a1=B[1]; a2=B[2]; a3=B[3];
+		A[0]=a0; A[1]=a1; A[2]=a2; A[3]=a3;
+		}
+	switch (b->top&3)
+		{
+		case 3: A[2]=B[2];
+		case 2: A[1]=B[1];
+		case 1: A[0]=B[0];
+		case 0: ; /* ultrix cc workaround, see comments in bn_expand2 */
+		}
+#else
+	memcpy(a->d,b->d,sizeof(b->d[0])*b->top);
+#endif
+
+/*      memset(&(a->d[b->top]),0,sizeof(a->d[0])*(a->max-b->top));*/
+	a->top=b->top;
+	if ((a->top == 0) && (a->d != NULL))
+		a->d[0]=0;
+	a->neg=b->neg;
+	return(a);
+	}
+
+int BN_set_word(BIGNUM *a, BN_ULONG w)
+	{
+	int i,n;
+	if (bn_expand(a,sizeof(BN_ULONG)*8) == NULL) return(0);
+
+	n=sizeof(BN_ULONG)/BN_BYTES;
+	a->neg=0;
+	a->top=0;
+	a->d[0]=(BN_ULONG)w&BN_MASK2;
+	if (a->d[0] != 0) a->top=1;
+	for (i=1; i<n; i++)
+		{
+		/* the following is done instead of
+		 * w>>=BN_BITS2 so compilers don't complain
+		 * on builds where sizeof(long) == BN_TYPES */
+#ifndef SIXTY_FOUR_BIT /* the data item > unsigned long */
+		w>>=BN_BITS4;
+		w>>=BN_BITS4;
+#else
+		w=0;
+#endif
+		a->d[i]=(BN_ULONG)w&BN_MASK2;
+		if (a->d[i] != 0) a->top=i+1;
+		}
+	return(1);
+	}
+
+/* ignore negative */
+BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret)
+	{
+	unsigned int i,m;
+	unsigned int n;
+	BN_ULONG l;
+
+	if (ret == NULL) ret=BN_new();
+	if (ret == NULL) return(NULL);
+	l=0;
+	n=len;
+	if (n == 0)
+		{
+		ret->top=0;
+		return(ret);
+		}
+	if (bn_expand(ret,(int)(n+2)*8) == NULL)
+		return(NULL);
+	i=((n-1)/BN_BYTES)+1;
+	m=((n-1)%(BN_BYTES));
+	ret->top=i;
+	while (n-- > 0)
+		{
+		l=(l<<8L)| *(s++);
+		if (m-- == 0)
+			{
+			ret->d[--i]=l;
+			l=0;
+			m=BN_BYTES-1;
+			}
+		}
+	/* need to call this due to clear byte at top if avoiding
+	 * having the top bit set (-ve number) */
+	bn_fix_top(ret);
+	return(ret);
+	}
+
+/* ignore negative */
+int BN_bn2bin(const BIGNUM *a, unsigned char *to)
+	{
+	int n,i;
+	BN_ULONG l;
+
+	n=i=BN_num_bytes(a);
+	while (i-- > 0)
+		{
+		l=a->d[i/BN_BYTES];
+		*(to++)=(unsigned char)(l>>(8*(i%BN_BYTES)))&0xff;
+		}
+	return(n);
+	}
+
+int BN_ucmp(const BIGNUM *a, const BIGNUM *b)
+	{
+	int i;
+	BN_ULONG t1,t2,*ap,*bp;
+
+	bn_check_top(a);
+	bn_check_top(b);
+
+	i=a->top-b->top;
+	if (i != 0) return(i);
+	ap=a->d;
+	bp=b->d;
+	for (i=a->top-1; i>=0; i--)
+		{
+		t1= ap[i];
+		t2= bp[i];
+		if (t1 != t2)
+			return(t1 > t2?1:-1);
+		}
+	return(0);
+	}
+
+int BN_cmp(const BIGNUM *a, const BIGNUM *b)
+	{
+	int i;
+	int gt,lt;
+	BN_ULONG t1,t2;
+
+	if ((a == NULL) || (b == NULL))
+		{
+		if (a != NULL)
+			return(-1);
+		else if (b != NULL)
+			return(1);
+		else
+			return(0);
+		}
+
+	bn_check_top(a);
+	bn_check_top(b);
+
+	if (a->neg != b->neg)
+		{
+		if (a->neg)
+			return(-1);
+		else    return(1);
+		}
+	if (a->neg == 0)
+		{ gt=1; lt= -1; }
+	else    { gt= -1; lt=1; }
+
+	if (a->top > b->top) return(gt);
+	if (a->top < b->top) return(lt);
+	for (i=a->top-1; i>=0; i--)
+		{
+		t1=a->d[i];
+		t2=b->d[i];
+		if (t1 > t2) return(gt);
+		if (t1 < t2) return(lt);
+		}
+	return(0);
+	}
+
+int BN_is_bit_set(const BIGNUM *a, int n)
+	{
+	int i,j;
+
+	if (n < 0) return(0);
+	i=n/BN_BITS2;
+	j=n%BN_BITS2;
+	if (a->top <= i) return(0);
+	return((a->d[i]&(((BN_ULONG)1)<<j))?1:0);
+	}
diff --git a/package/network/services/ead/src/tinysrp/bn_mul.c b/package/network/services/ead/src/tinysrp/bn_mul.c
new file mode 100644
index 0000000000..92330e5ecf
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_mul.c
@@ -0,0 +1,172 @@
+/* crypto/bn/bn_mul.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "bn_lcl.h"
+
+int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
+	{
+	int top,al,bl;
+	BIGNUM *rr;
+	int ret = 0;
+#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
+	int i;
+#endif
+
+#ifdef BN_COUNT
+	printf("BN_mul %d * %d\n",a->top,b->top);
+#endif
+
+	bn_check_top(a);
+	bn_check_top(b);
+	bn_check_top(r);
+
+	al=a->top;
+	bl=b->top;
+
+	if ((al == 0) || (bl == 0))
+		{
+		BN_zero(r);
+		return(1);
+		}
+	top=al+bl;
+
+	BN_CTX_start(ctx);
+	if ((r == a) || (r == b))
+		{
+		if ((rr = BN_CTX_get(ctx)) == NULL) goto err;
+		}
+	else
+		rr = r;
+	rr->neg=a->neg^b->neg;
+
+#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
+	i = al-bl;
+#endif
+#ifdef BN_MUL_COMBA
+	if (i == 0)
+		{
+# if 0
+		if (al == 4)
+			{
+			if (bn_wexpand(rr,8) == NULL) goto err;
+			rr->top=8;
+			bn_mul_comba4(rr->d,a->d,b->d);
+			goto end;
+			}
+# endif
+		if (al == 8)
+			{
+			if (bn_wexpand(rr,16) == NULL) goto err;
+			rr->top=16;
+			bn_mul_comba8(rr->d,a->d,b->d);
+			goto end;
+			}
+		}
+#endif /* BN_MUL_COMBA */
+	if (bn_wexpand(rr,top) == NULL) goto err;
+	rr->top=top;
+	bn_mul_normal(rr->d,a->d,al,b->d,bl);
+
+#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
+end:
+#endif
+	bn_fix_top(rr);
+	if (r != rr) BN_copy(r,rr);
+	ret=1;
+err:
+	BN_CTX_end(ctx);
+	return(ret);
+	}
+
+void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb)
+	{
+	BN_ULONG *rr;
+
+#ifdef BN_COUNT
+	printf(" bn_mul_normal %d * %d\n",na,nb);
+#endif
+
+	if (na < nb)
+		{
+		int itmp;
+		BN_ULONG *ltmp;
+
+		itmp=na; na=nb; nb=itmp;
+		ltmp=a;   a=b;   b=ltmp;
+
+		}
+	rr= &(r[na]);
+	rr[0]=bn_mul_words(r,a,na,b[0]);
+
+	for (;;)
+		{
+		if (--nb <= 0) return;
+		rr[1]=bn_mul_add_words(&(r[1]),a,na,b[1]);
+		if (--nb <= 0) return;
+		rr[2]=bn_mul_add_words(&(r[2]),a,na,b[2]);
+		if (--nb <= 0) return;
+		rr[3]=bn_mul_add_words(&(r[3]),a,na,b[3]);
+		if (--nb <= 0) return;
+		rr[4]=bn_mul_add_words(&(r[4]),a,na,b[4]);
+		rr+=4;
+		r+=4;
+		b+=4;
+		}
+	}
diff --git a/package/network/services/ead/src/tinysrp/bn_prime.h b/package/network/services/ead/src/tinysrp/bn_prime.h
new file mode 100644
index 0000000000..b7cf9a9bfe
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_prime.h
@@ -0,0 +1,325 @@
+/* Auto generated by bn_prime.pl */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef EIGHT_BIT
+#define NUMPRIMES 2048
+#else
+#define NUMPRIMES 54
+#endif
+static const unsigned int primes[NUMPRIMES]=
+	{
+	   2,   3,   5,   7,  11,  13,  17,  19,
+	  23,  29,  31,  37,  41,  43,  47,  53,
+	  59,  61,  67,  71,  73,  79,  83,  89,
+	  97, 101, 103, 107, 109, 113, 127, 131,
+	 137, 139, 149, 151, 157, 163, 167, 173,
+	 179, 181, 191, 193, 197, 199, 211, 223,
+	 227, 229, 233, 239, 241, 251,
+#ifndef EIGHT_BIT
+	 257, 263,
+	 269, 271, 277, 281, 283, 293, 307, 311,
+	 313, 317, 331, 337, 347, 349, 353, 359,
+	 367, 373, 379, 383, 389, 397, 401, 409,
+	 419, 421, 431, 433, 439, 443, 449, 457,
+	 461, 463, 467, 479, 487, 491, 499, 503,
+	 509, 521, 523, 541, 547, 557, 563, 569,
+	 571, 577, 587, 593, 599, 601, 607, 613,
+	 617, 619, 631, 641, 643, 647, 653, 659,
+	 661, 673, 677, 683, 691, 701, 709, 719,
+	 727, 733, 739, 743, 751, 757, 761, 769,
+	 773, 787, 797, 809, 811, 821, 823, 827,
+	 829, 839, 853, 857, 859, 863, 877, 881,
+	 883, 887, 907, 911, 919, 929, 937, 941,
+	 947, 953, 967, 971, 977, 983, 991, 997,
+	1009,1013,1019,1021,1031,1033,1039,1049,
+	1051,1061,1063,1069,1087,1091,1093,1097,
+	1103,1109,1117,1123,1129,1151,1153,1163,
+	1171,1181,1187,1193,1201,1213,1217,1223,
+	1229,1231,1237,1249,1259,1277,1279,1283,
+	1289,1291,1297,1301,1303,1307,1319,1321,
+	1327,1361,1367,1373,1381,1399,1409,1423,
+	1427,1429,1433,1439,1447,1451,1453,1459,
+	1471,1481,1483,1487,1489,1493,1499,1511,
+	1523,1531,1543,1549,1553,1559,1567,1571,
+	1579,1583,1597,1601,1607,1609,1613,1619,
+	1621,1627,1637,1657,1663,1667,1669,1693,
+	1697,1699,1709,1721,1723,1733,1741,1747,
+	1753,1759,1777,1783,1787,1789,1801,1811,
+	1823,1831,1847,1861,1867,1871,1873,1877,
+	1879,1889,1901,1907,1913,1931,1933,1949,
+	1951,1973,1979,1987,1993,1997,1999,2003,
+	2011,2017,2027,2029,2039,2053,2063,2069,
+	2081,2083,2087,2089,2099,2111,2113,2129,
+	2131,2137,2141,2143,2153,2161,2179,2203,
+	2207,2213,2221,2237,2239,2243,2251,2267,
+	2269,2273,2281,2287,2293,2297,2309,2311,
+	2333,2339,2341,2347,2351,2357,2371,2377,
+	2381,2383,2389,2393,2399,2411,2417,2423,
+	2437,2441,2447,2459,2467,2473,2477,2503,
+	2521,2531,2539,2543,2549,2551,2557,2579,
+	2591,2593,2609,2617,2621,2633,2647,2657,
+	2659,2663,2671,2677,2683,2687,2689,2693,
+	2699,2707,2711,2713,2719,2729,2731,2741,
+	2749,2753,2767,2777,2789,2791,2797,2801,
+	2803,2819,2833,2837,2843,2851,2857,2861,
+	2879,2887,2897,2903,2909,2917,2927,2939,
+	2953,2957,2963,2969,2971,2999,3001,3011,
+	3019,3023,3037,3041,3049,3061,3067,3079,
+	3083,3089,3109,3119,3121,3137,3163,3167,
+	3169,3181,3187,3191,3203,3209,3217,3221,
+	3229,3251,3253,3257,3259,3271,3299,3301,
+	3307,3313,3319,3323,3329,3331,3343,3347,
+	3359,3361,3371,3373,3389,3391,3407,3413,
+	3433,3449,3457,3461,3463,3467,3469,3491,
+	3499,3511,3517,3527,3529,3533,3539,3541,
+	3547,3557,3559,3571,3581,3583,3593,3607,
+	3613,3617,3623,3631,3637,3643,3659,3671,
+	3673,3677,3691,3697,3701,3709,3719,3727,
+	3733,3739,3761,3767,3769,3779,3793,3797,
+	3803,3821,3823,3833,3847,3851,3853,3863,
+	3877,3881,3889,3907,3911,3917,3919,3923,
+	3929,3931,3943,3947,3967,3989,4001,4003,
+	4007,4013,4019,4021,4027,4049,4051,4057,
+	4073,4079,4091,4093,4099,4111,4127,4129,
+	4133,4139,4153,4157,4159,4177,4201,4211,
+	4217,4219,4229,4231,4241,4243,4253,4259,
+	4261,4271,4273,4283,4289,4297,4327,4337,
+	4339,4349,4357,4363,4373,4391,4397,4409,
+	4421,4423,4441,4447,4451,4457,4463,4481,
+	4483,4493,4507,4513,4517,4519,4523,4547,
+	4549,4561,4567,4583,4591,4597,4603,4621,
+	4637,4639,4643,4649,4651,4657,4663,4673,
+	4679,4691,4703,4721,4723,4729,4733,4751,
+	4759,4783,4787,4789,4793,4799,4801,4813,
+	4817,4831,4861,4871,4877,4889,4903,4909,
+	4919,4931,4933,4937,4943,4951,4957,4967,
+	4969,4973,4987,4993,4999,5003,5009,5011,
+	5021,5023,5039,5051,5059,5077,5081,5087,
+	5099,5101,5107,5113,5119,5147,5153,5167,
+	5171,5179,5189,5197,5209,5227,5231,5233,
+	5237,5261,5273,5279,5281,5297,5303,5309,
+	5323,5333,5347,5351,5381,5387,5393,5399,
+	5407,5413,5417,5419,5431,5437,5441,5443,
+	5449,5471,5477,5479,5483,5501,5503,5507,
+	5519,5521,5527,5531,5557,5563,5569,5573,
+	5581,5591,5623,5639,5641,5647,5651,5653,
+	5657,5659,5669,5683,5689,5693,5701,5711,
+	5717,5737,5741,5743,5749,5779,5783,5791,
+	5801,5807,5813,5821,5827,5839,5843,5849,
+	5851,5857,5861,5867,5869,5879,5881,5897,
+	5903,5923,5927,5939,5953,5981,5987,6007,
+	6011,6029,6037,6043,6047,6053,6067,6073,
+	6079,6089,6091,6101,6113,6121,6131,6133,
+	6143,6151,6163,6173,6197,6199,6203,6211,
+	6217,6221,6229,6247,6257,6263,6269,6271,
+	6277,6287,6299,6301,6311,6317,6323,6329,
+	6337,6343,6353,6359,6361,6367,6373,6379,
+	6389,6397,6421,6427,6449,6451,6469,6473,
+	6481,6491,6521,6529,6547,6551,6553,6563,
+	6569,6571,6577,6581,6599,6607,6619,6637,
+	6653,6659,6661,6673,6679,6689,6691,6701,
+	6703,6709,6719,6733,6737,6761,6763,6779,
+	6781,6791,6793,6803,6823,6827,6829,6833,
+	6841,6857,6863,6869,6871,6883,6899,6907,
+	6911,6917,6947,6949,6959,6961,6967,6971,
+	6977,6983,6991,6997,7001,7013,7019,7027,
+	7039,7043,7057,7069,7079,7103,7109,7121,
+	7127,7129,7151,7159,7177,7187,7193,7207,
+	7211,7213,7219,7229,7237,7243,7247,7253,
+	7283,7297,7307,7309,7321,7331,7333,7349,
+	7351,7369,7393,7411,7417,7433,7451,7457,
+	7459,7477,7481,7487,7489,7499,7507,7517,
+	7523,7529,7537,7541,7547,7549,7559,7561,
+	7573,7577,7583,7589,7591,7603,7607,7621,
+	7639,7643,7649,7669,7673,7681,7687,7691,
+	7699,7703,7717,7723,7727,7741,7753,7757,
+	7759,7789,7793,7817,7823,7829,7841,7853,
+	7867,7873,7877,7879,7883,7901,7907,7919,
+	7927,7933,7937,7949,7951,7963,7993,8009,
+	8011,8017,8039,8053,8059,8069,8081,8087,
+	8089,8093,8101,8111,8117,8123,8147,8161,
+	8167,8171,8179,8191,8209,8219,8221,8231,
+	8233,8237,8243,8263,8269,8273,8287,8291,
+	8293,8297,8311,8317,8329,8353,8363,8369,
+	8377,8387,8389,8419,8423,8429,8431,8443,
+	8447,8461,8467,8501,8513,8521,8527,8537,
+	8539,8543,8563,8573,8581,8597,8599,8609,
+	8623,8627,8629,8641,8647,8663,8669,8677,
+	8681,8689,8693,8699,8707,8713,8719,8731,
+	8737,8741,8747,8753,8761,8779,8783,8803,
+	8807,8819,8821,8831,8837,8839,8849,8861,
+	8863,8867,8887,8893,8923,8929,8933,8941,
+	8951,8963,8969,8971,8999,9001,9007,9011,
+	9013,9029,9041,9043,9049,9059,9067,9091,
+	9103,9109,9127,9133,9137,9151,9157,9161,
+	9173,9181,9187,9199,9203,9209,9221,9227,
+	9239,9241,9257,9277,9281,9283,9293,9311,
+	9319,9323,9337,9341,9343,9349,9371,9377,
+	9391,9397,9403,9413,9419,9421,9431,9433,
+	9437,9439,9461,9463,9467,9473,9479,9491,
+	9497,9511,9521,9533,9539,9547,9551,9587,
+	9601,9613,9619,9623,9629,9631,9643,9649,
+	9661,9677,9679,9689,9697,9719,9721,9733,
+	9739,9743,9749,9767,9769,9781,9787,9791,
+	9803,9811,9817,9829,9833,9839,9851,9857,
+	9859,9871,9883,9887,9901,9907,9923,9929,
+	9931,9941,9949,9967,9973,10007,10009,10037,
+	10039,10061,10067,10069,10079,10091,10093,10099,
+	10103,10111,10133,10139,10141,10151,10159,10163,
+	10169,10177,10181,10193,10211,10223,10243,10247,
+	10253,10259,10267,10271,10273,10289,10301,10303,
+	10313,10321,10331,10333,10337,10343,10357,10369,
+	10391,10399,10427,10429,10433,10453,10457,10459,
+	10463,10477,10487,10499,10501,10513,10529,10531,
+	10559,10567,10589,10597,10601,10607,10613,10627,
+	10631,10639,10651,10657,10663,10667,10687,10691,
+	10709,10711,10723,10729,10733,10739,10753,10771,
+	10781,10789,10799,10831,10837,10847,10853,10859,
+	10861,10867,10883,10889,10891,10903,10909,10937,
+	10939,10949,10957,10973,10979,10987,10993,11003,
+	11027,11047,11057,11059,11069,11071,11083,11087,
+	11093,11113,11117,11119,11131,11149,11159,11161,
+	11171,11173,11177,11197,11213,11239,11243,11251,
+	11257,11261,11273,11279,11287,11299,11311,11317,
+	11321,11329,11351,11353,11369,11383,11393,11399,
+	11411,11423,11437,11443,11447,11467,11471,11483,
+	11489,11491,11497,11503,11519,11527,11549,11551,
+	11579,11587,11593,11597,11617,11621,11633,11657,
+	11677,11681,11689,11699,11701,11717,11719,11731,
+	11743,11777,11779,11783,11789,11801,11807,11813,
+	11821,11827,11831,11833,11839,11863,11867,11887,
+	11897,11903,11909,11923,11927,11933,11939,11941,
+	11953,11959,11969,11971,11981,11987,12007,12011,
+	12037,12041,12043,12049,12071,12073,12097,12101,
+	12107,12109,12113,12119,12143,12149,12157,12161,
+	12163,12197,12203,12211,12227,12239,12241,12251,
+	12253,12263,12269,12277,12281,12289,12301,12323,
+	12329,12343,12347,12373,12377,12379,12391,12401,
+	12409,12413,12421,12433,12437,12451,12457,12473,
+	12479,12487,12491,12497,12503,12511,12517,12527,
+	12539,12541,12547,12553,12569,12577,12583,12589,
+	12601,12611,12613,12619,12637,12641,12647,12653,
+	12659,12671,12689,12697,12703,12713,12721,12739,
+	12743,12757,12763,12781,12791,12799,12809,12821,
+	12823,12829,12841,12853,12889,12893,12899,12907,
+	12911,12917,12919,12923,12941,12953,12959,12967,
+	12973,12979,12983,13001,13003,13007,13009,13033,
+	13037,13043,13049,13063,13093,13099,13103,13109,
+	13121,13127,13147,13151,13159,13163,13171,13177,
+	13183,13187,13217,13219,13229,13241,13249,13259,
+	13267,13291,13297,13309,13313,13327,13331,13337,
+	13339,13367,13381,13397,13399,13411,13417,13421,
+	13441,13451,13457,13463,13469,13477,13487,13499,
+	13513,13523,13537,13553,13567,13577,13591,13597,
+	13613,13619,13627,13633,13649,13669,13679,13681,
+	13687,13691,13693,13697,13709,13711,13721,13723,
+	13729,13751,13757,13759,13763,13781,13789,13799,
+	13807,13829,13831,13841,13859,13873,13877,13879,
+	13883,13901,13903,13907,13913,13921,13931,13933,
+	13963,13967,13997,13999,14009,14011,14029,14033,
+	14051,14057,14071,14081,14083,14087,14107,14143,
+	14149,14153,14159,14173,14177,14197,14207,14221,
+	14243,14249,14251,14281,14293,14303,14321,14323,
+	14327,14341,14347,14369,14387,14389,14401,14407,
+	14411,14419,14423,14431,14437,14447,14449,14461,
+	14479,14489,14503,14519,14533,14537,14543,14549,
+	14551,14557,14561,14563,14591,14593,14621,14627,
+	14629,14633,14639,14653,14657,14669,14683,14699,
+	14713,14717,14723,14731,14737,14741,14747,14753,
+	14759,14767,14771,14779,14783,14797,14813,14821,
+	14827,14831,14843,14851,14867,14869,14879,14887,
+	14891,14897,14923,14929,14939,14947,14951,14957,
+	14969,14983,15013,15017,15031,15053,15061,15073,
+	15077,15083,15091,15101,15107,15121,15131,15137,
+	15139,15149,15161,15173,15187,15193,15199,15217,
+	15227,15233,15241,15259,15263,15269,15271,15277,
+	15287,15289,15299,15307,15313,15319,15329,15331,
+	15349,15359,15361,15373,15377,15383,15391,15401,
+	15413,15427,15439,15443,15451,15461,15467,15473,
+	15493,15497,15511,15527,15541,15551,15559,15569,
+	15581,15583,15601,15607,15619,15629,15641,15643,
+	15647,15649,15661,15667,15671,15679,15683,15727,
+	15731,15733,15737,15739,15749,15761,15767,15773,
+	15787,15791,15797,15803,15809,15817,15823,15859,
+	15877,15881,15887,15889,15901,15907,15913,15919,
+	15923,15937,15959,15971,15973,15991,16001,16007,
+	16033,16057,16061,16063,16067,16069,16073,16087,
+	16091,16097,16103,16111,16127,16139,16141,16183,
+	16187,16189,16193,16217,16223,16229,16231,16249,
+	16253,16267,16273,16301,16319,16333,16339,16349,
+	16361,16363,16369,16381,16411,16417,16421,16427,
+	16433,16447,16451,16453,16477,16481,16487,16493,
+	16519,16529,16547,16553,16561,16567,16573,16603,
+	16607,16619,16631,16633,16649,16651,16657,16661,
+	16673,16691,16693,16699,16703,16729,16741,16747,
+	16759,16763,16787,16811,16823,16829,16831,16843,
+	16871,16879,16883,16889,16901,16903,16921,16927,
+	16931,16937,16943,16963,16979,16981,16987,16993,
+	17011,17021,17027,17029,17033,17041,17047,17053,
+	17077,17093,17099,17107,17117,17123,17137,17159,
+	17167,17183,17189,17191,17203,17207,17209,17231,
+	17239,17257,17291,17293,17299,17317,17321,17327,
+	17333,17341,17351,17359,17377,17383,17387,17389,
+	17393,17401,17417,17419,17431,17443,17449,17467,
+	17471,17477,17483,17489,17491,17497,17509,17519,
+	17539,17551,17569,17573,17579,17581,17597,17599,
+	17609,17623,17627,17657,17659,17669,17681,17683,
+	17707,17713,17729,17737,17747,17749,17761,17783,
+	17789,17791,17807,17827,17837,17839,17851,17863,
+#endif
+	};
diff --git a/package/network/services/ead/src/tinysrp/bn_shift.c b/package/network/services/ead/src/tinysrp/bn_shift.c
new file mode 100644
index 0000000000..f403720ecc
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_shift.c
@@ -0,0 +1,139 @@
+/* crypto/bn/bn_shift.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "bn_lcl.h"
+
+int BN_lshift(BIGNUM *r, const BIGNUM *a, int n)
+	{
+	int i,nw,lb,rb;
+	BN_ULONG *t,*f;
+	BN_ULONG l;
+
+	r->neg=a->neg;
+	if (bn_wexpand(r,a->top+(n/BN_BITS2)+1) == NULL) return(0);
+	nw=n/BN_BITS2;
+	lb=n%BN_BITS2;
+	rb=BN_BITS2-lb;
+	f=a->d;
+	t=r->d;
+	t[a->top+nw]=0;
+	if (lb == 0)
+		for (i=a->top-1; i>=0; i--)
+			t[nw+i]=f[i];
+	else
+		for (i=a->top-1; i>=0; i--)
+			{
+			l=f[i];
+			t[nw+i+1]|=(l>>rb)&BN_MASK2;
+			t[nw+i]=(l<<lb)&BN_MASK2;
+			}
+	memset(t,0,nw*sizeof(t[0]));
+/*      for (i=0; i<nw; i++)
+		t[i]=0;*/
+	r->top=a->top+nw+1;
+	bn_fix_top(r);
+	return(1);
+	}
+
+int BN_rshift(BIGNUM *r, BIGNUM *a, int n)
+	{
+	int i,j,nw,lb,rb;
+	BN_ULONG *t,*f;
+	BN_ULONG l,tmp;
+
+	nw=n/BN_BITS2;
+	rb=n%BN_BITS2;
+	lb=BN_BITS2-rb;
+	if (nw > a->top || a->top == 0)
+		{
+		BN_zero(r);
+		return(1);
+		}
+	if (r != a)
+		{
+		r->neg=a->neg;
+		if (bn_wexpand(r,a->top-nw+1) == NULL) return(0);
+		}
+
+	f= &(a->d[nw]);
+	t=r->d;
+	j=a->top-nw;
+	r->top=j;
+
+	if (rb == 0)
+		{
+		for (i=j+1; i > 0; i--)
+			*(t++)= *(f++);
+		}
+	else
+		{
+		l= *(f++);
+		for (i=1; i<j; i++)
+			{
+			tmp =(l>>rb)&BN_MASK2;
+			l= *(f++);
+			*(t++) =(tmp|(l<<lb))&BN_MASK2;
+			}
+		*(t++) =(l>>rb)&BN_MASK2;
+		}
+	*t=0;
+	bn_fix_top(r);
+	return(1);
+	}
diff --git a/package/network/services/ead/src/tinysrp/bn_sqr.c b/package/network/services/ead/src/tinysrp/bn_sqr.c
new file mode 100644
index 0000000000..2d3db70e35
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_sqr.c
@@ -0,0 +1,160 @@
+/* crypto/bn/bn_sqr.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "bn_lcl.h"
+
+/* r must not be a */
+/* I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96 */
+int BN_sqr(BIGNUM *r, BIGNUM *a, BN_CTX *ctx)
+	{
+	int max,al;
+	int ret = 0;
+	BIGNUM *tmp,*rr;
+
+#ifdef BN_COUNT
+printf("BN_sqr %d * %d\n",a->top,a->top);
+#endif
+	bn_check_top(a);
+
+	al=a->top;
+	if (al <= 0)
+		{
+		r->top=0;
+		return(1);
+		}
+
+	BN_CTX_start(ctx);
+	rr=(a != r) ? r : BN_CTX_get(ctx);
+	tmp=BN_CTX_get(ctx);
+	if (tmp == NULL) goto err;
+
+	max=(al+al);
+	if (bn_wexpand(rr,max+1) == NULL) goto err;
+
+	r->neg=0;
+	if (al == 4)
+		{
+#ifndef BN_SQR_COMBA
+		BN_ULONG t[8];
+		bn_sqr_normal(rr->d,a->d,4,t);
+#else
+		bn_sqr_comba4(rr->d,a->d);
+#endif
+		}
+	else if (al == 8)
+		{
+#ifndef BN_SQR_COMBA
+		BN_ULONG t[16];
+		bn_sqr_normal(rr->d,a->d,8,t);
+#else
+		bn_sqr_comba8(rr->d,a->d);
+#endif
+		}
+	else
+		{
+		if (bn_wexpand(tmp,max) == NULL) goto err;
+		bn_sqr_normal(rr->d,a->d,al,tmp->d);
+		}
+
+	rr->top=max;
+	if ((max > 0) && (rr->d[max-1] == 0)) rr->top--;
+	if (rr != r) BN_copy(r,rr);
+	ret = 1;
+ err:
+	BN_CTX_end(ctx);
+	return(ret);
+	}
+
+/* tmp must have 2*n words */
+void bn_sqr_normal(BN_ULONG *r, BN_ULONG *a, int n, BN_ULONG *tmp)
+	{
+	int i,j,max;
+	BN_ULONG *ap,*rp;
+
+	max=n*2;
+	ap=a;
+	rp=r;
+	rp[0]=rp[max-1]=0;
+	rp++;
+	j=n;
+
+	if (--j > 0)
+		{
+		ap++;
+		rp[j]=bn_mul_words(rp,ap,j,ap[-1]);
+		rp+=2;
+		}
+
+	for (i=n-2; i>0; i--)
+		{
+		j--;
+		ap++;
+		rp[j]=bn_mul_add_words(rp,ap,j,ap[-1]);
+		rp+=2;
+		}
+
+	bn_add_words(r,r,r,max);
+
+	/* There will not be a carry */
+
+	bn_sqr_words(tmp,a,n);
+
+	bn_add_words(r,r,tmp,max);
+	}
diff --git a/package/network/services/ead/src/tinysrp/bn_word.c b/package/network/services/ead/src/tinysrp/bn_word.c
new file mode 100644
index 0000000000..7820e08a8a
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/bn_word.c
@@ -0,0 +1,130 @@
+/* crypto/bn/bn_word.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "bn_lcl.h"
+
+int BN_add_word(BIGNUM *a, BN_ULONG w)
+	{
+	BN_ULONG l;
+	int i;
+
+	if (a->neg)
+		{
+		a->neg=0;
+		i=BN_sub_word(a,w);
+		if (!BN_is_zero(a))
+			a->neg=!(a->neg);
+		return(i);
+		}
+	w&=BN_MASK2;
+	if (bn_wexpand(a,a->top+1) == NULL) return(0);
+	i=0;
+	for (;;)
+		{
+		l=(a->d[i]+(BN_ULONG)w)&BN_MASK2;
+		a->d[i]=l;
+		if (w > l)
+			w=1;
+		else
+			break;
+		i++;
+		}
+	if (i >= a->top)
+		a->top++;
+	return(1);
+	}
+
+int BN_sub_word(BIGNUM *a, BN_ULONG w)
+	{
+	int i;
+
+	if (BN_is_zero(a) || a->neg)
+		{
+		a->neg=0;
+		i=BN_add_word(a,w);
+		a->neg=1;
+		return(i);
+		}
+
+	w&=BN_MASK2;
+	if ((a->top == 1) && (a->d[0] < w))
+		{
+		a->d[0]=w-a->d[0];
+		a->neg=1;
+		return(1);
+		}
+	i=0;
+	for (;;)
+		{
+		if (a->d[i] >= w)
+			{
+			a->d[i]-=w;
+			break;
+			}
+		else
+			{
+			a->d[i]=(a->d[i]-w)&BN_MASK2;
+			i++;
+			w=1;
+			}
+		}
+	if ((a->d[i] == 0) && (i == (a->top-1)))
+		a->top--;
+	return(1);
+	}
diff --git a/package/network/services/ead/src/tinysrp/clitest.c b/package/network/services/ead/src/tinysrp/clitest.c
new file mode 100644
index 0000000000..338f41ff4e
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/clitest.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_client.h"
+
+int
+main()
+{
+  int index;
+  struct t_client * tc;
+  struct t_preconf *tcp;
+  struct t_num s;
+  struct t_num B;
+  char username[MAXUSERLEN];
+  char hexbuf[MAXHEXPARAMLEN];
+  char buf1[MAXPARAMLEN], buf2[MAXPARAMLEN], buf3[MAXSALTLEN];
+  unsigned char cbuf[20];
+  struct t_num * A;
+  unsigned char * skey;
+  char pass[128];
+
+  printf("Enter username: ");
+  fgets(username, sizeof(username), stdin);
+  username[strlen(username) - 1] = '\0';
+  printf("Enter index (from server): ");
+  fgets(hexbuf, sizeof(hexbuf), stdin);
+  index = atoi(hexbuf);
+  tcp = t_getpreparam(index - 1);
+  printf("Enter salt (from server): ");
+  fgets(hexbuf, sizeof(hexbuf), stdin);
+  s.data = buf3;
+  s.len = t_fromb64(s.data, hexbuf);
+
+  tc = t_clientopen(username, &tcp->modulus, &tcp->generator, &s);
+  if (tc == 0) {
+    printf("invalid n, g\n");
+    exit(1);
+  }
+
+  A = t_clientgenexp(tc);
+  printf("A (to server): %s\n", t_tob64(hexbuf, A->data, A->len));
+
+  t_getpass(pass, 128, "Enter password:");
+  t_clientpasswd(tc, pass);
+
+  printf("Enter B (from server): ");
+  fgets(hexbuf, sizeof(hexbuf), stdin);
+  B.data = buf1;
+  B.len = t_fromb64(B.data, hexbuf);
+
+  skey = t_clientgetkey(tc, &B);
+  printf("Session key: %s\n", t_tohex(hexbuf, skey, 40));
+  printf("Response (to server): %s\n",
+    t_tohex(hexbuf, t_clientresponse(tc), RESPONSE_LEN));
+
+  printf("Enter server response: ");
+  fgets(hexbuf, sizeof(hexbuf), stdin);
+  hexbuf[strlen(hexbuf) - 1] = '\0';
+  t_fromhex(cbuf, hexbuf);
+
+  if (t_clientverify(tc, cbuf) == 0)
+    printf("Server authentication successful.\n");
+  else
+    printf("Server authentication failed.\n");
+
+  t_clientclose(tc);
+
+  return 0;
+}
diff --git a/package/network/services/ead/src/tinysrp/config.h.in b/package/network/services/ead/src/tinysrp/config.h.in
new file mode 100644
index 0000000000..a4b50c714a
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/config.h.in
@@ -0,0 +1,79 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if type char is unsigned and you are not using gcc.  */
+#ifndef __CHAR_UNSIGNED__
+#undef __CHAR_UNSIGNED__
+#endif
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define as __inline if that's what the C compiler calls it.  */
+#undef inline
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef WORDS_BIGENDIAN
+
+#undef SHA1HANDSOFF
+
+#undef POSIX_TERMIOS
+
+#undef POSIX_SIGTYPE
+
+#undef volatile
+
+/* The number of bytes in a int.  */
+#undef SIZEOF_INT
+
+/* The number of bytes in a long.  */
+#undef SIZEOF_LONG
+
+/* The number of bytes in a long long.  */
+#undef SIZEOF_LONG_LONG
+
+/* The number of bytes in a short.  */
+#undef SIZEOF_SHORT
+
+/* Define if you have the memcpy function.  */
+#undef HAVE_MEMCPY
+
+/* Define if you have the sigaction function.  */
+#undef HAVE_SIGACTION
+
+/* Define if you have the strchr function.  */
+#undef HAVE_STRCHR
+
+/* Define if you have the <sgtty.h> header file.  */
+#undef HAVE_SGTTY_H
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <termio.h> header file.  */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <termios.h> header file.  */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Version number of package */
+#undef VERSION
+
diff --git a/package/network/services/ead/src/tinysrp/configure b/package/network/services/ead/src/tinysrp/configure
new file mode 100755
index 0000000000..6ee76bf436
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/configure
@@ -0,0 +1,2421 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=t_pwd.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:559: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:612: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:669: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+PACKAGE=libtinysrp
+
+VERSION=0.7.5
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:716: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:729: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:742: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:755: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:768: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+
+test "$CFLAGS" = "" && CFLAGS="-O2"
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:788: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:818: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:869: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:901: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 912 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:917: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:943: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:948: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:957: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:976: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1019: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1072: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1095: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1144: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1159 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1165: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1176 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1182: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1193 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1199: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1224: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1229 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1237: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1254 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1272 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1293 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1304: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in sgtty.h sys/ioctl.h sys/time.h termio.h termios.h unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1331: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1336 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1341: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1370: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1375 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1424: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:1445: checking for inline" >&5
+if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat > conftest.$ac_ext <<EOF
+#line 1452 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:1459: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+  inline | yes) ;;
+  no) cat >> confdefs.h <<\EOF
+#define inline 
+EOF
+ ;;
+  *)  cat >> confdefs.h <<EOF
+#define inline $ac_cv_c_inline
+EOF
+ ;;
+esac
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1485: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1490 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1499: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:1520: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 1527 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:1538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 1542 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:1553: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_bigendian=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1573 "configure"
+#include "confdefs.h"
+main () {
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+if { (eval echo configure:1586: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_bigendian=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+  cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo $ac_n "checking size of short""... $ac_c" 1>&6
+echo "configure:1610: checking size of short" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1618 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(short));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1629: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_short=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_short=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_short" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_SHORT $ac_cv_sizeof_short
+EOF
+
+
+echo $ac_n "checking size of int""... $ac_c" 1>&6
+echo "configure:1649: checking size of int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1657 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(int));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1668: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_int=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+EOF
+
+
+echo $ac_n "checking size of long""... $ac_c" 1>&6
+echo "configure:1688: checking size of long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1696 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(long));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1707: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_long=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+EOF
+
+
+echo $ac_n "checking size of long long""... $ac_c" 1>&6
+echo "configure:1727: checking size of long long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1735 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(long long));
+  exit(0);
+}
+EOF
+if { (eval echo configure:1746: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_long_long=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_long_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_long_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+EOF
+
+
+cat > conftest.$ac_ext <<EOF
+#line 1766 "configure"
+#include "confdefs.h"
+
+int main() {
+volatile int i;
+; return 0; }
+EOF
+if { (eval echo configure:1773: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define volatile 
+EOF
+
+fi
+rm -f conftest*
+echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6
+echo "configure:1786: checking whether char is unsigned" >&5
+if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$GCC" = yes; then
+  # GCC predefines this symbol on systems where it applies.
+cat > conftest.$ac_ext <<EOF
+#line 1793 "configure"
+#include "confdefs.h"
+#ifdef __CHAR_UNSIGNED__
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_c_char_unsigned=yes
+else
+  rm -rf conftest*
+  ac_cv_c_char_unsigned=no
+fi
+rm -f conftest*
+
+else
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1815 "configure"
+#include "confdefs.h"
+/* volatile prevents gcc2 from optimizing the test away on sparcs.  */
+#if !defined(__STDC__) || __STDC__ != 1
+#define volatile
+#endif
+main() {
+  volatile char c = 255; exit(c < 0);
+}
+EOF
+if { (eval echo configure:1825: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_char_unsigned=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_char_unsigned=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_char_unsigned" 1>&6
+if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then
+  cat >> confdefs.h <<\EOF
+#define __CHAR_UNSIGNED__ 1
+EOF
+
+fi
+
+
+if test "$ac_cv_c_char_unsigned" = "yes"; then
+  signed=-signed
+fi
+
+
+for ac_func in sigaction strchr memcpy
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1857: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1862 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking POSIX signal handlers""... $ac_c" 1>&6
+echo "configure:1911: checking POSIX signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_has_posix_signals'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1916 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1928: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_has_posix_signals=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_has_posix_signals=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_has_posix_signals" 1>&6
+if test $ac_cv_has_posix_signals = yes; then
+   cat >> confdefs.h <<\EOF
+#define RETSIGTYPE void
+EOF
+ cat >> confdefs.h <<\EOF
+#define POSIX_SIGTYPE 1
+EOF
+
+else
+  if test $ac_cv_type_signal = void; then
+     cat >> confdefs.h <<\EOF
+#define RETSIGTYPE void
+EOF
+
+  else
+     cat >> confdefs.h <<\EOF
+#define RETSIGTYPE int
+EOF
+
+  fi
+fi
+ac_safe=`echo "termios.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for termios.h""... $ac_c" 1>&6
+echo "configure:1964: checking for termios.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1969 "configure"
+#include "confdefs.h"
+#include <termios.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1974: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  echo $ac_n "checking for cfsetispeed""... $ac_c" 1>&6
+echo "configure:1991: checking for cfsetispeed" >&5
+if eval "test \"`echo '$''{'ac_cv_func_cfsetispeed'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1996 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char cfsetispeed(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char cfsetispeed();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_cfsetispeed) || defined (__stub___cfsetispeed)
+choke me
+#else
+cfsetispeed();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_cfsetispeed=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_cfsetispeed=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'cfsetispeed`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define POSIX_TERMIOS 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+cat >> confdefs.h <<\EOF
+#define SHA1HANDSOFF 1
+EOF
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@LN_S@%$LN_S%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@signed@%$signed%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/package/network/services/ead/src/tinysrp/configure.in b/package/network/services/ead/src/tinysrp/configure.in
new file mode 100644
index 0000000000..627d15a8c7
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/configure.in
@@ -0,0 +1,52 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(t_pwd.h)
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(libtinysrp, 0.7.5)
+
+test "$CFLAGS" = "" && CFLAGS="-O2"
+
+dnl Checks for programs.
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_RANLIB
+AC_ARG_PROGRAM
+
+dnl Checks for header files.
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS(sgtty.h sys/ioctl.h sys/time.h termio.h termios.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+AC_C_CONST
+AC_C_INLINE
+AC_HEADER_TIME
+AC_C_BIGENDIAN
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+AC_TRY_COMPILE(, [volatile int i;], , AC_DEFINE(volatile, ))
+AC_C_CHAR_UNSIGNED
+
+AC_SUBST(signed)dnl
+if test "$ac_cv_c_char_unsigned" = "yes"; then
+  signed=-signed
+fi
+
+dnl Checks for library functions.
+
+AC_CHECK_FUNCS(sigaction strchr memcpy)
+TYPE_SIGNAL
+AC_HEADER_CHECK(termios.h,AC_FUNC_CHECK(cfsetispeed,AC_DEFINE(POSIX_TERMIOS)))
+
+dnl User options
+
+dnl Some defines for now.
+
+AC_DEFINE(SHA1HANDSOFF)
+
+AC_OUTPUT(Makefile)
diff --git a/package/network/services/ead/src/tinysrp/install-sh b/package/network/services/ead/src/tinysrp/install-sh
new file mode 100755
index 0000000000..e8436696c1
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/install-sh
@@ -0,0 +1,250 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/package/network/services/ead/src/tinysrp/missing b/package/network/services/ead/src/tinysrp/missing
new file mode 100755
index 0000000000..a6abd06980
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/missing
@@ -0,0 +1,134 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        touch file \`y.tab.c'
+  makeinfo     touch the output file
+  yacc         touch file \`y.tab.c'"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing - GNU libit 0.0"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`configure.in'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`configure.in'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`configure.in'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    touch config.h.in
+    ;;
+
+  automake)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print \
+      | sed 's/^\(.*\).am$/touch \1.in/' \
+      | sh
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    touch y.tab.c
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/package/network/services/ead/src/tinysrp/mkinstalldirs b/package/network/services/ead/src/tinysrp/mkinstalldirs
new file mode 100755
index 0000000000..3bc183603e
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/mkinstalldirs
@@ -0,0 +1,39 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/package/network/services/ead/src/tinysrp/srvtest.c b/package/network/services/ead/src/tinysrp/srvtest.c
new file mode 100644
index 0000000000..e09d501ad3
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/srvtest.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_server.h"
+
+int
+main(argc, argv)
+     int argc;
+     char * argv[];
+{
+  struct t_server * ts;
+  struct t_pw * tpw;
+  struct t_conf * tcnf;
+  struct t_num * B;
+  char username[MAXUSERLEN];
+  char hexbuf[MAXHEXPARAMLEN];
+  char buf[MAXPARAMLEN];
+  struct t_num A;
+  unsigned char * skey;
+  unsigned char cbuf[20];
+  FILE * fp;
+  FILE * fp2;
+  char confname[256];
+
+  printf("Enter username: ");
+  fgets(username, sizeof(username), stdin);
+  username[strlen(username) - 1] = '\0';
+  ts = t_serveropen(username);
+
+  if(ts == NULL) {
+    fprintf(stderr, "User %s not found\n", username);
+    exit(1);
+  }
+
+#if 0
+  printf("n: %s\n", t_tob64(hexbuf, ts->n.data, ts->n.len));
+  printf("g: %s\n", t_tob64(hexbuf, ts->g.data, ts->g.len));
+#endif
+  printf("index (to client): %d\n", ts->index);
+  printf("salt (to client): %s\n", t_tob64(hexbuf, ts->s.data, ts->s.len));
+
+  B = t_servergenexp(ts);
+  printf("Enter A (from client): ");
+  fgets(hexbuf, sizeof(hexbuf), stdin);
+  A.data = buf;
+  A.len = t_fromb64(A.data, hexbuf);
+
+  printf("B (to client): %s\n", t_tob64(hexbuf, B->data, B->len));
+
+  skey = t_servergetkey(ts, &A);
+  printf("Session key: %s\n", t_tohex(hexbuf, skey, 40));
+
+  /* printf("[Expected response: %s]\n", t_tohex(hexbuf, cbuf, 16)); */
+
+  printf("Enter response (from client): ");
+  fgets(hexbuf, sizeof(hexbuf), stdin);
+  hexbuf[strlen(hexbuf) - 1] = '\0';
+  t_fromhex(cbuf, hexbuf);
+
+  if(t_serververify(ts, cbuf) == 0) {
+    printf("Authentication successful.\n");
+    printf("Response (to client): %s\n",
+      t_tohex(hexbuf, t_serverresponse(ts), RESPONSE_LEN));
+  } else
+    printf("Authentication failed.\n");
+
+  t_serverclose(ts);
+
+  return 0;
+}
diff --git a/package/network/services/ead/src/tinysrp/stamp-h.in b/package/network/services/ead/src/tinysrp/stamp-h.in
new file mode 100644
index 0000000000..9788f70238
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/package/network/services/ead/src/tinysrp/t_client.c b/package/network/services/ead/src/tinysrp/t_client.c
new file mode 100644
index 0000000000..692215a369
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_client.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_client.h"
+#include "t_sha.h"
+
+_TYPE( struct t_client * )
+t_clientopen(u, n, g, s)
+     const char * u;
+     struct t_num * n;
+     struct t_num * g;
+     struct t_num * s;
+{
+  struct t_client * tc;
+  unsigned char buf1[SHA_DIGESTSIZE], buf2[SHA_DIGESTSIZE];
+  SHA1_CTX ctxt;
+  int i, validated;
+  struct t_preconf * tpc;
+
+  validated = 0;
+  if(n->len < MIN_MOD_BYTES)
+    return 0;
+  for(i = 0; i < t_getprecount(); ++i) {
+    tpc = t_getpreparam(i);
+    if(tpc->modulus.len == n->len && tpc->generator.len == g->len &&
+       memcmp(tpc->modulus.data, n->data, n->len) == 0 &&
+       memcmp(tpc->generator.data, g->data, g->len) == 0) {
+      validated = 1;    /* Match found, done */
+      break;
+    }
+  }
+
+  if(validated == 0)
+    return 0;
+
+  if((tc = malloc(sizeof(struct t_client))) == 0)
+    return 0;
+
+  strncpy(tc->username, u, MAXUSERLEN);
+
+  SHA1Init(&tc->hash);
+
+  tc->n.len = n->len;
+  tc->n.data = tc->nbuf;
+  memcpy(tc->n.data, n->data, tc->n.len);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, tc->n.data, tc->n.len);
+  SHA1Final(buf1, &ctxt);
+
+  tc->g.len = g->len;
+  tc->g.data = tc->gbuf;
+  memcpy(tc->g.data, g->data, tc->g.len);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, tc->g.data, tc->g.len);
+  SHA1Final(buf2, &ctxt);
+
+  for(i = 0; i < sizeof(buf1); ++i)
+    buf1[i] ^= buf2[i];
+
+  SHA1Update(&tc->hash, buf1, sizeof(buf1));
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, tc->username, strlen(tc->username));
+  SHA1Final(buf1, &ctxt);
+
+  SHA1Update(&tc->hash, buf1, sizeof(buf1));
+
+  tc->s.len = s->len;
+  tc->s.data = tc->sbuf;
+  memcpy(tc->s.data, s->data, tc->s.len);
+
+  SHA1Update(&tc->hash, tc->s.data, tc->s.len);
+
+  tc->a.data = tc->abuf;
+  tc->A.data = tc->Abuf;
+  tc->p.data = tc->pbuf;
+  tc->v.data = tc->vbuf;
+
+  SHA1Init(&tc->ckhash);
+
+  return tc;
+}
+
+_TYPE( struct t_num * )
+t_clientgenexp(tc)
+     struct t_client * tc;
+{
+  BigInteger a, A, n, g;
+
+  if(tc->n.len < ALEN)
+    tc->a.len = tc->n.len;
+  else
+    tc->a.len = ALEN;
+
+  t_random(tc->a.data, tc->a.len);
+  a = BigIntegerFromBytes(tc->a.data, tc->a.len);
+  n = BigIntegerFromBytes(tc->n.data, tc->n.len);
+  g = BigIntegerFromBytes(tc->g.data, tc->g.len);
+  A = BigIntegerFromInt(0);
+  BigIntegerModExp(A, g, a, n);
+  tc->A.len = BigIntegerToBytes(A, tc->A.data);
+
+  BigIntegerFree(A);
+  BigIntegerFree(a);
+  BigIntegerFree(g);
+  BigIntegerFree(n);
+
+  SHA1Update(&tc->hash, tc->A.data, tc->A.len);
+  SHA1Update(&tc->ckhash, tc->A.data, tc->A.len);
+
+  return &tc->A;
+}
+
+_TYPE( void )
+t_clientpasswd(tc, password)
+     struct t_client * tc;
+     char * password;
+{
+  BigInteger n, g, p, v;
+  SHA1_CTX ctxt;
+  unsigned char dig[SHA_DIGESTSIZE];
+
+  n = BigIntegerFromBytes(tc->n.data, tc->n.len);
+  g = BigIntegerFromBytes(tc->g.data, tc->g.len);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, tc->username, strlen(tc->username));
+  SHA1Update(&ctxt, ":", 1);
+  SHA1Update(&ctxt, password, strlen(password));
+  SHA1Final(dig, &ctxt);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, tc->s.data, tc->s.len);
+  SHA1Update(&ctxt, dig, sizeof(dig));
+  SHA1Final(dig, &ctxt);
+
+  p = BigIntegerFromBytes(dig, sizeof(dig));
+
+  v = BigIntegerFromInt(0);
+  BigIntegerModExp(v, g, p, n);
+
+  tc->p.len = BigIntegerToBytes(p, tc->p.data);
+  BigIntegerFree(p);
+
+  tc->v.len = BigIntegerToBytes(v, tc->v.data);
+  BigIntegerFree(v);
+}
+
+_TYPE( unsigned char * )
+t_clientgetkey(tc, serverval)
+     struct t_client * tc;
+     struct t_num * serverval;
+{
+  BigInteger n, B, v, p, a, sum, S;
+  unsigned char sbuf[MAXPARAMLEN];
+  unsigned char dig[SHA_DIGESTSIZE];
+  unsigned slen;
+  unsigned int u;
+  SHA1_CTX ctxt;
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, serverval->data, serverval->len);
+  SHA1Final(dig, &ctxt);
+  u = (dig[0] << 24) | (dig[1] << 16) | (dig[2] << 8) | dig[3];
+  if(u == 0)
+    return NULL;
+
+  SHA1Update(&tc->hash, serverval->data, serverval->len);
+
+  B = BigIntegerFromBytes(serverval->data, serverval->len);
+  n = BigIntegerFromBytes(tc->n.data, tc->n.len);
+
+  if(BigIntegerCmp(B, n) >= 0 || BigIntegerCmpInt(B, 0) == 0) {
+    BigIntegerFree(B);
+    BigIntegerFree(n);
+    return NULL;
+  }
+  v = BigIntegerFromBytes(tc->v.data, tc->v.len);
+  if(BigIntegerCmp(B, v) < 0)
+    BigIntegerAdd(B, B, n);
+  BigIntegerSub(B, B, v);
+  BigIntegerFree(v);
+
+  a = BigIntegerFromBytes(tc->a.data, tc->a.len);
+  p = BigIntegerFromBytes(tc->p.data, tc->p.len);
+
+  sum = BigIntegerFromInt(0);
+  BigIntegerMulInt(sum, p, u);
+  BigIntegerAdd(sum, sum, a);
+
+  BigIntegerFree(p);
+  BigIntegerFree(a);
+
+  S = BigIntegerFromInt(0);
+  BigIntegerModExp(S, B, sum, n);
+  slen = BigIntegerToBytes(S, sbuf);
+
+  BigIntegerFree(S);
+  BigIntegerFree(sum);
+  BigIntegerFree(B);
+  BigIntegerFree(n);
+
+  t_sessionkey(tc->session_key, sbuf, slen);
+  memset(sbuf, 0, slen);
+
+  SHA1Update(&tc->hash, tc->session_key, sizeof(tc->session_key));
+
+  SHA1Final(tc->session_response, &tc->hash);
+  SHA1Update(&tc->ckhash, tc->session_response, sizeof(tc->session_response));
+  SHA1Update(&tc->ckhash, tc->session_key, sizeof(tc->session_key));
+
+  return tc->session_key;
+}
+
+_TYPE( int )
+t_clientverify(tc, resp)
+    struct t_client * tc;
+    unsigned char * resp;
+{
+  unsigned char expected[SHA_DIGESTSIZE];
+
+  SHA1Final(expected, &tc->ckhash);
+  return memcmp(expected, resp, sizeof(expected));
+}
+
+_TYPE( unsigned char * )
+t_clientresponse(tc)
+    struct t_client * tc;
+{
+  return tc->session_response;
+}
+
+_TYPE( void )
+t_clientclose(tc)
+     struct t_client * tc;
+{
+  memset(tc->abuf, 0, sizeof(tc->abuf));
+  memset(tc->pbuf, 0, sizeof(tc->pbuf));
+  memset(tc->vbuf, 0, sizeof(tc->vbuf));
+  memset(tc->session_key, 0, sizeof(tc->session_key));
+  free(tc);
+}
diff --git a/package/network/services/ead/src/tinysrp/t_client.h b/package/network/services/ead/src/tinysrp/t_client.h
new file mode 100644
index 0000000000..42922aff1b
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_client.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#ifndef T_CLIENT_H
+#define T_CLIENT_H
+
+#include "t_sha.h"
+
+#if     !defined(P)
+#ifdef  __STDC__
+#define P(x)    x
+#else
+#define P(x)    ()
+#endif
+#endif
+
+/*      For building dynamic link libraries under windows, windows NT
+ *      using MSVC1.5 or MSVC2.0
+ */
+
+#ifndef _DLLDECL
+#define _DLLDECL
+
+#ifdef MSVC15   /* MSVC1.5 support for 16 bit apps */
+#define _MSVC15EXPORT _export
+#define _MSVC20EXPORT
+#define _DLLAPI _export _pascal
+#define _TYPE(a) a _MSVC15EXPORT
+#define DLLEXPORT 1
+
+#elif MSVC20
+#define _MSVC15EXPORT
+#define _MSVC20EXPORT _declspec(dllexport)
+#define _DLLAPI
+#define _TYPE(a) _MSVC20EXPORT a
+#define DLLEXPORT 1
+
+#else                   /* Default, non-dll.  Use this for Unix or DOS */
+#define _MSVC15DEXPORT
+#define _MSVC20EXPORT
+#define _DLLAPI
+#define _TYPE(a) a
+#endif
+#endif
+
+#define ALEN 32
+#define MIN_MOD_BYTES 64        /* 512 bits */
+
+struct t_client {
+  struct t_num n;
+  struct t_num g;
+  struct t_num s;
+
+  struct t_num a;
+  struct t_num A;
+
+  struct t_num p;
+  struct t_num v;
+
+  SHA1_CTX hash, ckhash;
+
+  char username[MAXUSERLEN];
+  unsigned char session_key[SESSION_KEY_LEN];
+  unsigned char session_response[RESPONSE_LEN];
+
+  unsigned char nbuf[MAXPARAMLEN], gbuf[MAXPARAMLEN], sbuf[MAXSALTLEN];
+  unsigned char pbuf[MAXPARAMLEN], vbuf[MAXPARAMLEN];
+  unsigned char abuf[ALEN], Abuf[MAXPARAMLEN];
+};
+
+/*
+ * SRP client-side negotiation
+ *
+ * This code negotiates the client side of an SRP exchange.
+ * "t_clientopen" accepts a username, and N, g, and s parameters,
+ *   which are usually sent by the server in the first round.
+ *   The client should then call...
+ * "t_clientgenexp" will generate a random 256-bit exponent and
+ *   raise g to that power, returning the result.  This result
+ *   should be sent to the server as w(p).
+ * "t_clientpasswd" accepts the user's password, which should be
+ *   entered locally and updates the client's state.
+ * "t_clientgetkey" accepts the exponential y(p), which should
+ *   be sent by the server in the next round and computes the
+ *   256-bit session key.  This data should be saved before the
+ *   session is closed.
+ * "t_clientresponse" computes the session key proof as SHA(y(p), K).
+ * "t_clientclose" closes the session and frees its memory.
+ *
+ * Note that authentication is not performed per se; it is up
+ * to either/both sides of the protocol to now verify securely
+ * that their session keys agree in order to establish authenticity.
+ * One possible way is through "oracle hashing"; one side sends
+ * r, the other replies with H(r,K), where H() is a hash function.
+ *
+ * t_clientresponse and t_clientverify now implement a version of
+ * the session-key verification described above.
+ */
+_TYPE( struct t_client * )
+  t_clientopen P((const char *, struct t_num *, struct t_num *,
+		  struct t_num *));
+_TYPE( struct t_num * ) t_clientgenexp P((struct t_client *));
+_TYPE( void ) t_clientpasswd P((struct t_client *, char *));
+_TYPE( unsigned char * )
+  t_clientgetkey P((struct t_client *, struct t_num *));
+_TYPE( int ) t_clientverify P((struct t_client *, unsigned char *));
+_TYPE( unsigned char * ) t_clientresponse P((struct t_client *));
+_TYPE( void ) t_clientclose P((struct t_client *));
+
+#endif
diff --git a/package/network/services/ead/src/tinysrp/t_conf.c b/package/network/services/ead/src/tinysrp/t_conf.c
new file mode 100644
index 0000000000..fbe6f410e2
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_conf.c
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_read.h"
+#include "bn.h"
+#include "bn_lcl.h"
+#include "bn_prime.h"
+
+#define TABLE_SIZE      32
+
+static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
+	const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont);
+
+/*
+ * This is the safe prime generation logic.
+ * To generate a safe prime p (where p = 2q+1 and q is prime), we start
+ * with a random odd q that is one bit shorter than the desired length
+ * of p.  We use a simple 30-element sieve to filter the values of q
+ * and consider only those that are 11, 23, or 29 (mod 30).  (If q were
+ * anything else, either q or p would be divisible by 2, 3, or 5).
+ * For the values of q that are left, we apply the following tests in
+ * this order:
+ *
+ *   trial divide q
+ *   let p = 2q + 1
+ *   trial divide p
+ *   apply Fermat test to q (2^q == 2 (mod q))
+ *   apply Fermat test to p (2^p == 2 (mod p))
+ *   apply real probablistic primality test to q
+ *   apply real probablistic primality test to p
+ *
+ * A number that passes all these tests is considered a safe prime for
+ * our purposes.  The tests are ordered this way for efficiency; the
+ * slower tests are run rarely if ever at all.
+ */
+
+static int
+trialdiv(x)
+     const BigInteger x;
+{
+  static int primes[] = {               /* All odd primes < 256 */
+      3,   5,   7,  11,  13,  17,  19,  23,  29,
+     31,  37,  41,  43,  47,  53,  59,  61,  67,
+     71,  73,  79,  83,  89,  97, 101, 103,
+    107, 109, 113, 127, 131, 137, 139, 149, 151,
+    157, 163, 167, 173, 179, 181, 191, 193, 197,
+    199, 211, 223, 227, 229, 233, 239, 241, 251
+  };
+  static int nprimes = sizeof(primes) / sizeof(int);
+  int i;
+
+  for(i = 0; i < nprimes; ++i) {
+    if(BigIntegerModInt(x, primes[i]) == 0)
+      return primes[i];
+  }
+  return 1;
+}
+
+/* x + sieve30[x%30] == 11, 23, or 29 (mod 30) */
+
+static int sieve30[] =
+{  11, 10,  9,  8,  7,  6,  5,  4,  3,  2,
+    1, 12, 11, 10,  9,  8,  7,  6,  5,  4,
+    3,  2,  1,  6,  5,  4,  3,  2,  1, 12
+};
+
+/* Find a Sophie-Germain prime between "lo" and "hi".  NOTE: this is not
+   a "safe prime", but the smaller prime.  Take 2q+1 to get the safe prime. */
+
+static void
+sophie_germain(q, lo, hi)
+     BigInteger q;              /* assumed initialized */
+     const BigInteger lo;
+     const BigInteger hi;
+{
+  BigInteger m, p, r;
+  char parambuf[MAXPARAMLEN];
+  int foundprime = 0;
+  int i, mod30;
+
+  m = BigIntegerFromInt(0);
+  BigIntegerSub(m, hi, lo);
+  i = (BigIntegerBitLen(m) + 7) / 8;
+  t_random(parambuf, i);
+  r = BigIntegerFromBytes(parambuf, i);
+  BigIntegerMod(r, r, m);
+
+  BigIntegerAdd(q, r, lo);
+  if(BigIntegerModInt(q, 2) == 0)
+    BigIntegerAddInt(q, q, 1);          /* make q odd */
+
+  mod30 = BigIntegerModInt(q, 30);      /* mod30 = q % 30 */
+
+  BigIntegerFree(m);
+  m = BigIntegerFromInt(2);                     /* m = 2 */
+  p = BigIntegerFromInt(0);
+
+  while(BigIntegerCmp(q, hi) < 0) {
+    if(trialdiv(q) < 2) {
+      BigIntegerMulInt(p, q, 2);                        /* p = 2 * q */
+      BigIntegerAddInt(p, p, 1);                /* p += 1 */
+      if(trialdiv(p) < 2) {
+	BigIntegerModExp(r, m, q, q);           /* r = 2^q % q */
+	if(BigIntegerCmpInt(r, 2) == 0) {       /* if(r == 2) */
+	  BigIntegerModExp(r, m, p, p);         /* r = 2^p % p */
+	  if(BigIntegerCmpInt(r, 2) == 0) {     /* if(r == 2) */
+	    if(BigIntegerCheckPrime(q) && BigIntegerCheckPrime(p)) {
+	      ++foundprime;
+	      break;
+	    }
+	  }
+	}
+      }
+    }
+
+    i = sieve30[mod30];
+    BigIntegerAddInt(q, q, i);          /* q += i */
+    mod30 = (mod30 + i) % 30;
+  }
+
+  /* should wrap around on failure */
+  if(!foundprime) {
+    fprintf(stderr, "Prime generation failed!\n");
+    exit(1);
+  }
+
+  BigIntegerFree(r);
+  BigIntegerFree(m);
+  BigIntegerFree(p);
+}
+
+_TYPE( struct t_confent * )
+t_makeconfent(tc, nsize)
+     struct t_conf * tc;
+     int nsize;
+{
+  BigInteger n, g, q, t, u;
+
+  t = BigIntegerFromInt(0);
+  u = BigIntegerFromInt(1);             /* u = 1 */
+  BigIntegerLShift(t, u, nsize - 2);    /* t = 2^(nsize-2) */
+  BigIntegerMulInt(u, t, 2);            /* u = 2^(nsize-1) */
+
+  q = BigIntegerFromInt(0);
+  sophie_germain(q, t, u);
+
+  n = BigIntegerFromInt(0);
+  BigIntegerMulInt(n, q, 2);
+  BigIntegerAddInt(n, n, 1);
+
+  /* Look for a generator mod n */
+  g = BigIntegerFromInt(2);
+  while(1) {
+    BigIntegerModExp(t, g, q, n);               /* t = g^q % n */
+    if(BigIntegerCmpInt(t, 1) == 0)             /* if(t == 1) */
+      BigIntegerAddInt(g, g, 1);                /* ++g */
+    else
+      break;
+  }
+  BigIntegerFree(t);
+  BigIntegerFree(u);
+  BigIntegerFree(q);
+
+  tc->tcbuf.modulus.data = tc->modbuf;
+  tc->tcbuf.modulus.len = BigIntegerToBytes(n, tc->tcbuf.modulus.data);
+  BigIntegerFree(n);
+
+  tc->tcbuf.generator.data = tc->genbuf;
+  tc->tcbuf.generator.len = BigIntegerToBytes(g, tc->tcbuf.generator.data);
+  BigIntegerFree(g);
+
+  tc->tcbuf.index = 1;
+  return &tc->tcbuf;
+}
+
+_TYPE( struct t_confent * )
+t_makeconfent_c(tc, nsize)
+     struct t_conf * tc;
+     int nsize;
+{
+  BigInteger g, n, p, q, j, k, t, u;
+  int psize, qsize;
+
+  psize = nsize / 2;
+  qsize = nsize - psize;
+
+  t = BigIntegerFromInt(1);             /* t = 1 */
+  u = BigIntegerFromInt(0);
+  BigIntegerLShift(u, t, psize - 3);    /* u = t*2^(psize-3) = 2^(psize-3) */
+  BigIntegerMulInt(t, u, 3);                    /* t = 3*u = 1.5*2^(psize-2) */
+  BigIntegerAdd(u, u, t);                       /* u += t [u = 2^(psize-1)] */
+  j = BigIntegerFromInt(0);
+  sophie_germain(j, t, u);
+
+  k = BigIntegerFromInt(0);
+  if(qsize != psize) {
+    BigIntegerFree(t);
+    t = BigIntegerFromInt(1);           /* t = 1 */
+    BigIntegerLShift(u, t, qsize - 3);  /* u = t*2^(qsize-3) = 2^(qsize-3) */
+    BigIntegerMulInt(t, u, 3);          /* t = 3*u = 1.5*2^(qsize-2) */
+    BigIntegerAdd(u, u, t);             /* u += t [u = 2^(qsize-1)] */
+  }
+  sophie_germain(k, t, u);
+
+  p = BigIntegerFromInt(0);
+  BigIntegerMulInt(p, j, 2);            /* p = 2 * j */
+  BigIntegerAddInt(p, p, 1);            /* p += 1 */
+
+  q = BigIntegerFromInt(0);
+  BigIntegerMulInt(q, k, 2);            /* q = 2 * k */
+  BigIntegerAddInt(q, q, 1);            /* q += 1 */
+
+  n = BigIntegerFromInt(0);
+  BigIntegerMul(n, p, q);               /* n = p * q */
+  BigIntegerMul(u, j, k);               /* u = j * k */
+
+  BigIntegerFree(p);
+  BigIntegerFree(q);
+  BigIntegerFree(j);
+  BigIntegerFree(k);
+
+  g = BigIntegerFromInt(2);             /* g = 2 */
+
+  /* Look for a generator mod n */
+  while(1) {
+    BigIntegerModExp(t, g, u, n);       /* t = g^u % n */
+    if(BigIntegerCmpInt(t, 1) == 0)
+      BigIntegerAddInt(g, g, 1);        /* ++g */
+    else
+      break;
+  }
+
+  BigIntegerFree(u);
+  BigIntegerFree(t);
+
+  tc->tcbuf.modulus.data = tc->modbuf;
+  tc->tcbuf.modulus.len = BigIntegerToBytes(n, tc->tcbuf.modulus.data);
+  BigIntegerFree(n);
+
+  tc->tcbuf.generator.data = tc->genbuf;
+  tc->tcbuf.generator.len = BigIntegerToBytes(g, tc->tcbuf.generator.data);
+  BigIntegerFree(g);
+
+  tc->tcbuf.index = 1;
+  return &tc->tcbuf;
+}
+
+_TYPE( struct t_confent * )
+t_newconfent(tc)
+    struct t_conf * tc;
+{
+  tc->tcbuf.index = 0;
+  tc->tcbuf.modulus.data = tc->modbuf;
+  tc->tcbuf.modulus.len = 0;
+  tc->tcbuf.generator.data = tc->genbuf;
+  tc->tcbuf.generator.len = 0;
+  return &tc->tcbuf;
+}
+
+_TYPE( void )
+t_putconfent(ent, fp)
+     const struct t_confent * ent;
+     FILE * fp;
+{
+  char strbuf[MAXB64PARAMLEN];
+
+  fprintf(fp, "%d:%s:", ent->index,
+	  t_tob64(strbuf, ent->modulus.data, ent->modulus.len));
+  fprintf(fp, "%s\n",
+	  t_tob64(strbuf, ent->generator.data, ent->generator.len));
+}
+
+int
+BigIntegerBitLen(b)
+     BigInteger b;
+{
+  return BN_num_bits(b);
+}
+
+int
+BigIntegerCheckPrime(n)
+     BigInteger n;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  int rv = BN_is_prime(n, 25, NULL, ctx, NULL);
+  BN_CTX_free(ctx);
+  return rv;
+}
+
+unsigned int
+BigIntegerModInt(d, m)
+     BigInteger d;
+     unsigned int m;
+{
+  return BN_mod_word(d, m);
+}
+
+void
+BigIntegerMod(result, d, m)
+     BigInteger result, d, m;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  BN_mod(result, d, m, ctx);
+  BN_CTX_free(ctx);
+}
+
+void
+BigIntegerMul(result, m1, m2)
+     BigInteger result, m1, m2;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  BN_mul(result, m1, m2, ctx);
+  BN_CTX_free(ctx);
+}
+
+void
+BigIntegerLShift(result, x, bits)
+     BigInteger result, x;
+     unsigned int bits;
+{
+  BN_lshift(result, x, bits);
+}
+
+int BN_is_prime(const BIGNUM *a, int checks, void (*callback)(int,int,void *),
+	BN_CTX *ctx_passed, void *cb_arg)
+	{
+	return BN_is_prime_fasttest(a, checks, callback, ctx_passed, cb_arg, 0);
+	}
+
+int BN_is_prime_fasttest(const BIGNUM *a, int checks,
+		void (*callback)(int,int,void *),
+		BN_CTX *ctx_passed, void *cb_arg,
+		int do_trial_division)
+	{
+	int i, j, ret = -1;
+	int k;
+	BN_CTX *ctx = NULL;
+	BIGNUM *A1, *A1_odd, *check; /* taken from ctx */
+	BN_MONT_CTX *mont = NULL;
+	const BIGNUM *A = NULL;
+
+	if (checks == BN_prime_checks)
+		checks = BN_prime_checks_for_size(BN_num_bits(a));
+
+	/* first look for small factors */
+	if (!BN_is_odd(a))
+		return(0);
+	if (do_trial_division)
+		{
+		for (i = 1; i < NUMPRIMES; i++)
+			if (BN_mod_word(a, primes[i]) == 0)
+				return 0;
+		if (callback != NULL) callback(1, -1, cb_arg);
+		}
+
+	if (ctx_passed != NULL)
+		ctx = ctx_passed;
+	else
+		if ((ctx=BN_CTX_new()) == NULL)
+			goto err;
+	BN_CTX_start(ctx);
+
+	/* A := abs(a) */
+	if (a->neg)
+		{
+		BIGNUM *t;
+		if ((t = BN_CTX_get(ctx)) == NULL) goto err;
+		BN_copy(t, a);
+		t->neg = 0;
+		A = t;
+		}
+	else
+		A = a;
+	A1 = BN_CTX_get(ctx);
+	A1_odd = BN_CTX_get(ctx);
+	check = BN_CTX_get(ctx);
+	if (check == NULL) goto err;
+
+	/* compute A1 := A - 1 */
+	if (!BN_copy(A1, A))
+		goto err;
+	if (!BN_sub_word(A1, 1))
+		goto err;
+	if (BN_is_zero(A1))
+		{
+		ret = 0;
+		goto err;
+		}
+
+	/* write  A1  as  A1_odd * 2^k */
+	k = 1;
+	while (!BN_is_bit_set(A1, k))
+		k++;
+	if (!BN_rshift(A1_odd, A1, k))
+		goto err;
+
+	/* Montgomery setup for computations mod A */
+	mont = BN_MONT_CTX_new();
+	if (mont == NULL)
+		goto err;
+	if (!BN_MONT_CTX_set(mont, A, ctx))
+		goto err;
+
+	for (i = 0; i < checks; i++)
+		{
+		if (!BN_pseudo_rand(check, BN_num_bits(A1), 0, 0))
+			goto err;
+		if (BN_cmp(check, A1) >= 0)
+			if (!BN_sub(check, check, A1))
+				goto err;
+		if (!BN_add_word(check, 1))
+			goto err;
+		/* now 1 <= check < A */
+
+		j = witness(check, A, A1, A1_odd, k, ctx, mont);
+		if (j == -1) goto err;
+		if (j)
+			{
+			ret=0;
+			goto err;
+			}
+		if (callback != NULL) callback(1,i,cb_arg);
+		}
+	ret=1;
+err:
+	if (ctx != NULL)
+		{
+		BN_CTX_end(ctx);
+		if (ctx_passed == NULL)
+			BN_CTX_free(ctx);
+		}
+	if (mont != NULL)
+		BN_MONT_CTX_free(mont);
+
+	return(ret);
+	}
+
+static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
+	const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont)
+	{
+	if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) /* w := w^a1_odd mod a */
+		return -1;
+	if (BN_is_one(w))
+		return 0; /* probably prime */
+	if (BN_cmp(w, a1) == 0)
+		return 0; /* w == -1 (mod a),  'a' is probably prime */
+	while (--k)
+		{
+		if (!BN_mod_mul(w, w, w, a, ctx)) /* w := w^2 mod a */
+			return -1;
+		if (BN_is_one(w))
+			return 1; /* 'a' is composite, otherwise a previous 'w' would
+				   * have been == -1 (mod 'a') */
+		if (BN_cmp(w, a1) == 0)
+			return 0; /* w == -1 (mod a), 'a' is probably prime */
+		}
+	/* If we get here, 'w' is the (a-1)/2-th power of the original 'w',
+	 * and it is neither -1 nor +1 -- so 'a' cannot be prime */
+	return 1;
+	}
+
+int BN_mod_exp_mont(BIGNUM *rr, BIGNUM *a, const BIGNUM *p,
+		    const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
+	{
+	int i,j,bits,ret=0,wstart,wend,window,wvalue;
+	int start=1,ts=0;
+	BIGNUM *d,*r;
+	BIGNUM *aa;
+	BIGNUM val[TABLE_SIZE];
+	BN_MONT_CTX *mont=NULL;
+
+	bn_check_top(a);
+	bn_check_top(p);
+	bn_check_top(m);
+
+	if (!(m->d[0] & 1))
+		{
+		return(0);
+		}
+	bits=BN_num_bits(p);
+	if (bits == 0)
+		{
+		BN_one(rr);
+		return(1);
+		}
+	BN_CTX_start(ctx);
+	d = BN_CTX_get(ctx);
+	r = BN_CTX_get(ctx);
+	if (d == NULL || r == NULL) goto err;
+
+	/* If this is not done, things will break in the montgomery
+	 * part */
+
+	if (in_mont != NULL)
+		mont=in_mont;
+	else
+		{
+		if ((mont=BN_MONT_CTX_new()) == NULL) goto err;
+		if (!BN_MONT_CTX_set(mont,m,ctx)) goto err;
+		}
+
+	BN_init(&val[0]);
+	ts=1;
+	if (BN_ucmp(a,m) >= 0)
+		{
+		if (!BN_mod(&(val[0]),a,m,ctx))
+			goto err;
+		aa= &(val[0]);
+		}
+	else
+		aa=a;
+	if (!BN_to_montgomery(&(val[0]),aa,mont,ctx)) goto err; /* 1 */
+
+	window = BN_window_bits_for_exponent_size(bits);
+	if (window > 1)
+		{
+		if (!BN_mod_mul_montgomery(d,&(val[0]),&(val[0]),mont,ctx)) goto err; /* 2 */
+		j=1<<(window-1);
+		for (i=1; i<j; i++)
+			{
+			BN_init(&(val[i]));
+			if (!BN_mod_mul_montgomery(&(val[i]),&(val[i-1]),d,mont,ctx))
+				goto err;
+			}
+		ts=i;
+		}
+
+	start=1;        /* This is used to avoid multiplication etc
+			 * when there is only the value '1' in the
+			 * buffer. */
+	wvalue=0;       /* The 'value' of the window */
+	wstart=bits-1;  /* The top bit of the window */
+	wend=0;         /* The bottom bit of the window */
+
+	if (!BN_to_montgomery(r,BN_value_one(),mont,ctx)) goto err;
+	for (;;)
+		{
+		if (BN_is_bit_set(p,wstart) == 0)
+			{
+			if (!start)
+				{
+				if (!BN_mod_mul_montgomery(r,r,r,mont,ctx))
+				goto err;
+				}
+			if (wstart == 0) break;
+			wstart--;
+			continue;
+			}
+		/* We now have wstart on a 'set' bit, we now need to work out
+		 * how bit a window to do.  To do this we need to scan
+		 * forward until the last set bit before the end of the
+		 * window */
+		j=wstart;
+		wvalue=1;
+		wend=0;
+		for (i=1; i<window; i++)
+			{
+			if (wstart-i < 0) break;
+			if (BN_is_bit_set(p,wstart-i))
+				{
+				wvalue<<=(i-wend);
+				wvalue|=1;
+				wend=i;
+				}
+			}
+
+		/* wend is the size of the current window */
+		j=wend+1;
+		/* add the 'bytes above' */
+		if (!start)
+			for (i=0; i<j; i++)
+				{
+				if (!BN_mod_mul_montgomery(r,r,r,mont,ctx))
+					goto err;
+				}
+
+		/* wvalue will be an odd number < 2^window */
+		if (!BN_mod_mul_montgomery(r,r,&(val[wvalue>>1]),mont,ctx))
+			goto err;
+
+		/* move the 'window' down further */
+		wstart-=wend+1;
+		wvalue=0;
+		start=0;
+		if (wstart < 0) break;
+		}
+	if (!BN_from_montgomery(rr,r,mont,ctx)) goto err;
+	ret=1;
+err:
+	if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont);
+	BN_CTX_end(ctx);
+	for (i=0; i<ts; i++)
+		BN_clear_free(&(val[i]));
+	return(ret);
+	}
+
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w)
+	{
+#ifndef BN_LLONG
+	BN_ULONG ret=0;
+#else
+	BN_ULLONG ret=0;
+#endif
+	int i;
+
+	w&=BN_MASK2;
+	for (i=a->top-1; i>=0; i--)
+		{
+#ifndef BN_LLONG
+		ret=((ret<<BN_BITS4)|((a->d[i]>>BN_BITS4)&BN_MASK2l))%w;
+		ret=((ret<<BN_BITS4)|(a->d[i]&BN_MASK2l))%w;
+#else
+		ret=(BN_ULLONG)(((ret<<(BN_ULLONG)BN_BITS2)|a->d[i])%
+			(BN_ULLONG)w);
+#endif
+		}
+	return((BN_ULONG)ret);
+	}
+
+static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom)
+	{
+	unsigned char *buf=NULL;
+	int ret=0,bit,bytes,mask;
+
+	if (bits == 0)
+		{
+		BN_zero(rnd);
+		return 1;
+		}
+
+	bytes=(bits+7)/8;
+	bit=(bits-1)%8;
+	mask=0xff<<bit;
+
+	buf=(unsigned char *)malloc(bytes);
+	if (buf == NULL)
+		{
+		goto err;
+		}
+
+	/* make a random number and set the top and bottom bits */
+	/* this ignores the pseudorand flag */
+
+	t_random(buf, bytes);
+
+	if (top)
+		{
+		if (bit == 0)
+			{
+			buf[0]=1;
+			buf[1]|=0x80;
+			}
+		else
+			{
+			buf[0]|=(3<<(bit-1));
+			buf[0]&= ~(mask<<1);
+			}
+		}
+	else
+		{
+		buf[0]|=(1<<bit);
+		buf[0]&= ~(mask<<1);
+		}
+	if (bottom) /* set bottom bits to whatever odd is */
+		buf[bytes-1]|=1;
+	if (!BN_bin2bn(buf,bytes,rnd)) goto err;
+	ret=1;
+err:
+	if (buf != NULL)
+		{
+		memset(buf,0,bytes);
+		free(buf);
+		}
+	return(ret);
+	}
+
+/* BN_pseudo_rand is the same as BN_rand, now. */
+
+int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom)
+	{
+	return bnrand(1, rnd, bits, top, bottom);
+	}
+
+#define MONT_WORD /* use the faster word-based algorithm */
+
+int BN_mod_mul_montgomery(BIGNUM *r, BIGNUM *a, BIGNUM *b,
+			  BN_MONT_CTX *mont, BN_CTX *ctx)
+	{
+	BIGNUM *tmp,*tmp2;
+	int ret=0;
+
+	BN_CTX_start(ctx);
+	tmp = BN_CTX_get(ctx);
+	tmp2 = BN_CTX_get(ctx);
+	if (tmp == NULL || tmp2 == NULL) goto err;
+
+	bn_check_top(tmp);
+	bn_check_top(tmp2);
+
+	if (a == b)
+		{
+		if (!BN_sqr(tmp,a,ctx)) goto err;
+		}
+	else
+		{
+		if (!BN_mul(tmp,a,b,ctx)) goto err;
+		}
+	/* reduce from aRR to aR */
+	if (!BN_from_montgomery(r,tmp,mont,ctx)) goto err;
+	ret=1;
+err:
+	BN_CTX_end(ctx);
+	return(ret);
+	}
+
+int BN_from_montgomery(BIGNUM *ret, BIGNUM *a, BN_MONT_CTX *mont,
+	     BN_CTX *ctx)
+	{
+	int retn=0;
+
+#ifdef MONT_WORD
+	BIGNUM *n,*r;
+	BN_ULONG *ap,*np,*rp,n0,v,*nrp;
+	int al,nl,max,i,x,ri;
+
+	BN_CTX_start(ctx);
+	if ((r = BN_CTX_get(ctx)) == NULL) goto err;
+
+	if (!BN_copy(r,a)) goto err;
+	n= &(mont->N);
+
+	ap=a->d;
+	/* mont->ri is the size of mont->N in bits (rounded up
+	   to the word size) */
+	al=ri=mont->ri/BN_BITS2;
+
+	nl=n->top;
+	if ((al == 0) || (nl == 0)) { r->top=0; return(1); }
+
+	max=(nl+al+1); /* allow for overflow (no?) XXX */
+	if (bn_wexpand(r,max) == NULL) goto err;
+	if (bn_wexpand(ret,max) == NULL) goto err;
+
+	r->neg=a->neg^n->neg;
+	np=n->d;
+	rp=r->d;
+	nrp= &(r->d[nl]);
+
+	/* clear the top words of T */
+#if 1
+	for (i=r->top; i<max; i++) /* memset? XXX */
+		r->d[i]=0;
+#else
+	memset(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
+#endif
+
+	r->top=max;
+	n0=mont->n0;
+
+#ifdef BN_COUNT
+	printf("word BN_from_montgomery %d * %d\n",nl,nl);
+#endif
+	for (i=0; i<nl; i++)
+		{
+#ifdef __TANDEM
+		{
+		   long long t1;
+		   long long t2;
+		   long long t3;
+		   t1 = rp[0] * (n0 & 0177777);
+		   t2 = 037777600000l;
+		   t2 = n0 & t2;
+		   t3 = rp[0] & 0177777;
+		   t2 = (t3 * t2) & BN_MASK2;
+		   t1 = t1 + t2;
+		   v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1);
+		}
+#else
+		v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
+#endif
+		nrp++;
+		rp++;
+		if (((nrp[-1]+=v)&BN_MASK2) >= v)
+			continue;
+		else
+			{
+			if (((++nrp[0])&BN_MASK2) != 0) continue;
+			if (((++nrp[1])&BN_MASK2) != 0) continue;
+			for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ;
+			}
+		}
+	bn_fix_top(r);
+
+	/* mont->ri will be a multiple of the word size */
+#if 0
+	BN_rshift(ret,r,mont->ri);
+#else
+	ret->neg = r->neg;
+	x=ri;
+	rp=ret->d;
+	ap= &(r->d[x]);
+	if (r->top < x)
+		al=0;
+	else
+		al=r->top-x;
+	ret->top=al;
+	al-=4;
+	for (i=0; i<al; i+=4)
+		{
+		BN_ULONG t1,t2,t3,t4;
+
+		t1=ap[i+0];
+		t2=ap[i+1];
+		t3=ap[i+2];
+		t4=ap[i+3];
+		rp[i+0]=t1;
+		rp[i+1]=t2;
+		rp[i+2]=t3;
+		rp[i+3]=t4;
+		}
+	al+=4;
+	for (; i<al; i++)
+		rp[i]=ap[i];
+#endif
+#else /* !MONT_WORD */
+	BIGNUM *t1,*t2;
+
+	BN_CTX_start(ctx);
+	t1 = BN_CTX_get(ctx);
+	t2 = BN_CTX_get(ctx);
+	if (t1 == NULL || t2 == NULL) goto err;
+
+	if (!BN_copy(t1,a)) goto err;
+	BN_mask_bits(t1,mont->ri);
+
+	if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err;
+	BN_mask_bits(t2,mont->ri);
+
+	if (!BN_mul(t1,t2,&mont->N,ctx)) goto err;
+	if (!BN_add(t2,a,t1)) goto err;
+	BN_rshift(ret,t2,mont->ri);
+#endif /* MONT_WORD */
+
+	if (BN_ucmp(ret, &(mont->N)) >= 0)
+		{
+		BN_usub(ret,ret,&(mont->N));
+		}
+	retn=1;
+ err:
+	BN_CTX_end(ctx);
+	return(retn);
+	}
+
+void BN_MONT_CTX_init(BN_MONT_CTX *ctx)
+	{
+	ctx->ri=0;
+	BN_init(&(ctx->RR));
+	BN_init(&(ctx->N));
+	BN_init(&(ctx->Ni));
+	ctx->flags=0;
+	}
+
+BN_MONT_CTX *BN_MONT_CTX_new(void)
+	{
+	BN_MONT_CTX *ret;
+
+	if ((ret=(BN_MONT_CTX *)malloc(sizeof(BN_MONT_CTX))) == NULL)
+		return(NULL);
+
+	BN_MONT_CTX_init(ret);
+	ret->flags=BN_FLG_MALLOCED;
+	return(ret);
+	}
+
+void BN_MONT_CTX_free(BN_MONT_CTX *mont)
+	{
+	if(mont == NULL)
+	    return;
+
+	BN_free(&(mont->RR));
+	BN_free(&(mont->N));
+	BN_free(&(mont->Ni));
+	if (mont->flags & BN_FLG_MALLOCED)
+		free(mont);
+	}
+
+int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
+	{
+	BIGNUM Ri,*R;
+
+	BN_init(&Ri);
+	R= &(mont->RR);                                 /* grab RR as a temp */
+	BN_copy(&(mont->N),mod);                        /* Set N */
+
+#ifdef MONT_WORD
+		{
+		BIGNUM tmod;
+		BN_ULONG buf[2];
+
+		mont->ri=(BN_num_bits(mod)+(BN_BITS2-1))/BN_BITS2*BN_BITS2;
+		BN_zero(R);
+		BN_set_bit(R,BN_BITS2);                 /* R */
+
+		buf[0]=mod->d[0]; /* tmod = N mod word size */
+		buf[1]=0;
+		tmod.d=buf;
+		tmod.top=1;
+		tmod.dmax=2;
+		tmod.neg=mod->neg;
+							/* Ri = R^-1 mod N*/
+		if ((BN_mod_inverse(&Ri,R,&tmod,ctx)) == NULL)
+			goto err;
+		BN_lshift(&Ri,&Ri,BN_BITS2);            /* R*Ri */
+		if (!BN_is_zero(&Ri))
+			BN_sub_word(&Ri,1);
+		else /* if N mod word size == 1 */
+			BN_set_word(&Ri,BN_MASK2);  /* Ri-- (mod word size) */
+		BN_div(&Ri,NULL,&Ri,&tmod,ctx); /* Ni = (R*Ri-1)/N,
+						 * keep only least significant word: */
+		mont->n0=Ri.d[0];
+		BN_free(&Ri);
+		}
+#else /* !MONT_WORD */
+		{ /* bignum version */
+		mont->ri=BN_num_bits(mod);
+		BN_zero(R);
+		BN_set_bit(R,mont->ri);                 /* R = 2^ri */
+							/* Ri = R^-1 mod N*/
+		if ((BN_mod_inverse(&Ri,R,mod,ctx)) == NULL)
+			goto err;
+		BN_lshift(&Ri,&Ri,mont->ri);            /* R*Ri */
+		BN_sub_word(&Ri,1);
+							/* Ni = (R*Ri-1) / N */
+		BN_div(&(mont->Ni),NULL,&Ri,mod,ctx);
+		BN_free(&Ri);
+		}
+#endif
+
+	/* setup RR for conversions */
+	BN_zero(&(mont->RR));
+	BN_set_bit(&(mont->RR),mont->ri*2);
+	BN_mod(&(mont->RR),&(mont->RR),&(mont->N),ctx);
+
+	return(1);
+err:
+	return(0);
+	}
+
+BIGNUM *BN_value_one(void)
+	{
+	static BN_ULONG data_one=1L;
+	static BIGNUM const_one={&data_one,1,1,0};
+
+	return(&const_one);
+	}
+
+/* solves ax == 1 (mod n) */
+BIGNUM *BN_mod_inverse(BIGNUM *in, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx)
+	{
+	BIGNUM *A,*B,*X,*Y,*M,*D,*R=NULL;
+	BIGNUM *T,*ret=NULL;
+	int sign;
+
+	bn_check_top(a);
+	bn_check_top(n);
+
+	BN_CTX_start(ctx);
+	A = BN_CTX_get(ctx);
+	B = BN_CTX_get(ctx);
+	X = BN_CTX_get(ctx);
+	D = BN_CTX_get(ctx);
+	M = BN_CTX_get(ctx);
+	Y = BN_CTX_get(ctx);
+	if (Y == NULL) goto err;
+
+	if (in == NULL)
+		R=BN_new();
+	else
+		R=in;
+	if (R == NULL) goto err;
+
+	BN_zero(X);
+	BN_one(Y);
+	if (BN_copy(A,a) == NULL) goto err;
+	if (BN_copy(B,n) == NULL) goto err;
+	sign=1;
+
+	while (!BN_is_zero(B))
+		{
+		if (!BN_div(D,M,A,B,ctx)) goto err;
+		T=A;
+		A=B;
+		B=M;
+		/* T has a struct, M does not */
+
+		if (!BN_mul(T,D,X,ctx)) goto err;
+		if (!BN_add(T,T,Y)) goto err;
+		M=Y;
+		Y=X;
+		X=T;
+		sign= -sign;
+		}
+	if (sign < 0)
+		{
+		if (!BN_sub(Y,n,Y)) goto err;
+		}
+
+	if (BN_is_one(A))
+		{ if (!BN_mod(R,Y,n,ctx)) goto err; }
+	else
+		{
+		goto err;
+		}
+	ret=R;
+err:
+	if ((ret == NULL) && (in == NULL)) BN_free(R);
+	BN_CTX_end(ctx);
+	return(ret);
+	}
+
+int BN_set_bit(BIGNUM *a, int n)
+	{
+	int i,j,k;
+
+	i=n/BN_BITS2;
+	j=n%BN_BITS2;
+	if (a->top <= i)
+		{
+		if (bn_wexpand(a,i+1) == NULL) return(0);
+		for(k=a->top; k<i+1; k++)
+			a->d[k]=0;
+		a->top=i+1;
+		}
+
+	a->d[i]|=(((BN_ULONG)1)<<j);
+	return(1);
+	}
+
diff --git a/package/network/services/ead/src/tinysrp/t_conv.c b/package/network/services/ead/src/tinysrp/t_conv.c
new file mode 100644
index 0000000000..3be6d85b54
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_conv.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+/*#define _POSIX_SOURCE*/
+#include <stdio.h>
+#include "t_defines.h"
+
+static int
+hexDigitToInt(c)
+     char c;
+{
+  if(c >= '0' && c <= '9')
+    return c - '0';
+  else if(c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  else if(c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  else
+    return 0;
+}
+
+/*
+ * Convert a hex string to a string of bytes; return size of dst
+ */
+_TYPE( int )
+t_fromhex(dst, src)
+     register char *dst, *src;
+{
+  register char *chp = dst;
+  register unsigned size = strlen(src);
+
+  /* FIXME: handle whitespace and non-hex digits by setting size and src
+     appropriately. */
+
+  if(size % 2 == 1) {
+    *chp++ = hexDigitToInt(*src++);
+    --size;
+  }
+  while(size > 0) {
+    *chp++ = (hexDigitToInt(*src) << 4) | hexDigitToInt(*(src + 1));
+    src += 2;
+    size -= 2;
+  }
+  return chp - dst;
+}
+
+/*
+ * Convert a string of bytes to their hex representation
+ */
+_TYPE( char * )
+t_tohex(dst, src, size)
+     register char *dst, *src;
+     register unsigned size;
+{
+   int notleading = 0;
+
+   register char *chp = dst;
+   if (size != 0) do {
+      if(notleading || *src != '\0') {
+	notleading = 1;
+	sprintf(chp, "%.2x", * (unsigned char *) src);
+	chp += 2;
+      }
+      ++src;
+   } while (--size != 0);
+   return dst;
+}
+
+static char b64table[] =
+  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
+
+/*
+ * Convert a base64 string into raw byte array representation.
+ */
+_TYPE( int )
+t_fromb64(dst, src)
+     register char *dst, *src;
+{
+  unsigned char *a;
+  char *loc;
+  int i, j;
+  unsigned int size;
+
+  while(*src && (*src == ' ' || *src == '\t' || *src == '\n'))
+      ++src;
+  size = strlen(src);
+
+  a = malloc((size + 1) * sizeof(unsigned char));
+  if(a == (unsigned char *) 0)
+    return -1;
+
+  i = 0;
+  while(i < size) {
+    loc = strchr(b64table, src[i]);
+    if(loc == (char *) 0)
+      break;
+    else
+      a[i] = loc - b64table;
+    ++i;
+  }
+  size = i;
+
+  i = size - 1;
+  j = size;
+  while(1) {
+    a[j] = a[i];
+    if(--i < 0)
+      break;
+    a[j] |= (a[i] & 3) << 6;
+    --j;
+    a[j] = (unsigned char) ((a[i] & 0x3c) >> 2);
+    if(--i < 0)
+      break;
+    a[j] |= (a[i] & 0xf) << 4;
+    --j;
+    a[j] = (unsigned char) ((a[i] & 0x30) >> 4);
+    if(--i < 0)
+      break;
+    a[j] |= (a[i] << 2);
+
+    a[--j] = 0;
+    if(--i < 0)
+      break;
+  }
+
+  while(j <= size && a[j] == 0)
+    ++j;
+
+  memcpy(dst, a + j, size - j + 1);
+  free(a);
+  return size - j + 1;
+}
+
+/*
+ * Convert a raw byte string into a null-terminated base64 ASCII string.
+ */
+_TYPE( char * )
+t_tob64(dst, src, size)
+     register char *dst, *src;
+     register unsigned size;
+{
+  int c, pos = size % 3;
+  unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0;
+  char *olddst = dst;
+
+  switch(pos) {
+  case 1:
+    b2 = src[0];
+    break;
+  case 2:
+    b1 = src[0];
+    b2 = src[1];
+    break;
+  }
+
+  while(1) {
+    c = (b0 & 0xfc) >> 2;
+    if(notleading || c != 0) {
+      *dst++ = b64table[c];
+      notleading = 1;
+    }
+    c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4);
+    if(notleading || c != 0) {
+      *dst++ = b64table[c];
+      notleading = 1;
+    }
+    c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6);
+    if(notleading || c != 0) {
+      *dst++ = b64table[c];
+      notleading = 1;
+    }
+    c = b2 & 0x3f;
+    if(notleading || c != 0) {
+      *dst++ = b64table[c];
+      notleading = 1;
+    }
+    if(pos >= size)
+      break;
+    else {
+      b0 = src[pos++];
+      b1 = src[pos++];
+      b2 = src[pos++];
+    }
+  }
+
+  *dst++ = '\0';
+  return olddst;
+}
diff --git a/package/network/services/ead/src/tinysrp/t_defines.h b/package/network/services/ead/src/tinysrp/t_defines.h
new file mode 100644
index 0000000000..4128093f60
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_defines.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#ifndef T_DEFINES_H
+#define T_DEFINES_H
+
+#ifndef P
+#if defined(__STDC__) || defined(__cplusplus)
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef _DLLDECL
+#define _DLLDECL
+
+#ifdef MSVC15   /* MSVC1.5 support for 16 bit apps */
+#define _MSVC15EXPORT _export
+#define _MSVC20EXPORT
+#define _DLLAPI _export _pascal
+#define _TYPE(a) a _MSVC15EXPORT
+#define DLLEXPORT 1
+
+#elif MSVC20
+#define _MSVC15EXPORT
+#define _MSVC20EXPORT _declspec(dllexport)
+#define _DLLAPI
+#define _TYPE(a) _MSVC20EXPORT a
+#define DLLEXPORT 1
+
+#else                   /* Default, non-dll.  Use this for Unix or DOS */
+#define _MSVC15DEXPORT
+#define _MSVC20EXPORT
+#define _DLLAPI
+#define _TYPE(a) a
+#endif
+#endif
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* not STDC_HEADERS */
+#ifndef HAVE_STRCHR
+#define strchr index
+#define strrchr rindex
+#endif
+char *strchr(), *strrchr(), *strtok();
+#ifndef HAVE_MEMCPY
+#define memcpy(d, s, n) bcopy((s), (d), (n))
+#endif
+#endif /* not STDC_HEADERS */
+
+#include <sys/types.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else  /* not TIME_WITH_SYS_TIME */
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif /* not TIME_WITH_SYS_TIME */
+
+#if HAVE_TERMIOS_H
+#include <termios.h>
+#define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio)
+#define GTTY(fd, termio) tcgetattr(fd, termio)
+#define TERMIO struct termios
+#define USE_TERMIOS
+#elif HAVE_TERMIO_H
+#include <sys/ioctl.h>
+#include <termio.h>
+#define STTY(fd, termio) ioctl(fd, TCSETA, termio)
+#define GTTY(fd, termio) ioctl(fd, TCGETA, termio)
+#define TEMRIO struct termio
+#define USE_TERMIO
+#elif HAVE_SGTTY_H
+#include <sgtty.h>
+#define STTY(fd, termio) stty(fd, termio)
+#define GTTY(fd, termio) gtty(fd, termio)
+#define TERMIO struct sgttyb
+#define USE_SGTTY
+#endif
+
+#ifdef USE_FTIME
+#include <sys/timeb.h>
+#endif
+
+#ifndef MATH_PRIV
+typedef void * BigInteger;
+#endif
+
+_TYPE( BigInteger ) BigIntegerFromInt P((unsigned int number));
+_TYPE( BigInteger ) BigIntegerFromBytes P((unsigned char * bytes, int length));
+_TYPE( int ) BigIntegerToBytes P((BigInteger src, unsigned char * dest));
+_TYPE( int ) BigIntegerBitLen P((BigInteger b));
+_TYPE( int ) BigIntegerCmp P((BigInteger c1, BigInteger c2));
+_TYPE( int ) BigIntegerCmpInt P((BigInteger c1, unsigned int c2));
+_TYPE( void ) BigIntegerLShift P((BigInteger result, BigInteger x,
+				unsigned int bits));
+_TYPE( void ) BigIntegerAdd P((BigInteger result, BigInteger a1, BigInteger a2));
+_TYPE( void ) BigIntegerAddInt P((BigInteger result,
+				BigInteger a1, unsigned int a2));
+_TYPE( void ) BigIntegerSub P((BigInteger result, BigInteger s1, BigInteger s2));
+_TYPE( void ) BigIntegerSubInt P((BigInteger result,
+				BigInteger s1, unsigned int s2));
+/* For BigIntegerMul{,Int}: result != m1, m2 */
+_TYPE( void ) BigIntegerMul P((BigInteger result, BigInteger m1, BigInteger m2));
+_TYPE( void ) BigIntegerMulInt P((BigInteger result,
+				BigInteger m1, unsigned int m2));
+_TYPE( void ) BigIntegerDivInt P((BigInteger result,
+				BigInteger d, unsigned int m));
+_TYPE( void ) BigIntegerMod P((BigInteger result, BigInteger d, BigInteger m));
+_TYPE( unsigned int ) BigIntegerModInt P((BigInteger d, unsigned int m));
+_TYPE( void ) BigIntegerModMul P((BigInteger result,
+				BigInteger m1, BigInteger m2, BigInteger m));
+_TYPE( void ) BigIntegerModExp P((BigInteger result, BigInteger base,
+				BigInteger expt, BigInteger modulus));
+_TYPE( void ) BigIntegerModExpInt P((BigInteger result, BigInteger base,
+				   unsigned int expt, BigInteger modulus));
+_TYPE( int ) BigIntegerCheckPrime P((BigInteger n));
+_TYPE( void ) BigIntegerFree P((BigInteger b));
+
+#endif
diff --git a/package/network/services/ead/src/tinysrp/t_getconf.c b/package/network/services/ead/src/tinysrp/t_getconf.c
new file mode 100644
index 0000000000..db6de6171f
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_getconf.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_read.h"
+
+/* Master builtin parameter storage object.  The default that tphrase
+uses is the last one. */
+
+static struct pre_struct {
+  struct t_preconf preconf;
+  int state;    /* 0 == uninitialized/first time */
+  unsigned char modbuf[MAXPARAMLEN];
+  unsigned char genbuf[MAXPARAMLEN];
+} pre_params[] = {
+  { { "2iQzj1CagQc/5ctbuJYLWlhtAsPHc7xWVyCPAKFRLWKADpASkqe9djWPFWTNTdeJtL8nAhImCn3Sr/IAdQ1FrGw0WvQUstPx3FO9KNcXOwisOQ1VlL.gheAHYfbYyBaxXL.NcJx9TUwgWDT0hRzFzqSrdGGTN3FgSTA1v4QnHtEygNj3eZ.u0MThqWUaDiP87nqha7XnT66bkTCkQ8.7T8L4KZjIImrNrUftedTTBi.WCi.zlrBxDuOM0da0JbUkQlXqvp0yvJAPpC11nxmmZOAbQOywZGmu9nhZNuwTlxjfIro0FOdthaDTuZRL9VL7MRPUDo/DQEyW.d4H.UIlzp",
+      "2",
+      NULL }, 0 },
+  { { "dUyyhxav9tgnyIg65wHxkzkb7VIPh4o0lkwfOKiPp4rVJrzLRYVBtb76gKlaO7ef5LYGEw3G.4E0jbMxcYBetDy2YdpiP/3GWJInoBbvYHIRO9uBuxgsFKTKWu7RnR7yTau/IrFTdQ4LY/q.AvoCzMxV0PKvD9Odso/LFIItn8PbTov3VMn/ZEH2SqhtpBUkWtmcIkEflhX/YY/fkBKfBbe27/zUaKUUZEUYZ2H2nlCL60.JIPeZJSzsu/xHDVcx",
+      "2",
+      NULL }, 0 },
+  { { "3NUKQ2Re4P5BEK0TLg2dX3gETNNNECPoe92h4OVMaDn3Xo/0QdjgG/EvM.hiVV1BdIGklSI14HA38Mpe5k04juR5/EXMU0r1WtsLhNXwKBlf2zEfoOh0zVmDvqInpU695f29Iy7sNW3U5RIogcs740oUp2Kdv5wuITwnIx84cnO.e467/IV1lPnvMCr0pd1dgS0a.RV5eBJr03Q65Xy61R",
+      "2",
+      NULL }, 0 },
+  { { "F//////////oG/QeY5emZJ4ncABWDmSqIa2JWYAPynq0Wk.fZiJco9HIWXvZZG4tU.L6RFDEaCRC2iARV9V53TFuJLjRL72HUI5jNPYNdx6z4n2wQOtxMiB/rosz0QtxUuuQ/jQYP.bhfya4NnB7.P9A6PHxEPJWV//////////",
+      "5",
+      "oakley prime 2" }, 0 },
+  { { "Ewl2hcjiutMd3Fu2lgFnUXWSc67TVyy2vwYCKoS9MLsrdJVT9RgWTCuEqWJrfB6uE3LsE9GkOlaZabS7M29sj5TnzUqOLJMjiwEzArfiLr9WbMRANlF68N5AVLcPWvNx6Zjl3m5Scp0BzJBz9TkgfhzKJZ.WtP3Mv/67I/0wmRZ",
+      "2",
+      NULL }, 0 },
+};
+
+_TYPE( int )
+t_getprecount()
+{
+  return (sizeof(pre_params) / sizeof(struct pre_struct));
+}
+
+static struct t_confent sysconf;
+
+/* id is index origin 1 */
+
+_TYPE( struct t_confent * )
+gettcid
+(id)
+     int id;
+{
+	struct t_preconf *tcp;
+
+	if (id <= 0 || id > t_getprecount()) {
+		return NULL;
+	}
+	tcp = t_getpreparam(id - 1);
+	sysconf.index = id;
+	sysconf.modulus = tcp->modulus;
+	sysconf.generator = tcp->generator;
+
+	return &sysconf;
+}
+
+_TYPE( struct t_preconf * )
+t_getpreparam(idx)
+     int idx;
+{
+  if(pre_params[idx].state == 0) {
+    /* Wire up storage */
+    pre_params[idx].preconf.modulus.data = pre_params[idx].modbuf;
+    pre_params[idx].preconf.generator.data = pre_params[idx].genbuf;
+
+    /* Convert from b64 to t_num */
+    pre_params[idx].preconf.modulus.len = t_fromb64(pre_params[idx].preconf.modulus.data, pre_params[idx].preconf.mod_b64);
+    pre_params[idx].preconf.generator.len = t_fromb64(pre_params[idx].preconf.generator.data, pre_params[idx].preconf.gen_b64);
+
+    pre_params[idx].state = 1;
+  }
+  return &(pre_params[idx].preconf);
+}
diff --git a/package/network/services/ead/src/tinysrp/t_getpass.c b/package/network/services/ead/src/tinysrp/t_getpass.c
new file mode 100644
index 0000000000..6ae7fca4de
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_getpass.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 1990 - 1995, Julianne Frances Haugh
+ * 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.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH 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 JULIE HAUGH 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.
+ */
+
+#include "t_defines.h"
+#ifdef _WIN32
+#include <windows.h>
+#include <io.h>
+#endif /* _WIN32 */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <signal.h>
+#include <stdio.h>
+
+static  int     sig_caught;
+#ifdef HAVE_SIGACTION
+static  struct  sigaction sigact;
+#endif
+
+/*ARGSUSED*/
+static RETSIGTYPE
+sig_catch (sig)
+int     sig;
+{
+	sig_caught = 1;
+}
+
+_TYPE( int )
+t_getpass (buf, maxlen, prompt)
+	char *buf;
+	unsigned maxlen;
+	const char *prompt;
+{
+	char    *cp;
+#ifdef _WIN32
+    HANDLE handle = (HANDLE) _get_osfhandle(_fileno(stdin));
+    DWORD  mode;
+
+    GetConsoleMode( handle, &mode );
+    SetConsoleMode( handle, mode & ~ENABLE_ECHO_INPUT );
+
+    if(fputs(prompt, stdout) == EOF ||
+	fgets(buf, maxlen, stdin) == NULL) {
+	SetConsoleMode(handle,mode);
+	return -1;
+    }
+    cp = buf + strlen(buf) - 1;
+    if ( *cp == 0x0a )
+	*cp = '\0';
+    printf("\n");
+    SetConsoleMode(handle,mode);
+#else
+	FILE    *fp;
+	int     tty_opened = 0;
+
+#ifdef HAVE_SIGACTION
+	struct  sigaction old_sigact;
+#else
+	RETSIGTYPE      (*old_signal)();
+#endif
+	TERMIO  new_modes;
+	TERMIO  old_modes;
+
+	/*
+	 * set a flag so the SIGINT signal can be re-sent if it
+	 * is caught
+	 */
+
+	sig_caught = 0;
+
+	/*
+	 * if /dev/tty can't be opened, getpass() needs to read
+	 * from stdin instead.
+	 */
+
+	if ((fp = fopen ("/dev/tty", "r")) == 0) {
+		fp = stdin;
+		setbuf (fp, (char *) 0);
+	} else {
+		tty_opened = 1;
+	}
+
+	/*
+	 * the current tty modes must be saved so they can be
+	 * restored later on.  echo will be turned off, except
+	 * for the newline character (BSD has to punt on this)
+	 */
+
+	if (GTTY (fileno (fp), &new_modes))
+		return -1;
+
+	old_modes = new_modes;
+
+#ifdef HAVE_SIGACTION
+	sigact.sa_handler = sig_catch;
+	(void) sigaction (SIGINT, &sigact, &old_sigact);
+#else
+	old_signal = signal (SIGINT, sig_catch);
+#endif
+
+#ifdef USE_SGTTY
+	new_modes.sg_flags &= ~ECHO;
+#else
+	new_modes.c_iflag &= ~IGNCR;
+	new_modes.c_iflag |= ICRNL;
+	new_modes.c_oflag |= OPOST|ONLCR;
+	new_modes.c_lflag &= ~(ECHO|ECHOE|ECHOK);
+	new_modes.c_lflag |= ICANON|ECHONL;
+#endif
+
+	if (STTY (fileno (fp), &new_modes))
+		goto out;
+
+	/*
+	 * the prompt is output, and the response read without
+	 * echoing.  the trailing newline must be removed.  if
+	 * the fgets() returns an error, a NULL pointer is
+	 * returned.
+	 */
+
+	if (fputs (prompt, stdout) == EOF)
+		goto out;
+
+	(void) fflush (stdout);
+
+	if (fgets (buf, maxlen, fp) == buf) {
+		if ((cp = strchr (buf, '\n')))
+			*cp = '\0';
+		else
+			buf[maxlen - 1] = '\0';
+
+#ifdef USE_SGTTY
+		putc ('\n', stdout);
+#endif
+	}
+	else buf[0] = '\0';
+out:
+	/*
+	 * the old SIGINT handler is restored after the tty
+	 * modes.  then /dev/tty is closed if it was opened in
+	 * the beginning.  finally, if a signal was caught it
+	 * is sent to this process for normal processing.
+	 */
+
+	if (STTY (fileno (fp), &old_modes))
+	{ memset (buf, 0, maxlen); return -1; }
+
+#ifdef HAVE_SIGACTION
+	(void) sigaction (SIGINT, &old_sigact, NULL);
+#else
+	(void) signal (SIGINT, old_signal);
+#endif
+
+	if (tty_opened)
+		(void) fclose (fp);
+
+	if (sig_caught) {
+		kill (getpid (), SIGINT);
+		memset (buf, 0, maxlen);
+		return -1;
+	}
+#endif
+
+	return 0;
+}
diff --git a/package/network/services/ead/src/tinysrp/t_math.c b/package/network/services/ead/src/tinysrp/t_math.c
new file mode 100644
index 0000000000..20161a0112
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_math.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "config.h"
+
+#include "bn.h"
+typedef BIGNUM * BigInteger;
+#define MATH_PRIV
+
+#include "t_defines.h"
+#include "t_pwd.h"
+
+/* Math library interface stubs */
+
+BigInteger
+BigIntegerFromInt(n)
+     unsigned int n;
+{
+  BIGNUM * a = BN_new();
+  BN_set_word(a, n);
+  return a;
+}
+
+BigInteger
+BigIntegerFromBytes(bytes, length)
+     unsigned char * bytes;
+     int length;
+{
+  BIGNUM * a = BN_new();
+  BN_bin2bn(bytes, length, a);
+  return a;
+}
+
+int
+BigIntegerToBytes(src, dest)
+     BigInteger src;
+     unsigned char * dest;
+{
+  return BN_bn2bin(src, dest);
+}
+
+int
+BigIntegerCmp(c1, c2)
+     BigInteger c1, c2;
+{
+  return BN_cmp(c1, c2);
+}
+
+int
+BigIntegerCmpInt(c1, c2)
+     BigInteger c1;
+     unsigned int c2;
+{
+  BIGNUM * a = BN_new();
+  int rv;
+  BN_set_word(a, c2);
+  rv = BN_cmp(c1, a);
+  BN_free(a);
+  return rv;
+}
+
+void
+BigIntegerAdd(result, a1, a2)
+     BigInteger result, a1, a2;
+{
+  BN_add(result, a1, a2);
+}
+
+void
+BigIntegerAddInt(result, a1, a2)
+     BigInteger result, a1;
+     unsigned int a2;
+{
+  BIGNUM * a = BN_new();
+  BN_set_word(a, a2);
+  BN_add(result, a1, a);
+  BN_free(a);
+}
+
+void
+BigIntegerSub(result, s1, s2)
+     BigInteger result, s1, s2;
+{
+  BN_sub(result, s1, s2);
+}
+
+void
+BigIntegerMulInt(result, m1, m2)
+     BigInteger result, m1;
+     unsigned int m2;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  BIGNUM * m = BN_new();
+  BN_set_word(m, m2);
+  BN_mul(result, m1, m, ctx);
+  BN_CTX_free(ctx);
+}
+
+void
+BigIntegerModMul(r, m1, m2, modulus)
+     BigInteger r, m1, m2, modulus;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  BN_mod_mul(r, m1, m2, modulus, ctx);
+  BN_CTX_free(ctx);
+}
+
+void
+BigIntegerModExp(r, b, e, m)
+     BigInteger r, b, e, m;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  BN_mod_exp(r, b, e, m, ctx);
+  BN_CTX_free(ctx);
+}
+
+void
+BigIntegerModExpInt(r, b, e, m)
+     BigInteger r, b;
+     unsigned int e;
+     BigInteger m;
+{
+  BN_CTX * ctx = BN_CTX_new();
+  BIGNUM * p = BN_new();
+  BN_set_word(p, e);
+  BN_mod_exp(r, b, p, m, ctx);
+  BN_free(p);
+  BN_CTX_free(ctx);
+}
+
+void
+BigIntegerFree(b)
+     BigInteger b;
+{
+  BN_free(b);
+}
diff --git a/package/network/services/ead/src/tinysrp/t_misc.c b/package/network/services/ead/src/tinysrp/t_misc.c
new file mode 100644
index 0000000000..a23986f90f
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_misc.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include "t_defines.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "t_sha.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static unsigned char randpool[SHA_DIGESTSIZE], randout[SHA_DIGESTSIZE];
+static unsigned long randcnt = 0;
+static unsigned int outpos = 0;
+SHA1_CTX randctxt;
+
+/*
+ * t_envhash - Generate a 160-bit SHA hash of the environment
+ *
+ * This routine performs an SHA hash of all the "name=value" pairs
+ * in the environment concatenated together and dumps them in the
+ * output.  While it is true that anyone on the system can see
+ * your environment, someone not on the system will have a very
+ * difficult time guessing it, especially since some systems play
+ * tricks with variable ordering and sometimes define quirky
+ * environment variables like $WINDOWID or $_.
+ */
+extern char ** environ;
+
+static void
+t_envhash(out)
+     unsigned char * out;
+{
+  char ** ptr;
+  char ebuf[256];
+  SHA1_CTX ctxt;
+
+  SHA1Init(&ctxt);
+  for(ptr = environ; *ptr; ++ptr) {
+    strncpy(ebuf, *ptr, 255);
+    ebuf[255] = '\0';
+    SHA1Update(&ctxt, ebuf, strlen(ebuf));
+  }
+  SHA1Final(out, &ctxt);
+}
+
+/*
+ * t_fshash - Generate a 160-bit SHA hash from the file system
+ *
+ * This routine climbs up the directory tree from the current
+ * directory, running stat() on each directory until it hits the
+ * root directory.  This information is sensitive to the last
+ * access/modification times of all the directories above you,
+ * so someone who lists one of those directories injects some
+ * entropy into the system.  Obviously, this hash is very sensitive
+ * to your current directory when the program is run.
+ *
+ * For good measure, it also performs an fstat on the standard input,
+ * usually your tty, throws that into the buffer, creates a file in
+ * /tmp (the inode is unpredictable on a busy system), and runs stat()
+ * on that before deleting it.
+ *
+ * The entire buffer is run once through SHA to obtain the final result.
+ */
+static void
+t_fshash(out)
+     unsigned char * out;
+{
+  char dotpath[128];
+  struct stat st;
+  SHA1_CTX ctxt;
+  int i, pinode;
+  dev_t pdev;
+
+  SHA1Init(&ctxt);
+  if(stat(".", &st) >= 0) {
+    SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+    pinode = st.st_ino;
+    pdev = st.st_dev;
+    strcpy(dotpath, "..");
+    for(i = 0; i < 40; ++i) {
+      if(stat(dotpath, &st) < 0)
+	break;
+      if(st.st_ino == pinode && st.st_dev == pdev)
+	break;
+      SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+      pinode = st.st_ino;
+      pdev = st.st_dev;
+      strcat(dotpath, "/..");
+    }
+  }
+
+  if(fstat(0, &st) >= 0)
+    SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+
+  sprintf(dotpath, "/tmp/rnd.%d", getpid());
+  if(creat(dotpath, 0600) >= 0 && stat(dotpath, &st) >= 0)
+    SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st));
+  unlink(dotpath);
+
+  SHA1Final(out, &ctxt);
+}
+
+/*
+ * Generate a high-entropy seed for the strong random number generator.
+ * This uses a wide variety of quickly gathered and somewhat unpredictable
+ * system information.  The 'preseed' structure is assembled from:
+ *
+ *   The system time in seconds
+ *   The system time in microseconds
+ *   The current process ID
+ *   The parent process ID
+ *   A hash of the user's environment
+ *   A hash gathered from the file system
+ *   Input from a random device, if available
+ *   Timings of system interrupts
+ *
+ * The entire structure (60 bytes on most systems) is fed to SHA to produce
+ * a 160-bit seed for the strong random number generator.  It is believed
+ * that in the worst case (on a quiet system with no random device versus
+ * an attacker who has access to the system already), the seed contains at
+ * least about 80 bits of entropy.  Versus an attacker who does not have
+ * access to the system, the entropy should be slightly over 128 bits.
+ */
+static char initialized = 0;
+
+static struct {
+  unsigned int trand1;
+  time_t sec;
+  time_t usec;
+  short pid;
+  short ppid;
+  unsigned char envh[SHA_DIGESTSIZE];
+  unsigned char fsh[SHA_DIGESTSIZE];
+  unsigned char devrand[20];
+  unsigned int trand2;
+} preseed;
+
+unsigned long raw_truerand();
+
+void
+t_initrand()
+{
+  SHA1_CTX ctxt;
+#ifdef USE_FTIME
+  struct timeb t;
+#else
+  struct timeval t;
+#endif
+  int i, r=0;
+
+  if(initialized)
+    return;
+
+  initialized = 1;
+
+  i = open("/dev/urandom", O_RDONLY);
+  if(i > 0) {
+    r += read(i, preseed.devrand, sizeof(preseed.devrand));
+    close(i);
+  }
+
+  /* Resort to truerand only if desperate for some Real entropy */
+  if(r == 0)
+    preseed.trand1 = raw_truerand();
+
+#ifdef USE_FTIME
+  ftime(&t);
+#else
+  gettimeofday(&t, NULL);
+#endif
+
+#ifdef USE_FTIME
+  preseed.sec = t.time;
+  preseed.usec = t.millitm;
+#else
+  preseed.sec = t.tv_sec;
+  preseed.usec = t.tv_usec;
+#endif
+  preseed.pid = getpid();
+  preseed.ppid = getppid();
+  t_envhash(preseed.envh);
+  t_fshash(preseed.fsh);
+
+  if(r == 0)
+    preseed.trand2 = raw_truerand();
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, (unsigned char *) &preseed, sizeof(preseed));
+  SHA1Final(randpool, &ctxt);
+  outpos = 0;
+  memset((unsigned char *) &preseed, 0, sizeof(preseed));
+  memset((unsigned char *) &ctxt, 0, sizeof(ctxt));
+}
+
+#define NUM_RANDOMS 12
+
+/*
+ * The strong random number generator.  This uses a 160-bit seed
+ * and uses SHA-1 in a feedback configuration to generate successive
+ * outputs.  If S[0] is set to the initial seed, then:
+ *
+ *         S[i+1] = SHA-1(i || S[i])
+ *         A[i] = SHA-1(S[i])
+ *
+ * where the A[i] are the output blocks starting with i=0.
+ * Each cycle generates 20 bytes of new output.
+ */
+_TYPE( void )
+t_random(data, size)
+     unsigned char * data;
+     unsigned size;
+{
+  if(!initialized)
+    t_initrand();
+
+  if(size <= 0)         /* t_random(NULL, 0) forces seed initialization */
+    return;
+
+  while(size > outpos) {
+    if(outpos > 0) {
+      memcpy(data, randout + (sizeof(randout) - outpos), outpos);
+      data += outpos;
+      size -= outpos;
+    }
+
+    /* Recycle */
+    SHA1Init(&randctxt);
+    SHA1Update(&randctxt, randpool, sizeof(randpool));
+    SHA1Final(randout, &randctxt);
+    SHA1Init(&randctxt);
+    SHA1Update(&randctxt, (unsigned char *) &randcnt, sizeof(randcnt));
+    SHA1Update(&randctxt, randpool, sizeof(randpool));
+    SHA1Final(randpool, &randctxt);
+    ++randcnt;
+    outpos = sizeof(randout);
+  }
+
+  if(size > 0) {
+    memcpy(data, randout + (sizeof(randout) - outpos), size);
+    outpos -= size;
+  }
+}
+
+/*
+ * The interleaved session-key hash.  This separates the even and the odd
+ * bytes of the input (ignoring the first byte if the input length is odd),
+ * hashes them separately, and re-interleaves the two outputs to form a
+ * single 320-bit value.
+ */
+_TYPE( unsigned char * )
+t_sessionkey(key, sk, sklen)
+     unsigned char * key;
+     unsigned char * sk;
+     unsigned sklen;
+{
+  unsigned i, klen;
+  unsigned char * hbuf;
+  unsigned char hout[SHA_DIGESTSIZE];
+  SHA1_CTX ctxt;
+
+  while(sklen > 0 && *sk == 0) {        /* Skip leading 0's */
+    --sklen;
+    ++sk;
+  }
+
+  klen = sklen / 2;
+  if((hbuf = malloc(klen * sizeof(char))) == 0)
+    return 0;
+
+  for(i = 0; i < klen; ++i)
+    hbuf[i] = sk[sklen - 2 * i - 1];
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, hbuf, klen);
+  SHA1Final(hout, &ctxt);
+  for(i = 0; i < sizeof(hout); ++i)
+    key[2 * i] = hout[i];
+
+  for(i = 0; i < klen; ++i)
+    hbuf[i] = sk[sklen - 2 * i - 2];
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, hbuf, klen);
+  SHA1Final(hout, &ctxt);
+  for(i = 0; i < sizeof(hout); ++i)
+    key[2 * i + 1] = hout[i];
+
+  memset(hout, 0, sizeof(hout));
+  memset(hbuf, 0, klen);
+  free(hbuf);
+  return key;
+}
diff --git a/package/network/services/ead/src/tinysrp/t_pw.c b/package/network/services/ead/src/tinysrp/t_pw.c
new file mode 100644
index 0000000000..18e929bb79
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_pw.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1997-2000  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include "t_defines.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef USE_HOMEDIR
+#include <pwd.h>
+#endif
+#ifdef WIN32
+#include <io.h>
+#endif
+
+#include "t_pwd.h"
+#include "t_read.h"
+#include "t_sha.h"
+#include "t_server.h"
+
+static struct t_pw * syspw = NULL;
+static struct t_passwd tpass;
+
+_TYPE( struct t_server * )
+t_serveropen(username)
+     const char * username;
+{
+  struct t_passwd * p;
+  p = gettpnam(username);
+  if(p == NULL) {
+    return NULL;
+  } else {
+    return t_serveropenraw(&p->tp, &p->tc);
+  }
+}
+
+
+/* t_openpw(NULL) is deprecated - use settpent()/gettpnam() instead */
+
+_TYPE( struct t_pw * )
+t_openpw(fp)
+     FILE * fp;
+{
+  struct t_pw * tpw;
+  char close_flag = 0;
+
+  if(fp == NULL) { /* Deprecated */
+    if((fp = fopen(DEFAULT_PASSWD, "r")) == NULL)
+      return NULL;
+    close_flag = 1;
+  }
+  else
+    close_flag = 0;
+
+  if((tpw = malloc(sizeof(struct t_pw))) == NULL)
+    return NULL;
+  tpw->instream = fp;
+  tpw->close_on_exit = close_flag;
+  tpw->state = FILE_ONLY;
+
+  return tpw;
+}
+
+_TYPE( struct t_pw * )
+t_openpwbyname(pwname)
+     const char * pwname;
+{
+  FILE * fp;
+  struct t_pw * t;
+
+  if(pwname == NULL)            /* Deprecated */
+    return t_openpw(NULL);
+
+  if((fp = fopen(pwname, "r")) == NULL)
+    return NULL;
+
+  t = t_openpw(fp);
+  t->close_on_exit = 1;
+  return t;
+}
+
+_TYPE( void )
+t_closepw(tpw)
+     struct t_pw * tpw;
+{
+  if(tpw->close_on_exit)
+    fclose(tpw->instream);
+  free(tpw);
+}
+
+_TYPE( void )
+t_rewindpw(tpw)
+     struct t_pw * tpw;
+{
+#ifdef ENABLE_YP
+  if(tpw->state == IN_NIS)
+    tpw->state = FILE_NIS;
+#endif
+  rewind(tpw->instream);
+}
+
+#ifdef ENABLE_YP
+static void
+savepwent(tpw, pwent)
+     struct t_pw * tpw;
+     struct t_pwent *pwent;
+{
+  tpw->pebuf.name = tpw->userbuf;
+  tpw->pebuf.password.data = tpw->pwbuf;
+  tpw->pebuf.salt.data = tpw->saltbuf;
+  strcpy(tpw->pebuf.name, pwent->name);
+  tpw->pebuf.password.len = pwent->password.len;
+  memcpy(tpw->pebuf.password.data, pwent->password.data, pwent->password.len);
+  tpw->pebuf.salt.len = pwent->salt.len;
+  memcpy(tpw->pebuf.salt.data, pwent->salt.data, pwent->salt.len);
+  tpw->pebuf.index = pwent->index;
+}
+#endif /* ENABLE_YP */
+
+_TYPE( struct t_pwent * )
+t_getpwbyname(tpw, user)
+     struct t_pw * tpw;
+     const char * user;
+{
+  char indexbuf[16];
+  char passbuf[MAXB64PARAMLEN];
+  char saltstr[MAXB64SALTLEN];
+  char username[MAXUSERLEN];
+#ifdef ENABLE_YP
+  struct t_passwd * nisent;
+#endif
+
+  t_rewindpw(tpw);
+
+  while(t_nextfield(tpw->instream, username, MAXUSERLEN) > 0) {
+#ifdef ENABLE_YP
+    if(tpw->state == FILE_NIS && *username == '+') {
+      if(strlen(username) == 1 || strcmp(user, username+1) == 0) {
+	nisent = _yp_gettpnam(user);    /* Entry is +username or + */
+	if(nisent != NULL) {
+	  savepwent(tpw, &nisent->tp);
+	  return &tpw->pebuf;
+	}
+      }
+    }
+#endif
+    if(strcmp(user, username) == 0)
+      if(t_nextfield(tpw->instream, passbuf, MAXB64PARAMLEN) > 0 &&
+	 (tpw->pebuf.password.len = t_fromb64(tpw->pwbuf, passbuf)) > 0 &&
+	 t_nextfield(tpw->instream, saltstr, MAXB64SALTLEN) > 0 &&
+	 (tpw->pebuf.salt.len = t_fromb64(tpw->saltbuf, saltstr)) > 0 &&
+	 t_nextfield(tpw->instream, indexbuf, 16) > 0 &&
+	 (tpw->pebuf.index = atoi(indexbuf)) > 0) {
+	strcpy(tpw->userbuf, username);
+	tpw->pebuf.name = tpw->userbuf;
+	tpw->pebuf.password.data = tpw->pwbuf;
+	tpw->pebuf.salt.data = tpw->saltbuf;
+	t_nextline(tpw->instream);
+	return &tpw->pebuf;
+      }
+    if(t_nextline(tpw->instream) < 0)
+      return NULL;
+  }
+  return NULL;
+}
+
+/* System password file accessors */
+
+static int
+pwinit()
+{
+  if(syspw == NULL) {
+    if((syspw = t_openpwbyname(DEFAULT_PASSWD)) == NULL)
+      return -1;
+    syspw->state = FILE_NIS;
+  }
+  return 0;
+}
+
+static void
+pwsetup(out, tpwd, tcnf)
+     struct t_passwd * out;
+     struct t_pwent * tpwd;
+     struct t_confent * tcnf;
+{
+  out->tp.name = tpwd->name;
+  out->tp.password.len = tpwd->password.len;
+  out->tp.password.data = tpwd->password.data;
+  out->tp.salt.len = tpwd->salt.len;
+  out->tp.salt.data = tpwd->salt.data;
+  out->tp.index = tpwd->index;
+
+  out->tc.index = tcnf->index;
+  out->tc.modulus.len = tcnf->modulus.len;
+  out->tc.modulus.data = tcnf->modulus.data;
+  out->tc.generator.len = tcnf->generator.len;
+  out->tc.generator.data = tcnf->generator.data;
+}
+
+_TYPE( struct t_passwd * )
+gettpnam
+(user)
+     const char * user;
+{
+  struct t_pwent * tpptr;
+  struct t_confent * tcptr;
+
+  if(pwinit() < 0)
+    return NULL;
+  tpptr = t_getpwbyname(syspw, user);
+  if(tpptr == NULL)
+    return NULL;
+  tcptr =
+    gettcid
+    (tpptr->index);
+  if(tcptr == NULL)
+    return NULL;
+  pwsetup(&tpass, tpptr, tcptr);
+  return &tpass;
+}
diff --git a/package/network/services/ead/src/tinysrp/t_pwd.h b/package/network/services/ead/src/tinysrp/t_pwd.h
new file mode 100644
index 0000000000..73697bef3e
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_pwd.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#ifndef T_PWD_H
+#define T_PWD_H
+
+#ifndef P
+#if defined (__STDC__) || defined (__cplusplus)
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+#endif
+
+/*      For building dynamic link libraries under windows, windows NT
+ *      using MSVC1.5 or MSVC2.0
+ */
+
+#ifndef _DLLDECL
+#define _DLLDECL
+
+#ifdef MSVC15   /* MSVC1.5 support for 16 bit apps */
+#define _MSVC15EXPORT _export
+#define _MSVC20EXPORT
+#define _DLLAPI _export _pascal
+#define _TYPE(a) a _MSVC15EXPORT
+#define DLLEXPORT 1
+
+#elif MSVC20
+#define _MSVC15EXPORT
+#define _MSVC20EXPORT _declspec(dllexport)
+#define _DLLAPI
+#define _TYPE(a) _MSVC20EXPORT a
+#define DLLEXPORT 1
+
+#else                   /* Default, non-dll.  Use this for Unix or DOS */
+#define _MSVC15DEXPORT
+#define _MSVC20EXPORT
+#define _DLLAPI
+#define _TYPE(a) a
+#endif
+#endif
+
+#define MAXPARAMBITS    2048
+#define MAXPARAMLEN     ((MAXPARAMBITS + 7) / 8)
+#define MAXB64PARAMLEN  ((MAXPARAMBITS + 5) / 6 + 1)
+#define MAXHEXPARAMLEN  ((MAXPARAMBITS + 3) / 4 + 1)
+#define MAXOCTPARAMLEN  ((MAXPARAMBITS + 2) / 3 + 1)
+
+#define MAXUSERLEN      32
+#define MAXSALTLEN      32
+#define MAXB64SALTLEN   44      /* 256 bits in b64 + null */
+#define SALTLEN         10      /* Normally 80 bits */
+
+#define RESPONSE_LEN    20      /* 160-bit proof hashes */
+#define SESSION_KEY_LEN (2 * RESPONSE_LEN)      /* 320-bit session key */
+
+#define DEFAULT_PASSWD  "tpasswd"
+
+struct t_num {  /* Standard byte-oriented integer representation */
+  int len;
+  unsigned char * data;
+};
+
+struct t_preconf {      /* Structure returned by t_getpreparam() */
+  char * mod_b64;
+  char * gen_b64;
+  char * comment;
+
+  struct t_num modulus;
+  struct t_num generator;
+};
+
+/*
+ * The built-in (known good) parameters access routines
+ *
+ * "t_getprecount" returns the number of precompiled parameter sets.
+ * "t_getpreparam" returns the indicated parameter set.
+ * Memory is statically allocated - callers need not perform any memory mgmt.
+ */
+_TYPE( int ) t_getprecount();
+_TYPE( struct t_preconf * ) t_getpreparam P((int));
+
+struct t_confent {      /* One configuration file entry (index, N, g) */
+  int index;
+  struct t_num modulus;
+  struct t_num generator;
+};
+
+struct t_conf {         /* An open configuration file */
+  FILE * instream;
+  char close_on_exit;
+  unsigned char modbuf[MAXPARAMLEN];
+  unsigned char genbuf[MAXPARAMLEN];
+  struct t_confent tcbuf;
+};
+
+/*
+ * The configuration file routines are designed along the lines of the
+ * "getpw" functions in the standard C library.
+ *
+ * "t_openconf" accepts a stdio stream and interprets it as a config file.
+ * "t_openconfbyname" accepts a filename and does the same thing.
+ * "t_closeconf" closes the config file.
+ * "t_getconfent" fetches the next sequential configuration entry.
+ * "t_getconfbyindex" fetches the configuration entry whose index
+ *   matches the one supplied, or NULL if one can't be found.
+ * "t_getconflast" fetches the last configuration entry in the file.
+ * "t_makeconfent" generates a set of configuration entry parameters
+ *   randomly.
+ * "t_newconfent" returns an empty configuration entry.
+ * "t_cmpconfent" compares two configuration entries a la strcmp.
+ * "t_checkconfent" verifies that a set of configuration parameters
+ *   are suitable.  N must be prime and should be a safe prime.
+ * "t_putconfent" writes a configuration entry to a stream.
+ */
+_TYPE( struct t_conf * ) t_openconf P((FILE *));
+_TYPE( struct t_conf * ) t_openconfbyname P((const char *));
+_TYPE( void ) t_closeconf P((struct t_conf *));
+_TYPE( void ) t_rewindconf P((struct t_conf *));
+_TYPE( struct t_confent * ) t_getconfent P((struct t_conf *));
+_TYPE( struct t_confent * ) t_getconfbyindex P((struct t_conf *, int));
+_TYPE( struct t_confent * ) t_getconflast P((struct t_conf *));
+_TYPE( struct t_confent * ) t_makeconfent P((struct t_conf *, int));
+_TYPE( struct t_confent * ) t_makeconfent_c P((struct t_conf *, int));
+_TYPE( struct t_confent * ) t_newconfent P((struct t_conf *));
+_TYPE( int ) t_cmpconfent P((const struct t_confent *, const struct t_confent *));
+_TYPE( int ) t_checkconfent P((const struct t_confent *));
+_TYPE( void ) t_putconfent P((const struct t_confent *, FILE *));
+
+/* libc-style system conf file access */
+_TYPE( struct t_confent *) gettcent();
+_TYPE( struct t_confent *) gettcid P((int));
+_TYPE( void ) settcent();
+_TYPE( void ) endtcent();
+
+#ifdef ENABLE_NSW
+extern struct t_confent * _gettcent();
+extern struct t_confent * _gettcid P((int));
+extern void _settcent();
+extern void _endtcent();
+#endif
+
+/* A hack to support '+'-style entries in the passwd file */
+
+typedef enum fstate {
+  FILE_ONLY,    /* Ordinary file, don't consult NIS ever */
+  FILE_NIS,     /* Currently accessing file, use NIS if encountered */
+  IN_NIS,       /* Currently in a '+' entry; use NIS for getXXent */
+} FILE_STATE;
+
+struct t_pwent {        /* A single password file entry */
+  char * name;
+  struct t_num password;
+  struct t_num salt;
+  int index;
+};
+
+struct t_pw {           /* An open password file */
+  FILE * instream;
+  char close_on_exit;
+  FILE_STATE state;
+  char userbuf[MAXUSERLEN];
+  unsigned char pwbuf[MAXPARAMLEN];
+  unsigned char saltbuf[SALTLEN];
+  struct t_pwent pebuf;
+};
+
+/*
+ * The password manipulation routines are patterned after the getpw*
+ * standard C library function calls.
+ *
+ * "t_openpw" reads a stream as if it were a password file.
+ * "t_openpwbyname" opens the named file as a password file.
+ * "t_closepw" closes an open password file.
+ * "t_rewindpw" starts the internal file pointer from the beginning
+ *   of the password file.
+ * "t_getpwent" retrieves the next sequential password entry.
+ * "t_getpwbyname" looks up the password entry corresponding to the
+ *   specified user.
+ * "t_makepwent" constructs a password entry from a username, password,
+ *   numeric salt, and configuration entry.
+ * "t_putpwent" writes a password entry to a stream.
+ */
+_TYPE( struct t_pw * ) t_openpw P((FILE *));
+_TYPE( struct t_pw * ) t_openpwbyname P((const char *));
+_TYPE( void ) t_closepw P((struct t_pw *));
+_TYPE( void ) t_rewindpw P((struct t_pw *));
+_TYPE( struct t_pwent * ) t_getpwent P((struct t_pw *));
+_TYPE( struct t_pwent * ) t_getpwbyname P((struct t_pw *, const char *));
+_TYPE( struct t_pwent * ) t_makepwent P((struct t_pw *, const char *,
+					 const char *, const struct t_num *,
+					 const struct t_confent *));
+_TYPE( void ) t_putpwent P((const struct t_pwent *, FILE *));
+
+struct t_passwd {
+  struct t_pwent tp;
+  struct t_confent tc;
+};
+
+/* libc-style system password file access */
+_TYPE( struct t_passwd * ) gettpent();
+_TYPE( struct t_passwd * ) gettpnam P((const char *));
+_TYPE( void ) settpent();
+_TYPE( void ) endtpent();
+
+#ifdef ENABLE_NSW
+extern struct t_passwd * _gettpent();
+extern struct t_passwd * _gettpnam P((const char *));
+extern void _settpent();
+extern void _endtpent();
+#endif
+
+/*
+ * Utility functions
+ *
+ * "t_verifypw" accepts a username and password, and checks against the
+ *   system password file to see if the password for that user is correct.
+ *   Returns > 0 if it is correct, 0 if not, and -1 if some error occurred
+ *   (i.e. the user doesn't exist on the system).  This is intended ONLY
+ *   for local authentication; for remote authentication, look at the
+ *   t_client and t_server source.  (That's the whole point of SRP!)
+ * "t_changepw" modifies the specified file, substituting the given password
+ *   entry for the one already in the file.  If no matching entry is found,
+ *   the new entry is simply appended to the file.
+ * "t_deletepw" removes the specified user from the specified file.
+ */
+_TYPE( int ) t_verifypw P((const char *, const char *));
+_TYPE( int ) t_changepw P((const char *, const struct t_pwent *));
+_TYPE( int ) t_deletepw P((const char *, const char *));
+
+/* Conversion utilities */
+
+/*
+ * All these calls accept output as the first parameter.  In the case of
+ * t_tohex and t_tob64, the last argument is the length of the byte-string
+ * input.
+ */
+_TYPE( char * t_tohex ) P((char *, char *, unsigned));
+_TYPE( int ) t_fromhex P((char *, char *));
+_TYPE( char * ) t_tob64 P((char *, char *, unsigned));
+_TYPE( int ) t_fromb64 P((char *, char *));
+
+/* Miscellaneous utilities */
+
+/*
+ * "t_random" is a cryptographic random number generator, which is seeded
+ *   from various high-entropy sources and uses a one-way hash function
+ *   in a feedback configuration.
+ * "t_sessionkey" is the interleaved hash used to generate session keys
+ *   from a large integer.
+ * "t_getpass" reads a password from the terminal without echoing.
+ */
+_TYPE( void ) t_random P((unsigned char *, unsigned));
+_TYPE( void ) t_stronginitrand();
+_TYPE( unsigned char * )
+  t_sessionkey P((unsigned char *, unsigned char *, unsigned));
+_TYPE( int ) t_getpass P((char *, unsigned, const char *));
+
+/*
+ * Return value of t_checkprime:
+ *   < 0 : not prime
+ *   = 0 : prime, but not safe
+ *   > 0 : safe
+ */
+#define NUM_NOTPRIME    -1
+#define NUM_NOTSAFE     0
+#define NUM_SAFE        1
+
+_TYPE( int ) t_checkprime P((const struct t_num *));
+
+#endif
diff --git a/package/network/services/ead/src/tinysrp/t_read.c b/package/network/services/ead/src/tinysrp/t_read.c
new file mode 100644
index 0000000000..087b7d55b8
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_read.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+#include "config.h"
+
+#define FSEPARATOR	':'
+
+int
+t_nextfield(fp, s, max)
+FILE * fp;
+char * s;
+unsigned max;
+{
+  int c, count = 0;
+
+  while((c = getc(fp)) != EOF) {
+    if(c == '\n') {
+      ungetc(c, fp);
+      break;
+    }
+    else if(c == FSEPARATOR)
+      break;
+    if(count < max - 1) {
+      *s++ = c;
+      ++count;
+    }
+  }
+  *s++ = '\0';
+  return count;
+}
+
+int
+t_nextline(fp)
+FILE * fp;
+{
+  int c;
+
+  while((c = getc(fp)) != '\n')
+    if(c == EOF)
+      return -1;
+  return 0;
+}
diff --git a/package/network/services/ead/src/tinysrp/t_read.h b/package/network/services/ead/src/tinysrp/t_read.h
new file mode 100644
index 0000000000..e621f793ad
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_read.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#ifndef _T_READ_H_
+#define _T_READ_H_
+
+#if     !defined(P)
+#ifdef  __STDC__
+#define P(x)    x
+#else
+#define P(x)    ()
+#endif
+#endif
+
+extern int t_nextfield P((FILE *, char *, unsigned));
+extern int t_nextline P((FILE *));
+#endif
diff --git a/package/network/services/ead/src/tinysrp/t_server.c b/package/network/services/ead/src/tinysrp/t_server.c
new file mode 100644
index 0000000000..6ab501bcb8
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_server.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <stdio.h>
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_server.h"
+
+_TYPE( struct t_server * )
+t_serveropenraw(ent, tce)
+     struct t_pwent * ent;
+     struct t_confent * tce;
+{
+  struct t_server * ts;
+  unsigned char buf1[SHA_DIGESTSIZE], buf2[SHA_DIGESTSIZE];
+  SHA1_CTX ctxt;
+  int i;
+
+  if((ts = malloc(sizeof(struct t_server))) == 0)
+    return 0;
+
+  SHA1Init(&ts->ckhash);
+
+  ts->index = ent->index;
+  ts->n.len = tce->modulus.len;
+  ts->n.data = ts->nbuf;
+  memcpy(ts->n.data, tce->modulus.data, ts->n.len);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, ts->n.data, ts->n.len);
+  SHA1Final(buf1, &ctxt);
+
+  ts->g.len = tce->generator.len;
+  ts->g.data = ts->gbuf;
+  memcpy(ts->g.data, tce->generator.data, ts->g.len);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, ts->g.data, ts->g.len);
+  SHA1Final(buf2, &ctxt);
+
+  for(i = 0; i < sizeof(buf1); ++i)
+    buf1[i] ^= buf2[i];
+
+  SHA1Update(&ts->ckhash, buf1, sizeof(buf1));
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, ent->name, strlen(ent->name));
+  SHA1Final(buf1, &ctxt);
+
+  SHA1Update(&ts->ckhash, buf1, sizeof(buf1));
+
+  ts->v.len = ent->password.len;
+  ts->v.data = ts->vbuf;
+  memcpy(ts->v.data, ent->password.data, ts->v.len);
+
+  ts->s.len = ent->salt.len;
+  ts->s.data = ts->saltbuf;
+  memcpy(ts->s.data, ent->salt.data, ts->s.len);
+
+  SHA1Update(&ts->ckhash, ts->s.data, ts->s.len);
+
+  ts->b.data = ts->bbuf;
+  ts->B.data = ts->Bbuf;
+
+  SHA1Init(&ts->hash);
+  SHA1Init(&ts->oldhash);
+  SHA1Init(&ts->oldckhash);
+
+  return ts;
+}
+
+_TYPE( struct t_num * )
+t_servergenexp(ts)
+     struct t_server * ts;
+{
+  BigInteger b, B, v, n, g;
+
+  if(ts->n.len < BLEN)
+    ts->b.len = ts->n.len;
+  else
+    ts->b.len = BLEN;
+
+  t_random(ts->b.data, ts->b.len);
+  b = BigIntegerFromBytes(ts->b.data, ts->b.len);
+  n = BigIntegerFromBytes(ts->n.data, ts->n.len);
+  g = BigIntegerFromBytes(ts->g.data, ts->g.len);
+  B = BigIntegerFromInt(0);
+  BigIntegerModExp(B, g, b, n);
+
+  v = BigIntegerFromBytes(ts->v.data, ts->v.len);
+  BigIntegerAdd(B, B, v);
+  if(BigIntegerCmp(B, n) > 0)
+    BigIntegerSub(B, B, n);
+
+  ts->B.len = BigIntegerToBytes(B, ts->B.data);
+
+  BigIntegerFree(v);
+  BigIntegerFree(B);
+  BigIntegerFree(b);
+  BigIntegerFree(g);
+  BigIntegerFree(n);
+
+  SHA1Update(&ts->oldckhash, ts->B.data, ts->B.len);
+
+  return &ts->B;
+}
+
+_TYPE( unsigned char * )
+t_servergetkey(ts, clientval)
+     struct t_server * ts;
+     struct t_num * clientval;
+{
+  BigInteger n, v, A, b, prod, res, S;
+  SHA1_CTX ctxt;
+  unsigned char sbuf[MAXPARAMLEN];
+  unsigned char dig[SHA_DIGESTSIZE];
+  unsigned slen;
+  unsigned int u;
+
+  SHA1Update(&ts->ckhash, clientval->data, clientval->len);
+  SHA1Update(&ts->ckhash, ts->B.data, ts->B.len);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, ts->B.data, ts->B.len);
+  SHA1Final(dig, &ctxt);
+  u = (dig[0] << 24) | (dig[1] << 16) | (dig[2] << 8) | dig[3];
+
+  SHA1Update(&ts->oldhash, clientval->data, clientval->len);
+  SHA1Update(&ts->hash, clientval->data, clientval->len);
+
+  n = BigIntegerFromBytes(ts->n.data, ts->n.len);
+  b = BigIntegerFromBytes(ts->b.data, ts->b.len);
+  v = BigIntegerFromBytes(ts->v.data, ts->v.len);
+  A = BigIntegerFromBytes(clientval->data, clientval->len);
+
+  prod = BigIntegerFromInt(0);
+  BigIntegerModExpInt(prod, v, u, n);
+  res = BigIntegerFromInt(0);
+  BigIntegerModMul(res, prod, A, n);
+
+  BigIntegerFree(A);
+  BigIntegerFree(v);
+  BigIntegerFree(prod);
+
+  if(BigIntegerCmpInt(res, 1) <= 0) {   /* Check for Av^u == 1 (mod n) */
+    BigIntegerFree(res);
+    BigIntegerFree(b);
+    BigIntegerFree(n);
+    return NULL;
+  }
+
+  S = BigIntegerFromInt(0);
+
+  BigIntegerAddInt(S, res, 1);
+  if(BigIntegerCmp(S, n) == 0) {        /* Check for Av^u == -1 (mod n) */
+    BigIntegerFree(res);
+    BigIntegerFree(b);
+    BigIntegerFree(n);
+    BigIntegerFree(S);
+    return NULL;
+  }
+
+  BigIntegerModExp(S, res, b, n);
+  slen = BigIntegerToBytes(S, sbuf);
+
+  BigIntegerFree(S);
+  BigIntegerFree(res);
+  BigIntegerFree(b);
+  BigIntegerFree(n);
+
+  t_sessionkey(ts->session_key, sbuf, slen);
+  memset(sbuf, 0, slen);
+
+  SHA1Update(&ts->oldhash, ts->session_key, sizeof(ts->session_key));
+  SHA1Update(&ts->oldckhash, ts->session_key, sizeof(ts->session_key));
+  SHA1Update(&ts->ckhash, ts->session_key, sizeof(ts->session_key));
+
+  return ts->session_key;
+}
+
+_TYPE( int )
+t_serververify(ts, resp)
+    struct t_server * ts;
+    unsigned char * resp;
+{
+  unsigned char expected[SHA_DIGESTSIZE];
+  int i;
+
+  SHA1Final(expected, &ts->oldckhash);
+  i = memcmp(expected, resp, sizeof(expected));
+  if(i == 0) {
+    SHA1Final(ts->session_response, &ts->oldhash);
+    return 0;
+  }
+  SHA1Final(expected, &ts->ckhash);
+  i = memcmp(expected, resp, sizeof(expected));
+  if(i == 0) {
+    SHA1Update(&ts->hash, expected, sizeof(expected));
+    SHA1Update(&ts->hash, ts->session_key, sizeof(ts->session_key));
+    SHA1Final(ts->session_response, &ts->hash);
+  }
+  return i;
+}
+
+_TYPE( unsigned char * )
+t_serverresponse(ts)
+    struct t_server * ts;
+{
+  return ts->session_response;
+}
+
+_TYPE( void )
+t_serverclose(ts)
+     struct t_server * ts;
+{
+  memset(ts->bbuf, 0, sizeof(ts->bbuf));
+  memset(ts->vbuf, 0, sizeof(ts->vbuf));
+  memset(ts->saltbuf, 0, sizeof(ts->saltbuf));
+  memset(ts->session_key, 0, sizeof(ts->session_key));
+  free(ts);
+}
diff --git a/package/network/services/ead/src/tinysrp/t_server.h b/package/network/services/ead/src/tinysrp/t_server.h
new file mode 100644
index 0000000000..20970ffe06
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_server.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#ifndef T_SERVER_H
+#define T_SERVER_H
+
+#include "t_sha.h"
+
+#if     !defined(P)
+#ifdef  __STDC__
+#define P(x)    x
+#else
+#define P(x)    ()
+#endif
+#endif
+
+#ifndef _DLLDECL
+#define _DLLDECL
+
+#ifdef MSVC15   /* MSVC1.5 support for 16 bit apps */
+#define _MSVC15EXPORT _export
+#define _MSVC20EXPORT
+#define _DLLAPI _export _pascal
+#define _TYPE(a) a _MSVC15EXPORT
+#define DLLEXPORT 1
+
+#elif MSVC20
+#define _MSVC15EXPORT
+#define _MSVC20EXPORT _declspec(dllexport)
+#define _DLLAPI
+#define _TYPE(a) _MSVC20EXPORT a
+#define DLLEXPORT 1
+
+#else                   /* Default, non-dll.  Use this for Unix or DOS */
+#define _MSVC15DEXPORT
+#define _MSVC20EXPORT
+#define _DLLAPI
+#define _TYPE(a) a
+#endif
+#endif
+
+#define BLEN 32
+
+struct t_server {
+  int index;
+  struct t_num n;
+  struct t_num g;
+  struct t_num v;
+  struct t_num s;
+
+  struct t_num b;
+  struct t_num B;
+
+  SHA1_CTX oldhash, hash, oldckhash, ckhash;
+
+  unsigned char session_key[SESSION_KEY_LEN];
+  unsigned char session_response[RESPONSE_LEN];
+
+  unsigned char nbuf[MAXPARAMLEN], gbuf[MAXPARAMLEN], vbuf[MAXPARAMLEN];
+  unsigned char saltbuf[MAXSALTLEN], bbuf[BLEN], Bbuf[MAXPARAMLEN];
+};
+
+/*
+ * SRP server-side negotiation
+ *
+ * This code negotiates the server side of an SRP exchange.
+ * "t_serveropen" accepts a username (sent by the client), a pointer
+ *   to an open password file, and a pointer to an open configuration
+ *   file.  The server should then call...
+ * "t_servergenexp" will generate a random 256-bit exponent and
+ *   raise g (from the configuration file) to that power, returning
+ *   the result.  This result should be sent to the client as y(p).
+ * "t_servergetkey" accepts the exponential w(p), which should be
+ *   sent by the client, and computes the 256-bit session key.
+ *   This data should be saved before the session is closed.
+ * "t_serverresponse" computes the session key proof as SHA(w(p), K).
+ * "t_serverclose" closes the session and frees its memory.
+ *
+ * Note that authentication is not performed per se; it is up
+ * to either/both sides of the protocol to now verify securely
+ * that their session keys agree in order to establish authenticity.
+ * One possible way is through "oracle hashing"; one side sends
+ * r, the other replies with H(r,K), where H() is a hash function.
+ *
+ * t_serverresponse and t_serververify now implement a version of
+ * the session-key verification described above.
+ */
+_TYPE( struct t_server * )
+  t_serveropen P((const char *));
+_TYPE( struct t_server * )
+  t_serveropenfromfiles P((const char *, struct t_pw *, struct t_conf *));
+_TYPE( struct t_server * )
+  t_serveropenraw P((struct t_pwent *, struct t_confent *));
+_TYPE( struct t_num * ) t_servergenexp P((struct t_server *));
+_TYPE( unsigned char * ) t_servergetkey P((struct t_server *, struct t_num *));
+_TYPE( int ) t_serververify P((struct t_server *, unsigned char *));
+_TYPE( unsigned char * ) t_serverresponse P((struct t_server *));
+_TYPE( void ) t_serverclose P((struct t_server *));
+
+#endif
diff --git a/package/network/services/ead/src/tinysrp/t_sha.c b/package/network/services/ead/src/tinysrp/t_sha.c
new file mode 100644
index 0000000000..cc41d6487c
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_sha.c
@@ -0,0 +1,166 @@
+#include "t_defines.h"
+#include "t_sha.h"
+
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define WORDS_BIGENDIAN * This should be #define'd if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#include <stdio.h>
+#include <string.h>
+
+static void SHA1Transform(uint32 state[5], const unsigned char buffer[64]);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifndef WORDS_BIGENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void SHA1Transform(uint32 state[5], const unsigned char buffer[64])
+{
+uint32 a, b, c, d, e;
+typedef union {
+    unsigned char c[64];
+    uint32 l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+    block = (CHAR64LONG16*)workspace;
+    memcpy(block, buffer, 64);
+#else
+    block = (CHAR64LONG16*)buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const unsigned char* data, unsigned int len)
+{
+unsigned int i, j;
+
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63) {
+	memcpy(&context->buffer[j], data, (i = 64-j));
+	SHA1Transform(context->state, context->buffer);
+	for ( ; i + 63 < len; i += 64) {
+	    SHA1Transform(context->state, &data[i]);
+	}
+	j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+uint32 i, j;
+unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++) {
+	finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+	 >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+	SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
+    for (i = 0; i < 20; i++) {
+	digest[i] = (unsigned char)
+	 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    i = j = 0;
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, 20);
+    memset(context->count, 0, 8);
+    memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */
+    SHA1Transform(context->state, context->buffer);
+#endif
+}
diff --git a/package/network/services/ead/src/tinysrp/t_sha.h b/package/network/services/ead/src/tinysrp/t_sha.h
new file mode 100644
index 0000000000..d10115e748
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_sha.h
@@ -0,0 +1,26 @@
+#ifndef T_SHA_H
+#define T_SHA_H
+
+#if     !defined(P)
+#ifdef  __STDC__
+#define P(x)    x
+#else
+#define P(x)    ()
+#endif
+#endif
+
+#define SHA_DIGESTSIZE 20
+
+typedef unsigned int uint32;
+
+typedef struct {
+    uint32 state[5];
+    uint32 count[2];
+    unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Init P((SHA1_CTX* context));
+void SHA1Update P((SHA1_CTX* context, const unsigned char* data, unsigned int len));
+void SHA1Final P((unsigned char digest[20], SHA1_CTX* context));
+
+#endif /* T_SHA_H */
diff --git a/package/network/services/ead/src/tinysrp/t_truerand.c b/package/network/services/ead/src/tinysrp/t_truerand.c
new file mode 100644
index 0000000000..fa0d6ce603
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/t_truerand.c
@@ -0,0 +1,151 @@
+/*
+ *      Physically random numbers (very nearly uniform)
+ *      D. P. Mitchell
+ *      Modified by Matt Blaze 7/95
+ */
+/*
+ * The authors of this software are Don Mitchell and Matt Blaze.
+ *              Copyright (c) 1995 by AT&T.
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * This software may be subject to United States export controls.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * WARNING: depending on the particular platform, raw_truerand()
+ * output may be biased or correlated.  In general, you can expect
+ * about 16 bits of "pseudo-entropy" out of each 32 bit word returned
+ * by truerand(), but it may not be uniformly diffused.  You should
+ * raw_therefore run the output through some post-whitening function
+ * (like MD5 or DES or whatever) before using it to generate key
+ * material.  (RSAREF's random package does this for you when you feed
+ * raw_truerand() bits to the seed input function.)
+ *
+ * The application interface, for 8, 16, and 32 bit properly "whitened"
+ * random numbers, can be found in trand8(), trand16(), and trand32().
+ * Use those instead of calling raw_truerand() directly.
+ *
+ * The basic idea here is that between clock "skew" and various
+ * hard-to-predict OS event arrivals, counting a tight loop will yield
+ * a little (maybe a third of a bit or so) of "good" randomness per
+ * interval clock tick.  This seems to work well even on unloaded
+ * machines.  If there is a human operator at the machine, you should
+ * augment truerand with other measure, like keyboard event timing.
+ * On server machines (e.g., when you need to generate a
+ * Diffie-Hellman secret) truerand alone may be good enough.
+ *
+ * Test these assumptions on your own platform before fielding a
+ * system based on this software or these techniques.
+ *
+ * This software seems to work well (at 10 or so bits per
+ * raw_truerand() call) on a Sun Sparc-20 under SunOS 4.1.3 and on a
+ * P100 under BSDI 2.0.  You're on your own elsewhere.
+ *
+ */
+
+#include "t_defines.h"
+
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef OLD_TRUERAND
+static jmp_buf env;
+#endif
+static unsigned volatile count
+#ifndef OLD_TRUERAND
+  , done = 0
+#endif
+;
+
+static unsigned ocount;
+static unsigned buffer;
+
+static void
+tick()
+{
+	struct itimerval it, oit;
+
+	it.it_interval.tv_sec = 0;
+	it.it_interval.tv_usec = 0;
+	it.it_value.tv_sec = 0;
+	it.it_value.tv_usec = 16665;
+	if (setitimer(ITIMER_REAL, &it, &oit) < 0)
+		perror("tick");
+}
+
+static void
+interrupt()
+{
+	if (count) {
+#ifdef OLD_TRUERAND
+		longjmp(env, 1);
+#else
+		++done;
+		return;
+#endif
+	}
+
+	(void) signal(SIGALRM, interrupt);
+	tick();
+}
+
+static unsigned long
+roulette()
+{
+#ifdef OLD_TRUERAND
+	if (setjmp(env)) {
+		count ^= (count>>3) ^ (count>>6) ^ ocount;
+		count &= 0x7;
+		ocount=count;
+		buffer = (buffer<<3) ^ count;
+		return buffer;
+	}
+#else
+	done = 0;
+#endif
+	(void) signal(SIGALRM, interrupt);
+	count = 0;
+	tick();
+#ifdef OLD_TRUERAND
+	for (;;)
+#else
+	while(done == 0)
+#endif
+		count++;        /* about 1 MHz on VAX 11/780 */
+#ifndef OLD_TRUERAND
+	count ^= (count>>3) ^ (count>>6) ^ ocount;
+	count &= 0x7;
+	ocount=count;
+	buffer = (buffer<<3) ^ count;
+	return buffer;
+#endif
+}
+
+unsigned long
+raw_truerand()
+{
+	count=0;
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	(void) roulette();
+	return roulette();
+}
diff --git a/package/network/services/ead/src/tinysrp/tconf.c b/package/network/services/ead/src/tinysrp/tconf.c
new file mode 100644
index 0000000000..ad77f4cc1d
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/tconf.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 1997-2000  The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ *    must display the following acknowlegment:
+ *    "This product uses the 'Secure Remote Password' cryptographic
+ *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ *    itself must also display the following acknowledgment:
+ *    "This product includes software developed by Tom Wu and Eugene
+ *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ *    of this copyright notice and list of conditions.
+ */
+
+#include <unistd.h>     /* close getlogin */
+#include <stdlib.h>     /* atexit exit */
+#include <stdio.h>
+#include <string.h>
+
+#include "t_pwd.h"
+
+#define MIN_BASIS_BITS 512
+#define BASIS_BITS 2048
+
+extern int  optind;
+extern char *optarg;
+
+extern int errno;
+
+char *progName;
+
+int  debug   = 0;
+int  verbose = 0;
+int  composite = 0;
+
+int main(argc, argv)
+     int argc;
+     char *argv[];
+{
+  char *chp;
+  char *configFile = NULL;
+  char cbuf[256];
+  char b64buf[MAXB64PARAMLEN];
+  int c, ch, i, lastidx, keylen, yesno, fsize, status, nparams;
+  FILE *efp;
+
+  struct t_preconf * tpc;
+  struct t_conf tcs;
+  struct t_conf * tc = &tcs;
+  struct t_confent * tcent;
+
+  progName = *argv;
+  if ((chp = strrchr(progName, '/')) != (char *) 0) progName = chp + 1;
+
+  while ((ch = getopt(argc, argv, "dv2c:")) != EOF)
+    switch(ch) {
+    case 'c':
+      configFile = optarg;
+      break;
+    case 'v':
+      verbose++;
+      break;
+    case 'd':
+      debug++;
+      break;
+    case '2':
+      composite++;
+      break;
+    default:
+      fprintf(stderr, "usage: %s [-dv2] [-c configfile]\n", progName);
+      exit(1);
+    }
+
+  argc -= optind;
+  argv += optind;
+
+  lastidx = 0;
+  keylen = 0;
+
+  tcent = t_newconfent(tc);
+
+  printf("\nThis program will generate a set of parameters for the EPS\n");
+  printf("password file.  The size of these parameters, measured in bits,\n");
+  printf("determines the level of security offered by SRP, and is related\n");
+  printf("to the security of similarly-sized RSA or Diffie-Hellman keys.\n");
+  printf("Choosing a predefined field is generally preferable to generating\n");
+  printf("a new field because clients can avoid costly parameter verification.\n");
+  printf("Either way, the values generated by this program are public and\n");
+  printf("can even shared between systems.\n");
+
+  printf("\nEnter the new field size, in bits.  Suggested sizes:\n\n");
+  printf(" 512 (fast, minimally secure)\n");
+  printf(" 768 (moderate security)\n");
+  printf("1024 (most popular default)\n");
+  printf("1536 (additional security, possibly slow)\n");
+  printf("2048 (maximum supported security level)\n");
+  printf("\nField size (%d to %d): ", MIN_BASIS_BITS, BASIS_BITS);
+
+  fgets(cbuf, sizeof(cbuf), stdin);
+  fsize = atoi(cbuf);
+  if(fsize < MIN_BASIS_BITS || fsize > BASIS_BITS) {
+    fprintf(stderr, "%s: field size must be between %d and %d\n",
+	    progName, MIN_BASIS_BITS, BASIS_BITS);
+    exit(1);
+  }
+
+  if(fsize <= keylen)
+    fprintf(stderr, "Warning: new field size is not larger than old field size\n");
+
+  printf("\nInitializing random number generator...");
+  fflush(stdout);
+  t_initrand();
+
+  if(composite)
+    printf("done.\n\nGenerating a %d-bit composite with safe prime factors.  This may take a while.\n", fsize);
+  else
+    printf("done.\n\nGenerating a %d-bit safe prime.  This may take a while.\n", fsize);
+
+  while((tcent = (composite ? t_makeconfent_c(tc, fsize) :
+			      t_makeconfent(tc, fsize))) == NULL)
+    printf("Parameter generation failed, retrying...\n");
+  tcent->index = lastidx + 1;
+
+  printf("\nParameters successfully generated.\n");
+  printf("N = [%s]\n", t_tob64(b64buf,
+			       tcent->modulus.data, tcent->modulus.len));
+  printf("g = [%s]\n", t_tob64(b64buf,
+			       tcent->generator.data, tcent->generator.len));
+  printf("\nYou must update the pre_params array in t_getconf.c\n");
+}
diff --git a/package/network/services/ead/src/tinysrp/tinysrp.c b/package/network/services/ead/src/tinysrp/tinysrp.c
new file mode 100644
index 0000000000..fc01055417
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/tinysrp.c
@@ -0,0 +1,235 @@
+/* This bit implements a simple API for using the SRP library over sockets. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "t_defines.h"
+#include "t_pwd.h"
+#include "t_server.h"
+#include "t_client.h"
+#include "tinysrp.h"
+
+#ifndef MSG_WAITALL
+#ifdef linux
+#define MSG_WAITALL 0x100       /* somehow not defined on my box */
+#endif
+#endif
+
+/* This is called by the client with a connected socket, username, and
+passphrase.  pass can be NULL in which case the user is queried. */
+
+int tsrp_client_authenticate(int s, char *user, char *pass, TSRP_SESSION *tsrp)
+{
+	int i, index;
+	unsigned char username[MAXUSERLEN + 1], sbuf[MAXSALTLEN];
+	unsigned char msgbuf[MAXPARAMLEN + 1], bbuf[MAXPARAMLEN];
+	unsigned char passbuf[128], *skey;
+	struct t_client *tc;
+	struct t_preconf *tcp;          /* @@@ should go away */
+	struct t_num salt, *A, B;
+
+	/* Send the username. */
+
+	i = strlen(user);
+	if (i > MAXUSERLEN) {
+		i = MAXUSERLEN;
+	}
+	msgbuf[0] = i;
+	memcpy(msgbuf + 1, user, i);
+	if (send(s, msgbuf, i + 1, 0) < 0) {
+		return 0;
+	}
+	memcpy(username, user, i);
+	username[i] = '\0';
+
+	/* Get the prime index and salt. */
+
+	i = recv(s, msgbuf, 2, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+	index = msgbuf[0];
+	if (index <= 0 || index > t_getprecount()) {
+		return 0;
+	}
+	tcp = t_getpreparam(index - 1);
+	salt.len = msgbuf[1];
+	if (salt.len > MAXSALTLEN) {
+		return 0;
+	}
+	salt.data = sbuf;
+	i = recv(s, sbuf, salt.len, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+
+	/* @@@ t_clientopen() needs a variant that takes the index */
+
+	tc = t_clientopen(username, &tcp->modulus, &tcp->generator, &salt);
+	if (tc == NULL) {
+		return 0;
+	}
+
+	/* Calculate A and send it to the server. */
+
+	A = t_clientgenexp(tc);
+	msgbuf[0] = A->len - 1;         /* len is max 256 */
+	memcpy(msgbuf + 1, A->data, A->len);
+	if (send(s, msgbuf, A->len + 1, 0) < 0) {
+		return 0;
+	}
+
+	/* Ask the user for the passphrase. */
+
+	if (pass == NULL) {
+		t_getpass(passbuf, sizeof(passbuf), "Enter password:");
+		pass = passbuf;
+	}
+	t_clientpasswd(tc, pass);
+
+	/* Get B from the server. */
+
+	i = recv(s, msgbuf, 1, 0);
+	if (i <= 0) {
+		return 0;
+	}
+	B.len = msgbuf[0] + 1;
+	B.data = bbuf;
+	i = recv(s, bbuf, B.len, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+
+	/* Compute the session key. */
+
+	skey = t_clientgetkey(tc, &B);
+	if (skey == NULL) {
+		return 0;
+	}
+
+	/* Send the response. */
+
+	if (send(s, t_clientresponse(tc), RESPONSE_LEN, 0) < 0) {
+		return 0;
+	}
+
+	/* Get the server's response. */
+
+	i = recv(s, msgbuf, RESPONSE_LEN, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+	if (t_clientverify(tc, msgbuf) != 0) {
+		return 0;
+	}
+
+	/* All done.  Now copy the key and clean up. */
+
+	if (tsrp) {
+		memcpy(tsrp->username, username, strlen(username) + 1);
+		memcpy(tsrp->key, skey, SESSION_KEY_LEN);
+	}
+	t_clientclose(tc);
+
+	return 1;
+}
+
+/* This is called by the server with a connected socket. */
+
+int tsrp_server_authenticate(int s, TSRP_SESSION *tsrp)
+{
+	int i, j;
+	unsigned char username[MAXUSERLEN], *skey;
+	unsigned char msgbuf[MAXPARAMLEN + 1], abuf[MAXPARAMLEN];
+	struct t_server *ts;
+	struct t_num A, *B;
+
+	/* Get the username. */
+
+	i = recv(s, msgbuf, 1, 0);
+	if (i <= 0) {
+		return 0;
+	}
+	j = msgbuf[0];
+	i = recv(s, username, j, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+	username[j] = '\0';
+
+	ts = t_serveropen(username);
+	if (ts == NULL) {
+		return 0;
+	}
+
+	/* Send the prime index and the salt. */
+
+	msgbuf[0] = ts->index;                  /* max 256 primes... */
+	i = ts->s.len;
+	msgbuf[1] = i;
+	memcpy(msgbuf + 2, ts->s.data, i);
+	if (send(s, msgbuf, i + 2, 0) < 0) {
+		return 0;
+	}
+
+	/* Calculate B while we're waiting. */
+
+	B = t_servergenexp(ts);
+
+	/* Get A from the client. */
+
+	i = recv(s, msgbuf, 1, 0);
+	if (i <= 0) {
+		return 0;
+	}
+	A.len = msgbuf[0] + 1;
+	A.data = abuf;
+	i = recv(s, abuf, A.len, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+
+	/* Now send B. */
+
+	msgbuf[0] = B->len - 1;
+	memcpy(msgbuf + 1, B->data, B->len);
+	if (send(s, msgbuf, B->len + 1, 0) < 0) {
+		return 0;
+	}
+
+	/* Calculate the session key while we're waiting. */
+
+	skey = t_servergetkey(ts, &A);
+	if (skey == NULL) {
+		return 0;
+	}
+
+	/* Get the response from the client. */
+
+	i = recv(s, msgbuf, RESPONSE_LEN, MSG_WAITALL);
+	if (i <= 0) {
+		return 0;
+	}
+	if (t_serververify(ts, msgbuf) != 0) {
+		return 0;
+	}
+
+	/* Client authenticated.  Now authenticate ourselves to the client. */
+
+	if (send(s, t_serverresponse(ts), RESPONSE_LEN, 0) < 0) {
+		return 0;
+	}
+
+	/* Copy the key and clean up. */
+
+	if (tsrp) {
+		memcpy(tsrp->username, username, strlen(username) + 1);
+		memcpy(tsrp->key, skey, SESSION_KEY_LEN);
+	}
+	t_serverclose(ts);
+
+	return 1;
+}
diff --git a/package/network/services/ead/src/tinysrp/tinysrp.h b/package/network/services/ead/src/tinysrp/tinysrp.h
new file mode 100644
index 0000000000..4420a196a3
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/tinysrp.h
@@ -0,0 +1,18 @@
+/* Simple API for the tinysrp library. */
+
+#ifndef T_PWD_H
+#define MAXUSERLEN      32
+#define SESSION_KEY_LEN 40      /* 320-bit session key */
+#endif
+
+typedef struct {
+	char username[MAXUSERLEN + 1];
+	unsigned char key[SESSION_KEY_LEN];
+} TSRP_SESSION;
+
+/* These functions are passed a connected socket, and return true for a
+successful authentication.  If tsrp is not NULL, the username and key
+fields are filled in. */
+
+extern int tsrp_server_authenticate(int s, TSRP_SESSION *tsrp);
+extern int tsrp_client_authenticate(int s, char *user, char *pass, TSRP_SESSION *tsrp);
diff --git a/package/network/services/ead/src/tinysrp/tpasswd b/package/network/services/ead/src/tinysrp/tpasswd
new file mode 100644
index 0000000000..2ac7e2a1b6
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/tpasswd
@@ -0,0 +1,2 @@
+moo:A9lHvOGAMJvw1m3vcDsQRUFovh6/QUmLDKqwhv.drKQzbE9nS7HrOZLUPx2MmS6ewwybN8RHqpWqnUJRCMFT14FMbYXR7kYNUUQNx43A7F.xrVOU7tlFq5NjoK9sfFtp6PMdbIOP5wzWmipiNFlCOu4sjlSZb.o7C1chLzTKU.0:19AI0Hc9jEkdFc:5
+new user:1FsanML2fbTOEsa072bLjyRD1LEqoRD2GwElfN0VmHeR.FAg5A.2.G5bTjIHmMmHL60kgoAHJZhRrgopalYmujlyAuQoKiHJb98SHm1oJaQ9nl/DrZCvfyw5LpVMqg.CupdiWz6OtmOz8fwC96ItExFnNDt6SmsVDIOn4HqXG6C0lLaqEvcqlN3gFDlJXyP2yldM.LJ1TkHTHmA3DjRkmWEUL3mWEgzkEHyPcRB3Jd5ncDT7jaNbJTTLRoOtgRsaqE7OXuPADoK8MGBcUquYBRrGwyU4Y/wW4gLc3QmV793zxkk.P3.dxkLSjro/Kk94D7kC6fx3K9tadLJyzd94rr:3v/KRlxT0.oYF1:1
diff --git a/package/network/services/ead/src/tinysrp/tphrase.c b/package/network/services/ead/src/tinysrp/tphrase.c
new file mode 100644
index 0000000000..0ab1e085c1
--- /dev/null
+++ b/package/network/services/ead/src/tinysrp/tphrase.c
@@ -0,0 +1,354 @@
+/* Add passphrases to the tpasswd file.  Use the last entry in the config
+file by default or a particular one specified by index. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+#include "t_pwd.h"
+#include "t_read.h"
+#include "t_sha.h"
+#include "t_defines.h"
+
+char *Progname;
+char Usage[] = "usage: %s [-n configindex] [-p passfile] user\n";
+#define USAGE() fprintf(stderr, Usage, Progname)
+
+void doit(char *);
+
+int Configindex = -1;
+char *Passfile = DEFAULT_PASSWD;
+
+int main(int argc, char **argv)
+{
+	int c;
+
+	Progname = *argv;
+
+	/* Parse option arguments. */
+
+	while ((c = getopt(argc, argv, "n:p:")) != EOF) {
+		switch (c) {
+
+		case 'n':
+			Configindex = atoi(optarg);
+			break;
+
+		case 'p':
+			Passfile = optarg;
+			break;
+
+		default:
+			USAGE();
+			exit(1);
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1) {
+		USAGE();
+		exit(1);
+	}
+	doit(argv[0]);
+
+	return 0;
+}
+
+void doit(char *name)
+{
+	char passphrase[128], passphrase1[128];
+	FILE *f;
+	struct t_confent *tcent;
+	struct t_pw eps_passwd;
+
+	/* Get the config entry. */
+
+	if (Configindex <= 0) {
+		Configindex = t_getprecount();
+	}
+	tcent = gettcid(Configindex);
+	if (tcent == NULL) {
+		fprintf(stderr, "Invalid configuration file entry.\n");
+		exit(1);
+	}
+
+	/* Ask for the passphrase twice. */
+
+	printf("Setting passphrase for %s\n", name);
+
+	if (t_getpass(passphrase, sizeof(passphrase), "Enter passphrase: ") < 0) {
+		exit(1);
+	}
+	if (t_getpass(passphrase1, sizeof(passphrase1), "Verify: ") < 0) {
+		exit(1);
+	}
+	if (strcmp(passphrase, passphrase1) != 0) {
+		fprintf(stderr, "mismatch\n");
+		exit(1);
+	}
+
+	/* Create the passphrase verifier. */
+
+	t_makepwent(&eps_passwd, name, passphrase, NULL, tcent);
+
+	/* Don't need these anymore. */
+
+	memset(passphrase, 0, sizeof(passphrase));
+	memset(passphrase1, 0, sizeof(passphrase1));
+
+	/* See if the passphrase file is there; create it if not. */
+
+	if ((f = fopen(Passfile, "r+")) == NULL) {
+		creat(Passfile, 0400);
+	} else {
+		fclose(f);
+	}
+
+	/* Change the passphrase. */
+
+	if (t_changepw(Passfile, &eps_passwd.pebuf) < 0) {
+		fprintf(stderr, "Error changing passphrase\n");
+		exit(1);
+	}
+}
+
+/* TODO: Implement a more general method to handle delete/change */
+
+_TYPE( int )
+t_changepw(pwname, diff)
+     const char * pwname;
+     const struct t_pwent * diff;
+{
+  char * bakfile;
+  char * bakfile2;
+  struct stat st;
+  FILE * passfp;
+  FILE * bakfp;
+
+  if(pwname == NULL)
+    pwname = DEFAULT_PASSWD;
+
+  if((passfp = fopen(pwname, "rb")) == NULL || fstat(fileno(passfp), &st) < 0)
+    return -1;
+
+  if((bakfile = malloc(strlen(pwname) + 5)) == NULL) {
+    fclose(passfp);
+    return -1;
+  }
+  else if((bakfile2 = malloc(strlen(pwname) + 5)) == NULL) {
+    fclose(passfp);
+    free(bakfile);
+    return -1;
+  }
+
+  sprintf(bakfile, "%s.bak", pwname);
+  sprintf(bakfile2, "%s.sav", pwname);
+
+  if((bakfp = fopen(bakfile2, "wb")) == NULL &&
+     (unlink(bakfile2) < 0 || (bakfp = fopen(bakfile2, "wb")) == NULL)) {
+    fclose(passfp);
+    free(bakfile);
+    free(bakfile2);
+    return -1;
+  }
+
+#ifdef NO_FCHMOD
+  chmod(bakfile2, st.st_mode & 0777);
+#else
+  fchmod(fileno(bakfp), st.st_mode & 0777);
+#endif
+
+  t_pwcopy(bakfp, passfp, diff);
+
+  fclose(bakfp);
+  fclose(passfp);
+
+#ifdef USE_RENAME
+  unlink(bakfile);
+  if(rename(pwname, bakfile) < 0) {
+    free(bakfile);
+    free(bakfile2);
+    return -1;
+  }
+  if(rename(bakfile2, pwname) < 0) {
+    free(bakfile);
+    free(bakfile2);
+    return -1;
+  }
+#else
+  unlink(bakfile);
+  link(pwname, bakfile);
+  unlink(pwname);
+  link(bakfile2, pwname);
+  unlink(bakfile2);
+#endif
+  free(bakfile);
+  free(bakfile2);
+
+  return 0;
+}
+
+_TYPE( struct t_pwent * )
+t_makepwent(tpw, user, pass, salt, confent)
+     struct t_pw * tpw;
+     const char * user;
+     const char * pass;
+     const struct t_num * salt;
+     const struct t_confent * confent;
+{
+  BigInteger x, v, n, g;
+  unsigned char dig[SHA_DIGESTSIZE];
+  SHA1_CTX ctxt;
+
+  tpw->pebuf.name = tpw->userbuf;
+  tpw->pebuf.password.data = tpw->pwbuf;
+  tpw->pebuf.salt.data = tpw->saltbuf;
+
+  strncpy(tpw->pebuf.name, user, MAXUSERLEN);
+  tpw->pebuf.index = confent->index;
+
+  if(salt) {
+    tpw->pebuf.salt.len = salt->len;
+    memcpy(tpw->pebuf.salt.data, salt->data, salt->len);
+  }
+  else {
+    memset(dig, 0, SALTLEN);            /* salt is 80 bits */
+    tpw->pebuf.salt.len = SALTLEN;
+    do {
+      t_random(tpw->pebuf.salt.data, SALTLEN);
+    } while(memcmp(tpw->pebuf.salt.data, dig, SALTLEN) == 0);
+    if(tpw->pebuf.salt.data[0] == 0)
+      tpw->pebuf.salt.data[0] = 0xff;
+  }
+
+  n = BigIntegerFromBytes(confent->modulus.data, confent->modulus.len);
+  g = BigIntegerFromBytes(confent->generator.data, confent->generator.len);
+  v = BigIntegerFromInt(0);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, user, strlen(user));
+  SHA1Update(&ctxt, ":", 1);
+  SHA1Update(&ctxt, pass, strlen(pass));
+  SHA1Final(dig, &ctxt);
+
+  SHA1Init(&ctxt);
+  SHA1Update(&ctxt, tpw->pebuf.salt.data, tpw->pebuf.salt.len);
+  SHA1Update(&ctxt, dig, sizeof(dig));
+  SHA1Final(dig, &ctxt);
+
+  /* x = H(s, H(u, ':', p)) */
+  x = BigIntegerFromBytes(dig, sizeof(dig));
+
+  BigIntegerModExp(v, g, x, n);
+  tpw->pebuf.password.len = BigIntegerToBytes(v, tpw->pebuf.password.data);
+
+  BigIntegerFree(v);
+  BigIntegerFree(x);
+  BigIntegerFree(g);
+  BigIntegerFree(n);
+
+  return &tpw->pebuf;
+}
+
+int
+t_pwcopy(pwdest, pwsrc, diff)
+     FILE * pwdest;
+     FILE * pwsrc;
+     struct t_pwent * diff;
+{
+  struct t_pw * src;
+  struct t_pwent * ent;
+
+  if((src = t_openpw(pwsrc)) == NULL)
+    return -1;
+
+  while((ent = t_getpwent(src)) != NULL)
+    if(diff && strcmp(diff->name, ent->name) == 0) {
+      t_putpwent(diff, pwdest);
+      diff = NULL;
+    }
+    else
+      t_putpwent(ent, pwdest);
+
+  if(diff)
+    t_putpwent(diff, pwdest);
+
+  return 0;
+}
+
+_TYPE( struct t_pwent * )
+t_getpwent(tpw)
+     struct t_pw * tpw;
+{
+  char indexbuf[16];
+  char passbuf[MAXB64PARAMLEN];
+  char saltstr[MAXB64SALTLEN];
+
+#ifdef ENABLE_YP
+  struct t_passwd * nisent;
+  /* FIXME: should tell caller to get conf entry from NIS also */
+
+  if(tpw->state == IN_NIS) {
+    nisent = _yp_gettpent();
+    if(nisent != NULL) {
+      savepwent(tpw, &nisent->tp);
+      return &tpw->pebuf;
+    }
+    tpw->state = FILE_NIS;
+  }
+#endif
+
+  while(1) {
+    if(t_nextfield(tpw->instream, tpw->userbuf, MAXUSERLEN) > 0) {
+#ifdef ENABLE_YP
+      if(tpw->state == FILE_NIS && *tpw->userbuf == '+') {
+	t_nextline(tpw->instream);
+	if(strlen(tpw->userbuf) > 1) {  /* +name:... */
+	  nisent = _yp_gettpnam(tpw->userbuf + 1);
+	  if(nisent != NULL) {
+	    savepwent(tpw, nisent);
+	    return &tpw->pebuf;
+	  }
+	}
+	else {  /* +:... */
+	  tpw->state = IN_NIS;
+	  _yp_settpent();
+	  return t_getpwent(tpw);
+	}
+      }
+#endif
+      if(t_nextfield(tpw->instream, passbuf, MAXB64PARAMLEN) > 0 &&
+	 (tpw->pebuf.password.len = t_fromb64(tpw->pwbuf, passbuf)) > 0 &&
+	 t_nextfield(tpw->instream, saltstr, MAXB64SALTLEN) > 0 &&
+	 (tpw->pebuf.salt.len = t_fromb64(tpw->saltbuf, saltstr)) > 0 &&
+	 t_nextfield(tpw->instream, indexbuf, 16) > 0 &&
+	 (tpw->pebuf.index = atoi(indexbuf)) > 0) {
+	tpw->pebuf.name = tpw->userbuf;
+	tpw->pebuf.password.data = tpw->pwbuf;
+	tpw->pebuf.salt.data = tpw->saltbuf;
+	t_nextline(tpw->instream);
+	return &tpw->pebuf;
+      }
+    }
+    if(t_nextline(tpw->instream) < 0)
+      return NULL;
+  }
+}
+
+_TYPE( void )
+t_putpwent(ent, fp)
+     const struct t_pwent * ent;
+     FILE * fp;
+{
+  char strbuf[MAXB64PARAMLEN];
+  char saltbuf[MAXB64SALTLEN];
+
+  fprintf(fp, "%s:%s:%s:%d\n", ent->name,
+	  t_tob64(strbuf, ent->password.data, ent->password.len),
+	  t_tob64(saltbuf, ent->salt.data, ent->salt.len), ent->index);
+}
+
diff --git a/package/network/services/hostapd/Config.in b/package/network/services/hostapd/Config.in
new file mode 100644
index 0000000000..645888e745
--- /dev/null
+++ b/package/network/services/hostapd/Config.in
@@ -0,0 +1,51 @@
+# wpa_supplicant config
+config WPA_SUPPLICANT_NO_TIMESTAMP_CHECK
+	bool "Disable timestamp check"
+	depends on PACKAGE_wpa-supplicant || PACKAGE_wpa-supplicant-mesh || PACKAGE_wpa-supplicant-mini || PACKAGE_wpad || PACKAGE_wpad-mini || PACAKGE_wpad-mesh
+	default n
+	help
+	  This disables the timestamp check for certificates in wpa_supplicant
+	  Useful for devices without RTC that cannot reliably get the real date/time
+
+choice
+	prompt "Choose TLS provider"
+	default WPA_SUPPLICANT_INTERNAL
+	depends on PACKAGE_wpa-supplicant || PACKAGE_wpad
+
+config WPA_SUPPLICANT_INTERNAL
+	bool "internal"
+
+config WPA_SUPPLICANT_OPENSSL
+	bool "openssl"
+	select PACKAGE_libopenssl
+
+endchoice
+
+config WPA_RFKILL_SUPPORT
+	bool "Add rfkill support"
+	depends on PACKAGE_wpa-supplicant || PACKAGE_wpa-supplicant-mesh || PACKAGE_wpa-supplicant-mini || PACKAGE_wpad || PACKAGE_wpad-mini || PACKAGE_wpad-mesh
+	default n
+
+config WPA_MSG_MIN_PRIORITY
+	int "Minimum debug message priority"
+	default 3
+	help
+	  Useful values are:
+	    0 = all messages
+		1 = raw message dumps
+		2 = most debugging messages
+		3 = info messages
+		4 = warnings
+		5 = errors
+
+config DRIVER_WEXT_SUPPORT
+	bool
+	default n
+
+config DRIVER_11N_SUPPORT
+	bool
+	default n
+
+config DRIVER_11W_SUPPORT
+	bool
+	default n
diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile
new file mode 100644
index 0000000000..9570b2a8f5
--- /dev/null
+++ b/package/network/services/hostapd/Makefile
@@ -0,0 +1,431 @@
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=hostapd
+PKG_VERSION:=2016-09-05
+PKG_RELEASE:=1
+PKG_REV:=fcd85d9a3f2d9d63d0fa57e93446ad467db75b23
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://w1.fi/hostap.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_PROTO:=git
+PKG_MIRROR_MD5SUM:=b1b690fedae8ff5c5801b4fb75508ea35c036aae86425ae324875fa57ef1a01b
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=BSD-3-Clause
+
+PKG_BUILD_PARALLEL:=1
+
+PKG_CONFIG_DEPENDS:= \
+	CONFIG_WPA_SUPPLICANT_NO_TIMESTAMP_CHECK \
+	CONFIG_PACKAGE_kmod-ath9k \
+	CONFIG_PACKAGE_kmod-cfg80211 \
+	CONFIG_PACKAGE_hostapd \
+	CONFIG_PACKAGE_hostapd-mini \
+	CONFIG_WPA_RFKILL_SUPPORT \
+	CONFIG_DRIVER_WEXT_SUPPORT \
+	CONFIG_DRIVER_11N_SUPPORT
+
+LOCAL_TYPE=$(strip \
+		$(if $(findstring wpad,$(BUILD_VARIANT)),wpad, \
+		$(if $(findstring supplicant,$(BUILD_VARIANT)),supplicant, \
+		hostapd \
+	)))
+LOCAL_VARIANT=$(patsubst wpad-%,%,$(patsubst supplicant-%,%,$(BUILD_VARIANT)))
+CONFIG_VARIANT:=$(LOCAL_VARIANT)
+ifeq ($(LOCAL_VARIANT),mesh)
+  CONFIG_VARIANT:=full
+endif
+
+ifneq ($(LOCAL_TYPE),hostapd)
+  ifeq ($(LOCAL_VARIANT),full)
+    PKG_CONFIG_DEPENDS += \
+		CONFIG_WPA_SUPPLICANT_INTERNAL \
+		CONFIG_WPA_SUPPLICANT_OPENSSL
+  endif
+endif
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+STAMP_CONFIGURED:=$(STAMP_CONFIGURED)_$(CONFIG_WPA_MSG_MIN_PRIORITY)
+
+ifneq ($(CONFIG_DRIVER_11N_SUPPORT),)
+  HOSTAPD_IEEE80211N:=y
+endif
+
+DRIVER_MAKEOPTS= \
+	CONFIG_ACS=$(CONFIG_PACKAGE_kmod-cfg80211) \
+	CONFIG_DRIVER_NL80211=$(CONFIG_PACKAGE_kmod-cfg80211) \
+	CONFIG_IEEE80211N=$(HOSTAPD_IEEE80211N) \
+	CONFIG_DRIVER_WEXT=$(CONFIG_DRIVER_WEXT_SUPPORT) \
+
+ifeq ($(LOCAL_VARIANT),full)
+  DRIVER_MAKEOPTS += CONFIG_IEEE80211W=$(CONFIG_DRIVER_11W_SUPPORT)
+endif
+
+ifneq ($(LOCAL_TYPE),hostapd)
+  ifdef CONFIG_WPA_SUPPLICANT_OPENSSL
+    ifeq ($(LOCAL_VARIANT),full)
+      DRIVER_MAKEOPTS += CONFIG_TLS=openssl
+      TARGET_LDFLAGS += -lcrypto -lssl
+    endif
+  endif
+  ifeq ($(LOCAL_VARIANT),mesh)
+    DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_AP=y CONFIG_SAE=y CONFIG_MESH=y
+    TARGET_LDFLAGS += -lcrypto -lssl
+  endif
+  ifdef CONFIG_WPA_SUPPLICANT_NO_TIMESTAMP_CHECK
+    TARGET_CFLAGS += -DNO_TIMESTAMP_CHECK
+  endif
+  ifdef CONFIG_WPA_RFKILL_SUPPORT
+    DRIVER_MAKEOPTS += NEED_RFKILL=y
+  endif
+  DRIVER_MAKEOPTS += \
+	CONFIG_DRIVER_ROBOSWITCH=$(CONFIG_PACKAGE_kmod-switch)
+endif
+
+ifdef CONFIG_USE_GLIBC
+  TARGET_LDFLAGS += -lrt
+  TARGET_LDFLAGS_C += -lrt
+endif
+
+DRV_DEPENDS:=+PACKAGE_kmod-cfg80211:libnl-tiny
+
+define Package/hostapd/Default
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=IEEE 802.1x Authenticator
+  URL:=http://hostap.epitest.fi/
+  DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus
+endef
+
+define Package/hostapd
+$(call Package/hostapd/Default)
+  TITLE+= (full)
+  VARIANT:=full
+  CONFLICTS:=wpad wpad-mini wpad-mesh
+endef
+
+define Package/hostapd/description
+ This package contains a full featured IEEE 802.1x/WPA/EAP/RADIUS
+ Authenticator.
+endef
+
+define Package/hostapd-mini
+$(call Package/hostapd/Default)
+  TITLE+= (WPA-PSK only)
+  VARIANT:=mini
+  CONFLICTS:=wpad wpad-mini wpad-mesh
+endef
+
+define Package/hostapd-mini/description
+ This package contains a minimal IEEE 802.1x/WPA Authenticator (WPA-PSK only).
+endef
+
+define Package/hostapd-utils
+  $(call Package/hostapd/Default)
+  TITLE+= (utils)
+  DEPENDS:=@PACKAGE_hostapd||PACKAGE_hostapd-mini||PACKAGE_wpad||PACKAGE_wpad-mesh||PACKAGE_wpad-mini
+endef
+
+define Package/hostapd-utils/description
+ This package contains a command line utility to control the
+ IEEE 802.1x/WPA/EAP/RADIUS Authenticator.
+endef
+
+define Package/wpad/Default
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=IEEE 802.1x Authenticator/Supplicant
+  DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus
+  URL:=http://hostap.epitest.fi/
+endef
+
+define Package/wpad
+$(call Package/wpad/Default)
+  TITLE+= (full)
+  DEPENDS+=+WPA_SUPPLICANT_OPENSSL:libopenssl
+  VARIANT:=wpad-full
+endef
+
+define Package/wpad/description
+ This package contains a full featured IEEE 802.1x/WPA/EAP/RADIUS
+ Authenticator and Supplicant
+endef
+
+define Package/wpad-mini
+$(call Package/wpad/Default)
+  TITLE+= (WPA-PSK only)
+  VARIANT:=wpad-mini
+endef
+
+define Package/wpad-mini/description
+ This package contains a minimal IEEE 802.1x/WPA Authenticator and Supplicant (WPA-PSK only).
+endef
+
+define Package/wpad-mesh
+$(call Package/wpad/Default)
+  TITLE+= (with 802.11s mesh and SAE support)
+  DEPENDS:=$(DRV_DEPENDS) +libubus +PACKAGE_wpad-mesh:libopenssl @PACKAGE_kmod-cfg80211 @(!TARGET_uml||BROKEN)
+  VARIANT:=wpad-mesh
+endef
+
+define Package/wpad-mesh/description
+ This package contains a minimal IEEE 802.1x/WPA Authenticator and Supplicant (with 802.11s mesh and SAE support).
+endef
+
+define Package/wpa-supplicant
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=WPA Supplicant
+  URL:=http://hostap.epitest.fi/wpa_supplicant/
+  DEPENDS:=$(DRV_DEPENDS) +WPA_SUPPLICANT_OPENSSL:libopenssl
+  CONFLICTS:=wpad wpad-mini wpad-mesh
+  VARIANT:=supplicant-full
+endef
+
+define Package/wpa-supplicant/Description
+  WPA Supplicant
+endef
+
+define Package/wpa-supplicant/config
+	source "$(SOURCE)/Config.in"
+endef
+
+define Package/wpa-supplicant-p2p
+  $(Package/wpa-supplicant)
+  TITLE:=WPA Supplicant (with Wi-Fi P2P support)
+  DEPENDS:=$(DRV_DEPENDS) @PACKAGE_kmod-cfg80211
+  CONFLICTS:=wpad wpad-mini wpad-mesh
+  VARIANT:=supplicant-p2p
+endef
+
+define Package/wpa-supplicant-p2p/Description
+  WPA Supplicant (with Wi-Fi P2P support)
+endef
+
+define Package/wpa-supplicant-mesh
+  $(Package/wpa-supplicant)
+  TITLE:=WPA Supplicant (with 802.11s and SAE)
+  DEPENDS:=$(DRV_DEPENDS) +PACKAGE_wpa-supplicant-mesh:libopenssl @PACKAGE_kmod-cfg80211 @(!TARGET_uml||BROKEN)
+  CONFLICTS:=wpad wpad-mesh wpad-mesh
+  VARIANT:=supplicant-mesh
+endef
+
+define Package/wpa-supplicant-mesh/Description
+  WPA Supplicant (variant with 802.11s and SAE support)
+endef
+
+define Package/wpa-supplicant-mini
+  $(Package/wpa-supplicant)
+  TITLE:=WPA Supplicant (minimal version)
+  DEPENDS:=$(DRV_DEPENDS)
+  CONFLICTS:=wpad wpad-mini wpad-mesh
+  VARIANT:=supplicant-mini
+endef
+
+define Package/wpa-supplicant-mini/Description
+  WPA Supplicant (minimal version)
+endef
+
+define Package/wpa-cli
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=@PACKAGE_wpa-supplicant||PACKAGE_wpa-supplicant-p2p||PACKAGE_wpad-mini||PACKAGE_wpad||PACKAGE_wpad-mesh
+  TITLE:=WPA Supplicant command line interface
+endef
+
+define Package/wpa-cli/Description
+  WPA Supplicant control utility
+endef
+
+define Package/hostapd-common
+  TITLE:=hostapd/wpa_supplicant common support files
+  SECTION:=net
+  CATEGORY:=Network
+endef
+
+define Package/eapol-test
+  TITLE:=802.1x authentication test utility
+  SECTION:=net
+  CATEGORY:=Network
+  VARIANT:=supplicant-full
+  DEPENDS:=$(DRV_DEPENDS)
+endef
+
+
+ifneq ($(wildcard $(PKG_BUILD_DIR)/.config_*),$(subst .configured_,.config_,$(STAMP_CONFIGURED)))
+  define Build/Configure/rebuild
+	$(FIND) $(PKG_BUILD_DIR) -name \*.o -or -name \*.a | $(XARGS) rm -f
+	rm -f $(PKG_BUILD_DIR)/hostapd/hostapd
+	rm -f $(PKG_BUILD_DIR)/wpa_supplicant/wpa_supplicant
+	rm -f $(PKG_BUILD_DIR)/.config_*
+	touch $(subst .configured_,.config_,$(STAMP_CONFIGURED))
+  endef
+endif
+
+define Build/Configure
+	$(Build/Configure/rebuild)
+	$(if $(wildcard ./files/hostapd-$(CONFIG_VARIANT).config), \
+		$(CP) ./files/hostapd-$(CONFIG_VARIANT).config $(PKG_BUILD_DIR)/hostapd/.config \
+	)
+	$(CP) ./files/wpa_supplicant-$(CONFIG_VARIANT).config $(PKG_BUILD_DIR)/wpa_supplicant/.config
+endef
+
+TARGET_CPPFLAGS := \
+	-I$(STAGING_DIR)/usr/include/libnl-tiny \
+	-I$(PKG_BUILD_DIR)/src/crypto \
+	$(TARGET_CPPFLAGS) \
+	-DCONFIG_LIBNL20 \
+	-D_GNU_SOURCE \
+	$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+ifeq ($(findstring supplicant,$(BUILD_VARIANT)),)
+  TARGET_LDFLAGS += -lubox -lubus
+endif
+
+ifdef CONFIG_PACKAGE_kmod-cfg80211
+  TARGET_LDFLAGS += -lm -lnl-tiny
+endif
+
+define Build/RunMake
+	CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
+	$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/$(1) \
+		$(TARGET_CONFIGURE_OPTS) \
+		$(DRIVER_MAKEOPTS) \
+		LIBS="$(TARGET_LDFLAGS)" \
+		LIBS_c="$(TARGET_LDFLAGS_C)" \
+		BCHECK= \
+		$(2)
+endef
+
+define Build/Compile/wpad
+	echo ` \
+		$(call Build/RunMake,hostapd,-s MULTICALL=1 dump_cflags); \
+		$(call Build/RunMake,wpa_supplicant,-s MULTICALL=1 dump_cflags) | \
+		sed -e 's,-n ,,g' -e 's^$(TARGET_CFLAGS)^^' \
+	` > $(PKG_BUILD_DIR)/.cflags
+	+$(call Build/RunMake,hostapd, \
+		CFLAGS="$$$$(cat $(PKG_BUILD_DIR)/.cflags)" \
+		MULTICALL=1 \
+		hostapd_cli hostapd_multi.a \
+	)
+	+$(call Build/RunMake,wpa_supplicant, \
+		CFLAGS="$$$$(cat $(PKG_BUILD_DIR)/.cflags)" \
+		MULTICALL=1 \
+		wpa_cli wpa_supplicant_multi.a \
+	)
+	$(TARGET_CC) -o $(PKG_BUILD_DIR)/wpad \
+		$(TARGET_CFLAGS) \
+		./files/multicall.c \
+		$(PKG_BUILD_DIR)/hostapd/hostapd_multi.a \
+		$(PKG_BUILD_DIR)/wpa_supplicant/wpa_supplicant_multi.a \
+		$(TARGET_LDFLAGS)
+endef
+
+define Build/Compile/hostapd
+	$(call Build/RunMake,hostapd, \
+		hostapd hostapd_cli \
+	)
+endef
+
+define Build/Compile/supplicant
+	$(call Build/RunMake,wpa_supplicant, \
+		wpa_cli wpa_supplicant \
+	)
+endef
+
+define Build/Compile/supplicant-full
+	$(call Build/RunMake,wpa_supplicant, \
+		eapol_test \
+	)
+endef
+
+define Build/Compile
+	$(Build/Compile/$(LOCAL_TYPE))
+	$(Build/Compile/$(BUILD_VARIANT))
+endef
+
+define Install/hostapd
+	$(INSTALL_DIR) $(1)/usr/sbin
+endef
+
+define Install/supplicant
+	$(INSTALL_DIR) $(1)/usr/sbin
+endef
+
+define Package/hostapd-common/install
+	$(INSTALL_DIR) $(1)/lib/netifd
+	$(INSTALL_DATA) ./files/netifd.sh $(1)/lib/netifd/hostapd.sh
+endef
+
+define Package/hostapd/install
+	$(call Install/hostapd,$(1))
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/hostapd/hostapd $(1)/usr/sbin/
+endef
+Package/hostapd-mini/install = $(Package/hostapd/install)
+
+ifneq ($(LOCAL_TYPE),supplicant)
+  define Package/hostapd-utils/install
+	$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/rc.button
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/hostapd/hostapd_cli $(1)/usr/sbin/
+	$(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps
+  endef
+endif
+
+define Package/wpad/install
+	$(call Install/hostapd,$(1))
+	$(call Install/supplicant,$(1))
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/wpad $(1)/usr/sbin/
+	$(LN) wpad $(1)/usr/sbin/hostapd
+	$(LN) wpad $(1)/usr/sbin/wpa_supplicant
+endef
+Package/wpad-mini/install = $(Package/wpad/install)
+Package/wpad-mesh/install = $(Package/wpad/install)
+
+define Package/wpa-supplicant/install
+	$(call Install/supplicant,$(1))
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/wpa_supplicant/wpa_supplicant $(1)/usr/sbin/
+endef
+Package/wpa-supplicant-mini/install = $(Package/wpa-supplicant/install)
+Package/wpa-supplicant-p2p/install = $(Package/wpa-supplicant/install)
+Package/wpa-supplicant-mesh/install = $(Package/wpa-supplicant/install)
+
+ifneq ($(LOCAL_TYPE),hostapd)
+  define Package/wpa-cli/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_BUILD_DIR)/wpa_supplicant/wpa_cli $(1)/usr/sbin/
+  endef
+endif
+
+ifeq ($(BUILD_VARIANT),supplicant-full)
+  define Package/eapol-test/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_BUILD_DIR)/wpa_supplicant/eapol_test $(1)/usr/sbin/
+  endef
+endif
+
+$(eval $(call BuildPackage,hostapd))
+$(eval $(call BuildPackage,hostapd-mini))
+$(eval $(call BuildPackage,wpad))
+$(eval $(call BuildPackage,wpad-mesh))
+$(eval $(call BuildPackage,wpad-mini))
+$(eval $(call BuildPackage,wpa-supplicant))
+$(eval $(call BuildPackage,wpa-supplicant-mesh))
+$(eval $(call BuildPackage,wpa-supplicant-mini))
+$(eval $(call BuildPackage,wpa-supplicant-p2p))
+$(eval $(call BuildPackage,wpa-cli))
+$(eval $(call BuildPackage,hostapd-utils))
+$(eval $(call BuildPackage,hostapd-common))
+$(eval $(call BuildPackage,eapol-test))
diff --git a/package/network/services/hostapd/files/hostapd-full.config b/package/network/services/hostapd/files/hostapd-full.config
new file mode 100644
index 0000000000..e388109fbb
--- /dev/null
+++ b/package/network/services/hostapd/files/hostapd-full.config
@@ -0,0 +1,169 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for Prism54 driver
+#CONFIG_DRIVER_PRISM54=y
+
+# Driver interface for drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+CONFIG_EAP=y
+
+# EAP-FAST for the integrated EAP server
+CONFIG_EAP_FAST=y
+
+# EAP-MD5 for the integrated EAP server
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+CONFIG_WPS2=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g. FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=y
+
+# IEEE 802.11ac (Very High Throughput) support
+CONFIG_IEEE80211AC=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+#CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+CONFIG_TLS=internal
+CONFIG_INTERNAL_LIBTOMMATH=y
+CONFIG_INTERNAL_AES=y
+NEED_AES_DEC=y
+
+CONFIG_NO_RANDOM_POOL=y
+CONFIG_NO_DUMP_STATE=y
+
+CONFIG_WPS=y
+CONFIG_FULL_DYNAMIC_VLAN=y
+
+CONFIG_UBUS=y
diff --git a/package/network/services/hostapd/files/hostapd-mini.config b/package/network/services/hostapd/files/hostapd-mini.config
new file mode 100644
index 0000000000..8baff18fe4
--- /dev/null
+++ b/package/network/services/hostapd/files/hostapd-mini.config
@@ -0,0 +1,159 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for Prism54 driver
+#CONFIG_DRIVER_PRISM54=y
+
+# Driver interface for drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+# CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+#CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+#CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+#CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+#CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+#CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+#CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+#CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+#CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+#CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g. FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=y
+
+# IEEE 802.11ac (Very High Throughput) support
+CONFIG_IEEE80211AC=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove support for RADIUS accounting
+CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+CONFIG_TLS=internal
+
+CONFIG_NO_RANDOM_POOL=y
+CONFIG_NO_DUMP_STATE=y
+
+CONFIG_UBUS=y
diff --git a/package/network/services/hostapd/files/multicall.c b/package/network/services/hostapd/files/multicall.c
new file mode 100644
index 0000000000..c8e814bb5c
--- /dev/null
+++ b/package/network/services/hostapd/files/multicall.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+extern int hostapd_main(int argc, char **argv);
+extern int wpa_supplicant_main(int argc, char **argv);
+
+int main(int argc, char **argv)
+{
+	bool restart = false;
+	const char *prog = argv[0];
+
+restart:
+	if (strstr(argv[0], "hostapd"))
+		return hostapd_main(argc, argv);
+	else if (strstr(argv[0], "wpa_supplicant"))
+		return wpa_supplicant_main(argc, argv);
+
+	if (!restart && argc > 1) {
+		argv++;
+		argc--;
+		restart = true;
+		goto restart;
+	}
+
+	fprintf(stderr, "Invalid command.\nUsage: %s wpa_supplicant|hostapd [<arguments>]\n", prog);
+	return 255;
+}
diff --git a/package/network/services/hostapd/files/netifd.sh b/package/network/services/hostapd/files/netifd.sh
new file mode 100644
index 0000000000..a24a5c30d5
--- /dev/null
+++ b/package/network/services/hostapd/files/netifd.sh
@@ -0,0 +1,755 @@
+. /lib/functions/network.sh
+
+wpa_supplicant_add_rate() {
+	local var="$1"
+	local val="$(($2 / 1000))"
+	local sub="$((($2 / 100) % 10))"
+	append $var "$val" ","
+	[ $sub -gt 0 ] && append $var "."
+}
+
+hostapd_add_rate() {
+	local var="$1"
+	local val="$(($2 / 100))"
+	append $var "$val" " "
+}
+
+hostapd_append_wep_key() {
+	local var="$1"
+
+	wep_keyidx=0
+	set_default key 1
+	case "$key" in
+		[1234])
+			for idx in 1 2 3 4; do
+				local zidx
+				zidx=$(($idx - 1))
+				json_get_var ckey "key${idx}"
+				[ -n "$ckey" ] && \
+					append $var "wep_key${zidx}=$(prepare_key_wep "$ckey")" "$N$T"
+			done
+			wep_keyidx=$((key - 1))
+		;;
+		*)
+			append $var "wep_key0=$(prepare_key_wep "$key")" "$N$T"
+		;;
+	esac
+}
+
+hostapd_add_log_config() {
+	config_add_boolean \
+		log_80211 \
+		log_8021x \
+		log_radius \
+		log_wpa \
+		log_driver \
+		log_iapp \
+		log_mlme
+
+	config_add_int log_level
+}
+
+hostapd_common_add_device_config() {
+	config_add_array basic_rate
+	config_add_array supported_rates
+
+	config_add_string country
+	config_add_boolean country_ie doth
+	config_add_string require_mode
+
+	hostapd_add_log_config
+}
+
+hostapd_prepare_device_config() {
+	local config="$1"
+	local driver="$2"
+
+	local base="${config%%.conf}"
+	local base_cfg=
+
+	json_get_vars country country_ie beacon_int doth require_mode
+
+	hostapd_set_log_options base_cfg
+
+	set_default country_ie 1
+	set_default doth 1
+
+	[ -n "$country" ] && {
+		append base_cfg "country_code=$country" "$N"
+
+		[ "$country_ie" -gt 0 ] && append base_cfg "ieee80211d=1" "$N"
+		[ "$hwmode" = "a" -a "$doth" -gt 0 ] && append base_cfg "ieee80211h=1" "$N"
+	}
+	[ -n "$hwmode" ] && append base_cfg "hw_mode=$hwmode" "$N"
+
+	local brlist= br
+	json_get_values basic_rate_list basic_rate
+	for br in $basic_rate_list; do
+		hostapd_add_rate brlist "$br"
+	done
+	case "$require_mode" in
+		g) brlist="60 120 240" ;;
+		n) append base_cfg "require_ht=1" "$N";;
+		ac) append base_cfg "require_vht=1" "$N";;
+	esac
+
+	local rlist= r
+	json_get_values rate_list supported_rates
+	for r in $rate_list; do
+		hostapd_add_rate rlist "$r"
+	done
+
+	[ -n "$rlist" ] && append base_cfg "supported_rates=$rlist" "$N"
+	[ -n "$brlist" ] && append base_cfg "basic_rates=$brlist" "$N"
+	[ -n "$beacon_int" ] && append base_cfg "beacon_int=$beacon_int" "$N"
+
+	cat > "$config" <<EOF
+driver=$driver
+$base_cfg
+EOF
+}
+
+hostapd_common_add_bss_config() {
+	config_add_string 'bssid:macaddr' 'ssid:string'
+	config_add_boolean wds wmm uapsd hidden
+
+	config_add_int maxassoc max_inactivity
+	config_add_boolean disassoc_low_ack isolate short_preamble
+
+	config_add_int \
+		wep_rekey eap_reauth_period \
+		wpa_group_rekey wpa_pair_rekey wpa_master_rekey
+
+	config_add_boolean rsn_preauth auth_cache
+	config_add_int ieee80211w
+	config_add_int eapol_version
+
+	config_add_string 'auth_server:host' 'server:host'
+	config_add_string auth_secret
+	config_add_int 'auth_port:port' 'port:port'
+
+	config_add_string acct_server
+	config_add_string acct_secret
+	config_add_int acct_port
+
+	config_add_string dae_client
+	config_add_string dae_secret
+	config_add_int dae_port
+
+	config_add_string nasid
+	config_add_string ownip
+	config_add_string iapp_interface
+	config_add_string eap_type ca_cert client_cert identity anonymous_identity auth priv_key priv_key_pwd
+
+	config_add_int dynamic_vlan vlan_naming
+	config_add_string vlan_tagged_interface vlan_bridge
+	config_add_string vlan_file
+
+	config_add_string 'key1:wepkey' 'key2:wepkey' 'key3:wepkey' 'key4:wepkey' 'password:wpakey'
+
+	config_add_string wpa_psk_file
+
+	config_add_boolean wps_pushbutton wps_label ext_registrar wps_pbc_in_m1
+	config_add_string wps_device_type wps_device_name wps_manufacturer wps_pin
+
+	config_add_boolean ieee80211r pmk_r1_push
+	config_add_int r0_key_lifetime reassociation_deadline
+	config_add_string mobility_domain r1_key_holder
+	config_add_array r0kh r1kh
+
+	config_add_int ieee80211w_max_timeout ieee80211w_retry_timeout
+
+	config_add_string macfilter 'macfile:file'
+	config_add_array 'maclist:list(macaddr)'
+
+	config_add_array bssid_blacklist
+	config_add_array bssid_whitelist
+
+	config_add_int mcast_rate
+	config_add_array basic_rate
+	config_add_array supported_rates
+}
+
+hostapd_set_bss_options() {
+	local var="$1"
+	local phy="$2"
+	local vif="$3"
+
+	wireless_vif_parse_encryption
+
+	local bss_conf
+	local wep_rekey wpa_group_rekey wpa_pair_rekey wpa_master_rekey wpa_key_mgmt
+
+	json_get_vars \
+		wep_rekey wpa_group_rekey wpa_pair_rekey wpa_master_rekey \
+		maxassoc max_inactivity disassoc_low_ack isolate auth_cache \
+		wps_pushbutton wps_label ext_registrar wps_pbc_in_m1 \
+		wps_device_type wps_device_name wps_manufacturer wps_pin \
+		macfilter ssid wmm uapsd hidden short_preamble rsn_preauth \
+		iapp_interface eapol_version acct_server acct_secret acct_port \
+		dynamic_vlan
+
+	set_default isolate 0
+	set_default maxassoc 0
+	set_default max_inactivity 0
+	set_default short_preamble 1
+	set_default disassoc_low_ack 1
+	set_default hidden 0
+	set_default wmm 1
+	set_default uapsd 1
+	set_default eapol_version 0
+	set_default acct_port 1813
+
+	append bss_conf "ctrl_interface=/var/run/hostapd"
+	if [ "$isolate" -gt 0 ]; then
+		append bss_conf "ap_isolate=$isolate" "$N"
+	fi
+	if [ "$maxassoc" -gt 0 ]; then
+		append bss_conf "max_num_sta=$maxassoc" "$N"
+	fi
+	if [ "$max_inactivity" -gt 0 ]; then
+		append bss_conf "ap_max_inactivity=$max_inactivity" "$N"
+	fi
+
+	append bss_conf "disassoc_low_ack=$disassoc_low_ack" "$N"
+	append bss_conf "preamble=$short_preamble" "$N"
+	append bss_conf "wmm_enabled=$wmm" "$N"
+	append bss_conf "ignore_broadcast_ssid=$hidden" "$N"
+	append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N"
+
+	[ "$wpa" -gt 0 ] && {
+		[ -n "$wpa_group_rekey"  ] && append bss_conf "wpa_group_rekey=$wpa_group_rekey" "$N"
+		[ -n "$wpa_pair_rekey"   ] && append bss_conf "wpa_ptk_rekey=$wpa_pair_rekey"    "$N"
+		[ -n "$wpa_master_rekey" ] && append bss_conf "wpa_gmk_rekey=$wpa_master_rekey"  "$N"
+	}
+
+	[ -n "$acct_server" ] && {
+		append bss_conf "acct_server_addr=$acct_server" "$N"
+		append bss_conf "acct_server_port=$acct_port" "$N"
+		[ -n "$acct_secret" ] && \
+			append bss_conf "acct_server_shared_secret=$acct_secret" "$N"
+	}
+
+	local vlan_possible=""
+
+	case "$auth_type" in
+		none)
+			wps_possible=1
+			# Here we make the assumption that if we're in open mode
+			# with WPS enabled, we got to be in unconfigured state.
+			wps_not_configured=1
+		;;
+		psk)
+			json_get_vars key wpa_psk_file
+			if [ ${#key} -lt 8 ]; then
+				wireless_setup_vif_failed INVALID_WPA_PSK
+				return 1
+			elif [ ${#key} -eq 64 ]; then
+				append bss_conf "wpa_psk=$key" "$N"
+			else
+				append bss_conf "wpa_passphrase=$key" "$N"
+			fi
+			[ -n "$wpa_psk_file" ] && {
+				[ -e "$wpa_psk_file" ] || touch "$wpa_psk_file"
+				append bss_conf "wpa_psk_file=$wpa_psk_file" "$N"
+			}
+			[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N"
+
+			wps_possible=1
+			append wpa_key_mgmt "WPA-PSK"
+		;;
+		eap)
+			json_get_vars \
+				auth_server auth_secret auth_port \
+				dae_client dae_secret dae_port \
+				ownip \
+				eap_reauth_period
+
+			# radius can provide VLAN ID for clients
+			vlan_possible=1
+
+			# legacy compatibility
+			[ -n "$auth_server" ] || json_get_var auth_server server
+			[ -n "$auth_port" ] || json_get_var auth_port port
+			[ -n "$auth_secret" ] || json_get_var auth_secret key
+
+			set_default auth_port 1812
+			set_default dae_port 3799
+
+
+			append bss_conf "auth_server_addr=$auth_server" "$N"
+			append bss_conf "auth_server_port=$auth_port" "$N"
+			append bss_conf "auth_server_shared_secret=$auth_secret" "$N"
+
+			[ -n "$eap_reauth_period" ] && append bss_conf "eap_reauth_period=$eap_reauth_period" "$N"
+
+			[ -n "$dae_client" -a -n "$dae_secret" ] && {
+				append bss_conf "radius_das_port=$dae_port" "$N"
+				append bss_conf "radius_das_client=$dae_client $dae_secret" "$N"
+			}
+
+			[ -n "$ownip" ] && append bss_conf "own_ip_addr=$ownip" "$N"
+			append bss_conf "eapol_key_index_workaround=1" "$N"
+			append bss_conf "ieee8021x=1" "$N"
+			append wpa_key_mgmt "WPA-EAP"
+
+			[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N"
+		;;
+		wep)
+			local wep_keyidx=0
+			json_get_vars key
+			hostapd_append_wep_key bss_conf
+			append bss_conf "wep_default_key=$wep_keyidx" "$N"
+			[ -n "$wep_rekey" ] && append bss_conf "wep_rekey_period=$wep_rekey" "$N"
+		;;
+	esac
+
+	local auth_algs=$((($auth_mode_shared << 1) | $auth_mode_open))
+	append bss_conf "auth_algs=${auth_algs:-1}" "$N"
+	append bss_conf "wpa=$wpa" "$N"
+	[ -n "$wpa_pairwise" ] && append bss_conf "wpa_pairwise=$wpa_pairwise" "$N"
+
+	set_default wps_pushbutton 0
+	set_default wps_label 0
+	set_default wps_pbc_in_m1 0
+
+	config_methods=
+	[ "$wps_pushbutton" -gt 0 ] && append config_methods push_button
+	[ "$wps_label" -gt 0 ] && append config_methods label
+
+	[ -n "$wps_possible" -a -n "$config_methods" ] && {
+		set_default ext_registrar 0
+		set_default wps_device_type "6-0050F204-1"
+		set_default wps_device_name "Lede AP"
+		set_default wps_manufacturer "www.lede-project.org"
+
+		wps_state=2
+		[ -n "$wps_configured" ] && wps_state=1
+
+		[ "$ext_registrar" -gt 0 -a -n "$network_bridge" ] && append bss_conf "upnp_iface=$network_bridge" "$N"
+
+		append bss_conf "eap_server=1" "$N"
+		[ -n "$wps_pin" ] && append bss_conf "ap_pin=$wps_pin" "$N"
+		append bss_conf "wps_state=$wps_state" "$N"
+		append bss_conf "ap_setup_locked=0" "$N"
+		append bss_conf "device_type=$wps_device_type" "$N"
+		append bss_conf "device_name=$wps_device_name" "$N"
+		append bss_conf "manufacturer=$wps_manufacturer" "$N"
+		append bss_conf "config_methods=$config_methods" "$N"
+		[ "$wps_pbc_in_m1" -gt 0 ] && append bss_conf "pbc_in_m1=$wps_pbc_in_m1" "$N"
+	}
+
+	append bss_conf "ssid=$ssid" "$N"
+	[ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge" "$N"
+	[ -n "$iapp_interface" ] && {
+		local ifname
+		network_get_device ifname "$iapp_interface" || ifname = "$iapp_interface"
+		append bss_conf "iapp_interface=$ifname" "$N"
+	}
+
+	if [ "$wpa" -ge "1" ]; then
+		json_get_vars nasid ieee80211r
+		set_default ieee80211r 0
+		[ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N"
+
+		if [ "$ieee80211r" -gt "0" ]; then
+			json_get_vars mobility_domain r0_key_lifetime r1_key_holder \
+			reassociation_deadline pmk_r1_push
+			json_get_values r0kh r0kh
+			json_get_values r1kh r1kh
+
+			set_default mobility_domain "4f57"
+			set_default r0_key_lifetime 10000
+			set_default r1_key_holder "00004f577274"
+			set_default reassociation_deadline 1000
+			set_default pmk_r1_push 0
+
+			append bss_conf "mobility_domain=$mobility_domain" "$N"
+			append bss_conf "r0_key_lifetime=$r0_key_lifetime" "$N"
+			append bss_conf "r1_key_holder=$r1_key_holder" "$N"
+			append bss_conf "reassociation_deadline=$reassociation_deadline" "$N"
+			append bss_conf "pmk_r1_push=$pmk_r1_push" "$N"
+
+			for kh in $r0kh; do
+				append bss_conf "r0kh=${kh//,/ }" "$N"
+			done
+			for kh in $r1kh; do
+				append bss_conf "r1kh=${kh//,/ }" "$N"
+			done
+
+			[ "$wpa_key_mgmt" != "${wpa_key_mgmt/EAP/}" ] && append wpa_key_mgmt "FT-EAP"
+			[ "$wpa_key_mgmt" != "${wpa_key_mgmt/PSK/}" ] && append wpa_key_mgmt "FT-PSK"
+		fi
+
+		[ -n "$wpa_key_mgmt" ] && append bss_conf "wpa_key_mgmt=$wpa_key_mgmt" "$N"
+	fi
+
+	if [ "$wpa" -ge "2" ]; then
+		if [ -n "$network_bridge" -a "$rsn_preauth" = 1 ]; then
+			set_default auth_cache 1
+			append bss_conf "rsn_preauth=1" "$N"
+			append bss_conf "rsn_preauth_interfaces=$network_bridge" "$N"
+		else
+			set_default auth_cache 0
+		fi
+
+		append bss_conf "okc=$auth_cache" "$N"
+		[ "$auth_cache" = 0 ] && append bss_conf "disable_pmksa_caching=1" "$N"
+
+		# RSN -> allow management frame protection
+		json_get_var ieee80211w ieee80211w
+		case "$ieee80211w" in
+			[012])
+				json_get_vars ieee80211w_max_timeout ieee80211w_retry_timeout
+				append bss_conf "ieee80211w=$ieee80211w" "$N"
+				[ "$ieee80211w" -gt "0" ] && {
+					[ -n "$ieee80211w_max_timeout" ] && \
+						append bss_conf "assoc_sa_query_max_timeout=$ieee80211w_max_timeout" "$N"
+					[ -n "$ieee80211w_retry_timeout" ] && \
+						append bss_conf "assoc_sa_query_retry_timeout=$ieee80211w_retry_timeout" "$N"
+				}
+			;;
+		esac
+	fi
+
+	_macfile="/var/run/hostapd-$ifname.maclist"
+	case "$macfilter" in
+		allow)
+			append bss_conf "macaddr_acl=1" "$N"
+			append bss_conf "accept_mac_file=$_macfile" "$N"
+			# accept_mac_file can be used to set MAC to VLAN ID mapping
+			vlan_possible=1
+		;;
+		deny)
+			append bss_conf "macaddr_acl=0" "$N"
+			append bss_conf "deny_mac_file=$_macfile" "$N"
+		;;
+		*)
+			_macfile=""
+		;;
+	esac
+
+	[ -n "$_macfile" ] && {
+		json_get_vars macfile
+		json_get_values maclist maclist
+
+		rm -f "$_macfile"
+		(
+			for mac in $maclist; do
+				echo "$mac"
+			done
+			[ -n "$macfile" -a -f "$macfile" ] && cat "$macfile"
+		) > "$_macfile"
+	}
+
+	[ -n "$vlan_possible" -a -n "$dynamic_vlan" ] && {
+		json_get_vars vlan_naming vlan_tagged_interface vlan_bridge vlan_file
+		set_default vlan_naming 1
+		append bss_conf "dynamic_vlan=$dynamic_vlan" "$N"
+		append bss_conf "vlan_naming=$vlan_naming" "$N"
+		[ -n "$vlan_bridge" ] && \
+			append bss_conf "vlan_bridge=$vlan_bridge" "$N"
+		[ -n "$vlan_tagged_interface" ] && \
+			append bss_conf "vlan_tagged_interface=$vlan_tagged_interface" "$N"
+		[ -n "$vlan_file" ] && {
+			[ -e "$vlan_file" ] || touch "$vlan_file"
+			append bss_conf "vlan_file=$vlan_file" "$N"
+		}
+	}
+
+	append "$var" "$bss_conf" "$N"
+	return 0
+}
+
+hostapd_set_log_options() {
+	local var="$1"
+
+	local log_level log_80211 log_8021x log_radius log_wpa log_driver log_iapp log_mlme
+	json_get_vars log_level log_80211 log_8021x log_radius log_wpa log_driver log_iapp log_mlme
+
+	set_default log_level 2
+	set_default log_80211  1
+	set_default log_8021x  1
+	set_default log_radius 1
+	set_default log_wpa    1
+	set_default log_driver 1
+	set_default log_iapp   1
+	set_default log_mlme   1
+
+	local log_mask=$(( \
+		($log_80211  << 0) | \
+		($log_8021x  << 1) | \
+		($log_radius << 2) | \
+		($log_wpa    << 3) | \
+		($log_driver << 4) | \
+		($log_iapp   << 5) | \
+		($log_mlme   << 6)   \
+	))
+
+	append "$var" "logger_syslog=$log_mask" "$N"
+	append "$var" "logger_syslog_level=$log_level" "$N"
+	append "$var" "logger_stdout=$log_mask" "$N"
+	append "$var" "logger_stdout_level=$log_level" "$N"
+
+	return 0
+}
+
+_wpa_supplicant_common() {
+	local ifname="$1"
+
+	_rpath="/var/run/wpa_supplicant"
+	_config="${_rpath}-$ifname.conf"
+}
+
+wpa_supplicant_teardown_interface() {
+	_wpa_supplicant_common "$1"
+	rm -rf "$_rpath/$1" "$_config"
+}
+
+wpa_supplicant_prepare_interface() {
+	local ifname="$1"
+	_w_driver="$2"
+
+	_wpa_supplicant_common "$1"
+
+	json_get_vars mode wds
+
+	[ -n "$network_bridge" ] && {
+		fail=
+		case "$mode" in
+			adhoc)
+				fail=1
+			;;
+			sta)
+				[ "$wds" = 1 ] || fail=1
+			;;
+		esac
+
+		[ -n "$fail" ] && {
+			wireless_setup_vif_failed BRIDGE_NOT_ALLOWED
+			return 1
+		}
+	}
+
+	local ap_scan=
+
+	_w_mode="$mode"
+	_w_modestr=
+
+	[[ "$mode" = adhoc ]] && {
+		ap_scan="ap_scan=2"
+
+		_w_modestr="mode=1"
+	}
+
+	local country_str=
+	[ -n "$country" ] && {
+		country_str="country=$country"
+	}
+
+	wpa_supplicant_teardown_interface "$ifname"
+	cat > "$_config" <<EOF
+$ap_scan
+$country_str
+EOF
+	return 0
+}
+
+wpa_supplicant_add_network() {
+	local ifname="$1"
+
+	_wpa_supplicant_common "$1"
+	wireless_vif_parse_encryption
+
+	json_get_vars \
+		ssid bssid key \
+		basic_rate mcast_rate \
+		ieee80211w ieee80211r
+
+	set_default ieee80211r 0
+
+	local key_mgmt='NONE'
+	local enc_str=
+	local network_data=
+	local T="	"
+
+	local wpa_key_mgmt="WPA-PSK"
+	local scan_ssid="scan_ssid=1"
+	local freq
+
+	[ "$ieee80211r" -gt 0 ] && wpa_key_mgmt="FT-PSK $wpa_key_mgmt"
+
+	[[ "$_w_mode" = "adhoc" ]] && {
+		append network_data "mode=1" "$N$T"
+		[ -n "$channel" ] && {
+			freq="$(get_freq "$phy" "$channel")"
+			append network_data "fixed_freq=1" "$N$T"
+			append network_data "frequency=$freq" "$N$T"
+		}
+
+		scan_ssid="scan_ssid=0"
+
+		[ "$_w_driver" = "nl80211" ] ||	wpa_key_mgmt="WPA-NONE"
+	}
+
+	[[ "$_w_mode" = "mesh" ]] && {
+		json_get_vars mesh_id
+		ssid="${mesh_id}"
+
+		append network_data "mode=5" "$N$T"
+		[ -n "$channel" ] && {
+			freq="$(get_freq "$phy" "$channel")"
+			append network_data "frequency=$freq" "$N$T"
+		}
+		wpa_key_mgmt="SAE"
+		scan_ssid=""
+	}
+
+	[[ "$_w_mode" = "adhoc" -o "$_w_mode" = "mesh" ]] && append network_data "$_w_modestr" "$N$T"
+
+	case "$auth_type" in
+		none) ;;
+		wep)
+			local wep_keyidx=0
+			hostapd_append_wep_key network_data
+			append network_data "wep_tx_keyidx=$wep_keyidx" "$N$T"
+		;;
+		psk)
+			local passphrase
+
+			key_mgmt="$wpa_key_mgmt"
+			if [ ${#key} -eq 64 ]; then
+				passphrase="psk=${key}"
+			else
+				passphrase="psk=\"${key}\""
+			fi
+			append network_data "$passphrase" "$N$T"
+		;;
+		eap)
+			key_mgmt='WPA-EAP'
+		        [ "$ieee80211r" -gt 0 ] && key_mgmt="FT-EAP $key_mgmt"
+
+			json_get_vars eap_type identity anonymous_identity ca_cert
+			[ -n "$ca_cert" ] && append network_data "ca_cert=\"$ca_cert\"" "$N$T"
+			[ -n "$identity" ] && append network_data "identity=\"$identity\"" "$N$T"
+			[ -n "$anonymous_identity" ] && append network_data "anonymous_identity=\"$anonymous_identity\"" "$N$T"
+			case "$eap_type" in
+				tls)
+					json_get_vars client_cert priv_key priv_key_pwd
+					append network_data "client_cert=\"$client_cert\"" "$N$T"
+					append network_data "private_key=\"$priv_key\"" "$N$T"
+					append network_data "private_key_passwd=\"$priv_key_pwd\"" "$N$T"
+				;;
+				fast|peap|ttls)
+					json_get_vars auth password ca_cert2 client_cert2 priv_key2 priv_key2_pwd
+					set_default auth MSCHAPV2
+
+					if [ "$auth" = "EAP-TLS" ]; then
+						[ -n "$ca_cert2" ] &&
+							append network_data "ca_cert2=\"$ca_cert2\"" "$N$T"
+						append network_data "client_cert2=\"$client_cert2\"" "$N$T"
+						append network_data "private_key2=\"$priv_key2\"" "$N$T"
+						append network_data "private_key2_passwd=\"$priv_key2_pwd\"" "$N$T"
+					else
+						append network_data "password=\"$password\"" "$N$T"
+					fi
+
+					phase2proto="auth="
+					case "$auth" in
+						"auth"*)
+							phase2proto=""
+						;;
+						"EAP-"*)
+							auth="$(echo $auth | cut -b 5- )"
+							[ "$eap_type" = "ttls" ] &&
+								phase2proto="autheap="
+						;;
+					esac
+					append network_data "phase2=\"$phase2proto$auth\"" "$N$T"
+				;;
+			esac
+			append network_data "eap=$(echo $eap_type | tr 'a-z' 'A-Z')" "$N$T"
+		;;
+	esac
+
+	[ "$mode" = mesh ] || {
+		case "$wpa" in
+			1)
+				append network_data "proto=WPA" "$N$T"
+			;;
+			2)
+				append network_data "proto=RSN" "$N$T"
+			;;
+		esac
+
+		case "$ieee80211w" in
+			[012])
+				[ "$wpa" -ge 2 ] && append network_data "ieee80211w=$ieee80211w" "$N$T"
+			;;
+		esac
+	}
+	local beacon_int brates mrate
+	[ -n "$bssid" ] && append network_data "bssid=$bssid" "$N$T"
+	[ -n "$beacon_int" ] && append network_data "beacon_int=$beacon_int" "$N$T"
+
+	local bssid_blacklist bssid_whitelist
+	json_get_values bssid_blacklist bssid_blacklist
+	json_get_values bssid_whitelist bssid_whitelist
+
+	[ -n "$bssid_blacklist" ] && append network_data "bssid_blacklist=$bssid_blacklist" "$N$T"
+	[ -n "$bssid_whitelist" ] && append network_data "bssid_whitelist=$bssid_whitelist" "$N$T"
+
+	[ -n "$basic_rate" ] && {
+		local br rate_list=
+		for br in $basic_rate; do
+			wpa_supplicant_add_rate rate_list "$br"
+		done
+		[ -n "$rate_list" ] && append network_data "rates=$rate_list" "$N$T"
+	}
+
+	[ -n "$mcast_rate" ] && {
+		local mc_rate=
+		wpa_supplicant_add_rate mc_rate "$mcast_rate"
+		append network_data "mcast_rate=$mc_rate" "$N$T"
+	}
+
+	local ht_str
+	[[ "$_w_mode" = adhoc ]] || ibss_htmode=
+	[ -n "$ibss_htmode" ] && append network_data "htmode=$ibss_htmode" "$N$T"
+
+	cat >> "$_config" <<EOF
+network={
+	$scan_ssid
+	ssid="$ssid"
+	key_mgmt=$key_mgmt
+	$network_data
+}
+EOF
+	return 0
+}
+
+wpa_supplicant_run() {
+	local ifname="$1"; shift
+
+	_wpa_supplicant_common "$ifname"
+
+	/usr/sbin/wpa_supplicant -B \
+		${network_bridge:+-b $network_bridge} \
+		-P "/var/run/wpa_supplicant-${ifname}.pid" \
+		-D ${_w_driver:-wext} \
+		-i "$ifname" \
+		-c "$_config" \
+		-C "$_rpath" \
+		"$@"
+
+	ret="$?"
+	wireless_add_process "$(cat "/var/run/wpa_supplicant-${ifname}.pid")" /usr/sbin/wpa_supplicant 1
+
+	[ "$ret" != 0 ] && wireless_setup_vif_failed WPA_SUPPLICANT_FAILED
+
+	return $ret
+}
+
+hostapd_common_cleanup() {
+	killall hostapd wpa_supplicant meshd-nl80211
+}
diff --git a/package/network/services/hostapd/files/wpa_supplicant-full.config b/package/network/services/hostapd/files/wpa_supplicant-full.config
new file mode 100644
index 0000000000..18c3f9a5c1
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant-full.config
@@ -0,0 +1,406 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+#	-I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+# CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Include client MLME (management frame processing) for test driver
+# This can be used to test MLME operations in hostapd with the test interface.
+# space.
+#CONFIG_CLIENT_MLME=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-FAST
+CONFIG_EAP_FAST=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+#	path is given on command line, not here; this option is just used to
+#	select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=internal
+
+# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
+# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
+# even though the core GnuTLS library is released under LGPL, this extra
+# library uses GPL and as such, the terms of GPL apply to the combination
+# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
+# apply for distribution of the resulting binary.
+#CONFIG_GNUTLS_EXTRA=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+CONFIG_NO_RANDOM_POOL=y
+NEED_80211_COMMON=y
+
+CONFIG_IBSS_RSN=y
diff --git a/package/network/services/hostapd/files/wpa_supplicant-mini.config b/package/network/services/hostapd/files/wpa_supplicant-mini.config
new file mode 100644
index 0000000000..c272153b3a
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant-mini.config
@@ -0,0 +1,401 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+#	-I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+# CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Include client MLME (management frame processing) for test driver
+# This can be used to test MLME operations in hostapd with the test interface.
+# space.
+#CONFIG_CLIENT_MLME=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+# CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+# CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+# CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+# CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+# CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+# CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+# CONFIG_EAP_GTC=y
+
+# EAP-OTP
+# CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+# CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+# CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+# CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+#	path is given on command line, not here; this option is just used to
+#	select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+# CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=internal
+
+# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
+# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
+# even though the core GnuTLS library is released under LGPL, this extra
+# library uses GPL and as such, the terms of GPL apply to the combination
+# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
+# apply for distribution of the resulting binary.
+#CONFIG_GNUTLS_EXTRA=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+CONFIG_NO_RANDOM_POOL=y
+NEED_80211_COMMON=y
diff --git a/package/network/services/hostapd/files/wpa_supplicant-p2p.config b/package/network/services/hostapd/files/wpa_supplicant-p2p.config
new file mode 100644
index 0000000000..563dace352
--- /dev/null
+++ b/package/network/services/hostapd/files/wpa_supplicant-p2p.config
@@ -0,0 +1,406 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+#	-I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+# CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Include client MLME (management frame processing) for test driver
+# This can be used to test MLME operations in hostapd with the test interface.
+# space.
+#CONFIG_CLIENT_MLME=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+#	path is given on command line, not here; this option is just used to
+#	select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=internal
+
+# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
+# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
+# even though the core GnuTLS library is released under LGPL, this extra
+# library uses GPL and as such, the terms of GPL apply to the combination
+# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
+# apply for distribution of the resulting binary.
+#CONFIG_GNUTLS_EXTRA=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+CONFIG_NO_RANDOM_POOL=y
+NEED_80211_COMMON=y
+
+CONFIG_IBSS_RSN=y
+
+CONFIG_P2P=y
+CONFIG_AP=y
diff --git a/package/network/services/hostapd/files/wps-hotplug.sh b/package/network/services/hostapd/files/wps-hotplug.sh
new file mode 100644
index 0000000000..24af80e55b
--- /dev/null
+++ b/package/network/services/hostapd/files/wps-hotplug.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+if [ "$ACTION" = "pressed" -a "$BUTTON" = "wps" ]; then
+	cd /var/run/hostapd
+	for socket in *; do
+		[ -S "$socket" ] || continue
+		hostapd_cli -i "$socket" wps_pbc
+	done
+fi
+
+return 0
diff --git a/package/network/services/hostapd/patches/001-4addr-fix-reconnecting-client-on-connection-lost.patch b/package/network/services/hostapd/patches/001-4addr-fix-reconnecting-client-on-connection-lost.patch
new file mode 100644
index 0000000000..5c8b6622c9
--- /dev/null
+++ b/package/network/services/hostapd/patches/001-4addr-fix-reconnecting-client-on-connection-lost.patch
@@ -0,0 +1,25 @@
+From: Matthias May <matthias.may@neratec.com>
+Date: Tue, 5 Jul 2016 15:00:43 +0200
+Subject: [PATCH] 4addr: fix reconnecting client on connection lost
+
+When a 4addr client suddenly looses its connection (no deauth/deassoc)
+the AP still thinks it is connected.
+If the client reconnects before the AP timeoutes the client, traffic
+cannot flow.
+
+Fix this by making sure the WLAN_STA_WDS flag is unset in the sta->flags
+when the client completes association.
+
+Signed-off-by: Matthias May <matthias.may@neratec.com>
+---
+
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -2826,6 +2826,7 @@ static void handle_assoc_cb(struct hosta
+ 		new_assoc = 0;
+ 	sta->flags |= WLAN_STA_ASSOC;
+ 	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
++	sta->flags &= ~WLAN_STA_WDS;
+ 	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) ||
+ 	    sta->auth_alg == WLAN_AUTH_FT) {
+ 		/*
diff --git a/package/network/services/hostapd/patches/100-daemonize_fix.patch b/package/network/services/hostapd/patches/100-daemonize_fix.patch
new file mode 100644
index 0000000000..0389406a98
--- /dev/null
+++ b/package/network/services/hostapd/patches/100-daemonize_fix.patch
@@ -0,0 +1,97 @@
+--- a/src/utils/os_unix.c
++++ b/src/utils/os_unix.c
+@@ -10,6 +10,7 @@
+ 
+ #include <time.h>
+ #include <sys/wait.h>
++#include <fcntl.h>
+ 
+ #ifdef ANDROID
+ #include <sys/capability.h>
+@@ -179,59 +180,46 @@ int os_gmtime(os_time_t t, struct os_tm
+ 	return 0;
+ }
+ 
+-
+-#ifdef __APPLE__
+-#include <fcntl.h>
+-static int os_daemon(int nochdir, int noclose)
++int os_daemonize(const char *pid_file)
+ {
+-	int devnull;
++	int pid = 0, i, devnull;
+ 
+-	if (chdir("/") < 0)
+-		return -1;
++#if defined(__uClinux__) || defined(__sun__)
++	return -1;
++#else /* defined(__uClinux__) || defined(__sun__) */
+ 
+-	devnull = open("/dev/null", O_RDWR);
+-	if (devnull < 0)
++#ifndef __APPLE__
++	pid = fork();
++	if (pid < 0)
+ 		return -1;
++#endif
+ 
+-	if (dup2(devnull, STDIN_FILENO) < 0) {
+-		close(devnull);
+-		return -1;
++	if (pid > 0) {
++		if (pid_file) {
++			FILE *f = fopen(pid_file, "w");
++			if (f) {
++				fprintf(f, "%u\n", pid);
++				fclose(f);
++			}
++		}
++		_exit(0);
+ 	}
+ 
+-	if (dup2(devnull, STDOUT_FILENO) < 0) {
+-		close(devnull);
++	if (setsid() < 0)
+ 		return -1;
+-	}
+ 
+-	if (dup2(devnull, STDERR_FILENO) < 0) {
+-		close(devnull);
++	if (chdir("/") < 0)
+ 		return -1;
+-	}
+ 
+-	return 0;
+-}
+-#else /* __APPLE__ */
+-#define os_daemon daemon
+-#endif /* __APPLE__ */
+-
+-
+-int os_daemonize(const char *pid_file)
+-{
+-#if defined(__uClinux__) || defined(__sun__)
+-	return -1;
+-#else /* defined(__uClinux__) || defined(__sun__) */
+-	if (os_daemon(0, 0)) {
+-		perror("daemon");
++	devnull = open("/dev/null", O_RDWR);
++	if (devnull < 0)
+ 		return -1;
+-	}
+ 
+-	if (pid_file) {
+-		FILE *f = fopen(pid_file, "w");
+-		if (f) {
+-			fprintf(f, "%u\n", getpid());
+-			fclose(f);
+-		}
+-	}
++	for (i = 0; i <= STDERR_FILENO; i++)
++		dup2(devnull, i);
++
++	if (devnull > 2)
++		close(devnull);
+ 
+ 	return -0;
+ #endif /* defined(__uClinux__) || defined(__sun__) */
diff --git a/package/network/services/hostapd/patches/110-no_eapol_fix.patch b/package/network/services/hostapd/patches/110-no_eapol_fix.patch
new file mode 100644
index 0000000000..5aee3d07f1
--- /dev/null
+++ b/package/network/services/hostapd/patches/110-no_eapol_fix.patch
@@ -0,0 +1,14 @@
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -257,9 +257,10 @@ void wpa_supplicant_cancel_auth_timeout(
+  */
+ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
+ {
++	struct wpa_ssid *ssid = wpa_s->current_ssid;
++
+ #ifdef IEEE8021X_EAPOL
+ 	struct eapol_config eapol_conf;
+-	struct wpa_ssid *ssid = wpa_s->current_ssid;
+ 
+ #ifdef CONFIG_IBSS_RSN
+ 	if (ssid->mode == WPAS_MODE_IBSS &&
diff --git a/package/network/services/hostapd/patches/120-disable_bridge_packet_workaround.patch b/package/network/services/hostapd/patches/120-disable_bridge_packet_workaround.patch
new file mode 100644
index 0000000000..fdd5da9bf5
--- /dev/null
+++ b/package/network/services/hostapd/patches/120-disable_bridge_packet_workaround.patch
@@ -0,0 +1,12 @@
+--- a/src/l2_packet/l2_packet_linux.c
++++ b/src/l2_packet/l2_packet_linux.c
+@@ -337,8 +337,7 @@ struct l2_packet_data * l2_packet_init_b
+ 
+ 	l2 = l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
+ 			    rx_callback_ctx, l2_hdr);
+-	if (!l2)
+-		return NULL;
++	return l2;
+ 
+ #ifndef CONFIG_NO_LINUX_PACKET_SOCKET_WAR
+ 	/*
diff --git a/package/network/services/hostapd/patches/130-Revert-nl80211-Remove-duplicated-check-in-nl80211_se.patch b/package/network/services/hostapd/patches/130-Revert-nl80211-Remove-duplicated-check-in-nl80211_se.patch
new file mode 100644
index 0000000000..dda1fa5894
--- /dev/null
+++ b/package/network/services/hostapd/patches/130-Revert-nl80211-Remove-duplicated-check-in-nl80211_se.patch
@@ -0,0 +1,39 @@
+From 23dc11dfbd8e78a2450120e9afc83c1d32a8e683 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 12 Sep 2016 19:02:34 +0200
+Subject: [PATCH] Revert "nl80211: Remove duplicated check in
+ nl80211_setup_ap()"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit 647862eb60c324015ea31293cc052558b5185ca4.
+
+The second check of device_ap_sme looks like duplicated, but it isn't
+actually. The trick is nl80211_create_monitor_interface may change that
+variable value and the second evaluation may give a different result.
+
+This definitely isn't a very clear code, but that change caused a
+regression for drivers that:
+1) Don't report NL80211_ATTR_DEVICE_AP_SME
+2) Don't support monitor mode
+3) Don't support subscribing for PROBE_REQ and/or ACTION frames
+like brcmfmac. With such drivers hostapd doesn't start anymore.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ src/drivers/driver_nl80211.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4434,7 +4434,8 @@ static int nl80211_setup_ap(struct i802_
+ 				   "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
+ 
+ 	if (!drv->device_ap_sme && drv->use_monitor &&
+-	    nl80211_create_monitor_interface(drv))
++	    nl80211_create_monitor_interface(drv) &&
++	    !drv->device_ap_sme)
+ 		return -1;
+ 
+ 	if (drv->device_ap_sme &&
diff --git a/package/network/services/hostapd/patches/200-multicall.patch b/package/network/services/hostapd/patches/200-multicall.patch
new file mode 100644
index 0000000000..aba9dafc5f
--- /dev/null
+++ b/package/network/services/hostapd/patches/200-multicall.patch
@@ -0,0 +1,360 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -28,6 +28,7 @@ CFLAGS += -I$(abspath ../src/utils)
+ export BINDIR ?= /usr/local/bin/
+ 
+ -include .config
++-include $(if $(MULTICALL), ../wpa_supplicant/.config)
+ 
+ ifndef CONFIG_NO_GITVER
+ # Add VERSION_STR postfix for builds from a git repository
+@@ -193,7 +194,8 @@ endif
+ 
+ ifdef CONFIG_NO_VLAN
+ CFLAGS += -DCONFIG_NO_VLAN
+-else
++endif
++ifneq ($(findstring CONFIG_NO_VLAN,$(CFLAGS)), CONFIG_NO_VLAN)
+ OBJS += ../src/ap/vlan_init.o
+ OBJS += ../src/ap/vlan_ifconfig.o
+ OBJS += ../src/ap/vlan.o
+@@ -318,10 +320,14 @@ CFLAGS += -DCONFIG_MBO
+ OBJS += ../src/ap/mbo_ap.o
+ endif
+ 
++ifndef MULTICALL
++CFLAGS += -DNO_SUPPLICANT
++endif
++
+ include ../src/drivers/drivers.mak
+-OBJS += $(DRV_AP_OBJS)
+-CFLAGS += $(DRV_AP_CFLAGS)
+-LDFLAGS += $(DRV_AP_LDFLAGS)
++OBJS += $(sort $(DRV_AP_OBJS) $(if $(MULTICALL),$(DRV_WPA_OBJS)))
++CFLAGS += $(DRV_AP_CFLAGS) $(if $(MULTICALL),$(DRV_WPA_CFLAGS))
++LDFLAGS += $(DRV_AP_LDFLAGS) $(if $(MULTICALL),$(DRV_WPA_LDFLAGS))
+ LIBS += $(DRV_AP_LIBS)
+ 
+ ifdef CONFIG_L2_PACKET
+@@ -1054,6 +1060,12 @@ install: $(addprefix $(DESTDIR)$(BINDIR)
+ 
+ BCHECK=../src/drivers/build.hostapd
+ 
++hostapd_multi.a: $(BCHECK) $(OBJS)
++	$(Q)$(CC) -c -o hostapd_multi.o -Dmain=hostapd_main $(CFLAGS) main.c
++	@$(E) "  CC " $<
++	@rm -f $@
++	@$(AR) cr $@ hostapd_multi.o $(OBJS)
++
+ hostapd: $(BCHECK) $(OBJS)
+ 	$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
+ 	@$(E) "  LD " $@
+@@ -1095,6 +1107,12 @@ HOBJS += ../src/crypto/aes-internal.o
+ HOBJS += ../src/crypto/aes-internal-enc.o
+ endif
+ 
++dump_cflags:
++	@printf "%s " "$(CFLAGS)"
++
++dump_ldflags:
++	@printf "%s " "$(LDFLAGS) $(LIBS) $(EXTRALIBS)"
++
+ nt_password_hash: $(NOBJS)
+ 	$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
+ 	@$(E) "  LD " $@
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -27,6 +27,7 @@ CFLAGS += -I$(abspath ../src)
+ CFLAGS += -I$(abspath ../src/utils)
+ 
+ -include .config
++-include $(if $(MULTICALL),../hostapd/.config)
+ 
+ ifndef CONFIG_NO_GITVER
+ # Add VERSION_STR postfix for builds from a git repository
+@@ -313,7 +314,9 @@ endif
+ ifdef CONFIG_IBSS_RSN
+ NEED_RSN_AUTHENTICATOR=y
+ CFLAGS += -DCONFIG_IBSS_RSN
++ifndef MULTICALL
+ CFLAGS += -DCONFIG_NO_VLAN
++endif
+ OBJS += ibss_rsn.o
+ endif
+ 
+@@ -804,6 +807,10 @@ ifdef CONFIG_DYNAMIC_EAP_METHODS
+ CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+ LIBS += -ldl -rdynamic
+ endif
++else
++  ifdef MULTICALL
++    OBJS += ../src/eap_common/eap_common.o
++  endif
+ endif
+ 
+ ifdef CONFIG_MACSEC
+@@ -824,9 +831,11 @@ NEED_EAP_COMMON=y
+ NEED_RSN_AUTHENTICATOR=y
+ CFLAGS += -DCONFIG_AP
+ OBJS += ap.o
++ifndef MULTICALL
+ CFLAGS += -DCONFIG_NO_RADIUS
+ CFLAGS += -DCONFIG_NO_ACCOUNTING
+ CFLAGS += -DCONFIG_NO_VLAN
++endif
+ OBJS += ../src/ap/hostapd.o
+ OBJS += ../src/ap/wpa_auth_glue.o
+ OBJS += ../src/ap/utils.o
+@@ -899,10 +908,18 @@ endif
+ ifdef CONFIG_HS20
+ OBJS += ../src/ap/hs20.o
+ endif
++else
++  ifdef MULTICALL
++    OBJS += ../src/eap_server/eap_server.o
++    OBJS += ../src/eap_server/eap_server_identity.o
++    OBJS += ../src/eap_server/eap_server_methods.o
++  endif
+ endif
+ 
+ ifdef NEED_RSN_AUTHENTICATOR
++ifndef MULTICALL
+ CFLAGS += -DCONFIG_NO_RADIUS
++endif
+ NEED_AES_WRAP=y
+ OBJS += ../src/ap/wpa_auth.o
+ OBJS += ../src/ap/wpa_auth_ie.o
+@@ -1685,6 +1702,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv)
+ 
+ $(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
+ 
++wpa_supplicant_multi.a: .config $(BCHECK) $(OBJS) $(EXTRA_progs)
++	$(Q)$(CC) -c -o wpa_supplicant_multi.o -Dmain=wpa_supplicant_main $(CFLAGS) main.c
++	@$(E) "  CC " $<
++	@rm -f $@
++	@$(AR) cr $@ wpa_supplicant_multi.o $(OBJS)
++
+ wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
+ 	$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+ 	@$(E) "  LD " $@
+@@ -1787,6 +1810,12 @@ endif
+ 		-e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
+ 	@$(E) "  sed" $<
+ 
++dump_cflags:
++	@printf "%s " "$(CFLAGS)"
++
++dump_ldflags:
++	@printf "%s " "$(LDFLAGS) $(LIBS) $(EXTRALIBS)"
++
+ wpa_supplicant.exe: wpa_supplicant
+ 	mv -f $< $@
+ wpa_cli.exe: wpa_cli
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -4870,8 +4870,8 @@ union wpa_event_data {
+  * Driver wrapper code should call this function whenever an event is received
+  * from the driver.
+  */
+-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+-			  union wpa_event_data *data);
++extern void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event,
++				    union wpa_event_data *data);
+ 
+ /**
+  * wpa_supplicant_event_global - Report a driver event for wpa_supplicant
+@@ -4883,7 +4883,7 @@ void wpa_supplicant_event(void *ctx, enu
+  * Same as wpa_supplicant_event(), but we search for the interface in
+  * wpa_global.
+  */
+-void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
++extern void (*wpa_supplicant_event_global)(void *ctx, enum wpa_event_type event,
+ 				 union wpa_event_data *data);
+ 
+ /*
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -1164,8 +1164,8 @@ static void hostapd_event_dfs_cac_starte
+ #endif /* NEED_AP_MLME */
+ 
+ 
+-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+-			  union wpa_event_data *data)
++void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
++		       union wpa_event_data *data)
+ {
+ 	struct hostapd_data *hapd = ctx;
+ #ifndef CONFIG_NO_STDOUT_DEBUG
+@@ -1374,7 +1374,7 @@ void wpa_supplicant_event(void *ctx, enu
+ }
+ 
+ 
+-void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
++void hostapd_wpa_event_global(void *ctx, enum wpa_event_type event,
+ 				 union wpa_event_data *data)
+ {
+ 	struct hapd_interfaces *interfaces = ctx;
+--- a/wpa_supplicant/wpa_priv.c
++++ b/wpa_supplicant/wpa_priv.c
+@@ -940,8 +940,8 @@ static void wpa_priv_send_ft_response(st
+ }
+ 
+ 
+-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+-			  union wpa_event_data *data)
++static void supplicant_event(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data)
+ {
+ 	struct wpa_priv_interface *iface = ctx;
+ 
+@@ -1010,7 +1010,7 @@ void wpa_supplicant_event(void *ctx, enu
+ }
+ 
+ 
+-void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
++void supplicant_event_global(void *ctx, enum wpa_event_type event,
+ 				 union wpa_event_data *data)
+ {
+ 	struct wpa_priv_global *global = ctx;
+@@ -1122,6 +1122,8 @@ int main(int argc, char *argv[])
+ 	if (os_program_init())
+ 		return -1;
+ 
++	wpa_supplicant_event = supplicant_event;
++	wpa_supplicant_event_global = supplicant_event_global;
+ 	wpa_priv_fd_workaround();
+ 
+ 	os_memset(&global, 0, sizeof(global));
+--- a/wpa_supplicant/events.c
++++ b/wpa_supplicant/events.c
+@@ -3398,8 +3398,8 @@ static void wpa_supplicant_event_assoc_a
+ }
+ 
+ 
+-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+-			  union wpa_event_data *data)
++void supplicant_event(void *ctx, enum wpa_event_type event,
++		      union wpa_event_data *data)
+ {
+ 	struct wpa_supplicant *wpa_s = ctx;
+ 	int resched;
+@@ -4074,7 +4074,7 @@ void wpa_supplicant_event(void *ctx, enu
+ #endif /* CONFIG_AP */
+ 		break;
+ 	case EVENT_ACS_CHANNEL_SELECTED:
+-#ifdef CONFIG_ACS
++#if defined(CONFIG_ACS) && defined(CONFIG_AP)
+ 		if (!wpa_s->ap_iface)
+ 			break;
+ 		hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+@@ -4096,7 +4096,7 @@ void wpa_supplicant_event(void *ctx, enu
+ }
+ 
+ 
+-void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
++void supplicant_event_global(void *ctx, enum wpa_event_type event,
+ 				 union wpa_event_data *data)
+ {
+ 	struct wpa_supplicant *wpa_s;
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -5094,7 +5094,6 @@ struct wpa_interface * wpa_supplicant_ma
+ 	return NULL;
+ }
+ 
+-
+ /**
+  * wpa_supplicant_match_existing - Match existing interfaces
+  * @global: Pointer to global data from wpa_supplicant_init()
+@@ -5131,6 +5130,11 @@ static int wpa_supplicant_match_existing
+ 
+ #endif /* CONFIG_MATCH_IFACE */
+ 
++extern void supplicant_event(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
++
++extern void supplicant_event_global(void *ctx, enum wpa_event_type event,
++ 				 union wpa_event_data *data);
+ 
+ /**
+  * wpa_supplicant_add_iface - Add a new network interface
+@@ -5386,6 +5390,8 @@ struct wpa_global * wpa_supplicant_init(
+ #ifndef CONFIG_NO_WPA_MSG
+ 	wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
+ #endif /* CONFIG_NO_WPA_MSG */
++	wpa_supplicant_event = supplicant_event;
++	wpa_supplicant_event_global = supplicant_event_global;
+ 
+ 	if (params->wpa_debug_file_path)
+ 		wpa_debug_open_file(params->wpa_debug_file_path);
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -583,6 +583,11 @@ fail:
+ 	return -1;
+ }
+ 
++void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
++                       union wpa_event_data *data);
++
++void hostapd_wpa_event_global(void *ctx, enum wpa_event_type event,
++ 				 union wpa_event_data *data);
+ 
+ #ifdef CONFIG_WPS
+ static int gen_uuid(const char *txt_addr)
+@@ -660,6 +665,8 @@ int main(int argc, char *argv[])
+ 	interfaces.global_ctrl_sock = -1;
+ 	dl_list_init(&interfaces.global_ctrl_dst);
+ 
++	wpa_supplicant_event = hostapd_wpa_event;
++	wpa_supplicant_event_global = hostapd_wpa_event_global;
+ 	for (;;) {
+ 		c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
+ 		if (c < 0)
+--- a/src/drivers/drivers.c
++++ b/src/drivers/drivers.c
+@@ -10,6 +10,10 @@
+ #include "utils/common.h"
+ #include "driver.h"
+ 
++void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
++void (*wpa_supplicant_event_global)(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
+ 
+ const struct wpa_driver_ops *const wpa_drivers[] =
+ {
+--- a/wpa_supplicant/eapol_test.c
++++ b/wpa_supplicant/eapol_test.c
+@@ -29,7 +29,12 @@
+ #include "ctrl_iface.h"
+ #include "pcsc_funcs.h"
+ #include "wpas_glue.h"
++#include "drivers/driver.h"
+ 
++void (*wpa_supplicant_event)(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
++void (*wpa_supplicant_event_global)(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
+ 
+ const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
+ 
+@@ -1295,6 +1300,10 @@ static void usage(void)
+ 	       "option several times.\n");
+ }
+ 
++extern void supplicant_event(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
++extern void supplicant_event_global(void *ctx, enum wpa_event_type event,
++			     union wpa_event_data *data);
+ 
+ int main(int argc, char *argv[])
+ {
+@@ -1315,6 +1324,8 @@ int main(int argc, char *argv[])
+ 	if (os_program_init())
+ 		return -1;
+ 
++	wpa_supplicant_event = supplicant_event;
++	wpa_supplicant_event_global = supplicant_event_global;
+ 	hostapd_logger_register_cb(hostapd_logger_cb);
+ 
+ 	os_memset(&eapol_test, 0, sizeof(eapol_test));
diff --git a/package/network/services/hostapd/patches/300-noscan.patch b/package/network/services/hostapd/patches/300-noscan.patch
new file mode 100644
index 0000000000..394769e370
--- /dev/null
+++ b/package/network/services/hostapd/patches/300-noscan.patch
@@ -0,0 +1,58 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2863,6 +2863,10 @@ static int hostapd_config_fill(struct ho
+ 		}
+ #endif /* CONFIG_IEEE80211W */
+ #ifdef CONFIG_IEEE80211N
++	} else if (os_strcmp(buf, "noscan") == 0) {
++		conf->noscan = atoi(pos);
++	} else if (os_strcmp(buf, "ht_coex") == 0) {
++		conf->no_ht_coex = !atoi(pos);
+ 	} else if (os_strcmp(buf, "ieee80211n") == 0) {
+ 		conf->ieee80211n = atoi(pos);
+ 	} else if (os_strcmp(buf, "ht_capab") == 0) {
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -664,6 +664,8 @@ struct hostapd_config {
+ 
+ 	int ht_op_mode_fixed;
+ 	u16 ht_capab;
++	int noscan;
++	int no_ht_coex;
+ 	int ieee80211n;
+ 	int secondary_channel;
+ 	int no_pri_sec_switch;
+--- a/src/ap/hw_features.c
++++ b/src/ap/hw_features.c
+@@ -474,7 +474,8 @@ static int ieee80211n_check_40mhz(struct
+ 	int ret;
+ 
+ 	/* Check that HT40 is used and PRI / SEC switch is allowed */
+-	if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch)
++	if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch ||
++		iface->conf->noscan)
+ 		return 0;
+ 
+ 	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
+--- a/src/ap/ieee802_11_ht.c
++++ b/src/ap/ieee802_11_ht.c
+@@ -244,6 +244,9 @@ void hostapd_2040_coex_action(struct hos
+ 	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ 		return;
+ 
++	if (iface->conf->noscan || iface->conf->no_ht_coex)
++		return;
++
+ 	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
+ 		return;
+ 
+@@ -368,6 +371,9 @@ void ht40_intolerant_add(struct hostapd_
+ 	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ 		return;
+ 
++	if (iface->conf->noscan || iface->conf->no_ht_coex)
++		return;
++
+ 	wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR
+ 		   " in Association Request", MAC2STR(sta->addr));
+ 
diff --git a/package/network/services/hostapd/patches/310-rescan_immediately.patch b/package/network/services/hostapd/patches/310-rescan_immediately.patch
new file mode 100644
index 0000000000..684de0e922
--- /dev/null
+++ b/package/network/services/hostapd/patches/310-rescan_immediately.patch
@@ -0,0 +1,11 @@
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -3654,7 +3654,7 @@ wpa_supplicant_alloc(struct wpa_supplica
+ 	if (wpa_s == NULL)
+ 		return NULL;
+ 	wpa_s->scan_req = INITIAL_SCAN_REQ;
+-	wpa_s->scan_interval = 5;
++	wpa_s->scan_interval = 1;
+ 	wpa_s->new_connection = 1;
+ 	wpa_s->parent = parent ? parent : wpa_s;
+ 	wpa_s->p2pdev = wpa_s->parent;
diff --git a/package/network/services/hostapd/patches/320-optional_rfkill.patch b/package/network/services/hostapd/patches/320-optional_rfkill.patch
new file mode 100644
index 0000000000..cf2a2c108b
--- /dev/null
+++ b/package/network/services/hostapd/patches/320-optional_rfkill.patch
@@ -0,0 +1,61 @@
+--- a/src/drivers/drivers.mak
++++ b/src/drivers/drivers.mak
+@@ -36,7 +36,6 @@ NEED_SME=y
+ NEED_AP_MLME=y
+ NEED_NETLINK=y
+ NEED_LINUX_IOCTL=y
+-NEED_RFKILL=y
+ NEED_RADIOTAP=y
+ 
+ ifdef CONFIG_LIBNL32
+@@ -123,7 +122,6 @@ DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+ CONFIG_WIRELESS_EXTENSION=y
+ NEED_NETLINK=y
+ NEED_LINUX_IOCTL=y
+-NEED_RFKILL=y
+ endif
+ 
+ ifdef CONFIG_DRIVER_NDIS
+@@ -149,7 +147,6 @@ endif
+ ifdef CONFIG_WIRELESS_EXTENSION
+ DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+ DRV_WPA_OBJS += ../src/drivers/driver_wext.o
+-NEED_RFKILL=y
+ endif
+ 
+ ifdef NEED_NETLINK
+@@ -162,6 +159,7 @@ endif
+ 
+ ifdef NEED_RFKILL
+ DRV_OBJS += ../src/drivers/rfkill.o
++DRV_WPA_CFLAGS += -DCONFIG_RFKILL
+ endif
+ 
+ ifdef NEED_RADIOTAP
+--- a/src/drivers/rfkill.h
++++ b/src/drivers/rfkill.h
+@@ -18,8 +18,24 @@ struct rfkill_config {
+ 	void (*unblocked_cb)(void *ctx);
+ };
+ 
++#ifdef CONFIG_RFKILL
+ struct rfkill_data * rfkill_init(struct rfkill_config *cfg);
+ void rfkill_deinit(struct rfkill_data *rfkill);
+ int rfkill_is_blocked(struct rfkill_data *rfkill);
++#else
++static inline struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
++{
++	return (void *) 1;
++}
++
++static inline void rfkill_deinit(struct rfkill_data *rfkill)
++{
++}
++
++static inline int rfkill_is_blocked(struct rfkill_data *rfkill)
++{
++	return 0;
++}
++#endif
+ 
+ #endif /* RFKILL_H */
diff --git a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch
new file mode 100644
index 0000000000..e955479bf8
--- /dev/null
+++ b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch
@@ -0,0 +1,11 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -3864,7 +3864,7 @@ static int nl80211_set_channel(struct i8
+ 		   freq->freq, freq->ht_enabled, freq->vht_enabled,
+ 		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
+ 
+-	msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
++	msg = nl80211_bss_msg(bss, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ 			      NL80211_CMD_SET_WIPHY);
+ 	if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
+ 		nlmsg_free(msg);
diff --git a/package/network/services/hostapd/patches/340-reload_freq_change.patch b/package/network/services/hostapd/patches/340-reload_freq_change.patch
new file mode 100644
index 0000000000..086ade9ced
--- /dev/null
+++ b/package/network/services/hostapd/patches/340-reload_freq_change.patch
@@ -0,0 +1,44 @@
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -80,6 +80,16 @@ static void hostapd_reload_bss(struct ho
+ #endif /* CONFIG_NO_RADIUS */
+ 
+ 	ssid = &hapd->conf->ssid;
++
++	hostapd_set_freq(hapd, hapd->iconf->hw_mode, hapd->iface->freq,
++			 hapd->iconf->channel,
++			 hapd->iconf->ieee80211n,
++			 hapd->iconf->ieee80211ac,
++			 hapd->iconf->secondary_channel,
++			 hapd->iconf->vht_oper_chwidth,
++			 hapd->iconf->vht_oper_centr_freq_seg0_idx,
++			 hapd->iconf->vht_oper_centr_freq_seg1_idx);
++
+ 	if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
+ 	    ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
+ 		/*
+@@ -179,21 +189,12 @@ int hostapd_reload_config(struct hostapd
+ 	oldconf = hapd->iconf;
+ 	iface->conf = newconf;
+ 
++	if (iface->conf->channel)
++		iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
++
+ 	for (j = 0; j < iface->num_bss; j++) {
+ 		hapd = iface->bss[j];
+ 		hapd->iconf = newconf;
+-		hapd->iconf->channel = oldconf->channel;
+-		hapd->iconf->acs = oldconf->acs;
+-		hapd->iconf->secondary_channel = oldconf->secondary_channel;
+-		hapd->iconf->ieee80211n = oldconf->ieee80211n;
+-		hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
+-		hapd->iconf->ht_capab = oldconf->ht_capab;
+-		hapd->iconf->vht_capab = oldconf->vht_capab;
+-		hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
+-		hapd->iconf->vht_oper_centr_freq_seg0_idx =
+-			oldconf->vht_oper_centr_freq_seg0_idx;
+-		hapd->iconf->vht_oper_centr_freq_seg1_idx =
+-			oldconf->vht_oper_centr_freq_seg1_idx;
+ 		hapd->conf = newconf->bss[j];
+ 		hostapd_reload_bss(hapd);
+ 	}
diff --git a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch
new file mode 100644
index 0000000000..3a0820313e
--- /dev/null
+++ b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch
@@ -0,0 +1,72 @@
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -2398,13 +2398,18 @@ wpa_driver_nl80211_finish_drv_init(struc
+ }
+ 
+ 
+-static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
++static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
+ {
++	struct wpa_driver_nl80211_data *drv = bss->drv;
+ 	struct nl_msg *msg;
+ 
++	if (!bss->beacon_set)
++		return 0;
++
++	bss->beacon_set = 0;
+ 	wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
+-		   drv->ifindex);
+-	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
++		   bss->ifindex);
++	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_BEACON);
+ 	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ }
+ 
+@@ -2456,7 +2461,7 @@ static void wpa_driver_nl80211_deinit(st
+ 	nl80211_remove_monitor_interface(drv);
+ 
+ 	if (is_ap_interface(drv->nlmode))
+-		wpa_driver_nl80211_del_beacon(drv);
++		wpa_driver_nl80211_del_beacon(bss);
+ 
+ 	if (drv->eapol_sock >= 0) {
+ 		eloop_unregister_read_sock(drv->eapol_sock);
+@@ -4463,8 +4468,7 @@ static void nl80211_teardown_ap(struct i
+ 		nl80211_remove_monitor_interface(drv);
+ 	else
+ 		nl80211_mgmt_unsubscribe(bss, "AP teardown");
+-
+-	bss->beacon_set = 0;
++	wpa_driver_nl80211_del_beacon(bss);
+ }
+ 
+ 
+@@ -6473,8 +6477,6 @@ static int wpa_driver_nl80211_if_remove(
+ 	} else {
+ 		wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
+ 		nl80211_teardown_ap(bss);
+-		if (!bss->added_if && !drv->first_bss->next)
+-			wpa_driver_nl80211_del_beacon(drv);
+ 		nl80211_destroy_bss(bss);
+ 		if (!bss->added_if)
+ 			i802_set_iface_flags(bss, 0);
+@@ -6836,8 +6838,7 @@ static int wpa_driver_nl80211_deinit_ap(
+ 	struct wpa_driver_nl80211_data *drv = bss->drv;
+ 	if (!is_ap_interface(drv->nlmode))
+ 		return -1;
+-	wpa_driver_nl80211_del_beacon(drv);
+-	bss->beacon_set = 0;
++	wpa_driver_nl80211_del_beacon(bss);
+ 
+ 	/*
+ 	 * If the P2P GO interface was dynamically added, then it is
+@@ -6856,8 +6857,7 @@ static int wpa_driver_nl80211_stop_ap(vo
+ 	struct wpa_driver_nl80211_data *drv = bss->drv;
+ 	if (!is_ap_interface(drv->nlmode))
+ 		return -1;
+-	wpa_driver_nl80211_del_beacon(drv);
+-	bss->beacon_set = 0;
++	wpa_driver_nl80211_del_beacon(bss);
+ 	return 0;
+ }
+ 
diff --git a/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch b/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch
new file mode 100644
index 0000000000..8c46001c01
--- /dev/null
+++ b/package/network/services/hostapd/patches/360-ctrl_iface_reload.patch
@@ -0,0 +1,106 @@
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -55,6 +55,7 @@
+ #include "fst/fst_ctrl_iface.h"
+ #include "config_file.h"
+ #include "ctrl_iface.h"
++#include "config_file.h"
+ 
+ 
+ #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
+@@ -73,6 +74,7 @@ static void hostapd_ctrl_iface_send(stru
+ 				    enum wpa_msg_type type,
+ 				    const char *buf, size_t len);
+ 
++static char *reload_opts = NULL;
+ 
+ static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
+ 				     struct sockaddr_storage *from,
+@@ -124,6 +126,61 @@ static int hostapd_ctrl_iface_new_sta(st
+ 	return 0;
+ }
+ 
++static char *get_option(char *opt, char *str)
++{
++	int len = strlen(str);
++
++	if (!strncmp(opt, str, len))
++		return opt + len;
++	else
++		return NULL;
++}
++
++static struct hostapd_config *hostapd_ctrl_iface_config_read(const char *fname)
++{
++	struct hostapd_config *conf;
++	char *opt, *val;
++
++	conf = hostapd_config_read(fname);
++	if (!conf)
++		return NULL;
++
++	for (opt = strtok(reload_opts, " ");
++	     opt;
++		 opt = strtok(NULL, " ")) {
++
++		if ((val = get_option(opt, "channel=")))
++			conf->channel = atoi(val);
++		else if ((val = get_option(opt, "ht_capab=")))
++			conf->ht_capab = atoi(val);
++		else if ((val = get_option(opt, "ht_capab_mask=")))
++			conf->ht_capab &= atoi(val);
++		else if ((val = get_option(opt, "sec_chan=")))
++			conf->secondary_channel = atoi(val);
++		else if ((val = get_option(opt, "hw_mode=")))
++			conf->hw_mode = atoi(val);
++		else if ((val = get_option(opt, "ieee80211n=")))
++			conf->ieee80211n = atoi(val);
++		else
++			break;
++	}
++
++	return conf;
++}
++
++static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt)
++{
++	struct hostapd_config * (*config_read_cb)(const char *config_fname);
++	struct hostapd_iface *iface = hapd->iface;
++
++	config_read_cb = iface->interfaces->config_read_cb;
++	iface->interfaces->config_read_cb = hostapd_ctrl_iface_config_read;
++	reload_opts = txt;
++
++	hostapd_reload_config(iface);
++
++	iface->interfaces->config_read_cb = config_read_cb;
++}
+ 
+ #ifdef CONFIG_IEEE80211W
+ #ifdef NEED_AP_MLME
+@@ -2505,6 +2562,8 @@ static int hostapd_ctrl_iface_receive_pr
+ 	} else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
+ 		reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
+ 						      reply_size);
++	} else if (os_strncmp(buf, "UPDATE ", 7) == 0) {
++		hostapd_ctrl_iface_update(hapd, buf + 7);
+ 	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+ 		ieee802_1x_erp_flush(hapd);
+ #ifdef RADIUS_SERVER
+--- a/src/ap/ctrl_iface_ap.c
++++ b/src/ap/ctrl_iface_ap.c
+@@ -601,7 +601,13 @@ int hostapd_parse_csa_settings(const cha
+ 
+ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
+ {
+-	return hostapd_drv_stop_ap(hapd);
++	struct hostapd_iface *iface = hapd->iface;
++	int i;
++
++	for (i = 0; i < iface->num_bss; i++)
++		hostapd_drv_stop_ap(iface->bss[i]);
++
++	return 0;
+ }
+ 
+ 
diff --git a/package/network/services/hostapd/patches/370-ap_sta_support.patch b/package/network/services/hostapd/patches/370-ap_sta_support.patch
new file mode 100644
index 0000000000..c599311ba5
--- /dev/null
+++ b/package/network/services/hostapd/patches/370-ap_sta_support.patch
@@ -0,0 +1,237 @@
+--- a/wpa_supplicant/wpa_supplicant_i.h
++++ b/wpa_supplicant/wpa_supplicant_i.h
+@@ -100,6 +100,11 @@ struct wpa_interface {
+ 	const char *ifname;
+ 
+ 	/**
++	 * hostapd_ctrl - path to hostapd control socket for notification
++	 */
++	const char *hostapd_ctrl;
++
++	/**
+ 	 * bridge_ifname - Optional bridge interface name
+ 	 *
+ 	 * If the driver interface (ifname) is included in a Linux bridge
+@@ -484,6 +489,8 @@ struct wpa_supplicant {
+ #endif /* CONFIG_CTRL_IFACE_BINDER */
+ 	char bridge_ifname[16];
+ 
++	struct wpa_ctrl *hostapd;
++
+ 	char *confname;
+ 	char *confanother;
+ 
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -26,6 +26,10 @@ CFLAGS += $(EXTRA_CFLAGS)
+ CFLAGS += -I$(abspath ../src)
+ CFLAGS += -I$(abspath ../src/utils)
+ 
++ifdef MULTICALL
++CFLAGS += -DMULTICALL
++endif
++
+ -include .config
+ -include $(if $(MULTICALL),../hostapd/.config)
+ 
+@@ -114,6 +118,8 @@ OBJS_c += ../src/utils/common.o
+ OBJS_c += ../src/common/cli.o
+ OBJS += wmm_ac.o
+ 
++OBJS += ../src/common/wpa_ctrl.o
++
+ ifndef CONFIG_OS
+ ifdef CONFIG_NATIVE_WINDOWS
+ CONFIG_OS=win32
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -112,6 +112,55 @@ const char *const wpa_supplicant_full_li
+ "\n";
+ #endif /* CONFIG_NO_STDOUT_DEBUG */
+ 
++static int hostapd_stop(struct wpa_supplicant *wpa_s)
++{
++	const char *cmd = "STOP_AP";
++	char buf[256];
++	size_t len = sizeof(buf);
++
++	if (wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL) < 0) {
++		wpa_printf(MSG_ERROR, "\nFailed to stop hostapd AP interfaces\n");
++		return -1;
++	}
++	return 0;
++}
++
++static int hostapd_reload(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
++{
++	char *cmd = NULL;
++	char buf[256];
++	size_t len = sizeof(buf);
++	enum hostapd_hw_mode hw_mode;
++	u8 channel;
++	int sec_chan = 0;
++	int ret;
++
++	if (!bss)
++		return -1;
++
++	if (bss->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
++		int sec = bss->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
++		if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
++			sec_chan = 1;
++		else if (sec ==  HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
++			sec_chan = -1;
++	}
++
++	hw_mode = ieee80211_freq_to_chan(bss->freq, &channel);
++	if (asprintf(&cmd, "UPDATE channel=%d sec_chan=%d hw_mode=%d",
++		     channel, sec_chan, hw_mode) < 0)
++		return -1;
++
++	ret = wpa_ctrl_request(wpa_s->hostapd, cmd, os_strlen(cmd), buf, &len, NULL);
++	free(cmd);
++
++	if (ret < 0) {
++		wpa_printf(MSG_ERROR, "\nFailed to reload hostapd AP interfaces\n");
++		return -1;
++	}
++	return 0;
++}
++
+ /* Configure default/group WEP keys for static WEP */
+ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+ {
+@@ -812,8 +861,12 @@ void wpa_supplicant_set_state(struct wpa
+ 		wpas_p2p_completed(wpa_s);
+ 
+ 		sme_sched_obss_scan(wpa_s, 1);
++		if (wpa_s->hostapd)
++			hostapd_reload(wpa_s, wpa_s->current_bss);
+ 	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
+ 		   state == WPA_ASSOCIATED) {
++		if (wpa_s->hostapd)
++			hostapd_stop(wpa_s);
+ 		wpa_s->new_connection = 1;
+ 		wpa_drv_set_operstate(wpa_s, 0);
+ #ifndef IEEE8021X_EAPOL
+@@ -4748,6 +4801,20 @@ static int wpa_supplicant_init_iface(str
+ 			   sizeof(wpa_s->bridge_ifname));
+ 	}
+ 
++	if (iface->hostapd_ctrl) {
++		char *cmd = "STOP_AP";
++		char buf[256];
++		int len = sizeof(buf);
++
++		wpa_s->hostapd = wpa_ctrl_open(iface->hostapd_ctrl);
++		if (!wpa_s->hostapd) {
++			wpa_printf(MSG_ERROR, "\nFailed to connect to hostapd\n");
++			return -1;
++		}
++		if (hostapd_stop(wpa_s) < 0)
++			return -1;
++	}
++
+ 	/* RSNA Supplicant Key Management - INITIALIZE */
+ 	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+ 	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+@@ -5041,6 +5108,11 @@ static void wpa_supplicant_deinit_iface(
+ 	if (terminate)
+ 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
+ 
++	if (wpa_s->hostapd) {
++		wpa_ctrl_close(wpa_s->hostapd);
++		wpa_s->hostapd = NULL;
++	}
++
+ 	if (wpa_s->ctrl_iface) {
+ 		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ 		wpa_s->ctrl_iface = NULL;
+--- a/wpa_supplicant/bss.c
++++ b/wpa_supplicant/bss.c
+@@ -11,6 +11,7 @@
+ #include "utils/common.h"
+ #include "utils/eloop.h"
+ #include "common/ieee802_11_defs.h"
++#include "common/ieee802_11_common.h"
+ #include "drivers/driver.h"
+ #include "eap_peer/eap.h"
+ #include "wpa_supplicant_i.h"
+@@ -288,6 +289,10 @@ static void calculate_update_time(const
+ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+ 			     struct os_reltime *fetch_time)
+ {
++	struct ieee80211_ht_capabilities *capab;
++	struct ieee80211_ht_operation *oper;
++	struct ieee802_11_elems elems;
++
+ 	dst->flags = src->flags;
+ 	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
+ 	dst->freq = src->freq;
+@@ -300,6 +305,15 @@ static void wpa_bss_copy_res(struct wpa_
+ 	dst->est_throughput = src->est_throughput;
+ 	dst->snr = src->snr;
+ 
++	memset(&elems, 0, sizeof(elems));
++	ieee802_11_parse_elems((u8 *) (src + 1), src->ie_len, &elems, 0);
++	capab = (struct ieee80211_ht_capabilities *) elems.ht_capabilities;
++	oper = (struct ieee80211_ht_operation *) elems.ht_operation;
++	if (capab)
++		dst->ht_capab = le_to_host16(capab->ht_capabilities_info);
++	if (oper)
++		dst->ht_param = oper->ht_param;
++
+ 	calculate_update_time(fetch_time, src->age, &dst->last_update);
+ }
+ 
+--- a/wpa_supplicant/main.c
++++ b/wpa_supplicant/main.c
+@@ -34,7 +34,7 @@ static void usage(void)
+ 	       "vW] [-P<pid file>] "
+ 	       "[-g<global ctrl>] \\\n"
+ 	       "        [-G<group>] \\\n"
+-	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
++	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-H<hostapd path>] "
+ 	       "[-p<driver_param>] \\\n"
+ 	       "        [-b<br_ifname>] [-e<entropy file>]"
+ #ifdef CONFIG_DEBUG_FILE
+@@ -74,6 +74,7 @@ static void usage(void)
+ 	       "  -g = global ctrl_interface\n"
+ 	       "  -G = global ctrl_interface group\n"
+ 	       "  -h = show this help text\n"
++	       "  -H = connect to a hostapd instance to manage state changes\n"
+ 	       "  -i = interface name\n"
+ 	       "  -I = additional configuration file\n"
+ 	       "  -K = include keys (passwords, etc.) in debug output\n"
+@@ -201,7 +202,7 @@ int main(int argc, char *argv[])
+ 
+ 	for (;;) {
+ 		c = getopt(argc, argv,
+-			   "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
++			   "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuvW");
+ 		if (c < 0)
+ 			break;
+ 		switch (c) {
+@@ -248,6 +249,9 @@ int main(int argc, char *argv[])
+ 			usage();
+ 			exitcode = 0;
+ 			goto out;
++		case 'H':
++			iface->hostapd_ctrl = optarg;
++			break;
+ 		case 'i':
+ 			iface->ifname = optarg;
+ 			break;
+--- a/wpa_supplicant/bss.h
++++ b/wpa_supplicant/bss.h
+@@ -79,6 +79,10 @@ struct wpa_bss {
+ 	u8 ssid[SSID_MAX_LEN];
+ 	/** Length of SSID */
+ 	size_t ssid_len;
++	/** HT capabilities */
++	u16 ht_capab;
++	/* Five octets of HT Operation Information */
++	u8 ht_param;
+ 	/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
+ 	int freq;
+ 	/** Beacon interval in TUs (host byte order) */
diff --git a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch
new file mode 100644
index 0000000000..c6e7cd60fb
--- /dev/null
+++ b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch
@@ -0,0 +1,178 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -215,6 +215,9 @@ endif
+ ifdef CONFIG_NO_CTRL_IFACE
+ CFLAGS += -DCONFIG_NO_CTRL_IFACE
+ else
++ifdef CONFIG_CTRL_IFACE_MIB
++CFLAGS += -DCONFIG_CTRL_IFACE_MIB
++endif
+ ifeq ($(CONFIG_CTRL_IFACE), udp)
+ CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+ else
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -2364,6 +2364,7 @@ static int hostapd_ctrl_iface_receive_pr
+ 						      reply_size);
+ 	} else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
+ 		reply_len = hostapd_drv_status(hapd, reply, reply_size);
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 	} else if (os_strcmp(buf, "MIB") == 0) {
+ 		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
+ 		if (reply_len >= 0) {
+@@ -2405,6 +2406,7 @@ static int hostapd_ctrl_iface_receive_pr
+ 	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+ 		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
+ 							reply_size);
++#endif
+ 	} else if (os_strcmp(buf, "ATTACH") == 0) {
+ 		if (hostapd_ctrl_iface_attach(hapd, from, fromlen))
+ 			reply_len = -1;
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -875,6 +875,9 @@ ifdef CONFIG_MBO
+ OBJS += ../src/ap/mbo_ap.o
+ endif
+ ifdef CONFIG_CTRL_IFACE
++ifdef CONFIG_CTRL_IFACE_MIB
++CFLAGS += -DCONFIG_CTRL_IFACE_MIB
++endif
+ OBJS += ../src/ap/ctrl_iface_ap.o
+ endif
+ 
+--- a/wpa_supplicant/ctrl_iface.c
++++ b/wpa_supplicant/ctrl_iface.c
+@@ -1895,7 +1895,7 @@ static int wpa_supplicant_ctrl_iface_sta
+ 			pos += ret;
+ 		}
+ 
+-#ifdef CONFIG_AP
++#if defined(CONFIG_AP) && defined(CONFIG_CTRL_IFACE_MIB)
+ 		if (wpa_s->ap_iface) {
+ 			pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
+ 							    end - pos,
+@@ -8684,6 +8684,7 @@ char * wpa_supplicant_ctrl_iface_process
+ 			reply_len = -1;
+ 	} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+ 		wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 	} else if (os_strcmp(buf, "MIB") == 0) {
+ 		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
+ 		if (reply_len >= 0) {
+@@ -8691,6 +8692,7 @@ char * wpa_supplicant_ctrl_iface_process
+ 						      reply + reply_len,
+ 						      reply_size - reply_len);
+ 		}
++#endif
+ 	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
+ 		reply_len = wpa_supplicant_ctrl_iface_status(
+ 			wpa_s, buf + 6, reply, reply_size);
+@@ -9161,6 +9163,7 @@ char * wpa_supplicant_ctrl_iface_process
+ 		reply_len = wpa_supplicant_ctrl_iface_bss(
+ 			wpa_s, buf + 4, reply, reply_size);
+ #ifdef CONFIG_AP
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
+ 		reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
+ 	} else if (os_strncmp(buf, "STA ", 4) == 0) {
+@@ -9169,12 +9172,15 @@ char * wpa_supplicant_ctrl_iface_process
+ 	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+ 		reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
+ 						   reply_size);
++#endif
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+ 		if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+ 			reply_len = -1;
+ 	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+ 		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
+ 			reply_len = -1;
++#endif
+ 	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+ 		if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+ 			reply_len = -1;
+--- a/src/ap/ctrl_iface_ap.c
++++ b/src/ap/ctrl_iface_ap.c
+@@ -24,6 +24,7 @@
+ #include "ap_drv_ops.h"
+ #include "mbo_ap.h"
+ 
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 
+ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
+ 				 struct sta_info *sta,
+@@ -249,6 +250,7 @@ int hostapd_ctrl_iface_sta_next(struct h
+ 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
+ }
+ 
++#endif
+ 
+ #ifdef CONFIG_P2P_MANAGER
+ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+--- a/src/ap/ieee802_1x.c
++++ b/src/ap/ieee802_1x.c
+@@ -2442,6 +2442,7 @@ static const char * bool_txt(Boolean val
+ 	return val ? "TRUE" : "FALSE";
+ }
+ 
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 
+ int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+ {
+@@ -2617,6 +2618,7 @@ int ieee802_1x_get_mib_sta(struct hostap
+ 	return len;
+ }
+ 
++#endif
+ 
+ #ifdef CONFIG_HS20
+ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
+--- a/src/ap/wpa_auth.c
++++ b/src/ap/wpa_auth.c
+@@ -3069,6 +3069,7 @@ static const char * wpa_bool_txt(int val
+ 	return val ? "TRUE" : "FALSE";
+ }
+ 
++#ifdef CONFIG_CTRL_IFACE_MIB
+ 
+ #define RSN_SUITE "%02x-%02x-%02x-%d"
+ #define RSN_SUITE_ARG(s) \
+@@ -3213,7 +3214,7 @@ int wpa_get_mib_sta(struct wpa_state_mac
+ 
+ 	return len;
+ }
+-
++#endif
+ 
+ void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
+ {
+--- a/src/rsn_supp/wpa.c
++++ b/src/rsn_supp/wpa.c
+@@ -2108,6 +2108,8 @@ static u32 wpa_key_mgmt_suite(struct wpa
+ }
+ 
+ 
++#ifdef CONFIG_CTRL_IFACE_MIB
++
+ #define RSN_SUITE "%02x-%02x-%02x-%d"
+ #define RSN_SUITE_ARG(s) \
+ ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
+@@ -2191,6 +2193,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, ch
+ 
+ 	return (int) len;
+ }
++#endif
+ #endif /* CONFIG_CTRL_IFACE */
+ 
+ 
+--- a/wpa_supplicant/ap.c
++++ b/wpa_supplicant/ap.c
+@@ -1119,7 +1119,7 @@ int wpas_ap_wps_nfc_report_handover(stru
+ #endif /* CONFIG_WPS */
+ 
+ 
+-#ifdef CONFIG_CTRL_IFACE
++#if defined(CONFIG_CTRL_IFACE) && defined(CONFIG_CTRL_IFACE_MIB)
+ 
+ int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
+ 			    char *buf, size_t buflen)
diff --git a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch
new file mode 100644
index 0000000000..33a17d0001
--- /dev/null
+++ b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch
@@ -0,0 +1,56 @@
+--- a/src/common/wpa_common.c
++++ b/src/common/wpa_common.c
+@@ -1246,6 +1246,31 @@ u32 wpa_akm_to_suite(int akm)
+ }
+ 
+ 
++static void wpa_fixup_wpa_ie_rsn(u8 *assoc_ie, const u8 *wpa_msg_ie,
++				 size_t rsn_ie_len)
++{
++	int pos, count;
++
++	pos = sizeof(struct rsn_ie_hdr) + RSN_SELECTOR_LEN;
++	if (rsn_ie_len < pos + 2)
++		return;
++
++	count = WPA_GET_LE16(wpa_msg_ie + pos);
++	pos += 2 + count * RSN_SELECTOR_LEN;
++	if (rsn_ie_len < pos + 2)
++		return;
++
++	count = WPA_GET_LE16(wpa_msg_ie + pos);
++	pos += 2 + count * RSN_SELECTOR_LEN;
++	if (rsn_ie_len < pos + 2)
++		return;
++
++	if (!assoc_ie[pos] && !assoc_ie[pos + 1] &&
++	    (wpa_msg_ie[pos] || wpa_msg_ie[pos + 1]))
++		memcpy(&assoc_ie[pos], &wpa_msg_ie[pos], 2);
++}
++
++
+ int wpa_compare_rsn_ie(int ft_initial_assoc,
+ 		       const u8 *ie1, size_t ie1len,
+ 		       const u8 *ie2, size_t ie2len)
+@@ -1253,8 +1278,19 @@ int wpa_compare_rsn_ie(int ft_initial_as
+ 	if (ie1 == NULL || ie2 == NULL)
+ 		return -1;
+ 
+-	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
+-		return 0; /* identical IEs */
++	if (ie1len == ie2len) {
++		u8 *ie_tmp;
++
++		if (os_memcmp(ie1, ie2, ie1len) == 0)
++			return 0; /* identical IEs */
++
++		ie_tmp = alloca(ie1len);
++		memcpy(ie_tmp, ie1, ie1len);
++		wpa_fixup_wpa_ie_rsn(ie_tmp, ie2, ie1len);
++
++		if (os_memcmp(ie_tmp, ie2, ie1len) == 0)
++			return 0; /* only mismatch in RSN capabilties */
++	}
+ 
+ #ifdef CONFIG_IEEE80211R
+ 	if (ft_initial_assoc) {
diff --git a/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch b/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch
new file mode 100644
index 0000000000..c10176371f
--- /dev/null
+++ b/package/network/services/hostapd/patches/400-wps_single_auth_enc_type.patch
@@ -0,0 +1,22 @@
+--- a/src/ap/wps_hostapd.c
++++ b/src/ap/wps_hostapd.c
+@@ -346,8 +346,7 @@ static int hapd_wps_reconfig_in_memory(s
+ 				bss->wpa_pairwise |= WPA_CIPHER_GCMP;
+ 			else
+ 				bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+-		}
+-		if (cred->encr_type & WPS_ENCR_TKIP)
++		} else if (cred->encr_type & WPS_ENCR_TKIP)
+ 			bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+ 		bss->rsn_pairwise = bss->wpa_pairwise;
+ 		bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+@@ -1067,8 +1066,7 @@ int hostapd_init_wps(struct hostapd_data
+ 		if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) {
+ 			wps->encr_types |= WPS_ENCR_AES;
+ 			wps->encr_types_rsn |= WPS_ENCR_AES;
+-		}
+-		if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
++		} else if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+ 			wps->encr_types |= WPS_ENCR_TKIP;
+ 			wps->encr_types_rsn |= WPS_ENCR_TKIP;
+ 		}
diff --git a/package/network/services/hostapd/patches/410-limit_debug_messages.patch b/package/network/services/hostapd/patches/410-limit_debug_messages.patch
new file mode 100644
index 0000000000..a48b6962ee
--- /dev/null
+++ b/package/network/services/hostapd/patches/410-limit_debug_messages.patch
@@ -0,0 +1,214 @@
+--- a/src/utils/wpa_debug.c
++++ b/src/utils/wpa_debug.c
+@@ -201,7 +201,7 @@ void wpa_debug_close_linux_tracing(void)
+  *
+  * Note: New line '\n' is added to the end of the text when printing to stdout.
+  */
+-void wpa_printf(int level, const char *fmt, ...)
++void _wpa_printf(int level, const char *fmt, ...)
+ {
+ 	va_list ap;
+ 
+@@ -248,8 +248,8 @@ void wpa_printf(int level, const char *f
+ }
+ 
+ 
+-static void _wpa_hexdump(int level, const char *title, const u8 *buf,
+-			 size_t len, int show)
++void _wpa_hexdump(int level, const char *title, const u8 *buf,
++		  size_t len, int show)
+ {
+ 	size_t i;
+ 
+@@ -375,20 +375,8 @@ static void _wpa_hexdump(int level, cons
+ #endif /* CONFIG_ANDROID_LOG */
+ }
+ 
+-void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
+-{
+-	_wpa_hexdump(level, title, buf, len, 1);
+-}
+-
+-
+-void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
+-{
+-	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+-}
+-
+-
+-static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
+-			       size_t len, int show)
++void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
++			size_t len, int show)
+ {
+ 	size_t i, llen;
+ 	const u8 *pos = buf;
+@@ -495,20 +483,6 @@ static void _wpa_hexdump_ascii(int level
+ }
+ 
+ 
+-void wpa_hexdump_ascii(int level, const char *title, const void *buf,
+-		       size_t len)
+-{
+-	_wpa_hexdump_ascii(level, title, buf, len, 1);
+-}
+-
+-
+-void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
+-			   size_t len)
+-{
+-	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
+-}
+-
+-
+ #ifdef CONFIG_DEBUG_FILE
+ static char *last_path = NULL;
+ #endif /* CONFIG_DEBUG_FILE */
+@@ -604,7 +578,7 @@ void wpa_msg_register_ifname_cb(wpa_msg_
+ }
+ 
+ 
+-void wpa_msg(void *ctx, int level, const char *fmt, ...)
++void _wpa_msg(void *ctx, int level, const char *fmt, ...)
+ {
+ 	va_list ap;
+ 	char *buf;
+@@ -642,7 +616,7 @@ void wpa_msg(void *ctx, int level, const
+ }
+ 
+ 
+-void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
++void _wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+ {
+ 	va_list ap;
+ 	char *buf;
+--- a/src/utils/wpa_debug.h
++++ b/src/utils/wpa_debug.h
+@@ -49,6 +49,17 @@ int wpa_debug_reopen_file(void);
+ void wpa_debug_close_file(void);
+ void wpa_debug_setup_stdout(void);
+ 
++/* internal */
++void _wpa_hexdump(int level, const char *title, const u8 *buf,
++		  size_t len, int show);
++void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
++			size_t len, int show);
++extern int wpa_debug_show_keys;
++
++#ifndef CONFIG_MSG_MIN_PRIORITY
++#define CONFIG_MSG_MIN_PRIORITY 0
++#endif
++
+ /**
+  * wpa_debug_printf_timestamp - Print timestamp for debug output
+  *
+@@ -69,9 +80,15 @@ void wpa_debug_print_timestamp(void);
+  *
+  * Note: New line '\n' is added to the end of the text when printing to stdout.
+  */
+-void wpa_printf(int level, const char *fmt, ...)
++void _wpa_printf(int level, const char *fmt, ...)
+ PRINTF_FORMAT(2, 3);
+ 
++#define wpa_printf(level, ...)						\
++	do {								\
++		if (level >= CONFIG_MSG_MIN_PRIORITY)			\
++			_wpa_printf(level, __VA_ARGS__);		\
++	} while(0)
++
+ /**
+  * wpa_hexdump - conditional hex dump
+  * @level: priority level (MSG_*) of the message
+@@ -83,7 +100,13 @@ PRINTF_FORMAT(2, 3);
+  * output may be directed to stdout, stderr, and/or syslog based on
+  * configuration. The contents of buf is printed out has hex dump.
+  */
+-void wpa_hexdump(int level, const char *title, const void *buf, size_t len);
++static inline void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
++{
++	if (level < CONFIG_MSG_MIN_PRIORITY)
++		return;
++
++	_wpa_hexdump(level, title, buf, len, 1);
++}
+ 
+ static inline void wpa_hexdump_buf(int level, const char *title,
+ 				   const struct wpabuf *buf)
+@@ -105,7 +128,13 @@ static inline void wpa_hexdump_buf(int l
+  * like wpa_hexdump(), but by default, does not include secret keys (passwords,
+  * etc.) in debug output.
+  */
+-void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len);
++static inline void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
++{
++	if (level < CONFIG_MSG_MIN_PRIORITY)
++		return;
++
++	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
++}
+ 
+ static inline void wpa_hexdump_buf_key(int level, const char *title,
+ 				       const struct wpabuf *buf)
+@@ -127,8 +156,14 @@ static inline void wpa_hexdump_buf_key(i
+  * the hex numbers and ASCII characters (for printable range) are shown. 16
+  * bytes per line will be shown.
+  */
+-void wpa_hexdump_ascii(int level, const char *title, const void *buf,
+-		       size_t len);
++static inline void wpa_hexdump_ascii(int level, const char *title,
++				     const u8 *buf, size_t len)
++{
++	if (level < CONFIG_MSG_MIN_PRIORITY)
++		return;
++
++	_wpa_hexdump_ascii(level, title, buf, len, 1);
++}
+ 
+ /**
+  * wpa_hexdump_ascii_key - conditional hex dump, hide keys
+@@ -144,8 +179,14 @@ void wpa_hexdump_ascii(int level, const
+  * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
+  * default, does not include secret keys (passwords, etc.) in debug output.
+  */
+-void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
+-			   size_t len);
++static inline void wpa_hexdump_ascii_key(int level, const char *title,
++					 const u8 *buf, size_t len)
++{
++	if (level < CONFIG_MSG_MIN_PRIORITY)
++		return;
++
++	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
++}
+ 
+ /*
+  * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
+@@ -182,7 +223,12 @@ void wpa_hexdump_ascii_key(int level, co
+  *
+  * Note: New line '\n' is added to the end of the text when printing to stdout.
+  */
+-void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
++void _wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
++#define wpa_msg(ctx, level, ...)					\
++	do {								\
++		if (level >= CONFIG_MSG_MIN_PRIORITY)			\
++			_wpa_msg(ctx, level, __VA_ARGS__);		\
++	} while(0)
+ 
+ /**
+  * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
+@@ -196,8 +242,13 @@ void wpa_msg(void *ctx, int level, const
+  * attached ctrl_iface monitors. In other words, it can be used for frequent
+  * events that do not need to be sent to syslog.
+  */
+-void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
++void _wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+ PRINTF_FORMAT(3, 4);
++#define wpa_msg_ctrl(ctx, level, ...)					\
++	do {								\
++		if (level >= CONFIG_MSG_MIN_PRIORITY)			\
++			_wpa_msg_ctrl(ctx, level, __VA_ARGS__);		\
++	} while(0)
+ 
+ /**
+  * wpa_msg_global - Global printf for ctrl_iface monitors
diff --git a/package/network/services/hostapd/patches/420-indicate-features.patch b/package/network/services/hostapd/patches/420-indicate-features.patch
new file mode 100644
index 0000000000..8abeafcace
--- /dev/null
+++ b/package/network/services/hostapd/patches/420-indicate-features.patch
@@ -0,0 +1,62 @@
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -15,6 +15,7 @@
+ #include "utils/common.h"
+ #include "utils/eloop.h"
+ #include "utils/uuid.h"
++#include "utils/build_features.h"
+ #include "crypto/random.h"
+ #include "crypto/tls.h"
+ #include "common/version.h"
+@@ -668,7 +669,7 @@ int main(int argc, char *argv[])
+ 	wpa_supplicant_event = hostapd_wpa_event;
+ 	wpa_supplicant_event_global = hostapd_wpa_event_global;
+ 	for (;;) {
+-		c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
++		c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:g:G:v::");
+ 		if (c < 0)
+ 			break;
+ 		switch (c) {
+@@ -705,6 +706,8 @@ int main(int argc, char *argv[])
+ 			break;
+ #endif /* CONFIG_DEBUG_LINUX_TRACING */
+ 		case 'v':
++			if (optarg)
++				exit(!has_feature(optarg));
+ 			show_version();
+ 			exit(1);
+ 			break;
+--- a/wpa_supplicant/main.c
++++ b/wpa_supplicant/main.c
+@@ -12,6 +12,7 @@
+ #endif /* __linux__ */
+ 
+ #include "common.h"
++#include "build_features.h"
+ #include "fst/fst.h"
+ #include "wpa_supplicant_i.h"
+ #include "driver_i.h"
+@@ -202,7 +203,7 @@ int main(int argc, char *argv[])
+ 
+ 	for (;;) {
+ 		c = getopt(argc, argv,
+-			   "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuvW");
++			   "b:Bc:C:D:de:f:g:G:hH:i:I:KLMm:No:O:p:P:qsTtuv::W");
+ 		if (c < 0)
+ 			break;
+ 		switch (c) {
+@@ -305,8 +306,12 @@ int main(int argc, char *argv[])
+ 			break;
+ #endif /* CONFIG_DBUS */
+ 		case 'v':
+-			printf("%s\n", wpa_supplicant_version);
+-			exitcode = 0;
++			if (optarg) {
++				exitcode = !has_feature(optarg);
++			} else {
++				printf("%s\n", wpa_supplicant_version);
++				exitcode = 0;
++			}
+ 			goto out;
+ 		case 'W':
+ 			params.wait_for_monitor++;
diff --git a/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch b/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch
new file mode 100644
index 0000000000..cc7747abe1
--- /dev/null
+++ b/package/network/services/hostapd/patches/430-hostapd_cli_ifdef.patch
@@ -0,0 +1,34 @@
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -382,7 +382,6 @@ static int hostapd_cli_cmd_sa_query(stru
+ #endif /* CONFIG_IEEE80211W */
+ 
+ 
+-#ifdef CONFIG_WPS
+ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
+ 				   char *argv[])
+ {
+@@ -608,7 +607,6 @@ static int hostapd_cli_cmd_wps_config(st
+ 			 ssid_hex, argv[1]);
+ 	return wpa_ctrl_command(ctrl, buf);
+ }
+-#endif /* CONFIG_WPS */
+ 
+ 
+ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+@@ -1275,7 +1273,6 @@ static const struct hostapd_cli_cmd host
+ 	{ "sa_query", hostapd_cli_cmd_sa_query, NULL,
+ 	  "<addr> = send SA Query to a station" },
+ #endif /* CONFIG_IEEE80211W */
+-#ifdef CONFIG_WPS
+ 	{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
+ 	  "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
+ 	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
+@@ -1300,7 +1297,6 @@ static const struct hostapd_cli_cmd host
+ 	  "<SSID> <auth> <encr> <key> = configure AP" },
+ 	{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
+ 	  "= show current WPS status" },
+-#endif /* CONFIG_WPS */
+ 	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
+ 	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
+ 	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
diff --git a/package/network/services/hostapd/patches/431-wpa_cli_ifdef.patch b/package/network/services/hostapd/patches/431-wpa_cli_ifdef.patch
new file mode 100644
index 0000000000..2c9fe28a1d
--- /dev/null
+++ b/package/network/services/hostapd/patches/431-wpa_cli_ifdef.patch
@@ -0,0 +1,12 @@
+--- a/wpa_supplicant/wpa_cli.c
++++ b/wpa_supplicant/wpa_cli.c
+@@ -26,6 +26,9 @@
+ #include <cutils/properties.h>
+ #endif /* ANDROID */
+ 
++#ifndef CONFIG_P2P
++#define CONFIG_P2P
++#endif
+ 
+ static const char *const wpa_cli_version =
+ "wpa_cli v" VERSION_STR "\n"
diff --git a/package/network/services/hostapd/patches/432-missing-typedef.patch b/package/network/services/hostapd/patches/432-missing-typedef.patch
new file mode 100644
index 0000000000..7a100f1a0d
--- /dev/null
+++ b/package/network/services/hostapd/patches/432-missing-typedef.patch
@@ -0,0 +1,10 @@
+--- a/src/drivers/linux_wext.h
++++ b/src/drivers/linux_wext.h
+@@ -26,6 +26,7 @@ typedef int32_t __s32;
+ typedef uint16_t __u16;
+ typedef int16_t __s16;
+ typedef uint8_t __u8;
++typedef int8_t __s8;
+ #ifndef __user
+ #define __user
+ #endif /* __user */
diff --git a/package/network/services/hostapd/patches/450-scan_wait.patch b/package/network/services/hostapd/patches/450-scan_wait.patch
new file mode 100644
index 0000000000..78cf3064fa
--- /dev/null
+++ b/package/network/services/hostapd/patches/450-scan_wait.patch
@@ -0,0 +1,73 @@
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -37,6 +37,8 @@ struct hapd_global {
+ };
+ 
+ static struct hapd_global global;
++static int daemonize = 0;
++static char *pid_file = NULL;
+ 
+ 
+ #ifndef CONFIG_NO_HOSTAPD_LOGGER
+@@ -143,6 +145,14 @@ static void hostapd_logger_cb(void *ctx,
+ }
+ #endif /* CONFIG_NO_HOSTAPD_LOGGER */
+ 
++static void hostapd_setup_complete_cb(void *ctx)
++{
++	if (daemonize && os_daemonize(pid_file)) {
++		perror("daemon");
++		return;
++	}
++	daemonize = 0;
++}
+ 
+ /**
+  * hostapd_driver_init - Preparate driver interface
+@@ -161,6 +171,8 @@ static int hostapd_driver_init(struct ho
+ 		return -1;
+ 	}
+ 
++	hapd->setup_complete_cb = hostapd_setup_complete_cb;
++
+ 	/* Initialize the driver interface */
+ 	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
+ 		b = NULL;
+@@ -401,8 +413,6 @@ static void hostapd_global_deinit(const
+ #endif /* CONFIG_NATIVE_WINDOWS */
+ 
+ 	eap_server_unregister_methods();
+-
+-	os_daemonize_terminate(pid_file);
+ }
+ 
+ 
+@@ -428,18 +438,6 @@ static int hostapd_global_run(struct hap
+ 	}
+ #endif /* EAP_SERVER_TNC */
+ 
+-	if (daemonize) {
+-		if (os_daemonize(pid_file)) {
+-			wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
+-			return -1;
+-		}
+-		if (eloop_sock_requeue()) {
+-			wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
+-				   strerror(errno));
+-			return -1;
+-		}
+-	}
+-
+ 	eloop_run();
+ 
+ 	return 0;
+@@ -638,8 +636,7 @@ int main(int argc, char *argv[])
+ 	struct hapd_interfaces interfaces;
+ 	int ret = 1;
+ 	size_t i, j;
+-	int c, debug = 0, daemonize = 0;
+-	char *pid_file = NULL;
++	int c, debug = 0;
+ 	const char *log_file = NULL;
+ 	const char *entropy_file = NULL;
+ 	char **bss_config = NULL, **tmp_bss;
diff --git a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch
new file mode 100644
index 0000000000..c6053f0953
--- /dev/null
+++ b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch
@@ -0,0 +1,191 @@
+From 4bb69d15477e0f2b00e166845341dc933de47c58 Mon Sep 17 00:00:00 2001
+From: Antonio Quartulli <ordex@autistici.org>
+Date: Sun, 3 Jun 2012 18:22:56 +0200
+Subject: [PATCHv2 601/602] wpa_supplicant: add new config params to be used
+ with the ibss join command
+
+Signed-hostap: Antonio Quartulli <ordex@autistici.org>
+---
+ src/drivers/driver.h            |    6 +++
+ wpa_supplicant/config.c         |   96 +++++++++++++++++++++++++++++++++++++++
+ wpa_supplicant/config_ssid.h    |    6 +++
+ wpa_supplicant/wpa_supplicant.c |   23 +++++++---
+ 4 files changed, 124 insertions(+), 7 deletions(-)
+
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -19,6 +19,7 @@
+ 
+ #define WPA_SUPPLICANT_DRIVER_VERSION 4
+ 
++#include "ap/sta_info.h"
+ #include "common/defs.h"
+ #include "common/ieee802_11_defs.h"
+ #include "utils/list.h"
+@@ -587,6 +588,9 @@ struct wpa_driver_associate_params {
+ 	 * responsible for selecting with which BSS to associate. */
+ 	const u8 *bssid;
+ 
++	unsigned char rates[WLAN_SUPP_RATES_MAX];
++	int mcast_rate;
++
+ 	/**
+ 	 * bssid_hint - BSSID of a proposed AP
+ 	 *
+--- a/wpa_supplicant/config.c
++++ b/wpa_supplicant/config.c
+@@ -16,6 +16,7 @@
+ #include "eap_peer/eap.h"
+ #include "p2p/p2p.h"
+ #include "fst/fst.h"
++#include "ap/sta_info.h"
+ #include "config.h"
+ 
+ 
+@@ -1816,6 +1817,97 @@ static char * wpa_config_write_mesh_basi
+ #endif /* CONFIG_MESH */
+ 
+ 
++static int wpa_config_parse_mcast_rate(const struct parse_data *data,
++				       struct wpa_ssid *ssid, int line,
++				       const char *value)
++{
++	ssid->mcast_rate = (int)(strtod(value, NULL) * 10);
++
++	return 0;
++}
++
++#ifndef NO_CONFIG_WRITE
++static char * wpa_config_write_mcast_rate(const struct parse_data *data,
++					  struct wpa_ssid *ssid)
++{
++	char *value;
++	int res;
++
++	if (!ssid->mcast_rate == 0)
++		return NULL;
++
++	value = os_malloc(6); /* longest: 300.0 */
++	if (value == NULL)
++		return NULL;
++	res = os_snprintf(value, 5, "%.1f", (double)ssid->mcast_rate / 10);
++	if (res < 0) {
++		os_free(value);
++		return NULL;
++	}
++	return value;
++}
++#endif /* NO_CONFIG_WRITE */
++
++static int wpa_config_parse_rates(const struct parse_data *data,
++				  struct wpa_ssid *ssid, int line,
++				  const char *value)
++{
++	int i;
++	char *pos, *r, *sptr, *end;
++	double rate;
++
++	pos = (char *)value;
++	r = strtok_r(pos, ",", &sptr);
++	i = 0;
++	while (pos && i < WLAN_SUPP_RATES_MAX) {
++		rate = 0.0;
++		if (r)
++			rate = strtod(r, &end);
++		ssid->rates[i] = rate * 2;
++		if (*end != '\0' || rate * 2 != ssid->rates[i])
++			return 1;
++
++		i++;
++		r = strtok_r(NULL, ",", &sptr);
++	}
++
++	return 0;
++}
++
++#ifndef NO_CONFIG_WRITE
++static char * wpa_config_write_rates(const struct parse_data *data,
++				     struct wpa_ssid *ssid)
++{
++	char *value, *pos;
++	int res, i;
++
++	if (ssid->rates[0] <= 0)
++		return NULL;
++
++	value = os_malloc(6 * WLAN_SUPP_RATES_MAX + 1);
++	if (value == NULL)
++		return NULL;
++	pos = value;
++	for (i = 0; i < WLAN_SUPP_RATES_MAX - 1; i++) {
++		res = os_snprintf(pos, 6, "%.1f,", (double)ssid->rates[i] / 2);
++		if (res < 0) {
++			os_free(value);
++			return NULL;
++		}
++		pos += res;
++	}
++	res = os_snprintf(pos, 6, "%.1f",
++			  (double)ssid->rates[WLAN_SUPP_RATES_MAX - 1] / 2);
++	if (res < 0) {
++		os_free(value);
++		return NULL;
++	}
++
++	value[6 * WLAN_SUPP_RATES_MAX] = '\0';
++	return value;
++}
++#endif /* NO_CONFIG_WRITE */
++
+ /* Helper macros for network block parser */
+ 
+ #ifdef OFFSET
+@@ -2048,6 +2140,9 @@ static const struct parse_data ssid_fiel
+ 	{ INT(ap_max_inactivity) },
+ 	{ INT(dtim_period) },
+ 	{ INT(beacon_int) },
++	{ INT_RANGE(fixed_freq, 0, 1) },
++	{ FUNC(rates) },
++	{ FUNC(mcast_rate) },
+ #ifdef CONFIG_MACSEC
+ 	{ INT_RANGE(macsec_policy, 0, 1) },
+ #endif /* CONFIG_MACSEC */
+--- a/wpa_supplicant/config_ssid.h
++++ b/wpa_supplicant/config_ssid.h
+@@ -10,8 +10,10 @@
+ #define CONFIG_SSID_H
+ 
+ #include "common/defs.h"
++#include "ap/sta_info.h"
+ #include "utils/list.h"
+ #include "eap_peer/eap_config.h"
++#include "drivers/nl80211_copy.h"
+ 
+ 
+ #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
+@@ -719,6 +721,9 @@ struct wpa_ssid {
+ 	 */
+ 	void *parent_cred;
+ 
++	unsigned char rates[WLAN_SUPP_RATES_MAX];
++	double mcast_rate;
++
+ #ifdef CONFIG_MACSEC
+ 	/**
+ 	 * macsec_policy - Determines the policy for MACsec secure session
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -2527,6 +2527,13 @@ static void wpas_start_assoc_cb(struct w
+ 			params.beacon_int = ssid->beacon_int;
+ 		else
+ 			params.beacon_int = wpa_s->conf->beacon_int;
++		params.fixed_freq = ssid->fixed_freq;
++		i = 0;
++		while (i < WLAN_SUPP_RATES_MAX) {
++			params.rates[i] = ssid->rates[i];
++			i++;
++		}
++		params.mcast_rate = ssid->mcast_rate;
+ 	}
+ 
+ 	params.wpa_ie = wpa_ie;
diff --git a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch b/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch
new file mode 100644
index 0000000000..591543b89c
--- /dev/null
+++ b/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch
@@ -0,0 +1,59 @@
+From ffc4445958a3ed4064f2e1bf73fa478a61c5cf7b Mon Sep 17 00:00:00 2001
+From: Antonio Quartulli <ordex@autistici.org>
+Date: Sun, 3 Jun 2012 18:42:25 +0200
+Subject: [PATCHv2 602/602] driver_nl80211: use new parameters during ibss join
+
+Signed-hostap: Antonio Quartulli <ordex@autistici.org>
+---
+ src/drivers/driver_nl80211.c |   33 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4722,7 +4722,7 @@ static int wpa_driver_nl80211_ibss(struc
+ 				   struct wpa_driver_associate_params *params)
+ {
+ 	struct nl_msg *msg;
+-	int ret = -1;
++	int ret = -1, i;
+ 	int count = 0;
+ 
+ 	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
+@@ -4749,6 +4749,37 @@ retry:
+ 	    nl80211_put_beacon_int(msg, params->beacon_int))
+ 		goto fail;
+ 
++	if (params->fixed_freq) {
++		wpa_printf(MSG_DEBUG, "  * fixed_freq");
++		nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED);
++	}
++
++	if (params->beacon_int > 0) {
++		wpa_printf(MSG_DEBUG, "  * beacon_int=%d",
++			   params->beacon_int);
++		nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
++			    params->beacon_int);
++	}
++
++	if (params->rates[0] > 0) {
++		wpa_printf(MSG_DEBUG, "  * basic_rates:");
++		i = 0;
++		while (i < NL80211_MAX_SUPP_RATES &&
++		       params->rates[i] > 0) {
++			wpa_printf(MSG_DEBUG, "    %.1f",
++				   (double)params->rates[i] / 2);
++			i++;
++		}
++		nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, i,
++			params->rates);
++	}
++
++	if (params->mcast_rate > 0) {
++		wpa_printf(MSG_DEBUG, "  * mcast_rate=%.1f",
++			   (double)params->mcast_rate / 10);
++		nla_put_u32(msg, NL80211_ATTR_MCAST_RATE, params->mcast_rate);
++	}
++
+ 	ret = nl80211_set_conn_keys(params, msg);
+ 	if (ret)
+ 		goto fail;
diff --git a/package/network/services/hostapd/patches/462-wpa_s-support-htmode-param.patch b/package/network/services/hostapd/patches/462-wpa_s-support-htmode-param.patch
new file mode 100644
index 0000000000..993b6de0b5
--- /dev/null
+++ b/package/network/services/hostapd/patches/462-wpa_s-support-htmode-param.patch
@@ -0,0 +1,156 @@
+From b9329c5dfeed7d5c55d2117d8dfe326fc40c8fb1 Mon Sep 17 00:00:00 2001
+From: Antonio Quartulli <ordex@autistici.org>
+Date: Tue, 3 Jul 2012 00:36:24 +0200
+Subject: [PATCH] wpa_s: support htmode param
+
+possible values are HT20, HT40-, HT40+ and NOHT
+
+Signed-off-by: Antonio Quartulli <ordex@autistici.org>
+---
+ src/drivers/driver.h            |    2 ++
+ src/drivers/driver_nl80211.c    |   16 ++++++++++
+ wpa_supplicant/config.c         |   66 +++++++++++++++++++++++++++++++++++++++
+ wpa_supplicant/config_ssid.h    |    2 ++
+ wpa_supplicant/wpa_supplicant.c |    2 ++
+ 5 files changed, 88 insertions(+)
+
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -590,6 +590,8 @@ struct wpa_driver_associate_params {
+ 
+ 	unsigned char rates[WLAN_SUPP_RATES_MAX];
+ 	int mcast_rate;
++	int ht_set;
++	unsigned int htmode;
+ 
+ 	/**
+ 	 * bssid_hint - BSSID of a proposed AP
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4780,6 +4780,22 @@ retry:
+ 		nla_put_u32(msg, NL80211_ATTR_MCAST_RATE, params->mcast_rate);
+ 	}
+ 
++	if (params->ht_set) {
++		switch(params->htmode) {
++			case NL80211_CHAN_HT20:
++				wpa_printf(MSG_DEBUG, "  * ht=HT20");
++				break;
++			case NL80211_CHAN_HT40PLUS:
++				wpa_printf(MSG_DEBUG, "  * ht=HT40+");
++				break;
++			case NL80211_CHAN_HT40MINUS:
++				wpa_printf(MSG_DEBUG, "  * ht=HT40-");
++				break;
++		}
++		nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
++			    params->htmode);
++	}
++
+ 	ret = nl80211_set_conn_keys(params, msg);
+ 	if (ret)
+ 		goto fail;
+--- a/wpa_supplicant/config.c
++++ b/wpa_supplicant/config.c
+@@ -1848,6 +1848,71 @@ static char * wpa_config_write_mcast_rat
+ }
+ #endif /* NO_CONFIG_WRITE */
+ 
++static int wpa_config_parse_htmode(const struct parse_data *data,
++				   struct wpa_ssid *ssid, int line,
++				   const char *value)
++{
++	int i;
++	static const struct {
++		const char *name;
++		unsigned int val;
++	} htmap[] = {
++		{ .name = "HT20", .val = NL80211_CHAN_HT20, },
++		{ .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
++		{ .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
++		{ .name = "NOHT", .val = NL80211_CHAN_NO_HT, },
++	};
++	ssid->ht_set = 0;;
++	for (i = 0; i < 4; i++) {
++		if (strcasecmp(htmap[i].name, value) == 0) {
++			ssid->htmode = htmap[i].val;
++			ssid->ht_set = 1;
++			break;
++		}
++	}
++
++	return 0;
++}
++
++#ifndef NO_CONFIG_WRITE
++static char * wpa_config_write_htmode(const struct parse_data *data,
++				      struct wpa_ssid *ssid)
++{
++	char *value;
++	int res;
++
++	value = os_malloc(6); /* longest: HT40+ */
++	if (value == NULL)
++		return NULL;
++
++	switch(ssid->htmode) {
++		case NL80211_CHAN_HT20:
++			res = os_snprintf(value, 4, "HT20");
++			break;
++		case NL80211_CHAN_HT40PLUS:
++			res = os_snprintf(value, 5, "HT40+");
++			break;
++		case NL80211_CHAN_HT40MINUS:
++			res = os_snprintf(value, 5, "HT40-");
++			break;
++		case NL80211_CHAN_NO_HT:
++			res = os_snprintf(value, 4, "NOHT");
++			break;
++		default:
++			os_free(value);
++			return NULL;
++	}
++
++	if (res < 0) {
++		os_free(value);
++		return NULL;
++	}
++
++	return value;
++}
++#endif /* NO_CONFIG_WRITE */
++
++
+ static int wpa_config_parse_rates(const struct parse_data *data,
+ 				  struct wpa_ssid *ssid, int line,
+ 				  const char *value)
+@@ -2143,6 +2208,7 @@ static const struct parse_data ssid_fiel
+ 	{ INT_RANGE(fixed_freq, 0, 1) },
+ 	{ FUNC(rates) },
+ 	{ FUNC(mcast_rate) },
++	{ FUNC(htmode) },
+ #ifdef CONFIG_MACSEC
+ 	{ INT_RANGE(macsec_policy, 0, 1) },
+ #endif /* CONFIG_MACSEC */
+--- a/wpa_supplicant/config_ssid.h
++++ b/wpa_supplicant/config_ssid.h
+@@ -723,6 +723,8 @@ struct wpa_ssid {
+ 
+ 	unsigned char rates[WLAN_SUPP_RATES_MAX];
+ 	double mcast_rate;
++	int ht_set;
++	unsigned int htmode;
+ 
+ #ifdef CONFIG_MACSEC
+ 	/**
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -2534,6 +2534,8 @@ static void wpas_start_assoc_cb(struct w
+ 			i++;
+ 		}
+ 		params.mcast_rate = ssid->mcast_rate;
++		params.ht_set = ssid->ht_set;
++		params.htmode = ssid->htmode;
+ 	}
+ 
+ 	params.wpa_ie = wpa_ie;
diff --git a/package/network/services/hostapd/patches/470-survey_data_fallback.patch b/package/network/services/hostapd/patches/470-survey_data_fallback.patch
new file mode 100644
index 0000000000..4e40a87558
--- /dev/null
+++ b/package/network/services/hostapd/patches/470-survey_data_fallback.patch
@@ -0,0 +1,45 @@
+--- a/src/ap/acs.c
++++ b/src/ap/acs.c
+@@ -292,18 +292,12 @@ static void acs_fail(struct hostapd_ifac
+ static long double
+ acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
+ {
+-	long double factor, busy, total;
++	long double factor, busy = 0, total;
+ 
+ 	if (survey->filled & SURVEY_HAS_CHAN_TIME_BUSY)
+ 		busy = survey->channel_time_busy;
+ 	else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX)
+ 		busy = survey->channel_time_rx;
+-	else {
+-		/* This shouldn't really happen as survey data is checked in
+-		 * acs_sanity_check() */
+-		wpa_printf(MSG_ERROR, "ACS: Survey data missing");
+-		return 0;
+-	}
+ 
+ 	total = survey->channel_time;
+ 
+@@ -395,20 +389,19 @@ static int acs_usable_vht80_chan(struct
+ static int acs_survey_is_sufficient(struct freq_survey *survey)
+ {
+ 	if (!(survey->filled & SURVEY_HAS_NF)) {
++		survey->nf = -95;
+ 		wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
+-		return 0;
+ 	}
+ 
+ 	if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
++		survey->channel_time = 0;
+ 		wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
+-		return 0;
+ 	}
+ 
+ 	if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
+ 	    !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
+ 		wpa_printf(MSG_INFO,
+ 			   "ACS: Survey is missing RX and busy time (at least one is required)");
+-		return 0;
+ 	}
+ 
+ 	return 1;
diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch
new file mode 100644
index 0000000000..d64ab1e85f
--- /dev/null
+++ b/package/network/services/hostapd/patches/600-ubus_support.patch
@@ -0,0 +1,264 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -160,6 +160,11 @@ OBJS += ../src/common/hw_features_common
+ 
+ OBJS += ../src/eapol_auth/eapol_auth_sm.o
+ 
++ifdef CONFIG_UBUS
++CFLAGS += -DUBUS_SUPPORT
++OBJS += ../src/ap/ubus.o
++LIBS += -lubox -lubus
++endif
+ 
+ ifdef CONFIG_CODE_COVERAGE
+ CFLAGS += -O0 -fprofile-arcs -ftest-coverage
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -13,6 +13,7 @@
+ #include "utils/list.h"
+ #include "ap_config.h"
+ #include "drivers/driver.h"
++#include "ubus.h"
+ 
+ struct wpa_ctrl_dst;
+ struct radius_server_data;
+@@ -118,6 +119,7 @@ struct hostapd_data {
+ 	struct hostapd_iface *iface;
+ 	struct hostapd_config *iconf;
+ 	struct hostapd_bss_config *conf;
++	struct hostapd_ubus_bss ubus;
+ 	int interface_added; /* virtual interface added for this BSS */
+ 	unsigned int started:1;
+ 	unsigned int disabled:1;
+@@ -323,6 +325,8 @@ struct hostapd_iface {
+ 	struct hostapd_config *conf;
+ 	char phy[16]; /* Name of the PHY (radio) */
+ 
++	struct hostapd_ubus_iface ubus;
++
+ 	enum hostapd_iface_state {
+ 		HAPD_IFACE_UNINITIALIZED,
+ 		HAPD_IFACE_DISABLED,
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -284,6 +284,7 @@ static void hostapd_free_hapd_data(struc
+ 	hapd->started = 0;
+ 
+ 	wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
++	hostapd_ubus_free_bss(hapd);
+ 	iapp_deinit(hapd->iapp);
+ 	hapd->iapp = NULL;
+ 	accounting_deinit(hapd);
+@@ -1140,6 +1141,8 @@ static int hostapd_setup_bss(struct host
+ 	if (hapd->driver && hapd->driver->set_operstate)
+ 		hapd->driver->set_operstate(hapd->drv_priv, 1);
+ 
++	hostapd_ubus_add_bss(hapd);
++
+ 	return 0;
+ }
+ 
+@@ -1665,6 +1668,7 @@ static int hostapd_setup_interface_compl
+ 	if (err)
+ 		goto fail;
+ 
++	hostapd_ubus_add_iface(iface);
+ 	wpa_printf(MSG_DEBUG, "Completing interface initialization");
+ 	if (iface->conf->channel) {
+ #ifdef NEED_AP_MLME
+@@ -1845,6 +1849,7 @@ dfs_offload:
+ 
+ fail:
+ 	wpa_printf(MSG_ERROR, "Interface initialization failed");
++	hostapd_ubus_free_iface(iface);
+ 	hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+ 	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+ #ifdef CONFIG_FST
+@@ -2279,6 +2284,7 @@ void hostapd_interface_deinit_free(struc
+ 		   (unsigned int) iface->conf->num_bss);
+ 	driver = iface->bss[0]->driver;
+ 	drv_priv = iface->bss[0]->drv_priv;
++	hostapd_ubus_free_iface(iface);
+ 	hostapd_interface_deinit(iface);
+ 	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
+ 		   __func__, driver, drv_priv);
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -980,7 +980,8 @@ int auth_sae_init_committed(struct hosta
+ 
+ 
+ static void handle_auth(struct hostapd_data *hapd,
+-			const struct ieee80211_mgmt *mgmt, size_t len)
++			const struct ieee80211_mgmt *mgmt, size_t len,
++			struct hostapd_frame_info *fi)
+ {
+ 	u16 auth_alg, auth_transaction, status_code;
+ 	u16 resp = WLAN_STATUS_SUCCESS;
+@@ -996,6 +997,11 @@ static void handle_auth(struct hostapd_d
+ 	char *identity = NULL;
+ 	char *radius_cui = NULL;
+ 	u16 seq_ctrl;
++	struct hostapd_ubus_request req = {
++		.type = HOSTAPD_UBUS_AUTH_REQ,
++		.mgmt_frame = mgmt,
++		.frame_info = fi,
++	};
+ 
+ 	os_memset(&vlan_id, 0, sizeof(vlan_id));
+ 
+@@ -1149,6 +1155,14 @@ static void handle_auth(struct hostapd_d
+ 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ 		goto fail;
+ 	}
++
++	if (hostapd_ubus_handle_event(hapd, &req)) {
++		wpa_printf(MSG_DEBUG, "Station " MACSTR " rejected by ubus handler.\n",
++		       MAC2STR(mgmt->sa));
++		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
++		goto fail;
++	}
++
+ 	if (res == HOSTAPD_ACL_PENDING) {
+ 		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+ 			   " waiting for an external authentication",
+@@ -2052,13 +2066,18 @@ static u16 send_assoc_resp(struct hostap
+ 
+ static void handle_assoc(struct hostapd_data *hapd,
+ 			 const struct ieee80211_mgmt *mgmt, size_t len,
+-			 int reassoc)
++			 int reassoc, struct hostapd_frame_info *fi)
+ {
+ 	u16 capab_info, listen_interval, seq_ctrl, fc;
+ 	u16 resp = WLAN_STATUS_SUCCESS, reply_res;
+ 	const u8 *pos;
+ 	int left, i;
+ 	struct sta_info *sta;
++	struct hostapd_ubus_request req = {
++		.type = HOSTAPD_UBUS_ASSOC_REQ,
++		.mgmt_frame = mgmt,
++		.frame_info = fi,
++	};
+ 
+ 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
+ 				      sizeof(mgmt->u.assoc_req))) {
+@@ -2178,6 +2197,13 @@ static void handle_assoc(struct hostapd_
+ 	}
+ #endif /* CONFIG_MBO */
+ 
++	if (hostapd_ubus_handle_event(hapd, &req)) {
++		wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n",
++		       MAC2STR(mgmt->sa));
++		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
++		goto fail;
++	}
++
+ 	/*
+ 	 * sta->capability is used in check_assoc_ies() for RRM enabled
+ 	 * capability element.
+@@ -2654,7 +2680,7 @@ int ieee802_11_mgmt(struct hostapd_data
+ 
+ 
+ 	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+-		handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
++		handle_probe_req(hapd, mgmt, len, fi);
+ 		return 1;
+ 	}
+ 
+@@ -2672,17 +2698,17 @@ int ieee802_11_mgmt(struct hostapd_data
+ 	switch (stype) {
+ 	case WLAN_FC_STYPE_AUTH:
+ 		wpa_printf(MSG_DEBUG, "mgmt::auth");
+-		handle_auth(hapd, mgmt, len);
++		handle_auth(hapd, mgmt, len, fi);
+ 		ret = 1;
+ 		break;
+ 	case WLAN_FC_STYPE_ASSOC_REQ:
+ 		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
+-		handle_assoc(hapd, mgmt, len, 0);
++		handle_assoc(hapd, mgmt, len, 0, fi);
+ 		ret = 1;
+ 		break;
+ 	case WLAN_FC_STYPE_REASSOC_REQ:
+ 		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
+-		handle_assoc(hapd, mgmt, len, 1);
++		handle_assoc(hapd, mgmt, len, 1, fi);
+ 		ret = 1;
+ 		break;
+ 	case WLAN_FC_STYPE_DISASSOC:
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -675,7 +675,7 @@ sta_track_seen_on(struct hostapd_iface *
+ 
+ void handle_probe_req(struct hostapd_data *hapd,
+ 		      const struct ieee80211_mgmt *mgmt, size_t len,
+-		      int ssi_signal)
++		      struct hostapd_frame_info *fi)
+ {
+ 	u8 *resp;
+ 	struct ieee802_11_elems elems;
+@@ -684,9 +684,15 @@ void handle_probe_req(struct hostapd_dat
+ 	size_t i, resp_len;
+ 	int noack;
+ 	enum ssid_match_result res;
++	int ssi_signal = fi->ssi_signal;
+ 	int ret;
+ 	u16 csa_offs[2];
+ 	size_t csa_offs_len;
++	struct hostapd_ubus_request req = {
++		.type = HOSTAPD_UBUS_PROBE_REQ,
++		.mgmt_frame = mgmt,
++		.frame_info = fi,
++	};
+ 
+ 	if (len < IEEE80211_HDRLEN)
+ 		return;
+@@ -838,6 +844,12 @@ void handle_probe_req(struct hostapd_dat
+ 	}
+ #endif /* CONFIG_P2P */
+ 
++	if (hostapd_ubus_handle_event(hapd, &req)) {
++		wpa_printf(MSG_DEBUG, "Probe request for " MACSTR " rejected by ubus handler.\n",
++		       MAC2STR(mgmt->sa));
++		return;
++	}
++
+ 	/* TODO: verify that supp_rates contains at least one matching rate
+ 	 * with AP configuration */
+ 
+--- a/src/ap/beacon.h
++++ b/src/ap/beacon.h
+@@ -14,7 +14,7 @@ struct ieee80211_mgmt;
+ 
+ void handle_probe_req(struct hostapd_data *hapd,
+ 		      const struct ieee80211_mgmt *mgmt, size_t len,
+-		      int ssi_signal);
++		      struct hostapd_frame_info *fi);
+ int ieee802_11_set_beacon(struct hostapd_data *hapd);
+ int ieee802_11_set_beacons(struct hostapd_iface *iface);
+ int ieee802_11_update_beacons(struct hostapd_iface *iface);
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -52,6 +52,10 @@ int hostapd_notif_assoc(struct hostapd_d
+ 	u16 reason = WLAN_REASON_UNSPECIFIED;
+ 	u16 status = WLAN_STATUS_SUCCESS;
+ 	const u8 *p2p_dev_addr = NULL;
++	struct hostapd_ubus_request req = {
++		.type = HOSTAPD_UBUS_ASSOC_REQ,
++		.addr = addr,
++	};
+ 
+ 	if (addr == NULL) {
+ 		/*
+@@ -131,6 +135,12 @@ int hostapd_notif_assoc(struct hostapd_d
+ 		goto fail;
+ 	}
+ 
++	if (hostapd_ubus_handle_event(hapd, &req)) {
++		wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n",
++			   MAC2STR(req.addr));
++		goto fail;
++	}
++
+ #ifdef CONFIG_P2P
+ 	if (elems.p2p) {
+ 		wpabuf_free(sta->p2p_ie);
diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c
new file mode 100644
index 0000000000..c24f63fd8b
--- /dev/null
+++ b/package/network/services/hostapd/src/src/ap/ubus.c
@@ -0,0 +1,536 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "wps_hostapd.h"
+#include "sta_info.h"
+#include "ubus.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
+{
+	return container_of(obj, struct hostapd_data, ubus.obj);
+}
+
+
+struct ubus_banned_client {
+	struct avl_node avl;
+	u8 addr[ETH_ALEN];
+};
+
+static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct ubus_context *ctx = eloop_ctx;
+	ubus_handle_event(ctx);
+}
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+	if (ubus_reconnect(ctx, NULL)) {
+		eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+		return;
+	}
+
+	eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+}
+
+static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
+{
+	eloop_unregister_read_sock(ctx->sock.fd);
+	eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool hostapd_ubus_init(void)
+{
+	if (ctx)
+		return true;
+
+	ctx = ubus_connect(NULL);
+	if (!ctx)
+		return false;
+
+	ctx->connection_lost = hostapd_ubus_connection_lost;
+	eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+	return true;
+}
+
+static void hostapd_ubus_ref_inc(void)
+{
+	ctx_ref++;
+}
+
+static void hostapd_ubus_ref_dec(void)
+{
+	ctx_ref--;
+	if (!ctx)
+		return;
+
+	if (ctx_ref)
+		return;
+
+	eloop_unregister_read_sock(ctx->sock.fd);
+	ubus_free(ctx);
+	ctx = NULL;
+}
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+	if (!hostapd_ubus_init())
+		return;
+}
+
+void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+	if (!ctx)
+		return;
+}
+
+static void
+hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
+{
+	struct ubus_banned_client *ban = eloop_data;
+	struct hostapd_data *hapd = user_ctx;
+
+	avl_delete(&hapd->ubus.banned, &ban->avl);
+	free(ban);
+}
+
+static void
+hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time)
+{
+	struct ubus_banned_client *ban;
+
+	if (time < 0)
+		time = 0;
+
+	ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+	if (!ban) {
+		if (!time)
+			return;
+
+		ban = os_zalloc(sizeof(*ban));
+		memcpy(ban->addr, addr, sizeof(ban->addr));
+		ban->avl.key = ban->addr;
+		avl_insert(&hapd->ubus.banned, &ban->avl);
+	} else {
+		eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd);
+		if (!time) {
+			hostapd_bss_del_ban(ban, hapd);
+			return;
+		}
+	}
+
+	eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
+}
+
+static int
+hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct sta_info *sta;
+	void *list, *c;
+	char mac_buf[20];
+	static const struct {
+		const char *name;
+		uint32_t flag;
+	} sta_flags[] = {
+		{ "auth", WLAN_STA_AUTH },
+		{ "assoc", WLAN_STA_ASSOC },
+		{ "authorized", WLAN_STA_AUTHORIZED },
+		{ "preauth", WLAN_STA_PREAUTH },
+		{ "wds", WLAN_STA_WDS },
+		{ "wmm", WLAN_STA_WMM },
+		{ "ht", WLAN_STA_HT },
+		{ "vht", WLAN_STA_VHT },
+		{ "wps", WLAN_STA_WPS },
+		{ "mfp", WLAN_STA_MFP },
+	};
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+	list = blobmsg_open_table(&b, "clients");
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		int i;
+
+		sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
+		c = blobmsg_open_table(&b, mac_buf);
+		for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
+			blobmsg_add_u8(&b, sta_flags[i].name,
+				       !!(sta->flags & sta_flags[i].flag));
+		blobmsg_add_u32(&b, "aid", sta->aid);
+		blobmsg_close_table(&b, c);
+	}
+	blobmsg_close_array(&b, list);
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+enum {
+	DEL_CLIENT_ADDR,
+	DEL_CLIENT_REASON,
+	DEL_CLIENT_DEAUTH,
+	DEL_CLIENT_BAN_TIME,
+	__DEL_CLIENT_MAX
+};
+
+static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
+	[DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+	[DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
+	[DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
+	[DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__DEL_CLIENT_MAX];
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct sta_info *sta;
+	bool deauth = false;
+	int reason;
+	u8 addr[ETH_ALEN];
+
+	blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[DEL_CLIENT_ADDR])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (tb[DEL_CLIENT_REASON])
+		reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
+
+	if (tb[DEL_CLIENT_DEAUTH])
+		deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta) {
+		if (deauth) {
+			hostapd_drv_sta_deauth(hapd, addr, reason);
+			ap_sta_deauthenticate(hapd, sta, reason);
+		} else {
+			hostapd_drv_sta_disassoc(hapd, addr, reason);
+			ap_sta_disassociate(hapd, sta, reason);
+		}
+	}
+
+	if (tb[DEL_CLIENT_BAN_TIME])
+		hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
+
+	return 0;
+}
+
+static void
+blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
+{
+	char *s;
+
+	s = blobmsg_alloc_string_buffer(buf, name, 20);
+	sprintf(s, MACSTR, MAC2STR(addr));
+	blobmsg_add_string_buffer(buf);
+}
+
+static int
+hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct ubus_banned_client *ban;
+	void *c;
+
+	blob_buf_init(&b, 0);
+	c = blobmsg_open_array(&b, "clients");
+	avl_for_each_element(&hapd->ubus.banned, ban, avl)
+		blobmsg_add_macaddr(&b, NULL, ban->addr);
+	blobmsg_close_array(&b, c);
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+static int
+hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	rc = hostapd_wps_button_pushed(hapd, NULL);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+
+static int
+hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	rc = hostapd_wps_cancel(hapd);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+
+static int
+hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	rc = ieee802_11_set_beacon(hapd);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+
+enum {
+	CSA_FREQ,
+	CSA_BCN_COUNT,
+	__CSA_MAX
+};
+
+static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
+	/*
+	 * for now, frequency and beacon count are enough, add more
+	 * parameters on demand
+	 */
+	[CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
+	[CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
+};
+
+#ifdef NEED_AP_MLME
+static int
+hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
+		    struct ubus_request_data *req, const char *method,
+		    struct blob_attr *msg)
+{
+	struct blob_attr *tb[__CSA_MAX];
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct csa_settings css;
+
+	blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[CSA_FREQ])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	memset(&css, 0, sizeof(css));
+	css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
+	if (tb[CSA_BCN_COUNT])
+		css.cs_count = blobmsg_get_u32(tb[CSA_BCN_COUNT]);
+
+	if (hostapd_switch_channel(hapd, &css) != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+	return UBUS_STATUS_OK;
+}
+#endif
+
+enum {
+	VENDOR_ELEMENTS,
+	__VENDOR_ELEMENTS_MAX
+};
+
+static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
+	/* vendor elements are provided as hex-string */
+	[VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct hostapd_bss_config *bss = hapd->conf;
+	struct wpabuf *elems;
+	const char *pos;
+	size_t len;
+
+	blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
+		      blob_data(msg), blob_len(msg));
+
+	if (!tb[VENDOR_ELEMENTS])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
+	len = os_strlen(pos);
+	if (len & 0x01)
+			return UBUS_STATUS_INVALID_ARGUMENT;
+
+	len /= 2;
+	if (len == 0) {
+		wpabuf_free(bss->vendor_elements);
+		bss->vendor_elements = NULL;
+		return 0;
+	}
+
+	elems = wpabuf_alloc(len);
+	if (elems == NULL)
+		return 1;
+
+	if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+		wpabuf_free(elems);
+		return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	wpabuf_free(bss->vendor_elements);
+	bss->vendor_elements = elems;
+
+	/* update beacons if vendor elements were set successfully */
+	if (ieee802_11_update_beacons(hapd->iface) != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+	return UBUS_STATUS_OK;
+}
+
+static const struct ubus_method bss_methods[] = {
+	UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
+	UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
+	UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
+	UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
+	UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
+	UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
+#ifdef NEED_AP_MLME
+	UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
+#endif
+	UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
+};
+
+static struct ubus_object_type bss_object_type =
+	UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
+
+static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
+{
+	return memcmp(k1, k2, ETH_ALEN);
+}
+
+void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+	struct ubus_object *obj = &hapd->ubus.obj;
+	char *name;
+	int ret;
+
+	if (!hostapd_ubus_init())
+		return;
+
+	if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
+		return;
+
+	avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
+	obj->name = name;
+	obj->type = &bss_object_type;
+	obj->methods = bss_object_type.methods;
+	obj->n_methods = bss_object_type.n_methods;
+	ret = ubus_add_object(ctx, obj);
+	hostapd_ubus_ref_inc();
+}
+
+void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+	struct ubus_object *obj = &hapd->ubus.obj;
+	char *name = (char *) obj->name;
+
+	if (!ctx)
+		return;
+
+	if (obj->id) {
+		ubus_remove_object(ctx, obj);
+		hostapd_ubus_ref_dec();
+	}
+
+	free(name);
+}
+
+struct ubus_event_req {
+	struct ubus_notify_request nreq;
+	bool deny;
+};
+
+static void
+ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
+{
+	struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
+
+	if (ret)
+		ureq->deny = true;
+}
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+	struct ubus_banned_client *ban;
+	const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
+		[HOSTAPD_UBUS_PROBE_REQ] = "probe",
+		[HOSTAPD_UBUS_AUTH_REQ] = "auth",
+		[HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
+	};
+	const char *type = "mgmt";
+	struct ubus_event_req ureq = {};
+	const u8 *addr;
+
+	if (req->mgmt_frame)
+		addr = req->mgmt_frame->sa;
+	else
+		addr = req->addr;
+
+	ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+	if (ban)
+		return -2;
+
+	if (!hapd->ubus.obj.has_subscribers)
+		return 0;
+
+	if (req->type < ARRAY_SIZE(types))
+		type = types[req->type];
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", addr);
+	if (req->mgmt_frame)
+		blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
+	if (req->frame_info)
+		blobmsg_add_u32(&b, "signal", req->frame_info->ssi_signal);
+	blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+
+	if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
+		return 0;
+
+	ureq.nreq.status_cb = ubus_event_cb;
+	ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+	if (ureq.deny)
+		return -1;
+
+	return 0;
+}
diff --git a/package/network/services/hostapd/src/src/ap/ubus.h b/package/network/services/hostapd/src/src/ap/ubus.h
new file mode 100644
index 0000000000..479ddfca7a
--- /dev/null
+++ b/package/network/services/hostapd/src/src/ap/ubus.h
@@ -0,0 +1,78 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __HOSTAPD_UBUS_H
+#define __HOSTAPD_UBUS_H
+
+enum hostapd_ubus_event_type {
+	HOSTAPD_UBUS_PROBE_REQ,
+	HOSTAPD_UBUS_AUTH_REQ,
+	HOSTAPD_UBUS_ASSOC_REQ,
+	HOSTAPD_UBUS_TYPE_MAX
+};
+
+struct hostapd_ubus_request {
+	enum hostapd_ubus_event_type type;
+	const struct ieee80211_mgmt *mgmt_frame;
+	const struct hostapd_frame_info *frame_info;
+	const u8 *addr;
+};
+
+struct hostapd_iface;
+struct hostapd_data;
+
+#ifdef UBUS_SUPPORT
+
+#include <libubox/avl.h>
+#include <libubus.h>
+
+struct hostapd_ubus_iface {
+	struct ubus_object obj;
+};
+
+struct hostapd_ubus_bss {
+	struct ubus_object obj;
+	struct avl_tree banned;
+};
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface);
+void hostapd_ubus_free_iface(struct hostapd_iface *iface);
+void hostapd_ubus_add_bss(struct hostapd_data *hapd);
+void hostapd_ubus_free_bss(struct hostapd_data *hapd);
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
+
+#else
+
+struct hostapd_ubus_iface {};
+
+struct hostapd_ubus_bss {};
+
+static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+	return 0;
+}
+
+#endif
+
+#endif
diff --git a/package/network/services/hostapd/src/src/utils/build_features.h b/package/network/services/hostapd/src/src/utils/build_features.h
new file mode 100644
index 0000000000..ffbb7978d9
--- /dev/null
+++ b/package/network/services/hostapd/src/src/utils/build_features.h
@@ -0,0 +1,17 @@
+#ifndef BUILD_FEATURES_H
+#define BUILD_FEATURES_H
+
+static inline int has_feature(const char *feat)
+{
+#ifdef IEEE8021X_EAPOL
+	if (!strcmp(feat, "eap"))
+		return 1;
+#endif
+#ifdef IEEE80211N
+	if (!strcmp(feat, "11n"))
+		return 1;
+#endif
+	return 0;
+}
+
+#endif /* BUILD_FEATURES_H */
diff --git a/package/network/services/igmpproxy/Makefile b/package/network/services/igmpproxy/Makefile
new file mode 100644
index 0000000000..8d4da5ca9e
--- /dev/null
+++ b/package/network/services/igmpproxy/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=igmpproxy
+PKG_VERSION:=0.1
+PKG_RELEASE:=9
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/igmpproxy
+PKG_MD5SUM:=c56f41ec195bc1fe016369bf74efc5a1
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+define Package/igmpproxy
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Routing and Redirection
+  DEPENDS:=+USE_GLIBC:librt
+  TITLE:=Multicast Routing Daemon
+  URL:=http://sourceforge.net/projects/igmpproxy
+endef
+
+define Package/igmpproxy/description
+	IGMPproxy is a simple dynamic Multicast Routing Daemon using
+	only IGMP signalling (Internet Group Management Protocol).
+endef
+
+define Package/igmpproxy/conffiles
+/etc/config/igmpproxy
+endef
+
+TARGET_CFLAGS += -Dlog=igmpproxy_log
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR)/src \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -std=gnu99"
+endef
+
+define Package/igmpproxy/install
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_CONF) ./files/igmpproxy.config $(1)/etc/config/igmpproxy
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/igmpproxy.init $(1)/etc/init.d/igmpproxy
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/igmpproxy $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,igmpproxy))
diff --git a/package/network/services/igmpproxy/files/igmpproxy.config b/package/network/services/igmpproxy/files/igmpproxy.config
new file mode 100644
index 0000000000..d89013ca98
--- /dev/null
+++ b/package/network/services/igmpproxy/files/igmpproxy.config
@@ -0,0 +1,12 @@
+config igmpproxy
+	option quickleave 1
+#	option verbose [0-2]
+
+config phyint wan
+	option network wan
+	option direction upstream
+	list altnet 192.168.1.0/24
+
+config phyint lan
+	option network lan
+	option direction downstream
diff --git a/package/network/services/igmpproxy/files/igmpproxy.init b/package/network/services/igmpproxy/files/igmpproxy.init
new file mode 100644
index 0000000000..9f4e51ada4
--- /dev/null
+++ b/package/network/services/igmpproxy/files/igmpproxy.init
@@ -0,0 +1,134 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010-2014 OpenWrt.org
+
+START=99
+USE_PROCD=1
+PROG=/usr/sbin/igmpproxy
+CONFIGFILE=/var/etc/igmpproxy.conf
+
+igmp_header() {
+	local quickleave verbose
+	config_get_bool quickleave "$1" quickleave 0
+	config_get verbose "$1" verbose 0
+
+	[ $verbose = "1" ] && logopts="-v"
+	[ $verbose = "2" ] && logopts="-v -v"
+
+	mkdir -p /var/etc
+	rm -f /var/etc/igmpproxy.conf
+	[ $quickleave -gt 0 ] && echo "quickleave" >> /var/etc/igmpproxy.conf
+
+	[ -L /etc/igmpproxy.conf ] || ln -nsf /var/etc/igmpproxy.conf /etc/igmpproxy.conf
+}
+
+igmp_add_phyint() {
+	local network direction altnets device up
+
+	config_get network $1 network
+	config_get direction $1 direction
+	config_get altnets $1 altnet
+
+	local status="$(ubus -S call "network.interface.$network" status)"
+	[ -n "$status" ] || return
+
+	json_load "$status"
+	json_get_var device l3_device
+	json_get_var up up
+
+	[ -n "$device" -a "$up" = "1" ] || {
+		procd_append_param error "$network is not up"
+		return;
+	}
+
+	append netdevs "$device"
+
+	[[ "$direction" = "upstream" ]] && has_upstream=1
+
+	echo -e "\nphyint $device $direction ratelimit 0 threshold 1" >> /var/etc/igmpproxy.conf
+
+	if [ -n "$altnets" ]; then
+		local altnet
+		for altnet in $altnets; do
+			echo -e "\taltnet $altnet" >> /var/etc/igmpproxy.conf
+		done
+	fi
+}
+
+igmp_add_network() {
+	local network
+
+	config_get network $1 network
+	procd_add_interface_trigger "interface.*" $network /etc/init.d/igmpproxy reload
+}
+
+igmp_add_firewall_routing() {
+	config_get network $1 network
+	config_get direction $1 direction
+
+	[[ "$direction" = "downstream" ]] || return 0
+
+	json_add_object ""
+	json_add_string type rule
+	json_add_string src "$upstream"
+	json_add_string dest "$network"
+	json_add_string family ipv4
+	json_add_string proto udp
+	json_add_string dest_ip "224.0.0.0/4"
+	json_add_string target ACCEPT
+	json_close_object
+}
+
+igmp_add_firewall_network() {
+	config_get network $1 network
+	config_get direction $1 direction
+
+	json_add_object ""
+	json_add_string type rule
+	json_add_string src "$network"
+	json_add_string proto igmp
+	json_add_string target ACCEPT
+	json_close_object
+
+	[[ "$direction" = "upstream" ]] && {
+		upstream="$network"
+		config_foreach igmp_add_firewall_routing phyint
+	}
+}
+
+service_triggers() {
+	procd_add_reload_trigger "igmpproxy"
+	config_foreach igmp_add_network phyint
+}
+
+start_service() {
+	has_upstream=
+	netdevs=
+	logopts=
+	config_load igmpproxy
+
+	config_foreach igmp_header igmpproxy
+	config_foreach igmp_add_phyint phyint
+	[ -n "$has_upstream" ] || return
+
+	procd_open_instance
+	procd_set_param command $PROG
+	[ -n "$logopts" ] && procd_append_param command $logopts
+	procd_append_param command $CONFIGFILE
+	procd_set_param file $CONFIGFILE
+	procd_set_param netdev $netdevs
+	procd_set_param respawn
+
+	procd_open_data
+
+	json_add_array firewall
+	config_foreach igmp_add_firewall_network phyint
+	json_close_array
+
+	procd_close_data
+
+	procd_close_instance
+}
+
+service_started() {
+	procd_set_config_changed firewall
+}
diff --git a/package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch b/package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch
new file mode 100644
index 0000000000..ffe1cf15eb
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch
@@ -0,0 +1,79 @@
+From fed8c3db10bc9d3a1e799a774924c00522595d0c Mon Sep 17 00:00:00 2001
+From: Evgeny Yurchenko <evg.yurch@rogers.com>
+Date: Mon, 4 Jan 2010 05:13:59 +0500
+Subject: [PATCH] Send IGMP packets with IP Router Alert option [RFC 2113] included in IP header
+
+---
+ src/igmp.c      |   17 ++++++++++++-----
+ src/igmpproxy.h |    1 +
+ 2 files changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/src/igmp.c b/src/igmp.c
+index a0cd27d..b547688 100644
+--- a/src/igmp.c
++++ b/src/igmp.c
+@@ -67,7 +67,7 @@ void initIgmp() {
+      * - Checksum (let the kernel fill it in)
+      */
+     ip->ip_v   = IPVERSION;
+-    ip->ip_hl  = sizeof(struct ip) >> 2;
++    ip->ip_hl  = (sizeof(struct ip) + 4) >> 2; /* +4 for Router Alert option */
+     ip->ip_tos = 0xc0;      /* Internet Control */
+     ip->ip_ttl = MAXTTL;    /* applies to unicasts only */
+     ip->ip_p   = IPPROTO_IGMP;
+@@ -213,7 +213,7 @@ void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, i
+     ip                      = (struct ip *)send_buf;
+     ip->ip_src.s_addr       = src;
+     ip->ip_dst.s_addr       = dst;
+-    ip_set_len(ip, MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen);
++    ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen);
+ 
+     if (IN_MULTICAST(ntohl(dst))) {
+         ip->ip_ttl = curttl;
+@@ -221,13 +221,20 @@ void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, i
+         ip->ip_ttl = MAXTTL;
+     }
+ 
+-    igmp                    = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
++    /* Add Router Alert option */
++    ((u_char*)send_buf+MIN_IP_HEADER_LEN)[0] = IPOPT_RA;
++    ((u_char*)send_buf+MIN_IP_HEADER_LEN)[1] = 0x04;
++    ((u_char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00;
++    ((u_char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00;
++
++    igmp                    = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN);
+     igmp->igmp_type         = type;
+     igmp->igmp_code         = code;
+     igmp->igmp_group.s_addr = group;
+     igmp->igmp_cksum        = 0;
+     igmp->igmp_cksum        = inetChksum((u_short *)igmp,
+-                                         IGMP_MINLEN + datalen);
++                                         IP_HEADER_RAOPT_LEN + datalen);
++
+ }
+ 
+ /* 
+@@ -257,7 +264,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in
+ #endif
+     sdst.sin_addr.s_addr = dst;
+     if (sendto(MRouterFD, send_buf,
+-               MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
++               IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen, 0,
+                (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
+         if (errno == ENETDOWN)
+             my_log(LOG_ERR, errno, "Sender VIF was down.");
+diff --git a/src/igmpproxy.h b/src/igmpproxy.h
+index 0de7791..4df8a79 100644
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -64,6 +64,7 @@
+ #define MAX_IP_PACKET_LEN	576
+ #define MIN_IP_HEADER_LEN	20
+ #define MAX_IP_HEADER_LEN	60
++#define IP_HEADER_RAOPT_LEN	24
+ 
+ #define MAX_MC_VIFS    32     // !!! check this const in the specific includes
+ 
+-- 
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch b/package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch
new file mode 100644
index 0000000000..d7550d7961
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch
@@ -0,0 +1,43 @@
+From 85e240727305b156097ee7aa0f0c4473a136291f Mon Sep 17 00:00:00 2001
+From: Constantin Baranov <const@mimas.ru>
+Date: Tue, 23 Feb 2010 21:08:02 +0400
+Subject: [PATCH] Change default interface state to disabled (wrt #2945877)
+
+---
+ src/ifvc.c      |    2 +-
+ src/igmpproxy.c |    6 ++++--
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/ifvc.c b/src/ifvc.c
+index 545b3b4..9d7ee97 100644
+--- a/src/ifvc.c
++++ b/src/ifvc.c
+@@ -139,7 +139,7 @@ void buildIfVc() {
+             IfDescEp->allowednets->subnet_addr = subnet;
+ 
+             // Set the default params for the IF...
+-            IfDescEp->state         = IF_STATE_DOWNSTREAM;
++            IfDescEp->state         = IF_STATE_DISABLED;
+             IfDescEp->robustness    = DEFAULT_ROBUSTNESS;
+             IfDescEp->threshold     = DEFAULT_THRESHOLD;   /* ttl limit */
+             IfDescEp->ratelimit     = DEFAULT_RATELIMIT; 
+diff --git a/src/igmpproxy.c b/src/igmpproxy.c
+index 1ece15a..35000c7 100644
+--- a/src/igmpproxy.c
++++ b/src/igmpproxy.c
+@@ -186,8 +186,10 @@ int igmpProxyInit() {
+                     }
+                 }
+ 
+-                addVIF( Dp );
+-                vifcount++;
++                if (Dp->state != IF_STATE_DISABLED) {
++                    addVIF( Dp );
++                    vifcount++;
++                }
+             }
+         }
+ 
+-- 
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch b/package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch
new file mode 100644
index 0000000000..90d4d5f25f
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch
@@ -0,0 +1,164 @@
+From 65f777e7f66b55239d935c1cf81bb5abc0f6c89f Mon Sep 17 00:00:00 2001
+From: Grinch <grinch79@users.sourceforge.net>
+Date: Sun, 16 Aug 2009 19:58:26 +0500
+Subject: [PATCH] Restrict igmp reports for downstream interfaces (wrt #2833339)
+
+atm all igmp membership reports are forwarded to the upstream interface.
+Unfortunately some ISP Providers restrict some multicast groups (esp. those
+that are defined as local link groups and that are not supposed to be
+forwarded to the wan, i.e 224.0.0.0/24). Therefore there should be some
+kind of black oder whitelisting.
+As whitelisting can be accomplished quite easy I wrote a litte patch, which
+is attached to this request.
+---
+ doc/igmpproxy.conf.5.in |   19 +++++++++++++++++++
+ src/config.c            |   23 ++++++++++++++++++++++-
+ src/igmpproxy.h         |    1 +
+ src/request.c           |   20 ++++++++++++++++----
+ 4 files changed, 58 insertions(+), 5 deletions(-)
+
+diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in
+index a4ea7d0..56efa22 100644
+--- a/doc/igmpproxy.conf.5.in
++++ b/doc/igmpproxy.conf.5.in
+@@ -116,6 +116,25 @@ This is especially useful for the upstream interface, since the source for multi
+ traffic is often from a remote location. Any number of altnet parameters can be specified.
+ .RE
+ 
++.B whitelist
++.I networkaddr
++.RS
++Defines a whitelist for multicast groups. The network address must be in the following
++format 'a.b.c.d/n'. If you want to allow one single group use a network mask of /32,
++i.e. 'a.b.c.d/32'. 
++
++By default all multicast groups are allowed on any downstream interface. If at least one
++whitelist entry is defined, all igmp membership reports for not explicitly whitelisted
++multicast groups will be ignored and therefore not be served by igmpproxy. This is especially
++useful, if your provider does only allow a predefined set of multicast groups. These whitelists
++are only obeyed by igmpproxy itself, they won't prevent any other igmp client running on the
++same machine as igmpproxy from requesting 'unallowed' multicast groups.
++
++You may specify as many whitelist entries as needed. Although you should keep it as simple as
++possible, as this list is parsed for every membership report and therefore this increases igmp
++response times. Often used or large groups should be defined first, as parsing ends as soon as
++a group matches an entry.
++.RE
+ 
+ .SH EXAMPLE
+ ## Enable quickleave
+diff --git a/src/config.c b/src/config.c
+index 5a96ce0..d72619f 100644
+--- a/src/config.c
++++ b/src/config.c
+@@ -46,6 +46,9 @@ struct vifconfig {
+ 
+     // Keep allowed nets for VIF.
+     struct SubnetList*  allowednets;
++
++    // Allowed Groups
++    struct SubnetList*  allowedgroups;
+     
+     // Next config in list...
+     struct vifconfig*   next;
+@@ -202,6 +205,8 @@ void configureVifs() {
+                     // Insert the configured nets...
+                     vifLast->next = confPtr->allowednets;
+ 
++		    Dp->allowedgroups = confPtr->allowedgroups;
++
+                     break;
+                 }
+             }
+@@ -215,7 +220,7 @@ void configureVifs() {
+ */
+ struct vifconfig *parsePhyintToken() {
+     struct vifconfig  *tmpPtr;
+-    struct SubnetList **anetPtr;
++    struct SubnetList **anetPtr, **agrpPtr;
+     char *token;
+     short parseError = 0;
+ 
+@@ -239,6 +244,7 @@ struct vifconfig *parsePhyintToken() {
+     tmpPtr->threshold = 1;
+     tmpPtr->state = IF_STATE_DOWNSTREAM;
+     tmpPtr->allowednets = NULL;
++    tmpPtr->allowedgroups = NULL;
+ 
+     // Make a copy of the token to store the IF name
+     tmpPtr->name = strdup( token );
+@@ -248,6 +254,7 @@ struct vifconfig *parsePhyintToken() {
+ 
+     // Set the altnet pointer to the allowednets pointer.
+     anetPtr = &tmpPtr->allowednets;
++    agrpPtr = &tmpPtr->allowedgroups; 
+ 
+     // Parse the rest of the config..
+     token = nextConfigToken();
+@@ -266,6 +273,20 @@ struct vifconfig *parsePhyintToken() {
+                 anetPtr = &(*anetPtr)->next;
+             }
+         }
++	else if(strcmp("whitelist", token)==0) {
++	    // Whitelist
++	    token = nextConfigToken();
++	    my_log(LOG_DEBUG, 0, "Config: IF: Got whitelist token %s.", token);
++	
++	    *agrpPtr = parseSubnetAddress(token);
++	    if(*agrpPtr == NULL) {
++		parseError = 1;
++		my_log(LOG_WARNING, 0, "Unable to parse subnet address.");
++		break;
++	    } else {
++		agrpPtr = &(*agrpPtr)->next;
++	    }
++	}
+         else if(strcmp("upstream", token)==0) {
+             // Upstream
+             my_log(LOG_DEBUG, 0, "Config: IF: Got upstream token.");
+diff --git a/src/igmpproxy.h b/src/igmpproxy.h
+index 4dabd1c..0de7791 100644
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -145,6 +145,7 @@ struct IfDesc {
+     short               Flags;
+     short               state;
+     struct SubnetList*  allowednets;
++    struct SubnetList*  allowedgroups;
+     unsigned int        robustness;
+     unsigned char       threshold;   /* ttl limit */
+     unsigned int        ratelimit; 
+diff --git a/src/request.c b/src/request.c
+index e3589f6..89b91de 100644
+--- a/src/request.c
++++ b/src/request.c
+@@ -82,10 +82,22 @@ void acceptGroupReport(uint32_t src, uint32_t group, uint8_t type) {
+         my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d",
+             inetFmt(group,s1), inetFmt(src,s2), sourceVif->index);
+ 
+-        // The membership report was OK... Insert it into the route table..
+-        insertRoute(group, sourceVif->index);
+-
+-
++	// If we don't have a whitelist we insertRoute and done
++	if(sourceVif->allowedgroups == NULL)
++	{
++	    insertRoute(group, sourceVif->index);
++	    return;
++	}
++	// Check if this Request is legit on this interface
++	struct SubnetList *sn;
++	for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next)
++	    if((group & sn->subnet_mask) == sn->subnet_addr)
++	    {
++        	// The membership report was OK... Insert it into the route table..
++        	insertRoute(group, sourceVif->index);
++		return;
++	    }
++	my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
+     } else {
+         // Log the state of the interface the report was recieved on.
+         my_log(LOG_INFO, 0, "Mebership report was recieved on %s. Ignoring.",
+-- 
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch b/package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch
new file mode 100644
index 0000000000..a4caed72d2
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch
@@ -0,0 +1,62 @@
+From bcd7c648e86d97263c931de53a008c9629e7797e Mon Sep 17 00:00:00 2001
+From: Stefan Becker <stefan.becker@nokia.com>
+Date: Fri, 11 Dec 2009 21:08:57 +0200
+Subject: [PATCH] Restrict igmp reports forwarding to upstream interface
+
+Utilize the new "whitelist" keyword also on the upstream interface definition.
+If specified then only whitelisted multicast groups will be forwarded upstream.
+
+This can be used to avoid publishing private multicast groups to the world,
+e.g. SSDP from a UPnP server on the internal network.
+---
+ doc/igmpproxy.conf.5.in |    5 +++++
+ src/rttable.c           |   17 +++++++++++++++++
+ 2 files changed, 22 insertions(+), 0 deletions(-)
+
+diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in
+index 56efa22..d916f05 100644
+--- a/doc/igmpproxy.conf.5.in
++++ b/doc/igmpproxy.conf.5.in
+@@ -134,6 +134,11 @@ You may specify as many whitelist entries as needed. Although you should keep it
+ possible, as this list is parsed for every membership report and therefore this increases igmp
+ response times. Often used or large groups should be defined first, as parsing ends as soon as
+ a group matches an entry.
++
++You may also specify whitelist entries for the upstream interface. Only igmp membership reports
++for explicitely whitelisted multicast groups will be sent out on the upstream interface. This
++is useful if you want to use multicast groups only between your downstream interfaces, like SSDP
++from a UPnP server.
+ .RE
+ 
+ .SH EXAMPLE
+diff --git a/src/rttable.c b/src/rttable.c
+index f0701a8..77dd791 100644
+--- a/src/rttable.c
++++ b/src/rttable.c
+@@ -117,6 +117,23 @@ void sendJoinLeaveUpstream(struct RouteTable* route, int join) {
+         my_log(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF.");
+     }
+ 
++    // Check if there is a white list for the upstram VIF
++    if (upstrIf->allowedgroups != NULL) {
++      uint32_t           group = route->group;
++        struct SubnetList* sn;
++
++        // Check if this Request is legit to be forwarded to upstream
++        for(sn = upstrIf->allowedgroups; sn != NULL; sn = sn->next)
++            if((group & sn->subnet_mask) == sn->subnet_addr)
++                // Forward is OK...
++                break;
++
++        if (sn == NULL) {
++	    my_log(LOG_INFO, 0, "The group address %s may not be forwarded upstream. Ignoring.", inetFmt(group, s1));
++            return;
++        }
++    }
++
+     // Send join or leave request...
+     if(join) {
+ 
+-- 
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/010-missing_include.patch b/package/network/services/igmpproxy/patches/010-missing_include.patch
new file mode 100644
index 0000000000..af0eab845b
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/010-missing_include.patch
@@ -0,0 +1,10 @@
+--- a/src/os-linux.h
++++ b/src/os-linux.h
+@@ -3,6 +3,7 @@
+ #include <linux/mroute.h>
+ #include <netinet/ip.h>
+ #include <netinet/igmp.h>
++#include <sys/types.h>
+ 
+ static inline u_short ip_data_len(const struct ip *ip)
+ {
diff --git a/package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch b/package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch
new file mode 100644
index 0000000000..ccd000c638
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch
@@ -0,0 +1,19 @@
+--- a/src/igmp.c
++++ b/src/igmp.c
+@@ -139,8 +139,14 @@
+                 return;
+             }
+             else if(!isAdressValidForIf(checkVIF, src)) {
+-                my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
+-                    inetFmt(src, s1), inetFmt(dst, s2));
++                struct IfDesc *downVIF = getIfByAddress(src);
++                if (downVIF && downVIF->state & IF_STATE_DOWNSTREAM) {
++                    my_log(LOG_NOTICE, 0, "The source address %s for group %s is from downstream VIF. Ignoring.",
++                        inetFmt(src, s1), inetFmt(dst, s2));
++                } else {
++                    my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
++                        inetFmt(src, s1), inetFmt(dst, s2));
++                }
+                 return;
+             }
+             
diff --git a/package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch b/package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch
new file mode 100644
index 0000000000..e75283c036
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch
@@ -0,0 +1,120 @@
+From d0e66e0719ae8eb549f7cc220fdc66575d3db332 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski@gmail.com>
+Date: Thu, 29 Mar 2012 17:01:11 +0200
+Subject: [PATCH 4/4] use monotic clock instead of time of day
+
+The time of day might chance e.g. by daylight savings time during the
+runtime, which causes timers to fire repeatedly for a long time.
+
+Contributed by T-Labs, Deutsche Telekom Innovation Laboratories
+
+Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
+---
+ configure.ac    |    2 ++
+ src/igmpproxy.c |   26 +++++++++++++-------------
+ src/igmpproxy.h |    3 ++-
+ 3 files changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 85beb08..bd84eba 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -25,6 +25,8 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], [], [], [[
+ #include <netinet/in.h>
+ ]])
+ 
++AC_SEARCH_LIBS([clock_gettime],[rt])
++
+ AC_CONFIG_FILES([
+ 	Makefile
+ 	doc/Makefile
+diff --git a/src/igmpproxy.c b/src/igmpproxy.c
+index 35000c7..3a9ccad 100644
+--- a/src/igmpproxy.c
++++ b/src/igmpproxy.c
+@@ -234,13 +234,13 @@ void igmpProxyRun() {
+     int     MaxFD, Rt, secs;
+     fd_set  ReadFDS;
+     socklen_t dummy = 0;
+-    struct  timeval  curtime, lasttime, difftime, tv; 
++    struct  timespec  curtime, lasttime, difftime, tv; 
+     // The timeout is a pointer in order to set it to NULL if nessecary.
+-    struct  timeval  *timeout = &tv;
++    struct  timespec  *timeout = &tv;
+ 
+     // Initialize timer vars
+-    difftime.tv_usec = 0;
+-    gettimeofday(&curtime, NULL);
++    difftime.tv_nsec = 0;
++    clock_gettime(CLOCK_MONOTONIC, &curtime);
+     lasttime = curtime;
+ 
+     // First thing we send a membership query in downstream VIF's...
+@@ -263,7 +263,7 @@ void igmpProxyRun() {
+         if(secs == -1) {
+             timeout = NULL;
+         } else {
+-            timeout->tv_usec = 0;
++            timeout->tv_nsec = 0;
+             timeout->tv_sec = secs;
+         }
+ 
+@@ -274,7 +274,7 @@ void igmpProxyRun() {
+         FD_SET( MRouterFD, &ReadFDS );
+ 
+         // wait for input
+-        Rt = select( MaxFD +1, &ReadFDS, NULL, NULL, timeout );
++        Rt = pselect( MaxFD +1, &ReadFDS, NULL, NULL, timeout, NULL );
+ 
+         // log and ignore failures
+         if( Rt < 0 ) {
+@@ -307,20 +307,20 @@ void igmpProxyRun() {
+              */
+             if (Rt == 0) {
+                 curtime.tv_sec = lasttime.tv_sec + secs;
+-                curtime.tv_usec = lasttime.tv_usec;
++                curtime.tv_nsec = lasttime.tv_nsec;
+                 Rt = -1; /* don't do this next time through the loop */
+             } else {
+-                gettimeofday(&curtime, NULL);
++                clock_gettime(CLOCK_MONOTONIC, &curtime);
+             }
+             difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
+-            difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
+-            while (difftime.tv_usec > 1000000) {
++            difftime.tv_nsec += curtime.tv_nsec - lasttime.tv_nsec;
++            while (difftime.tv_nsec > 1000000000) {
+                 difftime.tv_sec++;
+-                difftime.tv_usec -= 1000000;
++                difftime.tv_nsec -= 1000000000;
+             }
+-            if (difftime.tv_usec < 0) {
++            if (difftime.tv_nsec < 0) {
+                 difftime.tv_sec--;
+-                difftime.tv_usec += 1000000;
++                difftime.tv_nsec += 1000000000;
+             }
+             lasttime = curtime;
+             if (secs == 0 || difftime.tv_sec > 0)
+diff --git a/src/igmpproxy.h b/src/igmpproxy.h
+index 4df8a79..36a4f04 100644
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -44,12 +44,13 @@
+ #include <string.h>
+ #include <fcntl.h>
+ #include <stdbool.h>
++#include <time.h>
+ 
+ #include <sys/socket.h>
+ #include <sys/un.h>
+-#include <sys/time.h>
+ #include <sys/ioctl.h>
+ #include <sys/param.h>
++#include <sys/select.h>
+ 
+ #include <net/if.h>
+ #include <netinet/in.h>
+-- 
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch b/package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch
new file mode 100644
index 0000000000..0dd772007a
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch
@@ -0,0 +1,24 @@
+--- a/src/config.c
++++ b/src/config.c
+@@ -357,15 +357,18 @@ struct SubnetList *parseSubnetAddress(ch
+     tmpStr = strtok(NULL, "/");
+     if(tmpStr != NULL) {
+         int bitcnt = atoi(tmpStr);
+-        if(bitcnt <= 0 || bitcnt > 32) {
++        if(bitcnt < 0 || bitcnt > 32) {
+             my_log(LOG_WARNING, 0, "The bits part of the address is invalid : %d.",tmpStr);
+             return NULL;
+         }
+ 
+-        mask <<= (32 - bitcnt);
++		if (bitcnt == 0)
++			mask = 0;
++		else
++	        mask <<= (32 - bitcnt);
+     }
+ 
+-    if(addr == -1 || addr == 0) {
++    if(addr == -1) {
+         my_log(LOG_WARNING, 0, "Unable to parse address token '%s'.", addrstr);
+         return NULL;
+     }
diff --git a/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch b/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
new file mode 100644
index 0000000000..24aefcef26
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
@@ -0,0 +1,154 @@
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -251,6 +251,7 @@ int activateRoute(uint32_t group, uint32
+ void ageActiveRoutes();
+ void setRouteLastMemberMode(uint32_t group);
+ int lastMemberGroupAge(uint32_t group);
++int interfaceInRoute(int32_t group, int Ix);
+ 
+ /* request.c
+  */
+--- a/src/request.c
++++ b/src/request.c
+@@ -41,10 +41,10 @@
+ 
+ // Prototypes...
+ void sendGroupSpecificMemberQuery(void *argument);  
+-    
++
+ typedef struct {
+     uint32_t      group;
+-    uint32_t      vifAddr;
++    // uint32_t      vifAddr;
+     short       started;
+ } GroupVifDesc;
+ 
+@@ -142,7 +142,7 @@ void acceptLeaveMessage(uint32_t src, ui
+ 
+         // Call the group spesific membership querier...
+         gvDesc->group = group;
+-        gvDesc->vifAddr = sourceVif->InAdr.s_addr;
++        // gvDesc->vifAddr = sourceVif->InAdr.s_addr;
+         gvDesc->started = 0;
+ 
+         sendGroupSpecificMemberQuery(gvDesc);
+@@ -159,6 +159,9 @@ void acceptLeaveMessage(uint32_t src, ui
+ */
+ void sendGroupSpecificMemberQuery(void *argument) {
+     struct  Config  *conf = getCommonConfig();
++    struct  IfDesc  *Dp;
++    struct  RouteTable  *croute;
++    int     Ix;
+ 
+     // Cast argument to correct type...
+     GroupVifDesc   *gvDesc = (GroupVifDesc*) argument;
+@@ -166,22 +169,38 @@ void sendGroupSpecificMemberQuery(void *
+     if(gvDesc->started) {
+         // If aging returns false, we don't do any further action...
+         if(!lastMemberGroupAge(gvDesc->group)) {
++            // FIXME: Should we free gvDesc here?
+             return;
+         }
+     } else {
+         gvDesc->started = 1;
+     }
+ 
+-    // Send a group specific membership query...
+-    sendIgmp(gvDesc->vifAddr, gvDesc->group, 
+-             IGMP_MEMBERSHIP_QUERY,
+-             conf->lastMemberQueryInterval * IGMP_TIMER_SCALE, 
+-             gvDesc->group, 0);
+-
+-    my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
+-        inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2),
+-        conf->lastMemberQueryInterval);
+-
++    /**
++     * FIXME: This loops through all interfaces the group is active on an sends queries.
++     *        It might be better to send only a query on the interface the leave was accepted on and remove only that interface from the route.
++     */
++
++    // Loop through all downstream interfaces
++    for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
++        if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
++            if(Dp->state == IF_STATE_DOWNSTREAM) {
++                // Is that interface used in the group?
++                if (interfaceInRoute(gvDesc->group ,Dp->index)) {
++                        
++                    // Send a group specific membership query... 
++                    sendIgmp(Dp->InAdr.s_addr, gvDesc->group, 
++                            IGMP_MEMBERSHIP_QUERY,
++                            conf->lastMemberQueryInterval * IGMP_TIMER_SCALE, 
++                            gvDesc->group, 0);
++
++                    my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
++                            inetFmt(Dp->InAdr.s_addr,s1), inetFmt(gvDesc->group,s2),
++                            conf->lastMemberQueryInterval);
++                }
++            }
++        }
++    }
+     // Set timeout for next round...
+     timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc);
+ 
+--- a/src/rttable.c
++++ b/src/rttable.c
+@@ -428,6 +428,25 @@ void ageActiveRoutes() {
+ }
+ 
+ /**
++*   Counts the number of interfaces a given route is active on
++*/
++int numberOfInterfaces(struct RouteTable *croute) {
++    int Ix;
++    struct IfDesc *Dp;
++    int result = 0;
++    // Loop through all interfaces
++    for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
++        // If the interface is used by the route, increase counter
++        if(BIT_TST(croute->vifBits, Dp->index)) {
++            result++;
++        }
++    }
++    my_log(LOG_DEBUG, 0, "counted %d interfaces", result);
++    return result;
++}
++
++
++/**
+ *   Should be called when a leave message is recieved, to
+ *   mark a route for the last member probe state.
+ */
+@@ -439,8 +458,11 @@ void setRouteLastMemberMode(uint32_t gro
+     if(croute!=NULL) {
+         // Check for fast leave mode...
+         if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) {
+-            // Send a leave message right away..
+-            sendJoinLeaveUpstream(croute, 0);
++            // Send a leave message right away only when the route has been active on only one interface
++            if (numberOfInterfaces(croute) <= 1) {
++		my_log(LOG_DEBUG, 0, "Leaving group %d now", group);
++                sendJoinLeaveUpstream(croute, 0);
++            } 
+         }
+         // Set the routingstate to Last member check...
+         croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;
+@@ -677,3 +699,18 @@ void logRouteTable(char *header) {
+     
+         my_log(LOG_DEBUG, 0, "-----------------------------------------------------");
+ }
++
++/**
++*   Returns true when the given group belongs to the given interface
++*/
++int interfaceInRoute(int32_t group, int Ix) {
++    struct RouteTable*  croute;
++    croute = findRoute(group);
++    if (croute != NULL) {
++        my_log(LOG_DEBUG, 0, "Interface id %d is in group $d", Ix, group);
++        return BIT_TST(croute->vifBits, Ix);
++    } else {
++        return 0;
++    }
++}
++
diff --git a/package/network/services/ipset-dns/Makefile b/package/network/services/ipset-dns/Makefile
new file mode 100644
index 0000000000..f24d6ef63a
--- /dev/null
+++ b/package/network/services/ipset-dns/Makefile
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ipset-dns
+PKG_VERSION:=2013-05-03
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=http://git.zx2c4.com/ipset-dns
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=6be3afd819a86136b51c5ae722ab48266187155b
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=9deca25a4602936938611d21d891f06685e109626b9eda7f84aa2f0af7aba092
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ipset-dns/Default
+endef
+
+define Package/ipset-dns
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=A lightweight DNS forwarder to populate ipsets
+  URL:=http://git.zx2c4.com/ipset-dns/about/
+  DEPENDS:=+libmnl
+endef
+
+define Package/ipset-dns/description
+ The ipset-dns daemon is a lightweight DNS forwarding server that adds all
+ resolved IPs to a given netfilter ipset. It is designed to be used in
+ conjunction with dnsmasq's upstream server directive.
+
+ Practical use cases include routing over a given gateway traffic for
+ particular web services or webpages that do not have a priori predictable
+ IP addresses and instead rely on dizzying arrays of DNS resolutions.
+endef
+
+define Package/ipset-dns/conffiles
+/etc/config/ipset-dns
+endef
+
+define Package/ipset-dns/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ipset-dns $(1)/usr/sbin/ipset-dns
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/ipset-dns.init $(1)/etc/init.d/ipset-dns
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_CONF) ./files/ipset-dns.config $(1)/etc/config/ipset-dns
+endef
+
+$(eval $(call BuildPackage,ipset-dns))
diff --git a/package/network/services/ipset-dns/files/ipset-dns.config b/package/network/services/ipset-dns/files/ipset-dns.config
new file mode 100644
index 0000000000..0270366af7
--- /dev/null
+++ b/package/network/services/ipset-dns/files/ipset-dns.config
@@ -0,0 +1,16 @@
+# declare an ipset-dns listener instance, multiple allowed
+config ipset-dns
+	# use given ipset for type A (IPv4) responses
+	option ipset 'domain-filter-ipv4'
+
+	# use given ipset for type AAAA (IPv6) responses
+	option ipset6 'domain-filter-ipv6'
+
+	# use given listening port
+	# defaults to 53000 + instance number
+	#option port  '53001'
+
+	# use given upstream DNS server,
+	# defaults to first entry in /tmp/resolv.conf.auto
+	#option dns   '8.8.8.8'
+
diff --git a/package/network/services/ipset-dns/files/ipset-dns.init b/package/network/services/ipset-dns/files/ipset-dns.init
new file mode 100755
index 0000000000..0a76fcc4cd
--- /dev/null
+++ b/package/network/services/ipset-dns/files/ipset-dns.init
@@ -0,0 +1,57 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2013 OpenWrt.org
+
+START=61
+
+USE_PROCD=1
+
+find_nameserver() {
+	. /lib/functions/network.sh
+
+	local tmp
+	if network_find_wan tmp && network_get_dnsserver tmp "$tmp"; then
+		echo "${tmp%% *}"
+		return 0
+	fi
+
+	return 1
+}
+
+start_instance() {
+	local cfg="$1"
+	local ipset ipset6 port dns
+
+	config_get ipset "$cfg" ipset
+	config_get ipset6 "$cfg" ipset6
+	[ -n "$ipset$ipset6" ] || {
+		echo "No ipset specified for instance $cfg" >&2
+		return 1
+	}
+
+	config_get dns "$cfg" dns "$DEFNS"
+	[ -n "$dns" ] || {
+		echo "No DNS server specified for instance $cfg" >&2
+		return 1
+	}
+
+	config_get port "$cfg" port $((PORT++))
+
+	procd_open_instance
+	procd_set_param command /usr/sbin/ipset-dns "$ipset" "$ipset6" "$port" "$dns"
+	procd_set_param env NO_DAEMONIZE=1
+	procd_set_param respawn
+	procd_close_instance
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "ipset-dns"
+}
+
+start_service() {
+	PORT=53001
+	DEFNS="$(find_nameserver)"
+
+	config_load ipset-dns
+	config_foreach start_instance ipset-dns
+}
diff --git a/package/network/services/ipset-dns/patches/100-simultaneous-ipv4-ipv6.patch b/package/network/services/ipset-dns/patches/100-simultaneous-ipv4-ipv6.patch
new file mode 100644
index 0000000000..19669a05b5
--- /dev/null
+++ b/package/network/services/ipset-dns/patches/100-simultaneous-ipv4-ipv6.patch
@@ -0,0 +1,57 @@
+--- a/ipset-dns.c
++++ b/ipset-dns.c
+@@ -307,19 +307,20 @@ int main(int argc, char *argv[]) 
+ 	struct timeval tv;
+ 	char msg[512];
+ 	char ip[INET6_ADDRSTRLEN];
+-	char *ipset;
++	char *ipset, *ipset6;
+ 	int listen_sock, upstream_sock;
+ 	int pos, i, size, af;
+ 	socklen_t len;
+ 	size_t received;
+ 	pid_t child;
+ 	
+-	if (argc != 4) {
+-		fprintf(stderr, "Usage: %s ipset port upstream\n", argv[0]);
++	if (argc != 5) {
++		fprintf(stderr, "Usage: %s ipv4-ipset ipv6-ipset port upstream\n", argv[0]);
+ 		return 1;
+ 	}
+ 
+ 	ipset = argv[1];
++	ipset6 = argv[2];
+ 
+ 	listen_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ 	if (listen_sock < 0) {
+@@ -329,7 +330,7 @@ int main(int argc, char *argv[]) 
+ 
+ 	memset(&listen_addr, 0, sizeof(listen_addr));
+ 	listen_addr.sin_family = AF_INET;
+-	listen_addr.sin_port = htons(atoi(argv[2]));
++	listen_addr.sin_port = htons(atoi(argv[3]));
+ 	listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ 	i = 1;
+ 	setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+@@ -341,7 +342,7 @@ int main(int argc, char *argv[]) 
+ 	memset(&upstream_addr, 0, sizeof(upstream_addr));
+ 	upstream_addr.sin_family = AF_INET;
+ 	upstream_addr.sin_port = htons(53);
+-	inet_aton(argv[3], &upstream_addr.sin_addr);
++	inet_aton(argv[4], &upstream_addr.sin_addr);
+ 	
+ 	/* TODO: Put all of the below code in several forks all listening on the same sock. */
+ 
+@@ -434,8 +435,11 @@ int main(int argc, char *argv[]) 
+ 				continue;
+ 			}
+ 
++			if ((af == AF_INET && !*ipset) || (af == AF_INET6 && !*ipset6))
++				continue;
++
+ 			printf("%s: %s\n", answer.dotted, ip);
+-			if (add_to_ipset(ipset, answer.rdata, af) < 0)
++			if (add_to_ipset((af == AF_INET) ? ipset : ipset6, answer.rdata, af) < 0)
+ 				perror("add_to_ipset");
+ 		}
+ 		
diff --git a/package/network/services/lldpd/Config.in b/package/network/services/lldpd/Config.in
new file mode 100644
index 0000000000..93d84e29ea
--- /dev/null
+++ b/package/network/services/lldpd/Config.in
@@ -0,0 +1,54 @@
+menu "Configuration"
+	depends on PACKAGE_lldpd
+
+config LLDPD_WITH_PRIVSEP
+	bool
+	default y
+	prompt "Enable privilege separation (run lldpd with a chrooted 'lldp' user)"
+
+config LLDPD_WITH_CDP
+	bool
+	default y
+	prompt "Enable support for the Cisco Discovery Protocol (CDP) version 1 and 2"
+
+config LLDPD_WITH_FDP
+	bool
+	default y
+	prompt "Enable support for the Foundry Discovery Protocol (FDP)"
+
+config LLDPD_WITH_EDP
+	bool
+	default y
+	prompt "Enable support for the Extreme Discovery Protocol (EDP)"
+
+config LLDPD_WITH_SONMP
+	bool
+	default y
+	prompt "Enable support for the SynOptics Network Management Protocol"
+
+config LLDPD_WITH_LLDPMED
+	bool
+	prompt "Enable LLDP-MED extension"
+	default y
+
+config LLDPD_WITH_DOT1
+	bool
+	prompt "Enable Dot1 extension (VLAN stuff)"
+	default y
+
+config LLDPD_WITH_DOT3
+	bool
+	prompt "Enable Dot3 extension (PHY stuff)"
+	default y
+
+config LLDPD_WITH_CUSTOM
+	bool
+	prompt "Enable Custom TLVs"
+	default y
+
+config LLDPD_WITH_JSON
+	bool
+	prompt "Enable JSON output for the LLDP Command-Line Interface"
+	default n
+
+endmenu
diff --git a/package/network/services/lldpd/Makefile b/package/network/services/lldpd/Makefile
new file mode 100644
index 0000000000..ff15057aa5
--- /dev/null
+++ b/package/network/services/lldpd/Makefile
@@ -0,0 +1,109 @@
+#
+# Copyright (C) 2008-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lldpd
+PKG_VERSION:=0.9.5
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://media.luffy.cx/files/lldpd
+PKG_MD5SUM:=e9585c52f14808f03f6b6c3a9163c95b542a47b18abe002992b155d143a1a247
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=ISC
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+TARGET_CFLAGS+=--std=c99
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/lldpd
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Routing and Redirection
+  TITLE:=Link Layer Discovery Protocol daemon
+  URL:=https://github.com/vincentbernat/lldpd/wiki
+  DEPENDS:=+libevent2 +USE_GLIBC:libbsd +LLDPD_WITH_JSON:libjson-c
+  USERID:=lldp=121:lldp=129
+  MENU:=1
+endef
+
+define Package/lldpd/config
+source "$(SOURCE)/Config.in"
+endef
+
+define Package/lldpd/description
+	LLDP (Link Layer Discovery Protocol) is an industry standard protocol designed
+	to supplant proprietary Link-Layer protocols such as
+	Extreme's EDP (Extreme Discovery Protocol) and
+	CDP (Cisco Discovery Protocol).
+	The goal of LLDP is to provide an inter-vendor compatible mechanism to deliver
+	Link-Layer notifications to adjacent network devices.
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/liblldpctl.so* $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/lldpctl.h $(1)/usr/include/lldpctl.h
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/lldp-const.h $(1)/usr/include/lldp-const.h
+endef
+
+define Package/lldpd/install
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_DIR) $(1)/etc/lldpd.d
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_DIR) $(1)/usr/lib $(1)/usr/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/lldp{cli,ctl,d} $(1)/usr/sbin/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/liblldpctl.so* $(1)/usr/lib/
+	$(INSTALL_BIN) ./files/lldpd.init $(1)/etc/init.d/lldpd
+	$(INSTALL_DATA) ./files/lldpd.config $(1)/etc/config/lldpd
+ifneq ($(CONFIG_LLDPD_WITH_CDP),y)
+	sed -i -e '/cdp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+endif
+ifneq ($(CONFIG_LLDPD_WITH_FDP),y)
+	sed -i -e '/fdp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+endif
+ifneq ($(CONFIG_LLDPD_WITH_EDP),y)
+	sed -i -e '/edp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+endif
+ifneq ($(CONFIG_LLDPD_WITH_SONMP),y)
+	sed -i -e '/sonmp/d' $(1)/etc/init.d/lldpd $(1)/etc/config/lldpd
+endif
+endef
+
+define Package/lldpd/conffiles
+/etc/config/lldpd
+endef
+
+CONFIGURE_ARGS += \
+	$(if $(CONFIG_LLDPD_WITH_PRIVSEP), \
+	--with-privsep-user=lldp \
+	--with-privsep-group=lldp \
+	--with-privsep-chroot=/var/run/lldp \
+	,--disable-privsep) \
+	--with-readline=no \
+	--with-embedded-libevent=no \
+	--disable-hardening \
+	--without-xml \
+	--sysconfdir=/tmp \
+	$(if $(CONFIG_LLDPD_WITH_CDP),,--disable-cdp) \
+	$(if $(CONFIG_LLDPD_WITH_FDP),,--disable-fdp) \
+	$(if $(CONFIG_LLDPD_WITH_EDP),,--disable-edp) \
+	$(if $(CONFIG_LLDPD_WITH_LLDPMED),,--disable-lldpmed) \
+	$(if $(CONFIG_LLDPD_WITH_DOT1),,--disable-dot1) \
+	$(if $(CONFIG_LLDPD_WITH_DOT3),,--disable-dot3) \
+	$(if $(CONFIG_LLDPD_WITH_CUSTOM),,--disable-custom) \
+	$(if $(CONFIG_LLDPD_WITH_SONMP),,--disable-sonmp) \
+	$(if $(CONFIG_LLDPD_WITH_JSON),--with-json=json-c,--with-json=no)
+
+
+$(eval $(call BuildPackage,lldpd))
diff --git a/package/network/services/lldpd/files/lldpd.config b/package/network/services/lldpd/files/lldpd.config
new file mode 100644
index 0000000000..92ab42116b
--- /dev/null
+++ b/package/network/services/lldpd/files/lldpd.config
@@ -0,0 +1,15 @@
+config lldpd config
+	option enable_cdp 1
+	option enable_fdp 1
+	option enable_sonmp 1
+	option enable_edp 1
+	
+	option lldp_class 4
+	option lldp_location "2:FR:6:Commercial Rd:3:Roseville:19:4"
+
+	# if empty, the distribution description is sent
+	#option lldp_description "Lede System"
+
+	# interfaces to listen on
+	list interface "loopback"
+	list interface "lan"
diff --git a/package/network/services/lldpd/files/lldpd.init b/package/network/services/lldpd/files/lldpd.init
new file mode 100644
index 0000000000..4e9efcae0d
--- /dev/null
+++ b/package/network/services/lldpd/files/lldpd.init
@@ -0,0 +1,121 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2008-2015 OpenWrt.org
+
+START=90
+STOP=01
+
+USE_PROCD=1
+LLDPCLI=/usr/sbin/lldpcli
+LLDPSOCKET=/var/run/lldpd.socket
+LLDPD_CONF=/tmp/lldpd.conf
+LLDPD_CONFS_DIR=/tmp/lldpd.d
+
+find_release_info()
+{
+	[ -s /etc/os-release ] && . /etc/os-release
+	[ -z "$PRETTY_NAME" ] && [ -s /etc/openwrt_version ] && \
+		PRETTY_NAME="$(cat /etc/openwrt_version)"
+
+	echo "${PRETTY_NAME:-Unknown Lede release} @ $(cat /proc/sys/kernel/hostname)"
+}
+
+write_lldpd_conf()
+{
+	. /lib/functions/network.sh
+
+	local lldp_description
+
+	config_load 'lldpd'
+	config_get lldp_description 'config' 'lldp_description' "$(find_release_info)"
+
+	local ifaces
+	config_get ifaces 'config' 'interface'
+
+	local iface ifnames=""
+	for iface in $ifaces; do
+		local ifname=""
+		if network_get_device ifname "$iface" || [ -e "/sys/class/net/$iface" ]; then
+			append ifnames "${ifname:-$iface}" ","
+		fi
+	done
+
+	# Clear out the config file first
+	echo -n > "$LLDPD_CONF"
+	[ -n "$ifnames" ] && echo "configure system interface pattern" "$ifnames" >> "$LLDPD_CONF"
+	[ -n "$lldp_description" ] && echo "configure system description" "\"$lldp_description\"" >> "$LLDPD_CONF"
+
+	# Since lldpd's sysconfdir is /tmp, we'll symlink /etc/lldpd.d to /tmp/$LLDPD_CONFS_DIR
+	[ -e $LLDPD_CONFS_DIR ] || ln -s /etc/lldpd.d $LLDPD_CONFS_DIR
+}
+
+start_service() {
+
+	local enable_cdp
+	local enable_fdp
+	local enable_sonmp
+	local enable_edp
+	local lldp_class
+	local lldp_location
+	local readonly_mode
+
+	config_load 'lldpd'
+	config_get_bool enable_cdp 'config' 'enable_cdp' 0
+	config_get_bool enable_fdp 'config' 'enable_fdp' 0
+	config_get_bool enable_sonmp 'config' 'enable_sonmp' 0
+	config_get_bool enable_edp 'config' 'enable_edp' 0
+	config_get lldp_class 'config' 'lldp_class'
+	config_get lldp_location 'config' 'lldp_location'
+	config_get_bool readonly_mode 'config' 'readonly_mode' 0
+
+	mkdir -p /var/run/lldp
+	chown lldp:lldp /var/run/lldp
+
+	# When lldpd starts, it also loads up what we write in this config file
+	write_lldpd_conf
+
+	procd_open_instance
+	procd_set_param command /usr/sbin/lldpd
+	procd_append_param command -d # don't daemonize, procd will handle that for us
+
+	[ $enable_cdp -gt 0 ] && procd_append_param command '-c'
+	[ $enable_fdp -gt 0 ] && procd_append_param command '-f'
+	[ $enable_sonmp -gt 0 ] && procd_append_param command '-s'
+	[ $enable_edp -gt 0 ] && procd_append_param command '-e'
+	[ $readonly_mode -gt 0 ] && procd_append_param command '-r'
+	[ -n "$lldp_class" ] && procd_append_param command -M "$lldp_class"
+
+	# set auto respawn behavior
+	procd_set_param respawn
+	procd_append_param respawn 3600
+	procd_append_param respawn 5
+	procd_append_param respawn -1
+	procd_close_instance
+}
+
+service_running() {
+	pgrep -x /usr/sbin/lldpd &> /dev/null
+}
+
+reload_service() {
+	running || return 1
+	$LLDPCLI -u $LLDPSOCKET &> /dev/null <<-EOF
+		pause
+		unconfigure lldp custom-tlv
+		unconfigure system interface pattern
+		unconfigure system description
+	EOF
+	# Rewrite lldpd.conf
+	# If something changed it should be included by the lldpcli call
+	write_lldpd_conf
+	$LLDPCLI -u $LLDPSOCKET -c $LLDPD_CONF -c $LLDPD_CONFS_DIR &> /dev/null
+	# Broadcast update over the wire
+	$LLDPCLI -u $LLDPSOCKET &> /dev/null <<-EOF
+		resume
+		update
+	EOF
+	return 0
+}
+
+stop_service() {
+	rm -rf /var/run/lldp $LLDPSOCKET
+}
diff --git a/package/network/services/mdns/Makefile b/package/network/services/mdns/Makefile
new file mode 100644
index 0000000000..319fc80398
--- /dev/null
+++ b/package/network/services/mdns/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mdns
+PKG_VERSION:=2016-05-23
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL=$(LEDE_GIT)/project/mdnsd.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=8a70b2b47dd328f8180e5ecaa7bdc817f574a81b
+PKG_MIRROR_MD5SUM:=f40f67c68ee62bd1967a5d32c3eb5601a7927c7ebd52da27029019c2fe9307d3
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+PKG_LICENSE:=LGPL-2.1
+
+include $(INCLUDE_DIR)/package-seccomp.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/mdns
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=OpenWrt Multicast DNS Daemon
+  DEPENDS:=+libubox +libubus +libblobmsg-json
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+define Package/mdns/conffiles
+/etc/config/mdns
+endef
+
+define Package/mdns/install
+	$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mdns $(1)/usr/sbin/
+	$(INSTALL_BIN) ./files/mdns.init $(1)/etc/init.d/mdns
+	$(INSTALL_CONF) ./files/mdns.config $(1)/etc/config/mdns
+	$(call InstallSeccomp,$(1),./files/mdns.json)
+endef
+
+$(eval $(call BuildPackage,mdns))
diff --git a/package/network/services/mdns/files/mdns.config b/package/network/services/mdns/files/mdns.config
new file mode 100644
index 0000000000..b09eaf5c89
--- /dev/null
+++ b/package/network/services/mdns/files/mdns.config
@@ -0,0 +1,3 @@
+config mdns
+	option jail 1
+	list network lan
diff --git a/package/network/services/mdns/files/mdns.init b/package/network/services/mdns/files/mdns.init
new file mode 100644
index 0000000000..c0f9155c06
--- /dev/null
+++ b/package/network/services/mdns/files/mdns.init
@@ -0,0 +1,54 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2014 OpenWrt.org
+
+. /lib/functions/network.sh
+
+START=80
+
+USE_PROCD=1
+PROG=/usr/sbin/mdns
+IFACES=""
+
+load_ifaces() {
+	local network="$(uci get mdns.@mdns[-1].network)"
+	for n in $network; do
+		local device
+		json_load "$(ifstatus $n)"
+		json_get_var device l3_device
+		echo -n "$device "
+	done
+}
+
+reload_service() {
+	json_init
+	json_add_array interfaces
+	for i in $(load_ifaces); do
+		json_add_string "" "$i"
+	done
+	json_close_array
+
+	ubus call mdns set_config "$(json_dump)"
+}
+
+start_service() {
+	local network="$(uci get mdns.@mdns[-1].network)"
+
+	procd_open_instance
+	procd_set_param command "$PROG"
+	procd_set_param seccomp /etc/seccomp/mdns.json
+	procd_set_param respawn
+	procd_open_trigger
+	procd_add_config_trigger "config.change" "mdns" /etc/init.d/mdns reload
+	for n in $network; do
+		procd_add_interface_trigger "interface.*" $n /etc/init.d/mdns reload	
+	done
+	procd_add_raw_trigger "instance.update" 5000 "/bin/ubus" "call" "mdns" "reload"
+	procd_close_trigger
+	[ "$(uci get mdns.@mdns[-1].jail)" = 1 ] && procd_add_jail mdns ubus log
+	procd_close_instance
+}
+
+service_started() {
+	ubus -t 10 wait_for mdns
+	[ $? = 0 ] && reload_service
+}
diff --git a/package/network/services/mdns/files/mdns.json b/package/network/services/mdns/files/mdns.json
new file mode 100644
index 0000000000..c22ba6f5fb
--- /dev/null
+++ b/package/network/services/mdns/files/mdns.json
@@ -0,0 +1,32 @@
+{
+	"whitelist": [
+		"read",
+		"write",
+		"open",
+		"close",
+		"time",
+		"brk",
+		"ioctl",
+		"uname",
+		"bind",
+		"connect",
+		"getsockname",
+		"recvmsg",
+		"sendmsg",
+		"sendto",
+		"setsockopt",
+		"socket",
+		"poll",
+		"fcntl64",
+		"epoll_create",
+		"epoll_ctl",
+		"epoll_wait",
+		"rt_sigaction",
+		"sigreturn",
+		"rt_sigreturn",
+		"exit_group",
+		"exit",
+		"clock_gettime"
+	],
+	"policy": 1
+}
diff --git a/package/network/services/odhcpd/Makefile b/package/network/services/odhcpd/Makefile
new file mode 100644
index 0000000000..f6ce26c150
--- /dev/null
+++ b/package/network/services/odhcpd/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (C) 2013-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=odhcpd
+PKG_VERSION:=2016-11-21
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL:=git://git.lede-project.org/project/odhcpd.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=5f425ed1e5f92397e27ec4f44820b6ef677b8134
+PKG_MIRROR_MD5SUM:=64ef09adbb88e1a419a689985dbc784c94003b247216d6e188e81b7f2807b032
+
+PKG_MAINTAINER:=Steven Barth <steven@midlink.org>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+CMAKE_OPTIONS += -DUBUS=1
+
+ifneq ($(CONFIG_PACKAGE_odhcpd_ext_cer_id),0)
+  CMAKE_OPTIONS += -DEXT_CER_ID=$(CONFIG_PACKAGE_odhcpd_ext_cer_id)
+endif
+
+
+define Package/odhcpd
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=OpenWrt DHCP/DHCPv6(-PD)/RA Server & Relay
+  DEPENDS:=+libubox +libuci +libubus
+endef
+
+define Package/odhcpd/config
+  config PACKAGE_odhcpd_ext_cer_id
+    int "CER-ID Extension ID (0 = disabled)"
+    depends on PACKAGE_odhcpd
+    default 0
+endef
+
+define Package/odhcpd/description
+ odhcpd is a daemon for serving and relaying IP management protocols to
+ configure clients and downstream routers. It tries to follow the RFC 6204
+ requirements for IPv6 home routers.
+ 
+ odhcpd provides server services for DHCP, RA, stateless and stateful DHCPv6,
+ prefix delegation and can be used to relay RA, DHCPv6 and NDP between routed
+ (non-bridged) interfaces in case no delegated prefixes are available.
+endef
+
+define Package/odhcpd/install
+	$(INSTALL_DIR) $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/odhcpd $(1)/usr/sbin/
+	$(INSTALL_BIN) ./files/odhcpd-update $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/odhcpd.init $(1)/etc/init.d/odhcpd
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_BIN) ./files/odhcpd.defaults $(1)/etc/uci-defaults
+endef
+
+$(eval $(call BuildPackage,odhcpd))
diff --git a/package/network/services/odhcpd/files/odhcpd-update b/package/network/services/odhcpd/files/odhcpd-update
new file mode 100755
index 0000000000..e17cd0bfff
--- /dev/null
+++ b/package/network/services/odhcpd/files/odhcpd-update
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Make dnsmasq reread hostfile
+
+pid=$(pidof dnsmasq)
+[ "$(readlink /proc/$pid/exe)" = "/usr/sbin/dnsmasq" ] && kill -SIGHUP $pid
diff --git a/package/network/services/odhcpd/files/odhcpd.defaults b/package/network/services/odhcpd/files/odhcpd.defaults
new file mode 100644
index 0000000000..d079ec0f80
--- /dev/null
+++ b/package/network/services/odhcpd/files/odhcpd.defaults
@@ -0,0 +1,13 @@
+#!/bin/sh
+uci -q get dhcp.odhcpd && exit 0
+touch /etc/config/dhcp
+
+uci batch <<EOF
+set dhcp.odhcpd=odhcpd
+set dhcp.odhcpd.maindhcp=0
+set dhcp.odhcpd.leasefile=/tmp/hosts/odhcpd
+set dhcp.odhcpd.leasetrigger=/usr/sbin/odhcpd-update
+set dhcp.lan.dhcpv6=server
+set dhcp.lan.ra=server
+commit dhcp
+EOF
diff --git a/package/network/services/odhcpd/files/odhcpd.init b/package/network/services/odhcpd/files/odhcpd.init
new file mode 100644
index 0000000000..bbbec9c232
--- /dev/null
+++ b/package/network/services/odhcpd/files/odhcpd.init
@@ -0,0 +1,22 @@
+#!/bin/sh /etc/rc.common
+
+START=35
+STOP=85
+USE_PROCD=1
+
+start_service() {
+	procd_open_instance
+	procd_set_param command /usr/sbin/odhcpd
+	procd_set_param respawn
+	procd_close_instance
+}
+
+reload_service() {
+	killall -HUP odhcpd
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "dhcp"
+}
+
diff --git a/package/network/services/omcproxy/Makefile b/package/network/services/omcproxy/Makefile
new file mode 100644
index 0000000000..aa1586a1d4
--- /dev/null
+++ b/package/network/services/omcproxy/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=omcproxy
+PKG_VERSION:=2015-08-24
+PKG_RELEASE:=3
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL:=https://github.com/sbyx/omcproxy.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=8de9fa84e018e152e45c342f10b5b5140b63e4b1
+PKG_MIRROR_MD5SUM:=e79dacf493155ebf7e0d9954dd007bb485d48819907bef6be4cda21bab769443
+PKG_MAINTAINER:=Steven Barth <cyrus@openwrt.org>
+PKG_LICENSE:=Apache-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/omcproxy
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libubox +libubus
+  TITLE:=IGMPv3 and MLDv2 Multicast Proxy
+endef
+
+CMAKE_OPTIONS += -DWITH_LIBUBOX=1
+
+define Package/omcproxy/install
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_CONF) ./files/omcproxy.config $(1)/etc/config/omcproxy
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/omcproxy.init $(1)/etc/init.d/omcproxy
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/omcproxy $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,omcproxy))
diff --git a/package/network/services/omcproxy/files/omcproxy.config b/package/network/services/omcproxy/files/omcproxy.config
new file mode 100644
index 0000000000..b0f9bb0672
--- /dev/null
+++ b/package/network/services/omcproxy/files/omcproxy.config
@@ -0,0 +1,9 @@
+config proxy
+	option scope global
+	option uplink wan
+	list downlink lan
+
+config proxy
+	option scope global
+	option uplink wan6
+	list downlink lan
diff --git a/package/network/services/omcproxy/files/omcproxy.init b/package/network/services/omcproxy/files/omcproxy.init
new file mode 100644
index 0000000000..a129792087
--- /dev/null
+++ b/package/network/services/omcproxy/files/omcproxy.init
@@ -0,0 +1,143 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010-2014 OpenWrt.org
+
+START=99
+USE_PROCD=1
+PROG=/usr/sbin/omcproxy
+
+# Uncomment to enable verbosity 
+#OPTIONS="-v" 
+PROXIES=""
+
+
+omcproxy_add_proxy() {
+	local uplink downlink scope proxy
+	config_get uplink $1 uplink
+	config_get downlink $1 downlink
+	config_get scope $1 scope
+
+	proxy=""
+
+	network_get_device updev $uplink
+	[ -n "$updev" ] || return 0
+
+	for network in $downlink; do
+		network_get_device downdev $network
+		[ -n "$downdev" ] && proxy="$proxy,$downdev"
+
+		# Disable in-kernel querier while ours is active
+		[ -f /sys/class/net/$downdev/bridge/multicast_querier ] && \
+			echo 0 > /sys/class/net/$downdev/bridge/multicast_querier
+	done
+
+	[ -n "$proxy" ] || return 0
+	[ -n "$scope" ] && proxy="$proxy,scope=$scope"
+
+	PROXIES="$PROXIES $updev$proxy"
+
+}
+
+omcproxy_add_trigger() {
+	local uplink downlink
+	config_get uplink $1 uplink
+	config_get downlink $1 downlink
+
+	for network in $uplink $downlink; do
+		procd_add_interface_trigger "interface.*" $network /etc/init.d/omcproxy restart
+	done
+}
+
+omcproxy_add_firewall() {
+	config_get uplink $1 uplink
+	config_get downlink $1 downlink
+
+	upzone=$(fw3 network $uplink)
+	[ -n "$upzone" ] || return 0
+
+	json_add_object ""
+	json_add_string type rule
+	json_add_string src "$upzone"
+	json_add_string proto igmp
+	json_add_string target ACCEPT
+	json_close_object
+
+	json_add_object ""
+	json_add_string type rule
+	json_add_string family ipv6
+	json_add_string src "$upzone"
+	json_add_string proto icmp
+	json_add_string src_ip fe80::/10
+	json_add_array icmp_type
+		json_add_string "" 130/0
+		json_add_string "" 131/0
+		json_add_string "" 132/0
+		json_add_string "" 143/0
+	json_close_array
+	json_add_string target ACCEPT
+	json_close_object
+
+	for network in $downlink; do
+		downzone=$(fw3 network $network)
+		[ -n "$downzone" ] || continue
+
+		json_add_object ""
+		json_add_string type rule
+		json_add_string src "$upzone"
+		json_add_string dest "$downzone"
+		json_add_string family ipv4
+		json_add_string proto any
+		json_add_string dest_ip "224.0.0.0/4"
+		json_add_string target ACCEPT
+		json_close_object
+
+		json_add_object ""
+		json_add_string type rule
+		json_add_string src "$upzone"
+		json_add_string dest "$downzone"
+		json_add_string family ipv6
+		json_add_string proto any
+		json_add_string dest_ip "ff00::/8"
+		json_add_string target ACCEPT
+		json_close_object
+	done
+}
+
+service_triggers() {
+	procd_add_reload_trigger "omcproxy"
+}
+
+start_service() {
+	include /lib/functions
+
+	config_load omcproxy
+	config_foreach omcproxy_add_proxy proxy
+
+	[ -n "$PROXIES" ] || return 0
+
+	procd_open_instance
+	procd_set_param command $PROG
+	[ -n "$OPTIONS" ] && procd_append_param command $OPTIONS
+	procd_append_param command $PROXIES
+	procd_set_param respawn
+
+	procd_open_trigger
+	config_foreach omcproxy_add_trigger proxy
+	procd_close_trigger
+
+	procd_open_data
+
+	json_add_array firewall
+	config_foreach omcproxy_add_firewall proxy
+	json_close_array
+
+	procd_close_data
+
+	procd_close_instance
+
+	# Increase maximum IPv4 group memberships per socket
+	echo 128 > /proc/sys/net/ipv4/igmp_max_memberships
+}
+
+service_started() {
+	procd_set_config_changed firewall
+}
diff --git a/package/network/services/openvpn-easy-rsa/Makefile b/package/network/services/openvpn-easy-rsa/Makefile
new file mode 100644
index 0000000000..d0ef3ef555
--- /dev/null
+++ b/package/network/services/openvpn-easy-rsa/Makefile
@@ -0,0 +1,60 @@
+#
+# Copyright (C) 2010-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=openvpn-easy-rsa
+
+PKG_REV:=ff5bfd1dd8e548cb24d302742af3894f893ef92f
+PKG_VERSION:=2013-01-30
+PKG_RELEASE=2
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/OpenVPN/easy-rsa.git
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_REV).tar.xz
+PKG_MIRROR_MD5SUM:=cdb0d3f1fb828e4026b6fb297303d5ccb9bc4e1faccbb6a7687518655b178875
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/openvpn-easy-rsa
+  TITLE:=Simple shell scripts to manage a Certificate Authority
+  SECTION:=net
+  CATEGORY:=Network
+  URL:=http://openvpn.net
+  SUBMENU:=VPN
+  DEPENDS:=+openssl-util
+endef
+
+define Package/openvpn-easy-rsa/conffiles
+/etc/easy-rsa/keys/serial
+/etc/easy-rsa/keys/index.txt
+/etc/easy-rsa/vars
+endef
+
+define Build/Configure
+
+endef
+
+define Build/Compile
+
+endef
+
+define Package/openvpn-easy-rsa/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_BUILD_DIR)/easy-rsa/2.0/{build-*,clean-all,inherit-inter,list-crl,pkitool,revoke-full,sign-req,whichopensslcnf} $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/etc/easy-rsa
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/easy-rsa/2.0/openssl-1.0.0.cnf $(1)/etc/easy-rsa/openssl-1.0.0.cnf
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/easy-rsa/2.0/vars $(1)/etc/easy-rsa/vars
+	$(INSTALL_DIR) $(1)/etc/easy-rsa/keys
+	$(INSTALL_DATA) files/easy-rsa.index $(1)/etc/easy-rsa/keys/index.txt
+	$(INSTALL_DATA) files/easy-rsa.serial $(1)/etc/easy-rsa/keys/serial
+endef
+
+$(eval $(call BuildPackage,openvpn-easy-rsa))
diff --git a/package/network/services/openvpn-easy-rsa/files/easy-rsa.index b/package/network/services/openvpn-easy-rsa/files/easy-rsa.index
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/package/network/services/openvpn-easy-rsa/files/easy-rsa.serial b/package/network/services/openvpn-easy-rsa/files/easy-rsa.serial
new file mode 100644
index 0000000000..8a0f05e166
--- /dev/null
+++ b/package/network/services/openvpn-easy-rsa/files/easy-rsa.serial
@@ -0,0 +1 @@
+01
diff --git a/package/network/services/openvpn-easy-rsa/patches/100-run-ootb.patch b/package/network/services/openvpn-easy-rsa/patches/100-run-ootb.patch
new file mode 100644
index 0000000000..4c1b889e39
--- /dev/null
+++ b/package/network/services/openvpn-easy-rsa/patches/100-run-ootb.patch
@@ -0,0 +1,152 @@
+--- a/easy-rsa/2.0/build-ca
++++ b/easy-rsa/2.0/build-ca
+@@ -5,4 +5,4 @@
+ #
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --initca $*
++"/usr/sbin/pkitool" --interact --initca $*
+--- a/easy-rsa/2.0/build-dh
++++ b/easy-rsa/2.0/build-dh
+@@ -1,5 +1,7 @@
+ #!/bin/sh
+ 
++. /etc/easy-rsa/vars
++
+ # Build Diffie-Hellman parameters for the server side
+ # of an SSL/TLS connection.
+ 
+--- a/easy-rsa/2.0/build-inter
++++ b/easy-rsa/2.0/build-inter
+@@ -4,4 +4,4 @@
+ # root certificate.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --inter $*
++"/usr/sbin/pkitool" --interact --inter $*
+--- a/easy-rsa/2.0/build-key
++++ b/easy-rsa/2.0/build-key
+@@ -4,4 +4,4 @@
+ # root certificate.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact $*
++"/usr/sbin/pkitool" --interact $*
+--- a/easy-rsa/2.0/build-key-pass
++++ b/easy-rsa/2.0/build-key-pass
+@@ -4,4 +4,4 @@
+ # with a password.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --pass $*
++"/usr/sbin/pkitool" --interact --pass $*
+--- a/easy-rsa/2.0/build-key-pkcs12
++++ b/easy-rsa/2.0/build-key-pkcs12
+@@ -5,4 +5,4 @@
+ # the CA certificate as well.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --pkcs12 $*
++"/usr/sbin/pkitool" --interact --pkcs12 $*
+--- a/easy-rsa/2.0/build-key-server
++++ b/easy-rsa/2.0/build-key-server
+@@ -7,4 +7,4 @@
+ # extension in the openssl.cnf file.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --server $*
++"/usr/sbin/pkitool" --interact --server $*
+--- a/easy-rsa/2.0/build-req
++++ b/easy-rsa/2.0/build-req
+@@ -4,4 +4,4 @@
+ # when your root certificate and key is not available locally.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --csr $*
++"/usr/sbin/pkitool" --interact --csr $*
+--- a/easy-rsa/2.0/build-req-pass
++++ b/easy-rsa/2.0/build-req-pass
+@@ -4,4 +4,4 @@
+ # with a password.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --csr --pass $*
++"/usr/sbin/pkitool" --interact --csr --pass $*
+--- a/easy-rsa/2.0/clean-all
++++ b/easy-rsa/2.0/clean-all
+@@ -1,5 +1,7 @@
+ #!/bin/sh
+ 
++. /etc/easy-rsa/vars
++
+ # Initialize the $KEY_DIR directory.
+ # Note that this script does a
+ # rm -rf on $KEY_DIR so be careful!
+--- a/easy-rsa/2.0/inherit-inter
++++ b/easy-rsa/2.0/inherit-inter
+@@ -1,5 +1,7 @@
+ #!/bin/sh
+ 
++. /etc/easy-rsa/vars
++
+ # Build a new PKI which is rooted on an intermediate certificate generated
+ # by ./build-inter or ./pkitool --inter from a parent PKI.  The new PKI should
+ # have independent vars settings, and must use a different KEY_DIR directory
+--- a/easy-rsa/2.0/list-crl
++++ b/easy-rsa/2.0/list-crl
+@@ -1,5 +1,7 @@
+ #!/bin/sh
+ 
++. /etc/easy-rsa/vars
++
+ # list revoked certificates
+ 
+ CRL="${1:-crl.pem}"
+--- a/easy-rsa/2.0/pkitool
++++ b/easy-rsa/2.0/pkitool
+@@ -1,5 +1,7 @@
+ #!/bin/sh
+ 
++. /etc/easy-rsa/vars
++
+ #  OpenVPN -- An application to securely tunnel IP networks
+ #             over a single TCP/UDP port, with support for SSL/TLS-based
+ #             session authentication and key exchange,
+--- a/easy-rsa/2.0/revoke-full
++++ b/easy-rsa/2.0/revoke-full
+@@ -1,5 +1,7 @@
+ #!/bin/sh
+ 
++. /etc/easy-rsa/vars
++
+ # revoke a certificate, regenerate CRL,
+ # and verify revocation
+ 
+--- a/easy-rsa/2.0/sign-req
++++ b/easy-rsa/2.0/sign-req
+@@ -4,4 +4,4 @@
+ # with a local root certificate and key.
+ 
+ export EASY_RSA="${EASY_RSA:-.}"
+-"$EASY_RSA/pkitool" --interact --sign $*
++"/usr/sbin/pkitool" --interact --sign $*
+--- a/easy-rsa/2.0/vars
++++ b/easy-rsa/2.0/vars
+@@ -12,7 +12,7 @@
+ # This variable should point to
+ # the top level of the easy-rsa
+ # tree.
+-export EASY_RSA="`pwd`"
++export EASY_RSA="/etc/easy-rsa"
+ 
+ #
+ # This variable should point to
+@@ -26,7 +26,7 @@
+ # This variable should point to
+ # the openssl.cnf file included
+ # with easy-rsa.
+-export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA`
++export KEY_CONFIG=`/usr/sbin/whichopensslcnf $EASY_RSA`
+ 
+ # Edit this variable to point to
+ # your soon-to-be-created key
diff --git a/package/network/services/openvpn/Config-nossl.in b/package/network/services/openvpn/Config-nossl.in
new file mode 100644
index 0000000000..3eaa228882
--- /dev/null
+++ b/package/network/services/openvpn/Config-nossl.in
@@ -0,0 +1,54 @@
+if PACKAGE_openvpn-nossl
+
+config OPENVPN_nossl_ENABLE_LZO
+	bool "Enable LZO compression support"
+	default y
+
+config OPENVPN_nossl_ENABLE_SERVER
+	bool "Enable server support (otherwise only client mode is support)"
+	default y
+
+config OPENVPN_nossl_ENABLE_MANAGEMENT
+	bool "Enable management server support"
+	default n
+
+config OPENVPN_nossl_ENABLE_HTTP
+	bool "Enable HTTP proxy support"
+	default y
+
+config OPENVPN_nossl_ENABLE_SOCKS
+	bool "Enable SOCKS proxy support"
+	default y
+
+config OPENVPN_nossl_ENABLE_FRAGMENT
+	bool "Enable internal fragmentation support (--fragment)"
+	default y
+
+config OPENVPN_nossl_ENABLE_MULTIHOME
+	bool "Enable multi-homed UDP server support (--multihome)"
+	default y
+
+config OPENVPN_nossl_ENABLE_PORT_SHARE
+	bool "Enable TCP server port-share support (--port-share)"
+	default y
+
+config OPENVPN_nossl_ENABLE_DEF_AUTH
+	bool "Enable deferred authentication"
+	default y
+
+config OPENVPN_nossl_ENABLE_PF
+	bool "Enable internal packet filter"
+	default y
+
+config OPENVPN_nossl_ENABLE_IPROUTE2
+	bool "Enable support for iproute2"
+	default n
+
+config OPENVPN_nossl_ENABLE_SMALL
+	bool "Enable size optimization"
+	default y
+	help
+	  enable smaller executable size (disable OCC, usage
+	  message, and verb 4 parm list)
+
+endif
diff --git a/package/network/services/openvpn/Config-openssl.in b/package/network/services/openvpn/Config-openssl.in
new file mode 100644
index 0000000000..ac4c774b03
--- /dev/null
+++ b/package/network/services/openvpn/Config-openssl.in
@@ -0,0 +1,66 @@
+if PACKAGE_openvpn-openssl
+
+config OPENVPN_openssl_ENABLE_LZO
+	bool "Enable LZO compression support"
+	default y
+
+config OPENVPN_openssl_ENABLE_X509_ALT_USERNAME
+	bool "Enable the --x509-username-field feature"
+	default n
+
+config OPENVPN_openssl_ENABLE_SERVER
+	bool "Enable server support (otherwise only client mode is support)"
+	default y
+
+#config OPENVPN_openssl_ENABLE_EUREPHIA
+#	bool "Enable support for the eurephia plug-in"
+#	default n
+
+config OPENVPN_openssl_ENABLE_MANAGEMENT
+	bool "Enable management server support"
+	default n
+
+#config OPENVPN_openssl_ENABLE_PKCS11
+#	bool "Enable pkcs11 support"
+#	default n
+
+config OPENVPN_openssl_ENABLE_HTTP
+	bool "Enable HTTP proxy support"
+	default y
+
+config OPENVPN_openssl_ENABLE_SOCKS
+	bool "Enable SOCKS proxy support"
+	default y
+
+config OPENVPN_openssl_ENABLE_FRAGMENT
+	bool "Enable internal fragmentation support (--fragment)"
+	default y
+
+config OPENVPN_openssl_ENABLE_MULTIHOME
+	bool "Enable multi-homed UDP server support (--multihome)"
+	default y
+
+config OPENVPN_openssl_ENABLE_PORT_SHARE
+	bool "Enable TCP server port-share support (--port-share)"
+	default y
+
+config OPENVPN_openssl_ENABLE_DEF_AUTH
+	bool "Enable deferred authentication"
+	default y
+
+config OPENVPN_openssl_ENABLE_PF
+	bool "Enable internal packet filter"
+	default y
+
+config OPENVPN_openssl_ENABLE_IPROUTE2
+	bool "Enable support for iproute2"
+	default n
+
+config OPENVPN_openssl_ENABLE_SMALL
+	bool "Enable size optimization"
+	default y
+	help
+	  enable smaller executable size (disable OCC, usage
+	  message, and verb 4 parm list)
+
+endif
diff --git a/package/network/services/openvpn/Config-polarssl.in b/package/network/services/openvpn/Config-polarssl.in
new file mode 100644
index 0000000000..26692ce04d
--- /dev/null
+++ b/package/network/services/openvpn/Config-polarssl.in
@@ -0,0 +1,66 @@
+if PACKAGE_openvpn-polarssl
+
+config OPENVPN_polarssl_ENABLE_LZO
+	bool "Enable LZO compression support"
+	default y
+
+config OPENVPN_polarssl_ENABLE_X509_ALT_USERNAME
+	bool "Enable the --x509-username-field feature"
+	default n
+
+config OPENVPN_polarssl_ENABLE_SERVER
+	bool "Enable server support (otherwise only client mode is support)"
+	default y
+
+#config OPENVPN_polarssl_ENABLE_EUREPHIA
+#	bool "Enable support for the eurephia plug-in"
+#	default n
+
+config OPENVPN_polarssl_ENABLE_MANAGEMENT
+	bool "Enable management server support"
+	default n
+
+#config OPENVPN_polarssl_ENABLE_PKCS11
+#	bool "Enable pkcs11 support"
+#	default n
+
+config OPENVPN_polarssl_ENABLE_HTTP
+	bool "Enable HTTP proxy support"
+	default y
+
+config OPENVPN_polarssl_ENABLE_SOCKS
+	bool "Enable SOCKS proxy support"
+	default y
+
+config OPENVPN_polarssl_ENABLE_FRAGMENT
+	bool "Enable internal fragmentation support (--fragment)"
+	default y
+
+config OPENVPN_polarssl_ENABLE_MULTIHOME
+	bool "Enable multi-homed UDP server support (--multihome)"
+	default y
+
+config OPENVPN_polarssl_ENABLE_PORT_SHARE
+	bool "Enable TCP server port-share support (--port-share)"
+	default y
+
+config OPENVPN_polarssl_ENABLE_DEF_AUTH
+	bool "Enable deferred authentication"
+	default y
+
+config OPENVPN_polarssl_ENABLE_PF
+	bool "Enable internal packet filter"
+	default y
+
+config OPENVPN_polarssl_ENABLE_IPROUTE2
+	bool "Enable support for iproute2"
+	default n
+
+config OPENVPN_polarssl_ENABLE_SMALL
+	bool "Enable size optimization"
+	default y
+	help
+	  enable smaller executable size (disable OCC, usage
+	  message, and verb 4 parm list)
+
+endif
diff --git a/package/network/services/openvpn/Makefile b/package/network/services/openvpn/Makefile
new file mode 100644
index 0000000000..05f56ad691
--- /dev/null
+++ b/package/network/services/openvpn/Makefile
@@ -0,0 +1,123 @@
+#
+# Copyright (C) 2010-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=openvpn
+
+PKG_VERSION:=2.3.13
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL:=http://swupdate.openvpn.net/community/releases
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MD5SUM:=9cde0c8000fd32d5275adb55f8bb1d8ba429ff3de35f60a36e81f3859b7537e0
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_INSTALL:=1
+PKG_FIXUP:=autoreconf
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/openvpn/Default
+  TITLE:=Open source VPN solution using $(2)
+  SECTION:=net
+  CATEGORY:=Network
+  URL:=http://openvpn.net
+  SUBMENU:=VPN
+  MENU:=1
+  DEPENDS:=+kmod-tun +OPENVPN_$(1)_ENABLE_LZO:liblzo +OPENVPN_$(1)_ENABLE_IPROUTE2:ip $(3)
+  VARIANT:=$(1)
+  MAINTAINER:=Mirko Vogt <mirko@openwrt.org>
+endef
+
+Package/openvpn-openssl=$(call Package/openvpn/Default,openssl,OpenSSL,+libopenssl)
+Package/openvpn-polarssl=$(call Package/openvpn/Default,polarssl,PolarSSL,+libpolarssl)
+Package/openvpn-nossl=$(call Package/openvpn/Default,nossl,plaintext (no SSL))
+
+define Package/openvpn/config/Default
+	source "$(SOURCE)/Config-$(1).in"
+endef
+
+Package/openvpn-openssl/config=$(call Package/openvpn/config/Default,openssl)
+Package/openvpn-polarssl/config=$(call Package/openvpn/config/Default,polarssl)
+Package/openvpn-nossl/config=$(call Package/openvpn/config/Default,nossl)
+
+ifeq ($(BUILD_VARIANT),polarssl)
+CONFIG_OPENVPN_POLARSSL:=y
+endif
+ifeq ($(BUILD_VARIANT),openssl)
+CONFIG_OPENVPN_OPENSSL:=y
+endif
+ifeq ($(BUILD_VARIANT),nossl)
+CONFIG_OPENVPN_NOSSL:=y
+endif
+
+CONFIGURE_VARS += \
+	IFCONFIG=/sbin/ifconfig \
+	ROUTE=/sbin/route \
+	IPROUTE=/sbin/ip \
+	NETSTAT=/sbin/netstat
+
+define Build/Configure
+	$(call Build/Configure/Default, \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_SMALL),--enable-small) \
+		--disable-selinux \
+		--disable-systemd \
+		--disable-plugins \
+		--disable-debug \
+		--disable-pkcs11 \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_LZO),--enable,--disable)-lzo \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_X509_ALT_USERNAME),enable,disable-x509-alt-username)-ssl \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_SERVER),--enable,--disable)-server \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_MANAGEMENT),--enable,--disable)-management \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_SOCKS),--enable,--disable)-socks \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_HTTP),--enable,--disable)-http-proxy \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_FRAGMENT),--enable,--disable)-fragment \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_MULTIHOME),--enable,--disable)-multihome \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_IPROUTE2),--enable,--disable)-iproute2 \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_DEF_AUTH),--enable,--disable)-def-auth \
+		$(if $(CONFIG_OPENVPN_$(BUILD_VARIANT)_ENABLE_PF),--enable,--disable)-pf \
+		$(if $(CONFIG_OPENVPN_NOSSL),--disable-ssl --disable-crypto,--enable-ssl --enable-crypto) \
+		$(if $(CONFIG_OPENVPN_OPENSSL),--with-crypto-library=openssl) \
+		$(if $(CONFIG_OPENVPN_POLARSSL),--with-crypto-library=polarssl) \
+	)
+endef
+
+define Package/openvpn-$(BUILD_VARIANT)/conffiles
+/etc/config/openvpn
+endef
+
+define Package/openvpn-$(BUILD_VARIANT)/install
+	$(INSTALL_DIR) \
+		$(1)/usr/sbin \
+		$(1)/etc/init.d \
+		$(1)/etc/config \
+		$(1)/etc/openvpn \
+		$(1)/lib/upgrade/keep.d
+
+	$(INSTALL_BIN) \
+		$(PKG_INSTALL_DIR)/usr/sbin/openvpn \
+		$(1)/usr/sbin/
+
+	$(INSTALL_BIN) \
+		files/openvpn.init \
+		$(1)/etc/init.d/openvpn
+
+	$(INSTALL_CONF) files/openvpn.config \
+		$(1)/etc/config/openvpn
+
+	$(INSTALL_DATA) \
+		files/openvpn.upgrade \
+		$(1)/lib/upgrade/keep.d/openvpn
+endef
+
+$(eval $(call BuildPackage,openvpn-openssl))
+$(eval $(call BuildPackage,openvpn-polarssl))
+$(eval $(call BuildPackage,openvpn-nossl))
diff --git a/package/network/services/openvpn/files/openvpn.config b/package/network/services/openvpn/files/openvpn.config
new file mode 100644
index 0000000000..3e053c36a9
--- /dev/null
+++ b/package/network/services/openvpn/files/openvpn.config
@@ -0,0 +1,400 @@
+package openvpn
+
+#################################################
+# Sample to include a custom config file.       #
+#################################################
+
+config openvpn custom_config
+
+	# Set to 1 to enable this instance:
+	option enabled 0
+
+	# Include OpenVPN configuration
+	option config /etc/openvpn/my-vpn.conf
+
+
+#################################################
+# Sample OpenVPN 2.0 uci config for             #
+# multi-client server.                          #
+#################################################
+
+config openvpn sample_server
+
+	# Set to 1 to enable this instance:
+	option enabled 0
+
+	# Which local IP address should OpenVPN
+	# listen on? (optional)
+#	option local 0.0.0.0
+
+	# Which TCP/UDP port should OpenVPN listen on?
+	# If you want to run multiple OpenVPN instances
+	# on the same machine, use a different port
+	# number for each one.  You will need to
+	# open up this port on your firewall.
+	option port 1194
+
+	# TCP or UDP server?
+#	option proto tcp
+	option proto udp
+
+	# "dev tun" will create a routed IP tunnel,
+	# "dev tap" will create an ethernet tunnel.
+	# Use "dev tap0" if you are ethernet bridging
+	# and have precreated a tap0 virtual interface
+	# and bridged it with your ethernet interface.
+	# If you want to control access policies
+	# over the VPN, you must create firewall
+	# rules for the the TUN/TAP interface.
+	# On non-Windows systems, you can give
+	# an explicit unit number, such as tun0.
+	# On Windows, use "dev-node" for this.
+	# On most systems, the VPN will not function
+	# unless you partially or fully disable
+	# the firewall for the TUN/TAP interface.
+#	option dev tap
+	option dev tun
+
+	# SSL/TLS root certificate (ca), certificate
+	# (cert), and private key (key).  Each client
+	# and the server must have their own cert and
+	# key file.  The server and all clients will
+	# use the same ca file.
+	#
+	# See the "easy-rsa" directory for a series
+	# of scripts for generating RSA certificates
+	# and private keys.  Remember to use
+	# a unique Common Name for the server
+	# and each of the client certificates.
+	#
+	# Any X509 key management system can be used.
+	# OpenVPN can also use a PKCS #12 formatted key file
+	# (see "pkcs12" directive in man page).
+	option ca /etc/openvpn/ca.crt
+	option cert /etc/openvpn/server.crt
+	# This file should be kept secret:
+	option key /etc/openvpn/server.key
+
+	# Diffie hellman parameters.
+	# Generate your own with:
+	#   openssl dhparam -out dh1024.pem 1024
+	# Substitute 2048 for 1024 if you are using
+	# 2048 bit keys.
+	option dh /etc/openvpn/dh1024.pem
+
+	# Configure server mode and supply a VPN subnet
+	# for OpenVPN to draw client addresses from.
+	# The server will take 10.8.0.1 for itself,
+	# the rest will be made available to clients.
+	# Each client will be able to reach the server
+	# on 10.8.0.1. Comment this line out if you are
+	# ethernet bridging. See the man page for more info.
+	option server "10.8.0.0 255.255.255.0"
+
+	# Maintain a record of client <-> virtual IP address
+	# associations in this file.  If OpenVPN goes down or
+	# is restarted, reconnecting clients can be assigned
+	# the same virtual IP address from the pool that was
+	# previously assigned.
+	option ifconfig_pool_persist /tmp/ipp.txt
+
+	# Configure server mode for ethernet bridging.
+	# You must first use your OS's bridging capability
+	# to bridge the TAP interface with the ethernet
+	# NIC interface.  Then you must manually set the
+	# IP/netmask on the bridge interface, here we
+	# assume 10.8.0.4/255.255.255.0.  Finally we
+	# must set aside an IP range in this subnet
+	# (start=10.8.0.50 end=10.8.0.100) to allocate
+	# to connecting clients.  Leave this line commented
+	# out unless you are ethernet bridging.
+#	option server_bridge "10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100"
+
+	# Push routes to the client to allow it
+	# to reach other private subnets behind
+	# the server.  Remember that these
+	# private subnets will also need
+	# to know to route the OpenVPN client
+	# address pool (10.8.0.0/255.255.255.0)
+	# back to the OpenVPN server.
+#	list push "route 192.168.10.0 255.255.255.0"
+#	list push "route 192.168.20.0 255.255.255.0"
+
+	# To assign specific IP addresses to specific
+	# clients or if a connecting client has a private
+	# subnet behind it that should also have VPN access,
+	# use the subdirectory "ccd" for client-specific
+	# configuration files (see man page for more info).
+
+	# EXAMPLE: Suppose the client
+	# having the certificate common name "Thelonious"
+	# also has a small subnet behind his connecting
+	# machine, such as 192.168.40.128/255.255.255.248.
+	# First, uncomment out these lines:
+#	option client_config_dir /etc/openvpn/ccd
+#	list route "192.168.40.128 255.255.255.248"
+	# Then create a file ccd/Thelonious with this line:
+	#   iroute 192.168.40.128 255.255.255.248
+	# This will allow Thelonious' private subnet to
+	# access the VPN.  This example will only work
+	# if you are routing, not bridging, i.e. you are
+	# using "dev tun" and "server" directives.
+
+	# EXAMPLE: Suppose you want to give
+	# Thelonious a fixed VPN IP address of 10.9.0.1.
+	# First uncomment out these lines:
+#	option client_config_dir /etc/openvpn/ccd
+#	list route "10.9.0.0 255.255.255.252"
+#	list route "192.168.100.0 255.255.255.0"
+	# Then add this line to ccd/Thelonious:
+	#   ifconfig-push "10.9.0.1 10.9.0.2"
+
+	# Suppose that you want to enable different
+	# firewall access policies for different groups
+	# of clients.  There are two methods:
+	# (1) Run multiple OpenVPN daemons, one for each
+	#     group, and firewall the TUN/TAP interface
+	#     for each group/daemon appropriately.
+	# (2) (Advanced) Create a script to dynamically
+	#     modify the firewall in response to access
+	#     from different clients.  See man
+	#     page for more info on learn-address script.
+#	option learn_address /etc/openvpn/script
+
+	# If enabled, this directive will configure
+	# all clients to redirect their default
+	# network gateway through the VPN, causing
+	# all IP traffic such as web browsing and
+	# and DNS lookups to go through the VPN
+	# (The OpenVPN server machine may need to NAT
+	# the TUN/TAP interface to the internet in
+	# order for this to work properly).
+	# CAVEAT: May break client's network config if
+	# client's local DHCP server packets get routed
+	# through the tunnel.  Solution: make sure
+	# client's local DHCP server is reachable via
+	# a more specific route than the default route
+	# of 0.0.0.0/0.0.0.0.
+#	list push "redirect-gateway"
+
+	# Certain Windows-specific network settings
+	# can be pushed to clients, such as DNS
+	# or WINS server addresses.  CAVEAT:
+	# http://openvpn.net/faq.html#dhcpcaveats
+#	list push "dhcp-option DNS 10.8.0.1"
+#	list push "dhcp-option WINS 10.8.0.1"
+
+	# Uncomment this directive to allow different
+	# clients to be able to "see" each other.
+	# By default, clients will only see the server.
+	# To force clients to only see the server, you
+	# will also need to appropriately firewall the
+	# server's TUN/TAP interface.
+#	option client_to_client 1
+
+	# Uncomment this directive if multiple clients
+	# might connect with the same certificate/key
+	# files or common names.  This is recommended
+	# only for testing purposes.  For production use,
+	# each client should have its own certificate/key
+	# pair.
+	#
+	# IF YOU HAVE NOT GENERATED INDIVIDUAL
+	# CERTIFICATE/KEY PAIRS FOR EACH CLIENT,
+	# EACH HAVING ITS OWN UNIQUE "COMMON NAME",
+	# UNCOMMENT THIS LINE OUT.
+#	option duplicate_cn 1
+
+	# The keepalive directive causes ping-like
+	# messages to be sent back and forth over
+	# the link so that each side knows when
+	# the other side has gone down.
+	# Ping every 10 seconds, assume that remote
+	# peer is down if no ping received during
+	# a 120 second time period.
+	option keepalive "10 120"
+
+	# For extra security beyond that provided
+	# by SSL/TLS, create an "HMAC firewall"
+	# to help block DoS attacks and UDP port flooding.
+	#
+	# Generate with:
+	#   openvpn --genkey --secret ta.key
+	#
+	# The server and each client must have
+	# a copy of this key.
+	# The second parameter should be '0'
+	# on the server and '1' on the clients.
+	# This file is secret:
+#	option tls_auth "/etc/openvpn/ta.key 0"
+
+	# Select a cryptographic cipher.
+	# This config item must be copied to
+	# the client config file as well.
+	# Blowfish (default):
+#	option cipher BF-CBC
+	# AES:
+#	option cipher AES-128-CBC
+	# Triple-DES:
+#	option cipher DES-EDE3-CBC
+
+	# Enable compression on the VPN link.
+	# If you enable it here, you must also
+	# enable it in the client config file.
+	option comp_lzo yes
+
+	# The maximum number of concurrently connected
+	# clients we want to allow.
+#	option max_clients 100
+
+	# The persist options will try to avoid
+	# accessing certain resources on restart
+	# that may no longer be accessible because
+	# of the privilege downgrade.
+	option persist_key 1
+	option persist_tun 1
+	option user nobody
+
+	# Output a short status file showing
+	# current connections, truncated
+	# and rewritten every minute.
+	option status /tmp/openvpn-status.log
+
+	# By default, log messages will go to the syslog (or
+	# on Windows, if running as a service, they will go to
+	# the "\Program Files\OpenVPN\log" directory).
+	# Use log or log-append to override this default.
+	# "log" will truncate the log file on OpenVPN startup,
+	# while "log-append" will append to it.  Use one
+	# or the other (but not both).
+#	option log         /tmp/openvpn.log
+#	option log_append  /tmp/openvpn.log
+
+	# Set the appropriate level of log
+	# file verbosity.
+	#
+	# 0 is silent, except for fatal errors
+	# 4 is reasonable for general usage
+	# 5 and 6 can help to debug connection problems
+	# 9 is extremely verbose
+	option verb 3
+
+	# Silence repeating messages.  At most 20
+	# sequential messages of the same message
+	# category will be output to the log.
+#	option mute 20
+
+
+##############################################
+# Sample client-side OpenVPN 2.0 uci config  #
+# for connecting to multi-client server.     #
+##############################################
+
+config openvpn sample_client
+
+	# Set to 1 to enable this instance:
+	option enabled 0
+
+	# Specify that we are a client and that we
+	# will be pulling certain config file directives
+	# from the server.
+	option client 1
+
+	# Use the same setting as you are using on
+	# the server.
+	# On most systems, the VPN will not function
+	# unless you partially or fully disable
+	# the firewall for the TUN/TAP interface.
+#	option dev tap
+	option dev tun
+
+	# Are we connecting to a TCP or
+	# UDP server?  Use the same setting as
+	# on the server.
+#	option proto tcp
+	option proto udp
+
+	# The hostname/IP and port of the server.
+	# You can have multiple remote entries
+	# to load balance between the servers.
+	list remote "my_server_1 1194"
+#	list remote "my_server_2 1194"
+
+	# Choose a random host from the remote
+	# list for load_balancing.  Otherwise
+	# try hosts in the order specified.
+#	option remote_random 1
+
+	# Keep trying indefinitely to resolve the
+	# host name of the OpenVPN server.  Very useful
+	# on machines which are not permanently connected
+	# to the internet such as laptops.
+	option resolv_retry infinite
+
+	# Most clients don't need to bind to
+	# a specific local port number.
+	option nobind 1
+
+	# Try to preserve some state across restarts.
+	option persist_key 1
+	option persist_tun 1
+	option user nobody
+
+	# If you are connecting through an
+	# HTTP proxy to reach the actual OpenVPN
+	# server, put the proxy server/IP and
+	# port number here.  See the man page
+	# if your proxy server requires
+	# authentication.
+	# retry on connection failures:
+#	option http_proxy_retry 1
+	# specify http proxy address and port:
+#	option http_proxy "192.168.1.100 8080"
+
+	# Wireless networks often produce a lot
+	# of duplicate packets.  Set this flag
+	# to silence duplicate packet warnings.
+#	option mute_replay_warnings 1
+
+	# SSL/TLS parms.
+	# See the server config file for more
+	# description.  It's best to use
+	# a separate .crt/.key file pair
+	# for each client.  A single ca
+	# file can be used for all clients.
+	option ca /etc/openvpn/ca.crt
+	option cert /etc/openvpn/client.crt
+	option key /etc/openvpn/client.key
+
+	# Verify server certificate by checking
+	# that the certicate has the nsCertType
+	# field set to "server".  This is an
+	# important precaution to protect against
+	# a potential attack discussed here:
+	#  http://openvpn.net/howto.html#mitm
+	#
+	# To use this feature, you will need to generate
+	# your server certificates with the nsCertType
+	# field set to "server".  The build_key_server
+	# script in the easy_rsa folder will do this.
+#	option ns_cert_type server
+
+	# If a tls_auth key is used on the server
+	# then every client must also have the key.
+#	option tls_auth "/etc/openvpn/ta.key 1"
+
+	# Select a cryptographic cipher.
+	# If the cipher option is used on the server
+	# then you must also specify it here.
+#	option cipher x
+
+	# Enable compression on the VPN link.
+	# Don't enable this unless it is also
+	# enabled in the server config file.
+	option comp_lzo yes
+
+	# Set log file verbosity.
+	option verb 3
+
+	# Silence repeating messages
+#	option mute 20
diff --git a/package/network/services/openvpn/files/openvpn.init b/package/network/services/openvpn/files/openvpn.init
new file mode 100644
index 0000000000..4c8f77f92e
--- /dev/null
+++ b/package/network/services/openvpn/files/openvpn.init
@@ -0,0 +1,159 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2008-2013 OpenWrt.org
+# Copyright (C) 2008 Jo-Philipp Wich
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+START=90
+STOP=10
+
+USE_PROCD=1
+PROG=/usr/sbin/openvpn
+
+LIST_SEP="
+"
+
+UCI_STARTED=
+UCI_DISABLED=
+
+append_param() {
+	local s="$1"
+	local v="$2"
+	case "$v" in
+		*_*_*_*) v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_} ;;
+		*_*_*)   v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_} ;;
+		*_*)     v=${v%%_*}-${v#*_} ;;
+	esac
+	echo -n "$v" >> "/var/etc/openvpn-$s.conf"
+	return 0
+}
+
+append_bools() {
+	local p; local v; local s="$1"; shift
+	for p in $*; do
+		config_get_bool v "$s" "$p"
+		[ "$v" = 1 ] && append_param "$s" "$p" && echo >> "/var/etc/openvpn-$s.conf"
+	done
+}
+
+append_params() {
+	local p; local v; local s="$1"; shift
+	for p in $*; do
+		config_get v "$s" "$p"
+		IFS="$LIST_SEP"
+		for v in $v; do
+			[ -n "$v" ] && append_param "$s" "$p" && echo " $v" >> "/var/etc/openvpn-$s.conf"
+		done
+		unset IFS
+	done
+}
+
+section_enabled() {
+	config_get_bool enable  "$1" 'enable'  0
+	config_get_bool enabled "$1" 'enabled' 0
+	[ $enable -gt 0 ] || [ $enabled -gt 0 ]
+}
+
+openvpn_add_instance() {
+	local name="$1"
+	local dir="$2"
+	local conf="$3"
+
+	procd_open_instance
+	procd_set_param command "$PROG"	\
+		--syslog "openvpn($name)" \
+		--status "/var/run/openvpn.$name.status" \
+		--cd "$dir" \
+		--config "$conf"
+	procd_set_param file "$dir/$conf"
+	procd_set_param respawn
+	procd_close_instance
+}
+
+start_instance() {
+	local s="$1"
+
+	config_get config "$s" config
+	config="${config:+$(readlink -f "$config")}"
+
+	section_enabled "$s" || {
+		append UCI_DISABLED "$config" "$LIST_SEP"
+		return 1
+	}
+
+	[ ! -d "/var/run" ] && mkdir -p "/var/run"
+
+	if [ ! -z "$config" ]; then
+		append UCI_STARTED "$config" "$LIST_SEP"
+		openvpn_add_instance "$s" "${config%/*}" "$config"
+		return
+	fi
+
+	[ ! -d "/var/etc" ] && mkdir -p "/var/etc"
+	[ -f "/var/etc/openvpn-$s.conf" ] && rm "/var/etc/openvpn-$s.conf"
+
+	# append flags
+	append_bools "$s" \
+		auth_nocache auth_user_pass_optional bind ccd_exclusive client client_cert_not_required \
+		client_to_client comp_noadapt disable \
+		disable_occ down_pre duplicate_cn fast_io float http_proxy_retry \
+		ifconfig_noexec ifconfig_nowarn ifconfig_pool_linear management_forget_disconnect management_hold \
+		management_query_passwords management_signal mktun mlock mtu_test multihome mute_replay_warnings \
+		nobind no_iv no_name_remapping no_replay opt_verify passtos persist_key persist_local_ip \
+		persist_remote_ip persist_tun ping_timer_rem pull push_reset \
+		remote_random rmtun route_noexec route_nopull single_session socks_proxy_retry \
+		suppress_timestamps tcp_nodelay test_crypto tls_client tls_exit tls_server \
+		tun_ipv6 up_delay up_restart username_as_common_name
+
+	# append params
+	append_params "$s" \
+		cd askpass auth auth_retry auth_user_pass auth_user_pass_verify bcast_buffers ca cert capath \
+		chroot cipher client_config_dir client_connect client_disconnect comp_lzo connect_freq \
+		connect_retry connect_timeout connect_retry_max crl_verify dev dev_node dev_type dh \
+		echo engine explicit_exit_notify fragment group hand_window hash_size \
+		http_proxy http_proxy_option http_proxy_timeout ifconfig ifconfig_pool \
+		ifconfig_pool_persist ifconfig_push inactive ipchange iroute keepalive \
+		key key_method keysize learn_address link_mtu lladdr local log log_append \
+		lport management management_log_cache max_clients \
+		max_routes_per_client mode mssfix mtu_disc mute nice ns_cert_type ping \
+		ping_exit ping_restart pkcs12 plugin port port_share prng proto rcvbuf \
+		redirect_gateway remap_usr1 remote remote_cert_eku remote_cert_ku remote_cert_tls \
+		reneg_bytes reneg_pkts reneg_sec \
+		replay_persist replay_window resolv_retry route route_delay route_gateway \
+		route_metric route_pre_down route_up rport script_security secret server server_bridge setenv shaper sndbuf \
+		socks_proxy status status_version syslog tcp_queue_limit tls_auth tls_version_min \
+		tls_cipher tls_remote tls_timeout tls_verify tmp_dir topology tran_window \
+		tun_mtu tun_mtu_extra txqueuelen user verb down push up \
+		verify_x509_name x509_username_field \
+		ifconfig_ipv6 route_ipv6 server_ipv6 ifconfig_ipv6_pool ifconfig_ipv6_push iroute_ipv6
+
+	openvpn_add_instance "$s" "/var/etc" "openvpn-$s.conf"
+}
+
+start_service() {
+	config_load 'openvpn'
+	config_foreach start_instance 'openvpn'
+
+	local path name
+	for path in /etc/openvpn/*.conf; do
+		if [ -f "$path" ]; then
+			name="${path##*/}"; name="${name%.conf}"
+
+			# don't start configs again that are already started by uci
+			if echo "$UCI_STARTED" | grep -qxF "$path"; then
+				continue
+
+			# don't start configs which are set to disabled in uci
+			elif echo "$UCI_DISABLED" | grep -qxF "$path"; then
+				logger -t openvpn "$name.conf is disabled in /etc/config/openvpn"
+				continue
+			fi
+
+			openvpn_add_instance "$name" "${path%/*}" "$path"
+		fi
+	done
+}
+
+service_triggers() {
+	procd_add_reload_trigger openvpn
+}
diff --git a/package/network/services/openvpn/files/openvpn.upgrade b/package/network/services/openvpn/files/openvpn.upgrade
new file mode 100644
index 0000000000..6ae49d22d0
--- /dev/null
+++ b/package/network/services/openvpn/files/openvpn.upgrade
@@ -0,0 +1 @@
+/etc/openvpn/
diff --git a/package/network/services/openvpn/patches/001-reproducible-remove_DATE.patch b/package/network/services/openvpn/patches/001-reproducible-remove_DATE.patch
new file mode 100644
index 0000000000..3ceef6f0ff
--- /dev/null
+++ b/package/network/services/openvpn/patches/001-reproducible-remove_DATE.patch
@@ -0,0 +1,10 @@
+--- a/src/openvpn/options.c
++++ b/src/openvpn/options.c
+@@ -102,7 +102,6 @@ const char title_string[] =
+   " [MH]"
+ #endif
+   " [IPv6]"
+-  " built on " __DATE__
+ ;
+ 
+ #ifndef ENABLE_SMALL
diff --git a/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch b/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch
new file mode 100644
index 0000000000..c7955c2460
--- /dev/null
+++ b/package/network/services/openvpn/patches/100-polarssl-disable-runtime-version-check.patch
@@ -0,0 +1,11 @@
+--- a/src/openvpn/ssl_polarssl.c
++++ b/src/openvpn/ssl_polarssl.c
+@@ -1156,7 +1156,7 @@ const char *
+ get_ssl_library_version(void)
+ {
+     static char polar_version[30];
+-    unsigned int pv = version_get_number();
++    unsigned int pv = POLARSSL_VERSION_NUMBER;
+     sprintf( polar_version, "PolarSSL %d.%d.%d",
+ 		(pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff );
+     return polar_version;
diff --git a/package/network/services/openvpn/patches/101-backport_upstream_polarssl_debug_call.patch b/package/network/services/openvpn/patches/101-backport_upstream_polarssl_debug_call.patch
new file mode 100644
index 0000000000..2155a4c79b
--- /dev/null
+++ b/package/network/services/openvpn/patches/101-backport_upstream_polarssl_debug_call.patch
@@ -0,0 +1,33 @@
+openvpn: fix build without POLARSSL_DEBUG_C
+
+Backport of upstream master commit
+b63f98633dbe2ca92cd43fc6f8597ab283a600bf.
+
+Signed-off-by: Magnus Kroken <mkroken@gmail.com>
+
+From b63f98633dbe2ca92cd43fc6f8597ab283a600bf Mon Sep 17 00:00:00 2001
+From: Steffan Karger <steffan@karger.me>
+Date: Tue, 14 Jun 2016 22:00:03 +0200
+Subject: [PATCH] mbedtls: don't set debug threshold if compiled without
+ MBEDTLS_DEBUG_C
+
+For targets with space constraints, one might want to compile mbed TLS
+without MBEDTLS_DEBUG_C defined, to save some tens of kilobytes.  Make
+sure OpenVPN still compiles if that is the case.
+
+Signed-off-by: Steffan Karger <steffan@karger.me>
+Acked-by: Gert Doering <gert@greenie.muc.de>
+Message-Id: <1465934403-22226-1-git-send-email-steffan@karger.me>
+URL: http://article.gmane.org/gmane.network.openvpn.devel/11922
+Signed-off-by: Gert Doering <gert@greenie.muc.de>
+--- a/src/openvpn/ssl_polarssl.c
++++ b/src/openvpn/ssl_polarssl.c
+@@ -747,7 +747,9 @@ void key_state_ssl_init(struct key_state
+   if (polar_ok(ssl_init(ks_ssl->ctx)))
+     {
+       /* Initialise SSL context */
++      #ifdef POLARSSL_DEBUG_C
+       debug_set_threshold(3);
++      #endif
+       ssl_set_dbg (ks_ssl->ctx, my_debug, NULL);
+       ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint);
diff --git a/package/network/services/openvpn/patches/200-small_build_enable_occ.patch b/package/network/services/openvpn/patches/200-small_build_enable_occ.patch
new file mode 100644
index 0000000000..eef4da2d26
--- /dev/null
+++ b/package/network/services/openvpn/patches/200-small_build_enable_occ.patch
@@ -0,0 +1,12 @@
+--- a/src/openvpn/syshead.h
++++ b/src/openvpn/syshead.h
+@@ -602,9 +602,7 @@ socket_defined (const socket_descriptor_
+ /*
+  * Should we include OCC (options consistency check) code?
+  */
+-#ifndef ENABLE_SMALL
+ #define ENABLE_OCC
+-#endif
+ 
+ /*
+  * Should we include NTLM proxy functionality
diff --git a/package/network/services/ppp/Makefile b/package/network/services/ppp/Makefile
new file mode 100644
index 0000000000..2b78761ea5
--- /dev/null
+++ b/package/network/services/ppp/Makefile
@@ -0,0 +1,284 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=ppp
+PKG_VERSION:=2.4.7
+PKG_RELEASE:=10
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://download.samba.org/pub/ppp/
+PKG_MD5SUM:=78818f40e6d33a1d1de68a1551f6595a
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=BSD-4-Clause
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_BUILD_DEPENDS:=libpcap
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ppp/Default
+  SECTION:=net
+  CATEGORY:=Network
+  URL:=http://ppp.samba.org/
+endef
+
+define Package/ppp
+$(call Package/ppp/Default)
+  DEPENDS:=+kmod-ppp
+  TITLE:=PPP daemon
+  VARIANT:=default
+endef
+
+define Package/ppp-multilink
+$(call Package/ppp/Default)
+  DEPENDS:=+kmod-ppp
+  TITLE:=PPP daemon (with multilink support)
+  VARIANT:=multilink
+endef
+
+define Package/ppp/description
+This package contains the PPP (Point-to-Point Protocol) daemon.
+endef
+
+define Package/ppp/conffiles
+/etc/ppp/chap-secrets
+/etc/ppp/filter
+/etc/ppp/ip-down
+/etc/ppp/ip-up
+/etc/ppp/ipv6-down
+/etc/ppp/ipv6-up
+/etc/ppp/options
+endef
+
+define Package/ppp-mod-pppoa
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink) +linux-atm +kmod-pppoa
+  TITLE:=PPPoA plugin
+endef
+
+define Package/ppp-mod-pppoa/description
+This package contains a PPPoA (PPP over ATM) plugin for ppp.
+endef
+
+define Package/ppp-mod-pppoe
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink) +kmod-pppoe
+  TITLE:=PPPoE plugin
+endef
+
+define Package/ppp-mod-pppoe/description
+This package contains a PPPoE (PPP over Ethernet) plugin for ppp.
+endef
+
+define Package/ppp-mod-radius
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink)
+  TITLE:=RADIUS plugin
+endef
+
+define Package/ppp-mod-radius/description
+This package contains a RADIUS (Remote Authentication Dial-In User Service)
+plugin for ppp.
+endef
+
+define Package/ppp-mod-radius/conffiles
+/etc/ppp/radius.conf
+/etc/ppp/radius/
+endef
+
+define Package/ppp-mod-pppol2tp
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink) +kmod-pppol2tp
+  TITLE:=PPPoL2TP plugin
+endef
+
+define Package/ppp-mod-pppol2tp/description
+This package contains a PPPoL2TP (PPP over L2TP) plugin for ppp.
+endef
+
+define Package/ppp-mod-pptp
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink) +kmod-pptp +kmod-mppe +resolveip
+  TITLE:=PPtP plugin
+endef
+
+define Package/ppp-mod-pptp/description
+This package contains a PPtP plugin for ppp.
+endef
+
+define Package/ppp-mod-passwordfd
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink)
+  TITLE:=pap/chap secret from filedescriptor
+endef
+
+define Package/ppp-mod-passwordfd/description
+This package allows to pass the PAP/CHAP secret from a filedescriptor.
+Eliminates the need for a secrets file.
+endef
+
+define Package/chat
+$(call Package/ppp/Default)
+  TITLE:=Establish conversation with a modem
+endef
+
+define Package/chat/description
+This package contains an utility to establish conversation with other PPP servers
+(via a modem).
+endef
+
+define Package/pppdump
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink)
+  TITLE:=Read PPP record file
+endef
+
+define Package/pppdump/description
+This package contains an utility to read PPP record file.
+endef
+
+define Package/pppstats
+$(call Package/ppp/Default)
+  DEPENDS:=@(PACKAGE_ppp||PACKAGE_ppp-multilink)
+  TITLE:=Report PPP statistics
+endef
+
+define Package/pppstats/description
+This package contains an utility to report PPP statistics.
+endef
+
+
+define Build/Configure
+$(call Build/Configure/Default,, \
+	UNAME_S="Linux" \
+	UNAME_R="$(LINUX_VERSION)" \
+	UNAME_M="$(ARCH)" \
+)
+	mkdir -p $(PKG_BUILD_DIR)/pppd/plugins/pppoatm/linux
+	cp \
+		$(LINUX_DIR)/include/linux/compiler.h \
+		$(LINUX_DIR)/include/$(LINUX_UAPI_DIR)linux/atm*.h \
+		$(PKG_BUILD_DIR)/pppd/plugins/pppoatm/linux/
+endef
+
+MAKE_FLAGS += COPTS="$(TARGET_CFLAGS)" \
+		PRECOMPILED_FILTER=1 \
+		STAGING_DIR="$(STAGING_DIR)"
+
+ifeq ($(BUILD_VARIANT),multilink)
+  MAKE_FLAGS += HAVE_MULTILINK=y
+else
+  MAKE_FLAGS += HAVE_MULTILINK=
+endif
+
+ifdef CONFIG_USE_MUSL
+  MAKE_FLAGS += USE_LIBUTIL=
+endif
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/include/pppd $(1)/usr/include/
+endef
+
+define Package/ppp/script_install
+endef
+
+define Package/ppp/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/sbin/pppd $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/etc/ppp
+	$(INSTALL_CONF) ./files/etc/ppp/chap-secrets $(1)/etc/ppp/
+	$(INSTALL_DATA) ./files/etc/ppp/filter $(1)/etc/ppp/
+	$(INSTALL_DATA) ./files/etc/ppp/options $(1)/etc/ppp/
+	$(LN) /tmp/resolv.conf.ppp $(1)/etc/ppp/resolv.conf
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/ppp.sh $(1)/lib/netifd/proto/
+	$(INSTALL_BIN) ./files/lib/netifd/ppp-up $(1)/lib/netifd/
+	$(INSTALL_BIN) ./files/lib/netifd/ppp6-up $(1)/lib/netifd/
+	$(INSTALL_BIN) ./files/lib/netifd/ppp-down $(1)/lib/netifd/
+endef
+Package/ppp-multilink/install=$(Package/ppp/install)
+
+define Package/ppp-mod-pppoa/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/lib/pppd/$(PKG_VERSION)/pppoatm.so \
+		$(1)/usr/lib/pppd/$(PKG_VERSION)/
+endef
+
+define Package/ppp-mod-pppoe/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/lib/pppd/$(PKG_VERSION)/rp-pppoe.so \
+		$(1)/usr/lib/pppd/$(PKG_VERSION)/
+endef
+
+define Package/ppp-mod-radius/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/lib/pppd/$(PKG_VERSION)/radius.so \
+		$(1)/usr/lib/pppd/$(PKG_VERSION)/
+	$(INSTALL_DIR) $(1)/etc/ppp
+	$(INSTALL_DATA) ./files/etc/ppp/radius.conf $(1)/etc/ppp/
+	$(INSTALL_DIR) $(1)/etc/ppp/radius
+	$(INSTALL_DATA) ./files/etc/ppp/radius/dictionary* \
+		$(1)/etc/ppp/radius/
+	$(INSTALL_CONF) ./files/etc/ppp/radius/servers \
+		$(1)/etc/ppp/radius/
+endef
+
+define Package/ppp-mod-pppol2tp/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/lib/pppd/$(PKG_VERSION)/pppol2tp.so \
+		$(1)/usr/lib/pppd/$(PKG_VERSION)/
+endef
+
+define Package/ppp-mod-pptp/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/lib/pppd/$(PKG_VERSION)/pptp.so \
+		$(1)/usr/lib/pppd/$(PKG_VERSION)/
+	$(INSTALL_DIR) $(1)/etc/ppp
+	$(INSTALL_DATA) ./files/etc/ppp/options.pptp $(1)/etc/ppp/
+endef
+
+define Package/ppp-mod-passwordfd/install
+	$(INSTALL_DIR) $(1)/usr/lib/pppd/$(PKG_VERSION)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/lib/pppd/$(PKG_VERSION)/passwordfd.so \
+		$(1)/usr/lib/pppd/$(PKG_VERSION)/
+endef
+
+define Package/chat/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/sbin/chat $(1)/usr/sbin/
+endef
+
+define Package/pppdump/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/sbin/pppdump $(1)/usr/sbin/
+endef
+
+define Package/pppstats/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/sbin/pppstats $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,ppp))
+$(eval $(call BuildPackage,ppp-multilink))
+$(eval $(call BuildPackage,ppp-mod-pppoa))
+$(eval $(call BuildPackage,ppp-mod-pppoe))
+$(eval $(call BuildPackage,ppp-mod-radius))
+$(eval $(call BuildPackage,ppp-mod-pppol2tp))
+$(eval $(call BuildPackage,ppp-mod-pptp))
+$(eval $(call BuildPackage,ppp-mod-passwordfd))
+$(eval $(call BuildPackage,chat))
+$(eval $(call BuildPackage,pppdump))
+$(eval $(call BuildPackage,pppstats))
diff --git a/package/network/services/ppp/files/etc/ppp/chap-secrets b/package/network/services/ppp/files/etc/ppp/chap-secrets
new file mode 100644
index 0000000000..6ab76e49e9
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/chap-secrets
@@ -0,0 +1 @@
+#USERNAME  PROVIDER  PASSWORD  IPADDRESS
diff --git a/package/network/services/ppp/files/etc/ppp/filter b/package/network/services/ppp/files/etc/ppp/filter
new file mode 100644
index 0000000000..ec72a81a01
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/filter
@@ -0,0 +1,23 @@
+#
+# Expression: outbound and not icmp[0] != 8 and not tcp[13] & 4 != 0
+#
+19
+48 0 0 0
+21 0 16 1
+40 0 0 2
+21 0 13 33
+48 0 0 13
+21 0 5 1
+40 0 0 10
+69 9 0 8191
+177 0 0 4
+80 0 0 4
+21 6 7 8
+21 0 5 6
+40 0 0 10
+69 3 0 8191
+177 0 0 4
+80 0 0 17
+69 1 0 4
+6 0 0 4
+6 0 0 0
diff --git a/package/network/services/ppp/files/etc/ppp/options b/package/network/services/ppp/files/etc/ppp/options
new file mode 100644
index 0000000000..6b93f7bdb6
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/options
@@ -0,0 +1,10 @@
+#debug
+logfile /dev/null
+noipdefault
+noaccomp
+nopcomp
+nocrtscts
+lock
+maxfail 0
+lcp-echo-failure 5
+lcp-echo-interval 1
diff --git a/package/network/services/ppp/files/etc/ppp/options.pptp b/package/network/services/ppp/files/etc/ppp/options.pptp
new file mode 100644
index 0000000000..46a3f48112
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/options.pptp
@@ -0,0 +1,7 @@
+noipdefault
+noauth
+nobsdcomp
+nodeflate
+idle 0
+mppe required,no40,no56,stateless
+maxfail 0
diff --git a/package/network/services/ppp/files/etc/ppp/radius.conf b/package/network/services/ppp/files/etc/ppp/radius.conf
new file mode 100644
index 0000000000..0f24a8c7f7
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/radius.conf
@@ -0,0 +1,8 @@
+authserver localhost:1812
+acctserver localhost:1813
+dictionary /etc/ppp/radius/dictionary
+servers /etc/ppp/radius/servers
+mapfile /dev/null
+seqfile /tmp/radius.seq
+radius_timeout 5
+radius_retries 3
diff --git a/package/network/services/ppp/files/etc/ppp/radius/dictionary b/package/network/services/ppp/files/etc/ppp/radius/dictionary
new file mode 100644
index 0000000000..706d1ce99c
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/radius/dictionary
@@ -0,0 +1,253 @@
+#
+# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl
+#
+#	This file contains dictionary translations for parsing
+#	requests and generating responses.  All transactions are
+#	composed of Attribute/Value Pairs.  The value of each attribute
+#	is specified as one of 4 data types.  Valid data types are:
+#
+#	string - 0-253 octets
+#	ipaddr - 4 octets in network byte order
+#	integer - 32 bit value in big endian order (high byte first)
+#	date - 32 bit value in big endian order - seconds since
+#					00:00:00 GMT,  Jan.  1,  1970
+#
+#	Enumerated values are stored in the user file with dictionary
+#	VALUE translations for easy administration.
+#
+#	Example:
+#
+#	ATTRIBUTE	  VALUE
+#	---------------   -----
+#	Framed-Protocol = PPP
+#	7		= 1	(integer encoding)
+#
+
+# The dictionary format now supports vendor-specific attributes.
+# Vendors are introduced like this:
+#
+#	VENDOR vendor_name vendor_number
+#
+# For example:
+#
+#	VENDOR RoaringPenguin 10055
+#
+# Vendor-specific attributes have a fifth field with the name of the
+# vendor.  For example:
+#
+#       ATTRIBUTE RP-Upstream-Speed-Limit 1 integer RoaringPenguin
+#
+# introduces a Roaring Penguin vendor-specific attribbute with name
+# RP-Upstream-Speed-Limit, number 1, type integer and vendor RoaringPenguin.
+
+#
+#	Following are the proper new names. Use these.
+#
+ATTRIBUTE	User-Name		1	string
+ATTRIBUTE	Password		2	string
+ATTRIBUTE	CHAP-Password		3	string
+ATTRIBUTE	NAS-IP-Address		4	ipaddr
+ATTRIBUTE	NAS-Port-Id		5	integer
+ATTRIBUTE	Service-Type		6	integer
+ATTRIBUTE	Framed-Protocol		7	integer
+ATTRIBUTE	Framed-IP-Address	8	ipaddr
+ATTRIBUTE	Framed-IP-Netmask	9	ipaddr
+ATTRIBUTE	Framed-Routing		10	integer
+ATTRIBUTE	Filter-Id		11	string
+ATTRIBUTE	Framed-MTU		12	integer
+ATTRIBUTE	Framed-Compression	13	integer
+ATTRIBUTE	Login-IP-Host		14	ipaddr
+ATTRIBUTE	Login-Service		15	integer
+ATTRIBUTE	Login-TCP-Port		16	integer
+ATTRIBUTE	Reply-Message		18	string
+ATTRIBUTE	Callback-Number		19	string
+ATTRIBUTE	Callback-Id		20	string
+ATTRIBUTE	Framed-Route		22	string
+ATTRIBUTE	Framed-IPX-Network	23	ipaddr
+ATTRIBUTE	State			24	string
+ATTRIBUTE	Class			25	string
+ATTRIBUTE	Session-Timeout		27	integer
+ATTRIBUTE	Idle-Timeout		28	integer
+ATTRIBUTE	Termination-Action	29	integer
+ATTRIBUTE	Called-Station-Id	30	string
+ATTRIBUTE	Calling-Station-Id	31	string
+ATTRIBUTE	NAS-Identifier		32	string
+ATTRIBUTE	Acct-Status-Type	40	integer
+ATTRIBUTE	Acct-Delay-Time		41	integer
+ATTRIBUTE	Acct-Input-Octets	42	integer
+ATTRIBUTE	Acct-Output-Octets	43	integer
+ATTRIBUTE	Acct-Session-Id		44	string
+ATTRIBUTE	Acct-Authentic		45	integer
+ATTRIBUTE	Acct-Session-Time	46	integer
+ATTRIBUTE	Acct-Input-Packets	47	integer
+ATTRIBUTE	Acct-Output-Packets	48	integer
+ATTRIBUTE	Acct-Terminate-Cause	49	integer
+ATTRIBUTE	Chap-Challenge		60	string
+ATTRIBUTE	NAS-Port-Type		61	integer
+ATTRIBUTE	Port-Limit		62	integer
+ATTRIBUTE	Connect-Info		77	string
+
+# RFC 2869
+ATTRIBUTE	Acct-Interim-Interval	85	integer
+
+#
+#	Experimental Non Protocol Attributes used by Cistron-Radiusd
+#
+ATTRIBUTE	Huntgroup-Name		221	string
+ATTRIBUTE	User-Category		1029	string
+ATTRIBUTE	Group-Name		1030	string
+ATTRIBUTE	Simultaneous-Use	1034	integer
+ATTRIBUTE	Strip-User-Name		1035	integer
+ATTRIBUTE	Fall-Through		1036	integer
+ATTRIBUTE	Add-Port-To-IP-Address	1037	integer
+ATTRIBUTE	Exec-Program		1038	string
+ATTRIBUTE	Exec-Program-Wait	1039	string
+ATTRIBUTE	Hint			1040	string
+
+#
+#	Non-Protocol Attributes
+#	These attributes are used internally by the server
+#
+ATTRIBUTE	Expiration		  21	date
+ATTRIBUTE	Auth-Type		1000	integer
+ATTRIBUTE	Menu			1001	string
+ATTRIBUTE	Termination-Menu	1002	string
+ATTRIBUTE	Prefix			1003	string
+ATTRIBUTE	Suffix			1004	string
+ATTRIBUTE	Group			1005	string
+ATTRIBUTE	Crypt-Password		1006	string
+ATTRIBUTE	Connect-Rate		1007	integer
+
+#
+#       Experimental, implementation specific attributes
+#
+# Limit session traffic
+ATTRIBUTE	Session-Octets-Limit	227	integer
+# What to assume as limit - 0 in+out, 1 in, 2 out, 3 max(in,out)
+ATTRIBUTE	Octets-Direction	228	integer
+
+#
+#	Integer Translations
+#
+
+#	User Types
+
+VALUE		Service-Type		Login-User		1
+VALUE		Service-Type		Framed-User		2
+VALUE		Service-Type		Callback-Login-User	3
+VALUE		Service-Type		Callback-Framed-User	4
+VALUE		Service-Type		Outbound-User		5
+VALUE		Service-Type		Administrative-User	6
+VALUE		Service-Type		NAS-Prompt-User		7
+
+#	Framed Protocols
+
+VALUE		Framed-Protocol		PPP			1
+VALUE		Framed-Protocol		SLIP			2
+
+#	Framed Routing Values
+
+VALUE		Framed-Routing		None			0
+VALUE		Framed-Routing		Broadcast		1
+VALUE		Framed-Routing		Listen			2
+VALUE		Framed-Routing		Broadcast-Listen	3
+
+#	Framed Compression Types
+
+VALUE		Framed-Compression	None			0
+VALUE		Framed-Compression	Van-Jacobson-TCP-IP	1
+
+#	Login Services
+
+VALUE		Login-Service		Telnet			0
+VALUE		Login-Service		Rlogin			1
+VALUE		Login-Service		TCP-Clear		2
+VALUE		Login-Service		PortMaster		3
+
+#	Status Types
+
+VALUE		Acct-Status-Type	Start			1
+VALUE		Acct-Status-Type	Stop			2
+VALUE		Acct-Status-Type	Accounting-On		7
+VALUE		Acct-Status-Type	Accounting-Off		8
+
+#	Authentication Types
+
+VALUE		Acct-Authentic		RADIUS			1
+VALUE		Acct-Authentic		Local			2
+VALUE		Acct-Authentic		PowerLink128		100
+
+#	Termination Options
+
+VALUE		Termination-Action	Default			0
+VALUE		Termination-Action	RADIUS-Request		1
+
+#	NAS Port Types, available in 3.3.1 and later
+
+VALUE		NAS-Port-Type		Async			0
+VALUE		NAS-Port-Type		Sync			1
+VALUE		NAS-Port-Type		ISDN			2
+VALUE		NAS-Port-Type		ISDN-V120		3
+VALUE		NAS-Port-Type		ISDN-V110		4
+
+#	Acct Terminate Causes, available in 3.3.2 and later
+
+VALUE           Acct-Terminate-Cause    User-Request            1
+VALUE           Acct-Terminate-Cause    Lost-Carrier            2
+VALUE           Acct-Terminate-Cause    Lost-Service            3
+VALUE           Acct-Terminate-Cause    Idle-Timeout            4
+VALUE           Acct-Terminate-Cause    Session-Timeout         5
+VALUE           Acct-Terminate-Cause    Admin-Reset             6
+VALUE           Acct-Terminate-Cause    Admin-Reboot            7
+VALUE           Acct-Terminate-Cause    Port-Error              8
+VALUE           Acct-Terminate-Cause    NAS-Error               9
+VALUE           Acct-Terminate-Cause    NAS-Request             10
+VALUE           Acct-Terminate-Cause    NAS-Reboot              11
+VALUE           Acct-Terminate-Cause    Port-Unneeded           12
+VALUE           Acct-Terminate-Cause    Port-Preempted          13
+VALUE           Acct-Terminate-Cause    Port-Suspended          14
+VALUE           Acct-Terminate-Cause    Service-Unavailable     15
+VALUE           Acct-Terminate-Cause    Callback                16
+VALUE           Acct-Terminate-Cause    User-Error              17
+VALUE           Acct-Terminate-Cause    Host-Request            18
+
+#
+#	Non-Protocol Integer Translations
+#
+
+VALUE		Auth-Type		Local			0
+VALUE		Auth-Type		System			1
+VALUE		Auth-Type		SecurID			2
+VALUE		Auth-Type		Crypt-Local		3
+VALUE		Auth-Type		Reject			4
+
+#
+#	Cistron extensions
+#
+VALUE		Auth-Type		Pam			253
+VALUE		Auth-Type		None			254
+
+#
+#	Experimental Non-Protocol Integer Translations for Cistron-Radiusd
+#
+VALUE		Fall-Through		No			0
+VALUE		Fall-Through		Yes			1
+VALUE		Add-Port-To-IP-Address	No			0
+VALUE		Add-Port-To-IP-Address	Yes			1
+
+#
+#	Configuration Values
+#	uncomment these two lines to turn account expiration on
+#
+
+#VALUE		Server-Config		Password-Expiration	30
+#VALUE		Server-Config		Password-Warning	5
+
+#       Octets-Direction
+VALUE		Octets-Direction        Sum			0
+VALUE		Octets-Direction        Input			1
+VALUE		Octets-Direction        Output			2
+VALUE		Octets-Direction        MaxOveral		3
+VALUE		Octets-Direction        MaxSession		4
+
+INCLUDE /etc/ppp/radius/dictionary.microsoft
diff --git a/package/network/services/ppp/files/etc/ppp/radius/dictionary.asnet b/package/network/services/ppp/files/etc/ppp/radius/dictionary.asnet
new file mode 100644
index 0000000000..337d1e1407
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/radius/dictionary.asnet
@@ -0,0 +1,3 @@
+VENDOR		ASNET		50000
+ATTRIBUTE	Speed-Down		1	string	ASNET
+ATTRIBUTE	Speed-Up		2	string	ASNET
diff --git a/package/network/services/ppp/files/etc/ppp/radius/dictionary.microsoft b/package/network/services/ppp/files/etc/ppp/radius/dictionary.microsoft
new file mode 100644
index 0000000000..2a6c20e5ff
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/radius/dictionary.microsoft
@@ -0,0 +1,80 @@
+#
+#	Microsoft's VSA's, from RFC 2548
+#
+#
+
+VENDOR		Microsoft	311	Microsoft
+
+ATTRIBUTE	MS-CHAP-Response	1	string	Microsoft
+ATTRIBUTE	MS-CHAP-Error		2	string	Microsoft
+ATTRIBUTE	MS-CHAP-CPW-1		3	string	Microsoft
+ATTRIBUTE	MS-CHAP-CPW-2		4	string	Microsoft
+ATTRIBUTE	MS-CHAP-LM-Enc-PW	5	string	Microsoft
+ATTRIBUTE	MS-CHAP-NT-Enc-PW	6	string	Microsoft
+ATTRIBUTE	MS-MPPE-Encryption-Policy 7	string	Microsoft
+# This is referred to as both singular and plural in the RFC.
+# Plural seems to make more sense.
+ATTRIBUTE	MS-MPPE-Encryption-Type 8	string	Microsoft
+ATTRIBUTE	MS-MPPE-Encryption-Types  8	string	Microsoft
+ATTRIBUTE	MS-RAS-Vendor		9	integer	Microsoft
+ATTRIBUTE	MS-CHAP-Domain		10	string	Microsoft
+ATTRIBUTE	MS-CHAP-Challenge	11	string	Microsoft
+ATTRIBUTE	MS-CHAP-MPPE-Keys	12	string	Microsoft
+ATTRIBUTE	MS-BAP-Usage		13	integer	Microsoft
+ATTRIBUTE	MS-Link-Utilization-Threshold 14 integer	Microsoft
+ATTRIBUTE	MS-Link-Drop-Time-Limit	15	integer	Microsoft
+ATTRIBUTE	MS-MPPE-Send-Key	16	string	Microsoft
+ATTRIBUTE	MS-MPPE-Recv-Key	17	string	Microsoft
+ATTRIBUTE	MS-RAS-Version		18	string	Microsoft
+ATTRIBUTE	MS-Old-ARAP-Password	19	string	Microsoft
+ATTRIBUTE	MS-New-ARAP-Password	20	string	Microsoft
+ATTRIBUTE	MS-ARAP-PW-Change-Reason 21	integer	Microsoft
+
+ATTRIBUTE	MS-Filter		22	string	Microsoft
+ATTRIBUTE	MS-Acct-Auth-Type	23	integer	Microsoft
+ATTRIBUTE	MS-Acct-EAP-Type	24	integer	Microsoft
+
+ATTRIBUTE	MS-CHAP2-Response	25	string	Microsoft
+ATTRIBUTE	MS-CHAP2-Success	26	string	Microsoft
+ATTRIBUTE	MS-CHAP2-CPW		27	string	Microsoft
+
+ATTRIBUTE	MS-Primary-DNS-Server	28	ipaddr	Microsoft
+ATTRIBUTE	MS-Secondary-DNS-Server	29	ipaddr	Microsoft
+ATTRIBUTE	MS-Primary-NBNS-Server	30	ipaddr	Microsoft
+ATTRIBUTE	MS-Secondary-NBNS-Server 31	ipaddr	Microsoft
+
+#ATTRIBUTE	MS-ARAP-Challenge	33	string	Microsoft
+
+
+#
+#	Integer Translations
+#
+
+#	MS-BAP-Usage Values
+
+VALUE		MS-BAP-Usage		Not-Allowed	0
+VALUE		MS-BAP-Usage		Allowed		1
+VALUE		MS-BAP-Usage		Required	2
+
+#	MS-ARAP-Password-Change-Reason Values
+
+VALUE	MS-ARAP-PW-Change-Reason	Just-Change-Password		1
+VALUE	MS-ARAP-PW-Change-Reason	Expired-Password		2
+VALUE	MS-ARAP-PW-Change-Reason	Admin-Requires-Password-Change	3
+VALUE	MS-ARAP-PW-Change-Reason	Password-Too-Short		4
+
+#	MS-Acct-Auth-Type Values
+
+VALUE		MS-Acct-Auth-Type	PAP		1
+VALUE		MS-Acct-Auth-Type	CHAP		2
+VALUE		MS-Acct-Auth-Type	MS-CHAP-1	3
+VALUE		MS-Acct-Auth-Type	MS-CHAP-2	4
+VALUE		MS-Acct-Auth-Type	EAP		5
+
+#	MS-Acct-EAP-Type Values
+
+VALUE		MS-Acct-EAP-Type	MD5		4
+VALUE		MS-Acct-EAP-Type	OTP		5
+VALUE		MS-Acct-EAP-Type	Generic-Token-Card	6
+VALUE		MS-Acct-EAP-Type	TLS		13
+
diff --git a/package/network/services/ppp/files/etc/ppp/radius/servers b/package/network/services/ppp/files/etc/ppp/radius/servers
new file mode 100644
index 0000000000..0d4f0691d0
--- /dev/null
+++ b/package/network/services/ppp/files/etc/ppp/radius/servers
@@ -0,0 +1,2 @@
+# SERVER SECRET
+localhost secret
diff --git a/package/network/services/ppp/files/lib/netifd/ppp-down b/package/network/services/ppp/files/lib/netifd/ppp-down
new file mode 100755
index 0000000000..94cefc415e
--- /dev/null
+++ b/package/network/services/ppp/files/lib/netifd/ppp-down
@@ -0,0 +1,13 @@
+#!/bin/sh
+PPP_IPPARAM="$6"
+
+. /lib/netifd/netifd-proto.sh
+proto_init_update "$IFNAME" 0
+proto_send_update "$PPP_IPPARAM"
+
+[ -d /etc/ppp/ip-down.d ] && {
+	for SCRIPT in /etc/ppp/ip-down.d/*
+	do
+		[ -x "$SCRIPT" ] && "$SCRIPT" "$@"
+	done
+}
diff --git a/package/network/services/ppp/files/lib/netifd/ppp-up b/package/network/services/ppp/files/lib/netifd/ppp-up
new file mode 100755
index 0000000000..18c32f0dee
--- /dev/null
+++ b/package/network/services/ppp/files/lib/netifd/ppp-up
@@ -0,0 +1,20 @@
+#!/bin/sh
+PPP_IPPARAM="$6"
+
+. /lib/netifd/netifd-proto.sh
+proto_init_update "$IFNAME" 1 1
+proto_set_keep 1
+[ -n "$PPP_IPPARAM" ] && {
+	[ -n "$IPLOCAL" ] && proto_add_ipv4_address "$IPLOCAL" 32 "" "${IPREMOTE:-2.2.2.2}"
+	[ -n "$IPREMOTE" ] && proto_add_ipv4_route 0.0.0.0 0 "$IPREMOTE"
+	[ -n "$DNS1" ] && proto_add_dns_server "$DNS1"
+	[ -n "$DNS2" -a "$DNS1" != "$DNS2" ] && proto_add_dns_server "$DNS2"
+}
+proto_send_update "$PPP_IPPARAM"
+
+[ -d /etc/ppp/ip-up.d ] && {
+	for SCRIPT in /etc/ppp/ip-up.d/*
+	do
+		[ -x "$SCRIPT" ] && "$SCRIPT" "$@"
+	done
+}
diff --git a/package/network/services/ppp/files/lib/netifd/ppp6-up b/package/network/services/ppp/files/lib/netifd/ppp6-up
new file mode 100644
index 0000000000..87ca63c751
--- /dev/null
+++ b/package/network/services/ppp/files/lib/netifd/ppp6-up
@@ -0,0 +1,27 @@
+#!/bin/sh
+PPP_IPPARAM="$6"
+
+. /lib/netifd/netifd-proto.sh
+proto_init_update "$IFNAME" 1 1
+proto_set_keep 1
+[ -n "$PPP_IPPARAM" ] && {
+	[ -n "$LLLOCAL" ] && proto_add_ipv6_address "$LLLOCAL" 128
+}
+proto_send_update "$PPP_IPPARAM"
+
+[ -d /etc/ppp/ip-up.d ] && {
+	for SCRIPT in /etc/ppp/ip-up.d/*
+	do
+		[ -x "$SCRIPT" ] && "$SCRIPT" "$@"
+	done
+}
+
+if [ -n "$AUTOIPV6" ]; then
+	json_init
+	json_add_string name "${PPP_IPPARAM}_6"
+	json_add_string ifname "@$PPP_IPPARAM"
+	json_add_string proto "dhcpv6"
+	[ -n "$EXTENDPREFIX" ] && json_add_string extendprefix 1
+	json_close_object
+	ubus call network add_dynamic "$(json_dump)"
+fi
diff --git a/package/network/services/ppp/files/ppp.sh b/package/network/services/ppp/files/ppp.sh
new file mode 100755
index 0000000000..91452b4288
--- /dev/null
+++ b/package/network/services/ppp/files/ppp.sh
@@ -0,0 +1,324 @@
+#!/bin/sh
+
+[ -x /usr/sbin/pppd ] || exit 0
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. /lib/functions/network.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+ppp_select_ipaddr()
+{
+	local subnets=$1
+	local res
+	local res_mask
+
+	for subnet in $subnets; do
+		local addr="${subnet%%/*}"
+		local mask="${subnet#*/}"
+
+		if [ -n "$res_mask" -a "$mask" != 32 ]; then
+			[ "$mask" -gt "$res_mask" ] || [ "$res_mask" = 32 ] && {
+				res="$addr"
+				res_mask="$mask"
+			}
+		elif [ -z "$res_mask" ]; then
+			res="$addr"
+			res_mask="$mask"
+		fi
+	done
+
+	echo "$res"
+}
+
+ppp_exitcode_tostring()
+{
+	local errorcode=$1
+	[ -n "$errorcode" ] || errorcode=5
+
+	case "$errorcode" in
+		0) echo "OK" ;;
+		1) echo "FATAL_ERROR" ;;
+		2) echo "OPTION_ERROR" ;;
+		3) echo "NOT_ROOT" ;;
+		4) echo "NO_KERNEL_SUPPORT" ;;
+		5) echo "USER_REQUEST" ;;
+		6) echo "LOCK_FAILED" ;;
+		7) echo "OPEN_FAILED" ;;
+		8) echo "CONNECT_FAILED" ;;
+		9) echo "PTYCMD_FAILED" ;;
+		10) echo "NEGOTIATION_FAILED" ;;
+		11) echo "PEER_AUTH_FAILED" ;;
+		12) echo "IDLE_TIMEOUT" ;;
+		13) echo "CONNECT_TIME" ;;
+		14) echo "CALLBACK" ;;
+		15) echo "PEER_DEAD" ;;
+		16) echo "HANGUP" ;;
+		17) echo "LOOPBACK" ;;
+		18) echo "INIT_FAILED" ;;
+		19) echo "AUTH_TOPEER_FAILED" ;;
+		20) echo "TRAFFIC_LIMIT" ;;
+		21) echo "CNID_AUTH_FAILED";;
+		*) echo "UNKNOWN_ERROR" ;;
+	esac
+}
+
+ppp_generic_init_config() {
+	proto_config_add_string username
+	proto_config_add_string password
+	proto_config_add_string keepalive
+	proto_config_add_boolean keepalive_adaptive
+	proto_config_add_int demand
+	proto_config_add_string pppd_options
+	proto_config_add_string 'connect:file'
+	proto_config_add_string 'disconnect:file'
+	proto_config_add_string ipv6
+	proto_config_add_boolean authfail
+	proto_config_add_int mtu
+	proto_config_add_string pppname
+	proto_config_add_string unnumbered
+	proto_config_add_boolean persist
+	proto_config_add_int maxfail
+	proto_config_add_int holdoff
+}
+
+ppp_generic_setup() {
+	local config="$1"; shift
+	local localip
+
+	json_get_vars ipv6 demand keepalive keepalive_adaptive username password pppd_options pppname unnumbered persist maxfail holdoff
+	if [ "$ipv6" = 0 ]; then
+		ipv6=""
+	elif [ -z "$ipv6" -o "$ipv6" = auto ]; then
+		ipv6=1
+		autoipv6=1
+	fi
+
+	if [ "${demand:-0}" -gt 0 ]; then
+		demand="precompiled-active-filter /etc/ppp/filter demand idle $demand"
+	else
+		demand=""
+	fi
+	if [ -n "$persist" ]; then
+		[ "${persist}" -lt 1 ] && persist="nopersist" || persist="persist"
+	fi
+	if [ -z "$maxfail" ]; then
+		[ "$persist" = "persist" ] && maxfail=0 || maxfail=1
+	fi
+	[ -n "$mtu" ] || json_get_var mtu mtu
+	[ -n "$pppname" ] || pppname="${proto:-ppp}-$config"
+	[ -n "$unnumbered" ] && {
+		local subnets
+		( proto_add_host_dependency "$config" "" "$unnumbered" )
+		network_get_subnets subnets "$unnumbered"
+		localip=$(ppp_select_ipaddr "$subnets")
+		[ -n "$localip" ] || {
+			proto_block_restart "$config"
+			return
+		}
+	}
+
+	local lcp_failure="${keepalive%%[, ]*}"
+	local lcp_interval="${keepalive##*[, ]}"
+	local lcp_adaptive="lcp-echo-adaptive"
+	[ "${lcp_failure:-0}" -lt 1 ] && lcp_failure=""
+	[ "$lcp_interval" != "$keepalive" ] || lcp_interval=5
+	[ "${keepalive_adaptive:-1}" -lt 1 ] && lcp_adaptive=""
+	[ -n "$connect" ] || json_get_var connect connect
+	[ -n "$disconnect" ] || json_get_var disconnect disconnect
+
+	proto_run_command "$config" /usr/sbin/pppd \
+		nodetach ipparam "$config" \
+		ifname "$pppname" \
+		${localip:+$localip:} \
+		${lcp_failure:+lcp-echo-interval $lcp_interval lcp-echo-failure $lcp_failure $lcp_adaptive} \
+		${ipv6:++ipv6} \
+		${autoipv6:+set AUTOIPV6=1} \
+		nodefaultroute \
+		usepeerdns \
+		$demand $persist maxfail $maxfail \
+		${holdoff:+holdoff "$holdoff"} \
+		${username:+user "$username" password "$password"} \
+		${connect:+connect "$connect"} \
+		${disconnect:+disconnect "$disconnect"} \
+		ip-up-script /lib/netifd/ppp-up \
+		ipv6-up-script /lib/netifd/ppp6-up \
+		ip-down-script /lib/netifd/ppp-down \
+		ipv6-down-script /lib/netifd/ppp-down \
+		${mtu:+mtu $mtu mru $mtu} \
+		"$@" $pppd_options
+}
+
+ppp_generic_teardown() {
+	local interface="$1"
+	local errorstring=$(ppp_exitcode_tostring $ERROR)
+
+	case "$ERROR" in
+		0)
+		;;
+		2)
+			proto_notify_error "$interface" "$errorstring"
+			proto_block_restart "$interface"
+		;;
+		11|19)
+			json_get_var authfail authfail
+			proto_notify_error "$interface" "$errorstring"
+			if [ "${authfail:-0}" -gt 0 ]; then
+				proto_block_restart "$interface"
+			fi
+		;;
+		*)
+			proto_notify_error "$interface" "$errorstring"
+		;;
+	esac
+
+	proto_kill_command "$interface"
+}
+
+# PPP on serial device
+
+proto_ppp_init_config() {
+	proto_config_add_string "device"
+	ppp_generic_init_config
+	no_device=1
+	available=1
+	lasterror=1
+}
+
+proto_ppp_setup() {
+	local config="$1"
+
+	json_get_var device device
+	ppp_generic_setup "$config" "$device"
+}
+
+proto_ppp_teardown() {
+	ppp_generic_teardown "$@"
+}
+
+proto_pppoe_init_config() {
+	ppp_generic_init_config
+	proto_config_add_string "ac"
+	proto_config_add_string "service"
+	proto_config_add_string "host_uniq"
+	lasterror=1
+}
+
+proto_pppoe_setup() {
+	local config="$1"
+	local iface="$2"
+
+	for module in slhc ppp_generic pppox pppoe; do
+		/sbin/insmod $module 2>&- >&-
+	done
+
+	json_get_var mtu mtu
+	mtu="${mtu:-1492}"
+
+	json_get_var ac ac
+	json_get_var service service
+	json_get_var host_uniq host_uniq
+
+	ppp_generic_setup "$config" \
+		plugin rp-pppoe.so \
+		${ac:+rp_pppoe_ac "$ac"} \
+		${service:+rp_pppoe_service "$service"} \
+		${host_uniq:+host-uniq "$host_uniq"} \
+		"nic-$iface"
+}
+
+proto_pppoe_teardown() {
+	ppp_generic_teardown "$@"
+}
+
+proto_pppoa_init_config() {
+	ppp_generic_init_config
+	proto_config_add_int "atmdev"
+	proto_config_add_int "vci"
+	proto_config_add_int "vpi"
+	proto_config_add_string "encaps"
+	no_device=1
+	available=1
+	lasterror=1
+}
+
+proto_pppoa_setup() {
+	local config="$1"
+	local iface="$2"
+
+	for module in slhc ppp_generic pppox pppoatm; do
+		/sbin/insmod $module 2>&- >&-
+	done
+
+	json_get_vars atmdev vci vpi encaps
+
+	case "$encaps" in
+		1|vc) encaps="vc-encaps" ;;
+		*) encaps="llc-encaps" ;;
+	esac
+
+	ppp_generic_setup "$config" \
+		plugin pppoatm.so \
+		${atmdev:+$atmdev.}${vpi:-8}.${vci:-35} \
+		${encaps}
+}
+
+proto_pppoa_teardown() {
+	ppp_generic_teardown "$@"
+}
+
+proto_pptp_init_config() {
+	ppp_generic_init_config
+	proto_config_add_string "server"
+	proto_config_add_string "interface"
+	available=1
+	no_device=1
+	lasterror=1
+}
+
+proto_pptp_setup() {
+	local config="$1"
+	local iface="$2"
+
+	local ip serv_addr server interface
+	json_get_vars interface server
+	[ -n "$server" ] && {
+		for ip in $(resolveip -t 5 "$server"); do
+			( proto_add_host_dependency "$config" "$ip" $interface )
+			serv_addr=1
+		done
+	}
+	[ -n "$serv_addr" ] || {
+		echo "Could not resolve server address"
+		sleep 5
+		proto_setup_failed "$config"
+		exit 1
+	}
+
+	local load
+	for module in slhc ppp_generic ppp_async ppp_mppe ip_gre gre pptp; do
+		grep -q "^$module " /proc/modules && continue
+		/sbin/insmod $module 2>&- >&-
+		load=1
+	done
+	[ "$load" = "1" ] && sleep 1
+
+	ppp_generic_setup "$config" \
+		plugin pptp.so \
+		pptp_server $server \
+		file /etc/ppp/options.pptp
+}
+
+proto_pptp_teardown() {
+	ppp_generic_teardown "$@"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol ppp
+	[ -f /usr/lib/pppd/*/rp-pppoe.so ] && add_protocol pppoe
+	[ -f /usr/lib/pppd/*/pppoatm.so ] && add_protocol pppoa
+	[ -f /usr/lib/pppd/*/pptp.so ] && add_protocol pptp
+}
+
diff --git a/package/network/services/ppp/patches/001-honor-ldflags.patch b/package/network/services/ppp/patches/001-honor-ldflags.patch
new file mode 100644
index 0000000000..1328811537
--- /dev/null
+++ b/package/network/services/ppp/patches/001-honor-ldflags.patch
@@ -0,0 +1,39 @@
+--- a/pppd/plugins/radius/Makefile.linux
++++ b/pppd/plugins/radius/Makefile.linux
+@@ -43,13 +43,13 @@ install: all
+ 	$(INSTALL) -c -m 444 pppd-radattr.8 $(MANDIR)
+ 
+ radius.so: radius.o libradiusclient.a
+-	$(CC) -o radius.so -shared radius.o libradiusclient.a
++	$(CC) $(COPTS) -o radius.so -shared radius.o libradiusclient.a
+ 
+ radattr.so: radattr.o
+-	$(CC) -o radattr.so -shared radattr.o
++	$(CC) $(COPTS) -o radattr.so -shared radattr.o
+ 
+ radrealms.so: radrealms.o
+-	$(CC) -o radrealms.so -shared radrealms.o
++	$(CC) $(COPTS) -o radrealms.so -shared radrealms.o
+ 
+ CLIENTOBJS = avpair.o buildreq.o config.o dict.o ip_util.o \
+ 	clientid.o sendserver.o lock.o util.o md5.o
+--- a/pppd/plugins/rp-pppoe/Makefile.linux
++++ b/pppd/plugins/rp-pppoe/Makefile.linux
+@@ -30,7 +30,7 @@ CFLAGS=$(COPTS) -I../../../include '-DRP
+ all: rp-pppoe.so pppoe-discovery
+ 
+ pppoe-discovery: pppoe-discovery.o debug.o
+-	$(CC) -o pppoe-discovery pppoe-discovery.o debug.o
++	$(CC) $(CFLAGS) -o pppoe-discovery pppoe-discovery.o debug.o
+ 
+ pppoe-discovery.o: pppoe-discovery.c
+ 	$(CC) $(CFLAGS) -c -o pppoe-discovery.o pppoe-discovery.c
+@@ -39,7 +39,7 @@ debug.o: debug.c
+ 	$(CC) $(CFLAGS) -c -o debug.o debug.c
+ 
+ rp-pppoe.so: plugin.o discovery.o if.o common.o
+-	$(CC) -o rp-pppoe.so -shared plugin.o discovery.o if.o common.o
++	$(CC) $(CFLAGS) -o rp-pppoe.so -shared plugin.o discovery.o if.o common.o
+ 
+ install: all
+ 	$(INSTALL) -d -m 755 $(LIBDIR)
diff --git a/package/network/services/ppp/patches/010-use_target_for_configure.patch b/package/network/services/ppp/patches/010-use_target_for_configure.patch
new file mode 100644
index 0000000000..7deac0e446
--- /dev/null
+++ b/package/network/services/ppp/patches/010-use_target_for_configure.patch
@@ -0,0 +1,24 @@
+configure: Allow overriding uname results
+
+In a cross compile setting it makes no sense to rely on the "uname" values
+reported by the build host system. This patch allows overriding the
+"uname -r", "uname -s" and "uname -m" results with the "UNAME_R", "UNAME_S"
+and "UNAME_M" environment variables.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/configure
++++ b/configure
+@@ -8,9 +8,9 @@ SYSCONF=/etc
+ #  if [ -d /NextApps ]; then
+ #    system="NeXTStep"
+ #  else
+-  system=`uname -s`
+-  release=`uname -r`
+-  arch=`uname -m`
++  system=${UNAME_S:-`uname -s`}
++  release=${UNAME_R:-`uname -r`}
++  arch=${UNAME_M:-`uname -m`}
+ #  fi
+ state="unknown"
+ 
diff --git a/package/network/services/ppp/patches/100-debian_ip-ip_option.patch b/package/network/services/ppp/patches/100-debian_ip-ip_option.patch
new file mode 100644
index 0000000000..703311fb47
--- /dev/null
+++ b/package/network/services/ppp/patches/100-debian_ip-ip_option.patch
@@ -0,0 +1,96 @@
+pppd: Allow specifying ip-up and ip-down scripts
+
+This patch implements the "ip-up-script" and "ip-down-script" options which
+allow to specify the path of the ip-up and ip-down scripts to call.
+
+These options default to _PATH_IPUP and _PATH_IPDOWN to retain the 
+existing behaviour.
+
+The patch originated from the Debian project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/ipcp.c
++++ b/pppd/ipcp.c
+@@ -1958,7 +1958,7 @@ ipcp_up(f)
+      */
+     if (ipcp_script_state == s_down && ipcp_script_pid == 0) {
+ 	ipcp_script_state = s_up;
+-	ipcp_script(_PATH_IPUP, 0);
++	ipcp_script(path_ipup, 0);
+     }
+ }
+ 
+@@ -2008,7 +2008,7 @@ ipcp_down(f)
+     /* Execute the ip-down script */
+     if (ipcp_script_state == s_up && ipcp_script_pid == 0) {
+ 	ipcp_script_state = s_down;
+-	ipcp_script(_PATH_IPDOWN, 0);
++	ipcp_script(path_ipdown, 0);
+     }
+ }
+ 
+@@ -2062,13 +2062,13 @@ ipcp_script_done(arg)
+     case s_up:
+ 	if (ipcp_fsm[0].state != OPENED) {
+ 	    ipcp_script_state = s_down;
+-	    ipcp_script(_PATH_IPDOWN, 0);
++	    ipcp_script(path_ipdown, 0);
+ 	}
+ 	break;
+     case s_down:
+ 	if (ipcp_fsm[0].state == OPENED) {
+ 	    ipcp_script_state = s_up;
+-	    ipcp_script(_PATH_IPUP, 0);
++	    ipcp_script(path_ipup, 0);
+ 	}
+ 	break;
+     }
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -316,6 +316,9 @@ main(argc, argv)
+     struct protent *protp;
+     char numbuf[16];
+ 
++    strlcpy(path_ipup, _PATH_IPUP, sizeof(path_ipup));
++    strlcpy(path_ipdown, _PATH_IPDOWN, sizeof(path_ipdown));
++
+     link_stats_valid = 0;
+     new_phase(PHASE_INITIALIZE);
+ 
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -114,6 +114,8 @@ char	linkname[MAXPATHLEN];	/* logical na
+ bool	tune_kernel;		/* may alter kernel settings */
+ int	connect_delay = 1000;	/* wait this many ms after connect script */
+ int	req_unit = -1;		/* requested interface unit */
++char	path_ipup[MAXPATHLEN];	/* pathname of ip-up script */
++char	path_ipdown[MAXPATHLEN];/* pathname of ip-down script */
+ bool	multilink = 0;		/* Enable multilink operation */
+ char	*bundle_name = NULL;	/* bundle name for multilink */
+ bool	dump_options;		/* print out option values */
+@@ -299,6 +301,13 @@ option_t general_options[] = {
+       "Unset user environment variable",
+       OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint },
+ 
++    { "ip-up-script", o_string, path_ipup,
++      "Set pathname of ip-up script",
++      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
++    { "ip-down-script", o_string, path_ipdown,
++      "Set pathname of ip-down script",
++      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
++
+ #ifdef HAVE_MULTILINK
+     { "multilink", o_bool, &multilink,
+       "Enable multilink operation", OPT_PRIO | 1 },
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -318,6 +318,8 @@ extern bool	tune_kernel;	/* May alter ke
+ extern int	connect_delay;	/* Time to delay after connect script */
+ extern int	max_data_rate;	/* max bytes/sec through charshunt */
+ extern int	req_unit;	/* interface unit number to use */
++extern char	path_ipup[MAXPATHLEN]; /* pathname of ip-up script */
++extern char	path_ipdown[MAXPATHLEN]; /* pathname of ip-down script */
+ extern bool	multilink;	/* enable multilink operation */
+ extern bool	noendpoint;	/* don't send or accept endpt. discrim. */
+ extern char	*bundle_name;	/* bundle name for multilink */
diff --git a/package/network/services/ppp/patches/101-debian_close_dev_ppp.patch b/package/network/services/ppp/patches/101-debian_close_dev_ppp.patch
new file mode 100644
index 0000000000..629c232543
--- /dev/null
+++ b/package/network/services/ppp/patches/101-debian_close_dev_ppp.patch
@@ -0,0 +1,28 @@
+pppd: Close already open ppp descriptors
+
+When using the kernel PPPoE driver in conjunction with the "persist" option,
+the already open descriptor to /dev/ppp is not closed when the link is
+reestablished. This eventually leads to high CPU load because the stray 
+descriptors are always reported as ready by select().
+
+This patch closes the descriptor if it is already open when establishing a
+new connection. It originated from the Debian project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -458,6 +458,13 @@ int generic_establish_ppp (int fd)
+     if (new_style_driver) {
+ 	int flags;
+ 
++        /* if a ppp_fd is already open, close it first */
++        if(ppp_fd > 0) {
++          close(ppp_fd);
++          remove_fd(ppp_fd);
++          ppp_fd = -1;
++        }
++
+ 	/* Open an instance of /dev/ppp and connect the channel to it */
+ 	if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) {
+ 	    error("Couldn't get channel number: %m");
diff --git a/package/network/services/ppp/patches/103-debian_fix_link_pidfile.patch b/package/network/services/ppp/patches/103-debian_fix_link_pidfile.patch
new file mode 100644
index 0000000000..d5d5851d47
--- /dev/null
+++ b/package/network/services/ppp/patches/103-debian_fix_link_pidfile.patch
@@ -0,0 +1,23 @@
+pppd: Fix creation of linkpidfile
+
+When pppd is run without "nodetach" or with "updetach", the linkpidfile is
+never created. The call to create_linkpidfile() is protected by a check for
+linkpidfile[0] but this is only filled in when create_linkpidfile() is called.
+
+This patch changes to code to allways uncondiationally call
+create_linkpidfile(), it originated from the Debian project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -773,8 +773,7 @@ detach()
+ 	/* update pid files if they have been written already */
+ 	if (pidfilename[0])
+ 	    create_pidfile(pid);
+-	if (linkpidfile[0])
+-	    create_linkpidfile(pid);
++	create_linkpidfile(pid);
+ 	exit(0);		/* parent dies */
+     }
+     setsid();
diff --git a/package/network/services/ppp/patches/105-debian_demand.patch b/package/network/services/ppp/patches/105-debian_demand.patch
new file mode 100644
index 0000000000..2502d49689
--- /dev/null
+++ b/package/network/services/ppp/patches/105-debian_demand.patch
@@ -0,0 +1,172 @@
+--- a/pppd/demand.c
++++ b/pppd/demand.c
+@@ -36,6 +36,8 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <netdb.h>
++#include <unistd.h>
++#include <syslog.h>
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+@@ -43,6 +45,8 @@
+ #include <sys/resource.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
+ #ifdef PPP_FILTER
+ #include <pcap-bpf.h>
+ #endif
+@@ -221,6 +225,14 @@ loop_chars(p, n)
+     int c, rv;
+ 
+     rv = 0;
++
++/* check for synchronous connection... */
++
++    if ( (p[0] == 0xFF) && (p[1] == 0x03) ) {
++        rv = loop_frame(p,n);
++        return rv;
++    }
++
+     for (; n > 0; --n) {
+ 	c = *p++;
+ 	if (c == PPP_FLAG) {
+@@ -299,17 +311,102 @@ loop_frame(frame, len)
+  * loopback, now that the real serial link is up.
+  */
+ void
+-demand_rexmit(proto)
++demand_rexmit(proto, newip)
+     int proto;
++    u_int32_t newip;
+ {
+     struct packet *pkt, *prev, *nextpkt;
++    unsigned short checksum;
++    unsigned short pkt_checksum = 0;
++    unsigned iphdr;
++    struct timeval tv;
++    char cv = 0;
++    char ipstr[16];
+ 
+     prev = NULL;
+     pkt = pend_q;
+     pend_q = NULL;
++    tv.tv_sec = 1;
++    tv.tv_usec = 0;
++    select(0,NULL,NULL,NULL,&tv);	/* Sleep for 1 Seconds */
+     for (; pkt != NULL; pkt = nextpkt) {
+ 	nextpkt = pkt->next;
+ 	if (PPP_PROTOCOL(pkt->data) == proto) {
++            if ( (proto == PPP_IP) && newip ) {
++		/* Get old checksum */
++
++		iphdr = (pkt->data[4] & 15) << 2;
++		checksum = *((unsigned short *) (pkt->data+14));
++                if (checksum == 0xFFFF) {
++                    checksum = 0;
++                }
++
++ 
++                if (pkt->data[13] == 17) {
++                    pkt_checksum =  *((unsigned short *) (pkt->data+10+iphdr));
++		    if (pkt_checksum) {
++                        cv = 1;
++                        if (pkt_checksum == 0xFFFF) {
++                            pkt_checksum = 0;
++                        }
++                    }
++                    else {
++                       cv = 0;
++                    }
++                }
++
++		if (pkt->data[13] == 6) {
++		    pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr));
++		    cv = 1;
++                    if (pkt_checksum == 0xFFFF) {
++                        pkt_checksum = 0;
++                    }
++		}
++
++		/* Delete old Source-IP-Address */
++                checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++                checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++		pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++		pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++		/* Change Source-IP-Address */
++                * ((u_int32_t *) (pkt->data + 16)) = newip;
++
++		/* Add new Source-IP-Address */
++                checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++                checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++                pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++                pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++		/* Write new checksum */
++                if (!checksum) {
++                    checksum = 0xFFFF;
++                }
++                *((unsigned short *) (pkt->data+14)) = checksum;
++		if (pkt->data[13] == 6) {
++		    *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum;
++		}
++		if (cv && (pkt->data[13] == 17) ) {
++		    *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum;
++		}
++
++		/* Log Packet */
++		strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16))));
++		if (pkt->data[13] == 1) {
++		    syslog(LOG_INFO,"Open ICMP %s -> %s\n",
++			ipstr,
++			inet_ntoa(*( (struct in_addr *) (pkt->data+20))));
++		} else {
++		    syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n",
++			pkt->data[13] == 6 ? "TCP" : "UDP",
++			ipstr,
++			ntohs(*( (short *) (pkt->data+iphdr+4))),
++			inet_ntoa(*( (struct in_addr *) (pkt->data+20))),
++			ntohs(*( (short *) (pkt->data+iphdr+6))));
++                }
++            }
+ 	    output(0, pkt->data, pkt->length);
+ 	    free(pkt);
+ 	} else {
+--- a/pppd/ipcp.c
++++ b/pppd/ipcp.c
+@@ -1883,7 +1883,7 @@ ipcp_up(f)
+ 		    proxy_arp_set[f->unit] = 1;
+ 
+ 	}
+-	demand_rexmit(PPP_IP);
++	demand_rexmit(PPP_IP,go->ouraddr);
+ 	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+ 
+     } else {
+--- a/pppd/ipv6cp.c
++++ b/pppd/ipv6cp.c
+@@ -1232,7 +1232,7 @@ ipv6cp_up(f)
+ 	    }
+ 
+ 	}
+-	demand_rexmit(PPP_IPV6);
++	demand_rexmit(PPP_IPV6,0);
+ 	sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+ 
+     } else {
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -585,7 +585,7 @@ void demand_conf __P((void));	/* config
+ void demand_block __P((void));	/* set all NPs to queue up packets */
+ void demand_unblock __P((void)); /* set all NPs to pass packets */
+ void demand_discard __P((void)); /* set all NPs to discard packets */
+-void demand_rexmit __P((int));	/* retransmit saved frames for an NP */
++void demand_rexmit __P((int, u_int32_t)); /* retransmit saved frames for an NP*/
+ int  loop_chars __P((unsigned char *, int)); /* process chars from loopback */
+ int  loop_frame __P((unsigned char *, int)); /* should we bring link up? */
+ 
diff --git a/package/network/services/ppp/patches/106-debian_stripMSdomain.patch b/package/network/services/ppp/patches/106-debian_stripMSdomain.patch
new file mode 100644
index 0000000000..376de64c43
--- /dev/null
+++ b/package/network/services/ppp/patches/106-debian_stripMSdomain.patch
@@ -0,0 +1,47 @@
+pppd: Implement option to strip domain part from MS CHAP response
+
+This patch implements a new boolean option "chapms-strip-domain" which
+strips the leading domain part of the username in a received MS Chap
+response.
+
+When the option is set, all leading chars up to and including the last
+backslash in the username are stripped. The option defaults to false.
+
+The patch originated from the Debian project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/chap-new.c
++++ b/pppd/chap-new.c
+@@ -58,6 +58,7 @@ int (*chap_verify_hook)(char *name, char
+ int chap_timeout_time = 3;
+ int chap_max_transmits = 10;
+ int chap_rechallenge_time = 0;
++int chapms_strip_domain = 0;
+ 
+ /*
+  * Command-line options.
+@@ -69,6 +70,8 @@ static option_t chap_option_list[] = {
+ 	  "Set max #xmits for challenge", OPT_PRIO },
+ 	{ "chap-interval", o_int, &chap_rechallenge_time,
+ 	  "Set interval for rechallenge", OPT_PRIO },
++	{ "chapms-strip-domain", o_bool, &chapms_strip_domain,
++	  "Strip the domain prefix before the Username", 1 },
+ 	{ NULL }
+ };
+ 
+@@ -336,6 +339,14 @@ chap_handle_response(struct chap_server_
+ 			/* Null terminate and clean remote name. */
+ 			slprintf(rname, sizeof(rname), "%.*v", len, name);
+ 			name = rname;
++
++			/* strip the MS domain name */
++			if (chapms_strip_domain && strrchr(rname, '\\')) {
++				char tmp[MAXNAMELEN+1];
++
++				strcpy(tmp, strrchr(rname, '\\') + 1);
++				strcpy(rname, tmp);
++			}
+ 		}
+ 
+ 		if (chap_verify_hook)
diff --git a/package/network/services/ppp/patches/107-debian_pppoatm_wildcard.patch b/package/network/services/ppp/patches/107-debian_pppoatm_wildcard.patch
new file mode 100644
index 0000000000..6f559a1231
--- /dev/null
+++ b/package/network/services/ppp/patches/107-debian_pppoatm_wildcard.patch
@@ -0,0 +1,25 @@
+pppoatm: Allow wildcard ATM devices
+
+When operating pppd's pppoatm plugin with an USB ADSL modem, e.g. an
+Alcatel Speedtouch, the ATM device number might change when the modem is
+reconnected to the USB port or when the host controller resets the USB
+device.
+
+This patch allows to specify the ATM device as wildcard which gives
+enough flexibility to cope with changing device names.
+
+The patch originated from the Debain project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/plugins/pppoatm/pppoatm.c
++++ b/pppd/plugins/pppoatm/pppoatm.c
+@@ -75,7 +75,7 @@ static int setdevname_pppoatm(const char
+ 	//info("PPPoATM setdevname_pppoatm: '%s'", cp);
+ 	memset(&addr, 0, sizeof addr);
+ 	if (text2atm(cp, (struct sockaddr *) &addr, sizeof(addr),
+-	    T2A_PVC | T2A_NAME) < 0) {
++	    T2A_PVC | T2A_NAME | T2A_WILDCARD) < 0) {
+                if(doit)
+                    info("atm does not recognize: %s", cp);
+ 		return 0;
diff --git a/package/network/services/ppp/patches/110-debian_defaultroute.patch b/package/network/services/ppp/patches/110-debian_defaultroute.patch
new file mode 100644
index 0000000000..1005c59ab5
--- /dev/null
+++ b/package/network/services/ppp/patches/110-debian_defaultroute.patch
@@ -0,0 +1,313 @@
+pppd: Add "replacedefaultroute" and "noreplacedefaultroute" options
+
+This patch implements two new options, "replacedefaultroute" to replace any
+existing system default route when specified and "noreplacedefaultroute" to
+disable the "replacedefaultroute" option, which is useful in multi user
+environments where the administrator wants to allow users to dial pppd
+connections but not allow them to change the system default route.
+
+The patch originated from the Debian project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/ipcp.c
++++ b/pppd/ipcp.c
+@@ -198,6 +198,14 @@ static option_t ipcp_option_list[] = {
+       "disable defaultroute option", OPT_ALIAS | OPT_A2CLR,
+       &ipcp_wantoptions[0].default_route },
+ 
++    { "replacedefaultroute", o_bool,
++				&ipcp_wantoptions[0].replace_default_route,
++      "Replace default route", 1
++    },
++    { "noreplacedefaultroute", o_bool,
++				&ipcp_allowoptions[0].replace_default_route,
++      "Never replace default route", OPT_A2COPY,
++				&ipcp_wantoptions[0].replace_default_route },
+     { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
+       "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
+     { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+@@ -271,7 +279,7 @@ struct protent ipcp_protent = {
+     ip_active_pkt
+ };
+ 
+-static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t));
++static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t, bool));
+ static void ipcp_script __P((char *, int));	/* Run an up/down script */
+ static void ipcp_script_done __P((void *));
+ 
+@@ -1761,7 +1769,8 @@ ip_demand_conf(u)
+     if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+ 	return 0;
+     if (wo->default_route)
+-	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
++	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr,
++		wo->replace_default_route))
+ 	    default_route_set[u] = 1;
+     if (wo->proxy_arp)
+ 	if (sifproxyarp(u, wo->hisaddr))
+@@ -1849,7 +1858,8 @@ ipcp_up(f)
+      */
+     if (demand) {
+ 	if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+-	    ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
++	    ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr,
++				      wo->replace_default_route);
+ 	    if (go->ouraddr != wo->ouraddr) {
+ 		warn("Local IP address changed to %I", go->ouraddr);
+ 		script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
+@@ -1874,7 +1884,8 @@ ipcp_up(f)
+ 
+ 	    /* assign a default route through the interface if required */
+ 	    if (ipcp_wantoptions[f->unit].default_route) 
+-		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
++		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr,
++			wo->replace_default_route))
+ 		    default_route_set[f->unit] = 1;
+ 
+ 	    /* Make a proxy ARP entry if requested. */
+@@ -1924,7 +1935,8 @@ ipcp_up(f)
+ 
+ 	/* assign a default route through the interface if required */
+ 	if (ipcp_wantoptions[f->unit].default_route) 
+-	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
++	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr,
++		    wo->replace_default_route))
+ 		default_route_set[f->unit] = 1;
+ 
+ 	/* Make a proxy ARP entry if requested. */
+@@ -2002,7 +2014,7 @@ ipcp_down(f)
+ 	sifnpmode(f->unit, PPP_IP, NPMODE_DROP);
+ 	sifdown(f->unit);
+ 	ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr,
+-			 ipcp_hisoptions[f->unit].hisaddr);
++			 ipcp_hisoptions[f->unit].hisaddr, 0);
+     }
+ 
+     /* Execute the ip-down script */
+@@ -2018,16 +2030,25 @@ ipcp_down(f)
+  * proxy arp entries, etc.
+  */
+ static void
+-ipcp_clear_addrs(unit, ouraddr, hisaddr)
++ipcp_clear_addrs(unit, ouraddr, hisaddr, replacedefaultroute)
+     int unit;
+     u_int32_t ouraddr;  /* local address */
+     u_int32_t hisaddr;  /* remote address */
++    bool replacedefaultroute;
+ {
+     if (proxy_arp_set[unit]) {
+ 	cifproxyarp(unit, hisaddr);
+ 	proxy_arp_set[unit] = 0;
+     }
+-    if (default_route_set[unit]) {
++    /* If replacedefaultroute, sifdefaultroute will be called soon
++     * with replacedefaultroute set and that will overwrite the current
++     * default route. This is the case only when doing demand, otherwise
++     * during demand, this cifdefaultroute would restore the old default
++     * route which is not what we want in this case. In the non-demand
++     * case, we'll delete the default route and restore the old if there
++     * is one saved by an sifdefaultroute with replacedefaultroute.
++     */
++    if (!replacedefaultroute && default_route_set[unit]) {
+ 	cifdefaultroute(unit, ouraddr, hisaddr);
+ 	default_route_set[unit] = 0;
+     }
+--- a/pppd/ipcp.h
++++ b/pppd/ipcp.h
+@@ -70,6 +70,7 @@ typedef struct ipcp_options {
+     bool old_addrs;		/* Use old (IP-Addresses) option? */
+     bool req_addr;		/* Ask peer to send IP address? */
+     bool default_route;		/* Assign default route through interface? */
++    bool replace_default_route;	/* Replace default route through interface? */
+     bool proxy_arp;		/* Make proxy ARP entry for peer? */
+     bool neg_vj;		/* Van Jacobson Compression? */
+     bool old_vj;		/* use old (short) form of VJ option? */
+--- a/pppd/pppd.8
++++ b/pppd/pppd.8
+@@ -121,6 +121,11 @@ the gateway, when IPCP negotiation is su
+ This entry is removed when the PPP connection is broken.  This option
+ is privileged if the \fInodefaultroute\fR option has been specified.
+ .TP
++.B replacedefaultroute
++This option is a flag to the defaultroute option. If defaultroute is
++set and this flag is also set, pppd replaces an existing default route
++with the new default route.
++.TP
+ .B disconnect \fIscript
+ Execute the command specified by \fIscript\fR, by passing it to a
+ shell, after
+@@ -734,7 +739,12 @@ disable both forms of hardware flow cont
+ .TP
+ .B nodefaultroute
+ Disable the \fIdefaultroute\fR option.  The system administrator who
+-wishes to prevent users from creating default routes with pppd
++wishes to prevent users from adding a default route with pppd
++can do so by placing this option in the /etc/ppp/options file.
++.TP
++.B noreplacedefaultroute
++Disable the \fIreplacedefaultroute\fR option. The system administrator who
++wishes to prevent users from replacing a default route with pppd
+ can do so by placing this option in the /etc/ppp/options file.
+ .TP
+ .B nodeflate
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -667,7 +667,7 @@ int  sif6addr __P((int, eui64_t, eui64_t
+ int  cif6addr __P((int, eui64_t, eui64_t));
+ 				/* Remove an IPv6 address from i/f */
+ #endif
+-int  sifdefaultroute __P((int, u_int32_t, u_int32_t));
++int  sifdefaultroute __P((int, u_int32_t, u_int32_t, bool replace_default_rt));
+ 				/* Create default route through i/f */
+ int  cifdefaultroute __P((int, u_int32_t, u_int32_t));
+ 				/* Delete default route through i/f */
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -207,6 +207,8 @@ static unsigned char inbuf[512]; /* buff
+ static int	if_is_up;	/* Interface has been marked up */
+ static int	if6_is_up;	/* Interface has been marked up for IPv6, to help differentiate */
+ static int	have_default_route;	/* Gateway for default route added */
++static struct	rtentry old_def_rt;	/* Old default route */
++static int	default_rt_repl_rest;	/* replace and restore old default rt */
+ static u_int32_t proxy_arp_addr;	/* Addr for proxy arp entry added */
+ static char proxy_arp_dev[16];		/* Device for proxy arp entry */
+ static u_int32_t our_old_addr;		/* for detecting address changes */
+@@ -1552,6 +1554,9 @@ static int read_route_table(struct rtent
+ 	p = NULL;
+     }
+ 
++    SET_SA_FAMILY (rt->rt_dst,     AF_INET);
++    SET_SA_FAMILY (rt->rt_gateway, AF_INET);
++
+     SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+     SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+     SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+@@ -1621,20 +1626,51 @@ int have_route_to(u_int32_t addr)
+ /********************************************************************
+  *
+  * sifdefaultroute - assign a default route through the address given.
+- */
+-
+-int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+-{
+-    struct rtentry rt;
+-
+-    if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+-	if (rt.rt_flags & RTF_GATEWAY)
+-	    error("not replacing existing default route via %I",
+-		  SIN_ADDR(rt.rt_gateway));
+-	else
++ *
++ * If the global default_rt_repl_rest flag is set, then this function
++ * already replaced the original system defaultroute with some other
++ * route and it should just replace the current defaultroute with
++ * another one, without saving the current route. Use: demand mode,
++ * when pppd sets first a defaultroute it it's temporary ppp0 addresses
++ * and then changes the temporary addresses to the addresses for the real
++ * ppp connection when it has come up.
++ */
++
++int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway, bool replace)
++{
++    struct rtentry rt, tmp_rt;
++    struct rtentry *del_rt = NULL;
++
++    if (default_rt_repl_rest) {
++	/* We have already reclaced the original defaultroute, if we
++	   are called again, we will delete the current default route
++	   and set the new default route in this function.
++	   - this is normally only the case the doing demand: */
++	if (defaultroute_exists(&tmp_rt))
++	    del_rt = &tmp_rt;
++    } else if (defaultroute_exists(&old_def_rt) &&
++	       strcmp(old_def_rt.rt_dev, ifname) != 0) {
++	/* We did not yet replace an existing default route, let's
++	   check if we should save and replace a default route: */
++	if (old_def_rt.rt_flags & RTF_GATEWAY) {
++	    if (!replace) {
++		error("not replacing existing default route via %I",
++		      SIN_ADDR(old_def_rt.rt_gateway));
++		return 0;
++	    } else {
++		/* we need to copy rt_dev because we need it permanent too: */
++		char *tmp_dev = malloc(strlen(old_def_rt.rt_dev) + 1);
++		strcpy(tmp_dev, old_def_rt.rt_dev);
++		old_def_rt.rt_dev = tmp_dev;
++
++		notice("replacing old default route to %s [%I]",
++			old_def_rt.rt_dev, SIN_ADDR(old_def_rt.rt_gateway));
++		default_rt_repl_rest = 1;
++		del_rt = &old_def_rt;
++	    }
++	} else
+ 	    error("not replacing existing default route through %s",
+-		  rt.rt_dev);
+-	return 0;
++		  old_def_rt.rt_dev);
+     }
+ 
+     memset (&rt, 0, sizeof (rt));
+@@ -1649,10 +1685,16 @@ int sifdefaultroute (int unit, u_int32_t
+ 
+     rt.rt_flags = RTF_UP;
+     if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+-	if ( ! ok_error ( errno ))
++	if (!ok_error(errno))
+ 	    error("default route ioctl(SIOCADDRT): %m");
+ 	return 0;
+     }
++    if (default_rt_repl_rest && del_rt)
++        if (ioctl(sock_fd, SIOCDELRT, del_rt) < 0) {
++	    if (!ok_error(errno))
++	        error("del old default route ioctl(SIOCDELRT): %m");
++	    return 0;
++        }
+ 
+     have_default_route = 1;
+     return 1;
+@@ -1683,11 +1725,21 @@ int cifdefaultroute (int unit, u_int32_t
+     rt.rt_flags = RTF_UP;
+     if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ 	if (still_ppp()) {
+-	    if ( ! ok_error ( errno ))
++	    if (!ok_error(errno))
+ 		error("default route ioctl(SIOCDELRT): %m");
+ 	    return 0;
+ 	}
+     }
++    if (default_rt_repl_rest) {
++	notice("restoring old default route to %s [%I]",
++		old_def_rt.rt_dev, SIN_ADDR(old_def_rt.rt_gateway));
++        if (ioctl(sock_fd, SIOCADDRT, &old_def_rt) < 0) {
++	    if (!ok_error(errno))
++	        error("restore default route ioctl(SIOCADDRT): %m");
++	    return 0;
++        }
++        default_rt_repl_rest = 0;
++    }
+ 
+     return 1;
+ }
+--- a/pppd/sys-solaris.c
++++ b/pppd/sys-solaris.c
+@@ -2039,12 +2039,18 @@ cifaddr(u, o, h)
+  * sifdefaultroute - assign a default route through the address given.
+  */
+ int
+-sifdefaultroute(u, l, g)
++sifdefaultroute(u, l, g, replace)
+     int u;
+     u_int32_t l, g;
++    bool replace;
+ {
+     struct rtentry rt;
+ 
++    if (replace) {
++	error("replacedefaultroute not supported on this platform");
++	return 0;
++    }
++
+ #if defined(__USLC__)
+     g = l;			/* use the local address as gateway */
+ #endif
diff --git a/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch b/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch
new file mode 100644
index 0000000000..a575df5f54
--- /dev/null
+++ b/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch
@@ -0,0 +1,95 @@
+pppd: Allow specifying ipv6-up and ipv6-down scripts
+
+This patch implements the "ipv6-up-script" and "ipv6-down-script" options
+which allow to specify the path of the ipv6-up and ipv6-down scripts to call.
+
+These options default to _PATH_IPV6UP and _PATH_IPV6DOWN to retain the
+existing behaviour.
+
+The patch originated from the Debian project.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -318,6 +318,8 @@ main(argc, argv)
+ 
+     strlcpy(path_ipup, _PATH_IPUP, sizeof(path_ipup));
+     strlcpy(path_ipdown, _PATH_IPDOWN, sizeof(path_ipdown));
++    strlcpy(path_ipv6up, _PATH_IPV6UP, sizeof(path_ipv6up));
++    strlcpy(path_ipv6down, _PATH_IPV6DOWN, sizeof(path_ipv6down));
+ 
+     link_stats_valid = 0;
+     new_phase(PHASE_INITIALIZE);
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -116,6 +116,8 @@ int	connect_delay = 1000;	/* wait this m
+ int	req_unit = -1;		/* requested interface unit */
+ char	path_ipup[MAXPATHLEN];	/* pathname of ip-up script */
+ char	path_ipdown[MAXPATHLEN];/* pathname of ip-down script */
++char	path_ipv6up[MAXPATHLEN];	/* pathname of ipv6-up script */
++char	path_ipv6down[MAXPATHLEN];/* pathname of ipv6-down script */
+ bool	multilink = 0;		/* Enable multilink operation */
+ char	*bundle_name = NULL;	/* bundle name for multilink */
+ bool	dump_options;		/* print out option values */
+@@ -308,6 +310,13 @@ option_t general_options[] = {
+       "Set pathname of ip-down script",
+       OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
+ 
++    { "ipv6-up-script", o_string, path_ipv6up,
++      "Set pathname of ipv6-up script",
++      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
++    { "ipv6-down-script", o_string, path_ipv6down,
++      "Set pathname of ipv6-down script",
++      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
++
+ #ifdef HAVE_MULTILINK
+     { "multilink", o_bool, &multilink,
+       "Enable multilink operation", OPT_PRIO | 1 },
+--- a/pppd/ipv6cp.c
++++ b/pppd/ipv6cp.c
+@@ -1269,7 +1269,7 @@ ipv6cp_up(f)
+      */
+     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
+ 	ipv6cp_script_state = s_up;
+-	ipv6cp_script(_PATH_IPV6UP);
++	ipv6cp_script(path_ipv6up);
+     }
+ }
+ 
+@@ -1321,7 +1321,7 @@ ipv6cp_down(f)
+     /* Execute the ipv6-down script */
+     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
+ 	ipv6cp_script_state = s_down;
+-	ipv6cp_script(_PATH_IPV6DOWN);
++	ipv6cp_script(path_ipv6down);
+     }
+ }
+ 
+@@ -1364,13 +1364,13 @@ ipv6cp_script_done(arg)
+     case s_up:
+ 	if (ipv6cp_fsm[0].state != OPENED) {
+ 	    ipv6cp_script_state = s_down;
+-	    ipv6cp_script(_PATH_IPV6DOWN);
++	    ipv6cp_script(path_ipv6down);
+ 	}
+ 	break;
+     case s_down:
+ 	if (ipv6cp_fsm[0].state == OPENED) {
+ 	    ipv6cp_script_state = s_up;
+-	    ipv6cp_script(_PATH_IPV6UP);
++	    ipv6cp_script(path_ipv6up);
+ 	}
+ 	break;
+     }
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -320,6 +320,8 @@ extern int	max_data_rate;	/* max bytes/s
+ extern int	req_unit;	/* interface unit number to use */
+ extern char	path_ipup[MAXPATHLEN]; /* pathname of ip-up script */
+ extern char	path_ipdown[MAXPATHLEN]; /* pathname of ip-down script */
++extern char	path_ipv6up[MAXPATHLEN]; /* pathname of ipv6-up script */
++extern char	path_ipv6down[MAXPATHLEN]; /* pathname of ipv6-down script */
+ extern bool	multilink;	/* enable multilink operation */
+ extern bool	noendpoint;	/* don't send or accept endpt. discrim. */
+ extern char	*bundle_name;	/* bundle name for multilink */
diff --git a/package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch b/package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch
new file mode 100644
index 0000000000..b7a62406d0
--- /dev/null
+++ b/package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch
@@ -0,0 +1,56 @@
+--- a/pppd/lcp.c
++++ b/pppd/lcp.c
+@@ -73,6 +73,7 @@ static void lcp_delayed_up __P((void *))
+  */
+ int	lcp_echo_interval = 0; 	/* Interval between LCP echo-requests */
+ int	lcp_echo_fails = 0;	/* Tolerance to unanswered echo-requests */
++bool	lcp_echo_adaptive = 0;	/* request echo only if the link was idle */
+ bool	lax_recv = 0;		/* accept control chars in asyncmap */
+ bool	noendpoint = 0;		/* don't send/accept endpoint discriminator */
+ 
+@@ -151,6 +152,8 @@ static option_t lcp_option_list[] = {
+       OPT_PRIO },
+     { "lcp-echo-interval", o_int, &lcp_echo_interval,
+       "Set time in seconds between LCP echo requests", OPT_PRIO },
++    { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive,
++      "Suppress LCP echo requests if traffic was received", 1 },
+     { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
+       "Set time in seconds between LCP retransmissions", OPT_PRIO },
+     { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
+@@ -2331,6 +2334,22 @@ LcpSendEchoRequest (f)
+ 	}
+     }
+ 
++    /*
++     * If adaptive echos have been enabled, only send the echo request if
++     * no traffic was received since the last one.
++     */
++    if (lcp_echo_adaptive) {
++	static unsigned int last_pkts_in = 0;
++
++	update_link_stats(f->unit);
++	link_stats_valid = 0;
++
++	if (link_stats.pkts_in != last_pkts_in) {
++	    last_pkts_in = link_stats.pkts_in;
++	    return;
++	}
++    }
++
+     /*
+      * Make and send the echo request frame.
+      */
+--- a/pppd/pppd.8
++++ b/pppd/pppd.8
+@@ -563,6 +563,11 @@ to 1) if the \fIproxyarp\fR option is us
+ dynamic IP address option (i.e. set /proc/sys/net/ipv4/ip_dynaddr to
+ 1) in demand mode if the local address changes.
+ .TP
++.B lcp\-echo\-adaptive
++If this option is used with the \fIlcp\-echo\-failure\fR option then
++pppd will send LCP echo\-request frames only if no traffic was received
++from the peer since the last echo\-request was sent.
++.TP
+ .B lcp\-echo\-failure \fIn
+ If this option is given, pppd will presume the peer to be dead
+ if \fIn\fR LCP echo\-requests are sent without receiving a valid LCP
diff --git a/package/network/services/ppp/patches/130-no_cdefs_h.patch b/package/network/services/ppp/patches/130-no_cdefs_h.patch
new file mode 100644
index 0000000000..caa892ec6b
--- /dev/null
+++ b/package/network/services/ppp/patches/130-no_cdefs_h.patch
@@ -0,0 +1,11 @@
+--- a/pppd/plugins/rp-pppoe/config.h
++++ b/pppd/plugins/rp-pppoe/config.h
+@@ -102,7 +102,7 @@
+ #define HAVE_NETPACKET_PACKET_H 1
+ 
+ /* Define if you have the <sys/cdefs.h> header file.  */
+-#define HAVE_SYS_CDEFS_H 1
++/* #undef HAVE_SYS_CDEFS_H */
+ 
+ /* Define if you have the <sys/dlpi.h> header file.  */
+ /* #undef HAVE_SYS_DLPI_H */
diff --git a/package/network/services/ppp/patches/131-missing_prototype_macro.patch b/package/network/services/ppp/patches/131-missing_prototype_macro.patch
new file mode 100644
index 0000000000..868a08b60f
--- /dev/null
+++ b/package/network/services/ppp/patches/131-missing_prototype_macro.patch
@@ -0,0 +1,23 @@
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -67,6 +67,9 @@
+ #define volatile
+ #endif
+ 
++#undef __P
++#define __P(args) args
++
+ #ifdef INET6
+ #include "eui64.h"
+ #endif
+--- a/pppd/magic.h
++++ b/pppd/magic.h
+@@ -42,6 +42,8 @@
+  * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $
+  */
+ 
++#include "pppd.h"
++
+ void magic_init __P((void));	/* Initialize the magic number generator */
+ u_int32_t magic __P((void));	/* Returns the next magic number */
+ 
diff --git a/package/network/services/ppp/patches/132-fix_linux_includes.patch b/package/network/services/ppp/patches/132-fix_linux_includes.patch
new file mode 100644
index 0000000000..696dad1198
--- /dev/null
+++ b/package/network/services/ppp/patches/132-fix_linux_includes.patch
@@ -0,0 +1,40 @@
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -73,12 +73,12 @@
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/time.h>
+-#include <sys/errno.h>
+ #include <sys/file.h>
+ #include <sys/stat.h>
+ #include <sys/utsname.h>
+ #include <sys/sysmacros.h>
+ 
++#include <errno.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <syslog.h>
+@@ -102,22 +102,15 @@
+ #define MAX_ADDR_LEN 7
+ #endif
+ 
+-#if __GLIBC__ >= 2
+ #include <asm/types.h>		/* glibc 2 conflicts with linux/types.h */
+ #include <net/if.h>
+ #include <net/if_arp.h>
+ #include <net/route.h>
+ #include <netinet/if_ether.h>
+-#else
+-#include <linux/types.h>
+-#include <linux/if.h>
+-#include <linux/if_arp.h>
+-#include <linux/route.h>
+-#include <linux/if_ether.h>
+-#endif
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ 
++#include <linux/sockios.h>
+ #include <linux/ppp_defs.h>
+ #include <linux/if_ppp.h>
+ 
diff --git a/package/network/services/ppp/patches/133-fix_sha1_include.patch b/package/network/services/ppp/patches/133-fix_sha1_include.patch
new file mode 100644
index 0000000000..b5ccd0852d
--- /dev/null
+++ b/package/network/services/ppp/patches/133-fix_sha1_include.patch
@@ -0,0 +1,11 @@
+--- a/pppd/sha1.c
++++ b/pppd/sha1.c
+@@ -18,7 +18,7 @@
+ 
+ #include <string.h>
+ #include <netinet/in.h>	/* htonl() */
+-#include <net/ppp_defs.h>
++#include "pppd.h"
+ #include "sha1.h"
+ 
+ static void
diff --git a/package/network/services/ppp/patches/140-pppoe_compile_fix.patch b/package/network/services/ppp/patches/140-pppoe_compile_fix.patch
new file mode 100644
index 0000000000..2983a75c42
--- /dev/null
+++ b/package/network/services/ppp/patches/140-pppoe_compile_fix.patch
@@ -0,0 +1,101 @@
+--- a/pppd/plugins/rp-pppoe/plugin.c
++++ b/pppd/plugins/rp-pppoe/plugin.c
+@@ -46,10 +46,10 @@ static char const RCSID[] =
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <signal.h>
+-#include <net/ethernet.h>
+ #include <net/if_arp.h>
+ #include <linux/ppp_defs.h>
+ #include <linux/if_pppox.h>
++#include <linux/if_ether.h>
+ 
+ #ifndef _ROOT_PATH
+ #define _ROOT_PATH ""
+--- a/pppd/plugins/rp-pppoe/pppoe.h
++++ b/pppd/plugins/rp-pppoe/pppoe.h
+@@ -86,17 +86,6 @@ typedef unsigned long UINT32_t;
+ 
+ #include <netinet/in.h>
+ 
+-#ifdef HAVE_NETINET_IF_ETHER_H
+-#include <sys/types.h>
+-
+-#ifdef HAVE_SYS_SOCKET_H
+-#include <sys/socket.h>
+-#endif
+-#ifndef HAVE_SYS_DLPI_H
+-#include <netinet/if_ether.h>
+-#endif
+-#endif
+-
+ 
+ 
+ /* Ethernet frame types according to RFC 2516 */
+--- a/pppd/plugins/rp-pppoe/if.c
++++ b/pppd/plugins/rp-pppoe/if.c
+@@ -31,7 +31,7 @@ static char const RCSID[] =
+ #endif
+ 
+ #ifdef HAVE_NET_ETHERNET_H
+-#include <net/ethernet.h>
++#include <linux/if_ether.h>
+ #endif
+ 
+ #ifdef HAVE_ASM_TYPES_H
+--- a/pppd/plugins/rp-pppoe/pppoe-discovery.c
++++ b/pppd/plugins/rp-pppoe/pppoe-discovery.c
+@@ -16,6 +16,7 @@
+ #include <string.h>
+ 
+ #include "pppoe.h"
++#include "pppd/pppd.h"
+ 
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+@@ -27,10 +28,6 @@
+ #include <linux/if_packet.h>
+ #endif
+ 
+-#ifdef HAVE_NET_ETHERNET_H
+-#include <net/ethernet.h>
+-#endif
+-
+ #ifdef HAVE_ASM_TYPES_H
+ #include <asm/types.h>
+ #endif
+@@ -717,6 +714,23 @@ char *xstrdup(const char *s)
+     return ret;
+ }
+ 
++void
++error(char *fmt, ...)
++{
++    va_list pvar;
++
++#if defined(__STDC__)
++    va_start(pvar, fmt);
++#else
++    char *fmt;
++    va_start(pvar);
++    fmt = va_arg(pvar, char *);
++#endif
++
++    fprintf(stderr, fmt, pvar);
++    va_end(pvar);
++}
++
+ void usage(void)
+ {
+     fprintf(stderr, "Usage: pppoe-discovery [options]\n");
+--- a/pppd/plugins/rp-pppoe/Makefile.linux
++++ b/pppd/plugins/rp-pppoe/Makefile.linux
+@@ -33,7 +33,7 @@ pppoe-discovery: pppoe-discovery.o debug
+ 	$(CC) $(CFLAGS) -o pppoe-discovery pppoe-discovery.o debug.o
+ 
+ pppoe-discovery.o: pppoe-discovery.c
+-	$(CC) $(CFLAGS) -c -o pppoe-discovery.o pppoe-discovery.c
++	$(CC) $(CFLAGS) -I../../.. -c -o pppoe-discovery.o pppoe-discovery.c
+ 
+ debug.o: debug.c
+ 	$(CC) $(CFLAGS) -c -o debug.o debug.c
diff --git a/package/network/services/ppp/patches/200-makefile.patch b/package/network/services/ppp/patches/200-makefile.patch
new file mode 100644
index 0000000000..143023246c
--- /dev/null
+++ b/package/network/services/ppp/patches/200-makefile.patch
@@ -0,0 +1,49 @@
+pppd: tune Linux config defaults for OpenWrt
+
+This patch adjusts a number defaults to properly match the OpenWrt environment.
+It is not intended for upstream.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -48,7 +48,7 @@ MPPE=y
+ # Uncomment the next line to include support for PPP packet filtering.
+ # This requires that the libpcap library and headers be installed
+ # and that the kernel driver support PPP packet filtering.
+-FILTER=y
++#FILTER=y
+ 
+ # Uncomment the next line to enable multilink PPP (enabled by default)
+ # Linux distributions: Please leave multilink ENABLED in your builds
+@@ -58,7 +58,7 @@ HAVE_MULTILINK=y
+ # Uncomment the next line to enable the TDB database (enabled by default.)
+ # If you enable multilink, then TDB is automatically enabled also.
+ # Linux distributions: Please leave TDB ENABLED in your builds.
+-USE_TDB=y
++#USE_TDB=y
+ 
+ HAS_SHADOW=y
+ #USE_PAM=y
+@@ -80,7 +80,7 @@ MAXOCTETS=y
+ 
+ INCLUDE_DIRS= -I../include
+ 
+-COMPILE_FLAGS= -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MMAP
++COMPILE_FLAGS= -DHAVE_PATHS_H -DHAVE_MMAP
+ 
+ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS) '-DDESTDIR="@DESTDIR@"'
+ 
+@@ -120,10 +120,10 @@ CFLAGS   += -DHAS_SHADOW
+ #LIBS     += -lshadow $(LIBS)
+ endif
+ 
+-ifneq ($(wildcard /usr/include/crypt.h),)
++#ifneq ($(wildcard /usr/include/crypt.h),)
+ CFLAGS  += -DHAVE_CRYPT_H=1
+ LIBS	+= -lcrypt
+-endif
++#endif
+ 
+ ifdef USE_LIBUTIL
+ CFLAGS	+= -DHAVE_LOGWTMP=1
diff --git a/package/network/services/ppp/patches/201-mppe_mppc_1.1.patch b/package/network/services/ppp/patches/201-mppe_mppc_1.1.patch
new file mode 100644
index 0000000000..3fc30bb433
--- /dev/null
+++ b/package/network/services/ppp/patches/201-mppe_mppc_1.1.patch
@@ -0,0 +1,1495 @@
+pppd: add support for MPPE and MPPC encryption and compression protocols
+
+This is a forward ported version of ppp-2.4.3-mppe-mppc-1.1.patch.gz found on
+http://mppe-mppc.alphacron.de/ .
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/include/linux/ppp-comp.h
++++ b/include/linux/ppp-comp.h
+@@ -36,7 +36,7 @@
+  */
+ 
+ /*
+- *  ==FILEVERSION 20020319==
++ *  ==FILEVERSION 20020715==
+  *
+  *  NOTE TO MAINTAINERS:
+  *     If you modify this file at all, please set the above date.
+@@ -201,6 +201,33 @@ struct compressor {
+ #define CI_MPPE			18	/* config option for MPPE */
+ #define CILEN_MPPE		6	/* length of config option */
+ 
++/* MPPE/MPPC definitions by J.D.*/
++#define MPPE_STATELESS          MPPE_H_BIT	/* configuration bit H */
++#define MPPE_40BIT              MPPE_L_BIT	/* configuration bit L */
++#define MPPE_56BIT              MPPE_M_BIT	/* configuration bit M */
++#define MPPE_128BIT             MPPE_S_BIT	/* configuration bit S */
++#define MPPE_MPPC               MPPE_C_BIT	/* configuration bit C */
++
++/*
++ * Definitions for Stac LZS.
++ */
++
++#define CI_LZS			17	/* config option for Stac LZS */
++#define CILEN_LZS		5	/* length of config option */
++
++#define LZS_OVHD		4	/* max. LZS overhead */
++#define LZS_HIST_LEN		2048	/* LZS history size */
++#define LZS_MAX_CCOUNT		0x0FFF	/* max. coherency counter value */
++
++#define LZS_MODE_NONE		0
++#define LZS_MODE_LCB		1
++#define LZS_MODE_CRC		2
++#define LZS_MODE_SEQ		3
++#define LZS_MODE_EXT		4
++
++#define LZS_EXT_BIT_FLUSHED	0x80	/* bit A */
++#define LZS_EXT_BIT_COMP	0x20	/* bit C */
++
+ /*
+  * Definitions for other, as yet unsupported, compression methods.
+  */
+--- a/include/net/ppp-comp.h
++++ b/include/net/ppp-comp.h
+@@ -168,6 +168,33 @@ struct compressor {
+ #define CI_MPPE			18	/* config option for MPPE */
+ #define CILEN_MPPE		6	/* length of config option */
+ 
++/* MPPE/MPPC definitions by J.D.*/
++#define MPPE_STATELESS          MPPE_H_BIT	/* configuration bit H */
++#define MPPE_40BIT              MPPE_L_BIT	/* configuration bit L */
++#define MPPE_56BIT              MPPE_M_BIT	/* configuration bit M */
++#define MPPE_128BIT             MPPE_S_BIT	/* configuration bit S */
++#define MPPE_MPPC               MPPE_C_BIT	/* configuration bit C */
++
++/*
++ * Definitions for Stac LZS.
++ */
++
++#define CI_LZS			17	/* config option for Stac LZS */
++#define CILEN_LZS		5	/* length of config option */
++
++#define LZS_OVHD		4	/* max. LZS overhead */
++#define LZS_HIST_LEN		2048	/* LZS history size */
++#define LZS_MAX_CCOUNT		0x0FFF	/* max. coherency counter value */
++
++#define LZS_MODE_NONE		0
++#define LZS_MODE_LCB		1
++#define LZS_MODE_CRC		2
++#define LZS_MODE_SEQ		3
++#define LZS_MODE_EXT		4
++
++#define LZS_EXT_BIT_FLUSHED	0x80	/* bit A */
++#define LZS_EXT_BIT_COMP	0x20	/* bit C */
++
+ /*
+  * Definitions for other, as yet unsupported, compression methods.
+  */
+--- a/pppd/ccp.c
++++ b/pppd/ccp.c
+@@ -62,12 +62,10 @@ static int setdeflate __P((char **));
+ static char bsd_value[8];
+ static char deflate_value[8];
+ 
+-/*
+- * Option variables.
+- */
+ #ifdef MPPE
+-bool refuse_mppe_stateful = 1;		/* Allow stateful mode? */
+-#endif
++static int setmppe(char **);
++static int setnomppe(void);
++#endif /* MPPE */
+ 
+ static option_t ccp_option_list[] = {
+     { "noccp", o_bool, &ccp_protent.enabled_flag,
+@@ -108,54 +106,36 @@ static option_t ccp_option_list[] = {
+       "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+       &ccp_allowoptions[0].predictor_1 },
+ 
++    { "lzs", o_bool, &ccp_wantoptions[0].lzs,
++      "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_PRIO },
++    { "+lzs", o_bool, &ccp_wantoptions[0].lzs,
++      "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_ALIAS | OPT_PRIO },
++    { "nolzs", o_bool, &ccp_wantoptions[0].lzs,
++      "don't allow Stac LZS", OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].lzs },
++    { "-lzs", o_bool, &ccp_wantoptions[0].lzs,
++      "don't allow Stac LZS", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].lzs },
++
+ #ifdef MPPE
+-    /* MPPE options are symmetrical ... we only set wantoptions here */
+-    { "require-mppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "require MPPE encryption",
+-      OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
+-    { "+mppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "require MPPE encryption",
+-      OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
+-    { "nomppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "don't allow MPPE encryption", OPT_PRIO },
+-    { "-mppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO },
+-
+-    /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */
+-    { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
+-      &ccp_wantoptions[0].mppe },
+-    { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
+-      &ccp_wantoptions[0].mppe },
+-    { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 40-bit encryption",
+-      OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe },
+-    { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 40-bit encryption",
+-      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40,
+-      &ccp_wantoptions[0].mppe },
+-
+-    { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
+-      &ccp_wantoptions[0].mppe },
+-    { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 128-bit encryption",
+-      OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
+-      &ccp_wantoptions[0].mppe },
+-    { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 128-bit encryption",
+-      OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe },
+-    { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 128-bit encryption",
+-      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128,
+-      &ccp_wantoptions[0].mppe },
+-
+-    /* strange one; we always request stateless, but will we allow stateful? */
+-    { "mppe-stateful", o_bool, &refuse_mppe_stateful,
+-      "allow MPPE stateful mode", OPT_PRIO },
+-    { "nomppe-stateful", o_bool, &refuse_mppe_stateful,
+-      "disallow MPPE stateful mode", OPT_PRIO | 1 },
++    { "mppc", o_bool, &ccp_wantoptions[0].mppc,
++      "request MPPC compression", 1, &ccp_allowoptions[0].mppc },
++    { "+mppc", o_bool, &ccp_wantoptions[0].mppc,
++      "request MPPC compression", 1, &ccp_allowoptions[0].mppc, OPT_ALIAS },
++    { "nomppc", o_bool, &ccp_wantoptions[0].mppc,
++      "don't allow MPPC compression", OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].mppc },
++    { "-mppc", o_bool, &ccp_wantoptions[0].mppc,
++      "don't allow MPPC compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].mppc },
++    { "mppe", o_special, (void *)setmppe,
++      "request MPPE encryption" },
++    { "+mppe", o_special, (void *)setmppe,
++      "request MPPE encryption" },
++    { "nomppe", o_special_noarg, (void *)setnomppe,
++      "don't allow MPPE encryption" },
++    { "-mppe", o_special_noarg, (void *)setnomppe,
++      "don't allow MPPE encryption" },
+ #endif /* MPPE */
+ 
+     { NULL }
+@@ -241,7 +221,7 @@ static fsm_callbacks ccp_callbacks = {
+  */
+ #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
+ 				 || (opt).predictor_1 || (opt).predictor_2 \
+-				 || (opt).mppe)
++				 || (opt).lzs || (opt).mppc || (opt).mppe)
+ 
+ /*
+  * Local state (mainly for handling reset-reqs and reset-acks).
+@@ -344,6 +324,100 @@ setdeflate(argv)
+     return 1;
+ }
+ 
++#ifdef MPPE
++/*
++ * Functions called from config options
++ */
++/* 
++   MPPE suboptions:
++	required - require MPPE; disconnect if peer doesn't support it
++	stateless - use stateless mode
++	no40 - disable 40 bit keys
++	no56 - disable 56 bit keys
++	no128 - disable 128 bit keys
++*/
++int setmppe(char **argv)
++{
++    int i;
++    char *str, cmdbuf[16];
++
++    ccp_allowoptions[0].mppe = 1;
++    ccp_allowoptions[0].mppe_40 = 1;
++    ccp_allowoptions[0].mppe_56 = 1;
++    ccp_allowoptions[0].mppe_128 = 1;
++    ccp_allowoptions[0].mppe_stateless = 0;
++    ccp_wantoptions[0].mppe = 0;
++
++    str = *argv;
++
++    while (1) {
++	i = 0;
++	memset(cmdbuf, '\0', 16);
++	while ((i < 16) && (*str != ',') && (*str != '\0'))
++	    cmdbuf[i++] = *str++;
++	cmdbuf[i] = '\0';
++	if (!strncasecmp(cmdbuf, "no40", strlen("no40"))) {
++	    ccp_allowoptions[0].mppe_40 = 0;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "no56", strlen("no56"))) {
++	    ccp_allowoptions[0].mppe_56 = 0;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "no128", strlen("no128"))) {
++	    ccp_allowoptions[0].mppe_128 = 0;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "stateless", strlen("stateless"))) {
++	    ccp_allowoptions[0].mppe_stateless = 1;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "required", strlen("required"))) {
++	    ccp_wantoptions[0].mppe = 1;
++	    goto next_param;
++	} else {
++	    option_error("invalid parameter '%s' for mppe option", cmdbuf);
++	    return 0;
++	}
++
++    next_param:
++	if (*str == ',') {
++	    str++;
++	    continue;
++	}
++	if (*str == '\0') {
++	    if (!(ccp_allowoptions[0].mppe_40 || ccp_allowoptions[0].mppe_56 ||
++		  ccp_allowoptions[0].mppe_128)) {
++		if (ccp_wantoptions[0].mppe == 1) {
++		    option_error("You require MPPE but you have switched off "
++				 "all encryption key lengths.");
++		    return 0;
++		}
++		ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
++		ccp_wantoptions[0].mppe_stateless =
++		    ccp_allowoptions[0].mppe_stateless = 0;
++	    } else {
++		ccp_allowoptions[0].mppe = 1;
++		ccp_wantoptions[0].mppe_stateless =
++		    ccp_allowoptions[0].mppe_stateless;
++		if (ccp_wantoptions[0].mppe == 1) {
++		    ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40;
++		    ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56;
++		    ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128;
++		}
++	    }
++	    return 1;
++	}
++    }
++}
++
++int setnomppe(void)
++{
++    ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
++    ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40 = 0;
++    ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56 = 0;
++    ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128 = 0;
++    ccp_wantoptions[0].mppe_stateless = ccp_allowoptions[0].mppe_stateless = 0;
++    return 1;
++}
++#endif /* MPPE */
++
+ /*
+  * ccp_init - initialize CCP.
+  */
+@@ -378,6 +452,30 @@ ccp_init(unit)
+     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+ 
+     ccp_allowoptions[0].predictor_1 = 1;
++
++    ccp_wantoptions[0].lzs = 0; /* Stac LZS  - will be enabled in the future */
++    ccp_wantoptions[0].lzs_mode = LZS_MODE_SEQ;
++    ccp_wantoptions[0].lzs_hists = 1;
++    ccp_allowoptions[0].lzs = 0; /* Stac LZS  - will be enabled in the future */
++    ccp_allowoptions[0].lzs_mode = LZS_MODE_SEQ;
++    ccp_allowoptions[0].lzs_hists = 1;
++
++#ifdef MPPE
++    /* by default allow and request MPPC... */
++    ccp_wantoptions[0].mppc = ccp_allowoptions[0].mppc = 1;
++
++    /* ... and allow but don't request MPPE */
++    ccp_allowoptions[0].mppe = 1;
++    ccp_allowoptions[0].mppe_40 = 1;
++    ccp_allowoptions[0].mppe_56 = 1;
++    ccp_allowoptions[0].mppe_128 = 1;
++    ccp_allowoptions[0].mppe_stateless = 1;
++    ccp_wantoptions[0].mppe = 0;
++    ccp_wantoptions[0].mppe_40 = 0;
++    ccp_wantoptions[0].mppe_56 = 0;
++    ccp_wantoptions[0].mppe_128 = 0;
++    ccp_wantoptions[0].mppe_stateless = 0;
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -455,11 +553,11 @@ ccp_input(unit, p, len)
+     if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) {
+ 	notice("Compression disabled by peer.");
+ #ifdef MPPE
+-	if (ccp_gotoptions[unit].mppe) {
++	if (ccp_wantoptions[unit].mppe) {
+ 	    error("MPPE disabled, closing LCP");
+ 	    lcp_close(unit, "MPPE disabled by peer");
+ 	}
+-#endif
++#endif /* MPPE */
+     }
+ 
+     /*
+@@ -487,6 +585,15 @@ ccp_extcode(f, code, id, p, len)
+ 	    break;
+ 	/* send a reset-ack, which the transmitter will see and
+ 	   reset its compression state. */
++
++	/* In case of MPPE/MPPC or LZS we shouldn't send CCP_RESETACK,
++	   but we do it in order to reset compressor; CCP_RESETACK is
++	   then silently discarded. See functions ppp_send_frame and
++	   ppp_ccp_peek in ppp_generic.c (Linux only !!!). All the
++	   confusion is caused by the fact that CCP code is splited
++	   into two parts - one part is handled by pppd, the other one
++	   is handled by kernel. */
++
+ 	fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
+ 	break;
+ 
+@@ -515,12 +622,11 @@ ccp_protrej(unit)
+     fsm_lowerdown(&ccp_fsm[unit]);
+ 
+ #ifdef MPPE
+-    if (ccp_gotoptions[unit].mppe) {
++    if (ccp_wantoptions[unit].mppe) {
+ 	error("MPPE required but peer negotiation failed");
+ 	lcp_close(unit, "MPPE required but peer negotiation failed");
+     }
+-#endif
+-
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -537,7 +643,7 @@ ccp_resetci(f)
+     all_rejected[f->unit] = 0;
+ 
+ #ifdef MPPE
+-    if (go->mppe) {
++    if (go->mppe || go->mppc) {
+ 	ccp_options *ao = &ccp_allowoptions[f->unit];
+ 	int auth_mschap_bits = auth_done[f->unit];
+ 	int numbits;
+@@ -551,80 +657,109 @@ ccp_resetci(f)
+ 	 * NB: If MPPE is required, all other compression opts are invalid.
+ 	 *     So, we return right away if we can't do it.
+ 	 */
++	if (ccp_wantoptions[f->unit].mppe) {
++	    /* Leave only the mschap auth bits set */
++	    auth_mschap_bits &= (CHAP_MS_WITHPEER  | CHAP_MS_PEER |
++				 CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
++	    /* Count the mschap auths */
++	    auth_mschap_bits >>= CHAP_MS_SHIFT;
++	    numbits = 0;
++	    do {
++		numbits += auth_mschap_bits & 1;
++		auth_mschap_bits >>= 1;
++	    } while (auth_mschap_bits);
++	    if (numbits > 1) {
++		error("MPPE required, but auth done in both directions.");
++		lcp_close(f->unit, "MPPE required but not available");
++		return;
++	    }
++	    if (!numbits) {
++		error("MPPE required, but MS-CHAP[v2] auth not performed.");
++		lcp_close(f->unit, "MPPE required but not available");
++		return;
++	    }
+ 
+-	/* Leave only the mschap auth bits set */
+-	auth_mschap_bits &= (CHAP_MS_WITHPEER  | CHAP_MS_PEER |
+-			     CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
+-	/* Count the mschap auths */
+-	auth_mschap_bits >>= CHAP_MS_SHIFT;
+-	numbits = 0;
+-	do {
+-	    numbits += auth_mschap_bits & 1;
+-	    auth_mschap_bits >>= 1;
+-	} while (auth_mschap_bits);
+-	if (numbits > 1) {
+-	    error("MPPE required, but auth done in both directions.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
+-	}
+-	if (!numbits) {
+-	    error("MPPE required, but MS-CHAP[v2] auth not performed.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
+-	}
+-
+-	/* A plugin (eg radius) may not have obtained key material. */
+-	if (!mppe_keys_set) {
+-	    error("MPPE required, but keys are not available.  "
+-		  "Possible plugin problem?");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
+-	}
+-
+-	/* LM auth not supported for MPPE */
+-	if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) {
+-	    /* This might be noise */
+-	    if (go->mppe & MPPE_OPT_40) {
+-		notice("Disabling 40-bit MPPE; MS-CHAP LM not supported");
+-		go->mppe &= ~MPPE_OPT_40;
+-		ccp_wantoptions[f->unit].mppe &= ~MPPE_OPT_40;
++	    /* A plugin (eg radius) may not have obtained key material. */
++	    if (!mppe_keys_set) {
++		error("MPPE required, but keys are not available.  "
++		      "Possible plugin problem?");
++		lcp_close(f->unit, "MPPE required but not available");
++		return;
+ 	    }
+ 	}
+ 
+-	/* Last check: can we actually negotiate something? */
+-	if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) {
+-	    /* Could be misconfig, could be 40-bit disabled above. */
+-	    error("MPPE required, but both 40-bit and 128-bit disabled.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
++	/*
++	 * Check whether the kernel knows about the various
++	 * compression methods we might request. Key material
++	 * unimportant here.
++	 */
++	if (go->mppc) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = 0;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_MPPC;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 0) <= 0)
++		go->mppc = 0;
++	}
++	if (go->mppe_40) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = MPPE_STATELESS;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_40BIT;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
++		go->mppe_40 = 0;
++	}
++	if (go->mppe_56) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = MPPE_STATELESS;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_56BIT;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
++		go->mppe_56 = 0;
++	}
++	if (go->mppe_128) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = MPPE_STATELESS;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_128BIT;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
++		go->mppe_128 = 0;
++	}
++	if (!go->mppe_40 && !go->mppe_56 && !go->mppe_128) {
++	    if (ccp_wantoptions[f->unit].mppe) {
++		error("MPPE required, but kernel has no support.");
++		lcp_close(f->unit, "MPPE required but not available");
++	    }
++	    go->mppe = go->mppe_stateless = 0;
++	} else {
++	    /* MPPE is not compatible with other compression types */
++	    if (ccp_wantoptions[f->unit].mppe) {
++		ao->bsd_compress = go->bsd_compress = 0;
++		ao->predictor_1  = go->predictor_1  = 0;
++		ao->predictor_2  = go->predictor_2  = 0;
++		ao->deflate	 = go->deflate	    = 0;
++		ao->lzs		 = go->lzs	    = 0;
++	    }
+ 	}
+-
+-	/* sync options */
+-	ao->mppe = go->mppe;
+-	/* MPPE is not compatible with other compression types */
+-	ao->bsd_compress = go->bsd_compress = 0;
+-	ao->predictor_1  = go->predictor_1  = 0;
+-	ao->predictor_2  = go->predictor_2  = 0;
+-	ao->deflate      = go->deflate      = 0;
+     }
+ #endif /* MPPE */
+-
+-    /*
+-     * Check whether the kernel knows about the various
+-     * compression methods we might request.
+-     */
+-#ifdef MPPE
+-    if (go->mppe) {
+-	opt_buf[0] = CI_MPPE;
+-	opt_buf[1] = CILEN_MPPE;
+-	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+-	/* Key material unimportant here. */
+-	if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) {
+-	    error("MPPE required, but kernel has no support.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	}
++    if (go->lzs) {
++	opt_buf[0] = CI_LZS;
++	opt_buf[1] = CILEN_LZS;
++	opt_buf[2] = go->lzs_hists >> 8;
++	opt_buf[3] = go->lzs_hists & 0xff;
++	opt_buf[4] = LZS_MODE_SEQ;
++	if (ccp_test(f->unit, opt_buf, CILEN_LZS, 0) <= 0)
++	    go->lzs = 0;
+     }
+-#endif
+     if (go->bsd_compress) {
+ 	opt_buf[0] = CI_BSD_COMPRESS;
+ 	opt_buf[1] = CILEN_BSD_COMPRESS;
+@@ -679,7 +814,8 @@ ccp_cilen(f)
+ 	+ (go->deflate? CILEN_DEFLATE: 0)
+ 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
+ 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0)
+-	+ (go->mppe? CILEN_MPPE: 0);
++	+ (go->lzs? CILEN_LZS: 0)
++	+ ((go->mppe || go->mppc)? CILEN_MPPE: 0);
+ }
+ 
+ /*
+@@ -693,6 +829,8 @@ ccp_addci(f, p, lenp)
+ {
+     int res;
+     ccp_options *go = &ccp_gotoptions[f->unit];
++    ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+     u_char *p0 = p;
+ 
+     /*
+@@ -701,22 +839,43 @@ ccp_addci(f, p, lenp)
+      * in case it gets Acked.
+      */
+ #ifdef MPPE
+-    if (go->mppe) {
++    if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
+ 	u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
+ 
+-	p[0] = opt_buf[0] = CI_MPPE;
+-	p[1] = opt_buf[1] = CILEN_MPPE;
+-	MPPE_OPTS_TO_CI(go->mppe, &p[2]);
+-	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
++	p[0] = CI_MPPE;
++	p[1] = CILEN_MPPE;
++	p[2] = (go->mppe_stateless ? MPPE_STATELESS : 0);
++	p[3] = 0;
++	p[4] = 0;
++	p[5] = (go->mppe_40 ? MPPE_40BIT : 0) | (go->mppe_56 ? MPPE_56BIT : 0) |
++	    (go->mppe_128 ? MPPE_128BIT : 0) | (go->mppc ? MPPE_MPPC : 0);
++
++	BCOPY(p, opt_buf, CILEN_MPPE);
+ 	BCOPY(mppe_recv_key, &opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN);
+ 	res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0);
+-	if (res > 0)
++	if (res > 0) {
+ 	    p += CILEN_MPPE;
+-	else
++	} else {
+ 	    /* This shouldn't happen, we've already tested it! */
+-	    lcp_close(f->unit, "MPPE required but not available in kernel");
++	    go->mppe = go->mppe_40 = go->mppe_56 = go->mppe_128 =
++		go->mppe_stateless = go->mppc = 0;
++	    if (ccp_wantoptions[f->unit].mppe)
++		lcp_close(f->unit, "MPPE required but not available in kernel");
++	}
++    }
++#endif /* MPPE */
++    if (go->lzs) {
++	p[0] = CI_LZS;
++	p[1] = CILEN_LZS;
++	p[2] = go->lzs_hists >> 8;
++	p[3] = go->lzs_hists & 0xff;
++	p[4] = LZS_MODE_SEQ;
++	res = ccp_test(f->unit, p, CILEN_LZS, 0);
++	if (res > 0) {
++	    p += CILEN_LZS;
++	} else
++	    go->lzs = 0;
+     }
+-#endif
+     if (go->deflate) {
+ 	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
+ 	p[1] = CILEN_DEFLATE;
+@@ -802,7 +961,7 @@ ccp_addci(f, p, lenp)
+ 
+ /*
+  * ccp_ackci - process a received configure-ack, and return
+- * 1 iff the packet was OK.
++ * 1 if the packet was OK.
+  */
+ static int
+ ccp_ackci(f, p, len)
+@@ -811,24 +970,44 @@ ccp_ackci(f, p, len)
+     int len;
+ {
+     ccp_options *go = &ccp_gotoptions[f->unit];
++    ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+     u_char *p0 = p;
+ 
+ #ifdef MPPE
+-    if (go->mppe) {
+-	u_char opt_buf[CILEN_MPPE];
+-
+-	opt_buf[0] = CI_MPPE;
+-	opt_buf[1] = CILEN_MPPE;
+-	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+-	if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE))
++    if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
++	if (len < CILEN_MPPE
++	    || p[1] != CILEN_MPPE || p[0] != CI_MPPE
++	    || p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0)
++	    || p[3] != 0
++	    || p[4] != 0
++	    || (p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
++			 (go->mppc ? MPPE_MPPC : 0))
++		&& p[5] != ((go->mppe_56 ? MPPE_56BIT : 0) |
++			    (go->mppc ? MPPE_MPPC : 0))
++		&& p[5] != ((go->mppe_128 ? MPPE_128BIT : 0) |
++			    (go->mppc ? MPPE_MPPC : 0))))
+ 	    return 0;
++	if (go->mppe_40 || go->mppe_56 || go->mppe_128)
++	    go->mppe = 1;
+ 	p += CILEN_MPPE;
+ 	len -= CILEN_MPPE;
++	/* Cope with first/fast ack */
++	if (p == p0 && len == 0)
++	    return 1;
++    }
++#endif /* MPPE */
++    if (go->lzs) {
++	if (len < CILEN_LZS || p[0] != CI_LZS || p[1] != CILEN_LZS
++	    || p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff)
++	    || p[4] != LZS_MODE_SEQ)
++	    return 0;
++	p += CILEN_LZS;
++	len -= CILEN_LZS;
+ 	/* XXX Cope with first/fast ack */
+-	if (len == 0)
++	if (p == p0 && len == 0)
+ 	    return 1;
+     }
+-#endif
+     if (go->deflate) {
+ 	if (len < CILEN_DEFLATE
+ 	    || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+@@ -901,6 +1080,8 @@ ccp_nakci(f, p, len, treat_as_reject)
+     int treat_as_reject;
+ {
+     ccp_options *go = &ccp_gotoptions[f->unit];
++    ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+     ccp_options no;		/* options we've seen already */
+     ccp_options try;		/* options to ask for next time */
+ 
+@@ -908,28 +1089,100 @@ ccp_nakci(f, p, len, treat_as_reject)
+     try = *go;
+ 
+ #ifdef MPPE
+-    if (go->mppe && len >= CILEN_MPPE
+-	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+-	no.mppe = 1;
+-	/*
+-	 * Peer wants us to use a different strength or other setting.
+-	 * Fail if we aren't willing to use his suggestion.
+-	 */
+-	MPPE_CI_TO_OPTS(&p[2], try.mppe);
+-	if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) {
+-	    error("Refusing MPPE stateful mode offered by peer");
+-	    try.mppe = 0;
+-	} else if (((go->mppe | MPPE_OPT_STATEFUL) & try.mppe) != try.mppe) {
+-	    /* Peer must have set options we didn't request (suggest) */
+-	    try.mppe = 0;
+-	}
++    if ((go->mppe || go->mppc || (!wo->mppe && ao->mppe)) &&
++	len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+ 
+-	if (!try.mppe) {
+-	    error("MPPE required but peer negotiation failed");
+-	    lcp_close(f->unit, "MPPE required but peer negotiation failed");
++	if (go->mppc) {
++	    no.mppc = 1;
++	    if (!(p[5] & MPPE_MPPC))
++		try.mppc = 0;
++	}
++
++	if (go->mppe)
++	    no.mppe = 1;
++	if (go->mppe_40)
++	    no.mppe_40 = 1;
++	if (go->mppe_56)
++	    no.mppe_56 = 1;
++	if (go->mppe_128)
++	    no.mppe_128 = 1;
++	if (go->mppe_stateless)
++	    no.mppe_stateless = 1;
++
++	if (ao->mppe_40) {
++	    if ((p[5] & MPPE_40BIT))
++		try.mppe_40 = 1;
++	    else
++		try.mppe_40 = (p[5] == 0) ? 1 : 0;
++	}
++	if (ao->mppe_56) {
++	    if ((p[5] & MPPE_56BIT))
++		try.mppe_56 = 1;
++	    else
++		try.mppe_56 = (p[5] == 0) ? 1 : 0;
++	}
++	if (ao->mppe_128) {
++	    if ((p[5] & MPPE_128BIT))
++		try.mppe_128 = 1;
++	    else
++		try.mppe_128 = (p[5] == 0) ? 1 : 0;
++	}
++
++	if (ao->mppe_stateless) {
++	    if ((p[2] & MPPE_STATELESS) || wo->mppe_stateless)
++		try.mppe_stateless = 1;
++	    else
++		try.mppe_stateless = 0;
++	}
++
++	if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128) {
++	    try.mppe = try.mppe_stateless = 0;
++	    if (wo->mppe) {
++		/* we require encryption, but peer doesn't support it
++		   so we close connection */
++		wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
++		    wo->mppe_56 = wo->mppe_128 = 0;
++		lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
++			  "key length");
++	    }
++        }
++	if (wo->mppe && (wo->mppe_40 != try.mppe_40) &&
++	    (wo->mppe_56 != try.mppe_56) && (wo->mppe_128 != try.mppe_128)) {
++	    /* cannot negotiate key length */
++	    wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
++		wo->mppe_56 = wo->mppe_128 = 0;
++	    lcp_close(f->unit, "Cannot negotiate MPPE key length");
+ 	}
++	if (try.mppe_40 && try.mppe_56 && try.mppe_128)
++	    try.mppe_40 = try.mppe_56 = 0;
++	else
++	    if (try.mppe_56 && try.mppe_128)
++		try.mppe_56 = 0;
++	    else
++		if (try.mppe_40 && try.mppe_128)
++		    try.mppe_40 = 0;
++		else
++		    if (try.mppe_40 && try.mppe_56)
++			try.mppe_40 = 0;
++
++	p += CILEN_MPPE;
++	len -= CILEN_MPPE;
+     }
+ #endif /* MPPE */
++
++    if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
++	no.lzs = 1;
++	if (((p[2]<<8)|p[3]) > 1 || (p[4] != LZS_MODE_SEQ &&
++				     p[4] != LZS_MODE_EXT))
++	    try.lzs = 0;
++	else {
++	    try.lzs_mode = p[4];
++	    try.lzs_hists = (p[2] << 8) | p[3];
++	}
++	p += CILEN_LZS;
++	len -= CILEN_LZS;
++    }
++
+     if (go->deflate && len >= CILEN_DEFLATE
+ 	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ 	&& p[1] == CILEN_DEFLATE) {
+@@ -1002,14 +1255,50 @@ ccp_rejci(f, p, len)
+ 	return -1;
+ 
+ #ifdef MPPE
+-    if (go->mppe && len >= CILEN_MPPE
++    if ((go->mppe || go->mppc) && len >= CILEN_MPPE
+ 	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+-	error("MPPE required but peer refused");
+-	lcp_close(f->unit, "MPPE required but peer refused");
++	ccp_options *wo = &ccp_wantoptions[f->unit];
++	if (p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0) ||
++	    p[3] != 0 ||
++	    p[4] != 0 ||
++	    p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
++		     (go->mppe_56 ? MPPE_56BIT : 0) |
++		     (go->mppe_128 ? MPPE_128BIT : 0) |
++		     (go->mppc ? MPPE_MPPC : 0)))
++	    return 0;
++	if (go->mppc)
++	    try.mppc = 0;
++	if (go->mppe) {
++	    try.mppe = 0;
++	    if (go->mppe_40)
++		try.mppe_40 = 0;
++	    if (go->mppe_56)
++		try.mppe_56 = 0;
++	    if (go->mppe_128)
++		try.mppe_128 = 0;
++	    if (go->mppe_stateless)
++		try.mppe_stateless = 0;
++	    if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128)
++		try.mppe = try.mppe_stateless = 0;
++	    if (wo->mppe) { /* we want MPPE but cannot negotiate key length */
++		wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
++		    wo->mppe_56 = wo->mppe_128 = 0;
++		lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
++			  "key length");
++	    }
++	}
+ 	p += CILEN_MPPE;
+ 	len -= CILEN_MPPE;
+     }
+-#endif
++#endif /* MPPE */
++    if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
++	if (p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff) 
++	    || p[4] != go->lzs_mode)
++	    return 0;
++	try.lzs = 0;
++	p += CILEN_LZS;
++	len -= CILEN_LZS;
++    }
+     if (go->deflate_correct && len >= CILEN_DEFLATE
+ 	&& p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
+ 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+@@ -1073,14 +1362,15 @@ ccp_reqci(f, p, lenp, dont_nak)
+     int dont_nak;
+ {
+     int ret, newret, res;
+-    u_char *p0, *retp;
++    u_char *p0, *retp, p2, p5;
+     int len, clen, type, nb;
+     ccp_options *ho = &ccp_hisoptions[f->unit];
+     ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+ #ifdef MPPE
+-    bool rej_for_ci_mppe = 1;	/* Are we rejecting based on a bad/missing */
+-				/* CI_MPPE, or due to other options?       */
+-#endif
++    u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
++/*     int mtu; */
++#endif /* MPPE */
+ 
+     ret = CONFACK;
+     retp = p0 = p;
+@@ -1103,106 +1393,302 @@ ccp_reqci(f, p, lenp, dont_nak)
+ 	    switch (type) {
+ #ifdef MPPE
+ 	    case CI_MPPE:
+-		if (!ao->mppe || clen != CILEN_MPPE) {
++ 		if ((!ao->mppc && !ao->mppe) || clen != CILEN_MPPE) {
+ 		    newret = CONFREJ;
+ 		    break;
+ 		}
+-		MPPE_CI_TO_OPTS(&p[2], ho->mppe);
+-
+-		/* Nak if anything unsupported or unknown are set. */
+-		if (ho->mppe & MPPE_OPT_UNSUPPORTED) {
+-		    newret = CONFNAK;
+-		    ho->mppe &= ~MPPE_OPT_UNSUPPORTED;
+-		}
+-		if (ho->mppe & MPPE_OPT_UNKNOWN) {
++ 		p2 = p[2];
++ 		p5 = p[5];
++ 		/* not sure what they want, tell 'em what we got */
++ 		if (((p[2] & ~MPPE_STATELESS) != 0 || p[3] != 0 || p[4] != 0 ||
++ 		     (p[5] & ~(MPPE_40BIT | MPPE_56BIT | MPPE_128BIT |
++ 			       MPPE_MPPC)) != 0 || p[5] == 0) ||
++ 		    (p[2] == 0 && p[3] == 0 && p[4] == 0 &&  p[5] == 0)) {
+ 		    newret = CONFNAK;
+-		    ho->mppe &= ~MPPE_OPT_UNKNOWN;
+-		}
+-
+-		/* Check state opt */
+-		if (ho->mppe & MPPE_OPT_STATEFUL) {
+-		    /*
+-		     * We can Nak and request stateless, but it's a
+-		     * lot easier to just assume the peer will request
+-		     * it if he can do it; stateful mode is bad over
+-		     * the Internet -- which is where we expect MPPE.
+-		     */
+-		   if (refuse_mppe_stateful) {
+-			error("Refusing MPPE stateful mode offered by peer");
+-			newret = CONFREJ;
+-			break;
++ 		    p[2] = (wo->mppe_stateless ? MPPE_STATELESS : 0);
++		    p[3] = 0;
++ 		    p[4] = 0;
++ 		    p[5] = (wo->mppe_40 ? MPPE_40BIT : 0) |
++ 			(wo->mppe_56 ? MPPE_56BIT : 0) |
++ 			(wo->mppe_128 ? MPPE_128BIT : 0) |
++ 			(wo->mppc ? MPPE_MPPC : 0);
++ 		    break;
++  		}
++
++ 		if ((p[5] & MPPE_MPPC)) {
++ 		    if (ao->mppc) {
++ 			ho->mppc = 1;
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++ 			opt_buf[2] = opt_buf[3] = opt_buf[4] = 0;
++ 			opt_buf[5] = MPPE_MPPC;
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 1) <= 0) {
++ 			    ho->mppc = 0;
++ 			    p[5] &= ~MPPE_MPPC;
++ 			    newret = CONFNAK;
++ 			}
++ 		    } else {
++		      newret = CONFREJ;
++ 			if (wo->mppe || ao->mppe) {
++ 			    p[5] &= ~MPPE_MPPC;
++ 			    newret = CONFNAK;
++ 			}
+ 		    }
+ 		}
+-
+-		/* Find out which of {S,L} are set. */
+-		if ((ho->mppe & MPPE_OPT_128)
+-		     && (ho->mppe & MPPE_OPT_40)) {
+-		    /* Both are set, negotiate the strongest. */
+-		    newret = CONFNAK;
+-		    if (ao->mppe & MPPE_OPT_128)
+-			ho->mppe &= ~MPPE_OPT_40;
+-		    else if (ao->mppe & MPPE_OPT_40)
+-			ho->mppe &= ~MPPE_OPT_128;
+-		    else {
+-			newret = CONFREJ;
+-			break;
+-		    }
+-		} else if (ho->mppe & MPPE_OPT_128) {
+-		    if (!(ao->mppe & MPPE_OPT_128)) {
+-			newret = CONFREJ;
+-			break;
+-		    }
+-		} else if (ho->mppe & MPPE_OPT_40) {
+-		    if (!(ao->mppe & MPPE_OPT_40)) {
+-			newret = CONFREJ;
+-			break;
+-		    }
++ 		if (ao->mppe)
++ 		    ho->mppe = 1;
++ 
++ 		if ((p[2] & MPPE_STATELESS)) {
++ 		    if (ao->mppe_stateless) {
++ 			if (wo->mppe_stateless)
++ 			    ho->mppe_stateless = 1;
++ 			else {
++ 			    newret = CONFNAK;
++ 			    if (!dont_nak)
++ 				p[2] &= ~MPPE_STATELESS;
++ 			}
++ 		    } else {
++ 			newret = CONFNAK;
++ 			if (!dont_nak)
++ 			    p[2] &= ~MPPE_STATELESS;
++ 		    }
++ 		} else {
++ 		    if (wo->mppe_stateless && !dont_nak) {
++ 			wo->mppe_stateless = 0;
++ 			newret = CONFNAK;
++ 			p[2] |= MPPE_STATELESS;
++  		    }
++  		}
++  
++ 		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT|MPPE_128BIT)) {
++  		    newret = CONFNAK;
++ 		    if (ao->mppe_128) {
++ 			ho->mppe_128 = 1;
++ 			p[5] &= ~(MPPE_40BIT|MPPE_56BIT);
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++ 			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++ 			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++ 				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_128 = 0;
++ 			    p[5] |= (MPPE_40BIT|MPPE_56BIT);
++ 			    p[5] &= ~MPPE_128BIT;
++ 			    goto check_mppe_56_40;
++ 			}
++ 			goto check_mppe;
++  		    }
++ 		    p[5] &= ~MPPE_128BIT;
++ 		    goto check_mppe_56_40;
++ 		}
++ 		if ((p[5] & ~MPPE_MPPC) == (MPPE_56BIT|MPPE_128BIT)) {
++ 		    newret = CONFNAK;
++ 		    if (ao->mppe_128) {
++ 			ho->mppe_128 = 1;
++ 			p[5] &= ~MPPE_56BIT;
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++ 			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++ 				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_128 = 0;
++ 			    p[5] |= MPPE_56BIT;
++ 			    p[5] &= ~MPPE_128BIT;
++ 			    goto check_mppe_56;
++ 			}
++ 			goto check_mppe;
++  		    }
++ 		    p[5] &= ~MPPE_128BIT;
++ 		    goto check_mppe_56;
++ 		}
++ 		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_128BIT)) {
++ 		    newret = CONFNAK;
++ 		    if (ao->mppe_128) {
++ 			ho->mppe_128 = 1;
++ 			p[5] &= ~MPPE_40BIT;
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++ 			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++ 			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++ 				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_128 = 0;
++ 			    p[5] |= MPPE_40BIT;
++ 			    p[5] &= ~MPPE_128BIT;
++ 			    goto check_mppe_40;
++ 			}
++ 			goto check_mppe;
++ 		    }
++ 		    p[5] &= ~MPPE_128BIT;
++ 		    goto check_mppe_40;
++ 		}
++ 		if ((p[5] & ~MPPE_MPPC) == MPPE_128BIT) {
++ 		    if (ao->mppe_128) {
++ 			ho->mppe_128 = 1;
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++ 			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++ 			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++ 				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_128 = 0;
++ 			    p[5] &= ~MPPE_128BIT;
++ 			    newret = CONFNAK;
++ 			}
++ 			goto check_mppe;
++ 		    }
++		    p[5] &= ~MPPE_128BIT;
++ 		    newret = CONFNAK;
++ 		    goto check_mppe;
++ 		}
++ 	    check_mppe_56_40:
++		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT)) {
++ 		    newret = CONFNAK;
++ 		    if (ao->mppe_56) {
++ 			ho->mppe_56 = 1;
++ 			p[5] &= ~MPPE_40BIT;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++ 			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++ 			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_56 = 0;
++ 			    p[5] |= MPPE_40BIT;
++ 			    p[5] &= ~MPPE_56BIT;
++			    newret = CONFNAK;
++ 			    goto check_mppe_40;
++ 			}
++			goto check_mppe;
++ 		    }
++		    p[5] &= ~MPPE_56BIT;
++ 		    goto check_mppe_40;
++ 		}
++ 	    check_mppe_56:
++		if ((p[5] & ~MPPE_MPPC) == MPPE_56BIT) {
++ 		    if (ao->mppe_56) {
++ 			ho->mppe_56 = 1;
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++ 			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++ 				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_56 = 0;
++ 			    p[5] &= ~MPPE_56BIT;
++			    newret = CONFNAK;
++ 			}
++			goto check_mppe;
++ 		    }
++ 		    p[5] &= ~MPPE_56BIT;
++ 		    newret = CONFNAK;
++		    goto check_mppe;
++ 		}
++ 	    check_mppe_40:
++		if ((p[5] & ~MPPE_MPPC) == MPPE_40BIT) {
++ 		    if (ao->mppe_40) {
++ 			ho->mppe_40 = 1;
++ 			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++ 			      MPPE_MAX_KEY_LEN);
++ 			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++ 				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++ 			    ho->mppe_40 = 0;
++			    p[5] &= ~MPPE_40BIT;
++ 			    newret = CONFNAK;
++ 			}
++ 			goto check_mppe;
++ 		    }
++ 		    p[5] &= ~MPPE_40BIT;
++ 		}
++ 
++ 	    check_mppe:
++ 		if (!ho->mppe_40 && !ho->mppe_56 && !ho->mppe_128) {
++ 		    if (wo->mppe_40 || wo->mppe_56 || wo->mppe_128) {
++ 			newret = CONFNAK;
++ 			p[2] |= (wo->mppe_stateless ? MPPE_STATELESS : 0);
++			p[5] |= (wo->mppe_40 ? MPPE_40BIT : 0) |
++ 			    (wo->mppe_56 ? MPPE_56BIT : 0) |
++ 			    (wo->mppe_128 ? MPPE_128BIT : 0) |
++ 			    (wo->mppc ? MPPE_MPPC : 0);
++ 		    } else {
++ 			ho->mppe = ho->mppe_stateless = 0;
++ 		    }
+ 		} else {
+-		    /* Neither are set. */
+-		    /* We cannot accept this.  */
+-		    newret = CONFNAK;
+-		    /* Give the peer our idea of what can be used,
+-		       so it can choose and confirm */
+-		    ho->mppe = ao->mppe;
+-		}
+-
+-		/* rebuild the opts */
+-		MPPE_OPTS_TO_CI(ho->mppe, &p[2]);
+-		if (newret == CONFACK) {
+-		    u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
+-		    int mtu;
+-
+-		    BCOPY(p, opt_buf, CILEN_MPPE);
+-		    BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
+-			  MPPE_MAX_KEY_LEN);
+-		    if (ccp_test(f->unit, opt_buf,
+-				 CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) {
+-			/* This shouldn't happen, we've already tested it! */
+-			error("MPPE required, but kernel has no support.");
+-			lcp_close(f->unit, "MPPE required but not available");
+-			newret = CONFREJ;
+-			break;
+-		    }
+-		    /*
+-		     * We need to decrease the interface MTU by MPPE_PAD
+-		     * because MPPE frames **grow**.  The kernel [must]
+-		     * allocate MPPE_PAD extra bytes in xmit buffers.
+-		     */
+-		    mtu = netif_get_mtu(f->unit);
+-		    if (mtu)
+-			netif_set_mtu(f->unit, mtu - MPPE_PAD);
+-		    else
+-			newret = CONFREJ;
+-		}
+-
+-		/*
+-		 * We have accepted MPPE or are willing to negotiate
+-		 * MPPE parameters.  A CONFREJ is due to subsequent
+-		 * (non-MPPE) processing.
+-		 */
+-		rej_for_ci_mppe = 0;
+-		break;
+-#endif /* MPPE */
++ 		    /* MPPE is not compatible with other compression types */
++ 		    if (wo->mppe) {
++ 			ao->bsd_compress = 0;
++ 			ao->predictor_1 = 0;
++ 			ao->predictor_2 = 0;
++			ao->deflate = 0;
++ 			ao->lzs = 0;
++ 		    }
++ 		}
++ 		if ((!ho->mppc || !ao->mppc) && !ho->mppe) {
++ 		    p[2] = p2;
++ 		    p[5] = p5;
++  		    newret = CONFREJ;
++  		    break;
++  		}
++  
++ 		/*
++ 		 * I have commented the code below because according to RFC1547
++ 		 * MTU is only information for higher level protocols about
++ 		 * "the maximum allowable length for a packet (q.v.) transmitted
++ 		 * over a point-to-point link without incurring network layer
++ 		 * fragmentation." Of course a PPP implementation should be able
++ 		 * to handle overhead added by MPPE - in our case apropriate code
++ 		 * is located in drivers/net/ppp_generic.c in the kernel sources.
++		 *
++ 		 * According to RFC1661:
++ 		 * - when negotiated MRU is less than 1500 octets, a PPP
++ 		 *   implementation must still be able to receive at least 1500
++ 		 *   octets,
++ 		 * - when PFC is negotiated, a PPP implementation is still
++ 		 *   required to receive frames with uncompressed protocol field.
++		 *
++ 		 * So why not to handle MPPE overhead without changing MTU value?
++ 		 * I am sure that RFC3078, unfortunately silently, assumes that.
++ 		 */
++ 
++ 		/*
++ 		 * We need to decrease the interface MTU by MPPE_PAD
++ 		 * because MPPE frames **grow**.  The kernel [must]
++ 		 * allocate MPPE_PAD extra bytes in xmit buffers.
++ 		 */
++ /*
++ 		mtu = netif_get_mtu(f->unit);
++ 		if (mtu) {
++ 		    netif_set_mtu(f->unit, mtu - MPPE_PAD);
++ 		} else {
++		    newret = CONFREJ;
++ 		    if (ccp_wantoptions[f->unit].mppe) {
++ 			error("Cannot adjust MTU needed by MPPE.");
++ 			lcp_close(f->unit, "Cannot adjust MTU needed by MPPE.");
++ 		    }
++ 		}
++ */
++ 		break;
++  #endif /* MPPE */
++ 
++	    case CI_LZS:
++ 		if (!ao->lzs || clen != CILEN_LZS) {
++ 		    newret = CONFREJ;
++ 		    break;
++ 		}
++ 
++ 		ho->lzs = 1;
++		ho->lzs_hists = (p[2] << 8) | p[3];
++ 		ho->lzs_mode = p[4];
++	if ((ho->lzs_hists != ao->lzs_hists) ||
++		    (ho->lzs_mode != ao->lzs_mode)) {
++ 		    newret = CONFNAK;
++ 		    if (!dont_nak) {
++ 			p[2] = ao->lzs_hists >> 8;
++ 			p[3] = ao->lzs_hists & 0xff;
++ 			p[4] = ao->lzs_mode;
++	    } else
++ 			break;
++ 		}
++ 
++ 		if (p == p0 && ccp_test(f->unit, p, CILEN_LZS, 1) <= 0) {
++ 		    newret = CONFREJ;
++ 		}
++ 		break;
+ 	    case CI_DEFLATE:
+ 	    case CI_DEFLATE_DRAFT:
+ 		if (!ao->deflate || clen != CILEN_DEFLATE
+@@ -1344,12 +1830,6 @@ ccp_reqci(f, p, lenp, dont_nak)
+ 	else
+ 	    *lenp = retp - p0;
+     }
+-#ifdef MPPE
+-    if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) {
+-	error("MPPE required but peer negotiation failed");
+-	lcp_close(f->unit, "MPPE required but peer negotiation failed");
+-    }
+-#endif
+     return ret;
+ }
+ 
+@@ -1371,24 +1851,35 @@ method_name(opt, opt2)
+ 	char *p = result;
+ 	char *q = result + sizeof(result); /* 1 past result */
+ 
+-	slprintf(p, q - p, "MPPE ");
+-	p += 5;
+-	if (opt->mppe & MPPE_OPT_128) {
+-	    slprintf(p, q - p, "128-bit ");
+-	    p += 8;
+-	}
+-	if (opt->mppe & MPPE_OPT_40) {
+-	    slprintf(p, q - p, "40-bit ");
+-	    p += 7;
+-	}
+-	if (opt->mppe & MPPE_OPT_STATEFUL)
+-	    slprintf(p, q - p, "stateful");
+-	else
+-	    slprintf(p, q - p, "stateless");
+-
++	if (opt->mppe) {
++	    if (opt->mppc) {
++		slprintf(p, q - p, "MPPC/MPPE ");
++		p += 10;
++	    } else {
++		slprintf(p, q - p, "MPPE ");
++		p += 5;
++	    }
++	    if (opt->mppe_128) {
++		slprintf(p, q - p, "128-bit ");
++		p += 8;
++	    } else if (opt->mppe_56) {
++		slprintf(p, q - p, "56-bit ");
++		p += 7;
++	    } else if (opt->mppe_40) {
++		slprintf(p, q - p, "40-bit ");
++		p += 7;
++	    }
++	    if (opt->mppe_stateless)
++		slprintf(p, q - p, "stateless");
++	    else
++		slprintf(p, q - p, "stateful");
++	} else if (opt->mppc)
++	    slprintf(p, q - p, "MPPC");
+ 	break;
+     }
+-#endif
++#endif /* MPPE */
++    case CI_LZS:
++	return "Stac LZS";
+     case CI_DEFLATE:
+     case CI_DEFLATE_DRAFT:
+ 	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+@@ -1444,12 +1935,12 @@ ccp_up(f)
+     } else if (ANY_COMPRESS(*ho))
+ 	notice("%s transmit compression enabled", method_name(ho, NULL));
+ #ifdef MPPE
+-    if (go->mppe) {
++    if (go->mppe || go->mppc) {
+ 	BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN);
+ 	BZERO(mppe_send_key, MPPE_MAX_KEY_LEN);
+ 	continue_networks(f->unit);		/* Bring up IP et al */
+     }
+-#endif
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -1472,7 +1963,7 @@ ccp_down(f)
+ 	    lcp_close(f->unit, "MPPE disabled");
+ 	}
+     }
+-#endif
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -1532,24 +2023,28 @@ ccp_printpkt(p, plen, printer, arg)
+ #ifdef MPPE
+ 	    case CI_MPPE:
+ 		if (optlen >= CILEN_MPPE) {
+-		    u_char mppe_opts;
+-
+-		    MPPE_CI_TO_OPTS(&p[2], mppe_opts);
+-		    printer(arg, "mppe %s %s %s %s %s %s%s",
+-			    (p[2] & MPPE_H_BIT)? "+H": "-H",
+-			    (p[5] & MPPE_M_BIT)? "+M": "-M",
+-			    (p[5] & MPPE_S_BIT)? "+S": "-S",
+-			    (p[5] & MPPE_L_BIT)? "+L": "-L",
++		    printer(arg, "mppe %s %s %s %s %s %s",
++			    (p[2] & MPPE_STATELESS)? "+H": "-H",
++			    (p[5] & MPPE_56BIT)? "+M": "-M",
++			    (p[5] & MPPE_128BIT)? "+S": "-S",
++			    (p[5] & MPPE_40BIT)? "+L": "-L",
+ 			    (p[5] & MPPE_D_BIT)? "+D": "-D",
+-			    (p[5] & MPPE_C_BIT)? "+C": "-C",
+-			    (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": "");
+-		    if (mppe_opts & MPPE_OPT_UNKNOWN)
++			    (p[5] & MPPE_MPPC)? "+C": "-C");
++		    if ((p[5] & ~(MPPE_56BIT | MPPE_128BIT | MPPE_40BIT |
++				  MPPE_D_BIT | MPPE_MPPC)) ||
++			(p[2] & ~MPPE_STATELESS))
+ 			printer(arg, " (%.2x %.2x %.2x %.2x)",
+ 				p[2], p[3], p[4], p[5]);
+ 		    p += CILEN_MPPE;
+ 		}
+ 		break;
+-#endif
++#endif /* MPPE */
++	    case CI_LZS:
++		if (optlen >= CILEN_LZS) {
++		    printer(arg, "lzs %.2x %.2x %.2x", p[2], p[3], p[4]);
++		    p += CILEN_LZS;
++		}
++		break;
+ 	    case CI_DEFLATE:
+ 	    case CI_DEFLATE_DRAFT:
+ 		if (optlen >= CILEN_DEFLATE) {
+@@ -1635,6 +2130,7 @@ ccp_datainput(unit, pkt, len)
+ 	    error("Lost compression sync: disabling compression");
+ 	    ccp_close(unit, "Lost compression sync");
+ #ifdef MPPE
++	    /* My module dosn't need this. J.D., 2003-07-06 */
+ 	    /*
+ 	     * If we were doing MPPE, we must also take the link down.
+ 	     */
+@@ -1642,9 +2138,18 @@ ccp_datainput(unit, pkt, len)
+ 		error("Too many MPPE errors, closing LCP");
+ 		lcp_close(unit, "Too many MPPE errors");
+ 	    }
+-#endif
++#endif /* MPPE */
+ 	} else {
+ 	    /*
++	     * When LZS or MPPE/MPPC is negotiated we just send CCP_RESETREQ
++	     * and don't wait for CCP_RESETACK
++	     */
++	    if ((ccp_gotoptions[f->unit].method == CI_LZS) ||
++		(ccp_gotoptions[f->unit].method == CI_MPPE)) {
++		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
++		return;
++	    }
++	    /*
+ 	     * Send a reset-request to reset the peer's compressor.
+ 	     * We don't do that if we are still waiting for an
+ 	     * acknowledgement to a previous reset-request.
+--- a/pppd/ccp.h
++++ b/pppd/ccp.h
+@@ -37,9 +37,17 @@ typedef struct ccp_options {
+     bool predictor_2;		/* do Predictor-2? */
+     bool deflate_correct;	/* use correct code for deflate? */
+     bool deflate_draft;		/* use draft RFC code for deflate? */
++    bool lzs;			/* do Stac LZS? */
++    bool mppc;			/* do MPPC? */
+     bool mppe;			/* do MPPE? */
++    bool mppe_40;		/* allow 40 bit encryption? */
++    bool mppe_56;		/* allow 56 bit encryption? */
++    bool mppe_128;		/* allow 128 bit encryption? */
++    bool mppe_stateless;	/* allow stateless encryption */
+     u_short bsd_bits;		/* # bits/code for BSD Compress */
+     u_short deflate_size;	/* lg(window size) for Deflate */
++    u_short lzs_mode;		/* LZS check mode */
++    u_short lzs_hists;		/* number of LZS histories */
+     short method;		/* code for chosen compression method */
+ } ccp_options;
+ 
+--- a/pppd/chap_ms.c
++++ b/pppd/chap_ms.c
+@@ -963,13 +963,17 @@ set_mppe_enc_types(int policy, int types
+     /*
+      * Disable undesirable encryption types.  Note that we don't ENABLE
+      * any encryption types, to avoid overriding manual configuration.
++     *
++     * It seems that 56 bit keys are unsupported in MS-RADIUS (see RFC 2548)
+      */
+     switch(types) {
+ 	case MPPE_ENC_TYPES_RC4_40:
+-	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
++	    ccp_wantoptions[0].mppe_128 = 0;	/* disable 128-bit */
++	    ccp_wantoptions[0].mppe_56 = 0;	/* disable 56-bit */
+ 	    break;
+ 	case MPPE_ENC_TYPES_RC4_128:
+-	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
++	    ccp_wantoptions[0].mppe_56 = 0;	/* disable 56-bit */
++	    ccp_wantoptions[0].mppe_40 = 0;	/* disable 40-bit */
+ 	    break;
+ 	default:
+ 	    break;
diff --git a/package/network/services/ppp/patches/202-no_strip.patch b/package/network/services/ppp/patches/202-no_strip.patch
new file mode 100644
index 0000000000..29d8f746bb
--- /dev/null
+++ b/package/network/services/ppp/patches/202-no_strip.patch
@@ -0,0 +1,88 @@
+build: Do not strip binaries on install
+
+Strippign executables should be handled by the distro packaging, not by ppp
+itself. This patch removes the "-s" (strip) switch from all "install" commands
+in order to install unstripped binaries into the destination prefix.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/chat/Makefile.linux
++++ b/chat/Makefile.linux
+@@ -25,7 +25,7 @@ chat.o:	chat.c
+ 
+ install: chat
+ 	mkdir -p $(BINDIR) $(MANDIR)
+-	$(INSTALL) -s -c chat $(BINDIR)
++	$(INSTALL) -c chat $(BINDIR)
+ 	$(INSTALL) -c -m 644 chat.8 $(MANDIR)
+ 
+ clean:
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -102,7 +102,7 @@ ifdef USE_SRP
+ CFLAGS	+= -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
+ LIBS	+= -lsrp -L/usr/local/ssl/lib -lcrypto
+ TARGETS	+= srp-entry
+-EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
++EXTRAINSTALL = $(INSTALL) -c -m 555 srp-entry $(BINDIR)/srp-entry
+ MANPAGES += srp-entry.8
+ EXTRACLEAN += srp-entry.o
+ NEEDDES=y
+@@ -208,7 +208,7 @@ all: $(TARGETS)
+ install: pppd
+ 	mkdir -p $(BINDIR) $(MANDIR)
+ 	$(EXTRAINSTALL)
+-	$(INSTALL) -s -c -m 555 pppd $(BINDIR)/pppd
++	$(INSTALL) -c -m 555 pppd $(BINDIR)/pppd
+ 	if chgrp pppusers $(BINDIR)/pppd 2>/dev/null; then \
+ 	  chmod o-rx,u+s $(BINDIR)/pppd; fi
+ 	$(INSTALL) -c -m 444 pppd.8 $(MANDIR)
+--- a/pppd/plugins/radius/Makefile.linux
++++ b/pppd/plugins/radius/Makefile.linux
+@@ -36,9 +36,9 @@ all: $(PLUGIN)
+ 
+ install: all
+ 	$(INSTALL) -d -m 755 $(LIBDIR)
+-	$(INSTALL) -s -c -m 755 radius.so $(LIBDIR)
+-	$(INSTALL) -s -c -m 755 radattr.so $(LIBDIR)
+-	$(INSTALL) -s -c -m 755 radrealms.so $(LIBDIR)
++	$(INSTALL) -c -m 755 radius.so $(LIBDIR)
++	$(INSTALL) -c -m 755 radattr.so $(LIBDIR)
++	$(INSTALL) -c -m 755 radrealms.so $(LIBDIR)
+ 	$(INSTALL) -c -m 444 pppd-radius.8 $(MANDIR)
+ 	$(INSTALL) -c -m 444 pppd-radattr.8 $(MANDIR)
+ 
+--- a/pppd/plugins/rp-pppoe/Makefile.linux
++++ b/pppd/plugins/rp-pppoe/Makefile.linux
+@@ -43,9 +43,9 @@ rp-pppoe.so: plugin.o discovery.o if.o c
+ 
+ install: all
+ 	$(INSTALL) -d -m 755 $(LIBDIR)
+-	$(INSTALL) -s -c -m 4550 rp-pppoe.so $(LIBDIR)
++	$(INSTALL) -c -m 4550 rp-pppoe.so $(LIBDIR)
+ 	$(INSTALL) -d -m 755 $(BINDIR)
+-	$(INSTALL) -s -c -m 555 pppoe-discovery $(BINDIR)
++	$(INSTALL) -c -m 555 pppoe-discovery $(BINDIR)
+ 
+ clean:
+ 	rm -f *.o *.so pppoe-discovery
+--- a/pppdump/Makefile.linux
++++ b/pppdump/Makefile.linux
+@@ -17,5 +17,5 @@ clean:
+ 
+ install:
+ 	mkdir -p $(BINDIR) $(MANDIR)
+-	$(INSTALL) -s -c pppdump $(BINDIR)
++	$(INSTALL) -c pppdump $(BINDIR)
+ 	$(INSTALL) -c -m 444 pppdump.8 $(MANDIR)
+--- a/pppstats/Makefile.linux
++++ b/pppstats/Makefile.linux
+@@ -22,7 +22,7 @@ all: pppstats
+ 
+ install: pppstats
+ 	-mkdir -p $(MANDIR)
+-	$(INSTALL) -s -c pppstats $(BINDIR)
++	$(INSTALL) -c pppstats $(BINDIR)
+ 	$(INSTALL) -c -m 444 pppstats.8 $(MANDIR)
+ 
+ pppstats: $(PPPSTATSRCS)
diff --git a/package/network/services/ppp/patches/203-opt_flags.patch b/package/network/services/ppp/patches/203-opt_flags.patch
new file mode 100644
index 0000000000..d0eb918299
--- /dev/null
+++ b/package/network/services/ppp/patches/203-opt_flags.patch
@@ -0,0 +1,32 @@
+build: Move optimization flags into a separate variable
+
+Isolate optimization related compiler flags from CFLAGS and move them into a
+separate COPTS variable so that it is easier to override optimizations from
+the environment.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/plugins/radius/Makefile.linux
++++ b/pppd/plugins/radius/Makefile.linux
+@@ -12,7 +12,8 @@ VERSION = $(shell awk -F '"' '/VERSION/
+ INSTALL	= install
+ 
+ PLUGIN=radius.so radattr.so radrealms.so
+-CFLAGS=-I. -I../.. -I../../../include -O2 -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
++COPTS = -O2
++CFLAGS=-I. -I../.. -I../../../include $(COPTS) -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
+ 
+ # Uncomment the next line to include support for Microsoft's
+ # MS-CHAP authentication protocol.
+--- a/pppdump/Makefile.linux
++++ b/pppdump/Makefile.linux
+@@ -2,7 +2,8 @@ DESTDIR = $(INSTROOT)@DESTDIR@
+ BINDIR = $(DESTDIR)/sbin
+ MANDIR = $(DESTDIR)/share/man/man8
+ 
+-CFLAGS= -O -I../include/net
++COPTS = -O
++CFLAGS= $(COPTS) -I../include/net
+ OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+ 
+ INSTALL= install
diff --git a/package/network/services/ppp/patches/204-radius_config.patch b/package/network/services/ppp/patches/204-radius_config.patch
new file mode 100644
index 0000000000..c97a535079
--- /dev/null
+++ b/package/network/services/ppp/patches/204-radius_config.patch
@@ -0,0 +1,72 @@
+--- a/pppd/plugins/radius/config.c
++++ b/pppd/plugins/radius/config.c
+@@ -369,31 +369,37 @@ static int test_config(char *filename)
+ 	}
+ #endif
+ 
++#if 0
+ 	if (rc_conf_int("login_tries") <= 0)
+ 	{
+ 		error("%s: login_tries <= 0 is illegal", filename);
+ 		return (-1);
+ 	}
++#endif
+ 	if (rc_conf_str("seqfile") == NULL)
+ 	{
+ 		error("%s: seqfile not specified", filename);
+ 		return (-1);
+ 	}
++#if 0
+ 	if (rc_conf_int("login_timeout") <= 0)
+ 	{
+ 		error("%s: login_timeout <= 0 is illegal", filename);
+ 		return (-1);
+ 	}
++#endif
+ 	if (rc_conf_str("mapfile") == NULL)
+ 	{
+ 		error("%s: mapfile not specified", filename);
+ 		return (-1);
+ 	}
++#if 0
+ 	if (rc_conf_str("nologin") == NULL)
+ 	{
+ 		error("%s: nologin not specified", filename);
+ 		return (-1);
+ 	}
++#endif
+ 
+ 	return 0;
+ }
+--- a/pppd/plugins/radius/options.h
++++ b/pppd/plugins/radius/options.h
+@@ -31,24 +31,21 @@ typedef struct _option {
+ static SERVER acctserver = {0};
+ static SERVER authserver = {0};
+ 
+-int default_tries = 4;
+-int default_timeout = 60;
+-
+ static OPTION config_options[] = {
+ /* internally used options */
+ {"config_file",		OT_STR, ST_UNDEF, NULL},
+ /* General options */
+ {"auth_order",	 	OT_AUO, ST_UNDEF, NULL},
+-{"login_tries",	 	OT_INT, ST_UNDEF, &default_tries},
+-{"login_timeout",	OT_INT, ST_UNDEF, &default_timeout},
+-{"nologin",		OT_STR, ST_UNDEF, "/etc/nologin"},
+-{"issue",		OT_STR, ST_UNDEF, "/etc/radiusclient/issue"},
++{"login_tries",	 	OT_INT, ST_UNDEF, NULL},
++{"login_timeout",	OT_INT, ST_UNDEF, NULL},
++{"nologin",		OT_STR, ST_UNDEF, NULL},
++{"issue",		OT_STR, ST_UNDEF, NULL},
+ /* RADIUS specific options */
+ {"authserver",		OT_SRV, ST_UNDEF, &authserver},
+ {"acctserver",		OT_SRV, ST_UNDEF, &acctserver},
+ {"servers",		OT_STR, ST_UNDEF, NULL},
+ {"dictionary",		OT_STR, ST_UNDEF, NULL},
+-{"login_radius",	OT_STR, ST_UNDEF, "/usr/sbin/login.radius"},
++{"login_radius",	OT_STR, ST_UNDEF, NULL},
+ {"seqfile",		OT_STR, ST_UNDEF, NULL},
+ {"mapfile",		OT_STR, ST_UNDEF, NULL},
+ {"default_realm",	OT_STR, ST_UNDEF, NULL},
diff --git a/package/network/services/ppp/patches/205-no_exponential_timeout.patch b/package/network/services/ppp/patches/205-no_exponential_timeout.patch
new file mode 100644
index 0000000000..1395ca5177
--- /dev/null
+++ b/package/network/services/ppp/patches/205-no_exponential_timeout.patch
@@ -0,0 +1,29 @@
+pppd: Don't use exponential timeout in discovery phase
+
+This patch removes the exponential timeout increase between PADO or PADS
+discovery attempts.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/plugins/rp-pppoe/discovery.c
++++ b/pppd/plugins/rp-pppoe/discovery.c
+@@ -644,7 +644,9 @@ discovery(PPPoEConnection *conn)
+ 	conn->discoveryState = STATE_SENT_PADI;
+ 	waitForPADO(conn, timeout);
+ 
++#if 0
+ 	timeout *= 2;
++#endif
+     } while (conn->discoveryState == STATE_SENT_PADI);
+ 
+     timeout = conn->discoveryTimeout;
+@@ -659,7 +661,9 @@ discovery(PPPoEConnection *conn)
+ 	sendPADR(conn);
+ 	conn->discoveryState = STATE_SENT_PADR;
+ 	waitForPADS(conn, timeout);
++#if 0
+ 	timeout *= 2;
++#endif
+     } while (conn->discoveryState == STATE_SENT_PADR);
+ 
+     if (!conn->seenMaxPayload) {
diff --git a/package/network/services/ppp/patches/206-compensate_time_change.patch b/package/network/services/ppp/patches/206-compensate_time_change.patch
new file mode 100644
index 0000000000..31a582a202
--- /dev/null
+++ b/package/network/services/ppp/patches/206-compensate_time_change.patch
@@ -0,0 +1,94 @@
+pppd: Watch out for time warps
+
+On many embedded systems there is no battery backed RTC and a proper system
+time only becomes available through NTP after establishing a connection.
+
+When the clock suddenly jumps forward, the internal accounting (connect time)
+is confused resulting in unreliable data.
+
+This patch implements periodic clock checking to look for time warps, if one
+is detected, the internal counters are adjusted accordingly.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -90,6 +90,7 @@
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
++#include <sys/sysinfo.h>
+ 
+ #include "pppd.h"
+ #include "magic.h"
+@@ -228,6 +229,7 @@ static struct subprocess *children;
+ 
+ /* Prototypes for procedures local to this file. */
+ 
++static void check_time(void);
+ static void setup_signals __P((void));
+ static void create_pidfile __P((int pid));
+ static void create_linkpidfile __P((int pid));
+@@ -535,6 +537,7 @@ main(argc, argv)
+ 	    info("Starting link");
+ 	}
+ 
++	check_time();
+ 	gettimeofday(&start_time, NULL);
+ 	script_unsetenv("CONNECT_TIME");
+ 	script_unsetenv("BYTES_SENT");
+@@ -1267,6 +1270,36 @@ struct	callout {
+ 
+ static struct callout *callout = NULL;	/* Callout list */
+ static struct timeval timenow;		/* Current time */
++static long uptime_diff = 0;
++static int uptime_diff_set = 0;
++
++static void check_time(void)
++{
++	long new_diff;
++	struct timeval t;
++	struct sysinfo i;
++    struct callout *p;
++	
++	gettimeofday(&t, NULL);
++	sysinfo(&i);
++	new_diff = t.tv_sec - i.uptime;
++	
++	if (!uptime_diff_set) {
++		uptime_diff = new_diff;
++		uptime_diff_set = 1;
++		return;
++	}
++
++	if ((new_diff - 5 > uptime_diff) || (new_diff + 5 < uptime_diff)) {
++		/* system time has changed, update counters and timeouts */
++		info("System time change detected.");
++		start_time.tv_sec += new_diff - uptime_diff;
++		
++    	for (p = callout; p != NULL; p = p->c_next)
++			p->c_time.tv_sec += new_diff - uptime_diff;
++	}
++	uptime_diff = new_diff;
++}
+ 
+ /*
+  * timeout - Schedule a timeout.
+@@ -1337,6 +1370,8 @@ calltimeout()
+ {
+     struct callout *p;
+ 
++	check_time();
++	
+     while (callout != NULL) {
+ 	p = callout;
+ 
+@@ -1364,6 +1399,8 @@ timeleft(tvp)
+ {
+     if (callout == NULL)
+ 	return NULL;
++	
++	check_time();
+ 
+     gettimeofday(&timenow, NULL);
+     tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
diff --git a/package/network/services/ppp/patches/207-lcp_mtu_max.patch b/package/network/services/ppp/patches/207-lcp_mtu_max.patch
new file mode 100644
index 0000000000..f406f685e0
--- /dev/null
+++ b/package/network/services/ppp/patches/207-lcp_mtu_max.patch
@@ -0,0 +1,25 @@
+pppd: Cap MTU to the user configured value
+
+This patchs caps the calculated MTU value in lcp.c to the user specified "mru"
+option value. Without this patch pppd would advertise a different MTU value
+compared to what is set on the local interface in some cases.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/lcp.c
++++ b/pppd/lcp.c
+@@ -1917,12 +1917,12 @@ lcp_up(f)
+      * the interface MTU is set to the lowest of that, the
+      * MTU we want to use, and our link MRU.
+      */
+-    mtu = ho->neg_mru? ho->mru: PPP_MRU;
++    mtu = MIN(ho->neg_mru? ho->mru: PPP_MRU, ao->mru);
+     mru = go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU;
+ #ifdef HAVE_MULTILINK
+     if (!(multilink && go->neg_mrru && ho->neg_mrru))
+ #endif /* HAVE_MULTILINK */
+-	netif_set_mtu(f->unit, MIN(MIN(mtu, mru), ao->mru));
++	netif_set_mtu(f->unit, MIN(mtu, mru));
+     ppp_send_config(f->unit, mtu,
+ 		    (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+ 		    ho->neg_pcompression, ho->neg_accompression);
diff --git a/package/network/services/ppp/patches/208-fix_status_code.patch b/package/network/services/ppp/patches/208-fix_status_code.patch
new file mode 100644
index 0000000000..eb24b0a055
--- /dev/null
+++ b/package/network/services/ppp/patches/208-fix_status_code.patch
@@ -0,0 +1,24 @@
+pppd: Do not clobber exit codes on hangup
+
+When a modem hangup occurs, pppd unconditionally sets the exit status code
+to EXIT_HANGUP. This patch only sets EXIT_HANGUP if the exit status code is
+not already set to an error value.
+
+The motiviation of this patch is to allow applications which remote control
+pppd to react properly on errors, e.g. only redial (relaunch pppd) if there
+was a hangup, but not if the CHAP authentication failed.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -1048,7 +1048,8 @@ get_input()
+ 	}
+ 	notice("Modem hangup");
+ 	hungup = 1;
+-	status = EXIT_HANGUP;
++	if (status == EXIT_OK)
++		status = EXIT_HANGUP;
+ 	lcp_lowerdown(0);	/* serial link is no longer available */
+ 	link_terminated(0);
+ 	return;
diff --git a/package/network/services/ppp/patches/300-filter-pcap-includes-lib.patch b/package/network/services/ppp/patches/300-filter-pcap-includes-lib.patch
new file mode 100644
index 0000000000..68a56aa6e1
--- /dev/null
+++ b/package/network/services/ppp/patches/300-filter-pcap-includes-lib.patch
@@ -0,0 +1,20 @@
+build: Add required CFLAGS for libpcap
+
+This patch adds some flags to required to properly link libpcap within the
+OpenWrt environment.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -178,8 +178,8 @@ endif
+ 
+ ifdef FILTER
+ ifneq ($(wildcard /usr/include/pcap-bpf.h),)
+-LIBS    += -lpcap
+-CFLAGS  += -DPPP_FILTER
++LIBS    += -lpcap -L$(STAGING_DIR)/usr/lib
++CFLAGS  += -DPPP_FILTER -I$(STAGING_DIR)/usr/include
+ endif
+ endif
+ 
diff --git a/package/network/services/ppp/patches/310-precompile_filter.patch b/package/network/services/ppp/patches/310-precompile_filter.patch
new file mode 100644
index 0000000000..701e49d321
--- /dev/null
+++ b/package/network/services/ppp/patches/310-precompile_filter.patch
@@ -0,0 +1,196 @@
+pppd: Implement support for precompiled pcap filters
+
+This patch implements support for precompiled pcap filters which is useful to
+support dial-on-demand on memory constrained embedded devices without having
+to link the full libpcap into pppd to generate the filters during runtime.
+
+Two new options are introduced; "precompiled-pass-filter" specifies a pre-
+compiled filter file containing rules to match packets which should be passed,
+"precompiled-active-filter" specifies a filter file containing rules to match
+packets which are treated as active.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/Makefile.linux
++++ b/pppd/Makefile.linux
+@@ -50,6 +50,9 @@ MPPE=y
+ # and that the kernel driver support PPP packet filtering.
+ #FILTER=y
+ 
++# Support for precompiled filters
++PRECOMPILED_FILTER=y
++
+ # Uncomment the next line to enable multilink PPP (enabled by default)
+ # Linux distributions: Please leave multilink ENABLED in your builds
+ # of pppd!
+@@ -183,6 +186,14 @@ CFLAGS  += -DPPP_FILTER -I$(STAGING_DIR)
+ endif
+ endif
+ 
++ifdef PRECOMPILED_FILTER
++PPPDSRCS += pcap_pcc.c
++HEADERS  += pcap_pcc.h
++PPPDOBJS += pcap_pcc.o
++LIBS	+= $(STAGING_DIR)/usr/lib/libpcap.a
++CFLAGS	+= -DPPP_FILTER -DPPP_PRECOMPILED_FILTER -I$(STAGING_DIR)/usr/include
++endif
++
+ ifdef HAVE_INET6
+      PPPDSRCS += ipv6cp.c eui64.c
+      HEADERS  += ipv6cp.h eui64.h
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -57,6 +57,7 @@
+ 
+ #ifdef PPP_FILTER
+ #include <pcap.h>
++#include <pcap-bpf.h>
+ /*
+  * There have been 3 or 4 different names for this in libpcap CVS, but
+  * this seems to be what they have settled on...
+@@ -165,6 +166,13 @@ static int setlogfile __P((char **));
+ static int loadplugin __P((char **));
+ #endif
+ 
++#ifdef PPP_PRECOMPILED_FILTER
++#include "pcap_pcc.h"
++static int setprecompiledpassfilter __P((char **));
++static int setprecompiledactivefilter __P((char **));
++#undef PPP_FILTER
++#endif
++
+ #ifdef PPP_FILTER
+ static int setpassfilter __P((char **));
+ static int setactivefilter __P((char **));
+@@ -344,6 +352,14 @@ option_t general_options[] = {
+       "set filter for active pkts", OPT_PRIO },
+ #endif
+ 
++#ifdef PPP_PRECOMPILED_FILTER
++    { "precompiled-pass-filter", 1, setprecompiledpassfilter,
++      "set precompiled filter for packets to pass", OPT_PRIO },
++
++    { "precompiled-active-filter", 1, setprecompiledactivefilter,
++      "set precompiled filter for active pkts", OPT_PRIO },
++#endif
++
+ #ifdef MAXOCTETS
+     { "maxoctets", o_int, &maxoctets,
+       "Set connection traffic limit",
+@@ -1493,6 +1509,29 @@ callfile(argv)
+     return ok;
+ }
+ 
++#ifdef PPP_PRECOMPILED_FILTER
++/*
++ * setprecompiledpassfilter - Set the pass filter for packets using a
++ * precompiled expression
++ */
++static int
++setprecompiledpassfilter(argv)
++    char **argv;
++{
++    return pcap_pre_compiled (*argv, &pass_filter);
++}
++
++/*
++ * setactivefilter - Set the active filter for packets
++ */
++static int
++setprecompiledactivefilter(argv)
++    char **argv;
++{
++    return pcap_pre_compiled (*argv, &active_filter);
++}
++#endif
++
+ #ifdef PPP_FILTER
+ /*
+  * setpassfilter - Set the pass filter for packets
+--- /dev/null
++++ b/pppd/pcap_pcc.c
+@@ -0,0 +1,74 @@
++#include <pcap.h>
++#include <pcap-bpf.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include "pppd.h"
++
++int pcap_pre_compiled (char * fname, struct bpf_program *p)
++{
++    char buf[128];
++    int line = 0, size = 0, index=0, ret=1;
++    FILE *f = fopen (fname, "r");
++    if (!f)
++    {
++       option_error("error opening precompiled active-filter '%s': %s",
++                    fname, strerror (errno));
++       return 0;
++    }
++    while (fgets (buf, 127, f))
++    {
++       line++;
++       if (*buf == '#')
++           continue;
++       if (size)
++       {
++           /*
++             struct bpf_insn {
++             u_short   code;
++             u_char    jt;
++             u_char    jf;
++             bpf_int32 k;
++             }
++           */
++           struct bpf_insn * insn = & p->bf_insns[index];
++           unsigned code, jt, jf, k;
++           if (sscanf (buf, "%u %u %u %u", &code, &jt, &jf, &k) != 4)
++           {
++               goto err;
++           }
++           insn->code = code;
++           insn->jt = jt;
++           insn->jf = jf;
++           insn->k  = k;
++           index++;
++       }
++       else
++       {
++           if (sscanf (buf, "%u", &size) != 1)
++           {
++               goto err;
++           }
++           p->bf_len = size;
++           p->bf_insns = (struct bpf_insn *) 
++               malloc (size * sizeof (struct bpf_insn));
++       }
++    } 
++    if (size != index)
++    {
++       option_error("error in precompiled active-filter,"
++                    " expected %d expressions, got %dn",
++                    size, index);
++       ret = 0;
++    }
++    fclose(f);
++    return ret;
++
++err:
++  option_error("error in precompiled active-filter"
++              " expression line %s:%d (wrong size)\n", 
++              fname, line);
++  fclose (f);
++  return 0;
++}
+--- /dev/null
++++ b/pppd/pcap_pcc.h
+@@ -0,0 +1,7 @@
++#ifndef PCAP_PCC_H
++#define PCAP_PCC_H
++
++#include <pcap.h>
++
++int pcap_pre_compiled (char * fname, struct bpf_program *p);
++#endif /* PCAP_PCC_H */
diff --git a/package/network/services/ppp/patches/320-custom_iface_names.patch b/package/network/services/ppp/patches/320-custom_iface_names.patch
new file mode 100644
index 0000000000..441f9eec61
--- /dev/null
+++ b/package/network/services/ppp/patches/320-custom_iface_names.patch
@@ -0,0 +1,135 @@
+pppd: Support arbitrary interface names
+
+This patch implements a new string option "ifname" which allows to specify
+fully custom PPP interface names on Linux. It does so by renaming the
+allocated pppX device immediately after it has been created to the requested
+interface name.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -745,8 +745,11 @@ void
+ set_ifunit(iskey)
+     int iskey;
+ {
+-    info("Using interface %s%d", PPP_DRV_NAME, ifunit);
+-    slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
++    if (use_ifname[0] == 0)
++	slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
++    else
++	slprintf(ifname, sizeof(ifname), "%s", use_ifname);
++    info("Using interface %s", ifname);
+     script_setenv("IFNAME", ifname, iskey);
+     if (iskey) {
+ 	create_pidfile(getpid());	/* write pid to file */
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -112,6 +112,7 @@ int	log_to_fd = 1;		/* send log messages
+ bool	log_default = 1;	/* log_to_fd is default (stdout) */
+ int	maxfail = 10;		/* max # of unsuccessful connection attempts */
+ char	linkname[MAXPATHLEN];	/* logical name for link */
++char	use_ifname[IFNAMSIZ];	/* physical name for PPP link */
+ bool	tune_kernel;		/* may alter kernel settings */
+ int	connect_delay = 1000;	/* wait this many ms after connect script */
+ int	req_unit = -1;		/* requested interface unit */
+@@ -277,6 +278,9 @@ option_t general_options[] = {
+     { "linkname", o_string, linkname,
+       "Set logical name for link",
+       OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
++    { "ifname", o_string, use_ifname,
++      "Set physical name for PPP interface",
++      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, IFNAMSIZ },
+ 
+     { "maxfail", o_int, &maxfail,
+       "Maximum number of unsuccessful connection attempts to allow",
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -74,6 +74,10 @@
+ #include "eui64.h"
+ #endif
+ 
++#ifndef IFNAMSIZ
++#define IFNAMSIZ	16
++#endif
++
+ /*
+  * Limits.
+  */
+@@ -317,6 +321,7 @@ extern char	*record_file;	/* File to rec
+ extern bool	sync_serial;	/* Device is synchronous serial device */
+ extern int	maxfail;	/* Max # of unsuccessful connection attempts */
+ extern char	linkname[MAXPATHLEN]; /* logical name for link */
++extern char	use_ifname[IFNAMSIZ]; /* physical name for PPP interface */
+ extern bool	tune_kernel;	/* May alter kernel settings as necessary */
+ extern int	connect_delay;	/* Time to delay after connect script */
+ extern int	max_data_rate;	/* max bytes/sec through charshunt */
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -161,6 +161,10 @@ struct in6_ifreq {
+ /* We can get an EIO error on an ioctl if the modem has hung up */
+ #define ok_error(num) ((num)==EIO)
+ 
++#if !defined(PPP_DRV_NAME)
++#define PPP_DRV_NAME	"ppp"
++#endif /* !defined(PPP_DRV_NAME) */
++
+ static int tty_disc = N_TTY;	/* The TTY discipline */
+ static int ppp_disc = N_PPP;	/* The PPP discpline */
+ static int initfdflags = -1;	/* Initial file descriptor flags for fd */
+@@ -620,7 +624,8 @@ void generic_disestablish_ppp(int dev_fd
+  */
+ static int make_ppp_unit()
+ {
+-	int x, flags;
++	struct ifreq ifr;
++	int x, flags, s;
+ 
+ 	if (ppp_dev_fd >= 0) {
+ 		dbglog("in make_ppp_unit, already had /dev/ppp open?");
+@@ -643,6 +648,30 @@ static int make_ppp_unit()
+ 	}
+ 	if (x < 0)
+ 		error("Couldn't create new ppp unit: %m");
++
++	if (use_ifname[0] != 0) {
++		s = socket(PF_INET, SOCK_DGRAM, 0);
++		if (s < 0)
++			s = socket(PF_PACKET, SOCK_DGRAM, 0);
++		if (s < 0)
++			s = socket(PF_INET6, SOCK_DGRAM, 0);
++		if (s < 0)
++			s = socket(PF_UNIX, SOCK_DGRAM, 0);
++		if (s >= 0) {
++			slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", PPP_DRV_NAME, ifunit);
++			slprintf(ifr.ifr_newname, sizeof(ifr.ifr_newname), "%s", use_ifname);
++			x = ioctl(s, SIOCSIFNAME, &ifr);
++			close(s);
++		} else {
++			x = s;
++		}
++		if (x < 0) {
++			error("Couldn't rename %s to %s", ifr.ifr_name, ifr.ifr_newname);
++			close(ppp_dev_fd);
++			ppp_dev_fd = -1;
++		}
++	}
++
+ 	return x;
+ }
+ 
+--- a/pppstats/pppstats.c
++++ b/pppstats/pppstats.c
+@@ -506,10 +506,12 @@ main(argc, argv)
+     if (argc > 0)
+ 	interface = argv[0];
+ 
++#if 0
+     if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
+ 	fprintf(stderr, "%s: invalid interface '%s' specified\n",
+ 		progname, interface);
+     }
++#endif
+ 
+ #ifndef STREAMS
+     {
diff --git a/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch b/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch
new file mode 100644
index 0000000000..bba5884fa4
--- /dev/null
+++ b/package/network/services/ppp/patches/321-multilink_support_custom_iface_names.patch
@@ -0,0 +1,146 @@
+From: George Kashperko <george@znau.edu.ua>
+
+Make mlppp support more generic interface naming other than pppX
+Signed-off-by: George Kashperko <george@znau.edu.ua>
+---
+ pppd/multilink.c |   55 +++++++++++++++++++++++++++++++++------------
+ pppd/sys-linux.c |   12 +++++++++
+ 2 files changed, 53 insertions(+), 14 deletions(-)
+--- a/pppd/multilink.c
++++ b/pppd/multilink.c
+@@ -56,7 +56,8 @@ static void iterate_bundle_links __P((vo
+ 
+ static int get_default_epdisc __P((struct epdisc *));
+ static int parse_num __P((char *str, const char *key, int *valp));
+-static int owns_unit __P((TDB_DATA pid, int unit));
++static int parse_str __P((char *str, const char *key, char *buf, int buflen));
++static int owns_link __P((TDB_DATA pid, char *ifname));
+ 
+ #define set_ip_epdisc(ep, addr) do {	\
+ 	ep->length = 4;			\
+@@ -197,35 +198,38 @@ mp_join_bundle()
+ 	key.dptr = bundle_id;
+ 	key.dsize = p - bundle_id;
+ 	pid = tdb_fetch(pppdb, key);
++
+ 	if (pid.dptr != NULL) {
++		char tmp[IFNAMSIZ];
++
+ 		/* bundle ID exists, see if the pppd record exists */
+ 		rec = tdb_fetch(pppdb, pid);
++
+ 		if (rec.dptr != NULL && rec.dsize > 0) {
+ 			/* make sure the string is null-terminated */
+ 			rec.dptr[rec.dsize-1] = 0;
+-			/* parse the interface number */
+-			parse_num(rec.dptr, "IFNAME=ppp", &unit);
++
+ 			/* check the pid value */
+ 			if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
++			    || !parse_str(rec.dptr, "IFNAME=", tmp, sizeof(tmp))
++			    || !parse_num(rec.dptr, "IFUNIT=", &unit)
+ 			    || !process_exists(pppd_pid)
+-			    || !owns_unit(pid, unit))
++			    || !owns_link(pid, tmp))
+ 				unit = -1;
+ 			free(rec.dptr);
+ 		}
+ 		free(pid.dptr);
+-	}
+ 
+-	if (unit >= 0) {
+ 		/* attach to existing unit */
+-		if (bundle_attach(unit)) {
++		if (unit >= 0 && bundle_attach(unit)) {
+ 			set_ifunit(0);
+ 			script_setenv("BUNDLE", bundle_id + 7, 0);
+ 			make_bundle_links(1);
+ 			unlock_db();
+-			info("Link attached to %s", ifname);
++			info("Link attached to %s", tmp);
+ 			return 1;
++			/* attach failed because bundle doesn't exist */
+ 		}
+-		/* attach failed because bundle doesn't exist */
+ 	}
+ 
+ 	/* we have to make a new bundle */
+@@ -408,22 +412,45 @@ parse_num(str, key, valp)
+ 	return 0;
+ }
+ 
++static int
++parse_str(str, key, buf, buflen)
++     char *str;
++     const char *key;
++     char *buf;
++     int buflen;
++{
++	char *p, *endp;
++	int i;
++
++	p = strstr(str, key);
++	if (p) {
++		p += strlen(key);
++		while (--buflen && *p != 0 && *p != ';')
++			*(buf++) = *(p++);
++		*buf = 0;
++		return 1;
++	}
++	return 0;
++}
++
+ /*
+- * Check whether the pppd identified by `key' still owns ppp unit `unit'.
++ * Check whether the pppd identified by `key' still owns ppp link `ifname'.
+  */
+ static int
+-owns_unit(key, unit)
++owns_link(key, ifname)
+      TDB_DATA key;
+-     int unit;
++     char *ifname;
+ {
+-	char ifkey[32];
++	char ifkey[7 + IFNAMSIZ];
+ 	TDB_DATA kd, vd;
+ 	int ret = 0;
+ 
+-	slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit);
++	slprintf(ifkey, sizeof(ifkey), "IFNAME=%s", ifname);
++
+ 	kd.dptr = ifkey;
+ 	kd.dsize = strlen(ifkey);
+ 	vd = tdb_fetch(pppdb, kd);
++
+ 	if (vd.dptr != NULL) {
+ 		ret = vd.dsize == key.dsize
+ 			&& memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -698,6 +698,16 @@ void cfg_bundle(int mrru, int mtru, int
+ 	add_fd(ppp_dev_fd);
+ }
+ 
++static void
++setenv_ifunit(void)
++{
++#ifdef USE_TDB
++	char tmp[11];
++	slprintf(tmp, sizeof(tmp), "%d", ifunit);
++	script_setenv("IFUNIT", tmp, 0);
++#endif
++}
++
+ /*
+  * make_new_bundle - create a new PPP unit (i.e. a bundle)
+  * and connect our channel to it.  This should only get called
+@@ -716,6 +726,8 @@ void make_new_bundle(int mrru, int mtru,
+ 
+ 	/* set the mrru and flags */
+ 	cfg_bundle(mrru, mtru, rssn, tssn);
++
++	setenv_ifunit();
+ }
+ 
+ /*
diff --git a/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch b/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
new file mode 100644
index 0000000000..45fc4b9449
--- /dev/null
+++ b/package/network/services/ppp/patches/330-retain_foreign_default_routes.patch
@@ -0,0 +1,22 @@
+pppd: Retain foreign default routes on Linux
+
+On Linux, when pppd attempts to delete its default route it does not fill
+the rt_dev field of the struct rtentry used to match the system default route.
+As a consequence, pppd happily deletes any default route even if it belongs
+to another interface.
+
+This patch makes pppd fill out the rt_dev field so that only own default
+routes are ever matched.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -1756,6 +1756,7 @@ int cifdefaultroute (int unit, u_int32_t
+ 	SIN_ADDR(rt.rt_genmask) = 0L;
+     }
+ 
++    rt.rt_dev = ifname;
+     rt.rt_flags = RTF_UP;
+     if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ 	if (still_ppp()) {
diff --git a/package/network/services/ppp/patches/340-populate_default_gateway.patch b/package/network/services/ppp/patches/340-populate_default_gateway.patch
new file mode 100644
index 0000000000..5a694476d9
--- /dev/null
+++ b/package/network/services/ppp/patches/340-populate_default_gateway.patch
@@ -0,0 +1,34 @@
+pppd: Fill in default gateway on Linux
+
+On Linux, when pppd creates the default route, it does not set the peer
+address as gateway, leading to a default route without gateway address.
+
+This behaviour breaks various downstream programs which attempt to infer
+the default gateway IP address from the system default route entry.
+
+This patch addresses the issue by filling in the peer address as gateway
+when generating the default route entry.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -1710,6 +1710,9 @@ int sifdefaultroute (int unit, u_int32_t
+     memset (&rt, 0, sizeof (rt));
+     SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ 
++    SET_SA_FAMILY(rt.rt_gateway, AF_INET);
++    SIN_ADDR(rt.rt_gateway) = gateway;
++
+     rt.rt_dev = ifname;
+ 
+     if (kernel_version > KVERSION(2,1,0)) {
+@@ -1717,7 +1720,7 @@ int sifdefaultroute (int unit, u_int32_t
+ 	SIN_ADDR(rt.rt_genmask) = 0L;
+     }
+ 
+-    rt.rt_flags = RTF_UP;
++    rt.rt_flags = RTF_UP | RTF_GATEWAY;
+     if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ 	if (!ok_error(errno))
+ 	    error("default route ioctl(SIOCADDRT): %m");
diff --git a/package/network/services/ppp/patches/400-simplify_kernel_checks.patch b/package/network/services/ppp/patches/400-simplify_kernel_checks.patch
new file mode 100644
index 0000000000..cea9e16c2e
--- /dev/null
+++ b/package/network/services/ppp/patches/400-simplify_kernel_checks.patch
@@ -0,0 +1,154 @@
+pppd: Remove runtime kernel checks
+
+On embedded system distributions the required kernel features for pppd are
+more or less guaranteed to be present, so there is not much point in
+performing runtime checks, it just increases the binary size.
+
+This patch removes the runtime kernel feature checks.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -196,7 +196,7 @@ static int driver_is_old       = 0;
+ static int restore_term        = 0;	/* 1 => we've munged the terminal */
+ static struct termios inittermios;	/* Initial TTY termios */
+ 
+-int new_style_driver = 0;
++static const int new_style_driver = 1;
+ 
+ static char loop_name[20];
+ static unsigned char inbuf[512]; /* buffer for chars read from loopback */
+@@ -214,8 +214,8 @@ static int	looped;			/* 1 if using loop
+ static int	link_mtu;		/* mtu for the link (not bundle) */
+ 
+ static struct utsname utsname;	/* for the kernel version */
+-static int kernel_version;
+ #define KVERSION(j,n,p)	((j)*1000000 + (n)*1000 + (p))
++static const int kernel_version = KVERSION(2,6,37);
+ 
+ #define MAX_IFS		100
+ 
+@@ -1451,11 +1451,12 @@ int ccp_fatal_error (int unit)
+  *
+  * path_to_procfs - find the path to the proc file system mount point
+  */
+-static char proc_path[MAXPATHLEN];
+-static int proc_path_len;
++static char proc_path[MAXPATHLEN] = "/proc";
++static int proc_path_len = 5;
+ 
+ static char *path_to_procfs(const char *tail)
+ {
++#if 0
+     struct mntent *mntent;
+     FILE *fp;
+ 
+@@ -1477,6 +1478,7 @@ static char *path_to_procfs(const char *
+ 	    fclose (fp);
+ 	}
+     }
++#endif
+ 
+     strlcpy(proc_path + proc_path_len, tail,
+ 	    sizeof(proc_path) - proc_path_len);
+@@ -2129,15 +2131,19 @@ int ppp_available(void)
+     int    my_version, my_modification, my_patch;
+     int osmaj, osmin, ospatch;
+ 
++#if 0
+     /* get the kernel version now, since we are called before sys_init */
+     uname(&utsname);
+     osmaj = osmin = ospatch = 0;
+     sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
+     kernel_version = KVERSION(osmaj, osmin, ospatch);
++#endif
+ 
+     fd = open("/dev/ppp", O_RDWR);
+     if (fd >= 0) {
++#if 0
+ 	new_style_driver = 1;
++#endif
+ 
+ 	/* XXX should get from driver */
+ 	driver_version = 2;
+@@ -2197,6 +2203,7 @@ int ppp_available(void)
+ 
+     if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
+ 	ok = 0;
++	return ok;
+ 
+ /*
+  *  This is the PPP device. Validate the version of the driver at this
+@@ -2730,6 +2737,7 @@ get_pty(master_fdp, slave_fdp, slave_nam
+     }
+ #endif /* TIOCGPTN */
+ 
++#if 0
+     if (sfd < 0) {
+ 	/* the old way - scan through the pty name space */
+ 	for (i = 0; i < 64; ++i) {
+@@ -2748,6 +2756,7 @@ get_pty(master_fdp, slave_fdp, slave_nam
+ 	    }
+ 	}
+     }
++#endif
+ 
+     if (sfd < 0)
+ 	return 0;
+--- a/pppd/plugins/pppoatm/pppoatm.c
++++ b/pppd/plugins/pppoatm/pppoatm.c
+@@ -168,14 +168,6 @@ static void disconnect_pppoatm(void)
+ 
+ void plugin_init(void)
+ {
+-#if defined(__linux__)
+-	extern int new_style_driver;	/* From sys-linux.c */
+-	if (!ppp_available() && !new_style_driver)
+-		fatal("Kernel doesn't support ppp_generic - "
+-		    "needed for PPPoATM");
+-#else
+-	fatal("No PPPoATM support on this OS");
+-#endif
+ 	info("PPPoATM plugin_init");
+ 	add_options(pppoa_options);
+ }
+--- a/pppd/plugins/rp-pppoe/plugin.c
++++ b/pppd/plugins/rp-pppoe/plugin.c
+@@ -59,9 +59,6 @@ static char const RCSID[] =
+ 
+ char pppd_version[] = VERSION;
+ 
+-/* From sys-linux.c in pppd -- MUST FIX THIS! */
+-extern int new_style_driver;
+-
+ char *pppd_pppoe_service = NULL;
+ static char *acName = NULL;
+ static char *existingSession = NULL;
+@@ -371,10 +368,6 @@ PPPoEDevnameHook(char *cmd, char **argv,
+ void
+ plugin_init(void)
+ {
+-    if (!ppp_available() && !new_style_driver) {
+-	fatal("Linux kernel does not support PPPoE -- are you running 2.4.x?");
+-    }
+-
+     add_options(Options);
+ 
+     info("RP-PPPoE plugin version %s compiled against pppd %s",
+--- a/pppd/plugins/pppol2tp/pppol2tp.c
++++ b/pppd/plugins/pppol2tp/pppol2tp.c
+@@ -486,12 +486,7 @@ static void pppol2tp_cleanup(void)
+ 
+ void plugin_init(void)
+ {
+-#if defined(__linux__)
+-	extern int new_style_driver;	/* From sys-linux.c */
+-	if (!ppp_available() && !new_style_driver)
+-		fatal("Kernel doesn't support ppp_generic - "
+-		    "needed for PPPoL2TP");
+-#else
++#if !defined(__linux__)
+ 	fatal("No PPPoL2TP support on this OS");
+ #endif
+ 	add_options(pppol2tp_options);
diff --git a/package/network/services/ppp/patches/401-no_record_file.patch b/package/network/services/ppp/patches/401-no_record_file.patch
new file mode 100644
index 0000000000..f5079fac4b
--- /dev/null
+++ b/package/network/services/ppp/patches/401-no_record_file.patch
@@ -0,0 +1,39 @@
+pppd: Remove the "record" option
+
+On many embedded systems there is not enough space to record PPP session
+information to the permanent storage, therfore remove this option.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/pppd.h
++++ b/pppd/pppd.h
+@@ -317,7 +317,6 @@ extern int	holdoff;	/* Dead time before
+ extern bool	holdoff_specified; /* true if user gave a holdoff value */
+ extern bool	notty;		/* Stdin/out is not a tty */
+ extern char	*pty_socket;	/* Socket to connect to pty */
+-extern char	*record_file;	/* File to record chars sent/received */
+ extern bool	sync_serial;	/* Device is synchronous serial device */
+ extern int	maxfail;	/* Max # of unsuccessful connection attempts */
+ extern char	linkname[MAXPATHLEN]; /* logical name for link */
+--- a/pppd/tty.c
++++ b/pppd/tty.c
+@@ -146,7 +146,7 @@ char	*disconnect_script = NULL; /* Scrip
+ char	*welcomer = NULL;	/* Script to run after phys link estab. */
+ char	*ptycommand = NULL;	/* Command to run on other side of pty */
+ bool	notty = 0;		/* Stdin/out is not a tty */
+-char	*record_file = NULL;	/* File to record chars sent/received */
++static  char	*const record_file = NULL;	/* File to record chars sent/received */
+ int	max_data_rate;		/* max bytes/sec through charshunt */
+ bool	sync_serial = 0;	/* Device is synchronous serial device */
+ char	*pty_socket = NULL;	/* Socket to connect to pty */
+@@ -202,8 +202,10 @@ option_t tty_options[] = {
+       "Send and receive over socket, arg is host:port",
+       OPT_PRIO | OPT_DEVNAM },
+ 
++#if 0
+     { "record", o_string, &record_file,
+       "Record characters sent/received to file", OPT_PRIO },
++#endif
+ 
+     { "crtscts", o_int, &crtscts,
+       "Set hardware (RTS/CTS) flow control",
diff --git a/package/network/services/ppp/patches/403-no_wtmp.patch b/package/network/services/ppp/patches/403-no_wtmp.patch
new file mode 100644
index 0000000000..98d6133c43
--- /dev/null
+++ b/package/network/services/ppp/patches/403-no_wtmp.patch
@@ -0,0 +1,25 @@
+pppd: Disable wtmp support
+
+Many uClibc based environments lack wtmp and utmp support, therfore remove
+the code updating the wtmp information.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/sys-linux.c
++++ b/pppd/sys-linux.c
+@@ -2267,6 +2267,7 @@ int ppp_available(void)
+ 
+ void logwtmp (const char *line, const char *name, const char *host)
+ {
++#if 0
+     struct utmp ut, *utp;
+     pid_t  mypid = getpid();
+ #if __GLIBC__ < 2
+@@ -2332,6 +2333,7 @@ void logwtmp (const char *line, const ch
+ 	close (wtmp);
+     }
+ #endif
++#endif
+ }
+ #endif /* HAVE_LOGWTMP */
+ 
diff --git a/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch b/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch
new file mode 100644
index 0000000000..3b35fe0030
--- /dev/null
+++ b/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch
@@ -0,0 +1,151 @@
+pppd: Remove historical protocol names
+
+Remove a number of historical protocol entries from pppd's builtin list, this
+reduced the binary size without loss of features.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/main.c
++++ b/pppd/main.c
+@@ -882,14 +882,17 @@ struct protocol_list {
+     const char	*name;
+ } protocol_list[] = {
+     { 0x21,	"IP" },
++#if 0
+     { 0x23,	"OSI Network Layer" },
+     { 0x25,	"Xerox NS IDP" },
+     { 0x27,	"DECnet Phase IV" },
+     { 0x29,	"Appletalk" },
+     { 0x2b,	"Novell IPX" },
++#endif
+     { 0x2d,	"VJ compressed TCP/IP" },
+     { 0x2f,	"VJ uncompressed TCP/IP" },
+     { 0x31,	"Bridging PDU" },
++#if 0
+     { 0x33,	"Stream Protocol ST-II" },
+     { 0x35,	"Banyan Vines" },
+     { 0x39,	"AppleTalk EDDP" },
+@@ -903,8 +906,11 @@ struct protocol_list {
+     { 0x49,	"Serial Data Transport Protocol (PPP-SDTP)" },
+     { 0x4b,	"SNA over 802.2" },
+     { 0x4d,	"SNA" },
++#endif
+     { 0x4f,	"IP6 Header Compression" },
++#if 0
+     { 0x51,	"KNX Bridging Data" },
++#endif
+     { 0x53,	"Encryption" },
+     { 0x55,	"Individual Link Encryption" },
+     { 0x57,	"IPv6" },
+@@ -915,12 +921,15 @@ struct protocol_list {
+     { 0x65,	"RTP IPHC Compressed non-TCP" },
+     { 0x67,	"RTP IPHC Compressed UDP 8" },
+     { 0x69,	"RTP IPHC Compressed RTP 8" },
++#if 0
+     { 0x6f,	"Stampede Bridging" },
+     { 0x73,	"MP+" },
+     { 0xc1,	"NTCITS IPI" },
++#endif
+     { 0xfb,	"single-link compression" },
+     { 0xfd,	"Compressed Datagram" },
+     { 0x0201,	"802.1d Hello Packets" },
++#if 0
+     { 0x0203,	"IBM Source Routing BPDU" },
+     { 0x0205,	"DEC LANBridge100 Spanning Tree" },
+     { 0x0207,	"Cisco Discovery Protocol" },
+@@ -932,15 +941,19 @@ struct protocol_list {
+     { 0x0231,	"Luxcom" },
+     { 0x0233,	"Sigma Network Systems" },
+     { 0x0235,	"Apple Client Server Protocol" },
++#endif
+     { 0x0281,	"MPLS Unicast" },
+     { 0x0283,	"MPLS Multicast" },
++#if 0
+     { 0x0285,	"IEEE p1284.4 standard - data packets" },
+     { 0x0287,	"ETSI TETRA Network Protocol Type 1" },
++#endif
+     { 0x0289,	"Multichannel Flow Treatment Protocol" },
+     { 0x2063,	"RTP IPHC Compressed TCP No Delta" },
+     { 0x2065,	"RTP IPHC Context State" },
+     { 0x2067,	"RTP IPHC Compressed UDP 16" },
+     { 0x2069,	"RTP IPHC Compressed RTP 16" },
++#if 0
+     { 0x4001,	"Cray Communications Control Protocol" },
+     { 0x4003,	"CDPD Mobile Network Registration Protocol" },
+     { 0x4005,	"Expand accelerator protocol" },
+@@ -951,8 +964,10 @@ struct protocol_list {
+     { 0x4023,	"RefTek Protocol" },
+     { 0x4025,	"Fibre Channel" },
+     { 0x4027,	"EMIT Protocols" },
++#endif
+     { 0x405b,	"Vendor-Specific Protocol (VSP)" },
+     { 0x8021,	"Internet Protocol Control Protocol" },
++#if 0
+     { 0x8023,	"OSI Network Layer Control Protocol" },
+     { 0x8025,	"Xerox NS IDP Control Protocol" },
+     { 0x8027,	"DECnet Phase IV Control Protocol" },
+@@ -961,7 +976,9 @@ struct protocol_list {
+     { 0x8031,	"Bridging NCP" },
+     { 0x8033,	"Stream Protocol Control Protocol" },
+     { 0x8035,	"Banyan Vines Control Protocol" },
++#endif
+     { 0x803d,	"Multi-Link Control Protocol" },
++#if 0
+     { 0x803f,	"NETBIOS Framing Control Protocol" },
+     { 0x8041,	"Cisco Systems Control Protocol" },
+     { 0x8043,	"Ascom Timeplex" },
+@@ -970,18 +987,24 @@ struct protocol_list {
+     { 0x8049,	"Serial Data Control Protocol (PPP-SDCP)" },
+     { 0x804b,	"SNA over 802.2 Control Protocol" },
+     { 0x804d,	"SNA Control Protocol" },
++#endif
+     { 0x804f,	"IP6 Header Compression Control Protocol" },
++#if 0
+     { 0x8051,	"KNX Bridging Control Protocol" },
++#endif
+     { 0x8053,	"Encryption Control Protocol" },
+     { 0x8055,	"Individual Link Encryption Control Protocol" },
+     { 0x8057,	"IPv6 Control Protocol" },
+     { 0x8059,	"PPP Muxing Control Protocol" },
+     { 0x805b,	"Vendor-Specific Network Control Protocol (VSNCP)" },
++#if 0
+     { 0x806f,	"Stampede Bridging Control Protocol" },
+     { 0x8073,	"MP+ Control Protocol" },
+     { 0x80c1,	"NTCITS IPI Control Protocol" },
++#endif
+     { 0x80fb,	"Single Link Compression Control Protocol" },
+     { 0x80fd,	"Compression Control Protocol" },
++#if 0
+     { 0x8207,	"Cisco Discovery Protocol Control" },
+     { 0x8209,	"Netcs Twin Routing" },
+     { 0x820b,	"STP - Control Protocol" },
+@@ -990,24 +1013,29 @@ struct protocol_list {
+     { 0x8281,	"MPLSCP" },
+     { 0x8285,	"IEEE p1284.4 standard - Protocol Control" },
+     { 0x8287,	"ETSI TETRA TNP1 Control Protocol" },
++#endif
+     { 0x8289,	"Multichannel Flow Treatment Protocol" },
+     { 0xc021,	"Link Control Protocol" },
+     { 0xc023,	"Password Authentication Protocol" },
+     { 0xc025,	"Link Quality Report" },
++#if 0
+     { 0xc027,	"Shiva Password Authentication Protocol" },
+     { 0xc029,	"CallBack Control Protocol (CBCP)" },
+     { 0xc02b,	"BACP Bandwidth Allocation Control Protocol" },
+     { 0xc02d,	"BAP" },
++#endif
+     { 0xc05b,	"Vendor-Specific Authentication Protocol (VSAP)" },
+     { 0xc081,	"Container Control Protocol" },
+     { 0xc223,	"Challenge Handshake Authentication Protocol" },
+     { 0xc225,	"RSA Authentication Protocol" },
+     { 0xc227,	"Extensible Authentication Protocol" },
++#if 0
+     { 0xc229,	"Mitsubishi Security Info Exch Ptcl (SIEP)" },
+     { 0xc26f,	"Stampede Bridging Authorization Protocol" },
+     { 0xc281,	"Proprietary Authentication Protocol" },
+     { 0xc283,	"Proprietary Authentication Protocol" },
+     { 0xc481,	"Proprietary Node ID Authentication Protocol" },
++#endif
+     { 0,	NULL },
+ };
+ 
diff --git a/package/network/services/ppp/patches/405-no_multilink_option.patch b/package/network/services/ppp/patches/405-no_multilink_option.patch
new file mode 100644
index 0000000000..b17747a5ec
--- /dev/null
+++ b/package/network/services/ppp/patches/405-no_multilink_option.patch
@@ -0,0 +1,28 @@
+pppd: Support "nomp" option even if multilink support is off
+
+This patch moves the "nomp" option entry outside of the defines protecting
+the multilink specific code. The motivation is to allow "nomp" even if pppd
+does not support multilink, so that controlling programs can unconditionally
+pass it to pppd regardless of the compile time features.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -336,13 +336,14 @@ option_t general_options[] = {
+       "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
+     { "nomultilink", o_bool, &multilink,
+       "Disable multilink operation", OPT_PRIOSUB | 0 },
+-    { "nomp", o_bool, &multilink,
+-      "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
+ 
+     { "bundle", o_string, &bundle_name,
+       "Bundle name for multilink", OPT_PRIO },
+ #endif /* HAVE_MULTILINK */
+ 
++    { "nomp", o_bool, &multilink,
++      "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
++
+ #ifdef PLUGIN
+     { "plugin", o_special, (void *)loadplugin,
+       "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
diff --git a/package/network/services/ppp/patches/500-add-pptp-plugin.patch b/package/network/services/ppp/patches/500-add-pptp-plugin.patch
new file mode 100644
index 0000000000..d984e1b162
--- /dev/null
+++ b/package/network/services/ppp/patches/500-add-pptp-plugin.patch
@@ -0,0 +1,3065 @@
+--- a/configure
++++ b/configure
+@@ -195,7 +195,7 @@ if [ -d "$ksrc" ]; then
+     mkmkf $ksrc/Makedefs$compiletype Makedefs.com
+     for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/rp-pppoe \
+ 	       pppd/plugins/radius pppd/plugins/pppoatm \
+-	       pppd/plugins/pppol2tp; do
++	       pppd/plugins/pppol2tp pppd/plugins/pptp ; do
+ 	mkmkf $dir/Makefile.$makext $dir/Makefile
+     done
+     if [ -f $ksrc/Makefile.$makext$archvariant ]; then
+--- a/pppd/plugins/Makefile.linux
++++ b/pppd/plugins/Makefile.linux
+@@ -9,7 +9,7 @@ BINDIR = $(DESTDIR)/sbin
+ MANDIR = $(DESTDIR)/share/man/man8
+ LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
+ 
+-SUBDIRS := rp-pppoe pppoatm pppol2tp
++SUBDIRS := rp-pppoe pppoatm pppol2tp pptp
+ # Uncomment the next line to include the radius authentication plugin
+ SUBDIRS += radius
+ PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so
+--- /dev/null
++++ b/pppd/plugins/pptp/Makefile.linux
+@@ -0,0 +1,31 @@
++#
++# This program may be distributed according to the terms of the GNU
++# General Public License, version 2 or (at your option) any later version.
++#
++# $Id: Makefile.linux,v 1.9 2012/05/04 21:48:00 dgolle Exp $
++#***********************************************************************
++
++DESTDIR = $(INSTROOT)@DESTDIR@
++LIBDIR = $(DESTDIR)/lib/pppd/$(PPPDVERSION)
++
++PPPDVERSION = $(shell awk -F '"' '/VERSION/ { print $$2; }' ../../patchlevel.h)
++
++INSTALL	= install
++
++COPTS=-O2 -g
++CFLAGS  = $(COPTS) -I. -I../.. -I../../../include -fPIC -DPPPD_VERSION=\"$(PPPDVERSION)\"
++all: pptp.so
++
++%.o: %.c
++	$(CC) $(CFLAGS) -c -o $@ $<
++
++pptp.so: dirutil.o orckit_quirks.o pptp.o pptp_callmgr.o pptp_ctrl.o pptp_quirks.o util.o vector.o
++	$(CC) -o pptp.so -shared dirutil.o orckit_quirks.o pptp.o pptp_callmgr.o pptp_ctrl.o pptp_quirks.o util.o vector.o
++
++install: all
++	$(INSTALL) -d -m 755 $(LIBDIR)
++	$(INSTALL) -c -m 4550 pptp.so $(LIBDIR)
++
++clean:
++	rm -f *.o *.so
++
+--- /dev/null
++++ b/pppd/plugins/pptp/dirutil.c
+@@ -0,0 +1,68 @@
++/* dirutil.c ... directory utilities.
++ *               C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: dirutil.c,v 1.2 2003/06/17 17:25:47 reink Exp $
++ */
++
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include "dirutil.h"
++
++/* Returned malloc'ed string representing basename */
++char *basenamex(char *pathname)
++{
++    char *dup = strdup(pathname);
++    char *ptr = strrchr(stripslash(dup), '/');
++    if (ptr == NULL) return dup;
++    ptr = strdup(ptr+1);
++    free(dup);
++    return ptr;
++}
++
++/* Return malloc'ed string representing directory name (no trailing slash) */
++char *dirnamex(char *pathname)
++{
++    char *dup = strdup(pathname);
++    char *ptr = strrchr(stripslash(dup), '/');
++    if (ptr == NULL) { free(dup); return strdup("."); }
++    if (ptr == dup && dup[0] == '/') ptr++;
++    *ptr = '\0';
++    return dup;
++}
++
++/* In-place modify a string to remove trailing slashes.  Returns arg.
++ * stripslash("/") returns "/";
++ */
++char *stripslash(char *pathname) {
++    int len = strlen(pathname);
++    while (len > 1 && pathname[len - 1] == '/')
++        pathname[--len] = '\0';
++    return pathname;
++}
++
++/* ensure dirname exists, creating it if necessary. */
++int make_valid_path(char *dir, mode_t mode)
++{
++    struct stat st;
++    char *tmp = NULL, *path = stripslash(strdup(dir));
++    int retval;
++    if (stat(path, &st) == 0) { /* file exists */
++        if (S_ISDIR(st.st_mode)) { retval = 1; goto end; }
++        else { retval = 0; goto end; } /* not a directory.  Oops. */
++    }
++    /* Directory doesn't exist.  Let's make it. */
++    /*   Make parent first. */
++    if (!make_valid_path(tmp = dirnamex(path), mode)) { retval = 0; goto end; }
++    /*   Now make this 'un. */
++    if (mkdir(path, mode) < 0) { retval = 0; goto end; }
++    /* Success. */
++    retval = 1;
++
++end:
++    if (tmp != NULL) free(tmp);
++    if (path != NULL) free(path);
++    return retval;
++}
+--- /dev/null
++++ b/pppd/plugins/pptp/dirutil.h
+@@ -0,0 +1,14 @@
++/* dirutil.h ... directory utilities.
++ *               C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: dirutil.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
++ */
++
++/* Returned malloc'ed string representing basename */
++char *basenamex(char *pathname);
++/* Return malloc'ed string representing directory name (no trailing slash) */
++char *dirnamex(char *pathname);
++/* In-place modify a string to remove trailing slashes.  Returns arg. */
++char *stripslash(char *pathname);
++/* ensure dirname exists, creating it if necessary. */
++int make_valid_path(char *dirname, mode_t mode);
+--- /dev/null
++++ b/pppd/plugins/pptp/orckit_quirks.c
+@@ -0,0 +1,86 @@
++/* orckit_quirks.c ...... fix quirks in orckit adsl modems
++ *                        mulix <mulix@actcom.co.il>
++ *
++ * $Id: orckit_quirks.c,v 1.3 2002/03/01 01:23:36 quozl Exp $
++ */
++
++#include <string.h>
++#include <sys/types.h>
++#include <netinet/in.h>
++#include "pptp_msg.h"
++#include "pptp_options.h"
++#include "pptp_ctrl.h"
++#include "util.h"
++
++
++
++/* return 0 on success, non zero otherwise */
++int
++orckit_atur3_build_hook(struct pptp_out_call_rqst* packet)
++{
++    unsigned int name_length = 10;
++
++    struct pptp_out_call_rqst fixed_packet = {
++	PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
++	0, /* hton16(call->callid) */
++	0, /* hton16(call->sernum) */
++	hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
++	hton32(PPTP_BEARER_DIGITAL), hton32(PPTP_FRAME_ANY),
++	hton16(PPTP_WINDOW), 0, hton16(name_length), 0,
++	{'R','E','L','A','Y','_','P','P','P','1',0}, {0}
++    };
++
++    if (!packet)
++	return -1;
++
++    memcpy(packet, &fixed_packet, sizeof(*packet));
++
++    return 0;
++}
++
++/* return 0 on success, non zero otherwise */
++int
++orckit_atur3_set_link_hook(struct pptp_set_link_info* packet,
++			   int peer_call_id)
++{
++    struct pptp_set_link_info fixed_packet = {
++	PPTP_HEADER_CTRL(PPTP_SET_LINK_INFO),
++	hton16(peer_call_id),
++	0,
++	0xffffffff,
++	0xffffffff};
++
++    if (!packet)
++	return -1;
++
++    memcpy(packet, &fixed_packet, sizeof(*packet));
++    return 0;
++}
++
++/* return 0 on success, non 0 otherwise */
++int
++orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet)
++{
++    struct pptp_start_ctrl_conn fixed_packet = {
++	{0}, /* we'll set the header later */
++	hton16(PPTP_VERSION), 0, 0,
++	hton32(PPTP_FRAME_ASYNC), hton32(PPTP_BEARER_ANALOG),
++	hton16(0) /* max channels */,
++	hton16(0x6021),
++	{'R','E','L','A','Y','_','P','P','P','1',0}, /* hostname */
++	{'M','S',' ','W','i','n',' ','N','T',0} /* vendor */
++    };
++
++    if (!packet)
++	return -1;
++
++    /* grab the header from the original packet, since we dont
++       know if this is a request or a reply */
++    memcpy(&fixed_packet.header, &packet->header, sizeof(struct pptp_header));
++
++    /* and now overwrite the full packet, effectively preserving the header */
++    memcpy(packet, &fixed_packet, sizeof(*packet));
++    return 0;
++}
++
++
+--- /dev/null
++++ b/pppd/plugins/pptp/orckit_quirks.h
+@@ -0,0 +1,27 @@
++/* orckit_quirks.h ...... fix quirks in orckit adsl modems
++ *                        mulix <mulix@actcom.co.il>
++ *
++ * $Id: orckit_quirks.h,v 1.2 2001/11/23 03:42:51 quozl Exp $
++ */
++
++#ifndef INC_ORCKIT_QUIRKS_H_
++#define INC_ORCKIT_QUIRKS_H_
++
++#include "pptp_options.h"
++#include "pptp_ctrl.h"
++#include "pptp_msg.h"
++
++/* return 0 on success, non zero otherwise */
++int
++orckit_atur3_build_hook(struct pptp_out_call_rqst* packt);
++
++/* return 0 on success, non zero otherwise */
++int
++orckit_atur3_set_link_hook(struct pptp_set_link_info* packet,
++			   int peer_call_id);
++
++/* return 0 on success, non zero otherwise */
++int
++orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet);
++
++#endif /* INC_ORCKIT_QUIRKS_H_ */
+--- /dev/null
++++ b/pppd/plugins/pptp/pppd-pptp.8
+@@ -0,0 +1,68 @@
++.\" manual page [] for PPTP plugin for pppd 2.4
++.\" $Id: pppd-pptp.8,v 1.0 2007/10/17 13:27:17 kad Exp $
++.\" SH section heading
++.\" SS subsection heading
++.\" LP paragraph
++.\" IP indented paragraph
++.\" TP hanging label
++.TH PPPD-PPTP 8
++.SH NAME
++pptp.so \- PPTP VPN plugin for
++.BR pppd (8)
++.SH SYNOPSIS
++.B pppd
++[
++.I options
++]
++plugin pptp.so
++.SH DESCRIPTION
++.LP
++The PPTP plugin for pppd performs interaction with pptp kernel module
++and has built-in call manager (client part of PPTP).
++It pasees necessary paremeters from \fIoptions\fR into kernel module 
++to configure ppp-pptp channel. If it runs in client mode, then additionally 
++call manager starts up. PPTPD daemon automaticaly invokes this plugin
++in server mode and passes necessary options, so additional configuration
++is not needed.
++
++.SH OPTIONS for client mode
++The PPTP plugin introduces one additional pppd option:
++.TP
++.BI "pptp_server " server " (required)"
++Specifies ip address or hostname of pptp server.
++.TP
++.BI "pptp_window " packets " (optional)"
++The amount of sliding window size. 
++Set to 0 to turn off sliding window.
++    to 3-10 for low speed connections.
++    to >10 for hi speed connections.
++Default is 50
++.TP
++.BI "pptp_phone " phone " (optional)"
++The phone string that sended to pptp server.
++.SH USAGE
++Sample configuration file:
++.nf
++plugin "pptp.so"
++pptp_server 192.168.0.1
++pptp_window 100
++name myname
++remotename pptp
++noauth
++refuse-eap
++refuse-chap
++refuse-mschap
++nobsdcomp
++nodeflate
++novj
++novjccomp
++require-mppe-128
++lcp-echo-interval 20
++lcp-echo-failure  3
++.fi
++
++.SH SEE ALSO
++.BR pppd (8) "  " pptpd (8) "  " pptpd.conf (5)
++
++.SH AUTHOR
++xeb xeb@mail.ru
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp.c
+@@ -0,0 +1,323 @@
++/***************************************************************************
++ *   Copyright (C) 2006 by Kozlov D. <xeb@mail.ru>                         *
++ *   some cleanup done (C) 2012 by Daniel Golle <dgolle@allnet.de>         *
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ *   This program is distributed in the hope that it will be useful,       *
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
++ *   GNU General Public License for more details.                          *
++ *                                                                         *
++ *   You should have received a copy of the GNU General Public License     *
++ *   along with this program; if not, write to the                         *
++ *   Free Software Foundation, Inc.,                                       *
++ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
++ ***************************************************************************/
++
++#define PPTP_VERSION "1.00"
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <sys/un.h>
++#include <netdb.h>
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <syslog.h>
++#include <unistd.h>
++#include <signal.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <sys/wait.h>
++#include <sys/ioctl.h>
++
++#include "pppd.h"
++#include "fsm.h"
++#include "lcp.h"
++#include "ipcp.h"
++#include "ccp.h"
++#include "pathnames.h"
++
++#include "pptp_callmgr.h"
++#include <net/if.h>
++#include <net/ethernet.h>
++#include <linux/if_pppox.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++
++
++
++extern char** environ;
++
++char pppd_version[] = PPPD_VERSION;
++extern int new_style_driver;
++
++
++char *pptp_server = NULL;
++char *pptp_client = NULL;
++char *pptp_phone = NULL;
++int pptp_window=50;
++int pptp_sock=-1;
++struct in_addr localbind = { INADDR_NONE };
++
++static int callmgr_sock;
++static int pptp_fd;
++int call_ID;
++
++static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window);
++static void launch_callmgr(int call_is,struct in_addr inetaddr, char *phonenr,int window);
++static int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *peer_call_id);
++
++static option_t Options[] =
++{
++    { "pptp_server", o_string, &pptp_server,
++      "PPTP Server" },
++    { "pptp_client", o_string, &pptp_client,
++      "PPTP Client" },
++    { "pptp_sock",o_int, &pptp_sock,
++      "PPTP socket" },
++    { "pptp_phone", o_string, &pptp_phone,
++      "PPTP Phone number" },
++    { "pptp_window",o_int, &pptp_window,
++      "PPTP window" },
++    { NULL }
++};
++
++static int pptp_connect(void);
++static void pptp_disconnect(void);
++
++struct channel pptp_channel = {
++    options: Options,
++    check_options: NULL,
++    connect: &pptp_connect,
++    disconnect: &pptp_disconnect,
++    establish_ppp: &generic_establish_ppp,
++    disestablish_ppp: &generic_disestablish_ppp,
++    close: NULL,
++    cleanup: NULL
++};
++
++static int pptp_start_server(void)
++{
++	pptp_fd=pptp_sock;
++	sprintf(ppp_devnam,"pptp (%s)",pptp_client);
++
++	return pptp_fd;
++}
++static int pptp_start_client(void)
++{
++	socklen_t len;
++	struct sockaddr_pppox src_addr,dst_addr;
++	struct hostent *hostinfo;
++
++	hostinfo=gethostbyname(pptp_server);
++  if (!hostinfo)
++	{
++		error("PPTP: Unknown host %s\n", pptp_server);
++		return -1;
++	}
++	dst_addr.sa_addr.pptp.sin_addr=*(struct in_addr*)hostinfo->h_addr;
++	{
++		int sock;
++		struct sockaddr_in addr;
++		len=sizeof(addr);
++		addr.sin_addr=dst_addr.sa_addr.pptp.sin_addr;
++		addr.sin_family=AF_INET;
++		addr.sin_port=htons(1700);
++		sock=socket(AF_INET,SOCK_DGRAM,0);
++		if (connect(sock,(struct sockaddr*)&addr,sizeof(addr)))
++		{
++			close(sock);
++			error("PPTP: connect failed (%s)\n",strerror(errno));
++			return -1;
++		}
++		getsockname(sock,(struct sockaddr*)&addr,&len);
++		src_addr.sa_addr.pptp.sin_addr=addr.sin_addr;
++		close(sock);
++	}
++
++	src_addr.sa_family=AF_PPPOX;
++	src_addr.sa_protocol=PX_PROTO_PPTP;
++	src_addr.sa_addr.pptp.call_id=0;
++
++	dst_addr.sa_family=AF_PPPOX;
++	dst_addr.sa_protocol=PX_PROTO_PPTP;
++	dst_addr.sa_addr.pptp.call_id=0;
++
++	pptp_fd=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP);
++	if (pptp_fd<0)
++	{
++		error("PPTP: failed to create PPTP socket (%s)\n",strerror(errno));
++		return -1;
++	}
++	if (bind(pptp_fd,(struct sockaddr*)&src_addr,sizeof(src_addr)))
++	{
++		close(pptp_fd);
++		error("PPTP: failed to bind PPTP socket (%s)\n",strerror(errno));
++		return -1;
++	}
++	len=sizeof(src_addr);
++	getsockname(pptp_fd,(struct sockaddr*)&src_addr,&len);
++	call_ID=src_addr.sa_addr.pptp.call_id;
++
++  do {
++        /*
++         * Open connection to call manager (Launch call manager if necessary.)
++         */
++        callmgr_sock = open_callmgr(src_addr.sa_addr.pptp.call_id,dst_addr.sa_addr.pptp.sin_addr, pptp_phone, pptp_window);
++	if (callmgr_sock<0)
++	{
++		close(pptp_fd);
++		return -1;
++        }
++        /* Exchange PIDs, get call ID */
++    } while (get_call_id(callmgr_sock, getpid(), getpid(), &dst_addr.sa_addr.pptp.call_id) < 0);
++
++	if (connect(pptp_fd,(struct sockaddr*)&dst_addr,sizeof(dst_addr)))
++	{
++		close(callmgr_sock);
++		close(pptp_fd);
++		error("PPTP: failed to connect PPTP socket (%s)\n",strerror(errno));
++		return -1;
++	}
++
++	sprintf(ppp_devnam,"pptp (%s)",pptp_server);
++
++	return pptp_fd;
++}
++static int pptp_connect(void)
++{
++	if ((!pptp_server && !pptp_client) || (pptp_server && pptp_client))
++	{
++		fatal("PPTP: unknown mode (you must specify pptp_server or pptp_client option)");
++		return -1;
++	}
++
++	if (pptp_server) return pptp_start_client();
++	return pptp_start_server();
++}
++
++static void pptp_disconnect(void)
++{
++	if (pptp_server) close(callmgr_sock);
++	close(pptp_fd);
++}
++
++static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window)
++{
++    /* Try to open unix domain socket to call manager. */
++    struct sockaddr_un where;
++    const int NUM_TRIES = 3;
++    int i, fd;
++    pid_t pid;
++    int status;
++    /* Open socket */
++    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
++    {
++        fatal("Could not create unix domain socket: %s", strerror(errno));
++    }
++    /* Make address */
++    callmgr_name_unixsock(&where, inetaddr, localbind);
++    for (i = 0; i < NUM_TRIES; i++)
++    {
++        if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0)
++        {
++            /* couldn't connect.  We'll have to launch this guy. */
++
++            unlink (where.sun_path);
++
++            /* fork and launch call manager process */
++            switch (pid = fork())
++            {
++                case -1: /* failure */
++                    fatal("fork() to launch call manager failed.");
++                case 0: /* child */
++                {
++                    /* close the pty and gre in the call manager */
++                    close(fd);
++                    close(pptp_fd);
++                    launch_callmgr(call_id,inetaddr,phonenr,window);
++                }
++                default: /* parent */
++                    waitpid(pid, &status, 0);
++                    if (status!= 0)
++		    {
++			close(fd);
++			error("Call manager exited with error %d", status);
++			return -1;
++		    }
++                    break;
++            }
++            sleep(1);
++        }
++        else return fd;
++    }
++    close(fd);
++    error("Could not launch call manager after %d tries.", i);
++    return -1;   /* make gcc happy */
++}
++
++/*** call the call manager main ***********************************************/
++static void launch_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window)
++{
++    dbglog("pptp: call manager for %s\n", inet_ntoa(inetaddr));
++    dbglog("window size:\t%d\n",window);
++    if (phonenr) dbglog("phone number:\t'%s'\n",phonenr);
++    dbglog("call id:\t%d\n",call_id);
++    exit(callmgr_main(inetaddr, phonenr, window, call_id));
++}
++
++/*** exchange data with the call manager  *************************************/
++/* XXX need better error checking XXX */
++static int get_call_id(int sock, pid_t gre, pid_t pppd,
++		u_int16_t *peer_call_id)
++{
++    u_int16_t m_call_id, m_peer_call_id;
++    /* write pid's to socket */
++    /* don't bother with network byte order, because pid's are meaningless
++     * outside the local host.
++     */
++    int rc;
++    rc = write(sock, &gre, sizeof(gre));
++    if (rc != sizeof(gre))
++        return -1;
++    rc = write(sock, &pppd, sizeof(pppd));
++    if (rc != sizeof(pppd))
++        return -1;
++    rc = read(sock,  &m_call_id, sizeof(m_call_id));
++    if (rc != sizeof(m_call_id))
++        return -1;
++    rc = read(sock,  &m_peer_call_id, sizeof(m_peer_call_id));
++    if (rc != sizeof(m_peer_call_id))
++        return -1;
++    /*
++     * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX
++     * (Rhialto: I am assuming for now that timeouts are not relevant
++     * here, because the read and write calls would return -1 (fail) when
++     * the peer goes away during the process. We know it is (or was)
++     * running because the connect() call succeeded.)
++     * (James: on the other hand, if the route to the peer goes away, we
++     * wouldn't get told by read() or write() for quite some time.)
++     */
++    *peer_call_id = m_peer_call_id;
++    return 0;
++}
++
++void plugin_init(void)
++{
++    add_options(Options);
++
++    info("PPTP plugin version %s", PPTP_VERSION);
++
++    the_channel = &pptp_channel;
++    modem = 0;
++}
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_callmgr.c
+@@ -0,0 +1,381 @@
++/* pptp_callmgr.c ... Call manager for PPTP connections.
++ *                    Handles TCP port 1723 protocol.
++ *                    C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: pptp_callmgr.c,v 1.20 2005/03/31 07:42:39 quozl Exp $
++ */
++#include <signal.h>
++#include <sys/time.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <sys/un.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++#include <setjmp.h>
++#include <stdio.h>
++#include <errno.h>
++#include "pptp_callmgr.h"
++#include "pptp_ctrl.h"
++#include "pptp_msg.h"
++#include "dirutil.h"
++#include "vector.h"
++#include "util.h"
++#include "pppd.h"
++
++extern struct in_addr localbind; /* from pptp.c */
++extern int call_ID;
++
++int open_inetsock(struct in_addr inetaddr);
++int open_unixsock(struct in_addr inetaddr);
++void close_inetsock(int fd, struct in_addr inetaddr);
++void close_unixsock(int fd, struct in_addr inetaddr);
++
++sigjmp_buf callmgr_env;
++
++void callmgr_sighandler(int sig) {
++    /* TODO: according to signal(2), siglongjmp() is unsafe used here */
++    siglongjmp (callmgr_env, 1);
++}
++
++void callmgr_do_nothing(int sig) {
++    /* do nothing signal handler */
++}
++
++struct local_callinfo {
++    int unix_sock;
++    pid_t pid[2];
++};
++
++struct local_conninfo {
++    VECTOR * call_list;
++    fd_set * call_set;
++};
++
++/* Call callback */
++void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state)
++{
++    struct local_callinfo *lci;
++    struct local_conninfo *conninfo;
++    u_int16_t call_id[2];
++    switch(state) {
++        case CALL_OPEN_DONE:
++            /* okey dokey.  This means that the call_id and peer_call_id are
++             * now valid, so lets send them on to our friends who requested
++             * this call.  */
++            lci = pptp_call_closure_get(conn, call); assert(lci != NULL);
++            pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]);
++            write(lci->unix_sock, &call_id, sizeof(call_id));
++            /* Our duty to the fatherland is now complete. */
++            break;
++        case CALL_OPEN_FAIL:
++        case CALL_CLOSE_RQST:
++        case CALL_CLOSE_DONE:
++            /* don't need to do anything here, except make sure tables
++             * are sync'ed */
++            dbglog("Closing connection (call state)");
++            conninfo = pptp_conn_closure_get(conn);
++            lci = pptp_call_closure_get(conn, call);
++            assert(lci != NULL && conninfo != NULL);
++            if (vector_contains(conninfo->call_list, lci->unix_sock)) {
++                vector_remove(conninfo->call_list, lci->unix_sock);
++                close(lci->unix_sock);
++                FD_CLR(lci->unix_sock, conninfo->call_set);
++            }
++            break;
++        default:
++            dbglog("Unhandled call callback state [%d].", (int) state);
++            break;
++    }
++}
++
++/******************************************************************************
++ * NOTE ABOUT 'VOLATILE':
++ * several variables here get a volatile qualifier to silence warnings
++ * from older (before 3.0) gccs. if the longjmp stuff is removed,
++ * the volatile qualifiers should be removed as well.
++ *****************************************************************************/
++
++/*** Call Manager *************************************************************/
++int callmgr_main(struct in_addr inetaddr, char phonenr[], int window, int pcallid)
++{
++    int inet_sock, unix_sock;
++    fd_set call_set;
++    PPTP_CONN * conn;
++    VECTOR * call_list;
++    int max_fd = 0;
++    volatile int first = 1;
++    int retval;
++    int i;
++    if (pcallid>0) call_ID=pcallid;
++
++    /* Step 1: Open sockets. */
++    if ((inet_sock = open_inetsock(inetaddr)) < 0)
++        fatal("Could not open control connection to %s", inet_ntoa(inetaddr));
++    dbglog("control connection");
++    if ((unix_sock = open_unixsock(inetaddr)) < 0)
++        fatal("Could not open unix socket for %s", inet_ntoa(inetaddr));
++    /* Step 1b: FORK and return status to calling process. */
++    dbglog("unix_sock");
++
++    switch (fork()) {
++        case 0: /* child. stick around. */
++            break;
++        case -1: /* failure.  Fatal. */
++            fatal("Could not fork.");
++        default: /* Parent. Return status to caller. */
++            exit(0);
++    }
++    /* re-open stderr as /dev/null to release it */
++    file2fd("/dev/null", "wb", STDERR_FILENO);
++    /* Step 1c: Clean up unix socket on TERM */
++    if (sigsetjmp(callmgr_env, 1) != 0)
++        goto cleanup;
++    signal(SIGINT, callmgr_sighandler);
++    signal(SIGTERM, callmgr_sighandler);
++    signal(SIGPIPE, callmgr_do_nothing);
++    signal(SIGUSR1, callmgr_do_nothing); /* signal state change
++                                            wake up accept */
++    /* Step 2: Open control connection and register callback */
++    if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) {
++        close(unix_sock); close(inet_sock); fatal("Could not open connection.");
++    }
++    FD_ZERO(&call_set);
++    call_list = vector_create();
++    {
++        struct local_conninfo *conninfo = malloc(sizeof(*conninfo));
++        if (conninfo == NULL) {
++            close(unix_sock); close(inet_sock); fatal("No memory.");
++        }
++        conninfo->call_list = call_list;
++        conninfo->call_set  = &call_set;
++        pptp_conn_closure_put(conn, conninfo);
++    }
++    if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown;
++    /* Step 3: Get FD_SETs */
++    max_fd = unix_sock;
++    do {
++        int rc;
++        fd_set read_set = call_set, write_set;
++        FD_ZERO (&write_set);
++        if (pptp_conn_established(conn)) {
++	  FD_SET (unix_sock, &read_set);
++	  if (unix_sock > max_fd) max_fd = unix_sock;
++	}
++        pptp_fd_set(conn, &read_set, &write_set, &max_fd);
++        for (; max_fd > 0 ; max_fd--) {
++            if (FD_ISSET (max_fd, &read_set) ||
++                    FD_ISSET (max_fd, &write_set))
++                break;
++        }
++        /* Step 4: Wait on INET or UNIX event */
++        if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) {
++	  if (errno == EBADF) break;
++	  /* a signal or somesuch. */
++	  continue;
++	}
++        /* Step 5a: Handle INET events */
++        rc = pptp_dispatch(conn, &read_set, &write_set);
++	if (rc < 0)
++	    break;
++        /* Step 5b: Handle new connection to UNIX socket */
++        if (FD_ISSET(unix_sock, &read_set)) {
++            /* New call! */
++            struct sockaddr_un from;
++            int len = sizeof(from);
++            PPTP_CALL * call;
++            struct local_callinfo *lci;
++            int s;
++            /* Accept the socket */
++            FD_CLR (unix_sock, &read_set);
++            if ((s = accept(unix_sock, (struct sockaddr *) &from, &len)) < 0) {
++                warn("Socket not accepted: %s", strerror(errno));
++                goto skip_accept;
++            }
++            /* Allocate memory for local call information structure. */
++            if ((lci = malloc(sizeof(*lci))) == NULL) {
++                warn("Out of memory."); close(s); goto skip_accept;
++            }
++            lci->unix_sock = s;
++            /* Give the initiator time to write the PIDs while we open
++             * the call */
++            call = pptp_call_open(conn, call_ID,call_callback, phonenr,window);
++            /* Read and store the associated pids */
++            read(s, &lci->pid[0], sizeof(lci->pid[0]));
++            read(s, &lci->pid[1], sizeof(lci->pid[1]));
++            /* associate the local information with the call */
++            pptp_call_closure_put(conn, call, (void *) lci);
++            /* The rest is done on callback. */
++            /* Keep alive; wait for close */
++            retval = vector_insert(call_list, s, call); assert(retval);
++            if (s > max_fd) max_fd = s;
++            FD_SET(s, &call_set);
++            first = 0;
++        }
++skip_accept: /* Step 5c: Handle socket close */
++        for (i = 0; i < max_fd + 1; i++)
++            if (FD_ISSET(i, &read_set)) {
++                /* close it */
++                PPTP_CALL * call;
++                retval = vector_search(call_list, i, &call);
++                if (retval) {
++                    struct local_callinfo *lci =
++                        pptp_call_closure_get(conn, call);
++                    dbglog("Closing connection (unhandled)");
++                    free(lci);
++                    /* soft shutdown.  Callback will do hard shutdown later */
++                    pptp_call_close(conn, call);
++                    vector_remove(call_list, i);
++                }
++                FD_CLR(i, &call_set);
++                close(i);
++            }
++    } while (vector_size(call_list) > 0 || first);
++shutdown:
++    {
++        int rc;
++        fd_set read_set, write_set;
++        struct timeval tv;
++	signal(SIGINT, callmgr_do_nothing);
++	signal(SIGTERM, callmgr_do_nothing);
++        /* warn("Shutdown"); */
++        /* kill all open calls */
++        for (i = 0; i < vector_size(call_list); i++) {
++            PPTP_CALL *call = vector_get_Nth(call_list, i);
++            dbglog("Closing connection (shutdown)");
++            pptp_call_close(conn, call);
++        }
++        /* attempt to dispatch these messages */
++        FD_ZERO(&read_set);
++        FD_ZERO(&write_set);
++        pptp_fd_set(conn, &read_set, &write_set, &max_fd);
++	tv.tv_sec = 0;
++	tv.tv_usec = 0;
++	select(max_fd + 1, &read_set, &write_set, NULL, &tv);
++        rc = pptp_dispatch(conn, &read_set, &write_set);
++	if (rc > 0) {
++	  /* wait for a respond, a timeout because there might not be one */
++	  FD_ZERO(&read_set);
++	  FD_ZERO(&write_set);
++	  pptp_fd_set(conn, &read_set, &write_set, &max_fd);
++	  tv.tv_sec = 2;
++	  tv.tv_usec = 0;
++	  select(max_fd + 1, &read_set, &write_set, NULL, &tv);
++	  rc = pptp_dispatch(conn, &read_set, &write_set);
++	  if (rc > 0) {
++	    if (i > 0) sleep(2);
++	    /* no more open calls.  Close the connection. */
++	    pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN);
++	    /* wait for a respond, a timeout because there might not be one */
++	    FD_ZERO(&read_set);
++	    FD_ZERO(&write_set);
++	    pptp_fd_set(conn, &read_set, &write_set, &max_fd);
++	    tv.tv_sec = 2;
++	    tv.tv_usec = 0;
++	    select(max_fd + 1, &read_set, &write_set, NULL, &tv);
++	    pptp_dispatch(conn, &read_set, &write_set);
++	    if (rc > 0) sleep(2);
++	  }
++	}
++        /* with extreme prejudice */
++        pptp_conn_destroy(conn);
++        vector_destroy(call_list);
++    }
++cleanup:
++    signal(SIGINT, callmgr_do_nothing);
++    signal(SIGTERM, callmgr_do_nothing);
++    close_inetsock(inet_sock, inetaddr);
++    close_unixsock(unix_sock, inetaddr);
++    return 0;
++}
++
++/*** open_inetsock ************************************************************/
++int open_inetsock(struct in_addr inetaddr)
++{
++    struct sockaddr_in dest, src;
++    int s;
++    dest.sin_family = AF_INET;
++    dest.sin_port   = htons(PPTP_PORT);
++    dest.sin_addr   = inetaddr;
++    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
++        warn("socket: %s", strerror(errno));
++        return s;
++    }
++    if (localbind.s_addr != INADDR_NONE) {
++        bzero(&src, sizeof(src));
++        src.sin_family = AF_INET;
++        src.sin_addr   = localbind;
++        if (bind(s, (struct sockaddr *) &src, sizeof(src)) != 0) {
++            warn("bind: %s", strerror(errno));
++            close(s); return -1;
++        }
++    }
++    if (connect(s, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
++        warn("connect: %s", strerror(errno));
++        close(s); return -1;
++    }
++    return s;
++}
++
++/*** open_unixsock ************************************************************/
++int open_unixsock(struct in_addr inetaddr)
++{
++    struct sockaddr_un where;
++    struct stat st;
++    char *dir;
++    int s;
++    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
++        warn("socket: %s", strerror(errno));
++        return s;
++    }
++    callmgr_name_unixsock( &where, inetaddr, localbind);
++    if (stat(where.sun_path, &st) >= 0)
++    {
++        warn("Call manager for %s is already running.", inet_ntoa(inetaddr));
++        close(s); return -1;
++    }
++   /* Make sure path is valid. */
++    dir = dirnamex(where.sun_path);
++    if (!make_valid_path(dir, 0770))
++        fatal("Could not make path to %s: %s", where.sun_path, strerror(errno));
++    free(dir);
++    if (bind(s, (struct sockaddr *) &where, sizeof(where)) < 0) {
++        warn("bind: %s", strerror(errno));
++        close(s); return -1;
++    }
++    chmod(where.sun_path, 0777);
++    listen(s, 127);
++    return s;
++}
++
++/*** close_inetsock ***********************************************************/
++void close_inetsock(int fd, struct in_addr inetaddr)
++{
++    close(fd);
++}
++
++/*** close_unixsock ***********************************************************/
++void close_unixsock(int fd, struct in_addr inetaddr)
++{
++    struct sockaddr_un where;
++    close(fd);
++    callmgr_name_unixsock(&where, inetaddr, localbind);
++    unlink(where.sun_path);
++}
++
++/*** make a unix socket address ***********************************************/
++void callmgr_name_unixsock(struct sockaddr_un *where,
++			   struct in_addr inetaddr,
++			   struct in_addr localbind)
++{
++    char localaddr[16], remoteaddr[16];
++    where->sun_family = AF_UNIX;
++    strncpy(localaddr,  inet_ntoa(localbind), 16);
++    strncpy(remoteaddr, inet_ntoa(inetaddr),  16);
++    snprintf(where->sun_path, sizeof(where->sun_path),
++            PPTP_SOCKET_PREFIX "%s:%i", remoteaddr,call_ID);
++}
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_callmgr.h
+@@ -0,0 +1,17 @@
++/* pptp_callmgr.h ... Call manager for PPTP connections.
++ *                    Handles TCP port 1723 protocol.
++ *                    C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: pptp_callmgr.h,v 1.3 2003/02/17 00:22:17 quozl Exp $
++ */
++
++#define PPTP_SOCKET_PREFIX "/var/run/pptp/"
++
++int callmgr_main(struct in_addr inetaddr,
++		char phonenr[],
++		int window,
++		int pcallid);
++
++void callmgr_name_unixsock(struct sockaddr_un *where,
++			   struct in_addr inetaddr,
++			   struct in_addr localbind);
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_ctrl.c
+@@ -0,0 +1,1077 @@
++/* pptp_ctrl.c ... handle PPTP control connection.
++ *                 C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: pptp_ctrl.c,v 1.31 2005/03/31 07:42:39 quozl Exp $
++ */
++
++#include <errno.h>
++#include <sys/time.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <assert.h>
++#include <signal.h>
++#include <string.h>
++#include <ctype.h>
++#include <fcntl.h>
++#include "pptp_msg.h"
++#include "pptp_ctrl.h"
++#include "pptp_options.h"
++#include "vector.h"
++#include "util.h"
++#include "pptp_quirks.h"
++
++/* BECAUSE OF SIGNAL LIMITATIONS, EACH PROCESS CAN ONLY MANAGE ONE
++ * CONNECTION.  SO THIS 'PPTP_CONN' STRUCTURE IS A BIT MISLEADING.
++ * WE'LL KEEP CONNECTION-SPECIFIC INFORMATION IN THERE ANYWAY (AS
++ * OPPOSED TO USING GLOBAL VARIABLES), BUT BEWARE THAT THE ENTIRE
++ * UNIX SIGNAL-HANDLING SEMANTICS WOULD HAVE TO CHANGE (OR THE
++ * TIME-OUT CODE DRASTICALLY REWRITTEN) BEFORE YOU COULD DO A
++ * PPTP_CONN_OPEN MORE THAN ONCE PER PROCESS AND GET AWAY WITH IT.
++ */
++
++/* This structure contains connection-specific information that the
++ * signal handler needs to see.  Thus, it needs to be in a global
++ * variable.  If you end up using pthreads or something (why not
++ * just processes?), this would have to be placed in a thread-specific
++ * data area, using pthread_get|set_specific, etc., so I've
++ * conveniently encapsulated it for you.
++ * [linux threads will have to support thread-specific signals
++ *  before this would work at all, which, as of this writing
++ *  (linux-threads v0.6, linux kernel 2.1.72), it does not.]
++ */
++
++/* Globals */
++
++/* control the number of times echo packets will be logged */
++static int nlogecho = 10;
++
++static struct thread_specific {
++    struct sigaction old_sigaction; /* evil signals */
++    PPTP_CONN * conn;
++} global;
++
++#define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */
++
++struct PPTP_CONN {
++    int inet_sock;
++    /* Connection States */
++    enum {
++        CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED
++    } conn_state; /* on startup: CONN_IDLE */
++    /* Keep-alive states */
++    enum {
++        KA_NONE, KA_OUTSTANDING
++    } ka_state;  /* on startup: KA_NONE */
++    /* Keep-alive ID; monotonically increasing (watch wrap-around!) */
++    u_int32_t ka_id; /* on startup: 1 */
++    /* Other properties. */
++    u_int16_t version;
++    u_int16_t firmware_rev;
++    u_int8_t  hostname[64], vendor[64];
++    /* XXX these are only PNS properties, currently XXX */
++    /* Call assignment information. */
++    u_int16_t call_serial_number;
++    VECTOR *call;
++    void * closure;
++    pptp_conn_cb callback;
++    /******* IO buffers ******/
++    char * read_buffer, *write_buffer;
++    size_t read_alloc,   write_alloc;
++    size_t read_size,    write_size;
++};
++
++struct PPTP_CALL {
++    /* Call properties */
++    enum {
++        PPTP_CALL_PAC, PPTP_CALL_PNS
++    } call_type;
++    union {
++        enum pptp_pac_state {
++            PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS
++        } pac;
++        enum pptp_pns_state {
++            PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT
++        } pns;
++    } state;
++    u_int16_t call_id, peer_call_id;
++    u_int16_t sernum;
++    u_int32_t speed;
++    /* For user data: */
++    pptp_call_cb callback;
++    void * closure;
++};
++
++
++/* PPTP error codes: ----------------------------------------------*/
++
++/* (General Error Codes) */
++static const struct {
++    const char *name, *desc;
++} pptp_general_errors[] = {
++#define PPTP_GENERAL_ERROR_NONE                 0
++    { "(None)", "No general error" },
++#define PPTP_GENERAL_ERROR_NOT_CONNECTED        1
++    { "(Not-Connected)", "No control connection exists yet for this "
++        "PAC-PNS pair" },
++#define PPTP_GENERAL_ERROR_BAD_FORMAT           2
++    { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" },
++#define PPTP_GENERAL_ERROR_BAD_VALUE            3
++    { "(Bad-Value)", "One of the field values was out of range or "
++            "reserved field was non-zero" },
++#define PPTP_GENERAL_ERROR_NO_RESOURCE          4
++    { "(No-Resource)", "Insufficient resources to handle this command now" },
++#define PPTP_GENERAL_ERROR_BAD_CALLID           5
++    { "(Bad-Call ID)", "The Call ID is invalid in this context" },
++#define PPTP_GENERAL_ERROR_PAC_ERROR            6
++    { "(PAC-Error)", "A generic vendor-specific error occured in the PAC" }
++};
++
++#define  MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \
++        sizeof(pptp_general_errors[0]) - 1)
++
++/* Outgoing Call Reply Result Codes */
++static const char *pptp_out_call_reply_result[] = {
++/* 0 */	"Unknown Result Code",
++/* 1 */	"Connected",
++/* 2 */	"General Error",
++/* 3 */	"No Carrier Detected",
++/* 4 */	"Busy Signal",
++/* 5 */	"No Dial Tone",
++/* 6 */	"Time Out",
++/* 7 */	"Not Accepted, Call is administratively prohibited" };
++
++#define MAX_OUT_CALL_REPLY_RESULT 7
++
++/* Call Disconnect Notify  Result Codes */
++static const char *pptp_call_disc_ntfy[] = {
++/* 0 */	"Unknown Result Code",
++/* 1 */	"Lost Carrier",
++/* 2 */	"General Error",
++/* 3 */	"Administrative Shutdown",
++/* 4 */	"(your) Request" };
++
++#define MAX_CALL_DISC_NTFY 4
++
++/* Call Disconnect Notify  Result Codes */
++static const char *pptp_start_ctrl_conn_rply[] = {
++/* 0 */	"Unknown Result Code",
++/* 1 */	"Successful Channel Establishment",
++/* 2 */	"General Error",
++/* 3 */	"Command Channel Already Exists",
++/* 4 */	"Requester is not Authorized" };
++
++#define MAX_START_CTRL_CONN_REPLY 4
++
++/* timing options */
++int idle_wait = PPTP_TIMEOUT;
++int max_echo_wait = PPTP_TIMEOUT;
++
++/* Local prototypes */
++static void pptp_reset_timer(void);
++static void pptp_handle_timer();
++/* Write/read as much as we can without blocking. */
++int pptp_write_some(PPTP_CONN * conn);
++int pptp_read_some(PPTP_CONN * conn);
++/* Make valid packets from read_buffer */
++int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size);
++/* Add packet to write_buffer */
++int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size);
++/* Dispatch packets (general) */
++int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size);
++/* Dispatch packets (control messages) */
++int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size);
++/* Set link info, for pptp servers that need it.
++   this is a noop, unless the user specified a quirk and
++   there's a set_link hook defined in the quirks table
++   for that quirk */
++void pptp_set_link(PPTP_CONN * conn, int peer_call_id);
++
++/*** log error information in control packets *********************************/
++static void ctrlp_error( int result, int error, int cause,
++        const char *result_text[], int max_result)
++{
++    if( cause >= 0)
++        warn("Result code is %d '%s'. Error code is %d, Cause code is %d",
++                result, result_text[result <= max_result ?  result : 0], error,
++                cause );
++    else
++        warn("Reply result code is %d '%s'. Error code is %d",
++                result, result_text[result <= max_result ?  result : 0], error);
++    if ((error > 0) && (error <= MAX_GENERAL_ERROR)){
++        if( result != PPTP_RESULT_GENERAL_ERROR )
++            warn("Result code is something else then \"general error\", "
++                    "so the following error is probably bogus.");
++        warn("Error is '%s', Error message: '%s'",
++                pptp_general_errors[error].name,
++                pptp_general_errors[error].desc);
++    }
++}
++
++static const char *ctrl_msg_types[] = {
++         "invalid control message type",
++/*         (Control Connection Management) */
++         "Start-Control-Connection-Request",            /* 1 */
++         "Start-Control-Connection-Reply",              /* 2 */
++         "Stop-Control-Connection-Request",             /* 3 */
++         "Stop-Control-Connection-Reply",               /* 4 */
++         "Echo-Request",                                /* 5 */
++         "Echo-Reply",                                  /* 6 */
++/*         (Call Management) */
++         "Outgoing-Call-Request",                       /* 7 */
++         "Outgoing-Call-Reply",                         /* 8 */
++         "Incoming-Call-Request",                       /* 9 */
++         "Incoming-Call-Reply",                        /* 10 */
++         "Incoming-Call-Connected",                    /* 11 */
++         "Call-Clear-Request",                         /* 12 */
++         "Call-Disconnect-Notify",                     /* 13 */
++/*         (Error Reporting) */
++         "WAN-Error-Notify",                           /* 14 */
++/*         (PPP Session Control) */
++         "Set-Link-Info"                              /* 15 */
++};
++#define MAX_CTRLMSG_TYPE 15
++
++/*** report a sent packet ****************************************************/
++static void ctrlp_rep( void * buffer, int size, int isbuff)
++{
++    struct pptp_header *packet = buffer;
++    unsigned int type;
++    if(size < sizeof(struct pptp_header)) return;
++    type = ntoh16(packet->ctrl_type);
++    /* FIXME: do not report sending echo requests as long as they are
++     * sent in a signal handler. This may dead lock as the syslog call
++     * is not reentrant */
++    if( type ==  PPTP_ECHO_RQST ) return;
++    /* don't keep reporting sending of echo's */
++    if( (type == PPTP_ECHO_RQST || type == PPTP_ECHO_RPLY) && nlogecho <= 0 ) return;
++    dbglog("%s control packet type is %d '%s'\n",isbuff ? "Buffered" : "Sent",
++            type, ctrl_msg_types[type <= MAX_CTRLMSG_TYPE ? type : 0]);
++
++}
++
++
++
++/* Open new pptp_connection.  Returns NULL on failure. */
++PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
++{
++    PPTP_CONN *conn;
++    /* Allocate structure */
++    if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
++    if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
++    /* Initialize */
++    conn->inet_sock = inet_sock;
++    conn->conn_state = CONN_IDLE;
++    conn->ka_state  = KA_NONE;
++    conn->ka_id     = 1;
++    conn->call_serial_number = 0;
++    conn->callback  = callback;
++    /* Create I/O buffers */
++    conn->read_size = conn->write_size = 0;
++    conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE;
++    conn->read_buffer =
++        malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc);
++    conn->write_buffer =
++        malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc);
++    if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
++        if (conn->read_buffer  != NULL) free(conn->read_buffer);
++        if (conn->write_buffer != NULL) free(conn->write_buffer);
++        vector_destroy(conn->call); free(conn); return NULL;
++    }
++    /* Make this socket non-blocking. */
++    fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
++    /* Request connection from server, if this is a client */
++    if (isclient) {
++        struct pptp_start_ctrl_conn packet = {
++            PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
++            hton16(PPTP_VERSION), 0, 0,
++            hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
++            hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
++            PPTP_HOSTNAME, PPTP_VENDOR
++        };
++        /* fix this packet, if necessary */
++        int idx, rc;
++        idx = get_quirk_index();
++        if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
++            if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
++                warn("calling the start_ctrl_conn hook failed (%d)", rc);
++        }
++        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
++            conn->conn_state = CONN_WAIT_CTL_REPLY;
++        else
++            return NULL; /* could not send initial start request. */
++    }
++    /* Set up interval/keep-alive timer */
++    /*   First, register handler for SIGALRM */
++    sigpipe_create();
++    sigpipe_assign(SIGALRM);
++    global.conn = conn;
++    /* Reset event timer */
++    pptp_reset_timer();
++    /* all done. */
++    return conn;
++}
++
++int pptp_conn_established(PPTP_CONN *conn) {
++  return (conn->conn_state == CONN_ESTABLISHED);
++}
++
++/* This currently *only* works for client call requests.
++ * We need to do something else to allocate calls for incoming requests.
++ */
++PPTP_CALL * pptp_call_open(PPTP_CONN * conn, int call_id,pptp_call_cb callback,
++        char *phonenr,int window)
++{
++    PPTP_CALL * call;
++    int idx, rc;
++    /* Send off the call request */
++    struct pptp_out_call_rqst packet = {
++        PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
++        0,0, /*call_id, sernum */
++        hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
++        hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP),
++        hton16(window), 0, 0, 0, {0}, {0}
++    };
++    assert(conn && conn->call);
++    assert(conn->conn_state == CONN_ESTABLISHED);
++    /* Assign call id */
++    if (!call_id && !vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &call_id))
++        /* no more calls available! */
++        return NULL;
++    /* allocate structure. */
++    if ((call = malloc(sizeof(*call))) == NULL) return NULL;
++    /* Initialize call structure */
++    call->call_type = PPTP_CALL_PNS;
++    call->state.pns = PNS_IDLE;
++    call->call_id   = (u_int16_t) call_id;
++    call->sernum    = conn->call_serial_number++;
++    call->callback  = callback;
++    call->closure   = NULL;
++    packet.call_id = htons(call->call_id);
++    packet.call_sernum = htons(call->sernum);
++    /* if we have a quirk, build a new packet to fit it */
++    idx = get_quirk_index();
++    if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) {
++        if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet)))
++            warn("calling the out_call_rqst hook failed (%d)", rc);
++    }
++    /* fill in the phone number if it was specified */
++    if (phonenr) {
++        strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num));
++        packet.phone_len = strlen(phonenr);
++        if( packet.phone_len > sizeof(packet.phone_num))
++            packet.phone_len = sizeof(packet.phone_num);
++        packet.phone_len = hton16 (packet.phone_len);
++    }
++    if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
++        pptp_reset_timer();
++        call->state.pns = PNS_WAIT_REPLY;
++        /* and add it to the call vector */
++        vector_insert(conn->call, call_id, call);
++        return call;
++    } else { /* oops, unsuccessful. Deallocate. */
++        free(call);
++        return NULL;
++    }
++}
++
++/*** pptp_call_close **********************************************************/
++void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call)
++{
++    struct pptp_call_clear_rqst rqst = {
++        PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0
++    };
++    assert(conn && conn->call); assert(call);
++    assert(vector_contains(conn->call, call->call_id));
++    /* haven't thought about PAC yet */
++    assert(call->call_type == PPTP_CALL_PNS);
++    assert(call->state.pns != PNS_IDLE);
++    rqst.call_id = hton16(call->call_id);
++    /* don't check state against WAIT_DISCONNECT... allow multiple disconnect
++     * requests to be made.
++     */
++    pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
++    pptp_reset_timer();
++    call->state.pns = PNS_WAIT_DISCONNECT;
++    /* call structure will be freed when we have confirmation of disconnect. */
++}
++
++/*** hard close ***************************************************************/
++void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call)
++{
++    assert(conn && conn->call); assert(call);
++    assert(vector_contains(conn->call, call->call_id));
++    /* notify */
++    if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE);
++    /* deallocate */
++    vector_remove(conn->call, call->call_id);
++    free(call);
++}
++
++/*** this is a soft close *****************************************************/
++void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason)
++{
++    struct pptp_stop_ctrl_conn rqst = {
++        PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST),
++        hton8(close_reason), 0, 0
++    };
++    int i;
++    assert(conn && conn->call);
++    /* avoid repeated close attempts */
++    if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY)
++        return;
++    /* close open calls, if any */
++    for (i = 0; i < vector_size(conn->call); i++)
++        pptp_call_close(conn, vector_get_Nth(conn->call, i));
++    /* now close connection */
++    info("Closing PPTP connection");
++    pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
++    pptp_reset_timer(); /* wait 60 seconds for reply */
++    conn->conn_state = CONN_WAIT_STOP_REPLY;
++    return;
++}
++
++/*** this is a hard close *****************************************************/
++void pptp_conn_destroy(PPTP_CONN * conn)
++{
++    int i;
++    assert(conn != NULL); assert(conn->call != NULL);
++    /* destroy all open calls */
++    for (i = 0; i < vector_size(conn->call); i++)
++        pptp_call_destroy(conn, vector_get_Nth(conn->call, i));
++    /* notify */
++    if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE);
++    sigpipe_close();
++    close(conn->inet_sock);
++    /* deallocate */
++    vector_destroy(conn->call);
++    free(conn);
++}
++
++/*** Deal with messages, in a non-blocking manner
++ * Add file descriptors used by pptp to fd_set.
++ */
++void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set,
++                 int * max_fd)
++{
++    assert(conn && conn->call);
++    /* Add fd to write_set if there are outstanding writes. */
++    if (conn->write_size > 0)
++        FD_SET(conn->inet_sock, write_set);
++    /* Always add fd to read_set. (always want something to read) */
++    FD_SET(conn->inet_sock, read_set);
++    if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock;
++    /* Add signal pipe file descriptor to set */
++    int sig_fd = sigpipe_fd();
++    FD_SET(sig_fd, read_set);
++    if (*max_fd < sig_fd) *max_fd = sig_fd;
++}
++
++/*** handle any pptp file descriptors set in fd_set, and clear them ***********/
++int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set)
++{
++    int r = 0;
++    assert(conn && conn->call);
++    /* Check for signals */
++    if (FD_ISSET(sigpipe_fd(), read_set)) {
++        if (sigpipe_read() == SIGALRM) pptp_handle_timer();
++	FD_CLR(sigpipe_fd(), read_set);
++    }
++    /* Check write_set could be set. */
++    if (FD_ISSET(conn->inet_sock, write_set)) {
++        FD_CLR(conn->inet_sock, write_set);
++        if (conn->write_size > 0)
++            r = pptp_write_some(conn);/* write as much as we can without blocking */
++    }
++    /* Check read_set */
++    if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) {
++        void *buffer; size_t size;
++        FD_CLR(conn->inet_sock, read_set);
++        r = pptp_read_some(conn); /* read as much as we can without blocking */
++	if (r < 0)
++	    return r;
++        /* make packets of the buffer, while we can. */
++        while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) {
++            r = pptp_dispatch_packet(conn, buffer, size);
++            free(buffer);
++        }
++    }
++    /* That's all, folks.  Simple, eh? */
++    return r;
++}
++
++/*** Non-blocking write *******************************************************/
++int pptp_write_some(PPTP_CONN * conn) {
++    ssize_t retval;
++    assert(conn && conn->call);
++    retval = write(conn->inet_sock, conn->write_buffer, conn->write_size);
++    if (retval < 0) { /* error. */
++        if (errno == EAGAIN || errno == EINTR) {
++            return 0;
++        } else { /* a real error */
++            warn("write error: %s", strerror(errno));
++	    return -1;
++        }
++    }
++    assert(retval <= conn->write_size);
++    conn->write_size -= retval;
++    memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size);
++    ctrlp_rep(conn->write_buffer, retval, 0);
++    return 0;
++}
++
++/*** Non-blocking read ********************************************************/
++int pptp_read_some(PPTP_CONN * conn)
++{
++    ssize_t retval;
++    assert(conn && conn->call);
++    if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */
++        char *new_buffer = realloc(conn->read_buffer,
++                sizeof(*(conn->read_buffer)) * conn->read_alloc * 2);
++        if (new_buffer == NULL) {
++            warn("Out of memory"); return -1;
++        }
++        conn->read_alloc *= 2;
++        conn->read_buffer = new_buffer;
++    }
++    retval = read(conn->inet_sock, conn->read_buffer + conn->read_size,
++            conn->read_alloc  - conn->read_size);
++    if (retval == 0) {
++        warn("read returned zero, peer has closed");
++        return -1;
++    }
++    if (retval < 0) {
++        if (errno == EINTR || errno == EAGAIN)
++	    return 0;
++        else { /* a real error */
++            warn("read error: %s", strerror(errno));
++            return -1;
++        }
++    }
++    conn->read_size += retval;
++    assert(conn->read_size <= conn->read_alloc);
++    return 0;
++}
++
++/*** Packet formation *********************************************************/
++int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size)
++{
++    struct pptp_header *header;
++    size_t bad_bytes = 0;
++    assert(conn && conn->call); assert(buf != NULL); assert(size != NULL);
++    /* Give up unless there are at least sizeof(pptp_header) bytes */
++    while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) {
++        /* Throw out bytes until we have a valid header. */
++        header = (struct pptp_header *) (conn->read_buffer + bad_bytes);
++        if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout;
++        if (ntoh16(header->reserved0) != 0)
++            warn("reserved0 field is not zero! (0x%x) Cisco feature? \n",
++                    ntoh16(header->reserved0));
++        if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout;
++        if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout;
++        /* well.  I guess it's good. Let's see if we've got it all. */
++        if (ntoh16(header->length) > (conn->read_size-bad_bytes))
++            /* nope.  Let's wait until we've got it, then. */
++            goto flushbadbytes;
++        /* One last check: */
++        if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) &&
++                (ntoh16(header->length) !=
++                         PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))))
++            goto throwitout;
++        /* well, I guess we've got it. */
++        *size = ntoh16(header->length);
++        *buf = malloc(*size);
++        if (*buf == NULL) { warn("Out of memory."); return 0; /* ack! */ }
++        memcpy(*buf, conn->read_buffer + bad_bytes, *size);
++        /* Delete this packet from the read_buffer. */
++        conn->read_size -= (bad_bytes + *size);
++        memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size,
++                conn->read_size);
++        if (bad_bytes > 0)
++            warn("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
++        return 1;
++throwitout:
++        bad_bytes++;
++    }
++flushbadbytes:
++    /* no more packets.  Let's get rid of those bad bytes */
++    conn->read_size -= bad_bytes;
++    memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size);
++    if (bad_bytes > 0)
++        warn("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
++    return 0;
++}
++
++/*** pptp_send_ctrl_packet ****************************************************/
++int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size)
++{
++    assert(conn && conn->call); assert(buffer);
++    if( conn->write_size > 0) pptp_write_some( conn);
++    if( conn->write_size == 0) {
++        ssize_t retval;
++        retval = write(conn->inet_sock, buffer, size);
++        if (retval < 0) { /* error. */
++            if (errno == EAGAIN || errno == EINTR) {
++                /* ignore */;
++                retval = 0;
++            } else { /* a real error */
++                warn("write error: %s", strerror(errno));
++                pptp_conn_destroy(conn); /* shut down fast. */
++                return 0;
++            }
++        }
++        ctrlp_rep( buffer, retval, 0);
++        size -= retval;
++        if( size <= 0) return 1;
++    }
++    /* Shove anything not written into the write buffer */
++    if (conn->write_size + size > conn->write_alloc) { /* need more memory */
++        char *new_buffer = realloc(conn->write_buffer,
++                sizeof(*(conn->write_buffer)) * conn->write_alloc * 2);
++        if (new_buffer == NULL) {
++            warn("Out of memory"); return 0;
++        }
++        conn->write_alloc *= 2;
++        conn->write_buffer = new_buffer;
++    }
++    memcpy(conn->write_buffer + conn->write_size, buffer, size);
++    conn->write_size += size;
++    ctrlp_rep( buffer,size,1);
++    return 1;
++}
++
++/*** Packet Dispatch **********************************************************/
++int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size)
++{
++    int r = 0;
++    struct pptp_header *header = (struct pptp_header *)buffer;
++    assert(conn && conn->call); assert(buffer);
++    assert(ntoh32(header->magic) == PPTP_MAGIC);
++    assert(ntoh16(header->length) == size);
++    switch (ntoh16(header->pptp_type)) {
++        case PPTP_MESSAGE_CONTROL:
++            r = ctrlp_disp(conn, buffer, size);
++            break;
++        case PPTP_MESSAGE_MANAGE:
++            /* MANAGEMENT messages aren't even part of the spec right now. */
++            dbglog("PPTP management message received, but not understood.");
++            break;
++        default:
++            dbglog("Unknown PPTP control message type received: %u",
++                    (unsigned int) ntoh16(header->pptp_type));
++            break;
++    }
++    return r;
++}
++
++/*** log echo request/replies *************************************************/
++static void logecho( int type)
++{
++    /* hack to stop flooding the log files (the most interesting part is right
++     * after the connection built-up) */
++    if( nlogecho > 0) {
++        dbglog("Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply");
++        if( --nlogecho == 0)
++            dbglog("no more Echo Reply/Request packets will be reported.");
++    }
++}
++
++/*** pptp_dispatch_ctrl_packet ************************************************/
++int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size)
++{
++    struct pptp_header *header = (struct pptp_header *)buffer;
++    u_int8_t close_reason = PPTP_STOP_NONE;
++    assert(conn && conn->call); assert(buffer);
++    assert(ntoh32(header->magic) == PPTP_MAGIC);
++    assert(ntoh16(header->length) == size);
++    assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL);
++    if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) {
++        warn("Invalid packet received [type: %d; length: %d].",
++                (int) ntoh16(header->ctrl_type), (int) size);
++        return 0;
++    }
++    switch (ntoh16(header->ctrl_type)) {
++        /* ----------- STANDARD Start-Session MESSAGES ------------ */
++        case PPTP_START_CTRL_CONN_RQST:
++        {
++            struct pptp_start_ctrl_conn *packet =
++                (struct pptp_start_ctrl_conn *) buffer;
++            struct pptp_start_ctrl_conn reply = {
++                PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
++                hton16(PPTP_VERSION), 0, 0,
++                hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
++                hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
++                PPTP_HOSTNAME, PPTP_VENDOR };
++            int idx, rc;
++            dbglog("Received Start Control Connection Request");
++            /* fix this packet, if necessary */
++            idx = get_quirk_index();
++            if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
++                if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply)))
++                    warn("calling the start_ctrl_conn hook failed (%d)", rc);
++            }
++            if (conn->conn_state == CONN_IDLE) {
++                if (ntoh16(packet->version) < PPTP_VERSION) {
++                    /* Can't support this (earlier) PPTP_VERSION */
++                    reply.version = packet->version;
++                    /* protocol version not supported */
++                    reply.result_code = hton8(5);
++                    pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
++                    pptp_reset_timer(); /* give sender a chance for a retry */
++                } else { /* same or greater version */
++                    if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
++                        conn->conn_state = CONN_ESTABLISHED;
++                        dbglog("server connection ESTABLISHED.");
++                        pptp_reset_timer();
++                    }
++                }
++            }
++            break;
++        }
++        case PPTP_START_CTRL_CONN_RPLY:
++        {
++            struct pptp_start_ctrl_conn *packet =
++                (struct pptp_start_ctrl_conn *) buffer;
++            dbglog("Received Start Control Connection Reply");
++            if (conn->conn_state == CONN_WAIT_CTL_REPLY) {
++                /* XXX handle collision XXX [see rfc] */
++                if (ntoh16(packet->version) != PPTP_VERSION) {
++                    if (conn->callback != NULL)
++                        conn->callback(conn, CONN_OPEN_FAIL);
++                    close_reason = PPTP_STOP_PROTOCOL;
++                    goto pptp_conn_close;
++                }
++                if (ntoh8(packet->result_code) != 1 &&
++                    /* J'ai change le if () afin que la connection ne se ferme
++                     * pas pour un "rien" :p adel@cybercable.fr -
++                     *
++                     * Don't close the connection if the result code is zero
++                     * (feature found in certain ADSL modems)
++                     */
++                        ntoh8(packet->result_code) != 0) {
++                    dbglog("Negative reply received to our Start Control "
++                            "Connection Request");
++                    ctrlp_error(packet->result_code, packet->error_code,
++                            -1, pptp_start_ctrl_conn_rply,
++                            MAX_START_CTRL_CONN_REPLY);
++                    if (conn->callback != NULL)
++                        conn->callback(conn, CONN_OPEN_FAIL);
++                    close_reason = PPTP_STOP_PROTOCOL;
++                    goto pptp_conn_close;
++                }
++                conn->conn_state = CONN_ESTABLISHED;
++                /* log session properties */
++                conn->version      = ntoh16(packet->version);
++                conn->firmware_rev = ntoh16(packet->firmware_rev);
++                memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname));
++                memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor));
++                pptp_reset_timer(); /* 60 seconds until keep-alive */
++                dbglog("Client connection established.");
++                if (conn->callback != NULL)
++                    conn->callback(conn, CONN_OPEN_DONE);
++            } /* else goto pptp_conn_close; */
++            break;
++        }
++            /* ----------- STANDARD Stop-Session MESSAGES ------------ */
++        case PPTP_STOP_CTRL_CONN_RQST:
++        {
++            /* conn_state should be CONN_ESTABLISHED, but it could be
++             * something else */
++            struct pptp_stop_ctrl_conn reply = {
++                PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY),
++                hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
++            };
++            dbglog("Received Stop Control Connection Request.");
++            if (conn->conn_state == CONN_IDLE) break;
++            if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
++                if (conn->callback != NULL)
++                    conn->callback(conn, CONN_CLOSE_RQST);
++                conn->conn_state = CONN_IDLE;
++		return -1;
++            }
++            break;
++        }
++        case PPTP_STOP_CTRL_CONN_RPLY:
++        {
++            dbglog("Received Stop Control Connection Reply.");
++            /* conn_state should be CONN_WAIT_STOP_REPLY, but it
++             * could be something else */
++            if (conn->conn_state == CONN_IDLE) break;
++            conn->conn_state = CONN_IDLE;
++	    return -1;
++        }
++            /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */
++        case PPTP_ECHO_RPLY:
++        {
++            struct pptp_echo_rply *packet =
++                (struct pptp_echo_rply *) buffer;
++            logecho( PPTP_ECHO_RPLY);
++            if ((conn->ka_state == KA_OUTSTANDING) &&
++                    (ntoh32(packet->identifier) == conn->ka_id)) {
++                conn->ka_id++;
++                conn->ka_state = KA_NONE;
++                pptp_reset_timer();
++            }
++            break;
++        }
++        case PPTP_ECHO_RQST:
++        {
++            struct pptp_echo_rqst *packet =
++                (struct pptp_echo_rqst *) buffer;
++            struct pptp_echo_rply reply = {
++                PPTP_HEADER_CTRL(PPTP_ECHO_RPLY),
++                packet->identifier, /* skip hton32(ntoh32(id)) */
++                hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
++            };
++            logecho( PPTP_ECHO_RQST);
++            pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
++            pptp_reset_timer();
++            break;
++        }
++            /* ----------- OUTGOING CALL MESSAGES ------------ */
++        case PPTP_OUT_CALL_RQST:
++        {
++            struct pptp_out_call_rqst *packet =
++                (struct pptp_out_call_rqst *)buffer;
++            struct pptp_out_call_rply reply = {
++                PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
++                0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0,
++                hton32(PPTP_CONNECT_SPEED),
++                hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0
++            };
++            dbglog("Received Outgoing Call Request.");
++            /* XXX PAC: eventually this should make an outgoing call. XXX */
++            reply.result_code = hton8(7); /* outgoing calls verboten */
++            pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
++            break;
++        }
++        case PPTP_OUT_CALL_RPLY:
++        {
++            struct pptp_out_call_rply *packet =
++                (struct pptp_out_call_rply *)buffer;
++            PPTP_CALL * call;
++            u_int16_t callid = ntoh16(packet->call_id_peer);
++            dbglog("Received Outgoing Call Reply.");
++            if (!vector_search(conn->call, (int) callid, &call)) {
++                dbglog("PPTP_OUT_CALL_RPLY received for non-existant call: "
++                        "peer call ID (us)  %d call ID (them) %d.",
++                        callid, ntoh16(packet->call_id));
++                break;
++            }
++            if (call->call_type != PPTP_CALL_PNS) {
++                dbglog("Ack!  How did this call_type get here?"); /* XXX? */
++                break;
++            }
++            if (call->state.pns != PNS_WAIT_REPLY) {
++                warn("Unexpected(?) Outgoing Call Reply will be ignored.");
++                break;
++            }
++            /* check for errors */
++            if (packet->result_code != 1) {
++                /* An error.  Log it verbosely. */
++                dbglog("Our outgoing call request [callid %d] has not been "
++                        "accepted.", (int) callid);
++                ctrlp_error(packet->result_code, packet->error_code,
++                        packet->cause_code, pptp_out_call_reply_result,
++                        MAX_OUT_CALL_REPLY_RESULT);
++                call->state.pns = PNS_IDLE;
++                if (call->callback != NULL)
++                    call->callback(conn, call, CALL_OPEN_FAIL);
++                pptp_call_destroy(conn, call);
++            } else {
++                /* connection established */
++                call->state.pns = PNS_ESTABLISHED;
++                call->peer_call_id = ntoh16(packet->call_id);
++                call->speed        = ntoh32(packet->speed);
++                pptp_reset_timer();
++                /* call pptp_set_link. unless the user specified a quirk
++                   and this quirk has a set_link hook, this is a noop */
++                pptp_set_link(conn, call->peer_call_id);
++                if (call->callback != NULL)
++                    call->callback(conn, call, CALL_OPEN_DONE);
++                dbglog("Outgoing call established (call ID %u, peer's "
++                        "call ID %u).\n", call->call_id, call->peer_call_id);
++            }
++            break;
++        }
++            /* ----------- INCOMING CALL MESSAGES ------------ */
++            /* XXX write me XXX */
++            /* ----------- CALL CONTROL MESSAGES ------------ */
++        case PPTP_CALL_CLEAR_RQST:
++        {
++            struct pptp_call_clear_rqst *packet =
++                (struct pptp_call_clear_rqst *)buffer;
++            struct pptp_call_clear_ntfy reply = {
++                PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id,
++                1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0}
++            };
++            dbglog("Received Call Clear Request.");
++            if (vector_contains(conn->call, ntoh16(packet->call_id))) {
++                PPTP_CALL * call;
++                vector_search(conn->call, ntoh16(packet->call_id), &call);
++                if (call->callback != NULL)
++                    call->callback(conn, call, CALL_CLOSE_RQST);
++                pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
++                pptp_call_destroy(conn, call);
++                dbglog("Call closed (RQST) (call id %d)", (int) call->call_id);
++            }
++            break;
++        }
++        case PPTP_CALL_CLEAR_NTFY:
++        {
++            struct pptp_call_clear_ntfy *packet =
++                (struct pptp_call_clear_ntfy *)buffer;
++            dbglog("Call disconnect notification received (call id %d)",
++                    ntoh16(packet->call_id));
++            if (vector_contains(conn->call, ntoh16(packet->call_id))) {
++                PPTP_CALL * call;
++                ctrlp_error(packet->result_code, packet->error_code,
++                        packet->cause_code, pptp_call_disc_ntfy,
++                        MAX_CALL_DISC_NTFY);
++                vector_search(conn->call, ntoh16(packet->call_id), &call);
++                pptp_call_destroy(conn, call);
++            }
++            /* XXX we could log call stats here XXX */
++            /* XXX not all servers send this XXX */
++            break;
++        }
++        case PPTP_SET_LINK_INFO:
++        {
++            /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */
++            /* this is really dealt with in the HDLC deencapsulation, anyway. */
++            struct pptp_set_link_info *packet =
++                (struct pptp_set_link_info *)buffer;
++            /* log it. */
++            dbglog("PPTP_SET_LINK_INFO received from peer_callid %u",
++                    (unsigned int) ntoh16(packet->call_id_peer));
++            dbglog("  send_accm is %08lX, recv_accm is %08lX",
++                    (unsigned long) ntoh32(packet->send_accm),
++                    (unsigned long) ntoh32(packet->recv_accm));
++            if (!(ntoh32(packet->send_accm) == 0 &&
++                    ntoh32(packet->recv_accm) == 0))
++                warn("Non-zero Async Control Character Maps are not supported!");
++            break;
++        }
++        default:
++            dbglog("Unrecognized Packet %d received.",
++                    (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type));
++            /* goto pptp_conn_close; */
++            break;
++    }
++    return 0;
++pptp_conn_close:
++    warn("pptp_conn_close(%d)", (int) close_reason);
++    pptp_conn_close(conn, close_reason);
++    return 0;
++}
++
++/*** pptp_set_link **************************************************************/
++void pptp_set_link(PPTP_CONN* conn, int peer_call_id)
++{
++    int idx, rc;
++    /* if we need to send a set_link packet because of buggy
++       hardware or pptp server, do it now */
++    if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) {
++        struct pptp_set_link_info packet;
++        if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id)))
++            warn("calling the set_link hook failed (%d)", rc);
++        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
++            pptp_reset_timer();
++        }
++    }
++}
++
++/*** Get info from call structure *********************************************/
++/* NOTE: The peer_call_id is undefined until we get a server response. */
++void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
++		       u_int16_t * call_id, u_int16_t * peer_call_id)
++{
++    assert(conn != NULL); assert(call != NULL);
++    *call_id = call->call_id;
++    *peer_call_id = call->peer_call_id;
++}
++
++/*** pptp_call_closure_put ****************************************************/
++void   pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl)
++{
++    assert(conn != NULL); assert(call != NULL);
++    call->closure = cl;
++}
++
++/*** pptp_call_closure_get ****************************************************/
++void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call)
++{
++    assert(conn != NULL); assert(call != NULL);
++    return call->closure;
++}
++
++/*** pptp_conn_closure_put ****************************************************/
++void   pptp_conn_closure_put(PPTP_CONN * conn, void *cl)
++{
++    assert(conn != NULL);
++    conn->closure = cl;
++}
++
++/*** pptp_conn_closure_get ****************************************************/
++void * pptp_conn_closure_get(PPTP_CONN * conn)
++{
++    assert(conn != NULL);
++    return conn->closure;
++}
++
++/*** Reset keep-alive timer ***************************************************/
++static void pptp_reset_timer(void)
++{
++    const struct itimerval tv = { {  0, 0 },   /* stop on time-out */
++        { idle_wait, 0 } };
++    if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL);
++}
++
++
++/*** Handle keep-alive timer **************************************************/
++static void pptp_handle_timer()
++{
++    int i;
++    /* "Keep Alives and Timers, 1": check connection state */
++    if (global.conn->conn_state != CONN_ESTABLISHED) {
++        if (global.conn->conn_state == CONN_WAIT_STOP_REPLY)
++            /* hard close. */
++            pptp_conn_destroy(global.conn);
++        else /* soft close */
++            pptp_conn_close(global.conn, PPTP_STOP_NONE);
++    }
++    /* "Keep Alives and Timers, 2": check echo status */
++    if (global.conn->ka_state == KA_OUTSTANDING) {
++        /* no response to keep-alive */
++        info("closing control connection due to missing echo reply");
++	pptp_conn_close(global.conn, PPTP_STOP_NONE);
++    } else { /* ka_state == NONE */ /* send keep-alive */
++        struct pptp_echo_rqst rqst = {
++            PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) };
++        pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst));
++        global.conn->ka_state = KA_OUTSTANDING;
++    }
++    /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */
++    for (i = 0; i < vector_size(global.conn->call); i++) {
++        PPTP_CALL * call = vector_get_Nth(global.conn->call, i);
++        if (call->call_type == PPTP_CALL_PNS) {
++            if (call->state.pns == PNS_WAIT_REPLY) {
++                /* send close request */
++                pptp_call_close(global.conn, call);
++                assert(call->state.pns == PNS_WAIT_DISCONNECT);
++            } else if (call->state.pns == PNS_WAIT_DISCONNECT) {
++                /* hard-close the call */
++                pptp_call_destroy(global.conn, call);
++            }
++        } else if (call->call_type == PPTP_CALL_PAC) {
++            if (call->state.pac == PAC_WAIT_REPLY) {
++                /* XXX FIXME -- drop the PAC connection XXX */
++            } else if (call->state.pac == PAC_WAIT_CS_ANS) {
++                /* XXX FIXME -- drop the PAC connection XXX */
++            }
++        }
++    }
++    pptp_reset_timer();
++}
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_ctrl.h
+@@ -0,0 +1,57 @@
++/* pptp_ctrl.h ... handle PPTP control connection.
++ *                 C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: pptp_ctrl.h,v 1.5 2004/11/09 01:42:32 quozl Exp $
++ */
++
++#ifndef INC_PPTP_CTRL_H
++#define INC_PPTP_CTRL_H
++#include <sys/types.h>
++
++typedef struct PPTP_CONN PPTP_CONN;
++typedef struct PPTP_CALL PPTP_CALL;
++
++enum call_state { CALL_OPEN_RQST,  CALL_OPEN_DONE, CALL_OPEN_FAIL,
++		  CALL_CLOSE_RQST, CALL_CLOSE_DONE };
++enum conn_state { CONN_OPEN_RQST,  CONN_OPEN_DONE, CONN_OPEN_FAIL,
++		  CONN_CLOSE_RQST, CONN_CLOSE_DONE };
++
++typedef void (*pptp_call_cb)(PPTP_CONN*, PPTP_CALL*, enum call_state);
++typedef void (*pptp_conn_cb)(PPTP_CONN*, enum conn_state);
++
++/* if 'isclient' is true, then will send 'conn open' packet to other host.
++ * not necessary if this is being opened by a server process after
++ * receiving a conn_open packet from client.
++ */
++PPTP_CONN * pptp_conn_open(int inet_sock, int isclient,
++			   pptp_conn_cb callback);
++PPTP_CALL * pptp_call_open(PPTP_CONN * conn, int call_id,
++			   pptp_call_cb callback, char *phonenr,int window);
++int pptp_conn_established(PPTP_CONN * conn);
++/* soft close.  Will callback on completion. */
++void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call);
++/* hard close. */
++void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call);
++/* soft close.  Will callback on completion. */
++void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason);
++/* hard close */
++void pptp_conn_destroy(PPTP_CONN * conn);
++
++/* Add file descriptors used by pptp to fd_set. */
++void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int *max_fd);
++/* handle any pptp file descriptors set in fd_set, and clear them */
++int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set);
++
++/* Get info about connection, call */
++void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
++		       u_int16_t * call_id, u_int16_t * peer_call_id);
++/* Arbitrary user data about this call/connection.
++ * It is the caller's responsibility to free this data before calling
++ * pptp_call|conn_close()
++ */
++void * pptp_conn_closure_get(PPTP_CONN * conn);
++void   pptp_conn_closure_put(PPTP_CONN * conn, void *cl);
++void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call);
++void   pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl);
++
++#endif /* INC_PPTP_CTRL_H */
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_msg.h
+@@ -0,0 +1,303 @@
++/*  pptp.h:  packet structures and magic constants for the PPTP protocol 
++ *           C. Scott Ananian <cananian@alumni.princeton.edu>            
++ *
++ * $Id: pptp_msg.h,v 1.3 2003/02/15 10:37:21 quozl Exp $
++ */
++
++#ifndef INC_PPTP_H
++#define INC_PPTP_H
++
++/* Grab definitions of int16, int32, etc. */
++#include <sys/types.h>
++/* define "portable" htons, etc. */
++#define hton8(x)  (x)
++#define ntoh8(x)  (x)
++#define hton16(x) htons(x)
++#define ntoh16(x) ntohs(x)
++#define hton32(x) htonl(x)
++#define ntoh32(x) ntohl(x)
++
++/* PPTP magic numbers: ----------------------------------------- */
++
++#define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */
++#define PPTP_PORT  1723       /* PPTP TCP port number            */
++#define PPTP_PROTO 47         /* PPTP IP protocol number         */
++
++/* Control Connection Message Types: --------------------------- */
++
++#define PPTP_MESSAGE_CONTROL		1
++#define PPTP_MESSAGE_MANAGE		2
++
++/* Control Message Types: -------------------------------------- */
++
++/* (Control Connection Management) */
++#define PPTP_START_CTRL_CONN_RQST	1
++#define PPTP_START_CTRL_CONN_RPLY	2
++#define PPTP_STOP_CTRL_CONN_RQST	3
++#define PPTP_STOP_CTRL_CONN_RPLY	4
++#define PPTP_ECHO_RQST			5
++#define PPTP_ECHO_RPLY			6
++
++/* (Call Management) */
++#define PPTP_OUT_CALL_RQST		7
++#define PPTP_OUT_CALL_RPLY		8
++#define PPTP_IN_CALL_RQST		9
++#define PPTP_IN_CALL_RPLY		10
++#define PPTP_IN_CALL_CONNECT		11
++#define PPTP_CALL_CLEAR_RQST		12
++#define PPTP_CALL_CLEAR_NTFY		13
++
++/* (Error Reporting) */
++#define PPTP_WAN_ERR_NTFY		14
++
++/* (PPP Session Control) */
++#define PPTP_SET_LINK_INFO		15
++
++/* PPTP version information: --------------------------------------*/
++#define PPTP_VERSION_STRING	"1.00"
++#define PPTP_VERSION		0x100
++#define PPTP_FIRMWARE_STRING	"0.01"
++#define PPTP_FIRMWARE_VERSION	0x001
++
++/* PPTP capabilities: ---------------------------------------------*/
++
++/* (Framing capabilities for msg sender) */
++#define PPTP_FRAME_ASYNC	1
++#define PPTP_FRAME_SYNC		2
++#define PPTP_FRAME_ANY          3
++
++/* (Bearer capabilities for msg sender) */
++#define PPTP_BEARER_ANALOG	1
++#define PPTP_BEARER_DIGITAL 	2
++#define PPTP_BEARER_ANY		3
++
++#define PPTP_RESULT_GENERAL_ERROR 2
++
++/* (Reasons to close a connection) */
++#define PPTP_STOP_NONE		  1 /* no good reason                        */
++#define PPTP_STOP_PROTOCOL	  2 /* can't support peer's protocol version */
++#define PPTP_STOP_LOCAL_SHUTDOWN  3 /* requester is being shut down          */
++
++/* PPTP datagram structures (all data in network byte order): ----------*/
++
++struct pptp_header {
++  u_int16_t length;	  /* message length in octets, including header */
++  u_int16_t pptp_type;	  /* PPTP message type. 1 for control message.  */
++  u_int32_t magic;	  /* this should be PPTP_MAGIC.                 */
++  u_int16_t ctrl_type;	  /* Control message type (0-15)                */
++  u_int16_t reserved0;	  /* reserved.  MUST BE ZERO.                   */
++};
++
++struct pptp_start_ctrl_conn { /* for control message types 1 and 2 */
++  struct pptp_header header;
++
++  u_int16_t version;      /* PPTP protocol version.  = PPTP_VERSION     */
++  u_int8_t  result_code;  /* these two fields should be zero on rqst msg*/
++  u_int8_t  error_code;   /* 0 unless result_code==2 (General Error)    */
++  u_int32_t framing_cap;  /* Framing capabilities                       */
++  u_int32_t bearer_cap;   /* Bearer Capabilities                        */
++  u_int16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */
++  u_int16_t firmware_rev; /* Firmware or Software Revision              */
++  u_int8_t  hostname[64]; /* Host Name (64 octets, zero terminated)     */
++  u_int8_t  vendor[64];   /* Vendor string (64 octets, zero term.)      */
++  /* MS says that end of hostname/vendor fields should be filled with   */
++  /* octets of value 0, but Win95 PPTP driver doesn't do this.          */
++};
++
++struct pptp_stop_ctrl_conn { /* for control message types 3 and 4 */
++  struct pptp_header header;
++
++  u_int8_t reason_result; /* reason for rqst, result for rply          */
++  u_int8_t error_code;	  /* MUST be 0, unless rply result==2 (general err)*/
++  u_int16_t reserved1;    /* MUST be 0                                */
++};
++
++struct pptp_echo_rqst { /* for control message type 5 */
++  struct pptp_header header;
++  u_int32_t identifier;   /* arbitrary value set by sender which is used */
++                          /* to match up reply and request               */
++};
++
++struct pptp_echo_rply { /* for control message type 6 */
++  struct pptp_header header;
++  u_int32_t identifier;	  /* should correspond to id of rqst             */
++  u_int8_t result_code;
++  u_int8_t error_code;    /* =0, unless result_code==2 (general error)   */
++  u_int16_t reserved1;    /* MUST BE ZERO                                */
++};
++
++struct pptp_out_call_rqst { /* for control message type 7 */
++  struct pptp_header header;
++  u_int16_t call_id;	  /* Call ID (unique id used to multiplex data)  */
++  u_int16_t call_sernum;  /* Call Serial Number (used for logging)       */
++  u_int32_t bps_min;      /* Minimum BPS (lowest acceptable line speed)  */
++  u_int32_t bps_max;	  /* Maximum BPS (highest acceptable line speed) */
++  u_int32_t bearer;	  /* Bearer type                                 */
++  u_int32_t framing;      /* Framing type                                */
++  u_int16_t recv_size;	  /* Recv. Window Size (no. of buffered packets) */
++  u_int16_t delay;	  /* Packet Processing Delay (in 1/10 sec)       */
++  u_int16_t phone_len;	  /* Phone Number Length (num. of valid digits)  */
++  u_int16_t reserved1;    /* MUST BE ZERO				 */
++  u_int8_t  phone_num[64]; /* Phone Number (64 octets, null term.)       */
++  u_int8_t subaddress[64]; /* Subaddress (64 octets, null term.)         */
++};
++
++struct pptp_out_call_rply { /* for control message type 8 */
++  struct pptp_header header;
++  u_int16_t call_id;      /* Call ID (used to multiplex data over tunnel)*/
++  u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
++  u_int8_t  result_code;  /* Result Code (1 is no errors)                */
++  u_int8_t  error_code;   /* Error Code (=0 unless result_code==2)       */
++  u_int16_t cause_code;   /* Cause Code (addt'l failure information)     */
++  u_int32_t speed;        /* Connect Speed (in BPS)                      */
++  u_int16_t recv_size;    /* Recv. Window Size (no. of buffered packets) */
++  u_int16_t delay;	  /* Packet Processing Delay (in 1/10 sec)       */
++  u_int32_t channel;      /* Physical Channel ID (for logging)           */
++};
++
++struct pptp_in_call_rqst { /* for control message type 9 */
++  struct pptp_header header;
++  u_int16_t call_id;	  /* Call ID (unique id used to multiplex data)  */
++  u_int16_t call_sernum;  /* Call Serial Number (used for logging)       */
++  u_int32_t bearer;	  /* Bearer type                                 */
++  u_int32_t channel;      /* Physical Channel ID (for logging)           */
++  u_int16_t dialed_len;   /* Dialed Number Length (# of valid digits)    */
++  u_int16_t dialing_len;  /* Dialing Number Length (# of valid digits)   */
++  u_int8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.)      */
++  u_int8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.)    */
++  u_int8_t subaddress[64];  /* Subaddress (64 octets, zero term.)        */
++};
++
++struct pptp_in_call_rply { /* for control message type 10 */
++  struct pptp_header header;
++  u_int16_t call_id;      /* Call ID (used to multiplex data over tunnel)*/
++  u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
++  u_int8_t  result_code;  /* Result Code (1 is no errors)                */
++  u_int8_t  error_code;   /* Error Code (=0 unless result_code==2)       */
++  u_int16_t recv_size;    /* Recv. Window Size (no. of buffered packets) */
++  u_int16_t delay;	  /* Packet Processing Delay (in 1/10 sec)       */
++  u_int16_t reserved1;    /* MUST BE ZERO                                */
++};
++
++struct pptp_in_call_connect { /* for control message type 11 */
++  struct pptp_header header;
++  u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
++  u_int16_t reserved1;    /* MUST BE ZERO                                */
++  u_int32_t speed;        /* Connect Speed (in BPS)                      */
++  u_int16_t recv_size;    /* Recv. Window Size (no. of buffered packets) */
++  u_int16_t delay;	  /* Packet Processing Delay (in 1/10 sec)       */
++  u_int32_t framing;      /* Framing type                                */
++};
++
++struct pptp_call_clear_rqst { /* for control message type 12 */
++  struct pptp_header header;
++  u_int16_t call_id;      /* Call ID (used to multiplex data over tunnel)*/
++  u_int16_t reserved1;    /* MUST BE ZERO                                */
++};
++
++struct pptp_call_clear_ntfy { /* for control message type 13 */
++  struct pptp_header header;
++  u_int16_t call_id;      /* Call ID (used to multiplex data over tunnel)*/
++  u_int8_t  result_code;  /* Result Code                                 */
++  u_int8_t  error_code;   /* Error Code (=0 unless result_code==2)       */
++  u_int16_t cause_code;   /* Cause Code (for ISDN, is Q.931 cause code)  */
++  u_int16_t reserved1;    /* MUST BE ZERO                                */
++  u_int8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */
++};
++
++struct pptp_wan_err_ntfy {    /* for control message type 14 */
++  struct pptp_header header;
++  u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
++  u_int16_t reserved1;    /* MUST BE ZERO                                */
++  u_int32_t crc_errors;   /* CRC errors 				 */
++  u_int32_t frame_errors; /* Framing errors 				 */
++  u_int32_t hard_errors;  /* Hardware overruns 				 */
++  u_int32_t buff_errors;  /* Buffer overruns				 */
++  u_int32_t time_errors;  /* Time-out errors				 */
++  u_int32_t align_errors; /* Alignment errors				 */
++};
++
++struct pptp_set_link_info {   /* for control message type 15 */
++  struct pptp_header header;
++  u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */
++  u_int16_t reserved1;    /* MUST BE ZERO                                   */
++  u_int32_t send_accm;    /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/
++  u_int32_t recv_accm;    /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/
++};
++
++/* helpful #defines: -------------------------------------------- */
++#define pptp_isvalid_ctrl(header, type, length) \
++ (!( ( ntoh16(((struct pptp_header *)header)->length)    < (length)  ) ||   \
++     ( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type)    ) ||   \
++     ( ntoh32(((struct pptp_header *)header)->magic)     !=PPTP_MAGIC) ||   \
++     ( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \
++     ( ntoh16(((struct pptp_header *)header)->reserved0) !=0         ) ))
++
++#define PPTP_HEADER_CTRL(type)  \
++{ hton16(PPTP_CTRL_SIZE(type)), \
++  hton16(PPTP_MESSAGE_CONTROL), \
++  hton32(PPTP_MAGIC),           \
++  hton16(type), 0 }             
++
++#define PPTP_CTRL_SIZE(type) ( \
++(type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn):	\
++(type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn):	\
++(type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn):	\
++(type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn):	\
++(type==PPTP_ECHO_RQST           )?sizeof(struct pptp_echo_rqst):	\
++(type==PPTP_ECHO_RPLY           )?sizeof(struct pptp_echo_rply):	\
++(type==PPTP_OUT_CALL_RQST       )?sizeof(struct pptp_out_call_rqst):	\
++(type==PPTP_OUT_CALL_RPLY       )?sizeof(struct pptp_out_call_rply):	\
++(type==PPTP_IN_CALL_RQST        )?sizeof(struct pptp_in_call_rqst):	\
++(type==PPTP_IN_CALL_RPLY        )?sizeof(struct pptp_in_call_rply):	\
++(type==PPTP_IN_CALL_CONNECT     )?sizeof(struct pptp_in_call_connect):	\
++(type==PPTP_CALL_CLEAR_RQST     )?sizeof(struct pptp_call_clear_rqst):	\
++(type==PPTP_CALL_CLEAR_NTFY     )?sizeof(struct pptp_call_clear_ntfy):	\
++(type==PPTP_WAN_ERR_NTFY        )?sizeof(struct pptp_wan_err_ntfy):	\
++(type==PPTP_SET_LINK_INFO       )?sizeof(struct pptp_set_link_info):	\
++0)
++#define max(a,b) (((a)>(b))?(a):(b))
++#define PPTP_CTRL_SIZE_MAX (			\
++max(sizeof(struct pptp_start_ctrl_conn),	\
++max(sizeof(struct pptp_echo_rqst),		\
++max(sizeof(struct pptp_echo_rply),		\
++max(sizeof(struct pptp_out_call_rqst),		\
++max(sizeof(struct pptp_out_call_rply),		\
++max(sizeof(struct pptp_in_call_rqst),		\
++max(sizeof(struct pptp_in_call_rply),		\
++max(sizeof(struct pptp_in_call_connect),	\
++max(sizeof(struct pptp_call_clear_rqst),	\
++max(sizeof(struct pptp_call_clear_ntfy),	\
++max(sizeof(struct pptp_wan_err_ntfy),		\
++max(sizeof(struct pptp_set_link_info), 0)))))))))))))
++
++
++/* gre header structure: -------------------------------------------- */
++
++#define PPTP_GRE_PROTO  0x880B
++#define PPTP_GRE_VER    0x1
++
++#define PPTP_GRE_FLAG_C	0x80
++#define PPTP_GRE_FLAG_R	0x40
++#define PPTP_GRE_FLAG_K	0x20
++#define PPTP_GRE_FLAG_S	0x10
++#define PPTP_GRE_FLAG_A	0x80
++
++#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
++#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
++#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
++#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
++#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
++
++struct pptp_gre_header {
++  u_int8_t flags;		/* bitfield */
++  u_int8_t ver;			/* should be PPTP_GRE_VER (enhanced GRE) */
++  u_int16_t protocol;		/* should be PPTP_GRE_PROTO (ppp-encaps) */
++  u_int16_t payload_len;	/* size of ppp payload, not inc. gre header */
++  u_int16_t call_id;		/* peer's call_id for this session */
++  u_int32_t seq;		/* sequence number.  Present if S==1 */
++  u_int32_t ack;		/* seq number of highest packet recieved by */
++  				/*  sender in this session */
++};
++
++#endif /* INC_PPTP_H */
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_options.h
+@@ -0,0 +1,41 @@
++/* pptp_options.h ...... various constants used in the PPTP protocol.
++ *                       #define STANDARD to emulate NT 4.0 exactly.
++ *                       C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: pptp_options.h,v 1.3 2004/11/09 01:42:32 quozl Exp $
++ */
++
++#ifndef INC_PPTP_OPTIONS_H
++#define INC_PPTP_OPTIONS_H
++
++#undef  PPTP_FIRMWARE_STRING
++#undef  PPTP_FIRMWARE_VERSION
++#define PPTP_BUF_MAX 65536
++#define PPTP_TIMEOUT 60 /* seconds */
++extern int idle_wait;
++extern int max_echo_wait;
++#define PPTP_CONNECT_SPEED 1000000000
++#define PPTP_WINDOW 3
++#define PPTP_DELAY  0
++#define PPTP_BPS_MIN 2400
++#define PPTP_BPS_MAX 1000000000
++
++#ifndef STANDARD
++#define PPTP_MAX_CHANNELS 65535
++#define PPTP_FIRMWARE_STRING "0.01"
++#define PPTP_FIRMWARE_VERSION 0x001
++#define PPTP_HOSTNAME {'l','o','c','a','l',0}
++#define PPTP_VENDOR   {'c','a','n','a','n','i','a','n',0}
++#define PPTP_FRAME_CAP  PPTP_FRAME_ANY
++#define PPTP_BEARER_CAP PPTP_BEARER_ANY
++#else
++#define PPTP_MAX_CHANNELS 5
++#define PPTP_FIRMWARE_STRING "0.01"
++#define PPTP_FIRMWARE_VERSION 0
++#define PPTP_HOSTNAME {'l','o','c','a','l',0}
++#define PPTP_VENDOR   {'N','T',0}
++#define PPTP_FRAME_CAP  2
++#define PPTP_BEARER_CAP 1
++#endif
++
++#endif /* INC_PPTP_OPTIONS_H */
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_quirks.c
+@@ -0,0 +1,54 @@
++/* pptp_quirks.c ...... various options to fix quirks found in buggy adsl modems
++ *                      mulix <mulix@actcom.co.il>
++ *
++ * $Id: pptp_quirks.c,v 1.2 2001/11/23 03:42:51 quozl Exp $
++ */
++
++#include <string.h>
++#include "orckit_quirks.h"
++#include "pptp_quirks.h"
++
++static int quirk_index = -1;
++
++struct pptp_fixup pptp_fixups[] = {
++    {BEZEQ_ISRAEL, ORCKIT, ORCKIT_ATUR3,
++     orckit_atur3_build_hook,
++     orckit_atur3_start_ctrl_conn_hook,
++     orckit_atur3_set_link_hook}
++};
++
++static int fixups_sz = sizeof(pptp_fixups)/sizeof(pptp_fixups[0]);
++
++/* return 0 on success, non 0 otherwise */
++int set_quirk_index(int index)
++{
++    if (index >= 0 && index < fixups_sz) {
++	quirk_index = index;
++	return 0;
++    }
++
++    return -1;
++}
++
++int get_quirk_index()
++{
++    return quirk_index;
++}
++
++/* return the index for this isp in the quirks table, -1 if not found */
++int find_quirk(const char* isp_name)
++{
++    int i = 0;
++    if (isp_name) {
++	while (i < fixups_sz && pptp_fixups[i].isp) {
++	    if (!strcmp(pptp_fixups[i].isp, isp_name)) {
++		return i;
++	    }
++	    ++i;
++	}
++    }
++
++    return -1;
++}
++
++
+--- /dev/null
++++ b/pppd/plugins/pptp/pptp_quirks.h
+@@ -0,0 +1,59 @@
++/* pptp_quirks.h ...... various options to fix quirks found in buggy adsl modems
++ *                      mulix <mulix@actcom.co.il>
++ *
++ * $Id: pptp_quirks.h,v 1.1 2001/11/20 06:30:10 quozl Exp $
++ */
++
++#ifndef INC_PPTP_QUIRKS_H
++#define INC_PPTP_QUIRKS_H
++
++/* isp defs - correspond to slots in the fixups table */
++#define BEZEQ_ISRAEL "BEZEQ_ISRAEL"
++
++/* vendor defs */
++
++#define ORCKIT 1
++#define ALCATEL 2
++
++/* device defs */
++
++#define ORCKIT_ATUR2 1
++#define ORCKIT_ATUR3 2
++
++#include "pptp_msg.h"
++#include "pptp_ctrl.h"
++
++struct pptp_fixup {
++    const char* isp;    /* which isp? e.g. Bezeq in Israel */
++    int vendor; /* which vendor? e.g. Orckit */
++    int device; /* which device? e.g. Orckit Atur3 */
++
++    /* use this hook to build your own out call request packet */
++    int (*out_call_rqst_hook)(struct pptp_out_call_rqst* packet);
++
++    /* use this hook to build your own start control connection packet */
++    /* note that this hook is called from two different places, depending
++       on whether this is a request or reply */
++    int (*start_ctrl_conn)(struct pptp_start_ctrl_conn* packet);
++
++    /* use this hook if you need to send a 'set_link' packet once
++       the connection is established */
++    int (*set_link_hook)(struct pptp_set_link_info* packet,
++			 int peer_call_id);
++};
++
++extern struct pptp_fixup pptp_fixups[];
++
++/* find the index for this isp in the quirks table */
++/* return the index on success, -1 if not found */
++int find_quirk(const char* isp_name);
++
++/* set the global quirk index. return 0 on success, non 0 otherwise */
++int set_quirk_index(int index);
++
++/* get the global quirk index. return the index on success,
++   -1 if no quirk is defined */
++int get_quirk_index();
++
++
++#endif /* INC_PPTP_QUIRKS_H */
+--- /dev/null
++++ b/pppd/plugins/pptp/util.c
+@@ -0,0 +1,109 @@
++/* util.c ....... error message utilities.
++ *                C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: util.c,v 1.11 2005/08/22 00:49:48 quozl Exp $
++ */
++
++#include <stdio.h>
++#include <stdarg.h>
++#include <syslog.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include "util.h"
++
++#define MAKE_STRING(label) 				\
++va_list ap;						\
++char buf[256], string[256];				\
++va_start(ap, format);					\
++vsnprintf(buf, sizeof(buf), format, ap);		\
++snprintf(string, sizeof(string), "%s %s[%s:%s:%d]: %s",	\
++	 log_string, label, func, file, line, buf);	\
++va_end(ap)
++
++/*** connect a file to a file descriptor **************************************/
++int file2fd(const char *path, const char *mode, int fd)
++{
++    int ok = 0;
++    FILE *file = NULL;
++    file = fopen(path, mode);
++    if (file != NULL && dup2(fileno(file), fd) != -1)
++        ok = 1;
++    if (file) fclose(file);
++    return ok;
++}
++
++/* signal to pipe delivery implementation */
++#include <unistd.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <string.h>
++
++/* pipe private to process */
++static int sigpipe[2];
++
++/* create a signal pipe, returns 0 for success, -1 with errno for failure */
++int sigpipe_create()
++{
++  int rc;
++  
++  rc = pipe(sigpipe);
++  if (rc < 0) return rc;
++  
++  fcntl(sigpipe[0], F_SETFD, FD_CLOEXEC);
++  fcntl(sigpipe[1], F_SETFD, FD_CLOEXEC);
++  
++#ifdef O_NONBLOCK
++#define FLAG_TO_SET O_NONBLOCK
++#else
++#ifdef SYSV
++#define FLAG_TO_SET O_NDELAY
++#else /* BSD */
++#define FLAG_TO_SET FNDELAY
++#endif
++#endif
++  
++  rc = fcntl(sigpipe[1], F_GETFL);
++  if (rc != -1)
++    rc = fcntl(sigpipe[1], F_SETFL, rc | FLAG_TO_SET);
++  if (rc < 0) return rc;
++  return 0;
++#undef FLAG_TO_SET
++}
++
++/* generic handler for signals, writes signal number to pipe */
++void sigpipe_handler(int signum)
++{
++  write(sigpipe[1], &signum, sizeof(signum));
++  signal(signum, sigpipe_handler);
++}
++
++/* assign a signal number to the pipe */
++void sigpipe_assign(int signum)
++{
++  struct sigaction sa;
++
++  memset(&sa, 0, sizeof(sa));
++  sa.sa_handler = sigpipe_handler;
++  sigaction(signum, &sa, NULL);
++}
++
++/* return the signal pipe read file descriptor for select(2) */
++int sigpipe_fd()
++{
++  return sigpipe[0];
++}
++
++/* read and return the pending signal from the pipe */
++int sigpipe_read()
++{
++  int signum;
++  read(sigpipe[0], &signum, sizeof(signum));
++  return signum;
++}
++
++void sigpipe_close()
++{
++  close(sigpipe[0]);
++  close(sigpipe[1]);
++}
++
+--- /dev/null
++++ b/pppd/plugins/pptp/util.h
+@@ -0,0 +1,31 @@
++/* util.h ....... error message utilities.
++ *                C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: util.h,v 1.6 2005/03/10 01:18:20 quozl Exp $
++ */
++
++#ifndef INC_UTIL_H
++#define INC_UTIL_H
++
++int file2fd(const char *path, const char *mode, int fd);
++
++/* signal to pipe delivery implementation */
++
++/* create a signal pipe, returns 0 for success, -1 with errno for failure */
++int sigpipe_create();
++
++/* generic handler for signals, writes signal number to pipe */
++void sigpipe_handler(int signum);
++
++/* assign a signal number to the pipe */
++void sigpipe_assign(int signum);
++
++/* return the signal pipe read file descriptor for select(2) */
++int sigpipe_fd();
++
++/* read and return the pending signal from the pipe */
++int sigpipe_read();
++
++void sigpipe_close();
++
++#endif /* INC_UTIL_H */
+--- /dev/null
++++ b/pppd/plugins/pptp/vector.c
+@@ -0,0 +1,209 @@
++/* vector.c ..... store a vector of PPTP_CALL information and search it
++ *                efficiently.
++ *                C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: vector.c,v 1.3 2003/06/17 10:12:55 reink Exp $
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <assert.h>
++#include "pptp_ctrl.h"
++#include "vector.h"
++/* #define VECTOR_DEBUG */
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++struct vector_item {
++    int key;
++    PPTP_CALL *call;
++};
++
++struct vector_struct {
++    struct vector_item *item;
++    int size;
++    int alloc;
++#ifdef VECTOR_DEBUG
++    int key_max;
++#endif
++};
++
++static struct vector_item *binary_search(VECTOR *v, int key);
++
++/*** vector_create ************************************************************/
++VECTOR *vector_create()
++{
++    const int INITIAL_SIZE = 4;
++
++    VECTOR *v = malloc(sizeof(*v));
++    if (v == NULL) return v;
++
++    v->size = 0;
++    v->alloc = INITIAL_SIZE;
++    v->item = malloc(sizeof(*(v->item)) * (v->alloc));
++#ifdef VECTOR_DEBUG
++    v->key_max = -1;
++#endif
++    if (v->item == NULL) { free(v); return NULL; }
++    else return v;
++}
++
++/*** vector_destroy ***********************************************************/
++void vector_destroy(VECTOR *v)
++{
++    free(v->item);
++#ifdef VECTOR_DEBUG
++    v->item = NULL;
++#endif
++    free(v);
++}
++
++/*** vector_size **************************************************************/
++int vector_size(VECTOR *v)
++{
++    assert(v != NULL);
++    return v->size;
++}
++
++/*** vector_insert*************************************************************
++ * nice thing about file descriptors is that we are assured by POSIX 
++ * that they are monotonically increasing.
++ */
++int vector_insert(VECTOR *v, int key, PPTP_CALL * call)
++{
++    int i;
++    assert(v != NULL && call != NULL);
++    assert(!vector_contains(v, key));
++#ifdef VECTOR_DEBUG
++    assert(v->key_max < key);
++#endif
++    if (!(v->size < v->alloc)) {
++        void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc);
++        if (tmp != NULL) {
++            v->alloc *= 2;
++            v->item = tmp;
++        } else return FALSE; /* failed to alloc memory. */
++    }
++    assert(v->size < v->alloc);
++    /* for safety, we make this work in the general case;
++     * but this is optimized for adding call to the end of the vector.
++     */
++    for(i = v->size - 1; i >= 0; i--)
++        if (v->item[i].key < key)
++            break;
++    /* insert after item i */
++    memmove(&v->item[i + 2], &v->item[i + 1],
++            (v->size - i - 1) * sizeof(*(v->item)));
++    v->item[i + 1].key  = key;
++    v->item[i + 1].call = call;
++    v->size++;
++#ifdef VECTOR_DEBUG
++    if (v->key_max < key) /* ie, always. */
++        v->key_max = key;
++#endif
++    return TRUE;
++}
++
++/*** vector_remove ************************************************************/
++int  vector_remove(VECTOR *v, int key)
++{
++    struct vector_item *tmp;
++    assert(v != NULL);
++    if ((tmp =binary_search(v,key)) == NULL) return FALSE;
++    assert(tmp >= v->item && tmp < v->item + v->size);
++    memmove(tmp, tmp + 1, (v->size - (v->item - tmp) - 1) * sizeof(*(v->item)));
++    v->size--;
++    return TRUE;
++}
++
++/*** vector_search ************************************************************/
++int  vector_search(VECTOR *v, int key, PPTP_CALL **call)
++{
++    struct vector_item *tmp;
++    assert(v != NULL);
++    tmp = binary_search(v, key);
++    if (tmp ==NULL) return FALSE;
++    *call = tmp->call;
++    return TRUE;
++}
++
++/*** vector_contains **********************************************************/
++int  vector_contains(VECTOR *v, int key)
++{
++    assert(v != NULL);
++    return (binary_search(v, key) != NULL);
++}
++
++/*** vector_item **************************************************************/
++static struct vector_item *binary_search(VECTOR *v, int key)
++{
++    int l,r,x;
++    l = 0;
++    r = v->size - 1;
++    while (r >= l) {
++        x = (l + r)/2;
++        if (key <  v->item[x].key) r = x - 1; else l = x + 1;
++        if (key == v->item[x].key) return &(v->item[x]);
++    }
++    return NULL;
++}
++
++/*** vector_scan ***************************************************************
++ * Hmm.  Let's be fancy and use a binary search for the first
++ * unused key, taking advantage of the list is stored sorted; ie
++ * we can look at pointers and keys at two different locations, 
++ * and if (ptr1 - ptr2) = (key1 - key2) then all the slots
++ * between ptr1 and ptr2 are filled.  Note that ptr1-ptr2 should
++ * never be greater than key1-key2 (no duplicate keys!)... we
++ * check for this.
++ */
++int vector_scan(VECTOR *v, int lo, int hi, int *key)
++{
++    int l,r,x;
++    assert(v != NULL);
++    assert(key != NULL);
++    if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; }
++    /* our array bounds */
++    l = 0;  r = v->size - 1;
++    while (r > l) {
++        /* check for a free spot right after l */
++        if (v->item[l].key + 1 < v->item[l + 1].key) { /* found it! */
++            *key = v->item[l].key + 1;
++            return TRUE;
++        }
++        /* no dice. Let's see if the free spot is before or after the midpoint */
++        x = (l + r)/2;
++        /* Okay, we have right (r), left (l) and the probe (x). */
++        assert(x - l <= v->item[x].key - v->item[l].key);
++        assert(r - x <= v->item[r].key - v->item[x].key);
++        if (x - l < v->item[x].key - v->item[l].key)
++            /* room between l and x */
++            r = x;
++        else /* no room between l and x */
++            if (r - x < v->item[r].key - v->item[x].key)
++                /* room between x and r */
++                l = x;
++            else /* no room between x and r, either */
++                break; /* game over, man. */
++    }
++    /* no room found in already allocated space.  Check to see if
++     * there's free space above allocated entries. */
++    if (v->item[v->size - 1].key < hi) {
++        *key = v->item[v->size - 1].key + 1;
++        return TRUE;
++    }
++    /* outta luck */
++    return FALSE;
++}
++
++/*** vector_get_Nth ***********************************************************/
++PPTP_CALL * vector_get_Nth(VECTOR *v, int n)
++{
++    assert(v != NULL);
++    assert(0 <= n && n < vector_size(v));
++    return v->item[n].call;
++}
+--- /dev/null
++++ b/pppd/plugins/pptp/vector.h
+@@ -0,0 +1,31 @@
++/* vector.h ..... store a vector of PPTP_CALL information and search it
++ *                efficiently.
++ *                C. Scott Ananian <cananian@alumni.princeton.edu>
++ *
++ * $Id: vector.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
++ */
++
++#ifndef INC_VECTOR_H
++#define INC_VECTOR_H
++
++#include "pptp_ctrl.h" /* for definition of PPTP_CALL */
++
++typedef struct vector_struct VECTOR;
++
++VECTOR *vector_create();
++void vector_destroy(VECTOR *v);
++
++int vector_size(VECTOR *v);
++
++/* vector_insert and vector_search return TRUE on success, FALSE on failure. */
++int  vector_insert(VECTOR *v, int key, PPTP_CALL * call);
++int  vector_remove(VECTOR *v, int key);
++int  vector_search(VECTOR *v, int key, PPTP_CALL ** call);
++/* vector_contains returns FALSE if not found, TRUE if found. */
++int  vector_contains(VECTOR *v, int key);
++/* find first unused key. Returns TRUE on success, FALSE if no. */
++int  vector_scan(VECTOR *v, int lo, int hi, int *key);
++/* get a specific PPTP_CALL ... useful only when iterating. */
++PPTP_CALL * vector_get_Nth(VECTOR *v, int n);
++
++#endif /* INC_VECTOR_H */
diff --git a/package/network/services/ppp/patches/510-pptp_compile_fix.patch b/package/network/services/ppp/patches/510-pptp_compile_fix.patch
new file mode 100644
index 0000000000..04bb620e76
--- /dev/null
+++ b/package/network/services/ppp/patches/510-pptp_compile_fix.patch
@@ -0,0 +1,11 @@
+--- a/pppd/plugins/pptp/pptp.c
++++ b/pppd/plugins/pptp/pptp.c
+@@ -48,7 +48,7 @@
+ 
+ #include "pptp_callmgr.h"
+ #include <net/if.h>
+-#include <net/ethernet.h>
++#include <linux/if_ether.h>
+ #include <linux/if_pppox.h>
+ 
+ #include <stdio.h>
diff --git a/package/network/services/ppp/patches/520-uniq.patch b/package/network/services/ppp/patches/520-uniq.patch
new file mode 100644
index 0000000000..54c0d62712
--- /dev/null
+++ b/package/network/services/ppp/patches/520-uniq.patch
@@ -0,0 +1,269 @@
+--- a/pppd/plugins/rp-pppoe/common.c
++++ b/pppd/plugins/rp-pppoe/common.c
+@@ -119,15 +119,11 @@ sendPADT(PPPoEConnection *conn, char con
+     conn->session = 0;
+ 
+     /* If we're using Host-Uniq, copy it over */
+-    if (conn->useHostUniq) {
+-	PPPoETag hostUniq;
+-	pid_t pid = getpid();
+-	hostUniq.type = htons(TAG_HOST_UNIQ);
+-	hostUniq.length = htons(sizeof(pid));
+-	memcpy(hostUniq.payload, &pid, sizeof(pid));
+-	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+-	cursor += sizeof(pid) + TAG_HDR_SIZE;
+-	plen += sizeof(pid) + TAG_HDR_SIZE;
++    if (conn->hostUniq.length) {
++	int len = ntohs(conn->hostUniq.length);
++	memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
++	cursor += len + TAG_HDR_SIZE;
++	plen += len + TAG_HDR_SIZE;
+     }
+ 
+     /* Copy error message */
+--- a/pppd/plugins/rp-pppoe/discovery.c
++++ b/pppd/plugins/rp-pppoe/discovery.c
+@@ -80,13 +80,10 @@ static void
+ parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
+ 		 void *extra)
+ {
+-    int *val = (int *) extra;
+-    if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
+-	pid_t tmp;
+-	memcpy(&tmp, data, len);
+-	if (tmp == getpid()) {
+-	    *val = 1;
+-	}
++    PPPoETag *tag = extra;
++
++    if (type == TAG_HOST_UNIQ && len == ntohs(tag->length)) {
++	tag->length = memcmp(data, tag->payload, len);
+     }
+ }
+ 
+@@ -104,16 +101,16 @@ parseForHostUniq(UINT16_t type, UINT16_t
+ static int
+ packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
+ {
+-    int forMe = 0;
++    PPPoETag hostUniq = conn->hostUniq;
+ 
+     /* If packet is not directed to our MAC address, forget it */
+     if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
+ 
+     /* If we're not using the Host-Unique tag, then accept the packet */
+-    if (!conn->useHostUniq) return 1;
++    if (!conn->hostUniq.length) return 1;
+ 
+-    parsePacket(packet, parseForHostUniq, &forMe);
+-    return forMe;
++    parsePacket(packet, parseForHostUniq, &hostUniq);
++    return (hostUniq.length == 0);
+ }
+ 
+ /**********************************************************************
+@@ -301,16 +298,12 @@ sendPADI(PPPoEConnection *conn)
+     }
+ 
+     /* If we're using Host-Uniq, copy it over */
+-    if (conn->useHostUniq) {
+-	PPPoETag hostUniq;
+-	pid_t pid = getpid();
+-	hostUniq.type = htons(TAG_HOST_UNIQ);
+-	hostUniq.length = htons(sizeof(pid));
+-	memcpy(hostUniq.payload, &pid, sizeof(pid));
+-	CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
+-	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+-	cursor += sizeof(pid) + TAG_HDR_SIZE;
+-	plen += sizeof(pid) + TAG_HDR_SIZE;
++    if (conn->hostUniq.length) {
++	int len = ntohs(conn->hostUniq.length);
++	CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
++	memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
++	cursor += len + TAG_HDR_SIZE;
++	plen += len + TAG_HDR_SIZE;
+     }
+ 
+     /* Add our maximum MTU/MRU */
+@@ -478,16 +471,12 @@ sendPADR(PPPoEConnection *conn)
+     cursor += namelen + TAG_HDR_SIZE;
+ 
+     /* If we're using Host-Uniq, copy it over */
+-    if (conn->useHostUniq) {
+-	PPPoETag hostUniq;
+-	pid_t pid = getpid();
+-	hostUniq.type = htons(TAG_HOST_UNIQ);
+-	hostUniq.length = htons(sizeof(pid));
+-	memcpy(hostUniq.payload, &pid, sizeof(pid));
+-	CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
+-	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+-	cursor += sizeof(pid) + TAG_HDR_SIZE;
+-	plen += sizeof(pid) + TAG_HDR_SIZE;
++    if (conn->hostUniq.length) {
++	int len = ntohs(conn->hostUniq.length);
++	CHECK_ROOM(cursor, packet.payload, len+TAG_HDR_SIZE);
++	memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
++	cursor += len + TAG_HDR_SIZE;
++	plen += len + TAG_HDR_SIZE;
+     }
+ 
+     /* Add our maximum MTU/MRU */
+--- a/pppd/plugins/rp-pppoe/plugin.c
++++ b/pppd/plugins/rp-pppoe/plugin.c
+@@ -65,6 +65,7 @@ static char *existingSession = NULL;
+ static int printACNames = 0;
+ static char *pppoe_reqd_mac = NULL;
+ unsigned char pppoe_reqd_mac_addr[6];
++static char *host_uniq = NULL;
+ 
+ static int PPPoEDevnameHook(char *cmd, char **argv, int doit);
+ static option_t Options[] = {
+@@ -82,6 +83,8 @@ static option_t Options[] = {
+       "Be verbose about discovered access concentrators"},
+     { "pppoe-mac", o_string, &pppoe_reqd_mac,
+       "Only connect to specified MAC address" },
++    { "host-uniq", o_string, &host_uniq,
++      "Specify custom Host-Uniq" },
+     { NULL }
+ };
+ int (*OldDevnameHook)(char *cmd, char **argv, int doit) = NULL;
+@@ -107,7 +110,6 @@ PPPOEInitDevice(void)
+     conn->ifName = devnam;
+     conn->discoverySocket = -1;
+     conn->sessionSocket = -1;
+-    conn->useHostUniq = 1;
+     conn->printACNames = printACNames;
+     conn->discoveryTimeout = PADI_TIMEOUT;
+     return 1;
+@@ -163,6 +165,9 @@ PPPOEConnectDevice(void)
+     if (lcp_wantoptions[0].mru > ifr.ifr_mtu - TOTAL_OVERHEAD)
+ 	lcp_wantoptions[0].mru = ifr.ifr_mtu - TOTAL_OVERHEAD;
+ 
++    if (host_uniq && !parseHostUniq(host_uniq, &conn->hostUniq))
++	fatal("Illegal value for host-uniq option");
++
+     conn->acName = acName;
+     conn->serviceName = pppd_pppoe_service;
+     strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+--- a/pppd/plugins/rp-pppoe/pppoe-discovery.c
++++ b/pppd/plugins/rp-pppoe/pppoe-discovery.c
+@@ -344,7 +344,7 @@ packetIsForMe(PPPoEConnection *conn, PPP
+     if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
+ 
+     /* If we're not using the Host-Unique tag, then accept the packet */
+-    if (!conn->useHostUniq) return 1;
++    if (!conn->hostUniq.length) return 1;
+ 
+     parsePacket(packet, parseForHostUniq, &forMe);
+     return forMe;
+@@ -470,16 +470,12 @@ sendPADI(PPPoEConnection *conn)
+     cursor += namelen + TAG_HDR_SIZE;
+ 
+     /* If we're using Host-Uniq, copy it over */
+-    if (conn->useHostUniq) {
+-	PPPoETag hostUniq;
+-	pid_t pid = getpid();
+-	hostUniq.type = htons(TAG_HOST_UNIQ);
+-	hostUniq.length = htons(sizeof(pid));
+-	memcpy(hostUniq.payload, &pid, sizeof(pid));
+-	CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
+-	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+-	cursor += sizeof(pid) + TAG_HDR_SIZE;
+-	plen += sizeof(pid) + TAG_HDR_SIZE;
++    if (conn->hostUniq.length) {
++	int len = ntohs(conn->hostUniq.length);
++	CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
++	memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
++	cursor += len + TAG_HDR_SIZE;
++	plen += len + TAG_HDR_SIZE;
+     }
+ 
+     packet.length = htons(plen);
+@@ -641,7 +637,7 @@ int main(int argc, char *argv[])
+ 
+     memset(conn, 0, sizeof(PPPoEConnection));
+ 
+-    while ((opt = getopt(argc, argv, "I:D:VUAS:C:h")) > 0) {
++    while ((opt = getopt(argc, argv, "I:D:VUW:AS:C:h")) > 0) {
+ 	switch(opt) {
+ 	case 'S':
+ 	    conn->serviceName = xstrdup(optarg);
+@@ -650,7 +646,23 @@ int main(int argc, char *argv[])
+ 	    conn->acName = xstrdup(optarg);
+ 	    break;
+ 	case 'U':
+-	    conn->useHostUniq = 1;
++	    if(conn->hostUniq.length) {
++		fprintf(stderr, "-U and -W are mutually exclusive\n");
++		exit(EXIT_FAILURE);
++	    }
++            char pidbuf[5];
++            snprintf(pidbuf, sizeof(pidbuf), "%04x", getpid());
++            parseHostUniq(pidbuf, &conn->hostUniq);
++	    break;
++	case 'W':
++	    if(conn->hostUniq.length) {
++		fprintf(stderr, "-U and -W are mutually exclusive\n");
++		exit(EXIT_FAILURE);
++	    }
++	    if (!parseHostUniq(optarg, &conn->hostUniq)) {
++                fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg);
++                exit(EXIT_FAILURE);
++            }
+ 	    break;
+ 	case 'D':
+ 	    conn->debugFile = fopen(optarg, "w");
+--- a/pppd/plugins/rp-pppoe/pppoe.h
++++ b/pppd/plugins/rp-pppoe/pppoe.h
+@@ -21,6 +21,8 @@
+ 
+ #include <stdio.h>		/* For FILE */
+ #include <sys/types.h>		/* For pid_t */
++#include <ctype.h>
++#include <string.h>
+ 
+ /* How do we access raw Ethernet devices? */
+ #undef USE_LINUX_PACKET
+@@ -224,7 +226,7 @@ typedef struct PPPoEConnectionStruct {
+     char *serviceName;		/* Desired service name, if any */
+     char *acName;		/* Desired AC name, if any */
+     int synchronous;		/* Use synchronous PPP */
+-    int useHostUniq;		/* Use Host-Uniq tag */
++    PPPoETag hostUniq;		/* Use Host-Uniq tag */
+     int printACNames;		/* Just print AC names */
+     FILE *debugFile;		/* Debug file for dumping packets */
+     int numPADOs;		/* Number of PADO packets received */
+@@ -280,6 +282,33 @@ void pppoe_printpkt(PPPoEPacket *packet,
+ 		    void (*printer)(void *, char *, ...), void *arg);
+ void pppoe_log_packet(const char *prefix, PPPoEPacket *packet);
+ 
++static inline int parseHostUniq(const char *uniq, PPPoETag *tag)
++{
++    int i, len = strlen(uniq);
++
++#define hex(x) \
++    (((x) <= '9') ? ((x) - '0') : \
++        (((x) <= 'F') ? ((x) - 'A' + 10) : \
++            ((x) - 'a' + 10)))
++
++    if (len % 2)
++        return 0;
++
++    for (i = 0; i < len; i += 2)
++    {
++        if (!isxdigit(uniq[i]) || !isxdigit(uniq[i+1]))
++            return 0;
++
++        tag->payload[i / 2] = (char)(16 * hex(uniq[i]) + hex(uniq[i+1]));
++    }
++
++#undef hex
++
++    tag->type = htons(TAG_HOST_UNIQ);
++    tag->length = htons(len / 2);
++    return 1;
++}
++
+ #define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0);
+ 
+ #define CHECK_ROOM(cursor, start, len) \
diff --git a/package/network/services/ppp/patches/530-pppoe_send_padt.patch b/package/network/services/ppp/patches/530-pppoe_send_padt.patch
new file mode 100644
index 0000000000..40fa420216
--- /dev/null
+++ b/package/network/services/ppp/patches/530-pppoe_send_padt.patch
@@ -0,0 +1,11 @@
+--- a/pppd/plugins/rp-pppoe/plugin.c
++++ b/pppd/plugins/rp-pppoe/plugin.c
+@@ -275,7 +275,7 @@ PPPOEDisconnectDevice(void)
+ 		sizeof(struct sockaddr_pppox)) < 0)
+ 	error("Failed to disconnect PPPoE socket: %d %m", errno);
+     close(conn->sessionSocket);
+-    /* don't send PADT?? */
++    sendPADT(conn, NULL);
+     if (conn->discoverySocket >= 0)
+ 	close(conn->discoverySocket);
+ }
diff --git a/package/network/services/ppp/patches/531-pppoe_no_disconnect_warning.patch b/package/network/services/ppp/patches/531-pppoe_no_disconnect_warning.patch
new file mode 100644
index 0000000000..799e961cd7
--- /dev/null
+++ b/package/network/services/ppp/patches/531-pppoe_no_disconnect_warning.patch
@@ -0,0 +1,14 @@
+--- a/pppd/plugins/rp-pppoe/plugin.c
++++ b/pppd/plugins/rp-pppoe/plugin.c
+@@ -271,9 +271,8 @@ PPPOEDisconnectDevice(void)
+     sp.sa_addr.pppoe.sid = 0;
+     memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
+     memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+-    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+-		sizeof(struct sockaddr_pppox)) < 0)
+-	error("Failed to disconnect PPPoE socket: %d %m", errno);
++    connect(conn->sessionSocket, (struct sockaddr *) &sp,
++	    sizeof(struct sockaddr_pppox));
+     close(conn->sessionSocket);
+     sendPADT(conn, NULL);
+     if (conn->discoverySocket >= 0)
diff --git a/package/network/services/ppp/patches/540-save-pppol2tp_fd_str.patch b/package/network/services/ppp/patches/540-save-pppol2tp_fd_str.patch
new file mode 100644
index 0000000000..7dd2ad844c
--- /dev/null
+++ b/package/network/services/ppp/patches/540-save-pppol2tp_fd_str.patch
@@ -0,0 +1,13 @@
+--- a/pppd/plugins/pppol2tp/pppol2tp.c
++++ b/pppd/plugins/pppol2tp/pppol2tp.c
+@@ -148,6 +148,10 @@ static int setdevname_pppol2tp(char **ar
+ 		fatal("PPPoL2TP kernel driver not installed");
+ 	}
+ 
++	pppol2tp_fd_str = strdup(*argv);
++	if (pppol2tp_fd_str == NULL)
++		novm("PPPoL2TP FD");
++
+ 	/* Setup option defaults. Compression options are disabled! */
+ 
+ 	modem = 0;
diff --git a/package/network/services/ppp/patches/550-fix-printer-args.patch b/package/network/services/ppp/patches/550-fix-printer-args.patch
new file mode 100644
index 0000000000..0eed9428a6
--- /dev/null
+++ b/package/network/services/ppp/patches/550-fix-printer-args.patch
@@ -0,0 +1,11 @@
+--- a/pppd/options.c
++++ b/pppd/options.c
+@@ -1013,7 +1013,7 @@ print_option(opt, mainopt, printer, arg)
+ 			p = (char *) opt->addr2;
+ 			if ((opt->flags & OPT_STATIC) == 0)
+ 				p = *(char **)p;
+-			printer("%q", p);
++			printer(arg, "%q", p);
+ 		} else if (opt->flags & OPT_A2LIST) {
+ 			struct option_value *ovp;
+ 
diff --git a/package/network/services/ppp/utils/pfc.c b/package/network/services/ppp/utils/pfc.c
new file mode 100644
index 0000000000..5476be170a
--- /dev/null
+++ b/package/network/services/ppp/utils/pfc.c
@@ -0,0 +1,51 @@
+/* 
+ * Taken from fli4l 3.0
+ * Make sure you compile it against the same libpcap version used in OpenWrt
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+
+#include <pcap.h>
+#include <pcap-bpf.h>
+
+int main (int argc, char ** argv)
+{
+    pcap_t  *pc; /* Fake struct pcap so we can compile expr */
+    struct  bpf_program filter; /* Filter program for link-active pkts */
+    u_int32_t netmask=0;
+
+    int dflag = 3;
+    if (argc == 4)
+    {
+	if (!strcmp (argv[1], "-d"))
+	{
+	    dflag = atoi (argv[2]);
+	    argv += 2;
+	    argc -=2;
+	}
+    }
+    if (argc != 2)
+    {
+	printf ("usage; %s [ -d <debug_level> ] expression\n", argv[0]);
+	return 1;
+    }
+
+    pc = pcap_open_dead(DLT_PPP_PPPD, PPP_HDRLEN);
+    if (pcap_compile(pc, &filter, argv[1], 1, netmask) == 0)
+    {
+	printf ("#\n# Expression: %s\n#\n", argv[1]);
+	bpf_dump (&filter, dflag);
+	return 0;
+    }
+    else
+    {
+	printf("error in active-filter expression: %s\n", pcap_geterr(pc));
+    }
+    return 1;
+}
diff --git a/package/network/services/relayd/Makefile b/package/network/services/relayd/Makefile
new file mode 100644
index 0000000000..e02c633cf8
--- /dev/null
+++ b/package/network/services/relayd/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2010-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=relayd
+PKG_VERSION:=2016-02-07
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL=$(LEDE_GIT)/project/relayd.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=ad0b25ad74345d367c62311e14b279f5ccb8ef13
+PKG_MIRROR_MD5SUM:=fb387d5edfecdaf8902bff37d02cb50d92110ab5987758fb98fc25a02257aee1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/relayd
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Routing and Redirection
+  TITLE:=Transparent routing / relay daemon
+  DEPENDS:=+libubox
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+define Package/relayd/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/relayd $(1)/usr/sbin/relayd
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
+	$(INSTALL_DATA) ./files/relay.hotplug $(1)/etc/hotplug.d/iface/30-relay
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/relay.init $(1)/etc/init.d/relayd
+endef
+
+$(eval $(call BuildPackage,relayd))
diff --git a/package/network/services/relayd/files/relay.hotplug b/package/network/services/relayd/files/relay.hotplug
new file mode 100644
index 0000000000..afffbfeab8
--- /dev/null
+++ b/package/network/services/relayd/files/relay.hotplug
@@ -0,0 +1,2 @@
+#!/bin/sh
+/etc/init.d/relayd enabled && /etc/init.d/relayd start
diff --git a/package/network/services/relayd/files/relay.init b/package/network/services/relayd/files/relay.init
new file mode 100644
index 0000000000..c6288637d1
--- /dev/null
+++ b/package/network/services/relayd/files/relay.init
@@ -0,0 +1,115 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2011-2012 OpenWrt.org
+
+START=80
+
+USE_PROCD=1
+PROG=/usr/sbin/relayd
+
+validate_proto_relayd()
+{
+	uci_validate_section network "interface" "${1}" \
+		'network:list(string)' \
+		'expiry:uinteger:30' \
+		'retry:uinteger:5' \
+		'table:range(0, 65535):16800' \
+		'forward_bcast:bool:1' \
+		'forward_dhcp:bool:1'
+}
+
+resolve_ifname() {
+	grep -qs "^ *$1:" /proc/net/dev && {
+		procd_append_param command -I "$1"
+		append ifaces "$1"
+	}
+}
+
+resolve_network() {
+	local ifn
+	fixup_interface "$1"
+	config_get ifn "$1" ifname
+	[ -z "$ifn" ] && return 1
+	resolve_ifname "$ifn"
+}
+
+start_relay() {
+	local cfg="$1"
+
+	local args=""
+	local ifaces=""
+
+	config_get proto "$cfg" proto
+	[ "$proto" = "relay" ] || return 0
+
+	config_get_bool disabled "$cfg" disabled 0
+	[ "$disabled" -gt 0 ] && return 0
+
+	SERVICE_DAEMONIZE=1
+	SERVICE_WRITE_PID=1
+	SERVICE_PID_FILE="/var/run/relay-$cfg.pid"
+	[ -f "$SERVICE_PID_FILE" ] && {
+		if grep -q relayd "/proc/$(cat $SERVICE_PID_FILE)/cmdline"; then
+			return 0
+		else
+			rm -f "$SERVICE_PID_FILE"
+		fi
+	}
+
+	procd_open_instance
+	procd_set_param command "$PROG"
+
+	local net networks
+	config_get networks "$cfg" network
+	for net in $networks; do
+		resolve_network "$net" || {
+			return 1
+		}
+	done
+
+	local ifn ifnames
+	config_get ifnames "$cfg" ifname
+	for ifn in $ifnames; do
+		resolve_ifname "$ifn"
+	done
+
+	local ipaddr
+	config_get ipaddr "$cfg" ipaddr
+	[ -n "$ipaddr" ] && procd_append_param command -L "$ipaddr"
+
+	local gateway
+	config_get gateway "$cfg" gateway
+	[ -n "$gateway" ] && procd_append_param command -G "$gateway"
+
+	local expiry # = 30
+	config_get expiry "$cfg" expiry
+	[ -n "$expiry" ] && procd_append_param command "$expiry"
+
+	local retry # = 5
+	config_get retry "$cfg" retry
+	[ -n "$retry" ] && procd_append_param command -p "$retry"
+
+	local table # = 16800
+	config_get table "$cfg" table
+	[ -n "$table" ] && procd_append_param command -T "$table"
+
+	local fwd_bcast # = 1
+	config_get_bool fwd_bcast "$cfg" forward_bcast 1
+	[ $fwd_bcast -eq 1 ] && procd_append_param command "-B"
+
+	local fwd_dhcp # = 1
+	config_get_bool fwd_dhcp "$cfg" forward_dhcp 1
+	[ $fwd_dhcp -eq 1 ] && procd_append_param command "-D"
+
+	procd_close_instance
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "network"
+}
+
+start_service() {
+	include /lib/network
+	config_load network
+	config_foreach start_relay interface
+}
diff --git a/package/network/services/samba36/Makefile b/package/network/services/samba36/Makefile
new file mode 100644
index 0000000000..2f0b5fa5f0
--- /dev/null
+++ b/package/network/services/samba36/Makefile
@@ -0,0 +1,161 @@
+#
+# Copyright (C) 2007-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=samba
+PKG_VERSION:=3.6.25
+PKG_RELEASE:=5
+
+PKG_SOURCE_URL:=http://ftp.samba.org/pub/samba \
+	http://ftp.samba.org/pub/samba/stable
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_MD5SUM:=76da2fa64edd94a0188531e7ecb27c4e
+
+PKG_LICENSE:=GPL-3.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+MAKE_PATH:=source3
+CONFIGURE_PATH:=source3
+
+PKG_BUILD_BIN:=$(PKG_BUILD_DIR)/$(MAKE_PATH)/bin
+
+define Package/samba36-server
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Samba 3.6 SMB/CIFS server
+  URL:=http://www.samba.org/
+  DEPENDS:=+USE_GLIBC:librt $(ICONV_DEPENDS)
+endef
+
+define Package/samba36-client
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Samba 3.6 SMB/CIFS client
+  URL:=http://www.samba.org/
+  DEPENDS:=+libreadline +libncurses
+endef
+
+define Package/samba36-server/config
+	config PACKAGE_SAMBA_MAX_DEBUG_LEVEL
+		int "Maximum level of compiled-in debug messages"
+		depends on PACKAGE_samba36-server || PACKAGE_samba36-client
+		default -1
+
+endef
+
+define Package/samba36-server/description
+ The Samba software suite is a collection of programs that implements the
+ SMB protocol for UNIX systems, allowing you to serve files and printers to
+ Windows, NT, OS/2 and DOS clients. This protocol is sometimes also referred
+ to as the LanManager or Netbios protocol.
+endef
+
+TARGET_CFLAGS += -DMAX_DEBUG_LEVEL=$(CONFIG_PACKAGE_SAMBA_MAX_DEBUG_LEVEL) -D__location__=\\\"\\\" -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+CONFIGURE_VARS += \
+	ac_cv_lib_attr_getxattr=no \
+	ac_cv_search_getxattr=no \
+	ac_cv_file__proc_sys_kernel_core_pattern=yes \
+	libreplace_cv_HAVE_C99_VSNPRINTF=yes \
+	libreplace_cv_HAVE_GETADDRINFO=yes \
+	libreplace_cv_HAVE_IFACE_IFCONF=yes \
+	LINUX_LFS_SUPPORT=yes \
+	samba_cv_CC_NEGATIVE_ENUM_VALUES=yes \
+	samba_cv_HAVE_GETTIMEOFDAY_TZ=yes \
+	samba_cv_HAVE_IFACE_IFCONF=yes \
+	samba_cv_HAVE_KERNEL_OPLOCKS_LINUX=yes \
+	samba_cv_HAVE_SECURE_MKSTEMP=yes \
+	samba_cv_HAVE_WRFILE_KEYTAB=no \
+	samba_cv_USE_SETREUID=yes \
+	samba_cv_USE_SETRESUID=yes \
+	samba_cv_have_setreuid=yes \
+	samba_cv_have_setresuid=yes \
+	ac_cv_header_libunwind_h=no \
+	ac_cv_header_zlib_h=no \
+	samba_cv_zlib_1_2_3=no \
+	ac_cv_path_PYTHON="" \
+	ac_cv_path_PYTHON_CONFIG=""
+
+CONFIGURE_ARGS += \
+	--exec-prefix=/usr \
+	--prefix=/ \
+	--disable-avahi \
+	--disable-cups \
+	--disable-pie \
+	--disable-relro \
+	--disable-static \
+	--disable-swat \
+	--disable-shared-libs \
+	--with-libiconv="$(ICONV_PREFIX)" \
+	--with-codepagedir=/etc/samba \
+	--with-configdir=/etc/samba \
+	--with-included-iniparser \
+	--with-included-popt \
+	--with-lockdir=/var/lock \
+	--with-logfilebase=/var/log \
+	--with-nmbdsocketdir=/var/nmbd \
+	--with-piddir=/var/run \
+	--with-privatedir=/etc/samba \
+	--with-sendfile-support \
+	--without-acl-support \
+	--without-cluster-support \
+	--without-ads \
+	--without-krb5 \
+	--without-ldap \
+	--without-pam \
+	--without-winbind \
+	--without-libtdb \
+	--without-libtalloc \
+	--without-libnetapi \
+	--without-libsmbclient \
+	--without-libsmbsharemodes \
+	--without-libtevent \
+	--without-libaddns \
+	--with-shared-modules=pdb_tdbsam,pdb_wbc_sam,idmap_nss,nss_info_template,auth_winbind,auth_wbc,auth_domain
+
+MAKE_FLAGS += DYNEXP= PICFLAG= MODULES=
+
+define Package/samba36-server/conffiles
+/etc/config/samba
+/etc/samba/smb.conf.template
+/etc/samba/smbpasswd
+endef
+
+define Package/samba36-server/install
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_CONF) ./files/samba.config $(1)/etc/config/samba
+	$(INSTALL_DIR) $(1)/etc/samba
+	$(INSTALL_DATA) ./files/smb.conf.template $(1)/etc/samba
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/codepages/lowcase.dat $(1)/etc/samba
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/codepages/upcase.dat $(1)/etc/samba
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/codepages/valid.dat $(1)/etc/samba
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/samba.init $(1)/etc/init.d/samba
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_BIN)/samba_multicall $(1)/usr/sbin
+	$(LN) samba_multicall $(1)/usr/sbin/smbd
+	$(LN) samba_multicall $(1)/usr/sbin/nmbd
+	$(LN) samba_multicall $(1)/usr/sbin/smbpasswd
+endef
+
+define Package/samba36-client/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_BIN)/smbclient $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_BIN)/nmblookup $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,samba36-client))
+$(eval $(call BuildPackage,samba36-server))
+
diff --git a/package/network/services/samba36/files/samba.config b/package/network/services/samba36/files/samba.config
new file mode 100644
index 0000000000..b34a8dcaac
--- /dev/null
+++ b/package/network/services/samba36/files/samba.config
@@ -0,0 +1,6 @@
+config samba
+	option 'name'			'Lede'
+	option 'workgroup'		'WORKGROUP'
+	option 'description'		'Lede'
+	option 'homes'			'1'
+
diff --git a/package/network/services/samba36/files/samba.init b/package/network/services/samba36/files/samba.init
new file mode 100755
index 0000000000..c8413243ba
--- /dev/null
+++ b/package/network/services/samba36/files/samba.init
@@ -0,0 +1,119 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2008-2012 OpenWrt.org
+
+START=60
+USE_PROCD=1
+
+smb_header() {
+	config_get samba_iface $1 interface "loopback lan"
+
+	# resolve interfaces
+	local interfaces=$(
+		. /lib/functions/network.sh
+
+		local net
+		for net in $samba_iface; do
+			local device
+			network_is_up $net || continue
+			network_get_device device "$net" && {
+				local subnet
+				network_get_subnet  subnet "$net" && echo -n "$subnet "
+				network_get_subnet6 subnet "$net" && echo -n "$subnet "
+			}
+
+			echo -n "${device:-$net} "
+		done
+	)
+
+	local name workgroup description charset
+	local hostname="$(uci_get system.@system[0].hostname)"
+
+	config_get name        $1 name        "${hostname:-Lede}"
+	config_get workgroup   $1 workgroup   "${hostname:-Lede}"
+	config_get description $1 description "Samba on ${hostname:-Lede}"
+	config_get charset     $1 charset     "UTF-8"
+
+	mkdir -p /var/etc
+	sed -e "s#|NAME|#$name#g" \
+	    -e "s#|WORKGROUP|#$workgroup#g" \
+	    -e "s#|DESCRIPTION|#$description#g" \
+	    -e "s#|INTERFACES|#$interfaces#g" \
+	    -e "s#|CHARSET|#$charset#g" \
+	    /etc/samba/smb.conf.template > /var/etc/smb.conf
+
+	local homes
+	config_get_bool homes $1 homes 0
+	[ $homes -gt 0 ] && {
+		cat <<EOT >> /var/etc/smb.conf
+
+[homes]
+	comment     = Home Directories
+	browsable   = no
+	read only   = no
+	create mode = 0750
+EOT
+	}
+
+	[ -L /etc/samba/smb.conf ] || ln -nsf /var/etc/smb.conf /etc/samba/smb.conf
+}
+
+smb_add_share() {
+	local name
+	local path
+	local users
+	local read_only
+	local guest_ok
+	local create_mask
+	local dir_mask
+	local browseable
+
+	config_get name $1 name
+	config_get path $1 path
+	config_get users $1 users
+	config_get read_only $1 read_only
+	config_get guest_ok $1 guest_ok
+	config_get create_mask $1 create_mask
+	config_get dir_mask $1 dir_mask
+	config_get browseable $1 browseable
+
+	[ -z "$name" -o -z "$path" ] && return
+
+	echo -e "\n[$name]\n\tpath = $path" >> /var/etc/smb.conf
+	[ -n "$users" ] && echo -e "\tvalid users = $users" >> /var/etc/smb.conf
+	[ -n "$read_only" ] && echo -e "\tread only = $read_only" >> /var/etc/smb.conf
+	[ -n "$guest_ok" ] && echo -e "\tguest ok = $guest_ok" >> /var/etc/smb.conf
+	[ -n "$create_mask" ] && echo -e "\tcreate mask = $create_mask" >> /var/etc/smb.conf
+	[ -n "$dir_mask" ] && echo -e "\tdirectory mask = $dir_mask" >> /var/etc/smb.conf
+	[ -n "$browseable" ] && echo -e "\tbrowseable = $browseable" >> /var/etc/smb.conf
+}
+
+init_config() {
+	config_load samba
+	config_foreach smb_header samba
+	config_foreach smb_add_share sambashare
+}
+
+service_triggers() {
+	procd_add_reload_trigger samba
+
+	local i
+	for i in $samba_iface; do
+		procd_add_reload_interface_trigger $i
+	done
+}
+
+start_service() {
+	init_config
+
+	procd_open_instance
+	procd_set_param command /usr/sbin/smbd -F
+	procd_set_param respawn
+	procd_set_param file /var/etc/smb.conf
+	procd_close_instance
+
+	procd_open_instance
+	procd_set_param command /usr/sbin/nmbd -F
+	procd_set_param respawn
+	procd_set_param file /var/etc/smb.conf
+	procd_close_instance
+}
diff --git a/package/network/services/samba36/files/smb.conf.template b/package/network/services/samba36/files/smb.conf.template
new file mode 100644
index 0000000000..35e486fd89
--- /dev/null
+++ b/package/network/services/samba36/files/smb.conf.template
@@ -0,0 +1,28 @@
+[global]
+	netbios name = |NAME| 
+	display charset = |CHARSET|
+	interfaces = |INTERFACES|
+	server string = |DESCRIPTION|
+	unix charset = |CHARSET|
+	workgroup = |WORKGROUP|
+	local master = no
+	browseable = yes
+	deadtime = 30
+	domain master = yes
+	encrypt passwords = yes
+	enable core files = no
+	guest ok = yes
+	invalid users = root
+	load printers = no
+	map to guest = Bad User
+	max protocol = SMB2
+	min receivefile size = 16384
+	null passwords = yes
+	passdb backend = smbpasswd
+	preferred master = yes
+	security = user
+	smb passwd file = /etc/samba/smbpasswd
+	syslog = 2
+	use sendfile = yes
+	writeable = yes
+	bind interfaces only = yes
diff --git a/package/network/services/samba36/patches/010-patch-cve-2015-5252.patch b/package/network/services/samba36/patches/010-patch-cve-2015-5252.patch
new file mode 100644
index 0000000000..3640907a9b
--- /dev/null
+++ b/package/network/services/samba36/patches/010-patch-cve-2015-5252.patch
@@ -0,0 +1,39 @@
+From 2e94b6ec10f1d15e24867bab3063bb85f173406a Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra@samba.org>
+Date: Thu, 9 Jul 2015 10:58:11 -0700
+Subject: [PATCH] CVE-2015-5252: s3: smbd: Fix symlink verification (file
+ access outside the share).
+
+Ensure matching component ends in '/' or '\0'.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11395
+
+Signed-off-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: Volker Lendecke <vl@samba.org>
+---
+ source3/smbd/vfs.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/source3/smbd/vfs.c
++++ b/source3/smbd/vfs.c
+@@ -982,6 +982,7 @@ NTSTATUS check_reduced_name(connection_s
+ 	if (!allow_widelinks || !allow_symlinks) {
+ 		const char *conn_rootdir;
+ 		size_t rootdir_len;
++		bool matched;
+ 
+ 		conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname);
+ 		if (conn_rootdir == NULL) {
+@@ -992,8 +993,10 @@ NTSTATUS check_reduced_name(connection_s
+ 		}
+ 
+ 		rootdir_len = strlen(conn_rootdir);
+-		if (strncmp(conn_rootdir, resolved_name,
+-				rootdir_len) != 0) {
++		matched = (strncmp(conn_rootdir, resolved_name,
++				rootdir_len) == 0);
++		if (!matched || (resolved_name[rootdir_len] != '/' &&
++				 resolved_name[rootdir_len] != '\0')) {
+ 			DEBUG(2, ("check_reduced_name: Bad access "
+ 				"attempt: %s is a symlink outside the "
+ 				"share path\n", fname));
diff --git a/package/network/services/samba36/patches/011-patch-cve-2015-5296.patch b/package/network/services/samba36/patches/011-patch-cve-2015-5296.patch
new file mode 100644
index 0000000000..a309cf1b7f
--- /dev/null
+++ b/package/network/services/samba36/patches/011-patch-cve-2015-5296.patch
@@ -0,0 +1,88 @@
+From 25139116756cc285a3a5534834cc276ef1b7baaa Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Wed, 30 Sep 2015 21:17:02 +0200
+Subject: [PATCH 1/2] CVE-2015-5296: s3:libsmb: force signing when requiring
+ encryption in do_connect()
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11536
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Jeremy Allison <jra@samba.org>
+---
+ source3/libsmb/clidfs.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/source3/libsmb/clidfs.c
++++ b/source3/libsmb/clidfs.c
+@@ -98,6 +98,11 @@ static struct cli_state *do_connect(TALL
+ 	const char *username;
+ 	const char *password;
+ 	NTSTATUS status;
++	int signing_state = get_cmdline_auth_info_signing_state(auth_info);
++
++	if (force_encrypt) {
++		signing_state = Required;
++	}
+ 
+ 	/* make a copy so we don't modify the global string 'service' */
+ 	servicename = talloc_strdup(ctx,share);
+@@ -132,7 +137,7 @@ static struct cli_state *do_connect(TALL
+ 	zero_sockaddr(&ss);
+ 
+ 	/* have to open a new connection */
+-	c = cli_initialise_ex(get_cmdline_auth_info_signing_state(auth_info));
++	c = cli_initialise_ex(signing_state);
+ 	if (c == NULL) {
+ 		d_printf("Connection to %s failed\n", server_n);
+ 		return NULL;
+--- a/source3/libsmb/libsmb_server.c
++++ b/source3/libsmb/libsmb_server.c
+@@ -258,6 +258,7 @@ SMBC_server_internal(TALLOC_CTX *ctx,
+         const char *username_used;
+  	NTSTATUS status;
+ 	char *newserver, *newshare;
++	int signing_state = Undefined;
+ 
+ 	zero_sockaddr(&ss);
+ 	ZERO_STRUCT(c);
+@@ -404,8 +405,12 @@ again:
+ 
+ 	zero_sockaddr(&ss);
+ 
++	if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) {
++		signing_state = Required;
++	}
++
+ 	/* have to open a new connection */
+-	if ((c = cli_initialise()) == NULL) {
++	if ((c = cli_initialise_ex(signing_state)) == NULL) {
+ 		errno = ENOMEM;
+ 		return NULL;
+ 	}
+@@ -750,6 +755,7 @@ SMBC_attr_server(TALLOC_CTX *ctx,
+         ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
+                                    pp_workgroup, pp_username, pp_password);
+         if (!ipc_srv) {
++		int signing_state = Undefined;
+ 
+                 /* We didn't find a cached connection.  Get the password */
+ 		if (!*pp_password || (*pp_password)[0] == '\0') {
+@@ -771,6 +777,9 @@ SMBC_attr_server(TALLOC_CTX *ctx,
+                 if (smbc_getOptionUseCCache(context)) {
+                         flags |= CLI_FULL_CONNECTION_USE_CCACHE;
+                 }
++		if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) {
++			signing_state = Required;
++		}
+ 
+                 zero_sockaddr(&ss);
+                 nt_status = cli_full_connection(&ipc_cli,
+@@ -780,7 +789,7 @@ SMBC_attr_server(TALLOC_CTX *ctx,
+ 						*pp_workgroup,
+ 						*pp_password,
+ 						flags,
+-						Undefined);
++						signing_state);
+                 if (! NT_STATUS_IS_OK(nt_status)) {
+                         DEBUG(1,("cli_full_connection failed! (%s)\n",
+                                  nt_errstr(nt_status)));
diff --git a/package/network/services/samba36/patches/012-patch-cve-2015-5299.patch b/package/network/services/samba36/patches/012-patch-cve-2015-5299.patch
new file mode 100644
index 0000000000..7a569c7462
--- /dev/null
+++ b/package/network/services/samba36/patches/012-patch-cve-2015-5299.patch
@@ -0,0 +1,93 @@
+From 8e49de7754f7171a58a1f94dee0f1138dbee3c60 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra@samba.org>
+Date: Fri, 23 Oct 2015 14:54:31 -0700
+Subject: [PATCH] CVE-2015-5299: s3-shadow-copy2: fix missing access check on
+ snapdir
+
+Fix originally from <partha@exablox.com>
+
+https://bugzilla.samba.org/show_bug.cgi?id=11529
+
+Signed-off-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: David Disseldorp <ddiss@samba.org>
+---
+ source3/modules/vfs_shadow_copy2.c | 47 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
+
+--- a/source3/modules/vfs_shadow_copy2.c
++++ b/source3/modules/vfs_shadow_copy2.c
+@@ -21,6 +21,8 @@
+ 
+ #include "includes.h"
+ #include "smbd/smbd.h"
++#include "smbd/globals.h"
++#include "../libcli/security/security.h"
+ #include "system/filesys.h"
+ #include "ntioctl.h"
+ 
+@@ -764,6 +766,43 @@ static int shadow_copy2_mkdir(vfs_handle
+         SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
+ }
+ 
++static bool check_access_snapdir(struct vfs_handle_struct *handle,
++				const char *path)
++{
++	struct smb_filename smb_fname;
++	int ret;
++	NTSTATUS status;
++	uint32_t access_granted = 0;
++
++	ZERO_STRUCT(smb_fname);
++	smb_fname.base_name = talloc_asprintf(talloc_tos(),
++						"%s",
++						path);
++	if (smb_fname.base_name == NULL) {
++		return false;
++	}
++
++	ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
++	if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
++		TALLOC_FREE(smb_fname.base_name);
++		return false;
++	}
++
++	status = smbd_check_open_rights(handle->conn,
++					&smb_fname,
++					SEC_DIR_LIST,
++					&access_granted);
++	if (!NT_STATUS_IS_OK(status)) {
++		DEBUG(0,("user does not have list permission "
++			"on snapdir %s\n",
++			smb_fname.base_name));
++		TALLOC_FREE(smb_fname.base_name);
++		return false;
++	}
++	TALLOC_FREE(smb_fname.base_name);
++	return true;
++}
++
+ static int shadow_copy2_rmdir(vfs_handle_struct *handle,  const char *fname)
+ {
+         SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
+@@ -877,6 +916,7 @@ static int shadow_copy2_get_shadow_copy2
+ 	SMB_STRUCT_DIRENT *d;
+ 	TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
+ 	char *snapshot;
++	bool ret;
+ 
+ 	snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
+ 	if (snapdir == NULL) {
+@@ -886,6 +926,13 @@ static int shadow_copy2_get_shadow_copy2
+ 		talloc_free(tmp_ctx);
+ 		return -1;
+ 	}
++	ret = check_access_snapdir(handle, snapdir);
++	if (!ret) {
++		DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
++		errno = EACCES;
++		talloc_free(tmp_ctx);
++		return -1;
++	}
+ 
+ 	p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
+ 
diff --git a/package/network/services/samba36/patches/015-patch-cve-2015-7560.patch b/package/network/services/samba36/patches/015-patch-cve-2015-7560.patch
new file mode 100644
index 0000000000..6ce8e2f9b7
--- /dev/null
+++ b/package/network/services/samba36/patches/015-patch-cve-2015-7560.patch
@@ -0,0 +1,172 @@
+From eb27f9b7bf9c1dc902d9545eecf805831bd4e46c Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra@samba.org>
+Date: Tue, 5 Jan 2016 11:18:12 -0800
+Subject: [PATCH 1/8] CVE-2015-7560: s3: smbd: Add refuse_symlink() function
+ that can be used to prevent operations on a symlink.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648
+
+Signed-off-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: Michael Adam <obnox@samba.org>
+---
+ source3/smbd/trans2.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/source3/smbd/trans2.c
++++ b/source3/smbd/trans2.c
+@@ -51,6 +51,34 @@ static char *store_file_unix_basic_info2
+ 				files_struct *fsp,
+ 				const SMB_STRUCT_STAT *psbuf);
+ 
++/****************************************************************************
++ Check if an open file handle or pathname is a symlink.
++****************************************************************************/
++
++static NTSTATUS refuse_symlink(connection_struct *conn,
++			const files_struct *fsp,
++			const char *name)
++{
++	SMB_STRUCT_STAT sbuf;
++	const SMB_STRUCT_STAT *pst = NULL;
++
++	if (fsp) {
++		pst = &fsp->fsp_name->st;
++	} else {
++		int ret = vfs_stat_smb_fname(conn,
++				name,
++				&sbuf);
++		if (ret == -1) {
++			return map_nt_error_from_unix(errno);
++		}
++		pst = &sbuf;
++	}
++	if (S_ISLNK(pst->st_ex_mode)) {
++		return NT_STATUS_ACCESS_DENIED;
++	}
++	return NT_STATUS_OK;
++}
++
+ /********************************************************************
+  Roundup a value to the nearest allocation roundup size boundary.
+  Only do this for Windows clients.
+@@ -181,12 +209,22 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
+ 	char **names, **tmp;
+ 	size_t num_names;
+ 	ssize_t sizeret = -1;
++	NTSTATUS status;
++
++	if (pnames) {
++		*pnames = NULL;
++	}
++	*pnum_names = 0;
+ 
+ 	if (!lp_ea_support(SNUM(conn))) {
+-		if (pnames) {
+-			*pnames = NULL;
+-		}
+-		*pnum_names = 0;
++		return NT_STATUS_OK;
++	}
++
++	status = refuse_symlink(conn, fsp, fname);
++	if (!NT_STATUS_IS_OK(status)) {
++		/*
++		 * Just return no EA's on a symlink.
++		 */
+ 		return NT_STATUS_OK;
+ 	}
+ 
+@@ -236,10 +274,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
+ 
+ 	if (sizeret == 0) {
+ 		TALLOC_FREE(names);
+-		if (pnames) {
+-			*pnames = NULL;
+-		}
+-		*pnum_names = 0;
+ 		return NT_STATUS_OK;
+ 	}
+ 
+@@ -550,6 +584,7 @@ NTSTATUS set_ea(connection_struct *conn,
+ 		const struct smb_filename *smb_fname, struct ea_list *ea_list)
+ {
+ 	char *fname = NULL;
++	NTSTATUS status;
+ 
+ 	if (!lp_ea_support(SNUM(conn))) {
+ 		return NT_STATUS_EAS_NOT_SUPPORTED;
+@@ -559,6 +594,12 @@ NTSTATUS set_ea(connection_struct *conn,
+ 		return NT_STATUS_ACCESS_DENIED;
+ 	}
+ 
++	status = refuse_symlink(conn, fsp, smb_fname->base_name);
++	if (!NT_STATUS_IS_OK(status)) {
++		return status;
++	}
++
++
+ 	/* For now setting EAs on streams isn't supported. */
+ 	fname = smb_fname->base_name;
+ 
+@@ -4931,6 +4972,13 @@ NTSTATUS smbd_do_qfilepathinfo(connectio
+ 				uint16 num_file_acls = 0;
+ 				uint16 num_def_acls = 0;
+ 
++				status = refuse_symlink(conn,
++						fsp,
++						smb_fname->base_name);
++				if (!NT_STATUS_IS_OK(status)) {
++					return status;
++				}
++
+ 				if (fsp && fsp->fh->fd != -1) {
+ 					file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+ 				} else {
+@@ -6452,6 +6500,7 @@ static NTSTATUS smb_set_posix_acl(connec
+ 	uint16 num_def_acls;
+ 	bool valid_file_acls = True;
+ 	bool valid_def_acls = True;
++	NTSTATUS status;
+ 
+ 	if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
+ 		return NT_STATUS_INVALID_PARAMETER;
+@@ -6479,6 +6528,11 @@ static NTSTATUS smb_set_posix_acl(connec
+ 		return NT_STATUS_INVALID_PARAMETER;
+ 	}
+ 
++	status = refuse_symlink(conn, fsp, smb_fname->base_name);
++	if (!NT_STATUS_IS_OK(status)) {
++		return status;
++	}
++
+ 	DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
+ 		smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
+ 		(unsigned int)num_file_acls,
+--- a/source3/smbd/nttrans.c
++++ b/source3/smbd/nttrans.c
+@@ -877,6 +877,12 @@ NTSTATUS set_sd(files_struct *fsp, struc
+ 		return NT_STATUS_OK;
+ 	}
+ 
++	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
++		DEBUG(10, ("ACL set on symlink %s denied.\n",
++			fsp_str_dbg(fsp)));
++		return NT_STATUS_ACCESS_DENIED;
++	}
++
+ 	if (psd->owner_sid == NULL) {
+ 		security_info_sent &= ~SECINFO_OWNER;
+ 	}
+@@ -1925,6 +1931,12 @@ NTSTATUS smbd_do_query_security_desc(con
+ 		return NT_STATUS_ACCESS_DENIED;
+ 	}
+ 
++	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
++		DEBUG(10, ("ACL get on symlink %s denied.\n",
++			fsp_str_dbg(fsp)));
++		return NT_STATUS_ACCESS_DENIED;
++	}
++
+ 	if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
+ 			SECINFO_GROUP|SECINFO_SACL)) {
+ 		/* Don't return SECINFO_LABEL if anything else was
diff --git a/package/network/services/samba36/patches/020-CVE-preparation-v3-6.patch b/package/network/services/samba36/patches/020-CVE-preparation-v3-6.patch
new file mode 100644
index 0000000000..ae822f47f1
--- /dev/null
+++ b/package/network/services/samba36/patches/020-CVE-preparation-v3-6.patch
@@ -0,0 +1,6824 @@
+From 39a3fa39967faaf216be8e108ca57d07de1aa95a Mon Sep 17 00:00:00 2001
+From: Vadim Zhukov <persgray@gmail.com>
+Date: Sat, 25 May 2013 15:19:24 +0100
+Subject: [PATCH 01/41] pidl: Recent Perl warns about "defined(@var)"
+ constructs.
+
+Signed-off-by: Jelmer Vernooij <jelmer@samba.org>
+
+Autobuild-User(master): Jelmer Vernooij <jelmer@samba.org>
+Autobuild-Date(master): Sat May 25 18:10:53 CEST 2013 on sn-devel-104
+
+(cherry picked from commit 92254d09e0ee5a7d9d0cd91fe1803f54e64d9a5f)
+---
+ pidl/lib/Parse/Pidl/ODL.pm | 2 +-
+ pidl/pidl                  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/pidl/lib/Parse/Pidl/ODL.pm
++++ b/pidl/lib/Parse/Pidl/ODL.pm
+@@ -70,7 +70,7 @@ sub ODL2IDL
+ 					next;
+ 				}
+ 				my $podl = Parse::Pidl::IDL::parse_file($idl_path, $opt_incdirs);
+-				if (defined(@$podl)) {
++				if (defined($podl)) {
+ 					require Parse::Pidl::Typelist;
+ 					my $basename = basename($idl_path, ".idl");
+ 
+--- a/pidl/pidl
++++ b/pidl/pidl
+@@ -605,7 +605,7 @@ sub process_file($)
+ 		require Parse::Pidl::IDL;
+ 
+ 		$pidl = Parse::Pidl::IDL::parse_file($idl_file, \@opt_incdirs);
+-		defined @$pidl || die "Failed to parse $idl_file";
++		defined $pidl || die "Failed to parse $idl_file";
+ 	}
+ 
+ 	require Parse::Pidl::Typelist;
+--- a/source4/heimdal/cf/make-proto.pl
++++ b/source4/heimdal/cf/make-proto.pl
+@@ -1,8 +1,8 @@
+ # Make prototypes from .c files
+ # $Id$
+ 
+-##use Getopt::Std;
+-require 'getopts.pl';
++use Getopt::Std;
++#require 'getopts.pl';
+ 
+ my $comment = 0;
+ my $if_0 = 0;
+@@ -12,7 +12,7 @@ my $debug = 0;
+ my $oproto = 1;
+ my $private_func_re = "^_";
+ 
+-Getopts('x:m:o:p:dqE:R:P:') || die "foo";
++getopts('x:m:o:p:dqE:R:P:') || die "foo";
+ 
+ if($opt_d) {
+     $debug = 1;
+--- a/source3/Makefile-smbtorture4
++++ b/source3/Makefile-smbtorture4
+@@ -6,7 +6,7 @@ SAMBA4_BINARIES="smbtorture,ndrdump"
+ samba4-configure:
+ 	@(cd .. && \
+ 		CFLAGS='' $(WAF) reconfigure || \
+-		CFLAGS='' $(WAF) configure --enable-socket-wrapper --enable-nss-wrapper --enable-uid-wrapper --nonshared-binary=$(SAMBA4_BINARIES) --enable-auto-reconfigure )
++		CFLAGS='' $(WAF) configure --enable-socket-wrapper --enable-nss-wrapper --enable-uid-wrapper --nonshared-binary=$(SAMBA4_BINARIES) --enable-auto-reconfigure --bundled-libraries=ALL --disable-gnutls )
+ 
+ .PHONY: samba4-configure
+ 
+--- a/source4/lib/ldb/wscript
++++ b/source4/lib/ldb/wscript
+@@ -135,9 +135,7 @@ def build(bld):
+                           pc_files=ldb_pc_files,
+                           vnum=VERSION,
+                           private_library=private_library,
+-                          manpages='man/ldb.3',
+-                          abi_directory = 'ABI',
+-                          abi_match = abi_match)
++                          manpages='man/ldb.3')
+ 
+         # generate a include/ldb_version.h
+         t = bld.SAMBA_GENERATOR('ldb_version.h',
+--- a/source3/selftest/skip
++++ b/source3/selftest/skip
+@@ -22,3 +22,8 @@ samba3.*raw.ioctl
+ samba3.*raw.qfileinfo
+ samba3.*raw.qfsinfo
+ samba3.*raw.sfileinfo.base
++# skip, don't work for badlock backports
++samba3.posix_s3.raw.eas
++samba3.posix_s3.raw.rename
++samba3.posix_s3.raw.search
++samba3.posix_s3.raw.streams
+--- a/librpc/ndr/ndr_ntlmssp.c
++++ b/librpc/ndr/ndr_ntlmssp.c
+@@ -176,4 +176,20 @@ _PUBLIC_ void ndr_print_ntlmssp_Version(
+ 	}
+ }
+ 
++_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list,
++					     enum ntlmssp_AvId AvId)
++{
++	struct AV_PAIR *res = NULL;
++	uint32_t i = 0;
+ 
++	for (i = 0; i < av_list->count; i++) {
++		if (av_list->pair[i].AvId != AvId) {
++			continue;
++		}
++
++		res = discard_const_p(struct AV_PAIR, &av_list->pair[i]);
++		break;
++	}
++
++	return res;
++}
+--- a/librpc/ndr/ndr_ntlmssp.h
++++ b/librpc/ndr/ndr_ntlmssp.h
+@@ -31,3 +31,5 @@ _PUBLIC_ void ndr_print_ntlmssp_lm_respo
+ 					    bool ntlmv2);
+ _PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r);
+ 
++_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list,
++					     enum ntlmssp_AvId AvId);
+--- /dev/null
++++ b/librpc/ABI/ndr-0.0.2.sigs
+@@ -0,0 +1,247 @@
++GUID_all_zero: bool (const struct GUID *)
++GUID_compare: int (const struct GUID *, const struct GUID *)
++GUID_equal: bool (const struct GUID *, const struct GUID *)
++GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
++GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
++GUID_from_string: NTSTATUS (const char *, struct GUID *)
++GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
++GUID_random: struct GUID (void)
++GUID_string: char *(TALLOC_CTX *, const struct GUID *)
++GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
++GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
++GUID_zero: struct GUID (void)
++ndr_align_size: size_t (uint32_t, size_t)
++ndr_charset_length: uint32_t (const void *, charset_t)
++ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
++ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
++ndr_check_padding: void (struct ndr_pull *, size_t)
++ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
++ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
++ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
++ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
++ndr_map_error2errno: int (enum ndr_err_code)
++ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
++ndr_map_error2string: const char *(enum ndr_err_code)
++ndr_policy_handle_empty: bool (const struct policy_handle *)
++ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
++ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
++ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
++ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
++ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
++ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
++ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
++ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
++ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
++ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
++ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
++ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
++ndr_print_bool: void (struct ndr_print *, const char *, const bool)
++ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
++ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
++ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
++ndr_print_double: void (struct ndr_print *, const char *, double)
++ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
++ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
++ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
++ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
++ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
++ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
++ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
++ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
++ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
++ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
++ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
++ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
++ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
++ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
++ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
++ndr_print_null: void (struct ndr_print *)
++ndr_print_pointer: void (struct ndr_print *, const char *, void *)
++ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
++ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
++ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
++ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
++ndr_print_string: void (struct ndr_print *, const char *, const char *)
++ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
++ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_struct: void (struct ndr_print *, const char *, const char *)
++ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
++ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
++ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
++ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
++ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
++ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
++ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
++ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
++ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
++ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
++ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
++ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
++ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
++ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
++ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
++ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
++ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
++ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
++ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
++ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
++ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
++ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
++ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
++ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
++ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
++ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
++ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
++ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
++ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
++ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
++ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
++ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
++ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
++ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
++ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
++ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
++ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
++ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
++ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
++ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
++ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
++ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
++ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
++ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
++ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
++ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
++ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
++ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
++ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
++ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
++ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
++ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
++ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
++ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
++ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
++ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
++ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
++ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
++ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
++ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
++ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
++ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
++ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
++ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
++ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
++ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
++ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
++ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
++ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
++ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
++ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
++ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
++ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
++ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
++ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
++ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
++ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
++ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
++ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
++ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
++ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
++ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
++ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
++ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
++ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
++ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
++ndr_push_blob: DATA_BLOB (struct ndr_push *)
++ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
++ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
++ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
++ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
++ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
++ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
++ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
++ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
++ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
++ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
++ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
++ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
++ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
++ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
++ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
++ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
++ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
++ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
++ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
++ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
++ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
++ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
++ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
++ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
++ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
++ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
++ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
++ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
++ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
++ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
++ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
++ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
++ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
++ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
++ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
++ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
++ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
++ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
++ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
++ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
++ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
++ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
++ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
++ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
++ndr_set_flags: void (uint32_t *, uint32_t)
++ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
++ndr_size_GUID: size_t (const struct GUID *, int)
++ndr_size_string: uint32_t (int, const char * const *, int)
++ndr_size_string_array: size_t (const char **, uint32_t, int)
++ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
++ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
++ndr_string_array_size: size_t (struct ndr_push *, const char *)
++ndr_string_length: uint32_t (const void *, uint32_t)
++ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
++ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
++ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
++ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
++ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
++ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
++ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
++ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+--- a/librpc/ndr/libndr.h
++++ b/librpc/ndr/libndr.h
+@@ -124,6 +124,20 @@ struct ndr_print {
+ #define LIBNDR_FLAG_STR_UTF8		(1<<12)
+ #define LIBNDR_STRING_FLAGS		(0x7FFC)
+ 
++/*
++ * don't debug NDR_ERR_BUFSIZE failures,
++ * as the available buffer might be incomplete.
++ *
++ * return NDR_ERR_INCOMPLETE_BUFFER instead.
++ */
++#define LIBNDR_FLAG_INCOMPLETE_BUFFER (1<<16)
++
++/*
++ * This lets ndr_pull_subcontext_end() return
++ * NDR_ERR_UNREAD_BYTES.
++ */
++#define LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES (1<<17)
++
+ /* set if relative pointers should *not* be marshalled in reverse order */
+ #define LIBNDR_FLAG_NO_RELATIVE_REVERSE	(1<<18)
+ 
+@@ -163,6 +177,7 @@ struct ndr_print {
+ 
+ /* useful macro for debugging */
+ #define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p)
++#define NDR_PRINT_DEBUGC(dbgc_class, type, p) ndr_print_debugc(dbgc_class, (ndr_print_fn_t)ndr_print_ ##type, #p, p)
+ #define NDR_PRINT_UNION_DEBUG(type, level, p) ndr_print_union_debug((ndr_print_fn_t)ndr_print_ ##type, #p, level, p)
+ #define NDR_PRINT_FUNCTION_DEBUG(type, flags, p) ndr_print_function_debug((ndr_print_function_t)ndr_print_ ##type, #type, flags, p)
+ #define NDR_PRINT_BOTH_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_BOTH, p)
+@@ -199,7 +214,9 @@ enum ndr_err_code {
+ 	NDR_ERR_IPV6ADDRESS,
+ 	NDR_ERR_INVALID_POINTER,
+ 	NDR_ERR_UNREAD_BYTES,
+-	NDR_ERR_NDR64
++	NDR_ERR_NDR64,
++	NDR_ERR_FLAGS,
++	NDR_ERR_INCOMPLETE_BUFFER
+ };
+ 
+ #define NDR_ERR_CODE_IS_SUCCESS(x) (x == NDR_ERR_SUCCESS)
+@@ -217,20 +234,52 @@ enum ndr_compression_alg {
+ 
+ /*
+   flags passed to control parse flow
++  These are deliberately in a different range to the NDR_IN/NDR_OUT
++  flags to catch mixups
+ */
+-#define NDR_SCALARS 1
+-#define NDR_BUFFERS 2
++#define NDR_SCALARS    0x100
++#define NDR_BUFFERS    0x200
+ 
+ /*
+-  flags passed to ndr_print_*()
++  flags passed to ndr_print_*() and ndr pull/push for functions
++  These are deliberately in a different range to the NDR_SCALARS/NDR_BUFFERS
++  flags to catch mixups
+ */
+-#define NDR_IN 1
+-#define NDR_OUT 2
+-#define NDR_BOTH 3
+-#define NDR_SET_VALUES 4
++#define NDR_IN         0x10
++#define NDR_OUT        0x20
++#define NDR_BOTH       0x30
++#define NDR_SET_VALUES 0x40
++
++
++#define NDR_PULL_CHECK_FLAGS(ndr, ndr_flags) do { \
++	if ((ndr_flags) & ~(NDR_SCALARS|NDR_BUFFERS)) { \
++		return ndr_pull_error(ndr, NDR_ERR_FLAGS, "Invalid pull struct ndr_flags 0x%x", ndr_flags); \
++	} \
++} while (0)
++
++#define NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags) do { \
++	if ((ndr_flags) & ~(NDR_SCALARS|NDR_BUFFERS)) \
++		return ndr_push_error(ndr, NDR_ERR_FLAGS, "Invalid push struct ndr_flags 0x%x", ndr_flags); \
++} while (0)
++
++#define NDR_PULL_CHECK_FN_FLAGS(ndr, flags) do { \
++	if ((flags) & ~(NDR_BOTH|NDR_SET_VALUES)) { \
++		return ndr_pull_error(ndr, NDR_ERR_FLAGS, "Invalid fn pull flags 0x%x", flags); \
++	} \
++} while (0)
++
++#define NDR_PUSH_CHECK_FN_FLAGS(ndr, flags) do { \
++	if ((flags) & ~(NDR_BOTH|NDR_SET_VALUES)) \
++		return ndr_push_error(ndr, NDR_ERR_FLAGS, "Invalid fn push flags 0x%x", flags); \
++} while (0)
+ 
+ #define NDR_PULL_NEED_BYTES(ndr, n) do { \
+ 	if (unlikely((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size)) { \
++		if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \
++			uint32_t _available = ndr->data_size - ndr->offset; \
++			uint32_t _missing = n - _available; \
++			ndr->relative_highest_offset = _missing; \
++		} \
+ 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %u (%s)", (unsigned)n, __location__); \
+ 	} \
+ } while(0)
+@@ -247,6 +296,10 @@ enum ndr_compression_alg {
+ 		ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \
+ 	} \
+ 	if (unlikely(ndr->offset > ndr->data_size)) {			\
++		if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \
++			uint32_t _missing = ndr->offset - ndr->data_size; \
++			ndr->relative_highest_offset = _missing; \
++		} \
+ 		return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %u", (unsigned)n); \
+ 	} \
+ } while(0)
+@@ -402,6 +455,8 @@ void ndr_print_dom_sid0(struct ndr_print
+ size_t ndr_size_dom_sid0(const struct dom_sid *sid, int flags);
+ void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid);
+ bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1, const struct ndr_syntax_id *i2); 
++char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id);
++bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id);
+ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn);
+ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_push_flags_fn_t fn);
+ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push);
+@@ -424,14 +479,18 @@ enum ndr_err_code ndr_pull_relative_ptr2
+ enum ndr_err_code ndr_pull_relative_ptr_short(struct ndr_pull *ndr, uint16_t *v);
+ size_t ndr_align_size(uint32_t offset, size_t n);
+ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx);
++enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob);
++enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr);
+ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size);
+ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx);
+ DATA_BLOB ndr_push_blob(struct ndr_push *ndr);
+ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size);
+ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
++void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr);
++void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr);
+ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr);
+ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr);
+ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr);
+--- a/librpc/ndr/ndr.c
++++ b/librpc/ndr/ndr.c
+@@ -77,6 +77,111 @@ _PUBLIC_ struct ndr_pull *ndr_pull_init_
+ 	return ndr;
+ }
+ 
++_PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
++{
++	enum ndr_err_code ndr_err;
++	DATA_BLOB b;
++	uint32_t append = 0;
++	bool ok;
++
++	if (blob->length == 0) {
++		return NDR_ERR_SUCCESS;
++	}
++
++	ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
++	if (ndr_err == NDR_ERR_TOKEN) {
++		append = 0;
++		ndr_err = NDR_ERR_SUCCESS;
++	}
++	NDR_CHECK(ndr_err);
++
++	if (ndr->data_size == 0) {
++		ndr->data = NULL;
++		append = UINT32_MAX;
++	}
++
++	if (append == UINT32_MAX) {
++		/*
++		 * append == UINT32_MAX means that
++		 * ndr->data is either NULL or a valid
++		 * talloc child of ndr, which means
++		 * we can use data_blob_append() without
++		 * data_blob_talloc() of the existing callers data
++		 */
++		b = data_blob_const(ndr->data, ndr->data_size);
++	} else {
++		b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
++		if (b.data == NULL) {
++			return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
++		}
++	}
++
++	ok = data_blob_append(ndr, &b, blob->data, blob->length);
++	if (!ok) {
++		return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
++	}
++
++	ndr->data = b.data;
++	ndr->data_size = b.length;
++
++	return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
++}
++
++_PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
++{
++	uint32_t skip = 0;
++	uint32_t append = 0;
++
++	if (ndr->relative_base_offset != 0) {
++		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
++				      "%s", __location__);
++	}
++	if (ndr->relative_highest_offset != 0) {
++		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
++				      "%s", __location__);
++	}
++	if (ndr->relative_list != NULL) {
++		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
++				      "%s", __location__);
++	}
++	if (ndr->relative_base_list != NULL) {
++		return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
++				      "%s", __location__);
++	}
++
++	/*
++	 * we need to keep up to 7 bytes
++	 * in order to get the aligment right.
++	 */
++	skip = ndr->offset & 0xFFFFFFF8;
++
++	if (skip == 0) {
++		return NDR_ERR_SUCCESS;
++	}
++
++	ndr->offset -= skip;
++	ndr->data_size -= skip;
++
++	append = ndr_token_peek(&ndr->array_size_list, ndr);
++	if (append != UINT32_MAX) {
++		/*
++		 * here we assume, that ndr->data is not a
++		 * talloc child of ndr.
++		 */
++		ndr->data += skip;
++		return NDR_ERR_SUCCESS;
++	}
++
++	memmove(ndr->data, ndr->data + skip, ndr->data_size);
++
++	ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
++	if (ndr->data_size != 0 && ndr->data == NULL) {
++		return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
++	}
++
++	return NDR_ERR_SUCCESS;
++}
++
+ /*
+   advance by 'size' bytes
+ */
+@@ -167,6 +272,38 @@ _PUBLIC_ enum ndr_err_code ndr_push_expa
+ 	return NDR_ERR_SUCCESS;
+ }
+ 
++_PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
++{
++	va_list ap;
++	char *s = NULL;
++	uint32_t i;
++	int ret;
++	int dbgc_class;
++
++	va_start(ap, format);
++	ret = vasprintf(&s, format, ap);
++	va_end(ap);
++
++	if (ret == -1) {
++		return;
++	}
++
++	dbgc_class = *(int *)ndr->private_data;
++
++	if (ndr->no_newline) {
++		DEBUGADDC(dbgc_class, 1,("%s", s));
++		free(s);
++		return;
++	}
++
++	for (i=0;i<ndr->depth;i++) {
++		DEBUGADDC(dbgc_class, 1,("    "));
++	}
++
++	DEBUGADDC(dbgc_class, 1,("%s\n", s));
++	free(s);
++}
++
+ _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) 
+ {
+ 	va_list ap;
+@@ -238,6 +375,25 @@ _PUBLIC_ void ndr_print_string_helper(st
+ }
+ 
+ /*
++  a useful helper function for printing idl structures via DEBUGC()
++*/
++_PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
++{
++	struct ndr_print *ndr;
++
++	DEBUGC(dbgc_class, 1,(" "));
++
++	ndr = talloc_zero(NULL, struct ndr_print);
++	if (!ndr) return;
++	ndr->private_data = &dbgc_class;
++	ndr->print = ndr_print_debugc_helper;
++	ndr->depth = 1;
++	ndr->flags = 0;
++	fn(ndr, name, ptr);
++	talloc_free(ndr);
++}
++
++/*
+   a useful helper function for printing idl structures via DEBUG()
+ */
+ _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
+@@ -403,6 +559,15 @@ _PUBLIC_ enum ndr_err_code ndr_pull_erro
+ 	va_list ap;
+ 	int ret;
+ 
++	if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
++		switch (ndr_err) {
++		case NDR_ERR_BUFSIZE:
++			return NDR_ERR_INCOMPLETE_BUFFER;
++		default:
++			break;
++		}
++	}
++
+ 	va_start(ap, format);
+ 	ret = vasprintf(&s, format, ap);
+ 	va_end(ap);
+@@ -557,6 +722,23 @@ _PUBLIC_ enum ndr_err_code ndr_pull_subc
+ 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
+ 		break;
+ 	}
++	case 0xFFFFFFFF:
++		/*
++		 * a shallow copy like subcontext
++		 * useful for DCERPC pipe chunks.
++		 */
++		subndr = talloc_zero(ndr, struct ndr_pull);
++		NDR_ERR_HAVE_NO_MEMORY(subndr);
++
++		subndr->flags		= ndr->flags;
++		subndr->current_mem_ctx	= ndr->current_mem_ctx;
++		subndr->data		= ndr->data;
++		subndr->offset		= ndr->offset;
++		subndr->data_size	= ndr->data_size;
++
++		*_subndr = subndr;
++		return NDR_ERR_SUCCESS;
++
+ 	default:
+ 		return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d", 
+ 				      (int)header_size);
+@@ -589,13 +771,35 @@ _PUBLIC_ enum ndr_err_code ndr_pull_subc
+ 				 ssize_t size_is)
+ {
+ 	uint32_t advance;
+-	if (size_is >= 0) {
++	uint32_t highest_ofs;
++
++	if (header_size == 0xFFFFFFFF) {
++		advance = subndr->offset - ndr->offset;
++	} else if (size_is >= 0) {
+ 		advance = size_is;
+ 	} else if (header_size > 0) {
+ 		advance = subndr->data_size;
+ 	} else {
+ 		advance = subndr->offset;
+ 	}
++
++	if (subndr->offset > ndr->relative_highest_offset) {
++		highest_ofs = subndr->offset;
++	} else {
++		highest_ofs = subndr->relative_highest_offset;
++	}
++	if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
++		/*
++		 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
++		 */
++		highest_ofs = advance;
++	}
++	if (highest_ofs < advance) {
++		return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
++				      "not all bytes consumed ofs[%u] advance[%u]",
++				      highest_ofs, advance);
++	}
++
+ 	NDR_CHECK(ndr_pull_advance(ndr, advance));
+ 	return NDR_ERR_SUCCESS;
+ }
+@@ -1440,6 +1644,7 @@ const static struct {
+ 	{ NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
+ 	{ NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
+ 	{ NDR_ERR_NDR64, "NDR64 assertion error" },
++	{ NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
+ 	{ 0, NULL }
+ };
+ 
+--- a/librpc/idl/idl_types.h
++++ b/librpc/idl/idl_types.h
+@@ -47,3 +47,5 @@
+ 
+ #define NDR_RELATIVE_REVERSE LIBNDR_FLAG_RELATIVE_REVERSE
+ #define NDR_NO_RELATIVE_REVERSE LIBNDR_FLAG_NO_RELATIVE_REVERSE
++
++#define NDR_SUBCONTEXT_NO_UNREAD_BYTES LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES
+--- a/librpc/idl/dcerpc.idl
++++ b/librpc/idl/dcerpc.idl
+@@ -10,6 +10,8 @@
+ */
+ import "misc.idl";
+ 
++cpp_quote("extern const uint8_t DCERPC_SEC_VT_MAGIC[8];")
++
+ interface dcerpc
+ {
+ 	typedef struct {
+@@ -453,14 +455,21 @@ interface dcerpc
+ 	} dcerpc_payload;
+ 
+ 	/* pfc_flags values */
+-	const uint8 DCERPC_PFC_FLAG_FIRST		= 0x01; /* First fragment */
+-	const uint8 DCERPC_PFC_FLAG_LAST		= 0x02; /* Last fragment */
+-	const uint8 DCERPC_PFC_FLAG_PENDING_CANCEL	= 0x04; /* Cancel was pending at sender */
+-	const uint8 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN	= DCERPC_PFC_FLAG_PENDING_CANCEL; /* depends on the pdu type */
+-	const uint8 DCERPC_PFC_FLAG_CONC_MPX		= 0x10; /* supports concurrent multiplexing of a single connection. */
+-	const uint8 DCERPC_PFC_FLAG_DID_NOT_EXECUTE	= 0x20; /* on a fault it means the server hasn't done anything */
+-	const uint8 DCERPC_PFC_FLAG_MAYBE		= 0x40; /* `maybe' call semantics requested */
+-	const uint8 DCERPC_PFC_FLAG_OBJECT_UUID		= 0x80; /* on valid guid is in the optional object field */
++	typedef [bitmap8bit] bitmap {
++		DCERPC_PFC_FLAG_FIRST		= 0x01, /* First fragment */
++		DCERPC_PFC_FLAG_LAST		= 0x02, /* Last fragment */
++		DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING = 0x04, /* depends on the pdu type */
++		DCERPC_PFC_FLAG_CONC_MPX	= 0x10, /* supports concurrent multiplexing of a single connection. */
++		DCERPC_PFC_FLAG_DID_NOT_EXECUTE	= 0x20, /* on a fault it means the server hasn't done anything */
++		DCERPC_PFC_FLAG_MAYBE		= 0x40, /* `maybe' call semantics requested */
++		DCERPC_PFC_FLAG_OBJECT_UUID	= 0x80 /* on valid guid is in the optional object field */
++	} dcerpc_pfc_flags;
++
++	/* Cancel was pending at sender */
++	const int DCERPC_PFC_FLAG_PENDING_CANCEL =
++		DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING;
++	const ist DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN =
++		DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING;
+ 
+ 	/* these offsets are needed by the signing code */
+ 	const uint8 DCERPC_PFC_OFFSET      =  3;
+@@ -468,6 +477,7 @@ interface dcerpc
+ 	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
+ 	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
+ 	const uint8 DCERPC_CALL_ID_OFFSET  = 12;
++	const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16;
+ 
+ 	/* little-endian flag */
+ 	const uint8 DCERPC_DREP_LE  = 0x10;
+@@ -476,7 +486,7 @@ interface dcerpc
+ 		uint8 rpc_vers;	        /* RPC version */
+ 		uint8 rpc_vers_minor;   /* Minor version */
+ 		dcerpc_pkt_type ptype;  /* Packet type */
+-		uint8 pfc_flags;        /* Fragmentation flags */
++		dcerpc_pfc_flags pfc_flags; /* Fragmentation flags */
+ 		uint8 drep[4];	        /* NDR data representation */
+ 		uint16 frag_length;     /* Total length of fragment */
+ 		uint16 auth_length;     /* authenticator length */
+@@ -506,4 +516,69 @@ interface dcerpc
+ 		uint8 serial_low;
+ 		[switch_is(ptype)] dcerpc_payload u;
+ 	} ncadg_packet;
++
++	typedef [bitmap16bit] bitmap {
++		DCERPC_SEC_VT_COMMAND_ENUM  = 0x3FFF,
++		DCERPC_SEC_VT_COMMAND_END   = 0x4000,
++		DCERPC_SEC_VT_MUST_PROCESS  = 0x8000
++	} dcerpc_sec_vt_command;
++
++	typedef [enum16bit] enum {
++		DCERPC_SEC_VT_COMMAND_BITMASK1  = 0x0001,
++		DCERPC_SEC_VT_COMMAND_PCONTEXT  = 0x0002,
++		DCERPC_SEC_VT_COMMAND_HEADER2   = 0x0003
++	} dcerpc_sec_vt_command_enum;
++
++	typedef [bitmap32bit] bitmap {
++		DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING = 0x00000001
++	} dcerpc_sec_vt_bitmask1;
++
++	typedef struct {
++		ndr_syntax_id abstract_syntax;
++		ndr_syntax_id transfer_syntax;
++	} dcerpc_sec_vt_pcontext;
++
++	typedef struct {
++		dcerpc_pkt_type ptype;  /* Packet type */
++		[value(0)] uint8 reserved1;
++		[value(0)] uint16 reserved2;
++		uint8 drep[4];          /* NDR data representation */
++		uint32 call_id;         /* Call identifier */
++		uint16 context_id;
++		uint16 opnum;
++	} dcerpc_sec_vt_header2;
++
++	typedef [switch_type(dcerpc_sec_vt_command_enum),nodiscriminant] union {
++	[case(DCERPC_SEC_VT_COMMAND_BITMASK1)] dcerpc_sec_vt_bitmask1 bitmask1;
++	[case(DCERPC_SEC_VT_COMMAND_PCONTEXT)] dcerpc_sec_vt_pcontext pcontext;
++	[case(DCERPC_SEC_VT_COMMAND_HEADER2)] dcerpc_sec_vt_header2 header2;
++	[default,flag(NDR_REMAINING)] DATA_BLOB _unknown;
++	} dcerpc_sec_vt_union;
++
++	typedef struct {
++		dcerpc_sec_vt_command command;
++		[switch_is(command & DCERPC_SEC_VT_COMMAND_ENUM)]
++			[subcontext(2),flag(NDR_SUBCONTEXT_NO_UNREAD_BYTES)]
++			dcerpc_sec_vt_union u;
++	} dcerpc_sec_vt;
++
++	typedef [public,nopush,nopull] struct {
++		uint16 count;
++	} dcerpc_sec_vt_count;
++
++	/*
++	 * We assume that the whole verification trailer fits into
++	 * the last 1024 bytes after the stub data.
++	 *
++	 * There're currently only 3 commands defined and each should
++	 * only be used once.
++	 */
++	const uint16 DCERPC_SEC_VT_MAX_SIZE = 1024;
++
++	typedef [public,flag(NDR_PAHEX)] struct {
++		[flag(NDR_ALIGN4)] DATA_BLOB _pad;
++		[value(DCERPC_SEC_VT_MAGIC)] uint8 magic[8];
++		dcerpc_sec_vt_count count;
++		dcerpc_sec_vt commands[count.count];
++	} dcerpc_sec_verification_trailer;
+ }
+--- /dev/null
++++ b/librpc/ndr/ndr_dcerpc.c
+@@ -0,0 +1,187 @@
++/*
++   Unix SMB/CIFS implementation.
++
++   Manually parsed structures found in the DCERPC protocol
++
++   Copyright (C) Stefan Metzmacher 2014
++   Copyright (C) Gregor Beck 2014
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "includes.h"
++#include "librpc/gen_ndr/ndr_dcerpc.h"
++
++#include "librpc/gen_ndr/ndr_misc.h"
++#include "lib/util/bitmap.h"
++
++const uint8_t DCERPC_SEC_VT_MAGIC[] = {0x8a,0xe3,0x13,0x71,0x02,0xf4,0x36,0x71};
++
++_PUBLIC_ enum ndr_err_code ndr_push_dcerpc_sec_vt_count(struct ndr_push *ndr, int ndr_flags, const struct dcerpc_sec_vt_count *r)
++{
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
++	/* nothing */
++	return NDR_ERR_SUCCESS;
++}
++
++_PUBLIC_ enum ndr_err_code ndr_pull_dcerpc_sec_vt_count(struct ndr_pull *ndr, int ndr_flags, struct dcerpc_sec_vt_count *r)
++{
++	uint32_t _saved_ofs = ndr->offset;
++
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
++
++	if (!(ndr_flags & NDR_SCALARS)) {
++		return NDR_ERR_SUCCESS;
++	}
++
++	r->count = 0;
++
++	while (true) {
++		uint16_t command;
++		uint16_t length;
++
++		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &command));
++		NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &length));
++		NDR_CHECK(ndr_pull_advance(ndr, length));
++
++		r->count += 1;
++
++		if (command & DCERPC_SEC_VT_COMMAND_END) {
++			break;
++		}
++	}
++
++	ndr->offset = _saved_ofs;
++	return NDR_ERR_SUCCESS;
++}
++
++_PUBLIC_ enum ndr_err_code ndr_pop_dcerpc_sec_verification_trailer(
++	struct ndr_pull *ndr, TALLOC_CTX *mem_ctx,
++	struct dcerpc_sec_verification_trailer **_r)
++{
++	enum ndr_err_code ndr_err;
++	uint32_t ofs;
++	uint32_t min_ofs = 0;
++	struct dcerpc_sec_verification_trailer *r;
++	DATA_BLOB sub_blob = data_blob_null;
++	struct ndr_pull *sub_ndr = NULL;
++	uint32_t remaining;
++
++	*_r = NULL;
++
++	r = talloc_zero(mem_ctx, struct dcerpc_sec_verification_trailer);
++	if (r == NULL) {
++		return NDR_ERR_ALLOC;
++	}
++
++	if (ndr->data_size < sizeof(DCERPC_SEC_VT_MAGIC)) {
++		/*
++		 * we return with r->count = 0
++		 */
++		*_r = r;
++		return NDR_ERR_SUCCESS;
++	}
++
++	ofs = ndr->data_size - sizeof(DCERPC_SEC_VT_MAGIC);
++	/* the magic is 4 byte aligned */
++	ofs &= ~3;
++
++	if (ofs > DCERPC_SEC_VT_MAX_SIZE) {
++		/*
++		 * We just scan the last 1024 bytes.
++		 */
++		min_ofs = ofs - DCERPC_SEC_VT_MAX_SIZE;
++	} else {
++		min_ofs = 0;
++	}
++
++	while (true) {
++		int ret;
++
++		ret = memcmp(&ndr->data[ofs],
++			     DCERPC_SEC_VT_MAGIC,
++			     sizeof(DCERPC_SEC_VT_MAGIC));
++		if (ret == 0) {
++			sub_blob = data_blob_const(&ndr->data[ofs],
++						   ndr->data_size - ofs);
++			break;
++		}
++
++		if (ofs <= min_ofs) {
++			break;
++		}
++
++		ofs -= 4;
++	}
++
++	if (sub_blob.length == 0) {
++		/*
++		 * we return with r->count = 0
++		 */
++		*_r = r;
++		return NDR_ERR_SUCCESS;
++	}
++
++	sub_ndr = ndr_pull_init_blob(&sub_blob, r);
++	if (sub_ndr == NULL) {
++		TALLOC_FREE(r);
++		return NDR_ERR_ALLOC;
++	}
++
++	ndr_err = ndr_pull_dcerpc_sec_verification_trailer(sub_ndr,
++							   NDR_SCALARS | NDR_BUFFERS,
++							   r);
++	if (ndr_err == NDR_ERR_ALLOC) {
++		TALLOC_FREE(r);
++		return NDR_ERR_ALLOC;
++	}
++
++	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
++		goto ignore_error;
++	}
++
++	remaining = sub_ndr->data_size - sub_ndr->offset;
++	if (remaining > 16) {
++		/*
++		 * we expect not more than 16 byte of additional
++		 * padding after the verification trailer.
++		 */
++		goto ignore_error;
++	}
++
++	/*
++	 * We assume that we got a real verification trailer.
++	 *
++	 * We remove it from the available stub data.
++	 */
++	ndr->data_size = ofs;
++
++	TALLOC_FREE(sub_ndr);
++
++	*_r = r;
++	return NDR_ERR_SUCCESS;
++
++ignore_error:
++	TALLOC_FREE(sub_ndr);
++	/*
++	 * just ignore the error, it's likely
++	 * that the magic we found belongs to
++	 * the stub data.
++	 *
++	 * we return with r->count = 0
++	 */
++	ZERO_STRUCTP(r);
++	*_r = r;
++	return NDR_ERR_SUCCESS;
++}
+--- a/librpc/wscript_build
++++ b/librpc/wscript_build
+@@ -274,8 +274,9 @@ bld.SAMBA_SUBSYSTEM('NDR_COMPRESSION',
+ 	)
+ 
+ bld.SAMBA_SUBSYSTEM('NDR_DCERPC',
+-	source='gen_ndr/ndr_dcerpc.c',
++	source='gen_ndr/ndr_dcerpc.c ndr/ndr_dcerpc.c',
+ 	public_deps='ndr',
++	deps='bitmap',
+ 	public_headers='gen_ndr/ndr_dcerpc.h gen_ndr/dcerpc.h',
+ 	header_path= [ ('*gen_ndr*', 'gen_ndr') ],
+ 	)
+--- a/source3/Makefile.in
++++ b/source3/Makefile.in
+@@ -323,7 +323,8 @@ LIBNDR_OBJ = ../librpc/ndr/ndr_basic.o \
+ 	     ../librpc/ndr/uuid.o \
+ 	     librpc/ndr/util.o \
+ 	     librpc/gen_ndr/ndr_server_id.o \
+-	     librpc/gen_ndr/ndr_dcerpc.o
++	     librpc/gen_ndr/ndr_dcerpc.o \
++	     ../librpc/ndr/ndr_dcerpc.o
+ 
+ LIBNDR_GEN_OBJ0 = librpc/gen_ndr/ndr_samr.o \
+ 		  librpc/gen_ndr/ndr_lsa.o
+@@ -454,7 +455,7 @@ LIB_OBJ = $(LIBSAMBAUTIL_OBJ) $(UTIL_OBJ
+ 	  lib/username.o \
+ 	  ../libds/common/flag_mapping.o \
+ 	  lib/access.o lib/smbrun.o \
+-	  lib/bitmap.o lib/dprintf.o $(UTIL_REG_OBJ) \
++	  ../lib/util/bitmap.o lib/dprintf.o $(UTIL_REG_OBJ) \
+ 	  lib/wins_srv.o \
+ 	  lib/util_str.o lib/clobber.o lib/util_sid.o \
+ 	  lib/util_unistr.o ../lib/util/charset/codepoints.o lib/util_file.o \
+@@ -987,7 +988,9 @@ SWAT_OBJ = $(SWAT_OBJ1) $(PARAM_OBJ) $(P
+ 	   $(POPT_LIB_OBJ) $(SMBLDAP_OBJ) $(LIBMSRPC_GEN_OBJ) $(LIBMSRPC_OBJ) \
+            $(PASSCHANGE_OBJ) $(FNAME_UTIL_OBJ) \
+ 	   $(LIBCLI_SAMR_OBJ) \
+-	   rpc_client/init_lsa.o
++	   $(LIBCLI_NETLOGON_OBJ) \
++	   rpc_client/init_lsa.o \
++	   rpc_client/init_netlogon.o
+ 
+ STATUS_OBJ = utils/status.o utils/status_profile.o \
+ 	     $(LOCKING_OBJ) $(PARAM_OBJ) \
+@@ -1003,7 +1006,9 @@ SMBTREE_OBJ = utils/smbtree.o $(PARAM_OB
+ 	     $(PASSDB_OBJ) $(SMBLDAP_OBJ) $(GROUPDB_OBJ) \
+ 	     $(LIBMSRPC_GEN_OBJ) \
+ 	     $(LIBMSRPC_OBJ) \
+-	     $(LIBCLI_SRVSVC_OBJ)
++	     $(LIBCLI_SRVSVC_OBJ) \
++	     $(LIBCLI_NETLOGON_OBJ) \
++	     rpc_client/init_netlogon.o
+ 
+ TESTPARM_OBJ = utils/testparm.o \
+                $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+@@ -1025,7 +1030,9 @@ SMBPASSWD_OBJ = utils/smbpasswd.o $(PASS
+ 		$(POPT_LIB_OBJ) $(SMBLDAP_OBJ) \
+ 		$(LIBMSRPC_GEN_OBJ) $(LIBMSRPC_OBJ) \
+ 		$(LIBCLI_SAMR_OBJ) \
+-		rpc_client/init_lsa.o
++		$(LIBCLI_NETLOGON_OBJ) \
++		rpc_client/init_lsa.o \
++		rpc_client/init_netlogon.o
+ 
+ PDBEDIT_OBJ = utils/pdbedit.o $(PASSWD_UTIL_OBJ) $(PARAM_OBJ) $(PASSDB_OBJ) \
+ 		$(LIBSAMBA_OBJ) $(LIBTSOCKET_OBJ) \
+@@ -1098,7 +1105,9 @@ LIBSMBCLIENT_OBJ1 = $(LIBSMBCLIENT_OBJ0)
+ 		    $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ 		    $(PASSDB_OBJ) $(SMBLDAP_OBJ) $(GROUPDB_OBJ) \
+ 		    $(LIBCLI_SRVSVC_OBJ) \
+-		    $(LIBCLI_LSA_OBJ)
++		    $(LIBCLI_LSA_OBJ) \
++		    $(LIBCLI_NETLOGON_OBJ) \
++		    rpc_client/init_netlogon.o
+ 
+ LIBSMBCLIENT_OBJ = $(LIBSMBCLIENT_OBJ1)
+ 
+@@ -1121,7 +1130,9 @@ CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ)
+              $(READLINE_OBJ) $(POPT_LIB_OBJ) \
+              $(PASSDB_OBJ) $(SMBLDAP_OBJ) $(GROUPDB_OBJ) \
+ 	     $(DISPLAY_SEC_OBJ) \
+-	     $(LIBCLI_SRVSVC_OBJ)
++	     $(LIBCLI_SRVSVC_OBJ) \
++	     $(LIBCLI_NETLOGON_OBJ) \
++	     rpc_client/init_netlogon.o
+ 
+ LIBSMBCONF_OBJ = ../lib/smbconf/smbconf.o \
+ 		 ../lib/smbconf/smbconf_util.o \
+@@ -1233,7 +1244,9 @@ SMBTORTURE_OBJ = $(SMBTORTURE_OBJ1) $(PA
+ 	@LIBWBCLIENT_STATIC@ \
+         torture/wbc_async.o \
+         ../nsswitch/wb_reqtrans.o \
+-	$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(LIBCLI_ECHO_OBJ)
++	$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(LIBCLI_ECHO_OBJ) \
++	$(LIBCLI_NETLOGON_OBJ) rpc_client/init_netlogon.o
++
+ 
+ MASKTEST_OBJ = torture/masktest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+                  $(LIB_NONSMBD_OBJ) \
+@@ -1268,14 +1281,18 @@ SMBCACLS_OBJ = utils/smbcacls.o $(PARAM_
+ 		$(KRBCLIENT_OBJ) $(LIB_NONSMBD_OBJ) \
+ 		$(PASSDB_OBJ) $(GROUPDB_OBJ) $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \
+ 		$(POPT_LIB_OBJ) $(SMBLDAP_OBJ) \
+-		$(LIBCLI_LSA_OBJ)
++		$(LIBCLI_LSA_OBJ) \
++		$(LIBCLI_NETLOGON_OBJ) \
++		rpc_client/init_netlogon.o
+ 
+ SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
+ 		$(PARAM_OBJ) \
+ 		$(LIB_NONSMBD_OBJ) \
+ 		$(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(POPT_LIB_OBJ) \
+ 		$(PASSDB_OBJ) $(SMBLDAP_OBJ) $(GROUPDB_OBJ) \
+-		$(LIBCLI_LSA_OBJ)
++		$(LIBCLI_LSA_OBJ) \
++		$(LIBCLI_NETLOGON_OBJ) \
++		rpc_client/init_netlogon.o
+ 
+ EVTLOGADM_OBJ0	= utils/eventlogadm.o
+ 
+--- a/librpc/ndr/ndr_basic.c
++++ b/librpc/ndr/ndr_basic.c
+@@ -61,6 +61,7 @@ _PUBLIC_ void ndr_check_padding(struct n
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_int8(struct ndr_pull *ndr, int ndr_flags, int8_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_NEED_BYTES(ndr, 1);
+ 	*v = (int8_t)CVAL(ndr->data, ndr->offset);
+ 	ndr->offset += 1;
+@@ -72,6 +73,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_int8
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_NEED_BYTES(ndr, 1);
+ 	*v = CVAL(ndr->data, ndr->offset);
+ 	ndr->offset += 1;
+@@ -83,6 +85,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_int16(struct ndr_pull *ndr, int ndr_flags, int16_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 2);
+ 	NDR_PULL_NEED_BYTES(ndr, 2);
+ 	*v = (uint16_t)NDR_SVAL(ndr, ndr->offset);
+@@ -95,6 +98,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_int1
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_uint16(struct ndr_pull *ndr, int ndr_flags, uint16_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 2);
+ 	NDR_PULL_NEED_BYTES(ndr, 2);
+ 	*v = NDR_SVAL(ndr, ndr->offset);
+@@ -107,6 +111,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_uint1632(struct ndr_pull *ndr, int ndr_flags, uint16_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) {
+ 		uint32_t v32 = 0;
+ 		enum ndr_err_code err = ndr_pull_uint32(ndr, ndr_flags, &v32);
+@@ -125,6 +130,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_int32(struct ndr_pull *ndr, int ndr_flags, int32_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 4);
+ 	NDR_PULL_NEED_BYTES(ndr, 4);
+ 	*v = NDR_IVALS(ndr, ndr->offset);
+@@ -137,6 +143,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_int3
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_uint32(struct ndr_pull *ndr, int ndr_flags, uint32_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 4);
+ 	NDR_PULL_NEED_BYTES(ndr, 4);
+ 	*v = NDR_IVAL(ndr, ndr->offset);
+@@ -151,6 +158,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_uint
+ {
+ 	uint64_t v64;
+ 	enum ndr_err_code err;
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	if (likely(!(ndr->flags & LIBNDR_FLAG_NDR64))) {
+ 		return ndr_pull_uint32(ndr, ndr_flags, v);
+ 	}
+@@ -169,6 +177,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_double(struct ndr_pull *ndr, int ndr_flags, double *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 8);
+ 	NDR_PULL_NEED_BYTES(ndr, 8);
+ 	memcpy(v, ndr->data+ndr->offset, 8);
+@@ -217,6 +226,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_ref_
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_udlong(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 4);
+ 	NDR_PULL_NEED_BYTES(ndr, 8);
+ 	*v = NDR_IVAL(ndr, ndr->offset);
+@@ -230,6 +240,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_udlo
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_udlongr(struct ndr_pull *ndr, int ndr_flags, uint64_t *v)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, 4);
+ 	NDR_PULL_NEED_BYTES(ndr, 8);
+ 	*v = ((uint64_t)NDR_IVAL(ndr, ndr->offset)) << 32;
+@@ -264,6 +275,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_hype
+ _PUBLIC_ enum ndr_err_code ndr_pull_pointer(struct ndr_pull *ndr, int ndr_flags, void* *v)
+ {
+ 	uintptr_t h;
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PULL_ALIGN(ndr, sizeof(h));
+ 	NDR_PULL_NEED_BYTES(ndr, sizeof(h));
+ 	memcpy(&h, ndr->data+ndr->offset, sizeof(h));
+@@ -278,6 +290,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_poin
+ _PUBLIC_ enum ndr_err_code ndr_pull_NTSTATUS(struct ndr_pull *ndr, int ndr_flags, NTSTATUS *status)
+ {
+ 	uint32_t v;
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ 	*status = NT_STATUS(v);
+ 	return NDR_ERR_SUCCESS;
+@@ -302,6 +315,7 @@ _PUBLIC_ void ndr_print_NTSTATUS(struct
+ _PUBLIC_ enum ndr_err_code ndr_pull_WERROR(struct ndr_pull *ndr, int ndr_flags, WERROR *status)
+ {
+ 	uint32_t v;
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ 	*status = W_ERROR(v);
+ 	return NDR_ERR_SUCCESS;
+@@ -414,6 +428,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_byte
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, int ndr_flags, uint8_t *data, uint32_t n)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	if (!(ndr_flags & NDR_SCALARS)) {
+ 		return NDR_ERR_SUCCESS;
+ 	}
+@@ -425,6 +440,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_arra
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_int8(struct ndr_push *ndr, int ndr_flags, int8_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_NEED_BYTES(ndr, 1);
+ 	SCVAL(ndr->data, ndr->offset, (uint8_t)v);
+ 	ndr->offset += 1;
+@@ -436,6 +452,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_int8
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_uint8(struct ndr_push *ndr, int ndr_flags, uint8_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_NEED_BYTES(ndr, 1);
+ 	SCVAL(ndr->data, ndr->offset, v);
+ 	ndr->offset += 1;
+@@ -447,6 +464,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_int16(struct ndr_push *ndr, int ndr_flags, int16_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 2);
+ 	NDR_PUSH_NEED_BYTES(ndr, 2);
+ 	NDR_SSVAL(ndr, ndr->offset, (uint16_t)v);
+@@ -459,6 +477,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_int1
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_uint16(struct ndr_push *ndr, int ndr_flags, uint16_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 2);
+ 	NDR_PUSH_NEED_BYTES(ndr, 2);
+ 	NDR_SSVAL(ndr, ndr->offset, v);
+@@ -482,6 +501,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_int32(struct ndr_push *ndr, int ndr_flags, int32_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 4);
+ 	NDR_PUSH_NEED_BYTES(ndr, 4);
+ 	NDR_SIVALS(ndr, ndr->offset, v);
+@@ -494,6 +514,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_int3
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_uint32(struct ndr_push *ndr, int ndr_flags, uint32_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 4);
+ 	NDR_PUSH_NEED_BYTES(ndr, 4);
+ 	NDR_SIVAL(ndr, ndr->offset, v);
+@@ -517,6 +538,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_uint
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_udlong(struct ndr_push *ndr, int ndr_flags, uint64_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 4);
+ 	NDR_PUSH_NEED_BYTES(ndr, 8);
+ 	NDR_SIVAL(ndr, ndr->offset, (v & 0xFFFFFFFF));
+@@ -530,6 +552,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_udlo
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_udlongr(struct ndr_push *ndr, int ndr_flags, uint64_t v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 4);
+ 	NDR_PUSH_NEED_BYTES(ndr, 8);
+ 	NDR_SIVAL(ndr, ndr->offset, (v>>32));
+@@ -563,6 +586,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_hype
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_double(struct ndr_push *ndr, int ndr_flags, double v)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, 8);
+ 	NDR_PUSH_NEED_BYTES(ndr, 8);
+ 	memcpy(ndr->data+ndr->offset, &v, 8);
+@@ -576,6 +600,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_doub
+ _PUBLIC_ enum ndr_err_code ndr_push_pointer(struct ndr_push *ndr, int ndr_flags, void* v)
+ {
+ 	uintptr_t h = (intptr_t)v;
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_PUSH_ALIGN(ndr, sizeof(h));
+ 	NDR_PUSH_NEED_BYTES(ndr, sizeof(h));
+ 	memcpy(ndr->data+ndr->offset, &h, sizeof(h));
+@@ -686,6 +711,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_zero
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, int ndr_flags, const uint8_t *data, uint32_t n)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	if (!(ndr_flags & NDR_SCALARS)) {
+ 		return NDR_ERR_SUCCESS;
+ 	}
+@@ -738,6 +764,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_ref_
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_NTTIME(struct ndr_push *ndr, int ndr_flags, NTTIME t)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_push_udlong(ndr, ndr_flags, t));
+ 	return NDR_ERR_SUCCESS;
+ }
+@@ -747,6 +774,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_NTTI
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_NTTIME(struct ndr_pull *ndr, int ndr_flags, NTTIME *t)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_pull_udlong(ndr, ndr_flags, t));
+ 	return NDR_ERR_SUCCESS;
+ }
+@@ -756,6 +784,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_NTTI
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_NTTIME_1sec(struct ndr_push *ndr, int ndr_flags, NTTIME t)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	t /= 10000000;
+ 	NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t));
+ 	return NDR_ERR_SUCCESS;
+@@ -766,6 +795,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_NTTI
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_1sec(struct ndr_pull *ndr, int ndr_flags, NTTIME *t)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t));
+ 	(*t) *= 10000000;
+ 	return NDR_ERR_SUCCESS;
+@@ -776,6 +806,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_NTTI
+ */
+ _PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_hyper(struct ndr_pull *ndr, int ndr_flags, NTTIME *t)
+ {
++	NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t));
+ 	return NDR_ERR_SUCCESS;
+ }
+@@ -785,6 +816,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_NTTI
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_NTTIME_hyper(struct ndr_push *ndr, int ndr_flags, NTTIME t)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t));
+ 	return NDR_ERR_SUCCESS;
+ }
+@@ -814,6 +846,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_time
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_uid_t(struct ndr_push *ndr, int ndr_flags, uid_t u)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	return ndr_push_hyper(ndr, NDR_SCALARS, (uint64_t)u);
+ }
+ 
+@@ -839,6 +872,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_uid_
+ */
+ _PUBLIC_ enum ndr_err_code ndr_push_gid_t(struct ndr_push *ndr, int ndr_flags, gid_t g)
+ {
++	NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ 	return ndr_push_hyper(ndr, NDR_SCALARS, (uint64_t)g);
+ }
+ 
+--- a/source3/lib/bitmap.c
++++ /dev/null
+@@ -1,136 +0,0 @@
+-/*
+-   Unix SMB/CIFS implementation.
+-   simple bitmap functions
+-   Copyright (C) Andrew Tridgell 1992-1998
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License as published by
+-   the Free Software Foundation; either version 3 of the License, or
+-   (at your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful,
+-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-   GNU General Public License for more details.
+-
+-   You should have received a copy of the GNU General Public License
+-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-*/
+-
+-#include "includes.h"
+-
+-/* these functions provide a simple way to allocate integers from a
+-   pool without repetition */
+-
+-/****************************************************************************
+-talloc a bitmap
+-****************************************************************************/
+-struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n)
+-{
+-	struct bitmap *bm;
+-
+-	bm = TALLOC_P(mem_ctx, struct bitmap);
+-
+-	if (!bm) return NULL;
+-
+-	bm->n = n;
+-	bm->b = TALLOC_ZERO_ARRAY(bm, uint32, (n+31)/32);
+-	if (!bm->b) {
+-		TALLOC_FREE(bm);
+-		return NULL;
+-	}
+-	return bm;
+-}
+-
+-/****************************************************************************
+-copy as much of the source bitmap as will fit in the destination bitmap.
+-****************************************************************************/
+-
+-int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src)
+-{
+-        int count = MIN(dst->n, src->n);
+-
+-        SMB_ASSERT(dst->b != src->b);
+-	memcpy(dst->b, src->b, sizeof(uint32)*((count+31)/32));
+-
+-        return count;
+-}
+-
+-/****************************************************************************
+-set a bit in a bitmap
+-****************************************************************************/
+-bool bitmap_set(struct bitmap *bm, unsigned i)
+-{
+-	if (i >= bm->n) {
+-		DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
+-		      i, bm->n));
+-		return False;
+-	}
+-	bm->b[i/32] |= (1<<(i%32));
+-	return True;
+-}
+-
+-/****************************************************************************
+-clear a bit in a bitmap
+-****************************************************************************/
+-bool bitmap_clear(struct bitmap *bm, unsigned i)
+-{
+-	if (i >= bm->n) {
+-		DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
+-		      i, bm->n));
+-		return False;
+-	}
+-	bm->b[i/32] &= ~(1<<(i%32));
+-	return True;
+-}
+-
+-/****************************************************************************
+-query a bit in a bitmap
+-****************************************************************************/
+-bool bitmap_query(struct bitmap *bm, unsigned i)
+-{
+-	if (i >= bm->n) return False;
+-	if (bm->b[i/32] & (1<<(i%32))) {
+-		return True;
+-	}
+-	return False;
+-}
+-
+-/****************************************************************************
+-find a zero bit in a bitmap starting at the specified offset, with
+-wraparound
+-****************************************************************************/
+-int bitmap_find(struct bitmap *bm, unsigned ofs)
+-{
+-	unsigned int i, j;
+-
+-	if (ofs > bm->n) ofs = 0;
+-
+-	i = ofs;
+-	while (i < bm->n) {
+-		if (~(bm->b[i/32])) {
+-			j = i;
+-			do {
+-				if (!bitmap_query(bm, j)) return j;
+-				j++;
+-			} while (j & 31 && j < bm->n);
+-		}
+-		i += 32;
+-		i &= ~31;
+-	}
+-
+-	i = 0;
+-	while (i < ofs) {
+-		if (~(bm->b[i/32])) {
+-			j = i;
+-			do {
+-				if (!bitmap_query(bm, j)) return j;
+-				j++;
+-			} while (j & 31 && j < bm->n);
+-		}
+-		i += 32;
+-		i &= ~31;
+-	}
+-
+-	return -1;
+-}
+--- /dev/null
++++ b/lib/util/bitmap.c
+@@ -0,0 +1,137 @@
++/*
++   Unix SMB/CIFS implementation.
++   simple bitmap functions
++   Copyright (C) Andrew Tridgell 1992-1998
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "includes.h"
++#include "lib/util/bitmap.h"
++
++/* these functions provide a simple way to allocate integers from a
++   pool without repetition */
++
++/****************************************************************************
++talloc a bitmap
++****************************************************************************/
++struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n)
++{
++	struct bitmap *bm;
++
++	bm = talloc_zero(mem_ctx, struct bitmap);
++
++	if (!bm) return NULL;
++
++	bm->n = n;
++	bm->b = talloc_zero_array(bm, uint32_t, (n+31)/32);
++	if (!bm->b) {
++		TALLOC_FREE(bm);
++		return NULL;
++	}
++	return bm;
++}
++
++/****************************************************************************
++copy as much of the source bitmap as will fit in the destination bitmap.
++****************************************************************************/
++
++int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src)
++{
++        int count = MIN(dst->n, src->n);
++
++        SMB_ASSERT(dst->b != src->b);
++	memcpy(dst->b, src->b, sizeof(uint32_t)*((count+31)/32));
++
++        return count;
++}
++
++/****************************************************************************
++set a bit in a bitmap
++****************************************************************************/
++bool bitmap_set(struct bitmap *bm, unsigned i)
++{
++	if (i >= bm->n) {
++		DEBUG(0,("Setting invalid bitmap entry %d (of %d)\n",
++		      i, bm->n));
++		return false;
++	}
++	bm->b[i/32] |= (1<<(i%32));
++	return true;
++}
++
++/****************************************************************************
++clear a bit in a bitmap
++****************************************************************************/
++bool bitmap_clear(struct bitmap *bm, unsigned i)
++{
++	if (i >= bm->n) {
++		DEBUG(0,("clearing invalid bitmap entry %d (of %d)\n",
++		      i, bm->n));
++		return false;
++	}
++	bm->b[i/32] &= ~(1<<(i%32));
++	return true;
++}
++
++/****************************************************************************
++query a bit in a bitmap
++****************************************************************************/
++bool bitmap_query(struct bitmap *bm, unsigned i)
++{
++	if (i >= bm->n) return false;
++	if (bm->b[i/32] & (1<<(i%32))) {
++		return true;
++	}
++	return false;
++}
++
++/****************************************************************************
++find a zero bit in a bitmap starting at the specified offset, with
++wraparound
++****************************************************************************/
++int bitmap_find(struct bitmap *bm, unsigned ofs)
++{
++	unsigned int i, j;
++
++	if (ofs > bm->n) ofs = 0;
++
++	i = ofs;
++	while (i < bm->n) {
++		if (~(bm->b[i/32])) {
++			j = i;
++			do {
++				if (!bitmap_query(bm, j)) return j;
++				j++;
++			} while (j & 31 && j < bm->n);
++		}
++		i += 32;
++		i &= ~31;
++	}
++
++	i = 0;
++	while (i < ofs) {
++		if (~(bm->b[i/32])) {
++			j = i;
++			do {
++				if (!bitmap_query(bm, j)) return j;
++				j++;
++			} while (j & 31 && j < bm->n);
++		}
++		i += 32;
++		i &= ~31;
++	}
++
++	return -1;
++}
+--- /dev/null
++++ b/lib/util/bitmap.h
+@@ -0,0 +1,32 @@
++/*
++   Unix SMB/CIFS implementation.
++   simple bitmap functions
++   Copyright (C) Andrew Tridgell 1992-1998
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++/* The following definitions come from lib/bitmap.c  */
++
++struct bitmap {
++	uint32_t *b;
++	unsigned int n;
++};
++
++struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n);
++int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src);
++bool bitmap_set(struct bitmap *bm, unsigned i);
++bool bitmap_clear(struct bitmap *bm, unsigned i);
++bool bitmap_query(struct bitmap *bm, unsigned i);
++int bitmap_find(struct bitmap *bm, unsigned ofs);
+--- a/lib/util/wscript_build
++++ b/lib/util/wscript_build
+@@ -99,5 +99,11 @@ bld.SAMBA_LIBRARY('tdb-wrap',
+                   public_headers='tdb_wrap.h',
+                   private_library=True,
+                   local_include=False
+-                  )
++                 )
++
++bld.SAMBA_LIBRARY('bitmap',
++		  source='bitmap.c',
++		  deps='talloc samba-util',
++                  local_include=False,
++		  private_library=True)
+ 
+--- a/source3/include/proto.h
++++ b/source3/include/proto.h
+@@ -61,15 +61,6 @@ const char *audit_description_str(uint32
+ bool get_audit_category_from_param(const char *param, uint32 *audit_category);
+ const char *audit_policy_str(TALLOC_CTX *mem_ctx, uint32 policy);
+ 
+-/* The following definitions come from lib/bitmap.c  */
+-
+-struct bitmap *bitmap_talloc(TALLOC_CTX *mem_ctx, int n);
+-int bitmap_copy(struct bitmap * const dst, const struct bitmap * const src);
+-bool bitmap_set(struct bitmap *bm, unsigned i);
+-bool bitmap_clear(struct bitmap *bm, unsigned i);
+-bool bitmap_query(struct bitmap *bm, unsigned i);
+-int bitmap_find(struct bitmap *bm, unsigned ofs);
+-
+ /* The following definitions come from lib/charcnv.c  */
+ 
+ char lp_failed_convert_char(void);
+--- a/source3/include/smb.h
++++ b/source3/include/smb.h
+@@ -712,7 +712,6 @@ struct connections_data {
+ 	uint32 unused_compatitibility_field;
+ };
+ 
+-
+ /* the following are used by loadparm for option lists */
+ typedef enum {
+ 	P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_LIST,
+@@ -759,11 +758,6 @@ struct parm_struct {
+ #define FLAG_META	0x8000 /* A meta directive - not a real parameter */
+ #define FLAG_CMDLINE	0x10000 /* option has been overridden */
+ 
+-struct bitmap {
+-	uint32 *b;
+-	unsigned int n;
+-};
+-
+ /* offsets into message for common items */
+ #define smb_com 8
+ #define smb_rcls 9
+--- a/source3/modules/vfs_acl_common.c
++++ b/source3/modules/vfs_acl_common.c
+@@ -23,6 +23,7 @@
+ #include "system/filesys.h"
+ #include "../libcli/security/security.h"
+ #include "../librpc/gen_ndr/ndr_security.h"
++#include "../lib/util/bitmap.h"
+ 
+ static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
+ 			DATA_BLOB *pblob,
+--- a/source3/modules/vfs_full_audit.c
++++ b/source3/modules/vfs_full_audit.c
+@@ -64,6 +64,7 @@
+ #include "../librpc/gen_ndr/ndr_netlogon.h"
+ #include "auth.h"
+ #include "ntioctl.h"
++#include "lib/util/bitmap.h"
+ 
+ static int vfs_full_audit_debug_level = DBGC_VFS;
+ 
+--- a/source3/param/loadparm.c
++++ b/source3/param/loadparm.c
+@@ -64,6 +64,7 @@
+ #include "smb_signing.h"
+ #include "dbwrap.h"
+ #include "smbldap.h"
++#include "../lib/util/bitmap.h"
+ 
+ #ifdef HAVE_SYS_SYSCTL_H
+ #include <sys/sysctl.h>
+--- a/source3/passdb/pdb_get_set.c
++++ b/source3/passdb/pdb_get_set.c
+@@ -25,6 +25,7 @@
+ #include "passdb.h"
+ #include "../libcli/auth/libcli_auth.h"
+ #include "../libcli/security/security.h"
++#include "../lib/util/bitmap.h"
+ 
+ #undef DBGC_CLASS
+ #define DBGC_CLASS DBGC_PASSDB
+--- a/source3/smbd/conn.c
++++ b/source3/smbd/conn.c
+@@ -23,6 +23,7 @@
+ #include "smbd/smbd.h"
+ #include "smbd/globals.h"
+ #include "rpc_server/rpc_ncacn_np.h"
++#include "lib/util/bitmap.h"
+ 
+ /* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The
+  * maximum size of the bitmap is the largest positive integer, but you will hit
+--- a/source3/smbd/dir.c
++++ b/source3/smbd/dir.c
+@@ -23,6 +23,7 @@
+ #include "smbd/smbd.h"
+ #include "smbd/globals.h"
+ #include "libcli/security/security.h"
++#include "lib/util/bitmap.h"
+ 
+ /*
+    This module implements directory related functions for Samba.
+--- a/source3/smbd/files.c
++++ b/source3/smbd/files.c
+@@ -22,6 +22,7 @@
+ #include "smbd/globals.h"
+ #include "libcli/security/security.h"
+ #include "util_tdb.h"
++#include "lib/util/bitmap.h"
+ 
+ #define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < real_max_open_files))
+ 
+--- a/source3/smbd/smb2_server.c
++++ b/source3/smbd/smb2_server.c
+@@ -26,6 +26,7 @@
+ #include "../lib/tsocket/tsocket.h"
+ #include "../lib/util/tevent_ntstatus.h"
+ #include "smbprofile.h"
++#include "../lib/util/bitmap.h"
+ 
+ #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
+ 
+--- a/source3/rpc_client/cli_pipe.c
++++ b/source3/rpc_client/cli_pipe.c
+@@ -28,6 +28,7 @@
+ #include "../libcli/auth/ntlmssp.h"
+ #include "ntlmssp_wrap.h"
+ #include "librpc/gen_ndr/ndr_dcerpc.h"
++#include "librpc/gen_ndr/ndr_netlogon_c.h"
+ #include "librpc/rpc/dcerpc.h"
+ #include "librpc/crypto/gse.h"
+ #include "librpc/crypto/spnego.h"
+@@ -399,6 +400,7 @@ static NTSTATUS cli_pipe_validate_curren
+ 						struct ncacn_packet *pkt,
+ 						DATA_BLOB *pdu,
+ 						uint8_t expected_pkt_type,
++						uint32_t call_id,
+ 						DATA_BLOB *rdata,
+ 						DATA_BLOB *reply_pdu)
+ {
+@@ -497,7 +499,7 @@ static NTSTATUS cli_pipe_validate_curren
+ 			  "from %s!\n",
+ 			  (unsigned int)pkt->ptype,
+ 			  rpccli_pipe_txt(talloc_tos(), cli)));
+-		return NT_STATUS_INVALID_INFO_CLASS;
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
+ 	}
+ 
+ 	if (pkt->ptype != expected_pkt_type) {
+@@ -505,7 +507,15 @@ static NTSTATUS cli_pipe_validate_curren
+ 			  "RPC packet type - %u, not %u\n",
+ 			  rpccli_pipe_txt(talloc_tos(), cli),
+ 			  pkt->ptype, expected_pkt_type));
+-		return NT_STATUS_INVALID_INFO_CLASS;
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
++	if (pkt->call_id != call_id) {
++		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
++			  "RPC call_id - %u, not %u\n",
++			  rpccli_pipe_txt(talloc_tos(), cli),
++			  pkt->call_id, call_id));
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
+ 	}
+ 
+ 	/* Do this just before return - we don't want to modify any rpc header
+@@ -898,6 +908,7 @@ static void rpc_api_pipe_got_pdu(struct
+ 						state->cli, state->pkt,
+ 						&state->incoming_frag,
+ 						state->expected_pkt_type,
++						state->call_id,
+ 						&rdata,
+ 						&state->reply_pdu);
+ 
+@@ -1269,12 +1280,17 @@ struct rpc_api_pipe_req_state {
+ 	uint32_t call_id;
+ 	DATA_BLOB *req_data;
+ 	uint32_t req_data_sent;
++	DATA_BLOB req_trailer;
++	uint32_t req_trailer_sent;
++	bool verify_bitmask1;
++	bool verify_pcontext;
+ 	DATA_BLOB rpc_out;
+ 	DATA_BLOB reply_pdu;
+ };
+ 
+ static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
+ static void rpc_api_pipe_req_done(struct tevent_req *subreq);
++static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
+ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
+ 				  bool *is_last_frag);
+ 
+@@ -1310,6 +1326,11 @@ struct tevent_req *rpc_api_pipe_req_send
+ 		goto post_status;
+ 	}
+ 
++	status = prepare_verification_trailer(state);
++	if (!NT_STATUS_IS_OK(status)) {
++		goto post_status;
++	}
++
+ 	status = prepare_next_frag(state, &is_last_frag);
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		goto post_status;
+@@ -1344,25 +1365,161 @@ struct tevent_req *rpc_api_pipe_req_send
+ 	return NULL;
+ }
+ 
++static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
++{
++	struct pipe_auth_data *a = state->cli->auth;
++	struct dcerpc_sec_verification_trailer *t;
++	struct dcerpc_sec_vt *c = NULL;
++	struct ndr_push *ndr = NULL;
++	enum ndr_err_code ndr_err;
++	size_t align = 0;
++	size_t pad = 0;
++
++	if (a == NULL) {
++		return NT_STATUS_OK;
++	}
++
++	if (a->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
++		return NT_STATUS_OK;
++	}
++
++	t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
++	if (t == NULL) {
++		return NT_STATUS_NO_MEMORY;
++	}
++
++	if (!a->verified_bitmask1) {
++		t->commands = talloc_realloc(t, t->commands,
++					     struct dcerpc_sec_vt,
++					     t->count.count + 1);
++		if (t->commands == NULL) {
++			return NT_STATUS_NO_MEMORY;
++		}
++		c = &t->commands[t->count.count++];
++		ZERO_STRUCTP(c);
++
++		c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
++		state->verify_bitmask1 = true;
++	}
++
++	if (!state->cli->verified_pcontext) {
++		t->commands = talloc_realloc(t, t->commands,
++					     struct dcerpc_sec_vt,
++					     t->count.count + 1);
++		if (t->commands == NULL) {
++			return NT_STATUS_NO_MEMORY;
++		}
++		c = &t->commands[t->count.count++];
++		ZERO_STRUCTP(c);
++
++		c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
++		c->u.pcontext.abstract_syntax = state->cli->abstract_syntax;
++		c->u.pcontext.transfer_syntax = state->cli->transfer_syntax;
++
++		state->verify_pcontext = true;
++	}
++
++	if (true) { /* We do not support header signing */
++		t->commands = talloc_realloc(t, t->commands,
++					     struct dcerpc_sec_vt,
++					     t->count.count + 1);
++		if (t->commands == NULL) {
++			return NT_STATUS_NO_MEMORY;
++		}
++		c = &t->commands[t->count.count++];
++		ZERO_STRUCTP(c);
++
++		c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
++		c->u.header2.ptype = DCERPC_PKT_REQUEST;
++		c->u.header2.drep[0] = DCERPC_DREP_LE;
++		c->u.header2.drep[1] = 0;
++		c->u.header2.drep[2] = 0;
++		c->u.header2.drep[3] = 0;
++		c->u.header2.call_id = state->call_id;
++		c->u.header2.context_id = 0;
++		c->u.header2.opnum = state->op_num;
++	}
++
++	if (t->count.count == 0) {
++		TALLOC_FREE(t);
++		return NT_STATUS_OK;
++	}
++
++	c = &t->commands[t->count.count - 1];
++	c->command |= DCERPC_SEC_VT_COMMAND_END;
++
++	if (DEBUGLEVEL >= 10) {
++		NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
++	}
++
++	ndr = ndr_push_init_ctx(state);
++	if (ndr == NULL) {
++		return NT_STATUS_NO_MEMORY;
++	}
++
++	ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
++						NDR_SCALARS | NDR_BUFFERS,
++						t);
++	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
++		return ndr_map_error2ntstatus(ndr_err);
++	}
++	state->req_trailer = ndr_push_blob(ndr);
++
++	align = state->req_data->length & 0x3;
++	if (align > 0) {
++		pad = 4 - align;
++	}
++	if (pad > 0) {
++		bool ok;
++		uint8_t *p;
++		const uint8_t zeros[4] = { 0, };
++
++		ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
++		if (!ok) {
++			return NT_STATUS_NO_MEMORY;
++		}
++
++		/* move the padding to the start */
++		p = state->req_trailer.data;
++		memmove(p + pad, p, state->req_trailer.length - pad);
++		memset(p, 0, pad);
++	}
++
++	return NT_STATUS_OK;
++}
++
+ static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
+ 				  bool *is_last_frag)
+ {
+-	size_t data_sent_thistime;
+ 	size_t auth_len;
+ 	size_t frag_len;
+ 	uint8_t flags = 0;
+ 	size_t pad_len;
+ 	size_t data_left;
++	size_t data_thistime;
++	size_t trailer_left;
++	size_t trailer_thistime = 0;
++	size_t total_left;
++	size_t total_thistime;
+ 	NTSTATUS status;
++	bool ok;
+ 	union dcerpc_payload u;
+ 
+ 	data_left = state->req_data->length - state->req_data_sent;
++	trailer_left = state->req_trailer.length - state->req_trailer_sent;
++	total_left = data_left + trailer_left;
++	if ((total_left < data_left) || (total_left < trailer_left)) {
++		/*
++		 * overflow
++		 */
++		return NT_STATUS_INVALID_PARAMETER_MIX;
++	}
+ 
+ 	status = dcerpc_guess_sizes(state->cli->auth,
+-				    DCERPC_REQUEST_LENGTH, data_left,
++				    DCERPC_REQUEST_LENGTH, total_left,
+ 				    state->cli->max_xmit_frag,
+ 				    CLIENT_NDR_PADDING_SIZE,
+-				    &data_sent_thistime,
++				    &total_thistime,
+ 				    &frag_len, &auth_len, &pad_len);
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		return status;
+@@ -1372,15 +1529,20 @@ static NTSTATUS prepare_next_frag(struct
+ 		flags = DCERPC_PFC_FLAG_FIRST;
+ 	}
+ 
+-	if (data_sent_thistime == data_left) {
++	if (total_thistime == total_left) {
+ 		flags |= DCERPC_PFC_FLAG_LAST;
+ 	}
+ 
++	data_thistime = MIN(total_thistime, data_left);
++	if (data_thistime < total_thistime) {
++		trailer_thistime = total_thistime - data_thistime;
++	}
++
+ 	data_blob_free(&state->rpc_out);
+ 
+ 	ZERO_STRUCT(u.request);
+ 
+-	u.request.alloc_hint	= state->req_data->length;
++	u.request.alloc_hint	= total_left;
+ 	u.request.context_id	= 0;
+ 	u.request.opnum		= state->op_num;
+ 
+@@ -1400,11 +1562,26 @@ static NTSTATUS prepare_next_frag(struct
+ 	 * at this stage */
+ 	dcerpc_set_frag_length(&state->rpc_out, frag_len);
+ 
+-	/* Copy in the data. */
+-	if (!data_blob_append(NULL, &state->rpc_out,
++	if (data_thistime > 0) {
++		/* Copy in the data. */
++		ok = data_blob_append(NULL, &state->rpc_out,
+ 				state->req_data->data + state->req_data_sent,
+-				data_sent_thistime)) {
+-		return NT_STATUS_NO_MEMORY;
++				data_thistime);
++		if (!ok) {
++			return NT_STATUS_NO_MEMORY;
++		}
++		state->req_data_sent += data_thistime;
++	}
++
++	if (trailer_thistime > 0) {
++		/* Copy in the verification trailer. */
++		ok = data_blob_append(NULL, &state->rpc_out,
++				state->req_trailer.data + state->req_trailer_sent,
++				trailer_thistime);
++		if (!ok) {
++			return NT_STATUS_NO_MEMORY;
++		}
++		state->req_trailer_sent += trailer_thistime;
+ 	}
+ 
+ 	switch (state->cli->auth->auth_level) {
+@@ -1424,7 +1601,6 @@ static NTSTATUS prepare_next_frag(struct
+ 		return NT_STATUS_INVALID_PARAMETER;
+ 	}
+ 
+-	state->req_data_sent += data_sent_thistime;
+ 	*is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
+ 
+ 	return status;
+@@ -1488,6 +1664,20 @@ static void rpc_api_pipe_req_done(struct
+ 		tevent_req_nterror(req, status);
+ 		return;
+ 	}
++
++	if (state->cli->auth == NULL) {
++		tevent_req_done(req);
++		return;
++	}
++
++	if (state->verify_bitmask1) {
++		state->cli->auth->verified_bitmask1 = true;
++	}
++
++	if (state->verify_pcontext) {
++		state->cli->verified_pcontext = true;
++	}
++
+ 	tevent_req_done(req);
+ }
+ 
+@@ -1647,9 +1837,15 @@ struct rpc_pipe_bind_state {
+ 	DATA_BLOB rpc_out;
+ 	bool auth3;
+ 	uint32_t rpc_call_id;
++	struct netr_Authenticator auth;
++	struct netr_Authenticator return_auth;
++	struct netlogon_creds_CredentialState *creds;
++	union netr_Capabilities capabilities;
++	struct netr_LogonGetCapabilities r;
+ };
+ 
+ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq);
++static void rpc_pipe_bind_step_two_trigger(struct tevent_req *req);
+ static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
+ 				   struct rpc_pipe_bind_state *state,
+ 				   DATA_BLOB *credentials);
+@@ -1753,11 +1949,14 @@ static void rpc_pipe_bind_step_one_done(
+ 
+ 	case DCERPC_AUTH_TYPE_NONE:
+ 	case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
+-	case DCERPC_AUTH_TYPE_SCHANNEL:
+ 		/* Bind complete. */
+ 		tevent_req_done(req);
+ 		return;
+ 
++	case DCERPC_AUTH_TYPE_SCHANNEL:
++		rpc_pipe_bind_step_two_trigger(req);
++		return;
++
+ 	case DCERPC_AUTH_TYPE_NTLMSSP:
+ 	case DCERPC_AUTH_TYPE_SPNEGO:
+ 	case DCERPC_AUTH_TYPE_KRB5:
+@@ -1869,6 +2068,153 @@ err_out:
+ 	tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ }
+ 
++static void rpc_pipe_bind_step_two_done(struct tevent_req *subreq);
++
++static void rpc_pipe_bind_step_two_trigger(struct tevent_req *req)
++{
++	struct rpc_pipe_bind_state *state =
++		tevent_req_data(req,
++				struct rpc_pipe_bind_state);
++	struct dcerpc_binding_handle *b = state->cli->binding_handle;
++	struct schannel_state *schannel_auth =
++		talloc_get_type_abort(state->cli->auth->auth_ctx,
++				      struct schannel_state);
++	struct tevent_req *subreq;
++
++	if (schannel_auth == NULL ||
++	    !ndr_syntax_id_equal(&state->cli->abstract_syntax,
++				 &ndr_table_netlogon.syntax_id)) {
++		tevent_req_done(req);
++		return;
++	}
++
++	ZERO_STRUCT(state->return_auth);
++
++	state->creds = netlogon_creds_copy(state, schannel_auth->creds);
++	if (state->creds == NULL) {
++		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
++		return;
++	}
++
++	netlogon_creds_client_authenticator(state->creds, &state->auth);
++
++	state->r.in.server_name = state->cli->srv_name_slash;
++	state->r.in.computer_name = state->creds->computer_name;
++	state->r.in.credential = &state->auth;
++	state->r.in.query_level = 1;
++	state->r.in.return_authenticator = &state->return_auth;
++
++	state->r.out.capabilities = &state->capabilities;
++	state->r.out.return_authenticator = &state->return_auth;
++
++	subreq = dcerpc_netr_LogonGetCapabilities_r_send(talloc_tos(),
++							 state->ev,
++							 b,
++							 &state->r);
++	if (subreq == NULL) {
++		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
++		return;
++	}
++
++	tevent_req_set_callback(subreq, rpc_pipe_bind_step_two_done, req);
++	return;
++}
++
++static void rpc_pipe_bind_step_two_done(struct tevent_req *subreq)
++{
++	struct tevent_req *req =
++		tevent_req_callback_data(subreq,
++					 struct tevent_req);
++	struct rpc_pipe_bind_state *state =
++		tevent_req_data(req,
++				struct rpc_pipe_bind_state);
++	struct schannel_state *schannel_auth =
++		talloc_get_type_abort(state->cli->auth->auth_ctx,
++				      struct schannel_state);
++	NTSTATUS status;
++
++	status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, talloc_tos());
++	TALLOC_FREE(subreq);
++	if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
++		if (state->cli->dc->negotiate_flags &
++		    NETLOGON_NEG_SUPPORTS_AES) {
++			DEBUG(5, ("AES is not supported and the error was %s\n",
++				  nt_errstr(status)));
++			tevent_req_nterror(req,
++					   NT_STATUS_INVALID_NETWORK_RESPONSE);
++			return;
++		}
++
++		/* This is probably NT */
++		DEBUG(5, ("We are checking against an NT - %s\n",
++			  nt_errstr(status)));
++		tevent_req_done(req);
++		return;
++	} else if (!NT_STATUS_IS_OK(status)) {
++		DEBUG(0, ("dcerpc_netr_LogonGetCapabilities_r_recv failed with %s\n",
++			  nt_errstr(status)));
++		tevent_req_nterror(req, status);
++		return;
++	}
++
++	if (NT_STATUS_EQUAL(state->r.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
++		if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
++			/* This means AES isn't supported. */
++			DEBUG(5, ("AES is not supported and the error was %s\n",
++				  nt_errstr(state->r.out.result)));
++			tevent_req_nterror(req,
++					   NT_STATUS_INVALID_NETWORK_RESPONSE);
++			return;
++		}
++
++		/* This is probably an old Samba version */
++		DEBUG(5, ("We are checking against an old Samba version - %s\n",
++			  nt_errstr(state->r.out.result)));
++		tevent_req_done(req);
++		return;
++	}
++
++	/* We need to check the credential state here, cause win2k3 and earlier
++	 * returns NT_STATUS_NOT_IMPLEMENTED */
++	if (!netlogon_creds_client_check(state->creds,
++					 &state->r.out.return_authenticator->cred)) {
++		/*
++		 * Server replied with bad credential. Fail.
++		 */
++		DEBUG(0,("rpc_pipe_bind_step_two_done: server %s "
++			 "replied with bad credential\n",
++			 state->cli->desthost));
++		tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
++		return;
++	}
++
++	TALLOC_FREE(schannel_auth->creds);
++	schannel_auth->creds = talloc_steal(state->cli, state->creds);
++
++	if (!NT_STATUS_IS_OK(state->r.out.result)) {
++		DEBUG(0, ("dcerpc_netr_LogonGetCapabilities_r_recv failed with %s\n",
++			  nt_errstr(state->r.out.result)));
++		tevent_req_nterror(req, state->r.out.result);
++		return;
++	}
++
++	if (state->creds->negotiate_flags !=
++	    state->r.out.capabilities->server_capabilities) {
++		DEBUG(0, ("The client capabilities don't match the server "
++			  "capabilities: local[0x%08X] remote[0x%08X]\n",
++			  state->creds->negotiate_flags,
++			  state->capabilities.server_capabilities));
++		tevent_req_nterror(req,
++				   NT_STATUS_INVALID_NETWORK_RESPONSE);
++		return;
++	}
++
++	/* TODO: Add downgrade dectection. */
++
++	tevent_req_done(req);
++	return;
++}
++
+ static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
+ 				   struct rpc_pipe_bind_state *state,
+ 				   DATA_BLOB *auth_token)
+--- a/source3/librpc/rpc/dcerpc.h
++++ b/source3/librpc/rpc/dcerpc.h
+@@ -39,6 +39,7 @@ struct NL_AUTH_MESSAGE;
+ struct pipe_auth_data {
+ 	enum dcerpc_AuthType auth_type;
+ 	enum dcerpc_AuthLevel auth_level;
++	bool verified_bitmask1;
+ 
+ 	void *auth_ctx;
+ 
+--- a/source3/rpc_client/rpc_client.h
++++ b/source3/rpc_client/rpc_client.h
+@@ -39,6 +39,7 @@ struct rpc_pipe_client {
+ 
+ 	struct ndr_syntax_id abstract_syntax;
+ 	struct ndr_syntax_id transfer_syntax;
++	bool verified_pcontext;
+ 
+ 	char *desthost;
+ 	char *srv_name_slash;
+--- /dev/null
++++ b/librpc/ndr/ndr_dcerpc.h
+@@ -0,0 +1,25 @@
++/*
++   Unix SMB/CIFS implementation.
++
++   Manually parsed structures found in the DCERPC protocol
++
++   Copyright (C) Stefan Metzmacher 2014
++   Copyright (C) Gregor Beck 2014
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++enum ndr_err_code ndr_pop_dcerpc_sec_verification_trailer(
++	struct ndr_pull *ndr, TALLOC_CTX *mem_ctx,
++	struct dcerpc_sec_verification_trailer **_r);
+--- /dev/null
++++ b/librpc/ABI/ndr-0.0.3.sigs
+@@ -0,0 +1,251 @@
++GUID_all_zero: bool (const struct GUID *)
++GUID_compare: int (const struct GUID *, const struct GUID *)
++GUID_equal: bool (const struct GUID *, const struct GUID *)
++GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
++GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
++GUID_from_string: NTSTATUS (const char *, struct GUID *)
++GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
++GUID_random: struct GUID (void)
++GUID_string: char *(TALLOC_CTX *, const struct GUID *)
++GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
++GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
++GUID_zero: struct GUID (void)
++ndr_align_size: size_t (uint32_t, size_t)
++ndr_charset_length: uint32_t (const void *, charset_t)
++ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
++ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
++ndr_check_padding: void (struct ndr_pull *, size_t)
++ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
++ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
++ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
++ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
++ndr_map_error2errno: int (enum ndr_err_code)
++ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
++ndr_map_error2string: const char *(enum ndr_err_code)
++ndr_policy_handle_empty: bool (const struct policy_handle *)
++ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
++ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
++ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
++ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
++ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
++ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
++ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
++ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
++ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
++ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
++ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
++ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
++ndr_print_bool: void (struct ndr_print *, const char *, const bool)
++ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
++ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
++ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
++ndr_print_double: void (struct ndr_print *, const char *, double)
++ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
++ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
++ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
++ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
++ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
++ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
++ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
++ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
++ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
++ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
++ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
++ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
++ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
++ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
++ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
++ndr_print_null: void (struct ndr_print *)
++ndr_print_pointer: void (struct ndr_print *, const char *, void *)
++ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
++ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
++ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
++ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
++ndr_print_string: void (struct ndr_print *, const char *, const char *)
++ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
++ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
++ndr_print_struct: void (struct ndr_print *, const char *, const char *)
++ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
++ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
++ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
++ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
++ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
++ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
++ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
++ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
++ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
++ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
++ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
++ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
++ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
++ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
++ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
++ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
++ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
++ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
++ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
++ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
++ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
++ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
++ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
++ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
++ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
++ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
++ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
++ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
++ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
++ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
++ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
++ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
++ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
++ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
++ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
++ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
++ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
++ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
++ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
++ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
++ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
++ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
++ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
++ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
++ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
++ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
++ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
++ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
++ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
++ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
++ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
++ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
++ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
++ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
++ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
++ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
++ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
++ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
++ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
++ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
++ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
++ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
++ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
++ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
++ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
++ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
++ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
++ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
++ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
++ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
++ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
++ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
++ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
++ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
++ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
++ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
++ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
++ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
++ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
++ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
++ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
++ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
++ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
++ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
++ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
++ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
++ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
++ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
++ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
++ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
++ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
++ndr_push_blob: DATA_BLOB (struct ndr_push *)
++ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
++ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
++ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
++ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
++ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
++ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
++ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
++ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
++ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
++ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
++ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
++ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
++ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
++ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
++ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
++ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
++ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
++ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
++ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
++ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
++ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
++ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
++ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
++ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
++ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
++ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
++ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
++ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
++ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
++ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
++ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
++ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
++ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
++ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
++ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
++ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
++ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
++ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
++ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
++ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
++ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
++ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
++ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
++ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
++ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
++ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
++ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
++ndr_set_flags: void (uint32_t *, uint32_t)
++ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
++ndr_size_GUID: size_t (const struct GUID *, int)
++ndr_size_string: uint32_t (int, const char * const *, int)
++ndr_size_string_array: size_t (const char **, uint32_t, int)
++ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
++ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
++ndr_string_array_size: size_t (struct ndr_push *, const char *)
++ndr_string_length: uint32_t (const void *, uint32_t)
++ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
++ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
++ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
++ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
++ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
++ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
++ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
++ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
++ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
++ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+--- a/librpc/ndr/ndr_misc.c
++++ b/librpc/ndr/ndr_misc.c
+@@ -35,3 +35,50 @@ bool ndr_syntax_id_equal(const struct nd
+ 	return GUID_equal(&i1->uuid, &i2->uuid)
+ 		&& (i1->if_version == i2->if_version);
+ }
++
++_PUBLIC_ char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id)
++{
++	return talloc_asprintf(mem_ctx,
++			       "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x/0x%08x",
++			       id->uuid.time_low, id->uuid.time_mid,
++			       id->uuid.time_hi_and_version,
++			       id->uuid.clock_seq[0],
++			       id->uuid.clock_seq[1],
++			       id->uuid.node[0], id->uuid.node[1],
++			       id->uuid.node[2], id->uuid.node[3],
++			       id->uuid.node[4], id->uuid.node[5],
++			       (unsigned)id->if_version);
++}
++
++_PUBLIC_ bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id)
++{
++	int ret;
++	size_t i;
++	uint32_t time_low;
++	uint32_t time_mid, time_hi_and_version;
++	uint32_t clock_seq[2];
++	uint32_t node[6];
++	uint32_t if_version;
++
++	ret = sscanf(s,
++		     "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x/0x%08x",
++		     &time_low, &time_mid, &time_hi_and_version,
++		     &clock_seq[0], &clock_seq[1],
++		     &node[0], &node[1], &node[2], &node[3], &node[4], &node[5],
++		     &if_version);
++	if (ret != 12) {
++		return false;
++	}
++
++	id->uuid.time_low = time_low;
++	id->uuid.time_mid = time_mid;
++	id->uuid.time_hi_and_version = time_hi_and_version;
++	id->uuid.clock_seq[0] = clock_seq[0];
++	id->uuid.clock_seq[1] = clock_seq[1];
++	for (i=0; i<6; i++) {
++		id->uuid.node[i] = node[i];
++	}
++	id->if_version = if_version;
++
++	return true;
++}
+--- a/librpc/rpc/dcerpc_util.c
++++ b/librpc/rpc/dcerpc_util.c
+@@ -27,6 +27,7 @@
+ #include "librpc/rpc/dcerpc.h"
+ #include "librpc/gen_ndr/ndr_dcerpc.h"
+ #include "rpc_common.h"
++#include "lib/util/bitmap.h"
+ 
+ /* we need to be able to get/set the fragment length without doing a full
+    decode */
+@@ -341,3 +342,194 @@ NTSTATUS dcerpc_read_ncacn_packet_recv(s
+ 	tevent_req_received(req);
+ 	return NT_STATUS_OK;
+ }
++
++struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt)
++{
++	struct dcerpc_sec_vt_header2 ret;
++
++	ZERO_STRUCT(ret);
++	ret.ptype = pkt->ptype;
++	memcpy(&ret.drep, pkt->drep, sizeof(ret.drep));
++	ret.call_id = pkt->call_id;
++
++	switch (pkt->ptype) {
++	case DCERPC_PKT_REQUEST:
++		ret.context_id = pkt->u.request.context_id;
++		ret.opnum      = pkt->u.request.opnum;
++		break;
++
++	case DCERPC_PKT_RESPONSE:
++		ret.context_id = pkt->u.response.context_id;
++		break;
++
++	case DCERPC_PKT_FAULT:
++		ret.context_id = pkt->u.fault.context_id;
++		break;
++
++	default:
++		break;
++	}
++
++	return ret;
++}
++
++bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
++				 const struct dcerpc_sec_vt_header2 *v2)
++{
++	if (v1->ptype != v2->ptype) {
++		return false;
++	}
++
++	if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) {
++		return false;
++	}
++
++	if (v1->call_id != v2->call_id) {
++		return false;
++	}
++
++	if (v1->context_id != v2->context_id) {
++		return false;
++	}
++
++	if (v1->opnum != v2->opnum) {
++		return false;
++	}
++
++	return true;
++}
++
++static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
++{
++	bool ret = false;
++	TALLOC_CTX *frame = talloc_stackframe();
++	struct bitmap *commands_seen;
++	int i;
++
++	if (r->count.count == 0) {
++		ret = true;
++		goto done;
++	}
++
++	if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
++		goto done;
++	}
++
++	commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
++	if (commands_seen == NULL) {
++		goto done;
++	}
++
++	for (i=0; i < r->count.count; i++) {
++		enum dcerpc_sec_vt_command_enum cmd =
++			r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
++
++		if (bitmap_query(commands_seen, cmd)) {
++			/* Each command must appear at most once. */
++			goto done;
++		}
++		bitmap_set(commands_seen, cmd);
++
++		switch (cmd) {
++		case DCERPC_SEC_VT_COMMAND_BITMASK1:
++		case DCERPC_SEC_VT_COMMAND_PCONTEXT:
++		case DCERPC_SEC_VT_COMMAND_HEADER2:
++			break;
++		default:
++			if ((r->commands[i].u._unknown.length % 4) != 0) {
++				goto done;
++			}
++			break;
++		}
++	}
++	ret = true;
++done:
++	TALLOC_FREE(frame);
++	return ret;
++}
++
++#define CHECK(msg, ok)						\
++do {								\
++	if (!ok) {						\
++		DEBUG(10, ("SEC_VT check %s failed\n", msg));	\
++		return false;					\
++	}							\
++} while(0)
++
++#define CHECK_SYNTAX(msg, s1, s2)					\
++do {								\
++	if (!ndr_syntax_id_equal(&s1, &s2)) {				\
++		TALLOC_CTX *frame = talloc_stackframe();		\
++		DEBUG(10, ("SEC_VT check %s failed: %s vs. %s\n", msg,	\
++			   ndr_syntax_id_to_string(frame, &s1),		\
++			   ndr_syntax_id_to_string(frame, &s1)));	\
++		TALLOC_FREE(frame);					\
++		return false;						\
++	}								\
++} while(0)
++
++
++bool dcerpc_sec_verification_trailer_check(
++		const struct dcerpc_sec_verification_trailer *vt,
++		const uint32_t *bitmask1,
++		const struct dcerpc_sec_vt_pcontext *pcontext,
++		const struct dcerpc_sec_vt_header2 *header2)
++{
++	size_t i;
++
++	if (!dcerpc_sec_vt_is_valid(vt)) {
++		return false;
++	}
++
++	for (i=0; i < vt->count.count; i++) {
++		struct dcerpc_sec_vt *c = &vt->commands[i];
++
++		switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
++		case DCERPC_SEC_VT_COMMAND_BITMASK1:
++			if (bitmask1 == NULL) {
++				CHECK("Bitmask1 must_process_command",
++				      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
++				break;
++			}
++
++			if (c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING) {
++				CHECK("Bitmask1 client_header_signing",
++				      *bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING);
++			}
++			break;
++
++		case DCERPC_SEC_VT_COMMAND_PCONTEXT:
++			if (pcontext == NULL) {
++				CHECK("Pcontext must_process_command",
++				      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
++				break;
++			}
++
++			CHECK_SYNTAX("Pcontect abstract_syntax",
++				     pcontext->abstract_syntax,
++				     c->u.pcontext.abstract_syntax);
++			CHECK_SYNTAX("Pcontext transfer_syntax",
++				     pcontext->transfer_syntax,
++				     c->u.pcontext.transfer_syntax);
++			break;
++
++		case DCERPC_SEC_VT_COMMAND_HEADER2: {
++			if (header2 == NULL) {
++				CHECK("Header2 must_process_command",
++				      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
++				break;
++			}
++
++			CHECK("Header2", dcerpc_sec_vt_header2_equal(header2, &c->u.header2));
++			break;
++		}
++
++		default:
++			CHECK("Unknown must_process_command",
++			      !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
++			break;
++		}
++	}
++
++	return true;
++}
+--- a/librpc/rpc/rpc_common.h
++++ b/librpc/rpc/rpc_common.h
+@@ -296,4 +296,45 @@ NTSTATUS dcerpc_binding_handle_call(stru
+ 				    TALLOC_CTX *r_mem,
+ 				    void *r_ptr);
+ 
++/**
++ * Extract header information from a ncacn_packet
++ * as a dcerpc_sec_vt_header2 as used by the security verification trailer.
++ *
++ * @param[in] pkt a packet
++ *
++ * @return a dcerpc_sec_vt_header2
++ */
++struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt);
++
++
++/**
++ * Test if two dcerpc_sec_vt_header2 structures are equal
++ * without consideration of reserved fields.
++ *
++ * @param v1 a pointer to a dcerpc_sec_vt_header2 structure
++ * @param v2 a pointer to a dcerpc_sec_vt_header2 structure
++ *
++ * @retval true if *v1 equals *v2
++ */
++bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
++				 const struct dcerpc_sec_vt_header2 *v2);
++
++/**
++ * Check for consistency of the security verification trailer with the PDU header.
++ * See <a href="http://msdn.microsoft.com/en-us/library/cc243559.aspx">MS-RPCE 2.2.2.13</a>.
++ * A check with an empty trailer succeeds.
++ *
++ * @param[in] vt a pointer to the security verification trailer.
++ * @param[in] bitmask1 which flags were negotiated on the connection.
++ * @param[in] pcontext the syntaxes negotiatied for the presentation context.
++ * @param[in] header2 some fields from the PDU header.
++ *
++ * @retval true on success.
++ */
++bool dcerpc_sec_verification_trailer_check(
++		const struct dcerpc_sec_verification_trailer *vt,
++		const uint32_t *bitmask1,
++		const struct dcerpc_sec_vt_pcontext *pcontext,
++		const struct dcerpc_sec_vt_header2 *header2);
++
+ #endif /* __DEFAULT_LIBRPC_RPCCOMMON_H__ */
+--- a/source4/torture/ndr/ndr.c
++++ b/source4/torture/ndr/ndr.c
+@@ -29,40 +29,65 @@ struct ndr_pull_test_data {
+ 	DATA_BLOB data_context;
+ 	size_t struct_size;
+ 	ndr_pull_flags_fn_t pull_fn;
++	ndr_push_flags_fn_t push_fn;
+ 	int ndr_flags;
++	int flags;
+ };
+ 
+-static bool wrap_ndr_pull_test(struct torture_context *tctx,
+-			       struct torture_tcase *tcase,
+-			       struct torture_test *test)
++static bool wrap_ndr_pullpush_test(struct torture_context *tctx,
++				   struct torture_tcase *tcase,
++				   struct torture_test *test)
+ {
+ 	bool (*check_fn) (struct torture_context *ctx, void *data) = test->fn;
+ 	const struct ndr_pull_test_data *data = (const struct ndr_pull_test_data *)test->data;
+-	void *ds = talloc_zero_size(tctx, data->struct_size);
+ 	struct ndr_pull *ndr = ndr_pull_init_blob(&(data->data), tctx);
++	void *ds = talloc_zero_size(ndr, data->struct_size);
++	bool ret;
++	uint32_t highest_ofs;
++
++	ndr->flags |= data->flags;
+ 
+ 	ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
+ 
+ 	torture_assert_ndr_success(tctx, data->pull_fn(ndr, data->ndr_flags, ds),
+ 				   "pulling");
+ 
+-	torture_assert(tctx, ndr->offset == ndr->data_size,
++	if (ndr->offset > ndr->relative_highest_offset) {
++		highest_ofs = ndr->offset;
++	} else {
++		highest_ofs = ndr->relative_highest_offset;
++	}
++
++	torture_assert(tctx, highest_ofs == ndr->data_size,
+ 				   talloc_asprintf(tctx,
+-					   "%d unread bytes", ndr->data_size - ndr->offset));
++					   "%d unread bytes", ndr->data_size - highest_ofs));
+ 
+-	if (check_fn != NULL)
+-		return check_fn(tctx, ds);
+-	else
+-		return true;
++	if (check_fn != NULL) {
++		ret = check_fn(tctx, ds);
++	} else {
++		ret = true;
++	}
++
++	if (data->push_fn != NULL) {
++		DATA_BLOB outblob;
++		torture_assert_ndr_success(tctx, ndr_push_struct_blob(&outblob, ndr, ds, data->push_fn), "pushing");
++		torture_assert_data_blob_equal(tctx, outblob, data->data, "ndr push compare");
++	}
++
++	talloc_free(ndr);
++	return ret;
+ }
+ 
+-_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_test(
+-					struct torture_suite *suite,
+-					const char *name, ndr_pull_flags_fn_t pull_fn,
+-					DATA_BLOB db,
+-					size_t struct_size,
+-					int ndr_flags,
+-					bool (*check_fn) (struct torture_context *ctx, void *data))
++_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pullpush_test(
++	struct torture_suite *suite,
++	const char *name,
++	ndr_pull_flags_fn_t pull_fn,
++	ndr_push_flags_fn_t push_fn,
++	DATA_BLOB db,
++	size_t struct_size,
++	int ndr_flags,
++	int flags,
++	bool (*check_fn) (struct torture_context *ctx, void *data))
+ {
+ 	struct torture_test *test;
+ 	struct torture_tcase *tcase;
+@@ -74,12 +99,16 @@ _PUBLIC_ struct torture_test *_torture_s
+ 
+ 	test->name = talloc_strdup(test, name);
+ 	test->description = NULL;
+-	test->run = wrap_ndr_pull_test;
++	test->run = wrap_ndr_pullpush_test;
++
+ 	data = talloc(test, struct ndr_pull_test_data);
+ 	data->data = db;
+ 	data->ndr_flags = ndr_flags;
++	data->flags = flags;
+ 	data->struct_size = struct_size;
+ 	data->pull_fn = pull_fn;
++	data->push_fn = push_fn;
++
+ 	test->data = data;
+ 	test->fn = check_fn;
+ 	test->dangerous = false;
+@@ -89,6 +118,7 @@ _PUBLIC_ struct torture_test *_torture_s
+ 	return test;
+ }
+ 
++
+ static bool wrap_ndr_inout_pull_test(struct torture_context *tctx,
+ 				     struct torture_tcase *tcase,
+ 				     struct torture_test *test)
+@@ -97,6 +127,7 @@ static bool wrap_ndr_inout_pull_test(str
+ 	const struct ndr_pull_test_data *data = (const struct ndr_pull_test_data *)test->data;
+ 	void *ds = talloc_zero_size(tctx, data->struct_size);
+ 	struct ndr_pull *ndr;
++	uint32_t highest_ofs;
+ 
+ 	/* handle NDR_IN context */
+ 
+@@ -109,8 +140,14 @@ static bool wrap_ndr_inout_pull_test(str
+ 		data->pull_fn(ndr, NDR_IN, ds),
+ 		"ndr pull of context failed");
+ 
+-	torture_assert(tctx, ndr->offset == ndr->data_size,
+-		talloc_asprintf(tctx, "%d unread bytes", ndr->data_size - ndr->offset));
++	if (ndr->offset > ndr->relative_highest_offset) {
++		highest_ofs = ndr->offset;
++	} else {
++		highest_ofs = ndr->relative_highest_offset;
++	}
++
++	torture_assert(tctx, highest_ofs == ndr->data_size,
++		talloc_asprintf(tctx, "%d unread bytes", ndr->data_size - highest_ofs));
+ 
+ 	talloc_free(ndr);
+ 
+@@ -125,8 +162,14 @@ static bool wrap_ndr_inout_pull_test(str
+ 		data->pull_fn(ndr, NDR_OUT, ds),
+ 		"ndr pull failed");
+ 
+-	torture_assert(tctx, ndr->offset == ndr->data_size,
+-		talloc_asprintf(tctx, "%d unread bytes", ndr->data_size - ndr->offset));
++	if (ndr->offset > ndr->relative_highest_offset) {
++		highest_ofs = ndr->offset;
++	} else {
++		highest_ofs = ndr->relative_highest_offset;
++	}
++
++	torture_assert(tctx, highest_ofs == ndr->data_size,
++		talloc_asprintf(tctx, "%d unread bytes", ndr->data_size - highest_ofs));
+ 
+ 	talloc_free(ndr);
+ 
+--- a/source4/torture/ndr/ndr.h
++++ b/source4/torture/ndr/ndr.h
+@@ -24,12 +24,15 @@
+ #include "librpc/ndr/libndr.h"
+ #include "libcli/security/security.h"
+ 
+-_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_test(
++_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pullpush_test(
+ 					struct torture_suite *suite,
+-					const char *name, ndr_pull_flags_fn_t fn,
++					const char *name,
++					ndr_pull_flags_fn_t pull_fn,
++					ndr_push_flags_fn_t push_fn,
+ 					DATA_BLOB db,
+ 					size_t struct_size,
+ 					int ndr_flags,
++					int flags,
+ 					bool (*check_fn) (struct torture_context *, void *data));
+ 
+ _PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_inout_test(
+@@ -41,20 +44,32 @@ _PUBLIC_ struct torture_test *_torture_s
+ 					bool (*check_fn) (struct torture_context *ctx, void *data));
+ 
+ #define torture_suite_add_ndr_pull_test(suite,name,data,check_fn) \
+-		_torture_suite_add_ndr_pull_test(suite, #name, \
+-			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, data_blob_talloc(suite, data, sizeof(data)), \
+-			 sizeof(struct name), NDR_SCALARS|NDR_BUFFERS, (bool (*) (struct torture_context *, void *)) check_fn);
++		_torture_suite_add_ndr_pullpush_test(suite, #name, \
++			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, NULL, data_blob_const(data, sizeof(data)), \
++			 sizeof(struct name), NDR_SCALARS|NDR_BUFFERS, 0, (bool (*) (struct torture_context *, void *)) check_fn);
+ 
+ #define torture_suite_add_ndr_pull_fn_test(suite,name,data,flags,check_fn) \
+-		_torture_suite_add_ndr_pull_test(suite, #name "_" #flags, \
+-			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, data_blob_talloc(suite, data, sizeof(data)), \
+-			 sizeof(struct name), flags, (bool (*) (struct torture_context *, void *)) check_fn);
++		_torture_suite_add_ndr_pullpush_test(suite, #name "_" #flags, \
++			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, NULL, data_blob_const(data, sizeof(data)), \
++			 sizeof(struct name), flags, 0, (bool (*) (struct torture_context *, void *)) check_fn);
++
++#define torture_suite_add_ndr_pull_fn_test_flags(suite,name,data,flags,flags2,check_fn) \
++		_torture_suite_add_ndr_pullpush_test(suite, #name "_" #flags "_" #flags2, \
++			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, NULL, data_blob_const(data, sizeof(data)), \
++			 sizeof(struct name), flags, flags2, (bool (*) (struct torture_context *, void *)) check_fn);
++
++#define torture_suite_add_ndr_pullpush_test(suite,name,data_blob,check_fn) \
++		_torture_suite_add_ndr_pullpush_test(suite, #name, \
++			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
++			 (ndr_push_flags_fn_t)ndr_push_ ## name, \
++			 data_blob, \
++			 sizeof(struct name), NDR_SCALARS|NDR_BUFFERS, 0, (bool (*) (struct torture_context *, void *)) check_fn);
+ 
+ #define torture_suite_add_ndr_pull_io_test(suite,name,data_in,data_out,check_fn_out) \
+ 		_torture_suite_add_ndr_pull_inout_test(suite, #name "_INOUT", \
+ 			 (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+-			 data_blob_talloc(suite, data_in, sizeof(data_in)), \
+-			 data_blob_talloc(suite, data_out, sizeof(data_out)), \
++			 data_blob_const(data_in, sizeof(data_in)), \
++			 data_blob_const(data_out, sizeof(data_out)), \
+ 			 sizeof(struct name), \
+ 			 (bool (*) (struct torture_context *, void *)) check_fn_out);
+ 
+--- a/source4/torture/ndr/dfsblob.c
++++ b/source4/torture/ndr/dfsblob.c
+@@ -74,11 +74,11 @@ struct torture_suite *ndr_dfsblob_suite(
+ {
+ 	struct torture_suite *suite = torture_suite_create(ctx, "dfsblob");
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, dfs_GetDFSReferral_in, dfs_get_ref_in, NDR_IN, NULL);
++	torture_suite_add_ndr_pull_test(suite, dfs_GetDFSReferral_in, dfs_get_ref_in, NULL);
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, dfs_referral_resp, dfs_get_ref_out2, NDR_BUFFERS|NDR_SCALARS, NULL);
++	torture_suite_add_ndr_pull_test(suite, dfs_referral_resp, dfs_get_ref_out2, NULL);
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, dfs_referral_resp, dfs_get_ref_out, NDR_BUFFERS|NDR_SCALARS,dfs_referral_out_check);
++	torture_suite_add_ndr_pull_test(suite, dfs_referral_resp, dfs_get_ref_out,dfs_referral_out_check);
+ 
+ 	return suite;
+ }
+--- a/source4/torture/ndr/nbt.c
++++ b/source4/torture/ndr/nbt.c
+@@ -62,9 +62,9 @@ struct torture_suite *ndr_nbt_suite(TALL
+ {
+ 	struct torture_suite *suite = torture_suite_create(ctx, "nbt");
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, nbt_netlogon_packet, netlogon_logon_request_req_data, NDR_IN, netlogon_logon_request_req_check);
++	torture_suite_add_ndr_pull_test(suite, nbt_netlogon_packet, netlogon_logon_request_req_data, netlogon_logon_request_req_check);
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, nbt_netlogon_response2, netlogon_logon_request_resp_data, NDR_IN, netlogon_logon_request_resp_check);
++	torture_suite_add_ndr_pull_test(suite, nbt_netlogon_response2, netlogon_logon_request_resp_data, netlogon_logon_request_resp_check);
+ 
+ 	return suite;
+ }
+--- a/source4/torture/ndr/ntlmssp.c
++++ b/source4/torture/ndr/ntlmssp.c
+@@ -111,9 +111,10 @@ struct torture_suite *ndr_ntlmssp_suite(
+ {
+ 	struct torture_suite *suite = torture_suite_create(ctx, "ntlmssp");
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, NEGOTIATE_MESSAGE, ntlmssp_NEGOTIATE_MESSAGE_data, NDR_IN, ntlmssp_NEGOTIATE_MESSAGE_check);
+-	/* torture_suite_add_ndr_pull_fn_test(suite, CHALLENGE_MESSAGE, ntlmssp_CHALLENGE_MESSAGE_data, NDR_IN, ntlmssp_CHALLENGE_MESSAGE_check);
+-	torture_suite_add_ndr_pull_fn_test(suite, AUTHENTICATE_MESSAGE, ntlmssp_AUTHENTICATE_MESSAGE_data, NDR_IN, ntlmssp_AUTHENTICATE_MESSAGE_check); */
+-
++	torture_suite_add_ndr_pull_test(suite, NEGOTIATE_MESSAGE, ntlmssp_NEGOTIATE_MESSAGE_data, ntlmssp_NEGOTIATE_MESSAGE_check);
++#if 0
++	torture_suite_add_ndr_pull_test(suite, CHALLENGE_MESSAGE, ntlmssp_CHALLENGE_MESSAGE_data, ntlmssp_CHALLENGE_MESSAGE_check);
++	torture_suite_add_ndr_pull_test(suite, AUTHENTICATE_MESSAGE, ntlmssp_AUTHENTICATE_MESSAGE_data, ntlmssp_AUTHENTICATE_MESSAGE_check);
++#endif
+ 	return suite;
+ }
+--- a/source4/torture/ndr/drsblobs.c
++++ b/source4/torture/ndr/drsblobs.c
+@@ -115,6 +115,34 @@ static const uint8_t trust_domain_passwo
+ 	0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00
+ };
+ 
++/* these are taken from the trust objects of a w2k8r2 forest, with a
++ * trust relationship between the forest parent and a child domain
++ */
++static const char *trustAuthIncoming =
++"AQAAAAwAAAAcAQAASuQ+RXJdzAECAAAAAAEAAMOWL6UVfVKiJOUsGcT03H"
++"jHxr2ACsMMOV5ynM617Tp7idNC+c4egdqk4S9YEpvR2YvHmdZdymL6F7QKm8OkXazYZF2r/gZ/bI+"
++"jkWbsn4O8qyAc3OUKQRZwBbf+lxBW+vM4O3ZpUjz5BSKCcFQgM+MY91yVU8Nji3HNnvGnDquobFAZ"
++"hxjL+S1l5+QZgkfyfv5mQScGRbU1Lar1xg9G3JznUb7S6pvrBO2nwK8g+KZBfJy5UeULigDH4IWo/"
++"JmtaEGkKE2uiKIjdsEQd/uwnkouW26XzRc0ulfJnPFftGnT9KIcShPf7DLj/tstmQAAceRMFHJTY3"
++"PmxoowoK8HUyBK5D5Fcl3MAQIAAAAAAQAAw5YvpRV9UqIk5SwZxPTceMfGvYAKwww5XnKczrXtOnu"
++"J00L5zh6B2qThL1gSm9HZi8eZ1l3KYvoXtAqbw6RdrNhkXav+Bn9sj6ORZuyfg7yrIBzc5QpBFnAF"
++"t/6XEFb68zg7dmlSPPkFIoJwVCAz4xj3XJVTw2OLcc2e8acOq6hsUBmHGMv5LWXn5BmCR/J+/mZBJ"
++"wZFtTUtqvXGD0bcnOdRvtLqm+sE7afAryD4pkF8nLlR5QuKAMfghaj8ma1oQaQoTa6IoiN2wRB3+7"
++"CeSi5bbpfNFzS6V8mc8V+0adP0ohxKE9/sMuP+2y2ZAABx5EwUclNjc+bGijCgrwdTIA==";
++
++static const char *trustAuthOutgoing =
++"AQAAAAwAAAAcAQAASuQ+RXJdzAECAAAAAAEAAMOWL6UVfVKiJOUsGcT03H"
++"jHxr2ACsMMOV5ynM617Tp7idNC+c4egdqk4S9YEpvR2YvHmdZdymL6F7QKm8OkXazYZF2r/gZ/bI+"
++"jkWbsn4O8qyAc3OUKQRZwBbf+lxBW+vM4O3ZpUjz5BSKCcFQgM+MY91yVU8Nji3HNnvGnDquobFAZ"
++"hxjL+S1l5+QZgkfyfv5mQScGRbU1Lar1xg9G3JznUb7S6pvrBO2nwK8g+KZBfJy5UeULigDH4IWo/"
++"JmtaEGkKE2uiKIjdsEQd/uwnkouW26XzRc0ulfJnPFftGnT9KIcShPf7DLj/tstmQAAceRMFHJTY3"
++"PmxoowoK8HUyBK5D5Fcl3MAQIAAAAAAQAAw5YvpRV9UqIk5SwZxPTceMfGvYAKwww5XnKczrXtOnu"
++"J00L5zh6B2qThL1gSm9HZi8eZ1l3KYvoXtAqbw6RdrNhkXav+Bn9sj6ORZuyfg7yrIBzc5QpBFnAF"
++"t/6XEFb68zg7dmlSPPkFIoJwVCAz4xj3XJVTw2OLcc2e8acOq6hsUBmHGMv5LWXn5BmCR/J+/mZBJ"
++"wZFtTUtqvXGD0bcnOdRvtLqm+sE7afAryD4pkF8nLlR5QuKAMfghaj8ma1oQaQoTa6IoiN2wRB3+7"
++"CeSi5bbpfNFzS6V8mc8V+0adP0ohxKE9/sMuP+2y2ZAABx5EwUclNjc+bGijCgrwdTIA==";
++
++
+ static bool trust_domain_passwords_check_in(struct torture_context *tctx,
+ 					    struct trustDomainPasswords *r)
+ {
+@@ -154,8 +182,20 @@ struct torture_suite *ndr_drsblobs_suite
+ {
+ 	struct torture_suite *suite = torture_suite_create(ctx, "drsblobs");
+ 
+-	torture_suite_add_ndr_pull_fn_test(suite, ForestTrustInfo, forest_trust_info_data_out, NDR_IN, forest_trust_info_check_out);
+-	torture_suite_add_ndr_pull_fn_test(suite, trustDomainPasswords, trust_domain_passwords_in, NDR_IN, trust_domain_passwords_check_in);
++	torture_suite_add_ndr_pull_test(suite, ForestTrustInfo, forest_trust_info_data_out, forest_trust_info_check_out);
++	torture_suite_add_ndr_pull_test(suite, trustDomainPasswords, trust_domain_passwords_in, trust_domain_passwords_check_in);
++
++#if 0
++	torture_suite_add_ndr_pullpush_test(suite,
++					    trustAuthInOutBlob,
++					    base64_decode_data_blob_talloc(suite, trustAuthIncoming),
++					    NULL);
++
++	torture_suite_add_ndr_pullpush_test(suite,
++					    trustAuthInOutBlob,
++					    base64_decode_data_blob_talloc(suite, trustAuthOutgoing),
++					    NULL);
++#endif
+ 
+ 	return suite;
+ }
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -1031,6 +1031,10 @@ out_free:
+ 		binding->transport = NCACN_NP;
+ 	}
+ 
++	if (binding->flags & DCERPC_CONNECT) {
++		pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
++		pipe_default_auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
++	}
+ 	if (binding->flags & DCERPC_SIGN) {
+ 		pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ 		pipe_default_auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+@@ -1044,12 +1048,6 @@ out_free:
+ 		pipe_default_auth_spnego_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP;
+ 	}
+ 	if (binding->flags & DCERPC_AUTH_NTLM) {
+-		/* If neither Integrity or Privacy are requested then
+-		 * Use just Connect level */
+-		if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
+-			pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+-		}
+-
+ 		if (pipe_default_auth_type == DCERPC_AUTH_TYPE_SPNEGO) {
+ 			pipe_default_auth_spnego_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP;
+ 		} else {
+@@ -1057,18 +1055,19 @@ out_free:
+ 		}
+ 	}
+ 	if (binding->flags & DCERPC_AUTH_KRB5) {
+-		/* If neither Integrity or Privacy are requested then
+-		 * Use just Connect level */
+-		if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
+-			pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+-		}
+-
+ 		if (pipe_default_auth_type == DCERPC_AUTH_TYPE_SPNEGO) {
+ 			pipe_default_auth_spnego_type = PIPE_AUTH_TYPE_SPNEGO_KRB5;
+ 		} else {
+ 			pipe_default_auth_type = DCERPC_AUTH_TYPE_KRB5;
+ 		}
+ 	}
++	if (pipe_default_auth_type != DCERPC_AUTH_TYPE_NONE) {
++		/* If neither Integrity or Privacy are requested then
++		 * Use just Connect level */
++		if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
++			pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
++		}
++	}
+ 
+ 	if (get_cmdline_auth_info_use_kerberos(rpcclient_auth_info)) {
+ 		flags |= CLI_FULL_CONNECTION_USE_KERBEROS |
+--- /dev/null
++++ b/source3/script/tests/test_rpcclient.sh
+@@ -0,0 +1,19 @@
++#!/bin/sh
++
++if [ $# -lt 1 ]; then
++cat <<EOF
++Usage: test_rpcclient.sh ccache binding <rpcclient commands>
++EOF
++exit 1;
++fi
++
++KRB5CCNAME=$1
++shift 1
++export KRB5CCNAME
++ADDARGS="$*"
++
++incdir=`dirname $0`/../../../testprogs/blackbox
++. $incdir/subunit.sh
++testit "rpcclient" $VALGRIND $BINDIR/rpcclient -c 'getusername' $ADDARGS || failed=`expr $failed + 1`
++
++testok $0 $failed
+--- a/source3/selftest/tests.py
++++ b/source3/selftest/tests.py
+@@ -208,7 +208,7 @@ if sub.returncode == 0:
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD')
+ 
+     test = 'rpc.lsa.lookupsids'
+-    auth_options = ["", "ntlm", "spnego" ]
++    auth_options = ["", "ntlm", "spnego", "spnego,ntlm" ]
+     signseal_options = ["", ",connect", ",sign", ",seal"]
+     smb_options = ["", ",smb2"]
+     endianness_options = ["", ",bigendian"]
+@@ -219,6 +219,9 @@ if sub.returncode == 0:
+                     binding_string = "ncacn_np:$SERVER_IP[%s%s%s%s]" % (a, s, z, e)
+                     options = binding_string + " -U$USERNAME%$PASSWORD"
+                     plansmbtorturetestsuite(test, "s3dc", options, 'over ncacn_np with [%s%s%s%s] ' % (a, s, z, e))
++                    plantestsuite("samba3.blackbox.rpcclient over ncacn_np with [%s%s%s%s] " % (a, s, z, e), "s3dc:local", [os.path.join(samba3srcdir, "script/tests/test_rpcclient.sh"),
++                                                                 "none", options, configuration])
++
+     for e in endianness_options:
+         for a in auth_options:
+             for s in signseal_options:
+--- a/source4/torture/rpc/rpc.c
++++ b/source4/torture/rpc/rpc.c
+@@ -501,6 +501,7 @@ NTSTATUS torture_rpc_init(void)
+ 	torture_suite_add_suite(suite, torture_rpc_samr_passwords_pwdlastset(suite));
+ 	torture_suite_add_suite(suite, torture_rpc_samr_passwords_badpwdcount(suite));
+ 	torture_suite_add_suite(suite, torture_rpc_samr_passwords_lockout(suite));
++	torture_suite_add_suite(suite, torture_rpc_samr_passwords_validate(suite));
+ 	torture_suite_add_suite(suite, torture_rpc_samr_user_privileges(suite));
+ 	torture_suite_add_suite(suite, torture_rpc_samr_large_dc(suite));
+ 	torture_suite_add_suite(suite, torture_rpc_epmapper(suite));
+--- a/source4/torture/rpc/samr.c
++++ b/source4/torture/rpc/samr.c
+@@ -7938,8 +7938,8 @@ static bool test_Connect(struct dcerpc_b
+ }
+ 
+ 
+-static bool test_samr_ValidatePassword(struct dcerpc_pipe *p,
+-				       struct torture_context *tctx)
++static bool test_samr_ValidatePassword(struct torture_context *tctx,
++				       struct dcerpc_pipe *p)
+ {
+ 	struct samr_ValidatePassword r;
+ 	union samr_ValidatePasswordReq req;
+@@ -7951,6 +7951,10 @@ static bool test_samr_ValidatePassword(s
+ 
+ 	torture_comment(tctx, "Testing samr_ValidatePassword\n");
+ 
++	if (p->conn->transport.transport != NCACN_IP_TCP) {
++		torture_comment(tctx, "samr_ValidatePassword only should succeed over NCACN_IP_TCP!\n");
++	}
++
+ 	ZERO_STRUCT(r);
+ 	r.in.level = NetValidatePasswordReset;
+ 	r.in.req = &req;
+@@ -8074,8 +8078,6 @@ bool torture_rpc_samr_passwords(struct t
+ 
+ 	ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+ 
+-	ret &= test_samr_ValidatePassword(p, torture);
+-
+ 	return ret;
+ }
+ 
+@@ -8370,4 +8372,15 @@ struct torture_suite *torture_rpc_samr_p
+ 	return suite;
+ }
+ 
++struct torture_suite *torture_rpc_samr_passwords_validate(TALLOC_CTX *mem_ctx)
++{
++	struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.validate");
++	struct torture_rpc_tcase *tcase;
++
++	tcase = torture_suite_add_rpc_iface_tcase(suite, "samr",
++						  &ndr_table_samr);
++	torture_rpc_tcase_add_test(tcase, "validate",
++				   test_samr_ValidatePassword);
+ 
++	return suite;
++}
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -42,6 +42,7 @@
+ #include "auth.h"
+ #include "ntdomain.h"
+ #include "rpc_server/srv_pipe.h"
++#include "../librpc/ndr/ndr_dcerpc.h"
+ 
+ #undef DBGC_CLASS
+ #define DBGC_CLASS DBGC_RPC_SRV
+@@ -202,7 +203,7 @@ bool create_next_pdu(struct pipes_struct
+ 	 * the pipe gets closed. JRA.
+ 	 */
+ 	if (p->fault_state) {
+-		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
++		setup_fault_pdu(p, NT_STATUS(p->fault_state));
+ 		return true;
+ 	}
+ 
+@@ -336,7 +337,7 @@ static bool check_bind_req(struct pipes_
+ 	struct pipe_rpc_fns *context_fns;
+ 
+ 	DEBUG(3,("check_bind_req for %s\n",
+-		 get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
++		 get_pipe_name_from_syntax(talloc_tos(), abstract)));
+ 
+ 	/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
+ 	if (rpc_srv_pipe_exists_by_id(abstract) &&
+@@ -358,6 +359,7 @@ static bool check_bind_req(struct pipes_
+ 	context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract);
+ 	context_fns->cmds = rpc_srv_get_pipe_cmds(abstract);
+ 	context_fns->context_id = context_id;
++	context_fns->syntax = *abstract;
+ 
+ 	/* add to the list of open contexts */
+ 
+@@ -1541,7 +1543,42 @@ static PIPE_RPC_FNS* find_pipe_fns_by_co
+ }
+ 
+ static bool api_rpcTNP(struct pipes_struct *p, struct ncacn_packet *pkt,
+-		       const struct api_struct *api_rpc_cmds, int n_cmds);
++		       const struct api_struct *api_rpc_cmds, int n_cmds,
++		       const struct ndr_syntax_id *syntax);
++
++static bool srv_pipe_check_verification_trailer(struct pipes_struct *p,
++						struct ncacn_packet *pkt,
++						struct pipe_rpc_fns *pipe_fns)
++{
++	TALLOC_CTX *frame = talloc_stackframe();
++	struct dcerpc_sec_verification_trailer *vt = NULL;
++	const uint32_t bitmask1 = 0;
++	const struct dcerpc_sec_vt_pcontext pcontext = {
++		.abstract_syntax = pipe_fns->syntax,
++		.transfer_syntax = ndr_transfer_syntax,
++	};
++	const struct dcerpc_sec_vt_header2 header2 =
++	       dcerpc_sec_vt_header2_from_ncacn_packet(pkt);
++	struct ndr_pull *ndr;
++	enum ndr_err_code ndr_err;
++	bool ret = false;
++
++	ndr = ndr_pull_init_blob(&p->in_data.data, frame);
++	if (ndr == NULL) {
++		goto done;
++	}
++
++	ndr_err = ndr_pop_dcerpc_sec_verification_trailer(ndr, frame, &vt);
++	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
++		goto done;
++	}
++
++	ret = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
++						    &pcontext, &header2);
++done:
++	TALLOC_FREE(frame);
++	return ret;
++}
+ 
+ /****************************************************************************
+  Find the correct RPC function to call for this request.
+@@ -1552,46 +1589,53 @@ static bool api_rpcTNP(struct pipes_stru
+ static bool api_pipe_request(struct pipes_struct *p,
+ 				struct ncacn_packet *pkt)
+ {
++	TALLOC_CTX *frame = talloc_stackframe();
+ 	bool ret = False;
+-	bool changed_user = False;
+ 	PIPE_RPC_FNS *pipe_fns;
+ 
+-	if (p->pipe_bound &&
+-	    ((p->auth.auth_type == DCERPC_AUTH_TYPE_NTLMSSP) ||
+-	     (p->auth.auth_type == DCERPC_AUTH_TYPE_KRB5) ||
+-	     (p->auth.auth_type == DCERPC_AUTH_TYPE_SPNEGO))) {
+-		if(!become_authenticated_pipe_user(p->session_info)) {
+-			data_blob_free(&p->out_data.rdata);
+-			return False;
+-		}
+-		changed_user = True;
++	if (!p->pipe_bound) {
++		DEBUG(1, ("Pipe not bound!\n"));
++		data_blob_free(&p->out_data.rdata);
++		TALLOC_FREE(frame);
++		return false;
+ 	}
+ 
+-	DEBUG(5, ("Requested \\PIPE\\%s\n",
+-		  get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
+-
+ 	/* get the set of RPC functions for this context */
+ 
+ 	pipe_fns = find_pipe_fns_by_context(p->contexts,
+ 					    pkt->u.request.context_id);
+-
+-	if ( pipe_fns ) {
+-		TALLOC_CTX *frame = talloc_stackframe();
+-		ret = api_rpcTNP(p, pkt, pipe_fns->cmds, pipe_fns->n_cmds);
++	if (pipe_fns == NULL) {
++		DEBUG(0, ("No rpc function table associated with context "
++			  "[%d]\n",
++			  pkt->u.request.context_id));
++		data_blob_free(&p->out_data.rdata);
+ 		TALLOC_FREE(frame);
++		return false;
+ 	}
+-	else {
+-		DEBUG(0, ("No rpc function table associated with context "
+-			  "[%d] on pipe [%s]\n",
+-			  pkt->u.request.context_id,
+-			  get_pipe_name_from_syntax(talloc_tos(),
+-						    &p->syntax)));
++
++	DEBUG(5, ("Requested \\PIPE\\%s\n",
++		  get_pipe_name_from_syntax(talloc_tos(), &pipe_fns->syntax)));
++
++	if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
++		DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
++		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
++		data_blob_free(&p->out_data.rdata);
++		TALLOC_FREE(frame);
++		return true;
+ 	}
+ 
+-	if (changed_user) {
+-		unbecome_authenticated_pipe_user();
++	if (!become_authenticated_pipe_user(p->session_info)) {
++		DEBUG(1, ("Failed to become pipe user!\n"));
++		data_blob_free(&p->out_data.rdata);
++		TALLOC_FREE(frame);
++		return false;
+ 	}
+ 
++	ret = api_rpcTNP(p, pkt, pipe_fns->cmds, pipe_fns->n_cmds,
++			 &pipe_fns->syntax);
++	unbecome_authenticated_pipe_user();
++
++	TALLOC_FREE(frame);
+ 	return ret;
+ }
+ 
+@@ -1600,20 +1644,21 @@ static bool api_pipe_request(struct pipe
+  ********************************************************************/
+ 
+ static bool api_rpcTNP(struct pipes_struct *p, struct ncacn_packet *pkt,
+-		       const struct api_struct *api_rpc_cmds, int n_cmds)
++		       const struct api_struct *api_rpc_cmds, int n_cmds,
++		       const struct ndr_syntax_id *syntax)
+ {
+ 	int fn_num;
+ 	uint32_t offset1;
+ 
+ 	/* interpret the command */
+ 	DEBUG(4,("api_rpcTNP: %s op 0x%x - ",
+-		 get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
++		 get_pipe_name_from_syntax(talloc_tos(), syntax),
+ 		 pkt->u.request.opnum));
+ 
+ 	if (DEBUGLEVEL >= 50) {
+ 		fstring name;
+ 		slprintf(name, sizeof(name)-1, "in_%s",
+-			 get_pipe_name_from_syntax(talloc_tos(), &p->syntax));
++			 get_pipe_name_from_syntax(talloc_tos(), syntax));
+ 		dump_pdu_region(name, pkt->u.request.opnum,
+ 				&p->in_data.data, 0,
+ 				p->in_data.data.length);
+@@ -1646,37 +1691,30 @@ static bool api_rpcTNP(struct pipes_stru
+ 	/* do the actual command */
+ 	if(!api_rpc_cmds[fn_num].fn(p)) {
+ 		DEBUG(0,("api_rpcTNP: %s: %s failed.\n",
+-			 get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
++			 get_pipe_name_from_syntax(talloc_tos(), syntax),
+ 			 api_rpc_cmds[fn_num].name));
+ 		data_blob_free(&p->out_data.rdata);
+ 		return False;
+ 	}
+ 
+-	if (p->bad_handle_fault_state) {
+-		DEBUG(4,("api_rpcTNP: bad handle fault return.\n"));
+-		p->bad_handle_fault_state = False;
+-		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_CONTEXT_MISMATCH));
+-		return True;
+-	}
+-
+-	if (p->rng_fault_state) {
+-		DEBUG(4, ("api_rpcTNP: rng fault return\n"));
+-		p->rng_fault_state = False;
+-		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
+-		return True;
++	if (p->fault_state) {
++		DEBUG(4,("api_rpcTNP: fault(%d) return.\n", p->fault_state));
++		setup_fault_pdu(p, NT_STATUS(p->fault_state));
++		p->fault_state = 0;
++		return true;
+ 	}
+ 
+ 	if (DEBUGLEVEL >= 50) {
+ 		fstring name;
+ 		slprintf(name, sizeof(name)-1, "out_%s",
+-			 get_pipe_name_from_syntax(talloc_tos(), &p->syntax));
++			 get_pipe_name_from_syntax(talloc_tos(), syntax));
+ 		dump_pdu_region(name, pkt->u.request.opnum,
+ 				&p->out_data.rdata, offset1,
+ 				p->out_data.rdata.length);
+ 	}
+ 
+ 	DEBUG(5,("api_rpcTNP: called %s successfully\n",
+-		 get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
++		 get_pipe_name_from_syntax(talloc_tos(), syntax)));
+ 
+ 	/* Check for buffer underflow in rpc parsing */
+ 	if ((DEBUGLEVEL >= 10) &&
+@@ -1718,9 +1756,9 @@ void set_incoming_fault(struct pipes_str
+ 	data_blob_free(&p->in_data.data);
+ 	p->in_data.pdu_needed_len = 0;
+ 	p->in_data.pdu.length = 0;
+-	p->fault_state = True;
+-	DEBUG(10, ("set_incoming_fault: Setting fault state on pipe %s\n",
+-		   get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
++	p->fault_state = DCERPC_FAULT_CANT_PERFORM;
++
++	DEBUG(10, ("Setting fault state\n"));
+ }
+ 
+ static NTSTATUS dcesrv_auth_request(struct pipe_auth_data *auth,
+--- a/source3/include/ntdomain.h
++++ b/source3/include/ntdomain.h
+@@ -87,6 +87,7 @@ typedef struct pipe_rpc_fns {
+ 	const struct api_struct *cmds;
+ 	int n_cmds;
+ 	uint32 context_id;
++	struct ndr_syntax_id syntax;
+ 
+ } PIPE_RPC_FNS;
+ 
+@@ -134,22 +135,10 @@ struct pipes_struct {
+ 	bool pipe_bound;
+ 
+ 	/*
+-	 * Set to true when we should return fault PDU's for everything.
+-	 */
+-
+-	bool fault_state;
+-
+-	/*
+-	 * Set to true when we should return fault PDU's for a bad handle.
+-	 */
+-
+-	bool bad_handle_fault_state;
+-
+-	/*
+-	 * Set to true when the backend does not support a call.
++	 * Set the DCERPC_FAULT to return.
+ 	 */
+ 
+-	bool rng_fault_state;
++	int fault_state;
+ 
+ 	/*
+ 	 * Set to RPC_BIG_ENDIAN when dealing with big-endian PDU's
+--- a/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm
++++ b/pidl/lib/Parse/Pidl/Samba3/ServerNDR.pm
+@@ -183,7 +183,7 @@ sub ParseFunction($$)
+ 	);
+ 
+ 	pidl "";
+-	pidl "if (p->rng_fault_state) {";
++	pidl "if (p->fault_state) {";
+ 	pidl "\ttalloc_free(r);";
+ 	pidl "\t/* Return true here, srv_pipe_hnd.c will take care */";
+ 	pidl "\treturn true;";
+--- a/source3/rpc_server/dfs/srv_dfs_nt.c
++++ b/source3/rpc_server/dfs/srv_dfs_nt.c
+@@ -411,125 +411,125 @@ WERROR _dfs_GetInfo(struct pipes_struct
+ WERROR _dfs_SetInfo(struct pipes_struct *p, struct dfs_SetInfo *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_Rename(struct pipes_struct *p, struct dfs_Rename *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_Move(struct pipes_struct *p, struct dfs_Move *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_ManagerGetConfigInfo(struct pipes_struct *p, struct dfs_ManagerGetConfigInfo *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_ManagerSendSiteInfo(struct pipes_struct *p, struct dfs_ManagerSendSiteInfo *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_AddFtRoot(struct pipes_struct *p, struct dfs_AddFtRoot *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_RemoveFtRoot(struct pipes_struct *p, struct dfs_RemoveFtRoot *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_AddStdRoot(struct pipes_struct *p, struct dfs_AddStdRoot *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_RemoveStdRoot(struct pipes_struct *p, struct dfs_RemoveStdRoot *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_ManagerInitialize(struct pipes_struct *p, struct dfs_ManagerInitialize *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_AddStdRootForced(struct pipes_struct *p, struct dfs_AddStdRootForced *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_GetDcAddress(struct pipes_struct *p, struct dfs_GetDcAddress *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_SetDcAddress(struct pipes_struct *p, struct dfs_SetDcAddress *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_FlushFtTable(struct pipes_struct *p, struct dfs_FlushFtTable *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_Add2(struct pipes_struct *p, struct dfs_Add2 *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_Remove2(struct pipes_struct *p, struct dfs_Remove2 *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_EnumEx(struct pipes_struct *p, struct dfs_EnumEx *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _dfs_SetInfo2(struct pipes_struct *p, struct dfs_SetInfo2 *r)
+ {
+ 	/* FIXME: Implement your code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/dssetup/srv_dssetup_nt.c
++++ b/source3/rpc_server/dssetup/srv_dssetup_nt.c
+@@ -130,7 +130,7 @@ WERROR _dssetup_DsRoleGetPrimaryDomainIn
+ WERROR _dssetup_DsRoleDnsNameToFlatName(struct pipes_struct *p,
+ 					struct dssetup_DsRoleDnsNameToFlatName *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -140,7 +140,7 @@ WERROR _dssetup_DsRoleDnsNameToFlatName(
+ WERROR _dssetup_DsRoleDcAsDc(struct pipes_struct *p,
+ 			     struct dssetup_DsRoleDcAsDc *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -150,7 +150,7 @@ WERROR _dssetup_DsRoleDcAsDc(struct pipe
+ WERROR _dssetup_DsRoleDcAsReplica(struct pipes_struct *p,
+ 				  struct dssetup_DsRoleDcAsReplica *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -160,7 +160,7 @@ WERROR _dssetup_DsRoleDcAsReplica(struct
+ WERROR _dssetup_DsRoleDemoteDc(struct pipes_struct *p,
+ 			       struct dssetup_DsRoleDemoteDc *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -170,7 +170,7 @@ WERROR _dssetup_DsRoleDemoteDc(struct pi
+ WERROR _dssetup_DsRoleGetDcOperationProgress(struct pipes_struct *p,
+ 					     struct dssetup_DsRoleGetDcOperationProgress *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -180,7 +180,7 @@ WERROR _dssetup_DsRoleGetDcOperationProg
+ WERROR _dssetup_DsRoleGetDcOperationResults(struct pipes_struct *p,
+ 					    struct dssetup_DsRoleGetDcOperationResults *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -190,7 +190,7 @@ WERROR _dssetup_DsRoleGetDcOperationResu
+ WERROR _dssetup_DsRoleCancel(struct pipes_struct *p,
+ 			     struct dssetup_DsRoleCancel *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -200,7 +200,7 @@ WERROR _dssetup_DsRoleCancel(struct pipe
+ WERROR _dssetup_DsRoleServerSaveStateForUpgrade(struct pipes_struct *p,
+ 						struct dssetup_DsRoleServerSaveStateForUpgrade *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -210,7 +210,7 @@ WERROR _dssetup_DsRoleServerSaveStateFor
+ WERROR _dssetup_DsRoleUpgradeDownlevelServer(struct pipes_struct *p,
+ 					     struct dssetup_DsRoleUpgradeDownlevelServer *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -220,6 +220,6 @@ WERROR _dssetup_DsRoleUpgradeDownlevelSe
+ WERROR _dssetup_DsRoleAbortDownlevelServerUpgrade(struct pipes_struct *p,
+ 						  struct dssetup_DsRoleAbortDownlevelServerUpgrade *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/echo/srv_echo_nt.c
++++ b/source3/rpc_server/echo/srv_echo_nt.c
+@@ -87,13 +87,13 @@ void _echo_SourceData(struct pipes_struc
+ 
+ void _echo_TestCall(struct pipes_struct *p, struct echo_TestCall *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return;
+ }
+ 
+ NTSTATUS _echo_TestCall2(struct pipes_struct *p, struct echo_TestCall2 *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_OK;
+ }
+ 
+@@ -105,18 +105,18 @@ uint32 _echo_TestSleep(struct pipes_stru
+ 
+ void _echo_TestEnum(struct pipes_struct *p, struct echo_TestEnum *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return;
+ }
+ 
+ void _echo_TestSurrounding(struct pipes_struct *p, struct echo_TestSurrounding *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return;
+ }
+ 
+ uint16 _echo_TestDoublePointer(struct pipes_struct *p, struct echo_TestDoublePointer *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return 0;
+ }
+--- a/source3/rpc_server/epmapper/srv_epmapper.c
++++ b/source3/rpc_server/epmapper/srv_epmapper.c
+@@ -297,6 +297,7 @@ error_status_t _epm_Insert(struct pipes_
+ 	/* If this is not a priviledged users, return */
+ 	if (p->transport != NCALRPC ||
+ 	    !is_priviledged_pipe(p->session_info)) {
++		p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 		return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ 	}
+ 
+@@ -433,6 +434,7 @@ error_status_t _epm_Delete(struct pipes_
+ 	/* If this is not a priviledged users, return */
+ 	if (p->transport != NCALRPC ||
+ 	    !is_priviledged_pipe(p->session_info)) {
++		p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 		return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ 	}
+ 
+@@ -1096,7 +1098,7 @@ error_status_t _epm_LookupHandleFree(str
+ error_status_t _epm_InqObject(struct pipes_struct *p,
+ 		      struct epm_InqObject *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+ 
+@@ -1110,7 +1112,7 @@ error_status_t _epm_InqObject(struct pip
+ error_status_t _epm_MgmtDelete(struct pipes_struct *p,
+ 		       struct epm_MgmtDelete *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+ 
+@@ -1121,7 +1123,7 @@ error_status_t _epm_MgmtDelete(struct pi
+ error_status_t _epm_MapAuth(struct pipes_struct *p,
+ 		    struct epm_MapAuth *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+ 
+--- a/source3/rpc_server/eventlog/srv_eventlog_nt.c
++++ b/source3/rpc_server/eventlog/srv_eventlog_nt.c
+@@ -695,7 +695,7 @@ NTSTATUS _eventlog_GetNumRecords(struct
+ 
+ NTSTATUS _eventlog_BackupEventLogW(struct pipes_struct *p, struct eventlog_BackupEventLogW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -838,104 +838,104 @@ NTSTATUS _eventlog_ReportEventW(struct p
+ NTSTATUS _eventlog_DeregisterEventSource(struct pipes_struct *p,
+ 					 struct eventlog_DeregisterEventSource *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_ChangeNotify(struct pipes_struct *p,
+ 				struct eventlog_ChangeNotify *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_RegisterEventSourceW(struct pipes_struct *p,
+ 					struct eventlog_RegisterEventSourceW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_OpenBackupEventLogW(struct pipes_struct *p,
+ 				       struct eventlog_OpenBackupEventLogW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_ClearEventLogA(struct pipes_struct *p,
+ 				  struct eventlog_ClearEventLogA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_BackupEventLogA(struct pipes_struct *p,
+ 				   struct eventlog_BackupEventLogA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_OpenEventLogA(struct pipes_struct *p,
+ 				 struct eventlog_OpenEventLogA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_RegisterEventSourceA(struct pipes_struct *p,
+ 					struct eventlog_RegisterEventSourceA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_OpenBackupEventLogA(struct pipes_struct *p,
+ 				       struct eventlog_OpenBackupEventLogA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_ReadEventLogA(struct pipes_struct *p,
+ 				 struct eventlog_ReadEventLogA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_ReportEventA(struct pipes_struct *p,
+ 				struct eventlog_ReportEventA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_RegisterClusterSvc(struct pipes_struct *p,
+ 				      struct eventlog_RegisterClusterSvc *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_DeregisterClusterSvc(struct pipes_struct *p,
+ 					struct eventlog_DeregisterClusterSvc *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_WriteClusterEvents(struct pipes_struct *p,
+ 				      struct eventlog_WriteClusterEvents *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _eventlog_ReportEventAndSourceW(struct pipes_struct *p,
+ 					 struct eventlog_ReportEventAndSourceW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+--- a/source3/rpc_server/lsa/srv_lsa_nt.c
++++ b/source3/rpc_server/lsa/srv_lsa_nt.c
+@@ -817,7 +817,7 @@ NTSTATUS _lsa_QueryInfoPolicy2(struct pi
+ 	struct lsa_QueryInfoPolicy r;
+ 
+ 	if ((pdb_capabilities() & PDB_CAP_ADS) == 0) {
+-		p->rng_fault_state = True;
++		p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 		return NT_STATUS_NOT_IMPLEMENTED;
+ 	}
+ 
+@@ -3210,88 +3210,88 @@ NTSTATUS _lsa_Delete(struct pipes_struct
+ 
+ NTSTATUS _lsa_SetSecObj(struct pipes_struct *p, struct lsa_SetSecObj *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_ChangePassword(struct pipes_struct *p,
+ 			     struct lsa_ChangePassword *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetInfoPolicy(struct pipes_struct *p, struct lsa_SetInfoPolicy *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_ClearAuditLog(struct pipes_struct *p, struct lsa_ClearAuditLog *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_GetQuotasForAccount(struct pipes_struct *p,
+ 				  struct lsa_GetQuotasForAccount *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetQuotasForAccount(struct pipes_struct *p,
+ 				  struct lsa_SetQuotasForAccount *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetInformationTrustedDomain(struct pipes_struct *p,
+ 					  struct lsa_SetInformationTrustedDomain *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, struct lsa_QuerySecret *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetTrustedDomainInfo(struct pipes_struct *p,
+ 				   struct lsa_SetTrustedDomainInfo *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_StorePrivateData(struct pipes_struct *p,
+ 			       struct lsa_StorePrivateData *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_RetrievePrivateData(struct pipes_struct *p,
+ 				  struct lsa_RetrievePrivateData *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetInfoPolicy2(struct pipes_struct *p,
+ 			     struct lsa_SetInfoPolicy2 *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetTrustedDomainInfoByName(struct pipes_struct *p,
+ 					 struct lsa_SetTrustedDomainInfoByName *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -3310,7 +3310,7 @@ NTSTATUS _lsa_EnumTrustedDomainsEx(struc
+ 	 * _lsa_EnumTrustedDomains() afterwards - gd */
+ 
+ 	if (!(pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
+-		p->rng_fault_state = True;
++		p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 		return NT_STATUS_NOT_IMPLEMENTED;
+ 	}
+ 
+@@ -3379,107 +3379,107 @@ NTSTATUS _lsa_EnumTrustedDomainsEx(struc
+ NTSTATUS _lsa_QueryDomainInformationPolicy(struct pipes_struct *p,
+ 					   struct lsa_QueryDomainInformationPolicy *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_SetDomainInformationPolicy(struct pipes_struct *p,
+ 					 struct lsa_SetDomainInformationPolicy *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_TestCall(struct pipes_struct *p, struct lsa_TestCall *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRWRITE(struct pipes_struct *p, struct lsa_CREDRWRITE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRREAD(struct pipes_struct *p, struct lsa_CREDRREAD *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRENUMERATE(struct pipes_struct *p, struct lsa_CREDRENUMERATE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRWRITEDOMAINCREDENTIALS(struct pipes_struct *p,
+ 					  struct lsa_CREDRWRITEDOMAINCREDENTIALS *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRREADDOMAINCREDENTIALS(struct pipes_struct *p,
+ 					 struct lsa_CREDRREADDOMAINCREDENTIALS *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRDELETE(struct pipes_struct *p, struct lsa_CREDRDELETE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRGETTARGETINFO(struct pipes_struct *p,
+ 				 struct lsa_CREDRGETTARGETINFO *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRPROFILELOADED(struct pipes_struct *p,
+ 				 struct lsa_CREDRPROFILELOADED *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_CREDRGETSESSIONTYPES(struct pipes_struct *p,
+ 				   struct lsa_CREDRGETSESSIONTYPES *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSARREGISTERAUDITEVENT(struct pipes_struct *p,
+ 				     struct lsa_LSARREGISTERAUDITEVENT *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSARGENAUDITEVENT(struct pipes_struct *p,
+ 				struct lsa_LSARGENAUDITEVENT *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSARUNREGISTERAUDITEVENT(struct pipes_struct *p,
+ 				       struct lsa_LSARUNREGISTERAUDITEVENT *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_lsaRQueryForestTrustInformation(struct pipes_struct *p,
+ 					      struct lsa_lsaRQueryForestTrustInformation *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -3992,34 +3992,34 @@ NTSTATUS _lsa_lsaRSetForestTrustInformat
+ NTSTATUS _lsa_CREDRRENAME(struct pipes_struct *p,
+ 			  struct lsa_CREDRRENAME *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSAROPENPOLICYSCE(struct pipes_struct *p,
+ 				struct lsa_LSAROPENPOLICYSCE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct pipes_struct *p,
+ 						 struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct pipes_struct *p,
+ 						   struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+ NTSTATUS _lsa_LSARADTREPORTSECURITYEVENT(struct pipes_struct *p,
+ 					 struct lsa_LSARADTREPORTSECURITYEVENT *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
++++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
+@@ -1787,7 +1787,7 @@ NTSTATUS _netr_LogonSamLogonEx(struct pi
+ WERROR _netr_LogonUasLogon(struct pipes_struct *p,
+ 			   struct netr_LogonUasLogon *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -1797,7 +1797,7 @@ WERROR _netr_LogonUasLogon(struct pipes_
+ WERROR _netr_LogonUasLogoff(struct pipes_struct *p,
+ 			    struct netr_LogonUasLogoff *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -1807,7 +1807,7 @@ WERROR _netr_LogonUasLogoff(struct pipes
+ NTSTATUS _netr_DatabaseDeltas(struct pipes_struct *p,
+ 			      struct netr_DatabaseDeltas *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -1817,7 +1817,7 @@ NTSTATUS _netr_DatabaseDeltas(struct pip
+ NTSTATUS _netr_DatabaseSync(struct pipes_struct *p,
+ 			    struct netr_DatabaseSync *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -1827,7 +1827,7 @@ NTSTATUS _netr_DatabaseSync(struct pipes
+ NTSTATUS _netr_AccountDeltas(struct pipes_struct *p,
+ 			     struct netr_AccountDeltas *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -1837,7 +1837,7 @@ NTSTATUS _netr_AccountDeltas(struct pipe
+ NTSTATUS _netr_AccountSync(struct pipes_struct *p,
+ 			   struct netr_AccountSync *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -1978,7 +1978,7 @@ WERROR _netr_GetAnyDCName(struct pipes_s
+ NTSTATUS _netr_DatabaseSync2(struct pipes_struct *p,
+ 			     struct netr_DatabaseSync2 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -1988,7 +1988,7 @@ NTSTATUS _netr_DatabaseSync2(struct pipe
+ NTSTATUS _netr_DatabaseRedo(struct pipes_struct *p,
+ 			    struct netr_DatabaseRedo *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -1998,7 +1998,7 @@ NTSTATUS _netr_DatabaseRedo(struct pipes
+ WERROR _netr_DsRGetDCName(struct pipes_struct *p,
+ 			  struct netr_DsRGetDCName *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2017,7 +2017,7 @@ NTSTATUS _netr_LogonGetCapabilities(stru
+ WERROR _netr_NETRLOGONSETSERVICEBITS(struct pipes_struct *p,
+ 				     struct netr_NETRLOGONSETSERVICEBITS *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2027,7 +2027,7 @@ WERROR _netr_NETRLOGONSETSERVICEBITS(str
+ WERROR _netr_LogonGetTrustRid(struct pipes_struct *p,
+ 			      struct netr_LogonGetTrustRid *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2037,7 +2037,7 @@ WERROR _netr_LogonGetTrustRid(struct pip
+ WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(struct pipes_struct *p,
+ 					  struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2047,7 +2047,7 @@ WERROR _netr_NETRLOGONCOMPUTESERVERDIGES
+ WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(struct pipes_struct *p,
+ 					  struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2057,7 +2057,7 @@ WERROR _netr_NETRLOGONCOMPUTECLIENTDIGES
+ WERROR _netr_DsRGetDCNameEx(struct pipes_struct *p,
+ 			    struct netr_DsRGetDCNameEx *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2067,7 +2067,7 @@ WERROR _netr_DsRGetDCNameEx(struct pipes
+ WERROR _netr_DsRGetSiteName(struct pipes_struct *p,
+ 			    struct netr_DsRGetSiteName *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2077,7 +2077,7 @@ WERROR _netr_DsRGetSiteName(struct pipes
+ NTSTATUS _netr_LogonGetDomainInfo(struct pipes_struct *p,
+ 				  struct netr_LogonGetDomainInfo *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -2087,7 +2087,7 @@ NTSTATUS _netr_LogonGetDomainInfo(struct
+ WERROR _netr_ServerPasswordGet(struct pipes_struct *p,
+ 			       struct netr_ServerPasswordGet *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2097,7 +2097,7 @@ WERROR _netr_ServerPasswordGet(struct pi
+ WERROR _netr_NETRLOGONSENDTOSAM(struct pipes_struct *p,
+ 				struct netr_NETRLOGONSENDTOSAM *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2107,7 +2107,7 @@ WERROR _netr_NETRLOGONSENDTOSAM(struct p
+ WERROR _netr_DsRAddressToSitenamesW(struct pipes_struct *p,
+ 				    struct netr_DsRAddressToSitenamesW *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2117,7 +2117,7 @@ WERROR _netr_DsRAddressToSitenamesW(stru
+ WERROR _netr_DsRGetDCNameEx2(struct pipes_struct *p,
+ 			     struct netr_DsRGetDCNameEx2 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2127,7 +2127,7 @@ WERROR _netr_DsRGetDCNameEx2(struct pipe
+ WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct pipes_struct *p,
+ 						 struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2137,7 +2137,7 @@ WERROR _netr_NETRLOGONGETTIMESERVICEPARE
+ WERROR _netr_NetrEnumerateTrustedDomainsEx(struct pipes_struct *p,
+ 					   struct netr_NetrEnumerateTrustedDomainsEx *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2147,7 +2147,7 @@ WERROR _netr_NetrEnumerateTrustedDomains
+ WERROR _netr_DsRAddressToSitenamesExW(struct pipes_struct *p,
+ 				      struct netr_DsRAddressToSitenamesExW *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2157,7 +2157,7 @@ WERROR _netr_DsRAddressToSitenamesExW(st
+ WERROR _netr_DsrGetDcSiteCoverageW(struct pipes_struct *p,
+ 				   struct netr_DsrGetDcSiteCoverageW *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2167,7 +2167,7 @@ WERROR _netr_DsrGetDcSiteCoverageW(struc
+ WERROR _netr_DsrEnumerateDomainTrusts(struct pipes_struct *p,
+ 				      struct netr_DsrEnumerateDomainTrusts *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2177,7 +2177,7 @@ WERROR _netr_DsrEnumerateDomainTrusts(st
+ WERROR _netr_DsrDeregisterDNSHostRecords(struct pipes_struct *p,
+ 					 struct netr_DsrDeregisterDNSHostRecords *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2187,7 +2187,7 @@ WERROR _netr_DsrDeregisterDNSHostRecords
+ NTSTATUS _netr_ServerTrustPasswordsGet(struct pipes_struct *p,
+ 				       struct netr_ServerTrustPasswordsGet *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -2197,7 +2197,7 @@ NTSTATUS _netr_ServerTrustPasswordsGet(s
+ WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p,
+ 					  struct netr_DsRGetForestTrustInformation *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -2476,7 +2476,7 @@ NTSTATUS _netr_ServerGetTrustInfo(struct
+ NTSTATUS _netr_Unused47(struct pipes_struct *p,
+ 			struct netr_Unused47 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -2486,6 +2486,6 @@ NTSTATUS _netr_Unused47(struct pipes_str
+ NTSTATUS _netr_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
+ 						 struct netr_DsrUpdateReadOnlyServerDnsRecords *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+--- a/source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c
++++ b/source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c
+@@ -227,7 +227,7 @@ WERROR _PNP_HwProfFlags(struct pipes_str
+ WERROR _PNP_Disconnect(struct pipes_struct *p,
+ 		       struct PNP_Disconnect *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -237,7 +237,7 @@ WERROR _PNP_Disconnect(struct pipes_stru
+ WERROR _PNP_Connect(struct pipes_struct *p,
+ 		    struct PNP_Connect *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -247,7 +247,7 @@ WERROR _PNP_Connect(struct pipes_struct
+ WERROR _PNP_GetGlobalState(struct pipes_struct *p,
+ 			   struct PNP_GetGlobalState *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -257,7 +257,7 @@ WERROR _PNP_GetGlobalState(struct pipes_
+ WERROR _PNP_InitDetection(struct pipes_struct *p,
+ 			  struct PNP_InitDetection *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -267,7 +267,7 @@ WERROR _PNP_InitDetection(struct pipes_s
+ WERROR _PNP_ReportLogOn(struct pipes_struct *p,
+ 			struct PNP_ReportLogOn *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -277,7 +277,7 @@ WERROR _PNP_ReportLogOn(struct pipes_str
+ WERROR _PNP_GetRootDeviceInstance(struct pipes_struct *p,
+ 				  struct PNP_GetRootDeviceInstance *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -287,7 +287,7 @@ WERROR _PNP_GetRootDeviceInstance(struct
+ WERROR _PNP_GetRelatedDeviceInstance(struct pipes_struct *p,
+ 				     struct PNP_GetRelatedDeviceInstance *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -297,7 +297,7 @@ WERROR _PNP_GetRelatedDeviceInstance(str
+ WERROR _PNP_EnumerateSubKeys(struct pipes_struct *p,
+ 			     struct PNP_EnumerateSubKeys *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -307,7 +307,7 @@ WERROR _PNP_EnumerateSubKeys(struct pipe
+ WERROR _PNP_GetDepth(struct pipes_struct *p,
+ 		     struct PNP_GetDepth *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -317,7 +317,7 @@ WERROR _PNP_GetDepth(struct pipes_struct
+ WERROR _PNP_SetDeviceRegProp(struct pipes_struct *p,
+ 			     struct PNP_SetDeviceRegProp *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -327,7 +327,7 @@ WERROR _PNP_SetDeviceRegProp(struct pipe
+ WERROR _PNP_GetClassInstance(struct pipes_struct *p,
+ 			     struct PNP_GetClassInstance *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -337,7 +337,7 @@ WERROR _PNP_GetClassInstance(struct pipe
+ WERROR _PNP_CreateKey(struct pipes_struct *p,
+ 		      struct PNP_CreateKey *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -347,7 +347,7 @@ WERROR _PNP_CreateKey(struct pipes_struc
+ WERROR _PNP_DeleteRegistryKey(struct pipes_struct *p,
+ 			      struct PNP_DeleteRegistryKey *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -357,7 +357,7 @@ WERROR _PNP_DeleteRegistryKey(struct pip
+ WERROR _PNP_GetClassCount(struct pipes_struct *p,
+ 			  struct PNP_GetClassCount *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -367,7 +367,7 @@ WERROR _PNP_GetClassCount(struct pipes_s
+ WERROR _PNP_GetClassName(struct pipes_struct *p,
+ 			 struct PNP_GetClassName *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -377,7 +377,7 @@ WERROR _PNP_GetClassName(struct pipes_st
+ WERROR _PNP_DeleteClassKey(struct pipes_struct *p,
+ 			   struct PNP_DeleteClassKey *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -387,7 +387,7 @@ WERROR _PNP_DeleteClassKey(struct pipes_
+ WERROR _PNP_GetInterfaceDeviceAlias(struct pipes_struct *p,
+ 				    struct PNP_GetInterfaceDeviceAlias *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -397,7 +397,7 @@ WERROR _PNP_GetInterfaceDeviceAlias(stru
+ WERROR _PNP_GetInterfaceDeviceList(struct pipes_struct *p,
+ 				   struct PNP_GetInterfaceDeviceList *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -407,7 +407,7 @@ WERROR _PNP_GetInterfaceDeviceList(struc
+ WERROR _PNP_GetInterfaceDeviceListSize(struct pipes_struct *p,
+ 				       struct PNP_GetInterfaceDeviceListSize *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -417,7 +417,7 @@ WERROR _PNP_GetInterfaceDeviceListSize(s
+ WERROR _PNP_RegisterDeviceClassAssociation(struct pipes_struct *p,
+ 					   struct PNP_RegisterDeviceClassAssociation *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -427,7 +427,7 @@ WERROR _PNP_RegisterDeviceClassAssociati
+ WERROR _PNP_UnregisterDeviceClassAssociation(struct pipes_struct *p,
+ 					     struct PNP_UnregisterDeviceClassAssociation *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -437,7 +437,7 @@ WERROR _PNP_UnregisterDeviceClassAssocia
+ WERROR _PNP_GetClassRegProp(struct pipes_struct *p,
+ 			    struct PNP_GetClassRegProp *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -447,7 +447,7 @@ WERROR _PNP_GetClassRegProp(struct pipes
+ WERROR _PNP_SetClassRegProp(struct pipes_struct *p,
+ 			    struct PNP_SetClassRegProp *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -457,7 +457,7 @@ WERROR _PNP_SetClassRegProp(struct pipes
+ WERROR _PNP_CreateDevInst(struct pipes_struct *p,
+ 			  struct PNP_CreateDevInst *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -467,7 +467,7 @@ WERROR _PNP_CreateDevInst(struct pipes_s
+ WERROR _PNP_DeviceInstanceAction(struct pipes_struct *p,
+ 				 struct PNP_DeviceInstanceAction *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -477,7 +477,7 @@ WERROR _PNP_DeviceInstanceAction(struct
+ WERROR _PNP_GetDeviceStatus(struct pipes_struct *p,
+ 			    struct PNP_GetDeviceStatus *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -487,7 +487,7 @@ WERROR _PNP_GetDeviceStatus(struct pipes
+ WERROR _PNP_SetDeviceProblem(struct pipes_struct *p,
+ 			     struct PNP_SetDeviceProblem *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -497,7 +497,7 @@ WERROR _PNP_SetDeviceProblem(struct pipe
+ WERROR _PNP_DisableDevInst(struct pipes_struct *p,
+ 			   struct PNP_DisableDevInst *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -507,7 +507,7 @@ WERROR _PNP_DisableDevInst(struct pipes_
+ WERROR _PNP_UninstallDevInst(struct pipes_struct *p,
+ 			     struct PNP_UninstallDevInst *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -517,7 +517,7 @@ WERROR _PNP_UninstallDevInst(struct pipe
+ WERROR _PNP_AddID(struct pipes_struct *p,
+ 		  struct PNP_AddID *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -527,7 +527,7 @@ WERROR _PNP_AddID(struct pipes_struct *p
+ WERROR _PNP_RegisterDriver(struct pipes_struct *p,
+ 			   struct PNP_RegisterDriver *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -537,7 +537,7 @@ WERROR _PNP_RegisterDriver(struct pipes_
+ WERROR _PNP_QueryRemove(struct pipes_struct *p,
+ 			struct PNP_QueryRemove *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -547,7 +547,7 @@ WERROR _PNP_QueryRemove(struct pipes_str
+ WERROR _PNP_RequestDeviceEject(struct pipes_struct *p,
+ 			       struct PNP_RequestDeviceEject *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -557,7 +557,7 @@ WERROR _PNP_RequestDeviceEject(struct pi
+ WERROR _PNP_IsDockStationPresent(struct pipes_struct *p,
+ 				 struct PNP_IsDockStationPresent *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -567,7 +567,7 @@ WERROR _PNP_IsDockStationPresent(struct
+ WERROR _PNP_RequestEjectPC(struct pipes_struct *p,
+ 			   struct PNP_RequestEjectPC *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -577,7 +577,7 @@ WERROR _PNP_RequestEjectPC(struct pipes_
+ WERROR _PNP_AddEmptyLogConf(struct pipes_struct *p,
+ 			    struct PNP_AddEmptyLogConf *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -587,7 +587,7 @@ WERROR _PNP_AddEmptyLogConf(struct pipes
+ WERROR _PNP_FreeLogConf(struct pipes_struct *p,
+ 			struct PNP_FreeLogConf *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -597,7 +597,7 @@ WERROR _PNP_FreeLogConf(struct pipes_str
+ WERROR _PNP_GetFirstLogConf(struct pipes_struct *p,
+ 			    struct PNP_GetFirstLogConf *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -607,7 +607,7 @@ WERROR _PNP_GetFirstLogConf(struct pipes
+ WERROR _PNP_GetNextLogConf(struct pipes_struct *p,
+ 			   struct PNP_GetNextLogConf *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -617,7 +617,7 @@ WERROR _PNP_GetNextLogConf(struct pipes_
+ WERROR _PNP_GetLogConfPriority(struct pipes_struct *p,
+ 			       struct PNP_GetLogConfPriority *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -627,7 +627,7 @@ WERROR _PNP_GetLogConfPriority(struct pi
+ WERROR _PNP_AddResDes(struct pipes_struct *p,
+ 		      struct PNP_AddResDes *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -637,7 +637,7 @@ WERROR _PNP_AddResDes(struct pipes_struc
+ WERROR _PNP_FreeResDes(struct pipes_struct *p,
+ 		       struct PNP_FreeResDes *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -647,7 +647,7 @@ WERROR _PNP_FreeResDes(struct pipes_stru
+ WERROR _PNP_GetNextResDes(struct pipes_struct *p,
+ 			  struct PNP_GetNextResDes *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -657,7 +657,7 @@ WERROR _PNP_GetNextResDes(struct pipes_s
+ WERROR _PNP_GetResDesData(struct pipes_struct *p,
+ 			  struct PNP_GetResDesData *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -667,7 +667,7 @@ WERROR _PNP_GetResDesData(struct pipes_s
+ WERROR _PNP_GetResDesDataSize(struct pipes_struct *p,
+ 			      struct PNP_GetResDesDataSize *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -677,7 +677,7 @@ WERROR _PNP_GetResDesDataSize(struct pip
+ WERROR _PNP_ModifyResDes(struct pipes_struct *p,
+ 			 struct PNP_ModifyResDes *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -687,7 +687,7 @@ WERROR _PNP_ModifyResDes(struct pipes_st
+ WERROR _PNP_DetectResourceLimit(struct pipes_struct *p,
+ 				struct PNP_DetectResourceLimit *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -697,7 +697,7 @@ WERROR _PNP_DetectResourceLimit(struct p
+ WERROR _PNP_QueryResConfList(struct pipes_struct *p,
+ 			     struct PNP_QueryResConfList *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -707,7 +707,7 @@ WERROR _PNP_QueryResConfList(struct pipe
+ WERROR _PNP_SetHwProf(struct pipes_struct *p,
+ 		      struct PNP_SetHwProf *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -717,7 +717,7 @@ WERROR _PNP_SetHwProf(struct pipes_struc
+ WERROR _PNP_QueryArbitratorFreeData(struct pipes_struct *p,
+ 				    struct PNP_QueryArbitratorFreeData *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -727,7 +727,7 @@ WERROR _PNP_QueryArbitratorFreeData(stru
+ WERROR _PNP_QueryArbitratorFreeSize(struct pipes_struct *p,
+ 				    struct PNP_QueryArbitratorFreeSize *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -737,7 +737,7 @@ WERROR _PNP_QueryArbitratorFreeSize(stru
+ WERROR _PNP_RunDetection(struct pipes_struct *p,
+ 			 struct PNP_RunDetection *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -747,7 +747,7 @@ WERROR _PNP_RunDetection(struct pipes_st
+ WERROR _PNP_RegisterNotification(struct pipes_struct *p,
+ 				 struct PNP_RegisterNotification *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -757,7 +757,7 @@ WERROR _PNP_RegisterNotification(struct
+ WERROR _PNP_UnregisterNotification(struct pipes_struct *p,
+ 				   struct PNP_UnregisterNotification *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -767,7 +767,7 @@ WERROR _PNP_UnregisterNotification(struc
+ WERROR _PNP_GetCustomDevProp(struct pipes_struct *p,
+ 			     struct PNP_GetCustomDevProp *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -777,7 +777,7 @@ WERROR _PNP_GetCustomDevProp(struct pipe
+ WERROR _PNP_GetVersionInternal(struct pipes_struct *p,
+ 			       struct PNP_GetVersionInternal *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -787,7 +787,7 @@ WERROR _PNP_GetVersionInternal(struct pi
+ WERROR _PNP_GetBlockedDriverInfo(struct pipes_struct *p,
+ 				 struct PNP_GetBlockedDriverInfo *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -797,6 +797,6 @@ WERROR _PNP_GetBlockedDriverInfo(struct
+ WERROR _PNP_GetServerSideDeviceInstallFlags(struct pipes_struct *p,
+ 					    struct PNP_GetServerSideDeviceInstallFlags *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/rpc_handles.c
++++ b/source3/rpc_server/rpc_handles.c
+@@ -242,7 +242,7 @@ static struct dcesrv_handle *find_policy
+ 	DEBUG(4,("Policy not found: "));
+ 	dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
+ 
+-	p->bad_handle_fault_state = true;
++	p->fault_state = DCERPC_FAULT_CONTEXT_MISMATCH;
+ 
+ 	return NULL;
+ }
+--- a/source3/rpc_server/rpc_ncacn_np.c
++++ b/source3/rpc_server/rpc_ncacn_np.c
+@@ -216,24 +216,13 @@ static NTSTATUS rpcint_dispatch(struct p
+ 	}
+ 
+ 	if (p->fault_state) {
+-		p->fault_state = false;
+-		data_blob_free(&p->out_data.rdata);
+-		talloc_free_children(p->mem_ctx);
+-		return NT_STATUS_RPC_CALL_FAILED;
+-	}
+-
+-	if (p->bad_handle_fault_state) {
+-		p->bad_handle_fault_state = false;
+-		data_blob_free(&p->out_data.rdata);
+-		talloc_free_children(p->mem_ctx);
+-		return NT_STATUS_RPC_SS_CONTEXT_MISMATCH;
+-	}
++		NTSTATUS status;
+ 
+-	if (p->rng_fault_state) {
+-		p->rng_fault_state = false;
++		status = NT_STATUS(p->fault_state);
++		p->fault_state = 0;
+ 		data_blob_free(&p->out_data.rdata);
+ 		talloc_free_children(p->mem_ctx);
+-		return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
++		return status;
+ 	}
+ 
+ 	*out_data = p->out_data.rdata;
+--- a/source3/rpc_server/samr/srv_samr_nt.c
++++ b/source3/rpc_server/samr/srv_samr_nt.c
+@@ -6682,7 +6682,7 @@ NTSTATUS _samr_ValidatePassword(struct p
+ NTSTATUS _samr_Shutdown(struct pipes_struct *p,
+ 			struct samr_Shutdown *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6692,7 +6692,7 @@ NTSTATUS _samr_Shutdown(struct pipes_str
+ NTSTATUS _samr_SetMemberAttributesOfGroup(struct pipes_struct *p,
+ 					  struct samr_SetMemberAttributesOfGroup *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6702,6 +6702,7 @@ NTSTATUS _samr_SetMemberAttributesOfGrou
+ NTSTATUS _samr_TestPrivateFunctionsDomain(struct pipes_struct *p,
+ 					  struct samr_TestPrivateFunctionsDomain *r)
+ {
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6711,6 +6712,7 @@ NTSTATUS _samr_TestPrivateFunctionsDomai
+ NTSTATUS _samr_TestPrivateFunctionsUser(struct pipes_struct *p,
+ 					struct samr_TestPrivateFunctionsUser *r)
+ {
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6720,7 +6722,7 @@ NTSTATUS _samr_TestPrivateFunctionsUser(
+ NTSTATUS _samr_AddMultipleMembersToAlias(struct pipes_struct *p,
+ 					 struct samr_AddMultipleMembersToAlias *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6730,7 +6732,7 @@ NTSTATUS _samr_AddMultipleMembersToAlias
+ NTSTATUS _samr_RemoveMultipleMembersFromAlias(struct pipes_struct *p,
+ 					      struct samr_RemoveMultipleMembersFromAlias *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6740,7 +6742,7 @@ NTSTATUS _samr_RemoveMultipleMembersFrom
+ NTSTATUS _samr_SetBootKeyInformation(struct pipes_struct *p,
+ 				     struct samr_SetBootKeyInformation *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6750,7 +6752,7 @@ NTSTATUS _samr_SetBootKeyInformation(str
+ NTSTATUS _samr_GetBootKeyInformation(struct pipes_struct *p,
+ 				     struct samr_GetBootKeyInformation *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ 
+@@ -6760,6 +6762,6 @@ NTSTATUS _samr_GetBootKeyInformation(str
+ NTSTATUS _samr_SetDsrmPassword(struct pipes_struct *p,
+ 			       struct samr_SetDsrmPassword *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return NT_STATUS_NOT_IMPLEMENTED;
+ }
+--- a/source3/rpc_server/spoolss/srv_spoolss_nt.c
++++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c
+@@ -10156,7 +10156,7 @@ WERROR _spoolss_AddPort(struct pipes_str
+ WERROR _spoolss_GetPrinterDriver(struct pipes_struct *p,
+ 				 struct spoolss_GetPrinterDriver *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10167,7 +10167,7 @@ WERROR _spoolss_GetPrinterDriver(struct
+ WERROR _spoolss_ReadPrinter(struct pipes_struct *p,
+ 			    struct spoolss_ReadPrinter *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10178,7 +10178,7 @@ WERROR _spoolss_ReadPrinter(struct pipes
+ WERROR _spoolss_WaitForPrinterChange(struct pipes_struct *p,
+ 				     struct spoolss_WaitForPrinterChange *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10189,7 +10189,7 @@ WERROR _spoolss_WaitForPrinterChange(str
+ WERROR _spoolss_ConfigurePort(struct pipes_struct *p,
+ 			      struct spoolss_ConfigurePort *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10200,7 +10200,7 @@ WERROR _spoolss_ConfigurePort(struct pip
+ WERROR _spoolss_DeletePort(struct pipes_struct *p,
+ 			   struct spoolss_DeletePort *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10211,7 +10211,7 @@ WERROR _spoolss_DeletePort(struct pipes_
+ WERROR _spoolss_CreatePrinterIC(struct pipes_struct *p,
+ 				struct spoolss_CreatePrinterIC *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10222,7 +10222,7 @@ WERROR _spoolss_CreatePrinterIC(struct p
+ WERROR _spoolss_PlayGDIScriptOnPrinterIC(struct pipes_struct *p,
+ 					 struct spoolss_PlayGDIScriptOnPrinterIC *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10233,7 +10233,7 @@ WERROR _spoolss_PlayGDIScriptOnPrinterIC
+ WERROR _spoolss_DeletePrinterIC(struct pipes_struct *p,
+ 				struct spoolss_DeletePrinterIC *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10244,7 +10244,7 @@ WERROR _spoolss_DeletePrinterIC(struct p
+ WERROR _spoolss_AddPrinterConnection(struct pipes_struct *p,
+ 				     struct spoolss_AddPrinterConnection *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10255,7 +10255,7 @@ WERROR _spoolss_AddPrinterConnection(str
+ WERROR _spoolss_DeletePrinterConnection(struct pipes_struct *p,
+ 					struct spoolss_DeletePrinterConnection *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10266,7 +10266,7 @@ WERROR _spoolss_DeletePrinterConnection(
+ WERROR _spoolss_PrinterMessageBox(struct pipes_struct *p,
+ 				  struct spoolss_PrinterMessageBox *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10277,7 +10277,7 @@ WERROR _spoolss_PrinterMessageBox(struct
+ WERROR _spoolss_AddMonitor(struct pipes_struct *p,
+ 			   struct spoolss_AddMonitor *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10288,7 +10288,7 @@ WERROR _spoolss_AddMonitor(struct pipes_
+ WERROR _spoolss_DeleteMonitor(struct pipes_struct *p,
+ 			      struct spoolss_DeleteMonitor *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10299,7 +10299,7 @@ WERROR _spoolss_DeleteMonitor(struct pip
+ WERROR _spoolss_DeletePrintProcessor(struct pipes_struct *p,
+ 				     struct spoolss_DeletePrintProcessor *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10310,7 +10310,7 @@ WERROR _spoolss_DeletePrintProcessor(str
+ WERROR _spoolss_AddPrintProvidor(struct pipes_struct *p,
+ 				 struct spoolss_AddPrintProvidor *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10321,7 +10321,7 @@ WERROR _spoolss_AddPrintProvidor(struct
+ WERROR _spoolss_DeletePrintProvidor(struct pipes_struct *p,
+ 				    struct spoolss_DeletePrintProvidor *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10332,7 +10332,7 @@ WERROR _spoolss_DeletePrintProvidor(stru
+ WERROR _spoolss_FindFirstPrinterChangeNotification(struct pipes_struct *p,
+ 						   struct spoolss_FindFirstPrinterChangeNotification *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10343,7 +10343,7 @@ WERROR _spoolss_FindFirstPrinterChangeNo
+ WERROR _spoolss_FindNextPrinterChangeNotification(struct pipes_struct *p,
+ 						  struct spoolss_FindNextPrinterChangeNotification *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10354,7 +10354,7 @@ WERROR _spoolss_FindNextPrinterChangeNot
+ WERROR _spoolss_RouterFindFirstPrinterChangeNotificationOld(struct pipes_struct *p,
+ 							    struct spoolss_RouterFindFirstPrinterChangeNotificationOld *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10365,7 +10365,7 @@ WERROR _spoolss_RouterFindFirstPrinterCh
+ WERROR _spoolss_ReplyOpenPrinter(struct pipes_struct *p,
+ 				 struct spoolss_ReplyOpenPrinter *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10376,7 +10376,7 @@ WERROR _spoolss_ReplyOpenPrinter(struct
+ WERROR _spoolss_RouterReplyPrinter(struct pipes_struct *p,
+ 				   struct spoolss_RouterReplyPrinter *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10387,7 +10387,7 @@ WERROR _spoolss_RouterReplyPrinter(struc
+ WERROR _spoolss_ReplyClosePrinter(struct pipes_struct *p,
+ 				  struct spoolss_ReplyClosePrinter *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10398,7 +10398,7 @@ WERROR _spoolss_ReplyClosePrinter(struct
+ WERROR _spoolss_AddPortEx(struct pipes_struct *p,
+ 			  struct spoolss_AddPortEx *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10409,7 +10409,7 @@ WERROR _spoolss_AddPortEx(struct pipes_s
+ WERROR _spoolss_RouterFindFirstPrinterChangeNotification(struct pipes_struct *p,
+ 							 struct spoolss_RouterFindFirstPrinterChangeNotification *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10420,7 +10420,7 @@ WERROR _spoolss_RouterFindFirstPrinterCh
+ WERROR _spoolss_SpoolerInit(struct pipes_struct *p,
+ 			    struct spoolss_SpoolerInit *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10431,7 +10431,7 @@ WERROR _spoolss_SpoolerInit(struct pipes
+ WERROR _spoolss_ResetPrinterEx(struct pipes_struct *p,
+ 			       struct spoolss_ResetPrinterEx *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10442,7 +10442,7 @@ WERROR _spoolss_ResetPrinterEx(struct pi
+ WERROR _spoolss_RouterReplyPrinterEx(struct pipes_struct *p,
+ 				     struct spoolss_RouterReplyPrinterEx *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10453,7 +10453,7 @@ WERROR _spoolss_RouterReplyPrinterEx(str
+ WERROR _spoolss_44(struct pipes_struct *p,
+ 		   struct spoolss_44 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10464,7 +10464,7 @@ WERROR _spoolss_44(struct pipes_struct *
+ WERROR _spoolss_SetPort(struct pipes_struct *p,
+ 			struct spoolss_SetPort *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10475,7 +10475,7 @@ WERROR _spoolss_SetPort(struct pipes_str
+ WERROR _spoolss_4a(struct pipes_struct *p,
+ 		   struct spoolss_4a *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10486,7 +10486,7 @@ WERROR _spoolss_4a(struct pipes_struct *
+ WERROR _spoolss_4b(struct pipes_struct *p,
+ 		   struct spoolss_4b *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10497,7 +10497,7 @@ WERROR _spoolss_4b(struct pipes_struct *
+ WERROR _spoolss_4c(struct pipes_struct *p,
+ 		   struct spoolss_4c *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10508,7 +10508,7 @@ WERROR _spoolss_4c(struct pipes_struct *
+ WERROR _spoolss_53(struct pipes_struct *p,
+ 		   struct spoolss_53 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10519,7 +10519,7 @@ WERROR _spoolss_53(struct pipes_struct *
+ WERROR _spoolss_AddPerMachineConnection(struct pipes_struct *p,
+ 					struct spoolss_AddPerMachineConnection *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10530,7 +10530,7 @@ WERROR _spoolss_AddPerMachineConnection(
+ WERROR _spoolss_DeletePerMachineConnection(struct pipes_struct *p,
+ 					   struct spoolss_DeletePerMachineConnection *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10541,7 +10541,7 @@ WERROR _spoolss_DeletePerMachineConnecti
+ WERROR _spoolss_EnumPerMachineConnections(struct pipes_struct *p,
+ 					  struct spoolss_EnumPerMachineConnections *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10552,7 +10552,7 @@ WERROR _spoolss_EnumPerMachineConnection
+ WERROR _spoolss_5a(struct pipes_struct *p,
+ 		   struct spoolss_5a *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10563,7 +10563,7 @@ WERROR _spoolss_5a(struct pipes_struct *
+ WERROR _spoolss_5b(struct pipes_struct *p,
+ 		   struct spoolss_5b *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10574,7 +10574,7 @@ WERROR _spoolss_5b(struct pipes_struct *
+ WERROR _spoolss_5c(struct pipes_struct *p,
+ 		   struct spoolss_5c *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10585,7 +10585,7 @@ WERROR _spoolss_5c(struct pipes_struct *
+ WERROR _spoolss_5d(struct pipes_struct *p,
+ 		   struct spoolss_5d *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10596,7 +10596,7 @@ WERROR _spoolss_5d(struct pipes_struct *
+ WERROR _spoolss_5e(struct pipes_struct *p,
+ 		   struct spoolss_5e *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10607,7 +10607,7 @@ WERROR _spoolss_5e(struct pipes_struct *
+ WERROR _spoolss_5f(struct pipes_struct *p,
+ 		   struct spoolss_5f *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10618,7 +10618,7 @@ WERROR _spoolss_5f(struct pipes_struct *
+ WERROR _spoolss_60(struct pipes_struct *p,
+ 		   struct spoolss_60 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10629,7 +10629,7 @@ WERROR _spoolss_60(struct pipes_struct *
+ WERROR _spoolss_61(struct pipes_struct *p,
+ 		   struct spoolss_61 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10640,7 +10640,7 @@ WERROR _spoolss_61(struct pipes_struct *
+ WERROR _spoolss_62(struct pipes_struct *p,
+ 		   struct spoolss_62 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10651,7 +10651,7 @@ WERROR _spoolss_62(struct pipes_struct *
+ WERROR _spoolss_63(struct pipes_struct *p,
+ 		   struct spoolss_63 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10662,7 +10662,7 @@ WERROR _spoolss_63(struct pipes_struct *
+ WERROR _spoolss_64(struct pipes_struct *p,
+ 		   struct spoolss_64 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10673,7 +10673,7 @@ WERROR _spoolss_64(struct pipes_struct *
+ WERROR _spoolss_65(struct pipes_struct *p,
+ 		   struct spoolss_65 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10684,7 +10684,7 @@ WERROR _spoolss_65(struct pipes_struct *
+ WERROR _spoolss_GetCorePrinterDrivers(struct pipes_struct *p,
+ 				      struct spoolss_GetCorePrinterDrivers *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10695,7 +10695,7 @@ WERROR _spoolss_GetCorePrinterDrivers(st
+ WERROR _spoolss_67(struct pipes_struct *p,
+ 		   struct spoolss_67 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10706,7 +10706,7 @@ WERROR _spoolss_67(struct pipes_struct *
+ WERROR _spoolss_GetPrinterDriverPackagePath(struct pipes_struct *p,
+ 					    struct spoolss_GetPrinterDriverPackagePath *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10717,7 +10717,7 @@ WERROR _spoolss_GetPrinterDriverPackageP
+ WERROR _spoolss_69(struct pipes_struct *p,
+ 		   struct spoolss_69 *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10728,7 +10728,7 @@ WERROR _spoolss_69(struct pipes_struct *
+ WERROR _spoolss_6a(struct pipes_struct *p,
+ 		   struct spoolss_6a *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10739,7 +10739,7 @@ WERROR _spoolss_6a(struct pipes_struct *
+ WERROR _spoolss_6b(struct pipes_struct *p,
+ 		   struct spoolss_6b *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10750,7 +10750,7 @@ WERROR _spoolss_6b(struct pipes_struct *
+ WERROR _spoolss_6c(struct pipes_struct *p,
+ 		   struct spoolss_6c *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -10761,6 +10761,6 @@ WERROR _spoolss_6c(struct pipes_struct *
+ WERROR _spoolss_6d(struct pipes_struct *p,
+ 		   struct spoolss_6d *r)
+ {
+-	p->rng_fault_state = true;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
++++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+@@ -2548,244 +2548,244 @@ WERROR _srvsvc_NetFileClose(struct pipes
+ WERROR _srvsvc_NetCharDevEnum(struct pipes_struct *p,
+ 			      struct srvsvc_NetCharDevEnum *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevGetInfo(struct pipes_struct *p,
+ 				 struct srvsvc_NetCharDevGetInfo *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevControl(struct pipes_struct *p,
+ 				 struct srvsvc_NetCharDevControl *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevQEnum(struct pipes_struct *p,
+ 			       struct srvsvc_NetCharDevQEnum *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevQGetInfo(struct pipes_struct *p,
+ 				  struct srvsvc_NetCharDevQGetInfo *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevQSetInfo(struct pipes_struct *p,
+ 				  struct srvsvc_NetCharDevQSetInfo *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevQPurge(struct pipes_struct *p,
+ 				struct srvsvc_NetCharDevQPurge *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetCharDevQPurgeSelf(struct pipes_struct *p,
+ 				    struct srvsvc_NetCharDevQPurgeSelf *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetFileGetInfo(struct pipes_struct *p,
+ 			      struct srvsvc_NetFileGetInfo *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetShareCheck(struct pipes_struct *p,
+ 			     struct srvsvc_NetShareCheck *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetServerStatisticsGet(struct pipes_struct *p,
+ 				      struct srvsvc_NetServerStatisticsGet *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetTransportAdd(struct pipes_struct *p,
+ 			       struct srvsvc_NetTransportAdd *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetTransportEnum(struct pipes_struct *p,
+ 				struct srvsvc_NetTransportEnum *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetTransportDel(struct pipes_struct *p,
+ 			       struct srvsvc_NetTransportDel *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetSetServiceBits(struct pipes_struct *p,
+ 				 struct srvsvc_NetSetServiceBits *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetPathType(struct pipes_struct *p,
+ 			   struct srvsvc_NetPathType *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetPathCanonicalize(struct pipes_struct *p,
+ 				   struct srvsvc_NetPathCanonicalize *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetPathCompare(struct pipes_struct *p,
+ 			      struct srvsvc_NetPathCompare *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRPRNAMECANONICALIZE(struct pipes_struct *p,
+ 				      struct srvsvc_NETRPRNAMECANONICALIZE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetPRNameCompare(struct pipes_struct *p,
+ 				struct srvsvc_NetPRNameCompare *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetShareDelStart(struct pipes_struct *p,
+ 				struct srvsvc_NetShareDelStart *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetShareDelCommit(struct pipes_struct *p,
+ 				 struct srvsvc_NetShareDelCommit *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetServerTransportAddEx(struct pipes_struct *p,
+ 				       struct srvsvc_NetServerTransportAddEx *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NetServerSetServiceBitsEx(struct pipes_struct *p,
+ 					 struct srvsvc_NetServerSetServiceBitsEx *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSGETVERSION(struct pipes_struct *p,
+ 				 struct srvsvc_NETRDFSGETVERSION *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSCREATELOCALPARTITION(struct pipes_struct *p,
+ 					   struct srvsvc_NETRDFSCREATELOCALPARTITION *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSDELETELOCALPARTITION(struct pipes_struct *p,
+ 					   struct srvsvc_NETRDFSDELETELOCALPARTITION *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct pipes_struct *p,
+ 					  struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSSETSERVERINFO(struct pipes_struct *p,
+ 				    struct srvsvc_NETRDFSSETSERVERINFO *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSCREATEEXITPOINT(struct pipes_struct *p,
+ 				      struct srvsvc_NETRDFSCREATEEXITPOINT *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSDELETEEXITPOINT(struct pipes_struct *p,
+ 				      struct srvsvc_NETRDFSDELETEEXITPOINT *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSMODIFYPREFIX(struct pipes_struct *p,
+ 				   struct srvsvc_NETRDFSMODIFYPREFIX *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSFIXLOCALVOLUME(struct pipes_struct *p,
+ 				     struct srvsvc_NETRDFSFIXLOCALVOLUME *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct pipes_struct *p,
+ 					    struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _srvsvc_NETRSERVERTRANSPORTDELEX(struct pipes_struct *p,
+ 					struct srvsvc_NETRSERVERTRANSPORTDELEX *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/svcctl/srv_svcctl_nt.c
++++ b/source3/rpc_server/svcctl/srv_svcctl_nt.c
+@@ -1004,195 +1004,195 @@ WERROR _svcctl_SetServiceObjectSecurity(
+ WERROR _svcctl_DeleteService(struct pipes_struct *p,
+ 			     struct svcctl_DeleteService *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_SetServiceStatus(struct pipes_struct *p,
+ 				struct svcctl_SetServiceStatus *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_NotifyBootConfigStatus(struct pipes_struct *p,
+ 				      struct svcctl_NotifyBootConfigStatus *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_SCSetServiceBitsW(struct pipes_struct *p,
+ 				 struct svcctl_SCSetServiceBitsW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_ChangeServiceConfigW(struct pipes_struct *p,
+ 				    struct svcctl_ChangeServiceConfigW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_CreateServiceW(struct pipes_struct *p,
+ 			      struct svcctl_CreateServiceW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_QueryServiceLockStatusW(struct pipes_struct *p,
+ 				       struct svcctl_QueryServiceLockStatusW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_GetServiceKeyNameW(struct pipes_struct *p,
+ 				  struct svcctl_GetServiceKeyNameW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_SCSetServiceBitsA(struct pipes_struct *p,
+ 				 struct svcctl_SCSetServiceBitsA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_ChangeServiceConfigA(struct pipes_struct *p,
+ 				    struct svcctl_ChangeServiceConfigA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_CreateServiceA(struct pipes_struct *p,
+ 			      struct svcctl_CreateServiceA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_EnumDependentServicesA(struct pipes_struct *p,
+ 				      struct svcctl_EnumDependentServicesA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_EnumServicesStatusA(struct pipes_struct *p,
+ 				   struct svcctl_EnumServicesStatusA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_OpenSCManagerA(struct pipes_struct *p,
+ 			      struct svcctl_OpenSCManagerA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_OpenServiceA(struct pipes_struct *p,
+ 			    struct svcctl_OpenServiceA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_QueryServiceConfigA(struct pipes_struct *p,
+ 				   struct svcctl_QueryServiceConfigA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_QueryServiceLockStatusA(struct pipes_struct *p,
+ 				       struct svcctl_QueryServiceLockStatusA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_StartServiceA(struct pipes_struct *p,
+ 			     struct svcctl_StartServiceA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_GetServiceDisplayNameA(struct pipes_struct *p,
+ 				      struct svcctl_GetServiceDisplayNameA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_GetServiceKeyNameA(struct pipes_struct *p,
+ 				  struct svcctl_GetServiceKeyNameA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_GetCurrentGroupeStateW(struct pipes_struct *p,
+ 				      struct svcctl_GetCurrentGroupeStateW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_EnumServiceGroupW(struct pipes_struct *p,
+ 				 struct svcctl_EnumServiceGroupW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_ChangeServiceConfig2A(struct pipes_struct *p,
+ 				     struct svcctl_ChangeServiceConfig2A *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_ChangeServiceConfig2W(struct pipes_struct *p,
+ 				     struct svcctl_ChangeServiceConfig2W *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_QueryServiceConfig2A(struct pipes_struct *p,
+ 				    struct svcctl_QueryServiceConfig2A *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _EnumServicesStatusExA(struct pipes_struct *p,
+ 			      struct EnumServicesStatusExA *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _EnumServicesStatusExW(struct pipes_struct *p,
+ 			      struct EnumServicesStatusExW *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+ WERROR _svcctl_SCSendTSMessage(struct pipes_struct *p,
+ 			       struct svcctl_SCSendTSMessage *r)
+ {
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/winreg/srv_winreg_nt.c
++++ b/source3/rpc_server/winreg/srv_winreg_nt.c
+@@ -760,7 +760,7 @@ WERROR _winreg_SaveKeyEx(struct pipes_st
+ 	/* fill in your code here if you think this call should
+ 	   do anything */
+ 
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -948,7 +948,7 @@ WERROR _winreg_UnLoadKey(struct pipes_st
+ 	/* fill in your code here if you think this call should
+ 	   do anything */
+ 
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -962,7 +962,7 @@ WERROR _winreg_ReplaceKey(struct pipes_s
+ 	/* fill in your code here if you think this call should
+ 	   do anything */
+ 
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -976,7 +976,7 @@ WERROR _winreg_LoadKey(struct pipes_stru
+ 	/* fill in your code here if you think this call should
+ 	   do anything */
+ 
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -1139,6 +1139,6 @@ WERROR _winreg_DeleteKeyEx(struct pipes_
+ 	/* fill in your code here if you think this call should
+ 	   do anything */
+ 
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
++++ b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
+@@ -405,7 +405,7 @@ WERROR _wkssvc_NetWkstaSetInfo(struct pi
+ 			       struct wkssvc_NetWkstaSetInfo *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -608,7 +608,7 @@ WERROR _wkssvc_NetrWkstaUserGetInfo(stru
+ 				    struct wkssvc_NetrWkstaUserGetInfo *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -619,7 +619,7 @@ WERROR _wkssvc_NetrWkstaUserSetInfo(stru
+ 				    struct wkssvc_NetrWkstaUserSetInfo *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -630,7 +630,7 @@ WERROR _wkssvc_NetWkstaTransportEnum(str
+ 				     struct wkssvc_NetWkstaTransportEnum *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -641,7 +641,7 @@ WERROR _wkssvc_NetrWkstaTransportAdd(str
+ 				     struct wkssvc_NetrWkstaTransportAdd *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -652,7 +652,7 @@ WERROR _wkssvc_NetrWkstaTransportDel(str
+ 				     struct wkssvc_NetrWkstaTransportDel *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -663,7 +663,7 @@ WERROR _wkssvc_NetrUseAdd(struct pipes_s
+ 			  struct wkssvc_NetrUseAdd *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -674,7 +674,7 @@ WERROR _wkssvc_NetrUseGetInfo(struct pip
+ 			      struct wkssvc_NetrUseGetInfo *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -685,7 +685,7 @@ WERROR _wkssvc_NetrUseDel(struct pipes_s
+ 			  struct wkssvc_NetrUseDel *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -696,7 +696,7 @@ WERROR _wkssvc_NetrUseEnum(struct pipes_
+ 			   struct wkssvc_NetrUseEnum *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -707,7 +707,7 @@ WERROR _wkssvc_NetrMessageBufferSend(str
+ 				     struct wkssvc_NetrMessageBufferSend *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -718,7 +718,7 @@ WERROR _wkssvc_NetrWorkstationStatistics
+ 					    struct wkssvc_NetrWorkstationStatisticsGet *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -729,7 +729,7 @@ WERROR _wkssvc_NetrLogonDomainNameAdd(st
+ 				      struct wkssvc_NetrLogonDomainNameAdd *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -740,7 +740,7 @@ WERROR _wkssvc_NetrLogonDomainNameDel(st
+ 				      struct wkssvc_NetrLogonDomainNameDel *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -751,7 +751,7 @@ WERROR _wkssvc_NetrJoinDomain(struct pip
+ 			      struct wkssvc_NetrJoinDomain *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -762,7 +762,7 @@ WERROR _wkssvc_NetrUnjoinDomain(struct p
+ 				struct wkssvc_NetrUnjoinDomain *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -773,7 +773,7 @@ WERROR _wkssvc_NetrRenameMachineInDomain
+ 					 struct wkssvc_NetrRenameMachineInDomain *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -784,7 +784,7 @@ WERROR _wkssvc_NetrValidateName(struct p
+ 				struct wkssvc_NetrValidateName *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -795,7 +795,7 @@ WERROR _wkssvc_NetrGetJoinInformation(st
+ 				      struct wkssvc_NetrGetJoinInformation *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -806,7 +806,7 @@ WERROR _wkssvc_NetrGetJoinableOus(struct
+ 				  struct wkssvc_NetrGetJoinableOus *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -962,6 +962,7 @@ WERROR _wkssvc_NetrRenameMachineInDomain
+ 					  struct wkssvc_NetrRenameMachineInDomain2 *r)
+ {
+ 	/* for now just return not supported */
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -972,7 +973,7 @@ WERROR _wkssvc_NetrValidateName2(struct
+ 				 struct wkssvc_NetrValidateName2 *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -983,7 +984,7 @@ WERROR _wkssvc_NetrGetJoinableOus2(struc
+ 				   struct wkssvc_NetrGetJoinableOus2 *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -994,7 +995,7 @@ WERROR _wkssvc_NetrAddAlternateComputerN
+ 					    struct wkssvc_NetrAddAlternateComputerName *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -1005,7 +1006,7 @@ WERROR _wkssvc_NetrRemoveAlternateComput
+ 					       struct wkssvc_NetrRemoveAlternateComputerName *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -1016,7 +1017,7 @@ WERROR _wkssvc_NetrSetPrimaryComputernam
+ 					  struct wkssvc_NetrSetPrimaryComputername *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+ 
+@@ -1027,6 +1028,6 @@ WERROR _wkssvc_NetrEnumerateComputerName
+ 					  struct wkssvc_NetrEnumerateComputerNames *r)
+ {
+ 	/* FIXME: Add implementation code here */
+-	p->rng_fault_state = True;
++	p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ 	return WERR_NOT_SUPPORTED;
+ }
+--- a/libcli/auth/smbencrypt.c
++++ b/libcli/auth/smbencrypt.c
+@@ -355,11 +355,18 @@ DATA_BLOB NTLMv2_generate_names_blob(TAL
+ 	DATA_BLOB names_blob = data_blob_talloc(mem_ctx, NULL, 0);
+ 
+ 	/* Deliberately ignore return here.. */
+-	(void)msrpc_gen(mem_ctx, &names_blob,
+-		  "aaa",
+-		  MsvAvNbDomainName, domain,
+-		  MsvAvNbComputerName, hostname,
+-		  MsvAvEOL, "");
++	if (hostname != NULL) {
++		(void)msrpc_gen(mem_ctx, &names_blob,
++			  "aaa",
++			  MsvAvNbDomainName, domain,
++			  MsvAvNbComputerName, hostname,
++			  MsvAvEOL, "");
++	} else {
++		(void)msrpc_gen(mem_ctx, &names_blob,
++			  "aa",
++			  MsvAvNbDomainName, domain,
++			  MsvAvEOL, "");
++	}
+ 	return names_blob;
+ }
+ 
diff --git a/package/network/services/samba36/patches/021-CVE-preparation-v3-6-addition.patch b/package/network/services/samba36/patches/021-CVE-preparation-v3-6-addition.patch
new file mode 100644
index 0000000000..dedd453be2
--- /dev/null
+++ b/package/network/services/samba36/patches/021-CVE-preparation-v3-6-addition.patch
@@ -0,0 +1,9515 @@
+--- a/source3/librpc/gen_ndr/srv_atsvc.c
++++ b/source3/librpc/gen_ndr/srv_atsvc.c
+@@ -51,7 +51,7 @@ static bool api_atsvc_JobAdd(struct pipe
+ 
+ 	r->out.result = _atsvc_JobAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -124,7 +124,7 @@ static bool api_atsvc_JobDel(struct pipe
+ 
+ 	r->out.result = _atsvc_JobDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -206,7 +206,7 @@ static bool api_atsvc_JobEnum(struct pip
+ 
+ 	r->out.result = _atsvc_JobEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -286,7 +286,7 @@ static bool api_atsvc_JobGetInfo(struct
+ 
+ 	r->out.result = _atsvc_JobGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_audiosrv.c
++++ b/source3/librpc/gen_ndr/srv_audiosrv.c
+@@ -44,7 +44,7 @@ static bool api_audiosrv_CreatezoneFacto
+ 
+ 	_audiosrv_CreatezoneFactoriesList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_audiosrv_CreateGfxFactor
+ 
+ 	_audiosrv_CreateGfxFactoriesList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_audiosrv_CreateGfxList(s
+ 
+ 	_audiosrv_CreateGfxList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_audiosrv_RemoveGfx(struc
+ 
+ 	_audiosrv_RemoveGfx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_audiosrv_AddGfx(struct p
+ 
+ 	_audiosrv_AddGfx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -409,7 +409,7 @@ static bool api_audiosrv_ModifyGfx(struc
+ 
+ 	_audiosrv_ModifyGfx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -482,7 +482,7 @@ static bool api_audiosrv_OpenGfx(struct
+ 
+ 	_audiosrv_OpenGfx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -555,7 +555,7 @@ static bool api_audiosrv_Logon(struct pi
+ 
+ 	_audiosrv_Logon(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -628,7 +628,7 @@ static bool api_audiosrv_Logoff(struct p
+ 
+ 	_audiosrv_Logoff(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -701,7 +701,7 @@ static bool api_audiosrv_RegisterSession
+ 
+ 	_audiosrv_RegisterSessionNotificationEvent(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -774,7 +774,7 @@ static bool api_audiosrv_UnregisterSessi
+ 
+ 	_audiosrv_UnregisterSessionNotificationEvent(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -847,7 +847,7 @@ static bool api_audiosrv_SessionConnectS
+ 
+ 	_audiosrv_SessionConnectState(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -920,7 +920,7 @@ static bool api_audiosrv_DriverOpenDrvRe
+ 
+ 	_audiosrv_DriverOpenDrvRegKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -993,7 +993,7 @@ static bool api_audiosrv_AdvisePreferred
+ 
+ 	_audiosrv_AdvisePreferredDeviceChange(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1066,7 +1066,7 @@ static bool api_audiosrv_GetPnpInfo(stru
+ 
+ 	_audiosrv_GetPnpInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_backupkey.c
++++ b/source3/librpc/gen_ndr/srv_backupkey.c
+@@ -57,7 +57,7 @@ static bool api_bkrp_BackupKey(struct pi
+ 
+ 	r->out.result = _bkrp_BackupKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_browser.c
++++ b/source3/librpc/gen_ndr/srv_browser.c
+@@ -44,7 +44,7 @@ static bool api_BrowserrServerEnum(struc
+ 
+ 	_BrowserrServerEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_BrowserrDebugCall(struct
+ 
+ 	_BrowserrDebugCall(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -198,7 +198,7 @@ static bool api_BrowserrQueryOtherDomain
+ 
+ 	r->out.result = _BrowserrQueryOtherDomains(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -271,7 +271,7 @@ static bool api_BrowserrResetNetlogonSta
+ 
+ 	_BrowserrResetNetlogonState(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -344,7 +344,7 @@ static bool api_BrowserrDebugTrace(struc
+ 
+ 	_BrowserrDebugTrace(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -417,7 +417,7 @@ static bool api_BrowserrQueryStatistics(
+ 
+ 	_BrowserrQueryStatistics(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -490,7 +490,7 @@ static bool api_BrowserResetStatistics(s
+ 
+ 	_BrowserResetStatistics(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -563,7 +563,7 @@ static bool api_NetrBrowserStatisticsCle
+ 
+ 	_NetrBrowserStatisticsClear(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -636,7 +636,7 @@ static bool api_NetrBrowserStatisticsGet
+ 
+ 	_NetrBrowserStatisticsGet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -709,7 +709,7 @@ static bool api_BrowserrSetNetlogonState
+ 
+ 	_BrowserrSetNetlogonState(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -782,7 +782,7 @@ static bool api_BrowserrQueryEmulatedDom
+ 
+ 	_BrowserrQueryEmulatedDomains(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -855,7 +855,7 @@ static bool api_BrowserrServerEnumEx(str
+ 
+ 	_BrowserrServerEnumEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dbgidl.c
++++ b/source3/librpc/gen_ndr/srv_dbgidl.c
+@@ -44,7 +44,7 @@ static bool api_dummy_dbgidl(struct pipe
+ 
+ 	_dummy_dbgidl(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dcom.c
++++ b/source3/librpc/gen_ndr/srv_dcom.c
+@@ -44,7 +44,7 @@ static bool api_UseProtSeq(struct pipes_
+ 
+ 	_UseProtSeq(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_GetCustomProtseqInfo(str
+ 
+ 	_GetCustomProtseqInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_UpdateResolverBindings(s
+ 
+ 	_UpdateResolverBindings(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -300,7 +300,7 @@ static bool api_QueryInterface(struct pi
+ 
+ 	r->out.result = _QueryInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -380,7 +380,7 @@ static bool api_AddRef(struct pipes_stru
+ 
+ 	r->out.result = _AddRef(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -460,7 +460,7 @@ static bool api_Release(struct pipes_str
+ 
+ 	r->out.result = _Release(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -570,7 +570,7 @@ static bool api_CreateInstance(struct pi
+ 
+ 	r->out.result = _CreateInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -650,7 +650,7 @@ static bool api_RemoteCreateInstance(str
+ 
+ 	r->out.result = _RemoteCreateInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -730,7 +730,7 @@ static bool api_LockServer(struct pipes_
+ 
+ 	r->out.result = _LockServer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -810,7 +810,7 @@ static bool api_RemoteLockServer(struct
+ 
+ 	r->out.result = _RemoteLockServer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -921,7 +921,7 @@ static bool api_RemQueryInterface(struct
+ 
+ 	r->out.result = _RemQueryInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1007,7 +1007,7 @@ static bool api_RemAddRef(struct pipes_s
+ 
+ 	r->out.result = _RemAddRef(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1087,7 +1087,7 @@ static bool api_RemRelease(struct pipes_
+ 
+ 	r->out.result = _RemRelease(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1197,7 +1197,7 @@ static bool api_GetClassObject(struct pi
+ 
+ 	_GetClassObject(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1299,7 +1299,7 @@ static bool api_ISCMLocalActivator_Creat
+ 
+ 	r->out.result = _ISCMLocalActivator_CreateInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1394,7 +1394,7 @@ static bool api_IMachineLocalActivator_f
+ 
+ 	r->out.result = _IMachineLocalActivator_foo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1489,7 +1489,7 @@ static bool api_ILocalObjectExporter_Foo
+ 
+ 	r->out.result = _ILocalObjectExporter_Foo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1603,7 +1603,7 @@ static bool api_ISystemActivatorRemoteCr
+ 
+ 	r->out.result = _ISystemActivatorRemoteCreateInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1717,7 +1717,7 @@ static bool api_RemQueryInterface2(struc
+ 
+ 	r->out.result = _RemQueryInterface2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1825,7 +1825,7 @@ static bool api_GetTypeInfoCount(struct
+ 
+ 	r->out.result = _GetTypeInfoCount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1911,7 +1911,7 @@ static bool api_GetTypeInfo(struct pipes
+ 
+ 	r->out.result = _GetTypeInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1997,7 +1997,7 @@ static bool api_GetIDsOfNames(struct pip
+ 
+ 	r->out.result = _GetIDsOfNames(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2096,7 +2096,7 @@ static bool api_Invoke(struct pipes_stru
+ 
+ 	r->out.result = _Invoke(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2201,7 +2201,7 @@ static bool api_MarshalInterface(struct
+ 
+ 	r->out.result = _MarshalInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2281,7 +2281,7 @@ static bool api_UnMarshalInterface(struc
+ 
+ 	r->out.result = _UnMarshalInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2384,7 +2384,7 @@ static bool api_MakeCoffee(struct pipes_
+ 
+ 	r->out.result = _MakeCoffee(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2498,7 +2498,7 @@ static bool api_Read(struct pipes_struct
+ 
+ 	r->out.result = _Read(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2584,7 +2584,7 @@ static bool api_Write(struct pipes_struc
+ 
+ 	r->out.result = _Write(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dfsblobs.c
++++ b/source3/librpc/gen_ndr/srv_dfsblobs.c
+@@ -51,7 +51,7 @@ static bool api_dfs_GetDFSReferral(struc
+ 
+ 	_dfs_GetDFSReferral(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dfs.c
++++ b/source3/librpc/gen_ndr/srv_dfs.c
+@@ -51,7 +51,7 @@ static bool api_dfs_GetManagerVersion(st
+ 
+ 	_dfs_GetManagerVersion(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -124,7 +124,7 @@ static bool api_dfs_Add(struct pipes_str
+ 
+ 	r->out.result = _dfs_Add(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -197,7 +197,7 @@ static bool api_dfs_Remove(struct pipes_
+ 
+ 	r->out.result = _dfs_Remove(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -270,7 +270,7 @@ static bool api_dfs_SetInfo(struct pipes
+ 
+ 	r->out.result = _dfs_SetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -350,7 +350,7 @@ static bool api_dfs_GetInfo(struct pipes
+ 
+ 	r->out.result = _dfs_GetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -426,7 +426,7 @@ static bool api_dfs_Enum(struct pipes_st
+ 	r->out.total = r->in.total;
+ 	r->out.result = _dfs_Enum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -499,7 +499,7 @@ static bool api_dfs_Rename(struct pipes_
+ 
+ 	r->out.result = _dfs_Rename(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -572,7 +572,7 @@ static bool api_dfs_Move(struct pipes_st
+ 
+ 	r->out.result = _dfs_Move(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -645,7 +645,7 @@ static bool api_dfs_ManagerGetConfigInfo
+ 
+ 	r->out.result = _dfs_ManagerGetConfigInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -718,7 +718,7 @@ static bool api_dfs_ManagerSendSiteInfo(
+ 
+ 	r->out.result = _dfs_ManagerSendSiteInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -793,7 +793,7 @@ static bool api_dfs_AddFtRoot(struct pip
+ 	r->out.unknown2 = r->in.unknown2;
+ 	r->out.result = _dfs_AddFtRoot(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -868,7 +868,7 @@ static bool api_dfs_RemoveFtRoot(struct
+ 	r->out.unknown = r->in.unknown;
+ 	r->out.result = _dfs_RemoveFtRoot(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -941,7 +941,7 @@ static bool api_dfs_AddStdRoot(struct pi
+ 
+ 	r->out.result = _dfs_AddStdRoot(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1014,7 +1014,7 @@ static bool api_dfs_RemoveStdRoot(struct
+ 
+ 	r->out.result = _dfs_RemoveStdRoot(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1087,7 +1087,7 @@ static bool api_dfs_ManagerInitialize(st
+ 
+ 	r->out.result = _dfs_ManagerInitialize(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1160,7 +1160,7 @@ static bool api_dfs_AddStdRootForced(str
+ 
+ 	r->out.result = _dfs_AddStdRootForced(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1237,7 +1237,7 @@ static bool api_dfs_GetDcAddress(struct
+ 	r->out.ttl = r->in.ttl;
+ 	r->out.result = _dfs_GetDcAddress(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1310,7 +1310,7 @@ static bool api_dfs_SetDcAddress(struct
+ 
+ 	r->out.result = _dfs_SetDcAddress(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1383,7 +1383,7 @@ static bool api_dfs_FlushFtTable(struct
+ 
+ 	r->out.result = _dfs_FlushFtTable(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1456,7 +1456,7 @@ static bool api_dfs_Add2(struct pipes_st
+ 
+ 	r->out.result = _dfs_Add2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1529,7 +1529,7 @@ static bool api_dfs_Remove2(struct pipes
+ 
+ 	r->out.result = _dfs_Remove2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1605,7 +1605,7 @@ static bool api_dfs_EnumEx(struct pipes_
+ 	r->out.total = r->in.total;
+ 	r->out.result = _dfs_EnumEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1678,7 +1678,7 @@ static bool api_dfs_SetInfo2(struct pipe
+ 
+ 	r->out.result = _dfs_SetInfo2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dns.c
++++ b/source3/librpc/gen_ndr/srv_dns.c
+@@ -44,7 +44,7 @@ static bool api_decode_dns_name_packet(s
+ 
+ 	_decode_dns_name_packet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dnsp.c
++++ b/source3/librpc/gen_ndr/srv_dnsp.c
+@@ -44,7 +44,7 @@ static bool api_decode_DnssrvRpcRecord(s
+ 
+ 	_decode_DnssrvRpcRecord(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dnsserver.c
++++ b/source3/librpc/gen_ndr/srv_dnsserver.c
+@@ -44,7 +44,7 @@ static bool api_dnsserver_foo(struct pip
+ 
+ 	_dnsserver_foo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_drsblobs.c
++++ b/source3/librpc/gen_ndr/srv_drsblobs.c
+@@ -44,7 +44,7 @@ static bool api_decode_replPropertyMetaD
+ 
+ 	_decode_replPropertyMetaData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_decode_replUpToDateVecto
+ 
+ 	_decode_replUpToDateVector(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_decode_repsFromTo(struct
+ 
+ 	_decode_repsFromTo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_decode_partialAttributeS
+ 
+ 	_decode_partialAttributeSet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_decode_prefixMap(struct
+ 
+ 	_decode_prefixMap(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -409,7 +409,7 @@ static bool api_decode_ldapControlDirSyn
+ 
+ 	_decode_ldapControlDirSync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -482,7 +482,7 @@ static bool api_decode_supplementalCrede
+ 
+ 	_decode_supplementalCredentials(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -555,7 +555,7 @@ static bool api_decode_Packages(struct p
+ 
+ 	_decode_Packages(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -628,7 +628,7 @@ static bool api_decode_PrimaryKerberos(s
+ 
+ 	_decode_PrimaryKerberos(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -701,7 +701,7 @@ static bool api_decode_PrimaryCLEARTEXT(
+ 
+ 	_decode_PrimaryCLEARTEXT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -774,7 +774,7 @@ static bool api_decode_PrimaryWDigest(st
+ 
+ 	_decode_PrimaryWDigest(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -847,7 +847,7 @@ static bool api_decode_trustAuthInOut(st
+ 
+ 	_decode_trustAuthInOut(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -920,7 +920,7 @@ static bool api_decode_trustDomainPasswo
+ 
+ 	_decode_trustDomainPasswords(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -993,7 +993,7 @@ static bool api_decode_ExtendedErrorInfo
+ 
+ 	_decode_ExtendedErrorInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1066,7 +1066,7 @@ static bool api_decode_ForestTrustInfo(s
+ 
+ 	_decode_ForestTrustInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_drsuapi.c
++++ b/source3/librpc/gen_ndr/srv_drsuapi.c
+@@ -52,7 +52,7 @@ static bool api_drsuapi_DsBind(struct pi
+ 
+ 	r->out.result = _drsuapi_DsBind(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -127,7 +127,7 @@ static bool api_drsuapi_DsUnbind(struct
+ 	r->out.bind_handle = r->in.bind_handle;
+ 	r->out.result = _drsuapi_DsUnbind(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -200,7 +200,7 @@ static bool api_drsuapi_DsReplicaSync(st
+ 
+ 	r->out.result = _drsuapi_DsReplicaSync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -286,7 +286,7 @@ static bool api_drsuapi_DsGetNCChanges(s
+ 
+ 	r->out.result = _drsuapi_DsGetNCChanges(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -359,7 +359,7 @@ static bool api_drsuapi_DsReplicaUpdateR
+ 
+ 	r->out.result = _drsuapi_DsReplicaUpdateRefs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -432,7 +432,7 @@ static bool api_drsuapi_DsReplicaAdd(str
+ 
+ 	r->out.result = _drsuapi_DsReplicaAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -505,7 +505,7 @@ static bool api_drsuapi_DsReplicaDel(str
+ 
+ 	r->out.result = _drsuapi_DsReplicaDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -578,7 +578,7 @@ static bool api_drsuapi_DsReplicaMod(str
+ 
+ 	r->out.result = _drsuapi_DsReplicaMod(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -651,7 +651,7 @@ static bool api_DRSUAPI_VERIFY_NAMES(str
+ 
+ 	r->out.result = _DRSUAPI_VERIFY_NAMES(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -737,7 +737,7 @@ static bool api_drsuapi_DsGetMemberships
+ 
+ 	r->out.result = _drsuapi_DsGetMemberships(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -810,7 +810,7 @@ static bool api_DRSUAPI_INTER_DOMAIN_MOV
+ 
+ 	r->out.result = _DRSUAPI_INTER_DOMAIN_MOVE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -896,7 +896,7 @@ static bool api_drsuapi_DsGetNT4ChangeLo
+ 
+ 	r->out.result = _drsuapi_DsGetNT4ChangeLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -982,7 +982,7 @@ static bool api_drsuapi_DsCrackNames(str
+ 
+ 	r->out.result = _drsuapi_DsCrackNames(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1068,7 +1068,7 @@ static bool api_drsuapi_DsWriteAccountSp
+ 
+ 	r->out.result = _drsuapi_DsWriteAccountSpn(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1154,7 +1154,7 @@ static bool api_drsuapi_DsRemoveDSServer
+ 
+ 	r->out.result = _drsuapi_DsRemoveDSServer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1227,7 +1227,7 @@ static bool api_DRSUAPI_REMOVE_DS_DOMAIN
+ 
+ 	r->out.result = _DRSUAPI_REMOVE_DS_DOMAIN(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1313,7 +1313,7 @@ static bool api_drsuapi_DsGetDomainContr
+ 
+ 	r->out.result = _drsuapi_DsGetDomainControllerInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1399,7 +1399,7 @@ static bool api_drsuapi_DsAddEntry(struc
+ 
+ 	r->out.result = _drsuapi_DsAddEntry(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1472,7 +1472,7 @@ static bool api_drsuapi_DsExecuteKCC(str
+ 
+ 	r->out.result = _drsuapi_DsExecuteKCC(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1558,7 +1558,7 @@ static bool api_drsuapi_DsReplicaGetInfo
+ 
+ 	r->out.result = _drsuapi_DsReplicaGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1631,7 +1631,7 @@ static bool api_DRSUAPI_ADD_SID_HISTORY(
+ 
+ 	r->out.result = _DRSUAPI_ADD_SID_HISTORY(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1717,7 +1717,7 @@ static bool api_drsuapi_DsGetMemberships
+ 
+ 	r->out.result = _drsuapi_DsGetMemberships2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1790,7 +1790,7 @@ static bool api_DRSUAPI_REPLICA_VERIFY_O
+ 
+ 	r->out.result = _DRSUAPI_REPLICA_VERIFY_OBJECTS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1863,7 +1863,7 @@ static bool api_DRSUAPI_GET_OBJECT_EXIST
+ 
+ 	r->out.result = _DRSUAPI_GET_OBJECT_EXISTENCE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1949,7 +1949,7 @@ static bool api_drsuapi_QuerySitesByCost
+ 
+ 	r->out.result = _drsuapi_QuerySitesByCost(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dsbackup.c
++++ b/source3/librpc/gen_ndr/srv_dsbackup.c
+@@ -44,7 +44,7 @@ static bool api_HrRBackupPrepare(struct
+ 
+ 	_HrRBackupPrepare(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_HrRBackupEnd(struct pipe
+ 
+ 	_HrRBackupEnd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_HrRBackupGetAttachmentIn
+ 
+ 	_HrRBackupGetAttachmentInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_HrRBackupOpenFile(struct
+ 
+ 	_HrRBackupOpenFile(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_HrRBackupRead(struct pip
+ 
+ 	_HrRBackupRead(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -409,7 +409,7 @@ static bool api_HrRBackupClose(struct pi
+ 
+ 	_HrRBackupClose(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -482,7 +482,7 @@ static bool api_HrRBackupGetBackupLogs(s
+ 
+ 	_HrRBackupGetBackupLogs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -555,7 +555,7 @@ static bool api_HrRBackupTruncateLogs(st
+ 
+ 	_HrRBackupTruncateLogs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -628,7 +628,7 @@ static bool api_HrRBackupPing(struct pip
+ 
+ 	_HrRBackupPing(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -731,7 +731,7 @@ static bool api_HrRIsNTDSOnline(struct p
+ 
+ 	_HrRIsNTDSOnline(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -804,7 +804,7 @@ static bool api_HrRRestorePrepare(struct
+ 
+ 	_HrRRestorePrepare(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -877,7 +877,7 @@ static bool api_HrRRestoreRegister(struc
+ 
+ 	_HrRRestoreRegister(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -950,7 +950,7 @@ static bool api_HrRRestoreRegisterComple
+ 
+ 	_HrRRestoreRegisterComplete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1023,7 +1023,7 @@ static bool api_HrRRestoreGetDatabaseLoc
+ 
+ 	_HrRRestoreGetDatabaseLocations(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1096,7 +1096,7 @@ static bool api_HrRRestoreEnd(struct pip
+ 
+ 	_HrRRestoreEnd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1169,7 +1169,7 @@ static bool api_HrRRestoreSetCurrentLogN
+ 
+ 	_HrRRestoreSetCurrentLogNumber(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1242,7 +1242,7 @@ static bool api_HrRRestoreCheckLogsForBa
+ 
+ 	_HrRRestoreCheckLogsForBackup(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_dssetup.c
++++ b/source3/librpc/gen_ndr/srv_dssetup.c
+@@ -51,7 +51,7 @@ static bool api_dssetup_DsRoleGetPrimary
+ 
+ 	r->out.result = _dssetup_DsRoleGetPrimaryDomainInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -124,7 +124,7 @@ static bool api_dssetup_DsRoleDnsNameToF
+ 
+ 	r->out.result = _dssetup_DsRoleDnsNameToFlatName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -197,7 +197,7 @@ static bool api_dssetup_DsRoleDcAsDc(str
+ 
+ 	r->out.result = _dssetup_DsRoleDcAsDc(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -270,7 +270,7 @@ static bool api_dssetup_DsRoleDcAsReplic
+ 
+ 	r->out.result = _dssetup_DsRoleDcAsReplica(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -343,7 +343,7 @@ static bool api_dssetup_DsRoleDemoteDc(s
+ 
+ 	r->out.result = _dssetup_DsRoleDemoteDc(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -416,7 +416,7 @@ static bool api_dssetup_DsRoleGetDcOpera
+ 
+ 	r->out.result = _dssetup_DsRoleGetDcOperationProgress(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -489,7 +489,7 @@ static bool api_dssetup_DsRoleGetDcOpera
+ 
+ 	r->out.result = _dssetup_DsRoleGetDcOperationResults(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -562,7 +562,7 @@ static bool api_dssetup_DsRoleCancel(str
+ 
+ 	r->out.result = _dssetup_DsRoleCancel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -635,7 +635,7 @@ static bool api_dssetup_DsRoleServerSave
+ 
+ 	r->out.result = _dssetup_DsRoleServerSaveStateForUpgrade(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -708,7 +708,7 @@ static bool api_dssetup_DsRoleUpgradeDow
+ 
+ 	r->out.result = _dssetup_DsRoleUpgradeDownlevelServer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -781,7 +781,7 @@ static bool api_dssetup_DsRoleAbortDownl
+ 
+ 	r->out.result = _dssetup_DsRoleAbortDownlevelServerUpgrade(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_echo.c
++++ b/source3/librpc/gen_ndr/srv_echo.c
+@@ -51,7 +51,7 @@ static bool api_echo_AddOne(struct pipes
+ 
+ 	_echo_AddOne(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -131,7 +131,7 @@ static bool api_echo_EchoData(struct pip
+ 
+ 	_echo_EchoData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -204,7 +204,7 @@ static bool api_echo_SinkData(struct pip
+ 
+ 	_echo_SinkData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -284,7 +284,7 @@ static bool api_echo_SourceData(struct p
+ 
+ 	_echo_SourceData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -364,7 +364,7 @@ static bool api_echo_TestCall(struct pip
+ 
+ 	_echo_TestCall(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -444,7 +444,7 @@ static bool api_echo_TestCall2(struct pi
+ 
+ 	r->out.result = _echo_TestCall2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -517,7 +517,7 @@ static bool api_echo_TestSleep(struct pi
+ 
+ 	r->out.result = _echo_TestSleep(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -594,7 +594,7 @@ static bool api_echo_TestEnum(struct pip
+ 	r->out.foo3 = r->in.foo3;
+ 	_echo_TestEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -669,7 +669,7 @@ static bool api_echo_TestSurrounding(str
+ 	r->out.data = r->in.data;
+ 	_echo_TestSurrounding(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -742,7 +742,7 @@ static bool api_echo_TestDoublePointer(s
+ 
+ 	r->out.result = _echo_TestDoublePointer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_efs.c
++++ b/source3/librpc/gen_ndr/srv_efs.c
+@@ -51,7 +51,7 @@ static bool api_EfsRpcOpenFileRaw(struct
+ 
+ 	r->out.result = _EfsRpcOpenFileRaw(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -124,7 +124,7 @@ static bool api_EfsRpcReadFileRaw(struct
+ 
+ 	r->out.result = _EfsRpcReadFileRaw(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -197,7 +197,7 @@ static bool api_EfsRpcWriteFileRaw(struc
+ 
+ 	r->out.result = _EfsRpcWriteFileRaw(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -272,7 +272,7 @@ static bool api_EfsRpcCloseRaw(struct pi
+ 	r->out.pvContext = r->in.pvContext;
+ 	_EfsRpcCloseRaw(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -345,7 +345,7 @@ static bool api_EfsRpcEncryptFileSrv(str
+ 
+ 	r->out.result = _EfsRpcEncryptFileSrv(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -418,7 +418,7 @@ static bool api_EfsRpcDecryptFileSrv(str
+ 
+ 	r->out.result = _EfsRpcDecryptFileSrv(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -498,7 +498,7 @@ static bool api_EfsRpcQueryUsersOnFile(s
+ 
+ 	r->out.result = _EfsRpcQueryUsersOnFile(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -578,7 +578,7 @@ static bool api_EfsRpcQueryRecoveryAgent
+ 
+ 	r->out.result = _EfsRpcQueryRecoveryAgents(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -651,7 +651,7 @@ static bool api_EfsRpcRemoveUsersFromFil
+ 
+ 	r->out.result = _EfsRpcRemoveUsersFromFile(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -724,7 +724,7 @@ static bool api_EfsRpcAddUsersToFile(str
+ 
+ 	r->out.result = _EfsRpcAddUsersToFile(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -797,7 +797,7 @@ static bool api_EfsRpcSetFileEncryptionK
+ 
+ 	r->out.result = _EfsRpcSetFileEncryptionKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -870,7 +870,7 @@ static bool api_EfsRpcNotSupported(struc
+ 
+ 	r->out.result = _EfsRpcNotSupported(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -943,7 +943,7 @@ static bool api_EfsRpcFileKeyInfo(struct
+ 
+ 	r->out.result = _EfsRpcFileKeyInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1016,7 +1016,7 @@ static bool api_EfsRpcDuplicateEncryptio
+ 
+ 	r->out.result = _EfsRpcDuplicateEncryptionInfoFile(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_epmapper.c
++++ b/source3/librpc/gen_ndr/srv_epmapper.c
+@@ -44,7 +44,7 @@ static bool api_epm_Insert(struct pipes_
+ 
+ 	r->out.result = _epm_Insert(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_epm_Delete(struct pipes_
+ 
+ 	r->out.result = _epm_Delete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -204,7 +204,7 @@ static bool api_epm_Lookup(struct pipes_
+ 
+ 	r->out.result = _epm_Lookup(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -291,7 +291,7 @@ static bool api_epm_Map(struct pipes_str
+ 
+ 	r->out.result = _epm_Map(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -366,7 +366,7 @@ static bool api_epm_LookupHandleFree(str
+ 	r->out.entry_handle = r->in.entry_handle;
+ 	r->out.result = _epm_LookupHandleFree(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -439,7 +439,7 @@ static bool api_epm_InqObject(struct pip
+ 
+ 	r->out.result = _epm_InqObject(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -512,7 +512,7 @@ static bool api_epm_MgmtDelete(struct pi
+ 
+ 	r->out.result = _epm_MgmtDelete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -585,7 +585,7 @@ static bool api_epm_MapAuth(struct pipes
+ 
+ 	r->out.result = _epm_MapAuth(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_eventlog6.c
++++ b/source3/librpc/gen_ndr/srv_eventlog6.c
+@@ -75,7 +75,7 @@ static bool api_eventlog6_EvtRpcRegister
+ 
+ 	r->out.result = _eventlog6_EvtRpcRegisterRemoteSubscription(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -179,7 +179,7 @@ static bool api_eventlog6_EvtRpcRemoteSu
+ 
+ 	r->out.result = _eventlog6_EvtRpcRemoteSubscriptionNextAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -283,7 +283,7 @@ static bool api_eventlog6_EvtRpcRemoteSu
+ 
+ 	r->out.result = _eventlog6_EvtRpcRemoteSubscriptionNext(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -356,7 +356,7 @@ static bool api_eventlog6_EvtRpcRemoteSu
+ 
+ 	r->out.result = _eventlog6_EvtRpcRemoteSubscriptionWaitAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -436,7 +436,7 @@ static bool api_eventlog6_EvtRpcRegister
+ 
+ 	r->out.result = _eventlog6_EvtRpcRegisterControllableOperation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -540,7 +540,7 @@ static bool api_eventlog6_EvtRpcRegister
+ 
+ 	r->out.result = _eventlog6_EvtRpcRegisterLogQuery(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -620,7 +620,7 @@ static bool api_eventlog6_EvtRpcClearLog
+ 
+ 	r->out.result = _eventlog6_EvtRpcClearLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -700,7 +700,7 @@ static bool api_eventlog6_EvtRpcExportLo
+ 
+ 	r->out.result = _eventlog6_EvtRpcExportLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -780,7 +780,7 @@ static bool api_eventlog6_EvtRpcLocalize
+ 
+ 	r->out.result = _eventlog6_EvtRpcLocalizeExportLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -878,7 +878,7 @@ static bool api_eventlog6_EvtRpcMessageR
+ 
+ 	r->out.result = _eventlog6_EvtRpcMessageRender(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -976,7 +976,7 @@ static bool api_eventlog6_EvtRpcMessageR
+ 
+ 	r->out.result = _eventlog6_EvtRpcMessageRenderDefault(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1080,7 +1080,7 @@ static bool api_eventlog6_EvtRpcQueryNex
+ 
+ 	r->out.result = _eventlog6_EvtRpcQueryNext(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1160,7 +1160,7 @@ static bool api_eventlog6_EvtRpcQuerySee
+ 
+ 	r->out.result = _eventlog6_EvtRpcQuerySeek(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1235,7 +1235,7 @@ static bool api_eventlog6_EvtRpcClose(st
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _eventlog6_EvtRpcClose(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1308,7 +1308,7 @@ static bool api_eventlog6_EvtRpcCancel(s
+ 
+ 	r->out.result = _eventlog6_EvtRpcCancel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1381,7 +1381,7 @@ static bool api_eventlog6_EvtRpcAssertCo
+ 
+ 	r->out.result = _eventlog6_EvtRpcAssertConfig(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1454,7 +1454,7 @@ static bool api_eventlog6_EvtRpcRetractC
+ 
+ 	r->out.result = _eventlog6_EvtRpcRetractConfig(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1540,7 +1540,7 @@ static bool api_eventlog6_EvtRpcOpenLogH
+ 
+ 	r->out.result = _eventlog6_EvtRpcOpenLogHandle(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1626,7 +1626,7 @@ static bool api_eventlog6_EvtRpcGetLogFi
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetLogFileInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1712,7 +1712,7 @@ static bool api_eventlog6_EvtRpcGetChann
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetChannelList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1792,7 +1792,7 @@ static bool api_eventlog6_EvtRpcGetChann
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetChannelConfig(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1872,7 +1872,7 @@ static bool api_eventlog6_EvtRpcPutChann
+ 
+ 	r->out.result = _eventlog6_EvtRpcPutChannelConfig(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1958,7 +1958,7 @@ static bool api_eventlog6_EvtRpcGetPubli
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetPublisherList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2044,7 +2044,7 @@ static bool api_eventlog6_EvtRpcGetPubli
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetPublisherListForChannel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2130,7 +2130,7 @@ static bool api_eventlog6_EvtRpcGetPubli
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetPublisherMetadata(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2210,7 +2210,7 @@ static bool api_eventlog6_EvtRpcGetPubli
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetPublisherResourceMetadata(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2290,7 +2290,7 @@ static bool api_eventlog6_EvtRpcGetEvent
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetEventMetadataEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2376,7 +2376,7 @@ static bool api_eventlog6_EvtRpcGetNextE
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetNextEventMetadata(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2456,7 +2456,7 @@ static bool api_eventlog6_EvtRpcGetClass
+ 
+ 	r->out.result = _eventlog6_EvtRpcGetClassicLogDisplayName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_eventlog.c
++++ b/source3/librpc/gen_ndr/srv_eventlog.c
+@@ -44,7 +44,7 @@ static bool api_eventlog_ClearEventLogW(
+ 
+ 	r->out.result = _eventlog_ClearEventLogW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_eventlog_BackupEventLogW
+ 
+ 	r->out.result = _eventlog_BackupEventLogW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -192,7 +192,7 @@ static bool api_eventlog_CloseEventLog(s
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _eventlog_CloseEventLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -267,7 +267,7 @@ static bool api_eventlog_DeregisterEvent
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _eventlog_DeregisterEventSource(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -347,7 +347,7 @@ static bool api_eventlog_GetNumRecords(s
+ 
+ 	r->out.result = _eventlog_GetNumRecords(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -427,7 +427,7 @@ static bool api_eventlog_GetOldestRecord
+ 
+ 	r->out.result = _eventlog_GetOldestRecord(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -500,7 +500,7 @@ static bool api_eventlog_ChangeNotify(st
+ 
+ 	r->out.result = _eventlog_ChangeNotify(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -580,7 +580,7 @@ static bool api_eventlog_OpenEventLogW(s
+ 
+ 	r->out.result = _eventlog_OpenEventLogW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -660,7 +660,7 @@ static bool api_eventlog_RegisterEventSo
+ 
+ 	r->out.result = _eventlog_RegisterEventSourceW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -740,7 +740,7 @@ static bool api_eventlog_OpenBackupEvent
+ 
+ 	r->out.result = _eventlog_OpenBackupEventLogW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -832,7 +832,7 @@ static bool api_eventlog_ReadEventLogW(s
+ 
+ 	r->out.result = _eventlog_ReadEventLogW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -908,7 +908,7 @@ static bool api_eventlog_ReportEventW(st
+ 	r->out.time_written = r->in.time_written;
+ 	r->out.result = _eventlog_ReportEventW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -981,7 +981,7 @@ static bool api_eventlog_ClearEventLogA(
+ 
+ 	r->out.result = _eventlog_ClearEventLogA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1054,7 +1054,7 @@ static bool api_eventlog_BackupEventLogA
+ 
+ 	r->out.result = _eventlog_BackupEventLogA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1127,7 +1127,7 @@ static bool api_eventlog_OpenEventLogA(s
+ 
+ 	r->out.result = _eventlog_OpenEventLogA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1200,7 +1200,7 @@ static bool api_eventlog_RegisterEventSo
+ 
+ 	r->out.result = _eventlog_RegisterEventSourceA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1273,7 +1273,7 @@ static bool api_eventlog_OpenBackupEvent
+ 
+ 	r->out.result = _eventlog_OpenBackupEventLogA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1346,7 +1346,7 @@ static bool api_eventlog_ReadEventLogA(s
+ 
+ 	r->out.result = _eventlog_ReadEventLogA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1419,7 +1419,7 @@ static bool api_eventlog_ReportEventA(st
+ 
+ 	r->out.result = _eventlog_ReportEventA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1492,7 +1492,7 @@ static bool api_eventlog_RegisterCluster
+ 
+ 	r->out.result = _eventlog_RegisterClusterSvc(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1565,7 +1565,7 @@ static bool api_eventlog_DeregisterClust
+ 
+ 	r->out.result = _eventlog_DeregisterClusterSvc(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1638,7 +1638,7 @@ static bool api_eventlog_WriteClusterEve
+ 
+ 	r->out.result = _eventlog_WriteClusterEvents(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1724,7 +1724,7 @@ static bool api_eventlog_GetLogInformati
+ 
+ 	r->out.result = _eventlog_GetLogInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1797,7 +1797,7 @@ static bool api_eventlog_FlushEventLog(s
+ 
+ 	r->out.result = _eventlog_FlushEventLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1873,7 +1873,7 @@ static bool api_eventlog_ReportEventAndS
+ 	r->out.time_written = r->in.time_written;
+ 	r->out.result = _eventlog_ReportEventAndSourceW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_frsapi.c
++++ b/source3/librpc/gen_ndr/srv_frsapi.c
+@@ -44,7 +44,7 @@ static bool api_FRSAPI_VERIFY_PROMOTION(
+ 
+ 	_FRSAPI_VERIFY_PROMOTION(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_FRSAPI_PROMOTION_STATUS(
+ 
+ 	_FRSAPI_PROMOTION_STATUS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_FRSAPI_START_DEMOTION(st
+ 
+ 	_FRSAPI_START_DEMOTION(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_FRSAPI_COMMIT_DEMOTION(s
+ 
+ 	_FRSAPI_COMMIT_DEMOTION(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_frsapi_SetDsPollingInter
+ 
+ 	r->out.result = _frsapi_SetDsPollingIntervalW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -428,7 +428,7 @@ static bool api_frsapi_GetDsPollingInter
+ 
+ 	r->out.result = _frsapi_GetDsPollingIntervalW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -501,7 +501,7 @@ static bool api_FRSAPI_VERIFY_PROMOTION_
+ 
+ 	_FRSAPI_VERIFY_PROMOTION_W(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -576,7 +576,7 @@ static bool api_frsapi_InfoW(struct pipe
+ 	r->out.info = r->in.info;
+ 	r->out.result = _frsapi_InfoW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -674,7 +674,7 @@ static bool api_frsapi_IsPathReplicated(
+ 
+ 	r->out.result = _frsapi_IsPathReplicated(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -747,7 +747,7 @@ static bool api_frsapi_WriterCommand(str
+ 
+ 	r->out.result = _frsapi_WriterCommand(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -820,7 +820,7 @@ static bool api_frsapi_ForceReplication(
+ 
+ 	r->out.result = _frsapi_ForceReplication(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_frsrpc.c
++++ b/source3/librpc/gen_ndr/srv_frsrpc.c
+@@ -44,7 +44,7 @@ static bool api_frsrpc_FrsSendCommPkt(st
+ 
+ 	r->out.result = _frsrpc_FrsSendCommPkt(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_frsrpc_FrsVerifyPromotio
+ 
+ 	r->out.result = _frsrpc_FrsVerifyPromotionParent(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -192,7 +192,7 @@ static bool api_frsrpc_FrsStartPromotion
+ 	r->out.parent_guid = r->in.parent_guid;
+ 	r->out.result = _frsrpc_FrsStartPromotionParent(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -265,7 +265,7 @@ static bool api_frsrpc_FrsNOP(struct pip
+ 
+ 	r->out.result = _frsrpc_FrsNOP(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -338,7 +338,7 @@ static bool api_FRSRPC_BACKUP_COMPLETE(s
+ 
+ 	_FRSRPC_BACKUP_COMPLETE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -411,7 +411,7 @@ static bool api_FRSRPC_BACKUP_COMPLETE_5
+ 
+ 	_FRSRPC_BACKUP_COMPLETE_5(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -484,7 +484,7 @@ static bool api_FRSRPC_BACKUP_COMPLETE_6
+ 
+ 	_FRSRPC_BACKUP_COMPLETE_6(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -557,7 +557,7 @@ static bool api_FRSRPC_BACKUP_COMPLETE_7
+ 
+ 	_FRSRPC_BACKUP_COMPLETE_7(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -630,7 +630,7 @@ static bool api_FRSRPC_BACKUP_COMPLETE_8
+ 
+ 	_FRSRPC_BACKUP_COMPLETE_8(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -703,7 +703,7 @@ static bool api_FRSRPC_BACKUP_COMPLETE_9
+ 
+ 	_FRSRPC_BACKUP_COMPLETE_9(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -776,7 +776,7 @@ static bool api_FRSRPC_VERIFY_PROMOTION_
+ 
+ 	_FRSRPC_VERIFY_PROMOTION_PARENT_EX(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_frstrans.c
++++ b/source3/librpc/gen_ndr/srv_frstrans.c
+@@ -44,7 +44,7 @@ static bool api_frstrans_CheckConnectivi
+ 
+ 	r->out.result = _frstrans_CheckConnectivity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -130,7 +130,7 @@ static bool api_frstrans_EstablishConnec
+ 
+ 	r->out.result = _frstrans_EstablishConnection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -203,7 +203,7 @@ static bool api_frstrans_EstablishSessio
+ 
+ 	r->out.result = _frstrans_EstablishSession(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -307,7 +307,7 @@ static bool api_frstrans_RequestUpdates(
+ 
+ 	r->out.result = _frstrans_RequestUpdates(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -380,7 +380,7 @@ static bool api_frstrans_RequestVersionV
+ 
+ 	r->out.result = _frstrans_RequestVersionVector(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -460,7 +460,7 @@ static bool api_frstrans_AsyncPoll(struc
+ 
+ 	r->out.result = _frstrans_AsyncPoll(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -533,7 +533,7 @@ static bool api_FRSTRANS_REQUEST_RECORDS
+ 
+ 	_FRSTRANS_REQUEST_RECORDS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -606,7 +606,7 @@ static bool api_FRSTRANS_UPDATE_CANCEL(s
+ 
+ 	_FRSTRANS_UPDATE_CANCEL(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -679,7 +679,7 @@ static bool api_FRSTRANS_RAW_GET_FILE_DA
+ 
+ 	_FRSTRANS_RAW_GET_FILE_DATA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -752,7 +752,7 @@ static bool api_FRSTRANS_RDC_GET_SIGNATU
+ 
+ 	_FRSTRANS_RDC_GET_SIGNATURES(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -825,7 +825,7 @@ static bool api_FRSTRANS_RDC_PUSH_SOURCE
+ 
+ 	_FRSTRANS_RDC_PUSH_SOURCE_NEEDS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -898,7 +898,7 @@ static bool api_FRSTRANS_RDC_GET_FILE_DA
+ 
+ 	_FRSTRANS_RDC_GET_FILE_DATA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -971,7 +971,7 @@ static bool api_FRSTRANS_RDC_CLOSE(struc
+ 
+ 	_FRSTRANS_RDC_CLOSE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1077,7 +1077,7 @@ static bool api_frstrans_InitializeFileT
+ 
+ 	r->out.result = _frstrans_InitializeFileTransferAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1150,7 +1150,7 @@ static bool api_FRSTRANS_OPNUM_0E_NOT_US
+ 
+ 	_FRSTRANS_OPNUM_0E_NOT_USED_ON_THE_WIRE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1230,7 +1230,7 @@ static bool api_frstrans_RawGetFileDataA
+ 
+ 	r->out.result = _frstrans_RawGetFileDataAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1310,7 +1310,7 @@ static bool api_frstrans_RdcGetFileDataA
+ 
+ 	r->out.result = _frstrans_RdcGetFileDataAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_initshutdown.c
++++ b/source3/librpc/gen_ndr/srv_initshutdown.c
+@@ -44,7 +44,7 @@ static bool api_initshutdown_Init(struct
+ 
+ 	r->out.result = _initshutdown_Init(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_initshutdown_Abort(struc
+ 
+ 	r->out.result = _initshutdown_Abort(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_initshutdown_InitEx(stru
+ 
+ 	r->out.result = _initshutdown_InitEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_keysvc.c
++++ b/source3/librpc/gen_ndr/srv_keysvc.c
+@@ -44,7 +44,7 @@ static bool api_keysvc_Unknown0(struct p
+ 
+ 	r->out.result = _keysvc_Unknown0(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_krb5pac.c
++++ b/source3/librpc/gen_ndr/srv_krb5pac.c
+@@ -44,7 +44,7 @@ static bool api_decode_pac(struct pipes_
+ 
+ 	_decode_pac(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_decode_pac_raw(struct pi
+ 
+ 	_decode_pac_raw(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_decode_login_info(struct
+ 
+ 	_decode_login_info(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_decode_login_info_ctr(st
+ 
+ 	_decode_login_info_ctr(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_decode_pac_validate(stru
+ 
+ 	_decode_pac_validate(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_libnetapi.c
++++ b/source3/librpc/gen_ndr/srv_libnetapi.c
+@@ -44,7 +44,7 @@ static bool api_NetJoinDomain(struct pip
+ 
+ 	r->out.result = _NetJoinDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_NetUnjoinDomain(struct p
+ 
+ 	r->out.result = _NetUnjoinDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -203,7 +203,7 @@ static bool api_NetGetJoinInformation(st
+ 
+ 	r->out.result = _NetGetJoinInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -289,7 +289,7 @@ static bool api_NetGetJoinableOUs(struct
+ 
+ 	r->out.result = _NetGetJoinableOUs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -362,7 +362,7 @@ static bool api_NetRenameMachineInDomain
+ 
+ 	r->out.result = _NetRenameMachineInDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -442,7 +442,7 @@ static bool api_NetServerGetInfo(struct
+ 
+ 	r->out.result = _NetServerGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -522,7 +522,7 @@ static bool api_NetServerSetInfo(struct
+ 
+ 	r->out.result = _NetServerSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -602,7 +602,7 @@ static bool api_NetGetDCName(struct pipe
+ 
+ 	r->out.result = _NetGetDCName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -682,7 +682,7 @@ static bool api_NetGetAnyDCName(struct p
+ 
+ 	r->out.result = _NetGetAnyDCName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -762,7 +762,7 @@ static bool api_DsGetDcName(struct pipes
+ 
+ 	r->out.result = _DsGetDcName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -842,7 +842,7 @@ static bool api_NetUserAdd(struct pipes_
+ 
+ 	r->out.result = _NetUserAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -915,7 +915,7 @@ static bool api_NetUserDel(struct pipes_
+ 
+ 	r->out.result = _NetUserDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1008,7 +1008,7 @@ static bool api_NetUserEnum(struct pipes
+ 
+ 	r->out.result = _NetUserEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1081,7 +1081,7 @@ static bool api_NetUserChangePassword(st
+ 
+ 	r->out.result = _NetUserChangePassword(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1161,7 +1161,7 @@ static bool api_NetUserGetInfo(struct pi
+ 
+ 	r->out.result = _NetUserGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1241,7 +1241,7 @@ static bool api_NetUserSetInfo(struct pi
+ 
+ 	r->out.result = _NetUserSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1333,7 +1333,7 @@ static bool api_NetUserGetGroups(struct
+ 
+ 	r->out.result = _NetUserGetGroups(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1406,7 +1406,7 @@ static bool api_NetUserSetGroups(struct
+ 
+ 	r->out.result = _NetUserSetGroups(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1498,7 +1498,7 @@ static bool api_NetUserGetLocalGroups(st
+ 
+ 	r->out.result = _NetUserGetLocalGroups(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1578,7 +1578,7 @@ static bool api_NetUserModalsGet(struct
+ 
+ 	r->out.result = _NetUserModalsGet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1658,7 +1658,7 @@ static bool api_NetUserModalsSet(struct
+ 
+ 	r->out.result = _NetUserModalsSet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1744,7 +1744,7 @@ static bool api_NetQueryDisplayInformati
+ 
+ 	r->out.result = _NetQueryDisplayInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1824,7 +1824,7 @@ static bool api_NetGroupAdd(struct pipes
+ 
+ 	r->out.result = _NetGroupAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1897,7 +1897,7 @@ static bool api_NetGroupDel(struct pipes
+ 
+ 	r->out.result = _NetGroupDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1990,7 +1990,7 @@ static bool api_NetGroupEnum(struct pipe
+ 
+ 	r->out.result = _NetGroupEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2070,7 +2070,7 @@ static bool api_NetGroupSetInfo(struct p
+ 
+ 	r->out.result = _NetGroupSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2150,7 +2150,7 @@ static bool api_NetGroupGetInfo(struct p
+ 
+ 	r->out.result = _NetGroupGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2223,7 +2223,7 @@ static bool api_NetGroupAddUser(struct p
+ 
+ 	r->out.result = _NetGroupAddUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2296,7 +2296,7 @@ static bool api_NetGroupDelUser(struct p
+ 
+ 	r->out.result = _NetGroupDelUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2389,7 +2389,7 @@ static bool api_NetGroupGetUsers(struct
+ 
+ 	r->out.result = _NetGroupGetUsers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2462,7 +2462,7 @@ static bool api_NetGroupSetUsers(struct
+ 
+ 	r->out.result = _NetGroupSetUsers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2542,7 +2542,7 @@ static bool api_NetLocalGroupAdd(struct
+ 
+ 	r->out.result = _NetLocalGroupAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2615,7 +2615,7 @@ static bool api_NetLocalGroupDel(struct
+ 
+ 	r->out.result = _NetLocalGroupDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2695,7 +2695,7 @@ static bool api_NetLocalGroupGetInfo(str
+ 
+ 	r->out.result = _NetLocalGroupGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2775,7 +2775,7 @@ static bool api_NetLocalGroupSetInfo(str
+ 
+ 	r->out.result = _NetLocalGroupSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2868,7 +2868,7 @@ static bool api_NetLocalGroupEnum(struct
+ 
+ 	r->out.result = _NetLocalGroupEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2941,7 +2941,7 @@ static bool api_NetLocalGroupAddMembers(
+ 
+ 	r->out.result = _NetLocalGroupAddMembers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3014,7 +3014,7 @@ static bool api_NetLocalGroupDelMembers(
+ 
+ 	r->out.result = _NetLocalGroupDelMembers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3107,7 +3107,7 @@ static bool api_NetLocalGroupGetMembers(
+ 
+ 	r->out.result = _NetLocalGroupGetMembers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3180,7 +3180,7 @@ static bool api_NetLocalGroupSetMembers(
+ 
+ 	r->out.result = _NetLocalGroupSetMembers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3260,7 +3260,7 @@ static bool api_NetRemoteTOD(struct pipe
+ 
+ 	r->out.result = _NetRemoteTOD(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3340,7 +3340,7 @@ static bool api_NetShareAdd(struct pipes
+ 
+ 	r->out.result = _NetShareAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3413,7 +3413,7 @@ static bool api_NetShareDel(struct pipes
+ 
+ 	r->out.result = _NetShareDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3506,7 +3506,7 @@ static bool api_NetShareEnum(struct pipe
+ 
+ 	r->out.result = _NetShareEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3586,7 +3586,7 @@ static bool api_NetShareGetInfo(struct p
+ 
+ 	r->out.result = _NetShareGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3666,7 +3666,7 @@ static bool api_NetShareSetInfo(struct p
+ 
+ 	r->out.result = _NetShareSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3739,7 +3739,7 @@ static bool api_NetFileClose(struct pipe
+ 
+ 	r->out.result = _NetFileClose(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3819,7 +3819,7 @@ static bool api_NetFileGetInfo(struct pi
+ 
+ 	r->out.result = _NetFileGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3912,7 +3912,7 @@ static bool api_NetFileEnum(struct pipes
+ 
+ 	r->out.result = _NetFileEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3985,7 +3985,7 @@ static bool api_NetShutdownInit(struct p
+ 
+ 	r->out.result = _NetShutdownInit(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4058,7 +4058,7 @@ static bool api_NetShutdownAbort(struct
+ 
+ 	r->out.result = _NetShutdownAbort(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4138,7 +4138,7 @@ static bool api_I_NetLogonControl(struct
+ 
+ 	r->out.result = _I_NetLogonControl(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4218,7 +4218,7 @@ static bool api_I_NetLogonControl2(struc
+ 
+ 	r->out.result = _I_NetLogonControl2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_lsa.c
++++ b/source3/librpc/gen_ndr/srv_lsa.c
+@@ -46,7 +46,7 @@ static bool api_lsa_Close(struct pipes_s
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _lsa_Close(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -119,7 +119,7 @@ static bool api_lsa_Delete(struct pipes_
+ 
+ 	r->out.result = _lsa_Delete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -200,7 +200,7 @@ static bool api_lsa_EnumPrivs(struct pip
+ 
+ 	r->out.result = _lsa_EnumPrivs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -280,7 +280,7 @@ static bool api_lsa_QuerySecurity(struct
+ 
+ 	r->out.result = _lsa_QuerySecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -353,7 +353,7 @@ static bool api_lsa_SetSecObj(struct pip
+ 
+ 	r->out.result = _lsa_SetSecObj(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -426,7 +426,7 @@ static bool api_lsa_ChangePassword(struc
+ 
+ 	r->out.result = _lsa_ChangePassword(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -506,7 +506,7 @@ static bool api_lsa_OpenPolicy(struct pi
+ 
+ 	r->out.result = _lsa_OpenPolicy(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -586,7 +586,7 @@ static bool api_lsa_QueryInfoPolicy(stru
+ 
+ 	r->out.result = _lsa_QueryInfoPolicy(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -659,7 +659,7 @@ static bool api_lsa_SetInfoPolicy(struct
+ 
+ 	r->out.result = _lsa_SetInfoPolicy(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -732,7 +732,7 @@ static bool api_lsa_ClearAuditLog(struct
+ 
+ 	r->out.result = _lsa_ClearAuditLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -812,7 +812,7 @@ static bool api_lsa_CreateAccount(struct
+ 
+ 	r->out.result = _lsa_CreateAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -893,7 +893,7 @@ static bool api_lsa_EnumAccounts(struct
+ 
+ 	r->out.result = _lsa_EnumAccounts(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -973,7 +973,7 @@ static bool api_lsa_CreateTrustedDomain(
+ 
+ 	r->out.result = _lsa_CreateTrustedDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1054,7 +1054,7 @@ static bool api_lsa_EnumTrustDom(struct
+ 
+ 	r->out.result = _lsa_EnumTrustDom(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1136,7 +1136,7 @@ static bool api_lsa_LookupNames(struct p
+ 
+ 	r->out.result = _lsa_LookupNames(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1218,7 +1218,7 @@ static bool api_lsa_LookupSids(struct pi
+ 
+ 	r->out.result = _lsa_LookupSids(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1298,7 +1298,7 @@ static bool api_lsa_CreateSecret(struct
+ 
+ 	r->out.result = _lsa_CreateSecret(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1378,7 +1378,7 @@ static bool api_lsa_OpenAccount(struct p
+ 
+ 	r->out.result = _lsa_OpenAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1458,7 +1458,7 @@ static bool api_lsa_EnumPrivsAccount(str
+ 
+ 	r->out.result = _lsa_EnumPrivsAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1531,7 +1531,7 @@ static bool api_lsa_AddPrivilegesToAccou
+ 
+ 	r->out.result = _lsa_AddPrivilegesToAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1604,7 +1604,7 @@ static bool api_lsa_RemovePrivilegesFrom
+ 
+ 	r->out.result = _lsa_RemovePrivilegesFromAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1677,7 +1677,7 @@ static bool api_lsa_GetQuotasForAccount(
+ 
+ 	r->out.result = _lsa_GetQuotasForAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1750,7 +1750,7 @@ static bool api_lsa_SetQuotasForAccount(
+ 
+ 	r->out.result = _lsa_SetQuotasForAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1830,7 +1830,7 @@ static bool api_lsa_GetSystemAccessAccou
+ 
+ 	r->out.result = _lsa_GetSystemAccessAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1903,7 +1903,7 @@ static bool api_lsa_SetSystemAccessAccou
+ 
+ 	r->out.result = _lsa_SetSystemAccessAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1983,7 +1983,7 @@ static bool api_lsa_OpenTrustedDomain(st
+ 
+ 	r->out.result = _lsa_OpenTrustedDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2063,7 +2063,7 @@ static bool api_lsa_QueryTrustedDomainIn
+ 
+ 	r->out.result = _lsa_QueryTrustedDomainInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2136,7 +2136,7 @@ static bool api_lsa_SetInformationTruste
+ 
+ 	r->out.result = _lsa_SetInformationTrustedDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2216,7 +2216,7 @@ static bool api_lsa_OpenSecret(struct pi
+ 
+ 	r->out.result = _lsa_OpenSecret(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2289,7 +2289,7 @@ static bool api_lsa_SetSecret(struct pip
+ 
+ 	r->out.result = _lsa_SetSecret(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2367,7 +2367,7 @@ static bool api_lsa_QuerySecret(struct p
+ 	r->out.old_mtime = r->in.old_mtime;
+ 	r->out.result = _lsa_QuerySecret(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2447,7 +2447,7 @@ static bool api_lsa_LookupPrivValue(stru
+ 
+ 	r->out.result = _lsa_LookupPrivValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2527,7 +2527,7 @@ static bool api_lsa_LookupPrivName(struc
+ 
+ 	r->out.result = _lsa_LookupPrivName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2613,7 +2613,7 @@ static bool api_lsa_LookupPrivDisplayNam
+ 
+ 	r->out.result = _lsa_LookupPrivDisplayName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2688,7 +2688,7 @@ static bool api_lsa_DeleteObject(struct
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _lsa_DeleteObject(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2768,7 +2768,7 @@ static bool api_lsa_EnumAccountsWithUser
+ 
+ 	r->out.result = _lsa_EnumAccountsWithUserRight(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2848,7 +2848,7 @@ static bool api_lsa_EnumAccountRights(st
+ 
+ 	r->out.result = _lsa_EnumAccountRights(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2921,7 +2921,7 @@ static bool api_lsa_AddAccountRights(str
+ 
+ 	r->out.result = _lsa_AddAccountRights(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2994,7 +2994,7 @@ static bool api_lsa_RemoveAccountRights(
+ 
+ 	r->out.result = _lsa_RemoveAccountRights(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3074,7 +3074,7 @@ static bool api_lsa_QueryTrustedDomainIn
+ 
+ 	r->out.result = _lsa_QueryTrustedDomainInfoBySid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3147,7 +3147,7 @@ static bool api_lsa_SetTrustedDomainInfo
+ 
+ 	r->out.result = _lsa_SetTrustedDomainInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3220,7 +3220,7 @@ static bool api_lsa_DeleteTrustedDomain(
+ 
+ 	r->out.result = _lsa_DeleteTrustedDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3293,7 +3293,7 @@ static bool api_lsa_StorePrivateData(str
+ 
+ 	r->out.result = _lsa_StorePrivateData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3368,7 +3368,7 @@ static bool api_lsa_RetrievePrivateData(
+ 	r->out.val = r->in.val;
+ 	r->out.result = _lsa_RetrievePrivateData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3448,7 +3448,7 @@ static bool api_lsa_OpenPolicy2(struct p
+ 
+ 	r->out.result = _lsa_OpenPolicy2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3524,7 +3524,7 @@ static bool api_lsa_GetUserName(struct p
+ 	r->out.authority_name = r->in.authority_name;
+ 	r->out.result = _lsa_GetUserName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3604,7 +3604,7 @@ static bool api_lsa_QueryInfoPolicy2(str
+ 
+ 	r->out.result = _lsa_QueryInfoPolicy2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3677,7 +3677,7 @@ static bool api_lsa_SetInfoPolicy2(struc
+ 
+ 	r->out.result = _lsa_SetInfoPolicy2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3757,7 +3757,7 @@ static bool api_lsa_QueryTrustedDomainIn
+ 
+ 	r->out.result = _lsa_QueryTrustedDomainInfoByName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3830,7 +3830,7 @@ static bool api_lsa_SetTrustedDomainInfo
+ 
+ 	r->out.result = _lsa_SetTrustedDomainInfoByName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3911,7 +3911,7 @@ static bool api_lsa_EnumTrustedDomainsEx
+ 
+ 	r->out.result = _lsa_EnumTrustedDomainsEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3991,7 +3991,7 @@ static bool api_lsa_CreateTrustedDomainE
+ 
+ 	r->out.result = _lsa_CreateTrustedDomainEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4066,7 +4066,7 @@ static bool api_lsa_CloseTrustedDomainEx
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _lsa_CloseTrustedDomainEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4146,7 +4146,7 @@ static bool api_lsa_QueryDomainInformati
+ 
+ 	r->out.result = _lsa_QueryDomainInformationPolicy(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4219,7 +4219,7 @@ static bool api_lsa_SetDomainInformation
+ 
+ 	r->out.result = _lsa_SetDomainInformationPolicy(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4299,7 +4299,7 @@ static bool api_lsa_OpenTrustedDomainByN
+ 
+ 	r->out.result = _lsa_OpenTrustedDomainByName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4372,7 +4372,7 @@ static bool api_lsa_TestCall(struct pipe
+ 
+ 	r->out.result = _lsa_TestCall(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4454,7 +4454,7 @@ static bool api_lsa_LookupSids2(struct p
+ 
+ 	r->out.result = _lsa_LookupSids2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4536,7 +4536,7 @@ static bool api_lsa_LookupNames2(struct
+ 
+ 	r->out.result = _lsa_LookupNames2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4616,7 +4616,7 @@ static bool api_lsa_CreateTrustedDomainE
+ 
+ 	r->out.result = _lsa_CreateTrustedDomainEx2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4689,7 +4689,7 @@ static bool api_lsa_CREDRWRITE(struct pi
+ 
+ 	r->out.result = _lsa_CREDRWRITE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4762,7 +4762,7 @@ static bool api_lsa_CREDRREAD(struct pip
+ 
+ 	r->out.result = _lsa_CREDRREAD(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4835,7 +4835,7 @@ static bool api_lsa_CREDRENUMERATE(struc
+ 
+ 	r->out.result = _lsa_CREDRENUMERATE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4908,7 +4908,7 @@ static bool api_lsa_CREDRWRITEDOMAINCRED
+ 
+ 	r->out.result = _lsa_CREDRWRITEDOMAINCREDENTIALS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4981,7 +4981,7 @@ static bool api_lsa_CREDRREADDOMAINCREDE
+ 
+ 	r->out.result = _lsa_CREDRREADDOMAINCREDENTIALS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5054,7 +5054,7 @@ static bool api_lsa_CREDRDELETE(struct p
+ 
+ 	r->out.result = _lsa_CREDRDELETE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5127,7 +5127,7 @@ static bool api_lsa_CREDRGETTARGETINFO(s
+ 
+ 	r->out.result = _lsa_CREDRGETTARGETINFO(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5200,7 +5200,7 @@ static bool api_lsa_CREDRPROFILELOADED(s
+ 
+ 	r->out.result = _lsa_CREDRPROFILELOADED(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5282,7 +5282,7 @@ static bool api_lsa_LookupNames3(struct
+ 
+ 	r->out.result = _lsa_LookupNames3(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5355,7 +5355,7 @@ static bool api_lsa_CREDRGETSESSIONTYPES
+ 
+ 	r->out.result = _lsa_CREDRGETSESSIONTYPES(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5428,7 +5428,7 @@ static bool api_lsa_LSARREGISTERAUDITEVE
+ 
+ 	r->out.result = _lsa_LSARREGISTERAUDITEVENT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5501,7 +5501,7 @@ static bool api_lsa_LSARGENAUDITEVENT(st
+ 
+ 	r->out.result = _lsa_LSARGENAUDITEVENT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5574,7 +5574,7 @@ static bool api_lsa_LSARUNREGISTERAUDITE
+ 
+ 	r->out.result = _lsa_LSARUNREGISTERAUDITEVENT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5654,7 +5654,7 @@ static bool api_lsa_lsaRQueryForestTrust
+ 
+ 	r->out.result = _lsa_lsaRQueryForestTrustInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5734,7 +5734,7 @@ static bool api_lsa_lsaRSetForestTrustIn
+ 
+ 	r->out.result = _lsa_lsaRSetForestTrustInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5807,7 +5807,7 @@ static bool api_lsa_CREDRRENAME(struct p
+ 
+ 	r->out.result = _lsa_CREDRRENAME(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5889,7 +5889,7 @@ static bool api_lsa_LookupSids3(struct p
+ 
+ 	r->out.result = _lsa_LookupSids3(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5971,7 +5971,7 @@ static bool api_lsa_LookupNames4(struct
+ 
+ 	r->out.result = _lsa_LookupNames4(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6044,7 +6044,7 @@ static bool api_lsa_LSAROPENPOLICYSCE(st
+ 
+ 	r->out.result = _lsa_LSAROPENPOLICYSCE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6117,7 +6117,7 @@ static bool api_lsa_LSARADTREGISTERSECUR
+ 
+ 	r->out.result = _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6190,7 +6190,7 @@ static bool api_lsa_LSARADTUNREGISTERSEC
+ 
+ 	r->out.result = _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6263,7 +6263,7 @@ static bool api_lsa_LSARADTREPORTSECURIT
+ 
+ 	r->out.result = _lsa_LSARADTREPORTSECURITYEVENT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_mgmt.c
++++ b/source3/librpc/gen_ndr/srv_mgmt.c
+@@ -51,7 +51,7 @@ static bool api_mgmt_inq_if_ids(struct p
+ 
+ 	r->out.result = _mgmt_inq_if_ids(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -131,7 +131,7 @@ static bool api_mgmt_inq_stats(struct pi
+ 
+ 	r->out.result = _mgmt_inq_stats(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -211,7 +211,7 @@ static bool api_mgmt_is_server_listening
+ 
+ 	r->out.result = _mgmt_is_server_listening(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -284,7 +284,7 @@ static bool api_mgmt_stop_server_listeni
+ 
+ 	r->out.result = _mgmt_stop_server_listening(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -364,7 +364,7 @@ static bool api_mgmt_inq_princ_name(stru
+ 
+ 	r->out.result = _mgmt_inq_princ_name(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_msgsvc.c
++++ b/source3/librpc/gen_ndr/srv_msgsvc.c
+@@ -44,7 +44,7 @@ static bool api_NetrMessageNameAdd(struc
+ 
+ 	_NetrMessageNameAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_NetrMessageNameEnum(stru
+ 
+ 	_NetrMessageNameEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_NetrMessageNameGetInfo(s
+ 
+ 	_NetrMessageNameGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_NetrMessageNameDel(struc
+ 
+ 	_NetrMessageNameDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -361,7 +361,7 @@ static bool api_NetrSendMessage(struct p
+ 
+ 	_NetrSendMessage(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_nbt.c
++++ b/source3/librpc/gen_ndr/srv_nbt.c
+@@ -44,7 +44,7 @@ static bool api_decode_nbt_netlogon_pack
+ 
+ 	_decode_nbt_netlogon_packet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_netlogon.c
++++ b/source3/librpc/gen_ndr/srv_netlogon.c
+@@ -51,7 +51,7 @@ static bool api_netr_LogonUasLogon(struc
+ 
+ 	r->out.result = _netr_LogonUasLogon(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -131,7 +131,7 @@ static bool api_netr_LogonUasLogoff(stru
+ 
+ 	r->out.result = _netr_LogonUasLogoff(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -218,7 +218,7 @@ static bool api_netr_LogonSamLogon(struc
+ 
+ 	r->out.result = _netr_LogonSamLogon(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -293,7 +293,7 @@ static bool api_netr_LogonSamLogoff(stru
+ 	r->out.return_authenticator = r->in.return_authenticator;
+ 	r->out.result = _netr_LogonSamLogoff(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -373,7 +373,7 @@ static bool api_netr_ServerReqChallenge(
+ 
+ 	r->out.result = _netr_ServerReqChallenge(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -453,7 +453,7 @@ static bool api_netr_ServerAuthenticate(
+ 
+ 	r->out.result = _netr_ServerAuthenticate(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -533,7 +533,7 @@ static bool api_netr_ServerPasswordSet(s
+ 
+ 	r->out.result = _netr_ServerPasswordSet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -615,7 +615,7 @@ static bool api_netr_DatabaseDeltas(stru
+ 
+ 	r->out.result = _netr_DatabaseDeltas(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -697,7 +697,7 @@ static bool api_netr_DatabaseSync(struct
+ 
+ 	r->out.result = _netr_DatabaseSync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -796,7 +796,7 @@ static bool api_netr_AccountDeltas(struc
+ 
+ 	r->out.result = _netr_AccountDeltas(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -896,7 +896,7 @@ static bool api_netr_AccountSync(struct
+ 
+ 	r->out.result = _netr_AccountSync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -976,7 +976,7 @@ static bool api_netr_GetDcName(struct pi
+ 
+ 	r->out.result = _netr_GetDcName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1056,7 +1056,7 @@ static bool api_netr_LogonControl(struct
+ 
+ 	r->out.result = _netr_LogonControl(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1136,7 +1136,7 @@ static bool api_netr_GetAnyDCName(struct
+ 
+ 	r->out.result = _netr_GetAnyDCName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1216,7 +1216,7 @@ static bool api_netr_LogonControl2(struc
+ 
+ 	r->out.result = _netr_LogonControl2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1297,7 +1297,7 @@ static bool api_netr_ServerAuthenticate2
+ 
+ 	r->out.result = _netr_ServerAuthenticate2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1379,7 +1379,7 @@ static bool api_netr_DatabaseSync2(struc
+ 
+ 	r->out.result = _netr_DatabaseSync2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1460,7 +1460,7 @@ static bool api_netr_DatabaseRedo(struct
+ 
+ 	r->out.result = _netr_DatabaseRedo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1540,7 +1540,7 @@ static bool api_netr_LogonControl2Ex(str
+ 
+ 	r->out.result = _netr_LogonControl2Ex(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1620,7 +1620,7 @@ static bool api_netr_NetrEnumerateTruste
+ 
+ 	r->out.result = _netr_NetrEnumerateTrustedDomains(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1700,7 +1700,7 @@ static bool api_netr_DsRGetDCName(struct
+ 
+ 	r->out.result = _netr_DsRGetDCName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1781,7 +1781,7 @@ static bool api_netr_LogonGetCapabilitie
+ 
+ 	r->out.result = _netr_LogonGetCapabilities(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1854,7 +1854,7 @@ static bool api_netr_NETRLOGONSETSERVICE
+ 
+ 	r->out.result = _netr_NETRLOGONSETSERVICEBITS(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1934,7 +1934,7 @@ static bool api_netr_LogonGetTrustRid(st
+ 
+ 	r->out.result = _netr_LogonGetTrustRid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2007,7 +2007,7 @@ static bool api_netr_NETRLOGONCOMPUTESER
+ 
+ 	r->out.result = _netr_NETRLOGONCOMPUTESERVERDIGEST(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2080,7 +2080,7 @@ static bool api_netr_NETRLOGONCOMPUTECLI
+ 
+ 	r->out.result = _netr_NETRLOGONCOMPUTECLIENTDIGEST(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2167,7 +2167,7 @@ static bool api_netr_ServerAuthenticate3
+ 
+ 	r->out.result = _netr_ServerAuthenticate3(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2247,7 +2247,7 @@ static bool api_netr_DsRGetDCNameEx(stru
+ 
+ 	r->out.result = _netr_DsRGetDCNameEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2327,7 +2327,7 @@ static bool api_netr_DsRGetSiteName(stru
+ 
+ 	r->out.result = _netr_DsRGetSiteName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2408,7 +2408,7 @@ static bool api_netr_LogonGetDomainInfo(
+ 
+ 	r->out.result = _netr_LogonGetDomainInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2488,7 +2488,7 @@ static bool api_netr_ServerPasswordSet2(
+ 
+ 	r->out.result = _netr_ServerPasswordSet2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2574,7 +2574,7 @@ static bool api_netr_ServerPasswordGet(s
+ 
+ 	r->out.result = _netr_ServerPasswordGet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2647,7 +2647,7 @@ static bool api_netr_NETRLOGONSENDTOSAM(
+ 
+ 	r->out.result = _netr_NETRLOGONSENDTOSAM(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2727,7 +2727,7 @@ static bool api_netr_DsRAddressToSitenam
+ 
+ 	r->out.result = _netr_DsRAddressToSitenamesW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2807,7 +2807,7 @@ static bool api_netr_DsRGetDCNameEx2(str
+ 
+ 	r->out.result = _netr_DsRGetDCNameEx2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2880,7 +2880,7 @@ static bool api_netr_NETRLOGONGETTIMESER
+ 
+ 	r->out.result = _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2960,7 +2960,7 @@ static bool api_netr_NetrEnumerateTruste
+ 
+ 	r->out.result = _netr_NetrEnumerateTrustedDomainsEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3040,7 +3040,7 @@ static bool api_netr_DsRAddressToSitenam
+ 
+ 	r->out.result = _netr_DsRAddressToSitenamesExW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3120,7 +3120,7 @@ static bool api_netr_DsrGetDcSiteCoverag
+ 
+ 	r->out.result = _netr_DsrGetDcSiteCoverageW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3207,7 +3207,7 @@ static bool api_netr_LogonSamLogonEx(str
+ 
+ 	r->out.result = _netr_LogonSamLogonEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3287,7 +3287,7 @@ static bool api_netr_DsrEnumerateDomainT
+ 
+ 	r->out.result = _netr_DsrEnumerateDomainTrusts(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3360,7 +3360,7 @@ static bool api_netr_DsrDeregisterDNSHos
+ 
+ 	r->out.result = _netr_DsrDeregisterDNSHostRecords(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3452,7 +3452,7 @@ static bool api_netr_ServerTrustPassword
+ 
+ 	r->out.result = _netr_ServerTrustPasswordsGet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3532,7 +3532,7 @@ static bool api_netr_DsRGetForestTrustIn
+ 
+ 	r->out.result = _netr_DsRGetForestTrustInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3618,7 +3618,7 @@ static bool api_netr_GetForestTrustInfor
+ 
+ 	r->out.result = _netr_GetForestTrustInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3706,7 +3706,7 @@ static bool api_netr_LogonSamLogonWithFl
+ 
+ 	r->out.result = _netr_LogonSamLogonWithFlags(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3804,7 +3804,7 @@ static bool api_netr_ServerGetTrustInfo(
+ 
+ 	r->out.result = _netr_ServerGetTrustInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3877,7 +3877,7 @@ static bool api_netr_Unused47(struct pip
+ 
+ 	r->out.result = _netr_Unused47(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3958,7 +3958,7 @@ static bool api_netr_DsrUpdateReadOnlySe
+ 
+ 	r->out.result = _netr_DsrUpdateReadOnlyServerDnsRecords(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_ntlmssp.c
++++ b/source3/librpc/gen_ndr/srv_ntlmssp.c
+@@ -44,7 +44,7 @@ static bool api_decode_NEGOTIATE_MESSAGE
+ 
+ 	_decode_NEGOTIATE_MESSAGE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_decode_CHALLENGE_MESSAGE
+ 
+ 	_decode_CHALLENGE_MESSAGE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_decode_AUTHENTICATE_MESS
+ 
+ 	_decode_AUTHENTICATE_MESSAGE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_decode_NTLMv2_CLIENT_CHA
+ 
+ 	_decode_NTLMv2_CLIENT_CHALLENGE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_decode_NTLMv2_RESPONSE(s
+ 
+ 	_decode_NTLMv2_RESPONSE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_ntprinting.c
++++ b/source3/librpc/gen_ndr/srv_ntprinting.c
+@@ -44,7 +44,7 @@ static bool api_decode_ntprinting_form(s
+ 
+ 	_decode_ntprinting_form(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_decode_ntprinting_driver
+ 
+ 	_decode_ntprinting_driver(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_decode_ntprinting_printe
+ 
+ 	_decode_ntprinting_printer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_ntsvcs.c
++++ b/source3/librpc/gen_ndr/srv_ntsvcs.c
+@@ -44,7 +44,7 @@ static bool api_PNP_Disconnect(struct pi
+ 
+ 	r->out.result = _PNP_Disconnect(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_PNP_Connect(struct pipes
+ 
+ 	r->out.result = _PNP_Connect(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -197,7 +197,7 @@ static bool api_PNP_GetVersion(struct pi
+ 
+ 	r->out.result = _PNP_GetVersion(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -270,7 +270,7 @@ static bool api_PNP_GetGlobalState(struc
+ 
+ 	r->out.result = _PNP_GetGlobalState(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -343,7 +343,7 @@ static bool api_PNP_InitDetection(struct
+ 
+ 	r->out.result = _PNP_InitDetection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -416,7 +416,7 @@ static bool api_PNP_ReportLogOn(struct p
+ 
+ 	r->out.result = _PNP_ReportLogOn(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -489,7 +489,7 @@ static bool api_PNP_ValidateDeviceInstan
+ 
+ 	r->out.result = _PNP_ValidateDeviceInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -562,7 +562,7 @@ static bool api_PNP_GetRootDeviceInstanc
+ 
+ 	r->out.result = _PNP_GetRootDeviceInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -635,7 +635,7 @@ static bool api_PNP_GetRelatedDeviceInst
+ 
+ 	r->out.result = _PNP_GetRelatedDeviceInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -708,7 +708,7 @@ static bool api_PNP_EnumerateSubKeys(str
+ 
+ 	r->out.result = _PNP_EnumerateSubKeys(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -789,7 +789,7 @@ static bool api_PNP_GetDeviceList(struct
+ 
+ 	r->out.result = _PNP_GetDeviceList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -869,7 +869,7 @@ static bool api_PNP_GetDeviceListSize(st
+ 
+ 	r->out.result = _PNP_GetDeviceListSize(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -942,7 +942,7 @@ static bool api_PNP_GetDepth(struct pipe
+ 
+ 	r->out.result = _PNP_GetDepth(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1025,7 +1025,7 @@ static bool api_PNP_GetDeviceRegProp(str
+ 
+ 	r->out.result = _PNP_GetDeviceRegProp(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1098,7 +1098,7 @@ static bool api_PNP_SetDeviceRegProp(str
+ 
+ 	r->out.result = _PNP_SetDeviceRegProp(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1171,7 +1171,7 @@ static bool api_PNP_GetClassInstance(str
+ 
+ 	r->out.result = _PNP_GetClassInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1244,7 +1244,7 @@ static bool api_PNP_CreateKey(struct pip
+ 
+ 	r->out.result = _PNP_CreateKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1317,7 +1317,7 @@ static bool api_PNP_DeleteRegistryKey(st
+ 
+ 	r->out.result = _PNP_DeleteRegistryKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1390,7 +1390,7 @@ static bool api_PNP_GetClassCount(struct
+ 
+ 	r->out.result = _PNP_GetClassCount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1463,7 +1463,7 @@ static bool api_PNP_GetClassName(struct
+ 
+ 	r->out.result = _PNP_GetClassName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1536,7 +1536,7 @@ static bool api_PNP_DeleteClassKey(struc
+ 
+ 	r->out.result = _PNP_DeleteClassKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1609,7 +1609,7 @@ static bool api_PNP_GetInterfaceDeviceAl
+ 
+ 	r->out.result = _PNP_GetInterfaceDeviceAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1682,7 +1682,7 @@ static bool api_PNP_GetInterfaceDeviceLi
+ 
+ 	r->out.result = _PNP_GetInterfaceDeviceList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1755,7 +1755,7 @@ static bool api_PNP_GetInterfaceDeviceLi
+ 
+ 	r->out.result = _PNP_GetInterfaceDeviceListSize(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1828,7 +1828,7 @@ static bool api_PNP_RegisterDeviceClassA
+ 
+ 	r->out.result = _PNP_RegisterDeviceClassAssociation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1901,7 +1901,7 @@ static bool api_PNP_UnregisterDeviceClas
+ 
+ 	r->out.result = _PNP_UnregisterDeviceClassAssociation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1974,7 +1974,7 @@ static bool api_PNP_GetClassRegProp(stru
+ 
+ 	r->out.result = _PNP_GetClassRegProp(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2047,7 +2047,7 @@ static bool api_PNP_SetClassRegProp(stru
+ 
+ 	r->out.result = _PNP_SetClassRegProp(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2120,7 +2120,7 @@ static bool api_PNP_CreateDevInst(struct
+ 
+ 	r->out.result = _PNP_CreateDevInst(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2193,7 +2193,7 @@ static bool api_PNP_DeviceInstanceAction
+ 
+ 	r->out.result = _PNP_DeviceInstanceAction(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2266,7 +2266,7 @@ static bool api_PNP_GetDeviceStatus(stru
+ 
+ 	r->out.result = _PNP_GetDeviceStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2339,7 +2339,7 @@ static bool api_PNP_SetDeviceProblem(str
+ 
+ 	r->out.result = _PNP_SetDeviceProblem(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2412,7 +2412,7 @@ static bool api_PNP_DisableDevInst(struc
+ 
+ 	r->out.result = _PNP_DisableDevInst(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2485,7 +2485,7 @@ static bool api_PNP_UninstallDevInst(str
+ 
+ 	r->out.result = _PNP_UninstallDevInst(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2558,7 +2558,7 @@ static bool api_PNP_AddID(struct pipes_s
+ 
+ 	r->out.result = _PNP_AddID(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2631,7 +2631,7 @@ static bool api_PNP_RegisterDriver(struc
+ 
+ 	r->out.result = _PNP_RegisterDriver(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2704,7 +2704,7 @@ static bool api_PNP_QueryRemove(struct p
+ 
+ 	r->out.result = _PNP_QueryRemove(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2777,7 +2777,7 @@ static bool api_PNP_RequestDeviceEject(s
+ 
+ 	r->out.result = _PNP_RequestDeviceEject(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2850,7 +2850,7 @@ static bool api_PNP_IsDockStationPresent
+ 
+ 	r->out.result = _PNP_IsDockStationPresent(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2923,7 +2923,7 @@ static bool api_PNP_RequestEjectPC(struc
+ 
+ 	r->out.result = _PNP_RequestEjectPC(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3005,7 +3005,7 @@ static bool api_PNP_HwProfFlags(struct p
+ 
+ 	r->out.result = _PNP_HwProfFlags(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3080,7 +3080,7 @@ static bool api_PNP_GetHwProfInfo(struct
+ 	r->out.info = r->in.info;
+ 	r->out.result = _PNP_GetHwProfInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3153,7 +3153,7 @@ static bool api_PNP_AddEmptyLogConf(stru
+ 
+ 	r->out.result = _PNP_AddEmptyLogConf(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3226,7 +3226,7 @@ static bool api_PNP_FreeLogConf(struct p
+ 
+ 	r->out.result = _PNP_FreeLogConf(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3299,7 +3299,7 @@ static bool api_PNP_GetFirstLogConf(stru
+ 
+ 	r->out.result = _PNP_GetFirstLogConf(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3372,7 +3372,7 @@ static bool api_PNP_GetNextLogConf(struc
+ 
+ 	r->out.result = _PNP_GetNextLogConf(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3445,7 +3445,7 @@ static bool api_PNP_GetLogConfPriority(s
+ 
+ 	r->out.result = _PNP_GetLogConfPriority(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3518,7 +3518,7 @@ static bool api_PNP_AddResDes(struct pip
+ 
+ 	r->out.result = _PNP_AddResDes(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3591,7 +3591,7 @@ static bool api_PNP_FreeResDes(struct pi
+ 
+ 	r->out.result = _PNP_FreeResDes(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3664,7 +3664,7 @@ static bool api_PNP_GetNextResDes(struct
+ 
+ 	r->out.result = _PNP_GetNextResDes(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3737,7 +3737,7 @@ static bool api_PNP_GetResDesData(struct
+ 
+ 	r->out.result = _PNP_GetResDesData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3810,7 +3810,7 @@ static bool api_PNP_GetResDesDataSize(st
+ 
+ 	r->out.result = _PNP_GetResDesDataSize(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3883,7 +3883,7 @@ static bool api_PNP_ModifyResDes(struct
+ 
+ 	r->out.result = _PNP_ModifyResDes(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3956,7 +3956,7 @@ static bool api_PNP_DetectResourceLimit(
+ 
+ 	r->out.result = _PNP_DetectResourceLimit(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4029,7 +4029,7 @@ static bool api_PNP_QueryResConfList(str
+ 
+ 	r->out.result = _PNP_QueryResConfList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4102,7 +4102,7 @@ static bool api_PNP_SetHwProf(struct pip
+ 
+ 	r->out.result = _PNP_SetHwProf(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4175,7 +4175,7 @@ static bool api_PNP_QueryArbitratorFreeD
+ 
+ 	r->out.result = _PNP_QueryArbitratorFreeData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4248,7 +4248,7 @@ static bool api_PNP_QueryArbitratorFreeS
+ 
+ 	r->out.result = _PNP_QueryArbitratorFreeSize(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4321,7 +4321,7 @@ static bool api_PNP_RunDetection(struct
+ 
+ 	r->out.result = _PNP_RunDetection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4394,7 +4394,7 @@ static bool api_PNP_RegisterNotification
+ 
+ 	r->out.result = _PNP_RegisterNotification(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4467,7 +4467,7 @@ static bool api_PNP_UnregisterNotificati
+ 
+ 	r->out.result = _PNP_UnregisterNotification(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4540,7 +4540,7 @@ static bool api_PNP_GetCustomDevProp(str
+ 
+ 	r->out.result = _PNP_GetCustomDevProp(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4613,7 +4613,7 @@ static bool api_PNP_GetVersionInternal(s
+ 
+ 	r->out.result = _PNP_GetVersionInternal(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4686,7 +4686,7 @@ static bool api_PNP_GetBlockedDriverInfo
+ 
+ 	r->out.result = _PNP_GetBlockedDriverInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4759,7 +4759,7 @@ static bool api_PNP_GetServerSideDeviceI
+ 
+ 	r->out.result = _PNP_GetServerSideDeviceInstallFlags(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_oxidresolver.c
++++ b/source3/librpc/gen_ndr/srv_oxidresolver.c
+@@ -63,7 +63,7 @@ static bool api_ResolveOxid(struct pipes
+ 
+ 	r->out.result = _ResolveOxid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -136,7 +136,7 @@ static bool api_SimplePing(struct pipes_
+ 
+ 	r->out.result = _SimplePing(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -217,7 +217,7 @@ static bool api_ComplexPing(struct pipes
+ 
+ 	r->out.result = _ComplexPing(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -290,7 +290,7 @@ static bool api_ServerAlive(struct pipes
+ 
+ 	r->out.result = _ServerAlive(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -388,7 +388,7 @@ static bool api_ResolveOxid2(struct pipe
+ 
+ 	r->out.result = _ResolveOxid2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -492,7 +492,7 @@ static bool api_ServerAlive2(struct pipe
+ 
+ 	r->out.result = _ServerAlive2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_policyagent.c
++++ b/source3/librpc/gen_ndr/srv_policyagent.c
+@@ -44,7 +44,7 @@ static bool api_policyagent_Dummy(struct
+ 
+ 	r->out.result = _policyagent_Dummy(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_preg.c
++++ b/source3/librpc/gen_ndr/srv_preg.c
+@@ -44,7 +44,7 @@ static bool api_decode_preg_file(struct
+ 
+ 	_decode_preg_file(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_rap.c
++++ b/source3/librpc/gen_ndr/srv_rap.c
+@@ -51,7 +51,7 @@ static bool api_rap_NetShareEnum(struct
+ 
+ 	_rap_NetShareEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -125,7 +125,7 @@ static bool api_rap_NetShareAdd(struct p
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetShareAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -205,7 +205,7 @@ static bool api_rap_NetServerEnum2(struc
+ 
+ 	_rap_NetServerEnum2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -279,7 +279,7 @@ static bool api_rap_WserverGetInfo(struc
+ 	ZERO_STRUCT(r->out);
+ 	_rap_WserverGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -359,7 +359,7 @@ static bool api_rap_NetPrintQEnum(struct
+ 
+ 	_rap_NetPrintQEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -433,7 +433,7 @@ static bool api_rap_NetPrintQGetInfo(str
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintQGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -507,7 +507,7 @@ static bool api_rap_NetPrintJobPause(str
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintJobPause(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -581,7 +581,7 @@ static bool api_rap_NetPrintJobContinue(
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintJobContinue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -655,7 +655,7 @@ static bool api_rap_NetPrintJobDelete(st
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintJobDelete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -729,7 +729,7 @@ static bool api_rap_NetPrintQueuePause(s
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintQueuePause(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -803,7 +803,7 @@ static bool api_rap_NetPrintQueueResume(
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintQueueResume(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -877,7 +877,7 @@ static bool api_rap_NetPrintQueuePurge(s
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintQueuePurge(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -957,7 +957,7 @@ static bool api_rap_NetPrintJobEnum(stru
+ 
+ 	_rap_NetPrintJobEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1031,7 +1031,7 @@ static bool api_rap_NetPrintJobGetInfo(s
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintJobGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1105,7 +1105,7 @@ static bool api_rap_NetPrintJobSetInfo(s
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintJobSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1185,7 +1185,7 @@ static bool api_rap_NetPrintDestEnum(str
+ 
+ 	_rap_NetPrintDestEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1259,7 +1259,7 @@ static bool api_rap_NetPrintDestGetInfo(
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetPrintDestGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1333,7 +1333,7 @@ static bool api_rap_NetUserPasswordSet2(
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetUserPasswordSet2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1407,7 +1407,7 @@ static bool api_rap_NetOEMChangePassword
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetOEMChangePassword(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1481,7 +1481,7 @@ static bool api_rap_NetUserGetInfo(struc
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetUserGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1561,7 +1561,7 @@ static bool api_rap_NetSessionEnum(struc
+ 
+ 	_rap_NetSessionEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1635,7 +1635,7 @@ static bool api_rap_NetSessionGetInfo(st
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetSessionGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1709,7 +1709,7 @@ static bool api_rap_NetUserAdd(struct pi
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetUserAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1783,7 +1783,7 @@ static bool api_rap_NetUserDelete(struct
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetUserDelete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1857,7 +1857,7 @@ static bool api_rap_NetRemoteTOD(struct
+ 	ZERO_STRUCT(r->out);
+ 	_rap_NetRemoteTOD(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_remact.c
++++ b/source3/librpc/gen_ndr/srv_remact.c
+@@ -99,7 +99,7 @@ static bool api_RemoteActivation(struct
+ 
+ 	r->out.result = _RemoteActivation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_rot.c
++++ b/source3/librpc/gen_ndr/srv_rot.c
+@@ -51,7 +51,7 @@ static bool api_rot_add(struct pipes_str
+ 
+ 	r->out.result = _rot_add(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -124,7 +124,7 @@ static bool api_rot_remove(struct pipes_
+ 
+ 	r->out.result = _rot_remove(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -197,7 +197,7 @@ static bool api_rot_is_listed(struct pip
+ 
+ 	r->out.result = _rot_is_listed(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -277,7 +277,7 @@ static bool api_rot_get_interface_pointe
+ 
+ 	r->out.result = _rot_get_interface_pointer(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -350,7 +350,7 @@ static bool api_rot_set_modification_tim
+ 
+ 	r->out.result = _rot_set_modification_time(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -430,7 +430,7 @@ static bool api_rot_get_modification_tim
+ 
+ 	r->out.result = _rot_get_modification_time(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -510,7 +510,7 @@ static bool api_rot_enum(struct pipes_st
+ 
+ 	r->out.result = _rot_enum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_samr.c
++++ b/source3/librpc/gen_ndr/srv_samr.c
+@@ -51,7 +51,7 @@ static bool api_samr_Connect(struct pipe
+ 
+ 	r->out.result = _samr_Connect(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -126,7 +126,7 @@ static bool api_samr_Close(struct pipes_
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _samr_Close(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -199,7 +199,7 @@ static bool api_samr_SetSecurity(struct
+ 
+ 	r->out.result = _samr_SetSecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -279,7 +279,7 @@ static bool api_samr_QuerySecurity(struc
+ 
+ 	r->out.result = _samr_QuerySecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -352,7 +352,7 @@ static bool api_samr_Shutdown(struct pip
+ 
+ 	r->out.result = _samr_Shutdown(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -432,7 +432,7 @@ static bool api_samr_LookupDomain(struct
+ 
+ 	r->out.result = _samr_LookupDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -519,7 +519,7 @@ static bool api_samr_EnumDomains(struct
+ 
+ 	r->out.result = _samr_EnumDomains(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -599,7 +599,7 @@ static bool api_samr_OpenDomain(struct p
+ 
+ 	r->out.result = _samr_OpenDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -679,7 +679,7 @@ static bool api_samr_QueryDomainInfo(str
+ 
+ 	r->out.result = _samr_QueryDomainInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -752,7 +752,7 @@ static bool api_samr_SetDomainInfo(struc
+ 
+ 	r->out.result = _samr_SetDomainInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -838,7 +838,7 @@ static bool api_samr_CreateDomainGroup(s
+ 
+ 	r->out.result = _samr_CreateDomainGroup(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -925,7 +925,7 @@ static bool api_samr_EnumDomainGroups(st
+ 
+ 	r->out.result = _samr_EnumDomainGroups(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1011,7 +1011,7 @@ static bool api_samr_CreateUser(struct p
+ 
+ 	r->out.result = _samr_CreateUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1098,7 +1098,7 @@ static bool api_samr_EnumDomainUsers(str
+ 
+ 	r->out.result = _samr_EnumDomainUsers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1184,7 +1184,7 @@ static bool api_samr_CreateDomAlias(stru
+ 
+ 	r->out.result = _samr_CreateDomAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1271,7 +1271,7 @@ static bool api_samr_EnumDomainAliases(s
+ 
+ 	r->out.result = _samr_EnumDomainAliases(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1351,7 +1351,7 @@ static bool api_samr_GetAliasMembership(
+ 
+ 	r->out.result = _samr_GetAliasMembership(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1437,7 +1437,7 @@ static bool api_samr_LookupNames(struct
+ 
+ 	r->out.result = _samr_LookupNames(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1523,7 +1523,7 @@ static bool api_samr_LookupRids(struct p
+ 
+ 	r->out.result = _samr_LookupRids(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1603,7 +1603,7 @@ static bool api_samr_OpenGroup(struct pi
+ 
+ 	r->out.result = _samr_OpenGroup(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1683,7 +1683,7 @@ static bool api_samr_QueryGroupInfo(stru
+ 
+ 	r->out.result = _samr_QueryGroupInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1756,7 +1756,7 @@ static bool api_samr_SetGroupInfo(struct
+ 
+ 	r->out.result = _samr_SetGroupInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1829,7 +1829,7 @@ static bool api_samr_AddGroupMember(stru
+ 
+ 	r->out.result = _samr_AddGroupMember(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1904,7 +1904,7 @@ static bool api_samr_DeleteDomainGroup(s
+ 	r->out.group_handle = r->in.group_handle;
+ 	r->out.result = _samr_DeleteDomainGroup(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1977,7 +1977,7 @@ static bool api_samr_DeleteGroupMember(s
+ 
+ 	r->out.result = _samr_DeleteGroupMember(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2057,7 +2057,7 @@ static bool api_samr_QueryGroupMember(st
+ 
+ 	r->out.result = _samr_QueryGroupMember(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2130,7 +2130,7 @@ static bool api_samr_SetMemberAttributes
+ 
+ 	r->out.result = _samr_SetMemberAttributesOfGroup(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2210,7 +2210,7 @@ static bool api_samr_OpenAlias(struct pi
+ 
+ 	r->out.result = _samr_OpenAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2290,7 +2290,7 @@ static bool api_samr_QueryAliasInfo(stru
+ 
+ 	r->out.result = _samr_QueryAliasInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2363,7 +2363,7 @@ static bool api_samr_SetAliasInfo(struct
+ 
+ 	r->out.result = _samr_SetAliasInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2438,7 +2438,7 @@ static bool api_samr_DeleteDomAlias(stru
+ 	r->out.alias_handle = r->in.alias_handle;
+ 	r->out.result = _samr_DeleteDomAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2511,7 +2511,7 @@ static bool api_samr_AddAliasMember(stru
+ 
+ 	r->out.result = _samr_AddAliasMember(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2584,7 +2584,7 @@ static bool api_samr_DeleteAliasMember(s
+ 
+ 	r->out.result = _samr_DeleteAliasMember(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2664,7 +2664,7 @@ static bool api_samr_GetMembersInAlias(s
+ 
+ 	r->out.result = _samr_GetMembersInAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2744,7 +2744,7 @@ static bool api_samr_OpenUser(struct pip
+ 
+ 	r->out.result = _samr_OpenUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2819,7 +2819,7 @@ static bool api_samr_DeleteUser(struct p
+ 	r->out.user_handle = r->in.user_handle;
+ 	r->out.result = _samr_DeleteUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2899,7 +2899,7 @@ static bool api_samr_QueryUserInfo(struc
+ 
+ 	r->out.result = _samr_QueryUserInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2972,7 +2972,7 @@ static bool api_samr_SetUserInfo(struct
+ 
+ 	r->out.result = _samr_SetUserInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3045,7 +3045,7 @@ static bool api_samr_ChangePasswordUser(
+ 
+ 	r->out.result = _samr_ChangePasswordUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3125,7 +3125,7 @@ static bool api_samr_GetGroupsForUser(st
+ 
+ 	r->out.result = _samr_GetGroupsForUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3217,7 +3217,7 @@ static bool api_samr_QueryDisplayInfo(st
+ 
+ 	r->out.result = _samr_QueryDisplayInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3297,7 +3297,7 @@ static bool api_samr_GetDisplayEnumerati
+ 
+ 	r->out.result = _samr_GetDisplayEnumerationIndex(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3370,7 +3370,7 @@ static bool api_samr_TestPrivateFunction
+ 
+ 	r->out.result = _samr_TestPrivateFunctionsDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3443,7 +3443,7 @@ static bool api_samr_TestPrivateFunction
+ 
+ 	r->out.result = _samr_TestPrivateFunctionsUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3523,7 +3523,7 @@ static bool api_samr_GetUserPwInfo(struc
+ 
+ 	r->out.result = _samr_GetUserPwInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3596,7 +3596,7 @@ static bool api_samr_RemoveMemberFromFor
+ 
+ 	r->out.result = _samr_RemoveMemberFromForeignDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3676,7 +3676,7 @@ static bool api_samr_QueryDomainInfo2(st
+ 
+ 	r->out.result = _samr_QueryDomainInfo2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3756,7 +3756,7 @@ static bool api_samr_QueryUserInfo2(stru
+ 
+ 	r->out.result = _samr_QueryUserInfo2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3848,7 +3848,7 @@ static bool api_samr_QueryDisplayInfo2(s
+ 
+ 	r->out.result = _samr_QueryDisplayInfo2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3928,7 +3928,7 @@ static bool api_samr_GetDisplayEnumerati
+ 
+ 	r->out.result = _samr_GetDisplayEnumerationIndex2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4020,7 +4020,7 @@ static bool api_samr_CreateUser2(struct
+ 
+ 	r->out.result = _samr_CreateUser2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4112,7 +4112,7 @@ static bool api_samr_QueryDisplayInfo3(s
+ 
+ 	r->out.result = _samr_QueryDisplayInfo3(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4185,7 +4185,7 @@ static bool api_samr_AddMultipleMembersT
+ 
+ 	r->out.result = _samr_AddMultipleMembersToAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4258,7 +4258,7 @@ static bool api_samr_RemoveMultipleMembe
+ 
+ 	r->out.result = _samr_RemoveMultipleMembersFromAlias(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4331,7 +4331,7 @@ static bool api_samr_OemChangePasswordUs
+ 
+ 	r->out.result = _samr_OemChangePasswordUser2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4404,7 +4404,7 @@ static bool api_samr_ChangePasswordUser2
+ 
+ 	r->out.result = _samr_ChangePasswordUser2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4484,7 +4484,7 @@ static bool api_samr_GetDomPwInfo(struct
+ 
+ 	r->out.result = _samr_GetDomPwInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4564,7 +4564,7 @@ static bool api_samr_Connect2(struct pip
+ 
+ 	r->out.result = _samr_Connect2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4637,7 +4637,7 @@ static bool api_samr_SetUserInfo2(struct
+ 
+ 	r->out.result = _samr_SetUserInfo2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4710,7 +4710,7 @@ static bool api_samr_SetBootKeyInformati
+ 
+ 	r->out.result = _samr_SetBootKeyInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4790,7 +4790,7 @@ static bool api_samr_GetBootKeyInformati
+ 
+ 	r->out.result = _samr_GetBootKeyInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4870,7 +4870,7 @@ static bool api_samr_Connect3(struct pip
+ 
+ 	r->out.result = _samr_Connect3(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4950,7 +4950,7 @@ static bool api_samr_Connect4(struct pip
+ 
+ 	r->out.result = _samr_Connect4(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5036,7 +5036,7 @@ static bool api_samr_ChangePasswordUser3
+ 
+ 	r->out.result = _samr_ChangePasswordUser3(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5128,7 +5128,7 @@ static bool api_samr_Connect5(struct pip
+ 
+ 	r->out.result = _samr_Connect5(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5208,7 +5208,7 @@ static bool api_samr_RidToSid(struct pip
+ 
+ 	r->out.result = _samr_RidToSid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5281,7 +5281,7 @@ static bool api_samr_SetDsrmPassword(str
+ 
+ 	r->out.result = _samr_SetDsrmPassword(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5361,7 +5361,7 @@ static bool api_samr_ValidatePassword(st
+ 
+ 	r->out.result = _samr_ValidatePassword(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_scerpc.c
++++ b/source3/librpc/gen_ndr/srv_scerpc.c
+@@ -44,7 +44,7 @@ static bool api_scerpc_Unknown0(struct p
+ 
+ 	r->out.result = _scerpc_Unknown0(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_spoolss.c
++++ b/source3/librpc/gen_ndr/srv_spoolss.c
+@@ -63,7 +63,7 @@ static bool api_spoolss_EnumPrinters(str
+ 
+ 	r->out.result = _spoolss_EnumPrinters(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -143,7 +143,7 @@ static bool api_spoolss_OpenPrinter(stru
+ 
+ 	r->out.result = _spoolss_OpenPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -216,7 +216,7 @@ static bool api_spoolss_SetJob(struct pi
+ 
+ 	r->out.result = _spoolss_SetJob(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -302,7 +302,7 @@ static bool api_spoolss_GetJob(struct pi
+ 
+ 	r->out.result = _spoolss_GetJob(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -394,7 +394,7 @@ static bool api_spoolss_EnumJobs(struct
+ 
+ 	r->out.result = _spoolss_EnumJobs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -474,7 +474,7 @@ static bool api_spoolss_AddPrinter(struc
+ 
+ 	r->out.result = _spoolss_AddPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -547,7 +547,7 @@ static bool api_spoolss_DeletePrinter(st
+ 
+ 	r->out.result = _spoolss_DeletePrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -620,7 +620,7 @@ static bool api_spoolss_SetPrinter(struc
+ 
+ 	r->out.result = _spoolss_SetPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -706,7 +706,7 @@ static bool api_spoolss_GetPrinter(struc
+ 
+ 	r->out.result = _spoolss_GetPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -779,7 +779,7 @@ static bool api_spoolss_AddPrinterDriver
+ 
+ 	r->out.result = _spoolss_AddPrinterDriver(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -871,7 +871,7 @@ static bool api_spoolss_EnumPrinterDrive
+ 
+ 	r->out.result = _spoolss_EnumPrinterDrivers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -957,7 +957,7 @@ static bool api_spoolss_GetPrinterDriver
+ 
+ 	r->out.result = _spoolss_GetPrinterDriver(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1043,7 +1043,7 @@ static bool api_spoolss_GetPrinterDriver
+ 
+ 	r->out.result = _spoolss_GetPrinterDriverDirectory(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1116,7 +1116,7 @@ static bool api_spoolss_DeletePrinterDri
+ 
+ 	r->out.result = _spoolss_DeletePrinterDriver(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1189,7 +1189,7 @@ static bool api_spoolss_AddPrintProcesso
+ 
+ 	r->out.result = _spoolss_AddPrintProcessor(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1281,7 +1281,7 @@ static bool api_spoolss_EnumPrintProcess
+ 
+ 	r->out.result = _spoolss_EnumPrintProcessors(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1367,7 +1367,7 @@ static bool api_spoolss_GetPrintProcesso
+ 
+ 	r->out.result = _spoolss_GetPrintProcessorDirectory(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1447,7 +1447,7 @@ static bool api_spoolss_StartDocPrinter(
+ 
+ 	r->out.result = _spoolss_StartDocPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1520,7 +1520,7 @@ static bool api_spoolss_StartPagePrinter
+ 
+ 	r->out.result = _spoolss_StartPagePrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1600,7 +1600,7 @@ static bool api_spoolss_WritePrinter(str
+ 
+ 	r->out.result = _spoolss_WritePrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1673,7 +1673,7 @@ static bool api_spoolss_EndPagePrinter(s
+ 
+ 	r->out.result = _spoolss_EndPagePrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1746,7 +1746,7 @@ static bool api_spoolss_AbortPrinter(str
+ 
+ 	r->out.result = _spoolss_AbortPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1832,7 +1832,7 @@ static bool api_spoolss_ReadPrinter(stru
+ 
+ 	r->out.result = _spoolss_ReadPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1905,7 +1905,7 @@ static bool api_spoolss_EndDocPrinter(st
+ 
+ 	r->out.result = _spoolss_EndDocPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1986,7 +1986,7 @@ static bool api_spoolss_AddJob(struct pi
+ 
+ 	r->out.result = _spoolss_AddJob(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2059,7 +2059,7 @@ static bool api_spoolss_ScheduleJob(stru
+ 
+ 	r->out.result = _spoolss_ScheduleJob(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2151,7 +2151,7 @@ static bool api_spoolss_GetPrinterData(s
+ 
+ 	r->out.result = _spoolss_GetPrinterData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2224,7 +2224,7 @@ static bool api_spoolss_SetPrinterData(s
+ 
+ 	r->out.result = _spoolss_SetPrinterData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2297,7 +2297,7 @@ static bool api_spoolss_WaitForPrinterCh
+ 
+ 	r->out.result = _spoolss_WaitForPrinterChange(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2372,7 +2372,7 @@ static bool api_spoolss_ClosePrinter(str
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _spoolss_ClosePrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2445,7 +2445,7 @@ static bool api_spoolss_AddForm(struct p
+ 
+ 	r->out.result = _spoolss_AddForm(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2518,7 +2518,7 @@ static bool api_spoolss_DeleteForm(struc
+ 
+ 	r->out.result = _spoolss_DeleteForm(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2604,7 +2604,7 @@ static bool api_spoolss_GetForm(struct p
+ 
+ 	r->out.result = _spoolss_GetForm(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2677,7 +2677,7 @@ static bool api_spoolss_SetForm(struct p
+ 
+ 	r->out.result = _spoolss_SetForm(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2769,7 +2769,7 @@ static bool api_spoolss_EnumForms(struct
+ 
+ 	r->out.result = _spoolss_EnumForms(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2861,7 +2861,7 @@ static bool api_spoolss_EnumPorts(struct
+ 
+ 	r->out.result = _spoolss_EnumPorts(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2953,7 +2953,7 @@ static bool api_spoolss_EnumMonitors(str
+ 
+ 	r->out.result = _spoolss_EnumMonitors(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3026,7 +3026,7 @@ static bool api_spoolss_AddPort(struct p
+ 
+ 	r->out.result = _spoolss_AddPort(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3099,7 +3099,7 @@ static bool api_spoolss_ConfigurePort(st
+ 
+ 	r->out.result = _spoolss_ConfigurePort(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3172,7 +3172,7 @@ static bool api_spoolss_DeletePort(struc
+ 
+ 	r->out.result = _spoolss_DeletePort(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3252,7 +3252,7 @@ static bool api_spoolss_CreatePrinterIC(
+ 
+ 	r->out.result = _spoolss_CreatePrinterIC(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3325,7 +3325,7 @@ static bool api_spoolss_PlayGDIScriptOnP
+ 
+ 	r->out.result = _spoolss_PlayGDIScriptOnPrinterIC(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3400,7 +3400,7 @@ static bool api_spoolss_DeletePrinterIC(
+ 	r->out.gdi_handle = r->in.gdi_handle;
+ 	r->out.result = _spoolss_DeletePrinterIC(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3473,7 +3473,7 @@ static bool api_spoolss_AddPrinterConnec
+ 
+ 	r->out.result = _spoolss_AddPrinterConnection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3546,7 +3546,7 @@ static bool api_spoolss_DeletePrinterCon
+ 
+ 	r->out.result = _spoolss_DeletePrinterConnection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3619,7 +3619,7 @@ static bool api_spoolss_PrinterMessageBo
+ 
+ 	r->out.result = _spoolss_PrinterMessageBox(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3692,7 +3692,7 @@ static bool api_spoolss_AddMonitor(struc
+ 
+ 	r->out.result = _spoolss_AddMonitor(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3765,7 +3765,7 @@ static bool api_spoolss_DeleteMonitor(st
+ 
+ 	r->out.result = _spoolss_DeleteMonitor(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3838,7 +3838,7 @@ static bool api_spoolss_DeletePrintProce
+ 
+ 	r->out.result = _spoolss_DeletePrintProcessor(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3911,7 +3911,7 @@ static bool api_spoolss_AddPrintProvidor
+ 
+ 	r->out.result = _spoolss_AddPrintProvidor(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3984,7 +3984,7 @@ static bool api_spoolss_DeletePrintProvi
+ 
+ 	r->out.result = _spoolss_DeletePrintProvidor(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4076,7 +4076,7 @@ static bool api_spoolss_EnumPrintProcDat
+ 
+ 	r->out.result = _spoolss_EnumPrintProcDataTypes(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4149,7 +4149,7 @@ static bool api_spoolss_ResetPrinter(str
+ 
+ 	r->out.result = _spoolss_ResetPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4247,7 +4247,7 @@ static bool api_spoolss_GetPrinterDriver
+ 
+ 	r->out.result = _spoolss_GetPrinterDriver2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4320,7 +4320,7 @@ static bool api_spoolss_FindFirstPrinter
+ 
+ 	r->out.result = _spoolss_FindFirstPrinterChangeNotification(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4393,7 +4393,7 @@ static bool api_spoolss_FindNextPrinterC
+ 
+ 	r->out.result = _spoolss_FindNextPrinterChangeNotification(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4466,7 +4466,7 @@ static bool api_spoolss_FindClosePrinter
+ 
+ 	r->out.result = _spoolss_FindClosePrinterNotify(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4539,7 +4539,7 @@ static bool api_spoolss_RouterFindFirstP
+ 
+ 	r->out.result = _spoolss_RouterFindFirstPrinterChangeNotificationOld(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4619,7 +4619,7 @@ static bool api_spoolss_ReplyOpenPrinter
+ 
+ 	r->out.result = _spoolss_ReplyOpenPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4692,7 +4692,7 @@ static bool api_spoolss_RouterReplyPrint
+ 
+ 	r->out.result = _spoolss_RouterReplyPrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4767,7 +4767,7 @@ static bool api_spoolss_ReplyClosePrinte
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _spoolss_ReplyClosePrinter(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4840,7 +4840,7 @@ static bool api_spoolss_AddPortEx(struct
+ 
+ 	r->out.result = _spoolss_AddPortEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4913,7 +4913,7 @@ static bool api_spoolss_RouterFindFirstP
+ 
+ 	r->out.result = _spoolss_RouterFindFirstPrinterChangeNotification(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4986,7 +4986,7 @@ static bool api_spoolss_SpoolerInit(stru
+ 
+ 	r->out.result = _spoolss_SpoolerInit(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5059,7 +5059,7 @@ static bool api_spoolss_ResetPrinterEx(s
+ 
+ 	r->out.result = _spoolss_ResetPrinterEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5132,7 +5132,7 @@ static bool api_spoolss_RemoteFindFirstP
+ 
+ 	r->out.result = _spoolss_RemoteFindFirstPrinterChangeNotifyEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5212,7 +5212,7 @@ static bool api_spoolss_RouterReplyPrint
+ 
+ 	r->out.result = _spoolss_RouterReplyPrinterEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5292,7 +5292,7 @@ static bool api_spoolss_RouterRefreshPri
+ 
+ 	r->out.result = _spoolss_RouterRefreshPrinterChangeNotify(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5365,7 +5365,7 @@ static bool api_spoolss_44(struct pipes_
+ 
+ 	r->out.result = _spoolss_44(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5445,7 +5445,7 @@ static bool api_spoolss_OpenPrinterEx(st
+ 
+ 	r->out.result = _spoolss_OpenPrinterEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5525,7 +5525,7 @@ static bool api_spoolss_AddPrinterEx(str
+ 
+ 	r->out.result = _spoolss_AddPrinterEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5598,7 +5598,7 @@ static bool api_spoolss_SetPort(struct p
+ 
+ 	r->out.result = _spoolss_SetPort(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5702,7 +5702,7 @@ static bool api_spoolss_EnumPrinterData(
+ 
+ 	r->out.result = _spoolss_EnumPrinterData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5775,7 +5775,7 @@ static bool api_spoolss_DeletePrinterDat
+ 
+ 	r->out.result = _spoolss_DeletePrinterData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5848,7 +5848,7 @@ static bool api_spoolss_4a(struct pipes_
+ 
+ 	r->out.result = _spoolss_4a(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5921,7 +5921,7 @@ static bool api_spoolss_4b(struct pipes_
+ 
+ 	r->out.result = _spoolss_4b(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -5994,7 +5994,7 @@ static bool api_spoolss_4c(struct pipes_
+ 
+ 	r->out.result = _spoolss_4c(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6067,7 +6067,7 @@ static bool api_spoolss_SetPrinterDataEx
+ 
+ 	r->out.result = _spoolss_SetPrinterDataEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6159,7 +6159,7 @@ static bool api_spoolss_GetPrinterDataEx
+ 
+ 	r->out.result = _spoolss_GetPrinterDataEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6251,7 +6251,7 @@ static bool api_spoolss_EnumPrinterDataE
+ 
+ 	r->out.result = _spoolss_EnumPrinterDataEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6343,7 +6343,7 @@ static bool api_spoolss_EnumPrinterKey(s
+ 
+ 	r->out.result = _spoolss_EnumPrinterKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6416,7 +6416,7 @@ static bool api_spoolss_DeletePrinterDat
+ 
+ 	r->out.result = _spoolss_DeletePrinterDataEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6489,7 +6489,7 @@ static bool api_spoolss_DeletePrinterKey
+ 
+ 	r->out.result = _spoolss_DeletePrinterKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6562,7 +6562,7 @@ static bool api_spoolss_53(struct pipes_
+ 
+ 	r->out.result = _spoolss_53(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6635,7 +6635,7 @@ static bool api_spoolss_DeletePrinterDri
+ 
+ 	r->out.result = _spoolss_DeletePrinterDriverEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6708,7 +6708,7 @@ static bool api_spoolss_AddPerMachineCon
+ 
+ 	r->out.result = _spoolss_AddPerMachineConnection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6781,7 +6781,7 @@ static bool api_spoolss_DeletePerMachine
+ 
+ 	r->out.result = _spoolss_DeletePerMachineConnection(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6854,7 +6854,7 @@ static bool api_spoolss_EnumPerMachineCo
+ 
+ 	r->out.result = _spoolss_EnumPerMachineConnections(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -6941,7 +6941,7 @@ static bool api_spoolss_XcvData(struct p
+ 
+ 	r->out.result = _spoolss_XcvData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7014,7 +7014,7 @@ static bool api_spoolss_AddPrinterDriver
+ 
+ 	r->out.result = _spoolss_AddPrinterDriverEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7087,7 +7087,7 @@ static bool api_spoolss_5a(struct pipes_
+ 
+ 	r->out.result = _spoolss_5a(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7160,7 +7160,7 @@ static bool api_spoolss_5b(struct pipes_
+ 
+ 	r->out.result = _spoolss_5b(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7233,7 +7233,7 @@ static bool api_spoolss_5c(struct pipes_
+ 
+ 	r->out.result = _spoolss_5c(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7306,7 +7306,7 @@ static bool api_spoolss_5d(struct pipes_
+ 
+ 	r->out.result = _spoolss_5d(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7379,7 +7379,7 @@ static bool api_spoolss_5e(struct pipes_
+ 
+ 	r->out.result = _spoolss_5e(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7452,7 +7452,7 @@ static bool api_spoolss_5f(struct pipes_
+ 
+ 	r->out.result = _spoolss_5f(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7525,7 +7525,7 @@ static bool api_spoolss_60(struct pipes_
+ 
+ 	r->out.result = _spoolss_60(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7598,7 +7598,7 @@ static bool api_spoolss_61(struct pipes_
+ 
+ 	r->out.result = _spoolss_61(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7671,7 +7671,7 @@ static bool api_spoolss_62(struct pipes_
+ 
+ 	r->out.result = _spoolss_62(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7744,7 +7744,7 @@ static bool api_spoolss_63(struct pipes_
+ 
+ 	r->out.result = _spoolss_63(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7817,7 +7817,7 @@ static bool api_spoolss_64(struct pipes_
+ 
+ 	r->out.result = _spoolss_64(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7890,7 +7890,7 @@ static bool api_spoolss_65(struct pipes_
+ 
+ 	r->out.result = _spoolss_65(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -7970,7 +7970,7 @@ static bool api_spoolss_GetCorePrinterDr
+ 
+ 	r->out.result = _spoolss_GetCorePrinterDrivers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8043,7 +8043,7 @@ static bool api_spoolss_67(struct pipes_
+ 
+ 	r->out.result = _spoolss_67(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8124,7 +8124,7 @@ static bool api_spoolss_GetPrinterDriver
+ 
+ 	r->out.result = _spoolss_GetPrinterDriverPackagePath(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8197,7 +8197,7 @@ static bool api_spoolss_69(struct pipes_
+ 
+ 	r->out.result = _spoolss_69(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8270,7 +8270,7 @@ static bool api_spoolss_6a(struct pipes_
+ 
+ 	r->out.result = _spoolss_6a(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8343,7 +8343,7 @@ static bool api_spoolss_6b(struct pipes_
+ 
+ 	r->out.result = _spoolss_6b(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8416,7 +8416,7 @@ static bool api_spoolss_6c(struct pipes_
+ 
+ 	r->out.result = _spoolss_6c(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -8489,7 +8489,7 @@ static bool api_spoolss_6d(struct pipes_
+ 
+ 	r->out.result = _spoolss_6d(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_srvsvc.c
++++ b/source3/librpc/gen_ndr/srv_srvsvc.c
+@@ -53,7 +53,7 @@ static bool api_srvsvc_NetCharDevEnum(st
+ 
+ 	r->out.result = _srvsvc_NetCharDevEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -133,7 +133,7 @@ static bool api_srvsvc_NetCharDevGetInfo
+ 
+ 	r->out.result = _srvsvc_NetCharDevGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -206,7 +206,7 @@ static bool api_srvsvc_NetCharDevControl
+ 
+ 	r->out.result = _srvsvc_NetCharDevControl(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -288,7 +288,7 @@ static bool api_srvsvc_NetCharDevQEnum(s
+ 
+ 	r->out.result = _srvsvc_NetCharDevQEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -368,7 +368,7 @@ static bool api_srvsvc_NetCharDevQGetInf
+ 
+ 	r->out.result = _srvsvc_NetCharDevQGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -443,7 +443,7 @@ static bool api_srvsvc_NetCharDevQSetInf
+ 	r->out.parm_error = r->in.parm_error;
+ 	r->out.result = _srvsvc_NetCharDevQSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -516,7 +516,7 @@ static bool api_srvsvc_NetCharDevQPurge(
+ 
+ 	r->out.result = _srvsvc_NetCharDevQPurge(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -589,7 +589,7 @@ static bool api_srvsvc_NetCharDevQPurgeS
+ 
+ 	r->out.result = _srvsvc_NetCharDevQPurgeSelf(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -671,7 +671,7 @@ static bool api_srvsvc_NetConnEnum(struc
+ 
+ 	r->out.result = _srvsvc_NetConnEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -753,7 +753,7 @@ static bool api_srvsvc_NetFileEnum(struc
+ 
+ 	r->out.result = _srvsvc_NetFileEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -833,7 +833,7 @@ static bool api_srvsvc_NetFileGetInfo(st
+ 
+ 	r->out.result = _srvsvc_NetFileGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -906,7 +906,7 @@ static bool api_srvsvc_NetFileClose(stru
+ 
+ 	r->out.result = _srvsvc_NetFileClose(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -988,7 +988,7 @@ static bool api_srvsvc_NetSessEnum(struc
+ 
+ 	r->out.result = _srvsvc_NetSessEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1061,7 +1061,7 @@ static bool api_srvsvc_NetSessDel(struct
+ 
+ 	r->out.result = _srvsvc_NetSessDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1136,7 +1136,7 @@ static bool api_srvsvc_NetShareAdd(struc
+ 	r->out.parm_error = r->in.parm_error;
+ 	r->out.result = _srvsvc_NetShareAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1218,7 +1218,7 @@ static bool api_srvsvc_NetShareEnumAll(s
+ 
+ 	r->out.result = _srvsvc_NetShareEnumAll(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1298,7 +1298,7 @@ static bool api_srvsvc_NetShareGetInfo(s
+ 
+ 	r->out.result = _srvsvc_NetShareGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1373,7 +1373,7 @@ static bool api_srvsvc_NetShareSetInfo(s
+ 	r->out.parm_error = r->in.parm_error;
+ 	r->out.result = _srvsvc_NetShareSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1446,7 +1446,7 @@ static bool api_srvsvc_NetShareDel(struc
+ 
+ 	r->out.result = _srvsvc_NetShareDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1519,7 +1519,7 @@ static bool api_srvsvc_NetShareDelSticky
+ 
+ 	r->out.result = _srvsvc_NetShareDelSticky(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1599,7 +1599,7 @@ static bool api_srvsvc_NetShareCheck(str
+ 
+ 	r->out.result = _srvsvc_NetShareCheck(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1679,7 +1679,7 @@ static bool api_srvsvc_NetSrvGetInfo(str
+ 
+ 	r->out.result = _srvsvc_NetSrvGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1754,7 +1754,7 @@ static bool api_srvsvc_NetSrvSetInfo(str
+ 	r->out.parm_error = r->in.parm_error;
+ 	r->out.result = _srvsvc_NetSrvSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1836,7 +1836,7 @@ static bool api_srvsvc_NetDiskEnum(struc
+ 
+ 	r->out.result = _srvsvc_NetDiskEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1916,7 +1916,7 @@ static bool api_srvsvc_NetServerStatisti
+ 
+ 	r->out.result = _srvsvc_NetServerStatisticsGet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1989,7 +1989,7 @@ static bool api_srvsvc_NetTransportAdd(s
+ 
+ 	r->out.result = _srvsvc_NetTransportAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2071,7 +2071,7 @@ static bool api_srvsvc_NetTransportEnum(
+ 
+ 	r->out.result = _srvsvc_NetTransportEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2144,7 +2144,7 @@ static bool api_srvsvc_NetTransportDel(s
+ 
+ 	r->out.result = _srvsvc_NetTransportDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2224,7 +2224,7 @@ static bool api_srvsvc_NetRemoteTOD(stru
+ 
+ 	r->out.result = _srvsvc_NetRemoteTOD(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2297,7 +2297,7 @@ static bool api_srvsvc_NetSetServiceBits
+ 
+ 	r->out.result = _srvsvc_NetSetServiceBits(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2377,7 +2377,7 @@ static bool api_srvsvc_NetPathType(struc
+ 
+ 	r->out.result = _srvsvc_NetPathType(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2458,7 +2458,7 @@ static bool api_srvsvc_NetPathCanonicali
+ 
+ 	r->out.result = _srvsvc_NetPathCanonicalize(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2531,7 +2531,7 @@ static bool api_srvsvc_NetPathCompare(st
+ 
+ 	r->out.result = _srvsvc_NetPathCompare(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2604,7 +2604,7 @@ static bool api_srvsvc_NetNameValidate(s
+ 
+ 	r->out.result = _srvsvc_NetNameValidate(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2677,7 +2677,7 @@ static bool api_srvsvc_NETRPRNAMECANONIC
+ 
+ 	r->out.result = _srvsvc_NETRPRNAMECANONICALIZE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2750,7 +2750,7 @@ static bool api_srvsvc_NetPRNameCompare(
+ 
+ 	r->out.result = _srvsvc_NetPRNameCompare(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2832,7 +2832,7 @@ static bool api_srvsvc_NetShareEnum(stru
+ 
+ 	r->out.result = _srvsvc_NetShareEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2912,7 +2912,7 @@ static bool api_srvsvc_NetShareDelStart(
+ 
+ 	r->out.result = _srvsvc_NetShareDelStart(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2987,7 +2987,7 @@ static bool api_srvsvc_NetShareDelCommit
+ 	r->out.hnd = r->in.hnd;
+ 	r->out.result = _srvsvc_NetShareDelCommit(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3067,7 +3067,7 @@ static bool api_srvsvc_NetGetFileSecurit
+ 
+ 	r->out.result = _srvsvc_NetGetFileSecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3140,7 +3140,7 @@ static bool api_srvsvc_NetSetFileSecurit
+ 
+ 	r->out.result = _srvsvc_NetSetFileSecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3213,7 +3213,7 @@ static bool api_srvsvc_NetServerTranspor
+ 
+ 	r->out.result = _srvsvc_NetServerTransportAddEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3286,7 +3286,7 @@ static bool api_srvsvc_NetServerSetServi
+ 
+ 	r->out.result = _srvsvc_NetServerSetServiceBitsEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3359,7 +3359,7 @@ static bool api_srvsvc_NETRDFSGETVERSION
+ 
+ 	r->out.result = _srvsvc_NETRDFSGETVERSION(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3432,7 +3432,7 @@ static bool api_srvsvc_NETRDFSCREATELOCA
+ 
+ 	r->out.result = _srvsvc_NETRDFSCREATELOCALPARTITION(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3505,7 +3505,7 @@ static bool api_srvsvc_NETRDFSDELETELOCA
+ 
+ 	r->out.result = _srvsvc_NETRDFSDELETELOCALPARTITION(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3578,7 +3578,7 @@ static bool api_srvsvc_NETRDFSSETLOCALVO
+ 
+ 	r->out.result = _srvsvc_NETRDFSSETLOCALVOLUMESTATE(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3651,7 +3651,7 @@ static bool api_srvsvc_NETRDFSSETSERVERI
+ 
+ 	r->out.result = _srvsvc_NETRDFSSETSERVERINFO(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3724,7 +3724,7 @@ static bool api_srvsvc_NETRDFSCREATEEXIT
+ 
+ 	r->out.result = _srvsvc_NETRDFSCREATEEXITPOINT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3797,7 +3797,7 @@ static bool api_srvsvc_NETRDFSDELETEEXIT
+ 
+ 	r->out.result = _srvsvc_NETRDFSDELETEEXITPOINT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3870,7 +3870,7 @@ static bool api_srvsvc_NETRDFSMODIFYPREF
+ 
+ 	r->out.result = _srvsvc_NETRDFSMODIFYPREFIX(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3943,7 +3943,7 @@ static bool api_srvsvc_NETRDFSFIXLOCALVO
+ 
+ 	r->out.result = _srvsvc_NETRDFSFIXLOCALVOLUME(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4016,7 +4016,7 @@ static bool api_srvsvc_NETRDFSMANAGERREP
+ 
+ 	r->out.result = _srvsvc_NETRDFSMANAGERREPORTSITEINFO(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4089,7 +4089,7 @@ static bool api_srvsvc_NETRSERVERTRANSPO
+ 
+ 	r->out.result = _srvsvc_NETRSERVERTRANSPORTDELEX(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_svcctl.c
++++ b/source3/librpc/gen_ndr/srv_svcctl.c
+@@ -46,7 +46,7 @@ static bool api_svcctl_CloseServiceHandl
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _svcctl_CloseServiceHandle(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -126,7 +126,7 @@ static bool api_svcctl_ControlService(st
+ 
+ 	r->out.result = _svcctl_ControlService(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -199,7 +199,7 @@ static bool api_svcctl_DeleteService(str
+ 
+ 	r->out.result = _svcctl_DeleteService(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -279,7 +279,7 @@ static bool api_svcctl_LockServiceDataba
+ 
+ 	r->out.result = _svcctl_LockServiceDatabase(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -365,7 +365,7 @@ static bool api_svcctl_QueryServiceObjec
+ 
+ 	r->out.result = _svcctl_QueryServiceObjectSecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -438,7 +438,7 @@ static bool api_svcctl_SetServiceObjectS
+ 
+ 	r->out.result = _svcctl_SetServiceObjectSecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -518,7 +518,7 @@ static bool api_svcctl_QueryServiceStatu
+ 
+ 	r->out.result = _svcctl_QueryServiceStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -591,7 +591,7 @@ static bool api_svcctl_SetServiceStatus(
+ 
+ 	r->out.result = _svcctl_SetServiceStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -666,7 +666,7 @@ static bool api_svcctl_UnlockServiceData
+ 	r->out.lock = r->in.lock;
+ 	r->out.result = _svcctl_UnlockServiceDatabase(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -739,7 +739,7 @@ static bool api_svcctl_NotifyBootConfigS
+ 
+ 	r->out.result = _svcctl_NotifyBootConfigStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -812,7 +812,7 @@ static bool api_svcctl_SCSetServiceBitsW
+ 
+ 	r->out.result = _svcctl_SCSetServiceBitsW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -892,7 +892,7 @@ static bool api_svcctl_ChangeServiceConf
+ 
+ 	r->out.result = _svcctl_ChangeServiceConfigW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -973,7 +973,7 @@ static bool api_svcctl_CreateServiceW(st
+ 
+ 	r->out.result = _svcctl_CreateServiceW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1065,7 +1065,7 @@ static bool api_svcctl_EnumDependentServ
+ 
+ 	r->out.result = _svcctl_EnumDependentServicesW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1158,7 +1158,7 @@ static bool api_svcctl_EnumServicesStatu
+ 
+ 	r->out.result = _svcctl_EnumServicesStatusW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1238,7 +1238,7 @@ static bool api_svcctl_OpenSCManagerW(st
+ 
+ 	r->out.result = _svcctl_OpenSCManagerW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1318,7 +1318,7 @@ static bool api_svcctl_OpenServiceW(stru
+ 
+ 	r->out.result = _svcctl_OpenServiceW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1404,7 +1404,7 @@ static bool api_svcctl_QueryServiceConfi
+ 
+ 	r->out.result = _svcctl_QueryServiceConfigW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1490,7 +1490,7 @@ static bool api_svcctl_QueryServiceLockS
+ 
+ 	r->out.result = _svcctl_QueryServiceLockStatusW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1563,7 +1563,7 @@ static bool api_svcctl_StartServiceW(str
+ 
+ 	r->out.result = _svcctl_StartServiceW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1644,7 +1644,7 @@ static bool api_svcctl_GetServiceDisplay
+ 
+ 	r->out.result = _svcctl_GetServiceDisplayNameW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1725,7 +1725,7 @@ static bool api_svcctl_GetServiceKeyName
+ 
+ 	r->out.result = _svcctl_GetServiceKeyNameW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1798,7 +1798,7 @@ static bool api_svcctl_SCSetServiceBitsA
+ 
+ 	r->out.result = _svcctl_SCSetServiceBitsA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1878,7 +1878,7 @@ static bool api_svcctl_ChangeServiceConf
+ 
+ 	r->out.result = _svcctl_ChangeServiceConfigA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1958,7 +1958,7 @@ static bool api_svcctl_CreateServiceA(st
+ 
+ 	r->out.result = _svcctl_CreateServiceA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2050,7 +2050,7 @@ static bool api_svcctl_EnumDependentServ
+ 
+ 	r->out.result = _svcctl_EnumDependentServicesA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2143,7 +2143,7 @@ static bool api_svcctl_EnumServicesStatu
+ 
+ 	r->out.result = _svcctl_EnumServicesStatusA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2223,7 +2223,7 @@ static bool api_svcctl_OpenSCManagerA(st
+ 
+ 	r->out.result = _svcctl_OpenSCManagerA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2296,7 +2296,7 @@ static bool api_svcctl_OpenServiceA(stru
+ 
+ 	r->out.result = _svcctl_OpenServiceA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2382,7 +2382,7 @@ static bool api_svcctl_QueryServiceConfi
+ 
+ 	r->out.result = _svcctl_QueryServiceConfigA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2468,7 +2468,7 @@ static bool api_svcctl_QueryServiceLockS
+ 
+ 	r->out.result = _svcctl_QueryServiceLockStatusA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2541,7 +2541,7 @@ static bool api_svcctl_StartServiceA(str
+ 
+ 	r->out.result = _svcctl_StartServiceA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2622,7 +2622,7 @@ static bool api_svcctl_GetServiceDisplay
+ 
+ 	r->out.result = _svcctl_GetServiceDisplayNameA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2703,7 +2703,7 @@ static bool api_svcctl_GetServiceKeyName
+ 
+ 	r->out.result = _svcctl_GetServiceKeyNameA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2776,7 +2776,7 @@ static bool api_svcctl_GetCurrentGroupeS
+ 
+ 	r->out.result = _svcctl_GetCurrentGroupeStateW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2849,7 +2849,7 @@ static bool api_svcctl_EnumServiceGroupW
+ 
+ 	r->out.result = _svcctl_EnumServiceGroupW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2922,7 +2922,7 @@ static bool api_svcctl_ChangeServiceConf
+ 
+ 	r->out.result = _svcctl_ChangeServiceConfig2A(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2995,7 +2995,7 @@ static bool api_svcctl_ChangeServiceConf
+ 
+ 	r->out.result = _svcctl_ChangeServiceConfig2W(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3081,7 +3081,7 @@ static bool api_svcctl_QueryServiceConfi
+ 
+ 	r->out.result = _svcctl_QueryServiceConfig2A(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3167,7 +3167,7 @@ static bool api_svcctl_QueryServiceConfi
+ 
+ 	r->out.result = _svcctl_QueryServiceConfig2W(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3253,7 +3253,7 @@ static bool api_svcctl_QueryServiceStatu
+ 
+ 	r->out.result = _svcctl_QueryServiceStatusEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3352,7 +3352,7 @@ static bool api_EnumServicesStatusExA(st
+ 
+ 	r->out.result = _EnumServicesStatusExA(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3445,7 +3445,7 @@ static bool api_EnumServicesStatusExW(st
+ 
+ 	r->out.result = _EnumServicesStatusExW(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3518,7 +3518,7 @@ static bool api_svcctl_SCSendTSMessage(s
+ 
+ 	r->out.result = _svcctl_SCSendTSMessage(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_trkwks.c
++++ b/source3/librpc/gen_ndr/srv_trkwks.c
+@@ -44,7 +44,7 @@ static bool api_trkwks_Unknown0(struct p
+ 
+ 	r->out.result = _trkwks_Unknown0(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_unixinfo.c
++++ b/source3/librpc/gen_ndr/srv_unixinfo.c
+@@ -51,7 +51,7 @@ static bool api_unixinfo_SidToUid(struct
+ 
+ 	r->out.result = _unixinfo_SidToUid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -131,7 +131,7 @@ static bool api_unixinfo_UidToSid(struct
+ 
+ 	r->out.result = _unixinfo_UidToSid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -211,7 +211,7 @@ static bool api_unixinfo_SidToGid(struct
+ 
+ 	r->out.result = _unixinfo_SidToGid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -291,7 +291,7 @@ static bool api_unixinfo_GidToSid(struct
+ 
+ 	r->out.result = _unixinfo_GidToSid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -372,7 +372,7 @@ static bool api_unixinfo_GetPWUid(struct
+ 
+ 	r->out.result = _unixinfo_GetPWUid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_w32time.c
++++ b/source3/librpc/gen_ndr/srv_w32time.c
+@@ -44,7 +44,7 @@ static bool api_w32time_SyncTime(struct
+ 
+ 	r->out.result = _w32time_SyncTime(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_w32time_GetNetLogonServi
+ 
+ 	r->out.result = _w32time_GetNetLogonServiceBits(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_w32time_QueryProviderSta
+ 
+ 	r->out.result = _w32time_QueryProviderStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_wbint.c
++++ b/source3/librpc/gen_ndr/srv_wbint.c
+@@ -51,7 +51,7 @@ static bool api_wbint_Ping(struct pipes_
+ 
+ 	_wbint_Ping(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -143,7 +143,7 @@ static bool api_wbint_LookupSid(struct p
+ 
+ 	r->out.result = _wbint_LookupSid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -229,7 +229,7 @@ static bool api_wbint_LookupSids(struct
+ 
+ 	r->out.result = _wbint_LookupSids(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -315,7 +315,7 @@ static bool api_wbint_LookupName(struct
+ 
+ 	r->out.result = _wbint_LookupName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -395,7 +395,7 @@ static bool api_wbint_Sid2Uid(struct pip
+ 
+ 	r->out.result = _wbint_Sid2Uid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -475,7 +475,7 @@ static bool api_wbint_Sid2Gid(struct pip
+ 
+ 	r->out.result = _wbint_Sid2Gid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -550,7 +550,7 @@ static bool api_wbint_Sids2UnixIDs(struc
+ 	r->out.ids = r->in.ids;
+ 	r->out.result = _wbint_Sids2UnixIDs(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -630,7 +630,7 @@ static bool api_wbint_Uid2Sid(struct pip
+ 
+ 	r->out.result = _wbint_Uid2Sid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -710,7 +710,7 @@ static bool api_wbint_Gid2Sid(struct pip
+ 
+ 	r->out.result = _wbint_Gid2Sid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -790,7 +790,7 @@ static bool api_wbint_AllocateUid(struct
+ 
+ 	r->out.result = _wbint_AllocateUid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -870,7 +870,7 @@ static bool api_wbint_AllocateGid(struct
+ 
+ 	r->out.result = _wbint_AllocateGid(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -950,7 +950,7 @@ static bool api_wbint_QueryUser(struct p
+ 
+ 	r->out.result = _wbint_QueryUser(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1030,7 +1030,7 @@ static bool api_wbint_LookupUserAliases(
+ 
+ 	r->out.result = _wbint_LookupUserAliases(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1110,7 +1110,7 @@ static bool api_wbint_LookupUserGroups(s
+ 
+ 	r->out.result = _wbint_LookupUserGroups(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1190,7 +1190,7 @@ static bool api_wbint_QuerySequenceNumbe
+ 
+ 	r->out.result = _wbint_QuerySequenceNumber(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1270,7 +1270,7 @@ static bool api_wbint_LookupGroupMembers
+ 
+ 	r->out.result = _wbint_LookupGroupMembers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1350,7 +1350,7 @@ static bool api_wbint_QueryUserList(stru
+ 
+ 	r->out.result = _wbint_QueryUserList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1430,7 +1430,7 @@ static bool api_wbint_QueryGroupList(str
+ 
+ 	r->out.result = _wbint_QueryGroupList(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1510,7 +1510,7 @@ static bool api_wbint_DsGetDcName(struct
+ 
+ 	r->out.result = _wbint_DsGetDcName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1596,7 +1596,7 @@ static bool api_wbint_LookupRids(struct
+ 
+ 	r->out.result = _wbint_LookupRids(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1669,7 +1669,7 @@ static bool api_wbint_CheckMachineAccoun
+ 
+ 	r->out.result = _wbint_CheckMachineAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1742,7 +1742,7 @@ static bool api_wbint_ChangeMachineAccou
+ 
+ 	r->out.result = _wbint_ChangeMachineAccount(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1815,7 +1815,7 @@ static bool api_wbint_PingDc(struct pipe
+ 
+ 	r->out.result = _wbint_PingDc(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_winreg.c
++++ b/source3/librpc/gen_ndr/srv_winreg.c
+@@ -51,7 +51,7 @@ static bool api_winreg_OpenHKCR(struct p
+ 
+ 	r->out.result = _winreg_OpenHKCR(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -131,7 +131,7 @@ static bool api_winreg_OpenHKCU(struct p
+ 
+ 	r->out.result = _winreg_OpenHKCU(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -211,7 +211,7 @@ static bool api_winreg_OpenHKLM(struct p
+ 
+ 	r->out.result = _winreg_OpenHKLM(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -291,7 +291,7 @@ static bool api_winreg_OpenHKPD(struct p
+ 
+ 	r->out.result = _winreg_OpenHKPD(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -371,7 +371,7 @@ static bool api_winreg_OpenHKU(struct pi
+ 
+ 	r->out.result = _winreg_OpenHKU(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -446,7 +446,7 @@ static bool api_winreg_CloseKey(struct p
+ 	r->out.handle = r->in.handle;
+ 	r->out.result = _winreg_CloseKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -527,7 +527,7 @@ static bool api_winreg_CreateKey(struct
+ 
+ 	r->out.result = _winreg_CreateKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -600,7 +600,7 @@ static bool api_winreg_DeleteKey(struct
+ 
+ 	r->out.result = _winreg_DeleteKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -673,7 +673,7 @@ static bool api_winreg_DeleteValue(struc
+ 
+ 	r->out.result = _winreg_DeleteValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -750,7 +750,7 @@ static bool api_winreg_EnumKey(struct pi
+ 	r->out.last_changed_time = r->in.last_changed_time;
+ 	r->out.result = _winreg_EnumKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -829,7 +829,7 @@ static bool api_winreg_EnumValue(struct
+ 	r->out.length = r->in.length;
+ 	r->out.result = _winreg_EnumValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -902,7 +902,7 @@ static bool api_winreg_FlushKey(struct p
+ 
+ 	r->out.result = _winreg_FlushKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -977,7 +977,7 @@ static bool api_winreg_GetKeySecurity(st
+ 	r->out.sd = r->in.sd;
+ 	r->out.result = _winreg_GetKeySecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1050,7 +1050,7 @@ static bool api_winreg_LoadKey(struct pi
+ 
+ 	r->out.result = _winreg_LoadKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1123,7 +1123,7 @@ static bool api_winreg_NotifyChangeKeyVa
+ 
+ 	r->out.result = _winreg_NotifyChangeKeyValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1203,7 +1203,7 @@ static bool api_winreg_OpenKey(struct pi
+ 
+ 	r->out.result = _winreg_OpenKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1326,7 +1326,7 @@ static bool api_winreg_QueryInfoKey(stru
+ 
+ 	r->out.result = _winreg_QueryInfoKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1404,7 +1404,7 @@ static bool api_winreg_QueryValue(struct
+ 	r->out.data_length = r->in.data_length;
+ 	r->out.result = _winreg_QueryValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1477,7 +1477,7 @@ static bool api_winreg_ReplaceKey(struct
+ 
+ 	r->out.result = _winreg_ReplaceKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1550,7 +1550,7 @@ static bool api_winreg_RestoreKey(struct
+ 
+ 	r->out.result = _winreg_RestoreKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1623,7 +1623,7 @@ static bool api_winreg_SaveKey(struct pi
+ 
+ 	r->out.result = _winreg_SaveKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1696,7 +1696,7 @@ static bool api_winreg_SetKeySecurity(st
+ 
+ 	r->out.result = _winreg_SetKeySecurity(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1769,7 +1769,7 @@ static bool api_winreg_SetValue(struct p
+ 
+ 	r->out.result = _winreg_SetValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1842,7 +1842,7 @@ static bool api_winreg_UnLoadKey(struct
+ 
+ 	r->out.result = _winreg_UnLoadKey(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1915,7 +1915,7 @@ static bool api_winreg_InitiateSystemShu
+ 
+ 	r->out.result = _winreg_InitiateSystemShutdown(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1988,7 +1988,7 @@ static bool api_winreg_AbortSystemShutdo
+ 
+ 	r->out.result = _winreg_AbortSystemShutdown(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2068,7 +2068,7 @@ static bool api_winreg_GetVersion(struct
+ 
+ 	r->out.result = _winreg_GetVersion(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2148,7 +2148,7 @@ static bool api_winreg_OpenHKCC(struct p
+ 
+ 	r->out.result = _winreg_OpenHKCC(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2228,7 +2228,7 @@ static bool api_winreg_OpenHKDD(struct p
+ 
+ 	r->out.result = _winreg_OpenHKDD(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2310,7 +2310,7 @@ static bool api_winreg_QueryMultipleValu
+ 
+ 	r->out.result = _winreg_QueryMultipleValues(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2383,7 +2383,7 @@ static bool api_winreg_InitiateSystemShu
+ 
+ 	r->out.result = _winreg_InitiateSystemShutdownEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2456,7 +2456,7 @@ static bool api_winreg_SaveKeyEx(struct
+ 
+ 	r->out.result = _winreg_SaveKeyEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2536,7 +2536,7 @@ static bool api_winreg_OpenHKPT(struct p
+ 
+ 	r->out.result = _winreg_OpenHKPT(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2616,7 +2616,7 @@ static bool api_winreg_OpenHKPN(struct p
+ 
+ 	r->out.result = _winreg_OpenHKPN(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2703,7 +2703,7 @@ static bool api_winreg_QueryMultipleValu
+ 
+ 	r->out.result = _winreg_QueryMultipleValues2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2776,7 +2776,7 @@ static bool api_winreg_DeleteKeyEx(struc
+ 
+ 	r->out.result = _winreg_DeleteKeyEx(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_wkssvc.c
++++ b/source3/librpc/gen_ndr/srv_wkssvc.c
+@@ -51,7 +51,7 @@ static bool api_wkssvc_NetWkstaGetInfo(s
+ 
+ 	r->out.result = _wkssvc_NetWkstaGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -126,7 +126,7 @@ static bool api_wkssvc_NetWkstaSetInfo(s
+ 	r->out.parm_error = r->in.parm_error;
+ 	r->out.result = _wkssvc_NetWkstaSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -208,7 +208,7 @@ static bool api_wkssvc_NetWkstaEnumUsers
+ 
+ 	r->out.result = _wkssvc_NetWkstaEnumUsers(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -288,7 +288,7 @@ static bool api_wkssvc_NetrWkstaUserGetI
+ 
+ 	r->out.result = _wkssvc_NetrWkstaUserGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -363,7 +363,7 @@ static bool api_wkssvc_NetrWkstaUserSetI
+ 	r->out.parm_err = r->in.parm_err;
+ 	r->out.result = _wkssvc_NetrWkstaUserSetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -445,7 +445,7 @@ static bool api_wkssvc_NetWkstaTransport
+ 
+ 	r->out.result = _wkssvc_NetWkstaTransportEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -520,7 +520,7 @@ static bool api_wkssvc_NetrWkstaTranspor
+ 	r->out.parm_err = r->in.parm_err;
+ 	r->out.result = _wkssvc_NetrWkstaTransportAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -593,7 +593,7 @@ static bool api_wkssvc_NetrWkstaTranspor
+ 
+ 	r->out.result = _wkssvc_NetrWkstaTransportDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -668,7 +668,7 @@ static bool api_wkssvc_NetrUseAdd(struct
+ 	r->out.parm_err = r->in.parm_err;
+ 	r->out.result = _wkssvc_NetrUseAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -748,7 +748,7 @@ static bool api_wkssvc_NetrUseGetInfo(st
+ 
+ 	r->out.result = _wkssvc_NetrUseGetInfo(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -821,7 +821,7 @@ static bool api_wkssvc_NetrUseDel(struct
+ 
+ 	r->out.result = _wkssvc_NetrUseDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -903,7 +903,7 @@ static bool api_wkssvc_NetrUseEnum(struc
+ 
+ 	r->out.result = _wkssvc_NetrUseEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -976,7 +976,7 @@ static bool api_wkssvc_NetrMessageBuffer
+ 
+ 	r->out.result = _wkssvc_NetrMessageBufferSend(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1056,7 +1056,7 @@ static bool api_wkssvc_NetrWorkstationSt
+ 
+ 	r->out.result = _wkssvc_NetrWorkstationStatisticsGet(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1129,7 +1129,7 @@ static bool api_wkssvc_NetrLogonDomainNa
+ 
+ 	r->out.result = _wkssvc_NetrLogonDomainNameAdd(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1202,7 +1202,7 @@ static bool api_wkssvc_NetrLogonDomainNa
+ 
+ 	r->out.result = _wkssvc_NetrLogonDomainNameDel(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1275,7 +1275,7 @@ static bool api_wkssvc_NetrJoinDomain(st
+ 
+ 	r->out.result = _wkssvc_NetrJoinDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1348,7 +1348,7 @@ static bool api_wkssvc_NetrUnjoinDomain(
+ 
+ 	r->out.result = _wkssvc_NetrUnjoinDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1421,7 +1421,7 @@ static bool api_wkssvc_NetrRenameMachine
+ 
+ 	r->out.result = _wkssvc_NetrRenameMachineInDomain(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1494,7 +1494,7 @@ static bool api_wkssvc_NetrValidateName(
+ 
+ 	r->out.result = _wkssvc_NetrValidateName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1575,7 +1575,7 @@ static bool api_wkssvc_NetrGetJoinInform
+ 
+ 	r->out.result = _wkssvc_NetrGetJoinInformation(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1656,7 +1656,7 @@ static bool api_wkssvc_NetrGetJoinableOu
+ 
+ 	r->out.result = _wkssvc_NetrGetJoinableOus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1729,7 +1729,7 @@ static bool api_wkssvc_NetrJoinDomain2(s
+ 
+ 	r->out.result = _wkssvc_NetrJoinDomain2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1802,7 +1802,7 @@ static bool api_wkssvc_NetrUnjoinDomain2
+ 
+ 	r->out.result = _wkssvc_NetrUnjoinDomain2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1875,7 +1875,7 @@ static bool api_wkssvc_NetrRenameMachine
+ 
+ 	r->out.result = _wkssvc_NetrRenameMachineInDomain2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1948,7 +1948,7 @@ static bool api_wkssvc_NetrValidateName2
+ 
+ 	r->out.result = _wkssvc_NetrValidateName2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2029,7 +2029,7 @@ static bool api_wkssvc_NetrGetJoinableOu
+ 
+ 	r->out.result = _wkssvc_NetrGetJoinableOus2(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2102,7 +2102,7 @@ static bool api_wkssvc_NetrAddAlternateC
+ 
+ 	r->out.result = _wkssvc_NetrAddAlternateComputerName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2175,7 +2175,7 @@ static bool api_wkssvc_NetrRemoveAlterna
+ 
+ 	r->out.result = _wkssvc_NetrRemoveAlternateComputerName(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2248,7 +2248,7 @@ static bool api_wkssvc_NetrSetPrimaryCom
+ 
+ 	r->out.result = _wkssvc_NetrSetPrimaryComputername(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2328,7 +2328,7 @@ static bool api_wkssvc_NetrEnumerateComp
+ 
+ 	r->out.result = _wkssvc_NetrEnumerateComputerNames(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_wmi.c
++++ b/source3/librpc/gen_ndr/srv_wmi.c
+@@ -51,7 +51,7 @@ static bool api_Delete(struct pipes_stru
+ 
+ 	r->out.result = _Delete(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -155,7 +155,7 @@ static bool api_OpenNamespace(struct pip
+ 
+ 	r->out.result = _OpenNamespace(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -235,7 +235,7 @@ static bool api_CancelAsyncCall(struct p
+ 
+ 	r->out.result = _CancelAsyncCall(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -321,7 +321,7 @@ static bool api_QueryObjectSink(struct p
+ 
+ 	r->out.result = _QueryObjectSink(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -403,7 +403,7 @@ static bool api_GetObject(struct pipes_s
+ 
+ 	r->out.result = _GetObject(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -483,7 +483,7 @@ static bool api_GetObjectAsync(struct pi
+ 
+ 	r->out.result = _GetObjectAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -564,7 +564,7 @@ static bool api_PutClass(struct pipes_st
+ 
+ 	r->out.result = _PutClass(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -644,7 +644,7 @@ static bool api_PutClassAsync(struct pip
+ 
+ 	r->out.result = _PutClassAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -725,7 +725,7 @@ static bool api_DeleteClass(struct pipes
+ 
+ 	r->out.result = _DeleteClass(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -805,7 +805,7 @@ static bool api_DeleteClassAsync(struct
+ 
+ 	r->out.result = _DeleteClassAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -891,7 +891,7 @@ static bool api_CreateClassEnum(struct p
+ 
+ 	r->out.result = _CreateClassEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -971,7 +971,7 @@ static bool api_CreateClassEnumAsync(str
+ 
+ 	r->out.result = _CreateClassEnumAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1052,7 +1052,7 @@ static bool api_PutInstance(struct pipes
+ 
+ 	r->out.result = _PutInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1132,7 +1132,7 @@ static bool api_PutInstanceAsync(struct
+ 
+ 	r->out.result = _PutInstanceAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1213,7 +1213,7 @@ static bool api_DeleteInstance(struct pi
+ 
+ 	r->out.result = _DeleteInstance(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1293,7 +1293,7 @@ static bool api_DeleteInstanceAsync(stru
+ 
+ 	r->out.result = _DeleteInstanceAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1379,7 +1379,7 @@ static bool api_CreateInstanceEnum(struc
+ 
+ 	r->out.result = _CreateInstanceEnum(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1459,7 +1459,7 @@ static bool api_CreateInstanceEnumAsync(
+ 
+ 	r->out.result = _CreateInstanceEnumAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1545,7 +1545,7 @@ static bool api_ExecQuery(struct pipes_s
+ 
+ 	r->out.result = _ExecQuery(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1625,7 +1625,7 @@ static bool api_ExecQueryAsync(struct pi
+ 
+ 	r->out.result = _ExecQueryAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1711,7 +1711,7 @@ static bool api_ExecNotificationQuery(st
+ 
+ 	r->out.result = _ExecNotificationQuery(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1791,7 +1791,7 @@ static bool api_ExecNotificationQueryAsy
+ 
+ 	r->out.result = _ExecNotificationQueryAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1873,7 +1873,7 @@ static bool api_ExecMethod(struct pipes_
+ 
+ 	r->out.result = _ExecMethod(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1953,7 +1953,7 @@ static bool api_ExecMethodAsync(struct p
+ 
+ 	r->out.result = _ExecMethodAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2077,7 +2077,7 @@ static bool api_Reset(struct pipes_struc
+ 
+ 	r->out.result = _Reset(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2169,7 +2169,7 @@ static bool api_IEnumWbemClassObject_Nex
+ 
+ 	r->out.result = _IEnumWbemClassObject_Next(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2249,7 +2249,7 @@ static bool api_NextAsync(struct pipes_s
+ 
+ 	r->out.result = _NextAsync(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2335,7 +2335,7 @@ static bool api_IEnumWbemClassObject_Clo
+ 
+ 	r->out.result = _IEnumWbemClassObject_Clone(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2415,7 +2415,7 @@ static bool api_Skip(struct pipes_struct
+ 
+ 	r->out.result = _Skip(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2527,7 +2527,7 @@ static bool api_Clone(struct pipes_struc
+ 
+ 	r->out.result = _Clone(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2607,7 +2607,7 @@ static bool api_GetNames(struct pipes_st
+ 
+ 	r->out.result = _GetNames(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2687,7 +2687,7 @@ static bool api_BeginEnumeration(struct
+ 
+ 	r->out.result = _BeginEnumeration(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2767,7 +2767,7 @@ static bool api_Next(struct pipes_struct
+ 
+ 	r->out.result = _Next(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2847,7 +2847,7 @@ static bool api_EndEnumeration(struct pi
+ 
+ 	r->out.result = _EndEnumeration(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -2927,7 +2927,7 @@ static bool api_SetValue(struct pipes_st
+ 
+ 	r->out.result = _SetValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3007,7 +3007,7 @@ static bool api_GetValue(struct pipes_st
+ 
+ 	r->out.result = _GetValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3087,7 +3087,7 @@ static bool api_DeleteValue(struct pipes
+ 
+ 	r->out.result = _DeleteValue(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3167,7 +3167,7 @@ static bool api_DeleteAll(struct pipes_s
+ 
+ 	r->out.result = _DeleteAll(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3283,7 +3283,7 @@ static bool api_EstablishPosition(struct
+ 
+ 	r->out.result = _EstablishPosition(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3369,7 +3369,7 @@ static bool api_RequestChallenge(struct
+ 
+ 	r->out.result = _RequestChallenge(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3455,7 +3455,7 @@ static bool api_WBEMLogin(struct pipes_s
+ 
+ 	r->out.result = _WBEMLogin(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3541,7 +3541,7 @@ static bool api_NTLMLogin(struct pipes_s
+ 
+ 	r->out.result = _NTLMLogin(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3664,7 +3664,7 @@ static bool api_IWbemWCOSmartEnum_Next(s
+ 
+ 	r->out.result = _IWbemWCOSmartEnum_Next(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3772,7 +3772,7 @@ static bool api_Fetch(struct pipes_struc
+ 
+ 	r->out.result = _Fetch(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3858,7 +3858,7 @@ static bool api_Test(struct pipes_struct
+ 
+ 	r->out.result = _Test(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -3967,7 +3967,7 @@ static bool api_GetResultObject(struct p
+ 
+ 	r->out.result = _GetResultObject(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4053,7 +4053,7 @@ static bool api_GetResultString(struct p
+ 
+ 	r->out.result = _GetResultString(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4139,7 +4139,7 @@ static bool api_GetResultServices(struct
+ 
+ 	r->out.result = _GetResultServices(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4225,7 +4225,7 @@ static bool api_GetCallStatus(struct pip
+ 
+ 	r->out.result = _GetCallStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4330,7 +4330,7 @@ static bool api_SetStatus(struct pipes_s
+ 
+ 	r->out.result = _SetStatus(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -4410,7 +4410,7 @@ static bool api_Indicate(struct pipes_st
+ 
+ 	r->out.result = _Indicate(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_wzcsvc.c
++++ b/source3/librpc/gen_ndr/srv_wzcsvc.c
+@@ -44,7 +44,7 @@ static bool api_wzcsvc_EnumInterfaces(st
+ 
+ 	_wzcsvc_EnumInterfaces(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -117,7 +117,7 @@ static bool api_wzcsvc_QueryInterface(st
+ 
+ 	_wzcsvc_QueryInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -190,7 +190,7 @@ static bool api_wzcsvc_SetInterface(stru
+ 
+ 	_wzcsvc_SetInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -263,7 +263,7 @@ static bool api_wzcsvc_RefreshInterface(
+ 
+ 	_wzcsvc_RefreshInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -336,7 +336,7 @@ static bool api_wzcsvc_QueryContext(stru
+ 
+ 	_wzcsvc_QueryContext(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -409,7 +409,7 @@ static bool api_wzcsvc_SetContext(struct
+ 
+ 	_wzcsvc_SetContext(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -482,7 +482,7 @@ static bool api_wzcsvc_EapolUIResponse(s
+ 
+ 	_wzcsvc_EapolUIResponse(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -555,7 +555,7 @@ static bool api_wzcsvc_EapolGetCustomAut
+ 
+ 	_wzcsvc_EapolGetCustomAuthData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -628,7 +628,7 @@ static bool api_wzcsvc_EapolSetCustomAut
+ 
+ 	_wzcsvc_EapolSetCustomAuthData(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -701,7 +701,7 @@ static bool api_wzcsvc_EapolGetInterface
+ 
+ 	_wzcsvc_EapolGetInterfaceParams(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -774,7 +774,7 @@ static bool api_wzcsvc_EapolSetInterface
+ 
+ 	_wzcsvc_EapolSetInterfaceParams(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -847,7 +847,7 @@ static bool api_wzcsvc_EapolReAuthentica
+ 
+ 	_wzcsvc_EapolReAuthenticateInterface(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -920,7 +920,7 @@ static bool api_wzcsvc_EapolQueryInterfa
+ 
+ 	_wzcsvc_EapolQueryInterfaceState(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -993,7 +993,7 @@ static bool api_wzcsvc_OpenWZCDbLogSessi
+ 
+ 	_wzcsvc_OpenWZCDbLogSession(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1066,7 +1066,7 @@ static bool api_wzcsvc_CloseWZCDbLogSess
+ 
+ 	_wzcsvc_CloseWZCDbLogSession(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1139,7 +1139,7 @@ static bool api_wzcsvc_EnumWZCDbLogRecor
+ 
+ 	_wzcsvc_EnumWZCDbLogRecords(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1212,7 +1212,7 @@ static bool api_wzcsvc_FlushWZCdbLog(str
+ 
+ 	_wzcsvc_FlushWZCdbLog(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+@@ -1285,7 +1285,7 @@ static bool api_wzcsvc_GetWZCDbLogRecord
+ 
+ 	_wzcsvc_GetWZCDbLogRecord(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
+--- a/source3/librpc/gen_ndr/srv_xattr.c
++++ b/source3/librpc/gen_ndr/srv_xattr.c
+@@ -44,7 +44,7 @@ static bool api_xattr_parse_DOSATTRIB(st
+ 
+ 	_xattr_parse_DOSATTRIB(p, r);
+ 
+-	if (p->rng_fault_state) {
++	if (p->fault_state) {
+ 		talloc_free(r);
+ 		/* Return true here, srv_pipe_hnd.c will take care */
+ 		return true;
diff --git a/package/network/services/samba36/patches/022-CVE-2015-5370-v3-6.patch b/package/network/services/samba36/patches/022-CVE-2015-5370-v3-6.patch
new file mode 100644
index 0000000000..36656ab882
--- /dev/null
+++ b/package/network/services/samba36/patches/022-CVE-2015-5370-v3-6.patch
@@ -0,0 +1,1791 @@
+From 8716bb5e03cc4f10e2d4edc704d8defe7e8045f1 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Thu, 16 Jul 2015 22:46:05 +0200
+Subject: [PATCH 01/40] CVE-2015-5370: dcerpc.idl: add
+ DCERPC_{NCACN_PAYLOAD,FRAG}_MAX_SIZE defines
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Günther Deschner <gd@samba.org>
+---
+ librpc/idl/dcerpc.idl | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/librpc/idl/dcerpc.idl
++++ b/librpc/idl/dcerpc.idl
+@@ -475,9 +475,11 @@ interface dcerpc
+ 	const uint8 DCERPC_PFC_OFFSET      =  3;
+ 	const uint8 DCERPC_DREP_OFFSET     =  4;
+ 	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
++	const uint32 DCERPC_FRAG_MAX_SIZE  = 5840;
+ 	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
+ 	const uint8 DCERPC_CALL_ID_OFFSET  = 12;
+ 	const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16;
++	const uint32 DCERPC_NCACN_PAYLOAD_MAX_SIZE = 0x400000; /* 4 MByte */
+ 
+ 	/* little-endian flag */
+ 	const uint8 DCERPC_DREP_LE  = 0x10;
+--- a/librpc/rpc/dcerpc_util.c
++++ b/librpc/rpc/dcerpc_util.c
+@@ -92,31 +92,49 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB
+ *
+ * @return		- A NTSTATUS error code.
+ */
+-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
++NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
+ 				  TALLOC_CTX *mem_ctx,
+-				  DATA_BLOB *pkt_trailer,
++				  const DATA_BLOB *pkt_trailer,
+ 				  struct dcerpc_auth *auth,
+-				  uint32_t *auth_length,
++				  uint32_t *_auth_length,
+ 				  bool auth_data_only)
+ {
+ 	struct ndr_pull *ndr;
+ 	enum ndr_err_code ndr_err;
+-	uint32_t data_and_pad;
++	uint16_t data_and_pad;
++	uint16_t auth_length;
++	uint32_t tmp_length;
+ 
+-	data_and_pad = pkt_trailer->length
+-			- (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
++	ZERO_STRUCTP(auth);
++	if (_auth_length != NULL) {
++		*_auth_length = 0;
++	}
++
++	/* Paranoia checks for auth_length. The caller should check this... */
++	if (pkt->auth_length == 0) {
++		return NT_STATUS_INTERNAL_ERROR;
++	}
++
++	/* Paranoia checks for auth_length. The caller should check this... */
++	if (pkt->auth_length > pkt->frag_length) {
++		return NT_STATUS_INTERNAL_ERROR;
++	}
++	tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
++	tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
++	tmp_length += pkt->auth_length;
++	if (tmp_length > pkt->frag_length) {
++		return NT_STATUS_INTERNAL_ERROR;
++	}
++	if (pkt_trailer->length > UINT16_MAX) {
++		return NT_STATUS_INTERNAL_ERROR;
++	}
+ 
+-	/* paranoia check for pad size. This would be caught anyway by
+-	   the ndr_pull_advance() a few lines down, but it scared
+-	   Jeremy enough for him to call me, so we might as well check
+-	   it now, just to prevent someone posting a bogus YouTube
+-	   video in the future.
+-	*/
+-	if (data_and_pad > pkt_trailer->length) {
+-		return NT_STATUS_INFO_LENGTH_MISMATCH;
++	auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
++	if (pkt_trailer->length < auth_length) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
+ 	}
+ 
+-	*auth_length = pkt_trailer->length - data_and_pad;
++	data_and_pad = pkt_trailer->length - auth_length;
+ 
+ 	ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
+ 	if (!ndr) {
+@@ -136,14 +154,28 @@ NTSTATUS dcerpc_pull_auth_trailer(struct
+ 	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
+ 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ 		talloc_free(ndr);
++		ZERO_STRUCTP(auth);
+ 		return ndr_map_error2ntstatus(ndr_err);
+ 	}
+ 
++	if (data_and_pad < auth->auth_pad_length) {
++		DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
++			  "Calculated %u  got %u\n",
++			  (unsigned)data_and_pad,
++			  (unsigned)auth->auth_pad_length));
++		talloc_free(ndr);
++		ZERO_STRUCTP(auth);
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
+ 	if (auth_data_only && data_and_pad != auth->auth_pad_length) {
+-		DEBUG(1, (__location__ ": WARNING: pad length mismatch. "
++		DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
+ 			  "Calculated %u  got %u\n",
+ 			  (unsigned)data_and_pad,
+ 			  (unsigned)auth->auth_pad_length));
++		talloc_free(ndr);
++		ZERO_STRUCTP(auth);
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
+ 	}
+ 
+ 	DEBUG(6,(__location__ ": auth_pad_length %u\n",
+@@ -152,6 +184,83 @@ NTSTATUS dcerpc_pull_auth_trailer(struct
+ 	talloc_steal(mem_ctx, auth->credentials.data);
+ 	talloc_free(ndr);
+ 
++	if (_auth_length != NULL) {
++		*_auth_length = auth_length;
++	}
++
++	return NT_STATUS_OK;
++}
++
++/**
++* @brief	Verify the fields in ncacn_packet header.
++*
++* @param pkt		- The ncacn_packet strcuture
++* @param ptype		- The expected PDU type
++* @param max_auth_info	- The maximum size of a possible auth trailer
++* @param required_flags	- The required flags for the pdu.
++* @param optional_flags	- The possible optional flags for the pdu.
++*
++* @return		- A NTSTATUS error code.
++*/
++NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
++					   enum dcerpc_pkt_type ptype,
++					   size_t max_auth_info,
++					   uint8_t required_flags,
++					   uint8_t optional_flags)
++{
++	if (pkt->rpc_vers != 5) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
++	if (pkt->rpc_vers_minor != 0) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
++	if (pkt->auth_length > pkt->frag_length) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
++	if (pkt->ptype != ptype) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
++	if (max_auth_info > UINT16_MAX) {
++		return NT_STATUS_INTERNAL_ERROR;
++	}
++
++	if (pkt->auth_length > 0) {
++		size_t max_auth_length;
++
++		if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
++			return NT_STATUS_RPC_PROTOCOL_ERROR;
++		}
++		max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
++
++		if (pkt->auth_length > max_auth_length) {
++			return NT_STATUS_RPC_PROTOCOL_ERROR;
++		}
++	}
++
++	if ((pkt->pfc_flags & required_flags) != required_flags) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++	if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
++	if (pkt->drep[0] & ~DCERPC_DREP_LE) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++	if (pkt->drep[1] != 0) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++	if (pkt->drep[2] != 0) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++	if (pkt->drep[3] != 0) {
++		return NT_STATUS_RPC_PROTOCOL_ERROR;
++	}
++
+ 	return NT_STATUS_OK;
+ }
+ 
+--- a/librpc/rpc/rpc_common.h
++++ b/librpc/rpc/rpc_common.h
+@@ -158,12 +158,17 @@ uint8_t dcerpc_get_endian_flag(DATA_BLOB
+ *
+ * @return		- A NTSTATUS error code.
+ */
+-NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
++NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
+ 				  TALLOC_CTX *mem_ctx,
+-				  DATA_BLOB *pkt_trailer,
++				  const DATA_BLOB *pkt_trailer,
+ 				  struct dcerpc_auth *auth,
+ 				  uint32_t *auth_length,
+ 				  bool auth_data_only);
++NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
++					   enum dcerpc_pkt_type ptype,
++					   size_t max_auth_info,
++					   uint8_t required_flags,
++					   uint8_t optional_flags);
+ struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+ 						 struct tevent_context *ev,
+ 						 struct tstream_context *stream);
+--- a/source3/librpc/rpc/dcerpc_helpers.c
++++ b/source3/librpc/rpc/dcerpc_helpers.c
+@@ -210,47 +210,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_
+ }
+ 
+ /**
+-* @brief Decodes a dcerpc_auth blob
+-*
+-* @param mem_ctx	The memory context on which to allocate the packet
+-*			elements
+-* @param blob		The blob of data to decode
+-* @param r		An empty dcerpc_auth structure, must not be NULL
+-*
+-* @return a NTSTATUS error code
+-*/
+-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
+-				 const DATA_BLOB *blob,
+-				 struct dcerpc_auth *r,
+-				 bool bigendian)
+-{
+-	enum ndr_err_code ndr_err;
+-	struct ndr_pull *ndr;
+-
+-	ndr = ndr_pull_init_blob(blob, mem_ctx);
+-	if (!ndr) {
+-		return NT_STATUS_NO_MEMORY;
+-	}
+-	if (bigendian) {
+-		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+-	}
+-
+-	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
+-
+-	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+-		talloc_free(ndr);
+-		return ndr_map_error2ntstatus(ndr_err);
+-	}
+-	talloc_free(ndr);
+-
+-	if (DEBUGLEVEL >= 10) {
+-		NDR_PRINT_DEBUG(dcerpc_auth, r);
+-	}
+-
+-	return NT_STATUS_OK;
+-}
+-
+-/**
+ * @brief Calculate how much data we can in a packet, including calculating
+ *	 auth token and pad lengths.
+ *
+@@ -782,7 +741,7 @@ NTSTATUS dcerpc_add_auth_footer(struct p
+ 					 auth->auth_type,
+ 					 auth->auth_level,
+ 					 pad_len,
+-					 1 /* context id. */,
++					 auth->auth_context_id,
+ 					 &auth_blob,
+ 					 &auth_info);
+ 	if (!NT_STATUS_IS_OK(status)) {
+@@ -844,19 +803,18 @@ NTSTATUS dcerpc_add_auth_footer(struct p
+ *
+ * @param auth		The auth data for the connection
+ * @param pkt		The actual ncacn_packet
+-* @param pkt_trailer	The stub_and_verifier part of the packet
++* @param pkt_trailer [in][out]	The stub_and_verifier part of the packet,
++* 			the auth_trailer and padding will be removed.
+ * @param header_size	The header size
+ * @param raw_pkt	The whole raw packet data blob
+-* @param pad_len	[out] The padding length used in the packet
+ *
+ * @return A NTSTATUS error code
+ */
+ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
+ 			   struct ncacn_packet *pkt,
+ 			   DATA_BLOB *pkt_trailer,
+-			   size_t header_size,
+-			   DATA_BLOB *raw_pkt,
+-			   size_t *pad_len)
++			   uint8_t header_size,
++			   DATA_BLOB *raw_pkt)
+ {
+ 	struct schannel_state *schannel_auth;
+ 	struct auth_ntlmssp_state *ntlmssp_ctx;
+@@ -868,6 +826,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
+ 	DATA_BLOB full_pkt;
+ 	DATA_BLOB data;
+ 
++	/*
++	 * These check should be done in the caller.
++	 */
++	SMB_ASSERT(raw_pkt->length == pkt->frag_length);
++	SMB_ASSERT(header_size <= pkt->frag_length);
++	SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
++	SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
++
+ 	switch (auth->auth_level) {
+ 	case DCERPC_AUTH_LEVEL_PRIVACY:
+ 		DEBUG(10, ("Requested Privacy.\n"));
+@@ -881,7 +847,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
+ 		if (pkt->auth_length != 0) {
+ 			break;
+ 		}
+-		*pad_len = 0;
+ 		return NT_STATUS_OK;
+ 
+ 	case DCERPC_AUTH_LEVEL_NONE:
+@@ -890,7 +855,6 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
+ 				  "authenticated connection!\n"));
+ 			return NT_STATUS_INVALID_PARAMETER;
+ 		}
+-		*pad_len = 0;
+ 		return NT_STATUS_OK;
+ 
+ 	default:
+@@ -899,16 +863,8 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
+ 		return NT_STATUS_INVALID_PARAMETER;
+ 	}
+ 
+-	/* Paranioa checks for auth_length. */
+-	if (pkt->auth_length > pkt->frag_length) {
+-		return NT_STATUS_INFO_LENGTH_MISMATCH;
+-	}
+-	if (((unsigned int)pkt->auth_length
+-	     + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
+-	    ((unsigned int)pkt->auth_length
+-	     + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
+-		/* Integer wrap attempt. */
+-		return NT_STATUS_INFO_LENGTH_MISMATCH;
++	if (pkt->auth_length == 0) {
++		return NT_STATUS_INVALID_PARAMETER;
+ 	}
+ 
+ 	status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
+@@ -917,10 +873,23 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
+ 		return status;
+ 	}
+ 
++	if (auth_info.auth_type != auth->auth_type) {
++		return NT_STATUS_INVALID_PARAMETER;
++	}
++
++	if (auth_info.auth_level != auth->auth_level) {
++		return NT_STATUS_INVALID_PARAMETER;
++	}
++
++	if (auth_info.auth_context_id != auth->auth_context_id) {
++		return NT_STATUS_INVALID_PARAMETER;
++	}
++
++	pkt_trailer->length -= auth_length;
+ 	data = data_blob_const(raw_pkt->data + header_size,
+-				pkt_trailer->length - auth_length);
+-	full_pkt = data_blob_const(raw_pkt->data,
+-				raw_pkt->length - auth_info.credentials.length);
++			       pkt_trailer->length);
++	full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
++	full_pkt.length -= auth_info.credentials.length;
+ 
+ 	switch (auth->auth_type) {
+ 	case DCERPC_AUTH_TYPE_NONE:
+@@ -996,10 +965,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_a
+ 	 * pkt_trailer actually has a copy of the raw data, and they
+ 	 * are still both used in later calls */
+ 	if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
++		if (pkt_trailer->length != data.length) {
++			return NT_STATUS_INVALID_PARAMETER;
++		}
+ 		memcpy(pkt_trailer->data, data.data, data.length);
+ 	}
+ 
+-	*pad_len = auth_info.auth_pad_length;
++	pkt_trailer->length -= auth_info.auth_pad_length;
+ 	data_blob_free(&auth_info.credentials);
+ 	return NT_STATUS_OK;
+ }
+--- a/source3/rpc_client/cli_pipe.c
++++ b/source3/rpc_client/cli_pipe.c
+@@ -404,9 +404,9 @@ static NTSTATUS cli_pipe_validate_curren
+ 						DATA_BLOB *rdata,
+ 						DATA_BLOB *reply_pdu)
+ {
+-	struct dcerpc_response *r;
++	const struct dcerpc_response *r = NULL;
++	DATA_BLOB tmp_stub = data_blob_null;
+ 	NTSTATUS ret = NT_STATUS_OK;
+-	size_t pad_len = 0;
+ 
+ 	/*
+ 	 * Point the return values at the real data including the RPC
+@@ -414,50 +414,128 @@ static NTSTATUS cli_pipe_validate_curren
+ 	 */
+ 	*rdata = *pdu;
+ 
++	if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
++	    !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
++		/*
++		 * TODO: do we still need this hack which was introduced
++		 * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
++		 *
++		 * I don't even know what AS/U might be...
++		 */
++		DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
++			  "fragment first/last ON.\n"));
++		pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
++	}
++
+ 	/* Ensure we have the correct type. */
+ 	switch (pkt->ptype) {
+-	case DCERPC_PKT_ALTER_RESP:
++	case DCERPC_PKT_BIND_NAK:
++		DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
++			  rpccli_pipe_txt(talloc_tos(), cli)));
++
++		ret = dcerpc_verify_ncacn_packet_header(pkt,
++						DCERPC_PKT_BIND_NAK,
++						0, /* max_auth_info */
++						DCERPC_PFC_FLAG_FIRST |
++						DCERPC_PFC_FLAG_LAST,
++						0); /* optional flags */
++		if (!NT_STATUS_IS_OK(ret)) {
++			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
++				  "RPC packet type - %u, expected %u: %s\n",
++				  rpccli_pipe_txt(talloc_tos(), cli),
++				  pkt->ptype, expected_pkt_type,
++				  nt_errstr(ret)));
++			NDR_PRINT_DEBUG(ncacn_packet, pkt);
++			return ret;
++		}
++
++		/* Use this for now... */
++		return NT_STATUS_NETWORK_ACCESS_DENIED;
++
+ 	case DCERPC_PKT_BIND_ACK:
++		ret = dcerpc_verify_ncacn_packet_header(pkt,
++					expected_pkt_type,
++					pkt->u.bind_ack.auth_info.length,
++					DCERPC_PFC_FLAG_FIRST |
++					DCERPC_PFC_FLAG_LAST,
++					DCERPC_PFC_FLAG_CONC_MPX |
++					DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
++		if (!NT_STATUS_IS_OK(ret)) {
++			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
++				  "RPC packet type - %u, expected %u: %s\n",
++				  rpccli_pipe_txt(talloc_tos(), cli),
++				  pkt->ptype, expected_pkt_type,
++				  nt_errstr(ret)));
++			NDR_PRINT_DEBUG(ncacn_packet, pkt);
++			return ret;
++		}
+ 
+-		/* Client code never receives this kind of packets */
+ 		break;
+ 
++	case DCERPC_PKT_ALTER_RESP:
++		ret = dcerpc_verify_ncacn_packet_header(pkt,
++					expected_pkt_type,
++					pkt->u.alter_resp.auth_info.length,
++					DCERPC_PFC_FLAG_FIRST |
++					DCERPC_PFC_FLAG_LAST,
++					DCERPC_PFC_FLAG_CONC_MPX |
++					DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
++		if (!NT_STATUS_IS_OK(ret)) {
++			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
++				  "RPC packet type - %u, expected %u: %s\n",
++				  rpccli_pipe_txt(talloc_tos(), cli),
++				  pkt->ptype, expected_pkt_type,
++				  nt_errstr(ret)));
++			NDR_PRINT_DEBUG(ncacn_packet, pkt);
++			return ret;
++		}
++
++		break;
+ 
+ 	case DCERPC_PKT_RESPONSE:
+ 
+ 		r = &pkt->u.response;
+ 
++		ret = dcerpc_verify_ncacn_packet_header(pkt,
++						expected_pkt_type,
++						r->stub_and_verifier.length,
++						0, /* required_flags */
++						DCERPC_PFC_FLAG_FIRST |
++						DCERPC_PFC_FLAG_LAST);
++		if (!NT_STATUS_IS_OK(ret)) {
++			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
++				  "RPC packet type - %u, expected %u: %s\n",
++				  rpccli_pipe_txt(talloc_tos(), cli),
++				  pkt->ptype, expected_pkt_type,
++				  nt_errstr(ret)));
++			NDR_PRINT_DEBUG(ncacn_packet, pkt);
++			return ret;
++		}
++
++		tmp_stub.data = r->stub_and_verifier.data;
++		tmp_stub.length = r->stub_and_verifier.length;
++
+ 		/* Here's where we deal with incoming sign/seal. */
+ 		ret = dcerpc_check_auth(cli->auth, pkt,
+-					&r->stub_and_verifier,
++					&tmp_stub,
+ 					DCERPC_RESPONSE_LENGTH,
+-					pdu, &pad_len);
++					pdu);
+ 		if (!NT_STATUS_IS_OK(ret)) {
++			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
++				  "RPC packet type - %u, expected %u: %s\n",
++				  rpccli_pipe_txt(talloc_tos(), cli),
++				  pkt->ptype, expected_pkt_type,
++				  nt_errstr(ret)));
++			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+-		if (pkt->frag_length < DCERPC_RESPONSE_LENGTH + pad_len) {
+-			return NT_STATUS_BUFFER_TOO_SMALL;
+-		}
+-
+ 		/* Point the return values at the NDR data. */
+-		rdata->data = r->stub_and_verifier.data;
++		*rdata = tmp_stub;
+ 
+-		if (pkt->auth_length) {
+-			/* We've already done integer wrap tests in
+-			 * dcerpc_check_auth(). */
+-			rdata->length = r->stub_and_verifier.length
+-					 - pad_len
+-					 - DCERPC_AUTH_TRAILER_LENGTH
+-					 - pkt->auth_length;
+-		} else {
+-			rdata->length = r->stub_and_verifier.length;
+-		}
+-
+-		DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
++		DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
+ 			   (long unsigned int)pdu->length,
+-			   (long unsigned int)rdata->length,
+-			   (unsigned int)pad_len));
++			   (long unsigned int)rdata->length));
+ 
+ 		/*
+ 		 * If this is the first reply, and the allocation hint is
+@@ -478,14 +556,24 @@ static NTSTATUS cli_pipe_validate_curren
+ 
+ 		break;
+ 
+-	case DCERPC_PKT_BIND_NAK:
+-		DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
+-			  rpccli_pipe_txt(talloc_tos(), cli)));
+-		/* Use this for now... */
+-		return NT_STATUS_NETWORK_ACCESS_DENIED;
+-
+ 	case DCERPC_PKT_FAULT:
+ 
++		ret = dcerpc_verify_ncacn_packet_header(pkt,
++						DCERPC_PKT_FAULT,
++						0, /* max_auth_info */
++						DCERPC_PFC_FLAG_FIRST |
++						DCERPC_PFC_FLAG_LAST,
++						DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
++		if (!NT_STATUS_IS_OK(ret)) {
++			DEBUG(1, (__location__ ": Connection to %s got an unexpected "
++				  "RPC packet type - %u, expected %u: %s\n",
++				  rpccli_pipe_txt(talloc_tos(), cli),
++				  pkt->ptype, expected_pkt_type,
++				  nt_errstr(ret)));
++			NDR_PRINT_DEBUG(ncacn_packet, pkt);
++			return ret;
++		}
++
+ 		DEBUG(1, (__location__ ": RPC fault code %s received "
+ 			  "from %s!\n",
+ 			  dcerpc_errstr(talloc_tos(),
+@@ -502,13 +590,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 		return NT_STATUS_RPC_PROTOCOL_ERROR;
+ 	}
+ 
+-	if (pkt->ptype != expected_pkt_type) {
+-		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
+-			  "RPC packet type - %u, not %u\n",
+-			  rpccli_pipe_txt(talloc_tos(), cli),
+-			  pkt->ptype, expected_pkt_type));
+-		return NT_STATUS_RPC_PROTOCOL_ERROR;
+-	}
+ 
+ 	if (pkt->call_id != call_id) {
+ 		DEBUG(3, (__location__ ": Connection to %s got an unexpected "
+@@ -518,17 +599,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 		return NT_STATUS_RPC_PROTOCOL_ERROR;
+ 	}
+ 
+-	/* Do this just before return - we don't want to modify any rpc header
+-	   data before now as we may have needed to do cryptographic actions on
+-	   it before. */
+-
+-	if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
+-	    !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+-		DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
+-			  "fragment first/last ON.\n"));
+-		pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+-	}
+-
+ 	return NT_STATUS_OK;
+ }
+ 
+@@ -883,6 +953,12 @@ static void rpc_api_pipe_got_pdu(struct
+ 
+ 	state->pkt = talloc(state, struct ncacn_packet);
+ 	if (!state->pkt) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
+ 		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ 		return;
+ 	}
+@@ -892,18 +968,16 @@ static void rpc_api_pipe_got_pdu(struct
+ 					  state->pkt,
+ 					  !state->endianess);
+ 	if (!NT_STATUS_IS_OK(status)) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
+ 		tevent_req_nterror(req, status);
+ 		return;
+ 	}
+ 
+-	if (state->incoming_frag.length != state->pkt->frag_length) {
+-		DEBUG(5, ("Incorrect pdu length %u, expected %u\n",
+-			  (unsigned int)state->incoming_frag.length,
+-			  (unsigned int)state->pkt->frag_length));
+-		tevent_req_nterror(req,  NT_STATUS_INVALID_PARAMETER);
+-		return;
+-	}
+-
+ 	status = cli_pipe_validate_current_pdu(state,
+ 						state->cli, state->pkt,
+ 						&state->incoming_frag,
+@@ -917,6 +991,28 @@ static void rpc_api_pipe_got_pdu(struct
+ 		  (unsigned)state->reply_pdu_offset,
+ 		  nt_errstr(status)));
+ 
++	if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
++	} else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
++	} else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
++	}
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		tevent_req_nterror(req, status);
+ 		return;
+@@ -941,7 +1037,24 @@ static void rpc_api_pipe_got_pdu(struct
+ 			 "%s\n",
+ 			 state->endianess?"little":"big",
+ 			 state->pkt->drep[0]?"little":"big"));
+-		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++		return;
++	}
++
++	if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
++		tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ 		return;
+ 	}
+ 
+@@ -949,6 +1062,12 @@ static void rpc_api_pipe_got_pdu(struct
+ 	if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
+ 		if (!data_blob_realloc(NULL, &state->reply_pdu,
+ 				state->reply_pdu_offset + rdata.length)) {
++			/*
++			 * TODO: do a real async disconnect ...
++			 *
++			 * For now do it sync...
++			 */
++			TALLOC_FREE(state->cli->transport);
+ 			tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ 			return;
+ 		}
+@@ -978,6 +1097,14 @@ static void rpc_api_pipe_got_pdu(struct
+ 	subreq = get_complete_frag_send(state, state->ev, state->cli,
+ 					state->call_id,
+ 					&state->incoming_frag);
++	if (subreq == NULL) {
++		/*
++		 * TODO: do a real async disconnect ...
++		 *
++		 * For now do it sync...
++		 */
++		TALLOC_FREE(state->cli->transport);
++	}
+ 	if (tevent_req_nomem(subreq, req)) {
+ 		return;
+ 	}
+@@ -1247,7 +1374,7 @@ static NTSTATUS create_rpc_bind_req(TALL
+ 						auth->auth_type,
+ 						auth->auth_level,
+ 						0, /* auth_pad_length */
+-						1, /* auth_context_id */
++						auth->auth_context_id,
+ 						&auth_token,
+ 						&auth_info);
+ 		if (!NT_STATUS_IS_OK(ret)) {
+@@ -1749,9 +1876,8 @@ static bool check_bind_response(const st
+ 
+ static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
+ 				struct rpc_pipe_client *cli,
+-				uint32 rpc_call_id,
+-				enum dcerpc_AuthType auth_type,
+-				enum dcerpc_AuthLevel auth_level,
++				struct pipe_auth_data *auth,
++				uint32_t rpc_call_id,
+ 				DATA_BLOB *pauth_blob,
+ 				DATA_BLOB *rpc_out)
+ {
+@@ -1761,10 +1887,10 @@ static NTSTATUS create_rpc_bind_auth3(TA
+ 	u.auth3._pad = 0;
+ 
+ 	status = dcerpc_push_dcerpc_auth(mem_ctx,
+-					 auth_type,
+-					 auth_level,
++					 auth->auth_type,
++					 auth->auth_level,
+ 					 0, /* auth_pad_length */
+-					 1, /* auth_context_id */
++					 auth->auth_context_id,
+ 					 pauth_blob,
+ 					 &u.auth3.auth_info);
+ 	if (!NT_STATUS_IS_OK(status)) {
+@@ -1794,9 +1920,8 @@ static NTSTATUS create_rpc_bind_auth3(TA
+  ********************************************************************/
+ 
+ static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
+-					enum dcerpc_AuthType auth_type,
+-					enum dcerpc_AuthLevel auth_level,
+-					uint32 rpc_call_id,
++					struct pipe_auth_data *auth,
++					uint32_t rpc_call_id,
+ 					const struct ndr_syntax_id *abstract,
+ 					const struct ndr_syntax_id *transfer,
+ 					const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
+@@ -1806,10 +1931,10 @@ static NTSTATUS create_rpc_alter_context
+ 	NTSTATUS status;
+ 
+ 	status = dcerpc_push_dcerpc_auth(mem_ctx,
+-					 auth_type,
+-					 auth_level,
++					 auth->auth_type,
++					 auth->auth_level,
+ 					 0, /* auth_pad_length */
+-					 1, /* auth_context_id */
++					 auth->auth_context_id,
+ 					 pauth_blob,
+ 					 &auth_info);
+ 	if (!NT_STATUS_IS_OK(status)) {
+@@ -1957,30 +2082,45 @@ static void rpc_pipe_bind_step_one_done(
+ 		rpc_pipe_bind_step_two_trigger(req);
+ 		return;
+ 
+-	case DCERPC_AUTH_TYPE_NTLMSSP:
+-	case DCERPC_AUTH_TYPE_SPNEGO:
+-	case DCERPC_AUTH_TYPE_KRB5:
+-		/* Paranoid lenght checks */
+-		if (pkt->frag_length < DCERPC_AUTH_TRAILER_LENGTH
+-						+ pkt->auth_length) {
+-			tevent_req_nterror(req,
+-					NT_STATUS_INFO_LENGTH_MISMATCH);
++	default:
++		if (pkt->auth_length == 0) {
++			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ 			return;
+ 		}
+ 		/* get auth credentials */
+-		status = dcerpc_pull_dcerpc_auth(talloc_tos(),
+-						 &pkt->u.bind_ack.auth_info,
+-						 &auth, false);
++		status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
++						  &pkt->u.bind_ack.auth_info,
++						  &auth, NULL, true);
+ 		if (!NT_STATUS_IS_OK(status)) {
+ 			DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
+ 				  nt_errstr(status)));
+ 			tevent_req_nterror(req, status);
+ 			return;
+ 		}
+-		break;
+ 
+-	default:
+-		goto err_out;
++		if (auth.auth_type != pauth->auth_type) {
++			DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n",
++				  auth.auth_type, pauth->auth_type));
++			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++			return;
++		}
++
++		if (auth.auth_level != pauth->auth_level) {
++			DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n",
++				  auth.auth_level, pauth->auth_level));
++			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++			return;
++		}
++
++		if (auth.auth_context_id != pauth->auth_context_id) {
++			DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n",
++				  (unsigned)auth.auth_context_id,
++				  (unsigned)pauth->auth_context_id));
++			tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
++			return;
++		}
++
++		break;
+ 	}
+ 
+ 	/*
+@@ -2226,9 +2366,7 @@ static NTSTATUS rpc_bind_next_send(struc
+ 	/* Now prepare the alter context pdu. */
+ 	data_blob_free(&state->rpc_out);
+ 
+-	status = create_rpc_alter_context(state,
+-					  auth->auth_type,
+-					  auth->auth_level,
++	status = create_rpc_alter_context(state, auth,
+ 					  state->rpc_call_id,
+ 					  &state->cli->abstract_syntax,
+ 					  &state->cli->transfer_syntax,
+@@ -2261,10 +2399,8 @@ static NTSTATUS rpc_bind_finish_send(str
+ 	/* Now prepare the auth3 context pdu. */
+ 	data_blob_free(&state->rpc_out);
+ 
+-	status = create_rpc_bind_auth3(state, state->cli,
++	status = create_rpc_bind_auth3(state, state->cli, auth,
+ 					state->rpc_call_id,
+-					auth->auth_type,
+-					auth->auth_level,
+ 					auth_token,
+ 					&state->rpc_out);
+ 	if (!NT_STATUS_IS_OK(status)) {
+@@ -2498,8 +2634,9 @@ static struct tevent_req *rpccli_bh_disc
+ 	/*
+ 	 * TODO: do a real async disconnect ...
+ 	 *
+-	 * For now the caller needs to free rpc_cli
++	 * For now we do it sync...
+ 	 */
++	TALLOC_FREE(hs->rpc_cli->transport);
+ 	hs->rpc_cli = NULL;
+ 
+ 	tevent_req_done(req);
+@@ -2636,6 +2773,7 @@ NTSTATUS rpccli_ncalrpc_bind_data(TALLOC
+ 
+ 	result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
+ 	result->auth_level = DCERPC_AUTH_LEVEL_CONNECT;
++	result->auth_context_id = 1;
+ 
+ 	result->user_name = talloc_strdup(result, "");
+ 	result->domain = talloc_strdup(result, "");
+@@ -2660,6 +2798,7 @@ NTSTATUS rpccli_anon_bind_data(TALLOC_CT
+ 
+ 	result->auth_type = DCERPC_AUTH_TYPE_NONE;
+ 	result->auth_level = DCERPC_AUTH_LEVEL_NONE;
++	result->auth_context_id = 0;
+ 
+ 	result->user_name = talloc_strdup(result, "");
+ 	result->domain = talloc_strdup(result, "");
+@@ -2697,6 +2836,7 @@ static NTSTATUS rpccli_ntlmssp_bind_data
+ 
+ 	result->auth_type = auth_type;
+ 	result->auth_level = auth_level;
++	result->auth_context_id = 1;
+ 
+ 	result->user_name = talloc_strdup(result, username);
+ 	result->domain = talloc_strdup(result, domain);
+@@ -2768,6 +2908,7 @@ NTSTATUS rpccli_schannel_bind_data(TALLO
+ 
+ 	result->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
+ 	result->auth_level = auth_level;
++	result->auth_context_id = 1;
+ 
+ 	result->user_name = talloc_strdup(result, "");
+ 	result->domain = talloc_strdup(result, domain);
+@@ -3432,6 +3573,7 @@ NTSTATUS cli_rpc_pipe_open_krb5(struct c
+ 	}
+ 	auth->auth_type = DCERPC_AUTH_TYPE_KRB5;
+ 	auth->auth_level = auth_level;
++	auth->auth_context_id = 1;
+ 
+ 	if (!username) {
+ 		username = "";
+@@ -3502,6 +3644,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_krb5(s
+ 	}
+ 	auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
+ 	auth->auth_level = auth_level;
++	auth->auth_context_id = 1;
+ 
+ 	if (!username) {
+ 		username = "";
+@@ -3576,6 +3719,7 @@ NTSTATUS cli_rpc_pipe_open_spnego_ntlmss
+ 	}
+ 	auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
+ 	auth->auth_level = auth_level;
++	auth->auth_context_id = 1;
+ 
+ 	if (!username) {
+ 		username = "";
+--- a/source4/rpc_server/dcesrv_auth.c
++++ b/source4/rpc_server/dcesrv_auth.c
+@@ -46,7 +46,7 @@ bool dcesrv_auth_bind(struct dcesrv_call
+ 	NTSTATUS status;
+ 	uint32_t auth_length;
+ 
+-	if (pkt->u.bind.auth_info.length == 0) {
++	if (pkt->auth_length == 0) {
+ 		dce_conn->auth_state.auth_info = NULL;
+ 		return true;
+ 	}
+@@ -108,7 +108,7 @@ NTSTATUS dcesrv_auth_bind_ack(struct dce
+ 	struct dcesrv_connection *dce_conn = call->conn;
+ 	NTSTATUS status;
+ 
+-	if (!call->conn->auth_state.gensec_security) {
++	if (call->pkt.auth_length == 0) {
+ 		return NT_STATUS_OK;
+ 	}
+ 
+@@ -155,10 +155,16 @@ bool dcesrv_auth_auth3(struct dcesrv_cal
+ 	NTSTATUS status;
+ 	uint32_t auth_length;
+ 
+-	/* We can't work without an existing gensec state, and an new blob to feed it */
+-	if (!dce_conn->auth_state.auth_info ||
+-	    !dce_conn->auth_state.gensec_security ||
+-	    pkt->u.auth3.auth_info.length == 0) {
++	if (pkt->auth_length == 0) {
++		return false;
++	}
++
++	if (!dce_conn->auth_state.auth_info) {
++		return false;
++	}
++
++	/* We can't work without an existing gensec state */
++	if (!dce_conn->auth_state.gensec_security) {
+ 		return false;
+ 	}
+ 
+@@ -203,7 +209,7 @@ bool dcesrv_auth_alter(struct dcesrv_cal
+ 	uint32_t auth_length;
+ 
+ 	/* on a pure interface change there is no auth blob */
+-	if (pkt->u.alter.auth_info.length == 0) {
++	if (pkt->auth_length == 0) {
+ 		return true;
+ 	}
+ 
+@@ -238,8 +244,7 @@ NTSTATUS dcesrv_auth_alter_ack(struct dc
+ 
+ 	/* on a pure interface change there is no auth_info structure
+ 	   setup */
+-	if (!call->conn->auth_state.auth_info ||
+-	    dce_conn->auth_state.auth_info->credentials.length == 0) {
++	if (call->pkt.auth_length == 0) {
+ 		return NT_STATUS_OK;
+ 	}
+ 
+@@ -315,6 +320,11 @@ bool dcesrv_auth_request(struct dcesrv_c
+ 		return false;
+ 	}
+ 
++	if (pkt->auth_length == 0) {
++		DEBUG(1,("dcesrv_auth_request: unexpected auth_length of 0\n"));
++		return false;
++	}
++
+ 	status = dcerpc_pull_auth_trailer(pkt, call,
+ 					  &pkt->u.request.stub_and_verifier,
+ 					  &auth, &auth_length, false);
+--- a/source4/librpc/rpc/dcerpc.c
++++ b/source4/librpc/rpc/dcerpc.c
+@@ -701,6 +701,14 @@ static NTSTATUS ncacn_pull_request_auth(
+ 		return NT_STATUS_INVALID_LEVEL;
+ 	}
+ 
++	if (pkt->auth_length == 0) {
++		return NT_STATUS_INVALID_NETWORK_RESPONSE;
++	}
++
++	if (c->security_state.generic_state == NULL) {
++		return NT_STATUS_INTERNAL_ERROR;
++	}
++
+ 	status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
+ 					  &pkt->u.response.stub_and_verifier,
+ 					  &auth, &auth_length, false);
+@@ -1074,7 +1082,7 @@ static void dcerpc_bind_recv_handler(str
+ 	}
+ 
+ 	/* the bind_ack might contain a reply set of credentials */
+-	if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
++	if (conn->security_state.auth_info && pkt->auth_length) {
+ 		NTSTATUS status;
+ 		uint32_t auth_length;
+ 		status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
+@@ -1847,8 +1855,7 @@ static void dcerpc_alter_recv_handler(st
+ 	}
+ 
+ 	/* the alter_resp might contain a reply set of credentials */
+-	if (recv_pipe->conn->security_state.auth_info &&
+-	    pkt->u.alter_resp.auth_info.length) {
++	if (recv_pipe->conn->security_state.auth_info && pkt->auth_length) {
+ 		struct dcecli_connection *conn = recv_pipe->conn;
+ 		NTSTATUS status;
+ 		uint32_t auth_length;
+--- a/source3/librpc/rpc/dcerpc.h
++++ b/source3/librpc/rpc/dcerpc.h
+@@ -42,6 +42,7 @@ struct pipe_auth_data {
+ 	bool verified_bitmask1;
+ 
+ 	void *auth_ctx;
++	uint32_t auth_context_id;
+ 
+ 	/* Only the client code uses these 3 for now */
+ 	char *domain;
+@@ -71,10 +72,6 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_
+ 				 uint32_t auth_context_id,
+ 				 const DATA_BLOB *credentials,
+ 				 DATA_BLOB *blob);
+-NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
+-				 const DATA_BLOB *blob,
+-				 struct dcerpc_auth *r,
+-				 bool bigendian);
+ NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
+ 			    size_t header_len, size_t data_left,
+ 			    size_t max_xmit_frag, size_t pad_alignment,
+@@ -85,9 +82,8 @@ NTSTATUS dcerpc_add_auth_footer(struct p
+ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
+ 			   struct ncacn_packet *pkt,
+ 			   DATA_BLOB *pkt_trailer,
+-			   size_t header_size,
+-			   DATA_BLOB *raw_pkt,
+-			   size_t *pad_len);
++			   uint8_t header_size,
++			   DATA_BLOB *raw_pkt);
+ 
+ /* The following definitions come from librpc/rpc/rpc_common.c  */
+ 
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -42,6 +42,7 @@
+ #include "auth.h"
+ #include "ntdomain.h"
+ #include "rpc_server/srv_pipe.h"
++#include "../librpc/gen_ndr/ndr_dcerpc.h"
+ #include "../librpc/ndr/ndr_dcerpc.h"
+ 
+ #undef DBGC_CLASS
+@@ -270,10 +271,14 @@ static bool setup_bind_nak(struct pipes_
+ 	p->out_data.data_sent_length = 0;
+ 	p->out_data.current_pdu_sent = 0;
+ 
++	set_incoming_fault(p);
+ 	TALLOC_FREE(p->auth.auth_ctx);
+ 	p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
+ 	p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
+ 	p->pipe_bound = False;
++	p->allow_bind = false;
++	p->allow_alter = false;
++	p->allow_auth3 = false;
+ 
+ 	return True;
+ }
+@@ -339,16 +344,46 @@ static bool check_bind_req(struct pipes_
+ 	DEBUG(3,("check_bind_req for %s\n",
+ 		 get_pipe_name_from_syntax(talloc_tos(), abstract)));
+ 
++	ok = ndr_syntax_id_equal(transfer, &ndr_transfer_syntax);
++	if (!ok) {
++		DEBUG(1,("check_bind_req unknown transfer syntax for "
++			 "%s context_id=%u\n",
++			 get_pipe_name_from_syntax(talloc_tos(), abstract),
++			 (unsigned)context_id));
++		return false;
++	}
++
++	for (context_fns = p->contexts;
++	     context_fns != NULL;
++	     context_fns = context_fns->next)
++	{
++		if (context_fns->context_id != context_id) {
++			continue;
++		}
++
++		ok = ndr_syntax_id_equal(&context_fns->syntax,
++					 abstract);
++		if (ok) {
++			return true;
++		}
++
++		DEBUG(1,("check_bind_req: changing abstract syntax for "
++			 "%s context_id=%u into %s not supported\n",
++			 get_pipe_name_from_syntax(talloc_tos(), &context_fns->syntax),
++			 (unsigned)context_id,
++			 get_pipe_name_from_syntax(talloc_tos(), abstract)));
++		return false;
++	}
++
+ 	/* we have to check all now since win2k introduced a new UUID on the lsaprpc pipe */
+-	if (rpc_srv_pipe_exists_by_id(abstract) &&
+-	   ndr_syntax_id_equal(transfer, &ndr_transfer_syntax)) {
+-		DEBUG(3, ("check_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n",
+-			rpc_srv_get_pipe_cli_name(abstract),
+-			rpc_srv_get_pipe_srv_name(abstract)));
+-	} else {
++	if (!rpc_srv_pipe_exists_by_id(abstract)) {
+ 		return false;
+ 	}
+ 
++	DEBUG(3, ("check_bind_req: %s -> %s rpc service\n",
++		  rpc_srv_get_pipe_cli_name(abstract),
++		  rpc_srv_get_pipe_srv_name(abstract)));
++
+ 	context_fns = SMB_MALLOC_P(struct pipe_rpc_fns);
+ 	if (context_fns == NULL) {
+ 		DEBUG(0,("check_bind_req: malloc() failed!\n"));
+@@ -447,6 +482,7 @@ static bool pipe_spnego_auth_bind(struct
+ 
+ 	p->auth.auth_ctx = spnego_ctx;
+ 	p->auth.auth_type = DCERPC_AUTH_TYPE_SPNEGO;
++	p->auth.auth_context_id = auth_info->auth_context_id;
+ 
+ 	DEBUG(10, ("SPNEGO auth started\n"));
+ 
+@@ -557,6 +593,7 @@ static bool pipe_schannel_auth_bind(stru
+ 	/* We're finished with this bind - no more packets. */
+ 	p->auth.auth_ctx = schannel_auth;
+ 	p->auth.auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
++	p->auth.auth_context_id = auth_info->auth_context_id;
+ 
+ 	p->pipe_bound = True;
+ 
+@@ -601,6 +638,7 @@ static bool pipe_ntlmssp_auth_bind(struc
+ 
+ 	p->auth.auth_ctx = ntlmssp_state;
+ 	p->auth.auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
++	p->auth.auth_context_id = auth_info->auth_context_id;
+ 
+ 	DEBUG(10, (__location__ ": NTLMSSP auth started\n"));
+ 
+@@ -776,6 +814,11 @@ static NTSTATUS pipe_auth_verify_final(s
+ 	void *mech_ctx;
+ 	NTSTATUS status;
+ 
++	if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
++		p->pipe_bound = true;
++		return NT_STATUS_OK;
++	}
++
+ 	switch (p->auth.auth_type) {
+ 	case DCERPC_AUTH_TYPE_NTLMSSP:
+ 		ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx,
+@@ -867,16 +910,38 @@ static bool api_pipe_bind_req(struct pip
+ 	DATA_BLOB auth_resp = data_blob_null;
+ 	DATA_BLOB auth_blob = data_blob_null;
+ 
+-	/* No rebinds on a bound pipe - use alter context. */
+-	if (p->pipe_bound) {
+-		DEBUG(2,("api_pipe_bind_req: rejecting bind request on bound "
+-			 "pipe %s.\n",
+-			 get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
++	if (!p->allow_bind) {
++		DEBUG(2,("Pipe not in allow bind state\n"));
+ 		return setup_bind_nak(p, pkt);
+ 	}
++	p->allow_bind = false;
++
++	status = dcerpc_verify_ncacn_packet_header(pkt,
++			DCERPC_PKT_BIND,
++			pkt->u.bind.auth_info.length,
++			0, /* required flags */
++			DCERPC_PFC_FLAG_FIRST |
++			DCERPC_PFC_FLAG_LAST |
++			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
++			0x08 | /* this is not defined, but should be ignored */
++			DCERPC_PFC_FLAG_CONC_MPX |
++			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
++			DCERPC_PFC_FLAG_MAYBE |
++			DCERPC_PFC_FLAG_OBJECT_UUID);
++	if (!NT_STATUS_IS_OK(status)) {
++		DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n",
++			  nt_errstr(status)));
++		NDR_PRINT_DEBUG(ncacn_packet, pkt);
++		goto err_exit;
++	}
+ 
+ 	if (pkt->u.bind.num_contexts == 0) {
+-		DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
++		DEBUG(1, ("api_pipe_bind_req: no rpc contexts around\n"));
++		goto err_exit;
++	}
++
++	if (pkt->u.bind.ctx_list[0].num_transfer_syntaxes == 0) {
++		DEBUG(1, ("api_pipe_bind_req: no transfer syntaxes around\n"));
+ 		goto err_exit;
+ 	}
+ 
+@@ -960,25 +1025,12 @@ static bool api_pipe_bind_req(struct pip
+ 	 * Check if this is an authenticated bind request.
+ 	 */
+ 	if (pkt->auth_length) {
+-		/* Quick length check. Won't catch a bad auth footer,
+-		 * prevents overrun. */
+-
+-		if (pkt->frag_length < RPC_HEADER_LEN +
+-					DCERPC_AUTH_TRAILER_LENGTH +
+-					pkt->auth_length) {
+-			DEBUG(0,("api_pipe_bind_req: auth_len (%u) "
+-				"too long for fragment %u.\n",
+-				(unsigned int)pkt->auth_length,
+-				(unsigned int)pkt->frag_length));
+-			goto err_exit;
+-		}
+-
+ 		/*
+ 		 * Decode the authentication verifier.
+ 		 */
+-		status = dcerpc_pull_dcerpc_auth(pkt,
+-						 &pkt->u.bind.auth_info,
+-						 &auth_info, p->endian);
++		status = dcerpc_pull_auth_trailer(pkt, pkt,
++						  &pkt->u.bind.auth_info,
++						  &auth_info, NULL, true);
+ 		if (!NT_STATUS_IS_OK(status)) {
+ 			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
+ 			goto err_exit;
+@@ -1072,6 +1124,7 @@ static bool api_pipe_bind_req(struct pip
+ 		p->pipe_bound = True;
+ 		/* The session key was initialized from the SMB
+ 		 * session in make_internal_rpc_pipe_p */
++		p->auth.auth_context_id = 0;
+ 	}
+ 
+ 	ZERO_STRUCT(u.bind_ack);
+@@ -1113,15 +1166,15 @@ static bool api_pipe_bind_req(struct pip
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
+ 			  nt_errstr(status)));
++		goto err_exit;
+ 	}
+ 
+ 	if (auth_resp.length) {
+-
+ 		status = dcerpc_push_dcerpc_auth(pkt,
+ 						 auth_type,
+ 						 auth_info.auth_level,
+-						 0,
+-						 1, /* auth_context_id */
++						 0, /* pad_len */
++						 p->auth.auth_context_id,
+ 						 &auth_resp,
+ 						 &auth_blob);
+ 		if (!NT_STATUS_IS_OK(status)) {
+@@ -1152,6 +1205,22 @@ static bool api_pipe_bind_req(struct pip
+ 	p->out_data.current_pdu_sent = 0;
+ 
+ 	TALLOC_FREE(auth_blob.data);
++
++	if (bind_ack_ctx.result == 0) {
++		p->allow_alter = true;
++		p->allow_auth3 = true;
++		if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
++			status = pipe_auth_verify_final(p);
++			if (!NT_STATUS_IS_OK(status)) {
++				DEBUG(0, ("pipe_auth_verify_final failed: %s\n",
++					  nt_errstr(status)));
++				goto err_exit;
++			}
++		}
++	} else {
++		goto err_exit;
++	}
++
+ 	return True;
+ 
+   err_exit:
+@@ -1176,18 +1245,39 @@ bool api_pipe_bind_auth3(struct pipes_st
+ 
+ 	DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
+ 
+-	if (pkt->auth_length == 0) {
+-		DEBUG(0, ("No auth field sent for bind request!\n"));
++	if (!p->allow_auth3) {
++		DEBUG(1, ("Pipe not in allow auth3 state.\n"));
+ 		goto err;
+ 	}
+ 
+-	/* Ensure there's enough data for an authenticated request. */
+-	if (pkt->frag_length < RPC_HEADER_LEN
+-				+ DCERPC_AUTH_TRAILER_LENGTH
+-				+ pkt->auth_length) {
+-			DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len "
+-				"%u is too large.\n",
+-                        (unsigned int)pkt->auth_length));
++	status = dcerpc_verify_ncacn_packet_header(pkt,
++			DCERPC_PKT_AUTH3,
++			pkt->u.auth3.auth_info.length,
++			0, /* required flags */
++			DCERPC_PFC_FLAG_FIRST |
++			DCERPC_PFC_FLAG_LAST |
++			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
++			0x08 | /* this is not defined, but should be ignored */
++			DCERPC_PFC_FLAG_CONC_MPX |
++			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
++			DCERPC_PFC_FLAG_MAYBE |
++			DCERPC_PFC_FLAG_OBJECT_UUID);
++	if (!NT_STATUS_IS_OK(status)) {
++		DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n",
++			  nt_errstr(status)));
++		NDR_PRINT_DEBUG(ncacn_packet, pkt);
++		goto err;
++	}
++
++	/* We can only finish if the pipe is unbound for now */
++	if (p->pipe_bound) {
++		DEBUG(0, (__location__ ": Pipe already bound, "
++			  "AUTH3 not supported!\n"));
++		goto err;
++	}
++
++	if (pkt->auth_length == 0) {
++		DEBUG(1, ("No auth field sent for auth3 request!\n"));
+ 		goto err;
+ 	}
+ 
+@@ -1195,9 +1285,9 @@ bool api_pipe_bind_auth3(struct pipes_st
+ 	 * Decode the authentication verifier response.
+ 	 */
+ 
+-	status = dcerpc_pull_dcerpc_auth(pkt,
+-					 &pkt->u.auth3.auth_info,
+-					 &auth_info, p->endian);
++	status = dcerpc_pull_auth_trailer(pkt, pkt,
++					  &pkt->u.auth3.auth_info,
++					  &auth_info, NULL, true);
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n"));
+ 		goto err;
+@@ -1215,6 +1305,21 @@ bool api_pipe_bind_auth3(struct pipes_st
+ 		goto err;
+ 	}
+ 
++	if (auth_info.auth_level != p->auth.auth_level) {
++		DEBUG(1, ("Auth level mismatch! Client sent %d, "
++			  "but auth was started as level %d!\n",
++			  auth_info.auth_level, p->auth.auth_level));
++		goto err;
++	}
++
++	if (auth_info.auth_context_id != p->auth.auth_context_id) {
++		DEBUG(0, ("Auth context id mismatch! Client sent %u, "
++			  "but auth was started as level %u!\n",
++			  (unsigned)auth_info.auth_context_id,
++			  (unsigned)p->auth.auth_context_id));
++		goto err;
++	}
++
+ 	switch (auth_info.auth_type) {
+ 	case DCERPC_AUTH_TYPE_NTLMSSP:
+ 		ntlmssp_ctx = talloc_get_type_abort(p->auth.auth_ctx,
+@@ -1267,6 +1372,10 @@ bool api_pipe_bind_auth3(struct pipes_st
+ 	return true;
+ 
+ err:
++	p->pipe_bound = false;
++	p->allow_bind = false;
++	p->allow_alter = false;
++	p->allow_auth3 = false;
+ 
+ 	TALLOC_FREE(p->auth.auth_ctx);
+ 	return false;
+@@ -1284,7 +1393,7 @@ static bool api_pipe_alter_context(struc
+ 	uint16 assoc_gid;
+ 	NTSTATUS status;
+ 	union dcerpc_payload u;
+-	struct dcerpc_ack_ctx bind_ack_ctx;
++	struct dcerpc_ack_ctx alter_ack_ctx;
+ 	DATA_BLOB auth_resp = data_blob_null;
+ 	DATA_BLOB auth_blob = data_blob_null;
+ 	int pad_len = 0;
+@@ -1294,8 +1403,42 @@ static bool api_pipe_alter_context(struc
+ 
+ 	DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
+ 
+-	if (pkt->u.bind.assoc_group_id != 0) {
+-		assoc_gid = pkt->u.bind.assoc_group_id;
++	if (!p->allow_alter) {
++		DEBUG(1, ("Pipe not in allow alter state.\n"));
++		goto err_exit;
++	}
++
++	status = dcerpc_verify_ncacn_packet_header(pkt,
++			DCERPC_PKT_ALTER,
++			pkt->u.alter.auth_info.length,
++			0, /* required flags */
++			DCERPC_PFC_FLAG_FIRST |
++			DCERPC_PFC_FLAG_LAST |
++			DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
++			0x08 | /* this is not defined, but should be ignored */
++			DCERPC_PFC_FLAG_CONC_MPX |
++			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
++			DCERPC_PFC_FLAG_MAYBE |
++			DCERPC_PFC_FLAG_OBJECT_UUID);
++	if (!NT_STATUS_IS_OK(status)) {
++		DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n",
++			  nt_errstr(status)));
++		NDR_PRINT_DEBUG(ncacn_packet, pkt);
++		goto err_exit;
++	}
++
++	if (pkt->u.alter.num_contexts == 0) {
++		DEBUG(1, ("api_pipe_alter_context: no rpc contexts around\n"));
++		goto err_exit;
++	}
++
++	if (pkt->u.alter.ctx_list[0].num_transfer_syntaxes == 0) {
++		DEBUG(1, ("api_pipe_alter_context: no transfer syntaxes around\n"));
++		goto err_exit;
++	}
++
++	if (pkt->u.alter.assoc_group_id != 0) {
++		assoc_gid = pkt->u.alter.assoc_group_id;
+ 	} else {
+ 		assoc_gid = 0x53f0;
+ 	}
+@@ -1305,59 +1448,45 @@ static bool api_pipe_alter_context(struc
+ 	 */
+ 
+ 	/* If the requested abstract synt uuid doesn't match our client pipe,
+-		reject the bind_ack & set the transfer interface synt to all 0's,
++		reject the alter_ack & set the transfer interface synt to all 0's,
+ 		ver 0 (observed when NT5 attempts to bind to abstract interfaces
+ 		unknown to NT4)
+ 		Needed when adding entries to a DACL from NT5 - SK */
+ 
+ 	if (check_bind_req(p,
+-			&pkt->u.bind.ctx_list[0].abstract_syntax,
+-			&pkt->u.bind.ctx_list[0].transfer_syntaxes[0],
+-			pkt->u.bind.ctx_list[0].context_id)) {
+-
+-		bind_ack_ctx.result = 0;
+-		bind_ack_ctx.reason = 0;
+-		bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
++			&pkt->u.alter.ctx_list[0].abstract_syntax,
++			&pkt->u.alter.ctx_list[0].transfer_syntaxes[0],
++			pkt->u.alter.ctx_list[0].context_id)) {
++
++		alter_ack_ctx.result = 0;
++		alter_ack_ctx.reason = 0;
++		alter_ack_ctx.syntax = pkt->u.alter.ctx_list[0].transfer_syntaxes[0];
+ 	} else {
+-		p->pipe_bound = False;
+ 		/* Rejection reason: abstract syntax not supported */
+-		bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
+-		bind_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX;
+-		bind_ack_ctx.syntax = null_ndr_syntax_id;
++		alter_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
++		alter_ack_ctx.reason = DCERPC_BIND_REASON_ASYNTAX;
++		alter_ack_ctx.syntax = null_ndr_syntax_id;
+ 	}
+ 
+ 	/*
+ 	 * Check if this is an authenticated alter context request.
+ 	 */
+ 	if (pkt->auth_length) {
+-		/* Quick length check. Won't catch a bad auth footer,
+-		 * prevents overrun. */
+-
+-		if (pkt->frag_length < RPC_HEADER_LEN +
+-					DCERPC_AUTH_TRAILER_LENGTH +
+-					pkt->auth_length) {
+-			DEBUG(0,("api_pipe_alter_context: auth_len (%u) "
+-				"too long for fragment %u.\n",
+-				(unsigned int)pkt->auth_length,
+-				(unsigned int)pkt->frag_length ));
++		/* We can only finish if the pipe is unbound for now */
++		if (p->pipe_bound) {
++			DEBUG(0, (__location__ ": Pipe already bound, "
++				  "Altering Context not yet supported!\n"));
+ 			goto err_exit;
+ 		}
+ 
+-		status = dcerpc_pull_dcerpc_auth(pkt,
+-						 &pkt->u.bind.auth_info,
+-						 &auth_info, p->endian);
++		status = dcerpc_pull_auth_trailer(pkt, pkt,
++						  &pkt->u.alter.auth_info,
++						  &auth_info, NULL, true);
+ 		if (!NT_STATUS_IS_OK(status)) {
+ 			DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n"));
+ 			goto err_exit;
+ 		}
+ 
+-		/* We can only finish if the pipe is unbound for now */
+-		if (p->pipe_bound) {
+-			DEBUG(0, (__location__ ": Pipe already bound, "
+-				  "Altering Context not yet supported!\n"));
+-			goto err_exit;
+-		}
+-
+ 		if (auth_info.auth_type != p->auth.auth_type) {
+ 			DEBUG(0, ("Auth type mismatch! Client sent %d, "
+ 				  "but auth was started as type %d!\n",
+@@ -1365,6 +1494,20 @@ static bool api_pipe_alter_context(struc
+ 			goto err_exit;
+ 		}
+ 
++		if (auth_info.auth_level != p->auth.auth_level) {
++			DEBUG(0, ("Auth level mismatch! Client sent %d, "
++				  "but auth was started as level %d!\n",
++				  auth_info.auth_level, p->auth.auth_level));
++			goto err_exit;
++		}
++
++		if (auth_info.auth_context_id != p->auth.auth_context_id) {
++			DEBUG(0, ("Auth context id mismatch! Client sent %u, "
++				  "but auth was started as level %u!\n",
++				  (unsigned)auth_info.auth_context_id,
++				  (unsigned)p->auth.auth_context_id));
++			goto err_exit;
++		}
+ 
+ 		switch (auth_info.auth_type) {
+ 		case DCERPC_AUTH_TYPE_SPNEGO:
+@@ -1431,7 +1574,7 @@ static bool api_pipe_alter_context(struc
+ 	u.alter_resp.secondary_address_size = 1;
+ 
+ 	u.alter_resp.num_results = 1;
+-	u.alter_resp.ctx_list = &bind_ack_ctx;
++	u.alter_resp.ctx_list = &alter_ack_ctx;
+ 
+ 	/* NOTE: We leave the auth_info empty so we can calculate the padding
+ 	 * later and then append the auth_info --simo */
+@@ -1451,8 +1594,9 @@ static bool api_pipe_alter_context(struc
+ 					  &u,
+ 					  &p->out_data.frag);
+ 	if (!NT_STATUS_IS_OK(status)) {
+-		DEBUG(0, ("Failed to marshall bind_ack packet. (%s)\n",
++		DEBUG(0, ("Failed to marshall alter_resp packet. (%s)\n",
+ 			  nt_errstr(status)));
++		goto err_exit;
+ 	}
+ 
+ 	if (auth_resp.length) {
+@@ -1469,7 +1613,7 @@ static bool api_pipe_alter_context(struc
+ 						 auth_info.auth_type,
+ 						 auth_info.auth_level,
+ 						 pad_len,
+-						 1, /* auth_context_id */
++						 p->auth.auth_context_id,
+ 						 &auth_resp,
+ 						 &auth_blob);
+ 		if (!NT_STATUS_IS_OK(status)) {
+@@ -1618,6 +1762,7 @@ static bool api_pipe_request(struct pipe
+ 
+ 	if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
+ 		DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
++		set_incoming_fault(p);
+ 		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
+ 		data_blob_free(&p->out_data.rdata);
+ 		TALLOC_FREE(frame);
+@@ -1756,7 +1901,11 @@ void set_incoming_fault(struct pipes_str
+ 	data_blob_free(&p->in_data.data);
+ 	p->in_data.pdu_needed_len = 0;
+ 	p->in_data.pdu.length = 0;
+-	p->fault_state = DCERPC_FAULT_CANT_PERFORM;
++	p->fault_state = DCERPC_NCA_S_PROTO_ERROR;
++
++	p->allow_alter = false;
++	p->allow_auth3 = false;
++	p->pipe_bound = false;
+ 
+ 	DEBUG(10, ("Setting fault state\n"));
+ }
+@@ -1767,7 +1916,6 @@ static NTSTATUS dcesrv_auth_request(stru
+ {
+ 	NTSTATUS status;
+ 	size_t hdr_size = DCERPC_REQUEST_LENGTH;
+-	size_t pad_len;
+ 
+ 	DEBUG(10, ("Checking request auth.\n"));
+ 
+@@ -1778,25 +1926,11 @@ static NTSTATUS dcesrv_auth_request(stru
+ 	/* in case of sealing this function will unseal the data in place */
+ 	status = dcerpc_check_auth(auth, pkt,
+ 				   &pkt->u.request.stub_and_verifier,
+-				   hdr_size, raw_pkt,
+-				   &pad_len);
++				   hdr_size, raw_pkt);
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		return status;
+ 	}
+ 
+-
+-	/* remove padding and auth trailer,
+-	 * this way the caller will get just the data */
+-	if (pkt->auth_length) {
+-		size_t trail_len = pad_len
+-					+ DCERPC_AUTH_TRAILER_LENGTH
+-					+ pkt->auth_length;
+-		if (pkt->u.request.stub_and_verifier.length < trail_len) {
+-			return NT_STATUS_INFO_LENGTH_MISMATCH;
+-		}
+-		pkt->u.request.stub_and_verifier.length -= trail_len;
+-	}
+-
+ 	return NT_STATUS_OK;
+ }
+ 
+@@ -1816,6 +1950,29 @@ static bool process_request_pdu(struct p
+ 		return False;
+ 	}
+ 
++	/*
++	 * We don't ignore DCERPC_PFC_FLAG_PENDING_CANCEL.
++	 * TODO: we can reject it with DCERPC_FAULT_NO_CALL_ACTIVE later.
++	 */
++	status = dcerpc_verify_ncacn_packet_header(pkt,
++			DCERPC_PKT_REQUEST,
++			pkt->u.request.stub_and_verifier.length,
++			0, /* required_flags */
++			DCERPC_PFC_FLAG_FIRST |
++			DCERPC_PFC_FLAG_LAST |
++			0x08 | /* this is not defined, but should be ignored */
++			DCERPC_PFC_FLAG_CONC_MPX |
++			DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
++			DCERPC_PFC_FLAG_MAYBE |
++			DCERPC_PFC_FLAG_OBJECT_UUID);
++	if (!NT_STATUS_IS_OK(status)) {
++		DEBUG(1, ("process_request_pdu: invalid pdu: %s\n",
++			  nt_errstr(status)));
++		NDR_PRINT_DEBUG(ncacn_packet, pkt);
++		set_incoming_fault(p);
++		return false;
++	}
++
+ 	/* Store the opnum */
+ 	p->opnum = pkt->u.request.opnum;
+ 
+@@ -2065,7 +2222,7 @@ done:
+ 			 "pipe %s\n", get_pipe_name_from_syntax(talloc_tos(),
+ 								&p->syntax)));
+ 		set_incoming_fault(p);
+-		setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
++		setup_fault_pdu(p, NT_STATUS(DCERPC_NCA_S_PROTO_ERROR));
+ 		TALLOC_FREE(pkt);
+ 	} else {
+ 		/*
+--- a/source3/include/ntdomain.h
++++ b/source3/include/ntdomain.h
+@@ -135,6 +135,13 @@ struct pipes_struct {
+ 	bool pipe_bound;
+ 
+ 	/*
++	 * States we can be in.
++	 */
++	bool allow_alter;
++	bool allow_bind;
++	bool allow_auth3;
++
++	/*
+ 	 * Set the DCERPC_FAULT to return.
+ 	 */
+ 
+--- a/source3/rpc_server/rpc_ncacn_np.c
++++ b/source3/rpc_server/rpc_ncacn_np.c
+@@ -171,6 +171,7 @@ struct pipes_struct *make_internal_rpc_p
+ 
+ 	p->syntax = *syntax;
+ 	p->transport = NCALRPC;
++	p->allow_bind = true;
+ 
+ 	DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
+ 		 get_pipe_name_from_syntax(talloc_tos(), syntax), pipes_open));
+@@ -780,6 +781,7 @@ static NTSTATUS rpc_pipe_open_external(T
+ 	}
+ 	result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ 	result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
++	result->auth->auth_context_id = 0;
+ 
+ 	status = rpccli_anon_bind_data(result, &auth);
+ 	if (!NT_STATUS_IS_OK(status)) {
+--- a/source3/rpc_server/rpc_server.c
++++ b/source3/rpc_server/rpc_server.c
+@@ -102,6 +102,7 @@ static int make_server_pipes_struct(TALL
+ 	p->syntax = id;
+ 	p->transport = transport;
+ 	p->ncalrpc_as_system = ncalrpc_as_system;
++	p->allow_bind = true;
+ 
+ 	p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p);
+ 	if (!p->mem_ctx) {
+@@ -663,6 +664,12 @@ static void named_pipe_packet_done(struc
+ 		goto fail;
+ 	}
+ 
++	if (npc->p->fault_state != 0) {
++		DEBUG(2, ("Disconnect after fault\n"));
++		sys_errno = EINVAL;
++		goto fail;
++	}
++
+ 	/* clear out any data that may have been left around */
+ 	npc->count = 0;
+ 	TALLOC_FREE(npc->iov);
+@@ -1391,6 +1398,12 @@ static void dcerpc_ncacn_packet_done(str
+ 		goto fail;
+ 	}
+ 
++	if (ncacn_conn->p->fault_state != 0) {
++		DEBUG(2, ("Disconnect after fault\n"));
++		sys_errno = EINVAL;
++		goto fail;
++	}
++
+ 	/* clear out any data that may have been left around */
+ 	ncacn_conn->count = 0;
+ 	TALLOC_FREE(ncacn_conn->iov);
diff --git a/package/network/services/samba36/patches/023-CVE-2016-2110-v3-6.patch b/package/network/services/samba36/patches/023-CVE-2016-2110-v3-6.patch
new file mode 100644
index 0000000000..0da66bf487
--- /dev/null
+++ b/package/network/services/samba36/patches/023-CVE-2016-2110-v3-6.patch
@@ -0,0 +1,255 @@
+From 202d69267c8550b850438877fb51c3d2c992949d Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Tue, 1 Dec 2015 08:46:45 +0100
+Subject: [PATCH 01/10] CVE-2016-2110: s3:ntlmssp: set and use
+ ntlmssp_state->allow_lm_key
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11644
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Günther Deschner <gd@samba.org>
+---
+ source3/libsmb/ntlmssp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/source3/libsmb/ntlmssp.c
++++ b/source3/libsmb/ntlmssp.c
+@@ -176,17 +176,19 @@ void ntlmssp_want_feature_list(struct nt
+ 	 * also add  NTLMSSP_NEGOTIATE_SEAL here. JRA.
+ 	 */
+ 	if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, True)) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ 	}
+ 	if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, True)) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ 	}
+ 	if(in_list("NTLMSSP_FEATURE_SEAL", feature_list, True)) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ 	}
+ 	if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
+ 		ntlmssp_state->use_ccache = true;
+ 	}
++
++	ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
+ }
+ 
+ /**
+@@ -199,17 +201,20 @@ void ntlmssp_want_feature(struct ntlmssp
+ {
+ 	/* As per JRA's comment above */
+ 	if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ 	}
+ 	if (feature & NTLMSSP_FEATURE_SIGN) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ 	}
+ 	if (feature & NTLMSSP_FEATURE_SEAL) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ 	}
+ 	if (feature & NTLMSSP_FEATURE_CCACHE) {
+ 		ntlmssp_state->use_ccache = true;
+ 	}
++
++	ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
+ }
+ 
+ /**
+@@ -387,7 +392,12 @@ static NTSTATUS ntlmssp_client_initial(s
+ 	}
+ 
+ 	if (ntlmssp_state->use_ntlmv2) {
+-		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
++		ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_NTLM2;
++		ntlmssp_state->allow_lm_key = false;
++	}
++
++	if (ntlmssp_state->allow_lm_key) {
++		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ 	}
+ 
+ 	/* generate the ntlmssp negotiate packet */
+@@ -422,6 +432,86 @@ static NTSTATUS ntlmssp_client_initial(s
+ 	return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ 
++static NTSTATUS ntlmssp3_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
++					  uint32_t flags)
++{
++	uint32_t missing_flags = ntlmssp_state->required_flags;
++
++	if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
++		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
++		ntlmssp_state->unicode = true;
++	} else {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
++		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
++		ntlmssp_state->unicode = false;
++	}
++
++	/*
++	 * NTLMSSP_NEGOTIATE_NTLM2 (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)
++	 * has priority over NTLMSSP_NEGOTIATE_LM_KEY
++	 */
++	if (!(flags & NTLMSSP_NEGOTIATE_NTLM2)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
++	}
++
++	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_LM_KEY)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_128)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_56)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_SIGN)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
++	}
++
++	if (!(flags & NTLMSSP_NEGOTIATE_SEAL)) {
++		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL;
++	}
++
++	if ((flags & NTLMSSP_REQUEST_TARGET)) {
++		ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
++	}
++
++	missing_flags &= ~ntlmssp_state->neg_flags;
++	if (missing_flags != 0) {
++		NTSTATUS status = NT_STATUS_RPC_SEC_PKG_ERROR;
++		DEBUG(1, ("%s: Got challenge flags[0x%08x] "
++			  "- possible downgrade detected! "
++			  "missing_flags[0x%08x] - %s\n",
++			  __func__,
++			  (unsigned)flags,
++			  (unsigned)missing_flags,
++			  nt_errstr(status)));
++		debug_ntlmssp_flags(missing_flags);
++		DEBUGADD(4, ("neg_flags[0x%08x]\n",
++			     (unsigned)ntlmssp_state->neg_flags));
++		debug_ntlmssp_flags(ntlmssp_state->neg_flags);
++
++		return status;
++	}
++
++	return NT_STATUS_OK;
++}
++
+ /**
+  * Next state function for the Challenge Packet.  Generate an auth packet.
+  *
+@@ -448,6 +538,26 @@ static NTSTATUS ntlmssp_client_challenge
+ 	DATA_BLOB encrypted_session_key = data_blob_null;
+ 	NTSTATUS nt_status = NT_STATUS_OK;
+ 
++	if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
++			 "NTLMSSP",
++			 &ntlmssp_command,
++			 &server_domain_blob,
++			 &chal_flags)) {
++		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
++		dump_data(2, reply.data, reply.length);
++
++		return NT_STATUS_INVALID_PARAMETER;
++	}
++	data_blob_free(&server_domain_blob);
++
++	DEBUG(3, ("Got challenge flags:\n"));
++	debug_ntlmssp_flags(chal_flags);
++
++	nt_status = ntlmssp3_handle_neg_flags(ntlmssp_state, chal_flags);
++	if (!NT_STATUS_IS_OK(nt_status)) {
++		return nt_status;
++	}
++
+ 	if (ntlmssp_state->use_ccache) {
+ 		struct wbcCredentialCacheParams params;
+ 		struct wbcCredentialCacheInfo *info = NULL;
+@@ -498,17 +608,6 @@ static NTSTATUS ntlmssp_client_challenge
+ 
+ noccache:
+ 
+-	if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
+-			 "NTLMSSP",
+-			 &ntlmssp_command,
+-			 &server_domain_blob,
+-			 &chal_flags)) {
+-		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+-		dump_data(2, reply.data, reply.length);
+-
+-		return NT_STATUS_INVALID_PARAMETER;
+-	}
+-
+ 	if (DEBUGLEVEL >= 10) {
+ 		struct CHALLENGE_MESSAGE *challenge = talloc(
+ 			talloc_tos(), struct CHALLENGE_MESSAGE);
+@@ -525,13 +624,6 @@ noccache:
+ 		}
+ 	}
+ 
+-	data_blob_free(&server_domain_blob);
+-
+-	DEBUG(3, ("Got challenge flags:\n"));
+-	debug_ntlmssp_flags(chal_flags);
+-
+-	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
+-
+ 	if (ntlmssp_state->unicode) {
+ 		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
+ 			chal_parse_string = "CdUdbddB";
+@@ -769,6 +861,7 @@ NTSTATUS ntlmssp_client_start(TALLOC_CTX
+ 	ntlmssp_state->unicode = True;
+ 
+ 	ntlmssp_state->use_ntlmv2 = use_ntlmv2;
++	ntlmssp_state->allow_lm_key = lp_client_lanman_auth();
+ 
+ 	ntlmssp_state->expected_state = NTLMSSP_INITIAL;
+ 
+@@ -780,6 +873,10 @@ NTSTATUS ntlmssp_client_start(TALLOC_CTX
+ 		NTLMSSP_NEGOTIATE_KEY_EXCH |
+ 		NTLMSSP_REQUEST_TARGET;
+ 
++	if (ntlmssp_state->use_ntlmv2) {
++		ntlmssp_state->allow_lm_key = false;
++	}
++
+ 	ntlmssp_state->client.netbios_name = talloc_strdup(ntlmssp_state, netbios_name);
+ 	if (!ntlmssp_state->client.netbios_name) {
+ 		talloc_free(ntlmssp_state);
+--- a/libcli/auth/ntlmssp.h
++++ b/libcli/auth/ntlmssp.h
+@@ -83,6 +83,7 @@ struct ntlmssp_state
+ 	DATA_BLOB nt_resp;
+ 	DATA_BLOB session_key;
+ 
++	uint32_t required_flags;
+ 	uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
+ 
+ 	/**
diff --git a/package/network/services/samba36/patches/024-CVE-2016-2111-v3-6.patch b/package/network/services/samba36/patches/024-CVE-2016-2111-v3-6.patch
new file mode 100644
index 0000000000..7f7f413c2f
--- /dev/null
+++ b/package/network/services/samba36/patches/024-CVE-2016-2111-v3-6.patch
@@ -0,0 +1,681 @@
+From ee105156fa151ebfd34b8febc2928e144b3b7b0e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
+Date: Sat, 26 Sep 2015 01:29:10 +0200
+Subject: [PATCH 01/15] CVE-2016-2111: s3:rpc_server/netlogon: always go
+ through netr_creds_server_step_check()
+
+The ensures we apply the "server schannel = yes" restrictions.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11749
+
+Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
+
+Signed-off-by: Guenther Deschner <gd@samba.org>
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+---
+ source3/rpc_server/netlogon/srv_netlog_nt.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
++++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
+@@ -1508,6 +1508,7 @@ static NTSTATUS _netr_LogonSamLogon_base
+ 	case NetlogonNetworkTransitiveInformation:
+ 	{
+ 		const char *wksname = nt_workstation;
++		const char *workgroup = lp_workgroup();
+ 
+ 		status = make_auth_context_fixed(talloc_tos(), &auth_context,
+ 						 logon->network->challenge);
+@@ -1532,6 +1533,14 @@ static NTSTATUS _netr_LogonSamLogon_base
+ 						     logon->network->nt.length)) {
+ 			status = NT_STATUS_NO_MEMORY;
+ 		}
++
++		if (NT_STATUS_IS_OK(status)) {
++			status = NTLMv2_RESPONSE_verify_netlogon_creds(
++						user_info->client.account_name,
++						user_info->client.domain_name,
++						user_info->password.response.nt,
++						creds, workgroup);
++		}
+ 		break;
+ 	}
+ 	case NetlogonInteractiveInformation:
+@@ -1636,6 +1645,14 @@ static NTSTATUS _netr_LogonSamLogon_base
+ 						r->out.validation->sam3);
+ 		break;
+ 	case 6:
++		/* Only allow this if the pipe is protected. */
++		if (p->auth.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
++			DEBUG(0,("netr_Validation6: client %s not using privacy for netlogon\n",
++				get_remote_machine_name()));
++			status = NT_STATUS_INVALID_PARAMETER;
++			break;
++		}
++
+ 		status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16,
+ 						r->out.validation->sam6);
+ 		break;
+@@ -2271,11 +2288,13 @@ NTSTATUS _netr_GetForestTrustInformation
+ 
+ 	/* TODO: check server name */
+ 
+-	status = schannel_check_creds_state(p->mem_ctx, lp_private_dir(),
+-					    r->in.computer_name,
+-					    r->in.credential,
+-					    r->out.return_authenticator,
+-					    &creds);
++	become_root();
++	status = netr_creds_server_step_check(p, p->mem_ctx,
++					      r->in.computer_name,
++					      r->in.credential,
++					      r->out.return_authenticator,
++					      &creds);
++	unbecome_root();
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		return status;
+ 	}
+@@ -2371,11 +2390,13 @@ NTSTATUS _netr_ServerGetTrustInfo(struct
+ 
+ 	/* TODO: check server name */
+ 
+-	status = schannel_check_creds_state(p->mem_ctx, lp_private_dir(),
+-					    r->in.computer_name,
+-					    r->in.credential,
+-					    r->out.return_authenticator,
+-					    &creds);
++	become_root();
++	status = netr_creds_server_step_check(p, p->mem_ctx,
++					      r->in.computer_name,
++					      r->in.credential,
++					      r->out.return_authenticator,
++					      &creds);
++	unbecome_root();
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		return status;
+ 	}
+--- a/source4/torture/rpc/samba3rpc.c
++++ b/source4/torture/rpc/samba3rpc.c
+@@ -1122,8 +1122,8 @@ static bool schan(struct torture_context
+ 		generate_random_buffer(chal.data, chal.length);
+ 		names_blob = NTLMv2_generate_names_blob(
+ 			mem_ctx,
+-			cli_credentials_get_workstation(user_creds),
+-			cli_credentials_get_domain(user_creds));
++			cli_credentials_get_workstation(wks_creds),
++			cli_credentials_get_domain(wks_creds));
+ 		status = cli_credentials_get_ntlm_response(
+ 			user_creds, mem_ctx, &flags, chal, names_blob,
+ 			&lm_resp, &nt_resp, NULL, NULL);
+--- a/libcli/auth/proto.h
++++ b/libcli/auth/proto.h
+@@ -139,6 +139,11 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ct
+ 		      const DATA_BLOB *names_blob,
+ 		      DATA_BLOB *lm_response, DATA_BLOB *nt_response, 
+ 		      DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
++NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
++			const char *account_domain,
++			const DATA_BLOB response,
++			const struct netlogon_creds_CredentialState *creds,
++			const char *workgroup);
+ 
+ /***********************************************************
+  encode a password buffer with a unicode password.  The buffer
+--- a/libcli/auth/smbencrypt.c
++++ b/libcli/auth/smbencrypt.c
+@@ -26,7 +26,7 @@
+ #include "../libcli/auth/msrpc_parse.h"
+ #include "../lib/crypto/crypto.h"
+ #include "../libcli/auth/libcli_auth.h"
+-#include "../librpc/gen_ndr/ntlmssp.h"
++#include "../librpc/gen_ndr/ndr_ntlmssp.h"
+ 
+ void SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
+ {
+@@ -522,6 +522,146 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ct
+ 				     lm_response, nt_response, lm_session_key, user_session_key);
+ }
+ 
++NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
++			const char *account_domain,
++			const DATA_BLOB response,
++			const struct netlogon_creds_CredentialState *creds,
++			const char *workgroup)
++{
++	TALLOC_CTX *frame = NULL;
++	/* RespType + HiRespType */
++	static const char *magic = "\x01\x01";
++	int cmp;
++	struct NTLMv2_RESPONSE v2_resp;
++	enum ndr_err_code err;
++	const struct AV_PAIR *av_nb_cn = NULL;
++	const struct AV_PAIR *av_nb_dn = NULL;
++
++	if (response.length < 48) {
++		/*
++		 * NTLMv2_RESPONSE has at least 48 bytes.
++		 */
++		return NT_STATUS_OK;
++	}
++
++	cmp = memcmp(response.data + 16, magic, 2);
++	if (cmp != 0) {
++		/*
++		 * It doesn't look like a valid NTLMv2_RESPONSE
++		 */
++		return NT_STATUS_OK;
++	}
++
++	frame = talloc_stackframe();
++
++	err = ndr_pull_struct_blob(&response, frame, &v2_resp,
++		(ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
++	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
++		NTSTATUS status;
++		status = ndr_map_error2ntstatus(err);
++		DEBUG(2,("Failed to parse NTLMv2_RESPONSE "
++			 "length %u - %s - %s\n",
++			 (unsigned)response.length,
++			 ndr_map_error2string(err),
++			 nt_errstr(status)));
++		dump_data(2, response.data, response.length);
++		TALLOC_FREE(frame);
++		return status;
++	}
++
++	if (DEBUGLVL(10)) {
++		NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
++	}
++
++	/*
++	 * Make sure the netbios computer name in the
++	 * NTLMv2_RESPONSE matches the computer name
++	 * in the secure channel credentials for workstation
++	 * trusts.
++	 *
++	 * And the netbios domain name matches our
++	 * workgroup.
++	 *
++	 * This prevents workstations from requesting
++	 * the session key of NTLMSSP sessions of clients
++	 * to other hosts.
++	 */
++	if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
++		av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
++					       MsvAvNbComputerName);
++		av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
++					       MsvAvNbDomainName);
++	}
++
++	if (av_nb_cn != NULL) {
++		const char *v = NULL;
++		char *a = NULL;
++		size_t len;
++
++		v = av_nb_cn->Value.AvNbComputerName;
++
++		a = talloc_strdup(frame, creds->account_name);
++		if (a == NULL) {
++			TALLOC_FREE(frame);
++			return NT_STATUS_NO_MEMORY;
++		}
++		len = strlen(a);
++		if (len > 0 && a[len - 1] == '$') {
++			a[len - 1] = '\0';
++		}
++
++#ifdef SAMBA4_INTERNAL_HEIMDAL /* smbtorture4 for make test */
++		cmp = strcasecmp_m(a, v);
++#else /* smbd */
++		cmp = StrCaseCmp(a, v);
++#endif
++		if (cmp != 0) {
++			DEBUG(2,("%s: NTLMv2_RESPONSE with "
++				 "NbComputerName[%s] rejected "
++				 "for user[%s\\%s] "
++				 "against SEC_CHAN_WKSTA[%s/%s] "
++				 "in workgroup[%s]\n",
++				 __func__, v,
++				 account_domain,
++				 account_name,
++				 creds->computer_name,
++				 creds->account_name,
++				 workgroup));
++			TALLOC_FREE(frame);
++			return NT_STATUS_LOGON_FAILURE;
++		}
++	}
++	if (av_nb_dn != NULL) {
++		const char *v = NULL;
++
++		v = av_nb_dn->Value.AvNbDomainName;
++
++#ifdef SAMBA4_INTERNAL_HEIMDAL /* smbtorture4 for make test */
++		cmp = strcasecmp_m(workgroup, v);
++#else /* smbd */
++		cmp = StrCaseCmp(workgroup, v);
++#endif
++		if (cmp != 0) {
++			DEBUG(2,("%s: NTLMv2_RESPONSE with "
++				 "NbDomainName[%s] rejected "
++				 "for user[%s\\%s] "
++				 "against SEC_CHAN_WKSTA[%s/%s] "
++				 "in workgroup[%s]\n",
++				 __func__, v,
++				 account_domain,
++				 account_name,
++				 creds->computer_name,
++				 creds->account_name,
++				 workgroup));
++			TALLOC_FREE(frame);
++			return NT_STATUS_LOGON_FAILURE;
++		}
++	}
++
++	TALLOC_FREE(frame);
++	return NT_STATUS_OK;
++}
++
+ /***********************************************************
+  encode a password buffer with a unicode password.  The buffer
+  is filled with random data to make it harder to attack.
+--- a/libcli/auth/wscript_build
++++ b/libcli/auth/wscript_build
+@@ -19,7 +19,7 @@ bld.SAMBA_SUBSYSTEM('MSRPC_PARSE',
+ 
+ bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
+ 	source='credentials.c session.c smbencrypt.c smbdes.c',
+-	public_deps='MSRPC_PARSE',
++	public_deps='MSRPC_PARSE NDR_NTLMSSP',
+ 	public_headers='credentials.h:domain_credentials.h'
+ 	)
+ 
+--- a/source3/Makefile.in
++++ b/source3/Makefile.in
+@@ -783,6 +783,7 @@ GROUPDB_OBJ = groupdb/mapping.o groupdb/
+ PROFILE_OBJ = profile/profile.o
+ PROFILES_OBJ = utils/profiles.o \
+ 	       $(LIBSMB_ERR_OBJ) \
++	       $(LIBNDR_NTLMSSP_OBJ) \
+ 	       $(PARAM_OBJ) \
+                $(LIB_OBJ) $(LIB_DUMMY_OBJ) \
+                $(POPT_LIB_OBJ) \
+@@ -995,10 +996,10 @@ SWAT_OBJ = $(SWAT_OBJ1) $(PARAM_OBJ) $(P
+ STATUS_OBJ = utils/status.o utils/status_profile.o \
+ 	     $(LOCKING_OBJ) $(PARAM_OBJ) \
+              $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+-	     $(LIBSMB_ERR_OBJ) $(FNAME_UTIL_OBJ)
++	     $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(FNAME_UTIL_OBJ)
+ 
+ SMBCONTROL_OBJ = utils/smbcontrol.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+-	$(LIBSMB_ERR_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
++	$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
+ 
+ SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \
+              $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_OBJ) \
+@@ -1012,11 +1013,11 @@ SMBTREE_OBJ = utils/smbtree.o $(PARAM_OB
+ 
+ TESTPARM_OBJ = utils/testparm.o \
+                $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
+-	       $(LIBSMB_ERR_OBJ)
++	       $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
+ 
+ SMBTA_UTIL_OBJ = utils/smbta-util.o $(PARAM_OBJ) $(POPT_LIB_OBJ) \
+ 	$(LIB_NONSMBD_OBJ) \
+-	$(LIBSMB_ERR_OBJ) $(FNAME_UTIL_OBJ)
++	$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(FNAME_UTIL_OBJ)
+ 
+ TEST_LP_LOAD_OBJ = param/test_lp_load.o \
+ 		   $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+@@ -1146,6 +1147,7 @@ SMBCONFTORT_OBJ = $(SMBCONFTORT_OBJ0) \
+ 		  $(LIB_NONSMBD_OBJ) \
+ 		  $(PARAM_OBJ) \
+ 		  $(LIBSMB_ERR_OBJ) \
++		  $(LIBNDR_NTLMSSP_OBJ) \
+ 		  $(POPT_LIB_OBJ)
+ 
+ PTHREADPOOLTEST_OBJ = lib/pthreadpool/pthreadpool.o \
+@@ -1229,7 +1231,7 @@ CUPS_OBJ = client/smbspool.o $(PARAM_OBJ
+ 	  $(LIBNDR_GEN_OBJ0)
+ 
+ NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(LIBNMB_OBJ) \
+-               $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ)
++               $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
+ 
+ SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
+ 		torture/denytest.o torture/mangle_test.o \
+@@ -1253,6 +1255,7 @@ MASKTEST_OBJ = torture/masktest.o $(PARA
+ 		 $(LIBNDR_GEN_OBJ0)
+ 
+ MSGTEST_OBJ = torture/msgtest.o $(PARAM_OBJ) $(LIBSMB_ERR_OBJ) \
++		 $(LIBNDR_NTLMSSP_OBJ) \
+                  $(LIB_NONSMBD_OBJ) \
+ 		 $(LIBNDR_GEN_OBJ0)
+ 
+@@ -1269,7 +1272,7 @@ PDBTEST_OBJ = torture/pdbtest.o $(PARAM_
+ 
+ VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
+ 
+-SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ)
++SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
+ 
+ LOG2PCAP_OBJ = utils/log2pcaphex.o
+ 
+@@ -1297,17 +1300,17 @@ SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LI
+ EVTLOGADM_OBJ0	= utils/eventlogadm.o
+ 
+ EVTLOGADM_OBJ	= $(EVTLOGADM_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+-		$(LIBSMB_ERR_OBJ) $(LIB_EVENTLOG_OBJ) \
++		$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(LIB_EVENTLOG_OBJ) \
+ 		librpc/gen_ndr/ndr_eventlog.o \
+ 		librpc/gen_ndr/ndr_lsa.o
+ 
+ SHARESEC_OBJ0 = utils/sharesec.o
+ SHARESEC_OBJ  = $(SHARESEC_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
+-		$(LIBSMB_ERR_OBJ) \
++		$(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) \
+                 $(POPT_LIB_OBJ)
+ 
+ TALLOCTORT_OBJ = @tallocdir@/testsuite.o @tallocdir@/testsuite_main.o \
+-		$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ)
++		$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
+ 
+ REPLACETORT_OBJ = @libreplacedir@/test/testsuite.o \
+ 		@libreplacedir@/test/getifaddrs.o \
+@@ -1323,7 +1326,7 @@ SMBFILTER_OBJ = utils/smbfilter.o $(PARA
+ 		 $(LIBNDR_GEN_OBJ0)
+ 
+ WINBIND_WINS_NSS_OBJ = ../nsswitch/wins.o $(PARAM_OBJ) \
+-	$(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNMB_OBJ)
++	$(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(LIBNMB_OBJ)
+ 
+ PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
+ 		pam_smbpass/pam_smb_acct.o pam_smbpass/support.o ../lib/util/asn1.o
+@@ -1531,12 +1534,14 @@ RPC_OPEN_TCP_OBJ = torture/rpc_open_tcp.
+ DBWRAP_TOOL_OBJ = utils/dbwrap_tool.o \
+ 		  $(PARAM_OBJ) \
+ 		  $(LIB_NONSMBD_OBJ) \
+-		  $(LIBSMB_ERR_OBJ)
++		  $(LIBSMB_ERR_OBJ) \
++		  $(LIBNDR_NTLMSSP_OBJ)
+ 
+ DBWRAP_TORTURE_OBJ = utils/dbwrap_torture.o \
+ 		     $(PARAM_OBJ) \
+ 		     $(LIB_NONSMBD_OBJ) \
+ 		     $(LIBSMB_ERR_OBJ) \
++		     $(LIBNDR_NTLMSSP_OBJ) \
+ 		     $(POPT_LIB_OBJ)
+ 
+ SPLIT_TOKENS_OBJ = utils/split_tokens.o \
+--- a/source4/torture/raw/samba3misc.c
++++ b/source4/torture/raw/samba3misc.c
+@@ -340,6 +340,7 @@ bool torture_samba3_badpath(struct tortu
+ 	bool ret = true;
+ 	TALLOC_CTX *mem_ctx;
+ 	bool nt_status_support;
++	bool client_ntlmv2_auth;
+ 
+ 	if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
+ 		d_printf("talloc_init failed\n");
+@@ -347,20 +348,17 @@ bool torture_samba3_badpath(struct tortu
+ 	}
+ 
+ 	nt_status_support = lpcfg_nt_status_support(torture->lp_ctx);
++	client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(torture->lp_ctx);
+ 
+-	if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes")) {
+-		printf("Could not set 'nt status support = yes'\n");
+-		goto fail;
+-	}
++	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n");
++	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "yes"), ret, fail, "Could not set 'client ntlmv2 auth = yes'\n");
+ 
+ 	if (!torture_open_connection(&cli_nt, torture, 0)) {
+ 		goto fail;
+ 	}
+ 
+-	if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no")) {
+-		printf("Could not set 'nt status support = yes'\n");
+-		goto fail;
+-	}
++	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n");
++	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "no"), ret, fail, "Could not set 'client ntlmv2 auth = no'\n");
+ 
+ 	if (!torture_open_connection(&cli_dos, torture, 1)) {
+ 		goto fail;
+@@ -373,6 +371,12 @@ bool torture_samba3_badpath(struct tortu
+ 	}
+ 
+ 	smbcli_deltree(cli_nt->tree, dirname);
++	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support",
++						       nt_status_support ? "yes":"no"),
++			    ret, fail, "Could not set 'nt status support' back to where it was\n");
++	torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth",
++						       client_ntlmv2_auth ? "yes":"no"),
++			    ret, fail, "Could not set 'client ntlmv2 auth' back to where it was\n");
+ 
+ 	status = smbcli_mkdir(cli_nt->tree, dirname);
+ 	if (!NT_STATUS_IS_OK(status)) {
+--- a/source4/torture/basic/base.c
++++ b/source4/torture/basic/base.c
+@@ -1476,6 +1476,7 @@ static bool torture_chkpath_test(struct
+ static bool torture_samba3_errorpaths(struct torture_context *tctx)
+ {
+ 	bool nt_status_support;
++	bool client_ntlmv2_auth;
+ 	struct smbcli_state *cli_nt = NULL, *cli_dos = NULL;
+ 	bool result = false;
+ 	int fnum;
+@@ -1485,18 +1486,27 @@ static bool torture_samba3_errorpaths(st
+ 	NTSTATUS status;
+ 
+ 	nt_status_support = lpcfg_nt_status_support(tctx->lp_ctx);
++	client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(tctx->lp_ctx);
+ 
+ 	if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "yes")) {
+ 		torture_comment(tctx, "Could not set 'nt status support = yes'\n");
+ 		goto fail;
+ 	}
++	if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "yes")) {
++		torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = yes'\n");
++		goto fail;
++	}
+ 
+ 	if (!torture_open_connection(&cli_nt, tctx, 0)) {
+ 		goto fail;
+ 	}
+ 
+ 	if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "no")) {
+-		torture_comment(tctx, "Could not set 'nt status support = yes'\n");
++		torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = no'\n");
++		goto fail;
++	}
++	if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "no")) {
++		torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = no'\n");
+ 		goto fail;
+ 	}
+ 
+@@ -1506,7 +1516,12 @@ static bool torture_samba3_errorpaths(st
+ 
+ 	if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support",
+ 			    nt_status_support ? "yes":"no")) {
+-		torture_comment(tctx, "Could not reset 'nt status support = yes'");
++		torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support'");
++		goto fail;
++	}
++	if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth",
++			       client_ntlmv2_auth ? "yes":"no")) {
++		torture_result(tctx, TORTURE_FAIL, "Could not reset 'client ntlmv2 auth'");
+ 		goto fail;
+ 	}
+ 
+--- a/source3/libsmb/cliconnect.c
++++ b/source3/libsmb/cliconnect.c
+@@ -2077,6 +2077,17 @@ NTSTATUS cli_session_setup(struct cli_st
+ 		NTSTATUS status;
+ 
+ 		/* otherwise do a NT1 style session setup */
++		if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) {
++			/*
++			 * Don't send an NTLMv2 response without NTLMSSP
++			 * if we want to use spnego support
++			 */
++			DEBUG(1, ("Server does not support EXTENDED_SECURITY "
++				  " but 'client use spnego = yes"
++				  " and 'client ntlmv2 auth = yes'\n"));
++			return NT_STATUS_ACCESS_DENIED;
++		}
++
+ 		status = cli_session_setup_nt1(cli, user, pass, passlen,
+ 					       ntpass, ntpasslen, workgroup);
+ 		if (!NT_STATUS_IS_OK(status)) {
+--- a/docs-xml/smbdotconf/protocol/clientusespnego.xml
++++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml
+@@ -9,6 +9,11 @@
+     supporting servers (including WindowsXP, Windows2000 and Samba
+     3.0) to agree upon an authentication
+     mechanism.  This enables Kerberos authentication in particular.</para>
++
++    <para>When <smbconfoption name="client NTLMv2 auth"/> is also set to
++    <constant>yes</constant> extended security (SPNEGO) is required
++    in order to use NTLMv2 only within NTLMSSP. This behavior was
++    introduced with the patches for CVE-2016-2111.</para>
+ </description>
+ 
+ <value type="default">yes</value>
+--- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml
++++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
+@@ -28,6 +28,11 @@
+     NTLMv2 by default, and some sites (particularly those following
+     'best practice' security polices) only allow NTLMv2 responses, and
+     not the weaker LM or NTLM.</para>
++
++    <para>When <smbconfoption name="client use spnego"/> is also set to
++    <constant>yes</constant> extended security (SPNEGO) is required
++    in order to use NTLMv2 only within NTLMSSP. This behavior was
++    introduced with the patches for CVE-2016-2111.</para>
+ </description>
+ <value type="default">yes</value>
+ </samba:parameter>
+--- /dev/null
++++ b/docs-xml/smbdotconf/security/rawntlmv2auth.xml
+@@ -0,0 +1,19 @@
++<samba:parameter name="raw NTLMv2 auth"
++                 context="G"
++                 type="boolean"
++                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
++<description>
++    <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle>
++    <manvolnum>8</manvolnum></citerefentry> will allow SMB1 clients without
++    extended security (without SPNEGO) to use NTLMv2 authentication.</para>
++
++    <para>If this option, <command moreinfo="none">lanman auth</command>
++    and <command moreinfo="none">ntlm auth</command> are all disabled,
++    then only clients with SPNEGO support will be permitted.
++    That means NTLMv2 is only supported within NTLMSSP.</para>
++</description>
++
++<related>lanman auth</related>
++<related>ntlm auth</related>
++<value type="default">no</value>
++</samba:parameter>
+--- a/source3/include/proto.h
++++ b/source3/include/proto.h
+@@ -1489,6 +1489,7 @@ bool lp_map_untrusted_to_domain(void);
+ int lp_restrict_anonymous(void);
+ bool lp_lanman_auth(void);
+ bool lp_ntlm_auth(void);
++bool lp_raw_ntlmv2_auth(void);
+ bool lp_client_plaintext_auth(void);
+ bool lp_client_lanman_auth(void);
+ bool lp_client_ntlmv2_auth(void);
+--- a/source3/param/loadparm.c
++++ b/source3/param/loadparm.c
+@@ -336,6 +336,7 @@ struct global {
+ 	bool bAllowTrustedDomains;
+ 	bool bLanmanAuth;
+ 	bool bNTLMAuth;
++	bool bRawNTLMv2Auth;
+ 	bool bUseSpnego;
+ 	bool bClientLanManAuth;
+ 	bool bClientNTLMv2Auth;
+@@ -1383,6 +1384,15 @@ static struct parm_struct parm_table[] =
+ 		.flags		= FLAG_ADVANCED,
+ 	},
+ 	{
++		.label		= "raw NTLMv2 auth",
++		.type		= P_BOOL,
++		.p_class	= P_GLOBAL,
++		.ptr		= &Globals.bRawNTLMv2Auth,
++		.special	= NULL,
++		.enum_list	= NULL,
++		.flags		= FLAG_ADVANCED,
++	},
++	{
+ 		.label		= "client NTLMv2 auth",
+ 		.type		= P_BOOL,
+ 		.p_class	= P_GLOBAL,
+@@ -5337,6 +5347,7 @@ static void init_globals(bool reinit_glo
+ 	Globals.bClientPlaintextAuth = False;	/* Do NOT use a plaintext password even if is requested by the server */
+ 	Globals.bLanmanAuth = False;	/* Do NOT use the LanMan hash, even if it is supplied */
+ 	Globals.bNTLMAuth = True;	/* Do use NTLMv1 if it is supplied by the client (otherwise NTLMv2) */
++	Globals.bRawNTLMv2Auth = false;	/* Allow NTLMv2 without NTLMSSP */
+ 	Globals.bClientNTLMv2Auth = True; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */
+ 	/* Note, that we will also use NTLM2 session security (which is different), if it is available */
+ 
+@@ -5819,6 +5830,7 @@ FN_GLOBAL_BOOL(lp_map_untrusted_to_domai
+ FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous)
+ FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
+ FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
++FN_GLOBAL_BOOL(lp_raw_ntlmv2_auth, &Globals.bRawNTLMv2Auth)
+ FN_GLOBAL_BOOL(lp_client_plaintext_auth, &Globals.bClientPlaintextAuth)
+ FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
+ FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
+--- a/source3/auth/auth_util.c
++++ b/source3/auth/auth_util.c
+@@ -30,6 +30,7 @@
+ #include "../lib/util/util_pw.h"
+ #include "lib/winbind_util.h"
+ #include "passdb.h"
++#include "../lib/tsocket/tsocket.h"
+ 
+ #undef DBGC_CLASS
+ #define DBGC_CLASS DBGC_AUTH
+@@ -367,6 +368,19 @@ NTSTATUS make_user_info_for_reply_enc(st
+                                       const char *client_domain, 
+                                       DATA_BLOB lm_resp, DATA_BLOB nt_resp)
+ {
++	bool allow_raw = lp_raw_ntlmv2_auth();
++
++	if (!allow_raw && nt_resp.length >= 48) {
++		/*
++		 * NTLMv2_RESPONSE has at least 48 bytes
++		 * and should only be supported via NTLMSSP.
++		 */
++		DEBUG(2,("Rejecting raw NTLMv2 authentication with "
++			 "user [%s\\%s]\n",
++			 client_domain, smb_name));
++		return NT_STATUS_INVALID_PARAMETER;
++	}
++
+ 	return make_user_info_map(user_info, smb_name, 
+ 				  client_domain, 
+ 				  get_remote_machine_name(), 
+--- a/selftest/target/Samba3.pm
++++ b/selftest/target/Samba3.pm
+@@ -127,6 +127,7 @@ sub setup_dc($$)
+ 	domain master = yes
+ 	domain logons = yes
+ 	lanman auth = yes
++	raw NTLMv2 auth = yes
+ ";
+ 
+ 	my $vars = $self->provision($path,
+@@ -230,6 +231,7 @@ sub setup_secserver($$$)
+ 	my $secserver_options = "
+ 	security = server
+         password server = $s3dcvars->{SERVER_IP}
++	client ntlmv2 auth = no
+ ";
+ 
+ 	my $ret = $self->provision($prefix,
diff --git a/package/network/services/samba36/patches/025-CVE-2016-2112-v3-6.patch b/package/network/services/samba36/patches/025-CVE-2016-2112-v3-6.patch
new file mode 100644
index 0000000000..78e0a66979
--- /dev/null
+++ b/package/network/services/samba36/patches/025-CVE-2016-2112-v3-6.patch
@@ -0,0 +1,129 @@
+From 126e3e992bed7174d60ee19212db9b717647ab2e Mon Sep 17 00:00:00 2001
+From: Andreas Schneider <asn@cryptomilk.org>
+Date: Wed, 30 Mar 2016 16:55:44 +0200
+Subject: [PATCH 1/3] CVE-2016-2112: s3:ntlmssp: Implement missing
+ ntlmssp_have_feature()
+
+Signed-off-by: Andreas Schneider <asn@samba.org>
+---
+ source3/include/proto.h  |  1 +
+ source3/libsmb/ntlmssp.c | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+--- a/source3/include/proto.h
++++ b/source3/include/proto.h
+@@ -1260,6 +1260,7 @@ NTSTATUS ntlmssp_set_password(struct ntl
+ NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) ;
+ void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list);
+ void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature);
++bool ntlmssp_have_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature);
+ NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
+ 			const DATA_BLOB in, DATA_BLOB *out) ;
+ NTSTATUS ntlmssp_server_start(TALLOC_CTX *mem_ctx,
+--- a/source3/libsmb/ntlmssp.c
++++ b/source3/libsmb/ntlmssp.c
+@@ -162,6 +162,36 @@ NTSTATUS ntlmssp_set_domain(struct ntlms
+ 	return NT_STATUS_OK;
+ }
+ 
++bool ntlmssp_have_feature(struct ntlmssp_state *ntlmssp_state,
++			  uint32_t feature)
++{
++	if (feature & NTLMSSP_FEATURE_SIGN) {
++		if (ntlmssp_state->session_key.length == 0) {
++			return false;
++		}
++		if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
++			return true;
++		}
++	}
++
++	if (feature & NTLMSSP_FEATURE_SEAL) {
++		if (ntlmssp_state->session_key.length == 0) {
++			return false;
++		}
++		if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
++			return true;
++		}
++	}
++
++	if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
++		if (ntlmssp_state->session_key.length > 0) {
++			return true;
++		}
++	}
++
++	return false;
++}
++
+ /**
+  * Request features for the NTLMSSP negotiation
+  *
+--- a/source3/libads/sasl.c
++++ b/source3/libads/sasl.c
+@@ -261,6 +261,37 @@ static ADS_STATUS ads_sasl_spnego_ntlmss
+ 	/* we have a reference conter on ntlmssp_state, if we are signing
+ 	   then the state will be kept by the signing engine */
+ 
++	if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
++		bool ok;
++
++		ok = ntlmssp_have_feature(ntlmssp_state,
++					  NTLMSSP_FEATURE_SEAL);
++		if (!ok) {
++			DEBUG(0,("The ntlmssp feature sealing request, but unavailable\n"));
++			TALLOC_FREE(ntlmssp_state);
++			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
++		}
++
++		ok = ntlmssp_have_feature(ntlmssp_state,
++					  NTLMSSP_FEATURE_SIGN);
++		if (!ok) {
++			DEBUG(0,("The ntlmssp feature signing request, but unavailable\n"));
++			TALLOC_FREE(ntlmssp_state);
++			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
++		}
++
++	} else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
++		bool ok;
++
++		ok = ntlmssp_have_feature(ntlmssp_state,
++					  NTLMSSP_FEATURE_SIGN);
++		if (!ok) {
++			DEBUG(0,("The gensec feature signing request, but unavailable\n"));
++			TALLOC_FREE(ntlmssp_state);
++			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
++		}
++	}
++
+ 	if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
+ 		ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
+ 		ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
+--- a/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
++++ b/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
+@@ -34,11 +34,9 @@
+ 	</para>
+ 
+ 	<para>
+-	The default value is <emphasis>plain</emphasis> which is not irritable 
+-	to KRB5 clock skew errors. That implies synchronizing the time
+-	with the KDC in the case of using <emphasis>sign</emphasis> or 
+-	<emphasis>seal</emphasis>.
++	The default value is <emphasis>sign</emphasis>. That implies synchronizing the time
++	with the KDC in the case of using <emphasis>Kerberos</emphasis>.
+ 	</para>
+ </description>
+-<value type="default">plain</value>
++<value type="default">sign</value>
+ </samba:parameter>
+--- a/source3/param/loadparm.c
++++ b/source3/param/loadparm.c
+@@ -5392,6 +5392,8 @@ static void init_globals(bool reinit_glo
+ 	Globals.ldap_debug_level = 0;
+ 	Globals.ldap_debug_threshold = 10;
+ 
++	Globals.client_ldap_sasl_wrapping = ADS_AUTH_SASL_SIGN;
++
+ 	/* This is what we tell the afs client. in reality we set the token 
+ 	 * to never expire, though, when this runs out the afs client will 
+ 	 * forget the token. Set to 0 to get NEVERDATE.*/
diff --git a/package/network/services/samba36/patches/026-CVE-2016-2115-v3-6.patch b/package/network/services/samba36/patches/026-CVE-2016-2115-v3-6.patch
new file mode 100644
index 0000000000..5618fb4eff
--- /dev/null
+++ b/package/network/services/samba36/patches/026-CVE-2016-2115-v3-6.patch
@@ -0,0 +1,256 @@
+From 513bd34e4523e49e742487be32a7239111486a12 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Sat, 27 Feb 2016 03:43:58 +0100
+Subject: [PATCH 1/4] CVE-2016-2115: docs-xml: add "client ipc signing" option
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11756
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Reviewed-by: Ralph Boehme <slow@samba.org>
+---
+ docs-xml/smbdotconf/security/clientipcsigning.xml | 23 +++++++++++++++++++++++
+ docs-xml/smbdotconf/security/clientsigning.xml    |  3 +++
+ source3/include/proto.h                           |  1 +
+ source3/param/loadparm.c                          | 12 ++++++++++++
+ 4 files changed, 39 insertions(+)
+ create mode 100644 docs-xml/smbdotconf/security/clientipcsigning.xml
+
+--- /dev/null
++++ b/docs-xml/smbdotconf/security/clientipcsigning.xml
+@@ -0,0 +1,23 @@
++<samba:parameter name="client ipc signing"
++                 context="G"
++                 type="enum"
++                 enumlist="enum_smb_signing_vals"
++                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
++<description>
++    <para>This controls whether the client is allowed or required to use SMB signing for IPC$
++    connections as DCERPC transport inside of winbind. Possible values
++    are <emphasis>auto</emphasis>, <emphasis>mandatory</emphasis>
++    and <emphasis>disabled</emphasis>.
++    </para>
++
++    <para>When set to auto, SMB signing is offered, but not enforced and if set
++    to disabled, SMB signing is not offered either.</para>
++
++    <para>Connections from winbindd to Active Directory Domain Controllers
++    always enforce signing.</para>
++</description>
++
++<related>client signing</related>
++
++<value type="default">mandatory</value>
++</samba:parameter>
+--- a/docs-xml/smbdotconf/security/clientsigning.xml
++++ b/docs-xml/smbdotconf/security/clientsigning.xml
+@@ -12,6 +12,9 @@
+     <para>When set to auto, SMB signing is offered, but not enforced. 
+     When set to mandatory, SMB signing is required and if set 
+ 	to disabled, SMB signing is not offered either.
++
++    <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the
++    <smbconfoption name="client ipc signing"/> option.</para>
+ </para>
+ </description>
+ 
+--- a/source3/include/proto.h
++++ b/source3/include/proto.h
+@@ -1690,9 +1690,11 @@ int lp_winbind_cache_time(void);
+ int lp_winbind_reconnect_delay(void);
+ int lp_winbind_max_clients(void);
+ const char **lp_winbind_nss_info(void);
++bool lp_winbind_sealed_pipes(void);
+ int lp_algorithmic_rid_base(void);
+ int lp_name_cache_timeout(void);
+ int lp_client_signing(void);
++int lp_client_ipc_signing(void);
+ int lp_server_signing(void);
+ int lp_client_ldap_sasl_wrapping(void);
+ char *lp_parm_talloc_string(int snum, const char *type, const char *option, const char *def);
+--- a/source3/param/loadparm.c
++++ b/source3/param/loadparm.c
+@@ -215,6 +215,7 @@ struct global {
+ 	int  winbind_expand_groups;
+ 	bool bWinbindRefreshTickets;
+ 	bool bWinbindOfflineLogon;
++	bool bWinbindSealedPipes;
+ 	bool bWinbindNormalizeNames;
+ 	bool bWinbindRpcOnly;
+ 	bool bCreateKrb5Conf;
+@@ -366,6 +367,7 @@ struct global {
+ 	int restrict_anonymous;
+ 	int name_cache_timeout;
+ 	int client_signing;
++	int client_ipc_signing;
+ 	int server_signing;
+ 	int client_ldap_sasl_wrapping;
+ 	int iUsershareMaxShares;
+@@ -2319,6 +2321,15 @@ static struct parm_struct parm_table[] =
+ 		.flags		= FLAG_ADVANCED,
+ 	},
+ 	{
++		.label		= "client ipc signing",
++		.type		= P_ENUM,
++		.p_class	= P_GLOBAL,
++		.ptr		= &Globals.client_ipc_signing,
++		.special	= NULL,
++		.enum_list	= enum_smb_signing_vals,
++		.flags		= FLAG_ADVANCED,
++	},
++	{
+ 		.label		= "server signing",
+ 		.type		= P_ENUM,
+ 		.p_class	= P_GLOBAL,
+@@ -4765,6 +4776,15 @@ static struct parm_struct parm_table[] =
+ 		.flags		= FLAG_ADVANCED,
+ 	},
+ 	{
++		.label		= "winbind sealed pipes",
++		.type		= P_BOOL,
++		.p_class	= P_GLOBAL,
++		.ptr		= &Globals.bWinbindSealedPipes,
++		.special	= NULL,
++		.enum_list	= NULL,
++		.flags		= FLAG_ADVANCED,
++	},
++	{
+ 		.label		= "winbind normalize names",
+ 		.type		= P_BOOL,
+ 		.p_class	= P_GLOBAL,
+@@ -5458,6 +5478,7 @@ static void init_globals(bool reinit_glo
+ 	Globals.szWinbindNssInfo = str_list_make_v3(NULL, "template", NULL);
+ 	Globals.bWinbindRefreshTickets = False;
+ 	Globals.bWinbindOfflineLogon = False;
++	Globals.bWinbindSealedPipes = True;
+ 
+ 	Globals.iIdmapCacheTime = 86400 * 7; /* a week by default */
+ 	Globals.iIdmapNegativeCacheTime = 120; /* 2 minutes by default */
+@@ -5470,6 +5491,7 @@ static void init_globals(bool reinit_glo
+ 	Globals.bClientUseSpnego = True;
+ 
+ 	Globals.client_signing = Auto;
++	Globals.client_ipc_signing = Required;
+ 	Globals.server_signing = False;
+ 
+ 	Globals.bDeferSharingViolations = True;
+@@ -5736,6 +5758,7 @@ FN_GLOBAL_BOOL(lp_winbind_nested_groups,
+ FN_GLOBAL_INTEGER(lp_winbind_expand_groups, &Globals.winbind_expand_groups)
+ FN_GLOBAL_BOOL(lp_winbind_refresh_tickets, &Globals.bWinbindRefreshTickets)
+ FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
++FN_GLOBAL_BOOL(lp_winbind_sealed_pipes, &Globals.bWinbindSealedPipes)
+ FN_GLOBAL_BOOL(lp_winbind_normalize_names, &Globals.bWinbindNormalizeNames)
+ FN_GLOBAL_BOOL(lp_winbind_rpc_only, &Globals.bWinbindRpcOnly)
+ FN_GLOBAL_BOOL(lp_create_krb5_conf, &Globals.bCreateKrb5Conf)
+@@ -6071,6 +6094,7 @@ FN_GLOBAL_LIST(lp_winbind_nss_info, &Glo
+ FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
+ FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
+ FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
++FN_GLOBAL_INTEGER(lp_client_ipc_signing, &Globals.client_ipc_signing)
+ FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
+ FN_GLOBAL_INTEGER(lp_client_ldap_sasl_wrapping, &Globals.client_ldap_sasl_wrapping)
+ 
+@@ -9700,6 +9724,20 @@ static bool lp_load_ex(const char *pszFn
+ 		lp_do_parameter(GLOBAL_SECTION_SNUM, "wins server", "127.0.0.1");
+ 	}
+ 
++	if (!lp_is_in_client()) {
++		switch (lp_client_ipc_signing()) {
++		case Required:
++			lp_set_cmdline("client signing", "mandatory");
++			break;
++		case Auto:
++			lp_set_cmdline("client signing", "auto");
++			break;
++		case False:
++			lp_set_cmdline("client signing", "disabled");
++			break;
++		}
++	}
++
+ 	init_iconv();
+ 
+ 	bAllowIncludeRegistry = true;
+--- a/source3/rpc_server/spoolss/srv_spoolss_nt.c
++++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c
+@@ -2480,7 +2480,7 @@ static bool spoolss_connect_to_client(st
+ 		"", /* username */
+ 		"", /* domain */
+ 		"", /* password */
+-		0, lp_client_signing());
++		0, False);
+ 
+ 	if ( !NT_STATUS_IS_OK( ret ) ) {
+ 		DEBUG(2,("spoolss_connect_to_client: connection to [%s] failed!\n",
+--- /dev/null
++++ b/docs-xml/smbdotconf/winbind/winbindsealedpipes.xml
+@@ -0,0 +1,15 @@
++<samba:parameter name="winbind sealed pipes"
++                 context="G"
++                 type="boolean"
++                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
++<description>
++	<para>This option controls whether any requests from winbindd to domain controllers
++		pipe will be sealed. Disabling sealing can be useful for debugging
++		purposes.</para>
++
++	<para>The behavior can be controlled per netbios domain
++	by using 'winbind sealed pipes:NETBIOSDOMAIN = no' as option.</para>
++</description>
++
++<value type="default">yes</value>
++</samba:parameter>
+--- a/source3/winbindd/winbindd_cm.c
++++ b/source3/winbindd/winbindd_cm.c
+@@ -2384,6 +2384,15 @@ NTSTATUS cm_connect_sam(struct winbindd_
+ 	TALLOC_FREE(conn->samr_pipe);
+ 
+  anonymous:
++	if (lp_winbind_sealed_pipes() && (IS_DC || domain->primary)) {
++		status = NT_STATUS_DOWNGRADE_DETECTED;
++		DEBUG(1, ("Unwilling to make SAMR connection to domain %s "
++			  "without connection level security, "
++			  "must set 'winbind sealed pipes = false' "
++			  "to proceed: %s\n",
++			  domain->name, nt_errstr(status)));
++		goto done;
++	}
+ 
+ 	/* Finally fall back to anonymous. */
+ 	status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr.syntax_id,
+@@ -2610,6 +2619,16 @@ NTSTATUS cm_connect_lsa(struct winbindd_
+ 
+  anonymous:
+ 
++	if (lp_winbind_sealed_pipes() && (IS_DC || domain->primary)) {
++		result = NT_STATUS_DOWNGRADE_DETECTED;
++		DEBUG(1, ("Unwilling to make LSA connection to domain %s "
++			  "without connection level security, "
++			  "must set 'winbind sealed pipes = false' "
++			  "to proceed: %s\n",
++			  domain->name, nt_errstr(result)));
++		goto done;
++	}
++
+ 	result = cli_rpc_pipe_open_noauth(conn->cli,
+ 					  &ndr_table_lsarpc.syntax_id,
+ 					  &conn->lsa_pipe);
+@@ -2749,7 +2768,18 @@ NTSTATUS cm_connect_netlogon(struct winb
+ 
+  no_schannel:
+ 	if ((lp_client_schannel() == False) ||
+-			((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
++		((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
++		if (lp_winbind_sealed_pipes() && (IS_DC || domain->primary)) {
++			result = NT_STATUS_DOWNGRADE_DETECTED;
++			DEBUG(1, ("Unwilling to make connection to domain %s "
++				  "without connection level security, "
++				  "must set 'winbind sealed pipes = false' "
++				  "to proceed: %s\n",
++				  domain->name, nt_errstr(result)));
++			TALLOC_FREE(netlogon_pipe);
++			invalidate_cm_connection(conn);
++			return result;
++		}
+ 		/*
+ 		 * NetSamLogonEx only works for schannel
+ 		 */
diff --git a/package/network/services/samba36/patches/027-CVE-2016-2118-v3-6.patch b/package/network/services/samba36/patches/027-CVE-2016-2118-v3-6.patch
new file mode 100644
index 0000000000..06c1b0b521
--- /dev/null
+++ b/package/network/services/samba36/patches/027-CVE-2016-2118-v3-6.patch
@@ -0,0 +1,308 @@
+From d68424b5ef92f5810760f90e9eeb664572a61e4e Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Tue, 15 Dec 2015 14:49:36 +0100
+Subject: [PATCH 01/10] CVE-2016-2118: s3: rpcclient: change the default auth
+ level from DCERPC_AUTH_LEVEL_CONNECT to DCERPC_AUTH_LEVEL_INTEGRITY
+
+ncacn_ip_tcp:server should get the same protection as ncacn_np:server
+if authentication and smb signing is used.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11616
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+
+(cherry picked from commit dab41dee8a4fb27dbf3913b0e44a4cc726e3ac98)
+---
+ source3/rpcclient/rpcclient.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -1062,10 +1062,9 @@ out_free:
+ 		}
+ 	}
+ 	if (pipe_default_auth_type != DCERPC_AUTH_TYPE_NONE) {
+-		/* If neither Integrity or Privacy are requested then
+-		 * Use just Connect level */
++		/* If nothing is requested then default to integrity */
+ 		if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
+-			pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
++			pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ 		}
+ 	}
+ 
+--- a/source4/librpc/rpc/dcerpc_util.c
++++ b/source4/librpc/rpc/dcerpc_util.c
+@@ -593,15 +593,15 @@ struct composite_context *dcerpc_pipe_au
+ 
+ 	/* Perform an authenticated DCE-RPC bind
+ 	 */
+-	if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
++	if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL))) {
+ 		/*
+ 		  we are doing an authenticated connection,
+-		  but not using sign or seal. We must force
+-		  the CONNECT dcerpc auth type as a NONE auth
+-		  type doesn't allow authentication
+-		  information to be passed.
++		  which needs to use [connect], [sign] or [seal].
++		  If nothing is specified, we default to [sign] now.
++		  This give roughly the same protection as
++		  ncacn_np with smb signing.
+ 		*/
+-		conn->flags |= DCERPC_CONNECT;
++		conn->flags |= DCERPC_SIGN;
+ 	}
+ 
+ 	if (s->binding->flags & DCERPC_AUTH_SPNEGO) {
+--- /dev/null
++++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml
+@@ -0,0 +1,22 @@
++<samba:parameter name="allow dcerpc auth level connect"
++                 context="G"
++                 type="boolean"
++                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
++<description>
++	<para>This option controls whether DCERPC services are allowed to
++	be used with DCERPC_AUTH_LEVEL_CONNECT, which provides authentication,
++	but no per message integrity nor privacy protection.</para>
++
++	<para>The behavior can be controlled per interface name (e.g. lsarpc, netlogon, samr, srvsvc,
++	winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = no' as option.</para>
++
++	<para>This option yields precedence to the implentation specific restrictions.
++	E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY.
++	While others like samr and lsarpc have a hardcoded default of <constant>no</constant>.
++	</para>
++</description>
++
++<value type="default">no</value>
++<value type="example">yes</value>
++
++</samba:parameter>
+--- a/source3/include/proto.h
++++ b/source3/include/proto.h
+@@ -1821,6 +1821,7 @@ char* lp_perfcount_module(void);
+ void lp_set_passdb_backend(const char *backend);
+ void widelinks_warning(int snum);
+ char *lp_ncalrpc_dir(void);
++bool lp_allow_dcerpc_auth_level_connect(void);
+ 
+ /* The following definitions come from param/loadparm_server_role.c  */
+ 
+--- a/source3/param/loadparm.c
++++ b/source3/param/loadparm.c
+@@ -355,6 +355,7 @@ struct global {
+ 	bool bUseMmap;
+ 	bool bHostnameLookups;
+ 	bool bUnixExtensions;
++	bool bAllowDcerpcAuthLevelConnect;
+ 	bool bDisableNetbios;
+ 	char * szDedicatedKeytabFile;
+ 	int  iKerberosMethod;
+@@ -2303,6 +2304,15 @@ static struct parm_struct parm_table[] =
+ 		.flags		= FLAG_ADVANCED,
+ 	},
+ 	{
++		.label		= "allow dcerpc auth level connect",
++		.type		= P_BOOL,
++		.p_class	= P_GLOBAL,
++		.ptr		= &Globals.bAllowDcerpcAuthLevelConnect,
++		.special	= NULL,
++		.enum_list	= NULL,
++		.flags		= FLAG_ADVANCED,
++	},
++	{
+ 		.label		= "use spnego",
+ 		.type		= P_BOOL,
+ 		.p_class	= P_GLOBAL,
+@@ -5371,6 +5381,8 @@ static void init_globals(bool reinit_glo
+ 	Globals.bClientNTLMv2Auth = True; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */
+ 	/* Note, that we will also use NTLM2 session security (which is different), if it is available */
+ 
++	Globals.bAllowDcerpcAuthLevelConnect = false; /* we don't allow this by default */
++
+ 	Globals.map_to_guest = 0;	/* By Default, "Never" */
+ 	Globals.oplock_break_wait_time = 0;	/* By Default, 0 msecs. */
+ 	Globals.enhanced_browsing = true;
+@@ -5745,6 +5757,7 @@ FN_GLOBAL_INTEGER(lp_username_map_cache_
+ 
+ FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript)
+ 
++FN_GLOBAL_BOOL(lp_allow_dcerpc_auth_level_connect, &Globals.bAllowDcerpcAuthLevelConnect)
+ FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
+ FN_GLOBAL_CONST_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
+ FN_GLOBAL_CONST_STRING(lp_template_shell, &Globals.szTemplateShell)
+--- a/source3/include/ntdomain.h
++++ b/source3/include/ntdomain.h
+@@ -89,6 +89,10 @@ typedef struct pipe_rpc_fns {
+ 	uint32 context_id;
+ 	struct ndr_syntax_id syntax;
+ 
++	/*
++	 * shall we allow "connect" auth level for this interface ?
++	 */
++	bool allow_connect;
+ } PIPE_RPC_FNS;
+ 
+ /*
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -44,6 +44,11 @@
+ #include "rpc_server/srv_pipe.h"
+ #include "../librpc/gen_ndr/ndr_dcerpc.h"
+ #include "../librpc/ndr/ndr_dcerpc.h"
++#include "../librpc/gen_ndr/ndr_samr.h"
++#include "../librpc/gen_ndr/ndr_lsa.h"
++#include "../librpc/gen_ndr/ndr_netlogon.h"
++#include "../librpc/gen_ndr/ndr_epmapper.h"
++#include "../librpc/gen_ndr/ndr_echo.h"
+ 
+ #undef DBGC_CLASS
+ #define DBGC_CLASS DBGC_RPC_SRV
+@@ -340,6 +345,8 @@ static bool check_bind_req(struct pipes_
+ 			   uint32 context_id)
+ {
+ 	struct pipe_rpc_fns *context_fns;
++	const char *interface_name = NULL;
++	bool ok;
+ 
+ 	DEBUG(3,("check_bind_req for %s\n",
+ 		 get_pipe_name_from_syntax(talloc_tos(), abstract)));
+@@ -390,12 +397,57 @@ static bool check_bind_req(struct pipes_
+ 		return False;
+ 	}
+ 
++	interface_name = get_pipe_name_from_syntax(talloc_tos(),
++						   abstract);
++
++	SMB_ASSERT(interface_name != NULL);
++
+ 	context_fns->next = context_fns->prev = NULL;
+ 	context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract);
+ 	context_fns->cmds = rpc_srv_get_pipe_cmds(abstract);
+ 	context_fns->context_id = context_id;
+ 	context_fns->syntax = *abstract;
+ 
++	context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect();
++	/*
++	 * for the samr and the lsarpc interfaces we don't allow "connect"
++	 * auth_level by default.
++	 */
++	ok = ndr_syntax_id_equal(abstract, &ndr_table_samr.syntax_id);
++	if (ok) {
++		context_fns->allow_connect = false;
++	}
++	ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
++	if (ok) {
++		context_fns->allow_connect = false;
++	}
++	ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
++	if (ok) {
++		context_fns->allow_connect = false;
++	}
++	/*
++	 * for the epmapper and echo interfaces we allow "connect"
++	 * auth_level by default.
++	 */
++	ok = ndr_syntax_id_equal(abstract, &ndr_table_epmapper.syntax_id);
++	if (ok) {
++		context_fns->allow_connect = true;
++	}
++	ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id);
++	if (ok) {
++		context_fns->allow_connect = true;
++	}
++	/*
++	 * every interface can be modified to allow "connect" auth_level by
++	 * using a parametric option like:
++	 * allow dcerpc auth level connect:<interface>
++	 * e.g.
++	 * allow dcerpc auth level connect:samr = yes
++	 */
++	context_fns->allow_connect = lp_parm_bool(-1,
++		"allow dcerpc auth level connect",
++		interface_name, context_fns->allow_connect);
++
+ 	/* add to the list of open contexts */
+ 
+ 	DLIST_ADD( p->contexts, context_fns );
+@@ -1736,6 +1788,7 @@ static bool api_pipe_request(struct pipe
+ 	TALLOC_CTX *frame = talloc_stackframe();
+ 	bool ret = False;
+ 	PIPE_RPC_FNS *pipe_fns;
++	const char *interface_name = NULL;
+ 
+ 	if (!p->pipe_bound) {
+ 		DEBUG(1, ("Pipe not bound!\n"));
+@@ -1757,8 +1810,36 @@ static bool api_pipe_request(struct pipe
+ 		return false;
+ 	}
+ 
++	interface_name = get_pipe_name_from_syntax(talloc_tos(),
++						   &pipe_fns->syntax);
++
++	SMB_ASSERT(interface_name != NULL);
++
+ 	DEBUG(5, ("Requested \\PIPE\\%s\n",
+-		  get_pipe_name_from_syntax(talloc_tos(), &pipe_fns->syntax)));
++		  interface_name));
++
++	switch (p->auth.auth_level) {
++	case DCERPC_AUTH_LEVEL_NONE:
++	case DCERPC_AUTH_LEVEL_INTEGRITY:
++	case DCERPC_AUTH_LEVEL_PRIVACY:
++		break;
++	default:
++		if (!pipe_fns->allow_connect) {
++			DEBUG(1, ("%s: restrict auth_level_connect access "
++				  "to [%s] with auth[type=0x%x,level=0x%x] "
++				  "on [%s] from [%s]\n",
++				  __func__, interface_name,
++				  p->auth.auth_type,
++				  p->auth.auth_level,
++				  derpc_transport_string_by_transport(p->transport),
++				  p->client_id->name));
++
++			setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
++			TALLOC_FREE(frame);
++			return true;
++		}
++		break;
++	}
+ 
+ 	if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
+ 		DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
+--- a/source3/selftest/knownfail
++++ b/source3/selftest/knownfail
+@@ -18,3 +18,5 @@ samba3.posix_s3.nbt.dgram.*netlogon2
+ samba3.*rap.sam.*.useradd # Not provided by Samba 3
+ samba3.*rap.sam.*.userdelete # Not provided by Samba 3
+ samba3.*rap.basic.*.netsessiongetinfo # Not provided by Samba 3
++samba3.blackbox.rpcclient.over.ncacn_np.with.*connect.* # we don't allow auth_level_connect anymore
++samba3.posix_s3.rpc.lsa.lookupsids.*ncacn_ip_tcp.*connect.* # we don't allow auth_level_connect anymore
+--- a/source3/selftest/tests.py
++++ b/source3/selftest/tests.py
+@@ -201,6 +201,8 @@ if sub.returncode == 0:
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD')
+         elif t == "raw.samba3posixtimedlock":
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/dc/share')
++        elif t == "rpc.samr.passwords.validate":
++            plansmbtorturetestsuite(t, "s3dc", 'ncacn_np:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_np ')
+         else:
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
+ 
+--- a/source3/rpc_server/samr/srv_samr_nt.c
++++ b/source3/rpc_server/samr/srv_samr_nt.c
+@@ -6628,6 +6628,11 @@ NTSTATUS _samr_ValidatePassword(struct p
+ 	struct samr_GetDomPwInfo pw;
+ 	struct samr_PwInfo dom_pw_info;
+ 
++	if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
++		p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
++		return NT_STATUS_ACCESS_DENIED;
++	}
++
+ 	if (r->in.level < 1 || r->in.level > 3) {
+ 		return NT_STATUS_INVALID_INFO_CLASS;
+ 	}
diff --git a/package/network/services/samba36/patches/100-configure_fixes.patch b/package/network/services/samba36/patches/100-configure_fixes.patch
new file mode 100644
index 0000000000..16e35c8049
--- /dev/null
+++ b/package/network/services/samba36/patches/100-configure_fixes.patch
@@ -0,0 +1,14 @@
+--- a/source3/configure
++++ b/source3/configure
+@@ -13294,10 +13294,7 @@ if test x"$libreplace_cv_HAVE_GETADDRINF
+ 	# see bug 5910, use our replacements if we detect
+ 	# a broken system.
+ 	if test "$cross_compiling" = yes; then :
+-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "cannot run test program while cross compiling
+-See \`config.log' for more details" "$LINENO" 5; }
++		$as_echo "assuming valid getaddrinfo without bug 5910" >&2
+ else
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h.  */
diff --git a/package/network/services/samba36/patches/110-multicall.patch b/package/network/services/samba36/patches/110-multicall.patch
new file mode 100644
index 0000000000..98a03b654c
--- /dev/null
+++ b/package/network/services/samba36/patches/110-multicall.patch
@@ -0,0 +1,119 @@
+--- a/source3/Makefile.in
++++ b/source3/Makefile.in
+@@ -73,22 +73,22 @@ LDAP_LIBS=@LDAP_LIBS@
+ NSCD_LIBS=@NSCD_LIBS@
+ UUID_LIBS=@UUID_LIBS@
+ LIBWBCLIENT=@LIBWBCLIENT_STATIC@ @LIBWBCLIENT_SHARED@
+-LIBWBCLIENT_LIBS=@LIBWBCLIENT_LIBS@
++LIBWBCLIENT_LIBS=@LIBWBCLIENT_STATIC@
+ PTHREAD_LDFLAGS=@PTHREAD_LDFLAGS@
+ PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
+ DNSSD_LIBS=@DNSSD_LIBS@
+ AVAHI_LIBS=@AVAHI_LIBS@
+ POPT_LIBS=@POPTLIBS@
+ LIBTALLOC=@LIBTALLOC_STATIC@ @LIBTALLOC_SHARED@
+-LIBTALLOC_LIBS=@LIBTALLOC_LIBS@
++LIBTALLOC_LIBS=@LIBTALLOC_STATIC@
+ LIBTEVENT=@LIBTEVENT_STATIC@ @LIBTEVENT_SHARED@
+ LIBTEVENT_LIBS=@LIBTEVENT_LIBS@
+ LIBREPLACE_LIBS=@LIBREPLACE_LIBS@
+ LIBTDB=@LIBTDB_STATIC@ @LIBTDB_SHARED@
+-LIBTDB_LIBS=@LIBTDB_LIBS@
++LIBTDB_LIBS=@LIBTDB_STATIC@
+ TDB_DEPS=@TDB_DEPS@
+ LIBNETAPI=@LIBNETAPI_STATIC@ @LIBNETAPI_SHARED@
+-LIBNETAPI_LIBS=@LIBNETAPI_LIBS@
++LIBNETAPI_LIBS=@LIBNETAPI_STATIC@
+ LIBSMBCLIENT_LIBS=@LIBSMBCLIENT_LIBS@
+ LIBSMBSHAREMODES_LIBS=@LIBSMBSHAREMODES_LIBS@
+ 
+@@ -216,7 +216,7 @@ PATH_FLAGS = -DSMB_PASSWD_FILE=\"$(SMB_P
+ 
+ # Note that all executable programs now provide for an optional executable suffix.
+ 
+-SBIN_PROGS = bin/smbd@EXEEXT@ bin/nmbd@EXEEXT@ @SWAT_SBIN_TARGETS@ @EXTRA_SBIN_PROGS@
++SBIN_PROGS = bin/samba_multicall@EXEEXT@ bin/smbd@EXEEXT@ bin/nmbd@EXEEXT@ @SWAT_SBIN_TARGETS@ @EXTRA_SBIN_PROGS@
+ 
+ BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \
+ 	bin/testparm@EXEEXT@ bin/smbstatus@EXEEXT@ bin/smbget@EXEEXT@ \
+@@ -1799,6 +1799,42 @@ bin/.dummy:
+ 	  dir=bin $(MAKEDIR); fi
+ 	@: >> $@ || : > $@ # what a fancy emoticon!
+ 
++smbd/server_multicall.o: smbd/server.c smbd/server.o
++	@echo Compiling $<.c
++	@$(COMPILE_CC_PATH) -Dmain=smbd_main && exit 0;\
++		echo "The following command failed:" 1>&2;\
++		echo "$(COMPILE_CC_PATH)" 1>&2;\
++		$(COMPILE_CC_PATH) >/dev/null 2>&1
++
++nmbd/nmbd_multicall.o: nmbd/nmbd.c nmbd/nmbd.o
++	@echo Compiling $<.c
++	@$(COMPILE_CC_PATH) -Dmain=nmbd_main && exit 0;\
++		echo "The following command failed:" 1>&2;\
++		echo "$(COMPILE_CC_PATH)" 1>&2;\
++		$(COMPILE_CC_PATH) >/dev/null 2>&1
++
++utils/smbpasswd_multicall.o: utils/smbpasswd.c utils/smbpasswd.o
++	@echo Compiling $<.c
++	@$(COMPILE_CC_PATH) -Dmain=smbpasswd_main && exit 0;\
++		echo "The following command failed:" 1>&2;\
++		echo "$(COMPILE_CC_PATH)" 1>&2;\
++		$(COMPILE_CC_PATH) >/dev/null 2>&1
++
++SMBD_MULTI_O = $(patsubst smbd/server.o,smbd/server_multicall.o,$(SMBD_OBJ))
++NMBD_MULTI_O = $(patsubst nmbd/nmbd.o,nmbd/nmbd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(NMBD_OBJ)))
++SMBPASSWD_MULTI_O = $(patsubst utils/smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ)))
++MULTI_O = multi.o
++
++MULTICALL_O = $(sort $(SMBD_MULTI_O) $(NMBD_MULTI_O) $(SMBPASSWD_MULTI_O) $(MULTI_O))
++
++bin/samba_multicall@EXEEXT@: $(BINARY_PREREQS) $(MULTICALL_O) $(LIBTALLOC) $(LIBTDB) $(LIBWBCLIENT) @BUILD_POPT@
++	@echo Linking $@
++	@$(CC) -o $@ $(MULTICALL_O) $(LDFLAGS) $(LDAP_LIBS) @SMBD_FAM_LIBS@ \
++		$(KRB5LIBS) $(DYNEXP) $(PRINT_LIBS) $(AUTH_LIBS) \
++		$(ACL_LIBS) $(PASSDB_LIBS) $(LIBS) $(DNSSD_LIBS) $(AVAHI_LIBS) \
++		$(POPT_LIBS) @SMBD_LIBS@ $(LIBTALLOC_LIBS) $(LIBTEVENT_LIBS) $(LIBTDB_LIBS) \
++		$(LIBWBCLIENT_LIBS) $(ZLIB_LIBS)
++
+ bin/smbd@EXEEXT@: $(BINARY_PREREQS) $(SMBD_OBJ) $(LIBTALLOC) $(LIBTEVENT) $(LIBTDB) $(LIBWBCLIENT) @BUILD_POPT@
+ 	@echo Linking $@
+ 	@$(CC) -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LDAP_LIBS) @SMBD_FAM_LIBS@ \
+--- /dev/null
++++ b/source3/multi.c
+@@ -0,0 +1,35 @@
++#include <stdio.h>
++#include <string.h>
++
++extern int smbd_main(int argc, char **argv);
++extern int nmbd_main(int argc, char **argv);
++extern int smbpasswd_main(int argc, char **argv);
++
++static struct {
++	const char *name;
++	int (*func)(int argc, char **argv);
++} multicall[] = {
++	{ "smbd", smbd_main },
++	{ "nmbd", nmbd_main },
++	{ "smbpasswd", smbpasswd_main },
++};
++
++#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
++
++int main(int argc, char **argv)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(multicall); i++) {
++		if (strstr(argv[0], multicall[i].name))
++			return multicall[i].func(argc, argv);
++	}
++
++	fprintf(stderr, "Invalid multicall command, available commands:");
++	for (i = 0; i < ARRAY_SIZE(multicall); i++)
++		fprintf(stderr, " %s", multicall[i].name);
++
++	fprintf(stderr, "\n");
++
++	return 1;
++}
diff --git a/package/network/services/samba36/patches/111-owrt_smbpasswd.patch b/package/network/services/samba36/patches/111-owrt_smbpasswd.patch
new file mode 100644
index 0000000000..40b34e9a77
--- /dev/null
+++ b/package/network/services/samba36/patches/111-owrt_smbpasswd.patch
@@ -0,0 +1,281 @@
+--- a/source3/Makefile.in
++++ b/source3/Makefile.in
+@@ -1025,7 +1025,7 @@ TEST_LP_LOAD_OBJ = param/test_lp_load.o
+ 
+ PASSWD_UTIL_OBJ = utils/passwd_util.o
+ 
+-SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \
++SMBPASSWD_OBJ = utils/owrt_smbpasswd.o $(PASSWD_UTIL_OBJ) $(PASSCHANGE_OBJ) \
+ 		$(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) \
+ 		$(GROUPDB_OBJ) $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \
+ 		$(POPT_LIB_OBJ) $(SMBLDAP_OBJ) \
+@@ -1813,7 +1813,7 @@ nmbd/nmbd_multicall.o: nmbd/nmbd.c nmbd/
+ 		echo "$(COMPILE_CC_PATH)" 1>&2;\
+ 		$(COMPILE_CC_PATH) >/dev/null 2>&1
+ 
+-utils/smbpasswd_multicall.o: utils/smbpasswd.c utils/smbpasswd.o
++utils/smbpasswd_multicall.o: utils/owrt_smbpasswd.c utils/owrt_smbpasswd.o
+ 	@echo Compiling $<.c
+ 	@$(COMPILE_CC_PATH) -Dmain=smbpasswd_main && exit 0;\
+ 		echo "The following command failed:" 1>&2;\
+@@ -1822,7 +1822,7 @@ utils/smbpasswd_multicall.o: utils/smbpa
+ 
+ SMBD_MULTI_O = $(patsubst smbd/server.o,smbd/server_multicall.o,$(SMBD_OBJ))
+ NMBD_MULTI_O = $(patsubst nmbd/nmbd.o,nmbd/nmbd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(NMBD_OBJ)))
+-SMBPASSWD_MULTI_O = $(patsubst utils/smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ)))
++SMBPASSWD_MULTI_O = $(patsubst utils/owrt_smbpasswd.o,utils/smbpasswd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(SMBPASSWD_OBJ)))
+ MULTI_O = multi.o
+ 
+ MULTICALL_O = $(sort $(SMBD_MULTI_O) $(NMBD_MULTI_O) $(SMBPASSWD_MULTI_O) $(MULTI_O))
+--- /dev/null
++++ b/source3/utils/owrt_smbpasswd.c
+@@ -0,0 +1,249 @@
++/*
++ * Copyright (C) 2012 Felix Fietkau <nbd@nbd.name>
++ * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 675
++ * Mass Ave, Cambridge, MA 02139, USA.  */
++
++#include "includes.h"
++#include <endian.h>
++#include <stdio.h>
++
++static char buf[256];
++
++static void md4hash(const char *passwd, uchar p16[16])
++{
++	int len;
++	smb_ucs2_t wpwd[129];
++	int i;
++
++	len = strlen(passwd);
++	for (i = 0; i < len; i++) {
++#if __BYTE_ORDER == __LITTLE_ENDIAN
++		wpwd[i] = (unsigned char)passwd[i];
++#else
++		wpwd[i] = (unsigned char)passwd[i] << 8;
++#endif
++	}
++	wpwd[i] = 0;
++
++	len = len * sizeof(int16);
++	mdfour(p16, (unsigned char *)wpwd, len);
++	ZERO_STRUCT(wpwd);
++}
++
++
++static bool find_passwd_line(FILE *fp, const char *user, char **next)
++{
++	char *p1;
++
++	while (!feof(fp)) {
++		if(!fgets(buf, sizeof(buf) - 1, fp))
++			continue;
++
++		p1 = strchr(buf, ':');
++
++		if (p1 - buf != strlen(user))
++			continue;
++
++		if (strncmp(buf, user, p1 - buf) != 0)
++			continue;
++
++		if (next)
++			*next = p1;
++		return true;
++	}
++	return false;
++}
++
++/* returns -1 if user is not present in /etc/passwd*/
++static int find_uid_for_user(const char *user)
++{
++	FILE *fp;
++	char *p1, *p2, *p3;
++	int ret = -1;
++
++	fp = fopen("/etc/passwd", "r");
++	if (!fp) {
++		printf("failed to open /etc/passwd");
++		goto out;
++	}
++
++	if (!find_passwd_line(fp, user, &p1)) {
++		printf("User %s not found or invalid in /etc/passwd\n", user);
++		goto out;
++	}
++
++	p2 = strchr(p1 + 1, ':');
++	if (!p2)
++		goto out;
++
++	p2++;
++	p3 = strchr(p2, ':');
++	if (!p1)
++		goto out;
++
++	*p3 = '\0';
++	ret = atoi(p2);
++
++out:
++	if(fp)
++		fclose(fp);
++	return ret;
++}
++
++static void smbpasswd_write_user(FILE *fp, const char *user, int uid, const char *password)
++{
++	static uchar nt_p16[NT_HASH_LEN];
++	int len = 0;
++	int i;
++
++	md4hash(strdup(password), nt_p16);
++
++	len += snprintf(buf + len, sizeof(buf) - len, "%s:%u:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:", user, uid);
++	for(i = 0; i < NT_HASH_LEN; i++)
++		len += snprintf(buf + len, sizeof(buf) - len, "%02X", nt_p16[i]);
++
++	snprintf(buf + len, sizeof(buf) - len, ":[U          ]:LCT-00000001:\n");
++	fputs(buf, fp);
++}
++
++static void smbpasswd_delete_user(FILE *fp)
++{
++	fpos_t r_pos, w_pos;
++	int len = strlen(buf);
++
++	fgetpos(fp, &r_pos);
++	fseek(fp, -len, SEEK_CUR);
++	fgetpos(fp, &w_pos);
++	fsetpos(fp, &r_pos);
++
++	while (fgets(buf, sizeof(buf) - 1, fp)) {
++		int cur_len = strlen(buf);
++
++		fsetpos(fp, &w_pos);
++		fputs(buf, fp);
++		fgetpos(fp, &w_pos);
++
++		fsetpos(fp, &r_pos);
++		fseek(fp, cur_len, SEEK_CUR);
++		fgetpos(fp, &r_pos);
++	}
++
++	fsetpos(fp, &w_pos);
++	ftruncate(fileno(fp), ftello(fp));
++}
++
++static int usage(const char *progname)
++{
++	fprintf(stderr,
++		"Usage: %s [options] <username>\n"
++		"\n"
++		"Options:\n"
++		"  -s		read password from stdin\n"
++		"  -a		add user\n"
++		"  -x		delete user\n",
++		progname);
++	return 1;
++}
++
++int main(int argc, char **argv)
++{
++	const char *prog = argv[0];
++	const char *user;
++	char *pw1, *pw2;
++	FILE *fp;
++	bool add = false, delete = false, get_stdin = false, found;
++	int ch;
++	int uid;
++
++	TALLOC_CTX *frame = talloc_stackframe();
++
++	while ((ch = getopt(argc, argv, "asx")) != EOF) {
++		switch (ch) {
++		case 's':
++			get_stdin = true;
++			break;
++		case 'a':
++			add = true;
++			break;
++		case 'x':
++			delete = true;
++			break;
++		default:
++			return usage(prog);
++		}
++	}
++
++	if (add && delete)
++		return usage(prog);
++
++	argc -= optind;
++	argv += optind;
++
++	if (!argc)
++		return usage(prog);
++
++	user = argv[0];
++	if (!delete) {
++		uid = find_uid_for_user(user);
++		if (uid < 0) {
++			fprintf(stderr, "Could not find user '%s' in /etc/passwd\n", user);
++			return 2;
++		}
++	}
++
++	fp = fopen("/etc/samba/smbpasswd", "r+");
++	if(!fp) {
++		fprintf(stderr, "Failed to open /etc/samba/smbpasswd");
++		return 3;
++	}
++
++	found = find_passwd_line(fp, user, NULL);
++	if (!add && !found) {
++		fprintf(stderr, "Could not find user '%s' in /etc/samba/smbpasswd\n", user);
++		return 3;
++	}
++
++	if (delete) {
++		smbpasswd_delete_user(fp);
++		goto out;
++	}
++
++	pw1 = get_pass("New SMB password:", get_stdin);
++	if (!pw1)
++		pw1 = strdup("");
++
++	pw2 = get_pass("Retype SMB password:", get_stdin);
++	if (!pw2)
++		pw2 = strdup("");
++
++	if (strcmp(pw1, pw2) != 0) {
++		fprintf(stderr, "Mismatch - password unchanged.\n");
++		goto out_free;
++	}
++
++	if (found)
++		fseek(fp, -strlen(buf), SEEK_CUR);
++	smbpasswd_write_user(fp, user, uid, pw2);
++
++out_free:
++	free(pw1);
++	free(pw2);
++out:
++	fclose(fp);
++	TALLOC_FREE(frame);
++
++	return 0;
++}
diff --git a/package/network/services/samba36/patches/120-add_missing_ifdef.patch b/package/network/services/samba36/patches/120-add_missing_ifdef.patch
new file mode 100644
index 0000000000..3c0ef8ab3f
--- /dev/null
+++ b/package/network/services/samba36/patches/120-add_missing_ifdef.patch
@@ -0,0 +1,41 @@
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -119,9 +119,11 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_netdfs)) {
+ 		return false;
+ 	}
++#ifdef DEVELOPER
+ 	if (!smb_register_ndr_interface(&ndr_table_rpcecho)) {
+ 		return false;
+ 	}
++#endif
+ 	if (!smb_register_ndr_interface(&ndr_table_initshutdown)) {
+ 		return false;
+ 	}
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -628,7 +628,9 @@ static struct cmd_set *rpcclient_command
+ 	netlogon_commands,
+ 	srvsvc_commands,
+ 	dfs_commands,
++#ifdef DEVELOPER
+ 	echo_commands,
++#endif
+ 	epmapper_commands,
+ 	shutdown_commands,
+  	test_commands,
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -433,10 +433,12 @@ static bool check_bind_req(struct pipes_
+ 	if (ok) {
+ 		context_fns->allow_connect = true;
+ 	}
++#ifdef DEVELOPER
+ 	ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id);
+ 	if (ok) {
+ 		context_fns->allow_connect = true;
+ 	}
++#endif
+ 	/*
+ 	 * every interface can be modified to allow "connect" auth_level by
+ 	 * using a parametric option like:
diff --git a/package/network/services/samba36/patches/200-remove_printer_support.patch b/package/network/services/samba36/patches/200-remove_printer_support.patch
new file mode 100644
index 0000000000..de567a7627
--- /dev/null
+++ b/package/network/services/samba36/patches/200-remove_printer_support.patch
@@ -0,0 +1,346 @@
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -1110,6 +1110,10 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 					   "rpc_server",
+ 					   "spoolss",
+ 					   "embedded");
++#ifndef PRINTER_SUPPORT
++	if (1) {
++	} else
++#endif
+ 	if (StrCaseCmp(rpcsrv_type, "embedded") == 0) {
+ 		spoolss_cb.init         = spoolss_init_cb;
+ 		spoolss_cb.shutdown     = spoolss_shutdown_cb;
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -624,7 +624,9 @@ static struct cmd_set *rpcclient_command
+ 	lsarpc_commands,
+ 	ds_commands,
+ 	samr_commands,
++#ifdef PRINTER_SUPPORT
+ 	spoolss_commands,
++#endif
+ 	netlogon_commands,
+ 	srvsvc_commands,
+ 	dfs_commands,
+--- a/source3/printing/spoolssd.c
++++ b/source3/printing/spoolssd.c
+@@ -165,6 +165,10 @@ void start_spoolssd(struct tevent_contex
+ 	NTSTATUS status;
+ 	int ret;
+ 
++#ifndef PRINTER_SUPPORT
++	return;
++#endif
++
+ 	DEBUG(1, ("Forking SPOOLSS Daemon\n"));
+ 
+ 	pid = sys_fork();
+--- a/source3/utils/net_rpc.c
++++ b/source3/utils/net_rpc.c
+@@ -7841,6 +7841,10 @@ int net_rpc_printer(struct net_context *
+ 		{NULL, NULL, 0, NULL, NULL}
+ 	};
+ 
++#ifndef PRINTER_SUPPORT
++	return 0;
++#endif
++
+ 	if (argc == 0) {
+ 		if (c->display_usage) {
+ 			d_printf(_("Usage:\n"));
+--- a/source3/smbd/reply.c
++++ b/source3/smbd/reply.c
+@@ -5208,7 +5208,11 @@ void reply_printopen(struct smb_request
+ 		return;
+ 	}
+ 
+-	if (!CAN_PRINT(conn)) {
++
++#ifdef PRINTER_SUPPORT
++	if (!CAN_PRINT(conn))
++#endif
++	{
+ 		reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ 		END_PROFILE(SMBsplopen);
+ 		return;
+@@ -5314,7 +5318,10 @@ void reply_printqueue(struct smb_request
+ 	   is really quite gross and only worked when there was only
+ 	   one printer - I think we should now only accept it if they
+ 	   get it right (tridge) */
+-	if (!CAN_PRINT(conn)) {
++#ifdef PRINTER_SUPPORT
++	if (!CAN_PRINT(conn))
++#endif
++	{
+ 		reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ 		END_PROFILE(SMBsplretq);
+ 		return;
+--- a/source3/smbd/lanman.c
++++ b/source3/smbd/lanman.c
+@@ -784,6 +784,10 @@ static bool api_DosPrintQGetInfo(struct
+ 	union spoolss_JobInfo *job_info = NULL;
+ 	union spoolss_PrinterInfo printer_info;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -999,6 +1003,10 @@ static bool api_DosPrintQEnum(struct smb
+ 	union spoolss_DriverInfo *driver_info;
+ 	union spoolss_JobInfo **job_info;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!param_format || !output_format1 || !p) {
+ 		return False;
+ 	}
+@@ -3105,6 +3113,10 @@ static bool api_RDosPrintJobDel(struct s
+ 	struct spoolss_DevmodeContainer devmode_ctr;
+ 	enum spoolss_JobControl command;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -3238,6 +3250,10 @@ static bool api_WPrintQueueCtrl(struct s
+ 	struct sec_desc_buf secdesc_ctr;
+ 	enum spoolss_PrinterControl command;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !QueueName) {
+ 		return False;
+ 	}
+@@ -3404,6 +3420,10 @@ static bool api_PrintJobInfo(struct smbd
+ 	union spoolss_JobInfo info;
+ 	struct spoolss_SetJobInfo1 info1;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -4547,6 +4567,10 @@ static bool api_WPrintJobGetInfo(struct
+ 	struct spoolss_DevmodeContainer devmode_ctr;
+ 	union spoolss_JobInfo info;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -4685,6 +4709,10 @@ static bool api_WPrintJobEnumerate(struc
+ 	uint32_t count = 0;
+ 	union spoolss_JobInfo *info;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -4890,6 +4918,10 @@ static bool api_WPrintDestGetInfo(struct
+ 	struct spoolss_DevmodeContainer devmode_ctr;
+ 	union spoolss_PrinterInfo info;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -5026,6 +5058,10 @@ static bool api_WPrintDestEnum(struct sm
+ 	union spoolss_PrinterInfo *info;
+ 	uint32_t count;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -5129,6 +5165,10 @@ static bool api_WPrintDriverEnum(struct
+ 	int succnt;
+ 	struct pack_desc desc;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -5193,6 +5233,10 @@ static bool api_WPrintQProcEnum(struct s
+ 	int succnt;
+ 	struct pack_desc desc;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -5257,6 +5301,10 @@ static bool api_WPrintPortEnum(struct sm
+ 	int succnt;
+ 	struct pack_desc desc;
+ 
++#ifndef PRINTER_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -141,7 +141,9 @@ static void exit_server_common(enum serv
+ 		rpc_eventlog_shutdown();
+ 		rpc_ntsvcs_shutdown();
+ 		rpc_svcctl_shutdown();
++#ifdef PRINTER_SUPPORT
+ 		rpc_spoolss_shutdown();
++#endif
+ 
+ 		rpc_srvsvc_shutdown();
+ 		rpc_winreg_shutdown();
+--- a/source3/smbd/open.c
++++ b/source3/smbd/open.c
+@@ -1608,6 +1608,9 @@ static NTSTATUS open_file_ntcreate(conne
+ 		 * Most of the passed parameters are ignored.
+ 		 */
+ 
++#ifndef PRINTER_SUPPORT
++		return NT_STATUS_ACCESS_DENIED;
++#endif
+ 		if (pinfo) {
+ 			*pinfo = FILE_WAS_CREATED;
+ 		}
+--- a/source3/smbd/close.c
++++ b/source3/smbd/close.c
+@@ -643,6 +643,9 @@ static NTSTATUS close_normal_file(struct
+ 	status = ntstatus_keeperror(status, tmp);
+ 
+ 	if (fsp->print_file) {
++#ifndef PRINTER_SUPPORT
++		return NT_STATUS_OK;
++#endif
+ 		/* FIXME: return spool errors */
+ 		print_spool_end(fsp, close_type);
+ 		file_free(req, fsp);
+--- a/source3/smbd/fileio.c
++++ b/source3/smbd/fileio.c
+@@ -298,6 +298,10 @@ ssize_t write_file(struct smb_request *r
+ 		uint32_t t;
+ 		int ret;
+ 
++#ifndef PRINTER_SUPPORT
++		return -1;
++#endif
++
+ 		ret = print_spool_write(fsp, data, n, pos, &t);
+ 		if (ret) {
+ 			errno = ret;
+--- a/source3/smbd/smb2_create.c
++++ b/source3/smbd/smb2_create.c
+@@ -486,7 +486,10 @@ static struct tevent_req *smbd_smb2_crea
+ 		info = FILE_WAS_OPENED;
+ 	} else if (CAN_PRINT(smb1req->conn)) {
+ 		status = file_new(smb1req, smb1req->conn, &result);
+-		if(!NT_STATUS_IS_OK(status)) {
++#ifdef PRINTER_SUPPORT
++		if(!NT_STATUS_IS_OK(status))
++#endif
++		{
+ 			tevent_req_nterror(req, status);
+ 			return tevent_req_post(req, ev);
+ 		}
+--- a/source3/rpc_server/svcctl/srv_svcctl_nt.c
++++ b/source3/rpc_server/svcctl/srv_svcctl_nt.c
+@@ -85,9 +85,11 @@ bool init_service_op_table( void )
+ 
+ 	/* add builtin services */
+ 
++#ifdef PRINTER_SUPPORT
+ 	svcctl_ops[i].name = talloc_strdup( svcctl_ops, "Spooler" );
+ 	svcctl_ops[i].ops  = &spoolss_svc_ops;
+ 	i++;
++#endif
+ 
+ 	svcctl_ops[i].name = talloc_strdup( svcctl_ops, "NETLOGON" );
+ 	svcctl_ops[i].ops  = &netlogon_svc_ops;
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -113,9 +113,11 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_winreg)) {
+ 		return false;
+ 	}
++#ifdef PRINTER_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_spoolss)) {
+ 		return false;
+ 	}
++#endif
+ 	if (!smb_register_ndr_interface(&ndr_table_netdfs)) {
+ 		return false;
+ 	}
+--- a/source3/smbd/process.c
++++ b/source3/smbd/process.c
+@@ -2423,8 +2423,10 @@ static bool housekeeping_fn(const struct
+ 
+ 	change_to_root_user();
+ 
++#ifdef PRINTER_SUPPORT
+ 	/* update printer queue caches if necessary */
+ 	update_monitored_printq_cache(sconn->msg_ctx);
++#endif
+ 
+ 	/* check if we need to reload services */
+ 	check_reload(sconn, time_mono(NULL));
+--- a/source3/smbd/server.c
++++ b/source3/smbd/server.c
+@@ -123,7 +123,9 @@ static void smb_pcap_updated(struct mess
+ {
+ 	struct tevent_context *ev_ctx =
+ 		talloc_get_type_abort(private_data, struct tevent_context);
+-
++#ifndef PRINTER_SUPPORT
++	return;
++#endif
+ 	DEBUG(10,("Got message saying pcap was updated. Reloading.\n"));
+ 	change_to_root_user();
+ 	reload_printers(ev_ctx, msg);
+@@ -1277,6 +1279,7 @@ extern void build_options(bool screen);
+ 	 * The print backend init also migrates the printing tdb's,
+ 	 * this requires a winreg pipe.
+ 	 */
++#ifdef PRINTER_SUPPORT
+ 	if (!print_backend_init(smbd_messaging_context()))
+ 		exit(1);
+ 
+@@ -1315,7 +1318,7 @@ extern void build_options(bool screen);
+ 				       smbd_messaging_context());
+ 		}
+ 	}
+-
++#endif
+ 	if (!is_daemon) {
+ 		/* inetd mode */
+ 		TALLOC_FREE(frame);
diff --git a/package/network/services/samba36/patches/210-remove_ad_support.patch b/package/network/services/samba36/patches/210-remove_ad_support.patch
new file mode 100644
index 0000000000..a2051869a1
--- /dev/null
+++ b/package/network/services/samba36/patches/210-remove_ad_support.patch
@@ -0,0 +1,88 @@
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -95,9 +95,11 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_lsarpc)) {
+ 		return false;
+ 	}
++#ifdef ACTIVE_DIRECTORY
+ 	if (!smb_register_ndr_interface(&ndr_table_dssetup)) {
+ 		return false;
+ 	}
++#endif
+ 	if (!smb_register_ndr_interface(&ndr_table_samr)) {
+ 		return false;
+ 	}
+@@ -141,9 +143,11 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_epmapper)) {
+ 		return false;
+ 	}
++#ifdef ACTIVE_DIRECTORY
+ 	if (!smb_register_ndr_interface(&ndr_table_drsuapi)) {
+ 		return false;
+ 	}
++#endif
+ 	return true;
+ }
+ 
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -918,6 +918,7 @@ static bool netdfs_init_cb(void *ptr)
+ 	return true;
+ }
+ 
++#ifdef ACTIVE_DIRECTORY
+ static bool dssetup_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -966,6 +967,7 @@ static bool dssetup_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ static bool wkssvc_init_cb(void *ptr)
+ {
+@@ -1172,12 +1174,14 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 	}
+ #endif
+ 
++#ifdef ACTIVE_DIRECTORY
+ 	dssetup_cb.init         = dssetup_init_cb;
+ 	dssetup_cb.shutdown     = NULL;
+ 	dssetup_cb.private_data = ep_ctx;
+ 	if (!NT_STATUS_IS_OK(rpc_dssetup_init(&dssetup_cb))) {
+ 		return false;
+ 	}
++#endif
+ 
+ 	wkssvc_cb.init         = wkssvc_init_cb;
+ 	wkssvc_cb.shutdown     = NULL;
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -132,7 +132,9 @@ static void exit_server_common(enum serv
+ 
+ 	if (am_parent) {
+ 		rpc_wkssvc_shutdown();
++#ifdef ACTIVE_DIRECTORY
+ 		rpc_dssetup_shutdown();
++#endif
+ #ifdef DEVELOPER
+ 		rpc_rpcecho_shutdown();
+ #endif
+--- a/source3/rpc_client/cli_pipe.c
++++ b/source3/rpc_client/cli_pipe.c
+@@ -3391,12 +3391,14 @@ NTSTATUS cli_rpc_pipe_open_noauth_transp
+ 	status = rpc_pipe_bind(result, auth);
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		int lvl = 0;
++#ifdef ACTIVE_DIRECTORY
+ 		if (ndr_syntax_id_equal(interface,
+ 					&ndr_table_dssetup.syntax_id)) {
+ 			/* non AD domains just don't have this pipe, avoid
+ 			 * level 0 statement in that case - gd */
+ 			lvl = 3;
+ 		}
++#endif
+ 		DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
+ 			    "%s failed with error %s\n",
+ 			    get_pipe_name_from_syntax(talloc_tos(), interface),
diff --git a/package/network/services/samba36/patches/220-remove_services.patch b/package/network/services/samba36/patches/220-remove_services.patch
new file mode 100644
index 0000000000..498232dee2
--- /dev/null
+++ b/package/network/services/samba36/patches/220-remove_services.patch
@@ -0,0 +1,98 @@
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -131,6 +131,7 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_initshutdown)) {
+ 		return false;
+ 	}
++#ifdef EXTRA_SERVICES
+ 	if (!smb_register_ndr_interface(&ndr_table_svcctl)) {
+ 		return false;
+ 	}
+@@ -140,6 +141,7 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_ntsvcs)) {
+ 		return false;
+ 	}
++#endif
+ 	if (!smb_register_ndr_interface(&ndr_table_epmapper)) {
+ 		return false;
+ 	}
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -697,6 +697,7 @@ static bool spoolss_shutdown_cb(void *pt
+ 	return true;
+ }
+ 
++#ifdef EXTRA_SERVICES
+ static bool svcctl_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -733,6 +734,7 @@ static bool svcctl_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ static bool svcctl_shutdown_cb(void *ptr)
+ {
+@@ -741,6 +743,8 @@ static bool svcctl_shutdown_cb(void *ptr
+ 	return true;
+ }
+ 
++#ifdef EXTRA_SERVICES
++
+ static bool ntsvcs_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -802,6 +806,7 @@ static bool eventlog_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ static bool initshutdown_init_cb(void *ptr)
+ {
+@@ -1130,6 +1135,7 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 		}
+ 	}
+ 
++#ifdef EXTRA_SERVICES
+ 	svcctl_cb.init         = svcctl_init_cb;
+ 	svcctl_cb.shutdown     = svcctl_shutdown_cb;
+ 	svcctl_cb.private_data = ep_ctx;
+@@ -1150,6 +1156,7 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 	if (!NT_STATUS_IS_OK(rpc_eventlog_init(&eventlog_cb))) {
+ 		return false;
+ 	}
++#endif
+ 
+ 	initshutdown_cb.init         = initshutdown_init_cb;
+ 	initshutdown_cb.shutdown     = NULL;
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -140,9 +140,11 @@ static void exit_server_common(enum serv
+ #endif
+ 		rpc_netdfs_shutdown();
+ 		rpc_initshutdown_shutdown();
++#ifdef EXTRA_SERVICES
+ 		rpc_eventlog_shutdown();
+-		rpc_ntsvcs_shutdown();
+ 		rpc_svcctl_shutdown();
++		rpc_ntsvcs_shutdown();
++#endif
+ #ifdef PRINTER_SUPPORT
+ 		rpc_spoolss_shutdown();
+ #endif
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -637,9 +637,11 @@ static struct cmd_set *rpcclient_command
+ 	shutdown_commands,
+  	test_commands,
+ 	wkssvc_commands,
++#ifdef EXTRA_SERVICES
+ 	ntsvcs_commands,
+ 	drsuapi_commands,
+ 	eventlog_commands,
++#endif
+ 	winreg_commands,
+ 	NULL
+ };
diff --git a/package/network/services/samba36/patches/230-remove_winreg_support.patch b/package/network/services/samba36/patches/230-remove_winreg_support.patch
new file mode 100644
index 0000000000..df2be4f222
--- /dev/null
+++ b/package/network/services/samba36/patches/230-remove_winreg_support.patch
@@ -0,0 +1,146 @@
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -409,6 +409,7 @@ static bool epmapper_shutdown_cb(void *p
+ 	return true;
+ }
+ 
++#ifdef WINREG_SUPPORT
+ static bool winreg_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -456,6 +457,7 @@ static bool winreg_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ static bool srvsvc_init_cb(void *ptr)
+ {
+@@ -710,10 +712,12 @@ static bool svcctl_init_cb(void *ptr)
+ 					   "epmapper",
+ 					   "none");
+ 
++#ifdef WINREG_SUPPORT
+ 	ok = svcctl_init_winreg(ep_ctx->msg_ctx);
+ 	if (!ok) {
+ 		return false;
+ 	}
++#endif
+ 
+ 	/* initialize the control hooks */
+ 	init_service_op_table();
+@@ -785,10 +789,12 @@ static bool eventlog_init_cb(void *ptr)
+ 					   "epmapper",
+ 					   "none");
+ 
++#ifdef WINREG_SUPPORT
+ 	ok = eventlog_init_winreg(ep_ctx->msg_ctx);
+ 	if (!ok) {
+ 		return false;
+ 	}
++#endif
+ 
+ 	if (StrCaseCmp(rpcsrv_type, "embedded") == 0 ||
+ 	    StrCaseCmp(rpcsrv_type, "daemon") == 0) {
+@@ -1077,12 +1083,14 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 		}
+ 	}
+ 
++#ifdef WINREG_SUPPORT
+ 	winreg_cb.init         = winreg_init_cb;
+ 	winreg_cb.shutdown     = NULL;
+ 	winreg_cb.private_data = ep_ctx;
+ 	if (!NT_STATUS_IS_OK(rpc_winreg_init(&winreg_cb))) {
+ 		return false;
+ 	}
++#endif
+ 
+ 	srvsvc_cb.init         = srvsvc_init_cb;
+ 	srvsvc_cb.shutdown     = NULL;
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -150,7 +150,9 @@ static void exit_server_common(enum serv
+ #endif
+ 
+ 		rpc_srvsvc_shutdown();
++#ifdef WINREG_SUPPORT
+ 		rpc_winreg_shutdown();
++#endif
+ 
+ 		rpc_netlogon_shutdown();
+ 		rpc_samr_shutdown();
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -112,9 +112,11 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_wkssvc)) {
+ 		return false;
+ 	}
++#ifdef WINREG_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_winreg)) {
+ 		return false;
+ 	}
++#endif
+ #ifdef PRINTER_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_spoolss)) {
+ 		return false;
+--- a/source3/rpc_server/svcctl/srv_svcctl_nt.c
++++ b/source3/rpc_server/svcctl/srv_svcctl_nt.c
+@@ -95,9 +95,11 @@ bool init_service_op_table( void )
+ 	svcctl_ops[i].ops  = &netlogon_svc_ops;
+ 	i++;
+ 
++#ifdef WINREG_SUPPORT
+ 	svcctl_ops[i].name = talloc_strdup( svcctl_ops, "RemoteRegistry" );
+ 	svcctl_ops[i].ops  = &winreg_svc_ops;
+ 	i++;
++#endif
+ 
+ 	svcctl_ops[i].name = talloc_strdup( svcctl_ops, "WINS" );
+ 	svcctl_ops[i].ops  = &wins_svc_ops;
+--- a/source3/services/svc_winreg_glue.c
++++ b/source3/services/svc_winreg_glue.c
+@@ -88,6 +88,10 @@ struct security_descriptor *svcctl_get_s
+ 	NTSTATUS status;
+ 	WERROR result = WERR_OK;
+ 
++#ifndef WINREG_SUPPORT
++	return NULL;
++#endif
++
+ 	key = talloc_asprintf(mem_ctx,
+ 			      "%s\\%s\\Security",
+ 			      TOP_LEVEL_SERVICES_KEY, name);
+@@ -161,6 +165,10 @@ bool svcctl_set_secdesc(struct messaging
+ 	NTSTATUS status;
+ 	WERROR result = WERR_OK;
+ 
++#ifndef WINREG_SUPPORT
++	return false;
++#endif
++
+ 	tmp_ctx = talloc_stackframe();
+ 	if (tmp_ctx == NULL) {
+ 		return false;
+@@ -272,6 +280,10 @@ const char *svcctl_get_string_value(TALL
+ 	NTSTATUS status;
+ 	WERROR result = WERR_OK;
+ 
++#ifndef WINREG_SUPPORT
++	return NULL;
++#endif
++
+ 	tmp_ctx = talloc_stackframe();
+ 	if (tmp_ctx == NULL) {
+ 		return NULL;
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -642,7 +642,9 @@ static struct cmd_set *rpcclient_command
+ 	drsuapi_commands,
+ 	eventlog_commands,
+ #endif
++#ifdef WINREG_SUPPORT
+ 	winreg_commands,
++#endif
+ 	NULL
+ };
+ 
diff --git a/package/network/services/samba36/patches/240-remove_dfs_api.patch b/package/network/services/samba36/patches/240-remove_dfs_api.patch
new file mode 100644
index 0000000000..f4d432e95d
--- /dev/null
+++ b/package/network/services/samba36/patches/240-remove_dfs_api.patch
@@ -0,0 +1,71 @@
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -881,6 +881,7 @@ static bool rpcecho_init_cb(void *ptr) {
+ 
+ #endif
+ 
++#ifdef DFS_SUPPORT
+ static bool netdfs_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -928,6 +929,7 @@ static bool netdfs_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ #ifdef ACTIVE_DIRECTORY
+ static bool dssetup_init_cb(void *ptr)
+@@ -1173,12 +1175,14 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 		return false;
+ 	}
+ 
++#ifdef DFS_SUPPORT
+ 	netdfs_cb.init         = netdfs_init_cb;
+ 	netdfs_cb.shutdown     = NULL;
+ 	netdfs_cb.private_data = ep_ctx;
+ 	if (!NT_STATUS_IS_OK(rpc_netdfs_init(&netdfs_cb))) {
+ 		return false;
+ 	}
++#endif
+ 
+ #ifdef DEVELOPER
+ 	rpcecho_cb.init         = rpcecho_init_cb;
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -122,9 +122,11 @@ static bool initialize_interfaces(void)
+ 		return false;
+ 	}
+ #endif
++#ifdef DFS_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_netdfs)) {
+ 		return false;
+ 	}
++#endif
+ #ifdef DEVELOPER
+ 	if (!smb_register_ndr_interface(&ndr_table_rpcecho)) {
+ 		return false;
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -138,7 +138,9 @@ static void exit_server_common(enum serv
+ #ifdef DEVELOPER
+ 		rpc_rpcecho_shutdown();
+ #endif
++#ifdef DFS_SUPPORT
+ 		rpc_netdfs_shutdown();
++#endif
+ 		rpc_initshutdown_shutdown();
+ #ifdef EXTRA_SERVICES
+ 		rpc_eventlog_shutdown();
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -629,7 +629,9 @@ static struct cmd_set *rpcclient_command
+ #endif
+ 	netlogon_commands,
+ 	srvsvc_commands,
++#ifdef DFS_SUPPORT
+ 	dfs_commands,
++#endif
+ #ifdef DEVELOPER
+ 	echo_commands,
+ #endif
diff --git a/package/network/services/samba36/patches/250-remove_domain_logon.patch b/package/network/services/samba36/patches/250-remove_domain_logon.patch
new file mode 100644
index 0000000000..9b434c515a
--- /dev/null
+++ b/package/network/services/samba36/patches/250-remove_domain_logon.patch
@@ -0,0 +1,213 @@
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -606,6 +606,7 @@ static bool samr_init_cb(void *ptr)
+ 	return true;
+ }
+ 
++#ifdef NETLOGON_SUPPORT
+ static bool netlogon_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -654,6 +655,7 @@ static bool netlogon_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ static bool spoolss_init_cb(void *ptr)
+ {
+@@ -1116,12 +1118,15 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 		return false;
+ 	}
+ 
++#ifdef NETLOGON_SUPPORT
+ 	netlogon_cb.init         = netlogon_init_cb;
+ 	netlogon_cb.shutdown     = NULL;
+ 	netlogon_cb.private_data = ep_ctx;
+ 	if (!NT_STATUS_IS_OK(rpc_netlogon_init(&netlogon_cb))) {
+ 		return false;
+ 	}
++#endif
++
+ 
+ 	rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
+ 					   "rpc_server",
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -103,9 +103,11 @@ static bool initialize_interfaces(void)
+ 	if (!smb_register_ndr_interface(&ndr_table_samr)) {
+ 		return false;
+ 	}
++#ifdef NETLOGON_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_netlogon)) {
+ 		return false;
+ 	}
++#endif
+ 	if (!smb_register_ndr_interface(&ndr_table_srvsvc)) {
+ 		return false;
+ 	}
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -156,7 +156,9 @@ static void exit_server_common(enum serv
+ 		rpc_winreg_shutdown();
+ #endif
+ 
++#ifdef NETLOGON_SUPPORT
+ 		rpc_netlogon_shutdown();
++#endif
+ 		rpc_samr_shutdown();
+ 		rpc_lsarpc_shutdown();
+ 	}
+--- a/source3/rpc_server/svcctl/srv_svcctl_nt.c
++++ b/source3/rpc_server/svcctl/srv_svcctl_nt.c
+@@ -91,9 +91,11 @@ bool init_service_op_table( void )
+ 	i++;
+ #endif
+ 
++#ifdef NETLOGON_SUPPORT
+ 	svcctl_ops[i].name = talloc_strdup( svcctl_ops, "NETLOGON" );
+ 	svcctl_ops[i].ops  = &netlogon_svc_ops;
+ 	i++;
++#endif
+ 
+ #ifdef WINREG_SUPPORT
+ 	svcctl_ops[i].name = talloc_strdup( svcctl_ops, "RemoteRegistry" );
+--- a/source3/nmbd/nmbd_processlogon.c
++++ b/source3/nmbd/nmbd_processlogon.c
+@@ -320,6 +320,10 @@ void process_logon_packet(struct packet_
+ 	NTSTATUS status;
+ 	const char *pdc_name;
+ 
++#ifndef NETLOGON_SUPPORT
++	return;
++#endif
++
+ 	in_addr_to_sockaddr_storage(&ss, p->ip);
+ 	pss = iface_ip((struct sockaddr *)&ss);
+ 	if (!pss) {
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -627,7 +627,9 @@ static struct cmd_set *rpcclient_command
+ #ifdef PRINTER_SUPPORT
+ 	spoolss_commands,
+ #endif
++#ifdef NETLOGON_SUPPORT
+ 	netlogon_commands,
++#endif
+ 	srvsvc_commands,
+ #ifdef DFS_SUPPORT
+ 	dfs_commands,
+--- a/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
++++ b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
+@@ -824,6 +824,10 @@ WERROR _wkssvc_NetrJoinDomain2(struct pi
+ 	WERROR werr;
+ 	struct security_token *token = p->session_info->security_token;
+ 
++#ifndef NETLOGON_SUPPORT
++	return WERR_NOT_SUPPORTED;
++#endif
++
+ 	if (!r->in.domain_name) {
+ 		return WERR_INVALID_PARAM;
+ 	}
+@@ -901,6 +905,10 @@ WERROR _wkssvc_NetrUnjoinDomain2(struct
+ 	WERROR werr;
+ 	struct security_token *token = p->session_info->security_token;
+ 
++#ifndef NETLOGON_SUPPORT
++	return WERR_NOT_SUPPORTED;
++#endif
++
+ 	if (!r->in.account || !r->in.encrypted_password) {
+ 		return WERR_INVALID_PARAM;
+ 	}
+--- a/source3/libsmb/trusts_util.c
++++ b/source3/libsmb/trusts_util.c
+@@ -46,9 +46,11 @@ NTSTATUS trust_pw_change_and_store_it(st
+ 	NTSTATUS nt_status;
+ 
+ 	switch (sec_channel_type) {
++#ifdef NETLOGON_SUPPORT
+ 	case SEC_CHAN_WKSTA:
+ 	case SEC_CHAN_DOMAIN:
+ 		break;
++#endif
+ 	default:
+ 		return NT_STATUS_NOT_SUPPORTED;
+ 	}
+@@ -159,6 +161,11 @@ bool enumerate_domain_trusts( TALLOC_CTX
+ 	*num_domains = 0;
+ 	*sids = NULL;
+ 
++#ifndef NETLOGON_SUPPORT
++	return False;
++#endif
++
++
+ 	/* lookup a DC first */
+ 
+ 	if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) {
+@@ -243,6 +250,10 @@ NTSTATUS change_trust_account_password(
+ 	struct cli_state *cli = NULL;
+ 	struct rpc_pipe_client *netlogon_pipe = NULL;
+ 
++#ifndef NETLOGON_SUPPORT
++	return NT_STATUS_UNSUCCESSFUL;
++#endif
++
+ 	DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n",
+ 		domain));
+ 
+--- a/source3/auth/auth_domain.c
++++ b/source3/auth/auth_domain.c
+@@ -538,7 +538,9 @@ static NTSTATUS auth_init_trustdomain(st
+ 
+ NTSTATUS auth_domain_init(void) 
+ {
++#ifdef NETLOGON_SUPPORT
+ 	smb_register_auth(AUTH_INTERFACE_VERSION, "trustdomain", auth_init_trustdomain);
+ 	smb_register_auth(AUTH_INTERFACE_VERSION, "ntdomain", auth_init_ntdomain);
++#endif
+ 	return NT_STATUS_OK;
+ }
+--- a/source3/smbd/process.c
++++ b/source3/smbd/process.c
+@@ -2431,8 +2431,10 @@ static bool housekeeping_fn(const struct
+ 	/* check if we need to reload services */
+ 	check_reload(sconn, time_mono(NULL));
+ 
++#ifdef NETLOGON_SUPPORT
+ 	/* Change machine password if neccessary. */
+ 	attempt_machine_password_change();
++#endif
+ 
+         /*
+ 	 * Force a log file check.
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -421,10 +421,12 @@ static bool check_bind_req(struct pipes_
+ 	if (ok) {
+ 		context_fns->allow_connect = false;
+ 	}
++#ifdef NETLOGON_SUPPORT
+ 	ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
+ 	if (ok) {
+ 		context_fns->allow_connect = false;
+ 	}
++#endif
+ 	/*
+ 	 * for the epmapper and echo interfaces we allow "connect"
+ 	 * auth_level by default.
+--- a/source3/rpc_client/cli_pipe.c
++++ b/source3/rpc_client/cli_pipe.c
+@@ -2221,6 +2221,10 @@ static void rpc_pipe_bind_step_two_trigg
+ 				      struct schannel_state);
+ 	struct tevent_req *subreq;
+ 
++#ifndef NETLOGON_SUPPORT
++	tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
++	return;
++#endif
+ 	if (schannel_auth == NULL ||
+ 	    !ndr_syntax_id_equal(&state->cli->abstract_syntax,
+ 				 &ndr_table_netlogon.syntax_id)) {
diff --git a/package/network/services/samba36/patches/260-remove_samr.patch b/package/network/services/samba36/patches/260-remove_samr.patch
new file mode 100644
index 0000000000..aeca3ed556
--- /dev/null
+++ b/package/network/services/samba36/patches/260-remove_samr.patch
@@ -0,0 +1,162 @@
+--- a/source3/rpc_server/rpc_handles.c
++++ b/source3/rpc_server/rpc_handles.c
+@@ -59,8 +59,11 @@ struct handle_list {
+ 
+ static bool is_samr_lsa_pipe(const struct ndr_syntax_id *syntax)
+ {
+-	return (ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id)
+-		|| ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id));
++	return
++#ifdef SAMR_SUPPORT
++		ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id) ||
++#endif
++		ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id);
+ }
+ 
+ size_t num_pipe_handles(struct pipes_struct *p)
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -100,9 +100,11 @@ static bool initialize_interfaces(void)
+ 		return false;
+ 	}
+ #endif
++#ifdef SAMR_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_samr)) {
+ 		return false;
+ 	}
++#endif
+ #ifdef NETLOGON_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_netlogon)) {
+ 		return false;
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -557,6 +557,7 @@ static bool lsarpc_init_cb(void *ptr)
+ 	return true;
+ }
+ 
++#ifdef SAMR_SUPPORT
+ static bool samr_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -605,6 +606,7 @@ static bool samr_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ #ifdef NETLOGON_SUPPORT
+ static bool netlogon_init_cb(void *ptr)
+@@ -1111,12 +1113,14 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 		return false;
+ 	}
+ 
++#ifdef SAMR_SUPPORT
+ 	samr_cb.init         = samr_init_cb;
+ 	samr_cb.shutdown     = NULL;
+ 	samr_cb.private_data = ep_ctx;
+ 	if (!NT_STATUS_IS_OK(rpc_samr_init(&samr_cb))) {
+ 		return false;
+ 	}
++#endif
+ 
+ #ifdef NETLOGON_SUPPORT
+ 	netlogon_cb.init         = netlogon_init_cb;
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -159,7 +159,9 @@ static void exit_server_common(enum serv
+ #ifdef NETLOGON_SUPPORT
+ 		rpc_netlogon_shutdown();
+ #endif
++#ifdef SAMR_SUPPORT
+ 		rpc_samr_shutdown();
++#endif
+ 		rpc_lsarpc_shutdown();
+ 	}
+ 
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -623,7 +623,9 @@ static struct cmd_set *rpcclient_command
+ 	rpcclient_commands,
+ 	lsarpc_commands,
+ 	ds_commands,
++#ifdef SAMR_SUPPORT
+ 	samr_commands,
++#endif
+ #ifdef PRINTER_SUPPORT
+ 	spoolss_commands,
+ #endif
+--- a/source3/smbd/lanman.c
++++ b/source3/smbd/lanman.c
+@@ -2353,6 +2353,10 @@ static bool api_RNetGroupEnum(struct smb
+ 	NTSTATUS status, result;
+ 	struct dcerpc_binding_handle *b;
+ 
++#ifndef SAMR_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -2541,6 +2545,10 @@ static bool api_NetUserGetGroups(struct
+ 	NTSTATUS status, result;
+ 	struct dcerpc_binding_handle *b;
+ 
++#ifndef SAMR_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !UserName || !p) {
+ 		return False;
+ 	}
+@@ -2741,6 +2749,10 @@ static bool api_RNetUserEnum(struct smbd
+ 
+ 	struct dcerpc_binding_handle *b;
+ 
++#ifndef SAMR_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -2979,6 +2991,10 @@ static bool api_SamOEMChangePassword(str
+ 	int bufsize;
+ 	struct dcerpc_binding_handle *b;
+ 
++#ifndef SAMR_SUPPORT
++	return False;
++#endif
++
+ 	*rparam_len = 4;
+ 	*rparam = smb_realloc_limit(*rparam,*rparam_len);
+ 	if (!*rparam) {
+@@ -4020,6 +4036,10 @@ static bool api_RNetUserGetInfo(struct s
+ 	union samr_UserInfo *info;
+ 	struct dcerpc_binding_handle *b = NULL;
+ 
++#ifndef SAMR_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !UserName || !p) {
+ 		return False;
+ 	}
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -409,6 +409,7 @@ static bool check_bind_req(struct pipes_
+ 	context_fns->syntax = *abstract;
+ 
+ 	context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect();
++#ifdef SAMR_SUPPORT
+ 	/*
+ 	 * for the samr and the lsarpc interfaces we don't allow "connect"
+ 	 * auth_level by default.
+@@ -417,6 +418,7 @@ static bool check_bind_req(struct pipes_
+ 	if (ok) {
+ 		context_fns->allow_connect = false;
+ 	}
++#endif
+ 	ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
+ 	if (ok) {
+ 		context_fns->allow_connect = false;
diff --git a/package/network/services/samba36/patches/270-remove_registry_backend.patch b/package/network/services/samba36/patches/270-remove_registry_backend.patch
new file mode 100644
index 0000000000..147b1cec74
--- /dev/null
+++ b/package/network/services/samba36/patches/270-remove_registry_backend.patch
@@ -0,0 +1,43 @@
+--- a/source3/lib/smbconf/smbconf_init.c
++++ b/source3/lib/smbconf/smbconf_init.c
+@@ -68,9 +68,12 @@ sbcErr smbconf_init(TALLOC_CTX *mem_ctx,
+ 		}
+ 	}
+ 
++#ifdef REGISTRY_BACKEND
+ 	if (strequal(backend, "registry") || strequal(backend, "reg")) {
+ 		err = smbconf_init_reg(mem_ctx, conf_ctx, path);
+-	} else if (strequal(backend, "file") || strequal(backend, "txt")) {
++	} else
++#endif
++	if (strequal(backend, "file") || strequal(backend, "txt")) {
+ 		err = smbconf_init_txt(mem_ctx, conf_ctx, path);
+ 	} else if (sep == NULL) {
+ 		/*
+--- a/source3/lib/netapi/serverinfo.c
++++ b/source3/lib/netapi/serverinfo.c
+@@ -557,7 +557,10 @@ static WERROR NetServerSetInfo_l_1005(st
+ 		return WERR_INVALID_PARAM;
+ 	}
+ 
+-	if (!lp_config_backend_is_registry()) {
++#ifdef REGISTRY_BACKEND
++	if (!lp_config_backend_is_registry())
++#endif
++	{
+ 		libnetapi_set_error_string(ctx,
+ 			"Configuration manipulation requested but not "
+ 			"supported by backend");
+--- a/source3/smbd/server.c
++++ b/source3/smbd/server.c
+@@ -1230,8 +1230,10 @@ extern void build_options(bool screen);
+ 		exit(1);
+ 	}
+ 
++#ifdef REGISTRY_BACKEND
+ 	if (!W_ERROR_IS_OK(registry_init_full()))
+ 		exit(1);
++#endif
+ 
+ 	/* Open the share_info.tdb here, so we don't have to open
+ 	   after the fork on every single connection.  This is a small
diff --git a/package/network/services/samba36/patches/280-strip_srvsvc.patch b/package/network/services/samba36/patches/280-strip_srvsvc.patch
new file mode 100644
index 0000000000..348cfbe7a4
--- /dev/null
+++ b/package/network/services/samba36/patches/280-strip_srvsvc.patch
@@ -0,0 +1,143 @@
+--- a/source3/smbd/lanman.c
++++ b/source3/smbd/lanman.c
+@@ -2197,6 +2197,10 @@ static bool api_RNetShareAdd(struct smbd
+ 	struct srvsvc_NetShareInfo2 info2;
+ 	struct dcerpc_binding_handle *b;
+ 
++#ifndef SRVSVC_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+@@ -3589,10 +3593,7 @@ static bool api_RNetServerGetInfo(struct
+ 	NTSTATUS status;
+ 	WERROR werr;
+ 	TALLOC_CTX *mem_ctx = talloc_tos();
+-	struct rpc_pipe_client *cli = NULL;
+-	union srvsvc_NetSrvInfo info;
+ 	int errcode;
+-	struct dcerpc_binding_handle *b;
+ 
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+@@ -3655,66 +3656,16 @@ static bool api_RNetServerGetInfo(struct
+ 	p = *rdata;
+ 	p2 = p + struct_len;
+ 
+-	status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc.syntax_id,
+-					conn->session_info,
+-					&conn->sconn->client_id,
+-					conn->sconn->msg_ctx,
+-					&cli);
+-	if (!NT_STATUS_IS_OK(status)) {
+-		DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n",
+-			  nt_errstr(status)));
+-		errcode = W_ERROR_V(ntstatus_to_werror(status));
+-		goto out;
+-	}
+-
+-	b = cli->binding_handle;
+-
+-	status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx,
+-					     NULL,
+-					     101,
+-					     &info,
+-					     &werr);
+-	if (!NT_STATUS_IS_OK(status)) {
+-		errcode = W_ERROR_V(ntstatus_to_werror(status));
+-		goto out;
+-	}
+-	if (!W_ERROR_IS_OK(werr)) {
+-		errcode = W_ERROR_V(werr);
+-		goto out;
+-	}
+-
+-	if (info.info101 == NULL) {
+-		errcode = W_ERROR_V(WERR_INVALID_PARAM);
+-		goto out;
+-	}
+-
+ 	if (uLevel != 20) {
+-		srvstr_push(NULL, 0, p, info.info101->server_name, 16,
++		srvstr_push(NULL, 0, p, global_myname(), 16,
+ 			STR_ASCII|STR_UPPER|STR_TERMINATE);
+-  	}
++	}
+ 	p += 16;
+ 	if (uLevel > 0) {
+-		SCVAL(p,0,info.info101->version_major);
+-		SCVAL(p,1,info.info101->version_minor);
+-		SIVAL(p,2,info.info101->server_type);
+-
+-		if (mdrcnt == struct_len) {
+-			SIVAL(p,6,0);
+-		} else {
+-			SIVAL(p,6,PTR_DIFF(p2,*rdata));
+-			if (mdrcnt - struct_len <= 0) {
+-				return false;
+-			}
+-			push_ascii(p2,
+-				info.info101->comment,
+-				MIN(mdrcnt - struct_len,
+-					MAX_SERVER_STRING_LENGTH),
+-				STR_TERMINATE);
+-			p2 = skip_string(*rdata,*rdata_len,p2);
+-			if (!p2) {
+-				return False;
+-			}
+-		}
++		SCVAL(p,0,lp_major_announce_version());
++		SCVAL(p,1,lp_minor_announce_version());
++		SIVAL(p,2,lp_default_server_announce());
++		SIVAL(p,6,0);
+ 	}
+ 
+ 	if (uLevel > 1) {
+@@ -5405,6 +5356,10 @@ static bool api_RNetSessionEnum(struct s
+ 	uint32_t totalentries, resume_handle = 0;
+ 	uint32_t count = 0;
+ 
++#ifndef SRVSVC_SUPPORT
++	return False;
++#endif
++
+ 	if (!str1 || !str2 || !p) {
+ 		return False;
+ 	}
+--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
++++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+@@ -1533,6 +1533,10 @@ WERROR _srvsvc_NetShareSetInfo(struct pi
+ 	TALLOC_CTX *ctx = p->mem_ctx;
+ 	union srvsvc_NetShareInfo *info = r->in.info;
+ 
++#ifndef FULL_SRVSVC
++	return WERR_ACCESS_DENIED;
++#endif
++
+ 	DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__));
+ 
+ 	if (!r->in.share_name) {
+@@ -1763,6 +1767,10 @@ WERROR _srvsvc_NetShareAdd(struct pipes_
+ 	int max_connections = 0;
+ 	TALLOC_CTX *ctx = p->mem_ctx;
+ 
++#ifndef FULL_SRVSVC
++	return WERR_ACCESS_DENIED;
++#endif
++
+ 	DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__));
+ 
+ 	if (r->out.parm_error) {
+@@ -1945,6 +1953,10 @@ WERROR _srvsvc_NetShareDel(struct pipes_
+ 	struct share_params *params;
+ 	TALLOC_CTX *ctx = p->mem_ctx;
+ 
++#ifndef FULL_SRVSVC
++	return WERR_ACCESS_DENIED;
++#endif
++
+ 	DEBUG(5,("_srvsvc_NetShareDel: %d\n", __LINE__));
+ 
+ 	if (!r->in.share_name) {
diff --git a/package/network/services/samba36/patches/290-remove_lsa.patch b/package/network/services/samba36/patches/290-remove_lsa.patch
new file mode 100644
index 0000000000..6dc35753b1
--- /dev/null
+++ b/package/network/services/samba36/patches/290-remove_lsa.patch
@@ -0,0 +1,88 @@
+--- a/source3/librpc/rpc/rpc_common.c
++++ b/source3/librpc/rpc/rpc_common.c
+@@ -92,9 +92,11 @@ bool smb_register_ndr_interface(const st
+ 
+ static bool initialize_interfaces(void)
+ {
++#ifdef LSA_SUPPORT
+ 	if (!smb_register_ndr_interface(&ndr_table_lsarpc)) {
+ 		return false;
+ 	}
++#endif
+ #ifdef ACTIVE_DIRECTORY
+ 	if (!smb_register_ndr_interface(&ndr_table_dssetup)) {
+ 		return false;
+--- a/source3/smbd/server_exit.c
++++ b/source3/smbd/server_exit.c
+@@ -162,7 +162,9 @@ static void exit_server_common(enum serv
+ #ifdef SAMR_SUPPORT
+ 		rpc_samr_shutdown();
+ #endif
++#ifdef LSA_SUPPORT
+ 		rpc_lsarpc_shutdown();
++#endif
+ 	}
+ 
+ 	/*
+--- a/source3/rpc_server/rpc_ep_setup.c
++++ b/source3/rpc_server/rpc_ep_setup.c
+@@ -508,6 +508,7 @@ static bool srvsvc_init_cb(void *ptr)
+ 	return true;
+ }
+ 
++#ifdef LSA_SUPPORT
+ static bool lsarpc_init_cb(void *ptr)
+ {
+ 	struct dcesrv_ep_context *ep_ctx =
+@@ -556,6 +557,7 @@ static bool lsarpc_init_cb(void *ptr)
+ 
+ 	return true;
+ }
++#endif
+ 
+ #ifdef SAMR_SUPPORT
+ static bool samr_init_cb(void *ptr)
+@@ -1106,12 +1108,14 @@ bool dcesrv_ep_setup(struct tevent_conte
+ 	}
+ 
+ 
++#ifdef LSA_SUPPORT
+ 	lsarpc_cb.init         = lsarpc_init_cb;
+ 	lsarpc_cb.shutdown     = NULL;
+ 	lsarpc_cb.private_data = ep_ctx;
+ 	if (!NT_STATUS_IS_OK(rpc_lsarpc_init(&lsarpc_cb))) {
+ 		return false;
+ 	}
++#endif
+ 
+ #ifdef SAMR_SUPPORT
+ 	samr_cb.init         = samr_init_cb;
+--- a/source3/rpc_server/rpc_handles.c
++++ b/source3/rpc_server/rpc_handles.c
+@@ -63,7 +63,10 @@ static bool is_samr_lsa_pipe(const struc
+ #ifdef SAMR_SUPPORT
+ 		ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id) ||
+ #endif
+-		ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id);
++#ifdef LSA_SUPPORT
++		ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id) ||
++#endif
++		false;
+ }
+ 
+ size_t num_pipe_handles(struct pipes_struct *p)
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -419,10 +419,12 @@ static bool check_bind_req(struct pipes_
+ 		context_fns->allow_connect = false;
+ 	}
+ #endif
++#ifdef LSA_SUPPORT
+ 	ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
+ 	if (ok) {
+ 		context_fns->allow_connect = false;
+ 	}
++#endif
+ #ifdef NETLOGON_SUPPORT
+ 	ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
+ 	if (ok) {
diff --git a/package/network/services/samba36/patches/300-assert_debug_level.patch b/package/network/services/samba36/patches/300-assert_debug_level.patch
new file mode 100644
index 0000000000..c5b07168c6
--- /dev/null
+++ b/package/network/services/samba36/patches/300-assert_debug_level.patch
@@ -0,0 +1,11 @@
+--- a/lib/util/util.h
++++ b/lib/util/util.h
+@@ -53,7 +53,7 @@ extern const char *panic_action;
+ #else
+ /* redefine the assert macro for non-developer builds */
+ #define SMB_ASSERT(b) do { if (!(b)) { \
+-        DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
++        DEBUG(3,("PANIC: assert failed at %s(%d): %s\n", \
+ 	    __FILE__, __LINE__, #b)); }} while (0)
+ #endif
+ 
diff --git a/package/network/services/samba36/patches/310-remove_error_strings.patch b/package/network/services/samba36/patches/310-remove_error_strings.patch
new file mode 100644
index 0000000000..ee3460dfdb
--- /dev/null
+++ b/package/network/services/samba36/patches/310-remove_error_strings.patch
@@ -0,0 +1,337 @@
+--- a/libcli/util/doserr.c
++++ b/libcli/util/doserr.c
+@@ -28,6 +28,7 @@ struct werror_code_struct {
+ 
+ static const struct werror_code_struct dos_errs[] =
+ {
++#ifdef VERBOSE_ERROR
+ 	{ "WERR_OK", WERR_OK },
+ 	{ "WERR_BADFILE", WERR_BADFILE },
+ 	{ "WERR_ACCESS_DENIED", WERR_ACCESS_DENIED },
+@@ -2668,6 +2669,7 @@ static const struct werror_code_struct d
+ 	{ "WERR_AMBIGUOUS_SYSTEM_DEVICE", WERR_AMBIGUOUS_SYSTEM_DEVICE },
+ 	{ "WERR_SYSTEM_DEVICE_NOT_FOUND", WERR_SYSTEM_DEVICE_NOT_FOUND },
+ 	/* END GENERATED-WIN32-ERROR-CODES */
++#endif
+ 	{ NULL, W_ERROR(0) }
+ };
+ 
+@@ -2684,12 +2686,14 @@ const char *win_errstr(WERROR werror)
+         static char msg[40];
+         int idx = 0;
+ 
++#ifdef VERBOSE_ERROR
+ 	while (dos_errs[idx].dos_errstr != NULL) {
+ 		if (W_ERROR_V(dos_errs[idx].werror) == 
+                     W_ERROR_V(werror))
+                         return dos_errs[idx].dos_errstr;
+ 		idx++;
+ 	}
++#endif
+ 
+ 	slprintf(msg, sizeof(msg), "DOS code 0x%08x", W_ERROR_V(werror));
+ 
+@@ -2702,6 +2706,7 @@ struct werror_str_struct {
+ };
+ 
+ const struct werror_str_struct dos_err_strs[] = {
++#ifdef VERBOSE_ERROR
+ 	{ WERR_OK, "Success" },
+ 	{ WERR_ACCESS_DENIED, "Access is denied" },
+ 	{ WERR_INVALID_PARAM, "Invalid parameter" },
+@@ -5324,6 +5329,7 @@ const struct werror_str_struct dos_err_s
+ 	{ WERR_AMBIGUOUS_SYSTEM_DEVICE, "The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria." },
+ 	{ WERR_SYSTEM_DEVICE_NOT_FOUND, "The requested system device cannot be found." },
+ 	/* END GENERATED-WIN32-ERROR-CODES-DESC */
++#endif
+ };
+ 
+ 
+@@ -5334,6 +5340,7 @@ const struct werror_str_struct dos_err_s
+ 
+ const char *get_friendly_werror_msg(WERROR werror)
+ {
++#ifdef VERBOSE_ERROR
+ 	int i = 0;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(dos_err_strs); i++) {
+@@ -5342,6 +5349,7 @@ const char *get_friendly_werror_msg(WERR
+ 			return dos_err_strs[i].friendly_errstr;
+ 		}
+ 	}
++#endif
+ 
+ 	return win_errstr(werror);
+ }
+--- a/librpc/ndr/libndr.h
++++ b/librpc/ndr/libndr.h
+@@ -663,4 +663,20 @@ _PUBLIC_ enum ndr_err_code ndr_push_enum
+ 
+ _PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);
+ 
++#ifndef VERBOSE_ERROR
++#define ndr_print_bool(...) do {} while (0)
++#define ndr_print_struct(...) do {} while (0)
++#define ndr_print_null(...) do {} while (0)
++#define ndr_print_enum(...) do {} while (0)
++#define ndr_print_bitmap_flag(...) do {} while (0)
++#define ndr_print_ptr(...) do {} while (0)
++#define ndr_print_union(...) do {} while (0)
++#define ndr_print_bad_level(...) do {} while (0)
++#define ndr_print_array_uint8(...) do {} while (0)
++#define ndr_print_string_array(...) do {} while (0)
++#define ndr_print_string_array(...) do {} while (0)
++#define ndr_print_NTSTATUS(...) do {} while (0)
++#define ndr_print_WERROR(...) do {} while (0)
++#endif
++
+ #endif /* __LIBNDR_H__ */
+--- a/librpc/ndr/ndr_basic.c
++++ b/librpc/ndr/ndr_basic.c
+@@ -31,6 +31,19 @@
+ #define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr))  { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0)
+ #define NDR_SIVALS(ndr, ofs, v) do { if (NDR_BE(ndr))  { RSIVALS(ndr->data,ofs,v); } else SIVALS(ndr->data,ofs,v); } while (0)
+ 
++#undef ndr_print_bool
++#undef ndr_print_struct
++#undef ndr_print_null
++#undef ndr_print_enum
++#undef ndr_print_bitmap_flag
++#undef ndr_print_ptr
++#undef ndr_print_union
++#undef ndr_print_bad_level
++#undef ndr_print_array_uint8
++#undef ndr_print_string_array
++#undef ndr_print_string_array
++#undef ndr_print_NTSTATUS
++#undef ndr_print_WERROR
+ 
+ /*
+   check for data leaks from the server by looking for non-zero pad bytes
+--- a/librpc/ndr/ndr_string.c
++++ b/librpc/ndr/ndr_string.c
+@@ -588,6 +588,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_stri
+ 	return NDR_ERR_SUCCESS;
+ }
+ 
++#undef ndr_print_string_array
+ _PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
+ {
+ 	uint32_t count;
+--- a/librpc/rpc/dcerpc_error.c
++++ b/librpc/rpc/dcerpc_error.c
+@@ -31,6 +31,7 @@ struct dcerpc_fault_table {
+ static const struct dcerpc_fault_table dcerpc_faults[] =
+ {
+ #define _FAULT_STR(x) { #x , x }
++#ifdef VERBOSE_ERROR
+ 	_FAULT_STR(DCERPC_NCA_S_COMM_FAILURE),
+ 	_FAULT_STR(DCERPC_NCA_S_OP_RNG_ERROR),
+ 	_FAULT_STR(DCERPC_NCA_S_UNKNOWN_IF),
+@@ -78,6 +79,7 @@ static const struct dcerpc_fault_table d
+ 	_FAULT_STR(DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR),
+ 	_FAULT_STR(DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND),
+ 	_FAULT_STR(DCERPC_NCA_S_FAULT_NO_CLIENT_STUB),
++#endif
+ 	{ NULL, 0 }
+ #undef _FAULT_STR
+ };
+@@ -87,12 +89,14 @@ _PUBLIC_ const char *dcerpc_errstr(TALLO
+ 	int idx = 0;
+ 	WERROR werr = W_ERROR(fault_code);
+ 
++#ifdef VERBOSE_ERROR
+ 	while (dcerpc_faults[idx].errstr != NULL) {
+ 		if (dcerpc_faults[idx].faultcode == fault_code) {
+ 			return dcerpc_faults[idx].errstr;
+ 		}
+ 		idx++;
+ 	}
++#endif
+ 
+ 	return win_errstr(werr);
+ }
+--- a/source3/libsmb/nterr.c
++++ b/source3/libsmb/nterr.c
+@@ -702,6 +702,7 @@ const char *nt_errstr(NTSTATUS nt_code)
+ 					NT_STATUS_DOS_CODE(nt_code));
+ 	}
+ 
++#ifdef VERBOSE_ERROR
+ 	while (nt_errs[idx].nt_errstr != NULL) {
+ 		if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ 		    NT_STATUS_V(nt_code)) {
+@@ -709,6 +710,7 @@ const char *nt_errstr(NTSTATUS nt_code)
+ 		}
+ 		idx++;
+ 	}
++#endif
+ 
+ 	result = talloc_asprintf(talloc_tos(), "NT code 0x%08x",
+ 				 NT_STATUS_V(nt_code));
+@@ -724,12 +726,14 @@ const char *get_friendly_nt_error_msg(NT
+ {
+ 	int idx = 0;
+ 
++#ifdef VERBOSE_ERROR
+ 	while (nt_err_desc[idx].nt_errstr != NULL) {
+ 		if (NT_STATUS_V(nt_err_desc[idx].nt_errcode) == NT_STATUS_V(nt_code)) {
+ 			return nt_err_desc[idx].nt_errstr;
+ 		}
+ 		idx++;
+ 	}
++#endif
+ 
+ 	/* fall back to NT_STATUS_XXX string */
+ 
+@@ -745,6 +749,7 @@ const char *get_nt_error_c_code(NTSTATUS
+ 	char *result;
+ 	int idx = 0;
+ 
++#ifdef VERBOSE_ERROR
+ 	while (nt_errs[idx].nt_errstr != NULL) {
+ 		if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ 		    NT_STATUS_V(nt_code)) {
+@@ -752,6 +757,7 @@ const char *get_nt_error_c_code(NTSTATUS
+ 		}
+ 		idx++;
+ 	}
++#endif
+ 
+ 	result = talloc_asprintf(talloc_tos(), "NT_STATUS(0x%08x)",
+ 				 NT_STATUS_V(nt_code));
+@@ -767,12 +773,14 @@ NTSTATUS nt_status_string_to_code(const
+ {
+ 	int idx = 0;
+ 
++#ifdef VERBOSE_ERROR
+ 	while (nt_errs[idx].nt_errstr != NULL) {
+ 		if (strcasecmp(nt_errs[idx].nt_errstr, nt_status_str) == 0) {
+ 			return nt_errs[idx].nt_errcode;
+ 		}
+ 		idx++;
+ 	}
++#endif
+ 	return NT_STATUS_UNSUCCESSFUL;
+ }
+ 
+--- a/lib/tdb/common/tdb_private.h
++++ b/lib/tdb/common/tdb_private.h
+@@ -69,7 +69,11 @@ typedef uint32_t tdb_off_t;
+ /* NB assumes there is a local variable called "tdb" that is the
+  * current context, also takes doubly-parenthesized print-style
+  * argument. */
++#ifdef VERBOSE_DEBUG
+ #define TDB_LOG(x) tdb->log.log_fn x
++#else
++#define TDB_LOG(x) do {} while(0)
++#endif
+ 
+ #ifdef TDB_TRACE
+ void tdb_trace(struct tdb_context *tdb, const char *op);
+--- a/source3/script/mkbuildoptions.awk
++++ b/source3/script/mkbuildoptions.awk
+@@ -55,7 +55,7 @@ BEGIN {
+ 	print "****************************************************************************/";
+ 	print "void build_options(bool screen)";
+ 	print "{";
+-	print "       if ((DEBUGLEVEL < 4) && (!screen)) {";
++	print "       if ((DEBUGLEVEL < 4) || (!screen)) {";
+ 	print "	       return;";
+ 	print "       }";
+ 	print "";
+--- a/source3/script/mkbuildoptions-waf.awk
++++ b/source3/script/mkbuildoptions-waf.awk
+@@ -55,7 +55,7 @@ BEGIN {
+ 	print "****************************************************************************/";
+ 	print "void build_options(bool screen)";
+ 	print "{";
+-	print "       if ((DEBUGLEVEL < 4) && (!screen)) {";
++	print "       if ((DEBUGLEVEL < 4) || (!screen)) {";
+ 	print "	       return;";
+ 	print "       }";
+ 	print "";
+--- a/source3/rpc_client/cli_pipe.c
++++ b/source3/rpc_client/cli_pipe.c
+@@ -445,7 +445,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 				  rpccli_pipe_txt(talloc_tos(), cli),
+ 				  pkt->ptype, expected_pkt_type,
+ 				  nt_errstr(ret)));
+-			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+@@ -466,7 +465,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 				  rpccli_pipe_txt(talloc_tos(), cli),
+ 				  pkt->ptype, expected_pkt_type,
+ 				  nt_errstr(ret)));
+-			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+@@ -486,7 +484,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 				  rpccli_pipe_txt(talloc_tos(), cli),
+ 				  pkt->ptype, expected_pkt_type,
+ 				  nt_errstr(ret)));
+-			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+@@ -508,7 +505,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 				  rpccli_pipe_txt(talloc_tos(), cli),
+ 				  pkt->ptype, expected_pkt_type,
+ 				  nt_errstr(ret)));
+-			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+@@ -526,7 +522,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 				  rpccli_pipe_txt(talloc_tos(), cli),
+ 				  pkt->ptype, expected_pkt_type,
+ 				  nt_errstr(ret)));
+-			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+@@ -570,7 +565,6 @@ static NTSTATUS cli_pipe_validate_curren
+ 				  rpccli_pipe_txt(talloc_tos(), cli),
+ 				  pkt->ptype, expected_pkt_type,
+ 				  nt_errstr(ret)));
+-			NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 			return ret;
+ 		}
+ 
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -991,7 +991,6 @@ static bool api_pipe_bind_req(struct pip
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n",
+ 			  nt_errstr(status)));
+-		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 		goto err_exit;
+ 	}
+ 
+@@ -1325,7 +1324,6 @@ bool api_pipe_bind_auth3(struct pipes_st
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n",
+ 			  nt_errstr(status)));
+-		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 		goto err;
+ 	}
+ 
+@@ -1483,7 +1481,6 @@ static bool api_pipe_alter_context(struc
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n",
+ 			  nt_errstr(status)));
+-		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 		goto err_exit;
+ 	}
+ 
+@@ -2057,7 +2054,6 @@ static bool process_request_pdu(struct p
+ 	if (!NT_STATUS_IS_OK(status)) {
+ 		DEBUG(1, ("process_request_pdu: invalid pdu: %s\n",
+ 			  nt_errstr(status)));
+-		NDR_PRINT_DEBUG(ncacn_packet, pkt);
+ 		set_incoming_fault(p);
+ 		return false;
+ 	}
diff --git a/package/network/services/samba36/patches/320-debug_level_checks.patch b/package/network/services/samba36/patches/320-debug_level_checks.patch
new file mode 100644
index 0000000000..c6f2e6e0d9
--- /dev/null
+++ b/package/network/services/samba36/patches/320-debug_level_checks.patch
@@ -0,0 +1,22 @@
+--- a/lib/util/debug.h
++++ b/lib/util/debug.h
+@@ -45,7 +45,7 @@ bool dbghdr( int level, const char *loca
+  * Redefine DEBUGLEVEL because so we don't have to change every source file
+  * that *unnecessarily* references it.
+  */
+-#define DEBUGLEVEL DEBUGLEVEL_CLASS[DBGC_ALL]
++#define DEBUGLEVEL 0
+ 
+ /*
+  * Define all new debug classes here. A class is represented by an entry in
+--- a/source3/nmbd/asyncdns.c
++++ b/source3/nmbd/asyncdns.c
+@@ -85,7 +85,7 @@ static void asyncdns_process(void)
+ 	struct query_record r;
+ 	unstring qname;
+ 
+-	DEBUGLEVEL = -1;
++	DEBUGLEVEL_CLASS[DBGC_ALL] = -1;
+ 
+ 	while (1) {
+ 		NTSTATUS status;
diff --git a/package/network/services/samba36/patches/330-librpc_default_print.patch b/package/network/services/samba36/patches/330-librpc_default_print.patch
new file mode 100644
index 0000000000..aa4bfe32c9
--- /dev/null
+++ b/package/network/services/samba36/patches/330-librpc_default_print.patch
@@ -0,0 +1,8854 @@
+--- a/source3/librpc/ndr/util.c
++++ b/source3/librpc/ndr/util.c
+@@ -28,3 +28,7 @@ _PUBLIC_ void ndr_print_sockaddr_storage
+ 	char addr[INET6_ADDRSTRLEN];
+ 	ndr->print(ndr, "%-25s: %s", name, print_sockaddr(addr, sizeof(addr), ss));
+ }
++
++_PUBLIC_ void ndr_print_disabled(struct ndr_print *ndr, const char *name, int flags, void *r)
++{
++}
+--- a/source3/librpc/gen_ndr/ndr_atsvc.c
++++ b/source3/librpc/gen_ndr/ndr_atsvc.c
+@@ -867,7 +867,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct atsvc_JobAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_atsvc_JobAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_atsvc_JobAdd,
+-		(ndr_print_function_t) ndr_print_atsvc_JobAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -876,7 +876,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct atsvc_JobDel),
+ 		(ndr_push_flags_fn_t) ndr_push_atsvc_JobDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_atsvc_JobDel,
+-		(ndr_print_function_t) ndr_print_atsvc_JobDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -885,7 +885,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct atsvc_JobEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_atsvc_JobEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_atsvc_JobEnum,
+-		(ndr_print_function_t) ndr_print_atsvc_JobEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -894,7 +894,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct atsvc_JobGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_atsvc_JobGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_atsvc_JobGetInfo,
+-		(ndr_print_function_t) ndr_print_atsvc_JobGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_audiosrv.c
++++ b/source3/librpc/gen_ndr/ndr_audiosrv.c
+@@ -594,7 +594,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_CreatezoneFactoriesList),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_CreatezoneFactoriesList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_CreatezoneFactoriesList,
+-		(ndr_print_function_t) ndr_print_audiosrv_CreatezoneFactoriesList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -603,7 +603,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_CreateGfxFactoriesList),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_CreateGfxFactoriesList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_CreateGfxFactoriesList,
+-		(ndr_print_function_t) ndr_print_audiosrv_CreateGfxFactoriesList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -612,7 +612,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_CreateGfxList),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_CreateGfxList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_CreateGfxList,
+-		(ndr_print_function_t) ndr_print_audiosrv_CreateGfxList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -621,7 +621,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_RemoveGfx),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_RemoveGfx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_RemoveGfx,
+-		(ndr_print_function_t) ndr_print_audiosrv_RemoveGfx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -630,7 +630,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_AddGfx),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_AddGfx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_AddGfx,
+-		(ndr_print_function_t) ndr_print_audiosrv_AddGfx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -639,7 +639,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_ModifyGfx),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_ModifyGfx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_ModifyGfx,
+-		(ndr_print_function_t) ndr_print_audiosrv_ModifyGfx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -648,7 +648,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_OpenGfx),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_OpenGfx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_OpenGfx,
+-		(ndr_print_function_t) ndr_print_audiosrv_OpenGfx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -657,7 +657,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_Logon),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_Logon,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_Logon,
+-		(ndr_print_function_t) ndr_print_audiosrv_Logon,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -666,7 +666,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_Logoff),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_Logoff,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_Logoff,
+-		(ndr_print_function_t) ndr_print_audiosrv_Logoff,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -675,7 +675,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_RegisterSessionNotificationEvent),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_RegisterSessionNotificationEvent,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_RegisterSessionNotificationEvent,
+-		(ndr_print_function_t) ndr_print_audiosrv_RegisterSessionNotificationEvent,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -684,7 +684,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_UnregisterSessionNotificationEvent),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_UnregisterSessionNotificationEvent,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_UnregisterSessionNotificationEvent,
+-		(ndr_print_function_t) ndr_print_audiosrv_UnregisterSessionNotificationEvent,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -693,7 +693,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_SessionConnectState),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_SessionConnectState,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_SessionConnectState,
+-		(ndr_print_function_t) ndr_print_audiosrv_SessionConnectState,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -702,7 +702,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_DriverOpenDrvRegKey),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_DriverOpenDrvRegKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_DriverOpenDrvRegKey,
+-		(ndr_print_function_t) ndr_print_audiosrv_DriverOpenDrvRegKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -711,7 +711,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_AdvisePreferredDeviceChange),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_AdvisePreferredDeviceChange,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_AdvisePreferredDeviceChange,
+-		(ndr_print_function_t) ndr_print_audiosrv_AdvisePreferredDeviceChange,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -720,7 +720,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct audiosrv_GetPnpInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_audiosrv_GetPnpInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_audiosrv_GetPnpInfo,
+-		(ndr_print_function_t) ndr_print_audiosrv_GetPnpInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_backupkey.c
++++ b/source3/librpc/gen_ndr/ndr_backupkey.c
+@@ -740,7 +740,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct bkrp_BackupKey),
+ 		(ndr_push_flags_fn_t) ndr_push_bkrp_BackupKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_bkrp_BackupKey,
+-		(ndr_print_function_t) ndr_print_bkrp_BackupKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_browser.c
++++ b/source3/librpc/gen_ndr/ndr_browser.c
+@@ -928,7 +928,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrServerEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrServerEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrServerEnum,
+-		(ndr_print_function_t) ndr_print_BrowserrServerEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -937,7 +937,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrDebugCall),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrDebugCall,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrDebugCall,
+-		(ndr_print_function_t) ndr_print_BrowserrDebugCall,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -946,7 +946,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrQueryOtherDomains),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrQueryOtherDomains,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrQueryOtherDomains,
+-		(ndr_print_function_t) ndr_print_BrowserrQueryOtherDomains,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -955,7 +955,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrResetNetlogonState),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrResetNetlogonState,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrResetNetlogonState,
+-		(ndr_print_function_t) ndr_print_BrowserrResetNetlogonState,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -964,7 +964,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrDebugTrace),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrDebugTrace,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrDebugTrace,
+-		(ndr_print_function_t) ndr_print_BrowserrDebugTrace,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -973,7 +973,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrQueryStatistics),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrQueryStatistics,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrQueryStatistics,
+-		(ndr_print_function_t) ndr_print_BrowserrQueryStatistics,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -982,7 +982,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserResetStatistics),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserResetStatistics,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserResetStatistics,
+-		(ndr_print_function_t) ndr_print_BrowserResetStatistics,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -991,7 +991,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct NetrBrowserStatisticsClear),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrBrowserStatisticsClear,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrBrowserStatisticsClear,
+-		(ndr_print_function_t) ndr_print_NetrBrowserStatisticsClear,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1000,7 +1000,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct NetrBrowserStatisticsGet),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrBrowserStatisticsGet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrBrowserStatisticsGet,
+-		(ndr_print_function_t) ndr_print_NetrBrowserStatisticsGet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1009,7 +1009,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrSetNetlogonState),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrSetNetlogonState,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrSetNetlogonState,
+-		(ndr_print_function_t) ndr_print_BrowserrSetNetlogonState,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1018,7 +1018,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrQueryEmulatedDomains),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrQueryEmulatedDomains,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrQueryEmulatedDomains,
+-		(ndr_print_function_t) ndr_print_BrowserrQueryEmulatedDomains,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1027,7 +1027,7 @@ static const struct ndr_interface_call b
+ 		sizeof(struct BrowserrServerEnumEx),
+ 		(ndr_push_flags_fn_t) ndr_push_BrowserrServerEnumEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BrowserrServerEnumEx,
+-		(ndr_print_function_t) ndr_print_BrowserrServerEnumEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dbgidl.c
++++ b/source3/librpc/gen_ndr/ndr_dbgidl.c
+@@ -48,7 +48,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dummy_dbgidl),
+ 		(ndr_push_flags_fn_t) ndr_push_dummy_dbgidl,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dummy_dbgidl,
+-		(ndr_print_function_t) ndr_print_dummy_dbgidl,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dcom.c
++++ b/source3/librpc/gen_ndr/ndr_dcom.c
+@@ -128,7 +128,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct UseProtSeq),
+ 		(ndr_push_flags_fn_t) ndr_push_UseProtSeq,
+ 		(ndr_pull_flags_fn_t) ndr_pull_UseProtSeq,
+-		(ndr_print_function_t) ndr_print_UseProtSeq,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -137,7 +137,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct GetCustomProtseqInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_GetCustomProtseqInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetCustomProtseqInfo,
+-		(ndr_print_function_t) ndr_print_GetCustomProtseqInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -146,7 +146,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct UpdateResolverBindings),
+ 		(ndr_push_flags_fn_t) ndr_push_UpdateResolverBindings,
+ 		(ndr_pull_flags_fn_t) ndr_pull_UpdateResolverBindings,
+-		(ndr_print_function_t) ndr_print_UpdateResolverBindings,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -450,7 +450,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct QueryInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_QueryInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_QueryInterface,
+-		(ndr_print_function_t) ndr_print_QueryInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -459,7 +459,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct AddRef),
+ 		(ndr_push_flags_fn_t) ndr_push_AddRef,
+ 		(ndr_pull_flags_fn_t) ndr_pull_AddRef,
+-		(ndr_print_function_t) ndr_print_AddRef,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -468,7 +468,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Release),
+ 		(ndr_push_flags_fn_t) ndr_push_Release,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Release,
+-		(ndr_print_function_t) ndr_print_Release,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -849,7 +849,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct CreateInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_CreateInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_CreateInstance,
+-		(ndr_print_function_t) ndr_print_CreateInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -858,7 +858,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemoteCreateInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_RemoteCreateInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemoteCreateInstance,
+-		(ndr_print_function_t) ndr_print_RemoteCreateInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -867,7 +867,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct LockServer),
+ 		(ndr_push_flags_fn_t) ndr_push_LockServer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_LockServer,
+-		(ndr_print_function_t) ndr_print_LockServer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -876,7 +876,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemoteLockServer),
+ 		(ndr_push_flags_fn_t) ndr_push_RemoteLockServer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemoteLockServer,
+-		(ndr_print_function_t) ndr_print_RemoteLockServer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1434,7 +1434,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemQueryInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_RemQueryInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemQueryInterface,
+-		(ndr_print_function_t) ndr_print_RemQueryInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1443,7 +1443,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemAddRef),
+ 		(ndr_push_flags_fn_t) ndr_push_RemAddRef,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemAddRef,
+-		(ndr_print_function_t) ndr_print_RemAddRef,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1452,7 +1452,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemRelease),
+ 		(ndr_push_flags_fn_t) ndr_push_RemRelease,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemRelease,
+-		(ndr_print_function_t) ndr_print_RemRelease,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1590,7 +1590,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetClassObject),
+ 		(ndr_push_flags_fn_t) ndr_push_GetClassObject,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetClassObject,
+-		(ndr_print_function_t) ndr_print_GetClassObject,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1701,7 +1701,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ISCMLocalActivator_CreateInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_ISCMLocalActivator_CreateInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ISCMLocalActivator_CreateInstance,
+-		(ndr_print_function_t) ndr_print_ISCMLocalActivator_CreateInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1788,7 +1788,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct IMachineLocalActivator_foo),
+ 		(ndr_push_flags_fn_t) ndr_push_IMachineLocalActivator_foo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_IMachineLocalActivator_foo,
+-		(ndr_print_function_t) ndr_print_IMachineLocalActivator_foo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1875,7 +1875,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ILocalObjectExporter_Foo),
+ 		(ndr_push_flags_fn_t) ndr_push_ILocalObjectExporter_Foo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ILocalObjectExporter_Foo,
+-		(ndr_print_function_t) ndr_print_ILocalObjectExporter_Foo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2031,7 +2031,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ISystemActivatorRemoteCreateInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_ISystemActivatorRemoteCreateInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ISystemActivatorRemoteCreateInstance,
+-		(ndr_print_function_t) ndr_print_ISystemActivatorRemoteCreateInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2319,7 +2319,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemQueryInterface2),
+ 		(ndr_push_flags_fn_t) ndr_push_RemQueryInterface2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemQueryInterface2,
+-		(ndr_print_function_t) ndr_print_RemQueryInterface2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3040,7 +3040,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetTypeInfoCount),
+ 		(ndr_push_flags_fn_t) ndr_push_GetTypeInfoCount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetTypeInfoCount,
+-		(ndr_print_function_t) ndr_print_GetTypeInfoCount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3049,7 +3049,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetTypeInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_GetTypeInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetTypeInfo,
+-		(ndr_print_function_t) ndr_print_GetTypeInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3058,7 +3058,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetIDsOfNames),
+ 		(ndr_push_flags_fn_t) ndr_push_GetIDsOfNames,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetIDsOfNames,
+-		(ndr_print_function_t) ndr_print_GetIDsOfNames,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3067,7 +3067,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Invoke),
+ 		(ndr_push_flags_fn_t) ndr_push_Invoke,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Invoke,
+-		(ndr_print_function_t) ndr_print_Invoke,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3243,7 +3243,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct MarshalInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_MarshalInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_MarshalInterface,
+-		(ndr_print_function_t) ndr_print_MarshalInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3252,7 +3252,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct UnMarshalInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_UnMarshalInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_UnMarshalInterface,
+-		(ndr_print_function_t) ndr_print_UnMarshalInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3385,7 +3385,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct MakeCoffee),
+ 		(ndr_push_flags_fn_t) ndr_push_MakeCoffee,
+ 		(ndr_pull_flags_fn_t) ndr_pull_MakeCoffee,
+-		(ndr_print_function_t) ndr_print_MakeCoffee,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3681,7 +3681,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Read),
+ 		(ndr_push_flags_fn_t) ndr_push_Read,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Read,
+-		(ndr_print_function_t) ndr_print_Read,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3690,7 +3690,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Write),
+ 		(ndr_push_flags_fn_t) ndr_push_Write,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Write,
+-		(ndr_print_function_t) ndr_print_Write,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dfs.c
++++ b/source3/librpc/gen_ndr/ndr_dfs.c
+@@ -5910,7 +5910,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_GetManagerVersion),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_GetManagerVersion,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_GetManagerVersion,
+-		(ndr_print_function_t) ndr_print_dfs_GetManagerVersion,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5919,7 +5919,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Add),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Add,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Add,
+-		(ndr_print_function_t) ndr_print_dfs_Add,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5928,7 +5928,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Remove),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Remove,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Remove,
+-		(ndr_print_function_t) ndr_print_dfs_Remove,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5937,7 +5937,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_SetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_SetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_SetInfo,
+-		(ndr_print_function_t) ndr_print_dfs_SetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5946,7 +5946,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_GetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_GetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_GetInfo,
+-		(ndr_print_function_t) ndr_print_dfs_GetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5955,7 +5955,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Enum),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Enum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Enum,
+-		(ndr_print_function_t) ndr_print_dfs_Enum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5964,7 +5964,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Rename),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Rename,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Rename,
+-		(ndr_print_function_t) ndr_print_dfs_Rename,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5973,7 +5973,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Move),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Move,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Move,
+-		(ndr_print_function_t) ndr_print_dfs_Move,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5982,7 +5982,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_ManagerGetConfigInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_ManagerGetConfigInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_ManagerGetConfigInfo,
+-		(ndr_print_function_t) ndr_print_dfs_ManagerGetConfigInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5991,7 +5991,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_ManagerSendSiteInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_ManagerSendSiteInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_ManagerSendSiteInfo,
+-		(ndr_print_function_t) ndr_print_dfs_ManagerSendSiteInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6000,7 +6000,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_AddFtRoot),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_AddFtRoot,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_AddFtRoot,
+-		(ndr_print_function_t) ndr_print_dfs_AddFtRoot,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6009,7 +6009,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_RemoveFtRoot),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_RemoveFtRoot,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_RemoveFtRoot,
+-		(ndr_print_function_t) ndr_print_dfs_RemoveFtRoot,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6018,7 +6018,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_AddStdRoot),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_AddStdRoot,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_AddStdRoot,
+-		(ndr_print_function_t) ndr_print_dfs_AddStdRoot,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6027,7 +6027,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_RemoveStdRoot),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_RemoveStdRoot,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_RemoveStdRoot,
+-		(ndr_print_function_t) ndr_print_dfs_RemoveStdRoot,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6036,7 +6036,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_ManagerInitialize),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_ManagerInitialize,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_ManagerInitialize,
+-		(ndr_print_function_t) ndr_print_dfs_ManagerInitialize,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6045,7 +6045,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_AddStdRootForced),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_AddStdRootForced,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_AddStdRootForced,
+-		(ndr_print_function_t) ndr_print_dfs_AddStdRootForced,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6054,7 +6054,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_GetDcAddress),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_GetDcAddress,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_GetDcAddress,
+-		(ndr_print_function_t) ndr_print_dfs_GetDcAddress,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6063,7 +6063,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_SetDcAddress),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_SetDcAddress,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_SetDcAddress,
+-		(ndr_print_function_t) ndr_print_dfs_SetDcAddress,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6072,7 +6072,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_FlushFtTable),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_FlushFtTable,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_FlushFtTable,
+-		(ndr_print_function_t) ndr_print_dfs_FlushFtTable,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6081,7 +6081,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Add2),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Add2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Add2,
+-		(ndr_print_function_t) ndr_print_dfs_Add2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6090,7 +6090,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_Remove2),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_Remove2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_Remove2,
+-		(ndr_print_function_t) ndr_print_dfs_Remove2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6099,7 +6099,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_EnumEx),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_EnumEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_EnumEx,
+-		(ndr_print_function_t) ndr_print_dfs_EnumEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6108,7 +6108,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct dfs_SetInfo2),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_SetInfo2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_SetInfo2,
+-		(ndr_print_function_t) ndr_print_dfs_SetInfo2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dfsblobs.c
++++ b/source3/librpc/gen_ndr/ndr_dfsblobs.c
+@@ -1398,7 +1398,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dfs_GetDFSReferral),
+ 		(ndr_push_flags_fn_t) ndr_push_dfs_GetDFSReferral,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dfs_GetDFSReferral,
+-		(ndr_print_function_t) ndr_print_dfs_GetDFSReferral,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dns.c
++++ b/source3/librpc/gen_ndr/ndr_dns.c
+@@ -860,7 +860,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_dns_name_packet),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_dns_name_packet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_dns_name_packet,
+-		(ndr_print_function_t) ndr_print_decode_dns_name_packet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dnsp.c
++++ b/source3/librpc/gen_ndr/ndr_dnsp.c
+@@ -700,7 +700,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_DnssrvRpcRecord),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_DnssrvRpcRecord,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_DnssrvRpcRecord,
+-		(ndr_print_function_t) ndr_print_decode_DnssrvRpcRecord,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dnsserver.c
++++ b/source3/librpc/gen_ndr/ndr_dnsserver.c
+@@ -48,7 +48,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dnsserver_foo),
+ 		(ndr_push_flags_fn_t) ndr_push_dnsserver_foo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dnsserver_foo,
+-		(ndr_print_function_t) ndr_print_dnsserver_foo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_drsblobs.c
++++ b/source3/librpc/gen_ndr/ndr_drsblobs.c
+@@ -5275,7 +5275,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_replPropertyMetaData),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_replPropertyMetaData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_replPropertyMetaData,
+-		(ndr_print_function_t) ndr_print_decode_replPropertyMetaData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5284,7 +5284,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_replUpToDateVector),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_replUpToDateVector,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_replUpToDateVector,
+-		(ndr_print_function_t) ndr_print_decode_replUpToDateVector,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5293,7 +5293,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_repsFromTo),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_repsFromTo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_repsFromTo,
+-		(ndr_print_function_t) ndr_print_decode_repsFromTo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5302,7 +5302,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_partialAttributeSet),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_partialAttributeSet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_partialAttributeSet,
+-		(ndr_print_function_t) ndr_print_decode_partialAttributeSet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5311,7 +5311,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_prefixMap),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_prefixMap,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_prefixMap,
+-		(ndr_print_function_t) ndr_print_decode_prefixMap,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5320,7 +5320,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_ldapControlDirSync),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_ldapControlDirSync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_ldapControlDirSync,
+-		(ndr_print_function_t) ndr_print_decode_ldapControlDirSync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5329,7 +5329,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_supplementalCredentials),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_supplementalCredentials,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_supplementalCredentials,
+-		(ndr_print_function_t) ndr_print_decode_supplementalCredentials,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5338,7 +5338,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_Packages),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_Packages,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_Packages,
+-		(ndr_print_function_t) ndr_print_decode_Packages,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5347,7 +5347,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_PrimaryKerberos),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_PrimaryKerberos,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_PrimaryKerberos,
+-		(ndr_print_function_t) ndr_print_decode_PrimaryKerberos,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5356,7 +5356,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_PrimaryCLEARTEXT),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_PrimaryCLEARTEXT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_PrimaryCLEARTEXT,
+-		(ndr_print_function_t) ndr_print_decode_PrimaryCLEARTEXT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5365,7 +5365,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_PrimaryWDigest),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_PrimaryWDigest,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_PrimaryWDigest,
+-		(ndr_print_function_t) ndr_print_decode_PrimaryWDigest,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5374,7 +5374,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_trustAuthInOut),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_trustAuthInOut,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_trustAuthInOut,
+-		(ndr_print_function_t) ndr_print_decode_trustAuthInOut,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5383,7 +5383,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_trustDomainPasswords),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_trustDomainPasswords,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_trustDomainPasswords,
+-		(ndr_print_function_t) ndr_print_decode_trustDomainPasswords,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5392,7 +5392,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_ExtendedErrorInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_ExtendedErrorInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_ExtendedErrorInfo,
+-		(ndr_print_function_t) ndr_print_decode_ExtendedErrorInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5401,7 +5401,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct decode_ForestTrustInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_ForestTrustInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_ForestTrustInfo,
+-		(ndr_print_function_t) ndr_print_decode_ForestTrustInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_drsuapi.c
++++ b/source3/librpc/gen_ndr/ndr_drsuapi.c
+@@ -16500,7 +16500,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsBind),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsBind,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsBind,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsBind,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16509,7 +16509,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsUnbind),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsUnbind,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsUnbind,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsUnbind,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16518,7 +16518,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsReplicaSync),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaSync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaSync,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsReplicaSync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16527,7 +16527,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsGetNCChanges),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetNCChanges,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetNCChanges,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsGetNCChanges,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16536,7 +16536,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsReplicaUpdateRefs),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaUpdateRefs,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaUpdateRefs,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsReplicaUpdateRefs,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16545,7 +16545,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsReplicaAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaAdd,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsReplicaAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16554,7 +16554,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsReplicaDel),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaDel,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsReplicaDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16563,7 +16563,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsReplicaMod),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaMod,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaMod,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsReplicaMod,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16572,7 +16572,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct DRSUAPI_VERIFY_NAMES),
+ 		(ndr_push_flags_fn_t) ndr_push_DRSUAPI_VERIFY_NAMES,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_VERIFY_NAMES,
+-		(ndr_print_function_t) ndr_print_DRSUAPI_VERIFY_NAMES,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16581,7 +16581,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsGetMemberships),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetMemberships,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetMemberships,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsGetMemberships,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16590,7 +16590,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct DRSUAPI_INTER_DOMAIN_MOVE),
+ 		(ndr_push_flags_fn_t) ndr_push_DRSUAPI_INTER_DOMAIN_MOVE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_INTER_DOMAIN_MOVE,
+-		(ndr_print_function_t) ndr_print_DRSUAPI_INTER_DOMAIN_MOVE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16599,7 +16599,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsGetNT4ChangeLog),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetNT4ChangeLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetNT4ChangeLog,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsGetNT4ChangeLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16608,7 +16608,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsCrackNames),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsCrackNames,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsCrackNames,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsCrackNames,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16617,7 +16617,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsWriteAccountSpn),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsWriteAccountSpn,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsWriteAccountSpn,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsWriteAccountSpn,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16626,7 +16626,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsRemoveDSServer),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsRemoveDSServer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsRemoveDSServer,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsRemoveDSServer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16635,7 +16635,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct DRSUAPI_REMOVE_DS_DOMAIN),
+ 		(ndr_push_flags_fn_t) ndr_push_DRSUAPI_REMOVE_DS_DOMAIN,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REMOVE_DS_DOMAIN,
+-		(ndr_print_function_t) ndr_print_DRSUAPI_REMOVE_DS_DOMAIN,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16644,7 +16644,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsGetDomainControllerInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetDomainControllerInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetDomainControllerInfo,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsGetDomainControllerInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16653,7 +16653,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsAddEntry),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsAddEntry,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsAddEntry,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsAddEntry,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16662,7 +16662,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsExecuteKCC),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsExecuteKCC,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsExecuteKCC,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsExecuteKCC,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16671,7 +16671,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsReplicaGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsReplicaGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsReplicaGetInfo,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsReplicaGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16680,7 +16680,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct DRSUAPI_ADD_SID_HISTORY),
+ 		(ndr_push_flags_fn_t) ndr_push_DRSUAPI_ADD_SID_HISTORY,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_ADD_SID_HISTORY,
+-		(ndr_print_function_t) ndr_print_DRSUAPI_ADD_SID_HISTORY,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16689,7 +16689,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_DsGetMemberships2),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_DsGetMemberships2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_DsGetMemberships2,
+-		(ndr_print_function_t) ndr_print_drsuapi_DsGetMemberships2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16698,7 +16698,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct DRSUAPI_REPLICA_VERIFY_OBJECTS),
+ 		(ndr_push_flags_fn_t) ndr_push_DRSUAPI_REPLICA_VERIFY_OBJECTS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_REPLICA_VERIFY_OBJECTS,
+-		(ndr_print_function_t) ndr_print_DRSUAPI_REPLICA_VERIFY_OBJECTS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16707,7 +16707,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct DRSUAPI_GET_OBJECT_EXISTENCE),
+ 		(ndr_push_flags_fn_t) ndr_push_DRSUAPI_GET_OBJECT_EXISTENCE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DRSUAPI_GET_OBJECT_EXISTENCE,
+-		(ndr_print_function_t) ndr_print_DRSUAPI_GET_OBJECT_EXISTENCE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -16716,7 +16716,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct drsuapi_QuerySitesByCost),
+ 		(ndr_push_flags_fn_t) ndr_push_drsuapi_QuerySitesByCost,
+ 		(ndr_pull_flags_fn_t) ndr_pull_drsuapi_QuerySitesByCost,
+-		(ndr_print_function_t) ndr_print_drsuapi_QuerySitesByCost,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dsbackup.c
++++ b/source3/librpc/gen_ndr/ndr_dsbackup.c
+@@ -360,7 +360,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupPrepare),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupPrepare,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupPrepare,
+-		(ndr_print_function_t) ndr_print_HrRBackupPrepare,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -369,7 +369,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupEnd),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupEnd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupEnd,
+-		(ndr_print_function_t) ndr_print_HrRBackupEnd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -378,7 +378,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupGetAttachmentInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupGetAttachmentInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupGetAttachmentInformation,
+-		(ndr_print_function_t) ndr_print_HrRBackupGetAttachmentInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -387,7 +387,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupOpenFile),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupOpenFile,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupOpenFile,
+-		(ndr_print_function_t) ndr_print_HrRBackupOpenFile,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -396,7 +396,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupRead),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupRead,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupRead,
+-		(ndr_print_function_t) ndr_print_HrRBackupRead,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -405,7 +405,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupClose),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupClose,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupClose,
+-		(ndr_print_function_t) ndr_print_HrRBackupClose,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -414,7 +414,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupGetBackupLogs),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupGetBackupLogs,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupGetBackupLogs,
+-		(ndr_print_function_t) ndr_print_HrRBackupGetBackupLogs,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -423,7 +423,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupTruncateLogs),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupTruncateLogs,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupTruncateLogs,
+-		(ndr_print_function_t) ndr_print_HrRBackupTruncateLogs,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -432,7 +432,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRBackupPing),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRBackupPing,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRBackupPing,
+-		(ndr_print_function_t) ndr_print_HrRBackupPing,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -789,7 +789,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRIsNTDSOnline),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRIsNTDSOnline,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRIsNTDSOnline,
+-		(ndr_print_function_t) ndr_print_HrRIsNTDSOnline,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -798,7 +798,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestorePrepare),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestorePrepare,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestorePrepare,
+-		(ndr_print_function_t) ndr_print_HrRRestorePrepare,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -807,7 +807,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestoreRegister),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestoreRegister,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestoreRegister,
+-		(ndr_print_function_t) ndr_print_HrRRestoreRegister,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -816,7 +816,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestoreRegisterComplete),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestoreRegisterComplete,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestoreRegisterComplete,
+-		(ndr_print_function_t) ndr_print_HrRRestoreRegisterComplete,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -825,7 +825,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestoreGetDatabaseLocations),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestoreGetDatabaseLocations,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestoreGetDatabaseLocations,
+-		(ndr_print_function_t) ndr_print_HrRRestoreGetDatabaseLocations,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -834,7 +834,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestoreEnd),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestoreEnd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestoreEnd,
+-		(ndr_print_function_t) ndr_print_HrRRestoreEnd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -843,7 +843,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestoreSetCurrentLogNumber),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestoreSetCurrentLogNumber,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestoreSetCurrentLogNumber,
+-		(ndr_print_function_t) ndr_print_HrRRestoreSetCurrentLogNumber,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -852,7 +852,7 @@ static const struct ndr_interface_call a
+ 		sizeof(struct HrRRestoreCheckLogsForBackup),
+ 		(ndr_push_flags_fn_t) ndr_push_HrRRestoreCheckLogsForBackup,
+ 		(ndr_pull_flags_fn_t) ndr_pull_HrRRestoreCheckLogsForBackup,
+-		(ndr_print_function_t) ndr_print_HrRRestoreCheckLogsForBackup,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_dssetup.c
++++ b/source3/librpc/gen_ndr/ndr_dssetup.c
+@@ -995,7 +995,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleGetPrimaryDomainInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleGetPrimaryDomainInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleGetPrimaryDomainInformation,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleGetPrimaryDomainInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1004,7 +1004,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleDnsNameToFlatName),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDnsNameToFlatName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDnsNameToFlatName,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleDnsNameToFlatName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1013,7 +1013,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleDcAsDc),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDcAsDc,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDcAsDc,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleDcAsDc,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1022,7 +1022,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleDcAsReplica),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDcAsReplica,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDcAsReplica,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleDcAsReplica,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1031,7 +1031,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleDemoteDc),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleDemoteDc,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleDemoteDc,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleDemoteDc,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1040,7 +1040,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleGetDcOperationProgress),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleGetDcOperationProgress,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleGetDcOperationProgress,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleGetDcOperationProgress,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1049,7 +1049,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleGetDcOperationResults),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleGetDcOperationResults,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleGetDcOperationResults,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleGetDcOperationResults,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1058,7 +1058,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleCancel),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleCancel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleCancel,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleCancel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1067,7 +1067,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleServerSaveStateForUpgrade),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleServerSaveStateForUpgrade,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleServerSaveStateForUpgrade,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleServerSaveStateForUpgrade,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1076,7 +1076,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleUpgradeDownlevelServer),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleUpgradeDownlevelServer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleUpgradeDownlevelServer,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleUpgradeDownlevelServer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1085,7 +1085,7 @@ static const struct ndr_interface_call d
+ 		sizeof(struct dssetup_DsRoleAbortDownlevelServerUpgrade),
+ 		(ndr_push_flags_fn_t) ndr_push_dssetup_DsRoleAbortDownlevelServerUpgrade,
+ 		(ndr_pull_flags_fn_t) ndr_pull_dssetup_DsRoleAbortDownlevelServerUpgrade,
+-		(ndr_print_function_t) ndr_print_dssetup_DsRoleAbortDownlevelServerUpgrade,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_echo.c
++++ b/source3/librpc/gen_ndr/ndr_echo.c
+@@ -1458,7 +1458,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_AddOne),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_AddOne,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_AddOne,
+-		(ndr_print_function_t) ndr_print_echo_AddOne,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1467,7 +1467,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_EchoData),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_EchoData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_EchoData,
+-		(ndr_print_function_t) ndr_print_echo_EchoData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1476,7 +1476,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_SinkData),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_SinkData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_SinkData,
+-		(ndr_print_function_t) ndr_print_echo_SinkData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1485,7 +1485,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_SourceData),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_SourceData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_SourceData,
+-		(ndr_print_function_t) ndr_print_echo_SourceData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1494,7 +1494,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_TestCall),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_TestCall,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_TestCall,
+-		(ndr_print_function_t) ndr_print_echo_TestCall,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1503,7 +1503,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_TestCall2),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_TestCall2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_TestCall2,
+-		(ndr_print_function_t) ndr_print_echo_TestCall2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1512,7 +1512,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_TestSleep),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_TestSleep,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_TestSleep,
+-		(ndr_print_function_t) ndr_print_echo_TestSleep,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1521,7 +1521,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_TestEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_TestEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_TestEnum,
+-		(ndr_print_function_t) ndr_print_echo_TestEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1530,7 +1530,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_TestSurrounding),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_TestSurrounding,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_TestSurrounding,
+-		(ndr_print_function_t) ndr_print_echo_TestSurrounding,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1539,7 +1539,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct echo_TestDoublePointer),
+ 		(ndr_push_flags_fn_t) ndr_push_echo_TestDoublePointer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_echo_TestDoublePointer,
+-		(ndr_print_function_t) ndr_print_echo_TestDoublePointer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_efs.c
++++ b/source3/librpc/gen_ndr/ndr_efs.c
+@@ -1327,7 +1327,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcOpenFileRaw),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcOpenFileRaw,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcOpenFileRaw,
+-		(ndr_print_function_t) ndr_print_EfsRpcOpenFileRaw,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1336,7 +1336,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcReadFileRaw),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcReadFileRaw,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcReadFileRaw,
+-		(ndr_print_function_t) ndr_print_EfsRpcReadFileRaw,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1345,7 +1345,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcWriteFileRaw),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcWriteFileRaw,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcWriteFileRaw,
+-		(ndr_print_function_t) ndr_print_EfsRpcWriteFileRaw,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1354,7 +1354,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcCloseRaw),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcCloseRaw,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcCloseRaw,
+-		(ndr_print_function_t) ndr_print_EfsRpcCloseRaw,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1363,7 +1363,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcEncryptFileSrv),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcEncryptFileSrv,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcEncryptFileSrv,
+-		(ndr_print_function_t) ndr_print_EfsRpcEncryptFileSrv,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1372,7 +1372,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcDecryptFileSrv),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcDecryptFileSrv,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcDecryptFileSrv,
+-		(ndr_print_function_t) ndr_print_EfsRpcDecryptFileSrv,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1381,7 +1381,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcQueryUsersOnFile),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcQueryUsersOnFile,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcQueryUsersOnFile,
+-		(ndr_print_function_t) ndr_print_EfsRpcQueryUsersOnFile,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1390,7 +1390,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcQueryRecoveryAgents),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcQueryRecoveryAgents,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcQueryRecoveryAgents,
+-		(ndr_print_function_t) ndr_print_EfsRpcQueryRecoveryAgents,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1399,7 +1399,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcRemoveUsersFromFile),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcRemoveUsersFromFile,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcRemoveUsersFromFile,
+-		(ndr_print_function_t) ndr_print_EfsRpcRemoveUsersFromFile,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1408,7 +1408,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcAddUsersToFile),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcAddUsersToFile,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcAddUsersToFile,
+-		(ndr_print_function_t) ndr_print_EfsRpcAddUsersToFile,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1417,7 +1417,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcSetFileEncryptionKey),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcSetFileEncryptionKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcSetFileEncryptionKey,
+-		(ndr_print_function_t) ndr_print_EfsRpcSetFileEncryptionKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1426,7 +1426,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcNotSupported),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcNotSupported,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcNotSupported,
+-		(ndr_print_function_t) ndr_print_EfsRpcNotSupported,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1435,7 +1435,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcFileKeyInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcFileKeyInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcFileKeyInfo,
+-		(ndr_print_function_t) ndr_print_EfsRpcFileKeyInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1444,7 +1444,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct EfsRpcDuplicateEncryptionInfoFile),
+ 		(ndr_push_flags_fn_t) ndr_push_EfsRpcDuplicateEncryptionInfoFile,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EfsRpcDuplicateEncryptionInfoFile,
+-		(ndr_print_function_t) ndr_print_EfsRpcDuplicateEncryptionInfoFile,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_epmapper.c
++++ b/source3/librpc/gen_ndr/ndr_epmapper.c
+@@ -2754,7 +2754,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_Insert),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_Insert,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_Insert,
+-		(ndr_print_function_t) ndr_print_epm_Insert,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2763,7 +2763,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_Delete),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_Delete,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_Delete,
+-		(ndr_print_function_t) ndr_print_epm_Delete,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2772,7 +2772,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_Lookup),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_Lookup,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_Lookup,
+-		(ndr_print_function_t) ndr_print_epm_Lookup,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2781,7 +2781,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_Map),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_Map,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_Map,
+-		(ndr_print_function_t) ndr_print_epm_Map,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2790,7 +2790,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_LookupHandleFree),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_LookupHandleFree,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_LookupHandleFree,
+-		(ndr_print_function_t) ndr_print_epm_LookupHandleFree,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2799,7 +2799,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_InqObject),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_InqObject,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_InqObject,
+-		(ndr_print_function_t) ndr_print_epm_InqObject,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2808,7 +2808,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_MgmtDelete),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_MgmtDelete,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_MgmtDelete,
+-		(ndr_print_function_t) ndr_print_epm_MgmtDelete,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2817,7 +2817,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct epm_MapAuth),
+ 		(ndr_push_flags_fn_t) ndr_push_epm_MapAuth,
+ 		(ndr_pull_flags_fn_t) ndr_pull_epm_MapAuth,
+-		(ndr_print_function_t) ndr_print_epm_MapAuth,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_eventlog.c
++++ b/source3/librpc/gen_ndr/ndr_eventlog.c
+@@ -2983,7 +2983,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ClearEventLogW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ClearEventLogW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ClearEventLogW,
+-		(ndr_print_function_t) ndr_print_eventlog_ClearEventLogW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2992,7 +2992,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_BackupEventLogW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_BackupEventLogW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_BackupEventLogW,
+-		(ndr_print_function_t) ndr_print_eventlog_BackupEventLogW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3001,7 +3001,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_CloseEventLog),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_CloseEventLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_CloseEventLog,
+-		(ndr_print_function_t) ndr_print_eventlog_CloseEventLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3010,7 +3010,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_DeregisterEventSource),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_DeregisterEventSource,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_DeregisterEventSource,
+-		(ndr_print_function_t) ndr_print_eventlog_DeregisterEventSource,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3019,7 +3019,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_GetNumRecords),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_GetNumRecords,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_GetNumRecords,
+-		(ndr_print_function_t) ndr_print_eventlog_GetNumRecords,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3028,7 +3028,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_GetOldestRecord),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_GetOldestRecord,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_GetOldestRecord,
+-		(ndr_print_function_t) ndr_print_eventlog_GetOldestRecord,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3037,7 +3037,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ChangeNotify),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ChangeNotify,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ChangeNotify,
+-		(ndr_print_function_t) ndr_print_eventlog_ChangeNotify,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3046,7 +3046,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_OpenEventLogW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_OpenEventLogW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenEventLogW,
+-		(ndr_print_function_t) ndr_print_eventlog_OpenEventLogW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3055,7 +3055,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_RegisterEventSourceW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_RegisterEventSourceW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_RegisterEventSourceW,
+-		(ndr_print_function_t) ndr_print_eventlog_RegisterEventSourceW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3064,7 +3064,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_OpenBackupEventLogW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_OpenBackupEventLogW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenBackupEventLogW,
+-		(ndr_print_function_t) ndr_print_eventlog_OpenBackupEventLogW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3073,7 +3073,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ReadEventLogW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ReadEventLogW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ReadEventLogW,
+-		(ndr_print_function_t) ndr_print_eventlog_ReadEventLogW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3082,7 +3082,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ReportEventW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ReportEventW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ReportEventW,
+-		(ndr_print_function_t) ndr_print_eventlog_ReportEventW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3091,7 +3091,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ClearEventLogA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ClearEventLogA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ClearEventLogA,
+-		(ndr_print_function_t) ndr_print_eventlog_ClearEventLogA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3100,7 +3100,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_BackupEventLogA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_BackupEventLogA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_BackupEventLogA,
+-		(ndr_print_function_t) ndr_print_eventlog_BackupEventLogA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3109,7 +3109,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_OpenEventLogA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_OpenEventLogA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenEventLogA,
+-		(ndr_print_function_t) ndr_print_eventlog_OpenEventLogA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3118,7 +3118,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_RegisterEventSourceA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_RegisterEventSourceA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_RegisterEventSourceA,
+-		(ndr_print_function_t) ndr_print_eventlog_RegisterEventSourceA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3127,7 +3127,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_OpenBackupEventLogA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_OpenBackupEventLogA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_OpenBackupEventLogA,
+-		(ndr_print_function_t) ndr_print_eventlog_OpenBackupEventLogA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3136,7 +3136,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ReadEventLogA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ReadEventLogA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ReadEventLogA,
+-		(ndr_print_function_t) ndr_print_eventlog_ReadEventLogA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3145,7 +3145,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ReportEventA),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ReportEventA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ReportEventA,
+-		(ndr_print_function_t) ndr_print_eventlog_ReportEventA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3154,7 +3154,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_RegisterClusterSvc),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_RegisterClusterSvc,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_RegisterClusterSvc,
+-		(ndr_print_function_t) ndr_print_eventlog_RegisterClusterSvc,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3163,7 +3163,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_DeregisterClusterSvc),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_DeregisterClusterSvc,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_DeregisterClusterSvc,
+-		(ndr_print_function_t) ndr_print_eventlog_DeregisterClusterSvc,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3172,7 +3172,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_WriteClusterEvents),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_WriteClusterEvents,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_WriteClusterEvents,
+-		(ndr_print_function_t) ndr_print_eventlog_WriteClusterEvents,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3181,7 +3181,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_GetLogInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_GetLogInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_GetLogInformation,
+-		(ndr_print_function_t) ndr_print_eventlog_GetLogInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3190,7 +3190,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_FlushEventLog),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_FlushEventLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_FlushEventLog,
+-		(ndr_print_function_t) ndr_print_eventlog_FlushEventLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3199,7 +3199,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog_ReportEventAndSourceW),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog_ReportEventAndSourceW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog_ReportEventAndSourceW,
+-		(ndr_print_function_t) ndr_print_eventlog_ReportEventAndSourceW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_eventlog6.c
++++ b/source3/librpc/gen_ndr/ndr_eventlog6.c
+@@ -5482,7 +5482,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRegisterRemoteSubscription),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRegisterRemoteSubscription,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRegisterRemoteSubscription,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRegisterRemoteSubscription,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5491,7 +5491,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRemoteSubscriptionNextAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRemoteSubscriptionNextAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRemoteSubscriptionNextAsync,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRemoteSubscriptionNextAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5500,7 +5500,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRemoteSubscriptionNext),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRemoteSubscriptionNext,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRemoteSubscriptionNext,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRemoteSubscriptionNext,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5509,7 +5509,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRemoteSubscriptionWaitAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRemoteSubscriptionWaitAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRemoteSubscriptionWaitAsync,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRemoteSubscriptionWaitAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5518,7 +5518,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRegisterControllableOperation),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRegisterControllableOperation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRegisterControllableOperation,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRegisterControllableOperation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5527,7 +5527,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRegisterLogQuery),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRegisterLogQuery,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRegisterLogQuery,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRegisterLogQuery,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5536,7 +5536,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcClearLog),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcClearLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcClearLog,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcClearLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5545,7 +5545,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcExportLog),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcExportLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcExportLog,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcExportLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5554,7 +5554,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcLocalizeExportLog),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcLocalizeExportLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcLocalizeExportLog,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcLocalizeExportLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5563,7 +5563,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcMessageRender),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcMessageRender,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcMessageRender,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcMessageRender,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5572,7 +5572,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcMessageRenderDefault),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcMessageRenderDefault,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcMessageRenderDefault,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcMessageRenderDefault,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5581,7 +5581,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcQueryNext),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcQueryNext,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcQueryNext,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcQueryNext,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5590,7 +5590,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcQuerySeek),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcQuerySeek,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcQuerySeek,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcQuerySeek,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5599,7 +5599,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcClose),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcClose,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcClose,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcClose,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5608,7 +5608,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcCancel),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcCancel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcCancel,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcCancel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5617,7 +5617,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcAssertConfig),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcAssertConfig,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcAssertConfig,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcAssertConfig,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5626,7 +5626,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcRetractConfig),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcRetractConfig,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcRetractConfig,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcRetractConfig,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5635,7 +5635,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcOpenLogHandle),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcOpenLogHandle,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcOpenLogHandle,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcOpenLogHandle,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5644,7 +5644,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetLogFileInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetLogFileInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetLogFileInfo,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetLogFileInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5653,7 +5653,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetChannelList),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetChannelList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetChannelList,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetChannelList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5662,7 +5662,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetChannelConfig),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetChannelConfig,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetChannelConfig,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetChannelConfig,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5671,7 +5671,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcPutChannelConfig),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcPutChannelConfig,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcPutChannelConfig,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcPutChannelConfig,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5680,7 +5680,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetPublisherList),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetPublisherList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetPublisherList,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetPublisherList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5689,7 +5689,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetPublisherListForChannel),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetPublisherListForChannel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetPublisherListForChannel,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetPublisherListForChannel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5698,7 +5698,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetPublisherMetadata),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetPublisherMetadata,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetPublisherMetadata,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetPublisherMetadata,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5707,7 +5707,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetPublisherResourceMetadata),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetPublisherResourceMetadata,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetPublisherResourceMetadata,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetPublisherResourceMetadata,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5716,7 +5716,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetEventMetadataEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetEventMetadataEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetEventMetadataEnum,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetEventMetadataEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5725,7 +5725,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetNextEventMetadata),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetNextEventMetadata,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetNextEventMetadata,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetNextEventMetadata,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5734,7 +5734,7 @@ static const struct ndr_interface_call e
+ 		sizeof(struct eventlog6_EvtRpcGetClassicLogDisplayName),
+ 		(ndr_push_flags_fn_t) ndr_push_eventlog6_EvtRpcGetClassicLogDisplayName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_eventlog6_EvtRpcGetClassicLogDisplayName,
+-		(ndr_print_function_t) ndr_print_eventlog6_EvtRpcGetClassicLogDisplayName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_frsapi.c
++++ b/source3/librpc/gen_ndr/ndr_frsapi.c
+@@ -979,7 +979,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSAPI_VERIFY_PROMOTION),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSAPI_VERIFY_PROMOTION,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSAPI_VERIFY_PROMOTION,
+-		(ndr_print_function_t) ndr_print_FRSAPI_VERIFY_PROMOTION,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -988,7 +988,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSAPI_PROMOTION_STATUS),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSAPI_PROMOTION_STATUS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSAPI_PROMOTION_STATUS,
+-		(ndr_print_function_t) ndr_print_FRSAPI_PROMOTION_STATUS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -997,7 +997,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSAPI_START_DEMOTION),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSAPI_START_DEMOTION,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSAPI_START_DEMOTION,
+-		(ndr_print_function_t) ndr_print_FRSAPI_START_DEMOTION,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1006,7 +1006,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSAPI_COMMIT_DEMOTION),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSAPI_COMMIT_DEMOTION,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSAPI_COMMIT_DEMOTION,
+-		(ndr_print_function_t) ndr_print_FRSAPI_COMMIT_DEMOTION,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1015,7 +1015,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsapi_SetDsPollingIntervalW),
+ 		(ndr_push_flags_fn_t) ndr_push_frsapi_SetDsPollingIntervalW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsapi_SetDsPollingIntervalW,
+-		(ndr_print_function_t) ndr_print_frsapi_SetDsPollingIntervalW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1024,7 +1024,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsapi_GetDsPollingIntervalW),
+ 		(ndr_push_flags_fn_t) ndr_push_frsapi_GetDsPollingIntervalW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsapi_GetDsPollingIntervalW,
+-		(ndr_print_function_t) ndr_print_frsapi_GetDsPollingIntervalW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1033,7 +1033,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSAPI_VERIFY_PROMOTION_W),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSAPI_VERIFY_PROMOTION_W,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSAPI_VERIFY_PROMOTION_W,
+-		(ndr_print_function_t) ndr_print_FRSAPI_VERIFY_PROMOTION_W,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1042,7 +1042,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsapi_InfoW),
+ 		(ndr_push_flags_fn_t) ndr_push_frsapi_InfoW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsapi_InfoW,
+-		(ndr_print_function_t) ndr_print_frsapi_InfoW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1051,7 +1051,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsapi_IsPathReplicated),
+ 		(ndr_push_flags_fn_t) ndr_push_frsapi_IsPathReplicated,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsapi_IsPathReplicated,
+-		(ndr_print_function_t) ndr_print_frsapi_IsPathReplicated,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1060,7 +1060,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsapi_WriterCommand),
+ 		(ndr_push_flags_fn_t) ndr_push_frsapi_WriterCommand,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsapi_WriterCommand,
+-		(ndr_print_function_t) ndr_print_frsapi_WriterCommand,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1069,7 +1069,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsapi_ForceReplication),
+ 		(ndr_push_flags_fn_t) ndr_push_frsapi_ForceReplication,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsapi_ForceReplication,
+-		(ndr_print_function_t) ndr_print_frsapi_ForceReplication,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_frsrpc.c
++++ b/source3/librpc/gen_ndr/ndr_frsrpc.c
+@@ -2781,7 +2781,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsrpc_FrsSendCommPkt),
+ 		(ndr_push_flags_fn_t) ndr_push_frsrpc_FrsSendCommPkt,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsrpc_FrsSendCommPkt,
+-		(ndr_print_function_t) ndr_print_frsrpc_FrsSendCommPkt,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2790,7 +2790,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsrpc_FrsVerifyPromotionParent),
+ 		(ndr_push_flags_fn_t) ndr_push_frsrpc_FrsVerifyPromotionParent,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsrpc_FrsVerifyPromotionParent,
+-		(ndr_print_function_t) ndr_print_frsrpc_FrsVerifyPromotionParent,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2799,7 +2799,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsrpc_FrsStartPromotionParent),
+ 		(ndr_push_flags_fn_t) ndr_push_frsrpc_FrsStartPromotionParent,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsrpc_FrsStartPromotionParent,
+-		(ndr_print_function_t) ndr_print_frsrpc_FrsStartPromotionParent,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2808,7 +2808,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frsrpc_FrsNOP),
+ 		(ndr_push_flags_fn_t) ndr_push_frsrpc_FrsNOP,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frsrpc_FrsNOP,
+-		(ndr_print_function_t) ndr_print_frsrpc_FrsNOP,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2817,7 +2817,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_BACKUP_COMPLETE),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_BACKUP_COMPLETE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_BACKUP_COMPLETE,
+-		(ndr_print_function_t) ndr_print_FRSRPC_BACKUP_COMPLETE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2826,7 +2826,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_BACKUP_COMPLETE_5),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_BACKUP_COMPLETE_5,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_BACKUP_COMPLETE_5,
+-		(ndr_print_function_t) ndr_print_FRSRPC_BACKUP_COMPLETE_5,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2835,7 +2835,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_BACKUP_COMPLETE_6),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_BACKUP_COMPLETE_6,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_BACKUP_COMPLETE_6,
+-		(ndr_print_function_t) ndr_print_FRSRPC_BACKUP_COMPLETE_6,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2844,7 +2844,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_BACKUP_COMPLETE_7),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_BACKUP_COMPLETE_7,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_BACKUP_COMPLETE_7,
+-		(ndr_print_function_t) ndr_print_FRSRPC_BACKUP_COMPLETE_7,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2853,7 +2853,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_BACKUP_COMPLETE_8),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_BACKUP_COMPLETE_8,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_BACKUP_COMPLETE_8,
+-		(ndr_print_function_t) ndr_print_FRSRPC_BACKUP_COMPLETE_8,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2862,7 +2862,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_BACKUP_COMPLETE_9),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_BACKUP_COMPLETE_9,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_BACKUP_COMPLETE_9,
+-		(ndr_print_function_t) ndr_print_FRSRPC_BACKUP_COMPLETE_9,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2871,7 +2871,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSRPC_VERIFY_PROMOTION_PARENT_EX),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSRPC_VERIFY_PROMOTION_PARENT_EX,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSRPC_VERIFY_PROMOTION_PARENT_EX,
+-		(ndr_print_function_t) ndr_print_FRSRPC_VERIFY_PROMOTION_PARENT_EX,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_frstrans.c
++++ b/source3/librpc/gen_ndr/ndr_frstrans.c
+@@ -2331,7 +2331,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_CheckConnectivity),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_CheckConnectivity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_CheckConnectivity,
+-		(ndr_print_function_t) ndr_print_frstrans_CheckConnectivity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2340,7 +2340,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_EstablishConnection),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_EstablishConnection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_EstablishConnection,
+-		(ndr_print_function_t) ndr_print_frstrans_EstablishConnection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2349,7 +2349,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_EstablishSession),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_EstablishSession,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_EstablishSession,
+-		(ndr_print_function_t) ndr_print_frstrans_EstablishSession,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2358,7 +2358,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_RequestUpdates),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_RequestUpdates,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_RequestUpdates,
+-		(ndr_print_function_t) ndr_print_frstrans_RequestUpdates,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2367,7 +2367,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_RequestVersionVector),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_RequestVersionVector,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_RequestVersionVector,
+-		(ndr_print_function_t) ndr_print_frstrans_RequestVersionVector,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2376,7 +2376,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_AsyncPoll),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_AsyncPoll,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_AsyncPoll,
+-		(ndr_print_function_t) ndr_print_frstrans_AsyncPoll,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2385,7 +2385,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_REQUEST_RECORDS),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_REQUEST_RECORDS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_REQUEST_RECORDS,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_REQUEST_RECORDS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2394,7 +2394,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_UPDATE_CANCEL),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_UPDATE_CANCEL,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_UPDATE_CANCEL,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_UPDATE_CANCEL,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2403,7 +2403,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_RAW_GET_FILE_DATA),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_RAW_GET_FILE_DATA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_RAW_GET_FILE_DATA,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_RAW_GET_FILE_DATA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2412,7 +2412,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_RDC_GET_SIGNATURES),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_RDC_GET_SIGNATURES,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_RDC_GET_SIGNATURES,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_RDC_GET_SIGNATURES,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2421,7 +2421,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_RDC_PUSH_SOURCE_NEEDS),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_RDC_PUSH_SOURCE_NEEDS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_RDC_PUSH_SOURCE_NEEDS,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_RDC_PUSH_SOURCE_NEEDS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2430,7 +2430,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_RDC_GET_FILE_DATA),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_RDC_GET_FILE_DATA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_RDC_GET_FILE_DATA,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_RDC_GET_FILE_DATA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2439,7 +2439,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_RDC_CLOSE),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_RDC_CLOSE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_RDC_CLOSE,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_RDC_CLOSE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2448,7 +2448,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_InitializeFileTransferAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_InitializeFileTransferAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_InitializeFileTransferAsync,
+-		(ndr_print_function_t) ndr_print_frstrans_InitializeFileTransferAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2457,7 +2457,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct FRSTRANS_OPNUM_0E_NOT_USED_ON_THE_WIRE),
+ 		(ndr_push_flags_fn_t) ndr_push_FRSTRANS_OPNUM_0E_NOT_USED_ON_THE_WIRE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_FRSTRANS_OPNUM_0E_NOT_USED_ON_THE_WIRE,
+-		(ndr_print_function_t) ndr_print_FRSTRANS_OPNUM_0E_NOT_USED_ON_THE_WIRE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2466,7 +2466,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_RawGetFileDataAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_RawGetFileDataAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_RawGetFileDataAsync,
+-		(ndr_print_function_t) ndr_print_frstrans_RawGetFileDataAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 1, frstrans_RawGetFileDataAsync_out_pipes },
+ 	},
+@@ -2475,7 +2475,7 @@ static const struct ndr_interface_call f
+ 		sizeof(struct frstrans_RdcGetFileDataAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_frstrans_RdcGetFileDataAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_frstrans_RdcGetFileDataAsync,
+-		(ndr_print_function_t) ndr_print_frstrans_RdcGetFileDataAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 1, frstrans_RdcGetFileDataAsync_out_pipes },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_initshutdown.c
++++ b/source3/librpc/gen_ndr/ndr_initshutdown.c
+@@ -277,7 +277,7 @@ static const struct ndr_interface_call i
+ 		sizeof(struct initshutdown_Init),
+ 		(ndr_push_flags_fn_t) ndr_push_initshutdown_Init,
+ 		(ndr_pull_flags_fn_t) ndr_pull_initshutdown_Init,
+-		(ndr_print_function_t) ndr_print_initshutdown_Init,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -286,7 +286,7 @@ static const struct ndr_interface_call i
+ 		sizeof(struct initshutdown_Abort),
+ 		(ndr_push_flags_fn_t) ndr_push_initshutdown_Abort,
+ 		(ndr_pull_flags_fn_t) ndr_pull_initshutdown_Abort,
+-		(ndr_print_function_t) ndr_print_initshutdown_Abort,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -295,7 +295,7 @@ static const struct ndr_interface_call i
+ 		sizeof(struct initshutdown_InitEx),
+ 		(ndr_push_flags_fn_t) ndr_push_initshutdown_InitEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_initshutdown_InitEx,
+-		(ndr_print_function_t) ndr_print_initshutdown_InitEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_keysvc.c
++++ b/source3/librpc/gen_ndr/ndr_keysvc.c
+@@ -51,7 +51,7 @@ static const struct ndr_interface_call k
+ 		sizeof(struct keysvc_Unknown0),
+ 		(ndr_push_flags_fn_t) ndr_push_keysvc_Unknown0,
+ 		(ndr_pull_flags_fn_t) ndr_pull_keysvc_Unknown0,
+-		(ndr_print_function_t) ndr_print_keysvc_Unknown0,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_krb5pac.c
++++ b/source3/librpc/gen_ndr/ndr_krb5pac.c
+@@ -1002,7 +1002,7 @@ static const struct ndr_interface_call k
+ 		sizeof(struct decode_pac),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_pac,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_pac,
+-		(ndr_print_function_t) ndr_print_decode_pac,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1011,7 +1011,7 @@ static const struct ndr_interface_call k
+ 		sizeof(struct decode_pac_raw),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_pac_raw,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_pac_raw,
+-		(ndr_print_function_t) ndr_print_decode_pac_raw,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1020,7 +1020,7 @@ static const struct ndr_interface_call k
+ 		sizeof(struct decode_login_info),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_login_info,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_login_info,
+-		(ndr_print_function_t) ndr_print_decode_login_info,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1029,7 +1029,7 @@ static const struct ndr_interface_call k
+ 		sizeof(struct decode_login_info_ctr),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_login_info_ctr,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_login_info_ctr,
+-		(ndr_print_function_t) ndr_print_decode_login_info_ctr,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -1038,7 +1038,7 @@ static const struct ndr_interface_call k
+ 		sizeof(struct decode_pac_validate),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_pac_validate,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_pac_validate,
+-		(ndr_print_function_t) ndr_print_decode_pac_validate,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_lsa.c
++++ b/source3/librpc/gen_ndr/ndr_lsa.c
+@@ -13565,7 +13565,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_Close),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_Close,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_Close,
+-		(ndr_print_function_t) ndr_print_lsa_Close,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13574,7 +13574,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_Delete),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_Delete,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_Delete,
+-		(ndr_print_function_t) ndr_print_lsa_Delete,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13583,7 +13583,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumPrivs),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumPrivs,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumPrivs,
+-		(ndr_print_function_t) ndr_print_lsa_EnumPrivs,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13592,7 +13592,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QuerySecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QuerySecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QuerySecurity,
+-		(ndr_print_function_t) ndr_print_lsa_QuerySecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13601,7 +13601,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetSecObj),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetSecObj,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetSecObj,
+-		(ndr_print_function_t) ndr_print_lsa_SetSecObj,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13610,7 +13610,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_ChangePassword),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_ChangePassword,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_ChangePassword,
+-		(ndr_print_function_t) ndr_print_lsa_ChangePassword,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13619,7 +13619,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_OpenPolicy),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_OpenPolicy,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_OpenPolicy,
+-		(ndr_print_function_t) ndr_print_lsa_OpenPolicy,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13628,7 +13628,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QueryInfoPolicy),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QueryInfoPolicy,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QueryInfoPolicy,
+-		(ndr_print_function_t) ndr_print_lsa_QueryInfoPolicy,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13637,7 +13637,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetInfoPolicy),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetInfoPolicy,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetInfoPolicy,
+-		(ndr_print_function_t) ndr_print_lsa_SetInfoPolicy,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13646,7 +13646,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_ClearAuditLog),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_ClearAuditLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_ClearAuditLog,
+-		(ndr_print_function_t) ndr_print_lsa_ClearAuditLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13655,7 +13655,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CreateAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CreateAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CreateAccount,
+-		(ndr_print_function_t) ndr_print_lsa_CreateAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13664,7 +13664,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumAccounts),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumAccounts,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumAccounts,
+-		(ndr_print_function_t) ndr_print_lsa_EnumAccounts,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13673,7 +13673,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CreateTrustedDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CreateTrustedDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CreateTrustedDomain,
+-		(ndr_print_function_t) ndr_print_lsa_CreateTrustedDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13682,7 +13682,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumTrustDom),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumTrustDom,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumTrustDom,
+-		(ndr_print_function_t) ndr_print_lsa_EnumTrustDom,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13691,7 +13691,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupNames),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupNames,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames,
+-		(ndr_print_function_t) ndr_print_lsa_LookupNames,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13700,7 +13700,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupSids),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupSids,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupSids,
+-		(ndr_print_function_t) ndr_print_lsa_LookupSids,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13709,7 +13709,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CreateSecret),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CreateSecret,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CreateSecret,
+-		(ndr_print_function_t) ndr_print_lsa_CreateSecret,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13718,7 +13718,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_OpenAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_OpenAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_OpenAccount,
+-		(ndr_print_function_t) ndr_print_lsa_OpenAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13727,7 +13727,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumPrivsAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumPrivsAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumPrivsAccount,
+-		(ndr_print_function_t) ndr_print_lsa_EnumPrivsAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13736,7 +13736,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_AddPrivilegesToAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_AddPrivilegesToAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_AddPrivilegesToAccount,
+-		(ndr_print_function_t) ndr_print_lsa_AddPrivilegesToAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13745,7 +13745,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_RemovePrivilegesFromAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_RemovePrivilegesFromAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_RemovePrivilegesFromAccount,
+-		(ndr_print_function_t) ndr_print_lsa_RemovePrivilegesFromAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13754,7 +13754,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_GetQuotasForAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_GetQuotasForAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_GetQuotasForAccount,
+-		(ndr_print_function_t) ndr_print_lsa_GetQuotasForAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13763,7 +13763,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetQuotasForAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetQuotasForAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetQuotasForAccount,
+-		(ndr_print_function_t) ndr_print_lsa_SetQuotasForAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13772,7 +13772,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_GetSystemAccessAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_GetSystemAccessAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_GetSystemAccessAccount,
+-		(ndr_print_function_t) ndr_print_lsa_GetSystemAccessAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13781,7 +13781,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetSystemAccessAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetSystemAccessAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetSystemAccessAccount,
+-		(ndr_print_function_t) ndr_print_lsa_SetSystemAccessAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13790,7 +13790,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_OpenTrustedDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_OpenTrustedDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_OpenTrustedDomain,
+-		(ndr_print_function_t) ndr_print_lsa_OpenTrustedDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13799,7 +13799,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QueryTrustedDomainInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QueryTrustedDomainInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QueryTrustedDomainInfo,
+-		(ndr_print_function_t) ndr_print_lsa_QueryTrustedDomainInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13808,7 +13808,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetInformationTrustedDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetInformationTrustedDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetInformationTrustedDomain,
+-		(ndr_print_function_t) ndr_print_lsa_SetInformationTrustedDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13817,7 +13817,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_OpenSecret),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_OpenSecret,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_OpenSecret,
+-		(ndr_print_function_t) ndr_print_lsa_OpenSecret,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13826,7 +13826,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetSecret),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetSecret,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetSecret,
+-		(ndr_print_function_t) ndr_print_lsa_SetSecret,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13835,7 +13835,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QuerySecret),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QuerySecret,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QuerySecret,
+-		(ndr_print_function_t) ndr_print_lsa_QuerySecret,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13844,7 +13844,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupPrivValue),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupPrivValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupPrivValue,
+-		(ndr_print_function_t) ndr_print_lsa_LookupPrivValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13853,7 +13853,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupPrivName),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupPrivName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupPrivName,
+-		(ndr_print_function_t) ndr_print_lsa_LookupPrivName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13862,7 +13862,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupPrivDisplayName),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupPrivDisplayName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupPrivDisplayName,
+-		(ndr_print_function_t) ndr_print_lsa_LookupPrivDisplayName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13871,7 +13871,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_DeleteObject),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_DeleteObject,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_DeleteObject,
+-		(ndr_print_function_t) ndr_print_lsa_DeleteObject,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13880,7 +13880,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumAccountsWithUserRight),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumAccountsWithUserRight,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumAccountsWithUserRight,
+-		(ndr_print_function_t) ndr_print_lsa_EnumAccountsWithUserRight,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13889,7 +13889,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumAccountRights),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumAccountRights,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumAccountRights,
+-		(ndr_print_function_t) ndr_print_lsa_EnumAccountRights,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13898,7 +13898,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_AddAccountRights),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_AddAccountRights,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_AddAccountRights,
+-		(ndr_print_function_t) ndr_print_lsa_AddAccountRights,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13907,7 +13907,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_RemoveAccountRights),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_RemoveAccountRights,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_RemoveAccountRights,
+-		(ndr_print_function_t) ndr_print_lsa_RemoveAccountRights,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13916,7 +13916,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QueryTrustedDomainInfoBySid),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QueryTrustedDomainInfoBySid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QueryTrustedDomainInfoBySid,
+-		(ndr_print_function_t) ndr_print_lsa_QueryTrustedDomainInfoBySid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13925,7 +13925,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetTrustedDomainInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetTrustedDomainInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetTrustedDomainInfo,
+-		(ndr_print_function_t) ndr_print_lsa_SetTrustedDomainInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13934,7 +13934,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_DeleteTrustedDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_DeleteTrustedDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_DeleteTrustedDomain,
+-		(ndr_print_function_t) ndr_print_lsa_DeleteTrustedDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13943,7 +13943,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_StorePrivateData),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_StorePrivateData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_StorePrivateData,
+-		(ndr_print_function_t) ndr_print_lsa_StorePrivateData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13952,7 +13952,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_RetrievePrivateData),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_RetrievePrivateData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_RetrievePrivateData,
+-		(ndr_print_function_t) ndr_print_lsa_RetrievePrivateData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13961,7 +13961,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_OpenPolicy2),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_OpenPolicy2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_OpenPolicy2,
+-		(ndr_print_function_t) ndr_print_lsa_OpenPolicy2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13970,7 +13970,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_GetUserName),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_GetUserName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_GetUserName,
+-		(ndr_print_function_t) ndr_print_lsa_GetUserName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13979,7 +13979,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QueryInfoPolicy2),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QueryInfoPolicy2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QueryInfoPolicy2,
+-		(ndr_print_function_t) ndr_print_lsa_QueryInfoPolicy2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13988,7 +13988,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetInfoPolicy2),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetInfoPolicy2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetInfoPolicy2,
+-		(ndr_print_function_t) ndr_print_lsa_SetInfoPolicy2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13997,7 +13997,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QueryTrustedDomainInfoByName),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QueryTrustedDomainInfoByName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QueryTrustedDomainInfoByName,
+-		(ndr_print_function_t) ndr_print_lsa_QueryTrustedDomainInfoByName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14006,7 +14006,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetTrustedDomainInfoByName),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetTrustedDomainInfoByName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetTrustedDomainInfoByName,
+-		(ndr_print_function_t) ndr_print_lsa_SetTrustedDomainInfoByName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14015,7 +14015,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_EnumTrustedDomainsEx),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_EnumTrustedDomainsEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_EnumTrustedDomainsEx,
+-		(ndr_print_function_t) ndr_print_lsa_EnumTrustedDomainsEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14024,7 +14024,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CreateTrustedDomainEx),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CreateTrustedDomainEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CreateTrustedDomainEx,
+-		(ndr_print_function_t) ndr_print_lsa_CreateTrustedDomainEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14033,7 +14033,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CloseTrustedDomainEx),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CloseTrustedDomainEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CloseTrustedDomainEx,
+-		(ndr_print_function_t) ndr_print_lsa_CloseTrustedDomainEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14042,7 +14042,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_QueryDomainInformationPolicy),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_QueryDomainInformationPolicy,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_QueryDomainInformationPolicy,
+-		(ndr_print_function_t) ndr_print_lsa_QueryDomainInformationPolicy,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14051,7 +14051,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_SetDomainInformationPolicy),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_SetDomainInformationPolicy,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_SetDomainInformationPolicy,
+-		(ndr_print_function_t) ndr_print_lsa_SetDomainInformationPolicy,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14060,7 +14060,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_OpenTrustedDomainByName),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_OpenTrustedDomainByName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_OpenTrustedDomainByName,
+-		(ndr_print_function_t) ndr_print_lsa_OpenTrustedDomainByName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14069,7 +14069,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_TestCall),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_TestCall,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_TestCall,
+-		(ndr_print_function_t) ndr_print_lsa_TestCall,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14078,7 +14078,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupSids2),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupSids2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupSids2,
+-		(ndr_print_function_t) ndr_print_lsa_LookupSids2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14087,7 +14087,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupNames2),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupNames2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames2,
+-		(ndr_print_function_t) ndr_print_lsa_LookupNames2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14096,7 +14096,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CreateTrustedDomainEx2),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CreateTrustedDomainEx2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CreateTrustedDomainEx2,
+-		(ndr_print_function_t) ndr_print_lsa_CreateTrustedDomainEx2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14105,7 +14105,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRWRITE),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRWRITE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRWRITE,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRWRITE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14114,7 +14114,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRREAD),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRREAD,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRREAD,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRREAD,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14123,7 +14123,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRENUMERATE),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRENUMERATE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRENUMERATE,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRENUMERATE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14132,7 +14132,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRWRITEDOMAINCREDENTIALS),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRWRITEDOMAINCREDENTIALS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRWRITEDOMAINCREDENTIALS,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRWRITEDOMAINCREDENTIALS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14141,7 +14141,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRREADDOMAINCREDENTIALS),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRREADDOMAINCREDENTIALS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRREADDOMAINCREDENTIALS,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRREADDOMAINCREDENTIALS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14150,7 +14150,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRDELETE),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRDELETE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRDELETE,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRDELETE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14159,7 +14159,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRGETTARGETINFO),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRGETTARGETINFO,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRGETTARGETINFO,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRGETTARGETINFO,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14168,7 +14168,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRPROFILELOADED),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRPROFILELOADED,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRPROFILELOADED,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRPROFILELOADED,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14177,7 +14177,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupNames3),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupNames3,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames3,
+-		(ndr_print_function_t) ndr_print_lsa_LookupNames3,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14186,7 +14186,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRGETSESSIONTYPES),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRGETSESSIONTYPES,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRGETSESSIONTYPES,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRGETSESSIONTYPES,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14195,7 +14195,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSARREGISTERAUDITEVENT),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSARREGISTERAUDITEVENT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSARREGISTERAUDITEVENT,
+-		(ndr_print_function_t) ndr_print_lsa_LSARREGISTERAUDITEVENT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14204,7 +14204,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSARGENAUDITEVENT),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSARGENAUDITEVENT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSARGENAUDITEVENT,
+-		(ndr_print_function_t) ndr_print_lsa_LSARGENAUDITEVENT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14213,7 +14213,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSARUNREGISTERAUDITEVENT),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSARUNREGISTERAUDITEVENT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSARUNREGISTERAUDITEVENT,
+-		(ndr_print_function_t) ndr_print_lsa_LSARUNREGISTERAUDITEVENT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14222,7 +14222,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_lsaRQueryForestTrustInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_lsaRQueryForestTrustInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_lsaRQueryForestTrustInformation,
+-		(ndr_print_function_t) ndr_print_lsa_lsaRQueryForestTrustInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14231,7 +14231,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_lsaRSetForestTrustInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_lsaRSetForestTrustInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_lsaRSetForestTrustInformation,
+-		(ndr_print_function_t) ndr_print_lsa_lsaRSetForestTrustInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14240,7 +14240,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_CREDRRENAME),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_CREDRRENAME,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_CREDRRENAME,
+-		(ndr_print_function_t) ndr_print_lsa_CREDRRENAME,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14249,7 +14249,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupSids3),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupSids3,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupSids3,
+-		(ndr_print_function_t) ndr_print_lsa_LookupSids3,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14258,7 +14258,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LookupNames4),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LookupNames4,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LookupNames4,
+-		(ndr_print_function_t) ndr_print_lsa_LookupNames4,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14267,7 +14267,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSAROPENPOLICYSCE),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSAROPENPOLICYSCE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSAROPENPOLICYSCE,
+-		(ndr_print_function_t) ndr_print_lsa_LSAROPENPOLICYSCE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14276,7 +14276,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSARADTREGISTERSECURITYEVENTSOURCE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSARADTREGISTERSECURITYEVENTSOURCE,
+-		(ndr_print_function_t) ndr_print_lsa_LSARADTREGISTERSECURITYEVENTSOURCE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14285,7 +14285,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE,
+-		(ndr_print_function_t) ndr_print_lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -14294,7 +14294,7 @@ static const struct ndr_interface_call l
+ 		sizeof(struct lsa_LSARADTREPORTSECURITYEVENT),
+ 		(ndr_push_flags_fn_t) ndr_push_lsa_LSARADTREPORTSECURITYEVENT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_lsa_LSARADTREPORTSECURITYEVENT,
+-		(ndr_print_function_t) ndr_print_lsa_LSARADTREPORTSECURITYEVENT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_mgmt.c
++++ b/source3/librpc/gen_ndr/ndr_mgmt.c
+@@ -515,7 +515,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct mgmt_inq_if_ids),
+ 		(ndr_push_flags_fn_t) ndr_push_mgmt_inq_if_ids,
+ 		(ndr_pull_flags_fn_t) ndr_pull_mgmt_inq_if_ids,
+-		(ndr_print_function_t) ndr_print_mgmt_inq_if_ids,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -524,7 +524,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct mgmt_inq_stats),
+ 		(ndr_push_flags_fn_t) ndr_push_mgmt_inq_stats,
+ 		(ndr_pull_flags_fn_t) ndr_pull_mgmt_inq_stats,
+-		(ndr_print_function_t) ndr_print_mgmt_inq_stats,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -533,7 +533,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct mgmt_is_server_listening),
+ 		(ndr_push_flags_fn_t) ndr_push_mgmt_is_server_listening,
+ 		(ndr_pull_flags_fn_t) ndr_pull_mgmt_is_server_listening,
+-		(ndr_print_function_t) ndr_print_mgmt_is_server_listening,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -542,7 +542,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct mgmt_stop_server_listening),
+ 		(ndr_push_flags_fn_t) ndr_push_mgmt_stop_server_listening,
+ 		(ndr_pull_flags_fn_t) ndr_pull_mgmt_stop_server_listening,
+-		(ndr_print_function_t) ndr_print_mgmt_stop_server_listening,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -551,7 +551,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct mgmt_inq_princ_name),
+ 		(ndr_push_flags_fn_t) ndr_push_mgmt_inq_princ_name,
+ 		(ndr_pull_flags_fn_t) ndr_pull_mgmt_inq_princ_name,
+-		(ndr_print_function_t) ndr_print_mgmt_inq_princ_name,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_msgsvc.c
++++ b/source3/librpc/gen_ndr/ndr_msgsvc.c
+@@ -165,7 +165,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct NetrMessageNameAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrMessageNameAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrMessageNameAdd,
+-		(ndr_print_function_t) ndr_print_NetrMessageNameAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -174,7 +174,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct NetrMessageNameEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrMessageNameEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrMessageNameEnum,
+-		(ndr_print_function_t) ndr_print_NetrMessageNameEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -183,7 +183,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct NetrMessageNameGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrMessageNameGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrMessageNameGetInfo,
+-		(ndr_print_function_t) ndr_print_NetrMessageNameGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -192,7 +192,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct NetrMessageNameDel),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrMessageNameDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrMessageNameDel,
+-		(ndr_print_function_t) ndr_print_NetrMessageNameDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -276,7 +276,7 @@ static const struct ndr_interface_call m
+ 		sizeof(struct NetrSendMessage),
+ 		(ndr_push_flags_fn_t) ndr_push_NetrSendMessage,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NetrSendMessage,
+-		(ndr_print_function_t) ndr_print_NetrSendMessage,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_nbt.c
++++ b/source3/librpc/gen_ndr/ndr_nbt.c
+@@ -3671,7 +3671,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_nbt_netlogon_packet),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_nbt_netlogon_packet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_nbt_netlogon_packet,
+-		(ndr_print_function_t) ndr_print_decode_nbt_netlogon_packet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_netlogon.c
++++ b/source3/librpc/gen_ndr/ndr_netlogon.c
+@@ -17827,7 +17827,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonUasLogon),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonUasLogon,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonUasLogon,
+-		(ndr_print_function_t) ndr_print_netr_LogonUasLogon,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17836,7 +17836,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonUasLogoff),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonUasLogoff,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonUasLogoff,
+-		(ndr_print_function_t) ndr_print_netr_LogonUasLogoff,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17845,7 +17845,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonSamLogon),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogon,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogon,
+-		(ndr_print_function_t) ndr_print_netr_LogonSamLogon,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17854,7 +17854,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonSamLogoff),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogoff,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogoff,
+-		(ndr_print_function_t) ndr_print_netr_LogonSamLogoff,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17863,7 +17863,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerReqChallenge),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerReqChallenge,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerReqChallenge,
+-		(ndr_print_function_t) ndr_print_netr_ServerReqChallenge,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17872,7 +17872,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerAuthenticate),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerAuthenticate,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerAuthenticate,
+-		(ndr_print_function_t) ndr_print_netr_ServerAuthenticate,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17881,7 +17881,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerPasswordSet),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerPasswordSet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerPasswordSet,
+-		(ndr_print_function_t) ndr_print_netr_ServerPasswordSet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17890,7 +17890,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DatabaseDeltas),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DatabaseDeltas,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseDeltas,
+-		(ndr_print_function_t) ndr_print_netr_DatabaseDeltas,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17899,7 +17899,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DatabaseSync),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DatabaseSync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseSync,
+-		(ndr_print_function_t) ndr_print_netr_DatabaseSync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17908,7 +17908,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_AccountDeltas),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_AccountDeltas,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_AccountDeltas,
+-		(ndr_print_function_t) ndr_print_netr_AccountDeltas,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17917,7 +17917,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_AccountSync),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_AccountSync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_AccountSync,
+-		(ndr_print_function_t) ndr_print_netr_AccountSync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17926,7 +17926,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_GetDcName),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_GetDcName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_GetDcName,
+-		(ndr_print_function_t) ndr_print_netr_GetDcName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17935,7 +17935,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonControl),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonControl,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonControl,
+-		(ndr_print_function_t) ndr_print_netr_LogonControl,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17944,7 +17944,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_GetAnyDCName),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_GetAnyDCName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_GetAnyDCName,
+-		(ndr_print_function_t) ndr_print_netr_GetAnyDCName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17953,7 +17953,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonControl2),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonControl2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonControl2,
+-		(ndr_print_function_t) ndr_print_netr_LogonControl2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17962,7 +17962,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerAuthenticate2),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerAuthenticate2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerAuthenticate2,
+-		(ndr_print_function_t) ndr_print_netr_ServerAuthenticate2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17971,7 +17971,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DatabaseSync2),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DatabaseSync2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseSync2,
+-		(ndr_print_function_t) ndr_print_netr_DatabaseSync2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17980,7 +17980,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DatabaseRedo),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DatabaseRedo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DatabaseRedo,
+-		(ndr_print_function_t) ndr_print_netr_DatabaseRedo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17989,7 +17989,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonControl2Ex),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonControl2Ex,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonControl2Ex,
+-		(ndr_print_function_t) ndr_print_netr_LogonControl2Ex,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -17998,7 +17998,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NetrEnumerateTrustedDomains),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NetrEnumerateTrustedDomains,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NetrEnumerateTrustedDomains,
+-		(ndr_print_function_t) ndr_print_netr_NetrEnumerateTrustedDomains,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18007,7 +18007,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRGetDCName),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRGetDCName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetDCName,
+-		(ndr_print_function_t) ndr_print_netr_DsRGetDCName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18016,7 +18016,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonGetCapabilities),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonGetCapabilities,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonGetCapabilities,
+-		(ndr_print_function_t) ndr_print_netr_LogonGetCapabilities,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18025,7 +18025,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NETRLOGONSETSERVICEBITS),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONSETSERVICEBITS,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONSETSERVICEBITS,
+-		(ndr_print_function_t) ndr_print_netr_NETRLOGONSETSERVICEBITS,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18034,7 +18034,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonGetTrustRid),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonGetTrustRid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonGetTrustRid,
+-		(ndr_print_function_t) ndr_print_netr_LogonGetTrustRid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18043,7 +18043,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NETRLOGONCOMPUTESERVERDIGEST),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONCOMPUTESERVERDIGEST,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONCOMPUTESERVERDIGEST,
+-		(ndr_print_function_t) ndr_print_netr_NETRLOGONCOMPUTESERVERDIGEST,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18052,7 +18052,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NETRLOGONCOMPUTECLIENTDIGEST),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONCOMPUTECLIENTDIGEST,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONCOMPUTECLIENTDIGEST,
+-		(ndr_print_function_t) ndr_print_netr_NETRLOGONCOMPUTECLIENTDIGEST,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18061,7 +18061,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerAuthenticate3),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerAuthenticate3,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerAuthenticate3,
+-		(ndr_print_function_t) ndr_print_netr_ServerAuthenticate3,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18070,7 +18070,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRGetDCNameEx),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRGetDCNameEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetDCNameEx,
+-		(ndr_print_function_t) ndr_print_netr_DsRGetDCNameEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18079,7 +18079,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRGetSiteName),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRGetSiteName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetSiteName,
+-		(ndr_print_function_t) ndr_print_netr_DsRGetSiteName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18088,7 +18088,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonGetDomainInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonGetDomainInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonGetDomainInfo,
+-		(ndr_print_function_t) ndr_print_netr_LogonGetDomainInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18097,7 +18097,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerPasswordSet2),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerPasswordSet2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerPasswordSet2,
+-		(ndr_print_function_t) ndr_print_netr_ServerPasswordSet2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18106,7 +18106,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerPasswordGet),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerPasswordGet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerPasswordGet,
+-		(ndr_print_function_t) ndr_print_netr_ServerPasswordGet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18115,7 +18115,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NETRLOGONSENDTOSAM),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONSENDTOSAM,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONSENDTOSAM,
+-		(ndr_print_function_t) ndr_print_netr_NETRLOGONSENDTOSAM,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18124,7 +18124,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRAddressToSitenamesW),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRAddressToSitenamesW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRAddressToSitenamesW,
+-		(ndr_print_function_t) ndr_print_netr_DsRAddressToSitenamesW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18133,7 +18133,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRGetDCNameEx2),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRGetDCNameEx2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetDCNameEx2,
+-		(ndr_print_function_t) ndr_print_netr_DsRGetDCNameEx2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18142,7 +18142,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
+-		(ndr_print_function_t) ndr_print_netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18151,7 +18151,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_NetrEnumerateTrustedDomainsEx),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_NetrEnumerateTrustedDomainsEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_NetrEnumerateTrustedDomainsEx,
+-		(ndr_print_function_t) ndr_print_netr_NetrEnumerateTrustedDomainsEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18160,7 +18160,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRAddressToSitenamesExW),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRAddressToSitenamesExW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRAddressToSitenamesExW,
+-		(ndr_print_function_t) ndr_print_netr_DsRAddressToSitenamesExW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18169,7 +18169,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsrGetDcSiteCoverageW),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsrGetDcSiteCoverageW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsrGetDcSiteCoverageW,
+-		(ndr_print_function_t) ndr_print_netr_DsrGetDcSiteCoverageW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18178,7 +18178,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonSamLogonEx),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogonEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogonEx,
+-		(ndr_print_function_t) ndr_print_netr_LogonSamLogonEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18187,7 +18187,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsrEnumerateDomainTrusts),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsrEnumerateDomainTrusts,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsrEnumerateDomainTrusts,
+-		(ndr_print_function_t) ndr_print_netr_DsrEnumerateDomainTrusts,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18196,7 +18196,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsrDeregisterDNSHostRecords),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsrDeregisterDNSHostRecords,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsrDeregisterDNSHostRecords,
+-		(ndr_print_function_t) ndr_print_netr_DsrDeregisterDNSHostRecords,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18205,7 +18205,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerTrustPasswordsGet),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerTrustPasswordsGet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerTrustPasswordsGet,
+-		(ndr_print_function_t) ndr_print_netr_ServerTrustPasswordsGet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18214,7 +18214,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsRGetForestTrustInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsRGetForestTrustInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsRGetForestTrustInformation,
+-		(ndr_print_function_t) ndr_print_netr_DsRGetForestTrustInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18223,7 +18223,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_GetForestTrustInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_GetForestTrustInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_GetForestTrustInformation,
+-		(ndr_print_function_t) ndr_print_netr_GetForestTrustInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18232,7 +18232,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_LogonSamLogonWithFlags),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_LogonSamLogonWithFlags,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_LogonSamLogonWithFlags,
+-		(ndr_print_function_t) ndr_print_netr_LogonSamLogonWithFlags,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18241,7 +18241,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_ServerGetTrustInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_ServerGetTrustInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_ServerGetTrustInfo,
+-		(ndr_print_function_t) ndr_print_netr_ServerGetTrustInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18250,7 +18250,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_Unused47),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_Unused47,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_Unused47,
+-		(ndr_print_function_t) ndr_print_netr_Unused47,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -18259,7 +18259,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct netr_DsrUpdateReadOnlyServerDnsRecords),
+ 		(ndr_push_flags_fn_t) ndr_push_netr_DsrUpdateReadOnlyServerDnsRecords,
+ 		(ndr_pull_flags_fn_t) ndr_pull_netr_DsrUpdateReadOnlyServerDnsRecords,
+-		(ndr_print_function_t) ndr_print_netr_DsrUpdateReadOnlyServerDnsRecords,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_ntlmssp.c
++++ b/source3/librpc/gen_ndr/ndr_ntlmssp.c
+@@ -2408,7 +2408,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_NEGOTIATE_MESSAGE),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_NEGOTIATE_MESSAGE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_NEGOTIATE_MESSAGE,
+-		(ndr_print_function_t) ndr_print_decode_NEGOTIATE_MESSAGE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2417,7 +2417,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_CHALLENGE_MESSAGE),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_CHALLENGE_MESSAGE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_CHALLENGE_MESSAGE,
+-		(ndr_print_function_t) ndr_print_decode_CHALLENGE_MESSAGE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2426,7 +2426,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_AUTHENTICATE_MESSAGE),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_AUTHENTICATE_MESSAGE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_AUTHENTICATE_MESSAGE,
+-		(ndr_print_function_t) ndr_print_decode_AUTHENTICATE_MESSAGE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2435,7 +2435,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_NTLMv2_CLIENT_CHALLENGE),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_NTLMv2_CLIENT_CHALLENGE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_NTLMv2_CLIENT_CHALLENGE,
+-		(ndr_print_function_t) ndr_print_decode_NTLMv2_CLIENT_CHALLENGE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2444,7 +2444,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_NTLMv2_RESPONSE),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_NTLMv2_RESPONSE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_NTLMv2_RESPONSE,
+-		(ndr_print_function_t) ndr_print_decode_NTLMv2_RESPONSE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_ntprinting.c
++++ b/source3/librpc/gen_ndr/ndr_ntprinting.c
+@@ -914,7 +914,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_ntprinting_form),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_ntprinting_form,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_ntprinting_form,
+-		(ndr_print_function_t) ndr_print_decode_ntprinting_form,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -923,7 +923,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_ntprinting_driver),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_ntprinting_driver,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_ntprinting_driver,
+-		(ndr_print_function_t) ndr_print_decode_ntprinting_driver,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -932,7 +932,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct decode_ntprinting_printer),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_ntprinting_printer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_ntprinting_printer,
+-		(ndr_print_function_t) ndr_print_decode_ntprinting_printer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_ntsvcs.c
++++ b/source3/librpc/gen_ndr/ndr_ntsvcs.c
+@@ -3466,7 +3466,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_Disconnect),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_Disconnect,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_Disconnect,
+-		(ndr_print_function_t) ndr_print_PNP_Disconnect,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3475,7 +3475,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_Connect),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_Connect,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_Connect,
+-		(ndr_print_function_t) ndr_print_PNP_Connect,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3484,7 +3484,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetVersion),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetVersion,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetVersion,
+-		(ndr_print_function_t) ndr_print_PNP_GetVersion,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3493,7 +3493,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetGlobalState),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetGlobalState,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetGlobalState,
+-		(ndr_print_function_t) ndr_print_PNP_GetGlobalState,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3502,7 +3502,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_InitDetection),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_InitDetection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_InitDetection,
+-		(ndr_print_function_t) ndr_print_PNP_InitDetection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3511,7 +3511,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_ReportLogOn),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_ReportLogOn,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_ReportLogOn,
+-		(ndr_print_function_t) ndr_print_PNP_ReportLogOn,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3520,7 +3520,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_ValidateDeviceInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_ValidateDeviceInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_ValidateDeviceInstance,
+-		(ndr_print_function_t) ndr_print_PNP_ValidateDeviceInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3529,7 +3529,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetRootDeviceInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetRootDeviceInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetRootDeviceInstance,
+-		(ndr_print_function_t) ndr_print_PNP_GetRootDeviceInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3538,7 +3538,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetRelatedDeviceInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetRelatedDeviceInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetRelatedDeviceInstance,
+-		(ndr_print_function_t) ndr_print_PNP_GetRelatedDeviceInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3547,7 +3547,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_EnumerateSubKeys),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_EnumerateSubKeys,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_EnumerateSubKeys,
+-		(ndr_print_function_t) ndr_print_PNP_EnumerateSubKeys,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3556,7 +3556,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetDeviceList),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceList,
+-		(ndr_print_function_t) ndr_print_PNP_GetDeviceList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3565,7 +3565,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetDeviceListSize),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceListSize,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceListSize,
+-		(ndr_print_function_t) ndr_print_PNP_GetDeviceListSize,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3574,7 +3574,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetDepth),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetDepth,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetDepth,
+-		(ndr_print_function_t) ndr_print_PNP_GetDepth,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3583,7 +3583,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetDeviceRegProp),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceRegProp,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceRegProp,
+-		(ndr_print_function_t) ndr_print_PNP_GetDeviceRegProp,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3592,7 +3592,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_SetDeviceRegProp),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_SetDeviceRegProp,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_SetDeviceRegProp,
+-		(ndr_print_function_t) ndr_print_PNP_SetDeviceRegProp,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3601,7 +3601,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetClassInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetClassInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassInstance,
+-		(ndr_print_function_t) ndr_print_PNP_GetClassInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3610,7 +3610,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_CreateKey),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_CreateKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_CreateKey,
+-		(ndr_print_function_t) ndr_print_PNP_CreateKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3619,7 +3619,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_DeleteRegistryKey),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_DeleteRegistryKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_DeleteRegistryKey,
+-		(ndr_print_function_t) ndr_print_PNP_DeleteRegistryKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3628,7 +3628,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetClassCount),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetClassCount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassCount,
+-		(ndr_print_function_t) ndr_print_PNP_GetClassCount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3637,7 +3637,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetClassName),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetClassName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassName,
+-		(ndr_print_function_t) ndr_print_PNP_GetClassName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3646,7 +3646,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_DeleteClassKey),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_DeleteClassKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_DeleteClassKey,
+-		(ndr_print_function_t) ndr_print_PNP_DeleteClassKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3655,7 +3655,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetInterfaceDeviceAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetInterfaceDeviceAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetInterfaceDeviceAlias,
+-		(ndr_print_function_t) ndr_print_PNP_GetInterfaceDeviceAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3664,7 +3664,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetInterfaceDeviceList),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetInterfaceDeviceList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetInterfaceDeviceList,
+-		(ndr_print_function_t) ndr_print_PNP_GetInterfaceDeviceList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3673,7 +3673,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetInterfaceDeviceListSize),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetInterfaceDeviceListSize,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetInterfaceDeviceListSize,
+-		(ndr_print_function_t) ndr_print_PNP_GetInterfaceDeviceListSize,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3682,7 +3682,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_RegisterDeviceClassAssociation),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_RegisterDeviceClassAssociation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_RegisterDeviceClassAssociation,
+-		(ndr_print_function_t) ndr_print_PNP_RegisterDeviceClassAssociation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3691,7 +3691,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_UnregisterDeviceClassAssociation),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_UnregisterDeviceClassAssociation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_UnregisterDeviceClassAssociation,
+-		(ndr_print_function_t) ndr_print_PNP_UnregisterDeviceClassAssociation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3700,7 +3700,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetClassRegProp),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetClassRegProp,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetClassRegProp,
+-		(ndr_print_function_t) ndr_print_PNP_GetClassRegProp,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3709,7 +3709,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_SetClassRegProp),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_SetClassRegProp,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_SetClassRegProp,
+-		(ndr_print_function_t) ndr_print_PNP_SetClassRegProp,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3718,7 +3718,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_CreateDevInst),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_CreateDevInst,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_CreateDevInst,
+-		(ndr_print_function_t) ndr_print_PNP_CreateDevInst,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3727,7 +3727,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_DeviceInstanceAction),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_DeviceInstanceAction,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_DeviceInstanceAction,
+-		(ndr_print_function_t) ndr_print_PNP_DeviceInstanceAction,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3736,7 +3736,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetDeviceStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetDeviceStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetDeviceStatus,
+-		(ndr_print_function_t) ndr_print_PNP_GetDeviceStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3745,7 +3745,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_SetDeviceProblem),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_SetDeviceProblem,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_SetDeviceProblem,
+-		(ndr_print_function_t) ndr_print_PNP_SetDeviceProblem,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3754,7 +3754,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_DisableDevInst),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_DisableDevInst,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_DisableDevInst,
+-		(ndr_print_function_t) ndr_print_PNP_DisableDevInst,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3763,7 +3763,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_UninstallDevInst),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_UninstallDevInst,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_UninstallDevInst,
+-		(ndr_print_function_t) ndr_print_PNP_UninstallDevInst,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3772,7 +3772,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_AddID),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_AddID,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_AddID,
+-		(ndr_print_function_t) ndr_print_PNP_AddID,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3781,7 +3781,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_RegisterDriver),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_RegisterDriver,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_RegisterDriver,
+-		(ndr_print_function_t) ndr_print_PNP_RegisterDriver,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3790,7 +3790,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_QueryRemove),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_QueryRemove,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_QueryRemove,
+-		(ndr_print_function_t) ndr_print_PNP_QueryRemove,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3799,7 +3799,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_RequestDeviceEject),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_RequestDeviceEject,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_RequestDeviceEject,
+-		(ndr_print_function_t) ndr_print_PNP_RequestDeviceEject,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3808,7 +3808,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_IsDockStationPresent),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_IsDockStationPresent,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_IsDockStationPresent,
+-		(ndr_print_function_t) ndr_print_PNP_IsDockStationPresent,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3817,7 +3817,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_RequestEjectPC),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_RequestEjectPC,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_RequestEjectPC,
+-		(ndr_print_function_t) ndr_print_PNP_RequestEjectPC,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3826,7 +3826,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_HwProfFlags),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_HwProfFlags,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_HwProfFlags,
+-		(ndr_print_function_t) ndr_print_PNP_HwProfFlags,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3835,7 +3835,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetHwProfInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetHwProfInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetHwProfInfo,
+-		(ndr_print_function_t) ndr_print_PNP_GetHwProfInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3844,7 +3844,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_AddEmptyLogConf),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_AddEmptyLogConf,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_AddEmptyLogConf,
+-		(ndr_print_function_t) ndr_print_PNP_AddEmptyLogConf,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3853,7 +3853,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_FreeLogConf),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_FreeLogConf,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_FreeLogConf,
+-		(ndr_print_function_t) ndr_print_PNP_FreeLogConf,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3862,7 +3862,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetFirstLogConf),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetFirstLogConf,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetFirstLogConf,
+-		(ndr_print_function_t) ndr_print_PNP_GetFirstLogConf,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3871,7 +3871,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetNextLogConf),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetNextLogConf,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetNextLogConf,
+-		(ndr_print_function_t) ndr_print_PNP_GetNextLogConf,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3880,7 +3880,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetLogConfPriority),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetLogConfPriority,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetLogConfPriority,
+-		(ndr_print_function_t) ndr_print_PNP_GetLogConfPriority,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3889,7 +3889,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_AddResDes),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_AddResDes,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_AddResDes,
+-		(ndr_print_function_t) ndr_print_PNP_AddResDes,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3898,7 +3898,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_FreeResDes),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_FreeResDes,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_FreeResDes,
+-		(ndr_print_function_t) ndr_print_PNP_FreeResDes,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3907,7 +3907,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetNextResDes),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetNextResDes,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetNextResDes,
+-		(ndr_print_function_t) ndr_print_PNP_GetNextResDes,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3916,7 +3916,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetResDesData),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetResDesData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetResDesData,
+-		(ndr_print_function_t) ndr_print_PNP_GetResDesData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3925,7 +3925,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetResDesDataSize),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetResDesDataSize,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetResDesDataSize,
+-		(ndr_print_function_t) ndr_print_PNP_GetResDesDataSize,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3934,7 +3934,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_ModifyResDes),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_ModifyResDes,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_ModifyResDes,
+-		(ndr_print_function_t) ndr_print_PNP_ModifyResDes,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3943,7 +3943,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_DetectResourceLimit),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_DetectResourceLimit,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_DetectResourceLimit,
+-		(ndr_print_function_t) ndr_print_PNP_DetectResourceLimit,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3952,7 +3952,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_QueryResConfList),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_QueryResConfList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_QueryResConfList,
+-		(ndr_print_function_t) ndr_print_PNP_QueryResConfList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3961,7 +3961,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_SetHwProf),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_SetHwProf,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_SetHwProf,
+-		(ndr_print_function_t) ndr_print_PNP_SetHwProf,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3970,7 +3970,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_QueryArbitratorFreeData),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_QueryArbitratorFreeData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_QueryArbitratorFreeData,
+-		(ndr_print_function_t) ndr_print_PNP_QueryArbitratorFreeData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3979,7 +3979,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_QueryArbitratorFreeSize),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_QueryArbitratorFreeSize,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_QueryArbitratorFreeSize,
+-		(ndr_print_function_t) ndr_print_PNP_QueryArbitratorFreeSize,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3988,7 +3988,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_RunDetection),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_RunDetection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_RunDetection,
+-		(ndr_print_function_t) ndr_print_PNP_RunDetection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3997,7 +3997,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_RegisterNotification),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_RegisterNotification,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_RegisterNotification,
+-		(ndr_print_function_t) ndr_print_PNP_RegisterNotification,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4006,7 +4006,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_UnregisterNotification),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_UnregisterNotification,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_UnregisterNotification,
+-		(ndr_print_function_t) ndr_print_PNP_UnregisterNotification,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4015,7 +4015,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetCustomDevProp),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetCustomDevProp,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetCustomDevProp,
+-		(ndr_print_function_t) ndr_print_PNP_GetCustomDevProp,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4024,7 +4024,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetVersionInternal),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetVersionInternal,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetVersionInternal,
+-		(ndr_print_function_t) ndr_print_PNP_GetVersionInternal,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4033,7 +4033,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetBlockedDriverInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetBlockedDriverInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetBlockedDriverInfo,
+-		(ndr_print_function_t) ndr_print_PNP_GetBlockedDriverInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4042,7 +4042,7 @@ static const struct ndr_interface_call n
+ 		sizeof(struct PNP_GetServerSideDeviceInstallFlags),
+ 		(ndr_push_flags_fn_t) ndr_push_PNP_GetServerSideDeviceInstallFlags,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PNP_GetServerSideDeviceInstallFlags,
+-		(ndr_print_function_t) ndr_print_PNP_GetServerSideDeviceInstallFlags,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_oxidresolver.c
++++ b/source3/librpc/gen_ndr/ndr_oxidresolver.c
+@@ -761,7 +761,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ResolveOxid),
+ 		(ndr_push_flags_fn_t) ndr_push_ResolveOxid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ResolveOxid,
+-		(ndr_print_function_t) ndr_print_ResolveOxid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -770,7 +770,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct SimplePing),
+ 		(ndr_push_flags_fn_t) ndr_push_SimplePing,
+ 		(ndr_pull_flags_fn_t) ndr_pull_SimplePing,
+-		(ndr_print_function_t) ndr_print_SimplePing,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -779,7 +779,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ComplexPing),
+ 		(ndr_push_flags_fn_t) ndr_push_ComplexPing,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ComplexPing,
+-		(ndr_print_function_t) ndr_print_ComplexPing,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -788,7 +788,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ServerAlive),
+ 		(ndr_push_flags_fn_t) ndr_push_ServerAlive,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ServerAlive,
+-		(ndr_print_function_t) ndr_print_ServerAlive,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -797,7 +797,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ResolveOxid2),
+ 		(ndr_push_flags_fn_t) ndr_push_ResolveOxid2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ResolveOxid2,
+-		(ndr_print_function_t) ndr_print_ResolveOxid2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -806,7 +806,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ServerAlive2),
+ 		(ndr_push_flags_fn_t) ndr_push_ServerAlive2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ServerAlive2,
+-		(ndr_print_function_t) ndr_print_ServerAlive2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_policyagent.c
++++ b/source3/librpc/gen_ndr/ndr_policyagent.c
+@@ -51,7 +51,7 @@ static const struct ndr_interface_call p
+ 		sizeof(struct policyagent_Dummy),
+ 		(ndr_push_flags_fn_t) ndr_push_policyagent_Dummy,
+ 		(ndr_pull_flags_fn_t) ndr_pull_policyagent_Dummy,
+-		(ndr_print_function_t) ndr_print_policyagent_Dummy,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_preg.c
++++ b/source3/librpc/gen_ndr/ndr_preg.c
+@@ -204,7 +204,7 @@ static const struct ndr_interface_call p
+ 		sizeof(struct decode_preg_file),
+ 		(ndr_push_flags_fn_t) ndr_push_decode_preg_file,
+ 		(ndr_pull_flags_fn_t) ndr_pull_decode_preg_file,
+-		(ndr_print_function_t) ndr_print_decode_preg_file,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_remact.c
++++ b/source3/librpc/gen_ndr/ndr_remact.c
+@@ -373,7 +373,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RemoteActivation),
+ 		(ndr_push_flags_fn_t) ndr_push_RemoteActivation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RemoteActivation,
+-		(ndr_print_function_t) ndr_print_RemoteActivation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_rot.c
++++ b/source3/librpc/gen_ndr/ndr_rot.c
+@@ -489,7 +489,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_add),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_add,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_add,
+-		(ndr_print_function_t) ndr_print_rot_add,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -498,7 +498,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_remove),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_remove,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_remove,
+-		(ndr_print_function_t) ndr_print_rot_remove,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -507,7 +507,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_is_listed),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_is_listed,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_is_listed,
+-		(ndr_print_function_t) ndr_print_rot_is_listed,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -516,7 +516,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_get_interface_pointer),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_get_interface_pointer,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_get_interface_pointer,
+-		(ndr_print_function_t) ndr_print_rot_get_interface_pointer,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -525,7 +525,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_set_modification_time),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_set_modification_time,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_set_modification_time,
+-		(ndr_print_function_t) ndr_print_rot_set_modification_time,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -534,7 +534,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_get_modification_time),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_get_modification_time,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_get_modification_time,
+-		(ndr_print_function_t) ndr_print_rot_get_modification_time,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -543,7 +543,7 @@ static const struct ndr_interface_call r
+ 		sizeof(struct rot_enum),
+ 		(ndr_push_flags_fn_t) ndr_push_rot_enum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_rot_enum,
+-		(ndr_print_function_t) ndr_print_rot_enum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_samr.c
++++ b/source3/librpc/gen_ndr/ndr_samr.c
+@@ -12674,7 +12674,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Connect),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Connect,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Connect,
+-		(ndr_print_function_t) ndr_print_samr_Connect,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12683,7 +12683,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Close),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Close,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Close,
+-		(ndr_print_function_t) ndr_print_samr_Close,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12692,7 +12692,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetSecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetSecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetSecurity,
+-		(ndr_print_function_t) ndr_print_samr_SetSecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12701,7 +12701,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QuerySecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QuerySecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QuerySecurity,
+-		(ndr_print_function_t) ndr_print_samr_QuerySecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12710,7 +12710,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Shutdown),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Shutdown,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Shutdown,
+-		(ndr_print_function_t) ndr_print_samr_Shutdown,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12719,7 +12719,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_LookupDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_LookupDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_LookupDomain,
+-		(ndr_print_function_t) ndr_print_samr_LookupDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12728,7 +12728,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_EnumDomains),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_EnumDomains,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomains,
+-		(ndr_print_function_t) ndr_print_samr_EnumDomains,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12737,7 +12737,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_OpenDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_OpenDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_OpenDomain,
+-		(ndr_print_function_t) ndr_print_samr_OpenDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12746,7 +12746,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryDomainInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryDomainInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryDomainInfo,
+-		(ndr_print_function_t) ndr_print_samr_QueryDomainInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12755,7 +12755,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetDomainInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetDomainInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetDomainInfo,
+-		(ndr_print_function_t) ndr_print_samr_SetDomainInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12764,7 +12764,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_CreateDomainGroup),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_CreateDomainGroup,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_CreateDomainGroup,
+-		(ndr_print_function_t) ndr_print_samr_CreateDomainGroup,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12773,7 +12773,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_EnumDomainGroups),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_EnumDomainGroups,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomainGroups,
+-		(ndr_print_function_t) ndr_print_samr_EnumDomainGroups,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12782,7 +12782,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_CreateUser),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_CreateUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_CreateUser,
+-		(ndr_print_function_t) ndr_print_samr_CreateUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12791,7 +12791,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_EnumDomainUsers),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_EnumDomainUsers,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomainUsers,
+-		(ndr_print_function_t) ndr_print_samr_EnumDomainUsers,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12800,7 +12800,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_CreateDomAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_CreateDomAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_CreateDomAlias,
+-		(ndr_print_function_t) ndr_print_samr_CreateDomAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12809,7 +12809,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_EnumDomainAliases),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_EnumDomainAliases,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_EnumDomainAliases,
+-		(ndr_print_function_t) ndr_print_samr_EnumDomainAliases,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12818,7 +12818,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetAliasMembership),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetAliasMembership,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetAliasMembership,
+-		(ndr_print_function_t) ndr_print_samr_GetAliasMembership,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12827,7 +12827,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_LookupNames),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_LookupNames,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_LookupNames,
+-		(ndr_print_function_t) ndr_print_samr_LookupNames,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12836,7 +12836,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_LookupRids),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_LookupRids,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_LookupRids,
+-		(ndr_print_function_t) ndr_print_samr_LookupRids,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12845,7 +12845,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_OpenGroup),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_OpenGroup,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_OpenGroup,
+-		(ndr_print_function_t) ndr_print_samr_OpenGroup,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12854,7 +12854,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryGroupInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryGroupInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryGroupInfo,
+-		(ndr_print_function_t) ndr_print_samr_QueryGroupInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12863,7 +12863,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetGroupInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetGroupInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetGroupInfo,
+-		(ndr_print_function_t) ndr_print_samr_SetGroupInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12872,7 +12872,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_AddGroupMember),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_AddGroupMember,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_AddGroupMember,
+-		(ndr_print_function_t) ndr_print_samr_AddGroupMember,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12881,7 +12881,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_DeleteDomainGroup),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_DeleteDomainGroup,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_DeleteDomainGroup,
+-		(ndr_print_function_t) ndr_print_samr_DeleteDomainGroup,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12890,7 +12890,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_DeleteGroupMember),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_DeleteGroupMember,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_DeleteGroupMember,
+-		(ndr_print_function_t) ndr_print_samr_DeleteGroupMember,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12899,7 +12899,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryGroupMember),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryGroupMember,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryGroupMember,
+-		(ndr_print_function_t) ndr_print_samr_QueryGroupMember,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12908,7 +12908,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetMemberAttributesOfGroup),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetMemberAttributesOfGroup,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetMemberAttributesOfGroup,
+-		(ndr_print_function_t) ndr_print_samr_SetMemberAttributesOfGroup,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12917,7 +12917,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_OpenAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_OpenAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_OpenAlias,
+-		(ndr_print_function_t) ndr_print_samr_OpenAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12926,7 +12926,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryAliasInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryAliasInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryAliasInfo,
+-		(ndr_print_function_t) ndr_print_samr_QueryAliasInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12935,7 +12935,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetAliasInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetAliasInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetAliasInfo,
+-		(ndr_print_function_t) ndr_print_samr_SetAliasInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12944,7 +12944,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_DeleteDomAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_DeleteDomAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_DeleteDomAlias,
+-		(ndr_print_function_t) ndr_print_samr_DeleteDomAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12953,7 +12953,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_AddAliasMember),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_AddAliasMember,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_AddAliasMember,
+-		(ndr_print_function_t) ndr_print_samr_AddAliasMember,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12962,7 +12962,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_DeleteAliasMember),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_DeleteAliasMember,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_DeleteAliasMember,
+-		(ndr_print_function_t) ndr_print_samr_DeleteAliasMember,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12971,7 +12971,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetMembersInAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetMembersInAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetMembersInAlias,
+-		(ndr_print_function_t) ndr_print_samr_GetMembersInAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12980,7 +12980,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_OpenUser),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_OpenUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_OpenUser,
+-		(ndr_print_function_t) ndr_print_samr_OpenUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12989,7 +12989,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_DeleteUser),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_DeleteUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_DeleteUser,
+-		(ndr_print_function_t) ndr_print_samr_DeleteUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -12998,7 +12998,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryUserInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryUserInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryUserInfo,
+-		(ndr_print_function_t) ndr_print_samr_QueryUserInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13007,7 +13007,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetUserInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetUserInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetUserInfo,
+-		(ndr_print_function_t) ndr_print_samr_SetUserInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13016,7 +13016,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_ChangePasswordUser),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_ChangePasswordUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_ChangePasswordUser,
+-		(ndr_print_function_t) ndr_print_samr_ChangePasswordUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13025,7 +13025,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetGroupsForUser),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetGroupsForUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetGroupsForUser,
+-		(ndr_print_function_t) ndr_print_samr_GetGroupsForUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13034,7 +13034,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryDisplayInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryDisplayInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryDisplayInfo,
+-		(ndr_print_function_t) ndr_print_samr_QueryDisplayInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13043,7 +13043,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetDisplayEnumerationIndex),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetDisplayEnumerationIndex,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetDisplayEnumerationIndex,
+-		(ndr_print_function_t) ndr_print_samr_GetDisplayEnumerationIndex,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13052,7 +13052,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_TestPrivateFunctionsDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_TestPrivateFunctionsDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_TestPrivateFunctionsDomain,
+-		(ndr_print_function_t) ndr_print_samr_TestPrivateFunctionsDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13061,7 +13061,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_TestPrivateFunctionsUser),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_TestPrivateFunctionsUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_TestPrivateFunctionsUser,
+-		(ndr_print_function_t) ndr_print_samr_TestPrivateFunctionsUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13070,7 +13070,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetUserPwInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetUserPwInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetUserPwInfo,
+-		(ndr_print_function_t) ndr_print_samr_GetUserPwInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13079,7 +13079,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_RemoveMemberFromForeignDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_RemoveMemberFromForeignDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_RemoveMemberFromForeignDomain,
+-		(ndr_print_function_t) ndr_print_samr_RemoveMemberFromForeignDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13088,7 +13088,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryDomainInfo2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryDomainInfo2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryDomainInfo2,
+-		(ndr_print_function_t) ndr_print_samr_QueryDomainInfo2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13097,7 +13097,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryUserInfo2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryUserInfo2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryUserInfo2,
+-		(ndr_print_function_t) ndr_print_samr_QueryUserInfo2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13106,7 +13106,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryDisplayInfo2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryDisplayInfo2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryDisplayInfo2,
+-		(ndr_print_function_t) ndr_print_samr_QueryDisplayInfo2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13115,7 +13115,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetDisplayEnumerationIndex2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetDisplayEnumerationIndex2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetDisplayEnumerationIndex2,
+-		(ndr_print_function_t) ndr_print_samr_GetDisplayEnumerationIndex2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13124,7 +13124,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_CreateUser2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_CreateUser2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_CreateUser2,
+-		(ndr_print_function_t) ndr_print_samr_CreateUser2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13133,7 +13133,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_QueryDisplayInfo3),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_QueryDisplayInfo3,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_QueryDisplayInfo3,
+-		(ndr_print_function_t) ndr_print_samr_QueryDisplayInfo3,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13142,7 +13142,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_AddMultipleMembersToAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_AddMultipleMembersToAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_AddMultipleMembersToAlias,
+-		(ndr_print_function_t) ndr_print_samr_AddMultipleMembersToAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13151,7 +13151,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_RemoveMultipleMembersFromAlias),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_RemoveMultipleMembersFromAlias,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_RemoveMultipleMembersFromAlias,
+-		(ndr_print_function_t) ndr_print_samr_RemoveMultipleMembersFromAlias,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13160,7 +13160,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_OemChangePasswordUser2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_OemChangePasswordUser2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_OemChangePasswordUser2,
+-		(ndr_print_function_t) ndr_print_samr_OemChangePasswordUser2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13169,7 +13169,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_ChangePasswordUser2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_ChangePasswordUser2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_ChangePasswordUser2,
+-		(ndr_print_function_t) ndr_print_samr_ChangePasswordUser2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13178,7 +13178,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetDomPwInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetDomPwInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetDomPwInfo,
+-		(ndr_print_function_t) ndr_print_samr_GetDomPwInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13187,7 +13187,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Connect2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Connect2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Connect2,
+-		(ndr_print_function_t) ndr_print_samr_Connect2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13196,7 +13196,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetUserInfo2),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetUserInfo2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetUserInfo2,
+-		(ndr_print_function_t) ndr_print_samr_SetUserInfo2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13205,7 +13205,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetBootKeyInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetBootKeyInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetBootKeyInformation,
+-		(ndr_print_function_t) ndr_print_samr_SetBootKeyInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13214,7 +13214,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_GetBootKeyInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_GetBootKeyInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_GetBootKeyInformation,
+-		(ndr_print_function_t) ndr_print_samr_GetBootKeyInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13223,7 +13223,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Connect3),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Connect3,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Connect3,
+-		(ndr_print_function_t) ndr_print_samr_Connect3,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13232,7 +13232,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Connect4),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Connect4,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Connect4,
+-		(ndr_print_function_t) ndr_print_samr_Connect4,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13241,7 +13241,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_ChangePasswordUser3),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_ChangePasswordUser3,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_ChangePasswordUser3,
+-		(ndr_print_function_t) ndr_print_samr_ChangePasswordUser3,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13250,7 +13250,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_Connect5),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_Connect5,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_Connect5,
+-		(ndr_print_function_t) ndr_print_samr_Connect5,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13259,7 +13259,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_RidToSid),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_RidToSid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_RidToSid,
+-		(ndr_print_function_t) ndr_print_samr_RidToSid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13268,7 +13268,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_SetDsrmPassword),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_SetDsrmPassword,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_SetDsrmPassword,
+-		(ndr_print_function_t) ndr_print_samr_SetDsrmPassword,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -13277,7 +13277,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct samr_ValidatePassword),
+ 		(ndr_push_flags_fn_t) ndr_push_samr_ValidatePassword,
+ 		(ndr_pull_flags_fn_t) ndr_pull_samr_ValidatePassword,
+-		(ndr_print_function_t) ndr_print_samr_ValidatePassword,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_scerpc.c
++++ b/source3/librpc/gen_ndr/ndr_scerpc.c
+@@ -51,7 +51,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct scerpc_Unknown0),
+ 		(ndr_push_flags_fn_t) ndr_push_scerpc_Unknown0,
+ 		(ndr_pull_flags_fn_t) ndr_pull_scerpc_Unknown0,
+-		(ndr_print_function_t) ndr_print_scerpc_Unknown0,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_spoolss.c
++++ b/source3/librpc/gen_ndr/ndr_spoolss.c
+@@ -32661,7 +32661,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrinters),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrinters,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrinters,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrinters,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32670,7 +32670,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_OpenPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_OpenPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_OpenPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_OpenPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32679,7 +32679,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SetJob),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SetJob,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SetJob,
+-		(ndr_print_function_t) ndr_print_spoolss_SetJob,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32688,7 +32688,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetJob),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetJob,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetJob,
+-		(ndr_print_function_t) ndr_print_spoolss_GetJob,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32697,7 +32697,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumJobs),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumJobs,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumJobs,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumJobs,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32706,7 +32706,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32715,7 +32715,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32724,7 +32724,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SetPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SetPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SetPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_SetPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32733,7 +32733,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32742,7 +32742,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrinterDriver),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrinterDriver,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrinterDriver,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrinterDriver,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32751,7 +32751,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrinterDrivers),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrinterDrivers,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrinterDrivers,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrinterDrivers,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32760,7 +32760,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinterDriver),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinterDriver,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinterDriver,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinterDriver,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32769,7 +32769,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinterDriverDirectory),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinterDriverDirectory,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinterDriverDirectory,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinterDriverDirectory,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32778,7 +32778,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterDriver),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterDriver,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterDriver,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterDriver,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32787,7 +32787,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrintProcessor),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrintProcessor,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrintProcessor,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrintProcessor,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32796,7 +32796,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrintProcessors),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrintProcessors,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrintProcessors,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrintProcessors,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32805,7 +32805,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrintProcessorDirectory),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrintProcessorDirectory,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrintProcessorDirectory,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrintProcessorDirectory,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32814,7 +32814,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_StartDocPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_StartDocPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_StartDocPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_StartDocPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32823,7 +32823,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_StartPagePrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_StartPagePrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_StartPagePrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_StartPagePrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32832,7 +32832,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_WritePrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_WritePrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_WritePrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_WritePrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32841,7 +32841,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EndPagePrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EndPagePrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EndPagePrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_EndPagePrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32850,7 +32850,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AbortPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AbortPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AbortPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_AbortPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32859,7 +32859,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ReadPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ReadPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ReadPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_ReadPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32868,7 +32868,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EndDocPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EndDocPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EndDocPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_EndDocPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32877,7 +32877,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddJob),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddJob,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddJob,
+-		(ndr_print_function_t) ndr_print_spoolss_AddJob,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32886,7 +32886,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ScheduleJob),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ScheduleJob,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ScheduleJob,
+-		(ndr_print_function_t) ndr_print_spoolss_ScheduleJob,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32895,7 +32895,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinterData),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinterData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinterData,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinterData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32904,7 +32904,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SetPrinterData),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SetPrinterData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SetPrinterData,
+-		(ndr_print_function_t) ndr_print_spoolss_SetPrinterData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32913,7 +32913,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_WaitForPrinterChange),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_WaitForPrinterChange,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_WaitForPrinterChange,
+-		(ndr_print_function_t) ndr_print_spoolss_WaitForPrinterChange,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32922,7 +32922,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ClosePrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ClosePrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ClosePrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_ClosePrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32931,7 +32931,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddForm),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddForm,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddForm,
+-		(ndr_print_function_t) ndr_print_spoolss_AddForm,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32940,7 +32940,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeleteForm),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeleteForm,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeleteForm,
+-		(ndr_print_function_t) ndr_print_spoolss_DeleteForm,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32949,7 +32949,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetForm),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetForm,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetForm,
+-		(ndr_print_function_t) ndr_print_spoolss_GetForm,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32958,7 +32958,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SetForm),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SetForm,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SetForm,
+-		(ndr_print_function_t) ndr_print_spoolss_SetForm,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32967,7 +32967,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumForms),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumForms,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumForms,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumForms,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32976,7 +32976,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPorts),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPorts,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPorts,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPorts,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32985,7 +32985,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumMonitors),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumMonitors,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumMonitors,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumMonitors,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -32994,7 +32994,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPort),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPort,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPort,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPort,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33003,7 +33003,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ConfigurePort),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ConfigurePort,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ConfigurePort,
+-		(ndr_print_function_t) ndr_print_spoolss_ConfigurePort,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33012,7 +33012,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePort),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePort,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePort,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePort,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33021,7 +33021,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_CreatePrinterIC),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_CreatePrinterIC,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_CreatePrinterIC,
+-		(ndr_print_function_t) ndr_print_spoolss_CreatePrinterIC,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33030,7 +33030,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_PlayGDIScriptOnPrinterIC),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_PlayGDIScriptOnPrinterIC,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_PlayGDIScriptOnPrinterIC,
+-		(ndr_print_function_t) ndr_print_spoolss_PlayGDIScriptOnPrinterIC,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33039,7 +33039,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterIC),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterIC,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterIC,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterIC,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33048,7 +33048,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrinterConnection),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrinterConnection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrinterConnection,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrinterConnection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33057,7 +33057,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterConnection),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterConnection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterConnection,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterConnection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33066,7 +33066,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_PrinterMessageBox),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_PrinterMessageBox,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_PrinterMessageBox,
+-		(ndr_print_function_t) ndr_print_spoolss_PrinterMessageBox,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33075,7 +33075,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddMonitor),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddMonitor,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddMonitor,
+-		(ndr_print_function_t) ndr_print_spoolss_AddMonitor,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33084,7 +33084,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeleteMonitor),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeleteMonitor,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeleteMonitor,
+-		(ndr_print_function_t) ndr_print_spoolss_DeleteMonitor,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33093,7 +33093,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrintProcessor),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrintProcessor,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrintProcessor,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrintProcessor,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33102,7 +33102,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrintProvidor),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrintProvidor,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrintProvidor,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrintProvidor,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33111,7 +33111,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrintProvidor),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrintProvidor,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrintProvidor,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrintProvidor,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33120,7 +33120,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrintProcDataTypes),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrintProcDataTypes,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrintProcDataTypes,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrintProcDataTypes,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33129,7 +33129,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ResetPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ResetPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ResetPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_ResetPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33138,7 +33138,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinterDriver2),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinterDriver2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinterDriver2,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinterDriver2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33147,7 +33147,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_FindFirstPrinterChangeNotification),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_FindFirstPrinterChangeNotification,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_FindFirstPrinterChangeNotification,
+-		(ndr_print_function_t) ndr_print_spoolss_FindFirstPrinterChangeNotification,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33156,7 +33156,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_FindNextPrinterChangeNotification),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_FindNextPrinterChangeNotification,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_FindNextPrinterChangeNotification,
+-		(ndr_print_function_t) ndr_print_spoolss_FindNextPrinterChangeNotification,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33165,7 +33165,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_FindClosePrinterNotify),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_FindClosePrinterNotify,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_FindClosePrinterNotify,
+-		(ndr_print_function_t) ndr_print_spoolss_FindClosePrinterNotify,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33174,7 +33174,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_RouterFindFirstPrinterChangeNotificationOld),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_RouterFindFirstPrinterChangeNotificationOld,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_RouterFindFirstPrinterChangeNotificationOld,
+-		(ndr_print_function_t) ndr_print_spoolss_RouterFindFirstPrinterChangeNotificationOld,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33183,7 +33183,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ReplyOpenPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ReplyOpenPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ReplyOpenPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_ReplyOpenPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33192,7 +33192,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_RouterReplyPrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_RouterReplyPrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_RouterReplyPrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_RouterReplyPrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33201,7 +33201,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ReplyClosePrinter),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ReplyClosePrinter,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ReplyClosePrinter,
+-		(ndr_print_function_t) ndr_print_spoolss_ReplyClosePrinter,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33210,7 +33210,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPortEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPortEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPortEx,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPortEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33219,7 +33219,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_RouterFindFirstPrinterChangeNotification),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_RouterFindFirstPrinterChangeNotification,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_RouterFindFirstPrinterChangeNotification,
+-		(ndr_print_function_t) ndr_print_spoolss_RouterFindFirstPrinterChangeNotification,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33228,7 +33228,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SpoolerInit),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SpoolerInit,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SpoolerInit,
+-		(ndr_print_function_t) ndr_print_spoolss_SpoolerInit,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33237,7 +33237,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_ResetPrinterEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_ResetPrinterEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_ResetPrinterEx,
+-		(ndr_print_function_t) ndr_print_spoolss_ResetPrinterEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33246,7 +33246,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_RemoteFindFirstPrinterChangeNotifyEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_RemoteFindFirstPrinterChangeNotifyEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_RemoteFindFirstPrinterChangeNotifyEx,
+-		(ndr_print_function_t) ndr_print_spoolss_RemoteFindFirstPrinterChangeNotifyEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33255,7 +33255,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_RouterReplyPrinterEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_RouterReplyPrinterEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_RouterReplyPrinterEx,
+-		(ndr_print_function_t) ndr_print_spoolss_RouterReplyPrinterEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33264,7 +33264,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_RouterRefreshPrinterChangeNotify),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_RouterRefreshPrinterChangeNotify,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_RouterRefreshPrinterChangeNotify,
+-		(ndr_print_function_t) ndr_print_spoolss_RouterRefreshPrinterChangeNotify,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33273,7 +33273,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_44),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_44,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_44,
+-		(ndr_print_function_t) ndr_print_spoolss_44,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33282,7 +33282,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_OpenPrinterEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_OpenPrinterEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_OpenPrinterEx,
+-		(ndr_print_function_t) ndr_print_spoolss_OpenPrinterEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33291,7 +33291,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrinterEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrinterEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrinterEx,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrinterEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33300,7 +33300,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SetPort),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SetPort,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SetPort,
+-		(ndr_print_function_t) ndr_print_spoolss_SetPort,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33309,7 +33309,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrinterData),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrinterData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrinterData,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrinterData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33318,7 +33318,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterData),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterData,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33327,7 +33327,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_4a),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_4a,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_4a,
+-		(ndr_print_function_t) ndr_print_spoolss_4a,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33336,7 +33336,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_4b),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_4b,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_4b,
+-		(ndr_print_function_t) ndr_print_spoolss_4b,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33345,7 +33345,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_4c),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_4c,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_4c,
+-		(ndr_print_function_t) ndr_print_spoolss_4c,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33354,7 +33354,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_SetPrinterDataEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_SetPrinterDataEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_SetPrinterDataEx,
+-		(ndr_print_function_t) ndr_print_spoolss_SetPrinterDataEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33363,7 +33363,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinterDataEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinterDataEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinterDataEx,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinterDataEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33372,7 +33372,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrinterDataEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrinterDataEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrinterDataEx,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrinterDataEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33381,7 +33381,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPrinterKey),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPrinterKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPrinterKey,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPrinterKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33390,7 +33390,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterDataEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterDataEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterDataEx,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterDataEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33399,7 +33399,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterKey),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterKey,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33408,7 +33408,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_53),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_53,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_53,
+-		(ndr_print_function_t) ndr_print_spoolss_53,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33417,7 +33417,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePrinterDriverEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePrinterDriverEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePrinterDriverEx,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePrinterDriverEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33426,7 +33426,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPerMachineConnection),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPerMachineConnection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPerMachineConnection,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPerMachineConnection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33435,7 +33435,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_DeletePerMachineConnection),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_DeletePerMachineConnection,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_DeletePerMachineConnection,
+-		(ndr_print_function_t) ndr_print_spoolss_DeletePerMachineConnection,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33444,7 +33444,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_EnumPerMachineConnections),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_EnumPerMachineConnections,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_EnumPerMachineConnections,
+-		(ndr_print_function_t) ndr_print_spoolss_EnumPerMachineConnections,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33453,7 +33453,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_XcvData),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_XcvData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_XcvData,
+-		(ndr_print_function_t) ndr_print_spoolss_XcvData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33462,7 +33462,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_AddPrinterDriverEx),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_AddPrinterDriverEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_AddPrinterDriverEx,
+-		(ndr_print_function_t) ndr_print_spoolss_AddPrinterDriverEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33471,7 +33471,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_5a),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_5a,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_5a,
+-		(ndr_print_function_t) ndr_print_spoolss_5a,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33480,7 +33480,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_5b),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_5b,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_5b,
+-		(ndr_print_function_t) ndr_print_spoolss_5b,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33489,7 +33489,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_5c),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_5c,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_5c,
+-		(ndr_print_function_t) ndr_print_spoolss_5c,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33498,7 +33498,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_5d),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_5d,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_5d,
+-		(ndr_print_function_t) ndr_print_spoolss_5d,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33507,7 +33507,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_5e),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_5e,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_5e,
+-		(ndr_print_function_t) ndr_print_spoolss_5e,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33516,7 +33516,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_5f),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_5f,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_5f,
+-		(ndr_print_function_t) ndr_print_spoolss_5f,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33525,7 +33525,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_60),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_60,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_60,
+-		(ndr_print_function_t) ndr_print_spoolss_60,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33534,7 +33534,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_61),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_61,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_61,
+-		(ndr_print_function_t) ndr_print_spoolss_61,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33543,7 +33543,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_62),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_62,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_62,
+-		(ndr_print_function_t) ndr_print_spoolss_62,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33552,7 +33552,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_63),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_63,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_63,
+-		(ndr_print_function_t) ndr_print_spoolss_63,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33561,7 +33561,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_64),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_64,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_64,
+-		(ndr_print_function_t) ndr_print_spoolss_64,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33570,7 +33570,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_65),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_65,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_65,
+-		(ndr_print_function_t) ndr_print_spoolss_65,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33579,7 +33579,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetCorePrinterDrivers),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetCorePrinterDrivers,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetCorePrinterDrivers,
+-		(ndr_print_function_t) ndr_print_spoolss_GetCorePrinterDrivers,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33588,7 +33588,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_67),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_67,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_67,
+-		(ndr_print_function_t) ndr_print_spoolss_67,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33597,7 +33597,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_GetPrinterDriverPackagePath),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_GetPrinterDriverPackagePath,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_GetPrinterDriverPackagePath,
+-		(ndr_print_function_t) ndr_print_spoolss_GetPrinterDriverPackagePath,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33606,7 +33606,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_69),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_69,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_69,
+-		(ndr_print_function_t) ndr_print_spoolss_69,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33615,7 +33615,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_6a),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_6a,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_6a,
+-		(ndr_print_function_t) ndr_print_spoolss_6a,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33624,7 +33624,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_6b),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_6b,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_6b,
+-		(ndr_print_function_t) ndr_print_spoolss_6b,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33633,7 +33633,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_6c),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_6c,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_6c,
+-		(ndr_print_function_t) ndr_print_spoolss_6c,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -33642,7 +33642,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct spoolss_6d),
+ 		(ndr_push_flags_fn_t) ndr_push_spoolss_6d,
+ 		(ndr_pull_flags_fn_t) ndr_pull_spoolss_6d,
+-		(ndr_print_function_t) ndr_print_spoolss_6d,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_srvsvc.c
++++ b/source3/librpc/gen_ndr/ndr_srvsvc.c
+@@ -20229,7 +20229,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20238,7 +20238,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevGetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20247,7 +20247,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevControl),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevControl,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevControl,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevControl,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20256,7 +20256,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevQEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevQEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20265,7 +20265,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevQGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQGetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevQGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20274,7 +20274,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevQSetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQSetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQSetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevQSetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20283,7 +20283,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevQPurge),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQPurge,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQPurge,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevQPurge,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20292,7 +20292,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetCharDevQPurgeSelf),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetCharDevQPurgeSelf,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetCharDevQPurgeSelf,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetCharDevQPurgeSelf,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20301,7 +20301,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetConnEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetConnEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetConnEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetConnEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20310,7 +20310,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetFileEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetFileEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetFileEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetFileEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20319,7 +20319,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetFileGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetFileGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetFileGetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetFileGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20328,7 +20328,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetFileClose),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetFileClose,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetFileClose,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetFileClose,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20337,7 +20337,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetSessEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetSessEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSessEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetSessEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20346,7 +20346,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetSessDel),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetSessDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSessDel,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetSessDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20355,7 +20355,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareAdd,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20364,7 +20364,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareEnumAll),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareEnumAll,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareEnumAll,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareEnumAll,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20373,7 +20373,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareGetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20382,7 +20382,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareSetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareSetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareSetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareSetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20391,7 +20391,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareDel),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDel,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20400,7 +20400,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareDelSticky),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDelSticky,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDelSticky,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareDelSticky,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20409,7 +20409,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareCheck),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareCheck,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareCheck,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareCheck,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20418,7 +20418,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetSrvGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetSrvGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSrvGetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetSrvGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20427,7 +20427,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetSrvSetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetSrvSetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSrvSetInfo,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetSrvSetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20436,7 +20436,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetDiskEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetDiskEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetDiskEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetDiskEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20445,7 +20445,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetServerStatisticsGet),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetServerStatisticsGet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetServerStatisticsGet,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetServerStatisticsGet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20454,7 +20454,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetTransportAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetTransportAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetTransportAdd,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetTransportAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20463,7 +20463,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetTransportEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetTransportEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetTransportEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetTransportEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20472,7 +20472,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetTransportDel),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetTransportDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetTransportDel,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetTransportDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20481,7 +20481,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetRemoteTOD),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetRemoteTOD,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetRemoteTOD,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetRemoteTOD,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20490,7 +20490,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetSetServiceBits),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetSetServiceBits,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSetServiceBits,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetSetServiceBits,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20499,7 +20499,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetPathType),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetPathType,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPathType,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetPathType,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20508,7 +20508,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetPathCanonicalize),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetPathCanonicalize,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPathCanonicalize,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetPathCanonicalize,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20517,7 +20517,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetPathCompare),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetPathCompare,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPathCompare,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetPathCompare,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20526,7 +20526,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetNameValidate),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetNameValidate,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetNameValidate,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetNameValidate,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20535,7 +20535,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRPRNAMECANONICALIZE),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRPRNAMECANONICALIZE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRPRNAMECANONICALIZE,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRPRNAMECANONICALIZE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20544,7 +20544,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetPRNameCompare),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetPRNameCompare,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetPRNameCompare,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetPRNameCompare,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20553,7 +20553,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareEnum,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20562,7 +20562,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareDelStart),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDelStart,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDelStart,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareDelStart,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20571,7 +20571,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetShareDelCommit),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetShareDelCommit,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetShareDelCommit,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetShareDelCommit,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20580,7 +20580,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetGetFileSecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetGetFileSecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetGetFileSecurity,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetGetFileSecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20589,7 +20589,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetSetFileSecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetSetFileSecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetSetFileSecurity,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetSetFileSecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20598,7 +20598,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetServerTransportAddEx),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetServerTransportAddEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetServerTransportAddEx,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetServerTransportAddEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20607,7 +20607,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NetServerSetServiceBitsEx),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NetServerSetServiceBitsEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NetServerSetServiceBitsEx,
+-		(ndr_print_function_t) ndr_print_srvsvc_NetServerSetServiceBitsEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20616,7 +20616,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSGETVERSION),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSGETVERSION,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSGETVERSION,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSGETVERSION,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20625,7 +20625,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSCREATELOCALPARTITION),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSCREATELOCALPARTITION,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSCREATELOCALPARTITION,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSCREATELOCALPARTITION,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20634,7 +20634,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSDELETELOCALPARTITION),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSDELETELOCALPARTITION,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSDELETELOCALPARTITION,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSDELETELOCALPARTITION,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20643,7 +20643,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSSETLOCALVOLUMESTATE),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSSETLOCALVOLUMESTATE,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSSETLOCALVOLUMESTATE,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSSETLOCALVOLUMESTATE,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20652,7 +20652,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSSETSERVERINFO),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSSETSERVERINFO,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSSETSERVERINFO,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSSETSERVERINFO,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20661,7 +20661,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSCREATEEXITPOINT),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSCREATEEXITPOINT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSCREATEEXITPOINT,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSCREATEEXITPOINT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20670,7 +20670,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSDELETEEXITPOINT),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSDELETEEXITPOINT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSDELETEEXITPOINT,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSDELETEEXITPOINT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20679,7 +20679,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSMODIFYPREFIX),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSMODIFYPREFIX,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSMODIFYPREFIX,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSMODIFYPREFIX,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20688,7 +20688,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSFIXLOCALVOLUME),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSFIXLOCALVOLUME,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSFIXLOCALVOLUME,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSFIXLOCALVOLUME,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20697,7 +20697,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRDFSMANAGERREPORTSITEINFO),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRDFSMANAGERREPORTSITEINFO,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRDFSMANAGERREPORTSITEINFO,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRDFSMANAGERREPORTSITEINFO,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -20706,7 +20706,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct srvsvc_NETRSERVERTRANSPORTDELEX),
+ 		(ndr_push_flags_fn_t) ndr_push_srvsvc_NETRSERVERTRANSPORTDELEX,
+ 		(ndr_pull_flags_fn_t) ndr_pull_srvsvc_NETRSERVERTRANSPORTDELEX,
+-		(ndr_print_function_t) ndr_print_srvsvc_NETRSERVERTRANSPORTDELEX,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_svcctl.c
++++ b/source3/librpc/gen_ndr/ndr_svcctl.c
+@@ -7175,7 +7175,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_CloseServiceHandle),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_CloseServiceHandle,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_CloseServiceHandle,
+-		(ndr_print_function_t) ndr_print_svcctl_CloseServiceHandle,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7184,7 +7184,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_ControlService),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_ControlService,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_ControlService,
+-		(ndr_print_function_t) ndr_print_svcctl_ControlService,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7193,7 +7193,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_DeleteService),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_DeleteService,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_DeleteService,
+-		(ndr_print_function_t) ndr_print_svcctl_DeleteService,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7202,7 +7202,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_LockServiceDatabase),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_LockServiceDatabase,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_LockServiceDatabase,
+-		(ndr_print_function_t) ndr_print_svcctl_LockServiceDatabase,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7211,7 +7211,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceObjectSecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceObjectSecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceObjectSecurity,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceObjectSecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7220,7 +7220,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_SetServiceObjectSecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_SetServiceObjectSecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_SetServiceObjectSecurity,
+-		(ndr_print_function_t) ndr_print_svcctl_SetServiceObjectSecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7229,7 +7229,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceStatus,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7238,7 +7238,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_SetServiceStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_SetServiceStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_SetServiceStatus,
+-		(ndr_print_function_t) ndr_print_svcctl_SetServiceStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7247,7 +7247,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_UnlockServiceDatabase),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_UnlockServiceDatabase,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_UnlockServiceDatabase,
+-		(ndr_print_function_t) ndr_print_svcctl_UnlockServiceDatabase,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7256,7 +7256,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_NotifyBootConfigStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_NotifyBootConfigStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_NotifyBootConfigStatus,
+-		(ndr_print_function_t) ndr_print_svcctl_NotifyBootConfigStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7265,7 +7265,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_SCSetServiceBitsW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_SCSetServiceBitsW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_SCSetServiceBitsW,
+-		(ndr_print_function_t) ndr_print_svcctl_SCSetServiceBitsW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7274,7 +7274,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_ChangeServiceConfigW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfigW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfigW,
+-		(ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfigW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7283,7 +7283,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_CreateServiceW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_CreateServiceW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_CreateServiceW,
+-		(ndr_print_function_t) ndr_print_svcctl_CreateServiceW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7292,7 +7292,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_EnumDependentServicesW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_EnumDependentServicesW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumDependentServicesW,
+-		(ndr_print_function_t) ndr_print_svcctl_EnumDependentServicesW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7301,7 +7301,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_EnumServicesStatusW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_EnumServicesStatusW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumServicesStatusW,
+-		(ndr_print_function_t) ndr_print_svcctl_EnumServicesStatusW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7310,7 +7310,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_OpenSCManagerW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_OpenSCManagerW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenSCManagerW,
+-		(ndr_print_function_t) ndr_print_svcctl_OpenSCManagerW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7319,7 +7319,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_OpenServiceW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_OpenServiceW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenServiceW,
+-		(ndr_print_function_t) ndr_print_svcctl_OpenServiceW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7328,7 +7328,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceConfigW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfigW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfigW,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceConfigW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7337,7 +7337,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceLockStatusW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceLockStatusW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceLockStatusW,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceLockStatusW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7346,7 +7346,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_StartServiceW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_StartServiceW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_StartServiceW,
+-		(ndr_print_function_t) ndr_print_svcctl_StartServiceW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7355,7 +7355,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_GetServiceDisplayNameW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceDisplayNameW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceDisplayNameW,
+-		(ndr_print_function_t) ndr_print_svcctl_GetServiceDisplayNameW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7364,7 +7364,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_GetServiceKeyNameW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceKeyNameW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceKeyNameW,
+-		(ndr_print_function_t) ndr_print_svcctl_GetServiceKeyNameW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7373,7 +7373,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_SCSetServiceBitsA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_SCSetServiceBitsA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_SCSetServiceBitsA,
+-		(ndr_print_function_t) ndr_print_svcctl_SCSetServiceBitsA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7382,7 +7382,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_ChangeServiceConfigA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfigA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfigA,
+-		(ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfigA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7391,7 +7391,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_CreateServiceA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_CreateServiceA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_CreateServiceA,
+-		(ndr_print_function_t) ndr_print_svcctl_CreateServiceA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7400,7 +7400,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_EnumDependentServicesA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_EnumDependentServicesA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumDependentServicesA,
+-		(ndr_print_function_t) ndr_print_svcctl_EnumDependentServicesA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7409,7 +7409,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_EnumServicesStatusA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_EnumServicesStatusA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumServicesStatusA,
+-		(ndr_print_function_t) ndr_print_svcctl_EnumServicesStatusA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7418,7 +7418,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_OpenSCManagerA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_OpenSCManagerA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenSCManagerA,
+-		(ndr_print_function_t) ndr_print_svcctl_OpenSCManagerA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7427,7 +7427,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_OpenServiceA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_OpenServiceA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_OpenServiceA,
+-		(ndr_print_function_t) ndr_print_svcctl_OpenServiceA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7436,7 +7436,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceConfigA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfigA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfigA,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceConfigA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7445,7 +7445,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceLockStatusA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceLockStatusA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceLockStatusA,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceLockStatusA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7454,7 +7454,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_StartServiceA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_StartServiceA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_StartServiceA,
+-		(ndr_print_function_t) ndr_print_svcctl_StartServiceA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7463,7 +7463,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_GetServiceDisplayNameA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceDisplayNameA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceDisplayNameA,
+-		(ndr_print_function_t) ndr_print_svcctl_GetServiceDisplayNameA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7472,7 +7472,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_GetServiceKeyNameA),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_GetServiceKeyNameA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_GetServiceKeyNameA,
+-		(ndr_print_function_t) ndr_print_svcctl_GetServiceKeyNameA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7481,7 +7481,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_GetCurrentGroupeStateW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_GetCurrentGroupeStateW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_GetCurrentGroupeStateW,
+-		(ndr_print_function_t) ndr_print_svcctl_GetCurrentGroupeStateW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7490,7 +7490,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_EnumServiceGroupW),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_EnumServiceGroupW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_EnumServiceGroupW,
+-		(ndr_print_function_t) ndr_print_svcctl_EnumServiceGroupW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7499,7 +7499,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_ChangeServiceConfig2A),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfig2A,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfig2A,
+-		(ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfig2A,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7508,7 +7508,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_ChangeServiceConfig2W),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_ChangeServiceConfig2W,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_ChangeServiceConfig2W,
+-		(ndr_print_function_t) ndr_print_svcctl_ChangeServiceConfig2W,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7517,7 +7517,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceConfig2A),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfig2A,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfig2A,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceConfig2A,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7526,7 +7526,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceConfig2W),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceConfig2W,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceConfig2W,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceConfig2W,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7535,7 +7535,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_QueryServiceStatusEx),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_QueryServiceStatusEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_QueryServiceStatusEx,
+-		(ndr_print_function_t) ndr_print_svcctl_QueryServiceStatusEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7544,7 +7544,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct EnumServicesStatusExA),
+ 		(ndr_push_flags_fn_t) ndr_push_EnumServicesStatusExA,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EnumServicesStatusExA,
+-		(ndr_print_function_t) ndr_print_EnumServicesStatusExA,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7553,7 +7553,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct EnumServicesStatusExW),
+ 		(ndr_push_flags_fn_t) ndr_push_EnumServicesStatusExW,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EnumServicesStatusExW,
+-		(ndr_print_function_t) ndr_print_EnumServicesStatusExW,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7562,7 +7562,7 @@ static const struct ndr_interface_call s
+ 		sizeof(struct svcctl_SCSendTSMessage),
+ 		(ndr_push_flags_fn_t) ndr_push_svcctl_SCSendTSMessage,
+ 		(ndr_pull_flags_fn_t) ndr_pull_svcctl_SCSendTSMessage,
+-		(ndr_print_function_t) ndr_print_svcctl_SCSendTSMessage,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_trkwks.c
++++ b/source3/librpc/gen_ndr/ndr_trkwks.c
+@@ -51,7 +51,7 @@ static const struct ndr_interface_call t
+ 		sizeof(struct trkwks_Unknown0),
+ 		(ndr_push_flags_fn_t) ndr_push_trkwks_Unknown0,
+ 		(ndr_pull_flags_fn_t) ndr_pull_trkwks_Unknown0,
+-		(ndr_print_function_t) ndr_print_trkwks_Unknown0,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_unixinfo.c
++++ b/source3/librpc/gen_ndr/ndr_unixinfo.c
+@@ -472,7 +472,7 @@ static const struct ndr_interface_call u
+ 		sizeof(struct unixinfo_SidToUid),
+ 		(ndr_push_flags_fn_t) ndr_push_unixinfo_SidToUid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_unixinfo_SidToUid,
+-		(ndr_print_function_t) ndr_print_unixinfo_SidToUid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -481,7 +481,7 @@ static const struct ndr_interface_call u
+ 		sizeof(struct unixinfo_UidToSid),
+ 		(ndr_push_flags_fn_t) ndr_push_unixinfo_UidToSid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_unixinfo_UidToSid,
+-		(ndr_print_function_t) ndr_print_unixinfo_UidToSid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -490,7 +490,7 @@ static const struct ndr_interface_call u
+ 		sizeof(struct unixinfo_SidToGid),
+ 		(ndr_push_flags_fn_t) ndr_push_unixinfo_SidToGid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_unixinfo_SidToGid,
+-		(ndr_print_function_t) ndr_print_unixinfo_SidToGid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -499,7 +499,7 @@ static const struct ndr_interface_call u
+ 		sizeof(struct unixinfo_GidToSid),
+ 		(ndr_push_flags_fn_t) ndr_push_unixinfo_GidToSid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_unixinfo_GidToSid,
+-		(ndr_print_function_t) ndr_print_unixinfo_GidToSid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -508,7 +508,7 @@ static const struct ndr_interface_call u
+ 		sizeof(struct unixinfo_GetPWUid),
+ 		(ndr_push_flags_fn_t) ndr_push_unixinfo_GetPWUid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_unixinfo_GetPWUid,
+-		(ndr_print_function_t) ndr_print_unixinfo_GetPWUid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_w32time.c
++++ b/source3/librpc/gen_ndr/ndr_w32time.c
+@@ -135,7 +135,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct w32time_SyncTime),
+ 		(ndr_push_flags_fn_t) ndr_push_w32time_SyncTime,
+ 		(ndr_pull_flags_fn_t) ndr_pull_w32time_SyncTime,
+-		(ndr_print_function_t) ndr_print_w32time_SyncTime,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -144,7 +144,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct w32time_GetNetLogonServiceBits),
+ 		(ndr_push_flags_fn_t) ndr_push_w32time_GetNetLogonServiceBits,
+ 		(ndr_pull_flags_fn_t) ndr_pull_w32time_GetNetLogonServiceBits,
+-		(ndr_print_function_t) ndr_print_w32time_GetNetLogonServiceBits,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -153,7 +153,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct w32time_QueryProviderStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_w32time_QueryProviderStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_w32time_QueryProviderStatus,
+-		(ndr_print_function_t) ndr_print_w32time_QueryProviderStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_wbint.c
++++ b/source3/librpc/gen_ndr/ndr_wbint.c
+@@ -2696,7 +2696,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_Ping),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_Ping,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_Ping,
+-		(ndr_print_function_t) ndr_print_wbint_Ping,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2705,7 +2705,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupSid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupSid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupSid,
+-		(ndr_print_function_t) ndr_print_wbint_LookupSid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2714,7 +2714,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupSids),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupSids,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupSids,
+-		(ndr_print_function_t) ndr_print_wbint_LookupSids,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2723,7 +2723,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupName),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupName,
+-		(ndr_print_function_t) ndr_print_wbint_LookupName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2732,7 +2732,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_Sid2Uid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_Sid2Uid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_Sid2Uid,
+-		(ndr_print_function_t) ndr_print_wbint_Sid2Uid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2741,7 +2741,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_Sid2Gid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_Sid2Gid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_Sid2Gid,
+-		(ndr_print_function_t) ndr_print_wbint_Sid2Gid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2750,7 +2750,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_Sids2UnixIDs),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_Sids2UnixIDs,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_Sids2UnixIDs,
+-		(ndr_print_function_t) ndr_print_wbint_Sids2UnixIDs,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2759,7 +2759,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_Uid2Sid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_Uid2Sid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_Uid2Sid,
+-		(ndr_print_function_t) ndr_print_wbint_Uid2Sid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2768,7 +2768,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_Gid2Sid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_Gid2Sid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_Gid2Sid,
+-		(ndr_print_function_t) ndr_print_wbint_Gid2Sid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2777,7 +2777,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_AllocateUid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_AllocateUid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_AllocateUid,
+-		(ndr_print_function_t) ndr_print_wbint_AllocateUid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2786,7 +2786,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_AllocateGid),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_AllocateGid,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_AllocateGid,
+-		(ndr_print_function_t) ndr_print_wbint_AllocateGid,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2795,7 +2795,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_QueryUser),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_QueryUser,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_QueryUser,
+-		(ndr_print_function_t) ndr_print_wbint_QueryUser,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2804,7 +2804,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupUserAliases),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupUserAliases,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupUserAliases,
+-		(ndr_print_function_t) ndr_print_wbint_LookupUserAliases,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2813,7 +2813,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupUserGroups),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupUserGroups,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupUserGroups,
+-		(ndr_print_function_t) ndr_print_wbint_LookupUserGroups,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2822,7 +2822,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_QuerySequenceNumber),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_QuerySequenceNumber,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_QuerySequenceNumber,
+-		(ndr_print_function_t) ndr_print_wbint_QuerySequenceNumber,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2831,7 +2831,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupGroupMembers),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupGroupMembers,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupGroupMembers,
+-		(ndr_print_function_t) ndr_print_wbint_LookupGroupMembers,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2840,7 +2840,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_QueryUserList),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_QueryUserList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_QueryUserList,
+-		(ndr_print_function_t) ndr_print_wbint_QueryUserList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2849,7 +2849,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_QueryGroupList),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_QueryGroupList,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_QueryGroupList,
+-		(ndr_print_function_t) ndr_print_wbint_QueryGroupList,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2858,7 +2858,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_DsGetDcName),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_DsGetDcName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_DsGetDcName,
+-		(ndr_print_function_t) ndr_print_wbint_DsGetDcName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2867,7 +2867,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_LookupRids),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_LookupRids,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_LookupRids,
+-		(ndr_print_function_t) ndr_print_wbint_LookupRids,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2876,7 +2876,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_CheckMachineAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_CheckMachineAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_CheckMachineAccount,
+-		(ndr_print_function_t) ndr_print_wbint_CheckMachineAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2885,7 +2885,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_ChangeMachineAccount),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_ChangeMachineAccount,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_ChangeMachineAccount,
+-		(ndr_print_function_t) ndr_print_wbint_ChangeMachineAccount,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -2894,7 +2894,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wbint_PingDc),
+ 		(ndr_push_flags_fn_t) ndr_push_wbint_PingDc,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wbint_PingDc,
+-		(ndr_print_function_t) ndr_print_wbint_PingDc,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_winreg.c
++++ b/source3/librpc/gen_ndr/ndr_winreg.c
+@@ -4864,7 +4864,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKCR),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKCR,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKCR,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKCR,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4873,7 +4873,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKCU),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKCU,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKCU,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKCU,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4882,7 +4882,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKLM),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKLM,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKLM,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKLM,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4891,7 +4891,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKPD),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKPD,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKPD,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKPD,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4900,7 +4900,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKU),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKU,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKU,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKU,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4909,7 +4909,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_CloseKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_CloseKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_CloseKey,
+-		(ndr_print_function_t) ndr_print_winreg_CloseKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4918,7 +4918,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_CreateKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_CreateKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_CreateKey,
+-		(ndr_print_function_t) ndr_print_winreg_CreateKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4927,7 +4927,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_DeleteKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_DeleteKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_DeleteKey,
+-		(ndr_print_function_t) ndr_print_winreg_DeleteKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4936,7 +4936,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_DeleteValue),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_DeleteValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_DeleteValue,
+-		(ndr_print_function_t) ndr_print_winreg_DeleteValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4945,7 +4945,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_EnumKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_EnumKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_EnumKey,
+-		(ndr_print_function_t) ndr_print_winreg_EnumKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4954,7 +4954,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_EnumValue),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_EnumValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_EnumValue,
+-		(ndr_print_function_t) ndr_print_winreg_EnumValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4963,7 +4963,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_FlushKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_FlushKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_FlushKey,
+-		(ndr_print_function_t) ndr_print_winreg_FlushKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4972,7 +4972,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_GetKeySecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_GetKeySecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_GetKeySecurity,
+-		(ndr_print_function_t) ndr_print_winreg_GetKeySecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4981,7 +4981,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_LoadKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_LoadKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_LoadKey,
+-		(ndr_print_function_t) ndr_print_winreg_LoadKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4990,7 +4990,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_NotifyChangeKeyValue),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_NotifyChangeKeyValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_NotifyChangeKeyValue,
+-		(ndr_print_function_t) ndr_print_winreg_NotifyChangeKeyValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4999,7 +4999,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenKey,
+-		(ndr_print_function_t) ndr_print_winreg_OpenKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5008,7 +5008,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_QueryInfoKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_QueryInfoKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_QueryInfoKey,
+-		(ndr_print_function_t) ndr_print_winreg_QueryInfoKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5017,7 +5017,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_QueryValue),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_QueryValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_QueryValue,
+-		(ndr_print_function_t) ndr_print_winreg_QueryValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5026,7 +5026,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_ReplaceKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_ReplaceKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_ReplaceKey,
+-		(ndr_print_function_t) ndr_print_winreg_ReplaceKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5035,7 +5035,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_RestoreKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_RestoreKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_RestoreKey,
+-		(ndr_print_function_t) ndr_print_winreg_RestoreKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5044,7 +5044,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_SaveKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_SaveKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_SaveKey,
+-		(ndr_print_function_t) ndr_print_winreg_SaveKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5053,7 +5053,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_SetKeySecurity),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_SetKeySecurity,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_SetKeySecurity,
+-		(ndr_print_function_t) ndr_print_winreg_SetKeySecurity,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5062,7 +5062,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_SetValue),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_SetValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_SetValue,
+-		(ndr_print_function_t) ndr_print_winreg_SetValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5071,7 +5071,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_UnLoadKey),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_UnLoadKey,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_UnLoadKey,
+-		(ndr_print_function_t) ndr_print_winreg_UnLoadKey,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5080,7 +5080,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_InitiateSystemShutdown),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_InitiateSystemShutdown,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_InitiateSystemShutdown,
+-		(ndr_print_function_t) ndr_print_winreg_InitiateSystemShutdown,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5089,7 +5089,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_AbortSystemShutdown),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_AbortSystemShutdown,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_AbortSystemShutdown,
+-		(ndr_print_function_t) ndr_print_winreg_AbortSystemShutdown,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5098,7 +5098,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_GetVersion),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_GetVersion,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_GetVersion,
+-		(ndr_print_function_t) ndr_print_winreg_GetVersion,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5107,7 +5107,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKCC),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKCC,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKCC,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKCC,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5116,7 +5116,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKDD),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKDD,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKDD,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKDD,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5125,7 +5125,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_QueryMultipleValues),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_QueryMultipleValues,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_QueryMultipleValues,
+-		(ndr_print_function_t) ndr_print_winreg_QueryMultipleValues,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5134,7 +5134,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_InitiateSystemShutdownEx),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_InitiateSystemShutdownEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_InitiateSystemShutdownEx,
+-		(ndr_print_function_t) ndr_print_winreg_InitiateSystemShutdownEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5143,7 +5143,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_SaveKeyEx),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_SaveKeyEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_SaveKeyEx,
+-		(ndr_print_function_t) ndr_print_winreg_SaveKeyEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5152,7 +5152,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKPT),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKPT,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKPT,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKPT,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5161,7 +5161,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_OpenHKPN),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_OpenHKPN,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_OpenHKPN,
+-		(ndr_print_function_t) ndr_print_winreg_OpenHKPN,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5170,7 +5170,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_QueryMultipleValues2),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_QueryMultipleValues2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_QueryMultipleValues2,
+-		(ndr_print_function_t) ndr_print_winreg_QueryMultipleValues2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5179,7 +5179,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct winreg_DeleteKeyEx),
+ 		(ndr_push_flags_fn_t) ndr_push_winreg_DeleteKeyEx,
+ 		(ndr_pull_flags_fn_t) ndr_pull_winreg_DeleteKeyEx,
+-		(ndr_print_function_t) ndr_print_winreg_DeleteKeyEx,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_wkssvc.c
++++ b/source3/librpc/gen_ndr/ndr_wkssvc.c
+@@ -11005,7 +11005,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetWkstaGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaGetInfo,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetWkstaGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11014,7 +11014,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetWkstaSetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaSetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaSetInfo,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetWkstaSetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11023,7 +11023,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetWkstaEnumUsers),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaEnumUsers,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaEnumUsers,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetWkstaEnumUsers,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11032,7 +11032,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrWkstaUserGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaUserGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaUserGetInfo,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrWkstaUserGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11041,7 +11041,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrWkstaUserSetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaUserSetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaUserSetInfo,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrWkstaUserSetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11050,7 +11050,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetWkstaTransportEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetWkstaTransportEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetWkstaTransportEnum,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetWkstaTransportEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11059,7 +11059,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrWkstaTransportAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaTransportAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaTransportAdd,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrWkstaTransportAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11068,7 +11068,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrWkstaTransportDel),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWkstaTransportDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWkstaTransportDel,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrWkstaTransportDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11077,7 +11077,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrUseAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseAdd,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrUseAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11086,7 +11086,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrUseGetInfo),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseGetInfo,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseGetInfo,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrUseGetInfo,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11095,7 +11095,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrUseDel),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseDel,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrUseDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11104,7 +11104,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrUseEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUseEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUseEnum,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrUseEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11113,7 +11113,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrMessageBufferSend),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrMessageBufferSend,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrMessageBufferSend,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrMessageBufferSend,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11122,7 +11122,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrWorkstationStatisticsGet),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrWorkstationStatisticsGet,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrWorkstationStatisticsGet,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrWorkstationStatisticsGet,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11131,7 +11131,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrLogonDomainNameAdd),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrLogonDomainNameAdd,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrLogonDomainNameAdd,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrLogonDomainNameAdd,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11140,7 +11140,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrLogonDomainNameDel),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrLogonDomainNameDel,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrLogonDomainNameDel,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrLogonDomainNameDel,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11149,7 +11149,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrJoinDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrJoinDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrJoinDomain,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrJoinDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11158,7 +11158,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrUnjoinDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUnjoinDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUnjoinDomain,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrUnjoinDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11167,7 +11167,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrRenameMachineInDomain),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrRenameMachineInDomain,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrRenameMachineInDomain,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrRenameMachineInDomain,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11176,7 +11176,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrValidateName),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrValidateName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrValidateName,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrValidateName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11185,7 +11185,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrGetJoinInformation),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrGetJoinInformation,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrGetJoinInformation,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrGetJoinInformation,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11194,7 +11194,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrGetJoinableOus),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrGetJoinableOus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrGetJoinableOus,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrGetJoinableOus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11203,7 +11203,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrJoinDomain2),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrJoinDomain2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrJoinDomain2,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrJoinDomain2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11212,7 +11212,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrUnjoinDomain2),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrUnjoinDomain2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrUnjoinDomain2,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrUnjoinDomain2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11221,7 +11221,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrRenameMachineInDomain2),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrRenameMachineInDomain2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrRenameMachineInDomain2,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrRenameMachineInDomain2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11230,7 +11230,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrValidateName2),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrValidateName2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrValidateName2,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrValidateName2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11239,7 +11239,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrGetJoinableOus2),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrGetJoinableOus2,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrGetJoinableOus2,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrGetJoinableOus2,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11248,7 +11248,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrAddAlternateComputerName),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrAddAlternateComputerName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrAddAlternateComputerName,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrAddAlternateComputerName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11257,7 +11257,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrRemoveAlternateComputerName),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrRemoveAlternateComputerName,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrRemoveAlternateComputerName,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrRemoveAlternateComputerName,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11266,7 +11266,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrSetPrimaryComputername),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrSetPrimaryComputername,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrSetPrimaryComputername,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrSetPrimaryComputername,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -11275,7 +11275,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wkssvc_NetrEnumerateComputerNames),
+ 		(ndr_push_flags_fn_t) ndr_push_wkssvc_NetrEnumerateComputerNames,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wkssvc_NetrEnumerateComputerNames,
+-		(ndr_print_function_t) ndr_print_wkssvc_NetrEnumerateComputerNames,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_wmi.c
++++ b/source3/librpc/gen_ndr/ndr_wmi.c
+@@ -139,7 +139,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Delete),
+ 		(ndr_push_flags_fn_t) ndr_push_Delete,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Delete,
+-		(ndr_print_function_t) ndr_print_Delete,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3704,7 +3704,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct OpenNamespace),
+ 		(ndr_push_flags_fn_t) ndr_push_OpenNamespace,
+ 		(ndr_pull_flags_fn_t) ndr_pull_OpenNamespace,
+-		(ndr_print_function_t) ndr_print_OpenNamespace,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3713,7 +3713,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct CancelAsyncCall),
+ 		(ndr_push_flags_fn_t) ndr_push_CancelAsyncCall,
+ 		(ndr_pull_flags_fn_t) ndr_pull_CancelAsyncCall,
+-		(ndr_print_function_t) ndr_print_CancelAsyncCall,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3722,7 +3722,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct QueryObjectSink),
+ 		(ndr_push_flags_fn_t) ndr_push_QueryObjectSink,
+ 		(ndr_pull_flags_fn_t) ndr_pull_QueryObjectSink,
+-		(ndr_print_function_t) ndr_print_QueryObjectSink,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3731,7 +3731,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetObject),
+ 		(ndr_push_flags_fn_t) ndr_push_GetObject,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetObject,
+-		(ndr_print_function_t) ndr_print_GetObject,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3740,7 +3740,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetObjectAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_GetObjectAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetObjectAsync,
+-		(ndr_print_function_t) ndr_print_GetObjectAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3749,7 +3749,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct PutClass),
+ 		(ndr_push_flags_fn_t) ndr_push_PutClass,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PutClass,
+-		(ndr_print_function_t) ndr_print_PutClass,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3758,7 +3758,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct PutClassAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_PutClassAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PutClassAsync,
+-		(ndr_print_function_t) ndr_print_PutClassAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3767,7 +3767,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct DeleteClass),
+ 		(ndr_push_flags_fn_t) ndr_push_DeleteClass,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DeleteClass,
+-		(ndr_print_function_t) ndr_print_DeleteClass,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3776,7 +3776,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct DeleteClassAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_DeleteClassAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DeleteClassAsync,
+-		(ndr_print_function_t) ndr_print_DeleteClassAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3785,7 +3785,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct CreateClassEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_CreateClassEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_CreateClassEnum,
+-		(ndr_print_function_t) ndr_print_CreateClassEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3794,7 +3794,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct CreateClassEnumAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_CreateClassEnumAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_CreateClassEnumAsync,
+-		(ndr_print_function_t) ndr_print_CreateClassEnumAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3803,7 +3803,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct PutInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_PutInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PutInstance,
+-		(ndr_print_function_t) ndr_print_PutInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3812,7 +3812,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct PutInstanceAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_PutInstanceAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_PutInstanceAsync,
+-		(ndr_print_function_t) ndr_print_PutInstanceAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3821,7 +3821,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct DeleteInstance),
+ 		(ndr_push_flags_fn_t) ndr_push_DeleteInstance,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DeleteInstance,
+-		(ndr_print_function_t) ndr_print_DeleteInstance,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3830,7 +3830,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct DeleteInstanceAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_DeleteInstanceAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DeleteInstanceAsync,
+-		(ndr_print_function_t) ndr_print_DeleteInstanceAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3839,7 +3839,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct CreateInstanceEnum),
+ 		(ndr_push_flags_fn_t) ndr_push_CreateInstanceEnum,
+ 		(ndr_pull_flags_fn_t) ndr_pull_CreateInstanceEnum,
+-		(ndr_print_function_t) ndr_print_CreateInstanceEnum,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3848,7 +3848,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct CreateInstanceEnumAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_CreateInstanceEnumAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_CreateInstanceEnumAsync,
+-		(ndr_print_function_t) ndr_print_CreateInstanceEnumAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3857,7 +3857,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ExecQuery),
+ 		(ndr_push_flags_fn_t) ndr_push_ExecQuery,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ExecQuery,
+-		(ndr_print_function_t) ndr_print_ExecQuery,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3866,7 +3866,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ExecQueryAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_ExecQueryAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ExecQueryAsync,
+-		(ndr_print_function_t) ndr_print_ExecQueryAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3875,7 +3875,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ExecNotificationQuery),
+ 		(ndr_push_flags_fn_t) ndr_push_ExecNotificationQuery,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ExecNotificationQuery,
+-		(ndr_print_function_t) ndr_print_ExecNotificationQuery,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3884,7 +3884,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ExecNotificationQueryAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_ExecNotificationQueryAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ExecNotificationQueryAsync,
+-		(ndr_print_function_t) ndr_print_ExecNotificationQueryAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3893,7 +3893,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ExecMethod),
+ 		(ndr_push_flags_fn_t) ndr_push_ExecMethod,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ExecMethod,
+-		(ndr_print_function_t) ndr_print_ExecMethod,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -3902,7 +3902,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct ExecMethodAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_ExecMethodAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_ExecMethodAsync,
+-		(ndr_print_function_t) ndr_print_ExecMethodAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4434,7 +4434,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Reset),
+ 		(ndr_push_flags_fn_t) ndr_push_Reset,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Reset,
+-		(ndr_print_function_t) ndr_print_Reset,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4443,7 +4443,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct IEnumWbemClassObject_Next),
+ 		(ndr_push_flags_fn_t) ndr_push_IEnumWbemClassObject_Next,
+ 		(ndr_pull_flags_fn_t) ndr_pull_IEnumWbemClassObject_Next,
+-		(ndr_print_function_t) ndr_print_IEnumWbemClassObject_Next,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4452,7 +4452,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct NextAsync),
+ 		(ndr_push_flags_fn_t) ndr_push_NextAsync,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NextAsync,
+-		(ndr_print_function_t) ndr_print_NextAsync,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4461,7 +4461,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct IEnumWbemClassObject_Clone),
+ 		(ndr_push_flags_fn_t) ndr_push_IEnumWbemClassObject_Clone,
+ 		(ndr_pull_flags_fn_t) ndr_pull_IEnumWbemClassObject_Clone,
+-		(ndr_print_function_t) ndr_print_IEnumWbemClassObject_Clone,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -4470,7 +4470,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Skip),
+ 		(ndr_push_flags_fn_t) ndr_push_Skip,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Skip,
+-		(ndr_print_function_t) ndr_print_Skip,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5143,7 +5143,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Clone),
+ 		(ndr_push_flags_fn_t) ndr_push_Clone,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Clone,
+-		(ndr_print_function_t) ndr_print_Clone,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5152,7 +5152,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetNames),
+ 		(ndr_push_flags_fn_t) ndr_push_GetNames,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetNames,
+-		(ndr_print_function_t) ndr_print_GetNames,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5161,7 +5161,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct BeginEnumeration),
+ 		(ndr_push_flags_fn_t) ndr_push_BeginEnumeration,
+ 		(ndr_pull_flags_fn_t) ndr_pull_BeginEnumeration,
+-		(ndr_print_function_t) ndr_print_BeginEnumeration,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5170,7 +5170,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Next),
+ 		(ndr_push_flags_fn_t) ndr_push_Next,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Next,
+-		(ndr_print_function_t) ndr_print_Next,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5179,7 +5179,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct EndEnumeration),
+ 		(ndr_push_flags_fn_t) ndr_push_EndEnumeration,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EndEnumeration,
+-		(ndr_print_function_t) ndr_print_EndEnumeration,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5188,7 +5188,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct SetValue),
+ 		(ndr_push_flags_fn_t) ndr_push_SetValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_SetValue,
+-		(ndr_print_function_t) ndr_print_SetValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5197,7 +5197,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetValue),
+ 		(ndr_push_flags_fn_t) ndr_push_GetValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetValue,
+-		(ndr_print_function_t) ndr_print_GetValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5206,7 +5206,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct DeleteValue),
+ 		(ndr_push_flags_fn_t) ndr_push_DeleteValue,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DeleteValue,
+-		(ndr_print_function_t) ndr_print_DeleteValue,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5215,7 +5215,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct DeleteAll),
+ 		(ndr_push_flags_fn_t) ndr_push_DeleteAll,
+ 		(ndr_pull_flags_fn_t) ndr_pull_DeleteAll,
+-		(ndr_print_function_t) ndr_print_DeleteAll,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5963,7 +5963,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct EstablishPosition),
+ 		(ndr_push_flags_fn_t) ndr_push_EstablishPosition,
+ 		(ndr_pull_flags_fn_t) ndr_pull_EstablishPosition,
+-		(ndr_print_function_t) ndr_print_EstablishPosition,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5972,7 +5972,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct RequestChallenge),
+ 		(ndr_push_flags_fn_t) ndr_push_RequestChallenge,
+ 		(ndr_pull_flags_fn_t) ndr_pull_RequestChallenge,
+-		(ndr_print_function_t) ndr_print_RequestChallenge,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5981,7 +5981,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct WBEMLogin),
+ 		(ndr_push_flags_fn_t) ndr_push_WBEMLogin,
+ 		(ndr_pull_flags_fn_t) ndr_pull_WBEMLogin,
+-		(ndr_print_function_t) ndr_print_WBEMLogin,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -5990,7 +5990,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct NTLMLogin),
+ 		(ndr_push_flags_fn_t) ndr_push_NTLMLogin,
+ 		(ndr_pull_flags_fn_t) ndr_pull_NTLMLogin,
+-		(ndr_print_function_t) ndr_print_NTLMLogin,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6225,7 +6225,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct IWbemWCOSmartEnum_Next),
+ 		(ndr_push_flags_fn_t) ndr_push_IWbemWCOSmartEnum_Next,
+ 		(ndr_pull_flags_fn_t) ndr_pull_IWbemWCOSmartEnum_Next,
+-		(ndr_print_function_t) ndr_print_IWbemWCOSmartEnum_Next,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6479,7 +6479,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Fetch),
+ 		(ndr_push_flags_fn_t) ndr_push_Fetch,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Fetch,
+-		(ndr_print_function_t) ndr_print_Fetch,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6488,7 +6488,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Test),
+ 		(ndr_push_flags_fn_t) ndr_push_Test,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Test,
+-		(ndr_print_function_t) ndr_print_Test,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6920,7 +6920,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetResultObject),
+ 		(ndr_push_flags_fn_t) ndr_push_GetResultObject,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetResultObject,
+-		(ndr_print_function_t) ndr_print_GetResultObject,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6929,7 +6929,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetResultString),
+ 		(ndr_push_flags_fn_t) ndr_push_GetResultString,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetResultString,
+-		(ndr_print_function_t) ndr_print_GetResultString,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6938,7 +6938,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetResultServices),
+ 		(ndr_push_flags_fn_t) ndr_push_GetResultServices,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetResultServices,
+-		(ndr_print_function_t) ndr_print_GetResultServices,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -6947,7 +6947,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct GetCallStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_GetCallStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_GetCallStatus,
+-		(ndr_print_function_t) ndr_print_GetCallStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7211,7 +7211,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct SetStatus),
+ 		(ndr_push_flags_fn_t) ndr_push_SetStatus,
+ 		(ndr_pull_flags_fn_t) ndr_pull_SetStatus,
+-		(ndr_print_function_t) ndr_print_SetStatus,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -7220,7 +7220,7 @@ static const struct ndr_interface_call I
+ 		sizeof(struct Indicate),
+ 		(ndr_push_flags_fn_t) ndr_push_Indicate,
+ 		(ndr_pull_flags_fn_t) ndr_pull_Indicate,
+-		(ndr_print_function_t) ndr_print_Indicate,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_wzcsvc.c
++++ b/source3/librpc/gen_ndr/ndr_wzcsvc.c
+@@ -711,7 +711,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EnumInterfaces),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EnumInterfaces,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EnumInterfaces,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EnumInterfaces,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -720,7 +720,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_QueryInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_QueryInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_QueryInterface,
+-		(ndr_print_function_t) ndr_print_wzcsvc_QueryInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -729,7 +729,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_SetInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_SetInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_SetInterface,
+-		(ndr_print_function_t) ndr_print_wzcsvc_SetInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -738,7 +738,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_RefreshInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_RefreshInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_RefreshInterface,
+-		(ndr_print_function_t) ndr_print_wzcsvc_RefreshInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -747,7 +747,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_QueryContext),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_QueryContext,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_QueryContext,
+-		(ndr_print_function_t) ndr_print_wzcsvc_QueryContext,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -756,7 +756,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_SetContext),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_SetContext,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_SetContext,
+-		(ndr_print_function_t) ndr_print_wzcsvc_SetContext,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -765,7 +765,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolUIResponse),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolUIResponse,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolUIResponse,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolUIResponse,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -774,7 +774,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolGetCustomAuthData),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolGetCustomAuthData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolGetCustomAuthData,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolGetCustomAuthData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -783,7 +783,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolSetCustomAuthData),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolSetCustomAuthData,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolSetCustomAuthData,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolSetCustomAuthData,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -792,7 +792,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolGetInterfaceParams),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolGetInterfaceParams,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolGetInterfaceParams,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolGetInterfaceParams,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -801,7 +801,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolSetInterfaceParams),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolSetInterfaceParams,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolSetInterfaceParams,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolSetInterfaceParams,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -810,7 +810,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolReAuthenticateInterface),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolReAuthenticateInterface,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolReAuthenticateInterface,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolReAuthenticateInterface,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -819,7 +819,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EapolQueryInterfaceState),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EapolQueryInterfaceState,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EapolQueryInterfaceState,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EapolQueryInterfaceState,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -828,7 +828,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_OpenWZCDbLogSession),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_OpenWZCDbLogSession,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_OpenWZCDbLogSession,
+-		(ndr_print_function_t) ndr_print_wzcsvc_OpenWZCDbLogSession,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -837,7 +837,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_CloseWZCDbLogSession),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_CloseWZCDbLogSession,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_CloseWZCDbLogSession,
+-		(ndr_print_function_t) ndr_print_wzcsvc_CloseWZCDbLogSession,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -846,7 +846,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_EnumWZCDbLogRecords),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_EnumWZCDbLogRecords,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_EnumWZCDbLogRecords,
+-		(ndr_print_function_t) ndr_print_wzcsvc_EnumWZCDbLogRecords,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -855,7 +855,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_FlushWZCdbLog),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_FlushWZCdbLog,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_FlushWZCdbLog,
+-		(ndr_print_function_t) ndr_print_wzcsvc_FlushWZCdbLog,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+@@ -864,7 +864,7 @@ static const struct ndr_interface_call w
+ 		sizeof(struct wzcsvc_GetWZCDbLogRecord),
+ 		(ndr_push_flags_fn_t) ndr_push_wzcsvc_GetWZCDbLogRecord,
+ 		(ndr_pull_flags_fn_t) ndr_pull_wzcsvc_GetWZCDbLogRecord,
+-		(ndr_print_function_t) ndr_print_wzcsvc_GetWZCDbLogRecord,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- a/source3/librpc/gen_ndr/ndr_xattr.c
++++ b/source3/librpc/gen_ndr/ndr_xattr.c
+@@ -1101,7 +1101,7 @@ static const struct ndr_interface_call x
+ 		sizeof(struct xattr_parse_DOSATTRIB),
+ 		(ndr_push_flags_fn_t) ndr_push_xattr_parse_DOSATTRIB,
+ 		(ndr_pull_flags_fn_t) ndr_pull_xattr_parse_DOSATTRIB,
+-		(ndr_print_function_t) ndr_print_xattr_parse_DOSATTRIB,
++		(ndr_print_function_t) ndr_print_disabled,
+ 		{ 0, NULL },
+ 		{ 0, NULL },
+ 	},
+--- /dev/null
++++ b/source3/remove-librpc-print-calls.sh
+@@ -0,0 +1,22 @@
++#!/usr/bin/env bash
++set -e
++for file in ${1:-librpc/gen_ndr/ndr_*.c}; do
++	quilt add "$file" || true
++	awk '
++$0 ~ /^static const struct ndr_interface_call .* = {$/ {
++	replace = 1
++}
++
++$0 ~ /^}$/ {
++	replace = 0;
++}
++
++replace == 1 {
++	gsub(/.ndr_print_function_t. .*,/, "(ndr_print_function_t) ndr_print_disabled,", $0)
++}
++{
++	print $0
++}
++	' < "$file" > "$file.new"
++	mv "$file.new" "$file"
++done
+--- a/librpc/ndr/libndr.h
++++ b/librpc/ndr/libndr.h
+@@ -662,6 +662,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_enum
+ _PUBLIC_ enum ndr_err_code ndr_push_enum_uint1632(struct ndr_push *ndr, int ndr_flags, uint16_t v);
+ 
+ _PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);
++_PUBLIC_ void ndr_print_disabled(struct ndr_print *ndr, const char *name, int flags, void *r);
+ 
+ #ifndef VERBOSE_ERROR
+ #define ndr_print_bool(...) do {} while (0)
diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile
new file mode 100644
index 0000000000..3600d80637
--- /dev/null
+++ b/package/network/services/uhttpd/Makefile
@@ -0,0 +1,153 @@
+#
+# Copyright (C) 2010-2015 Jo-Philipp Wich <jo@mein.io>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uhttpd
+PKG_VERSION:=2016-10-25
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/uhttpd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=1628fa4b34aa143187353f81e8001b9a15286bda
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=9d7ceef6ce40cb12f4065b41d99cf584fcd971dce4a5a13b6a92b04d663e4301
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=ISC
+
+PKG_BUILD_DEPENDS = ustream-ssl
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+include $(INCLUDE_DIR)/version.mk
+
+define Package/uhttpd/default
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Web Servers/Proxies
+  TITLE:=uHTTPd - tiny, single threaded HTTP server
+endef
+
+define Package/uhttpd
+  $(Package/uhttpd/default)
+  DEPENDS:=+libubox +libblobmsg-json +libjson-script
+endef
+
+define Package/uhttpd/description
+ uHTTPd is a tiny single threaded HTTP server with TLS, CGI and Lua
+ support. It is intended as a drop-in replacement for the Busybox
+ HTTP daemon.
+endef
+
+define Package/uhttpd/config
+  config PACKAGE_uhttpd_debug
+    bool "Build with debug messages"
+    default n
+endef
+
+
+define Package/uhttpd-mod-tls
+  $(Package/uhttpd/default)
+  TITLE+= (TLS plugin)
+  DEPENDS:=uhttpd \
+	+PACKAGE_uhttpd-mod-tls_polarssl:libustream-polarssl \
+	+PACKAGE_uhttpd-mod-tls_mbedtls:libustream-mbedtls \
+	+PACKAGE_uhttpd-mod-tls_cyassl:libustream-cyassl \
+	+PACKAGE_uhttpd-mod-tls_openssl:libustream-openssl
+endef
+
+define Package/uhttpd-mod-tls/description
+ The TLS plugin adds HTTPS support to uHTTPd.
+endef
+
+define Package/uhttpd-mod-tls/config
+  choice
+    depends on PACKAGE_uhttpd-mod-tls
+    prompt "TLS Provider"
+    default PACKAGE_uhttpd-mod-tls_polarssl
+
+    config PACKAGE_uhttpd-mod-tls_mbedtls
+      bool "mbedTLS"
+
+    config PACKAGE_uhttpd-mod-tls_polarssl
+      bool "PolarSSL"
+
+    config PACKAGE_uhttpd-mod-tls_cyassl
+      bool "CyaSSL"
+
+    config PACKAGE_uhttpd-mod-tls_openssl
+      bool "OpenSSL"
+  endchoice
+endef
+
+define Package/uhttpd-mod-lua
+  $(Package/uhttpd/default)
+  TITLE+= (Lua plugin)
+  DEPENDS:=uhttpd +liblua
+endef
+
+define Package/uhttpd-mod-lua/description
+ The Lua plugin adds a CGI-like Lua runtime interface to uHTTPd.
+endef
+
+
+define Package/uhttpd-mod-ubus
+  $(Package/uhttpd/default)
+  TITLE+= (ubus plugin)
+  DEPENDS:=uhttpd +libubus +libblobmsg-json
+endef
+
+define Package/uhttpd-mod-ubus/description
+ The ubus plugin adds a HTTP/JSON RPC proxy for ubus and publishes the
+ session.* namespace and procedures.
+endef
+
+define Package/uhttpd/conffiles
+/etc/config/uhttpd
+/etc/uhttpd.crt
+/etc/uhttpd.key
+endef
+
+ifneq ($(CONFIG_USE_GLIBC),)
+  TARGET_CFLAGS += -D_DEFAULT_SOURCE
+endif
+
+TARGET_LDFLAGS += -lcrypt
+
+CMAKE_OPTIONS = -DTLS_SUPPORT=on
+
+define Package/uhttpd/install
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/uhttpd.init $(1)/etc/init.d/uhttpd
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_CONF) ./files/uhttpd.config $(1)/etc/config/uhttpd
+	$(VERSION_SED_SCRIPT) $(1)/etc/config/uhttpd
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd $(1)/usr/sbin/uhttpd
+endef
+
+define Package/uhttpd-mod-tls/install
+	true
+endef
+
+define Package/uhttpd-mod-lua/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_lua.so $(1)/usr/lib/
+endef
+
+define Package/uhttpd-mod-ubus/install
+	$(INSTALL_DIR) $(1)/usr/lib $(1)/etc/uci-defaults
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_ubus.so $(1)/usr/lib/
+	$(INSTALL_DATA) ./files/ubus.default $(1)/etc/uci-defaults/00_uhttpd_ubus
+endef
+
+
+$(eval $(call BuildPackage,uhttpd))
+$(eval $(call BuildPackage,uhttpd-mod-tls))
+$(eval $(call BuildPackage,uhttpd-mod-lua))
+$(eval $(call BuildPackage,uhttpd-mod-ubus))
diff --git a/package/network/services/uhttpd/files/ubus.default b/package/network/services/uhttpd/files/ubus.default
new file mode 100644
index 0000000000..f0f71e9d35
--- /dev/null
+++ b/package/network/services/uhttpd/files/ubus.default
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ -z "$(uci -q get uhttpd.main.ubus_prefix)" ]; then
+	uci set uhttpd.main.ubus_prefix=/ubus
+	uci commit uhttpd
+fi
+
+exit 0
diff --git a/package/network/services/uhttpd/files/uhttpd.config b/package/network/services/uhttpd/files/uhttpd.config
new file mode 100644
index 0000000000..89f99aaeea
--- /dev/null
+++ b/package/network/services/uhttpd/files/uhttpd.config
@@ -0,0 +1,132 @@
+# Server configuration
+config uhttpd main
+
+	# HTTP listen addresses, multiple allowed
+	list listen_http	0.0.0.0:80
+	list listen_http	[::]:80
+
+	# HTTPS listen addresses, multiple allowed
+	list listen_https	0.0.0.0:443
+	list listen_https	[::]:443
+
+	# Redirect HTTP requests to HTTPS if possible
+	option redirect_https	1
+
+	# Server document root
+	option home		/www
+
+	# Reject requests from RFC1918 IP addresses
+	# directed to the servers public IP(s).
+	# This is a DNS rebinding countermeasure.
+	option rfc1918_filter 1
+
+	# Maximum number of concurrent requests.
+	# If this number is exceeded, further requests are
+	# queued until the number of running requests drops
+	# below the limit again.
+	option max_requests 3
+
+	# Maximum number of concurrent connections.
+	# If this number is exceeded, further TCP connection
+	# attempts are queued until the number of active
+	# connections drops below the limit again.
+	option max_connections 100
+
+	# Certificate and private key for HTTPS.
+	# If no listen_https addresses are given,
+	# the key options are ignored.
+	option cert		/etc/uhttpd.crt
+	option key		/etc/uhttpd.key
+
+	# CGI url prefix, will be searched in docroot.
+	# Default is /cgi-bin
+	option cgi_prefix	/cgi-bin
+
+	# List of extension->interpreter mappings.
+	# Files with an associated interpreter can
+	# be called outside of the CGI prefix and do
+	# not need to be executable.
+#	list interpreter	".php=/usr/bin/php-cgi"
+#	list interpreter	".cgi=/usr/bin/perl"
+
+	# Lua url prefix and handler script.
+	# Lua support is disabled if no prefix given.
+#	option lua_prefix	/luci
+#	option lua_handler	/usr/lib/lua/luci/sgi/uhttpd.lua
+
+	# Specify the ubus-rpc prefix and socket path.
+#	option ubus_prefix	/ubus
+#	option ubus_socket	/var/run/ubus.sock
+
+	# CGI/Lua timeout, if the called script does not
+	# write data within the given amount of seconds,
+	# the server will terminate the request with
+	# 504 Gateway Timeout response.
+	option script_timeout	60
+
+	# Network timeout, if the current connection is
+	# blocked for the specified amount of seconds,
+	# the server will terminate the associated
+	# request process.
+	option network_timeout	30
+
+	# HTTP Keep-Alive, specifies the timeout for persistent
+	# HTTP/1.1 connections. Setting this to 0 will disable
+	# persistent HTTP connections.
+	option http_keepalive	20
+
+	# TCP Keep-Alive, send periodic keep-alive probes
+	# over established connections to detect dead peers.
+	# The value is given in seconds to specify the
+	# interval between subsequent probes.
+	# Setting this to 0 will disable TCP keep-alive.
+	option tcp_keepalive	1
+
+	# Basic auth realm, defaults to local hostname
+#	option realm	Lede
+
+	# Configuration file in busybox httpd format
+#	option config	/etc/httpd.conf
+
+	# Do not follow symlinks that point outside of the
+	# home directory.
+#	option no_symlinks	0
+
+	# Do not produce directory listings but send 403
+	# instead if a client requests an url pointing to
+	# a directory without any index file.
+#	option no_dirlists	0
+
+	# Do not authenticate any ubus-rpc requests against
+	# the ubus session/access procedure.
+	# This is dangerous and should be always left off
+	# except for development and debug purposes!
+#	option no_ubusauth	0
+
+	# For this instance of uhttpd use the listed httpauth
+	# sections to require Basic auth to the specified
+	# resources.
+#	list httpauth prefix_user
+
+
+# Defaults for automatic certificate and key generation
+config cert defaults
+
+	# Validity time
+	option days		730
+
+	# RSA key size
+	option bits		2048
+
+	# Location
+	option country		ZZ
+	option state		Somewhere
+	option location		Unknown
+
+	# Common name
+	option commonname	'%D'
+
+# config httpauth prefix_user
+#	option prefix /protected/url/path
+#	option username user
+#	option password 'plaintext_or_md5_or_$p$user_for_system_user'
diff --git a/package/network/services/uhttpd/files/uhttpd.init b/package/network/services/uhttpd/files/uhttpd.init
new file mode 100755
index 0000000000..53bf04c921
--- /dev/null
+++ b/package/network/services/uhttpd/files/uhttpd.init
@@ -0,0 +1,187 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010 Jo-Philipp Wich
+
+START=50
+
+USE_PROCD=1
+
+UHTTPD_BIN="/usr/sbin/uhttpd"
+PX5G_BIN="/usr/sbin/px5g"
+OPENSSL_BIN="/usr/bin/openssl"
+
+append_arg() {
+	local cfg="$1"
+	local var="$2"
+	local opt="$3"
+	local def="$4"
+	local val
+
+	config_get val "$cfg" "$var"
+	[ -n "$val" -o -n "$def" ] && procd_append_param command "$opt" "${val:-$def}"
+}
+
+append_bool() {
+	local cfg="$1"
+	local var="$2"
+	local opt="$3"
+	local def="$4"
+	local val
+
+	config_get_bool val "$cfg" "$var" "$def"
+	[ "$val" = 1 ] && procd_append_param command "$opt"
+}
+
+generate_keys() {
+	local cfg="$1"
+	local key="$2"
+	local crt="$3"
+	local days bits country state location commonname
+
+	config_get days       "$cfg" days
+	config_get bits       "$cfg" bits
+	config_get country    "$cfg" country
+	config_get state      "$cfg" state
+	config_get location   "$cfg" location
+	config_get commonname "$cfg" commonname
+
+	# Prefer px5g for certificate generation (existence evaluated last)
+	local GENKEY_CMD=""
+	local UNIQUEID=$(dd if=/dev/urandom bs=1 count=4 | hexdump -e '1/1 "%02x"')
+	[ -x "$OPENSSL_BIN" ] && GENKEY_CMD="$OPENSSL_BIN req -x509 -outform der -nodes"
+	[ -x "$PX5G_BIN" ] && GENKEY_CMD="$PX5G_BIN selfsigned -der"
+	[ -n "$GENKEY_CMD" ] && {
+		$GENKEY_CMD \
+			-days ${days:-730} -newkey rsa:${bits:-2048} -keyout "${UHTTPD_KEY}.new" -out "${UHTTPD_CERT}.new" \
+			-subj /C="${country:-DE}"/ST="${state:-Saxony}"/L="${location:-Leipzig}"/O="${commonname:-Lede}$UNIQUEID"/CN="${commonname:-Lede}"
+		sync
+		mv "${UHTTPD_KEY}.new" "${UHTTPD_KEY}"
+		mv "${UHTTPD_CERT}.new" "${UHTTPD_CERT}"
+	}
+}
+
+create_httpauth() {
+	local cfg="$1"
+	local prefix username password
+
+	config_get prefix "$cfg" prefix
+	config_get username "$cfg" username
+	config_get password "$cfg" password
+
+	if [ -z "$prefix" ] || [ -z "$username" ] || [ -z "$password" ]; then
+		return
+	fi
+	echo "${prefix}:${username}:${password}" >>$httpdconf
+	haveauth=1
+}
+
+start_instance()
+{
+	UHTTPD_CERT=""
+	UHTTPD_KEY=""
+
+	local cfg="$1"
+	local realm="$(uci_get system.@system[0].hostname)"
+	local listen http https interpreter indexes path handler httpdconf haveauth
+
+	procd_open_instance
+	procd_set_param respawn
+	procd_set_param stderr 1
+	procd_set_param command "$UHTTPD_BIN" -f
+
+	config_get config "$cfg" config
+	if [ -z "$config" ]; then
+		mkdir -p /var/etc/uhttpd
+		httpdconf="/var/etc/uhttpd/httpd.${cfg}.conf"
+		rm -f ${httpdconf}
+		config_list_foreach "$cfg" httpauth create_httpauth
+		if [ "$haveauth" = "1" ]; then
+			procd_append_param command -c ${httpdconf}
+			[ -r /etc/httpd.conf ] && cat /etc/httpd.conf >>/var/etc/uhttpd/httpd.${cfg}.conf
+		fi
+	fi
+
+	append_arg "$cfg" home "-h"
+	append_arg "$cfg" realm "-r" "${realm:-OpenWrt}"
+	append_arg "$cfg" config "-c"
+	append_arg "$cfg" cgi_prefix "-x"
+	[ -f /usr/lib/uhttpd_lua.so ] && {
+		config_get handler "$cfg" lua_handler
+		[ -f "$handler" ] && append_arg "$cfg" lua_prefix "-l" && {
+			procd_append_param command "-L" "$handler"
+		}
+	}
+	[ -f /usr/lib/uhttpd_ubus.so ] && {
+		append_arg "$cfg" ubus_prefix "-u"
+		append_arg "$cfg" ubus_socket "-U"
+		append_bool "$cfg" ubus_cors "-X" 0
+	}
+	append_arg "$cfg" script_timeout "-t"
+	append_arg "$cfg" network_timeout "-T"
+	append_arg "$cfg" http_keepalive "-k"
+	append_arg "$cfg" tcp_keepalive "-A"
+	append_arg "$cfg" error_page "-E"
+	append_arg "$cfg" max_requests "-n" 3
+	append_arg "$cfg" max_connections "-N"
+
+	append_bool "$cfg" no_ubusauth "-a" 0
+	append_bool "$cfg" no_symlinks "-S" 0
+	append_bool "$cfg" no_dirlists "-D" 0
+	append_bool "$cfg" rfc1918_filter "-R" 0
+
+	config_get alias_list "$cfg" alias
+	for alias in $alias_list; do
+		 procd_append_param command -y "$alias"
+	done
+
+	config_get http "$cfg" listen_http
+	for listen in $http; do
+		 procd_append_param command -p "$listen"
+	done
+
+	config_get interpreter "$cfg" interpreter
+	for path in $interpreter; do
+		procd_append_param command -i "$path"
+	done
+
+	config_get indexes "$cfg" index_page
+	for path in $indexes; do
+		procd_append_param command -I "$path"
+	done
+
+	config_get https "$cfg" listen_https
+	config_get UHTTPD_KEY  "$cfg" key  /etc/uhttpd.key
+	config_get UHTTPD_CERT "$cfg" cert /etc/uhttpd.crt
+
+	[ -f /lib/libustream-ssl.so ] && [ -n "$https" ] && {
+		[ -s "$UHTTPD_CERT" -a -s "$UHTTPD_KEY" ] || {
+			config_foreach generate_keys cert
+		}
+
+		[ -f "$UHTTPD_CERT" -a -f "$UHTTPD_KEY" ] && {
+			append_arg "$cfg" cert "-C"
+			append_arg "$cfg" key  "-K"
+
+			for listen in $https; do
+				procd_append_param command -s "$listen"
+			done
+		}
+
+		append_bool "$cfg" redirect_https "-q" 0
+	}
+
+	for file in /etc/uhttpd/*.json; do
+		[ -s "$file" ] && procd_append_param command -H "$file"
+	done
+
+	procd_close_instance
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "uhttpd"
+}
+
+start_service() {
+	config_load uhttpd
+	config_foreach start_instance uhttpd
+}
diff --git a/package/network/utils/arptables/Makefile b/package/network/utils/arptables/Makefile
new file mode 100644
index 0000000000..1ed0287ca2
--- /dev/null
+++ b/package/network/utils/arptables/Makefile
@@ -0,0 +1,42 @@
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=arptables
+PKG_VERSION:=2015-05-20
+PKG_RELEASE:=1
+PKG_MIRROR_MD5SUM:=736c2a88f99936811d80dd75d3016c3829ebb9dac8b28ced020a0bee149c2a31
+
+PKG_SOURCE_URL:=git://git.netfilter.org/arptables
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=f4ab8f63f11a72f14687a6646d04ae1bae3fa45f
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/arptables
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Firewall
+  TITLE:=ARP firewalling software
+  DEPENDS:=+kmod-arptables
+  URL:=https://git.netfilter.org/arptables/
+endef
+
+MAKE_FLAGS += \
+	COPT_FLAGS="$(TARGET_CFLAGS) -D__OPTIMIZE__=1" \
+	KERNEL_DIR="$(LINUX_DIR)"
+
+define Package/arptables/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,arptables))
diff --git a/package/network/utils/comgt/Makefile b/package/network/utils/comgt/Makefile
new file mode 100644
index 0000000000..9d99d640bc
--- /dev/null
+++ b/package/network/utils/comgt/Makefile
@@ -0,0 +1,104 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=comgt
+PKG_VERSION:=0.32
+PKG_RELEASE:=27
+
+PKG_SOURCE:=$(PKG_NAME).$(PKG_VERSION).tgz
+PKG_SOURCE_URL:=@SF/comgt
+PKG_MD5SUM:=db2452680c3d953631299e331daf49ef
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0+
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME).$(PKG_VERSION)
+PKG_CHECK_FORMAT_SECURITY:=0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/comgt/Default
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=WWAN
+endef
+
+define Package/comgt
+$(call Package/comgt/Default)
+  TITLE:=Option/Vodafone 3G/GPRS control tool
+  DEPENDS:=+chat
+  URL:=http://manpages.ubuntu.com/manpages/trusty/man1/comgt.1.html
+endef
+
+define Package/comgt-directip
+$(call Package/comgt/Default)
+  TITLE:=Sierra Wireless Direct-IP support
+  DEPENDS:=+comgt +kmod-usb-serial +kmod-usb-serial-sierrawireless +kmod-usb-net +kmod-usb-net-sierrawireless
+endef
+
+define Package/comgt-ncm
+$(call Package/comgt/Default)
+  TITLE+=NCM 3G/4G Support
+  DEPENDS:=+comgt +wwan
+endef
+
+define Package/comgt/description
+ comgt is a scripting language interpreter useful for establishing 
+ communications on serial lines and through PCMCIA modems as well as GPRS 
+ and 3G datacards.
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		CFLAGS="$(TARGET_CFLAGS)" \
+		LDFLAGS="" \
+		comgt
+endef
+
+define Package/comgt/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/comgt $(1)/usr/bin/
+	$(LN) comgt $(1)/usr/bin/gcom
+	$(INSTALL_DIR) $(1)/etc/chatscripts
+	$(INSTALL_DATA) ./files/3g.chat $(1)/etc/chatscripts/3g.chat
+	$(INSTALL_DATA) ./files/evdo.chat $(1)/etc/chatscripts/evdo.chat
+	$(INSTALL_DIR) $(1)/etc/gcom
+	$(INSTALL_DATA) ./files/setpin.gcom $(1)/etc/gcom/setpin.gcom
+	$(INSTALL_DATA) ./files/setmode.gcom $(1)/etc/gcom/setmode.gcom
+	$(INSTALL_DATA) ./files/getcardinfo.gcom $(1)/etc/gcom/getcardinfo.gcom
+	$(INSTALL_DATA) ./files/getstrength.gcom $(1)/etc/gcom/getstrength.gcom
+	$(INSTALL_DATA) ./files/getcarrier.gcom $(1)/etc/gcom/getcarrier.gcom
+	$(INSTALL_DATA) ./files/getcnum.gcom $(1)/etc/gcom/getcnum.gcom
+	$(INSTALL_DATA) ./files/getimsi.gcom $(1)/etc/gcom/getimsi.gcom
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/tty
+	$(INSTALL_DATA) ./files/3g.usb $(1)/etc/hotplug.d/tty/30-3g
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/3g.sh $(1)/lib/netifd/proto/3g.sh
+endef
+
+define Package/comgt-directip/install
+	$(INSTALL_DIR) $(1)/etc/gcom
+	$(INSTALL_DATA) ./files/directip.gcom $(1)/etc/gcom/directip.gcom
+	$(INSTALL_DATA) ./files/directip-stop.gcom $(1)/etc/gcom/directip-stop.gcom
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/directip.sh $(1)/lib/netifd/proto/directip.sh
+endef
+
+define Package/comgt-ncm/install
+	$(INSTALL_DIR) $(1)/etc/gcom
+	$(INSTALL_DATA) ./files/ncm.json $(1)/etc/gcom/ncm.json
+	$(INSTALL_DATA) ./files/runcommand.gcom $(1)/etc/gcom/runcommand.gcom
+	$(INSTALL_DIR) $(1)/lib/netifd/proto
+	$(INSTALL_BIN) ./files/ncm.sh $(1)/lib/netifd/proto/ncm.sh
+endef
+
+$(eval $(call BuildPackage,comgt))
+$(eval $(call BuildPackage,comgt-directip))
+$(eval $(call BuildPackage,comgt-ncm))
diff --git a/package/network/utils/comgt/files/3g.chat b/package/network/utils/comgt/files/3g.chat
new file mode 100644
index 0000000000..66562400f0
--- /dev/null
+++ b/package/network/utils/comgt/files/3g.chat
@@ -0,0 +1,12 @@
+ABORT   BUSY
+ABORT   'NO CARRIER'
+ABORT   ERROR
+REPORT  CONNECT
+TIMEOUT 10
+""      "AT&F"
+OK      "ATE1"
+OK      'AT+CGDCONT=1,"IP","$USE_APN"'
+SAY     "Calling UMTS/GPRS"
+TIMEOUT 30
+OK      "ATD$DIALNUMBER"
+CONNECT ' '
diff --git a/package/network/utils/comgt/files/3g.sh b/package/network/utils/comgt/files/3g.sh
new file mode 100644
index 0000000000..b0cdae234d
--- /dev/null
+++ b/package/network/utils/comgt/files/3g.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	NOT_INCLUDED=1
+	INCLUDE_ONLY=1
+
+	. ../netifd-proto.sh
+	. ./ppp.sh
+	init_proto "$@"
+}
+
+proto_3g_init_config() {
+	no_device=1
+	available=1
+	ppp_generic_init_config
+	proto_config_add_string "device:device"
+	proto_config_add_string "apn"
+	proto_config_add_string "service"
+	proto_config_add_string "pincode"
+	proto_config_add_string "dialnumber"
+}
+
+proto_3g_setup() {
+	local interface="$1"
+	local chat
+
+	json_get_var device device
+	json_get_var apn apn
+	json_get_var service service
+	json_get_var pincode pincode
+	json_get_var dialnumber dialnumber
+
+	[ -n "$dat_device" ] && device=$dat_device
+	[ -e "$device" ] || {
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	case "$service" in
+		cdma|evdo)
+			chat="/etc/chatscripts/evdo.chat"
+		;;
+		*)
+			chat="/etc/chatscripts/3g.chat"
+			cardinfo=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom)
+			if echo "$cardinfo" | grep -q Novatel; then
+				case "$service" in
+					umts_only) CODE=2;;
+					gprs_only) CODE=1;;
+					*) CODE=0;;
+				esac
+				export MODE="AT\$NWRAT=${CODE},2"
+			elif echo "$cardinfo" | grep -q Option; then
+				case "$service" in
+					umts_only) CODE=1;;
+					gprs_only) CODE=0;;
+					*) CODE=3;;
+				esac
+				export MODE="AT_OPSYS=${CODE}"
+			elif echo "$cardinfo" | grep -q "Sierra Wireless"; then
+				SIERRA=1
+			elif echo "$cardinfo" | grep -qi huawei; then
+				case "$service" in
+					umts_only) CODE="14,2";;
+					gprs_only) CODE="13,1";;
+					*) CODE="2,2";;
+				esac
+				export MODE="AT^SYSCFG=${CODE},3FFFFFFF,2,4"
+			fi
+
+			if [ -n "$pincode" ]; then
+				PINCODE="$pincode" gcom -d "$device" -s /etc/gcom/setpin.gcom || {
+					proto_notify_error "$interface" PIN_FAILED
+					proto_block_restart "$interface"
+					return 1
+				}
+			fi
+			[ -n "$MODE" ] && gcom -d "$device" -s /etc/gcom/setmode.gcom
+
+			# wait for carrier to avoid firmware stability bugs
+			[ -n "$SIERRA" ] && {
+				gcom -d "$device" -s /etc/gcom/getcarrier.gcom || return 1
+			}
+
+			if [ -z "$dialnumber" ]; then
+				dialnumber="*99***1#"
+			fi
+
+		;;
+	esac
+
+	connect="${apn:+USE_APN=$apn }DIALNUMBER=$dialnumber /usr/sbin/chat -t5 -v -E -f $chat"
+	ppp_generic_setup "$interface" \
+		noaccomp \
+		nopcomp \
+		novj \
+		nobsdcomp \
+		noauth \
+		set EXTENDPREFIX=1 \
+		lock \
+		crtscts \
+		115200 "$device"
+	return 0
+}
+
+proto_3g_teardown() {
+	proto_kill_command "$interface"
+}
+
+[ -z "NOT_INCLUDED" ] || add_protocol 3g
diff --git a/package/network/utils/comgt/files/3g.usb b/package/network/utils/comgt/files/3g.usb
new file mode 100644
index 0000000000..ac8326b710
--- /dev/null
+++ b/package/network/utils/comgt/files/3g.usb
@@ -0,0 +1,33 @@
+#!/bin/sh
+. /lib/functions.sh
+. /lib/netifd/netifd-proto.sh
+
+find_3g_iface() {
+	local cfg="$1"
+	local tty="$2"
+
+	local proto
+	config_get proto "$cfg" proto
+	[ "$proto" = 3g ] || [ "$proto" = ncm ] || return 0
+
+	# bypass state vars here because 00-netstate could clobber .device
+	local dev=$(uci_get network "$cfg" device)
+
+	if [ "${dev##*/}" = "${tty##*/}" ]; then
+		if [ "$ACTION" = add ]; then
+			available=1
+		else
+			available=0
+		fi
+		proto_set_available "$cfg" $available
+	fi
+}
+
+case "$DEVICENAME" in
+	tty*)
+		[ -e "/dev/$DEVICENAME" ] || [ "$ACTION" = remove ] || exit 0
+		config_load network
+		config_foreach find_3g_iface interface "/dev/$DEVICENAME"
+	;;
+esac
+
diff --git a/package/network/utils/comgt/files/directip-stop.gcom b/package/network/utils/comgt/files/directip-stop.gcom
new file mode 100644
index 0000000000..1c14863734
--- /dev/null
+++ b/package/network/utils/comgt/files/directip-stop.gcom
@@ -0,0 +1,16 @@
+opengt
+set com 115200n81
+set comecho off
+set senddelay 0.05
+waitquiet 1 0.2
+
+:start
+ send "AT!SCACT=0,3^m"
+ waitfor 5 "OK"
+ if % = 0 goto hangupok
+ print "WWAN error. Hangup failed.\r\n"
+ exit 1
+
+:hangupok
+ print "WWAN connection established.\r\n"
+ exit 0
diff --git a/package/network/utils/comgt/files/directip.gcom b/package/network/utils/comgt/files/directip.gcom
new file mode 100644
index 0000000000..9a772a90f7
--- /dev/null
+++ b/package/network/utils/comgt/files/directip.gcom
@@ -0,0 +1,55 @@
+opengt
+set com 115200n81
+set comecho off
+set senddelay 0.05
+waitquiet 1 0.2
+
+:start
+ if $env("USE_AUTH") = "0" goto connect
+ send "AT$QCPDPP=3,"
+ send $env("USE_AUTH")
+ send ",\""
+ if $env("USE_USER") <> "" send $env("USE_USER")
+ send "\",\""
+ if $env("USE_PASS") <> "" send $env("USE_PASS")
+ send "\"^m"
+ waitfor 5 "OK"
+ if % = 0 goto connect
+ print "WWAN error. Auth failed.\r\n"
+ exit 1
+
+:connect
+ send "AT+CFUN=1^m"
+ send "AT+CGDCONT=3,\"IP\",\""
+ send $env("USE_APN")
+ send "\"^m"
+ waitfor 5 "OK"
+ if % = 0 goto connok
+ print "WWAN error. Connection failed.\r\n"
+ exit 1
+
+:connok
+ let c=1
+:loop
+ sleep 2
+ send "AT+CGATT?^m"
+ waitfor 5 "+CGATT: 1"
+ if % = 0 goto carrierok
+ if c > 10 goto carriererr
+ inc c
+ goto loop
+
+:carriererr
+ print "WWAN error. No carrier.\r\n"
+ exit 1
+
+:carrierok
+ send "AT!SCACT=1,3^m"
+ waitfor 5 "OK"
+ if % = 0 goto dialok
+ print "WWAN error. Dialing failed.\r\n"
+ exit 1
+
+:dialok
+ print "WWAN connection established.\r\n"
+ exit 0
diff --git a/package/network/utils/comgt/files/directip.sh b/package/network/utils/comgt/files/directip.sh
new file mode 100644
index 0000000000..79b8c32c83
--- /dev/null
+++ b/package/network/utils/comgt/files/directip.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_directip_init_config() {
+	available=1
+	no_device=1
+	proto_config_add_string "device:device"
+	proto_config_add_string "apn"
+	proto_config_add_string "pincode"
+	proto_config_add_string "auth"
+	proto_config_add_string "username"
+	proto_config_add_string "password"
+	proto_config_add_defaults
+}
+
+proto_directip_setup() {
+	local interface="$1"
+	local chat devpath devname
+
+	local device apn pincode ifname auth username password $PROTO_DEFAULT_OPTIONS
+	json_get_vars device apn pincode auth username password $PROTO_DEFAULT_OPTIONS
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	[ -e "$device" ] || {
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	devname="$(basename "$device")"
+	devpath="$(readlink -f /sys/class/tty/$devname/device)"
+	ifname="$( ls "$devpath"/../../*/net )"
+
+	[ -n "$ifname" ] || {
+		proto_notify_error "$interface" NO_IFNAME
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	cardinfo=$(gcom -d "$device" -s /etc/gcom/getcardinfo.gcom)
+	[ -n $(echo "$cardinfo" | grep -q "Sierra Wireless") ] || {
+		proto_notify_error "$interface" BAD_DEVICE
+		proto_block_restart "$interface"
+		return 1
+	}
+
+	if [ -n "$pincode" ]; then
+		PINCODE="$pincode" gcom -d "$device" -s /etc/gcom/setpin.gcom || {
+			proto_notify_error "$interface" PIN_FAILED
+			proto_block_restart "$interface"
+			return 1
+		}
+	fi
+	# wait for carrier to avoid firmware stability bugs
+	gcom -d "$device" -s /etc/gcom/getcarrier.gcom || return 1
+
+	local auth_type=0
+	case $auth in
+	pap) auth_type=1;;
+	chap) auth_type=2;;
+	esac
+
+	USE_APN="$apn" USE_USER="$username" USE_PASS="$password" USE_AUTH="$auth_type" \
+			gcom -d "$device" -s /etc/gcom/directip.gcom || {
+		proto_notify_error "$interface" CONNECT_FAILED
+		proto_block_restart "$interface"
+		return 1
+	}
+
+	logger -p daemon.info -t "directip[$$]" "Connected, starting DHCP"
+	proto_init_update "$ifname" 1
+	proto_send_update "$interface"
+
+	json_init
+	json_add_string name "${interface}_4"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcp"
+	proto_add_dynamic_defaults
+	ubus call network add_dynamic "$(json_dump)"
+
+	json_init
+	json_add_string name "${interface}_6"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcpv6"
+	json_add_string extendprefix 1
+	proto_add_dynamic_defaults
+	ubus call network add_dynamic "$(json_dump)"
+
+	return 0
+}
+
+proto_directip_teardown() {
+	local interface="$1"
+
+	local device
+	json_get_vars device
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	gcom -d "$device" -s /etc/gcom/directip-stop.gcom || proto_notify_error "$interface" CONNECT_FAILED
+
+	proto_init_update "*" 0
+	proto_send_update "$interface"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol directip
+}
diff --git a/package/network/utils/comgt/files/evdo.chat b/package/network/utils/comgt/files/evdo.chat
new file mode 100644
index 0000000000..de49e41a1b
--- /dev/null
+++ b/package/network/utils/comgt/files/evdo.chat
@@ -0,0 +1,17 @@
+# This is a simple chat script based off of the one provided by Sierra Wireless
+# for CDMA connections.  It should work for both Sprint and Verizon networks.
+
+ABORT	BUSY
+ABORT 	'NO CARRIER'
+ABORT	ERROR
+ABORT 	'NO DIAL TONE'
+ABORT 	'NO ANSWER'
+ABORT 	DELAYED
+REPORT	CONNECT
+TIMEOUT	10
+'' 		AT
+OK 		ATZ
+SAY     'Calling CDMA/EVDO'
+TIMEOUT	30
+OK		ATDT#777
+CONNECT	''
diff --git a/package/network/utils/comgt/files/getcardinfo.gcom b/package/network/utils/comgt/files/getcardinfo.gcom
new file mode 100644
index 0000000000..5c69a64604
--- /dev/null
+++ b/package/network/utils/comgt/files/getcardinfo.gcom
@@ -0,0 +1,14 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "ATI^m"
+ get 1 "" $s
+ print $s
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/getcarrier.gcom b/package/network/utils/comgt/files/getcarrier.gcom
new file mode 100644
index 0000000000..1e0216d46a
--- /dev/null
+++ b/package/network/utils/comgt/files/getcarrier.gcom
@@ -0,0 +1,20 @@
+opengt
+  set senddelay 0.05
+  waitquiet 1 0.2
+  let c=1
+ :loop
+    inc c
+    send "AT+CGATT?^m"
+    waitfor 5 "+CGATT: 1","+CGATT: 0"
+    print "\n."
+    if % = -1 goto error
+    if c > 10 goto toolong
+    if % = 0 goto out
+    sleep 2
+    if % = 1 goto loop
+  :toolong
+  exit 1
+  :error
+  exit 0
+  :out
+ exit 0
diff --git a/package/network/utils/comgt/files/getcnum.gcom b/package/network/utils/comgt/files/getcnum.gcom
new file mode 100644
index 0000000000..450cf8c413
--- /dev/null
+++ b/package/network/utils/comgt/files/getcnum.gcom
@@ -0,0 +1,20 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CNUM^m"
+ get 1 "^m" $n
+ get 1 ":" $n
+ get 1 "\"" $n
+ get 1 "\"" $n
+ get 1 "\"" $n
+ get 1 "\"" $n
+ let n = len($n)
+ if n<1 goto continue
+ print $n
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/getimsi.gcom b/package/network/utils/comgt/files/getimsi.gcom
new file mode 100644
index 0000000000..04854561b1
--- /dev/null
+++ b/package/network/utils/comgt/files/getimsi.gcom
@@ -0,0 +1,17 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CIMI^m"
+ get 1 "^m" $s
+ get 1 "^m" $s
+ let x = len($s)
+ if x<2 goto continue
+ let $s = $right($s, x-1)
+ print $s
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/getstrength.gcom b/package/network/utils/comgt/files/getstrength.gcom
new file mode 100644
index 0000000000..2886285971
--- /dev/null
+++ b/package/network/utils/comgt/files/getstrength.gcom
@@ -0,0 +1,14 @@
+opengt
+ set com 115200n81
+ set comecho off
+ set senddelay 0.02
+ waitquiet 0.2 0.2
+ flash 0.1
+
+:start
+ send "AT+CSQ^m"
+ get 1 "" $s
+ print $s
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/ncm.json b/package/network/utils/comgt/files/ncm.json
new file mode 100644
index 0000000000..d1f869974a
--- /dev/null
+++ b/package/network/utils/comgt/files/ncm.json
@@ -0,0 +1,67 @@
+{
+	"huawei": {
+		"initialize": [
+			"AT",
+			"ATZ",
+			"ATQ0",
+			"ATV1",
+			"ATE1",
+			"ATS0=0",
+			"AT+CGDCONT=1,\\\"${pdptype}\\\",\\\"${apn}\\\""
+		],
+		"modes": {
+			"preferlte": "AT^SYSCFGEX=\\\"030201\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"preferumts": "AT^SYSCFGEX=\\\"0201\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"lte": "AT^SYSCFGEX=\\\"03\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"umts": "AT^SYSCFGEX=\\\"02\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"gsm": "AT^SYSCFGEX=\\\"01\\\",3fffffff,2,4,7fffffffffffffff,,",
+			"auto": "AT^SYSCFGEX=\\\"00\\\",3fffffff,2,4,7fffffffffffffff,,"
+		},
+		"connect": "AT^NDISDUP=1,1,\\\"${apn}\\\"${username:+,\\\"$username\\\"}${password:+,\\\"$password\\\"}${auth:+,$auth}",
+		"disconnect": "AT^NDISDUP=1,0"
+	},
+	"samsung": {
+		"initialize": [
+			"AT",
+			"AT+CGREG=2",
+			"AT+CFUN=5",
+			"AT+MODESELECT=3",
+			"AT+CGDCONT=1,\\\"${pdptype}\\\",\\\"${apn}\\\""
+		],
+		"modes": {
+			"umts": "AT+CHANGEALLPATH=1"
+		},
+		"connect": "AT+CGATT=1",
+		"disconnect": "AT+CGATT=0"
+	},
+	"sierra wireless, incorporated": {
+		"initialize": [
+			"AT+CFUN=1",
+			"AT+CGDCONT=1,\\\"${pdptype}\\\",\\\"${apn}\\\"",
+			"AT$QCPDPP=1${auth:+,$auth}${password:+,\\\"$password\\\"}${username:+,\\\"$username\\\"}"
+		],
+		"modes": {
+			"preferlte": "AT!SELRAT=07",
+			"preferumts": "AT!SELRAT=05",
+			"lte": "AT!SELRAT=06",
+			"umts": "AT!SELRAT=01",
+			"gsm": "AT!SELRAT=02",
+			"auto": "AT!SELRAT=00"
+		},
+		"connect": "AT!SCACT=1,1",
+		"disconnect": "AT!SCACT=0,1"
+	},
+	"sony ericsson": {
+		"initialize": [
+			"AT+CFUN=1",
+			"AT+CGDCONT=1,\\\"${pdptype}\\\",\\\"${apn}\\\"",
+			"AT*EIAAUW=1,1,\\\"${username}\\\",\\\"${password}\\\",${auth:-00111}"
+		],
+		"modes": {
+			"umts": "AT+CFUN=6",
+			"gsm": "AT+CFUN=5"
+		},
+		"connect": "AT*ENAP=1,1",
+		"disconnect": "AT*ENAP=0"
+	}
+}
diff --git a/package/network/utils/comgt/files/ncm.sh b/package/network/utils/comgt/files/ncm.sh
new file mode 100644
index 0000000000..14b6347d3f
--- /dev/null
+++ b/package/network/utils/comgt/files/ncm.sh
@@ -0,0 +1,195 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_ncm_init_config() {
+	no_device=1
+	available=1
+	proto_config_add_string "device:device"
+	proto_config_add_string apn
+	proto_config_add_string auth
+	proto_config_add_string username
+	proto_config_add_string password
+	proto_config_add_string pincode
+	proto_config_add_string delay
+	proto_config_add_string mode
+	proto_config_add_string pdptype
+	proto_config_add_boolean ipv6
+	proto_config_add_defaults
+}
+
+proto_ncm_setup() {
+	local interface="$1"
+
+	local manufacturer initialize setmode connect ifname devname devpath
+
+	local device apn auth username password pincode delay mode pdptype ipv6 $PROTO_DEFAULT_OPTIONS
+	json_get_vars device apn auth username password pincode delay mode pdptype ipv6 $PROTO_DEFAULT_OPTIONS
+	
+	if [ "$ipv6" = 0 ]; then
+		ipv6=""
+	else
+		ipv6=1
+	fi
+	
+	[ -z "$pdptype" ] && {
+		if [ -n "$ipv6" ]; then
+			pdptype="IPV4V6"
+		else
+			pdptype="IP"
+		fi
+	}
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	[ -n "$device" ] || {
+		echo "No control device specified"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+	[ -e "$device" ] || {
+		echo "Control device not valid"
+		proto_set_available "$interface" 0
+		return 1
+	}
+	[ -n "$apn" ] || {
+		echo "No APN specified"
+		proto_notify_error "$interface" NO_APN
+		return 1
+	}
+
+	devname="$(basename "$device")"
+	case "$devname" in
+	'tty'*)
+		devpath="$(readlink -f /sys/class/tty/$devname/device)"
+		ifname="$( ls "$devpath"/../../*/net )"
+		;;
+	*)
+		devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
+		ifname="$( ls "$devpath"/net )"
+		;;
+	esac
+	[ -n "$ifname" ] || {
+		echo "The interface could not be found."
+		proto_notify_error "$interface" NO_IFACE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	[ -n "$delay" ] && sleep "$delay"
+
+	manufacturer=`gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | awk '/Manufacturer/ { print tolower($2) }'`
+	[ $? -ne 0 ] && {
+		echo "Failed to get modem information"
+		proto_notify_error "$interface" GETINFO_FAILED
+		return 1
+	}
+
+	json_load "$(cat /etc/gcom/ncm.json)"
+	json_select "$manufacturer"
+	[ $? -ne 0 ] && {
+		echo "Unsupported modem"
+		proto_notify_error "$interface" UNSUPPORTED_MODEM
+		proto_set_available "$interface" 0
+		return 1
+	}
+	json_get_values initialize initialize
+	for i in $initialize; do
+		eval COMMAND="$i" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to initialize modem"
+			proto_notify_error "$interface" INITIALIZE_FAILED
+			return 1
+		}
+	done
+
+	[ -n "$pincode" ] && {
+		PINCODE="$pincode" gcom -d "$device" -s /etc/gcom/setpin.gcom || {
+			echo "Unable to verify PIN"
+			proto_notify_error "$interface" PIN_FAILED
+			proto_block_restart "$interface"
+			return 1
+		}
+	}
+	[ -n "$mode" ] && {
+		json_select modes
+		json_get_var setmode "$mode"
+		eval COMMAND="$setmode" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+			echo "Failed to set operating mode"
+			proto_notify_error "$interface" SETMODE_FAILED
+			return 1
+		}
+		json_select ..
+	}
+
+	json_get_vars connect
+	eval COMMAND="$connect" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+		echo "Failed to connect"
+		proto_notify_error "$interface" CONNECT_FAILED
+		return 1
+	}
+
+	echo "Connected, starting DHCP on $ifname"
+	
+	proto_init_update "$ifname" 1
+	proto_send_update "$interface"
+
+	json_init
+	json_add_string name "${interface}_4"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcp"
+	proto_add_dynamic_defaults
+	ubus call network add_dynamic "$(json_dump)"
+
+	[ -n "$ipv6" ] && {
+		json_init
+		json_add_string name "${interface}_6"
+		json_add_string ifname "@$interface"
+		json_add_string proto "dhcpv6"
+		json_add_string extendprefix 1
+		proto_add_dynamic_defaults
+		ubus call network add_dynamic "$(json_dump)"
+	}
+}
+
+proto_ncm_teardown() {
+	local interface="$1"
+
+	local manufacturer disconnect
+
+	local device
+	json_get_vars device
+
+	echo "Stopping network"
+
+	manufacturer=`gcom -d "$device" -s /etc/gcom/getcardinfo.gcom | awk '/Manufacturer/ { print tolower($2) }'`
+	[ $? -ne 0 ] && {
+		echo "Failed to get modem information"
+		proto_notify_error "$interface" GETINFO_FAILED
+		return 1
+	}
+
+	json_load "$(cat /etc/gcom/ncm.json)"
+	json_select "$manufacturer" || {
+		echo "Unsupported modem"
+		proto_notify_error "$interface" UNSUPPORTED_MODEM
+		return 1
+	}
+
+	json_get_vars disconnect
+	COMMAND="$disconnect" gcom -d "$device" -s /etc/gcom/runcommand.gcom || {
+		echo "Failed to disconnect"
+		proto_notify_error "$interface" DISCONNECT_FAILED
+		return 1
+	}
+
+	proto_init_update "*" 0
+	proto_send_update "$interface"
+}
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol ncm
+}
diff --git a/package/network/utils/comgt/files/runcommand.gcom b/package/network/utils/comgt/files/runcommand.gcom
new file mode 100644
index 0000000000..e99b6f922a
--- /dev/null
+++ b/package/network/utils/comgt/files/runcommand.gcom
@@ -0,0 +1,31 @@
+# run AT-command from environment
+opengt
+ set com 115200n81
+ set senddelay 0.02
+ waitquiet 1 0.2
+ flash 0.1
+
+:start
+ print "sending -> ",$env("COMMAND"),"\n"
+ send $env("COMMAND")
+ send "^m"
+
+ waitfor 15 "OK","ERR","ERROR","COMMAND NOT SUPPORT"
+ if % = 0 goto continue
+ if % = 1 goto error
+ if % = 2 goto error
+ if % = 3 goto notsupported
+
+ print "Timeout running AT-command\n"
+ exit 1
+
+:error
+ print "Error running AT-command\n"
+ exit 1
+
+:notsupported
+ print "AT-command not supported\n"
+ exit 1
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/setmode.gcom b/package/network/utils/comgt/files/setmode.gcom
new file mode 100644
index 0000000000..4ce0b5fa78
--- /dev/null
+++ b/package/network/utils/comgt/files/setmode.gcom
@@ -0,0 +1,26 @@
+# set wwan mode from environment
+opengt
+ set com 115200n81
+ set senddelay 0.02
+ waitquiet 1 0.2
+ flash 0.1
+
+:start
+ print "Trying to set mode\n"
+ send $env("MODE")
+ send "^m"
+
+ waitfor 15 "OK","ERR","ERROR"
+ if % = 0 goto continue
+ if % = 1 goto modeerror
+ if % = 2 goto modeerror
+
+ print "Timeout setting WWAN mode!\n"
+ exit 1
+
+:modeerror
+ print "Error setting WWAN mode!\n"
+ exit 1
+
+:continue
+ exit 0
diff --git a/package/network/utils/comgt/files/setpin.gcom b/package/network/utils/comgt/files/setpin.gcom
new file mode 100644
index 0000000000..66350fe20b
--- /dev/null
+++ b/package/network/utils/comgt/files/setpin.gcom
@@ -0,0 +1,55 @@
+# set pin code from evnironment "$PINCODE"
+opengt
+ set com 115200n81
+ set senddelay 0.05
+ waitquiet 3 0.5
+ flash 0.1
+
+ let c=0
+:start
+ send "AT+CPIN?^m"
+ waitfor 15 "SIM PUK","SIM PIN","READY","ERROR","ERR"
+ if % = -1 goto timeout
+ if % = 0 goto ready
+ if % = 1 goto setpin
+ if % = 2 goto ready
+ if % = 3 goto checkrepeat
+ if % = 4 goto checkrepeat
+
+:checkrepeat
+ inc c
+ if c>3 goto pinerror
+ waitquiet 12 0.5
+ goto start
+
+:timeout
+ print "timeout checking for PIN."
+ exit 1
+
+:ready
+ print "SIM ready\n"
+ goto continue
+ exit 0
+
+:setpin
+ # check if output was "SIM PIN2", that's ok.
+ waitfor 1 "2"
+ if % = 0 goto ready
+
+ print "Trying to set PIN\n"
+ send "AT+CPIN=\""
+ send $env("PINCODE")
+ send "\"^m"
+
+ waitfor 20 "OK","ERR"
+ if % = -1 goto pinerror
+ if % = 0 goto continue
+ if % = 1 goto pinerror
+
+:pinerror
+ print "Error setting PIN, check card manually\n"
+ exit 1
+
+:continue
+ print "PIN set successfully\n"
+ exit 0
diff --git a/package/network/utils/comgt/patches/001-compile_fix.patch b/package/network/utils/comgt/patches/001-compile_fix.patch
new file mode 100644
index 0000000000..15de850b73
--- /dev/null
+++ b/package/network/utils/comgt/patches/001-compile_fix.patch
@@ -0,0 +1,23 @@
+--- a/Makefile
++++ b/Makefile
+@@ -32,6 +32,7 @@ SCRIPTPATH = /etc/comgt/
+ SCRIPTSRC = ./scripts/
+ BIN     = $(CPROG) 
+ MANP	= comgt.1 sigmon.1
++CC	= cc
+ 
+ CFLAGS  = -c
+ LDFLAGS =
+@@ -70,10 +71,5 @@ clean:
+ 	-rm *~
+ 	-rm $(SCRIPTSRC)*~
+ 
+-
+-comgt: comgt.o
+-	cc comgt.o $(LDFLAGS) -o comgt
+-
+-comgt.o: comgt.c comgt.h
+-	cc comgt.c $(CFLAGS) 
+-
++comgt:  comgt.c comgt.h
++	$(CC) $(CFLAGS) -o comgt $< $(LDFLAGS)
diff --git a/package/network/utils/comgt/patches/002-termios.patch b/package/network/utils/comgt/patches/002-termios.patch
new file mode 100644
index 0000000000..08f22d15d9
--- /dev/null
+++ b/package/network/utils/comgt/patches/002-termios.patch
@@ -0,0 +1,105 @@
+--- a/comgt.c
++++ b/comgt.c
+@@ -30,7 +30,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <signal.h>
+-#include <termio.h>
++#include <termios.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <string.h>
+@@ -81,7 +81,7 @@ char token[MAXTOKEN];   /* For gettoken(
+ char scriptfile[MAXPATH]; /* Script file name */
+ char scriptfilepath[MAXPATH]; /* temp storage for full path */
+ BOOL verbose=0; /* Log actions */
+-struct termio cons, stbuf, svbuf;  /* termios: svbuf=before, stbuf=while */
++struct termios cons, stbuf, svbuf;  /* termios: svbuf=before, stbuf=while */
+ int comfd=0; /* Communication file descriptor.  Defaults to stdin. */
+ char msg[STRINGL]; /* Massage messages here */
+ int preturn,returns[MAXGOSUBS];
+@@ -172,7 +172,7 @@ void dotestkey(void) {
+ 
+ /* Exit after resetting terminal settings */
+ void ext(long xtc) {
+-  ioctl(1, TCSETA, &cons);
++  ioctl(1, TCSETS, &cons);
+   exit(xtc);
+ }
+ 
+@@ -920,24 +920,24 @@ BOOL getonoroff(void) {
+ void setcom(void) {
+   stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
+   stbuf.c_cflag |= (speed | bits | CREAD | clocal | parity | stopbits );
+-  if (ioctl(comfd, TCSETA, &stbuf) < 0) {
++  if (ioctl(comfd, TCSETS, &stbuf) < 0) {
+     serror("Can't ioctl set device",1);
+   }
+ }
+ 
+ void doset(void) {
+-  struct termio console;
++  struct termios console;
+   int a,b;
+   gettoken();
+   if(strcmp(token,"echo")==0) {
+     a=0;
+     if(getonoroff()) a=ECHO|ECHOE;
+-    if(ioctl(0, TCGETA, &console)<0) {
++    if(ioctl(0, TCGETS, &console)<0) {
+       serror("Can't ioctl FD zero!\n",2);
+     }
+     console.c_lflag &= ~(ECHO | ECHOE);
+     console.c_lflag |= a;
+-    ioctl(0, TCSETA, &console);
++    ioctl(0, TCSETS, &console);
+   }
+   else if(strcmp(token,"senddelay")==0) {
+     senddelay=10000L*getdvalue();
+@@ -1224,7 +1224,7 @@ void doclose(void) {
+   if(strcmp(token,"hardcom")==0) {
+     if(comfd== -1) serror("Com device not open",1);
+     vmsg("Closing device");
+-    if (ioctl(comfd, TCSETA, &svbuf) < 0) {
++    if (ioctl(comfd, TCSETS, &svbuf) < 0) {
+       sprintf(msg,"Can't ioctl set device %s.\n",device);
+       serror(msg,1);
+     }
+@@ -1266,12 +1266,12 @@ void opengt(void) {
+       ext(1);
+     }
+   }
+-  if (ioctl (comfd, TCGETA, &svbuf) < 0) {
++  if (ioctl (comfd, TCGETS, &svbuf) < 0) {
+     sprintf(msg,"Can't control %s, please try again.\n",device);
+     serror(msg,1);
+   }
+   setenv("COMGTDEVICE",device,1);
+-  ioctl(comfd, TCGETA, &stbuf);
++  ioctl(comfd, TCGETS, &stbuf);
+   speed=stbuf.c_cflag & CBAUD;
+   if (high_speed == 0)  strcpy(cspeed,"115200");
+   else strcpy(cspeed,"57600");
+@@ -1303,11 +1303,11 @@ void opendevice(void) {
+   }
+   else comfd=0;
+ 
+-  if (ioctl (comfd, TCGETA, &svbuf) < 0) {
++  if (ioctl (comfd, TCGETS, &svbuf) < 0) {
+     sprintf(msg,"Can't ioctl get device %s.\n",device);
+     serror(msg,1);
+   }
+-  ioctl(comfd, TCGETA, &stbuf);
++  ioctl(comfd, TCGETS, &stbuf);
+   speed=stbuf.c_cflag & CBAUD;
+   switch(speed) {
+     case B0: strcpy(cspeed,"0");break;
+@@ -1553,7 +1553,7 @@ int main(int argc,char **argv) {
+   skip_default=0;
+   filep=NULL;
+   scriptspace=4096;
+-  ioctl(1, TCGETA, &cons);
++  ioctl(1, TCGETS, &cons);
+   if((script=( char *)malloc(scriptspace))==NULL) {
+     serror("Could not malloc()",3);
+   }
diff --git a/package/network/utils/comgt/patches/003-no_XCASE.patch b/package/network/utils/comgt/patches/003-no_XCASE.patch
new file mode 100644
index 0000000000..f2060a8288
--- /dev/null
+++ b/package/network/utils/comgt/patches/003-no_XCASE.patch
@@ -0,0 +1,20 @@
+--- a/comgt.c
++++ b/comgt.c
+@@ -1281,7 +1281,7 @@ void opengt(void) {
+   parity=stbuf.c_cflag & (PARENB | PARODD);
+   stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
+   stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
+-  stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
++  stbuf.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL);
+   stbuf.c_lflag &= ~(ECHO | ECHOE);
+   stbuf.c_cc[VMIN] = 1;
+   stbuf.c_cc[VTIME] = 0;
+@@ -1336,7 +1336,7 @@ void opendevice(void) {
+   parity=stbuf.c_cflag & (PARENB | PARODD);
+   stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
+   stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
+-  stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
++  stbuf.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL);
+   stbuf.c_lflag &= ~(ECHO | ECHOE);
+   stbuf.c_cc[VMIN] = 1;
+   stbuf.c_cc[VTIME] = 0;
diff --git a/package/network/utils/comgt/patches/004-check_tty.patch b/package/network/utils/comgt/patches/004-check_tty.patch
new file mode 100644
index 0000000000..fb1d9af4bb
--- /dev/null
+++ b/package/network/utils/comgt/patches/004-check_tty.patch
@@ -0,0 +1,68 @@
+--- a/comgt.c
++++ b/comgt.c
+@@ -91,6 +91,7 @@ unsigned long hstart,hset;
+ char NullString[]={ "" };
+ BOOL lastcharnl=1; /* Indicate that last char printed from getonebyte
+                                was a nl, so no new one is needed */
++BOOL tty=1;
+ 
+ 
+ //"open com \"/dev/modem\"\nset com 38400n81\nset senddelay 0.05\nsend \"ATi^m\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response :\",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\n\n";
+@@ -920,7 +921,7 @@ BOOL getonoroff(void) {
+ void setcom(void) {
+   stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
+   stbuf.c_cflag |= (speed | bits | CREAD | clocal | parity | stopbits );
+-  if (ioctl(comfd, TCSETS, &stbuf) < 0) {
++  if (tty && ioctl(comfd, TCSETS, &stbuf) < 0) {
+     serror("Can't ioctl set device",1);
+   }
+ }
+@@ -1224,7 +1225,7 @@ void doclose(void) {
+   if(strcmp(token,"hardcom")==0) {
+     if(comfd== -1) serror("Com device not open",1);
+     vmsg("Closing device");
+-    if (ioctl(comfd, TCSETS, &svbuf) < 0) {
++    if (tty && ioctl(comfd, TCSETS, &svbuf) < 0) {
+       sprintf(msg,"Can't ioctl set device %s.\n",device);
+       serror(msg,1);
+     }
+@@ -1266,12 +1267,17 @@ void opengt(void) {
+       ext(1);
+     }
+   }
+-  if (ioctl (comfd, TCGETS, &svbuf) < 0) {
++  if (isatty (comfd))
++    tty=1;
++  else
++    tty=0;
++  if (tty && ioctl (comfd, TCGETS, &svbuf) < 0) {
+     sprintf(msg,"Can't control %s, please try again.\n",device);
+     serror(msg,1);
+   }
+   setenv("COMGTDEVICE",device,1);
+-  ioctl(comfd, TCGETS, &stbuf);
++  if (tty)
++    ioctl(comfd, TCGETS, &stbuf);
+   speed=stbuf.c_cflag & CBAUD;
+   if (high_speed == 0)  strcpy(cspeed,"115200");
+   else strcpy(cspeed,"57600");
+@@ -1302,12 +1308,16 @@ void opendevice(void) {
+     }
+   }
+   else comfd=0;
+-
+-  if (ioctl (comfd, TCGETS, &svbuf) < 0) {
++  if (isatty (comfd))
++    tty=1;
++  else
++    tty=0;
++  if (tty && ioctl (comfd, TCGETS, &svbuf) < 0) {
+     sprintf(msg,"Can't ioctl get device %s.\n",device);
+     serror(msg,1);
+   }
+-  ioctl(comfd, TCGETS, &stbuf);
++  if (tty)
++    ioctl(comfd, TCGETS, &stbuf);
+   speed=stbuf.c_cflag & CBAUD;
+   switch(speed) {
+     case B0: strcpy(cspeed,"0");break;
diff --git a/package/network/utils/conntrack-tools/Makefile b/package/network/utils/conntrack-tools/Makefile
new file mode 100644
index 0000000000..95257c6c67
--- /dev/null
+++ b/package/network/utils/conntrack-tools/Makefile
@@ -0,0 +1,80 @@
+#
+# Copyright (C) 2009-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=conntrack-tools
+PKG_VERSION:=1.4.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+	http://www.netfilter.org/projects/conntrack-tools/files \
+	ftp://ftp.netfilter.org/pub/conntrack-tools \
+	http://mirrors.evolva.ro/netfilter.org/conntrack-tools
+PKG_MD5SUM:=b7caf4fcc4c03575df57d25e5216584d597fd916c891f191dac616ce68bdba6c
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+PKG_BUILD_DEPENDS:=librpc
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/conntrack-tools/default
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libnetfilter-conntrack +libnetfilter-cttimeout +libnetfilter-cthelper +libnetfilter-queue
+  SUBMENU:=Firewall
+  URL:=http://conntrack-tools.netfilter.org/
+endef
+
+define Package/conntrack
+$(call Package/conntrack-tools/default)
+  TITLE:=Connection tracking tool
+endef
+
+define Package/conntrack/description
+ Conntrack is a userspace command line program targeted at system
+ administrators. It enables them to view and manage the in-kernel
+ connection tracking state table.
+endef
+
+define Package/conntrack/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/conntrack $(1)/usr/sbin/
+endef
+
+define Package/conntrackd
+$(call Package/conntrack-tools/default)
+  TITLE:=Connection tracking daemon
+endef
+
+define Package/conntrackd/conffiles
+/etc/conntrackd/
+endef
+
+define Package/conntrackd/description
+ Conntrackd can replicate the status of the connections that are
+ currently being processed by your stateful firewall based on Linux.
+ Conntrackd can also run as statistics daemon.
+endef
+
+define Package/conntrackd/install
+	$(INSTALL_DIR) \
+		$(1)/etc/conntrackd \
+		$(1)/etc/init.d \
+		$(1)/usr/sbin
+	$(INSTALL_BIN) 	$(PKG_INSTALL_DIR)/usr/sbin/conntrackd $(1)/usr/sbin/
+	$(INSTALL_BIN) ./files/conntrackd.init $(1)/etc/init.d/conntrackd
+endef
+
+$(eval $(call BuildPackage,conntrack))
+$(eval $(call BuildPackage,conntrackd))
diff --git a/package/network/utils/conntrack-tools/files/conntrackd.init b/package/network/utils/conntrack-tools/files/conntrackd.init
new file mode 100644
index 0000000000..0e2945c9a5
--- /dev/null
+++ b/package/network/utils/conntrack-tools/files/conntrackd.init
@@ -0,0 +1,18 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2015 OpenWrt.org
+
+START=21
+STOP=89
+
+USE_PROCD=1
+PROG="/usr/sbin/conntrackd"
+
+start_service() {
+	[ -e /etc/conntrackd/conntrackd.conf ] || return
+	procd_open_instance
+
+	procd_set_param command $PROG -C /etc/conntrackd/conntrackd.conf
+	procd_set_param respawn
+
+	procd_close_instance
+}
diff --git a/package/network/utils/curl/Config.in b/package/network/utils/curl/Config.in
new file mode 100644
index 0000000000..1e98b3a598
--- /dev/null
+++ b/package/network/utils/curl/Config.in
@@ -0,0 +1,159 @@
+if PACKAGE_libcurl
+
+comment "SSL support"
+
+choice
+	prompt "Selected SSL library"
+	default LIBCURL_POLARSSL
+
+	config LIBCURL_POLARSSL
+		bool "PolarSSL"
+
+	config LIBCURL_MBEDTLS
+		bool "mbed TLS"
+
+	config LIBCURL_CYASSL
+		bool "CyaSSL"
+
+	config LIBCURL_OPENSSL
+		bool "OpenSSL"
+
+	config LIBCURL_GNUTLS
+		bool "GNUTLS"
+
+	config LIBCURL_NOSSL
+		bool "No SSL support"
+
+endchoice
+
+comment "Supported protocols"
+
+config LIBCURL_DICT
+	bool "DICT protocol"
+	default n
+
+config LIBCURL_FILE
+	bool "FILE protocol"
+	default y
+
+config LIBCURL_FTP
+	bool "FTP / FTPS protocol"
+	default y
+
+config LIBCURL_GOPHER
+	bool "Gopher protocol"
+	default n
+
+config LIBCURL_HTTP
+	bool "HTTP / HTTPS protocol"
+	default y
+
+config LIBCURL_COOKIES
+	bool "Enable Cookies support"
+	depends on LIBCURL_HTTP
+	default y
+
+config LIBCURL_IMAP
+	bool "IMAP / IMAPS protocol"
+	default n
+
+config LIBCURL_LDAP
+	bool "LDAP protocol"
+	default n
+
+config LIBCURL_LDAPS
+	bool "Enable LDAPS support"
+	depends on LIBCURL_LDAP && !LIBCURL_NOSSL
+	default y
+
+config LIBCURL_POP3
+	bool "POP3 / POP3S protocol"
+	default n
+
+config LIBCURL_RTSP
+	bool "RTSP protocol"
+	depends on LIBCURL_HTTP
+	default n
+config LIBCURL_NO_RTSP
+	string "RTSP require HTTP protocol"
+	depends on !LIBCURL_HTTP
+	default "!"
+
+config LIBCURL_SSH2
+	bool "SCP / SFTP protocol"
+	default n
+
+config LIBCURL_SMB
+	bool "SMB protocol (CIFS)"
+	depends on LIBCURL_CRYPTO_AUTH && (LIBCURL_GNUTLS || LIBCURL_OPENSSL)
+	default n
+config LIBCURL_NO_SMB
+	string "SMB require 'cryptographic authentication' and either 'GnuTLS' or 'OpenSSL'"
+	depends on !LIBCURL_CRYPTO_AUTH || (!LIBCURL_GNUTLS && !LIBCURL_OPENSSL)
+	default "!"
+
+config LIBCURL_SMTP
+	bool "SMTP / SMTPS protocol"
+	default n
+
+config LIBCURL_TELNET
+	bool "TELNET protocol"
+	default n
+
+config LIBCURL_TFTP
+	bool "TFTP protocol"
+	default n
+
+comment "Miscellaneous"
+
+config LIBCURL_PROXY
+	bool "Enable proxy support"
+	default y
+
+config LIBCURL_CRYPTO_AUTH
+	bool "Enable cryptographic authentication"
+	default n
+
+config LIBCURL_TLS_SRP
+	bool "Enable TLS-SRP authentication"
+	default n
+
+config LIBCURL_LIBIDN
+	bool "Enable IDN support"
+	default n
+
+config LIBCURL_THREADED_RESOLVER
+	bool "Enable threaded DNS resolver"
+	default n
+	help
+		Enable POSIX threaded asynchronous DNS resolution
+
+config LIBCURL_ZLIB
+	bool "Enable zlib support"
+	default n
+
+config LIBCURL_UNIX_SOCKETS
+	bool "Enable unix domain socket support"
+	default n
+	help
+		Enable HTTP over unix domain sockets.
+		To use this with the curl command line, you specify the socket path to the new --unix-domain option.
+		This feature is actually not limited to HTTP, you can do all the TCP-based protocols 
+		except FTP over the unix domain socket, but it is only HTTP that is regularly used this way. 
+		The reason FTP isn't supported is of course its use of two connections 
+		which would be even weirder to do like this.
+
+config LIBCURL_LIBCURL_OPTION
+	bool "Enable generation of C code"
+	default n
+
+config LIBCURL_VERBOSE
+	bool "Enable verbose error strings"
+	default n
+
+config LIBCURL_NTLM
+	bool "Enable NTLM support"
+	depends on LIBCURL_CRYPTO_AUTH && !LIBCURL_NOSSL
+	default n
+
+endif
diff --git a/package/network/utils/curl/Makefile b/package/network/utils/curl/Makefile
new file mode 100644
index 0000000000..d1e8097602
--- /dev/null
+++ b/package/network/utils/curl/Makefile
@@ -0,0 +1,180 @@
+#
+# Copyright (C) 2007-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=curl
+PKG_VERSION:=7.51.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://curl.haxx.se/download/ \
+	http://www.mirrorspace.org/curl/ \
+	ftp://ftp.sunet.se/pub/www/utilities/curl/ \
+	ftp://ftp.planetmirror.com/pub/curl/ \
+	http://www.mirrormonster.com/curl/download/ \
+	http://curl.mirrors.cyberservers.net/download/
+PKG_MD5SUM:=7f8240048907e5030f67be0a6129bc4b333783b9cca1391026d700835a788dde
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=COPYING
+
+PKG_FIXUP:=autoreconf
+PKG_BUILD_PARALLEL:=1
+
+PKG_CONFIG_DEPENDS:= \
+  CONFIG_IPV6 \
+  \
+  CONFIG_LIBCURL_CYASSL \
+  CONFIG_LIBCURL_GNUTLS \
+  CONFIG_LIBCURL_OPENSSL \
+  CONFIG_LIBCURL_POLARSSL \
+  CONFIG_LIBCURL_MBEDTLS \
+  CONFIG_LIBCURL_NOSSL \
+  \
+  CONFIG_LIBCURL_LIBIDN \
+  CONFIG_LIBCURL_SSH2 \
+  CONFIG_LIBCURL_ZLIB \
+  \
+  CONFIG_LIBCURL_DICT \
+  CONFIG_LIBCURL_FILE \
+  CONFIG_LIBCURL_FTP \
+  CONFIG_LIBCURL_GOPHER \
+  CONFIG_LIBCURL_HTTP \
+  CONFIG_LIBCURL_IMAP \
+  CONFIG_LIBCURL_LDAP \
+  CONFIG_LIBCURL_LDAPS \
+  CONFIG_LIBCURL_POP3 \
+  CONFIG_LIBCURL_RTSP \
+  CONFIG_LIBCURL_NO_RTSP \
+  CONFIG_LIBCURL_SMB \
+  CONFIG_LIBCURL_NO_SMB \
+  CONFIG_LIBCURL_SMTP \
+  CONFIG_LIBCURL_TELNET \
+  CONFIG_LIBCURL_TFTP \
+  \
+  CONFIG_LIBCURL_COOKIES \
+  CONFIG_LIBCURL_CRYPTO_AUTH \
+  CONFIG_LIBCURL_LIBCURL_OPTION \
+  CONFIG_LIBCURL_PROXY \
+  CONFIG_LIBCURL_THREADED_RESOLVER \
+  CONFIG_LIBCURL_TLS_SRP \
+  CONFIG_LIBCURL_UNIX_SOCKETS \
+  CONFIG_LIBCURL_VERBOSE \
+  CONFIG_LIBCURL_NTLM
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/curl/Default
+  SECTION:=net
+  CATEGORY:=Network
+  URL:=http://curl.haxx.se/
+  MAINTAINER:=Imre Kaloz <kaloz@openwrt.org>
+endef
+
+define Package/curl
+  $(call Package/curl/Default)
+  SUBMENU:=File Transfer
+  DEPENDS:=+libcurl
+  TITLE:=A client-side URL transfer utility
+endef
+
+define Package/libcurl
+  $(call Package/curl/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+LIBCURL_POLARSSL:libpolarssl +LIBCURL_CYASSL:libcyassl +LIBCURL_OPENSSL:libopenssl +LIBCURL_GNUTLS:libgnutls +LIBCURL_MBEDTLS:libmbedtls
+  DEPENDS += +LIBCURL_ZLIB:zlib +LIBCURL_THREADED_RESOLVER:libpthread +LIBCURL_LDAP:libopenldap +LIBCURL_LIBIDN:libidn +LIBCURL_SSH2:libssh2
+  TITLE:=A client-side URL transfer library
+  MENU:=1
+endef
+
+
+define Package/libcurl/config
+  source "$(SOURCE)/Config.in"
+endef
+
+TARGET_CFLAGS += $(FPIC) -ffunction-sections -fdata-sections
+TARGET_CPPFLAGS += $(if $(CONFIG_LIBCURL_NTLM),,-DCURL_DISABLE_NTLM)
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+CONFIGURE_ARGS += \
+	--disable-debug \
+	--disable-ares \
+	--enable-shared \
+	--enable-static \
+	--disable-manual \
+	--without-nss \
+	--without-libmetalink \
+	--without-librtmp \
+	\
+	$(call autoconf_bool,CONFIG_IPV6,ipv6) \
+	\
+	$(if $(CONFIG_LIBCURL_CYASSL),--with-cyassl="$(STAGING_DIR)/usr" --without-ca-path --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt,--without-cyassl) \
+	$(if $(CONFIG_LIBCURL_GNUTLS),--with-gnutls="$(STAGING_DIR)/usr" --without-ca-bundle --with-ca-path=/etc/ssl/certs,--without-gnutls) \
+	$(if $(CONFIG_LIBCURL_OPENSSL),--with-ssl="$(STAGING_DIR)/usr" --without-ca-bundle --with-ca-path=/etc/ssl/certs,--without-ssl) \
+	$(if $(CONFIG_LIBCURL_POLARSSL),--with-polarssl="$(STAGING_DIR)/usr" --without-ca-bundle --with-ca-path=/etc/ssl/certs,--without-polarssl) \
+	$(if $(CONFIG_LIBCURL_MBEDTLS),--with-mbedtls="$(STAGING_DIR)/usr" --without-ca-path --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt,--without-mbedtls) \
+	\
+	$(if $(CONFIG_LIBCURL_LIBIDN),--with-libidn="$(STAGING_DIR)/usr",--without-libidn) \
+	$(if $(CONFIG_LIBCURL_SSH2),--with-libssh2="$(STAGING_DIR)/usr",--without-libssh2) \
+	$(if $(CONFIG_LIBCURL_ZLIB),--with-zlib="$(STAGING_DIR)/usr",--without-zlib) \
+	\
+	$(call autoconf_bool,CONFIG_LIBCURL_DICT,dict) \
+	$(call autoconf_bool,CONFIG_LIBCURL_FILE,file) \
+	$(call autoconf_bool,CONFIG_LIBCURL_FTP,ftp) \
+	$(call autoconf_bool,CONFIG_LIBCURL_GOPHER,gopher) \
+	$(call autoconf_bool,CONFIG_LIBCURL_HTTP,http) \
+	$(call autoconf_bool,CONFIG_LIBCURL_IMAP,imap) \
+	$(call autoconf_bool,CONFIG_LIBCURL_LDAP,ldap) \
+	$(call autoconf_bool,CONFIG_LIBCURL_LDAPS,ldaps) \
+	$(call autoconf_bool,CONFIG_LIBCURL_POP3,pop3) \
+	$(call autoconf_bool,CONFIG_LIBCURL_RTSP,rtsp) \
+	$(call autoconf_bool,CONFIG_LIBCURL_SMB,smb) \
+	$(call autoconf_bool,CONFIG_LIBCURL_SMTP,smtp) \
+	$(call autoconf_bool,CONFIG_LIBCURL_TELNET,telnet) \
+	$(call autoconf_bool,CONFIG_LIBCURL_TFTP,tftp) \
+	\
+	$(call autoconf_bool,CONFIG_LIBCURL_COOKIES,cookies) \
+	$(call autoconf_bool,CONFIG_LIBCURL_CRYPTO_AUTH,crypto-auth) \
+	$(call autoconf_bool,CONFIG_LIBCURL_LIBCURL_OPTION,libcurl-option) \
+	$(call autoconf_bool,CONFIG_LIBCURL_PROXY,proxy) \
+	$(call autoconf_bool,CONFIG_LIBCURL_THREADED_RESOLVER,threaded-resolver) \
+	$(call autoconf_bool,CONFIG_LIBCURL_TLS_SRP,tls-srp) \
+	$(call autoconf_bool,CONFIG_LIBCURL_UNIX_SOCKETS,unix-sockets) \
+	$(call autoconf_bool,CONFIG_LIBCURL_VERBOSE,verbose) \
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		CC="$(TARGET_CC)" \
+		install
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(2)/bin $(1)/usr/bin $(1)/usr/include $(1)/usr/lib $(1)/usr/lib/pkgconfig
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/curl-config $(1)/usr/bin/
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/curl $(1)/usr/include/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libcurl.{a,so*} $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/libcurl.pc $(1)/usr/lib/pkgconfig/
+	$(SED) 's,-L$$$${exec_prefix}/lib,,g' $(1)/usr/bin/curl-config
+	[ -n "$(TARGET_LDFLAGS)" ] && $(SED) 's#$(TARGET_LDFLAGS)##g' $(1)/usr/lib/pkgconfig/libcurl.pc || true
+	$(LN) $(STAGING_DIR)/usr/bin/curl-config $(2)/bin/
+endef
+
+define Package/curl/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/curl $(1)/usr/bin/
+endef
+
+define Package/libcurl/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libcurl.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,curl))
+$(eval $(call BuildPackage,libcurl))
diff --git a/package/network/utils/curl/patches/200-no_docs_tests.patch b/package/network/utils/curl/patches/200-no_docs_tests.patch
new file mode 100644
index 0000000000..139c05e64b
--- /dev/null
+++ b/package/network/utils/curl/patches/200-no_docs_tests.patch
@@ -0,0 +1,22 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -153,7 +153,7 @@ CLEANFILES = $(VC6_LIBDSP) $(VC6_SRCDSP)
+ bin_SCRIPTS = curl-config
+ 
+ SUBDIRS = lib src include
+-DIST_SUBDIRS = $(SUBDIRS) tests packages docs scripts
++DIST_SUBDIRS = $(SUBDIRS) packages
+ 
+ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = libcurl.pc
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -613,7 +613,7 @@ CLEANFILES = $(VC6_LIBDSP) $(VC6_SRCDSP)
+ 
+ bin_SCRIPTS = curl-config
+ SUBDIRS = lib src include
+-DIST_SUBDIRS = $(SUBDIRS) tests packages docs scripts
++DIST_SUBDIRS = $(SUBDIRS) packages
+ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = libcurl.pc
+ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c         \
diff --git a/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch b/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch
new file mode 100644
index 0000000000..a26caa8571
--- /dev/null
+++ b/package/network/utils/curl/patches/310-polarssl-disable-runtime-version-check.patch
@@ -0,0 +1,22 @@
+--- a/lib/vtls/polarssl.c
++++ b/lib/vtls/polarssl.c
+@@ -646,7 +646,7 @@ void Curl_polarssl_session_free(void *pt
+ 
+ size_t Curl_polarssl_version(char *buffer, size_t size)
+ {
+-  unsigned int version = version_get_number();
++  unsigned int version = POLARSSL_VERSION_NUMBER;
+   return snprintf(buffer, size, "%s/%d.%d.%d",
+                   version >= 0x01030A00?"mbedTLS":"PolarSSL",
+                   version>>24, (version>>16)&0xff, (version>>8)&0xff);
+--- a/lib/vtls/mbedtls.c
++++ b/lib/vtls/mbedtls.c
+@@ -712,7 +712,7 @@ void Curl_mbedtls_session_free(void *ptr
+ 
+ size_t Curl_mbedtls_version(char *buffer, size_t size)
+ {
+-  unsigned int version = mbedtls_version_get_number();
++  unsigned int version = MBEDTLS_VERSION_NUMBER;
+   return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
+                   (version>>16)&0xff, (version>>8)&0xff);
+ }
diff --git a/package/network/utils/dante/Makefile b/package/network/utils/dante/Makefile
new file mode 100644
index 0000000000..a78c40dbde
--- /dev/null
+++ b/package/network/utils/dante/Makefile
@@ -0,0 +1,116 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dante
+PKG_VERSION:=1.4.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.inet.no/dante/files/
+PKG_MD5SUM:=68c2ce12119e12cea11a90c7a80efa8f
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=BSD-4-Clause
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+CONFIGURE_ARGS += \
+	--without-upnp \
+	--without-pam \
+	--disable-libwrap
+
+CONFIGURE_VARS += \
+	ac_cv_search_pam_start=""
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/*.{a,so*,la} $(1)/usr/lib/
+endef
+
+
+define Package/dante/default
+  TITLE:=Dante SOCKS
+  URL:=http://www.inet.no/dante/
+endef
+
+define Package/dante/default/description
+Dante is a circuit-level firewall/proxy that can be used to provide convenient
+and secure network connectivity, requiring only that the server Dante runs on
+has external network connectivity. Dante is used daily by Fortune 100 companies
+and large international organizations, either as a standard SOCKS server or as
+a "reverse proxy". 
+endef
+
+define Package/libsocks
+  $(call Package/dante/default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= Library
+endef
+
+define Package/libsocks/description
+$(call Package/dante/default/description)
+This package provides the shared libsocks library.
+endef
+
+define Package/libsocks/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libsocks.so* $(1)/usr/lib/
+endef
+
+
+define Package/sockd
+  $(call Package/dante/default)
+  SUBMENU:=Web Servers/Proxies
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE+= Daemon
+endef
+
+define Package/sockd/description
+$(call Package/dante/default/description)
+This package provides the Dante sockd daemon.
+endef
+
+define Package/sockd/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/sockd $(1)/usr/sbin/
+endef
+
+
+define Package/socksify
+  $(call Package/dante/default)
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Web Servers/Proxies
+  TITLE+= Client
+endef
+
+define Package/socksify/description
+$(call Package/dante/default/description)
+This package provides the Dante socksify client.
+endef
+
+define Package/socksify/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/socksify $(1)/usr/bin/
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libdsocks.so* $(1)/usr/lib/
+endef
+
+
+$(eval $(call BuildPackage,libsocks))
+$(eval $(call BuildPackage,sockd))
+$(eval $(call BuildPackage,socksify))
diff --git a/package/network/utils/dante/patches/200-fix-RTLD_NEXT.patch b/package/network/utils/dante/patches/200-fix-RTLD_NEXT.patch
new file mode 100644
index 0000000000..594a6f900b
--- /dev/null
+++ b/package/network/utils/dante/patches/200-fix-RTLD_NEXT.patch
@@ -0,0 +1,36 @@
+--- a/lib/address.c
++++ b/lib/address.c
+@@ -48,11 +48,12 @@
+ 
+ #include "upnp.h"
+ 
+-#ifndef __USE_GNU
+-#define __USE_GNU /* XXX for RTLD_NEXT on Linux */
+-#endif /* !__USE_GNU */
+ #include <dlfcn.h>
+ 
++#ifndef RTLD_NEXT
++#define RTLD_NEXT  ((void *) -1l)
++#endif
++
+ static const char rcsid[] =
+ "$Id: address.c,v 1.288.4.4 2014/08/15 18:16:40 karls Exp $";
+ 
+--- a/dlib/interposition.c
++++ b/dlib/interposition.c
+@@ -93,11 +93,12 @@ write$NOCANCEL(HAVE_PROT_WRITE_1, HAVE_P
+ 
+ #endif /* HAVE_DARWIN */
+ 
+-#ifndef __USE_GNU
+-#define __USE_GNU /* XXX for RTLD_NEXT on Linux */
+-#endif /* !__USE_GNU */
+ #include <dlfcn.h>
+ 
++#ifndef RTLD_NEXT
++#define RTLD_NEXT  ((void *) -1l)
++#endif
++
+ #ifdef __COVERITY__
+ /*
+  * Coverity naturally has no idea what the function sys_foo calls does,
diff --git a/package/network/utils/ebtables/Makefile b/package/network/utils/ebtables/Makefile
new file mode 100644
index 0000000000..78b83b817b
--- /dev/null
+++ b/package/network/utils/ebtables/Makefile
@@ -0,0 +1,72 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ebtables
+PKG_VERSION:=2.0.10-4
+PKG_RELEASE:=5
+
+PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/ebtables
+PKG_MD5SUM:=506742a3d44b9925955425a659c1a8d0
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/ebtables-v$(PKG_VERSION)
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ebtables
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Firewall
+  DEPENDS:=+kmod-ebtables
+  TITLE:=Ethernet bridge firewall administration utility
+  URL:=http://ebtables.sourceforge.net/
+endef
+
+define Package/ebtables-utils
+  $(call Package/ebtables)
+  DEPENDS += ebtables
+  TITLE:=ebtables save/restore utilities
+endef
+
+define Package/ebtables/description
+	The ebtables program is a filtering tool for a bridging firewall. The
+	filtering is focussed on the Link Layer Ethernet frame fields. Apart
+	from filtering, it also gives the ability to alter the Ethernet MAC
+	addresses and implement a brouter.
+endef
+
+define Package/ebtables-utils/description
+	$(call Package/ebtables/description)
+endef
+
+MAKE_VARS += EXT_LIBSI="$(LIBGCC_S)"
+
+MAKE_FLAGS += \
+	CFLAGS="$(TARGET_CFLAGS)" \
+	LIBDIR="/usr/lib/ebtables"
+
+define Package/ebtables/install
+	$(INSTALL_DIR) $(1)/etc
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/ethertypes $(1)/etc/
+	$(INSTALL_DIR) $(1)/usr/lib/ebtables
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/lib*.so $(1)/usr/lib/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/extensions/*.so $(1)/usr/lib/ebtables/
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables $(1)/usr/sbin/
+endef
+
+define Package/ebtables-utils/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables-save $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ebtables-restore $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,ebtables))
+$(eval $(call BuildPackage,ebtables-utils))
diff --git a/package/network/utils/ebtables/patches/100-musl_fix.patch b/package/network/utils/ebtables/patches/100-musl_fix.patch
new file mode 100644
index 0000000000..0ac1fbfecf
--- /dev/null
+++ b/package/network/utils/ebtables/patches/100-musl_fix.patch
@@ -0,0 +1,181 @@
+--- a/extensions/ebt_among.c
++++ b/extensions/ebt_among.c
+@@ -13,7 +13,6 @@
+ #include <ctype.h>
+ #include <unistd.h>
+ #include "../include/ebtables_u.h"
+-#include <netinet/ether.h>
+ #include "../include/ethernetdb.h"
+ #include <linux/if_ether.h>
+ #include <linux/netfilter_bridge/ebt_among.h>
+--- a/extensions/ebt_arpreply.c
++++ b/extensions/ebt_arpreply.c
+@@ -12,7 +12,6 @@
+ #include <string.h>
+ #include <getopt.h>
+ #include "../include/ebtables_u.h"
+-#include <netinet/ether.h>
+ #include <linux/netfilter_bridge/ebt_arpreply.h>
+ 
+ static int mac_supplied;
+--- a/extensions/ebt_nat.c
++++ b/extensions/ebt_nat.c
+@@ -11,7 +11,6 @@
+ #include <string.h>
+ #include <getopt.h>
+ #include "../include/ebtables_u.h"
+-#include <netinet/ether.h>
+ #include <linux/netfilter_bridge/ebt_nat.h>
+ 
+ static int to_source_supplied, to_dest_supplied;
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -25,7 +25,6 @@
+ #include "include/ebtables_u.h"
+ #include "include/ethernetdb.h"
+ #include <stdio.h>
+-#include <netinet/ether.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <getopt.h>
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -23,7 +23,9 @@
+ 
+ #ifndef EBTABLES_U_H
+ #define EBTABLES_U_H
++#include <sys/types.h>
+ #include <netinet/in.h>
++#include <netinet/ether.h>
+ #include <linux/netfilter_bridge/ebtables.h>
+ #include <linux/netfilter/x_tables.h>
+ 
+--- a/include/linux/if_ether.h
++++ /dev/null
+@@ -1,126 +0,0 @@
+-/*
+- * INET		An implementation of the TCP/IP protocol suite for the LINUX
+- *		operating system.  INET is implemented using the  BSD Socket
+- *		interface as the means of communication with the user level.
+- *
+- *		Global definitions for the Ethernet IEEE 802.3 interface.
+- *
+- * Version:	@(#)if_ether.h	1.0.1a	02/08/94
+- *
+- * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+- *		Donald Becker, <becker@super.org>
+- *		Alan Cox, <alan@lxorguk.ukuu.org.uk>
+- *		Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+- *
+- *		This program is free software; you can redistribute it and/or
+- *		modify it under the terms of the GNU General Public License
+- *		as published by the Free Software Foundation; either version
+- *		2 of the License, or (at your option) any later version.
+- */
+-
+-#ifndef _LINUX_IF_ETHER_H
+-#define _LINUX_IF_ETHER_H
+-
+-#include <linux/types.h>
+-
+-/*
+- *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+- *	and FCS/CRC (frame check sequence).
+- */
+-
+-#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+-#define ETH_HLEN	14		/* Total octets in header.	 */
+-#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
+-#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
+-#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
+-#define ETH_FCS_LEN	4		/* Octets in the FCS		 */
+-
+-/*
+- *	These are the defined Ethernet Protocol ID's.
+- */
+-
+-#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
+-#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
+-#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
+-#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+-#define ETH_P_X25	0x0805		/* CCITT X.25			*/
+-#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+-#define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet	[ NOT AN OFFICIALLY REGISTERED ID ] */
+-#define ETH_P_IEEEPUP	0x0a00		/* Xerox IEEE802.3 PUP packet */
+-#define ETH_P_IEEEPUPAT	0x0a01		/* Xerox IEEE802.3 PUP Addr Trans packet */
+-#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
+-#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
+-#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
+-#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
+-#define ETH_P_LAT       0x6004          /* DEC LAT                      */
+-#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
+-#define ETH_P_CUST      0x6006          /* DEC Customer use             */
+-#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+-#define ETH_P_TEB	0x6558		/* Trans Ether Bridging		*/
+-#define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
+-#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
+-#define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
+-#define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
+-#define ETH_P_IPX	0x8137		/* IPX over DIX			*/
+-#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
+-#define ETH_P_PAUSE	0x8808		/* IEEE Pause frames. See 802.3 31B */
+-#define ETH_P_SLOW	0x8809		/* Slow Protocol. See 802.3ad 43B */
+-#define ETH_P_WCCP	0x883E		/* Web-cache coordination protocol
+-					 * defined in draft-wilson-wrec-wccp-v2-00.txt */
+-#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
+-#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+-#define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic		*/
+-#define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic	*/
+-#define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
+-#define ETH_P_LINK_CTL	0x886c		/* HPNA, wlan link local tunnel */
+-#define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
+-					 * over Ethernet
+-					 */
+-#define ETH_P_PAE	0x888E		/* Port Access Entity (IEEE 802.1X) */
+-#define ETH_P_AOE	0x88A2		/* ATA over Ethernet		*/
+-#define ETH_P_TIPC	0x88CA		/* TIPC 			*/
+-#define ETH_P_1588	0x88F7		/* IEEE 1588 Timesync */
+-#define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
+-#define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
+-#define ETH_P_EDSA	0xDADA		/* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+-
+-/*
+- *	Non DIX types. Won't clash for 1500 types.
+- */
+-
+-#define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
+-#define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
+-#define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
+-#define ETH_P_802_2	0x0004		/* 802.2 frames 		*/
+-#define ETH_P_SNAP	0x0005		/* Internal only		*/
+-#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
+-#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
+-#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
+-#define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type 	*/
+-#define ETH_P_CAN	0x000C		/* Controller Area Network      */
+-#define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
+-#define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
+-#define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz@cafe.net)	*/
+-#define ETH_P_CONTROL	0x0016		/* Card specific control frames */
+-#define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
+-#define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
+-#define ETH_P_HDLC	0x0019		/* HDLC frames			*/
+-#define ETH_P_ARCNET	0x001A		/* 1A for ArcNet :-)            */
+-#define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
+-#define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
+-#define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
+-#define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
+-#define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/
+-
+-/*
+- *	This is an Ethernet frame header.
+- */
+-
+-struct ethhdr {
+-	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+-	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+-	__be16		h_proto;		/* packet type ID field	*/
+-} __attribute__((packed));
+-
+-
+-#endif	/* _LINUX_IF_ETHER_H */
diff --git a/package/network/utils/ebtables/patches/200-fix-extension-init.patch b/package/network/utils/ebtables/patches/200-fix-extension-init.patch
new file mode 100644
index 0000000000..63d237708f
--- /dev/null
+++ b/package/network/utils/ebtables/patches/200-fix-extension-init.patch
@@ -0,0 +1,249 @@
+--- a/extensions/Makefile
++++ b/extensions/Makefile
+@@ -11,13 +11,13 @@ EXT_LIBSI+=$(foreach T,$(EXT_FUNC), -leb
+ EXT_LIBSI+=$(foreach T,$(EXT_TABLES), -lebtable_$(T))
+ 
+ extensions/ebt_%.so: extensions/ebt_%.o
+-	$(CC) $(LDFLAGS) -shared -o $@ -lc $< -nostartfiles
++	$(CC) $(LDFLAGS) -shared -o $@ -lc $<
+ 
+ extensions/libebt_%.so: extensions/ebt_%.so
+ 	mv $< $@
+ 
+ extensions/ebtable_%.so: extensions/ebtable_%.o
+-	$(CC) $(LDFLAGS) -shared -o $@ -lc $< -nostartfiles
++	$(CC) $(LDFLAGS) -shared -o $@ -lc $<
+ 
+ extensions/libebtable_%.so: extensions/ebtable_%.so
+ 	mv $< $@
+--- a/extensions/ebt_802_3.c
++++ b/extensions/ebt_802_3.c
+@@ -141,7 +141,7 @@ static struct ebt_u_match _802_3_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&_802_3_match);
+ }
+--- a/extensions/ebt_among.c
++++ b/extensions/ebt_among.c
+@@ -490,7 +490,7 @@ static struct ebt_u_match among_match =
+ 	.extra_ops 	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&among_match);
+ }
+--- a/extensions/ebt_arp.c
++++ b/extensions/ebt_arp.c
+@@ -362,7 +362,7 @@ static struct ebt_u_match arp_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&arp_match);
+ }
+--- a/extensions/ebt_arpreply.c
++++ b/extensions/ebt_arpreply.c
+@@ -132,7 +132,7 @@ static struct ebt_u_target arpreply_targ
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_target(&arpreply_target);
+ }
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -338,7 +338,7 @@ static struct ebt_u_match ip_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&ip_match);
+ }
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -556,7 +556,7 @@ static struct ebt_u_match ip6_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&ip6_match);
+ }
+--- a/extensions/ebt_limit.c
++++ b/extensions/ebt_limit.c
+@@ -212,7 +212,7 @@ static struct ebt_u_match limit_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&limit_match);
+ }
+--- a/extensions/ebt_log.c
++++ b/extensions/ebt_log.c
+@@ -217,7 +217,7 @@ static struct ebt_u_watcher log_watcher
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_watcher(&log_watcher);
+ }
+--- a/extensions/ebt_mark.c
++++ b/extensions/ebt_mark.c
+@@ -172,7 +172,7 @@ static struct ebt_u_target mark_target =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_target(&mark_target);
+ }
+--- a/extensions/ebt_mark_m.c
++++ b/extensions/ebt_mark_m.c
+@@ -121,7 +121,7 @@ static struct ebt_u_match mark_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&mark_match);
+ }
+--- a/extensions/ebt_nat.c
++++ b/extensions/ebt_nat.c
+@@ -230,7 +230,7 @@ static struct ebt_u_target dnat_target =
+ 	.extra_ops	= opts_d,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_target(&snat_target);
+ 	ebt_register_target(&dnat_target);
+--- a/extensions/ebt_nflog.c
++++ b/extensions/ebt_nflog.c
+@@ -166,7 +166,7 @@ static struct ebt_u_watcher nflog_watche
+ 	.extra_ops = nflog_opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_watcher(&nflog_watcher);
+ }
+--- a/extensions/ebt_pkttype.c
++++ b/extensions/ebt_pkttype.c
+@@ -125,7 +125,7 @@ static struct ebt_u_match pkttype_match
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&pkttype_match);
+ }
+--- a/extensions/ebt_redirect.c
++++ b/extensions/ebt_redirect.c
+@@ -108,7 +108,7 @@ static struct ebt_u_target redirect_targ
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_target(&redirect_target);
+ }
+--- a/extensions/ebt_standard.c
++++ b/extensions/ebt_standard.c
+@@ -84,7 +84,7 @@ static struct ebt_u_target standard =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_target(&standard);
+ }
+--- a/extensions/ebt_stp.c
++++ b/extensions/ebt_stp.c
+@@ -337,7 +337,7 @@ static struct ebt_u_match stp_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&stp_match);
+ }
+--- a/extensions/ebt_ulog.c
++++ b/extensions/ebt_ulog.c
+@@ -180,7 +180,7 @@ static struct ebt_u_watcher ulog_watcher
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_watcher(&ulog_watcher);
+ }
+--- a/extensions/ebt_vlan.c
++++ b/extensions/ebt_vlan.c
+@@ -181,7 +181,7 @@ static struct ebt_u_match vlan_match = {
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_match(&vlan_match);
+ }
+--- a/extensions/ebtable_broute.c
++++ b/extensions/ebtable_broute.c
+@@ -23,7 +23,7 @@ ebt_u_table table =
+ 	.help		= print_help,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_table(&table);
+ }
+--- a/extensions/ebtable_filter.c
++++ b/extensions/ebtable_filter.c
+@@ -29,7 +29,7 @@ static struct ebt_u_table table =
+ 	.help		= print_help,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_table(&table);
+ }
+--- a/extensions/ebtable_nat.c
++++ b/extensions/ebtable_nat.c
+@@ -30,7 +30,7 @@ ebt_u_table table =
+ 	.help		= print_help,
+ };
+ 
+-void _init(void)
++__attribute__((constructor)) static void extension_init(void)
+ {
+ 	ebt_register_table(&table);
+ }
diff --git a/package/network/utils/iftop/Makefile b/package/network/utils/iftop/Makefile
new file mode 100644
index 0000000000..5a4cd8b3d3
--- /dev/null
+++ b/package/network/utils/iftop/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iftop
+PKG_VERSION:=1.0pre4
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.ex-parrot.com/~pdw/iftop/download
+PKG_MD5SUM:=7e6decb4958e8a4890cccac335239f24
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/iftop
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libpcap +libncurses +libpthread
+  TITLE:=display bandwith usage on an interface
+  URL:=http://www.ex-parrot.com/~pdw/iftop/
+endef
+
+define Package/iftop/description
+	iftop does for network usage what top(1) does for CPU usage. It 
+	listens to network traffic on a named interface and displays a 
+	table of current bandwidth usage by pairs of hosts. Handy for 
+	answering the question 'why is our ADSL link so slow?'.
+endef
+
+define Package/iftop/install	
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/iftop $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,iftop))
diff --git a/package/network/utils/iftop/patches/110-fix-mac-display.patch b/package/network/utils/iftop/patches/110-fix-mac-display.patch
new file mode 100644
index 0000000000..5db53aaa52
--- /dev/null
+++ b/package/network/utils/iftop/patches/110-fix-mac-display.patch
@@ -0,0 +1,67 @@
+iftop: fix mac address display
+
+iftop would display portions of mac address with large ffffff prefixes.
+Make if_hw_addr type consistent.
+
+Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
+---
+ addrs_dlpi.c  | 2 +-
+ addrs_ioctl.c | 2 +-
+ addrs_ioctl.h | 2 +-
+ iftop.c       | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/addrs_dlpi.c b/addrs_dlpi.c
+index 188fef8..6c04ea1 100644
+--- a/addrs_dlpi.c
++++ b/addrs_dlpi.c
+@@ -50,7 +50,7 @@ extern char *strncat2(char *dest, char *src, int n);
+  */
+ 
+ int
+-get_addrs_dlpi(char *interface, char if_hw_addr[], struct in_addr *if_ip_addr)
++get_addrs_dlpi(char *interface, u_int8_t if_hw_addr[], struct in_addr *if_ip_addr)
+ {
+   int got_hw_addr = 0;
+   int got_ip_addr = 0;
+diff --git a/addrs_ioctl.c b/addrs_ioctl.c
+index 870c83b..7d01fb2 100644
+--- a/addrs_ioctl.c
++++ b/addrs_ioctl.c
+@@ -45,7 +45,7 @@
+  */
+ 
+ int
+-get_addrs_ioctl(char *interface, char if_hw_addr[], struct in_addr *if_ip_addr, struct in6_addr *if_ip6_addr)
++get_addrs_ioctl(char *interface, u_int8_t if_hw_addr[], struct in_addr *if_ip_addr, struct in6_addr *if_ip6_addr)
+ {
+   int s;
+   struct ifreq ifr = {};
+diff --git a/addrs_ioctl.h b/addrs_ioctl.h
+index f93a0b4..739de61 100644
+--- a/addrs_ioctl.h
++++ b/addrs_ioctl.h
+@@ -7,6 +7,6 @@
+ #define __ADDRS_IOCTL_H_
+ 
+ int
+-get_addrs_ioctl(char *interface, char if_hw_addr[], struct in_addr *if_ip_addr, struct in6_addr *if_ip6_addr);
++get_addrs_ioctl(char *interface, u_int8_t if_hw_addr[], struct in_addr *if_ip_addr, struct in6_addr *if_ip6_addr);
+ 
+ #endif /* __ADDRS_IOCTL_H_ */
+diff --git a/iftop.c b/iftop.c
+index a090dcf..f1b371a 100644
+--- a/iftop.c
++++ b/iftop.c
+@@ -55,7 +55,7 @@
+ 
+ /* ethernet address of interface. */
+ int have_hw_addr = 0;
+-char if_hw_addr[6];    
++u_int8_t if_hw_addr[6];    
+ 
+ /* IP address of interface */
+ int have_ip_addr = 0;
+-- 
+1.9.1
+
diff --git a/package/network/utils/iperf/Makefile b/package/network/utils/iperf/Makefile
new file mode 100644
index 0000000000..b17ed0fc7b
--- /dev/null
+++ b/package/network/utils/iperf/Makefile
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2007-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iperf
+PKG_VERSION:=2.0.9
+PKG_VERSION_SUFFIX:=a
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)$(PKG_VERSION_SUFFIX).tar.gz
+# Temporary URL change - iperf upstream altered the already released target
+# without bumping the version number. The new tarball is renamed to avoid
+# conflicts with existing mirrored files.
+# PKG_SOURCE_URL:=@SF/iperf2
+PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
+PKG_MD5SUM:=db02911f35686e808ed247160dfa766e08ae3f59d1e7dcedef0ffb2a6643f0bf
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=BSD-3-Clause
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/uclibc++.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/iperf
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:= $(CXX_DEPENDS) +libpthread
+  TITLE:=Internet Protocol bandwidth measuring tool
+  URL:=http://sourceforge.net/projects/iperf2/
+endef
+
+define Package/iperf/description
+ Iperf is a modern alternative for measuring TCP and UDP bandwidth
+ performance, allowing the tuning of various parameters and
+ characteristics.
+endef
+
+TARGET_CFLAGS += -D_GNU_SOURCE
+CONFIGURE_ARGS += --disable-multicast
+
+CONFIGURE_VARS += CXXFLAGS="$$$$CXXFLAGS -fno-rtti"
+CONFIGURE_VARS += LIBS="-lpthread -lm"
+
+define Package/iperf/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/iperf $(1)/usr/bin/iperf
+endef
+
+$(eval $(call BuildPackage,iperf))
diff --git a/package/network/utils/iperf3/Makefile b/package/network/utils/iperf3/Makefile
new file mode 100644
index 0000000000..52838421f5
--- /dev/null
+++ b/package/network/utils/iperf3/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2007-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iperf
+PKG_VERSION:=3.1.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://downloads.es.net/pub/iperf
+PKG_MD5SUM:=db61d70ac62003ebe0bf15496bd8c4b3c4b728578a44d0a1a88fcf8afc0e8f76
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=BSD-3-Clause
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/iperf3
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Internet Protocol bandwidth measuring tool
+  URL:=https://github.com/esnet/iperf
+endef
+
+TARGET_CFLAGS += -D_GNU_SOURCE
+CONFIGURE_ARGS += --disable-shared
+
+MAKE_FLAGS += noinst_PROGRAMS=
+
+define Package/iperf3/description
+ Iperf is a modern alternative for measuring TCP and UDP bandwidth
+ performance, allowing the tuning of various parameters and
+ characteristics.
+endef
+
+define Package/iperf3/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/iperf3 $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,iperf3))
diff --git a/package/network/utils/iproute2/Makefile b/package/network/utils/iproute2/Makefile
new file mode 100644
index 0000000000..ab38d0e6d3
--- /dev/null
+++ b/package/network/utils/iproute2/Makefile
@@ -0,0 +1,148 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iproute2
+PKG_VERSION:=4.4.0
+PKG_RELEASE:=5
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/linux/utils/net/iproute2
+PKG_MD5SUM:=d762653ec3e1ab0d4a9689e169ca184f
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/iproute2/Default
+  TITLE:=Routing control utility ($(2))
+  SECTION:=net
+  CATEGORY:=Network
+  URL:=http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
+  SUBMENU:=Routing and Redirection
+  MAINTAINER:=Russell Senior <russell@personaltelco.net>
+  DEPENDS:= +libnl-tiny
+  VARIANT:=$(1)
+  PROVIDES:=$(3)
+endef
+
+define Package/ip-tiny
+$(call Package/iproute2/Default,tiny,Minimal,ip)
+  CONFLICTS:=ip-full
+endef
+
+Package/ip-full:=$(call Package/iproute2/Default,full,Full,ip)
+
+define Package/tc
+$(call Package/iproute2/Default)
+  TITLE:=Traffic control utility
+  DEPENDS:=+kmod-sched-core
+endef
+
+define Package/genl
+$(call Package/iproute2/Default)
+  TITLE:=General netlink utility frontend
+endef
+
+define Package/ip-bridge
+$(call Package/iproute2/Default)
+  TITLE:=Bridge configuration utility from iproute2
+endef
+
+define Package/ss
+$(call Package/iproute2/Default)
+  TITLE:=Socket statistics utility
+endef
+
+define Package/nstat
+$(call Package/iproute2/Default)
+  TITLE:=Network statistics utility
+endef
+
+ifeq ($(BUILD_VARIANT),tiny)
+  IP_CONFIG_TINY:=y
+endif
+
+define Build/Configure
+	$(SED) "s,-I/usr/include/db3,," $(PKG_BUILD_DIR)/Makefile
+	$(SED) "s,^KERNEL_INCLUDE.*,KERNEL_INCLUDE=$(LINUX_DIR)/include," \
+		$(PKG_BUILD_DIR)/Makefile
+	$(SED) "s,^LIBC_INCLUDE.*,LIBC_INCLUDE=$(STAGING_DIR)/include," \
+		$(PKG_BUILD_DIR)/Makefile
+	echo "static const char SNAPSHOT[] = \"$(PKG_VERSION)-$(PKG_RELEASE)-lede\";" \
+		> $(PKG_BUILD_DIR)/include/SNAPSHOT.h
+endef
+
+TARGET_CFLAGS += -DHAVE_SETNS
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+
+MAKE_FLAGS += \
+	EXTRA_CCOPTS="$(TARGET_CFLAGS) -I../include -I$(STAGING_DIR)/usr/include/libnl-tiny" \
+	KERNEL_INCLUDE="$(LINUX_DIR)/include" \
+	SHARED_LIBS="" \
+	LDFLAGS="$(TARGET_LDFLAGS) -Wl,--gc-sections" \
+	IP_CONFIG_TINY=$(IP_CONFIG_TINY) \
+	FPIC="$(FPIC)"
+
+define Build/Compile
+	+$(MAKE_VARS) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) $(MAKE_FLAGS)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_BUILD_DIR)/include/libnetlink.h $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/lib/libnetlink.a $(1)/usr/lib/
+endef
+
+define Package/ip-tiny/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ip/ip $(1)/usr/bin/
+endef
+
+define Package/ip-full/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ip/ip $(1)/usr/sbin/
+endef
+
+define Package/tc/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tc/tc $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
+	$(INSTALL_BIN) ./files/15-teql $(1)/etc/hotplug.d/iface/
+endef
+
+define Package/genl/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/genl/genl $(1)/usr/sbin/
+endef
+
+define Package/ip-bridge/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bridge/bridge $(1)/usr/sbin/
+endef
+
+define Package/ss/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/misc/ss $(1)/usr/sbin/
+endef
+
+define Package/nstat/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/misc/nstat $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,ip-tiny))
+$(eval $(call BuildPackage,ip-full))
+$(eval $(call BuildPackage,tc))
+$(eval $(call BuildPackage,genl))
+$(eval $(call BuildPackage,ip-bridge))
+$(eval $(call BuildPackage,ss))
+$(eval $(call BuildPackage,nstat))
diff --git a/package/network/utils/iproute2/files/15-teql b/package/network/utils/iproute2/files/15-teql
new file mode 100644
index 0000000000..a0c0e503aa
--- /dev/null
+++ b/package/network/utils/iproute2/files/15-teql
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+. /lib/functions.sh
+
+if [ "$ACTION" != "ifup" ]; then
+	exit
+fi
+
+config_load network
+
+config_get teql $INTERFACE teql
+
+if [ "$teql" != "" ]; then
+    logger Adding device $DEVICE to TEQL master $teql
+    insmod sch_teql
+    tc qdisc add dev $DEVICE root $teql
+
+    # The kernel doesn't let us bring it up until it has at least one
+    # slave. So bring it up now, if it isn't already.
+    if ! cat /sys/class/net/$teql/carrier &>/dev/null; then
+        ifup $teql &
+    fi
+fi
diff --git a/package/network/utils/iproute2/patches/001-config.patch b/package/network/utils/iproute2/patches/001-config.patch
new file mode 100644
index 0000000000..ece8652994
--- /dev/null
+++ b/package/network/utils/iproute2/patches/001-config.patch
@@ -0,0 +1,7 @@
+--- /dev/null
++++ b/Config
+@@ -0,0 +1,4 @@
++# Fixed config to disable ATM support even if present on host system
++TC_CONFIG_ATM:=n
++TC_CONFIG_ACTION_GACT=y
++TC_CONFIG_ACTION_PROB=y
diff --git a/package/network/utils/iproute2/patches/004-darwin_fixes.patch b/package/network/utils/iproute2/patches/004-darwin_fixes.patch
new file mode 100644
index 0000000000..e1a5e97568
--- /dev/null
+++ b/package/network/utils/iproute2/patches/004-darwin_fixes.patch
@@ -0,0 +1,59 @@
+--- a/netem/maketable.c
++++ b/netem/maketable.c
+@@ -10,7 +10,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <math.h>
++#if !defined(__APPLE__) && !defined(__FreeBSD__)
+ #include <malloc.h>
++#endif
+ #include <string.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+--- a/netem/normal.c
++++ b/netem/normal.c
+@@ -8,8 +8,12 @@
+ #include <string.h>
+ #include <limits.h>
+ 
++#if !defined(__APPLE__) && !defined(__FreeBSD__)
+ #include <linux/types.h>
+ #include <linux/pkt_sched.h>
++#else
++#define NETEM_DIST_SCALE        8192
++#endif
+ 
+ #define TABLESIZE 16384
+ #define TABLEFACTOR NETEM_DIST_SCALE
+--- a/netem/pareto.c
++++ b/netem/pareto.c
+@@ -7,8 +7,12 @@
+ #include <math.h>
+ #include <limits.h>
+ 
++#if !defined(__APPLE__) && !defined(__FreeBSD__)
+ #include <linux/types.h>
+ #include <linux/pkt_sched.h>
++#else
++#define NETEM_DIST_SCALE        8192
++#endif
+ 
+ static const double a=3.0;
+ #define TABLESIZE	16384
+--- a/netem/paretonormal.c
++++ b/netem/paretonormal.c
+@@ -15,10 +15,13 @@
+ #include <string.h>
+ #include <math.h>
+ #include <limits.h>
++#if !defined(__APPLE__) && !defined(__FreeBSD__)
+ #include <malloc.h>
+-
+ #include <linux/types.h>
+ #include <linux/pkt_sched.h>
++#else
++#define NETEM_DIST_SCALE        8192
++#endif
+ 
+ #define TABLESIZE	16384
+ #define TABLEFACTOR	NETEM_DIST_SCALE
diff --git a/package/network/utils/iproute2/patches/006-no_sctp.patch b/package/network/utils/iproute2/patches/006-no_sctp.patch
new file mode 100644
index 0000000000..6805468d81
--- /dev/null
+++ b/package/network/utils/iproute2/patches/006-no_sctp.patch
@@ -0,0 +1,18 @@
+--- a/ip/ipxfrm.c
++++ b/ip/ipxfrm.c
+@@ -470,7 +470,6 @@ void xfrm_selector_print(struct xfrm_sel
+ 	switch (sel->proto) {
+ 	case IPPROTO_TCP:
+ 	case IPPROTO_UDP:
+-	case IPPROTO_SCTP:
+ 	case IPPROTO_DCCP:
+ 	default: /* XXX */
+ 		if (sel->sport_mask)
+@@ -1341,7 +1340,6 @@ static int xfrm_selector_upspec_parse(st
+ 		switch (sel->proto) {
+ 		case IPPROTO_TCP:
+ 		case IPPROTO_UDP:
+-		case IPPROTO_SCTP:
+ 		case IPPROTO_DCCP:
+ 		case IPPROTO_IP: /* to allow shared SA for different protocols */
+ 			break;
diff --git a/package/network/utils/iproute2/patches/007-no_arpd.patch b/package/network/utils/iproute2/patches/007-no_arpd.patch
new file mode 100644
index 0000000000..94fb197a45
--- /dev/null
+++ b/package/network/utils/iproute2/patches/007-no_arpd.patch
@@ -0,0 +1,15 @@
+--- a/misc/Makefile
++++ b/misc/Makefile
+@@ -5,9 +5,9 @@ TARGETS=ss nstat ifstat rtacct lnstat
+ 
+ include ../Config
+ 
+-ifeq ($(HAVE_BERKELEY_DB),y)
+-	TARGETS += arpd
+-endif
++#ifeq ($(HAVE_BERKELEY_DB),y)
++#	TARGETS += arpd
++#endif
+ 
+ ifeq ($(HAVE_SELINUX),y)
+ 	LDLIBS += $(shell $(PKG_CONFIG) --libs libselinux)
diff --git a/package/network/utils/iproute2/patches/008-no_netem.patch b/package/network/utils/iproute2/patches/008-no_netem.patch
new file mode 100644
index 0000000000..fce16e02df
--- /dev/null
+++ b/package/network/utils/iproute2/patches/008-no_netem.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -41,7 +41,7 @@ WFLAGS += -Wmissing-declarations -Wold-s
+ CFLAGS := $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) $(CFLAGS)
+ YACCFLAGS = -d -t -v
+ 
+-SUBDIRS=lib ip tc bridge misc netem genl tipc man
++SUBDIRS=lib ip tc bridge misc genl tipc man
+ 
+ LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
+ LDLIBS += $(LIBNETLINK)
diff --git a/package/network/utils/iproute2/patches/010-type_fixes.patch b/package/network/utils/iproute2/patches/010-type_fixes.patch
new file mode 100644
index 0000000000..e0055fce71
--- /dev/null
+++ b/package/network/utils/iproute2/patches/010-type_fixes.patch
@@ -0,0 +1,396 @@
+--- a/include/iptables_common.h
++++ b/include/iptables_common.h
+@@ -2,6 +2,8 @@
+ #define _IPTABLES_COMMON_H
+ /* Shared definitions between ipv4 and ipv6. */
+ 
++#include <stdint.h>
++
+ enum exittype {
+ 	OTHER_PROBLEM = 1,
+ 	PARAMETER_PROBLEM,
+@@ -43,9 +45,9 @@ extern char *lib_dir;
+   extern void init_extensions(void);
+ #endif
+ 
+-#define __be32	u_int32_t
+-#define __le32	u_int32_t
+-#define __be16	u_int16_t
+-#define __le16	u_int16_t
++#define __be32	uint32_t
++#define __le32	uint32_t
++#define __be16	uint16_t
++#define __le16	uint16_t
+ 
+ #endif /*_IPTABLES_COMMON_H*/
+--- a/include/netinet/tcp.h
++++ /dev/null
+@@ -1,231 +0,0 @@
+-/*
+- * Copyright (c) 1982, 1986, 1993
+- *	The Regents of the University of California.  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.
+- * 4. Neither the name of the University nor the names of its contributors
+- *    may be used to endorse or promote products derived from this software
+- *    without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+- *
+- *	@(#)tcp.h	8.1 (Berkeley) 6/10/93
+- */
+-
+-#ifndef _NETINET_TCP_H
+-#define _NETINET_TCP_H	1
+-
+-#include <features.h>
+-
+-/*
+- * User-settable options (used with setsockopt).
+- */
+-#define	TCP_NODELAY	 1	/* Don't delay send to coalesce packets  */
+-#define	TCP_MAXSEG	 2	/* Set maximum segment size  */
+-#define TCP_CORK	 3	/* Control sending of partial frames  */
+-#define TCP_KEEPIDLE	 4	/* Start keeplives after this period */
+-#define TCP_KEEPINTVL	 5	/* Interval between keepalives */
+-#define TCP_KEEPCNT	 6	/* Number of keepalives before death */
+-#define TCP_SYNCNT	 7	/* Number of SYN retransmits */
+-#define TCP_LINGER2	 8	/* Life time of orphaned FIN-WAIT-2 state */
+-#define TCP_DEFER_ACCEPT 9	/* Wake up listener only when data arrive */
+-#define TCP_WINDOW_CLAMP 10	/* Bound advertised window */
+-#define TCP_INFO	 11	/* Information about this connection. */
+-#define	TCP_QUICKACK	 12	/* Bock/reenable quick ACKs.  */
+-#define TCP_CONGESTION	 13	/* Congestion control algorithm.  */
+-
+-#ifdef __USE_MISC
+-# include <sys/types.h>
+-
+-# ifdef __FAVOR_BSD
+-typedef	u_int32_t tcp_seq;
+-/*
+- * TCP header.
+- * Per RFC 793, September, 1981.
+- */
+-struct tcphdr
+-  {
+-    u_int16_t th_sport;		/* source port */
+-    u_int16_t th_dport;		/* destination port */
+-    tcp_seq th_seq;		/* sequence number */
+-    tcp_seq th_ack;		/* acknowledgement number */
+-#  if __BYTE_ORDER == __LITTLE_ENDIAN
+-    u_int8_t th_x2:4;		/* (unused) */
+-    u_int8_t th_off:4;		/* data offset */
+-#  endif
+-#  if __BYTE_ORDER == __BIG_ENDIAN
+-    u_int8_t th_off:4;		/* data offset */
+-    u_int8_t th_x2:4;		/* (unused) */
+-#  endif
+-    u_int8_t th_flags;
+-#  define TH_FIN	0x01
+-#  define TH_SYN	0x02
+-#  define TH_RST	0x04
+-#  define TH_PUSH	0x08
+-#  define TH_ACK	0x10
+-#  define TH_URG	0x20
+-    u_int16_t th_win;		/* window */
+-    u_int16_t th_sum;		/* checksum */
+-    u_int16_t th_urp;		/* urgent pointer */
+-};
+-
+-# else /* !__FAVOR_BSD */
+-struct tcphdr
+-  {
+-    u_int16_t source;
+-    u_int16_t dest;
+-    u_int32_t seq;
+-    u_int32_t ack_seq;
+-#  if __BYTE_ORDER == __LITTLE_ENDIAN
+-    u_int16_t res1:4;
+-    u_int16_t doff:4;
+-    u_int16_t fin:1;
+-    u_int16_t syn:1;
+-    u_int16_t rst:1;
+-    u_int16_t psh:1;
+-    u_int16_t ack:1;
+-    u_int16_t urg:1;
+-    u_int16_t res2:2;
+-#  elif __BYTE_ORDER == __BIG_ENDIAN
+-    u_int16_t doff:4;
+-    u_int16_t res1:4;
+-    u_int16_t res2:2;
+-    u_int16_t urg:1;
+-    u_int16_t ack:1;
+-    u_int16_t psh:1;
+-    u_int16_t rst:1;
+-    u_int16_t syn:1;
+-    u_int16_t fin:1;
+-#  else
+-#   error "Adjust your <bits/endian.h> defines"
+-#  endif
+-    u_int16_t window;
+-    u_int16_t check;
+-    u_int16_t urg_ptr;
+-};
+-# endif /* __FAVOR_BSD */
+-
+-enum
+-{
+-  TCP_ESTABLISHED = 1,
+-  TCP_SYN_SENT,
+-  TCP_SYN_RECV,
+-  TCP_FIN_WAIT1,
+-  TCP_FIN_WAIT2,
+-  TCP_TIME_WAIT,
+-  TCP_CLOSE,
+-  TCP_CLOSE_WAIT,
+-  TCP_LAST_ACK,
+-  TCP_LISTEN,
+-  TCP_CLOSING   /* now a valid state */
+-};
+-
+-# define TCPOPT_EOL		0
+-# define TCPOPT_NOP		1
+-# define TCPOPT_MAXSEG		2
+-# define TCPOLEN_MAXSEG		4
+-# define TCPOPT_WINDOW		3
+-# define TCPOLEN_WINDOW		3
+-# define TCPOPT_SACK_PERMITTED	4		/* Experimental */
+-# define TCPOLEN_SACK_PERMITTED	2
+-# define TCPOPT_SACK		5		/* Experimental */
+-# define TCPOPT_TIMESTAMP	8
+-# define TCPOLEN_TIMESTAMP	10
+-# define TCPOLEN_TSTAMP_APPA	(TCPOLEN_TIMESTAMP+2) /* appendix A */
+-
+-# define TCPOPT_TSTAMP_HDR	\
+-    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)
+-
+-/*
+- * Default maximum segment size for TCP.
+- * With an IP MSS of 576, this is 536,
+- * but 512 is probably more convenient.
+- * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
+- */
+-# define TCP_MSS	512
+-
+-# define TCP_MAXWIN	65535	/* largest value for (unscaled) window */
+-
+-# define TCP_MAX_WINSHIFT	14	/* maximum window shift */
+-
+-# define SOL_TCP		6	/* TCP level */
+-
+-
+-# define TCPI_OPT_TIMESTAMPS	1
+-# define TCPI_OPT_SACK		2
+-# define TCPI_OPT_WSCALE	4
+-# define TCPI_OPT_ECN		8
+-# define TCPI_OPT_ECN_SEEN	16
+-
+-/* Values for tcpi_state.  */
+-enum tcp_ca_state
+-{
+-  TCP_CA_Open = 0,
+-  TCP_CA_Disorder = 1,
+-  TCP_CA_CWR = 2,
+-  TCP_CA_Recovery = 3,
+-  TCP_CA_Loss = 4
+-};
+-
+-struct tcp_info
+-{
+-  u_int8_t	tcpi_state;
+-  u_int8_t	tcpi_ca_state;
+-  u_int8_t	tcpi_retransmits;
+-  u_int8_t	tcpi_probes;
+-  u_int8_t	tcpi_backoff;
+-  u_int8_t	tcpi_options;
+-  u_int8_t	tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+-
+-  u_int32_t	tcpi_rto;
+-  u_int32_t	tcpi_ato;
+-  u_int32_t	tcpi_snd_mss;
+-  u_int32_t	tcpi_rcv_mss;
+-
+-  u_int32_t	tcpi_unacked;
+-  u_int32_t	tcpi_sacked;
+-  u_int32_t	tcpi_lost;
+-  u_int32_t	tcpi_retrans;
+-  u_int32_t	tcpi_fackets;
+-
+-  /* Times. */
+-  u_int32_t	tcpi_last_data_sent;
+-  u_int32_t	tcpi_last_ack_sent;	/* Not remembered, sorry.  */
+-  u_int32_t	tcpi_last_data_recv;
+-  u_int32_t	tcpi_last_ack_recv;
+-
+-  /* Metrics. */
+-  u_int32_t	tcpi_pmtu;
+-  u_int32_t	tcpi_rcv_ssthresh;
+-  u_int32_t	tcpi_rtt;
+-  u_int32_t	tcpi_rttvar;
+-  u_int32_t	tcpi_snd_ssthresh;
+-  u_int32_t	tcpi_snd_cwnd;
+-  u_int32_t	tcpi_advmss;
+-  u_int32_t	tcpi_reordering;
+-  u_int32_t	tcpi_rcv_rtt;
+-  u_int32_t	tcpi_rcv_space;
+-  u_int32_t	tcpi_total_retrans;
+-
+-};
+-
+-#endif /* Misc.  */
+-
+-#endif /* netinet/tcp.h */
+--- a/include/iptables.h
++++ b/include/iptables.h
+@@ -20,7 +20,7 @@ struct ipt_get_revision
+ {
+ 	char name[IPT_FUNCTION_MAXNAMELEN-1];
+ 
+-	u_int8_t revision;
++	uint8_t revision;
+ };
+ #endif /* IPT_SO_GET_REVISION_MATCH   Old kernel source */
+ 
+@@ -39,7 +39,7 @@ struct iptables_match
+ 	ipt_chainlabel name;
+ 
+ 	/* Revision of match (0 by default). */
+-	u_int8_t revision;
++	uint8_t revision;
+ 
+ 	const char *version;
+ 
+@@ -92,7 +92,7 @@ struct iptables_target
+ 	ipt_chainlabel name;
+ 
+ 	/* Revision of target (0 by default). */
+-	u_int8_t revision;
++	uint8_t revision;
+ 
+ 	const char *version;
+ 
+@@ -153,7 +153,7 @@ extern char *mask_to_dotted(const struct
+ 
+ extern void parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
+                       struct in_addr *maskp, unsigned int *naddrs);
+-extern u_int16_t parse_protocol(const char *s);
++extern uint16_t parse_protocol(const char *s);
+ 
+ extern int do_command(int argc, char *argv[], char **table,
+ 		      iptc_handle_t *handle);
+--- a/lib/dnet_ntop.c
++++ b/lib/dnet_ntop.c
+@@ -1,24 +1,25 @@
+ #include <errno.h>
+ #include <string.h>
++#include <stdint.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ 
+ #include "utils.h"
+ 
+-static __inline__ u_int16_t dn_ntohs(u_int16_t addr)
++static __inline__ uint16_t dn_ntohs(uint16_t addr)
+ {
+ 	union {
+-		u_int8_t byte[2];
+-		u_int16_t word;
++		uint8_t byte[2];
++		uint16_t word;
+ 	} u;
+ 
+ 	u.word = addr;
+-	return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
++	return ((uint16_t)u.byte[0]) | (((uint16_t)u.byte[1]) << 8);
+ }
+ 
+-static __inline__ int do_digit(char *str, u_int16_t *addr, u_int16_t scale, size_t *pos, size_t len, int *started)
++static __inline__ int do_digit(char *str, uint16_t *addr, uint16_t scale, size_t *pos, size_t len, int *started)
+ {
+-	u_int16_t tmp = *addr / scale;
++	uint16_t tmp = *addr / scale;
+ 
+ 	if (*pos == len)
+ 		return 1;
+@@ -36,7 +37,7 @@ static __inline__ int do_digit(char *str
+ 
+ static const char *dnet_ntop1(const struct dn_naddr *dna, char *str, size_t len)
+ {
+-	u_int16_t addr, area;
++	uint16_t addr, area;
+ 	size_t pos = 0;
+ 	int started = 0;
+ 
+--- a/lib/dnet_pton.c
++++ b/lib/dnet_pton.c
+@@ -1,23 +1,24 @@
+ #include <errno.h>
+ #include <string.h>
++#include <stdint.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ 
+ #include "utils.h"
+ 
+-static __inline__ u_int16_t dn_htons(u_int16_t addr)
++static __inline__ uint16_t dn_htons(uint16_t addr)
+ {
+         union {
+-                u_int8_t byte[2];
+-                u_int16_t word;
++                uint8_t byte[2];
++                uint16_t word;
+         } u;
+ 
+         u.word = addr;
+-        return ((u_int16_t)u.byte[0]) | (((u_int16_t)u.byte[1]) << 8);
++        return ((uint16_t)u.byte[0]) | (((uint16_t)u.byte[1]) << 8);
+ }
+ 
+ 
+-static int dnet_num(const char *src, u_int16_t * dst)
++static int dnet_num(const char *src, uint16_t * dst)
+ {
+ 	int rv = 0;
+ 	int tmp;
+@@ -38,9 +39,9 @@ static int dnet_num(const char *src, u_i
+ 
+ static int dnet_pton1(const char *src, struct dn_naddr *dna)
+ {
+-	u_int16_t addr;
+-	u_int16_t area = 0;
+-	u_int16_t node = 0;
++	uint16_t addr;
++	uint16_t area = 0;
++	uint16_t node = 0;
+ 	int pos;
+ 
+ 	pos = dnet_num(src, &area);
+--- a/include/libiptc/ipt_kernel_headers.h
++++ b/include/libiptc/ipt_kernel_headers.h
+@@ -5,7 +5,7 @@
+ 
+ #include <limits.h>
+ 
+-#if defined(__GLIBC__) && __GLIBC__ == 2
++#if 1
+ #include <netinet/ip.h>
+ #include <netinet/in.h>
+ #include <netinet/ip_icmp.h>
diff --git a/package/network/utils/iproute2/patches/100-allow_pfifo_fast.patch b/package/network/utils/iproute2/patches/100-allow_pfifo_fast.patch
new file mode 100644
index 0000000000..ce958a9345
--- /dev/null
+++ b/package/network/utils/iproute2/patches/100-allow_pfifo_fast.patch
@@ -0,0 +1,9 @@
+--- a/tc/q_fifo.c
++++ b/tc/q_fifo.c
+@@ -98,5 +98,6 @@ struct qdisc_util pfifo_head_drop_qdisc_
+ extern int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt);
+ struct qdisc_util pfifo_fast_qdisc_util = {
+ 	.id = "pfifo_fast",
++	.parse_qopt = fifo_parse_opt,
+ 	.print_qopt = prio_print_opt,
+ };
diff --git a/package/network/utils/iproute2/patches/110-extra-ccopts.patch b/package/network/utils/iproute2/patches/110-extra-ccopts.patch
new file mode 100644
index 0000000000..3cb5a79400
--- /dev/null
+++ b/package/network/utils/iproute2/patches/110-extra-ccopts.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -34,7 +34,7 @@ HOSTCC = gcc
+ DEFINES += -D_GNU_SOURCE
+ # Turn on transparent support for LFS
+ DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+-CCOPTS = -O2
++CCOPTS = -O2 $(EXTRA_CCOPTS)
+ WFLAGS := -Wall -Wstrict-prototypes  -Wmissing-prototypes
+ WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2
+ 
diff --git a/package/network/utils/iproute2/patches/120-libnetlink-pic.patch b/package/network/utils/iproute2/patches/120-libnetlink-pic.patch
new file mode 100644
index 0000000000..1f397f71b2
--- /dev/null
+++ b/package/network/utils/iproute2/patches/120-libnetlink-pic.patch
@@ -0,0 +1,11 @@
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -4,7 +4,7 @@ ifeq ($(IP_CONFIG_SETNS),y)
+ 	CFLAGS += -DHAVE_SETNS
+ endif
+ 
+-CFLAGS += -fPIC
++CFLAGS += $(FPIC)
+ 
+ UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
+ 	inet_proto.o namespace.o json_writer.o \
diff --git a/package/network/utils/iproute2/patches/130-missing_include.patch b/package/network/utils/iproute2/patches/130-missing_include.patch
new file mode 100644
index 0000000000..8759a62599
--- /dev/null
+++ b/package/network/utils/iproute2/patches/130-missing_include.patch
@@ -0,0 +1,20 @@
+--- a/lib/namespace.c
++++ b/lib/namespace.c
+@@ -10,6 +10,7 @@
+ #include <fcntl.h>
+ #include <dirent.h>
+ #include <limits.h>
++#include <sys/param.h>
+ 
+ #include "utils.h"
+ #include "namespace.h"
+--- a/lib/rt_names.c
++++ b/lib/rt_names.c
+@@ -18,6 +18,7 @@
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <dirent.h>
++#include <limits.h>
+ 
+ #include <asm/types.h>
+ #include <linux/rtnetlink.h>
diff --git a/package/network/utils/iproute2/patches/300-ip_tiny.patch b/package/network/utils/iproute2/patches/300-ip_tiny.patch
new file mode 100644
index 0000000000..290adbe5f5
--- /dev/null
+++ b/package/network/utils/iproute2/patches/300-ip_tiny.patch
@@ -0,0 +1,101 @@
+--- a/ip/Makefile
++++ b/ip/Makefile
+@@ -17,6 +17,13 @@ ifeq ($(IP_CONFIG_SETNS),y)
+ 	CFLAGS += -DHAVE_SETNS
+ endif
+ 
++STATIC_SYM_FILTER:=
++ifeq ($(IP_CONFIG_TINY),y)
++  STATIC_SYM_FILTER:=iplink_can.c iplink_ipoib.c iplink_vxlan.c
++  CFLAGS += -DIPROUTE2_TINY
++endif
++STATIC_SYM_SOURCES:=$(filter-out $(STATIC_SYM_FILTER),$(wildcard *.c))
++
+ ALLOBJ=$(IPOBJ) $(RTMONOBJ)
+ SCRIPTS=ifcfg rtpr routel routef
+ TARGETS=ip rtmon
+@@ -44,7 +51,7 @@ else
+ 
+ ip: static-syms.o
+ static-syms.o: static-syms.h
+-static-syms.h: $(wildcard *.c)
++static-syms.h: $(STATIC_SYM_SOURCES)
+ 	files="$^" ; \
+ 	for s in `grep -B 3 '\<dlsym' $$files | sed -n '/snprintf/{s:.*"\([^"]*\)".*:\1:;s:%s::;p}'` ; do \
+ 		sed -n '/'$$s'[^ ]* =/{s:.* \([^ ]*'$$s'[^ ]*\) .*:extern char \1[] __attribute__((weak)); if (!strcmp(sym, "\1")) return \1;:;p}' $$files ; \
+--- a/ip/ip.c
++++ b/ip/ip.c
+@@ -73,30 +73,42 @@ static const struct cmd {
+ 	int (*func)(int argc, char **argv);
+ } cmds[] = {
+ 	{ "address",	do_ipaddr },
++#ifndef IPROUTE2_TINY
+ 	{ "addrlabel",	do_ipaddrlabel },
++#endif
+ 	{ "maddress",	do_multiaddr },
+ 	{ "route",	do_iproute },
+ 	{ "rule",	do_iprule },
+ 	{ "neighbor",	do_ipneigh },
+ 	{ "neighbour",	do_ipneigh },
++#ifndef IPROUTE2_TINY
+ 	{ "ntable",	do_ipntable },
+ 	{ "ntbl",	do_ipntable },
++#endif
+ 	{ "link",	do_iplink },
++#ifndef IPROUTE2_TINY
+ 	{ "l2tp",	do_ipl2tp },
+ 	{ "fou",	do_ipfou },
++#endif
+ 	{ "tunnel",	do_iptunnel },
+ 	{ "tunl",	do_iptunnel },
++#ifndef IPROUTE2_TINY
+ 	{ "tuntap",	do_iptuntap },
+ 	{ "tap",	do_iptuntap },
+ 	{ "token",	do_iptoken },
+ 	{ "tcpmetrics",	do_tcp_metrics },
+ 	{ "tcp_metrics", do_tcp_metrics },
++#endif
+ 	{ "monitor",	do_ipmonitor },
++#ifndef IPROUTE2_TINY
+ 	{ "xfrm",	do_xfrm },
++#endif
+ 	{ "mroute",	do_multiroute },
+ 	{ "mrule",	do_multirule },
+ 	{ "netns",	do_netns },
++#ifndef IPROUTE2_TINY
+ 	{ "netconf",	do_ipnetconf },
++#endif
+ 	{ "help",	do_help },
+ 	{ 0 }
+ };
+--- a/lib/utils.c
++++ b/lib/utils.c
+@@ -710,6 +710,7 @@ const char *rt_addr_n2a(int af, int len,
+ 		return inet_ntop(af, addr, buf, buflen);
+ 	case AF_MPLS:
+ 		return mpls_ntop(af, addr, buf, buflen);
++#ifndef IPROUTE2_TINY
+ 	case AF_IPX:
+ 		return ipx_ntop(af, addr, buf, buflen);
+ 	case AF_DECnet:
+@@ -718,6 +719,7 @@ const char *rt_addr_n2a(int af, int len,
+ 		memcpy(dna.a_addr, addr, 2);
+ 		return dnet_ntop(af, &dna, buf, buflen);
+ 	}
++#endif
+ 	case AF_PACKET:
+ 		return ll_addr_n2a(addr, len, ARPHRD_VOID, buf, buflen);
+ 	default:
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -4,6 +4,10 @@ ifeq ($(IP_CONFIG_SETNS),y)
+ 	CFLAGS += -DHAVE_SETNS
+ endif
+ 
++ifeq ($(IP_CONFIG_TINY),y)
++  CFLAGS += -DIPROUTE2_TINY
++endif
++
+ CFLAGS += $(FPIC)
+ 
+ UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
diff --git a/package/network/utils/iproute2/patches/900-drop_FAILED_POLICY.patch b/package/network/utils/iproute2/patches/900-drop_FAILED_POLICY.patch
new file mode 100644
index 0000000000..ff2e0aa1ee
--- /dev/null
+++ b/package/network/utils/iproute2/patches/900-drop_FAILED_POLICY.patch
@@ -0,0 +1,54 @@
+From 4e7dbf76227e8c7be7897dc81def3011f637864d Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Thu, 30 May 2013 11:54:04 +0200
+Subject: [PATCH] add support for dropping with FAILED_POLICY
+
+---
+ include/linux/fib_rules.h |    4 ++++
+ include/linux/rtnetlink.h |    1 +
+ ip/rtm_map.c              |    4 ++++
+ 3 files changed, 9 insertions(+)
+
+--- a/include/linux/fib_rules.h
++++ b/include/linux/fib_rules.h
+@@ -64,6 +64,10 @@ enum {
+ 	FR_ACT_BLACKHOLE,	/* Drop without notification */
+ 	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
+ 	FR_ACT_PROHIBIT,	/* Drop with EACCES */
++	FR_ACT_RES8,
++	FR_ACT_RES9,
++	FR_ACT_RES10,
++	FR_ACT_FAILED_POLICY,	/* Drop with EPERM */
+ 	__FR_ACT_MAX,
+ };
+ 
+--- a/include/linux/rtnetlink.h
++++ b/include/linux/rtnetlink.h
+@@ -210,6 +210,7 @@ enum {
+ 	RTN_THROW,		/* Not in this table		*/
+ 	RTN_NAT,		/* Translate this address	*/
+ 	RTN_XRESOLVE,		/* Use external resolver	*/
++	RTN_FAILED_POLICY,	/* Source address failed policy */
+ 	__RTN_MAX
+ };
+ 
+--- a/ip/rtm_map.c
++++ b/ip/rtm_map.c
+@@ -49,6 +49,8 @@ char *rtnl_rtntype_n2a(int id, char *buf
+ 		return "nat";
+ 	case RTN_XRESOLVE:
+ 		return "xresolve";
++	case RTN_FAILED_POLICY:
++		return "failed_policy";
+ 	default:
+ 		snprintf(buf, len, "%d", id);
+ 		return buf;
+@@ -84,6 +86,8 @@ int rtnl_rtntype_a2n(int *id, char *arg)
+ 		res = RTN_UNICAST;
+ 	else if (strcmp(arg, "throw") == 0)
+ 		res = RTN_THROW;
++	else if (strcmp(arg, "failed_policy") == 0)
++		res = RTN_FAILED_POLICY;
+ 	else {
+ 		res = strtoul(arg, &end, 0);
+ 		if (!end || end == arg || *end || res > 255)
diff --git a/package/network/utils/iproute2/patches/910-sanitize_headers_for_musl.patch b/package/network/utils/iproute2/patches/910-sanitize_headers_for_musl.patch
new file mode 100644
index 0000000000..ca1125d1d5
--- /dev/null
+++ b/package/network/utils/iproute2/patches/910-sanitize_headers_for_musl.patch
@@ -0,0 +1,10 @@
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -15,7 +15,6 @@
+ 
+ #include <linux/types.h>
+ #include <linux/if_ether.h>
+-#include <linux/in6.h>
+ 
+ #define SYSFS_BRIDGE_ATTR	"bridge"
+ #define SYSFS_BRIDGE_FDB	"brforward"
diff --git a/package/network/utils/iproute2/patches/911-fix_in_h_include.patch b/package/network/utils/iproute2/patches/911-fix_in_h_include.patch
new file mode 100644
index 0000000000..42a7b24bbb
--- /dev/null
+++ b/package/network/utils/iproute2/patches/911-fix_in_h_include.patch
@@ -0,0 +1,30 @@
+--- a/include/linux/in.h
++++ b/include/linux/in.h
+@@ -15,6 +15,7 @@
+  *		as published by the Free Software Foundation; either version
+  *		2 of the License, or (at your option) any later version.
+  */
++#ifndef _NETINET_IN_H
+ #ifndef _LINUX_IN_H
+ #define _LINUX_IN_H
+ 
+@@ -297,3 +298,4 @@ struct sockaddr_in {
+ 
+ 
+ #endif /* _LINUX_IN_H */
++#endif /* _NETINET_IN_H */
+--- a/include/linux/in6.h
++++ b/include/linux/in6.h
+@@ -18,6 +18,7 @@
+  *      2 of the License, or (at your option) any later version.
+  */
+ 
++#ifndef _NETINET_IN_H
+ #ifndef _LINUX_IN6_H
+ #define _LINUX_IN6_H
+ 
+@@ -291,3 +292,4 @@ struct in6_flowlabel_req {
+  * MRT6_MAX
+  */
+ #endif /* _LINUX_IN6_H */
++#endif /* _NETINET_IN_H */
diff --git a/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch b/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch
new file mode 100644
index 0000000000..ffb3e63e13
--- /dev/null
+++ b/package/network/utils/iproute2/patches/950-add-cake-to-tc.patch
@@ -0,0 +1,716 @@
+--- a/include/linux/pkt_sched.h
++++ b/include/linux/pkt_sched.h
+@@ -850,4 +850,57 @@ struct tc_pie_xstats {
+ 	__u32 maxq;             /* maximum queue size */
+ 	__u32 ecn_mark;         /* packets marked with ecn*/
+ };
++
++/* CAKE */
++enum {
++	TCA_CAKE_UNSPEC,
++	TCA_CAKE_BASE_RATE,
++	TCA_CAKE_DIFFSERV_MODE,
++	TCA_CAKE_ATM,
++	TCA_CAKE_FLOW_MODE,
++	TCA_CAKE_OVERHEAD,
++	TCA_CAKE_RTT,
++	TCA_CAKE_TARGET,
++	TCA_CAKE_AUTORATE,
++	TCA_CAKE_MEMORY,
++	TCA_CAKE_NAT,
++	__TCA_CAKE_MAX
++};
++#define TCA_CAKE_MAX	(__TCA_CAKE_MAX - 1)
++
++struct tc_cake_traffic_stats {
++	__u32 packets;
++	__u32 link_ms;
++	__u64 bytes;
++};
++
++#define TC_CAKE_MAX_TINS (8)
++struct tc_cake_xstats {
++	__u16 version;  /* == 4, increments when struct extended */
++	__u8  max_tins; /* == TC_CAKE_MAX_TINS */
++	__u8  tin_cnt;  /* <= TC_CAKE_MAX_TINS */
++
++	__u32 threshold_rate   [TC_CAKE_MAX_TINS];
++	__u32 target_us        [TC_CAKE_MAX_TINS];
++	struct tc_cake_traffic_stats sent      [TC_CAKE_MAX_TINS];
++	struct tc_cake_traffic_stats dropped   [TC_CAKE_MAX_TINS];
++	struct tc_cake_traffic_stats ecn_marked[TC_CAKE_MAX_TINS];
++	struct tc_cake_traffic_stats backlog   [TC_CAKE_MAX_TINS];
++	__u32 interval_us      [TC_CAKE_MAX_TINS];
++	__u32 way_indirect_hits[TC_CAKE_MAX_TINS];
++	__u32 way_misses       [TC_CAKE_MAX_TINS];
++	__u32 way_collisions   [TC_CAKE_MAX_TINS];
++	__u32 peak_delay_us    [TC_CAKE_MAX_TINS]; /* ~= delay to bulk flows */
++	__u32 avge_delay_us    [TC_CAKE_MAX_TINS];
++	__u32 base_delay_us    [TC_CAKE_MAX_TINS]; /* ~= delay to sparse flows */
++	__u16 sparse_flows     [TC_CAKE_MAX_TINS];
++	__u16 bulk_flows       [TC_CAKE_MAX_TINS];
++	__u16 unresponse_flows [TC_CAKE_MAX_TINS]; /* v4 - was u32 last_len  */
++	__u16 spare            [TC_CAKE_MAX_TINS]; /* v4 - split last_len */
++	__u32 max_skblen       [TC_CAKE_MAX_TINS];
++	__u32 capacity_estimate;  /* version 2 */
++	__u32 memory_limit;       /* version 3 */
++	__u32 memory_used;        /* version 3 */
++};
++
+ #endif
+--- a/tc/Makefile
++++ b/tc/Makefile
+@@ -63,6 +63,7 @@ TCMODULES += q_codel.o
+ TCMODULES += q_fq_codel.o
+ TCMODULES += q_fq.o
+ TCMODULES += q_pie.o
++TCMODULES += q_cake.o
+ TCMODULES += q_hhf.o
+ TCMODULES += e_bpf.o
+ 
+--- /dev/null
++++ b/tc/q_cake.c
+@@ -0,0 +1,643 @@
++/*
++ * Common Applications Kept Enhanced  --  CAKE
++ *
++ *  Copyright (C) 2014-2015 Jonathan Morton <chromatix99@gmail.com>
++ *
++ * 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,
++ *    without modification.
++ * 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.
++ * 3. The names of the authors may not be used to endorse or promote products
++ *    derived from this software without specific prior written permission.
++ *
++ * Alternatively, provided that this notice is retained in full, this
++ * software may be distributed under the terms of the GNU General
++ * Public License ("GPL") version 2, in which case the provisions of the
++ * GPL apply INSTEAD OF those given above.
++ *
++ * 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
++ * OWNER 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.
++ *
++ */
++
++#include <stddef.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <syslog.h>
++#include <fcntl.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <string.h>
++
++#include "utils.h"
++#include "tc_util.h"
++
++static void explain(void)
++{
++	fprintf(stderr, "Usage: ... cake [ bandwidth RATE | unlimited* | autorate_ingress ]\n"
++	                "                [ rtt TIME | datacentre | lan | metro | regional | internet* | oceanic | satellite | interplanetary ]\n"
++	                "                [ besteffort | precedence | diffserv8 | diffserv4* ]\n"
++	                "                [ flowblind | srchost | dsthost | hosts | flows* | dual-srchost | dual-dsthost | triple-isolate ] [ nat | nonat* ]\n"
++	                "                [ ptm | atm | noatm* ] [ overhead N | conservative | raw* ]\n"
++	                "                [ memlimit LIMIT ]\n"
++	                "    (* marks defaults)\n");
++}
++
++static int cake_parse_opt(struct qdisc_util *qu, int argc, char **argv,
++			      struct nlmsghdr *n)
++{
++	int unlimited = 0;
++	unsigned bandwidth = 0;
++	unsigned interval = 0;
++	unsigned target = 0;
++	unsigned diffserv = 0;
++	unsigned memlimit = 0;
++	int  overhead = 0;
++	bool overhead_set = false;
++	int flowmode = -1;
++	int nat = -1;
++	int atm = -1;
++	int autorate = -1;
++	struct rtattr *tail;
++
++	while (argc > 0) {
++		if (strcmp(*argv, "bandwidth") == 0) {
++			NEXT_ARG();
++			if (get_rate(&bandwidth, *argv)) {
++				fprintf(stderr, "Illegal \"bandwidth\"\n");
++				return -1;
++			}
++			unlimited = 0;
++			autorate = 0;
++		} else if (strcmp(*argv, "unlimited") == 0) {
++			bandwidth = 0;
++			unlimited = 1;
++			autorate = 0;
++		} else if (strcmp(*argv, "autorate_ingress") == 0) {
++			autorate = 1;
++
++		} else if (strcmp(*argv, "rtt") == 0) {
++			NEXT_ARG();
++			if (get_time(&interval, *argv)) {
++				fprintf(stderr, "Illegal \"rtt\"\n");
++				return -1;
++			}
++			target = interval / 20;
++			if(!target)
++				target = 1;
++		} else if (strcmp(*argv, "datacentre") == 0) {
++			interval = 100;
++			target   =   5;
++		} else if (strcmp(*argv, "lan") == 0) {
++			interval = 1000;
++			target   =   50;
++		} else if (strcmp(*argv, "metro") == 0) {
++			interval = 10000;
++			target   =   500;
++		} else if (strcmp(*argv, "regional") == 0) {
++			interval = 30000;
++			target    = 1500;
++		} else if (strcmp(*argv, "internet") == 0) {
++			interval = 100000;
++			target   =   5000;
++		} else if (strcmp(*argv, "oceanic") == 0) {
++			interval = 300000;
++			target   =  15000;
++		} else if (strcmp(*argv, "satellite") == 0) {
++			interval = 1000000;
++			target   =   50000;
++		} else if (strcmp(*argv, "interplanetary") == 0) {
++			interval = 3600000000U;
++			target   =       5000;
++
++		} else if (strcmp(*argv, "besteffort") == 0) {
++			diffserv = 1;
++		} else if (strcmp(*argv, "precedence") == 0) {
++			diffserv = 2;
++		} else if (strcmp(*argv, "diffserv8") == 0) {
++			diffserv = 3;
++		} else if (strcmp(*argv, "diffserv4") == 0) {
++			diffserv = 4;
++		} else if (strcmp(*argv, "diffserv") == 0) {
++			diffserv = 4;
++		} else if (strcmp(*argv, "diffserv-llt") == 0) {
++			diffserv = 5;
++
++		} else if (strcmp(*argv, "flowblind") == 0) {
++			flowmode = 0;
++		} else if (strcmp(*argv, "srchost") == 0) {
++			flowmode = 1;
++		} else if (strcmp(*argv, "dsthost") == 0) {
++			flowmode = 2;
++		} else if (strcmp(*argv, "hosts") == 0) {
++			flowmode = 3;
++		} else if (strcmp(*argv, "flows") == 0) {
++			flowmode = 4;
++		} else if (strcmp(*argv, "dual-srchost") == 0) {
++			flowmode = 5;
++		} else if (strcmp(*argv, "dual-dsthost") == 0) {
++			flowmode = 6;
++		} else if (strcmp(*argv, "triple-isolate") == 0) {
++			flowmode = 7;
++
++		} else if (strcmp(*argv, "nat") == 0) {
++			nat = 1;
++		} else if (strcmp(*argv, "nonat") == 0) {
++			nat = 0;
++
++		} else if (strcmp(*argv, "ptm") == 0) {
++			atm = 2;
++		} else if (strcmp(*argv, "atm") == 0) {
++			atm = 1;
++		} else if (strcmp(*argv, "noatm") == 0) {
++			atm = 0;
++
++		} else if (strcmp(*argv, "raw") == 0) {
++			atm = 0;
++			overhead = 0;
++			overhead_set = true;
++		} else if (strcmp(*argv, "conservative") == 0) {
++			/*
++			 * Deliberately over-estimate overhead:
++			 * one whole ATM cell plus ATM framing.
++			 * A safe choice if the actual overhead is unknown.
++			 */
++			atm = 1;
++			overhead = 48;
++			overhead_set = true;
++
++		/*
++		 * DOCSIS overhead figures courtesy of Greg White @ CableLabs.
++		 * The "-ip" versions include the Ethernet frame header, in case
++		 * you are shaping an IP interface instead of an Ethernet one.
++		 */
++		} else if (strcmp(*argv, "docsis-downstream-ip") == 0) {
++			atm = 0;
++			overhead += 35;
++			overhead_set = true;
++		} else if (strcmp(*argv, "docsis-downstream") == 0) {
++			atm = 0;
++			overhead += 35 - 14;
++			overhead_set = true;
++		} else if (strcmp(*argv, "docsis-upstream-ip") == 0) {
++			atm = 0;
++			overhead += 28;
++			overhead_set = true;
++		} else if (strcmp(*argv, "docsis-upstream") == 0) {
++			atm = 0;
++			overhead += 28 - 14;
++			overhead_set = true;
++
++		/* Various ADSL framing schemes, all over ATM cells */
++		} else if (strcmp(*argv, "ipoa-vcmux") == 0) {
++			atm = 1;
++			overhead += 8;
++			overhead_set = true;
++		} else if (strcmp(*argv, "ipoa-llcsnap") == 0) {
++			atm = 1;
++			overhead += 16;
++			overhead_set = true;
++		} else if (strcmp(*argv, "bridged-vcmux") == 0) {
++			atm = 1;
++			overhead += 24;
++			overhead_set = true;
++		} else if (strcmp(*argv, "bridged-llcsnap") == 0) {
++			atm = 1;
++			overhead += 32;
++			overhead_set = true;
++		} else if (strcmp(*argv, "pppoa-vcmux") == 0) {
++			atm = 1;
++			overhead += 10;
++			overhead_set = true;
++		} else if (strcmp(*argv, "pppoa-llc") == 0) {
++			atm = 1;
++			overhead += 14;
++			overhead_set = true;
++		} else if (strcmp(*argv, "pppoe-vcmux") == 0) {
++			atm = 1;
++			overhead += 32;
++			overhead_set = true;
++		} else if (strcmp(*argv, "pppoe-llcsnap") == 0) {
++			atm = 1;
++			overhead += 40;
++			overhead_set = true;
++
++		/* Typical VDSL2 framing schemes, both over PTM */
++		/* PTM has 64b/65b coding which absorbs some bandwidth */
++		} else if (strcmp(*argv, "pppoe-ptm") == 0) {
++			atm = 2;
++			overhead += 27;
++			overhead_set = true;
++		} else if (strcmp(*argv, "bridged-ptm") == 0) {
++			atm = 2;
++			overhead += 19;
++			overhead_set = true;
++
++		} else if (strcmp(*argv, "via-ethernet") == 0) {
++			/*
++			 * The above overheads are relative to an IP packet,
++			 * but Linux includes Ethernet framing overhead already
++			 * if we are shaping an Ethernet interface rather than
++			 * an IP interface.
++			 */
++			overhead -= 14;
++			overhead_set = true;
++
++		/* Additional Ethernet-related overheads used by some ISPs */
++		} else if (strcmp(*argv, "ether-phy") == 0) {
++			/* ethernet pre-amble & interframe gap 20 bytes
++			 * Linux will have already accounted for MACs & frame type 14 bytes
++			 * you probably want to add an FCS as well*/
++			overhead += 20;
++			overhead_set = true;
++		} else if (strcmp(*argv, "ether-all") == 0) {
++			/* ethernet pre-amble & interframe gap & FCS
++			 * Linux will have already accounted for MACs & frame type 14 bytes
++			 * you may need to add vlan tag*/
++			overhead += 24;
++			overhead_set = true;
++
++		} else if (strcmp(*argv, "ether-fcs") == 0) {
++			/* Frame Check Sequence */
++			/* we ignore the minimum frame size, because IP packets usually meet it */
++			overhead += 4;
++			overhead_set = true;
++		} else if (strcmp(*argv, "ether-vlan") == 0) {
++			/* 802.1q VLAN tag - may be repeated */
++			overhead += 4;
++			overhead_set = true;
++
++		} else if (strcmp(*argv, "overhead") == 0) {
++			char* p = NULL;
++			NEXT_ARG();
++			overhead = strtol(*argv, &p, 10);
++			if(!p || *p || !*argv || overhead < -64 || overhead > 256) {
++				fprintf(stderr, "Illegal \"overhead\", valid range is -64 to 256\\n");
++				return -1;
++			}
++			overhead_set = true;
++
++		} else if (strcmp(*argv, "memlimit") == 0) {
++			NEXT_ARG();
++			if(get_size(&memlimit, *argv)) {
++				fprintf(stderr, "Illegal value for \"memlimit\": \"%s\"\n", *argv);
++				return -1;
++			}
++
++		} else if (strcmp(*argv, "help") == 0) {
++			explain();
++			return -1;
++		} else {
++			fprintf(stderr, "What is \"%s\"?\n", *argv);
++			explain();
++			return -1;
++		}
++		argc--; argv++;
++	}
++
++	tail = NLMSG_TAIL(n);
++	addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
++	if (bandwidth || unlimited)
++		addattr_l(n, 1024, TCA_CAKE_BASE_RATE, &bandwidth, sizeof(bandwidth));
++	if (diffserv)
++		addattr_l(n, 1024, TCA_CAKE_DIFFSERV_MODE, &diffserv, sizeof(diffserv));
++	if (atm != -1)
++		addattr_l(n, 1024, TCA_CAKE_ATM, &atm, sizeof(atm));
++	if (flowmode != -1)
++		addattr_l(n, 1024, TCA_CAKE_FLOW_MODE, &flowmode, sizeof(flowmode));
++	if (overhead_set)
++		addattr_l(n, 1024, TCA_CAKE_OVERHEAD, &overhead, sizeof(overhead));
++	if (interval)
++		addattr_l(n, 1024, TCA_CAKE_RTT, &interval, sizeof(interval));
++	if (target)
++		addattr_l(n, 1024, TCA_CAKE_TARGET, &target, sizeof(target));
++	if (autorate != -1)
++		addattr_l(n, 1024, TCA_CAKE_AUTORATE, &autorate, sizeof(autorate));
++	if (memlimit)
++		addattr_l(n, 1024, TCA_CAKE_MEMORY, &memlimit, sizeof(memlimit));
++	if (nat != -1)
++		addattr_l(n, 1024, TCA_CAKE_NAT, &nat, sizeof(nat));
++
++	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
++	return 0;
++}
++
++
++static int cake_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
++{
++	struct rtattr *tb[TCA_CAKE_MAX + 1];
++	unsigned bandwidth = 0;
++	unsigned diffserv = 0;
++	unsigned flowmode = 0;
++	unsigned interval = 0;
++	unsigned memlimit = 0;
++	int overhead = 0;
++	int atm = 0;
++	int nat = 0;
++	int autorate = 0;
++	SPRINT_BUF(b1);
++	SPRINT_BUF(b2);
++
++	if (opt == NULL)
++		return 0;
++
++	parse_rtattr_nested(tb, TCA_CAKE_MAX, opt);
++
++	if (tb[TCA_CAKE_BASE_RATE] &&
++	    RTA_PAYLOAD(tb[TCA_CAKE_BASE_RATE]) >= sizeof(__u32)) {
++		bandwidth = rta_getattr_u32(tb[TCA_CAKE_BASE_RATE]);
++		if(bandwidth)
++			fprintf(f, "bandwidth %s ", sprint_rate(bandwidth, b1));
++		else
++			fprintf(f, "unlimited ");
++	}
++	if (tb[TCA_CAKE_AUTORATE] &&
++		RTA_PAYLOAD(tb[TCA_CAKE_AUTORATE]) >= sizeof(__u32)) {
++		autorate = rta_getattr_u32(tb[TCA_CAKE_AUTORATE]);
++		if(autorate == 1)
++			fprintf(f, "autorate_ingress ");
++		else if(autorate)
++			fprintf(f, "(?autorate?) ");
++	}
++	if (tb[TCA_CAKE_DIFFSERV_MODE] &&
++	    RTA_PAYLOAD(tb[TCA_CAKE_DIFFSERV_MODE]) >= sizeof(__u32)) {
++		diffserv = rta_getattr_u32(tb[TCA_CAKE_DIFFSERV_MODE]);
++		switch(diffserv) {
++		case 1:
++			fprintf(f, "besteffort ");
++			break;
++		case 2:
++			fprintf(f, "precedence ");
++			break;
++		case 3:
++			fprintf(f, "diffserv8 ");
++			break;
++		case 4:
++			fprintf(f, "diffserv4 ");
++			break;
++		case 5:
++			fprintf(f, "diffserv-llt ");
++			break;
++		default:
++			fprintf(f, "(?diffserv?) ");
++			break;
++		};
++	}
++	if (tb[TCA_CAKE_FLOW_MODE] &&
++	    RTA_PAYLOAD(tb[TCA_CAKE_FLOW_MODE]) >= sizeof(__u32)) {
++		flowmode = rta_getattr_u32(tb[TCA_CAKE_FLOW_MODE]);
++		nat = !!(flowmode & 64);
++		flowmode &= ~64;
++		switch(flowmode) {
++		case 0:
++			fprintf(f, "flowblind ");
++			break;
++		case 1:
++			fprintf(f, "srchost ");
++			break;
++		case 2:
++			fprintf(f, "dsthost ");
++			break;
++		case 3:
++			fprintf(f, "hosts ");
++			break;
++		case 4:
++			fprintf(f, "flows ");
++			break;
++		case 5:
++			fprintf(f, "dual-srchost ");
++			break;
++		case 6:
++			fprintf(f, "dual-dsthost ");
++			break;
++		case 7:
++			fprintf(f, "triple-isolate ");
++			break;
++		default:
++			fprintf(f, "(?flowmode?) ");
++			break;
++		};
++
++		if(nat)
++			fprintf(f, "nat ");
++	}
++	if (tb[TCA_CAKE_ATM] &&
++	    RTA_PAYLOAD(tb[TCA_CAKE_ATM]) >= sizeof(__u32)) {
++		atm = rta_getattr_u32(tb[TCA_CAKE_ATM]);
++	}
++	if (tb[TCA_CAKE_OVERHEAD] &&
++	    RTA_PAYLOAD(tb[TCA_CAKE_OVERHEAD]) >= sizeof(__u32)) {
++		overhead = rta_getattr_u32(tb[TCA_CAKE_OVERHEAD]);
++	}
++	if (tb[TCA_CAKE_RTT] &&
++	    RTA_PAYLOAD(tb[TCA_CAKE_RTT]) >= sizeof(__u32)) {
++		interval = rta_getattr_u32(tb[TCA_CAKE_RTT]);
++	}
++
++	if (interval)
++		fprintf(f, "rtt %s ", sprint_time(interval, b2));
++
++	if (atm == 1)
++		fprintf(f, "atm ");
++	else if (atm == 2)
++		fprintf(f, "ptm ");
++	else if (overhead)
++		fprintf(f, "noatm ");
++
++	if (overhead || atm)
++		fprintf(f, "overhead %d ", overhead);
++
++	if (!atm && !overhead)
++		fprintf(f, "raw ");
++
++	if (memlimit)
++		fprintf(f, "memlimit %s", sprint_size(memlimit, b1));
++
++	return 0;
++}
++
++static int cake_print_xstats(struct qdisc_util *qu, FILE *f,
++				 struct rtattr *xstats)
++{
++	/* fq_codel stats format borrowed */
++	struct tc_fq_codel_xstats *st;
++	struct tc_cake_xstats     *stnc;
++	SPRINT_BUF(b1);
++	SPRINT_BUF(b2);
++
++	if (xstats == NULL)
++		return 0;
++
++	if (RTA_PAYLOAD(xstats) < sizeof(st->type))
++		return -1;
++
++	st   = RTA_DATA(xstats);
++	stnc = RTA_DATA(xstats);
++
++	if (st->type == TCA_FQ_CODEL_XSTATS_QDISC && RTA_PAYLOAD(xstats) >= sizeof(*st)) {
++		fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u",
++			st->qdisc_stats.maxpacket,
++			st->qdisc_stats.drop_overlimit,
++			st->qdisc_stats.new_flow_count,
++			st->qdisc_stats.ecn_mark);
++		fprintf(f, "\n  new_flows_len %u old_flows_len %u",
++			st->qdisc_stats.new_flows_len,
++			st->qdisc_stats.old_flows_len);
++	} else if (st->type == TCA_FQ_CODEL_XSTATS_CLASS && RTA_PAYLOAD(xstats) >= sizeof(*st)) {
++		fprintf(f, "  deficit %d count %u lastcount %u ldelay %s",
++			st->class_stats.deficit,
++			st->class_stats.count,
++			st->class_stats.lastcount,
++			sprint_time(st->class_stats.ldelay, b1));
++		if (st->class_stats.dropping) {
++			fprintf(f, " dropping");
++			if (st->class_stats.drop_next < 0)
++				fprintf(f, " drop_next -%s",
++					sprint_time(-st->class_stats.drop_next, b1));
++			else
++				fprintf(f, " drop_next %s",
++					sprint_time(st->class_stats.drop_next, b1));
++		}
++	} else if (stnc->version >= 1 && stnc->version < 0xFF
++				&& stnc->max_tins == TC_CAKE_MAX_TINS
++				&& RTA_PAYLOAD(xstats) >= offsetof(struct tc_cake_xstats, capacity_estimate))
++	{
++		int i;
++
++		if(stnc->version >= 3)
++			fprintf(f, " memory used: %s of %s\n", sprint_size(stnc->memory_used, b1), sprint_size(stnc->memory_limit, b2));
++
++		if(stnc->version >= 2)
++			fprintf(f, " capacity estimate: %s\n", sprint_rate(stnc->capacity_estimate, b1));
++
++		switch(stnc->tin_cnt) {
++		case 4:
++			fprintf(f, "                 Bulk   Best Effort      Video       Voice\n");
++			break;
++
++		case 5:
++			fprintf(f, "              Low Loss  Best Effort   Low Delay       Bulk  Net Control\n");
++			break;
++
++		default:
++			fprintf(f, "          ");
++			for(i=0; i < stnc->tin_cnt; i++)
++				fprintf(f, "       Tin %u", i);
++			fprintf(f, "\n");
++		};
++
++		fprintf(f, "  thresh  ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12s", sprint_rate(stnc->threshold_rate[i], b1));
++		fprintf(f, "\n");
++
++		fprintf(f, "  target  ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12s", sprint_time(stnc->target_us[i], b1));
++		fprintf(f, "\n");
++
++		fprintf(f, "  interval");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12s", sprint_time(stnc->interval_us[i], b1));
++		fprintf(f, "\n");
++
++		fprintf(f, "  pk_delay");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12s", sprint_time(stnc->peak_delay_us[i], b1));
++		fprintf(f, "\n");
++
++		fprintf(f, "  av_delay");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12s", sprint_time(stnc->avge_delay_us[i], b1));
++		fprintf(f, "\n");
++
++		fprintf(f, "  sp_delay");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12s", sprint_time(stnc->base_delay_us[i], b1));
++		fprintf(f, "\n");
++
++		fprintf(f, "  pkts    ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->sent[i].packets);
++		fprintf(f, "\n");
++
++		fprintf(f, "  bytes   ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12llu", stnc->sent[i].bytes);
++		fprintf(f, "\n");
++
++		fprintf(f, "  way_inds");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->way_indirect_hits[i]);
++		fprintf(f, "\n");
++
++		fprintf(f, "  way_miss");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->way_misses[i]);
++		fprintf(f, "\n");
++
++		fprintf(f, "  way_cols");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->way_collisions[i]);
++		fprintf(f, "\n");
++
++		fprintf(f, "  drops   ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->dropped[i].packets);
++		fprintf(f, "\n");
++
++		fprintf(f, "  marks   ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->ecn_marked[i].packets);
++		fprintf(f, "\n");
++
++		fprintf(f, "  sp_flows");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->sparse_flows[i]);
++		fprintf(f, "\n");
++
++		fprintf(f, "  bk_flows");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->bulk_flows[i]);
++		fprintf(f, "\n");
++
++		if(stnc->version >= 4) {
++			fprintf(f, "  un_flows");
++			for(i=0; i < stnc->tin_cnt; i++)
++				fprintf(f, "%12u", stnc->unresponse_flows[i]);
++			fprintf(f, "\n");
++		}
++
++		fprintf(f, "  max_len ");
++		for(i=0; i < stnc->tin_cnt; i++)
++			fprintf(f, "%12u", stnc->max_skblen[i]);
++		fprintf(f, "\n");
++	} else {
++		return -1;
++	}
++	return 0;
++}
++
++struct qdisc_util cake_qdisc_util = {
++	.id		= "cake",
++	.parse_qopt	= cake_parse_opt,
++	.print_qopt	= cake_print_opt,
++	.print_xstats	= cake_print_xstats,
++};
diff --git a/package/network/utils/ipset/Makefile b/package/network/utils/ipset/Makefile
new file mode 100644
index 0000000000..13d1d3d649
--- /dev/null
+++ b/package/network/utils/ipset/Makefile
@@ -0,0 +1,60 @@
+
+# Copyright (C) 2009-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=ipset
+PKG_VERSION:=6.30
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://ipset.netfilter.org
+PKG_MD5SUM:=41c32e3b884ec714f0aac95e7675f9d1
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ipset
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS+= +kmod-ipt-ipset +libmnl
+  TITLE:=IPset administration utility
+  URL:=http://ipset.netfilter.org/
+endef
+
+CONFIGURE_ARGS += \
+	--with-kbuild="$(LINUX_DIR)"
+
+MAKE_FLAGS += \
+	ARCH="$(LINUX_KARCH)" \
+	SHELL="$(BASH)"
+
+define Build/Compile
+	$(call Build/Compile/Default)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include $(1)/usr/lib $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libipset $(1)/usr/include/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libipset.{a,so*} $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/lib/libipset.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/ipset/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/ipset $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libipset*.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,ipset))
diff --git a/package/network/utils/iptables/Makefile b/package/network/utils/iptables/Makefile
new file mode 100644
index 0000000000..6f7529c736
--- /dev/null
+++ b/package/network/utils/iptables/Makefile
@@ -0,0 +1,558 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=iptables
+PKG_VERSION:=1.4.21
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://www.netfilter.org/projects/iptables/files \
+	ftp://ftp.be.netfilter.org/pub/netfilter/iptables/ \
+	ftp://ftp.de.netfilter.org/pub/netfilter/iptables/ \
+	ftp://ftp.no.netfilter.org/pub/netfilter/iptables/
+PKG_MD5SUM:=536d048c8e8eeebcd9757d0863ebb0c0
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+ifeq ($(DUMP),)
+  -include $(LINUX_DIR)/.config
+  include $(INCLUDE_DIR)/netfilter.mk
+  STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell $(SH_FUNC) grep 'NETFILTER' $(LINUX_DIR)/.config | md5s)
+endif
+
+
+define Package/iptables/Default
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Firewall
+  URL:=http://netfilter.org/
+endef
+
+define Package/iptables/Module
+$(call Package/iptables/Default)
+  DEPENDS:=iptables $(1)
+endef
+
+define Package/iptables
+$(call Package/iptables/Default)
+  TITLE:=IP firewall administration tool
+  MENU:=1
+  DEPENDS+= +kmod-ipt-core +libip4tc +IPV6:libip6tc +libxtables
+endef
+
+define Package/iptables/description
+IP firewall administration tool.
+
+ Matches:
+  - icmp
+  - tcp
+  - udp
+  - comment
+  - conntrack
+  - limit
+  - mac
+  - mark
+  - multiport
+  - set
+  - state
+  - time
+
+ Targets:
+  - ACCEPT
+  - CT
+  - DNAT
+  - DROP
+  - REJECT
+  - LOG
+  - MARK
+  - MASQUERADE
+  - REDIRECT
+  - SET
+  - SNAT
+  - TCPMSS
+
+ Tables:
+  - filter
+  - mangle
+  - nat
+  - raw
+
+endef
+
+define Package/iptables-mod-conntrack-extra
+$(call Package/iptables/Module, +kmod-ipt-conntrack-extra)
+  TITLE:=Extra connection tracking extensions
+endef
+
+define Package/iptables-mod-conntrack-extra/description
+Extra iptables extensions for connection tracking.
+
+ Matches:
+  - connbytes
+  - connlimit
+  - connmark
+  - recent
+  - helper
+
+ Targets:
+  - CONNMARK
+
+endef
+
+define Package/iptables-mod-filter
+$(call Package/iptables/Module, +kmod-ipt-filter)
+  TITLE:=Content inspection extensions
+endef
+
+define Package/iptables-mod-filter/description
+iptables extensions for packet content inspection.
+Includes support for:
+
+ Matches:
+  - string
+
+endef
+
+define Package/iptables-mod-ipopt
+$(call Package/iptables/Module, +kmod-ipt-ipopt)
+  TITLE:=IP/Packet option extensions
+endef
+
+define Package/iptables-mod-ipopt/description
+iptables extensions for matching/changing IP packet options.
+
+ Matches:
+  - dscp
+  - ecn
+  - length
+  - statistic
+  - tcpmss
+  - unclean
+  - hl
+
+ Targets:
+  - DSCP
+  - CLASSIFY
+  - ECN
+  - HL
+
+endef
+
+define Package/iptables-mod-ipsec
+$(call Package/iptables/Module, +kmod-ipt-ipsec)
+  TITLE:=IPsec extensions
+endef
+
+define Package/iptables-mod-ipsec/description
+iptables extensions for matching ipsec traffic.
+
+ Matches:
+  - ah
+  - esp
+  - policy
+
+endef
+
+define Package/iptables-mod-nat-extra
+$(call Package/iptables/Module, +kmod-ipt-nat-extra)
+  TITLE:=Extra NAT extensions
+endef
+
+define Package/iptables-mod-nat-extra/description
+iptables extensions for extra NAT targets.
+
+ Targets:
+  - MIRROR
+  - NETMAP
+endef
+
+define Package/iptables-mod-ulog
+$(call Package/iptables/Module, +kmod-ipt-ulog)
+  TITLE:=user-space packet logging
+endef
+
+define Package/iptables-mod-ulog/description
+iptables extensions for user-space packet logging.
+
+ Targets:
+  - ULOG
+
+endef
+
+define Package/iptables-mod-nflog
+$(call Package/iptables/Module, +kmod-nfnetlink-log +kmod-ipt-nflog)
+  TITLE:=Netfilter NFLOG target
+endef
+
+define Package/iptables-mod-nflog/description
+ iptables extension for user-space logging via NFNETLINK.
+
+ Includes:
+  - libxt_NFLOG
+
+endef
+
+define Package/iptables-mod-nfqueue
+$(call Package/iptables/Module, +kmod-nfnetlink-queue +kmod-ipt-nfqueue)
+  TITLE:=Netfilter NFQUEUE target
+endef
+
+define Package/iptables-mod-nfqueue/description
+ iptables extension for user-space queuing via NFNETLINK.
+
+ Includes:
+  - libxt_NFQUEUE
+
+endef
+
+define Package/iptables-mod-hashlimit
+$(call Package/iptables/Module, +kmod-ipt-hashlimit)
+  TITLE:=hashlimit matching
+endef
+
+define Package/iptables-mod-hashlimit/description
+iptables extensions for hashlimit matching
+
+ Matches:
+  - hashlimit
+
+endef
+
+define Package/iptables-mod-iprange
+$(call Package/iptables/Module, +kmod-ipt-iprange)
+  TITLE:=IP range extension
+endef
+
+define Package/iptables-mod-iprange/description
+iptables extensions for matching ip ranges.
+
+ Matches:
+  - iprange
+
+endef
+
+define Package/iptables-mod-cluster
+$(call Package/iptables/Module, +kmod-ipt-cluster)
+  TITLE:=Match cluster extension
+endef
+
+define Package/iptables-mod-cluster/description
+iptables extensions for matching cluster.
+
+ Netfilter (IPv4/IPv6) module for matching cluster
+ This option allows you to build work-load-sharing clusters of
+ network servers/stateful firewalls without having a dedicated
+ load-balancing router/server/switch. Basically, this match returns
+ true when the packet must be handled by this cluster node. Thus,
+ all nodes see all packets and this match decides which node handles
+ what packets. The work-load sharing algorithm is based on source
+ address hashing.
+
+ This module is usable for ipv4 and ipv6.
+
+ If you select it, it enables kmod-ipt-cluster.
+
+ see `iptables -m cluster --help` for more information.
+endef
+
+define Package/iptables-mod-clusterip
+$(call Package/iptables/Module, +kmod-ipt-clusterip)
+  TITLE:=Clusterip extension
+endef
+
+define Package/iptables-mod-clusterip/description
+iptables extensions for CLUSTERIP.
+ The CLUSTERIP target allows you to build load-balancing clusters of
+ network servers without having a dedicated load-balancing
+ router/server/switch.
+
+ If you select it, it enables kmod-ipt-clusterip.
+
+ see `iptables -j CLUSTERIP --help` for more information.
+endef
+
+define Package/iptables-mod-extra
+$(call Package/iptables/Module, +kmod-ipt-extra)
+  TITLE:=Other extra iptables extensions
+endef
+
+define Package/iptables-mod-extra/description
+Other extra iptables extensions.
+
+ Matches:
+  - addrtype
+  - condition
+  - owner
+  - physdev (if ebtables is enabled)
+  - pkttype
+  - quota
+
+endef
+
+define Package/iptables-mod-led
+$(call Package/iptables/Module, +kmod-ipt-led)
+  TITLE:=LED trigger iptables extension
+endef
+
+define Package/iptables-mod-led/description
+iptables extension for triggering a LED.
+
+ Targets:
+  - LED
+
+endef
+
+define Package/iptables-mod-tproxy
+$(call Package/iptables/Module, +kmod-ipt-tproxy)
+  TITLE:=Transparent proxy iptables extensions
+endef
+
+define Package/iptables-mod-tproxy/description
+Transparent proxy iptables extensions.
+
+ Matches:
+  - socket
+
+ Targets:
+  - TPROXY
+
+endef
+
+define Package/iptables-mod-tee
+$(call Package/iptables/Module, +kmod-ipt-tee)
+  TITLE:=TEE iptables extensions
+endef
+
+define Package/iptables-mod-tee/description
+TEE iptables extensions.
+
+ Targets:
+  - TEE
+
+endef
+
+define Package/iptables-mod-u32
+$(call Package/iptables/Module, +kmod-ipt-u32)
+  TITLE:=U32 iptables extensions
+endef
+
+define Package/iptables-mod-u32/description
+U32 iptables extensions.
+
+ Matches:
+  - u32
+
+endef
+
+define Package/ip6tables
+$(call Package/iptables/Default)
+  DEPENDS:=@IPV6 +kmod-ip6tables +iptables
+  CATEGORY:=Network
+  TITLE:=IPv6 firewall administration tool
+  MENU:=1
+endef
+
+
+define Package/ip6tables-extra
+$(call Package/iptables/Default)
+  DEPENDS:=ip6tables +kmod-ip6tables-extra
+  TITLE:=IPv6 header matching modules
+endef
+
+define Package/ip6tables-mod-extra/description
+iptables header matching modules for IPv6
+endef
+
+define Package/ip6tables-mod-nat
+$(call Package/iptables/Default)
+  DEPENDS:=ip6tables +kmod-ipt-nat6
+  TITLE:=IPv6 NAT extensions
+endef
+
+define Package/ip6tables-mod-nat/description
+iptables extensions for IPv6-NAT targets.
+endef
+
+define Package/libiptc
+$(call Package/iptables/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libip4tc +libip6tc +libxtables
+  TITLE:=IPv4/IPv6 firewall - shared libiptc library (compatibility stub)
+endef
+
+define Package/libip4tc
+$(call Package/iptables/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=IPv4 firewall - shared libiptc library
+  DEPENDS:=+libxtables
+endef
+
+define Package/libip6tc
+$(call Package/iptables/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=IPv6 firewall - shared libiptc library
+  DEPENDS:=+libxtables
+endef
+
+define Package/libxtables
+ $(call Package/iptables/Default)
+ SECTION:=libs
+ CATEGORY:=Libraries
+ TITLE:=IPv4/IPv6 firewall - shared xtables library
+endef
+
+TARGET_CPPFLAGS := \
+	-I$(PKG_BUILD_DIR)/include \
+	-I$(LINUX_DIR)/user_headers/include \
+	$(TARGET_CPPFLAGS)
+
+TARGET_CFLAGS += \
+	-I$(PKG_BUILD_DIR)/include \
+	-I$(LINUX_DIR)/user_headers/include \
+	-ffunction-sections -fdata-sections \
+	-DNO_LEGACY
+
+TARGET_LDFLAGS += \
+	-Wl,--gc-sections
+
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-devel \
+	--with-kernel="$(LINUX_DIR)/user_headers" \
+	--with-xtlibdir=/usr/lib/iptables \
+	--enable-static \
+	$(if $(CONFIG_IPV6),,--disable-ipv6)
+
+MAKE_FLAGS := \
+	$(TARGET_CONFIGURE_OPTS) \
+	COPT_FLAGS="$(TARGET_CFLAGS)" \
+	KERNEL_DIR="$(LINUX_DIR)/user_headers/" PREFIX=/usr \
+	KBUILD_OUTPUT="$(LINUX_DIR)" \
+	BUILTIN_MODULES="$(patsubst ip6t_%,%,$(patsubst ipt_%,%,$(patsubst xt_%,%,$(IPT_BUILTIN) $(IPT_CONNTRACK-m) $(IPT_NAT-m))))"
+
+ifneq ($(wildcard $(PKG_BUILD_DIR)/.config_*),$(subst .configured_,.config_,$(STAMP_CONFIGURED)))
+  define Build/Configure/rebuild
+	$(FIND) $(PKG_BUILD_DIR) -name \*.o -or -name \*.\?o -or -name \*.a | $(XARGS) rm -f
+	rm -f $(PKG_BUILD_DIR)/.config_*
+	rm -f $(PKG_BUILD_DIR)/.configured_*
+	touch $(subst .configured_,.config_,$(STAMP_CONFIGURED))
+  endef
+endif
+
+define Build/Configure
+$(Build/Configure/rebuild)
+$(Build/Configure/Default)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(INSTALL_DIR) $(1)/usr/include/iptables
+	$(INSTALL_DIR) $(1)/usr/include/net/netfilter
+
+	# XXX: iptables header fixup, some headers are not installed by iptables anymore
+	$(CP) $(PKG_BUILD_DIR)/include/iptables/*.h $(1)/usr/include/iptables/
+	$(CP) $(PKG_BUILD_DIR)/include/iptables.h $(1)/usr/include/
+	$(CP) $(PKG_BUILD_DIR)/include/ip6tables.h $(1)/usr/include/
+	$(CP) $(PKG_BUILD_DIR)/include/libipulog $(1)/usr/include/
+	$(CP) $(PKG_BUILD_DIR)/include/libiptc $(1)/usr/include/
+
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libxtables.so* $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libip*tc.so* $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/xtables.pc $(1)/usr/lib/pkgconfig/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libip*tc.pc $(1)/usr/lib/pkgconfig/
+
+	# XXX: needed by firewall3
+	$(CP) $(PKG_BUILD_DIR)/extensions/libiptext*.so $(1)/usr/lib/
+endef
+
+define Package/iptables/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/xtables-multi $(1)/usr/sbin/
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/iptables{,-restore,-save} $(1)/usr/sbin/
+	$(INSTALL_DIR) $(1)/usr/lib/iptables
+endef
+
+define Package/ip6tables/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/ip6tables{,-restore,-save} $(1)/usr/sbin/
+endef
+
+define Package/libiptc/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libiptc.so* $(1)/usr/lib/
+endef
+
+define Package/libip4tc/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libip4tc.so* $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/extensions/libiptext4.so $(1)/usr/lib/
+endef
+
+define Package/libip6tc/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libip6tc.so* $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/extensions/libiptext6.so $(1)/usr/lib/
+endef
+
+define Package/libxtables/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libxtables.so* $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/extensions/libiptext.so $(1)/usr/lib/
+endef
+
+define BuildPlugin
+  define Package/$(1)/install
+	$(INSTALL_DIR) $$(1)/usr/lib/iptables
+	for m in $(patsubst xt_%,ipt_%,$(2)) $(patsubst ipt_%,xt_%,$(2)) $(patsubst xt_%,ip6t_%,$(2)) $(patsubst ip6t_%,xt_%,$(2)); do \
+		if [ -f $(PKG_INSTALL_DIR)/usr/lib/iptables/lib$$$$$$$${m}.so ]; then \
+			$(CP) $(PKG_INSTALL_DIR)/usr/lib/iptables/lib$$$$$$$${m}.so $$(1)/usr/lib/iptables/ ; \
+		fi; \
+	done
+	$(3)
+  endef
+
+  $$(eval $$(call BuildPackage,$(1)))
+endef
+
+$(eval $(call BuildPackage,iptables))
+$(eval $(call BuildPlugin,iptables-mod-conntrack-extra,$(IPT_CONNTRACK_EXTRA-m)))
+$(eval $(call BuildPlugin,iptables-mod-extra,$(IPT_EXTRA-m)))
+$(eval $(call BuildPlugin,iptables-mod-filter,$(IPT_FILTER-m)))
+$(eval $(call BuildPlugin,iptables-mod-ipopt,$(IPT_IPOPT-m)))
+$(eval $(call BuildPlugin,iptables-mod-ipsec,$(IPT_IPSEC-m)))
+$(eval $(call BuildPlugin,iptables-mod-nat-extra,$(IPT_NAT_EXTRA-m)))
+$(eval $(call BuildPlugin,iptables-mod-iprange,$(IPT_IPRANGE-m)))
+$(eval $(call BuildPlugin,iptables-mod-cluster,$(IPT_CLUSTER-m)))
+$(eval $(call BuildPlugin,iptables-mod-clusterip,$(IPT_CLUSTERIP-m)))
+$(eval $(call BuildPlugin,iptables-mod-ulog,$(IPT_ULOG-m)))
+$(eval $(call BuildPlugin,iptables-mod-hashlimit,$(IPT_HASHLIMIT-m)))
+$(eval $(call BuildPlugin,iptables-mod-led,$(IPT_LED-m)))
+$(eval $(call BuildPlugin,iptables-mod-tproxy,$(IPT_TPROXY-m)))
+$(eval $(call BuildPlugin,iptables-mod-tee,$(IPT_TEE-m)))
+$(eval $(call BuildPlugin,iptables-mod-u32,$(IPT_U32-m)))
+$(eval $(call BuildPlugin,iptables-mod-nflog,$(IPT_NFLOG-m)))
+$(eval $(call BuildPlugin,iptables-mod-nfqueue,$(IPT_NFQUEUE-m)))
+$(eval $(call BuildPackage,ip6tables))
+$(eval $(call BuildPlugin,ip6tables-extra,$(IPT_IPV6_EXTRA-m)))
+$(eval $(call BuildPlugin,ip6tables-mod-nat,$(IPT_NAT6-m)))
+$(eval $(call BuildPackage,libiptc))
+$(eval $(call BuildPackage,libip4tc))
+$(eval $(call BuildPackage,libip6tc))
+$(eval $(call BuildPackage,libxtables))
diff --git a/package/network/utils/iptables/patches/020-iptables-disable-modprobe.patch b/package/network/utils/iptables/patches/020-iptables-disable-modprobe.patch
new file mode 100644
index 0000000000..2b6c57ec9e
--- /dev/null
+++ b/package/network/utils/iptables/patches/020-iptables-disable-modprobe.patch
@@ -0,0 +1,18 @@
+--- a/libxtables/xtables.c
++++ b/libxtables/xtables.c
+@@ -336,6 +336,7 @@ static char *get_modprobe(void)
+ 
+ int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
+ {
++#if 0
+ 	char *buf = NULL;
+ 	char *argv[4];
+ 	int status;
+@@ -380,6 +381,7 @@ int xtables_insmod(const char *modname, 
+ 	free(buf);
+ 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ 		return 0;
++#endif
+ 	return -1;
+ }
+ 
diff --git a/package/network/utils/iptables/patches/030-no-libnfnetlink.patch b/package/network/utils/iptables/patches/030-no-libnfnetlink.patch
new file mode 100644
index 0000000000..50542ac0b5
--- /dev/null
+++ b/package/network/utils/iptables/patches/030-no-libnfnetlink.patch
@@ -0,0 +1,94 @@
+--- a/configure
++++ b/configure
+@@ -12367,77 +12367,7 @@ fi
+ fi
+ 
+ 
+-pkg_failed=no
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnfnetlink" >&5
+-$as_echo_n "checking for libnfnetlink... " >&6; }
+-
+-if test -n "$libnfnetlink_CFLAGS"; then
+-    pkg_cv_libnfnetlink_CFLAGS="$libnfnetlink_CFLAGS"
+- elif test -n "$PKG_CONFIG"; then
+-    if test -n "$PKG_CONFIG" && \
+-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnfnetlink >= 1.0\""; } >&5
+-  ($PKG_CONFIG --exists --print-errors "libnfnetlink >= 1.0") 2>&5
+-  ac_status=$?
+-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+-  test $ac_status = 0; }; then
+-  pkg_cv_libnfnetlink_CFLAGS=`$PKG_CONFIG --cflags "libnfnetlink >= 1.0" 2>/dev/null`
+-		      test "x$?" != "x0" && pkg_failed=yes
+-else
+-  pkg_failed=yes
+-fi
+- else
+-    pkg_failed=untried
+-fi
+-if test -n "$libnfnetlink_LIBS"; then
+-    pkg_cv_libnfnetlink_LIBS="$libnfnetlink_LIBS"
+- elif test -n "$PKG_CONFIG"; then
+-    if test -n "$PKG_CONFIG" && \
+-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnfnetlink >= 1.0\""; } >&5
+-  ($PKG_CONFIG --exists --print-errors "libnfnetlink >= 1.0") 2>&5
+-  ac_status=$?
+-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+-  test $ac_status = 0; }; then
+-  pkg_cv_libnfnetlink_LIBS=`$PKG_CONFIG --libs "libnfnetlink >= 1.0" 2>/dev/null`
+-		      test "x$?" != "x0" && pkg_failed=yes
+-else
+-  pkg_failed=yes
+-fi
+- else
+-    pkg_failed=untried
+-fi
+-
+-
+-
+-if test $pkg_failed = yes; then
+-   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+-$as_echo "no" >&6; }
+-
+-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+-        _pkg_short_errors_supported=yes
+-else
+-        _pkg_short_errors_supported=no
+-fi
+-        if test $_pkg_short_errors_supported = yes; then
+-	        libnfnetlink_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnfnetlink >= 1.0" 2>&1`
+-        else
+-	        libnfnetlink_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnfnetlink >= 1.0" 2>&1`
+-        fi
+-	# Put the nasty error message in config.log where it belongs
+-	echo "$libnfnetlink_PKG_ERRORS" >&5
+-
+-	nfnetlink=0
+-elif test $pkg_failed = untried; then
+-     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+-$as_echo "no" >&6; }
+-	nfnetlink=0
+-else
+-	libnfnetlink_CFLAGS=$pkg_cv_libnfnetlink_CFLAGS
+-	libnfnetlink_LIBS=$pkg_cv_libnfnetlink_LIBS
+-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+-$as_echo "yes" >&6; }
+-	nfnetlink=1
+-fi
+- if test "$nfnetlink" = 1; then
++if false; then
+   HAVE_LIBNFNETLINK_TRUE=
+   HAVE_LIBNFNETLINK_FALSE='#'
+ else
+--- a/configure.ac
++++ b/configure.ac
+@@ -111,9 +111,7 @@ if test "x$enable_bpfc" = "xyes" || test
+ 	AC_CHECK_LIB(pcap, pcap_compile,, AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool))
+ fi
+ 
+-PKG_CHECK_MODULES([libnfnetlink], [libnfnetlink >= 1.0],
+-	[nfnetlink=1], [nfnetlink=0])
+-AM_CONDITIONAL([HAVE_LIBNFNETLINK], [test "$nfnetlink" = 1])
++AM_CONDITIONAL([HAVE_LIBNFNETLINK], [false])
+ 
+ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
+ 	-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
diff --git a/package/network/utils/iptables/patches/050-optional-xml.patch b/package/network/utils/iptables/patches/050-optional-xml.patch
new file mode 100644
index 0000000000..11311ddb47
--- /dev/null
+++ b/package/network/utils/iptables/patches/050-optional-xml.patch
@@ -0,0 +1,13 @@
+--- a/iptables/xtables-multi.c
++++ b/iptables/xtables-multi.c
+@@ -22,8 +22,10 @@ static const struct subcommand multi_sub
+ 	{"iptables-restore",    iptables_restore_main},
+ 	{"restore4",            iptables_restore_main},
+ #endif
++#ifdef ENABLE_XML
+ 	{"iptables-xml",        iptables_xml_main},
+ 	{"xml",                 iptables_xml_main},
++#endif
+ #ifdef ENABLE_IPV6
+ 	{"ip6tables",           ip6tables_main},
+ 	{"main6",               ip6tables_main},
diff --git a/package/network/utils/iptables/patches/100-bash-location.patch b/package/network/utils/iptables/patches/100-bash-location.patch
new file mode 100644
index 0000000000..02ee45ba1e
--- /dev/null
+++ b/package/network/utils/iptables/patches/100-bash-location.patch
@@ -0,0 +1,8 @@
+--- a/iptables/iptables-apply
++++ b/iptables/iptables-apply
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!/usr/bin/env bash
+ #
+ # iptables-apply -- a safer way to update iptables remotely
+ #
diff --git a/package/network/utils/iptables/patches/200-configurable_builtin.patch b/package/network/utils/iptables/patches/200-configurable_builtin.patch
new file mode 100644
index 0000000000..d35bc5a85d
--- /dev/null
+++ b/package/network/utils/iptables/patches/200-configurable_builtin.patch
@@ -0,0 +1,60 @@
+--- a/extensions/GNUmakefile.in
++++ b/extensions/GNUmakefile.in
+@@ -45,9 +45,24 @@ pfx_symlinks  := NOTRACK state
+ pfx_build_mod := $(filter-out @blacklist_modules@,${pfx_build_mod})
+ pf4_build_mod := $(filter-out @blacklist_modules@,${pf4_build_mod})
+ pf6_build_mod := $(filter-out @blacklist_modules@,${pf6_build_mod})
+-pfx_objs      := $(patsubst %,libxt_%.o,${pfx_build_mod})
+-pf4_objs      := $(patsubst %,libipt_%.o,${pf4_build_mod})
+-pf6_objs      := $(patsubst %,libip6t_%.o,${pf6_build_mod})
++
++ifdef BUILTIN_MODULES
++pfx_build_static := $(filter $(BUILTIN_MODULES),${pfx_build_mod})
++pf4_build_static := $(filter $(BUILTIN_MODULES),${pf4_build_mod})
++pf6_build_static := $(filter $(BUILTIN_MODULES),${pf6_build_mod})
++else
++@ENABLE_STATIC_TRUE@ pfx_build_static := $(pfx_build_mod)
++@ENABLE_STATIC_TRUE@ pf4_build_static := $(pf4_build_mod)
++@ENABLE_STATIC_TRUE@ pf6_build_static := $(pf6_build_mod)
++endif
++
++pfx_build_mod := $(filter-out $(pfx_build_static),$(pfx_build_mod))
++pf4_build_mod := $(filter-out $(pf4_build_static),$(pf4_build_mod))
++pf6_build_mod := $(filter-out $(pf6_build_static),$(pf6_build_mod))
++
++pfx_objs      := $(patsubst %,libxt_%.o,${pfx_build_static})
++pf4_objs      := $(patsubst %,libipt_%.o,${pf4_build_static})
++pf6_objs      := $(patsubst %,libip6t_%.o,${pf6_build_static})
+ pfx_solibs    := $(patsubst %,libxt_%.so,${pfx_build_mod} ${pfx_symlinks})
+ pf4_solibs    := $(patsubst %,libipt_%.so,${pf4_build_mod})
+ pf6_solibs    := $(patsubst %,libip6t_%.so,${pf6_build_mod})
+@@ -58,11 +73,11 @@ pf6_solibs    := $(patsubst %,libip6t_%.
+ #
+ targets := libext.a libext4.a libext6.a matches.man targets.man
+ targets_install :=
+-@ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs}
+-@ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs}
+-@ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs}
+-@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
+-@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
++libext_objs := ${pfx_objs}
++libext4_objs := ${pf4_objs}
++libext6_objs := ${pf6_objs}
++targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
++targets_install := $(strip ${targets_install} ${pfx_solibs} ${pf4_solibs} ${pf6_solibs})
+ 
+ .SECONDARY:
+ 
+@@ -126,9 +141,9 @@ libext4.a: initext4.o ${libext4_objs}
+ libext6.a: initext6.o ${libext6_objs}
+ 	${AM_VERBOSE_AR} ${AR} crs $@ $^;
+ 
+-initext_func  := $(addprefix xt_,${pfx_build_mod})
+-initext4_func := $(addprefix ipt_,${pf4_build_mod})
+-initext6_func := $(addprefix ip6t_,${pf6_build_mod})
++initext_func  := $(addprefix xt_,${pfx_build_static})
++initext4_func := $(addprefix ipt_,${pf4_build_static})
++initext6_func := $(addprefix ip6t_,${pf6_build_static})
+ 
+ .initext.dd: FORCE
+ 	@echo "${initext_func}" >$@.tmp; \
diff --git a/package/network/utils/iptables/patches/300-musl_fixes.patch b/package/network/utils/iptables/patches/300-musl_fixes.patch
new file mode 100644
index 0000000000..a78eda775d
--- /dev/null
+++ b/package/network/utils/iptables/patches/300-musl_fixes.patch
@@ -0,0 +1,127 @@
+--- a/extensions/libip6t_ipv6header.c
++++ b/extensions/libip6t_ipv6header.c
+@@ -10,6 +10,9 @@ on whether they contain certain headers 
+ #include <netdb.h>
+ #include <xtables.h>
+ #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
++#ifndef IPPROTO_HOPOPTS
++#	define IPPROTO_HOPOPTS 0
++#endif
+ 
+ enum {
+ 	O_HEADER = 0,
+--- a/extensions/libxt_TCPOPTSTRIP.c
++++ b/extensions/libxt_TCPOPTSTRIP.c
+@@ -12,6 +12,21 @@
+ #ifndef TCPOPT_MD5SIG
+ #	define TCPOPT_MD5SIG 19
+ #endif
++#ifndef TCPOPT_MAXSEG
++#	define TCPOPT_MAXSEG 2
++#endif
++#ifndef TCPOPT_WINDOW
++#	define TCPOPT_WINDOW 3
++#endif
++#ifndef TCPOPT_SACK_PERMITTED
++#	define TCPOPT_SACK_PERMITTED 4
++#endif
++#ifndef TCPOPT_SACK
++#	define TCPOPT_SACK 5
++#endif
++#ifndef TCPOPT_TIMESTAMP
++#	define TCPOPT_TIMESTAMP 8
++#endif
+ 
+ enum {
+ 	O_STRIP_OPTION = 0,
+--- a/include/libiptc/ipt_kernel_headers.h
++++ b/include/libiptc/ipt_kernel_headers.h
+@@ -5,7 +5,6 @@
+ 
+ #include <limits.h>
+ 
+-#if defined(__GLIBC__) && __GLIBC__ == 2
+ #include <netinet/ip.h>
+ #include <netinet/in.h>
+ #include <netinet/ip_icmp.h>
+@@ -13,15 +12,4 @@
+ #include <netinet/udp.h>
+ #include <net/if.h>
+ #include <sys/types.h>
+-#else /* libc5 */
+-#include <sys/socket.h>
+-#include <linux/ip.h>
+-#include <linux/in.h>
+-#include <linux/if.h>
+-#include <linux/icmp.h>
+-#include <linux/tcp.h>
+-#include <linux/udp.h>
+-#include <linux/types.h>
+-#include <linux/in6.h>
+-#endif
+ #endif
+--- a/include/linux/netfilter_ipv4/ip_tables.h
++++ b/include/linux/netfilter_ipv4/ip_tables.h
+@@ -16,6 +16,7 @@
+ #define _IPTABLES_H
+ 
+ #include <linux/types.h>
++#include <sys/types.h>
+ 
+ #include <linux/netfilter_ipv4.h>
+ 
+--- a/iptables/ip6tables-restore.c
++++ b/iptables/ip6tables-restore.c
+@@ -9,7 +9,7 @@
+  */
+ 
+ #include <getopt.h>
+-#include <sys/errno.h>
++#include <errno.h>
+ #include <stdbool.h>
+ #include <string.h>
+ #include <stdio.h>
+--- a/iptables/ip6tables-save.c
++++ b/iptables/ip6tables-save.c
+@@ -6,7 +6,7 @@
+  * This code is distributed under the terms of GNU GPL v2
+  */
+ #include <getopt.h>
+-#include <sys/errno.h>
++#include <errno.h>
+ #include <stdio.h>
+ #include <fcntl.h>
+ #include <stdlib.h>
+--- a/iptables/iptables-restore.c
++++ b/iptables/iptables-restore.c
+@@ -6,7 +6,7 @@
+  */
+ 
+ #include <getopt.h>
+-#include <sys/errno.h>
++#include <errno.h>
+ #include <stdbool.h>
+ #include <string.h>
+ #include <stdio.h>
+--- a/iptables/iptables-save.c
++++ b/iptables/iptables-save.c
+@@ -6,7 +6,7 @@
+  *
+  */
+ #include <getopt.h>
+-#include <sys/errno.h>
++#include <errno.h>
+ #include <stdio.h>
+ #include <fcntl.h>
+ #include <stdlib.h>
+--- a/iptables/iptables-xml.c
++++ b/iptables/iptables-xml.c
+@@ -7,7 +7,7 @@
+  */
+ 
+ #include <getopt.h>
+-#include <sys/errno.h>
++#include <errno.h>
+ #include <string.h>
+ #include <stdio.h>
+ #include <stdlib.h>
diff --git a/package/network/utils/iptables/patches/500-add-xt_id-match.patch b/package/network/utils/iptables/patches/500-add-xt_id-match.patch
new file mode 100644
index 0000000000..0964f0175f
--- /dev/null
+++ b/package/network/utils/iptables/patches/500-add-xt_id-match.patch
@@ -0,0 +1,69 @@
+--- /dev/null
++++ b/extensions/libxt_id.c
+@@ -0,0 +1,55 @@
++/* Shared library add-on to iptables to add id match support. */
++
++#include <stdio.h>
++#include <xtables.h>
++#include <linux/netfilter/xt_id.h>
++
++enum {
++	O_ID = 0,
++};
++
++static const struct xt_option_entry id_opts[] = {
++	{
++		.name  = "id",
++		.id    = O_ID,
++		.type  = XTTYPE_UINT32,
++		.flags = XTOPT_MAND | XTOPT_PUT,
++		XTOPT_POINTER(struct xt_id_info, id)
++	},
++	XTOPT_TABLEEND,
++};
++
++static void
++id_print(const void *ip, const struct xt_entry_match *match, int numeric)
++{
++	struct xt_id_info *idinfo = (void *)match->data;
++
++	printf(" ID:%08lx", idinfo->id);
++}
++
++
++/* Saves the union ipt_matchinfo in parsable form to stdout. */
++static void
++id_save(const void *ip, const struct xt_entry_match *match)
++{
++	struct xt_id_info *idinfo = (void *)match->data;
++
++	printf(" --id 0x%lx", idinfo->id);
++}
++
++static struct xtables_match id_match = {
++	.family		= NFPROTO_UNSPEC,
++	.name		= "id",
++	.version	= XTABLES_VERSION,
++	.size		= XT_ALIGN(sizeof(struct xt_id_info)),
++	.userspacesize	= XT_ALIGN(sizeof(struct xt_id_info)),
++	.print		= id_print,
++	.save 		= id_save,
++	.x6_parse	= xtables_option_parse,
++	.x6_options	= id_opts,
++};
++
++void _init(void)
++{
++	xtables_register_match(&id_match);
++}
+--- /dev/null
++++ b/include/linux/netfilter/xt_id.h
+@@ -0,0 +1,8 @@
++#ifndef _XT_ID_H
++#define _XT_ID_H
++
++struct xt_id_info {
++	__u32 id;
++};
++
++#endif /* XT_ID_H */
diff --git a/package/network/utils/iptables/patches/600-shared-libext.patch b/package/network/utils/iptables/patches/600-shared-libext.patch
new file mode 100644
index 0000000000..92f5485399
--- /dev/null
+++ b/package/network/utils/iptables/patches/600-shared-libext.patch
@@ -0,0 +1,78 @@
+Index: iptables-1.4.21/extensions/GNUmakefile.in
+===================================================================
+--- iptables-1.4.21.orig/extensions/GNUmakefile.in
++++ iptables-1.4.21/extensions/GNUmakefile.in
+@@ -71,7 +71,7 @@ pf6_solibs    := $(patsubst %,libip6t_%.
+ #
+ # Building blocks
+ #
+-targets := libext.a libext4.a libext6.a matches.man targets.man
++targets := libiptext.so libiptext4.so libiptext6.so matches.man targets.man
+ targets_install :=
+ libext_objs := ${pfx_objs}
+ libext4_objs := ${pf4_objs}
+@@ -96,7 +96,7 @@ clean:
+ distclean: clean
+ 
+ init%.o: init%.c
+-	${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<;
++	${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init  -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
+ 
+ -include .*.d
+ 
+@@ -130,16 +130,16 @@ xt_statistic_LIBADD = -lm
+ #	handling code in the Makefiles.
+ #
+ lib%.o: ${srcdir}/lib%.c
+-	${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<;
++	${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
+ 
+-libext.a: initext.o ${libext_objs}
+-	${AM_VERBOSE_AR} ${AR} crs $@ $^;
++libiptext.so: initext.o ${libext_objs}
++	${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $^ -L../libxtables/.libs -lxtables ${$*_LIBADD};
+ 
+-libext4.a: initext4.o ${libext4_objs}
+-	${AM_VERBOSE_AR} ${AR} crs $@ $^;
++libiptext4.so: initext4.o ${libext4_objs}
++	${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $^ -L../libxtables/.libs -lxtables ${$*_LIBADD};
+ 
+-libext6.a: initext6.o ${libext6_objs}
+-	${AM_VERBOSE_AR} ${AR} crs $@ $^;
++libiptext6.so: initext6.o ${libext6_objs}
++	${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $^ -L../libxtables/.libs -lxtables ${$*_LIBADD};
+ 
+ initext_func  := $(addprefix xt_,${pfx_build_static})
+ initext4_func := $(addprefix ipt_,${pf4_build_static})
+Index: iptables-1.4.21/iptables/Makefile.am
+===================================================================
+--- iptables-1.4.21.orig/iptables/Makefile.am
++++ iptables-1.4.21/iptables/Makefile.am
+@@ -5,7 +5,8 @@ AM_CPPFLAGS      = ${regular_CPPFLAGS} -
+ 
+ xtables_multi_SOURCES  = xtables-multi.c iptables-xml.c
+ xtables_multi_CFLAGS   = ${AM_CFLAGS}
+-xtables_multi_LDADD    = ../extensions/libext.a
++xtables_multi_LDADD    =
++xtables_multi_LDFLAGS  = -L../extensions/ -liptext
+ if ENABLE_STATIC
+ xtables_multi_CFLAGS  += -DALL_INCLUSIVE
+ endif
+@@ -13,13 +14,15 @@ if ENABLE_IPV4
+ xtables_multi_SOURCES += iptables-save.c iptables-restore.c \
+                          iptables-standalone.c iptables.c
+ xtables_multi_CFLAGS  += -DENABLE_IPV4
+-xtables_multi_LDADD   += ../libiptc/libip4tc.la ../extensions/libext4.a
++xtables_multi_LDADD   += ../libiptc/libip4tc.la
++xtables_multi_LDFLAGS += -liptext4
+ endif
+ if ENABLE_IPV6
+ xtables_multi_SOURCES += ip6tables-save.c ip6tables-restore.c \
+                           ip6tables-standalone.c ip6tables.c
+ xtables_multi_CFLAGS  += -DENABLE_IPV6
+-xtables_multi_LDADD   += ../libiptc/libip6tc.la ../extensions/libext6.a
++xtables_multi_LDADD   += ../libiptc/libip6tc.la
++xtables_multi_LDFLAGS += -liptext6
+ endif
+ xtables_multi_SOURCES += xshared.c
+ xtables_multi_LDADD   += ../libxtables/libxtables.la -lm
diff --git a/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch b/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch
new file mode 100644
index 0000000000..342c3b013a
--- /dev/null
+++ b/package/network/utils/iptables/patches/700-disable-legacy-revisions.patch
@@ -0,0 +1,108 @@
+Index: iptables-1.4.21/extensions/libxt_conntrack.c
+===================================================================
+--- iptables-1.4.21.orig/extensions/libxt_conntrack.c
++++ iptables-1.4.21/extensions/libxt_conntrack.c
+@@ -1157,6 +1157,7 @@ static void state_save(const void *ip, c
+ }
+ 
+ static struct xtables_match conntrack_mt_reg[] = {
++#ifndef NO_LEGACY
+ 	{
+ 		.version       = XTABLES_VERSION,
+ 		.name          = "conntrack",
+@@ -1232,6 +1233,7 @@ static struct xtables_match conntrack_mt
+ 		.alias	       = conntrack_print_name_alias,
+ 		.x6_options    = conntrack2_mt_opts,
+ 	},
++#endif
+ 	{
+ 		.version       = XTABLES_VERSION,
+ 		.name          = "conntrack",
+@@ -1262,6 +1264,7 @@ static struct xtables_match conntrack_mt
+ 		.alias	       = conntrack_print_name_alias,
+ 		.x6_options    = conntrack3_mt_opts,
+ 	},
++#ifndef NO_LEGACY
+ 	{
+ 		.family        = NFPROTO_UNSPEC,
+ 		.name          = "state",
+@@ -1292,6 +1295,7 @@ static struct xtables_match conntrack_mt
+ 		.x6_parse      = state_ct23_parse,
+ 		.x6_options    = state_opts,
+ 	},
++#endif
+ 	{
+ 		.family        = NFPROTO_UNSPEC,
+ 		.name          = "state",
+@@ -1307,6 +1311,7 @@ static struct xtables_match conntrack_mt
+ 		.x6_parse      = state_ct23_parse,
+ 		.x6_options    = state_opts,
+ 	},
++#ifndef NO_LEGACY
+ 	{
+ 		.family        = NFPROTO_UNSPEC,
+ 		.name          = "state",
+@@ -1320,6 +1325,7 @@ static struct xtables_match conntrack_mt
+ 		.x6_parse      = state_parse,
+ 		.x6_options    = state_opts,
+ 	},
++#endif
+ };
+ 
+ void _init(void)
+Index: iptables-1.4.21/extensions/libxt_CT.c
+===================================================================
+--- iptables-1.4.21.orig/extensions/libxt_CT.c
++++ iptables-1.4.21/extensions/libxt_CT.c
+@@ -290,6 +290,7 @@ static void notrack_ct2_tg_init(struct x
+ }
+ 
+ static struct xtables_target ct_target_reg[] = {
++#ifndef NO_LEGACY
+ 	{
+ 		.family		= NFPROTO_UNSPEC,
+ 		.name		= "CT",
+@@ -315,6 +316,7 @@ static struct xtables_target ct_target_r
+ 		.x6_parse	= ct_parse_v1,
+ 		.x6_options	= ct_opts_v1,
+ 	},
++#endif
+ 	{
+ 		.family		= NFPROTO_UNSPEC,
+ 		.name		= "CT",
+@@ -329,6 +331,7 @@ static struct xtables_target ct_target_r
+ 		.x6_parse	= ct_parse_v1,
+ 		.x6_options	= ct_opts_v1,
+ 	},
++#ifndef NO_LEGACY
+ 	{
+ 		.family        = NFPROTO_UNSPEC,
+ 		.name          = "NOTRACK",
+@@ -366,6 +369,7 @@ static struct xtables_target ct_target_r
+ 		.revision      = 0,
+ 		.version       = XTABLES_VERSION,
+ 	},
++#endif
+ };
+ 
+ void _init(void)
+Index: iptables-1.4.21/extensions/libxt_multiport.c
+===================================================================
+--- iptables-1.4.21.orig/extensions/libxt_multiport.c
++++ iptables-1.4.21/extensions/libxt_multiport.c
+@@ -469,6 +469,7 @@ static void multiport_save6_v1(const voi
+ }
+ 
+ static struct xtables_match multiport_mt_reg[] = {
++#ifndef NO_LEGACY
+ 	{
+ 		.family        = NFPROTO_IPV4,
+ 		.name          = "multiport",
+@@ -497,6 +498,7 @@ static struct xtables_match multiport_mt
+ 		.save          = multiport_save6,
+ 		.x6_options    = multiport_opts,
+ 	},
++#endif
+ 	{
+ 		.family        = NFPROTO_IPV4,
+ 		.name          = "multiport",
diff --git a/package/network/utils/iputils/Makefile b/package/network/utils/iputils/Makefile
new file mode 100644
index 0000000000..11f3a7d2b7
--- /dev/null
+++ b/package/network/utils/iputils/Makefile
@@ -0,0 +1,181 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iputils
+PKG_VERSION:=20101006
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-s$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://www.skbuff.net/iputils
+PKG_MD5SUM:=a36c25e9ec17e48be514dc0485e7376c
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0+
+
+PKG_BUILD_DEPENDS:=sysfsutils
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-s$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define Package/iputils/Default
+  SECTION:=net
+  CATEGORY:=Network
+  URL:=http://www.skbuff.net/iputils
+endef
+
+
+define Package/iputils-arping
+$(call Package/iputils/Default)
+  TITLE:=iputils - arping
+  DEPENDS+= +libsysfs
+endef
+
+define Package/iputils-arping/description
+  Program arping from iputils.
+  Sends ARP REQUEST to a neighbour host.
+endef
+
+
+define Package/iputils-clockdiff
+$(call Package/iputils/Default)
+  TITLE:=iputils - clockdiff
+endef
+
+define Package/iputils-clockdiff/description
+  Program clockdiff from iputils.
+  Measures clock difference between hosts.
+endef
+
+
+define Package/iputils-ping
+$(call Package/iputils/Default)
+  TITLE:=iputils - ping
+endef
+
+define Package/iputils-ping/description
+  Program ping from iputils.
+  Sends ICMP ECHO_REQUEST to network hosts (IPv4).
+endef
+
+
+define Package/iputils-ping6
+$(call Package/iputils/Default)
+  TITLE:=iputils - ping6
+  DEPENDS+= @IPV6 +USE_GLIBC:libopenssl
+endef
+
+define Package/iputils-ping6/description
+  Program ping6 from iputils.
+  Sends ICMP ECHO_REQUEST to network hosts (IPv6).
+endef
+
+
+define Package/iputils-tftpd
+$(call Package/iputils/Default)
+  TITLE:=iputils - tftpd
+endef
+
+define Package/iputils-tftpd/description
+  Program tftpd from iputils
+  Trivial File Transfer Protocol server.
+endef
+
+
+define Package/iputils-tracepath
+$(call Package/iputils/Default)
+  TITLE:=iputils - tracepath
+endef
+
+define Package/iputils-tracepath/description
+  Program tracepath from iputils.
+  Traces path to a network host discovering MTU along this path (IPv4).
+endef
+
+
+define Package/iputils-tracepath6
+$(call Package/iputils/Default)
+  TITLE:=iputils - tracepath6
+  DEPENDS+= @IPV6
+endef
+
+define Package/iputils-tracepath6/description
+  Program tracepath6 from iputils.
+  Traces path to a network host discovering MTU along this path (IPv6).
+endef
+
+
+define Package/iputils-traceroute6
+$(call Package/iputils/Default)
+  TITLE:=iputils - traceroute6
+  DEPENDS+= @IPV6
+endef
+
+define Package/iputils-traceroute6/description
+  Program traceroute6 from iputils.
+  Traces path to a network host (IPv6).
+endef
+
+ifdef CONFIG_USE_MUSL
+  TARGET_CFLAGS += -D__UCLIBC__
+endif
+
+MAKE_FLAGS += \
+	CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS) $(TARGET_LDFLAGS)" \
+	CONFIG_IPV6="$(CONFIG_IPV6)" \
+	CONFIG_USE_UCLIBC="$(CONFIG_USE_UCLIBC)$(CONFIG_USE_MUSL)" \
+
+define Package/iputils-arping/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/arping $(1)/usr/bin/
+endef
+
+define Package/iputils-clockdiff/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/clockdiff $(1)/usr/bin/
+endef
+
+define Package/iputils-ping/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ping $(1)/usr/bin/
+endef
+
+define Package/iputils-ping6/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ping6 $(1)/usr/bin/
+endef
+
+define Package/iputils-tftpd/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tftpd $(1)/usr/sbin/
+endef
+
+define Package/iputils-tracepath/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tracepath $(1)/usr/bin/
+endef
+
+define Package/iputils-tracepath6/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tracepath6 $(1)/usr/bin/
+endef
+
+define Package/iputils-traceroute6/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/traceroute6 $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,iputils-arping))
+$(eval $(call BuildPackage,iputils-clockdiff))
+$(eval $(call BuildPackage,iputils-ping))
+$(eval $(call BuildPackage,iputils-tftpd))
+$(eval $(call BuildPackage,iputils-tracepath))
+$(eval $(call BuildPackage,iputils-ping6))
+$(eval $(call BuildPackage,iputils-tracepath6))
+$(eval $(call BuildPackage,iputils-traceroute6))
diff --git a/package/network/utils/iputils/patches/001-iputils.patch b/package/network/utils/iputils/patches/001-iputils.patch
new file mode 100644
index 0000000000..e57db1379e
--- /dev/null
+++ b/package/network/utils/iputils/patches/001-iputils.patch
@@ -0,0 +1,14 @@
+diff -ur a/Makefile b/Makefile
+--- a/Makefile	2002-09-20 18:23:55.000000000 +0000
++++ b/Makefile	2007-05-17 13:59:55.000000000 +0000
+@@ -16,8 +16,8 @@
+ CCOPT=-D_GNU_SOURCE -O2 -Wstrict-prototypes -Wall -g
+ CFLAGS=$(CCOPT) $(GLIBCFIX) $(DEFINES) 
+ 
+-IPV4_TARGETS=tracepath ping clockdiff rdisc arping tftpd rarpd
+-IPV6_TARGETS=tracepath6 traceroute6 ping6
++IPV4_TARGETS=tracepath ping clockdiff arping tftpd
++IPV6_TARGETS=tracepath6 traceroute6 ping6
+ TARGETS=$(IPV4_TARGETS) $(IPV6_TARGETS)
+ 
+ LASTTAG:=`git describe HEAD | sed -e 's/-.*//'`
diff --git a/package/network/utils/iputils/patches/002-fix-ipv6.patch b/package/network/utils/iputils/patches/002-fix-ipv6.patch
new file mode 100644
index 0000000000..4411ca7ef3
--- /dev/null
+++ b/package/network/utils/iputils/patches/002-fix-ipv6.patch
@@ -0,0 +1,14 @@
+--- a/Makefile
++++ b/Makefile
+@@ -18,7 +18,10 @@ CFLAGS=$(CCOPT) $(GLIBCFIX) $(DEFINES)
+ 
+ IPV4_TARGETS=tracepath ping clockdiff arping tftpd
+ IPV6_TARGETS=tracepath6 traceroute6 ping6
+-TARGETS=$(IPV4_TARGETS) $(IPV6_TARGETS)
++TARGETS=$(IPV4_TARGETS)
++ifeq ($(CONFIG_IPV6),y)
++	TARGETS=$(IPV4_TARGETS) $(IPV6_TARGETS)
++endif
+ 
+ LASTTAG:=`git describe HEAD | sed -e 's/-.*//'`
+ TAG:=`date +s%Y%m%d`
diff --git a/package/network/utils/iputils/patches/003-fix-makefile.patch b/package/network/utils/iputils/patches/003-fix-makefile.patch
new file mode 100644
index 0000000000..926c685519
--- /dev/null
+++ b/package/network/utils/iputils/patches/003-fix-makefile.patch
@@ -0,0 +1,18 @@
+--- a/Makefile
++++ b/Makefile
+@@ -30,9 +30,13 @@ all: $(TARGETS)
+ 
+ 
+ tftpd: tftpd.o tftpsubs.o
+-arping: arping.o -lsysfs
++arping: arping.o 
++	$(CC) $(CFLAGS) -o $@ arping.o -lsysfs
+ ping: ping.o ping_common.o
+-ping6: ping6.o ping_common.o -lresolv -lcrypto
++ping6: ping6.o ping_common.o
++ifneq ($(CONFIG_USE_UCLIBC),y)
++	$(CC) $(CFLAGS) -o $@ ping6.o ping_common.o -lresolv -lcrypto
++endif
+ ping.o ping6.o ping_common.o: ping_common.h
+ tftpd.o tftpsubs.o: tftp.h
+ 
diff --git a/package/network/utils/iputils/patches/010-ping6_uclibc_resolv.patch b/package/network/utils/iputils/patches/010-ping6_uclibc_resolv.patch
new file mode 100644
index 0000000000..695580347b
--- /dev/null
+++ b/package/network/utils/iputils/patches/010-ping6_uclibc_resolv.patch
@@ -0,0 +1,200 @@
+diff --git a/ping6.c b/ping6.c
+index c5ff881..ef2243f 100644
+--- a/ping6.c
++++ b/ping6.c
+@@ -71,9 +71,11 @@ char copyright[] =
+ #include <linux/filter.h>
+ #include <netinet/ip6.h>
+ #include <netinet/icmp6.h>
++#ifndef __UCLIBC__
+ #include <resolv.h>
+ 
+ #include "ping6_niquery.h"
++#endif /* __UCLIBC__ */
+ 
+ #ifndef SOL_IPV6
+ #define SOL_IPV6 IPPROTO_IPV6
+@@ -154,6 +156,7 @@ int pmtudisc=-1;
+ 
+ static int icmp_sock;
+ 
++#ifndef __UCLIBC__
+ #include <openssl/md5.h>
+ 
+ /* Node Information query */
+@@ -165,6 +168,7 @@ int ni_subject_type = 0;
+ char *ni_group;
+ 
+ __u8 ni_nonce[8];
++#endif /* __UCLIBC__ */
+ 
+ static struct in6_addr in6_anyaddr;
+ static __inline__ int ipv6_addr_any(struct in6_addr *addr)
+@@ -223,6 +227,7 @@ unsigned int if_name2index(const char *ifname)
+ 	return i;
+ }
+ 
++#ifndef __UCLIBC__
+ struct niquery_option {
+ 	char *name;
+ 	int namelen;
+@@ -512,6 +517,7 @@ char *ni_groupaddr(const char *name)
+ 		strcat(nigroup_buf, q);
+ 	return nigroup_buf;
+ }
++#endif /* __UCLIBC__ */
+ 
+ int main(int argc, char *argv[])
+ {
+@@ -595,12 +601,14 @@ int main(int argc, char *argv[])
+ 		case 'V':
+ 			printf("ping6 utility, iputils-ss%s\n", SNAPSHOT);
+ 			exit(0);
++#ifndef __UCLIBC__
+ 		case 'N':
+ 			if (niquery_option_handler(optarg) < 0) {
+ 				usage();
+ 				break;
+ 			}
+ 			break;
++#endif /* __UCLIBC__ */
+ 		COMMON_OPTIONS
+ 			common_options(ch);
+ 			break;
+@@ -663,6 +671,7 @@ int main(int argc, char *argv[])
+ 		argc--;
+ 	}
+ 
++#ifndef __UCLIBC__
+ 	if (ni_query >= 0) {
+ 		int i;
+ 		for (i = 0; i < 8; i++)
+@@ -674,15 +683,20 @@ int main(int argc, char *argv[])
+ 			ni_subject_type = NI_SUBJ_IPV6;
+ 		}
+ 	}
++#endif /* __UCLIBC__ */
+ 
+ 	if (argc > 1)
+ 		usage();
+ 	else if (argc == 1) {
+ 		target = *argv;
+ 	} else {
++#ifndef __UCLIBC__
+ 		if (ni_query < 0 && ni_subject_type != NI_SUBJ_NAME)
++#endif /* __UCLIBC__ */
+ 			usage();
++#ifndef __UCLIBC__
+ 		target = ni_group;
++#endif /* __UCLIBC__ */
+ 	}
+ 
+ 	memset(&hints, 0, sizeof(hints));
+@@ -817,7 +831,11 @@ int main(int argc, char *argv[])
+ 		exit(2);
+ 	}
+ 
++#ifndef __UCLIBC__
+ 	if (datalen >= sizeof(struct timeval) && (ni_query < 0)) {
++#else
++	if (datalen >= sizeof(struct timeval)) {
++#endif /* __UCLIBC__ */
+ 		/* can we time transfer */
+ 		timing = 1;
+ 	}
+@@ -866,9 +884,11 @@ int main(int argc, char *argv[])
+ 		ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
+ 	}
+ 
++#ifndef __UCLIBC__
+ 	if (ni_query >= 0)
+ 		ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter);
+ 	else
++#endif /* __UCLIBC__ */
+ 		ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
+ 
+ 	err = setsockopt(icmp_sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+@@ -1100,6 +1120,7 @@ int build_echo(__u8 *_icmph)
+ 	return cc;
+ }
+ 
++#ifndef __UCLIBC__
+ int build_niquery(__u8 *_nih)
+ {
+ 	struct ni_hdr *nih;
+@@ -1125,6 +1146,7 @@ int build_niquery(__u8 *_nih)
+ 
+ 	return cc;
+ }
++#endif /* __UCLIBC__ */
+ 
+ int send_probe(void)
+ {
+@@ -1132,9 +1154,11 @@ int send_probe(void)
+ 
+ 	CLR((ntransmitted+1) % mx_dup_ck);
+ 
++#ifndef __UCLIBC__
+ 	if (ni_query >= 0)
+ 		len = build_niquery(outpack);
+ 	else
++#endif /* __UCLIBC__ */
+ 		len = build_echo(outpack);
+ 
+ 	if (cmsglen == 0) {
+@@ -1176,6 +1200,7 @@ static void putchar_safe(char c)
+ 		printf("\\%03o", c);
+ }
+ 
++#ifndef __UCLIBC__
+ void pr_niquery_reply_name(struct ni_hdr *nih, int len)
+ {
+ 	__u8 *h = (__u8 *)(nih + 1);
+@@ -1304,6 +1329,7 @@ void pr_niquery_reply(__u8 *_nih, int len)
+ 	}
+ 	putchar(';');
+ }
++#endif /* __UCLIBC__ */
+ 
+ /*
+  * parse_reply --
+@@ -1353,6 +1379,7 @@ parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
+ 				      hops, 0, tv, pr_addr(&from->sin6_addr),
+ 				      pr_echo_reply))
+ 			return 0;
++#ifndef __UCLIBC__
+ 	} else if (icmph->icmp6_type == ICMPV6_NI_REPLY) {
+ 		struct ni_hdr *nih = (struct ni_hdr *)icmph;
+ 		__u16 seq = ntohs(*(__u16 *)nih->ni_nonce);
+@@ -1363,6 +1390,7 @@ parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
+ 				      hops, 0, tv, pr_addr(&from->sin6_addr),
+ 				      pr_niquery_reply))
+ 			return 0;
++#endif /* __UCLIBC__ */
+ 	} else {
+ 		int nexthdr;
+ 		struct ip6_hdr *iph1 = (struct ip6_hdr*)(icmph+1);
+@@ -1557,7 +1585,9 @@ void usage(void)
+ "Usage: ping6 [-LUdfnqrvVaAD] [-c count] [-i interval] [-w deadline]\n"
+ "             [-p pattern] [-s packetsize] [-t ttl] [-I interface]\n"
+ "             [-M pmtudisc-hint] [-S sndbuf] [-F flowlabel] [-Q tclass]\n"
++#ifndef __UCLIBC__
+ "             [[-N nodeinfo-option] ...]\n"
++#endif /* __UCLIBC__ */
+ "             [hop1 ...] destination\n");
+ 	exit(2);
+ }
+diff --git a/ping6_niquery.h b/ping6_niquery.h
+index 61a5cfa..34c31f8 100644
+--- a/ping6_niquery.h
++++ b/ping6_niquery.h
+@@ -1,3 +1,4 @@
++#ifndef __UCLIBC__
+ #include <asm/byteorder.h>
+ 
+ /* Node Information Query */
+@@ -45,3 +46,4 @@ struct ni_hdr {
+ #define NI_IPV4ADDR_F_TRUNCATE		NI_IPV6ADDR_F_TRUNCATE
+ #define NI_IPV4ADDR_F_ALL		NI_IPV6ADDR_F_ALL
+ 
++#endif /* __UCLIBC__ */
diff --git a/package/network/utils/iputils/patches/011-ping6_use_gnu_source.patch b/package/network/utils/iputils/patches/011-ping6_use_gnu_source.patch
new file mode 100644
index 0000000000..dc61b8c22f
--- /dev/null
+++ b/package/network/utils/iputils/patches/011-ping6_use_gnu_source.patch
@@ -0,0 +1,11 @@
+--- a/ping6.c
++++ b/ping6.c
+@@ -66,6 +66,8 @@ char copyright[] =
+  *	More statistics could always be gathered.
+  *	This program has to run SUID to ROOT to access the ICMP socket.
+  */
++
++#define _GNU_SOURCE
+ #include "ping_common.h"
+ 
+ #include <linux/filter.h>
diff --git a/package/network/utils/iputils/patches/020-include_fixes.patch b/package/network/utils/iputils/patches/020-include_fixes.patch
new file mode 100644
index 0000000000..e982dabc37
--- /dev/null
+++ b/package/network/utils/iputils/patches/020-include_fixes.patch
@@ -0,0 +1,71 @@
+--- a/ping_common.h
++++ b/ping_common.h
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <time.h>
++#include <sys/types.h>
+ #include <sys/param.h>
+ #include <sys/socket.h>
+ #include <linux/sockios.h>
+@@ -11,7 +12,7 @@
+ #include <sys/ioctl.h>
+ #include <net/if.h>
+ #include <sys/uio.h>
+-#include <sys/poll.h>
++#include <poll.h>
+ #include <ctype.h>
+ #include <errno.h>
+ #include <string.h>
+@@ -24,6 +25,10 @@
+ 
+ #include "SNAPSHOT.h"
+ 
++#ifndef HZ
++#define HZ 100
++#endif
++
+ #define	DEFDATALEN	(64 - 8)	/* default data length */
+ 
+ #define	MAXWAIT		10		/* max seconds to wait for response */
+--- a/clockdiff.c
++++ b/clockdiff.c
+@@ -13,8 +13,6 @@
+ #include <netinet/in.h>
+ #include <netinet/ip.h>
+ #include <netinet/ip_icmp.h>
+-#define TSPTYPES
+-#include <protocols/timed.h>
+ #include <fcntl.h>
+ #include <netdb.h>
+ #include <arpa/inet.h>
+--- a/tracepath.c
++++ b/tracepath.c
+@@ -13,6 +13,7 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <sys/socket.h>
++#include <sys/time.h>
+ #include <linux/types.h>
+ #include <linux/errqueue.h>
+ #include <errno.h>
+--- a/ping.c
++++ b/ping.c
+@@ -661,8 +661,15 @@ int send_probe()
+ 
+ 	do {
+ 		static struct iovec iov = {outpack, 0};
+-		static struct msghdr m = { &whereto, sizeof(whereto),
+-						   &iov, 1, &cmsg, 0, 0 };
++		static struct msghdr m = {
++			.msg_name = &whereto,
++			.msg_namelen = sizeof(whereto),
++			.msg_iov = &iov,
++			.msg_iovlen = 1,
++			.msg_control = &cmsg,
++			.msg_controllen = 0,
++			.msg_flags = 0
++		};
+ 		m.msg_controllen = cmsg_len;
+ 		iov.iov_len = cc;
+ 
diff --git a/package/network/utils/iw/Makefile b/package/network/utils/iw/Makefile
new file mode 100644
index 0000000000..f84978ff25
--- /dev/null
+++ b/package/network/utils/iw/Makefile
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2007-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iw
+PKG_VERSION:=4.9
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/software/network/iw
+PKG_MD5SUM:=02d36655b45a0288feb0e87e461e365a
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/iw
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=cfg80211 interface configuration utility
+  URL:=http://wireless.kernel.org/en/users/Documentation/iw
+  DEPENDS:= +libnl-tiny
+endef
+
+define Build/Configure
+	echo "const char iw_version[] = \"$(PKG_VERSION)\";" > $(PKG_BUILD_DIR)/version.c
+	rm -f $(PKG_BUILD_DIR)/version.sh
+	touch $(PKG_BUILD_DIR)/version.sh
+	chmod +x $(PKG_BUILD_DIR)/version.sh
+endef
+
+TARGET_CPPFLAGS:= \
+	-I$(STAGING_DIR)/usr/include/libnl-tiny \
+	$(TARGET_CPPFLAGS) \
+	-DCONFIG_LIBNL20 \
+	-D_GNU_SOURCE
+
+MAKE_FLAGS += \
+	CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -ffunction-sections -fdata-sections" \
+	LDFLAGS="$(TARGET_LDFLAGS) -Wl,--gc-sections" \
+	NL1FOUND="" NL2FOUND=Y \
+	NLLIBNAME="libnl-tiny" \
+	LIBS="-lm -lnl-tiny" \
+	V=1
+
+define Package/iw/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/iw $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,iw))
diff --git a/package/network/utils/iw/patches/001-nl80211_h_sync.patch b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
new file mode 100644
index 0000000000..5d98281eae
--- /dev/null
+++ b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
@@ -0,0 +1,21 @@
+--- a/nl80211.h
++++ b/nl80211.h
+@@ -1937,6 +1937,9 @@ enum nl80211_commands {
+  * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
+  *	See &enum nl80211_nan_match_attributes.
+  *
++ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
++ *	transmit power to stay within regulatory limits. u32, dBi.
++ *
+  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
+  * @NL80211_ATTR_MAX: highest attribute number currently defined
+  * @__NL80211_ATTR_AFTER_LAST: internal use
+@@ -2336,6 +2339,8 @@ enum nl80211_attrs {
+ 	NL80211_ATTR_NAN_FUNC,
+ 	NL80211_ATTR_NAN_MATCH,
+ 
++	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
++
+ 	/* add attributes here, update the policy in nl80211.c */
+ 
+ 	__NL80211_ATTR_AFTER_LAST,
diff --git a/package/network/utils/iw/patches/120-antenna_gain.patch b/package/network/utils/iw/patches/120-antenna_gain.patch
new file mode 100644
index 0000000000..b219437364
--- /dev/null
+++ b/package/network/utils/iw/patches/120-antenna_gain.patch
@@ -0,0 +1,33 @@
+--- a/phy.c
++++ b/phy.c
+@@ -675,3 +675,30 @@ COMMAND(set, antenna, "<bitmap> | all |
+ 	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
+ 	"Set a bitmap of allowed antennas to use for TX and RX.\n"
+ 	"The driver may reject antenna configurations it cannot support.");
++
++static int handle_antenna_gain(struct nl80211_state *state,
++			       struct nl_msg *msg,
++			       int argc, char **argv,
++			       enum id_input id)
++{
++	char *endptr;
++	int dbm;
++
++	/* get the required args */
++	if (argc != 1)
++		return 1;
++
++	dbm = strtol(argv[0], &endptr, 10);
++	if (*endptr)
++		return 2;
++
++	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_GAIN, dbm);
++
++	return 0;
++
++ nla_put_failure:
++	return -ENOBUFS;
++}
++COMMAND(set, antenna_gain, "<antenna gain in dBm>",
++	NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna_gain,
++	"Specify antenna gain.");
diff --git a/package/network/utils/iw/patches/200-reduce_size.patch b/package/network/utils/iw/patches/200-reduce_size.patch
new file mode 100644
index 0000000000..98836783df
--- /dev/null
+++ b/package/network/utils/iw/patches/200-reduce_size.patch
@@ -0,0 +1,255 @@
+--- a/Makefile
++++ b/Makefile
+@@ -16,8 +16,8 @@ CFLAGS += -Wall -Wundef -Wstrict-prototy
+ OBJS = iw.o genl.o event.o info.o phy.o \
+ 	interface.o ibss.o station.o survey.o util.o ocb.o \
+ 	mesh.o mpath.o mpp.o scan.o reg.o version.o \
+-	reason.o status.o connect.o link.o offch.o ps.o cqm.o \
+-	bitrate.o wowlan.o coalesce.o roc.o p2p.o vendor.o
++	reason.o status.o link.o offch.o ps.o cqm.o \
++	bitrate.o vendor.o
+ OBJS += sections.o
+ 
+ OBJS-$(HWSIM) += hwsim.o
+--- a/event.c
++++ b/event.c
+@@ -342,6 +342,7 @@ static int print_event(struct nl_msg *ms
+ 	}
+ 
+ 	switch (gnlh->cmd) {
++#if 0
+ 	case NL80211_CMD_NEW_WIPHY:
+ 		printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
+ 		break;
+@@ -376,6 +377,7 @@ static int print_event(struct nl_msg *ms
+ 	case NL80211_CMD_SCHED_SCAN_RESULTS:
+ 		printf("got scheduled scan results\n");
+ 		break;
++#endif
+ 	case NL80211_CMD_REG_CHANGE:
+ 		printf("regulatory domain change: ");
+ 
+@@ -454,6 +456,7 @@ static int print_event(struct nl_msg *ms
+ 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
+ 		printf("del station %s\n", macbuf);
+ 		break;
++#if 0
+ 	case NL80211_CMD_JOIN_IBSS:
+ 		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
+ 		printf("IBSS %s joined\n", macbuf);
+@@ -612,9 +615,9 @@ static int print_event(struct nl_msg *ms
+ 	case NL80211_CMD_DEL_WIPHY:
+ 		printf("delete wiphy\n");
+ 		break;
++#endif
+ 	default:
+-		printf("unknown event %d (%s)\n",
+-		       gnlh->cmd, command_name(gnlh->cmd));
++		printf("unknown event %d\n", gnlh->cmd);
+ 		break;
+ 	}
+ 
+--- a/info.c
++++ b/info.c
+@@ -197,6 +197,7 @@ next:
+ 				}
+ 			}
+ 
++#if 0
+ 			if (tb_band[NL80211_BAND_ATTR_RATES]) {
+ 			printf("\t\tBitrates (non-HT):\n");
+ 			nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+@@ -213,6 +214,7 @@ next:
+ 				printf("\n");
+ 			}
+ 			}
++#endif
+ 		}
+ 	}
+ 
+@@ -278,6 +280,7 @@ next:
+ 		printf("\tCoverage class: %d (up to %dm)\n", coverage, 450 * coverage);
+ 	}
+ 
++#if 0
+ 	if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) {
+ 		int num = nla_len(tb_msg[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
+ 		int i;
+@@ -289,6 +292,7 @@ next:
+ 					cipher_name(ciphers[i]));
+ 		}
+ 	}
++#endif
+ 
+ 	if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX] &&
+ 	    tb_msg[NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX])
+@@ -308,11 +312,13 @@ next:
+ 			printf("\t\t * %s\n", iftype_name(nla_type(nl_mode)));
+ 	}
+ 
++#if 0
+ 	if (tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES]) {
+ 		printf("\tsoftware interface modes (can always be added):\n");
+ 		nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SOFTWARE_IFTYPES], rem_mode)
+ 			printf("\t\t * %s\n", iftype_name(nla_type(nl_mode)));
+ 	}
++#endif
+ 
+ 	if (tb_msg[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
+ 		struct nlattr *nl_combi;
+@@ -409,6 +415,7 @@ broken_combination:
+ 			printf("\tinterface combinations are not supported\n");
+ 	}
+ 
++#if 0
+ 	if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+ 		printf("\tSupported commands:\n");
+ 		nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], rem_cmd)
+@@ -506,6 +513,7 @@ broken_combination:
+ 				printf("\t\t * wake up on TCP connection\n");
+ 		}
+ 	}
++#endif
+ 
+ 	if (tb_msg[NL80211_ATTR_ROAM_SUPPORT])
+ 		printf("\tDevice supports roaming.\n");
+@@ -544,6 +552,7 @@ broken_combination:
+ 		}
+ 	}
+ 
++#if 0
+ 	if (tb_msg[NL80211_ATTR_FEATURE_FLAGS]) {
+ 		unsigned int features = nla_get_u32(tb_msg[NL80211_ATTR_FEATURE_FLAGS]);
+ 
+@@ -602,6 +611,7 @@ broken_combination:
+ 		if (features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)
+ 			printf("\tDevice supports TDLS channel switching\n");
+ 	}
++#endif
+ 
+ 	if (tb_msg[NL80211_ATTR_EXT_FEATURES]) {
+ 		struct nlattr *tb = tb_msg[NL80211_ATTR_EXT_FEATURES];
+@@ -658,6 +668,7 @@ TOPLEVEL(list, NULL, NL80211_CMD_GET_WIP
+ 	 "List all wireless devices and their capabilities.");
+ TOPLEVEL(phy, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info, NULL);
+ 
++#if 0
+ static int handle_commands(struct nl80211_state *state, struct nl_msg *msg,
+ 			   int argc, char **argv, enum id_input id)
+ {
+@@ -669,6 +680,7 @@ static int handle_commands(struct nl8021
+ }
+ TOPLEVEL(commands, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_NONE, handle_commands,
+ 	 "list all known commands and their decimal & hex value");
++#endif
+ 
+ static int print_feature_handler(struct nl_msg *msg, void *arg)
+ {
+--- a/scan.c
++++ b/scan.c
+@@ -1147,6 +1147,7 @@ static void print_ht_op(const uint8_t ty
+ 	printf("\t\t * secondary channel offset: %s\n",
+ 		ht_secondary_offset[data[1] & 0x3]);
+ 	printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
++	return;
+ 	printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
+ 	printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
+ 	printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
+@@ -1380,6 +1381,13 @@ static void print_ie(const struct ie_pri
+ 
+ static const struct ie_print ieprinters[] = {
+ 	[0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
++	[45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
++	[48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
++	[61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
++	[62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
++	[191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
++	[192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
++#if 0
+ 	[1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
+ 	[3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
+ 	[5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
+@@ -1389,14 +1397,8 @@ static const struct ie_print ieprinters[
+ 	[32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
+ 	[35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
+ 	[42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
+-	[45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+ 	[47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
+ 	[74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
+-	[61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
+-	[62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
+-	[191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
+-	[192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
+-	[48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
+ 	[50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
+ 	[113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
+ 	[114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
+@@ -1404,6 +1406,7 @@ static const struct ie_print ieprinters[
+ 	[107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
+ 	[108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
+ 	[111] = { "802.11u Roaming Consortium", print_11u_rcon, 0, 255, BIT(PRINT_SCAN), },
++#endif
+ };
+ 
+ static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data)
+@@ -1835,6 +1838,7 @@ void print_ies(unsigned char *ie, int ie
+ 		    ieprinters[ie[0]].name &&
+ 		    ieprinters[ie[0]].flags & BIT(ptype)) {
+ 			print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
++#if 0
+ 		} else if (ie[0] == 221 /* vendor */) {
+ 			print_vendor(ie[1], ie + 2, unknown, ptype);
+ 		} else if (unknown) {
+@@ -1844,6 +1848,7 @@ void print_ies(unsigned char *ie, int ie
+ 			for (i=0; i<ie[1]; i++)
+ 				printf(" %.2x", ie[2+i]);
+ 			printf("\n");
++#endif
+ 		}
+ 		ielen -= ie[1] + 2;
+ 		ie += ie[1] + 2;
+@@ -1884,6 +1889,7 @@ static void print_capa_non_dmg(__u16 cap
+ 		printf(" ESS");
+ 	if (capa & WLAN_CAPABILITY_IBSS)
+ 		printf(" IBSS");
++#if 0
+ 	if (capa & WLAN_CAPABILITY_CF_POLLABLE)
+ 		printf(" CfPollable");
+ 	if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
+@@ -1912,6 +1918,7 @@ static void print_capa_non_dmg(__u16 cap
+ 		printf(" DelayedBACK");
+ 	if (capa & WLAN_CAPABILITY_IMM_BACK)
+ 		printf(" ImmediateBACK");
++#endif
+ }
+ 
+ static int print_bss_handler(struct nl_msg *msg, void *arg)
+@@ -1996,8 +2003,10 @@ static int print_bss_handler(struct nl_m
+ 	if (bss[NL80211_BSS_FREQUENCY]) {
+ 		int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ 		printf("\tfreq: %d\n", freq);
++#if 0
+ 		if (freq > 45000)
+ 			is_dmg = true;
++#endif
+ 	}
+ 	if (bss[NL80211_BSS_BEACON_INTERVAL])
+ 		printf("\tbeacon interval: %d TUs\n",
+--- a/util.c
++++ b/util.c
+@@ -275,6 +275,7 @@ static const char *commands[NL80211_CMD_
+ 
+ static char cmdbuf[100];
+ 
++#if 0
+ const char *command_name(enum nl80211_commands cmd)
+ {
+ 	if (cmd <= NL80211_CMD_MAX && commands[cmd])
+@@ -282,6 +283,7 @@ const char *command_name(enum nl80211_co
+ 	sprintf(cmdbuf, "Unknown command (%d)", cmd);
+ 	return cmdbuf;
+ }
++#endif
+ 
+ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
+ {
diff --git a/package/network/utils/iwcap/Makefile b/package/network/utils/iwcap/Makefile
new file mode 100644
index 0000000000..7b43d6222a
--- /dev/null
+++ b/package/network/utils/iwcap/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
+#
+# This is free software, licensed under the Apache 2 license.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iwcap
+PKG_RELEASE:=1
+PKG_LICENSE:=Apache-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define Package/iwcap
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Simple radiotap capture utility
+  MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+endef
+
+define Package/iwcap/description
+  The iwcap utility receives radiotap packet data from wifi monitor interfaces
+  and outputs it to pcap format. It gathers recived packets in a fixed ring
+  buffer to dump them on demand which is useful for background monitoring.
+  Alternatively the utility can stream the data to stdout to act as remote
+  capture drone for Wireshark or similar programs.
+endef
+
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) \
+		-o $(PKG_BUILD_DIR)/iwcap $(PKG_BUILD_DIR)/iwcap.c
+endef
+
+
+define Package/iwcap/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwcap $(1)/usr/sbin/iwcap
+endef
+
+$(eval $(call BuildPackage,iwcap))
diff --git a/package/network/utils/iwcap/src/iwcap.c b/package/network/utils/iwcap/src/iwcap.c
new file mode 100644
index 0000000000..6bf25c57dd
--- /dev/null
+++ b/package/network/utils/iwcap/src/iwcap.c
@@ -0,0 +1,583 @@
+/*
+ * iwcap.c - A simply radiotap capture utility outputting pcap dumps
+ *
+ *    Copyright 2012 Jo-Philipp Wich <jo@mein.io>
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_packet.h>
+
+#define ARPHRD_IEEE80211_RADIOTAP	803
+
+#define DLT_IEEE802_11_RADIO		127
+#define LEN_IEEE802_11_HDR			32
+
+#define FRAMETYPE_MASK				0xFC
+#define FRAMETYPE_BEACON			0x80
+#define FRAMETYPE_DATA				0x08
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define le16(x) __bswap_16(x)
+#else
+#define le16(x) (x)
+#endif
+
+uint8_t run_dump   = 0;
+uint8_t run_stop   = 0;
+uint8_t run_daemon = 0;
+
+uint32_t frames_captured = 0;
+uint32_t frames_filtered = 0;
+
+int capture_sock = -1;
+const char *ifname = NULL;
+
+
+struct ringbuf {
+	uint32_t len;            /* number of slots */
+	uint32_t fill;           /* last used slot */
+	uint32_t slen;           /* slot size */
+	void *buf;               /* ring memory */
+};
+
+struct ringbuf_entry {
+	uint32_t len;            /* used slot memory */
+	uint32_t olen;           /* original data size */
+	uint32_t sec;            /* epoch of slot creation */
+	uint32_t usec;			 /* epoch microseconds */
+};
+
+typedef struct pcap_hdr_s {
+	uint32_t magic_number;   /* magic number */
+	uint16_t version_major;  /* major version number */
+	uint16_t version_minor;  /* minor version number */
+	int32_t  thiszone;       /* GMT to local correction */
+	uint32_t sigfigs;        /* accuracy of timestamps */
+	uint32_t snaplen;        /* max length of captured packets, in octets */
+	uint32_t network;        /* data link type */
+} pcap_hdr_t;
+
+typedef struct pcaprec_hdr_s {
+	uint32_t ts_sec;         /* timestamp seconds */
+	uint32_t ts_usec;        /* timestamp microseconds */
+	uint32_t incl_len;       /* number of octets of packet saved in file */
+	uint32_t orig_len;       /* actual length of packet */
+} pcaprec_hdr_t;
+
+typedef struct ieee80211_radiotap_header {
+	u_int8_t  it_version;    /* set to 0 */
+	u_int8_t  it_pad;
+	u_int16_t it_len;        /* entire length */
+	u_int32_t it_present;    /* fields present */
+} __attribute__((__packed__)) radiotap_hdr_t;
+
+
+int check_type(void)
+{
+	struct ifreq ifr;
+
+	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+	if (ioctl(capture_sock, SIOCGIFHWADDR, &ifr) < 0)
+		return -1;
+
+	return (ifr.ifr_hwaddr.sa_family == ARPHRD_IEEE80211_RADIOTAP);
+}
+
+int set_promisc(int on)
+{
+	struct ifreq ifr;
+
+	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+	if (ioctl(capture_sock, SIOCGIFFLAGS, &ifr) < 0)
+		return -1;
+
+	if (on && !(ifr.ifr_flags & IFF_PROMISC))
+	{
+		ifr.ifr_flags |= IFF_PROMISC;
+
+		if (ioctl(capture_sock, SIOCSIFFLAGS, &ifr))
+			return -1;
+
+		return 1;
+	}
+	else if (!on && (ifr.ifr_flags & IFF_PROMISC))
+	{
+		ifr.ifr_flags &= ~IFF_PROMISC;
+
+		if (ioctl(capture_sock, SIOCSIFFLAGS, &ifr))
+			return -1;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+
+void sig_dump(int sig)
+{
+	run_dump = 1;
+}
+
+void sig_teardown(int sig)
+{
+	run_stop = 1;
+}
+
+
+void write_pcap_header(FILE *o)
+{
+	pcap_hdr_t ghdr = {
+		.magic_number  = 0xa1b2c3d4,
+		.version_major = 2,
+		.version_minor = 4,
+		.thiszone      = 0,
+		.sigfigs       = 0,
+		.snaplen       = 0xFFFF,
+		.network       = DLT_IEEE802_11_RADIO
+	};
+
+	fwrite(&ghdr, 1, sizeof(ghdr), o);
+}
+
+void write_pcap_frame(FILE *o, uint32_t *sec, uint32_t *usec,
+					  uint16_t len, uint16_t olen)
+{
+	struct timeval tv;
+	pcaprec_hdr_t fhdr;
+
+	if (!sec || !usec)
+	{
+		gettimeofday(&tv, NULL);
+	}
+	else
+	{
+		tv.tv_sec  = *sec;
+		tv.tv_usec = *usec;
+	}
+
+	fhdr.ts_sec   = tv.tv_sec;
+	fhdr.ts_usec  = tv.tv_usec;
+	fhdr.incl_len = len;
+	fhdr.orig_len = olen;
+
+	fwrite(&fhdr, 1, sizeof(fhdr), o);
+}
+
+
+struct ringbuf * ringbuf_init(uint32_t num_item, uint16_t len_item)
+{
+	static struct ringbuf r;
+
+	if (len_item <= 0)
+		return NULL;
+
+	r.buf = malloc(num_item * (len_item + sizeof(struct ringbuf_entry)));
+
+	if (r.buf)
+	{
+		r.len = num_item;
+		r.fill = 0;
+		r.slen = (len_item + sizeof(struct ringbuf_entry));
+
+		memset(r.buf, 0, num_item * len_item);
+
+		return &r;
+	}
+
+	return NULL;
+}
+
+struct ringbuf_entry * ringbuf_add(struct ringbuf *r)
+{
+	struct timeval t;
+	struct ringbuf_entry *e;
+
+	gettimeofday(&t, NULL);
+
+	e = r->buf + (r->fill++ * r->slen);
+	r->fill %= r->len;
+
+	memset(e, 0, r->slen);
+
+	e->sec = t.tv_sec;
+	e->usec = t.tv_usec;
+
+	return e;
+}
+
+struct ringbuf_entry * ringbuf_get(struct ringbuf *r, int i)
+{
+	struct ringbuf_entry *e = r->buf + (((r->fill + i) % r->len) * r->slen);
+
+	if (e->len > 0)
+		return e;
+
+	return NULL;
+}
+
+void ringbuf_free(struct ringbuf *r)
+{
+	free(r->buf);
+	memset(r, 0, sizeof(*r));
+}
+
+
+void msg(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+
+	if (run_daemon)
+		vsyslog(LOG_INFO | LOG_USER, fmt, ap);
+	else
+		vfprintf(stderr, fmt, ap);
+
+	va_end(ap);
+}
+
+
+int main(int argc, char **argv)
+{
+	int i, n;
+	struct ringbuf *ring;
+	struct ringbuf_entry *e;
+	struct sockaddr_ll local = {
+		.sll_family   = AF_PACKET,
+		.sll_protocol = htons(ETH_P_ALL)
+	};
+
+	radiotap_hdr_t *rhdr;
+
+	uint8_t frametype;
+	uint8_t pktbuf[0xFFFF];
+	ssize_t pktlen;
+
+	FILE *o;
+
+	int opt;
+
+	uint8_t promisc        = 0;
+	uint8_t streaming      = 0;
+	uint8_t foreground     = 0;
+	uint8_t filter_data    = 0;
+	uint8_t filter_beacon  = 0;
+	uint8_t header_written = 0;
+
+	uint32_t ringsz   = 1024 * 1024; /* 1 Mbyte ring buffer */
+	uint16_t pktcap   = 256;		 /* truncate frames after 265KB */
+
+	const char *output = NULL;
+
+
+	while ((opt = getopt(argc, argv, "i:r:c:o:sfhBD")) != -1)
+	{
+		switch (opt)
+		{
+		case 'i':
+			ifname = optarg;
+			if (!(local.sll_ifindex = if_nametoindex(ifname)))
+			{
+				msg("Unknown interface '%s'\n", ifname);
+				return 2;
+			}
+			break;
+
+		case 'r':
+			ringsz = atoi(optarg);
+			if (ringsz < (3 * pktcap))
+			{
+				msg("Ring size of %d bytes is too short, "
+					"must be at least %d bytes\n", ringsz, 3 * pktcap);
+				return 3;
+			}
+			break;
+
+		case 'c':
+			pktcap = atoi(optarg);
+			if (pktcap <= (sizeof(radiotap_hdr_t) + LEN_IEEE802_11_HDR))
+			{
+				msg("Packet truncate after %d bytes is too short, "
+					"must be at least %d bytes\n",
+					pktcap, sizeof(radiotap_hdr_t) + LEN_IEEE802_11_HDR);
+				return 4;
+			}
+			break;
+
+		case 's':
+			streaming = 1;
+			break;
+
+		case 'o':
+			output = optarg;
+			break;
+
+		case 'B':
+			filter_beacon = 1;
+			break;
+
+		case 'D':
+			filter_data = 1;
+			break;
+
+		case 'f':
+			foreground = 1;
+			break;
+
+		case 'h':
+			msg(
+				"Usage:\n"
+				"  %s -i {iface} -s [-b] [-d]\n"
+				"  %s -i {iface} -o {file} [-r len] [-c len] [-B] [-D] [-f]\n"
+				"\n"
+				"  -i iface\n"
+				"    Specify interface to use, must be in monitor mode and\n"
+				"    produce IEEE 802.11 Radiotap headers.\n\n"
+				"  -s\n"
+				"    Stream to stdout instead of Dumping to file on USR1.\n\n"
+				"  -o file\n"
+				"    Write current ringbuffer contents to given output file\n"
+				"    on receipt of SIGUSR1.\n\n"
+				"  -r len\n"
+				"    Specify the amount of bytes to use for the ringbuffer.\n"
+				"    The default length is %d bytes.\n\n"
+				"  -c len\n"
+				"    Truncate captured packets after given amount of bytes.\n"
+				"    The default size limit is %d bytes.\n\n"
+				"  -B\n"
+				"    Don't store beacon frames in ring, default is keep.\n\n"
+				"  -D\n"
+				"    Don't store data frames in ring, default is keep.\n\n"
+				"  -f\n"
+				"    Do not daemonize but keep running in foreground.\n\n"
+				"  -h\n"
+				"    Display this help.\n\n",
+				argv[0], argv[0], ringsz, pktcap);
+
+			return 1;
+		}
+	}
+
+	if (!streaming && !output)
+	{
+		msg("No output file specified\n");
+		return 1;
+	}
+
+	if (streaming && output)
+	{
+		msg("The -s and -o options are exclusive\n");
+		return 1;
+	}
+
+	if (streaming && isatty(1))
+	{
+		msg("Refusing to stream into a terminal\n");
+		return 1;
+	}
+
+	if (!local.sll_ifindex)
+	{
+		msg("No interface specified\n");
+		return 2;
+	}
+
+	if (!check_type())
+	{
+		msg("Bad interface: not ARPHRD_IEEE80211_RADIOTAP\n");
+		return 2;
+	}
+
+	if ((capture_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
+	{
+		msg("Unable to create raw socket: %s\n",
+				strerror(errno));
+		return 6;
+	}
+
+	if (bind(capture_sock, (struct sockaddr *)&local, sizeof(local)) == -1)
+	{
+		msg("Unable to bind to interface: %s\n",
+			strerror(errno));
+		return 7;
+	}
+
+	if (!streaming)
+	{
+		if (!foreground)
+		{
+			switch (fork())
+			{
+				case -1:
+					msg("Unable to fork: %s\n", strerror(errno));
+					return 8;
+
+				case 0:
+					umask(0077);
+					chdir("/");
+					freopen("/dev/null", "r", stdin);
+					freopen("/dev/null", "w", stdout);
+					freopen("/dev/null", "w", stderr);
+					run_daemon = 1;
+					break;
+
+				default:
+					msg("Daemon launched ...\n");
+					return 0;
+			}
+		}
+
+		msg("Monitoring interface %s ...\n", ifname);
+
+		if (!(ring = ringbuf_init(ringsz / pktcap, pktcap)))
+		{
+			msg("Unable to allocate ring buffer: %s\n",
+				strerror(errno));
+			return 5;
+		}
+
+		msg(" * Using %d bytes ringbuffer with %d slots\n", ringsz, ring->len);
+		msg(" * Truncating frames at %d bytes\n", pktcap);
+		msg(" * Dumping data to file %s\n", output);
+
+		signal(SIGUSR1, sig_dump);
+	}
+	else
+	{
+		msg("Monitoring interface %s ...\n", ifname);
+		msg(" * Streaming data to stdout\n");
+	}
+
+	msg(" * Beacon frames are %sfiltered\n", filter_beacon ? "" : "not ");
+	msg(" * Data frames are %sfiltered\n", filter_data ? "" : "not ");
+
+	signal(SIGINT, sig_teardown);
+	signal(SIGTERM, sig_teardown);
+
+	promisc = set_promisc(1);
+
+	/* capture loop */
+	while (1)
+	{
+		if (run_stop)
+		{
+			msg("Shutting down ...\n");
+
+			if (promisc)
+				set_promisc(0);
+
+			if (ring)
+				ringbuf_free(ring);
+
+			return 0;
+		}
+		else if (run_dump)
+		{
+			msg("Dumping ring to %s ...\n", output);
+
+			if (!(o = fopen(output, "w")))
+			{
+				msg("Unable to open %s: %s\n",
+					output, strerror(errno));
+			}
+			else
+			{
+				write_pcap_header(o);
+
+				/* sig_dump packet buffer */
+				for (i = 0, n = 0; i < ring->len; i++)
+				{
+					if (!(e = ringbuf_get(ring, i)))
+						continue;
+
+					write_pcap_frame(o, &(e->sec), &(e->usec), e->len, e->olen);
+					fwrite((void *)e + sizeof(*e), 1, e->len, o);
+					n++;
+				}
+
+				fclose(o);
+
+				msg(" * %d frames captured\n", frames_captured);
+				msg(" * %d frames filtered\n", frames_filtered);
+				msg(" * %d frames dumped\n", n);
+			}
+
+			run_dump = 0;
+		}
+
+		pktlen = recvfrom(capture_sock, pktbuf, sizeof(pktbuf), 0, NULL, 0);
+		frames_captured++;
+
+		/* check received frametype, if we should filter it, rewind the ring */
+		rhdr = (radiotap_hdr_t *)pktbuf;
+
+		if (pktlen <= sizeof(radiotap_hdr_t) || le16(rhdr->it_len) >= pktlen)
+		{
+			frames_filtered++;
+			continue;
+		}
+
+		frametype = *(uint8_t *)(pktbuf + le16(rhdr->it_len));
+
+		if ((filter_data   && (frametype & FRAMETYPE_MASK) == FRAMETYPE_DATA) ||
+		    (filter_beacon && (frametype & FRAMETYPE_MASK) == FRAMETYPE_BEACON))
+		{
+			frames_filtered++;
+			continue;
+		}
+
+		if (streaming)
+		{
+			if (!header_written)
+			{
+				write_pcap_header(stdout);
+				header_written = 1;
+			}
+
+			write_pcap_frame(stdout, NULL, NULL, pktlen, pktlen);
+			fwrite(pktbuf, 1, pktlen, stdout);
+			fflush(stdout);
+		}
+		else
+		{
+			e = ringbuf_add(ring);
+			e->olen = pktlen;
+			e->len = (pktlen > pktcap) ? pktcap : pktlen;
+
+			memcpy((void *)e + sizeof(*e), pktbuf, e->len);
+		}
+	}
+
+	return 0;
+}
diff --git a/package/network/utils/iwinfo/Makefile b/package/network/utils/iwinfo/Makefile
new file mode 100644
index 0000000000..0ac9069f1f
--- /dev/null
+++ b/package/network/utils/iwinfo/Makefile
@@ -0,0 +1,124 @@
+#
+# Copyright (C) 2010-2016 Jo-Philipp Wich <jo@mein.io>
+#
+# This is free software, licensed under the GPL 2 license.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libiwinfo
+PKG_VERSION:=2016-09-21
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/iwinfo.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=fd9e17be0c43bd6b8df5371f0b353747bc563874
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=fa2d47caf0927ca79a7c25fc9a480bdbc2f4330210f6aa0cb2e934a3355ce1b5
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0
+
+PKG_FLAGS := nonshared
+
+PKG_CONFIG_DEPENDS := \
+	CONFIG_PACKAGE_kmod-brcm-wl \
+	CONFIG_PACKAGE_kmod-brcm-wl-mini \
+	CONFIG_PACKAGE_kmod-brcm-wl-mimo \
+	CONFIG_PACKAGE_kmod-madwifi \
+	CONFIG_PACKAGE_kmod-cfg80211
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define Package/libiwinfo
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Generalized Wireless Information Library (iwinfo)
+  DEPENDS:=+PACKAGE_kmod-cfg80211:libnl-tiny +libuci
+  ABI_VERSION:=$(PKG_RELEASE)
+endef
+
+define Package/libiwinfo/description
+  Wireless information library with consistent interface for proprietary Broadcom,
+  madwifi, nl80211 and wext driver interfaces.
+endef
+
+
+define Package/libiwinfo-lua
+  SUBMENU:=Lua
+  SECTION:=lang
+  CATEGORY:=Languages
+  TITLE:=libiwinfo Lua binding
+  DEPENDS:=+libiwinfo +liblua
+endef
+
+define Package/libiwinfo-lua/description
+  This is the Lua binding for the iwinfo library. It provides access to all enabled
+  backends.
+endef
+
+
+define Package/iwinfo
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Generalized Wireless Information utility
+  DEPENDS:=+libiwinfo
+endef
+
+define Package/iwinfo/description
+  Command line frontend for the wireless information library.
+endef
+
+
+define Build/Configure
+endef
+
+IWINFO_BACKENDS := \
+	$(if $(CONFIG_PACKAGE_kmod-brcm-wl),wl) \
+	$(if $(CONFIG_PACKAGE_kmod-brcm-wl-mini),wl) \
+	$(if $(CONFIG_PACKAGE_kmod-brcm-wl-mimo),wl) \
+	$(if $(CONFIG_PACKAGE_kmod-madwifi),madwifi) \
+	$(if $(CONFIG_PACKAGE_kmod-cfg80211),nl80211)
+
+TARGET_CFLAGS += \
+	-I$(STAGING_DIR)/usr/include/libnl-tiny \
+	-I$(STAGING_DIR)/usr/include \
+	-D_GNU_SOURCE
+
+MAKE_FLAGS += \
+	FPIC="$(FPIC)" \
+	CFLAGS="$(TARGET_CFLAGS)" \
+	LDFLAGS="$(TARGET_LDFLAGS)" \
+	BACKENDS="$(IWINFO_BACKENDS)"
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include/iwinfo
+	$(CP) $(PKG_BUILD_DIR)/include/iwinfo.h $(1)/usr/include/
+	$(CP) $(PKG_BUILD_DIR)/include/iwinfo/* $(1)/usr/include/iwinfo/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/libiwinfo.so $(1)/usr/lib/libiwinfo.so
+	$(INSTALL_DIR) $(1)/usr/lib/lua
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo.so $(1)/usr/lib/lua/iwinfo.so
+endef
+
+define Package/libiwinfo/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/libiwinfo.so $(1)/usr/lib/libiwinfo.so
+	$(INSTALL_DIR) $(1)/usr/share/libiwinfo
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/hardware.txt $(1)/usr/share/libiwinfo/hardware.txt
+endef
+
+define Package/libiwinfo-lua/install
+	$(INSTALL_DIR) $(1)/usr/lib/lua
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo.so $(1)/usr/lib/lua/iwinfo.so
+endef
+
+define Package/iwinfo/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/iwinfo $(1)/usr/bin/iwinfo
+endef
+
+$(eval $(call BuildPackage,libiwinfo))
+$(eval $(call BuildPackage,libiwinfo-lua))
+$(eval $(call BuildPackage,iwinfo))
diff --git a/package/network/utils/linux-atm/Makefile b/package/network/utils/linux-atm/Makefile
new file mode 100644
index 0000000000..62d71ea75d
--- /dev/null
+++ b/package/network/utils/linux-atm/Makefile
@@ -0,0 +1,196 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=linux-atm
+PKG_VERSION:=2.5.2
+PKG_RELEASE:=5
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/$(PKG_NAME)
+PKG_MD5SUM:=d49499368c3cf15f73a05d9bce8824a8
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_LICENSE:=GPL-2.0+
+PKG_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/package.mk
+
+ATM_DEBUG_BINS:=aread awrite atmdiag atmdump atmswitch saaldump \
+		sonetdiag svc_recv svc_send ttcp_atm
+ATM_DEBUG_SBINS:=atmaddr atmloop atmtcp esi atmsigd bus \
+		 ilmid ilmidiag lecs les mpcd zeppelin
+ATM_DEBUG_TOOLS:=$(ATM_DEBUG_BINS) $(ATM_DEBUG_SBINS)
+
+define Package/linux-atm
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Linux ATM library
+  URL:=http://linux-atm.sourceforge.net/
+endef
+
+define Package/linux-atm/description
+  This package contains a library for accessing the Linux ATM subsystem.
+endef
+
+define Package/linux-atm/Default
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+linux-atm
+  URL:=http://linux-atm.sourceforge.net/
+  SUBMENU:=Linux ATM tools
+endef
+
+define Package/atm-tools
+  $(call Package/linux-atm/Default)
+  TITLE:=Linux ATM tools
+endef
+
+define Package/atm-tools/description
+  This package contains the Linux ATM tools.
+endef
+
+define Package/atm-diagnostics
+  $(call Package/linux-atm/Default)
+  TITLE:=Linux ATM Diagnostics
+endef
+
+define Package/atm-diagnostics/description
+  This package contains the Linux ATM diagnostics.
+endef
+
+define Package/atm-debug-tools
+  $(call Package/linux-atm/Default)
+  TITLE:=Linux ATM debugging tools
+endef
+
+define Package/atm-debug-tools/description
+  This package contains the Linux ATM debugging tools.
+endef
+
+define Package/br2684ctl
+  $(call Package/linux-atm/Default)
+  TITLE:=ATM Ethernet bridging configuration utility
+endef
+
+define Package/br2684ctl/description
+  Support for AAL5 encapsulation (RFC-1483/RFC-2684) over ATM.
+endef
+
+define GenAtmPlugin
+  define Package/$(1)
+     $(call Package/linux-atm/Default)
+     TITLE:=Linux ATM tool $(2)
+  endef
+
+  define Package/$(1)/description
+     Linux ATM tool $(2).
+  endef
+endef
+
+$(foreach t,$(ATM_DEBUG_TOOLS),$(eval $(call GenAtmPlugin,atm-$(t),$(t))))
+
+define Build/Configure
+	$(call Build/Configure/Default)
+	# prevent autoheader invocation
+	touch $(PKG_BUILD_DIR)/stamp-h.in
+endef
+
+unexport PREFIX
+
+define Build/Compile
+	# src/qgen is built with HOSTCC, which does not really like our LDFLAGS
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/src/qgen \
+		LDFLAGS="" \
+		all
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) OBJCOPY=$(TARGET_CROSS)objcopy all
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/include \
+		$(PKG_INSTALL_DIR)/usr/lib \
+		$(1)/usr/
+endef
+
+define Package/linux-atm/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libatm.so* $(1)/usr/lib/
+endef
+
+define Package/atm-tools/install
+	$(INSTALL_DIR) $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/atmarp{,d} $(1)/usr/sbin/
+endef
+
+
+define BuildAtmPlugin
+  define Package/$(1)/install
+	$(INSTALL_DIR) $$(1)/usr/$(3)
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/$(3)/$(2) $$(1)/usr/$(3)
+  endef
+
+  $$(eval $$(call BuildPackage,$(1)))
+endef
+
+define Package/atm-debug-tools/install
+	$(INSTALL_DIR) $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/atmaddr $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/atmloop $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/atmtcp     $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/esi $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/aread $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/awrite $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atmdiag $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atmdump $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/atmsigd $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/bus $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ilmid $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ilmidiag $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/lecs $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/les $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/mpcd $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/zeppelin $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atmswitch $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/saaldump $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/sonetdiag $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/svc_recv $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/svc_send $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/ttcp_atm $(1)/usr/bin/
+endef
+
+define Package/atm-diagnostics/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/aread $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/awrite $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atmdiag $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atmdump $(1)/usr/bin/
+endef
+
+define Package/br2684ctl/install
+	$(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/hotplug.d/atm $(1)/usr/sbin $(1)/lib/netifd
+	$(INSTALL_BIN) ./files/br2684-up $(1)/lib/netifd/br2684-up
+	$(INSTALL_BIN) ./files/br2684ctl $(1)/etc/init.d/
+	$(INSTALL_DATA) ./files/atm.hotplug $(1)/etc/hotplug.d/atm/00-trigger
+	$(INSTALL_BIN) \
+		./files/br2684ctl_wrap \
+		$(PKG_INSTALL_DIR)/usr/sbin/br2684ctl \
+		$(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,linux-atm))
+$(eval $(call BuildPackage,atm-tools))
+$(eval $(call BuildPackage,atm-debug-tools))
+$(eval $(call BuildPackage,atm-diagnostics))
+$(eval $(call BuildPackage,br2684ctl))
+$(foreach t,$(ATM_DEBUG_BINS),$(eval $(call BuildAtmPlugin,atm-$(t),$(t),bin)))
+$(foreach t,$(ATM_DEBUG_SBINS),$(eval $(call BuildAtmPlugin,atm-$(t),$(t),sbin)))
diff --git a/package/network/utils/linux-atm/files/atm.hotplug b/package/network/utils/linux-atm/files/atm.hotplug
new file mode 100644
index 0000000000..68fb96d3ac
--- /dev/null
+++ b/package/network/utils/linux-atm/files/atm.hotplug
@@ -0,0 +1 @@
+ubus call service event '{ "type": "hotplug.atm", "data": { "name": "'"$DEVICENAME"'" } }'
diff --git a/package/network/utils/linux-atm/files/br2684-up b/package/network/utils/linux-atm/files/br2684-up
new file mode 100644
index 0000000000..ba1d67023e
--- /dev/null
+++ b/package/network/utils/linux-atm/files/br2684-up
@@ -0,0 +1,3 @@
+#!/bin/sh
+. /lib/functions/network.sh
+network_ready_device "$1"
diff --git a/package/network/utils/linux-atm/files/br2684ctl b/package/network/utils/linux-atm/files/br2684ctl
new file mode 100755
index 0000000000..0fa86bdefd
--- /dev/null
+++ b/package/network/utils/linux-atm/files/br2684ctl
@@ -0,0 +1,81 @@
+#!/bin/sh /etc/rc.common
+
+START=50
+USE_PROCD=1
+
+start_daemon() {
+	local cfg="$1"
+
+	local atmdev disabled
+
+	config_get_bool disabled "$cfg" disabled 0
+	[ "$disabled" -eq 1 ] && return
+
+	config_get atmdev "$cfg" atmdev 0
+
+	local unit
+	config_get unit "$cfg" unit 0
+
+	local vpi
+	config_get vpi "$cfg" vpi 8
+
+	local vci
+	config_get vci "$cfg" vci 35
+
+	local encaps
+	config_get encaps "$cfg" encaps
+
+	case "$encaps" in
+		1|vc) encaps=1;;
+		*) encaps=0;;
+	esac
+
+	local payload
+	config_get payload "$cfg" payload
+
+	case "$payload" in
+		0|routed) payload=0;;
+		*) payload=1;;
+	esac
+
+	local qos
+	config_get qos "$cfg" qos
+
+	local sendsize
+	config_get sendsize "$cfg" sendsize
+
+	found=
+	for device in /sys/class/atm/*; do
+		[ -d "$device" ] || break
+		[ "$(cat $device/atmindex)" = "$atmdev" ] || continue
+		found=1
+		break
+	done
+
+	[ -n "$found" ] || return
+
+	local circuit="$atmdev.$vpi.$vci"
+
+	procd_open_instance
+	procd_set_param command \
+		/usr/sbin/br2684ctl_wrap "nas$unit" \
+		-c "$unit" -e "$encaps" -p "$payload" \
+		-a "$circuit" ${qos:+-q "$qos"} ${sendsize:+-s "$sendsize"} \
+		-S /lib/netifd/br2684-up
+	procd_close_instance
+}
+
+service_triggers() {
+	local script=$(readlink "$initscript")
+	local name=$(basename ${script:-$initscript})
+
+	procd_open_trigger
+	procd_add_raw_trigger hotplug.atm 2000 /etc/init.d/$name reload
+	procd_add_config_trigger "config.change" "network" /etc/init.d/$name reload
+	procd_close_trigger
+}
+
+start_service() {
+	config_load network
+	config_foreach start_daemon atm-bridge
+}
diff --git a/package/network/utils/linux-atm/files/br2684ctl_wrap b/package/network/utils/linux-atm/files/br2684ctl_wrap
new file mode 100644
index 0000000000..d1bc98e014
--- /dev/null
+++ b/package/network/utils/linux-atm/files/br2684ctl_wrap
@@ -0,0 +1,5 @@
+#!/bin/sh
+. /lib/functions/network.sh
+device="$1"; shift
+network_defer_device "$device"
+exec /usr/sbin/br2684ctl "$@"
diff --git a/package/network/utils/linux-atm/patches/000-debian_16.patch b/package/network/utils/linux-atm/patches/000-debian_16.patch
new file mode 100644
index 0000000000..4abaac07e8
--- /dev/null
+++ b/package/network/utils/linux-atm/patches/000-debian_16.patch
@@ -0,0 +1,270 @@
+--- a/src/arpd/io.c
++++ b/src/arpd/io.c
+@@ -277,7 +277,8 @@ static void accept_new(void)
+     struct atm_qos qos;
+     ENTRY *entry;
+     VCC *vcc;
+-    int fd,len,size,error;
++    int fd,error;
++    socklen_t len,size;
+ 
+     len = sizeof(addr);
+     if ((fd = accept(incoming,(struct sockaddr *) &addr,&len)) < 0) {
+@@ -614,7 +615,8 @@ int ip_itf_info(int number,uint32_t *ip,
+ 
+ int get_local(int fd,struct sockaddr_atmsvc *addr)
+ {
+-    int length,result;
++    int result;
++    size_t length;
+ 
+     length = sizeof(struct sockaddr_atmsvc);
+     result = getsockname(fd,(struct sockaddr *) addr,&length);
+--- a/src/arpd/table.c
++++ b/src/arpd/table.c
+@@ -101,7 +101,8 @@ static void dump_vcc(VCC *vcc)
+     char addr_buf[MAX_ATM_ADDR_LEN+1];
+     char qos_buf[MAX_ATM_QOS_LEN+1];
+     struct atm_qos qos;
+-    int size,sndbuf;
++    int sndbuf;
++    socklen_t size;
+ 
+     size = sizeof(addr);
+     if (getpeername(vcc->fd,(struct sockaddr *) &addr,&size) < 0) {
+--- a/src/ilmid/asn1/asn_int.c
++++ b/src/ilmid/asn1/asn_int.c
+@@ -185,7 +185,7 @@ FILE* f _AND_
+ AsnInt* v _AND_
+ unsigned short int indent)
+ {
+-    fprintf(f,"%d", *v);
++    fprintf(f,"%ld", *v);
+ } 
+ 
+ 
+@@ -370,5 +370,5 @@ FILE* f _AND_
+ UAsnInt* v _AND_
+ unsigned short int indent)
+ {
+-    fprintf(f,"%u", *v);
++    fprintf(f,"%lu", *v);
+ } 
+--- a/src/ilmid/asn1/asn_oid.c
++++ b/src/ilmid/asn1/asn_oid.c
+@@ -127,7 +127,7 @@ unsigned short int indent)
+     if (firstArcNum > 2)
+         firstArcNum = 2;
+ 
+-    fprintf(f,"%u %u", firstArcNum, arcNum - (firstArcNum * 40));
++    fprintf(f,"%d %lu", firstArcNum, arcNum - (firstArcNum * 40));
+ 
+     for (; i < v->octetLen ; )
+     {
+@@ -136,7 +136,7 @@ unsigned short int indent)
+ 
+         arcNum = (arcNum << 7) + (v->octs[i] & 0x7f);
+         i++;
+-        fprintf(f," %u", arcNum);
++        fprintf(f," %lu", arcNum);
+     }
+     fprintf(f,"}");
+ 
+--- a/src/lane/connect.c
++++ b/src/lane/connect.c
+@@ -258,7 +258,8 @@ static int
+ data_handler(const Event_t *event, void *funcdata)
+ {
+   Conn_t *tmp, *newconn;
+-  int fd, nbytes;
++  int fd;
++  socklen_t nbytes;
+   static char buffer[BUFSIZE];
+   LaneControl_t *ctmp;
+   struct sockaddr_atmsvc addr;
+--- a/src/lane/connect_bus.c
++++ b/src/lane/connect_bus.c
+@@ -170,7 +170,8 @@ static int
+ data_handler(const Event_t *event, void *funcdata)
+ {
+   Conn_t *tmp, *newconn;
+-  int fd, nbytes;
++  int fd;
++  socklen_t nbytes;
+   static char buffer[BUFSIZE];
+   struct sockaddr_atmsvc addr;
+ 
+--- a/src/lane/lane_atm.c
++++ b/src/lane/lane_atm.c
+@@ -138,7 +138,7 @@ atm_connect_back(const AtmAddr_t *our_ad
+   struct atm_blli blli;
+   struct atm_qos qos;
+   int fd, ret;
+-  int len = sizeof(address);
++  socklen_t len = sizeof(address);
+   
+   fd = socket(PF_ATMSVC, SOCK_DGRAM, 0);
+   if (fd <0) {
+--- a/src/lane/lecs.c
++++ b/src/lane/lecs.c
+@@ -119,7 +119,7 @@ int main(int argc, char **argv)
+   int just_dump=0;
+   fd_set fds;
+   struct sockaddr_atmsvc client;
+-  int len;
++  socklen_t len;
+   unsigned char buffer[P_SIZE];
+ 
+   while(i!=-1) {
+--- a/src/lib/ans.c
++++ b/src/lib/ans.c
+@@ -41,7 +41,7 @@
+ static int ans(const char *text,int wanted,void *result,int res_len)
+ {
+     unsigned char answer[MAX_ANSWER];
+-    unsigned char name[MAX_NAME];
++    char name[MAX_NAME];
+     unsigned char *pos,*data,*found;
+     int answer_len,name_len,data_len,found_len;
+     int questions,answers;
+--- a/src/lib/sdu2cell.c
++++ b/src/lib/sdu2cell.c
+@@ -15,7 +15,8 @@ int sdu2cell(int s,int sizes,const int *
+ {
+     struct atm_qos qos;
+     int trailer,total,cells;
+-    int size,i;
++    int i;
++    socklen_t size;
+ 
+     size = sizeof(qos);
+     if (getsockopt(s,SOL_AAL,SO_ATMQOS,&qos,&size) < 0) return -1;
+--- a/src/lib/unix.c
++++ b/src/lib/unix.c
+@@ -63,8 +63,8 @@ int un_attach(const char *path)
+ int un_recv_connect(int s,void *buf,int size)
+ {
+     struct sockaddr_un addr;
+-    int addr_size;
+     int len;
++    socklen_t addr_size;
+ 
+     addr_size = sizeof(addr);
+     len = recvfrom(s,buf,size,0,(struct sockaddr *) &addr,&addr_size);
+--- a/src/maint/atmtcp.c
++++ b/src/maint/atmtcp.c
+@@ -817,7 +817,8 @@ int main(int argc,char **argv)
+ 	}
+ 	else if (!strcmp(ARG,"listen") ||
+ 	  (do_background = !strcmp(ARG,"listen-bg"))) {
+-	    int fd,port,addr_len;
++	    int fd,port;
++	    socklen_t addr_len;
+ 	    int *fd2 = alloc_t(int);
+ 
+ 	    if ((fd = socket(PF_INET,SOCK_STREAM,0)) < 0) {
+--- a/src/maint/hediag.c
++++ b/src/maint/hediag.c
+@@ -1,6 +1,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
++#include <string.h>
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+--- a/src/mpoad/io.c
++++ b/src/mpoad/io.c
+@@ -521,7 +521,8 @@ static int msg_from_mps(int slot)
+ static int accept_conn(int slot)
+ {
+         struct sockaddr_atmsvc sa;
+-        int i, new_fd, sa_len;
++        int i, new_fd;
++        socklen_t sa_len;
+ 
+         sa_len = sizeof(sa);
+         new_fd = accept(fds[slot].fd, (struct sockaddr *)&sa, &sa_len);
+--- a/src/sigd/io.c
++++ b/src/sigd/io.c
+@@ -355,7 +355,7 @@ int get_pvc(int itf,int *vci)
+     error = 0;
+     if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) error = errno;
+     else {
+-	int size;
++	socklen_t size;
+ 
+ 	size = sizeof(addr);
+ 	if (getsockname(s,(struct sockaddr *) &addr,&size) < 0)
+--- a/src/test/ttcp.c
++++ b/src/test/ttcp.c
+@@ -92,7 +92,8 @@ struct sockaddr_in frominet;
+ struct sockaddr_atmsvc satm;
+ struct atm_qos qos;
+ 
+-int domain, fromlen;
++int domain;
++socklen_t fromlen;
+ int fd;				/* fd of network socket */
+ 
+ int buflen = 8 * 1024;		/* length of buffer */
+@@ -466,7 +467,7 @@ int no_check = 0;
+ 	    
+ 	    {
+ 		struct sockaddr_atmsvc peer;
+-		int peerlen = sizeof(peer);
++		socklen_t peerlen = sizeof(peer);
+ 		if (getpeername(fd, (struct sockaddr *) &peer, 
+ 				&peerlen) < 0) {
+ 		    err("getpeername");
+@@ -498,7 +499,7 @@ int no_check = 0;
+     /* set socket buffer size */
+ #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
+     if (sockbufsize) {
+-	int len;
++	socklen_t len;
+ 
+ 	if (trans) {
+ 	    /* set send socket buffer if we are transmitting */    
+--- a/src/mpoad/mpcd.8
++++ b/src/mpoad/mpcd.8
+@@ -28,7 +28,7 @@ mpcd \- ATM MPOA (Multi\-Protocol Over A
+ .B ]]
+ .SH DESCRIPTION
+ MPOA client
+-.SM(MPC) is responsible for creating and receiving
++.SM (MPC) is responsible for creating and receiving
+ internetwork layer shortcuts. Using these shortcuts MPCs forward
+ unicast internetwork layer packets effectively over ATM without need
+ for routing protocols.
+@@ -43,7 +43,7 @@ accepts shortcuts and packets arriving o
+ shortcuts is done with the help of
+ .SM MPOA
+ server
+-.SM(MPS).
++.SM (MPS).
+ .PP
+ Just as the Linux
+ .SM LAN
+--- a/src/led/zeppelin.8
++++ b/src/led/zeppelin.8
+@@ -99,7 +99,7 @@ Ring and ATM parts of the ELAN, so using
+ recommended. Token Ring support has received less testing than its
+ Ethernet counterpart.
+ .SH FILES
+-.IP \fI/var/run/lec[interface number].pid\fP
++.IP \fI/var/run/lec[interface\ number].pid\fP
+ The file containing the process id of zeppelin.
+ .SH BUGS
+ John Bonham died 1980 and Led Zeppelin broke.
+--- a/src/sigd/atmsigd.conf.4
++++ b/src/sigd/atmsigd.conf.4
+@@ -125,7 +125,7 @@ a comment. The `#' character cannot be e
+ .P
+ If an option is specified in \fBatmsigd.conf\fP and on the command
+ line, the command line has priority.
+-.COMPATIBILITY
++.SH COMPATIBILITY
+ Certain options used by past versions of \fBatmsigd\fP but no longer documented
+ on the man page are still recognized and supported, but they also yield a
+ warning message. Future versions of \fBatmsigd\fP will not recognize those
diff --git a/package/network/utils/linux-atm/patches/200-no_libfl.patch b/package/network/utils/linux-atm/patches/200-no_libfl.patch
new file mode 100644
index 0000000000..6db877931f
--- /dev/null
+++ b/package/network/utils/linux-atm/patches/200-no_libfl.patch
@@ -0,0 +1,179 @@
+--- a/src/qgen/Makefile.am
++++ b/src/qgen/Makefile.am
+@@ -2,7 +2,7 @@ noinst_PROGRAMS = qgen
+ 
+ qgen_SOURCES = common.c common.h file.c file.h first.c ql_y.y ql_l.l qgen.c \
+ 		qgen.h second.c third.c
+-qgen_LDADD = -lfl
++qgen_LDADD = 
+ 
+ COMPILE = @CC_FOR_BUILD@ @CFLAGS_FOR_BUILD@
+ LINK = @CC_FOR_BUILD@ @CFLAGS_FOR_BUILD@ -o $@
+--- a/src/qgen/Makefile.in
++++ b/src/qgen/Makefile.in
+@@ -204,7 +204,7 @@ top_srcdir = @top_srcdir@
+ qgen_SOURCES = common.c common.h file.c file.h first.c ql_y.y ql_l.l qgen.c \
+ 		qgen.h second.c third.c
+ 
+-qgen_LDADD = -lfl
++qgen_LDADD =
+ COMPILE = @CC_FOR_BUILD@ @CFLAGS_FOR_BUILD@
+ LINK = @CC_FOR_BUILD@ @CFLAGS_FOR_BUILD@ -o $@
+ 
+--- a/src/sigd/Makefile.am
++++ b/src/sigd/Makefile.am
+@@ -8,7 +8,7 @@ atmsigd_XTRAS = mess.o $(top_builddir)/s
+ 			$(top_builddir)/src/q2931/qd.dump.o \
+ 			$(top_builddir)/src/lib/libatm.la \
+ 			$(top_builddir)/src/saal/libsaal.a
+-atmsigd_LDADD = $(atmsigd_XTRAS) -lfl
++atmsigd_LDADD = $(atmsigd_XTRAS) 
+ atmsigd_DEPENDENCIES = mess.c $(atmsigd_XTRAS)
+ 
+ CLEANFILES = mess.c
+--- a/src/sigd/Makefile.in
++++ b/src/sigd/Makefile.in
+@@ -245,7 +245,7 @@ atmsigd_XTRAS = mess.o $(top_builddir)/s
+ 			$(top_builddir)/src/lib/libatm.la \
+ 			$(top_builddir)/src/saal/libsaal.a
+ 
+-atmsigd_LDADD = $(atmsigd_XTRAS) -lfl
++atmsigd_LDADD = $(atmsigd_XTRAS) 
+ atmsigd_DEPENDENCIES = mess.c $(atmsigd_XTRAS)
+ CLEANFILES = mess.c
+ sysconf_DATA = atmsigd.conf
+--- a/src/switch/debug/debug.c
++++ b/src/switch/debug/debug.c
+@@ -20,6 +20,11 @@
+ 
+ #define PRV(call) ((FAB *) (call)->fab)
+ 
++int yywrap(void)
++{
++        return 1;
++}
++
+ 
+ typedef struct _fab {
+     CALL *next; /* relay.c may not keep track of calls, but WE are */
+--- a/src/switch/debug/Makefile.am
++++ b/src/switch/debug/Makefile.am
+@@ -5,7 +5,7 @@ INCLUDES = -I$(srcdir)/../../q2931
+ sw_debug_SOURCES = debug.c
+ sw_debug_XTRAS = $(top_builddir)/src/switch/libsw.a \
+ 			$(top_builddir)/src/lib/libatm.la
+-sw_debug_LDADD = $(sw_debug_XTRAS) -lfl
++sw_debug_LDADD = $(sw_debug_XTRAS) 
+ 			
+ sw_debug_DEPENDENCIES = $(sw_debug_XTRAS)
+ 
+--- a/src/switch/debug/Makefile.in
++++ b/src/switch/debug/Makefile.in
+@@ -200,7 +200,8 @@ sw_debug_SOURCES = debug.c
+ sw_debug_XTRAS = $(top_builddir)/src/switch/libsw.a \
+ 			$(top_builddir)/src/lib/libatm.la
+ 
+-sw_debug_LDADD = $(sw_debug_XTRAS) -lfl
++sw_debug_LDADD = $(sw_debug_XTRAS)
++
+ sw_debug_DEPENDENCIES = $(sw_debug_XTRAS)
+ EXTRA_DIST = demo README
+ all: all-am
+--- a/src/switch/tcp/Makefile.am
++++ b/src/switch/tcp/Makefile.am
+@@ -5,7 +5,7 @@ INCLUDES = -I$(srcdir)/../../q2931
+ sw_tcp_SOURCES = tcpsw.c
+ sw_tcp_XTRAS = $(top_builddir)/src/switch/libsw.a \
+ 		$(top_builddir)/src/lib/libatm.la
+-sw_tcp_LDADD = $(sw_tcp_XTRAS) -lfl
++sw_tcp_LDADD = $(sw_tcp_XTRAS) 
+ sw_tcp_DEPENDENCIES = $(sw_tcp_XTRAS)
+ 
+ EXTRA_DIST = mkfiles README
+--- a/src/switch/tcp/Makefile.in
++++ b/src/switch/tcp/Makefile.in
+@@ -200,7 +200,7 @@ sw_tcp_SOURCES = tcpsw.c
+ sw_tcp_XTRAS = $(top_builddir)/src/switch/libsw.a \
+ 		$(top_builddir)/src/lib/libatm.la
+ 
+-sw_tcp_LDADD = $(sw_tcp_XTRAS) -lfl
++sw_tcp_LDADD = $(sw_tcp_XTRAS) 
+ sw_tcp_DEPENDENCIES = $(sw_tcp_XTRAS)
+ EXTRA_DIST = mkfiles README
+ all: all-am
+--- a/src/switch/tcp/tcpsw.c
++++ b/src/switch/tcp/tcpsw.c
+@@ -35,6 +35,10 @@
+ #define MAX_PACKET (ATM_MAX_AAL5_PDU+sizeof(struct atmtcp_hdr))
+ #define BUFFER_SIZE (MAX_PACKET*2)
+ 
++int yywrap(void)
++{
++        return 1;
++}
+ 
+ typedef struct _table {
+     struct _link *out;	/* output port */
+--- a/src/test/Makefile.am
++++ b/src/test/Makefile.am
+@@ -20,7 +20,7 @@ br_SOURCES = br.c
+ bw_SOURCES = bw.c
+ isp_SOURCES = isp.c isp.h ispl_y.y ispl_l.l
+ isp_XTRAS = $(LDADD)
+-isp_LDADD = $(isp_XTRAS) -lfl
++isp_LDADD = $(isp_XTRAS)
+ isp_DEPENDENCIES = $(isp_XTRAS)
+ window_SOURCES = window.c
+ 
+--- a/src/test/Makefile.in
++++ b/src/test/Makefile.in
+@@ -283,7 +283,7 @@ br_SOURCES = br.c
+ bw_SOURCES = bw.c
+ isp_SOURCES = isp.c isp.h ispl_y.y ispl_l.l
+ isp_XTRAS = $(LDADD)
+-isp_LDADD = $(isp_XTRAS) -lfl
++isp_LDADD = $(isp_XTRAS)
+ isp_DEPENDENCIES = $(isp_XTRAS)
+ window_SOURCES = window.c
+ CLEANFILES = errnos.inc
+--- a/src/test/ispl_l.l
++++ b/src/test/ispl_l.l
+@@ -18,6 +18,11 @@
+ #include "ispl_y.h"
+ 
+ 
++int yywrap(void)
++{
++       return 1;
++}
++
+ static int lineno = 1;
+ 
+ %}
+--- a/src/qgen/ql_l.l
++++ b/src/qgen/ql_l.l
+@@ -11,6 +11,11 @@
+ #include "ql_y.h"
+ 
+ 
++int yywrap(void)
++{
++        return 1;
++}
++
+ typedef struct _tree {
+     struct _tree *left,*right;
+     const char str[0];
+--- a/src/sigd/cfg_l.l
++++ b/src/sigd/cfg_l.l
+@@ -16,6 +16,10 @@
+ 
+ #include "cfg_y.h"
+ 
++int yywrap(void)
++{
++        return 1;
++}
+ 
+ static int lineno = 1;
+ static int token; /* f@#%ing flex doesn't grok return after BEGIN */
diff --git a/package/network/utils/linux-atm/patches/300-objcopy_path.patch b/package/network/utils/linux-atm/patches/300-objcopy_path.patch
new file mode 100644
index 0000000000..4f11516b2f
--- /dev/null
+++ b/package/network/utils/linux-atm/patches/300-objcopy_path.patch
@@ -0,0 +1,40 @@
+--- a/src/extra/Makefile.am
++++ b/src/extra/Makefile.am
+@@ -7,6 +7,8 @@ EXTRA_DIST = linux-atm.spec.in \
+ BUILT_SOURCES = pca200e.bin pca200e_ecd.bin2 sba200e_ecd.bin2
+ CLEANFILES = pca200e.bin pca200e_ecd.bin2 sba200e_ecd.bin2
+ 
++OBJCOPY = objcopy
++
+ install-exec-hook:
+ 	$(MKDIR_P) $(DESTDIR)/lib/firmware
+ 	$(INSTALL_DATA) $(srcdir)/pca200e.bin $(DESTDIR)/lib/firmware
+@@ -14,7 +16,7 @@ install-exec-hook:
+ 	$(INSTALL_DATA) $(srcdir)/sba200e_ecd.bin2 $(DESTDIR)/lib/firmware
+ 
+ %.bin %.bin2: %.data
+-	objcopy -Iihex $< -Obinary $@.gz
++	$(OBJCOPY) -Iihex $< -Obinary $@.gz
+ 	gzip -n -df $@.gz
+ 
+ 
+--- a/src/extra/Makefile.in
++++ b/src/extra/Makefile.in
+@@ -187,6 +187,8 @@ CLEANFILES = pca200e.bin pca200e_ecd.bin
+ all: $(BUILT_SOURCES)
+ 	$(MAKE) $(AM_MAKEFLAGS) all-am
+ 
++OBJCOPY = objcopy
++
+ .SUFFIXES:
+ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+ 	@for dep in $?; do \
+@@ -385,7 +387,7 @@ install-exec-hook:
+ 	$(INSTALL_DATA) $(srcdir)/sba200e_ecd.bin2 $(DESTDIR)/lib/firmware
+ 
+ %.bin %.bin2: %.data
+-	objcopy -Iihex $< -Obinary $@.gz
++	$(OBJCOPY) -Iihex $< -Obinary $@.gz
+ 	gzip -n -df $@.gz
+ 
+ # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/package/network/utils/linux-atm/patches/400-portability_fixes.patch b/package/network/utils/linux-atm/patches/400-portability_fixes.patch
new file mode 100644
index 0000000000..9fe3e1faea
--- /dev/null
+++ b/package/network/utils/linux-atm/patches/400-portability_fixes.patch
@@ -0,0 +1,56 @@
+--- a/src/ilmid/io.c
++++ b/src/ilmid/io.c
+@@ -48,6 +48,14 @@
+ 			     be manually configured (after ilmid has
+ 			     registered the "official" address) - HACK */
+ 
++#ifndef SUN_LEN
++# include <string.h>            /* For prototype of `strlen'.  */
++
++/* Evaluate to actual length of the `sockaddr_un' structure.  */
++# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)        \
++                      + strlen ((ptr)->sun_path))
++#endif
++
+ extern SysGroup *remsys;
+ extern State ilmi_state;
+ static short atm_itf = -1; /* bad value */
+--- a/src/mpoad/io.c
++++ b/src/mpoad/io.c
+@@ -10,14 +10,7 @@
+ #include <errno.h>
+ #include <sys/ioctl.h>
+ #include <sys/param.h> /* for OPEN_MAX   */
+-#if __GLIBC__ >= 2
+ #include <sys/poll.h>
+-#else /* ugly hack to make it compile on RH 4.2 - WA */
+-#include <syscall.h>
+-#include <linux/poll.h>
+-#define SYS_poll 168
+-_syscall3(int,poll,struct pollfd *,ufds,unsigned int,nfds,int,timeout);
+-#endif
+ #include <atm.h>
+ #include <linux/types.h>
+ #include <linux/atmioc.h>
+--- a/src/sigd/atmsigd.c
++++ b/src/sigd/atmsigd.c
+@@ -517,7 +517,7 @@ int main(int argc,char **argv)
+ 	    exit(0);
+ 	}
+     }
+-    (void) on_exit(trace_on_exit,NULL);
++    (void) atexit(trace_on_exit);
+     poll_loop();
+     close_all();
+     for (sig = entities; sig; sig = sig->next) stop_saal(&sig->saal);
+--- a/src/test/align.c
++++ b/src/test/align.c
+@@ -24,7 +24,7 @@
+ #include <signal.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+-#include <sys/errno.h>
++#include <errno.h>
+ #include <atm.h>
+ 
+ 
diff --git a/package/network/utils/linux-atm/patches/500-br2684ctl_script.patch b/package/network/utils/linux-atm/patches/500-br2684ctl_script.patch
new file mode 100644
index 0000000000..78aabf894c
--- /dev/null
+++ b/package/network/utils/linux-atm/patches/500-br2684ctl_script.patch
@@ -0,0 +1,63 @@
+--- a/src/br2684/br2684ctl.c
++++ b/src/br2684/br2684ctl.c
+@@ -1,3 +1,4 @@
++#define _GNU_SOURCE
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+@@ -43,6 +44,7 @@ struct br2684_params {
+ 
+ 
+ int lastsock, lastitf;
++static char *up_script;
+ 
+ 
+ void fatal(const char *str, int err)
+@@ -185,6 +187,8 @@ int assign_vcc(char *astr, int encap, in
+ 
+ void start_interface(struct br2684_params* params)
+ {
++  char *cmd;
++
+   if (params->astr==NULL) {
+     syslog(LOG_ERR, "Required ATM parameters not specified.");
+     exit(1);
+@@ -193,13 +197,18 @@ void start_interface(struct br2684_param
+   create_br(params->itfnum, params->payload);
+   assign_vcc(params->astr, params->encap, params->payload, params->sndbuf,
+ 	     params->reqqos);
++  if (up_script) {
++    asprintf(&cmd, "%s nas%d", up_script, lastitf);
++    system(cmd);
++    free(cmd);
++  }
+ }
+ 
+ 
+ void usage(char *s)
+ {
+   printf("usage: %s [-b] [[-c number] [-e 0|1] [-s sndbuf] [-q qos] [-p 0|1] "
+-	 "[-a [itf.]vpi.vci]*]*\n", s);
++	 "[-a [itf.]vpi.vci]*]* [-S script]\n", s);
+   printf("  encapsulations: 0=llc, 1=vcmux\n  payloads: 0=routed, 1=bridged\n");
+   exit(1);
+ }
+@@ -225,7 +234,7 @@ int main (int argc, char **argv)
+ 
+   openlog (LOG_NAME,LOG_OPTION,LOG_FACILITY);
+   if (argc>1)
+-    while ((c = getopt(argc, argv,"q:a:bc:e:s:p:?h")) !=EOF)
++    while ((c = getopt(argc, argv,"q:a:bc:e:s:S:p:?h")) !=EOF)
+       switch (c) {
+       case 'q':
+ 	printf ("optarg : %s",optarg);
+@@ -258,6 +267,9 @@ int main (int argc, char **argv)
+ 	  params.sndbuf=8192;
+ 	}
+ 	break;
++      case 'S':
++	up_script = optarg;
++	break;
+       case 'p':	/* payload type: routed (0) or bridged (1) */
+ #ifdef BR2684_FLAG_ROUTED
+ 	params.payload = atoi(optarg);
diff --git a/package/network/utils/linux-atm/patches/600-fix-format-errors.patch b/package/network/utils/linux-atm/patches/600-fix-format-errors.patch
new file mode 100644
index 0000000000..ef484f2fa3
--- /dev/null
+++ b/package/network/utils/linux-atm/patches/600-fix-format-errors.patch
@@ -0,0 +1,11 @@
+--- a/src/test/ttcp.c
++++ b/src/test/ttcp.c
+@@ -664,7 +664,7 @@ int no_check = 0;
+     exit(0);
+ 
+   usage:
+-    fprintf(stderr, Usage);
++    fprintf(stderr, "%s", Usage);
+     exit(1);
+ }
+ 
diff --git a/package/network/utils/maccalc/Makefile b/package/network/utils/maccalc/Makefile
new file mode 100644
index 0000000000..dc11b6b7c1
--- /dev/null
+++ b/package/network/utils/maccalc/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=maccalc
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-2.0
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/maccalc
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=MAC address calculation
+endef
+
+define Package/maccalc/description
+ This package contains a MAC address manipulation utility.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall" \
+		LDFLAGS="$(TARGET_LDFLAGS)"
+endef
+
+define Package/maccalc/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/maccalc $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,maccalc))
diff --git a/package/network/utils/maccalc/src/Makefile b/package/network/utils/maccalc/src/Makefile
new file mode 100644
index 0000000000..486badb256
--- /dev/null
+++ b/package/network/utils/maccalc/src/Makefile
@@ -0,0 +1,14 @@
+CC = gcc
+CFLAGS = -Wall
+OBJS = main.o
+
+all: maccalc
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+maccalc: $(OBJS)
+	$(CC) -o $@ $(OBJS)
+
+clean:
+	rm -f maccalc *.o
diff --git a/package/network/utils/maccalc/src/main.c b/package/network/utils/maccalc/src/main.c
new file mode 100644
index 0000000000..dcb5f55c55
--- /dev/null
+++ b/package/network/utils/maccalc/src/main.c
@@ -0,0 +1,256 @@
+/*
+ * MAC address manupulation utility
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAC_ADDRESS_LEN		6
+
+#define ERR_INVALID		1
+#define ERR_IO			2
+
+static void usage(void);
+
+char *maccalc_name;
+
+static int parse_mac(const char *mac_str, unsigned char *buf)
+{
+	int t;
+
+	t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+		   &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
+
+	if (t != MAC_ADDRESS_LEN)
+		return ERR_INVALID;
+
+	return 0;
+}
+
+static void print_mac(unsigned char *buf)
+{
+	printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+	       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+}
+
+static int maccalc_do_add(int argc, const char *argv[])
+{
+	unsigned char mac[MAC_ADDRESS_LEN];
+	uint32_t t;
+	int err;
+	int i;
+
+	if (argc != 2) {
+		usage();
+		return ERR_INVALID;
+	}
+
+	err = parse_mac(argv[0], mac);
+	if (err)
+		return err;
+
+	i = atoi(argv[1]);
+
+	t = (mac[3] << 16) | (mac[4] << 8) | mac[5];
+	t += i;
+	mac[3] = (t >> 16) & 0xff;
+	mac[4] = (t >> 8) & 0xff;
+	mac[5] = t & 0xff;
+
+	print_mac(mac);
+	return 0;
+}
+
+static int maccalc_do_logical(int argc, const char *argv[],
+			      unsigned char (*op)(unsigned char n1,
+						  unsigned char n2))
+{
+	unsigned char mac1[MAC_ADDRESS_LEN];
+	unsigned char mac2[MAC_ADDRESS_LEN];
+	int err;
+	int i;
+
+	if (argc != 2) {
+		usage();
+		return ERR_INVALID;
+	}
+
+	err = parse_mac(argv[0], mac1);
+	if (err)
+		return err;
+
+	err = parse_mac(argv[1], mac2);
+	if (err)
+		return err;
+
+	for (i = 0; i < MAC_ADDRESS_LEN; i++)
+		mac1[i] = op(mac1[i],mac2[i]);
+
+	print_mac(mac1);
+	return 0;
+}
+
+static int maccalc_do_mac2bin(int argc, const char *argv[])
+{
+	unsigned char mac[MAC_ADDRESS_LEN];
+	ssize_t c;
+	int err;
+
+	if (argc != 1) {
+		usage();
+		return ERR_INVALID;
+	}
+
+	err = parse_mac(argv[0], mac);
+	if (err)
+		return err;
+
+	c = write(STDOUT_FILENO, mac, sizeof(mac));
+	if (c != sizeof(mac)) {
+		fprintf(stderr, "failed to write to stdout\n");
+		return ERR_IO;
+	}
+
+	return 0;
+}
+
+static ssize_t read_safe(int fd, void *buf, size_t count)
+{
+	ssize_t total = 0;
+	ssize_t r;
+
+	while(count > 0) {
+		r = read(fd, buf, count);
+		if (r == 0)
+			/* EOF */
+			break;
+		if (r < 0) {
+			if (errno == EINTR)
+				/* interrupted by a signal, restart */
+				continue;
+			/* error */
+			total = -1;
+			break;
+		}
+
+		/* ok */
+		total += r;
+		count -= r;
+		buf += r;
+	}
+
+	return total;
+}
+
+static int maccalc_do_bin2mac(int argc, const char *argv[])
+{
+	unsigned char mac[MAC_ADDRESS_LEN];
+	ssize_t c;
+
+	if (argc != 0) {
+		usage();
+		return ERR_INVALID;
+	}
+
+	c = read_safe(STDIN_FILENO, mac, sizeof(mac));
+	if (c != sizeof(mac)) {
+		fprintf(stderr, "failed to read from stdin\n");
+		return ERR_IO;
+	}
+
+	print_mac(mac);
+	return 0;
+}
+
+static unsigned char op_or(unsigned char n1, unsigned char n2)
+{
+	return n1 | n2;
+}
+
+static int maccalc_do_or(int argc, const char *argv[])
+{
+	return maccalc_do_logical(argc, argv, op_or);
+}
+
+static unsigned char op_and(unsigned char n1, unsigned char n2)
+{
+	return n1 & n2;
+}
+
+static int maccalc_do_and(int argc, const char *argv[])
+{
+	return maccalc_do_logical(argc, argv, op_and);
+}
+
+static unsigned char op_xor(unsigned char n1, unsigned char n2)
+{
+	return n1 ^ n2;
+}
+
+static int maccalc_do_xor(int argc, const char *argv[])
+{
+	return maccalc_do_logical(argc, argv, op_xor);
+}
+
+static void usage(void)
+{
+	fprintf(stderr,
+		"Usage: %s <command>\n"
+		"valid commands:\n"
+		"  add <mac> <number>\n"
+		"  and|or|xor <mac1> <mac2>\n"
+		"  mac2bin <mac>\n"
+		"  bin2mac\n",
+		maccalc_name);
+}
+
+int main(int argc, const char *argv[])
+{
+	int (*op)(int argc, const char *argv[]);
+	int ret;
+
+	maccalc_name = (char *) argv[0];
+
+	if (argc < 2) {
+		usage();
+		return EXIT_FAILURE;
+	}
+
+	if (strcmp(argv[1], "add") == 0) {
+		op = maccalc_do_add;
+	} else if (strcmp(argv[1], "and") == 0) {
+		op = maccalc_do_and;
+	} else if (strcmp(argv[1], "or") == 0) {
+		op = maccalc_do_or;
+	} else if (strcmp(argv[1], "xor") == 0) {
+		op = maccalc_do_xor;
+	} else if (strcmp(argv[1], "mac2bin") == 0) {
+		op = maccalc_do_mac2bin;
+	} else if (strcmp(argv[1], "bin2mac") == 0) {
+		op = maccalc_do_bin2mac;
+	} else {
+		fprintf(stderr, "unknown command '%s'\n", argv[1]);
+		usage();
+		return EXIT_FAILURE;
+	}
+
+	argc -= 2;
+	argv += 2;
+
+	ret = op(argc, argv);
+	if (ret)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/package/network/utils/nftables/Makefile b/package/network/utils/nftables/Makefile
new file mode 100644
index 0000000000..ca212ad7fb
--- /dev/null
+++ b/package/network/utils/nftables/Makefile
@@ -0,0 +1,44 @@
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=nftables
+PKG_VERSION:=0.4+2015-04-09
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL:=git://git.netfilter.org/nftables
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=3ed296118a065caff5600e60d4f7ef18e137f9a0
+PKG_MIRROR_MD5SUM:=561d0e057e916289eaa1f1a688deb78d7de095b002c8bb0f478ce6e53ae220a4
+PKG_MAINTAINER:=Steven Barth <steven@midlink.org>
+PKG_LICENSE:=GPL-2.0
+
+PKG_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/package.mk
+
+CONFIGURE_ARGS += \
+        --with-mini-gmp \
+        --without-cli \
+
+define Package/nftables
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Firewall
+  TITLE:=nftables packet filtering userspace utility
+  DEPENDS:=+kmod-nft-core +kmod-nft-nat +libnftnl
+  URL:=http://netfilter.org/projects/nftables/
+endef
+
+define Package/nftables/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) $(PKG_BUILD_DIR)/src/nft $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,nftables))
diff --git a/package/network/utils/nftables/patches/100-disable-doc-generation.patch b/package/network/utils/nftables/patches/100-disable-doc-generation.patch
new file mode 100644
index 0000000000..bcbffe25c7
--- /dev/null
+++ b/package/network/utils/nftables/patches/100-disable-doc-generation.patch
@@ -0,0 +1,8 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -2,5 +2,4 @@ ACLOCAL_AMFLAGS	= -I m4
+ 
+ SUBDIRS = 	src	\
+ 		include	\
+-		doc	\
+ 		files
diff --git a/package/network/utils/owipcalc/Makefile b/package/network/utils/owipcalc/Makefile
new file mode 100644
index 0000000000..fd193ea11f
--- /dev/null
+++ b/package/network/utils/owipcalc/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
+#
+# This is free software, licensed under the Apache 2 license.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=owipcalc
+PKG_RELEASE:=3
+PKG_LICENSE:=Apache-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define Package/owipcalc
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Simple IPv4/IPv6 address calculator
+  MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+endef
+
+define Package/owipcalc/description
+  The owipcalc utility supports a number of calculations and tests to work
+  with ip-address ranges, this is useful for scripts that e.g. need to
+  partition ipv6-prefixes into small subnets or to calculate address ranges
+  for dhcp pools.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) \
+		-o $(PKG_BUILD_DIR)/owipcalc $(PKG_BUILD_DIR)/owipcalc.c
+endef
+
+
+define Package/owipcalc/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/owipcalc $(1)/usr/bin/owipcalc
+endef
+
+$(eval $(call BuildPackage,owipcalc))
diff --git a/package/network/utils/owipcalc/src/owipcalc.c b/package/network/utils/owipcalc/src/owipcalc.c
new file mode 100644
index 0000000000..f95280cd1c
--- /dev/null
+++ b/package/network/utils/owipcalc/src/owipcalc.c
@@ -0,0 +1,951 @@
+/*
+ * owipcalc - OpenWrt IP Calculator
+ *
+ *   Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+
+struct cidr {
+	uint8_t family;
+	uint32_t prefix;
+	union {
+		struct in_addr v4;
+		struct in6_addr v6;
+	} addr;
+	union {
+		char v4[sizeof("255.255.255.255/255.255.255.255 ")];
+		char v6[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128 ")];
+	} buf;
+	struct cidr *next;
+};
+
+struct op {
+	const char *name;
+	const char *desc;
+	struct {
+		bool (*a1)(struct cidr *a);
+		bool (*a2)(struct cidr *a, struct cidr *b);
+	} f4;
+	struct {
+		bool (*a1)(struct cidr *a);
+		bool (*a2)(struct cidr *a, struct cidr *b);
+	} f6;
+};
+
+
+static bool quiet = false;
+static bool printed = false;
+
+static struct cidr *stack = NULL;
+
+#define qprintf(...) \
+	do { \
+		if (!quiet) printf(__VA_ARGS__); \
+		printed = true; \
+	} while(0)
+
+static void cidr_push(struct cidr *a)
+{
+	if (a)
+	{
+		a->next = stack;
+		stack = a;
+	}
+}
+
+static bool cidr_pop(struct cidr *a)
+{
+	struct cidr *old = stack;
+
+	if (old)
+	{
+		stack = stack->next;
+		free(old);
+
+		return true;
+	}
+
+	return false;
+}
+
+static struct cidr * cidr_clone(struct cidr *a)
+{
+	struct cidr *b = malloc(sizeof(*b));
+
+	if (!b)
+	{
+		fprintf(stderr, "out of memory\n");
+		exit(255);
+	}
+
+	memcpy(b, a, sizeof(*b));
+	cidr_push(b);
+
+	return b;
+}
+
+
+static struct cidr * cidr_parse4(const char *s)
+{
+	char *p = NULL, *r;
+	struct in_addr mask;
+	struct cidr *addr = malloc(sizeof(struct cidr));
+
+	if (!addr || (strlen(s) >= sizeof(addr->buf.v4)))
+		goto err;
+
+	snprintf(addr->buf.v4, sizeof(addr->buf.v4), "%s", s);
+
+	addr->family = AF_INET;
+
+	if ((p = strchr(addr->buf.v4, '/')) != NULL)
+	{
+		*p++ = 0;
+
+		if (strchr(p, '.') != NULL)
+		{
+			if (inet_pton(AF_INET, p, &mask) != 1)
+				goto err;
+
+			for (addr->prefix = 0; mask.s_addr; mask.s_addr >>= 1)
+				addr->prefix += (mask.s_addr & 1);
+		}
+		else
+		{
+			addr->prefix = strtoul(p, &r, 10);
+
+			if ((p == r) || (*r != 0) || (addr->prefix > 32))
+				goto err;
+		}
+	}
+	else
+	{
+		addr->prefix = 32;
+	}
+
+	if (p == addr->buf.v4+1)
+		memset(&addr->addr.v4, 0, sizeof(addr->addr.v4));
+	else if (inet_pton(AF_INET, addr->buf.v4, &addr->addr.v4) != 1)
+		goto err;
+
+	return addr;
+
+err:
+	if (addr)
+		free(addr);
+
+	return NULL;
+}
+
+static bool cidr_add4(struct cidr *a, struct cidr *b)
+{
+	uint32_t x = ntohl(a->addr.v4.s_addr);
+	uint32_t y = ntohl(b->addr.v4.s_addr);
+
+	struct cidr *n = cidr_clone(a);
+
+	if ((n->family != AF_INET) || (b->family != AF_INET))
+		return false;
+
+	if ((uint32_t)(x + y) < x)
+	{
+		fprintf(stderr, "overflow during 'add'\n");
+		return false;
+	}
+
+	n->addr.v4.s_addr = htonl(x + y);
+	return true;
+}
+
+static bool cidr_sub4(struct cidr *a, struct cidr *b)
+{
+	uint32_t x = ntohl(a->addr.v4.s_addr);
+	uint32_t y = ntohl(b->addr.v4.s_addr);
+
+	struct cidr *n = cidr_clone(a);
+
+	if ((n->family != AF_INET) || (b->family != AF_INET))
+		return false;
+
+	if ((uint32_t)(x - y) > x)
+	{
+		fprintf(stderr, "underflow during 'sub'\n");
+		return false;
+	}
+
+	n->addr.v4.s_addr = htonl(x - y);
+	return true;
+}
+
+static bool cidr_network4(struct cidr *a)
+{
+	struct cidr *n = cidr_clone(a);
+
+	n->addr.v4.s_addr &= htonl(~((1 << (32 - n->prefix)) - 1));
+	n->prefix = 32;
+
+	return true;
+}
+
+static bool cidr_broadcast4(struct cidr *a)
+{
+	struct cidr *n = cidr_clone(a);
+
+	n->addr.v4.s_addr |= htonl(((1 << (32 - n->prefix)) - 1));
+	n->prefix = 32;
+
+	return true;
+}
+
+static bool cidr_contains4(struct cidr *a, struct cidr *b)
+{
+	uint32_t net1 = a->addr.v4.s_addr & htonl(~((1 << (32 - a->prefix)) - 1));
+	uint32_t net2 = b->addr.v4.s_addr & htonl(~((1 << (32 - a->prefix)) - 1));
+
+	if (printed)
+		qprintf(" ");
+
+	if ((b->prefix >= a->prefix) && (net1 == net2))
+	{
+		qprintf("1");
+		return true;
+	}
+	else
+	{
+		qprintf("0");
+		return false;
+	}
+}
+
+static bool cidr_netmask4(struct cidr *a)
+{
+	struct cidr *n = cidr_clone(a);
+
+	n->addr.v4.s_addr = htonl(~((1 << (32 - n->prefix)) - 1));
+	n->prefix = 32;
+
+	return true;
+}
+
+static bool cidr_private4(struct cidr *a)
+{
+	uint32_t x = ntohl(a->addr.v4.s_addr);
+
+	if (printed)
+		qprintf(" ");
+
+	if (((x >= 0x0A000000) && (x <= 0x0AFFFFFF)) ||
+	    ((x >= 0xAC100000) && (x <= 0xAC1FFFFF)) ||
+	    ((x >= 0xC0A80000) && (x <= 0xC0A8FFFF)))
+	{
+		qprintf("1");
+		return true;
+	}
+	else
+	{
+		qprintf("0");
+		return false;
+	}
+}
+
+static bool cidr_linklocal4(struct cidr *a)
+{
+	uint32_t x = ntohl(a->addr.v4.s_addr);
+
+	if (printed)
+		qprintf(" ");
+
+	if ((x >= 0xA9FE0000) && (x <= 0xA9FEFFFF))
+	{
+		qprintf("1");
+		return true;
+	}
+	else
+	{
+		qprintf("0");
+		return false;
+	}
+}
+
+static bool cidr_prev4(struct cidr *a, struct cidr *b)
+{
+	struct cidr *n = cidr_clone(a);
+
+	n->prefix = b->prefix;
+	n->addr.v4.s_addr -= htonl(1 << (32 - b->prefix));
+
+	return true;
+}
+
+static bool cidr_next4(struct cidr *a, struct cidr *b)
+{
+	struct cidr *n = cidr_clone(a);
+
+	n->prefix = b->prefix;
+	n->addr.v4.s_addr += htonl(1 << (32 - b->prefix));
+
+	return true;
+}
+
+static bool cidr_6to4(struct cidr *a)
+{
+	struct cidr *n = cidr_clone(a);
+	uint32_t x = a->addr.v4.s_addr;
+
+	memset(&n->addr.v6.s6_addr, 0, sizeof(n->addr.v6.s6_addr));
+
+	n->family = AF_INET6;
+	n->prefix = 48;
+
+	n->addr.v6.s6_addr[0] = 0x20;
+	n->addr.v6.s6_addr[1] = 0x02;
+	n->addr.v6.s6_addr[2] = (x >> 24);
+	n->addr.v6.s6_addr[3] = (x >> 16) & 0xFF;
+	n->addr.v6.s6_addr[4] = (x >>  8) & 0xFF;
+	n->addr.v6.s6_addr[5] = x & 0xFF;
+
+	return true;
+}
+
+static bool cidr_print4(struct cidr *a)
+{
+	char *p;
+
+	if (!a || (a->family != AF_INET))
+		return false;
+
+	if (!(p = (char *)inet_ntop(AF_INET, &a->addr.v4, a->buf.v4, sizeof(a->buf.v4))))
+		return false;
+
+	if (printed)
+		qprintf(" ");
+
+	qprintf("%s", p);
+
+	if (a->prefix < 32)
+		qprintf("/%u", a->prefix);
+
+	cidr_pop(a);
+
+	return true;
+}
+
+
+static struct cidr * cidr_parse6(const char *s)
+{
+	char *p = NULL, *r;
+	struct cidr *addr = malloc(sizeof(struct cidr));
+
+	if (!addr || (strlen(s) >= sizeof(addr->buf.v6)))
+		goto err;
+
+	snprintf(addr->buf.v4, sizeof(addr->buf.v6), "%s", s);
+
+	addr->family = AF_INET6;
+
+	if ((p = strchr(addr->buf.v4, '/')) != NULL)
+	{
+		*p++ = 0;
+
+		addr->prefix = strtoul(p, &r, 10);
+
+		if ((p == r) || (*r != 0) || (addr->prefix > 128))
+			goto err;
+	}
+	else
+	{
+		addr->prefix = 128;
+	}
+
+	if (p == addr->buf.v4+1)
+		memset(&addr->addr.v6, 0, sizeof(addr->addr.v6));
+	else if (inet_pton(AF_INET6, addr->buf.v4, &addr->addr.v6) != 1)
+		goto err;
+
+	return addr;
+
+err:
+	if (addr)
+		free(addr);
+
+	return NULL;
+}
+
+static bool cidr_add6(struct cidr *a, struct cidr *b)
+{
+	uint8_t idx = 15, carry = 0, overflow = 0;
+
+	struct cidr *n = cidr_clone(a);
+	struct in6_addr *x = &n->addr.v6;
+	struct in6_addr *y = &b->addr.v6;
+
+	if ((a->family != AF_INET6) || (b->family != AF_INET6))
+		return false;
+
+	do {
+		overflow = !!((x->s6_addr[idx] + y->s6_addr[idx] + carry) >= 256);
+		x->s6_addr[idx] += y->s6_addr[idx] + carry;
+		carry = overflow;
+	}
+	while (idx-- > 0);
+
+	if (carry)
+	{
+		fprintf(stderr, "overflow during 'add'\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool cidr_sub6(struct cidr *a, struct cidr *b)
+{
+	uint8_t idx = 15, carry = 0, underflow = 0;
+
+	struct cidr *n = cidr_clone(a);
+	struct in6_addr *x = &n->addr.v6;
+	struct in6_addr *y = &b->addr.v6;
+
+	if ((n->family != AF_INET6) || (b->family != AF_INET6))
+		return false;
+
+	do {
+		underflow = !!((x->s6_addr[idx] - y->s6_addr[idx] - carry) < 0);
+		x->s6_addr[idx] -= y->s6_addr[idx] + carry;
+		carry = underflow;
+	}
+	while (idx-- > 0);
+
+	if (carry)
+	{
+		fprintf(stderr, "underflow during 'sub'\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool cidr_prev6(struct cidr *a, struct cidr *b)
+{
+	uint8_t idx, carry = 1, underflow = 0;
+	struct cidr *n = cidr_clone(a);
+	struct in6_addr *x = &n->addr.v6;
+
+	if (b->prefix == 0)
+	{
+		fprintf(stderr, "underflow during 'prev'\n");
+		return false;
+	}
+
+	idx = (b->prefix - 1) / 8;
+
+	do {
+		underflow = !!((x->s6_addr[idx] - carry) < 0);
+		x->s6_addr[idx] -= carry;
+		carry = underflow;
+	}
+	while (idx-- > 0);
+
+	if (carry)
+	{
+		fprintf(stderr, "underflow during 'prev'\n");
+		return false;
+	}
+
+	n->prefix = b->prefix;
+
+	return true;
+}
+
+static bool cidr_next6(struct cidr *a, struct cidr *b)
+{
+	uint8_t idx, carry = 1, overflow = 0;
+	struct cidr *n = cidr_clone(a);
+	struct in6_addr *x = &n->addr.v6;
+
+	if (b->prefix == 0)
+	{
+		fprintf(stderr, "overflow during 'next'\n");
+		return false;
+	}
+
+	idx = (b->prefix - 1) / 8;
+
+	do {
+		overflow = !!((x->s6_addr[idx] + carry) >= 256);
+		x->s6_addr[idx] += carry;
+		carry = overflow;
+	}
+	while (idx-- > 0);
+
+	if (carry)
+	{
+		fprintf(stderr, "overflow during 'next'\n");
+		return false;
+	}
+
+	n->prefix = b->prefix;
+
+	return true;
+}
+
+static bool cidr_network6(struct cidr *a)
+{
+	uint8_t i;
+	struct cidr *n = cidr_clone(a);
+
+	for (i = 0; i < (128 - n->prefix) / 8; i++)
+		n->addr.v6.s6_addr[15-i] = 0;
+
+	if ((128 - n->prefix) % 8)
+		n->addr.v6.s6_addr[15-i] &= ~((1 << ((128 - n->prefix) % 8)) - 1);
+
+	return true;
+}
+
+static bool cidr_contains6(struct cidr *a, struct cidr *b)
+{
+	struct cidr *n = cidr_clone(a);
+	struct in6_addr *x = &n->addr.v6;
+	struct in6_addr *y = &b->addr.v6;
+	uint8_t i = (128 - n->prefix) / 8;
+	uint8_t m = ~((1 << ((128 - n->prefix) % 8)) - 1);
+	uint8_t net1 = x->s6_addr[15-i] & m;
+	uint8_t net2 = y->s6_addr[15-i] & m;
+
+	if (printed)
+		qprintf(" ");
+
+	if ((b->prefix >= n->prefix) && (net1 == net2) &&
+	    ((i == 15) || !memcmp(&x->s6_addr, &y->s6_addr, 15-i)))
+	{
+		qprintf("1");
+		return true;
+	}
+	else
+	{
+		qprintf("0");
+		return false;
+	}
+}
+
+static bool cidr_linklocal6(struct cidr *a)
+{
+	if (printed)
+		qprintf(" ");
+
+	if ((a->addr.v6.s6_addr[0] == 0xFE) &&
+	    (a->addr.v6.s6_addr[1] >= 0x80) &&
+	    (a->addr.v6.s6_addr[1] <= 0xBF))
+	{
+		qprintf("1");
+		return true;
+	}
+	else
+	{
+		qprintf("0");
+		return false;
+	}
+}
+
+static bool cidr_ula6(struct cidr *a)
+{
+	if (printed)
+		qprintf(" ");
+
+	if ((a->addr.v6.s6_addr[0] >= 0xFC) &&
+	    (a->addr.v6.s6_addr[0] <= 0xFD))
+	{
+		qprintf("1");
+		return true;
+	}
+	else
+	{
+		qprintf("0");
+		return false;
+	}
+}
+
+static bool cidr_print6(struct cidr *a)
+{
+	char *p;
+
+	if (!a || (a->family != AF_INET6))
+		return NULL;
+
+	if (!(p = (char *)inet_ntop(AF_INET6, &a->addr.v6, a->buf.v6, sizeof(a->buf.v6))))
+		return false;
+
+	if (printed)
+		qprintf(" ");
+
+	qprintf("%s", p);
+
+	if (a->prefix < 128)
+		qprintf("/%u", a->prefix);
+
+	cidr_pop(a);
+
+	return true;
+}
+
+
+static struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
+{
+	char *r;
+	struct cidr *a;
+
+	uint8_t i;
+	uint32_t sum = strtoul(s, &r, 0);
+
+	if ((r > s) && (*r == 0))
+	{
+		a = malloc(sizeof(struct cidr));
+
+		if (!a)
+			return NULL;
+
+		if (af_hint == AF_INET)
+		{
+			a->family = AF_INET;
+			a->prefix = sum;
+			a->addr.v4.s_addr = htonl(sum);
+		}
+		else
+		{
+			a->family = AF_INET6;
+			a->prefix = sum;
+
+			for (i = 0; i <= 15; i++)
+			{
+				a->addr.v6.s6_addr[15-i] = sum % 256;
+				sum >>= 8;
+			}
+		}
+
+		return a;
+	}
+
+	if (strchr(s, ':'))
+		a = cidr_parse6(s);
+	else
+		a = cidr_parse4(s);
+
+	if (!a)
+		return NULL;
+
+	if (a->family != af_hint)
+	{
+		fprintf(stderr, "attempt to '%s' %s with %s address\n",
+				op,
+				(af_hint == AF_INET) ? "ipv4" : "ipv6",
+				(af_hint != AF_INET) ? "ipv4" : "ipv6");
+		exit(4);
+	}
+
+	return a;
+}
+
+static bool cidr_howmany(struct cidr *a, struct cidr *b)
+{
+	if (printed)
+		qprintf(" ");
+
+	if (b->prefix < a->prefix)
+		qprintf("0");
+	else
+		qprintf("%u", 1 << (b->prefix - a->prefix));
+
+	return true;
+}
+
+static bool cidr_prefix(struct cidr *a, struct cidr *b)
+{
+	a->prefix = b->prefix;
+	return true;
+}
+
+static bool cidr_quiet(struct cidr *a)
+{
+	quiet = true;
+	return true;
+}
+
+
+struct op ops[] = {
+	{ .name = "add",
+	  .desc = "Add argument to base address",
+	  .f4.a2 = cidr_add4,
+	  .f6.a2 = cidr_add6 },
+
+	{ .name = "sub",
+	  .desc = "Substract argument from base address",
+	  .f4.a2 = cidr_sub4,
+	  .f6.a2 = cidr_sub6 },
+
+	{ .name = "next",
+	  .desc = "Advance base address to next prefix of given size",
+	  .f4.a2 = cidr_next4,
+	  .f6.a2 = cidr_next6 },
+
+	{ .name = "prev",
+	  .desc = "Lower base address to previous prefix of give size",
+	  .f4.a2 = cidr_prev4,
+	  .f6.a2 = cidr_prev6 },
+
+	{ .name = "network",
+	  .desc = "Turn base address into network address",
+	  .f4.a1 = cidr_network4,
+	  .f6.a1 = cidr_network6 },
+
+	{ .name = "broadcast",
+	  .desc = "Turn base address into broadcast address",
+	  .f4.a1 = cidr_broadcast4 },
+
+	{ .name = "prefix",
+	  .desc = "Set the prefix of base address to argument",
+	  .f4.a2 = cidr_prefix,
+	  .f6.a2 = cidr_prefix },
+
+	{ .name = "netmask",
+	  .desc = "Calculate netmask of base address",
+	  .f4.a1 = cidr_netmask4 },
+
+	{ .name = "6to4",
+	  .desc = "Calculate 6to4 prefix of given ipv4-address",
+	  .f4.a1 = cidr_6to4 },
+
+	{ .name = "howmany",
+	  .desc = "Print amount of righ-hand prefixes that fit into base address",
+	  .f4.a2 = cidr_howmany,
+	  .f6.a2 = cidr_howmany },
+
+	{ .name = "contains",
+	  .desc = "Print '1' if argument fits into base address or '0' if not",
+	  .f4.a2 = cidr_contains4,
+	  .f6.a2 = cidr_contains6 },
+
+	{ .name = "private",
+	  .desc = "Print '1' if base address is in RFC1918 private space or '0' "
+	          "if not",
+	  .f4.a1 = cidr_private4 },
+
+	{ .name = "linklocal",
+	  .desc = "Print '1' if base address is in 169.254.0.0/16 or FE80::/10 "
+	          "link local space or '0' if not",
+	  .f4.a1 = cidr_linklocal4,
+	  .f6.a1 = cidr_linklocal6 },
+
+	{ .name = "ula",
+	  .desc = "Print '1' if base address is in FC00::/7 unique local address "
+	          "(ULA) space or '0' if not",
+	  .f6.a1 = cidr_ula6 },
+
+	{ .name = "quiet",
+	  .desc = "Suppress output, useful for test operation where the result can "
+	          "be inferred from the exit code",
+	  .f4.a1 = cidr_quiet,
+	  .f6.a1 = cidr_quiet },
+
+	{ .name = "pop",
+	  .desc = "Pop intermediate result from stack",
+	  .f4.a1 = cidr_pop,
+	  .f6.a1 = cidr_pop },
+
+	{ .name = "print",
+	  .desc = "Print intermediate result and pop it from stack, invoked "
+	          "implicitely at the end of calculation if no intermediate prints "
+	          "happened",
+	  .f4.a1 = cidr_print4,
+	  .f6.a1 = cidr_print6 },
+};
+
+static void usage(const char *prog)
+{
+	int i;
+
+	fprintf(stderr,
+	        "\n"
+	        "Usage:\n\n"
+	        "  %s {base address} operation [argument] "
+	        "[operation [argument] ...]\n\n"
+	        "Operations:\n\n",
+	        prog);
+
+	for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
+	{
+		if (ops[i].f4.a2 || ops[i].f6.a2)
+		{
+			fprintf(stderr, "  %s %s\n",
+			        ops[i].name,
+			        (ops[i].f4.a2 && ops[i].f6.a2) ? "{ipv4/ipv6/amount}" :
+			         (ops[i].f6.a2 ? "{ipv6/amount}" : "{ipv4/amount}"));
+		}
+		else
+		{
+			fprintf(stderr, "  %s\n", ops[i].name);
+		}
+
+		fprintf(stderr, "    %s.\n", ops[i].desc);
+
+		if ((ops[i].f4.a1 && ops[i].f6.a1) || (ops[i].f4.a2 && ops[i].f6.a2))
+			fprintf(stderr, "    Applicable to ipv4- and ipv6-addresses.\n\n");
+		else if (ops[i].f6.a2 || ops[i].f6.a1)
+			fprintf(stderr, "    Only applicable to ipv6-addresses.\n\n");
+		else
+			fprintf(stderr, "    Only applicable to ipv4-addresses.\n\n");
+	}
+
+	fprintf(stderr,
+	        "Examples:\n\n"
+	        " Calculate a DHCP range:\n\n"
+	        "  $ %s 192.168.1.1/255.255.255.0 network add 100 print add 150 print\n"
+			"  192.168.1.100\n"
+			"  192.168.1.250\n\n"
+			" Count number of prefixes:\n\n"
+			"  $ %s 2001:0DB8:FDEF::/48 howmany ::/64\n"
+			"  65536\n\n",
+	        prog, prog);
+
+	exit(1);
+}
+
+static bool runop(char ***arg, int *status)
+{
+	int i;
+	char *arg1 = **arg;
+	char *arg2 = *(*arg+1);
+	struct cidr *a = stack;
+	struct cidr *b = NULL;
+
+	if (!arg1)
+		return false;
+
+	for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
+	{
+		if (!strcmp(ops[i].name, arg1))
+		{
+			if (ops[i].f4.a2 || ops[i].f6.a2)
+			{
+				if (!arg2)
+				{
+					fprintf(stderr, "'%s' requires an argument\n",
+							ops[i].name);
+
+					*status = 2;
+					return false;
+				}
+
+				b = cidr_parse(ops[i].name, arg2, a->family);
+
+				if (!b)
+				{
+					fprintf(stderr, "invalid address argument for '%s'\n",
+							ops[i].name);
+
+					*status = 3;
+					return false;
+				}
+
+				*arg += 2;
+
+				if (((a->family == AF_INET)  && !ops[i].f4.a2) ||
+					((a->family == AF_INET6) && !ops[i].f6.a2))
+				{
+					fprintf(stderr, "'%s' not supported for %s addresses\n",
+					        ops[i].name,
+							(a->family == AF_INET) ? "ipv4" : "ipv6");
+
+					*status = 5;
+					return false;
+				}
+
+				*status = !((a->family == AF_INET) ? ops[i].f4.a2(a, b)
+				                                   : ops[i].f6.a2(a, b));
+
+				return true;
+			}
+			else
+			{
+				*arg += 1;
+
+				if (((a->family == AF_INET)  && !ops[i].f4.a1) ||
+					((a->family == AF_INET6) && !ops[i].f6.a1))
+				{
+					fprintf(stderr, "'%s' not supported for %s addresses\n",
+					        ops[i].name,
+							(a->family == AF_INET) ? "ipv4" : "ipv6");
+
+					*status = 5;
+					return false;
+				}
+
+				*status = !((a->family == AF_INET) ? ops[i].f4.a1(a)
+				                                   : ops[i].f6.a1(a));
+
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+int main(int argc, char **argv)
+{
+	int status = 0;
+	char **arg = argv+2;
+	struct cidr *a;
+
+	if (argc < 3)
+		usage(argv[0]);
+
+	a = strchr(argv[1], ':') ? cidr_parse6(argv[1]) : cidr_parse4(argv[1]);
+
+	if (!a)
+		usage(argv[0]);
+
+	cidr_push(a);
+
+	while (runop(&arg, &status));
+
+	if (*arg)
+	{
+		fprintf(stderr, "unknown operation '%s'\n", *arg);
+		exit(6);
+	}
+
+	if (!printed && (status < 2))
+	{
+		if (stack->family == AF_INET)
+			cidr_print4(stack);
+		else
+			cidr_print6(stack);
+	}
+
+	qprintf("\n");
+
+	exit(status);
+}
diff --git a/package/network/utils/resolveip/Makefile b/package/network/utils/resolveip/Makefile
new file mode 100644
index 0000000000..ab5d4eada2
--- /dev/null
+++ b/package/network/utils/resolveip/Makefile
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=resolveip
+PKG_RELEASE:=2
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/resolveip
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=Simple DNS resolver with configurable timeout
+  MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+endef
+
+define Package/resolveip/description
+ This package contains the small resolveip utility which
+ can be used by scripts to turn host names into numeric
+ IP addresses. It supports IPv4 and IPv6 resolving and
+ has a configurable timeout to guarantee a certain maximum
+ runtime in case of slow or defunct DNS servers.
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -Wall \
+		-o $(PKG_BUILD_DIR)/resolveip $(PKG_BUILD_DIR)/resolveip.c
+endef
+
+define Package/resolveip/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/resolveip $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,resolveip))
diff --git a/package/network/utils/resolveip/src/resolveip.c b/package/network/utils/resolveip/src/resolveip.c
new file mode 100644
index 0000000000..f7a918d0a2
--- /dev/null
+++ b/package/network/utils/resolveip/src/resolveip.c
@@ -0,0 +1,98 @@
+/*
+ * Based on code found at https://dev.openwrt.org/ticket/4876 .
+ * Extended by Jo-Philipp Wich <jo@mein.io> for use in OpenWrt.
+ *
+ * You may use this program under the terms of the GPLv2 license.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+
+static void abort_query(int sig)
+{
+	exit(1);
+}
+
+static void show_usage(void)
+{
+	printf("Usage:\n");
+	printf("	resolveip -h\n");
+	printf("	resolveip [-t timeout] hostname\n");
+	printf("	resolveip -4 [-t timeout] hostname\n");
+	printf("	resolveip -6 [-t timeout] hostname\n");
+	exit(255);
+}
+
+int main(int argc, char **argv)
+{
+	int timeout = 3;
+	int opt;
+	char ipaddr[INET6_ADDRSTRLEN];
+	void *addr;
+	struct addrinfo *res, *rp;
+	struct sigaction sa = {	.sa_handler = &abort_query };
+	struct addrinfo hints = {
+		.ai_family   = AF_UNSPEC,
+		.ai_socktype = SOCK_STREAM,
+		.ai_protocol = IPPROTO_TCP,
+		.ai_flags    = 0
+	};
+
+	while ((opt = getopt(argc, argv, "46t:h")) > -1)
+	{
+		switch ((char)opt)
+		{
+			case '4':
+				hints.ai_family = AF_INET;
+				break;
+
+			case '6':
+				hints.ai_family = AF_INET6;
+				break;
+
+			case 't':
+				timeout = atoi(optarg);
+				if (timeout <= 0)
+					show_usage();
+				break;
+
+			case 'h':
+				show_usage();
+				break;
+		}
+	}
+
+	if (!argv[optind])
+		show_usage();
+
+	sigaction(SIGALRM, &sa, NULL);
+	alarm(timeout);
+
+	if (getaddrinfo(argv[optind], NULL, &hints, &res))
+		exit(2);
+
+	for (rp = res; rp != NULL; rp = rp->ai_next)
+	{
+		addr = (rp->ai_family == AF_INET)
+			? (void *)&((struct sockaddr_in *)rp->ai_addr)->sin_addr
+			: (void *)&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr
+		;
+
+		if (!inet_ntop(rp->ai_family, addr, ipaddr, INET6_ADDRSTRLEN - 1))
+			exit(3);
+
+		printf("%s\n", ipaddr);
+	}
+
+	freeaddrinfo(res);
+	exit(0);
+}
diff --git a/package/network/utils/rssileds/Makefile b/package/network/utils/rssileds/Makefile
new file mode 100644
index 0000000000..e475bcd5bb
--- /dev/null
+++ b/package/network/utils/rssileds/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2011-2012 Daniel Golle <dgolle@allnet.de>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=rssileds
+PKG_VERSION:=0.2
+PKG_RELEASE:=1
+PKG_LICNESE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/rssileds
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=RSSI real-time LED indicator
+  DEPENDS:=+libiwinfo
+  MAINTAINER:=Daniel Golle <dgolle@allnet.de>
+endef
+
+define Package/rssileds/description
+  A small process written in C to update the signal-strength indicator LEDs
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -Wall -liwinfo \
+		-o $(PKG_BUILD_DIR)/rssileds $(PKG_BUILD_DIR)/rssileds.c
+endef
+
+define Package/rssileds/install
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/rssileds.init $(1)/etc/init.d/rssileds
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/rssileds $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,rssileds))
diff --git a/package/network/utils/rssileds/files/rssileds.init b/package/network/utils/rssileds/files/rssileds.init
new file mode 100644
index 0000000000..b0d262725b
--- /dev/null
+++ b/package/network/utils/rssileds/files/rssileds.init
@@ -0,0 +1,75 @@
+#!/bin/sh /etc/rc.common
+# (C) 2012 Daniel Golle, Allnet GmbH <dgolle@allnet.de>
+
+START=96
+STOP=96
+RSSILEDS_BIN="/usr/sbin/rssileds"
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+
+start_rssid() {
+	local name
+	local dev
+	local threshold
+	local refresh
+	local leds
+	config_get name $1 name
+	config_get dev $1 dev
+	config_get threshold $1 threshold
+	config_get refresh $1 refresh
+	leds="$( cur_iface=$1 ; config_foreach get_led led )"
+	SERVICE_PID_FILE=/var/run/rssileds-$dev.pid
+	service_start $RSSILEDS_BIN $dev $refresh $threshold $leds
+}
+
+stop_rssid() {
+	local dev
+	config_get dev $1 dev
+	SERVICE_PID_FILE=/var/run/rssileds-$dev.pid
+	service_stop $RSSILEDS_BIN
+}
+
+get_led() {
+	local name
+	local sysfs
+	local trigger
+	local iface
+	config_get sysfs $1 sysfs
+	config_get name $1 name "$sysfs"
+	config_get trigger $1 trigger "none"
+	config_get iface $1 iface
+	config_get minq $1 minq
+	config_get maxq $1 maxq
+	config_get offset $1 offset
+	config_get factor $1 factor
+	[ "$trigger" = "rssi" ] || return
+	[ "$iface" = "$cur_iface" ] || return
+	[ ! "$minq" ] || [ ! "$maxq" ] || [ ! "$offset" ] || [ ! "$factor" ] && return
+	echo "none" > /sys/class/leds/$sysfs/trigger
+	echo "$sysfs $minq $maxq $offset $factor"
+}
+
+off_led() {
+	local name
+	local sysfs
+	local trigger
+	config_get sysfs $1 sysfs
+	config_get name $1 name "$sysfs"
+	config_get trigger $1 trigger "none"
+	[ "$trigger" = "rssi" ] || return
+	echo "0" > /sys/class/leds/$sysfs/brightness
+}
+
+start() {
+	[ -e /sys/class/leds/ ] && [ -x "$RSSILEDS_BIN" ] && {
+		config_load system
+		config_foreach start_rssid rssid
+	}
+}
+
+stop() {
+	config_load system
+	config_foreach stop_rssid rssid
+	config_foreach off_led led
+}
diff --git a/package/network/utils/rssileds/src/rssileds.c b/package/network/utils/rssileds/src/rssileds.c
new file mode 100644
index 0000000000..60d30f13b7
--- /dev/null
+++ b/package/network/utils/rssileds/src/rssileds.c
@@ -0,0 +1,290 @@
+/*
+ * configurable RSSI LED control daemon for OpenWrt
+ *  (c) 2012 Allnet GmbH, Daniel Golle <dgolle@allnet.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The author may be reached as dgolle@allnet.de, or
+ * ALLNET GmbH
+ * Maistr. 2
+ * D-82110 Germering
+ * Germany
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include "iwinfo.h"
+
+#define RUN_DIR			"/var/run"
+#define LEDS_BASEPATH		"/sys/class/leds/"
+#define BACKEND_RETRY_DELAY	500000
+
+char *ifname;
+int qual_max;
+
+struct led {
+	char *sysfspath;
+	FILE *controlfd;
+	unsigned char state;
+};
+
+typedef struct rule rule_t;
+struct rule {
+	struct led *led;
+	int minq;
+	int maxq;
+	int boffset;
+	int bfactor;
+	rule_t *next;
+};
+
+void log_rules(rule_t *rules)
+{
+	rule_t *rule = rules;
+	while (rule)
+	{
+		syslog(LOG_INFO, " %s r: %d..%d, o: %d, f: %d\n",
+			rule->led->sysfspath,
+			rule->minq, rule->maxq,
+			rule->boffset, rule->bfactor);
+		rule = rule->next;
+	}
+}
+
+int set_led(struct led *led, unsigned char value)
+{
+	char buf[8];
+
+	if ( ! led )
+		return -1;
+
+	if ( ! led->controlfd )
+		return -1;
+
+	if ( led->state == value )
+		return 0;
+
+	snprintf(buf, 8, "%d", value);
+
+	rewind(led->controlfd);
+
+	if ( ! fwrite(buf, sizeof(char), strlen(buf), led->controlfd) )
+		return -2;
+
+	fflush(led->controlfd);
+	led->state=value;
+
+	return 0;
+}
+
+int init_led(struct led **led, char *ledname)
+{
+	struct led *newled;
+	struct stat statbuffer;
+	int status;
+	char *bp;
+	FILE *bfp;
+
+	bp = calloc(sizeof(char), strlen(ledname) + strlen(LEDS_BASEPATH) + 12);
+	if ( ! bp )
+		goto return_error;
+
+	sprintf(bp, "%s%s/brightness", LEDS_BASEPATH, ledname);
+
+	status = stat(bp, &statbuffer);
+	if ( status )
+		goto cleanup_fname;
+
+	bfp = fopen( bp, "w" );
+	if ( !bfp )
+		goto cleanup_fname;
+
+	if ( ferror(bfp) )
+		goto cleanup_fp;
+
+	/* sysfs path exists and, allocate LED struct */
+	newled = calloc(sizeof(struct led),1);
+	if ( !newled )
+		goto cleanup_fp;
+
+	newled->sysfspath = bp;
+	newled->controlfd = bfp;
+
+	*led = newled;
+
+	if ( set_led(newled, 255) )
+		goto cleanup_fp;
+
+	if ( set_led(newled, 0) )
+		goto cleanup_fp;
+
+	return 0;
+
+cleanup_fp:
+	fclose(bfp);
+cleanup_fname:
+	free(bp);
+return_error:
+	syslog(LOG_CRIT, "can't open LED %s\n", ledname);
+	*led = NULL;
+	return -1;
+}
+
+void close_led(struct led **led)
+{
+	fclose((*led)->controlfd);
+	free((*led)->sysfspath);
+	free((*led));
+	(*led)=NULL;
+}
+
+
+int quality(const struct iwinfo_ops *iw, const char *ifname)
+{
+	int qual;
+
+	if ( ! iw ) return -1;
+
+	if (qual_max < 1)
+		if (iw->quality_max(ifname, &qual_max))
+			return -1;
+
+	if (iw->quality(ifname, &qual))
+		return -1;
+
+	return ( qual * 100 ) / qual_max ;
+}
+
+int open_backend(const struct iwinfo_ops **iw, const char *ifname)
+{
+	*iw = iwinfo_backend(ifname);
+
+	if (!(*iw))
+		return 1;
+
+	return 0;
+}
+
+void update_leds(rule_t *rules, int q)
+{
+	rule_t *rule = rules;
+	while (rule)
+	{
+		int b;
+		/* offset and factore correction according to rule */
+		b = ( q + rule->boffset ) * rule->bfactor;
+		if ( b < 0 )
+			b=0;
+		if ( b > 255 )
+			b=255;
+
+		if ( q >= rule->minq && q <= rule->maxq )
+			set_led(rule->led, (unsigned char)b);
+		else
+			set_led(rule->led, 0);
+
+		rule = rule->next;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int i,q,q0,r,s;
+	const struct iwinfo_ops *iw = NULL;
+	rule_t *headrule = NULL, *currentrule = NULL;
+
+	if (argc < 9 || ( (argc-4) % 5 != 0 ) )
+	{
+		printf("syntax: %s (ifname) (refresh) (threshold) (rule) [rule] ...\n", argv[0]);
+		printf("  rule: (sysfs-name) (minq) (maxq) (offset) (factore)\n");
+		return 1;
+	}
+
+	ifname = argv[1];
+
+	/* refresh interval */
+	if ( sscanf(argv[2], "%d", &r) != 1 )
+		return 1;
+
+	/* sustain threshold */
+	if ( sscanf(argv[3], "%d", &s) != 1 )
+		return 1;
+
+	openlog("rssileds", LOG_PID, LOG_DAEMON);
+	syslog(LOG_INFO, "monitoring %s, refresh rate %d, threshold %d\n", ifname, r, s);
+
+	currentrule = headrule;
+	for (i=4; i<argc; i=i+5) {
+		if (! currentrule)
+		{
+			/* first element in the list */
+			currentrule = calloc(sizeof(rule_t),1);
+			headrule = currentrule;
+		}
+		else
+		{
+			/* follow-up element */
+			currentrule->next = calloc(sizeof(rule_t),1);
+			currentrule = currentrule->next;
+		}
+
+		if ( init_led(&(currentrule->led), argv[i]) )
+			return 1;
+		
+		if ( sscanf(argv[i+1], "%d", &(currentrule->minq)) != 1 )
+			return 1;
+
+		if ( sscanf(argv[i+2], "%d", &(currentrule->maxq)) != 1 )
+			return 1;
+		
+		if ( sscanf(argv[i+3], "%d", &(currentrule->boffset)) != 1 )
+			return 1;
+		
+		if ( sscanf(argv[i+4], "%d", &(currentrule->bfactor)) != 1 )
+			return 1;
+	}
+	log_rules(headrule);
+
+	q0 = -1;
+	do {
+		q = quality(iw, ifname);
+		if ( q < q0 - s || q > q0 + s ) {
+			update_leds(headrule, q);
+			q0=q;
+		};
+		// re-open backend...
+		if ( q == -1 && q0 == -1 ) {
+			if (iw) {
+				iwinfo_finish();
+				iw=NULL;
+				usleep(BACKEND_RETRY_DELAY);
+			}
+			while (open_backend(&iw, ifname))
+				usleep(BACKEND_RETRY_DELAY);
+		}
+		usleep(r);
+	} while(1);
+
+	iwinfo_finish();
+
+	return 0;
+}
diff --git a/package/network/utils/tcpdump/Makefile b/package/network/utils/tcpdump/Makefile
new file mode 100644
index 0000000000..d0a05e0618
--- /dev/null
+++ b/package/network/utils/tcpdump/Makefile
@@ -0,0 +1,90 @@
+#
+# Copyright (C) 2007-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=tcpdump
+PKG_VERSION:=4.5.1
+PKG_RELEASE:=4
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.tcpdump.org/release/ \
+	http://ftp.gwdg.de/pub/misc/tcpdump/ \
+	http://www.at.tcpdump.org/ \
+	http://www.br.tcpdump.org/
+PKG_MD5SUM:=973a2513d0076e34aa9da7e15ed98e1b
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_BUILD_PARALLEL:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=BSD-3-Clause
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/tcpdump/default
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libpcap
+  TITLE:=Network monitoring and data acquisition tool
+  URL:=http://www.tcpdump.org/
+endef
+
+define Package/tcpdump
+  $(Package/tcpdump/default)
+  VARIANT:=full
+endef
+
+define Package/tcpdump-mini
+  $(Package/tcpdump/default)
+  TITLE+= (minimal version)
+  VARIANT:=mini
+endef
+
+CONFIGURE_ARGS += \
+	--without-crypto
+
+ifeq ($(CONFIG_IPV6),y)
+CONFIGURE_ARGS += \
+	--enable-ipv6
+endif
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+CONFIGURE_VARS += \
+	BUILD_CC="$(TARGET_CC)" \
+	HOSTCC="$(HOSTCC)" \
+	td_cv_buggygetaddrinfo="no" \
+	ac_cv_linux_vers=$(LINUX_VERSION) \
+	ac_cv_header_rpc_rpcent_h=no \
+	ac_cv_lib_rpc_main=no \
+	ac_cv_path_PCAP_CONFIG=""
+
+MAKE_FLAGS :=
+
+ifeq ($(BUILD_VARIANT),mini)
+  TARGET_CFLAGS += -DTCPDUMP_MINI
+  CONFIGURE_ARGS += --disable-smb
+  MAKE_FLAGS += TCPDUMP_MINI=1
+endif
+
+MAKE_FLAGS += \
+	CCOPT="$(TARGET_CFLAGS)" INCLS="-I. $(TARGET_CPPFLAGS)"
+
+
+define Package/tcpdump/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/tcpdump $(1)/usr/sbin/
+endef
+
+Package/tcpdump-mini/install = $(Package/tcpdump/install)
+
+$(eval $(call BuildPackage,tcpdump))
+$(eval $(call BuildPackage,tcpdump-mini))
diff --git a/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch b/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch
new file mode 100644
index 0000000000..d2c724d509
--- /dev/null
+++ b/package/network/utils/tcpdump/patches/001-remove_pcap_debug.patch
@@ -0,0 +1,23 @@
+--- a/tcpdump.c
++++ b/tcpdump.c
+@@ -1095,20 +1095,6 @@ main(int argc, char **argv)
+ 				error("invalid data link type %s", gndo->ndo_dltname);
+ 			break;
+ 
+-#if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG)
+-		case 'Y':
+-			{
+-			/* Undocumented flag */
+-#ifdef HAVE_PCAP_DEBUG
+-			extern int pcap_debug;
+-			pcap_debug = 1;
+-#else
+-			extern int yydebug;
+-			yydebug = 1;
+-#endif
+-			}
+-			break;
+-#endif
+ 		case 'z':
+ 			if (optarg) {
+ 				zflag = strdup(optarg);
diff --git a/package/network/utils/tcpdump/patches/002-remove_static_libpcap_check.patch b/package/network/utils/tcpdump/patches/002-remove_static_libpcap_check.patch
new file mode 100644
index 0000000000..c8bdf1499e
--- /dev/null
+++ b/package/network/utils/tcpdump/patches/002-remove_static_libpcap_check.patch
@@ -0,0 +1,73 @@
+--- a/configure
++++ b/configure
+@@ -5813,28 +5813,6 @@ $as_echo "Using $pfopen" >&6; }
+ 		    LIBS="$LIBS $pfopen"
+ 	    fi
+     fi
+-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for local pcap library" >&5
+-$as_echo_n "checking for local pcap library... " >&6; }
+-    libpcap=FAIL
+-    lastdir=FAIL
+-    places=`ls $srcdir/.. | sed -e 's,/$,,' -e "s,^,$srcdir/../," | \
+-	egrep '/libpcap-[0-9]+\.[0-9]+(\.[0-9]*)?([ab][0-9]*|-PRE-GIT)?$'`
+-    for dir in $places $srcdir/../libpcap $srcdir/libpcap ; do
+-	    basedir=`echo $dir | sed -e 's/[ab][0-9]*$//' | \
+-	        sed -e 's/-PRE-GIT$//' `
+-	    if test $lastdir = $basedir ; then
+-		    		    continue;
+-	    fi
+-	    lastdir=$dir
+-	    if test -r $dir/libpcap.a ; then
+-		    libpcap=$dir/libpcap.a
+-		    d=$dir
+-		    	    fi
+-    done
+-    if test $libpcap = FAIL ; then
+-	    { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+-$as_echo "not found" >&6; }
+-
+ 	    #
+ 	    # Look for pcap-config.
+ 	    #
+@@ -5989,41 +5967,6 @@ if test "x$ac_cv_lib_pcap_main" = xyes;
+   libpcap="-lpcap"
+ fi
+ 
+-		if test $libpcap = FAIL ; then
+-		    as_fn_error $? "see the INSTALL doc for more info" "$LINENO" 5
+-		fi
+-																																								{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for extraneous pcap header directories" >&5
+-$as_echo_n "checking for extraneous pcap header directories... " >&6; }
+-		if test \( ! -r /usr/local/include/pcap.h \) -a \
+-			\( ! -r /usr/include/pcap.h \); then
+-		    if test -r /usr/local/include/pcap/pcap.h; then
+-			d="/usr/local/include/pcap"
+-		    elif test -r /usr/include/pcap/pcap.h; then
+-			d="/usr/include/pcap"
+-		    fi
+-		fi
+-		if test -z "$d" ; then
+-		    { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+-$as_echo "not found" >&6; }
+-		else
+-		    V_INCLS="-I$d $V_INCLS"
+-		    { $as_echo "$as_me:${as_lineno-$LINENO}: result: found -- -I$d added" >&5
+-$as_echo "found -- -I$d added" >&6; }
+-		fi
+-	    fi
+-    else
+-	    V_PCAPDEP=$libpcap
+-	    places=`ls $srcdir/.. | sed -e 's,/$,,' -e "s,^,$srcdir/../," | \
+-    	 		egrep '/libpcap-[0-9]*.[0-9]*(.[0-9]*)?([ab][0-9]*)?$'`
+-	    if test -r $d/pcap.h; then
+-		    V_INCLS="-I$d $V_INCLS"
+-	    elif test -r $places/pcap.h; then
+-		    V_INCLS="-I$places $V_INCLS"
+-	    else
+-                    as_fn_error see INSTALL "cannot find pcap.h" "$LINENO" 5
+- 	    fi
+-	    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libpcap" >&5
+-$as_echo "$libpcap" >&6; }
+ 	    # Extract the first word of "pcap-config", so it can be a program name with args.
+ set dummy pcap-config; ac_word=$2
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
diff --git a/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch b/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch
new file mode 100644
index 0000000000..8d07be6b40
--- /dev/null
+++ b/package/network/utils/tcpdump/patches/100-tcpdump_mini.patch
@@ -0,0 +1,844 @@
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -71,6 +71,22 @@ DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@
+ 	@rm -f $@
+ 	$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
+ 
++ifdef TCPDUMP_MINI
++
++CSRC =	addrtoname.c af.c checksum.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c \
++        nlpid.c l2vpn.c machdep.c parsenfsfh.c in_cksum.c \
++	print-802_11.c print-aodv.c print-arp.c print-ascii.c \
++	print-bgp.c print-bootp.c print-cdp.c print-domain.c print-eap.c print-ether.c \
++	print-gre.c print-icmp.c print-igmp.c print-ip.c \
++	print-l2tp.c print-lldp.c print-llc.c \
++ 	print-nfs.c print-ntp.c print-null.c print-olsr.c print-ospf.c \
++	print-ppp.c print-pppoe.c print-pptp.c print-radius.c print-raw.c print-rsvp.c \
++	print-sctp.c print-sip.c print-sll.c print-snmp.c print-stp.c print-sunrpc.c \
++	print-syslog.c print-tcp.c print-telnet.c print-tftp.c print-udp.c \
++	setsignal.c tcpdump.c util.c signature.c print-ipnet.c print-forces.c
++
++else
++
+ CSRC =	addrtoname.c af.c checksum.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c \
+         nlpid.c l2vpn.c machdep.c parsenfsfh.c in_cksum.c \
+ 	print-802_11.c print-802_15_4.c print-ap1394.c print-ah.c \
+@@ -103,6 +119,8 @@ LIBNETDISSECT_SRC=print-isakmp.c
+ LIBNETDISSECT_OBJ=$(LIBNETDISSECT_SRC:.c=.o)
+ LIBNETDISSECT=libnetdissect.a
+ 
++endif
++
+ LOCALSRC = @LOCALSRC@
+ GENSRC = version.c
+ LIBOBJS = @LIBOBJS@
+@@ -286,10 +304,12 @@ $(PROG): $(OBJ) @V_PCAPDEP@
+ 	@rm -f $@
+ 	$(CC) $(FULL_CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
+ 
++ifndef TCPDUMP_MINI
+ $(LIBNETDISSECT): $(LIBNETDISSECT_OBJ)
+ 	@rm -f $@
+ 	$(AR) cr $@ $(LIBNETDISSECT_OBJ) 
+ 	$(RANLIB) $@
++endif
+ 
+ datalinks.o: $(srcdir)/missing/datalinks.c
+ 	$(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/datalinks.c
+--- a/addrtoname.c
++++ b/addrtoname.c
+@@ -556,10 +556,10 @@ linkaddr_string(const u_char *ep, const
+ 
+ 	if (type == LINKADDR_ETHER && len == ETHER_ADDR_LEN)
+ 		return (etheraddr_string(ep));
+-
++#ifndef TCPDUMP_MINI
+ 	if (type == LINKADDR_FRELAY)
+ 		return (q922_string(ep));
+-
++#endif
+ 	tp = lookup_bytestring(ep, len);
+ 	if (tp->e_name)
+ 		return (tp->e_name);
+@@ -1159,6 +1159,7 @@ init_addrtoname(u_int32_t localnet, u_in
+ 	init_ipxsaparray();
+ }
+ 
++#ifndef TCPDUMP_MINI
+ const char *
+ dnaddr_string(u_short dnaddr)
+ {
+@@ -1178,6 +1179,7 @@ dnaddr_string(u_short dnaddr)
+ 
+ 	return(tp->name);
+ }
++#endif
+ 
+ /* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
+ struct hnamemem *
+--- a/print-ether.c
++++ b/print-ether.c
+@@ -342,6 +342,7 @@ ethertype_print(netdissect_options *ndo,
+   	        arp_print(ndo, p, length, caplen);
+ 		return (1);
+ 
++#ifndef TCPDUMP_MINI
+ 	case ETHERTYPE_DN:
+ 		decnet_print(/*ndo,*/p, length, caplen);
+ 		return (1);
+@@ -360,10 +361,13 @@ ethertype_print(netdissect_options *ndo,
+ 		ND_PRINT((ndo, "(NOV-ETHII) "));
+ 		ipx_print(/*ndo,*/p, length);
+ 		return (1);
++#endif
+ 
++#ifndef TCPDUMP_MINI
+         case ETHERTYPE_ISO:
+                 isoclns_print(/*ndo,*/p+1, length-1, length-1);
+                 return(1);
++#endif
+ 
+ 	case ETHERTYPE_PPPOED:
+ 	case ETHERTYPE_PPPOES:
+@@ -376,9 +380,11 @@ ethertype_print(netdissect_options *ndo,
+ 	        eap_print(ndo, p, length);
+ 		return (1);
+ 
++#ifndef TCPDUMP_MINI
+ 	case ETHERTYPE_RRCP:
+ 	        rrcp_print(ndo, p - 14 , length + 14);
+ 		return (1);
++#endif
+ 
+ 	case ETHERTYPE_PPP:
+ 		if (length) {
+@@ -387,6 +393,7 @@ ethertype_print(netdissect_options *ndo,
+ 		}
+ 		return (1);
+ 
++#ifndef TCPDUMP_MINI
+ 	case ETHERTYPE_MPCP:
+ 	        mpcp_print(/*ndo,*/p, length);
+ 		return (1);
+@@ -399,7 +406,7 @@ ethertype_print(netdissect_options *ndo,
+ 	case ETHERTYPE_CFM_OLD:
+ 	        cfm_print(/*ndo,*/p, length);
+ 		return (1);
+-
++#endif
+ 	case ETHERTYPE_LLDP:
+ 	        lldp_print(/*ndo,*/p, length);
+ 		return (1);
+@@ -407,6 +414,7 @@ ethertype_print(netdissect_options *ndo,
+         case ETHERTYPE_LOOPBACK:
+                 return (1);
+ 
++#ifndef TCPDUMP_MINI
+ 	case ETHERTYPE_MPLS:
+ 	case ETHERTYPE_MPLS_MULTI:
+ 		mpls_print(/*ndo,*/p, length);
+@@ -428,6 +436,7 @@ ethertype_print(netdissect_options *ndo,
+         case ETHERTYPE_CALM_FAST:
+                 calm_fast_print(ndo, p-14, p, length);
+                 return (1);
++#endif
+ 
+ 	case ETHERTYPE_LAT:
+ 	case ETHERTYPE_SCA:
+--- a/print-gre.c
++++ b/print-gre.c
+@@ -213,6 +213,7 @@ gre_print_0(const u_char *bp, u_int leng
+ 		ip6_print(gndo, bp, len);
+ 		break;
+ #endif
++#ifndef TCPDUMP_MINI
+ 	case ETHERTYPE_MPLS:
+ 		mpls_print(bp, len);
+ 		break;
+@@ -228,6 +229,7 @@ gre_print_0(const u_char *bp, u_int leng
+ 	case ETHERTYPE_TEB:
+ 		ether_print(gndo, bp, len, len, NULL, NULL);
+ 		break;
++#endif
+ 	default:
+ 		printf("gre-proto-0x%x", prot);
+ 	}
+--- a/print-igmp.c
++++ b/print-igmp.c
+@@ -309,6 +309,7 @@ igmp_print(register const u_char *bp, re
+         TCHECK2(bp[4], 4);
+         (void)printf("igmp leave %s", ipaddr_string(&bp[4]));
+         break;
++#ifndef TCPDUMP_MINI
+     case 0x13:
+         (void)printf("igmp dvmrp");
+         if (len < 8)
+@@ -320,6 +321,7 @@ igmp_print(register const u_char *bp, re
+         (void)printf("igmp pimv1");
+         pimv1_print(bp, len);
+         break;
++#endif
+     case 0x1e:
+         print_mresp(bp, len);
+         break;
+--- a/print-ip.c
++++ b/print-ip.c
+@@ -328,6 +328,7 @@ ip_print_demux(netdissect_options *ndo,
+ again:
+ 	switch (ipds->nh) {
+ 
++#ifndef TCPDUMP_MINI
+ 	case IPPROTO_AH:
+ 		ipds->nh = *ipds->cp;
+ 		ipds->advance = ah_print(ipds->cp);
+@@ -362,15 +363,15 @@ again:
+ 		ipds->nh = enh & 0xff;
+ 		goto again;
+ 	}
+-
++#endif
+ 	case IPPROTO_SCTP:
+ 		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
+ 		break;
+-
++#ifndef TCPDUMP_MINI
+ 	case IPPROTO_DCCP:
+ 		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
+ 		break;
+-
++#endif
+ 	case IPPROTO_TCP:
+ 		/* pass on the MF bit plus the offset to detect fragments */
+ 		tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
+@@ -388,7 +389,7 @@ again:
+ 		icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
+ 			   ipds->off & (IP_MF|IP_OFFMASK));
+ 		break;
+-
++#ifndef TCPDUMP_MINI
+ 	case IPPROTO_PIGP:
+ 		/*
+ 		 * XXX - the current IANA protocol number assignments
+@@ -409,15 +410,15 @@ again:
+ 	case IPPROTO_EIGRP:
+ 		eigrp_print(ipds->cp, ipds->len);
+ 		break;
+-
++#endif
+ 	case IPPROTO_ND:
+ 		ND_PRINT((ndo, " nd %d", ipds->len));
+ 		break;
+-
++#ifndef TCPDUMP_MINI
+ 	case IPPROTO_EGP:
+ 		egp_print(ipds->cp, ipds->len);
+ 		break;
+-
++#endif
+ 	case IPPROTO_OSPF:
+ 		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
+ 		break;
+@@ -451,10 +452,10 @@ again:
+ 		gre_print(ipds->cp, ipds->len);
+ 		break;
+ 
++#ifndef TCPDUMP_MINI
+ 	case IPPROTO_MOBILE:
+ 		mobile_print(ipds->cp, ipds->len);
+ 		break;
+-
+ 	case IPPROTO_PIM:
+ 		vec[0].ptr = ipds->cp;
+ 		vec[0].len = ipds->len;
+@@ -480,7 +481,7 @@ again:
+ 	case IPPROTO_PGM:
+ 		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
+ 		break;
+-
++#endif
+ 	default:
+ 		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
+ 			ND_PRINT((ndo, " %s", proto->p_name));
+--- a/print-ip6.c
++++ b/print-ip6.c
+@@ -192,9 +192,11 @@ ip6_print(netdissect_options *ndo, const
+ 		case IPPROTO_SCTP:
+ 			sctp_print(cp, (const u_char *)ip6, len);
+ 			return;
++#ifndef TCPDUMP_MINI
+ 		case IPPROTO_DCCP:
+ 			dccp_print(cp, (const u_char *)ip6, len);
+ 			return;
++#endif
+ 		case IPPROTO_TCP:
+ 			tcp_print(cp, len, (const u_char *)ip6, fragmented);
+ 			return;
+@@ -204,6 +206,7 @@ ip6_print(netdissect_options *ndo, const
+ 		case IPPROTO_ICMPV6:
+ 			icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented);
+ 			return;
++#ifndef TCPDUMP_MINI
+ 		case IPPROTO_AH:
+ 			advance = ah_print(cp);
+ 			nh = *cp;
+@@ -228,7 +231,7 @@ ip6_print(netdissect_options *ndo, const
+ 			pim_print(cp, len, nextproto6_cksum(ip6, cp, len,
+ 							    IPPROTO_PIM));
+ 			return;
+-
++#endif
+ 		case IPPROTO_OSPF:
+ 			ospf6_print(cp, len);
+ 			return;
+@@ -240,11 +243,11 @@ ip6_print(netdissect_options *ndo, const
+ 		case IPPROTO_IPV4:
+ 		        ip_print(ndo, cp, len);
+ 			return;
+-
++#ifndef TCPDUMP_MINI
+                 case IPPROTO_PGM:
+                         pgm_print(cp, len, (const u_char *)ip6);
+                         return;
+-
++#endif
+ 		case IPPROTO_GRE:
+ 			gre_print(cp, len);
+ 			return;
+--- a/print-llc.c
++++ b/print-llc.c
+@@ -196,7 +196,7 @@ llc_print(const u_char *p, u_int length,
+ 		control = EXTRACT_LE_16BITS(p + 2);
+ 		is_u = 0;
+ 	}
+-
++#ifndef TCPDUMP_MINI
+ 	if (ssap_field == LLCSAP_GLOBAL && dsap_field == LLCSAP_GLOBAL) {
+ 		/*
+ 		 * This is an Ethernet_802.3 IPX frame; it has an
+@@ -219,6 +219,7 @@ llc_print(const u_char *p, u_int length,
+             ipx_print(p, length);
+             return (1);
+ 	}
++#endif
+ 
+ 	dsap = dsap_field & ~LLC_IG;
+ 	ssap = ssap_field & ~LLC_GSAP;
+@@ -251,6 +252,7 @@ llc_print(const u_char *p, u_int length,
+ 		return (1);
+ 	}
+ 
++#ifndef TCPDUMP_MINI
+ 	if (ssap == LLCSAP_IPX && dsap == LLCSAP_IPX &&
+ 	    control == LLC_UI) {
+ 		/*
+@@ -266,6 +268,7 @@ llc_print(const u_char *p, u_int length,
+ 		ipx_print(p+3, length-3);
+ 		return (1);
+ 	}
++#endif
+ 
+ #ifdef TCPDUMP_DO_SMB
+ 	if (ssap == LLCSAP_NETBEUI && dsap == LLCSAP_NETBEUI
+@@ -297,11 +300,13 @@ llc_print(const u_char *p, u_int length,
+ 		return (1);
+ 	}
+ #endif
++#ifndef TCPDUMP_MINI
+ 	if (ssap == LLCSAP_ISONS && dsap == LLCSAP_ISONS
+ 	    && control == LLC_UI) {
+ 		isoclns_print(p + 3, length - 3, caplen - 3);
+ 		return (1);
+ 	}
++#endif
+ 
+ 	if (ssap == LLCSAP_SNAP && dsap == LLCSAP_SNAP
+ 	    && control == LLC_UI) {
+@@ -444,6 +449,7 @@ snap_print(const u_char *p, u_int length
+                 case PID_CISCO_CDP:
+                         cdp_print(p, length, caplen);
+                         return (1);
++#ifndef TCPDUMP_MINI
+                 case PID_CISCO_DTP:
+                         dtp_print(p, length); 
+                         return (1);
+@@ -453,6 +459,7 @@ snap_print(const u_char *p, u_int length
+                 case PID_CISCO_VTP:
+                         vtp_print(p, length);
+                         return (1);
++#endif
+                 case PID_CISCO_PVST:
+                 case PID_CISCO_VLANBRIDGE:
+                         stp_print(p, length);
+@@ -484,6 +491,7 @@ snap_print(const u_char *p, u_int length
+ 			ether_print(gndo, p, length, caplen, NULL, NULL);
+ 			return (1);
+ 
++#ifndef TCPDUMP_MINI
+ 		case PID_RFC2684_802_5_FCS:
+ 		case PID_RFC2684_802_5_NOFCS:
+ 			/*
+@@ -525,6 +533,7 @@ snap_print(const u_char *p, u_int length
+ 			 */
+ 			fddi_print(p, length, caplen);
+ 			return (1);
++#endif
+ 
+ 		case PID_RFC2684_BPDU:
+ 			stp_print(p, length);
+--- a/print-null.c
++++ b/print-null.c
+@@ -128,7 +128,7 @@ null_if_print(const struct pcap_pkthdr *
+ 		ip6_print(gndo, p, length);
+ 		break;
+ #endif
+-
++#ifndef TCPDUMP_MINI
+ 	case BSD_AFNUM_ISO:
+ 		isoclns_print(p, length, caplen);
+ 		break;
+@@ -140,7 +140,7 @@ null_if_print(const struct pcap_pkthdr *
+ 	case BSD_AFNUM_IPX:
+ 		ipx_print(p, length);
+ 		break;
+-
++#endif
+ 	default:
+ 		/* unknown AF_ value */
+ 		if (!eflag)
+--- a/print-ppp.c
++++ b/print-ppp.c
+@@ -1262,7 +1262,7 @@ trunc:
+ 	return 0;
+ }
+ 
+-
++#ifndef TCPDUMP_MINI
+ static void
+ ppp_hdlc(const u_char *p, int length)
+ {
+@@ -1327,17 +1327,19 @@ cleanup:
+ 	free(b);
+         return;
+ }
++#endif
+ 
+ 
+ /* PPP */
+ static void
+ handle_ppp(u_int proto, const u_char *p, int length)
+ {
++#ifndef TCPDUMP_MINI
+         if ((proto & 0xff00) == 0x7e00) {/* is this an escape code ? */
+             ppp_hdlc(p-1, length);
+             return;
+         }
+-
++#endif
+ 	switch (proto) {
+ 	case PPP_LCP: /* fall through */
+ 	case PPP_IPCP:
+@@ -1371,6 +1373,7 @@ handle_ppp(u_int proto, const u_char *p,
+ 		ip6_print(gndo, p, length);
+ 		break;
+ #endif
++#ifndef TCPDUMP_MINI
+ 	case ETHERTYPE_IPX:	/*XXX*/
+ 	case PPP_IPX:
+ 		ipx_print(p, length);
+@@ -1382,6 +1385,7 @@ handle_ppp(u_int proto, const u_char *p,
+ 	case PPP_MPLS_MCAST:
+ 		mpls_print(p, length);
+ 		break;
++#endif
+ 	case PPP_COMP:
+ 		printf("compressed PPP data");
+ 		break;
+@@ -1520,6 +1524,7 @@ ppp_if_print(const struct pcap_pkthdr *h
+ 	return (0);
+ }
+ 
++#ifndef TCPDUMP_MINI
+ /*
+  * PPP I/F printer to use if we know that RFC 1662-style PPP in HDLC-like
+  * framing, or Cisco PPP with HDLC framing as per section 4.3.1 of RFC 1547,
+@@ -1747,7 +1752,7 @@ printx:
+ #endif /* __bsdi__ */
+ 	return (hdrlength);
+ }
+-
++#endif
+ 
+ /*
+  * Local Variables:
+--- a/print-tcp.c
++++ b/print-tcp.c
+@@ -573,14 +573,14 @@ tcp_print(register const u_char *bp, reg
+                                         utoval >>= 1;
+                                 (void)printf(" %u", utoval);
+                                 break;
+-
++#ifndef TCPDUMP_MINI
+                         case TCPOPT_MPTCP:
+                                 datalen = len - 2;
+                                 LENCHECK(datalen);
+                                 if (!mptcp_print(cp-2, len, flags))
+                                         goto bad;
+                                 break;
+-
++#endif
+                         case TCPOPT_EXPERIMENT2:
+                                 datalen = len - 2;
+                                 LENCHECK(datalen);
+@@ -659,8 +659,8 @@ tcp_print(register const u_char *bp, reg
+         if ((flags & TH_RST) && vflag) {
+                 print_tcp_rst_data(bp, length);
+                 return;
+-        } 
+-
++        }
++#ifndef TCPDUMP_MINI
+         if (packettype) {
+                 switch (packettype) {
+                 case PT_ZMTP1:
+@@ -669,7 +669,7 @@ tcp_print(register const u_char *bp, reg
+                 }
+                 return;
+         }
+-
++#endif
+         if (sport == TELNET_PORT || dport == TELNET_PORT) {
+                 if (!qflag && vflag)
+                         telnet_print(bp, length);
+@@ -683,10 +683,12 @@ tcp_print(register const u_char *bp, reg
+ 	else if (sport == SMB_PORT || dport == SMB_PORT)
+ 		smb_tcp_print(bp, length);
+ #endif
++#ifndef TCPDUMP_MINI
+         else if (sport == BEEP_PORT || dport == BEEP_PORT)
+                 beep_print(bp, length);
+         else if (sport == OPENFLOW_PORT || dport == OPENFLOW_PORT)
+                 openflow_print(bp, length);
++#endif
+         else if (length > 2 &&
+                  (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT ||
+                   sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) {
+@@ -695,6 +697,7 @@ tcp_print(register const u_char *bp, reg
+                  * XXX packet could be unaligned, it can go strange
+                  */
+                 ns_print(bp + 2, length - 2, 0);
++#ifndef TCPDUMP_MINI
+         } else if (sport == MSDP_PORT || dport == MSDP_PORT) {
+                 msdp_print(bp, length);
+         } else if (sport == RPKI_RTR_PORT || dport == RPKI_RTR_PORT) {
+@@ -702,6 +705,7 @@ tcp_print(register const u_char *bp, reg
+         }
+         else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) {
+                 ldp_print(bp, length);
++#endif
+         }
+         else if ((sport == NFS_PORT || dport == NFS_PORT) &&
+                  length >= 4 && TTEST2(*bp, 4)) {
+--- a/print-udp.c
++++ b/print-udp.c
+@@ -418,11 +418,12 @@ udp_print(register const u_char *bp, u_i
+ 			vat_print((void *)(up + 1), up);
+ 			break;
+ 
++#ifndef TCPDUMP_MINI
+ 		case PT_WB:
+ 			udpipaddr_print(ip, sport, dport);
+ 			wb_print((void *)(up + 1), length);
+ 			break;
+-
++#endif
+ 		case PT_RPC:
+ 			rp = (struct sunrpc_msg *)(up + 1);
+ 			direction = (enum sunrpc_msg_type)EXTRACT_32BITS(&rp->rm_direction);
+@@ -450,11 +451,12 @@ udp_print(register const u_char *bp, u_i
+ 			snmp_print((const u_char *)(up + 1), length);
+ 			break;
+ 
++#ifndef TCPDUMP_MINI
+ 		case PT_CNFP:
+ 			udpipaddr_print(ip, sport, dport);
+ 			cnfp_print(cp, (const u_char *)ip);
+ 			break;
+-
++#endif
+ 		case PT_TFTP:
+ 			udpipaddr_print(ip, sport, dport);
+ 			tftp_print(cp, length);
+@@ -475,6 +477,7 @@ udp_print(register const u_char *bp, u_i
+ 			radius_print(cp, length);
+ 			break;
+ 
++#ifndef TCPDUMP_MINI
+ 		case PT_VXLAN:
+ 			udpipaddr_print(ip, sport, dport);
+ 			vxlan_print((const u_char *)(up + 1), length);
+@@ -489,6 +492,7 @@ udp_print(register const u_char *bp, u_i
+ 			udpipaddr_print(ip, sport, dport);
+ 			lmp_print(cp, length);
+ 			break;
++#endif
+ 		}
+ 		return;
+ 	}
+@@ -517,6 +521,7 @@ udp_print(register const u_char *bp, u_i
+ 			}
+ #endif
+ 		}
++#ifndef TCPDUMP_MINI
+ 		if (TTEST(((struct LAP *)cp)->type) &&
+ 		    ((struct LAP *)cp)->type == lapDDP &&
+ 		    (atalk_port(sport) || atalk_port(dport))) {
+@@ -525,6 +530,7 @@ udp_print(register const u_char *bp, u_i
+ 			llap_print(cp, length);
+ 			return;
+ 		}
++#endif
+ 	}
+ 	udpipaddr_print(ip, sport, dport);
+ 
+@@ -575,14 +581,18 @@ udp_print(register const u_char *bp, u_i
+ 			ns_print((const u_char *)(up + 1), length, 0);
+ 		else if (ISPORT(MULTICASTDNS_PORT))
+ 			ns_print((const u_char *)(up + 1), length, 1);
++#ifndef TCPDUMP_MINI
+ 		else if (ISPORT(TIMED_PORT))
+ 			timed_print((const u_char *)(up + 1));
++#endif
+ 		else if (ISPORT(TFTP_PORT))
+ 			tftp_print((const u_char *)(up + 1), length);
+ 		else if (ISPORT(IPPORT_BOOTPC) || ISPORT(IPPORT_BOOTPS))
+ 			bootp_print((const u_char *)(up + 1), length);
++#ifndef TCPDUMP_MINI
+ 		else if (ISPORT(RIP_PORT))
+ 			rip_print((const u_char *)(up + 1), length);
++#endif
+ 		else if (ISPORT(AODV_PORT))
+ 			aodv_print((const u_char *)(up + 1), length,
+ #ifdef INET6
+@@ -590,6 +600,7 @@ udp_print(register const u_char *bp, u_i
+ #else
+ 			    0);
+ #endif
++#ifndef TCPDUMP_MINI
+ 	        else if (ISPORT(ISAKMP_PORT))
+ 			 isakmp_print(gndo, (const u_char *)(up + 1), length, bp2);
+   	        else if (ISPORT(ISAKMP_PORT_NATT))
+@@ -598,12 +609,15 @@ udp_print(register const u_char *bp, u_i
+    	        else if (ISPORT(ISAKMP_PORT_USER1) || ISPORT(ISAKMP_PORT_USER2))
+ 			isakmp_print(gndo, (const u_char *)(up + 1), length, bp2);
+ #endif
++#endif
+ 		else if (ISPORT(SNMP_PORT) || ISPORT(SNMPTRAP_PORT))
+ 			snmp_print((const u_char *)(up + 1), length);
+ 		else if (ISPORT(NTP_PORT))
+ 			ntp_print((const u_char *)(up + 1), length);
++#ifndef TCPDUMP_MINI
+ 		else if (ISPORT(KERBEROS_PORT) || ISPORT(KERBEROS_SEC_PORT))
+ 			krb_print((const void *)(up + 1));
++#endif
+ 		else if (ISPORT(L2TP_PORT))
+ 			l2tp_print((const u_char *)(up + 1), length);
+ #ifdef TCPDUMP_DO_SMB
+@@ -614,6 +628,7 @@ udp_print(register const u_char *bp, u_i
+ #endif
+ 		else if (dport == VAT_PORT)
+ 			vat_print((const void *)(up + 1), up);
++#ifndef TCPDUMP_MINI
+ 		else if (ISPORT(ZEPHYR_SRV_PORT) || ISPORT(ZEPHYR_CLT_PORT))
+ 			zephyr_print((const void *)(up + 1), length);
+ 		/*
+@@ -624,6 +639,7 @@ udp_print(register const u_char *bp, u_i
+ 			 (dport >= RX_PORT_LOW && dport <= RX_PORT_HIGH))
+ 			rx_print((const void *)(up + 1), length, sport, dport,
+ 				 (u_char *) ip);
++#endif
+ #ifdef INET6
+ 		else if (ISPORT(RIPNG_PORT))
+ 			ripng_print((const u_char *)(up + 1), length);
+@@ -635,21 +651,25 @@ udp_print(register const u_char *bp, u_i
+ 		/*
+ 		 * Kludge in test for whiteboard packets.
+ 		 */
++#ifndef TCPDUMP_MINI
+ 		else if (dport == WB_PORT)
+ 			wb_print((const void *)(up + 1), length);
+ 		else if (ISPORT(CISCO_AUTORP_PORT))
+ 			cisco_autorp_print((const void *)(up + 1), length);
++#endif
+ 		else if (ISPORT(RADIUS_PORT) ||
+ 			 ISPORT(RADIUS_NEW_PORT) ||
+ 			 ISPORT(RADIUS_ACCOUNTING_PORT) ||
+ 			 ISPORT(RADIUS_NEW_ACCOUNTING_PORT) )
+ 			radius_print((const u_char *)(up+1), length);
++#ifndef TCPDUMP_MINI
+ 		else if (dport == HSRP_PORT)
+ 			hsrp_print((const u_char *)(up + 1), length);
+ 		else if (ISPORT(LWRES_PORT))
+ 			lwres_print((const u_char *)(up + 1), length);
+ 		else if (ISPORT(LDP_PORT))
+ 			ldp_print((const u_char *)(up + 1), length);
++#endif
+ 		else if (ISPORT(OLSR_PORT))
+ 			olsr_print((const u_char *)(up + 1), length,
+ #if INET6
+@@ -657,6 +677,7 @@ udp_print(register const u_char *bp, u_i
+ #else
+ 					0);
+ #endif
++#ifndef TCPDUMP_MINI
+ 		else if (ISPORT(MPLS_LSP_PING_PORT))
+ 			lspping_print((const u_char *)(up + 1), length);
+ 		else if (dport == BFD_CONTROL_PORT ||
+@@ -674,14 +695,17 @@ udp_print(register const u_char *bp, u_i
+                         lwapp_control_print((const u_char *)(up + 1), length, 0);
+                 else if (ISPORT(LWAPP_DATA_PORT))
+                         lwapp_data_print((const u_char *)(up + 1), length);
++#endif
+                 else if (ISPORT(SIP_PORT))
+ 			sip_print((const u_char *)(up + 1), length);
+                 else if (ISPORT(SYSLOG_PORT))
+ 			syslog_print((const u_char *)(up + 1), length);
++#ifndef TCPDUMP_MINI
+                 else if (ISPORT(OTV_PORT))
+ 			otv_print((const u_char *)(up + 1), length);
+                 else if (ISPORT(VXLAN_PORT))
+ 			vxlan_print((const u_char *)(up + 1), length);
++#endif
+ 		else
+ 			(void)printf("UDP, length %u",
+ 			    (u_int32_t)(ulen - sizeof(*up)));
+--- a/tcpdump.c
++++ b/tcpdump.c
+@@ -161,6 +161,7 @@ struct ndo_printer {
+ 
+ 
+ static struct printer printers[] = {
++#ifndef TCPDUMP_MINI
+ 	{ arcnet_if_print,	DLT_ARCNET },
+ #ifdef DLT_ARCNET_LINUX
+ 	{ arcnet_linux_if_print, DLT_ARCNET_LINUX },
+@@ -179,19 +180,23 @@ static struct printer printers[] = {
+ #ifdef DLT_SLIP_BSDOS
+ 	{ sl_bsdos_if_print,	DLT_SLIP_BSDOS },
+ #endif
++#endif
+ 	{ ppp_if_print,		DLT_PPP },
+ #ifdef DLT_PPP_WITHDIRECTION
+ 	{ ppp_if_print,		DLT_PPP_WITHDIRECTION },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_PPP_BSDOS
+ 	{ ppp_bsdos_if_print,	DLT_PPP_BSDOS },
+ #endif
+ 	{ fddi_if_print,	DLT_FDDI },
++#endif
+ 	{ null_if_print,	DLT_NULL },
+ #ifdef DLT_LOOP
+ 	{ null_if_print,	DLT_LOOP },
+ #endif
+ 	{ raw_if_print,		DLT_RAW },
++#ifndef TCPDUMP_MINI
+ 	{ atm_if_print,		DLT_ATM_RFC1483 },
+ #ifdef DLT_C_HDLC
+ 	{ chdlc_if_print,	DLT_C_HDLC },
+@@ -202,6 +207,7 @@ static struct printer printers[] = {
+ #ifdef DLT_PPP_SERIAL
+ 	{ ppp_hdlc_if_print,	DLT_PPP_SERIAL },
+ #endif
++#endif
+ #ifdef DLT_PPP_ETHER
+ 	{ pppoe_if_print,	DLT_PPP_ETHER },
+ #endif
+@@ -211,6 +217,7 @@ static struct printer printers[] = {
+ #ifdef DLT_IEEE802_11
+ 	{ ieee802_11_if_print,	DLT_IEEE802_11},
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_LTALK
+ 	{ ltalk_if_print,	DLT_LTALK },
+ #endif
+@@ -229,12 +236,14 @@ static struct printer printers[] = {
+ #ifdef DLT_IP_OVER_FC
+ 	{ ipfc_if_print,	DLT_IP_OVER_FC },
+ #endif
++#endif
+ #ifdef DLT_PRISM_HEADER
+ 	{ prism_if_print,	DLT_PRISM_HEADER },
+ #endif
+ #ifdef DLT_IEEE802_11_RADIO
+ 	{ ieee802_11_radio_if_print,	DLT_IEEE802_11_RADIO },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_ENC
+ 	{ enc_if_print,		DLT_ENC },
+ #endif
+@@ -244,9 +253,11 @@ static struct printer printers[] = {
+ #ifdef DLT_APPLE_IP_OVER_IEEE1394
+ 	{ ap1394_if_print,	DLT_APPLE_IP_OVER_IEEE1394 },
+ #endif
++#endif
+ #ifdef DLT_IEEE802_11_RADIO_AVS
+ 	{ ieee802_11_radio_avs_if_print,	DLT_IEEE802_11_RADIO_AVS },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_JUNIPER_ATM1
+ 	{ juniper_atm1_print,	DLT_JUNIPER_ATM1 },
+ #endif
+@@ -312,6 +323,7 @@ static struct printer printers[] = {
+ #ifdef DLT_IPV6
+ 	{ raw_if_print,		DLT_IPV6 },
+ #endif
++#endif
+ 	{ NULL,			0 },
+ };
+ 
+@@ -320,6 +332,7 @@ static struct ndo_printer ndo_printers[]
+ #ifdef DLT_IPNET
+ 	{ ipnet_if_print,	DLT_IPNET },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_IEEE802_15_4
+ 	{ ieee802_15_4_if_print, DLT_IEEE802_15_4 },
+ #endif
+@@ -329,15 +342,18 @@ static struct ndo_printer ndo_printers[]
+ #ifdef DLT_PPI
+ 	{ ppi_if_print,		DLT_PPI },
+ #endif
++#endif
+ #ifdef DLT_NETANALYZER
+ 	{ netanalyzer_if_print, DLT_NETANALYZER },
+ #endif
+ #ifdef DLT_NETANALYZER_TRANSPARENT
+ 	{ netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT },
+ #endif
++#ifndef TCPDUMP_MINI
+ #ifdef DLT_NFLOG
+ 	{ nflog_if_print,	DLT_NFLOG},
+ #endif
++#endif
+ 	{ NULL,			0 },
+ };
+ 
+--- a/print-sll.c
++++ b/print-sll.c
+@@ -154,14 +154,14 @@ recurse:
+ 		 * Yes - what type is it?
+ 		 */
+ 		switch (ether_type) {
+-
++#ifndef TCPDUMP_MINI
+ 		case LINUX_SLL_P_802_3:
+ 			/*
+ 			 * Ethernet_802.3 IPX frame.
+ 			 */
+ 			ipx_print(p, length);
+ 			break;
+-
++#endif
+ 		case LINUX_SLL_P_802_2:
+ 			/*
+ 			 * 802.2.
diff --git a/package/network/utils/umbim/Makefile b/package/network/utils/umbim/Makefile
new file mode 100644
index 0000000000..f494bb6b0e
--- /dev/null
+++ b/package/network/utils/umbim/Makefile
@@ -0,0 +1,46 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=umbim
+PKG_VERSION:=2015-07-04
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/umbim.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=29aaf43b097ee57f7aa1bb24341db6cc4148cbf3
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=bc0e7dd3dc388bddf7a9536bebe8672f275adf9523c2e0aa87cbc64ccd3e8e2f
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/umbim
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libubox +kmod-usb-net +kmod-usb-net-cdc-mbim +wwan
+  TITLE:=Control utility for mobile broadband modems
+endef
+
+define Package/umbim/description
+  umbim is a command line tool for controlling mobile broadband modems using
+  the MBIM-protocol.
+endef
+
+TARGET_CFLAGS += \
+	-I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
+
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+define Package/umbim/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/umbim $(1)/sbin/
+	$(CP) ./files/* $(1)/
+endef
+
+$(eval $(call BuildPackage,umbim))
diff --git a/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh b/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh
new file mode 100755
index 0000000000..9b5729a7ab
--- /dev/null
+++ b/package/network/utils/umbim/files/lib/netifd/proto/mbim.sh
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+#DBG=-v
+
+proto_mbim_init_config() {
+	available=1
+	no_device=1
+	proto_config_add_string "device:device"
+	proto_config_add_string apn
+	proto_config_add_string pincode
+	proto_config_add_string delay
+	proto_config_add_string auth
+	proto_config_add_string username
+	proto_config_add_string password
+	proto_config_add_defaults
+}
+
+_proto_mbim_setup() {
+	local interface="$1"
+	local tid=2
+	local ret
+
+	local device apn pincode delay $PROTO_DEFAULT_OPTIONS
+	json_get_vars device apn pincode delay auth username password $PROTO_DEFAULT_OPTIONS
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	[ -n "$device" ] || {
+		echo "mbim[$$]" "No control device specified"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+	[ -c "$device" ] || {
+		echo "mbim[$$]" "The specified control device does not exist"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	devname="$(basename "$device")"
+	devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
+	ifname="$( ls "$devpath"/net )"
+
+	[ -n "$ifname" ] || {
+		echo "mbim[$$]" "Failed to find matching interface"
+		proto_notify_error "$interface" NO_IFNAME
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	[ -n "$apn" ] || {
+		echo "mbim[$$]" "No APN specified"
+		proto_notify_error "$interface" NO_APN
+		return 1
+	}
+
+	[ -n "$delay" ] && sleep "$delay"
+
+	echo "mbim[$$]" "Reading capabilities"
+	umbim $DBG -n -d $device caps || {
+		echo "mbim[$$]" "Failed to read modem caps"
+		proto_notify_error "$interface" PIN_FAILED
+		return 1
+	}
+	tid=$((tid + 1))
+
+	[ "$pincode" ] && {
+		echo "mbim[$$]" "Sending pin"
+		umbim $DBG -n -t $tid -d $device unlock "$pincode" || {
+			echo "mbim[$$]" "Unable to verify PIN"
+			proto_notify_error "$interface" PIN_FAILED
+			proto_block_restart "$interface"
+			return 1
+		}
+	}
+	tid=$((tid + 1))
+
+	echo "mbim[$$]" "Checking pin"
+	umbim $DBG -n -t $tid -d $device pinstate || {
+		echo "mbim[$$]" "PIN required"
+		proto_notify_error "$interface" PIN_FAILED
+		proto_block_restart "$interface"
+		return 1
+	}
+	tid=$((tid + 1))
+
+	echo "mbim[$$]" "Checking subscriber"
+ 	umbim $DBG -n -t $tid -d $device subscriber || {
+		echo "mbim[$$]" "Subscriber init failed"
+		proto_notify_error "$interface" NO_SUBSCRIBER
+		return 1
+	}
+	tid=$((tid + 1))
+
+	echo "mbim[$$]" "Register with network"
+  	umbim $DBG -n -t $tid -d $device registration || {
+		echo "mbim[$$]" "Subscriber registration failed"
+		proto_notify_error "$interface" NO_REGISTRATION
+		return 1
+	}
+	tid=$((tid + 1))
+
+	echo "mbim[$$]" "Attach to network"
+   	umbim $DBG -n -t $tid -d $device attach || {
+		echo "mbim[$$]" "Failed to attach to network"
+		proto_notify_error "$interface" ATTACH_FAILED
+		return 1
+	}
+	tid=$((tid + 1))
+ 
+	echo "mbim[$$]" "Connect to network"
+	while ! umbim $DBG -n -t $tid -d $device connect "$apn" "$auth" "$username" "$password"; do
+		tid=$((tid + 1))
+		sleep 1;
+	done
+	tid=$((tid + 1))
+
+	uci_set_state network $interface tid "$tid"
+
+	echo "mbim[$$]" "Connected, starting DHCP"
+	proto_init_update "$ifname" 1
+	proto_send_update "$interface"
+
+	json_init
+	json_add_string name "${interface}_4"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcp"
+	proto_add_dynamic_defaults
+	json_close_object
+	ubus call network add_dynamic "$(json_dump)"
+
+	json_init
+	json_add_string name "${interface}_6"
+	json_add_string ifname "@$interface"
+	json_add_string proto "dhcpv6"
+	json_add_string extendprefix 1
+	proto_add_dynamic_defaults
+	ubus call network add_dynamic "$(json_dump)"
+}
+
+proto_mbim_setup() {
+	local ret
+
+	_proto_mbim_setup $@
+	ret=$?
+
+	[ "$ret" = 0 ] || {
+		logger "mbim bringup failed, retry in 15s"
+		sleep 15
+	}
+
+	return $rt
+}
+
+proto_mbim_teardown() {
+	local interface="$1"
+
+	local device
+	json_get_vars device
+	local tid=$(uci_get_state network $interface tid)
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	echo "mbim[$$]" "Stopping network"
+	[ -n "$tid" ] && {
+		umbim $DBG -t$tid -d "$device" disconnect
+		uci_revert_state network $interface tid
+	}
+
+	proto_init_update "*" 0
+	proto_send_update "$interface"
+}
+
+[ -n "$INCLUDE_ONLY" ] || add_protocol mbim
diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile
new file mode 100644
index 0000000000..06d9ac2b2b
--- /dev/null
+++ b/package/network/utils/uqmi/Makefile
@@ -0,0 +1,50 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uqmi
+PKG_VERSION:=2016-08-23
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/uqmi.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=eb1dec7d0dc283a7f61aa574a443a0ab61f8793f
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=e6273e6aee6fce419e13f84439c240d48c32020fce7f07b2dc123ae32742382c
+PKG_MAINTAINER:=Matti Laakso <malaakso@elisanet.fi>
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/uqmi
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=WWAN
+  DEPENDS:=+libubox +libblobmsg-json +kmod-usb-net +kmod-usb-net-qmi-wwan +wwan
+  TITLE:=Control utility for mobile broadband modems
+endef
+
+define Package/uqmi/description
+  uqmi is a command line tool for controlling mobile broadband modems using
+  the QMI-protocol.
+endef
+
+TARGET_CFLAGS += \
+	-I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
+
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+CMAKE_OPTIONS += \
+	-DDEBUG=1
+
+define Package/uqmi/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/uqmi $(1)/sbin/
+	$(CP) ./files/* $(1)/
+endef
+
+$(eval $(call BuildPackage,uqmi))
diff --git a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
new file mode 100755
index 0000000000..12356989a2
--- /dev/null
+++ b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh
@@ -0,0 +1,246 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+	. /lib/functions.sh
+	. ../netifd-proto.sh
+	init_proto "$@"
+}
+
+proto_qmi_init_config() {
+	available=1
+	no_device=1
+	proto_config_add_string "device:device"
+	proto_config_add_string apn
+	proto_config_add_string auth
+	proto_config_add_string username
+	proto_config_add_string password
+	proto_config_add_string pincode
+	proto_config_add_string delay
+	proto_config_add_string modes
+	proto_config_add_boolean ipv6
+	proto_config_add_boolean dhcp
+	proto_config_add_defaults
+}
+
+proto_qmi_setup() {
+	local interface="$1"
+
+	local device apn auth username password pincode delay modes ipv6 dhcp $PROTO_DEFAULT_OPTIONS
+	local cid_4 pdh_4 cid_6 pdh_6 ipv4
+	local ip subnet gateway dns1 dns2 ip_6 ip_prefix_length gateway_6 dns1_6 dns2_6
+	json_get_vars device apn auth username password pincode delay modes ipv6 dhcp $PROTO_DEFAULT_OPTIONS
+
+	ipv4=1
+
+	[ "$ipv6" = 1 ] || ipv6=""
+
+	[ "$metric" = "" ] && metric="0"
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	[ -n "$device" ] || {
+		echo "No control device specified"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+	[ -c "$device" ] || {
+		echo "The specified control device does not exist"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	devname="$(basename "$device")"
+	devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
+	ifname="$( ls "$devpath"/net )"
+	[ -n "$ifname" ] || {
+		echo "The interface could not be found."
+		proto_notify_error "$interface" NO_IFACE
+		proto_set_available "$interface" 0
+		return 1
+	}
+
+	[ -n "$delay" ] && sleep "$delay"
+
+	while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
+		sleep 1;
+	done
+
+	[ -n "$pincode" ] && {
+		uqmi -s -d "$device" --verify-pin1 "$pincode" || {
+			echo "Unable to verify PIN"
+			proto_notify_error "$interface" PIN_FAILED
+			proto_block_restart "$interface"
+			return 1
+		}
+	}
+
+	[ -n "$apn" ] || {
+		echo "No APN specified"
+		proto_notify_error "$interface" NO_APN
+		return 1
+	}
+
+	# try to clear previous autoconnect state
+	# do not reuse previous wds client id to prevent hangs caused by stale data
+	uqmi -s -d "$device" \
+		--stop-network 0xffffffff \
+		--autoconnect > /dev/null
+
+	uqmi -s -d "$device" --set-data-format 802.3
+	uqmi -s -d "$device" --wda-set-data-format 802.3
+
+	echo "Waiting for network registration"
+	while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do
+		sleep 5;
+	done
+
+	[ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes"
+
+	echo "Starting network $apn"
+
+	cid_4=`uqmi -s -d "$device" --get-client-id wds`
+	[ $? -ne 0 ] && {
+		echo "Unable to obtain client ID"
+		proto_notify_error "$interface" NO_CID
+		return 1
+	}
+
+	pdh_4=`uqmi -s -d "$device" --set-client-id wds,"$cid_4" \
+		--start-network "$apn" \
+		${auth:+--auth-type $auth} \
+		${username:+--username $username} \
+		${password:+--password $password} \
+		--ip-family ipv4 \
+		--autoconnect`
+	[ $? -ne 0 ] && {
+		echo "Unable to connect IPv4"
+		uqmi -s -d "$device" --set-client-id wds,"$cid_4" --release-client-id wds
+		ipv4=""
+	}
+
+	[ -n "$ipv6" ] && {
+		cid_6=`uqmi -s -d "$device" --get-client-id wds`
+		if [ $? = 0 ]; then
+			pdh_6=`uqmi -s -d "$device" --set-client-id wds,"$cid_6" \
+				--start-network "$apn" \
+				${auth:+--auth-type $auth} \
+				${username:+--username $username} \
+				${password:+--password $password} \
+				--ip-family ipv6 --autoconnect`
+			[ $? -ne 0 ] && {
+				echo "Unable to connect IPv6"
+				uqmi -s -d "$device" --set-client-id wds,"$cid_6" --release-client-id wds
+				ipv6=""
+			}
+		else
+			echo "Unable to connect IPv6"
+			ipv6=""
+		fi
+	}
+
+	[ -z "$ipv4" -a -z "$ipv6" ] && {
+		echo "Unable to connect"
+		proto_notify_error "$interface" CALL_FAILED
+		return 1
+	}
+
+	echo "Setting up $ifname"
+	proto_init_update "$ifname" 1
+	proto_add_data
+	[ -n "$ipv4" ] && {
+		json_add_string "cid_4" "$cid_4"
+		json_add_string "pdh_4" "$pdh_4"
+	}
+	[ -n "$ipv6" ] && {
+		json_add_string "cid_6" "$cid_6"
+		json_add_string "pdh_6" "$pdh_6"
+	}
+
+	[ -n "$ipv6" ] && {
+		if [ -z "$dhcp" -o "$dhcp" = 0 ]; then
+			json_load "$(uqmi -s -d $device --set-client-id wds,$cid_6 --get-current-settings)"
+			json_select ipv6
+			json_get_var ip_6 ip
+			json_get_var gateway_6 gateway
+			json_get_var dns1_6 dns1
+			json_get_var dns2_6 dns2
+			json_get_var ip_prefix_length ip-prefix-length
+
+			# RFC 7278: Extend an IPv6 /64 Prefix to LAN
+			proto_add_ipv6_address "$ip_6" "128"
+			proto_add_ipv6_prefix "${ip_6}/${ip_prefix_length}"
+			proto_add_ipv6_route "$gateway_6" "128"
+			[ "$defaultroute" = 0 ] || proto_add_ipv6_route "::0" 0 "$gateway_6" "" "" "${ip_6}/${ip_prefix_length}"
+			[ "$peerdns" = 0 ] || {
+				proto_add_dns_server "$dns1_6"
+				proto_add_dns_server "$dns2_6"
+			}
+			proto_add_data
+			json_add_string "cid_6" "$cid_6"
+			json_add_string "pdh_6" "$pdh_6"
+		else
+			json_init
+			json_add_string name "${interface}_6"
+			json_add_string ifname "@$interface"
+			json_add_string proto "dhcpv6"
+			proto_add_dynamic_defaults
+			# RFC 7278: Extend an IPv6 /64 Prefix to LAN
+			json_add_string extendprefix 1
+			json_close_object
+			ubus call network add_dynamic "$(json_dump)"
+		fi
+	}
+
+	proto_close_data
+	proto_send_update "$interface"
+
+	[ -n "$ipv4" ] && {
+		json_init
+		json_add_string name "${interface}_4"
+		json_add_string ifname "@$interface"
+		json_add_string proto "dhcp"
+		proto_add_dynamic_defaults
+		json_close_object
+		ubus call network add_dynamic "$(json_dump)"
+	}
+}
+
+qmi_wds_stop() {
+	local cid="$1"
+	local pdh="$2"
+
+	[ -n "$cid" ] || return
+
+	# disable previous autoconnect state using the global handle
+	uqmi -s -d "$device" --set-client-id wds,"$cid" --stop-network "0xffffffff"
+
+	[ -n "$pdh" ] && uqmi -s -d "$device" --set-client-id wds,"$cid" --stop-network "$pdh"
+	uqmi -s -d "$device" --set-client-id wds,"$cid" --release-client-id wds
+}
+
+proto_qmi_teardown() {
+	local interface="$1"
+
+	local device cid_4 pdh_4 cid_6 pdh_6
+	json_get_vars device
+
+	[ -n "$ctl_device" ] && device=$ctl_device
+
+	echo "Stopping network"
+
+	json_load "$(ubus call network.interface.$interface status)"
+	json_select data
+	json_get_vars cid_4 pdh_4 cid_6 pdh_6
+
+	qmi_wds_stop "$cid_4" "$pdh_4"
+	qmi_wds_stop "$cid_6" "$pdh_6"
+
+	proto_init_update "*" 0
+	proto_send_update "$interface"
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+	add_protocol qmi
+}
diff --git a/package/network/utils/wireless-tools/Makefile b/package/network/utils/wireless-tools/Makefile
new file mode 100644
index 0000000000..df7f6be9d6
--- /dev/null
+++ b/package/network/utils/wireless-tools/Makefile
@@ -0,0 +1,92 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wireless-tools
+PKG_VERSION:=29
+PKG_MINOR:=
+PKG_RELEASE:=5
+
+PKG_SOURCE:=wireless_tools.$(PKG_VERSION)$(PKG_MINOR).tar.gz
+PKG_SOURCE_URL:=http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux
+PKG_MD5SUM:=e06c222e186f7cc013fd272d023710cb
+TAR_OPTIONS += || true
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+PKG_LICENSE:=GPL-2.0
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/wireless_tools.$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/wireless-tools/Default
+  URL:=http://hplabs.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
+endef
+
+define Package/wireless-tools
+$(call Package/wireless-tools/Default)
+  SECTION:=net
+  CATEGORY:=Base system
+  TITLE:=Tools for manipulating Linux Wireless Extensions
+endef
+
+define Package/wireless-tools/description
+ This package contains a collection of tools for configuring wireless
+ adapters implementing the "Linux Wireless Extensions".
+endef
+
+define Package/libiw
+$(call Package/wireless-tools/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Library for manipulating Linux Wireless Extensions
+endef
+
+define Package/libiw/description
+ This package contains a library for manipulating
+ "Linux Wireless Extensions".
+endef
+
+define Build/Compile
+	rm -rf $(PKG_INSTALL_DIR)
+	mkdir -p $(PKG_INSTALL_DIR)
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		$(TARGET_CONFIGURE_OPTS) \
+		CFLAGS="$(TARGET_CFLAGS) -I." \
+		BUILD_WE_ESSENTIAL=y \
+		LIBS="-lm -Wl,--gc-sections" \
+		libiw.so.$(PKG_VERSION) iwmulticall
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		PREFIX="$(PKG_INSTALL_DIR)" \
+		INSTALL_DIR="$(PKG_INSTALL_DIR)/usr/sbin" \
+		INSTALL_LIB="$(PKG_INSTALL_DIR)/usr/lib" \
+		install-iwmulticall
+endef
+
+define Build/InstallDev
+	mkdir -p $(1)/usr/include
+	$(CP) $(PKG_BUILD_DIR)/{iwlib,wireless}.h $(1)/usr/include/
+	mkdir -p $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libiw.so* $(1)/usr/lib/
+	$(LN) libiw.so.$(PKG_VERSION) $(1)/usr/lib/libiw.so
+endef
+
+define Package/wireless-tools/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/iwconfig $(1)/usr/sbin/
+	$(LN) iwconfig $(1)/usr/sbin/iwlist
+	$(LN) iwconfig $(1)/usr/sbin/iwpriv
+endef
+
+define Package/libiw/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libiw.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,wireless-tools))
+$(eval $(call BuildPackage,libiw))
diff --git a/package/network/utils/wireless-tools/patches/001-debian.patch b/package/network/utils/wireless-tools/patches/001-debian.patch
new file mode 100644
index 0000000000..e00bad279b
--- /dev/null
+++ b/package/network/utils/wireless-tools/patches/001-debian.patch
@@ -0,0 +1,35 @@
+--- a/iwlib.c
++++ b/iwlib.c
+@@ -667,6 +667,7 @@ iw_get_basic_config(int			skfd,
+ {
+   struct iwreq		wrq;
+ 
++  memset((char *) &wrq, 0, sizeof(struct iwreq));
+   memset((char *) info, 0, sizeof(struct wireless_config));
+ 
+   /* Get wireless name */
+--- a/Makefile
++++ b/Makefile
+@@ -73,8 +73,8 @@ DYNAMIC_LINK= libiw.so
+ # Install directories
+ INSTALL_DIR= $(PREFIX)/sbin/
+ INSTALL_LIB= $(PREFIX)/lib/
+-INSTALL_INC= $(PREFIX)/include/
+-INSTALL_MAN= $(PREFIX)/man/
++INSTALL_INC= $(PREFIX)/usr/include/
++INSTALL_MAN= $(PREFIX)/usr/share/man/
+ 
+ # Various commands
+ RM = rm -f
+@@ -102,9 +102,9 @@ ifdef BUILD_WE_ESSENTIAL
+ endif
+ 
+ # Other flags
+-CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \
++#CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \
+ 	-Wpointer-arith -Wcast-qual -Winline -I.
+-#CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I.
++CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I.
+ DEPFLAGS=-MMD
+ XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG) $(WEDEF_FLAG)
+ PICFLAG=-fPIC
diff --git a/package/network/utils/wireless-tools/patches/002-fix-iwconfig-power-argument-parsing.patch b/package/network/utils/wireless-tools/patches/002-fix-iwconfig-power-argument-parsing.patch
new file mode 100644
index 0000000000..2b61ef291e
--- /dev/null
+++ b/package/network/utils/wireless-tools/patches/002-fix-iwconfig-power-argument-parsing.patch
@@ -0,0 +1,13 @@
+--- a/iwconfig.c
++++ b/iwconfig.c
+@@ -1034,8 +1034,8 @@ set_power_info(int		skfd,
+ 	wrq.u.power.disabled = 0;
+ 
+ 	/* Is there any value to grab ? */
+-	value = strtod(args[0], &unit);
+-	if(unit != args[0])
++	value = strtod(args[i], &unit);
++	if(unit != args[i])
+ 	  {
+ 	    struct iw_range	range;
+ 	    int			flags;
diff --git a/package/network/utils/wireless-tools/patches/003-we_essential_def.patch b/package/network/utils/wireless-tools/patches/003-we_essential_def.patch
new file mode 100644
index 0000000000..8666f3e80e
--- /dev/null
+++ b/package/network/utils/wireless-tools/patches/003-we_essential_def.patch
@@ -0,0 +1,359 @@
+--- a/iwlist.c
++++ b/iwlist.c
+@@ -58,7 +58,6 @@ typedef struct iw_auth_descr
+  * Maybe this should go in iwlib.c ?
+  */
+ 
+-#ifndef WE_ESSENTIAL
+ #define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
+ 
+ //static const struct iwmask_name iw_enc_mode_name[] = {
+@@ -161,11 +160,8 @@ static const char *	iw_ie_key_mgmt_name[
+ };
+ #define	IW_IE_KEY_MGMT_NUM	IW_ARRAY_LEN(iw_ie_key_mgmt_name)
+ 
+-#endif	/* WE_ESSENTIAL */
+-
+ /************************* WPA SUBROUTINES *************************/
+ 
+-#ifndef WE_ESSENTIAL
+ /*------------------------------------------------------------------*/
+ /*
+  * Print all names corresponding to a mask.
+@@ -431,7 +427,6 @@ iw_print_gen_ie(unsigned char *	buffer,
+       offset += buffer[offset+1] + 2;
+     }
+ }
+-#endif	/* WE_ESSENTIAL */
+ 
+ /***************************** SCANNING *****************************/
+ /*
+@@ -585,12 +580,10 @@ print_scanning_token(struct stream_descr
+ 		     &event->u.qual, iw_range, has_range);
+       printf("                    %s\n", buffer);
+       break;
+-#ifndef WE_ESSENTIAL
+     case IWEVGENIE:
+       /* Informations Elements are complex, let's do only some of them */
+       iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
+       break;
+-#endif	/* WE_ESSENTIAL */
+     case IWEVCUSTOM:
+       {
+ 	char custom[IW_CUSTOM_MAX+1];
+@@ -1302,7 +1295,6 @@ print_pm_info(int		skfd,
+   return(0);
+ }
+ 
+-#ifndef WE_ESSENTIAL
+ /************************** TRANSMIT POWER **************************/
+ 
+ /*------------------------------------------------------------------*/
+@@ -1405,6 +1397,7 @@ print_txpower_info(int		skfd,
+   return(0);
+ }
+ 
++#ifndef WE_ESSENTIAL
+ /*********************** RETRY LIMIT/LIFETIME ***********************/
+ 
+ /*------------------------------------------------------------------*/
+@@ -2060,8 +2053,8 @@ static const struct iwlist_entry iwlist_
+   { "encryption",	print_keys_info,	0, NULL },
+   { "keys",		print_keys_info,	0, NULL },
+   { "power",		print_pm_info,		0, NULL },
+-#ifndef WE_ESSENTIAL
+   { "txpower",		print_txpower_info,	0, NULL },
++#ifndef WE_ESSENTIAL
+   { "retry",		print_retry_info,	0, NULL },
+   { "ap",		print_ap_info,		0, NULL },
+   { "accesspoints",	print_ap_info,		0, NULL },
+--- a/iwconfig.c
++++ b/iwconfig.c
+@@ -106,16 +106,6 @@ get_info(int			skfd,
+     if(wrq.u.data.length > 1)
+       info->has_nickname = 1;
+ 
+-  if((info->has_range) && (info->range.we_version_compiled > 9))
+-    {
+-      /* Get Transmit Power */
+-      if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
+-	{
+-	  info->has_txpower = 1;
+-	  memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
+-	}
+-    }
+-
+   /* Get sensitivity */
+   if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
+     {
+@@ -132,6 +122,17 @@ get_info(int			skfd,
+ 	  memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
+ 	}
+     }
++#endif	/* WE_ESSENTIAL */
++
++  if((info->has_range) && (info->range.we_version_compiled > 9))
++    {
++      /* Get Transmit Power */
++      if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
++	{
++	  info->has_txpower = 1;
++	  memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
++	}
++    }
+ 
+   /* Get RTS threshold */
+   if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
+@@ -146,7 +147,6 @@ get_info(int			skfd,
+       info->has_frag = 1;
+       memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
+     }
+-#endif	/* WE_ESSENTIAL */
+ 
+   return(0);
+ }
+@@ -269,7 +269,6 @@ display_info(struct wireless_info *	info
+       printf("Bit Rate%c%s   ", (info->bitrate.fixed ? '=' : ':'), buffer);
+     }
+ 
+-#ifndef WE_ESSENTIAL
+   /* Display the Transmit Power */
+   if(info->has_txpower)
+     {
+@@ -286,6 +285,7 @@ display_info(struct wireless_info *	info
+       printf("Tx-Power%c%s   ", (info->txpower.fixed ? '=' : ':'), buffer);
+     }
+ 
++#ifndef WE_ESSENTIAL
+   /* Display sensitivity */
+   if(info->has_sens)
+     {
+@@ -340,6 +340,7 @@ display_info(struct wireless_info *	info
+       printf("   ");
+       tokens += 5;	/* Between 3 and 5, depend on flags */
+     }
++#endif	/* WE_ESSENTIAL */
+ 
+   /* Display the RTS threshold */
+   if(info->has_rts)
+@@ -383,7 +384,6 @@ display_info(struct wireless_info *	info
+   /* Formating */
+   if(tokens > 0)
+     printf("\n          ");
+-#endif	/* WE_ESSENTIAL */
+ 
+   /* Display encryption information */
+   /* Note : we display only the "current" key, use iwlist to list all keys */
+@@ -1196,6 +1196,7 @@ set_nwid_info(int		skfd,
+   /* 1 arg */
+   return(1);
+ }
++#endif	/* WE_ESSENTIAL */
+ 
+ /*------------------------------------------------------------------*/
+ /*
+@@ -1362,6 +1363,7 @@ set_txpower_info(int		skfd,
+   return(i);
+ }
+ 
++#ifndef WE_ESSENTIAL
+ /*------------------------------------------------------------------*/
+ /*
+  * Set Sensitivity
+@@ -1459,6 +1461,7 @@ set_retry_info(int		skfd,
+   /* Var args */
+   return(i);
+ }
++#endif	/* WE_ESSENTIAL */
+ 
+ /*------------------------------------------------------------------*/
+ /*
+@@ -1565,6 +1568,7 @@ set_frag_info(int		skfd,
+   return(1);
+ }
+ 
++#ifndef WE_ESSENTIAL
+ /*------------------------------------------------------------------*/
+ /*
+  * Set Modulation
+@@ -1719,21 +1723,21 @@ static const struct iwconfig_entry iwcon
+ 	"Set Nickname",			"NNN" },
+   { "nwid",		set_nwid_info,		1,	SIOCSIWNWID,
+ 	"Set NWID",			"{NN|on|off}" },
+-  { "ap",		set_apaddr_info,	1,	SIOCSIWAP,
+-	"Set AP Address",		"{N|off|auto}" },
+-  { "txpower",		set_txpower_info,	1,	SIOCSIWTXPOW,
+-	"Set Tx Power",			"{NmW|NdBm|off|auto}" },
+   { "sens",		set_sens_info,		1,	SIOCSIWSENS,
+ 	"Set Sensitivity",		"N" },
++  { "modulation",	set_modulation_info,	1,	SIOCGIWMODUL,
++	"Set Modulation",		"{11g|11a|CCK|OFDMg|...}" },
+   { "retry",		set_retry_info,		1,	SIOCSIWRETRY,
+ 	"Set Retry Limit",		"{limit N|lifetime N}" },
++#endif	/* WE_ESSENTIAL */
++  { "ap",		set_apaddr_info,	1,	SIOCSIWAP,
++	"Set AP Address",		"{N|off|auto}" },
++  { "txpower",		set_txpower_info,	1,	SIOCSIWTXPOW,
++	"Set Tx Power",			"{NmW|NdBm|off|auto}" },
+   { "rts",		set_rts_info,		1,	SIOCSIWRTS,
+ 	"Set RTS Threshold",		"{N|auto|fixed|off}" },
+   { "frag",		set_frag_info,		1,	SIOCSIWFRAG,
+ 	"Set Fragmentation Threshold",	"{N|auto|fixed|off}" },
+-  { "modulation",	set_modulation_info,	1,	SIOCGIWMODUL,
+-	"Set Modulation",		"{11g|11a|CCK|OFDMg|...}" },
+-#endif	/* WE_ESSENTIAL */
+   { "commit",		set_commit_info,	0,	SIOCSIWCOMMIT,
+ 	"Commit changes",		"" },
+   { NULL, NULL, 0, 0, NULL, NULL },
+--- a/iwmulticall.c
++++ b/iwmulticall.c
+@@ -81,7 +81,7 @@ extern int
+ #define main(args...) main_iwspy(args)
+ #include "iwspy.c"
+ #undef main
+-#endif	/* WE_ESSENTIAL */
++#endif
+ 
+ /* Get iwpriv in there. Mandatory for HostAP and some other drivers. */
+ #define main(args...) main_iwpriv(args)
+@@ -90,12 +90,14 @@ extern int
+ #undef iw_usage
+ #undef main
+ 
++#ifndef WE_ESSENTIAL
+ /* Do we really need iwgetid ? Well, it's not like it's a big one */
+ #define main(args...) main_iwgetid(args)
+ #define iw_usage(args...) iwgetid_usage(args)
+ #include "iwgetid.c"
+ #undef iw_usage
+ #undef main
++#endif
+ 
+ /* iwevent is useless for most people, don't grab it ? */
+ 
+@@ -131,11 +133,13 @@ main(int	argc,
+ #ifndef WE_ESSENTIAL
+   if(!strcmp(call_name, "iwspy"))
+     return(main_iwspy(argc, argv));
+-#endif	/* WE_ESSENTIAL */
++#endif
+   if(!strcmp(call_name, "iwpriv"))
+     return(main_iwpriv(argc, argv));
++#ifndef WE_ESSENTIAL
+   if(!strcmp(call_name, "iwgetid"))
+     return(main_iwgetid(argc, argv));
++#endif
+ 
+   /* Uh oh... Not supposed to come here. */
+   printf("iwmulticall : you are not supposed to call me this way...\n");
+--- a/iwlib.c
++++ b/iwlib.c
+@@ -113,6 +113,7 @@ const struct iw_modul_descr	iw_modul_lis
+   { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
+   { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
+ 
++#ifndef WE_ESSENTIAL
+   /* Proprietary aggregates */
+   { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
+     "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
+@@ -120,6 +121,7 @@ const struct iw_modul_descr	iw_modul_lis
+     "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
+   { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
+     "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
++#endif
+ 
+   /* Individual modulations */
+   { IW_MODUL_OFDM_G, "OFDMg",
+@@ -129,6 +131,7 @@ const struct iw_modul_descr	iw_modul_lis
+   { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
+   { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
+ 
++#ifndef WE_ESSENTIAL
+   /* Proprietary modulations */
+   { IW_MODUL_TURBO, "turbo",
+     "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
+@@ -136,6 +139,7 @@ const struct iw_modul_descr	iw_modul_lis
+     "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
+   { IW_MODUL_CUSTOM, "custom",
+     "Driver specific modulation (check driver documentation)" },
++#endif
+ };
+ 
+ /* Disable runtime version warning in iw_get_range_info() */
+@@ -440,6 +444,7 @@ iw_print_version_info(const char *	tooln
+       return -1;
+     }
+ 
++#ifndef WE_ESSENTIAL
+   /* Information about the tools themselves */
+   if(toolname != NULL)
+     printf("%-8.16s  Wireless-Tools version %d\n", toolname, WT_VERSION);
+@@ -452,6 +457,7 @@ iw_print_version_info(const char *	tooln
+   if(we_kernel_version > 15)
+     printf("Kernel    Currently compiled with Wireless Extension v%d.\n\n",
+ 	   we_kernel_version);
++#endif
+ 
+   /* Version for each device */
+   iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
+@@ -501,6 +507,7 @@ iw_get_range_info(int		skfd,
+       /* Copy stuff at the right place, ignore extra */
+       memcpy((char *) range, buffer, sizeof(iwrange));
+     }
++#ifndef WE_ESSENTIAL
+   else
+     {
+       /* Zero unknown fields */
+@@ -574,6 +581,7 @@ iw_get_range_info(int		skfd,
+        * If the driver source has not been updated to the latest, it doesn't
+        * matter because the new fields are set to zero */
+     }
++#endif
+ 
+   /* Don't complain twice.
+    * In theory, the test apply to each individual driver, but usually
+@@ -1542,6 +1550,7 @@ iw_print_key(char *			buffer,
+     }
+ }
+ 
++#ifndef WE_ESSENTIAL
+ /*------------------------------------------------------------------*/
+ /*
+  * Convert a passphrase into a key
+@@ -1556,6 +1565,7 @@ iw_pass_key(const char *	input,
+   fprintf(stderr, "Error: Passphrase not implemented\n");
+   return(-1);
+ }
++#endif
+ 
+ /*------------------------------------------------------------------*/
+ /*
+@@ -1578,12 +1588,14 @@ iw_in_key(const char *		input,
+ 	keylen = IW_ENCODING_TOKEN_MAX;
+       memcpy(key, input + 2, keylen);
+     }
++#ifndef WE_ESSENTIAL
+   else
+     if(!strncmp(input, "p:", 2))
+       {
+ 	/* Second case : as a passphrase (PrismII cards) */
+ 	return(iw_pass_key(input + 2, key));		/* skip "p:" */
+       }
++#endif
+     else
+       {
+ 	const char *	p;
+--- a/Makefile
++++ b/Makefile
+@@ -195,9 +195,9 @@ install-iwmulticall:: iwmulticall
+ 	install -m 755 $< $(INSTALL_DIR)/iwconfig
+ 	( cd $(INSTALL_DIR) ; \
+ 	  ln -f -s iwconfig iwlist ; \
+-	  ln -f -s iwconfig iwspy ; \
++	  $(if $(BUILD_WE_ESSENTIAL),,ln -f -s iwconfig iwspy ;) \
+ 	  ln -f -s iwconfig iwpriv ; \
+-	  ln -f -s iwconfig iwgetid )
++	  $(if $(BUILD_WE_ESSENTIAL),,ln -f -s iwconfig iwgetid ) )
+ 
+ clean::
+ 	$(RM_CMD) 
diff --git a/package/network/utils/wireless-tools/patches/004-increase_iwlist_buffer.patch b/package/network/utils/wireless-tools/patches/004-increase_iwlist_buffer.patch
new file mode 100644
index 0000000000..f2fdb124e6
--- /dev/null
+++ b/package/network/utils/wireless-tools/patches/004-increase_iwlist_buffer.patch
@@ -0,0 +1,46 @@
+--- a/iwlist.c
++++ b/iwlist.c
+@@ -792,7 +792,8 @@ print_scanning_info(int		skfd,
+ 	  if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
+ 	    {
+ 	      /* Check if buffer was too small (WE-17 only) */
+-	      if((errno == E2BIG) && (range.we_version_compiled > 16))
++	      if((errno == E2BIG) && (range.we_version_compiled > 16)
++	         && (buflen < 0xFFFF))
+ 		{
+ 		  /* Some driver may return very large scan results, either
+ 		   * because there are many cells, or because they have many
+@@ -808,6 +809,10 @@ print_scanning_info(int		skfd,
+ 		  else
+ 		    buflen *= 2;
+ 
++                 /* wrq.u.data.length is 16 bits so max size is 65535 */
++                 if(buflen > 0xFFFF)
++                   buflen = 0xFFFF;
++
+ 		  /* Try again */
+ 		  goto realloc;
+ 		}
+@@ -2152,6 +2157,7 @@ main(int	argc,
+   char **args;			/* Command arguments */
+   int count;			/* Number of arguments */
+   const iwlist_cmd *iwcmd;
++  int goterr = 0;
+ 
+   if(argc < 2)
+     iw_usage(1);
+@@ -2199,12 +2205,12 @@ main(int	argc,
+ 
+   /* do the actual work */
+   if (dev)
+-    (*iwcmd->fn)(skfd, dev, args, count);
++    goterr = (*iwcmd->fn)(skfd, dev, args, count);
+   else
+     iw_enum_devices(skfd, iwcmd->fn, args, count);
+ 
+   /* Close the socket. */
+   iw_sockets_close(skfd);
+ 
+-  return 0;
++  return goterr;
+ }
diff --git a/package/network/utils/wpan-tools/Makefile b/package/network/utils/wpan-tools/Makefile
new file mode 100644
index 0000000000..857a693f01
--- /dev/null
+++ b/package/network/utils/wpan-tools/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wpan-tools
+PKG_VERSION:=0.7
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://wpan.cakelab.org/releases/
+PKG_MD5SUM:=c16de9d7861c2d9b6a4436a0fac730f9f545ee290b92bc770c538ec6a3f22309
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/wpan-tools
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=cfg802154 interface configuration utility
+  URL:=http://wpan.cakelab.org/
+  DEPENDS:= +libnl
+endef
+
+define Build/Configure
+  $(call Build/Configure/Default)
+endef
+
+define Package/wpan-tools/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/iwpan $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,wpan-tools))
diff --git a/package/network/utils/wwan/Makefile b/package/network/utils/wwan/Makefile
new file mode 100644
index 0000000000..8ce9fd224c
--- /dev/null
+++ b/package/network/utils/wwan/Makefile
@@ -0,0 +1,45 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wwan
+PKG_VERSION:=2014-07-17
+PKG_RELEASE=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/wwan
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=Generic OpenWrt 3G/4G proto handler
+endef
+
+define Build/Compile
+	true
+endef
+
+define Package/wwan/install
+	$(INSTALL_DIR) $(1)/lib/netifd/proto/
+	$(CP) ./files/wwan.sh $(1)/lib/netifd/proto/
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/usb
+	$(INSTALL_BIN) ./files/wwan.usb $(1)/etc/hotplug.d/usb/00_wwan.sh
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/usbmisc
+	$(INSTALL_BIN) ./files/wwan.usbmisc $(1)/etc/hotplug.d/usbmisc/00_wwan.sh
+	$(INSTALL_DIR) $(1)/lib/network/wwan/
+	$(INSTALL_DATA) ./files/data/* $(1)/lib/network/wwan/
+	#in order to keep the Lede GIT repo free of filenames with colons,
+	#we name the files xxxx-yyyy
+	# and rename here after copying to the build directory
+	shopt -s nullglob ; \
+	for filevar in $(1)/lib/network/wwan/*-* ; \
+	do \
+		FILENAME=$$$$(basename $$$$filevar) ; \
+		NEWNAME=$$$${FILENAME//-/:} ; \
+		mv "$(1)/lib/network/wwan/$$$$FILENAME" "$(1)/lib/network/wwan/$$$$NEWNAME" ; \
+	done
+endef
+
+$(eval $(call BuildPackage,wwan))
diff --git a/package/network/utils/wwan/files/data/0421-03a7 b/package/network/utils/wwan/files/data/0421-03a7
new file mode 100644
index 0000000000..1313401353
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-03a7
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia C5-00 Mobile phone",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-060d b/package/network/utils/wwan/files/data/0421-060d
new file mode 100644
index 0000000000..a9ad650d6b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-060d
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-10",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-060e b/package/network/utils/wwan/files/data/0421-060e
new file mode 100644
index 0000000000..a9ad650d6b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-060e
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-10",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-0612 b/package/network/utils/wwan/files/data/0421-0612
new file mode 100644
index 0000000000..bc3e780ba9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-0612
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-15/CS-18",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-0619 b/package/network/utils/wwan/files/data/0421-0619
new file mode 100644
index 0000000000..52fbf58416
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-0619
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-12",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-061e b/package/network/utils/wwan/files/data/0421-061e
new file mode 100644
index 0000000000..c1cb9f44d4
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-061e
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-11",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-0623 b/package/network/utils/wwan/files/data/0421-0623
new file mode 100644
index 0000000000..f6674bac6a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-0623
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-17",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-0629 b/package/network/utils/wwan/files/data/0421-0629
new file mode 100644
index 0000000000..b637c344b4
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-0629
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-18",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-062d b/package/network/utils/wwan/files/data/0421-062d
new file mode 100644
index 0000000000..a95192b8e5
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-062d
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-19",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-062f b/package/network/utils/wwan/files/data/0421-062f
new file mode 100644
index 0000000000..a95192b8e5
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-062f
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia CS-19",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0421-0638 b/package/network/utils/wwan/files/data/0421-0638
new file mode 100644
index 0000000000..5fa7d4983e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0421-0638
@@ -0,0 +1,6 @@
+{
+	"desc": "Nokia 21M-02",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/05c6-0016 b/package/network/utils/wwan/files/data/05c6-0016
new file mode 100644
index 0000000000..1a4a796b7c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/05c6-0016
@@ -0,0 +1,6 @@
+{
+	"desc": "iBall 3.5G Connect",
+	"control": 2,
+	"data": 2
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/05c6-0023 b/package/network/utils/wwan/files/data/05c6-0023
new file mode 100644
index 0000000000..ce288ed48f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/05c6-0023
@@ -0,0 +1,5 @@
+{
+	"desc": "Leoxsys LN-72V",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/05c6-00a0 b/package/network/utils/wwan/files/data/05c6-00a0
new file mode 100644
index 0000000000..0b9616025e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/05c6-00a0
@@ -0,0 +1,6 @@
+{
+	"desc": "Axesstel MV241",
+	"control": 2,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/05c6-6000 b/package/network/utils/wwan/files/data/05c6-6000
new file mode 100644
index 0000000000..e8863b9e15
--- /dev/null
+++ b/package/network/utils/wwan/files/data/05c6-6000
@@ -0,0 +1,5 @@
+{
+	"desc": "Siemens SG75",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/05c6-9000 b/package/network/utils/wwan/files/data/05c6-9000
new file mode 100644
index 0000000000..6a72f4ff9c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/05c6-9000
@@ -0,0 +1,5 @@
+{
+	"desc": "Generic Qualcomm",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/07d1-3e01 b/package/network/utils/wwan/files/data/07d1-3e01
new file mode 100644
index 0000000000..b1da177003
--- /dev/null
+++ b/package/network/utils/wwan/files/data/07d1-3e01
@@ -0,0 +1,5 @@
+{
+	"desc": "D-Link DWM-152",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/07d1-3e02 b/package/network/utils/wwan/files/data/07d1-3e02
new file mode 100644
index 0000000000..cd1eceed9e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/07d1-3e02
@@ -0,0 +1,5 @@
+{
+	"desc": "D-Link DWM-156",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/07d1-7e11 b/package/network/utils/wwan/files/data/07d1-7e11
new file mode 100644
index 0000000000..84705b7519
--- /dev/null
+++ b/package/network/utils/wwan/files/data/07d1-7e11
@@ -0,0 +1,6 @@
+{
+	"desc": "D-Link DWM-156",
+	"control": 1,
+	"data": 2
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/0af0-4005 b/package/network/utils/wwan/files/data/0af0-4005
new file mode 100644
index 0000000000..5ab6c127ae
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0af0-4005
@@ -0,0 +1,4 @@
+{
+	"desc": "Option GIO711",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0af0-6901 b/package/network/utils/wwan/files/data/0af0-6901
new file mode 100644
index 0000000000..06b26643de
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0af0-6901
@@ -0,0 +1,5 @@
+{
+	"desc": "Option GI0201",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/0af0-7201 b/package/network/utils/wwan/files/data/0af0-7201
new file mode 100644
index 0000000000..20b18b76cc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0af0-7201
@@ -0,0 +1,5 @@
+{
+	"desc": "Option GTM380",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/0af0-8120 b/package/network/utils/wwan/files/data/0af0-8120
new file mode 100644
index 0000000000..c378e7fa55
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0af0-8120
@@ -0,0 +1,4 @@
+{
+	"desc": "Option GTM681W",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0af0-9200 b/package/network/utils/wwan/files/data/0af0-9200
new file mode 100644
index 0000000000..7e55a3661d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0af0-9200
@@ -0,0 +1,5 @@
+{
+	"desc": "Option GTM671WFS",
+	"control": 2,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/0b3c-c000 b/package/network/utils/wwan/files/data/0b3c-c000
new file mode 100644
index 0000000000..b45bbf419b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c000
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 100",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0b3c-c001 b/package/network/utils/wwan/files/data/0b3c-c001
new file mode 100644
index 0000000000..74a03346be
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c001
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 120",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0b3c-c002 b/package/network/utils/wwan/files/data/0b3c-c002
new file mode 100644
index 0000000000..ed4f2fd38c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c002
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 140",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0b3c-c003 b/package/network/utils/wwan/files/data/0b3c-c003
new file mode 100644
index 0000000000..5b4ea480e3
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c003
@@ -0,0 +1,5 @@
+{
+	"desc": "Olivetti Olicard 145",
+	"control": 0,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/0b3c-c004 b/package/network/utils/wwan/files/data/0b3c-c004
new file mode 100644
index 0000000000..d819379042
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c004
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 155",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0b3c-c005 b/package/network/utils/wwan/files/data/0b3c-c005
new file mode 100644
index 0000000000..f3768c6d1b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c005
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 200",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0b3c-c00a b/package/network/utils/wwan/files/data/0b3c-c00a
new file mode 100644
index 0000000000..a2ba14ab1d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c00a
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 160",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0b3c-c00b b/package/network/utils/wwan/files/data/0b3c-c00b
new file mode 100644
index 0000000000..1c6edb1f6d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0b3c-c00b
@@ -0,0 +1,4 @@
+{
+	"desc": "Olivetti Olicard 500",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0bdb-1900 b/package/network/utils/wwan/files/data/0bdb-1900
new file mode 100644
index 0000000000..84a9a9b7b0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0bdb-1900
@@ -0,0 +1,6 @@
+{
+	"desc": "Ericsson F3507g",
+	"control": 4,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0bdb-1902 b/package/network/utils/wwan/files/data/0bdb-1902
new file mode 100644
index 0000000000..84a9a9b7b0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0bdb-1902
@@ -0,0 +1,6 @@
+{
+	"desc": "Ericsson F3507g",
+	"control": 4,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0bdb-190a b/package/network/utils/wwan/files/data/0bdb-190a
new file mode 100644
index 0000000000..2e826130b1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0bdb-190a
@@ -0,0 +1,6 @@
+{
+	"desc": "Ericsson F3307",
+	"control": 4,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0bdb-190d b/package/network/utils/wwan/files/data/0bdb-190d
new file mode 100644
index 0000000000..2f725eb720
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0bdb-190d
@@ -0,0 +1,6 @@
+{
+	"desc": "Ericsson F5521gw",
+	"control": 4,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0bdb-1910 b/package/network/utils/wwan/files/data/0bdb-1910
new file mode 100644
index 0000000000..2f725eb720
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0bdb-1910
@@ -0,0 +1,6 @@
+{
+	"desc": "Ericsson F5521gw",
+	"control": 4,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/0c88-17da b/package/network/utils/wwan/files/data/0c88-17da
new file mode 100644
index 0000000000..d5ca787a66
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0c88-17da
@@ -0,0 +1,5 @@
+{
+	"desc": "Kyocera KPC650",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/0c88-180a b/package/network/utils/wwan/files/data/0c88-180a
new file mode 100644
index 0000000000..a2bee34e56
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0c88-180a
@@ -0,0 +1,5 @@
+{
+	"desc": "Kyocera KPC680",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/0f3d-68a2 b/package/network/utils/wwan/files/data/0f3d-68a2
new file mode 100644
index 0000000000..f85a049cd1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0f3d-68a2
@@ -0,0 +1,4 @@
+{
+	"desc": "Sierra MC7700",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/0f3d-68aa b/package/network/utils/wwan/files/data/0f3d-68aa
new file mode 100644
index 0000000000..3a68c20648
--- /dev/null
+++ b/package/network/utils/wwan/files/data/0f3d-68aa
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra Wireless AC313U/320U/330U Direct IP",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1004-6124 b/package/network/utils/wwan/files/data/1004-6124
new file mode 100644
index 0000000000..471d8a5cf0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1004-6124
@@ -0,0 +1,6 @@
+{
+	"desc": "LG L-05A",
+	"control": 0,
+	"data": 2
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/1004-6141 b/package/network/utils/wwan/files/data/1004-6141
new file mode 100644
index 0000000000..840dc64cf2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1004-6141
@@ -0,0 +1,6 @@
+{
+	"desc": "LG LUU-2100TI",
+	"control": 0,
+	"data": 2
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/1004-6157 b/package/network/utils/wwan/files/data/1004-6157
new file mode 100644
index 0000000000..ec94956626
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1004-6157
@@ -0,0 +1,6 @@
+{
+	"desc": "LG LUU-2110TI",
+	"control": 0,
+	"data": 2
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/1004-618f b/package/network/utils/wwan/files/data/1004-618f
new file mode 100644
index 0000000000..df98b66be0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1004-618f
@@ -0,0 +1,5 @@
+{
+	"desc": "LG L-02C",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/106c-3711 b/package/network/utils/wwan/files/data/106c-3711
new file mode 100644
index 0000000000..4d22d4daa8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3711
@@ -0,0 +1,6 @@
+{
+	"desc": "PANTECH UM-150",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/106c-3714 b/package/network/utils/wwan/files/data/106c-3714
new file mode 100644
index 0000000000..5fa2a3a69c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3714
@@ -0,0 +1,6 @@
+{
+	"desc": "PANTECH UM-175",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/106c-3715 b/package/network/utils/wwan/files/data/106c-3715
new file mode 100644
index 0000000000..8cbe23dad0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3715
@@ -0,0 +1,6 @@
+{
+	"desc": "PANTECH UM-175AL",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/106c-3716 b/package/network/utils/wwan/files/data/106c-3716
new file mode 100644
index 0000000000..18bd074f9d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3716
@@ -0,0 +1,6 @@
+{
+	"desc": "PANTECH UM-190",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/106c-3717 b/package/network/utils/wwan/files/data/106c-3717
new file mode 100644
index 0000000000..e028a4b410
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3717
@@ -0,0 +1,6 @@
+{
+	"desc": "PANTECH UM-185C/UM185E",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/106c-3718 b/package/network/utils/wwan/files/data/106c-3718
new file mode 100644
index 0000000000..362f482be9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3718
@@ -0,0 +1,4 @@
+{
+	"desc": "PANTECH UML-290 4G Modem",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/106c-3721 b/package/network/utils/wwan/files/data/106c-3721
new file mode 100644
index 0000000000..ac61a0822a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/106c-3721
@@ -0,0 +1,4 @@
+{
+	"desc": "PANTECH P4200 4G Modem",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/1199-0017 b/package/network/utils/wwan/files/data/1199-0017
new file mode 100644
index 0000000000..a50654d7fe
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0017
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra EM5625",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0018 b/package/network/utils/wwan/files/data/1199-0018
new file mode 100644
index 0000000000..02d7494aec
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0018
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5720",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0019 b/package/network/utils/wwan/files/data/1199-0019
new file mode 100644
index 0000000000..4d6d4a9db6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0019
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC595U",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0020 b/package/network/utils/wwan/files/data/1199-0020
new file mode 100644
index 0000000000..3482db4d66
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0020
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5725",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0021 b/package/network/utils/wwan/files/data/1199-0021
new file mode 100644
index 0000000000..226c1b44dd
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0021
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC597E",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0022 b/package/network/utils/wwan/files/data/1199-0022
new file mode 100644
index 0000000000..dd089a37e4
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0022
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra EM5725",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0023 b/package/network/utils/wwan/files/data/1199-0023
new file mode 100644
index 0000000000..9c7e72b9b1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0023
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC597",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0024 b/package/network/utils/wwan/files/data/1199-0024
new file mode 100644
index 0000000000..425d4cccd2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0024
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5727 CDMA",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0025 b/package/network/utils/wwan/files/data/1199-0025
new file mode 100644
index 0000000000..002d6fb18f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0025
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC598",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0026 b/package/network/utils/wwan/files/data/1199-0026
new file mode 100644
index 0000000000..13998dee99
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0026
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra T11",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0027 b/package/network/utils/wwan/files/data/1199-0027
new file mode 100644
index 0000000000..af4824c9c5
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0027
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC402",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0028 b/package/network/utils/wwan/files/data/1199-0028
new file mode 100644
index 0000000000..34c896e41d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0028
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5728",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0112 b/package/network/utils/wwan/files/data/1199-0112
new file mode 100644
index 0000000000..083baeea5f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0112
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra CDMA 1xEVDO PC Card, AC580",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0120 b/package/network/utils/wwan/files/data/1199-0120
new file mode 100644
index 0000000000..4d6d4a9db6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0120
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC595U",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0218 b/package/network/utils/wwan/files/data/1199-0218
new file mode 100644
index 0000000000..02d7494aec
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0218
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5720",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0220 b/package/network/utils/wwan/files/data/1199-0220
new file mode 100644
index 0000000000..3482db4d66
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0220
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5725",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0224 b/package/network/utils/wwan/files/data/1199-0224
new file mode 100644
index 0000000000..a57e54a647
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0224
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC5727",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-0301 b/package/network/utils/wwan/files/data/1199-0301
new file mode 100644
index 0000000000..13fd7da9f2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-0301
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC250U",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6802 b/package/network/utils/wwan/files/data/1199-6802
new file mode 100644
index 0000000000..d9bd29f956
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6802
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8755",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6803 b/package/network/utils/wwan/files/data/1199-6803
new file mode 100644
index 0000000000..c694fa3e12
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6803
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8765",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6804 b/package/network/utils/wwan/files/data/1199-6804
new file mode 100644
index 0000000000..d9bd29f956
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6804
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8755",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6805 b/package/network/utils/wwan/files/data/1199-6805
new file mode 100644
index 0000000000..c694fa3e12
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6805
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8765",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6808 b/package/network/utils/wwan/files/data/1199-6808
new file mode 100644
index 0000000000..d9bd29f956
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6808
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8755",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6809 b/package/network/utils/wwan/files/data/1199-6809
new file mode 100644
index 0000000000..d9bd29f956
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6809
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8755",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6813 b/package/network/utils/wwan/files/data/1199-6813
new file mode 100644
index 0000000000..f10c10449a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6813
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8775",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6815 b/package/network/utils/wwan/files/data/1199-6815
new file mode 100644
index 0000000000..f10c10449a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6815
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8775",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6816 b/package/network/utils/wwan/files/data/1199-6816
new file mode 100644
index 0000000000..f10c10449a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6816
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8775",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6820 b/package/network/utils/wwan/files/data/1199-6820
new file mode 100644
index 0000000000..ce52c8f2ae
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6820
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC875",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6821 b/package/network/utils/wwan/files/data/1199-6821
new file mode 100644
index 0000000000..3ebd0be113
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6821
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC875U",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6822 b/package/network/utils/wwan/files/data/1199-6822
new file mode 100644
index 0000000000..35ee919cc7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6822
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC875E",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6833 b/package/network/utils/wwan/files/data/1199-6833
new file mode 100644
index 0000000000..0fcd10e93a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6833
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8781",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6834 b/package/network/utils/wwan/files/data/1199-6834
new file mode 100644
index 0000000000..0b9eadf708
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6834
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8780",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6835 b/package/network/utils/wwan/files/data/1199-6835
new file mode 100644
index 0000000000..0fcd10e93a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6835
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8781",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6838 b/package/network/utils/wwan/files/data/1199-6838
new file mode 100644
index 0000000000..0b9eadf708
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6838
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8780",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6839 b/package/network/utils/wwan/files/data/1199-6839
new file mode 100644
index 0000000000..0fcd10e93a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6839
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8781",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-683a b/package/network/utils/wwan/files/data/1199-683a
new file mode 100644
index 0000000000..02da610cf2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-683a
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8785",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-683b b/package/network/utils/wwan/files/data/1199-683b
new file mode 100644
index 0000000000..0f2a133cf2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-683b
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra MC8785 Composite",
+	"control": 3,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6850 b/package/network/utils/wwan/files/data/1199-6850
new file mode 100644
index 0000000000..1989d0abc3
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6850
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC880",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6851 b/package/network/utils/wwan/files/data/1199-6851
new file mode 100644
index 0000000000..16d8ab4654
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6851
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC 881",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6852 b/package/network/utils/wwan/files/data/1199-6852
new file mode 100644
index 0000000000..65be37b7a1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6852
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC880E",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6853 b/package/network/utils/wwan/files/data/1199-6853
new file mode 100644
index 0000000000..a8aee6d9c4
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6853
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC881E",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6855 b/package/network/utils/wwan/files/data/1199-6855
new file mode 100644
index 0000000000..24eddc6f1e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6855
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC880U",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6856 b/package/network/utils/wwan/files/data/1199-6856
new file mode 100644
index 0000000000..415a80a153
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6856
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra ATT USB Connect 881",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6859 b/package/network/utils/wwan/files/data/1199-6859
new file mode 100644
index 0000000000..075cc6bcd1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6859
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC885E",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-685a b/package/network/utils/wwan/files/data/1199-685a
new file mode 100644
index 0000000000..075cc6bcd1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-685a
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC885E",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6880 b/package/network/utils/wwan/files/data/1199-6880
new file mode 100644
index 0000000000..e188c03774
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6880
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra C885",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6890 b/package/network/utils/wwan/files/data/1199-6890
new file mode 100644
index 0000000000..6d2f892a37
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6890
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra C888",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6891 b/package/network/utils/wwan/files/data/1199-6891
new file mode 100644
index 0000000000..fa866e2918
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6891
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra C22 and C33",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6892 b/package/network/utils/wwan/files/data/1199-6892
new file mode 100644
index 0000000000..99a2bd2d6d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6892
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra Compass HSPA",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1199-6893 b/package/network/utils/wwan/files/data/1199-6893
new file mode 100644
index 0000000000..16f4dfda4e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-6893
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra C889",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1199-68a2 b/package/network/utils/wwan/files/data/1199-68a2
new file mode 100644
index 0000000000..ac1b184583
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-68a2
@@ -0,0 +1,4 @@
+{
+	"desc": "Sierra MC7710",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/1199-68aa b/package/network/utils/wwan/files/data/1199-68aa
new file mode 100644
index 0000000000..7c5a9f2bae
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1199-68aa
@@ -0,0 +1,5 @@
+{
+	"desc": "Sierra AC320U/AC330U Direct IP",
+	"control": 3,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1035 b/package/network/utils/wwan/files/data/12d1-1035
new file mode 100644
index 0000000000..ad7025a1d3
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1035
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI U8110",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1404 b/package/network/utils/wwan/files/data/12d1-1404
new file mode 100644
index 0000000000..b186ad54e8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1404
@@ -0,0 +1,4 @@
+{
+	"desc": "HUAWEI UMG1831",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1406 b/package/network/utils/wwan/files/data/12d1-1406
new file mode 100644
index 0000000000..b1aa31783e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1406
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option newer modems",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-140b b/package/network/utils/wwan/files/data/12d1-140b
new file mode 100644
index 0000000000..cc99898ae8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-140b
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option EC1260 Wireless Data Modem HSD USB Card",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-140c b/package/network/utils/wwan/files/data/12d1-140c
new file mode 100644
index 0000000000..148d1d1a23
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-140c
@@ -0,0 +1,4 @@
+{
+	"desc": "HUAWEI/Option newer modems",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1412 b/package/network/utils/wwan/files/data/12d1-1412
new file mode 100644
index 0000000000..e6fb6cc7e0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1412
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option EC168",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-141b b/package/network/utils/wwan/files/data/12d1-141b
new file mode 100644
index 0000000000..b1aa31783e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-141b
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option newer modems",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1433 b/package/network/utils/wwan/files/data/12d1-1433
new file mode 100644
index 0000000000..c5d86cb152
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1433
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option E1756C",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1436 b/package/network/utils/wwan/files/data/12d1-1436
new file mode 100644
index 0000000000..7db8644b15
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1436
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option E1800",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1444 b/package/network/utils/wwan/files/data/12d1-1444
new file mode 100644
index 0000000000..500d775127
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1444
@@ -0,0 +1,5 @@
+{
+	"desc": "HUAWEI/Option E352-R1",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-144e b/package/network/utils/wwan/files/data/12d1-144e
new file mode 100644
index 0000000000..a704946aa0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-144e
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei K3806",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1464 b/package/network/utils/wwan/files/data/12d1-1464
new file mode 100644
index 0000000000..1b5397cd66
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1464
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei K4505",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1465 b/package/network/utils/wwan/files/data/12d1-1465
new file mode 100644
index 0000000000..dbb20f7cc8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1465
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei K3765",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1491 b/package/network/utils/wwan/files/data/12d1-1491
new file mode 100644
index 0000000000..c1ae9a5684
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1491
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei R201",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-14a5 b/package/network/utils/wwan/files/data/12d1-14a5
new file mode 100644
index 0000000000..50ea079579
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14a5
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-14a8 b/package/network/utils/wwan/files/data/12d1-14a8
new file mode 100644
index 0000000000..50ea079579
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14a8
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-14ac b/package/network/utils/wwan/files/data/12d1-14ac
new file mode 100644
index 0000000000..148d1d1a23
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14ac
@@ -0,0 +1,4 @@
+{
+	"desc": "HUAWEI/Option newer modems",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-14ae b/package/network/utils/wwan/files/data/12d1-14ae
new file mode 100644
index 0000000000..e27a798ff8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14ae
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei K3806",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-14c6 b/package/network/utils/wwan/files/data/12d1-14c6
new file mode 100644
index 0000000000..0cb4d8c100
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14c6
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K4605",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-14c8 b/package/network/utils/wwan/files/data/12d1-14c8
new file mode 100644
index 0000000000..958b118867
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14c8
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K5005",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-14c9 b/package/network/utils/wwan/files/data/12d1-14c9
new file mode 100644
index 0000000000..bc75791851
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14c9
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K3770",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-14ca b/package/network/utils/wwan/files/data/12d1-14ca
new file mode 100644
index 0000000000..8155b4bf0b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14ca
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K3771",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-14cb b/package/network/utils/wwan/files/data/12d1-14cb
new file mode 100644
index 0000000000..b496a60bc9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14cb
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei K4510",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-14cc b/package/network/utils/wwan/files/data/12d1-14cc
new file mode 100644
index 0000000000..98488bd261
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14cc
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K4511",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-14cf b/package/network/utils/wwan/files/data/12d1-14cf
new file mode 100644
index 0000000000..18e1e1e3a7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14cf
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei K3772",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-14d2 b/package/network/utils/wwan/files/data/12d1-14d2
new file mode 100644
index 0000000000..414b84673a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-14d2
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E173/E177",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1506 b/package/network/utils/wwan/files/data/12d1-1506
new file mode 100644
index 0000000000..65760e8f9a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1506
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E367/E398",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-150a b/package/network/utils/wwan/files/data/12d1-150a
new file mode 100644
index 0000000000..45f191a3a6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-150a
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E398",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-150c b/package/network/utils/wwan/files/data/12d1-150c
new file mode 100644
index 0000000000..7ab4c49938
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-150c
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E367",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-150f b/package/network/utils/wwan/files/data/12d1-150f
new file mode 100644
index 0000000000..7ab4c49938
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-150f
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E367",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-151b b/package/network/utils/wwan/files/data/12d1-151b
new file mode 100644
index 0000000000..28e561c8ec
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-151b
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E392u-12",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-151d b/package/network/utils/wwan/files/data/12d1-151d
new file mode 100644
index 0000000000..e5eae2a88b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-151d
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E3131",
+	"control": 3,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-156c b/package/network/utils/wwan/files/data/12d1-156c
new file mode 100644
index 0000000000..3fc6b1b13c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-156c
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E3276",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1576 b/package/network/utils/wwan/files/data/12d1-1576
new file mode 100644
index 0000000000..1aeb021c2f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1576
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K4201 composite",
+	"type": "mbim"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1577 b/package/network/utils/wwan/files/data/12d1-1577
new file mode 100644
index 0000000000..46a12dafe9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1577
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K4202 composite",
+	"type": "mbim"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1578 b/package/network/utils/wwan/files/data/12d1-1578
new file mode 100644
index 0000000000..6710d159eb
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1578
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K4606 composite",
+	"type": "mbim"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1589 b/package/network/utils/wwan/files/data/12d1-1589
new file mode 100644
index 0000000000..e2d352752f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1589
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E8278",
+	"type": "ncm"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1c05 b/package/network/utils/wwan/files/data/12d1-1c05
new file mode 100644
index 0000000000..c5612241bb
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c05
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173s",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1c07 b/package/network/utils/wwan/files/data/12d1-1c07
new file mode 100644
index 0000000000..cee727686b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c07
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E188",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1c08 b/package/network/utils/wwan/files/data/12d1-1c08
new file mode 100644
index 0000000000..4f6fb21fa6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c08
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173s",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1c10 b/package/network/utils/wwan/files/data/12d1-1c10
new file mode 100644
index 0000000000..50ea079579
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c10
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1c12 b/package/network/utils/wwan/files/data/12d1-1c12
new file mode 100644
index 0000000000..50ea079579
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c12
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1c1e b/package/network/utils/wwan/files/data/12d1-1c1e
new file mode 100644
index 0000000000..4622965a1a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c1e
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E586",
+	"type": "ncm"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1c1f b/package/network/utils/wwan/files/data/12d1-1c1f
new file mode 100644
index 0000000000..13cb40ffe7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c1f
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei E587",
+	"type": "ncm"
+}
diff --git a/package/network/utils/wwan/files/data/12d1-1c23 b/package/network/utils/wwan/files/data/12d1-1c23
new file mode 100644
index 0000000000..d1043471be
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1c23
@@ -0,0 +1,5 @@
+{
+	"desc": "Huawei E173",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/12d1-1f16 b/package/network/utils/wwan/files/data/12d1-1f16
new file mode 100644
index 0000000000..10d27cf5af
--- /dev/null
+++ b/package/network/utils/wwan/files/data/12d1-1f16
@@ -0,0 +1,4 @@
+{
+	"desc": "Huawei K5150 composite",
+	"mode": "mbim"
+}
diff --git a/package/network/utils/wwan/files/data/1410-1400 b/package/network/utils/wwan/files/data/1410-1400
new file mode 100644
index 0000000000..e2bda9674f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-1400
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel U730",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-1410 b/package/network/utils/wwan/files/data/1410-1410
new file mode 100644
index 0000000000..ba48aea923
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-1410
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel U740",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-1420 b/package/network/utils/wwan/files/data/1410-1420
new file mode 100644
index 0000000000..5cc96b695a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-1420
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel U870",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-1430 b/package/network/utils/wwan/files/data/1410-1430
new file mode 100644
index 0000000000..012f3ad9f9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-1430
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel XU870",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-1450 b/package/network/utils/wwan/files/data/1410-1450
new file mode 100644
index 0000000000..d1016773df
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-1450
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel X950D",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2100 b/package/network/utils/wwan/files/data/1410-2100
new file mode 100644
index 0000000000..a0328cf92b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2100
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel EV620",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2110 b/package/network/utils/wwan/files/data/1410-2110
new file mode 100644
index 0000000000..701bf42455
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2110
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel ES720",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2120 b/package/network/utils/wwan/files/data/1410-2120
new file mode 100644
index 0000000000..7ab3c9d782
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2120
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel E725",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2130 b/package/network/utils/wwan/files/data/1410-2130
new file mode 100644
index 0000000000..98006e20ec
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2130
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel ES620",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2400 b/package/network/utils/wwan/files/data/1410-2400
new file mode 100644
index 0000000000..cd9f290691
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2400
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel EU730",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2410 b/package/network/utils/wwan/files/data/1410-2410
new file mode 100644
index 0000000000..4635063b24
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2410
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel EU740",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-2420 b/package/network/utils/wwan/files/data/1410-2420
new file mode 100644
index 0000000000..340666c7ca
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-2420
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel EU870D",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-4100 b/package/network/utils/wwan/files/data/1410-4100
new file mode 100644
index 0000000000..260a2891ad
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-4100
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel MC727/U727",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-4400 b/package/network/utils/wwan/files/data/1410-4400
new file mode 100644
index 0000000000..838a7fbf9a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-4400
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel Ovation MC930D/MC950D",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-6000 b/package/network/utils/wwan/files/data/1410-6000
new file mode 100644
index 0000000000..a12716e4b7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-6000
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel USB760",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-6001 b/package/network/utils/wwan/files/data/1410-6001
new file mode 100644
index 0000000000..a12716e4b7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-6001
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel USB760",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-6002 b/package/network/utils/wwan/files/data/1410-6002
new file mode 100644
index 0000000000..fce8e9bfd6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-6002
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel USB760 3G",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-6010 b/package/network/utils/wwan/files/data/1410-6010
new file mode 100644
index 0000000000..d08c399a16
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-6010
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel MC780",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-7001 b/package/network/utils/wwan/files/data/1410-7001
new file mode 100644
index 0000000000..079c7d52c8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-7001
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel MiFi 2372",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-7003 b/package/network/utils/wwan/files/data/1410-7003
new file mode 100644
index 0000000000..079c7d52c8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-7003
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel MiFi 2372",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-7030 b/package/network/utils/wwan/files/data/1410-7030
new file mode 100644
index 0000000000..0fc402905d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-7030
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel USB998",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-7031 b/package/network/utils/wwan/files/data/1410-7031
new file mode 100644
index 0000000000..e1ba049c13
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-7031
@@ -0,0 +1,6 @@
+{
+	"desc": "Novatel USB679",
+	"control": 0,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1410-7041 b/package/network/utils/wwan/files/data/1410-7041
new file mode 100644
index 0000000000..03e8fcd509
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-7041
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel MF3470",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-7042 b/package/network/utils/wwan/files/data/1410-7042
new file mode 100644
index 0000000000..0bb9cdbd2b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-7042
@@ -0,0 +1,5 @@
+{
+	"desc": "Novatel Ovation MC545/MC547",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1410-9011 b/package/network/utils/wwan/files/data/1410-9011
new file mode 100644
index 0000000000..8247a97c0d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-9011
@@ -0,0 +1,4 @@
+{
+	"desc": "Novatel E371",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/1410-b001 b/package/network/utils/wwan/files/data/1410-b001
new file mode 100644
index 0000000000..3c13539a5f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1410-b001
@@ -0,0 +1,4 @@
+{
+	"desc": "Novatel MC551/USB551L",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/1529-3100 b/package/network/utils/wwan/files/data/1529-3100
new file mode 100644
index 0000000000..5e4fe34b5a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1529-3100
@@ -0,0 +1,6 @@
+{
+	"desc": "UBIQUAM U-100/105/200/300/520",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d5-6202 b/package/network/utils/wwan/files/data/16d5-6202
new file mode 100644
index 0000000000..1ba8a502b6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d5-6202
@@ -0,0 +1,5 @@
+{
+	"desc": "AnyData ADU-620UW",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/16d5-6501 b/package/network/utils/wwan/files/data/16d5-6501
new file mode 100644
index 0000000000..09207df3b3
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d5-6501
@@ -0,0 +1,5 @@
+{
+	"desc": "AnyData ADU-300A",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/16d5-6502 b/package/network/utils/wwan/files/data/16d5-6502
new file mode 100644
index 0000000000..4bdbf899ac
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d5-6502
@@ -0,0 +1,5 @@
+{
+	"desc": "AnyData ADU-500A",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/16d5-6603 b/package/network/utils/wwan/files/data/16d5-6603
new file mode 100644
index 0000000000..5c108a2d38
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d5-6603
@@ -0,0 +1,6 @@
+{
+	"desc": "AnyData ADU-890WH",
+	"control": 0,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d5-900d b/package/network/utils/wwan/files/data/16d5-900d
new file mode 100644
index 0000000000..b1c486988b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d5-900d
@@ -0,0 +1,6 @@
+{
+	"desc": "AnyData ADU-890WH",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-5141 b/package/network/utils/wwan/files/data/16d8-5141
new file mode 100644
index 0000000000..bda356fda0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-5141
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CNU-510",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-5533 b/package/network/utils/wwan/files/data/16d8-5533
new file mode 100644
index 0000000000..185d257d4e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-5533
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CNU-550",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-5543 b/package/network/utils/wwan/files/data/16d8-5543
new file mode 100644
index 0000000000..185d257d4e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-5543
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CNU-550",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-5553 b/package/network/utils/wwan/files/data/16d8-5553
new file mode 100644
index 0000000000..2403381d1a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-5553
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CDU-550",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6002 b/package/network/utils/wwan/files/data/16d8-6002
new file mode 100644
index 0000000000..715878c45c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6002
@@ -0,0 +1,5 @@
+{
+	"desc": "Franklin U300",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/16d8-6006 b/package/network/utils/wwan/files/data/16d8-6006
new file mode 100644
index 0000000000..bb8f87e0ce
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6006
@@ -0,0 +1,5 @@
+{
+	"desc": "Cmotech CGU-628",
+	"control": 0,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/16d8-6007 b/package/network/utils/wwan/files/data/16d8-6007
new file mode 100644
index 0000000000..a0ed8bcea4
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6007
@@ -0,0 +1,4 @@
+{
+	"desc": "Cmotech CHE-628S",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6008 b/package/network/utils/wwan/files/data/16d8-6008
new file mode 100644
index 0000000000..1afeb99d7c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6008
@@ -0,0 +1,4 @@
+{
+	"desc": "Franklin U301",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6522 b/package/network/utils/wwan/files/data/16d8-6522
new file mode 100644
index 0000000000..44343d002e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6522
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CDU-650",
+	"control": 2,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6523 b/package/network/utils/wwan/files/data/16d8-6523
new file mode 100644
index 0000000000..406566b9a0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6523
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CCU-650U",
+	"control": 2,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6532 b/package/network/utils/wwan/files/data/16d8-6532
new file mode 100644
index 0000000000..5b6a147ffc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6532
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CCU-650",
+	"control": 2,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6533 b/package/network/utils/wwan/files/data/16d8-6533
new file mode 100644
index 0000000000..07175f3180
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6533
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CNM-650",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-6543 b/package/network/utils/wwan/files/data/16d8-6543
new file mode 100644
index 0000000000..c518ca723d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-6543
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CNU-650",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/16d8-680a b/package/network/utils/wwan/files/data/16d8-680a
new file mode 100644
index 0000000000..9b1c85fe86
--- /dev/null
+++ b/package/network/utils/wwan/files/data/16d8-680a
@@ -0,0 +1,6 @@
+{
+	"desc": "Cmotech CDU-680",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0001 b/package/network/utils/wwan/files/data/19d2-0001
new file mode 100644
index 0000000000..31ee3fd329
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0001
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0002 b/package/network/utils/wwan/files/data/19d2-0002
new file mode 100644
index 0000000000..ee80af5fea
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0002
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE ET502HS/MT505UP/MF632",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0015 b/package/network/utils/wwan/files/data/19d2-0015
new file mode 100644
index 0000000000..31ee3fd329
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0015
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0016 b/package/network/utils/wwan/files/data/19d2-0016
new file mode 100644
index 0000000000..48c5fefd3a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0016
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MF110/ZTE",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0017 b/package/network/utils/wwan/files/data/19d2-0017
new file mode 100644
index 0000000000..87178fba5e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0017
@@ -0,0 +1,4 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0018 b/package/network/utils/wwan/files/data/19d2-0018
new file mode 100644
index 0000000000..76120d480e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0018
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MSA110UP/ZTE",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0019 b/package/network/utils/wwan/files/data/19d2-0019
new file mode 100644
index 0000000000..8d31ed7664
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0019
@@ -0,0 +1,4 @@
+{
+	"desc": "ONDA MT689DC/ZTE",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0022 b/package/network/utils/wwan/files/data/19d2-0022
new file mode 100644
index 0000000000..7ed8ed1ca1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0022
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE K2525",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0024 b/package/network/utils/wwan/files/data/19d2-0024
new file mode 100644
index 0000000000..5ae34af23e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0024
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MT503HSA",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0025 b/package/network/utils/wwan/files/data/19d2-0025
new file mode 100644
index 0000000000..68baeb778c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0025
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF628",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0031 b/package/network/utils/wwan/files/data/19d2-0031
new file mode 100644
index 0000000000..7aa8aa4b41
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0031
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF110/MF112/MF626",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0033 b/package/network/utils/wwan/files/data/19d2-0033
new file mode 100644
index 0000000000..e99314e34d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0033
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF636",
+	"control": 1,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0037 b/package/network/utils/wwan/files/data/19d2-0037
new file mode 100644
index 0000000000..8ee565d427
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0037
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"control": 2,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0039 b/package/network/utils/wwan/files/data/19d2-0039
new file mode 100644
index 0000000000..c80a51aefa
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0039
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF100",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0042 b/package/network/utils/wwan/files/data/19d2-0042
new file mode 100644
index 0000000000..c08014c5bc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0042
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF190",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0052 b/package/network/utils/wwan/files/data/19d2-0052
new file mode 100644
index 0000000000..87178fba5e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0052
@@ -0,0 +1,4 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0055 b/package/network/utils/wwan/files/data/19d2-0055
new file mode 100644
index 0000000000..87178fba5e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0055
@@ -0,0 +1,4 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0057 b/package/network/utils/wwan/files/data/19d2-0057
new file mode 100644
index 0000000000..7800746132
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0057
@@ -0,0 +1,5 @@
+{
+	"desc": "AIKO 83D",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0063 b/package/network/utils/wwan/files/data/19d2-0063
new file mode 100644
index 0000000000..f45825d049
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0063
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K3565-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0064 b/package/network/utils/wwan/files/data/19d2-0064
new file mode 100644
index 0000000000..edb0efef05
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0064
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF627",
+	"control": 0,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0066 b/package/network/utils/wwan/files/data/19d2-0066
new file mode 100644
index 0000000000..c57d7aec18
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0066
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF626",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0073 b/package/network/utils/wwan/files/data/19d2-0073
new file mode 100644
index 0000000000..0f9502f122
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0073
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE A580",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0079 b/package/network/utils/wwan/files/data/19d2-0079
new file mode 100644
index 0000000000..569a9996cc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0079
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE A353",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0082 b/package/network/utils/wwan/files/data/19d2-0082
new file mode 100644
index 0000000000..ea4fcd9459
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0082
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF668/MF190",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0086 b/package/network/utils/wwan/files/data/19d2-0086
new file mode 100644
index 0000000000..f25d77a60e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0086
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF645",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0091 b/package/network/utils/wwan/files/data/19d2-0091
new file mode 100644
index 0000000000..4e429a6329
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0091
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF636",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0094 b/package/network/utils/wwan/files/data/19d2-0094
new file mode 100644
index 0000000000..34a976ebae
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0094
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE AC581",
+	"control": 3,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0104 b/package/network/utils/wwan/files/data/19d2-0104
new file mode 100644
index 0000000000..0646b8d15a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0104
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K4505-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0108 b/package/network/utils/wwan/files/data/19d2-0108
new file mode 100644
index 0000000000..369d70f09d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0108
@@ -0,0 +1,5 @@
+{
+	"desc": "ONDA MT505UP/ZTE",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0116 b/package/network/utils/wwan/files/data/19d2-0116
new file mode 100644
index 0000000000..bfe9b5d44a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0116
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF651",
+	"control": 1,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0117 b/package/network/utils/wwan/files/data/19d2-0117
new file mode 100644
index 0000000000..8610bbf419
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0117
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF112",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0121 b/package/network/utils/wwan/files/data/19d2-0121
new file mode 100644
index 0000000000..da5b96c0c9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0121
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF637",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0124 b/package/network/utils/wwan/files/data/19d2-0124
new file mode 100644
index 0000000000..74b4f6fb01
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0124
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF110",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0128 b/package/network/utils/wwan/files/data/19d2-0128
new file mode 100644
index 0000000000..620eb90f05
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0128
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF651",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0142 b/package/network/utils/wwan/files/data/19d2-0142
new file mode 100644
index 0000000000..6d19e3e8dd
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0142
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF665C",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0143 b/package/network/utils/wwan/files/data/19d2-0143
new file mode 100644
index 0000000000..6885a9b2e1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0143
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF190B",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0152 b/package/network/utils/wwan/files/data/19d2-0152
new file mode 100644
index 0000000000..20047be7a9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0152
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE AC583",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-0157 b/package/network/utils/wwan/files/data/19d2-0157
new file mode 100644
index 0000000000..d7be7c4deb
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0157
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF683",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0167 b/package/network/utils/wwan/files/data/19d2-0167
new file mode 100644
index 0000000000..0eefdc12a3
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0167
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF820D",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0170 b/package/network/utils/wwan/files/data/19d2-0170
new file mode 100644
index 0000000000..d7d6f97a5b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0170
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE A371",
+	"control": 0,
+	"data": 1
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0199 b/package/network/utils/wwan/files/data/19d2-0199
new file mode 100644
index 0000000000..565afcf664
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0199
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF820S",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0257 b/package/network/utils/wwan/files/data/19d2-0257
new file mode 100644
index 0000000000..6e94316961
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0257
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF821",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0265 b/package/network/utils/wwan/files/data/19d2-0265
new file mode 100644
index 0000000000..284c6ed93e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0265
@@ -0,0 +1,4 @@
+{
+	"desc": "Onda MT8205/ZTE",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0284 b/package/network/utils/wwan/files/data/19d2-0284
new file mode 100644
index 0000000000..4fc3bbbcba
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0284
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF880",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-0326 b/package/network/utils/wwan/files/data/19d2-0326
new file mode 100644
index 0000000000..c854f2a68e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-0326
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF821D",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1003 b/package/network/utils/wwan/files/data/19d2-1003
new file mode 100644
index 0000000000..a7d0eb5aa1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1003
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE K3805-Z",
+	"control": 1,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1008 b/package/network/utils/wwan/files/data/19d2-1008
new file mode 100644
index 0000000000..d0b329ce7b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1008
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K3570-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1010 b/package/network/utils/wwan/files/data/19d2-1010
new file mode 100644
index 0000000000..fe294f0f55
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1010
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K3571-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1015 b/package/network/utils/wwan/files/data/19d2-1015
new file mode 100644
index 0000000000..a5eab00e93
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1015
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE K3806-Z",
+	"control": 1,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1018 b/package/network/utils/wwan/files/data/19d2-1018
new file mode 100644
index 0000000000..48add8f41f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1018
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K5006-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1172 b/package/network/utils/wwan/files/data/19d2-1172
new file mode 100644
index 0000000000..1b4c728f96
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1172
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE K4510-Z",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1173 b/package/network/utils/wwan/files/data/19d2-1173
new file mode 100644
index 0000000000..1b4c728f96
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1173
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE K4510-Z",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1176 b/package/network/utils/wwan/files/data/19d2-1176
new file mode 100644
index 0000000000..4bbd5b74ee
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1176
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K3770-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1177 b/package/network/utils/wwan/files/data/19d2-1177
new file mode 100644
index 0000000000..3d196af449
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1177
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE K3770-Z",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1181 b/package/network/utils/wwan/files/data/19d2-1181
new file mode 100644
index 0000000000..5ee7b2f208
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1181
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE K3772-Z",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1203 b/package/network/utils/wwan/files/data/19d2-1203
new file mode 100644
index 0000000000..4502531243
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1203
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF691",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1208 b/package/network/utils/wwan/files/data/19d2-1208
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1208
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1211 b/package/network/utils/wwan/files/data/19d2-1211
new file mode 100644
index 0000000000..0df58f0aed
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1211
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF195",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1212 b/package/network/utils/wwan/files/data/19d2-1212
new file mode 100644
index 0000000000..0df58f0aed
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1212
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF195",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1217 b/package/network/utils/wwan/files/data/19d2-1217
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1217
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1218 b/package/network/utils/wwan/files/data/19d2-1218
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1218
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1220 b/package/network/utils/wwan/files/data/19d2-1220
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1220
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1222 b/package/network/utils/wwan/files/data/19d2-1222
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1222
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1245 b/package/network/utils/wwan/files/data/19d2-1245
new file mode 100644
index 0000000000..c08014c5bc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1245
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF190",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1252 b/package/network/utils/wwan/files/data/19d2-1252
new file mode 100644
index 0000000000..768a43333c
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1252
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF669",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1254 b/package/network/utils/wwan/files/data/19d2-1254
new file mode 100644
index 0000000000..c08014c5bc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1254
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF190",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1256 b/package/network/utils/wwan/files/data/19d2-1256
new file mode 100644
index 0000000000..c08014c5bc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1256
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF190",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1270 b/package/network/utils/wwan/files/data/19d2-1270
new file mode 100644
index 0000000000..7ad57f0216
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1270
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF667",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1401 b/package/network/utils/wwan/files/data/19d2-1401
new file mode 100644
index 0000000000..730b6349d6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1401
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF60",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1402 b/package/network/utils/wwan/files/data/19d2-1402
new file mode 100644
index 0000000000..730b6349d6
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1402
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF60",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1426 b/package/network/utils/wwan/files/data/19d2-1426
new file mode 100644
index 0000000000..cb9337b495
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1426
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE MF91D",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1512 b/package/network/utils/wwan/files/data/19d2-1512
new file mode 100644
index 0000000000..7e4bbf7503
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1512
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MFxxx",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1515 b/package/network/utils/wwan/files/data/19d2-1515
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1515
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1518 b/package/network/utils/wwan/files/data/19d2-1518
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1518
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1519 b/package/network/utils/wwan/files/data/19d2-1519
new file mode 100644
index 0000000000..d8bc573a1f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1519
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF192",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1522 b/package/network/utils/wwan/files/data/19d2-1522
new file mode 100644
index 0000000000..4c926f0186
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1522
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF652",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1525 b/package/network/utils/wwan/files/data/19d2-1525
new file mode 100644
index 0000000000..7a37c432c8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1525
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF591",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1527 b/package/network/utils/wwan/files/data/19d2-1527
new file mode 100644
index 0000000000..6b46c73d76
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1527
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF196",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1537 b/package/network/utils/wwan/files/data/19d2-1537
new file mode 100644
index 0000000000..a62516407d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1537
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF190J",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1538 b/package/network/utils/wwan/files/data/19d2-1538
new file mode 100644
index 0000000000..a62516407d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1538
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF190J",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-1544 b/package/network/utils/wwan/files/data/19d2-1544
new file mode 100644
index 0000000000..a62516407d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-1544
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE MF190J",
+	"control": 0,
+	"data": 0
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-2002 b/package/network/utils/wwan/files/data/19d2-2002
new file mode 100644
index 0000000000..a049f19638
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-2002
@@ -0,0 +1,4 @@
+{
+	"desc": "ZTE K3765-Z",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/19d2-2003 b/package/network/utils/wwan/files/data/19d2-2003
new file mode 100644
index 0000000000..a2a0880862
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-2003
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MF180",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-ffdd b/package/network/utils/wwan/files/data/19d2-ffdd
new file mode 100644
index 0000000000..71d1050a93
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-ffdd
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE AC682",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-ffe4 b/package/network/utils/wwan/files/data/19d2-ffe4
new file mode 100644
index 0000000000..03a16bff54
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-ffe4
@@ -0,0 +1,6 @@
+{
+	"desc": "ZTE AC3781",
+	"control": 1,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/19d2-ffe9 b/package/network/utils/wwan/files/data/19d2-ffe9
new file mode 100644
index 0000000000..57531e26e7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-ffe9
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE AC2738",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-fff1 b/package/network/utils/wwan/files/data/19d2-fff1
new file mode 100644
index 0000000000..4347f288a2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-fff1
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE generic",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-fffb b/package/network/utils/wwan/files/data/19d2-fffb
new file mode 100644
index 0000000000..4ff616a0c0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-fffb
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MG880",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-fffc b/package/network/utils/wwan/files/data/19d2-fffc
new file mode 100644
index 0000000000..4ff616a0c0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-fffc
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MG880",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-fffd b/package/network/utils/wwan/files/data/19d2-fffd
new file mode 100644
index 0000000000..4ff616a0c0
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-fffd
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE MG880",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-fffe b/package/network/utils/wwan/files/data/19d2-fffe
new file mode 100644
index 0000000000..4e6004981a
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-fffe
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE AC8700",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/19d2-ffff b/package/network/utils/wwan/files/data/19d2-ffff
new file mode 100644
index 0000000000..747fa238d1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/19d2-ffff
@@ -0,0 +1,5 @@
+{
+	"desc": "ZTE AC8710",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-1002 b/package/network/utils/wwan/files/data/1a8d-1002
new file mode 100644
index 0000000000..93388be2fd
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-1002
@@ -0,0 +1,5 @@
+{
+	"desc": "Bandrich C-100/C-120",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-1003 b/package/network/utils/wwan/files/data/1a8d-1003
new file mode 100644
index 0000000000..93388be2fd
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-1003
@@ -0,0 +1,5 @@
+{
+	"desc": "Bandrich C-100/C-120",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-1007 b/package/network/utils/wwan/files/data/1a8d-1007
new file mode 100644
index 0000000000..f013968f94
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-1007
@@ -0,0 +1,5 @@
+{
+	"desc": "Bandrich C-270",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-1009 b/package/network/utils/wwan/files/data/1a8d-1009
new file mode 100644
index 0000000000..82e4bf03ab
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-1009
@@ -0,0 +1,5 @@
+{
+	"desc": "Bandrich C-170/C-180",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-100c b/package/network/utils/wwan/files/data/1a8d-100c
new file mode 100644
index 0000000000..1acb9eec5f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-100c
@@ -0,0 +1,5 @@
+{
+	"desc": "Bandrich C-320",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-100d b/package/network/utils/wwan/files/data/1a8d-100d
new file mode 100644
index 0000000000..67db2b46cc
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-100d
@@ -0,0 +1,5 @@
+{
+	"desc": "Bandrich C-508",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1a8d-2006 b/package/network/utils/wwan/files/data/1a8d-2006
new file mode 100644
index 0000000000..78f36cef18
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1a8d-2006
@@ -0,0 +1,6 @@
+{
+	"desc": "Bandrich C-33x",
+	"control": 0,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/1bbb-0000 b/package/network/utils/wwan/files/data/1bbb-0000
new file mode 100644
index 0000000000..0be73afa18
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-0000
@@ -0,0 +1,5 @@
+{
+	"desc": "Alcatel X060S/X070S/X080S/X200",
+	"control": 2,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1bbb-0012 b/package/network/utils/wwan/files/data/1bbb-0012
new file mode 100644
index 0000000000..3eecac0e52
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-0012
@@ -0,0 +1,6 @@
+{
+	"desc": "Alcatel X085C",
+	"control": 2,
+	"data": 2
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1bbb-0017 b/package/network/utils/wwan/files/data/1bbb-0017
new file mode 100644
index 0000000000..853c05c0b1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-0017
@@ -0,0 +1,5 @@
+{
+	"desc": "Alcatel X220L",
+	"control": 4,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1bbb-0052 b/package/network/utils/wwan/files/data/1bbb-0052
new file mode 100644
index 0000000000..853c05c0b1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-0052
@@ -0,0 +1,5 @@
+{
+	"desc": "Alcatel X220L",
+	"control": 4,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1bbb-00b7 b/package/network/utils/wwan/files/data/1bbb-00b7
new file mode 100644
index 0000000000..9eaffe6609
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-00b7
@@ -0,0 +1,5 @@
+{
+	"desc": "Alcatel X600",
+	"control": 0,
+	"data": 4
+}}
diff --git a/package/network/utils/wwan/files/data/1bbb-00ca b/package/network/utils/wwan/files/data/1bbb-00ca
new file mode 100644
index 0000000000..80d71fad54
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-00ca
@@ -0,0 +1,6 @@
+{
+	"desc": "Alcatel X080C",
+	"control": 0,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1bbb-011e b/package/network/utils/wwan/files/data/1bbb-011e
new file mode 100644
index 0000000000..160221ddaf
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-011e
@@ -0,0 +1,4 @@
+{
+	"desc": "Alcatel L100V,",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/1bbb-0203 b/package/network/utils/wwan/files/data/1bbb-0203
new file mode 100644
index 0000000000..2632a6320f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1bbb-0203
@@ -0,0 +1,4 @@
+{
+	"desc": "Alcatel L800Z,",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/1c9e-6060 b/package/network/utils/wwan/files/data/1c9e-6060
new file mode 100644
index 0000000000..6f77bb4b97
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-6060
@@ -0,0 +1,6 @@
+{
+	"desc": "Alcatel X020 & X030",
+	"control": 2,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1c9e-6061 b/package/network/utils/wwan/files/data/1c9e-6061
new file mode 100644
index 0000000000..6f77bb4b97
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-6061
@@ -0,0 +1,6 @@
+{
+	"desc": "Alcatel X020 & X030",
+	"control": 2,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1c9e-9000 b/package/network/utils/wwan/files/data/1c9e-9000
new file mode 100644
index 0000000000..39dcd776ea
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-9000
@@ -0,0 +1,6 @@
+{
+	"desc": "4G Systems XS Stick W14",
+	"control": 0,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1c9e-9603 b/package/network/utils/wwan/files/data/1c9e-9603
new file mode 100644
index 0000000000..fd3f099d1b
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-9603
@@ -0,0 +1,5 @@
+{
+	"desc": "4G Systems XS Stick W14",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1c9e-9605 b/package/network/utils/wwan/files/data/1c9e-9605
new file mode 100644
index 0000000000..c2992c16ea
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-9605
@@ -0,0 +1,5 @@
+{
+	"desc": "4G Systems XS Stick W14",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1c9e-9607 b/package/network/utils/wwan/files/data/1c9e-9607
new file mode 100644
index 0000000000..c2992c16ea
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-9607
@@ -0,0 +1,5 @@
+{
+	"desc": "4G Systems XS Stick W14",
+	"control": 1,
+	"data": 3
+}}
diff --git a/package/network/utils/wwan/files/data/1c9e-9801 b/package/network/utils/wwan/files/data/1c9e-9801
new file mode 100644
index 0000000000..40dcc76055
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-9801
@@ -0,0 +1,6 @@
+{
+	"desc": "4G Systems XS Stick W21",
+	"control": 2,
+	"data": 1
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1c9e-9900 b/package/network/utils/wwan/files/data/1c9e-9900
new file mode 100644
index 0000000000..42da3abaf1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1c9e-9900
@@ -0,0 +1,6 @@
+{
+	"desc": "Softbank C02LC",
+	"control": 1,
+	"data": 2
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/1e0e-9000 b/package/network/utils/wwan/files/data/1e0e-9000
new file mode 100644
index 0000000000..bdb159da1d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1e0e-9000
@@ -0,0 +1,5 @@
+{
+	"desc": "PROLink PHS100, Hyundai MB-810, A-Link 3GU",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1e0e-9100 b/package/network/utils/wwan/files/data/1e0e-9100
new file mode 100644
index 0000000000..d1b2dda7be
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1e0e-9100
@@ -0,0 +1,5 @@
+{
+	"desc": "PROLink PHS300, A-Link 3GU",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1e0e-9200 b/package/network/utils/wwan/files/data/1e0e-9200
new file mode 100644
index 0000000000..bdb159da1d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1e0e-9200
@@ -0,0 +1,5 @@
+{
+	"desc": "PROLink PHS100, Hyundai MB-810, A-Link 3GU",
+	"control": 1,
+	"data": 2
+}}
diff --git a/package/network/utils/wwan/files/data/1e0e-ce16 b/package/network/utils/wwan/files/data/1e0e-ce16
new file mode 100644
index 0000000000..93e0c3fa13
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1e0e-ce16
@@ -0,0 +1,5 @@
+{
+	"desc": "D-Link DWM-162-U5, Micromax MMX 300c",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/1e0e-cefe b/package/network/utils/wwan/files/data/1e0e-cefe
new file mode 100644
index 0000000000..ebc941dfb1
--- /dev/null
+++ b/package/network/utils/wwan/files/data/1e0e-cefe
@@ -0,0 +1,6 @@
+{
+	"desc": "D-Link DWM-162-U5, Micromax MMX 300c",
+	"control": 1,
+	"data": 2
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/2001-7d00 b/package/network/utils/wwan/files/data/2001-7d00
new file mode 100644
index 0000000000..b0cc479125
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2001-7d00
@@ -0,0 +1,6 @@
+{
+	"desc": "D-Link DWM-156 A6",
+	"control": 1,
+	"data": 0
+}	"generic": 1
+}
diff --git a/package/network/utils/wwan/files/data/2001-7d01 b/package/network/utils/wwan/files/data/2001-7d01
new file mode 100644
index 0000000000..ab8fd9ded7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2001-7d01
@@ -0,0 +1,5 @@
+{
+	"desc": "D-Link DWM-156 A7",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/2001-7d02 b/package/network/utils/wwan/files/data/2001-7d02
new file mode 100644
index 0000000000..ab8fd9ded7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2001-7d02
@@ -0,0 +1,5 @@
+{
+	"desc": "D-Link DWM-156 A7",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/2001-7d03 b/package/network/utils/wwan/files/data/2001-7d03
new file mode 100644
index 0000000000..ab8fd9ded7
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2001-7d03
@@ -0,0 +1,5 @@
+{
+	"desc": "D-Link DWM-156 A7",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/211f-6801 b/package/network/utils/wwan/files/data/211f-6801
new file mode 100644
index 0000000000..06cdddca9e
--- /dev/null
+++ b/package/network/utils/wwan/files/data/211f-6801
@@ -0,0 +1,5 @@
+{
+	"desc": "Celot K-3000/CT-650/CT-680",
+	"control": 2,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/2357-0201 b/package/network/utils/wwan/files/data/2357-0201
new file mode 100644
index 0000000000..7ad8690e62
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2357-0201
@@ -0,0 +1,4 @@
+{
+	"desc": "TP-Link MA180",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/2357-0202 b/package/network/utils/wwan/files/data/2357-0202
new file mode 100644
index 0000000000..7ad8690e62
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2357-0202
@@ -0,0 +1,4 @@
+{
+	"desc": "TP-Link MA180",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/2357-0203 b/package/network/utils/wwan/files/data/2357-0203
new file mode 100644
index 0000000000..7ad8690e62
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2357-0203
@@ -0,0 +1,4 @@
+{
+	"desc": "TP-Link MA180",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/2357-9000 b/package/network/utils/wwan/files/data/2357-9000
new file mode 100644
index 0000000000..0ddb804af3
--- /dev/null
+++ b/package/network/utils/wwan/files/data/2357-9000
@@ -0,0 +1,4 @@
+{
+	"desc": "TP-Link MA260",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/413c-8114 b/package/network/utils/wwan/files/data/413c-8114
new file mode 100644
index 0000000000..a3cb2cd743
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8114
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5700",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8115 b/package/network/utils/wwan/files/data/413c-8115
new file mode 100644
index 0000000000..af27cbe079
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8115
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5500",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8116 b/package/network/utils/wwan/files/data/413c-8116
new file mode 100644
index 0000000000..31b79bf98f
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8116
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5505",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8117 b/package/network/utils/wwan/files/data/413c-8117
new file mode 100644
index 0000000000..a3cb2cd743
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8117
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5700",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8118 b/package/network/utils/wwan/files/data/413c-8118
new file mode 100644
index 0000000000..b92d415141
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8118
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5510",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8128 b/package/network/utils/wwan/files/data/413c-8128
new file mode 100644
index 0000000000..a3cb2cd743
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8128
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5700",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8129 b/package/network/utils/wwan/files/data/413c-8129
new file mode 100644
index 0000000000..a3cb2cd743
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8129
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5700",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8133 b/package/network/utils/wwan/files/data/413c-8133
new file mode 100644
index 0000000000..4ae84020fe
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8133
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5720",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8134 b/package/network/utils/wwan/files/data/413c-8134
new file mode 100644
index 0000000000..4ae84020fe
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8134
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5720",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8135 b/package/network/utils/wwan/files/data/413c-8135
new file mode 100644
index 0000000000..4ae84020fe
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8135
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5720",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8136 b/package/network/utils/wwan/files/data/413c-8136
new file mode 100644
index 0000000000..d2bf508fe9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8136
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5520",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8137 b/package/network/utils/wwan/files/data/413c-8137
new file mode 100644
index 0000000000..d2bf508fe9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8137
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5520",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8138 b/package/network/utils/wwan/files/data/413c-8138
new file mode 100644
index 0000000000..d2bf508fe9
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8138
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5520",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8147 b/package/network/utils/wwan/files/data/413c-8147
new file mode 100644
index 0000000000..f0b0638fd5
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8147
@@ -0,0 +1,6 @@
+{
+	"desc": "Dell 5530",
+	"control": 0,
+	"data": 1
+}	"acm": 1
+}
diff --git a/package/network/utils/wwan/files/data/413c-8180 b/package/network/utils/wwan/files/data/413c-8180
new file mode 100644
index 0000000000..1ae44053c8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8180
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5730",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8181 b/package/network/utils/wwan/files/data/413c-8181
new file mode 100644
index 0000000000..1ae44053c8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8181
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5730",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8182 b/package/network/utils/wwan/files/data/413c-8182
new file mode 100644
index 0000000000..1ae44053c8
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8182
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5730",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/data/413c-8186 b/package/network/utils/wwan/files/data/413c-8186
new file mode 100644
index 0000000000..fa24099855
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8186
@@ -0,0 +1,4 @@
+{
+	"desc": "Dell 5620",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/413c-8194 b/package/network/utils/wwan/files/data/413c-8194
new file mode 100644
index 0000000000..b361f54db4
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8194
@@ -0,0 +1,4 @@
+{
+	"desc": "Dell 5630",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/413c-8195 b/package/network/utils/wwan/files/data/413c-8195
new file mode 100644
index 0000000000..45b78768ce
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8195
@@ -0,0 +1,4 @@
+{
+	"desc": "Dell 5800",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/413c-8196 b/package/network/utils/wwan/files/data/413c-8196
new file mode 100644
index 0000000000..cd2473036d
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-8196
@@ -0,0 +1,4 @@
+{
+	"desc": "Dell 5800v2",
+	"type": "qmi"
+}
diff --git a/package/network/utils/wwan/files/data/413c-819b b/package/network/utils/wwan/files/data/413c-819b
new file mode 100644
index 0000000000..e66c3fc4c2
--- /dev/null
+++ b/package/network/utils/wwan/files/data/413c-819b
@@ -0,0 +1,5 @@
+{
+	"desc": "Dell 5804",
+	"control": 1,
+	"data": 0
+}}
diff --git a/package/network/utils/wwan/files/wwan.sh b/package/network/utils/wwan/files/wwan.sh
new file mode 100755
index 0000000000..6b33600b32
--- /dev/null
+++ b/package/network/utils/wwan/files/wwan.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+. /lib/functions.sh
+. ../netifd-proto.sh
+init_proto "$@"
+
+INCLUDE_ONLY=1
+
+ctl_device=""
+dat_device=""
+
+proto_mbim_setup() { echo "wwan[$$] mbim proto is missing"; }
+proto_qmi_setup() { echo "wwan[$$] qmi proto is missing"; }
+proto_ncm_setup() { echo "wwan[$$] ncm proto is missing"; }
+proto_3g_setup() { echo "wwan[$$] 3g proto is missing"; }
+proto_directip_setup() { echo "wwan[$$] directip proto is missing"; }
+
+[ -f ./mbim.sh ] && . ./mbim.sh
+[ -f ./ncm.sh ] && . ./ncm.sh
+[ -f ./qmi.sh ] && . ./qmi.sh
+[ -f ./3g.sh ] && { . ./ppp.sh; . ./3g.sh; }
+[ -f ./directip.sh ] && . ./directip.sh
+
+proto_wwan_init_config() {
+	available=1
+	no_device=1
+
+	proto_config_add_string apn
+	proto_config_add_string auth
+	proto_config_add_string username
+	proto_config_add_string password
+	proto_config_add_string pincode
+	proto_config_add_string delay
+	proto_config_add_string modes
+}
+
+proto_wwan_setup() {
+	local driver usb devicename desc
+
+	for a in `ls /sys/bus/usb/devices`; do
+		local vendor product
+		[ -z "$usb" -a -f /sys/bus/usb/devices/$a/idVendor -a -f /sys/bus/usb/devices/$a/idProduct ] || continue
+		vendor=$(cat /sys/bus/usb/devices/$a/idVendor)
+		product=$(cat /sys/bus/usb/devices/$a/idProduct)
+		[ -f /lib/network/wwan/$vendor:$product ] && {
+			usb=/lib/network/wwan/$vendor:$product
+			devicename=$a
+		}
+	done
+
+	[ -n "$usb" ] && {
+		local old_cb control data
+
+		json_set_namespace wwan old_cb
+		json_init
+		json_load "$(cat $usb)"
+		json_select
+		json_get_vars desc control data
+		json_set_namespace $old_cb
+
+		[ -n "$control" -a -n "$data" ] && {
+			ttys=$(ls -d /sys/bus/usb/devices/$devicename/${devicename}*/tty* | sed "s/.*\///g" | tr "\n" " ")
+			ctl_device=/dev/$(echo $ttys | cut -d" " -f $((control + 1)))
+			dat_device=/dev/$(echo $ttys | cut -d" " -f $((data + 1)))
+			driver=comgt
+		}
+	}
+
+	[ -z "$ctl_device" ] && for net in $(ls /sys/class/net/ | grep wwan); do
+		[ -z "$ctl_device" ] || continue
+		driver=$(grep DRIVER /sys/class/net/$net/device/uevent | cut -d= -f2)
+		case "$driver" in
+		qmi_wwan|cdc_mbim)
+			ctl_device=/dev/$(ls /sys/class/net/$net/device/usbmisc)
+			;;
+		sierra_net|*cdc_ncm)
+			ctl_device=/dev/$(cd /sys/class/net/$net/; find ../../../ -name ttyUSB* |xargs basename | head -n1)
+			;;
+		*) continue;;
+		esac
+		echo "wwan[$$]" "Using proto:$proto device:$ctl_device iface:$net desc:$desc"
+	done
+
+	[ -n "$ctl_device" ] || {
+		echo "wwan[$$]" "No valid device was found"
+		proto_notify_error "$interface" NO_DEVICE
+		proto_block_restart "$interface"
+		return 1
+	}
+
+	uci_set_state network $interface driver "$driver"
+	uci_set_state network $interface ctl_device "$ctl_device"
+	uci_set_state network $interface dat_device "$dat_device"
+
+	case $driver in
+	qmi_wwan)	proto_qmi_setup $@ ;;
+	cdc_mbim)	proto_mbim_setup $@ ;;
+	sierra_net)	proto_directip_setup $@ ;;
+	comgt)		proto_3g_setup $@ ;;
+	*cdc_ncm)	proto_ncm_setup $@ ;;
+	esac
+}
+
+proto_wwan_teardown() {
+	local interface=$1
+	local driver=$(uci_get_state network $interface driver)
+	ctl_device=$(uci_get_state network $interface ctl_device)
+	dat_device=$(uci_get_state network $interface dat_device)
+
+	case $driver in
+	qmi_wwan)	proto_qmi_teardown $@ ;;
+	cdc_mbim)	proto_mbim_teardown $@ ;;
+	sierra_net)	proto_mbim_teardown $@ ;;
+	comgt)		proto_3g_teardown $@ ;;
+	*cdc_ncm)	proto_ncm_teardown $@ ;;
+	esac
+}
+
+add_protocol wwan
diff --git a/package/network/utils/wwan/files/wwan.usb b/package/network/utils/wwan/files/wwan.usb
new file mode 100644
index 0000000000..507b002d14
--- /dev/null
+++ b/package/network/utils/wwan/files/wwan.usb
@@ -0,0 +1,18 @@
+[ "$ACTION" = add -a "$DEVTYPE" = usb_device ] || exit 0
+
+vid=$(cat /sys$DEVPATH/idVendor)
+pid=$(cat /sys$DEVPATH/idProduct)
+[ -f "/lib/network/wwan/$vid:$pid" ] || exit 0
+
+find_wwan_iface() {
+	local cfg="$1"
+	local proto
+	config_get proto "$cfg" proto
+	[ "$proto" = wwan ] || return 0
+	proto_set_available "$cfg" 1
+	ifup $cfg
+	exit 0
+}
+
+config_load network
+config_foreach find_wwan_iface interface
diff --git a/package/network/utils/wwan/files/wwan.usbmisc b/package/network/utils/wwan/files/wwan.usbmisc
new file mode 100644
index 0000000000..4079a7fd8f
--- /dev/null
+++ b/package/network/utils/wwan/files/wwan.usbmisc
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+[ "$ACTION" = add ] || [ "$ACTION" = remove ] || exit 0
+[ "${DEVNAME/[0-9]/}" = cdc-wdm ] || exit 0
+
+. /lib/functions.sh
+. /lib/netifd/netifd-proto.sh
+
+find_wwan_iface() {
+	local cfg="$1"
+
+	local proto device
+	config_get proto "$cfg" proto
+	config_get device "$cfg" device
+
+	[ "$proto" = wwan ] || [ "$proto" = mbim ] || [ "$proto" = qmi ] || [ "$proto" = ncm ] || return 0
+	[ -z "$device" -a "$proto" = wwan ] || [ "$device" = "/dev/$DEVNAME" ] || return 0
+	if [ "$ACTION" = add ]; then
+		proto_set_available "$cfg" 1
+	else
+		proto_set_available "$cfg" 0
+	fi
+	exit 0
+}
+
+config_load network
+config_foreach find_wwan_iface interface
diff --git a/package/network/utils/xtables-addons/Makefile b/package/network/utils/xtables-addons/Makefile
new file mode 100644
index 0000000000..014887d06b
--- /dev/null
+++ b/package/network/utils/xtables-addons/Makefile
@@ -0,0 +1,151 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=xtables-addons
+PKG_VERSION:=2.11
+PKG_RELEASE:=1
+PKG_MD5SUM:=9f3123295db81a9d1bc08dabf075d0d6
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@SF/xtables-addons
+PKG_BUILD_DEPENDS:=iptables
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+PKG_CHECK_FORMAT_SECURITY:=0
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=GPL-2.0
+
+PKG_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/xtables-addons
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Firewall
+  TITLE:=Extensions not distributed in the main Xtables
+  URL:=http://xtables-addons.sourceforge.net/
+endef
+
+# uses GNU configure
+
+CONFIGURE_ARGS+= \
+	--with-kbuild="$(LINUX_DIR)" \
+	--with-xtlibdir="/usr/lib/iptables" \
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		ARCH="$(LINUX_KARCH)" \
+		CROSS_COMPILE="$(TARGET_CROSS)" \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		DEPMOD="/bin/true" \
+		all
+endef
+
+define Build/Install
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		ARCH="$(LINUX_KARCH)" \
+		CROSS_COMPILE="$(TARGET_CROSS)" \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		DEPMOD="/bin/true" \
+		install
+endef
+
+# 1: extension/module suffix used in package name
+# 2: extension/module display name used in package title/description
+# 3: list of extensions to package
+# 4: list of modules to package
+# 5: module load priority
+# 6: module depends
+define BuildTemplate
+
+ ifneq ($(3),)
+  define Package/iptables-mod-$(1)
+    $$(call Package/xtables-addons)
+    CATEGORY:=Network
+    TITLE:=$(2) iptables extension
+    DEPENDS:=iptables $(if $(4),+kmod-ipt-$(1))
+  endef
+
+  define Package/iptables-mod-$(1)/install
+	$(INSTALL_DIR) $$(1)/usr/lib/iptables
+	for m in $(3); do \
+		$(CP) \
+			$(PKG_INSTALL_DIR)/usr/lib/iptables/lib$$$$$$$${m}.so \
+			$$(1)/usr/lib/iptables/ ; \
+	done
+  endef
+
+  $$(eval $$(call BuildPackage,iptables-mod-$(1)))
+ endif
+
+ ifneq ($(4),)
+  define KernelPackage/ipt-$(1)
+    SUBMENU:=Netfilter Extensions
+    TITLE:=$(2) netfilter module
+    DEPENDS:=+kmod-ipt-core $(5)
+    KCONFIG:=CONFIG_NF_CONNTRACK_MARK=y
+    FILES:=$(foreach mod,$(4),$(PKG_BUILD_DIR)/extensions/$(mod).$(LINUX_KMOD_SUFFIX))
+    AUTOLOAD:=$(call AutoProbe,$(notdir $(4)))
+  endef
+
+  $$(eval $$(call KernelPackage,ipt-$(1)))
+ endif
+
+endef
+
+
+define Package/iptaccount
+  $(call Package/xtables-addons)
+  CATEGORY:=Network
+  TITLE:=iptables-mod-account control utility
+  DEPENDS:=iptables +iptables-mod-account
+endef
+
+define Package/iptaccount/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libxt_ACCOUNT_cl.so* \
+		$(1)/usr/lib/
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/sbin/iptaccount \
+		$(1)/usr/sbin/
+endef
+
+
+#$(eval $(call BuildTemplate,SUFFIX,DESCRIPTION,EXTENSION,MODULE,PRIORITY,DEPENDS))
+
+$(eval $(call BuildTemplate,compat-xtables,API compatibilty layer,,compat_xtables,+IPV6:kmod-ip6tables))
+$(eval $(call BuildTemplate,nathelper-rtsp,RTSP Conntrack and NAT,,rtsp/nf_conntrack_rtsp rtsp/nf_nat_rtsp,+kmod-ipt-conntrack-extra +kmod-ipt-nat))
+
+$(eval $(call BuildTemplate,account,ACCOUNT,xt_ACCOUNT,ACCOUNT/xt_ACCOUNT,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,chaos,CHAOS,xt_CHAOS,xt_CHAOS,+kmod-ipt-compat-xtables +kmod-ipt-delude +kmod-ipt-tarpit))
+$(eval $(call BuildTemplate,condition,Condition,xt_condition,xt_condition,))
+$(eval $(call BuildTemplate,delude,DELUDE,xt_DELUDE,xt_DELUDE,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,dhcpmac,DHCPMAC,xt_DHCPMAC,xt_DHCPMAC,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,dnetmap,DNETMAP,xt_DNETMAP,xt_DNETMAP,+kmod-ipt-compat-xtables +kmod-ipt-nat))
+$(eval $(call BuildTemplate,fuzzy,fuzzy,xt_fuzzy,xt_fuzzy,))
+$(eval $(call BuildTemplate,geoip,geoip,xt_geoip,xt_geoip,))
+$(eval $(call BuildTemplate,iface,iface,xt_iface,xt_iface,))
+$(eval $(call BuildTemplate,ipmark,IPMARK,xt_IPMARK,xt_IPMARK,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,ipp2p,IPP2P,xt_ipp2p,xt_ipp2p,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,ipv4options,ipv4options,xt_ipv4options,xt_ipv4options,))
+$(eval $(call BuildTemplate,length2,length2,xt_length2,xt_length2,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,logmark,LOGMARK,xt_LOGMARK,xt_LOGMARK,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,lscan,lscan,xt_lscan,xt_lscan,))
+$(eval $(call BuildTemplate,lua,Lua PacketScript,xt_LUA,LUA/xt_LUA,+kmod-ipt-conntrack-extra))
+$(eval $(call BuildTemplate,psd,psd,xt_psd,xt_psd,))
+$(eval $(call BuildTemplate,quota2,quota2,xt_quota2,xt_quota2,))
+$(eval $(call BuildTemplate,sysrq,SYSRQ,xt_SYSRQ,xt_SYSRQ,+kmod-ipt-compat-xtables +kmod-crypto-hash))
+$(eval $(call BuildTemplate,tarpit,TARPIT,xt_TARPIT,xt_TARPIT,+kmod-ipt-compat-xtables))
+
+$(eval $(call BuildPackage,iptaccount))
diff --git a/package/network/utils/xtables-addons/patches/002-fix-kernel-version-detection.patch b/package/network/utils/xtables-addons/patches/002-fix-kernel-version-detection.patch
new file mode 100644
index 0000000000..775ccf657c
--- /dev/null
+++ b/package/network/utils/xtables-addons/patches/002-fix-kernel-version-detection.patch
@@ -0,0 +1,11 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -44,7 +44,7 @@ regular_CFLAGS="-Wall -Waggregate-return
+ 
+ if test -n "$kbuilddir"; then
+ 	AC_MSG_CHECKING([kernel version that we will build against])
+-	krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease | $AWK -v 'FS=[[^0-9.]]' '{print $1; exit}')"
++	krel="$(make -sC "$kbuilddir" M=$PWD kernelversion | $AWK -v 'FS=[[^0-9.]]' '{print $1; exit}')"
+ 	save_IFS="$IFS"
+ 	IFS='.'
+ 	set x $krel
diff --git a/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch b/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
new file mode 100644
index 0000000000..bd49d92de6
--- /dev/null
+++ b/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
@@ -0,0 +1,1526 @@
+--- /dev/null
++++ b/extensions/rtsp/Kbuild
+@@ -0,0 +1,4 @@
++# -*- Makefile -*-
++
++obj-m += nf_nat_rtsp.o
++obj-m += nf_conntrack_rtsp.o
+--- /dev/null
++++ b/extensions/rtsp/netfilter_helpers.h
+@@ -0,0 +1,133 @@
++/*
++ * Helpers for netfiler modules.  This file provides implementations for basic
++ * functions such as strncasecmp(), etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested.  The following macros are used:
++ *   NF_NEED_STRNCASECMP        nf_strncasecmp()
++ *   NF_NEED_STRTOU16           nf_strtou16()
++ *   NF_NEED_STRTOU32           nf_strtou32()
++ */
++#ifndef _NETFILTER_HELPERS_H
++#define _NETFILTER_HELPERS_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++#define iseol(c) ( (c) == '\r' || (c) == '\n' )
++
++/*
++ * The standard strncasecmp()
++ */
++#ifdef NF_NEED_STRNCASECMP
++static int
++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
++{
++    if (s1 == NULL || s2 == NULL)
++    {
++        if (s1 == NULL && s2 == NULL)
++        {
++            return 0;
++        }
++        return (s1 == NULL) ? -1 : 1;
++    }
++    while (len > 0 && tolower(*s1) == tolower(*s2))
++    {
++        len--;
++        s1++;
++        s2++;
++    }
++    return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
++}
++#endif /* NF_NEED_STRNCASECMP */
++
++/*
++ * Parse a string containing a 16-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU16
++static int
++nf_strtou16(const char* pbuf, u_int16_t* pval)
++{
++    int n = 0;
++
++    *pval = 0;
++    while (isdigit(pbuf[n]))
++    {
++        *pval = (*pval * 10) + (pbuf[n] - '0');
++        n++;
++    }
++
++    return n;
++}
++#endif /* NF_NEED_STRTOU16 */
++
++/*
++ * Parse a string containing a 32-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU32
++static int
++nf_strtou32(const char* pbuf, u_int32_t* pval)
++{
++    int n = 0;
++
++    *pval = 0;
++    while (pbuf[n] >= '0' && pbuf[n] <= '9')
++    {
++        *pval = (*pval * 10) + (pbuf[n] - '0');
++        n++;
++    }
++
++    return n;
++}
++#endif /* NF_NEED_STRTOU32 */
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.
++ */
++#ifdef NF_NEED_NEXTLINE
++static int
++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++    uint    off = *poff;
++    uint    physlen = 0;
++
++    if (off >= len)
++    {
++        return 0;
++    }
++
++    while (p[off] != '\n')
++    {
++        if (len-off <= 1)
++        {
++            return 0;
++        }
++
++        physlen++;
++        off++;
++    }
++
++    /* if we saw a crlf, physlen needs adjusted */
++    if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++    {
++        physlen--;
++    }
++
++    /* advance past the newline */
++    off++;
++
++    *plineoff = *poff;
++    *plinelen = physlen;
++    *poff = off;
++
++    return 1;
++}
++#endif /* NF_NEED_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_HELPERS_H */
+--- /dev/null
++++ b/extensions/rtsp/netfilter_mime.h
+@@ -0,0 +1,89 @@
++/*
++ * MIME functions for netfilter modules.  This file provides implementations
++ * for basic MIME parsing.  MIME headers are used in many protocols, such as
++ * HTTP, RTSP, SIP, etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested.  The following macros are used:
++ *   NF_NEED_MIME_NEXTLINE      nf_mime_nextline()
++ */
++#ifndef _NETFILTER_MIME_H
++#define _NETFILTER_MIME_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.  If the current line is empty, *plinelen will be set to zero.  If
++ * not, it will be set to the actual line length (including CRLF).
++ *
++ * 'line' in this context means logical line (includes LWS continuations).
++ * Returns 1 on success, 0 on failure.
++ */
++#ifdef NF_NEED_MIME_NEXTLINE
++static int
++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++    uint    off = *poff;
++    uint    physlen = 0;
++    int     is_first_line = 1;
++
++    if (off >= len)
++    {
++        return 0;
++    }
++
++    do
++    {
++        while (p[off] != '\n')
++        {
++            if (len-off <= 1)
++            {
++                return 0;
++            }
++
++            physlen++;
++            off++;
++        }
++
++        /* if we saw a crlf, physlen needs adjusted */
++        if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++        {
++            physlen--;
++        }
++
++        /* advance past the newline */
++        off++;
++
++        /* check for an empty line */
++        if (physlen == 0)
++        {
++            break;
++        }
++
++        /* check for colon on the first physical line */
++        if (is_first_line)
++        {
++            is_first_line = 0;
++            if (memchr(p+(*poff), ':', physlen) == NULL)
++            {
++                return 0;
++            }
++        }
++    }
++    while (p[off] == ' ' || p[off] == '\t');
++
++    *plineoff = *poff;
++    *plinelen = (physlen == 0) ? 0 : (off - *poff);
++    *poff = off;
++
++    return 1;
++}
++#endif /* NF_NEED_MIME_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_MIME_H */
+--- /dev/null
++++ b/extensions/rtsp/nf_conntrack_rtsp.c
+@@ -0,0 +1,576 @@
++/*
++ * RTSP extension for IP connection tracking
++ * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ *
++ * 2005-02-13: Harald Welte <laforge at netfilter.org>
++ * 	- port to 2.6
++ * 	- update to recent post-2.6.11 api changes
++ * 2006-09-14: Steven Van Acker <deepstar at singularity.be>
++ *	- removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack
++ * 2007-04-18: Michael Guntsche <mike at it-loops.com>
++ * 			- Port to new NF API
++ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
++ *	- fixed rtcp nat mapping and other port mapping fixes
++ *	- simple TEARDOWN request handling
++ *	- codestyle fixes and other less significant bug fixes 
++ *
++ * based on ip_conntrack_irc.c
++ *
++ *      This program is free software; you can redistribute it and/or
++ *      modify it under the terms of the GNU General Public License
++ *      as published by the Free Software Foundation; either version
++ *      2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ *   insmod nf_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ *                              max_outstanding=n setup_timeout=secs
++ *
++ * If no ports are specified, the default will be port 554.
++ *
++ * With max_outstanding you can define the maximum number of not yet
++ * answered SETUP requests per RTSP session (default 8).
++ * With setup_timeout you can specify how long the system waits for
++ * an expected data channel (default 300 seconds).
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/inet.h>
++#include <net/tcp.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_expect.h>
++#include <net/netfilter/nf_conntrack_helper.h>
++#include "nf_conntrack_rtsp.h"
++
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#define NF_NEED_STRTOU32
++#define NF_NEED_NEXTLINE
++#include "netfilter_helpers.h"
++#define NF_NEED_MIME_NEXTLINE
++#include "netfilter_mime.h"
++
++#include <linux/ctype.h>
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int num_ports = 0;
++static int max_outstanding = 8;
++static unsigned int setup_timeout = 300;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
++MODULE_DESCRIPTION("RTSP connection tracking module");
++MODULE_LICENSE("GPL");
++module_param_array(ports, int, &num_ports, 0400);
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++module_param(max_outstanding, int, 0400);
++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
++module_param(setup_timeout, int, 0400);
++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
++
++static char *rtsp_buffer;
++static DEFINE_SPINLOCK(rtsp_buffer_lock);
++
++static struct nf_conntrack_expect_policy rtsp_exp_policy;
++
++unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
++				 enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++				 unsigned int protoff,
++#endif
++				 unsigned int matchoff, unsigned int matchlen,
++				 struct ip_ct_rtsp_expect* prtspexp,
++				 struct nf_conntrack_expect *rtp_exp,
++				 struct nf_conntrack_expect *rtcp_exp);
++
++EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook);
++
++/*
++ * Max mappings we will allow for one RTSP connection (for RTP, the number
++ * of allocated ports is twice this value).  Note that SMIL burns a lot of
++ * ports so keep this reasonably high.  If this is too low, you will see a
++ * lot of "no free client map entries" messages.
++ */
++#define MAX_PORT_MAPS 16
++
++/*** default port list was here in the masq code: 554, 3030, 4040 ***/
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*
++ * Parse an RTSP packet.
++ *
++ * Returns zero if parsing failed.
++ *
++ * Parameters:
++ *  IN      ptcp        tcp data pointer
++ *  IN      tcplen      tcp data len
++ *  IN/OUT  ptcpoff     points to current tcp offset
++ *  OUT     phdrsoff    set to offset of rtsp headers
++ *  OUT     phdrslen    set to length of rtsp headers
++ *  OUT     pcseqoff    set to offset of CSeq header
++ *  OUT     pcseqlen    set to length of CSeq header
++ */
++static int
++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
++		   uint* phdrsoff, uint* phdrslen,
++		   uint* pcseqoff, uint* pcseqlen,
++		   uint* transoff, uint* translen)
++{
++	uint	entitylen = 0;
++	uint	lineoff;
++	uint	linelen;
++	
++	if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++		return 0;
++	
++	*phdrsoff = *ptcpoff;
++	while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) {
++		if (linelen == 0) {
++			if (entitylen > 0)
++				*ptcpoff += min(entitylen, tcplen - *ptcpoff);
++			break;
++		}
++		if (lineoff+linelen > tcplen) {
++			pr_info("!! overrun !!\n");
++			break;
++		}
++
++		if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
++			*pcseqoff = lineoff;
++			*pcseqlen = linelen;
++		} 
++
++		if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
++			*transoff = lineoff;
++			*translen = linelen;
++		}
++		
++		if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) {
++			uint off = lineoff+15;
++			SKIP_WSPACE(ptcp+lineoff, linelen, off);
++			nf_strtou32(ptcp+off, &entitylen);
++		}
++	}
++	*phdrslen = (*ptcpoff) - (*phdrsoff);
++	
++	return 1;
++}
++
++/*
++ * Find lo/hi client ports (if any) in transport header
++ * In:
++ *   ptcp, tcplen = packet
++ *   tranoff, tranlen = buffer to search
++ *
++ * Out:
++ *   pport_lo, pport_hi = lo/hi ports (host endian)
++ *
++ * Returns nonzero if any client ports found
++ *
++ * Note: it is valid (and expected) for the client to request multiple
++ * transports, so we need to parse the entire line.
++ */
++static int
++rtsp_parse_transport(char* ptran, uint tranlen,
++		     struct ip_ct_rtsp_expect* prtspexp)
++{
++	int  rc = 0;
++	uint off = 0;
++	
++	if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++	    nf_strncasecmp(ptran, "Transport:", 10) != 0) {
++		pr_info("sanity check failed\n");
++		return 0;
++	}
++	
++	pr_debug("tran='%.*s'\n", (int)tranlen, ptran);
++	off += 10;
++	SKIP_WSPACE(ptran, tranlen, off);
++	
++	/* Transport: tran;field;field=val,tran;field;field=val,... */
++	while (off < tranlen) {
++		const char* pparamend;
++		uint        nextparamoff;
++		
++		pparamend = memchr(ptran+off, ',', tranlen-off);
++		pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++		nextparamoff = pparamend-ptran;
++		
++		while (off < nextparamoff) {
++			const char* pfieldend;
++			uint        nextfieldoff;
++			
++			pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++			nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++		   
++			if (strncmp(ptran+off, "client_port=", 12) == 0) {
++				u_int16_t   port;
++				uint        numlen;
++
++				off += 12;
++				numlen = nf_strtou16(ptran+off, &port);
++				off += numlen;
++				if (prtspexp->loport != 0 && prtspexp->loport != port)
++					pr_debug("multiple ports found, port %hu ignored\n", port);
++				else {
++					pr_debug("lo port found : %hu\n", port);
++					prtspexp->loport = prtspexp->hiport = port;
++					if (ptran[off] == '-') {
++						off++;
++						numlen = nf_strtou16(ptran+off, &port);
++						off += numlen;
++						prtspexp->pbtype = pb_range;
++						prtspexp->hiport = port;
++						
++						// If we have a range, assume rtp:
++						// loport must be even, hiport must be loport+1
++						if ((prtspexp->loport & 0x0001) != 0 ||
++						    prtspexp->hiport != prtspexp->loport+1) {
++							pr_debug("incorrect range: %hu-%hu, correcting\n",
++							       prtspexp->loport, prtspexp->hiport);
++							prtspexp->loport &= 0xfffe;
++							prtspexp->hiport = prtspexp->loport+1;
++						}
++					} else if (ptran[off] == '/') {
++						off++;
++						numlen = nf_strtou16(ptran+off, &port);
++						off += numlen;
++						prtspexp->pbtype = pb_discon;
++						prtspexp->hiport = port;
++					}
++					rc = 1;
++				}
++			}
++			
++			/*
++			 * Note we don't look for the destination parameter here.
++			 * If we are using NAT, the NAT module will handle it.  If not,
++			 * and the client is sending packets elsewhere, the expectation
++			 * will quietly time out.
++			 */
++			
++			off = nextfieldoff;
++		}
++		
++		off = nextparamoff;
++	}
++	
++	return rc;
++}
++
++
++/*** conntrack functions ***/
++
++/* outbound packet: client->server */
++
++static inline int
++help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
++	 unsigned int protoff)
++#else
++	 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
++#endif
++{
++	struct ip_ct_rtsp_expect expinfo;
++	
++	int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
++	//struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
++	//uint    tcplen = pktlen - iph->ihl * 4;
++	char*   pdata = rb_ptr;
++	//uint    datalen = tcplen - tcph->doff * 4;
++	uint    dataoff = 0;
++	int ret = NF_ACCEPT;
++	
++	struct nf_conntrack_expect *rtp_exp;
++	struct nf_conntrack_expect *rtcp_exp = NULL;
++	
++	__be16 be_loport;
++	__be16 be_hiport;
++	
++	typeof(nf_nat_rtsp_hook) nf_nat_rtsp;
++
++	memset(&expinfo, 0, sizeof(expinfo));
++	
++	while (dataoff < datalen) {
++		uint cmdoff = dataoff;
++		uint hdrsoff = 0;
++		uint hdrslen = 0;
++		uint cseqoff = 0;
++		uint cseqlen = 0;
++		uint transoff = 0;
++		uint translen = 0;
++		uint off;
++		
++		if (!rtsp_parse_message(pdata, datalen, &dataoff,
++					&hdrsoff, &hdrslen,
++					&cseqoff, &cseqlen,
++					&transoff, &translen))
++			break;      /* not a valid message */
++
++		if (strncmp(pdata+cmdoff, "TEARDOWN ", 9) == 0) {
++			pr_debug("teardown handled\n");
++			nf_ct_remove_expectations(ct); /* FIXME must be session id aware */
++			break;
++		}
++
++		if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
++			continue;   /* not a SETUP message */
++
++		pr_debug("found a setup message\n");
++
++		off = 0;
++		if(translen)
++			rtsp_parse_transport(pdata+transoff, translen, &expinfo);
++
++		if (expinfo.loport == 0) {
++			pr_debug("no udp transports found\n");
++			continue;   /* no udp transports found */
++		}
++
++		pr_debug("udp transport found, ports=(%d,%hu,%hu)\n",
++			 (int)expinfo.pbtype, expinfo.loport, expinfo.hiport);
++
++
++		be_loport = htons(expinfo.loport);
++
++		rtp_exp = nf_ct_expect_alloc(ct);
++		if (rtp_exp == NULL) {
++			ret = NF_DROP;
++			goto out;
++		}
++
++		nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
++				  nf_ct_l3num(ct),
++				  NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */
++				  &ct->tuplehash[!dir].tuple.dst.u3,
++				  IPPROTO_UDP, NULL, &be_loport);
++
++		rtp_exp->flags = 0;
++
++		if (expinfo.pbtype == pb_range) {
++			pr_debug("setup expectation for rtcp\n");
++
++			be_hiport = htons(expinfo.hiport);
++			rtcp_exp = nf_ct_expect_alloc(ct);
++			if (rtcp_exp == NULL) {
++				ret = NF_DROP;
++				goto out1;
++			}
++
++			nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
++					  nf_ct_l3num(ct),
++					  NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */
++					  &ct->tuplehash[!dir].tuple.dst.u3,
++					  IPPROTO_UDP, NULL, &be_hiport);
++
++			rtcp_exp->flags = 0;
++
++			pr_debug("expect_related %pI4:%u-%u-%pI4:%u-%u\n",
++				   &rtp_exp->tuple.src.u3.ip,
++				   ntohs(rtp_exp->tuple.src.u.udp.port),
++				   ntohs(rtcp_exp->tuple.src.u.udp.port),
++				   &rtp_exp->tuple.dst.u3.ip,
++				   ntohs(rtp_exp->tuple.dst.u.udp.port),
++				   ntohs(rtcp_exp->tuple.dst.u.udp.port));
++		} else {
++			pr_debug("expect_related %pI4:%u-%pI4:%u\n",
++					&rtp_exp->tuple.src.u3.ip,
++					ntohs(rtp_exp->tuple.src.u.udp.port),
++					&rtp_exp->tuple.dst.u3.ip,
++					ntohs(rtp_exp->tuple.dst.u.udp.port));
++		}
++
++		nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook);
++		if (nf_nat_rtsp && ct->status & IPS_NAT_MASK)
++			/* pass the request off to the nat helper */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++			ret = nf_nat_rtsp(skb, ctinfo, protoff, hdrsoff, hdrslen,
++					  &expinfo, rtp_exp, rtcp_exp);
++#else
++			ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen,
++					  &expinfo, rtp_exp, rtcp_exp);
++#endif
++		else {
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				if (rtcp_exp && nf_ct_expect_related(rtcp_exp) != 0) {
++					nf_ct_unexpect_related(rtp_exp);
++					pr_info("nf_conntrack_expect_related failed for rtcp\n");
++					ret = NF_DROP;
++				}
++			} else {
++				pr_info("nf_conntrack_expect_related failed for rtp\n");
++				ret = NF_DROP;
++			}
++		}
++		if (rtcp_exp) {
++			nf_ct_expect_put(rtcp_exp);
++		}
++out1:
++		nf_ct_expect_put(rtp_exp);
++		goto out;
++	}
++out:
++
++	return ret;
++}
++
++
++static inline int
++help_in(struct sk_buff *skb, size_t pktlen,
++	struct nf_conn* ct, enum ip_conntrack_info ctinfo)
++{
++	return NF_ACCEPT;
++}
++
++static int help(struct sk_buff *skb, unsigned int protoff,
++		struct nf_conn *ct, enum ip_conntrack_info ctinfo) 
++{
++	struct tcphdr _tcph, *th;
++	unsigned int dataoff, datalen;
++	char *rb_ptr;
++	int ret = NF_DROP;
++
++	/* Until there's been traffic both ways, don't look in packets. */
++	if (ctinfo != IP_CT_ESTABLISHED && 
++	    ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++		pr_debug("conntrackinfo = %u\n", ctinfo);
++		return NF_ACCEPT;
++	} 
++
++	/* Not whole TCP header? */
++	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
++
++	if (!th)
++		return NF_ACCEPT;
++   
++	/* No data ? */
++	dataoff = protoff + th->doff*4;
++	datalen = skb->len - dataoff;
++	if (dataoff >= skb->len)
++		return NF_ACCEPT;
++
++	spin_lock_bh(&rtsp_buffer_lock);
++	rb_ptr = skb_header_pointer(skb, dataoff,
++				    skb->len - dataoff, rtsp_buffer);
++	BUG_ON(rb_ptr == NULL);
++
++#if 0
++	/* Checksum invalid?  Ignore. */
++	/* FIXME: Source route IP option packets --RR */
++	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++			 csum_partial((char*)tcph, tcplen, 0)))
++	{
++		DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++		       tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++		return NF_ACCEPT;
++	}
++#endif
++
++	switch (CTINFO2DIR(ctinfo)) {
++	case IP_CT_DIR_ORIGINAL:
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++		ret = help_out(skb, rb_ptr, datalen, ct, ctinfo, protoff);
++#else
++		ret = help_out(skb, rb_ptr, datalen, ct, ctinfo);
++#endif
++		break;
++	case IP_CT_DIR_REPLY:
++		pr_debug("IP_CT_DIR_REPLY\n");
++		/* inbound packet: server->client */
++		ret = NF_ACCEPT;
++		break;
++	}
++
++	spin_unlock_bh(&rtsp_buffer_lock);
++
++	return ret;
++}
++
++static struct nf_conntrack_helper rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++	int i;
++	for (i = 0; i < num_ports; i++) {
++		pr_debug("unregistering port %d\n", ports[i]);
++		nf_conntrack_helper_unregister(&rtsp_helpers[i]);
++	}
++	kfree(rtsp_buffer);
++}
++
++static int __init
++init(void)
++{
++	int i, ret;
++	struct nf_conntrack_helper *hlpr;
++	char *tmpname;
++
++	printk("nf_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++	if (max_outstanding < 1) {
++		printk("nf_conntrack_rtsp: max_outstanding must be a positive integer\n");
++		return -EBUSY;
++	}
++	if (setup_timeout < 0) {
++		printk("nf_conntrack_rtsp: setup_timeout must be a positive integer\n");
++		return -EBUSY;
++	}
++
++	rtsp_exp_policy.max_expected = max_outstanding;
++	rtsp_exp_policy.timeout = setup_timeout;
++	
++	rtsp_buffer = kmalloc(65536, GFP_KERNEL);
++	if (!rtsp_buffer) 
++		return -ENOMEM;
++
++	/* If no port given, default to standard rtsp port */
++	if (ports[0] == 0) {
++		ports[0] = RTSP_PORT;
++		num_ports = 1;
++	}
++
++	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++		hlpr = &rtsp_helpers[i];
++		memset(hlpr, 0, sizeof(struct nf_conntrack_helper));
++		hlpr->tuple.src.l3num = AF_INET;
++		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++		hlpr->tuple.dst.protonum = IPPROTO_TCP;
++		hlpr->expect_policy = &rtsp_exp_policy;
++		hlpr->me = THIS_MODULE;
++		hlpr->help = help;
++
++		tmpname = &rtsp_names[i][0];
++		if (ports[i] == RTSP_PORT) {
++			sprintf(tmpname, "rtsp");
++		} else {
++			sprintf(tmpname, "rtsp-%d", i);
++		}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++		strlcpy(hlpr->name, tmpname, sizeof(hlpr->name));
++#else
++		hlpr->name = tmpname;
++#endif
++		pr_debug("port #%d: %d\n", i, ports[i]);
++
++		ret = nf_conntrack_helper_register(hlpr);
++
++		if (ret) {
++			printk("nf_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
++			fini();
++			return -EBUSY;
++		}
++	}
++	return 0;
++}
++
++module_init(init);
++module_exit(fini);
+--- /dev/null
++++ b/extensions/rtsp/nf_conntrack_rtsp.h
+@@ -0,0 +1,72 @@
++/*
++ * RTSP extension for IP connection tracking.
++ * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ * based on ip_conntrack_irc.h
++ *
++ *      This program is free software; you can redistribute it and/or
++ *      modify it under the terms of the GNU General Public License
++ *      as published by the Free Software Foundation; either version
++ *      2 of the License, or (at your option) any later version.
++ *
++ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
++ *	- conditional compilation for kernel 3.7
++ *	- port mapping improvements
++*/
++#ifndef _IP_CONNTRACK_RTSP_H
++#define _IP_CONNTRACK_RTSP_H
++
++#include <linux/version.h>
++
++//#define IP_NF_RTSP_DEBUG 1
++#define IP_NF_RTSP_VERSION "0.7"
++
++#ifdef __KERNEL__
++/* port block types */
++typedef enum {
++    pb_single,  /* client_port=x */
++    pb_range,   /* client_port=x-y */
++    pb_discon   /* client_port=x/y (rtspbis) */
++} portblock_t;
++
++/* We record seq number and length of rtsp headers here, all in host order. */
++
++/*
++ * This structure is per expected connection.  It is a member of struct
++ * ip_conntrack_expect.  The TCP SEQ for the conntrack expect is stored
++ * there and we are expected to only store the length of the data which
++ * needs replaced.  If a packet contains multiple RTSP messages, we create
++ * one expected connection per message.
++ *
++ * We use these variables to mark the entire header block.  This may seem
++ * like overkill, but the nature of RTSP requires it.  A header may appear
++ * multiple times in a message.  We must treat two Transport headers the
++ * same as one Transport header with two entries.
++ */
++struct ip_ct_rtsp_expect
++{
++    u_int32_t   len;        /* length of header block */
++    portblock_t pbtype;     /* Type of port block that was requested */
++    u_int16_t   loport;     /* Port that was requested, low or first */
++    u_int16_t   hiport;     /* Port that was requested, high or second */
++#if 0
++    uint        method;     /* RTSP method */
++    uint        cseq;       /* CSeq from request */
++#endif
++};
++
++extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
++					enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++					unsigned int protoff,
++#endif
++					unsigned int matchoff,
++					unsigned int matchlen,
++					struct ip_ct_rtsp_expect *prtspexp,
++					struct nf_conntrack_expect *rtp_exp,
++					struct nf_conntrack_expect *rtcp_exp);
++
++#define RTSP_PORT   554
++
++#endif /* __KERNEL__ */
++
++#endif /* _IP_CONNTRACK_RTSP_H */
+--- /dev/null
++++ b/extensions/rtsp/nf_nat_rtsp.c
+@@ -0,0 +1,617 @@
++/*
++ * RTSP extension for TCP NAT alteration
++ * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ *
++ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
++ *	- fixed rtcp nat mapping and other port mapping fixes
++ *	- fixed system hard lock because of bug in the parser
++ *	- codestyle fixes and less significant fixes
++ *
++ * based on ip_nat_irc.c
++ *
++ *	This program is free software; you can redistribute it and/or
++ *	modify it under the terms of the GNU General Public License
++ *	as published by the Free Software Foundation; either version
++ *	2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ *	insmod nf_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ *	                     stunaddr=<address>
++ *	                     destaction=[auto|strip|none]
++ *
++ * If no ports are specified, the default will be port 554 only.
++ *
++ * stunaddr specifies the address used to detect that a client is using STUN.
++ * If this address is seen in the destination parameter, it is assumed that
++ * the client has already punched a UDP hole in the firewall, so we don't
++ * mangle the client_port.  If none is specified, it is autodetected.  It
++ * only needs to be set if you have multiple levels of NAT.  It should be
++ * set to the external address that the STUN clients detect.  Note that in
++ * this case, it will not be possible for clients to use UDP with servers
++ * between the NATs.
++ *
++ * If no destaction is specified, auto is used.
++ *   destaction=auto:  strip destination parameter if it is not stunaddr.
++ *   destaction=strip: always strip destination parameter (not recommended).
++ *   destaction=none:  do not touch destination parameter (not recommended).
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <net/tcp.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++# include <net/netfilter/nf_nat.h>
++#else
++# include <net/netfilter/nf_nat_rule.h>
++#endif
++#include <net/netfilter/nf_nat_helper.h>
++#include "nf_conntrack_rtsp.h"
++#include <net/netfilter/nf_conntrack_expect.h>
++
++#include <linux/inet.h>
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#include "netfilter_helpers.h"
++#define NF_NEED_MIME_NEXTLINE
++#include "netfilter_mime.h"
++
++#define MAX_PORTS     8
++#define DSTACT_AUTO   0
++#define DSTACT_STRIP  1
++#define DSTACT_NONE   2
++
++static char* stunaddr = NULL;
++static char* destaction = NULL;
++
++static u_int32_t extip = 0;
++static int       dstact = 0;
++
++static void nf_nat_rtsp_expected(struct nf_conn* ct, struct nf_conntrack_expect *exp);
++
++MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
++MODULE_DESCRIPTION("RTSP network address translation module");
++MODULE_LICENSE("GPL");
++module_param(stunaddr, charp, 0644);
++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
++module_param(destaction, charp, 0644);
++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*** helper functions ***/
++
++static void
++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
++{
++	struct iphdr*   iph  = ip_hdr(skb);
++	struct tcphdr*  tcph = (void *)iph + ip_hdrlen(skb);
++
++	*pptcpdata = (char*)tcph +  tcph->doff*4;
++	*ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++/* copy of sip_sprintf_addr */
++static int rtsp_sprintf_addr(const struct nf_conn *ct, char *buffer,
++			     const union nf_inet_addr *addr, bool delim)
++{
++	if (nf_ct_l3num(ct) == NFPROTO_IPV4) {
++		return sprintf(buffer, "%pI4", &addr->ip);
++	} else {
++		if (delim)
++			return sprintf(buffer, "[%pI6c]", &addr->ip6);
++		else
++			return sprintf(buffer, "%pI6c", &addr->ip6);
++	}
++}
++#endif
++
++/*** nat functions ***/
++
++/*
++ * Mangle the "Transport:" header:
++ *   - Replace all occurences of "client_port=<spec>"
++ *   - Handle destination parameter
++ *
++ * In:
++ *   ct, ctinfo = conntrack context
++ *   skb        = packet
++ *   tranoff    = Transport header offset from TCP data
++ *   tranlen    = Transport header length (incl. CRLF)
++ *   rport_lo   = replacement low  port (host endian)
++ *   rport_hi   = replacement high port (host endian)
++ *
++ * Returns packet size difference.
++ *
++ * Assumes that a complete transport header is present, ending with CR or LF
++ */
++static int
++rtsp_mangle_tran(enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++		 unsigned int protoff,
++#endif
++		 struct nf_conntrack_expect* rtp_exp,
++		 struct nf_conntrack_expect* rtcp_exp,
++		 struct ip_ct_rtsp_expect* prtspexp,
++		 struct sk_buff* skb, uint tranoff, uint tranlen)
++{
++	char*  ptcp;
++	uint   tcplen;
++	char*  ptran;
++	char   rbuf1[16];	  /* Replacement buffer (one port) */
++	uint   rbuf1len;	  /* Replacement len (one port) */
++	char   rbufa[16];	  /* Replacement buffer (all ports) */
++	uint   rbufalen;	  /* Replacement len (all ports) */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	union nf_inet_addr newip;
++#else
++	u_int32_t  newip;
++#endif
++	u_int16_t loport, hiport;
++	uint      off = 0;
++	uint      diff;		   /* Number of bytes we removed */
++
++	struct nf_conn *ct = rtp_exp->master;
++	/* struct nf_conn *ct = nf_ct_get(skb, &ctinfo); */
++	struct nf_conntrack_tuple *rtp_t;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	char szextaddr[INET6_ADDRSTRLEN];
++#else
++	char szextaddr[INET_ADDRSTRLEN];
++#endif
++	uint extaddrlen;
++	int  is_stun;
++
++	get_skb_tcpdata(skb, &ptcp, &tcplen);
++	ptran = ptcp+tranoff;
++
++	if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
++	    tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++	    nf_strncasecmp(ptran, "Transport:", 10) != 0) {
++		pr_info("sanity check failed\n");
++		return 0;
++	}
++	off += 10;
++	SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3;
++	rtp_t = &rtp_exp->tuple;
++	rtp_t->dst.u3 = newip;
++	if (rtcp_exp) {
++		rtcp_exp->tuple.dst.u3 = newip;
++	}
++	extaddrlen = rtsp_sprintf_addr(ct, szextaddr, &newip, true); // FIXME handle extip
++	pr_debug("stunaddr=%s (auto)\n", szextaddr);
++#else
++	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
++	rtp_t = &rtp_exp->tuple;
++	rtp_t->dst.u3.ip = newip;
++	if (rtcp_exp) {
++		rtcp_exp->tuple.dst.u3.ip = newip;
++	}
++	extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip)
++			   : sprintf(szextaddr, "%pI4", &newip);
++	pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++#endif
++	hiport = 0;
++	rbuf1len = rbufalen = 0;
++	switch (prtspexp->pbtype) {
++	case pb_single:
++		for (loport = prtspexp->loport; loport != 0; loport++) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(loport);
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				pr_debug("using port %hu\n", loport);
++				break;
++			}
++		}
++		if (loport != 0) {
++			rbuf1len = sprintf(rbuf1, "%hu", loport);
++			rbufalen = sprintf(rbufa, "%hu", loport);
++		}
++		break;
++	case pb_range:
++		for (loport = prtspexp->loport; loport != 0; loport += 2) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(loport);
++			if (nf_ct_expect_related(rtp_exp) != 0) {
++				continue;
++			}
++			hiport = loport + 1;
++			rtcp_exp->tuple.dst.u.udp.port = htons(hiport);
++			if (nf_ct_expect_related(rtcp_exp) != 0) {
++				nf_ct_unexpect_related(rtp_exp);
++				continue;
++			}
++
++			/* FIXME: invalid print in case of ipv6 */
++			pr_debug("nat expect_related %pI4:%u-%u-%pI4:%u-%u\n",
++				 &rtp_exp->tuple.src.u3.ip,
++				 ntohs(rtp_exp->tuple.src.u.udp.port),
++				 ntohs(rtcp_exp->tuple.src.u.udp.port),
++				 &rtp_exp->tuple.dst.u3.ip,
++				 ntohs(rtp_exp->tuple.dst.u.udp.port),
++				 ntohs(rtcp_exp->tuple.dst.u.udp.port));
++			break;
++		}
++		if (loport != 0) {
++			rbuf1len = sprintf(rbuf1, "%hu", loport);
++			rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
++		}
++		break;
++	case pb_discon:
++		for (loport = prtspexp->loport; loport != 0; loport++) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(loport);
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				pr_debug("using port %hu (1 of 2)\n", loport);
++				break;
++			}
++		}
++		for (hiport = prtspexp->hiport; hiport != 0; hiport++) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(hiport);
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				pr_debug("using port %hu (2 of 2)\n", hiport);
++				break;
++			}
++		}
++		if (loport != 0 && hiport != 0) {
++			rbuf1len = sprintf(rbuf1, "%hu", loport);
++			rbufalen = sprintf(rbufa, hiport == loport+1 ?
++					   "%hu-%hu":"%hu/%hu", loport, hiport);
++		}
++		break;
++	}
++
++	if (rbuf1len == 0)
++		return 0;   /* cannot get replacement port(s) */
++
++	/* Transport: tran;field;field=val,tran;field;field=val,...
++	   `off` is set to the start of Transport value from start of line
++	*/
++	while (off < tranlen) {
++		uint        saveoff;
++		const char* pparamend;
++		uint        nextparamoff;
++
++		pparamend = memchr(ptran+off, ',', tranlen-off);
++		pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++		nextparamoff = pparamend-ptran;
++
++		/*
++		 * We pass over each param twice.  On the first pass, we look for a
++		 * destination= field.  It is handled by the security policy.  If it
++		 * is present, allowed, and equal to our external address, we assume
++		 * that STUN is being used and we leave the client_port= field alone.
++		 */
++		is_stun = 0;
++		saveoff = off;
++		while (off < nextparamoff) {
++			const char* pfieldend;
++			uint        nextfieldoff;
++
++			pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++			nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++			if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) {
++				if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
++					is_stun = 1;
++
++				if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) {
++					uint dstoff = (ptran-ptcp)+off;
++					uint dstlen = nextfieldoff-off;
++					char* pdstrep = NULL;
++					uint dstreplen = 0;
++					diff = dstlen;
++					if (dstact == DSTACT_AUTO && !is_stun) {
++						pr_debug("RTSP: replace dst addr\n");
++						dstoff += 12;
++						dstlen -= 13;
++						pdstrep = szextaddr;
++						dstreplen = extaddrlen;
++						diff = nextfieldoff-off-13-extaddrlen;
++					}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
++								      dstoff, dstlen, pdstrep, dstreplen)) {
++#else
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
++								      dstoff, dstlen, pdstrep, dstreplen)) {
++#endif
++						/* mangle failed, all we can do is bail */
++						nf_ct_unexpect_related(rtp_exp);
++						if (rtcp_exp)
++							nf_ct_unexpect_related(rtcp_exp);
++						return 0;
++					}
++					get_skb_tcpdata(skb, &ptcp, &tcplen);
++					ptran = ptcp+tranoff;
++					tranlen -= diff;
++					nextparamoff -= diff;
++					nextfieldoff -= diff;
++				}
++			}
++
++			off = nextfieldoff;
++		}
++
++		if (is_stun)
++			continue;
++
++		off = saveoff;
++		while (off < nextparamoff) {
++			const char* pfieldend;
++			uint        nextfieldoff;
++
++			pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++			nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++			if (strncmp(ptran+off, "client_port=", 12) == 0) {
++				u_int16_t port;
++				uint	  numlen;
++				uint      origoff;
++				uint      origlen;
++				char*     rbuf = rbuf1;
++				uint      rbuflen = rbuf1len;
++
++				off += 12;
++				origoff = (ptran-ptcp)+off;
++				origlen = 0;
++				numlen = nf_strtou16(ptran+off, &port);
++				off += numlen;
++				origlen += numlen;
++				if (port != prtspexp->loport) {
++					pr_debug("multiple ports found, port %hu ignored\n", port);
++				} else {
++					if (ptran[off] == '-' || ptran[off] == '/') {
++						off++;
++						origlen++;
++						numlen = nf_strtou16(ptran+off, &port);
++						off += numlen;
++						origlen += numlen;
++						rbuf = rbufa;
++						rbuflen = rbufalen;
++					}
++
++					/*
++					 * note we cannot just memcpy() if the sizes are the same.
++					 * the mangle function does skb resizing, checks for a
++					 * cloned skb, and updates the checksums.
++					 *
++					 * parameter 4 below is offset from start of tcp data.
++					 */
++					diff = origlen-rbuflen;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
++								      origoff, origlen, rbuf, rbuflen)) {
++#else
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
++								      origoff, origlen, rbuf, rbuflen)) {
++#endif
++						/* mangle failed, all we can do is bail */
++						nf_ct_unexpect_related(rtp_exp);
++						if (rtcp_exp)
++							nf_ct_unexpect_related(rtcp_exp);
++						return 0;
++					}
++					get_skb_tcpdata(skb, &ptcp, &tcplen);
++					ptran = ptcp+tranoff;
++					tranlen -= diff;
++					nextparamoff -= diff;
++					nextfieldoff -= diff;
++				}
++			}
++
++			off = nextfieldoff;
++		}
++
++		off = nextparamoff;
++	}
++
++	return 1;
++}
++
++static uint
++help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	 unsigned int protoff,
++#endif
++	 unsigned int matchoff, unsigned int matchlen,
++	 struct ip_ct_rtsp_expect* prtspexp,
++	 struct nf_conntrack_expect* rtp_exp,
++	 struct nf_conntrack_expect* rtcp_exp)
++{
++	char* ptcp;
++	uint  tcplen;
++	uint  hdrsoff;
++	uint  hdrslen;
++	uint  lineoff;
++	uint  linelen;
++	uint  off;
++	int   dir = CTINFO2DIR(ctinfo);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	union nf_inet_addr saddr = rtp_exp->master->tuplehash[dir].tuple.src.u3;
++#else
++	__be32 saddr = rtp_exp->master->tuplehash[dir].tuple.src.u3.ip;
++#endif
++
++	//struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++	//struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
++
++	get_skb_tcpdata(skb, &ptcp, &tcplen);
++	hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq);
++	hdrslen = matchlen;
++	off = hdrsoff;
++	pr_debug("NAT rtsp help_out\n");
++
++	while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) {
++		if (linelen == 0)
++			break;
++
++		if (off > hdrsoff+hdrslen) {
++			pr_info("!! overrun !!");
++			break;
++		}
++		pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++
++		if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
++			uint oldtcplen = tcplen;
++			pr_debug("hdr: Transport\n");
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++			if (!rtsp_mangle_tran(ctinfo, protoff, rtp_exp, rtcp_exp,
++					      prtspexp, skb, lineoff, linelen)) {
++#else
++			if (!rtsp_mangle_tran(ctinfo, rtp_exp, rtcp_exp, prtspexp,
++					      skb, lineoff, linelen)) {
++#endif
++				pr_debug("hdr: Transport mangle failed");
++				break;
++			}
++			rtp_exp->expectfn = nf_nat_rtsp_expected;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++			rtp_exp->saved_addr = saddr;
++#else
++			rtp_exp->saved_ip = saddr;
++#endif
++			rtp_exp->saved_proto.udp.port = htons(prtspexp->loport);
++			rtp_exp->dir = !dir;
++			if (rtcp_exp) {
++				rtcp_exp->expectfn = nf_nat_rtsp_expected;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++				rtcp_exp->saved_addr = saddr;
++#else
++				rtcp_exp->saved_ip = saddr;
++#endif
++				rtcp_exp->saved_proto.udp.port = htons(prtspexp->hiport);
++				rtcp_exp->dir = !dir;
++			}
++			get_skb_tcpdata(skb, &ptcp, &tcplen);
++			hdrslen -= (oldtcplen-tcplen);
++			off -= (oldtcplen-tcplen);
++			lineoff -= (oldtcplen-tcplen);
++			linelen -= (oldtcplen-tcplen);
++			pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++		}
++	}
++
++	return NF_ACCEPT;
++}
++
++static unsigned int
++nf_nat_rtsp(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	    unsigned int protoff,
++#endif
++	    unsigned int matchoff, unsigned int matchlen,
++	    struct ip_ct_rtsp_expect* prtspexp,
++	    struct nf_conntrack_expect* rtp_exp,
++	    struct nf_conntrack_expect* rtcp_exp)
++{
++	int dir = CTINFO2DIR(ctinfo);
++	int rc = NF_ACCEPT;
++
++	switch (dir) {
++	case IP_CT_DIR_ORIGINAL:
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++		rc = help_out(skb, ctinfo, protoff, matchoff, matchlen, prtspexp,
++			      rtp_exp, rtcp_exp);
++#else
++		rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp,
++			      rtp_exp, rtcp_exp);
++#endif
++		break;
++	case IP_CT_DIR_REPLY:
++		pr_debug("unmangle ! %u\n", ctinfo);
++		/* XXX: unmangle */
++		rc = NF_ACCEPT;
++		break;
++	}
++	//UNLOCK_BH(&ip_rtsp_lock);
++
++	return rc;
++}
++
++static void nf_nat_rtsp_expected(struct nf_conn* ct, struct nf_conntrack_expect *exp)
++{
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	struct nf_nat_range range;
++#else
++	struct nf_nat_ipv4_range range;
++#endif
++
++	/* This must be a fresh one. */
++	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
++
++	/* For DST manip, map port here to where it's expected. */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	range.min_proto = range.max_proto = exp->saved_proto;
++	range.min_addr = range.max_addr = exp->saved_addr;
++#else
++	range.min = range.max = exp->saved_proto;
++	range.min_ip = range.max_ip = exp->saved_ip;
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
++	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
++	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
++#else
++	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
++	nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
++#endif
++
++	/* Change src to where master sends to, but only if the connection
++	 * actually came from the same source. */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
++			     &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
++		range.min_addr = range.max_addr
++			= ct->master->tuplehash[!exp->dir].tuple.dst.u3;
++#else
++	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
++	    ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
++		range.min_ip = range.max_ip
++			= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
++		range.flags = NF_NAT_RANGE_MAP_IPS;
++		nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
++#else
++		range.flags = IP_NAT_RANGE_MAP_IPS;
++		nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
++#endif
++	}
++}
++
++
++static void __exit fini(void)
++{
++	rcu_assign_pointer(nf_nat_rtsp_hook, NULL);
++	synchronize_net();
++}
++
++static int __init init(void)
++{
++	printk("nf_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++	BUG_ON(nf_nat_rtsp_hook);
++	rcu_assign_pointer(nf_nat_rtsp_hook, nf_nat_rtsp);
++
++	if (stunaddr != NULL)
++		extip = in_aton(stunaddr);
++
++	if (destaction != NULL) {
++		if (strcmp(destaction, "auto") == 0)
++			dstact = DSTACT_AUTO;
++
++		if (strcmp(destaction, "strip") == 0)
++			dstact = DSTACT_STRIP;
++
++		if (strcmp(destaction, "none") == 0)
++			dstact = DSTACT_NONE;
++	}
++
++	return 0;
++}
++
++module_init(init);
++module_exit(fini);
+--- a/extensions/Kbuild
++++ b/extensions/Kbuild
+@@ -26,6 +26,7 @@ obj-${build_lscan}       += xt_lscan.o
+ obj-${build_pknock}      += pknock/
+ obj-${build_psd}         += xt_psd.o
+ obj-${build_quota2}      += xt_quota2.o
++obj-${build_rtsp}        += rtsp/
+ 
+ -include ${M}/*.Kbuild
+ -include ${M}/Kbuild.*
+--- a/mconfig
++++ b/mconfig
+@@ -22,3 +22,4 @@ build_lscan=m
+ build_pknock=m
+ build_psd=m
+ build_quota2=m
++build_rtsp=m
diff --git a/package/network/utils/xtables-addons/patches/200-add-lua-packetscript.patch b/package/network/utils/xtables-addons/patches/200-add-lua-packetscript.patch
new file mode 100644
index 0000000000..33d0d74814
--- /dev/null
+++ b/package/network/utils/xtables-addons/patches/200-add-lua-packetscript.patch
@@ -0,0 +1,18158 @@
+--- /dev/null
++++ b/extensions/LUA/byte_array.c
+@@ -0,0 +1,145 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++#include "controller.h"
++
++/* Initialization helper function. This function should be used whenever
++ * a new byte array need to be initialized. Depending on the arguments it
++ * initializes the array in a different way. Have a look at the inline
++ * comments */
++lua_packet_segment * init_byte_array(lua_State *L, unsigned char * start, int length, int do_copy)
++{
++	lua_packet_segment *array;
++
++	if (length < 0)
++		luaL_error(L, "init_byte_array, requested size < 0");
++
++	if (start && do_copy) {
++		/* we have a start address where we copy from */
++		array = lua_newuserdata(L, sizeof(lua_packet_segment) + length);
++		array->start = (unsigned char *)array + sizeof(lua_packet_segment); /* aligning pointer */
++		memcpy(array->start, start, length);
++	}else if (start && !do_copy) {
++		/* just link the start pointer, in this case you have to free the memory yourself */
++		array = lua_newuserdata(L, sizeof(lua_packet_segment));
++		array->start = start;
++	}else{
++		/* create an empty array, fully managed by Lua */
++		array = lua_newuserdata(L, sizeof(lua_packet_segment) + length);
++		array->start = (unsigned char *)array + sizeof(lua_packet_segment); /* aligning pointer */
++		memset(array->start, 0, length);
++	}
++
++	array->length = length;
++	array->offset = 0;
++	array->changes = NULL;
++
++	luaL_getmetatable(L, LUA_BYTE_ARRAY);
++	lua_setmetatable(L, -2);
++
++	return array;
++}
++
++
++
++/* LUA_API: get one byte of the given byte array 
++ * access-pattern: array[<index>] */
++static int32_t get_byte_array(lua_State *L)
++{
++	lua_packet_segment * array = checkbytearray(L, 1);
++	int32_t index = luaL_checkinteger(L, 2); /* array starts with index 0 (not 1 as usual in Lua) */
++
++	luaL_argcheck(L, 0 <= index && index < array->length, 1, "index out of range");
++	lua_pushinteger(L, (array->start + array->offset)[index]);
++
++	return 1;
++}
++
++/* LUA_API: set one byte of the given byte array
++ * access-pattern: array[<index>]= 0xFF */
++static int32_t set_byte_array(lua_State *L)
++{
++	lua_packet_segment * array = checkbytearray(L, 1);
++	uint8_t byte;
++	int32_t index = luaL_checkinteger(L, 2);    /* array starts with index 0 (not 1 as usual in Lua) */
++	int32_t val = luaL_checkinteger(L, 3);
++	uint32_t  nob = 1 << CHAR_BIT;               /* we should use something like 1 << CHAR_BIT */
++
++	luaL_argcheck(L, 0 <= index && index < array->length, 1, "index out of range");
++	luaL_argcheck(L, 0 <= val && val < nob, 2, "cannot cast value to char");
++
++	byte = (uint8_t)val;
++
++	(array->start + array->offset)[index] = byte;
++
++	return 0;
++}
++
++/* LUA_API: get size of the given byte array
++ * access-pattern: #array (__length meta-method) */
++static int32_t get_byte_array_size(lua_State *L)
++{
++	lua_packet_segment * array = checkbytearray(L, 1);
++
++	lua_pushnumber(L, array->length);
++
++	return 1;
++}
++
++
++/* LUA_API: converts a given byte array to a string. 
++ * access-pattern: implicit through functions calling the
++ * __to_string() metamethod , e.g. print32_t */
++static int32_t byte_array_to_string(lua_State *L)
++{
++	lua_packet_segment * array = checkbytearray(L, 1);
++	uint8_t buf[(array->length * 3) + 255];
++	uint8_t hexval[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
++	char res[255 + (array->length * 3)]; /* make sure the buffer is big enough*/
++	int32_t i, n;
++	uint8_t *ptr = array->start + array->offset;
++
++	for (i = 0; i < array->length; i++) {
++		buf[i * 3] = hexval[(ptr[i] >> 4) & 0xF];
++		buf[(i * 3) + 1] = hexval[ptr[i] & 0x0F];
++		buf[(i * 3) + 2] = ' '; /* seperator */
++	}
++
++	buf[array->length * 3] = '\0';
++	n = sprintf(res, "byte_array: length: %d  value: %s", array->length, buf);
++
++	lua_pushlstring(L, res, n);
++
++	return 1;
++}
++
++static const struct luaL_Reg bytearray_lib_m [] = {
++	{ "__len",	get_byte_array_size  },
++	{ "__newindex", set_byte_array	     },
++	{ "__index",	get_byte_array	     },
++	{ "__tostring", byte_array_to_string },
++	{ NULL,		NULL		     }
++};
++
++void luaopen_bytearraylib(lua_State *L)
++{
++	luaL_newmetatable(L, LUA_BYTE_ARRAY);
++	luaL_register(L, NULL, bytearray_lib_m);
++	lua_pop(L, 1);
++}
++
++
+--- /dev/null
++++ b/extensions/LUA/controller.c
+@@ -0,0 +1,604 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#if defined(__KERNEL__)
++	#include <linux/mm.h>
++#endif
++#include "controller.h"
++
++/* the array 'supported_protocols' holds all pointers to the 
++ * static and dynamic protocol buffers. It is filled by the 
++ * call to register_protbuf */
++static struct protocol_buf * supported_protocols[MAX_NR_OF_PROTOCOLS];
++
++/* C_API: the function 'get_protocol_buf' returns the pointer 
++ * to the protocol buffer of a given protocol id. */
++struct protocol_buf * get_protocol_buf(uint32_t  protocol_id)
++{
++	return (struct protocol_buf *)supported_protocols[protocol_id];
++}
++
++
++/* LUA_INT: the function 'gc_packet_segment' is triggered by the 
++ * garbage collector whenever a userdata annotated with one of 
++ * the protocol buffer metatable should be collected. */
++static int32_t gc_packet_segment(lua_State *L)
++{
++	lua_packet_segment * seg = (lua_packet_segment *)lua_touserdata(L, 1);
++	if (seg && seg->changes) {
++		seg->changes->ref_count--;
++		if (seg->changes->ref_count <= 0) {
++			kfree(seg->changes->field_length_changes);
++			kfree(seg->changes->field_offset_changes);
++			kfree(seg->changes);
++			seg->changes = NULL;
++		}
++	}
++	return 0;
++}
++
++
++/* LUA_API: the function 'set_raw' is used to set the bytes of a segment 
++ * in 'raw' mode. The function is per default available in each protocol 
++ * buffer until it gets overridden by a specific setter function inside 
++ * a protocol buffer.
++ * 
++ * Parameters:
++ * 1. lua_packet_segment (implicit)
++ * 2. int32_t byte_value
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return: void
++ */
++static int32_t set_raw(lua_State *L)
++{
++	int32_t i;
++	uint32_t  nob;
++	uint8_t byte;
++	uint8_t *ptr;
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	int32_t val = luaL_checkinteger(L, 2);
++
++	nob = 1 << CHAR_BIT;
++
++	luaL_argcheck(L, 0 <= val && val < nob, 2, "cannot cast value to char");
++
++	byte = (uint8_t)val;
++	ptr = seg->start + seg->offset;
++
++	for (i = 0; i < seg->length; i++)
++		ptr[i] = byte;
++
++	return 0;
++}
++
++/* LUA_API: the function 'get_raw' is used to get the bytes of a segment 
++ * in 'raw' mode. The function is per default available in each protocol 
++ * buffer until it gets overridden by a specific getter function inside 
++ * a protocol buffer.
++ *
++ * Parameters:
++ * 1. lua_packet_segment (implicit)
++ * 2. uint32_t  offset
++ * 3. uint32_t  length 
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return: 
++ * the byte array representing the given array
++ */
++static int32_t get_raw(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	init_byte_array(L, seg->start + seg->offset,  seg->length, 1);
++
++	return 1;
++}
++/* LUA_API: The function 'get_segment' is used to get a new segment in 'raw' mode. 
++ * Typically this function is applied on another raw segment in order 
++ * to extract a part of the segment as new segment.
++ *
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ * 2.  uint32_t  offset, this indicates where to start the new segment, see e.g below.
++ * 3.  uint32_t  length, this indicates the size of the new segment
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return:
++ * 1.  A lua_packet_segment annotated with the according metatable or False in
++ *     case the input data is not valid
++ *
++ * Example:
++ *
++ * +------------------------+---------------------------------------+
++ * | function call          | resulting lua_packet_segment          |
++ * +========================+===+===+===+===+===+===+===+===+===+===+
++ * | seg = packet:raw(0,10) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
++ * +------------------------+---+---+---+---+---+---+---+---+---+---+
++ * | 1st_half = seg:raw(0,5)| 0 | 1 | 2 | 3 | 4 |                   |
++ * +------------------------+---+---+---+---+---+---+---+---+---+---+
++ * | 2nd_half = seg:raw(5,5)|                   | 5 | 6 | 7 | 8 | 9 |
++ * +------------------------+-------------------+---+---+---+---+---+
++ */
++static int32_t get_segment(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	uint32_t  offset = luaL_checkinteger(L, 2);
++	uint32_t  length = luaL_checkinteger(L, 3);
++	lua_packet_segment * new = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++
++	new->start = seg->start;
++	new->offset = seg->offset + offset;
++	new->changes = NULL;
++	/* we allow a seg->length == 0 , this enables processing packets where the packetsize is not fixed (0 = not fixed)*/
++	if (seg->length != 0 && length > seg->length) {
++		lua_pushboolean(L, 0);
++		return 1;
++	}
++
++	new->length = length;
++	luaL_getmetatable(L, prot_buf->name);
++	lua_setmetatable(L, -2);
++
++	return 1;
++}
++
++/* LUA_API: the function 'get_segment_size' is used to get the size of a segment.
++ * 
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return:
++ * 1.  Size as lua_Number
++ */
++static int32_t get_segment_size(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushnumber(L, seg->length);
++	return 1;
++}
++
++/* LUA_API: the function 'get_segment_offset' is used to get the real offset 
++ * of a segment. This function returns the offset of the segment to the start
++ * of the buffer. This means the following
++ *     seg1 = packet:raw(2,10)
++ *     seg2 = seg1:raw(3,5)
++ *   offset = seg2:get_offset()
++ *
++ * will give an offset of 5, since the seg1 starts at offset 2, and seg2 starts
++ * at offset (seg1:get_offset() + 3).
++ * 
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return:
++ * 1.  Offset as lua_Number
++ */
++static int32_t get_segment_offset(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushnumber(L, seg->offset);
++	return 1;
++}
++
++/* LUA_API: overwrites the __tostring function of a lua_packet_segment.
++ * this will print32_t a nicely formated string, including length,
++ * offset and name of the protocol buffer.
++ *
++ * Parameters:
++ * 1. lua_packet_segment (implicit)
++ *
++ * Returns:
++ * 1. the representing string
++ */
++static int32_t packet_segment_tostring(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	int32_t n;
++	char buf[128];
++
++	n = sprintf(buf, "type: %s, offset: %d, length: %d", prot_buf->name, seg->offset, seg->length);
++	lua_pushlstring(L, buf, n);
++
++	return 1;
++}
++
++
++static const struct luaL_Reg seg_access_functions [] = {
++	{ "set",	set_raw			},
++	{ "get",	get_raw			},
++	{ "raw",	get_segment		},
++	{ "get_offset", get_segment_offset	},
++	{ "get_size",	get_segment_size	},
++	{ "to_bytes",	get_raw			},
++	{ "__tostring", packet_segment_tostring },
++	{ "__gc",	gc_packet_segment	},
++	{ NULL,		NULL			}
++};
++
++/* C_API: the function 'get_metatable_from_protocol_type' is a helper
++ * used in controller.c as well as it may find usage in the static 
++ * protocol buffers and byte array implementation. */
++void get_metatable_from_protocol_type(lua_State *L, int32_t type)
++{
++	char * table;
++	lua_getglobal(L, SUPPORTED_PROTOCOL_TABLE);
++	lua_rawgeti(L, -1, type);
++	table = (char *)luaL_checkstring(L, -1);
++	lua_pop(L, 2); /* pop the table SUPPORTED_PROTOCOL_TABLE and the string pushed by lua_gettable */
++	luaL_getmetatable(L, table);
++	return;
++}
++
++/* C_INT: the function 'payload_contains_protocol' is used internally. 
++ * Depending if static or dynamic protocol buffer it calls the right
++ * validation function. */
++static int32_t payload_contains_protocol(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment *seg, uint32_t  prot_type)
++{
++	if (prot_buf->is_dynamic)
++		return has_protocol_dynamic(L, prot_buf, seg, prot_type);
++	else
++		return prot_buf->has_protocol(L, prot_buf, seg, prot_type);
++}
++
++/* C_INT: the function 'protocol_get_field_changes' is used interally. 
++ * It requests the field_changes struct calling the protocol buffers
++ * 'get_field_changes' function. This funciton is called, whenever
++ * the payload field with a given protocol type is requested inside 
++ * the function 'get_protocol_field' */
++static struct field_changes * protocol_get_field_changes(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg)
++{
++	struct field_changes * changes = NULL;
++
++	if (prot_buf->get_field_changes) {
++		if (prot_buf->is_dynamic)
++			changes = get_field_changes_dynamic(L, prot_buf, seg);
++		else
++			changes = prot_buf->get_field_changes(L, seg);
++		 /* is already 1 when set by helper 'get_allocated_field_changes,
++		  * since not every prot_buf may use this function we enforce it. */
++		changes->ref_count = 1;
++	}
++	return changes;
++}
++
++/* C_INT: the function 'get_field_offset_in_bytes' wrapps the logic of 
++ * calculating the new length with considering the optional field_changes. */
++static int32_t get_field_offset_in_bytes(struct protocol_field * field, lua_packet_segment * seg, int32_t field_index)
++{
++	uint32_t  nr_of_bits, nr_of_bytes, field_offset;
++
++	field_offset = field->offset;
++	/* do we need to manipulate the default values stored inside the protocol buffer ?? */
++	if (seg->changes)
++		field_offset += seg->changes->field_offset_changes[field_index];
++	/* how many bits remain */
++	nr_of_bits = field_offset & (CHAR_BIT - 1);
++	/* assuming CHAR_BIT == 2 ^ 3 */
++	nr_of_bytes = (field_offset - nr_of_bits) >> 3;
++
++	return seg->offset + nr_of_bytes;
++}
++
++/* C_INT: the function 'get_field_length_in_bytes' wrapps the logic of 
++ * calculating the new offset with considering the optional field_changes. */
++static int32_t get_field_length_in_bytes(struct protocol_field * field, lua_packet_segment * seg, int32_t field_index)
++{
++	uint32_t  nr_of_bits, nr_of_bytes, field_length;
++
++	field_length = field->length;
++	/* if the field length is smaller than 1 byte, we take the size of one byte
++	 * we treat the case where field_length == 0 in a special way ...*/
++	if (field_length < CHAR_BIT && field_length > 0)
++		field_length = CHAR_BIT;
++
++	/* do we need to manipulate the default values stored inside the protocol buffer ?? */
++	if (seg->changes)
++		field_length += seg->changes->field_length_changes[field_index];
++	/* how many bits remain */
++	nr_of_bits = field_length & (CHAR_BIT - 1);
++	/* assuming CHAR_BIT == 2 ^ 3 */
++	nr_of_bytes = (field_length - nr_of_bits) >> 3;
++	return nr_of_bytes;
++}
++
++/* C_INT: the function 'initialize_field_getter_and_setter' initializes 
++ * the setter and getter function of the field, considering the optional
++ * field manipulator functions defined inside the protocol buffers. */
++static void initialize_field_getter_and_setter(lua_State *L, struct protocol_buf *prot_buf, int32_t field_index)
++{
++	/* lets check if there is a metatable on top of the stack */
++	struct protocol_field * f = (struct protocol_field *)&prot_buf->protocol_fields[field_index];
++
++	if (!lua_istable(L, -1)) luaL_error(L, "cannot initialize getter and setter for field %s->%s, "
++					    "not a table on top of the stack, is '%s'", prot_buf->name, f->name, lua_typename(L, lua_type(L, -1)));
++
++	/* is there a 'getter' to initialize ? */
++	lua_pushlightuserdata(L, prot_buf);     /* push upvalue 1 */
++	lua_pushinteger(L, field_index);        /* push upvalue 2 */
++	if (f->get) {
++		if (prot_buf->is_dynamic)
++			lua_pushcclosure(L, field_dynamic_getter, 2);
++		else
++			lua_pushcclosure(L, f->get, 2);
++	}else
++		/* there is no specific getter defined - fall back to 'get_raw'  */
++		lua_pushcclosure(L, get_raw, 2);
++	 /* set the metatable field 'get' */
++	lua_setfield(L, -2, "get");
++
++	/* is there a 'setter' to initialize ? */
++	lua_pushlightuserdata(L, prot_buf);     /* push upvalue 1 */
++	lua_pushinteger(L, field_index);        /* push upvalue 2 */
++	if (f->set) {
++		if (prot_buf->is_dynamic)
++			lua_pushcclosure(L, field_dynamic_setter, 2);
++		else
++			lua_pushcclosure(L, f->set, 2);
++	}else
++		/* there is no specific setter defined - fall back to 'set_raw'  */
++		lua_pushcclosure(L, set_raw, 2);
++	 /* set the metatable field 'set' */
++	lua_setfield(L, -2, "set");
++}
++
++/* LUA_API: 'get_protocol_field' is used in Lua as a closure for each field of a protocol
++ * buffer. E.g a call to ip = packet:data(packet_ip) will go to this function,
++ * and trigger the conversion of the raw packet to a ip packet. Each call
++ * to a field function of an IP packet, like ip:daddr() uses this function
++ * to to return the right data. In each case you will end up either with a
++ * new packet segment (annotated with the proper metatable) or a boolean
++ * value (False) if something went wrong. In the case everything went fine,
++ * the newly created lua_packet_segment is annotated with the proper
++ * metatable where the fields get and set also contain the specific getter
++ * and setter functions given by the protocol buffer. E.g. the function call
++ * ip:daddr():get() or ip:daddr():set(...) will call the proper function
++ * defined inside the corresponding field definition.
++ *
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ * 2.  type of the protocol buffer, optional, and only used if the accessed
++ *     field is the payload field. If a type is provided for the access of the
++ *     payload field, the function tries to convert the data pointed to by the
++ *     payload field to the given type. To check if such a conversion is
++ *     possible, it calls the function pointed to by the protocol buffer member
++ *     has_protocol. If this function returns True, the conversion takes place.
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index
++ *
++ * Return:
++ * 1.  A lua_packet_segment annotated with the according metatable or False in
++ *     case the input data is not valid
++ */
++static int32_t get_protocol_field(lua_State *L)
++{
++	int32_t prot_type;
++	lua_packet_segment * seg, *new;
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	int32_t field_index = lua_tointeger(L, lua_upvalueindex(2));
++	struct protocol_field * field = &prot_buf->protocol_fields[field_index];
++
++	/* get the current packet segment */
++	seg = checkpacketseg(L, 1, prot_buf->name);
++
++	/* initialize the new packet segment */
++	new = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++	new->start = seg->start;         /* the start is unchanged */
++	new->offset = get_field_offset_in_bytes(field, seg, field_index);
++	new->length = get_field_length_in_bytes(field, seg, field_index);
++
++	/* if new->length == 0 then no configuration was done, we guess the size by subtracting the
++	 * new offset from the packet length. since the old length is getting initialized by the
++	 * netfilter extension this assumption holds for the very last field of the protocol.
++	 * this 'feature' should be used by protocol buffers containing a payload, whereas the
++	 * payload field is the last field of the buffer. However, at compile-time unknown field
++	 * sizes (and offsets) of fields not being placed at the end of the protocol should be
++	 * initialized using the 'get_field_changes' hook system. */
++	if (new->length == 0)
++		new->length = (seg->length + seg->offset) - (new->offset);
++	         /*
++	                         printf("%s->%s:: seg->offset %i, seg->length %i, new->offset %i, new->length %i\n",
++	                                         prot_buf->name, field->name, seg->offset, seg->length, new->offset, new->length);
++	          */
++	/* special care for packet payload requests */
++	if (prot_buf->payload_field != NULL && strcmp(prot_buf->payload_field, field->name) == 0) {
++		/* we know the payload field is requested */
++		/* the requested payload can be delivered either as a common segment or as
++		 * an other packet type, such a conversion needs an extra protocol parameter
++		 * ... so lets check */
++
++		if (lua_isnumber(L, 2)) {
++			/* we have an extra parameter, ... lets see if it is a valid protocol
++			 * the parameter is the index of the 'supported_protocols'-array member */
++			prot_type = lua_tointeger(L, 2);
++			if (prot_type >= 0 && prot_type < PACKET_SENTINEL) {
++				/* we are sure the purpose of the request is to get the payload data,
++				 * converted to the given protocol.  lets check if the payload contains
++				 * data of the given protocol */
++				if (payload_contains_protocol(L, prot_buf, seg, prot_type)) {
++					/* success, we can  push the metatable for the given protocol */
++					get_metatable_from_protocol_type(L, prot_type);
++					if (!lua_isnil(L, -1))  /* check if the metatable was found */
++						/* perhaps the field offsets and lengths of the containing protocol
++						 * are not set correctly. request the optional 'field_changes' structure
++						 * holding the changes for lengths and offsets. */
++						new->changes = protocol_get_field_changes(L, get_protocol_buf(prot_type), new);
++					else{
++						/* failed, the requested protocol is not available
++						 * we push false and return */
++						lua_pop(L, 1); /* pop the userdata */
++						lua_pushboolean(L, 0);
++						return 1;
++					}
++				}else{
++					/* payload does not carry the provided protocol */
++					/* we push false and return */
++					lua_pop(L, 1); /* pop the userdata */
++					lua_pushboolean(L, 0);
++					return 1;
++				}
++			}else{
++				/* unknown protocol */
++				lua_pop(L, 1); /* pop the userdata */
++				luaL_error(L, "provided protocol is unknown");
++			}
++		}
++	}
++
++	/* if there is still the 'new' userdata on the top, we push our own metatable */
++	if (lua_isuserdata(L, -1)) {
++		luaL_getmetatable(L, prot_buf->name);
++		new->changes = seg->changes;
++		if (seg->changes)
++			new->changes->ref_count++;
++	}
++
++	/* a new packet segment is at index -2 , and the proper metatable at index -1 of the stack
++	 * lets set the propper setter and getter function for the requested field */
++	initialize_field_getter_and_setter(L, prot_buf, field_index);
++
++	lua_setmetatable(L, -2);
++	return 1;
++}
++
++/* C_API: 'register_protbuf' is only used internally. This function takes a
++ * pointer to a fully initialized protocol buffer struct and registers it
++ * inside the Lua state. Registering means:
++ *
++ * 1.  it creates a new metatable with the name of the protocol buffer.
++ * 2.  it registers the default functions which are stored in the luaL_Reg
++ *     array seg_access_functions.
++ * 3.  it loops over the protocol fields stored at prot_buf->protocol_fields
++ *     and registers a new function (using the field name) inside the
++ *     metatable. Each field points to the function 'get_protocol_field'
++ *     which acts as a closure taking a pointer to the protocol buffer as
++ *     well as the index of the field as upvalues.
++ * 4.  The protocol index, serves as numerical identifier of this protocol
++ *     buffer or even of the protocol itself. This index is stored as a
++ *     global value inside the Lua state as well as inside the Lua table
++ *     'supported_protocols'. Assuming the name of a procotol buffer is
++ *     "packet_ip" the following statements are true:
++ * 
++ *       supported_protocols[protocol_index] == "packet_ip"
++ *                                 packet_ip == protocol_index
++ *
++ *     This allows you to get all registered protocols from within Lua. This
++ *     is especially usefull for the dynamic protocol buffers where you have
++ *     to provide your own "has_protocol"-function, which probably needs the
++ *     information on which protocols it is able to contain.
++ */
++void register_protbuf(lua_State *L, struct protocol_buf * prot_buf, uint32_t  protocol_index)
++{
++	int32_t field_index;
++	luaL_Reg *reg = (struct luaL_Reg *)seg_access_functions;
++	struct protocol_field * field = prot_buf->protocol_fields;
++
++	luaL_newmetatable(L, prot_buf->name);
++
++	/* metatable.__index = metatable */
++	lua_pushvalue(L, -1);   /* duplicates the metatable */
++	lua_setfield(L, -2, "__index");
++
++	/* pushing default functions */
++	for (; reg->name; reg++) {
++		lua_pushlightuserdata(L, (void *)prot_buf);
++		lua_pushcclosure(L, reg->func, 1);
++		lua_setfield(L, -2, reg->name);
++	}
++
++	/* pushing functions specific to the protocol buffer */
++	for (field_index = 0; field->name; field++, field_index++) {
++		lua_pushlightuserdata(L, (void *)prot_buf);             /* upvalue: prot_buf */
++		lua_pushinteger(L, field_index);                        /* upvalue: index of protocol field */
++		lua_pushcclosure(L, get_protocol_field, 2);
++		lua_setfield(L, -2, field->name);
++	}
++	/* pop the metatable */
++	lua_pop(L, 1);
++
++	/* registering the array-index as the protocol_id*/
++	lua_getglobal(L, "_G");
++	lua_pushinteger(L, protocol_index);
++	lua_setfield(L, -2, prot_buf->name);
++	lua_pop(L, 1); /* pop _G */
++
++	lua_getglobal(L, SUPPORTED_PROTOCOL_TABLE);
++	lua_pushstring(L, prot_buf->name);
++	lua_rawseti(L, -2, protocol_index);
++
++	lua_pop(L, 1);  /* pop SUPPORTED_PROTOCOL_TABLE */
++
++	supported_protocols[protocol_index] = prot_buf;
++}
++
++void luaopen_controller(lua_State *L)
++{
++	/* registering a table inside the _G with table[protocol_index] = prot_buf->name */
++	lua_getglobal(L, "_G");
++	lua_newtable(L);
++	lua_setfield(L, -2, SUPPORTED_PROTOCOL_TABLE);
++	lua_pop(L, 1); /* pop _G */                   
++	
++	luaopen_protbuf_raw(L);
++	luaopen_protbuf_eth(L);
++	luaopen_protbuf_ip(L);
++	luaopen_protbuf_icmp(L);
++	luaopen_protbuf_tcp(L);
++	luaopen_protbuf_tcp_options(L);
++	luaopen_protbuf_udp(L);
++	luaopen_protbuf_tftp(L);
++	luaopen_protbuf_dynamic(L);
++	/* should follow all other static buffers */
++#if defined(__KERNEL__)
++	luaopen_nflib(L);
++#endif
++
++	luaopen_bytearraylib(L);
++}
++
++
++
++
+--- /dev/null
++++ b/extensions/LUA/controller.h
+@@ -0,0 +1,264 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef CONTROLLER_H_
++#define CONTROLLER_H_
++
++#include "stdlib.h"     /* wrapper */
++#include "string.h"     /* wrapper */
++#include "lua.h"
++#include "lualib.h"
++#include "lauxlib.h"
++
++#if defined(__KERNEL__)
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#endif
++
++
++/* to compile the stuff in userspace (for testing)*/
++#if !defined(__KERNEL__)
++#include <stdint.h>
++#define pr_debug printf;
++
++#define kmalloc(size, type) malloc(size)
++#define kfree(ptr) free(ptr)
++
++#endif
++
++
++/**********************************************************************/
++/* nf Lua configuration                                               */
++/**********************************************************************/
++#define MAX_NR_OF_PROTOCOLS 16
++#define SUPPORTED_PROTOCOL_TABLE "supported_protocols"
++
++#define MAX_NR_OF_FIELDS_IN_DYN_PROT_BUF 32
++
++
++/**********************************************************************/
++/* Static Protocol Buffer configuration                               */
++/**********************************************************************/
++
++/* the definitions of the stringified expression of the prot_bufs...
++ * make sure all static prot_bufs are listed and are unique */
++#define LUA_PACKET_SEG_RAW "packet_raw"
++#define LUA_PACKET_SEG_ETH "packet_eth"
++#define LUA_PACKET_SEG_ICMP "packet_icmp"
++#define LUA_PACKET_SEG_IP "packet_ip"
++#define LUA_PACKET_SEG_TCP "packet_tcp"
++#define LUA_PACKET_SEG_TCP_OPT "packet_tcp_opt"
++#define LUA_PACKET_SEG_UDP "packet_udp"
++#define LUA_PACKET_SEG_TFTP "packet_tftp"
++
++/* the enum holding all static prot_bufs... make sure it contains all
++ * static prot_bufs */
++enum PROT_BUF {
++	PACKET_RAW,
++	PACKET_ETH,
++	PACKET_IP,
++	PACKET_ICMP,
++	PACKET_TCP,
++	PACKET_TCP_OPTIONS,
++	PACKET_UDP,
++	PACKET_TFTP,
++	PACKET_DYNAMIC,
++	PACKET_SENTINEL
++};
++
++/* the luaopen-function of the prot_bufs... make sure it is called
++ * inside luaopen_controller */
++void luaopen_protbuf_raw(lua_State *L);
++void luaopen_protbuf_eth(lua_State *L);
++void luaopen_protbuf_ip(lua_State *L);
++void luaopen_protbuf_icmp(lua_State *L);
++void luaopen_protbuf_tcp(lua_State *L);
++void luaopen_protbuf_tcp_options(lua_State *L);
++void luaopen_protbuf_udp(lua_State *L);
++void luaopen_protbuf_tftp(lua_State *L);
++void luaopen_protbuf_dynamic(lua_State *L);
++
++/**********************************************************************/
++/* field changes                                                      */
++/**********************************************************************/
++struct field_changes {
++	int ref_count;
++	int *field_length_changes;
++	int *field_offset_changes;
++};
++
++/**********************************************************************/
++/* lua packet segment												  */
++/* ------------------                                                 */
++/* The struct lua_packet_segment is the integral part of a Lua packet.*/
++/* At the very beginning, when a new packet arrives in `lua_tg`_ such */
++/* a struct is initialized. The field start then points to the lowest */
++/* available header inside the sk_buff structure. During packet       */
++/* processing the start pointer remains the same, only the offset and */
++/* length value change.                                               */
++/**********************************************************************/
++#define checkpacketseg(L, i, seg_type) \
++	(lua_packet_segment *)luaL_checkudata(L, i, seg_type)
++
++typedef struct lua_packet_segment {
++	unsigned int offset;
++	unsigned int length;
++	struct field_changes * changes;
++	unsigned char * start;  /* need to be at the end because of the memory alignment */
++} lua_packet_segment;
++
++/**********************************************************************/
++/* protocol field                                                     */
++/* --------------													  */
++/* This structure is a container for the field definitions used by the*/
++/* protocol buffer. Each protocol field is expressed using this struct*/
++/* Have a look at the protocol buffers to see how the struct gets     */
++/* initialized.														  */
++/*																	  */
++/* name:														      */
++/*   This member expresses the name of the field, ending			  */
++/*   in its own Lua function to access the field.					  */
++/* offset / length:													  */
++/*   These members do specify the position inside the protocol header */
++/*   in bits (not bytes!).											  */
++/* get / set:														  */
++/*   The get and set functions take a function pointer pointing to the*/
++/*   specific getter and setter function for this field.			  */
++/**********************************************************************/
++struct protocol_field {
++	const char * name;
++	uint32_t offset;
++	uint32_t length;
++	lua_CFunction get;
++	lua_CFunction set;
++};
++#define PROT_FIELD_SENTINEL { NULL, 0, 0, NULL, NULL }
++
++
++/**********************************************************************/
++/* protocol_buf                                                       */
++/**********************************************************************/
++/* This structure is a container for all the information needed for a
++ * protocol buffer. It gets initialized in each protocol buffer header
++ * file or for the dynamic protocol buffers on runtime using the
++ * 'register_dynamic_protocol_buffer' function.
++ *
++ * name:
++ *   This member is used throughout the system. It is also exported
++ *   to Lua as a variable name holding the index of the 'supported_protocols'
++ *   array. The name is also used as the name of the generated Lua
++ *   metatable, that is why inside the macro checkpacketseg_ it
++ *   is always the name of a protocol buffer that is passed as the
++ *   second parameter.
++ * payload_field:
++ *   This member holds the string of the field responsible for payload
++ *   data. The payload field of a protocol has an extra property, since
++ *   it can be used to invoke another protocol buffer that is applied to
++ *   the payload content.
++ * has_protocol:
++ *   This member is used together with the payload_field. Since we must
++ *   be sure that the payload content does really contain a protocol
++ *   of type X. The function pointed to by has_protocol checks if the
++ *   protocol buffer X can be applied on the payload_data.
++ * protocol_fields:
++ *   This member points to the array of 'protocol_field' structures
++ * get_field_changes:
++ *   This member is optional. It is used to return a pointer to an initialized
++ *   field_changes struct. The function is called, whenever the payload field
++ *   is requested with a given protocol type. Usually this function will
++ *   initialize the field_changes struct depending on the content of the 
++ *   payload data. e.g.
++ *     tcp = ip:data(packet_tcp)
++ *   such a request will call the 'get_field_changes' function of the tcp
++ *   protocol buffer. This enables, that the tcp options field have the proper
++ *   length as well as the tcp data start at the right offset. 
++ */
++struct protocol_buf {
++	int is_dynamic;
++	const char * name;
++	char * payload_field;
++	int (*has_protocol)(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg, int type);
++	struct protocol_field * protocol_fields;
++	struct field_changes * (*get_field_changes)(lua_State *L, lua_packet_segment * seg);
++};
++
++/**********************************************************************/
++/* lua byte array library                                             */
++/**********************************************************************/
++#define LUA_BYTE_ARRAY "byte_array"
++#define checkbytearray(L, i) \
++	(lua_packet_segment *)luaL_checkudata(L, i, LUA_BYTE_ARRAY)
++lua_packet_segment * init_byte_array(lua_State *L, unsigned char * start, int length, int do_copy);
++void luaopen_bytearraylib(lua_State *L);
++
++
++/**********************************************************************/
++/* lua netfilter environment library                                  */
++/**********************************************************************/
++#define NETFILTER_LIB "nf"
++#if defined(__KERNEL__)
++	struct lua_env {
++		lua_State *L;
++		/* perhaps more to come here (e.g. a state per CPU) */
++	}; 
++	#define LUA_ENV "lua_env"
++	#define checkluaenv(L, i) \
++	(struct lua_env *)luaL_checkudata(L, i, LUA_ENV)
++
++	void luaopen_nflib(lua_State *L);
++#endif
++
++void cleanup_dynamic_prot_bufs(void); /* freeing all dynamic prot bufs */
++/**********************************************************************/
++/* lua protbuf helpers                                                */
++/**********************************************************************/
++int get_1_bit_generic(lua_State *L);
++int set_1_bit_generic(lua_State *L);
++int get_lower_4_bit_generic(lua_State *L);
++int set_lower_4_bit_generic(lua_State *L);
++int get_upper_4_bit_generic(lua_State *L);
++int set_upper_4_bit_generic(lua_State *L);
++int get_8_bit_generic(lua_State *L);
++int set_8_bit_generic(lua_State *L);
++int get_16_bit_generic(lua_State *L);
++int set_16_bit_generic(lua_State *L);
++int get_32_bit_generic(lua_State *L);
++int set_32_bit_generic(lua_State *L);
++int set_data_generic(lua_State *L);
++int get_string_generic(lua_State *L);
++int get_byte_generic_str(lua_State *L);
++struct field_changes * get_allocated_field_changes(lua_State *L, int nr_of_fields);
++
++/* only used by the dynamic prot buf subsystem */
++#define MAX_NR_OF_DYN_PROT_BUFS 16
++int field_dynamic_setter(lua_State *L);
++int field_dynamic_getter(lua_State *L);
++int has_protocol_dynamic(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int type);
++struct field_changes * get_field_changes_dynamic(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg);
++
++/**********************************************************************/
++/* lua controller API                                                 */
++/**********************************************************************/
++void luaopen_controller(lua_State *L);
++struct protocol_buf * get_protocol_buf(unsigned int protocol_id);
++void get_metatable_from_protocol_type(lua_State *L, int type);
++void register_protbuf(lua_State *L, struct protocol_buf * prot_buf, unsigned int protocol_index);
++
++
++#endif /* CONTROLLER_H_ */
+--- /dev/null
++++ b/extensions/LUA/Kbuild
+@@ -0,0 +1,49 @@
++# -*- Makefile -*-
++
++# Adding debug options
++EXTRA_CFLAGS += -DDEBUG
++
++obj-m += xt_LUA.o
++
++EXTRA_CFLAGS += -I$(src)/prot_buf_new
++xt_LUA-y += xt_LUA_target.o \
++
++xt_LUA-y += nf_lua.o \
++			prot_buf_helpers.o \
++			byte_array.o \
++			controller.o \
++			prot_buf_ethernet.o \
++			prot_buf_icmp.o \
++			prot_buf_ip.o \
++			prot_buf_raw.o \
++			prot_buf_tcp.o \
++			prot_buf_udp.o \
++			prot_buf_tftp.o \
++			prot_buf_dynamic.o \
++
++
++# Adding Lua Support
++EXTRA_CFLAGS += -I$(src)/lua -I$(src)/lua/include 
++xt_LUA-y += lua/lapi.o \
++			lua/lbaselib.o \
++			lua/lcode.o \
++			lua/ldebug.o \
++			lua/ldo.o \
++			lua/ldump.o \
++			lua/lfunc.o \
++			lua/lgc.o \
++			lua/llex.o \
++			lua/lmem.o \
++			lua/lobject.o \
++			lua/lopcodes.o \
++			lua/lparser.o \
++			lua/lstate.o \
++			lua/lstring.o \
++			lua/lstrlib.o \
++			lua/ltable.o \
++			lua/ltablib.o \
++			lua/ltm.o \
++			lua/lundump.o \
++			lua/lvm.o \
++			lua/lzio.o \
++			lua/lauxlib.o \
+--- /dev/null
++++ b/extensions/LUA/libxt_LUA.c
+@@ -0,0 +1,191 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <getopt.h>
++#include <stdio.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include <xtables.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter/x_tables.h>
++#include "xt_LUA.h"
++
++enum {
++	FLAG_SCRIPT   = 1 << 0,
++	FLAG_STATE    = 1 << 1,
++	FLAG_FUNCTION = 1 << 2,
++};
++
++static const struct option lua_tg_opts[] = {
++	{ .name = "script",   .has_arg = true, .val = 's' },
++	{ .name = "state",    .has_arg = true, .val = 'l' },
++	{ .name = "function", .has_arg = true, .val = 'f' },
++	{ NULL },
++};
++
++
++static void lua_tg_help(void)
++{
++	printf(
++		"LUA target options:\n"
++		"  --script SCRIPT      Process packet with the Lua script given by SCRIPT\n"
++		"                                                                       \n"
++		"  --state ID           Process packet within the Lua state given by ID.\n"
++		"                       Omitting --state infers the ID 0, which can be\n"
++		"                       refered to the 'global' state.\n"
++		"                                                                       \n"
++		"  --function FUNCTION  Name of the function that processes the Lua packet\n"
++		"\n");
++}
++
++static void
++lua_tg_init(struct xt_entry_target *target)
++{
++	struct xt_lua_tginfo *info = (void *)target->data;
++
++	info->state_id = 0;
++	strncpy(info->function, "process_packet\0", sizeof("process_packet\0"));
++}
++
++static int
++lua_tg_parse(int32_t c, char **argv, int32_t invert, uint32_t  *flags,
++	     const void *entry, struct xt_entry_target **target)
++{
++	struct xt_lua_tginfo *info = (void *)(*target)->data;
++	char buf[MAX_SCRIPT_SIZE];
++	long script_size;
++	uint32_t  state_id;
++	FILE *file;
++
++	switch (c) {
++	case 's':
++		if (*flags & FLAG_SCRIPT)
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Cannot specify --script more than once");
++
++		if (strlen(optarg) > sizeof(info->filename))
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Maximum script length is %zu",
++				      sizeof(info->filename));
++
++		if (strchr(optarg, '\n'))
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Newlines not allowed in script name");
++		file = fopen(optarg, "rb");
++		if (file != NULL) {
++			fseek(file, 0, SEEK_END);
++			script_size = ftell(file);
++			if (script_size > MAX_SCRIPT_SIZE)
++				xtables_error(PARAMETER_PROBLEM,
++					      "LUA: The size of the script is too big");
++
++			fseek(file, 0, SEEK_SET);
++			fread(buf, script_size, 1, file);
++			fclose(file);
++		} else
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Cannot open script %s", optarg);
++
++		strncpy(info->filename, optarg, sizeof(info->filename));
++		strncpy(info->buf, buf, sizeof(info->buf));
++		info->script_size = script_size;
++
++		*flags |= FLAG_SCRIPT;
++		return true;
++
++	case 'l':
++		if (*flags & FLAG_STATE)
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Cannot specify --state more than once");
++
++		if (!xtables_strtoui(optarg, NULL, &state_id, 0, 8))
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Invalid --state %s", optarg);
++
++		info->state_id = state_id;
++		*flags |= FLAG_STATE;
++		return true;
++
++	case 'f':
++		if (*flags & FLAG_FUNCTION)
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Cannot specify --function more than once");
++		if (strlen(optarg) > sizeof(info->function))
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Maximum function length is %zu",
++				      sizeof(info->function));
++
++		if (strchr(optarg, '\n'))
++			xtables_error(PARAMETER_PROBLEM,
++				      "LUA: Newlines not allowed in function name");
++
++		strncpy(info->function, optarg, sizeof(info->function));
++
++		*flags |= FLAG_FUNCTION;
++		return true;
++	}
++
++	return false;
++}
++
++static void
++lua_tg_check(uint32_t  flags)
++{
++	if (flags == 0)
++		xtables_error(PARAMETER_PROBLEM, "LUA: --script parameter required");
++}
++
++static void
++lua_tg_print(const void *entry, const struct xt_entry_target *target,
++	     int32_t numeric)
++{
++	const struct xt_lua_tginfo *info = (const void *)target->data;
++
++	printf("LUA script: %s ", info->filename);
++}
++
++static void
++lua_tg_save(const void *entry, const struct xt_entry_target *target)
++{
++	const struct xt_lua_tginfo *info = (const void *)target->data;
++
++	printf("--script %s ", info->filename);
++}
++
++static struct xtables_target lua_tg_reg = {
++	.name			= "LUA",
++	.version		= XTABLES_VERSION,
++	.revision		= 0,
++	.family			= NFPROTO_UNSPEC,
++	.size			= XT_ALIGN(sizeof(struct xt_lua_tginfo)),
++	.userspacesize		= XT_ALIGN(sizeof(struct xt_lua_tginfo)),
++	.help			= lua_tg_help,
++	.init			= lua_tg_init,
++	.parse			= lua_tg_parse,
++	.final_check		= lua_tg_check,
++	.print			= lua_tg_print,
++	.save			= lua_tg_save,
++	.extra_opts		= lua_tg_opts,
++};
++
++static __attribute__((constructor)) void lua_tg_ldr(void)
++{
++	xtables_register_target(&lua_tg_reg);
++}
++
+--- /dev/null
++++ b/extensions/LUA/libxt_LUA.man
+@@ -0,0 +1 @@
++Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+--- /dev/null
++++ b/extensions/LUA/lua/include/ctype.h
+@@ -0,0 +1,11 @@
++#include <linux/ctype.h>
++#undef  isalnum
++#define isalnum(c)      (((__ismask(c)&(_U|_L|_D)) != 0) && (c > 0))
++#undef  isalpha
++#define isalpha(c)      (((__ismask(c)&(_U|_L)) != 0) && (c > 0))
++#undef  iscntrl
++#define iscntrl(c)      (((__ismask(c)&(_C)) != 0) && (c > 0))
++#undef  isdigit
++#define isdigit(c)      (((__ismask(c)&(_D)) != 0) && (c > 0))
++#undef  isspace
++#define isspace(c)      (((__ismask(c)&(_S)) != 0) && (c > 0))
+--- /dev/null
++++ b/extensions/LUA/lua/include/errno.h
+@@ -0,0 +1 @@
++#include <linux/errno.h>
+--- /dev/null
++++ b/extensions/LUA/lua/include/locale.h
+@@ -0,0 +1,5 @@
++struct lconv {
++   char * decimal_point ;
++} ;
++
++#define localeconv()		NULL
+--- /dev/null
++++ b/extensions/LUA/lua/include/setjmp.h
+@@ -0,0 +1,26 @@
++/*
++ * arch/um/include/sysdep-i386/archsetjmp.h
++ */
++
++#ifndef _KLIBC_ARCHSETJMP_H
++#define _KLIBC_ARCHSETJMP_H
++
++struct __jmp_buf {
++	unsigned int __ebx;
++	unsigned int __esp;
++	unsigned int __ebp;
++	unsigned int __esi;
++	unsigned int __edi;
++	unsigned int __eip;
++};
++
++typedef struct __jmp_buf jmp_buf[1];
++
++#define JB_IP __eip
++#define JB_SP __esp
++
++int setjmp(jmp_buf);
++void longjmp(jmp_buf, int);
++
++#endif				/* _SETJMP_H */
++
+--- /dev/null
++++ b/extensions/LUA/lua/include/stdio.h
+@@ -0,0 +1 @@
++#include <linux/kernel.h>
+--- /dev/null
++++ b/extensions/LUA/lua/include/stdlib.h
+@@ -0,0 +1,7 @@
++#include <linux/kernel.h>
++
++#define exit(E)         return
++#define strtoul		simple_strtoul
++#define strcoll		strcmp
++
++#define CHAR_BIT 8
+--- /dev/null
++++ b/extensions/LUA/lua/include/string.h
+@@ -0,0 +1 @@
++#include <linux/string.h>
+--- /dev/null
++++ b/extensions/LUA/lua/lapi.c
+@@ -0,0 +1,1086 @@
++/*
++** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $
++** Lua API
++** See Copyright Notice in lua.h
++*/
++
++#include <stdarg.h>
++#include <math.h>
++#include <assert.h>
++#include <string.h>
++
++#define lapi_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lapi.h"
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lgc.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++#include "lundump.h"
++#include "lvm.h"
++
++
++
++const char lua_ident[] =
++  "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n"
++  "$Authors: " LUA_AUTHORS " $\n"
++  "$URL: www.lua.org $\n";
++
++
++
++#define api_checknelems(L, n)	api_check(L, (n) <= (L->top - L->base))
++
++#define api_checkvalidindex(L, i)	api_check(L, (i) != luaO_nilobject)
++
++#define api_incr_top(L)   {api_check(L, L->top < L->ci->top); L->top++;}
++
++
++
++static TValue *index2adr (lua_State *L, int idx) {
++  if (idx > 0) {
++    TValue *o = L->base + (idx - 1);
++    api_check(L, idx <= L->ci->top - L->base);
++    if (o >= L->top) return cast(TValue *, luaO_nilobject);
++    else return o;
++  }
++  else if (idx > LUA_REGISTRYINDEX) {
++    api_check(L, idx != 0 && -idx <= L->top - L->base);
++    return L->top + idx;
++  }
++  else switch (idx) {  /* pseudo-indices */
++    case LUA_REGISTRYINDEX: return registry(L);
++    case LUA_ENVIRONINDEX: {
++      Closure *func = curr_func(L);
++      sethvalue(L, &L->env, func->c.env);
++      return &L->env;
++    }
++    case LUA_GLOBALSINDEX: return gt(L);
++    default: {
++      Closure *func = curr_func(L);
++      idx = LUA_GLOBALSINDEX - idx;
++      return (idx <= func->c.nupvalues)
++                ? &func->c.upvalue[idx-1]
++                : cast(TValue *, luaO_nilobject);
++    }
++  }
++}
++
++
++static Table *getcurrenv (lua_State *L) {
++  if (L->ci == L->base_ci)  /* no enclosing function? */
++    return hvalue(gt(L));  /* use global table as environment */
++  else {
++    Closure *func = curr_func(L);
++    return func->c.env;
++  }
++}
++
++
++void luaA_pushobject (lua_State *L, const TValue *o) {
++  setobj2s(L, L->top, o);
++  api_incr_top(L);
++}
++
++
++LUA_API int lua_checkstack (lua_State *L, int size) {
++  int res = 1;
++  lua_lock(L);
++  if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK)
++    res = 0;  /* stack overflow */
++  else if (size > 0) {
++    luaD_checkstack(L, size);
++    if (L->ci->top < L->top + size)
++      L->ci->top = L->top + size;
++  }
++  lua_unlock(L);
++  return res;
++}
++
++
++LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
++  int i;
++  if (from == to) return;
++  lua_lock(to);
++  api_checknelems(from, n);
++  api_check(from, G(from) == G(to));
++  api_check(from, to->ci->top - to->top >= n);
++  from->top -= n;
++  for (i = 0; i < n; i++) {
++    setobj2s(to, to->top++, from->top + i);
++  }
++  lua_unlock(to);
++}
++
++
++LUA_API void lua_setlevel (lua_State *from, lua_State *to) {
++  to->nCcalls = from->nCcalls;
++}
++
++
++LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
++  lua_CFunction old;
++  lua_lock(L);
++  old = G(L)->panic;
++  G(L)->panic = panicf;
++  lua_unlock(L);
++  return old;
++}
++
++
++LUA_API lua_State *lua_newthread (lua_State *L) {
++  lua_State *L1;
++  lua_lock(L);
++  luaC_checkGC(L);
++  L1 = luaE_newthread(L);
++  setthvalue(L, L->top, L1);
++  api_incr_top(L);
++  lua_unlock(L);
++  luai_userstatethread(L, L1);
++  return L1;
++}
++
++
++
++/*
++** basic stack manipulation
++*/
++
++
++LUA_API int lua_gettop (lua_State *L) {
++  return cast_int(L->top - L->base);
++}
++
++
++LUA_API void lua_settop (lua_State *L, int idx) {
++  lua_lock(L);
++  if (idx >= 0) {
++    api_check(L, idx <= L->stack_last - L->base);
++    while (L->top < L->base + idx)
++      setnilvalue(L->top++);
++    L->top = L->base + idx;
++  }
++  else {
++    api_check(L, -(idx+1) <= (L->top - L->base));
++    L->top += idx+1;  /* `subtract' index (index is negative) */
++  }
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_remove (lua_State *L, int idx) {
++  StkId p;
++  lua_lock(L);
++  p = index2adr(L, idx);
++  api_checkvalidindex(L, p);
++  while (++p < L->top) setobjs2s(L, p-1, p);
++  L->top--;
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_insert (lua_State *L, int idx) {
++  StkId p;
++  StkId q;
++  lua_lock(L);
++  p = index2adr(L, idx);
++  api_checkvalidindex(L, p);
++  for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
++  setobjs2s(L, p, L->top);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_replace (lua_State *L, int idx) {
++  StkId o;
++  lua_lock(L);
++  /* explicit test for incompatible code */
++  if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci)
++    luaG_runerror(L, "no calling environment");
++  api_checknelems(L, 1);
++  o = index2adr(L, idx);
++  api_checkvalidindex(L, o);
++  if (idx == LUA_ENVIRONINDEX) {
++    Closure *func = curr_func(L);
++    api_check(L, ttistable(L->top - 1)); 
++    func->c.env = hvalue(L->top - 1);
++    luaC_barrier(L, func, L->top - 1);
++  }
++  else {
++    setobj(L, o, L->top - 1);
++    if (idx < LUA_GLOBALSINDEX)  /* function upvalue? */
++      luaC_barrier(L, curr_func(L), L->top - 1);
++  }
++  L->top--;
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushvalue (lua_State *L, int idx) {
++  lua_lock(L);
++  setobj2s(L, L->top, index2adr(L, idx));
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++
++/*
++** access functions (stack -> C)
++*/
++
++
++LUA_API int lua_type (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
++}
++
++
++LUA_API const char *lua_typename (lua_State *L, int t) {
++  UNUSED(L);
++  return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
++}
++
++
++LUA_API int lua_iscfunction (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  return iscfunction(o);
++}
++
++
++LUA_API int lua_isnumber (lua_State *L, int idx) {
++  TValue n;
++  const TValue *o = index2adr(L, idx);
++  return tonumber(o, &n);
++}
++
++
++LUA_API int lua_isstring (lua_State *L, int idx) {
++  int t = lua_type(L, idx);
++  return (t == LUA_TSTRING || t == LUA_TNUMBER);
++}
++
++
++LUA_API int lua_isuserdata (lua_State *L, int idx) {
++  const TValue *o = index2adr(L, idx);
++  return (ttisuserdata(o) || ttislightuserdata(o));
++}
++
++
++LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
++  StkId o1 = index2adr(L, index1);
++  StkId o2 = index2adr(L, index2);
++  return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
++         : luaO_rawequalObj(o1, o2);
++}
++
++
++LUA_API int lua_equal (lua_State *L, int index1, int index2) {
++  StkId o1, o2;
++  int i;
++  lua_lock(L);  /* may call tag method */
++  o1 = index2adr(L, index1);
++  o2 = index2adr(L, index2);
++  i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2);
++  lua_unlock(L);
++  return i;
++}
++
++
++LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
++  StkId o1, o2;
++  int i;
++  lua_lock(L);  /* may call tag method */
++  o1 = index2adr(L, index1);
++  o2 = index2adr(L, index2);
++  i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
++       : luaV_lessthan(L, o1, o2);
++  lua_unlock(L);
++  return i;
++}
++
++
++
++LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
++  TValue n;
++  const TValue *o = index2adr(L, idx);
++  if (tonumber(o, &n))
++    return nvalue(o);
++  else
++    return 0;
++}
++
++
++LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
++  TValue n;
++  const TValue *o = index2adr(L, idx);
++  if (tonumber(o, &n)) {
++    lua_Integer res;
++    lua_Number num = nvalue(o);
++    lua_number2integer(res, num);
++    return res;
++  }
++  else
++    return 0;
++}
++
++
++LUA_API int lua_toboolean (lua_State *L, int idx) {
++  const TValue *o = index2adr(L, idx);
++  return !l_isfalse(o);
++}
++
++
++LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
++  StkId o = index2adr(L, idx);
++  if (!ttisstring(o)) {
++    lua_lock(L);  /* `luaV_tostring' may create a new string */
++    if (!luaV_tostring(L, o)) {  /* conversion failed? */
++      if (len != NULL) *len = 0;
++      lua_unlock(L);
++      return NULL;
++    }
++    luaC_checkGC(L);
++    o = index2adr(L, idx);  /* previous call may reallocate the stack */
++    lua_unlock(L);
++  }
++  if (len != NULL) *len = tsvalue(o)->len;
++  return svalue(o);
++}
++
++
++LUA_API size_t lua_objlen (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  switch (ttype(o)) {
++    case LUA_TSTRING: return tsvalue(o)->len;
++    case LUA_TUSERDATA: return uvalue(o)->len;
++    case LUA_TTABLE: return luaH_getn(hvalue(o));
++    case LUA_TNUMBER: {
++      size_t l;
++      lua_lock(L);  /* `luaV_tostring' may create a new string */
++      l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0);
++      lua_unlock(L);
++      return l;
++    }
++    default: return 0;
++  }
++}
++
++
++LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  return (!iscfunction(o)) ? NULL : clvalue(o)->c.f;
++}
++
++
++LUA_API void *lua_touserdata (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  switch (ttype(o)) {
++    case LUA_TUSERDATA: return (rawuvalue(o) + 1);
++    case LUA_TLIGHTUSERDATA: return pvalue(o);
++    default: return NULL;
++  }
++}
++
++
++LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  return (!ttisthread(o)) ? NULL : thvalue(o);
++}
++
++
++LUA_API const void *lua_topointer (lua_State *L, int idx) {
++  StkId o = index2adr(L, idx);
++  switch (ttype(o)) {
++    case LUA_TTABLE: return hvalue(o);
++    case LUA_TFUNCTION: return clvalue(o);
++    case LUA_TTHREAD: return thvalue(o);
++    case LUA_TUSERDATA:
++    case LUA_TLIGHTUSERDATA:
++      return lua_touserdata(L, idx);
++    default: return NULL;
++  }
++}
++
++
++
++/*
++** push functions (C -> stack)
++*/
++
++
++LUA_API void lua_pushnil (lua_State *L) {
++  lua_lock(L);
++  setnilvalue(L->top);
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
++  lua_lock(L);
++  setnvalue(L->top, n);
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
++  lua_lock(L);
++  setnvalue(L->top, cast_num(n));
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
++  lua_lock(L);
++  luaC_checkGC(L);
++  setsvalue2s(L, L->top, luaS_newlstr(L, s, len));
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushstring (lua_State *L, const char *s) {
++  if (s == NULL)
++    lua_pushnil(L);
++  else
++    lua_pushlstring(L, s, strlen(s));
++}
++
++
++LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
++                                      va_list argp) {
++  const char *ret;
++  lua_lock(L);
++  luaC_checkGC(L);
++  ret = luaO_pushvfstring(L, fmt, argp);
++  lua_unlock(L);
++  return ret;
++}
++
++
++LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
++  const char *ret;
++  va_list argp;
++  lua_lock(L);
++  luaC_checkGC(L);
++  va_start(argp, fmt);
++  ret = luaO_pushvfstring(L, fmt, argp);
++  va_end(argp);
++  lua_unlock(L);
++  return ret;
++}
++
++
++LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
++  Closure *cl;
++  lua_lock(L);
++  luaC_checkGC(L);
++  api_checknelems(L, n);
++  cl = luaF_newCclosure(L, n, getcurrenv(L));
++  cl->c.f = fn;
++  L->top -= n;
++  while (n--)
++    setobj2n(L, &cl->c.upvalue[n], L->top+n);
++  setclvalue(L, L->top, cl);
++  lua_assert(iswhite(obj2gco(cl)));
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushboolean (lua_State *L, int b) {
++  lua_lock(L);
++  setbvalue(L->top, (b != 0));  /* ensure that true is 1 */
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
++  lua_lock(L);
++  setpvalue(L->top, p);
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API int lua_pushthread (lua_State *L) {
++  lua_lock(L);
++  setthvalue(L, L->top, L);
++  api_incr_top(L);
++  lua_unlock(L);
++  return (G(L)->mainthread == L);
++}
++
++
++
++/*
++** get functions (Lua -> stack)
++*/
++
++
++LUA_API void lua_gettable (lua_State *L, int idx) {
++  StkId t;
++  lua_lock(L);
++  t = index2adr(L, idx);
++  api_checkvalidindex(L, t);
++  luaV_gettable(L, t, L->top - 1, L->top - 1);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
++  StkId t;
++  TValue key;
++  lua_lock(L);
++  t = index2adr(L, idx);
++  api_checkvalidindex(L, t);
++  setsvalue(L, &key, luaS_new(L, k));
++  luaV_gettable(L, t, &key, L->top);
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_rawget (lua_State *L, int idx) {
++  StkId t;
++  lua_lock(L);
++  t = index2adr(L, idx);
++  api_check(L, ttistable(t));
++  setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_rawgeti (lua_State *L, int idx, int n) {
++  StkId o;
++  lua_lock(L);
++  o = index2adr(L, idx);
++  api_check(L, ttistable(o));
++  setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
++  lua_lock(L);
++  luaC_checkGC(L);
++  sethvalue(L, L->top, luaH_new(L, narray, nrec));
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++LUA_API int lua_getmetatable (lua_State *L, int objindex) {
++  const TValue *obj;
++  Table *mt = NULL;
++  int res;
++  lua_lock(L);
++  obj = index2adr(L, objindex);
++  switch (ttype(obj)) {
++    case LUA_TTABLE:
++      mt = hvalue(obj)->metatable;
++      break;
++    case LUA_TUSERDATA:
++      mt = uvalue(obj)->metatable;
++      break;
++    default:
++      mt = G(L)->mt[ttype(obj)];
++      break;
++  }
++  if (mt == NULL)
++    res = 0;
++  else {
++    sethvalue(L, L->top, mt);
++    api_incr_top(L);
++    res = 1;
++  }
++  lua_unlock(L);
++  return res;
++}
++
++
++LUA_API void lua_getfenv (lua_State *L, int idx) {
++  StkId o;
++  lua_lock(L);
++  o = index2adr(L, idx);
++  api_checkvalidindex(L, o);
++  switch (ttype(o)) {
++    case LUA_TFUNCTION:
++      sethvalue(L, L->top, clvalue(o)->c.env);
++      break;
++    case LUA_TUSERDATA:
++      sethvalue(L, L->top, uvalue(o)->env);
++      break;
++    case LUA_TTHREAD:
++      setobj2s(L, L->top,  gt(thvalue(o)));
++      break;
++    default:
++      setnilvalue(L->top);
++      break;
++  }
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++/*
++** set functions (stack -> Lua)
++*/
++
++
++LUA_API void lua_settable (lua_State *L, int idx) {
++  StkId t;
++  lua_lock(L);
++  api_checknelems(L, 2);
++  t = index2adr(L, idx);
++  api_checkvalidindex(L, t);
++  luaV_settable(L, t, L->top - 2, L->top - 1);
++  L->top -= 2;  /* pop index and value */
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
++  StkId t;
++  TValue key;
++  lua_lock(L);
++  api_checknelems(L, 1);
++  t = index2adr(L, idx);
++  api_checkvalidindex(L, t);
++  setsvalue(L, &key, luaS_new(L, k));
++  luaV_settable(L, t, &key, L->top - 1);
++  L->top--;  /* pop value */
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_rawset (lua_State *L, int idx) {
++  StkId t;
++  lua_lock(L);
++  api_checknelems(L, 2);
++  t = index2adr(L, idx);
++  api_check(L, ttistable(t));
++  setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
++  luaC_barriert(L, hvalue(t), L->top-1);
++  L->top -= 2;
++  lua_unlock(L);
++}
++
++
++LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
++  StkId o;
++  lua_lock(L);
++  api_checknelems(L, 1);
++  o = index2adr(L, idx);
++  api_check(L, ttistable(o));
++  setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
++  luaC_barriert(L, hvalue(o), L->top-1);
++  L->top--;
++  lua_unlock(L);
++}
++
++
++LUA_API int lua_setmetatable (lua_State *L, int objindex) {
++  TValue *obj;
++  Table *mt;
++  lua_lock(L);
++  api_checknelems(L, 1);
++  obj = index2adr(L, objindex);
++  api_checkvalidindex(L, obj);
++  if (ttisnil(L->top - 1))
++    mt = NULL;
++  else {
++    api_check(L, ttistable(L->top - 1));
++    mt = hvalue(L->top - 1);
++  }
++  switch (ttype(obj)) {
++    case LUA_TTABLE: {
++      hvalue(obj)->metatable = mt;
++      if (mt)
++        luaC_objbarriert(L, hvalue(obj), mt);
++      break;
++    }
++    case LUA_TUSERDATA: {
++      uvalue(obj)->metatable = mt;
++      if (mt)
++        luaC_objbarrier(L, rawuvalue(obj), mt);
++      break;
++    }
++    default: {
++      G(L)->mt[ttype(obj)] = mt;
++      break;
++    }
++  }
++  L->top--;
++  lua_unlock(L);
++  return 1;
++}
++
++
++LUA_API int lua_setfenv (lua_State *L, int idx) {
++  StkId o;
++  int res = 1;
++  lua_lock(L);
++  api_checknelems(L, 1);
++  o = index2adr(L, idx);
++  api_checkvalidindex(L, o);
++  api_check(L, ttistable(L->top - 1));
++  switch (ttype(o)) {
++    case LUA_TFUNCTION:
++      clvalue(o)->c.env = hvalue(L->top - 1);
++      break;
++    case LUA_TUSERDATA:
++      uvalue(o)->env = hvalue(L->top - 1);
++      break;
++    case LUA_TTHREAD:
++      sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1));
++      break;
++    default:
++      res = 0;
++      break;
++  }
++  if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
++  L->top--;
++  lua_unlock(L);
++  return res;
++}
++
++
++/*
++** `load' and `call' functions (run Lua code)
++*/
++
++
++#define adjustresults(L,nres) \
++    { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; }
++
++
++#define checkresults(L,na,nr) \
++     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)))
++	
++
++LUA_API void lua_call (lua_State *L, int nargs, int nresults) {
++  StkId func;
++  lua_lock(L);
++  api_checknelems(L, nargs+1);
++  checkresults(L, nargs, nresults);
++  func = L->top - (nargs+1);
++  luaD_call(L, func, nresults);
++  adjustresults(L, nresults);
++  lua_unlock(L);
++}
++
++
++
++/*
++** Execute a protected call.
++*/
++struct CallS {  /* data to `f_call' */
++  StkId func;
++  int nresults;
++};
++
++
++static void f_call (lua_State *L, void *ud) {
++  struct CallS *c = cast(struct CallS *, ud);
++  luaD_call(L, c->func, c->nresults);
++}
++
++
++
++LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
++  struct CallS c;
++  int status;
++  ptrdiff_t func;
++  lua_lock(L);
++  api_checknelems(L, nargs+1);
++  checkresults(L, nargs, nresults);
++  if (errfunc == 0)
++    func = 0;
++  else {
++    StkId o = index2adr(L, errfunc);
++    api_checkvalidindex(L, o);
++    func = savestack(L, o);
++  }
++  c.func = L->top - (nargs+1);  /* function to be called */
++  c.nresults = nresults;
++  status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
++  adjustresults(L, nresults);
++  lua_unlock(L);
++  return status;
++}
++
++
++/*
++** Execute a protected C call.
++*/
++struct CCallS {  /* data to `f_Ccall' */
++  lua_CFunction func;
++  void *ud;
++};
++
++
++static void f_Ccall (lua_State *L, void *ud) {
++  struct CCallS *c = cast(struct CCallS *, ud);
++  Closure *cl;
++  cl = luaF_newCclosure(L, 0, getcurrenv(L));
++  cl->c.f = c->func;
++  setclvalue(L, L->top, cl);  /* push function */
++  api_incr_top(L);
++  setpvalue(L->top, c->ud);  /* push only argument */
++  api_incr_top(L);
++  luaD_call(L, L->top - 2, 0);
++}
++
++
++LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) {
++  struct CCallS c;
++  int status;
++  lua_lock(L);
++  c.func = func;
++  c.ud = ud;
++  status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0);
++  lua_unlock(L);
++  return status;
++}
++
++
++LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
++                      const char *chunkname) {
++  ZIO z;
++  int status;
++  lua_lock(L);
++  if (!chunkname) chunkname = "?";
++  luaZ_init(L, &z, reader, data);
++  status = luaD_protectedparser(L, &z, chunkname);
++  lua_unlock(L);
++  return status;
++}
++
++
++LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
++  int status;
++  TValue *o;
++  lua_lock(L);
++  api_checknelems(L, 1);
++  o = L->top - 1;
++  if (isLfunction(o))
++    status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0);
++  else
++    status = 1;
++  lua_unlock(L);
++  return status;
++}
++
++
++LUA_API int  lua_status (lua_State *L) {
++  return L->status;
++}
++
++
++/*
++** Garbage-collection function
++*/
++
++LUA_API int lua_gc (lua_State *L, int what, int data) {
++  int res = 0;
++  global_State *g;
++  lua_lock(L);
++  g = G(L);
++  switch (what) {
++    case LUA_GCSTOP: {
++      g->GCthreshold = MAX_LUMEM;
++      break;
++    }
++    case LUA_GCRESTART: {
++      g->GCthreshold = g->totalbytes;
++      break;
++    }
++    case LUA_GCCOLLECT: {
++      luaC_fullgc(L);
++      break;
++    }
++    case LUA_GCCOUNT: {
++      /* GC values are expressed in Kbytes: #bytes/2^10 */
++      res = cast_int(g->totalbytes >> 10);
++      break;
++    }
++    case LUA_GCCOUNTB: {
++      res = cast_int(g->totalbytes & 0x3ff);
++      break;
++    }
++    case LUA_GCSTEP: {
++      lu_mem a = (cast(lu_mem, data) << 10);
++      if (a <= g->totalbytes)
++        g->GCthreshold = g->totalbytes - a;
++      else
++        g->GCthreshold = 0;
++      while (g->GCthreshold <= g->totalbytes) {
++        luaC_step(L);
++        if (g->gcstate == GCSpause) {  /* end of cycle? */
++          res = 1;  /* signal it */
++          break;
++        }
++      }
++      break;
++    }
++    case LUA_GCSETPAUSE: {
++      res = g->gcpause;
++      g->gcpause = data;
++      break;
++    }
++    case LUA_GCSETSTEPMUL: {
++      res = g->gcstepmul;
++      g->gcstepmul = data;
++      break;
++    }
++    default: res = -1;  /* invalid option */
++  }
++  lua_unlock(L);
++  return res;
++}
++
++
++
++/*
++** miscellaneous functions
++*/
++
++
++LUA_API int lua_error (lua_State *L) {
++  lua_lock(L);
++  api_checknelems(L, 1);
++  luaG_errormsg(L);
++  lua_unlock(L);
++  return 0;  /* to avoid warnings */
++}
++
++
++LUA_API int lua_next (lua_State *L, int idx) {
++  StkId t;
++  int more;
++  lua_lock(L);
++  t = index2adr(L, idx);
++  api_check(L, ttistable(t));
++  more = luaH_next(L, hvalue(t), L->top - 1);
++  if (more) {
++    api_incr_top(L);
++  }
++  else  /* no more elements */
++    L->top -= 1;  /* remove key */
++  lua_unlock(L);
++  return more;
++}
++
++
++LUA_API void lua_concat (lua_State *L, int n) {
++  lua_lock(L);
++  api_checknelems(L, n);
++  if (n >= 2) {
++    luaC_checkGC(L);
++    luaV_concat(L, n, cast_int(L->top - L->base) - 1);
++    L->top -= (n-1);
++  }
++  else if (n == 0) {  /* push empty string */
++    setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
++    api_incr_top(L);
++  }
++  /* else n == 1; nothing to do */
++  lua_unlock(L);
++}
++
++
++LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) {
++  lua_Alloc f;
++  lua_lock(L);
++  if (ud) *ud = G(L)->ud;
++  f = G(L)->frealloc;
++  lua_unlock(L);
++  return f;
++}
++
++
++LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
++  lua_lock(L);
++  G(L)->ud = ud;
++  G(L)->frealloc = f;
++  lua_unlock(L);
++}
++
++
++LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
++  Udata *u;
++  lua_lock(L);
++  luaC_checkGC(L);
++  u = luaS_newudata(L, size, getcurrenv(L));
++  setuvalue(L, L->top, u);
++  api_incr_top(L);
++  lua_unlock(L);
++  return u + 1;
++}
++
++
++
++
++static const char *aux_upvalue (StkId fi, int n, TValue **val) {
++  Closure *f;
++  if (!ttisfunction(fi)) return NULL;
++  f = clvalue(fi);
++  if (f->c.isC) {
++    if (!(1 <= n && n <= f->c.nupvalues)) return NULL;
++    *val = &f->c.upvalue[n-1];
++    return "";
++  }
++  else {
++    Proto *p = f->l.p;
++    if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
++    *val = f->l.upvals[n-1]->v;
++    return getstr(p->upvalues[n-1]);
++  }
++}
++
++
++LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
++  const char *name;
++  TValue *val;
++  lua_lock(L);
++  name = aux_upvalue(index2adr(L, funcindex), n, &val);
++  if (name) {
++    setobj2s(L, L->top, val);
++    api_incr_top(L);
++  }
++  lua_unlock(L);
++  return name;
++}
++
++
++LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
++  const char *name;
++  TValue *val;
++  StkId fi;
++  lua_lock(L);
++  fi = index2adr(L, funcindex);
++  api_checknelems(L, 1);
++  name = aux_upvalue(fi, n, &val);
++  if (name) {
++    L->top--;
++    setobj(L, val, L->top);
++    luaC_barrier(L, clvalue(fi), L->top);
++  }
++  lua_unlock(L);
++  return name;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lapi.h
+@@ -0,0 +1,16 @@
++/*
++** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $
++** Auxiliary functions from Lua API
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lapi_h
++#define lapi_h
++
++
++#include "lobject.h"
++
++
++LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lauxlib.c
+@@ -0,0 +1,674 @@
++/*
++** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $
++** Auxiliary functions for building Lua libraries
++** See Copyright Notice in lua.h
++*/
++
++#include <stdarg.h>
++
++#if !defined(__KERNEL__)
++#include <ctype.h>
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#else
++#include <linux/ctype.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#endif
++
++/* This file uses only the official API of Lua.
++** Any function declared here could be written as an application function.
++*/
++
++#define lauxlib_c
++#define LUA_LIB
++
++#include "lua.h"
++
++#include "lauxlib.h"
++
++
++#define FREELIST_REF	0	/* free list of references */
++
++
++/* convert a stack index to positive */
++#define abs_index(L, i)		((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
++					lua_gettop(L) + (i) + 1)
++
++
++/*
++** {======================================================
++** Error-report functions
++** =======================================================
++*/
++
++
++LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
++  lua_Debug ar;
++  if (!lua_getstack(L, 0, &ar))  /* no stack frame? */
++    return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
++  lua_getinfo(L, "n", &ar);
++  if (strcmp(ar.namewhat, "method") == 0) {
++    narg--;  /* do not count `self' */
++    if (narg == 0)  /* error is in the self argument itself? */
++      return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
++                           ar.name, extramsg);
++  }
++  if (ar.name == NULL)
++    ar.name = "?";
++  return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
++                        narg, ar.name, extramsg);
++}
++
++
++LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
++  const char *msg = lua_pushfstring(L, "%s expected, got %s",
++                                    tname, luaL_typename(L, narg));
++  return luaL_argerror(L, narg, msg);
++}
++
++
++static void tag_error (lua_State *L, int narg, int tag) {
++  luaL_typerror(L, narg, lua_typename(L, tag));
++}
++
++
++LUALIB_API void luaL_where (lua_State *L, int level) {
++  lua_Debug ar;
++  if (lua_getstack(L, level, &ar)) {  /* check function at level */
++    lua_getinfo(L, "Sl", &ar);  /* get info about it */
++    if (ar.currentline > 0) {  /* is there info? */
++      lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
++      return;
++    }
++  }
++  lua_pushliteral(L, "");  /* else, no information available... */
++}
++
++
++LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
++  va_list argp;
++  va_start(argp, fmt);
++  luaL_where(L, 1);
++  lua_pushvfstring(L, fmt, argp);
++  va_end(argp);
++  lua_concat(L, 2);
++  return lua_error(L);
++}
++
++/* }====================================================== */
++
++
++LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
++                                 const char *const lst[]) {
++  const char *name = (def) ? luaL_optstring(L, narg, def) :
++                             luaL_checkstring(L, narg);
++  int i;
++  for (i=0; lst[i]; i++)
++    if (strcmp(lst[i], name) == 0)
++      return i;
++  return luaL_argerror(L, narg,
++                       lua_pushfstring(L, "invalid option " LUA_QS, name));
++}
++
++
++LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
++  lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get registry.name */
++  if (!lua_isnil(L, -1))  /* name already in use? */
++    return 0;  /* leave previous value on top, but return 0 */
++  lua_pop(L, 1);
++  lua_newtable(L);  /* create metatable */
++  lua_pushvalue(L, -1);
++  lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */
++  return 1;
++}
++
++
++LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
++  void *p = lua_touserdata(L, ud);
++  if (p != NULL) {  /* value is a userdata? */
++    if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
++      lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get correct metatable */
++      if (lua_rawequal(L, -1, -2)) {  /* does it have the correct mt? */
++        lua_pop(L, 2);  /* remove both metatables */
++        return p;
++      }
++    }
++  }
++  luaL_typerror(L, ud, tname);  /* else error */
++  return NULL;  /* to avoid warnings */
++}
++
++
++LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
++  if (!lua_checkstack(L, space))
++    luaL_error(L, "stack overflow (%s)", mes);
++}
++
++
++LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
++  if (lua_type(L, narg) != t)
++    tag_error(L, narg, t);
++}
++
++
++LUALIB_API void luaL_checkany (lua_State *L, int narg) {
++  if (lua_type(L, narg) == LUA_TNONE)
++    luaL_argerror(L, narg, "value expected");
++}
++
++
++LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
++  const char *s = lua_tolstring(L, narg, len);
++  if (!s) tag_error(L, narg, LUA_TSTRING);
++  return s;
++}
++
++
++LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
++                                        const char *def, size_t *len) {
++  if (lua_isnoneornil(L, narg)) {
++    if (len)
++      *len = (def ? strlen(def) : 0);
++    return def;
++  }
++  else return luaL_checklstring(L, narg, len);
++}
++
++
++LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
++  lua_Number d = lua_tonumber(L, narg);
++  if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
++    tag_error(L, narg, LUA_TNUMBER);
++  return d;
++}
++
++
++LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
++  return luaL_opt(L, luaL_checknumber, narg, def);
++}
++
++
++LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
++  lua_Integer d = lua_tointeger(L, narg);
++  if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
++    tag_error(L, narg, LUA_TNUMBER);
++  return d;
++}
++
++
++LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
++                                                      lua_Integer def) {
++  return luaL_opt(L, luaL_checkinteger, narg, def);
++}
++
++
++LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
++  if (!lua_getmetatable(L, obj))  /* no metatable? */
++    return 0;
++  lua_pushstring(L, event);
++  lua_rawget(L, -2);
++  if (lua_isnil(L, -1)) {
++    lua_pop(L, 2);  /* remove metatable and metafield */
++    return 0;
++  }
++  else {
++    lua_remove(L, -2);  /* remove only metatable */
++    return 1;
++  }
++}
++
++
++LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
++  obj = abs_index(L, obj);
++  if (!luaL_getmetafield(L, obj, event))  /* no metafield? */
++    return 0;
++  lua_pushvalue(L, obj);
++  lua_call(L, 1, 1);
++  return 1;
++}
++
++
++LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
++                                const luaL_Reg *l) {
++  luaI_openlib(L, libname, l, 0);
++}
++
++
++static int libsize (const luaL_Reg *l) {
++  int size = 0;
++  for (; l->name; l++) size++;
++  return size;
++}
++
++
++LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
++                              const luaL_Reg *l, int nup) {
++  if (libname) {
++    int size = libsize(l);
++    /* check whether lib already exists */
++    luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
++    lua_getfield(L, -1, libname);  /* get _LOADED[libname] */
++    if (!lua_istable(L, -1)) {  /* not found? */
++      lua_pop(L, 1);  /* remove previous result */
++      /* try global variable (and create one if it does not exist) */
++      if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
++        luaL_error(L, "name conflict for module " LUA_QS, libname);
++      lua_pushvalue(L, -1);
++      lua_setfield(L, -3, libname);  /* _LOADED[libname] = new table */
++    }
++    lua_remove(L, -2);  /* remove _LOADED table */
++    lua_insert(L, -(nup+1));  /* move library table to below upvalues */
++  }
++  for (; l->name; l++) {
++    int i;
++    for (i=0; i<nup; i++)  /* copy upvalues to the top */
++      lua_pushvalue(L, -nup);
++    lua_pushcclosure(L, l->func, nup);
++    lua_setfield(L, -(nup+2), l->name);
++  }
++  lua_pop(L, nup);  /* remove upvalues */
++}
++
++
++
++/*
++** {======================================================
++** getn-setn: size for arrays
++** =======================================================
++*/
++
++#if defined(LUA_COMPAT_GETN)
++
++static int checkint (lua_State *L, int topop) {
++  int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1;
++  lua_pop(L, topop);
++  return n;
++}
++
++
++static void getsizes (lua_State *L) {
++  lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");
++  if (lua_isnil(L, -1)) {  /* no `size' table? */
++    lua_pop(L, 1);  /* remove nil */
++    lua_newtable(L);  /* create it */
++    lua_pushvalue(L, -1);  /* `size' will be its own metatable */
++    lua_setmetatable(L, -2);
++    lua_pushliteral(L, "kv");
++    lua_setfield(L, -2, "__mode");  /* metatable(N).__mode = "kv" */
++    lua_pushvalue(L, -1);
++    lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");  /* store in register */
++  }
++}
++
++
++LUALIB_API void luaL_setn (lua_State *L, int t, int n) {
++  t = abs_index(L, t);
++  lua_pushliteral(L, "n");
++  lua_rawget(L, t);
++  if (checkint(L, 1) >= 0) {  /* is there a numeric field `n'? */
++    lua_pushliteral(L, "n");  /* use it */
++    lua_pushinteger(L, n);
++    lua_rawset(L, t);
++  }
++  else {  /* use `sizes' */
++    getsizes(L);
++    lua_pushvalue(L, t);
++    lua_pushinteger(L, n);
++    lua_rawset(L, -3);  /* sizes[t] = n */
++    lua_pop(L, 1);  /* remove `sizes' */
++  }
++}
++
++
++LUALIB_API int luaL_getn (lua_State *L, int t) {
++  int n;
++  t = abs_index(L, t);
++  lua_pushliteral(L, "n");  /* try t.n */
++  lua_rawget(L, t);
++  if ((n = checkint(L, 1)) >= 0) return n;
++  getsizes(L);  /* else try sizes[t] */
++  lua_pushvalue(L, t);
++  lua_rawget(L, -2);
++  if ((n = checkint(L, 2)) >= 0) return n;
++  return (int)lua_objlen(L, t);
++}
++
++#endif
++
++/* }====================================================== */
++
++
++
++LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
++                                                               const char *r) {
++  const char *wild;
++  size_t l = strlen(p);
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "luaL_gsub: cannot allocate memory");
++  luaL_buffinit(L, b);
++  while ((wild = strstr(s, p)) != NULL) {
++    luaL_addlstring(b, s, wild - s);  /* push prefix */
++    luaL_addstring(b, r);  /* push replacement in place of pattern */
++    s = wild + l;  /* continue after `p' */
++  }
++  luaL_addstring(b, s);  /* push last suffix */
++  luaL_pushresult(b);
++  kfree(b);
++  return lua_tostring(L, -1);
++}
++
++
++LUALIB_API const char *luaL_findtable (lua_State *L, int idx,
++                                       const char *fname, int szhint) {
++  const char *e;
++  lua_pushvalue(L, idx);
++  do {
++    e = strchr(fname, '.');
++    if (e == NULL) e = fname + strlen(fname);
++    lua_pushlstring(L, fname, e - fname);
++    lua_rawget(L, -2);
++    if (lua_isnil(L, -1)) {  /* no such field? */
++      lua_pop(L, 1);  /* remove this nil */
++      lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
++      lua_pushlstring(L, fname, e - fname);
++      lua_pushvalue(L, -2);
++      lua_settable(L, -4);  /* set new table into field */
++    }
++    else if (!lua_istable(L, -1)) {  /* field has a non-table value? */
++      lua_pop(L, 2);  /* remove table and value */
++      return fname;  /* return problematic part of the name */
++    }
++    lua_remove(L, -2);  /* remove previous table */
++    fname = e + 1;
++  } while (*e == '.');
++  return NULL;
++}
++
++
++
++/*
++** {======================================================
++** Generic Buffer manipulation
++** =======================================================
++*/
++
++
++#define bufflen(B)	((B)->p - (B)->buffer)
++#define bufffree(B)	((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
++
++#define LIMIT	(LUA_MINSTACK/2)
++
++
++static int emptybuffer (luaL_Buffer *B) {
++  size_t l = bufflen(B);
++  if (l == 0) return 0;  /* put nothing on stack */
++  else {
++    lua_pushlstring(B->L, B->buffer, l);
++    B->p = B->buffer;
++    B->lvl++;
++    return 1;
++  }
++}
++
++
++static void adjuststack (luaL_Buffer *B) {
++  if (B->lvl > 1) {
++    lua_State *L = B->L;
++    int toget = 1;  /* number of levels to concat */
++    size_t toplen = lua_strlen(L, -1);
++    do {
++      size_t l = lua_strlen(L, -(toget+1));
++      if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
++        toplen += l;
++        toget++;
++      }
++      else break;
++    } while (toget < B->lvl);
++    lua_concat(L, toget);
++    B->lvl = B->lvl - toget + 1;
++  }
++}
++
++
++LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
++  if (emptybuffer(B))
++    adjuststack(B);
++  return B->buffer;
++}
++
++
++LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
++  while (l--)
++    luaL_addchar(B, *s++);
++}
++
++
++LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
++  luaL_addlstring(B, s, strlen(s));
++}
++
++
++LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
++  emptybuffer(B);
++  lua_concat(B->L, B->lvl);
++  B->lvl = 1;
++}
++
++
++LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
++  lua_State *L = B->L;
++  size_t vl;
++  const char *s = lua_tolstring(L, -1, &vl);
++  if (vl <= bufffree(B)) {  /* fit into buffer? */
++    memcpy(B->p, s, vl);  /* put it there */
++    B->p += vl;
++    lua_pop(L, 1);  /* remove from stack */
++  }
++  else {
++    if (emptybuffer(B))
++      lua_insert(L, -2);  /* put buffer before new value */
++    B->lvl++;  /* add new value into B stack */
++    adjuststack(B);
++  }
++}
++
++
++LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
++  B->L = L;
++  B->p = B->buffer;
++  B->lvl = 0;
++}
++
++/* }====================================================== */
++
++
++LUALIB_API int luaL_ref (lua_State *L, int t) {
++  int ref;
++  t = abs_index(L, t);
++  if (lua_isnil(L, -1)) {
++    lua_pop(L, 1);  /* remove from stack */
++    return LUA_REFNIL;  /* `nil' has a unique fixed reference */
++  }
++  lua_rawgeti(L, t, FREELIST_REF);  /* get first free element */
++  ref = (int)lua_tointeger(L, -1);  /* ref = t[FREELIST_REF] */
++  lua_pop(L, 1);  /* remove it from stack */
++  if (ref != 0) {  /* any free element? */
++    lua_rawgeti(L, t, ref);  /* remove it from list */
++    lua_rawseti(L, t, FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */
++  }
++  else {  /* no free elements */
++    ref = (int)lua_objlen(L, t);
++    ref++;  /* create new reference */
++  }
++  lua_rawseti(L, t, ref);
++  return ref;
++}
++
++
++LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
++  if (ref >= 0) {
++    t = abs_index(L, t);
++    lua_rawgeti(L, t, FREELIST_REF);
++    lua_rawseti(L, t, ref);  /* t[ref] = t[FREELIST_REF] */
++    lua_pushinteger(L, ref);
++    lua_rawseti(L, t, FREELIST_REF);  /* t[FREELIST_REF] = ref */
++  }
++}
++
++
++
++/*
++** {======================================================
++** Load functions
++** =======================================================
++*/
++
++#if !defined(__KERNEL__)
++typedef struct LoadF {
++  int extraline;
++  FILE *f;
++  char buff[LUAL_BUFFERSIZE];
++} LoadF;
++
++
++static const char *getF (lua_State *L, void *ud, size_t *size) {
++  LoadF *lf = (LoadF *)ud;
++  (void)L;
++  if (lf->extraline) {
++    lf->extraline = 0;
++    *size = 1;
++    return "\n";
++  }
++  if (feof(lf->f)) return NULL;
++  *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
++  return (*size > 0) ? lf->buff : NULL;
++}
++
++
++static int errfile (lua_State *L, const char *what, int fnameindex) {
++  const char *serr = strerror(errno);
++  const char *filename = lua_tostring(L, fnameindex) + 1;
++  lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
++  lua_remove(L, fnameindex);
++  return LUA_ERRFILE;
++}
++
++
++LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
++  LoadF lf;
++  int status, readstatus;
++  int c;
++  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
++  lf.extraline = 0;
++  if (filename == NULL) {
++    lua_pushliteral(L, "=stdin");
++    lf.f = stdin;
++  }
++  else {
++    lua_pushfstring(L, "@%s", filename);
++    lf.f = fopen(filename, "r");
++    if (lf.f == NULL) return errfile(L, "open", fnameindex);
++  }
++  c = getc(lf.f);
++  if (c == '#') {  /* Unix exec. file? */
++    lf.extraline = 1;
++    while ((c = getc(lf.f)) != EOF && c != '\n') ;  /* skip first line */
++    if (c == '\n') c = getc(lf.f);
++  }
++  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
++    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
++    if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
++    /* skip eventual `#!...' */
++   while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
++    lf.extraline = 0;
++  }
++  ungetc(c, lf.f);
++  status = lua_load(L, getF, &lf, lua_tostring(L, -1));
++  readstatus = ferror(lf.f);
++  if (filename) fclose(lf.f);  /* close file (even in case of errors) */
++  if (readstatus) {
++    lua_settop(L, fnameindex);  /* ignore results from `lua_load' */
++    return errfile(L, "read", fnameindex);
++  }
++  lua_remove(L, fnameindex);
++  return status;
++}
++#endif
++
++typedef struct LoadS {
++  const char *s;
++  size_t size;
++} LoadS;
++
++
++static const char *getS (lua_State *L, void *ud, size_t *size) {
++  LoadS *ls = (LoadS *)ud;
++  (void)L;
++  if (ls->size == 0) return NULL;
++  *size = ls->size;
++  ls->size = 0;
++  return ls->s;
++}
++
++
++LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
++                                const char *name) {
++  LoadS ls;
++  ls.s = buff;
++  ls.size = size;
++  return lua_load(L, getS, &ls, name);
++}
++
++
++LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
++  return luaL_loadbuffer(L, s, strlen(s), s);
++}
++
++
++
++/* }====================================================== */
++
++
++static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
++  (void)ud;
++  (void)osize;
++  if (nsize == 0) {
++#if !defined(__KERNEL__)
++    free(ptr);
++#else
++    kfree(ptr);
++#endif
++    return NULL;
++  }
++  else
++#if !defined(__KERNEL__)
++    return realloc(ptr, nsize);
++#else
++    return krealloc(ptr, nsize, GFP_ATOMIC);
++#endif
++}
++
++
++static int lpanic (lua_State *L) {
++  (void)L;  /* to avoid warnings */
++#if !defined(__KERNEL__)
++  fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
++#else
++  printk( "PANIC: unprotected error in call to Lua API (%s)\n",
++#endif
++                   lua_tostring(L, -1));
++  return 0;
++}
++
++
++LUALIB_API lua_State *luaL_newstate (void) {
++  lua_State *L = lua_newstate(l_alloc, NULL);
++  if (L) lua_atpanic(L, &lpanic);
++  return L;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lauxlib.h
+@@ -0,0 +1,184 @@
++/*
++** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
++** Auxiliary functions for building Lua libraries
++** See Copyright Notice in lua.h
++*/
++
++
++#ifndef lauxlib_h
++#define lauxlib_h
++
++
++#include <stddef.h>
++#include <linux/slab.h>	/* for kmalloc and kfree when allocating luaL_Buffer */
++
++#if !defined(__KERNEL__)
++#include <stdio.h>
++#endif
++
++#include "lua.h"
++
++
++#if defined(LUA_COMPAT_GETN)
++LUALIB_API int (luaL_getn) (lua_State *L, int t);
++LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
++#else
++#define luaL_getn(L,i)          ((int)lua_objlen(L, i))
++#define luaL_setn(L,i,j)        ((void)0)  /* no op! */
++#endif
++
++#if defined(LUA_COMPAT_OPENLIB)
++#define luaI_openlib	luaL_openlib
++#endif
++
++
++/* extra error code for `luaL_load' */
++#define LUA_ERRFILE     (LUA_ERRERR+1)
++
++
++typedef struct luaL_Reg {
++  const char *name;
++  lua_CFunction func;
++} luaL_Reg;
++
++
++
++LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname,
++                                const luaL_Reg *l, int nup);
++LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
++                                const luaL_Reg *l);
++LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
++LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
++LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
++LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
++LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
++                                                          size_t *l);
++LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
++                                          const char *def, size_t *l);
++LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
++LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
++
++LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
++LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
++                                          lua_Integer def);
++
++LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
++LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
++LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
++
++LUALIB_API int   (luaL_newmetatable) (lua_State *L, const char *tname);
++LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
++
++LUALIB_API void (luaL_where) (lua_State *L, int lvl);
++LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
++
++LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
++                                   const char *const lst[]);
++
++LUALIB_API int (luaL_ref) (lua_State *L, int t);
++LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
++
++#if !defined(__KERNEL__)
++LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
++#endif
++
++LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
++                                  const char *name);
++LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
++
++LUALIB_API lua_State *(luaL_newstate) (void);
++
++
++LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
++                                                  const char *r);
++
++LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
++                                         const char *fname, int szhint);
++
++
++
++
++/*
++** ===============================================================
++** some useful macros
++** ===============================================================
++*/
++
++#define luaL_argcheck(L, cond,numarg,extramsg)	\
++		((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
++#define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL))
++#define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL))
++#define luaL_checkint(L,n)	((int)luaL_checkinteger(L, (n)))
++#define luaL_optint(L,n,d)	((int)luaL_optinteger(L, (n), (d)))
++#define luaL_checklong(L,n)	((long)luaL_checkinteger(L, (n)))
++#define luaL_optlong(L,n,d)	((long)luaL_optinteger(L, (n), (d)))
++
++#define luaL_typename(L,i)	lua_typename(L, lua_type(L,(i)))
++
++#if !defined(__KERNEL__)
++#define luaL_dofile(L, fn) \
++	(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
++#endif
++
++#define luaL_dostring(L, s) \
++	(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
++
++#define luaL_getmetatable(L,n)	(lua_getfield(L, LUA_REGISTRYINDEX, (n)))
++
++#define luaL_opt(L,f,n,d)	(lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
++
++/*
++** {======================================================
++** Generic Buffer manipulation
++** =======================================================
++*/
++
++
++
++typedef struct luaL_Buffer {
++  char *p;			/* current position in buffer */
++  int lvl;  /* number of strings in the stack (level) */
++  lua_State *L;
++  char buffer[LUAL_BUFFERSIZE];
++} luaL_Buffer;
++
++#define luaL_addchar(B,c) \
++  ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
++   (*(B)->p++ = (char)(c)))
++
++/* compatibility only */
++#define luaL_putchar(B,c)	luaL_addchar(B,c)
++
++#define luaL_addsize(B,n)	((B)->p += (n))
++
++
++LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
++LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
++LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
++LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
++LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
++LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
++
++
++/* }====================================================== */
++
++
++/* compatibility with ref system */
++
++/* pre-defined references */
++#define LUA_NOREF       (-2)
++#define LUA_REFNIL      (-1)
++
++#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
++      (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
++
++#define lua_unref(L,ref)        luaL_unref(L, LUA_REGISTRYINDEX, (ref))
++
++#define lua_getref(L,ref)       lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
++
++
++#define luaL_reg	luaL_Reg
++
++#endif
++
++
+--- /dev/null
++++ b/extensions/LUA/lua/lbaselib.c
+@@ -0,0 +1,647 @@
++/*
++** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $
++** Basic library
++** See Copyright Notice in lua.h
++*/
++
++
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++
++#define lbaselib_c
++#define LUA_LIB
++
++#include "lua.h"
++
++#include "lauxlib.h"
++#include "lualib.h"
++
++
++
++
++/*
++** If your system does not support `stdout', you can just remove this function.
++** If you need, you can define your own `print' function, following this
++** model but changing `fputs' to put the strings at a proper place
++** (a console window or a log file, for instance).
++*/
++static int luaB_print (lua_State *L) {
++  int n = lua_gettop(L);  /* number of arguments */
++  int i;
++  lua_getglobal(L, "tostring");
++  for (i=1; i<=n; i++) {
++    const char *s;
++    lua_pushvalue(L, -1);  /* function to be called */
++    lua_pushvalue(L, i);   /* value to print */
++    lua_call(L, 1, 1);
++    s = lua_tostring(L, -1);  /* get result */
++    if (s == NULL)
++      return luaL_error(L, LUA_QL("tostring") " must return a string to "
++                           LUA_QL("print"));
++    printk(KERN_INFO "LUA[print]: %s", s);
++    lua_pop(L, 1);  /* pop result */
++  }
++  return 0;
++}
++
++
++static int luaB_tonumber (lua_State *L) {
++  int base = luaL_optint(L, 2, 10);
++  if (base == 10) {  /* standard conversion */
++    luaL_checkany(L, 1);
++    if (lua_isnumber(L, 1)) {
++      lua_pushnumber(L, lua_tonumber(L, 1));
++      return 1;
++    }
++  }
++  else {
++    const char *s1 = luaL_checkstring(L, 1);
++    char *s2;
++    unsigned long n;
++    luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
++    n = simple_strtoul(s1, &s2, base);
++    if (s1 != s2) {  /* at least one valid digit? */
++      while (isspace((unsigned char)(*s2))) s2++;  /* skip trailing spaces */
++      if (*s2 == '\0') {  /* no invalid trailing characters? */
++        lua_pushnumber(L, (lua_Number)n);
++        return 1;
++      }
++    }
++  }
++  lua_pushnil(L);  /* else not a number */
++  return 1;
++}
++
++
++static int luaB_error (lua_State *L) {
++  int level = luaL_optint(L, 2, 1);
++  lua_settop(L, 1);
++  if (lua_isstring(L, 1) && level > 0) {  /* add extra information? */
++    luaL_where(L, level);
++    lua_pushvalue(L, 1);
++    lua_concat(L, 2);
++  }
++  return lua_error(L);
++}
++
++
++static int luaB_getmetatable (lua_State *L) {
++  luaL_checkany(L, 1);
++  if (!lua_getmetatable(L, 1)) {
++    lua_pushnil(L);
++    return 1;  /* no metatable */
++  }
++  luaL_getmetafield(L, 1, "__metatable");
++  return 1;  /* returns either __metatable field (if present) or metatable */
++}
++
++
++static int luaB_setmetatable (lua_State *L) {
++  int t = lua_type(L, 2);
++  luaL_checktype(L, 1, LUA_TTABLE);
++  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
++                    "nil or table expected");
++  if (luaL_getmetafield(L, 1, "__metatable"))
++    luaL_error(L, "cannot change a protected metatable");
++  lua_settop(L, 2);
++  lua_setmetatable(L, 1);
++  return 1;
++}
++
++
++static void getfunc (lua_State *L, int opt) {
++  if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
++  else {
++    lua_Debug ar;
++    int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
++    luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
++    if (lua_getstack(L, level, &ar) == 0)
++      luaL_argerror(L, 1, "invalid level");
++    lua_getinfo(L, "f", &ar);
++    if (lua_isnil(L, -1))
++      luaL_error(L, "no function environment for tail call at level %d",
++                    level);
++  }
++}
++
++
++static int luaB_getfenv (lua_State *L) {
++  getfunc(L, 1);
++  if (lua_iscfunction(L, -1))  /* is a C function? */
++    lua_pushvalue(L, LUA_GLOBALSINDEX);  /* return the thread's global env. */
++  else
++    lua_getfenv(L, -1);
++  return 1;
++}
++
++
++static int luaB_setfenv (lua_State *L) {
++  luaL_checktype(L, 2, LUA_TTABLE);
++  getfunc(L, 0);
++  lua_pushvalue(L, 2);
++  if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
++    /* change environment of current thread */
++    lua_pushthread(L);
++    lua_insert(L, -2);
++    lua_setfenv(L, -2);
++    return 0;
++  }
++  else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
++    luaL_error(L,
++          LUA_QL("setfenv") " cannot change environment of given object");
++  return 1;
++}
++
++
++static int luaB_rawequal (lua_State *L) {
++  luaL_checkany(L, 1);
++  luaL_checkany(L, 2);
++  lua_pushboolean(L, lua_rawequal(L, 1, 2));
++  return 1;
++}
++
++
++static int luaB_rawget (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  luaL_checkany(L, 2);
++  lua_settop(L, 2);
++  lua_rawget(L, 1);
++  return 1;
++}
++
++static int luaB_rawset (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  luaL_checkany(L, 2);
++  luaL_checkany(L, 3);
++  lua_settop(L, 3);
++  lua_rawset(L, 1);
++  return 1;
++}
++
++
++static int luaB_gcinfo (lua_State *L) {
++  lua_pushinteger(L, lua_getgccount(L));
++  return 1;
++}
++
++static int luaB_collectgarbage (lua_State *L) {
++  static const char *const opts[] = {"stop", "restart", "collect",
++    "count", "step", "setpause", "setstepmul", NULL};
++  static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
++    LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
++  int o = luaL_checkoption(L, 1, "collect", opts);
++  int ex = luaL_optint(L, 2, 0);
++  int res = lua_gc(L, optsnum[o], ex);
++  switch (optsnum[o]) {
++    case LUA_GCCOUNT: {
++      int b = lua_gc(L, LUA_GCCOUNTB, 0);
++      lua_pushnumber(L, res + ((lua_Number)b/1024));
++      return 1;
++    }
++    case LUA_GCSTEP: {
++      lua_pushboolean(L, res);
++      return 1;
++    }
++    default: {
++      lua_pushnumber(L, res);
++      return 1;
++    }
++  }
++}
++
++
++static int luaB_type (lua_State *L) {
++  luaL_checkany(L, 1);
++  lua_pushstring(L, luaL_typename(L, 1));
++  return 1;
++}
++
++
++static int luaB_next (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  lua_settop(L, 2);  /* create a 2nd argument if there isn't one */
++  if (lua_next(L, 1))
++    return 2;
++  else {
++    lua_pushnil(L);
++    return 1;
++  }
++}
++
++
++static int luaB_pairs (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */
++  lua_pushvalue(L, 1);  /* state, */
++  lua_pushnil(L);  /* and initial value */
++  return 3;
++}
++
++
++static int ipairsaux (lua_State *L) {
++  int i = luaL_checkint(L, 2);
++  luaL_checktype(L, 1, LUA_TTABLE);
++  i++;  /* next value */
++  lua_pushinteger(L, i);
++  lua_rawgeti(L, 1, i);
++  return (lua_isnil(L, -1)) ? 0 : 2;
++}
++
++
++static int luaB_ipairs (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */
++  lua_pushvalue(L, 1);  /* state, */
++  lua_pushinteger(L, 0);  /* and initial value */
++  return 3;
++}
++
++
++static int load_aux (lua_State *L, int status) {
++  if (status == 0)  /* OK? */
++    return 1;
++  else {
++    lua_pushnil(L);
++    lua_insert(L, -2);  /* put before error message */
++    return 2;  /* return nil plus error message */
++  }
++}
++
++
++static int luaB_loadstring (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  const char *chunkname = luaL_optstring(L, 2, s);
++  return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
++}
++
++/*
++static int luaB_loadfile (lua_State *L) {
++  const char *fname = luaL_optstring(L, 1, NULL);
++  return load_aux(L, luaL_loadfile(L, fname));
++}
++*/
++
++/*
++** Reader for generic `load' function: `lua_load' uses the
++** stack for internal stuff, so the reader cannot change the
++** stack top. Instead, it keeps its resulting string in a
++** reserved slot inside the stack.
++*/
++static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
++  (void)ud;  /* to avoid warnings */
++  luaL_checkstack(L, 2, "too many nested functions");
++  lua_pushvalue(L, 1);  /* get function */
++  lua_call(L, 0, 1);  /* call it */
++  if (lua_isnil(L, -1)) {
++    *size = 0;
++    return NULL;
++  }
++  else if (lua_isstring(L, -1)) {
++    lua_replace(L, 3);  /* save string in a reserved stack slot */
++    return lua_tolstring(L, 3, size);
++  }
++  else luaL_error(L, "reader function must return a string");
++  return NULL;  /* to avoid warnings */
++}
++
++
++static int luaB_load (lua_State *L) {
++  int status;
++  const char *cname = luaL_optstring(L, 2, "=(load)");
++  luaL_checktype(L, 1, LUA_TFUNCTION);
++  lua_settop(L, 3);  /* function, eventual name, plus one reserved slot */
++  status = lua_load(L, generic_reader, NULL, cname);
++  return load_aux(L, status);
++}
++
++/*
++static int luaB_dofile (lua_State *L) {
++  const char *fname = luaL_optstring(L, 1, NULL);
++  int n = lua_gettop(L);
++  if (luaL_loadfile(L, fname) != 0) lua_error(L);
++  lua_call(L, 0, LUA_MULTRET);
++  return lua_gettop(L) - n;
++}
++*/
++
++static int luaB_assert (lua_State *L) {
++  luaL_checkany(L, 1);
++  if (!lua_toboolean(L, 1))
++    return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
++  return lua_gettop(L);
++}
++
++
++static int luaB_unpack (lua_State *L) {
++  int i, e, n;
++  luaL_checktype(L, 1, LUA_TTABLE);
++  i = luaL_optint(L, 2, 1);
++  e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
++  if (i > e) return 0;  /* empty range */
++  n = e - i + 1;  /* number of elements */
++  if (n <= 0 || !lua_checkstack(L, n))  /* n <= 0 means arith. overflow */
++    return luaL_error(L, "too many results to unpack");
++  lua_rawgeti(L, 1, i);  /* push arg[i] (avoiding overflow problems) */
++  while (i++ < e)  /* push arg[i + 1...e] */
++    lua_rawgeti(L, 1, i);
++  return n;
++}
++
++
++static int luaB_select (lua_State *L) {
++  int n = lua_gettop(L);
++  if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
++    lua_pushinteger(L, n-1);
++    return 1;
++  }
++  else {
++    int i = luaL_checkint(L, 1);
++    if (i < 0) i = n + i;
++    else if (i > n) i = n;
++    luaL_argcheck(L, 1 <= i, 1, "index out of range");
++    return n - i;
++  }
++}
++
++
++static int luaB_pcall (lua_State *L) {
++  int status;
++  luaL_checkany(L, 1);
++  status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
++  lua_pushboolean(L, (status == 0));
++  lua_insert(L, 1);
++  return lua_gettop(L);  /* return status + all results */
++}
++
++
++static int luaB_xpcall (lua_State *L) {
++  int status;
++  luaL_checkany(L, 2);
++  lua_settop(L, 2);
++  lua_insert(L, 1);  /* put error function under function to be called */
++  status = lua_pcall(L, 0, LUA_MULTRET, 1);
++  lua_pushboolean(L, (status == 0));
++  lua_replace(L, 1);
++  return lua_gettop(L);  /* return status + all results */
++}
++
++
++static int luaB_tostring (lua_State *L) {
++  luaL_checkany(L, 1);
++  if (luaL_callmeta(L, 1, "__tostring"))  /* is there a metafield? */
++    return 1;  /* use its value */
++  switch (lua_type(L, 1)) {
++    case LUA_TNUMBER:
++      lua_pushstring(L, lua_tostring(L, 1));
++      break;
++    case LUA_TSTRING:
++      lua_pushvalue(L, 1);
++      break;
++    case LUA_TBOOLEAN:
++      lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
++      break;
++    case LUA_TNIL:
++      lua_pushliteral(L, "nil");
++      break;
++    default:
++      lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
++      break;
++  }
++  return 1;
++}
++
++
++static int luaB_newproxy (lua_State *L) {
++  lua_settop(L, 1);
++  lua_newuserdata(L, 0);  /* create proxy */
++  if (lua_toboolean(L, 1) == 0)
++    return 1;  /* no metatable */
++  else if (lua_isboolean(L, 1)) {
++    lua_newtable(L);  /* create a new metatable `m' ... */
++    lua_pushvalue(L, -1);  /* ... and mark `m' as a valid metatable */
++    lua_pushboolean(L, 1);
++    lua_rawset(L, lua_upvalueindex(1));  /* weaktable[m] = true */
++  }
++  else {
++    int validproxy = 0;  /* to check if weaktable[metatable(u)] == true */
++    if (lua_getmetatable(L, 1)) {
++      lua_rawget(L, lua_upvalueindex(1));
++      validproxy = lua_toboolean(L, -1);
++      lua_pop(L, 1);  /* remove value */
++    }
++    luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
++    lua_getmetatable(L, 1);  /* metatable is valid; get it */
++  }
++  lua_setmetatable(L, 2);
++  return 1;
++}
++
++
++static const luaL_Reg base_funcs[] = {
++  {"assert", luaB_assert},
++  {"collectgarbage", luaB_collectgarbage},
++//  {"dofile", luaB_dofile},
++  {"error", luaB_error},
++  {"gcinfo", luaB_gcinfo},
++  {"getfenv", luaB_getfenv},
++  {"getmetatable", luaB_getmetatable},
++//  {"loadfile", luaB_loadfile},
++  {"load", luaB_load},
++  {"loadstring", luaB_loadstring},
++  {"next", luaB_next},
++  {"pcall", luaB_pcall},
++  {"print", luaB_print},
++  {"rawequal", luaB_rawequal},
++  {"rawget", luaB_rawget},
++  {"rawset", luaB_rawset},
++  {"select", luaB_select},
++  {"setfenv", luaB_setfenv},
++  {"setmetatable", luaB_setmetatable},
++  {"tonumber", luaB_tonumber},
++  {"tostring", luaB_tostring},
++  {"type", luaB_type},
++  {"unpack", luaB_unpack},
++  {"xpcall", luaB_xpcall},
++  {NULL, NULL}
++};
++
++
++/*
++** {======================================================
++** Coroutine library
++** =======================================================
++*/
++
++#define CO_RUN	0	/* running */
++#define CO_SUS	1	/* suspended */
++#define CO_NOR	2	/* 'normal' (it resumed another coroutine) */
++#define CO_DEAD	3
++
++static const char *const statnames[] =
++    {"running", "suspended", "normal", "dead"};
++
++static int costatus (lua_State *L, lua_State *co) {
++  if (L == co) return CO_RUN;
++  switch (lua_status(co)) {
++    case LUA_YIELD:
++      return CO_SUS;
++    case 0: {
++      lua_Debug ar;
++      if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */
++        return CO_NOR;  /* it is running */
++      else if (lua_gettop(co) == 0)
++          return CO_DEAD;
++      else
++        return CO_SUS;  /* initial state */
++    }
++    default:  /* some error occured */
++      return CO_DEAD;
++  }
++}
++
++
++static int luaB_costatus (lua_State *L) {
++  lua_State *co = lua_tothread(L, 1);
++  luaL_argcheck(L, co, 1, "coroutine expected");
++  lua_pushstring(L, statnames[costatus(L, co)]);
++  return 1;
++}
++
++
++static int auxresume (lua_State *L, lua_State *co, int narg) {
++  int status = costatus(L, co);
++  if (!lua_checkstack(co, narg))
++    luaL_error(L, "too many arguments to resume");
++  if (status != CO_SUS) {
++    lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);
++    return -1;  /* error flag */
++  }
++  lua_xmove(L, co, narg);
++  lua_setlevel(L, co);
++  status = lua_resume(co, narg);
++  if (status == 0 || status == LUA_YIELD) {
++    int nres = lua_gettop(co);
++    if (!lua_checkstack(L, nres + 1))
++      luaL_error(L, "too many results to resume");
++    lua_xmove(co, L, nres);  /* move yielded values */
++    return nres;
++  }
++  else {
++    lua_xmove(co, L, 1);  /* move error message */
++    return -1;  /* error flag */
++  }
++}
++
++
++static int luaB_coresume (lua_State *L) {
++  lua_State *co = lua_tothread(L, 1);
++  int r;
++  luaL_argcheck(L, co, 1, "coroutine expected");
++  r = auxresume(L, co, lua_gettop(L) - 1);
++  if (r < 0) {
++    lua_pushboolean(L, 0);
++    lua_insert(L, -2);
++    return 2;  /* return false + error message */
++  }
++  else {
++    lua_pushboolean(L, 1);
++    lua_insert(L, -(r + 1));
++    return r + 1;  /* return true + `resume' returns */
++  }
++}
++
++
++static int luaB_auxwrap (lua_State *L) {
++  lua_State *co = lua_tothread(L, lua_upvalueindex(1));
++  int r = auxresume(L, co, lua_gettop(L));
++  if (r < 0) {
++    if (lua_isstring(L, -1)) {  /* error object is a string? */
++      luaL_where(L, 1);  /* add extra info */
++      lua_insert(L, -2);
++      lua_concat(L, 2);
++    }
++    lua_error(L);  /* propagate error */
++  }
++  return r;
++}
++
++
++static int luaB_cocreate (lua_State *L) {
++  lua_State *NL = lua_newthread(L);
++  luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
++    "Lua function expected");
++  lua_pushvalue(L, 1);  /* move function to top */
++  lua_xmove(L, NL, 1);  /* move function from L to NL */
++  return 1;
++}
++
++
++static int luaB_cowrap (lua_State *L) {
++  luaB_cocreate(L);
++  lua_pushcclosure(L, luaB_auxwrap, 1);
++  return 1;
++}
++
++
++static int luaB_yield (lua_State *L) {
++  return lua_yield(L, lua_gettop(L));
++}
++
++
++static int luaB_corunning (lua_State *L) {
++  if (lua_pushthread(L))
++    lua_pushnil(L);  /* main thread is not a coroutine */
++  return 1;
++}
++
++
++static const luaL_Reg co_funcs[] = {
++  {"create", luaB_cocreate},
++  {"resume", luaB_coresume},
++  {"running", luaB_corunning},
++  {"status", luaB_costatus},
++  {"wrap", luaB_cowrap},
++  {"yield", luaB_yield},
++  {NULL, NULL}
++};
++
++/* }====================================================== */
++
++
++static void auxopen (lua_State *L, const char *name,
++                     lua_CFunction f, lua_CFunction u) {
++  lua_pushcfunction(L, u);
++  lua_pushcclosure(L, f, 1);
++  lua_setfield(L, -2, name);
++}
++
++
++static void base_open (lua_State *L) {
++  /* set global _G */
++  lua_pushvalue(L, LUA_GLOBALSINDEX);
++  lua_setglobal(L, "_G");
++  /* open lib into global table */
++  luaL_register(L, "_G", base_funcs);
++  lua_pushliteral(L, LUA_VERSION);
++  lua_setglobal(L, "_VERSION");  /* set global _VERSION */
++  /* `ipairs' and `pairs' need auxliliary functions as upvalues */
++  auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
++  auxopen(L, "pairs", luaB_pairs, luaB_next);
++  /* `newproxy' needs a weaktable as upvalue */
++  lua_createtable(L, 0, 1);  /* new table `w' */
++  lua_pushvalue(L, -1);  /* `w' will be its own metatable */
++  lua_setmetatable(L, -2);
++  lua_pushliteral(L, "kv");
++  lua_setfield(L, -2, "__mode");  /* metatable(w).__mode = "kv" */
++  lua_pushcclosure(L, luaB_newproxy, 1);
++  lua_setglobal(L, "newproxy");  /* set global `newproxy' */
++}
++
++
++LUALIB_API int luaopen_base (lua_State *L) {
++  base_open(L);
++  luaL_register(L, LUA_COLIBNAME, co_funcs);
++  return 2;
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lcode.c
+@@ -0,0 +1,838 @@
++/*
++** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $
++** Code generator for Lua
++** See Copyright Notice in lua.h
++*/
++
++#include <stdlib.h>
++
++#define lcode_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lcode.h"
++#include "ldebug.h"
++#include "ldo.h"
++#include "lgc.h"
++#include "llex.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lopcodes.h"
++#include "lparser.h"
++#include "ltable.h"
++
++
++#define hasjumps(e)	((e)->t != (e)->f)
++
++
++static int isnumeral(expdesc *e) {
++  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
++}
++
++
++void luaK_nil (FuncState *fs, int from, int n) {
++  Instruction *previous;
++  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
++    if (fs->pc == 0) {  /* function start? */
++      if (from >= fs->nactvar)
++        return;  /* positions are already clean */
++    }
++    else {
++      previous = &fs->f->code[fs->pc-1];
++      if (GET_OPCODE(*previous) == OP_LOADNIL) {
++        int pfrom = GETARG_A(*previous);
++        int pto = GETARG_B(*previous);
++        if (pfrom <= from && from <= pto+1) {  /* can connect both? */
++          if (from+n-1 > pto)
++            SETARG_B(*previous, from+n-1);
++          return;
++        }
++      }
++    }
++  }
++  luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */
++}
++
++
++int luaK_jump (FuncState *fs) {
++  int jpc = fs->jpc;  /* save list of jumps to here */
++  int j;
++  fs->jpc = NO_JUMP;
++  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
++  luaK_concat(fs, &j, jpc);  /* keep them on hold */
++  return j;
++}
++
++
++void luaK_ret (FuncState *fs, int first, int nret) {
++  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
++}
++
++
++static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
++  luaK_codeABC(fs, op, A, B, C);
++  return luaK_jump(fs);
++}
++
++
++static void fixjump (FuncState *fs, int pc, int dest) {
++  Instruction *jmp = &fs->f->code[pc];
++  int offset = dest-(pc+1);
++  lua_assert(dest != NO_JUMP);
++  if (abs(offset) > MAXARG_sBx)
++    luaX_syntaxerror(fs->ls, "control structure too long");
++  SETARG_sBx(*jmp, offset);
++}
++
++
++/*
++** returns current `pc' and marks it as a jump target (to avoid wrong
++** optimizations with consecutive instructions not in the same basic block).
++*/
++int luaK_getlabel (FuncState *fs) {
++  fs->lasttarget = fs->pc;
++  return fs->pc;
++}
++
++
++static int getjump (FuncState *fs, int pc) {
++  int offset = GETARG_sBx(fs->f->code[pc]);
++  if (offset == NO_JUMP)  /* point to itself represents end of list */
++    return NO_JUMP;  /* end of list */
++  else
++    return (pc+1)+offset;  /* turn offset into absolute position */
++}
++
++
++static Instruction *getjumpcontrol (FuncState *fs, int pc) {
++  Instruction *pi = &fs->f->code[pc];
++  if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
++    return pi-1;
++  else
++    return pi;
++}
++
++
++/*
++** check whether list has any jump that do not produce a value
++** (or produce an inverted value)
++*/
++static int need_value (FuncState *fs, int list) {
++  for (; list != NO_JUMP; list = getjump(fs, list)) {
++    Instruction i = *getjumpcontrol(fs, list);
++    if (GET_OPCODE(i) != OP_TESTSET) return 1;
++  }
++  return 0;  /* not found */
++}
++
++
++static int patchtestreg (FuncState *fs, int node, int reg) {
++  Instruction *i = getjumpcontrol(fs, node);
++  if (GET_OPCODE(*i) != OP_TESTSET)
++    return 0;  /* cannot patch other instructions */
++  if (reg != NO_REG && reg != GETARG_B(*i))
++    SETARG_A(*i, reg);
++  else  /* no register to put value or register already has the value */
++    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
++
++  return 1;
++}
++
++
++static void removevalues (FuncState *fs, int list) {
++  for (; list != NO_JUMP; list = getjump(fs, list))
++      patchtestreg(fs, list, NO_REG);
++}
++
++
++static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
++                          int dtarget) {
++  while (list != NO_JUMP) {
++    int next = getjump(fs, list);
++    if (patchtestreg(fs, list, reg))
++      fixjump(fs, list, vtarget);
++    else
++      fixjump(fs, list, dtarget);  /* jump to default target */
++    list = next;
++  }
++}
++
++
++static void dischargejpc (FuncState *fs) {
++  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
++  fs->jpc = NO_JUMP;
++}
++
++
++void luaK_patchlist (FuncState *fs, int list, int target) {
++  if (target == fs->pc)
++    luaK_patchtohere(fs, list);
++  else {
++    lua_assert(target < fs->pc);
++    patchlistaux(fs, list, target, NO_REG, target);
++  }
++}
++
++
++void luaK_patchtohere (FuncState *fs, int list) {
++  luaK_getlabel(fs);
++  luaK_concat(fs, &fs->jpc, list);
++}
++
++
++void luaK_concat (FuncState *fs, int *l1, int l2) {
++  if (l2 == NO_JUMP) return;
++  else if (*l1 == NO_JUMP)
++    *l1 = l2;
++  else {
++    int list = *l1;
++    int next;
++    while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */
++      list = next;
++    fixjump(fs, list, l2);
++  }
++}
++
++
++void luaK_checkstack (FuncState *fs, int n) {
++  int newstack = fs->freereg + n;
++  if (newstack > fs->f->maxstacksize) {
++    if (newstack >= MAXSTACK)
++      luaX_syntaxerror(fs->ls, "function or expression too complex");
++    fs->f->maxstacksize = cast_byte(newstack);
++  }
++}
++
++
++void luaK_reserveregs (FuncState *fs, int n) {
++  luaK_checkstack(fs, n);
++  fs->freereg += n;
++}
++
++
++static void freereg (FuncState *fs, int reg) {
++  if (!ISK(reg) && reg >= fs->nactvar) {
++    fs->freereg--;
++    lua_assert(reg == fs->freereg);
++  }
++}
++
++
++static void freeexp (FuncState *fs, expdesc *e) {
++  if (e->k == VNONRELOC)
++    freereg(fs, e->u.s.info);
++}
++
++
++static int addk (FuncState *fs, TValue *k, TValue *v) {
++  lua_State *L = fs->L;
++  TValue *idx = luaH_set(L, fs->h, k);
++  Proto *f = fs->f;
++  int oldsize = f->sizek;
++  if (ttisnumber(idx)) {
++    lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
++    return cast_int(nvalue(idx));
++  }
++  else {  /* constant not found; create a new entry */
++    setnvalue(idx, cast_num(fs->nk));
++    luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
++                    MAXARG_Bx, "constant table overflow");
++    while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
++    setobj(L, &f->k[fs->nk], v);
++    luaC_barrier(L, f, v);
++    return fs->nk++;
++  }
++}
++
++
++int luaK_stringK (FuncState *fs, TString *s) {
++  TValue o;
++  setsvalue(fs->L, &o, s);
++  return addk(fs, &o, &o);
++}
++
++
++int luaK_numberK (FuncState *fs, lua_Number r) {
++  TValue o;
++  setnvalue(&o, r);
++  return addk(fs, &o, &o);
++}
++
++
++static int boolK (FuncState *fs, int b) {
++  TValue o;
++  setbvalue(&o, b);
++  return addk(fs, &o, &o);
++}
++
++
++static int nilK (FuncState *fs) {
++  TValue k, v;
++  setnilvalue(&v);
++  /* cannot use nil as key; instead use table itself to represent nil */
++  sethvalue(fs->L, &k, fs->h);
++  return addk(fs, &k, &v);
++}
++
++
++void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
++  if (e->k == VCALL) {  /* expression is an open function call? */
++    SETARG_C(getcode(fs, e), nresults+1);
++  }
++  else if (e->k == VVARARG) {
++    SETARG_B(getcode(fs, e), nresults+1);
++    SETARG_A(getcode(fs, e), fs->freereg);
++    luaK_reserveregs(fs, 1);
++  }
++}
++
++
++void luaK_setoneret (FuncState *fs, expdesc *e) {
++  if (e->k == VCALL) {  /* expression is an open function call? */
++    e->k = VNONRELOC;
++    e->u.s.info = GETARG_A(getcode(fs, e));
++  }
++  else if (e->k == VVARARG) {
++    SETARG_B(getcode(fs, e), 2);
++    e->k = VRELOCABLE;  /* can relocate its simple result */
++  }
++}
++
++
++void luaK_dischargevars (FuncState *fs, expdesc *e) {
++  switch (e->k) {
++    case VLOCAL: {
++      e->k = VNONRELOC;
++      break;
++    }
++    case VUPVAL: {
++      e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
++      e->k = VRELOCABLE;
++      break;
++    }
++    case VGLOBAL: {
++      e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
++      e->k = VRELOCABLE;
++      break;
++    }
++    case VINDEXED: {
++      freereg(fs, e->u.s.aux);
++      freereg(fs, e->u.s.info);
++      e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
++      e->k = VRELOCABLE;
++      break;
++    }
++    case VVARARG:
++    case VCALL: {
++      luaK_setoneret(fs, e);
++      break;
++    }
++    default: break;  /* there is one value available (somewhere) */
++  }
++}
++
++
++static int code_label (FuncState *fs, int A, int b, int jump) {
++  luaK_getlabel(fs);  /* those instructions may be jump targets */
++  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
++}
++
++
++static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
++  luaK_dischargevars(fs, e);
++  switch (e->k) {
++    case VNIL: {
++      luaK_nil(fs, reg, 1);
++      break;
++    }
++    case VFALSE:  case VTRUE: {
++      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
++      break;
++    }
++    case VK: {
++      luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
++      break;
++    }
++    case VKNUM: {
++      luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
++      break;
++    }
++    case VRELOCABLE: {
++      Instruction *pc = &getcode(fs, e);
++      SETARG_A(*pc, reg);
++      break;
++    }
++    case VNONRELOC: {
++      if (reg != e->u.s.info)
++        luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
++      break;
++    }
++    default: {
++      lua_assert(e->k == VVOID || e->k == VJMP);
++      return;  /* nothing to do... */
++    }
++  }
++  e->u.s.info = reg;
++  e->k = VNONRELOC;
++}
++
++
++static void discharge2anyreg (FuncState *fs, expdesc *e) {
++  if (e->k != VNONRELOC) {
++    luaK_reserveregs(fs, 1);
++    discharge2reg(fs, e, fs->freereg-1);
++  }
++}
++
++
++static void exp2reg (FuncState *fs, expdesc *e, int reg) {
++  discharge2reg(fs, e, reg);
++  if (e->k == VJMP)
++    luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */
++  if (hasjumps(e)) {
++    int final;  /* position after whole expression */
++    int p_f = NO_JUMP;  /* position of an eventual LOAD false */
++    int p_t = NO_JUMP;  /* position of an eventual LOAD true */
++    if (need_value(fs, e->t) || need_value(fs, e->f)) {
++      int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
++      p_f = code_label(fs, reg, 0, 1);
++      p_t = code_label(fs, reg, 1, 0);
++      luaK_patchtohere(fs, fj);
++    }
++    final = luaK_getlabel(fs);
++    patchlistaux(fs, e->f, final, reg, p_f);
++    patchlistaux(fs, e->t, final, reg, p_t);
++  }
++  e->f = e->t = NO_JUMP;
++  e->u.s.info = reg;
++  e->k = VNONRELOC;
++}
++
++
++void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
++  luaK_dischargevars(fs, e);
++  freeexp(fs, e);
++  luaK_reserveregs(fs, 1);
++  exp2reg(fs, e, fs->freereg - 1);
++}
++
++
++int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
++  luaK_dischargevars(fs, e);
++  if (e->k == VNONRELOC) {
++    if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */
++    if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */
++      exp2reg(fs, e, e->u.s.info);  /* put value on it */
++      return e->u.s.info;
++    }
++  }
++  luaK_exp2nextreg(fs, e);  /* default */
++  return e->u.s.info;
++}
++
++
++void luaK_exp2val (FuncState *fs, expdesc *e) {
++  if (hasjumps(e))
++    luaK_exp2anyreg(fs, e);
++  else
++    luaK_dischargevars(fs, e);
++}
++
++
++int luaK_exp2RK (FuncState *fs, expdesc *e) {
++  luaK_exp2val(fs, e);
++  switch (e->k) {
++    case VKNUM:
++    case VTRUE:
++    case VFALSE:
++    case VNIL: {
++      if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
++        e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
++                      (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
++                                        boolK(fs, (e->k == VTRUE));
++        e->k = VK;
++        return RKASK(e->u.s.info);
++      }
++      else break;
++    }
++    case VK: {
++      if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */
++        return RKASK(e->u.s.info);
++      else break;
++    }
++    default: break;
++  }
++  /* not a constant in the right range: put it in a register */
++  return luaK_exp2anyreg(fs, e);
++}
++
++
++void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
++  switch (var->k) {
++    case VLOCAL: {
++      freeexp(fs, ex);
++      exp2reg(fs, ex, var->u.s.info);
++      return;
++    }
++    case VUPVAL: {
++      int e = luaK_exp2anyreg(fs, ex);
++      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
++      break;
++    }
++    case VGLOBAL: {
++      int e = luaK_exp2anyreg(fs, ex);
++      luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
++      break;
++    }
++    case VINDEXED: {
++      int e = luaK_exp2RK(fs, ex);
++      luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
++      break;
++    }
++    default: {
++      lua_assert(0);  /* invalid var kind to store */
++      break;
++    }
++  }
++  freeexp(fs, ex);
++}
++
++
++void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
++  int func;
++  luaK_exp2anyreg(fs, e);
++  freeexp(fs, e);
++  func = fs->freereg;
++  luaK_reserveregs(fs, 2);
++  luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
++  freeexp(fs, key);
++  e->u.s.info = func;
++  e->k = VNONRELOC;
++}
++
++
++static void invertjump (FuncState *fs, expdesc *e) {
++  Instruction *pc = getjumpcontrol(fs, e->u.s.info);
++  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
++                                           GET_OPCODE(*pc) != OP_TEST);
++  SETARG_A(*pc, !(GETARG_A(*pc)));
++}
++
++
++static int jumponcond (FuncState *fs, expdesc *e, int cond) {
++  if (e->k == VRELOCABLE) {
++    Instruction ie = getcode(fs, e);
++    if (GET_OPCODE(ie) == OP_NOT) {
++      fs->pc--;  /* remove previous OP_NOT */
++      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
++    }
++    /* else go through */
++  }
++  discharge2anyreg(fs, e);
++  freeexp(fs, e);
++  return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
++}
++
++
++void luaK_goiftrue (FuncState *fs, expdesc *e) {
++  int pc;  /* pc of last jump */
++  luaK_dischargevars(fs, e);
++  switch (e->k) {
++    case VK: case VKNUM: case VTRUE: {
++      pc = NO_JUMP;  /* always true; do nothing */
++      break;
++    }
++    case VFALSE: {
++      pc = luaK_jump(fs);  /* always jump */
++      break;
++    }
++    case VJMP: {
++      invertjump(fs, e);
++      pc = e->u.s.info;
++      break;
++    }
++    default: {
++      pc = jumponcond(fs, e, 0);
++      break;
++    }
++  }
++  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
++  luaK_patchtohere(fs, e->t);
++  e->t = NO_JUMP;
++}
++
++
++static void luaK_goiffalse (FuncState *fs, expdesc *e) {
++  int pc;  /* pc of last jump */
++  luaK_dischargevars(fs, e);
++  switch (e->k) {
++    case VNIL: case VFALSE: {
++      pc = NO_JUMP;  /* always false; do nothing */
++      break;
++    }
++    case VTRUE: {
++      pc = luaK_jump(fs);  /* always jump */
++      break;
++    }
++    case VJMP: {
++      pc = e->u.s.info;
++      break;
++    }
++    default: {
++      pc = jumponcond(fs, e, 1);
++      break;
++    }
++  }
++  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
++  luaK_patchtohere(fs, e->f);
++  e->f = NO_JUMP;
++}
++
++
++static void codenot (FuncState *fs, expdesc *e) {
++  luaK_dischargevars(fs, e);
++  switch (e->k) {
++    case VNIL: case VFALSE: {
++      e->k = VTRUE;
++      break;
++    }
++    case VK: case VKNUM: case VTRUE: {
++      e->k = VFALSE;
++      break;
++    }
++    case VJMP: {
++      invertjump(fs, e);
++      break;
++    }
++    case VRELOCABLE:
++    case VNONRELOC: {
++      discharge2anyreg(fs, e);
++      freeexp(fs, e);
++      e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
++      e->k = VRELOCABLE;
++      break;
++    }
++    default: {
++      lua_assert(0);  /* cannot happen */
++      break;
++    }
++  }
++  /* interchange true and false lists */
++  { int temp = e->f; e->f = e->t; e->t = temp; }
++  removevalues(fs, e->f);
++  removevalues(fs, e->t);
++}
++
++
++void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
++  t->u.s.aux = luaK_exp2RK(fs, k);
++  t->k = VINDEXED;
++}
++
++
++static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
++  lua_Number v1, v2, r;
++  if (!isnumeral(e1) || !isnumeral(e2)) return 0;
++  v1 = e1->u.nval;
++  v2 = e2->u.nval;
++  switch (op) {
++    case OP_ADD: r = luai_numadd(v1, v2); break;
++    case OP_SUB: r = luai_numsub(v1, v2); break;
++    case OP_MUL: r = luai_nummul(v1, v2); break;
++    case OP_DIV:
++      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
++      r = luai_numdiv(v1, v2); break;
++    case OP_MOD:
++      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
++      r = luai_nummod(v1, v2); break;
++    case OP_POW: r = luai_numpow(v1, v2); break;
++    case OP_UNM: r = luai_numunm(v1); break;
++    case OP_LEN: return 0;  /* no constant folding for 'len' */
++    default: lua_assert(0); r = 0; break;
++  }
++  if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */
++  e1->u.nval = r;
++  return 1;
++}
++
++
++static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
++  if (constfolding(op, e1, e2))
++    return;
++  else {
++    int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
++    int o1 = luaK_exp2RK(fs, e1);
++    if (o1 > o2) {
++      freeexp(fs, e1);
++      freeexp(fs, e2);
++    }
++    else {
++      freeexp(fs, e2);
++      freeexp(fs, e1);
++    }
++    e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
++    e1->k = VRELOCABLE;
++  }
++}
++
++
++static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
++                                                          expdesc *e2) {
++  int o1 = luaK_exp2RK(fs, e1);
++  int o2 = luaK_exp2RK(fs, e2);
++  freeexp(fs, e2);
++  freeexp(fs, e1);
++  if (cond == 0 && op != OP_EQ) {
++    int temp;  /* exchange args to replace by `<' or `<=' */
++    temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
++    cond = 1;
++  }
++  e1->u.s.info = condjump(fs, op, cond, o1, o2);
++  e1->k = VJMP;
++}
++
++
++void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
++  expdesc e2;
++  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
++  switch (op) {
++    case OPR_MINUS: {
++      if (!isnumeral(e))
++        luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
++      codearith(fs, OP_UNM, e, &e2);
++      break;
++    }
++    case OPR_NOT: codenot(fs, e); break;
++    case OPR_LEN: {
++      luaK_exp2anyreg(fs, e);  /* cannot operate on constants */
++      codearith(fs, OP_LEN, e, &e2);
++      break;
++    }
++    default: lua_assert(0);
++  }
++}
++
++
++void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
++  switch (op) {
++    case OPR_AND: {
++      luaK_goiftrue(fs, v);
++      break;
++    }
++    case OPR_OR: {
++      luaK_goiffalse(fs, v);
++      break;
++    }
++    case OPR_CONCAT: {
++      luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
++      break;
++    }
++    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
++    case OPR_MOD: case OPR_POW: {
++      if (!isnumeral(v)) luaK_exp2RK(fs, v);
++      break;
++    }
++    default: {
++      luaK_exp2RK(fs, v);
++      break;
++    }
++  }
++}
++
++
++void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
++  switch (op) {
++    case OPR_AND: {
++      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
++      luaK_dischargevars(fs, e2);
++      luaK_concat(fs, &e2->f, e1->f);
++      *e1 = *e2;
++      break;
++    }
++    case OPR_OR: {
++      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
++      luaK_dischargevars(fs, e2);
++      luaK_concat(fs, &e2->t, e1->t);
++      *e1 = *e2;
++      break;
++    }
++    case OPR_CONCAT: {
++      luaK_exp2val(fs, e2);
++      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
++        lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
++        freeexp(fs, e1);
++        SETARG_B(getcode(fs, e2), e1->u.s.info);
++        e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
++      }
++      else {
++        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
++        codearith(fs, OP_CONCAT, e1, e2);
++      }
++      break;
++    }
++    case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
++    case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
++    case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
++    case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
++    case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
++    case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
++    case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
++    case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
++    case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
++    case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
++    case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
++    case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
++    default: lua_assert(0);
++  }
++}
++
++
++void luaK_fixline (FuncState *fs, int line) {
++  fs->f->lineinfo[fs->pc - 1] = line;
++}
++
++
++static int luaK_code (FuncState *fs, Instruction i, int line) {
++  Proto *f = fs->f;
++  dischargejpc(fs);  /* `pc' will change */
++  /* put new instruction in code array */
++  luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
++                  MAX_INT, "code size overflow");
++  f->code[fs->pc] = i;
++  /* save corresponding line information */
++  luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
++                  MAX_INT, "code size overflow");
++  f->lineinfo[fs->pc] = line;
++  return fs->pc++;
++}
++
++
++int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
++  lua_assert(getOpMode(o) == iABC);
++  lua_assert(getBMode(o) != OpArgN || b == 0);
++  lua_assert(getCMode(o) != OpArgN || c == 0);
++  return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
++}
++
++
++int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
++  lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
++  lua_assert(getCMode(o) == OpArgN);
++  return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
++}
++
++
++void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
++  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
++  int b = (tostore == LUA_MULTRET) ? 0 : tostore;
++  lua_assert(tostore != 0);
++  if (c <= MAXARG_C)
++    luaK_codeABC(fs, OP_SETLIST, base, b, c);
++  else {
++    luaK_codeABC(fs, OP_SETLIST, base, b, 0);
++    luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
++  }
++  fs->freereg = base + 1;  /* free registers with list values */
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lcode.h
+@@ -0,0 +1,76 @@
++/*
++** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $
++** Code generator for Lua
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lcode_h
++#define lcode_h
++
++#include "llex.h"
++#include "lobject.h"
++#include "lopcodes.h"
++#include "lparser.h"
++
++
++/*
++** Marks the end of a patch list. It is an invalid value both as an absolute
++** address, and as a list link (would link an element to itself).
++*/
++#define NO_JUMP (-1)
++
++
++/*
++** grep "ORDER OPR" if you change these enums
++*/
++typedef enum BinOpr {
++  OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
++  OPR_CONCAT,
++  OPR_NE, OPR_EQ,
++  OPR_LT, OPR_LE, OPR_GT, OPR_GE,
++  OPR_AND, OPR_OR,
++  OPR_NOBINOPR
++} BinOpr;
++
++
++typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
++
++
++#define getcode(fs,e)	((fs)->f->code[(e)->u.s.info])
++
++#define luaK_codeAsBx(fs,o,A,sBx)	luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
++
++#define luaK_setmultret(fs,e)	luaK_setreturns(fs, e, LUA_MULTRET)
++
++LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
++LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
++LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
++LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
++LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
++LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
++LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
++LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
++LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
++LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
++LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
++LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
++LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
++LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
++LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
++LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
++LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
++LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
++LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
++LUAI_FUNC int luaK_jump (FuncState *fs);
++LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
++LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
++LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
++LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
++LUAI_FUNC int luaK_getlabel (FuncState *fs);
++LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
++LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
++LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
++LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/ldebug.c
+@@ -0,0 +1,637 @@
++/*
++** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $
++** Debug Interface
++** See Copyright Notice in lua.h
++*/
++
++
++#include <stdarg.h>
++#include <stddef.h>
++#include <string.h>
++
++#define ldebug_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lapi.h"
++#include "lcode.h"
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lobject.h"
++#include "lopcodes.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++#include "lvm.h"
++
++
++
++static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
++
++
++static int currentpc (lua_State *L, CallInfo *ci) {
++  if (!isLua(ci)) return -1;  /* function is not a Lua function? */
++  if (ci == L->ci)
++    ci->savedpc = L->savedpc;
++  return pcRel(ci->savedpc, ci_func(ci)->l.p);
++}
++
++
++static int currentline (lua_State *L, CallInfo *ci) {
++  int pc = currentpc(L, ci);
++  if (pc < 0)
++    return -1;  /* only active lua functions have current-line information */
++  else
++    return getline(ci_func(ci)->l.p, pc);
++}
++
++
++/*
++** this function can be called asynchronous (e.g. during a signal)
++*/
++LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
++  if (func == NULL || mask == 0) {  /* turn off hooks? */
++    mask = 0;
++    func = NULL;
++  }
++  L->hook = func;
++  L->basehookcount = count;
++  resethookcount(L);
++  L->hookmask = cast_byte(mask);
++  return 1;
++}
++
++
++LUA_API lua_Hook lua_gethook (lua_State *L) {
++  return L->hook;
++}
++
++
++LUA_API int lua_gethookmask (lua_State *L) {
++  return L->hookmask;
++}
++
++
++LUA_API int lua_gethookcount (lua_State *L) {
++  return L->basehookcount;
++}
++
++
++LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
++  int status;
++  CallInfo *ci;
++  lua_lock(L);
++  for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
++    level--;
++    if (f_isLua(ci))  /* Lua function? */
++      level -= ci->tailcalls;  /* skip lost tail calls */
++  }
++  if (level == 0 && ci > L->base_ci) {  /* level found? */
++    status = 1;
++    ar->i_ci = cast_int(ci - L->base_ci);
++  }
++  else if (level < 0) {  /* level is of a lost tail call? */
++    status = 1;
++    ar->i_ci = 0;
++  }
++  else status = 0;  /* no such level */
++  lua_unlock(L);
++  return status;
++}
++
++
++static Proto *getluaproto (CallInfo *ci) {
++  return (isLua(ci) ? ci_func(ci)->l.p : NULL);
++}
++
++
++static const char *findlocal (lua_State *L, CallInfo *ci, int n) {
++  const char *name;
++  Proto *fp = getluaproto(ci);
++  if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL)
++    return name;  /* is a local variable in a Lua function */
++  else {
++    StkId limit = (ci == L->ci) ? L->top : (ci+1)->func;
++    if (limit - ci->base >= n && n > 0)  /* is 'n' inside 'ci' stack? */
++      return "(*temporary)";
++    else
++      return NULL;
++  }
++}
++
++
++LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
++  CallInfo *ci = L->base_ci + ar->i_ci;
++  const char *name = findlocal(L, ci, n);
++  lua_lock(L);
++  if (name)
++      luaA_pushobject(L, ci->base + (n - 1));
++  lua_unlock(L);
++  return name;
++}
++
++
++LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
++  CallInfo *ci = L->base_ci + ar->i_ci;
++  const char *name = findlocal(L, ci, n);
++  lua_lock(L);
++  if (name)
++      setobjs2s(L, ci->base + (n - 1), L->top - 1);
++  L->top--;  /* pop value */
++  lua_unlock(L);
++  return name;
++}
++
++
++static void funcinfo (lua_Debug *ar, Closure *cl) {
++  if (cl->c.isC) {
++    ar->source = "=[C]";
++    ar->linedefined = -1;
++    ar->lastlinedefined = -1;
++    ar->what = "C";
++  }
++  else {
++    ar->source = getstr(cl->l.p->source);
++    ar->linedefined = cl->l.p->linedefined;
++    ar->lastlinedefined = cl->l.p->lastlinedefined;
++    ar->what = (ar->linedefined == 0) ? "main" : "Lua";
++  }
++  luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
++}
++
++
++static void info_tailcall (lua_Debug *ar) {
++  ar->name = ar->namewhat = "";
++  ar->what = "tail";
++  ar->lastlinedefined = ar->linedefined = ar->currentline = -1;
++  ar->source = "=(tail call)";
++  luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
++  ar->nups = 0;
++}
++
++
++static void collectvalidlines (lua_State *L, Closure *f) {
++  if (f == NULL || f->c.isC) {
++    setnilvalue(L->top);
++  }
++  else {
++    Table *t = luaH_new(L, 0, 0);
++    int *lineinfo = f->l.p->lineinfo;
++    int i;
++    for (i=0; i<f->l.p->sizelineinfo; i++)
++      setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
++    sethvalue(L, L->top, t); 
++  }
++  incr_top(L);
++}
++
++
++static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
++                    Closure *f, CallInfo *ci) {
++  int status = 1;
++  if (f == NULL) {
++    info_tailcall(ar);
++    return status;
++  }
++  for (; *what; what++) {
++    switch (*what) {
++      case 'S': {
++        funcinfo(ar, f);
++        break;
++      }
++      case 'l': {
++        ar->currentline = (ci) ? currentline(L, ci) : -1;
++        break;
++      }
++      case 'u': {
++        ar->nups = f->c.nupvalues;
++        break;
++      }
++      case 'n': {
++        ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
++        if (ar->namewhat == NULL) {
++          ar->namewhat = "";  /* not found */
++          ar->name = NULL;
++        }
++        break;
++      }
++      case 'L':
++      case 'f':  /* handled by lua_getinfo */
++        break;
++      default: status = 0;  /* invalid option */
++    }
++  }
++  return status;
++}
++
++
++LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
++  int status;
++  Closure *f = NULL;
++  CallInfo *ci = NULL;
++  lua_lock(L);
++  if (*what == '>') {
++    StkId func = L->top - 1;
++    luai_apicheck(L, ttisfunction(func));
++    what++;  /* skip the '>' */
++    f = clvalue(func);
++    L->top--;  /* pop function */
++  }
++  else if (ar->i_ci != 0) {  /* no tail call? */
++    ci = L->base_ci + ar->i_ci;
++    lua_assert(ttisfunction(ci->func));
++    f = clvalue(ci->func);
++  }
++  status = auxgetinfo(L, what, ar, f, ci);
++  if (strchr(what, 'f')) {
++    if (f == NULL) setnilvalue(L->top);
++    else setclvalue(L, L->top, f);
++    incr_top(L);
++  }
++  if (strchr(what, 'L'))
++    collectvalidlines(L, f);
++  lua_unlock(L);
++  return status;
++}
++
++
++/*
++** {======================================================
++** Symbolic Execution and code checker
++** =======================================================
++*/
++
++#define check(x)		if (!(x)) return 0;
++
++#define checkjump(pt,pc)	check(0 <= pc && pc < pt->sizecode)
++
++#define checkreg(pt,reg)	check((reg) < (pt)->maxstacksize)
++
++
++
++static int precheck (const Proto *pt) {
++  check(pt->maxstacksize <= MAXSTACK);
++  check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
++  check(!(pt->is_vararg & VARARG_NEEDSARG) ||
++              (pt->is_vararg & VARARG_HASARG));
++  check(pt->sizeupvalues <= pt->nups);
++  check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
++  check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
++  return 1;
++}
++
++
++#define checkopenop(pt,pc)	luaG_checkopenop((pt)->code[(pc)+1])
++
++int luaG_checkopenop (Instruction i) {
++  switch (GET_OPCODE(i)) {
++    case OP_CALL:
++    case OP_TAILCALL:
++    case OP_RETURN:
++    case OP_SETLIST: {
++      check(GETARG_B(i) == 0);
++      return 1;
++    }
++    default: return 0;  /* invalid instruction after an open call */
++  }
++}
++
++
++static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) {
++  switch (mode) {
++    case OpArgN: check(r == 0); break;
++    case OpArgU: break;
++    case OpArgR: checkreg(pt, r); break;
++    case OpArgK:
++      check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize);
++      break;
++  }
++  return 1;
++}
++
++
++static Instruction symbexec (const Proto *pt, int lastpc, int reg) {
++  int pc;
++  int last;  /* stores position of last instruction that changed `reg' */
++  last = pt->sizecode-1;  /* points to final return (a `neutral' instruction) */
++  check(precheck(pt));
++  for (pc = 0; pc < lastpc; pc++) {
++    Instruction i = pt->code[pc];
++    OpCode op = GET_OPCODE(i);
++    int a = GETARG_A(i);
++    int b = 0;
++    int c = 0;
++    check(op < NUM_OPCODES);
++    checkreg(pt, a);
++    switch (getOpMode(op)) {
++      case iABC: {
++        b = GETARG_B(i);
++        c = GETARG_C(i);
++        check(checkArgMode(pt, b, getBMode(op)));
++        check(checkArgMode(pt, c, getCMode(op)));
++        break;
++      }
++      case iABx: {
++        b = GETARG_Bx(i);
++        if (getBMode(op) == OpArgK) check(b < pt->sizek);
++        break;
++      }
++      case iAsBx: {
++        b = GETARG_sBx(i);
++        if (getBMode(op) == OpArgR) {
++          int dest = pc+1+b;
++          check(0 <= dest && dest < pt->sizecode);
++          if (dest > 0) {
++            int j;
++            /* check that it does not jump to a setlist count; this
++               is tricky, because the count from a previous setlist may
++               have the same value of an invalid setlist; so, we must
++               go all the way back to the first of them (if any) */
++            for (j = 0; j < dest; j++) {
++              Instruction d = pt->code[dest-1-j];
++              if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break;
++            }
++            /* if 'j' is even, previous value is not a setlist (even if
++               it looks like one) */
++            check((j&1) == 0);
++          }
++        }
++        break;
++      }
++    }
++    if (testAMode(op)) {
++      if (a == reg) last = pc;  /* change register `a' */
++    }
++    if (testTMode(op)) {
++      check(pc+2 < pt->sizecode);  /* check skip */
++      check(GET_OPCODE(pt->code[pc+1]) == OP_JMP);
++    }
++    switch (op) {
++      case OP_LOADBOOL: {
++        if (c == 1) {  /* does it jump? */
++          check(pc+2 < pt->sizecode);  /* check its jump */
++          check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST ||
++                GETARG_C(pt->code[pc+1]) != 0);
++        }
++        break;
++      }
++      case OP_LOADNIL: {
++        if (a <= reg && reg <= b)
++          last = pc;  /* set registers from `a' to `b' */
++        break;
++      }
++      case OP_GETUPVAL:
++      case OP_SETUPVAL: {
++        check(b < pt->nups);
++        break;
++      }
++      case OP_GETGLOBAL:
++      case OP_SETGLOBAL: {
++        check(ttisstring(&pt->k[b]));
++        break;
++      }
++      case OP_SELF: {
++        checkreg(pt, a+1);
++        if (reg == a+1) last = pc;
++        break;
++      }
++      case OP_CONCAT: {
++        check(b < c);  /* at least two operands */
++        break;
++      }
++      case OP_TFORLOOP: {
++        check(c >= 1);  /* at least one result (control variable) */
++        checkreg(pt, a+2+c);  /* space for results */
++        if (reg >= a+2) last = pc;  /* affect all regs above its base */
++        break;
++      }
++      case OP_FORLOOP:
++      case OP_FORPREP:
++        checkreg(pt, a+3);
++        /* go through */
++      case OP_JMP: {
++        int dest = pc+1+b;
++        /* not full check and jump is forward and do not skip `lastpc'? */
++        if (reg != NO_REG && pc < dest && dest <= lastpc)
++          pc += b;  /* do the jump */
++        break;
++      }
++      case OP_CALL:
++      case OP_TAILCALL: {
++        if (b != 0) {
++          checkreg(pt, a+b-1);
++        }
++        c--;  /* c = num. returns */
++        if (c == LUA_MULTRET) {
++          check(checkopenop(pt, pc));
++        }
++        else if (c != 0)
++          checkreg(pt, a+c-1);
++        if (reg >= a) last = pc;  /* affect all registers above base */
++        break;
++      }
++      case OP_RETURN: {
++        b--;  /* b = num. returns */
++        if (b > 0) checkreg(pt, a+b-1);
++        break;
++      }
++      case OP_SETLIST: {
++        if (b > 0) checkreg(pt, a + b);
++        if (c == 0) {
++          pc++;
++          check(pc < pt->sizecode - 1);
++        }
++        break;
++      }
++      case OP_CLOSURE: {
++        int nup, j;
++        check(b < pt->sizep);
++        nup = pt->p[b]->nups;
++        check(pc + nup < pt->sizecode);
++        for (j = 1; j <= nup; j++) {
++          OpCode op1 = GET_OPCODE(pt->code[pc + j]);
++          check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
++        }
++        if (reg != NO_REG)  /* tracing? */
++          pc += nup;  /* do not 'execute' these pseudo-instructions */
++        break;
++      }
++      case OP_VARARG: {
++        check((pt->is_vararg & VARARG_ISVARARG) &&
++             !(pt->is_vararg & VARARG_NEEDSARG));
++        b--;
++        if (b == LUA_MULTRET) check(checkopenop(pt, pc));
++        checkreg(pt, a+b-1);
++        break;
++      }
++      default: break;
++    }
++  }
++  return pt->code[last];
++}
++
++#undef check
++#undef checkjump
++#undef checkreg
++
++/* }====================================================== */
++
++
++int luaG_checkcode (const Proto *pt) {
++  return (symbexec(pt, pt->sizecode, NO_REG) != 0);
++}
++
++
++static const char *kname (Proto *p, int c) {
++  if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
++    return svalue(&p->k[INDEXK(c)]);
++  else
++    return "?";
++}
++
++
++static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos,
++                               const char **name) {
++  if (isLua(ci)) {  /* a Lua function? */
++    Proto *p = ci_func(ci)->l.p;
++    int pc = currentpc(L, ci);
++    Instruction i;
++    *name = luaF_getlocalname(p, stackpos+1, pc);
++    if (*name)  /* is a local? */
++      return "local";
++    i = symbexec(p, pc, stackpos);  /* try symbolic execution */
++    lua_assert(pc != -1);
++    switch (GET_OPCODE(i)) {
++      case OP_GETGLOBAL: {
++        int g = GETARG_Bx(i);  /* global index */
++        lua_assert(ttisstring(&p->k[g]));
++        *name = svalue(&p->k[g]);
++        return "global";
++      }
++      case OP_MOVE: {
++        int a = GETARG_A(i);
++        int b = GETARG_B(i);  /* move from `b' to `a' */
++        if (b < a)
++          return getobjname(L, ci, b, name);  /* get name for `b' */
++        break;
++      }
++      case OP_GETTABLE: {
++        int k = GETARG_C(i);  /* key index */
++        *name = kname(p, k);
++        return "field";
++      }
++      case OP_GETUPVAL: {
++        int u = GETARG_B(i);  /* upvalue index */
++        *name = p->upvalues ? getstr(p->upvalues[u]) : "?";
++        return "upvalue";
++      }
++      case OP_SELF: {
++        int k = GETARG_C(i);  /* key index */
++        *name = kname(p, k);
++        return "method";
++      }
++      default: break;
++    }
++  }
++  return NULL;  /* no useful name found */
++}
++
++
++static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
++  Instruction i;
++  if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1))
++    return NULL;  /* calling function is not Lua (or is unknown) */
++  ci--;  /* calling function */
++  i = ci_func(ci)->l.p->code[currentpc(L, ci)];
++  if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL ||
++      GET_OPCODE(i) == OP_TFORLOOP)
++    return getobjname(L, ci, GETARG_A(i), name);
++  else
++    return NULL;  /* no useful name can be found */
++}
++
++
++/* only ANSI way to check whether a pointer points to an array */
++static int isinstack (CallInfo *ci, const TValue *o) {
++  StkId p;
++  for (p = ci->base; p < ci->top; p++)
++    if (o == p) return 1;
++  return 0;
++}
++
++
++void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
++  const char *name = NULL;
++  const char *t = luaT_typenames[ttype(o)];
++  const char *kind = (isinstack(L->ci, o)) ?
++                         getobjname(L, L->ci, cast_int(o - L->base), &name) :
++                         NULL;
++  if (kind)
++    luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
++                op, kind, name, t);
++  else
++    luaG_runerror(L, "attempt to %s a %s value", op, t);
++}
++
++
++void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
++  if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
++  lua_assert(!ttisstring(p1) && !ttisnumber(p1));
++  luaG_typeerror(L, p1, "concatenate");
++}
++
++
++void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
++  TValue temp;
++  if (luaV_tonumber(p1, &temp) == NULL)
++    p2 = p1;  /* first operand is wrong */
++  luaG_typeerror(L, p2, "perform arithmetic on");
++}
++
++
++int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
++  const char *t1 = luaT_typenames[ttype(p1)];
++  const char *t2 = luaT_typenames[ttype(p2)];
++  if (t1[2] == t2[2])
++    luaG_runerror(L, "attempt to compare two %s values", t1);
++  else
++    luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
++  return 0;
++}
++
++
++static void addinfo (lua_State *L, const char *msg) {
++  CallInfo *ci = L->ci;
++  if (isLua(ci)) {  /* is Lua code? */
++    char buff[LUA_IDSIZE];  /* add file:line information */
++    int line = currentline(L, ci);
++    luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
++    luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
++  }
++}
++
++
++void luaG_errormsg (lua_State *L) {
++  if (L->errfunc != 0) {  /* is there an error handling function? */
++    StkId errfunc = restorestack(L, L->errfunc);
++    if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
++    setobjs2s(L, L->top, L->top - 1);  /* move argument */
++    setobjs2s(L, L->top - 1, errfunc);  /* push function */
++    incr_top(L);
++    luaD_call(L, L->top - 2, 1);  /* call it */
++  }
++  luaD_throw(L, LUA_ERRRUN);
++}
++
++
++void luaG_runerror (lua_State *L, const char *fmt, ...) {
++  va_list argp;
++  va_start(argp, fmt);
++  addinfo(L, luaO_pushvfstring(L, fmt, argp));
++  va_end(argp);
++  luaG_errormsg(L);
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/ldebug.h
+@@ -0,0 +1,33 @@
++/*
++** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $
++** Auxiliary functions from Debug Interface module
++** See Copyright Notice in lua.h
++*/
++
++#ifndef ldebug_h
++#define ldebug_h
++
++
++#include "lstate.h"
++
++
++#define pcRel(pc, p)	(cast(int, (pc) - (p)->code) - 1)
++
++#define getline(f,pc)	(((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
++
++#define resethookcount(L)	(L->hookcount = L->basehookcount)
++
++
++LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o,
++                                             const char *opname);
++LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
++LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1,
++                                              const TValue *p2);
++LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1,
++                                             const TValue *p2);
++LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...);
++LUAI_FUNC void luaG_errormsg (lua_State *L);
++LUAI_FUNC int luaG_checkcode (const Proto *pt);
++LUAI_FUNC int luaG_checkopenop (Instruction i);
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/ldo.c
+@@ -0,0 +1,515 @@
++/*
++** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $
++** Stack and Call structure of Lua
++** See Copyright Notice in lua.h
++*/
++
++#include <setjmp.h>
++#include <stdlib.h>
++#include <string.h>
++
++#define ldo_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lgc.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lopcodes.h"
++#include "lparser.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++#include "lundump.h"
++#include "lvm.h"
++#include "lzio.h"
++
++
++
++/*
++** {======================================================
++** Error-recovery functions
++** =======================================================
++*/
++
++
++/* chain list of long jump buffers */
++struct lua_longjmp {
++  struct lua_longjmp *previous;
++  luai_jmpbuf b;
++  volatile int status;  /* error code */
++};
++
++
++void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
++  switch (errcode) {
++    case LUA_ERRMEM: {
++      setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
++      break;
++    }
++    case LUA_ERRERR: {
++      setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
++      break;
++    }
++    case LUA_ERRSYNTAX:
++    case LUA_ERRRUN: {
++      setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
++      break;
++    }
++  }
++  L->top = oldtop + 1;
++}
++
++
++static void restore_stack_limit (lua_State *L) {
++  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
++  if (L->size_ci > LUAI_MAXCALLS) {  /* there was an overflow? */
++    int inuse = cast_int(L->ci - L->base_ci);
++    if (inuse + 1 < LUAI_MAXCALLS)  /* can `undo' overflow? */
++      luaD_reallocCI(L, LUAI_MAXCALLS);
++  }
++}
++
++
++static void resetstack (lua_State *L, int status) {
++  L->ci = L->base_ci;
++  L->base = L->ci->base;
++  luaF_close(L, L->base);  /* close eventual pending closures */
++  luaD_seterrorobj(L, status, L->base);
++  L->nCcalls = L->baseCcalls;
++  L->allowhook = 1;
++  restore_stack_limit(L);
++  L->errfunc = 0;
++  L->errorJmp = NULL;
++}
++
++
++void luaD_throw (lua_State *L, int errcode) {
++  if (L->errorJmp) {
++    L->errorJmp->status = errcode;
++    LUAI_THROW(L, L->errorJmp);
++  }
++  else {
++    L->status = cast_byte(errcode);
++    if (G(L)->panic) {
++      resetstack(L, errcode);
++      lua_unlock(L);
++      G(L)->panic(L);
++    }
++    exit(EXIT_FAILURE);
++  }
++}
++
++
++int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
++  struct lua_longjmp lj;
++  lj.status = 0;
++  lj.previous = L->errorJmp;  /* chain new error handler */
++  L->errorJmp = &lj;
++  LUAI_TRY(L, &lj,
++    (*f)(L, ud);
++  );
++  L->errorJmp = lj.previous;  /* restore old error handler */
++  return lj.status;
++}
++
++/* }====================================================== */
++
++
++static void correctstack (lua_State *L, TValue *oldstack) {
++  CallInfo *ci;
++  GCObject *up;
++  L->top = (L->top - oldstack) + L->stack;
++  for (up = L->openupval; up != NULL; up = up->gch.next)
++    gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
++  for (ci = L->base_ci; ci <= L->ci; ci++) {
++    ci->top = (ci->top - oldstack) + L->stack;
++    ci->base = (ci->base - oldstack) + L->stack;
++    ci->func = (ci->func - oldstack) + L->stack;
++  }
++  L->base = (L->base - oldstack) + L->stack;
++}
++
++
++void luaD_reallocstack (lua_State *L, int newsize) {
++  TValue *oldstack = L->stack;
++  int realsize = newsize + 1 + EXTRA_STACK;
++  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
++  luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
++  L->stacksize = realsize;
++  L->stack_last = L->stack+newsize;
++  correctstack(L, oldstack);
++}
++
++
++void luaD_reallocCI (lua_State *L, int newsize) {
++  CallInfo *oldci = L->base_ci;
++  luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
++  L->size_ci = newsize;
++  L->ci = (L->ci - oldci) + L->base_ci;
++  L->end_ci = L->base_ci + L->size_ci - 1;
++}
++
++
++void luaD_growstack (lua_State *L, int n) {
++  if (n <= L->stacksize)  /* double size is enough? */
++    luaD_reallocstack(L, 2*L->stacksize);
++  else
++    luaD_reallocstack(L, L->stacksize + n);
++}
++
++
++static CallInfo *growCI (lua_State *L) {
++  if (L->size_ci > LUAI_MAXCALLS)  /* overflow while handling overflow? */
++    luaD_throw(L, LUA_ERRERR);
++  else {
++    luaD_reallocCI(L, 2*L->size_ci);
++    if (L->size_ci > LUAI_MAXCALLS)
++      luaG_runerror(L, "stack overflow");
++  }
++  return ++L->ci;
++}
++
++
++void luaD_callhook (lua_State *L, int event, int line) {
++  lua_Hook hook = L->hook;
++  if (hook && L->allowhook) {
++    ptrdiff_t top = savestack(L, L->top);
++    ptrdiff_t ci_top = savestack(L, L->ci->top);
++    lua_Debug ar;
++    ar.event = event;
++    ar.currentline = line;
++    if (event == LUA_HOOKTAILRET)
++      ar.i_ci = 0;  /* tail call; no debug information about it */
++    else
++      ar.i_ci = cast_int(L->ci - L->base_ci);
++    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
++    L->ci->top = L->top + LUA_MINSTACK;
++    lua_assert(L->ci->top <= L->stack_last);
++    L->allowhook = 0;  /* cannot call hooks inside a hook */
++    lua_unlock(L);
++    (*hook)(L, &ar);
++    lua_lock(L);
++    lua_assert(!L->allowhook);
++    L->allowhook = 1;
++    L->ci->top = restorestack(L, ci_top);
++    L->top = restorestack(L, top);
++  }
++}
++
++
++static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
++  int i;
++  int nfixargs = p->numparams;
++  Table *htab = NULL;
++  StkId base, fixed;
++  for (; actual < nfixargs; ++actual)
++    setnilvalue(L->top++);
++#if defined(LUA_COMPAT_VARARG)
++  if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */
++    int nvar = actual - nfixargs;  /* number of extra arguments */
++    lua_assert(p->is_vararg & VARARG_HASARG);
++    luaC_checkGC(L);
++    htab = luaH_new(L, nvar, 1);  /* create `arg' table */
++    for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */
++      setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
++    /* store counter in field `n' */
++    setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
++  }
++#endif
++  /* move fixed parameters to final position */
++  fixed = L->top - actual;  /* first fixed argument */
++  base = L->top;  /* final position of first argument */
++  for (i=0; i<nfixargs; i++) {
++    setobjs2s(L, L->top++, fixed+i);
++    setnilvalue(fixed+i);
++  }
++  /* add `arg' parameter */
++  if (htab) {
++    sethvalue(L, L->top++, htab);
++    lua_assert(iswhite(obj2gco(htab)));
++  }
++  return base;
++}
++
++
++static StkId tryfuncTM (lua_State *L, StkId func) {
++  const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
++  StkId p;
++  ptrdiff_t funcr = savestack(L, func);
++  if (!ttisfunction(tm))
++    luaG_typeerror(L, func, "call");
++  /* Open a hole inside the stack at `func' */
++  for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
++  incr_top(L);
++  func = restorestack(L, funcr);  /* previous call may change stack */
++  setobj2s(L, func, tm);  /* tag method is the new function to be called */
++  return func;
++}
++
++
++
++#define inc_ci(L) \
++  ((L->ci == L->end_ci) ? growCI(L) : \
++   (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci))
++
++
++int luaD_precall (lua_State *L, StkId func, int nresults) {
++  LClosure *cl;
++  ptrdiff_t funcr;
++  if (!ttisfunction(func)) /* `func' is not a function? */
++    func = tryfuncTM(L, func);  /* check the `function' tag method */
++  funcr = savestack(L, func);
++  cl = &clvalue(func)->l;
++  L->ci->savedpc = L->savedpc;
++  if (!cl->isC) {  /* Lua function? prepare its call */
++    CallInfo *ci;
++    StkId st, base;
++    Proto *p = cl->p;
++    luaD_checkstack(L, p->maxstacksize);
++    func = restorestack(L, funcr);
++    if (!p->is_vararg) {  /* no varargs? */
++      base = func + 1;
++      if (L->top > base + p->numparams)
++        L->top = base + p->numparams;
++    }
++    else {  /* vararg function */
++      int nargs = cast_int(L->top - func) - 1;
++      base = adjust_varargs(L, p, nargs);
++      func = restorestack(L, funcr);  /* previous call may change the stack */
++    }
++    ci = inc_ci(L);  /* now `enter' new function */
++    ci->func = func;
++    L->base = ci->base = base;
++    ci->top = L->base + p->maxstacksize;
++    lua_assert(ci->top <= L->stack_last);
++    L->savedpc = p->code;  /* starting point */
++    ci->tailcalls = 0;
++    ci->nresults = nresults;
++    for (st = L->top; st < ci->top; st++)
++      setnilvalue(st);
++    L->top = ci->top;
++    if (L->hookmask & LUA_MASKCALL) {
++      L->savedpc++;  /* hooks assume 'pc' is already incremented */
++      luaD_callhook(L, LUA_HOOKCALL, -1);
++      L->savedpc--;  /* correct 'pc' */
++    }
++    return PCRLUA;
++  }
++  else {  /* if is a C function, call it */
++    CallInfo *ci;
++    int n;
++    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
++    ci = inc_ci(L);  /* now `enter' new function */
++    ci->func = restorestack(L, funcr);
++    L->base = ci->base = ci->func + 1;
++    ci->top = L->top + LUA_MINSTACK;
++    lua_assert(ci->top <= L->stack_last);
++    ci->nresults = nresults;
++    if (L->hookmask & LUA_MASKCALL)
++      luaD_callhook(L, LUA_HOOKCALL, -1);
++    lua_unlock(L);
++    n = (*curr_func(L)->c.f)(L);  /* do the actual call */
++    lua_lock(L);
++    if (n < 0)  /* yielding? */
++      return PCRYIELD;
++    else {
++      luaD_poscall(L, L->top - n);
++      return PCRC;
++    }
++  }
++}
++
++
++static StkId callrethooks (lua_State *L, StkId firstResult) {
++  ptrdiff_t fr = savestack(L, firstResult);  /* next call may change stack */
++  luaD_callhook(L, LUA_HOOKRET, -1);
++  if (f_isLua(L->ci)) {  /* Lua function? */
++    while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */
++      luaD_callhook(L, LUA_HOOKTAILRET, -1);
++  }
++  return restorestack(L, fr);
++}
++
++
++int luaD_poscall (lua_State *L, StkId firstResult) {
++  StkId res;
++  int wanted, i;
++  CallInfo *ci;
++  if (L->hookmask & LUA_MASKRET)
++    firstResult = callrethooks(L, firstResult);
++  ci = L->ci--;
++  res = ci->func;  /* res == final position of 1st result */
++  wanted = ci->nresults;
++  L->base = (ci - 1)->base;  /* restore base */
++  L->savedpc = (ci - 1)->savedpc;  /* restore savedpc */
++  /* move results to correct place */
++  for (i = wanted; i != 0 && firstResult < L->top; i--)
++    setobjs2s(L, res++, firstResult++);
++  while (i-- > 0)
++    setnilvalue(res++);
++  L->top = res;
++  return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */
++}
++
++
++/*
++** Call a function (C or Lua). The function to be called is at *func.
++** The arguments are on the stack, right after the function.
++** When returns, all the results are on the stack, starting at the original
++** function position.
++*/
++void luaD_call (lua_State *L, StkId func, int nResults) {
++  if (++L->nCcalls >= LUAI_MAXCCALLS) {
++    if (L->nCcalls == LUAI_MAXCCALLS)
++      luaG_runerror(L, "C stack overflow");
++    else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
++      luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
++  }
++  if (luaD_precall(L, func, nResults) == PCRLUA)  /* is a Lua function? */
++    luaV_execute(L, 1);  /* call it */
++  L->nCcalls--;
++  luaC_checkGC(L);
++}
++
++
++static void resume (lua_State *L, void *ud) {
++  StkId firstArg = cast(StkId, ud);
++  CallInfo *ci = L->ci;
++  if (L->status == 0) {  /* start coroutine? */
++    lua_assert(ci == L->base_ci && firstArg > L->base);
++    if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA)
++      return;
++  }
++  else {  /* resuming from previous yield */
++    lua_assert(L->status == LUA_YIELD);
++    L->status = 0;
++    if (!f_isLua(ci)) {  /* `common' yield? */
++      /* finish interrupted execution of `OP_CALL' */
++      lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
++                 GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
++      if (luaD_poscall(L, firstArg))  /* complete it... */
++        L->top = L->ci->top;  /* and correct top if not multiple results */
++    }
++    else  /* yielded inside a hook: just continue its execution */
++      L->base = L->ci->base;
++  }
++  luaV_execute(L, cast_int(L->ci - L->base_ci));
++}
++
++
++static int resume_error (lua_State *L, const char *msg) {
++  L->top = L->ci->base;
++  setsvalue2s(L, L->top, luaS_new(L, msg));
++  incr_top(L);
++  lua_unlock(L);
++  return LUA_ERRRUN;
++}
++
++
++LUA_API int lua_resume (lua_State *L, int nargs) {
++  int status;
++  lua_lock(L);
++  if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
++      return resume_error(L, "cannot resume non-suspended coroutine");
++  if (L->nCcalls >= LUAI_MAXCCALLS)
++    return resume_error(L, "C stack overflow");
++  luai_userstateresume(L, nargs);
++  lua_assert(L->errfunc == 0);
++  L->baseCcalls = ++L->nCcalls;
++  status = luaD_rawrunprotected(L, resume, L->top - nargs);
++  if (status != 0) {  /* error? */
++    L->status = cast_byte(status);  /* mark thread as `dead' */
++    luaD_seterrorobj(L, status, L->top);
++    L->ci->top = L->top;
++  }
++  else {
++    lua_assert(L->nCcalls == L->baseCcalls);
++    status = L->status;
++  }
++  --L->nCcalls;
++  lua_unlock(L);
++  return status;
++}
++
++
++LUA_API int lua_yield (lua_State *L, int nresults) {
++  luai_userstateyield(L, nresults);
++  lua_lock(L);
++  if (L->nCcalls > L->baseCcalls)
++    luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
++  L->base = L->top - nresults;  /* protect stack slots below */
++  L->status = LUA_YIELD;
++  lua_unlock(L);
++  return -1;
++}
++
++
++int luaD_pcall (lua_State *L, Pfunc func, void *u,
++                ptrdiff_t old_top, ptrdiff_t ef) {
++  int status;
++  unsigned short oldnCcalls = L->nCcalls;
++  ptrdiff_t old_ci = saveci(L, L->ci);
++  lu_byte old_allowhooks = L->allowhook;
++  ptrdiff_t old_errfunc = L->errfunc;
++  L->errfunc = ef;
++  status = luaD_rawrunprotected(L, func, u);
++  if (status != 0) {  /* an error occurred? */
++    StkId oldtop = restorestack(L, old_top);
++    luaF_close(L, oldtop);  /* close eventual pending closures */
++    luaD_seterrorobj(L, status, oldtop);
++    L->nCcalls = oldnCcalls;
++    L->ci = restoreci(L, old_ci);
++    L->base = L->ci->base;
++    L->savedpc = L->ci->savedpc;
++    L->allowhook = old_allowhooks;
++    restore_stack_limit(L);
++  }
++  L->errfunc = old_errfunc;
++  return status;
++}
++
++
++
++/*
++** Execute a protected parser.
++*/
++struct SParser {  /* data to `f_parser' */
++  ZIO *z;
++  Mbuffer buff;  /* buffer to be used by the scanner */
++  const char *name;
++};
++
++static void f_parser (lua_State *L, void *ud) {
++  int i;
++  Proto *tf;
++  Closure *cl;
++  struct SParser *p = cast(struct SParser *, ud);
++  int c = luaZ_lookahead(p->z);
++  luaC_checkGC(L);
++  tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
++                                                             &p->buff, p->name);
++  cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
++  cl->l.p = tf;
++  for (i = 0; i < tf->nups; i++)  /* initialize eventual upvalues */
++    cl->l.upvals[i] = luaF_newupval(L);
++  setclvalue(L, L->top, cl);
++  incr_top(L);
++}
++
++
++int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) {
++  struct SParser p;
++  int status;
++  p.z = z; p.name = name;
++  luaZ_initbuffer(L, &p.buff);
++  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
++  luaZ_freebuffer(L, &p.buff);
++  return status;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/ldo.h
+@@ -0,0 +1,57 @@
++/*
++** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $
++** Stack and Call structure of Lua
++** See Copyright Notice in lua.h
++*/
++
++#ifndef ldo_h
++#define ldo_h
++
++
++#include "lobject.h"
++#include "lstate.h"
++#include "lzio.h"
++
++
++#define luaD_checkstack(L,n)	\
++  if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \
++    luaD_growstack(L, n); \
++  else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1));
++
++
++#define incr_top(L) {luaD_checkstack(L,1); L->top++;}
++
++#define savestack(L,p)		((char *)(p) - (char *)L->stack)
++#define restorestack(L,n)	((TValue *)((char *)L->stack + (n)))
++
++#define saveci(L,p)		((char *)(p) - (char *)L->base_ci)
++#define restoreci(L,n)		((CallInfo *)((char *)L->base_ci + (n)))
++
++
++/* results from luaD_precall */
++#define PCRLUA		0	/* initiated a call to a Lua function */
++#define PCRC		1	/* did a call to a C function */
++#define PCRYIELD	2	/* C funtion yielded */
++
++
++/* type of protected functions, to be ran by `runprotected' */
++typedef void (*Pfunc) (lua_State *L, void *ud);
++
++LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
++LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line);
++LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
++LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
++LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
++                                        ptrdiff_t oldtop, ptrdiff_t ef);
++LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
++LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
++LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
++LUAI_FUNC void luaD_growstack (lua_State *L, int n);
++
++LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
++LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
++
++LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
++
++#endif
++
+--- /dev/null
++++ b/extensions/LUA/lua/ldump.c
+@@ -0,0 +1,164 @@
++/*
++** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
++** save precompiled Lua chunks
++** See Copyright Notice in lua.h
++*/
++
++#include <stddef.h>
++
++#define ldump_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lobject.h"
++#include "lstate.h"
++#include "lundump.h"
++
++typedef struct {
++ lua_State* L;
++ lua_Writer writer;
++ void* data;
++ int strip;
++ int status;
++} DumpState;
++
++#define DumpMem(b,n,size,D)	DumpBlock(b,(n)*(size),D)
++#define DumpVar(x,D)	 	DumpMem(&x,1,sizeof(x),D)
++
++static void DumpBlock(const void* b, size_t size, DumpState* D)
++{
++ if (D->status==0)
++ {
++  lua_unlock(D->L);
++  D->status=(*D->writer)(D->L,b,size,D->data);
++  lua_lock(D->L);
++ }
++}
++
++static void DumpChar(int y, DumpState* D)
++{
++ char x=(char)y;
++ DumpVar(x,D);
++}
++
++static void DumpInt(int x, DumpState* D)
++{
++ DumpVar(x,D);
++}
++
++static void DumpNumber(lua_Number x, DumpState* D)
++{
++ DumpVar(x,D);
++}
++
++static void DumpVector(const void* b, int n, size_t size, DumpState* D)
++{
++ DumpInt(n,D);
++ DumpMem(b,n,size,D);
++}
++
++static void DumpString(const TString* s, DumpState* D)
++{
++ if (s==NULL || getstr(s)==NULL)
++ {
++  size_t size=0;
++  DumpVar(size,D);
++ }
++ else
++ {
++  size_t size=s->tsv.len+1;		/* include trailing '\0' */
++  DumpVar(size,D);
++  DumpBlock(getstr(s),size,D);
++ }
++}
++
++#define DumpCode(f,D)	 DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
++
++static void DumpFunction(const Proto* f, const TString* p, DumpState* D);
++
++static void DumpConstants(const Proto* f, DumpState* D)
++{
++ int i,n=f->sizek;
++ DumpInt(n,D);
++ for (i=0; i<n; i++)
++ {
++  const TValue* o=&f->k[i];
++  DumpChar(ttype(o),D);
++  switch (ttype(o))
++  {
++   case LUA_TNIL:
++	break;
++   case LUA_TBOOLEAN:
++	DumpChar(bvalue(o),D);
++	break;
++   case LUA_TNUMBER:
++	DumpNumber(nvalue(o),D);
++	break;
++   case LUA_TSTRING:
++	DumpString(rawtsvalue(o),D);
++	break;
++   default:
++	lua_assert(0);			/* cannot happen */
++	break;
++  }
++ }
++ n=f->sizep;
++ DumpInt(n,D);
++ for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
++}
++
++static void DumpDebug(const Proto* f, DumpState* D)
++{
++ int i,n;
++ n= (D->strip) ? 0 : f->sizelineinfo;
++ DumpVector(f->lineinfo,n,sizeof(int),D);
++ n= (D->strip) ? 0 : f->sizelocvars;
++ DumpInt(n,D);
++ for (i=0; i<n; i++)
++ {
++  DumpString(f->locvars[i].varname,D);
++  DumpInt(f->locvars[i].startpc,D);
++  DumpInt(f->locvars[i].endpc,D);
++ }
++ n= (D->strip) ? 0 : f->sizeupvalues;
++ DumpInt(n,D);
++ for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
++}
++
++static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
++{
++ DumpString((f->source==p || D->strip) ? NULL : f->source,D);
++ DumpInt(f->linedefined,D);
++ DumpInt(f->lastlinedefined,D);
++ DumpChar(f->nups,D);
++ DumpChar(f->numparams,D);
++ DumpChar(f->is_vararg,D);
++ DumpChar(f->maxstacksize,D);
++ DumpCode(f,D);
++ DumpConstants(f,D);
++ DumpDebug(f,D);
++}
++
++static void DumpHeader(DumpState* D)
++{
++ char h[LUAC_HEADERSIZE];
++ luaU_header(h);
++ DumpBlock(h,LUAC_HEADERSIZE,D);
++}
++
++/*
++** dump Lua function as precompiled chunk
++*/
++int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
++{
++ DumpState D;
++ D.L=L;
++ D.writer=w;
++ D.data=data;
++ D.strip=strip;
++ D.status=0;
++ DumpHeader(&D);
++ DumpFunction(f,NULL,&D);
++ return D.status;
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lfunc.c
+@@ -0,0 +1,174 @@
++/*
++** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $
++** Auxiliary functions to manipulate prototypes and closures
++** See Copyright Notice in lua.h
++*/
++
++
++#include <stddef.h>
++
++#define lfunc_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lfunc.h"
++#include "lgc.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++
++
++
++Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) {
++  Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
++  luaC_link(L, obj2gco(c), LUA_TFUNCTION);
++  c->c.isC = 1;
++  c->c.env = e;
++  c->c.nupvalues = cast_byte(nelems);
++  return c;
++}
++
++
++Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
++  Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
++  luaC_link(L, obj2gco(c), LUA_TFUNCTION);
++  c->l.isC = 0;
++  c->l.env = e;
++  c->l.nupvalues = cast_byte(nelems);
++  while (nelems--) c->l.upvals[nelems] = NULL;
++  return c;
++}
++
++
++UpVal *luaF_newupval (lua_State *L) {
++  UpVal *uv = luaM_new(L, UpVal);
++  luaC_link(L, obj2gco(uv), LUA_TUPVAL);
++  uv->v = &uv->u.value;
++  setnilvalue(uv->v);
++  return uv;
++}
++
++
++UpVal *luaF_findupval (lua_State *L, StkId level) {
++  global_State *g = G(L);
++  GCObject **pp = &L->openupval;
++  UpVal *p;
++  UpVal *uv;
++  while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) {
++    lua_assert(p->v != &p->u.value);
++    if (p->v == level) {  /* found a corresponding upvalue? */
++      if (isdead(g, obj2gco(p)))  /* is it dead? */
++        changewhite(obj2gco(p));  /* ressurect it */
++      return p;
++    }
++    pp = &p->next;
++  }
++  uv = luaM_new(L, UpVal);  /* not found: create a new one */
++  uv->tt = LUA_TUPVAL;
++  uv->marked = luaC_white(g);
++  uv->v = level;  /* current value lives in the stack */
++  uv->next = *pp;  /* chain it in the proper position */
++  *pp = obj2gco(uv);
++  uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */
++  uv->u.l.next = g->uvhead.u.l.next;
++  uv->u.l.next->u.l.prev = uv;
++  g->uvhead.u.l.next = uv;
++  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
++  return uv;
++}
++
++
++static void unlinkupval (UpVal *uv) {
++  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
++  uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */
++  uv->u.l.prev->u.l.next = uv->u.l.next;
++}
++
++
++void luaF_freeupval (lua_State *L, UpVal *uv) {
++  if (uv->v != &uv->u.value)  /* is it open? */
++    unlinkupval(uv);  /* remove from open list */
++  luaM_free(L, uv);  /* free upvalue */
++}
++
++
++void luaF_close (lua_State *L, StkId level) {
++  UpVal *uv;
++  global_State *g = G(L);
++  while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
++    GCObject *o = obj2gco(uv);
++    lua_assert(!isblack(o) && uv->v != &uv->u.value);
++    L->openupval = uv->next;  /* remove from `open' list */
++    if (isdead(g, o))
++      luaF_freeupval(L, uv);  /* free upvalue */
++    else {
++      unlinkupval(uv);
++      setobj(L, &uv->u.value, uv->v);
++      uv->v = &uv->u.value;  /* now current value lives here */
++      luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */
++    }
++  }
++}
++
++
++Proto *luaF_newproto (lua_State *L) {
++  Proto *f = luaM_new(L, Proto);
++  luaC_link(L, obj2gco(f), LUA_TPROTO);
++  f->k = NULL;
++  f->sizek = 0;
++  f->p = NULL;
++  f->sizep = 0;
++  f->code = NULL;
++  f->sizecode = 0;
++  f->sizelineinfo = 0;
++  f->sizeupvalues = 0;
++  f->nups = 0;
++  f->upvalues = NULL;
++  f->numparams = 0;
++  f->is_vararg = 0;
++  f->maxstacksize = 0;
++  f->lineinfo = NULL;
++  f->sizelocvars = 0;
++  f->locvars = NULL;
++  f->linedefined = 0;
++  f->lastlinedefined = 0;
++  f->source = NULL;
++  return f;
++}
++
++
++void luaF_freeproto (lua_State *L, Proto *f) {
++  luaM_freearray(L, f->code, f->sizecode, Instruction);
++  luaM_freearray(L, f->p, f->sizep, Proto *);
++  luaM_freearray(L, f->k, f->sizek, TValue);
++  luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
++  luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
++  luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
++  luaM_free(L, f);
++}
++
++
++void luaF_freeclosure (lua_State *L, Closure *c) {
++  int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
++                          sizeLclosure(c->l.nupvalues);
++  luaM_freemem(L, c, size);
++}
++
++
++/*
++** Look for n-th local variable at line `line' in function `func'.
++** Returns NULL if not found.
++*/
++const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
++  int i;
++  for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
++    if (pc < f->locvars[i].endpc) {  /* is variable active? */
++      local_number--;
++      if (local_number == 0)
++        return getstr(f->locvars[i].varname);
++    }
++  }
++  return NULL;  /* not found */
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lfunc.h
+@@ -0,0 +1,34 @@
++/*
++** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $
++** Auxiliary functions to manipulate prototypes and closures
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lfunc_h
++#define lfunc_h
++
++
++#include "lobject.h"
++
++
++#define sizeCclosure(n)	(cast(int, sizeof(CClosure)) + \
++                         cast(int, sizeof(TValue)*((n)-1)))
++
++#define sizeLclosure(n)	(cast(int, sizeof(LClosure)) + \
++                         cast(int, sizeof(TValue *)*((n)-1)))
++
++
++LUAI_FUNC Proto *luaF_newproto (lua_State *L);
++LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
++LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
++LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
++LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
++LUAI_FUNC void luaF_close (lua_State *L, StkId level);
++LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
++LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
++LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
++LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
++                                         int pc);
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lgc.c
+@@ -0,0 +1,711 @@
++/*
++** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
++** Garbage Collector
++** See Copyright Notice in lua.h
++*/
++
++#include <string.h>
++
++#define lgc_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lgc.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++
++
++#define GCSTEPSIZE	1024u
++#define GCSWEEPMAX	40
++#define GCSWEEPCOST	10
++#define GCFINALIZECOST	100
++
++
++#define maskmarks	cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
++
++#define makewhite(g,x)	\
++   ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
++
++#define white2gray(x)	reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
++#define black2gray(x)	resetbit((x)->gch.marked, BLACKBIT)
++
++#define stringmark(s)	reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
++
++
++#define isfinalized(u)		testbit((u)->marked, FINALIZEDBIT)
++#define markfinalized(u)	l_setbit((u)->marked, FINALIZEDBIT)
++
++
++#define KEYWEAK         bitmask(KEYWEAKBIT)
++#define VALUEWEAK       bitmask(VALUEWEAKBIT)
++
++
++
++#define markvalue(g,o) { checkconsistency(o); \
++  if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
++
++#define markobject(g,t) { if (iswhite(obj2gco(t))) \
++		reallymarkobject(g, obj2gco(t)); }
++
++
++#define setthreshold(g)  (g->GCthreshold = (g->estimate/100) * g->gcpause)
++
++
++static void removeentry (Node *n) {
++  lua_assert(ttisnil(gval(n)));
++  if (iscollectable(gkey(n)))
++    setttype(gkey(n), LUA_TDEADKEY);  /* dead key; remove it */
++}
++
++
++static void reallymarkobject (global_State *g, GCObject *o) {
++  lua_assert(iswhite(o) && !isdead(g, o));
++  white2gray(o);
++  switch (o->gch.tt) {
++    case LUA_TSTRING: {
++      return;
++    }
++    case LUA_TUSERDATA: {
++      Table *mt = gco2u(o)->metatable;
++      gray2black(o);  /* udata are never gray */
++      if (mt) markobject(g, mt);
++      markobject(g, gco2u(o)->env);
++      return;
++    }
++    case LUA_TUPVAL: {
++      UpVal *uv = gco2uv(o);
++      markvalue(g, uv->v);
++      if (uv->v == &uv->u.value)  /* closed? */
++        gray2black(o);  /* open upvalues are never black */
++      return;
++    }
++    case LUA_TFUNCTION: {
++      gco2cl(o)->c.gclist = g->gray;
++      g->gray = o;
++      break;
++    }
++    case LUA_TTABLE: {
++      gco2h(o)->gclist = g->gray;
++      g->gray = o;
++      break;
++    }
++    case LUA_TTHREAD: {
++      gco2th(o)->gclist = g->gray;
++      g->gray = o;
++      break;
++    }
++    case LUA_TPROTO: {
++      gco2p(o)->gclist = g->gray;
++      g->gray = o;
++      break;
++    }
++    default: lua_assert(0);
++  }
++}
++
++
++static void marktmu (global_State *g) {
++  GCObject *u = g->tmudata;
++  if (u) {
++    do {
++      u = u->gch.next;
++      makewhite(g, u);  /* may be marked, if left from previous GC */
++      reallymarkobject(g, u);
++    } while (u != g->tmudata);
++  }
++}
++
++
++/* move `dead' udata that need finalization to list `tmudata' */
++size_t luaC_separateudata (lua_State *L, int all) {
++  global_State *g = G(L);
++  size_t deadmem = 0;
++  GCObject **p = &g->mainthread->next;
++  GCObject *curr;
++  while ((curr = *p) != NULL) {
++    if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
++      p = &curr->gch.next;  /* don't bother with them */
++    else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
++      markfinalized(gco2u(curr));  /* don't need finalization */
++      p = &curr->gch.next;
++    }
++    else {  /* must call its gc method */
++      deadmem += sizeudata(gco2u(curr));
++      markfinalized(gco2u(curr));
++      *p = curr->gch.next;
++      /* link `curr' at the end of `tmudata' list */
++      if (g->tmudata == NULL)  /* list is empty? */
++        g->tmudata = curr->gch.next = curr;  /* creates a circular list */
++      else {
++        curr->gch.next = g->tmudata->gch.next;
++        g->tmudata->gch.next = curr;
++        g->tmudata = curr;
++      }
++    }
++  }
++  return deadmem;
++}
++
++
++static int traversetable (global_State *g, Table *h) {
++  int i;
++  int weakkey = 0;
++  int weakvalue = 0;
++  const TValue *mode;
++  if (h->metatable)
++    markobject(g, h->metatable);
++  mode = gfasttm(g, h->metatable, TM_MODE);
++  if (mode && ttisstring(mode)) {  /* is there a weak mode? */
++    weakkey = (strchr(svalue(mode), 'k') != NULL);
++    weakvalue = (strchr(svalue(mode), 'v') != NULL);
++    if (weakkey || weakvalue) {  /* is really weak? */
++      h->marked &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */
++      h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
++                             (weakvalue << VALUEWEAKBIT));
++      h->gclist = g->weak;  /* must be cleared after GC, ... */
++      g->weak = obj2gco(h);  /* ... so put in the appropriate list */
++    }
++  }
++  if (weakkey && weakvalue) return 1;
++  if (!weakvalue) {
++    i = h->sizearray;
++    while (i--)
++      markvalue(g, &h->array[i]);
++  }
++  i = sizenode(h);
++  while (i--) {
++    Node *n = gnode(h, i);
++    lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
++    if (ttisnil(gval(n)))
++      removeentry(n);  /* remove empty entries */
++    else {
++      lua_assert(!ttisnil(gkey(n)));
++      if (!weakkey) markvalue(g, gkey(n));
++      if (!weakvalue) markvalue(g, gval(n));
++    }
++  }
++  return weakkey || weakvalue;
++}
++
++
++/*
++** All marks are conditional because a GC may happen while the
++** prototype is still being created
++*/
++static void traverseproto (global_State *g, Proto *f) {
++  int i;
++  if (f->source) stringmark(f->source);
++  for (i=0; i<f->sizek; i++)  /* mark literals */
++    markvalue(g, &f->k[i]);
++  for (i=0; i<f->sizeupvalues; i++) {  /* mark upvalue names */
++    if (f->upvalues[i])
++      stringmark(f->upvalues[i]);
++  }
++  for (i=0; i<f->sizep; i++) {  /* mark nested protos */
++    if (f->p[i])
++      markobject(g, f->p[i]);
++  }
++  for (i=0; i<f->sizelocvars; i++) {  /* mark local-variable names */
++    if (f->locvars[i].varname)
++      stringmark(f->locvars[i].varname);
++  }
++}
++
++
++
++static void traverseclosure (global_State *g, Closure *cl) {
++  markobject(g, cl->c.env);
++  if (cl->c.isC) {
++    int i;
++    for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */
++      markvalue(g, &cl->c.upvalue[i]);
++  }
++  else {
++    int i;
++    lua_assert(cl->l.nupvalues == cl->l.p->nups);
++    markobject(g, cl->l.p);
++    for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */
++      markobject(g, cl->l.upvals[i]);
++  }
++}
++
++
++static void checkstacksizes (lua_State *L, StkId max) {
++  int ci_used = cast_int(L->ci - L->base_ci);  /* number of `ci' in use */
++  int s_used = cast_int(max - L->stack);  /* part of stack in use */
++  if (L->size_ci > LUAI_MAXCALLS)  /* handling overflow? */
++    return;  /* do not touch the stacks */
++  if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
++    luaD_reallocCI(L, L->size_ci/2);  /* still big enough... */
++  condhardstacktests(luaD_reallocCI(L, ci_used + 1));
++  if (4*s_used < L->stacksize &&
++      2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
++    luaD_reallocstack(L, L->stacksize/2);  /* still big enough... */
++  condhardstacktests(luaD_reallocstack(L, s_used));
++}
++
++
++static void traversestack (global_State *g, lua_State *l) {
++  StkId o, lim;
++  CallInfo *ci;
++  markvalue(g, gt(l));
++  lim = l->top;
++  for (ci = l->base_ci; ci <= l->ci; ci++) {
++    lua_assert(ci->top <= l->stack_last);
++    if (lim < ci->top) lim = ci->top;
++  }
++  for (o = l->stack; o < l->top; o++)
++    markvalue(g, o);
++  for (; o <= lim; o++)
++    setnilvalue(o);
++  checkstacksizes(l, lim);
++}
++
++
++/*
++** traverse one gray object, turning it to black.
++** Returns `quantity' traversed.
++*/
++static l_mem propagatemark (global_State *g) {
++  GCObject *o = g->gray;
++  lua_assert(isgray(o));
++  gray2black(o);
++  switch (o->gch.tt) {
++    case LUA_TTABLE: {
++      Table *h = gco2h(o);
++      g->gray = h->gclist;
++      if (traversetable(g, h))  /* table is weak? */
++        black2gray(o);  /* keep it gray */
++      return sizeof(Table) + sizeof(TValue) * h->sizearray +
++                             sizeof(Node) * sizenode(h);
++    }
++    case LUA_TFUNCTION: {
++      Closure *cl = gco2cl(o);
++      g->gray = cl->c.gclist;
++      traverseclosure(g, cl);
++      return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
++                           sizeLclosure(cl->l.nupvalues);
++    }
++    case LUA_TTHREAD: {
++      lua_State *th = gco2th(o);
++      g->gray = th->gclist;
++      th->gclist = g->grayagain;
++      g->grayagain = o;
++      black2gray(o);
++      traversestack(g, th);
++      return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
++                                 sizeof(CallInfo) * th->size_ci;
++    }
++    case LUA_TPROTO: {
++      Proto *p = gco2p(o);
++      g->gray = p->gclist;
++      traverseproto(g, p);
++      return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
++                             sizeof(Proto *) * p->sizep +
++                             sizeof(TValue) * p->sizek + 
++                             sizeof(int) * p->sizelineinfo +
++                             sizeof(LocVar) * p->sizelocvars +
++                             sizeof(TString *) * p->sizeupvalues;
++    }
++    default: lua_assert(0); return 0;
++  }
++}
++
++
++static size_t propagateall (global_State *g) {
++  size_t m = 0;
++  while (g->gray) m += propagatemark(g);
++  return m;
++}
++
++
++/*
++** The next function tells whether a key or value can be cleared from
++** a weak table. Non-collectable objects are never removed from weak
++** tables. Strings behave as `values', so are never removed too. for
++** other objects: if really collected, cannot keep them; for userdata
++** being finalized, keep them in keys, but not in values
++*/
++static int iscleared (const TValue *o, int iskey) {
++  if (!iscollectable(o)) return 0;
++  if (ttisstring(o)) {
++    stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */
++    return 0;
++  }
++  return iswhite(gcvalue(o)) ||
++    (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
++}
++
++
++/*
++** clear collected entries from weaktables
++*/
++static void cleartable (GCObject *l) {
++  while (l) {
++    Table *h = gco2h(l);
++    int i = h->sizearray;
++    lua_assert(testbit(h->marked, VALUEWEAKBIT) ||
++               testbit(h->marked, KEYWEAKBIT));
++    if (testbit(h->marked, VALUEWEAKBIT)) {
++      while (i--) {
++        TValue *o = &h->array[i];
++        if (iscleared(o, 0))  /* value was collected? */
++          setnilvalue(o);  /* remove value */
++      }
++    }
++    i = sizenode(h);
++    while (i--) {
++      Node *n = gnode(h, i);
++      if (!ttisnil(gval(n)) &&  /* non-empty entry? */
++          (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
++        setnilvalue(gval(n));  /* remove value ... */
++        removeentry(n);  /* remove entry from table */
++      }
++    }
++    l = h->gclist;
++  }
++}
++
++
++static void freeobj (lua_State *L, GCObject *o) {
++  switch (o->gch.tt) {
++    case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
++    case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
++    case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
++    case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
++    case LUA_TTHREAD: {
++      lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
++      luaE_freethread(L, gco2th(o));
++      break;
++    }
++    case LUA_TSTRING: {
++      G(L)->strt.nuse--;
++      luaM_freemem(L, o, sizestring(gco2ts(o)));
++      break;
++    }
++    case LUA_TUSERDATA: {
++      luaM_freemem(L, o, sizeudata(gco2u(o)));
++      break;
++    }
++    default: lua_assert(0);
++  }
++}
++
++
++
++#define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM)
++
++
++static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
++  GCObject *curr;
++  global_State *g = G(L);
++  int deadmask = otherwhite(g);
++  while ((curr = *p) != NULL && count-- > 0) {
++    if (curr->gch.tt == LUA_TTHREAD)  /* sweep open upvalues of each thread */
++      sweepwholelist(L, &gco2th(curr)->openupval);
++    if ((curr->gch.marked ^ WHITEBITS) & deadmask) {  /* not dead? */
++      lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
++      makewhite(g, curr);  /* make it white (for next cycle) */
++      p = &curr->gch.next;
++    }
++    else {  /* must erase `curr' */
++      lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
++      *p = curr->gch.next;
++      if (curr == g->rootgc)  /* is the first element of the list? */
++        g->rootgc = curr->gch.next;  /* adjust first */
++      freeobj(L, curr);
++    }
++  }
++  return p;
++}
++
++
++static void checkSizes (lua_State *L) {
++  global_State *g = G(L);
++  /* check size of string hash */
++  if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
++      g->strt.size > MINSTRTABSIZE*2)
++    luaS_resize(L, g->strt.size/2);  /* table is too big */
++  /* check size of buffer */
++  if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
++    size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
++    luaZ_resizebuffer(L, &g->buff, newsize);
++  }
++}
++
++
++static void GCTM (lua_State *L) {
++  global_State *g = G(L);
++  GCObject *o = g->tmudata->gch.next;  /* get first element */
++  Udata *udata = rawgco2u(o);
++  const TValue *tm;
++  /* remove udata from `tmudata' */
++  if (o == g->tmudata)  /* last element? */
++    g->tmudata = NULL;
++  else
++    g->tmudata->gch.next = udata->uv.next;
++  udata->uv.next = g->mainthread->next;  /* return it to `root' list */
++  g->mainthread->next = o;
++  makewhite(g, o);
++  tm = fasttm(L, udata->uv.metatable, TM_GC);
++  if (tm != NULL) {
++    lu_byte oldah = L->allowhook;
++    lu_mem oldt = g->GCthreshold;
++    L->allowhook = 0;  /* stop debug hooks during GC tag method */
++    g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */
++    setobj2s(L, L->top, tm);
++    setuvalue(L, L->top+1, udata);
++    L->top += 2;
++    luaD_call(L, L->top - 2, 0);
++    L->allowhook = oldah;  /* restore hooks */
++    g->GCthreshold = oldt;  /* restore threshold */
++  }
++}
++
++
++/*
++** Call all GC tag methods
++*/
++void luaC_callGCTM (lua_State *L) {
++  while (G(L)->tmudata)
++    GCTM(L);
++}
++
++
++void luaC_freeall (lua_State *L) {
++  global_State *g = G(L);
++  int i;
++  g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);  /* mask to collect all elements */
++  sweepwholelist(L, &g->rootgc);
++  for (i = 0; i < g->strt.size; i++)  /* free all string lists */
++    sweepwholelist(L, &g->strt.hash[i]);
++}
++
++
++static void markmt (global_State *g) {
++  int i;
++  for (i=0; i<NUM_TAGS; i++)
++    if (g->mt[i]) markobject(g, g->mt[i]);
++}
++
++
++/* mark root set */
++static void markroot (lua_State *L) {
++  global_State *g = G(L);
++  g->gray = NULL;
++  g->grayagain = NULL;
++  g->weak = NULL;
++  markobject(g, g->mainthread);
++  /* make global table be traversed before main stack */
++  markvalue(g, gt(g->mainthread));
++  markvalue(g, registry(L));
++  markmt(g);
++  g->gcstate = GCSpropagate;
++}
++
++
++static void remarkupvals (global_State *g) {
++  UpVal *uv;
++  for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
++    lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
++    if (isgray(obj2gco(uv)))
++      markvalue(g, uv->v);
++  }
++}
++
++
++static void atomic (lua_State *L) {
++  global_State *g = G(L);
++  size_t udsize;  /* total size of userdata to be finalized */
++  /* remark occasional upvalues of (maybe) dead threads */
++  remarkupvals(g);
++  /* traverse objects cautch by write barrier and by 'remarkupvals' */
++  propagateall(g);
++  /* remark weak tables */
++  g->gray = g->weak;
++  g->weak = NULL;
++  lua_assert(!iswhite(obj2gco(g->mainthread)));
++  markobject(g, L);  /* mark running thread */
++  markmt(g);  /* mark basic metatables (again) */
++  propagateall(g);
++  /* remark gray again */
++  g->gray = g->grayagain;
++  g->grayagain = NULL;
++  propagateall(g);
++  udsize = luaC_separateudata(L, 0);  /* separate userdata to be finalized */
++  marktmu(g);  /* mark `preserved' userdata */
++  udsize += propagateall(g);  /* remark, to propagate `preserveness' */
++  cleartable(g->weak);  /* remove collected objects from weak tables */
++  /* flip current white */
++  g->currentwhite = cast_byte(otherwhite(g));
++  g->sweepstrgc = 0;
++  g->sweepgc = &g->rootgc;
++  g->gcstate = GCSsweepstring;
++  g->estimate = g->totalbytes - udsize;  /* first estimate */
++}
++
++
++static l_mem singlestep (lua_State *L) {
++  global_State *g = G(L);
++  /*lua_checkmemory(L);*/
++  switch (g->gcstate) {
++    case GCSpause: {
++      markroot(L);  /* start a new collection */
++      return 0;
++    }
++    case GCSpropagate: {
++      if (g->gray)
++        return propagatemark(g);
++      else {  /* no more `gray' objects */
++        atomic(L);  /* finish mark phase */
++        return 0;
++      }
++    }
++    case GCSsweepstring: {
++      lu_mem old = g->totalbytes;
++      sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
++      if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
++        g->gcstate = GCSsweep;  /* end sweep-string phase */
++      lua_assert(old >= g->totalbytes);
++      g->estimate -= old - g->totalbytes;
++      return GCSWEEPCOST;
++    }
++    case GCSsweep: {
++      lu_mem old = g->totalbytes;
++      g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
++      if (*g->sweepgc == NULL) {  /* nothing more to sweep? */
++        checkSizes(L);
++        g->gcstate = GCSfinalize;  /* end sweep phase */
++      }
++      lua_assert(old >= g->totalbytes);
++      g->estimate -= old - g->totalbytes;
++      return GCSWEEPMAX*GCSWEEPCOST;
++    }
++    case GCSfinalize: {
++      if (g->tmudata) {
++        GCTM(L);
++        if (g->estimate > GCFINALIZECOST)
++          g->estimate -= GCFINALIZECOST;
++        return GCFINALIZECOST;
++      }
++      else {
++        g->gcstate = GCSpause;  /* end collection */
++        g->gcdept = 0;
++        return 0;
++      }
++    }
++    default: lua_assert(0); return 0;
++  }
++}
++
++
++void luaC_step (lua_State *L) {
++  global_State *g = G(L);
++  l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
++  if (lim == 0)
++    lim = (MAX_LUMEM-1)/2;  /* no limit */
++  g->gcdept += g->totalbytes - g->GCthreshold;
++  do {
++    lim -= singlestep(L);
++    if (g->gcstate == GCSpause)
++      break;
++  } while (lim > 0);
++  if (g->gcstate != GCSpause) {
++    if (g->gcdept < GCSTEPSIZE)
++      g->GCthreshold = g->totalbytes + GCSTEPSIZE;  /* - lim/g->gcstepmul;*/
++    else {
++      g->gcdept -= GCSTEPSIZE;
++      g->GCthreshold = g->totalbytes;
++    }
++  }
++  else {
++    lua_assert(g->totalbytes >= g->estimate);
++    setthreshold(g);
++  }
++}
++
++
++void luaC_fullgc (lua_State *L) {
++  global_State *g = G(L);
++  if (g->gcstate <= GCSpropagate) {
++    /* reset sweep marks to sweep all elements (returning them to white) */
++    g->sweepstrgc = 0;
++    g->sweepgc = &g->rootgc;
++    /* reset other collector lists */
++    g->gray = NULL;
++    g->grayagain = NULL;
++    g->weak = NULL;
++    g->gcstate = GCSsweepstring;
++  }
++  lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
++  /* finish any pending sweep phase */
++  while (g->gcstate != GCSfinalize) {
++    lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
++    singlestep(L);
++  }
++  markroot(L);
++  while (g->gcstate != GCSpause) {
++    singlestep(L);
++  }
++  setthreshold(g);
++}
++
++
++void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
++  global_State *g = G(L);
++  lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
++  lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
++  lua_assert(ttype(&o->gch) != LUA_TTABLE);
++  /* must keep invariant? */
++  if (g->gcstate == GCSpropagate)
++    reallymarkobject(g, v);  /* restore invariant */
++  else  /* don't mind */
++    makewhite(g, o);  /* mark as white just to avoid other barriers */
++}
++
++
++void luaC_barrierback (lua_State *L, Table *t) {
++  global_State *g = G(L);
++  GCObject *o = obj2gco(t);
++  lua_assert(isblack(o) && !isdead(g, o));
++  lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
++  black2gray(o);  /* make table gray (again) */
++  t->gclist = g->grayagain;
++  g->grayagain = o;
++}
++
++
++void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
++  global_State *g = G(L);
++  o->gch.next = g->rootgc;
++  g->rootgc = o;
++  o->gch.marked = luaC_white(g);
++  o->gch.tt = tt;
++}
++
++
++void luaC_linkupval (lua_State *L, UpVal *uv) {
++  global_State *g = G(L);
++  GCObject *o = obj2gco(uv);
++  o->gch.next = g->rootgc;  /* link upvalue into `rootgc' list */
++  g->rootgc = o;
++  if (isgray(o)) { 
++    if (g->gcstate == GCSpropagate) {
++      gray2black(o);  /* closed upvalues need barrier */
++      luaC_barrier(L, uv, uv->v);
++    }
++    else {  /* sweep phase: sweep it (turning it into white) */
++      makewhite(g, o);
++      lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
++    }
++  }
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lgc.h
+@@ -0,0 +1,110 @@
++/*
++** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $
++** Garbage Collector
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lgc_h
++#define lgc_h
++
++
++#include "lobject.h"
++
++
++/*
++** Possible states of the Garbage Collector
++*/
++#define GCSpause	0
++#define GCSpropagate	1
++#define GCSsweepstring	2
++#define GCSsweep	3
++#define GCSfinalize	4
++
++
++/*
++** some userful bit tricks
++*/
++#define resetbits(x,m)	((x) &= cast(lu_byte, ~(m)))
++#define setbits(x,m)	((x) |= (m))
++#define testbits(x,m)	((x) & (m))
++#define bitmask(b)	(1<<(b))
++#define bit2mask(b1,b2)	(bitmask(b1) | bitmask(b2))
++#define l_setbit(x,b)	setbits(x, bitmask(b))
++#define resetbit(x,b)	resetbits(x, bitmask(b))
++#define testbit(x,b)	testbits(x, bitmask(b))
++#define set2bits(x,b1,b2)	setbits(x, (bit2mask(b1, b2)))
++#define reset2bits(x,b1,b2)	resetbits(x, (bit2mask(b1, b2)))
++#define test2bits(x,b1,b2)	testbits(x, (bit2mask(b1, b2)))
++
++
++
++/*
++** Layout for bit use in `marked' field:
++** bit 0 - object is white (type 0)
++** bit 1 - object is white (type 1)
++** bit 2 - object is black
++** bit 3 - for userdata: has been finalized
++** bit 3 - for tables: has weak keys
++** bit 4 - for tables: has weak values
++** bit 5 - object is fixed (should not be collected)
++** bit 6 - object is "super" fixed (only the main thread)
++*/
++
++
++#define WHITE0BIT	0
++#define WHITE1BIT	1
++#define BLACKBIT	2
++#define FINALIZEDBIT	3
++#define KEYWEAKBIT	3
++#define VALUEWEAKBIT	4
++#define FIXEDBIT	5
++#define SFIXEDBIT	6
++#define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
++
++
++#define iswhite(x)      test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
++#define isblack(x)      testbit((x)->gch.marked, BLACKBIT)
++#define isgray(x)	(!isblack(x) && !iswhite(x))
++
++#define otherwhite(g)	(g->currentwhite ^ WHITEBITS)
++#define isdead(g,v)	((v)->gch.marked & otherwhite(g) & WHITEBITS)
++
++#define changewhite(x)	((x)->gch.marked ^= WHITEBITS)
++#define gray2black(x)	l_setbit((x)->gch.marked, BLACKBIT)
++
++#define valiswhite(x)	(iscollectable(x) && iswhite(gcvalue(x)))
++
++#define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS)
++
++
++#define luaC_checkGC(L) { \
++  condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
++  if (G(L)->totalbytes >= G(L)->GCthreshold) \
++	luaC_step(L); }
++
++
++#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p)))  \
++	luaC_barrierf(L,obj2gco(p),gcvalue(v)); }
++
++#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t)))  \
++	luaC_barrierback(L,t); }
++
++#define luaC_objbarrier(L,p,o)  \
++	{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
++		luaC_barrierf(L,obj2gco(p),obj2gco(o)); }
++
++#define luaC_objbarriert(L,t,o)  \
++   { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
++
++LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all);
++LUAI_FUNC void luaC_callGCTM (lua_State *L);
++LUAI_FUNC void luaC_freeall (lua_State *L);
++LUAI_FUNC void luaC_step (lua_State *L);
++LUAI_FUNC void luaC_fullgc (lua_State *L);
++LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
++LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
++LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
++LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/llex.c
+@@ -0,0 +1,460 @@
++/*
++** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lexical Analyzer
++** See Copyright Notice in lua.h
++*/
++
++#include <ctype.h>
++#include <locale.h>
++#include <string.h>
++
++#define llex_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldo.h"
++#include "llex.h"
++#include "lobject.h"
++#include "lparser.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "lzio.h"
++
++
++
++#define next(ls) (ls->current = zgetc(ls->z))
++
++
++
++
++#define currIsNewline(ls)	(ls->current == '\n' || ls->current == '\r')
++
++
++/* ORDER RESERVED */
++const char *const luaX_tokens [] = {
++    "and", "break", "do", "else", "elseif",
++    "end", "false", "for", "function", "if",
++    "in", "local", "nil", "not", "or", "repeat",
++    "return", "then", "true", "until", "while",
++    "..", "...", "==", ">=", "<=", "~=",
++    "<number>", "<name>", "<string>", "<eof>",
++    NULL
++};
++
++
++#define save_and_next(ls) (save(ls, ls->current), next(ls))
++
++
++static void save (LexState *ls, int c) {
++  Mbuffer *b = ls->buff;
++  if (b->n + 1 > b->buffsize) {
++    size_t newsize;
++    if (b->buffsize >= MAX_SIZET/2)
++      luaX_lexerror(ls, "lexical element too long", 0);
++    newsize = b->buffsize * 2;
++    luaZ_resizebuffer(ls->L, b, newsize);
++  }
++  b->buffer[b->n++] = cast(char, c);
++}
++
++
++void luaX_init (lua_State *L) {
++  int i;
++  for (i=0; i<NUM_RESERVED; i++) {
++    TString *ts = luaS_new(L, luaX_tokens[i]);
++    luaS_fix(ts);  /* reserved words are never collected */
++    lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
++    ts->tsv.reserved = cast_byte(i+1);  /* reserved word */
++  }
++}
++
++
++#define MAXSRC          80
++
++
++const char *luaX_token2str (LexState *ls, int token) {
++  if (token < FIRST_RESERVED) {
++    lua_assert(token == cast(unsigned char, token));
++    return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) :
++                              luaO_pushfstring(ls->L, "%c", token);
++  }
++  else
++    return luaX_tokens[token-FIRST_RESERVED];
++}
++
++
++static const char *txtToken (LexState *ls, int token) {
++  switch (token) {
++    case TK_NAME:
++    case TK_STRING:
++    case TK_NUMBER:
++      save(ls, '\0');
++      return luaZ_buffer(ls->buff);
++    default:
++      return luaX_token2str(ls, token);
++  }
++}
++
++
++void luaX_lexerror (LexState *ls, const char *msg, int token) {
++  char buff[MAXSRC];
++  luaO_chunkid(buff, getstr(ls->source), MAXSRC);
++  msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
++  if (token)
++    luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token));
++  luaD_throw(ls->L, LUA_ERRSYNTAX);
++}
++
++
++void luaX_syntaxerror (LexState *ls, const char *msg) {
++  luaX_lexerror(ls, msg, ls->t.token);
++}
++
++
++TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
++  lua_State *L = ls->L;
++  TString *ts = luaS_newlstr(L, str, l);
++  TValue *o = luaH_setstr(L, ls->fs->h, ts);  /* entry for `str' */
++  if (ttisnil(o))
++    setbvalue(o, 1);  /* make sure `str' will not be collected */
++  return ts;
++}
++
++
++static void inclinenumber (LexState *ls) {
++  int old = ls->current;
++  lua_assert(currIsNewline(ls));
++  next(ls);  /* skip `\n' or `\r' */
++  if (currIsNewline(ls) && ls->current != old)
++    next(ls);  /* skip `\n\r' or `\r\n' */
++  if (++ls->linenumber >= MAX_INT)
++    luaX_syntaxerror(ls, "chunk has too many lines");
++}
++
++
++void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
++  ls->decpoint = '.';
++  ls->L = L;
++  ls->lookahead.token = TK_EOS;  /* no look-ahead token */
++  ls->z = z;
++  ls->fs = NULL;
++  ls->linenumber = 1;
++  ls->lastline = 1;
++  ls->source = source;
++  luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */
++  next(ls);  /* read first char */
++}
++
++
++
++/*
++** =======================================================
++** LEXICAL ANALYZER
++** =======================================================
++*/
++
++
++
++static int check_next (LexState *ls, const char *set) {
++  if (!strchr(set, ls->current))
++    return 0;
++  save_and_next(ls);
++  return 1;
++}
++
++
++static void buffreplace (LexState *ls, char from, char to) {
++  size_t n = luaZ_bufflen(ls->buff);
++  char *p = luaZ_buffer(ls->buff);
++  while (n--)
++    if (p[n] == from) p[n] = to;
++}
++
++
++static void trydecpoint (LexState *ls, SemInfo *seminfo) {
++  /* format error: try to update decimal point separator */
++  char old = ls->decpoint;
++  struct lconv *cv = localeconv();
++  ls->decpoint = (cv ? cv->decimal_point[0] : '.');
++  buffreplace(ls, old, ls->decpoint);  /* try updated decimal separator */
++  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
++    /* format error with correct decimal point: no more options */
++    buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */
++    luaX_lexerror(ls, "malformed number", TK_NUMBER);
++  }
++}
++
++
++/* LUA_NUMBER */
++static void read_numeral (LexState *ls, SemInfo *seminfo) {
++  lua_assert(isdigit(ls->current));
++  do {
++    save_and_next(ls);
++  } while (isdigit(ls->current) || ls->current == '.');
++  if (check_next(ls, "Ee"))  /* `E'? */
++    check_next(ls, "+-");  /* optional exponent sign */
++  while (isalnum(ls->current) || ls->current == '_')
++    save_and_next(ls);
++  save(ls, '\0');
++  buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */
++  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r))  /* format error? */
++    trydecpoint(ls, seminfo); /* try to update decimal point separator */
++}
++
++
++static int skip_sep (LexState *ls) {
++  int count = 0;
++  int s = ls->current;
++  lua_assert(s == '[' || s == ']');
++  save_and_next(ls);
++  while (ls->current == '=') {
++    save_and_next(ls);
++    count++;
++  }
++  return (ls->current == s) ? count : (-count) - 1;
++}
++
++
++static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
++  int cont = 0;
++  (void)(cont);  /* avoid warnings when `cont' is not used */
++  save_and_next(ls);  /* skip 2nd `[' */
++  if (currIsNewline(ls))  /* string starts with a newline? */
++    inclinenumber(ls);  /* skip it */
++  for (;;) {
++    switch (ls->current) {
++      case EOZ:
++        luaX_lexerror(ls, (seminfo) ? "unfinished long string" :
++                                   "unfinished long comment", TK_EOS);
++        break;  /* to avoid warnings */
++#if defined(LUA_COMPAT_LSTR)
++      case '[': {
++        if (skip_sep(ls) == sep) {
++          save_and_next(ls);  /* skip 2nd `[' */
++          cont++;
++#if LUA_COMPAT_LSTR == 1
++          if (sep == 0)
++            luaX_lexerror(ls, "nesting of [[...]] is deprecated", '[');
++#endif
++        }
++        break;
++      }
++#endif
++      case ']': {
++        if (skip_sep(ls) == sep) {
++          save_and_next(ls);  /* skip 2nd `]' */
++#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2
++          cont--;
++          if (sep == 0 && cont >= 0) break;
++#endif
++          goto endloop;
++        }
++        break;
++      }
++      case '\n':
++      case '\r': {
++        save(ls, '\n');
++        inclinenumber(ls);
++        if (!seminfo) luaZ_resetbuffer(ls->buff);  /* avoid wasting space */
++        break;
++      }
++      default: {
++        if (seminfo) save_and_next(ls);
++        else next(ls);
++      }
++    }
++  } endloop:
++  if (seminfo)
++    seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
++                                     luaZ_bufflen(ls->buff) - 2*(2 + sep));
++}
++
++
++static void read_string (LexState *ls, int del, SemInfo *seminfo) {
++  save_and_next(ls);
++  while (ls->current != del) {
++    switch (ls->current) {
++      case EOZ:
++        luaX_lexerror(ls, "unfinished string", TK_EOS);
++        continue;  /* to avoid warnings */
++      case '\n':
++      case '\r':
++        luaX_lexerror(ls, "unfinished string", TK_STRING);
++        continue;  /* to avoid warnings */
++      case '\\': {
++        int c;
++        next(ls);  /* do not save the `\' */
++        switch (ls->current) {
++          case 'a': c = '\a'; break;
++          case 'b': c = '\b'; break;
++          case 'f': c = '\f'; break;
++          case 'n': c = '\n'; break;
++          case 'r': c = '\r'; break;
++          case 't': c = '\t'; break;
++          case 'v': c = '\v'; break;
++          case '\n':  /* go through */
++          case '\r': save(ls, '\n'); inclinenumber(ls); continue;
++          case EOZ: continue;  /* will raise an error next loop */
++          default: {
++            if (!isdigit(ls->current))
++              save_and_next(ls);  /* handles \\, \", \', and \? */
++            else {  /* \xxx */
++              int i = 0;
++              c = 0;
++              do {
++                c = 10*c + (ls->current-'0');
++                next(ls);
++              } while (++i<3 && isdigit(ls->current));
++              if (c > UCHAR_MAX)
++                luaX_lexerror(ls, "escape sequence too large", TK_STRING);
++              save(ls, c);
++            }
++            continue;
++          }
++        }
++        save(ls, c);
++        next(ls);
++        continue;
++      }
++      default:
++        save_and_next(ls);
++    }
++  }
++  save_and_next(ls);  /* skip delimiter */
++  seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
++                                   luaZ_bufflen(ls->buff) - 2);
++}
++
++
++static int llex (LexState *ls, SemInfo *seminfo) {
++  luaZ_resetbuffer(ls->buff);
++  for (;;) {
++    switch (ls->current) {
++      case '\n':
++      case '\r': {
++        inclinenumber(ls);
++        continue;
++      }
++      case '-': {
++        next(ls);
++        if (ls->current != '-') return '-';
++        /* else is a comment */
++        next(ls);
++        if (ls->current == '[') {
++          int sep = skip_sep(ls);
++          luaZ_resetbuffer(ls->buff);  /* `skip_sep' may dirty the buffer */
++          if (sep >= 0) {
++            read_long_string(ls, NULL, sep);  /* long comment */
++            luaZ_resetbuffer(ls->buff);
++            continue;
++          }
++        }
++        /* else short comment */
++        while (!currIsNewline(ls) && ls->current != EOZ)
++          next(ls);
++        continue;
++      }
++      case '[': {
++        int sep = skip_sep(ls);
++        if (sep >= 0) {
++          read_long_string(ls, seminfo, sep);
++          return TK_STRING;
++        }
++        else if (sep == -1) return '[';
++        else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
++      }
++      case '=': {
++        next(ls);
++        if (ls->current != '=') return '=';
++        else { next(ls); return TK_EQ; }
++      }
++      case '<': {
++        next(ls);
++        if (ls->current != '=') return '<';
++        else { next(ls); return TK_LE; }
++      }
++      case '>': {
++        next(ls);
++        if (ls->current != '=') return '>';
++        else { next(ls); return TK_GE; }
++      }
++      case '~': {
++        next(ls);
++        if (ls->current != '=') return '~';
++        else { next(ls); return TK_NE; }
++      }
++      case '"':
++      case '\'': {
++        read_string(ls, ls->current, seminfo);
++        return TK_STRING;
++      }
++      case '.': {
++        save_and_next(ls);
++        if (check_next(ls, ".")) {
++          if (check_next(ls, "."))
++            return TK_DOTS;   /* ... */
++          else return TK_CONCAT;   /* .. */
++        }
++        else if (!isdigit(ls->current)) return '.';
++        else {
++          read_numeral(ls, seminfo);
++          return TK_NUMBER;
++        }
++      }
++      case EOZ: {
++        return TK_EOS;
++      }
++      default: {
++        if (isspace(ls->current)) {
++          lua_assert(!currIsNewline(ls));
++          next(ls);
++          continue;
++        }
++        else if (isdigit(ls->current)) {
++          read_numeral(ls, seminfo);
++          return TK_NUMBER;
++        }
++        else if (isalpha(ls->current) || ls->current == '_') {
++          /* identifier or reserved word */
++          TString *ts;
++          do {
++            save_and_next(ls);
++          } while (isalnum(ls->current) || ls->current == '_');
++          ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
++                                  luaZ_bufflen(ls->buff));
++          if (ts->tsv.reserved > 0)  /* reserved word? */
++            return ts->tsv.reserved - 1 + FIRST_RESERVED;
++          else {
++            seminfo->ts = ts;
++            return TK_NAME;
++          }
++        }
++        else {
++          int c = ls->current;
++          next(ls);
++          return c;  /* single-char tokens (+ - / ...) */
++        }
++      }
++    }
++  }
++}
++
++
++void luaX_next (LexState *ls) {
++  ls->lastline = ls->linenumber;
++  if (ls->lookahead.token != TK_EOS) {  /* is there a look-ahead token? */
++    ls->t = ls->lookahead;  /* use this one */
++    ls->lookahead.token = TK_EOS;  /* and discharge it */
++  }
++  else
++    ls->t.token = llex(ls, &ls->t.seminfo);  /* read next token */
++}
++
++
++void luaX_lookahead (LexState *ls) {
++  lua_assert(ls->lookahead.token == TK_EOS);
++  ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/llex.h
+@@ -0,0 +1,81 @@
++/*
++** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lexical Analyzer
++** See Copyright Notice in lua.h
++*/
++
++#ifndef llex_h
++#define llex_h
++
++#include "lobject.h"
++#include "lzio.h"
++
++
++#define FIRST_RESERVED	257
++
++/* maximum length of a reserved word */
++#define TOKEN_LEN	(sizeof("function")/sizeof(char))
++
++
++/*
++* WARNING: if you change the order of this enumeration,
++* grep "ORDER RESERVED"
++*/
++enum RESERVED {
++  /* terminal symbols denoted by reserved words */
++  TK_AND = FIRST_RESERVED, TK_BREAK,
++  TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
++  TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
++  TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
++  /* other terminal symbols */
++  TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
++  TK_NAME, TK_STRING, TK_EOS
++};
++
++/* number of reserved words */
++#define NUM_RESERVED	(cast(int, TK_WHILE-FIRST_RESERVED+1))
++
++
++/* array with token `names' */
++LUAI_DATA const char *const luaX_tokens [];
++
++
++typedef union {
++  lua_Number r;
++  TString *ts;
++} SemInfo;  /* semantics information */
++
++
++typedef struct Token {
++  int token;
++  SemInfo seminfo;
++} Token;
++
++
++typedef struct LexState {
++  int current;  /* current character (charint) */
++  int linenumber;  /* input line counter */
++  int lastline;  /* line of last token `consumed' */
++  Token t;  /* current token */
++  Token lookahead;  /* look ahead token */
++  struct FuncState *fs;  /* `FuncState' is private to the parser */
++  struct lua_State *L;
++  ZIO *z;  /* input stream */
++  Mbuffer *buff;  /* buffer for tokens */
++  TString *source;  /* current source name */
++  char decpoint;  /* locale decimal point */
++} LexState;
++
++
++LUAI_FUNC void luaX_init (lua_State *L);
++LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
++                              TString *source);
++LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
++LUAI_FUNC void luaX_next (LexState *ls);
++LUAI_FUNC void luaX_lookahead (LexState *ls);
++LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token);
++LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s);
++LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/llimits.h
+@@ -0,0 +1,125 @@
++/*
++** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $
++** Limits, basic types, and some other `installation-dependent' definitions
++** See Copyright Notice in lua.h
++*/
++
++#ifndef llimits_h
++#define llimits_h
++
++#include <stddef.h>
++#include <limits.h>
++
++#include "lua.h"
++
++typedef LUAI_UINT32 lu_int32;
++
++typedef LUAI_UMEM lu_mem;
++
++typedef LUAI_MEM l_mem;
++
++
++
++/* chars used as small naturals (so that `char' is reserved for characters) */
++typedef unsigned char lu_byte;
++
++
++#define MAX_SIZET	((size_t)(~(size_t)0)-2)
++
++#define MAX_LUMEM	((lu_mem)(~(lu_mem)0)-2)
++
++
++#define MAX_INT (LUA_INT_MAX-2)  /* maximum value of an int (-2 for safety) */
++
++/*
++** conversion of pointer to integer
++** this is for hashing only; there is no problem if the integer
++** cannot hold the whole pointer value
++*/
++#define IntPoint(p)  ((unsigned int)(lu_mem)(p))
++
++
++
++/* type to ensure maximum alignment */
++typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
++
++
++/* result of a `usual argument conversion' over lua_Number */
++typedef LUAI_UACNUMBER l_uacNumber;
++
++
++/* internal assertions for in-house debugging */
++#ifdef lua_assert
++
++#define check_exp(c,e)		(lua_assert(c), (e))
++#define api_check(l,e)		lua_assert(e)
++
++#else
++
++#define lua_assert(c)		((void)0)
++#define check_exp(c,e)		(e)
++#define api_check		luai_apicheck
++
++#endif
++
++
++#ifndef UNUSED
++#define UNUSED(x)	((void)(x))	/* to avoid warnings */
++#endif
++
++
++#ifndef cast
++#define cast(t, exp)	((t)(exp))
++#endif
++
++#define cast_byte(i)	cast(lu_byte, (i))
++#define cast_num(i)	cast(lua_Number, (i))
++#define cast_int(i)	cast(int, (i))
++
++
++
++/*
++** type for virtual-machine instructions
++** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
++*/
++typedef lu_int32 Instruction;
++
++
++
++/* maximum stack for a Lua function */
++#define MAXSTACK	250
++
++
++
++/* minimum size for the string table (must be power of 2) */
++#ifndef MINSTRTABSIZE
++#define MINSTRTABSIZE	32
++#endif
++
++
++/* minimum size for string buffer */
++#ifndef LUA_MINBUFFER
++#define LUA_MINBUFFER	32
++#endif
++
++
++#ifndef lua_lock
++#define lua_lock(L)     ((void) 0) 
++#define lua_unlock(L)   ((void) 0)
++#endif
++
++#ifndef luai_threadyield
++#define luai_threadyield(L)     {lua_unlock(L); lua_lock(L);}
++#endif
++
++
++/*
++** macro to control inclusion of some hard tests on stack reallocation
++*/ 
++#ifndef HARDSTACKTESTS
++#define condhardstacktests(x)	((void)0)
++#else
++#define condhardstacktests(x)	x
++#endif
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lmem.c
+@@ -0,0 +1,86 @@
++/*
++** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $
++** Interface to Memory Manager
++** See Copyright Notice in lua.h
++*/
++
++
++#include <stddef.h>
++
++#define lmem_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++
++
++
++/*
++** About the realloc function:
++** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
++** (`osize' is the old size, `nsize' is the new size)
++**
++** Lua ensures that (ptr == NULL) iff (osize == 0).
++**
++** * frealloc(ud, NULL, 0, x) creates a new block of size `x'
++**
++** * frealloc(ud, p, x, 0) frees the block `p'
++** (in this specific case, frealloc must return NULL).
++** particularly, frealloc(ud, NULL, 0, 0) does nothing
++** (which is equivalent to free(NULL) in ANSI C)
++**
++** frealloc returns NULL if it cannot create or reallocate the area
++** (any reallocation to an equal or smaller size cannot fail!)
++*/
++
++
++
++#define MINSIZEARRAY	4
++
++
++void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
++                     int limit, const char *errormsg) {
++  void *newblock;
++  int newsize;
++  if (*size >= limit/2) {  /* cannot double it? */
++    if (*size >= limit)  /* cannot grow even a little? */
++      luaG_runerror(L, errormsg);
++    newsize = limit;  /* still have at least one free place */
++  }
++  else {
++    newsize = (*size)*2;
++    if (newsize < MINSIZEARRAY)
++      newsize = MINSIZEARRAY;  /* minimum size */
++  }
++  newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
++  *size = newsize;  /* update only when everything else is OK */
++  return newblock;
++}
++
++
++void *luaM_toobig (lua_State *L) {
++  luaG_runerror(L, "memory allocation error: block too big");
++  return NULL;  /* to avoid warnings */
++}
++
++
++
++/*
++** generic allocation routine.
++*/
++void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
++  global_State *g = G(L);
++  lua_assert((osize == 0) == (block == NULL));
++  block = (*g->frealloc)(g->ud, block, osize, nsize);
++  if (block == NULL && nsize > 0)
++    luaD_throw(L, LUA_ERRMEM);
++  lua_assert((nsize == 0) == (block == NULL));
++  g->totalbytes = (g->totalbytes - osize) + nsize;
++  return block;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lmem.h
+@@ -0,0 +1,49 @@
++/*
++** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
++** Interface to Memory Manager
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lmem_h
++#define lmem_h
++
++
++#include <stddef.h>
++
++#include "llimits.h"
++#include "lua.h"
++
++#define MEMERRMSG	"not enough memory"
++
++
++#define luaM_reallocv(L,b,on,n,e) \
++	((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ?  /* +1 to avoid warnings */ \
++		luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \
++		luaM_toobig(L))
++
++#define luaM_freemem(L, b, s)	luaM_realloc_(L, (b), (s), 0)
++#define luaM_free(L, b)		luaM_realloc_(L, (b), sizeof(*(b)), 0)
++#define luaM_freearray(L, b, n, t)   luaM_reallocv(L, (b), n, 0, sizeof(t))
++
++#define luaM_malloc(L,t)	luaM_realloc_(L, NULL, 0, (t))
++#define luaM_new(L,t)		cast(t *, luaM_malloc(L, sizeof(t)))
++#define luaM_newvector(L,n,t) \
++		cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
++
++#define luaM_growvector(L,v,nelems,size,t,limit,e) \
++          if ((nelems)+1 > (size)) \
++            ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
++
++#define luaM_reallocvector(L, v,oldn,n,t) \
++   ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
++
++
++LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
++                                                          size_t size);
++LUAI_FUNC void *luaM_toobig (lua_State *L);
++LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
++                               size_t size_elem, int limit,
++                               const char *errormsg);
++
++#endif
++
+--- /dev/null
++++ b/extensions/LUA/lua/lobject.c
+@@ -0,0 +1,215 @@
++/*
++** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $
++** Some generic functions over Lua objects
++** See Copyright Notice in lua.h
++*/
++
++#include <stdarg.h>
++
++#include <ctype.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#define lobject_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldo.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "lvm.h"
++
++
++
++const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL};
++
++
++/*
++** converts an integer to a "floating point byte", represented as
++** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
++** eeeee != 0 and (xxx) otherwise.
++*/
++int luaO_int2fb (unsigned int x) {
++  int e = 0;  /* expoent */
++  while (x >= 16) {
++    x = (x+1) >> 1;
++    e++;
++  }
++  if (x < 8) return x;
++  else return ((e+1) << 3) | (cast_int(x) - 8);
++}
++
++
++/* converts back */
++int luaO_fb2int (int x) {
++  int e = (x >> 3) & 31;
++  if (e == 0) return x;
++  else return ((x & 7)+8) << (e - 1);
++}
++
++
++int luaO_log2 (unsigned int x) {
++  static const lu_byte log_2[256] = {
++    0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
++    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
++    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
++    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
++  };
++  int l = -1;
++  while (x >= 256) { l += 8; x >>= 8; }
++  return l + log_2[x];
++
++}
++
++
++int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
++  if (ttype(t1) != ttype(t2)) return 0;
++  else switch (ttype(t1)) {
++    case LUA_TNIL:
++      return 1;
++    case LUA_TNUMBER:
++      return luai_numeq(nvalue(t1), nvalue(t2));
++    case LUA_TBOOLEAN:
++      return bvalue(t1) == bvalue(t2);  /* boolean true must be 1 !! */
++    case LUA_TLIGHTUSERDATA:
++      return pvalue(t1) == pvalue(t2);
++    default:
++      lua_assert(iscollectable(t1));
++      return gcvalue(t1) == gcvalue(t2);
++  }
++}
++
++
++int luaO_str2d (const char *s, lua_Number *result) {
++  char *endptr;
++  *result = lua_str2number(s, &endptr);
++  if (endptr == s) return 0;  /* conversion failed */
++  if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */
++    *result = cast_num(strtoul(s, &endptr, 16));
++  if (*endptr == '\0') return 1;  /* most common case */
++  while (isspace(cast(unsigned char, *endptr))) endptr++;
++  if (*endptr != '\0') return 0;  /* invalid trailing characters? */
++  return 1;
++}
++
++
++
++static void pushstr (lua_State *L, const char *str) {
++  setsvalue2s(L, L->top, luaS_new(L, str));
++  incr_top(L);
++}
++
++
++/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
++const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
++  int n = 1;
++  pushstr(L, "");
++  for (;;) {
++    const char *e = strchr(fmt, '%');
++    if (e == NULL) break;
++    setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt));
++    incr_top(L);
++    switch (*(e+1)) {
++      case 's': {
++        const char *s = va_arg(argp, char *);
++        if (s == NULL) s = "(null)";
++        pushstr(L, s);
++        break;
++      }
++      case 'c': {
++        char buff[2];
++        buff[0] = cast(char, va_arg(argp, int));
++        buff[1] = '\0';
++        pushstr(L, buff);
++        break;
++      }
++      case 'd': {
++        setnvalue(L->top, cast_num(va_arg(argp, int)));
++        incr_top(L);
++        break;
++      }
++      case 'f': {
++        setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
++        incr_top(L);
++        break;
++      }
++      case 'p': {
++        char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
++        sprintf(buff, "%p", va_arg(argp, void *));
++        pushstr(L, buff);
++        break;
++      }
++      case '%': {
++        pushstr(L, "%");
++        break;
++      }
++      default: {
++        char buff[3];
++        buff[0] = '%';
++        buff[1] = *(e+1);
++        buff[2] = '\0';
++        pushstr(L, buff);
++        break;
++      }
++    }
++    n += 2;
++    fmt = e+2;
++  }
++  pushstr(L, fmt);
++  luaV_concat(L, n+1, cast_int(L->top - L->base) - 1);
++  L->top -= n;
++  return svalue(L->top - 1);
++}
++
++
++const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
++  const char *msg;
++  va_list argp;
++  va_start(argp, fmt);
++  msg = luaO_pushvfstring(L, fmt, argp);
++  va_end(argp);
++  return msg;
++}
++
++
++void luaO_chunkid (char *out, const char *source, size_t bufflen) {
++  if (*source == '=') {
++    strncpy(out, source+1, bufflen);  /* remove first char */
++    out[bufflen-1] = '\0';  /* ensures null termination */
++  }
++  else {  /* out = "source", or "...source" */
++    if (*source == '@') {
++      size_t l;
++      source++;  /* skip the `@' */
++      bufflen -= sizeof(" '...' ");
++      l = strlen(source);
++      strcpy(out, "");
++      if (l > bufflen) {
++        source += (l-bufflen);  /* get last part of file name */
++        strcat(out, "...");
++      }
++      strcat(out, source);
++    }
++    else {  /* out = [string "string"] */
++      size_t len = strcspn(source, "\n\r");  /* stop at first newline */
++      bufflen -= sizeof(" [string \"...\"] ");
++      if (len > bufflen) len = bufflen;
++      strcpy(out, "[string \"");
++      if (source[len] != '\0') {  /* must truncate? */
++        strncat(out, source, len);
++        strcat(out, "...");
++      }
++      else
++        strcat(out, source);
++      strcat(out, "\"]");
++    }
++  }
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lobject.h
+@@ -0,0 +1,381 @@
++/*
++** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $
++** Type definitions for Lua objects
++** See Copyright Notice in lua.h
++*/
++
++
++#ifndef lobject_h
++#define lobject_h
++
++
++#include <stdarg.h>
++
++
++#include "llimits.h"
++#include "lua.h"
++
++
++/* tags for values visible from Lua */
++#define LAST_TAG	LUA_TTHREAD
++
++#define NUM_TAGS	(LAST_TAG+1)
++
++
++/*
++** Extra tags for non-values
++*/
++#define LUA_TPROTO	(LAST_TAG+1)
++#define LUA_TUPVAL	(LAST_TAG+2)
++#define LUA_TDEADKEY	(LAST_TAG+3)
++
++
++/*
++** Union of all collectable objects
++*/
++typedef union GCObject GCObject;
++
++
++/*
++** Common Header for all collectable objects (in macro form, to be
++** included in other objects)
++*/
++#define CommonHeader	GCObject *next; lu_byte tt; lu_byte marked
++
++
++/*
++** Common header in struct form
++*/
++typedef struct GCheader {
++  CommonHeader;
++} GCheader;
++
++
++
++
++/*
++** Union of all Lua values
++*/
++typedef union {
++  GCObject *gc;
++  void *p;
++  lua_Number n;
++  int b;
++} Value;
++
++
++/*
++** Tagged Values
++*/
++
++#define TValuefields	Value value; int tt
++
++typedef struct lua_TValue {
++  TValuefields;
++} TValue;
++
++
++/* Macros to test type */
++#define ttisnil(o)	(ttype(o) == LUA_TNIL)
++#define ttisnumber(o)	(ttype(o) == LUA_TNUMBER)
++#define ttisstring(o)	(ttype(o) == LUA_TSTRING)
++#define ttistable(o)	(ttype(o) == LUA_TTABLE)
++#define ttisfunction(o)	(ttype(o) == LUA_TFUNCTION)
++#define ttisboolean(o)	(ttype(o) == LUA_TBOOLEAN)
++#define ttisuserdata(o)	(ttype(o) == LUA_TUSERDATA)
++#define ttisthread(o)	(ttype(o) == LUA_TTHREAD)
++#define ttislightuserdata(o)	(ttype(o) == LUA_TLIGHTUSERDATA)
++
++/* Macros to access values */
++#define ttype(o)	((o)->tt)
++#define gcvalue(o)	check_exp(iscollectable(o), (o)->value.gc)
++#define pvalue(o)	check_exp(ttislightuserdata(o), (o)->value.p)
++#define nvalue(o)	check_exp(ttisnumber(o), (o)->value.n)
++#define rawtsvalue(o)	check_exp(ttisstring(o), &(o)->value.gc->ts)
++#define tsvalue(o)	(&rawtsvalue(o)->tsv)
++#define rawuvalue(o)	check_exp(ttisuserdata(o), &(o)->value.gc->u)
++#define uvalue(o)	(&rawuvalue(o)->uv)
++#define clvalue(o)	check_exp(ttisfunction(o), &(o)->value.gc->cl)
++#define hvalue(o)	check_exp(ttistable(o), &(o)->value.gc->h)
++#define bvalue(o)	check_exp(ttisboolean(o), (o)->value.b)
++#define thvalue(o)	check_exp(ttisthread(o), &(o)->value.gc->th)
++
++#define l_isfalse(o)	(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
++
++/*
++** for internal debug only
++*/
++#define checkconsistency(obj) \
++  lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt))
++
++#define checkliveness(g,obj) \
++  lua_assert(!iscollectable(obj) || \
++  ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))
++
++
++/* Macros to set values */
++#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
++
++#define setnvalue(obj,x) \
++  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
++
++#define setpvalue(obj,x) \
++  { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
++
++#define setbvalue(obj,x) \
++  { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
++
++#define setsvalue(L,obj,x) \
++  { TValue *i_o=(obj); \
++    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
++    checkliveness(G(L),i_o); }
++
++#define setuvalue(L,obj,x) \
++  { TValue *i_o=(obj); \
++    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
++    checkliveness(G(L),i_o); }
++
++#define setthvalue(L,obj,x) \
++  { TValue *i_o=(obj); \
++    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
++    checkliveness(G(L),i_o); }
++
++#define setclvalue(L,obj,x) \
++  { TValue *i_o=(obj); \
++    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
++    checkliveness(G(L),i_o); }
++
++#define sethvalue(L,obj,x) \
++  { TValue *i_o=(obj); \
++    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
++    checkliveness(G(L),i_o); }
++
++#define setptvalue(L,obj,x) \
++  { TValue *i_o=(obj); \
++    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
++    checkliveness(G(L),i_o); }
++
++
++
++
++#define setobj(L,obj1,obj2) \
++  { const TValue *o2=(obj2); TValue *o1=(obj1); \
++    o1->value = o2->value; o1->tt=o2->tt; \
++    checkliveness(G(L),o1); }
++
++
++/*
++** different types of sets, according to destination
++*/
++
++/* from stack to (same) stack */
++#define setobjs2s	setobj
++/* to stack (not from same stack) */
++#define setobj2s	setobj
++#define setsvalue2s	setsvalue
++#define sethvalue2s	sethvalue
++#define setptvalue2s	setptvalue
++/* from table to same table */
++#define setobjt2t	setobj
++/* to table */
++#define setobj2t	setobj
++/* to new object */
++#define setobj2n	setobj
++#define setsvalue2n	setsvalue
++
++#define setttype(obj, tt) (ttype(obj) = (tt))
++
++
++#define iscollectable(o)	(ttype(o) >= LUA_TSTRING)
++
++
++
++typedef TValue *StkId;  /* index to stack elements */
++
++
++/*
++** String headers for string table
++*/
++typedef union TString {
++  L_Umaxalign dummy;  /* ensures maximum alignment for strings */
++  struct {
++    CommonHeader;
++    lu_byte reserved;
++    unsigned int hash;
++    size_t len;
++  } tsv;
++} TString;
++
++
++#define getstr(ts)	cast(const char *, (ts) + 1)
++#define svalue(o)       getstr(rawtsvalue(o))
++
++
++
++typedef union Udata {
++  L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */
++  struct {
++    CommonHeader;
++    struct Table *metatable;
++    struct Table *env;
++    size_t len;
++  } uv;
++} Udata;
++
++
++
++
++/*
++** Function Prototypes
++*/
++typedef struct Proto {
++  CommonHeader;
++  TValue *k;  /* constants used by the function */
++  Instruction *code;
++  struct Proto **p;  /* functions defined inside the function */
++  int *lineinfo;  /* map from opcodes to source lines */
++  struct LocVar *locvars;  /* information about local variables */
++  TString **upvalues;  /* upvalue names */
++  TString  *source;
++  int sizeupvalues;
++  int sizek;  /* size of `k' */
++  int sizecode;
++  int sizelineinfo;
++  int sizep;  /* size of `p' */
++  int sizelocvars;
++  int linedefined;
++  int lastlinedefined;
++  GCObject *gclist;
++  lu_byte nups;  /* number of upvalues */
++  lu_byte numparams;
++  lu_byte is_vararg;
++  lu_byte maxstacksize;
++} Proto;
++
++
++/* masks for new-style vararg */
++#define VARARG_HASARG		1
++#define VARARG_ISVARARG		2
++#define VARARG_NEEDSARG		4
++
++
++typedef struct LocVar {
++  TString *varname;
++  int startpc;  /* first point where variable is active */
++  int endpc;    /* first point where variable is dead */
++} LocVar;
++
++
++
++/*
++** Upvalues
++*/
++
++typedef struct UpVal {
++  CommonHeader;
++  TValue *v;  /* points to stack or to its own value */
++  union {
++    TValue value;  /* the value (when closed) */
++    struct {  /* double linked list (when open) */
++      struct UpVal *prev;
++      struct UpVal *next;
++    } l;
++  } u;
++} UpVal;
++
++
++/*
++** Closures
++*/
++
++#define ClosureHeader \
++	CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
++	struct Table *env
++
++typedef struct CClosure {
++  ClosureHeader;
++  lua_CFunction f;
++  TValue upvalue[1];
++} CClosure;
++
++
++typedef struct LClosure {
++  ClosureHeader;
++  struct Proto *p;
++  UpVal *upvals[1];
++} LClosure;
++
++
++typedef union Closure {
++  CClosure c;
++  LClosure l;
++} Closure;
++
++
++#define iscfunction(o)	(ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC)
++#define isLfunction(o)	(ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC)
++
++
++/*
++** Tables
++*/
++
++typedef union TKey {
++  struct {
++    TValuefields;
++    struct Node *next;  /* for chaining */
++  } nk;
++  TValue tvk;
++} TKey;
++
++
++typedef struct Node {
++  TValue i_val;
++  TKey i_key;
++} Node;
++
++
++typedef struct Table {
++  CommonHeader;
++  lu_byte flags;  /* 1<<p means tagmethod(p) is not present */ 
++  lu_byte lsizenode;  /* log2 of size of `node' array */
++  struct Table *metatable;
++  TValue *array;  /* array part */
++  Node *node;
++  Node *lastfree;  /* any free position is before this position */
++  GCObject *gclist;
++  int sizearray;  /* size of `array' array */
++} Table;
++
++
++
++/*
++** `module' operation for hashing (size is always a power of 2)
++*/
++#define lmod(s,size) \
++	(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))
++
++
++#define twoto(x)	(1<<(x))
++#define sizenode(t)	(twoto((t)->lsizenode))
++
++
++#define luaO_nilobject		(&luaO_nilobject_)
++
++LUAI_DATA const TValue luaO_nilobject_;
++
++#define ceillog2(x)	(luaO_log2((x)-1) + 1)
++
++LUAI_FUNC int luaO_log2 (unsigned int x);
++LUAI_FUNC int luaO_int2fb (unsigned int x);
++LUAI_FUNC int luaO_fb2int (int x);
++LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
++LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
++LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
++                                                       va_list argp);
++LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
++LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
++
++
++#endif
++
+--- /dev/null
++++ b/extensions/LUA/lua/lopcodes.c
+@@ -0,0 +1,102 @@
++/*
++** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
++** See Copyright Notice in lua.h
++*/
++
++
++#define lopcodes_c
++#define LUA_CORE
++
++
++#include "lopcodes.h"
++
++
++/* ORDER OP */
++
++const char *const luaP_opnames[NUM_OPCODES+1] = {
++  "MOVE",
++  "LOADK",
++  "LOADBOOL",
++  "LOADNIL",
++  "GETUPVAL",
++  "GETGLOBAL",
++  "GETTABLE",
++  "SETGLOBAL",
++  "SETUPVAL",
++  "SETTABLE",
++  "NEWTABLE",
++  "SELF",
++  "ADD",
++  "SUB",
++  "MUL",
++  "DIV",
++  "MOD",
++  "POW",
++  "UNM",
++  "NOT",
++  "LEN",
++  "CONCAT",
++  "JMP",
++  "EQ",
++  "LT",
++  "LE",
++  "TEST",
++  "TESTSET",
++  "CALL",
++  "TAILCALL",
++  "RETURN",
++  "FORLOOP",
++  "FORPREP",
++  "TFORLOOP",
++  "SETLIST",
++  "CLOSE",
++  "CLOSURE",
++  "VARARG",
++  NULL
++};
++
++
++#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
++
++const lu_byte luaP_opmodes[NUM_OPCODES] = {
++/*       T  A    B       C     mode		   opcode	*/
++  opmode(0, 1, OpArgR, OpArgN, iABC) 		/* OP_MOVE */
++ ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */
++ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
++ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LOADNIL */
++ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
++ ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_GETGLOBAL */
++ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
++ ,opmode(0, 0, OpArgK, OpArgN, iABx)		/* OP_SETGLOBAL */
++ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
++ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
++ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
++ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
++ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */
++ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */
++ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */
++ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */
++ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */
++ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */
++ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */
++ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */
++ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */
++ ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */
++ ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */
++ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
++ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
++ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
++ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TEST */
++ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
++ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
++ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
++ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */
++ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */
++ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */
++ ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TFORLOOP */
++ ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */
++ ,opmode(0, 0, OpArgN, OpArgN, iABC)		/* OP_CLOSE */
++ ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
++ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
++};
++
+--- /dev/null
++++ b/extensions/LUA/lua/lopcodes.h
+@@ -0,0 +1,268 @@
++/*
++** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $
++** Opcodes for Lua virtual machine
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lopcodes_h
++#define lopcodes_h
++
++#include "llimits.h"
++
++
++/*===========================================================================
++  We assume that instructions are unsigned numbers.
++  All instructions have an opcode in the first 6 bits.
++  Instructions can have the following fields:
++	`A' : 8 bits
++	`B' : 9 bits
++	`C' : 9 bits
++	`Bx' : 18 bits (`B' and `C' together)
++	`sBx' : signed Bx
++
++  A signed argument is represented in excess K; that is, the number
++  value is the unsigned value minus K. K is exactly the maximum value
++  for that argument (so that -max is represented by 0, and +max is
++  represented by 2*max), which is half the maximum for the corresponding
++  unsigned argument.
++===========================================================================*/
++
++
++enum OpMode {iABC, iABx, iAsBx};  /* basic instruction format */
++
++
++/*
++** size and position of opcode arguments.
++*/
++#define SIZE_C		9
++#define SIZE_B		9
++#define SIZE_Bx		(SIZE_C + SIZE_B)
++#define SIZE_A		8
++
++#define SIZE_OP		6
++
++#define POS_OP		0
++#define POS_A		(POS_OP + SIZE_OP)
++#define POS_C		(POS_A + SIZE_A)
++#define POS_B		(POS_C + SIZE_C)
++#define POS_Bx		POS_C
++
++
++/*
++** limits for opcode arguments.
++** we use (signed) int to manipulate most arguments,
++** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
++*/
++#if SIZE_Bx < LUAI_BITSINT-1
++#define MAXARG_Bx        ((1<<SIZE_Bx)-1)
++#define MAXARG_sBx        (MAXARG_Bx>>1)         /* `sBx' is signed */
++#else
++#define MAXARG_Bx        MAX_INT
++#define MAXARG_sBx        MAX_INT
++#endif
++
++
++#define MAXARG_A        ((1<<SIZE_A)-1)
++#define MAXARG_B        ((1<<SIZE_B)-1)
++#define MAXARG_C        ((1<<SIZE_C)-1)
++
++
++/* creates a mask with `n' 1 bits at position `p' */
++#define MASK1(n,p)	((~((~(Instruction)0)<<n))<<p)
++
++/* creates a mask with `n' 0 bits at position `p' */
++#define MASK0(n,p)	(~MASK1(n,p))
++
++/*
++** the following macros help to manipulate instructions
++*/
++
++#define GET_OPCODE(i)	(cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
++#define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
++		((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
++
++#define GETARG_A(i)	(cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0)))
++#define SETARG_A(i,u)	((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
++		((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A))))
++
++#define GETARG_B(i)	(cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0)))
++#define SETARG_B(i,b)	((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
++		((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B))))
++
++#define GETARG_C(i)	(cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0)))
++#define SETARG_C(i,b)	((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
++		((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C))))
++
++#define GETARG_Bx(i)	(cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0)))
++#define SETARG_Bx(i,b)	((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \
++		((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx))))
++
++#define GETARG_sBx(i)	(GETARG_Bx(i)-MAXARG_sBx)
++#define SETARG_sBx(i,b)	SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
++
++
++#define CREATE_ABC(o,a,b,c)	((cast(Instruction, o)<<POS_OP) \
++			| (cast(Instruction, a)<<POS_A) \
++			| (cast(Instruction, b)<<POS_B) \
++			| (cast(Instruction, c)<<POS_C))
++
++#define CREATE_ABx(o,a,bc)	((cast(Instruction, o)<<POS_OP) \
++			| (cast(Instruction, a)<<POS_A) \
++			| (cast(Instruction, bc)<<POS_Bx))
++
++
++/*
++** Macros to operate RK indices
++*/
++
++/* this bit 1 means constant (0 means register) */
++#define BITRK		(1 << (SIZE_B - 1))
++
++/* test whether value is a constant */
++#define ISK(x)		((x) & BITRK)
++
++/* gets the index of the constant */
++#define INDEXK(r)	((int)(r) & ~BITRK)
++
++#define MAXINDEXRK	(BITRK - 1)
++
++/* code a constant index as a RK value */
++#define RKASK(x)	((x) | BITRK)
++
++
++/*
++** invalid register that fits in 8 bits
++*/
++#define NO_REG		MAXARG_A
++
++
++/*
++** R(x) - register
++** Kst(x) - constant (in constant table)
++** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
++*/
++
++
++/*
++** grep "ORDER OP" if you change these enums
++*/
++
++typedef enum {
++/*----------------------------------------------------------------------
++name		args	description
++------------------------------------------------------------------------*/
++OP_MOVE,/*	A B	R(A) := R(B)					*/
++OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/
++OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
++OP_LOADNIL,/*	A B	R(A) := ... := R(B) := nil			*/
++OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
++
++OP_GETGLOBAL,/*	A Bx	R(A) := Gbl[Kst(Bx)]				*/
++OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
++
++OP_SETGLOBAL,/*	A Bx	Gbl[Kst(Bx)] := R(A)				*/
++OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
++OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
++
++OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
++
++OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
++
++OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
++OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/
++OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/
++OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/
++OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/
++OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/
++OP_UNM,/*	A B	R(A) := -R(B)					*/
++OP_NOT,/*	A B	R(A) := not R(B)				*/
++OP_LEN,/*	A B	R(A) := length of R(B)				*/
++
++OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
++
++OP_JMP,/*	sBx	pc+=sBx					*/
++
++OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
++OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++  		*/
++OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++  		*/
++
++OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/ 
++OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/ 
++
++OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
++OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
++OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
++
++OP_FORLOOP,/*	A sBx	R(A)+=R(A+2);
++			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
++OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/
++
++OP_TFORLOOP,/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); 
++                        if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++	*/ 
++OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
++
++OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/
++OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))	*/
++
++OP_VARARG/*	A B	R(A), R(A+1), ..., R(A+B-1) = vararg		*/
++} OpCode;
++
++
++#define NUM_OPCODES	(cast(int, OP_VARARG) + 1)
++
++
++
++/*===========================================================================
++  Notes:
++  (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
++      and can be 0: OP_CALL then sets `top' to last_result+1, so
++      next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
++
++  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
++      set top (like in OP_CALL with C == 0).
++
++  (*) In OP_RETURN, if (B == 0) then return up to `top'
++
++  (*) In OP_SETLIST, if (B == 0) then B = `top';
++      if (C == 0) then next `instruction' is real C
++
++  (*) For comparisons, A specifies what condition the test should accept
++      (true or false).
++
++  (*) All `skips' (pc++) assume that next instruction is a jump
++===========================================================================*/
++
++
++/*
++** masks for instruction properties. The format is:
++** bits 0-1: op mode
++** bits 2-3: C arg mode
++** bits 4-5: B arg mode
++** bit 6: instruction set register A
++** bit 7: operator is a test
++*/  
++
++enum OpArgMask {
++  OpArgN,  /* argument is not used */
++  OpArgU,  /* argument is used */
++  OpArgR,  /* argument is a register or a jump offset */
++  OpArgK   /* argument is a constant or register/constant */
++};
++
++LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES];
++
++#define getOpMode(m)	(cast(enum OpMode, luaP_opmodes[m] & 3))
++#define getBMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
++#define getCMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
++#define testAMode(m)	(luaP_opmodes[m] & (1 << 6))
++#define testTMode(m)	(luaP_opmodes[m] & (1 << 7))
++
++
++LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1];  /* opcode names */
++
++
++/* number of list items to accumulate before a SETLIST instruction */
++#define LFIELDS_PER_FLUSH	50
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lparser.c
+@@ -0,0 +1,1339 @@
++/*
++** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
++** Lua Parser
++** See Copyright Notice in lua.h
++*/
++
++
++#include <string.h>
++
++#define lparser_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lcode.h"
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "llex.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lopcodes.h"
++#include "lparser.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++
++
++
++#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
++
++#define getlocvar(fs, i)	((fs)->f->locvars[(fs)->actvar[i]])
++
++#define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) errorlimit(fs,l,m)
++
++
++/*
++** nodes for block list (list of active blocks)
++*/
++typedef struct BlockCnt {
++  struct BlockCnt *previous;  /* chain */
++  int breaklist;  /* list of jumps out of this loop */
++  lu_byte nactvar;  /* # active locals outside the breakable structure */
++  lu_byte upval;  /* true if some variable in the block is an upvalue */
++  lu_byte isbreakable;  /* true if `block' is a loop */
++} BlockCnt;
++
++
++
++/*
++** prototypes for recursive non-terminal functions
++*/
++static void chunk (LexState *ls);
++static void expr (LexState *ls, expdesc *v);
++
++
++static void anchor_token (LexState *ls) {
++  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
++    TString *ts = ls->t.seminfo.ts;
++    luaX_newstring(ls, getstr(ts), ts->tsv.len);
++  }
++}
++
++
++static void error_expected (LexState *ls, int token) {
++  luaX_syntaxerror(ls,
++      luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token)));
++}
++
++
++static void errorlimit (FuncState *fs, int limit, const char *what) {
++  const char *msg = (fs->f->linedefined == 0) ?
++    luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
++    luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
++                            fs->f->linedefined, limit, what);
++  luaX_lexerror(fs->ls, msg, 0);
++}
++
++
++static int testnext (LexState *ls, int c) {
++  if (ls->t.token == c) {
++    luaX_next(ls);
++    return 1;
++  }
++  else return 0;
++}
++
++
++static void check (LexState *ls, int c) {
++  if (ls->t.token != c)
++    error_expected(ls, c);
++}
++
++static void checknext (LexState *ls, int c) {
++  check(ls, c);
++  luaX_next(ls);
++}
++
++
++#define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }
++
++
++
++static void check_match (LexState *ls, int what, int who, int where) {
++  if (!testnext(ls, what)) {
++    if (where == ls->linenumber)
++      error_expected(ls, what);
++    else {
++      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
++             LUA_QS " expected (to close " LUA_QS " at line %d)",
++              luaX_token2str(ls, what), luaX_token2str(ls, who), where));
++    }
++  }
++}
++
++
++static TString *str_checkname (LexState *ls) {
++  TString *ts;
++  check(ls, TK_NAME);
++  ts = ls->t.seminfo.ts;
++  luaX_next(ls);
++  return ts;
++}
++
++
++static void init_exp (expdesc *e, expkind k, int i) {
++  e->f = e->t = NO_JUMP;
++  e->k = k;
++  e->u.s.info = i;
++}
++
++
++static void codestring (LexState *ls, expdesc *e, TString *s) {
++  init_exp(e, VK, luaK_stringK(ls->fs, s));
++}
++
++
++static void checkname(LexState *ls, expdesc *e) {
++  codestring(ls, e, str_checkname(ls));
++}
++
++
++static int registerlocalvar (LexState *ls, TString *varname) {
++  FuncState *fs = ls->fs;
++  Proto *f = fs->f;
++  int oldsize = f->sizelocvars;
++  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
++                  LocVar, SHRT_MAX, "too many local variables");
++  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
++  f->locvars[fs->nlocvars].varname = varname;
++  luaC_objbarrier(ls->L, f, varname);
++  return fs->nlocvars++;
++}
++
++
++#define new_localvarliteral(ls,v,n) \
++  new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
++
++
++static void new_localvar (LexState *ls, TString *name, int n) {
++  FuncState *fs = ls->fs;
++  luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
++  fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
++}
++
++
++static void adjustlocalvars (LexState *ls, int nvars) {
++  FuncState *fs = ls->fs;
++  fs->nactvar = cast_byte(fs->nactvar + nvars);
++  for (; nvars; nvars--) {
++    getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc;
++  }
++}
++
++
++static void removevars (LexState *ls, int tolevel) {
++  FuncState *fs = ls->fs;
++  while (fs->nactvar > tolevel)
++    getlocvar(fs, --fs->nactvar).endpc = fs->pc;
++}
++
++
++static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
++  int i;
++  Proto *f = fs->f;
++  int oldsize = f->sizeupvalues;
++  for (i=0; i<f->nups; i++) {
++    if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) {
++      lua_assert(f->upvalues[i] == name);
++      return i;
++    }
++  }
++  /* new one */
++  luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues");
++  luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
++                  TString *, MAX_INT, "");
++  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
++  f->upvalues[f->nups] = name;
++  luaC_objbarrier(fs->L, f, name);
++  lua_assert(v->k == VLOCAL || v->k == VUPVAL);
++  fs->upvalues[f->nups].k = cast_byte(v->k);
++  fs->upvalues[f->nups].info = cast_byte(v->u.s.info);
++  return f->nups++;
++}
++
++
++static int searchvar (FuncState *fs, TString *n) {
++  int i;
++  for (i=fs->nactvar-1; i >= 0; i--) {
++    if (n == getlocvar(fs, i).varname)
++      return i;
++  }
++  return -1;  /* not found */
++}
++
++
++static void markupval (FuncState *fs, int level) {
++  BlockCnt *bl = fs->bl;
++  while (bl && bl->nactvar > level) bl = bl->previous;
++  if (bl) bl->upval = 1;
++}
++
++
++static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
++  if (fs == NULL) {  /* no more levels? */
++    init_exp(var, VGLOBAL, NO_REG);  /* default is global variable */
++    return VGLOBAL;
++  }
++  else {
++    int v = searchvar(fs, n);  /* look up at current level */
++    if (v >= 0) {
++      init_exp(var, VLOCAL, v);
++      if (!base)
++        markupval(fs, v);  /* local will be used as an upval */
++      return VLOCAL;
++    }
++    else {  /* not found at current level; try upper one */
++      if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
++        return VGLOBAL;
++      var->u.s.info = indexupvalue(fs, n, var);  /* else was LOCAL or UPVAL */
++      var->k = VUPVAL;  /* upvalue in this level */
++      return VUPVAL;
++    }
++  }
++}
++
++
++static void singlevar (LexState *ls, expdesc *var) {
++  TString *varname = str_checkname(ls);
++  FuncState *fs = ls->fs;
++  if (singlevaraux(fs, varname, var, 1) == VGLOBAL)
++    var->u.s.info = luaK_stringK(fs, varname);  /* info points to global name */
++}
++
++
++static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
++  FuncState *fs = ls->fs;
++  int extra = nvars - nexps;
++  if (hasmultret(e->k)) {
++    extra++;  /* includes call itself */
++    if (extra < 0) extra = 0;
++    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
++    if (extra > 1) luaK_reserveregs(fs, extra-1);
++  }
++  else {
++    if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
++    if (extra > 0) {
++      int reg = fs->freereg;
++      luaK_reserveregs(fs, extra);
++      luaK_nil(fs, reg, extra);
++    }
++  }
++}
++
++
++static void enterlevel (LexState *ls) {
++  if (++ls->L->nCcalls > LUAI_MAXCCALLS)
++	luaX_lexerror(ls, "chunk has too many syntax levels", 0);
++}
++
++
++#define leavelevel(ls)	((ls)->L->nCcalls--)
++
++
++static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
++  bl->breaklist = NO_JUMP;
++  bl->isbreakable = isbreakable;
++  bl->nactvar = fs->nactvar;
++  bl->upval = 0;
++  bl->previous = fs->bl;
++  fs->bl = bl;
++  lua_assert(fs->freereg == fs->nactvar);
++}
++
++
++static void leaveblock (FuncState *fs) {
++  BlockCnt *bl = fs->bl;
++  fs->bl = bl->previous;
++  removevars(fs->ls, bl->nactvar);
++  if (bl->upval)
++    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
++  /* a block either controls scope or breaks (never both) */
++  lua_assert(!bl->isbreakable || !bl->upval);
++  lua_assert(bl->nactvar == fs->nactvar);
++  fs->freereg = fs->nactvar;  /* free registers */
++  luaK_patchtohere(fs, bl->breaklist);
++}
++
++
++static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
++  FuncState *fs = ls->fs;
++  Proto *f = fs->f;
++  int oldsize = f->sizep;
++  int i;
++  luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
++                  MAXARG_Bx, "constant table overflow");
++  while (oldsize < f->sizep) f->p[oldsize++] = NULL;
++  f->p[fs->np++] = func->f;
++  luaC_objbarrier(ls->L, f, func->f);
++  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
++  for (i=0; i<func->f->nups; i++) {
++    OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
++    luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
++  }
++}
++
++
++static void open_func (LexState *ls, FuncState *fs) {
++  lua_State *L = ls->L;
++  Proto *f = luaF_newproto(L);
++  fs->f = f;
++  fs->prev = ls->fs;  /* linked list of funcstates */
++  fs->ls = ls;
++  fs->L = L;
++  ls->fs = fs;
++  fs->pc = 0;
++  fs->lasttarget = -1;
++  fs->jpc = NO_JUMP;
++  fs->freereg = 0;
++  fs->nk = 0;
++  fs->np = 0;
++  fs->nlocvars = 0;
++  fs->nactvar = 0;
++  fs->bl = NULL;
++  f->source = ls->source;
++  f->maxstacksize = 2;  /* registers 0/1 are always valid */
++  fs->h = luaH_new(L, 0, 0);
++  /* anchor table of constants and prototype (to avoid being collected) */
++  sethvalue2s(L, L->top, fs->h);
++  incr_top(L);
++  setptvalue2s(L, L->top, f);
++  incr_top(L);
++}
++
++
++static void close_func (LexState *ls) {
++  lua_State *L = ls->L;
++  FuncState *fs = ls->fs;
++  Proto *f = fs->f;
++  removevars(ls, 0);
++  luaK_ret(fs, 0, 0);  /* final return */
++  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
++  f->sizecode = fs->pc;
++  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
++  f->sizelineinfo = fs->pc;
++  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
++  f->sizek = fs->nk;
++  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
++  f->sizep = fs->np;
++  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
++  f->sizelocvars = fs->nlocvars;
++  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
++  f->sizeupvalues = f->nups;
++  lua_assert(luaG_checkcode(f));
++  lua_assert(fs->bl == NULL);
++  ls->fs = fs->prev;
++  L->top -= 2;  /* remove table and prototype from the stack */
++  /* last token read was anchored in defunct function; must reanchor it */
++  if (fs) anchor_token(ls);
++}
++
++
++Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
++  struct LexState lexstate;
++  struct FuncState funcstate;
++  lexstate.buff = buff;
++  luaX_setinput(L, &lexstate, z, luaS_new(L, name));
++  open_func(&lexstate, &funcstate);
++  funcstate.f->is_vararg = VARARG_ISVARARG;  /* main func. is always vararg */
++  luaX_next(&lexstate);  /* read first token */
++  chunk(&lexstate);
++  check(&lexstate, TK_EOS);
++  close_func(&lexstate);
++  lua_assert(funcstate.prev == NULL);
++  lua_assert(funcstate.f->nups == 0);
++  lua_assert(lexstate.fs == NULL);
++  return funcstate.f;
++}
++
++
++
++/*============================================================*/
++/* GRAMMAR RULES */
++/*============================================================*/
++
++
++static void field (LexState *ls, expdesc *v) {
++  /* field -> ['.' | ':'] NAME */
++  FuncState *fs = ls->fs;
++  expdesc key;
++  luaK_exp2anyreg(fs, v);
++  luaX_next(ls);  /* skip the dot or colon */
++  checkname(ls, &key);
++  luaK_indexed(fs, v, &key);
++}
++
++
++static void yindex (LexState *ls, expdesc *v) {
++  /* index -> '[' expr ']' */
++  luaX_next(ls);  /* skip the '[' */
++  expr(ls, v);
++  luaK_exp2val(ls->fs, v);
++  checknext(ls, ']');
++}
++
++
++/*
++** {======================================================================
++** Rules for Constructors
++** =======================================================================
++*/
++
++
++struct ConsControl {
++  expdesc v;  /* last list item read */
++  expdesc *t;  /* table descriptor */
++  int nh;  /* total number of `record' elements */
++  int na;  /* total number of array elements */
++  int tostore;  /* number of array elements pending to be stored */
++};
++
++
++static void recfield (LexState *ls, struct ConsControl *cc) {
++  /* recfield -> (NAME | `['exp1`]') = exp1 */
++  FuncState *fs = ls->fs;
++  int reg = ls->fs->freereg;
++  expdesc key, val;
++  int rkkey;
++  if (ls->t.token == TK_NAME) {
++    luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
++    checkname(ls, &key);
++  }
++  else  /* ls->t.token == '[' */
++    yindex(ls, &key);
++  cc->nh++;
++  checknext(ls, '=');
++  rkkey = luaK_exp2RK(fs, &key);
++  expr(ls, &val);
++  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val));
++  fs->freereg = reg;  /* free registers */
++}
++
++
++static void closelistfield (FuncState *fs, struct ConsControl *cc) {
++  if (cc->v.k == VVOID) return;  /* there is no list item */
++  luaK_exp2nextreg(fs, &cc->v);
++  cc->v.k = VVOID;
++  if (cc->tostore == LFIELDS_PER_FLUSH) {
++    luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);  /* flush */
++    cc->tostore = 0;  /* no more items pending */
++  }
++}
++
++
++static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
++  if (cc->tostore == 0) return;
++  if (hasmultret(cc->v.k)) {
++    luaK_setmultret(fs, &cc->v);
++    luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET);
++    cc->na--;  /* do not count last expression (unknown number of elements) */
++  }
++  else {
++    if (cc->v.k != VVOID)
++      luaK_exp2nextreg(fs, &cc->v);
++    luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);
++  }
++}
++
++
++static void listfield (LexState *ls, struct ConsControl *cc) {
++  expr(ls, &cc->v);
++  luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
++  cc->na++;
++  cc->tostore++;
++}
++
++
++static void constructor (LexState *ls, expdesc *t) {
++  /* constructor -> ?? */
++  FuncState *fs = ls->fs;
++  int line = ls->linenumber;
++  int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
++  struct ConsControl cc;
++  cc.na = cc.nh = cc.tostore = 0;
++  cc.t = t;
++  init_exp(t, VRELOCABLE, pc);
++  init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
++  luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top (for gc) */
++  checknext(ls, '{');
++  do {
++    lua_assert(cc.v.k == VVOID || cc.tostore > 0);
++    if (ls->t.token == '}') break;
++    closelistfield(fs, &cc);
++    switch(ls->t.token) {
++      case TK_NAME: {  /* may be listfields or recfields */
++        luaX_lookahead(ls);
++        if (ls->lookahead.token != '=')  /* expression? */
++          listfield(ls, &cc);
++        else
++          recfield(ls, &cc);
++        break;
++      }
++      case '[': {  /* constructor_item -> recfield */
++        recfield(ls, &cc);
++        break;
++      }
++      default: {  /* constructor_part -> listfield */
++        listfield(ls, &cc);
++        break;
++      }
++    }
++  } while (testnext(ls, ',') || testnext(ls, ';'));
++  check_match(ls, '}', '{', line);
++  lastlistfield(fs, &cc);
++  SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
++  SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
++}
++
++/* }====================================================================== */
++
++
++
++static void parlist (LexState *ls) {
++  /* parlist -> [ param { `,' param } ] */
++  FuncState *fs = ls->fs;
++  Proto *f = fs->f;
++  int nparams = 0;
++  f->is_vararg = 0;
++  if (ls->t.token != ')') {  /* is `parlist' not empty? */
++    do {
++      switch (ls->t.token) {
++        case TK_NAME: {  /* param -> NAME */
++          new_localvar(ls, str_checkname(ls), nparams++);
++          break;
++        }
++        case TK_DOTS: {  /* param -> `...' */
++          luaX_next(ls);
++#if defined(LUA_COMPAT_VARARG)
++          /* use `arg' as default name */
++          new_localvarliteral(ls, "arg", nparams++);
++          f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
++#endif
++          f->is_vararg |= VARARG_ISVARARG;
++          break;
++        }
++        default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
++      }
++    } while (!f->is_vararg && testnext(ls, ','));
++  }
++  adjustlocalvars(ls, nparams);
++  f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG));
++  luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */
++}
++
++
++static void body (LexState *ls, expdesc *e, int needself, int line) {
++  /* body ->  `(' parlist `)' chunk END */
++  FuncState new_fs;
++  open_func(ls, &new_fs);
++  new_fs.f->linedefined = line;
++  checknext(ls, '(');
++  if (needself) {
++    new_localvarliteral(ls, "self", 0);
++    adjustlocalvars(ls, 1);
++  }
++  parlist(ls);
++  checknext(ls, ')');
++  chunk(ls);
++  new_fs.f->lastlinedefined = ls->linenumber;
++  check_match(ls, TK_END, TK_FUNCTION, line);
++  close_func(ls);
++  pushclosure(ls, &new_fs, e);
++}
++
++
++static int explist1 (LexState *ls, expdesc *v) {
++  /* explist1 -> expr { `,' expr } */
++  int n = 1;  /* at least one expression */
++  expr(ls, v);
++  while (testnext(ls, ',')) {
++    luaK_exp2nextreg(ls->fs, v);
++    expr(ls, v);
++    n++;
++  }
++  return n;
++}
++
++
++static void funcargs (LexState *ls, expdesc *f) {
++  FuncState *fs = ls->fs;
++  expdesc args;
++  int base, nparams;
++  int line = ls->linenumber;
++  switch (ls->t.token) {
++    case '(': {  /* funcargs -> `(' [ explist1 ] `)' */
++      if (line != ls->lastline)
++        luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
++      luaX_next(ls);
++      if (ls->t.token == ')')  /* arg list is empty? */
++        args.k = VVOID;
++      else {
++        explist1(ls, &args);
++        luaK_setmultret(fs, &args);
++      }
++      check_match(ls, ')', '(', line);
++      break;
++    }
++    case '{': {  /* funcargs -> constructor */
++      constructor(ls, &args);
++      break;
++    }
++    case TK_STRING: {  /* funcargs -> STRING */
++      codestring(ls, &args, ls->t.seminfo.ts);
++      luaX_next(ls);  /* must use `seminfo' before `next' */
++      break;
++    }
++    default: {
++      luaX_syntaxerror(ls, "function arguments expected");
++      return;
++    }
++  }
++  lua_assert(f->k == VNONRELOC);
++  base = f->u.s.info;  /* base register for call */
++  if (hasmultret(args.k))
++    nparams = LUA_MULTRET;  /* open call */
++  else {
++    if (args.k != VVOID)
++      luaK_exp2nextreg(fs, &args);  /* close last argument */
++    nparams = fs->freereg - (base+1);
++  }
++  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
++  luaK_fixline(fs, line);
++  fs->freereg = base+1;  /* call remove function and arguments and leaves
++                            (unless changed) one result */
++}
++
++
++
++
++/*
++** {======================================================================
++** Expression parsing
++** =======================================================================
++*/
++
++
++static void prefixexp (LexState *ls, expdesc *v) {
++  /* prefixexp -> NAME | '(' expr ')' */
++  switch (ls->t.token) {
++    case '(': {
++      int line = ls->linenumber;
++      luaX_next(ls);
++      expr(ls, v);
++      check_match(ls, ')', '(', line);
++      luaK_dischargevars(ls->fs, v);
++      return;
++    }
++    case TK_NAME: {
++      singlevar(ls, v);
++      return;
++    }
++    default: {
++      luaX_syntaxerror(ls, "unexpected symbol");
++      return;
++    }
++  }
++}
++
++
++static void primaryexp (LexState *ls, expdesc *v) {
++  /* primaryexp ->
++        prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
++  FuncState *fs = ls->fs;
++  prefixexp(ls, v);
++  for (;;) {
++    switch (ls->t.token) {
++      case '.': {  /* field */
++        field(ls, v);
++        break;
++      }
++      case '[': {  /* `[' exp1 `]' */
++        expdesc key;
++        luaK_exp2anyreg(fs, v);
++        yindex(ls, &key);
++        luaK_indexed(fs, v, &key);
++        break;
++      }
++      case ':': {  /* `:' NAME funcargs */
++        expdesc key;
++        luaX_next(ls);
++        checkname(ls, &key);
++        luaK_self(fs, v, &key);
++        funcargs(ls, v);
++        break;
++      }
++      case '(': case TK_STRING: case '{': {  /* funcargs */
++        luaK_exp2nextreg(fs, v);
++        funcargs(ls, v);
++        break;
++      }
++      default: return;
++    }
++  }
++}
++
++
++static void simpleexp (LexState *ls, expdesc *v) {
++  /* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
++                  constructor | FUNCTION body | primaryexp */
++  switch (ls->t.token) {
++    case TK_NUMBER: {
++      init_exp(v, VKNUM, 0);
++      v->u.nval = ls->t.seminfo.r;
++      break;
++    }
++    case TK_STRING: {
++      codestring(ls, v, ls->t.seminfo.ts);
++      break;
++    }
++    case TK_NIL: {
++      init_exp(v, VNIL, 0);
++      break;
++    }
++    case TK_TRUE: {
++      init_exp(v, VTRUE, 0);
++      break;
++    }
++    case TK_FALSE: {
++      init_exp(v, VFALSE, 0);
++      break;
++    }
++    case TK_DOTS: {  /* vararg */
++      FuncState *fs = ls->fs;
++      check_condition(ls, fs->f->is_vararg,
++                      "cannot use " LUA_QL("...") " outside a vararg function");
++      fs->f->is_vararg &= ~VARARG_NEEDSARG;  /* don't need 'arg' */
++      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
++      break;
++    }
++    case '{': {  /* constructor */
++      constructor(ls, v);
++      return;
++    }
++    case TK_FUNCTION: {
++      luaX_next(ls);
++      body(ls, v, 0, ls->linenumber);
++      return;
++    }
++    default: {
++      primaryexp(ls, v);
++      return;
++    }
++  }
++  luaX_next(ls);
++}
++
++
++static UnOpr getunopr (int op) {
++  switch (op) {
++    case TK_NOT: return OPR_NOT;
++    case '-': return OPR_MINUS;
++    case '#': return OPR_LEN;
++    default: return OPR_NOUNOPR;
++  }
++}
++
++
++static BinOpr getbinopr (int op) {
++  switch (op) {
++    case '+': return OPR_ADD;
++    case '-': return OPR_SUB;
++    case '*': return OPR_MUL;
++    case '/': return OPR_DIV;
++    case '%': return OPR_MOD;
++    case '^': return OPR_POW;
++    case TK_CONCAT: return OPR_CONCAT;
++    case TK_NE: return OPR_NE;
++    case TK_EQ: return OPR_EQ;
++    case '<': return OPR_LT;
++    case TK_LE: return OPR_LE;
++    case '>': return OPR_GT;
++    case TK_GE: return OPR_GE;
++    case TK_AND: return OPR_AND;
++    case TK_OR: return OPR_OR;
++    default: return OPR_NOBINOPR;
++  }
++}
++
++
++static const struct {
++  lu_byte left;  /* left priority for each binary operator */
++  lu_byte right; /* right priority */
++} priority[] = {  /* ORDER OPR */
++   {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `/' `%' */
++   {10, 9}, {5, 4},                 /* power and concat (right associative) */
++   {3, 3}, {3, 3},                  /* equality and inequality */
++   {3, 3}, {3, 3}, {3, 3}, {3, 3},  /* order */
++   {2, 2}, {1, 1}                   /* logical (and/or) */
++};
++
++#define UNARY_PRIORITY	8  /* priority for unary operators */
++
++
++/*
++** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
++** where `binop' is any binary operator with a priority higher than `limit'
++*/
++static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
++  BinOpr op;
++  UnOpr uop;
++  enterlevel(ls);
++  uop = getunopr(ls->t.token);
++  if (uop != OPR_NOUNOPR) {
++    luaX_next(ls);
++    subexpr(ls, v, UNARY_PRIORITY);
++    luaK_prefix(ls->fs, uop, v);
++  }
++  else simpleexp(ls, v);
++  /* expand while operators have priorities higher than `limit' */
++  op = getbinopr(ls->t.token);
++  while (op != OPR_NOBINOPR && priority[op].left > limit) {
++    expdesc v2;
++    BinOpr nextop;
++    luaX_next(ls);
++    luaK_infix(ls->fs, op, v);
++    /* read sub-expression with higher priority */
++    nextop = subexpr(ls, &v2, priority[op].right);
++    luaK_posfix(ls->fs, op, v, &v2);
++    op = nextop;
++  }
++  leavelevel(ls);
++  return op;  /* return first untreated operator */
++}
++
++
++static void expr (LexState *ls, expdesc *v) {
++  subexpr(ls, v, 0);
++}
++
++/* }==================================================================== */
++
++
++
++/*
++** {======================================================================
++** Rules for Statements
++** =======================================================================
++*/
++
++
++static int block_follow (int token) {
++  switch (token) {
++    case TK_ELSE: case TK_ELSEIF: case TK_END:
++    case TK_UNTIL: case TK_EOS:
++      return 1;
++    default: return 0;
++  }
++}
++
++
++static void block (LexState *ls) {
++  /* block -> chunk */
++  FuncState *fs = ls->fs;
++  BlockCnt bl;
++  enterblock(fs, &bl, 0);
++  chunk(ls);
++  lua_assert(bl.breaklist == NO_JUMP);
++  leaveblock(fs);
++}
++
++
++/*
++** structure to chain all variables in the left-hand side of an
++** assignment
++*/
++struct LHS_assign {
++  struct LHS_assign *prev;
++  expdesc v;  /* variable (global, local, upvalue, or indexed) */
++};
++
++
++/*
++** check whether, in an assignment to a local variable, the local variable
++** is needed in a previous assignment (to a table). If so, save original
++** local value in a safe place and use this safe copy in the previous
++** assignment.
++*/
++static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
++  FuncState *fs = ls->fs;
++  int extra = fs->freereg;  /* eventual position to save local variable */
++  int conflict = 0;
++  for (; lh; lh = lh->prev) {
++    if (lh->v.k == VINDEXED) {
++      if (lh->v.u.s.info == v->u.s.info) {  /* conflict? */
++        conflict = 1;
++        lh->v.u.s.info = extra;  /* previous assignment will use safe copy */
++      }
++      if (lh->v.u.s.aux == v->u.s.info) {  /* conflict? */
++        conflict = 1;
++        lh->v.u.s.aux = extra;  /* previous assignment will use safe copy */
++      }
++    }
++  }
++  if (conflict) {
++    luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0);  /* make copy */
++    luaK_reserveregs(fs, 1);
++  }
++}
++
++
++static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
++  expdesc e;
++  check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
++                      "syntax error");
++  if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */
++    struct LHS_assign nv;
++    nv.prev = lh;
++    primaryexp(ls, &nv.v);
++    if (nv.v.k == VLOCAL)
++      check_conflict(ls, lh, &nv.v);
++    luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls,
++                    "variables in assignment");
++    assignment(ls, &nv, nvars+1);
++  }
++  else {  /* assignment -> `=' explist1 */
++    int nexps;
++    checknext(ls, '=');
++    nexps = explist1(ls, &e);
++    if (nexps != nvars) {
++      adjust_assign(ls, nvars, nexps, &e);
++      if (nexps > nvars)
++        ls->fs->freereg -= nexps - nvars;  /* remove extra values */
++    }
++    else {
++      luaK_setoneret(ls->fs, &e);  /* close last expression */
++      luaK_storevar(ls->fs, &lh->v, &e);
++      return;  /* avoid default */
++    }
++  }
++  init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
++  luaK_storevar(ls->fs, &lh->v, &e);
++}
++
++
++static int cond (LexState *ls) {
++  /* cond -> exp */
++  expdesc v;
++  expr(ls, &v);  /* read condition */
++  if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */
++  luaK_goiftrue(ls->fs, &v);
++  return v.f;
++}
++
++
++static void breakstat (LexState *ls) {
++  FuncState *fs = ls->fs;
++  BlockCnt *bl = fs->bl;
++  int upval = 0;
++  while (bl && !bl->isbreakable) {
++    upval |= bl->upval;
++    bl = bl->previous;
++  }
++  if (!bl)
++    luaX_syntaxerror(ls, "no loop to break");
++  if (upval)
++    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
++  luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
++}
++
++
++static void whilestat (LexState *ls, int line) {
++  /* whilestat -> WHILE cond DO block END */
++  FuncState *fs = ls->fs;
++  int whileinit;
++  int condexit;
++  BlockCnt bl;
++  luaX_next(ls);  /* skip WHILE */
++  whileinit = luaK_getlabel(fs);
++  condexit = cond(ls);
++  enterblock(fs, &bl, 1);
++  checknext(ls, TK_DO);
++  block(ls);
++  luaK_patchlist(fs, luaK_jump(fs), whileinit);
++  check_match(ls, TK_END, TK_WHILE, line);
++  leaveblock(fs);
++  luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */
++}
++
++
++static void repeatstat (LexState *ls, int line) {
++  /* repeatstat -> REPEAT block UNTIL cond */
++  int condexit;
++  FuncState *fs = ls->fs;
++  int repeat_init = luaK_getlabel(fs);
++  BlockCnt bl1, bl2;
++  enterblock(fs, &bl1, 1);  /* loop block */
++  enterblock(fs, &bl2, 0);  /* scope block */
++  luaX_next(ls);  /* skip REPEAT */
++  chunk(ls);
++  check_match(ls, TK_UNTIL, TK_REPEAT, line);
++  condexit = cond(ls);  /* read condition (inside scope block) */
++  if (!bl2.upval) {  /* no upvalues? */
++    leaveblock(fs);  /* finish scope */
++    luaK_patchlist(ls->fs, condexit, repeat_init);  /* close the loop */
++  }
++  else {  /* complete semantics when there are upvalues */
++    breakstat(ls);  /* if condition then break */
++    luaK_patchtohere(ls->fs, condexit);  /* else... */
++    leaveblock(fs);  /* finish scope... */
++    luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init);  /* and repeat */
++  }
++  leaveblock(fs);  /* finish loop */
++}
++
++
++static int exp1 (LexState *ls) {
++  expdesc e;
++  int k;
++  expr(ls, &e);
++  k = e.k;
++  luaK_exp2nextreg(ls->fs, &e);
++  return k;
++}
++
++
++static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
++  /* forbody -> DO block */
++  BlockCnt bl;
++  FuncState *fs = ls->fs;
++  int prep, endfor;
++  adjustlocalvars(ls, 3);  /* control variables */
++  checknext(ls, TK_DO);
++  prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
++  enterblock(fs, &bl, 0);  /* scope for declared variables */
++  adjustlocalvars(ls, nvars);
++  luaK_reserveregs(fs, nvars);
++  block(ls);
++  leaveblock(fs);  /* end of scope for declared variables */
++  luaK_patchtohere(fs, prep);
++  endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
++                     luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
++  luaK_fixline(fs, line);  /* pretend that `OP_FOR' starts the loop */
++  luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
++}
++
++
++static void fornum (LexState *ls, TString *varname, int line) {
++  /* fornum -> NAME = exp1,exp1[,exp1] forbody */
++  FuncState *fs = ls->fs;
++  int base = fs->freereg;
++  new_localvarliteral(ls, "(for index)", 0);
++  new_localvarliteral(ls, "(for limit)", 1);
++  new_localvarliteral(ls, "(for step)", 2);
++  new_localvar(ls, varname, 3);
++  checknext(ls, '=');
++  exp1(ls);  /* initial value */
++  checknext(ls, ',');
++  exp1(ls);  /* limit */
++  if (testnext(ls, ','))
++    exp1(ls);  /* optional step */
++  else {  /* default step = 1 */
++    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
++    luaK_reserveregs(fs, 1);
++  }
++  forbody(ls, base, line, 1, 1);
++}
++
++
++static void forlist (LexState *ls, TString *indexname) {
++  /* forlist -> NAME {,NAME} IN explist1 forbody */
++  FuncState *fs = ls->fs;
++  expdesc e;
++  int nvars = 0;
++  int line;
++  int base = fs->freereg;
++  /* create control variables */
++  new_localvarliteral(ls, "(for generator)", nvars++);
++  new_localvarliteral(ls, "(for state)", nvars++);
++  new_localvarliteral(ls, "(for control)", nvars++);
++  /* create declared variables */
++  new_localvar(ls, indexname, nvars++);
++  while (testnext(ls, ','))
++    new_localvar(ls, str_checkname(ls), nvars++);
++  checknext(ls, TK_IN);
++  line = ls->linenumber;
++  adjust_assign(ls, 3, explist1(ls, &e), &e);
++  luaK_checkstack(fs, 3);  /* extra space to call generator */
++  forbody(ls, base, line, nvars - 3, 0);
++}
++
++
++static void forstat (LexState *ls, int line) {
++  /* forstat -> FOR (fornum | forlist) END */
++  FuncState *fs = ls->fs;
++  TString *varname;
++  BlockCnt bl;
++  enterblock(fs, &bl, 1);  /* scope for loop and control variables */
++  luaX_next(ls);  /* skip `for' */
++  varname = str_checkname(ls);  /* first variable name */
++  switch (ls->t.token) {
++    case '=': fornum(ls, varname, line); break;
++    case ',': case TK_IN: forlist(ls, varname); break;
++    default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
++  }
++  check_match(ls, TK_END, TK_FOR, line);
++  leaveblock(fs);  /* loop scope (`break' jumps to this point) */
++}
++
++
++static int test_then_block (LexState *ls) {
++  /* test_then_block -> [IF | ELSEIF] cond THEN block */
++  int condexit;
++  luaX_next(ls);  /* skip IF or ELSEIF */
++  condexit = cond(ls);
++  checknext(ls, TK_THEN);
++  block(ls);  /* `then' part */
++  return condexit;
++}
++
++
++static void ifstat (LexState *ls, int line) {
++  /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
++  FuncState *fs = ls->fs;
++  int flist;
++  int escapelist = NO_JUMP;
++  flist = test_then_block(ls);  /* IF cond THEN block */
++  while (ls->t.token == TK_ELSEIF) {
++    luaK_concat(fs, &escapelist, luaK_jump(fs));
++    luaK_patchtohere(fs, flist);
++    flist = test_then_block(ls);  /* ELSEIF cond THEN block */
++  }
++  if (ls->t.token == TK_ELSE) {
++    luaK_concat(fs, &escapelist, luaK_jump(fs));
++    luaK_patchtohere(fs, flist);
++    luaX_next(ls);  /* skip ELSE (after patch, for correct line info) */
++    block(ls);  /* `else' part */
++  }
++  else
++    luaK_concat(fs, &escapelist, flist);
++  luaK_patchtohere(fs, escapelist);
++  check_match(ls, TK_END, TK_IF, line);
++}
++
++
++static void localfunc (LexState *ls) {
++  expdesc v, b;
++  FuncState *fs = ls->fs;
++  new_localvar(ls, str_checkname(ls), 0);
++  init_exp(&v, VLOCAL, fs->freereg);
++  luaK_reserveregs(fs, 1);
++  adjustlocalvars(ls, 1);
++  body(ls, &b, 0, ls->linenumber);
++  luaK_storevar(fs, &v, &b);
++  /* debug information will only see the variable after this point! */
++  getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
++}
++
++
++static void localstat (LexState *ls) {
++  /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
++  int nvars = 0;
++  int nexps;
++  expdesc e;
++  do {
++    new_localvar(ls, str_checkname(ls), nvars++);
++  } while (testnext(ls, ','));
++  if (testnext(ls, '='))
++    nexps = explist1(ls, &e);
++  else {
++    e.k = VVOID;
++    nexps = 0;
++  }
++  adjust_assign(ls, nvars, nexps, &e);
++  adjustlocalvars(ls, nvars);
++}
++
++
++static int funcname (LexState *ls, expdesc *v) {
++  /* funcname -> NAME {field} [`:' NAME] */
++  int needself = 0;
++  singlevar(ls, v);
++  while (ls->t.token == '.')
++    field(ls, v);
++  if (ls->t.token == ':') {
++    needself = 1;
++    field(ls, v);
++  }
++  return needself;
++}
++
++
++static void funcstat (LexState *ls, int line) {
++  /* funcstat -> FUNCTION funcname body */
++  int needself;
++  expdesc v, b;
++  luaX_next(ls);  /* skip FUNCTION */
++  needself = funcname(ls, &v);
++  body(ls, &b, needself, line);
++  luaK_storevar(ls->fs, &v, &b);
++  luaK_fixline(ls->fs, line);  /* definition `happens' in the first line */
++}
++
++
++static void exprstat (LexState *ls) {
++  /* stat -> func | assignment */
++  FuncState *fs = ls->fs;
++  struct LHS_assign v;
++  primaryexp(ls, &v.v);
++  if (v.v.k == VCALL)  /* stat -> func */
++    SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */
++  else {  /* stat -> assignment */
++    v.prev = NULL;
++    assignment(ls, &v, 1);
++  }
++}
++
++
++static void retstat (LexState *ls) {
++  /* stat -> RETURN explist */
++  FuncState *fs = ls->fs;
++  expdesc e;
++  int first, nret;  /* registers with returned values */
++  luaX_next(ls);  /* skip RETURN */
++  if (block_follow(ls->t.token) || ls->t.token == ';')
++    first = nret = 0;  /* return no values */
++  else {
++    nret = explist1(ls, &e);  /* optional return values */
++    if (hasmultret(e.k)) {
++      luaK_setmultret(fs, &e);
++      if (e.k == VCALL && nret == 1) {  /* tail call? */
++        SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
++        lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
++      }
++      first = fs->nactvar;
++      nret = LUA_MULTRET;  /* return all values */
++    }
++    else {
++      if (nret == 1)  /* only one single value? */
++        first = luaK_exp2anyreg(fs, &e);
++      else {
++        luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
++        first = fs->nactvar;  /* return all `active' values */
++        lua_assert(nret == fs->freereg - first);
++      }
++    }
++  }
++  luaK_ret(fs, first, nret);
++}
++
++
++static int statement (LexState *ls) {
++  int line = ls->linenumber;  /* may be needed for error messages */
++  switch (ls->t.token) {
++    case TK_IF: {  /* stat -> ifstat */
++      ifstat(ls, line);
++      return 0;
++    }
++    case TK_WHILE: {  /* stat -> whilestat */
++      whilestat(ls, line);
++      return 0;
++    }
++    case TK_DO: {  /* stat -> DO block END */
++      luaX_next(ls);  /* skip DO */
++      block(ls);
++      check_match(ls, TK_END, TK_DO, line);
++      return 0;
++    }
++    case TK_FOR: {  /* stat -> forstat */
++      forstat(ls, line);
++      return 0;
++    }
++    case TK_REPEAT: {  /* stat -> repeatstat */
++      repeatstat(ls, line);
++      return 0;
++    }
++    case TK_FUNCTION: {
++      funcstat(ls, line);  /* stat -> funcstat */
++      return 0;
++    }
++    case TK_LOCAL: {  /* stat -> localstat */
++      luaX_next(ls);  /* skip LOCAL */
++      if (testnext(ls, TK_FUNCTION))  /* local function? */
++        localfunc(ls);
++      else
++        localstat(ls);
++      return 0;
++    }
++    case TK_RETURN: {  /* stat -> retstat */
++      retstat(ls);
++      return 1;  /* must be last statement */
++    }
++    case TK_BREAK: {  /* stat -> breakstat */
++      luaX_next(ls);  /* skip BREAK */
++      breakstat(ls);
++      return 1;  /* must be last statement */
++    }
++    default: {
++      exprstat(ls);
++      return 0;  /* to avoid warnings */
++    }
++  }
++}
++
++
++static void chunk (LexState *ls) {
++  /* chunk -> { stat [`;'] } */
++  int islast = 0;
++  enterlevel(ls);
++  while (!islast && !block_follow(ls->t.token)) {
++    islast = statement(ls);
++    testnext(ls, ';');
++    lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
++               ls->fs->freereg >= ls->fs->nactvar);
++    ls->fs->freereg = ls->fs->nactvar;  /* free registers */
++  }
++  leavelevel(ls);
++}
++
++/* }====================================================================== */
+--- /dev/null
++++ b/extensions/LUA/lua/lparser.h
+@@ -0,0 +1,82 @@
++/*
++** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lua Parser
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lparser_h
++#define lparser_h
++
++#include "llimits.h"
++#include "lobject.h"
++#include "lzio.h"
++
++
++/*
++** Expression descriptor
++*/
++
++typedef enum {
++  VVOID,	/* no value */
++  VNIL,
++  VTRUE,
++  VFALSE,
++  VK,		/* info = index of constant in `k' */
++  VKNUM,	/* nval = numerical value */
++  VLOCAL,	/* info = local register */
++  VUPVAL,       /* info = index of upvalue in `upvalues' */
++  VGLOBAL,	/* info = index of table; aux = index of global name in `k' */
++  VINDEXED,	/* info = table register; aux = index register (or `k') */
++  VJMP,		/* info = instruction pc */
++  VRELOCABLE,	/* info = instruction pc */
++  VNONRELOC,	/* info = result register */
++  VCALL,	/* info = instruction pc */
++  VVARARG	/* info = instruction pc */
++} expkind;
++
++typedef struct expdesc {
++  expkind k;
++  union {
++    struct { int info, aux; } s;
++    lua_Number nval;
++  } u;
++  int t;  /* patch list of `exit when true' */
++  int f;  /* patch list of `exit when false' */
++} expdesc;
++
++
++typedef struct upvaldesc {
++  lu_byte k;
++  lu_byte info;
++} upvaldesc;
++
++
++struct BlockCnt;  /* defined in lparser.c */
++
++
++/* state needed to generate code for a given function */
++typedef struct FuncState {
++  Proto *f;  /* current function header */
++  Table *h;  /* table to find (and reuse) elements in `k' */
++  struct FuncState *prev;  /* enclosing function */
++  struct LexState *ls;  /* lexical state */
++  struct lua_State *L;  /* copy of the Lua state */
++  struct BlockCnt *bl;  /* chain of current blocks */
++  int pc;  /* next position to code (equivalent to `ncode') */
++  int lasttarget;   /* `pc' of last `jump target' */
++  int jpc;  /* list of pending jumps to `pc' */
++  int freereg;  /* first free register */
++  int nk;  /* number of elements in `k' */
++  int np;  /* number of elements in `p' */
++  short nlocvars;  /* number of elements in `locvars' */
++  lu_byte nactvar;  /* number of active local variables */
++  upvaldesc upvalues[LUAI_MAXUPVALUES];  /* upvalues */
++  unsigned short actvar[LUAI_MAXVARS];  /* declared-variable stack */
++} FuncState;
++
++
++LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
++                                            const char *name);
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lstate.c
+@@ -0,0 +1,214 @@
++/*
++** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $
++** Global State
++** See Copyright Notice in lua.h
++*/
++
++
++#include <stddef.h>
++
++#define lstate_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lgc.h"
++#include "llex.h"
++#include "lmem.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++
++
++#define state_size(x)	(sizeof(x) + LUAI_EXTRASPACE)
++#define fromstate(l)	(cast(lu_byte *, (l)) - LUAI_EXTRASPACE)
++#define tostate(l)   (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE))
++
++
++/*
++** Main thread combines a thread state and the global state
++*/
++typedef struct LG {
++  lua_State l;
++  global_State g;
++} LG;
++  
++
++
++static void stack_init (lua_State *L1, lua_State *L) {
++  /* initialize CallInfo array */
++  L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
++  L1->ci = L1->base_ci;
++  L1->size_ci = BASIC_CI_SIZE;
++  L1->end_ci = L1->base_ci + L1->size_ci - 1;
++  /* initialize stack array */
++  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue);
++  L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
++  L1->top = L1->stack;
++  L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
++  /* initialize first ci */
++  L1->ci->func = L1->top;
++  setnilvalue(L1->top++);  /* `function' entry for this `ci' */
++  L1->base = L1->ci->base = L1->top;
++  L1->ci->top = L1->top + LUA_MINSTACK;
++}
++
++
++static void freestack (lua_State *L, lua_State *L1) {
++  luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
++  luaM_freearray(L, L1->stack, L1->stacksize, TValue);
++}
++
++
++/*
++** open parts that may cause memory-allocation errors
++*/
++static void f_luaopen (lua_State *L, void *ud) {
++  global_State *g = G(L);
++  UNUSED(ud);
++  stack_init(L, L);  /* init stack */
++  sethvalue(L, gt(L), luaH_new(L, 0, 2));  /* table of globals */
++  sethvalue(L, registry(L), luaH_new(L, 0, 2));  /* registry */
++  luaS_resize(L, MINSTRTABSIZE);  /* initial size of string table */
++  luaT_init(L);
++  luaX_init(L);
++  luaS_fix(luaS_newliteral(L, MEMERRMSG));
++  g->GCthreshold = 4*g->totalbytes;
++}
++
++
++static void preinit_state (lua_State *L, global_State *g) {
++  G(L) = g;
++  L->stack = NULL;
++  L->stacksize = 0;
++  L->errorJmp = NULL;
++  L->hook = NULL;
++  L->hookmask = 0;
++  L->basehookcount = 0;
++  L->allowhook = 1;
++  resethookcount(L);
++  L->openupval = NULL;
++  L->size_ci = 0;
++  L->nCcalls = L->baseCcalls = 0;
++  L->status = 0;
++  L->base_ci = L->ci = NULL;
++  L->savedpc = NULL;
++  L->errfunc = 0;
++  setnilvalue(gt(L));
++}
++
++
++static void close_state (lua_State *L) {
++  global_State *g = G(L);
++  luaF_close(L, L->stack);  /* close all upvalues for this thread */
++  luaC_freeall(L);  /* collect all objects */
++  lua_assert(g->rootgc == obj2gco(L));
++  lua_assert(g->strt.nuse == 0);
++  luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
++  luaZ_freebuffer(L, &g->buff);
++  freestack(L, L);
++  lua_assert(g->totalbytes == sizeof(LG));
++  (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0);
++}
++
++
++lua_State *luaE_newthread (lua_State *L) {
++  lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
++  luaC_link(L, obj2gco(L1), LUA_TTHREAD);
++  preinit_state(L1, G(L));
++  stack_init(L1, L);  /* init stack */
++  setobj2n(L, gt(L1), gt(L));  /* share table of globals */
++  L1->hookmask = L->hookmask;
++  L1->basehookcount = L->basehookcount;
++  L1->hook = L->hook;
++  resethookcount(L1);
++  lua_assert(iswhite(obj2gco(L1)));
++  return L1;
++}
++
++
++void luaE_freethread (lua_State *L, lua_State *L1) {
++  luaF_close(L1, L1->stack);  /* close all upvalues for this thread */
++  lua_assert(L1->openupval == NULL);
++  luai_userstatefree(L1);
++  freestack(L, L1);
++  luaM_freemem(L, fromstate(L1), state_size(lua_State));
++}
++
++
++LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
++  int i;
++  lua_State *L;
++  global_State *g;
++  void *l = (*f)(ud, NULL, 0, state_size(LG));
++  if (l == NULL) return NULL;
++  L = tostate(l);
++  g = &((LG *)L)->g;
++  L->next = NULL;
++  L->tt = LUA_TTHREAD;
++  g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
++  L->marked = luaC_white(g);
++  set2bits(L->marked, FIXEDBIT, SFIXEDBIT);
++  preinit_state(L, g);
++  g->frealloc = f;
++  g->ud = ud;
++  g->mainthread = L;
++  g->uvhead.u.l.prev = &g->uvhead;
++  g->uvhead.u.l.next = &g->uvhead;
++  g->GCthreshold = 0;  /* mark it as unfinished state */
++  g->strt.size = 0;
++  g->strt.nuse = 0;
++  g->strt.hash = NULL;
++  setnilvalue(registry(L));
++  luaZ_initbuffer(L, &g->buff);
++  g->panic = NULL;
++  g->gcstate = GCSpause;
++  g->rootgc = obj2gco(L);
++  g->sweepstrgc = 0;
++  g->sweepgc = &g->rootgc;
++  g->gray = NULL;
++  g->grayagain = NULL;
++  g->weak = NULL;
++  g->tmudata = NULL;
++  g->totalbytes = sizeof(LG);
++  g->gcpause = LUAI_GCPAUSE;
++  g->gcstepmul = LUAI_GCMUL;
++  g->gcdept = 0;
++  for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
++  if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
++    /* memory allocation error: free partial state */
++    close_state(L);
++    L = NULL;
++  }
++  else
++    luai_userstateopen(L);
++  return L;
++}
++
++
++static void callallgcTM (lua_State *L, void *ud) {
++  UNUSED(ud);
++  luaC_callGCTM(L);  /* call GC metamethods for all udata */
++}
++
++
++LUA_API void lua_close (lua_State *L) {
++  L = G(L)->mainthread;  /* only the main thread can be closed */
++  lua_lock(L);
++  luaF_close(L, L->stack);  /* close all upvalues for this thread */
++  luaC_separateudata(L, 1);  /* separate udata that have GC metamethods */
++  L->errfunc = 0;  /* no error function during GC metamethods */
++  do {  /* repeat until no more errors */
++    L->ci = L->base_ci;
++    L->base = L->top = L->ci->base;
++    L->nCcalls = L->baseCcalls = 0;
++  } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0);
++  lua_assert(G(L)->tmudata == NULL);
++  luai_userstateclose(L);
++  close_state(L);
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lstate.h
+@@ -0,0 +1,169 @@
++/*
++** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $
++** Global State
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lstate_h
++#define lstate_h
++
++#include "lua.h"
++
++#include "lobject.h"
++#include "ltm.h"
++#include "lzio.h"
++
++
++
++struct lua_longjmp;  /* defined in ldo.c */
++
++
++/* table of globals */
++#define gt(L)	(&L->l_gt)
++
++/* registry */
++#define registry(L)	(&G(L)->l_registry)
++
++
++/* extra stack space to handle TM calls and some other extras */
++#define EXTRA_STACK   5
++
++
++#define BASIC_CI_SIZE           8
++
++#define BASIC_STACK_SIZE        (2*LUA_MINSTACK)
++
++
++
++typedef struct stringtable {
++  GCObject **hash;
++  lu_int32 nuse;  /* number of elements */
++  int size;
++} stringtable;
++
++
++/*
++** informations about a call
++*/
++typedef struct CallInfo {
++  StkId base;  /* base for this function */
++  StkId func;  /* function index in the stack */
++  StkId	top;  /* top for this function */
++  const Instruction *savedpc;
++  int nresults;  /* expected number of results from this function */
++  int tailcalls;  /* number of tail calls lost under this entry */
++} CallInfo;
++
++
++
++#define curr_func(L)	(clvalue(L->ci->func))
++#define ci_func(ci)	(clvalue((ci)->func))
++#define f_isLua(ci)	(!ci_func(ci)->c.isC)
++#define isLua(ci)	(ttisfunction((ci)->func) && f_isLua(ci))
++
++
++/*
++** `global state', shared by all threads of this state
++*/
++typedef struct global_State {
++  stringtable strt;  /* hash table for strings */
++  lua_Alloc frealloc;  /* function to reallocate memory */
++  void *ud;         /* auxiliary data to `frealloc' */
++  lu_byte currentwhite;
++  lu_byte gcstate;  /* state of garbage collector */
++  int sweepstrgc;  /* position of sweep in `strt' */
++  GCObject *rootgc;  /* list of all collectable objects */
++  GCObject **sweepgc;  /* position of sweep in `rootgc' */
++  GCObject *gray;  /* list of gray objects */
++  GCObject *grayagain;  /* list of objects to be traversed atomically */
++  GCObject *weak;  /* list of weak tables (to be cleared) */
++  GCObject *tmudata;  /* last element of list of userdata to be GC */
++  Mbuffer buff;  /* temporary buffer for string concatentation */
++  lu_mem GCthreshold;
++  lu_mem totalbytes;  /* number of bytes currently allocated */
++  lu_mem estimate;  /* an estimate of number of bytes actually in use */
++  lu_mem gcdept;  /* how much GC is `behind schedule' */
++  int gcpause;  /* size of pause between successive GCs */
++  int gcstepmul;  /* GC `granularity' */
++  lua_CFunction panic;  /* to be called in unprotected errors */
++  TValue l_registry;
++  struct lua_State *mainthread;
++  UpVal uvhead;  /* head of double-linked list of all open upvalues */
++  struct Table *mt[NUM_TAGS];  /* metatables for basic types */
++  TString *tmname[TM_N];  /* array with tag-method names */
++} global_State;
++
++
++/*
++** `per thread' state
++*/
++struct lua_State {
++  CommonHeader;
++  lu_byte status;
++  StkId top;  /* first free slot in the stack */
++  StkId base;  /* base of current function */
++  global_State *l_G;
++  CallInfo *ci;  /* call info for current function */
++  const Instruction *savedpc;  /* `savedpc' of current function */
++  StkId stack_last;  /* last free slot in the stack */
++  StkId stack;  /* stack base */
++  CallInfo *end_ci;  /* points after end of ci array*/
++  CallInfo *base_ci;  /* array of CallInfo's */
++  int stacksize;
++  int size_ci;  /* size of array `base_ci' */
++  unsigned short nCcalls;  /* number of nested C calls */
++  unsigned short baseCcalls;  /* nested C calls when resuming coroutine */
++  lu_byte hookmask;
++  lu_byte allowhook;
++  int basehookcount;
++  int hookcount;
++  lua_Hook hook;
++  TValue l_gt;  /* table of globals */
++  TValue env;  /* temporary place for environments */
++  GCObject *openupval;  /* list of open upvalues in this stack */
++  GCObject *gclist;
++  struct lua_longjmp *errorJmp;  /* current error recover point */
++  ptrdiff_t errfunc;  /* current error handling function (stack index) */
++};
++
++
++#define G(L)	(L->l_G)
++
++
++/*
++** Union of all collectable objects
++*/
++union GCObject {
++  GCheader gch;
++  union TString ts;
++  union Udata u;
++  union Closure cl;
++  struct Table h;
++  struct Proto p;
++  struct UpVal uv;
++  struct lua_State th;  /* thread */
++};
++
++
++/* macros to convert a GCObject into a specific value */
++#define rawgco2ts(o)	check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
++#define gco2ts(o)	(&rawgco2ts(o)->tsv)
++#define rawgco2u(o)	check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
++#define gco2u(o)	(&rawgco2u(o)->uv)
++#define gco2cl(o)	check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
++#define gco2h(o)	check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
++#define gco2p(o)	check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
++#define gco2uv(o)	check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
++#define ngcotouv(o) \
++	check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv))
++#define gco2th(o)	check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
++
++/* macro to convert any Lua object into a GCObject */
++#define obj2gco(v)	(cast(GCObject *, (v)))
++
++
++LUAI_FUNC lua_State *luaE_newthread (lua_State *L);
++LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
++
++#endif
++
+--- /dev/null
++++ b/extensions/LUA/lua/lstring.c
+@@ -0,0 +1,110 @@
++/*
++** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
++** String table (keeps all strings handled by Lua)
++** See Copyright Notice in lua.h
++*/
++
++#include <string.h>
++
++#define lstring_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++#include "lstring.h"
++
++
++
++void luaS_resize (lua_State *L, int newsize) {
++  GCObject **newhash;
++  stringtable *tb;
++  int i;
++  if (G(L)->gcstate == GCSsweepstring)
++    return;  /* cannot resize during GC traverse */
++  newhash = luaM_newvector(L, newsize, GCObject *);
++  tb = &G(L)->strt;
++  for (i=0; i<newsize; i++) newhash[i] = NULL;
++  /* rehash */
++  for (i=0; i<tb->size; i++) {
++    GCObject *p = tb->hash[i];
++    while (p) {  /* for each node in the list */
++      GCObject *next = p->gch.next;  /* save next */
++      unsigned int h = gco2ts(p)->hash;
++      int h1 = lmod(h, newsize);  /* new position */
++      lua_assert(cast_int(h%newsize) == lmod(h, newsize));
++      p->gch.next = newhash[h1];  /* chain it */
++      newhash[h1] = p;
++      p = next;
++    }
++  }
++  luaM_freearray(L, tb->hash, tb->size, TString *);
++  tb->size = newsize;
++  tb->hash = newhash;
++}
++
++
++static TString *newlstr (lua_State *L, const char *str, size_t l,
++                                       unsigned int h) {
++  TString *ts;
++  stringtable *tb;
++  if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
++    luaM_toobig(L);
++  ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
++  ts->tsv.len = l;
++  ts->tsv.hash = h;
++  ts->tsv.marked = luaC_white(G(L));
++  ts->tsv.tt = LUA_TSTRING;
++  ts->tsv.reserved = 0;
++  memcpy(ts+1, str, l*sizeof(char));
++  ((char *)(ts+1))[l] = '\0';  /* ending 0 */
++  tb = &G(L)->strt;
++  h = lmod(h, tb->size);
++  ts->tsv.next = tb->hash[h];  /* chain new entry */
++  tb->hash[h] = obj2gco(ts);
++  tb->nuse++;
++  if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
++    luaS_resize(L, tb->size*2);  /* too crowded */
++  return ts;
++}
++
++
++TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
++  GCObject *o;
++  unsigned int h = cast(unsigned int, l);  /* seed */
++  size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */
++  size_t l1;
++  for (l1=l; l1>=step; l1-=step)  /* compute hash */
++    h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
++  for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
++       o != NULL;
++       o = o->gch.next) {
++    TString *ts = rawgco2ts(o);
++    if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
++      /* string may be dead */
++      if (isdead(G(L), o)) changewhite(o);
++      return ts;
++    }
++  }
++  return newlstr(L, str, l, h);  /* not found */
++}
++
++
++Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
++  Udata *u;
++  if (s > MAX_SIZET - sizeof(Udata))
++    luaM_toobig(L);
++  u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata)));
++  u->uv.marked = luaC_white(G(L));  /* is not finalized */
++  u->uv.tt = LUA_TUSERDATA;
++  u->uv.len = s;
++  u->uv.metatable = NULL;
++  u->uv.env = e;
++  /* chain it on udata list (after main thread) */
++  u->uv.next = G(L)->mainthread->next;
++  G(L)->mainthread->next = obj2gco(u);
++  return u;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lstring.h
+@@ -0,0 +1,31 @@
++/*
++** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $
++** String table (keep all strings handled by Lua)
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lstring_h
++#define lstring_h
++
++
++#include "lgc.h"
++#include "lobject.h"
++#include "lstate.h"
++
++
++#define sizestring(s)	(sizeof(union TString)+((s)->len+1)*sizeof(char))
++
++#define sizeudata(u)	(sizeof(union Udata)+(u)->len)
++
++#define luaS_new(L, s)	(luaS_newlstr(L, s, strlen(s)))
++#define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \
++                                 (sizeof(s)/sizeof(char))-1))
++
++#define luaS_fix(s)	l_setbit((s)->tsv.marked, FIXEDBIT)
++
++LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
++LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
++LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lstrlib.c
+@@ -0,0 +1,883 @@
++/*
++** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $
++** Standard library for string operations and pattern-matching
++** See Copyright Notice in lua.h
++*/
++
++
++#include <ctype.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#define lstrlib_c
++#define LUA_LIB
++
++#include "lua.h"
++
++#include "lauxlib.h"
++#include "lualib.h"
++
++
++/* macro to `unsign' a character */
++#define uchar(c)        ((unsigned char)(c))
++
++
++
++static int str_len (lua_State *L) {
++  size_t l;
++  luaL_checklstring(L, 1, &l);
++  lua_pushinteger(L, l);
++  return 1;
++}
++
++
++static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
++  /* relative string position: negative means back from end */
++  if (pos < 0) pos += (ptrdiff_t)len + 1;
++  return (pos >= 0) ? pos : 0;
++}
++
++
++static int str_sub (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
++  ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
++  if (start < 1) start = 1;
++  if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
++  if (start <= end)
++    lua_pushlstring(L, s+start-1, end-start+1);
++  else lua_pushliteral(L, "");
++  return 1;
++}
++
++
++static int str_reverse (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_reverse: cannot allocate memory");
++  luaL_buffinit(L, b);
++  while (l--) luaL_addchar(b, s[l]);
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++static int str_lower (lua_State *L) {
++  size_t l;
++  size_t i;
++  const char *s = luaL_checklstring(L, 1, &l);
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_lower: cannot allocate memory");
++  luaL_buffinit(L, b);
++  for (i=0; i<l; i++)
++    luaL_addchar(b, tolower(uchar(s[i])));
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++static int str_upper (lua_State *L) {
++  size_t l;
++  size_t i;
++  const char *s = luaL_checklstring(L, 1, &l);
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_upper: cannot allocate memory");
++  luaL_buffinit(L, b);
++  for (i=0; i<l; i++)
++    luaL_addchar(b, toupper(uchar(s[i])));
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++static int str_rep (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  int n = luaL_checkint(L, 2);
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_rep: cannot allocate memory");
++  luaL_buffinit(L, b);
++  while (n-- > 0)
++    luaL_addlstring(b, s, l);
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++static int str_byte (lua_State *L) {
++  size_t l;
++  const char *s = luaL_checklstring(L, 1, &l);
++  ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
++  ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
++  int n, i;
++  if (posi <= 0) posi = 1;
++  if ((size_t)pose > l) pose = l;
++  if (posi > pose) return 0;  /* empty interval; return no values */
++  n = (int)(pose -  posi + 1);
++  if (posi + n <= pose)  /* overflow? */
++    luaL_error(L, "string slice too long");
++  luaL_checkstack(L, n, "string slice too long");
++  for (i=0; i<n; i++)
++    lua_pushinteger(L, uchar(s[posi+i-1]));
++  return n;
++}
++
++
++static int str_char (lua_State *L) {
++  int n = lua_gettop(L);  /* number of arguments */
++  int i;
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_char: cannot allocate memory");
++  luaL_buffinit(L, b);
++  for (i=1; i<=n; i++) {
++    int c = luaL_checkint(L, i);
++    luaL_argcheck(L, uchar(c) == c, i, "invalid value");
++    luaL_addchar(b, uchar(c));
++  }
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++static int writer (lua_State *L, const void* b, size_t size, void* B) {
++  (void)L;
++  luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
++  return 0;
++}
++
++
++static int str_dump (lua_State *L) {
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_dump: cannot allocate memory");
++  luaL_checktype(L, 1, LUA_TFUNCTION);
++  lua_settop(L, 1);
++  luaL_buffinit(L,b);
++  if (lua_dump(L, writer, b) != 0){
++	  kfree(b);
++	  luaL_error(L, "unable to dump given function");
++  }
++
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++
++/*
++** {======================================================
++** PATTERN MATCHING
++** =======================================================
++*/
++
++
++#define CAP_UNFINISHED	(-1)
++#define CAP_POSITION	(-2)
++
++typedef struct MatchState {
++  const char *src_init;  /* init of source string */
++  const char *src_end;  /* end (`\0') of source string */
++  lua_State *L;
++  int level;  /* total number of captures (finished or unfinished) */
++  struct {
++    const char *init;
++    ptrdiff_t len;
++  } capture[LUA_MAXCAPTURES];
++} MatchState;
++
++
++#define L_ESC		'%'
++#define SPECIALS	"^$*+?.([%-"
++
++
++static int check_capture (MatchState *ms, int l) {
++  l -= '1';
++  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
++    return luaL_error(ms->L, "invalid capture index");
++  return l;
++}
++
++
++static int capture_to_close (MatchState *ms) {
++  int level = ms->level;
++  for (level--; level>=0; level--)
++    if (ms->capture[level].len == CAP_UNFINISHED) return level;
++  return luaL_error(ms->L, "invalid pattern capture");
++}
++
++
++static const char *classend (MatchState *ms, const char *p) {
++  switch (*p++) {
++    case L_ESC: {
++      if (*p == '\0')
++        luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
++      return p+1;
++    }
++    case '[': {
++      if (*p == '^') p++;
++      do {  /* look for a `]' */
++        if (*p == '\0')
++          luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
++        if (*(p++) == L_ESC && *p != '\0')
++          p++;  /* skip escapes (e.g. `%]') */
++      } while (*p != ']');
++      return p+1;
++    }
++    default: {
++      return p;
++    }
++  }
++}
++
++
++static int match_class (int c, int cl) {
++  int res;
++  switch (tolower(cl)) {
++    case 'a' : res = isalpha(c); break;
++    case 'c' : res = iscntrl(c); break;
++    case 'd' : res = isdigit(c); break;
++    case 'l' : res = islower(c); break;
++    case 'p' : res = ispunct(c); break;
++    case 's' : res = isspace(c); break;
++    case 'u' : res = isupper(c); break;
++    case 'w' : res = isalnum(c); break;
++    case 'x' : res = isxdigit(c); break;
++    case 'z' : res = (c == 0); break;
++    default: return (cl == c);
++  }
++  return (islower(cl) ? res : !res);
++}
++
++
++static int matchbracketclass (int c, const char *p, const char *ec) {
++  int sig = 1;
++  if (*(p+1) == '^') {
++    sig = 0;
++    p++;  /* skip the `^' */
++  }
++  while (++p < ec) {
++    if (*p == L_ESC) {
++      p++;
++      if (match_class(c, uchar(*p)))
++        return sig;
++    }
++    else if ((*(p+1) == '-') && (p+2 < ec)) {
++      p+=2;
++      if (uchar(*(p-2)) <= c && c <= uchar(*p))
++        return sig;
++    }
++    else if (uchar(*p) == c) return sig;
++  }
++  return !sig;
++}
++
++
++static int singlematch (int c, const char *p, const char *ep) {
++  switch (*p) {
++    case '.': return 1;  /* matches any char */
++    case L_ESC: return match_class(c, uchar(*(p+1)));
++    case '[': return matchbracketclass(c, p, ep-1);
++    default:  return (uchar(*p) == c);
++  }
++}
++
++
++static const char *match (MatchState *ms, const char *s, const char *p);
++
++
++static const char *matchbalance (MatchState *ms, const char *s,
++                                   const char *p) {
++  if (*p == 0 || *(p+1) == 0)
++    luaL_error(ms->L, "unbalanced pattern");
++  if (*s != *p) return NULL;
++  else {
++    int b = *p;
++    int e = *(p+1);
++    int cont = 1;
++    while (++s < ms->src_end) {
++      if (*s == e) {
++        if (--cont == 0) return s+1;
++      }
++      else if (*s == b) cont++;
++    }
++  }
++  return NULL;  /* string ends out of balance */
++}
++
++
++static const char *max_expand (MatchState *ms, const char *s,
++                                 const char *p, const char *ep) {
++  ptrdiff_t i = 0;  /* counts maximum expand for item */
++  while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
++    i++;
++  /* keeps trying to match with the maximum repetitions */
++  while (i>=0) {
++    const char *res = match(ms, (s+i), ep+1);
++    if (res) return res;
++    i--;  /* else didn't match; reduce 1 repetition to try again */
++  }
++  return NULL;
++}
++
++
++static const char *min_expand (MatchState *ms, const char *s,
++                                 const char *p, const char *ep) {
++  for (;;) {
++    const char *res = match(ms, s, ep+1);
++    if (res != NULL)
++      return res;
++    else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
++      s++;  /* try with one more repetition */
++    else return NULL;
++  }
++}
++
++
++static const char *start_capture (MatchState *ms, const char *s,
++                                    const char *p, int what) {
++  const char *res;
++  int level = ms->level;
++  if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
++  ms->capture[level].init = s;
++  ms->capture[level].len = what;
++  ms->level = level+1;
++  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
++    ms->level--;  /* undo capture */
++  return res;
++}
++
++
++static const char *end_capture (MatchState *ms, const char *s,
++                                  const char *p) {
++  int l = capture_to_close(ms);
++  const char *res;
++  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
++  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
++    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
++  return res;
++}
++
++
++static const char *match_capture (MatchState *ms, const char *s, int l) {
++  size_t len;
++  l = check_capture(ms, l);
++  len = ms->capture[l].len;
++  if ((size_t)(ms->src_end-s) >= len &&
++      memcmp(ms->capture[l].init, s, len) == 0)
++    return s+len;
++  else return NULL;
++}
++
++
++static const char *match (MatchState *ms, const char *s, const char *p) {
++  init: /* using goto's to optimize tail recursion */
++  switch (*p) {
++    case '(': {  /* start capture */
++      if (*(p+1) == ')')  /* position capture? */
++        return start_capture(ms, s, p+2, CAP_POSITION);
++      else
++        return start_capture(ms, s, p+1, CAP_UNFINISHED);
++    }
++    case ')': {  /* end capture */
++      return end_capture(ms, s, p+1);
++    }
++    case L_ESC: {
++      switch (*(p+1)) {
++        case 'b': {  /* balanced string? */
++          s = matchbalance(ms, s, p+2);
++          if (s == NULL) return NULL;
++          p+=4; goto init;  /* else return match(ms, s, p+4); */
++        }
++        case 'f': {  /* frontier? */
++          const char *ep; char previous;
++          p += 2;
++          if (*p != '[')
++            luaL_error(ms->L, "missing " LUA_QL("[") " after "
++                               LUA_QL("%%f") " in pattern");
++          ep = classend(ms, p);  /* points to what is next */
++          previous = (s == ms->src_init) ? '\0' : *(s-1);
++          if (matchbracketclass(uchar(previous), p, ep-1) ||
++             !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
++          p=ep; goto init;  /* else return match(ms, s, ep); */
++        }
++        default: {
++          if (isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */
++            s = match_capture(ms, s, uchar(*(p+1)));
++            if (s == NULL) return NULL;
++            p+=2; goto init;  /* else return match(ms, s, p+2) */
++          }
++          goto dflt;  /* case default */
++        }
++      }
++    }
++    case '\0': {  /* end of pattern */
++      return s;  /* match succeeded */
++    }
++    case '$': {
++      if (*(p+1) == '\0')  /* is the `$' the last char in pattern? */
++        return (s == ms->src_end) ? s : NULL;  /* check end of string */
++      else goto dflt;
++    }
++    default: dflt: {  /* it is a pattern item */
++      const char *ep = classend(ms, p);  /* points to what is next */
++      int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
++      switch (*ep) {
++        case '?': {  /* optional */
++          const char *res;
++          if (m && ((res=match(ms, s+1, ep+1)) != NULL))
++            return res;
++          p=ep+1; goto init;  /* else return match(ms, s, ep+1); */
++        }
++        case '*': {  /* 0 or more repetitions */
++          return max_expand(ms, s, p, ep);
++        }
++        case '+': {  /* 1 or more repetitions */
++          return (m ? max_expand(ms, s+1, p, ep) : NULL);
++        }
++        case '-': {  /* 0 or more repetitions (minimum) */
++          return min_expand(ms, s, p, ep);
++        }
++        default: {
++          if (!m) return NULL;
++          s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */
++        }
++      }
++    }
++  }
++}
++
++
++
++static const char *lmemfind (const char *s1, size_t l1,
++                               const char *s2, size_t l2) {
++  if (l2 == 0) return s1;  /* empty strings are everywhere */
++  else if (l2 > l1) return NULL;  /* avoids a negative `l1' */
++  else {
++    const char *init;  /* to search for a `*s2' inside `s1' */
++    l2--;  /* 1st char will be checked by `memchr' */
++    l1 = l1-l2;  /* `s2' cannot be found after that */
++    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
++      init++;   /* 1st char is already checked */
++      if (memcmp(init, s2+1, l2) == 0)
++        return init-1;
++      else {  /* correct `l1' and `s1' to try again */
++        l1 -= init-s1;
++        s1 = init;
++      }
++    }
++    return NULL;  /* not found */
++  }
++}
++
++
++static void push_onecapture (MatchState *ms, int i, const char *s,
++                                                    const char *e) {
++  if (i >= ms->level) {
++    if (i == 0)  /* ms->level == 0, too */
++      lua_pushlstring(ms->L, s, e - s);  /* add whole match */
++    else
++      luaL_error(ms->L, "invalid capture index");
++  }
++  else {
++    ptrdiff_t l = ms->capture[i].len;
++    if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
++    if (l == CAP_POSITION)
++      lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
++    else
++      lua_pushlstring(ms->L, ms->capture[i].init, l);
++  }
++}
++
++
++static int push_captures (MatchState *ms, const char *s, const char *e) {
++  int i;
++  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
++  luaL_checkstack(ms->L, nlevels, "too many captures");
++  for (i = 0; i < nlevels; i++)
++    push_onecapture(ms, i, s, e);
++  return nlevels;  /* number of strings pushed */
++}
++
++
++static int str_find_aux (lua_State *L, int find) {
++  size_t l1, l2;
++  const char *s = luaL_checklstring(L, 1, &l1);
++  const char *p = luaL_checklstring(L, 2, &l2);
++  ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
++  if (init < 0) init = 0;
++  else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
++  if (find && (lua_toboolean(L, 4) ||  /* explicit request? */
++      strpbrk(p, SPECIALS) == NULL)) {  /* or no special characters? */
++    /* do a plain search */
++    const char *s2 = lmemfind(s+init, l1-init, p, l2);
++    if (s2) {
++      lua_pushinteger(L, s2-s+1);
++      lua_pushinteger(L, s2-s+l2);
++      return 2;
++    }
++  }
++  else {
++    MatchState ms;
++    int anchor = (*p == '^') ? (p++, 1) : 0;
++    const char *s1=s+init;
++    ms.L = L;
++    ms.src_init = s;
++    ms.src_end = s+l1;
++    do {
++      const char *res;
++      ms.level = 0;
++      if ((res=match(&ms, s1, p)) != NULL) {
++        if (find) {
++          lua_pushinteger(L, s1-s+1);  /* start */
++          lua_pushinteger(L, res-s);   /* end */
++          return push_captures(&ms, NULL, 0) + 2;
++        }
++        else
++          return push_captures(&ms, s1, res);
++      }
++    } while (s1++ < ms.src_end && !anchor);
++  }
++  lua_pushnil(L);  /* not found */
++  return 1;
++}
++
++
++static int str_find (lua_State *L) {
++  return str_find_aux(L, 1);
++}
++
++
++static int str_match (lua_State *L) {
++  return str_find_aux(L, 0);
++}
++
++
++static int gmatch_aux (lua_State *L) {
++  MatchState ms;
++  size_t ls;
++  const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
++  const char *p = lua_tostring(L, lua_upvalueindex(2));
++  const char *src;
++  ms.L = L;
++  ms.src_init = s;
++  ms.src_end = s+ls;
++  for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
++       src <= ms.src_end;
++       src++) {
++    const char *e;
++    ms.level = 0;
++    if ((e = match(&ms, src, p)) != NULL) {
++      lua_Integer newstart = e-s;
++      if (e == src) newstart++;  /* empty match? go at least one position */
++      lua_pushinteger(L, newstart);
++      lua_replace(L, lua_upvalueindex(3));
++      return push_captures(&ms, src, e);
++    }
++  }
++  return 0;  /* not found */
++}
++
++
++static int gmatch (lua_State *L) {
++  luaL_checkstring(L, 1);
++  luaL_checkstring(L, 2);
++  lua_settop(L, 2);
++  lua_pushinteger(L, 0);
++  lua_pushcclosure(L, gmatch_aux, 3);
++  return 1;
++}
++
++
++static int gfind_nodef (lua_State *L) {
++  return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
++                       LUA_QL("string.gmatch"));
++}
++
++
++static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
++                                                   const char *e) {
++  size_t l, i;
++  const char *news = lua_tolstring(ms->L, 3, &l);
++  for (i = 0; i < l; i++) {
++    if (news[i] != L_ESC)
++      luaL_addchar(b, news[i]);
++    else {
++      i++;  /* skip ESC */
++      if (!isdigit(uchar(news[i])))
++        luaL_addchar(b, news[i]);
++      else if (news[i] == '0')
++          luaL_addlstring(b, s, e - s);
++      else {
++        push_onecapture(ms, news[i] - '1', s, e);
++        luaL_addvalue(b);  /* add capture to accumulated result */
++      }
++    }
++  }
++}
++
++
++static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
++                                                       const char *e) {
++  lua_State *L = ms->L;
++  switch (lua_type(L, 3)) {
++    case LUA_TNUMBER:
++    case LUA_TSTRING: {
++      add_s(ms, b, s, e);
++      return;
++    }
++    case LUA_TFUNCTION: {
++      int n;
++      lua_pushvalue(L, 3);
++      n = push_captures(ms, s, e);
++      lua_call(L, n, 1);
++      break;
++    }
++    case LUA_TTABLE: {
++      push_onecapture(ms, 0, s, e);
++      lua_gettable(L, 3);
++      break;
++    }
++  }
++  if (!lua_toboolean(L, -1)) {  /* nil or false? */
++    lua_pop(L, 1);
++    lua_pushlstring(L, s, e - s);  /* keep original text */
++  }
++  else if (!lua_isstring(L, -1))
++    luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
++  luaL_addvalue(b);  /* add result to accumulator */
++}
++
++
++static int str_gsub (lua_State *L) {
++  size_t srcl;
++  const char *src = luaL_checklstring(L, 1, &srcl);
++  const char *p = luaL_checkstring(L, 2);
++  int  tr = lua_type(L, 3);
++  int max_s = luaL_optint(L, 4, srcl+1);
++  int anchor = (*p == '^') ? (p++, 1) : 0;
++  int n = 0;
++  MatchState ms;
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_gsub: cannot allocate memory");
++  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
++                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
++                      "string/function/table expected");
++  luaL_buffinit(L, b);
++  ms.L = L;
++  ms.src_init = src;
++  ms.src_end = src+srcl;
++  while (n < max_s) {
++    const char *e;
++    ms.level = 0;
++    e = match(&ms, src, p);
++    if (e) {
++      n++;
++      add_value(&ms, b, src, e);
++    }
++    if (e && e>src) /* non empty match? */
++      src = e;  /* skip it */
++    else if (src < ms.src_end)
++      luaL_addchar(b, *src++);
++    else break;
++    if (anchor) break;
++  }
++  luaL_addlstring(b, src, ms.src_end-src);
++  luaL_pushresult(b);
++  lua_pushinteger(L, n);  /* number of substitutions */
++  kfree(b);
++  return 2;
++}
++
++/* }====================================================== */
++
++
++/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
++#define MAX_ITEM	512
++/* valid flags in a format specification */
++#define FLAGS	"-+ #0"
++/*
++** maximum size of each format specification (such as '%-099.99d')
++** (+10 accounts for %99.99x plus margin of error)
++*/
++#define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
++
++
++static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
++  size_t l;
++  const char *s = luaL_checklstring(L, arg, &l);
++  luaL_addchar(b, '"');
++  while (l--) {
++    switch (*s) {
++      case '"': case '\\': case '\n': {
++        luaL_addchar(b, '\\');
++        luaL_addchar(b, *s);
++        break;
++      }
++      case '\r': {
++        luaL_addlstring(b, "\\r", 2);
++        break;
++      }
++      case '\0': {
++        luaL_addlstring(b, "\\000", 4);
++        break;
++      }
++      default: {
++        luaL_addchar(b, *s);
++        break;
++      }
++    }
++    s++;
++  }
++  luaL_addchar(b, '"');
++}
++
++static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
++  const char *p = strfrmt;
++  while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
++  if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
++    luaL_error(L, "invalid format (repeated flags)");
++  if (isdigit(uchar(*p))) p++;  /* skip width */
++  if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
++  if (*p == '.') {
++    p++;
++    if (isdigit(uchar(*p))) p++;  /* skip precision */
++    if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
++  }
++  if (isdigit(uchar(*p)))
++    luaL_error(L, "invalid format (width or precision too long)");
++  *(form++) = '%';
++  strncpy(form, strfrmt, p - strfrmt + 1);
++  form += p - strfrmt + 1;
++  *form = '\0';
++  return p;
++}
++
++
++static void addintlen (char *form) {
++  size_t l = strlen(form);
++  char spec = form[l - 1];
++  strcpy(form + l - 1, LUA_INTFRMLEN);
++  form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
++  form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
++}
++
++
++static int str_format (lua_State *L) {
++  int arg = 1;
++  size_t sfl;
++  const char *strfrmt = luaL_checklstring(L, arg, &sfl);
++  const char *strfrmt_end = strfrmt+sfl;
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "str_format: cannot allocate memory");
++  luaL_buffinit(L, b);
++  while (strfrmt < strfrmt_end) {
++    if (*strfrmt != L_ESC)
++      luaL_addchar(b, *strfrmt++);
++    else if (*++strfrmt == L_ESC)
++      luaL_addchar(b, *strfrmt++);  /* %% */
++    else { /* format item */
++      char form[MAX_FORMAT];  /* to store the format (`%...') */
++      char buff[MAX_ITEM];  /* to store the formatted item */
++      arg++;
++      strfrmt = scanformat(L, strfrmt, form);
++      switch (*strfrmt++) {
++        case 'c': {
++          sprintf(buff, form, (int)luaL_checknumber(L, arg));
++          break;
++        }
++        case 'd':  case 'i': {
++          addintlen(form);
++          sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
++          break;
++        }
++        case 'o':  case 'u':  case 'x':  case 'X': {
++          addintlen(form);
++          sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
++          break;
++        }
++        case 'q': {
++          addquoted(L, b, arg);
++          continue;  /* skip the 'addsize' at the end */
++        }
++        case 's': {
++          size_t l;
++          const char *s = luaL_checklstring(L, arg, &l);
++          if (!strchr(form, '.') && l >= 100) {
++            /* no precision and string is too long to be formatted;
++               keep original string */
++            lua_pushvalue(L, arg);
++            luaL_addvalue(b);
++            continue;  /* skip the `addsize' at the end */
++          }
++          else {
++            sprintf(buff, form, s);
++            break;
++          }
++        }
++        default: {  /* also treat cases `pnLlh' */
++          kfree(b);
++          return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
++                               LUA_QL("format"), *(strfrmt - 1));
++        }
++      }
++      luaL_addlstring(b, buff, strlen(buff));
++    }
++  }
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++static const luaL_Reg strlib[] = {
++  {"byte", str_byte},
++  {"char", str_char},
++  {"dump", str_dump},
++  {"find", str_find},
++  {"format", str_format},
++  {"gfind", gfind_nodef},
++  {"gmatch", gmatch},
++  {"gsub", str_gsub},
++  {"len", str_len},
++  {"lower", str_lower},
++  {"match", str_match},
++  {"rep", str_rep},
++  {"reverse", str_reverse},
++  {"sub", str_sub},
++  {"upper", str_upper},
++  {NULL, NULL}
++};
++
++
++static void createmetatable (lua_State *L) {
++  lua_createtable(L, 0, 1);  /* create metatable for strings */
++  lua_pushliteral(L, "");  /* dummy string */
++  lua_pushvalue(L, -2);
++  lua_setmetatable(L, -2);  /* set string metatable */
++  lua_pop(L, 1);  /* pop dummy string */
++  lua_pushvalue(L, -2);  /* string library... */
++  lua_setfield(L, -2, "__index");  /* ...is the __index metamethod */
++  lua_pop(L, 1);  /* pop metatable */
++}
++
++
++/*
++** Open string library
++*/
++LUALIB_API int luaopen_string (lua_State *L) {
++  luaL_register(L, LUA_STRLIBNAME, strlib);
++#if defined(LUA_COMPAT_GFIND)
++  lua_getfield(L, -1, "gmatch");
++  lua_setfield(L, -2, "gfind");
++#endif
++  createmetatable(L);
++  return 1;
++}
+--- /dev/null
++++ b/extensions/LUA/lua/ltable.c
+@@ -0,0 +1,588 @@
++/*
++** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $
++** Lua tables (hash)
++** See Copyright Notice in lua.h
++*/
++
++
++/*
++** Implementation of tables (aka arrays, objects, or hash tables).
++** Tables keep its elements in two parts: an array part and a hash part.
++** Non-negative integer keys are all candidates to be kept in the array
++** part. The actual size of the array is the largest `n' such that at
++** least half the slots between 0 and n are in use.
++** Hash uses a mix of chained scatter table with Brent's variation.
++** A main invariant of these tables is that, if an element is not
++** in its main position (i.e. the `original' position that its hash gives
++** to it), then the colliding element is in its own main position.
++** Hence even when the load factor reaches 100%, performance remains good.
++*/
++
++#include <math.h>
++#include <string.h>
++
++#define ltable_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lgc.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstate.h"
++#include "ltable.h"
++
++
++/*
++** max size of array part is 2^MAXBITS
++*/
++#if LUAI_BITSINT > 26
++#define MAXBITS		26
++#else
++#define MAXBITS		(LUAI_BITSINT-2)
++#endif
++
++#define MAXASIZE	(1 << MAXBITS)
++
++
++#define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t))))
++  
++#define hashstr(t,str)  hashpow2(t, (str)->tsv.hash)
++#define hashboolean(t,p)        hashpow2(t, p)
++
++
++/*
++** for some types, it is better to avoid modulus by power of 2, as
++** they tend to have many 2 factors.
++*/
++#define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))
++
++
++#define hashpointer(t,p)	hashmod(t, IntPoint(p))
++
++
++/*
++** number of ints inside a lua_Number
++*/
++#define numints		cast_int(sizeof(lua_Number)/sizeof(int))
++
++
++
++#define dummynode		(&dummynode_)
++
++static const Node dummynode_ = {
++  {{NULL}, LUA_TNIL},  /* value */
++  {{{NULL}, LUA_TNIL, NULL}}  /* key */
++};
++
++
++/*
++** hash for lua_Numbers
++*/
++static Node *hashnum (const Table *t, lua_Number n) {
++  unsigned int a[numints];
++  int i;
++  if (luai_numeq(n, 0))  /* avoid problems with -0 */
++    return gnode(t, 0);
++  memcpy(a, &n, sizeof(a));
++  for (i = 1; i < numints; i++) a[0] += a[i];
++  return hashmod(t, a[0]);
++}
++
++
++
++/*
++** returns the `main' position of an element in a table (that is, the index
++** of its hash value)
++*/
++static Node *mainposition (const Table *t, const TValue *key) {
++  switch (ttype(key)) {
++    case LUA_TNUMBER:
++      return hashnum(t, nvalue(key));
++    case LUA_TSTRING:
++      return hashstr(t, rawtsvalue(key));
++    case LUA_TBOOLEAN:
++      return hashboolean(t, bvalue(key));
++    case LUA_TLIGHTUSERDATA:
++      return hashpointer(t, pvalue(key));
++    default:
++      return hashpointer(t, gcvalue(key));
++  }
++}
++
++
++/*
++** returns the index for `key' if `key' is an appropriate key to live in
++** the array part of the table, -1 otherwise.
++*/
++static int arrayindex (const TValue *key) {
++  if (ttisnumber(key)) {
++    lua_Number n = nvalue(key);
++    int k;
++    lua_number2int(k, n);
++    if (luai_numeq(cast_num(k), n))
++      return k;
++  }
++  return -1;  /* `key' did not match some condition */
++}
++
++
++/*
++** returns the index of a `key' for table traversals. First goes all
++** elements in the array part, then elements in the hash part. The
++** beginning of a traversal is signalled by -1.
++*/
++static int findindex (lua_State *L, Table *t, StkId key) {
++  int i;
++  if (ttisnil(key)) return -1;  /* first iteration */
++  i = arrayindex(key);
++  if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */
++    return i-1;  /* yes; that's the index (corrected to C) */
++  else {
++    Node *n = mainposition(t, key);
++    do {  /* check whether `key' is somewhere in the chain */
++      /* key may be dead already, but it is ok to use it in `next' */
++      if (luaO_rawequalObj(key2tval(n), key) ||
++            (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) &&
++             gcvalue(gkey(n)) == gcvalue(key))) {
++        i = cast_int(n - gnode(t, 0));  /* key index in hash table */
++        /* hash elements are numbered after array ones */
++        return i + t->sizearray;
++      }
++      else n = gnext(n);
++    } while (n);
++    luaG_runerror(L, "invalid key to " LUA_QL("next"));  /* key not found */
++    return 0;  /* to avoid warnings */
++  }
++}
++
++
++int luaH_next (lua_State *L, Table *t, StkId key) {
++  int i = findindex(L, t, key);  /* find original element */
++  for (i++; i < t->sizearray; i++) {  /* try first array part */
++    if (!ttisnil(&t->array[i])) {  /* a non-nil value? */
++      setnvalue(key, cast_num(i+1));
++      setobj2s(L, key+1, &t->array[i]);
++      return 1;
++    }
++  }
++  for (i -= t->sizearray; i < sizenode(t); i++) {  /* then hash part */
++    if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */
++      setobj2s(L, key, key2tval(gnode(t, i)));
++      setobj2s(L, key+1, gval(gnode(t, i)));
++      return 1;
++    }
++  }
++  return 0;  /* no more elements */
++}
++
++
++/*
++** {=============================================================
++** Rehash
++** ==============================================================
++*/
++
++
++static int computesizes (int nums[], int *narray) {
++  int i;
++  int twotoi;  /* 2^i */
++  int a = 0;  /* number of elements smaller than 2^i */
++  int na = 0;  /* number of elements to go to array part */
++  int n = 0;  /* optimal size for array part */
++  for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
++    if (nums[i] > 0) {
++      a += nums[i];
++      if (a > twotoi/2) {  /* more than half elements present? */
++        n = twotoi;  /* optimal size (till now) */
++        na = a;  /* all elements smaller than n will go to array part */
++      }
++    }
++    if (a == *narray) break;  /* all elements already counted */
++  }
++  *narray = n;
++  lua_assert(*narray/2 <= na && na <= *narray);
++  return na;
++}
++
++
++static int countint (const TValue *key, int *nums) {
++  int k = arrayindex(key);
++  if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */
++    nums[ceillog2(k)]++;  /* count as such */
++    return 1;
++  }
++  else
++    return 0;
++}
++
++
++static int numusearray (const Table *t, int *nums) {
++  int lg;
++  int ttlg;  /* 2^lg */
++  int ause = 0;  /* summation of `nums' */
++  int i = 1;  /* count to traverse all array keys */
++  for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) {  /* for each slice */
++    int lc = 0;  /* counter */
++    int lim = ttlg;
++    if (lim > t->sizearray) {
++      lim = t->sizearray;  /* adjust upper limit */
++      if (i > lim)
++        break;  /* no more elements to count */
++    }
++    /* count elements in range (2^(lg-1), 2^lg] */
++    for (; i <= lim; i++) {
++      if (!ttisnil(&t->array[i-1]))
++        lc++;
++    }
++    nums[lg] += lc;
++    ause += lc;
++  }
++  return ause;
++}
++
++
++static int numusehash (const Table *t, int *nums, int *pnasize) {
++  int totaluse = 0;  /* total number of elements */
++  int ause = 0;  /* summation of `nums' */
++  int i = sizenode(t);
++  while (i--) {
++    Node *n = &t->node[i];
++    if (!ttisnil(gval(n))) {
++      ause += countint(key2tval(n), nums);
++      totaluse++;
++    }
++  }
++  *pnasize += ause;
++  return totaluse;
++}
++
++
++static void setarrayvector (lua_State *L, Table *t, int size) {
++  int i;
++  luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
++  for (i=t->sizearray; i<size; i++)
++     setnilvalue(&t->array[i]);
++  t->sizearray = size;
++}
++
++
++static void setnodevector (lua_State *L, Table *t, int size) {
++  int lsize;
++  if (size == 0) {  /* no elements to hash part? */
++    t->node = cast(Node *, dummynode);  /* use common `dummynode' */
++    lsize = 0;
++  }
++  else {
++    int i;
++    lsize = ceillog2(size);
++    if (lsize > MAXBITS)
++      luaG_runerror(L, "table overflow");
++    size = twoto(lsize);
++    t->node = luaM_newvector(L, size, Node);
++    for (i=0; i<size; i++) {
++      Node *n = gnode(t, i);
++      gnext(n) = NULL;
++      setnilvalue(gkey(n));
++      setnilvalue(gval(n));
++    }
++  }
++  t->lsizenode = cast_byte(lsize);
++  t->lastfree = gnode(t, size);  /* all positions are free */
++}
++
++
++static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
++  int i;
++  int oldasize = t->sizearray;
++  int oldhsize = t->lsizenode;
++  Node *nold = t->node;  /* save old hash ... */
++  if (nasize > oldasize)  /* array part must grow? */
++    setarrayvector(L, t, nasize);
++  /* create new hash part with appropriate size */
++  setnodevector(L, t, nhsize);  
++  if (nasize < oldasize) {  /* array part must shrink? */
++    t->sizearray = nasize;
++    /* re-insert elements from vanishing slice */
++    for (i=nasize; i<oldasize; i++) {
++      if (!ttisnil(&t->array[i]))
++        setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
++    }
++    /* shrink array */
++    luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
++  }
++  /* re-insert elements from hash part */
++  for (i = twoto(oldhsize) - 1; i >= 0; i--) {
++    Node *old = nold+i;
++    if (!ttisnil(gval(old)))
++      setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old));
++  }
++  if (nold != dummynode)
++    luaM_freearray(L, nold, twoto(oldhsize), Node);  /* free old array */
++}
++
++
++void luaH_resizearray (lua_State *L, Table *t, int nasize) {
++  int nsize = (t->node == dummynode) ? 0 : sizenode(t);
++  resize(L, t, nasize, nsize);
++}
++
++
++static void rehash (lua_State *L, Table *t, const TValue *ek) {
++  int nasize, na;
++  int nums[MAXBITS+1];  /* nums[i] = number of keys between 2^(i-1) and 2^i */
++  int i;
++  int totaluse;
++  for (i=0; i<=MAXBITS; i++) nums[i] = 0;  /* reset counts */
++  nasize = numusearray(t, nums);  /* count keys in array part */
++  totaluse = nasize;  /* all those keys are integer keys */
++  totaluse += numusehash(t, nums, &nasize);  /* count keys in hash part */
++  /* count extra key */
++  nasize += countint(ek, nums);
++  totaluse++;
++  /* compute new size for array part */
++  na = computesizes(nums, &nasize);
++  /* resize the table to new computed sizes */
++  resize(L, t, nasize, totaluse - na);
++}
++
++
++
++/*
++** }=============================================================
++*/
++
++
++Table *luaH_new (lua_State *L, int narray, int nhash) {
++  Table *t = luaM_new(L, Table);
++  luaC_link(L, obj2gco(t), LUA_TTABLE);
++  t->metatable = NULL;
++  t->flags = cast_byte(~0);
++  /* temporary values (kept only if some malloc fails) */
++  t->array = NULL;
++  t->sizearray = 0;
++  t->lsizenode = 0;
++  t->node = cast(Node *, dummynode);
++  setarrayvector(L, t, narray);
++  setnodevector(L, t, nhash);
++  return t;
++}
++
++
++void luaH_free (lua_State *L, Table *t) {
++  if (t->node != dummynode)
++    luaM_freearray(L, t->node, sizenode(t), Node);
++  luaM_freearray(L, t->array, t->sizearray, TValue);
++  luaM_free(L, t);
++}
++
++
++static Node *getfreepos (Table *t) {
++  while (t->lastfree-- > t->node) {
++    if (ttisnil(gkey(t->lastfree)))
++      return t->lastfree;
++  }
++  return NULL;  /* could not find a free place */
++}
++
++
++
++/*
++** inserts a new key into a hash table; first, check whether key's main 
++** position is free. If not, check whether colliding node is in its main 
++** position or not: if it is not, move colliding node to an empty place and 
++** put new key in its main position; otherwise (colliding node is in its main 
++** position), new key goes to an empty position. 
++*/
++static TValue *newkey (lua_State *L, Table *t, const TValue *key) {
++  Node *mp = mainposition(t, key);
++  if (!ttisnil(gval(mp)) || mp == dummynode) {
++    Node *othern;
++    Node *n = getfreepos(t);  /* get a free place */
++    if (n == NULL) {  /* cannot find a free place? */
++      rehash(L, t, key);  /* grow table */
++      return luaH_set(L, t, key);  /* re-insert key into grown table */
++    }
++    lua_assert(n != dummynode);
++    othern = mainposition(t, key2tval(mp));
++    if (othern != mp) {  /* is colliding node out of its main position? */
++      /* yes; move colliding node into free position */
++      while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */
++      gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
++      *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
++      gnext(mp) = NULL;  /* now `mp' is free */
++      setnilvalue(gval(mp));
++    }
++    else {  /* colliding node is in its own main position */
++      /* new node will go into free position */
++      gnext(n) = gnext(mp);  /* chain new position */
++      gnext(mp) = n;
++      mp = n;
++    }
++  }
++  gkey(mp)->value = key->value; gkey(mp)->tt = key->tt;
++  luaC_barriert(L, t, key);
++  lua_assert(ttisnil(gval(mp)));
++  return gval(mp);
++}
++
++
++/*
++** search function for integers
++*/
++const TValue *luaH_getnum (Table *t, int key) {
++  /* (1 <= key && key <= t->sizearray) */
++  if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
++    return &t->array[key-1];
++  else {
++    lua_Number nk = cast_num(key);
++    Node *n = hashnum(t, nk);
++    do {  /* check whether `key' is somewhere in the chain */
++      if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
++        return gval(n);  /* that's it */
++      else n = gnext(n);
++    } while (n);
++    return luaO_nilobject;
++  }
++}
++
++
++/*
++** search function for strings
++*/
++const TValue *luaH_getstr (Table *t, TString *key) {
++  Node *n = hashstr(t, key);
++  do {  /* check whether `key' is somewhere in the chain */
++    if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key)
++      return gval(n);  /* that's it */
++    else n = gnext(n);
++  } while (n);
++  return luaO_nilobject;
++}
++
++
++/*
++** main search function
++*/
++const TValue *luaH_get (Table *t, const TValue *key) {
++  switch (ttype(key)) {
++    case LUA_TNIL: return luaO_nilobject;
++    case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
++    case LUA_TNUMBER: {
++      int k;
++      lua_Number n = nvalue(key);
++      lua_number2int(k, n);
++      if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
++        return luaH_getnum(t, k);  /* use specialized version */
++      /* else go through */
++    }
++    default: {
++      Node *n = mainposition(t, key);
++      do {  /* check whether `key' is somewhere in the chain */
++        if (luaO_rawequalObj(key2tval(n), key))
++          return gval(n);  /* that's it */
++        else n = gnext(n);
++      } while (n);
++      return luaO_nilobject;
++    }
++  }
++}
++
++
++TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
++  const TValue *p = luaH_get(t, key);
++  t->flags = 0;
++  if (p != luaO_nilobject)
++    return cast(TValue *, p);
++  else {
++    if (ttisnil(key)) luaG_runerror(L, "table index is nil");
++    else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
++      luaG_runerror(L, "table index is NaN");
++    return newkey(L, t, key);
++  }
++}
++
++
++TValue *luaH_setnum (lua_State *L, Table *t, int key) {
++  const TValue *p = luaH_getnum(t, key);
++  if (p != luaO_nilobject)
++    return cast(TValue *, p);
++  else {
++    TValue k;
++    setnvalue(&k, cast_num(key));
++    return newkey(L, t, &k);
++  }
++}
++
++
++TValue *luaH_setstr (lua_State *L, Table *t, TString *key) {
++  const TValue *p = luaH_getstr(t, key);
++  if (p != luaO_nilobject)
++    return cast(TValue *, p);
++  else {
++    TValue k;
++    setsvalue(L, &k, key);
++    return newkey(L, t, &k);
++  }
++}
++
++
++static int unbound_search (Table *t, unsigned int j) {
++  unsigned int i = j;  /* i is zero or a present index */
++  j++;
++  /* find `i' and `j' such that i is present and j is not */
++  while (!ttisnil(luaH_getnum(t, j))) {
++    i = j;
++    j *= 2;
++    if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */
++      /* table was built with bad purposes: resort to linear search */
++      i = 1;
++      while (!ttisnil(luaH_getnum(t, i))) i++;
++      return i - 1;
++    }
++  }
++  /* now do a binary search between them */
++  while (j - i > 1) {
++    unsigned int m = (i+j)/2;
++    if (ttisnil(luaH_getnum(t, m))) j = m;
++    else i = m;
++  }
++  return i;
++}
++
++
++/*
++** Try to find a boundary in table `t'. A `boundary' is an integer index
++** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
++*/
++int luaH_getn (Table *t) {
++  unsigned int j = t->sizearray;
++  if (j > 0 && ttisnil(&t->array[j - 1])) {
++    /* there is a boundary in the array part: (binary) search for it */
++    unsigned int i = 0;
++    while (j - i > 1) {
++      unsigned int m = (i+j)/2;
++      if (ttisnil(&t->array[m - 1])) j = m;
++      else i = m;
++    }
++    return i;
++  }
++  /* else must find a boundary in hash part */
++  else if (t->node == dummynode)  /* hash part is empty? */
++    return j;  /* that is easy... */
++  else return unbound_search(t, j);
++}
++
++
++
++#if defined(LUA_DEBUG)
++
++Node *luaH_mainposition (const Table *t, const TValue *key) {
++  return mainposition(t, key);
++}
++
++int luaH_isdummy (Node *n) { return n == dummynode; }
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/ltable.h
+@@ -0,0 +1,40 @@
++/*
++** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lua tables (hash)
++** See Copyright Notice in lua.h
++*/
++
++#ifndef ltable_h
++#define ltable_h
++
++#include "lobject.h"
++
++
++#define gnode(t,i)	(&(t)->node[i])
++#define gkey(n)		(&(n)->i_key.nk)
++#define gval(n)		(&(n)->i_val)
++#define gnext(n)	((n)->i_key.nk.next)
++
++#define key2tval(n)	(&(n)->i_key.tvk)
++
++
++LUAI_FUNC const TValue *luaH_getnum (Table *t, int key);
++LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
++LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
++LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
++LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
++LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
++LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash);
++LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize);
++LUAI_FUNC void luaH_free (lua_State *L, Table *t);
++LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
++LUAI_FUNC int luaH_getn (Table *t);
++
++
++#if defined(LUA_DEBUG)
++LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
++LUAI_FUNC int luaH_isdummy (Node *n);
++#endif
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/ltablib.c
+@@ -0,0 +1,288 @@
++/*
++** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $
++** Library for Table Manipulation
++** See Copyright Notice in lua.h
++*/
++
++
++#include <stddef.h>
++
++#define ltablib_c
++#define LUA_LIB
++
++#include "lua.h"
++
++#include "lauxlib.h"
++#include "lualib.h"
++
++
++#define aux_getn(L,n)	(luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))
++
++
++static int foreachi (lua_State *L) {
++  int i;
++  int n = aux_getn(L, 1);
++  luaL_checktype(L, 2, LUA_TFUNCTION);
++  for (i=1; i <= n; i++) {
++    lua_pushvalue(L, 2);  /* function */
++    lua_pushinteger(L, i);  /* 1st argument */
++    lua_rawgeti(L, 1, i);  /* 2nd argument */
++    lua_call(L, 2, 1);
++    if (!lua_isnil(L, -1))
++      return 1;
++    lua_pop(L, 1);  /* remove nil result */
++  }
++  return 0;
++}
++
++
++static int foreach (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++  luaL_checktype(L, 2, LUA_TFUNCTION);
++  lua_pushnil(L);  /* first key */
++  while (lua_next(L, 1)) {
++    lua_pushvalue(L, 2);  /* function */
++    lua_pushvalue(L, -3);  /* key */
++    lua_pushvalue(L, -3);  /* value */
++    lua_call(L, 2, 1);
++    if (!lua_isnil(L, -1))
++      return 1;
++    lua_pop(L, 2);  /* remove value and result */
++  }
++  return 0;
++}
++
++
++static int maxn (lua_State *L) {
++  lua_Number max = 0;
++  luaL_checktype(L, 1, LUA_TTABLE);
++  lua_pushnil(L);  /* first key */
++  while (lua_next(L, 1)) {
++    lua_pop(L, 1);  /* remove value */
++    if (lua_type(L, -1) == LUA_TNUMBER) {
++      lua_Number v = lua_tonumber(L, -1);
++      if (v > max) max = v;
++    }
++  }
++  lua_pushnumber(L, max);
++  return 1;
++}
++
++
++static int getn (lua_State *L) {
++  lua_pushinteger(L, aux_getn(L, 1));
++  return 1;
++}
++
++
++static int setn (lua_State *L) {
++  luaL_checktype(L, 1, LUA_TTABLE);
++#ifndef luaL_setn
++  luaL_setn(L, 1, luaL_checkint(L, 2));
++#else
++  luaL_error(L, LUA_QL("setn") " is obsolete");
++#endif
++  lua_pushvalue(L, 1);
++  return 1;
++}
++
++
++static int tinsert (lua_State *L) {
++  int e = aux_getn(L, 1) + 1;  /* first empty element */
++  int pos;  /* where to insert new element */
++  switch (lua_gettop(L)) {
++    case 2: {  /* called with only 2 arguments */
++      pos = e;  /* insert new element at the end */
++      break;
++    }
++    case 3: {
++      int i;
++      pos = luaL_checkint(L, 2);  /* 2nd argument is the position */
++      if (pos > e) e = pos;  /* `grow' array if necessary */
++      for (i = e; i > pos; i--) {  /* move up elements */
++        lua_rawgeti(L, 1, i-1);
++        lua_rawseti(L, 1, i);  /* t[i] = t[i-1] */
++      }
++      break;
++    }
++    default: {
++      return luaL_error(L, "wrong number of arguments to " LUA_QL("insert"));
++    }
++  }
++  luaL_setn(L, 1, e);  /* new size */
++  lua_rawseti(L, 1, pos);  /* t[pos] = v */
++  return 0;
++}
++
++
++static int tremove (lua_State *L) {
++  int e = aux_getn(L, 1);
++  int pos = luaL_optint(L, 2, e);
++  if (!(1 <= pos && pos <= e))  /* position is outside bounds? */
++   return 0;  /* nothing to remove */
++  luaL_setn(L, 1, e - 1);  /* t.n = n-1 */
++  lua_rawgeti(L, 1, pos);  /* result = t[pos] */
++  for ( ;pos<e; pos++) {
++    lua_rawgeti(L, 1, pos+1);
++    lua_rawseti(L, 1, pos);  /* t[pos] = t[pos+1] */
++  }
++  lua_pushnil(L);
++  lua_rawseti(L, 1, e);  /* t[e] = nil */
++  return 1;
++}
++
++
++static void addfield (lua_State *L, luaL_Buffer *b, int i) {
++  lua_rawgeti(L, 1, i);
++  if (!lua_isstring(L, -1))
++    luaL_error(L, "invalid value (%s) at index %d in table for "
++                  LUA_QL("concat"), luaL_typename(L, -1), i);
++    luaL_addvalue(b);
++}
++
++
++static int tconcat (lua_State *L) {
++  size_t lsep;
++  int i, last;
++  const char *sep = luaL_optlstring(L, 2, "", &lsep);
++  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "tconcat: cannot allocate memory");
++  luaL_checktype(L, 1, LUA_TTABLE);
++  i = luaL_optint(L, 3, 1);
++  last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1));
++  luaL_buffinit(L, b);
++  for (; i < last; i++) {
++    addfield(L, b, i);
++    luaL_addlstring(b, sep, lsep);
++  }
++  if (i == last)  /* add last value (if interval was not empty) */
++    addfield(L, b, i);
++  luaL_pushresult(b);
++  kfree(b);
++  return 1;
++}
++
++
++
++/*
++** {======================================================
++** Quicksort
++** (based on `Algorithms in MODULA-3', Robert Sedgewick;
++**  Addison-Wesley, 1993.)
++*/
++
++
++static void set2 (lua_State *L, int i, int j) {
++  lua_rawseti(L, 1, i);
++  lua_rawseti(L, 1, j);
++}
++
++static int sort_comp (lua_State *L, int a, int b) {
++  if (!lua_isnil(L, 2)) {  /* function? */
++    int res;
++    lua_pushvalue(L, 2);
++    lua_pushvalue(L, a-1);  /* -1 to compensate function */
++    lua_pushvalue(L, b-2);  /* -2 to compensate function and `a' */
++    lua_call(L, 2, 1);
++    res = lua_toboolean(L, -1);
++    lua_pop(L, 1);
++    return res;
++  }
++  else  /* a < b? */
++    return lua_lessthan(L, a, b);
++}
++
++static void auxsort (lua_State *L, int l, int u) {
++  while (l < u) {  /* for tail recursion */
++    int i, j;
++    /* sort elements a[l], a[(l+u)/2] and a[u] */
++    lua_rawgeti(L, 1, l);
++    lua_rawgeti(L, 1, u);
++    if (sort_comp(L, -1, -2))  /* a[u] < a[l]? */
++      set2(L, l, u);  /* swap a[l] - a[u] */
++    else
++      lua_pop(L, 2);
++    if (u-l == 1) break;  /* only 2 elements */
++    i = (l+u)/2;
++    lua_rawgeti(L, 1, i);
++    lua_rawgeti(L, 1, l);
++    if (sort_comp(L, -2, -1))  /* a[i]<a[l]? */
++      set2(L, i, l);
++    else {
++      lua_pop(L, 1);  /* remove a[l] */
++      lua_rawgeti(L, 1, u);
++      if (sort_comp(L, -1, -2))  /* a[u]<a[i]? */
++        set2(L, i, u);
++      else
++        lua_pop(L, 2);
++    }
++    if (u-l == 2) break;  /* only 3 elements */
++    lua_rawgeti(L, 1, i);  /* Pivot */
++    lua_pushvalue(L, -1);
++    lua_rawgeti(L, 1, u-1);
++    set2(L, i, u-1);
++    /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
++    i = l; j = u-1;
++    for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */
++      /* repeat ++i until a[i] >= P */
++      while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
++        if (i>u) luaL_error(L, "invalid order function for sorting");
++        lua_pop(L, 1);  /* remove a[i] */
++      }
++      /* repeat --j until a[j] <= P */
++      while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
++        if (j<l) luaL_error(L, "invalid order function for sorting");
++        lua_pop(L, 1);  /* remove a[j] */
++      }
++      if (j<i) {
++        lua_pop(L, 3);  /* pop pivot, a[i], a[j] */
++        break;
++      }
++      set2(L, i, j);
++    }
++    lua_rawgeti(L, 1, u-1);
++    lua_rawgeti(L, 1, i);
++    set2(L, u-1, i);  /* swap pivot (a[u-1]) with a[i] */
++    /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
++    /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
++    if (i-l < u-i) {
++      j=l; i=i-1; l=i+2;
++    }
++    else {
++      j=i+1; i=u; u=j-2;
++    }
++    auxsort(L, j, i);  /* call recursively the smaller one */
++  }  /* repeat the routine for the larger one */
++}
++
++static int sort (lua_State *L) {
++  int n = aux_getn(L, 1);
++  luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */
++  if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */
++    luaL_checktype(L, 2, LUA_TFUNCTION);
++  lua_settop(L, 2);  /* make sure there is two arguments */
++  auxsort(L, 1, n);
++  return 0;
++}
++
++/* }====================================================== */
++
++
++static const luaL_Reg tab_funcs[] = {
++  {"concat", tconcat},
++  {"foreach", foreach},
++  {"foreachi", foreachi},
++  {"getn", getn},
++  {"maxn", maxn},
++  {"insert", tinsert},
++  {"remove", tremove},
++  {"setn", setn},
++  {"sort", sort},
++  {NULL, NULL}
++};
++
++
++LUALIB_API int luaopen_table (lua_State *L) {
++  luaL_register(L, LUA_TABLIBNAME, tab_funcs);
++  return 1;
++}
+--- /dev/null
++++ b/extensions/LUA/lua/ltm.c
+@@ -0,0 +1,74 @@
++/*
++** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
++** Tag methods
++** See Copyright Notice in lua.h
++*/
++
++#include <string.h>
++
++#define ltm_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "lobject.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++
++
++
++const char *const luaT_typenames[] = {
++  "nil", "boolean", "userdata", "number",
++  "string", "table", "function", "userdata", "thread",
++  "proto", "upval"
++};
++
++
++void luaT_init (lua_State *L) {
++  static const char *const luaT_eventname[] = {  /* ORDER TM */
++    "__index", "__newindex",
++    "__gc", "__mode", "__eq",
++    "__add", "__sub", "__mul", "__div", "__mod",
++    "__pow", "__unm", "__len", "__lt", "__le",
++    "__concat", "__call"
++  };
++  int i;
++  for (i=0; i<TM_N; i++) {
++    G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
++    luaS_fix(G(L)->tmname[i]);  /* never collect these names */
++  }
++}
++
++
++/*
++** function to be used with macro "fasttm": optimized for absence of
++** tag methods
++*/
++const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
++  const TValue *tm = luaH_getstr(events, ename);
++  lua_assert(event <= TM_EQ);
++  if (ttisnil(tm)) {  /* no tag method? */
++    events->flags |= cast_byte(1u<<event);  /* cache this fact */
++    return NULL;
++  }
++  else return tm;
++}
++
++
++const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
++  Table *mt;
++  switch (ttype(o)) {
++    case LUA_TTABLE:
++      mt = hvalue(o)->metatable;
++      break;
++    case LUA_TUSERDATA:
++      mt = uvalue(o)->metatable;
++      break;
++    default:
++      mt = G(L)->mt[ttype(o)];
++  }
++  return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/ltm.h
+@@ -0,0 +1,54 @@
++/*
++** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $
++** Tag methods
++** See Copyright Notice in lua.h
++*/
++
++#ifndef ltm_h
++#define ltm_h
++
++
++#include "lobject.h"
++
++
++/*
++* WARNING: if you change the order of this enumeration,
++* grep "ORDER TM"
++*/
++typedef enum {
++  TM_INDEX,
++  TM_NEWINDEX,
++  TM_GC,
++  TM_MODE,
++  TM_EQ,  /* last tag method with `fast' access */
++  TM_ADD,
++  TM_SUB,
++  TM_MUL,
++  TM_DIV,
++  TM_MOD,
++  TM_POW,
++  TM_UNM,
++  TM_LEN,
++  TM_LT,
++  TM_LE,
++  TM_CONCAT,
++  TM_CALL,
++  TM_N		/* number of elements in the enum */
++} TMS;
++
++
++
++#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
++  ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
++
++#define fasttm(l,et,e)	gfasttm(G(l), et, e)
++
++LUAI_DATA const char *const luaT_typenames[];
++
++
++LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
++LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
++                                                       TMS event);
++LUAI_FUNC void luaT_init (lua_State *L);
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/luaconf.h
+@@ -0,0 +1,797 @@
++/*
++** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $
++** Configuration file for Lua
++** See Copyright Notice in lua.h
++*/
++
++
++#ifndef lconfig_h
++#define lconfig_h
++
++#include <stddef.h>
++
++#if !defined(__KERNEL__)
++#include <limits.h>
++#else
++#define UCHAR_MAX	255
++#define SHRT_MAX        32767
++#define BUFSIZ 		8192
++#define NO_FPU
++#endif
++
++/*
++** ==================================================================
++** Search for "@@" to find all configurable definitions.
++** ===================================================================
++*/
++
++
++/*
++@@ LUA_ANSI controls the use of non-ansi features.
++** CHANGE it (define it) if you want Lua to avoid the use of any
++** non-ansi feature or library.
++*/
++#if defined(__STRICT_ANSI__)
++#define LUA_ANSI
++#endif
++
++
++#if !defined(LUA_ANSI) && defined(_WIN32)
++#define LUA_WIN
++#endif
++
++#if defined(LUA_USE_LINUX)
++#define LUA_USE_POSIX
++#define LUA_USE_DLOPEN		/* needs an extra library: -ldl */
++#define LUA_USE_READLINE	/* needs some extra libraries */
++#endif
++
++#if defined(LUA_USE_MACOSX)
++#define LUA_USE_POSIX
++#define LUA_DL_DYLD		/* does not need extra library */
++#endif
++
++
++
++/*
++@@ LUA_USE_POSIX includes all functionallity listed as X/Open System
++@* Interfaces Extension (XSI).
++** CHANGE it (define it) if your system is XSI compatible.
++*/
++#if defined(LUA_USE_POSIX)
++#define LUA_USE_MKSTEMP
++#define LUA_USE_ISATTY
++#define LUA_USE_POPEN
++#define LUA_USE_ULONGJMP
++#endif
++
++
++/*
++@@ LUA_PATH and LUA_CPATH are the names of the environment variables that
++@* Lua check to set its paths.
++@@ LUA_INIT is the name of the environment variable that Lua
++@* checks for initialization code.
++** CHANGE them if you want different names.
++*/
++#define LUA_PATH        "LUA_PATH"
++#define LUA_CPATH       "LUA_CPATH"
++#define LUA_INIT	"LUA_INIT"
++
++
++/*
++@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
++@* Lua libraries.
++@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
++@* C libraries.
++** CHANGE them if your machine has a non-conventional directory
++** hierarchy or if you want to install your libraries in
++** non-conventional directories.
++*/
++#if defined(_WIN32)
++/*
++** In Windows, any exclamation mark ('!') in the path is replaced by the
++** path of the directory of the executable file of the current process.
++*/
++#define LUA_LDIR	"!\\lua\\"
++#define LUA_CDIR	"!\\"
++#define LUA_PATH_DEFAULT  \
++		".\\?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?\\init.lua;" \
++		             LUA_CDIR"?.lua;"  LUA_CDIR"?\\init.lua"
++#define LUA_CPATH_DEFAULT \
++	".\\?.dll;"  LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
++
++#else
++#define LUA_ROOT	"/usr/local/"
++#define LUA_LDIR	LUA_ROOT "share/lua/5.1/"
++#define LUA_CDIR	LUA_ROOT "lib/lua/5.1/"
++#define LUA_PATH_DEFAULT  \
++		"./?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?/init.lua;" \
++		            LUA_CDIR"?.lua;"  LUA_CDIR"?/init.lua"
++#define LUA_CPATH_DEFAULT \
++	"./?.so;"  LUA_CDIR"?.so;" LUA_CDIR"loadall.so"
++#endif
++
++
++/*
++@@ LUA_DIRSEP is the directory separator (for submodules).
++** CHANGE it if your machine does not use "/" as the directory separator
++** and is not Windows. (On Windows Lua automatically uses "\".)
++*/
++#if defined(_WIN32)
++#define LUA_DIRSEP	"\\"
++#else
++#define LUA_DIRSEP	"/"
++#endif
++
++
++/*
++@@ LUA_PATHSEP is the character that separates templates in a path.
++@@ LUA_PATH_MARK is the string that marks the substitution points in a
++@* template.
++@@ LUA_EXECDIR in a Windows path is replaced by the executable's
++@* directory.
++@@ LUA_IGMARK is a mark to ignore all before it when bulding the
++@* luaopen_ function name.
++** CHANGE them if for some reason your system cannot use those
++** characters. (E.g., if one of those characters is a common character
++** in file/directory names.) Probably you do not need to change them.
++*/
++#define LUA_PATHSEP	";"
++#define LUA_PATH_MARK	"?"
++#define LUA_EXECDIR	"!"
++#define LUA_IGMARK	"-"
++
++
++/*
++@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
++** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
++** machines, ptrdiff_t gives a good choice between int or long.)
++*/
++#define LUA_INTEGER	ptrdiff_t
++
++
++/*
++@@ LUA_API is a mark for all core API functions.
++@@ LUALIB_API is a mark for all standard library functions.
++** CHANGE them if you need to define those functions in some special way.
++** For instance, if you want to create one Windows DLL with the core and
++** the libraries, you may want to use the following definition (define
++** LUA_BUILD_AS_DLL to get it).
++*/
++#if defined(LUA_BUILD_AS_DLL)
++
++#if defined(LUA_CORE) || defined(LUA_LIB)
++#define LUA_API __declspec(dllexport)
++#else
++#define LUA_API __declspec(dllimport)
++#endif
++
++#else
++
++#define LUA_API		extern
++
++#endif
++
++/* more often than not the libs go together with the core */
++#define LUALIB_API	LUA_API
++
++
++/*
++@@ LUAI_FUNC is a mark for all extern functions that are not to be
++@* exported to outside modules.
++@@ LUAI_DATA is a mark for all extern (const) variables that are not to
++@* be exported to outside modules.
++** CHANGE them if you need to mark them in some special way. Elf/gcc
++** (versions 3.2 and later) mark them as "hidden" to optimize access
++** when Lua is compiled as a shared library.
++*/
++#if defined(luaall_c)
++#define LUAI_FUNC	static
++#define LUAI_DATA	/* empty */
++
++#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
++      defined(__ELF__)
++#define LUAI_FUNC	__attribute__((visibility("hidden"))) extern
++#define LUAI_DATA	LUAI_FUNC
++
++#else
++#define LUAI_FUNC	extern
++#define LUAI_DATA	extern
++#endif
++
++
++
++/*
++@@ LUA_QL describes how error messages quote program elements.
++** CHANGE it if you want a different appearance.
++*/
++#define LUA_QL(x)	"'" x "'"
++#define LUA_QS		LUA_QL("%s")
++
++
++/*
++@@ LUA_IDSIZE gives the maximum size for the description of the source
++@* of a function in debug information.
++** CHANGE it if you want a different size.
++*/
++#define LUA_IDSIZE	60
++
++
++/*
++** {==================================================================
++** Stand-alone configuration
++** ===================================================================
++*/
++
++#if defined(lua_c) || defined(luaall_c)
++
++/*
++@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that
++@* is, whether we're running lua interactively).
++** CHANGE it if you have a better definition for non-POSIX/non-Windows
++** systems.
++*/
++#if defined(LUA_USE_ISATTY)
++#include <unistd.h>
++#define lua_stdin_is_tty()	isatty(0)
++#elif defined(LUA_WIN)
++#include <io.h>
++#include <stdio.h>
++#define lua_stdin_is_tty()	_isatty(_fileno(stdin))
++#else
++#define lua_stdin_is_tty()	1  /* assume stdin is a tty */
++#endif
++
++
++/*
++@@ LUA_PROMPT is the default prompt used by stand-alone Lua.
++@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua.
++** CHANGE them if you want different prompts. (You can also change the
++** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.)
++*/
++#define LUA_PROMPT		"> "
++#define LUA_PROMPT2		">> "
++
++
++/*
++@@ LUA_PROGNAME is the default name for the stand-alone Lua program.
++** CHANGE it if your stand-alone interpreter has a different name and
++** your system is not able to detect that name automatically.
++*/
++#define LUA_PROGNAME		"lua"
++
++
++/*
++@@ LUA_MAXINPUT is the maximum length for an input line in the
++@* stand-alone interpreter.
++** CHANGE it if you need longer lines.
++*/
++#define LUA_MAXINPUT	512
++
++
++/*
++@@ lua_readline defines how to show a prompt and then read a line from
++@* the standard input.
++@@ lua_saveline defines how to "save" a read line in a "history".
++@@ lua_freeline defines how to free a line read by lua_readline.
++** CHANGE them if you want to improve this functionality (e.g., by using
++** GNU readline and history facilities).
++*/
++#if defined(LUA_USE_READLINE)
++#include <stdio.h>
++#include <readline/readline.h>
++#include <readline/history.h>
++#define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
++#define lua_saveline(L,idx) \
++	if (lua_strlen(L,idx) > 0)  /* non-empty line? */ \
++	  add_history(lua_tostring(L, idx));  /* add it to history */
++#define lua_freeline(L,b)	((void)L, free(b))
++#else
++#define lua_readline(L,b,p)	\
++	((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
++	fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
++#define lua_saveline(L,idx)	{ (void)L; (void)idx; }
++#define lua_freeline(L,b)	{ (void)L; (void)b; }
++#endif
++
++#endif
++
++/* }================================================================== */
++
++
++/*
++@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles
++@* as a percentage.
++** CHANGE it if you want the GC to run faster or slower (higher values
++** mean larger pauses which mean slower collection.) You can also change
++** this value dynamically.
++*/
++#define LUAI_GCPAUSE	200  /* 200% (wait memory to double before next GC) */
++
++
++/*
++@@ LUAI_GCMUL defines the default speed of garbage collection relative to
++@* memory allocation as a percentage.
++** CHANGE it if you want to change the granularity of the garbage
++** collection. (Higher values mean coarser collections. 0 represents
++** infinity, where each step performs a full collection.) You can also
++** change this value dynamically.
++*/
++#define LUAI_GCMUL	200 /* GC runs 'twice the speed' of memory allocation */
++
++
++
++/*
++@@ LUA_COMPAT_GETN controls compatibility with old getn behavior.
++** CHANGE it (define it) if you want exact compatibility with the
++** behavior of setn/getn in Lua 5.0.
++*/
++#undef LUA_COMPAT_GETN
++
++/*
++@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib.
++** CHANGE it to undefined as soon as you do not need a global 'loadlib'
++** function (the function is still available as 'package.loadlib').
++*/
++#undef LUA_COMPAT_LOADLIB
++
++/*
++@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature.
++** CHANGE it to undefined as soon as your programs use only '...' to
++** access vararg parameters (instead of the old 'arg' table).
++*/
++#define LUA_COMPAT_VARARG
++
++/*
++@@ LUA_COMPAT_MOD controls compatibility with old math.mod function.
++** CHANGE it to undefined as soon as your programs use 'math.fmod' or
++** the new '%' operator instead of 'math.mod'.
++*/
++#define LUA_COMPAT_MOD
++
++/*
++@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting
++@* facility.
++** CHANGE it to 2 if you want the old behaviour, or undefine it to turn
++** off the advisory error when nesting [[...]].
++*/
++#define LUA_COMPAT_LSTR		1
++
++/*
++@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name.
++** CHANGE it to undefined as soon as you rename 'string.gfind' to
++** 'string.gmatch'.
++*/
++#define LUA_COMPAT_GFIND
++
++/*
++@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib'
++@* behavior.
++** CHANGE it to undefined as soon as you replace to 'luaL_register'
++** your uses of 'luaL_openlib'
++*/
++#define LUA_COMPAT_OPENLIB
++
++
++
++/*
++@@ luai_apicheck is the assert macro used by the Lua-C API.
++** CHANGE luai_apicheck if you want Lua to perform some checks in the
++** parameters it gets from API calls. This may slow down the interpreter
++** a bit, but may be quite useful when debugging C code that interfaces
++** with Lua. A useful redefinition is to use assert.h.
++*/
++#if defined(LUA_USE_APICHECK)
++#include <assert.h>
++#define luai_apicheck(L,o)	{ (void)L; assert(o); }
++#else
++#define luai_apicheck(L,o)	{ (void)L; }
++#endif
++
++
++/*
++@@ LUAI_BITSINT defines the number of bits in an int.
++** CHANGE here if Lua cannot automatically detect the number of bits of
++** your machine. Probably you do not need to change this.
++*/
++/* avoid overflows in comparison */
++#if !defined(__KERNEL__)
++#include <limits.h>
++#define LUA_INT_MAX INT_MAX
++#else
++#define LUA_INT_MAX (~0U>>1)
++#endif
++
++#if LUA_INT_MAX-20 < 32760
++#define LUAI_BITSINT	16
++#elif LUA_INT_MAX > 2147483640L
++/* int has at least 32 bits */
++#define LUAI_BITSINT	32
++#else
++#error "you must define LUA_BITSINT with number of bits in an integer"
++#endif
++
++
++/*
++@@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
++@@ LUAI_INT32 is an signed integer with at least 32 bits.
++@@ LUAI_UMEM is an unsigned integer big enough to count the total
++@* memory used by Lua.
++@@ LUAI_MEM is a signed integer big enough to count the total memory
++@* used by Lua.
++** CHANGE here if for some weird reason the default definitions are not
++** good enough for your machine. (The definitions in the 'else'
++** part always works, but may waste space on machines with 64-bit
++** longs.) Probably you do not need to change this.
++*/
++#if LUAI_BITSINT >= 32
++#define LUAI_UINT32	unsigned int
++#define LUAI_INT32	int
++#define LUAI_MAXINT32	INT_MAX
++#define LUAI_UMEM	size_t
++#define LUAI_MEM	ptrdiff_t
++#else
++/* 16-bit ints */
++#define LUAI_UINT32	unsigned long
++#define LUAI_INT32	long
++#define LUAI_MAXINT32	LONG_MAX
++#define LUAI_UMEM	unsigned long
++#define LUAI_MEM	long
++#endif
++
++
++/*
++@@ LUAI_MAXCALLS limits the number of nested calls.
++** CHANGE it if you need really deep recursive calls. This limit is
++** arbitrary; its only purpose is to stop infinite recursion before
++** exhausting memory.
++*/
++#define LUAI_MAXCALLS	20000
++
++
++/*
++@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
++@* can use.
++** CHANGE it if you need lots of (Lua) stack space for your C
++** functions. This limit is arbitrary; its only purpose is to stop C
++** functions to consume unlimited stack space. (must be smaller than
++** -LUA_REGISTRYINDEX)
++*/
++#define LUAI_MAXCSTACK	8000
++
++
++
++/*
++** {==================================================================
++** CHANGE (to smaller values) the following definitions if your system
++** has a small C stack. (Or you may want to change them to larger
++** values if your system has a large C stack and these limits are
++** too rigid for you.) Some of these constants control the size of
++** stack-allocated arrays used by the compiler or the interpreter, while
++** others limit the maximum number of recursive calls that the compiler
++** or the interpreter can perform. Values too large may cause a C stack
++** overflow for some forms of deep constructs.
++** ===================================================================
++*/
++
++
++/*
++@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and
++@* syntactical nested non-terminals in a program.
++*/
++#define LUAI_MAXCCALLS		200
++
++
++/*
++@@ LUAI_MAXVARS is the maximum number of local variables per function
++@* (must be smaller than 250).
++*/
++#define LUAI_MAXVARS		200
++
++
++/*
++@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function
++@* (must be smaller than 250).
++*/
++#define LUAI_MAXUPVALUES	60
++
++
++/*
++@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
++*/
++#define LUAL_BUFFERSIZE		BUFSIZ
++
++/* }================================================================== */
++
++
++
++
++/*
++** {==================================================================
++@@ LUA_NUMBER is the type of numbers in Lua.
++** CHANGE the following definitions only if you want to build Lua
++** with a number type different from double. You may also need to
++** change lua_number2int & lua_number2integer.
++** ===================================================================
++*/
++#if !defined(NO_FPU)
++#define LUA_NUMBER_DOUBLE
++#define LUA_NUMBER	double
++#else
++#define LUA_NUMBER	long
++#endif
++
++/*
++@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
++@* over a number.
++*/
++#define LUAI_UACNUMBER	LUA_NUMBER
++
++
++/*
++@@ LUA_NUMBER_SCAN is the format for reading numbers.
++@@ LUA_NUMBER_FMT is the format for writing numbers.
++@@ lua_number2str converts a number to a string.
++@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
++@@ lua_str2number converts a string to a number.
++*/
++#if !defined(NO_FPU)
++#define LUA_NUMBER_SCAN		"%lf"
++#define LUA_NUMBER_FMT		"%.14g"
++#define lua_str2number(s,p)	strtod((s), (p))
++#else
++#define LUA_NUMBER_SCAN		"%ld"
++#define LUA_NUMBER_FMT		"%ld"
++#if !defined(__KERNEL__)
++#define lua_str2number(s,p)	strtol((s), (p), 10)
++#else
++#define lua_str2number(s,p)	simple_strtol((s), (p), 10)
++#endif
++#endif
++
++#define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */
++#define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n))
++
++/*
++@@ The luai_num* macros define the primitive operations over numbers.
++*/
++#if defined(LUA_CORE)
++#define luai_numadd(a,b)	((a)+(b))
++#define luai_numsub(a,b)	((a)-(b))
++#define luai_nummul(a,b)	((a)*(b))
++#define luai_numdiv(a,b)	((a)/(b))
++#define luai_numunm(a)		(-(a))
++#define luai_numeq(a,b)		((a)==(b))
++#define luai_numlt(a,b)		((a)<(b))
++#define luai_numle(a,b)		((a)<=(b))
++#define luai_numisnan(a)	(!luai_numeq((a), (a)))
++#if !defined(NO_FPU)
++#include <math.h>
++#define luai_nummod(a,b)	((a) - floor((a)/(b))*(b))
++#define luai_numpow(a,b)	(pow(a,b))
++#else
++#define luai_nummod(a,b)	((a)%(b))
++#define luai_numpow(a,b)	luai_nummul(a,b)
++#endif
++#endif
++
++
++/*
++@@ lua_number2int is a macro to convert lua_Number to int.
++@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
++** CHANGE them if you know a faster way to convert a lua_Number to
++** int (with any rounding method and without throwing errors) in your
++** system. In Pentium machines, a naive typecast from double to int
++** in C is extremely slow, so any alternative is worth trying.
++*/
++
++/* On a Pentium, resort to a trick */
++#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
++    (defined(__i386) || defined (_M_IX86) || defined(__i386__))
++
++/* On a Microsoft compiler, use assembler */
++#if defined(_MSC_VER)
++
++#define lua_number2int(i,d)   __asm fld d   __asm fistp i
++#define lua_number2integer(i,n)		lua_number2int(i, n)
++
++/* the next trick should work on any Pentium, but sometimes clashes
++   with a DirectX idiosyncrasy */
++#else
++
++union luai_Cast { double l_d; long l_l; };
++#define lua_number2int(i,d) \
++  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
++#define lua_number2integer(i,n)		lua_number2int(i, n)
++
++#endif
++
++
++/* this option always works, but may be slow */
++#else
++#define lua_number2int(i,d)	((i)=(int)(d))
++#define lua_number2integer(i,d)	((i)=(lua_Integer)(d))
++
++#endif
++
++/* }================================================================== */
++
++
++/*
++@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
++** CHANGE it if your system requires alignments larger than double. (For
++** instance, if your system supports long doubles and they must be
++** aligned in 16-byte boundaries, then you should add long double in the
++** union.) Probably you do not need to change this.
++*/
++#define LUAI_USER_ALIGNMENT_T	union { double u; void *s; long l; }
++
++
++/*
++@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling.
++** CHANGE them if you prefer to use longjmp/setjmp even with C++
++** or if want/don't to use _longjmp/_setjmp instead of regular
++** longjmp/setjmp. By default, Lua handles errors with exceptions when
++** compiling as C++ code, with _longjmp/_setjmp when asked to use them,
++** and with longjmp/setjmp otherwise.
++*/
++#if defined(__KERNEL__)
++#undef LUA_USE_ULONGJMP
++#endif
++
++#if defined(__cplusplus)
++/* C++ exceptions */
++#define LUAI_THROW(L,c)	throw(c)
++#define LUAI_TRY(L,c,a)	try { a } catch(...) \
++	{ if ((c)->status == 0) (c)->status = -1; }
++#define luai_jmpbuf	int  /* dummy variable */
++
++#elif defined(LUA_USE_ULONGJMP)
++/* in Unix, try _longjmp/_setjmp (more efficient) */
++#define LUAI_THROW(L,c)	_longjmp((c)->b, 1)
++#define LUAI_TRY(L,c,a)	if (_setjmp((c)->b) == 0) { a }
++#define luai_jmpbuf	jmp_buf
++
++#else
++/* default handling with long jumps */
++#define LUAI_THROW(L,c)	longjmp((c)->b, 1)
++#define LUAI_TRY(L,c,a)	if (setjmp((c)->b) == 0) { a }
++#define luai_jmpbuf	jmp_buf
++
++#endif
++
++
++/*
++@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern
++@* can do during pattern-matching.
++** CHANGE it if you need more captures. This limit is arbitrary.
++*/
++#define LUA_MAXCAPTURES		32
++
++
++/*
++@@ lua_tmpnam is the function that the OS library uses to create a
++@* temporary name.
++@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam.
++** CHANGE them if you have an alternative to tmpnam (which is considered
++** insecure) or if you want the original tmpnam anyway.  By default, Lua
++** uses tmpnam except when POSIX is available, where it uses mkstemp.
++*/
++#if defined(loslib_c) || defined(luaall_c)
++
++#if defined(LUA_USE_MKSTEMP)
++#include <unistd.h>
++#define LUA_TMPNAMBUFSIZE	32
++#define lua_tmpnam(b,e)	{ \
++	strcpy(b, "/tmp/lua_XXXXXX"); \
++	e = mkstemp(b); \
++	if (e != -1) close(e); \
++	e = (e == -1); }
++
++#else
++#define LUA_TMPNAMBUFSIZE	L_tmpnam
++#define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); }
++#endif
++
++#endif
++
++
++/*
++@@ lua_popen spawns a new process connected to the current one through
++@* the file streams.
++** CHANGE it if you have a way to implement it in your system.
++*/
++#if defined(LUA_USE_POPEN)
++
++#define lua_popen(L,c,m)	((void)L, fflush(NULL), popen(c,m))
++#define lua_pclose(L,file)	((void)L, (pclose(file) != -1))
++
++#elif defined(LUA_WIN)
++
++#define lua_popen(L,c,m)	((void)L, _popen(c,m))
++#define lua_pclose(L,file)	((void)L, (_pclose(file) != -1))
++
++#else
++
++#define lua_popen(L,c,m)	((void)((void)c, m),  \
++		luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
++#define lua_pclose(L,file)		((void)((void)L, file), 0)
++
++#endif
++
++/*
++@@ LUA_DL_* define which dynamic-library system Lua should use.
++** CHANGE here if Lua has problems choosing the appropriate
++** dynamic-library system for your platform (either Windows' DLL, Mac's
++** dyld, or Unix's dlopen). If your system is some kind of Unix, there
++** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for
++** it.  To use dlopen you also need to adapt the src/Makefile (probably
++** adding -ldl to the linker options), so Lua does not select it
++** automatically.  (When you change the makefile to add -ldl, you must
++** also add -DLUA_USE_DLOPEN.)
++** If you do not want any kind of dynamic library, undefine all these
++** options.
++** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD.
++*/
++#if defined(LUA_USE_DLOPEN)
++#define LUA_DL_DLOPEN
++#endif
++
++#if defined(LUA_WIN)
++#define LUA_DL_DLL
++#endif
++
++
++/*
++@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State
++@* (the data goes just *before* the lua_State pointer).
++** CHANGE (define) this if you really need that. This value must be
++** a multiple of the maximum alignment required for your machine.
++*/
++#define LUAI_EXTRASPACE		0
++
++
++/*
++@@ luai_userstate* allow user-specific actions on threads.
++** CHANGE them if you defined LUAI_EXTRASPACE and need to do something
++** extra when a thread is created/deleted/resumed/yielded.
++*/
++#define luai_userstateopen(L)		((void)L)
++#define luai_userstateclose(L)		((void)L)
++#define luai_userstatethread(L,L1)	((void)L)
++#define luai_userstatefree(L)		((void)L)
++#define luai_userstateresume(L,n)	((void)L)
++#define luai_userstateyield(L,n)	((void)L)
++
++
++/*
++@@ LUA_INTFRMLEN is the length modifier for integer conversions
++@* in 'string.format'.
++@@ LUA_INTFRM_T is the integer type correspoding to the previous length
++@* modifier.
++** CHANGE them if your system supports long long or does not support long.
++*/
++
++#if defined(LUA_USELONGLONG)
++
++#define LUA_INTFRMLEN		"ll"
++#define LUA_INTFRM_T		long long
++
++#else
++
++#define LUA_INTFRMLEN		"l"
++#define LUA_INTFRM_T		long
++
++#endif
++
++/* =================================================================== */
++
++/*
++** Local configuration. You can use this space to add your redefinitions
++** without modifying the main part of the file.
++*/
++
++
++
++#endif
++
+--- /dev/null
++++ b/extensions/LUA/lua/lua.h
+@@ -0,0 +1,387 @@
++/*
++** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
++** Lua - An Extensible Extension Language
++** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
++** See Copyright Notice at the end of this file
++*/
++
++
++#ifndef lua_h
++#define lua_h
++
++#include <stdarg.h>
++#include <stddef.h>
++
++#include "luaconf.h"
++
++
++#define LUA_VERSION	"Lua 5.1"
++#define LUA_RELEASE	"Lua 5.1.4"
++#define LUA_VERSION_NUM	501
++#define LUA_COPYRIGHT	"Copyright (C) 1994-2008 Lua.org, PUC-Rio"
++#define LUA_AUTHORS 	"R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
++
++
++/* mark for precompiled code (`<esc>Lua') */
++#define	LUA_SIGNATURE	"\033Lua"
++
++/* option for multiple returns in `lua_pcall' and `lua_call' */
++#define LUA_MULTRET	(-1)
++
++
++/*
++** pseudo-indices
++*/
++#define LUA_REGISTRYINDEX	(-10000)
++#define LUA_ENVIRONINDEX	(-10001)
++#define LUA_GLOBALSINDEX	(-10002)
++#define lua_upvalueindex(i)	(LUA_GLOBALSINDEX-(i))
++
++
++/* thread status; 0 is OK */
++#define LUA_YIELD	1
++#define LUA_ERRRUN	2
++#define LUA_ERRSYNTAX	3
++#define LUA_ERRMEM	4
++#define LUA_ERRERR	5
++
++
++typedef struct lua_State lua_State;
++
++typedef int (*lua_CFunction) (lua_State *L);
++
++
++/*
++** functions that read/write blocks when loading/dumping Lua chunks
++*/
++typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
++
++typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
++
++
++/*
++** prototype for memory-allocation functions
++*/
++typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
++
++
++/*
++** basic types
++*/
++#define LUA_TNONE		(-1)
++
++#define LUA_TNIL		0
++#define LUA_TBOOLEAN		1
++#define LUA_TLIGHTUSERDATA	2
++#define LUA_TNUMBER		3
++#define LUA_TSTRING		4
++#define LUA_TTABLE		5
++#define LUA_TFUNCTION		6
++#define LUA_TUSERDATA		7
++#define LUA_TTHREAD		8
++
++
++
++/* minimum Lua stack available to a C function */
++#define LUA_MINSTACK	20
++
++
++/*
++** generic extra include file
++*/
++#if defined(LUA_USER_H)
++#include LUA_USER_H
++#endif
++
++
++/* type of numbers in Lua */
++typedef LUA_NUMBER lua_Number;
++
++
++/* type for integer functions */
++typedef LUA_INTEGER lua_Integer;
++
++
++
++/*
++** state manipulation
++*/
++LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
++LUA_API void       (lua_close) (lua_State *L);
++LUA_API lua_State *(lua_newthread) (lua_State *L);
++
++LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
++
++
++/*
++** basic stack manipulation
++*/
++LUA_API int   (lua_gettop) (lua_State *L);
++LUA_API void  (lua_settop) (lua_State *L, int idx);
++LUA_API void  (lua_pushvalue) (lua_State *L, int idx);
++LUA_API void  (lua_remove) (lua_State *L, int idx);
++LUA_API void  (lua_insert) (lua_State *L, int idx);
++LUA_API void  (lua_replace) (lua_State *L, int idx);
++LUA_API int   (lua_checkstack) (lua_State *L, int sz);
++
++LUA_API void  (lua_xmove) (lua_State *from, lua_State *to, int n);
++
++
++/*
++** access functions (stack -> C)
++*/
++
++LUA_API int             (lua_isnumber) (lua_State *L, int idx);
++LUA_API int             (lua_isstring) (lua_State *L, int idx);
++LUA_API int             (lua_iscfunction) (lua_State *L, int idx);
++LUA_API int             (lua_isuserdata) (lua_State *L, int idx);
++LUA_API int             (lua_type) (lua_State *L, int idx);
++LUA_API const char     *(lua_typename) (lua_State *L, int tp);
++
++LUA_API int            (lua_equal) (lua_State *L, int idx1, int idx2);
++LUA_API int            (lua_rawequal) (lua_State *L, int idx1, int idx2);
++LUA_API int            (lua_lessthan) (lua_State *L, int idx1, int idx2);
++
++LUA_API lua_Number      (lua_tonumber) (lua_State *L, int idx);
++LUA_API lua_Integer     (lua_tointeger) (lua_State *L, int idx);
++LUA_API int             (lua_toboolean) (lua_State *L, int idx);
++LUA_API const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len);
++LUA_API size_t          (lua_objlen) (lua_State *L, int idx);
++LUA_API lua_CFunction   (lua_tocfunction) (lua_State *L, int idx);
++LUA_API void	       *(lua_touserdata) (lua_State *L, int idx);
++LUA_API lua_State      *(lua_tothread) (lua_State *L, int idx);
++LUA_API const void     *(lua_topointer) (lua_State *L, int idx);
++
++
++/*
++** push functions (C -> stack)
++*/
++LUA_API void  (lua_pushnil) (lua_State *L);
++LUA_API void  (lua_pushnumber) (lua_State *L, lua_Number n);
++LUA_API void  (lua_pushinteger) (lua_State *L, lua_Integer n);
++LUA_API void  (lua_pushlstring) (lua_State *L, const char *s, size_t l);
++LUA_API void  (lua_pushstring) (lua_State *L, const char *s);
++LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
++                                                      va_list argp);
++LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
++LUA_API void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
++LUA_API void  (lua_pushboolean) (lua_State *L, int b);
++LUA_API void  (lua_pushlightuserdata) (lua_State *L, void *p);
++LUA_API int   (lua_pushthread) (lua_State *L);
++
++
++/*
++** get functions (Lua -> stack)
++*/
++LUA_API void  (lua_gettable) (lua_State *L, int idx);
++LUA_API void  (lua_getfield) (lua_State *L, int idx, const char *k);
++LUA_API void  (lua_rawget) (lua_State *L, int idx);
++LUA_API void  (lua_rawgeti) (lua_State *L, int idx, int n);
++LUA_API void  (lua_createtable) (lua_State *L, int narr, int nrec);
++LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
++LUA_API int   (lua_getmetatable) (lua_State *L, int objindex);
++LUA_API void  (lua_getfenv) (lua_State *L, int idx);
++
++
++/*
++** set functions (stack -> Lua)
++*/
++LUA_API void  (lua_settable) (lua_State *L, int idx);
++LUA_API void  (lua_setfield) (lua_State *L, int idx, const char *k);
++LUA_API void  (lua_rawset) (lua_State *L, int idx);
++LUA_API void  (lua_rawseti) (lua_State *L, int idx, int n);
++LUA_API int   (lua_setmetatable) (lua_State *L, int objindex);
++LUA_API int   (lua_setfenv) (lua_State *L, int idx);
++
++
++/*
++** `load' and `call' functions (load and run Lua code)
++*/
++LUA_API void  (lua_call) (lua_State *L, int nargs, int nresults);
++LUA_API int   (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
++LUA_API int   (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
++LUA_API int   (lua_load) (lua_State *L, lua_Reader reader, void *dt,
++                                        const char *chunkname);
++
++LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
++
++
++/*
++** coroutine functions
++*/
++LUA_API int  (lua_yield) (lua_State *L, int nresults);
++LUA_API int  (lua_resume) (lua_State *L, int narg);
++LUA_API int  (lua_status) (lua_State *L);
++
++/*
++** garbage-collection function and options
++*/
++
++#define LUA_GCSTOP		0
++#define LUA_GCRESTART		1
++#define LUA_GCCOLLECT		2
++#define LUA_GCCOUNT		3
++#define LUA_GCCOUNTB		4
++#define LUA_GCSTEP		5
++#define LUA_GCSETPAUSE		6
++#define LUA_GCSETSTEPMUL	7
++
++LUA_API int (lua_gc) (lua_State *L, int what, int data);
++
++
++/*
++** miscellaneous functions
++*/
++
++LUA_API int   (lua_error) (lua_State *L);
++
++LUA_API int   (lua_next) (lua_State *L, int idx);
++
++LUA_API void  (lua_concat) (lua_State *L, int n);
++
++LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
++LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
++
++
++
++/* 
++** ===============================================================
++** some useful macros
++** ===============================================================
++*/
++
++#define lua_pop(L,n)		lua_settop(L, -(n)-1)
++
++#define lua_newtable(L)		lua_createtable(L, 0, 0)
++
++#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
++
++#define lua_pushcfunction(L,f)	lua_pushcclosure(L, (f), 0)
++
++#define lua_strlen(L,i)		lua_objlen(L, (i))
++
++#define lua_isfunction(L,n)	(lua_type(L, (n)) == LUA_TFUNCTION)
++#define lua_istable(L,n)	(lua_type(L, (n)) == LUA_TTABLE)
++#define lua_islightuserdata(L,n)	(lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
++#define lua_isnil(L,n)		(lua_type(L, (n)) == LUA_TNIL)
++#define lua_isboolean(L,n)	(lua_type(L, (n)) == LUA_TBOOLEAN)
++#define lua_isthread(L,n)	(lua_type(L, (n)) == LUA_TTHREAD)
++#define lua_isnone(L,n)		(lua_type(L, (n)) == LUA_TNONE)
++#define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0)
++
++#define lua_pushliteral(L, s)	\
++	lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
++
++#define lua_setglobal(L,s)	lua_setfield(L, LUA_GLOBALSINDEX, (s))
++#define lua_getglobal(L,s)	lua_getfield(L, LUA_GLOBALSINDEX, (s))
++
++#define lua_tostring(L,i)	lua_tolstring(L, (i), NULL)
++
++
++
++/*
++** compatibility macros and functions
++*/
++
++#define lua_open()	luaL_newstate()
++
++#define lua_getregistry(L)	lua_pushvalue(L, LUA_REGISTRYINDEX)
++
++#define lua_getgccount(L)	lua_gc(L, LUA_GCCOUNT, 0)
++
++#define lua_Chunkreader		lua_Reader
++#define lua_Chunkwriter		lua_Writer
++
++
++/* hack */
++LUA_API void lua_setlevel	(lua_State *from, lua_State *to);
++
++
++/*
++** {======================================================================
++** Debug API
++** =======================================================================
++*/
++
++
++/*
++** Event codes
++*/
++#define LUA_HOOKCALL	0
++#define LUA_HOOKRET	1
++#define LUA_HOOKLINE	2
++#define LUA_HOOKCOUNT	3
++#define LUA_HOOKTAILRET 4
++
++
++/*
++** Event masks
++*/
++#define LUA_MASKCALL	(1 << LUA_HOOKCALL)
++#define LUA_MASKRET	(1 << LUA_HOOKRET)
++#define LUA_MASKLINE	(1 << LUA_HOOKLINE)
++#define LUA_MASKCOUNT	(1 << LUA_HOOKCOUNT)
++
++typedef struct lua_Debug lua_Debug;  /* activation record */
++
++
++/* Functions to be called by the debuger in specific events */
++typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
++
++
++LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
++LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
++LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
++LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
++LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
++LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
++
++LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
++LUA_API lua_Hook lua_gethook (lua_State *L);
++LUA_API int lua_gethookmask (lua_State *L);
++LUA_API int lua_gethookcount (lua_State *L);
++
++
++struct lua_Debug {
++  int event;
++  const char *name;	/* (n) */
++  const char *namewhat;	/* (n) `global', `local', `field', `method' */
++  const char *what;	/* (S) `Lua', `C', `main', `tail' */
++  const char *source;	/* (S) */
++  int currentline;	/* (l) */
++  int nups;		/* (u) number of upvalues */
++  int linedefined;	/* (S) */
++  int lastlinedefined;	/* (S) */
++  char short_src[LUA_IDSIZE]; /* (S) */
++  /* private part */
++  int i_ci;  /* active function */
++};
++
++/* }====================================================================== */
++
++
++/******************************************************************************
++* Copyright (C) 1994-2008 Lua.org, PUC-Rio.  All rights reserved.
++*
++* Permission is hereby granted, free of charge, to any person obtaining
++* a copy of this software and associated documentation files (the
++* "Software"), to deal in the Software without restriction, including
++* without limitation the rights to use, copy, modify, merge, publish,
++* distribute, sublicense, and/or sell copies of the Software, and to
++* permit persons to whom the Software is furnished to do so, subject to
++* the following conditions:
++*
++* The above copyright notice and this permission notice shall be
++* included in all copies or substantial portions of the Software.
++*
++* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
++* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
++* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
++* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++******************************************************************************/
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lualib.h
+@@ -0,0 +1,55 @@
++/*
++** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lua standard libraries
++** See Copyright Notice in lua.h
++*/
++
++
++#ifndef lualib_h
++#define lualib_h
++
++#include "lua.h"
++
++
++/* Key to file-handle type */
++#define LUA_FILEHANDLE		"FILE*"
++
++
++#define LUA_COLIBNAME	"coroutine"
++LUALIB_API int (luaopen_base) (lua_State *L);
++
++#define LUA_TABLIBNAME	"table"
++LUALIB_API int (luaopen_table) (lua_State *L);
++/*
++#define LUA_IOLIBNAME	"io"
++LUALIB_API int (luaopen_io) (lua_State *L);
++
++#define LUA_OSLIBNAME	"os"
++LUALIB_API int (luaopen_os) (lua_State *L);
++*/
++
++#define LUA_STRLIBNAME	"string"
++LUALIB_API int (luaopen_string) (lua_State *L);
++
++/*
++#define LUA_MATHLIBNAME	"math"
++LUALIB_API int (luaopen_math) (lua_State *L);
++
++#define LUA_DBLIBNAME	"debug"
++LUALIB_API int (luaopen_debug) (lua_State *L);
++
++#define LUA_LOADLIBNAME	"package"
++LUALIB_API int (luaopen_package) (lua_State *L);
++*/
++
++/* open all previous libraries */
++LUALIB_API void (luaL_openlibs) (lua_State *L);
++
++
++
++#ifndef lua_assert
++#define lua_assert(x)	((void)0)
++#endif
++
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lundump.c
+@@ -0,0 +1,227 @@
++/*
++** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $
++** load precompiled Lua chunks
++** See Copyright Notice in lua.h
++*/
++
++#include <string.h>
++
++#define lundump_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lmem.h"
++#include "lobject.h"
++#include "lstring.h"
++#include "lundump.h"
++#include "lzio.h"
++
++typedef struct {
++ lua_State* L;
++ ZIO* Z;
++ Mbuffer* b;
++ const char* name;
++} LoadState;
++
++#ifdef LUAC_TRUST_BINARIES
++#define IF(c,s)
++#define error(S,s)
++#else
++#define IF(c,s)		if (c) error(S,s)
++
++static void error(LoadState* S, const char* why)
++{
++ luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why);
++ luaD_throw(S->L,LUA_ERRSYNTAX);
++}
++#endif
++
++#define LoadMem(S,b,n,size)	LoadBlock(S,b,(n)*(size))
++#define	LoadByte(S)		(lu_byte)LoadChar(S)
++#define LoadVar(S,x)		LoadMem(S,&x,1,sizeof(x))
++#define LoadVector(S,b,n,size)	LoadMem(S,b,n,size)
++
++static void LoadBlock(LoadState* S, void* b, size_t size)
++{
++ size_t r=luaZ_read(S->Z,b,size);
++ IF (r!=0, "unexpected end");
++}
++
++static int LoadChar(LoadState* S)
++{
++ char x;
++ LoadVar(S,x);
++ return x;
++}
++
++static int LoadInt(LoadState* S)
++{
++ int x;
++ LoadVar(S,x);
++ IF (x<0, "bad integer");
++ return x;
++}
++
++static lua_Number LoadNumber(LoadState* S)
++{
++ lua_Number x;
++ LoadVar(S,x);
++ return x;
++}
++
++static TString* LoadString(LoadState* S)
++{
++ size_t size;
++ LoadVar(S,size);
++ if (size==0)
++  return NULL;
++ else
++ {
++  char* s=luaZ_openspace(S->L,S->b,size);
++  LoadBlock(S,s,size);
++  return luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */
++ }
++}
++
++static void LoadCode(LoadState* S, Proto* f)
++{
++ int n=LoadInt(S);
++ f->code=luaM_newvector(S->L,n,Instruction);
++ f->sizecode=n;
++ LoadVector(S,f->code,n,sizeof(Instruction));
++}
++
++static Proto* LoadFunction(LoadState* S, TString* p);
++
++static void LoadConstants(LoadState* S, Proto* f)
++{
++ int i,n;
++ n=LoadInt(S);
++ f->k=luaM_newvector(S->L,n,TValue);
++ f->sizek=n;
++ for (i=0; i<n; i++) setnilvalue(&f->k[i]);
++ for (i=0; i<n; i++)
++ {
++  TValue* o=&f->k[i];
++  int t=LoadChar(S);
++  switch (t)
++  {
++   case LUA_TNIL:
++   	setnilvalue(o);
++	break;
++   case LUA_TBOOLEAN:
++   	setbvalue(o,LoadChar(S)!=0);
++	break;
++   case LUA_TNUMBER:
++	setnvalue(o,LoadNumber(S));
++	break;
++   case LUA_TSTRING:
++	setsvalue2n(S->L,o,LoadString(S));
++	break;
++   default:
++	error(S,"bad constant");
++	break;
++  }
++ }
++ n=LoadInt(S);
++ f->p=luaM_newvector(S->L,n,Proto*);
++ f->sizep=n;
++ for (i=0; i<n; i++) f->p[i]=NULL;
++ for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
++}
++
++static void LoadDebug(LoadState* S, Proto* f)
++{
++ int i,n;
++ n=LoadInt(S);
++ f->lineinfo=luaM_newvector(S->L,n,int);
++ f->sizelineinfo=n;
++ LoadVector(S,f->lineinfo,n,sizeof(int));
++ n=LoadInt(S);
++ f->locvars=luaM_newvector(S->L,n,LocVar);
++ f->sizelocvars=n;
++ for (i=0; i<n; i++) f->locvars[i].varname=NULL;
++ for (i=0; i<n; i++)
++ {
++  f->locvars[i].varname=LoadString(S);
++  f->locvars[i].startpc=LoadInt(S);
++  f->locvars[i].endpc=LoadInt(S);
++ }
++ n=LoadInt(S);
++ f->upvalues=luaM_newvector(S->L,n,TString*);
++ f->sizeupvalues=n;
++ for (i=0; i<n; i++) f->upvalues[i]=NULL;
++ for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
++}
++
++static Proto* LoadFunction(LoadState* S, TString* p)
++{
++ Proto* f;
++ if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep");
++ f=luaF_newproto(S->L);
++ setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
++ f->source=LoadString(S); if (f->source==NULL) f->source=p;
++ f->linedefined=LoadInt(S);
++ f->lastlinedefined=LoadInt(S);
++ f->nups=LoadByte(S);
++ f->numparams=LoadByte(S);
++ f->is_vararg=LoadByte(S);
++ f->maxstacksize=LoadByte(S);
++ LoadCode(S,f);
++ LoadConstants(S,f);
++ LoadDebug(S,f);
++ IF (!luaG_checkcode(f), "bad code");
++ S->L->top--;
++ S->L->nCcalls--;
++ return f;
++}
++
++static void LoadHeader(LoadState* S)
++{
++ char h[LUAC_HEADERSIZE];
++ char s[LUAC_HEADERSIZE];
++ luaU_header(h);
++ LoadBlock(S,s,LUAC_HEADERSIZE);
++ IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header");
++}
++
++/*
++** load precompiled chunk
++*/
++Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
++{
++ LoadState S;
++ if (*name=='@' || *name=='=')
++  S.name=name+1;
++ else if (*name==LUA_SIGNATURE[0])
++  S.name="binary string";
++ else
++  S.name=name;
++ S.L=L;
++ S.Z=Z;
++ S.b=buff;
++ LoadHeader(&S);
++ return LoadFunction(&S,luaS_newliteral(L,"=?"));
++}
++
++/*
++* make header
++*/
++void luaU_header (char* h)
++{
++ int x=1;
++ memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
++ h+=sizeof(LUA_SIGNATURE)-1;
++ *h++=(char)LUAC_VERSION;
++ *h++=(char)LUAC_FORMAT;
++ *h++=(char)*(char*)&x;				/* endianness */
++ *h++=(char)sizeof(int);
++ *h++=(char)sizeof(size_t);
++ *h++=(char)sizeof(Instruction);
++ *h++=(char)sizeof(lua_Number);
++ *h++=(char)(((lua_Number)0.5)==0);		/* is lua_Number integral? */
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lundump.h
+@@ -0,0 +1,36 @@
++/*
++** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
++** load precompiled Lua chunks
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lundump_h
++#define lundump_h
++
++#include "lobject.h"
++#include "lzio.h"
++
++/* load one chunk; from lundump.c */
++LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
++
++/* make header; from lundump.c */
++LUAI_FUNC void luaU_header (char* h);
++
++/* dump one chunk; from ldump.c */
++LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
++
++#ifdef luac_c
++/* print one chunk; from print.c */
++LUAI_FUNC void luaU_print (const Proto* f, int full);
++#endif
++
++/* for header of binary files -- this is Lua 5.1 */
++#define LUAC_VERSION		0x51
++
++/* for header of binary files -- this is the official format */
++#define LUAC_FORMAT		0
++
++/* size of header of binary files */
++#define LUAC_HEADERSIZE		12
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lvm.c
+@@ -0,0 +1,762 @@
++/*
++** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $
++** Lua virtual machine
++** See Copyright Notice in lua.h
++*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#define lvm_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "ldebug.h"
++#include "ldo.h"
++#include "lfunc.h"
++#include "lgc.h"
++#include "lobject.h"
++#include "lopcodes.h"
++#include "lstate.h"
++#include "lstring.h"
++#include "ltable.h"
++#include "ltm.h"
++#include "lvm.h"
++
++
++
++/* limit for table tag-method chains (to avoid loops) */
++#define MAXTAGLOOP	100
++
++
++const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
++  lua_Number num;
++  if (ttisnumber(obj)) return obj;
++  if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
++    setnvalue(n, num);
++    return n;
++  }
++  else
++    return NULL;
++}
++
++
++int luaV_tostring (lua_State *L, StkId obj) {
++  if (!ttisnumber(obj))
++    return 0;
++  else {
++    char s[LUAI_MAXNUMBER2STR];
++    lua_Number n = nvalue(obj);
++    lua_number2str(s, n);
++    setsvalue2s(L, obj, luaS_new(L, s));
++    return 1;
++  }
++}
++
++
++static void traceexec (lua_State *L, const Instruction *pc) {
++  lu_byte mask = L->hookmask;
++  const Instruction *oldpc = L->savedpc;
++  L->savedpc = pc;
++  if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
++    resethookcount(L);
++    luaD_callhook(L, LUA_HOOKCOUNT, -1);
++  }
++  if (mask & LUA_MASKLINE) {
++    Proto *p = ci_func(L->ci)->l.p;
++    int npc = pcRel(pc, p);
++    int newline = getline(p, npc);
++    /* call linehook when enter a new function, when jump back (loop),
++       or when enter a new line */
++    if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p)))
++      luaD_callhook(L, LUA_HOOKLINE, newline);
++  }
++}
++
++
++static void callTMres (lua_State *L, StkId res, const TValue *f,
++                        const TValue *p1, const TValue *p2) {
++  ptrdiff_t result = savestack(L, res);
++  setobj2s(L, L->top, f);  /* push function */
++  setobj2s(L, L->top+1, p1);  /* 1st argument */
++  setobj2s(L, L->top+2, p2);  /* 2nd argument */
++  luaD_checkstack(L, 3);
++  L->top += 3;
++  luaD_call(L, L->top - 3, 1);
++  res = restorestack(L, result);
++  L->top--;
++  setobjs2s(L, res, L->top);
++}
++
++
++
++static void callTM (lua_State *L, const TValue *f, const TValue *p1,
++                    const TValue *p2, const TValue *p3) {
++  setobj2s(L, L->top, f);  /* push function */
++  setobj2s(L, L->top+1, p1);  /* 1st argument */
++  setobj2s(L, L->top+2, p2);  /* 2nd argument */
++  setobj2s(L, L->top+3, p3);  /* 3th argument */
++  luaD_checkstack(L, 4);
++  L->top += 4;
++  luaD_call(L, L->top - 4, 0);
++}
++
++
++void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
++  int loop;
++  for (loop = 0; loop < MAXTAGLOOP; loop++) {
++    const TValue *tm;
++    if (ttistable(t)) {  /* `t' is a table? */
++      Table *h = hvalue(t);
++      const TValue *res = luaH_get(h, key); /* do a primitive get */
++      if (!ttisnil(res) ||  /* result is no nil? */
++          (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
++        setobj2s(L, val, res);
++        return;
++      }
++      /* else will try the tag method */
++    }
++    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
++      luaG_typeerror(L, t, "index");
++    if (ttisfunction(tm)) {
++      callTMres(L, val, tm, t, key);
++      return;
++    }
++    t = tm;  /* else repeat with `tm' */ 
++  }
++  luaG_runerror(L, "loop in gettable");
++}
++
++
++void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
++  int loop;
++  for (loop = 0; loop < MAXTAGLOOP; loop++) {
++    const TValue *tm;
++    if (ttistable(t)) {  /* `t' is a table? */
++      Table *h = hvalue(t);
++      TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
++      if (!ttisnil(oldval) ||  /* result is no nil? */
++          (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
++        setobj2t(L, oldval, val);
++        luaC_barriert(L, h, val);
++        return;
++      }
++      /* else will try the tag method */
++    }
++    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
++      luaG_typeerror(L, t, "index");
++    if (ttisfunction(tm)) {
++      callTM(L, tm, t, key, val);
++      return;
++    }
++    t = tm;  /* else repeat with `tm' */ 
++  }
++  luaG_runerror(L, "loop in settable");
++}
++
++
++static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
++                       StkId res, TMS event) {
++  const TValue *tm = luaT_gettmbyobj(L, p1, event);  /* try first operand */
++  if (ttisnil(tm))
++    tm = luaT_gettmbyobj(L, p2, event);  /* try second operand */
++  if (ttisnil(tm)) return 0;
++  callTMres(L, res, tm, p1, p2);
++  return 1;
++}
++
++
++static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
++                                  TMS event) {
++  const TValue *tm1 = fasttm(L, mt1, event);
++  const TValue *tm2;
++  if (tm1 == NULL) return NULL;  /* no metamethod */
++  if (mt1 == mt2) return tm1;  /* same metatables => same metamethods */
++  tm2 = fasttm(L, mt2, event);
++  if (tm2 == NULL) return NULL;  /* no metamethod */
++  if (luaO_rawequalObj(tm1, tm2))  /* same metamethods? */
++    return tm1;
++  return NULL;
++}
++
++
++static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2,
++                         TMS event) {
++  const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
++  const TValue *tm2;
++  if (ttisnil(tm1)) return -1;  /* no metamethod? */
++  tm2 = luaT_gettmbyobj(L, p2, event);
++  if (!luaO_rawequalObj(tm1, tm2))  /* different metamethods? */
++    return -1;
++  callTMres(L, L->top, tm1, p1, p2);
++  return !l_isfalse(L->top);
++}
++
++
++static int l_strcmp (const TString *ls, const TString *rs) {
++  const char *l = getstr(ls);
++  size_t ll = ls->tsv.len;
++  const char *r = getstr(rs);
++  size_t lr = rs->tsv.len;
++  for (;;) {
++    int temp = strcoll(l, r);
++    if (temp != 0) return temp;
++    else {  /* strings are equal up to a `\0' */
++      size_t len = strlen(l);  /* index of first `\0' in both strings */
++      if (len == lr)  /* r is finished? */
++        return (len == ll) ? 0 : 1;
++      else if (len == ll)  /* l is finished? */
++        return -1;  /* l is smaller than r (because r is not finished) */
++      /* both strings longer than `len'; go on comparing (after the `\0') */
++      len++;
++      l += len; ll -= len; r += len; lr -= len;
++    }
++  }
++}
++
++
++int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
++  int res;
++  if (ttype(l) != ttype(r))
++    return luaG_ordererror(L, l, r);
++  else if (ttisnumber(l))
++    return luai_numlt(nvalue(l), nvalue(r));
++  else if (ttisstring(l))
++    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
++  else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
++    return res;
++  return luaG_ordererror(L, l, r);
++}
++
++
++static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
++  int res;
++  if (ttype(l) != ttype(r))
++    return luaG_ordererror(L, l, r);
++  else if (ttisnumber(l))
++    return luai_numle(nvalue(l), nvalue(r));
++  else if (ttisstring(l))
++    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
++  else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
++    return res;
++  else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */
++    return !res;
++  return luaG_ordererror(L, l, r);
++}
++
++
++int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
++  const TValue *tm;
++  lua_assert(ttype(t1) == ttype(t2));
++  switch (ttype(t1)) {
++    case LUA_TNIL: return 1;
++    case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
++    case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */
++    case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
++    case LUA_TUSERDATA: {
++      if (uvalue(t1) == uvalue(t2)) return 1;
++      tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
++                         TM_EQ);
++      break;  /* will try TM */
++    }
++    case LUA_TTABLE: {
++      if (hvalue(t1) == hvalue(t2)) return 1;
++      tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
++      break;  /* will try TM */
++    }
++    default: return gcvalue(t1) == gcvalue(t2);
++  }
++  if (tm == NULL) return 0;  /* no TM? */
++  callTMres(L, L->top, tm, t1, t2);  /* call TM */
++  return !l_isfalse(L->top);
++}
++
++
++void luaV_concat (lua_State *L, int total, int last) {
++  do {
++    StkId top = L->base + last + 1;
++    int n = 2;  /* number of elements handled in this pass (at least 2) */
++    if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
++      if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
++        luaG_concaterror(L, top-2, top-1);
++    } else if (tsvalue(top-1)->len == 0)  /* second op is empty? */
++      (void)tostring(L, top - 2);  /* result is first op (as string) */
++    else {
++      /* at least two string values; get as many as possible */
++      size_t tl = tsvalue(top-1)->len;
++      char *buffer;
++      int i;
++      /* collect total length */
++      for (n = 1; n < total && tostring(L, top-n-1); n++) {
++        size_t l = tsvalue(top-n-1)->len;
++        if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
++        tl += l;
++      }
++      buffer = luaZ_openspace(L, &G(L)->buff, tl);
++      tl = 0;
++      for (i=n; i>0; i--) {  /* concat all strings */
++        size_t l = tsvalue(top-i)->len;
++        memcpy(buffer+tl, svalue(top-i), l);
++        tl += l;
++      }
++      setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
++    }
++    total -= n-1;  /* got `n' strings to create 1 new */
++    last -= n-1;
++  } while (total > 1);  /* repeat until only 1 result left */
++}
++
++
++static void Arith (lua_State *L, StkId ra, const TValue *rb,
++                   const TValue *rc, TMS op) {
++  TValue tempb, tempc;
++  const TValue *b, *c;
++  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
++      (c = luaV_tonumber(rc, &tempc)) != NULL) {
++    lua_Number nb = nvalue(b), nc = nvalue(c);
++    switch (op) {
++      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
++      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
++      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
++      case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
++      case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
++      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
++      case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
++      default: lua_assert(0); break;
++    }
++  }
++  else if (!call_binTM(L, rb, rc, ra, op))
++    luaG_aritherror(L, rb, rc);
++}
++
++
++
++/*
++** some macros for common tasks in `luaV_execute'
++*/
++
++#define runtime_check(L, c)	{ if (!(c)) break; }
++
++#define RA(i)	(base+GETARG_A(i))
++/* to be used after possible stack reallocation */
++#define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
++#define RC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
++#define RKB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
++	ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
++#define RKC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
++	ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
++#define KBx(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i))
++
++
++#define dojump(L,pc,i)	{(pc) += (i); luai_threadyield(L);}
++
++
++#define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; }
++
++
++#define arith_op(op,tm) { \
++        TValue *rb = RKB(i); \
++        TValue *rc = RKC(i); \
++        if (ttisnumber(rb) && ttisnumber(rc)) { \
++          lua_Number nb = nvalue(rb), nc = nvalue(rc); \
++          setnvalue(ra, op(nb, nc)); \
++        } \
++        else \
++          Protect(Arith(L, ra, rb, rc, tm)); \
++      }
++
++
++
++void luaV_execute (lua_State *L, int nexeccalls) {
++  LClosure *cl;
++  StkId base;
++  TValue *k;
++  const Instruction *pc;
++ reentry:  /* entry point */
++  lua_assert(isLua(L->ci));
++  pc = L->savedpc;
++  cl = &clvalue(L->ci->func)->l;
++  base = L->base;
++  k = cl->p->k;
++  /* main loop of interpreter */
++  for (;;) {
++    const Instruction i = *pc++;
++    StkId ra;
++    if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
++        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
++      traceexec(L, pc);
++      if (L->status == LUA_YIELD) {  /* did hook yield? */
++        L->savedpc = pc - 1;
++        return;
++      }
++      base = L->base;
++    }
++    /* warning!! several calls may realloc the stack and invalidate `ra' */
++    ra = RA(i);
++    lua_assert(base == L->base && L->base == L->ci->base);
++    lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
++    lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
++    switch (GET_OPCODE(i)) {
++      case OP_MOVE: {
++        setobjs2s(L, ra, RB(i));
++        continue;
++      }
++      case OP_LOADK: {
++        setobj2s(L, ra, KBx(i));
++        continue;
++      }
++      case OP_LOADBOOL: {
++        setbvalue(ra, GETARG_B(i));
++        if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
++        continue;
++      }
++      case OP_LOADNIL: {
++        TValue *rb = RB(i);
++        do {
++          setnilvalue(rb--);
++        } while (rb >= ra);
++        continue;
++      }
++      case OP_GETUPVAL: {
++        int b = GETARG_B(i);
++        setobj2s(L, ra, cl->upvals[b]->v);
++        continue;
++      }
++      case OP_GETGLOBAL: {
++        TValue g;
++        TValue *rb = KBx(i);
++        sethvalue(L, &g, cl->env);
++        lua_assert(ttisstring(rb));
++        Protect(luaV_gettable(L, &g, rb, ra));
++        continue;
++      }
++      case OP_GETTABLE: {
++        Protect(luaV_gettable(L, RB(i), RKC(i), ra));
++        continue;
++      }
++      case OP_SETGLOBAL: {
++        TValue g;
++        sethvalue(L, &g, cl->env);
++        lua_assert(ttisstring(KBx(i)));
++        Protect(luaV_settable(L, &g, KBx(i), ra));
++        continue;
++      }
++      case OP_SETUPVAL: {
++        UpVal *uv = cl->upvals[GETARG_B(i)];
++        setobj(L, uv->v, ra);
++        luaC_barrier(L, uv, ra);
++        continue;
++      }
++      case OP_SETTABLE: {
++        Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
++        continue;
++      }
++      case OP_NEWTABLE: {
++        int b = GETARG_B(i);
++        int c = GETARG_C(i);
++        sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
++        Protect(luaC_checkGC(L));
++        continue;
++      }
++      case OP_SELF: {
++        StkId rb = RB(i);
++        setobjs2s(L, ra+1, rb);
++        Protect(luaV_gettable(L, rb, RKC(i), ra));
++        continue;
++      }
++      case OP_ADD: {
++        arith_op(luai_numadd, TM_ADD);
++        continue;
++      }
++      case OP_SUB: {
++        arith_op(luai_numsub, TM_SUB);
++        continue;
++      }
++      case OP_MUL: {
++        arith_op(luai_nummul, TM_MUL);
++        continue;
++      }
++      case OP_DIV: {
++        arith_op(luai_numdiv, TM_DIV);
++        continue;
++      }
++      case OP_MOD: {
++        arith_op(luai_nummod, TM_MOD);
++        continue;
++      }
++      case OP_POW: {
++        arith_op(luai_numpow, TM_POW);
++        continue;
++      }
++      case OP_UNM: {
++        TValue *rb = RB(i);
++        if (ttisnumber(rb)) {
++          lua_Number nb = nvalue(rb);
++          setnvalue(ra, luai_numunm(nb));
++        }
++        else {
++          Protect(Arith(L, ra, rb, rb, TM_UNM));
++        }
++        continue;
++      }
++      case OP_NOT: {
++        int res = l_isfalse(RB(i));  /* next assignment may change this value */
++        setbvalue(ra, res);
++        continue;
++      }
++      case OP_LEN: {
++        const TValue *rb = RB(i);
++        switch (ttype(rb)) {
++          case LUA_TTABLE: {
++            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
++            break;
++          }
++          case LUA_TSTRING: {
++            setnvalue(ra, cast_num(tsvalue(rb)->len));
++            break;
++          }
++          default: {  /* try metamethod */
++            Protect(
++              if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
++                luaG_typeerror(L, rb, "get length of");
++            )
++          }
++        }
++        continue;
++      }
++      case OP_CONCAT: {
++        int b = GETARG_B(i);
++        int c = GETARG_C(i);
++        Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
++        setobjs2s(L, RA(i), base+b);
++        continue;
++      }
++      case OP_JMP: {
++        dojump(L, pc, GETARG_sBx(i));
++        continue;
++      }
++      case OP_EQ: {
++        TValue *rb = RKB(i);
++        TValue *rc = RKC(i);
++        Protect(
++          if (equalobj(L, rb, rc) == GETARG_A(i))
++            dojump(L, pc, GETARG_sBx(*pc));
++        )
++        pc++;
++        continue;
++      }
++      case OP_LT: {
++        Protect(
++          if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
++            dojump(L, pc, GETARG_sBx(*pc));
++        )
++        pc++;
++        continue;
++      }
++      case OP_LE: {
++        Protect(
++          if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
++            dojump(L, pc, GETARG_sBx(*pc));
++        )
++        pc++;
++        continue;
++      }
++      case OP_TEST: {
++        if (l_isfalse(ra) != GETARG_C(i))
++          dojump(L, pc, GETARG_sBx(*pc));
++        pc++;
++        continue;
++      }
++      case OP_TESTSET: {
++        TValue *rb = RB(i);
++        if (l_isfalse(rb) != GETARG_C(i)) {
++          setobjs2s(L, ra, rb);
++          dojump(L, pc, GETARG_sBx(*pc));
++        }
++        pc++;
++        continue;
++      }
++      case OP_CALL: {
++        int b = GETARG_B(i);
++        int nresults = GETARG_C(i) - 1;
++        if (b != 0) L->top = ra+b;  /* else previous instruction set top */
++        L->savedpc = pc;
++        switch (luaD_precall(L, ra, nresults)) {
++          case PCRLUA: {
++            nexeccalls++;
++            goto reentry;  /* restart luaV_execute over new Lua function */
++          }
++          case PCRC: {
++            /* it was a C function (`precall' called it); adjust results */
++            if (nresults >= 0) L->top = L->ci->top;
++            base = L->base;
++            continue;
++          }
++          default: {
++            return;  /* yield */
++          }
++        }
++      }
++      case OP_TAILCALL: {
++        int b = GETARG_B(i);
++        if (b != 0) L->top = ra+b;  /* else previous instruction set top */
++        L->savedpc = pc;
++        lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
++        switch (luaD_precall(L, ra, LUA_MULTRET)) {
++          case PCRLUA: {
++            /* tail call: put new frame in place of previous one */
++            CallInfo *ci = L->ci - 1;  /* previous frame */
++            int aux;
++            StkId func = ci->func;
++            StkId pfunc = (ci+1)->func;  /* previous function index */
++            if (L->openupval) luaF_close(L, ci->base);
++            L->base = ci->base = ci->func + ((ci+1)->base - pfunc);
++            for (aux = 0; pfunc+aux < L->top; aux++)  /* move frame down */
++              setobjs2s(L, func+aux, pfunc+aux);
++            ci->top = L->top = func+aux;  /* correct top */
++            lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);
++            ci->savedpc = L->savedpc;
++            ci->tailcalls++;  /* one more call lost */
++            L->ci--;  /* remove new frame */
++            goto reentry;
++          }
++          case PCRC: {  /* it was a C function (`precall' called it) */
++            base = L->base;
++            continue;
++          }
++          default: {
++            return;  /* yield */
++          }
++        }
++      }
++      case OP_RETURN: {
++        int b = GETARG_B(i);
++        if (b != 0) L->top = ra+b-1;
++        if (L->openupval) luaF_close(L, base);
++        L->savedpc = pc;
++        b = luaD_poscall(L, ra);
++        if (--nexeccalls == 0)  /* was previous function running `here'? */
++          return;  /* no: return */
++        else {  /* yes: continue its execution */
++          if (b) L->top = L->ci->top;
++          lua_assert(isLua(L->ci));
++          lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL);
++          goto reentry;
++        }
++      }
++      case OP_FORLOOP: {
++        lua_Number step = nvalue(ra+2);
++        lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
++        lua_Number limit = nvalue(ra+1);
++        if (luai_numlt(0, step) ? luai_numle(idx, limit)
++                                : luai_numle(limit, idx)) {
++          dojump(L, pc, GETARG_sBx(i));  /* jump back */
++          setnvalue(ra, idx);  /* update internal index... */
++          setnvalue(ra+3, idx);  /* ...and external index */
++        }
++        continue;
++      }
++      case OP_FORPREP: {
++        const TValue *init = ra;
++        const TValue *plimit = ra+1;
++        const TValue *pstep = ra+2;
++        L->savedpc = pc;  /* next steps may throw errors */
++        if (!tonumber(init, ra))
++          luaG_runerror(L, LUA_QL("for") " initial value must be a number");
++        else if (!tonumber(plimit, ra+1))
++          luaG_runerror(L, LUA_QL("for") " limit must be a number");
++        else if (!tonumber(pstep, ra+2))
++          luaG_runerror(L, LUA_QL("for") " step must be a number");
++        setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
++        dojump(L, pc, GETARG_sBx(i));
++        continue;
++      }
++      case OP_TFORLOOP: {
++        StkId cb = ra + 3;  /* call base */
++        setobjs2s(L, cb+2, ra+2);
++        setobjs2s(L, cb+1, ra+1);
++        setobjs2s(L, cb, ra);
++        L->top = cb+3;  /* func. + 2 args (state and index) */
++        Protect(luaD_call(L, cb, GETARG_C(i)));
++        L->top = L->ci->top;
++        cb = RA(i) + 3;  /* previous call may change the stack */
++        if (!ttisnil(cb)) {  /* continue loop? */
++          setobjs2s(L, cb-1, cb);  /* save control variable */
++          dojump(L, pc, GETARG_sBx(*pc));  /* jump back */
++        }
++        pc++;
++        continue;
++      }
++      case OP_SETLIST: {
++        int n = GETARG_B(i);
++        int c = GETARG_C(i);
++        int last;
++        Table *h;
++        if (n == 0) {
++          n = cast_int(L->top - ra) - 1;
++          L->top = L->ci->top;
++        }
++        if (c == 0) c = cast_int(*pc++);
++        runtime_check(L, ttistable(ra));
++        h = hvalue(ra);
++        last = ((c-1)*LFIELDS_PER_FLUSH) + n;
++        if (last > h->sizearray)  /* needs more space? */
++          luaH_resizearray(L, h, last);  /* pre-alloc it at once */
++        for (; n > 0; n--) {
++          TValue *val = ra+n;
++          setobj2t(L, luaH_setnum(L, h, last--), val);
++          luaC_barriert(L, h, val);
++        }
++        continue;
++      }
++      case OP_CLOSE: {
++        luaF_close(L, ra);
++        continue;
++      }
++      case OP_CLOSURE: {
++        Proto *p;
++        Closure *ncl;
++        int nup, j;
++        p = cl->p->p[GETARG_Bx(i)];
++        nup = p->nups;
++        ncl = luaF_newLclosure(L, nup, cl->env);
++        ncl->l.p = p;
++        for (j=0; j<nup; j++, pc++) {
++          if (GET_OPCODE(*pc) == OP_GETUPVAL)
++            ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
++          else {
++            lua_assert(GET_OPCODE(*pc) == OP_MOVE);
++            ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
++          }
++        }
++        setclvalue(L, ra, ncl);
++        Protect(luaC_checkGC(L));
++        continue;
++      }
++      case OP_VARARG: {
++        int b = GETARG_B(i) - 1;
++        int j;
++        CallInfo *ci = L->ci;
++        int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1;
++        if (b == LUA_MULTRET) {
++          Protect(luaD_checkstack(L, n));
++          ra = RA(i);  /* previous call may change the stack */
++          b = n;
++          L->top = ra + n;
++        }
++        for (j = 0; j < b; j++) {
++          if (j < n) {
++            setobjs2s(L, ra + j, ci->base - n + j);
++          }
++          else {
++            setnilvalue(ra + j);
++          }
++        }
++        continue;
++      }
++    }
++  }
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lvm.h
+@@ -0,0 +1,36 @@
++/*
++** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lua virtual machine
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lvm_h
++#define lvm_h
++
++
++#include "ldo.h"
++#include "lobject.h"
++#include "ltm.h"
++
++
++#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
++
++#define tonumber(o,n)	(ttype(o) == LUA_TNUMBER || \
++                         (((o) = luaV_tonumber(o,n)) != NULL))
++
++#define equalobj(L,o1,o2) \
++	(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
++
++
++LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
++LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2);
++LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n);
++LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj);
++LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
++                                            StkId val);
++LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
++                                            StkId val);
++LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls);
++LUAI_FUNC void luaV_concat (lua_State *L, int total, int last);
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/lua/lzio.c
+@@ -0,0 +1,81 @@
++/*
++** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
++** a generic input stream interface
++** See Copyright Notice in lua.h
++*/
++
++#include <string.h>
++
++#define lzio_c
++#define LUA_CORE
++
++#include "lua.h"
++
++#include "llimits.h"
++#include "lmem.h"
++#include "lstate.h"
++#include "lzio.h"
++
++
++int luaZ_fill (ZIO *z) {
++  size_t size;
++  lua_State *L = z->L;
++  const char *buff;
++  lua_unlock(L);
++  buff = z->reader(L, z->data, &size);
++  lua_lock(L);
++  if (buff == NULL || size == 0) return EOZ;
++  z->n = size - 1;
++  z->p = buff;
++  return char2int(*(z->p++));
++}
++
++
++int luaZ_lookahead (ZIO *z) {
++  if (z->n == 0) {
++    if (luaZ_fill(z) == EOZ)
++      return EOZ;
++    else {
++      z->n++;  /* luaZ_fill removed first byte; put back it */
++      z->p--;
++    }
++  }
++  return char2int(*z->p);
++}
++
++
++void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
++  z->L = L;
++  z->reader = reader;
++  z->data = data;
++  z->n = 0;
++  z->p = NULL;
++}
++
++
++/* --------------------------------------------------------------- read --- */
++size_t luaZ_read (ZIO *z, void *b, size_t n) {
++  while (n) {
++    size_t m;
++    if (luaZ_lookahead(z) == EOZ)
++      return n;  /* return number of missing bytes */
++    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */
++    memcpy(b, z->p, m);
++    z->n -= m;
++    z->p += m;
++    b = (char *)b + m;
++    n -= m;
++  }
++  return 0;
++}
++
++/* ------------------------------------------------------------------------ */
++char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
++  if (n > buff->buffsize) {
++    if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
++    luaZ_resizebuffer(L, buff, n);
++  }
++  return buff->buffer;
++}
++
++
+--- /dev/null
++++ b/extensions/LUA/lua/lzio.h
+@@ -0,0 +1,67 @@
++/*
++** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $
++** Buffered streams
++** See Copyright Notice in lua.h
++*/
++
++
++#ifndef lzio_h
++#define lzio_h
++
++#include "lua.h"
++
++#include "lmem.h"
++
++
++#define EOZ	(-1)			/* end of stream */
++
++typedef struct Zio ZIO;
++
++#define char2int(c)	cast(int, cast(unsigned char, (c)))
++
++#define zgetc(z)  (((z)->n--)>0 ?  char2int(*(z)->p++) : luaZ_fill(z))
++
++typedef struct Mbuffer {
++  char *buffer;
++  size_t n;
++  size_t buffsize;
++} Mbuffer;
++
++#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
++
++#define luaZ_buffer(buff)	((buff)->buffer)
++#define luaZ_sizebuffer(buff)	((buff)->buffsize)
++#define luaZ_bufflen(buff)	((buff)->n)
++
++#define luaZ_resetbuffer(buff) ((buff)->n = 0)
++
++
++#define luaZ_resizebuffer(L, buff, size) \
++	(luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
++	(buff)->buffsize = size)
++
++#define luaZ_freebuffer(L, buff)	luaZ_resizebuffer(L, buff, 0)
++
++
++LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
++LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
++                                        void *data);
++LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n);	/* read next n bytes */
++LUAI_FUNC int luaZ_lookahead (ZIO *z);
++
++
++
++/* --------- Private Part ------------------ */
++
++struct Zio {
++  size_t n;			/* bytes still unread */
++  const char *p;		/* current position in buffer */
++  lua_Reader reader;
++  void* data;			/* additional data */
++  lua_State *L;			/* Lua state (for reader) */
++};
++
++
++LUAI_FUNC int luaZ_fill (ZIO *z);
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/Makefile
+@@ -0,0 +1,389 @@
++# Makefile.in generated by automake 1.11.1 from Makefile.am.
++# extensions/LUA/Makefile.  Generated from Makefile.in by configure.
++
++# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
++# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
++# Inc.
++# This Makefile.in is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
++# PARTICULAR PURPOSE.
++
++
++
++# -*- Makefile -*-
++# AUTOMAKE
++
++pkgdatadir = $(datadir)/xtables-addons
++pkgincludedir = $(includedir)/xtables-addons
++pkglibdir = $(libdir)/xtables-addons
++pkglibexecdir = $(libexecdir)/xtables-addons
++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
++install_sh_DATA = $(install_sh) -c -m 644
++install_sh_PROGRAM = $(install_sh) -c
++install_sh_SCRIPT = $(install_sh) -c
++INSTALL_HEADER = $(INSTALL_DATA)
++transform = $(program_transform_name)
++NORMAL_INSTALL = :
++PRE_INSTALL = :
++POST_INSTALL = :
++NORMAL_UNINSTALL = :
++PRE_UNINSTALL = :
++POST_UNINSTALL = :
++build_triplet = i686-pc-linux-gnu
++host_triplet = i686-pc-linux-gnu
++DIST_COMMON = $(srcdir)/../../Makefile.extra $(srcdir)/Makefile.am \
++	$(srcdir)/Makefile.in
++subdir = extensions/LUA
++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
++am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
++	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
++	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
++	$(top_srcdir)/configure.ac
++am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
++	$(ACLOCAL_M4)
++mkinstalldirs = $(install_sh) -d
++CONFIG_HEADER = $(top_builddir)/config.h
++CONFIG_CLEAN_FILES =
++CONFIG_CLEAN_VPATH_FILES =
++SOURCES =
++DIST_SOURCES =
++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
++ACLOCAL = ${SHELL} /home/andre/Dropbox/xtables-addons/missing --run aclocal-1.11
++AMTAR = ${SHELL} /home/andre/Dropbox/xtables-addons/missing --run tar
++AR = ar
++AUTOCONF = ${SHELL} /home/andre/Dropbox/xtables-addons/missing --run autoconf
++AUTOHEADER = ${SHELL} /home/andre/Dropbox/xtables-addons/missing --run autoheader
++AUTOMAKE = ${SHELL} /home/andre/Dropbox/xtables-addons/missing --run automake-1.11
++AWK = mawk
++CC = gcc
++CCDEPMODE = depmode=gcc3
++CFLAGS = -g -O2
++CPP = gcc -E
++CPPFLAGS = 
++CYGPATH_W = echo
++DEFS = -DHAVE_CONFIG_H
++DEPDIR = .deps
++DSYMUTIL = 
++DUMPBIN = 
++ECHO_C = 
++ECHO_N = -n
++ECHO_T = 
++EGREP = /bin/grep -E
++EXEEXT = 
++FGREP = /bin/grep -F
++GREP = /bin/grep
++INSTALL = /usr/bin/install -c
++INSTALL_DATA = ${INSTALL} -m 644
++INSTALL_PROGRAM = ${INSTALL}
++INSTALL_SCRIPT = ${INSTALL}
++INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
++LD = /usr/bin/ld
++LDFLAGS = 
++LIBOBJS = 
++LIBS = 
++LIBTOOL = $(SHELL) $(top_builddir)/libtool
++LIPO = 
++LN_S = ln -s
++LTLIBOBJS = 
++MAKEINFO = ${SHELL} /home/andre/Dropbox/xtables-addons/missing --run makeinfo
++MKDIR_P = /bin/mkdir -p
++NM = /usr/bin/nm -B
++NMEDIT = 
++OBJDUMP = objdump
++OBJEXT = o
++OTOOL = 
++OTOOL64 = 
++PACKAGE = xtables-addons
++PACKAGE_BUGREPORT = 
++PACKAGE_NAME = xtables-addons
++PACKAGE_STRING = xtables-addons 1.21
++PACKAGE_TARNAME = xtables-addons
++PACKAGE_URL = 
++PACKAGE_VERSION = 1.21
++PATH_SEPARATOR = :
++PKG_CONFIG = /usr/bin/pkg-config
++RANLIB = ranlib
++SED = /bin/sed
++SET_MAKE = 
++SHELL = /bin/bash
++STRIP = strip
++VERSION = 1.21
++abs_builddir = /home/andre/Dropbox/xtables-addons/extensions/LUA
++abs_srcdir = /home/andre/Dropbox/xtables-addons/extensions/LUA
++abs_top_builddir = /home/andre/Dropbox/xtables-addons
++abs_top_srcdir = /home/andre/Dropbox/xtables-addons
++ac_ct_CC = gcc
++ac_ct_DUMPBIN = 
++am__include = include
++am__leading_dot = .
++am__quote = 
++am__tar = ${AMTAR} chof - "$$tardir"
++am__untar = ${AMTAR} xf -
++bindir = ${exec_prefix}/bin
++build = i686-pc-linux-gnu
++build_alias = 
++build_cpu = i686
++build_os = linux-gnu
++build_vendor = pc
++builddir = .
++datadir = ${datarootdir}
++datarootdir = ${prefix}/share
++docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
++dvidir = ${docdir}
++exec_prefix = ${prefix}
++host = i686-pc-linux-gnu
++host_alias = 
++host_cpu = i686
++host_os = linux-gnu
++host_vendor = pc
++htmldir = ${docdir}
++includedir = ${prefix}/include
++infodir = ${datarootdir}/info
++install_sh = ${SHELL} /home/andre/Dropbox/xtables-addons/install-sh
++kbuilddir = /lib/modules/2.6.33-020633-generic/build
++kinclude_CFLAGS =  -I /lib/modules/2.6.33-020633-generic/build/include
++ksourcedir = 
++libdir = ${exec_prefix}/lib
++libexecdir = ${exec_prefix}/libexec
++libxtables_CFLAGS =  
++libxtables_LIBS = -L/lib -lxtables  
++localedir = ${datarootdir}/locale
++localstatedir = ${prefix}/var
++lt_ECHO = echo
++mandir = ${datarootdir}/man
++mkdir_p = /bin/mkdir -p
++oldincludedir = /usr/include
++pdfdir = ${docdir}
++prefix = /usr/local
++program_transform_name = s,x,x,
++psdir = ${docdir}
++regular_CFLAGS = -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 	-D_REENTRANT -Wall -Waggregate-return -Wmissing-declarations 	-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes 	-Winline -pipe -DXTABLES_LIBDIR=\"${xtlibdir}\"
++sbindir = ${exec_prefix}/sbin
++sharedstatedir = ${prefix}/com
++srcdir = .
++sysconfdir = ${prefix}/etc
++target_alias = 
++top_build_prefix = ../../
++top_builddir = ../..
++top_srcdir = ../..
++xtlibdir = ${libexecdir}/xtables
++XA_SRCDIR = ${srcdir}
++XA_TOPSRCDIR = ${top_srcdir}
++XA_ABSTOPSRCDIR = ${abs_top_srcdir}
++_mcall = -f ${top_builddir}/Makefile.iptrules
++all: all-am
++
++.SUFFIXES:
++$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(srcdir)/../../Makefile.extra $(am__configure_deps)
++	@for dep in $?; do \
++	  case '$(am__configure_deps)' in \
++	    *$$dep*) \
++	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
++	        && { if test -f $@; then exit 0; else break; fi; }; \
++	      exit 1;; \
++	  esac; \
++	done; \
++	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign extensions/LUA/Makefile'; \
++	$(am__cd) $(top_srcdir) && \
++	  $(AUTOMAKE) --foreign extensions/LUA/Makefile
++.PRECIOUS: Makefile
++Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
++	@case '$?' in \
++	  *config.status*) \
++	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
++	  *) \
++	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
++	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
++	esac;
++
++$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
++	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++
++$(top_srcdir)/configure:  $(am__configure_deps)
++	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
++	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++$(am__aclocal_m4_deps):
++
++mostlyclean-libtool:
++	-rm -f *.lo
++
++clean-libtool:
++	-rm -rf .libs _libs
++tags: TAGS
++TAGS:
++
++ctags: CTAGS
++CTAGS:
++
++
++distdir: $(DISTFILES)
++	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++	list='$(DISTFILES)'; \
++	  dist_files=`for file in $$list; do echo $$file; done | \
++	  sed -e "s|^$$srcdirstrip/||;t" \
++	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
++	case $$dist_files in \
++	  */*) $(MKDIR_P) `echo "$$dist_files" | \
++			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
++			   sort -u` ;; \
++	esac; \
++	for file in $$dist_files; do \
++	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
++	  if test -d $$d/$$file; then \
++	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
++	    if test -d "$(distdir)/$$file"; then \
++	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++	    fi; \
++	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
++	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
++	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++	    fi; \
++	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
++	  else \
++	    test -f "$(distdir)/$$file" \
++	    || cp -p $$d/$$file "$(distdir)/$$file" \
++	    || exit 1; \
++	  fi; \
++	done
++check-am: all-am
++check: check-am
++all-am: Makefile all-local
++installdirs:
++install: install-am
++install-exec: install-exec-am
++install-data: install-data-am
++uninstall: uninstall-am
++
++install-am: all-am
++	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
++
++installcheck: installcheck-am
++install-strip:
++	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
++	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
++	  `test -z '$(STRIP)' || \
++	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
++mostlyclean-generic:
++
++clean-generic:
++
++distclean-generic:
++	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
++	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
++
++maintainer-clean-generic:
++	@echo "This command is intended for maintainers to use"
++	@echo "it deletes files that may require special tools to rebuild."
++clean: clean-am
++
++clean-am: clean-generic clean-libtool clean-local mostlyclean-am
++
++distclean: distclean-am
++	-rm -f Makefile
++distclean-am: clean-am distclean-generic
++
++dvi: dvi-am
++
++dvi-am:
++
++html: html-am
++
++html-am:
++
++info: info-am
++
++info-am:
++
++install-data-am:
++
++install-dvi: install-dvi-am
++
++install-dvi-am:
++
++install-exec-am: install-exec-local
++
++install-html: install-html-am
++
++install-html-am:
++
++install-info: install-info-am
++
++install-info-am:
++
++install-man:
++
++install-pdf: install-pdf-am
++
++install-pdf-am:
++
++install-ps: install-ps-am
++
++install-ps-am:
++
++installcheck-am:
++
++maintainer-clean: maintainer-clean-am
++	-rm -f Makefile
++maintainer-clean-am: distclean-am maintainer-clean-generic
++
++mostlyclean: mostlyclean-am
++
++mostlyclean-am: mostlyclean-generic mostlyclean-libtool
++
++pdf: pdf-am
++
++pdf-am:
++
++ps: ps-am
++
++ps-am:
++
++uninstall-am:
++
++.MAKE: install-am install-strip
++
++.PHONY: all all-am all-local check check-am clean clean-generic \
++	clean-libtool clean-local distclean distclean-generic \
++	distclean-libtool distdir dvi dvi-am html html-am info info-am \
++	install install-am install-data install-data-am install-dvi \
++	install-dvi-am install-exec install-exec-am install-exec-local \
++	install-html install-html-am install-info install-info-am \
++	install-man install-pdf install-pdf-am install-ps \
++	install-ps-am install-strip installcheck installcheck-am \
++	installdirs maintainer-clean maintainer-clean-generic \
++	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
++	ps ps-am uninstall uninstall-am
++
++export XA_SRCDIR
++export XA_TOPSRCDIR
++export XA_ABSTOPSRCDIR
++
++all-local: user-all-local
++
++install-exec-local: user-install-local
++
++clean-local: user-clean-local
++
++user-all-local:
++	${MAKE} ${_mcall} all;
++
++# Have no user-install-data-local ATM
++user-install-local: user-install-exec-local
++
++user-install-exec-local:
++	${MAKE} ${_mcall} install;
++
++user-clean-local:
++	${MAKE} ${_mcall} clean;
++
++# Tell versions [3.59,3.63) of GNU make to not export all variables.
++# Otherwise a system limit (for SysV at least) may be exceeded.
++.NOEXPORT:
++
+--- /dev/null
++++ b/extensions/LUA/Makefile.am
+@@ -0,0 +1 @@
++include ../../Makefile.extra
+--- /dev/null
++++ b/extensions/LUA/Makefile.in
+@@ -0,0 +1,389 @@
++# Makefile.in generated by automake 1.11.1 from Makefile.am.
++# @configure_input@
++
++# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
++# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
++# Inc.
++# This Makefile.in is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
++# PARTICULAR PURPOSE.
++
++@SET_MAKE@
++
++# -*- Makefile -*-
++# AUTOMAKE
++VPATH = @srcdir@
++pkgdatadir = $(datadir)/@PACKAGE@
++pkgincludedir = $(includedir)/@PACKAGE@
++pkglibdir = $(libdir)/@PACKAGE@
++pkglibexecdir = $(libexecdir)/@PACKAGE@
++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
++install_sh_DATA = $(install_sh) -c -m 644
++install_sh_PROGRAM = $(install_sh) -c
++install_sh_SCRIPT = $(install_sh) -c
++INSTALL_HEADER = $(INSTALL_DATA)
++transform = $(program_transform_name)
++NORMAL_INSTALL = :
++PRE_INSTALL = :
++POST_INSTALL = :
++NORMAL_UNINSTALL = :
++PRE_UNINSTALL = :
++POST_UNINSTALL = :
++build_triplet = @build@
++host_triplet = @host@
++DIST_COMMON = $(srcdir)/../../Makefile.extra $(srcdir)/Makefile.am \
++	$(srcdir)/Makefile.in
++subdir = extensions/LUA
++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
++am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
++	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
++	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
++	$(top_srcdir)/configure.ac
++am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
++	$(ACLOCAL_M4)
++mkinstalldirs = $(install_sh) -d
++CONFIG_HEADER = $(top_builddir)/config.h
++CONFIG_CLEAN_FILES =
++CONFIG_CLEAN_VPATH_FILES =
++SOURCES =
++DIST_SOURCES =
++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
++ACLOCAL = @ACLOCAL@
++AMTAR = @AMTAR@
++AR = @AR@
++AUTOCONF = @AUTOCONF@
++AUTOHEADER = @AUTOHEADER@
++AUTOMAKE = @AUTOMAKE@
++AWK = @AWK@
++CC = @CC@
++CCDEPMODE = @CCDEPMODE@
++CFLAGS = @CFLAGS@
++CPP = @CPP@
++CPPFLAGS = @CPPFLAGS@
++CYGPATH_W = @CYGPATH_W@
++DEFS = @DEFS@
++DEPDIR = @DEPDIR@
++DSYMUTIL = @DSYMUTIL@
++DUMPBIN = @DUMPBIN@
++ECHO_C = @ECHO_C@
++ECHO_N = @ECHO_N@
++ECHO_T = @ECHO_T@
++EGREP = @EGREP@
++EXEEXT = @EXEEXT@
++FGREP = @FGREP@
++GREP = @GREP@
++INSTALL = @INSTALL@
++INSTALL_DATA = @INSTALL_DATA@
++INSTALL_PROGRAM = @INSTALL_PROGRAM@
++INSTALL_SCRIPT = @INSTALL_SCRIPT@
++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
++LD = @LD@
++LDFLAGS = @LDFLAGS@
++LIBOBJS = @LIBOBJS@
++LIBS = @LIBS@
++LIBTOOL = @LIBTOOL@
++LIPO = @LIPO@
++LN_S = @LN_S@
++LTLIBOBJS = @LTLIBOBJS@
++MAKEINFO = @MAKEINFO@
++MKDIR_P = @MKDIR_P@
++NM = @NM@
++NMEDIT = @NMEDIT@
++OBJDUMP = @OBJDUMP@
++OBJEXT = @OBJEXT@
++OTOOL = @OTOOL@
++OTOOL64 = @OTOOL64@
++PACKAGE = @PACKAGE@
++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
++PACKAGE_NAME = @PACKAGE_NAME@
++PACKAGE_STRING = @PACKAGE_STRING@
++PACKAGE_TARNAME = @PACKAGE_TARNAME@
++PACKAGE_URL = @PACKAGE_URL@
++PACKAGE_VERSION = @PACKAGE_VERSION@
++PATH_SEPARATOR = @PATH_SEPARATOR@
++PKG_CONFIG = @PKG_CONFIG@
++RANLIB = @RANLIB@
++SED = @SED@
++SET_MAKE = @SET_MAKE@
++SHELL = @SHELL@
++STRIP = @STRIP@
++VERSION = @VERSION@
++abs_builddir = @abs_builddir@
++abs_srcdir = @abs_srcdir@
++abs_top_builddir = @abs_top_builddir@
++abs_top_srcdir = @abs_top_srcdir@
++ac_ct_CC = @ac_ct_CC@
++ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
++am__include = @am__include@
++am__leading_dot = @am__leading_dot@
++am__quote = @am__quote@
++am__tar = @am__tar@
++am__untar = @am__untar@
++bindir = @bindir@
++build = @build@
++build_alias = @build_alias@
++build_cpu = @build_cpu@
++build_os = @build_os@
++build_vendor = @build_vendor@
++builddir = @builddir@
++datadir = @datadir@
++datarootdir = @datarootdir@
++docdir = @docdir@
++dvidir = @dvidir@
++exec_prefix = @exec_prefix@
++host = @host@
++host_alias = @host_alias@
++host_cpu = @host_cpu@
++host_os = @host_os@
++host_vendor = @host_vendor@
++htmldir = @htmldir@
++includedir = @includedir@
++infodir = @infodir@
++install_sh = @install_sh@
++kbuilddir = @kbuilddir@
++kinclude_CFLAGS = @kinclude_CFLAGS@
++ksourcedir = @ksourcedir@
++libdir = @libdir@
++libexecdir = @libexecdir@
++libxtables_CFLAGS = @libxtables_CFLAGS@
++libxtables_LIBS = @libxtables_LIBS@
++localedir = @localedir@
++localstatedir = @localstatedir@
++lt_ECHO = @lt_ECHO@
++mandir = @mandir@
++mkdir_p = @mkdir_p@
++oldincludedir = @oldincludedir@
++pdfdir = @pdfdir@
++prefix = @prefix@
++program_transform_name = @program_transform_name@
++psdir = @psdir@
++regular_CFLAGS = @regular_CFLAGS@
++sbindir = @sbindir@
++sharedstatedir = @sharedstatedir@
++srcdir = @srcdir@
++sysconfdir = @sysconfdir@
++target_alias = @target_alias@
++top_build_prefix = @top_build_prefix@
++top_builddir = @top_builddir@
++top_srcdir = @top_srcdir@
++xtlibdir = @xtlibdir@
++XA_SRCDIR = ${srcdir}
++XA_TOPSRCDIR = ${top_srcdir}
++XA_ABSTOPSRCDIR = ${abs_top_srcdir}
++_mcall = -f ${top_builddir}/Makefile.iptrules
++all: all-am
++
++.SUFFIXES:
++$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(srcdir)/../../Makefile.extra $(am__configure_deps)
++	@for dep in $?; do \
++	  case '$(am__configure_deps)' in \
++	    *$$dep*) \
++	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
++	        && { if test -f $@; then exit 0; else break; fi; }; \
++	      exit 1;; \
++	  esac; \
++	done; \
++	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign extensions/LUA/Makefile'; \
++	$(am__cd) $(top_srcdir) && \
++	  $(AUTOMAKE) --foreign extensions/LUA/Makefile
++.PRECIOUS: Makefile
++Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
++	@case '$?' in \
++	  *config.status*) \
++	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
++	  *) \
++	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
++	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
++	esac;
++
++$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
++	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++
++$(top_srcdir)/configure:  $(am__configure_deps)
++	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
++	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
++$(am__aclocal_m4_deps):
++
++mostlyclean-libtool:
++	-rm -f *.lo
++
++clean-libtool:
++	-rm -rf .libs _libs
++tags: TAGS
++TAGS:
++
++ctags: CTAGS
++CTAGS:
++
++
++distdir: $(DISTFILES)
++	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
++	list='$(DISTFILES)'; \
++	  dist_files=`for file in $$list; do echo $$file; done | \
++	  sed -e "s|^$$srcdirstrip/||;t" \
++	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
++	case $$dist_files in \
++	  */*) $(MKDIR_P) `echo "$$dist_files" | \
++			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
++			   sort -u` ;; \
++	esac; \
++	for file in $$dist_files; do \
++	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
++	  if test -d $$d/$$file; then \
++	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
++	    if test -d "$(distdir)/$$file"; then \
++	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++	    fi; \
++	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
++	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
++	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
++	    fi; \
++	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
++	  else \
++	    test -f "$(distdir)/$$file" \
++	    || cp -p $$d/$$file "$(distdir)/$$file" \
++	    || exit 1; \
++	  fi; \
++	done
++check-am: all-am
++check: check-am
++all-am: Makefile all-local
++installdirs:
++install: install-am
++install-exec: install-exec-am
++install-data: install-data-am
++uninstall: uninstall-am
++
++install-am: all-am
++	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
++
++installcheck: installcheck-am
++install-strip:
++	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
++	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
++	  `test -z '$(STRIP)' || \
++	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
++mostlyclean-generic:
++
++clean-generic:
++
++distclean-generic:
++	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
++	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
++
++maintainer-clean-generic:
++	@echo "This command is intended for maintainers to use"
++	@echo "it deletes files that may require special tools to rebuild."
++clean: clean-am
++
++clean-am: clean-generic clean-libtool clean-local mostlyclean-am
++
++distclean: distclean-am
++	-rm -f Makefile
++distclean-am: clean-am distclean-generic
++
++dvi: dvi-am
++
++dvi-am:
++
++html: html-am
++
++html-am:
++
++info: info-am
++
++info-am:
++
++install-data-am:
++
++install-dvi: install-dvi-am
++
++install-dvi-am:
++
++install-exec-am: install-exec-local
++
++install-html: install-html-am
++
++install-html-am:
++
++install-info: install-info-am
++
++install-info-am:
++
++install-man:
++
++install-pdf: install-pdf-am
++
++install-pdf-am:
++
++install-ps: install-ps-am
++
++install-ps-am:
++
++installcheck-am:
++
++maintainer-clean: maintainer-clean-am
++	-rm -f Makefile
++maintainer-clean-am: distclean-am maintainer-clean-generic
++
++mostlyclean: mostlyclean-am
++
++mostlyclean-am: mostlyclean-generic mostlyclean-libtool
++
++pdf: pdf-am
++
++pdf-am:
++
++ps: ps-am
++
++ps-am:
++
++uninstall-am:
++
++.MAKE: install-am install-strip
++
++.PHONY: all all-am all-local check check-am clean clean-generic \
++	clean-libtool clean-local distclean distclean-generic \
++	distclean-libtool distdir dvi dvi-am html html-am info info-am \
++	install install-am install-data install-data-am install-dvi \
++	install-dvi-am install-exec install-exec-am install-exec-local \
++	install-html install-html-am install-info install-info-am \
++	install-man install-pdf install-pdf-am install-ps \
++	install-ps-am install-strip installcheck installcheck-am \
++	installdirs maintainer-clean maintainer-clean-generic \
++	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
++	ps ps-am uninstall uninstall-am
++
++export XA_SRCDIR
++export XA_TOPSRCDIR
++export XA_ABSTOPSRCDIR
++
++all-local: user-all-local
++
++install-exec-local: user-install-local
++
++clean-local: user-clean-local
++
++user-all-local:
++	${MAKE} ${_mcall} all;
++
++# Have no user-install-data-local ATM
++user-install-local: user-install-exec-local
++
++user-install-exec-local:
++	${MAKE} ${_mcall} install;
++
++user-clean-local:
++	${MAKE} ${_mcall} clean;
++
++# Tell versions [3.59,3.63) of GNU make to not export all variables.
++# Otherwise a system limit (for SysV at least) may be exceeded.
++.NOEXPORT:
++
+--- /dev/null
++++ b/extensions/LUA/Mbuild
+@@ -0,0 +1,3 @@
++# -*- Makefile -*-
++
++obj-${build_LUA}     += libxt_LUA.so
+--- /dev/null
++++ b/extensions/LUA/nf_lua.c
+@@ -0,0 +1,64 @@
++#if defined(__KERNEL__)
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/timer.h>
++#include <linux/random.h>
++#include <linux/netfilter/x_tables.h>
++
++#endif
++
++#include "lua.h"
++#include "lobject.h" /*sizeof(udata) */
++#include "lauxlib.h"
++#include "controller.h"
++
++#if defined(__KERNEL__) /* reachs until luaopen_nflib */
++
++
++static int32_t nf_get_random(lua_State *L)
++{
++	uint32_t  rand = 0;
++
++	get_random_bytes(&rand, sizeof(uint32_t ));
++	lua_pushnumber(L, rand);
++	return 1;
++}
++
++static int32_t nf_get_time(lua_State *L)
++{
++	lua_pushnumber(L, jiffies_to_msecs(jiffies_64));
++	return 1;
++}
++
++static const struct luaL_Reg nf_lua_lib_f [] = {
++	{ "get_random",	   nf_get_random    },
++	{ "get_time",	   nf_get_time	    },
++	{ NULL,		   NULL		    }
++};
++
++void luaopen_nflib(lua_State *L)
++{
++	int32_t top;
++
++	luaL_register(L, NETFILTER_LIB, nf_lua_lib_f);
++	lua_pop(L, 1);
++
++	/* registering verdicts inside the _G */
++	lua_getglobal(L, "_G");
++	top = lua_gettop(L);
++
++	lua_pushinteger(L, XT_CONTINUE);
++	lua_setfield(L, top, "XT_CONTINUE");    /* continiue with next rule */
++
++	lua_pushinteger(L, NF_DROP);
++	lua_setfield(L, top, "NF_DROP");        /* stop traversal in the current table hook and drop packet */
++
++	lua_pushinteger(L, NF_ACCEPT);
++	lua_setfield(L, top, "NF_ACCEPT");      /* stop traversal in the current table hook and accept packet */
++
++	lua_pop(L, 1);                          /* pop _G */
++}
++
++#endif
+--- /dev/null
++++ b/extensions/LUA/prot_buf_dynamic.c
+@@ -0,0 +1,486 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "controller.h"
++
++
++
++struct protocol_buf * dyn_prot_buf_array[MAX_NR_OF_DYN_PROT_BUFS] = { NULL }; 
++
++
++/* LUA_API: the function 'field_dynamic_setter' acts as a wrapper around
++ * a given Lua field setter function of a dynamic protocol buffer. The 
++ * string containing the lua function name was piggybacked in the 'set'
++ * member of the protocol_field. We call this function passing the actual
++ * segment as byte array and the set value.
++ * 
++ * Paramters:
++ * 1.  lua_packet_segment (implicit)
++ * 2.  some lua value 
++ *
++ * Upvalues:
++ * 1.  pointer to the protocol buffer 
++ * 2.  field index 
++ *
++ * Returns:
++ * 1.  true or false if the 'set' was successful
++ */
++int32_t field_dynamic_setter(lua_State *L)
++{
++	size_t nbytes;
++	lua_packet_segment * array;
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	int32_t field_index = lua_tointeger(L, lua_upvalueindex(2));
++    
++	/* the function name is piggybacked as a string */
++	lua_getglobal(L, (char *)prot_buf->protocol_fields[field_index].set);
++	if (!lua_isfunction(L, -1)) {
++		lua_pushboolean(L, 0);
++		return 1;
++	}
++
++	nbytes = sizeof(lua_packet_segment) + seg->length * sizeof(uint8_t);
++	array = (lua_packet_segment *)lua_newuserdata(L, nbytes);
++	array->length = seg->length;
++	array->start = seg->start + seg->offset;
++	array->changes = NULL;
++
++	luaL_getmetatable(L, LUA_BYTE_ARRAY);
++	lua_setmetatable(L, -2);
++	lua_pushvalue(L, 2); /* push value to set */
++	if (lua_pcall(L, 2, 1, 0) != 0) {
++		pr_debug("Error: %s \n", lua_tostring(L, -1));
++		lua_pop(L, 1);
++		lua_pushboolean(L, 0);
++	}
++	return 1;
++}
++
++/* LUA_API: the function 'field_dynamic_getter' acts as a wrapper around
++ * a given Lua field getter function of a dynamic protocol buffer. The 
++ * string containing the lua function name was piggybacked in the 'get'
++ * member of the protocol_field. We call this function passing the actual
++ * segment as byte array.
++ * 
++ * Paramters:
++ * 1.  lua_packet_segment (implicit)
++ *
++ * Upvalues:
++ * 1.  pointer to the protocol buffer 
++ * 2.  field index 
++ *
++ * Returns:
++ * 1.  true or false if the 'get' was successful
++ */
++int32_t field_dynamic_getter(lua_State *L)
++{
++	size_t nbytes;
++	lua_packet_segment * array;
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	int32_t field_index = lua_tointeger(L, lua_upvalueindex(2));
++    
++	/* the function name is piggybacked as a string */
++	lua_getglobal(L, (char *)prot_buf->protocol_fields[field_index].get);
++	if (!lua_isfunction(L, -1)) {
++		lua_pushboolean(L, 0);
++		return 1;
++	}
++
++	nbytes = sizeof(lua_packet_segment) + seg->length * sizeof(uint8_t);
++	array = (lua_packet_segment *)lua_newuserdata(L, nbytes);
++	array->length = seg->length;
++	array->start = seg->start + seg->offset;
++	array->changes = NULL;
++
++	luaL_getmetatable(L, LUA_BYTE_ARRAY);
++	lua_setmetatable(L, -2);
++	if (lua_pcall(L, 1, 1, 0) != 0) {
++		pr_debug("Error: %s \n", luaL_checkstring(L, -1));
++		lua_pop(L, 1);
++		lua_pushboolean(L, 0);
++	}
++	return 1;
++}
++
++/* LUA_API: the function 'has_protocol_dynamic' acts as a wrapper around 
++ * a given lua has_protocol function of a dynamic protocol buffer. The 
++ * string containing the lua function name was piggybacked in the 'has_protocol'
++ * member of the protocol_buffer. We call this function passing the actual
++ * segment.
++ * 
++ * Paramters:
++ * 1.  lua_packet_segment
++ * 2.  protocol type 
++ *
++ * Returns:
++ * 1.  true or false if the payload field contains the given protocol 
++ */
++int32_t has_protocol_dynamic(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t type)
++{
++	lua_packet_segment *seg_new;
++	int32_t res = 0;                                      
++	
++    /* the function name is piggybacked as a string */
++	lua_getglobal(L, (char *)prot_buf->has_protocol);
++	seg_new = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++	seg_new->start = seg->start;
++	seg_new->offset = seg->offset;
++	seg_new->length = seg->length;
++	seg_new->changes = NULL;
++	luaL_getmetatable(L, prot_buf->name);
++	lua_setmetatable(L, -2);
++	lua_pushinteger(L, type);  /* push the protocol type */
++	if (lua_pcall(L, 2, 1, 0) != 0) {
++		pr_debug("Error: %s \n", luaL_checkstring(L, -1));
++		lua_pop(L, 1);
++		return 0;
++	}
++	res = lua_toboolean(L, -1);
++	lua_pop(L, 1);
++
++	return res;
++}
++
++/* LUA_API: the function 'get_field_changes_dynamic' acts as a wrapper around 
++ * a given lua get_field_changes function of a dynamic protocol buffer. The 
++ * string containing the lua function name was piggybacked in the 'get_field_changes'
++ * member of the protocol_buffer. We call this function passing the actual
++ * segment. The lua function must return two lua table containing the offset 
++ * and length changes (in bits). 
++ * 
++ * Paramters:
++ * 1.  lua_packet_segment 
++ *
++ * Returns:
++ * 1.  new allocated field_changes struct 
++ */
++struct field_changes * get_field_changes_dynamic(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg)
++{
++	lua_packet_segment *seg_new;
++	struct field_changes * changes;
++	int32_t nr_of_changes, i;
++
++	lua_getglobal(L, (char *)prot_buf->get_field_changes);
++
++	seg_new = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++	seg_new->start = seg->start;
++	seg_new->offset = seg->offset;
++	seg_new->length = seg->length;
++	seg_new->changes = NULL;
++	luaL_getmetatable(L, prot_buf->name);
++	lua_setmetatable(L, -2);
++
++	if (lua_pcall(L, 1, 2, 0) != 0)
++		luaL_error(L, "inside get_field_changes_dynamic. %s\n", lua_tostring(L, -1));
++
++	/* the function call must return a table containing length changes */
++	luaL_checktype(L, -1, LUA_TTABLE);
++	/* the function call must return a table containing offset changes */
++	luaL_checktype(L, -2, LUA_TTABLE);
++	/* both tables have to be of same size */
++	if (lua_objlen(L, -1) != lua_objlen(L, -2))
++		luaL_error(L, "the provided tables are not of equal size");
++
++	nr_of_changes = lua_objlen(L, -1);
++	changes = get_allocated_field_changes(L, nr_of_changes);
++
++	/* loop over the tables */
++	for (i = 1; i < nr_of_changes; i++) {
++		lua_rawgeti(L, -1, i);  /* push length value of field at index i */
++		changes->field_length_changes[i - 1] = luaL_checkinteger(L, -1);
++		lua_pop(L, 1);          /* pop offset value */
++
++		lua_rawgeti(L, -2, i);  /* push offset value of field at index i */
++		changes->field_offset_changes[i - 1] = luaL_checkinteger(L, -1);
++		lua_pop(L, 1);          /* pop length value */
++	}
++
++	/* pop both tables */
++	lua_pop(L, 2);
++
++	return changes;
++}
++
++/* C_INT: 'get_free_protocol_index' is only used internally. This function
++ * gets a free slot inside the array holding all the  protocol buffers.
++ * There are several ways to get to this information. In this case I take
++ * the way over the reflected array SUPPORTED_PROTOCOL_TABLE inside the
++ * Lua state. Since this function is called at laodtime, we do not have
++ * to care about performance.
++ */
++static int32_t get_free_protocol_index(lua_State *L)
++{
++	int32_t protocol_index;
++
++	lua_getglobal(L, SUPPORTED_PROTOCOL_TABLE);
++	protocol_index = lua_objlen(L, -1) + 1;
++	lua_pop(L, 1);
++	return protocol_index;
++}
++
++/* C_API: 'free_dynamic_prot_buf' frees the allocated memory of a given
++ * dynamic protocol buffer. this function is normally called inside a 
++ * cleanup routine. Be aware, before running this function you must be 
++ * sure that no references to the dynamic protocol buffers were available.
++ * It's recomended to close the Lua state before calling the function. */
++void free_dynamic_prot_buf(struct protocol_buf * prot_buf)
++{
++	struct protocol_field * field = prot_buf->protocol_fields;
++
++	for (; field->name != NULL; field++) {
++		if (field->get) kfree(field->get);
++		if (field->set) kfree(field->set);
++		if (field->name) kfree((char *)field->name);
++	}
++
++	if (prot_buf->payload_field) kfree(prot_buf->payload_field);
++	if (prot_buf->has_protocol) kfree(prot_buf->has_protocol);
++
++	if (prot_buf->get_field_changes) kfree(prot_buf->get_field_changes);
++	kfree((char *)prot_buf->name);
++	kfree(prot_buf);
++	return;
++}
++
++void cleanup_dynamic_prot_bufs(void)
++{
++	int32_t i;
++
++	for (i = 0; i < MAX_NR_OF_DYN_PROT_BUFS; i++) {
++		if (dyn_prot_buf_array[i]) {
++			free_dynamic_prot_buf(dyn_prot_buf_array[i]);
++			dyn_prot_buf_array[i] = NULL;
++		}
++	}
++	return;
++}
++
++
++/* C_INT: 'free_protocol_fields' is used internally as a helper function for
++ * 'register_dynamic_protbuf'. It is used when durin registration an error
++ * occurs and the afore allocated fields needed to be freed. */
++static inline void free_protocol_fields(struct protocol_field * prot_fields, int32_t i)
++{
++	struct protocol_field * f;
++
++	while (i >= 0) {
++		f = &prot_fields[i];
++		if (f->name) kfree((void *)f->name);
++		if (f->get) kfree((void *)f->get);
++		if (f->set) kfree((void *)f->set);
++		kfree((void *)f);
++		i--;
++	}
++}
++
++/* LUA_API: 'register_dynamic_protbuf' is called from within the Lua script.
++ * it takes a Lua table representing the dynamic protocol buffer as parameter.
++ * e.g.:
++ * 	eth_prot_buf = {
++ * 		name = "packet_eth_dyn",
++ * 		payload_field = "data",
++ * 		protocol_fields = {
++ * 			{"dmac", 		0, 		48,		nil,	nil	},
++ * 			{"smac", 		48, 	48,		nil,	nil	},
++ * 			{"type", 		96, 	16,		nil,	nil	},
++ * 			{"data", 		112, 	0,		nil,	nil },
++ * 		},
++ *		has_protocol = "eth_dyn_has_protocol",
++ *		get_field_changes = "eth_dyn_get_field_changes"
++ * 	}
++ * register_dynamic_protbuf(eth_prot_buf)
++ * 
++ * the table gets parsed and a new protocol_buf struct is allocated and 
++ * initialized using 'register_protbuf', which is also used for the static
++ * protocol buffers. This enables an identical behavior like the static
++ * protocol buffers. The dynamic protocol buffers are not garbage collected,
++ * use 'free_dynamic_protbuf' to free them after closing the Lua state. 
++ */
++static int32_t register_dynamic_protbuf(lua_State *L)
++{
++	struct protocol_buf *prot_buf;
++	struct protocol_field *field, sentinel = PROT_FIELD_SENTINEL;
++	int32_t nr_of_fields, i;
++
++	prot_buf = (struct protocol_buf *)kmalloc(sizeof(struct protocol_buf), GFP_KERNEL);
++	prot_buf->is_dynamic = 1;
++
++	/* check if parameter is a table */
++	luaL_checktype(L, 1, LUA_TTABLE);
++
++	/* initialize prot_buf.name */
++	lua_getfield(L, 1, "name");
++	prot_buf->name = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++	strcpy((char *)prot_buf->name, luaL_checkstring(L, -1));
++	lua_pop(L, 1);  /* pop res from lua_getfield */
++
++	/* check if protocol buffer is already registered */
++	lua_getglobal(L, prot_buf->name);
++	if (!lua_isnil(L, -1)) {
++		lua_pop(L, 1); /* pop res from lua_getglobal */
++		pr_debug("protocol_buf '%s' already registered.\n", prot_buf->name);
++		goto free_prot_buf;
++	}
++	lua_pop(L, 1); /* pop res from lua_getglobal */
++
++	/* initialize payload field */
++	lua_getfield(L, 1, "payload_field");
++	if (lua_isstring(L, -1)) {
++		prot_buf->payload_field = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++		strcpy(prot_buf->payload_field, lua_tostring(L, -1));
++	}else
++		prot_buf->payload_field = NULL;
++	lua_pop(L, 1); /* pop res from lua_getfield */
++
++	/* initialize protocol_fields field*/
++	lua_getfield(L, 1, "protocol_fields");
++	if (!lua_istable(L, -1)) {
++		pr_debug("invalid protocol_fields table.\n");
++		goto err2;
++
++	}
++
++	nr_of_fields = lua_objlen(L, -1);
++	prot_buf->protocol_fields = (struct protocol_field *)kmalloc((nr_of_fields + 1) * sizeof(struct protocol_field), GFP_KERNEL);
++
++	for (i = 1; i <= nr_of_fields; i++) {
++		field = &prot_buf->protocol_fields[i - 1];
++		/* initialize protocol field */
++		lua_rawgeti(L, -1, i);  /* push field-table */
++		if (!lua_istable(L, -1)) {
++			free_protocol_fields(prot_buf->protocol_fields, i);
++			pr_debug("invalid protocol_field at %i.\n", i);
++			goto err;
++		}
++
++		/* initialize protocol field name */
++		lua_rawgeti(L, -1, 1);
++		if (!lua_isstring(L, -1)) {
++			free_protocol_fields(prot_buf->protocol_fields, i);
++			pr_debug("invalid protocol_field name at %i.\n", i);
++			goto err;
++		}
++
++		field->name = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++		strcpy((char*)field->name, lua_tostring(L, -1));
++		lua_pop(L, 1); /* pop field name */
++
++		/* initialize protocol field offset */
++		lua_rawgeti(L, -1, 2);
++		if (!lua_isnumber(L, -1)) {
++			free_protocol_fields(prot_buf->protocol_fields, i);
++			pr_debug("invalid protocol_field offset at %i.\n", i);
++			goto err;
++		}
++		field->offset = lua_tointeger(L, -1);
++		lua_pop(L, 1); /* pop field offset */
++
++		/* initialize protocol field length */
++		lua_rawgeti(L, -1, 3);
++		if (!lua_isnumber(L, -1)) {
++			free_protocol_fields(prot_buf->protocol_fields, i);
++			pr_debug("invalid protocol_field length at %i.\n", i);
++			goto err;
++		}
++		field->length = lua_tointeger(L, -1);
++		lua_pop(L, 1); /* pop field length */
++
++		/* initialize protocol field getter */
++		lua_rawgeti(L, -1, 4);
++		if (lua_isstring(L, -1)) {
++			field->get = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++			strcpy((char *)field->get, lua_tostring(L, -1)); /* the get-wrapper knows about the piggybacked string */
++		}else
++			field->get = NULL;
++		lua_pop(L, 1); /* pop field getter */
++
++		/* initialize protocol field setter */
++		lua_rawgeti(L, -1, 5);
++		if (lua_isstring(L, -1)) {
++			field->set = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++			strcpy((char *)field->set, lua_tostring(L, -1)); /* the set-wrapper knows about the piggybacked string */
++		}else
++			field->set = NULL;
++		lua_pop(L, 1); /* pop field setter */
++
++		/* field initialization completed */
++		lua_pop(L, 1); /* pop field-table */
++	}
++
++	/* put sentinel at the end of protocol_fields */
++	memcpy(&prot_buf->protocol_fields[nr_of_fields], &sentinel, sizeof(sentinel));
++	lua_pop(L, 1); /* pop protocol-fields-table */
++
++	/* initialize has_protocol field */
++	lua_getfield(L, 1, "has_protocol");
++	if (lua_isstring(L, -1)) {
++		prot_buf->has_protocol = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++		strcpy((char *)prot_buf->has_protocol, lua_tostring(L, -1)); /* the has_protocol-wrapper knows about the piggybacked string */
++	}else
++		prot_buf->has_protocol = NULL;
++	lua_pop(L, 1); /* pop has_protocol */
++
++	/* initialize get_field_changes field */
++	lua_getfield(L, 1, "get_field_changes");
++	if (lua_isstring(L, -1)) {
++		prot_buf->get_field_changes = kmalloc(lua_objlen(L, -1), GFP_KERNEL);
++		strcpy((char *)prot_buf->get_field_changes, lua_tostring(L, -1)); /* the get_field_changes-wrapper knows about the piggybacked string */
++	}else
++		prot_buf->get_field_changes = NULL;
++	lua_pop(L, 1);                                                  /* pop get_field_changes */
++
++	/* Storing the pointer to the DYNAMIC protbuf within dyn_prot_buf_array, in order to free it at cleanup */
++	for (i = 0; i < MAX_NR_OF_DYN_PROT_BUFS; i++) {
++		if (!dyn_prot_buf_array[i]) {
++			dyn_prot_buf_array[i] = prot_buf;
++			break;
++		}else
++			goto err;
++	}
++	
++	/* call the "common" register_protbuf */
++	register_protbuf(L, prot_buf, get_free_protocol_index(L));      /* register prot_buf as it is done with the static ones */
++
++	return 0;
++
++err:
++	kfree(prot_buf->protocol_fields);
++err2:
++	if (prot_buf->payload_field) kfree(prot_buf->payload_field);
++free_prot_buf:
++	kfree((void *)prot_buf->name);
++	kfree(prot_buf);
++
++	luaL_error(L, "one or more error happend while registering a dynamic protocol buffer, please consult the debug log");
++
++	return 0;
++
++}
++
++void luaopen_protbuf_dynamic(lua_State *L)
++{
++	lua_getglobal(L, "_G");
++	lua_pushcclosure(L, register_dynamic_protbuf, 0);
++	lua_setfield(L, -2, "register_dynamic_protbuf");
++	lua_pop(L, 1); /* pop _G */
++	return;
++}
+--- /dev/null
++++ b/extensions/LUA/prot_buf_ethernet.c
+@@ -0,0 +1,60 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "controller.h"
++
++
++static int32_t eth_has_protocol(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t protocol_type)
++{
++	uint8_t *embedded_protocol = seg->start + seg->offset + 12 /*bytes*/;
++	unsigned short res = (unsigned short)((embedded_protocol[1] << CHAR_BIT) | (embedded_protocol[0] << CHAR_BIT));
++
++	switch (res) {
++	case 0x0800:    /* 1: Internet Protocol (IP) */
++		if (protocol_type == PACKET_IP) return 1;
++		break;
++	default:
++		return 0;
++	}
++
++	return 0;
++}
++
++static const struct protocol_field eth_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "dmac", 0,		      48,	       NULL,		  NULL		    },
++	{ "smac", 48,		      48,	       NULL,		  NULL		    },
++	{ "type", 96,		      16,	       NULL,		  NULL		    },
++	{ "data", 112,		      0,	       NULL,		  NULL		    },
++	PROT_FIELD_SENTINEL,
++};
++
++static const struct protocol_buf eth_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_ETH,
++	.payload_field			= "data",
++	.protocol_fields		= (struct protocol_field *)&eth_protocol_fields,
++	.has_protocol			= &eth_has_protocol,
++	.get_field_changes		= NULL,
++};
++
++
++void luaopen_protbuf_eth(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&eth_protocol_buf, PACKET_ETH);
++}
+--- /dev/null
++++ b/extensions/LUA/prot_buf_helpers.c
+@@ -0,0 +1,216 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#if defined(__KERNEL__)
++#include <linux/netfilter_ipv4.h>
++#include <linux/slab.h>         /* kmalloc */
++#endif
++
++#include "controller.h"
++
++int32_t get_header_size(struct protocol_buf * prot_buf)
++{
++	int32_t bit_counter = 0;
++	struct protocol_field * field = prot_buf->protocol_fields;
++
++	for (; field->name; field++)
++		bit_counter += field->length;
++
++	return bit_counter >> 3;
++}
++
++
++int32_t set_32_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	*(uint32_t  *)(seg->start + seg->offset) = (uint32_t  )htonl(luaL_checkinteger(L, 2));
++	return 0;
++}
++int32_t get_32_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushinteger(L, ntohl(*((uint32_t  *)(seg->start + seg->offset))));
++	return 1;
++}
++
++int32_t set_16_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	*(uint16_t *)(seg->start + seg->offset) = (uint16_t)htons(luaL_checkinteger(L, 2));
++	return 0;
++}
++int32_t get_16_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushinteger(L, ntohs(*((uint16_t *)(seg->start + seg->offset))));
++	return 1;
++}
++
++int32_t set_lower_4_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	uint8_t b = (uint8_t)luaL_checkinteger(L, 2) << 4;
++	uint8_t * pos = (uint8_t *)(seg->start + seg->offset);
++
++	*pos &= 0x0F; /* reset lower 4 bits*/
++	*pos |= b;
++
++	return 0;
++}
++
++int32_t get_lower_4_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushinteger(L, (*(uint8_t *)(seg->start + seg->offset)) >> 4);
++	return 1;
++}
++
++int32_t set_upper_4_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	uint8_t b = (uint8_t)luaL_checkinteger(L, 2) << 4;
++	uint8_t * pos = (uint8_t *)(seg->start + seg->offset);
++
++	*pos &= 0xF0; /* reset upper 4 bits*/
++	*pos |= (b >> 4);
++
++	return 0;
++}
++
++int32_t get_upper_4_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushinteger(L, (*(uint8_t *)(seg->start + seg->offset)) & 0x0F);
++	return 1;
++}
++
++
++int32_t set_8_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	*(uint8_t *)(seg->start + seg->offset) = (uint8_t)luaL_checkinteger(L, 2);
++	return 0;
++}
++
++int32_t get_8_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++	lua_pushinteger(L, *(uint8_t *)(seg->start + seg->offset));
++	return 1;
++}
++
++int32_t set_1_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	unsigned long l = 0;
++
++	memcpy(&l, (seg->start + seg->offset), seg->length);
++	l |= (1 << ((CHAR_BIT * seg->length) - luaL_checkinteger(L, 2)));
++	memcpy((seg->start + seg->offset), &l, seg->length);
++
++	return 0;
++}
++
++int32_t get_1_bit_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	unsigned long l = 0;
++	uint32_t  bit = 0;
++
++	memcpy(&l, (seg->start + seg->offset), seg->length);
++	bit = l & (1 << ((CHAR_BIT * seg->length) - luaL_checkinteger(L, 2)));
++
++	lua_pushboolean(L, bit);
++	return 1;
++}
++
++int32_t get_string_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++    
++	/* Warning we cast from uchar to char */
++	lua_pushlstring(L, (char *)seg->start + seg->offset, seg->length);
++	return 1;
++}
++
++int32_t set_data_generic(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++	lua_packet_segment * data = checkbytearray(L, 2);
++
++	pr_debug("seg->length %u, data->length %u\n", seg->length, data->length);
++
++	if (seg->length >= data->length)
++		memcpy((seg->start + seg->offset), data->start, data->length);
++	else
++		luaL_error(L, "provided byte array too big for given packet segment");
++	return 0;
++}
++
++struct field_changes * get_allocated_field_changes(lua_State *L, int32_t nr_of_fields)
++{
++	struct field_changes * changes;
++
++	changes = kmalloc(sizeof(struct field_changes), GFP_ATOMIC);
++
++	if (!changes)
++		goto failure;
++
++	changes->field_length_changes = kmalloc(nr_of_fields * sizeof(int), GFP_ATOMIC);
++	if (!changes->field_length_changes)
++		goto free1;
++
++	changes->field_offset_changes = kmalloc(nr_of_fields * sizeof(int), GFP_ATOMIC);
++	if (!changes->field_offset_changes)
++		goto free2;
++
++	memset(changes->field_length_changes, 0, nr_of_fields * sizeof(int));
++	memset(changes->field_offset_changes, 0, nr_of_fields * sizeof(int));
++
++	changes->ref_count = 1;
++
++	return changes;
++
++free2: kfree(changes->field_length_changes);
++free1: kfree(changes);
++failure:
++	if (!changes) luaL_error(L, "couldnt allocate memory inside 'get_allocated_field_changes'");
++	return NULL; /* only to omit warnings */
++}
+\ No newline at end of file
+--- /dev/null
++++ b/extensions/LUA/prot_buf_icmp.c
+@@ -0,0 +1,49 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "controller.h"
++
++static int32_t icmp_has_protocol(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t protocol_type)
++{
++	return 0;
++}
++
++static const struct protocol_field icmp_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "type",     0,		   8,		   NULL,	      NULL	},
++	{ "code",     8,		   8,		   NULL,	      NULL	},
++	{ "checksum", 16,		   16,		   NULL,	      NULL	},
++	{ "id",	      32,		   16,		   NULL,	      NULL	},
++	{ "sequence", 48,		   16,		   NULL,	      NULL	},
++	PROT_FIELD_SENTINEL,
++};
++
++static const struct protocol_buf icmp_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_ICMP,
++	.payload_field			= NULL,
++	.protocol_fields		= (struct protocol_field *)&icmp_protocol_fields,
++	.has_protocol			= &icmp_has_protocol,
++	.get_field_changes		= NULL,
++};
++
++void luaopen_protbuf_icmp(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&icmp_protocol_buf, PACKET_ICMP);
++}
++
+--- /dev/null
++++ b/extensions/LUA/prot_buf_ip.c
+@@ -0,0 +1,209 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#if defined(__KERNEL__)
++	#include <net/checksum.h>
++	#include <net/tcp.h>
++#endif
++
++#include "controller.h"
++
++
++#define IP_FMT "%u.%u.%u.%u"
++#define IP_ACC(buf) buf[0], buf[1], buf[2], buf[3]
++
++
++static int32_t ip_version_set(lua_State *L)
++{
++	uint8_t version_checked;
++	lua_packet_segment * seg = checkpacketseg(L, 1, LUA_PACKET_SEG_IP);
++	uint8_t *version_seg = seg->start + seg->offset;
++	int32_t version = luaL_checkinteger(L, 2);
++
++	luaL_argcheck(L, version >= 0 && version <= 15, 1, "version number invalid");
++
++	version_checked = (uint8_t)version;
++
++	version_seg[0] &= (uint8_t)0x0F;  /* reset version bits */
++	version_seg[0] |= version_checked << 4;
++
++	return 0;
++}
++static int32_t ip_version_get(lua_State *L)
++{
++	lua_packet_segment * seg = checkpacketseg(L, 1, LUA_PACKET_SEG_IP);
++	uint8_t *version_seg = seg->start + seg->offset;
++	uint8_t v = version_seg[0] & 0xF0;
++
++	v >>= 4;
++
++	lua_pushinteger(L, v);
++	return 1;
++}
++
++static int32_t ip_ihl_set(lua_State *L)
++{
++	uint8_t ihl_checked;
++	lua_packet_segment * seg = checkpacketseg(L, 1, LUA_PACKET_SEG_IP);
++	uint8_t *ihl_seg = seg->start + seg->offset;
++	int32_t ihl = luaL_checkinteger(L, 2);
++
++	luaL_argcheck(L, ihl >= 5 && ihl <= 15, 1, "ip header length invalid");         // RFC 791 5x32 = 160 bits
++
++	ihl_checked = (uint8_t)ihl;
++
++	ihl_seg[0] &= (uint8_t)0xF0;      /* reset ihl bits */
++	ihl_seg[0] |= ihl_checked;
++
++	return 0;
++}
++static int32_t ip_ihl_get(lua_State *L)
++{
++	lua_packet_segment * seg = checkpacketseg(L, 1, LUA_PACKET_SEG_IP);
++	uint8_t *ihl_seg = seg->start + seg->offset;
++	uint8_t v = ihl_seg[0] & 0x0F;
++
++	lua_pushinteger(L, v);
++	return 1;
++}
++
++static int32_t ip_addr_set(lua_State *L)
++{
++	int32_t field_id = lua_tointeger(L, lua_upvalueindex(2));
++	lua_packet_segment * seg = checkpacketseg(L, 1, LUA_PACKET_SEG_IP);
++	uint8_t *addr_seg = seg->start + seg->offset;
++	uint32_t  old_addr;
++	char *ip = (char *)luaL_checkstring(L, 2);
++	uint32_t  a, b, c, d;
++	struct sk_buff * skb = (struct sk_buff *)lua_touserdata(L, 3);
++
++	/* for tcp / udp checksumming*/
++	uint32_t  prot_offset;
++	uint8_t *check, *protocol_seg;
++
++	/* end */
++
++	sscanf(ip, IP_FMT, &a, &b, &c, &d);
++
++	luaL_argcheck(L, a < 256 && b < 256 && c < 256 && d < 256, 1, "invalid ip addr");
++
++	old_addr = *((uint32_t  *)addr_seg);
++	addr_seg[0] = (uint8_t)a;
++	addr_seg[1] = (uint8_t)b;
++	addr_seg[2] = (uint8_t)c;
++	addr_seg[3] = (uint8_t)d;
++
++#if defined(__KERNEL__)
++	if (old_addr != *(uint32_t  *)addr_seg) {
++		int32_t offset = (field_id == 10) ? -2 : -6;         /* offset from saddr or daddr */
++
++		csum_replace4((uint16_t *)(addr_seg + offset), old_addr, *(uint32_t  *)addr_seg);
++
++		prot_offset = (field_id == 10) ? -3 : -7;         /* offset from saddr or daddr */
++		protocol_seg = seg->start + seg->offset + prot_offset;
++
++		if (skb && (protocol_seg[0] == 0x06 || protocol_seg[0] == 0x11)) {               /* is payload TCP or UDP ? */
++
++			check = seg->start + seg->offset;                       /* tmp res */
++			check += (field_id == 10) ? 8 : 16;                     /* the start of the payload, depending saddr or daddr */
++			check += (protocol_seg[0] == 0x06) ? 16 : 6;            /* the start of the checksum, depending on TCP or UDP */
++
++			inet_proto_csum_replace4((__sum16 *)check, skb, old_addr, *(uint32_t  *)addr_seg, 1);
++
++			lua_pop(L, 1);
++		}
++	}
++#endif
++	return 0;
++}
++
++
++
++
++
++static int32_t ip_addr_get(lua_State *L)
++{
++	lua_packet_segment * seg = checkpacketseg(L, 1, LUA_PACKET_SEG_IP);
++	uint8_t *addr_seg = seg->start + seg->offset;
++
++	char buf[16]; /*max: 255.255.255.255\0 --> 16 chars */
++
++	sprintf(buf, IP_FMT, IP_ACC(addr_seg));
++	lua_pushstring(L, buf);
++	return 1;
++}
++
++static int32_t ip_has_protocol(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t protocol_type)
++{
++	uint8_t * embedded_protocol = seg->start + seg->offset + 9 /*bytes*/;
++
++	switch (embedded_protocol[0]) {
++	case 0x01:      /* 1: Internet Control Message Protocol (ICMP) */
++		if (protocol_type == PACKET_ICMP) return 1;
++		break;
++	case 0x02:      /* 2: Internet Group Management Protocol (IGMP) */
++		break;
++	case 0x06:      /* 6: Transmission Control Protocol (TCP) */
++		if (protocol_type == PACKET_TCP) return 1;
++		break;
++	case 0x11:      /* 17: User Datagram Protocol (UDP) */
++		if (protocol_type == PACKET_UDP) return 1;
++		break;
++	case 0x59:      /* 89: Open Shortest Path First (OSPF) */
++		break;
++	case 0x84:      /* 132: Stream Control Transmission Protocol (SCTP) */
++		break;
++	default:
++		break;
++	}
++
++	return 0;
++}
++
++static const struct protocol_field ip_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "version",  0,		   4,		   ip_version_get,		   ip_version_set		},
++	{ "ihl",      4,		   4,		   ip_ihl_get,			   ip_ihl_set			},
++	{ "tos",      8,		   8,		   get_8_bit_generic,		   set_8_bit_generic		},
++	{ "tot_len",  16,		   16,		   get_16_bit_generic,		   set_16_bit_generic		},
++	{ "id",	      32,		   16,		   get_16_bit_generic,		   set_16_bit_generic		},
++	{ "flags",    48,		   3,		   get_1_bit_generic,		   set_1_bit_generic		},
++	{ "frag_off", 51,		   13,		   NULL,			   NULL				},
++	{ "ttl",      64,		   8,		   get_8_bit_generic,		   set_8_bit_generic		},
++	{ "protocol", 72,		   8,		   get_8_bit_generic,		   set_8_bit_generic		},
++	{ "check",    80,		   16,		   get_16_bit_generic,		   set_16_bit_generic		},
++	{ "saddr",    96,		   32,		   ip_addr_get,			   ip_addr_set			},
++	{ "daddr",    128,		   32,		   ip_addr_get,			   ip_addr_set			},
++	{ "data",     160,		   0,		   NULL,			   set_data_generic		},
++	PROT_FIELD_SENTINEL,
++};
++
++static const struct protocol_buf ip_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_IP,
++	.payload_field			= "data",
++	.protocol_fields		= (struct protocol_field *)&ip_protocol_fields,
++	.has_protocol			= &ip_has_protocol,
++	.get_field_changes		= NULL,
++};
++
++void luaopen_protbuf_ip(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&ip_protocol_buf, PACKET_IP);
++}
++
+--- /dev/null
++++ b/extensions/LUA/prot_buf_raw.c
+@@ -0,0 +1,43 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "controller.h"
++static int32_t raw_has_protocol(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t protocol_type)
++{
++	return 1;
++}
++
++static const struct protocol_field raw_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "data", 0,		    0,		    NULL,	       NULL	 },
++	PROT_FIELD_SENTINEL,
++};
++
++static const struct protocol_buf raw_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_RAW,
++	.payload_field			= "data",
++	.protocol_fields		= (struct protocol_field *)&raw_protocol_fields,
++	.has_protocol			= &raw_has_protocol,
++	.get_field_changes		= NULL,
++};
++
++void luaopen_protbuf_raw(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&raw_protocol_buf, PACKET_RAW);
++}
+--- /dev/null
++++ b/extensions/LUA/prot_buf_tcp.c
+@@ -0,0 +1,188 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#if defined(__KERNEL__)
++	#include <net/checksum.h>
++	#include <net/tcp.h>
++#endif
++#include "controller.h"
++
++
++static int32_t tcp_has_protocol(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t protocol_type)
++{
++	return 1;
++}
++
++static int32_t tcp_set_checksum(lua_State *L)
++{
++	struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++	lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++#if defined(__KERNEL__)
++	uint8_t * check_seg = seg->start + seg->offset;
++	uint8_t * tcp_hdr = check_seg - 16;
++	uint8_t * saddr = tcp_hdr - 8;
++	uint8_t * daddr = saddr + 4;
++	uint32_t  len = 20 + (seg->changes->field_length_changes[11] / 8) + (seg->changes->field_length_changes[10] / 8);
++	unsigned short checksum = tcp_v4_check(len, *(uint32_t  *)saddr, *(uint32_t  *)daddr,
++					       csum_partial(tcp_hdr, len, 0));
++
++	memcpy(check_seg, &checksum, sizeof(unsigned short));
++#endif
++	return 0;
++}
++
++
++static const struct protocol_field tcp_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "sport",	 0,			     16,	      get_16_bit_generic,		    set_16_bit_generic		   },
++	{ "dport",	 16,			     16,	      get_16_bit_generic,		    set_16_bit_generic		   },
++	{ "seq",	 32,			     32,	      get_32_bit_generic,		    set_32_bit_generic		   },
++	{ "ack",	 64,			     32,	      get_32_bit_generic,		    set_32_bit_generic		   },
++	{ "data_off",	 96,			     4,		      get_lower_4_bit_generic,		    set_lower_4_bit_generic	   },
++	{ "reserved",	 100,			     4,		      get_upper_4_bit_generic,		    set_upper_4_bit_generic	   },
++	{ "flags",	 104,			     8,		      get_1_bit_generic,		    set_1_bit_generic		   },
++	{ "window_size", 112,			     16,	      get_16_bit_generic,		    set_16_bit_generic		   },
++	{ "check",	 128,			     16,	      get_16_bit_generic,		    tcp_set_checksum		   },
++	{ "urgent",	 144,			     16,	      NULL,				    NULL			   },
++	{ "options",	 160,			     0,		      NULL,				    set_data_generic		   },
++	{ "data",	 160,			     0,		      NULL,				    set_data_generic		   }, /* begin of data depends on options */
++	PROT_FIELD_SENTINEL,
++};
++
++
++static const struct protocol_field tcp_options_and_data[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "MSS",   0,			       16,		get_16_bit_generic,		set_16_bit_generic	     },
++	{ "WS",	   0,			       8,		get_8_bit_generic,		set_8_bit_generic	     },
++	{ "SACK",  0,			       16,		get_16_bit_generic,		set_16_bit_generic	     },
++	{ "TSVAL", 0,			       32,		get_32_bit_generic,		set_32_bit_generic	     },
++	{ "TSER",  0,			       32,		get_32_bit_generic,		set_32_bit_generic	     },
++	PROT_FIELD_SENTINEL,
++};
++
++
++static struct field_changes * tcp_get_field_changes(lua_State *L, lua_packet_segment * seg);
++
++static const struct protocol_buf tcp_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_TCP,
++	.payload_field			= "data",
++	.protocol_fields		= (struct protocol_field *)&tcp_protocol_fields,
++	.has_protocol			= &tcp_has_protocol,
++	.get_field_changes		= &tcp_get_field_changes,
++};
++
++
++static struct field_changes * tcp_options_get_field_changes(lua_State *L, lua_packet_segment * seg);
++
++static const struct protocol_buf tcp_options_and_data_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_TCP_OPT,
++	.payload_field			= NULL,
++	.protocol_fields		= (struct protocol_field *)&tcp_options_and_data,
++	.has_protocol			= NULL,
++	.get_field_changes		= &tcp_options_get_field_changes,
++};
++
++struct field_changes * tcp_get_field_changes(lua_State *L, lua_packet_segment * seg)
++{
++	/* depending on the value stored inside the 'data_off'-field, the length of
++	 * the 'options' field has to be changed, as well as the length and offset
++	 * of the 'data' field */
++	uint8_t *tcp_hdr = seg->start + seg->offset;
++
++	/* get the pointer to the 'data_off' field */
++	uint8_t * data_off_field = tcp_hdr + 12; /* 12 bytes offset */
++	/* extract the stored header length in bits */
++	uint32_t  tcp_hdr_len = ((*(uint8_t *)data_off_field) >> 4) * 32;
++
++	/* get an allocated 'field_changes' structure */
++	struct field_changes * changes = get_allocated_field_changes(L, 12);
++
++	/* depending on the tcp header length, change the length of the options*/
++	changes->field_length_changes[10] = tcp_hdr_len - 160;
++	/* depending on the options length, change the offset of the data */
++	changes->field_offset_changes[11] = changes->field_length_changes[10];
++	changes->field_length_changes[11] = (seg->length * 8) - tcp_hdr_len;
++
++	return changes;
++
++}
++
++struct field_changes * tcp_options_get_field_changes(lua_State *L, lua_packet_segment * seg)
++{
++	/* depending on the value stored inside the 'data_off'-field, the length of
++	 * the 'options' field has to be changed, as well as the length and offset
++	 * of the 'data' field */
++	uint8_t *tcp_opt_hdr = seg->start + seg->offset;
++
++	/* get an allocated 'field_changes' structure */
++	struct field_changes * changes = get_allocated_field_changes(L, 5);
++
++	int32_t MSS = 0, WS = 0, SACK = 0, TS = 0, i;
++
++	uint8_t b1, b2;
++
++	for (i = 0; i < seg->length; i++) {
++		b1 = tcp_opt_hdr[i];
++		b2 = tcp_opt_hdr[i + 1];
++
++		if (b1 == 0x00)
++			break;
++
++		/* test for MSS */
++		if (!MSS && (b1 == 0x02 && b2 == 0x04)) {
++			changes->field_offset_changes[0] = (i + 2) * CHAR_BIT;
++			MSS = 1;
++		}
++
++		/* test for WS --- yet buggy somehow */
++		if (!WS && (b1 == 0x03 && b2 == 0x03)) {
++			changes->field_offset_changes[1] = (i + 2) * CHAR_BIT;
++			WS = 1;
++		}
++
++		/* test for SACK*/
++		if (!SACK && (b1 == 0x04 && b2 == 0x02)) {
++			changes->field_offset_changes[2] = i * CHAR_BIT;        /* has no value */
++			SACK = 1;
++		}
++
++		/* test for TS */
++		if (!TS && (b1 == 0x08 && b2 == 0x0A)) {
++			changes->field_offset_changes[3] = (i + 2) * CHAR_BIT;
++			changes->field_offset_changes[4] = (i + 2 + 4) * CHAR_BIT;
++			TS = 1;
++		}
++	}
++
++	return changes;
++
++}
++
++void luaopen_protbuf_tcp(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&tcp_protocol_buf, PACKET_TCP);
++}
++void luaopen_protbuf_tcp_options(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&tcp_options_and_data_buf, PACKET_TCP_OPTIONS);
++}
++
++
+--- /dev/null
++++ b/extensions/LUA/prot_buf_tftp.c
+@@ -0,0 +1,87 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++#include "controller.h"
++
++static const struct protocol_field tftp_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "opcode",  		0,		16,		get_16_bit_generic,	NULL},
++	{ "filename",  		0,		0,		get_string_generic,	NULL},
++	{ "mode", 			0,		0,		get_string_generic, NULL},
++	{ "block_nr",		0,		16,		get_16_bit_generic, NULL},
++	{ "data",			0,		0,		NULL, NULL},
++	PROT_FIELD_SENTINEL,
++};
++
++struct field_changes * tftp_get_field_changes(lua_State *L, lua_packet_segment * seg)
++{
++	/* depending on the value stored inside the 'opcode'-field we have to change
++	 * offsets and lengths */
++	uint8_t *tftp_hdr = seg->start + seg->offset;
++	short opcode = ntohs(*((uint16_t *)tftp_hdr));
++	/* get an allocated 'field_changes' structure */
++	struct field_changes * changes = get_allocated_field_changes(L, 5);
++	switch (opcode) {
++		case 1:	/* Read Request (RRQ) */
++			/* setting offset and length of field 'filename' */
++			changes->field_offset_changes[1] = sizeof(unsigned short) << 3;
++			changes->field_length_changes[1] = strlen((char *)tftp_hdr + sizeof(unsigned short)) << 3;
++			/* setting offset and length of field 'mode' */
++			changes->field_offset_changes[2] = changes->field_offset_changes[1] + changes->field_length_changes[1];
++			changes->field_length_changes[2] = strlen((char *)tftp_hdr + (changes->field_offset_changes[2] >> 3));
++			break;
++		case 2:	/* Write Request (WRQ) */
++			/* setting offset and length of field 'filename' */
++			changes->field_offset_changes[1] = sizeof(unsigned short) << 3;
++			changes->field_length_changes[1] = strlen((char *)tftp_hdr + sizeof(unsigned short)) << 3;
++			/* setting offset and length of field 'mode' */
++			changes->field_offset_changes[2] = changes->field_offset_changes[1] + changes->field_length_changes[1];
++			changes->field_length_changes[2] = strlen((char *)tftp_hdr + (changes->field_offset_changes[2] >> 3));
++			break;
++		case 3:	/* Data (DATA) */
++			/* setting offset of field 'block_nr' */
++			changes->field_offset_changes[3] = sizeof(unsigned short) << 3;
++			/* setting offset of field 'data' */
++			changes->field_offset_changes[4] = changes->field_offset_changes[3] + (sizeof(unsigned short) << 3);
++			break;
++		case 4: /* Acknowledgment (ACK) */
++			/* setting offset of field 'block_nr' */
++			changes->field_offset_changes[3] = sizeof(unsigned short) << 3;
++			break;
++		case 5: /* Error (ERROR) */
++			/* we don't care ... yet */
++			break;
++		default:
++			break;
++	}
++
++	return changes;
++}
++
++static const struct protocol_buf tftp_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_TFTP,
++	.payload_field		= NULL,
++	.protocol_fields	= (struct protocol_field *)&tftp_protocol_fields,
++	.has_protocol		= NULL, /* we don't need it, since we don't provide a payload field */
++	.get_field_changes	= tftp_get_field_changes,
++};
++
++void luaopen_protbuf_tftp(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&tftp_protocol_buf, PACKET_TFTP);
++}
+--- /dev/null
++++ b/extensions/LUA/prot_buf_udp.c
+@@ -0,0 +1,53 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#if defined(__KERNEL__)
++	#include <net/checksum.h>
++#endif
++
++#include "controller.h"
++
++
++static int32_t udp_has_protocol(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int32_t protocol_type)
++{
++	return 1;
++}
++
++static const struct protocol_field udp_protocol_fields[] = {
++	/*	 field name    offset  length  getter  setter  */
++	{ "sport",  0,			       16,		get_16_bit_generic,		set_16_bit_generic	},
++	{ "dport",  16,			       16,		get_16_bit_generic,		set_16_bit_generic	},
++	{ "length", 32,			       16,		get_16_bit_generic,		set_16_bit_generic	},
++	{ "check",  48,			       16,		get_16_bit_generic,		set_16_bit_generic	},
++	{ "data",   64,			       0,		NULL,			  NULL		    },
++	PROT_FIELD_SENTINEL,
++};
++
++static const struct protocol_buf udp_protocol_buf = {
++	.is_dynamic			= 0,
++	.name				= LUA_PACKET_SEG_UDP,
++	.payload_field			= "data",
++	.protocol_fields		= (struct protocol_field *)&udp_protocol_fields,
++	.has_protocol			= &udp_has_protocol,
++	.get_field_changes		= NULL,
++};
++
++void luaopen_protbuf_udp(lua_State *L)
++{
++	register_protbuf(L, (struct protocol_buf *)&udp_protocol_buf, PACKET_UDP);
++}
+--- /dev/null
++++ b/extensions/LUA/xt_LUA.h
+@@ -0,0 +1,36 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre.graf@stud.unibas.ch>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef XT_LUA_H_
++#define XT_LUA_H_
++
++#define MAX_FILENAME_SIZE  256
++#define MAX_FUNCTION_SIZE  256
++#define MAX_SCRIPT_SIZE 32768
++#define LUA_STATE_ARRAY_SIZE 128
++
++/* the targetsize is stored in a u16, so max size of the xt_lua_tginfo cannot exceed 64K*/
++struct xt_lua_tginfo {
++	char buf[MAX_SCRIPT_SIZE];
++	char filename[MAX_FILENAME_SIZE];
++	char function[MAX_FUNCTION_SIZE];
++	__u64 script_size;
++	__u32 state_id;
++};
++
++#endif /* XT_LUA_H_ */
+--- /dev/null
++++ b/extensions/LUA/xt_LUA_target.c
+@@ -0,0 +1,286 @@
++/*
++ *	Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *	by Andre Graf <andre@dergraf.org>
++ *
++ *	This program is free software; you can redistribute it and/or modify
++ *	it under the terms of the GNU General Public License as published by
++ *	the Free Software Foundation; either version 2 of the License, or
++ *	(at your option) any later version.
++ *
++ *	This program is distributed in the hope that it will be useful,
++ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *	GNU General Public License for more details.
++ *
++ *	You should have received a copy of the GNU General Public License
++ *	along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <asm/uaccess.h>
++#include <net/ip.h>
++#include <linux/netfilter/x_tables.h>
++#include "xt_LUA.h"
++
++#include "controller.h"
++
++/*::*
++ * lua_envs
++ * ----------
++ * This array holds a defined number of `lua_envs`_ structures.
++ * The used array index is also used as the Lua state identifier.
++ * The size of the array is defined in `LUA_STATE_ARRAY_SIZE`_.
++ */
++struct lua_env * lua_envs[LUA_STATE_ARRAY_SIZE];
++
++/*::*
++ * lua_state_refs
++ * --------------
++ * This array holds the reference counts of the several `lua_nf_state`_s
++ * which are stored inside the array `lua_states`_.
++ */
++uint32_t  lua_state_refs[LUA_STATE_ARRAY_SIZE] = { 0 };
++
++/*::*
++ * lua_tg
++ * ------
++ * This function is called whenever a packet matches all matching conditions
++ * inside a rule. It is the target. It extracts the state identifier comming
++ * inside the *xt_target_param* structure and uses it to access the proper
++ * Lua state inside the `lua_states`_ array.
++ *
++ * It then constructs a new Lua userdata of type *lua_packet_segment* and
++ * initializes it with the lowest network header available. This userdata
++ * is annotated with the Lua metatable `LUA_PACKET_SEG_RAW`_ which converts
++ * the userdata to a raw lua packet having all raw functions available.
++ * This raw packet is the single parameter to the Lua function *process_packet*
++ * which must be defined inside the Lua script provided by the user. So far
++ * hardcoded, may be later configured by Lua - subject to change.
++ *
++ * The process_packet function must return an integer value, the verdict. For
++ * convenience reasons xt_LUA exports the verdicts NF_ACCEPT, NF_DROP and
++ * XT_CONTINUE inside the *register_lua_packet_lib* function.
++ */
++
++spinlock_t lock = SPIN_LOCK_UNLOCKED;
++
++static uint32_t 
++lua_tg(struct sk_buff *pskb, const struct xt_target_param *par)
++{
++	uint32_t  verdict;
++	lua_packet_segment *p;
++	const struct xt_lua_tginfo *info = par->targinfo;
++	lua_State * L;
++
++	/* START critical section on SMP, PacketScript is on the sequential trail at the moment TODO*/
++	spin_lock_irq(&lock);
++
++	L = lua_envs[info->state_id]->L;
++
++	if (!skb_make_writable(pskb, pskb->len))
++		return NF_DROP;
++
++	/* call the function provided by --function parameter or the default 'process_packet' defined in Lua */
++	lua_getglobal(L, info->function);
++
++	/* push the lua_packet_segment as a parameter */
++	p = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++	if (pskb->mac_header)
++		p->start = pskb->mac_header;
++	else if (pskb->network_header)
++		p->start = pskb->network_header;
++	else if (pskb->transport_header)
++		p->start = pskb->transport_header;
++	p->offset = 0;
++	p->length = (unsigned long)pskb->tail - (unsigned long)p->start;
++	p->changes = NULL;
++
++	/* marking userdata 'lua_packet_seg' with the corresponding metatable */
++	luaL_getmetatable(L, LUA_PACKET_SEG_RAW);
++	lua_setmetatable(L, -2);
++
++	/* push a reference to the skb as a parameter, needed at the moment for calculating TCP checksum, but I am not happy with it*/
++	lua_pushlightuserdata(L, (void *)skb_get(pskb));
++
++	/* do the function call (2 argument, 1 result) */
++	if (lua_pcall(L, 2, 1, 0) != 0) {
++		printk(KERN_ERR "LUA [%d]: pcall '%s' failed: %s\n", info->state_id, info->function, lua_tostring(L, -1));
++		lua_pop(L, 1);
++		return NF_DROP;
++	}
++
++	if (!lua_isnumber(L, -1)) {
++		printk(KERN_ERR "LUA [%d]: function '%s' must return a verdict\n", info->state_id, info->function);
++		lua_pop(L, 1);
++		return NF_DROP;
++	}
++
++	verdict = lua_tonumber(L, -1);
++	lua_pop(L, 1);
++
++	kfree_skb(pskb);
++
++	/* END critical section on SMP */
++	spin_unlock_irq(&lock);
++
++
++	return verdict;
++
++} 
++/* Helper for checkentry */
++static bool load_script_into_state(uint32_t  state_id, unsigned long script_size, char *script_buf)
++{
++	char *buf = kmalloc(script_size, GFP_KERNEL);
++	int32_t ret;
++	struct lua_env * env = kmalloc(sizeof(struct lua_env), GFP_KERNEL);
++
++	if (!script_size > 0) {
++		pr_debug("LUA [%d]: script_size %lu < 0\n", state_id, script_size);
++		return false;
++	}
++
++	env->L = lua_open();
++	luaopen_base(env->L);
++	luaopen_controller(env->L);
++
++	lua_getglobal(env->L, "_G");
++	lua_pushinteger(env->L, state_id);
++	lua_setfield(env->L, -2, "STATE_ID");
++	lua_pop(env->L, 1); /* pop _G */
++
++	strncpy(buf, script_buf, script_size);
++	ret = luaL_loadbuffer(env->L, buf, script_size, "PacketScript, loadbuffer") ||
++	      lua_pcall(env->L, 0, 1, 0);
++
++	if (ret != 0) {
++		printk(KERN_ERR "LUA [%d]: failure loading script, error %s \n", state_id, lua_tostring(env->L, -1));
++		lua_pop(env->L, 1);
++		kfree(buf);
++		kfree(env);
++		return false;
++	}
++
++	lua_envs[state_id] = env;
++
++	kfree(buf);
++
++	return true;
++}
++/*::*
++ * lua_tg_checkentry
++ * -----------------
++ * This function is used as a kernel-side sanity check of the data comming
++ * from the iptables userspace program. Since this is the function which is
++ * called everytime a new rule (with -j xt_LUA) is injected, this function
++ * is used to do the bookkeeping work, such as counting the reference of
++ * several Lua states and the initialization of new states if needed. As an
++ * extra initialization step it loads the provided Lua script into the Lua
++ * state.
++ *
++ * Lua state initialization
++ * ~~~~~~~~~~~~~~~~~~~~~~~~
++ * 1. If a new rule is inserted and there is no existing state for the given
++ *    state identifier (default state identifier is 0) a new Lua state is
++ *    initialized using *lua_open*.
++ * 2. The Lua base library is registered inside the newly initialized state.
++ *    Have a look at *lua/lbaselib.c* to see what functions of the Lua base
++ *    library are available inside Lua.
++ * 3. The Lua packet library is registered inside the Lua state using the
++ *    function *register_lua_packet_lib*. So far this function only registers
++ *    the Netfilter verdicts NF_ACCEPT, NF_DROP and XT_CONTINUE inside the
++ *    global environment of the given Lua state.
++ * 4. All the protocol Buffers, and the functions for accessing the bytes are
++ *    registered using *register_protocols*.
++ *
++ * Lua state reference counting
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Bookkeeping of the Lua states inside the *lua_state_refs* array. The
++ * state identifier is mapped to the array index, which holds an integer
++ * counting the several initialized states.
++ *
++ * Loading the Lua script
++ * ~~~~~~~~~~~~~~~~~~~~~~
++ * Copying the buffer which was initialized by the userspace program to a
++ * buffer with the proper size. The script is then loaded by the function
++ * xt_LUA_loadcode, which wrapps the *luaL_loadbuffer* function and does
++ * some workqueue initialization. So far this is done each time this function
++ * is called, subject to change.
++ */
++static bool
++lua_tg_checkentry(const struct xt_tgchk_param *par)
++{
++	const struct xt_lua_tginfo *info = par->targinfo;
++
++	if (load_script_into_state(info->state_id, info->script_size, (char *)info->buf)) {
++		lua_state_refs[info->state_id]++;
++		return true;
++	}
++	return false;
++}
++
++/*::*
++ * lua_tg_destroy
++ * --------------
++ * This function is the counterpart of the `lua_tg_checkentry`_ function. It is
++ * responsible to free all the resources alocated inside the checkentry process.
++ * To be more specific it frees the Lua state using *lua_close* and kfree on all
++ * the dynamically allocated pointers to the registered dynamic protocol buffers.
++ *
++ * Additionally the function cares about decrementing the reference counters
++ * inside the array `lua_states`_.
++ */
++static void
++lua_tg_destroy(const struct xt_tgdtor_param *par)
++{
++	const struct xt_lua_tginfo *info = par->targinfo;
++	struct lua_env * env = lua_envs[info->state_id];
++
++	if (lua_state_refs[info->state_id] == 1) {
++		lua_close(env->L);
++		cleanup_dynamic_prot_bufs();  /* clean memory allocated by protocols defined in Lua */
++		kfree(env);
++		pr_debug("LUA [%d]: Rule removed, close Lua state\n", info->state_id);
++	} else
++		pr_debug("LUA [%d]: Rule removed, Lua state stays open, referenced %d time(s)\n",
++			 info->state_id, lua_state_refs[info->state_id] - 1);
++	
++	lua_state_refs[info->state_id]--;
++}
++
++static struct xt_target lua_tg_reg __read_mostly = {
++	.name			= "LUA",
++	.revision		= 0,
++	.family			= NFPROTO_UNSPEC,
++	.targetsize		= XT_ALIGN(sizeof(struct xt_lua_tginfo)),
++	.target			= lua_tg,
++	.checkentry		= lua_tg_checkentry,
++	.destroy		= lua_tg_destroy,
++	.me			= THIS_MODULE,
++};
++
++
++static int32_t lua_tg_init(void)
++{
++	return xt_register_target(&lua_tg_reg);
++}
++
++static void lua_tg_exit(void)
++{
++	xt_unregister_target(&lua_tg_reg);
++}
++
++module_init(lua_tg_init);
++module_exit(lua_tg_exit);
++
++MODULE_AUTHOR("Andre Graf <andre@dergraf.org>");
++MODULE_DESCRIPTION("Xtables: Processing of matched packets using the Lua scripting environment");
++MODULE_ALIAS("ipt_LUA");
++MODULE_ALIAS("ipt6t_LUA");
++MODULE_ALIAS("arpt_LUA");
++MODULE_ALIAS("ebt_LUA");
++MODULE_LICENSE("GPL");
++
++
++
+--- a/extensions/Kbuild
++++ b/extensions/Kbuild
+@@ -27,6 +27,7 @@ obj-${build_pknock}      += pknock/
+ obj-${build_psd}         += xt_psd.o
+ obj-${build_quota2}      += xt_quota2.o
+ obj-${build_rtsp}        += rtsp/
++obj-${build_LUA}         += LUA/
+ 
+ -include ${M}/*.Kbuild
+ -include ${M}/Kbuild.*
+--- a/extensions/Mbuild
++++ b/extensions/Mbuild
+@@ -22,3 +22,4 @@ obj-${build_pknock}      += pknock/
+ obj-${build_psd}         += libxt_psd.so
+ obj-${build_quota2}      += libxt_quota2.so
+ obj-${build_gradm}       += libxt_gradm.so
++obj-${build_LUA}         += LUA/
+--- a/mconfig
++++ b/mconfig
+@@ -23,3 +23,4 @@ build_pknock=m
+ build_psd=m
+ build_quota2=m
+ build_rtsp=m
++build_LUA=m
diff --git a/package/network/utils/xtables-addons/patches/201-fix-lua-packetscript.patch b/package/network/utils/xtables-addons/patches/201-fix-lua-packetscript.patch
new file mode 100644
index 0000000000..02250ec206
--- /dev/null
+++ b/package/network/utils/xtables-addons/patches/201-fix-lua-packetscript.patch
@@ -0,0 +1,107 @@
+--- a/extensions/LUA/xt_LUA_target.c
++++ b/extensions/LUA/xt_LUA_target.c
+@@ -64,10 +64,10 @@ uint32_t  lua_state_refs[LUA_STATE_ARRAY
+  * XT_CONTINUE inside the *register_lua_packet_lib* function.
+  */
+ 
+-spinlock_t lock = SPIN_LOCK_UNLOCKED;
++DEFINE_SPINLOCK(lock);
+ 
+ static uint32_t 
+-lua_tg(struct sk_buff *pskb, const struct xt_target_param *par)
++lua_tg(struct sk_buff *pskb, const struct xt_action_param *par)
+ {
+ 	uint32_t  verdict;
+ 	lua_packet_segment *p;
+@@ -88,11 +88,11 @@ lua_tg(struct sk_buff *pskb, const struc
+ 	/* push the lua_packet_segment as a parameter */
+ 	p = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
+ 	if (pskb->mac_header)
+-		p->start = pskb->mac_header;
++		p->start = skb_mac_header(pskb);
+ 	else if (pskb->network_header)
+-		p->start = pskb->network_header;
++		p->start = skb_network_header(pskb);
+ 	else if (pskb->transport_header)
+-		p->start = pskb->transport_header;
++		p->start = skb_transport_header(pskb);
+ 	p->offset = 0;
+ 	p->length = (unsigned long)pskb->tail - (unsigned long)p->start;
+ 	p->changes = NULL;
+@@ -208,16 +208,16 @@ static bool load_script_into_state(uint3
+  * some workqueue initialization. So far this is done each time this function
+  * is called, subject to change.
+  */
+-static bool
++static int
+ lua_tg_checkentry(const struct xt_tgchk_param *par)
+ {
+ 	const struct xt_lua_tginfo *info = par->targinfo;
+ 
+ 	if (load_script_into_state(info->state_id, info->script_size, (char *)info->buf)) {
+ 		lua_state_refs[info->state_id]++;
+-		return true;
++		return 0;
+ 	}
+-	return false;
++	return -EINVAL;
+ }
+ 
+ /*::*
+--- a/extensions/LUA/lua/llimits.h
++++ b/extensions/LUA/lua/llimits.h
+@@ -8,7 +8,6 @@
+ #define llimits_h
+ 
+ #include <stddef.h>
+-#include <limits.h>
+ 
+ #include "lua.h"
+ 
+--- a/extensions/LUA/lua/lapi.c
++++ b/extensions/LUA/lua/lapi.c
+@@ -4,9 +4,6 @@
+ ** See Copyright Notice in lua.h
+ */
+ 
+-#include <stdarg.h>
+-#include <math.h>
+-#include <assert.h>
+ #include <string.h>
+ 
+ #define lapi_c
+--- a/extensions/LUA/lua/ltable.c
++++ b/extensions/LUA/lua/ltable.c
+@@ -18,7 +18,6 @@
+ ** Hence even when the load factor reaches 100%, performance remains good.
+ */
+ 
+-#include <math.h>
+ #include <string.h>
+ 
+ #define ltable_c
+--- a/extensions/LUA/lua/luaconf.h
++++ b/extensions/LUA/lua/luaconf.h
+@@ -13,8 +13,12 @@
+ #if !defined(__KERNEL__)
+ #include <limits.h>
+ #else
++#include <linux/kernel.h>
++
++#undef UCHAR_MAX
++#undef BUFSIZ
++#undef NO_FPU
+ #define UCHAR_MAX	255
+-#define SHRT_MAX        32767
+ #define BUFSIZ 		8192
+ #define NO_FPU
+ #endif
+@@ -637,6 +641,8 @@ union luai_Cast { double l_d; long l_l;
+ */
+ #if defined(__KERNEL__)
+ #undef LUA_USE_ULONGJMP
++#define setjmp __builtin_setjmp
++#define longjmp __builtin_longjmp
+ #endif
+ 
+ #if defined(__cplusplus)
diff --git a/package/network/utils/xtables-addons/patches/300-geoip-endian-detection.patch b/package/network/utils/xtables-addons/patches/300-geoip-endian-detection.patch
new file mode 100644
index 0000000000..842e7afcc7
--- /dev/null
+++ b/package/network/utils/xtables-addons/patches/300-geoip-endian-detection.patch
@@ -0,0 +1,18 @@
+--- a/extensions/libxt_geoip.c
++++ b/extensions/libxt_geoip.c
+@@ -59,13 +59,13 @@ geoip_get_subnets(const char *code, uint
+ 
+ 	/* Use simple integer vector files */
+ 	if (nfproto == NFPROTO_IPV6) {
+-#if __BYTE_ORDER == _BIG_ENDIAN
++#if BYTE_ORDER == BIG_ENDIAN
+ 		snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv6", code);
+ #else
+ 		snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv6", code);
+ #endif
+ 	} else {
+-#if __BYTE_ORDER == _BIG_ENDIAN
++#if BYTE_ORDER == BIG_ENDIAN
+ 		snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code);
+ #else
+ 		snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code);
diff --git a/package/system/ca-certificates/Makefile b/package/system/ca-certificates/Makefile
new file mode 100644
index 0000000000..980f61a4c1
--- /dev/null
+++ b/package/system/ca-certificates/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ca-certificates
+PKG_VERSION:=20161102
+PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
+
+PKG_SOURCE:=$(PKG_NAME)_$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://ftp.debian.org/debian/pool/main/c/ca-certificates
+PKG_MD5SUM:=74642bd9b9e0a449fa55e6632070745f
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ca-certificates
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=System CA certificates
+  PKGARCH:=all
+endef
+
+define Package/ca-bundle
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=System CA certificates as a bundle
+  PKGARCH:=all
+endef
+
+define Build/Install
+	mkdir -p \
+		$(PKG_INSTALL_DIR)/usr/sbin \
+		$(PKG_INSTALL_DIR)/usr/share/ca-certificates
+	$(call Build/Install/Default,)
+endef
+
+define Package/ca-certificates/install
+	$(INSTALL_DIR) $(1)/etc/ssl/certs
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/ca-certificates/*/*.crt $(1)/etc/ssl/certs/
+
+	for CERTFILE in `ls -1 $(1)/etc/ssl/certs`; do \
+		HASH=`openssl x509 -hash -noout -in $(1)/etc/ssl/certs/$$$$CERTFILE` ; \
+		SUFFIX=0 ; \
+		while [ -h "$(1)/etc/ssl/certs/$$$$HASH.$$$$SUFFIX" ]; do \
+			let "SUFFIX += 1" ; \
+		done ; \
+		$(LN) "$$$$CERTFILE" "$(1)/etc/ssl/certs/$$$$HASH.$$$$SUFFIX" ; \
+	done
+endef
+
+define Package/ca-bundle/install
+	$(INSTALL_DIR) $(1)/etc/ssl/certs
+	cat $(PKG_INSTALL_DIR)/usr/share/ca-certificates/*/*.crt >$(1)/etc/ssl/certs/ca-certificates.crt
+endef
+$(eval $(call BuildPackage,ca-certificates))
+$(eval $(call BuildPackage,ca-bundle))
diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile
new file mode 100644
index 0000000000..785d680bf8
--- /dev/null
+++ b/package/system/fstools/Makefile
@@ -0,0 +1,110 @@
+#
+# Copyright (C) 2014-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fstools
+PKG_VERSION:=2016-09-31
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/fstools.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=94a5b0ad8d53f024f036c3526b48c34ebbd66a2f
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=f9fca74463187f2ef07c45154ae5dea296bd7e6fcb734bdc5f8d452e8d6b9fa2
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_USE_MIPS16:=0
+PKG_FLAGS:=nonshared
+
+PKG_BUILD_DEPENDS := util-linux
+PKG_CONFIG_DEPENDS := CONFIG_NAND_SUPPORT CONFIG_FSTOOLS_UBIFS_EXTROOT
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-lrt)
+CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_UBIFS_EXTROOT),-DCMAKE_UBIFS_EXTROOT=y)
+
+define Package/fstools
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+ubox +USE_GLIBC:librt +NAND_SUPPORT:ubi-utils
+  TITLE:=OpenWrt filesystem tools
+  MENU:=1
+endef
+
+define Package/fstools/config
+	config FSTOOLS_UBIFS_EXTROOT
+		depends on PACKAGE_fstools
+		depends on NAND_SUPPORT
+		bool "Support extroot functionality with UBIFS"
+		default y
+		help
+			This option makes it possible to use extroot functionality if the root filesystem resides on an UBIFS partition
+endef
+
+define Package/snapshot-tool
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=rootfs snapshoting tool
+  DEPENDS:=+libubox +fstools
+endef
+
+define Package/block-mount
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=Block device mounting and checking
+  DEPENDS:=+ubox +libubox +libuci
+endef
+
+define Package/fstools/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/lib
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,jffs2reset} $(1)/sbin/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools.so $(1)/lib/
+	$(LN) jffs2reset $(1)/sbin/jffs2mark
+endef
+
+define Package/snapshot-tool/install
+	$(INSTALL_DIR) $(1)/sbin
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/snapshot_tool $(1)/sbin/
+	$(INSTALL_BIN) ./files/snapshot $(1)/sbin/
+endef
+
+define Package/block-mount/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/lib $(1)/usr/sbin $(1)/etc/hotplug.d/block $(1)/etc/init.d/ $(1)/etc/uci-defaults/
+
+	$(INSTALL_BIN) ./files/fstab.init $(1)/etc/init.d/fstab
+	$(INSTALL_DATA) ./files/fstab.default $(1)/etc/uci-defaults/10-fstab
+	$(INSTALL_DATA) ./files/mount.hotplug $(1)/etc/hotplug.d/block/10-mount
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/block $(1)/sbin/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libblkid-tiny.so $(1)/lib/
+	$(LN) ../../sbin/block $(1)/usr/sbin/swapon
+	$(LN) ../../sbin/block $(1)/usr/sbin/swapoff
+
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libubi-utils.a $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,fstools))
+$(eval $(call BuildPackage,snapshot-tool))
+$(eval $(call BuildPackage,block-mount))
diff --git a/package/system/fstools/files/fstab.default b/package/system/fstools/files/fstab.default
new file mode 100644
index 0000000000..2331e0c288
--- /dev/null
+++ b/package/system/fstools/files/fstab.default
@@ -0,0 +1,2 @@
+[ ! -f /etc/config/fstab ] && ( block detect > /etc/config/fstab )
+exit 0
diff --git a/package/system/fstools/files/fstab.init b/package/system/fstools/files/fstab.init
new file mode 100644
index 0000000000..5faa8ecbb9
--- /dev/null
+++ b/package/system/fstools/files/fstab.init
@@ -0,0 +1,16 @@
+#!/bin/sh /etc/rc.common
+# (C) 2013 openwrt.org
+
+START=40
+
+boot() {
+	/sbin/block mount
+}
+
+start() {
+	echo "this file has been obsoleted. please call \"/sbin/block mount\" directly"
+}
+
+stop() {
+	/sbin/block umount
+}
diff --git a/package/system/fstools/files/mount.hotplug b/package/system/fstools/files/mount.hotplug
new file mode 100644
index 0000000000..946924e351
--- /dev/null
+++ b/package/system/fstools/files/mount.hotplug
@@ -0,0 +1 @@
+/sbin/block hotplug
diff --git a/package/system/fstools/files/snapshot b/package/system/fstools/files/snapshot
new file mode 100644
index 0000000000..c1a5b733f3
--- /dev/null
+++ b/package/system/fstools/files/snapshot
@@ -0,0 +1,111 @@
+#!/bin/sh
+# Copyright (C) 2014 OpenWrt.org
+
+
+do_snapshot_unpack() {
+	echo "- snapshot -"
+	mkdir /tmp/snapshot
+	cd /tmp/snapshot
+	snapshot_tool read
+	block=`ls block*.tar.gz 2> /dev/null`
+	[ -z "$block" ] || for a in $block; do
+		tar xzf $a -C /
+		rm -f $a
+	done
+}
+
+do_config_unpack() {
+	echo "- config -"
+	snapshot_tool config_read
+	[ -f /tmp/config.tar.gz ] && {
+		tar xzf /tmp/config.tar.gz -C /
+		rm -f /tmp/config.tar.gz
+	}
+}
+
+do_snapshot_push() {
+	cd /volatile/upper
+	tar czf /tmp/snapshot.tar.gz *
+	snapshot_tool write
+	reboot
+}
+
+do_config_push() {
+	cd /volatile/upper
+	tar czf /tmp/config.tar.gz *
+	snapshot_tool config_write
+}
+
+do_snapshot_upgrade() {
+	opkg update
+	[ $? -eq 0 ] || exit 1
+
+	opkg list-upgradable
+	[ $? -eq 0 ] || exit 2
+	
+	UPDATES=`opkg list-upgradable | cut -d" " -f1`
+	[ -z "${UPDATES}" ] && exit 0
+
+	opkg upgrade ${UPDATES}
+	[ $? -eq 0 ] || exit 3
+
+	do_snapshot_push
+	sleep 5
+	reboot
+	sleep 10
+}
+
+do_convert_jffs2() {
+	snapshot_tool write
+	sleep 2
+	reboot -f
+}
+
+do_convert() {
+	. /lib/functions.sh
+	. /lib/upgrade/common.sh
+	ubus call system upgrade
+	touch /tmp/sysupgrade
+	cd /overlay/upper
+	tar czf /tmp/snapshot.tar.gz *
+	kill_remaining TERM
+	sleep 3
+	kill_remaining KILL
+	run_ramfs '. /sbin/snapshot; do_convert_jffs2'
+}
+
+[ -n "$(cat /proc/mounts|grep /overlay|grep jffs2)" ] && {
+case $1 in
+convert)
+	do_convert
+	;;
+esac
+}
+
+[ -d /volatile/upper ] && {
+case $1 in
+push)
+	do_snapshot_push
+	;;
+config)
+	do_config_push
+	;;
+upgrade)
+	do_snapshot_upgrade
+	;;
+info)
+	snapshot_tool info
+	;;
+esac
+}
+
+[ "$SNAPSHOT" = "magic" ] && {
+case $1 in
+unpack)
+	do_snapshot_unpack
+	;;
+config_unpack)
+	do_config_unpack
+	;;
+esac
+}
diff --git a/package/system/fwtool/Makefile b/package/system/fwtool/Makefile
new file mode 100644
index 0000000000..901081c1f4
--- /dev/null
+++ b/package/system/fwtool/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) Felix Fietkau <nbd@nbd.name>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fwtool
+PKG_RELEASE:=1
+
+PKG_FLAGS:=nonshared
+
+PKG_MAINTAINER := Felix Fietkau <nbd@nbd.name>
+PKG_BUILD_DEPENDS := fwtool/host
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
+
+define Package/fwtool
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=Utility for appending and extracting firmware metadata and signatures
+endef
+
+define Host/Compile
+	$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $(HOST_BUILD_DIR)/fwtool ./src/fwtool.c
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/fwtool $(1)/bin/
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/fwtool ./src/fwtool.c
+endef
+
+define Package/fwtool/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/fwtool $(1)/usr/bin/
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,fwtool))
diff --git a/package/system/fwtool/src/crc32.h b/package/system/fwtool/src/crc32.h
new file mode 100644
index 0000000000..022c69fc7f
--- /dev/null
+++ b/package/system/fwtool/src/crc32.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Based on busybox code:
+ *   CRC32 table fill function
+ *   Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __BB_CRC32_H
+#define __BB_CRC32_H
+
+static inline void
+crc32_filltable(uint32_t *crc_table)
+{
+	uint32_t polynomial = 0xedb88320;
+	uint32_t c;
+	int i, j;
+
+	for (i = 0; i < 256; i++) {
+		c = i;
+		for (j = 8; j; j--)
+			c = (c&1) ? ((c >> 1) ^ polynomial) : (c >> 1);
+
+		*crc_table++ = c;
+	}
+}
+
+static inline uint32_t
+crc32_block(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
+{
+	const void *end = (uint8_t*)buf + len;
+
+	while (buf != end) {
+		val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
+		buf = (uint8_t*)buf + 1;
+	}
+	return val;
+}
+
+#endif
diff --git a/package/system/fwtool/src/fwimage.h b/package/system/fwtool/src/fwimage.h
new file mode 100644
index 0000000000..52dcfb1bac
--- /dev/null
+++ b/package/system/fwtool/src/fwimage.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __FWIMAGE_H
+#define __FWIMAGE_H
+
+#include <stdint.h>
+
+#define FWIMAGE_MAGIC		0x46577830 /* FWx0 */
+
+struct fwimage_header {
+	uint32_t version;
+	uint32_t flags;
+	char data[];
+};
+
+struct fwimage_trailer {
+	uint32_t magic;
+	uint32_t crc32;
+	uint8_t type;
+	uint8_t __pad[3];
+	uint32_t size;
+};
+
+enum fwimage_type {
+	FWIMAGE_SIGNATURE,
+	FWIMAGE_INFO,
+};
+
+#endif
diff --git a/package/system/fwtool/src/fwtool.c b/package/system/fwtool/src/fwtool.c
new file mode 100644
index 0000000000..e77b8b58e1
--- /dev/null
+++ b/package/system/fwtool/src/fwtool.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fwimage.h"
+#include "utils.h"
+#include "crc32.h"
+
+#define METADATA_MAXLEN		30 * 1024
+#define SIGNATURE_MAXLEN	1 * 1024
+
+#define BUFLEN			(METADATA_MAXLEN + SIGNATURE_MAXLEN + 1024)
+
+enum {
+	MODE_DEFAULT = -1,
+	MODE_EXTRACT = 0,
+	MODE_APPEND = 1,
+};
+
+struct data_buf {
+	char *cur;
+	char *prev;
+	int cur_len;
+	int file_len;
+};
+
+static FILE *signature_file, *metadata_file, *firmware_file;
+static int file_mode = MODE_DEFAULT;
+static bool truncate_file;
+static bool quiet = false;
+
+static uint32_t crc_table[256];
+
+#define msg(...)					\
+	do {						\
+		if (!quiet)				\
+			fprintf(stderr, __VA_ARGS__);	\
+	} while (0)
+
+static int
+usage(const char *progname)
+{
+	fprintf(stderr, "Usage: %s <options> <firmware>\n"
+		"\n"
+		"Options:\n"
+		"  -S <file>:		Append signature file to firmware image\n"
+		"  -I <file>:		Append metadata file to firmware image\n"
+		"  -s <file>:		Extract signature file from firmware image\n"
+		"  -i <file>:		Extract metadata file from firmware image\n"
+		"  -t:			Remove extracted chunks from firmare image (using -s, -i)\n"
+		"  -q:			Quiet (suppress error messages)\n"
+		"\n", progname);
+	return 1;
+}
+
+static FILE *
+open_file(const char *name, bool write)
+{
+	FILE *ret;
+
+	if (!strcmp(name, "-"))
+		return write ? stdout : stdin;
+
+	ret = fopen(name, write ? "w" : "r+");
+	if (!ret && !write)
+		ret = fopen(name, "r");
+
+	return ret;
+}
+
+static int
+set_file(FILE **file, const char *name, int mode)
+{
+	if (file_mode < 0)
+		file_mode = mode;
+	else if (file_mode != mode) {
+		msg("Error: mixing appending and extracting data is not supported\n");
+		return 1;
+	}
+
+	if (*file) {
+		msg("Error: the same append/extract option cannot be used multiple times\n");
+		return 1;
+	}
+
+	*file = open_file(name, mode == MODE_EXTRACT);
+	return !*file;
+}
+
+static void
+trailer_update_crc(struct fwimage_trailer *tr, void *buf, int len)
+{
+	tr->crc32 = cpu_to_be32(crc32_block(be32_to_cpu(tr->crc32), buf, len, crc_table));
+}
+
+static int
+append_data(FILE *in, FILE *out, struct fwimage_trailer *tr, int maxlen)
+{
+	while (1) {
+		char buf[512];
+		int len;
+
+		len = fread(buf, 1, sizeof(buf), in);
+		if (!len)
+			break;
+
+		maxlen -= len;
+		if (maxlen < 0)
+			return 1;
+
+		tr->size += len;
+		trailer_update_crc(tr, buf, len);
+		fwrite(buf, len, 1, out);
+	}
+
+	return 0;
+}
+
+static void
+append_trailer(FILE *out, struct fwimage_trailer *tr)
+{
+	tr->size = cpu_to_be32(tr->size);
+	fwrite(tr, sizeof(*tr), 1, out);
+	trailer_update_crc(tr, tr, sizeof(*tr));
+}
+
+static int
+add_metadata(struct fwimage_trailer *tr)
+{
+	struct fwimage_header hdr = {};
+
+	tr->type = FWIMAGE_INFO;
+	tr->size = sizeof(hdr) + sizeof(*tr);
+
+	trailer_update_crc(tr, &hdr, sizeof(hdr));
+	fwrite(&hdr, sizeof(hdr), 1, firmware_file);
+
+	if (append_data(metadata_file, firmware_file, tr, METADATA_MAXLEN))
+		return 1;
+
+	append_trailer(firmware_file, tr);
+
+	return 0;
+}
+
+static int
+add_signature(struct fwimage_trailer *tr)
+{
+	if (!signature_file)
+		return 0;
+
+	tr->type = FWIMAGE_SIGNATURE;
+	tr->size = sizeof(*tr);
+
+	if (append_data(signature_file, firmware_file, tr, SIGNATURE_MAXLEN))
+		return 1;
+
+	append_trailer(firmware_file, tr);
+
+	return 0;
+}
+
+static int
+add_data(const char *name)
+{
+	struct fwimage_trailer tr = {
+		.magic = cpu_to_be32(FWIMAGE_MAGIC),
+		.crc32 = ~0,
+	};
+	int file_len = 0;
+	int ret = 0;
+
+	firmware_file = fopen(name, "r+");
+	if (!firmware_file) {
+		msg("Failed to open firmware file\n");
+		return 1;
+	}
+
+	while (1) {
+		char buf[512];
+		int len;
+
+		len = fread(buf, 1, sizeof(buf), firmware_file);
+		if (!len)
+			break;
+
+		file_len += len;
+		trailer_update_crc(&tr, buf, len);
+	}
+
+	if (metadata_file)
+		ret = add_metadata(&tr);
+	else if (signature_file)
+		ret = add_signature(&tr);
+
+	if (ret) {
+		fflush(firmware_file);
+		ftruncate(fileno(firmware_file), file_len);
+	}
+
+	return ret;
+}
+
+static void
+remove_tail(struct data_buf *dbuf, int len)
+{
+	dbuf->cur_len -= len;
+	dbuf->file_len -= len;
+
+	if (dbuf->cur_len)
+		return;
+
+	free(dbuf->cur);
+	dbuf->cur = dbuf->prev;
+	dbuf->prev = NULL;
+	dbuf->cur_len = BUFLEN;
+}
+
+static int
+extract_tail(struct data_buf *dbuf, void *dest, int len)
+{
+	int cur_len = dbuf->cur_len;
+
+	if (!dbuf->cur)
+		return 1;
+
+	if (cur_len >= len)
+		cur_len = len;
+
+	memcpy(dest + (len - cur_len), dbuf->cur + dbuf->cur_len - cur_len, cur_len);
+	remove_tail(dbuf, cur_len);
+
+	cur_len = len - cur_len;
+	if (cur_len && !dbuf->cur)
+		return 1;
+
+	memcpy(dest, dbuf->cur + dbuf->cur_len - cur_len, cur_len);
+	remove_tail(dbuf, cur_len);
+
+	return 0;
+}
+
+static uint32_t
+tail_crc32(struct data_buf *dbuf, uint32_t crc32)
+{
+	if (dbuf->prev)
+		crc32 = crc32_block(crc32, dbuf->prev, BUFLEN, crc_table);
+
+	return crc32_block(crc32, dbuf->cur, dbuf->cur_len, crc_table);
+}
+
+static int
+validate_metadata(struct fwimage_header *hdr, int data_len)
+{
+	 if (hdr->version != 0)
+		 return 1;
+	 return 0;
+}
+
+static int
+extract_data(const char *name)
+{
+	struct fwimage_header *hdr;
+	struct fwimage_trailer tr;
+	struct data_buf dbuf = {};
+	uint32_t crc32 = ~0;
+	int ret = 1;
+	void *buf;
+
+	firmware_file = open_file(name, false);
+	if (!firmware_file) {
+		msg("Failed to open firmware file\n");
+		return 1;
+	}
+
+	if (truncate_file && firmware_file == stdin) {
+		msg("Cannot truncate file when reading from stdin\n");
+		return 1;
+	}
+
+	buf = malloc(BUFLEN);
+	if (!buf)
+		return 1;
+
+	do {
+		char *tmp = dbuf.cur;
+
+		dbuf.cur = dbuf.prev;
+		dbuf.prev = tmp;
+
+		if (dbuf.cur)
+			crc32 = crc32_block(crc32, dbuf.cur, BUFLEN, crc_table);
+		else
+			dbuf.cur = malloc(BUFLEN);
+
+		if (!dbuf.cur)
+			goto out;
+
+		dbuf.cur_len = fread(dbuf.cur, 1, BUFLEN, firmware_file);
+		dbuf.file_len += dbuf.cur_len;
+	} while (dbuf.cur_len == BUFLEN);
+
+	while (1) {
+		int data_len;
+
+		if (extract_tail(&dbuf, &tr, sizeof(tr)))
+			break;
+
+		data_len = be32_to_cpu(tr.size) - sizeof(tr);
+		if (tr.magic != cpu_to_be32(FWIMAGE_MAGIC)) {
+			msg("Data not found\n");
+			break;
+		}
+
+		if (be32_to_cpu(tr.crc32) != tail_crc32(&dbuf, crc32)) {
+			msg("CRC error\n");
+			break;
+		}
+
+		if (data_len > BUFLEN) {
+			msg("Size error\n");
+			break;
+		}
+
+		extract_tail(&dbuf, buf, data_len);
+
+		if (tr.type == FWIMAGE_SIGNATURE) {
+			if (!signature_file)
+				continue;
+			fwrite(buf, data_len, 1, signature_file);
+			ret = 0;
+			break;
+		} else if (tr.type == FWIMAGE_INFO) {
+			if (!metadata_file)
+				break;
+
+			hdr = buf;
+			data_len -= sizeof(*hdr);
+			if (validate_metadata(hdr, data_len))
+				continue;
+
+			fwrite(hdr + 1, data_len, 1, metadata_file);
+			ret = 0;
+			break;
+		} else {
+			continue;
+		}
+	}
+
+	if (!ret && truncate_file)
+		ftruncate(fileno(firmware_file), dbuf.file_len);
+
+out:
+	free(buf);
+	free(dbuf.cur);
+	free(dbuf.prev);
+	return ret;
+}
+
+static void cleanup(void)
+{
+	if (signature_file)
+		fclose(signature_file);
+	if (metadata_file)
+		fclose(metadata_file);
+	if (firmware_file)
+		fclose(firmware_file);
+}
+
+int main(int argc, char **argv)
+{
+	const char *progname = argv[0];
+	int ret, ch;
+
+	crc32_filltable(crc_table);
+
+	while ((ch = getopt(argc, argv, "i:I:qs:S:t")) != -1) {
+		ret = 0;
+		switch(ch) {
+		case 'S':
+			ret = set_file(&signature_file, optarg, MODE_APPEND);
+			break;
+		case 'I':
+			ret = set_file(&metadata_file, optarg, MODE_APPEND);
+			break;
+		case 's':
+			ret = set_file(&signature_file, optarg, MODE_EXTRACT);
+			break;
+		case 'i':
+			ret = set_file(&metadata_file, optarg, MODE_EXTRACT);
+			break;
+		case 't':
+			truncate_file = true;
+			break;
+		case 'q':
+			quiet = true;
+			break;
+		}
+
+		if (ret)
+			goto out;
+	}
+
+	if (optind >= argc) {
+		ret = usage(progname);
+		goto out;
+	}
+
+	if (file_mode == MODE_DEFAULT) {
+		ret = usage(progname);
+		goto out;
+	}
+
+	if (signature_file && metadata_file) {
+		msg("Cannot append/extract metadata and signature in one run\n");
+		return 1;
+	}
+
+	if (file_mode)
+		ret = add_data(argv[optind]);
+	else
+		ret = extract_data(argv[optind]);
+
+out:
+	cleanup();
+	return ret;
+}
diff --git a/package/system/fwtool/src/utils.h b/package/system/fwtool/src/utils.h
new file mode 100644
index 0000000000..c2e665e54a
--- /dev/null
+++ b/package/system/fwtool/src/utils.h
@@ -0,0 +1,116 @@
+/*
+ * utils - misc libubox utility functions
+ *
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __LIBUBOX_UTILS_H
+#define __LIBUBOX_UTILS_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#ifdef __GNUC__
+#define _GNUC_MIN_VER(maj, min) (((__GNUC__ << 8) + __GNUC_MINOR__) >= (((maj) << 8) + (min)))
+#else
+#define _GNUC_MIN_VER(maj, min) 0
+#endif
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#include <byteswap.h>
+#include <endian.h>
+
+#elif defined(__APPLE__)
+#include <machine/endian.h>
+#include <machine/byte_order.h>
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#else
+#include <machine/endian.h>
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#endif
+
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER BYTE_ORDER
+#endif
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#endif
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#endif
+
+static inline uint16_t __u_bswap16(uint16_t val)
+{
+	return ((val >> 8) & 0xffu) | ((val & 0xffu) << 8);
+}
+
+#if _GNUC_MIN_VER(4, 2)
+#define __u_bswap32(x) __builtin_bswap32(x)
+#define __u_bswap64(x) __builtin_bswap64(x)
+#else
+#define __u_bswap32(x) bswap_32(x)
+#define __u_bswap64(x) bswap_64(x)
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#define cpu_to_be64(x) __u_bswap64(x)
+#define cpu_to_be32(x) __u_bswap32(x)
+#define cpu_to_be16(x) __u_bswap16((uint16_t) (x))
+
+#define be64_to_cpu(x) __u_bswap64(x)
+#define be32_to_cpu(x) __u_bswap32(x)
+#define be16_to_cpu(x) __u_bswap16((uint16_t) (x))
+
+#define cpu_to_le64(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+#define le64_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+
+#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+
+#define cpu_to_le64(x) __u_bswap64(x)
+#define cpu_to_le32(x) __u_bswap32(x)
+#define cpu_to_le16(x) __u_bswap16((uint16_t) (x))
+
+#define le64_to_cpu(x) __u_bswap64(x)
+#define le32_to_cpu(x) __u_bswap32(x)
+#define le16_to_cpu(x) __u_bswap16((uint16_t) (x))
+
+#define cpu_to_be64(x) (x)
+#define cpu_to_be32(x) (x)
+#define cpu_to_be16(x) (x)
+
+#define be64_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#define be16_to_cpu(x) (x)
+
+#endif
+
+#endif
diff --git a/package/system/lede-keyring/Makefile b/package/system/lede-keyring/Makefile
new file mode 100644
index 0000000000..df14530c22
--- /dev/null
+++ b/package/system/lede-keyring/Makefile
@@ -0,0 +1,40 @@
+# Copyright (C) 2016 LEDE project
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lede-keyring
+PKG_VERSION:=2016-04-30
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/keyring.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=5c7857eed3fa06a9005f96b9b029388c7f316e83
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=c5997bf1505042c857d5e19fec497c6516cc1d9e07fc19ff4c5b1a33da3cdf29
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/lede-keyring
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=LEDE Developer Keyring
+  URL:=http://www.lede-project.org
+endef
+
+define Package/lede-keyring/description
+  The keyring of with the developer using and gpg public keys.
+endef
+
+Build/Compile=
+
+define Package/lede-keyring/install
+	$(INSTALL_DIR) $(1)/etc/opkg/keys/
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/usign/* $(1)/etc/opkg/keys/
+endef
+
+$(eval $(call BuildPackage,lede-keyring))
diff --git a/package/system/mountd/Makefile b/package/system/mountd/Makefile
new file mode 100644
index 0000000000..fe9ecc7b43
--- /dev/null
+++ b/package/system/mountd/Makefile
@@ -0,0 +1,48 @@
+# Copyright (C) 2009-2012 OpenWrt.org
+# All rights reserved.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mountd
+PKG_VERSION:=2016-09-30
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/mountd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=3dd115bb4046521986abe78bc488dfd6b95e5a6e
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=40baff09ee09ab7b80ec4786c1e7c9ec69726c776f435244d225b765bd5992b7
+CMAKE_INSTALL:=1
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+PKG_LICENSE:=GPL-2.0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/mountd
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=OpenWrt automount daemon
+  DEPENDS:=@USB_SUPPORT +uci +kmod-usb-storage +kmod-fs-autofs4
+  URL:=http://www.openwrt.org
+endef
+
+define Package/mountd/description
+  openwrt automount daemon
+endef
+
+define Package/mountd/conffiles
+/etc/config/mountd
+endef
+
+define Package/mountd/install
+	$(INSTALL_DIR) $(1)/sbin/ $(1)/etc/config/ $(1)/etc/init.d/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mountd $(1)/sbin/
+	$(INSTALL_DATA) ./files/mountd.config $(1)/etc/config/mountd
+	$(INSTALL_BIN) ./files/mountd.init $(1)/etc/init.d/mountd
+endef
+
+$(eval $(call BuildPackage,mountd))
diff --git a/package/system/mountd/files/mountd.config b/package/system/mountd/files/mountd.config
new file mode 100644
index 0000000000..5610129501
--- /dev/null
+++ b/package/system/mountd/files/mountd.config
@@ -0,0 +1,3 @@
+config mountd mountd
+	option	timeout		60
+	option	path		/tmp/mounts/
diff --git a/package/system/mountd/files/mountd.init b/package/system/mountd/files/mountd.init
new file mode 100755
index 0000000000..772bd6ed5a
--- /dev/null
+++ b/package/system/mountd/files/mountd.init
@@ -0,0 +1,22 @@
+#!/bin/sh /etc/rc.common
+
+START=80
+
+SERVICE_DAEMONIZE=1
+SERVICE_WRITE_PID=1
+SERVICE_PID_FILE=/var/run/mountd.pid
+
+MOUNTD_BIN=/sbin/mountd
+
+start()
+{
+	P="$(uci get mountd.mountd.path)"
+	[ -n "$P" -a ! -f "$P" ] && mkdir -p $P
+
+	service_start $MOUNTD_BIN -f
+}
+
+stop()
+{
+	service_stop $MOUNTD_BIN
+}
diff --git a/package/system/mtd/Makefile b/package/system/mtd/Makefile
new file mode 100644
index 0000000000..01277d9f46
--- /dev/null
+++ b/package/system/mtd/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=mtd
+PKG_RELEASE:=21
+
+PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
+STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
+
+PKG_LICENSE:=GPL-2.0+
+PKG_LICENSE_FILES:=
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mtd
+  SECTION:=utils
+  CATEGORY:=Base system
+  DEPENDS:=+libubox
+  TITLE:=Update utility for trx firmware images
+endef
+
+define Package/mtd/description
+ This package contains an utility useful to upgrade from other firmware or 
+ older OpenWrt releases.
+endef
+
+target=$(firstword $(subst -, ,$(BOARD)))
+
+MAKE_FLAGS += TARGET="$(target)"
+TARGET_CFLAGS := $(TARGET_CFLAGS) -Dtarget_$(target)=1 -Wall
+
+ifdef CONFIG_MTD_REDBOOT_PARTS
+  MAKE_FLAGS += FIS_SUPPORT=1
+  TARGET_CFLAGS += -DFIS_SUPPORT=1
+endif
+
+define Package/mtd/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mtd $(1)/sbin/
+endef
+
+$(eval $(call BuildPackage,mtd))
diff --git a/package/system/mtd/src/Makefile b/package/system/mtd/src/Makefile
new file mode 100644
index 0000000000..4e39a89315
--- /dev/null
+++ b/package/system/mtd/src/Makefile
@@ -0,0 +1,24 @@
+CC = gcc
+CFLAGS += -Wall
+LDFLAGS += -lubox
+
+obj = mtd.o jffs2.o crc32.o md5.o
+obj.seama = seama.o md5.o
+obj.wrgg = wrgg.o md5.o
+obj.ar71xx = trx.o $(obj.seama) $(obj.wrgg)
+obj.brcm = trx.o
+obj.brcm47xx = $(obj.brcm)
+obj.bcm53xx = $(obj.brcm) $(obj.seama)
+obj.brcm63xx = imagetag.o
+obj.ramips = $(obj.seama)
+obj.mvebu = linksys_bootcount.o
+obj.kirkwood = linksys_bootcount.o
+obj.ipq806x = linksys_bootcount.o
+
+ifdef FIS_SUPPORT
+  obj += fis.o
+endif
+
+mtd: $(obj) $(obj.$(TARGET))
+clean:
+	rm -f *.o jffs2
diff --git a/package/system/mtd/src/crc32.c b/package/system/mtd/src/crc32.c
new file mode 100644
index 0000000000..6b1e50c42d
--- /dev/null
+++ b/package/system/mtd/src/crc32.c
@@ -0,0 +1,95 @@
+/*
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+	0x2d02ef8dL
+};
diff --git a/package/system/mtd/src/crc32.h b/package/system/mtd/src/crc32.h
new file mode 100644
index 0000000000..68f8ee4feb
--- /dev/null
+++ b/package/system/mtd/src/crc32.h
@@ -0,0 +1,26 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+	const unsigned char *s = ss;
+	while (--len >= 0)
+		val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+	return val;
+}
+
+static inline unsigned int crc32buf(char *buf, size_t len)
+{
+	return crc32(0xFFFFFFFF, buf, len);
+}
+
+
+
+#endif
diff --git a/package/system/mtd/src/fis.c b/package/system/mtd/src/fis.c
new file mode 100644
index 0000000000..b50411cfeb
--- /dev/null
+++ b/package/system/mtd/src/fis.c
@@ -0,0 +1,262 @@
+/*
+ * FIS table updating code for mtd
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <sys/mman.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "crc32.h"
+#include "mtd.h"
+#include "fis.h"
+
+struct fis_image_hdr {
+	unsigned char name[16];
+	uint32_t flash_base;
+	uint32_t mem_base;
+	uint32_t size;
+	uint32_t entry_point;
+	uint32_t data_length;
+} __attribute__((packed));
+
+struct fis_image_crc {
+	uint32_t desc;
+	uint32_t file;
+} __attribute__((packed));
+
+struct fis_image_desc {
+	struct fis_image_hdr hdr;
+	char _pad[256 - sizeof(struct fis_image_hdr) - sizeof(struct fis_image_crc)];
+	struct fis_image_crc crc;
+} __attribute__((packed));
+
+static int fis_fd = -1;
+static struct fis_image_desc *fis_desc;
+static int fis_erasesize = 0;
+
+static void
+fis_close(void)
+{
+	if (fis_desc)
+		munmap(fis_desc, fis_erasesize);
+
+	if (fis_fd >= 0)
+		close(fis_fd);
+
+	fis_fd = -1;
+	fis_desc = NULL;
+}
+
+static struct fis_image_desc *
+fis_open(void)
+{
+	struct fis_image_desc *desc;
+
+	if (fis_fd >= 0)
+		fis_close();
+
+	fis_fd = mtd_check_open("FIS directory");
+	if (fis_fd < 0)
+		goto error;
+
+	close(fis_fd);
+	fis_fd = mtd_open("FIS directory", true);
+	if (fis_fd < 0)
+		goto error;
+
+	fis_erasesize = erasesize;
+	desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fis_fd, 0);
+	if (desc == MAP_FAILED)
+		goto error;
+
+	fis_desc = desc;
+	return desc;
+
+error:
+	fis_close();
+	return NULL;
+}
+
+int
+fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
+{
+	struct fis_image_desc *desc;
+	void *end;
+	int found = 0;
+	int i;
+
+	desc = fis_open();
+	if (!desc)
+		return -1;
+
+	for (i = 0; i < n_new - 1; i++) {
+		if (!new[i].size) {
+			fprintf(stderr, "FIS error: only the last partition can detect the size automatically\n");
+			i = -1;
+			goto done;
+		}
+	}
+
+	end = desc;
+	end = (char *) end + fis_erasesize;
+	while ((void *) desc < end) {
+		if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
+			break;
+
+		for (i = 0; i < n_old; i++) {
+			if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
+				found++;
+				goto next;
+			}
+		}
+next:
+		desc++;
+		continue;
+	}
+
+	if (found == n_old)
+		i = 1;
+	else
+		i = -1;
+
+done:
+	fis_close();
+	return i;
+}
+
+int
+fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
+{
+	struct fis_image_desc *fisdir = NULL;
+	struct fis_image_desc *redboot = NULL;
+	struct fis_image_desc *first = NULL;
+	struct fis_image_desc *last = NULL;
+	struct fis_image_desc *first_fb = NULL;
+	struct fis_image_desc *last_fb = NULL;
+	struct fis_image_desc *desc;
+	struct fis_part *part;
+	uint32_t offset = 0, size = 0;
+	char *start, *end, *tmp;
+	int i;
+
+	desc = fis_open();
+	if (!desc)
+		return -1;
+
+	if (!quiet)
+		fprintf(stderr, "Updating FIS table... \n");
+
+	start = (char *) desc;
+	end = (char *) desc + fis_erasesize;
+	while ((char *) desc < end) {
+		if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
+			break;
+
+		if (!strcmp((char *) desc->hdr.name, "FIS directory"))
+			fisdir = desc;
+
+		if (!strcmp((char *) desc->hdr.name, "RedBoot"))
+			redboot = desc;
+
+		/* update max offset */
+		if (offset < desc->hdr.flash_base)
+			offset = desc->hdr.flash_base;
+
+		for (i = 0; i < n_old; i++) {
+			if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) {
+				last = desc;
+				if (!first)
+					first = desc;
+				break;
+			}
+		}
+		desc++;
+	}
+	desc--;
+
+	first_fb = first;
+	last_fb = last;
+
+	if (first_fb->hdr.flash_base > last_fb->hdr.flash_base) {
+		first_fb = last;
+		last_fb = first;
+	}
+
+	/* determine size of available space */
+	desc = (struct fis_image_desc *) start;
+	while ((char *) desc < end) {
+		if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
+			break;
+
+		if (desc->hdr.flash_base > last_fb->hdr.flash_base &&
+		    desc->hdr.flash_base < offset)
+			offset = desc->hdr.flash_base;
+
+		desc++;
+	}
+	desc--;
+
+	size = offset - first_fb->hdr.flash_base;
+
+#ifdef notyet
+	desc = first - 1;
+	if (redboot && (desc >= redboot)) {
+		if (first->hdr.flash_base - desc->hdr.size > desc->hdr.flash_base) {
+			int delta = first->hdr.flash_base - desc->hdr.size - desc->hdr.flash_base;
+
+			offset -= delta;
+			size += delta;
+		}
+	}
+#endif
+
+	last++;
+	desc = first + n_new;
+	offset = first_fb->hdr.flash_base;
+
+	if (desc != last) {
+		if (desc > last)
+			tmp = (char *) desc;
+		else
+			tmp = (char *) last;
+
+		memmove(desc, last, end - tmp);
+		if (desc < last) {
+			tmp = end - (last - desc) * sizeof(struct fis_image_desc);
+			memset(tmp, 0xff, tmp - end);
+		}
+	}
+
+	for (part = new, desc = first; desc < first + n_new; desc++, part++) {
+		memset(desc, 0, sizeof(struct fis_image_desc));
+		memcpy(desc->hdr.name, part->name, sizeof(desc->hdr.name));
+		desc->crc.desc = 0;
+		desc->crc.file = 0;
+
+		desc->hdr.flash_base = offset;
+		desc->hdr.mem_base = part->loadaddr;
+		desc->hdr.entry_point = part->loadaddr;
+		desc->hdr.size = (part->size > 0) ? part->size : size;
+		desc->hdr.data_length = desc->hdr.size;
+
+		offset += desc->hdr.size;
+		size -= desc->hdr.size;
+	}
+
+	msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE);
+	fis_close();
+
+	return 0;
+}
diff --git a/package/system/mtd/src/fis.h b/package/system/mtd/src/fis.h
new file mode 100644
index 0000000000..bdf1103d8a
--- /dev/null
+++ b/package/system/mtd/src/fis.h
@@ -0,0 +1,14 @@
+#ifndef __FIS_H
+#define __FIS_H
+
+struct fis_part {
+	unsigned char name[16];
+	uint32_t offset;
+	uint32_t loadaddr;
+	uint32_t size;
+};
+
+int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new);
+int fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new);
+
+#endif
diff --git a/package/system/mtd/src/imagetag.c b/package/system/mtd/src/imagetag.c
new file mode 100644
index 0000000000..673dd44de5
--- /dev/null
+++ b/package/system/mtd/src/imagetag.c
@@ -0,0 +1,410 @@
+/*
+ * imagetag.c
+ *
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ * Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "mtd.h"
+#include "crc32.h"
+
+#define TAGVER_LEN		4	/* Length of Tag Version */
+#define TAGLAYOUT_LEN		4	/* Length of FlashLayoutVer */
+#define SIG1_LEN		20	/* Company Signature 1 Length */
+#define SIG2_LEN		14	/* Company Signature 2 Length */
+#define BOARDID_LEN		16	/* Length of BoardId */
+#define ENDIANFLAG_LEN		2	/* Endian Flag Length */
+#define CHIPID_LEN		6	/* Chip Id Length */
+#define IMAGE_LEN		10	/* Length of Length Field */
+#define ADDRESS_LEN		12	/* Length of Address field */
+#define DUALFLAG_LEN		2	/* Dual Image flag Length */
+#define INACTIVEFLAG_LEN	2	/* Inactie Flag Length */
+#define RSASIG_LEN		20	/* Length of RSA Signature in tag */
+#define TAGINFO1_LEN		30	/* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN	4	/* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN		16	/* Length of vendor information field2 in tag */
+#define ALTTAGINFO_LEN		54	/* Alternate length for vendor information; Pirelli */
+
+#define NUM_PIRELLI		2
+#define IMAGETAG_CRC_START	0xFFFFFFFF
+
+#define PIRELLI_BOARDS { \
+	"AGPF-S0", \
+	"DWV-S0", \
+}
+/*
+ * The broadcom firmware assumes the rootfs starts the image,
+ * therefore uses the rootfs start (flash_image_address)
+ * to determine where to flash the image.  Since we have the kernel first
+ * we have to give it the kernel address, but the crc uses the length
+ * associated with this address (root_length), which is added to the kernel
+ * length (kernel_length) to determine the length of image to flash and thus
+ * needs to be rootfs + deadcode (jffs2 EOF marker)
+*/
+
+struct bcm_tag {
+	/* 0-3: Version of the image tag */
+	char tag_version[TAGVER_LEN];
+	/* 4-23: Company Line 1 */
+	char sig_1[SIG1_LEN];
+	/*  24-37: Company Line 2 */
+	char sig_2[SIG2_LEN];
+	/* 38-43: Chip this image is for */
+	char chip_id[CHIPID_LEN];
+	/* 44-59: Board name */
+	char board_id[BOARDID_LEN];
+	/* 60-61: Map endianness -- 1 BE 0 LE */
+	char big_endian[ENDIANFLAG_LEN];
+	/* 62-71: Total length of image */
+	char total_length[IMAGE_LEN];
+	/* 72-83: Address in memory of CFE */
+	char cfe__address[ADDRESS_LEN];
+	/* 84-93: Size of CFE */
+	char cfe_length[IMAGE_LEN];
+	/* 94-105: Address in memory of image start
+	 * (kernel for OpenWRT, rootfs for stock firmware)
+	 */
+	char flash_image_start[ADDRESS_LEN];
+	/* 106-115: Size of rootfs */
+	char root_length[IMAGE_LEN];
+	/* 116-127: Address in memory of kernel */
+	char kernel_address[ADDRESS_LEN];
+	/* 128-137: Size of kernel */
+	char kernel_length[IMAGE_LEN];
+	/* 138-139: Unused at the moment */
+	char dual_image[DUALFLAG_LEN];
+	/* 140-141: Unused at the moment */
+	char inactive_flag[INACTIVEFLAG_LEN];
+	/* 142-161: RSA Signature (not used; some vendors may use this) */
+	char rsa_signature[RSASIG_LEN];
+	/* 162-191: Compilation and related information (not used in OpenWrt) */
+	char information1[TAGINFO1_LEN];
+	/* 192-195: Version flash layout */
+	char flash_layout_ver[FLASHLAYOUTVER_LEN];
+	/* 196-199: kernel+rootfs CRC32 */
+	__u32 fskernel_crc;
+	/* 200-215: Unused except on Alice Gate where is is information */
+	char information2[TAGINFO2_LEN];
+	/* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */
+	__u32 image_crc;
+	/* 220-223: CRC32 of rootfs partition */
+	__u32 rootfs_crc;
+	/* 224-227: CRC32 of kernel partition */
+	__u32 kernel_crc;
+	/* 228-231: Image sequence number */
+	char image_sequence[4];
+	/* 222-235: Openwrt: real rootfs length */
+	__u32 real_rootfs_length;
+	/* 236-239: CRC32 of header excluding last 20 bytes */
+	__u32 header_crc;
+	/* 240-255: Unused at present */
+	char reserved2[16];
+};
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+#define CRC_START 0xFFFFFFFF
+
+static uint32_t strntoul(char *str, char **endptr, int base, size_t len) {
+  char *newstr;
+  uint32_t res = 0;
+
+  newstr = calloc(len + 1, sizeof(char));
+  if (newstr) {
+	strncpy(newstr, str, len); 
+	res = strtoul(newstr, endptr, base);
+	free(newstr);
+  }
+  return res;
+}
+
+uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd)
+{
+	uint8_t readbuf[1024];
+	ssize_t res;
+	off_t offset = start;
+
+	/* Read a buffer's worth of bytes  */
+	while (fd && (compute_len >= sizeof(readbuf))) {
+		res = pread(fd, readbuf, sizeof(readbuf), offset);
+		crc = crc32(crc, readbuf, res);
+		compute_len = compute_len - res;
+		offset += res;
+	}
+
+	/* Less than buffer-size bytes remains, read compute_len bytes */
+	if (fd && (compute_len > 0)) {
+	  res = pread(fd, readbuf, compute_len, offset);
+	  crc = crc32(crc, readbuf, res);
+	}
+
+	return crc;
+}
+
+int
+trx_fixup(int fd, const char *name)
+{
+	struct mtd_info_user mtdInfo;
+	unsigned long len;
+	void *ptr, *scan;
+	int bfd;
+	struct bcm_tag *tag;
+	ssize_t res;
+	uint32_t cfelen, imagelen, imagestart, rootfslen;
+	uint32_t imagecrc, rootfscrc, headercrc;
+	uint32_t offset = 0;
+	cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
+
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
+		fprintf(stderr, "Failed to get mtd info\n");
+		goto err;
+	}
+
+	len = mtdInfo.size;
+	if (mtdInfo.size <= 0) {
+		fprintf(stderr, "Invalid MTD device size\n");
+		goto err;
+	}
+
+	bfd = mtd_open(name, true);
+	ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
+	if (!ptr || (ptr == (void *) -1)) {
+		perror("mmap");
+		goto err1;
+	}
+
+	tag = (struct bcm_tag *) (ptr);
+
+	cfelen = strntoul(&tag->cfe_length[0], NULL, 10, IMAGE_LEN);
+	if (cfelen) {
+	  fprintf(stderr, "Non-zero CFE length.  This is currently unsupported.\n");
+	  exit(1);
+	}
+
+	headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd);
+	if (headercrc != *(uint32_t *)(&tag->header_crc)) {
+		fprintf(stderr, "Tag verify failed.  This may not be a valid image.\n");
+		exit(1);
+	}
+
+	sprintf(&tag->root_length[0], "%u", 0);
+	strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN);
+
+	imagestart = sizeof(tag);
+	memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t));
+	memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t));
+	rootfscrc = CRC_START;
+	memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t));
+	headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc));
+	memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t));
+
+	msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE);
+	munmap(ptr, len);
+	close(bfd);
+	return 0;
+
+err1:
+	close(bfd);
+err:
+	fprintf(stderr, "Error fixing up imagetag header\n");
+	return -1;
+}
+
+
+int
+trx_check(int imagefd, const char *mtd, char *buf, int *len)
+{
+    struct bcm_tag *tag = (const struct bcm_tag *) buf;
+	int fd;
+	uint32_t headerCRC;
+	uint32_t imageLen;
+
+	if (strcmp(mtd, "linux") != 0)
+		return 1;
+
+	*len = read(imagefd, buf, sizeof(struct bcm_tag));
+	if (*len < sizeof(struct bcm_tag)) {
+		fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
+		return 0;
+	}
+	headerCRC = crc32buf(buf, offsetof(struct bcm_tag, header_crc));
+	if (*(uint32_t *)(&tag->header_crc) != headerCRC) {
+  
+	  if (quiet < 2) {
+		fprintf(stderr, "Bad header CRC got %08x, calculated %08x\n",
+				*(uint32_t *)(&tag->header_crc), headerCRC);
+		fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
+				"Please specify the correct file or use -f to force.\n");
+	  }
+	  return 0;
+	}
+
+	/* check if image fits to mtd device */
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	imageLen = strntoul(&tag->total_length[0], NULL, 10, IMAGE_LEN);
+	
+	if(mtdsize < imageLen) {
+		fprintf(stderr, "Image too big for partition: %s\n", mtd);
+		close(fd);
+		return 0;
+	}
+
+	close(fd);
+	return 1;
+}
+
+int
+mtd_fixtrx(const char *mtd, size_t offset, size_t data_size)
+{
+	int fd;
+	struct bcm_tag *tag;
+	char *buf;
+	ssize_t res;
+	size_t block_offset;
+	uint32_t cfelen, imagelen, imagestart, rootfslen;
+	uint32_t imagecrc, rootfscrc, headercrc;
+	cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
+
+	if (data_size)
+		fprintf(stderr, "Specifying data size in unsupported for imagetag\n");
+
+	if (quiet < 2)
+		fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+	block_offset = offset & ~(erasesize - 1);
+	offset -= block_offset;
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	if (block_offset + erasesize > mtdsize) {
+		fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+		exit(1);
+	}
+
+	buf = malloc(erasesize);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+
+	res = pread(fd, buf, erasesize, block_offset);
+	if (res != erasesize) {
+		perror("pread");
+		exit(1);
+	}
+
+	tag = (struct bcm_tag *) (buf + offset);
+
+	cfelen = strntoul(tag->cfe_length, NULL, 10, IMAGE_LEN);
+	if (cfelen) {
+	  fprintf(stderr, "Non-zero CFE length.  This is currently unsupported.\n");
+	  exit(1);
+	}
+
+	if (quiet < 2) {
+	  fprintf(stderr, "Verifying we actually have an imagetag.\n");
+	}
+
+	headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd);
+	if (headercrc != *(uint32_t *)(&tag->header_crc)) {
+		fprintf(stderr, "Tag verify failed.  This may not be a valid image.\n");
+		exit(1);
+	}
+
+	if (quiet < 2) {
+	  fprintf(stderr, "Checking current fixed status.\n");
+	}
+
+	rootfslen = strntoul(&tag->root_length[0], NULL, 10, IMAGE_LEN);
+	if (rootfslen == 0) {
+	  if (quiet < 2) 
+		fprintf(stderr, "Header already fixed, exiting\n");
+	  close(fd);
+	  return 0;
+	}
+
+	if (quiet < 2) {
+	  fprintf(stderr, "Setting root length to 0.\n");
+	}
+
+	sprintf(&tag->root_length[0], "%u", 0);
+	strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN);
+
+	if (quiet < 2) {
+	  fprintf(stderr, "Recalculating CRCs.\n");
+	}
+
+	imagestart = sizeof(tag);
+	memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t));
+	memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t));
+	rootfscrc = CRC_START;
+	memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t));
+	headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc));
+	memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t));
+
+	if (quiet < 2) {
+	  fprintf(stderr, "Erasing imagetag block\n");
+	}
+
+	if (mtd_erase_block(fd, block_offset)) {
+		fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2) {
+	  fprintf(stderr, "New image crc32: 0x%x, rewriting block\n", 
+			  *(uint32_t *)(&tag->image_crc));
+	  fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc);  
+	}
+
+	if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
+		fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "Done.\n");
+
+	close (fd);
+	sync();
+	return 0;
+
+}
diff --git a/package/system/mtd/src/jffs2.c b/package/system/mtd/src/jffs2.c
new file mode 100644
index 0000000000..b432f64ac0
--- /dev/null
+++ b/package/system/mtd/src/jffs2.c
@@ -0,0 +1,366 @@
+/*
+ * jffs2 on-disk structure generator for mtd
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * Based on:
+ *   JFFS2 -- Journalling Flash File System, Version 2.
+ *   Copyright © 2001-2007 Red Hat, Inc.
+ *   Created by David Woodhouse <dwmw2@infradead.org>
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <endian.h>
+#include "jffs2.h"
+#include "crc32.h"
+#include "mtd.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"
+#else
+# define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"
+#endif
+
+static int last_ino = 0;
+static int last_version = 0;
+static char *buf = NULL;
+static int ofs = 0;
+static int outfd = -1;
+static int mtdofs = 0;
+static int target_ino = 0;
+
+static void prep_eraseblock(void);
+
+static void pad(int size)
+{
+	if ((ofs % size == 0) && (ofs < erasesize))
+		return;
+
+	if (ofs < erasesize) {
+		memset(buf + ofs, 0xff, (size - (ofs % size)));
+		ofs += (size - (ofs % size));
+	}
+	ofs = ofs % erasesize;
+	if (ofs == 0) {
+		while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize)) {
+			if (!quiet)
+				fprintf(stderr, "\nSkipping bad block at 0x%08x   ", mtdofs);
+
+			mtdofs += erasesize;
+
+			/* Move the file pointer along over the bad block. */
+			lseek(outfd, erasesize, SEEK_CUR);
+		}
+		mtd_erase_block(outfd, mtdofs);
+		write(outfd, buf, erasesize);
+		mtdofs += erasesize;
+	}
+}
+
+static inline int rbytes(void)
+{
+	return erasesize - (ofs % erasesize);
+}
+
+static inline void add_data(char *ptr, int len)
+{
+	if (ofs + len > erasesize) {
+		pad(erasesize);
+		prep_eraseblock();
+	}
+	memcpy(buf + ofs, ptr, len);
+	ofs += len;
+}
+
+static void prep_eraseblock(void)
+{
+	if (ofs > 0)
+		return;
+
+	add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1);
+}
+
+static int add_dirent(const char *name, const char type, int parent)
+{
+	struct jffs2_raw_dirent *de;
+
+	if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name))
+		pad(erasesize);
+
+	prep_eraseblock();
+	last_ino++;
+	memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent));
+	de = (struct jffs2_raw_dirent *) (buf + ofs);
+
+	de->magic = JFFS2_MAGIC_BITMASK;
+	de->nodetype = JFFS2_NODETYPE_DIRENT;
+	de->type = type;
+	de->name_crc = crc32(0, name, strlen(name));
+	de->ino = last_ino++;
+	de->pino = parent;
+	de->totlen = sizeof(*de) + strlen(name);
+	de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4);
+	de->version = last_version++;
+	de->mctime = 0;
+	de->nsize = strlen(name);
+	de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8);
+	memcpy(de->name, name, strlen(name));
+
+	ofs += sizeof(struct jffs2_raw_dirent) + de->nsize;
+	pad(4);
+
+	return de->ino;
+}
+
+static int add_dir(const char *name, int parent)
+{
+	struct jffs2_raw_inode ri;
+	int inode;
+
+	inode = add_dirent(name, IFTODT(S_IFDIR), parent);
+
+	if (rbytes() < sizeof(ri))
+		pad(erasesize);
+	prep_eraseblock();
+
+	memset(&ri, 0, sizeof(ri));
+	ri.magic = JFFS2_MAGIC_BITMASK;
+	ri.nodetype = JFFS2_NODETYPE_INODE;
+	ri.totlen = sizeof(ri);
+	ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
+
+	ri.ino = inode;
+	ri.mode = S_IFDIR | 0755;
+	ri.uid = ri.gid = 0;
+	ri.atime = ri.ctime = ri.mtime = 0;
+	ri.isize = ri.csize = ri.dsize = 0;
+	ri.version = 1;
+	ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
+	ri.data_crc = 0;
+
+	add_data((char *) &ri, sizeof(ri));
+	pad(4);
+	return inode;
+}
+
+static void add_file(const char *name, int parent)
+{
+	int inode, f_offset = 0, fd;
+	struct jffs2_raw_inode ri;
+	struct stat st;
+	char wbuf[4096];
+	const char *fname;
+
+	if (stat(name, &st)) {
+		fprintf(stderr, "File %s does not exist\n", name);
+		return;
+	}
+
+	fname = strrchr(name, '/');
+	if (fname)
+		fname++;
+	else
+		fname = name;
+
+	inode = add_dirent(fname, IFTODT(S_IFREG), parent);
+	memset(&ri, 0, sizeof(ri));
+	ri.magic = JFFS2_MAGIC_BITMASK;
+	ri.nodetype = JFFS2_NODETYPE_INODE;
+
+	ri.ino = inode;
+	ri.mode = st.st_mode;
+	ri.uid = ri.gid = 0;
+	ri.atime = st.st_atime;
+	ri.ctime = st.st_ctime;
+	ri.mtime = st.st_mtime;
+	ri.isize = st.st_size;
+	ri.compr = 0;
+	ri.usercompr = 0;
+
+	fd = open(name, 0);
+	if (fd < 0) {
+		fprintf(stderr, "File %s does not exist\n", name);
+		return;
+	}
+
+	for (;;) {
+		int len = 0;
+
+		for (;;) {
+			len = rbytes() - sizeof(ri);
+			if (len > 128)
+				break;
+
+			pad(erasesize);
+			prep_eraseblock();
+		}
+
+		if (len > sizeof(wbuf))
+			len = sizeof(wbuf);
+
+		len = read(fd, wbuf, len);
+		if (len <= 0)
+			break;
+
+		ri.totlen = sizeof(ri) + len;
+		ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
+		ri.version = ++last_version;
+		ri.offset = f_offset;
+		ri.csize = ri.dsize = len;
+		ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
+		ri.data_crc = crc32(0, wbuf, len);
+		f_offset += len;
+		add_data((char *) &ri, sizeof(ri));
+		add_data(wbuf, len);
+		pad(4);
+		prep_eraseblock();
+	}
+
+	close(fd);
+}
+
+int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
+{
+	outfd = fd;
+	mtdofs = ofs;
+
+	buf = malloc(erasesize);
+	target_ino = 1;
+	if (!last_ino)
+		last_ino = 1;
+	add_file(filename, target_ino);
+	pad(erasesize);
+
+	/* add eof marker, pad to eraseblock size and write the data */
+	add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
+	pad(erasesize);
+	free(buf);
+
+	return (mtdofs - ofs);
+}
+
+void mtd_parse_jffs2data(const char *buf, const char *dir)
+{
+	struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
+	unsigned int ofs = 0;
+
+	while (ofs < erasesize) {
+		node = (struct jffs2_unknown_node *) (buf + ofs);
+		if (node->magic != 0x1985)
+			break;
+
+		ofs += PAD(node->totlen);
+		if (node->nodetype == JFFS2_NODETYPE_DIRENT) {
+			struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node;
+
+			/* is this the right directory name and is it a subdirectory of / */
+			if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize))
+				target_ino = de->ino;
+
+			/* store the last inode and version numbers for adding extra files */
+			if (last_ino < de->ino)
+				last_ino = de->ino;
+			if (last_version < de->version)
+				last_version = de->version;
+		}
+	}
+}
+
+int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
+{
+	int err = -1, fdeof = 0;
+
+	outfd = mtd_check_open(mtd);
+	if (outfd < 0)
+		return -1;
+
+	if (quiet < 2)
+		fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
+	
+	buf = malloc(erasesize);
+	if (!buf) {
+		fprintf(stderr, "Out of memory!\n");
+		goto done;
+	}
+
+	if (!*dir)
+		target_ino = 1;
+
+	/* parse the structure of the jffs2 first
+	 * locate the directory that the file is going to be placed in */
+	for(;;) {
+		struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
+
+		if (read(outfd, buf, erasesize) != erasesize) {
+			fdeof = 1;
+			break;
+		}
+		mtdofs += erasesize;
+
+		if (node->magic == 0x8519) {
+			fprintf(stderr, "Error: wrong endianness filesystem\n");
+			goto done;
+		}
+
+		/* assume  no magic == end of filesystem
+		 * the filesystem will probably end with be32(0xdeadc0de) */
+		if (node->magic != 0x1985)
+			break;
+
+		mtd_parse_jffs2data(buf, dir);
+	}
+
+	if (fdeof) {
+		fprintf(stderr, "Error: No room for additional data\n");
+		goto done;
+	}
+
+	/* jump back one eraseblock */
+	mtdofs -= erasesize;
+	lseek(outfd, mtdofs, SEEK_SET);
+
+	ofs = 0;
+
+	if (!last_ino)
+		last_ino = 1;
+
+	if (!target_ino)
+		target_ino = add_dir(dir, 1);
+
+	add_file(filename, target_ino);
+	pad(erasesize);
+
+	/* add eof marker, pad to eraseblock size and write the data */
+	add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
+	pad(erasesize);
+
+	err = 0;
+
+	if (trx_fixup) {
+	  trx_fixup(outfd, mtd);
+	}
+
+done:
+	close(outfd);
+	if (buf)
+		free(buf);
+
+	return err;
+}
diff --git a/package/system/mtd/src/jffs2.h b/package/system/mtd/src/jffs2.h
new file mode 100644
index 0000000000..858e77a017
--- /dev/null
+++ b/package/system/mtd/src/jffs2.h
@@ -0,0 +1,216 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ *
+ *
+ */
+
+#ifndef __LINUX_JFFS2_H__
+#define __LINUX_JFFS2_H__
+
+#define JFFS2_SUPER_MAGIC   0x72b6
+
+/* You must include something which defines the C99 uintXX_t types. 
+   We don't do it from here because this file is used in too many
+   different environments. */
+
+/* Values we may expect to find in the 'magic' field */
+#define JFFS2_OLD_MAGIC_BITMASK 0x1984
+#define JFFS2_MAGIC_BITMASK 0x1985
+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
+#define JFFS2_EMPTY_BITMASK 0xffff
+#define JFFS2_DIRTY_BITMASK 0x0000
+
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC	0x02851885
+
+/* We only allow a single char for length, and 0xFF is empty flash so
+   we don't want it confused with a real length. Hence max 254.
+*/
+#define JFFS2_MAX_NAME_LEN 254
+
+/* How small can we sensibly write nodes? */
+#define JFFS2_MIN_DATA_LEN 128
+
+#define JFFS2_COMPR_NONE	0x00
+#define JFFS2_COMPR_ZERO	0x01
+#define JFFS2_COMPR_RTIME	0x02
+#define JFFS2_COMPR_RUBINMIPS	0x03
+#define JFFS2_COMPR_COPY	0x04
+#define JFFS2_COMPR_DYNRUBIN	0x05
+#define JFFS2_COMPR_ZLIB	0x06
+/* Compatibility flags. */
+#define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+#define JFFS2_NODE_ACCURATE 0x2000
+/* INCOMPAT: Fail to mount the filesystem */
+#define JFFS2_FEATURE_INCOMPAT 0xc000
+/* ROCOMPAT: Mount read-only */
+#define JFFS2_FEATURE_ROCOMPAT 0x8000
+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
+
+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER		1	/* for "user." */
+#define JFFS2_XPREFIX_SECURITY		2	/* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS	3	/* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT	4	/* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED		5	/* for "trusted.*" */
+
+#define JFFS2_ACL_VERSION		0x0001
+
+// Maybe later...
+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
+
+
+#define JFFS2_INO_FLAG_PREREAD	  1	/* Do read_inode() for this one at
+					   mount time, don't wait for it to
+					   happen later */
+#define JFFS2_INO_FLAG_USERCOMPR  2	/* User has requested a specific
+					   compression type */
+
+
+/* These can go once we've made sure we've caught all uses without
+   byteswapping */
+
+typedef	uint32_t jint32_t;
+
+typedef uint32_t jmode_t;
+
+typedef uint16_t jint16_t;
+
+struct jffs2_unknown_node
+{
+	/* All start like this */
+	jint16_t magic;
+	jint16_t nodetype;
+	jint32_t totlen; /* So we can skip over nodes we don't grok */
+	jint32_t hdr_crc;
+};
+
+struct jffs2_raw_dirent
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* == JFFS2_NODETYPE_DIRENT */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t pino;
+	jint32_t version;
+	jint32_t ino; /* == zero for unlink */
+	jint32_t mctime;
+	uint8_t nsize;
+	uint8_t type;
+	uint8_t unused[2];
+	jint32_t node_crc;
+	jint32_t name_crc;
+	uint8_t name[0];
+};
+
+/* The JFFS2 raw inode structure: Used for storage on physical media.  */
+/* The uid, gid, atime, mtime and ctime members could be longer, but
+   are left like this for space efficiency. If and when people decide
+   they really need them extended, it's simple enough to add support for
+   a new type of raw node.
+*/
+struct jffs2_raw_inode
+{
+	jint16_t magic;      /* A constant magic number.  */
+	jint16_t nodetype;   /* == JFFS2_NODETYPE_INODE */
+	jint32_t totlen;     /* Total length of this node (inc data, etc.) */
+	jint32_t hdr_crc;
+	jint32_t ino;        /* Inode number.  */
+	jint32_t version;    /* Version number.  */
+	jmode_t mode;       /* The file's type or mode.  */
+	jint16_t uid;        /* The file's owner.  */
+	jint16_t gid;        /* The file's group.  */
+	jint32_t isize;      /* Total resultant size of this inode (used for truncations)  */
+	jint32_t atime;      /* Last access time.  */
+	jint32_t mtime;      /* Last modification time.  */
+	jint32_t ctime;      /* Change time.  */
+	jint32_t offset;     /* Where to begin to write.  */
+	jint32_t csize;      /* (Compressed) data size */
+	jint32_t dsize;	     /* Size of the node's data. (after decompression) */
+	uint8_t compr;       /* Compression algorithm used */
+	uint8_t usercompr;   /* Compression algorithm requested by the user */
+	jint16_t flags;	     /* See JFFS2_INO_FLAG_* */
+	jint32_t data_crc;   /* CRC for the (compressed) data.  */
+	jint32_t node_crc;   /* CRC for the raw inode (excluding data)  */
+	uint8_t data[0];
+};
+
+struct jffs2_raw_xattr {
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XATTR */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t version;
+	uint8_t xprefix;
+	uint8_t name_len;
+	jint16_t value_len;
+	jint32_t data_crc;
+	jint32_t node_crc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XREF */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t ino;		/* inode number */
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t xseqno;	/* xref sequencial number */
+	jint32_t node_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_summary
+{
+	jint16_t magic;
+	jint16_t nodetype; 	/* = JFFS2_NODETYPE_SUMMARY */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t sum_num;	/* number of sum entries*/
+	jint32_t cln_mkr;	/* clean marker size, 0 = no cleanmarker */
+	jint32_t padded;	/* sum of the size of padding nodes */
+	jint32_t sum_crc;	/* summary information crc */
+	jint32_t node_crc; 	/* node crc */
+	jint32_t sum[0]; 	/* inode summary info */
+};
+
+union jffs2_node_union
+{
+	struct jffs2_raw_inode i;
+	struct jffs2_raw_dirent d;
+	struct jffs2_raw_xattr x;
+	struct jffs2_raw_xref r;
+	struct jffs2_raw_summary s;
+	struct jffs2_unknown_node u;
+};
+
+/* Data payload for device nodes. */
+union jffs2_device_node {
+	jint16_t old;
+	jint32_t new;
+};
+
+#endif /* __LINUX_JFFS2_H__ */
diff --git a/package/system/mtd/src/linksys_bootcount.c b/package/system/mtd/src/linksys_bootcount.c
new file mode 100644
index 0000000000..500ede4972
--- /dev/null
+++ b/package/system/mtd/src/linksys_bootcount.c
@@ -0,0 +1,115 @@
+/*
+ * Linksys boot counter reset code for mtd
+ *
+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <endian.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "mtd.h"
+
+#define BOOTCOUNT_MAGIC	0x20110811
+
+struct bootcounter {
+	uint32_t magic;
+	uint32_t count;
+	uint32_t checksum;
+};
+
+static char page[2048];
+
+int mtd_resetbc(const char *mtd)
+{
+	struct mtd_info_user mtd_info;
+	struct bootcounter *curr = (struct bootcounter *)page;
+	unsigned int i;
+	int last_count = 0;
+	int num_bc;
+	int fd;
+	int ret;
+
+	fd = mtd_check_open(mtd);
+
+	if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) {
+		fprintf(stderr, "failed to get mtd info!\n");
+		return -1;
+	}
+
+	num_bc = mtd_info.size / mtd_info.writesize;
+
+	for (i = 0; i < num_bc; i++) {
+		pread(fd, curr, sizeof(*curr), i * mtd_info.writesize);
+
+		if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) {
+			fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic);
+			goto out;
+		}
+
+		if (curr->magic == 0xffffffff)
+			break;
+
+		last_count = curr->count;
+	}
+
+	/* no need to do writes when last boot count is already 0 */
+	if (last_count == 0)
+		goto out;
+
+
+	if (i == num_bc) {
+		struct erase_info_user erase_info;
+		erase_info.start = 0;
+		erase_info.length = mtd_info.size;
+
+		/* erase block */
+		ret = ioctl(fd, MEMERASE, &erase_info);
+		if (ret < 0) {
+			fprintf(stderr, "failed to erase block: %i\n", ret);
+			return -1;
+		}
+
+		i = 0;
+	}
+
+	memset(curr, 0xff, mtd_info.writesize);
+
+	curr->magic = BOOTCOUNT_MAGIC;
+	curr->count = 0;
+	curr->checksum = BOOTCOUNT_MAGIC;
+
+	ret = pwrite(fd, curr, mtd_info.writesize, i * mtd_info.writesize);
+	if (ret < 0)
+		fprintf(stderr, "failed to write: %i\n", ret);
+	sync();
+out:
+	close(fd);
+
+	return 0;
+}
diff --git a/package/system/mtd/src/md5.c b/package/system/mtd/src/md5.c
new file mode 100644
index 0000000000..2039760383
--- /dev/null
+++ b/package/system/mtd/src/md5.c
@@ -0,0 +1,307 @@
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include <string.h>
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using MD5_Init       **
+ **    (2) Call MD5_Update on mdContext and M                         **
+ **    (3) Call MD5_Final on mdContext                                **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+
+#ifdef __STDC__
+#define UL(x)	x##U
+#else
+#define UL(x)	x
+#endif
+
+/* The routine MD5_Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void MD5_Init (mdContext)
+MD5_CTX *mdContext;
+{
+  mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (UINT4)0x67452301;
+  mdContext->buf[1] = (UINT4)0xefcdab89;
+  mdContext->buf[2] = (UINT4)0x98badcfe;
+  mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void MD5_Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((UINT4)inLen << 3);
+  mdContext->i[1] += ((UINT4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+                (((UINT4)mdContext->in[ii+2]) << 16) |
+                (((UINT4)mdContext->in[ii+1]) << 8) |
+                ((UINT4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5_Final (hash, mdContext)
+unsigned char hash[];
+MD5_CTX *mdContext;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5_Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+            (((UINT4)mdContext->in[ii+2]) << 16) |
+            (((UINT4)mdContext->in[ii+1]) << 8) |
+            ((UINT4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+  memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+  UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */
+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c                                                      **
+ ******************************** (cut) ********************************
+ */
diff --git a/package/system/mtd/src/md5.h b/package/system/mtd/src/md5.h
new file mode 100644
index 0000000000..f7a0c96418
--- /dev/null
+++ b/package/system/mtd/src/md5.h
@@ -0,0 +1,65 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#ifndef __MD5_INCLUDE__
+
+/* typedef a 32-bit type */
+#ifdef _LP64
+typedef unsigned int UINT4;
+typedef int          INT4;
+#else
+typedef unsigned long UINT4;
+typedef long          INT4;
+#endif
+#define _UINT4_T
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */
+  UINT4 buf[4];                                    /* scratch buffer */
+  unsigned char in[64];                              /* input buffer */
+  unsigned char digest[16];     /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5_Init ();
+void MD5_Update ();
+void MD5_Final ();
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
diff --git a/package/system/mtd/src/mtd.c b/package/system/mtd/src/mtd.c
new file mode 100644
index 0000000000..e66e647c01
--- /dev/null
+++ b/package/system/mtd/src/mtd.c
@@ -0,0 +1,1027 @@
+/*
+ * mtd - simple memory technology device manipulation tool
+ *
+ * Copyright (C) 2005      Waldemar Brodkorb <wbx@dass-it.de>,
+ * Copyright (C) 2005-2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * The code is based on the linux-mtd examples.
+ */
+
+#define _GNU_SOURCE
+#include <byteswap.h>
+#include <endian.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/reboot.h>
+#include <linux/reboot.h>
+#include <mtd/mtd-user.h>
+#include "fis.h"
+#include "mtd.h"
+
+#include <libubox/md5.h>
+
+#define MAX_ARGS 8
+#define JFFS2_DEFAULT_DIR	"" /* directory name without /, empty means root dir */
+
+#define TRX_MAGIC		0x48445230	/* "HDR0" */
+#define SEAMA_MAGIC		0x5ea3a417
+#define WRGG03_MAGIC		0x20080321
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x)	(x)
+#define be32_to_cpu(x)	(x)
+#define le32_to_cpu(x)	bswap_32(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_be32(x)	bswap_32(x)
+#define be32_to_cpu(x)	bswap_32(x)
+#define le32_to_cpu(x)  (x)
+#else
+#error "Unsupported endianness"
+#endif
+
+enum mtd_image_format {
+	MTD_IMAGE_FORMAT_UNKNOWN,
+	MTD_IMAGE_FORMAT_TRX,
+	MTD_IMAGE_FORMAT_SEAMA,
+	MTD_IMAGE_FORMAT_WRGG03,
+};
+
+static char *buf = NULL;
+static char *imagefile = NULL;
+static enum mtd_image_format imageformat = MTD_IMAGE_FORMAT_UNKNOWN;
+static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
+static int buflen = 0;
+int quiet;
+int no_erase;
+int mtdsize = 0;
+int erasesize = 0;
+int jffs2_skip_bytes=0;
+int mtdtype = 0;
+
+int mtd_open(const char *mtd, bool block)
+{
+	FILE *fp;
+	char dev[PATH_MAX];
+	int i;
+	int ret;
+	int flags = O_RDWR | O_SYNC;
+	char name[PATH_MAX];
+
+	snprintf(name, sizeof(name), "\"%s\"", mtd);
+	if ((fp = fopen("/proc/mtd", "r"))) {
+		while (fgets(dev, sizeof(dev), fp)) {
+			if (sscanf(dev, "mtd%d:", &i) && strstr(dev, name)) {
+				snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
+				if ((ret=open(dev, flags))<0) {
+					snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
+					ret=open(dev, flags);
+				}
+				fclose(fp);
+				return ret;
+			}
+		}
+		fclose(fp);
+	}
+
+	return open(mtd, flags);
+}
+
+int mtd_check_open(const char *mtd)
+{
+	struct mtd_info_user mtdInfo;
+	int fd;
+
+	fd = mtd_open(mtd, false);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		return -1;
+	}
+
+	if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
+		fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
+		close(fd);
+		return -1;
+	}
+	mtdsize = mtdInfo.size;
+	erasesize = mtdInfo.erasesize;
+	mtdtype = mtdInfo.type;
+
+	return fd;
+}
+
+int mtd_block_is_bad(int fd, int offset)
+{
+	int r = 0;
+	loff_t o = offset;
+
+	if (mtdtype == MTD_NANDFLASH)
+	{
+		r = ioctl(fd, MEMGETBADBLOCK, &o);
+		if (r < 0)
+		{
+			fprintf(stderr, "Failed to get erase block status\n");
+			exit(1);
+		}
+	}
+	return r;
+}
+
+int mtd_erase_block(int fd, int offset)
+{
+	struct erase_info_user mtdEraseInfo;
+
+	mtdEraseInfo.start = offset;
+	mtdEraseInfo.length = erasesize;
+	ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+	if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0)
+		return -1;
+
+	return 0;
+}
+
+int mtd_write_buffer(int fd, const char *buf, int offset, int length)
+{
+	lseek(fd, offset, SEEK_SET);
+	write(fd, buf, length);
+	return 0;
+}
+
+static int
+image_check(int imagefd, const char *mtd)
+{
+	uint32_t magic;
+	int ret = 1;
+	int bufread;
+
+	while (buflen < sizeof(magic)) {
+		bufread = read(imagefd, buf + buflen, sizeof(magic) - buflen);
+		if (bufread < 1)
+			break;
+
+		buflen += bufread;
+	}
+
+	if (buflen < sizeof(magic)) {
+		fprintf(stdout, "Could not get image magic\n");
+		return 0;
+	}
+
+	magic = ((uint32_t *)buf)[0];
+
+	if (be32_to_cpu(magic) == TRX_MAGIC)
+		imageformat = MTD_IMAGE_FORMAT_TRX;
+	else if (be32_to_cpu(magic) == SEAMA_MAGIC)
+		imageformat = MTD_IMAGE_FORMAT_SEAMA;
+	else if (le32_to_cpu(magic) == WRGG03_MAGIC)
+		imageformat = MTD_IMAGE_FORMAT_WRGG03;
+
+	switch (imageformat) {
+	case MTD_IMAGE_FORMAT_TRX:
+		if (trx_check)
+			ret = trx_check(imagefd, mtd, buf, &buflen);
+		break;
+	case MTD_IMAGE_FORMAT_SEAMA:
+		break;
+	case MTD_IMAGE_FORMAT_WRGG03:
+		break;
+	default:
+#ifdef target_brcm
+		if (!strcmp(mtd, "firmware"))
+			ret = 0;
+#endif
+		break;
+	}
+
+	return ret;
+}
+
+static int mtd_check(const char *mtd)
+{
+	char *next = NULL;
+	char *str = NULL;
+	int fd;
+
+	if (strchr(mtd, ':')) {
+		str = strdup(mtd);
+		mtd = str;
+	}
+
+	do {
+		next = strchr(mtd, ':');
+		if (next) {
+			*next = 0;
+			next++;
+		}
+
+		fd = mtd_check_open(mtd);
+		if (fd < 0)
+			return 0;
+
+		if (!buf)
+			buf = malloc(erasesize);
+
+		close(fd);
+		mtd = next;
+	} while (next);
+
+	if (str)
+		free(str);
+
+	return 1;
+}
+
+static int
+mtd_unlock(const char *mtd)
+{
+	struct erase_info_user mtdLockInfo;
+	char *next = NULL;
+	char *str = NULL;
+	int fd;
+
+	if (strchr(mtd, ':')) {
+		str = strdup(mtd);
+		mtd = str;
+	}
+
+	do {
+		next = strchr(mtd, ':');
+		if (next) {
+			*next = 0;
+			next++;
+		}
+
+		fd = mtd_check_open(mtd);
+		if(fd < 0) {
+			fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+			exit(1);
+		}
+
+		if (quiet < 2)
+			fprintf(stderr, "Unlocking %s ...\n", mtd);
+
+		mtdLockInfo.start = 0;
+		mtdLockInfo.length = mtdsize;
+		ioctl(fd, MEMUNLOCK, &mtdLockInfo);
+		close(fd);
+		mtd = next;
+	} while (next);
+
+	if (str)
+		free(str);
+
+	return 0;
+}
+
+static int
+mtd_erase(const char *mtd)
+{
+	int fd;
+	struct erase_info_user mtdEraseInfo;
+
+	if (quiet < 2)
+		fprintf(stderr, "Erasing %s ...\n", mtd);
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	mtdEraseInfo.length = erasesize;
+
+	for (mtdEraseInfo.start = 0;
+		 mtdEraseInfo.start < mtdsize;
+		 mtdEraseInfo.start += erasesize) {
+		if (mtd_block_is_bad(fd, mtdEraseInfo.start)) {
+			if (!quiet)
+				fprintf(stderr, "\nSkipping bad block at 0x%x   ", mtdEraseInfo.start);
+		} else {
+			ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+			if(ioctl(fd, MEMERASE, &mtdEraseInfo))
+				fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
+		}
+	}
+
+	close(fd);
+	return 0;
+
+}
+
+static int
+mtd_dump(const char *mtd, int part_offset, int size)
+{
+	int ret = 0, offset = 0;
+	int fd;
+	char *buf;
+
+	if (quiet < 2)
+		fprintf(stderr, "Dumping %s ...\n", mtd);
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		return -1;
+	}
+
+	if (!size)
+		size = mtdsize;
+
+	if (part_offset)
+		lseek(fd, part_offset, SEEK_SET);
+
+	buf = malloc(erasesize);
+	if (!buf)
+		return -1;
+
+	do {
+		int len = (size > erasesize) ? (erasesize) : (size);
+		int rlen = read(fd, buf, len);
+
+		if (rlen < 0) {
+			if (errno == EINTR)
+				continue;
+			ret = -1;
+			goto out;
+		}
+		if (!rlen || rlen != len)
+			break;
+		if (mtd_block_is_bad(fd, offset)) {
+			fprintf(stderr, "skipping bad block at 0x%08x\n", offset);
+		} else {
+			size -= rlen;
+			write(1, buf, rlen);
+		}
+		offset += rlen;
+	} while (size > 0);
+
+out:
+	close(fd);
+	return ret;
+}
+
+static int
+mtd_verify(const char *mtd, char *file)
+{
+	uint32_t f_md5[4], m_md5[4];
+	struct stat s;
+	md5_ctx_t ctx;
+	int ret = 0;
+	int fd;
+
+	if (quiet < 2)
+		fprintf(stderr, "Verifying %s against %s ...\n", mtd, file);
+
+	if (stat(file, &s) || md5sum(file, f_md5) < 0) {
+		fprintf(stderr, "Failed to hash %s\n", file);
+		return -1;
+	}
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		return -1;
+	}
+
+	md5_begin(&ctx);
+	do {
+		char buf[256];
+		int len = (s.st_size > sizeof(buf)) ? (sizeof(buf)) : (s.st_size);
+		int rlen = read(fd, buf, len);
+
+		if (rlen < 0) {
+			if (errno == EINTR)
+				continue;
+			ret = -1;
+			goto out;
+		}
+		if (!rlen)
+			break;
+		md5_hash(buf, rlen, &ctx);
+		s.st_size -= rlen;
+	} while (s.st_size > 0);
+
+	md5_end(m_md5, &ctx);
+
+	fprintf(stderr, "%08x%08x%08x%08x - %s\n", m_md5[0], m_md5[1], m_md5[2], m_md5[3], mtd);
+	fprintf(stderr, "%08x%08x%08x%08x - %s\n", f_md5[0], f_md5[1], f_md5[2], f_md5[3], file);
+
+	ret = memcmp(f_md5, m_md5, sizeof(m_md5));
+	if (!ret)
+		fprintf(stderr, "Success\n");
+	else
+		fprintf(stderr, "Failed\n");
+
+out:
+	close(fd);
+	return ret;
+}
+
+static void
+indicate_writing(const char *mtd)
+{
+	if (quiet < 2)
+		fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd);
+
+	if (!quiet)
+		fprintf(stderr, " [ ]");
+}
+
+static int
+mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
+{
+	char *next = NULL;
+	char *str = NULL;
+	int fd, result;
+	ssize_t r, w, e;
+	ssize_t skip = 0;
+	uint32_t offset = 0;
+	int jffs2_replaced = 0;
+	int skip_bad_blocks = 0;
+
+#ifdef FIS_SUPPORT
+	static struct fis_part new_parts[MAX_ARGS];
+	static struct fis_part old_parts[MAX_ARGS];
+	int n_new = 0, n_old = 0;
+
+	if (fis_layout) {
+		const char *tmp = mtd;
+		char *word, *brkt;
+		int ret;
+
+		memset(&old_parts, 0, sizeof(old_parts));
+		memset(&new_parts, 0, sizeof(new_parts));
+
+		do {
+			next = strchr(tmp, ':');
+			if (!next)
+				next = (char *) tmp + strlen(tmp);
+
+			memcpy(old_parts[n_old].name, tmp, next - tmp);
+
+			n_old++;
+			tmp = next + 1;
+		} while(*next);
+
+		for (word = strtok_r(fis_layout, ",", &brkt);
+		     word;
+			 word = strtok_r(NULL, ",", &brkt)) {
+
+			tmp = strtok(word, ":");
+			strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1);
+
+			tmp = strtok(NULL, ":");
+			if (!tmp)
+				goto next;
+
+			new_parts[n_new].size = strtoul(tmp, NULL, 0);
+
+			tmp = strtok(NULL, ":");
+			if (!tmp)
+				goto next;
+
+			new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16);
+next:
+			n_new++;
+		}
+		ret = fis_validate(old_parts, n_old, new_parts, n_new);
+		if (ret < 0) {
+			fprintf(stderr, "Failed to validate the new FIS partition table\n");
+			exit(1);
+		}
+		if (ret == 0)
+			fis_layout = NULL;
+	}
+#endif
+
+	if (strchr(mtd, ':')) {
+		str = strdup(mtd);
+		mtd = str;
+	}
+
+	r = 0;
+
+resume:
+	next = strchr(mtd, ':');
+	if (next) {
+		*next = 0;
+		next++;
+	}
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+	if (part_offset > 0) {
+		fprintf(stderr, "Seeking on mtd device '%s' to: %zu\n", mtd, part_offset);
+		lseek(fd, part_offset, SEEK_SET);
+	}
+
+	indicate_writing(mtd);
+
+	w = e = 0;
+	for (;;) {
+		/* buffer may contain data already (from trx check or last mtd partition write attempt) */
+		while (buflen < erasesize) {
+			r = read(imagefd, buf + buflen, erasesize - buflen);
+			if (r < 0) {
+				if ((errno == EINTR) || (errno == EAGAIN))
+					continue;
+				else {
+					perror("read");
+					break;
+				}
+			}
+
+			if (r == 0)
+				break;
+
+			buflen += r;
+		}
+
+		if (buflen == 0)
+			break;
+
+		if (buflen < erasesize) {
+			/* Pad block to eraseblock size */
+			memset(&buf[buflen], 0xff, erasesize - buflen);
+			buflen = erasesize;
+		}
+
+		if (skip > 0) {
+			skip -= buflen;
+			buflen = 0;
+			if (skip <= 0)
+				indicate_writing(mtd);
+
+			continue;
+		}
+
+		if (jffs2file && w >= jffs2_skip_bytes) {
+			if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
+				if (!quiet)
+					fprintf(stderr, "\b\b\b   ");
+				if (quiet < 2)
+					fprintf(stderr, "\nAppending jffs2 data from %s to %s..\n.", jffs2file, mtd);
+				/* got an EOF marker - this is the place to add some jffs2 data */
+				skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
+				jffs2_replaced = 1;
+
+				/* don't add it again */
+				jffs2file = NULL;
+
+				w += skip;
+				e += skip;
+				skip -= buflen;
+				buflen = 0;
+				offset = 0;
+				continue;
+			}
+			/* no EOF marker, make sure we figure out the last inode number
+			 * before appending some data */
+			mtd_parse_jffs2data(buf, jffs2dir);
+		}
+
+		/* need to erase the next block before writing data to it */
+		if(!no_erase)
+		{
+			while (w + buflen > e - skip_bad_blocks) {
+				if (!quiet)
+					fprintf(stderr, "\b\b\b[e]");
+
+				if (mtd_block_is_bad(fd, e)) {
+					if (!quiet)
+						fprintf(stderr, "\nSkipping bad block at 0x%08zx   ", e);
+
+					skip_bad_blocks += erasesize;
+					e += erasesize;
+
+					// Move the file pointer along over the bad block.
+					lseek(fd, erasesize, SEEK_CUR);
+					continue;
+				}
+
+				if (mtd_erase_block(fd, e) < 0) {
+					if (next) {
+						if (w < e) {
+							write(fd, buf + offset, e - w);
+							offset = e - w;
+						}
+						w = 0;
+						e = 0;
+						close(fd);
+						mtd = next;
+						fprintf(stderr, "\b\b\b   \n");
+						goto resume;
+					} else {
+						fprintf(stderr, "Failed to erase block\n");
+						exit(1);
+					}
+				}
+
+				/* erase the chunk */
+				e += erasesize;
+			}
+		}
+
+		if (!quiet)
+			fprintf(stderr, "\b\b\b[w]");
+
+		if ((result = write(fd, buf + offset, buflen)) < buflen) {
+			if (result < 0) {
+				fprintf(stderr, "Error writing image.\n");
+				exit(1);
+			} else {
+				fprintf(stderr, "Insufficient space.\n");
+				exit(1);
+			}
+		}
+		w += buflen;
+
+		buflen = 0;
+		offset = 0;
+	}
+
+	if (jffs2_replaced) {
+		switch (imageformat) {
+		case MTD_IMAGE_FORMAT_TRX:
+			if (trx_fixup)
+				trx_fixup(fd, mtd);
+			break;
+		case MTD_IMAGE_FORMAT_SEAMA:
+			if (mtd_fixseama)
+				mtd_fixseama(mtd, 0, 0);
+			break;
+		case MTD_IMAGE_FORMAT_WRGG03:
+			if (mtd_fixwrgg)
+				mtd_fixwrgg(mtd, 0, 0);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!quiet)
+		fprintf(stderr, "\b\b\b\b    ");
+
+	if (quiet < 2)
+		fprintf(stderr, "\n");
+
+#ifdef FIS_SUPPORT
+	if (fis_layout) {
+		if (fis_remap(old_parts, n_old, new_parts, n_new) < 0)
+			fprintf(stderr, "Failed to update the FIS partition table\n");
+	}
+#endif
+
+	close(fd);
+	return 0;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>[:<device>...]\n\n"
+	"The device is in the format of mtdX (eg: mtd4) or its label.\n"
+	"mtd recognizes these commands:\n"
+	"        unlock                  unlock the device\n"
+	"        refresh                 refresh mtd partition\n"
+	"        erase                   erase all data on device\n"
+	"        verify <imagefile>|-    verify <imagefile> (use - for stdin) to device\n"
+	"        write <imagefile>|-     write <imagefile> (use - for stdin) to device\n"
+	"        jffs2write <file>       append <file> to the jffs2 partition on the device\n");
+	if (mtd_resetbc) {
+	    fprintf(stderr,
+	"        resetbc <device>        reset the uboot boot counter\n");
+	}
+	if (mtd_fixtrx) {
+	    fprintf(stderr,
+	"        fixtrx                  fix the checksum in a trx header on first boot\n");
+	}
+	if (mtd_fixseama) {
+	    fprintf(stderr,
+	"        fixseama                fix the checksum in a seama header on first boot\n");
+	}
+	if (mtd_fixwrgg) {
+	    fprintf(stderr,
+	"        fixwrgg                 fix the checksum in a wrgg header on first boot\n");
+	}
+	fprintf(stderr,
+	"Following options are available:\n"
+	"        -q                      quiet mode (once: no [w] on writing,\n"
+	"                                           twice: no status messages)\n"
+	"        -n                      write without first erasing the blocks\n"
+	"        -r                      reboot after successful command\n"
+	"        -f                      force write without trx checks\n"
+	"        -e <device>             erase <device> before executing the command\n"
+	"        -d <name>               directory for jffs2write, defaults to \"tmp\"\n"
+	"        -j <name>               integrate <file> into jffs2 data when writing an image\n"
+	"        -s <number>             skip the first n bytes when appending data to the jffs2 partiton, defaults to \"0\"\n"
+	"        -p <number>             write beginning at partition offset\n"
+	"        -l <length>             the length of data that we want to dump\n");
+	if (mtd_fixtrx) {
+	    fprintf(stderr,
+	"        -o offset               offset of the image header in the partition(for fixtrx)\n");
+	}
+	if (mtd_fixtrx || mtd_fixseama || mtd_fixwrgg) {
+		fprintf(stderr,
+	"        -c datasize             amount of data to be used for checksum calculation (for fixtrx / fixseama / fixwrgg)\n");
+	}
+	fprintf(stderr,
+#ifdef FIS_SUPPORT
+	"        -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
+	"                                alter the fis partition table to create new partitions replacing\n"
+	"                                the partitions provided as argument to the write command\n"
+	"                                (only valid together with the write command)\n"
+#endif
+	"\n"
+	"Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"
+	"         mtd -r write linux.trx linux\n\n");
+	exit(1);
+}
+
+static void do_reboot(void)
+{
+	fprintf(stderr, "Rebooting ...\n");
+	fflush(stderr);
+
+	/* try regular reboot method first */
+	system("/sbin/reboot");
+	sleep(2);
+
+	/* if we're still alive at this point, force the kernel to reboot */
+	syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
+}
+
+int main (int argc, char **argv)
+{
+	int ch, i, boot, imagefd = 0, force, unlocked;
+	char *erase[MAX_ARGS], *device = NULL;
+	char *fis_layout = NULL;
+	size_t offset = 0, data_size = 0, part_offset = 0, dump_len = 0;
+	enum {
+		CMD_ERASE,
+		CMD_WRITE,
+		CMD_UNLOCK,
+		CMD_JFFS2WRITE,
+		CMD_FIXTRX,
+		CMD_FIXSEAMA,
+		CMD_FIXWRGG,
+		CMD_VERIFY,
+		CMD_DUMP,
+		CMD_RESETBC,
+	} cmd = -1;
+
+	erase[0] = NULL;
+	boot = 0;
+	force = 0;
+	buflen = 0;
+	quiet = 0;
+	no_erase = 0;
+
+	while ((ch = getopt(argc, argv,
+#ifdef FIS_SUPPORT
+			"F:"
+#endif
+			"frnqe:d:s:j:p:o:c:l:")) != -1)
+		switch (ch) {
+			case 'f':
+				force = 1;
+				break;
+			case 'r':
+				boot = 1;
+				break;
+			case 'n':
+				no_erase = 1;
+				break;
+			case 'j':
+				jffs2file = optarg;
+				break;
+			case 's':
+				errno = 0;
+				jffs2_skip_bytes = strtoul(optarg, 0, 0);
+				if (errno) {
+						fprintf(stderr, "-s: illegal numeric string\n");
+						usage();
+				}
+				break;
+			case 'q':
+				quiet++;
+				break;
+			case 'e':
+				i = 0;
+				while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
+					i++;
+
+				erase[i++] = optarg;
+				erase[i] = NULL;
+				break;
+			case 'd':
+				jffs2dir = optarg;
+				break;
+			case 'p':
+				errno = 0;
+				part_offset = strtoul(optarg, 0, 0);
+				if (errno) {
+					fprintf(stderr, "-p: illegal numeric string\n");
+					usage();
+				}
+				break;
+			case 'l':
+				errno = 0;
+				dump_len = strtoul(optarg, 0, 0);
+				if (errno) {
+					fprintf(stderr, "-l: illegal numeric string\n");
+					usage();
+				}
+				break;
+			case 'o':
+				errno = 0;
+				offset = strtoul(optarg, 0, 0);
+				if (errno) {
+					fprintf(stderr, "-o: illegal numeric string\n");
+					usage();
+				}
+				break;
+			case 'c':
+				errno = 0;
+				data_size = strtoul(optarg, 0, 0);
+				if (errno) {
+					fprintf(stderr, "-c: illegal numeric string\n");
+					usage();
+				}
+				break;
+#ifdef FIS_SUPPORT
+			case 'F':
+				fis_layout = optarg;
+				break;
+#endif
+			case '?':
+			default:
+				usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 2)
+		usage();
+
+	if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
+		cmd = CMD_UNLOCK;
+		device = argv[1];
+	} else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
+		cmd = CMD_ERASE;
+		device = argv[1];
+	} else if (((strcmp(argv[0], "resetbc") == 0) && (argc == 2)) && mtd_resetbc) {
+		cmd = CMD_RESETBC;
+		device = argv[1];
+	} else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) {
+		cmd = CMD_FIXTRX;
+		device = argv[1];
+	} else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
+		cmd = CMD_FIXSEAMA;
+		device = argv[1];
+	} else if (((strcmp(argv[0], "fixwrgg") == 0) && (argc == 2)) && mtd_fixwrgg) {
+		cmd = CMD_FIXWRGG;
+		device = argv[1];
+	} else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) {
+		cmd = CMD_VERIFY;
+		imagefile = argv[1];
+		device = argv[2];
+	} else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) {
+		cmd = CMD_DUMP;
+		device = argv[1];
+	} else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
+		cmd = CMD_WRITE;
+		device = argv[2];
+
+		if (strcmp(argv[1], "-") == 0) {
+			imagefile = "<stdin>";
+			imagefd = 0;
+		} else {
+			imagefile = argv[1];
+			if ((imagefd = open(argv[1], O_RDONLY)) < 0) {
+				fprintf(stderr, "Couldn't open image file: %s!\n", imagefile);
+				exit(1);
+			}
+		}
+
+		if (!mtd_check(device)) {
+			fprintf(stderr, "Can't open device for writing!\n");
+			exit(1);
+		}
+		/* check trx file before erasing or writing anything */
+		if (!image_check(imagefd, device) && !force) {
+			fprintf(stderr, "Image check failed.\n");
+			exit(1);
+		}
+	} else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
+		cmd = CMD_JFFS2WRITE;
+		device = argv[2];
+
+		imagefile = argv[1];
+		if (!mtd_check(device)) {
+			fprintf(stderr, "Can't open device for writing!\n");
+			exit(1);
+		}
+	} else {
+		usage();
+	}
+
+	sync();
+
+	i = 0;
+	unlocked = 0;
+	while (erase[i] != NULL) {
+		mtd_unlock(erase[i]);
+		mtd_erase(erase[i]);
+		if (strcmp(erase[i], device) == 0)
+			unlocked = 1;
+		i++;
+	}
+
+	switch (cmd) {
+		case CMD_UNLOCK:
+			if (!unlocked)
+				mtd_unlock(device);
+			break;
+		case CMD_VERIFY:
+			mtd_verify(device, imagefile);
+			break;
+		case CMD_DUMP:
+			mtd_dump(device, offset, dump_len);
+			break;
+		case CMD_ERASE:
+			if (!unlocked)
+				mtd_unlock(device);
+			mtd_erase(device);
+			break;
+		case CMD_WRITE:
+			if (!unlocked)
+				mtd_unlock(device);
+			mtd_write(imagefd, device, fis_layout, part_offset);
+			break;
+		case CMD_JFFS2WRITE:
+			if (!unlocked)
+				mtd_unlock(device);
+			mtd_write_jffs2(device, imagefile, jffs2dir);
+			break;
+		case CMD_FIXTRX:
+			if (mtd_fixtrx) {
+				mtd_fixtrx(device, offset, data_size);
+			}
+			break;
+		case CMD_RESETBC:
+			if (mtd_resetbc) {
+				mtd_resetbc(device);
+			}
+			break;
+		case CMD_FIXSEAMA:
+			if (mtd_fixseama)
+				mtd_fixseama(device, 0, data_size);
+			break;
+		case CMD_FIXWRGG:
+			if (mtd_fixwrgg)
+				mtd_fixwrgg(device, 0, data_size);
+			break;
+	}
+
+	sync();
+
+	if (boot)
+		do_reboot();
+
+	return 0;
+}
diff --git a/package/system/mtd/src/mtd.h b/package/system/mtd/src/mtd.h
new file mode 100644
index 0000000000..50a42da14b
--- /dev/null
+++ b/package/system/mtd/src/mtd.h
@@ -0,0 +1,32 @@
+#ifndef __mtd_h
+#define __mtd_h
+
+#include <stdbool.h>
+
+#if defined(target_brcm47xx) || defined(target_bcm53xx)
+#define target_brcm 1
+#endif
+
+#define JFFS2_EOF "\xde\xad\xc0\xde"
+
+extern int quiet;
+extern int mtdsize;
+extern int erasesize;
+
+extern int mtd_open(const char *mtd, bool block);
+extern int mtd_check_open(const char *mtd);
+extern int mtd_block_is_bad(int fd, int offset);
+extern int mtd_erase_block(int fd, int offset);
+extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);
+extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir);
+extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename);
+extern void mtd_parse_jffs2data(const char *buf, const char *dir);
+
+/* target specific functions */
+extern int trx_fixup(int fd, const char *name)  __attribute__ ((weak));
+extern int trx_check(int imagefd, const char *mtd, char *buf, int *len) __attribute__ ((weak));
+extern int mtd_fixtrx(const char *mtd, size_t offset, size_t data_size) __attribute__ ((weak));
+extern int mtd_fixseama(const char *mtd, size_t offset, size_t data_size) __attribute__ ((weak));
+extern int mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size) __attribute__ ((weak));
+extern int mtd_resetbc(const char *mtd) __attribute__ ((weak));
+#endif /* __mtd_h */
diff --git a/package/system/mtd/src/seama.c b/package/system/mtd/src/seama.c
new file mode 100644
index 0000000000..1f66adc439
--- /dev/null
+++ b/package/system/mtd/src/seama.c
@@ -0,0 +1,188 @@
+/*
+ * seama.c
+ *
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the trx fixup code:
+ *   Copyright (C) 2005 Mike Baker
+ *   Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "seama.h"
+#include "md5.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)           (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+int
+seama_fix_md5(struct seama_entity_header *shdr, int fd, size_t data_offset, size_t data_size)
+{
+	char *buf;
+	ssize_t res;
+	MD5_CTX ctx;
+	unsigned char digest[16];
+	int i;
+	int err = 0;
+
+	buf = malloc(data_size);
+	if (!buf) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	res = pread(fd, buf, data_size, data_offset);
+	if (res != data_size) {
+		perror("pread");
+		err = -EIO;
+		goto err_free;
+	}
+
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, buf, data_size);
+	MD5_Final(digest, &ctx);
+
+	if (!memcmp(digest, shdr->md5, sizeof(digest))) {
+		if (quiet < 2)
+			fprintf(stderr, "the header is fixed already\n");
+		return -1;
+	}
+
+	if (quiet < 2) {
+		fprintf(stderr, "new size:%u, new MD5: ", data_size);
+		for (i = 0; i < sizeof(digest); i++)
+			fprintf(stderr, "%02x", digest[i]);
+
+		fprintf(stderr, "\n");
+	}
+
+	/* update the size in the image */
+	shdr->size = htonl(data_size);
+
+	/* update the checksum in the image */
+	memcpy(shdr->md5, digest, sizeof(digest));
+
+err_free:
+	free(buf);
+err_out:
+	return err;
+}
+
+int
+mtd_fixseama(const char *mtd, size_t offset, size_t data_size)
+{
+	int fd;
+	char *first_block;
+	ssize_t res;
+	size_t block_offset;
+	size_t data_offset;
+	struct seama_entity_header *shdr;
+
+	if (quiet < 2)
+		fprintf(stderr, "Trying to fix SEAMA header in %s at 0x%x...\n",
+			mtd, offset);
+
+	block_offset = offset & ~(erasesize - 1);
+	offset -= block_offset;
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	if (block_offset + erasesize > mtdsize) {
+		fprintf(stderr, "Offset too large, device size 0x%x\n",
+			mtdsize);
+		exit(1);
+	}
+
+	first_block = malloc(erasesize);
+	if (!first_block) {
+		perror("malloc");
+		exit(1);
+	}
+
+	res = pread(fd, first_block, erasesize, block_offset);
+	if (res != erasesize) {
+		perror("pread");
+		exit(1);
+	}
+
+	shdr = (struct seama_entity_header *)(first_block + offset);
+	if (shdr->magic != htonl(SEAMA_MAGIC)) {
+		fprintf(stderr, "No SEAMA header found\n");
+		exit(1);
+	} else if (!ntohl(shdr->size)) {
+		fprintf(stderr, "Seama entity with empty image\n");
+		exit(1);
+	}
+
+	data_offset = offset + sizeof(struct seama_entity_header) + ntohs(shdr->metasize);
+	if (!data_size)
+		data_size = mtdsize - data_offset;
+	if (data_size > ntohl(shdr->size))
+		data_size = ntohl(shdr->size);
+	if (seama_fix_md5(shdr, fd, data_offset, data_size))
+		goto out;
+
+	if (mtd_erase_block(fd, block_offset)) {
+		fprintf(stderr, "Can't erease block at 0x%x (%s)\n",
+			block_offset, strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "Rewriting block at 0x%x\n", block_offset);
+
+	if (pwrite(fd, first_block, erasesize, block_offset) != erasesize) {
+		fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "Done.\n");
+
+out:
+	close (fd);
+	sync();
+
+	return 0;
+}
+
diff --git a/package/system/mtd/src/seama.h b/package/system/mtd/src/seama.h
new file mode 100644
index 0000000000..c6634bd15a
--- /dev/null
+++ b/package/system/mtd/src/seama.h
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *	(SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ *	Created by David Hsieh <david_hsieh@alphanetworks.com>
+ *	Copyright (C) 2008-2009 Alpha Networks, Inc.
+ *
+ *	This file is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation; either'
+ *	version 2.1 of the License, or (at your option) any later version.
+ *
+ *	The GNU C Library is distributed in the hope that it will be useful,'
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *	Lesser General Public License for more details.
+ *
+ *	You should have received a copy of the GNU Lesser General Public
+ *	License along with the GNU C Library; if not, write to the Free
+ *	Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *	02111-1307 USA.
+ */
+
+#ifndef __SEAMA_HEADER_FILE__
+#define __SEAMA_HEADER_FILE__
+
+#include <stdint.h>
+
+#define SEAMA_MAGIC		0x5EA3A417
+
+/*
+ *	SEAMA looks like the following map.
+ *	All the data of the header should be in network byte order.
+ *
+ *  +-------------+-------------+------------
+ *	| SEAMA magic               |     ^
+ *  +-------------+-------------+     |
+ *	| reserved    | meta size   |     |
+ *  +-------------+-------------+   header
+ *	| image size (0 bytes)      |     |
+ *  +-------------+-------------+     |
+ *	~ Meta data                 ~     v
+ *  +-------------+-------------+------------
+ *	| SEAMA magic               |   ^     ^
+ *  +-------------+-------------+   |     |
+ *	| reserved    | meta size   |   |     |
+ *  +-------------+-------------+   |     |
+ *	| image size                |   |     |
+ *  +-------------+-------------+ header  |
+ *	|                           |   |     |
+ *	| 16 bytes of MD5 digest    |   |     |
+ *	|                           |   |     |
+ *	|                           |   |     |
+ *  +-------------+-------------+   |     |
+ *	~ Meta data                 ~   v     |
+ *  +-------------+-------------+-------  |
+ *	|                           |         |
+ *	| Image of the 1st entity   |         |
+ *	~                           ~ 1st entity
+ *	|                           |         |
+ *	|                           |         v
+ *  +-------------+-------------+-------------
+ *	| SEAMA magic               |   ^     ^
+ *  +-------------+-------------+   |     |
+ *	| reserved    | meta size   |   |     |
+ *  +-------------+-------------+   |     |
+ *	| image size                |   |     |
+ *  +-------------+-------------+ header  |
+ *	|                           |   |     |
+ *	| 16 bytes of MD5 digest    |   |     |
+ *	|                           |   |     |
+ *	|                           |   |     |
+ *  +-------------+-------------+   |     |
+ *	~ Meta data                 ~   v     |
+ *  +-------------+-------------+-------  |
+ *	|                           |         |
+ *	| Image of the 2nd entity   |         |
+ *	~                           ~ 2nd entity
+ *	|                           |         |
+ *	|                           |         v
+ *  +-------------+-------------+-------------
+ */
+
+
+/*
+ *	SEAMA header
+ *
+ *	|<-------- 32 bits -------->|
+ *  +-------------+-------------+
+ *	| SEAMA magic               |
+ *  +-------------+-------------+
+ *	| reserved    | meta size   |
+ *  +-------------+-------------+
+ *	| image size                |
+ *  +-------------+-------------+
+ */
+
+/* seama header */
+struct seama_entity_header {
+	uint32_t	magic;			/* should always be SEAMA_MAGIC. */
+	uint16_t	reserved;		/* reserved for  */
+	uint16_t	metasize;		/* size of the META data */
+	uint32_t	size;			/* size of the image */
+	uint8_t		md5[16];
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/package/system/mtd/src/trx.c b/package/system/mtd/src/trx.c
new file mode 100644
index 0000000000..1f5c52914c
--- /dev/null
+++ b/package/system/mtd/src/trx.c
@@ -0,0 +1,247 @@
+/*
+ * trx.c
+ *
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <endian.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "crc32.h"
+
+#define TRX_MAGIC       0x30524448      /* "HDR0" */
+#define TRX_CRC32_DATA_OFFSET	12	/* First 12 bytes are not covered by CRC32 */
+#define TRX_CRC32_DATA_SIZE	16
+struct trx_header {
+	uint32_t magic;		/* "HDR0" */
+	uint32_t len;		/* Length of file including header */
+	uint32_t crc32;		/* 32-bit CRC from flag_version to end of file */
+	uint32_t flag_version;	/* 0:15 flags, 16:31 version */
+	uint32_t offsets[3];    /* Offsets of partitions from start of header */
+};
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)           (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+int
+trx_fixup(int fd, const char *name)
+{
+	struct mtd_info_user mtdInfo;
+	unsigned long len;
+	struct trx_header *trx;
+	void *ptr, *scan;
+	int bfd;
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
+		fprintf(stderr, "Failed to get mtd info\n");
+		goto err;
+	}
+
+	len = mtdInfo.size;
+	if (mtdInfo.size <= 0) {
+		fprintf(stderr, "Invalid MTD device size\n");
+		goto err;
+	}
+
+	bfd = mtd_open(name, true);
+	ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
+	if (!ptr || (ptr == (void *) -1)) {
+		perror("mmap");
+		fprintf(stderr, "Mapping the TRX header failed\n");
+		goto err1;
+	}
+
+	trx = ptr;
+	if (trx->magic != TRX_MAGIC) {
+		fprintf(stderr, "TRX header not found\n");
+		goto err;
+	}
+
+	scan = ptr + offsetof(struct trx_header, flag_version);
+	trx->crc32 = crc32buf(scan, trx->len - (scan - ptr));
+	msync(ptr, sizeof(struct trx_header), MS_SYNC|MS_INVALIDATE);
+	munmap(ptr, len);
+	close(bfd);
+	return 0;
+
+err1:
+	close(bfd);
+err:
+	return -1;
+}
+
+#ifndef target_ar71xx
+int
+trx_check(int imagefd, const char *mtd, char *buf, int *len)
+{
+	const struct trx_header *trx = (const struct trx_header *) buf;
+	int fd;
+
+	if (strcmp(mtd, "firmware") != 0)
+		return 1;
+
+	if (*len < 32) {
+		*len += read(imagefd, buf + *len, 32 - *len);
+		if (*len < 32) {
+			fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
+			return 0;
+		}
+	}
+
+	if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) {
+		if (quiet < 2) {
+			fprintf(stderr, "Bad trx header\n");
+			fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
+					"Please specify the correct file or use -f to force.\n");
+		}
+		return 0;
+	}
+
+	/* check if image fits to mtd device */
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	if(mtdsize < trx->len) {
+		fprintf(stderr, "Image too big for partition: %s\n", mtd);
+		close(fd);
+		return 0;
+	}
+
+	close(fd);
+	return 1;
+}
+#endif
+
+int
+mtd_fixtrx(const char *mtd, size_t offset, size_t data_size)
+{
+	size_t data_offset;
+	int fd;
+	struct trx_header *trx;
+	char *first_block;
+	char *buf;
+	ssize_t res;
+	size_t block_offset;
+
+	if (quiet < 2)
+		fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	data_offset = offset + TRX_CRC32_DATA_OFFSET;
+	if (data_size)
+		data_size += TRX_CRC32_DATA_SIZE;
+	else
+		data_size = erasesize - TRX_CRC32_DATA_OFFSET;
+
+	block_offset = offset & ~(erasesize - 1);
+	offset -= block_offset;
+
+	if (data_offset + data_size > mtdsize) {
+		fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
+		exit(1);
+	}
+
+	first_block = malloc(erasesize);
+	if (!first_block) {
+		perror("malloc");
+		exit(1);
+	}
+
+	res = pread(fd, first_block, erasesize, block_offset);
+	if (res != erasesize) {
+		perror("pread");
+		exit(1);
+	}
+
+	trx = (struct trx_header *)(first_block + offset);
+	if (trx->magic != STORE32_LE(0x30524448)) {
+		fprintf(stderr, "No trx magic found\n");
+		exit(1);
+	}
+
+	if (trx->len == STORE32_LE(data_size + TRX_CRC32_DATA_OFFSET)) {
+		if (quiet < 2)
+			fprintf(stderr, "Header already fixed, exiting\n");
+		close(fd);
+		return 0;
+	}
+
+	buf = malloc(data_size);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+
+	res = pread(fd, buf, data_size, data_offset);
+	if (res != data_size) {
+		perror("pread");
+		exit(1);
+	}
+
+	trx->len = STORE32_LE(data_size + offsetof(struct trx_header, flag_version));
+
+	trx->crc32 = STORE32_LE(crc32buf(buf, data_size));
+	if (mtd_erase_block(fd, block_offset)) {
+		fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
+
+	if (pwrite(fd, first_block, erasesize, block_offset) != erasesize) {
+		fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "Done.\n");
+
+	close (fd);
+	sync();
+	return 0;
+
+}
+
diff --git a/package/system/mtd/src/wrgg.c b/package/system/mtd/src/wrgg.c
new file mode 100644
index 0000000000..e0b5ca172d
--- /dev/null
+++ b/package/system/mtd/src/wrgg.c
@@ -0,0 +1,190 @@
+/*
+ * wrgg.c
+ *
+ * Copyright (C) 2005 Mike Baker
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+#include "mtd.h"
+#include "wrgg.h"
+#include "md5.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)           (X)
+#else
+#error unknown endianness!
+#endif
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+
+int
+wrgg_fix_md5(struct wrgg03_header *shdr, int fd, size_t data_offset, size_t data_size)
+{
+	char *buf;
+	ssize_t res;
+	MD5_CTX ctx;
+	unsigned char digest[16];
+	int i;
+	int err = 0;
+
+	buf = malloc(data_size);
+	if (!buf) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	res = pread(fd, buf, data_size, data_offset);
+	if (res != data_size) {
+		perror("pread");
+		err = -EIO;
+		goto err_free;
+	}
+
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, (char *)&shdr->offset, sizeof(shdr->offset));
+	MD5_Update(&ctx, (char *)&shdr->dev_name, sizeof(shdr->dev_name));
+	MD5_Update(&ctx, buf, data_size);
+	MD5_Final(digest, &ctx);
+
+	if (!memcmp(digest, shdr->digest, sizeof(digest))) {
+		if (quiet < 2)
+			fprintf(stderr, "the header is fixed already\n");
+		return -1;
+	}
+
+	if (quiet < 2) {
+		fprintf(stderr, "new size:%u, new MD5: ", data_size);
+		for (i = 0; i < sizeof(digest); i++)
+			fprintf(stderr, "%02x", digest[i]);
+
+		fprintf(stderr, "\n");
+	}
+
+	/* update the size in the image */
+	shdr->size = htonl(data_size);
+
+	/* update the checksum in the image */
+	memcpy(shdr->digest, digest, sizeof(digest));
+
+err_free:
+	free(buf);
+err_out:
+	return err;
+}
+
+int
+mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size)
+{
+	int fd;
+	char *first_block;
+	ssize_t res;
+	size_t block_offset;
+	size_t data_offset;
+	struct wrgg03_header *shdr;
+
+	if (quiet < 2)
+		fprintf(stderr, "Trying to fix WRGG header in %s at 0x%x...\n",
+			mtd, offset);
+
+	block_offset = offset & ~(erasesize - 1);
+	offset -= block_offset;
+
+	fd = mtd_check_open(mtd);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
+		exit(1);
+	}
+
+	if (block_offset + erasesize > mtdsize) {
+		fprintf(stderr, "Offset too large, device size 0x%x\n",
+			mtdsize);
+		exit(1);
+	}
+
+	first_block = malloc(erasesize);
+	if (!first_block) {
+		perror("malloc");
+		exit(1);
+	}
+
+	res = pread(fd, first_block, erasesize, block_offset);
+	if (res != erasesize) {
+		perror("pread");
+		exit(1);
+	}
+
+	shdr = (struct wrgg03_header *)(first_block + offset);
+	if (shdr->magic1 != htonl(STORE32_LE(WRGG03_MAGIC))) {
+		fprintf(stderr, "magic1 %x\n", shdr->magic1);
+		fprintf(stderr, "htonl(WRGG03_MAGIC) %x\n", WRGG03_MAGIC);
+		fprintf(stderr, "No WRGG header found\n");
+		exit(1);
+	} else if (!ntohl(shdr->size)) {
+		fprintf(stderr, "WRGG entity with empty image\n");
+		exit(1);
+	}
+
+	data_offset = offset + sizeof(struct wrgg03_header);
+	if (!data_size)
+		data_size = mtdsize - data_offset;
+	if (data_size > ntohl(shdr->size))
+		data_size = ntohl(shdr->size);
+	if (wrgg_fix_md5(shdr, fd, data_offset, data_size))
+		goto out;
+
+	if (mtd_erase_block(fd, block_offset)) {
+		fprintf(stderr, "Can't erease block at 0x%x (%s)\n",
+			block_offset, strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "Rewriting block at 0x%x\n", block_offset);
+
+	if (pwrite(fd, first_block, erasesize, block_offset) != erasesize) {
+		fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
+		exit(1);
+	}
+
+	if (quiet < 2)
+		fprintf(stderr, "Done.\n");
+
+out:
+	close (fd);
+	sync();
+
+	return 0;
+}
diff --git a/package/system/mtd/src/wrgg.h b/package/system/mtd/src/wrgg.h
new file mode 100644
index 0000000000..0c4b3677ec
--- /dev/null
+++ b/package/system/mtd/src/wrgg.h
@@ -0,0 +1,20 @@
+#ifndef __wrgg_h
+#define __wrgg_h
+
+#define WRGG03_MAGIC	0x20080321
+
+struct wrgg03_header {
+	char		signature[32];
+	uint32_t	magic1;
+	uint32_t	magic2;
+	char		version[16];
+	char		model[16];
+	uint32_t	flag[2];
+	uint32_t	reserve[2];
+	char		buildno[16];
+	uint32_t	size;
+	uint32_t	offset;
+	char		dev_name[32];
+	char		digest[16];
+} __attribute__ ((packed));
+#endif /* __wrgg_h */
diff --git a/package/system/opkg/Makefile b/package/system/opkg/Makefile
new file mode 100644
index 0000000000..2a04c4d247
--- /dev/null
+++ b/package/system/opkg/Makefile
@@ -0,0 +1,198 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/version.mk
+include $(INCLUDE_DIR)/feeds.mk
+
+PKG_NAME:=opkg
+PKG_REV:=9c97d5ecd795709c8584e972bfdf3aee3a5b846d
+PKG_VERSION:=$(PKG_REV)
+PKG_RELEASE:=15
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_SUBDIR:=opkg-$(PKG_VERSION)
+PKG_SOURCE_URL:=http://git.yoctoproject.org/git/opkg
+PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.xz
+PKG_MIRROR_MD5SUM:=abba824695a7dd4acf2a6371c4e22142656b3d1f0fa93c04410116d2170ce1a9
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_FIXUP:=autoreconf
+PKG_REMOVE_FILES = autogen.sh aclocal.m4
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+
+PKG_FLAGS := nonshared
+PKG_CONFIG_DEPENDS := CONFIG_SIGNED_PACKAGES
+
+PKG_BUILD_PARALLEL:=1
+HOST_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/opkg/Default
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=opkg package manager
+  DEPENDS:=+uclient-fetch
+  URL:=http://wiki.openmoko.org/wiki/Opkg
+  MENU:=1
+endef
+
+define Package/opkg/Default/description
+  Lightweight package management system
+  opkg is the opkg Package Management System, for handling
+  installation and removal of packages on a system. It can
+  recursively follow dependencies and download all packages
+  necessary to install a particular package.
+
+  opkg knows how to install both .ipk and .deb packages.
+endef
+
+define Package/opkg/config
+config OPKG_SUPPORT_MD5
+  bool
+  default n
+  depends on PACKAGE_opkg
+  prompt "Support reading old md5 hashes."
+  help
+	Old opkg used md5s, new uses sha. This options enables understanding both while prefering sha.
+endef
+
+define Package/opkg
+  $(call Package/opkg/Default)
+  VARIANT:=unsigned
+endef
+
+define Package/opkg/description
+  $(call Package/opkg/Default/description)
+endef
+
+define Package/opkg/conffiles
+/etc/opkg.conf
+/etc/opkg/keys/
+/etc/opkg/customfeeds.conf
+endef
+
+
+define Package/opkg-smime
+  $(call Package/opkg/Default)
+  TITLE+= (with S/MIME signature support)
+  DEPENDS+=+PACKAGE_opkg-smime:libopenssl
+  VARIANT:=smime
+endef
+
+define Package/opkg-smime/description
+  $(call Package/opkg/Default/description)
+
+  This package allows the Package index to be verified with S/MIME.
+endef
+
+define Package/opkg-smime/config
+config OPKG_SMIME_SUPPORT_MD5
+  bool
+  default n
+  depends on PACKAGE_opkg-smime
+  prompt "Support reading old md5 hashes."
+  help
+	Old opkg used md5s, new uses sha. This options enables understanding both while prefering sha.
+endef
+
+Package/opkg-smime/conffiles = $(Package/opkg/conffiles)
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+EXTRA_CFLAGS += $(TARGET_CPPFLAGS)
+
+CONFIGURE_ARGS += \
+	--disable-curl \
+	--disable-gpg \
+	--enable-sha256 \
+	--with-opkgetcdir=/etc \
+	--with-opkglockfile=/var/lock/opkg.lock
+
+ifeq ($(BUILD_VARIANT),smime)
+  CONFIGURE_ARGS += --enable-openssl --disable-usign
+  ifeq ($(CONFIG_OPKG_SMIME_SUPPORT_MD5),y)
+    CONFIGURE_ARGS += --enable-md5
+  else
+    CONFIGURE_ARGS += --disable-md5
+  endif
+else
+  ifndef CONFIG_SIGNED_PACKAGES
+    CONFIGURE_ARGS += --disable-usign
+  endif
+  ifeq ($(CONFIG_OPKG_SUPPORT_MD5),y)
+    CONFIGURE_ARGS += --enable-md5
+  else
+    CONFIGURE_ARGS += --disable-md5
+  endif
+endif
+
+MAKE_FLAGS = \
+		CC="$(TARGET_CC)" \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		HOST_CPU="$(PKGARCH)" \
+		LDFLAGS="-Wl,--gc-sections" \
+
+define Package/opkg/Default/install
+	$(INSTALL_DIR) $(1)/usr/lib/opkg
+	$(INSTALL_DIR) $(1)/bin
+	$(INSTALL_DIR) $(1)/etc/opkg
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DATA) ./files/customfeeds.conf $(1)/etc/opkg/customfeeds.conf
+	$(INSTALL_DATA) ./files/opkg$(2).conf $(1)/etc/opkg.conf
+	$(call FeedSourcesAppend,$(1)/etc/opkg/distfeeds.conf)
+	$(VERSION_SED) $(1)/etc/opkg/distfeeds.conf
+	$(INSTALL_BIN) ./files/20_migrate-feeds $(1)/etc/uci-defaults/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/opkg-cl $(1)/bin/opkg
+endef
+
+define Package/opkg/install
+	$(call Package/opkg/Default/install,$(1),)
+  ifneq ($(CONFIG_SIGNED_PACKAGES),)
+	echo "option check_signature 1" >> $(1)/etc/opkg.conf
+  endif
+	mkdir $(1)/usr/sbin
+	$(INSTALL_BIN) ./files/opkg-key $(1)/usr/sbin/
+endef
+
+define Package/opkg-smime/install
+	$(call Package/opkg/Default/install,$(1),-smime)
+	$(INSTALL_DIR) $(1)/etc/ssl/certs
+	$(if $(CONFIG_OPKGSMIME_CERT),$(INSTALL_DATA) $(call qstrip,$(CONFIG_OPKGSMIME_CERT)) $(1)/etc/ssl/certs/opkg.pem,)
+endef
+
+define Build/InstallDev
+	mkdir -p $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libopkg $(1)/usr/include/
+endef
+
+
+HOST_CONFIGURE_ARGS+= \
+	--disable-curl \
+	--disable-gpg \
+	--enable-sha256 \
+	--with-opkgetcdir=/etc \
+	--with-opkglockfile=/tmp/opkg.lock
+
+define Host/Compile
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) CC="$(HOSTCC)" all
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/src/opkg-cl $(STAGING_DIR_HOST)/bin/opkg
+endef
+
+$(eval $(call BuildPackage,opkg))
+$(eval $(call BuildPackage,opkg-smime))
+$(eval $(call HostBuild))
diff --git a/package/system/opkg/files/20_migrate-feeds b/package/system/opkg/files/20_migrate-feeds
new file mode 100644
index 0000000000..38cc57c467
--- /dev/null
+++ b/package/system/opkg/files/20_migrate-feeds
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+[ -f /etc/opkg.conf ] && grep -q "src\/" /etc/opkg.conf || exit 0
+
+echo -e "# Old feeds from previous image\n# Uncomment to reenable\n" >> /etc/opkg/customfeeds.conf
+sed -n "s/.*\(src\/.*\)/# \1/p" /etc/opkg.conf >> /etc/opkg/customfeeds.conf
+sed -i "/.*src\/.*/d" /etc/opkg.conf
+
+exit 0
diff --git a/package/system/opkg/files/customfeeds.conf b/package/system/opkg/files/customfeeds.conf
new file mode 100644
index 0000000000..f130113c47
--- /dev/null
+++ b/package/system/opkg/files/customfeeds.conf
@@ -0,0 +1,3 @@
+# add your custom package feeds here
+#
+# src/gz example_feed_name http://www.example.com/path/to/files
diff --git a/package/system/opkg/files/opkg-key b/package/system/opkg/files/opkg-key
new file mode 100755
index 0000000000..ae5e8a4591
--- /dev/null
+++ b/package/system/opkg/files/opkg-key
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+usage() {
+	cat <<EOF
+Usage: $0 <command> <arguments...>
+Commands:
+  add <file>:			Add keyfile <file> to opkg trusted keys
+  remove <file>:		Remove keyfile matching <file> from opkg trusted keys
+  verify <sigfile> <list>:	Check list file <list> against signature file <sigfile>
+
+EOF
+	exit 1
+}
+
+opkg_key_verify() {
+	local sigfile="$1"
+	local msgfile="$2"
+
+	(
+		zcat "$msgfile" 2>/dev/null ||
+		cat "$msgfile" 2>/dev/null
+	) | usign -V -P /etc/opkg/keys -q -x "$sigfile" -m -
+}
+
+opkg_key_add() {
+	local key="$1"
+	[ -n "$key" ] || usage
+	[ -f "$key" ] || echo "Cannot open file $1"
+	local fingerprint="$(usign -F -p "$key")"
+	mkdir -p "/etc/opkg/keys"
+	cp "$key" "/etc/opkg/keys/$fingerprint"
+}
+
+opkg_key_remove() {
+	local key="$1"
+	[ -n "$key" ] || usage
+	[ -f "$key" ] || echo "Cannot open file $1"
+	local fingerprint="$(usign -F -p "$key")"
+	rm -f "/etc/opkg/keys/$fingerprint"
+}
+
+case "$1" in
+	add)
+		shift
+		opkg_key_add "$@"
+		;;
+	remove)
+		shift
+		opkg_key_remove "$@"
+		;;
+	verify)
+		shift
+		opkg_key_verify "$@"
+		;;
+	*) usage ;;
+esac
diff --git a/package/system/opkg/files/opkg-smime.conf b/package/system/opkg/files/opkg-smime.conf
new file mode 100644
index 0000000000..fd2cade1f8
--- /dev/null
+++ b/package/system/opkg/files/opkg-smime.conf
@@ -0,0 +1,6 @@
+dest root /
+dest ram /tmp
+lists_dir ext /var/opkg-lists
+option overlay_root /overlay
+option check_signature 1
+option signature_ca_file /etc/ssl/certs/opkg.pem
diff --git a/package/system/opkg/files/opkg.conf b/package/system/opkg/files/opkg.conf
new file mode 100644
index 0000000000..d8d3a2d693
--- /dev/null
+++ b/package/system/opkg/files/opkg.conf
@@ -0,0 +1,4 @@
+dest root /
+dest ram /tmp
+lists_dir ext /var/opkg-lists
+option overlay_root /overlay
diff --git a/package/system/opkg/patches/001-ship-pkg-m4.patch b/package/system/opkg/patches/001-ship-pkg-m4.patch
new file mode 100644
index 0000000000..4ca0f88970
--- /dev/null
+++ b/package/system/opkg/patches/001-ship-pkg-m4.patch
@@ -0,0 +1,168 @@
+--- /dev/null
++++ b/m4/pkg.m4
+@@ -0,0 +1,157 @@
++# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
++# 
++# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++#
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that program.
++
++# PKG_PROG_PKG_CONFIG([MIN-VERSION])
++# ----------------------------------
++AC_DEFUN([PKG_PROG_PKG_CONFIG],
++[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
++m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
++AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
++if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
++	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
++fi
++if test -n "$PKG_CONFIG"; then
++	_pkg_min_version=m4_default([$1], [0.9.0])
++	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
++	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
++		AC_MSG_RESULT([yes])
++	else
++		AC_MSG_RESULT([no])
++		PKG_CONFIG=""
++	fi
++		
++fi[]dnl
++])# PKG_PROG_PKG_CONFIG
++
++# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
++#
++# Check to see whether a particular set of modules exists.  Similar
++# to PKG_CHECK_MODULES(), but does not set variables or print errors.
++#
++#
++# Similar to PKG_CHECK_MODULES, make sure that the first instance of
++# this or PKG_CHECK_MODULES is called, or make sure to call
++# PKG_CHECK_EXISTS manually
++# --------------------------------------------------------------
++AC_DEFUN([PKG_CHECK_EXISTS],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
++if test -n "$PKG_CONFIG" && \
++    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
++  m4_ifval([$2], [$2], [:])
++m4_ifvaln([$3], [else
++  $3])dnl
++fi])
++
++
++# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
++# ---------------------------------------------
++m4_define([_PKG_CONFIG],
++[if test -n "$PKG_CONFIG"; then
++    if test -n "$$1"; then
++        pkg_cv_[]$1="$$1"
++    else
++        PKG_CHECK_EXISTS([$3],
++                         [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
++			 [pkg_failed=yes])
++    fi
++else
++	pkg_failed=untried
++fi[]dnl
++])# _PKG_CONFIG
++
++# _PKG_SHORT_ERRORS_SUPPORTED
++# -----------------------------
++AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
++        _pkg_short_errors_supported=yes
++else
++        _pkg_short_errors_supported=no
++fi[]dnl
++])# _PKG_SHORT_ERRORS_SUPPORTED
++
++
++# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
++# [ACTION-IF-NOT-FOUND])
++#
++#
++# Note that if there is a possibility the first call to
++# PKG_CHECK_MODULES might not happen, you should be sure to include an
++# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
++#
++#
++# --------------------------------------------------------------
++AC_DEFUN([PKG_CHECK_MODULES],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
++AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
++AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
++
++pkg_failed=no
++AC_MSG_CHECKING([for $1])
++
++_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
++_PKG_CONFIG([$1][_LIBS], [libs], [$2])
++
++m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
++and $1[]_LIBS to avoid the need to call pkg-config.
++See the pkg-config man page for more details.])
++
++if test $pkg_failed = yes; then
++        _PKG_SHORT_ERRORS_SUPPORTED
++        if test $_pkg_short_errors_supported = yes; then
++	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
++        else 
++	        $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
++        fi
++	# Put the nasty error message in config.log where it belongs
++	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
++
++	ifelse([$4], , [AC_MSG_ERROR(dnl
++[Package requirements ($2) were not met:
++
++$$1_PKG_ERRORS
++
++Consider adjusting the PKG_CONFIG_PATH environment variable if you
++installed software in a non-standard prefix.
++
++_PKG_TEXT
++])],
++		[AC_MSG_RESULT([no])
++                $4])
++elif test $pkg_failed = untried; then
++	ifelse([$4], , [AC_MSG_FAILURE(dnl
++[The pkg-config script could not be found or is too old.  Make sure it
++is in your PATH or set the PKG_CONFIG environment variable to the full
++path to pkg-config.
++
++_PKG_TEXT
++
++To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
++		[$4])
++else
++	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
++	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
++        AC_MSG_RESULT([yes])
++	ifelse([$3], , :, [$3])
++fi[]dnl
++])# PKG_CHECK_MODULES
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,4 +1,4 @@
+-ACLOCAL_AMFLAGS = -I shave
++ACLOCAL_AMFLAGS = -I shave -I m4
+ 
+ SUBDIRS = libbb libopkg src tests utils man
+ 
diff --git a/package/system/opkg/patches/002-no-shave.patch b/package/system/opkg/patches/002-no-shave.patch
new file mode 100644
index 0000000000..313aa71b00
--- /dev/null
+++ b/package/system/opkg/patches/002-no-shave.patch
@@ -0,0 +1,37 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -4,7 +4,6 @@ AC_CONFIG_SRCDIR([libopkg/pkg.c])
+ 
+ AC_CONFIG_AUX_DIR([conf])
+ AC_CONFIG_MACRO_DIR([m4])
+-AC_CONFIG_MACRO_DIR([shave])
+ 
+ AM_INIT_AUTOMAKE
+ AM_CONFIG_HEADER(libopkg/config.h)
+@@ -277,9 +276,6 @@ AC_SUBST(opkgetcdir)
+ AC_SUBST(opkglockfile)
+ AC_SUBST([CLEAN_DATE])
+ 
+-# Setup output beautifier.
+-SHAVE_INIT([shave], [enable])
+-
+ AC_OUTPUT(
+     Makefile
+     libopkg/Makefile
+@@ -289,8 +285,6 @@ AC_OUTPUT(
+     utils/Makefile
+     utils/update-alternatives
+     libopkg.pc
+-    shave/shave
+-    shave/shave-libtool
+     man/Makefile
+     man/opkg-cl.1
+     man/opkg-key.1
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,4 +1,4 @@
+-ACLOCAL_AMFLAGS = -I shave -I m4
++ACLOCAL_AMFLAGS = -I m4
+ 
+ SUBDIRS = libbb libopkg src tests utils man
+ 
diff --git a/package/system/opkg/patches/004-host_cpu.patch b/package/system/opkg/patches/004-host_cpu.patch
new file mode 100644
index 0000000000..d500d603da
--- /dev/null
+++ b/package/system/opkg/patches/004-host_cpu.patch
@@ -0,0 +1,20 @@
+--- a/libbb/Makefile.am
++++ b/libbb/Makefile.am
+@@ -1,6 +1,6 @@
+ HOST_CPU=@host_cpu@
+ BUILD_CPU=@build_cpu@
+-ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@
++ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"$(HOST_CPU)\" -DBUILD_CPU=@build_cpu@
+ 
+ noinst_LTLIBRARIES = libbb.la
+ 
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -1,5 +1,5 @@
+-
+-AM_CFLAGS=-Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS)
++HOST_CPU=@host_cpu@
++AM_CFLAGS=-Wall -DHOST_CPU_STR=\"$(HOST_CPU)\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS)
+ 
+ libopkg_includedir=$(includedir)/libopkg
+ libopkg_include_HEADERS= *.h
diff --git a/package/system/opkg/patches/007-force_static.patch b/package/system/opkg/patches/007-force_static.patch
new file mode 100644
index 0000000000..74977070c3
--- /dev/null
+++ b/package/system/opkg/patches/007-force_static.patch
@@ -0,0 +1,71 @@
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -38,16 +38,10 @@ if HAVE_SHA256
+ opkg_util_sources += sha256.c sha256.h
+ endif
+ 
+-lib_LTLIBRARIES = libopkg.la
+-libopkg_la_SOURCES = \
++noinst_LIBRARIES = libopkg.a
++libopkg_a_SOURCES = \
+ 	$(opkg_libcore_sources) \
+ 	$(opkg_cmd_sources) $(opkg_db_sources) \
+ 	$(opkg_util_sources) $(opkg_list_sources)
+ 
+-libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
+-
+-# make sure we only export symbols that are for public use
+-#libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*"
+-
+-
+-
++libopkg_a_LIBADD = $(top_builddir)/libbb/libbb.a
+--- a/libbb/Makefile.am
++++ b/libbb/Makefile.am
+@@ -2,9 +2,9 @@ HOST_CPU=@host_cpu@
+ BUILD_CPU=@build_cpu@
+ ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"$(HOST_CPU)\" -DBUILD_CPU=@build_cpu@
+ 
+-noinst_LTLIBRARIES = libbb.la
++noinst_LIBRARIES = libbb.a
+ 
+-libbb_la_SOURCES = gz_open.c \
++libbb_a_SOURCES = gz_open.c \
+ 	libbb.h \
+ 	unzip.c \
+ 	wfopen.c \
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -4,11 +4,11 @@ AM_CFLAGS = $(ALL_CFLAGS) -Wall -g -O3 -
+ #noinst_PROGRAMS = libopkg_test opkg_active_list_test
+ noinst_PROGRAMS = libopkg_test
+ 
+-#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
++#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.a $(top_builddir)/libopkg/libopkg.a
+ #opkg_hash_test_SOURCES = opkg_hash_test.c
+ #opkg_hash_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+ 
+-#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
++#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.a $(top_builddir)/libopkg/libopkg.a
+ #opkg_extract_test_SOURCES = opkg_extract_test.c
+ #opkg_extract_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+ 
+@@ -16,7 +16,7 @@ noinst_PROGRAMS = libopkg_test
+ #opkg_active_list_test_SOURCES = opkg_active_list_test.c
+ #opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+ 
+-libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.la
++libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.a $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
+ libopkg_test_SOURCE = libopkg_test.c
+ libopkg_test_LDFLAGS = -static
+ 
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -2,5 +2,5 @@ AM_CFLAGS = -I${top_srcdir}/libopkg ${AL
+ bin_PROGRAMS = opkg-cl
+ 
+ opkg_cl_SOURCES = opkg-cl.c
+-opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.la \
+-                $(top_builddir)/libbb/libbb.la 
++opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.a \
++                $(top_builddir)/libbb/libbb.a $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS)
diff --git a/package/system/opkg/patches/009-remove-upgrade-all.patch b/package/system/opkg/patches/009-remove-upgrade-all.patch
new file mode 100644
index 0000000000..395a2a6f91
--- /dev/null
+++ b/package/system/opkg/patches/009-remove-upgrade-all.patch
@@ -0,0 +1,41 @@
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -551,18 +551,6 @@ opkg_upgrade_cmd(int argc, char **argv)
+ 			    err = -1;
+                }
+ 	  }
+-     } else {
+-	  pkg_vec_t *installed = pkg_vec_alloc();
+-
+-	  pkg_info_preinstall_check();
+-
+-	  pkg_hash_fetch_all_installed(installed);
+-	  for (i = 0; i < installed->len; i++) {
+-	       pkg = installed->pkgs[i];
+-	       if (opkg_upgrade_pkg(pkg))
+-		       err = -1;
+-	  }
+-	  pkg_vec_free(installed);
+      }
+ 
+      if (opkg_configure_packages(NULL))
+@@ -1258,7 +1246,7 @@ opkg_print_architecture_cmd(int argc, ch
+    array for easier maintenance */
+ static opkg_cmd_t cmds[] = {
+      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+-     {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
++     {"upgrade", 1, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE},
+      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
+      {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -221,7 +221,7 @@ usage()
+ 
+ 	printf("\nPackage Manipulation:\n");
+ 	printf("\tupdate			Update list of available packages\n");
+-	printf("\tupgrade			Upgrade installed packages\n");
++	printf("\tupgrade <pkgs>		Upgrade packages\n");
+ 	printf("\tinstall <pkgs>		Install package(s)\n");
+ 	printf("\tconfigure <pkgs>	Configure unpacked package(s)\n");
+ 	printf("\tremove <pkgs|regexp>	Remove package(s)\n");
diff --git a/package/system/opkg/patches/011-old-config-location.patch b/package/system/opkg/patches/011-old-config-location.patch
new file mode 100644
index 0000000000..0555926864
--- /dev/null
+++ b/package/system/opkg/patches/011-old-config-location.patch
@@ -0,0 +1,12 @@
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -207,6 +207,9 @@ args_parse(int argc, char *argv[])
+ 		}
+ 	}
+ 
++	if(!conf->conf_file && !conf->offline_root)
++		conf->conf_file = xstrdup("/etc/opkg.conf");
++
+ 	if (parse_err)
+ 		return parse_err;
+ 	else
diff --git a/package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch b/package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch
new file mode 100644
index 0000000000..a47ae77cee
--- /dev/null
+++ b/package/system/opkg/patches/012-strip-trailing-conffiles-whitespace.patch
@@ -0,0 +1,23 @@
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -274,6 +274,7 @@ unpack_pkg_control_files(pkg_t *pkg)
+      while (1) {
+ 	  char *cf_name;
+ 	  char *cf_name_in_dest;
++	  int i;
+ 
+ 	  cf_name = file_read_line_alloc(conffiles_file);
+ 	  if (cf_name == NULL) {
+@@ -282,6 +283,12 @@ unpack_pkg_control_files(pkg_t *pkg)
+ 	  if (cf_name[0] == '\0') {
+ 	       continue;
+ 	  }
++	  for (i = strlen(cf_name) - 1;
++	       (i >= 0) && (cf_name[i] == ' ' || cf_name[i] == '\t');
++	       i--
++	  ) {
++	       cf_name[i] = '\0';
++	  }
+ 
+ 	  /* Prepend dest->root_dir to conffile name.
+ 	     Take pains to avoid multiple slashes. */
diff --git a/package/system/opkg/patches/014-errors-to-stderr.patch b/package/system/opkg/patches/014-errors-to-stderr.patch
new file mode 100644
index 0000000000..f0a93a8717
--- /dev/null
+++ b/package/system/opkg/patches/014-errors-to-stderr.patch
@@ -0,0 +1,15 @@
+--- a/libopkg/opkg_message.c
++++ b/libopkg/opkg_message.c
+@@ -64,10 +64,10 @@ print_error_list(void)
+ 	struct errlist *err = error_list_head;
+ 
+ 	if (err) {
+-		printf("Collected errors:\n");
++		fprintf(stderr, "Collected errors:\n");
+ 		/* Here we print the errors collected and free the list */
+ 		while (err != NULL) {
+-			printf(" * %s", err->errmsg);
++			fprintf(stderr, " * %s", err->errmsg);
+ 			err = err->next;
+ 		}
+ 	}
diff --git a/package/system/opkg/patches/020-avoid_getline.patch b/package/system/opkg/patches/020-avoid_getline.patch
new file mode 100644
index 0000000000..8a1a8f6272
--- /dev/null
+++ b/package/system/opkg/patches/020-avoid_getline.patch
@@ -0,0 +1,317 @@
+--- a/libopkg/parse_util.c
++++ b/libopkg/parse_util.c
+@@ -22,6 +22,7 @@
+ #include "libbb/libbb.h"
+ 
+ #include "parse_util.h"
++#include "pkg_parse.h"
+ 
+ int
+ is_field(const char *type, const char *line)
+@@ -86,3 +87,84 @@ parse_list(const char *raw, unsigned int
+ 	*count = line_count;
+ 	return depends;
+ }
++
++int
++parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask,
++						char **buf0, size_t buf0len)
++{
++	int ret, lineno;
++	char *buf, *nl;
++	size_t buflen;
++
++	lineno = 1;
++	ret = 0;
++
++	buflen = buf0len;
++	buf = *buf0;
++	buf[0] = '\0';
++
++	while (1) {
++		if (fgets(buf, (int)buflen, fp) == NULL) {
++			if (ferror(fp)) {
++				opkg_perror(ERROR, "fgets");
++				ret = -1;
++			} else if (strlen(*buf0) == buf0len-1) {
++				opkg_msg(ERROR, "Missing new line character"
++						" at end of file!\n");
++				parse_line(item, *buf0, mask);
++			}
++			break;
++		}
++
++		nl = strchr(buf, '\n');
++		if (nl == NULL) {
++			if (strlen(buf) < buflen-1) {
++				/*
++				 * Line could be exactly buflen-1 long and
++				 * missing a newline, but we won't know until
++				 * fgets fails to read more data.
++				 */
++				opkg_msg(ERROR, "Missing new line character"
++						" at end of file!\n");
++				parse_line(item, *buf0, mask);
++				break;
++			}
++			if (buf0len >= EXCESSIVE_LINE_LEN) {
++				opkg_msg(ERROR, "Excessively long line at "
++					"%d. Corrupt file?\n",
++					lineno);
++				ret = -1;
++				break;
++			}
++
++			/*
++			 * Realloc and point buf past the data already read,
++			 * at the NULL terminator inserted by fgets.
++			 * |<--------------- buf0len ----------------->|
++			 * |                     |<------- buflen ---->|
++			 * |---------------------|---------------------|
++			 * buf0                   buf
++			 */
++			buflen = buf0len +1;
++			buf0len *= 2;
++			*buf0 = xrealloc(*buf0, buf0len);
++			buf = *buf0 + buflen -2;
++
++			continue;
++		}
++
++		*nl = '\0';
++
++		lineno++;
++
++		if (parse_line(item, *buf0, mask))
++			break;
++
++		buf = *buf0;
++		buflen = buf0len;
++		buf[0] = '\0';
++	}
++
++	return ret;
++}
++
+--- a/libopkg/parse_util.h
++++ b/libopkg/parse_util.h
+@@ -22,4 +22,8 @@ int is_field(const char *type, const cha
+ char *parse_simple(const char *type, const char *line);
+ char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field);
+ 
++typedef int (*parse_line_t)(void *, const char *, uint);
++int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask,
++						char **buf0, size_t buf0len);
++
+ #endif
+--- a/libopkg/pkg_hash.c
++++ b/libopkg/pkg_hash.c
+@@ -23,6 +23,7 @@
+ #include "opkg_message.h"
+ #include "pkg_vec.h"
+ #include "pkg_hash.h"
++#include "parse_util.h"
+ #include "pkg_parse.h"
+ #include "opkg_utils.h"
+ #include "sprintf_alloc.h"
+@@ -119,8 +120,14 @@ pkg_hash_add_from_file(const char *file_
+ 		pkg->src = src;
+ 		pkg->dest = dest;
+ 
+-		ret = pkg_parse_from_stream_nomalloc(pkg, fp, 0,
++		ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0,
+ 				&buf, len);
++
++		if (pkg->name == NULL) {
++			/* probably just a blank line */
++			ret = 1;
++		}
++
+ 		if (ret) {
+ 			pkg_deinit (pkg);
+ 			free(pkg);
+--- a/libopkg/pkg_parse.c
++++ b/libopkg/pkg_parse.c
+@@ -104,9 +104,11 @@ get_arch_priority(const char *arch)
+ 	return 0;
+ }
+ 
+-static int
+-pkg_parse_line(pkg_t *pkg, const char *line, uint mask)
++int
++pkg_parse_line(void *ptr, const char *line, uint mask)
+ {
++	pkg_t *pkg = (pkg_t *) ptr;
++
+ 	/* these flags are a bit hackish... */
+ 	static int reading_conffiles = 0, reading_description = 0;
+ 	int ret = 0;
+@@ -266,91 +268,6 @@ dont_reset_flags:
+ }
+ 
+ int
+-pkg_parse_from_stream_nomalloc(pkg_t *pkg, FILE *fp, uint mask,
+-						char **buf0, size_t buf0len)
+-{
+-	int ret, lineno;
+-	char *buf, *nl;
+-	size_t buflen;
+-
+-	lineno = 1;
+-	ret = 0;
+-
+-	buflen = buf0len;
+-	buf = *buf0;
+-	buf[0] = '\0';
+-
+-	while (1) {
+-		if (fgets(buf, (int)buflen, fp) == NULL) {
+-			if (ferror(fp)) {
+-				opkg_perror(ERROR, "fgets");
+-				ret = -1;
+-			} else if (strlen(*buf0) == buf0len-1) {
+-				opkg_msg(ERROR, "Missing new line character"
+-						" at end of file!\n");
+-				pkg_parse_line(pkg, *buf0, mask);
+-			}
+-			break;
+-		}
+-
+-		nl = strchr(buf, '\n');
+-		if (nl == NULL) {
+-			if (strlen(buf) < buflen-1) {
+-				/*
+-				 * Line could be exactly buflen-1 long and
+-				 * missing a newline, but we won't know until
+-				 * fgets fails to read more data.
+-				 */
+-				opkg_msg(ERROR, "Missing new line character"
+-						" at end of file!\n");
+-				pkg_parse_line(pkg, *buf0, mask);
+-				break;
+-			}
+-			if (buf0len >= EXCESSIVE_LINE_LEN) {
+-				opkg_msg(ERROR, "Excessively long line at "
+-					"%d. Corrupt file?\n",
+-					lineno);
+-				ret = -1;
+-				break;
+-			}
+-
+-			/*
+-			 * Realloc and point buf past the data already read,
+-			 * at the NULL terminator inserted by fgets.
+-			 * |<--------------- buf0len ----------------->|
+-			 * |                     |<------- buflen ---->|
+-			 * |---------------------|---------------------|
+-			 * buf0                   buf
+-			 */
+-			buflen = buf0len +1;
+-			buf0len *= 2;
+-			*buf0 = xrealloc(*buf0, buf0len);
+-			buf = *buf0 + buflen -2;
+-
+-			continue;
+-		}
+-
+-		*nl = '\0';
+-
+-		lineno++;
+-
+-		if (pkg_parse_line(pkg, *buf0, mask))
+-			break;
+-
+-		buf = *buf0;
+-		buflen = buf0len;
+-		buf[0] = '\0';
+-	}
+-
+-	if (pkg->name == NULL) {
+-		/* probably just a blank line */
+-		ret = 1;
+-	}
+-
+-	return ret;
+-}
+-
+-int
+ pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask)
+ {
+ 	int ret;
+@@ -358,8 +275,13 @@ pkg_parse_from_stream(pkg_t *pkg, FILE *
+ 	const size_t len = 4096;
+ 
+ 	buf = xmalloc(len);
+-	ret = pkg_parse_from_stream_nomalloc(pkg, fp, mask, &buf, len);
++	ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len);
+ 	free(buf);
+ 
++	if (pkg->name == NULL) {
++		/* probably just a blank line */
++		ret = 1;
++	}
++
+ 	return ret;
+ }
+--- a/libopkg/pkg_parse.h
++++ b/libopkg/pkg_parse.h
+@@ -18,10 +18,11 @@
+ #ifndef PKG_PARSE_H
+ #define PKG_PARSE_H
+ 
++#include "pkg.h"
++
+ int parse_version(pkg_t *pkg, const char *raw);
+ int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask);
+-int pkg_parse_from_stream_nomalloc(pkg_t *pkg, FILE *fp, uint mask,
+-						char **buf0, size_t buf0len);
++int pkg_parse_line(void *ptr, const char *line, uint mask);
+ 
+ #define EXCESSIVE_LINE_LEN	(4096 << 8)
+ 
+--- a/libopkg/release_parse.c
++++ b/libopkg/release_parse.c
+@@ -23,8 +23,10 @@
+ #include "parse_util.h"
+ 
+ static int
+-release_parse_line(release_t *release, const char *line)
++release_parse_line(void *ptr, const char *line, uint mask)
+ {
++	release_t *release = (release_t *) ptr;
++
+ 	int ret = 0;
+ 	unsigned int count = 0;
+ 	char **list = 0;
+@@ -111,25 +113,14 @@ dont_reset_flags:
+ int
+ release_parse_from_stream(release_t *release, FILE *fp)
+ {
+-	int ret = 0;
+-	char *buf = NULL;
+-	size_t buflen, nread;
+-
+-	nread = getline(&buf, &buflen, fp);
+-	while ( nread != -1 ) {
+-		if (buf[nread-1] == '\n') buf[nread-1] = '\0';
+-		if (release_parse_line(release, buf))
+-                        opkg_msg(DEBUG, "Failed to parse release line for %s:\n\t%s\n",
+-					release->name, buf);
+-		nread = getline(&buf, &buflen, fp);
+-	}
+-
+-	if (!feof(fp)) {
+-		opkg_perror(ERROR, "Problems reading Release file for %sd\n", release->name);
+-		ret = -1;
+-	}
++	int ret;
++	char *buf;
++	const size_t len = 4096;
+ 
++	buf = xmalloc(len);
++	ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len);
+ 	free(buf);
++
+ 	return ret;
+ }
+ 
diff --git a/package/system/opkg/patches/030-fix-double-free.patch b/package/system/opkg/patches/030-fix-double-free.patch
new file mode 100644
index 0000000000..312e06c548
--- /dev/null
+++ b/package/system/opkg/patches/030-fix-double-free.patch
@@ -0,0 +1,10 @@
+--- a/libopkg/opkg_remove.c
++++ b/libopkg/opkg_remove.c
+@@ -138,7 +138,6 @@ opkg_remove_dependent_pkgs(pkg_t *pkg, a
+     for (i = 0; i < dependent_pkgs->len; i++) {
+         err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0);
+         if (err) {
+-            pkg_vec_free(dependent_pkgs);
+             break;
+ 	}
+     }
diff --git a/package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch b/package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch
new file mode 100644
index 0000000000..95406687b6
--- /dev/null
+++ b/package/system/opkg/patches/040-wrap-descriptions-only-on-ttys.patch
@@ -0,0 +1,31 @@
+--- a/libopkg/pkg_parse.c
++++ b/libopkg/pkg_parse.c
+@@ -20,6 +20,7 @@
+ 
+ #include <stdio.h>
+ #include <ctype.h>
++#include <unistd.h>
+ 
+ #include "pkg.h"
+ #include "opkg_utils.h"
+@@ -239,10 +240,16 @@ pkg_parse_line(void *ptr, const char *li
+ 
+ 	case ' ':
+ 		if ((mask & PFM_DESCRIPTION) && reading_description) {
+-			pkg->description = xrealloc(pkg->description,
+-						strlen(pkg->description)
+-						+ 1 + strlen(line) + 1);
+-			strcat(pkg->description, "\n");
++			if (isatty(1)) {
++				pkg->description = xrealloc(pkg->description,
++							strlen(pkg->description)
++							+ 1 + strlen(line) + 1);
++				strcat(pkg->description, "\n");
++			} else {
++				pkg->description = xrealloc(pkg->description,
++							strlen(pkg->description)
++							+ 1 + strlen(line));
++			}
+ 			strcat(pkg->description, (line));
+ 			goto dont_reset_flags;
+ 		} else if ((mask & PFM_CONFFILES) && reading_conffiles) {
diff --git a/package/system/opkg/patches/050-add-case-insensitive-flag.patch b/package/system/opkg/patches/050-add-case-insensitive-flag.patch
new file mode 100644
index 0000000000..4b9215b87a
--- /dev/null
+++ b/package/system/opkg/patches/050-add-case-insensitive-flag.patch
@@ -0,0 +1,169 @@
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -436,7 +436,7 @@ opkg_configure_packages(char *pkg_name)
+      for(i = 0; i < ordered->len; i++) {
+ 	  pkg = ordered->pkgs[i];
+ 
+-	  if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ 	       continue;
+ 
+ 	  if (pkg->state_status == SS_UNPACKED) {
+@@ -610,7 +610,7 @@ opkg_list_cmd(int argc, char **argv)
+      for (i=0; i < available->len; i++) {
+ 	  pkg = available->pkgs[i];
+ 	  /* if we have package name or pattern and pkg does not match, then skip it */
+-	  if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ 	       continue;
+           print_pkg(pkg);
+      }
+@@ -637,7 +637,7 @@ opkg_list_installed_cmd(int argc, char *
+      for (i=0; i < available->len; i++) {
+ 	  pkg = available->pkgs[i];
+ 	  /* if we have package name or pattern and pkg does not match, then skip it */
+-	  if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ 	       continue;
+           print_pkg(pkg);
+      }
+@@ -666,7 +666,7 @@ opkg_list_changed_conffiles_cmd(int argc
+      for (i=0; i < available->len; i++) {
+ 	  pkg = available->pkgs[i];
+ 	  /* if we have package name or pattern and pkg does not match, then skip it */
+-	  if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
++	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+ 	    continue;
+ 	  if (nv_pair_list_empty(&pkg->conffiles))
+ 	    continue;
+@@ -722,7 +722,7 @@ opkg_info_status_cmd(int argc, char **ar
+ 
+      for (i=0; i < available->len; i++) {
+ 	  pkg = available->pkgs[i];
+-	  if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
++	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
+ 	       continue;
+ 	  }
+ 
+@@ -792,7 +792,7 @@ opkg_remove_cmd(int argc, char **argv)
+      for (i=0; i<argc; i++) {
+         for (a=0; a<available->len; a++) {
+             pkg = available->pkgs[a];
+-	    if (fnmatch(argv[i], pkg->name, 0)) {
++	    if (fnmatch(argv[i], pkg->name, conf->nocase)) {
+                continue;
+             }
+             if (conf->restrict_to_default_dest) {
+@@ -926,7 +926,7 @@ opkg_depends_cmd(int argc, char **argv)
+ 		for (j=0; j<available_pkgs->len; j++) {
+ 			pkg = available_pkgs->pkgs[j];
+ 
+-			if (fnmatch(argv[i], pkg->name, 0) != 0)
++			if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
+ 				continue;
+ 
+ 			depends_count = pkg->depends_count +
+@@ -1147,9 +1147,9 @@ opkg_what_provides_replaces_cmd(enum wha
+ 			      ((what_field_type == WHATPROVIDES)
+ 			       ? pkg->provides[k]
+ 			       : pkg->replaces[k]);
+-			 if (fnmatch(target, apkg->name, 0) == 0) {
++			 if (fnmatch(target, apkg->name, conf->nocase) == 0) {
+ 			      opkg_msg(NOTICE, "    %s", pkg->name);
+-			      if (strcmp(target, apkg->name) != 0)
++			      if ((conf->nocase ? strcasecmp(target, apkg->name) : strcmp(target, apkg->name)) != 0)
+ 				   opkg_msg(NOTICE, "\t%s %s\n",
+ 						   rel_str, apkg->name);
+ 			      opkg_message(NOTICE, "\n");
+@@ -1200,7 +1200,7 @@ opkg_search_cmd(int argc, char **argv)
+ 
+ 	  for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
+ 	       installed_file = (char *)iter->data;
+-	       if (fnmatch(argv[0], installed_file, 0)==0)
++	       if (fnmatch(argv[0], installed_file, conf->nocase)==0)
+ 	            print_pkg(pkg);
+ 	  }
+ 
+--- a/libopkg/opkg_conf.c
++++ b/libopkg/opkg_conf.c
+@@ -62,6 +62,7 @@ opkg_option_t options[] = {
+ 	  { "noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction },
+ 	  { "download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only },
+ 	  { "nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps },
++	  { "nocase", OPKG_OPT_TYPE_BOOL, &_conf.nocase },
+ 	  { "offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root },
+ 	  { "overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root },
+ 	  { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd },
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -24,6 +24,7 @@ extern opkg_conf_t *conf;
+ #include "config.h"
+ 
+ #include <stdarg.h>
++#include <fnmatch.h> /* FNM_CASEFOLD */
+ 
+ #include "hash_table.h"
+ #include "pkg_src_list.h"
+@@ -79,6 +80,7 @@ struct opkg_conf
+      int force_remove;
+      int check_signature;
+      int nodeps; /* do not follow dependencies */
++     int nocase; /* perform case insensitive matching */
+      char *offline_root;
+      char *overlay_root;
+      int query_all;
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -47,6 +47,7 @@ enum {
+ 	ARGS_OPT_NOACTION,
+ 	ARGS_OPT_DOWNLOAD_ONLY,
+ 	ARGS_OPT_NODEPS,
++	ARGS_OPT_NOCASE,
+ 	ARGS_OPT_AUTOREMOVE,
+ 	ARGS_OPT_CACHE,
+ };
+@@ -86,6 +87,7 @@ static struct option long_options[] = {
+ 	{"noaction", 0, 0, ARGS_OPT_NOACTION},
+ 	{"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ 	{"nodeps", 0, 0, ARGS_OPT_NODEPS},
++	{"nocase", 0, 0, ARGS_OPT_NOCASE},
+ 	{"offline", 1, 0, 'o'},
+ 	{"offline-root", 1, 0, 'o'},
+ 	{"add-arch", 1, 0, ARGS_OPT_ADD_ARCH},
+@@ -107,7 +109,7 @@ args_parse(int argc, char *argv[])
+ 	char *tuple, *targ;
+ 
+ 	while (1) {
+-		c = getopt_long_only(argc, argv, "Ad:f:no:p:t:vV::",
++		c = getopt_long_only(argc, argv, "Ad:f:ino:p:t:vV::",
+ 				long_options, &option_index);
+ 		if (c == -1)
+ 			break;
+@@ -122,6 +124,9 @@ args_parse(int argc, char *argv[])
+ 		case 'f':
+ 			conf->conf_file = xstrdup(optarg);
+ 			break;
++		case 'i':
++			conf->nocase = FNM_CASEFOLD;
++			break;
+ 		case 'o':
+ 			conf->offline_root = xstrdup(optarg);
+ 			break;
+@@ -176,6 +181,9 @@ args_parse(int argc, char *argv[])
+ 		case ARGS_OPT_NODEPS:
+ 			conf->nodeps = 1;
+ 			break;
++		case ARGS_OPT_NOCASE:
++			conf->nocase = FNM_CASEFOLD;
++			break;
+ 		case ARGS_OPT_ADD_ARCH:
+ 		case ARGS_OPT_ADD_DEST:
+ 			tuple = xstrdup(optarg);
+@@ -287,6 +295,7 @@ usage()
+ 	printf("\t--noaction		No action -- test only\n");
+ 	printf("\t--download-only	No action -- download only\n");
+ 	printf("\t--nodeps		Do not follow dependencies\n");
++	printf("\t--nocase		Perform case insensitive pattern matching\n");
+ 	printf("\t--force-removal-of-dependent-packages\n");
+ 	printf("\t			Remove package and all dependencies\n");
+ 	printf("\t--autoremove		Remove packages that were installed\n");
diff --git a/package/system/opkg/patches/060-add-find-command.patch b/package/system/opkg/patches/060-add-find-command.patch
new file mode 100644
index 0000000000..17625349f8
--- /dev/null
+++ b/package/system/opkg/patches/060-add-find-command.patch
@@ -0,0 +1,58 @@
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -594,7 +594,7 @@ opkg_download_cmd(int argc, char **argv)
+ 
+ 
+ static int
+-opkg_list_cmd(int argc, char **argv)
++opkg_list_find_cmd(int argc, char **argv, int use_desc)
+ {
+      int i;
+      pkg_vec_t *available;
+@@ -610,7 +610,8 @@ opkg_list_cmd(int argc, char **argv)
+      for (i=0; i < available->len; i++) {
+ 	  pkg = available->pkgs[i];
+ 	  /* if we have package name or pattern and pkg does not match, then skip it */
+-	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
++	  if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase) &&
++	      (!use_desc || !pkg->description || fnmatch(pkg_name, pkg->description, conf->nocase)))
+ 	       continue;
+           print_pkg(pkg);
+      }
+@@ -619,6 +620,18 @@ opkg_list_cmd(int argc, char **argv)
+      return 0;
+ }
+ 
++static int
++opkg_list_cmd(int argc, char **argv)
++{
++	return opkg_list_find_cmd(argc, argv, 0);
++}
++
++static int
++opkg_find_cmd(int argc, char **argv)
++{
++	return opkg_list_find_cmd(argc, argv, 1);
++}
++
+ 
+ static int
+ opkg_list_installed_cmd(int argc, char **argv)
+@@ -1262,6 +1275,7 @@ static opkg_cmd_t cmds[] = {
+      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE},
++     {"find", 1, (opkg_cmd_fun_t)opkg_find_cmd, PFM_SOURCE},
+      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -246,6 +246,7 @@ usage()
+ 	printf("\tlist-changed-conffiles	List user modified configuration files\n");
+ 	printf("\tfiles <pkg>		List files belonging to <pkg>\n");
+ 	printf("\tsearch <file|regexp>	List package providing <file>\n");
++	printf("\tfind <regexp>		List packages whose name or description matches <regexp>\n");
+ 	printf("\tinfo [pkg|regexp]	Display all info for <pkg>\n");
+ 	printf("\tstatus [pkg|regexp]	Display all status for <pkg>\n");
+ 	printf("\tdownload <pkg>		Download <pkg> to current directory\n");
diff --git a/package/system/opkg/patches/070-use_gzipped_pkg_list.patch b/package/system/opkg/patches/070-use_gzipped_pkg_list.patch
new file mode 100644
index 0000000000..d32b519182
--- /dev/null
+++ b/package/system/opkg/patches/070-use_gzipped_pkg_list.patch
@@ -0,0 +1,120 @@
+--- a/libopkg/opkg.c
++++ b/libopkg/opkg.c
+@@ -592,49 +592,8 @@ opkg_update_package_lists(opkg_progress_
+ 				      src->gzip ? "Packages.gz" : "Packages");
+ 
+ 		sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+-		if (src->gzip) {
+-			FILE *in, *out;
+-			struct _curl_cb_data cb_data;
+-			char *tmp_file_name = NULL;
+ 
+-			sprintf_alloc(&tmp_file_name, "%s/%s.gz", tmp,
+-				      src->name);
+-
+-			opkg_msg(INFO, "Downloading %s to %s...\n", url,
+-					tmp_file_name);
+-
+-			cb_data.cb = progress_callback;
+-			cb_data.progress_data = &pdata;
+-			cb_data.user_data = user_data;
+-			cb_data.start_range =
+-			    100 * sources_done / sources_list_count;
+-			cb_data.finish_range =
+-			    100 * (sources_done + 1) / sources_list_count;
+-
+-			err = opkg_download(url, tmp_file_name,
+-					  (curl_progress_func) curl_progress_cb,
+-					  &cb_data, 0);
+-
+-			if (err == 0) {
+-				opkg_msg(INFO, "Inflating %s...\n",
+-						tmp_file_name);
+-				in = fopen(tmp_file_name, "r");
+-				out = fopen(list_file_name, "w");
+-				if (in && out)
+-					unzip(in, out);
+-				else
+-					err = 1;
+-				if (in)
+-					fclose(in);
+-				if (out)
+-					fclose(out);
+-				unlink(tmp_file_name);
+-			}
+-			free(tmp_file_name);
+-		} else
+-			err = opkg_download(url, list_file_name, NULL, NULL, 0);
+-
+-		if (err) {
++		if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
+ 			opkg_msg(ERROR, "Couldn't retrieve %s\n", url);
+ 			result = -1;
+ 		}
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -162,30 +162,7 @@ opkg_update_cmd(int argc, char **argv)
+ 	      sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
+ 
+ 	  sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+-	  if (src->gzip) {
+-	      char *tmp_file_name;
+-	      FILE *in, *out;
+-
+-	      sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
+-	      err = opkg_download(url, tmp_file_name, NULL, NULL, 0);
+-	      if (err == 0) {
+-		   opkg_msg(NOTICE, "Inflating %s.\n", url);
+-		   in = fopen (tmp_file_name, "r");
+-		   out = fopen (list_file_name, "w");
+-		   if (in && out)
+-			unzip (in, out);
+-		   else
+-			err = 1;
+-		   if (in)
+-			fclose (in);
+-		   if (out)
+-			fclose (out);
+-		   unlink (tmp_file_name);
+-	      }
+-	      free(tmp_file_name);
+-	  } else
+-	      err = opkg_download(url, list_file_name, NULL, NULL, 0);
+-	  if (err) {
++	  if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
+ 	       failures++;
+ 	  } else {
+ 	       opkg_msg(NOTICE, "Updated list of available packages in %s.\n",
+--- a/libopkg/pkg_hash.c
++++ b/libopkg/pkg_hash.c
+@@ -102,12 +102,18 @@ pkg_hash_add_from_file(const char *file_
+ 			pkg_src_t *src, pkg_dest_t *dest, int is_status_file)
+ {
+ 	pkg_t *pkg;
+-	FILE *fp;
++	FILE *fp, *fp_c = NULL;
+ 	char *buf;
+ 	const size_t len = 4096;
+ 	int ret = 0;
++	int pid;
+ 
+ 	fp = fopen(file_name, "r");
++	if (fp && src && src->gzip) {
++		fp_c = fp;
++		fp = gz_open(fp_c, &pid);
++	}
++
+ 	if (fp == NULL) {
+ 		opkg_perror(ERROR, "Failed to open %s", file_name);
+ 		return -1;
+@@ -154,6 +160,10 @@ pkg_hash_add_from_file(const char *file_
+ 
+ 	free(buf);
+ 	fclose(fp);
++	if (fp_c) {
++		fclose(fp_c);
++		gz_close(pid);
++	}
+ 
+ 	return ret;
+ }
diff --git a/package/system/opkg/patches/080-suppress-blank-package-fields.patch b/package/system/opkg/patches/080-suppress-blank-package-fields.patch
new file mode 100644
index 0000000000..976b97d7d2
--- /dev/null
+++ b/package/system/opkg/patches/080-suppress-blank-package-fields.patch
@@ -0,0 +1,16 @@
+--- a/libopkg/parse_util.c
++++ b/libopkg/parse_util.c
+@@ -35,7 +35,12 @@ is_field(const char *type, const char *l
+ char *
+ parse_simple(const char *type, const char *line)
+ {
+-	return trim_xstrdup(line + strlen(type) + 1);
++	char *field = trim_xstrdup(line + strlen(type) + 1);
++	if (strlen(field) == 0) {
++		free(field);
++		return NULL;
++	}
++	return field;
+ }
+ 
+ /*
diff --git a/package/system/opkg/patches/090-suppress-blank-provides-field.patch b/package/system/opkg/patches/090-suppress-blank-provides-field.patch
new file mode 100644
index 0000000000..7adf92235c
--- /dev/null
+++ b/package/system/opkg/patches/090-suppress-blank-provides-field.patch
@@ -0,0 +1,11 @@
+--- a/libopkg/pkg.c
++++ b/libopkg/pkg.c
+@@ -731,7 +731,7 @@ pkg_formatted_field(FILE *fp, pkg_t *pkg
+ 	  } else if (strcasecmp(field, "Priority") == 0) {
+                fprintf(fp, "Priority: %s\n", pkg->priority);
+ 	  } else if (strcasecmp(field, "Provides") == 0) {
+-	       if (pkg->provides_count) {
++	       if (pkg->provides_count > 1) {
+                   fprintf(fp, "Provides:");
+ 		  for(i = 1; i < pkg->provides_count; i++) {
+                       fprintf(fp, "%s %s", i == 1 ? "" : ",",
diff --git a/package/system/opkg/patches/100-add-force-checksum.patch b/package/system/opkg/patches/100-add-force-checksum.patch
new file mode 100644
index 0000000000..5f65a7540c
--- /dev/null
+++ b/package/system/opkg/patches/100-add-force-checksum.patch
@@ -0,0 +1,85 @@
+--- a/libopkg/opkg_conf.c
++++ b/libopkg/opkg_conf.c
+@@ -54,6 +54,7 @@ opkg_option_t options[] = {
+ 	  { "force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall },
+ 	  { "force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space },
+ 	  { "force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall },
++	  { "force_checksum", OPKG_OPT_TYPE_BOOL, &_conf.force_checksum },
+           { "check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature },
+ 	  { "ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy },
+ 	  { "http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy },
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -78,6 +78,7 @@ struct opkg_conf
+      int force_removal_of_essential_packages;
+      int force_postinstall;
+      int force_remove;
++     int force_checksum;
+      int check_signature;
+      int nodeps; /* do not follow dependencies */
+      int nocase; /* perform case insensitive matching */
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1327,12 +1327,19 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+          file_md5 = file_md5sum_alloc(pkg->local_filename);
+          if (file_md5 && strcmp(file_md5, pkg->md5sum))
+          {
+-              opkg_msg(ERROR, "Package %s md5sum mismatch. "
+-			"Either the opkg or the package index are corrupt. "
+-			"Try 'opkg update'.\n",
+-			pkg->name);
+-              free(file_md5);
+-              return -1;
++              if (!conf->force_checksum)
++              {
++                  opkg_msg(ERROR, "Package %s md5sum mismatch. "
++			    "Either the opkg or the package index are corrupt. "
++			    "Try 'opkg update'.\n",
++			    pkg->name);
++                  free(file_md5);
++                  return -1;
++              }
++              else
++              {
++                  opkg_msg(NOTICE, "Ignored %s md5sum mismatch.\n", pkg->name);
++              }
+          }
+ 	 if (file_md5)
+               free(file_md5);
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -42,6 +42,7 @@ enum {
+ 	ARGS_OPT_FORCE_SPACE,
+ 	ARGS_OPT_FORCE_POSTINSTALL,
+ 	ARGS_OPT_FORCE_REMOVE,
++	ARGS_OPT_FORCE_CHECKSUM,
+ 	ARGS_OPT_ADD_ARCH,
+ 	ARGS_OPT_ADD_DEST,
+ 	ARGS_OPT_NOACTION,
+@@ -84,6 +85,8 @@ static struct option long_options[] = {
+ 	{"force_postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL},
+ 	{"force-remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ 	{"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
++	{"force-checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
++	{"force_checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
+ 	{"noaction", 0, 0, ARGS_OPT_NOACTION},
+ 	{"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ 	{"nodeps", 0, 0, ARGS_OPT_NODEPS},
+@@ -178,6 +181,9 @@ args_parse(int argc, char *argv[])
+ 		case ARGS_OPT_FORCE_REMOVE:
+ 			conf->force_remove = 1;
+ 			break;
++		case ARGS_OPT_FORCE_CHECKSUM:
++			conf->force_checksum = 1;
++			break;
+ 		case ARGS_OPT_NODEPS:
+ 			conf->nodeps = 1;
+ 			break;
+@@ -293,6 +299,7 @@ usage()
+ 	printf("\t--force-space		Disable free space checks\n");
+ 	printf("\t--force-postinstall	Run postinstall scripts even in offline mode\n");
+ 	printf("\t--force-remove	Remove package even if prerm script fails\n");
++	printf("\t--force-checksum	Don't fail on checksum mismatches\n");
+ 	printf("\t--noaction		No action -- test only\n");
+ 	printf("\t--download-only	No action -- download only\n");
+ 	printf("\t--nodeps		Do not follow dependencies\n");
diff --git a/package/system/opkg/patches/110-upgrade.patch b/package/system/opkg/patches/110-upgrade.patch
new file mode 100644
index 0000000000..61f454ae1c
--- /dev/null
+++ b/package/system/opkg/patches/110-upgrade.patch
@@ -0,0 +1,50 @@
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1405,9 +1405,11 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ 	  opkg_state_changed++;
+ 	  pkg->state_flag |= SF_FILELIST_CHANGED;
+ 
+-	  if (old_pkg)
++	  if (old_pkg) {
+                pkg_remove_orphan_dependent(pkg, old_pkg);
+-
++	       old_pkg->is_upgrade = 1;
++	       pkg->is_upgrade = 1;
++	  }
+ 	  /* XXX: BUG: we really should treat replacement more like an upgrade
+ 	   *      Instead, we're going to remove the replacees
+ 	   */
+@@ -1466,7 +1468,7 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ 	  }
+ 
+ 
+-	  opkg_msg(INFO, "Installing maintainer scripts.\n");
++	  opkg_msg(INFO, "%s maintainer scripts.\n", (pkg->is_upgrade) ? ("Upgrading") : ("Installing"));
+ 	  if (install_maintainer_scripts(pkg, old_pkg)) {
+ 		opkg_msg(ERROR, "Failed to extract maintainer scripts for %s."
+ 			       " Package debris may remain!\n",
+--- a/libopkg/pkg.c
++++ b/libopkg/pkg.c
+@@ -1285,6 +1285,12 @@ pkg_run_script(pkg_t *pkg, const char *s
+      setenv("PKG_ROOT",
+ 	    pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
+ 
++	if (pkg->is_upgrade)
++		setenv("PKG_UPGRADE", "1", 1);
++	else
++		setenv("PKG_UPGRADE", "0", 1);
++
++
+      if (! file_exists(path)) {
+ 	  free(path);
+ 	  return 0;
+--- a/libopkg/pkg.h
++++ b/libopkg/pkg.h
+@@ -184,6 +184,7 @@ struct pkg
+      /* this flag specifies whether the package was installed to satisfy another
+       * package's dependancies */
+      int auto_installed;
++     int is_upgrade;
+ };
+ 
+ pkg_t *pkg_new(void);
diff --git a/package/system/opkg/patches/200-usign_support.patch b/package/system/opkg/patches/200-usign_support.patch
new file mode 100644
index 0000000000..6479d57330
--- /dev/null
+++ b/package/system/opkg/patches/200-usign_support.patch
@@ -0,0 +1,91 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -169,6 +169,15 @@ if test "x$want_gpgme" = "xyes"; then
+   fi
+ fi
+ 
++AC_ARG_ENABLE(usign,
++    AC_HELP_STRING([--enable-usign], [Enable signature checking with usign
++      [[default=yes]] ]),
++    [want_usign="$enableval"], [want_usign="yes"])
++
++if test "x$want_usign" = "xyes"; then
++  AC_DEFINE(HAVE_USIGN, 1, [Define if you want usign support])
++fi
++
+ AC_SUBST(GPGME_CFLAGS)
+ AC_SUBST(GPGME_LIBS)
+ 
+--- a/libopkg/opkg.c
++++ b/libopkg/opkg.c
+@@ -599,7 +599,7 @@ opkg_update_package_lists(opkg_progress_
+ 		}
+ 		free(url);
+ 
+-#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
++#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+ 		if (conf->check_signature) {
+ 			char *sig_file_name;
+ 			/* download detached signitures to verify the package lists */
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -169,7 +169,7 @@ opkg_update_cmd(int argc, char **argv)
+ 			    list_file_name);
+ 	  }
+ 	  free(url);
+-#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
++#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+           if (conf->check_signature) {
+               /* download detached signitures to verify the package lists */
+               /* get the url for the sig file */
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1288,7 +1288,7 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+      }
+ 
+      /* check that the repository is valid */
+-     #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
++     #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+      char *list_file_name, *sig_file_name, *lists_dir;
+ 
+      /* check to ensure the package has come from a repository */
+--- a/libopkg/opkg_download.c
++++ b/libopkg/opkg_download.c
+@@ -19,6 +19,7 @@
+ 
+ #include "config.h"
+ 
++#include <sys/wait.h>
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <libgen.h>
+@@ -342,7 +343,28 @@ opkg_prepare_url_for_install(const char
+ int
+ opkg_verify_file (char *text_file, char *sig_file)
+ {
+-#if defined HAVE_GPGME
++#if defined HAVE_USIGN
++	int status = -1;
++	int pid;
++
++    if (conf->check_signature == 0 )
++        return 0;
++
++	pid = fork();
++	if (pid < 0)
++		return -1;
++
++	if (!pid) {
++		execl("/usr/sbin/opkg-key", "opkg-key", "verify", sig_file, text_file, NULL);
++		exit(255);
++	}
++
++	waitpid(pid, &status, 0);
++	if (!WIFEXITED(status) || WEXITSTATUS(status))
++		return -1;
++
++	return 0;
++#elif defined HAVE_GPGME
+     if (conf->check_signature == 0 )
+         return 0;
+     int status = -1;
diff --git a/package/system/opkg/patches/210-add-force-signature.patch b/package/system/opkg/patches/210-add-force-signature.patch
new file mode 100644
index 0000000000..c41eab02d3
--- /dev/null
+++ b/package/system/opkg/patches/210-add-force-signature.patch
@@ -0,0 +1,70 @@
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -80,6 +80,7 @@ struct opkg_conf
+      int force_remove;
+      int force_checksum;
+      int check_signature;
++     int force_signature;
+      int nodeps; /* do not follow dependencies */
+      int nocase; /* perform case insensitive matching */
+      char *offline_root;
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -51,6 +51,7 @@ enum {
+ 	ARGS_OPT_NOCASE,
+ 	ARGS_OPT_AUTOREMOVE,
+ 	ARGS_OPT_CACHE,
++	ARGS_OPT_FORCE_SIGNATURE,
+ };
+ 
+ static struct option long_options[] = {
+@@ -87,6 +88,8 @@ static struct option long_options[] = {
+ 	{"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ 	{"force-checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
+ 	{"force_checksum", 0, 0, ARGS_OPT_FORCE_CHECKSUM},
++	{"force-signature", 0, 0, ARGS_OPT_FORCE_SIGNATURE},
++	{"force_signature", 0, 0, ARGS_OPT_FORCE_SIGNATURE},
+ 	{"noaction", 0, 0, ARGS_OPT_NOACTION},
+ 	{"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ 	{"nodeps", 0, 0, ARGS_OPT_NODEPS},
+@@ -210,6 +213,9 @@ args_parse(int argc, char *argv[])
+         case ARGS_OPT_DOWNLOAD_ONLY:
+ 			conf->download_only = 1;
+ 			break;
++		case ARGS_OPT_FORCE_SIGNATURE:
++			conf->force_signature = 1;
++			break;
+ 		case ':':
+ 			parse_err = -1;
+ 			break;
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1306,13 +1306,15 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+          if (opkg_verify_file (list_file_name, sig_file_name)){
+            opkg_msg(ERROR, "Failed to verify the signature of %s.\n",
+                            list_file_name);
+-           return -1;
++           if (!conf->force_signature)
++             return -1;
+          }
+        }else{
+          opkg_msg(ERROR, "Signature file is missing for %s. "
+                          "Perhaps you need to run 'opkg update'?\n",
+ 			 pkg->name);
+-         return -1;
++         if (!conf->force_signature)
++           return -1;
+        }
+ 
+        free (lists_dir);
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -196,7 +196,7 @@ opkg_update_cmd(int argc, char **argv)
+                   else
+                       opkg_msg(NOTICE, "Signature check failed.\n");
+               }
+-              if (err) {
++              if (err && !conf->force_signature) {
+                   /* The signature was wrong so delete it */
+                   opkg_msg(NOTICE, "Remove wrong Signature file.\n");
+                   unlink (tmp_file_name);
diff --git a/package/system/opkg/patches/220-drop-release-support.patch b/package/system/opkg/patches/220-drop-release-support.patch
new file mode 100644
index 0000000000..131c2cba6b
--- /dev/null
+++ b/package/system/opkg/patches/220-drop-release-support.patch
@@ -0,0 +1,812 @@
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -15,7 +15,6 @@ opkg_cmd_sources = opkg_cmd.c opkg_cmd.h
+ 		   opkg_upgrade.c opkg_upgrade.h \
+ 		   opkg_remove.c opkg_remove.h
+ opkg_db_sources = opkg_conf.c opkg_conf.h \
+-		  release.c release.h release_parse.c release_parse.h \
+ 		  opkg_utils.c opkg_utils.h pkg.c pkg.h hash_table.h \
+ 		  pkg_depends.c pkg_depends.h pkg_extract.c pkg_extract.h \
+ 		  hash_table.c pkg_hash.c pkg_hash.h pkg_parse.c pkg_parse.h \
+@@ -28,7 +27,6 @@ opkg_list_sources = conffile.c conffile.
+ 		    active_list.c active_list.h list.h 
+ opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \
+ 		    parse_util.c parse_util.h \
+-		    cksum_list.c cksum_list.h \
+ 		    sprintf_alloc.c sprintf_alloc.h \
+ 		    xregex.c xregex.h xsystem.c xsystem.h
+ if HAVE_PATHFINDER
+--- a/libopkg/cksum_list.c
++++ /dev/null
+@@ -1,87 +0,0 @@
+-/* cksum_lis.c - the opkg package management system
+-
+-   Copyright (C) 2010,2011 Javier Palacios
+-
+-   This program is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU General Public License as
+-   published by the Free Software Foundation; either version 2, or (at
+-   your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful, but
+-   WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   General Public License for more details.
+-*/
+-
+-#include "config.h"
+-
+-#include <stdio.h>
+-
+-#include "cksum_list.h"
+-#include "libbb/libbb.h"
+-
+-
+-int cksum_init(cksum_t *cksum, char **itemlist)
+-{
+-    cksum->value = xstrdup(*itemlist++);
+-    cksum->size = atoi(*itemlist++);
+-    cksum->name = xstrdup(*itemlist++);
+-
+-    return 0;
+-}
+-
+-void cksum_deinit(cksum_t *cksum)
+-{
+-    free (cksum->name);
+-    cksum->name = NULL;
+-
+-    free (cksum->value);
+-    cksum->value = NULL;
+-}
+-
+-void cksum_list_init(cksum_list_t *list)
+-{
+-    void_list_init((void_list_t *) list);
+-}
+-
+-void cksum_list_deinit(cksum_list_t *list)
+-{
+-    cksum_list_elt_t *iter, *n;
+-    cksum_t *cksum;
+-
+-    list_for_each_entry_safe(iter, n, &list->head, node) {
+-      cksum = (cksum_t *)iter->data;
+-      cksum_deinit(cksum);
+-
+-      /* malloced in cksum_list_append */
+-      free(cksum);
+-      iter->data = NULL;
+-    }
+-    void_list_deinit((void_list_t *) list);
+-}
+-
+-cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist)
+-{
+-    /* freed in cksum_list_deinit */
+-    cksum_t *cksum = xcalloc(1, sizeof(cksum_t));
+-    cksum_init(cksum, itemlist);
+-
+-    void_list_append((void_list_t *) list, cksum);
+-
+-    return cksum;
+-}
+-
+-const cksum_t *cksum_list_find(cksum_list_t *list, const char *name)
+-{
+-     cksum_list_elt_t *iter;
+-     cksum_t *cksum;
+-
+-     list_for_each_entry(iter, &list->head, node) {
+-	  cksum = (cksum_t *)iter->data;
+-	  if (strcmp(cksum->name, name) == 0) {
+-	       return cksum;
+-	  }
+-     }    
+-     return NULL;
+-}
+-
+--- a/libopkg/cksum_list.h
++++ /dev/null
+@@ -1,46 +0,0 @@
+-/* cksum_list.h - the opkg package management system
+-
+-   Copyright (C) 2010,2011 Javier Palacios
+-
+-   This program is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU General Public License as
+-   published by the Free Software Foundation; either version 2, or (at
+-   your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful, but
+-   WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   General Public License for more details.
+-*/
+-
+-#ifndef CKSUM_LIST_H
+-#define CKSUM_LIST_H
+-
+-typedef struct 
+-{
+-  char *name;
+-  char *value;
+-  int size;
+-} cksum_t;
+-
+-int cksum_init(cksum_t *cksum, char **itemlist);
+-void cksum_deinit(cksum_t *cksum);
+-
+-#include "void_list.h"
+-
+-typedef struct void_list_elt cksum_list_elt_t;
+-
+-typedef struct void_list cksum_list_t;
+-
+-static inline int cksum_list_empty(cksum_list_t *list)
+-{
+-    return void_list_empty ((void_list_t *)list);
+-}
+-
+-void cksum_list_init(cksum_list_t *list);
+-void cksum_list_deinit(cksum_list_t *list);
+-
+-cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist);
+-const cksum_t *cksum_list_find(cksum_list_t *list, const char *name);
+-
+-#endif
+--- a/libopkg/release.c
++++ /dev/null
+@@ -1,342 +0,0 @@
+-/* release.c - the opkg package management system
+-
+-   Copyright (C) 2010,2011 Javier Palacios
+-
+-   This program is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU General Public License as
+-   published by the Free Software Foundation; either version 2, or (at
+-   your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful, but
+-   WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   General Public License for more details.
+-*/
+-
+-#include <unistd.h>
+-#include <ctype.h>
+-
+-#include "release.h"
+-#include "opkg_utils.h"
+-#include "libbb/libbb.h"
+-
+-#include "opkg_download.h"
+-#include "sprintf_alloc.h"
+-
+-#include "release_parse.h"
+-
+-#include "parse_util.h"
+-#include "file_util.h"
+-
+-static void
+-release_init(release_t *release)
+-{
+-     release->name = NULL;
+-     release->datestring = NULL;
+-     release->architectures = NULL;
+-     release->architectures_count = 0;
+-     release->components = NULL;
+-     release->components_count = 0;
+-     release->complist = NULL;
+-     release->complist_count = 0;
+-}
+-
+-release_t *
+-release_new(void)
+-{
+-     release_t *release;
+-
+-     release = xcalloc(1, sizeof(release_t));
+-     release_init(release);
+-
+-     return release;
+-}
+-
+-void
+-release_deinit(release_t *release)
+-{
+-    int i;
+-
+-    free(release->name);
+-    free(release->datestring);
+-
+-    for(i = 0; i < release->architectures_count; i++){
+-	free(release->architectures[i]);
+-    }
+-    free(release->architectures);
+-
+-    for(i = 0; i < release->components_count; i++){
+-	free(release->components[i]);
+-    }
+-    free(release->components);
+-
+-    for(i = 0; i < release->complist_count; i++){
+-	free(release->complist[i]);
+-    }
+-    free(release->complist);
+-
+-}
+-
+-int
+-release_init_from_file(release_t *release, const char *filename)
+-{
+-	int err = 0;
+-	FILE *release_file;
+-
+-	release_file = fopen(filename, "r");
+-	if (release_file == NULL) {
+-		opkg_perror(ERROR, "Failed to open %s", filename);
+-		return -1;
+-	}
+-
+-	err=release_parse_from_stream(release, release_file);
+-	if (!err) {
+-		if (!release_arch_supported(release)) {
+-			opkg_msg(ERROR, "No valid architecture found on Release file.\n");
+-			err = -1;
+-		}
+-	}
+-
+-	return err;
+-}
+-
+-const char *
+-item_in_list(const char *comp, char **complist, const unsigned int count)
+-{
+-     int i;
+-
+-     if (!complist)
+-	  return comp;
+-
+-     for(i = 0; i < count; i++){
+-	  if (strcmp(comp, complist[i]) == 0)
+-		    return complist[i];
+-     }
+-
+-     return NULL;
+-}
+-
+-int
+-release_arch_supported(release_t *release)
+-{
+-     nv_pair_list_elt_t *l;
+-
+-     list_for_each_entry(l , &conf->arch_list.head, node) {
+-	  nv_pair_t *nv = (nv_pair_t *)l->data;
+-	  if (item_in_list(nv->name, release->architectures, release->architectures_count)) {
+-	       opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n",
+-			       nv->name, nv->value, release->name);
+-	       return 1;
+-	  }
+-     }
+-
+-     return 0;
+-}
+-
+-int
+-release_comps_supported(release_t *release, const char *complist)
+-{
+-     int ret = 1;
+-     int i;
+-
+-     if (complist) {
+-	  release->complist = parse_list(complist, &release->complist_count, ' ', 1);
+-	  for(i = 0; i < release->complist_count; i++){
+-	       if (!item_in_list(release->complist[i], release->components, release->components_count)) {
+-		    opkg_msg(ERROR, "Component %s not supported for dist %s.\n",
+-				    release->complist[i], release->name);
+-		    ret = 0;
+-	       }
+-	  }
+-     }
+-
+-     return ret;
+-}
+-
+-const char **
+-release_comps(release_t *release, unsigned int *count)
+-{
+-     char **comps = release->complist;
+-
+-     if (!comps) {
+-	  comps = release->components;
+-	  *count = release->components_count;
+-     } else {
+-	  *count = release->complist_count;
+-     }
+-
+-     return (const char **)comps;
+-}
+-
+-int
+-release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir)
+-{
+-     int ret = 0;
+-     unsigned int ncomp;
+-     const char **comps = release_comps(release, &ncomp);
+-     nv_pair_list_elt_t *l;
+-     int i;
+-
+-     for(i = 0; i < ncomp; i++){
+-	  int err = 0;
+-	  char *prefix;
+-
+-	  sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name,
+-			comps[i]);
+-
+-	  list_for_each_entry(l , &conf->arch_list.head, node) {
+-	       char *url;
+-	       char *tmp_file_name, *list_file_name;
+-	       char *subpath = NULL;
+-
+-	       nv_pair_t *nv = (nv_pair_t *)l->data;
+-
+-	       sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name);
+-
+-	       sprintf_alloc(&tmp_file_name, "%s/%s-%s-%s%s", tmpdir, dist->name, comps[i], nv->name, ".gz");
+-
+-	       sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages");
+-
+-	       if (dist->gzip) {
+-	       sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name);
+-	       err = opkg_download(url, tmp_file_name, NULL, NULL, 1);
+-	       if (!err) {
+-		    err = release_verify_file(release, tmp_file_name, subpath);
+-		    if (err) {
+-			 unlink (tmp_file_name);
+-			 unlink (list_file_name);
+-		    }
+-	       }
+-	       if (!err) {
+-		    FILE *in, *out;
+-		    opkg_msg(NOTICE, "Inflating %s.\n", url);
+-		    in = fopen (tmp_file_name, "r");
+-		    out = fopen (list_file_name, "w");
+-		    if (in && out) {
+-			 err = unzip (in, out);
+-			 if (err)
+-			      opkg_msg(INFO, "Corrumpt file at %s.\n", url);
+-		    } else
+-			 err = 1;
+-		    if (in)
+-			 fclose (in);
+-		    if (out)
+-			 fclose (out);
+-		    unlink (tmp_file_name);
+-	       }
+-	       free(url);
+-	       }
+-
+-	       if (err) {
+-		    sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name);
+-		    err = opkg_download(url, list_file_name, NULL, NULL, 1);
+-		    if (!err) {
+-			 err = release_verify_file(release, tmp_file_name, subpath);
+-			 if (err)
+-			      unlink (list_file_name);
+-		    }
+-		    free(url);
+-	       }
+-
+-	       free(tmp_file_name);
+-	       free(list_file_name);
+-	  }
+-
+-	  if(err)
+-	       ret = 1;
+-
+-	  free(prefix);
+-     }
+-
+-     return ret;
+-}
+-
+-int
+-release_get_size(release_t *release, const char *pathname)
+-{
+-     const cksum_t *cksum;
+-
+-     if (release->md5sums) {
+-	  cksum = cksum_list_find(release->md5sums, pathname);
+-	  return cksum->size;
+-     }
+-
+-#ifdef HAVE_SHA256
+-     if (release->sha256sums) {
+-	  cksum = cksum_list_find(release->sha256sums, pathname);
+-	  return cksum->size;
+-     }
+-#endif
+-
+-     return -1;
+-}
+-
+-const char *
+-release_get_md5(release_t *release, const char *pathname)
+-{
+-     const cksum_t *cksum;
+-
+-     if (release->md5sums) {
+-	  cksum = cksum_list_find(release->md5sums, pathname);
+-	  return cksum->value;
+-     }
+-
+-     return '\0';
+-}
+-
+-#ifdef HAVE_SHA256
+-const char *
+-release_get_sha256(release_t *release, const char *pathname)
+-{
+-     const cksum_t *cksum;
+-
+-     if (release->sha256sums) {
+-	  cksum = cksum_list_find(release->sha256sums, pathname);
+-	  return cksum->value;
+-     }
+-
+-     return '\0';
+-}
+-#endif
+-
+-int
+-release_verify_file(release_t *release, const char* file_name, const char *pathname)
+-{
+-     struct stat f_info;
+-     char *f_md5 = NULL;
+-     const char *md5 = release_get_md5(release, pathname);
+-#ifdef HAVE_SHA256
+-     char *f_sha256 = NULL;
+-     const char *sha256 = release_get_sha256(release, pathname);
+-#endif
+-     int ret = 0;
+-
+-     if (stat(file_name, &f_info) || (f_info.st_size!=release_get_size(release, pathname))) {
+-	  opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname);
+-	  ret = 1;
+-     } else {
+-
+-     f_md5 = file_md5sum_alloc(file_name);
+-#ifdef HAVE_SHA256
+-     f_sha256 = file_sha256sum_alloc(file_name);
+-#endif
+-
+-     if (md5 && strcmp(md5, f_md5)) {
+-	  opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname);
+-	  ret = 1;
+-#ifdef HAVE_SHA256
+-     } else if (sha256 && strcmp(sha256, f_sha256)) {
+-	  opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname);
+-	  ret = 1;
+-#endif
+-     }
+-
+-     }
+-
+-     free(f_md5);
+-#ifdef HAVE_SHA256
+-     free(f_sha256);
+-#endif
+-
+-     return ret;
+-}
+--- a/libopkg/release.h
++++ /dev/null
+@@ -1,53 +0,0 @@
+-/* release.h - the opkg package management system
+-
+-   Copyright (C) 2010,2011 Javier Palacios
+-
+-   This program is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU General Public License as
+-   published by the Free Software Foundation; either version 2, or (at
+-   your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful, but
+-   WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   General Public License for more details.
+-*/
+-
+-#ifndef RELEASE_H
+-#define RELEASE_H
+-
+-#include <stdio.h>
+-#include "pkg.h"
+-#include "cksum_list.h"
+-
+-struct release
+-{
+-     char *name;
+-     char *datestring;
+-     char **architectures;
+-     unsigned int architectures_count;
+-     char **components;
+-     unsigned int components_count;
+-     cksum_list_t *md5sums;
+-#ifdef HAVE_SHA256
+-     cksum_list_t *sha256sums;
+-#endif
+-     char **complist;
+-     unsigned int complist_count;
+-};
+-
+-typedef struct release release_t;
+-
+-release_t *release_new(void);
+-void release_deinit(release_t *release);
+-int release_init_from_file(release_t *release, const char *filename);
+-
+-int release_arch_supported(release_t *release);
+-int release_comps_supported(release_t *release, const char *complist);
+-int release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir);
+-
+-const char **release_comps(release_t *release, unsigned int *count);
+-
+-int release_verify_file(release_t *release, const char *filename, const char *pathname);
+-
+-#endif
+--- a/libopkg/release_parse.c
++++ /dev/null
+@@ -1,126 +0,0 @@
+-/* release_parse.c - the opkg package management system
+-
+-   Copyright (C) 2010,2011 Javier Palacios
+-
+-   This program is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU General Public License as
+-   published by the Free Software Foundation; either version 2, or (at
+-   your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful, but
+-   WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   General Public License for more details.
+-*/
+-
+-#include "config.h"
+-
+-#include <stdio.h>
+-
+-#include "release.h"
+-#include "release_parse.h"
+-#include "libbb/libbb.h"
+-#include "parse_util.h"
+-
+-static int
+-release_parse_line(void *ptr, const char *line, uint mask)
+-{
+-	release_t *release = (release_t *) ptr;
+-
+-	int ret = 0;
+-	unsigned int count = 0;
+-	char **list = 0;
+-	static int reading_md5sums = 0;
+-#ifdef HAVE_SHA256
+-	static int reading_sha256sums = 0;
+-#endif
+-
+-	switch (*line) {
+-	case 'A':
+-		if (is_field("Architectures", line)) {
+-			release->architectures = parse_list(line, &release->architectures_count, ' ', 0);
+-		}
+-		break;
+-
+-	case 'C':
+-		if (is_field("Codename", line)) {
+-			release->name = parse_simple("Codename", line);
+-	    	}
+-		else if (is_field("Components", line)) {
+-			release->components = parse_list(line, &release->components_count, ' ', 0);
+-	    	}
+-		break;
+-
+-	case 'D':
+-		if (is_field("Date", line)) {
+-			release->datestring = parse_simple("Date", line);
+-		}
+-		break;
+-
+-	case 'M':
+-		if (is_field("MD5sum", line)) {
+-			reading_md5sums = 1;
+-			if (release->md5sums == NULL) {
+-			     release->md5sums = xcalloc(1, sizeof(cksum_list_t));
+-			     cksum_list_init(release->md5sums);
+-			}
+-			goto dont_reset_flags;
+-	    	}
+-		break;
+-
+-#ifdef HAVE_SHA256
+-	case 'S':
+-		if (is_field("SHA256", line)) {
+-			reading_sha256sums = 1;
+-			if (release->sha256sums == NULL) {
+-			     release->sha256sums = xcalloc(1, sizeof(cksum_list_t));
+-			     cksum_list_init(release->sha256sums);
+-			}
+-			goto dont_reset_flags;
+-	    	}
+-		break;
+-#endif
+-
+-	case ' ':
+-		if (reading_md5sums) {
+-			list = parse_list(line, &count, ' ', 1);
+-			cksum_list_append(release->md5sums, list);
+-			goto dont_reset_flags;
+-		}
+-#ifdef HAVE_SHA256
+-		else if (reading_sha256sums) {
+-			list = parse_list(line, &count, ' ', 1);
+-			cksum_list_append(release->sha256sums, list);
+-			goto dont_reset_flags;
+-		}
+-#endif
+-		break;
+-
+-	default:
+-		ret = 1;
+-	}
+-
+-	reading_md5sums = 0;
+-#ifdef HAVE_SHA256
+-	reading_sha256sums = 0;
+-#endif
+-
+-dont_reset_flags:
+-
+-	return ret;
+-}
+-
+-int
+-release_parse_from_stream(release_t *release, FILE *fp)
+-{
+-	int ret;
+-	char *buf;
+-	const size_t len = 4096;
+-
+-	buf = xmalloc(len);
+-	ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len);
+-	free(buf);
+-
+-	return ret;
+-}
+-
+--- a/libopkg/release_parse.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-/* release_parse.h - the opkg package management system
+-
+-   Copyright (C) 2010,2011 Javier Palacios
+-
+-   This program is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU General Public License as
+-   published by the Free Software Foundation; either version 2, or (at
+-   your option) any later version.
+-
+-   This program is distributed in the hope that it will be useful, but
+-   WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   General Public License for more details.
+-*/
+-
+-#ifndef RELEASE_PARSE_H
+-#define RELEASE_PARSE_H
+-
+-int release_parse_from_stream(release_t *release, FILE *fp);
+-
+-#endif
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -27,7 +27,6 @@
+ #include "opkg_conf.h"
+ #include "opkg_cmd.h"
+ #include "opkg_message.h"
+-#include "release.h"
+ #include "pkg.h"
+ #include "pkg_dest.h"
+ #include "pkg_parse.h"
+@@ -114,39 +113,6 @@ opkg_update_cmd(int argc, char **argv)
+      }
+ 
+ 
+-     for (iter = void_list_first(&conf->dist_src_list); iter; iter = void_list_next(&conf->dist_src_list, iter)) {
+-	  char *url, *list_file_name;
+-
+-	  src = (pkg_src_t *)iter->data;
+-
+-	  sprintf_alloc(&url, "%s/dists/%s/Release", src->value, src->name);
+-
+-	  sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+-	  err = opkg_download(url, list_file_name, NULL, NULL, 0);
+-	  if (!err) {
+-	       opkg_msg(NOTICE, "Downloaded release files for dist %s.\n",
+-			    src->name);
+-	       release_t *release = release_new(); 
+-	       err = release_init_from_file(release, list_file_name);
+-	       if (!err) {
+-		    if (!release_comps_supported(release, src->extra_data))
+-			 err = -1;
+-	       }
+-	       if (!err) {
+-		    err = release_download(release, src, lists_dir, tmp);
+-	       }
+-	       release_deinit(release); 
+-	       if (err)
+-		    unlink(list_file_name);
+-	  }
+-
+-	  if (err)
+-	       failures++;
+-
+-	  free(list_file_name);
+-	  free(url);
+-     }
+-
+      for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
+ 	  char *url, *list_file_name;
+ 
+--- a/libopkg/pkg_hash.c
++++ b/libopkg/pkg_hash.c
+@@ -18,7 +18,6 @@
+ #include <stdio.h>
+ 
+ #include "hash_table.h"
+-#include "release.h"
+ #include "pkg.h"
+ #include "opkg_message.h"
+ #include "pkg_vec.h"
+@@ -183,40 +182,6 @@ pkg_hash_load_feeds(void)
+ 	lists_dir = conf->restrict_to_default_dest ?
+ 		conf->default_dest->lists_dir : conf->lists_dir;
+ 
+-	for (iter = void_list_first(&conf->dist_src_list); iter;
+-			iter = void_list_next(&conf->dist_src_list, iter)) {
+-
+-		src = (pkg_src_t *)iter->data;
+-
+-		sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name);
+-
+-		if (file_exists(list_file)) {
+-			int i;
+-			release_t *release = release_new();
+-			if(release_init_from_file(release, list_file)) {
+-				free(list_file);
+-				return -1;
+-			}
+-
+-			unsigned int ncomp;
+-			const char **comps = release_comps(release, &ncomp);
+-			subdist = (pkg_src_t *) xmalloc(sizeof(pkg_src_t));
+-			memcpy(subdist, src, sizeof(pkg_src_t));
+-
+-			for(i = 0; i < ncomp; i++){
+-				subdist->name = NULL;
+-				sprintf_alloc(&subdist->name, "%s-%s", src->name, comps[i]);
+-				if (dist_hash_add_from_file(lists_dir, subdist)) {
+-					free(subdist->name); free(subdist);
+-					free(list_file);
+-					return -1;
+-				}
+-			}
+-			free(subdist->name); free(subdist);
+-		}
+-		free(list_file);
+-	}
+-
+ 	for (iter = void_list_first(&conf->pkg_src_list); iter;
+ 			iter = void_list_next(&conf->pkg_src_list, iter)) {
+ 
diff --git a/package/system/opkg/patches/230-drop_md5_support.patch b/package/system/opkg/patches/230-drop_md5_support.patch
new file mode 100644
index 0000000000..57546bedf1
--- /dev/null
+++ b/package/system/opkg/patches/230-drop_md5_support.patch
@@ -0,0 +1,192 @@
+--- a/libopkg/conffile.c
++++ b/libopkg/conffile.c
+@@ -36,7 +36,7 @@ void conffile_deinit(conffile_t *conffil
+ 
+ int conffile_has_been_modified(conffile_t *conffile)
+ {
+-    char *md5sum;
++    char *chksum;
+     char *filename = conffile->name;
+     char *root_filename;
+     int ret = 1;
+@@ -48,16 +48,23 @@ int conffile_has_been_modified(conffile_
+ 
+     root_filename = root_filename_alloc(filename);
+ 
+-    md5sum = file_md5sum_alloc(root_filename);
+-
+-    if (md5sum && (ret = strcmp(md5sum, conffile->value))) {
+-        opkg_msg(INFO, "Conffile %s:\n\told md5=%s\n\tnew md5=%s\n",
+-		conffile->name, md5sum, conffile->value);
++#ifdef HAVE_MD5
++    if(conffile->value && strlen(conffile->value) > 33) {
++        chksum = file_sha256sum_alloc(root_filename);
++    } else {
++        chksum = file_md5sum_alloc(root_filename);
++    }
++#else
++    chksum = file_sha256sum_alloc(root_filename);
++#endif
++    if (chksum && (ret = strcmp(chksum, conffile->value))) {
++        opkg_msg(INFO, "Conffile %s:\n\told chk=%s\n\tnew chk=%s\n",
++		conffile->name, chksum, conffile->value);
+     }
+ 
+     free(root_filename);
+-    if (md5sum)
+-        free(md5sum);
++    if (chksum)
++        free(chksum);
+ 
+     return ret;
+ }
+--- a/libopkg/file_util.c
++++ b/libopkg/file_util.c
+@@ -26,7 +26,9 @@
+ 
+ #include "sprintf_alloc.h"
+ #include "file_util.h"
++#ifdef HAVE_MD5
+ #include "md5.h"
++#endif
+ #include "libbb/libbb.h"
+ 
+ #if defined HAVE_SHA256
+@@ -135,6 +137,7 @@ file_mkdir_hier(const char *path, long m
+ 	return make_directory(path, mode, FILEUTILS_RECUR);
+ }
+ 
++#ifdef HAVE_MD5
+ char *file_md5sum_alloc(const char *file_name)
+ {
+     static const int md5sum_bin_len = 16;
+@@ -180,6 +183,7 @@ char *file_md5sum_alloc(const char *file
+ 
+     return md5sum_hex;
+ }
++#endif
+ 
+ #ifdef HAVE_SHA256
+ char *file_sha256sum_alloc(const char *file_name)
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1082,7 +1082,7 @@ resolve_conffiles(pkg_t *pkg)
+      conffile_list_elt_t *iter;
+      conffile_t *cf;
+      char *cf_backup;
+-     char *md5sum;
++     char *chksum;
+ 
+      if (conf->noaction) return 0;
+ 
+@@ -1093,7 +1093,7 @@ resolve_conffiles(pkg_t *pkg)
+ 
+ 	  /* Might need to initialize the md5sum for each conffile */
+ 	  if (cf->value == NULL) {
+-	       cf->value = file_md5sum_alloc(root_filename);
++	       cf->value = file_sha256sum_alloc(root_filename);
+ 	  }
+ 
+ 	  if (!file_exists(root_filename)) {
+@@ -1105,8 +1105,16 @@ resolve_conffiles(pkg_t *pkg)
+ 
+           if (file_exists(cf_backup)) {
+               /* Let's compute md5 to test if files are changed */
+-              md5sum = file_md5sum_alloc(cf_backup);
+-              if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) {
++#ifdef HAVE_MD5
++              if(cf->value && strlen(cf->value) > 33) {
++                  chksum = file_sha256sum_alloc(cf_backup);
++              } else {
++                  chksum = file_md5sum_alloc(cf_backup);
++              }
++#else
++              chksum = file_sha256sum_alloc(cf_backup);
++#endif
++              if (chksum && cf->value && strcmp(cf->value,chksum) != 0 ) {
+                   if (conf->force_maintainer) {
+                       opkg_msg(NOTICE, "Conffile %s using maintainer's setting.\n",
+ 				      cf_backup);
+@@ -1123,8 +1131,8 @@ resolve_conffiles(pkg_t *pkg)
+ 		  }
+               }
+               unlink(cf_backup);
+-	      if (md5sum)
+-                  free(md5sum);
++	      if (chksum)
++                  free(chksum);
+           }
+ 
+ 	  free(cf_backup);
+@@ -1323,6 +1331,7 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+      }
+      #endif
+ 
++#ifdef HAVE_MD5
+      /* Check for md5 values */
+      if (pkg->md5sum)
+      {
+@@ -1346,6 +1355,7 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+ 	 if (file_md5)
+               free(file_md5);
+      }
++#endif
+ 
+ #ifdef HAVE_SHA256
+      /* Check for sha256 value */
+--- a/libopkg/Makefile.am
++++ b/libopkg/Makefile.am
+@@ -25,13 +25,16 @@ opkg_list_sources = conffile.c conffile.
+ 		    pkg_src.c pkg_src.h pkg_src_list.c pkg_src_list.h \
+ 		    str_list.c str_list.h void_list.c void_list.h \
+ 		    active_list.c active_list.h list.h 
+-opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \
++opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c \
+ 		    parse_util.c parse_util.h \
+ 		    sprintf_alloc.c sprintf_alloc.h \
+ 		    xregex.c xregex.h xsystem.c xsystem.h
+ if HAVE_PATHFINDER
+ opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h
+ endif
++if HAVE_MD5
++opkg_util_sources += md5.c md5.h
++endif
+ if HAVE_SHA256
+ opkg_util_sources += sha256.c sha256.h
+ endif
+--- a/configure.ac
++++ b/configure.ac
+@@ -68,10 +68,19 @@ AC_ARG_ENABLE(sha256,
+       (sha256.{c,h} are GPLv3 licensed) [[default=no]] ]),
+     [want_sha256="$enableval"], [want_sha256="no"])
+ 
++AC_ARG_ENABLE(md5,
++              AC_HELP_STRING([--enable-md5], [Enable md5sum check
++      (md5.{c,h} are GPLv3 licensed) [[default=no]] ]),
++    [want_md5="$enableval"], [want_md5="yes"])
++
+ if test "x$want_sha256" = "xyes"; then
+   AC_DEFINE(HAVE_SHA256, 1, [Define if you want sha256 support])
+ fi
++if test "x$want_md5" = "xyes"; then
++  AC_DEFINE(HAVE_MD5, 1, [Define if you want md5 support])
++fi
+ AM_CONDITIONAL(HAVE_SHA256, test "x$want_sha256" = "xyes")
++AM_CONDITIONAL(HAVE_MD5, test "x$want_md5" = "xyes")
+ 
+ # check for openssl
+ AC_ARG_ENABLE(openssl,
+--- a/libopkg/pkg_parse.c
++++ b/libopkg/pkg_parse.c
+@@ -49,9 +49,9 @@ parse_status(pkg_t *pkg, const char *sst
+ static void
+ parse_conffiles(pkg_t *pkg, const char *cstr)
+ {
+-	char file_name[1024], md5sum[35];
++	char file_name[1024], md5sum[85];
+ 
+-	if (sscanf(cstr, "%1023s %34s", file_name, md5sum) != 2) {
++	if (sscanf(cstr, "%1023s %84s", file_name, md5sum) != 2) {
+ 		opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n",
+ 				pkg->name);
+ 		return;
diff --git a/package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch b/package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch
new file mode 100644
index 0000000000..8af4d4071d
--- /dev/null
+++ b/package/system/opkg/patches/240-fix-force-checksum-for-sha256.patch
@@ -0,0 +1,31 @@
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -1364,12 +1364,22 @@ opkg_install_pkg(pkg_t *pkg, int from_up
+          file_sha256 = file_sha256sum_alloc(pkg->local_filename);
+          if (file_sha256 && strcmp(file_sha256, pkg->sha256sum))
+          {
+-              opkg_msg(ERROR, "Package %s sha256sum mismatch. "
+-			"Either the opkg or the package index are corrupt. "
+-			"Try 'opkg update'.\n",
+-			pkg->name);
+-              free(file_sha256);
+-              return -1;
++              if (!conf->force_checksum)
++              {
++                  opkg_msg(ERROR,
++                           "Package %s sha256sum mismatch. "
++                           "Either the opkg or the package index are corrupt. "
++                           "Try 'opkg update'.\n",
++                           pkg->name);
++                  free(file_sha256);
++                  return -1;
++              }
++              else
++              {
++                  opkg_msg(NOTICE,
++                           "Ignored %s sha256sum mismatch.\n",
++                           pkg->name);
++              }
+          }
+ 	 if (file_sha256)
+               free(file_sha256);
diff --git a/package/system/opkg/patches/250-add-lists-dir-switch.patch b/package/system/opkg/patches/250-add-lists-dir-switch.patch
new file mode 100644
index 0000000000..d0d0707836
--- /dev/null
+++ b/package/system/opkg/patches/250-add-lists-dir-switch.patch
@@ -0,0 +1,39 @@
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -101,6 +101,8 @@ static struct option long_options[] = {
+ 	{"test", 0, 0, ARGS_OPT_NOACTION},
+ 	{"tmp-dir", 1, 0, 't'},
+ 	{"tmp_dir", 1, 0, 't'},
++	{"lists-dir", 1, 0, 'l'},
++	{"lists_dir", 1, 0, 'l'},
+ 	{"verbosity", 2, 0, 'V'},
+ 	{"version", 0, 0, 'v'},
+ 	{0, 0, 0, 0}
+@@ -115,7 +117,7 @@ args_parse(int argc, char *argv[])
+ 	char *tuple, *targ;
+ 
+ 	while (1) {
+-		c = getopt_long_only(argc, argv, "Ad:f:ino:p:t:vV::",
++		c = getopt_long_only(argc, argv, "Ad:f:ino:p:l:t:vV::",
+ 				long_options, &option_index);
+ 		if (c == -1)
+ 			break;
+@@ -139,6 +141,9 @@ args_parse(int argc, char *argv[])
+ 		case 't':
+ 			conf->tmp_dir = xstrdup(optarg);
+ 			break;
++		case 'l':
++			conf->lists_dir = xstrdup(optarg);
++			break;
+ 		case 'v':
+ 			printf("opkg version %s\n", VERSION);
+ 			exit(0);
+@@ -316,6 +321,8 @@ usage()
+ 	printf("\t			automatically to satisfy dependencies\n");
+ 	printf("\t-t			Specify tmp-dir.\n");
+ 	printf("\t--tmp-dir		Specify tmp-dir.\n");
++	printf("\t-l			Specify lists-dir.\n");
++	printf("\t--lists-dir		Specify lists-dir.\n");
+ 
+ 	printf("\n");
+ 
diff --git a/package/system/opkg/patches/260-add-print-package-size.patch b/package/system/opkg/patches/260-add-print-package-size.patch
new file mode 100644
index 0000000000..4dce356e67
--- /dev/null
+++ b/package/system/opkg/patches/260-add-print-package-size.patch
@@ -0,0 +1,74 @@
+--- a/libopkg/opkg_conf.c
++++ b/libopkg/opkg_conf.c
+@@ -69,6 +69,7 @@ opkg_option_t options[] = {
+ 	  { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd },
+ 	  { "proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user },
+ 	  { "query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all },
++	  { "size", OPKG_OPT_TYPE_BOOL, &_conf.size },
+ 	  { "tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir },
+ 	  { "verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity },
+ #if defined(HAVE_OPENSSL)
+--- a/libopkg/opkg_conf.h
++++ b/libopkg/opkg_conf.h
+@@ -88,6 +88,7 @@ struct opkg_conf
+      int query_all;
+      int verbosity;
+      int noaction;
++     int size;
+      int download_only;
+      char *cache;
+ 
+--- a/src/opkg-cl.c
++++ b/src/opkg-cl.c
+@@ -52,6 +52,7 @@ enum {
+ 	ARGS_OPT_AUTOREMOVE,
+ 	ARGS_OPT_CACHE,
+ 	ARGS_OPT_FORCE_SIGNATURE,
++	ARGS_OPT_SIZE,
+ };
+ 
+ static struct option long_options[] = {
+@@ -98,6 +99,7 @@ static struct option long_options[] = {
+ 	{"offline-root", 1, 0, 'o'},
+ 	{"add-arch", 1, 0, ARGS_OPT_ADD_ARCH},
+ 	{"add-dest", 1, 0, ARGS_OPT_ADD_DEST},
++	{"size", 0, 0, ARGS_OPT_SIZE},
+ 	{"test", 0, 0, ARGS_OPT_NOACTION},
+ 	{"tmp-dir", 1, 0, 't'},
+ 	{"tmp_dir", 1, 0, 't'},
+@@ -212,6 +214,9 @@ args_parse(int argc, char *argv[])
+ 			}
+ 			free(tuple);
+ 			break;
++		case ARGS_OPT_SIZE:
++			conf->size = 1;
++			break;
+ 		case ARGS_OPT_NOACTION:
+ 			conf->noaction = 1;
+ 			break;
+@@ -315,6 +320,7 @@ usage()
+ 	printf("\t--download-only	No action -- download only\n");
+ 	printf("\t--nodeps		Do not follow dependencies\n");
+ 	printf("\t--nocase		Perform case insensitive pattern matching\n");
++	printf("\t--size			Print package size when listing available packages\n");
+ 	printf("\t--force-removal-of-dependent-packages\n");
+ 	printf("\t			Remove package and all dependencies\n");
+ 	printf("\t--autoremove		Remove packages that were installed\n");
+--- a/libopkg/opkg_cmd.c
++++ b/libopkg/opkg_cmd.c
+@@ -47,10 +47,12 @@ static void
+ print_pkg(pkg_t *pkg)
+ {
+ 	char *version = pkg_version_str_alloc(pkg);
++	printf("%s - %s", pkg->name, version);
++	if (conf->size)
++		printf(" - %lu", pkg->size);
+ 	if (pkg->description)
+-		printf("%s - %s - %s\n", pkg->name, version, pkg->description);
+-	else
+-		printf("%s - %s\n", pkg->name, version);
++		printf(" - %s", pkg->description);
++	printf("\n");
+ 	free(version);
+ }
+ 
diff --git a/package/system/opkg/patches/270-fix-use-after-free.patch b/package/system/opkg/patches/270-fix-use-after-free.patch
new file mode 100644
index 0000000000..96e24b9456
--- /dev/null
+++ b/package/system/opkg/patches/270-fix-use-after-free.patch
@@ -0,0 +1,11 @@
+--- a/libopkg/opkg_download.c
++++ b/libopkg/opkg_download.c
+@@ -335,7 +335,7 @@ opkg_prepare_url_for_install(const char
+      hash_insert_pkg(pkg, 1);
+ 
+      if (namep) {
+-	  *namep = pkg->name;
++	  *namep = xstrdup(pkg->name);
+      }
+      return 0;
+ }
diff --git a/package/system/opkg/patches/280-call-prerm-and-postrm-scripts-on-upgrade.patch b/package/system/opkg/patches/280-call-prerm-and-postrm-scripts-on-upgrade.patch
new file mode 100644
index 0000000000..6abbd5df8e
--- /dev/null
+++ b/package/system/opkg/patches/280-call-prerm-and-postrm-scripts-on-upgrade.patch
@@ -0,0 +1,73 @@
+From a8555d352d2851ee1482b74b57ba9eacfb354c18 Mon Sep 17 00:00:00 2001
+From: Peter Urbanec <peteru@urbanec.net>
+Date: Thu, 23 Oct 2014 01:05:35 +1100
+Subject: [PATCH] opkg_install: Call prerm and postrm scripts on package
+ upgrade
+
+When upgrading a package from v1 to v2, run "v1-prerm upgrade v2" and
+"v1-postrm upgrade v2", similarly to what dpkg does.
+
+This patch fixes issue 104.
+
+Signed-off-by: Peter Urbanec <openembedded-devel@urbanec.net>
+Signed-off-by: Paul Barker <paul@paulbarker.me.uk>
+---
+ libopkg/opkg_install.c | 40 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 38 insertions(+), 2 deletions(-)
+
+--- a/libopkg/opkg_install.c
++++ b/libopkg/opkg_install.c
+@@ -528,7 +528,25 @@ prerm_upgrade_old_pkg(pkg_t *pkg, pkg_t
+ 	   Error unwind, for both the above cases:
+ 	   old-postinst abort-upgrade new-version
+      */
+-     return 0;
++    int err;
++    char *script_args;
++    char *new_version;
++
++    if (!old_pkg || !pkg)
++        return 0;
++
++    new_version = pkg_version_str_alloc(pkg);
++
++    sprintf_alloc(&script_args, "upgrade %s", new_version);
++    free(new_version);
++    err = pkg_run_script(old_pkg, "prerm", script_args);
++    free(script_args);
++    if (err != 0) {
++        opkg_msg(ERROR, "prerm script for package \"%s\" failed\n",
++                 old_pkg->name);
++        return -1;
++    }
++    return 0;
+ }
+ 
+ static int
+@@ -925,7 +943,25 @@ postrm_upgrade_old_pkg(pkg_t *pkg, pkg_t
+ 	   new-postrm failed-upgrade old-version
+ 	Error unwind, for both cases:
+ 	   old-preinst abort-upgrade new-version    */
+-     return 0;
++    int err;
++    char *script_args;
++    char *new_version;
++
++    if (!old_pkg || !pkg)
++        return 0;
++
++    new_version = pkg_version_str_alloc(pkg);
++
++    sprintf_alloc(&script_args, "upgrade %s", new_version);
++    free(new_version);
++    err = pkg_run_script(old_pkg, "postrm", script_args);
++    free(script_args);
++    if (err != 0) {
++        opkg_msg(ERROR, "postrm script for package \"%s\" failed\n",
++                 old_pkg->name);
++        return -1;
++    }
++    return 0;
+ }
+ 
+ static int
diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
new file mode 100644
index 0000000000..8f3d57851c
--- /dev/null
+++ b/package/system/procd/Makefile
@@ -0,0 +1,156 @@
+#
+# Copyright (C) 2014-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=procd
+PKG_VERSION:=2016-12-02
+
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=a07669704798cb0262485f69c5547033c64ade58
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=d6a6760133a8ceb78d717a851f426266a35e3957381876d91824e9877fa8c096
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+
+PKG_FLAGS:=nonshared
+
+PKG_CONFIG_DEPENDS:= \
+	CONFIG_TARGET_INIT_PATH CONFIG_KERNEL_SECCOMP \
+	CONFIG_NAND_SUPPORT CONFIG_PROCD_SHOW_BOOT CONFIG_PROCD_ZRAM_TMPFS \
+	CONFIG_KERNEL_NAMESPACES CONFIG_PACKAGE_procd-ujail CONFIG_PACKAGE_procd-seccomp
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+ifeq ($(DUMP),)
+  STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell $(SH_FUNC) echo $(CONFIG_TARGET_INIT_PATH) | md5s)
+endif
+
+CMAKE_OPTIONS += -DEARLY_PATH="$(TARGET_INIT_PATH)"
+TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-lrt)
+
+define Package/procd
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+ubusd +ubus +libjson-script +ubox +USE_GLIBC:librt +libubox +libubus +NAND_SUPPORT:procd-nand
+  TITLE:=OpenWrt system process manager
+endef
+
+define Package/procd-ujail
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=@KERNEL_NAMESPACES +@KERNEL_UTS_NS +@KERNEL_IPC_NS +@KERNEL_PID_NS +libubox +libblobmsg-json
+  TITLE:=OpenWrt process jail helper
+endef
+
+define Package/procd-seccomp
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=@arm||@armeb||@mips||@mipsel||@i386||@x86_64 @!TARGET_uml @KERNEL_SECCOMP +libubox +libblobmsg-json
+  TITLE:=OpenWrt process seccomp helper + utrace
+endef
+
+define Package/procd-nand
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=@NAND_SUPPORT +ubi-utils
+  TITLE:=OpenWrt sysupgrade nand helper
+endef
+
+define Package/procd-nand-firstboot
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=procd-nand
+  TITLE:=OpenWrt firstboot nand helper
+endef
+
+define Package/procd/config
+menu "Configuration"
+	depends on PACKAGE_procd
+
+config PROCD_SHOW_BOOT
+	bool
+	default n
+	prompt "Print the shutdown to the console as well as logging it to syslog"
+
+config PROCD_ZRAM_TMPFS
+	bool
+	default n
+	prompt "Mount /tmp using zram."
+endmenu
+endef
+
+
+ifeq ($(CONFIG_NAND_SUPPORT),y)
+  CMAKE_OPTIONS += -DBUILD_UPGRADED=1
+endif
+
+ifeq ($(CONFIG_PROCD_SHOW_BOOT),y)
+  CMAKE_OPTIONS += -DSHOW_BOOT_ON_CONSOLE=1
+endif
+
+ifeq ($(CONFIG_PROCD_ZRAM_TMPFS),y)
+  CMAKE_OPTIONS += -DZRAM_TMPFS=1
+endif
+
+ifdef CONFIG_PACKAGE_procd-ujail
+  CMAKE_OPTIONS += -DJAIL_SUPPORT=1
+endif
+
+ifdef CONFIG_PACKAGE_procd-seccomp
+  CMAKE_OPTIONS += -DSECCOMP_SUPPORT=1 -DUTRACE_SUPPORT=1
+endif
+
+define Package/procd/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/etc $(1)/lib/functions
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{init,procd,askfirst,udevtrigger} $(1)/sbin/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libsetlbf.so $(1)/lib
+	$(INSTALL_BIN) ./files/reload_config $(1)/sbin/
+	$(INSTALL_DATA) ./files/hotplug*.json $(1)/etc/
+	$(INSTALL_DATA) ./files/procd.sh $(1)/lib/functions/
+endef
+
+define Package/procd-ujail/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ujail $(1)/sbin/
+endef
+
+define Package/procd-seccomp/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/lib
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libpreload-seccomp.so $(1)/lib
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/utrace $(1)/sbin/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libpreload-trace.so $(1)/lib
+endef
+
+define Package/procd-nand/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/lib/upgrade
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/upgraded $(1)/sbin/
+	$(INSTALL_DATA) ./files/nand.sh $(1)/lib/upgrade/
+endef
+
+define Package/procd-nand-firstboot/install
+	$(INSTALL_DIR) $(1)/lib/preinit
+
+	$(INSTALL_DATA) ./files/nand-preinit.sh $(1)/lib/preinit/60-nand-firstboot.sh
+endef
+
+$(eval $(call BuildPackage,procd))
+$(eval $(call BuildPackage,procd-ujail))
+$(eval $(call BuildPackage,procd-seccomp))
+$(eval $(call BuildPackage,procd-nand))
+$(eval $(call BuildPackage,procd-nand-firstboot))
diff --git a/package/system/procd/files/hotplug-preinit.json b/package/system/procd/files/hotplug-preinit.json
new file mode 100644
index 0000000000..58afc6c696
--- /dev/null
+++ b/package/system/procd/files/hotplug-preinit.json
@@ -0,0 +1,18 @@
+[
+	[ "case", "ACTION", {
+		"add": [
+			[ "if",
+				[ "has", "FIRMWARE" ],
+				[
+					[ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
+					[ "load-firmware", "/lib/firmware" ],
+					[ "return" ]
+				]
+			],
+		],
+	}, ],
+	[ "if",
+		[ "eq", "SUBSYSTEM", "button" ],
+		[ "exec", "/etc/rc.button/failsafe" ]
+	],
+]
diff --git a/package/system/procd/files/hotplug.json b/package/system/procd/files/hotplug.json
new file mode 100644
index 0000000000..e5f8d967e8
--- /dev/null
+++ b/package/system/procd/files/hotplug.json
@@ -0,0 +1,69 @@
+[
+	[ "case", "ACTION", {
+		"add": [
+			[ "if",
+				[ "and",
+					[ "has", "MAJOR" ],
+					[ "has", "MINOR" ],
+				],
+				[
+					[ "if",
+						[ "eq", "DEVNAME",
+							[ "null", "full", "ptmx", "zero", "tty", "net", "random", "urandom" ],
+						],
+						[
+							[ "makedev", "/dev/%DEVNAME%", "0666" ],
+							[ "return" ],
+						]
+					],
+					[ "if",
+						[ "regex", "DEVNAME", "^snd" ],
+						[ "makedev", "/dev/%DEVNAME%", "0660", "audio" ],
+					],
+					[ "if",
+						[ "has", "DEVNAME" ],
+						[ "makedev", "/dev/%DEVNAME%", "0600" ],
+					],
+				],
+			],
+			[ "if",
+				[ "has", "FIRMWARE" ],
+				[
+					[ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
+					[ "load-firmware", "/lib/firmware" ],
+					[ "return" ]
+				]
+			],
+		],
+		"remove" : [
+			[ "if",
+				[ "and",
+					[ "has", "DEVNAME" ],
+					[ "has", "MAJOR" ],
+					[ "has", "MINOR" ],
+				],
+				[ "rm", "/dev/%DEVNAME%" ]
+			]
+		]
+	} ],
+	[ "if",
+		[ "and",
+			[ "has", "BUTTON" ],
+			[ "eq", "SUBSYSTEM", "button" ],
+		],
+		[ "button", "/etc/rc.button/%BUTTON%" ]
+	],
+	[ "if",
+		[ "and",
+			[ "eq", "SUBSYSTEM", "usb-serial" ],
+			[ "regex", "DEVNAME",
+				[ "^ttyUSB", "^ttyACM" ]
+			]
+		],
+		[ "exec", "/sbin/hotplug-call", "tty" ],
+		[ "if",
+			[ "isdir", "/etc/hotplug.d/%SUBSYSTEM%" ],
+			[ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]
+		]
+	],
+]
diff --git a/package/system/procd/files/nand-preinit.sh b/package/system/procd/files/nand-preinit.sh
new file mode 100644
index 0000000000..cf596246d1
--- /dev/null
+++ b/package/system/procd/files/nand-preinit.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Copyright (C) 2014 OpenWrt.org
+
+nand_takeover() {
+	. /lib/upgrade/nand.sh
+	mtd=$(find_mtd_index "$CI_UBIPART")
+	esize=$(cat /proc/mtd | grep mtd$mtd |cut -d" " -f 3)
+	[ -z "$esize" ] && return 1
+	esize=$(printf "%d" 0x$esize)
+	for a in `seq 0 64`; do
+		mtd -o $((a * esize)) -l 400 dump /dev/mtd$mtd > /tmp/takeover.hdr
+		MAGIC=$(dd if=/tmp/takeover.hdr bs=1 skip=261 count=5 2> /dev/null)
+		SIZE=$(printf "%d" 0x$(dd if=/tmp/takeover.hdr bs=4 count=1 2> /dev/null | hexdump -v -n 4 -e '1/1 "%02x"'))
+		[ "$MAGIC" = "ustar" ] && {
+			mtd -o $((a * esize)) -l $((SIZE + 4)) dump /dev/mtd$mtd | dd bs=1 skip=4 of=/tmp/sysupgrade.tar
+			nand_do_upgrade_stage2 /tmp/sysupgrade.tar
+		}
+	done
+}
+
+boot_hook_add initramfs nand_takeover
diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
new file mode 100644
index 0000000000..70b9af559d
--- /dev/null
+++ b/package/system/procd/files/nand.sh
@@ -0,0 +1,366 @@
+#!/bin/sh
+# Copyright (C) 2014 OpenWrt.org
+#
+
+. /lib/functions.sh
+
+# 'kernel' partition on NAND contains the kernel
+CI_KERNPART="kernel"
+
+# 'ubi' partition on NAND contains UBI
+CI_UBIPART="ubi"
+
+ubi_mknod() {
+	local dir="$1"
+	local dev="/dev/$(basename $dir)"
+
+	[ -e "$dev" ] && return 0
+
+	local devid="$(cat $dir/dev)"
+	local major="${devid%%:*}"
+	local minor="${devid##*:}"
+	mknod "$dev" c $major $minor
+}
+
+nand_find_volume() {
+	local ubidevdir ubivoldir
+	ubidevdir="/sys/devices/virtual/ubi/$1"
+	[ ! -d "$ubidevdir" ] && return 1
+	for ubivoldir in $ubidevdir/${1}_*; do
+		[ ! -d "$ubivoldir" ] && continue
+		if [ "$( cat $ubivoldir/name )" = "$2" ]; then
+			basename $ubivoldir
+			ubi_mknod "$ubivoldir"
+			return 0
+		fi
+	done
+}
+
+nand_find_ubi() {
+	local ubidevdir ubidev mtdnum
+	mtdnum="$( find_mtd_index $1 )"
+	[ ! "$mtdnum" ] && return 1
+	for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
+		[ ! -d "$ubidevdir" ] && continue
+		cmtdnum="$( cat $ubidevdir/mtd_num )"
+		[ ! "$mtdnum" ] && continue
+		if [ "$mtdnum" = "$cmtdnum" ]; then
+			ubidev=$( basename $ubidevdir )
+			ubi_mknod "$ubidevdir"
+			echo $ubidev
+			return 0
+		fi
+	done
+}
+
+nand_get_magic_long() {
+	dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+get_magic_long_tar() {
+	( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
+}
+
+identify_magic() {
+	local magic=$1
+	case "$magic" in
+		"55424923")
+			echo "ubi"
+			;;
+		"31181006")
+			echo "ubifs"
+			;;
+		"68737173")
+			echo "squashfs"
+			;;
+		"d00dfeed")
+			echo "fit"
+			;;
+		"4349"*)
+			echo "combined"
+			;;
+		*)
+			echo "unknown $magic"
+			;;
+	esac
+}
+
+
+identify() {
+	identify_magic $(nand_get_magic_long "$1" "${2:-0}")
+}
+
+identify_tar() {
+	identify_magic $(get_magic_long_tar "$1" "$2")
+}
+
+nand_restore_config() {
+	sync
+	local ubidev=$( nand_find_ubi $CI_UBIPART )
+	local ubivol="$( nand_find_volume $ubidev rootfs_data )"
+	[ ! "$ubivol" ] &&
+		ubivol="$( nand_find_volume $ubidev rootfs )"
+	mkdir /tmp/new_root
+	if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
+		echo "mounting ubifs $ubivol failed"
+		rmdir /tmp/new_root
+		return 1
+	fi
+	mv "$1" "/tmp/new_root/sysupgrade.tgz"
+	umount /tmp/new_root
+	sync
+	rmdir /tmp/new_root
+}
+
+nand_upgrade_prepare_ubi() {
+	local rootfs_length="$1"
+	local rootfs_type="$2"
+	local has_kernel="${3:-0}"
+	local has_env="${4:-0}"
+
+	local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
+	if [ ! "$mtdnum" ]; then
+		echo "cannot find ubi mtd partition $CI_UBIPART"
+		return 1
+	fi
+
+	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+	if [ ! "$ubidev" ]; then
+		ubiattach -m "$mtdnum"
+		sync
+		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+	fi
+
+	if [ ! "$ubidev" ]; then
+		ubiformat /dev/mtd$mtdnum -y
+		ubiattach -m "$mtdnum"
+		sync
+		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+		[ "$has_env" -gt 0 ] && {
+			ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
+			ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
+		}
+	fi
+
+	local kern_ubivol="$( nand_find_volume $ubidev kernel )"
+	local root_ubivol="$( nand_find_volume $ubidev rootfs )"
+	local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
+
+	# remove ubiblock device of rootfs
+	local root_ubiblk="ubiblock${root_ubivol:3}"
+	if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
+		echo "removing $root_ubiblk"
+		if ! ubiblock -r /dev/$root_ubivol; then
+			echo "cannot remove $root_ubiblk"
+			return 1;
+		fi
+	fi
+
+	# kill volumes
+	[ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true
+	[ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true
+	[ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
+
+	# update kernel
+	if [ "$has_kernel" = "1" ]; then
+		if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then
+			echo "cannot create kernel volume"
+			return 1;
+		fi
+	fi
+
+	# update rootfs
+	local root_size_param
+	if [ "$rootfs_type" = "ubifs" ]; then
+		root_size_param="-m"
+	else
+		root_size_param="-s $rootfs_length"
+	fi
+	if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then
+		echo "cannot create rootfs volume"
+		return 1;
+	fi
+
+	# create rootfs_data for non-ubifs rootfs
+	if [ "$rootfs_type" != "ubifs" ]; then
+		if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
+			echo "cannot initialize rootfs_data volume"
+			return 1
+		fi
+	fi
+	sync
+	return 0
+}
+
+nand_do_upgrade_success() {
+	local conf_tar="/tmp/sysupgrade.tgz"
+	
+	sync
+	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
+	echo "sysupgrade successful"
+	umount -a
+	reboot -f
+}
+
+# Flash the UBI image to MTD partition
+nand_upgrade_ubinized() {
+	local ubi_file="$1"
+	local mtdnum="$(find_mtd_index "$CI_UBIPART")"
+
+	[ ! "$mtdnum" ] && {
+		CI_UBIPART="rootfs"
+		mtdnum="$(find_mtd_index "$CI_UBIPART")"
+	}
+
+	if [ ! "$mtdnum" ]; then
+		echo "cannot find mtd device $CI_UBIPART"
+		umount -a
+		reboot -f
+	fi
+
+	local mtddev="/dev/mtd${mtdnum}"
+	ubidetach -p "${mtddev}" || true
+	sync
+	ubiformat "${mtddev}" -y -f "${ubi_file}"
+	ubiattach -p "${mtddev}"
+	nand_do_upgrade_success
+}
+
+# Write the UBIFS image to UBI volume
+nand_upgrade_ubifs() {
+	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
+
+	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+	
+	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
+
+	nand_do_upgrade_success
+}
+
+nand_upgrade_tar() {
+	local tar_file="$1"
+	local board_name="$(cat /tmp/sysinfo/board_name)"
+	local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
+
+	local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null`
+	local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null`
+
+	local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)"
+
+	local has_kernel=1
+	local has_env=0
+
+	[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
+		tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART
+	}
+	[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
+
+	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
+
+	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+	[ "$has_kernel" = "1" ] && {
+		local kern_ubivol="$(nand_find_volume $ubidev kernel)"
+	 	tar xf $tar_file sysupgrade-$board_name/kernel -O | \
+			ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
+	}
+
+	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+	tar xf $tar_file sysupgrade-$board_name/root -O | \
+		ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
+
+	nand_do_upgrade_success
+}
+
+# Recognize type of passed file and start the upgrade process
+nand_do_upgrade_stage2() {
+	local file_type=$(identify $1)
+
+	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
+		platform_nand_pre_upgrade "$1"
+	fi
+
+	[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
+
+	case "$file_type" in
+		"ubi")		nand_upgrade_ubinized $1;;
+		"ubifs")	nand_upgrade_ubifs $1;;
+		*)		nand_upgrade_tar $1;;
+	esac
+}
+
+nand_upgrade_stage2() {
+	[ $1 = "nand" ] && {
+		[ -f "$2" ] && {
+			touch /tmp/sysupgrade
+
+			killall -9 telnetd
+			killall -9 dropbear
+			killall -9 ash
+
+			kill_remaining TERM
+			sleep 3
+			kill_remaining KILL
+
+			sleep 1
+
+			if [ -n "$(rootfs_type)" ]; then
+				v "Switching to ramdisk..."
+				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
+			else
+				nand_do_upgrade_stage2 $2
+			fi
+			return 0
+		}
+		echo "Nand upgrade failed"
+		exit 1
+	}
+}
+
+nand_upgrade_stage1() {
+	[ -f /tmp/sysupgrade-nand-path ] && {
+		path="$(cat /tmp/sysupgrade-nand-path)"
+		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+			rm $CONF_TAR
+
+		ubus call system nandupgrade "{\"path\": \"$path\" }"
+		exit 0
+	}
+}
+
+# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
+# 3 types of files:
+# 1) UBI - should contain an ubinized image, header is checked for the proper
+#    MAGIC
+# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
+#    header is checked for the proper MAGIC
+# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
+#    "CONTROL" file (at this point its content isn't verified)
+#
+# You usually want to call this function in platform_check_image.
+#
+# $(1): board name, used in case of passing TAR file
+# $(2): file to be checked
+nand_do_platform_check() {
+	local board_name="$1"
+	local tar_file="$2"
+	local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
+	local file_type="$(identify $2)"
+
+	[ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
+		echo "Invalid sysupgrade file."
+		return 1
+	}
+
+	return 0
+}
+
+# Start NAND upgrade process
+#
+# $(1): file to be used for upgrade
+nand_do_upgrade() {
+	echo -n $1 > /tmp/sysupgrade-nand-path
+	cp /sbin/upgraded /tmp/
+	nand_upgrade_stage1
+}
diff --git a/package/system/procd/files/procd.sh b/package/system/procd/files/procd.sh
new file mode 100644
index 0000000000..290c90eb81
--- /dev/null
+++ b/package/system/procd/files/procd.sh
@@ -0,0 +1,460 @@
+# procd API:
+#
+# procd_open_service(name, [script]):
+#   Initialize a new procd command message containing a service with one or more instances
+#
+# procd_close_service()
+#   Send the command message for the service
+#
+# procd_open_instance([name]):
+#   Add an instance to the service described by the previous procd_open_service call
+#
+# procd_set_param(type, [value...])
+#   Available types:
+#     command: command line (array).
+#     respawn info: array with 3 values $fail_threshold $restart_timeout $max_fail
+#     env: environment variable (passed to the process)
+#     data: arbitrary name/value pairs for detecting config changes (table)
+#     file: configuration files (array)
+#     netdev: bound network device (detects ifindex changes)
+#     limits: resource limits (passed to the process)
+#     user info: array with 1 values $username
+#     pidfile: file name to write pid into
+#
+#   No space separation is done for arrays/tables - use one function argument per command line argument
+#
+# procd_close_instance():
+#   Complete the instance being prepared
+#
+# procd_kill(service, [instance]):
+#   Kill a service instance (or all instances)
+#
+
+. $IPKG_INSTROOT/usr/share/libubox/jshn.sh
+
+PROCD_RELOAD_DELAY=1000
+_PROCD_SERVICE=
+
+_procd_call() {
+	local old_cb
+
+	json_set_namespace procd old_cb
+	"$@"
+	json_set_namespace $old_cb
+}
+
+_procd_wrapper() {
+	while [ -n "$1" ]; do
+		eval "$1() { _procd_call _$1 \"\$@\"; }"
+		shift
+	done
+}
+
+_procd_ubus_call() {
+	local cmd="$1"
+
+	[ -n "$PROCD_DEBUG" ] && json_dump >&2
+	ubus call service "$cmd" "$(json_dump)"
+	json_cleanup
+}
+
+_procd_open_service() {
+	local name="$1"
+	local script="$2"
+
+	_PROCD_SERVICE="$name"
+	_PROCD_INSTANCE_SEQ=0
+
+	json_init
+	json_add_string name "$name"
+	[ -n "$script" ] && json_add_string script "$script"
+	json_add_object instances
+}
+
+_procd_close_service() {
+	json_close_object
+	_procd_open_trigger
+	service_triggers
+	_procd_close_trigger
+	_procd_ubus_call ${1:-set}
+}
+
+_procd_add_array_data() {
+	while [ "$#" -gt 0 ]; do
+		json_add_string "" "$1"
+		shift
+	done
+}
+
+_procd_add_array() {
+	json_add_array "$1"
+	shift
+	_procd_add_array_data "$@"
+	json_close_array
+}
+
+_procd_add_table_data() {
+	while [ -n "$1" ]; do
+		local var="${1%%=*}"
+		local val="${1#*=}"
+		[ "$1" = "$val" ] && val=
+		json_add_string "$var" "$val"
+		shift
+	done
+}
+
+_procd_add_table() {
+	json_add_object "$1"
+	shift
+	_procd_add_table_data "$@"
+	json_close_object
+}
+
+_procd_open_instance() {
+	local name="$1"; shift
+
+	_PROCD_INSTANCE_SEQ="$(($_PROCD_INSTANCE_SEQ + 1))"
+	name="${name:-instance$_PROCD_INSTANCE_SEQ}"
+	json_add_object "$name"
+	[ -n "$TRACE_SYSCALLS" ] && json_add_boolean trace "1"
+}
+
+_procd_open_trigger() {
+	let '_procd_trigger_open = _procd_trigger_open + 1'
+	[ "$_procd_trigger_open" -gt 1 ] && return
+	json_add_array "triggers"
+}
+
+_procd_close_trigger() {
+	let '_procd_trigger_open = _procd_trigger_open - 1'
+	[ "$_procd_trigger_open" -lt 1 ] || return
+	json_close_array
+}
+
+_procd_open_validate() {
+	json_select ..
+	json_add_array "validate"
+}
+
+_procd_close_validate() {
+	json_close_array
+	json_select triggers
+}
+
+_procd_add_jail() {
+	json_add_object "jail"
+	json_add_string name "$1"
+
+	shift
+	
+	for a in $@; do
+		case $a in
+		log)	json_add_boolean "log" "1";;
+		ubus)	json_add_boolean "ubus" "1";;
+		procfs)	json_add_boolean "procfs" "1";;
+		sysfs)	json_add_boolean "sysfs" "1";;
+		ronly)	json_add_boolean "ronly" "1";;
+		esac
+	done
+	json_add_object "mount"
+	json_close_object
+	json_close_object
+}
+
+_procd_add_jail_mount() {
+	local _json_no_warning=1
+
+	json_select "jail"
+	[ $? = 0 ] || return
+	json_select "mount"
+	[ $? = 0 ] || {
+		json_select ..
+		return
+	}
+	for a in $@; do
+		json_add_string "$a" "0"
+	done
+	json_select ..
+	json_select ..
+}
+
+_procd_add_jail_mount_rw() {
+	local _json_no_warning=1
+
+	json_select "jail"
+	[ $? = 0 ] || return
+	json_select "mount"
+	[ $? = 0 ] || {
+		json_select ..
+		return
+	}
+	for a in $@; do
+		json_add_string "$a" "1"
+	done
+	json_select ..
+	json_select ..
+}
+
+_procd_set_param() {
+	local type="$1"; shift
+
+	case "$type" in
+		env|data|limits)
+			_procd_add_table "$type" "$@"
+		;;
+		command|netdev|file|respawn|watch)
+			_procd_add_array "$type" "$@"
+		;;
+		error)
+			json_add_array "$type"
+			json_add_string "" "$@"
+			json_close_array
+		;;
+		nice)
+			json_add_int "$type" "$1"
+		;;
+		pidfile|user|seccomp|capabilities)
+			json_add_string "$type" "$1"
+		;;
+		stdout|stderr|no_new_privs)
+			json_add_boolean "$type" "$1"
+		;;
+	esac
+}
+
+_procd_add_timeout() {
+	[ "$PROCD_RELOAD_DELAY" -gt 0 ] && json_add_int "" "$PROCD_RELOAD_DELAY"
+	return 0
+}
+
+_procd_add_interface_trigger() {
+	json_add_array
+	_procd_add_array_data "$1"
+	shift
+
+	json_add_array
+	_procd_add_array_data "if"
+
+	json_add_array
+	_procd_add_array_data "eq" "interface" "$1"
+	shift
+	json_close_array
+
+	json_add_array
+	_procd_add_array_data "run_script" "$@"
+	json_close_array
+
+	json_close_array
+	json_close_array
+
+	_procd_add_timeout
+}
+
+_procd_add_reload_interface_trigger() {
+	local script=$(readlink "$initscript")
+	local name=$(basename ${script:-$initscript})
+
+	_procd_open_trigger
+	_procd_add_interface_trigger "interface.*" $1 /etc/init.d/$name reload
+	_procd_close_trigger
+}
+
+_procd_add_config_trigger() {
+	json_add_array
+	_procd_add_array_data "$1"
+	shift
+
+	json_add_array
+	_procd_add_array_data "if"
+
+	json_add_array
+	_procd_add_array_data "eq" "package" "$1"
+	shift
+	json_close_array
+
+	json_add_array
+	_procd_add_array_data "run_script" "$@"
+	json_close_array
+
+	json_close_array
+
+	json_close_array
+
+	_procd_add_timeout
+}
+
+_procd_add_raw_trigger() {
+	json_add_array
+	_procd_add_array_data "$1"
+	shift
+	local timeout=$1
+	shift
+
+	json_add_array
+	json_add_array
+	_procd_add_array_data "run_script" "$@"
+	json_close_array
+	json_close_array
+
+	json_add_int "" "$timeout"
+
+	json_close_array
+}
+
+_procd_add_reload_trigger() {
+	local script=$(readlink "$initscript")
+	local name=$(basename ${script:-$initscript})
+	local file
+
+	_procd_open_trigger
+	for file in "$@"; do
+		_procd_add_config_trigger "config.change" "$file" /etc/init.d/$name reload
+	done
+	_procd_close_trigger
+}
+
+_procd_add_validation() {
+	_procd_open_validate
+	$@
+	_procd_close_validate
+}
+
+_procd_append_param() {
+	local type="$1"; shift
+	local _json_no_warning=1
+
+	json_select "$type"
+	[ $? = 0 ] || {
+		_procd_set_param "$type" "$@"
+		return
+	}
+	case "$type" in
+		env|data|limits)
+			_procd_add_table_data "$@"
+		;;
+		command|netdev|file|respawn|watch)
+			_procd_add_array_data "$@"
+		;;
+		error)
+			json_add_string "" "$@"
+		;;
+	esac
+	json_select ..
+}
+
+_procd_close_instance() {
+	local respawn_vals
+	_json_no_warning=1
+	if json_select respawn ; then
+		json_get_values respawn_vals
+		if [ -z "$respawn_vals" ]; then
+			local respawn_retry=$(uci_get system.@service[0].respawn_retry)
+			_procd_add_array_data 3600 5 ${respawn_retry:-5}
+		fi
+		json_select ..
+	fi
+
+	json_close_object
+}
+
+_procd_add_instance() {
+	_procd_open_instance
+	_procd_set_param command "$@"
+	_procd_close_instance
+}
+
+_procd_kill() {
+	local service="$1"
+	local instance="$2"
+
+	json_init
+	[ -n "$service" ] && json_add_string name "$service"
+	[ -n "$instance" ] && json_add_string instance "$instance"
+	_procd_ubus_call delete
+}
+
+procd_open_data() {
+	local name="$1"
+	json_set_namespace procd __procd_old_cb
+	json_add_object data
+}
+
+procd_close_data() {
+	json_close_object
+	json_set_namespace $__procd_old_cb
+}
+
+_procd_set_config_changed() {
+	local package="$1"
+
+	json_init
+	json_add_string type config.change
+	json_add_object data
+	json_add_string package "$package"
+	json_close_object
+
+	ubus call service event "$(json_dump)"
+}
+
+procd_add_mdns_service() {
+	local service proto port
+	service=$1; shift
+	proto=$1; shift
+	port=$1; shift
+	json_add_object "${service}_$port"
+	json_add_string "service" "_$service._$proto.local"
+	json_add_int port "$port"
+	[ -n "$1" ] && {
+		json_add_array txt
+		for txt in $@; do json_add_string "" $txt; done
+		json_select ..
+	}
+	json_select ..
+}
+
+procd_add_mdns() {
+	procd_open_data
+	json_add_object "mdns"
+	procd_add_mdns_service $@
+	json_close_object
+	procd_close_data
+}
+
+uci_validate_section()
+{
+	local _package="$1"
+	local _type="$2"
+	local _name="$3"
+	local _result
+	local _error
+	shift; shift; shift
+	_result=`/sbin/validate_data "$_package" "$_type" "$_name" "$@" 2> /dev/null`
+	_error=$?
+	eval "$_result"
+	[ "$_error" = "0" ] || `/sbin/validate_data "$_package" "$_type" "$_name" "$@" 1> /dev/null`
+	return $_error
+}
+
+_procd_wrapper \
+	procd_open_service \
+	procd_close_service \
+	procd_add_instance \
+	procd_add_raw_trigger \
+	procd_add_config_trigger \
+	procd_add_interface_trigger \
+	procd_add_reload_trigger \
+	procd_add_reload_interface_trigger \
+	procd_open_trigger \
+	procd_close_trigger \
+	procd_open_instance \
+	procd_close_instance \
+	procd_open_validate \
+	procd_close_validate \
+	procd_add_jail \
+	procd_add_jail_mount \
+	procd_add_jail_mount_rw \
+	procd_set_param \
+	procd_append_param \
+	procd_add_validation \
+	procd_set_config_changed \
+	procd_kill
diff --git a/package/system/procd/files/reload_config b/package/system/procd/files/reload_config
new file mode 100644
index 0000000000..8d1cdb1378
--- /dev/null
+++ b/package/system/procd/files/reload_config
@@ -0,0 +1,15 @@
+#!/bin/sh
+rm -rf /var/run/config.check
+mkdir -p /var/run/config.check
+for config in /etc/config/*; do
+	file=${config##*/}
+	uci show "${file##*/}" > /var/run/config.check/$file
+done
+MD5FILE=/var/run/config.md5
+[ -f $MD5FILE ] && {
+	for c in `md5sum -c $MD5FILE 2>/dev/null| grep FAILED | cut -d: -f1`; do
+		ubus call service event "{ \"type\": \"config.change\", \"data\": { \"package\": \"$(basename $c)\" }}"
+	done
+}
+md5sum /var/run/config.check/* > $MD5FILE
+rm -rf /var/run/config.check
diff --git a/package/system/rpcd/Makefile b/package/system/rpcd/Makefile
new file mode 100644
index 0000000000..ef3f3c3c2f
--- /dev/null
+++ b/package/system/rpcd/Makefile
@@ -0,0 +1,98 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=rpcd
+PKG_VERSION:=2016-06-30
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/rpcd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)
+PKG_SOURCE_VERSION:=23417e94d25570e6d62542bac46edd51e8e0243a
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_MIRROR_MD5SUM:=a52ce026105ff6d944896686399d97960f34246b4f7e0c464ff6631ed33325c9
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_BUILD_DIR)/include/rpcd $(1)/usr/include/
+endef
+
+define Package/rpcd/default
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=OpenWrt ubus RPC backend server
+  DEPENDS:=+libubus +libubox
+endef
+
+define Package/rpcd
+  $(Package/rpcd/default)
+  DEPENDS+= +libuci +libblobmsg-json
+endef
+
+define Package/rpcd/description
+ This package provides the UBUS RPC backend server to expose various
+ functionality to frontend programs via JSON-RPC.
+endef
+
+define Package/rpcd/conffiles
+/etc/config/rpcd
+endef
+
+define Package/rpcd/install
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/rpcd.init $(1)/etc/init.d/rpcd
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd $(1)/sbin/rpcd
+	$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/unauthenticated.json $(1)/usr/share/rpcd/acl.d/unauthenticated.json
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_CONF) ./files/rpcd.config $(1)/etc/config/rpcd
+endef
+
+
+# 1: plugin name
+# 2: extra dependencies
+# 3: plugin title/description
+define BuildPlugin
+
+  PKG_CONFIG_DEPENDS += CONFIG_PACKAGE_luci-rpc-mod-$(1)
+
+  define Package/rpcd-mod-$(1)
+    $(Package/rpcd/default)
+    TITLE+= ($(1) plugin)
+    DEPENDS+=rpcd $(2)
+  endef
+
+  define Package/rpcd-mod-$(1)/description
+    $(3)
+  endef
+
+  define Package/rpcd-mod-$(1)/install
+	$(INSTALL_DIR) $$(1)/usr/lib/rpcd
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(1).so $$(1)/usr/lib/rpcd/
+  endef
+
+  $$(eval $$(call BuildPackage,rpcd-mod-$(1)))
+
+endef
+
+$(eval $(call BuildPackage,rpcd))
+$(eval $(call BuildPlugin,file,,Provides ubus calls for file and directory operations.))
+$(eval $(call BuildPlugin,rpcsys,,Provides ubus calls for sysupgrade and password changing.))
+$(eval $(call BuildPlugin,iwinfo,+libiwinfo,Provides ubus calls for accessing iwinfo data.))
diff --git a/package/system/rpcd/files/rpcd.config b/package/system/rpcd/files/rpcd.config
new file mode 100644
index 0000000000..499ea27628
--- /dev/null
+++ b/package/system/rpcd/files/rpcd.config
@@ -0,0 +1,7 @@
+
+config login
+	option username 'root'
+	option password '$p$root'
+	list read '*'
+	list write '*'
+
diff --git a/package/system/rpcd/files/rpcd.init b/package/system/rpcd/files/rpcd.init
new file mode 100755
index 0000000000..98b633365b
--- /dev/null
+++ b/package/system/rpcd/files/rpcd.init
@@ -0,0 +1,21 @@
+#!/bin/sh /etc/rc.common
+
+START=12
+
+USE_PROCD=1
+NAME=rpcd
+PROG=/sbin/rpcd
+
+start_service() {
+	procd_open_instance
+	procd_set_param command "$PROG"
+	procd_close_instance
+}
+
+stop() {
+	service_stop /sbin/rpcd
+}
+
+reload() {
+	service_reload /sbin/rpcd
+}
diff --git a/package/system/ubox/Makefile b/package/system/ubox/Makefile
new file mode 100644
index 0000000000..fda9425612
--- /dev/null
+++ b/package/system/ubox/Makefile
@@ -0,0 +1,49 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ubox
+PKG_VERSION:=2016-09-26
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/ubox.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=5649c028c426060616e2bd4e7ea83271cd333d21
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=ee460ca724ff505966ca710a3363ac8d308f1a9a91de92b281d22d3d4df51de1
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-lrt)
+
+define Package/ubox
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libubox +ubusd +ubus +libubus +libuci +USE_GLIBC:librt
+  TITLE:=OpenWrt system helper toolbox
+endef
+
+define Package/ubox/install
+	$(INSTALL_DIR) $(1)/sbin $(1)/usr/sbin $(1)/lib $(1)/usr/bin $(1)/etc/init.d
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{kmodloader,validate_data} $(1)/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/getrandom $(1)/usr/bin/
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libvalidate.so $(1)/lib
+
+	$(LN) ../../sbin/kmodloader $(1)/usr/sbin/rmmod
+	$(LN) ../../sbin/kmodloader $(1)/usr/sbin/insmod
+	$(LN) ../../sbin/kmodloader $(1)/usr/sbin/lsmod
+	$(LN) ../../sbin/kmodloader $(1)/usr/sbin/modinfo
+	$(LN) ../../sbin/kmodloader $(1)/usr/sbin/modprobe
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{logd,logread} $(1)/sbin/
+	$(INSTALL_BIN) ./files/log.init $(1)/etc/init.d/log
+endef
+
+$(eval $(call BuildPackage,ubox))
diff --git a/package/system/ubox/files/log.init b/package/system/ubox/files/log.init
new file mode 100644
index 0000000000..722dc20e90
--- /dev/null
+++ b/package/system/ubox/files/log.init
@@ -0,0 +1,100 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2013 OpenWrt.org
+
+# start after and stop before networking
+START=12
+STOP=89
+PIDCOUNT=0
+
+USE_PROCD=1
+PROG=/sbin/logread
+
+validate_log_section()
+{
+	uci_validate_section system system "${1}" \
+		'log_file:string' \
+		'log_size:uinteger' \
+		'log_hostname:string' \
+		'log_ip:ipaddr' \
+		'log_remote:bool:1' \
+		'log_port:port:514' \
+		'log_proto:or("tcp", "udp"):udp' \
+		'log_trailer_null:bool:0' \
+		'log_prefix:string'
+}
+
+validate_log_daemon()
+{
+	uci_validate_section system system "${1}" \
+		'log_size:uinteger:0' \
+		'log_buffer_size:uinteger:0'
+}
+
+start_service_daemon()
+{
+	local log_buffer_size log_size
+	validate_log_daemon "${1}"
+	[ $log_buffer_size -eq 0 -a $log_size -gt 0 ] && log_buffer_size=$log_size
+	[ $log_buffer_size -eq 0 ] && log_buffer_size=64
+	procd_open_instance
+	procd_set_param command "/sbin/logd"
+	procd_append_param command -S "${log_buffer_size}"
+	procd_set_param respawn
+	procd_close_instance
+}
+
+start_service_file()
+{
+	PIDCOUNT="$(( ${PIDCOUNT} + 1))"
+	local pid_file="/var/run/logread.${PIDCOUNT}.pid"
+	local log_file log_size
+
+	validate_log_section "${1}" || {
+		echo "validation failed"
+		return 1
+	}
+	[ -z "${log_file}" ] && return
+
+	procd_open_instance
+	procd_set_param command "$PROG" -f -F "$log_file" -p "$pid_file"
+	[ -n "${log_size}" ] && procd_append_param command -S "$log_size"
+	procd_close_instance
+}
+
+start_service_remote()
+{
+	PIDCOUNT="$(( ${PIDCOUNT} + 1))"
+	local pid_file="/var/run/logread.${PIDCOUNT}.pid"
+	local log_ip log_port log_proto log_prefix log_remote log_trailer_null log_hostname
+
+	validate_log_section "${1}" || {
+		echo "validation failed"
+		return 1
+	}
+	[ "${log_remote}" -ne 0 ] || return
+	[ -z "${log_ip}" ] && return
+	[ -z "${log_hostname}" ] && log_hostname=$(cat /proc/sys/kernel/hostname)
+
+	procd_open_instance
+	procd_set_param command "$PROG" -f -h "$log_hostname" -r "$log_ip" "${log_port}" -p "$pid_file"
+	case "${log_proto}" in
+		"udp") procd_append_param command -u;;
+		"tcp") [ "${log_trailer_null}" -eq 1 ] && procd_append_param command -0;;
+	esac
+	[ -z "${log_prefix}" ] || procd_append_param command -P "${log_prefix}"
+	procd_close_instance
+}
+
+service_triggers()
+{
+	procd_add_reload_trigger "system"
+	procd_add_validation validate_log_section
+}
+
+start_service()
+{
+	config_load system
+	config_foreach start_service_daemon system
+	config_foreach start_service_file system
+	config_foreach start_service_remote system
+}
diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile
new file mode 100644
index 0000000000..b2352f4f09
--- /dev/null
+++ b/package/system/ubus/Makefile
@@ -0,0 +1,80 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ubus
+PKG_VERSION:=2016-10-12
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/ubus.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=312448a5b147c221836827a7a641e76a4514db44
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=0d572863d46c9d6e89a573ed5db671f4eaff311df6fa5e8fa83b8f07e7dc928d
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/ubus
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libubus +libblobmsg-json +ubusd
+  TITLE:=OpenWrt RPC client utility
+endef
+
+define Package/ubusd
+  SECTION:=base
+  CATEGORY:=Base system
+  TITLE:=OpenWrt RPC daemon
+  DEPENDS:=+libubox +libblobmsg-json
+endef
+
+define Package/libubus
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libubox
+  ABI_VERSION:=$(PKG_VERSION)
+  TITLE:=OpenWrt RPC client library
+endef
+
+define Package/libubus-lua
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libubus +liblua
+  TITLE:=Lua binding for the OpenWrt RPC client
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS = \
+	-DLUAPATH=/usr/lib/lua
+
+define Package/ubus/install
+	$(INSTALL_DIR) $(1)/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/ubus $(1)/bin/
+endef
+
+define Package/ubusd/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/ubusd $(1)/sbin/
+endef
+
+define Package/libubus/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so $(1)/lib/
+endef
+
+define Package/libubus-lua/install
+	$(INSTALL_DIR) $(1)/usr/lib/lua
+	$(CP) $(PKG_BUILD_DIR)/lua/ubus.so $(1)/usr/lib/lua/
+endef
+
+$(eval $(call BuildPackage,libubus))
+$(eval $(call BuildPackage,libubus-lua))
+$(eval $(call BuildPackage,ubus))
+$(eval $(call BuildPackage,ubusd))
diff --git a/package/system/uci/Makefile b/package/system/uci/Makefile
new file mode 100644
index 0000000000..65cbf9d35c
--- /dev/null
+++ b/package/system/uci/Makefile
@@ -0,0 +1,94 @@
+#
+# Copyright (C) 2008-2014 OpenWrt.org
+# Copyright (C) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+UCI_VERSION=2016-07-04
+UCI_RELEASE=1
+
+PKG_NAME:=uci
+PKG_VERSION:=$(UCI_VERSION)$(if $(UCI_RELEASE),.$(UCI_RELEASE))
+PKG_RELEASE:=1
+PKG_REV:=e1bf4356e1b513e158e1b5049147087ed6342cfd
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL=$(LEDE_GIT)/project/uci.git
+PKG_SOURCE_SUBDIR:=uci-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_SOURCE_PROTO:=git
+PKG_MIRROR_MD5SUM:=1206aff4b41bc4aa78205c7537bc75886244c293cb5f08dc7ba3dc4def93a81c
+
+PKG_LICENSE:=LGPL-2.1
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_PARALLEL:=0
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+# set to 1 to enable debugging
+DEBUG=
+
+define Package/libuci
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=C library for the Unified Configuration Interface (UCI)
+  DEPENDS:=+libubox
+endef
+
+define Package/uci
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libuci
+  TITLE:=Utility for the Unified Configuration Interface (UCI)
+endef
+
+define Package/libuci-lua
+  SECTION=libs
+  CATEGORY=Libraries
+  DEPENDS:=+libuci +liblua
+  TITLE:=Lua plugin for UCI
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib
+
+CMAKE_OPTIONS = \
+	-DLUAPATH=/usr/lib/lua \
+	$(if $(DEBUG),-DUCI_DEBUG=ON)
+
+define Package/libuci/install
+	$(INSTALL_DIR) $(1)/lib
+	$(CP) $(PKG_BUILD_DIR)/libuci.so* $(1)/lib/
+endef
+
+define Package/libuci-lua/install
+	$(INSTALL_DIR) $(1)/usr/lib/lua
+	$(CP) $(PKG_BUILD_DIR)/lua/uci.so $(1)/usr/lib/lua/
+endef
+
+define Package/uci/install
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/uci $(1)/sbin/
+	$(CP) ./files/* $(1)/
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_BUILD_DIR)/uci{,_config,_blob,map}.h $(1)/usr/include
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libuci.so* $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libucimap.a $(1)/usr/lib
+endef
+
+$(eval $(call BuildPackage,uci))
+$(eval $(call BuildPackage,libuci))
+$(eval $(call BuildPackage,libuci-lua))
diff --git a/package/system/uci/files/lib/config/uci.sh b/package/system/uci/files/lib/config/uci.sh
new file mode 100644
index 0000000000..50891a64e4
--- /dev/null
+++ b/package/system/uci/files/lib/config/uci.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+# Shell script compatibility wrappers for /sbin/uci
+#
+# Copyright (C) 2008-2010  OpenWrt.org
+# Copyright (C) 2008  Felix Fietkau <nbd@nbd.name>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+CONFIG_APPEND=
+uci_load() {
+	local PACKAGE="$1"
+	local DATA
+	local RET
+	local VAR
+
+	_C=0
+	if [ -z "$CONFIG_APPEND" ]; then
+		for VAR in $CONFIG_LIST_STATE; do
+			export ${NO_EXPORT:+-n} CONFIG_${VAR}=
+			export ${NO_EXPORT:+-n} CONFIG_${VAR}_LENGTH=
+		done
+		export ${NO_EXPORT:+-n} CONFIG_LIST_STATE=
+		export ${NO_EXPORT:+-n} CONFIG_SECTIONS=
+		export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=0
+		export ${NO_EXPORT:+-n} CONFIG_SECTION=
+	fi
+
+	DATA="$(/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} ${LOAD_STATE:+-P /var/state} -S -n export "$PACKAGE" 2>/dev/null)"
+	RET="$?"
+	[ "$RET" != 0 -o -z "$DATA" ] || eval "$DATA"
+	unset DATA
+
+	${CONFIG_SECTION:+config_cb}
+	return "$RET"
+}
+
+uci_set_default() {
+	local PACKAGE="$1"
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -q show "$PACKAGE" > /dev/null && return 0
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} import "$PACKAGE"
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} commit "$PACKAGE"
+}
+
+uci_revert_state() {
+	local PACKAGE="$1"
+	local CONFIG="$2"
+	local OPTION="$3"
+
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state revert "$PACKAGE${CONFIG:+.$CONFIG}${OPTION:+.$OPTION}"
+}
+
+uci_set_state() {
+	local PACKAGE="$1"
+	local CONFIG="$2"
+	local OPTION="$3"
+	local VALUE="$4"
+
+	[ "$#" = 4 ] || return 0
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} -P /var/state set "$PACKAGE.$CONFIG${OPTION:+.$OPTION}=$VALUE"
+}
+
+uci_toggle_state() {
+	uci_revert_state "$1" "$2" "$3"
+	uci_set_state "$1" "$2" "$3" "$4"
+}
+
+uci_set() {
+	local PACKAGE="$1"
+	local CONFIG="$2"
+	local OPTION="$3"
+	local VALUE="$4"
+
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} set "$PACKAGE.$CONFIG.$OPTION=$VALUE"
+}
+
+uci_get_state() {
+	uci_get "$1" "$2" "$3" "$4" "/var/state"
+}
+
+uci_get() {
+	local PACKAGE="$1"
+	local CONFIG="$2"
+	local OPTION="$3"
+	local DEFAULT="$4"
+	local STATE="$5"
+
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} ${STATE:+-P $STATE} -q get "$PACKAGE${CONFIG:+.$CONFIG}${OPTION:+.$OPTION}"
+	RET="$?"
+	[ "$RET" -ne 0 ] && [ -n "$DEFAULT" ] && echo "$DEFAULT"
+	return "$RET"
+}
+
+uci_add() {
+	local PACKAGE="$1"
+	local TYPE="$2"
+	local CONFIG="$3"
+
+	if [ -z "$CONFIG" ]; then
+		export ${NO_EXPORT:+-n} CONFIG_SECTION="$(/sbin/uci add "$PACKAGE" "$TYPE")"
+	else
+		/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} set "$PACKAGE.$CONFIG=$TYPE"
+		export ${NO_EXPORT:+-n} CONFIG_SECTION="$CONFIG"
+	fi
+}
+
+uci_rename() {
+	local PACKAGE="$1"
+	local CONFIG="$2"
+	local VALUE="$3"
+
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} rename "$PACKAGE.$CONFIG=$VALUE"
+}
+
+uci_remove() {
+	local PACKAGE="$1"
+	local CONFIG="$2"
+	local OPTION="$3"
+
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} del "$PACKAGE.$CONFIG${OPTION:+.$OPTION}"
+}
+
+uci_commit() {
+	local PACKAGE="$1"
+	/sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} commit $PACKAGE
+}
diff --git a/package/system/usign/Makefile b/package/system/usign/Makefile
new file mode 100644
index 0000000000..cd14404d92
--- /dev/null
+++ b/package/system/usign/Makefile
@@ -0,0 +1,46 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=usign
+PKG_VERSION:=2015-07-04
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/usign.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=ef6419142a3b0fbcddcccf536e3c1880302c6f89
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=8539292a3e8047bd7e94d4a5efc5c1228e100c7e6dfdc79670e869fb4aec3b70
+CMAKE_INSTALL:=1
+PKG_CHECK_FORMAT_SECURITY:=1
+PKG_USE_MIPS16:=0
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
+
+define Package/usign
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libubox
+  TITLE:=OpenWrt signature verification utility
+endef
+
+CMAKE_OPTIONS += \
+	-DUSE_LIBUBOX=on
+
+define Package/usign/install
+	$(INSTALL_DIR) $(1)/usr/bin
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/usign $(1)/usr/bin
+	ln -s usign $(1)/usr/bin/signify
+endef
+
+$(eval $(call BuildPackage,usign))
+$(eval $(call HostBuild))
diff --git a/package/system/zram-swap/Makefile b/package/system/zram-swap/Makefile
new file mode 100644
index 0000000000..bd84d79b01
--- /dev/null
+++ b/package/system/zram-swap/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=zram-swap
+PKG_VERSION:=1
+PKG_RELEASE:=2
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/zram-swap
+  SECTION:=utils
+  CATEGORY:=Base system
+  DEPENDS:=+kmod-zram +!BUSYBOX_CONFIG_MKSWAP:swap-utils +!BUSYBOX_CONFIG_SWAPONOFF:block-mount
+  TITLE:=ZRAM swap scripts
+  PKGARCH:=all
+endef
+
+define Package/zram-swap/description
+ A script to activate swaping on a compressed zram partition. This 
+ could be used to increase the available memory, by using compressed 
+ memory.
+endef
+
+define Build/Prepare
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/zram-swap/install
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/zram.init $(1)/etc/init.d/zram
+endef
+
+$(eval $(call BuildPackage,zram-swap))
diff --git a/package/system/zram-swap/files/zram.init b/package/system/zram-swap/files/zram.init
new file mode 100644
index 0000000000..431e47c8f9
--- /dev/null
+++ b/package/system/zram-swap/files/zram.init
@@ -0,0 +1,132 @@
+#!/bin/sh /etc/rc.common
+
+START=15
+
+ram_size()
+{
+	local line
+
+	while read line; do case "$line" in MemTotal:*) set $line; echo "$2"; break ;; esac; done </proc/meminfo
+}
+
+zram_size()	# in megabytes
+{
+	local zram_size="$( uci -q get system.@system[0].zram_size_mb )"
+	local ram_size="$( ram_size )"
+
+	if [ -z "$zram_size" ]; then
+		# e.g. 6mb for 16mb-routers or 61mb for 128mb-routers
+		echo $(( $ram_size / 2048 ))
+	else
+		echo "$zram_size"
+	fi
+}
+
+zram_applicable()
+{
+	local zram_dev="$1"
+
+	grep -sq ^"$zram_dev " /proc/swaps && {
+		logger -s -t zram_applicable -p daemon.notice "[OK] '$zram_dev' already active"
+		return 1
+	}
+
+	[ -e "$zram_dev" ] || {
+		logger -s -t zram_applicable -p daemon.crit "[ERROR] device '$zram_dev' not found"
+		return 1
+	}
+
+	which mkswap >/dev/null || {
+		logger -s -t zram_applicable -p daemon.err "[ERROR] 'mkswap' not installed"
+		return 1
+	}
+
+	which swapon >/dev/null || {
+		logger -s -t zram_applicable -p daemon.err "[ERROR] 'swapon' not installed"
+		return 1
+	}
+
+	which swapoff >/dev/null || {
+		logger -s -t zram_applicable -p daemon.err "[ERROR] 'swapoff' not installed"
+		return 1
+	}
+}
+
+zram_dev()
+{
+	local core="$1"
+
+	echo "/dev/zram${core:-0}"
+}
+
+zram_reset()
+{
+	local dev="$1"
+	local message="$2"
+	local proc_entry="/sys/block/$( basename "$dev" )/reset"
+
+	logger -s -t zram_reset -p daemon.debug "$message via $proc_entry"
+	echo "1" >"$proc_entry"
+}
+
+list_cpu_idx()
+{
+	# Offset by 1 if /dev/zram0 is in use by /tmp
+	if [ "$(mount | grep /dev/zram0)" ]; then
+		local line i=1
+		# Hot-add new ZRAM device (if necessary)
+		if [ ! -b /dev/zram1 ]; then 
+			cat /sys/class/zram-control/hot_add
+		fi
+	else
+		local line i=0
+	fi
+	
+	while read line; do {
+		case "$line" in
+			[Pp]rocessor*)
+				echo $i
+				i=$(( $i + 1 ))
+			;;
+		esac
+	} done <"/proc/cpuinfo"
+}
+
+start()
+{
+	# http://shmilyxbq-compcache.googlecode.com/hg/README
+	# if >1 cpu_core, reinit kmodule with e.g. num_devices=4
+
+	local zram_size="$( zram_size )"
+	local zram_dev core
+
+	for core in $( list_cpu_idx ); do {
+		zram_dev="$( zram_dev "$core" )"
+		zram_applicable "$zram_dev" || return 1
+
+		logger -s -t zram_start -p daemon.debug "activating '$zram_dev' for swapping ($zram_size MegaBytes)"
+
+		zram_reset "$zram_dev" "enforcing defaults"
+		echo $(( $zram_size * 1024 * 1024 )) >"/sys/block/$( basename $zram_dev )/disksize"
+		mkswap "$zram_dev"
+		swapon "$zram_dev"
+	} done
+}
+
+stop()
+{
+	local zram_dev proc_entry
+
+	for core in $( list_cpu_idx ); do {
+		zram_dev="$( zram_dev "$core" )"
+		proc_entry="/sys/block/$( basename "$zram_dev" )/reset"
+
+		grep -sq ^"$zram_dev " /proc/swaps && {
+			logger -s -t zram_stop -p daemon.debug "deactivate swap $zram_dev"
+			swapoff "$zram_dev"
+		}
+
+		zram_reset "$zram_dev" "claiming memory back"
+	} done
+}
+
diff --git a/package/utils/admswconfig/Makefile b/package/utils/admswconfig/Makefile
new file mode 100644
index 0000000000..6f4b6049e2
--- /dev/null
+++ b/package/utils/admswconfig/Makefile
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=admswconfig
+PKG_VERSION:=0.1
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://downloads.openwrt.org/sources
+PKG_MD5SUM:=faafd4618f970119a665b11b21ac6a26
+
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/admswconfig
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=ADM5120 Switch configuration tool
+  DEPENDS:=@TARGET_adm5120
+  URL:=http://sharon.esrac.ele.tue.nl/users/pe1rxq/linux-adm/admswconfig/
+  MAINTAINER:=Florian Fainelli <florian@openwrt.org>
+endef
+
+define Package/admswconfig/description
+ A program to configure the internal ethernet switch of an ADM5120 processor.
+ You need the corresponding driver for the switch in the kernel. 
+ With this program you can configure which ports of the switch belong 
+ to the different ethernet devices.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -Os $(PKG_BUILD_DIR)/admswconfig.c -o $(PKG_BUILD_DIR)/$(PKG_NAME)
+endef
+
+define Package/admswconfig/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/admswconfig $(1)/sbin/
+	$(INSTALL_DIR) $(1)/lib/network/
+	$(INSTALL_DATA) ./files/admswswitch.sh $(1)/lib/network/admswswitch.sh
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/admswconfig $(1)/etc/init.d/admswconfig
+endef
+
+$(eval $(call BuildPackage,admswconfig))
diff --git a/package/utils/admswconfig/files/admswconfig b/package/utils/admswconfig/files/admswconfig
new file mode 100644
index 0000000000..7231030650
--- /dev/null
+++ b/package/utils/admswconfig/files/admswconfig
@@ -0,0 +1,68 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006 OpenWrt.org
+
+START=05
+
+start() {
+	[ -e /etc/config/network ] && exit 0
+
+	mkdir -p /etc/config
+
+	board_name=$(awk 'BEGIN{FS="[ \t]+:[ \t]"} /system type/ {print $2}' /proc/cpuinfo)
+
+	case "$board_name" in
+	"Compex WP54"*)
+		board="Compex WP54";;
+	esac
+
+	echo "$board" |awk '
+	function p(cfgname, name) {
+		if (c[name] != "") print "	option " cfgname "	\"" c[name] "\""
+	}
+
+	BEGIN {
+		FS="="
+		c["lan_ifname"]="eth0"
+		c["wan_ifname"]="eth1"
+		c["eth0ports"]="1 2 3 4"
+		c["eth1ports"]="0"
+	}
+	END {
+		board=$1
+		if (board == "Compex WP54") {
+			c["eth0ports"]="0"
+			c["eth1ports"]="1"
+		}
+
+		print "#### VLAN configuration "
+		print "config switch"
+		p("eth0", "eth0ports")
+		p("eth1", "eth1ports")
+		print ""
+		print ""
+		print "#### Loopback configuration"
+		print "config interface loopback"
+		print "	option ifname	\"lo\""
+		print "	option proto	static"
+		print "	option ipaddr	127.0.0.1"
+		print "	option netmask	255.0.0.0"
+		print ""
+		print ""
+		print "#### LAN configuration"
+		print "config interface lan"
+		print "	option type 	bridge"
+		p("ifname", "lan_ifname")
+		p("macaddr", "lan_macaddr")
+		print "	option proto	static"
+		print "	option ipaddr	192.168.1.1"
+		print "	option netmask	255.255.255.0"
+		print ""
+		print ""
+		print "#### WAN configuration"
+		print "config interface	wan"
+		p("ifname", "wan_ifname")
+		p("macaddr", "wan_macaddr")
+		print "	option proto	dhcp"
+	}' > /etc/config/network
+}
+
diff --git a/package/utils/admswconfig/files/admswswitch.sh b/package/utils/admswconfig/files/admswswitch.sh
new file mode 100644
index 0000000000..3b8aabf34d
--- /dev/null
+++ b/package/utils/admswconfig/files/admswswitch.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+
+setup_switch_vlan() {
+	config_get ports "$CONFIG_SECTION" "eth$1"
+	ports=`echo "$ports"| sed s/" "/""/g`
+	ip link set dev eth$1 down
+	admswconfig eth$1 ${ports}c
+	ip link set dev eth$1 up
+}
+
+setup_switch() {
+	config_cb() {
+		case "$1" in
+			switch)
+				option_cb() {
+					case "$1" in
+						eth*) setup_switch_vlan "${1##eth}";;
+					esac
+				}
+			;;
+			*)
+				option_cb() { return 0; }
+			;;
+		esac
+	}
+	config_load network
+}
diff --git a/package/utils/admswconfig/patches/001-matrix.patch b/package/utils/admswconfig/patches/001-matrix.patch
new file mode 100644
index 0000000000..e50d515757
--- /dev/null
+++ b/package/utils/admswconfig/patches/001-matrix.patch
@@ -0,0 +1,15 @@
+--- a/admswconfig.c
++++ b/admswconfig.c
+@@ -111,9 +111,9 @@ int main(int argc, char **argv)
+ 		}
+ 	} else {
+ 		/* display matrix */
+-		printf("ethX\tport0\tport1\tport2\tport3\tport4");
+-		if (info.ports == 6)
+-			printf("\tport5");
++		printf("ethX");
++		for (i = 0; i < info.ports; i++)
++			printf("\tport%d", i);
+ 		printf("\tCPU\n");
+ 		for (i = 0; i < info.ports; i++) {
+ 			printf("%d", i);
diff --git a/package/utils/admswconfig/patches/002-fix-musl.patch b/package/utils/admswconfig/patches/002-fix-musl.patch
new file mode 100644
index 0000000000..3dad1f99d5
--- /dev/null
+++ b/package/utils/admswconfig/patches/002-fix-musl.patch
@@ -0,0 +1,11 @@
+--- a/admswconfig.c
++++ b/admswconfig.c
+@@ -68,7 +68,7 @@ int main(int argc, char **argv)
+ 		return 1;
+ 	}
+ 	strcpy(ifr.ifr_name, device);
+-	ifr.ifr_data = (caddr_t)&info;
++	ifr.ifr_data = (void *)&info;
+ 	if (ioctl(fd, SIOCGADMINFO, &ifr) < 0) {
+ 		perror("SIOCGADMINFO");
+ 		return 1;
diff --git a/package/utils/bsdiff/Makefile b/package/utils/bsdiff/Makefile
new file mode 100644
index 0000000000..e5eef840b3
--- /dev/null
+++ b/package/utils/bsdiff/Makefile
@@ -0,0 +1,79 @@
+#
+# Copyright (C) 2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bsdiff
+PKG_VERSION:=4.3
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.daemonology.net/bsdiff/
+PKG_MD5SUM:=e6d812394f0e0ecc8d5df255aa1db22a
+PKG_MAINTAINER:=Hauke Mehrtens <hauke@hauke-m.de>
+HOST_BUILD_DEPENDS:=bzip2/host
+
+PKG_LICENSE:=BSD-2-Clause
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/bsdiff
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libbz2
+  TITLE:=Binary diff tool
+  URL:=http://www.daemonology.net/bsdiff/
+endef
+
+define Package/bspatch
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libbz2
+  TITLE:=Binary patch tool
+  URL:=http://www.daemonology.net/bsdiff/
+endef
+
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) $(TARGET_LDFLAGS) \
+		-o $(PKG_BUILD_DIR)/bsdiff \
+		$(PKG_BUILD_DIR)/bsdiff.c -lbz2
+	$(TARGET_CC) $(TARGET_CFLAGS) $(TARGET_LDFLAGS) \
+		-o $(PKG_BUILD_DIR)/bspatch \
+		$(PKG_BUILD_DIR)/bspatch.c -lbz2
+endef
+
+define Package/bsdiff/install
+	$(INSTALL_DIR) $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bsdiff $(1)/usr/bin/bsdiff
+endef
+
+define Package/bspatch/install
+	$(INSTALL_DIR) $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bspatch $(1)/usr/bin/bspatch
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR)/host/bin/
+	$(MAKE) -C $(HOST_BUILD_DIR) PREFIX=$(STAGING_DIR)/host/ install
+endef
+
+define Host/Compile
+	$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) \
+		-o $(HOST_BUILD_DIR)/bsdiff \
+		$(HOST_BUILD_DIR)/bsdiff.c -lbz2
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/bsdiff $(STAGING_DIR)/host/bin/
+endef
+
+$(eval $(call HostBuild))
+
+$(eval $(call BuildPackage,bsdiff))
+$(eval $(call BuildPackage,bspatch))
diff --git a/package/utils/bsdiff/patches/001-musl.patch b/package/utils/bsdiff/patches/001-musl.patch
new file mode 100644
index 0000000000..5232bc1fe7
--- /dev/null
+++ b/package/utils/bsdiff/patches/001-musl.patch
@@ -0,0 +1,84 @@
+--- a/bsdiff.c	2005-08-17 00:13:52.000000000 +0200
++++ b/bsdiff.c	2016-02-21 01:39:31.157915765 +0100
+@@ -101,7 +101,7 @@
+ 	if(start+len>kk) split(I,V,kk,start+len-kk,h);
+ }
+ 
+-static void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize)
++static void qsufsort(off_t *I,off_t *V,unsigned char *old,off_t oldsize)
+ {
+ 	off_t buckets[256];
+ 	off_t i,h,len;
+@@ -139,7 +139,7 @@
+ 	for(i=0;i<oldsize+1;i++) I[V[i]]=i;
+ }
+ 
+-static off_t matchlen(u_char *old,off_t oldsize,u_char *new,off_t newsize)
++static off_t matchlen(unsigned char *old,off_t oldsize,unsigned char *new,off_t newsize)
+ {
+ 	off_t i;
+ 
+@@ -149,8 +149,8 @@
+ 	return i;
+ }
+ 
+-static off_t search(off_t *I,u_char *old,off_t oldsize,
+-		u_char *new,off_t newsize,off_t st,off_t en,off_t *pos)
++static off_t search(off_t *I,unsigned char *old,off_t oldsize,
++		unsigned char *new,off_t newsize,off_t st,off_t en,off_t *pos)
+ {
+ 	off_t x,y;
+ 
+@@ -175,7 +175,7 @@
+ 	};
+ }
+ 
+-static void offtout(off_t x,u_char *buf)
++static void offtout(off_t x,unsigned char *buf)
+ {
+ 	off_t y;
+ 
+@@ -196,7 +196,7 @@
+ int main(int argc,char *argv[])
+ {
+ 	int fd;
+-	u_char *old,*new;
++	unsigned char *old,*new;
+ 	off_t oldsize,newsize;
+ 	off_t *I,*V;
+ 	off_t scan,pos,len;
+@@ -206,9 +206,9 @@
+ 	off_t overlap,Ss,lens;
+ 	off_t i;
+ 	off_t dblen,eblen;
+-	u_char *db,*eb;
+-	u_char buf[8];
+-	u_char header[32];
++	unsigned char *db,*eb;
++	unsigned char buf[8];
++	unsigned char header[32];
+ 	FILE * pf;
+ 	BZFILE * pfbz2;
+ 	int bz2err;
+--- a/bspatch.c	2005-08-17 00:14:00.000000000 +0200
++++ b/bspatch.c	2016-02-21 01:39:29.753859970 +0100
+@@ -36,7 +36,7 @@
+ #include <unistd.h>
+ #include <fcntl.h>
+ 
+-static off_t offtin(u_char *buf)
++static off_t offtin(unsigned char *buf)
+ {
+ 	off_t y;
+ 
+@@ -62,8 +62,8 @@
+ 	int fd;
+ 	ssize_t oldsize,newsize;
+ 	ssize_t bzctrllen,bzdatalen;
+-	u_char header[32],buf[8];
+-	u_char *old, *new;
++	unsigned char header[32],buf[8];
++	unsigned char *old, *new;
+ 	off_t oldpos,newpos;
+ 	off_t ctrl[3];
+ 	off_t lenread;
diff --git a/package/utils/busybox/Config-defaults.in b/package/utils/busybox/Config-defaults.in
new file mode 100644
index 0000000000..11cce03db9
--- /dev/null
+++ b/package/utils/busybox/Config-defaults.in
@@ -0,0 +1,2805 @@
+config BUSYBOX_DEFAULT_HAVE_DOT_CONFIG
+	bool
+	default y
+config BUSYBOX_DEFAULT_DESKTOP
+	bool
+	default n
+config BUSYBOX_DEFAULT_EXTRA_COMPAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_INCLUDE_SUSv2
+	bool
+	default y
+config BUSYBOX_DEFAULT_USE_PORTABLE_CODE
+	bool
+	default n
+config BUSYBOX_DEFAULT_PLATFORM_LINUX
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_BUFFERS_USE_MALLOC
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BUFFERS_GO_ON_STACK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_BUFFERS_GO_IN_BSS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SHOW_USAGE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VERBOSE_USAGE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_COMPRESS_USAGE
+	bool
+	default y
+config BUSYBOX_DEFAULT_BUSYBOX
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSTALLER
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_NO_USR
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOCALE_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNICODE_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNICODE_USING_LOCALE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHECK_UNICODE_IN_ENV
+	bool
+	default n
+config BUSYBOX_DEFAULT_SUBST_WCHAR
+	int
+	default 0
+config BUSYBOX_DEFAULT_LAST_SUPPORTED_WCHAR
+	int
+	default 0
+config BUSYBOX_DEFAULT_UNICODE_COMBINING_WCHARS
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNICODE_WIDE_WCHARS
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNICODE_BIDI_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNICODE_NEUTRAL_TABLE
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNICODE_PRESERVE_BROKEN
+	bool
+	default n
+config BUSYBOX_DEFAULT_PAM
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_USE_SENDFILE
+	bool
+	default n
+config BUSYBOX_DEFAULT_LONG_OPTS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DEVPTS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_CLEAN_UP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_UTMP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WTMP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PIDFILE
+	bool
+	default y
+config BUSYBOX_DEFAULT_PID_FILE_PATH
+	string
+	default "/var/run"
+config BUSYBOX_DEFAULT_FEATURE_SUID
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SUID_CONFIG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SUID_CONFIG_QUIET
+	bool
+	default n
+config BUSYBOX_DEFAULT_SELINUX
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PREFER_APPLETS
+	bool
+	default y
+config BUSYBOX_DEFAULT_BUSYBOX_EXEC_PATH
+	string
+	default "/proc/self/exe"
+config BUSYBOX_DEFAULT_FEATURE_SYSLOG
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_HAVE_RPC
+	bool
+	default n
+config BUSYBOX_DEFAULT_STATIC
+	bool
+	default n
+config BUSYBOX_DEFAULT_PIE
+	bool
+	default n
+config BUSYBOX_DEFAULT_NOMMU
+	bool
+	default n
+config BUSYBOX_DEFAULT_BUILD_LIBBUSYBOX
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INDIVIDUAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SHARED_BUSYBOX
+	bool
+	default n
+config BUSYBOX_DEFAULT_LFS
+	bool
+	default y
+config BUSYBOX_DEFAULT_CROSS_COMPILER_PREFIX
+	string
+	default ""
+config BUSYBOX_DEFAULT_SYSROOT
+	string
+	default ""
+config BUSYBOX_DEFAULT_EXTRA_CFLAGS
+	string
+	default ""
+config BUSYBOX_DEFAULT_EXTRA_LDFLAGS
+	string
+	default ""
+config BUSYBOX_DEFAULT_EXTRA_LDLIBS
+	string
+	default ""
+config BUSYBOX_DEFAULT_DEBUG
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEBUG_PESSIMIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEBUG_SANITIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNIT_TEST
+	bool
+	default n
+config BUSYBOX_DEFAULT_WERROR
+	bool
+	default n
+config BUSYBOX_DEFAULT_NO_DEBUG_LIB
+	bool
+	default y
+config BUSYBOX_DEFAULT_DMALLOC
+	bool
+	default n
+config BUSYBOX_DEFAULT_EFENCE
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_APPLET_SYMLINKS
+	bool
+	default y
+config BUSYBOX_DEFAULT_INSTALL_APPLET_HARDLINKS
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_APPLET_SCRIPT_WRAPPERS
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_APPLET_DONT
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_SH_APPLET_SYMLINK
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_SH_APPLET_HARDLINK
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSTALL_SH_APPLET_SCRIPT_WRAPPER
+	bool
+	default n
+config BUSYBOX_DEFAULT_PREFIX
+	string
+	default "./_install"
+config BUSYBOX_DEFAULT_FEATURE_USE_BSS_TAIL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_RTMINMAX
+	bool
+	default n
+config BUSYBOX_DEFAULT_PASSWORD_MINLEN
+	int
+	default 6
+config BUSYBOX_DEFAULT_MD5_SMALL
+	int
+	default 1
+config BUSYBOX_DEFAULT_SHA3_SMALL
+	int
+	default 1
+config BUSYBOX_DEFAULT_FEATURE_FAST_TOP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_ETC_NETWORKS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_USE_TERMIOS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EDITING
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_EDITING_MAX_LEN
+	int
+	default 512
+config BUSYBOX_DEFAULT_FEATURE_EDITING_VI
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EDITING_HISTORY
+	int
+	default 256
+config BUSYBOX_DEFAULT_FEATURE_EDITING_SAVEHISTORY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EDITING_SAVE_ON_EXIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_REVERSE_SEARCH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAB_COMPLETION
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_USERNAME_COMPLETION
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EDITING_FANCY_PROMPT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_EDITING_ASK_TERMINAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_NON_POSIX_CP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VERBOSE_CP_MESSAGE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_COPYBUF_KB
+	int
+	default 4
+config BUSYBOX_DEFAULT_FEATURE_SKIP_ROOTFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_MONOTONIC_SYSCALL
+	bool
+	default n
+config BUSYBOX_DEFAULT_IOCTL_HEX2STR_ERROR
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_HWIB
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SEAMLESS_XZ
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SEAMLESS_LZMA
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SEAMLESS_BZ2
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SEAMLESS_GZ
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SEAMLESS_Z
+	bool
+	default n
+config BUSYBOX_DEFAULT_AR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_AR_LONG_FILENAMES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_AR_CREATE
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNCOMPRESS
+	bool
+	default n
+config BUSYBOX_DEFAULT_GUNZIP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_GUNZIP_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_BUNZIP2
+	bool
+	default y
+config BUSYBOX_DEFAULT_UNLZMA
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LZMA_FAST
+	bool
+	default n
+config BUSYBOX_DEFAULT_LZMA
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNXZ
+	bool
+	default n
+config BUSYBOX_DEFAULT_XZ
+	bool
+	default n
+config BUSYBOX_DEFAULT_BZIP2
+	bool
+	default n
+config BUSYBOX_DEFAULT_CPIO
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CPIO_O
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CPIO_P
+	bool
+	default n
+config BUSYBOX_DEFAULT_DPKG
+	bool
+	default n
+config BUSYBOX_DEFAULT_DPKG_DEB
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DPKG_DEB_EXTRACT_ONLY
+	bool
+	default n
+config BUSYBOX_DEFAULT_GZIP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_GZIP_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_GZIP_FAST
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_GZIP_LEVELS
+	bool
+	default n
+config BUSYBOX_DEFAULT_LZOP
+	bool
+	default n
+config BUSYBOX_DEFAULT_LZOP_COMPR_HIGH
+	bool
+	default n
+config BUSYBOX_DEFAULT_RPM
+	bool
+	default n
+config BUSYBOX_DEFAULT_RPM2CPIO
+	bool
+	default n
+config BUSYBOX_DEFAULT_TAR
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TAR_CREATE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TAR_AUTODETECT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_FROM
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TAR_OLDGNU_COMPATIBILITY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_OLDSUN_COMPATIBILITY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_GNU_EXTENSIONS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TAR_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_TO_COMMAND
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_UNAME_GNAME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_NOPRESERVE_TIME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TAR_SELINUX
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNZIP
+	bool
+	default n
+config BUSYBOX_DEFAULT_BASENAME
+	bool
+	default y
+config BUSYBOX_DEFAULT_CAT
+	bool
+	default y
+config BUSYBOX_DEFAULT_DATE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DATE_ISOFMT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DATE_NANO
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DATE_COMPAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_DD
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DD_SIGNAL_HANDLING
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DD_THIRD_STATUS_LINE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DD_IBS_OBS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DD_STATUS
+	bool
+	default n
+config BUSYBOX_DEFAULT_HOSTID
+	bool
+	default n
+config BUSYBOX_DEFAULT_ID
+	bool
+	default y
+config BUSYBOX_DEFAULT_GROUPS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SHUF
+	bool
+	default n
+config BUSYBOX_DEFAULT_STAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_STAT_FORMAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_STAT_FILESYSTEM
+	bool
+	default n
+config BUSYBOX_DEFAULT_SYNC
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SYNC_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_TEST
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TEST_64
+	bool
+	default y
+config BUSYBOX_DEFAULT_TOUCH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TOUCH_NODEREF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TOUCH_SUSV3
+	bool
+	default y
+config BUSYBOX_DEFAULT_TR
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TR_CLASSES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TR_EQUIV
+	bool
+	default n
+config BUSYBOX_DEFAULT_TRUNCATE
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNLINK
+	bool
+	default n
+config BUSYBOX_DEFAULT_BASE64
+	bool
+	default n
+config BUSYBOX_DEFAULT_WHO
+	bool
+	default n
+config BUSYBOX_DEFAULT_USERS
+	bool
+	default n
+config BUSYBOX_DEFAULT_CAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_CATV
+	bool
+	default n
+config BUSYBOX_DEFAULT_CHGRP
+	bool
+	default y
+config BUSYBOX_DEFAULT_CHMOD
+	bool
+	default y
+config BUSYBOX_DEFAULT_CHOWN
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_CHOWN_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_CHROOT
+	bool
+	default y
+config BUSYBOX_DEFAULT_CKSUM
+	bool
+	default n
+config BUSYBOX_DEFAULT_COMM
+	bool
+	default n
+config BUSYBOX_DEFAULT_CP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_CP_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_CUT
+	bool
+	default y
+config BUSYBOX_DEFAULT_DF
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DF_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_DIRNAME
+	bool
+	default y
+config BUSYBOX_DEFAULT_DOS2UNIX
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNIX2DOS
+	bool
+	default n
+config BUSYBOX_DEFAULT_DU
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+	bool
+	default y
+config BUSYBOX_DEFAULT_ECHO
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FANCY_ECHO
+	bool
+	default y
+config BUSYBOX_DEFAULT_ENV
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_ENV_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_EXPAND
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EXPAND_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_EXPR
+	bool
+	default y
+config BUSYBOX_DEFAULT_EXPR_MATH_SUPPORT_64
+	bool
+	default y
+config BUSYBOX_DEFAULT_FALSE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FOLD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FSYNC
+	bool
+	default y
+config BUSYBOX_DEFAULT_HEAD
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FANCY_HEAD
+	bool
+	default y
+config BUSYBOX_DEFAULT_INSTALL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSTALL_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_LN
+	bool
+	default y
+config BUSYBOX_DEFAULT_LOGNAME
+	bool
+	default n
+config BUSYBOX_DEFAULT_LS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_FILETYPES
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_FOLLOWLINKS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_RECURSIVE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_SORTFILES
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_TIMESTAMPS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_USERNAME
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_COLOR
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LS_COLOR_IS_DEFAULT
+	bool
+	default y
+config BUSYBOX_DEFAULT_MD5SUM
+	bool
+	default y
+config BUSYBOX_DEFAULT_MKDIR
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MKDIR_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKFIFO
+	bool
+	default y
+config BUSYBOX_DEFAULT_MKNOD
+	bool
+	default y
+config BUSYBOX_DEFAULT_MV
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MV_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_NICE
+	bool
+	default y
+config BUSYBOX_DEFAULT_NOHUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_OD
+	bool
+	default n
+config BUSYBOX_DEFAULT_PRINTENV
+	bool
+	default n
+config BUSYBOX_DEFAULT_PRINTF
+	bool
+	default y
+config BUSYBOX_DEFAULT_PWD
+	bool
+	default y
+config BUSYBOX_DEFAULT_READLINK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_READLINK_FOLLOW
+	bool
+	default y
+config BUSYBOX_DEFAULT_REALPATH
+	bool
+	default n
+config BUSYBOX_DEFAULT_RM
+	bool
+	default y
+config BUSYBOX_DEFAULT_RMDIR
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_RMDIR_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SEQ
+	bool
+	default y
+config BUSYBOX_DEFAULT_SHA1SUM
+	bool
+	default n
+config BUSYBOX_DEFAULT_SHA256SUM
+	bool
+	default y
+config BUSYBOX_DEFAULT_SHA512SUM
+	bool
+	default n
+config BUSYBOX_DEFAULT_SHA3SUM
+	bool
+	default n
+config BUSYBOX_DEFAULT_SLEEP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FANCY_SLEEP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FLOAT_SLEEP
+	bool
+	default n
+config BUSYBOX_DEFAULT_SORT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SORT_BIG
+	bool
+	default n
+config BUSYBOX_DEFAULT_SPLIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SPLIT_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_STTY
+	bool
+	default n
+config BUSYBOX_DEFAULT_SUM
+	bool
+	default n
+config BUSYBOX_DEFAULT_TAC
+	bool
+	default n
+config BUSYBOX_DEFAULT_TAIL
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FANCY_TAIL
+	bool
+	default y
+config BUSYBOX_DEFAULT_TEE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TEE_USE_BLOCK_IO
+	bool
+	default y
+config BUSYBOX_DEFAULT_TRUE
+	bool
+	default y
+config BUSYBOX_DEFAULT_TTY
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNAME
+	bool
+	default y
+config BUSYBOX_DEFAULT_UNAME_OSNAME
+	string
+	default "GNU/Linux"
+config BUSYBOX_DEFAULT_UNEXPAND
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_UNEXPAND_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNIQ
+	bool
+	default y
+config BUSYBOX_DEFAULT_USLEEP
+	bool
+	default n
+config BUSYBOX_DEFAULT_UUDECODE
+	bool
+	default n
+config BUSYBOX_DEFAULT_UUENCODE
+	bool
+	default n
+config BUSYBOX_DEFAULT_WC
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_WC_LARGE
+	bool
+	default n
+config BUSYBOX_DEFAULT_WHOAMI
+	bool
+	default n
+config BUSYBOX_DEFAULT_YES
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VERBOSE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PRESERVE_HARDLINKS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_AUTOWIDTH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_HUMAN_READABLE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MD5_SHA1_SUM_CHECK
+	bool
+	default y
+config BUSYBOX_DEFAULT_CHVT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FGCONSOLE
+	bool
+	default n
+config BUSYBOX_DEFAULT_CLEAR
+	bool
+	default y
+config BUSYBOX_DEFAULT_DEALLOCVT
+	bool
+	default n
+config BUSYBOX_DEFAULT_DUMPKMAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_KBD_MODE
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOADFONT
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOADKMAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_OPENVT
+	bool
+	default n
+config BUSYBOX_DEFAULT_RESET
+	bool
+	default y
+config BUSYBOX_DEFAULT_RESIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_RESIZE_PRINT
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETCONSOLE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SETCONSOLE_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETFONT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SETFONT_TEXTUAL_MAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEFAULT_SETFONT_DIR
+	string
+	default ""
+config BUSYBOX_DEFAULT_SETKEYCODES
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETLOGCONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SHOWKEY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LOADFONT_PSF2
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LOADFONT_RAW
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKTEMP
+	bool
+	default y
+config BUSYBOX_DEFAULT_PIPE_PROGRESS
+	bool
+	default n
+config BUSYBOX_DEFAULT_RUN_PARTS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_RUN_PARTS_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_RUN_PARTS_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_START_STOP_DAEMON
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_START_STOP_DAEMON_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_WHICH
+	bool
+	default y
+config BUSYBOX_DEFAULT_AWK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_AWK_LIBM
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_AWK_GNU_EXTENSIONS
+	bool
+	default y
+config BUSYBOX_DEFAULT_CMP
+	bool
+	default y
+config BUSYBOX_DEFAULT_DIFF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DIFF_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DIFF_DIR
+	bool
+	default n
+config BUSYBOX_DEFAULT_ED
+	bool
+	default n
+config BUSYBOX_DEFAULT_PATCH
+	bool
+	default n
+config BUSYBOX_DEFAULT_SED
+	bool
+	default y
+config BUSYBOX_DEFAULT_VI
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_MAX_LEN
+	int
+	default 1024
+config BUSYBOX_DEFAULT_FEATURE_VI_8BIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VI_COLON
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_YANKMARK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_SEARCH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_REGEX_SEARCH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VI_USE_SIGNALS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_DOT_CMD
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_READONLY
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_SETOPTS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_SET
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_WIN_RESIZE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_ASK_TERMINAL
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_VI_UNDO
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VI_UNDO_QUEUE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VI_UNDO_QUEUE_MAX
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_ALLOW_EXEC
+	bool
+	default y
+config BUSYBOX_DEFAULT_FIND
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_PRINT0
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_MTIME
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_MMIN
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FIND_PERM
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_TYPE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_XDEV
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_MAXDEPTH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_NEWER
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FIND_INUM
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FIND_EXEC
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_EXEC_PLUS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FIND_USER
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_GROUP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_NOT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_DEPTH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_PAREN
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_SIZE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_PRUNE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_DELETE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FIND_PATH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_REGEX
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FIND_CONTEXT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FIND_LINKS
+	bool
+	default n
+config BUSYBOX_DEFAULT_GREP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_GREP_EGREP_ALIAS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_GREP_FGREP_ALIAS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_GREP_CONTEXT
+	bool
+	default y
+config BUSYBOX_DEFAULT_XARGS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_CONFIRMATION
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_QUOTES
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_TERMOPT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_ZERO_TERM
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_REPL_STR
+	bool
+	default n
+config BUSYBOX_DEFAULT_BOOTCHARTD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BOOTCHARTD_BLOATED_HEADER
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BOOTCHARTD_CONFIG_FILE
+	bool
+	default n
+config BUSYBOX_DEFAULT_HALT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_CALL_TELINIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_TELINIT_PATH
+	string
+	default ""
+config BUSYBOX_DEFAULT_INIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_LINUXRC
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_USE_INITTAB
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_KILL_REMOVED
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_KILL_DELAY
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_INIT_SCTTY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INIT_SYSLOG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EXTRA_QUIET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INIT_COREDUMPS
+	bool
+	default n
+config BUSYBOX_DEFAULT_INIT_TERMINAL_TYPE
+	string
+	default ""
+config BUSYBOX_DEFAULT_FEATURE_INIT_MODIFY_CMDLINE
+	bool
+	default n
+config BUSYBOX_DEFAULT_MESG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MESG_ENABLE_ONLY_GROUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SHADOWPASSWDS
+	bool
+	default y
+config BUSYBOX_DEFAULT_USE_BB_PWD_GRP
+	bool
+	default n
+config BUSYBOX_DEFAULT_USE_BB_SHADOW
+	bool
+	default n
+config BUSYBOX_DEFAULT_USE_BB_CRYPT
+	bool
+	default n
+config BUSYBOX_DEFAULT_USE_BB_CRYPT_SHA
+	bool
+	default n
+config BUSYBOX_DEFAULT_ADD_SHELL
+	bool
+	default n
+config BUSYBOX_DEFAULT_REMOVE_SHELL
+	bool
+	default n
+config BUSYBOX_DEFAULT_ADDGROUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_ADDGROUP_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_ADDUSER_TO_GROUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_ADDUSER
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_ADDUSER_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHECK_NAMES
+	bool
+	default n
+config BUSYBOX_DEFAULT_LAST_ID
+	int
+	default 0
+config BUSYBOX_DEFAULT_FIRST_SYSTEM_ID
+	int
+	default 0
+config BUSYBOX_DEFAULT_LAST_SYSTEM_ID
+	int
+	default 0
+config BUSYBOX_DEFAULT_CHPASSWD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DEFAULT_PASSWD_ALGO
+	string
+	default "md5"
+config BUSYBOX_DEFAULT_CRYPTPW
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKPASSWD
+	bool
+	default n
+config BUSYBOX_DEFAULT_DELUSER
+	bool
+	default n
+config BUSYBOX_DEFAULT_DELGROUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DEL_USER_FROM_GROUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_GETTY
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOGIN
+	bool
+	default y
+config BUSYBOX_DEFAULT_LOGIN_SESSION_AS_CHILD
+	bool
+	default y
+config BUSYBOX_DEFAULT_LOGIN_SCRIPTS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_NOLOGIN
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SECURETTY
+	bool
+	default n
+config BUSYBOX_DEFAULT_PASSWD
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_PASSWD_WEAK_CHECK
+	bool
+	default y
+config BUSYBOX_DEFAULT_SU
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SU_SYSLOG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SU_CHECKS_SHELLS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SULOGIN
+	bool
+	default n
+config BUSYBOX_DEFAULT_VLOCK
+	bool
+	default n
+config BUSYBOX_DEFAULT_CHATTR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FSCK
+	bool
+	default n
+config BUSYBOX_DEFAULT_LSATTR
+	bool
+	default n
+config BUSYBOX_DEFAULT_TUNE2FS
+	bool
+	default n
+config BUSYBOX_DEFAULT_MODINFO
+	bool
+	default n
+config BUSYBOX_DEFAULT_MODPROBE_SMALL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
+	bool
+	default n
+config BUSYBOX_DEFAULT_INSMOD
+	bool
+	default n
+config BUSYBOX_DEFAULT_RMMOD
+	bool
+	default n
+config BUSYBOX_DEFAULT_LSMOD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+	bool
+	default n
+config BUSYBOX_DEFAULT_MODPROBE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MODPROBE_BLACKLIST
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEPMOD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_2_4_MODULES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSMOD_TRY_MMAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSMOD_VERSION_CHECKING
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSMOD_LOADINKMEM
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSMOD_LOAD_MAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INSMOD_LOAD_MAP_FULL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHECK_TAINTED_MODULE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MODUTILS_ALIAS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MODUTILS_SYMBOLS
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEFAULT_MODULES_DIR
+	string
+	default ""
+config BUSYBOX_DEFAULT_DEFAULT_DEPMOD_FILE
+	string
+	default ""
+config BUSYBOX_DEFAULT_BLKDISCARD
+	bool
+	default n
+config BUSYBOX_DEFAULT_BLOCKDEV
+	bool
+	default n
+config BUSYBOX_DEFAULT_FATATTR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FSTRIM
+	bool
+	default n
+config BUSYBOX_DEFAULT_MDEV
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MDEV_CONF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MDEV_RENAME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MDEV_RENAME_REGEXP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MDEV_EXEC
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MDEV_LOAD_FIRMWARE
+	bool
+	default n
+config BUSYBOX_DEFAULT_MOUNT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_FAKE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_VERBOSE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_HELPERS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_LABEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_NFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_CIFS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_FLAGS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_FSTAB
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_OTHERTAB
+	bool
+	default n
+config BUSYBOX_DEFAULT_NSENTER
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_NSENTER_LONG_OPTS
+	bool
+	default n
+config BUSYBOX_DEFAULT_REV
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETARCH
+	bool
+	default n
+config BUSYBOX_DEFAULT_UEVENT
+	bool
+	default n
+config BUSYBOX_DEFAULT_UNSHARE
+	bool
+	default n
+config BUSYBOX_DEFAULT_ACPID
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_ACPID_COMPAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_BLKID
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BLKID_TYPE
+	bool
+	default n
+config BUSYBOX_DEFAULT_DMESG
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_DMESG_PRETTY
+	bool
+	default y
+config BUSYBOX_DEFAULT_FBSET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FBSET_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FBSET_READMODE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FDFLUSH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FDFORMAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FDISK
+	bool
+	default n
+config BUSYBOX_DEFAULT_FDISK_SUPPORT_LARGE_DISKS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FDISK_WRITABLE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_AIX_LABEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SGI_LABEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SUN_LABEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_OSF_LABEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_GPT_LABEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FDISK_ADVANCED
+	bool
+	default n
+config BUSYBOX_DEFAULT_FINDFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FLOCK
+	bool
+	default n
+config BUSYBOX_DEFAULT_FREERAMDISK
+	bool
+	default n
+config BUSYBOX_DEFAULT_FSCK_MINIX
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKFS_EXT2
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKFS_MINIX
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MINIX2
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKFS_REISER
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKFS_VFAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_GETOPT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_GETOPT_LONG
+	bool
+	default n
+config BUSYBOX_DEFAULT_HEXDUMP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_HEXDUMP_REVERSE
+	bool
+	default n
+config BUSYBOX_DEFAULT_HD
+	bool
+	default n
+config BUSYBOX_DEFAULT_HWCLOCK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_HWCLOCK_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HWCLOCK_ADJTIME_FHS
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPCRM
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPCS
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOSETUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_LSPCI
+	bool
+	default n
+config BUSYBOX_DEFAULT_LSUSB
+	bool
+	default n
+config BUSYBOX_DEFAULT_MKSWAP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MKSWAP_UUID
+	bool
+	default n
+config BUSYBOX_DEFAULT_MORE
+	bool
+	default n
+config BUSYBOX_DEFAULT_PIVOT_ROOT
+	bool
+	default y
+config BUSYBOX_DEFAULT_RDATE
+	bool
+	default n
+config BUSYBOX_DEFAULT_RDEV
+	bool
+	default n
+config BUSYBOX_DEFAULT_READPROFILE
+	bool
+	default n
+config BUSYBOX_DEFAULT_RTCWAKE
+	bool
+	default n
+config BUSYBOX_DEFAULT_SCRIPT
+	bool
+	default n
+config BUSYBOX_DEFAULT_SCRIPTREPLAY
+	bool
+	default n
+config BUSYBOX_DEFAULT_SWAPONOFF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SWAPON_DISCARD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SWAPON_PRI
+	bool
+	default n
+config BUSYBOX_DEFAULT_SWITCH_ROOT
+	bool
+	default y
+config BUSYBOX_DEFAULT_UMOUNT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_UMOUNT_ALL
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_LOOP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_MOUNT_LOOP_CREATE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MTAB_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_VOLUMEID
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_BCACHE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_BTRFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_CRAMFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_EXFAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_EXT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_F2FS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_FAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_HFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_ISO9660
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_JFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_LINUXRAID
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_LINUXSWAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_LUKS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_NILFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_NTFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_OCFS2
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_REISERFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_ROMFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_SQUASHFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_SYSV
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_UDF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_VOLUMEID_XFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_CONSPY
+	bool
+	default n
+config BUSYBOX_DEFAULT_CROND
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_CROND_D
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CROND_CALL_SENDMAIL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CROND_DIR
+	string
+	default "/etc"
+config BUSYBOX_DEFAULT_I2CGET
+	bool
+	default n
+config BUSYBOX_DEFAULT_I2CSET
+	bool
+	default n
+config BUSYBOX_DEFAULT_I2CDUMP
+	bool
+	default n
+config BUSYBOX_DEFAULT_I2CDETECT
+	bool
+	default n
+config BUSYBOX_DEFAULT_LESS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_LESS_MAXLINES
+	int
+	default 9999999
+config BUSYBOX_DEFAULT_FEATURE_LESS_BRACKETS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_FLAGS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_TRUNCATE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_MARKS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_REGEXP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_WINCH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_ASK_TERMINAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_DASHCMD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LESS_LINENUMS
+	bool
+	default n
+config BUSYBOX_DEFAULT_NANDWRITE
+	bool
+	default n
+config BUSYBOX_DEFAULT_NANDDUMP
+	bool
+	default n
+config BUSYBOX_DEFAULT_RFKILL
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETSERIAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_TASKSET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TASKSET_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIATTACH
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIDETACH
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIMKVOL
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIRMVOL
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIRSVOL
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIUPDATEVOL
+	bool
+	default n
+config BUSYBOX_DEFAULT_UBIRENAME
+	bool
+	default n
+config BUSYBOX_DEFAULT_WALL
+	bool
+	default n
+config BUSYBOX_DEFAULT_ADJTIMEX
+	bool
+	default n
+config BUSYBOX_DEFAULT_BBCONFIG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_COMPRESS_BBCONFIG
+	bool
+	default n
+config BUSYBOX_DEFAULT_BEEP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BEEP_FREQ
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_BEEP_LENGTH_MS
+	int
+	default 0
+config BUSYBOX_DEFAULT_CHAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_NOFAIL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_TTY_HIFI
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_IMPLICIT_CR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_SWALLOW_OPTS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_SEND_ESCAPES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_VAR_ABORT_LEN
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHAT_CLR_ABORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_CHRT
+	bool
+	default n
+config BUSYBOX_DEFAULT_CRONTAB
+	bool
+	default y
+config BUSYBOX_DEFAULT_DC
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DC_LIBM
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEVFSD
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEVFSD_MODLOAD
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEVFSD_FG_NP
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEVFSD_VERBOSE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_DEVFS
+	bool
+	default n
+config BUSYBOX_DEFAULT_DEVMEM
+	bool
+	default n
+config BUSYBOX_DEFAULT_EJECT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_EJECT_SCSI
+	bool
+	default n
+config BUSYBOX_DEFAULT_FBSPLASH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FLASHCP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FLASH_LOCK
+	bool
+	default n
+config BUSYBOX_DEFAULT_FLASH_UNLOCK
+	bool
+	default n
+config BUSYBOX_DEFAULT_FLASH_ERASEALL
+	bool
+	default n
+config BUSYBOX_DEFAULT_IONICE
+	bool
+	default n
+config BUSYBOX_DEFAULT_INOTIFYD
+	bool
+	default n
+config BUSYBOX_DEFAULT_LAST
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LAST_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_HDPARM
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HDPARM_GET_IDENTITY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_SCAN_HWIF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_DRIVE_RESET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_GETSET_DMA
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOCK
+	bool
+	default y
+config BUSYBOX_DEFAULT_MAKEDEVS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MAKEDEVS_LEAF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MAKEDEVS_TABLE
+	bool
+	default n
+config BUSYBOX_DEFAULT_MAN
+	bool
+	default n
+config BUSYBOX_DEFAULT_MICROCOM
+	bool
+	default n
+config BUSYBOX_DEFAULT_MOUNTPOINT
+	bool
+	default n
+config BUSYBOX_DEFAULT_MT
+	bool
+	default n
+config BUSYBOX_DEFAULT_RAIDAUTORUN
+	bool
+	default n
+config BUSYBOX_DEFAULT_READAHEAD
+	bool
+	default n
+config BUSYBOX_DEFAULT_RUNLEVEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_RX
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETSID
+	bool
+	default n
+config BUSYBOX_DEFAULT_STRINGS
+	bool
+	default y
+config BUSYBOX_DEFAULT_TIME
+	bool
+	default y
+config BUSYBOX_DEFAULT_TIMEOUT
+	bool
+	default n
+config BUSYBOX_DEFAULT_TTYSIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_VOLNAME
+	bool
+	default n
+config BUSYBOX_DEFAULT_WATCHDOG
+	bool
+	default n
+config BUSYBOX_DEFAULT_NAMEIF
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_NAMEIF_EXTENDED
+	bool
+	default n
+config BUSYBOX_DEFAULT_NBDCLIENT
+	bool
+	default n
+config BUSYBOX_DEFAULT_NC
+	bool
+	default y
+config BUSYBOX_DEFAULT_NC_SERVER
+	bool
+	default n
+config BUSYBOX_DEFAULT_NC_EXTRA
+	bool
+	default n
+config BUSYBOX_DEFAULT_NC_110_COMPAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_PING
+	bool
+	default y
+config BUSYBOX_DEFAULT_PING6
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_FANCY_PING
+	bool
+	default y
+config BUSYBOX_DEFAULT_WGET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WGET_STATUSBAR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WGET_AUTHENTICATION
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WGET_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WGET_TIMEOUT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WGET_OPENSSL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_WGET_SSL_HELPER
+	bool
+	default n
+config BUSYBOX_DEFAULT_WHOIS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IPV6
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_UNIX_LOCAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PREFER_IPV4_ADDRESS
+	bool
+	default y
+config BUSYBOX_DEFAULT_VERBOSE_RESOLUTION_ERRORS
+	bool
+	default y
+config BUSYBOX_DEFAULT_ARP
+	bool
+	default n
+config BUSYBOX_DEFAULT_ARPING
+	bool
+	default n
+config BUSYBOX_DEFAULT_BRCTL
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_BRCTL_FANCY
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_BRCTL_SHOW
+	bool
+	default y
+config BUSYBOX_DEFAULT_DNSD
+	bool
+	default n
+config BUSYBOX_DEFAULT_ETHER_WAKE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FAKEIDENTD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FTPD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FTP_WRITE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FTPD_ACCEPT_BROKEN_LIST
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FTP_AUTHENTICATION
+	bool
+	default n
+config BUSYBOX_DEFAULT_FTPGET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FTPPUT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_FTPGETPUT_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_HOSTNAME
+	bool
+	default n
+config BUSYBOX_DEFAULT_HTTPD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_RANGES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_SETUID
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_BASIC_AUTH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_AUTH_MD5
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_CGI
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_ENCODE_URL_STR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_ERROR_PAGES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_PROXY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_HTTPD_GZIP
+	bool
+	default n
+config BUSYBOX_DEFAULT_IFCONFIG
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IFCONFIG_STATUS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IFCONFIG_SLIP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFCONFIG_HW
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IFCONFIG_BROADCAST_PLUS
+	bool
+	default y
+config BUSYBOX_DEFAULT_IFENSLAVE
+	bool
+	default n
+config BUSYBOX_DEFAULT_IFPLUGD
+	bool
+	default n
+config BUSYBOX_DEFAULT_IFUPDOWN
+	bool
+	default n
+config BUSYBOX_DEFAULT_IFUPDOWN_IFSTATE_PATH
+	string
+	default ""
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IP_BUILTIN
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IPV4
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IPV6
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_MAPPING
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_EXTERNAL_DHCP
+	bool
+	default n
+config BUSYBOX_DEFAULT_INETD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_TIME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_INETD_RPC
+	bool
+	default n
+config BUSYBOX_DEFAULT_IP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IP_ADDRESS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IP_LINK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IP_ROUTE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IP_ROUTE_DIR
+	string
+	default "/etc/iproute2"
+config BUSYBOX_DEFAULT_FEATURE_IP_TUNNEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IP_RULE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_IP_NEIGH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IP_SHORT_FORMS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IP_RARE_PROTOCOLS
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPADDR
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPLINK
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPROUTE
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPTUNNEL
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPRULE
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPNEIGH
+	bool
+	default n
+config BUSYBOX_DEFAULT_IPCALC
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IPCALC_FANCY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IPCALC_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_NETMSG
+	bool
+	default y
+config BUSYBOX_DEFAULT_NETSTAT
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_NETSTAT_WIDE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_NETSTAT_PRG
+	bool
+	default y
+config BUSYBOX_DEFAULT_NSLOOKUP
+	bool
+	default y
+config BUSYBOX_DEFAULT_NTPD
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_NTPD_SERVER
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_NTPD_CONF
+	bool
+	default n
+config BUSYBOX_DEFAULT_PSCAN
+	bool
+	default n
+config BUSYBOX_DEFAULT_ROUTE
+	bool
+	default y
+config BUSYBOX_DEFAULT_SLATTACH
+	bool
+	default n
+config BUSYBOX_DEFAULT_TCPSVD
+	bool
+	default n
+config BUSYBOX_DEFAULT_TELNET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TELNET_TTYPE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TELNET_AUTOLOGIN
+	bool
+	default n
+config BUSYBOX_DEFAULT_TELNETD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TELNETD_STANDALONE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TELNETD_INETD_WAIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_TFTP
+	bool
+	default n
+config BUSYBOX_DEFAULT_TFTPD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TFTP_GET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TFTP_PUT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TFTP_BLOCKSIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TFTP_PROGRESS_BAR
+	bool
+	default n
+config BUSYBOX_DEFAULT_TFTP_DEBUG
+	bool
+	default n
+config BUSYBOX_DEFAULT_TRACEROUTE
+	bool
+	default y
+config BUSYBOX_DEFAULT_TRACEROUTE6
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TRACEROUTE_VERBOSE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TRACEROUTE_SOURCE_ROUTE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TRACEROUTE_USE_ICMP
+	bool
+	default n
+config BUSYBOX_DEFAULT_TUNCTL
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TUNCTL_UG
+	bool
+	default n
+config BUSYBOX_DEFAULT_UDHCPC6
+	bool
+	default n
+config BUSYBOX_DEFAULT_UDHCPD
+	bool
+	default n
+config BUSYBOX_DEFAULT_DHCPRELAY
+	bool
+	default n
+config BUSYBOX_DEFAULT_DUMPLEASES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_UDHCPD_WRITE_LEASES_EARLY
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_UDHCPD_BASE_IP_ON_MAC
+	bool
+	default n
+config BUSYBOX_DEFAULT_DHCPD_LEASES_FILE
+	string
+	default ""
+config BUSYBOX_DEFAULT_UDHCPC
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_UDHCPC_ARPING
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_UDHCPC_SANITIZEOPT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_UDHCP_PORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_UDHCP_DEBUG
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_UDHCP_RFC3397
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_UDHCP_8021Q
+	bool
+	default n
+config BUSYBOX_DEFAULT_UDHCPC_DEFAULT_SCRIPT
+	string
+	default "/usr/share/udhcpc/default.script"
+config BUSYBOX_DEFAULT_UDHCPC_SLACK_FOR_BUGGY_SERVERS
+	int
+	default 80
+config BUSYBOX_DEFAULT_IFUPDOWN_UDHCPC_CMD_OPTIONS
+	string
+	default ""
+config BUSYBOX_DEFAULT_UDPSVD
+	bool
+	default n
+config BUSYBOX_DEFAULT_VCONFIG
+	bool
+	default n
+config BUSYBOX_DEFAULT_ZCIP
+	bool
+	default n
+config BUSYBOX_DEFAULT_LPD
+	bool
+	default n
+config BUSYBOX_DEFAULT_LPR
+	bool
+	default n
+config BUSYBOX_DEFAULT_LPQ
+	bool
+	default n
+config BUSYBOX_DEFAULT_MAKEMIME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_MIME_CHARSET
+	string
+	default ""
+config BUSYBOX_DEFAULT_POPMAILDIR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_POPMAILDIR_DELIVERY
+	bool
+	default n
+config BUSYBOX_DEFAULT_REFORMIME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_REFORMIME_COMPAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_SENDMAIL
+	bool
+	default n
+config BUSYBOX_DEFAULT_IOSTAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_LSOF
+	bool
+	default n
+config BUSYBOX_DEFAULT_MPSTAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_NMETER
+	bool
+	default n
+config BUSYBOX_DEFAULT_PMAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_POWERTOP
+	bool
+	default n
+config BUSYBOX_DEFAULT_PSTREE
+	bool
+	default n
+config BUSYBOX_DEFAULT_PWDX
+	bool
+	default n
+config BUSYBOX_DEFAULT_SMEMCAP
+	bool
+	default n
+config BUSYBOX_DEFAULT_TOP
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TOP_CPU_USAGE_PERCENTAGE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TOP_CPU_GLOBAL_PERCENTS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_TOP_SMP_CPU
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TOP_DECIMALS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TOP_SMP_PROCESS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_TOPMEM
+	bool
+	default n
+config BUSYBOX_DEFAULT_UPTIME
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_UPTIME_UTMP_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_FREE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FUSER
+	bool
+	default n
+config BUSYBOX_DEFAULT_KILL
+	bool
+	default y
+config BUSYBOX_DEFAULT_KILLALL
+	bool
+	default y
+config BUSYBOX_DEFAULT_KILLALL5
+	bool
+	default n
+config BUSYBOX_DEFAULT_PGREP
+	bool
+	default y
+config BUSYBOX_DEFAULT_PIDOF
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_PIDOF_SINGLE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PIDOF_OMIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_PKILL
+	bool
+	default n
+config BUSYBOX_DEFAULT_PS
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_PS_WIDE
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_PS_LONG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PS_TIME
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PS_ADDITIONAL_COLUMNS
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_PS_UNUSUAL_SYSTEMS
+	bool
+	default n
+config BUSYBOX_DEFAULT_RENICE
+	bool
+	default n
+config BUSYBOX_DEFAULT_BB_SYSCTL
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SHOW_THREADS
+	bool
+	default n
+config BUSYBOX_DEFAULT_WATCH
+	bool
+	default n
+config BUSYBOX_DEFAULT_CHPST
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETUIDGID
+	bool
+	default n
+config BUSYBOX_DEFAULT_ENVUIDGID
+	bool
+	default n
+config BUSYBOX_DEFAULT_ENVDIR
+	bool
+	default n
+config BUSYBOX_DEFAULT_SOFTLIMIT
+	bool
+	default n
+config BUSYBOX_DEFAULT_RUNSV
+	bool
+	default n
+config BUSYBOX_DEFAULT_RUNSVDIR
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_RUNSVDIR_LOG
+	bool
+	default n
+config BUSYBOX_DEFAULT_SV
+	bool
+	default n
+config BUSYBOX_DEFAULT_SV_DEFAULT_SERVICE_DIR
+	string
+	default ""
+config BUSYBOX_DEFAULT_SVLOGD
+	bool
+	default n
+config BUSYBOX_DEFAULT_CHCON
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_CHCON_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_GETENFORCE
+	bool
+	default n
+config BUSYBOX_DEFAULT_GETSEBOOL
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOAD_POLICY
+	bool
+	default n
+config BUSYBOX_DEFAULT_MATCHPATHCON
+	bool
+	default n
+config BUSYBOX_DEFAULT_RESTORECON
+	bool
+	default n
+config BUSYBOX_DEFAULT_RUNCON
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_RUNCON_LONG_OPTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_SELINUXENABLED
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETENFORCE
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETFILES
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SETFILES_CHECK_OPTION
+	bool
+	default n
+config BUSYBOX_DEFAULT_SETSEBOOL
+	bool
+	default n
+config BUSYBOX_DEFAULT_SESTATUS
+	bool
+	default n
+config BUSYBOX_DEFAULT_ASH
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_BASH_COMPAT
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_IDLE_TIMEOUT
+	bool
+	default n
+config BUSYBOX_DEFAULT_ASH_JOB_CONTROL
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_ALIAS
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_GETOPTS
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_BUILTIN_ECHO
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_BUILTIN_PRINTF
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_BUILTIN_TEST
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_HELP
+	bool
+	default n
+config BUSYBOX_DEFAULT_ASH_CMDCMD
+	bool
+	default y
+config BUSYBOX_DEFAULT_ASH_MAIL
+	bool
+	default n
+config BUSYBOX_DEFAULT_ASH_OPTIMIZE_FOR_SIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_ASH_RANDOM_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_ASH_EXPAND_PRMT
+	bool
+	default y
+config BUSYBOX_DEFAULT_CTTYHACK
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_BASH_COMPAT
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_BRACE_EXPANSION
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_HELP
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_INTERACTIVE
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_SAVEHISTORY
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_JOB
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_TICK
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_IF
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_LOOPS
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_CASE
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_FUNCTIONS
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_LOCAL
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_RANDOM_SUPPORT
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_EXPORT_N
+	bool
+	default n
+config BUSYBOX_DEFAULT_HUSH_MODE_X
+	bool
+	default n
+config BUSYBOX_DEFAULT_MSH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SH_IS_ASH
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SH_IS_HUSH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SH_IS_NONE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BASH_IS_ASH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BASH_IS_HUSH
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_BASH_IS_NONE
+	bool
+	default y
+config BUSYBOX_DEFAULT_SH_MATH_SUPPORT
+	bool
+	default y
+config BUSYBOX_DEFAULT_SH_MATH_SUPPORT_64
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SH_EXTRA_QUIET
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SH_STANDALONE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SH_NOFORK
+	bool
+	default y
+config BUSYBOX_DEFAULT_FEATURE_SH_HISTFILESIZE
+	bool
+	default n
+config BUSYBOX_DEFAULT_KLOGD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_KLOGD_KLOGCTL
+	bool
+	default n
+config BUSYBOX_DEFAULT_LOGGER
+	bool
+	default y
+config BUSYBOX_DEFAULT_LOGREAD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_LOGREAD_REDUCED_LOCKING
+	bool
+	default n
+config BUSYBOX_DEFAULT_SYSLOGD
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_ROTATE_LOGFILE
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_REMOTE_LOG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SYSLOGD_DUP
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SYSLOGD_CFG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_SYSLOGD_READ_BUFFER_SIZE
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_IPC_SYSLOG
+	bool
+	default n
+config BUSYBOX_DEFAULT_FEATURE_IPC_SYSLOG_BUFFER_SIZE
+	int
+	default 0
+config BUSYBOX_DEFAULT_FEATURE_KMSG_SYSLOG
+	bool
+	default n
diff --git a/package/utils/busybox/Config.in b/package/utils/busybox/Config.in
new file mode 100644
index 0000000000..917e714f6c
--- /dev/null
+++ b/package/utils/busybox/Config.in
@@ -0,0 +1,26 @@
+if PACKAGE_busybox
+
+config BUSYBOX_CUSTOM
+	bool "Customize busybox options"
+	default n
+        help
+          Enabling this allows full customization of busybox settings.
+          Note that there are many options here that can result in a build
+          that doesn't work properly.  Enabling customization will mark your
+          build as "tainted" for the purpose of bug reports.
+          See the variables written to /etc/openwrt_release
+
+          Unless you know what you are doing, you should leave this as 'n'
+
+	source "Config-defaults.in"
+
+	if BUSYBOX_CUSTOM
+	source "config/Config.in"
+	endif
+
+config BUSYBOX_USE_LIBRPC
+	bool
+	default y if BUSYBOX_CUSTOM && BUSYBOX_CONFIG_FEATURE_HAVE_RPC
+	default y if !BUSYBOX_CUSTOM && BUSYBOX_DEFAULT_FEATURE_HAVE_RPC
+
+endif
diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile
new file mode 100644
index 0000000000..b2935defcf
--- /dev/null
+++ b/package/utils/busybox/Makefile
@@ -0,0 +1,121 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=busybox
+PKG_VERSION:=1.25.1
+PKG_RELEASE:=2
+PKG_FLAGS:=essential
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=https://www.busybox.net/downloads \
+		http://sources.buildroot.net
+PKG_MD5SUM:=4f4c5de50b479b11ff636d7d8eb902a2
+
+PKG_BUILD_DEPENDS:=BUSYBOX_USE_LIBRPC:librpc BUSYBOX_CONFIG_PAM:libpam
+PKG_BUILD_PARALLEL:=1
+PKG_CHECK_FORMAT_SECURITY:=0
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=LICENSE archival/libarchive/bz/LICENSE
+
+include $(INCLUDE_DIR)/package.mk
+
+ifeq ($(DUMP),)
+  STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell $(SH_FUNC) grep '^CONFIG_BUSYBOX_' $(TOPDIR)/.config | md5s)
+endif
+
+ifneq ($(findstring c,$(OPENWRT_VERBOSE)),)
+  BB_MAKE_VERBOSE := V=1
+else
+  BB_MAKE_VERBOSE :=
+endif
+
+define Package/busybox
+  SECTION:=base
+  CATEGORY:=Base system
+  MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+  TITLE:=Core utilities for embedded Linux
+  URL:=http://busybox.net/
+  DEPENDS:=+BUSYBOX_USE_LIBRPC:librpc +BUSYBOX_CONFIG_PAM:libpam +BUSYBOX_CONFIG_NTPD:jsonfilter
+  MENU:=1
+endef
+
+define Package/busybox/description
+ The Swiss Army Knife of embedded Linux.
+ It slices, it dices, it makes Julian Fries.
+endef
+
+define Package/busybox/config
+	source "$(SOURCE)/Config.in"
+endef
+
+BUSYBOX_SYM=$(if $(CONFIG_BUSYBOX_CUSTOM),CONFIG,DEFAULT)
+
+# don't create a version string containing the actual timestamp
+export KCONFIG_NOTIMESTAMP=1
+
+define Build/Configure
+	rm -f $(PKG_BUILD_DIR)/.configured*
+	grep 'CONFIG_BUSYBOX_$(BUSYBOX_SYM)' $(TOPDIR)/.config | sed -e "s,\\(# \)\\?CONFIG_BUSYBOX_$(BUSYBOX_SYM)_\\(.*\\),\\1CONFIG_\\2,g" > $(PKG_BUILD_DIR)/.config
+	yes 'n' | $(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CROSS_COMPILE="$(TARGET_CROSS)" \
+		KBUILD_HAVE_NLS=no \
+		ARCH="$(ARCH)" \
+		$(BB_MAKE_VERBOSE) \
+		oldconfig
+endef
+
+LDLIBS:=m crypt
+ifdef CONFIG_BUSYBOX_USE_LIBRPC
+  TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+  export LDFLAGS=$(TARGET_LDFLAGS)
+  LDLIBS += rpc
+endif
+
+ifdef CONFIG_BUSYBOX_CONFIG_PAM
+  TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+  export LDFLAGS=$(TARGET_LDFLAGS)
+  LDLIBS += pam pam_misc pthread
+endif
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CROSS_COMPILE="$(TARGET_CROSS)" \
+		KBUILD_HAVE_NLS=no \
+		EXTRA_CFLAGS="$(TARGET_CFLAGS)" \
+		ARCH="$(ARCH)" \
+		SKIP_STRIP=y \
+		LDLIBS="$(LDLIBS)" \
+		$(BB_MAKE_VERBOSE) \
+		all
+	rm -rf $(PKG_INSTALL_DIR)
+	$(FIND) $(PKG_BUILD_DIR) -lname "*busybox" -exec rm \{\} \;
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CROSS_COMPILE="$(TARGET_CROSS)" \
+		EXTRA_CFLAGS="$(TARGET_CFLAGS)" \
+		ARCH="$(ARCH)" \
+		CONFIG_PREFIX="$(PKG_INSTALL_DIR)" \
+		LDLIBS="$(LDLIBS)" \
+		$(BB_MAKE_VERBOSE) \
+		install
+endef
+
+define Package/busybox/install
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
+	$(INSTALL_BIN) ./files/cron $(1)/etc/init.d/cron
+	$(INSTALL_BIN) ./files/sysntpd $(1)/etc/init.d/sysntpd
+	$(INSTALL_BIN) ./files/ntpd-hotplug $(1)/usr/sbin/ntpd-hotplug
+	-rm -rf $(1)/lib64
+endef
+
+$(eval $(call BuildPackage,busybox))
diff --git a/package/utils/busybox/config/Config.in b/package/utils/busybox/config/Config.in
new file mode 100644
index 0000000000..3bf67c5cf3
--- /dev/null
+++ b/package/utils/busybox/config/Config.in
@@ -0,0 +1,865 @@
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+
+config BUSYBOX_CONFIG_HAVE_DOT_CONFIG
+	bool
+	default BUSYBOX_DEFAULT_HAVE_DOT_CONFIG
+
+menu "Busybox Settings"
+
+menu "General Configuration"
+
+config BUSYBOX_CONFIG_DESKTOP
+	bool "Enable options for full-blown desktop systems"
+	default BUSYBOX_DEFAULT_DESKTOP
+	help
+	  Enable options and features which are not essential.
+	  Select this only if you plan to use busybox on full-blown
+	  desktop machine with common Linux distro, not on an embedded box.
+
+config BUSYBOX_CONFIG_EXTRA_COMPAT
+	bool "Provide compatible behavior for rare corner cases (bigger code)"
+	default BUSYBOX_DEFAULT_EXTRA_COMPAT
+	help
+	  This option makes grep, sed etc handle rare corner cases
+	  (embedded NUL bytes and such). This makes code bigger and uses
+	  some GNU extensions in libc. You probably only need this option
+	  if you plan to run busybox on desktop.
+
+config BUSYBOX_CONFIG_INCLUDE_SUSv2
+	bool "Enable obsolete features removed before SUSv3"
+	default BUSYBOX_DEFAULT_INCLUDE_SUSv2
+	help
+	  This option will enable backwards compatibility with SuSv2,
+	  specifically, old-style numeric options ('command -1 <file>')
+	  will be supported in head, tail, and fold. (Note: should
+	  affect renice too.)
+
+config BUSYBOX_CONFIG_USE_PORTABLE_CODE
+	bool "Avoid using GCC-specific code constructs"
+	default BUSYBOX_DEFAULT_USE_PORTABLE_CODE
+	help
+	  Use this option if you are trying to compile busybox with
+	  compiler other than gcc.
+	  If you do use gcc, this option may needlessly increase code size.
+
+config BUSYBOX_CONFIG_PLATFORM_LINUX
+	bool "Enable Linux-specific applets and features"
+	default BUSYBOX_DEFAULT_PLATFORM_LINUX
+	help
+	  For the most part, busybox requires only POSIX compatibility
+	  from the target system, but some applets and features use
+	  Linux-specific interfaces.
+
+	  Answering 'N' here will disable such applets and hide the
+	  corresponding configuration options.
+
+choice
+	prompt "Buffer allocation policy"
+	default BUSYBOX_CONFIG_FEATURE_BUFFERS_GO_ON_STACK
+	help
+	  There are 3 ways BusyBox can handle buffer allocations:
+	  - Use malloc. This costs code size for the call to xmalloc.
+	  - Put them on stack. For some very small machines with limited stack
+	    space, this can be deadly. For most folks, this works just fine.
+	  - Put them in BSS. This works beautifully for computers with a real
+	    MMU (and OS support), but wastes runtime RAM for uCLinux. This
+	    behavior was the only one available for BusyBox versions 0.48 and
+	    earlier.
+
+config BUSYBOX_CONFIG_FEATURE_BUFFERS_USE_MALLOC
+	bool "Allocate with Malloc"
+
+config BUSYBOX_CONFIG_FEATURE_BUFFERS_GO_ON_STACK
+	bool "Allocate on the Stack"
+
+config BUSYBOX_CONFIG_FEATURE_BUFFERS_GO_IN_BSS
+	bool "Allocate in the .bss section"
+
+endchoice
+
+config BUSYBOX_CONFIG_SHOW_USAGE
+	bool "Show applet usage messages"
+	default BUSYBOX_DEFAULT_SHOW_USAGE
+	help
+	  Enabling this option, BusyBox applets will show terse help messages
+	  when invoked with wrong arguments.
+	  If you do not want to show any (helpful) usage message when
+	  issuing wrong command syntax, you can say 'N' here,
+	  saving approximately 7k.
+
+config BUSYBOX_CONFIG_FEATURE_VERBOSE_USAGE
+	bool "Show verbose applet usage messages"
+	default BUSYBOX_DEFAULT_FEATURE_VERBOSE_USAGE
+	depends on BUSYBOX_CONFIG_SHOW_USAGE
+	help
+	  All BusyBox applets will show verbose help messages when
+	  busybox is invoked with --help. This will add a lot of text to the
+	  busybox binary. In the default configuration, this will add about
+	  13k, but it can add much more depending on your configuration.
+
+config BUSYBOX_CONFIG_FEATURE_COMPRESS_USAGE
+	bool "Store applet usage messages in compressed form"
+	default BUSYBOX_DEFAULT_FEATURE_COMPRESS_USAGE
+	depends on BUSYBOX_CONFIG_SHOW_USAGE
+	help
+	  Store usage messages in .bz compressed form, uncompress them
+	  on-the-fly when <applet> --help is called.
+
+	  If you have a really tiny busybox with few applets enabled (and
+	  bunzip2 isn't one of them), the overhead of the decompressor might
+	  be noticeable. Also, if you run executables directly from ROM
+	  and have very little memory, this might not be a win. Otherwise,
+	  you probably want this.
+
+config BUSYBOX_CONFIG_BUSYBOX
+	bool "Include busybox applet"
+	default BUSYBOX_DEFAULT_BUSYBOX
+	help
+	  The busybox applet provides general help regarding busybox and
+	  allows the included applets to be listed.  It's also required
+	  if applet links are to be installed at runtime.
+
+	  If you can live without these features disabling this will save
+	  some space.
+
+config BUSYBOX_CONFIG_FEATURE_INSTALLER
+	bool "Support --install [-s] to install applet links at runtime"
+	default BUSYBOX_DEFAULT_FEATURE_INSTALLER
+	depends on BUSYBOX_CONFIG_BUSYBOX
+	help
+	  Enable 'busybox --install [-s]' support. This will allow you to use
+	  busybox at runtime to create hard links or symlinks for all the
+	  applets that are compiled into busybox.
+
+config BUSYBOX_CONFIG_INSTALL_NO_USR
+	bool "Don't use /usr"
+	default BUSYBOX_DEFAULT_INSTALL_NO_USR
+	help
+	  Disable use of /usr. busybox --install and "make install"
+	  will install applets only to /bin and /sbin,
+	  never to /usr/bin or /usr/sbin.
+
+config BUSYBOX_CONFIG_LOCALE_SUPPORT
+	bool "Enable locale support (system needs locale for this to work)"
+	default BUSYBOX_DEFAULT_LOCALE_SUPPORT
+	help
+	  Enable this if your system has locale support and you would like
+	  busybox to support locale settings.
+
+config BUSYBOX_CONFIG_UNICODE_SUPPORT
+	bool "Support Unicode"
+	default BUSYBOX_DEFAULT_UNICODE_SUPPORT
+	help
+	  This makes various applets aware that one byte is not
+	  one character on screen.
+
+	  Busybox aims to eventually work correctly with Unicode displays.
+	  Any older encodings are not guaranteed to work.
+	  Probably by the time when busybox will be fully Unicode-clean,
+	  other encodings will be mainly of historic interest.
+
+config BUSYBOX_CONFIG_UNICODE_USING_LOCALE
+	bool "Use libc routines for Unicode (else uses internal ones)"
+	default BUSYBOX_DEFAULT_UNICODE_USING_LOCALE
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT && BUSYBOX_CONFIG_LOCALE_SUPPORT
+	help
+	  With this option on, Unicode support is implemented using libc
+	  routines. Otherwise, internal implementation is used.
+	  Internal implementation is smaller.
+
+config BUSYBOX_CONFIG_FEATURE_CHECK_UNICODE_IN_ENV
+	bool "Check $LC_ALL, $LC_CTYPE and $LANG environment variables"
+	default BUSYBOX_DEFAULT_FEATURE_CHECK_UNICODE_IN_ENV
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT && !BUSYBOX_CONFIG_UNICODE_USING_LOCALE
+	help
+	  With this option on, Unicode support is activated
+	  only if locale-related variables have the value of the form
+	  "xxxx.utf8"
+
+	  Otherwise, Unicode support will be always enabled and active.
+
+config BUSYBOX_CONFIG_SUBST_WCHAR
+	int "Character code to substitute unprintable characters with"
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT
+	default BUSYBOX_DEFAULT_SUBST_WCHAR
+	help
+	  Typical values are 63 for '?' (works with any output device),
+	  30 for ASCII substitute control code,
+	  65533 (0xfffd) for Unicode replacement character.
+
+config BUSYBOX_CONFIG_LAST_SUPPORTED_WCHAR
+	int "Range of supported Unicode characters"
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT
+	default BUSYBOX_DEFAULT_LAST_SUPPORTED_WCHAR
+	help
+	  Any character with Unicode value bigger than this is assumed
+	  to be non-printable on output device. Many applets replace
+	  such chars with substitution character.
+
+	  The idea is that many valid printable Unicode chars are
+	  nevertheless are not displayed correctly. Think about
+	  combining charachers, double-wide hieroglyphs, obscure
+	  characters in dozens of ancient scripts...
+	  Many terminals, terminal emulators, xterms etc will fail
+	  to handle them correctly. Choose the smallest value
+	  which suits your needs.
+
+	  Typical values are:
+	  126 - ASCII only
+	  767 (0x2ff) - there are no combining chars in [0..767] range
+			(the range includes Latin 1, Latin Ext. A and B),
+			code is ~700 bytes smaller for this case.
+	  4351 (0x10ff) - there are no double-wide chars in [0..4351] range,
+			code is ~300 bytes smaller for this case.
+	  12799 (0x31ff) - nearly all non-ideographic characters are
+			available in [0..12799] range, including
+			East Asian scripts like katakana, hiragana, hangul,
+			bopomofo...
+	  0 - off, any valid printable Unicode character will be printed.
+
+config BUSYBOX_CONFIG_UNICODE_COMBINING_WCHARS
+	bool "Allow zero-width Unicode characters on output"
+	default BUSYBOX_DEFAULT_UNICODE_COMBINING_WCHARS
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT
+	help
+	  With this option off, any Unicode char with width of 0
+	  is substituted on output.
+
+config BUSYBOX_CONFIG_UNICODE_WIDE_WCHARS
+	bool "Allow wide Unicode characters on output"
+	default BUSYBOX_DEFAULT_UNICODE_WIDE_WCHARS
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT
+	help
+	  With this option off, any Unicode char with width > 1
+	  is substituted on output.
+
+config BUSYBOX_CONFIG_UNICODE_BIDI_SUPPORT
+	bool "Bidirectional character-aware line input"
+	default BUSYBOX_DEFAULT_UNICODE_BIDI_SUPPORT
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT && !BUSYBOX_CONFIG_UNICODE_USING_LOCALE
+	help
+	  With this option on, right-to-left Unicode characters
+	  are treated differently on input (e.g. cursor movement).
+
+config BUSYBOX_CONFIG_UNICODE_NEUTRAL_TABLE
+	bool "In bidi input, support non-ASCII neutral chars too"
+	default BUSYBOX_DEFAULT_UNICODE_NEUTRAL_TABLE
+	depends on BUSYBOX_CONFIG_UNICODE_BIDI_SUPPORT
+	help
+	  In most cases it's enough to treat only ASCII non-letters
+	  (i.e. punctuation, numbers and space) as characters
+	  with neutral directionality.
+	  With this option on, more extensive (and bigger) table
+	  of neutral chars will be used.
+
+config BUSYBOX_CONFIG_UNICODE_PRESERVE_BROKEN
+	bool "Make it possible to enter sequences of chars which are not Unicode"
+	default BUSYBOX_DEFAULT_UNICODE_PRESERVE_BROKEN
+	depends on BUSYBOX_CONFIG_UNICODE_SUPPORT
+	help
+	  With this option on, on line-editing input (such as used by shells)
+	  invalid UTF-8 bytes are not substituted with the selected
+	  substitution character.
+	  For example, this means that entering 'l', 's', ' ', 0xff, [Enter]
+	  at shell prompt will list file named 0xff (single char name
+	  with char value 255), not file named '?'.
+
+config BUSYBOX_CONFIG_PAM
+	bool "Support for PAM (Pluggable Authentication Modules)"
+	default BUSYBOX_DEFAULT_PAM
+	help
+	  Use PAM in some busybox applets (currently login and httpd) instead
+	  of direct access to password database.
+
+config BUSYBOX_CONFIG_FEATURE_USE_SENDFILE
+	bool "Use sendfile system call"
+	default BUSYBOX_DEFAULT_FEATURE_USE_SENDFILE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  When enabled, busybox will use the kernel sendfile() function
+	  instead of read/write loops to copy data between file descriptors
+	  (for example, cp command does this a lot).
+	  If sendfile() doesn't work, copying code falls back to read/write
+	  loop. sendfile() was originally implemented for faster I/O
+	  from files to sockets, but since Linux 2.6.33 it was extended
+	  to work for many more file types.
+
+config BUSYBOX_CONFIG_LONG_OPTS
+	bool "Support for --long-options"
+	default BUSYBOX_DEFAULT_LONG_OPTS
+	help
+	  Enable this if you want busybox applets to use the gnu --long-option
+	  style, in addition to single character -a -b -c style options.
+
+config BUSYBOX_CONFIG_FEATURE_DEVPTS
+	bool "Use the devpts filesystem for Unix98 PTYs"
+	default BUSYBOX_DEFAULT_FEATURE_DEVPTS
+	help
+	  Enable if you want BusyBox to use Unix98 PTY support. If enabled,
+	  busybox will use /dev/ptmx for the master side of the pseudoterminal
+	  and /dev/pts/<number> for the slave side. Otherwise, BSD style
+	  /dev/ttyp<number> will be used. To use this option, you should have
+	  devpts mounted.
+
+config BUSYBOX_CONFIG_FEATURE_CLEAN_UP
+	bool "Clean up all memory before exiting (usually not needed)"
+	default BUSYBOX_DEFAULT_FEATURE_CLEAN_UP
+	help
+	  As a size optimization, busybox normally exits without explicitly
+	  freeing dynamically allocated memory or closing files. This saves
+	  space since the OS will clean up for us, but it can confuse debuggers
+	  like valgrind, which report tons of memory and resource leaks.
+
+	  Don't enable this unless you have a really good reason to clean
+	  things up manually.
+
+config BUSYBOX_CONFIG_FEATURE_UTMP
+	bool "Support utmp file"
+	default BUSYBOX_DEFAULT_FEATURE_UTMP
+	help
+	  The file /var/run/utmp is used to track who is currently logged in.
+	  With this option on, certain applets (getty, login, telnetd etc)
+	  will create and delete entries there.
+	  "who" applet requires this option.
+
+config BUSYBOX_CONFIG_FEATURE_WTMP
+	bool "Support wtmp file"
+	default BUSYBOX_DEFAULT_FEATURE_WTMP
+	depends on BUSYBOX_CONFIG_FEATURE_UTMP
+	help
+	  The file /var/run/wtmp is used to track when users have logged into
+	  and logged out of the system.
+	  With this option on, certain applets (getty, login, telnetd etc)
+	  will append new entries there.
+	  "last" applet requires this option.
+
+config BUSYBOX_CONFIG_FEATURE_PIDFILE
+	bool "Support writing pidfiles"
+	default BUSYBOX_DEFAULT_FEATURE_PIDFILE
+	help
+	  This option makes some applets (e.g. crond, syslogd, inetd) write
+	  a pidfile at the configured PID_FILE_PATH.  It has no effect
+	  on applets which require pidfiles to run.
+
+config BUSYBOX_CONFIG_PID_FILE_PATH
+	string "Path to directory for pidfile"
+	default BUSYBOX_DEFAULT_PID_FILE_PATH
+	depends on BUSYBOX_CONFIG_FEATURE_PIDFILE
+	help
+	  This is the default path where pidfiles are created.  Applets which
+	  allow you to set the pidfile path on the command line will override
+	  this value.  The option has no effect on applets that require you to
+	  specify a pidfile path.
+
+config BUSYBOX_CONFIG_FEATURE_SUID
+	bool "Support for SUID/SGID handling"
+	default BUSYBOX_DEFAULT_FEATURE_SUID
+	help
+	  With this option you can install the busybox binary belonging
+	  to root with the suid bit set, enabling some applets to perform
+	  root-level operations even when run by ordinary users
+	  (for example, mounting of user mounts in fstab needs this).
+
+	  Busybox will automatically drop privileges for applets
+	  that don't need root access.
+
+	  If you are really paranoid and don't want to do this, build two
+	  busybox binaries with different applets in them (and the appropriate
+	  symlinks pointing to each binary), and only set the suid bit on the
+	  one that needs it.
+
+	  The applets which require root rights (need suid bit or
+	  to be run by root) and will refuse to execute otherwise:
+	  crontab, login, passwd, su, vlock, wall.
+
+	  The applets which will use root rights if they have them
+	  (via suid bit, or because run by root), but would try to work
+	  without root right nevertheless:
+	  findfs, ping[6], traceroute[6], mount.
+
+	  Note that if you DONT select this option, but DO make busybox
+	  suid root, ALL applets will run under root, which is a huge
+	  security hole (think "cp /some/file /etc/passwd").
+
+config BUSYBOX_CONFIG_FEATURE_SUID_CONFIG
+	bool "Runtime SUID/SGID configuration via /etc/busybox.conf"
+	default BUSYBOX_DEFAULT_FEATURE_SUID_CONFIG
+	depends on BUSYBOX_CONFIG_FEATURE_SUID
+	help
+	  Allow the SUID / SGID state of an applet to be determined at runtime
+	  by checking /etc/busybox.conf. (This is sort of a poor man's sudo.)
+	  The format of this file is as follows:
+
+	  APPLET = [Ssx-][Ssx-][x-] [USER.GROUP]
+
+	  s: USER or GROUP is allowed to execute APPLET.
+	     APPLET will run under USER or GROUP
+	     (reagardless of who's running it).
+	  S: USER or GROUP is NOT allowed to execute APPLET.
+	     APPLET will run under USER or GROUP.
+	     This option is not very sensical.
+	  x: USER/GROUP/others are allowed to execute APPLET.
+	     No UID/GID change will be done when it is run.
+	  -: USER/GROUP/others are not allowed to execute APPLET.
+
+	  An example might help:
+
+	  [SUID]
+	  su = ssx root.0 # applet su can be run by anyone and runs with
+	                  # euid=0/egid=0
+	  su = ssx        # exactly the same
+
+	  mount = sx- root.disk # applet mount can be run by root and members
+	                        # of group disk (but not anyone else)
+	                        # and runs with euid=0 (egid is not changed)
+
+	  cp = --- # disable applet cp for everyone
+
+	  The file has to be owned by user root, group root and has to be
+	  writeable only by root:
+	        (chown 0.0 /etc/busybox.conf; chmod 600 /etc/busybox.conf)
+	  The busybox executable has to be owned by user root, group
+	  root and has to be setuid root for this to work:
+	        (chown 0.0 /bin/busybox; chmod 4755 /bin/busybox)
+
+	  Robert 'sandman' Griebl has more information here:
+	  <url: http://www.softforge.de/bb/suid.html >.
+
+config BUSYBOX_CONFIG_FEATURE_SUID_CONFIG_QUIET
+	bool "Suppress warning message if /etc/busybox.conf is not readable"
+	default BUSYBOX_DEFAULT_FEATURE_SUID_CONFIG_QUIET
+	depends on BUSYBOX_CONFIG_FEATURE_SUID_CONFIG
+	help
+	  /etc/busybox.conf should be readable by the user needing the SUID,
+	  check this option to avoid users to be notified about missing
+	  permissions.
+
+config BUSYBOX_CONFIG_SELINUX
+	bool "Support NSA Security Enhanced Linux"
+	default BUSYBOX_DEFAULT_SELINUX
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Enable support for SELinux in applets ls, ps, and id. Also provide
+	  the option of compiling in SELinux applets.
+
+	  If you do not have a complete SELinux userland installed, this stuff
+	  will not compile.  Specifially, libselinux 1.28 or better is
+	  directly required by busybox. If the installation is located in a
+	  non-standard directory, provide it by invoking make as follows:
+		CFLAGS=-I<libselinux-include-path> \
+		LDFLAGS=-L<libselinux-lib-path> \
+		make
+
+	  Most people will leave this set to 'N'.
+
+config BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS
+	bool "exec prefers applets"
+	default BUSYBOX_DEFAULT_FEATURE_PREFER_APPLETS
+	help
+	  This is an experimental option which directs applets about to
+	  call 'exec' to try and find an applicable busybox applet before
+	  searching the PATH. This is typically done by exec'ing
+	  /proc/self/exe.
+	  This may affect shell, find -exec, xargs and similar applets.
+	  They will use applets even if /bin/<applet> -> busybox link
+	  is missing (or is not a link to busybox). However, this causes
+	  problems in chroot jails without mounted /proc and with ps/top
+	  (command name can be shown as 'exe' for applets started this way).
+
+config BUSYBOX_CONFIG_BUSYBOX_EXEC_PATH
+	string "Path to BusyBox executable"
+	default BUSYBOX_DEFAULT_BUSYBOX_EXEC_PATH
+	help
+	  When Busybox applets need to run other busybox applets, BusyBox
+	  sometimes needs to exec() itself. When the /proc filesystem is
+	  mounted, /proc/self/exe always points to the currently running
+	  executable. If you haven't got /proc, set this to wherever you
+	  want to run BusyBox from.
+
+# These are auto-selected by other options
+
+config BUSYBOX_CONFIG_FEATURE_SYSLOG
+	bool #No description makes it a hidden option
+	default BUSYBOX_DEFAULT_FEATURE_SYSLOG
+	#help
+	#  This option is auto-selected when you select any applet which may
+	#  send its output to syslog. You do not need to select it manually.
+
+config BUSYBOX_CONFIG_FEATURE_HAVE_RPC
+	bool #No description makes it a hidden option
+	default BUSYBOX_DEFAULT_FEATURE_HAVE_RPC
+	#help
+	#  This is automatically selected if any of enabled applets need it.
+	#  You do not need to select it manually.
+
+endmenu
+
+menu 'Build Options'
+
+config BUSYBOX_CONFIG_STATIC
+	bool "Build BusyBox as a static binary (no shared libs)"
+	default BUSYBOX_DEFAULT_STATIC
+	help
+	  If you want to build a static BusyBox binary, which does not
+	  use or require any shared libraries, then enable this option.
+	  This can cause BusyBox to be considerably larger, so you should
+	  leave this option false unless you have a good reason (i.e.
+	  your target platform does not support shared libraries, or
+	  you are building an initrd which doesn't need anything but
+	  BusyBox, etc).
+
+	  Most people will leave this set to 'N'.
+
+config BUSYBOX_CONFIG_PIE
+	bool "Build BusyBox as a position independent executable"
+	default BUSYBOX_DEFAULT_PIE
+	depends on !BUSYBOX_CONFIG_STATIC
+	help
+	  Hardened code option. PIE binaries are loaded at a different
+	  address at each invocation. This has some overhead,
+	  particularly on x86-32 which is short on registers.
+
+	  Most people will leave this set to 'N'.
+
+config BUSYBOX_CONFIG_NOMMU
+	bool "Force NOMMU build"
+	default BUSYBOX_DEFAULT_NOMMU
+	help
+	  Busybox tries to detect whether architecture it is being
+	  built against supports MMU or not. If this detection fails,
+	  or if you want to build NOMMU version of busybox for testing,
+	  you may force NOMMU build here.
+
+	  Most people will leave this set to 'N'.
+
+# PIE can be made to work with BUILD_LIBBUSYBOX, but currently
+# build system does not support that
+config BUSYBOX_CONFIG_BUILD_LIBBUSYBOX
+	bool "Build shared libbusybox"
+	default BUSYBOX_DEFAULT_BUILD_LIBBUSYBOX
+	depends on !BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS && !BUSYBOX_CONFIG_PIE && !BUSYBOX_CONFIG_STATIC
+	help
+	  Build a shared library libbusybox.so.N.N.N which contains all
+	  busybox code.
+
+	  This feature allows every applet to be built as a tiny
+	  separate executable. Enabling it for "one big busybox binary"
+	  approach serves no purpose and increases code size.
+	  You should almost certainly say "no" to this.
+
+### config FEATURE_FULL_LIBBUSYBOX
+###	bool "Feature-complete libbusybox"
+###	default n if !FEATURE_SHARED_BUSYBOX
+###	depends on BUILD_LIBBUSYBOX
+###	help
+###	  Build a libbusybox with the complete feature-set, disregarding
+###	  the actually selected config.
+###
+###	  Normally, libbusybox will only contain the features which are
+###	  used by busybox itself. If you plan to write a separate
+###	  standalone application which uses libbusybox say 'Y'.
+###
+###	  Note: libbusybox is GPL, not LGPL, and exports no stable API that
+###	  might act as a copyright barrier. We can and will modify the
+###	  exported function set between releases (even minor version number
+###	  changes), and happily break out-of-tree features.
+###
+###	  Say 'N' if in doubt.
+
+config BUSYBOX_CONFIG_FEATURE_INDIVIDUAL
+	bool "Produce a binary for each applet, linked against libbusybox"
+	default BUSYBOX_DEFAULT_FEATURE_INDIVIDUAL
+	depends on BUSYBOX_CONFIG_BUILD_LIBBUSYBOX
+	help
+	  If your CPU architecture doesn't allow for sharing text/rodata
+	  sections of running binaries, but allows for runtime dynamic
+	  libraries, this option will allow you to reduce memory footprint
+	  when you have many different applets running at once.
+
+	  If your CPU architecture allows for sharing text/rodata,
+	  having single binary is more optimal.
+
+	  Each applet will be a tiny program, dynamically linked
+	  against libbusybox.so.N.N.N.
+
+	  You need to have a working dynamic linker.
+
+config BUSYBOX_CONFIG_FEATURE_SHARED_BUSYBOX
+	bool "Produce additional busybox binary linked against libbusybox"
+	default BUSYBOX_DEFAULT_FEATURE_SHARED_BUSYBOX
+	depends on BUSYBOX_CONFIG_BUILD_LIBBUSYBOX
+	help
+	  Build busybox, dynamically linked against libbusybox.so.N.N.N.
+
+	  You need to have a working dynamic linker.
+
+### config BUILD_AT_ONCE
+###	bool "Compile all sources at once"
+###	default n
+###	help
+###	  Normally each source-file is compiled with one invocation of
+###	  the compiler.
+###	  If you set this option, all sources are compiled at once.
+###	  This gives the compiler more opportunities to optimize which can
+###	  result in smaller and/or faster binaries.
+###
+###	  Setting this option will consume alot of memory, e.g. if you
+###	  enable all applets with all features, gcc uses more than 300MB
+###	  RAM during compilation of busybox.
+###
+###	  This option is most likely only beneficial for newer compilers
+###	  such as gcc-4.1 and above.
+###
+###	  Say 'N' unless you know what you are doing.
+
+config BUSYBOX_CONFIG_LFS
+	bool
+	default BUSYBOX_DEFAULT_LFS
+	help
+	  If you want to build BusyBox with large file support, then enable
+	  this option. This will have no effect if your kernel or your C
+	  library lacks large file support for large files. Some of the
+	  programs that can benefit from large file support include dd, gzip,
+	  cp, mount, tar, and many others. If you want to access files larger
+	  than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'.
+
+config BUSYBOX_CONFIG_CROSS_COMPILER_PREFIX
+	string "Cross Compiler prefix"
+	default BUSYBOX_DEFAULT_CROSS_COMPILER_PREFIX
+	help
+	  If you want to build BusyBox with a cross compiler, then you
+	  will need to set this to the cross-compiler prefix, for example,
+	  "i386-uclibc-".
+
+	  Note that CROSS_COMPILE environment variable or
+	  "make CROSS_COMPILE=xxx ..." will override this selection.
+
+	  Native builds leave this empty.
+
+config BUSYBOX_CONFIG_SYSROOT
+	string "Path to sysroot"
+	default BUSYBOX_DEFAULT_SYSROOT
+	help
+	  If you want to build BusyBox with a cross compiler, then you
+	  might also need to specify where /usr/include and /usr/lib
+	  will be found.
+
+	  For example, BusyBox can be built against an installed
+	  Android NDK, platform version 9, for ARM ABI with
+
+	  CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm
+
+	  Native builds leave this empty.
+
+config BUSYBOX_CONFIG_EXTRA_CFLAGS
+	string "Additional CFLAGS"
+	default BUSYBOX_DEFAULT_EXTRA_CFLAGS
+	help
+	  Additional CFLAGS to pass to the compiler verbatim.
+
+config BUSYBOX_CONFIG_EXTRA_LDFLAGS
+	string "Additional LDFLAGS"
+	default BUSYBOX_DEFAULT_EXTRA_LDFLAGS
+	help
+	  Additional LDFLAGS to pass to the linker verbatim.
+
+config BUSYBOX_CONFIG_EXTRA_LDLIBS
+	string "Additional LDLIBS"
+	default BUSYBOX_DEFAULT_EXTRA_LDLIBS
+	help
+	  Additional LDLIBS to pass to the linker with -l.
+
+endmenu
+
+menu 'Debugging Options'
+
+config BUSYBOX_CONFIG_DEBUG
+	bool "Build BusyBox with extra Debugging symbols"
+	default BUSYBOX_DEFAULT_DEBUG
+	help
+	  Say Y here if you wish to examine BusyBox internals while applets are
+	  running. This increases the size of the binary considerably, and
+	  should only be used when doing development. If you are doing
+	  development and want to debug BusyBox, answer Y.
+
+	  Most people should answer N.
+
+config BUSYBOX_CONFIG_DEBUG_PESSIMIZE
+	bool "Disable compiler optimizations"
+	default BUSYBOX_DEFAULT_DEBUG_PESSIMIZE
+	depends on BUSYBOX_CONFIG_DEBUG
+	help
+	  The compiler's optimization of source code can eliminate and reorder
+	  code, resulting in an executable that's hard to understand when
+	  stepping through it with a debugger. This switches it off, resulting
+	  in a much bigger executable that more closely matches the source
+	  code.
+
+config BUSYBOX_CONFIG_DEBUG_SANITIZE
+	bool "Enable runtime sanitizers (ASAN/LSAN/USAN/etc...)"
+	default BUSYBOX_DEFAULT_DEBUG_SANITIZE
+	help
+	  Say Y here if you want to enable runtime sanitizers. These help
+	  catch bad memory accesses (e.g. buffer overflows), but will make
+	  the executable larger and slow down runtime a bit.
+
+	  If you aren't developing/testing busybox, say N here.
+
+config BUSYBOX_CONFIG_UNIT_TEST
+	bool "Build unit tests"
+	default BUSYBOX_DEFAULT_UNIT_TEST
+	help
+	  Say Y here if you want to build unit tests (both the framework and
+	  test cases) as a Busybox applet. This results in bigger code, so you
+	  probably don't want this option in production builds.
+
+config BUSYBOX_CONFIG_WERROR
+	bool "Abort compilation on any warning"
+	default BUSYBOX_DEFAULT_WERROR
+	help
+	  Selecting this will add -Werror to gcc command line.
+
+	  Most people should answer N.
+
+choice
+	prompt "Additional debugging library"
+	default BUSYBOX_CONFIG_NO_DEBUG_LIB
+	help
+	  Using an additional debugging library will make BusyBox become
+	  considerable larger and will cause it to run more slowly. You
+	  should always leave this option disabled for production use.
+
+	  dmalloc support:
+	  ----------------
+	  This enables compiling with dmalloc ( http://dmalloc.com/ )
+	  which is an excellent public domain mem leak and malloc problem
+	  detector. To enable dmalloc, before running busybox you will
+	  want to properly set your environment, for example:
+	    export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile
+	  The 'debug=' value is generated using the following command
+	    dmalloc -p log-stats -p log-non-free -p log-bad-space \
+	       -p log-elapsed-time -p check-fence -p check-heap \
+	       -p check-lists -p check-blank -p check-funcs -p realloc-copy \
+	       -p allow-free-null
+
+	  Electric-fence support:
+	  -----------------------
+	  This enables compiling with Electric-fence support. Electric
+	  fence is another very useful malloc debugging library which uses
+	  your computer's virtual memory hardware to detect illegal memory
+	  accesses. This support will make BusyBox be considerable larger
+	  and run slower, so you should leave this option disabled unless
+	  you are hunting a hard to find memory problem.
+
+
+config BUSYBOX_CONFIG_NO_DEBUG_LIB
+	bool "None"
+
+config BUSYBOX_CONFIG_DMALLOC
+	bool "Dmalloc"
+
+config BUSYBOX_CONFIG_EFENCE
+	bool "Electric-fence"
+
+endchoice
+
+endmenu
+
+menu 'Installation Options ("make install" behavior)'
+
+choice
+	prompt "What kind of applet links to install"
+	default BUSYBOX_CONFIG_INSTALL_APPLET_SYMLINKS
+	help
+	  Choose what kind of links to applets are created by "make install".
+
+config BUSYBOX_CONFIG_INSTALL_APPLET_SYMLINKS
+	bool "as soft-links"
+	help
+	  Install applets as soft-links to the busybox binary. This needs some
+	  free inodes on the filesystem, but might help with filesystem
+	  generators that can't cope with hard-links.
+
+config BUSYBOX_CONFIG_INSTALL_APPLET_HARDLINKS
+	bool "as hard-links"
+	help
+	  Install applets as hard-links to the busybox binary. This might
+	  count on a filesystem with few inodes.
+
+config BUSYBOX_CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS
+	bool "as script wrappers"
+	help
+	  Install applets as script wrappers that call the busybox binary.
+
+config BUSYBOX_CONFIG_INSTALL_APPLET_DONT
+	bool "not installed"
+	help
+	  Do not install applet links. Useful when you plan to use
+	  busybox --install for installing links, or plan to use
+	  a standalone shell and thus don't need applet links.
+
+endchoice
+
+choice
+	prompt "/bin/sh applet link"
+	default BUSYBOX_CONFIG_INSTALL_SH_APPLET_SYMLINK
+	depends on BUSYBOX_CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS
+	help
+	  Choose how you install /bin/sh applet link.
+
+config BUSYBOX_CONFIG_INSTALL_SH_APPLET_SYMLINK
+	bool "as soft-link"
+	help
+	  Install /bin/sh applet as soft-link to the busybox binary.
+
+config BUSYBOX_CONFIG_INSTALL_SH_APPLET_HARDLINK
+	bool "as hard-link"
+	help
+	  Install /bin/sh applet as hard-link to the busybox binary.
+
+config BUSYBOX_CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER
+	bool "as script wrapper"
+	help
+	  Install /bin/sh applet as script wrapper that calls
+	  the busybox binary.
+
+endchoice
+
+config BUSYBOX_CONFIG_PREFIX
+	string "BusyBox installation prefix"
+	default BUSYBOX_DEFAULT_PREFIX
+	help
+	  Define your directory to install BusyBox files/subdirs in.
+
+endmenu
+
+source libbb/Config.in
+
+endmenu
+
+comment "Applets"
+
+source archival/Config.in
+source coreutils/Config.in
+source console-tools/Config.in
+source debianutils/Config.in
+source editors/Config.in
+source findutils/Config.in
+source init/Config.in
+source loginutils/Config.in
+source e2fsprogs/Config.in
+source modutils/Config.in
+source util-linux/Config.in
+source miscutils/Config.in
+source networking/Config.in
+source printutils/Config.in
+source mailutils/Config.in
+source procps/Config.in
+source runit/Config.in
+source selinux/Config.in
+source shell/Config.in
+source sysklogd/Config.in
diff --git a/package/utils/busybox/config/archival/Config.in b/package/utils/busybox/config/archival/Config.in
new file mode 100644
index 0000000000..ff4c2cf6bd
--- /dev/null
+++ b/package/utils/busybox/config/archival/Config.in
@@ -0,0 +1,379 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Archival Utilities"
+
+config BUSYBOX_CONFIG_FEATURE_SEAMLESS_XZ
+	bool "Make tar, rpm, modprobe etc understand .xz data"
+	default BUSYBOX_DEFAULT_FEATURE_SEAMLESS_XZ
+	help
+	  Make tar, rpm, modprobe etc understand .xz data.
+
+config BUSYBOX_CONFIG_FEATURE_SEAMLESS_LZMA
+	bool "Make tar, rpm, modprobe etc understand .lzma data"
+	default BUSYBOX_DEFAULT_FEATURE_SEAMLESS_LZMA
+	help
+	  Make tar, rpm, modprobe etc understand .lzma data.
+
+config BUSYBOX_CONFIG_FEATURE_SEAMLESS_BZ2
+	bool "Make tar, rpm, modprobe etc understand .bz2 data"
+	default BUSYBOX_DEFAULT_FEATURE_SEAMLESS_BZ2
+	help
+	  Make tar, rpm, modprobe etc understand .bz2 data.
+
+config BUSYBOX_CONFIG_FEATURE_SEAMLESS_GZ
+	bool "Make tar, rpm, modprobe etc understand .gz data"
+	default BUSYBOX_DEFAULT_FEATURE_SEAMLESS_GZ
+	help
+	  Make tar, rpm, modprobe etc understand .gz data.
+
+config BUSYBOX_CONFIG_FEATURE_SEAMLESS_Z
+	bool "tar, rpm, modprobe etc understand .Z data"
+	default BUSYBOX_DEFAULT_FEATURE_SEAMLESS_Z  # it is ancient
+	help
+	  Make tar, rpm, modprobe etc understand .Z data.
+
+config BUSYBOX_CONFIG_AR
+	bool "ar"
+	default BUSYBOX_DEFAULT_AR  # needs to be improved to be able to replace binutils ar
+	help
+	  ar is an archival utility program used to create, modify, and
+	  extract contents from archives. In practice, it is used exclusively
+	  for object module archives used by compilers.
+
+	  On an x86 system, the ar applet adds about 1K.
+
+	  Unless you have a specific application which requires ar, you should
+	  probably say N here: most compilers come with their own ar utility.
+
+config BUSYBOX_CONFIG_FEATURE_AR_LONG_FILENAMES
+	bool "Support for long filenames (not needed for debs)"
+	default BUSYBOX_DEFAULT_FEATURE_AR_LONG_FILENAMES
+	depends on BUSYBOX_CONFIG_AR
+	help
+	  By default the ar format can only store the first 15 characters
+	  of the filename, this option removes that limitation.
+	  It supports the GNU ar long filename method which moves multiple long
+	  filenames into a the data section of a new ar entry.
+
+config BUSYBOX_CONFIG_FEATURE_AR_CREATE
+	bool "Support archive creation"
+	default BUSYBOX_DEFAULT_FEATURE_AR_CREATE
+	depends on BUSYBOX_CONFIG_AR
+	help
+	  This enables archive creation (-c and -r) with busybox ar.
+config BUSYBOX_CONFIG_UNCOMPRESS
+	bool "uncompress"
+	default BUSYBOX_DEFAULT_UNCOMPRESS  # ancient
+	help
+	  uncompress is used to decompress archives created by compress.
+	  Not much used anymore, replaced by gzip/gunzip.
+config BUSYBOX_CONFIG_GUNZIP
+	bool "gunzip"
+	default BUSYBOX_DEFAULT_GUNZIP
+	help
+	  gunzip is used to decompress archives created by gzip.
+	  You can use the `-t' option to test the integrity of
+	  an archive, without decompressing it.
+
+config BUSYBOX_CONFIG_FEATURE_GUNZIP_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_GUNZIP_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_GUNZIP && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Enable use of long options.
+config BUSYBOX_CONFIG_BUNZIP2
+	bool "bunzip2"
+	default BUSYBOX_DEFAULT_BUNZIP2
+	help
+	  bunzip2 is a compression utility using the Burrows-Wheeler block
+	  sorting text compression algorithm, and Huffman coding. Compression
+	  is generally considerably better than that achieved by more
+	  conventional LZ77/LZ78-based compressors, and approaches the
+	  performance of the PPM family of statistical compressors.
+
+	  Unless you have a specific application which requires bunzip2, you
+	  should probably say N here.
+config BUSYBOX_CONFIG_UNLZMA
+	bool "unlzma"
+	default BUSYBOX_DEFAULT_UNLZMA
+	help
+	  unlzma is a compression utility using the Lempel-Ziv-Markov chain
+	  compression algorithm, and range coding. Compression
+	  is generally considerably better than that achieved by the bzip2
+	  compressors.
+
+	  The BusyBox unlzma applet is limited to decompression only.
+	  On an x86 system, this applet adds about 4K.
+
+config BUSYBOX_CONFIG_FEATURE_LZMA_FAST
+	bool "Optimize unlzma for speed"
+	default BUSYBOX_DEFAULT_FEATURE_LZMA_FAST
+	depends on BUSYBOX_CONFIG_UNLZMA
+	help
+	  This option reduces decompression time by about 25% at the cost of
+	  a 1K bigger binary.
+
+config BUSYBOX_CONFIG_LZMA
+	bool "Provide lzma alias which supports only unpacking"
+	default BUSYBOX_DEFAULT_LZMA
+	depends on BUSYBOX_CONFIG_UNLZMA
+	help
+	  Enable this option if you want commands like "lzma -d" to work.
+	  IOW: you'll get lzma applet, but it will always require -d option.
+config BUSYBOX_CONFIG_UNXZ
+	bool "unxz"
+	default BUSYBOX_DEFAULT_UNXZ
+	help
+	  unxz is a unlzma successor.
+
+config BUSYBOX_CONFIG_XZ
+	bool "Provide xz alias which supports only unpacking"
+	default BUSYBOX_DEFAULT_XZ
+	depends on BUSYBOX_CONFIG_UNXZ
+	help
+	  Enable this option if you want commands like "xz -d" to work.
+	  IOW: you'll get xz applet, but it will always require -d option.
+config BUSYBOX_CONFIG_BZIP2
+	bool "bzip2"
+	default BUSYBOX_DEFAULT_BZIP2
+	help
+	  bzip2 is a compression utility using the Burrows-Wheeler block
+	  sorting text compression algorithm, and Huffman coding. Compression
+	  is generally considerably better than that achieved by more
+	  conventional LZ77/LZ78-based compressors, and approaches the
+	  performance of the PPM family of statistical compressors.
+
+	  Unless you have a specific application which requires bzip2, you
+	  should probably say N here.
+config BUSYBOX_CONFIG_CPIO
+	bool "cpio"
+	default BUSYBOX_DEFAULT_CPIO
+	help
+	  cpio is an archival utility program used to create, modify, and
+	  extract contents from archives.
+	  cpio has 110 bytes of overheads for every stored file.
+
+	  This implementation of cpio can extract cpio archives created in the
+	  "newc" or "crc" format, it cannot create or modify them.
+
+	  Unless you have a specific application which requires cpio, you
+	  should probably say N here.
+
+config BUSYBOX_CONFIG_FEATURE_CPIO_O
+	bool "Support for archive creation"
+	default BUSYBOX_DEFAULT_FEATURE_CPIO_O
+	depends on BUSYBOX_CONFIG_CPIO
+	help
+	  This implementation of cpio can create cpio archives in the "newc"
+	  format only.
+
+config BUSYBOX_CONFIG_FEATURE_CPIO_P
+	bool "Support for passthrough mode"
+	default BUSYBOX_DEFAULT_FEATURE_CPIO_P
+	depends on BUSYBOX_CONFIG_FEATURE_CPIO_O
+	help
+	  Passthrough mode. Rarely used.
+config BUSYBOX_CONFIG_DPKG
+	bool "dpkg"
+	default BUSYBOX_DEFAULT_DPKG
+	select BUSYBOX_CONFIG_FEATURE_SEAMLESS_GZ
+	help
+	  dpkg is a medium-level tool to install, build, remove and manage
+	  Debian packages.
+
+	  This implementation of dpkg has a number of limitations,
+	  you should use the official dpkg if possible.
+config BUSYBOX_CONFIG_DPKG_DEB
+	bool "dpkg_deb"
+	default BUSYBOX_DEFAULT_DPKG_DEB
+	select BUSYBOX_CONFIG_FEATURE_SEAMLESS_GZ
+	help
+	  dpkg-deb unpacks and provides information about Debian archives.
+
+	  This implementation of dpkg-deb cannot pack archives.
+
+	  Unless you have a specific application which requires dpkg-deb,
+	  say N here.
+
+config BUSYBOX_CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY
+	bool "Extract only (-x)"
+	default BUSYBOX_DEFAULT_FEATURE_DPKG_DEB_EXTRACT_ONLY
+	depends on BUSYBOX_CONFIG_DPKG_DEB
+	help
+	  This reduces dpkg-deb to the equivalent of
+	  "ar -p <deb> data.tar.gz | tar -zx". However it saves space as none
+	  of the extra dpkg-deb, ar or tar options are needed, they are linked
+	  to internally.
+config BUSYBOX_CONFIG_GZIP
+	bool "gzip"
+	default BUSYBOX_DEFAULT_GZIP
+	help
+	  gzip is used to compress files.
+	  It's probably the most widely used UNIX compression program.
+
+config BUSYBOX_CONFIG_FEATURE_GZIP_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_GZIP_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_GZIP && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Enable use of long options, increases size by about 106 Bytes
+
+config BUSYBOX_CONFIG_GZIP_FAST
+	int "Trade memory for gzip speed (0:small,slow - 2:fast,big)"
+	default BUSYBOX_DEFAULT_GZIP_FAST
+	range 0 2
+	depends on BUSYBOX_CONFIG_GZIP
+	help
+	  Enable big memory options for gzip.
+	  0: small buffers, small hash-tables
+	  1: larger buffers, larger hash-tables
+	  2: larger buffers, largest hash-tables
+	  Larger models may give slightly better compression
+
+config BUSYBOX_CONFIG_FEATURE_GZIP_LEVELS
+	bool "Enable compression levels"
+	default BUSYBOX_DEFAULT_FEATURE_GZIP_LEVELS
+	depends on BUSYBOX_CONFIG_GZIP
+	help
+	  Enable support for compression levels 4-9. The default level
+	  is 6. If levels 1-3 are specified, 4 is used.
+	  If this option is not selected, -N options are ignored and -9
+	  is used.
+config BUSYBOX_CONFIG_LZOP
+	bool "lzop"
+	default BUSYBOX_DEFAULT_LZOP
+	help
+	  Lzop compression/decompresion.
+
+config BUSYBOX_CONFIG_LZOP_COMPR_HIGH
+	bool "lzop compression levels 7,8,9 (not very useful)"
+	default BUSYBOX_DEFAULT_LZOP_COMPR_HIGH
+	depends on BUSYBOX_CONFIG_LZOP
+	help
+	  High levels (7,8,9) of lzop compression. These levels
+	  are actually slower than gzip at equivalent compression ratios
+	  and take up 3.2K of code.
+config BUSYBOX_CONFIG_RPM
+	bool "rpm"
+	default BUSYBOX_DEFAULT_RPM
+	help
+	  Mini RPM applet - queries and extracts RPM packages.
+config BUSYBOX_CONFIG_RPM2CPIO
+	bool "rpm2cpio"
+	default BUSYBOX_DEFAULT_RPM2CPIO
+	help
+	  Converts a RPM file into a CPIO archive.
+config BUSYBOX_CONFIG_TAR
+	bool "tar"
+	default BUSYBOX_DEFAULT_TAR
+	help
+	  tar is an archiving program. It's commonly used with gzip to
+	  create compressed archives. It's probably the most widely used
+	  UNIX archive program.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_CREATE
+	bool "Enable archive creation"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_CREATE
+	depends on BUSYBOX_CONFIG_TAR
+	help
+	  If you enable this option you'll be able to create
+	  tar archives using the `-c' option.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_AUTODETECT
+	bool "Autodetect compressed tarballs"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_AUTODETECT
+	depends on BUSYBOX_CONFIG_TAR && (BUSYBOX_CONFIG_FEATURE_SEAMLESS_Z || BUSYBOX_CONFIG_FEATURE_SEAMLESS_GZ || BUSYBOX_CONFIG_FEATURE_SEAMLESS_BZ2 || BUSYBOX_CONFIG_FEATURE_SEAMLESS_LZMA || BUSYBOX_CONFIG_FEATURE_SEAMLESS_XZ)
+	help
+	  With this option tar can automatically detect compressed
+	  tarballs. Currently it works only on files (not pipes etc).
+
+config BUSYBOX_CONFIG_FEATURE_TAR_FROM
+	bool "Enable -X (exclude from) and -T (include from) options)"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_FROM
+	depends on BUSYBOX_CONFIG_TAR
+	help
+	  If you enable this option you'll be able to specify
+	  a list of files to include or exclude from an archive.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY
+	bool "Support for old tar header format"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_OLDGNU_COMPATIBILITY
+	depends on BUSYBOX_CONFIG_TAR || BUSYBOX_CONFIG_DPKG
+	help
+	  This option is required to unpack archives created in
+	  the old GNU format; help to kill this old format by
+	  repacking your ancient archives with the new format.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY
+	bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_OLDSUN_COMPATIBILITY
+	depends on BUSYBOX_CONFIG_TAR || BUSYBOX_CONFIG_DPKG
+	help
+	  This option is required to unpack archives created by some old
+	  version of Sun's tar (it was calculating checksum using signed
+	  arithmetic). It is said to be fixed in newer Sun tar, but "old"
+	  tarballs still exist.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+	bool "Support for GNU tar extensions (long filenames)"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_GNU_EXTENSIONS
+	depends on BUSYBOX_CONFIG_TAR || BUSYBOX_CONFIG_DPKG
+	help
+	  With this option busybox supports GNU long filenames and
+	  linknames.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_TAR && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Enable use of long options, increases size by about 400 Bytes
+
+config BUSYBOX_CONFIG_FEATURE_TAR_TO_COMMAND
+	bool "Support for writing to an external program"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_TO_COMMAND
+	depends on BUSYBOX_CONFIG_TAR && BUSYBOX_CONFIG_FEATURE_TAR_LONG_OPTIONS
+	help
+	  If you enable this option you'll be able to instruct tar to send
+	  the contents of each extracted file to the standard input of an
+	  external program.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_UNAME_GNAME
+	bool "Enable use of user and group names"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_UNAME_GNAME
+	depends on BUSYBOX_CONFIG_TAR
+	help
+	  Enables use of user and group names in tar. This affects contents
+	  listings (-t) and preserving permissions when unpacking (-p).
+	  +200 bytes.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_NOPRESERVE_TIME
+	bool "Enable -m (do not preserve time) option"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_NOPRESERVE_TIME
+	depends on BUSYBOX_CONFIG_TAR
+	help
+	  With this option busybox supports GNU tar -m
+	  (do not preserve time) option.
+
+config BUSYBOX_CONFIG_FEATURE_TAR_SELINUX
+	bool "Support for extracting SELinux labels"
+	default BUSYBOX_DEFAULT_FEATURE_TAR_SELINUX
+	depends on BUSYBOX_CONFIG_TAR && BUSYBOX_CONFIG_SELINUX
+	help
+	  With this option busybox supports restoring SELinux labels
+	  when extracting files from tar archives.
+config BUSYBOX_CONFIG_UNZIP
+	bool "unzip"
+	default BUSYBOX_DEFAULT_UNZIP
+	help
+	  unzip will list or extract files from a ZIP archive,
+	  commonly found on DOS/WIN systems. The default behavior
+	  (with no options) is to extract the archive into the
+	  current directory. Use the `-d' option to extract to a
+	  directory of your choice.
+
+endmenu
diff --git a/package/utils/busybox/config/console-tools/Config.in b/package/utils/busybox/config/console-tools/Config.in
new file mode 100644
index 0000000000..53937d2b5c
--- /dev/null
+++ b/package/utils/busybox/config/console-tools/Config.in
@@ -0,0 +1,176 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Console Utilities"
+
+
+config BUSYBOX_CONFIG_CHVT
+	bool "chvt"
+	default BUSYBOX_DEFAULT_CHVT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program is used to change to another terminal.
+	  Example: chvt 4 (change to terminal /dev/tty4)
+
+config BUSYBOX_CONFIG_FGCONSOLE
+	bool "fgconsole"
+	default BUSYBOX_DEFAULT_FGCONSOLE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program prints active (foreground) console number.
+
+config BUSYBOX_CONFIG_CLEAR
+	bool "clear"
+	default BUSYBOX_DEFAULT_CLEAR
+	help
+	  This program clears the terminal screen.
+
+config BUSYBOX_CONFIG_DEALLOCVT
+	bool "deallocvt"
+	default BUSYBOX_DEFAULT_DEALLOCVT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program deallocates unused virtual consoles.
+
+config BUSYBOX_CONFIG_DUMPKMAP
+	bool "dumpkmap"
+	default BUSYBOX_DEFAULT_DUMPKMAP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program dumps the kernel's keyboard translation table to
+	  stdout, in binary format. You can then use loadkmap to load it.
+
+config BUSYBOX_CONFIG_KBD_MODE
+	bool "kbd_mode"
+	default BUSYBOX_DEFAULT_KBD_MODE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program reports and sets keyboard mode.
+
+config BUSYBOX_CONFIG_LOADFONT
+	bool "loadfont"
+	default BUSYBOX_DEFAULT_LOADFONT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program loads a console font from standard input.
+
+config BUSYBOX_CONFIG_LOADKMAP
+	bool "loadkmap"
+	default BUSYBOX_DEFAULT_LOADKMAP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program loads a keyboard translation table from
+	  standard input.
+
+config BUSYBOX_CONFIG_OPENVT
+	bool "openvt"
+	default BUSYBOX_DEFAULT_OPENVT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program is used to start a command on an unused
+	  virtual terminal.
+
+config BUSYBOX_CONFIG_RESET
+	bool "reset"
+	default BUSYBOX_DEFAULT_RESET
+	help
+	  This program is used to reset the terminal screen, if it
+	  gets messed up.
+
+config BUSYBOX_CONFIG_RESIZE
+	bool "resize"
+	default BUSYBOX_DEFAULT_RESIZE
+	help
+	  This program is used to (re)set the width and height of your current
+	  terminal.
+
+config BUSYBOX_CONFIG_FEATURE_RESIZE_PRINT
+	bool "Print environment variables"
+	default BUSYBOX_DEFAULT_FEATURE_RESIZE_PRINT
+	depends on BUSYBOX_CONFIG_RESIZE
+	help
+	  Prints the newly set size (number of columns and rows) of
+	  the terminal.
+	  E.g.:
+	  COLUMNS=80;LINES=44;export COLUMNS LINES;
+
+config BUSYBOX_CONFIG_SETCONSOLE
+	bool "setconsole"
+	default BUSYBOX_DEFAULT_SETCONSOLE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program redirects the system console to another device,
+	  like the current tty while logged in via telnet.
+
+config BUSYBOX_CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_SETCONSOLE_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_SETCONSOLE && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the setconsole applet.
+
+config BUSYBOX_CONFIG_SETFONT
+	bool "setfont"
+	default BUSYBOX_DEFAULT_SETFONT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Allows to load console screen map. Useful for i18n.
+
+config BUSYBOX_CONFIG_FEATURE_SETFONT_TEXTUAL_MAP
+	bool "Support reading textual screen maps"
+	default BUSYBOX_DEFAULT_FEATURE_SETFONT_TEXTUAL_MAP
+	depends on BUSYBOX_CONFIG_SETFONT
+	help
+	  Support reading textual screen maps.
+
+config BUSYBOX_CONFIG_DEFAULT_SETFONT_DIR
+	string "Default directory for console-tools files"
+	default BUSYBOX_DEFAULT_DEFAULT_SETFONT_DIR
+	depends on BUSYBOX_CONFIG_SETFONT
+	help
+	  Directory to use if setfont's params are simple filenames
+	  (not /path/to/file or ./file). Default is "" (no default directory).
+
+config BUSYBOX_CONFIG_SETKEYCODES
+	bool "setkeycodes"
+	default BUSYBOX_DEFAULT_SETKEYCODES
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program loads entries into the kernel's scancode-to-keycode
+	  map, allowing unusual keyboards to generate usable keycodes.
+
+config BUSYBOX_CONFIG_SETLOGCONS
+	bool "setlogcons"
+	default BUSYBOX_DEFAULT_SETLOGCONS
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This program redirects the output console of kernel messages.
+
+config BUSYBOX_CONFIG_SHOWKEY
+	bool "showkey"
+	default BUSYBOX_DEFAULT_SHOWKEY
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Shows keys pressed.
+
+comment "Common options for loadfont and setfont"
+	depends on BUSYBOX_CONFIG_LOADFONT || BUSYBOX_CONFIG_SETFONT
+
+config BUSYBOX_CONFIG_FEATURE_LOADFONT_PSF2
+	bool "Support for PSF2 console fonts"
+	default BUSYBOX_DEFAULT_FEATURE_LOADFONT_PSF2
+	depends on BUSYBOX_CONFIG_LOADFONT || BUSYBOX_CONFIG_SETFONT
+	help
+	  Support PSF2 console fonts.
+
+config BUSYBOX_CONFIG_FEATURE_LOADFONT_RAW
+	bool "Support for old (raw) console fonts"
+	default BUSYBOX_DEFAULT_FEATURE_LOADFONT_RAW
+	depends on BUSYBOX_CONFIG_LOADFONT || BUSYBOX_CONFIG_SETFONT
+	help
+	  Support old (raw) console fonts.
+
+endmenu
diff --git a/package/utils/busybox/config/coreutils/Config.in b/package/utils/busybox/config/coreutils/Config.in
new file mode 100644
index 0000000000..ec5611bdfd
--- /dev/null
+++ b/package/utils/busybox/config/coreutils/Config.in
@@ -0,0 +1,987 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Coreutils"
+
+config BUSYBOX_CONFIG_BASENAME
+	bool "basename"
+	default BUSYBOX_DEFAULT_BASENAME
+	help
+	  basename is used to strip the directory and suffix from filenames,
+	  leaving just the filename itself. Enable this option if you wish
+	  to enable the 'basename' utility.
+config BUSYBOX_CONFIG_CAT
+	bool "cat"
+	default BUSYBOX_DEFAULT_CAT
+	help
+	  cat is used to concatenate files and print them to the standard
+	  output. Enable this option if you wish to enable the 'cat' utility.
+config BUSYBOX_CONFIG_DATE
+	bool "date"
+	default BUSYBOX_DEFAULT_DATE
+	help
+	  date is used to set the system date or display the
+	  current time in the given format.
+
+config BUSYBOX_CONFIG_FEATURE_DATE_ISOFMT
+	bool "Enable ISO date format output (-I)"
+	default BUSYBOX_DEFAULT_FEATURE_DATE_ISOFMT
+	depends on BUSYBOX_CONFIG_DATE
+	help
+	  Enable option (-I) to output an ISO-8601 compliant
+	  date/time string.
+
+# defaults to "no": stat's nanosecond field is a bit non-portable
+config BUSYBOX_CONFIG_FEATURE_DATE_NANO
+	bool "Support %[num]N nanosecond format specifier"
+	default BUSYBOX_DEFAULT_FEATURE_DATE_NANO
+	depends on BUSYBOX_CONFIG_DATE  # syscall(__NR_clock_gettime)
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Support %[num]N format specifier. Adds ~250 bytes of code.
+
+config BUSYBOX_CONFIG_FEATURE_DATE_COMPAT
+	bool "Support weird 'date MMDDhhmm[[YY]YY][.ss]' format"
+	default BUSYBOX_DEFAULT_FEATURE_DATE_COMPAT
+	depends on BUSYBOX_CONFIG_DATE
+	help
+	  System time can be set by 'date -s DATE' and simply 'date DATE',
+	  but formats of DATE string are different. 'date DATE' accepts
+	  a rather weird MMDDhhmm[[YY]YY][.ss] format with completely
+	  unnatural placement of year between minutes and seconds.
+	  date -s (and other commands like touch -d) use more sensible
+	  formats (for one, ISO format YYYY-MM-DD hh:mm:ss.ssssss).
+
+	  With this option off, 'date DATE' is 'date -s DATE' support
+	  the same format. With it on, 'date DATE' additionally supports
+	  MMDDhhmm[[YY]YY][.ss] format.
+config BUSYBOX_CONFIG_DD
+	bool "dd"
+	default BUSYBOX_DEFAULT_DD
+	help
+	  dd copies a file (from standard input to standard output,
+	  by default) using specific input and output blocksizes,
+	  while optionally performing conversions on it.
+
+config BUSYBOX_CONFIG_FEATURE_DD_SIGNAL_HANDLING
+	bool "Enable signal handling for status reporting"
+	default BUSYBOX_DEFAULT_FEATURE_DD_SIGNAL_HANDLING
+	depends on BUSYBOX_CONFIG_DD
+	help
+	  Sending a SIGUSR1 signal to a running `dd' process makes it
+	  print to standard error the number of records read and written
+	  so far, then to resume copying.
+
+	  $ dd if=/dev/zero of=/dev/null &
+	  $ pid=$!; kill -USR1 $pid; sleep 1; kill $pid
+	  10899206+0 records in
+	  10899206+0 records out
+
+config BUSYBOX_CONFIG_FEATURE_DD_THIRD_STATUS_LINE
+	bool "Enable the third status line upon signal"
+	default BUSYBOX_DEFAULT_FEATURE_DD_THIRD_STATUS_LINE
+	depends on BUSYBOX_CONFIG_DD && BUSYBOX_CONFIG_FEATURE_DD_SIGNAL_HANDLING
+	help
+	  Displays a coreutils-like third status line with transferred bytes,
+	  elapsed time and speed.
+
+config BUSYBOX_CONFIG_FEATURE_DD_IBS_OBS
+	bool "Enable ibs, obs and conv options"
+	default BUSYBOX_DEFAULT_FEATURE_DD_IBS_OBS
+	depends on BUSYBOX_CONFIG_DD
+	help
+	  Enables support for writing a certain number of bytes in and out,
+	  at a time, and performing conversions on the data stream.
+
+config BUSYBOX_CONFIG_FEATURE_DD_STATUS
+	bool "Enable status display options"
+	default BUSYBOX_DEFAULT_FEATURE_DD_STATUS
+	depends on BUSYBOX_CONFIG_DD
+	help
+	  Enables support for status=noxfer/none option.
+config BUSYBOX_CONFIG_HOSTID
+	bool "hostid"
+	default BUSYBOX_DEFAULT_HOSTID
+	help
+	  hostid prints the numeric identifier (in hexadecimal) for
+	  the current host.
+config BUSYBOX_CONFIG_ID
+	bool "id"
+	default BUSYBOX_DEFAULT_ID
+	help
+	  id displays the current user and group ID names.
+config BUSYBOX_CONFIG_GROUPS
+	bool "groups"
+	default BUSYBOX_DEFAULT_GROUPS
+	help
+	  Print the group names associated with current user id.
+config BUSYBOX_CONFIG_SHUF
+	bool "shuf"
+	default BUSYBOX_DEFAULT_SHUF
+	help
+	  Generate random permutations
+config BUSYBOX_CONFIG_STAT
+	bool "stat"
+	default BUSYBOX_DEFAULT_STAT
+	help
+	  display file or filesystem status.
+
+config BUSYBOX_CONFIG_FEATURE_STAT_FORMAT
+	bool "Enable custom formats (-c)"
+	default BUSYBOX_DEFAULT_FEATURE_STAT_FORMAT
+	depends on BUSYBOX_CONFIG_STAT
+	help
+	  Without this, stat will not support the '-c format' option where
+	  users can pass a custom format string for output. This adds about
+	  7k to a nonstatic build on amd64.
+
+config BUSYBOX_CONFIG_FEATURE_STAT_FILESYSTEM
+	bool "Enable display of filesystem status (-f)"
+	default BUSYBOX_DEFAULT_FEATURE_STAT_FILESYSTEM
+	depends on BUSYBOX_CONFIG_STAT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX # statfs()
+	help
+	  Without this, stat will not support the '-f' option to display
+	  information about filesystem status.
+config BUSYBOX_CONFIG_SYNC
+	bool "sync"
+	default BUSYBOX_DEFAULT_SYNC
+	help
+	  sync is used to flush filesystem buffers.
+config BUSYBOX_CONFIG_FEATURE_SYNC_FANCY
+	bool "Enable -d and -f flags (requres syncfs(2) in libc)"
+	default BUSYBOX_DEFAULT_FEATURE_SYNC_FANCY
+	depends on BUSYBOX_CONFIG_SYNC
+	help
+	  sync -d FILE... executes fdatasync() on each FILE.
+	  sync -f FILE... executes syncfs() on each FILE.
+config BUSYBOX_CONFIG_TEST
+	bool "test"
+	default BUSYBOX_DEFAULT_TEST
+	help
+	  test is used to check file types and compare values,
+	  returning an appropriate exit code. The bash shell
+	  has test built in, ash can build it in optionally.
+
+config BUSYBOX_CONFIG_FEATURE_TEST_64
+	bool "Extend test to 64 bit"
+	default BUSYBOX_DEFAULT_FEATURE_TEST_64
+	depends on BUSYBOX_CONFIG_TEST || BUSYBOX_CONFIG_ASH_BUILTIN_TEST || BUSYBOX_CONFIG_HUSH
+	help
+	  Enable 64-bit support in test.
+config BUSYBOX_CONFIG_TOUCH
+	bool "touch"
+	default BUSYBOX_DEFAULT_TOUCH
+	help
+	  touch is used to create or change the access and/or
+	  modification timestamp of specified files.
+
+config BUSYBOX_CONFIG_FEATURE_TOUCH_NODEREF
+	bool "Add support for -h"
+	default BUSYBOX_DEFAULT_FEATURE_TOUCH_NODEREF
+	depends on BUSYBOX_CONFIG_TOUCH
+	help
+	  Enable touch to have the -h option.
+	  This requires libc support for lutimes() function.
+
+config BUSYBOX_CONFIG_FEATURE_TOUCH_SUSV3
+	bool "Add support for SUSV3 features (-d -t -r)"
+	default BUSYBOX_DEFAULT_FEATURE_TOUCH_SUSV3
+	depends on BUSYBOX_CONFIG_TOUCH
+	help
+	  Enable touch to use a reference file or a given date/time argument.
+config BUSYBOX_CONFIG_TR
+	bool "tr"
+	default BUSYBOX_DEFAULT_TR
+	help
+	  tr is used to squeeze, and/or delete characters from standard
+	  input, writing to standard output.
+
+config BUSYBOX_CONFIG_FEATURE_TR_CLASSES
+	bool "Enable character classes (such as [:upper:])"
+	default BUSYBOX_DEFAULT_FEATURE_TR_CLASSES
+	depends on BUSYBOX_CONFIG_TR
+	help
+	  Enable character classes, enabling commands such as:
+	  tr [:upper:] [:lower:] to convert input into lowercase.
+
+config BUSYBOX_CONFIG_FEATURE_TR_EQUIV
+	bool "Enable equivalence classes"
+	default BUSYBOX_DEFAULT_FEATURE_TR_EQUIV
+	depends on BUSYBOX_CONFIG_TR
+	help
+	  Enable equivalence classes, which essentially add the enclosed
+	  character to the current set. For instance, tr [=a=] xyz would
+	  replace all instances of 'a' with 'xyz'. This option is mainly
+	  useful for cases when no other way of expressing a character
+	  is possible.
+config BUSYBOX_CONFIG_TRUNCATE
+	bool "truncate"
+	default BUSYBOX_DEFAULT_TRUNCATE
+	help
+	  truncate truncates files to a given size. If a file does
+	  not exist, it is created unless told otherwise.
+config BUSYBOX_CONFIG_UNLINK
+	bool "unlink"
+	default BUSYBOX_DEFAULT_UNLINK
+	help
+	  unlink deletes a file by calling unlink()
+config BUSYBOX_CONFIG_BASE64
+	bool "base64"
+	default BUSYBOX_DEFAULT_BASE64
+	help
+	  Base64 encode and decode
+config BUSYBOX_CONFIG_WHO
+      bool "who"
+      default BUSYBOX_DEFAULT_WHO
+      depends on BUSYBOX_CONFIG_FEATURE_UTMP
+      help
+        who is used to show who is logged on.
+config BUSYBOX_CONFIG_USERS
+      bool "users"
+      default BUSYBOX_DEFAULT_USERS
+      depends on BUSYBOX_CONFIG_FEATURE_UTMP
+      help
+        Print users currently logged on.
+
+config BUSYBOX_CONFIG_CAL
+	bool "cal"
+	default BUSYBOX_DEFAULT_CAL
+	help
+	  cal is used to display a monthly calendar.
+
+config BUSYBOX_CONFIG_CATV
+	bool "catv"
+	default BUSYBOX_DEFAULT_CATV
+	help
+	  Display nonprinting characters as escape sequences (like some
+	  implementations' cat -v option).
+
+config BUSYBOX_CONFIG_CHGRP
+	bool "chgrp"
+	default BUSYBOX_DEFAULT_CHGRP
+	help
+	  chgrp is used to change the group ownership of files.
+
+config BUSYBOX_CONFIG_CHMOD
+	bool "chmod"
+	default BUSYBOX_DEFAULT_CHMOD
+	help
+	  chmod is used to change the access permission of files.
+
+config BUSYBOX_CONFIG_CHOWN
+	bool "chown"
+	default BUSYBOX_DEFAULT_CHOWN
+	help
+	  chown is used to change the user and/or group ownership
+	  of files.
+
+config BUSYBOX_CONFIG_FEATURE_CHOWN_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_CHOWN_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_CHOWN && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Enable use of long options
+
+config BUSYBOX_CONFIG_CHROOT
+	bool "chroot"
+	default BUSYBOX_DEFAULT_CHROOT
+	help
+	  chroot is used to change the root directory and run a command.
+	  The default command is `/bin/sh'.
+
+config BUSYBOX_CONFIG_CKSUM
+	bool "cksum"
+	default BUSYBOX_DEFAULT_CKSUM
+	help
+	  cksum is used to calculate the CRC32 checksum of a file.
+
+config BUSYBOX_CONFIG_COMM
+	bool "comm"
+	default BUSYBOX_DEFAULT_COMM
+	help
+	  comm is used to compare two files line by line and return
+	  a three-column output.
+
+config BUSYBOX_CONFIG_CP
+	bool "cp"
+	default BUSYBOX_DEFAULT_CP
+	help
+	  cp is used to copy files and directories.
+
+config BUSYBOX_CONFIG_FEATURE_CP_LONG_OPTIONS
+	bool "Enable long options for cp"
+	default BUSYBOX_DEFAULT_FEATURE_CP_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_CP && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Enable long options for cp.
+	  Also add support for --parents option.
+
+config BUSYBOX_CONFIG_CUT
+	bool "cut"
+	default BUSYBOX_DEFAULT_CUT
+	help
+	  cut is used to print selected parts of lines from
+	  each file to stdout.
+
+config BUSYBOX_CONFIG_DF
+	bool "df"
+	default BUSYBOX_DEFAULT_DF
+	help
+	  df reports the amount of disk space used and available
+	  on filesystems.
+
+config BUSYBOX_CONFIG_FEATURE_DF_FANCY
+	bool "Enable -a, -i, -B"
+	default BUSYBOX_DEFAULT_FEATURE_DF_FANCY
+	depends on BUSYBOX_CONFIG_DF
+	help
+	  This option enables -a, -i and -B.
+
+	    -a Show all filesystems
+	    -i Inodes
+	    -B <SIZE> Blocksize
+
+config BUSYBOX_CONFIG_DIRNAME
+	bool "dirname"
+	default BUSYBOX_DEFAULT_DIRNAME
+	help
+	  dirname is used to strip a non-directory suffix from
+	  a file name.
+
+config BUSYBOX_CONFIG_DOS2UNIX
+	bool "dos2unix/unix2dos"
+	default BUSYBOX_DEFAULT_DOS2UNIX
+	help
+	  dos2unix is used to convert a text file from DOS format to
+	  UNIX format, and vice versa.
+
+config BUSYBOX_CONFIG_UNIX2DOS
+	bool
+	default BUSYBOX_DEFAULT_UNIX2DOS
+	depends on BUSYBOX_CONFIG_DOS2UNIX
+	help
+	  unix2dos is used to convert a text file from UNIX format to
+	  DOS format, and vice versa.
+
+config BUSYBOX_CONFIG_DU
+	bool "du (default blocksize of 512 bytes)"
+	default BUSYBOX_DEFAULT_DU
+	help
+	  du is used to report the amount of disk space used
+	  for specified files.
+
+config BUSYBOX_CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+	bool "Use a default blocksize of 1024 bytes (1K)"
+	default BUSYBOX_DEFAULT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+	depends on BUSYBOX_CONFIG_DU
+	help
+	  Use a blocksize of (1K) instead of the default 512b.
+
+config BUSYBOX_CONFIG_ECHO
+	bool "echo (basic SuSv3 version taking no options)"
+	default BUSYBOX_DEFAULT_ECHO
+	help
+	  echo is used to print a specified string to stdout.
+
+# this entry also appears in shell/Config.in, next to the echo builtin
+config BUSYBOX_CONFIG_FEATURE_FANCY_ECHO
+	bool "Enable echo options (-n and -e)"
+	default BUSYBOX_DEFAULT_FEATURE_FANCY_ECHO
+	depends on BUSYBOX_CONFIG_ECHO || BUSYBOX_CONFIG_ASH_BUILTIN_ECHO || BUSYBOX_CONFIG_HUSH
+	help
+	  This adds options (-n and -e) to echo.
+
+config BUSYBOX_CONFIG_ENV
+	bool "env"
+	default BUSYBOX_DEFAULT_ENV
+	help
+	  env is used to set an environment variable and run
+	  a command; without options it displays the current
+	  environment.
+
+config BUSYBOX_CONFIG_FEATURE_ENV_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_ENV_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_ENV && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the env applet.
+
+config BUSYBOX_CONFIG_EXPAND
+	bool "expand"
+	default BUSYBOX_DEFAULT_EXPAND
+	help
+	  By default, convert all tabs to spaces.
+
+config BUSYBOX_CONFIG_FEATURE_EXPAND_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_EXPAND_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_EXPAND && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the expand applet.
+
+config BUSYBOX_CONFIG_EXPR
+	bool "expr"
+	default BUSYBOX_DEFAULT_EXPR
+	help
+	  expr is used to calculate numbers and print the result
+	  to standard output.
+
+config BUSYBOX_CONFIG_EXPR_MATH_SUPPORT_64
+	bool "Extend Posix numbers support to 64 bit"
+	default BUSYBOX_DEFAULT_EXPR_MATH_SUPPORT_64
+	depends on BUSYBOX_CONFIG_EXPR
+	help
+	  Enable 64-bit math support in the expr applet. This will make
+	  the applet slightly larger, but will allow computation with very
+	  large numbers.
+
+config BUSYBOX_CONFIG_FALSE
+	bool "false"
+	default BUSYBOX_DEFAULT_FALSE
+	help
+	  false returns an exit code of FALSE (1).
+
+config BUSYBOX_CONFIG_FOLD
+	bool "fold"
+	default BUSYBOX_DEFAULT_FOLD
+	help
+	  Wrap text to fit a specific width.
+
+config BUSYBOX_CONFIG_FSYNC
+	bool "fsync"
+	default BUSYBOX_DEFAULT_FSYNC
+	help
+	  fsync is used to flush file-related cached blocks to disk.
+
+config BUSYBOX_CONFIG_HEAD
+	bool "head"
+	default BUSYBOX_DEFAULT_HEAD
+	help
+	  head is used to print the first specified number of lines
+	  from files.
+
+config BUSYBOX_CONFIG_FEATURE_FANCY_HEAD
+	bool "Enable head options (-c, -q, and -v)"
+	default BUSYBOX_DEFAULT_FEATURE_FANCY_HEAD
+	depends on BUSYBOX_CONFIG_HEAD
+	help
+	  This enables the head options (-c, -q, and -v).
+
+config BUSYBOX_CONFIG_INSTALL
+	bool "install"
+	default BUSYBOX_DEFAULT_INSTALL
+	help
+	  Copy files and set attributes.
+
+config BUSYBOX_CONFIG_FEATURE_INSTALL_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_INSTALL_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_INSTALL && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the install applet.
+
+####config LENGTH
+####	bool "length"
+####	default y
+####	help
+####	  length is used to print out the length of a specified string.
+
+config BUSYBOX_CONFIG_LN
+	bool "ln"
+	default BUSYBOX_DEFAULT_LN
+	help
+	  ln is used to create hard or soft links between files.
+
+config BUSYBOX_CONFIG_LOGNAME
+	bool "logname"
+	default BUSYBOX_DEFAULT_LOGNAME
+	help
+	  logname is used to print the current user's login name.
+
+config BUSYBOX_CONFIG_LS
+	bool "ls"
+	default BUSYBOX_DEFAULT_LS
+	help
+	  ls is used to list the contents of directories.
+
+config BUSYBOX_CONFIG_FEATURE_LS_FILETYPES
+	bool "Enable filetyping options (-p and -F)"
+	default BUSYBOX_DEFAULT_FEATURE_LS_FILETYPES
+	depends on BUSYBOX_CONFIG_LS
+	help
+	  Enable the ls options (-p and -F).
+
+config BUSYBOX_CONFIG_FEATURE_LS_FOLLOWLINKS
+	bool "Enable symlinks dereferencing (-L)"
+	default BUSYBOX_DEFAULT_FEATURE_LS_FOLLOWLINKS
+	depends on BUSYBOX_CONFIG_LS
+	help
+	  Enable the ls option (-L).
+
+config BUSYBOX_CONFIG_FEATURE_LS_RECURSIVE
+	bool "Enable recursion (-R)"
+	default BUSYBOX_DEFAULT_FEATURE_LS_RECURSIVE
+	depends on BUSYBOX_CONFIG_LS
+	help
+	  Enable the ls option (-R).
+
+config BUSYBOX_CONFIG_FEATURE_LS_SORTFILES
+	bool "Sort the file names"
+	default BUSYBOX_DEFAULT_FEATURE_LS_SORTFILES
+	depends on BUSYBOX_CONFIG_LS
+	help
+	  Allow ls to sort file names alphabetically.
+
+config BUSYBOX_CONFIG_FEATURE_LS_TIMESTAMPS
+	bool "Show file timestamps"
+	default BUSYBOX_DEFAULT_FEATURE_LS_TIMESTAMPS
+	depends on BUSYBOX_CONFIG_LS
+	help
+	  Allow ls to display timestamps for files.
+
+config BUSYBOX_CONFIG_FEATURE_LS_USERNAME
+	bool "Show username/groupnames"
+	default BUSYBOX_DEFAULT_FEATURE_LS_USERNAME
+	depends on BUSYBOX_CONFIG_LS
+	help
+	  Allow ls to display username/groupname for files.
+
+config BUSYBOX_CONFIG_FEATURE_LS_COLOR
+	bool "Allow use of color to identify file types"
+	default BUSYBOX_DEFAULT_FEATURE_LS_COLOR
+	depends on BUSYBOX_CONFIG_LS && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  This enables the --color option to ls.
+
+config BUSYBOX_CONFIG_FEATURE_LS_COLOR_IS_DEFAULT
+	bool "Produce colored ls output by default"
+	default BUSYBOX_DEFAULT_FEATURE_LS_COLOR_IS_DEFAULT
+	depends on BUSYBOX_CONFIG_FEATURE_LS_COLOR
+	help
+	  Saying yes here will turn coloring on by default,
+	  even if no "--color" option is given to the ls command.
+	  This is not recommended, since the colors are not
+	  configurable, and the output may not be legible on
+	  many output screens.
+
+config BUSYBOX_CONFIG_MD5SUM
+	bool "md5sum"
+	default BUSYBOX_DEFAULT_MD5SUM
+	help
+	  md5sum is used to print or check MD5 checksums.
+
+config BUSYBOX_CONFIG_MKDIR
+	bool "mkdir"
+	default BUSYBOX_DEFAULT_MKDIR
+	help
+	  mkdir is used to create directories with the specified names.
+
+config BUSYBOX_CONFIG_FEATURE_MKDIR_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_MKDIR_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_MKDIR && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the mkdir applet.
+
+config BUSYBOX_CONFIG_MKFIFO
+	bool "mkfifo"
+	default BUSYBOX_DEFAULT_MKFIFO
+	help
+	  mkfifo is used to create FIFOs (named pipes).
+	  The `mknod' program can also create FIFOs.
+
+config BUSYBOX_CONFIG_MKNOD
+	bool "mknod"
+	default BUSYBOX_DEFAULT_MKNOD
+	help
+	  mknod is used to create FIFOs or block/character special
+	  files with the specified names.
+
+config BUSYBOX_CONFIG_MV
+	bool "mv"
+	default BUSYBOX_DEFAULT_MV
+	help
+	  mv is used to move or rename files or directories.
+
+config BUSYBOX_CONFIG_FEATURE_MV_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_MV_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_MV && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the mv applet.
+
+config BUSYBOX_CONFIG_NICE
+	bool "nice"
+	default BUSYBOX_DEFAULT_NICE
+	help
+	  nice runs a program with modified scheduling priority.
+
+config BUSYBOX_CONFIG_NOHUP
+	bool "nohup"
+	default BUSYBOX_DEFAULT_NOHUP
+	help
+	  run a command immune to hangups, with output to a non-tty.
+
+config BUSYBOX_CONFIG_OD
+	bool "od"
+	default BUSYBOX_DEFAULT_OD
+	help
+	  od is used to dump binary files in octal and other formats.
+
+config BUSYBOX_CONFIG_PRINTENV
+	bool "printenv"
+	default BUSYBOX_DEFAULT_PRINTENV
+	help
+	  printenv is used to print all or part of environment.
+
+config BUSYBOX_CONFIG_PRINTF
+	bool "printf"
+	default BUSYBOX_DEFAULT_PRINTF
+	help
+	  printf is used to format and print specified strings.
+	  It's similar to `echo' except it has more options.
+
+config BUSYBOX_CONFIG_PWD
+	bool "pwd"
+	default BUSYBOX_DEFAULT_PWD
+	help
+	  pwd is used to print the current directory.
+
+config BUSYBOX_CONFIG_READLINK
+	bool "readlink"
+	default BUSYBOX_DEFAULT_READLINK
+	help
+	  This program reads a symbolic link and returns the name
+	  of the file it points to
+
+config BUSYBOX_CONFIG_FEATURE_READLINK_FOLLOW
+	bool "Enable canonicalization by following all symlinks (-f)"
+	default BUSYBOX_DEFAULT_FEATURE_READLINK_FOLLOW
+	depends on BUSYBOX_CONFIG_READLINK
+	help
+	  Enable the readlink option (-f).
+
+config BUSYBOX_CONFIG_REALPATH
+	bool "realpath"
+	default BUSYBOX_DEFAULT_REALPATH
+	help
+	  Return the canonicalized absolute pathname.
+	  This isn't provided by GNU shellutils, but where else does it belong.
+
+config BUSYBOX_CONFIG_RM
+	bool "rm"
+	default BUSYBOX_DEFAULT_RM
+	help
+	  rm is used to remove files or directories.
+
+config BUSYBOX_CONFIG_RMDIR
+	bool "rmdir"
+	default BUSYBOX_DEFAULT_RMDIR
+	help
+	  rmdir is used to remove empty directories.
+
+config BUSYBOX_CONFIG_FEATURE_RMDIR_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_RMDIR_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_RMDIR && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the rmdir applet, including
+	  --ignore-fail-on-non-empty for compatibility with GNU rmdir.
+
+config BUSYBOX_CONFIG_SEQ
+	bool "seq"
+	default BUSYBOX_DEFAULT_SEQ
+	help
+	  print a sequence of numbers
+
+config BUSYBOX_CONFIG_SHA1SUM
+	bool "sha1sum"
+	default BUSYBOX_DEFAULT_SHA1SUM
+	help
+	  Compute and check SHA1 message digest
+
+config BUSYBOX_CONFIG_SHA256SUM
+	bool "sha256sum"
+	default BUSYBOX_DEFAULT_SHA256SUM
+	help
+	  Compute and check SHA256 message digest
+
+config BUSYBOX_CONFIG_SHA512SUM
+	bool "sha512sum"
+	default BUSYBOX_DEFAULT_SHA512SUM
+	help
+	  Compute and check SHA512 message digest
+
+config BUSYBOX_CONFIG_SHA3SUM
+	bool "sha3sum"
+	default BUSYBOX_DEFAULT_SHA3SUM
+	help
+	  Compute and check SHA3 (512-bit) message digest
+
+config BUSYBOX_CONFIG_SLEEP
+	bool "sleep"
+	default BUSYBOX_DEFAULT_SLEEP
+	help
+	  sleep is used to pause for a specified number of seconds.
+	  It comes in 3 versions:
+	  - small: takes one integer parameter
+	  - fancy: takes multiple integer arguments with suffixes:
+	    sleep 1d 2h 3m 15s
+	  - fancy with fractional numbers:
+	    sleep 2.3s 4.5h sleeps for 16202.3 seconds
+	  Last one is "the most compatible" with coreutils sleep,
+	  but it adds around 1k of code.
+
+config BUSYBOX_CONFIG_FEATURE_FANCY_SLEEP
+	bool "Enable multiple arguments and s/m/h/d suffixes"
+	default BUSYBOX_DEFAULT_FEATURE_FANCY_SLEEP
+	depends on BUSYBOX_CONFIG_SLEEP
+	help
+	  Allow sleep to pause for specified minutes, hours, and days.
+
+config BUSYBOX_CONFIG_FEATURE_FLOAT_SLEEP
+	bool "Enable fractional arguments"
+	default BUSYBOX_DEFAULT_FEATURE_FLOAT_SLEEP
+	depends on BUSYBOX_CONFIG_FEATURE_FANCY_SLEEP
+	help
+	  Allow for fractional numeric parameters.
+
+config BUSYBOX_CONFIG_SORT
+	bool "sort"
+	default BUSYBOX_DEFAULT_SORT
+	help
+	  sort is used to sort lines of text in specified files.
+
+config BUSYBOX_CONFIG_FEATURE_SORT_BIG
+	bool "Full SuSv3 compliant sort (support -ktcsbdfiozgM)"
+	default BUSYBOX_DEFAULT_FEATURE_SORT_BIG
+	depends on BUSYBOX_CONFIG_SORT
+	help
+	  Without this, sort only supports -r, -u, and an integer version
+	  of -n. Selecting this adds sort keys, floating point support, and
+	  more. This adds a little over 3k to a nonstatic build on x86.
+
+	  The SuSv3 sort standard is available at:
+	  http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
+
+config BUSYBOX_CONFIG_SPLIT
+	bool "split"
+	default BUSYBOX_DEFAULT_SPLIT
+	help
+	  split a file into pieces.
+
+config BUSYBOX_CONFIG_FEATURE_SPLIT_FANCY
+	bool "Fancy extensions"
+	default BUSYBOX_DEFAULT_FEATURE_SPLIT_FANCY
+	depends on BUSYBOX_CONFIG_SPLIT
+	help
+	  Add support for features not required by SUSv3.
+	  Supports additional suffixes 'b' for 512 bytes,
+	  'g' for 1GiB for the -b option.
+
+config BUSYBOX_CONFIG_STTY
+	bool "stty"
+	default BUSYBOX_DEFAULT_STTY
+	help
+	  stty is used to change and print terminal line settings.
+
+config BUSYBOX_CONFIG_SUM
+	bool "sum"
+	default BUSYBOX_DEFAULT_SUM
+	help
+	  checksum and count the blocks in a file
+
+config BUSYBOX_CONFIG_TAC
+	bool "tac"
+	default BUSYBOX_DEFAULT_TAC
+	help
+	  tac is used to concatenate and print files in reverse.
+
+config BUSYBOX_CONFIG_TAIL
+	bool "tail"
+	default BUSYBOX_DEFAULT_TAIL
+	help
+	  tail is used to print the last specified number of lines
+	  from files.
+
+config BUSYBOX_CONFIG_FEATURE_FANCY_TAIL
+	bool "Enable extra tail options (-q, -s, -v, and -F)"
+	default BUSYBOX_DEFAULT_FEATURE_FANCY_TAIL
+	depends on BUSYBOX_CONFIG_TAIL
+	help
+	  The options (-q, -s, -v and -F) are provided by GNU tail, but
+	  are not specific in the SUSv3 standard.
+
+	    -q      Never output headers giving file names
+	    -s SEC  Wait SEC seconds between reads with -f
+	    -v      Always output headers giving file names
+	    -F      Same as -f, but keep retrying
+
+config BUSYBOX_CONFIG_TEE
+	bool "tee"
+	default BUSYBOX_DEFAULT_TEE
+	help
+	  tee is used to read from standard input and write
+	  to standard output and files.
+
+config BUSYBOX_CONFIG_FEATURE_TEE_USE_BLOCK_IO
+	bool "Enable block I/O (larger/faster) instead of byte I/O"
+	default BUSYBOX_DEFAULT_FEATURE_TEE_USE_BLOCK_IO
+	depends on BUSYBOX_CONFIG_TEE
+	help
+	  Enable this option for a faster tee, at expense of size.
+
+config BUSYBOX_CONFIG_TRUE
+	bool "true"
+	default BUSYBOX_DEFAULT_TRUE
+	help
+	  true returns an exit code of TRUE (0).
+
+config BUSYBOX_CONFIG_TTY
+	bool "tty"
+	default BUSYBOX_DEFAULT_TTY
+	help
+	  tty is used to print the name of the current terminal to
+	  standard output.
+
+config BUSYBOX_CONFIG_UNAME
+	bool "uname"
+	default BUSYBOX_DEFAULT_UNAME
+	help
+	  uname is used to print system information.
+
+config BUSYBOX_CONFIG_UNAME_OSNAME
+	string "Operating system name"
+	default BUSYBOX_DEFAULT_UNAME_OSNAME
+	depends on BUSYBOX_CONFIG_UNAME
+	help
+	  Sets the operating system name reported by uname -o.  The
+	  default BUSYBOX_DEFAULT_UNAME_OSNAME "GNU/Linux".
+
+config BUSYBOX_CONFIG_UNEXPAND
+	bool "unexpand"
+	default BUSYBOX_DEFAULT_UNEXPAND
+	help
+	  By default, convert only leading sequences of blanks to tabs.
+
+config BUSYBOX_CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_UNEXPAND_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_UNEXPAND && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the unexpand applet.
+
+config BUSYBOX_CONFIG_UNIQ
+	bool "uniq"
+	default BUSYBOX_DEFAULT_UNIQ
+	help
+	  uniq is used to remove duplicate lines from a sorted file.
+
+config BUSYBOX_CONFIG_USLEEP
+	bool "usleep"
+	default BUSYBOX_DEFAULT_USLEEP
+	help
+	  usleep is used to pause for a specified number of microseconds.
+
+config BUSYBOX_CONFIG_UUDECODE
+	bool "uudecode"
+	default BUSYBOX_DEFAULT_UUDECODE
+	help
+	  uudecode is used to decode a uuencoded file.
+
+config BUSYBOX_CONFIG_UUENCODE
+	bool "uuencode"
+	default BUSYBOX_DEFAULT_UUENCODE
+	help
+	  uuencode is used to uuencode a file.
+
+config BUSYBOX_CONFIG_WC
+	bool "wc"
+	default BUSYBOX_DEFAULT_WC
+	help
+	  wc is used to print the number of bytes, words, and lines,
+	  in specified files.
+
+config BUSYBOX_CONFIG_FEATURE_WC_LARGE
+	bool "Support very large files in wc"
+	default BUSYBOX_DEFAULT_FEATURE_WC_LARGE
+	depends on BUSYBOX_CONFIG_WC
+	help
+	  Use "unsigned long long" in wc for counter variables.
+
+config BUSYBOX_CONFIG_WHOAMI
+	bool "whoami"
+	default BUSYBOX_DEFAULT_WHOAMI
+	help
+	  whoami is used to print the username of the current
+	  user id (same as id -un).
+
+config BUSYBOX_CONFIG_YES
+	bool "yes"
+	default BUSYBOX_DEFAULT_YES
+	help
+	  yes is used to repeatedly output a specific string, or
+	  the default string `y'.
+
+comment "Common options"
+
+config BUSYBOX_CONFIG_FEATURE_VERBOSE
+	bool "Support verbose options (usually -v) for various applets"
+	default BUSYBOX_DEFAULT_FEATURE_VERBOSE
+	help
+	  Enable cp -v, rm -v and similar messages.
+	  Also enables long option (--verbose) if it exists.
+	  Without this option, -v is accepted but ignored.
+
+comment "Common options for cp and mv"
+	depends on BUSYBOX_CONFIG_CP || BUSYBOX_CONFIG_MV
+
+config BUSYBOX_CONFIG_FEATURE_PRESERVE_HARDLINKS
+	bool "Preserve hard links"
+	default BUSYBOX_DEFAULT_FEATURE_PRESERVE_HARDLINKS
+	depends on BUSYBOX_CONFIG_CP || BUSYBOX_CONFIG_MV
+	help
+	  Allow cp and mv to preserve hard links.
+
+comment "Common options for ls, more and telnet"
+	depends on BUSYBOX_CONFIG_LS || BUSYBOX_CONFIG_MORE || BUSYBOX_CONFIG_TELNET
+
+config BUSYBOX_CONFIG_FEATURE_AUTOWIDTH
+	bool "Calculate terminal & column widths"
+	default BUSYBOX_DEFAULT_FEATURE_AUTOWIDTH
+	depends on BUSYBOX_CONFIG_LS || BUSYBOX_CONFIG_MORE || BUSYBOX_CONFIG_TELNET
+	help
+	  This option allows utilities such as 'ls', 'more' and 'telnet'
+	  to determine the width of the screen, which can allow them to
+	  display additional text or avoid wrapping text onto the next line.
+	  If you leave this disabled, your utilities will be especially
+	  primitive and will be unable to determine the current screen width.
+
+comment "Common options for df, du, ls"
+	depends on BUSYBOX_CONFIG_DF || BUSYBOX_CONFIG_DU || BUSYBOX_CONFIG_LS
+
+config BUSYBOX_CONFIG_FEATURE_HUMAN_READABLE
+	bool "Support for human readable output (example 13k, 23M, 235G)"
+	default BUSYBOX_DEFAULT_FEATURE_HUMAN_READABLE
+	depends on BUSYBOX_CONFIG_DF || BUSYBOX_CONFIG_DU || BUSYBOX_CONFIG_LS
+	help
+	  Allow df, du, and ls to have human readable output.
+
+comment "Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum"
+	depends on BUSYBOX_CONFIG_MD5SUM || BUSYBOX_CONFIG_SHA1SUM || BUSYBOX_CONFIG_SHA256SUM || BUSYBOX_CONFIG_SHA512SUM || BUSYBOX_CONFIG_SHA3SUM
+
+config BUSYBOX_CONFIG_FEATURE_MD5_SHA1_SUM_CHECK
+	bool "Enable -c, -s and -w options"
+	default BUSYBOX_DEFAULT_FEATURE_MD5_SHA1_SUM_CHECK
+	depends on BUSYBOX_CONFIG_MD5SUM || BUSYBOX_CONFIG_SHA1SUM || BUSYBOX_CONFIG_SHA256SUM || BUSYBOX_CONFIG_SHA512SUM || BUSYBOX_CONFIG_SHA3SUM
+	help
+	  Enabling the -c options allows files to be checked
+	  against pre-calculated hash values.
+
+	  -s and -w are useful options when verifying checksums.
+
+endmenu
diff --git a/package/utils/busybox/config/debianutils/Config.in b/package/utils/busybox/config/debianutils/Config.in
new file mode 100644
index 0000000000..d39c60f43e
--- /dev/null
+++ b/package/utils/busybox/config/debianutils/Config.in
@@ -0,0 +1,80 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Debian Utilities"
+
+config BUSYBOX_CONFIG_MKTEMP
+	bool "mktemp"
+	default BUSYBOX_DEFAULT_MKTEMP
+	help
+	  mktemp is used to create unique temporary files
+config BUSYBOX_CONFIG_PIPE_PROGRESS
+	bool "pipe_progress"
+	default BUSYBOX_DEFAULT_PIPE_PROGRESS
+	help
+	  Display a dot to indicate pipe activity.
+config BUSYBOX_CONFIG_RUN_PARTS
+	bool "run-parts"
+	default BUSYBOX_DEFAULT_RUN_PARTS
+	help
+	  run-parts is a utility designed to run all the scripts in a directory.
+
+	  It is useful to set up a directory like cron.daily, where you need to
+	  execute all the scripts in that directory.
+
+	  In this implementation of run-parts some features (such as report
+	  mode) are not implemented.
+
+	  Unless you know that run-parts is used in some of your scripts
+	  you can safely say N here.
+
+config BUSYBOX_CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_RUN_PARTS_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_RUN_PARTS && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the run-parts applet.
+
+config BUSYBOX_CONFIG_FEATURE_RUN_PARTS_FANCY
+	bool "Support additional arguments"
+	default BUSYBOX_DEFAULT_FEATURE_RUN_PARTS_FANCY
+	depends on BUSYBOX_CONFIG_RUN_PARTS
+	help
+	  Support additional options:
+	  -l --list print the names of the all matching files (not
+	            limited to executables), but don't actually run them.
+config BUSYBOX_CONFIG_START_STOP_DAEMON
+	bool "start-stop-daemon"
+	default BUSYBOX_DEFAULT_START_STOP_DAEMON
+	help
+	  start-stop-daemon is used to control the creation and
+	  termination of system-level processes, usually the ones
+	  started during the startup of the system.
+
+config BUSYBOX_CONFIG_FEATURE_START_STOP_DAEMON_FANCY
+	bool "Support additional arguments"
+	default BUSYBOX_DEFAULT_FEATURE_START_STOP_DAEMON_FANCY
+	depends on BUSYBOX_CONFIG_START_STOP_DAEMON
+	help
+	  Support additional arguments.
+	  -o|--oknodo ignored since we exit with 0 anyway
+	  -v|--verbose
+	  -N|--nicelevel N
+
+config BUSYBOX_CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_START_STOP_DAEMON && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the start-stop-daemon applet.
+config BUSYBOX_CONFIG_WHICH
+	bool "which"
+	default BUSYBOX_DEFAULT_WHICH
+	help
+	  which is used to find programs in your PATH and
+	  print out their pathnames.
+
+endmenu
diff --git a/package/utils/busybox/config/e2fsprogs/Config.in b/package/utils/busybox/config/e2fsprogs/Config.in
new file mode 100644
index 0000000000..df255481c3
--- /dev/null
+++ b/package/utils/busybox/config/e2fsprogs/Config.in
@@ -0,0 +1,67 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux Ext2 FS Progs"
+
+config BUSYBOX_CONFIG_CHATTR
+	bool "chattr"
+	default BUSYBOX_DEFAULT_CHATTR
+	help
+	  chattr changes the file attributes on a second extended file system.
+config BUSYBOX_CONFIG_FSCK
+	bool "fsck"
+	default BUSYBOX_DEFAULT_FSCK
+	help
+	  fsck is used to check and optionally repair one or more filesystems.
+	  In actuality, fsck is simply a front-end for the various file system
+	  checkers (fsck.fstype) available under Linux.
+config BUSYBOX_CONFIG_LSATTR
+	bool "lsattr"
+	default BUSYBOX_DEFAULT_LSATTR
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  lsattr lists the file attributes on a second extended file system.
+config BUSYBOX_CONFIG_TUNE2FS
+	bool "tune2fs"
+	default BUSYBOX_DEFAULT_TUNE2FS  # off: it is too limited compared to upstream version
+	help
+	  tune2fs allows the system administrator to adjust various tunable
+	  filesystem parameters on Linux ext2/ext3 filesystems.
+
+### config E2FSCK
+###	bool "e2fsck"
+###	default y
+###	help
+###	  e2fsck is used to check Linux second extended file systems (ext2fs).
+###	  e2fsck also supports ext2 filesystems countaining a journal (ext3).
+###	  The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also
+###	  provided.
+
+### config MKE2FS
+###	bool "mke2fs"
+###	default y
+###	help
+###	  mke2fs is used to create an ext2/ext3 filesystem. The normal compat
+###	  symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
+
+### config E2LABEL
+###	bool "e2label"
+###	default y
+###	depends on TUNE2FS
+###	help
+###	  e2label will display or change the filesystem label on the ext2
+###	  filesystem located on device.
+
+### NB: this one is now provided by util-linux/volume_id/*
+### config FINDFS
+###	bool "findfs"
+###	default y
+###	depends on TUNE2FS
+###	help
+###	  findfs will search the disks in the system looking for a filesystem
+###	  which has a label matching label or a UUID equal to uuid.
+
+endmenu
diff --git a/package/utils/busybox/config/e2fsprogs/old_e2fsprogs/Config.in b/package/utils/busybox/config/e2fsprogs/old_e2fsprogs/Config.in
new file mode 100644
index 0000000000..d7a5396deb
--- /dev/null
+++ b/package/utils/busybox/config/e2fsprogs/old_e2fsprogs/Config.in
@@ -0,0 +1,69 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux Ext2 FS Progs"
+
+
+config BUSYBOX_CONFIG_CHATTR
+	bool "chattr"
+	default BUSYBOX_DEFAULT_CHATTR
+	help
+	  chattr changes the file attributes on a second extended file system.
+
+config BUSYBOX_CONFIG_E2FSCK
+	bool "e2fsck"
+	default BUSYBOX_DEFAULT_E2FSCK
+	help
+	  e2fsck is used to check Linux second extended file systems (ext2fs).
+	  e2fsck also supports ext2 filesystems countaining a journal (ext3).
+	  The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also
+	  provided.
+
+config BUSYBOX_CONFIG_FSCK
+	bool "fsck"
+	default BUSYBOX_DEFAULT_FSCK
+	help
+	  fsck is used to check and optionally repair one or more filesystems.
+	  In actuality, fsck is simply a front-end for the various file system
+	  checkers (fsck.fstype) available under Linux.
+
+config BUSYBOX_CONFIG_LSATTR
+	bool "lsattr"
+	default BUSYBOX_DEFAULT_LSATTR
+	help
+	  lsattr lists the file attributes on a second extended file system.
+
+config BUSYBOX_CONFIG_MKE2FS
+	bool "mke2fs"
+	default BUSYBOX_DEFAULT_MKE2FS
+	help
+	  mke2fs is used to create an ext2/ext3 filesystem. The normal compat
+	  symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
+
+config BUSYBOX_CONFIG_TUNE2FS
+	bool "tune2fs"
+	default BUSYBOX_DEFAULT_TUNE2FS
+	help
+	  tune2fs allows the system administrator to adjust various tunable
+	  filesystem parameters on Linux ext2/ext3 filesystems.
+
+config BUSYBOX_CONFIG_E2LABEL
+	bool "e2label"
+	default BUSYBOX_DEFAULT_E2LABEL
+	depends on BUSYBOX_CONFIG_TUNE2FS
+	help
+	  e2label will display or change the filesystem label on the ext2
+	  filesystem located on device.
+
+config BUSYBOX_CONFIG_FINDFS
+	bool "findfs"
+	default BUSYBOX_DEFAULT_FINDFS
+	depends on BUSYBOX_CONFIG_TUNE2FS
+	help
+	  findfs will search the disks in the system looking for a filesystem
+	  which has a label matching label or a UUID equal to uuid.
+
+endmenu
diff --git a/package/utils/busybox/config/editors/Config.in b/package/utils/busybox/config/editors/Config.in
new file mode 100644
index 0000000000..6ae361f7ff
--- /dev/null
+++ b/package/utils/busybox/config/editors/Config.in
@@ -0,0 +1,234 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Editors"
+
+config BUSYBOX_CONFIG_AWK
+	bool "awk"
+	default BUSYBOX_DEFAULT_AWK
+	help
+	  Awk is used as a pattern scanning and processing language. This is
+	  the BusyBox implementation of that programming language.
+
+config BUSYBOX_CONFIG_FEATURE_AWK_LIBM
+	bool "Enable math functions (requires libm)"
+	default BUSYBOX_DEFAULT_FEATURE_AWK_LIBM
+	depends on BUSYBOX_CONFIG_AWK
+	help
+	  Enable math functions of the Awk programming language.
+	  NOTE: This will require libm to be present for linking.
+
+config BUSYBOX_CONFIG_FEATURE_AWK_GNU_EXTENSIONS
+	bool "Enable a few GNU extensions"
+	default BUSYBOX_DEFAULT_FEATURE_AWK_GNU_EXTENSIONS
+	depends on BUSYBOX_CONFIG_AWK
+	help
+	  Enable a few features from gawk:
+	  * command line option -e AWK_PROGRAM
+	  * simultaneous use of -f and -e on the command line.
+	    This enables the use of awk library files.
+	    Ex: awk -f mylib.awk -e '{print myfunction($1);}' ...
+config BUSYBOX_CONFIG_CMP
+	bool "cmp"
+	default BUSYBOX_DEFAULT_CMP
+	help
+	  cmp is used to compare two files and returns the result
+	  to standard output.
+config BUSYBOX_CONFIG_DIFF
+	bool "diff"
+	default BUSYBOX_DEFAULT_DIFF
+	help
+	  diff compares two files or directories and outputs the
+	  differences between them in a form that can be given to
+	  the patch command.
+
+config BUSYBOX_CONFIG_FEATURE_DIFF_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_DIFF_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_DIFF && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Enable use of long options.
+
+config BUSYBOX_CONFIG_FEATURE_DIFF_DIR
+	bool "Enable directory support"
+	default BUSYBOX_DEFAULT_FEATURE_DIFF_DIR
+	depends on BUSYBOX_CONFIG_DIFF
+	help
+	  This option enables support for directory and subdirectory
+	  comparison.
+config BUSYBOX_CONFIG_ED
+	bool "ed"
+	default BUSYBOX_DEFAULT_ED
+	help
+	  The original 1970's Unix text editor, from the days of teletypes.
+	  Small, simple, evil. Part of SUSv3. If you're not already using
+	  this, you don't need it.
+config BUSYBOX_CONFIG_PATCH
+	bool "patch"
+	default BUSYBOX_DEFAULT_PATCH
+	help
+	  Apply a unified diff formatted patch.
+config BUSYBOX_CONFIG_SED
+	bool "sed"
+	default BUSYBOX_DEFAULT_SED
+	help
+	  sed is used to perform text transformations on a file
+	  or input from a pipeline.
+config BUSYBOX_CONFIG_VI
+	bool "vi"
+	default BUSYBOX_DEFAULT_VI
+	help
+	  'vi' is a text editor. More specifically, it is the One True
+	  text editor <grin>. It does, however, have a rather steep
+	  learning curve. If you are not already comfortable with 'vi'
+	  you may wish to use something else.
+
+config BUSYBOX_CONFIG_FEATURE_VI_MAX_LEN
+	int "Maximum screen width in vi"
+	range 256 16384
+	default BUSYBOX_DEFAULT_FEATURE_VI_MAX_LEN
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Contrary to what you may think, this is not eating much.
+	  Make it smaller than 4k only if you are very limited on memory.
+
+config BUSYBOX_CONFIG_FEATURE_VI_8BIT
+	bool "Allow vi to display 8-bit chars (otherwise shows dots)"
+	default BUSYBOX_DEFAULT_FEATURE_VI_8BIT
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  If your terminal can display characters with high bit set,
+	  you may want to enable this. Note: vi is not Unicode-capable.
+	  If your terminal combines several 8-bit bytes into one character
+	  (as in Unicode mode), this will not work properly.
+
+config BUSYBOX_CONFIG_FEATURE_VI_COLON
+	bool "Enable \":\" colon commands (no \"ex\" mode)"
+	default BUSYBOX_DEFAULT_FEATURE_VI_COLON
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Enable a limited set of colon commands for vi. This does not
+	  provide an "ex" mode.
+
+config BUSYBOX_CONFIG_FEATURE_VI_YANKMARK
+	bool "Enable yank/put commands and mark cmds"
+	default BUSYBOX_DEFAULT_FEATURE_VI_YANKMARK
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  This will enable you to use yank and put, as well as mark in
+	  busybox vi.
+
+config BUSYBOX_CONFIG_FEATURE_VI_SEARCH
+	bool "Enable search and replace cmds"
+	default BUSYBOX_DEFAULT_FEATURE_VI_SEARCH
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Select this if you wish to be able to do search and replace in
+	  busybox vi.
+
+config BUSYBOX_CONFIG_FEATURE_VI_REGEX_SEARCH
+	bool "Enable regex in search and replace"
+	default BUSYBOX_DEFAULT_FEATURE_VI_REGEX_SEARCH   # Uses GNU regex, which may be unavailable. FIXME
+	depends on BUSYBOX_CONFIG_FEATURE_VI_SEARCH
+	help
+	  Use extended regex search.
+
+config BUSYBOX_CONFIG_FEATURE_VI_USE_SIGNALS
+	bool "Catch signals"
+	default BUSYBOX_DEFAULT_FEATURE_VI_USE_SIGNALS
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Selecting this option will make busybox vi signal aware. This will
+	  make busybox vi support SIGWINCH to deal with Window Changes, catch
+	  Ctrl-Z and Ctrl-C and alarms.
+
+config BUSYBOX_CONFIG_FEATURE_VI_DOT_CMD
+	bool "Remember previous cmd and \".\" cmd"
+	default BUSYBOX_DEFAULT_FEATURE_VI_DOT_CMD
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Make busybox vi remember the last command and be able to repeat it.
+
+config BUSYBOX_CONFIG_FEATURE_VI_READONLY
+	bool "Enable -R option and \"view\" mode"
+	default BUSYBOX_DEFAULT_FEATURE_VI_READONLY
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Enable the read-only command line option, which allows the user to
+	  open a file in read-only mode.
+
+config BUSYBOX_CONFIG_FEATURE_VI_SETOPTS
+	bool "Enable set-able options, ai ic showmatch"
+	default BUSYBOX_DEFAULT_FEATURE_VI_SETOPTS
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Enable the editor to set some (ai, ic, showmatch) options.
+
+config BUSYBOX_CONFIG_FEATURE_VI_SET
+	bool "Support for :set"
+	default BUSYBOX_DEFAULT_FEATURE_VI_SET
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Support for ":set".
+
+config BUSYBOX_CONFIG_FEATURE_VI_WIN_RESIZE
+	bool "Handle window resize"
+	default BUSYBOX_DEFAULT_FEATURE_VI_WIN_RESIZE
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Make busybox vi behave nicely with terminals that get resized.
+
+config BUSYBOX_CONFIG_FEATURE_VI_ASK_TERMINAL
+	bool "Use 'tell me cursor position' ESC sequence to measure window"
+	default BUSYBOX_DEFAULT_FEATURE_VI_ASK_TERMINAL
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
+	  this option makes vi perform a last-ditch effort to find it:
+	  position cursor to 999,999 and ask terminal to report real
+	  cursor position using "ESC [ 6 n" escape sequence, then read stdin.
+
+	  This is not clean but helps a lot on serial lines and such.
+config BUSYBOX_CONFIG_FEATURE_VI_UNDO
+	bool "Support undo command 'u'"
+	default BUSYBOX_DEFAULT_FEATURE_VI_UNDO
+	depends on BUSYBOX_CONFIG_VI
+	help
+	  Support the 'u' command to undo insertion, deletion, and replacement
+	  of text.
+config BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE
+	bool "Enable undo operation queuing"
+	default BUSYBOX_DEFAULT_FEATURE_VI_UNDO_QUEUE
+	depends on BUSYBOX_CONFIG_FEATURE_VI_UNDO
+	help
+	  The vi undo functions can use an intermediate queue to greatly lower
+	  malloc() calls and overhead. When the maximum size of this queue is
+	  reached, the contents of the queue are committed to the undo stack.
+	  This increases the size of the undo code and allows some undo
+	  operations (especially un-typing/backspacing) to be far more useful.
+config BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE_MAX
+	int "Maximum undo character queue size"
+	default BUSYBOX_DEFAULT_FEATURE_VI_UNDO_QUEUE_MAX
+	range 32 65536
+	depends on BUSYBOX_CONFIG_FEATURE_VI_UNDO_QUEUE
+	help
+	  This option sets the number of bytes used at runtime for the queue.
+	  Smaller values will create more undo objects and reduce the amount
+	  of typed or backspaced characters that are grouped into one undo
+	  operation; larger values increase the potential size of each undo
+	  and will generally malloc() larger objects and less frequently.
+	  Unless you want more (or less) frequent "undo points" while typing,
+	  you should probably leave this unchanged.
+
+config BUSYBOX_CONFIG_FEATURE_ALLOW_EXEC
+	bool "Allow vi and awk to execute shell commands"
+	default BUSYBOX_DEFAULT_FEATURE_ALLOW_EXEC
+	depends on BUSYBOX_CONFIG_VI || BUSYBOX_CONFIG_AWK
+	help
+	  Enables vi and awk features which allows user to execute
+	  shell commands (using system() C call).
+
+endmenu
diff --git a/package/utils/busybox/config/findutils/Config.in b/package/utils/busybox/config/findutils/Config.in
new file mode 100644
index 0000000000..85ee1db2c3
--- /dev/null
+++ b/package/utils/busybox/config/findutils/Config.in
@@ -0,0 +1,269 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Finding Utilities"
+
+config BUSYBOX_CONFIG_FIND
+	bool "find"
+	default BUSYBOX_DEFAULT_FIND
+	help
+	  find is used to search your system to find specified files.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_PRINT0
+	bool "Enable -print0: NUL-terminated output"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_PRINT0
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Causes output names to be separated by a NUL character
+	  rather than a newline. This allows names that contain
+	  newlines and other whitespace to be more easily
+	  interpreted by other programs.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_MTIME
+	bool "Enable -mtime: modified time matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_MTIME
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Allow searching based on the modification time of
+	  files, in days.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_MMIN
+	bool "Enable -mmin: modified time matching by minutes"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_MMIN
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Allow searching based on the modification time of
+	  files, in minutes.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_PERM
+	bool "Enable -perm: permissions matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_PERM
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Enable searching based on file permissions.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_TYPE
+	bool "Enable -type: file type matching (file/dir/link/...)"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_TYPE
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Enable searching based on file type (file,
+	  directory, socket, device, etc.).
+
+config BUSYBOX_CONFIG_FEATURE_FIND_XDEV
+	bool "Enable -xdev: 'stay in filesystem'"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_XDEV
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  This option allows find to restrict searches to a single filesystem.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_MAXDEPTH
+	bool "Enable -mindepth N and -maxdepth N"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_MAXDEPTH
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  This option enables -mindepth N and -maxdepth N option.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_NEWER
+	bool "Enable -newer: compare file modification times"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_NEWER
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -newer' option for finding any files which have
+	  modification time that is more recent than the specified FILE.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_INUM
+	bool "Enable -inum: inode number matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_INUM
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -inum' option for searching by inode number.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_EXEC
+	bool "Enable -exec: execute commands"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_EXEC
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -exec' option for executing commands based upon
+	  the files matched.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_EXEC_PLUS
+	bool "Enable -exec ... {} +"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_EXEC_PLUS
+	depends on BUSYBOX_CONFIG_FEATURE_FIND_EXEC
+	help
+	  Support the 'find -exec ... {} +' option for executing commands
+	  for all matched files at once.
+	  Without this option, -exec + is a synonym for -exec ;
+	  (IOW: it works correctly, but without expected speedup)
+
+config BUSYBOX_CONFIG_FEATURE_FIND_USER
+	bool "Enable -user: username/uid matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_USER
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -user' option for searching by username or uid.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_GROUP
+	bool "Enable -group: group/gid matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_GROUP
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -group' option for searching by group name or gid.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_NOT
+	bool "Enable the 'not' (!) operator"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_NOT
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the '!' operator to invert the test results.
+	  If 'Enable full-blown desktop' is enabled, then will also support
+	  the non-POSIX notation '-not'.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_DEPTH
+	bool "Enable -depth"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_DEPTH
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Process each directory's contents before the directory itself.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_PAREN
+	bool "Enable parens in options"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_PAREN
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Enable usage of parens '(' to specify logical order of arguments.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_SIZE
+	bool "Enable -size: file size matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_SIZE
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -size' option for searching by file size.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_PRUNE
+	bool "Enable -prune: exclude subdirectories"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_PRUNE
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  If the file is a directory, dont descend into it. Useful for
+	  exclusion .svn and CVS directories.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_DELETE
+	bool "Enable -delete: delete files/dirs"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_DELETE
+	depends on BUSYBOX_CONFIG_FIND && BUSYBOX_CONFIG_FEATURE_FIND_DEPTH
+	help
+	  Support the 'find -delete' option for deleting files and directories.
+	  WARNING: This option can do much harm if used wrong. Busybox will not
+	  try to protect the user from doing stupid things. Use with care.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_PATH
+	bool "Enable -path: match pathname with shell pattern"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_PATH
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  The -path option matches whole pathname instead of just filename.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_REGEX
+	bool "Enable -regex: match pathname with regex"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_REGEX
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  The -regex option matches whole pathname against regular expression.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_CONTEXT
+	bool "Enable -context: security context matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_CONTEXT
+	depends on BUSYBOX_CONFIG_FIND && BUSYBOX_CONFIG_SELINUX
+	help
+	  Support the 'find -context' option for matching security context.
+
+config BUSYBOX_CONFIG_FEATURE_FIND_LINKS
+	bool "Enable -links: link count matching"
+	default BUSYBOX_DEFAULT_FEATURE_FIND_LINKS
+	depends on BUSYBOX_CONFIG_FIND
+	help
+	  Support the 'find -links' option for matching number of links.
+config BUSYBOX_CONFIG_GREP
+	bool "grep"
+	default BUSYBOX_DEFAULT_GREP
+	help
+	  grep is used to search files for a specified pattern.
+
+config BUSYBOX_CONFIG_FEATURE_GREP_EGREP_ALIAS
+	bool "Enable extended regular expressions (egrep & grep -E)"
+	default BUSYBOX_DEFAULT_FEATURE_GREP_EGREP_ALIAS
+	depends on BUSYBOX_CONFIG_GREP
+	help
+	  Enabled support for extended regular expressions. Extended
+	  regular expressions allow for alternation (foo|bar), grouping,
+	  and various repetition operators.
+
+config BUSYBOX_CONFIG_FEATURE_GREP_FGREP_ALIAS
+	bool "Alias fgrep to grep -F"
+	default BUSYBOX_DEFAULT_FEATURE_GREP_FGREP_ALIAS
+	depends on BUSYBOX_CONFIG_GREP
+	help
+	  fgrep sees the search pattern as a normal string rather than
+	  regular expressions.
+	  grep -F always works, this just creates the fgrep alias.
+
+config BUSYBOX_CONFIG_FEATURE_GREP_CONTEXT
+	bool "Enable before and after context flags (-A, -B and -C)"
+	default BUSYBOX_DEFAULT_FEATURE_GREP_CONTEXT
+	depends on BUSYBOX_CONFIG_GREP
+	help
+	  Print the specified number of leading (-B) and/or trailing (-A)
+	  context surrounding our matching lines.
+	  Print the specified number of context lines (-C).
+config BUSYBOX_CONFIG_XARGS
+	bool "xargs"
+	default BUSYBOX_DEFAULT_XARGS
+	help
+	  xargs is used to execute a specified command for
+	  every item from standard input.
+
+config BUSYBOX_CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
+	bool "Enable -p: prompt and confirmation"
+	default BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_CONFIRMATION
+	depends on BUSYBOX_CONFIG_XARGS
+	help
+	  Support -p: prompt the user whether to run each command
+	  line and read a line from the terminal.
+
+config BUSYBOX_CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
+	bool "Enable single and double quotes and backslash"
+	default BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_QUOTES
+	depends on BUSYBOX_CONFIG_XARGS
+	help
+	  Support quoting in the input.
+
+config BUSYBOX_CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
+	bool "Enable -x: exit if -s or -n is exceeded"
+	default BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_TERMOPT
+	depends on BUSYBOX_CONFIG_XARGS
+	help
+	  Support -x: exit if the command size (see the -s or -n option)
+	  is exceeded.
+
+config BUSYBOX_CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
+	bool "Enable -0: NUL-terminated input"
+	default BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_ZERO_TERM
+	depends on BUSYBOX_CONFIG_XARGS
+	help
+	  Support -0: input items are terminated by a NUL character
+	  instead of whitespace, and the quotes and backslash
+	  are not special.
+
+config BUSYBOX_CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR
+	bool "Enable -I STR: string to replace"
+	default BUSYBOX_DEFAULT_FEATURE_XARGS_SUPPORT_REPL_STR
+	depends on BUSYBOX_CONFIG_XARGS
+	help
+	  Support -I STR and -i[STR] options.
+
+endmenu
diff --git a/package/utils/busybox/config/init/Config.in b/package/utils/busybox/config/init/Config.in
new file mode 100644
index 0000000000..021656d3f9
--- /dev/null
+++ b/package/utils/busybox/config/init/Config.in
@@ -0,0 +1,199 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Init Utilities"
+
+config BUSYBOX_CONFIG_BOOTCHARTD
+	bool "bootchartd"
+	default BUSYBOX_DEFAULT_BOOTCHARTD
+	help
+	  bootchartd is commonly used to profile the boot process
+	  for the purpose of speeding it up. In this case, it is started
+	  by the kernel as the init process. This is configured by adding
+	  the init=/sbin/bootchartd option to the kernel command line.
+
+	  It can also be used to monitor the resource usage of a specific
+	  application or the running system in general. In this case,
+	  bootchartd is started interactively by running bootchartd start
+	  and stopped using bootchartd stop.
+
+config BUSYBOX_CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER
+	bool "Compatible, bloated header"
+	default BUSYBOX_DEFAULT_FEATURE_BOOTCHARTD_BLOATED_HEADER
+	depends on BUSYBOX_CONFIG_BOOTCHARTD
+	help
+	  Create extended header file compatible with "big" bootchartd.
+	  "Big" bootchartd is a shell script and it dumps some
+	  "convenient" info int the header, such as:
+	    title = Boot chart for `hostname` (`date`)
+	    system.uname = `uname -srvm`
+	    system.release = `cat /etc/DISTRO-release`
+	    system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
+	    system.kernel.options = `cat /proc/cmdline`
+	  This data is not mandatory for bootchart graph generation,
+	  and is considered bloat. Nevertheless, this option
+	  makes bootchartd applet to dump a subset of it.
+
+config BUSYBOX_CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE
+	bool "Support bootchartd.conf"
+	default BUSYBOX_DEFAULT_FEATURE_BOOTCHARTD_CONFIG_FILE
+	depends on BUSYBOX_CONFIG_BOOTCHARTD
+	help
+	  Enable reading and parsing of $PWD/bootchartd.conf
+	  and /etc/bootchartd.conf files.
+config BUSYBOX_CONFIG_HALT
+	bool "poweroff, halt, and reboot"
+	default BUSYBOX_DEFAULT_HALT
+	help
+	  Stop all processes and either halt, reboot, or power off the system.
+
+config BUSYBOX_CONFIG_FEATURE_CALL_TELINIT
+	bool "Call telinit on shutdown and reboot"
+	default BUSYBOX_DEFAULT_FEATURE_CALL_TELINIT
+	depends on BUSYBOX_CONFIG_HALT && !BUSYBOX_CONFIG_INIT
+	help
+	  Call an external program (normally telinit) to facilitate
+	  a switch to a proper runlevel.
+
+	  This option is only available if you selected halt and friends,
+	  but did not select init.
+
+config BUSYBOX_CONFIG_TELINIT_PATH
+	string "Path to telinit executable"
+	default BUSYBOX_DEFAULT_TELINIT_PATH
+	depends on BUSYBOX_CONFIG_FEATURE_CALL_TELINIT
+	help
+	  When busybox halt and friends have to call external telinit
+	  to facilitate proper shutdown, this path is to be used when
+	  locating telinit executable.
+config BUSYBOX_CONFIG_INIT
+	bool "init"
+	default BUSYBOX_DEFAULT_INIT
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  init is the first program run when the system boots.
+
+config BUSYBOX_CONFIG_LINUXRC
+	bool "Support running init from within an initrd (not initramfs)"
+	default BUSYBOX_DEFAULT_LINUXRC
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  Legacy support for running init under the old-style initrd. Allows
+	  the name linuxrc to act as init, and it doesn't assume init is PID 1.
+
+	  This does not apply to initramfs, which runs /init as PID 1 and
+	  requires no special support.
+
+config BUSYBOX_CONFIG_FEATURE_USE_INITTAB
+	bool "Support reading an inittab file"
+	default BUSYBOX_DEFAULT_FEATURE_USE_INITTAB
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+	help
+	  Allow init to read an inittab file when the system boot.
+
+config BUSYBOX_CONFIG_FEATURE_KILL_REMOVED
+	bool "Support killing processes that have been removed from inittab"
+	default BUSYBOX_DEFAULT_FEATURE_KILL_REMOVED
+	depends on BUSYBOX_CONFIG_FEATURE_USE_INITTAB
+	help
+	  When respawn entries are removed from inittab and a SIGHUP is
+	  sent to init, this option will make init kill the processes
+	  that have been removed.
+
+config BUSYBOX_CONFIG_FEATURE_KILL_DELAY
+	int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED
+	range 0 1024
+	default BUSYBOX_DEFAULT_FEATURE_KILL_DELAY
+	depends on BUSYBOX_CONFIG_FEATURE_KILL_REMOVED
+	help
+	  With nonzero setting, init sends TERM, forks, child waits N
+	  seconds, sends KILL and exits. Setting it too high is unwise
+	  (child will hang around for too long and could actually kill
+	  the wrong process!)
+
+config BUSYBOX_CONFIG_FEATURE_INIT_SCTTY
+	bool "Run commands with leading dash with controlling tty"
+	default BUSYBOX_DEFAULT_FEATURE_INIT_SCTTY
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+	help
+	  If this option is enabled, init will try to give a controlling
+	  tty to any command which has leading hyphen (often it's "-/bin/sh").
+	  More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
+	  If device attached to STDIN_FILENO can be a ctty but is not yet
+	  a ctty for other session, it will become this process' ctty.
+	  This is not the traditional init behavour, but is often what you want
+	  in an embedded system where the console is only accessed during
+	  development or for maintenance.
+	  NB: using cttyhack applet may work better.
+
+config BUSYBOX_CONFIG_FEATURE_INIT_SYSLOG
+	bool "Enable init to write to syslog"
+	default BUSYBOX_DEFAULT_FEATURE_INIT_SYSLOG
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+
+config BUSYBOX_CONFIG_FEATURE_EXTRA_QUIET
+	bool "Be _extra_ quiet on boot"
+	default BUSYBOX_DEFAULT_FEATURE_EXTRA_QUIET
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+	help
+	  Prevent init from logging some messages to the console during boot.
+
+config BUSYBOX_CONFIG_FEATURE_INIT_COREDUMPS
+	bool "Support dumping core for child processes (debugging only)"
+	default BUSYBOX_DEFAULT_FEATURE_INIT_COREDUMPS
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+	help
+	  If this option is enabled and the file /.init_enable_core
+	  exists, then init will call setrlimit() to allow unlimited
+	  core file sizes. If this option is disabled, processes
+	  will not generate any core files.
+
+config BUSYBOX_CONFIG_INIT_TERMINAL_TYPE
+	string "Initial terminal type"
+	default BUSYBOX_DEFAULT_INIT_TERMINAL_TYPE
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+	help
+	  This is the initial value set by init for the TERM environment
+	  variable. This variable is used by programs which make use of
+	  extended terminal capabilities.
+
+	  Note that on Linux, init attempts to detect serial terminal and
+	  sets TERM to "vt102" if one is found.
+
+config BUSYBOX_CONFIG_FEATURE_INIT_MODIFY_CMDLINE
+	bool "Modify the command-line to \"init\""
+	default BUSYBOX_DEFAULT_FEATURE_INIT_MODIFY_CMDLINE
+	depends on BUSYBOX_CONFIG_INIT || BUSYBOX_CONFIG_LINUXRC
+	help
+	  When launched as PID 1 and after parsing its arguments, init
+	  wipes all the arguments but argv[0] and rewrites argv[0] to
+	  contain only "init", so that its command-line appears solely as
+	  "init" in tools such as ps.
+	  If this option is set to Y, init will keep its original behavior,
+	  otherwise, all the arguments including argv[0] will be preserved,
+	  be they parsed or ignored by init.
+	  The original command-line used to launch init can then be
+	  retrieved in /proc/1/cmdline on Linux, for example.
+config BUSYBOX_CONFIG_MESG
+	bool "mesg"
+	default BUSYBOX_DEFAULT_MESG
+	help
+	  Mesg controls access to your terminal by others. It is typically
+	  used to allow or disallow other users to write to your terminal
+
+config BUSYBOX_CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP
+	bool "Enable writing to tty only by group, not by everybody"
+	default BUSYBOX_DEFAULT_FEATURE_MESG_ENABLE_ONLY_GROUP
+	depends on BUSYBOX_CONFIG_MESG
+	help
+	  Usually, ttys are owned by group "tty", and "write" tool is
+	  setgid to this group. This way, "mesg y" only needs to enable
+	  "write by owning group" bit in tty mode.
+
+	  If you set this option to N, "mesg y" will enable writing
+	  by anybody at all. This is not recommended.
+
+endmenu
diff --git a/package/utils/busybox/config/libbb/Config.in b/package/utils/busybox/config/libbb/Config.in
new file mode 100644
index 0000000000..0695f9ba39
--- /dev/null
+++ b/package/utils/busybox/config/libbb/Config.in
@@ -0,0 +1,273 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Busybox Library Tuning"
+
+config BUSYBOX_CONFIG_FEATURE_USE_BSS_TAIL
+	bool "Use the end of BSS page"
+	default BUSYBOX_DEFAULT_FEATURE_USE_BSS_TAIL
+	help
+	  Attempt to reclaim a small unused part of BSS.
+
+	  Executables have the following parts:
+	  = read-only executable code and constants, also known as "text"
+	  = read-write data
+	  = non-initialized (zeroed on demand) data, also known as "bss"
+
+	  At link time, "text" is padded to a full page. At runtime, all "text"
+	  pages are mapped RO and executable.
+	  "Data" starts on the next page boundary, but is not padded
+	  to a full page at the end. "Bss" starts wherever "data" ends.
+	  At runtime, "data" pages are mapped RW and they are file-backed
+	  (this includes a small portion of "bss" which may live in the last
+	  partial page of "data").
+	  Pages which are fully in "bss" are mapped to anonymous memory.
+
+	  "Bss" end is usually not page-aligned. There is an unused space
+	  in the last page. Linker marks its start with the "_end" symbol.
+
+	  This option will attempt to use that space for bb_common_bufsiz1[]
+	  array. If it fits after _end, it will be used, and COMMON_BUFSIZE
+	  will be enlarged from its guaranteed minimum size of 1 kbyte.
+	  This may require recompilation a second time, since value of _end
+	  is known only after final link.
+
+	  If you are getting a build error like this:
+	        appletlib.c:(.text.main+0xd): undefined reference to '_end'
+	  disable this option.
+config BUSYBOX_CONFIG_FEATURE_RTMINMAX
+	bool "Support RTMIN[+n] and RTMAX[-n] signal names"
+	default BUSYBOX_DEFAULT_FEATURE_RTMINMAX
+	help
+	  Support RTMIN[+n] and RTMAX[-n] signal names
+	  in kill, killall etc. This costs ~250 bytes.
+
+config BUSYBOX_CONFIG_PASSWORD_MINLEN
+	int "Minimum password length"
+	default BUSYBOX_DEFAULT_PASSWORD_MINLEN
+	range 5 32
+	help
+	  Minimum allowable password length.
+
+config BUSYBOX_CONFIG_MD5_SMALL
+	int "MD5: Trade bytes for speed (0:fast, 3:slow)"
+	default BUSYBOX_DEFAULT_MD5_SMALL  # all "fast or small" options default to small
+	range 0 3
+	help
+	  Trade binary size versus speed for the md5sum algorithm.
+	  Approximate values running uClibc and hashing
+	  linux-2.4.4.tar.bz2 were:
+	                    user times (sec)  text size (386)
+	  0 (fastest)         1.1                6144
+	  1                   1.4                5392
+	  2                   3.0                5088
+	  3 (smallest)        5.1                4912
+
+config BUSYBOX_CONFIG_SHA3_SMALL
+	int "SHA3: Trade bytes for speed (0:fast, 1:slow)"
+	default BUSYBOX_DEFAULT_SHA3_SMALL  # all "fast or small" options default to small
+	range 0 1
+	help
+	  Trade binary size versus speed for the sha3sum algorithm.
+	  SHA3_SMALL=0 compared to SHA3_SMALL=1 (approximate):
+	  64-bit x86: +270 bytes of code, 45% faster
+	  32-bit x86: +450 bytes of code, 75% faster
+
+config BUSYBOX_CONFIG_FEATURE_FAST_TOP
+	bool "Faster /proc scanning code (+100 bytes)"
+	default BUSYBOX_DEFAULT_FEATURE_FAST_TOP  # all "fast or small" options default to small
+	help
+	  This option makes top (and ps) ~20% faster (or 20% less CPU hungry),
+	  but code size is slightly bigger.
+
+config BUSYBOX_CONFIG_FEATURE_ETC_NETWORKS
+	bool "Support for /etc/networks"
+	default BUSYBOX_DEFAULT_FEATURE_ETC_NETWORKS
+	help
+	  Enable support for network names in /etc/networks. This is
+	  a rarely used feature which allows you to use names
+	  instead of IP/mask pairs in route command.
+
+config BUSYBOX_CONFIG_FEATURE_USE_TERMIOS
+	bool "Use termios to manipulate the screen"
+	default BUSYBOX_DEFAULT_FEATURE_USE_TERMIOS
+	depends on BUSYBOX_CONFIG_MORE || BUSYBOX_CONFIG_TOP || BUSYBOX_CONFIG_POWERTOP
+	help
+	  This option allows utilities such as 'more' and 'top' to determine
+	  the size of the screen. If you leave this disabled, your utilities
+	  that display things on the screen will be especially primitive and
+	  will be unable to determine the current screen size, and will be
+	  unable to move the cursor.
+
+config BUSYBOX_CONFIG_FEATURE_EDITING
+	bool "Command line editing"
+	default BUSYBOX_DEFAULT_FEATURE_EDITING
+	help
+	  Enable line editing (mainly for shell command line).
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_MAX_LEN
+	int "Maximum length of input"
+	range 128 8192
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_MAX_LEN
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Line editing code uses on-stack buffers for storage.
+	  You may want to decrease this parameter if your target machine
+	  benefits from smaller stack usage.
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_VI
+	bool "vi-style line editing commands"
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_VI
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Enable vi-style line editing. In shells, this mode can be
+	  turned on and off with "set -o vi" and "set +o vi".
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_HISTORY
+	int "History size"
+	# Don't allow way too big values here, code uses fixed "char *history[N]" struct member
+	range 0 9999
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_HISTORY
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Specify command history size (0 - disable).
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY
+	bool "History saving"
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_SAVEHISTORY
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Enable history saving in shells.
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_SAVE_ON_EXIT
+	bool "Save history on shell exit, not after every command"
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_SAVE_ON_EXIT
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY
+	help
+	  Save history on shell exit, not after every command.
+
+config BUSYBOX_CONFIG_FEATURE_REVERSE_SEARCH
+	bool "Reverse history search"
+	default BUSYBOX_DEFAULT_FEATURE_REVERSE_SEARCH
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Enable readline-like Ctrl-R combination for reverse history search.
+	  Increases code by about 0.5k.
+
+config BUSYBOX_CONFIG_FEATURE_TAB_COMPLETION
+	bool "Tab completion"
+	default BUSYBOX_DEFAULT_FEATURE_TAB_COMPLETION
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Enable tab completion.
+
+config BUSYBOX_CONFIG_FEATURE_USERNAME_COMPLETION
+	bool "Username completion"
+	default BUSYBOX_DEFAULT_FEATURE_USERNAME_COMPLETION
+	depends on BUSYBOX_CONFIG_FEATURE_TAB_COMPLETION
+	help
+	  Enable username completion.
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_FANCY_PROMPT
+	bool "Fancy shell prompts"
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_FANCY_PROMPT
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Setting this option allows for prompts to use things like \w and
+	  \$ and escape codes.
+
+config BUSYBOX_CONFIG_FEATURE_EDITING_ASK_TERMINAL
+	bool "Query cursor position from terminal"
+	default BUSYBOX_DEFAULT_FEATURE_EDITING_ASK_TERMINAL
+	depends on BUSYBOX_CONFIG_FEATURE_EDITING
+	help
+	  Allow usage of "ESC [ 6 n" sequence. Terminal answers back with
+	  current cursor position. This information is used to make line
+	  editing more robust in some cases.
+	  If you are not sure whether your terminals respond to this code
+	  correctly, or want to save on code size (about 400 bytes),
+	  then do not turn this option on.
+
+config BUSYBOX_CONFIG_FEATURE_NON_POSIX_CP
+	bool "Non-POSIX, but safer, copying to special nodes"
+	default BUSYBOX_DEFAULT_FEATURE_NON_POSIX_CP
+	help
+	  With this option, "cp file symlink" will delete symlink
+	  and create a regular file. This does not conform to POSIX,
+	  but prevents a symlink attack.
+	  Similarly, "cp file device" will not send file's data
+	  to the device. (To do that, use "cat file >device")
+
+config BUSYBOX_CONFIG_FEATURE_VERBOSE_CP_MESSAGE
+	bool "Give more precise messages when copy fails (cp, mv etc)"
+	default BUSYBOX_DEFAULT_FEATURE_VERBOSE_CP_MESSAGE
+	help
+	  Error messages with this feature enabled:
+	    $ cp file /does_not_exist/file
+	    cp: cannot create '/does_not_exist/file': Path does not exist
+	    $ cp file /vmlinuz/file
+	    cp: cannot stat '/vmlinuz/file': Path has non-directory component
+	  If this feature is not enabled, they will be, respectively:
+	    cp: cannot create '/does_not_exist/file': No such file or directory
+	    cp: cannot stat '/vmlinuz/file': Not a directory
+	  This will cost you ~60 bytes.
+
+config BUSYBOX_CONFIG_FEATURE_COPYBUF_KB
+	int "Copy buffer size, in kilobytes"
+	range 1 1024
+	default BUSYBOX_DEFAULT_FEATURE_COPYBUF_KB
+	help
+	  Size of buffer used by cp, mv, install, wget etc.
+	  Buffers which are 4 kb or less will be allocated on stack.
+	  Bigger buffers will be allocated with mmap, with fallback to 4 kb
+	  stack buffer if mmap fails.
+
+config BUSYBOX_CONFIG_FEATURE_SKIP_ROOTFS
+	bool "Skip rootfs in mount table"
+	default BUSYBOX_DEFAULT_FEATURE_SKIP_ROOTFS
+	help
+	  Ignore rootfs entry in mount table.
+
+	  In Linux, kernel has a special filesystem, rootfs, which is initially
+	  mounted on /. It contains initramfs data, if kernel is configured
+	  to have one. Usually, another file system is mounted over / early
+	  in boot process, and therefore most tools which manipulate
+	  mount table, such as df, will skip rootfs entry.
+
+	  However, some systems do not mount anything on /.
+	  If you need to configure busybox for one of these systems,
+	  you may find it useful to turn this option off to make df show
+	  initramfs statistics.
+
+	  Otherwise, choose Y.
+
+config BUSYBOX_CONFIG_MONOTONIC_SYSCALL
+	bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
+	default BUSYBOX_DEFAULT_MONOTONIC_SYSCALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring
+	  time intervals (time, ping, traceroute etc need this).
+	  Probably requires Linux 2.6+. If not selected, gettimeofday
+	  will be used instead (which gives wrong results if date/time
+	  is reset).
+
+config BUSYBOX_CONFIG_IOCTL_HEX2STR_ERROR
+	bool "Use ioctl names rather than hex values in error messages"
+	default BUSYBOX_DEFAULT_IOCTL_HEX2STR_ERROR
+	help
+	  Use ioctl names rather than hex values in error messages
+	  (e.g. VT_DISALLOCATE rather than 0x5608). If disabled this
+	  saves about 1400 bytes.
+
+config BUSYBOX_CONFIG_FEATURE_HWIB
+	bool "Support infiniband HW"
+	default BUSYBOX_DEFAULT_FEATURE_HWIB
+	help
+	  Support for printing infiniband addresses in
+	  network applets.
+
+endmenu
diff --git a/package/utils/busybox/config/loginutils/Config.in b/package/utils/busybox/config/loginutils/Config.in
new file mode 100644
index 0000000000..956115c7f4
--- /dev/null
+++ b/package/utils/busybox/config/loginutils/Config.in
@@ -0,0 +1,338 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Login/Password Management Utilities"
+
+config BUSYBOX_CONFIG_FEATURE_SHADOWPASSWDS
+	bool "Support for shadow passwords"
+	default BUSYBOX_DEFAULT_FEATURE_SHADOWPASSWDS
+	help
+	  Build support for shadow password in /etc/shadow. This file is only
+	  readable by root and thus the encrypted passwords are no longer
+	  publicly readable.
+
+config BUSYBOX_CONFIG_USE_BB_PWD_GRP
+	bool "Use internal password and group functions rather than system functions"
+	default BUSYBOX_DEFAULT_USE_BB_PWD_GRP
+	help
+	  If you leave this disabled, busybox will use the system's password
+	  and group functions. And if you are using the GNU C library
+	  (glibc), you will then need to install the /etc/nsswitch.conf
+	  configuration file and the required /lib/libnss_* libraries in
+	  order for the password and group functions to work. This generally
+	  makes your embedded system quite a bit larger.
+
+	  Enabling this option will cause busybox to directly access the
+	  system's /etc/password, /etc/group files (and your system will be
+	  smaller, and I will get fewer emails asking about how glibc NSS
+	  works). When this option is enabled, you will not be able to use
+	  PAM to access remote LDAP password servers and whatnot. And if you
+	  want hostname resolution to work with glibc, you still need the
+	  /lib/libnss_* libraries.
+
+	  If you need to use glibc's nsswitch.conf mechanism
+	  (e.g. if user/group database is NOT stored in /etc/passwd etc),
+	  you must NOT use this option.
+
+	  If you enable this option, it will add about 1.5k.
+
+config BUSYBOX_CONFIG_USE_BB_SHADOW
+	bool "Use internal shadow password functions"
+	default BUSYBOX_DEFAULT_USE_BB_SHADOW
+	depends on BUSYBOX_CONFIG_USE_BB_PWD_GRP && BUSYBOX_CONFIG_FEATURE_SHADOWPASSWDS
+	help
+	  If you leave this disabled, busybox will use the system's shadow
+	  password handling functions. And if you are using the GNU C library
+	  (glibc), you will then need to install the /etc/nsswitch.conf
+	  configuration file and the required /lib/libnss_* libraries in
+	  order for the shadow password functions to work. This generally
+	  makes your embedded system quite a bit larger.
+
+	  Enabling this option will cause busybox to directly access the
+	  system's /etc/shadow file when handling shadow passwords. This
+	  makes your system smaller (and I will get fewer emails asking about
+	  how glibc NSS works). When this option is enabled, you will not be
+	  able to use PAM to access shadow passwords from remote LDAP
+	  password servers and whatnot.
+
+config BUSYBOX_CONFIG_USE_BB_CRYPT
+	bool "Use internal crypt functions"
+	default BUSYBOX_DEFAULT_USE_BB_CRYPT
+	help
+	  Busybox has internal DES and MD5 crypt functions.
+	  They produce results which are identical to corresponding
+	  standard C library functions.
+
+	  If you leave this disabled, busybox will use the system's
+	  crypt functions. Most C libraries use large (~70k)
+	  static buffers there, and also combine them with more general
+	  DES encryption/decryption.
+
+	  For busybox, having large static buffers is undesirable,
+	  especially on NOMMU machines. Busybox also doesn't need
+	  DES encryption/decryption and can do with smaller code.
+
+	  If you enable this option, it will add about 4.8k of code
+	  if you are building dynamically linked executable.
+	  In static build, it makes code _smaller_ by about 1.2k,
+	  and likely many kilobytes less of bss.
+
+config BUSYBOX_CONFIG_USE_BB_CRYPT_SHA
+	bool "Enable SHA256/512 crypt functions"
+	default BUSYBOX_DEFAULT_USE_BB_CRYPT_SHA
+	depends on BUSYBOX_CONFIG_USE_BB_CRYPT
+	help
+	  Enable this if you have passwords starting with "$5$" or "$6$"
+	  in your /etc/passwd or /etc/shadow files. These passwords
+	  are hashed using SHA256 and SHA512 algorithms. Support for them
+	  was added to glibc in 2008.
+	  With this option off, login will fail password check for any
+	  user which has password encrypted with these algorithms.
+
+config BUSYBOX_CONFIG_ADD_SHELL
+       bool "add-shell"
+       default BUSYBOX_DEFAULT_ADD_SHELL if BUSYBOX_CONFIG_DESKTOP
+       help
+         Add shells to /etc/shells.
+
+config BUSYBOX_CONFIG_REMOVE_SHELL
+       bool "remove-shell"
+       default BUSYBOX_DEFAULT_REMOVE_SHELL if BUSYBOX_CONFIG_DESKTOP
+       help
+         Remove shells from /etc/shells.
+config BUSYBOX_CONFIG_ADDGROUP
+	bool "addgroup"
+	default BUSYBOX_DEFAULT_ADDGROUP
+	help
+	  Utility for creating a new group account.
+
+config BUSYBOX_CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_ADDGROUP_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_ADDGROUP && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the addgroup applet.
+
+config BUSYBOX_CONFIG_FEATURE_ADDUSER_TO_GROUP
+	bool "Support for adding users to groups"
+	default BUSYBOX_DEFAULT_FEATURE_ADDUSER_TO_GROUP
+	depends on BUSYBOX_CONFIG_ADDGROUP
+	help
+	  If  called  with two non-option arguments,
+	  addgroup will add an existing user to an
+	  existing group.
+config BUSYBOX_CONFIG_ADDUSER
+	bool "adduser"
+	default BUSYBOX_DEFAULT_ADDUSER
+	help
+	  Utility for creating a new user account.
+
+config BUSYBOX_CONFIG_FEATURE_ADDUSER_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_ADDUSER_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_ADDUSER && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the adduser applet.
+
+config BUSYBOX_CONFIG_FEATURE_CHECK_NAMES
+	bool "Enable sanity check on user/group names in adduser and addgroup"
+	default BUSYBOX_DEFAULT_FEATURE_CHECK_NAMES
+	depends on BUSYBOX_CONFIG_ADDUSER || BUSYBOX_CONFIG_ADDGROUP
+	help
+	  Enable sanity check on user and group names in adduser and addgroup.
+	  To avoid problems, the user or group name should consist only of
+	  letters, digits, underscores, periods, at signs and dashes,
+	  and not start with a dash (as defined by IEEE Std 1003.1-2001).
+	  For compatibility with Samba machine accounts "$" is also supported
+	  at the end of the user or group name.
+
+config BUSYBOX_CONFIG_LAST_ID
+	int "Last valid uid or gid for adduser and addgroup"
+	depends on BUSYBOX_CONFIG_ADDUSER || BUSYBOX_CONFIG_ADDGROUP
+	default BUSYBOX_DEFAULT_LAST_ID
+	help
+	  Last valid uid or gid for adduser and addgroup
+
+config BUSYBOX_CONFIG_FIRST_SYSTEM_ID
+	int "First valid system uid or gid for adduser and addgroup"
+	depends on BUSYBOX_CONFIG_ADDUSER || BUSYBOX_CONFIG_ADDGROUP
+	range 0 BUSYBOX_CONFIG_LAST_ID
+	default BUSYBOX_DEFAULT_FIRST_SYSTEM_ID
+	help
+	  First valid system uid or gid for adduser and addgroup
+
+config BUSYBOX_CONFIG_LAST_SYSTEM_ID
+	int "Last valid system uid or gid for adduser and addgroup"
+	depends on BUSYBOX_CONFIG_ADDUSER || BUSYBOX_CONFIG_ADDGROUP
+	range BUSYBOX_CONFIG_FIRST_SYSTEM_ID BUSYBOX_CONFIG_LAST_ID
+	default BUSYBOX_DEFAULT_LAST_SYSTEM_ID
+	help
+	  Last valid system uid or gid for adduser and addgroup
+config BUSYBOX_CONFIG_CHPASSWD
+	bool "chpasswd"
+	default BUSYBOX_DEFAULT_CHPASSWD
+	help
+	  Reads a file of user name and password pairs from standard input
+	  and uses this information to update a group of existing users.
+
+config BUSYBOX_CONFIG_FEATURE_DEFAULT_PASSWD_ALGO
+	string "Default password encryption method (passwd -a, cryptpw -m parameter)"
+	default BUSYBOX_DEFAULT_FEATURE_DEFAULT_PASSWD_ALGO
+	depends on BUSYBOX_CONFIG_PASSWD || BUSYBOX_CONFIG_CRYPTPW
+	help
+	  Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512".
+config BUSYBOX_CONFIG_CRYPTPW
+	bool "cryptpw"
+	default BUSYBOX_DEFAULT_CRYPTPW
+	help
+	  Encrypts the given password with the crypt(3) libc function
+	  using the given salt.
+
+config BUSYBOX_CONFIG_MKPASSWD
+	bool "mkpasswd"
+	default BUSYBOX_DEFAULT_MKPASSWD
+	help
+	  Encrypts the given password with the crypt(3) libc function
+	  using the given salt. Debian has this utility under mkpasswd
+	  name. Busybox provides mkpasswd as an alias for cryptpw.
+config BUSYBOX_CONFIG_DELUSER
+	bool "deluser"
+	default BUSYBOX_DEFAULT_DELUSER
+	help
+	  Utility for deleting a user account.
+
+config BUSYBOX_CONFIG_DELGROUP
+	bool "delgroup"
+	default BUSYBOX_DEFAULT_DELGROUP
+	help
+	  Utility for deleting a group account.
+
+config BUSYBOX_CONFIG_FEATURE_DEL_USER_FROM_GROUP
+	bool "Support for removing users from groups"
+	default BUSYBOX_DEFAULT_FEATURE_DEL_USER_FROM_GROUP
+	depends on BUSYBOX_CONFIG_DELGROUP
+	help
+	  If called with two non-option arguments, deluser
+	  or delgroup will remove an user from a specified group.
+config BUSYBOX_CONFIG_GETTY
+	bool "getty"
+	default BUSYBOX_DEFAULT_GETTY
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  getty lets you log in on a tty. It is normally invoked by init.
+
+	  Note that you can save a few bytes by disabling it and
+	  using login applet directly.
+	  If you need to reset tty attributes before calling login,
+	  this script approximates getty:
+
+	  exec </dev/$1 >/dev/$1 2>&1 || exit 1
+	  reset
+	  stty sane; stty ispeed 38400; stty ospeed 38400
+	  printf "%s login: " "`hostname`"
+	  read -r login
+	  exec /bin/login "$login"
+config BUSYBOX_CONFIG_LOGIN
+	bool "login"
+	default BUSYBOX_DEFAULT_LOGIN
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  login is used when signing onto a system.
+
+	  Note that Busybox binary must be setuid root for this applet to
+	  work properly.
+
+config BUSYBOX_CONFIG_LOGIN_SESSION_AS_CHILD
+	bool "Run logged in session in a child process"
+	default BUSYBOX_DEFAULT_LOGIN_SESSION_AS_CHILD if BUSYBOX_CONFIG_PAM
+	depends on BUSYBOX_CONFIG_LOGIN
+	help
+	  Run the logged in session in a child process.  This allows
+	  login to clean up things such as utmp entries or PAM sessions
+	  when the login session is complete.  If you use PAM, you
+	  almost always would want this to be set to Y, else PAM session
+	  will not be cleaned up.
+
+config BUSYBOX_CONFIG_LOGIN_SCRIPTS
+	bool "Support for login scripts"
+	depends on BUSYBOX_CONFIG_LOGIN
+	default BUSYBOX_DEFAULT_LOGIN_SCRIPTS
+	help
+	  Enable this if you want login to execute $LOGIN_PRE_SUID_SCRIPT
+	  just prior to switching from root to logged-in user.
+
+config BUSYBOX_CONFIG_FEATURE_NOLOGIN
+	bool "Support for /etc/nologin"
+	default BUSYBOX_DEFAULT_FEATURE_NOLOGIN
+	depends on BUSYBOX_CONFIG_LOGIN
+	help
+	  The file /etc/nologin is used by (some versions of) login(1).
+	  If it exists, non-root logins are prohibited.
+
+config BUSYBOX_CONFIG_FEATURE_SECURETTY
+	bool "Support for /etc/securetty"
+	default BUSYBOX_DEFAULT_FEATURE_SECURETTY
+	depends on BUSYBOX_CONFIG_LOGIN
+	help
+	  The file /etc/securetty is used by (some versions of) login(1).
+	  The file contains the device names of tty lines (one per line,
+	  without leading /dev/) on which root is allowed to login.
+config BUSYBOX_CONFIG_PASSWD
+	bool "passwd"
+	default BUSYBOX_DEFAULT_PASSWD
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  passwd changes passwords for user and group accounts. A normal user
+	  may only change the password for his/her own account, the super user
+	  may change the password for any account. The administrator of a group
+	  may change the password for the group.
+
+	  Note that Busybox binary must be setuid root for this applet to
+	  work properly.
+
+config BUSYBOX_CONFIG_FEATURE_PASSWD_WEAK_CHECK
+	bool "Check new passwords for weakness"
+	default BUSYBOX_DEFAULT_FEATURE_PASSWD_WEAK_CHECK
+	depends on BUSYBOX_CONFIG_PASSWD
+	help
+	  With this option passwd will refuse new passwords which are "weak".
+config BUSYBOX_CONFIG_SU
+	bool "su"
+	default BUSYBOX_DEFAULT_SU
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  su is used to become another user during a login session.
+	  Invoked without a username, su defaults to becoming the super user.
+
+	  Note that Busybox binary must be setuid root for this applet to
+	  work properly.
+
+config BUSYBOX_CONFIG_FEATURE_SU_SYSLOG
+	bool "Enable su to write to syslog"
+	default BUSYBOX_DEFAULT_FEATURE_SU_SYSLOG
+	depends on BUSYBOX_CONFIG_SU
+
+config BUSYBOX_CONFIG_FEATURE_SU_CHECKS_SHELLS
+	bool "Enable su to check user's shell to be listed in /etc/shells"
+	depends on BUSYBOX_CONFIG_SU
+	default BUSYBOX_DEFAULT_FEATURE_SU_CHECKS_SHELLS
+config BUSYBOX_CONFIG_SULOGIN
+	bool "sulogin"
+	default BUSYBOX_DEFAULT_SULOGIN
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  sulogin is invoked when the system goes into single user
+	  mode (this is done through an entry in inittab).
+config BUSYBOX_CONFIG_VLOCK
+	bool "vlock"
+	default BUSYBOX_DEFAULT_VLOCK
+	help
+	  Build the "vlock" applet which allows you to lock (virtual) terminals.
+
+	  Note that Busybox binary must be setuid root for this applet to
+	  work properly.
+
+endmenu
diff --git a/package/utils/busybox/config/mailutils/Config.in b/package/utils/busybox/config/mailutils/Config.in
new file mode 100644
index 0000000000..64b9a2baa9
--- /dev/null
+++ b/package/utils/busybox/config/mailutils/Config.in
@@ -0,0 +1,55 @@
+# DO NOT EDIT. This file is generated from Config.src
+menu "Mail Utilities"
+
+
+config BUSYBOX_CONFIG_MAKEMIME
+	bool "makemime"
+	default BUSYBOX_DEFAULT_MAKEMIME
+	help
+	  Create MIME-formatted messages.
+
+config BUSYBOX_CONFIG_FEATURE_MIME_CHARSET
+	string "Default charset"
+	default BUSYBOX_DEFAULT_FEATURE_MIME_CHARSET
+	depends on BUSYBOX_CONFIG_MAKEMIME || BUSYBOX_CONFIG_REFORMIME || BUSYBOX_CONFIG_SENDMAIL
+	help
+	  Default charset of the message.
+
+config BUSYBOX_CONFIG_POPMAILDIR
+	bool "popmaildir"
+	default BUSYBOX_DEFAULT_POPMAILDIR
+	help
+	  Simple yet powerful POP3 mail popper. Delivers content
+	  of remote mailboxes to local Maildir.
+
+config BUSYBOX_CONFIG_FEATURE_POPMAILDIR_DELIVERY
+	bool "Allow message filters and custom delivery program"
+	default BUSYBOX_DEFAULT_FEATURE_POPMAILDIR_DELIVERY
+	depends on BUSYBOX_CONFIG_POPMAILDIR
+	help
+	  Allow to use a custom program to filter the content
+	  of the message before actual delivery (-F "prog [args...]").
+	  Allow to use a custom program for message actual delivery
+	  (-M "prog [args...]").
+
+config BUSYBOX_CONFIG_REFORMIME
+	bool "reformime"
+	default BUSYBOX_DEFAULT_REFORMIME
+	help
+	  Parse MIME-formatted messages.
+
+config BUSYBOX_CONFIG_FEATURE_REFORMIME_COMPAT
+	bool "Accept and ignore options other than -x and -X"
+	default BUSYBOX_DEFAULT_FEATURE_REFORMIME_COMPAT
+	depends on BUSYBOX_CONFIG_REFORMIME
+	help
+	  Accept (for compatibility only) and ignore options
+	  other than -x and -X.
+
+config BUSYBOX_CONFIG_SENDMAIL
+	bool "sendmail"
+	default BUSYBOX_DEFAULT_SENDMAIL
+	help
+	  Barebones sendmail.
+
+endmenu
diff --git a/package/utils/busybox/config/miscutils/Config.in b/package/utils/busybox/config/miscutils/Config.in
new file mode 100644
index 0000000000..3465df40ab
--- /dev/null
+++ b/package/utils/busybox/config/miscutils/Config.in
@@ -0,0 +1,792 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Miscellaneous Utilities"
+
+config BUSYBOX_CONFIG_CONSPY
+	bool "conspy"
+	default BUSYBOX_DEFAULT_CONSPY
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  A text-mode VNC like program for Linux virtual terminals.
+	  example:  conspy NUM      shared access to console num
+	  or        conspy -nd NUM  screenshot of console num
+	  or        conspy -cs NUM  poor man's GNU screen like
+config BUSYBOX_CONFIG_CROND
+	bool "crond"
+	default BUSYBOX_DEFAULT_CROND
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  Crond is a background daemon that parses individual crontab
+	  files and executes commands on behalf of the users in question.
+	  This is a port of dcron from slackware. It uses files of the
+	  format /var/spool/cron/crontabs/<username> files, for example:
+	      $ cat /var/spool/cron/crontabs/root
+	      # Run daily cron jobs at 4:40 every day:
+	      40 4 * * * /etc/cron/daily > /dev/null 2>&1
+
+config BUSYBOX_CONFIG_FEATURE_CROND_D
+	bool "Support option -d to redirect output to stderr"
+	depends on BUSYBOX_CONFIG_CROND
+	default BUSYBOX_DEFAULT_FEATURE_CROND_D
+	help
+	  -d N sets loglevel (0:most verbose) and directs all output to stderr.
+
+config BUSYBOX_CONFIG_FEATURE_CROND_CALL_SENDMAIL
+	bool "Report command output via email (using sendmail)"
+	default BUSYBOX_DEFAULT_FEATURE_CROND_CALL_SENDMAIL
+	depends on BUSYBOX_CONFIG_CROND
+	help
+	  Command output will be sent to corresponding user via email.
+
+config BUSYBOX_CONFIG_FEATURE_CROND_DIR
+	string "crond spool directory"
+	default BUSYBOX_DEFAULT_FEATURE_CROND_DIR
+	depends on BUSYBOX_CONFIG_CROND || BUSYBOX_CONFIG_CRONTAB
+	help
+	  Location of crond spool.
+config BUSYBOX_CONFIG_I2CGET
+	bool "i2cget"
+	default BUSYBOX_DEFAULT_I2CGET
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Read from I2C/SMBus chip registers.
+
+config BUSYBOX_CONFIG_I2CSET
+	bool "i2cset"
+	default BUSYBOX_DEFAULT_I2CSET
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Set I2C registers.
+
+config BUSYBOX_CONFIG_I2CDUMP
+	bool "i2cdump"
+	default BUSYBOX_DEFAULT_I2CDUMP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Examine I2C registers.
+
+config BUSYBOX_CONFIG_I2CDETECT
+	bool "i2cdetect"
+	default BUSYBOX_DEFAULT_I2CDETECT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Detect I2C chips.
+
+config BUSYBOX_CONFIG_LESS
+	bool "less"
+	default BUSYBOX_DEFAULT_LESS
+	help
+	  'less' is a pager, meaning that it displays text files. It possesses
+	  a wide array of features, and is an improvement over 'more'.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_MAXLINES
+	int "Max number of input lines less will try to eat"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_MAXLINES
+	depends on BUSYBOX_CONFIG_LESS
+
+config BUSYBOX_CONFIG_FEATURE_LESS_BRACKETS
+	bool "Enable bracket searching"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_BRACKETS
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  This option adds the capability to search for matching left and right
+	  brackets, facilitating programming.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_FLAGS
+	bool "Enable -m/-M"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_FLAGS
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  The -M/-m flag enables a more sophisticated status line.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_TRUNCATE
+	bool "Enable -S"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_TRUNCATE
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  The -S flag causes long lines to be truncated rather than
+	  wrapped.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_MARKS
+	bool "Enable marks"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_MARKS
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  Marks enable positions in a file to be stored for easy reference.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_REGEXP
+	bool "Enable regular expressions"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_REGEXP
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  Enable regular expressions, allowing complex file searches.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_WINCH
+	bool "Enable automatic resizing on window size changes"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_WINCH
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  Makes less track window size changes.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_ASK_TERMINAL
+	bool "Use 'tell me cursor position' ESC sequence to measure window"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_ASK_TERMINAL
+	depends on BUSYBOX_CONFIG_FEATURE_LESS_WINCH
+	help
+	  Makes less track window size changes.
+	  If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
+	  this option makes less perform a last-ditch effort to find it:
+	  position cursor to 999,999 and ask terminal to report real
+	  cursor position using "ESC [ 6 n" escape sequence, then read stdin.
+
+	  This is not clean but helps a lot on serial lines and such.
+
+config BUSYBOX_CONFIG_FEATURE_LESS_DASHCMD
+	bool "Enable flag changes ('-' command)"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_DASHCMD
+	depends on BUSYBOX_CONFIG_LESS
+	help
+	  This enables the ability to change command-line flags within
+	  less itself ('-' keyboard command).
+
+config BUSYBOX_CONFIG_FEATURE_LESS_LINENUMS
+	bool "Enable dynamic switching of line numbers"
+	default BUSYBOX_DEFAULT_FEATURE_LESS_LINENUMS
+	depends on BUSYBOX_CONFIG_FEATURE_LESS_DASHCMD
+	help
+	  Enables "-N" command.
+config BUSYBOX_CONFIG_NANDWRITE
+	bool "nandwrite"
+	default BUSYBOX_DEFAULT_NANDWRITE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Write to the specified MTD device, with bad blocks awareness
+
+config BUSYBOX_CONFIG_NANDDUMP
+	bool "nanddump"
+	default BUSYBOX_DEFAULT_NANDDUMP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Dump the content of raw NAND chip
+config BUSYBOX_CONFIG_RFKILL
+	bool "rfkill"
+	default BUSYBOX_DEFAULT_RFKILL # doesn't build on Ubuntu 9.04
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Enable/disable wireless devices.
+
+	  rfkill list : list all wireless devices
+	  rfkill list bluetooth : list all bluetooth devices
+	  rfkill list 1 : list device corresponding to the given index
+	  rfkill block|unblock wlan : block/unblock all wlan(wifi) devices
+
+config BUSYBOX_CONFIG_SETSERIAL
+	bool "setserial"
+	default BUSYBOX_DEFAULT_SETSERIAL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Retrieve or set Linux serial port.
+config BUSYBOX_CONFIG_TASKSET
+	bool "taskset"
+	default BUSYBOX_DEFAULT_TASKSET  # doesn't build on some non-x86 targets (m68k)
+	help
+	  Retrieve or set a processes's CPU affinity.
+	  This requires sched_{g,s}etaffinity support in your libc.
+
+config BUSYBOX_CONFIG_FEATURE_TASKSET_FANCY
+	bool "Fancy output"
+	default BUSYBOX_DEFAULT_FEATURE_TASKSET_FANCY
+	depends on BUSYBOX_CONFIG_TASKSET
+	help
+	  Add code for fancy output. This merely silences a compiler-warning
+	  and adds about 135 Bytes. May be needed for machines with alot
+	  of CPUs.
+config BUSYBOX_CONFIG_UBIATTACH
+	bool "ubiattach"
+	default BUSYBOX_DEFAULT_UBIATTACH
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Attach MTD device to an UBI device.
+
+config BUSYBOX_CONFIG_UBIDETACH
+	bool "ubidetach"
+	default BUSYBOX_DEFAULT_UBIDETACH
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Detach MTD device from an UBI device.
+
+config BUSYBOX_CONFIG_UBIMKVOL
+	bool "ubimkvol"
+	default BUSYBOX_DEFAULT_UBIMKVOL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Create a UBI volume.
+
+config BUSYBOX_CONFIG_UBIRMVOL
+	bool "ubirmvol"
+	default BUSYBOX_DEFAULT_UBIRMVOL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Delete a UBI volume.
+
+config BUSYBOX_CONFIG_UBIRSVOL
+	bool "ubirsvol"
+	default BUSYBOX_DEFAULT_UBIRSVOL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Resize a UBI volume.
+
+config BUSYBOX_CONFIG_UBIUPDATEVOL
+	bool "ubiupdatevol"
+	default BUSYBOX_DEFAULT_UBIUPDATEVOL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Update a UBI volume.
+config BUSYBOX_CONFIG_UBIRENAME
+	bool "ubirename"
+	default BUSYBOX_DEFAULT_UBIRENAME
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Utility to rename UBI volumes
+config BUSYBOX_CONFIG_WALL
+	bool "wall"
+	default BUSYBOX_DEFAULT_WALL
+	depends on BUSYBOX_CONFIG_FEATURE_UTMP
+	help
+	  Write a message to all users that are logged in.
+
+config BUSYBOX_CONFIG_ADJTIMEX
+	bool "adjtimex"
+	default BUSYBOX_DEFAULT_ADJTIMEX
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Adjtimex reads and optionally sets adjustment parameters for
+	  the Linux clock adjustment algorithm.
+
+config BUSYBOX_CONFIG_BBCONFIG
+	bool "bbconfig"
+	default BUSYBOX_DEFAULT_BBCONFIG
+	help
+	  The bbconfig applet will print the config file with which
+	  busybox was built.
+
+config BUSYBOX_CONFIG_FEATURE_COMPRESS_BBCONFIG
+	bool "Compress bbconfig data"
+	default BUSYBOX_DEFAULT_FEATURE_COMPRESS_BBCONFIG
+	depends on BUSYBOX_CONFIG_BBCONFIG
+	help
+	  Store bbconfig data in compressed form, uncompress them on-the-fly
+	  before output.
+
+	  If you have a really tiny busybox with few applets enabled (and
+	  bunzip2 isn't one of them), the overhead of the decompressor might
+	  be noticeable. Also, if you run executables directly from ROM
+	  and have very little memory, this might not be a win. Otherwise,
+	  you probably want this.
+
+config BUSYBOX_CONFIG_BEEP
+	bool "beep"
+	default BUSYBOX_DEFAULT_BEEP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The beep applets beeps in a given freq/Hz.
+
+config BUSYBOX_CONFIG_FEATURE_BEEP_FREQ
+	int "default frequency"
+	range 0 2147483647
+	default BUSYBOX_DEFAULT_FEATURE_BEEP_FREQ
+	depends on BUSYBOX_CONFIG_BEEP
+	help
+	  Frequency for default beep.
+
+config BUSYBOX_CONFIG_FEATURE_BEEP_LENGTH_MS
+	int "default length"
+	range 0 2147483647
+	default BUSYBOX_DEFAULT_FEATURE_BEEP_LENGTH_MS
+	depends on BUSYBOX_CONFIG_BEEP
+	help
+	  Length in ms for default beep.
+
+config BUSYBOX_CONFIG_CHAT
+	bool "chat"
+	default BUSYBOX_DEFAULT_CHAT
+	help
+	  Simple chat utility.
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_NOFAIL
+	bool "Enable NOFAIL expect strings"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_NOFAIL
+	help
+	  When enabled expect strings which are started with a dash trigger
+	  no-fail mode. That is when expectation is not met within timeout
+	  the script is not terminated but sends next SEND string and waits
+	  for next EXPECT string. This allows to compose far more flexible
+	  scripts.
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_TTY_HIFI
+	bool "Force STDIN to be a TTY"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_TTY_HIFI
+	help
+	  Original chat always treats STDIN as a TTY device and sets for it
+	  so-called raw mode. This option turns on such behaviour.
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_IMPLICIT_CR
+	bool "Enable implicit Carriage Return"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_IMPLICIT_CR
+	help
+	  When enabled make chat to terminate all SEND strings with a "\r"
+	  unless "\c" is met anywhere in the string.
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_SWALLOW_OPTS
+	bool "Swallow options"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_SWALLOW_OPTS
+	help
+	  Busybox chat require no options. To make it not fail when used
+	  in place of original chat (which has a bunch of options) turn
+	  this on.
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_SEND_ESCAPES
+	bool "Support weird SEND escapes"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_SEND_ESCAPES
+	help
+	  Original chat uses some escape sequences in SEND arguments which
+	  are not sent to device but rather performs special actions.
+	  E.g. "\K" means to send a break sequence to device.
+	  "\d" delays execution for a second, "\p" -- for a 1/100 of second.
+	  Before turning this option on think twice: do you really need them?
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_VAR_ABORT_LEN
+	bool "Support variable-length ABORT conditions"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_VAR_ABORT_LEN
+	help
+	  Original chat uses fixed 50-bytes length ABORT conditions. Say N here.
+
+config BUSYBOX_CONFIG_FEATURE_CHAT_CLR_ABORT
+	bool "Support revoking of ABORT conditions"
+	depends on BUSYBOX_CONFIG_CHAT
+	default BUSYBOX_DEFAULT_FEATURE_CHAT_CLR_ABORT
+	help
+	  Support CLR_ABORT directive.
+
+config BUSYBOX_CONFIG_CHRT
+	bool "chrt"
+	default BUSYBOX_DEFAULT_CHRT
+	help
+	  manipulate real-time attributes of a process.
+	  This requires sched_{g,s}etparam support in your libc.
+
+config BUSYBOX_CONFIG_CRONTAB
+	bool "crontab"
+	default BUSYBOX_DEFAULT_CRONTAB
+	help
+	  Crontab manipulates the crontab for a particular user. Only
+	  the superuser may specify a different user and/or crontab directory.
+	  Note that Busybox binary must be setuid root for this applet to
+	  work properly.
+
+config BUSYBOX_CONFIG_DC
+	bool "dc"
+	default BUSYBOX_DEFAULT_DC
+	help
+	  Dc is a reverse-polish desk calculator which supports unlimited
+	  precision arithmetic.
+
+config BUSYBOX_CONFIG_FEATURE_DC_LIBM
+	bool "Enable power and exp functions (requires libm)"
+	default BUSYBOX_DEFAULT_FEATURE_DC_LIBM
+	depends on BUSYBOX_CONFIG_DC
+	help
+	  Enable power and exp functions.
+	  NOTE: This will require libm to be present for linking.
+
+config BUSYBOX_CONFIG_DEVFSD
+	bool "devfsd (obsolete)"
+	default BUSYBOX_DEFAULT_DEVFSD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  This is deprecated and should NOT be used anymore.
+	  Use linux >= 2.6 (optionally with hotplug) and mdev instead!
+	  See docs/mdev.txt for detailed instructions on how to use mdev
+	  instead.
+
+	  Provides compatibility with old device names on a devfs systems.
+	  You should set it to true if you have devfs enabled.
+	  The following keywords in devsfd.conf are supported:
+	  "CLEAR_CONFIG", "INCLUDE", "OPTIONAL_INCLUDE", "RESTORE",
+	  "PERMISSIONS", "EXECUTE", "COPY", "IGNORE",
+	  "MKOLDCOMPAT", "MKNEWCOMPAT","RMOLDCOMPAT", "RMNEWCOMPAT".
+
+	  But only if they are written UPPERCASE!!!!!!!!
+
+config BUSYBOX_CONFIG_DEVFSD_MODLOAD
+	bool "Adds support for MODLOAD keyword in devsfd.conf"
+	default BUSYBOX_DEFAULT_DEVFSD_MODLOAD
+	depends on BUSYBOX_CONFIG_DEVFSD
+	help
+	  This actually doesn't work with busybox modutils but needs
+	  the external modutils.
+
+config BUSYBOX_CONFIG_DEVFSD_FG_NP
+	bool "Enables the -fg and -np options"
+	default BUSYBOX_DEFAULT_DEVFSD_FG_NP
+	depends on BUSYBOX_CONFIG_DEVFSD
+	help
+	  -fg  Run the daemon in the foreground.
+	  -np  Exit after parsing the configuration file.
+	       Do not poll for events.
+
+config BUSYBOX_CONFIG_DEVFSD_VERBOSE
+	bool "Increases logging (and size)"
+	default BUSYBOX_DEFAULT_DEVFSD_VERBOSE
+	depends on BUSYBOX_CONFIG_DEVFSD
+	help
+	  Increases logging to stderr or syslog.
+
+config BUSYBOX_CONFIG_FEATURE_DEVFS
+	bool "Use devfs names for all devices (obsolete)"
+	default BUSYBOX_DEFAULT_FEATURE_DEVFS
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This is obsolete and should NOT be used anymore.
+	  Use linux >= 2.6 (optionally with hotplug) and mdev instead!
+
+	  For legacy systems -- if there is no way around devfsd -- this
+	  tells busybox to look for names like /dev/loop/0 instead of
+	  /dev/loop0. If your /dev directory has normal names instead of
+	  devfs names, you don't want this.
+
+config BUSYBOX_CONFIG_DEVMEM
+	bool "devmem"
+	default BUSYBOX_DEFAULT_DEVMEM
+	help
+	  devmem is a small program that reads and writes from physical
+	  memory using /dev/mem.
+
+config BUSYBOX_CONFIG_EJECT
+	bool "eject"
+	default BUSYBOX_DEFAULT_EJECT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Used to eject cdroms. (defaults to /dev/cdrom)
+
+config BUSYBOX_CONFIG_FEATURE_EJECT_SCSI
+	bool "SCSI support"
+	default BUSYBOX_DEFAULT_FEATURE_EJECT_SCSI
+	depends on BUSYBOX_CONFIG_EJECT
+	help
+	  Add the -s option to eject, this allows to eject SCSI-Devices and
+	  usb-storage devices.
+
+config BUSYBOX_CONFIG_FBSPLASH
+	bool "fbsplash"
+	default BUSYBOX_DEFAULT_FBSPLASH
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Shows splash image and progress bar on framebuffer device.
+	  Can be used during boot phase of an embedded device. ~2kb.
+	  Usage:
+	  - use kernel option 'vga=xxx' or otherwise enable fb device.
+	  - put somewhere fbsplash.cfg file and an image in .ppm format.
+	  - $ setsid fbsplash [params] &
+	    -c: hide cursor
+	    -d /dev/fbN: framebuffer device (if not /dev/fb0)
+	    -s path_to_image_file (can be "-" for stdin)
+	    -i path_to_cfg_file (can be "-" for stdin)
+	    -f path_to_fifo (can be "-" for stdin)
+	  - if you want to run it only in presence of kernel parameter:
+	    grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params] &
+	  - commands for fifo:
+	    "NN" (ASCII decimal number) - percentage to show on progress bar
+	    "exit" - well you guessed it
+
+config BUSYBOX_CONFIG_FLASHCP
+	bool "flashcp"
+	default BUSYBOX_DEFAULT_FLASHCP  # doesn't build on Ubuntu 8.04
+	help
+	  The flashcp binary, inspired by mtd-utils as of git head 5eceb74f7.
+	  This utility is used to copy images into a MTD device.
+
+config BUSYBOX_CONFIG_FLASH_LOCK
+	bool "flash_lock"
+	default BUSYBOX_DEFAULT_FLASH_LOCK  # doesn't build on Ubuntu 8.04
+	help
+	  The flash_lock binary from mtd-utils as of git head 5ec0c10d0. This
+	  utility locks part or all of the flash device.
+
+config BUSYBOX_CONFIG_FLASH_UNLOCK
+	bool "flash_unlock"
+	default BUSYBOX_DEFAULT_FLASH_UNLOCK  # doesn't build on Ubuntu 8.04
+	help
+	  The flash_unlock binary from mtd-utils as of git head 5ec0c10d0. This
+	  utility unlocks part or all of the flash device.
+
+config BUSYBOX_CONFIG_FLASH_ERASEALL
+	bool "flash_eraseall"
+	default BUSYBOX_DEFAULT_FLASH_ERASEALL  # doesn't build on Ubuntu 8.04
+	help
+	  The flash_eraseall binary from mtd-utils as of git head c4c6a59eb.
+	  This utility is used to erase the whole MTD device.
+
+config BUSYBOX_CONFIG_IONICE
+	bool "ionice"
+	default BUSYBOX_DEFAULT_IONICE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Set/set program io scheduling class and priority
+	  Requires kernel >= 2.6.13
+
+config BUSYBOX_CONFIG_INOTIFYD
+	bool "inotifyd"
+	default BUSYBOX_DEFAULT_INOTIFYD  # doesn't build on Knoppix 5
+	help
+	  Simple inotify daemon. Reports filesystem changes. Requires
+	  kernel >= 2.6.13
+
+config BUSYBOX_CONFIG_LAST
+	bool "last"
+	default BUSYBOX_DEFAULT_LAST
+	depends on BUSYBOX_CONFIG_FEATURE_WTMP
+	help
+	  'last' displays a list of the last users that logged into the system.
+
+config BUSYBOX_CONFIG_FEATURE_LAST_FANCY
+	bool "Turn on output of extra information"
+	default BUSYBOX_DEFAULT_FEATURE_LAST_FANCY
+	depends on BUSYBOX_CONFIG_LAST
+	help
+	  'last' displays detailed information about the last users that
+	  logged into the system (mimics sysvinit last). +900 bytes.
+
+config BUSYBOX_CONFIG_HDPARM
+	bool "hdparm"
+	default BUSYBOX_DEFAULT_HDPARM
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Get/Set hard drive parameters. Primarily intended for ATA
+	  drives. Adds about 13k (or around 30k if you enable the
+	  FEATURE_HDPARM_GET_IDENTITY option)....
+
+config BUSYBOX_CONFIG_FEATURE_HDPARM_GET_IDENTITY
+	bool "Support obtaining detailed information directly from drives"
+	default BUSYBOX_DEFAULT_FEATURE_HDPARM_GET_IDENTITY
+	depends on BUSYBOX_CONFIG_HDPARM
+	help
+	  Enables the -I and -i options to obtain detailed information
+	  directly from drives about their capabilities and supported ATA
+	  feature set. If no device name is specified, hdparm will read
+	  identify data from stdin. Enabling this option will add about 16k...
+
+config BUSYBOX_CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF
+	bool "Register an IDE interface (DANGEROUS)"
+	default BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_SCAN_HWIF
+	depends on BUSYBOX_CONFIG_HDPARM
+	help
+	  Enables the 'hdparm -R' option to register an IDE interface.
+	  This is dangerous stuff, so you should probably say N.
+
+config BUSYBOX_CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
+	bool "Un-register an IDE interface (DANGEROUS)"
+	default BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF
+	depends on BUSYBOX_CONFIG_HDPARM
+	help
+	  Enables the 'hdparm -U' option to un-register an IDE interface.
+	  This is dangerous stuff, so you should probably say N.
+
+config BUSYBOX_CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET
+	bool "Perform device reset (DANGEROUS)"
+	default BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_DRIVE_RESET
+	depends on BUSYBOX_CONFIG_HDPARM
+	help
+	  Enables the 'hdparm -w' option to perform a device reset.
+	  This is dangerous stuff, so you should probably say N.
+
+config BUSYBOX_CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+	bool "Tristate device for hotswap (DANGEROUS)"
+	default BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_TRISTATE_HWIF
+	depends on BUSYBOX_CONFIG_HDPARM
+	help
+	  Enables the 'hdparm -x' option to tristate device for hotswap,
+	  and the '-b' option to get/set bus state. This is dangerous
+	  stuff, so you should probably say N.
+
+config BUSYBOX_CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA
+	bool "Get/set using_dma flag"
+	default BUSYBOX_DEFAULT_FEATURE_HDPARM_HDIO_GETSET_DMA
+	depends on BUSYBOX_CONFIG_HDPARM
+	help
+	  Enables the 'hdparm -d' option to get/set using_dma flag.
+
+config BUSYBOX_CONFIG_LOCK
+	bool "lock"
+	default BUSYBOX_DEFAULT_LOCK
+	help
+	  Small utility for using locks in scripts
+
+config BUSYBOX_CONFIG_MAKEDEVS
+	bool "makedevs"
+	default BUSYBOX_DEFAULT_MAKEDEVS
+	help
+	  'makedevs' is a utility used to create a batch of devices with
+	  one command.
+
+	  There are two choices for command line behaviour, the interface
+	  as used by LEAF/Linux Router Project, or a device table file.
+
+	  'leaf' is traditionally what busybox follows, it allows multiple
+	  devices of a particluar type to be created per command.
+	  e.g. /dev/hda[0-9]
+	  Device properties are passed as command line arguments.
+
+	  'table' reads device properties from a file or stdin, allowing
+	  a batch of unrelated devices to be made with one command.
+	  User/group names are allowed as an alternative to uid/gid.
+
+choice
+	prompt "Choose makedevs behaviour"
+	depends on BUSYBOX_CONFIG_MAKEDEVS
+	default BUSYBOX_CONFIG_FEATURE_MAKEDEVS_TABLE
+
+config BUSYBOX_CONFIG_FEATURE_MAKEDEVS_LEAF
+	bool "leaf"
+
+config BUSYBOX_CONFIG_FEATURE_MAKEDEVS_TABLE
+	bool "table"
+
+endchoice
+
+config BUSYBOX_CONFIG_MAN
+	bool "man"
+	default BUSYBOX_DEFAULT_MAN
+	help
+	  Format and display manual pages.
+
+config BUSYBOX_CONFIG_MICROCOM
+	bool "microcom"
+	default BUSYBOX_DEFAULT_MICROCOM
+	help
+	  The poor man's minicom utility for chatting with serial port devices.
+
+config BUSYBOX_CONFIG_MOUNTPOINT
+	bool "mountpoint"
+	default BUSYBOX_DEFAULT_MOUNTPOINT
+	help
+	  mountpoint checks if the directory is a mountpoint.
+
+config BUSYBOX_CONFIG_MT
+	bool "mt"
+	default BUSYBOX_DEFAULT_MT
+	help
+	  mt is used to control tape devices. You can use the mt utility
+	  to advance or rewind a tape past a specified number of archive
+	  files on the tape.
+
+config BUSYBOX_CONFIG_RAIDAUTORUN
+	bool "raidautorun"
+	default BUSYBOX_DEFAULT_RAIDAUTORUN
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  raidautorun tells the kernel md driver to
+	  search and start RAID arrays.
+
+config BUSYBOX_CONFIG_READAHEAD
+	bool "readahead"
+	default BUSYBOX_DEFAULT_READAHEAD
+	depends on BUSYBOX_CONFIG_LFS
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Preload the files listed on the command line into RAM cache so that
+	  subsequent reads on these files will not block on disk I/O.
+
+	  This applet just calls the readahead(2) system call on each file.
+	  It is mainly useful in system startup scripts to preload files
+	  or executables before they are used. When used at the right time
+	  (in particular when a CPU bound process is running) it can
+	  significantly speed up system startup.
+
+	  As readahead(2) blocks until each file has been read, it is best to
+	  run this applet as a background job.
+
+config BUSYBOX_CONFIG_RUNLEVEL
+	bool "runlevel"
+	default BUSYBOX_DEFAULT_RUNLEVEL
+	depends on BUSYBOX_CONFIG_FEATURE_UTMP
+	help
+	  find the current and previous system runlevel.
+
+	  This applet uses utmp but does not rely on busybox supporing
+	  utmp on purpose. It is used by e.g. emdebian via /etc/init.d/rc.
+
+config BUSYBOX_CONFIG_RX
+	bool "rx"
+	default BUSYBOX_DEFAULT_RX
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Receive files using the Xmodem protocol.
+
+config BUSYBOX_CONFIG_SETSID
+	bool "setsid"
+	default BUSYBOX_DEFAULT_SETSID
+	help
+	  setsid runs a program in a new session
+
+config BUSYBOX_CONFIG_STRINGS
+	bool "strings"
+	default BUSYBOX_DEFAULT_STRINGS
+	help
+	  strings prints the printable character sequences for each file
+	  specified.
+
+config BUSYBOX_CONFIG_TIME
+	bool "time"
+	default BUSYBOX_DEFAULT_TIME
+	help
+	  The time command runs the specified program with the given arguments.
+	  When the command finishes, time writes a message to standard output
+	  giving timing statistics about this program run.
+
+config BUSYBOX_CONFIG_TIMEOUT
+	bool "timeout"
+	default BUSYBOX_DEFAULT_TIMEOUT
+	help
+	  Runs a program and watches it. If it does not terminate in
+	  specified number of seconds, it is sent a signal.
+
+config BUSYBOX_CONFIG_TTYSIZE
+	bool "ttysize"
+	default BUSYBOX_DEFAULT_TTYSIZE
+	help
+	  A replacement for "stty size". Unlike stty, can report only width,
+	  only height, or both, in any order. It also does not complain on
+	  error, but returns default 80x24.
+	  Usage in shell scripts: width=`ttysize w`.
+
+config BUSYBOX_CONFIG_VOLNAME
+	bool "volname"
+	default BUSYBOX_DEFAULT_VOLNAME
+	help
+	  Prints a CD-ROM volume name.
+
+config BUSYBOX_CONFIG_WATCHDOG
+	bool "watchdog"
+	default BUSYBOX_DEFAULT_WATCHDOG
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The watchdog utility is used with hardware or software watchdog
+	  device drivers. It opens the specified watchdog device special file
+	  and periodically writes a magic character to the device. If the
+	  watchdog applet ever fails to write the magic character within a
+	  certain amount of time, the watchdog device assumes the system has
+	  hung, and will cause the hardware to reboot.
+
+endmenu
diff --git a/package/utils/busybox/config/modutils/Config.in b/package/utils/busybox/config/modutils/Config.in
new file mode 100644
index 0000000000..8e0e2af9ef
--- /dev/null
+++ b/package/utils/busybox/config/modutils/Config.in
@@ -0,0 +1,266 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux Module Utilities"
+
+config BUSYBOX_CONFIG_MODINFO
+	bool "modinfo"
+	default BUSYBOX_DEFAULT_MODINFO
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Show information about a Linux Kernel module
+
+config BUSYBOX_CONFIG_MODPROBE_SMALL
+	bool "Simplified modutils"
+	default BUSYBOX_DEFAULT_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Simplified modutils.
+
+	  With this option modprobe does not require modules.dep file
+	  and does not use /etc/modules.conf file.
+	  It scans module files in /lib/modules/`uname -r` and
+	  determines dependencies and module alias names on the fly.
+	  This may make module loading slower, most notably
+	  when one needs to load module by alias (this requires
+	  scanning through module _bodies_).
+
+	  At the first attempt to load a module by alias modprobe
+	  will try to generate modules.dep.bb file in order to speed up
+	  future loads by alias. Failure to do so (read-only /lib/modules,
+	  etc) is not reported, and future modprobes will be slow too.
+
+	  NB: modules.dep.bb file format is not compatible
+	  with modules.dep file as created/used by standard module tools.
+
+	  Additional module parameters can be stored in
+	  /etc/modules/$module_name files.
+
+	  Apart from modprobe, other utilities are also provided:
+	  - insmod is an alias to modprobe
+	  - rmmod is an alias to modprobe -r
+	  - depmod generates modules.dep.bb
+
+config BUSYBOX_CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+	bool "Accept module options on modprobe command line"
+	default BUSYBOX_DEFAULT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+	depends on BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Allow insmod and modprobe take module options from command line.
+
+config BUSYBOX_CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
+	bool "Skip loading of already loaded modules"
+	default BUSYBOX_DEFAULT_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
+	depends on BUSYBOX_CONFIG_MODPROBE_SMALL
+	help
+	  Check if the module is already loaded.
+
+config BUSYBOX_CONFIG_INSMOD
+	bool "insmod"
+	default BUSYBOX_DEFAULT_INSMOD
+	depends on !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  insmod is used to load specified modules in the running kernel.
+
+config BUSYBOX_CONFIG_RMMOD
+	bool "rmmod"
+	default BUSYBOX_DEFAULT_RMMOD
+	depends on !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  rmmod is used to unload specified modules from the kernel.
+
+config BUSYBOX_CONFIG_LSMOD
+	bool "lsmod"
+	default BUSYBOX_DEFAULT_LSMOD
+	depends on !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  lsmod is used to display a list of loaded modules.
+
+config BUSYBOX_CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+	bool "Pretty output"
+	default BUSYBOX_DEFAULT_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+	depends on BUSYBOX_CONFIG_LSMOD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This option makes output format of lsmod adjusted to
+	  the format of module-init-tools for Linux kernel 2.6.
+	  Increases size somewhat.
+
+config BUSYBOX_CONFIG_MODPROBE
+	bool "modprobe"
+	default BUSYBOX_DEFAULT_MODPROBE
+	depends on !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Handle the loading of modules, and their dependencies on a high
+	  level.
+
+config BUSYBOX_CONFIG_FEATURE_MODPROBE_BLACKLIST
+	bool "Blacklist support"
+	default BUSYBOX_DEFAULT_FEATURE_MODPROBE_BLACKLIST
+	depends on BUSYBOX_CONFIG_MODPROBE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Say 'y' here to enable support for the 'blacklist' command in
+	  modprobe.conf. This prevents the alias resolver to resolve
+	  blacklisted modules. This is useful if you want to prevent your
+	  hardware autodetection scripts to load modules like evdev, frame
+	  buffer drivers etc.
+
+config BUSYBOX_CONFIG_DEPMOD
+	bool "depmod"
+	default BUSYBOX_DEFAULT_DEPMOD
+	depends on !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  depmod generates modules.dep (and potentially modules.alias
+	  and modules.symbols) that contain dependency information
+	  for modprobe.
+
+comment "Options common to multiple modutils"
+
+config BUSYBOX_CONFIG_FEATURE_2_4_MODULES
+	bool "Support version 2.2/2.4 Linux kernels"
+	default BUSYBOX_DEFAULT_FEATURE_2_4_MODULES
+	depends on BUSYBOX_CONFIG_INSMOD || BUSYBOX_CONFIG_RMMOD || BUSYBOX_CONFIG_LSMOD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Support module loading for 2.2.x and 2.4.x Linux kernels.
+	  This increases size considerably. Say N unless you plan
+	  to run ancient kernels.
+
+config BUSYBOX_CONFIG_FEATURE_INSMOD_TRY_MMAP
+	bool "Try to load module from a mmap'ed area"
+	default BUSYBOX_DEFAULT_FEATURE_INSMOD_TRY_MMAP
+	depends on BUSYBOX_CONFIG_INSMOD || BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This option causes module loading code to try to mmap
+	  module first. If it does not work (for example,
+	  it does not work for compressed modules), module will be read
+	  (and unpacked if needed) into a memory block allocated by malloc.
+
+	  The only case when mmap works but malloc does not is when
+	  you are trying to load a big module on a very memory-constrained
+	  machine. Malloc will momentarily need 2x as much memory as mmap.
+
+	  Choosing N saves about 250 bytes of code (on 32-bit x86).
+
+config BUSYBOX_CONFIG_FEATURE_INSMOD_VERSION_CHECKING
+	bool "Enable module version checking"
+	default BUSYBOX_DEFAULT_FEATURE_INSMOD_VERSION_CHECKING
+	depends on BUSYBOX_CONFIG_FEATURE_2_4_MODULES && (BUSYBOX_CONFIG_INSMOD || BUSYBOX_CONFIG_MODPROBE)
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Support checking of versions for modules. This is used to
+	  ensure that the kernel and module are made for each other.
+
+config BUSYBOX_CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+	bool "Add module symbols to kernel symbol table"
+	default BUSYBOX_DEFAULT_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+	depends on BUSYBOX_CONFIG_FEATURE_2_4_MODULES && (BUSYBOX_CONFIG_INSMOD || BUSYBOX_CONFIG_MODPROBE)
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  By adding module symbols to the kernel symbol table, Oops messages
+	  occuring within kernel modules can be properly debugged. By enabling
+	  this feature, module symbols will always be added to the kernel symbol
+	  table for proper debugging support. If you are not interested in
+	  Oops messages from kernel modules, say N.
+
+config BUSYBOX_CONFIG_FEATURE_INSMOD_LOADINKMEM
+	bool "In kernel memory optimization (uClinux only)"
+	default BUSYBOX_DEFAULT_FEATURE_INSMOD_LOADINKMEM
+	depends on BUSYBOX_CONFIG_FEATURE_2_4_MODULES && (BUSYBOX_CONFIG_INSMOD || BUSYBOX_CONFIG_MODPROBE)
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This is a special uClinux only memory optimization that lets insmod
+	  load the specified kernel module directly into kernel space, reducing
+	  memory usage by preventing the need for two copies of the module
+	  being loaded into memory.
+
+config BUSYBOX_CONFIG_FEATURE_INSMOD_LOAD_MAP
+	bool "Enable insmod load map (-m) option"
+	default BUSYBOX_DEFAULT_FEATURE_INSMOD_LOAD_MAP
+	depends on BUSYBOX_CONFIG_FEATURE_2_4_MODULES && BUSYBOX_CONFIG_INSMOD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Enabling this, one would be able to get a load map
+	  output on stdout. This makes kernel module debugging
+	  easier.
+	  If you don't plan to debug kernel modules, you
+	  don't need this option.
+
+config BUSYBOX_CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL
+	bool "Symbols in load map"
+	default BUSYBOX_DEFAULT_FEATURE_INSMOD_LOAD_MAP_FULL
+	depends on BUSYBOX_CONFIG_FEATURE_INSMOD_LOAD_MAP && !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Without this option, -m will only output section
+	  load map. With this option, -m will also output
+	  symbols load map.
+
+config BUSYBOX_CONFIG_FEATURE_CHECK_TAINTED_MODULE
+	bool "Support tainted module checking with new kernels"
+	default BUSYBOX_DEFAULT_FEATURE_CHECK_TAINTED_MODULE
+	depends on (BUSYBOX_CONFIG_LSMOD || BUSYBOX_CONFIG_FEATURE_2_4_MODULES) && !BUSYBOX_CONFIG_MODPROBE_SMALL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Support checking for tainted modules. These are usually binary
+	  only modules that will make the linux-kernel list ignore your
+	  support request.
+	  This option is required to support GPLONLY modules.
+
+config BUSYBOX_CONFIG_FEATURE_MODUTILS_ALIAS
+	bool "Support for module.aliases file"
+	default BUSYBOX_DEFAULT_FEATURE_MODUTILS_ALIAS
+	depends on BUSYBOX_CONFIG_DEPMOD || BUSYBOX_CONFIG_MODPROBE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Generate and parse modules.alias containing aliases for bus
+	  identifiers:
+	    alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs
+
+	  and aliases for logical modules names e.g.:
+	    alias padlock_aes aes
+	    alias aes_i586 aes
+	    alias aes_generic aes
+
+	  Say Y if unsure.
+
+config BUSYBOX_CONFIG_FEATURE_MODUTILS_SYMBOLS
+	bool "Support for module.symbols file"
+	default BUSYBOX_DEFAULT_FEATURE_MODUTILS_SYMBOLS
+	depends on BUSYBOX_CONFIG_DEPMOD || BUSYBOX_CONFIG_MODPROBE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Generate and parse modules.symbols containing aliases for
+	  symbol_request() kernel calls, such as:
+	    alias symbol:usb_sg_init usbcore
+
+	  Say Y if unsure.
+
+config BUSYBOX_CONFIG_DEFAULT_MODULES_DIR
+	string "Default directory containing modules"
+	default BUSYBOX_DEFAULT_DEFAULT_MODULES_DIR
+	depends on BUSYBOX_CONFIG_DEPMOD || BUSYBOX_CONFIG_MODPROBE || BUSYBOX_CONFIG_MODPROBE_SMALL || BUSYBOX_CONFIG_MODINFO
+	help
+	  Directory that contains kernel modules.
+	  Defaults to "/lib/modules"
+
+config BUSYBOX_CONFIG_DEFAULT_DEPMOD_FILE
+	string "Default name of modules.dep"
+	default BUSYBOX_DEFAULT_DEFAULT_DEPMOD_FILE
+	depends on BUSYBOX_CONFIG_DEPMOD || BUSYBOX_CONFIG_MODPROBE || BUSYBOX_CONFIG_MODPROBE_SMALL || BUSYBOX_CONFIG_MODINFO
+	help
+	  Filename that contains kernel modules dependencies.
+	  Defaults to "modules.dep"
+
+endmenu
diff --git a/package/utils/busybox/config/networking/Config.in b/package/utils/busybox/config/networking/Config.in
new file mode 100644
index 0000000000..407ddd30dd
--- /dev/null
+++ b/package/utils/busybox/config/networking/Config.in
@@ -0,0 +1,1165 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Networking Utilities"
+
+config BUSYBOX_CONFIG_NAMEIF
+	bool "nameif"
+	default BUSYBOX_DEFAULT_NAMEIF
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  nameif is used to rename network interface by its MAC address.
+	  Renamed interfaces MUST be in the down state.
+	  It is possible to use a file (default: /etc/mactab)
+	  with list of new interface names and MACs.
+	  Maximum interface name length: IFNAMSIZ = 16
+	  File fields are separated by space or tab.
+	  File format:
+	  # Comment
+	  new_interface_name    XX:XX:XX:XX:XX:XX
+
+config BUSYBOX_CONFIG_FEATURE_NAMEIF_EXTENDED
+	bool "Extended nameif"
+	default BUSYBOX_DEFAULT_FEATURE_NAMEIF_EXTENDED
+	depends on BUSYBOX_CONFIG_NAMEIF
+	help
+	  This extends the nameif syntax to support the bus_info, driver,
+	  phyaddr selectors. The syntax is compatible to the normal nameif.
+	  File format:
+	    new_interface_name  driver=asix bus=usb-0000:00:08.2-3
+	    new_interface_name  bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5
+	    new_interface_name  phy_address=2 00:80:C8:38:91:B5
+	    new_interface_name  mac=00:80:C8:38:91:B5
+	    new_interface_name  00:80:C8:38:91:B5
+config BUSYBOX_CONFIG_NBDCLIENT
+	bool "nbd-client"
+	default BUSYBOX_DEFAULT_NBDCLIENT
+	help
+	  Network block device client
+config BUSYBOX_CONFIG_NC
+	bool "nc"
+	default BUSYBOX_DEFAULT_NC
+	help
+	  A simple Unix utility which reads and writes data across network
+	  connections.
+
+config BUSYBOX_CONFIG_NC_SERVER
+	bool "Netcat server options (-l)"
+	default BUSYBOX_DEFAULT_NC_SERVER
+	depends on BUSYBOX_CONFIG_NC
+	help
+	  Allow netcat to act as a server.
+
+config BUSYBOX_CONFIG_NC_EXTRA
+	bool "Netcat extensions (-eiw and -f FILE)"
+	default BUSYBOX_DEFAULT_NC_EXTRA
+	depends on BUSYBOX_CONFIG_NC
+	help
+	  Add -e (support for executing the rest of the command line after
+	  making or receiving a successful connection), -i (delay interval for
+	  lines sent), -w (timeout for initial connection).
+
+config BUSYBOX_CONFIG_NC_110_COMPAT
+	bool "Netcat 1.10 compatibility (+2.5k)"
+	default BUSYBOX_DEFAULT_NC_110_COMPAT  # off specially for Rob
+	depends on BUSYBOX_CONFIG_NC
+	help
+	  This option makes nc closely follow original nc-1.10.
+	  The code is about 2.5k bigger. It enables
+	  -s ADDR, -n, -u, -v, -o FILE, -z options, but loses
+	  busybox-specific extensions: -f FILE.
+config BUSYBOX_CONFIG_PING
+	bool "ping"
+	default BUSYBOX_DEFAULT_PING
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
+	  elicit an ICMP ECHO_RESPONSE from a host or gateway.
+
+config BUSYBOX_CONFIG_PING6
+	bool "ping6"
+	default BUSYBOX_DEFAULT_PING6
+	depends on BUSYBOX_CONFIG_FEATURE_IPV6 && BUSYBOX_CONFIG_PING
+	help
+	  This will give you a ping that can talk IPv6.
+
+config BUSYBOX_CONFIG_FEATURE_FANCY_PING
+	bool "Enable fancy ping output"
+	default BUSYBOX_DEFAULT_FEATURE_FANCY_PING
+	depends on BUSYBOX_CONFIG_PING
+	help
+	  Make the output from the ping applet include statistics, and at the
+	  same time provide full support for ICMP packets.
+config BUSYBOX_CONFIG_WGET
+	bool "wget"
+	default BUSYBOX_DEFAULT_WGET
+	help
+	  wget is a utility for non-interactive download of files from HTTP
+	  and FTP servers.
+
+config BUSYBOX_CONFIG_FEATURE_WGET_STATUSBAR
+	bool "Enable a nifty process meter (+2k)"
+	default BUSYBOX_DEFAULT_FEATURE_WGET_STATUSBAR
+	depends on BUSYBOX_CONFIG_WGET
+	help
+	  Enable the transfer progress bar for wget transfers.
+
+config BUSYBOX_CONFIG_FEATURE_WGET_AUTHENTICATION
+	bool "Enable HTTP authentication"
+	default BUSYBOX_DEFAULT_FEATURE_WGET_AUTHENTICATION
+	depends on BUSYBOX_CONFIG_WGET
+	help
+	  Support authenticated HTTP transfers.
+
+config BUSYBOX_CONFIG_FEATURE_WGET_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_WGET_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_WGET && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the wget applet.
+
+config BUSYBOX_CONFIG_FEATURE_WGET_TIMEOUT
+	bool "Enable timeout option -T SEC"
+	default BUSYBOX_DEFAULT_FEATURE_WGET_TIMEOUT
+	depends on BUSYBOX_CONFIG_WGET
+	help
+	  Supports network read and connect timeouts for wget,
+	  so that wget will give up and timeout, through the -T
+	  command line option.
+
+	  Currently only connect and network data read timeout are
+	  supported (i.e., timeout is not applied to the DNS query). When
+	  FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option
+	  will work in addition to -T.
+
+config BUSYBOX_CONFIG_FEATURE_WGET_OPENSSL
+	bool "Try to connect to HTTPS using openssl"
+	default BUSYBOX_DEFAULT_FEATURE_WGET_OPENSSL
+	depends on BUSYBOX_CONFIG_WGET
+	help
+	  Choose how wget establishes SSL connection for https:// URLs.
+
+	  Busybox itself contains no SSL code. wget will spawn
+	  a helper program to talk over HTTPS.
+
+	  OpenSSL has a simple SSL client for debug purposes.
+	  If you select "openssl" helper, wget will effectively call
+	  "openssl s_client -quiet -connect IP:443 2>/dev/null"
+	  and pipe its data through it.
+	  Note inconvenient API: host resolution is done twice,
+	  and there is no guarantee openssl's idea of IPv6 address
+	  format is the same as ours.
+	  Another problem is that s_client prints debug information
+	  to stderr, and it needs to be suppressed. This means
+	  all error messages get suppressed too.
+	  openssl is also a big binary, often dynamically linked
+	  against ~15 libraries.
+
+config BUSYBOX_CONFIG_FEATURE_WGET_SSL_HELPER
+	bool "Try to connect to HTTPS using ssl_helper"
+	default BUSYBOX_DEFAULT_FEATURE_WGET_SSL_HELPER
+	depends on BUSYBOX_CONFIG_WGET
+	help
+	  Choose how wget establishes SSL connection for https:// URLs.
+
+	  Busybox itself contains no SSL code. wget will spawn
+	  a helper program to talk over HTTPS.
+
+	  ssl_helper is a tool which can be built statically
+	  from busybox sources against a small embedded SSL library.
+	  Please see networking/ssl_helper/README.
+	  It does not require double host resolution and emits
+	  error messages to stderr.
+
+	  Precompiled static binary may be available at
+	  http://busybox.net/downloads/binaries/
+config BUSYBOX_CONFIG_WHOIS
+	bool "whois"
+	default BUSYBOX_DEFAULT_WHOIS
+	help
+	  whois is a client for the whois directory service
+
+config BUSYBOX_CONFIG_FEATURE_IPV6
+	bool "Enable IPv6 support"
+	default BUSYBOX_DEFAULT_FEATURE_IPV6
+	help
+	  Enable IPv6 support in busybox.
+	  This adds IPv6 support in the networking applets.
+
+config BUSYBOX_CONFIG_FEATURE_UNIX_LOCAL
+	bool "Enable Unix domain socket support (usually not needed)"
+	default BUSYBOX_DEFAULT_FEATURE_UNIX_LOCAL
+	help
+	  Enable Unix domain socket support in all busybox networking
+	  applets.  Address of the form local:/path/to/unix/socket
+	  will be recognized.
+
+	  This extension is almost never used in real world usage.
+	  You most likely want to say N.
+
+config BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS
+	bool "Prefer IPv4 addresses from DNS queries"
+	default BUSYBOX_DEFAULT_FEATURE_PREFER_IPV4_ADDRESS
+	depends on BUSYBOX_CONFIG_FEATURE_IPV6
+	help
+	  Use IPv4 address of network host if it has one.
+
+	  If this option is off, the first returned address will be used.
+	  This may cause problems when your DNS server is IPv6-capable and
+	  is returning IPv6 host addresses too. If IPv6 address
+	  precedes IPv4 one in DNS reply, busybox network applets
+	  (e.g. wget) will use IPv6 address. On an IPv6-incapable host
+	  or network applets will fail to connect to the host
+	  using IPv6 address.
+
+config BUSYBOX_CONFIG_VERBOSE_RESOLUTION_ERRORS
+	bool "Verbose resolution errors"
+	default BUSYBOX_DEFAULT_VERBOSE_RESOLUTION_ERRORS
+	help
+	  Enable if you are not satisfied with simplistic
+	  "can't resolve 'hostname.com'" and want to know more.
+	  This may increase size of your executable a bit.
+
+config BUSYBOX_CONFIG_ARP
+	bool "arp"
+	default BUSYBOX_DEFAULT_ARP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Manipulate the system ARP cache.
+
+config BUSYBOX_CONFIG_ARPING
+	bool "arping"
+	default BUSYBOX_DEFAULT_ARPING
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Ping hosts by ARP packets.
+
+config BUSYBOX_CONFIG_BRCTL
+	bool "brctl"
+	default BUSYBOX_DEFAULT_BRCTL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Manage ethernet bridges.
+	  Supports addbr/delbr and addif/delif.
+
+config BUSYBOX_CONFIG_FEATURE_BRCTL_FANCY
+	bool "Fancy options"
+	default BUSYBOX_DEFAULT_FEATURE_BRCTL_FANCY
+	depends on BUSYBOX_CONFIG_BRCTL
+	help
+	  Add support for extended option like:
+	    setageing, setfd, sethello, setmaxage,
+	    setpathcost, setportprio, setbridgeprio,
+	    stp
+	  This adds about 600 bytes.
+
+config BUSYBOX_CONFIG_FEATURE_BRCTL_SHOW
+	bool "Support show"
+	default BUSYBOX_DEFAULT_FEATURE_BRCTL_SHOW
+	depends on BUSYBOX_CONFIG_BRCTL && BUSYBOX_CONFIG_FEATURE_BRCTL_FANCY
+	help
+	  Add support for option which prints the current config:
+	    show
+
+config BUSYBOX_CONFIG_DNSD
+	bool "dnsd"
+	default BUSYBOX_DEFAULT_DNSD
+	help
+	  Small and static DNS server daemon.
+
+config BUSYBOX_CONFIG_ETHER_WAKE
+	bool "ether-wake"
+	default BUSYBOX_DEFAULT_ETHER_WAKE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Send a magic packet to wake up sleeping machines.
+
+config BUSYBOX_CONFIG_FAKEIDENTD
+	bool "fakeidentd"
+	default BUSYBOX_DEFAULT_FAKEIDENTD
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  fakeidentd listens on the ident port and returns a predefined
+	  fake value on any query.
+
+config BUSYBOX_CONFIG_FTPD
+	bool "ftpd"
+	default BUSYBOX_DEFAULT_FTPD
+	help
+	  simple FTP daemon. You have to run it via inetd.
+
+config BUSYBOX_CONFIG_FEATURE_FTP_WRITE
+	bool "Enable upload commands"
+	default BUSYBOX_DEFAULT_FEATURE_FTP_WRITE
+	depends on BUSYBOX_CONFIG_FTPD
+	help
+	  Enable all kinds of FTP upload commands (-w option)
+
+config BUSYBOX_CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST
+	bool "Enable workaround for RFC-violating clients"
+	default BUSYBOX_DEFAULT_FEATURE_FTPD_ACCEPT_BROKEN_LIST
+	depends on BUSYBOX_CONFIG_FTPD
+	help
+	  Some ftp clients (among them KDE's Konqueror) issue illegal
+	  "LIST -l" requests. This option works around such problems.
+	  It might prevent you from listing files starting with "-" and
+	  it increases the code size by ~40 bytes.
+	  Most other ftp servers seem to behave similar to this.
+
+config BUSYBOX_CONFIG_FEATURE_FTP_AUTHENTICATION
+	bool "Enable authentication"
+	default BUSYBOX_DEFAULT_FEATURE_FTP_AUTHENTICATION
+	depends on BUSYBOX_CONFIG_FTPD
+	help
+	  Enable basic system login as seen in telnet etc.
+
+config BUSYBOX_CONFIG_FTPGET
+	bool "ftpget"
+	default BUSYBOX_DEFAULT_FTPGET
+	help
+	  Retrieve a remote file via FTP.
+
+config BUSYBOX_CONFIG_FTPPUT
+	bool "ftpput"
+	default BUSYBOX_DEFAULT_FTPPUT
+	help
+	  Store a remote file via FTP.
+
+config BUSYBOX_CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS
+	bool "Enable long options in ftpget/ftpput"
+	default BUSYBOX_DEFAULT_FEATURE_FTPGETPUT_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_LONG_OPTS && (BUSYBOX_CONFIG_FTPGET || BUSYBOX_CONFIG_FTPPUT)
+	help
+	  Support long options for the ftpget/ftpput applet.
+
+config BUSYBOX_CONFIG_HOSTNAME
+	bool "hostname"
+	default BUSYBOX_DEFAULT_HOSTNAME
+	help
+	  Show or set the system's host name.
+
+config BUSYBOX_CONFIG_HTTPD
+	bool "httpd"
+	default BUSYBOX_DEFAULT_HTTPD
+	help
+	  Serve web pages via an HTTP server.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_RANGES
+	bool "Support 'Ranges:' header"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_RANGES
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  Makes httpd emit "Accept-Ranges: bytes" header and understand
+	  "Range: bytes=NNN-[MMM]" header. Allows for resuming interrupted
+	  downloads, seeking in multimedia players etc.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_SETUID
+	bool "Enable -u <user> option"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_SETUID
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  This option allows the server to run as a specific user
+	  rather than defaulting to the user that starts the server.
+	  Use of this option requires special privileges to change to a
+	  different user.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_BASIC_AUTH
+	bool "Enable Basic http Authentication"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_BASIC_AUTH
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  Utilizes password settings from /etc/httpd.conf for basic
+	  authentication on a per url basis.
+	  Example for httpd.conf file:
+	  /adm:toor:PaSsWd
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_AUTH_MD5
+	bool "Support MD5 crypted passwords for http Authentication"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_AUTH_MD5
+	depends on BUSYBOX_CONFIG_FEATURE_HTTPD_BASIC_AUTH
+	help
+	  Enables encrypted passwords, and wildcard user/passwords
+	  in httpd.conf file.
+	  User '*' means 'any system user name is ok',
+	  password of '*' means 'use system password for this user'
+	  Examples:
+	  /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0
+	  /adm:root:*
+	  /wiki:*:*
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_CGI
+	bool "Support Common Gateway Interface (CGI)"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_CGI
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  This option allows scripts and executables to be invoked
+	  when specific URLs are requested.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	bool "Support for running scripts through an interpreter"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	depends on BUSYBOX_CONFIG_FEATURE_HTTPD_CGI
+	help
+	  This option enables support for running scripts through an
+	  interpreter. Turn this on if you want PHP scripts to work
+	  properly. You need to supply an additional line in your
+	  httpd.conf file:
+	  *.php:/path/to/your/php
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
+	bool "Set REMOTE_PORT environment variable for CGI"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
+	depends on BUSYBOX_CONFIG_FEATURE_HTTPD_CGI
+	help
+	  Use of this option can assist scripts in generating
+	  references that contain a unique port number.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_ENCODE_URL_STR
+	bool "Enable -e option (useful for CGIs written as shell scripts)"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_ENCODE_URL_STR
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  This option allows html encoding of arbitrary strings for display
+	  by the browser. Output goes to stdout.
+	  For example, httpd -e "<Hello World>" produces
+	  "&#60Hello&#32World&#62".
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_ERROR_PAGES
+	bool "Support for custom error pages"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_ERROR_PAGES
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  This option allows you to define custom error pages in
+	  the configuration file instead of the default HTTP status
+	  error pages. For instance, if you add the line:
+	        E404:/path/e404.html
+	  in the config file, the server will respond the specified
+	  '/path/e404.html' file instead of the terse '404 NOT FOUND'
+	  message.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_PROXY
+	bool "Support for reverse proxy"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_PROXY
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  This option allows you to define URLs that will be forwarded
+	  to another HTTP server. To setup add the following line to the
+	  configuration file
+	        P:/url/:http://hostname[:port]/new/path/
+	  Then a request to /url/myfile will be forwarded to
+	  http://hostname[:port]/new/path/myfile.
+
+config BUSYBOX_CONFIG_FEATURE_HTTPD_GZIP
+	bool "Support for GZIP content encoding"
+	default BUSYBOX_DEFAULT_FEATURE_HTTPD_GZIP
+	depends on BUSYBOX_CONFIG_HTTPD
+	help
+	  Makes httpd send files using GZIP content encoding if the
+	  client supports it and a pre-compressed <file>.gz exists.
+
+config BUSYBOX_CONFIG_IFCONFIG
+	bool "ifconfig"
+	default BUSYBOX_DEFAULT_IFCONFIG
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Ifconfig is used to configure the kernel-resident network interfaces.
+
+config BUSYBOX_CONFIG_FEATURE_IFCONFIG_STATUS
+	bool "Enable status reporting output (+7k)"
+	default BUSYBOX_DEFAULT_FEATURE_IFCONFIG_STATUS
+	depends on BUSYBOX_CONFIG_IFCONFIG
+	help
+	  If ifconfig is called with no arguments it will display the status
+	  of the currently active interfaces.
+
+config BUSYBOX_CONFIG_FEATURE_IFCONFIG_SLIP
+	bool "Enable slip-specific options \"keepalive\" and \"outfill\""
+	default BUSYBOX_DEFAULT_FEATURE_IFCONFIG_SLIP
+	depends on BUSYBOX_CONFIG_IFCONFIG
+	help
+	  Allow "keepalive" and "outfill" support for SLIP. If you're not
+	  planning on using serial lines, leave this unchecked.
+
+config BUSYBOX_CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+	bool "Enable options \"mem_start\", \"io_addr\", and \"irq\""
+	default BUSYBOX_DEFAULT_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
+	depends on BUSYBOX_CONFIG_IFCONFIG
+	help
+	  Allow the start address for shared memory, start address for I/O,
+	  and/or the interrupt line used by the specified device.
+
+config BUSYBOX_CONFIG_FEATURE_IFCONFIG_HW
+	bool "Enable option \"hw\" (ether only)"
+	default BUSYBOX_DEFAULT_FEATURE_IFCONFIG_HW
+	depends on BUSYBOX_CONFIG_IFCONFIG
+	help
+	  Set the hardware address of this interface, if the device driver
+	  supports  this  operation. Currently, we only support the 'ether'
+	  class.
+
+config BUSYBOX_CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
+	bool "Set the broadcast automatically"
+	default BUSYBOX_DEFAULT_FEATURE_IFCONFIG_BROADCAST_PLUS
+	depends on BUSYBOX_CONFIG_IFCONFIG
+	help
+	  Setting this will make ifconfig attempt to find the broadcast
+	  automatically if the value '+' is used.
+
+config BUSYBOX_CONFIG_IFENSLAVE
+	bool "ifenslave"
+	default BUSYBOX_DEFAULT_IFENSLAVE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Userspace application to bind several interfaces
+	  to a logical interface (use with kernel bonding driver).
+
+config BUSYBOX_CONFIG_IFPLUGD
+	bool "ifplugd"
+	default BUSYBOX_DEFAULT_IFPLUGD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Network interface plug detection daemon.
+
+config BUSYBOX_CONFIG_IFUPDOWN
+	bool "ifupdown"
+	default BUSYBOX_DEFAULT_IFUPDOWN
+	help
+	  Activate or deactivate the specified interfaces. This applet makes
+	  use of either "ifconfig" and "route" or the "ip" command to actually
+	  configure network interfaces. Therefore, you will probably also want
+	  to enable either IFCONFIG and ROUTE, or enable
+	  FEATURE_IFUPDOWN_IP and the various IP options. Of
+	  course you could use non-busybox versions of these programs, so
+	  against my better judgement (since this will surely result in plenty
+	  of support questions on the mailing list), I do not force you to
+	  enable these additional options. It is up to you to supply either
+	  "ifconfig", "route" and "run-parts" or the "ip" command, either
+	  via busybox or via standalone utilities.
+
+config BUSYBOX_CONFIG_IFUPDOWN_IFSTATE_PATH
+	string "Absolute path to ifstate file"
+	default BUSYBOX_DEFAULT_IFUPDOWN_IFSTATE_PATH
+	depends on BUSYBOX_CONFIG_IFUPDOWN
+	help
+	  ifupdown keeps state information in a file called ifstate.
+	  Typically it is located in /var/run/ifstate, however
+	  some distributions tend to put it in other places
+	  (debian, for example, uses /etc/network/run/ifstate).
+	  This config option defines location of ifstate.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IP
+	bool "Use ip applet"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IP
+	depends on BUSYBOX_CONFIG_IFUPDOWN
+	help
+	  Use the iproute "ip" command to implement "ifup" and "ifdown", rather
+	  than the default of using the older 'ifconfig' and 'route' utilities.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN
+	bool "Use busybox ip applet"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IP_BUILTIN
+	depends on BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	select BUSYBOX_CONFIG_IP
+	select BUSYBOX_CONFIG_FEATURE_IP_ADDRESS
+	select BUSYBOX_CONFIG_FEATURE_IP_LINK
+	select BUSYBOX_CONFIG_FEATURE_IP_ROUTE
+	help
+	  Use the busybox iproute "ip" applet to implement "ifupdown".
+
+	  If left disabled, you must install the full-blown iproute2
+	  utility or the  "ifup" and "ifdown" applets will not work.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN
+	bool "Use busybox ifconfig and route applets"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN
+	depends on BUSYBOX_CONFIG_IFUPDOWN && !BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IP
+	select BUSYBOX_CONFIG_IFCONFIG
+	select BUSYBOX_CONFIG_ROUTE
+	help
+	  Use the busybox iproute "ifconfig" and "route" applets to
+	  implement the "ifup" and "ifdown" utilities.
+
+	  If left disabled, you must install the full-blown ifconfig
+	  and route utilities, or the  "ifup" and "ifdown" applets will not
+	  work.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IPV4
+	bool "Support for IPv4"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IPV4
+	depends on BUSYBOX_CONFIG_IFUPDOWN
+	help
+	  If you want ifup/ifdown to talk IPv4, leave this on.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_IPV6
+	bool "Support for IPv6"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_IPV6
+	depends on BUSYBOX_CONFIG_IFUPDOWN && BUSYBOX_CONFIG_FEATURE_IPV6
+	help
+	  If you need support for IPv6, turn this option on.
+
+### UNUSED
+###config FEATURE_IFUPDOWN_IPX
+###	bool "Support for IPX"
+###	default y
+###	depends on IFUPDOWN
+###	help
+###	  If this option is selected you can use busybox to work with IPX
+###	  networks.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_MAPPING
+	bool "Enable mapping support"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_MAPPING
+	depends on BUSYBOX_CONFIG_IFUPDOWN
+	help
+	  This enables support for the "mapping" stanza, unless you have
+	  a weird network setup you don't need it.
+
+config BUSYBOX_CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP
+	bool "Support for external dhcp clients"
+	default BUSYBOX_DEFAULT_FEATURE_IFUPDOWN_EXTERNAL_DHCP
+	depends on BUSYBOX_CONFIG_IFUPDOWN
+	help
+	  This enables support for the external dhcp clients. Clients are
+	  tried in the following order: dhcpcd, dhclient, pump and udhcpc.
+	  Otherwise, if udhcpc applet is enabled, it is used.
+	  Otherwise, ifup/ifdown will have no support for DHCP.
+
+config BUSYBOX_CONFIG_INETD
+	bool "inetd"
+	default BUSYBOX_DEFAULT_INETD
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  Internet superserver daemon
+
+config BUSYBOX_CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+	bool "Support echo service"
+	default BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
+	depends on BUSYBOX_CONFIG_INETD
+	help
+	  Echo received data internal inetd service
+
+config BUSYBOX_CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+	bool "Support discard service"
+	default BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
+	depends on BUSYBOX_CONFIG_INETD
+	help
+	  Internet /dev/null internal inetd service
+
+config BUSYBOX_CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
+	bool "Support time service"
+	default BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_TIME
+	depends on BUSYBOX_CONFIG_INETD
+	help
+	  Return 32 bit time since 1900 internal inetd service
+
+config BUSYBOX_CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+	bool "Support daytime service"
+	default BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
+	depends on BUSYBOX_CONFIG_INETD
+	help
+	  Return human-readable time internal inetd service
+
+config BUSYBOX_CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+	bool "Support chargen service"
+	default BUSYBOX_DEFAULT_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
+	depends on BUSYBOX_CONFIG_INETD
+	help
+	  Familiar character generator internal inetd service
+
+config BUSYBOX_CONFIG_FEATURE_INETD_RPC
+	bool "Support RPC services"
+	default BUSYBOX_DEFAULT_FEATURE_INETD_RPC  # very rarely used, and needs Sun RPC support in libc
+	depends on BUSYBOX_CONFIG_INETD
+	select BUSYBOX_CONFIG_FEATURE_HAVE_RPC
+	help
+	  Support Sun-RPC based services
+
+config BUSYBOX_CONFIG_IP
+	bool "ip"
+	default BUSYBOX_DEFAULT_IP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The "ip" applet is a TCP/IP interface configuration and routing
+	  utility. You generally don't need "ip" to use busybox with
+	  TCP/IP.
+
+config BUSYBOX_CONFIG_FEATURE_IP_ADDRESS
+	bool "ip address"
+	default BUSYBOX_DEFAULT_FEATURE_IP_ADDRESS
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Address manipulation support for the "ip" applet.
+
+config BUSYBOX_CONFIG_FEATURE_IP_LINK
+	bool "ip link"
+	default BUSYBOX_DEFAULT_FEATURE_IP_LINK
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Configure network devices with "ip".
+
+config BUSYBOX_CONFIG_FEATURE_IP_ROUTE
+	bool "ip route"
+	default BUSYBOX_DEFAULT_FEATURE_IP_ROUTE
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Add support for routing table management to "ip".
+
+config BUSYBOX_CONFIG_FEATURE_IP_ROUTE_DIR
+	string "ip route configuration directory"
+	default BUSYBOX_DEFAULT_FEATURE_IP_ROUTE_DIR
+	depends on BUSYBOX_CONFIG_FEATURE_IP_ROUTE
+	help
+	  Location of the "ip" applet routing configuration.
+
+config BUSYBOX_CONFIG_FEATURE_IP_TUNNEL
+	bool "ip tunnel"
+	default BUSYBOX_DEFAULT_FEATURE_IP_TUNNEL
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Add support for tunneling commands to "ip".
+
+config BUSYBOX_CONFIG_FEATURE_IP_RULE
+	bool "ip rule"
+	default BUSYBOX_DEFAULT_FEATURE_IP_RULE
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Add support for rule commands to "ip".
+
+config BUSYBOX_CONFIG_FEATURE_IP_NEIGH
+	bool "ip neighbor"
+	default BUSYBOX_DEFAULT_FEATURE_IP_NEIGH
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Add support for neighbor commands to "ip".
+
+config BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS
+	bool "Support short forms of ip commands"
+	default BUSYBOX_DEFAULT_FEATURE_IP_SHORT_FORMS
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  Also support short-form of ip <OBJECT> commands:
+	  ip addr   -> ipaddr
+	  ip link   -> iplink
+	  ip route  -> iproute
+	  ip tunnel -> iptunnel
+	  ip rule   -> iprule
+	  ip neigh  -> ipneigh
+
+	  Say N unless you desparately need the short form of the ip
+	  object commands.
+
+config BUSYBOX_CONFIG_FEATURE_IP_RARE_PROTOCOLS
+	bool "Support displaying rarely used link types"
+	default BUSYBOX_DEFAULT_FEATURE_IP_RARE_PROTOCOLS
+	depends on BUSYBOX_CONFIG_IP
+	help
+	  If you are not going to use links of type "frad", "econet",
+	  "bif" etc, you probably don't need to enable this.
+	  Ethernet, wireless, infrared, ppp/slip, ip tunnelling
+	  link types are supported without this option selected.
+
+config BUSYBOX_CONFIG_IPADDR
+	bool
+	default BUSYBOX_DEFAULT_IPADDR
+	depends on BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS && BUSYBOX_CONFIG_FEATURE_IP_ADDRESS
+
+config BUSYBOX_CONFIG_IPLINK
+	bool
+	default BUSYBOX_DEFAULT_IPLINK
+	depends on BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS && BUSYBOX_CONFIG_FEATURE_IP_LINK
+
+config BUSYBOX_CONFIG_IPROUTE
+	bool
+	default BUSYBOX_DEFAULT_IPROUTE
+	depends on BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS && BUSYBOX_CONFIG_FEATURE_IP_ROUTE
+
+config BUSYBOX_CONFIG_IPTUNNEL
+	bool
+	default BUSYBOX_DEFAULT_IPTUNNEL
+	depends on BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS && BUSYBOX_CONFIG_FEATURE_IP_TUNNEL
+
+config BUSYBOX_CONFIG_IPRULE
+	bool
+	default BUSYBOX_DEFAULT_IPRULE
+	depends on BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS && BUSYBOX_CONFIG_FEATURE_IP_RULE
+
+config BUSYBOX_CONFIG_IPNEIGH
+	bool
+	default BUSYBOX_DEFAULT_IPNEIGH
+	depends on BUSYBOX_CONFIG_FEATURE_IP_SHORT_FORMS && BUSYBOX_CONFIG_FEATURE_IP_NEIGH
+
+config BUSYBOX_CONFIG_IPCALC
+	bool "ipcalc"
+	default BUSYBOX_DEFAULT_IPCALC
+	help
+	  ipcalc takes an IP address and netmask and calculates the
+	  resulting broadcast, network, and host range.
+
+config BUSYBOX_CONFIG_FEATURE_IPCALC_FANCY
+	bool "Fancy IPCALC, more options, adds 1 kbyte"
+	default BUSYBOX_DEFAULT_FEATURE_IPCALC_FANCY
+	depends on BUSYBOX_CONFIG_IPCALC
+	help
+	  Adds the options hostname, prefix and silent to the output of
+	  "ipcalc".
+
+config BUSYBOX_CONFIG_FEATURE_IPCALC_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_IPCALC_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_IPCALC && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the ipcalc applet.
+
+config BUSYBOX_CONFIG_NETMSG
+	bool "netmsg"
+	default BUSYBOX_DEFAULT_NETMSG
+	help
+	  simple program for sending udp broadcast messages
+
+config BUSYBOX_CONFIG_NETSTAT
+	bool "netstat"
+	default BUSYBOX_DEFAULT_NETSTAT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  netstat prints information about the Linux networking subsystem.
+
+config BUSYBOX_CONFIG_FEATURE_NETSTAT_WIDE
+	bool "Enable wide netstat output"
+	default BUSYBOX_DEFAULT_FEATURE_NETSTAT_WIDE
+	depends on BUSYBOX_CONFIG_NETSTAT
+	help
+	  Add support for wide columns. Useful when displaying IPv6 addresses
+	  (-W option).
+
+config BUSYBOX_CONFIG_FEATURE_NETSTAT_PRG
+	bool "Enable PID/Program name output"
+	default BUSYBOX_DEFAULT_FEATURE_NETSTAT_PRG
+	depends on BUSYBOX_CONFIG_NETSTAT
+	help
+	  Add support for -p flag to print out PID and program name.
+	  +700 bytes of code.
+
+config BUSYBOX_CONFIG_NSLOOKUP
+	bool "nslookup"
+	default BUSYBOX_DEFAULT_NSLOOKUP
+	help
+	  nslookup is a tool to query Internet name servers.
+
+config BUSYBOX_CONFIG_NTPD
+	bool "ntpd"
+	default BUSYBOX_DEFAULT_NTPD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The NTP client/server daemon.
+
+config BUSYBOX_CONFIG_FEATURE_NTPD_SERVER
+	bool "Make ntpd usable as a NTP server"
+	default BUSYBOX_DEFAULT_FEATURE_NTPD_SERVER
+	depends on BUSYBOX_CONFIG_NTPD
+	help
+	  Make ntpd usable as a NTP server. If you disable this option
+	  ntpd will be usable only as a NTP client.
+
+config BUSYBOX_CONFIG_FEATURE_NTPD_CONF
+	bool "Make ntpd understand /etc/ntp.conf"
+	default BUSYBOX_DEFAULT_FEATURE_NTPD_CONF
+	depends on BUSYBOX_CONFIG_NTPD
+	help
+	  Make ntpd look in /etc/ntp.conf for peers. Only "server address"
+	  is supported.
+
+config BUSYBOX_CONFIG_PSCAN
+	bool "pscan"
+	default BUSYBOX_DEFAULT_PSCAN
+	help
+	  Simple network port scanner.
+
+config BUSYBOX_CONFIG_ROUTE
+	bool "route"
+	default BUSYBOX_DEFAULT_ROUTE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Route displays or manipulates the kernel's IP routing tables.
+
+config BUSYBOX_CONFIG_SLATTACH
+	bool "slattach"
+	default BUSYBOX_DEFAULT_SLATTACH
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  slattach is a small utility to attach network interfaces to serial
+	  lines.
+
+#config TC
+#	bool "tc"
+#	default y
+#	help
+#	  show / manipulate traffic control settings
+#
+#config FEATURE_TC_INGRESS
+#	def_bool n
+#	depends on TC
+
+config BUSYBOX_CONFIG_TCPSVD
+	bool "tcpsvd"
+	default BUSYBOX_DEFAULT_TCPSVD
+	help
+	  tcpsvd listens on a TCP port and runs a program for each new
+	  connection.
+
+config BUSYBOX_CONFIG_TELNET
+	bool "telnet"
+	default BUSYBOX_DEFAULT_TELNET
+	help
+	  Telnet is an interface to the TELNET protocol, but is also commonly
+	  used to test other simple protocols.
+
+config BUSYBOX_CONFIG_FEATURE_TELNET_TTYPE
+	bool "Pass TERM type to remote host"
+	default BUSYBOX_DEFAULT_FEATURE_TELNET_TTYPE
+	depends on BUSYBOX_CONFIG_TELNET
+	help
+	  Setting this option will forward the TERM environment variable to the
+	  remote host you are connecting to. This is useful to make sure that
+	  things like ANSI colors and other control sequences behave.
+
+config BUSYBOX_CONFIG_FEATURE_TELNET_AUTOLOGIN
+	bool "Pass USER type to remote host"
+	default BUSYBOX_DEFAULT_FEATURE_TELNET_AUTOLOGIN
+	depends on BUSYBOX_CONFIG_TELNET
+	help
+	  Setting this option will forward the USER environment variable to the
+	  remote host you are connecting to. This is useful when you need to
+	  log into a machine without telling the username (autologin). This
+	  option enables `-a' and `-l USER' arguments.
+
+config BUSYBOX_CONFIG_TELNETD
+	bool "telnetd"
+	default BUSYBOX_DEFAULT_TELNETD
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  A daemon for the TELNET protocol, allowing you to log onto the host
+	  running the daemon. Please keep in mind that the TELNET protocol
+	  sends passwords in plain text. If you can't afford the space for an
+	  SSH daemon and you trust your network, you may say 'y' here. As a
+	  more secure alternative, you should seriously consider installing the
+	  very small Dropbear SSH daemon instead:
+		http://matt.ucc.asn.au/dropbear/dropbear.html
+
+	  Note that for busybox telnetd to work you need several things:
+	  First of all, your kernel needs:
+		  CONFIG_UNIX98_PTYS=y
+
+	  Next, you need a /dev/pts directory on your root filesystem:
+
+		  $ ls -ld /dev/pts
+		  drwxr-xr-x  2 root root 0 Sep 23 13:21 /dev/pts/
+
+	  Next you need the pseudo terminal master multiplexer /dev/ptmx:
+
+		  $ ls -la /dev/ptmx
+		  crw-rw-rw-  1 root tty 5, 2 Sep 23 13:55 /dev/ptmx
+
+	  Any /dev/ttyp[0-9]* files you may have can be removed.
+	  Next, you need to mount the devpts filesystem on /dev/pts using:
+
+		  mount -t devpts devpts /dev/pts
+
+	  You need to be sure that busybox has LOGIN and
+	  FEATURE_SUID enabled. And finally, you should make
+	  certain that Busybox has been installed setuid root:
+
+		chown root.root /bin/busybox
+		chmod 4755 /bin/busybox
+
+	  with all that done, telnetd _should_ work....
+
+
+config BUSYBOX_CONFIG_FEATURE_TELNETD_STANDALONE
+	bool "Support standalone telnetd (not inetd only)"
+	default BUSYBOX_DEFAULT_FEATURE_TELNETD_STANDALONE
+	depends on BUSYBOX_CONFIG_TELNETD
+	help
+	  Selecting this will make telnetd able to run standalone.
+
+config BUSYBOX_CONFIG_FEATURE_TELNETD_INETD_WAIT
+	bool "Support -w SEC option (inetd wait mode)"
+	default BUSYBOX_DEFAULT_FEATURE_TELNETD_INETD_WAIT
+	depends on BUSYBOX_CONFIG_FEATURE_TELNETD_STANDALONE
+	help
+	  This option allows you to run telnetd in "inet wait" mode.
+	  Example inetd.conf line (note "wait", not usual "nowait"):
+
+	  telnet stream tcp wait root /bin/telnetd telnetd -w10
+
+	  In this example, inetd passes _listening_ socket_ as fd 0
+	  to telnetd when connection appears.
+	  telnetd will wait for connections until all existing
+	  connections are closed, and no new connections
+	  appear during 10 seconds. Then it exits, and inetd continues
+	  to listen for new connections.
+
+	  This option is rarely used. "tcp nowait" is much more usual
+	  way of running tcp services, including telnetd.
+	  You most probably want to say N here.
+
+config BUSYBOX_CONFIG_TFTP
+	bool "tftp"
+	default BUSYBOX_DEFAULT_TFTP
+	help
+	  This enables the Trivial File Transfer Protocol client program. TFTP
+	  is usually used for simple, small transfers such as a root image
+	  for a network-enabled bootloader.
+
+config BUSYBOX_CONFIG_TFTPD
+	bool "tftpd"
+	default BUSYBOX_DEFAULT_TFTPD
+	help
+	  This enables the Trivial File Transfer Protocol server program.
+	  It expects that stdin is a datagram socket and a packet
+	  is already pending on it. It will exit after one transfer.
+	  In other words: it should be run from inetd in nowait mode,
+	  or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR"
+
+comment "Common options for tftp/tftpd"
+	depends on BUSYBOX_CONFIG_TFTP || BUSYBOX_CONFIG_TFTPD
+
+config BUSYBOX_CONFIG_FEATURE_TFTP_GET
+	bool "Enable 'tftp get' and/or tftpd upload code"
+	default BUSYBOX_DEFAULT_FEATURE_TFTP_GET
+	depends on BUSYBOX_CONFIG_TFTP || BUSYBOX_CONFIG_TFTPD
+	help
+	  Add support for the GET command within the TFTP client. This allows
+	  a client to retrieve a file from a TFTP server.
+	  Also enable upload support in tftpd, if tftpd is selected.
+
+	  Note: this option does _not_ make tftpd capable of download
+	  (the usual operation people need from it)!
+
+config BUSYBOX_CONFIG_FEATURE_TFTP_PUT
+	bool "Enable 'tftp put' and/or tftpd download code"
+	default BUSYBOX_DEFAULT_FEATURE_TFTP_PUT
+	depends on BUSYBOX_CONFIG_TFTP || BUSYBOX_CONFIG_TFTPD
+	help
+	  Add support for the PUT command within the TFTP client. This allows
+	  a client to transfer a file to a TFTP server.
+	  Also enable download support in tftpd, if tftpd is selected.
+
+config BUSYBOX_CONFIG_FEATURE_TFTP_BLOCKSIZE
+	bool "Enable 'blksize' and 'tsize' protocol options"
+	default BUSYBOX_DEFAULT_FEATURE_TFTP_BLOCKSIZE
+	depends on BUSYBOX_CONFIG_TFTP || BUSYBOX_CONFIG_TFTPD
+	help
+	  Allow tftp to specify block size, and tftpd to understand
+	  "blksize" and "tsize" options.
+
+config BUSYBOX_CONFIG_FEATURE_TFTP_PROGRESS_BAR
+	bool "Enable tftp progress meter"
+	default BUSYBOX_DEFAULT_FEATURE_TFTP_PROGRESS_BAR
+	depends on BUSYBOX_CONFIG_TFTP && BUSYBOX_CONFIG_FEATURE_TFTP_BLOCKSIZE
+	help
+	  Show progress bar.
+
+config BUSYBOX_CONFIG_TFTP_DEBUG
+	bool "Enable debug"
+	default BUSYBOX_DEFAULT_TFTP_DEBUG
+	depends on BUSYBOX_CONFIG_TFTP || BUSYBOX_CONFIG_TFTPD
+	help
+	  Make tftp[d] print debugging messages on stderr.
+	  This is useful if you are diagnosing a bug in tftp[d].
+
+config BUSYBOX_CONFIG_TRACEROUTE
+	bool "traceroute"
+	default BUSYBOX_DEFAULT_TRACEROUTE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Utility to trace the route of IP packets.
+
+config BUSYBOX_CONFIG_TRACEROUTE6
+	bool "traceroute6"
+	default BUSYBOX_DEFAULT_TRACEROUTE6
+	depends on BUSYBOX_CONFIG_FEATURE_IPV6 && BUSYBOX_CONFIG_TRACEROUTE
+	help
+	  Utility to trace the route of IPv6 packets.
+
+config BUSYBOX_CONFIG_FEATURE_TRACEROUTE_VERBOSE
+	bool "Enable verbose output"
+	default BUSYBOX_DEFAULT_FEATURE_TRACEROUTE_VERBOSE
+	depends on BUSYBOX_CONFIG_TRACEROUTE
+	help
+	  Add some verbosity to traceroute. This includes among other things
+	  hostnames and ICMP response types.
+
+config BUSYBOX_CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
+	bool "Enable loose source route"
+	default BUSYBOX_DEFAULT_FEATURE_TRACEROUTE_SOURCE_ROUTE
+	depends on BUSYBOX_CONFIG_TRACEROUTE
+	help
+	  Add option to specify a loose source route gateway
+	  (8 maximum).
+
+config BUSYBOX_CONFIG_FEATURE_TRACEROUTE_USE_ICMP
+	bool "Use ICMP instead of UDP"
+	default BUSYBOX_DEFAULT_FEATURE_TRACEROUTE_USE_ICMP
+	depends on BUSYBOX_CONFIG_TRACEROUTE
+	help
+	  Add option -I to use ICMP ECHO instead of UDP datagrams.
+
+config BUSYBOX_CONFIG_TUNCTL
+	bool "tunctl"
+	default BUSYBOX_DEFAULT_TUNCTL
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  tunctl creates or deletes tun devices.
+
+config BUSYBOX_CONFIG_FEATURE_TUNCTL_UG
+	bool "Support owner:group assignment"
+	default BUSYBOX_DEFAULT_FEATURE_TUNCTL_UG
+	depends on BUSYBOX_CONFIG_TUNCTL
+	help
+	  Allow to specify owner and group of newly created interface.
+	  340 bytes of pure bloat. Say no here.
+
+source udhcp/Config.in
+
+config BUSYBOX_CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
+	string "ifup udhcpc command line options"
+	default BUSYBOX_DEFAULT_IFUPDOWN_UDHCPC_CMD_OPTIONS
+	depends on BUSYBOX_CONFIG_IFUPDOWN && BUSYBOX_CONFIG_UDHCPC
+	help
+	  Command line options to pass to udhcpc from ifup.
+	  Intended to alter options not available in /etc/network/interfaces.
+	  (IE: --syslog --background etc...)
+
+config BUSYBOX_CONFIG_UDPSVD
+	bool "udpsvd"
+	default BUSYBOX_DEFAULT_UDPSVD
+	help
+	  udpsvd listens on an UDP port and runs a program for each new
+	  connection.
+
+config BUSYBOX_CONFIG_VCONFIG
+	bool "vconfig"
+	default BUSYBOX_DEFAULT_VCONFIG
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Creates, removes, and configures VLAN interfaces
+
+config BUSYBOX_CONFIG_ZCIP
+	bool "zcip"
+	default BUSYBOX_DEFAULT_ZCIP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927.
+	  It's a daemon that allocates and defends a dynamically assigned
+	  address on the 169.254/16 network, requiring no system administrator.
+
+	  See http://www.zeroconf.org for further details, and "zcip.script"
+	  in the busybox examples.
+
+endmenu
diff --git a/package/utils/busybox/config/networking/udhcp/Config.in b/package/utils/busybox/config/networking/udhcp/Config.in
new file mode 100644
index 0000000000..4f48400225
--- /dev/null
+++ b/package/utils/busybox/config/networking/udhcp/Config.in
@@ -0,0 +1,171 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+config BUSYBOX_CONFIG_UDHCPC6
+	bool "udhcp client for DHCPv6 (udhcpc6)"
+	default BUSYBOX_DEFAULT_UDHCPC6  # not yet ready
+	depends on BUSYBOX_CONFIG_FEATURE_IPV6
+	help
+	  udhcpc6 is a DHCPv6 client
+
+config BUSYBOX_CONFIG_UDHCPD
+	bool "udhcp server (udhcpd)"
+	default BUSYBOX_DEFAULT_UDHCPD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  udhcpd is a DHCP server geared primarily toward embedded systems,
+	  while striving to be fully functional and RFC compliant.
+
+config BUSYBOX_CONFIG_DHCPRELAY
+	bool "dhcprelay"
+	default BUSYBOX_DEFAULT_DHCPRELAY
+	depends on BUSYBOX_CONFIG_UDHCPD
+	help
+	  dhcprelay listens for dhcp requests on one or more interfaces
+	  and forwards these requests to a different interface or dhcp
+	  server.
+
+config BUSYBOX_CONFIG_DUMPLEASES
+	bool "Lease display utility (dumpleases)"
+	default BUSYBOX_DEFAULT_DUMPLEASES
+	depends on BUSYBOX_CONFIG_UDHCPD
+	help
+	  dumpleases displays the leases written out by the udhcpd server.
+	  Lease times are stored in the file by time remaining in lease, or
+	  by the absolute time that it expires in seconds from epoch.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY
+	bool "Rewrite the lease file at every new acknowledge"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCPD_WRITE_LEASES_EARLY
+	depends on BUSYBOX_CONFIG_UDHCPD
+	help
+	  If selected, udhcpd will write a new file with leases every
+	  time a new lease has been accepted, thus eliminating the need
+	  to send SIGUSR1 for the initial writing or updating. Any timed
+	  rewriting remains undisturbed.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC
+	bool "Select IP address based on client MAC"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCPD_BASE_IP_ON_MAC
+	depends on BUSYBOX_CONFIG_UDHCPD
+	help
+	  If selected, udhcpd will base its selection of IP address to offer
+	  on the client's hardware address. Otherwise udhcpd uses the next
+	  consecutive free address.
+
+	  This reduces the frequency of IP address changes for clients
+	  which let their lease expire, and makes consecutive DHCPOFFERS
+	  for the same client to (almost always) contain the same
+	  IP address.
+
+config BUSYBOX_CONFIG_DHCPD_LEASES_FILE
+	string "Absolute path to lease file"
+	default BUSYBOX_DEFAULT_DHCPD_LEASES_FILE
+	depends on BUSYBOX_CONFIG_UDHCPD
+	help
+	  udhcpd stores addresses in a lease file. This is the absolute path
+	  of the file. Normally it is safe to leave it untouched.
+
+config BUSYBOX_CONFIG_UDHCPC
+	bool "udhcp client (udhcpc)"
+	default BUSYBOX_DEFAULT_UDHCPC
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  udhcpc is a DHCP client geared primarily toward embedded systems,
+	  while striving to be fully functional and RFC compliant.
+
+	  The udhcp client negotiates a lease with the DHCP server and
+	  runs a script when a lease is obtained or lost.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCPC_ARPING
+	bool "Verify that the offered address is free, using ARP ping"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCPC_ARPING
+	depends on BUSYBOX_CONFIG_UDHCPC
+	help
+	  If selected, udhcpc will send ARP probes and make sure
+	  the offered address is really not in use by anyone. The client
+	  will DHCPDECLINE the offer if the address is in use,
+	  and restart the discover process.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCPC_SANITIZEOPT
+	bool "Do not pass malformed host and domain names"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCPC_SANITIZEOPT
+	depends on BUSYBOX_CONFIG_UDHCPC
+	help
+	  If selected, udhcpc will check some options (such as option 12 -
+	  hostname) and if they don't look like valid hostnames
+	  (for example, if they start with dash or contain spaces),
+	  they will be replaced with string "bad" when exporting
+	  to the environment.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCP_PORT
+	bool "Enable '-P port' option for udhcpd and udhcpc"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCP_PORT
+	depends on BUSYBOX_CONFIG_UDHCPD || BUSYBOX_CONFIG_UDHCPC
+	help
+	  At the cost of ~300 bytes, enables -P port option.
+	  This feature is typically not needed.
+
+config BUSYBOX_CONFIG_UDHCP_DEBUG
+	int "Maximum verbosity level for udhcp applets (0..9)"
+	default BUSYBOX_DEFAULT_UDHCP_DEBUG
+	range 0 9
+	depends on BUSYBOX_CONFIG_UDHCPD || BUSYBOX_CONFIG_UDHCPC || BUSYBOX_CONFIG_DHCPRELAY
+	help
+	  Verbosity can be increased with multiple -v options.
+	  This option controls how high it can be cranked up.
+
+	  Bigger values result in bigger code. Levels above 1
+	  are very verbose and useful for debugging only.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCP_RFC3397
+	bool "Support for RFC3397 domain search (experimental)"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCP_RFC3397
+	depends on BUSYBOX_CONFIG_UDHCPD || BUSYBOX_CONFIG_UDHCPC
+	help
+	  If selected, both client and server will support passing of domain
+	  search lists via option 119, specified in RFC 3397,
+	  and SIP servers option 120, specified in RFC 3361.
+
+config BUSYBOX_CONFIG_FEATURE_UDHCP_8021Q
+	bool "Support for 802.1Q VLAN parameters"
+	default BUSYBOX_DEFAULT_FEATURE_UDHCP_8021Q
+	depends on BUSYBOX_CONFIG_UDHCPD || BUSYBOX_CONFIG_UDHCPC
+	help
+	  If selected, both client and server will support passing of VLAN
+	  ID and priority via options 132 and 133 as per 802.1Q.
+
+config BUSYBOX_CONFIG_UDHCPC_DEFAULT_SCRIPT
+	string "Absolute path to config script"
+	default BUSYBOX_DEFAULT_UDHCPC_DEFAULT_SCRIPT
+	depends on BUSYBOX_CONFIG_UDHCPC
+	help
+	  This script is called after udhcpc receives an answer. See
+	  examples/udhcp for a working example. Normally it is safe
+	  to leave this untouched.
+
+config BUSYBOX_CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS
+	int "DHCP options slack buffer size"
+	default BUSYBOX_DEFAULT_UDHCPC_SLACK_FOR_BUGGY_SERVERS
+	range 0 924
+	depends on BUSYBOX_CONFIG_UDHCPD || BUSYBOX_CONFIG_UDHCPC
+	help
+	  Some buggy DHCP servers send DHCP offer packets with option
+	  field larger than we expect (which might also be considered a
+	  buffer overflow attempt). These packets are normally discarded.
+	  If circumstances beyond your control force you to support such
+	  servers, this may help. The upper limit (924) makes dhcpc accept
+	  even 1500 byte packets (maximum-sized ethernet packets).
+
+	  This option does not make dhcp[cd] emit non-standard
+	  sized packets.
+
+	  Known buggy DHCP servers:
+	  3Com OfficeConnect Remote 812 ADSL Router:
+	    seems to confuse maximum allowed UDP packet size with
+	    maximum size of entire IP packet, and sends packets which are
+	    28 bytes too large.
+	  Seednet (ISP) VDSL: sends packets 2 bytes too large.
diff --git a/package/utils/busybox/config/printutils/Config.in b/package/utils/busybox/config/printutils/Config.in
new file mode 100644
index 0000000000..3a2baa311d
--- /dev/null
+++ b/package/utils/busybox/config/printutils/Config.in
@@ -0,0 +1,26 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Print Utilities"
+
+config BUSYBOX_CONFIG_LPD
+	bool "lpd"
+	default BUSYBOX_DEFAULT_LPD
+	help
+	  lpd is a print spooling daemon.
+config BUSYBOX_CONFIG_LPR
+	bool "lpr"
+	default BUSYBOX_DEFAULT_LPR
+	help
+	  lpr sends files (or standard input) to a print spooling daemon.
+
+config BUSYBOX_CONFIG_LPQ
+	bool "lpq"
+	default BUSYBOX_DEFAULT_LPQ
+	help
+	  lpq is a print spool queue examination and manipulation program.
+
+endmenu
diff --git a/package/utils/busybox/config/procps/Config.in b/package/utils/busybox/config/procps/Config.in
new file mode 100644
index 0000000000..6eafbda0fa
--- /dev/null
+++ b/package/utils/busybox/config/procps/Config.in
@@ -0,0 +1,273 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Process Utilities"
+
+config BUSYBOX_CONFIG_IOSTAT
+	bool "iostat"
+	default BUSYBOX_DEFAULT_IOSTAT
+	help
+	  Report CPU and I/O statistics
+config BUSYBOX_CONFIG_LSOF
+	bool "lsof"
+	default BUSYBOX_DEFAULT_LSOF
+	help
+	  Show open files in the format of:
+	  PID <TAB> /path/to/executable <TAB> /path/to/opened/file
+config BUSYBOX_CONFIG_MPSTAT
+	bool "mpstat"
+	default BUSYBOX_DEFAULT_MPSTAT
+	help
+	  Per-processor statistics
+config BUSYBOX_CONFIG_NMETER
+	bool "nmeter"
+	default BUSYBOX_DEFAULT_NMETER
+	help
+	  Prints selected system stats continuously, one line per update.
+config BUSYBOX_CONFIG_PMAP
+       bool "pmap"
+       default BUSYBOX_DEFAULT_PMAP
+       help
+         Display processes' memory mappings.
+config BUSYBOX_CONFIG_POWERTOP
+	bool "powertop"
+	default BUSYBOX_DEFAULT_POWERTOP
+	help
+	  Analyze power consumption on Intel-based laptops
+config BUSYBOX_CONFIG_PSTREE
+	bool "pstree"
+	default BUSYBOX_DEFAULT_PSTREE
+	help
+	  Display a tree of processes.
+config BUSYBOX_CONFIG_PWDX
+	bool "pwdx"
+	default BUSYBOX_DEFAULT_PWDX
+	help
+	  Report current working directory of a process
+config BUSYBOX_CONFIG_SMEMCAP
+	bool "smemcap"
+	default BUSYBOX_DEFAULT_SMEMCAP
+	help
+	  smemcap is a tool for capturing process data for smem,
+	  a memory usage statistic tool.
+config BUSYBOX_CONFIG_TOP
+	bool "top"
+	default BUSYBOX_DEFAULT_TOP
+	help
+	  The top program provides a dynamic real-time view of a running
+	  system.
+
+config BUSYBOX_CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
+	bool "Show CPU per-process usage percentage"
+	default BUSYBOX_DEFAULT_FEATURE_TOP_CPU_USAGE_PERCENTAGE
+	depends on BUSYBOX_CONFIG_TOP
+	help
+	  Make top display CPU usage for each process.
+	  This adds about 2k.
+
+config BUSYBOX_CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS
+	bool "Show CPU global usage percentage"
+	default BUSYBOX_DEFAULT_FEATURE_TOP_CPU_GLOBAL_PERCENTS
+	depends on BUSYBOX_CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
+	help
+	  Makes top display "CPU: NN% usr NN% sys..." line.
+	  This adds about 0.5k.
+
+config BUSYBOX_CONFIG_FEATURE_TOP_SMP_CPU
+	bool "SMP CPU usage display ('c' key)"
+	default BUSYBOX_DEFAULT_FEATURE_TOP_SMP_CPU
+	depends on BUSYBOX_CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS
+	help
+	  Allow 'c' key to switch between individual/cumulative CPU stats
+	  This adds about 0.5k.
+
+config BUSYBOX_CONFIG_FEATURE_TOP_DECIMALS
+	bool "Show 1/10th of a percent in CPU/mem statistics"
+	default BUSYBOX_DEFAULT_FEATURE_TOP_DECIMALS
+	depends on BUSYBOX_CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
+	help
+	  Show 1/10th of a percent in CPU/mem statistics.
+	  This adds about 0.3k.
+
+config BUSYBOX_CONFIG_FEATURE_TOP_SMP_PROCESS
+	bool "Show CPU process runs on ('j' field)"
+	default BUSYBOX_DEFAULT_FEATURE_TOP_SMP_PROCESS
+	depends on BUSYBOX_CONFIG_TOP
+	help
+	  Show CPU where process was last found running on.
+	  This is the 'j' field.
+
+config BUSYBOX_CONFIG_FEATURE_TOPMEM
+	bool "Topmem command ('s' key)"
+	default BUSYBOX_DEFAULT_FEATURE_TOPMEM
+	depends on BUSYBOX_CONFIG_TOP
+	help
+	  Enable 's' in top (gives lots of memory info).
+config BUSYBOX_CONFIG_UPTIME
+	bool "uptime"
+	default BUSYBOX_DEFAULT_UPTIME
+	select BUSYBOX_CONFIG_PLATFORM_LINUX #sysinfo()
+	help
+	  uptime gives a one line display of the current time, how long
+	  the system has been running, how many users are currently logged
+	  on, and the system load averages for the past 1, 5, and 15 minutes.
+
+config BUSYBOX_CONFIG_FEATURE_UPTIME_UTMP_SUPPORT
+	bool "Support for showing the number of users"
+	default BUSYBOX_DEFAULT_FEATURE_UPTIME_UTMP_SUPPORT
+	depends on BUSYBOX_CONFIG_UPTIME && BUSYBOX_CONFIG_FEATURE_UTMP
+	help
+	  Makes uptime display the number of users currently logged on.
+
+config BUSYBOX_CONFIG_FREE
+	bool "free"
+	default BUSYBOX_DEFAULT_FREE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX #sysinfo()
+	help
+	  free displays the total amount of free and used physical and swap
+	  memory in the system, as well as the buffers used by the kernel.
+	  The shared memory column should be ignored; it is obsolete.
+
+config BUSYBOX_CONFIG_FUSER
+	bool "fuser"
+	default BUSYBOX_DEFAULT_FUSER
+	help
+	  fuser lists all PIDs (Process IDs) that currently have a given
+	  file open. fuser can also list all PIDs that have a given network
+	  (TCP or UDP) port open.
+
+config BUSYBOX_CONFIG_KILL
+	bool "kill"
+	default BUSYBOX_DEFAULT_KILL
+	help
+	  The command kill sends the specified signal to the specified
+	  process or process group. If no signal is specified, the TERM
+	  signal is sent.
+
+config BUSYBOX_CONFIG_KILLALL
+	bool "killall"
+	default BUSYBOX_DEFAULT_KILLALL
+	depends on BUSYBOX_CONFIG_KILL
+	help
+	  killall sends a signal to all processes running any of the
+	  specified commands. If no signal name is specified, SIGTERM is
+	  sent.
+
+config BUSYBOX_CONFIG_KILLALL5
+	bool "killall5"
+	default BUSYBOX_DEFAULT_KILLALL5
+	depends on BUSYBOX_CONFIG_KILL
+
+config BUSYBOX_CONFIG_PGREP
+	bool "pgrep"
+	default BUSYBOX_DEFAULT_PGREP
+	help
+	  Look for processes by name.
+
+config BUSYBOX_CONFIG_PIDOF
+	bool "pidof"
+	default BUSYBOX_DEFAULT_PIDOF
+	help
+	  Pidof finds the process id's (pids) of the named programs. It prints
+	  those id's on the standard output.
+
+config BUSYBOX_CONFIG_FEATURE_PIDOF_SINGLE
+	bool "Enable argument for single shot (-s)"
+	default BUSYBOX_DEFAULT_FEATURE_PIDOF_SINGLE
+	depends on BUSYBOX_CONFIG_PIDOF
+	help
+	  Support argument '-s' for returning only the first pid found.
+
+config BUSYBOX_CONFIG_FEATURE_PIDOF_OMIT
+	bool "Enable argument for omitting pids (-o)"
+	default BUSYBOX_DEFAULT_FEATURE_PIDOF_OMIT
+	depends on BUSYBOX_CONFIG_PIDOF
+	help
+	  Support argument '-o' for omitting the given pids in output.
+	  The special pid %PPID can be used to name the parent process
+	  of the pidof, in other words the calling shell or shell script.
+
+config BUSYBOX_CONFIG_PKILL
+	bool "pkill"
+	default BUSYBOX_DEFAULT_PKILL
+	help
+	  Send signals to processes by name.
+
+config BUSYBOX_CONFIG_PS
+	bool "ps"
+	default BUSYBOX_DEFAULT_PS
+	help
+	  ps gives a snapshot of the current processes.
+
+config BUSYBOX_CONFIG_FEATURE_PS_WIDE
+	bool "Enable wide output option (-w)"
+	default BUSYBOX_DEFAULT_FEATURE_PS_WIDE
+	depends on BUSYBOX_CONFIG_PS && !BUSYBOX_CONFIG_DESKTOP
+	help
+	  Support argument 'w' for wide output.
+	  If given once, 132 chars are printed, and if given more
+	  than once, the length is unlimited.
+
+config BUSYBOX_CONFIG_FEATURE_PS_LONG
+	bool "Enable long output option (-l)"
+	default BUSYBOX_DEFAULT_FEATURE_PS_LONG
+	depends on BUSYBOX_CONFIG_PS && !BUSYBOX_CONFIG_DESKTOP
+	help
+	  Support argument 'l' for long output.
+	  Adds fields PPID, RSS, START, TIME & TTY
+
+config BUSYBOX_CONFIG_FEATURE_PS_TIME
+	bool "Enable time and elapsed time output"
+	default BUSYBOX_DEFAULT_FEATURE_PS_TIME
+	depends on BUSYBOX_CONFIG_PS && BUSYBOX_CONFIG_DESKTOP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Support -o time and -o etime output specifiers.
+
+config BUSYBOX_CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS
+	bool "Enable additional ps columns"
+	default BUSYBOX_DEFAULT_FEATURE_PS_ADDITIONAL_COLUMNS
+	depends on BUSYBOX_CONFIG_PS && BUSYBOX_CONFIG_DESKTOP
+	help
+	  Support -o rgroup, -o ruser, -o nice output specifiers.
+
+config BUSYBOX_CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS
+	bool "Support Linux prior to 2.4.0 and non-ELF systems"
+	default BUSYBOX_DEFAULT_FEATURE_PS_UNUSUAL_SYSTEMS
+	depends on BUSYBOX_CONFIG_FEATURE_PS_TIME
+	help
+	  Include support for measuring HZ on old kernels and non-ELF systems
+	  (if you are on Linux 2.4.0+ and use ELF, you don't need this)
+
+config BUSYBOX_CONFIG_RENICE
+	bool "renice"
+	default BUSYBOX_DEFAULT_RENICE
+	help
+	  Renice alters the scheduling priority of one or more running
+	  processes.
+
+config BUSYBOX_CONFIG_BB_SYSCTL
+	bool "sysctl"
+	default BUSYBOX_DEFAULT_BB_SYSCTL
+	help
+	  Configure kernel parameters at runtime.
+
+config BUSYBOX_CONFIG_FEATURE_SHOW_THREADS
+	bool "Support for showing threads in ps/pstree/top"
+	default BUSYBOX_DEFAULT_FEATURE_SHOW_THREADS
+	depends on BUSYBOX_CONFIG_PS || BUSYBOX_CONFIG_TOP || BUSYBOX_CONFIG_PSTREE
+	help
+	  Enables the ps -T option, showing of threads in pstree,
+	  and 'h' command in top.
+
+config BUSYBOX_CONFIG_WATCH
+	bool "watch"
+	default BUSYBOX_DEFAULT_WATCH
+	help
+	  watch is used to execute a program periodically, showing
+	  output to the screen.
+
+endmenu
diff --git a/package/utils/busybox/config/runit/Config.in b/package/utils/busybox/config/runit/Config.in
new file mode 100644
index 0000000000..a322a2cd8a
--- /dev/null
+++ b/package/utils/busybox/config/runit/Config.in
@@ -0,0 +1,84 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Runit Utilities"
+
+config BUSYBOX_CONFIG_CHPST
+	bool "chpst"
+	default BUSYBOX_DEFAULT_CHPST
+	help
+	  chpst changes the process state according to the given options, and
+	  execs specified program.
+
+config BUSYBOX_CONFIG_SETUIDGID
+	bool "setuidgid"
+	default BUSYBOX_DEFAULT_SETUIDGID
+	help
+	  Sets soft resource limits as specified by options
+
+config BUSYBOX_CONFIG_ENVUIDGID
+	bool "envuidgid"
+	default BUSYBOX_DEFAULT_ENVUIDGID
+	help
+	  Sets $UID to account's uid and $GID to account's gid
+
+config BUSYBOX_CONFIG_ENVDIR
+	bool "envdir"
+	default BUSYBOX_DEFAULT_ENVDIR
+	help
+	  Sets various environment variables as specified by files
+	  in the given directory
+
+config BUSYBOX_CONFIG_SOFTLIMIT
+	bool "softlimit"
+	default BUSYBOX_DEFAULT_SOFTLIMIT
+	help
+	  Sets soft resource limits as specified by options
+config BUSYBOX_CONFIG_RUNSV
+	bool "runsv"
+	default BUSYBOX_DEFAULT_RUNSV
+	help
+	  runsv starts and monitors a service and optionally an appendant log
+	  service.
+config BUSYBOX_CONFIG_RUNSVDIR
+	bool "runsvdir"
+	default BUSYBOX_DEFAULT_RUNSVDIR
+	help
+	  runsvdir starts a runsv process for each subdirectory, or symlink to
+	  a directory, in the services directory dir, up to a limit of 1000
+	  subdirectories, and restarts a runsv process if it terminates.
+
+config BUSYBOX_CONFIG_FEATURE_RUNSVDIR_LOG
+	bool "Enable scrolling argument log"
+	depends on BUSYBOX_CONFIG_RUNSVDIR
+	default BUSYBOX_DEFAULT_FEATURE_RUNSVDIR_LOG
+	help
+	  Enable feature where second parameter of runsvdir holds last error
+	  message (viewable via top/ps). Otherwise (feature is off
+	  or no parameter), error messages go to stderr only.
+config BUSYBOX_CONFIG_SV
+	bool "sv"
+	default BUSYBOX_DEFAULT_SV
+	help
+	  sv reports the current status and controls the state of services
+	  monitored by the runsv supervisor.
+
+config BUSYBOX_CONFIG_SV_DEFAULT_SERVICE_DIR
+	string "Default directory for services"
+	default BUSYBOX_DEFAULT_SV_DEFAULT_SERVICE_DIR
+	depends on BUSYBOX_CONFIG_SV
+	help
+	  Default directory for services.
+	  Defaults to "/var/service"
+config BUSYBOX_CONFIG_SVLOGD
+	bool "svlogd"
+	default BUSYBOX_DEFAULT_SVLOGD
+	help
+	  svlogd continuously reads log data from its standard input, optionally
+	  filters log messages, and writes the data to one or more automatically
+	  rotated logs.
+
+endmenu
diff --git a/package/utils/busybox/config/selinux/Config.in b/package/utils/busybox/config/selinux/Config.in
new file mode 100644
index 0000000000..1d23f7de43
--- /dev/null
+++ b/package/utils/busybox/config/selinux/Config.in
@@ -0,0 +1,124 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "SELinux Utilities"
+	depends on BUSYBOX_CONFIG_SELINUX
+
+
+config BUSYBOX_CONFIG_CHCON
+	bool "chcon"
+	default BUSYBOX_DEFAULT_CHCON
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to change the security context of file.
+
+config BUSYBOX_CONFIG_FEATURE_CHCON_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_CHCON_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_CHCON && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the chcon applet.
+
+config BUSYBOX_CONFIG_GETENFORCE
+	bool "getenforce"
+	default BUSYBOX_DEFAULT_GETENFORCE
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to get the current mode of SELinux.
+
+config BUSYBOX_CONFIG_GETSEBOOL
+	bool "getsebool"
+	default BUSYBOX_DEFAULT_GETSEBOOL
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to get SELinux boolean values.
+
+config BUSYBOX_CONFIG_LOAD_POLICY
+	bool "load_policy"
+	default BUSYBOX_DEFAULT_LOAD_POLICY
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to load SELinux policy.
+
+config BUSYBOX_CONFIG_MATCHPATHCON
+	bool "matchpathcon"
+	default BUSYBOX_DEFAULT_MATCHPATHCON
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to get default security context of the
+	  specified path from the file contexts configuration.
+
+config BUSYBOX_CONFIG_RESTORECON
+	bool "restorecon"
+	default BUSYBOX_DEFAULT_RESTORECON
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to relabel files. The feature is almost
+	  the same as setfiles, but usage is a little different.
+
+config BUSYBOX_CONFIG_RUNCON
+	bool "runcon"
+	default BUSYBOX_DEFAULT_RUNCON
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to run command in specified security context.
+
+config BUSYBOX_CONFIG_FEATURE_RUNCON_LONG_OPTIONS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_RUNCON_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_RUNCON && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the runcon applet.
+
+config BUSYBOX_CONFIG_SELINUXENABLED
+	bool "selinuxenabled"
+	default BUSYBOX_DEFAULT_SELINUXENABLED
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support for this command to be used within shell scripts
+	  to determine if selinux is enabled.
+
+config BUSYBOX_CONFIG_SETENFORCE
+	bool "setenforce"
+	default BUSYBOX_DEFAULT_SETENFORCE
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to modify the mode SELinux is running in.
+
+config BUSYBOX_CONFIG_SETFILES
+	bool "setfiles"
+	default BUSYBOX_DEFAULT_SETFILES
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support to modify to relabel files.
+	  Notice: If you built libselinux with -D_FILE_OFFSET_BITS=64,
+	  (It is default in libselinux's Makefile), you _must_ enable
+	  CONFIG_LFS.
+
+config BUSYBOX_CONFIG_FEATURE_SETFILES_CHECK_OPTION
+	bool "Enable check option"
+	default BUSYBOX_DEFAULT_FEATURE_SETFILES_CHECK_OPTION
+	depends on BUSYBOX_CONFIG_SETFILES
+	help
+	  Support "-c" option (check the validity of the contexts against
+	  the specified binary policy) for setfiles. Requires libsepol.
+
+config BUSYBOX_CONFIG_SETSEBOOL
+	bool "setsebool"
+	default BUSYBOX_DEFAULT_SETSEBOOL
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Enable support for change boolean.
+	  semanage and -P option is not supported yet.
+
+config BUSYBOX_CONFIG_SESTATUS
+	bool "sestatus"
+	default BUSYBOX_DEFAULT_SESTATUS
+	depends on BUSYBOX_CONFIG_SELINUX
+	help
+	  Displays the status of SELinux.
+
+endmenu
diff --git a/package/utils/busybox/config/shell/Config.in b/package/utils/busybox/config/shell/Config.in
new file mode 100644
index 0000000000..69ecf145e1
--- /dev/null
+++ b/package/utils/busybox/config/shell/Config.in
@@ -0,0 +1,444 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Shells"
+
+config BUSYBOX_CONFIG_ASH
+	bool "ash"
+	default BUSYBOX_DEFAULT_ASH
+	depends on !BUSYBOX_CONFIG_NOMMU
+	help
+	  Tha 'ash' shell adds about 60k in the default configuration and is
+	  the most complete and most pedantically correct shell included with
+	  busybox. This shell is actually a derivative of the Debian 'dash'
+	  shell (by Herbert Xu), which was created by porting the 'ash' shell
+	  (written by Kenneth Almquist) from NetBSD.
+
+config BUSYBOX_CONFIG_ASH_BASH_COMPAT
+	bool "bash-compatible extensions"
+	default BUSYBOX_DEFAULT_ASH_BASH_COMPAT
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable bash-compatible extensions.
+
+config BUSYBOX_CONFIG_ASH_IDLE_TIMEOUT
+	bool "Idle timeout variable"
+	default BUSYBOX_DEFAULT_ASH_IDLE_TIMEOUT
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enables bash-like auto-logout after $TMOUT seconds of idle time.
+
+config BUSYBOX_CONFIG_ASH_JOB_CONTROL
+	bool "Job control"
+	default BUSYBOX_DEFAULT_ASH_JOB_CONTROL
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable job control in the ash shell.
+
+config BUSYBOX_CONFIG_ASH_ALIAS
+	bool "Alias support"
+	default BUSYBOX_DEFAULT_ASH_ALIAS
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable alias support in the ash shell.
+
+config BUSYBOX_CONFIG_ASH_GETOPTS
+	bool "Builtin getopt to parse positional parameters"
+	default BUSYBOX_DEFAULT_ASH_GETOPTS
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable support for getopts builtin in ash.
+
+config BUSYBOX_CONFIG_ASH_BUILTIN_ECHO
+	bool "Builtin version of 'echo'"
+	default BUSYBOX_DEFAULT_ASH_BUILTIN_ECHO
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable support for echo builtin in ash.
+
+config BUSYBOX_CONFIG_ASH_BUILTIN_PRINTF
+	bool "Builtin version of 'printf'"
+	default BUSYBOX_DEFAULT_ASH_BUILTIN_PRINTF
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable support for printf builtin in ash.
+
+config BUSYBOX_CONFIG_ASH_BUILTIN_TEST
+	bool "Builtin version of 'test'"
+	default BUSYBOX_DEFAULT_ASH_BUILTIN_TEST
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable support for test builtin in ash.
+
+config BUSYBOX_CONFIG_ASH_HELP
+	bool "help builtin"
+	default BUSYBOX_DEFAULT_ASH_HELP
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable help builtin in ash.
+
+config BUSYBOX_CONFIG_ASH_CMDCMD
+	bool "'command' command to override shell builtins"
+	default BUSYBOX_DEFAULT_ASH_CMDCMD
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable support for the ash 'command' builtin, which allows
+	  you to run the specified command with the specified arguments,
+	  even when there is an ash builtin command with the same name.
+
+config BUSYBOX_CONFIG_ASH_MAIL
+	bool "Check for new mail on interactive shells"
+	default BUSYBOX_DEFAULT_ASH_MAIL
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable "check for new mail" function in the ash shell.
+
+config BUSYBOX_CONFIG_ASH_OPTIMIZE_FOR_SIZE
+	bool "Optimize for size instead of speed"
+	default BUSYBOX_DEFAULT_ASH_OPTIMIZE_FOR_SIZE
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Compile ash for reduced size at the price of speed.
+
+config BUSYBOX_CONFIG_ASH_RANDOM_SUPPORT
+	bool "Pseudorandom generator and $RANDOM variable"
+	default BUSYBOX_DEFAULT_ASH_RANDOM_SUPPORT
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  Enable pseudorandom generator and dynamic variable "$RANDOM".
+	  Each read of "$RANDOM" will generate a new pseudorandom value.
+	  You can reset the generator by using a specified start value.
+	  After "unset RANDOM" the generator will switch off and this
+	  variable will no longer have special treatment.
+
+config BUSYBOX_CONFIG_ASH_EXPAND_PRMT
+	bool "Expand prompt string"
+	default BUSYBOX_DEFAULT_ASH_EXPAND_PRMT
+	depends on BUSYBOX_CONFIG_ASH
+	help
+	  "PS#" may contain volatile content, such as backquote commands.
+	  This option recreates the prompt string from the environment
+	  variable each time it is displayed.
+
+config BUSYBOX_CONFIG_CTTYHACK
+	bool "cttyhack"
+	default BUSYBOX_DEFAULT_CTTYHACK
+	help
+	  One common problem reported on the mailing list is the "can't
+	  access tty; job control turned off" error message, which typically
+	  appears when one tries to use a shell with stdin/stdout on
+	  /dev/console.
+	  This device is special - it cannot be a controlling tty.
+
+	  The proper solution is to use the correct device instead of
+	  /dev/console.
+
+	  cttyhack provides a "quick and dirty" solution to this problem.
+	  It analyzes stdin with various ioctls, trying to determine whether
+	  it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line).
+	  On Linux it also checks sysfs for a pointer to the active console.
+	  If cttyhack is able to find the real console device, it closes
+	  stdin/out/err and reopens that device.
+	  Then it executes the given program. Opening the device will make
+	  that device a controlling tty. This may require cttyhack
+	  to be a session leader.
+
+	  Example for /etc/inittab (for busybox init):
+
+	  ::respawn:/bin/cttyhack /bin/sh
+
+	  Starting an interactive shell from boot shell script:
+
+	  setsid cttyhack sh
+
+	  Giving controlling tty to shell running with PID 1:
+
+	  # exec cttyhack sh
+
+	  Without cttyhack, you need to know exact tty name,
+	  and do something like this:
+
+	  # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1'
+
+	  Starting getty on a controlling tty from a shell script:
+
+	  # getty 115200 $(cttyhack)
+config BUSYBOX_CONFIG_HUSH
+	bool "hush"
+	default BUSYBOX_DEFAULT_HUSH
+	help
+	  hush is a small shell (25k). It handles the normal flow control
+	  constructs such as if/then/elif/else/fi, for/in/do/done, while loops,
+	  case/esac. Redirections, here documents, $((arithmetic))
+	  and functions are supported.
+
+	  It will compile and work on no-mmu systems.
+
+	  It does not handle select, aliases, tilde expansion,
+	  &>file and >&file redirection of stdout+stderr.
+
+config BUSYBOX_CONFIG_HUSH_BASH_COMPAT
+	bool "bash-compatible extensions"
+	default BUSYBOX_DEFAULT_HUSH_BASH_COMPAT
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable bash-compatible extensions.
+
+config BUSYBOX_CONFIG_HUSH_BRACE_EXPANSION
+	bool "Brace expansion"
+	default BUSYBOX_DEFAULT_HUSH_BRACE_EXPANSION
+	depends on BUSYBOX_CONFIG_HUSH_BASH_COMPAT
+	help
+	  Enable {abc,def} extension.
+
+config BUSYBOX_CONFIG_HUSH_HELP
+	bool "help builtin"
+	default BUSYBOX_DEFAULT_HUSH_HELP
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable help builtin in hush. Code size + ~1 kbyte.
+
+config BUSYBOX_CONFIG_HUSH_INTERACTIVE
+	bool "Interactive mode"
+	default BUSYBOX_DEFAULT_HUSH_INTERACTIVE
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable interactive mode (prompt and command editing).
+	  Without this, hush simply reads and executes commands
+	  from stdin just like a shell script from a file.
+	  No prompt, no PS1/PS2 magic shell variables.
+
+config BUSYBOX_CONFIG_HUSH_SAVEHISTORY
+	bool "Save command history to .hush_history"
+	default BUSYBOX_DEFAULT_HUSH_SAVEHISTORY
+	depends on BUSYBOX_CONFIG_HUSH_INTERACTIVE && BUSYBOX_CONFIG_FEATURE_EDITING_SAVEHISTORY
+	help
+	  Enable history saving in hush.
+
+config BUSYBOX_CONFIG_HUSH_JOB
+	bool "Job control"
+	default BUSYBOX_DEFAULT_HUSH_JOB
+	depends on BUSYBOX_CONFIG_HUSH_INTERACTIVE
+	help
+	  Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current
+	  command (not entire shell), fg/bg builtins work. Without this option,
+	  "cmd &" still works by simply spawning a process and immediately
+	  prompting for next command (or executing next command in a script),
+	  but no separate process group is formed.
+
+config BUSYBOX_CONFIG_HUSH_TICK
+	bool "Process substitution"
+	default BUSYBOX_DEFAULT_HUSH_TICK
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable process substitution `command` and $(command) in hush.
+
+config BUSYBOX_CONFIG_HUSH_IF
+	bool "Support if/then/elif/else/fi"
+	default BUSYBOX_DEFAULT_HUSH_IF
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable if/then/elif/else/fi in hush.
+
+config BUSYBOX_CONFIG_HUSH_LOOPS
+	bool "Support for, while and until loops"
+	default BUSYBOX_DEFAULT_HUSH_LOOPS
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable for, while and until loops in hush.
+
+config BUSYBOX_CONFIG_HUSH_CASE
+	bool "Support case ... esac statement"
+	default BUSYBOX_DEFAULT_HUSH_CASE
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable case ... esac statement in hush. +400 bytes.
+
+config BUSYBOX_CONFIG_HUSH_FUNCTIONS
+	bool "Support funcname() { commands; } syntax"
+	default BUSYBOX_DEFAULT_HUSH_FUNCTIONS
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable support for shell functions in hush. +800 bytes.
+
+config BUSYBOX_CONFIG_HUSH_LOCAL
+	bool "Support local builtin"
+	default BUSYBOX_DEFAULT_HUSH_LOCAL
+	depends on BUSYBOX_CONFIG_HUSH_FUNCTIONS
+	help
+	  Enable support for local variables in functions.
+
+config BUSYBOX_CONFIG_HUSH_RANDOM_SUPPORT
+	bool "Pseudorandom generator and $RANDOM variable"
+	default BUSYBOX_DEFAULT_HUSH_RANDOM_SUPPORT
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  Enable pseudorandom generator and dynamic variable "$RANDOM".
+	  Each read of "$RANDOM" will generate a new pseudorandom value.
+
+config BUSYBOX_CONFIG_HUSH_EXPORT_N
+	bool "Support 'export -n' option"
+	default BUSYBOX_DEFAULT_HUSH_EXPORT_N
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  export -n unexports variables. It is a bash extension.
+
+config BUSYBOX_CONFIG_HUSH_MODE_X
+	bool "Support 'hush -x' option and 'set -x' command"
+	default BUSYBOX_DEFAULT_HUSH_MODE_X
+	depends on BUSYBOX_CONFIG_HUSH
+	help
+	  This instructs hush to print commands before execution.
+	  Adds ~300 bytes.
+
+config BUSYBOX_CONFIG_MSH
+	bool "msh (deprecated: aliased to hush)"
+	default BUSYBOX_DEFAULT_MSH
+	select BUSYBOX_CONFIG_HUSH
+	help
+	  msh is deprecated and will be removed, please migrate to hush.
+
+
+
+choice
+	prompt "Choose which shell is aliased to 'sh' name"
+	default BUSYBOX_CONFIG_FEATURE_SH_IS_ASH
+	help
+	  Choose which shell you want to be executed by 'sh' alias.
+	  The ash shell is the most bash compatible and full featured one.
+
+# note: cannot use "select ASH" here, it breaks "make allnoconfig"
+config BUSYBOX_CONFIG_FEATURE_SH_IS_ASH
+	depends on BUSYBOX_CONFIG_ASH
+	bool "ash"
+	depends on !BUSYBOX_CONFIG_NOMMU
+
+config BUSYBOX_CONFIG_FEATURE_SH_IS_HUSH
+	depends on BUSYBOX_CONFIG_HUSH
+	bool "hush"
+
+config BUSYBOX_CONFIG_FEATURE_SH_IS_NONE
+	bool "none"
+
+endchoice
+
+choice
+	prompt "Choose which shell is aliased to 'bash' name"
+	default BUSYBOX_CONFIG_FEATURE_BASH_IS_NONE
+	help
+	  Choose which shell you want to be executed by 'bash' alias.
+	  The ash shell is the most bash compatible and full featured one.
+
+	  Note that selecting this option does not switch on any bash
+	  compatibility code. It merely makes it possible to install
+	  /bin/bash (sym)link and run scripts which start with
+	  #!/bin/bash line.
+
+	  Many systems use it in scripts which use bash-specific features,
+	  even simple ones like $RANDOM. Without this option, busybox
+	  can't be used for running them because it won't recongnize
+	  "bash" as a supported applet name.
+
+config BUSYBOX_CONFIG_FEATURE_BASH_IS_ASH
+	depends on BUSYBOX_CONFIG_ASH
+	bool "ash"
+	depends on !BUSYBOX_CONFIG_NOMMU
+
+config BUSYBOX_CONFIG_FEATURE_BASH_IS_HUSH
+	depends on BUSYBOX_CONFIG_HUSH
+	bool "hush"
+
+config BUSYBOX_CONFIG_FEATURE_BASH_IS_NONE
+	bool "none"
+
+endchoice
+
+
+config BUSYBOX_CONFIG_SH_MATH_SUPPORT
+	bool "POSIX math support"
+	default BUSYBOX_DEFAULT_SH_MATH_SUPPORT
+	depends on BUSYBOX_CONFIG_ASH || BUSYBOX_CONFIG_HUSH
+	help
+	  Enable math support in the shell via $((...)) syntax.
+
+config BUSYBOX_CONFIG_SH_MATH_SUPPORT_64
+	bool "Extend POSIX math support to 64 bit"
+	default BUSYBOX_DEFAULT_SH_MATH_SUPPORT_64
+	depends on BUSYBOX_CONFIG_SH_MATH_SUPPORT
+	help
+	  Enable 64-bit math support in the shell. This will make the shell
+	  slightly larger, but will allow computation with very large numbers.
+	  This is not in POSIX, so do not rely on this in portable code.
+
+config BUSYBOX_CONFIG_FEATURE_SH_EXTRA_QUIET
+	bool "Hide message on interactive shell startup"
+	default BUSYBOX_DEFAULT_FEATURE_SH_EXTRA_QUIET
+	depends on BUSYBOX_CONFIG_HUSH || BUSYBOX_CONFIG_ASH
+	help
+	  Remove the busybox introduction when starting a shell.
+
+config BUSYBOX_CONFIG_FEATURE_SH_STANDALONE
+	bool "Standalone shell"
+	default BUSYBOX_DEFAULT_FEATURE_SH_STANDALONE
+	depends on (BUSYBOX_CONFIG_HUSH || BUSYBOX_CONFIG_ASH) && BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS
+	help
+	  This option causes busybox shells to use busybox applets
+	  in preference to executables in the PATH whenever possible. For
+	  example, entering the command 'ifconfig' into the shell would cause
+	  busybox to use the ifconfig busybox applet. Specifying the fully
+	  qualified executable name, such as '/sbin/ifconfig' will still
+	  execute the /sbin/ifconfig executable on the filesystem. This option
+	  is generally used when creating a statically linked version of busybox
+	  for use as a rescue shell, in the event that you screw up your system.
+
+	  This is implemented by re-execing /proc/self/exe (typically)
+	  with right parameters. Some selected applets ("NOFORK" applets)
+	  can even be executed without creating new process.
+	  Instead, busybox will call <applet>_main() internally.
+
+	  However, this causes problems in chroot jails without mounted /proc
+	  and with ps/top (command name can be shown as 'exe' for applets
+	  started this way).
+# untrue?
+#	  Note that this will *also* cause applets to take precedence
+#	  over shell builtins of the same name. So turning this on will
+#	  eliminate any performance gained by turning on the builtin "echo"
+#	  and "test" commands in ash.
+# untrue?
+#	  Note that when using this option, the shell will attempt to directly
+#	  run '/bin/busybox'. If you do not have the busybox binary sitting in
+#	  that exact location with that exact name, this option will not work at
+#	  all.
+
+config BUSYBOX_CONFIG_FEATURE_SH_NOFORK
+	bool "Run 'nofork' applets directly"
+	default BUSYBOX_DEFAULT_FEATURE_SH_NOFORK
+	depends on (BUSYBOX_CONFIG_HUSH || BUSYBOX_CONFIG_ASH) && BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS
+	help
+	  This option causes busybox shells to not execute typical
+	  fork/exec/wait sequence, but call <applet>_main directly,
+	  if possible. (Sometimes it is not possible: for example,
+	  this is not possible in pipes).
+
+	  This will be done only for some applets (those which are marked
+	  NOFORK in include/applets.h).
+
+	  This may significantly speed up some shell scripts.
+
+	  This feature is relatively new. Use with care. Report bugs
+	  to project mailing list.
+
+config BUSYBOX_CONFIG_FEATURE_SH_HISTFILESIZE
+	bool "Use $HISTFILESIZE"
+	default BUSYBOX_DEFAULT_FEATURE_SH_HISTFILESIZE
+	depends on BUSYBOX_CONFIG_HUSH || BUSYBOX_CONFIG_ASH
+	help
+	  This option makes busybox shells to use $HISTFILESIZE variable
+	  to set shell history size. Note that its max value is capped
+	  by "History size" setting in library tuning section.
+
+
+endmenu
diff --git a/package/utils/busybox/config/sysklogd/Config.in b/package/utils/busybox/config/sysklogd/Config.in
new file mode 100644
index 0000000000..5fcee2c7ff
--- /dev/null
+++ b/package/utils/busybox/config/sysklogd/Config.in
@@ -0,0 +1,166 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "System Logging Utilities"
+
+config BUSYBOX_CONFIG_KLOGD
+	bool "klogd"
+	default BUSYBOX_DEFAULT_KLOGD
+	help
+	  klogd is a utility which intercepts and logs all
+	  messages from the Linux kernel and sends the messages
+	  out to the 'syslogd' utility so they can be logged. If
+	  you wish to record the messages produced by the kernel,
+	  you should enable this option.
+
+comment "klogd should not be used together with syslog to kernel printk buffer"
+	depends on BUSYBOX_CONFIG_KLOGD && BUSYBOX_CONFIG_FEATURE_KMSG_SYSLOG
+
+config BUSYBOX_CONFIG_FEATURE_KLOGD_KLOGCTL
+	bool "Use the klogctl() interface"
+	default BUSYBOX_DEFAULT_FEATURE_KLOGD_KLOGCTL
+	depends on BUSYBOX_CONFIG_KLOGD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The klogd applet supports two interfaces for reading
+	  kernel messages. Linux provides the klogctl() interface
+	  which allows reading messages from the kernel ring buffer
+	  independently from the file system.
+
+	  If you answer 'N' here, klogd will use the more portable
+	  approach of reading them from /proc or a device node.
+	  However, this method requires the file to be available.
+
+	  If in doubt, say 'Y'.
+config BUSYBOX_CONFIG_LOGGER
+	bool "logger"
+	default BUSYBOX_DEFAULT_LOGGER
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	    The logger utility allows you to send arbitrary text
+	    messages to the system log (i.e. the 'syslogd' utility) so
+	    they can be logged. This is generally used to help locate
+	    problems that occur within programs and scripts.
+config BUSYBOX_CONFIG_LOGREAD
+	bool "logread"
+	default BUSYBOX_DEFAULT_LOGREAD
+	depends on BUSYBOX_CONFIG_FEATURE_IPC_SYSLOG
+	help
+	  If you enabled Circular Buffer support, you almost
+	  certainly want to enable this feature as well. This
+	  utility will allow you to read the messages that are
+	  stored in the syslogd circular buffer.
+
+config BUSYBOX_CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING
+	bool "Double buffering"
+	default BUSYBOX_DEFAULT_FEATURE_LOGREAD_REDUCED_LOCKING
+	depends on BUSYBOX_CONFIG_LOGREAD
+	help
+	  'logread' ouput to slow serial terminals can have
+	  side effects on syslog because of the semaphore.
+	  This option make logread to double buffer copy
+	  from circular buffer, minimizing semaphore
+	  contention at some minor memory expense.
+
+config BUSYBOX_CONFIG_SYSLOGD
+	bool "syslogd"
+	default BUSYBOX_DEFAULT_SYSLOGD
+	help
+	  The syslogd utility is used to record logs of all the
+	  significant events that occur on a system. Every
+	  message that is logged records the date and time of the
+	  event, and will generally also record the name of the
+	  application that generated the message. When used in
+	  conjunction with klogd, messages from the Linux kernel
+	  can also be recorded. This is terribly useful,
+	  especially for finding what happened when something goes
+	  wrong. And something almost always will go wrong if
+	  you wait long enough....
+
+config BUSYBOX_CONFIG_FEATURE_ROTATE_LOGFILE
+	bool "Rotate message files"
+	default BUSYBOX_DEFAULT_FEATURE_ROTATE_LOGFILE
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	help
+	  This enables syslogd to rotate the message files
+	  on his own. No need to use an external rotate script.
+
+config BUSYBOX_CONFIG_FEATURE_REMOTE_LOG
+	bool "Remote Log support"
+	default BUSYBOX_DEFAULT_FEATURE_REMOTE_LOG
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	help
+	  When you enable this feature, the syslogd utility can
+	  be used to send system log messages to another system
+	  connected via a network. This allows the remote
+	  machine to log all the system messages, which can be
+	  terribly useful for reducing the number of serial
+	  cables you use. It can also be a very good security
+	  measure to prevent system logs from being tampered with
+	  by an intruder.
+
+config BUSYBOX_CONFIG_FEATURE_SYSLOGD_DUP
+	bool "Support -D (drop dups) option"
+	default BUSYBOX_DEFAULT_FEATURE_SYSLOGD_DUP
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	help
+	  Option -D instructs syslogd to drop consecutive messages
+	  which are totally the same.
+
+config BUSYBOX_CONFIG_FEATURE_SYSLOGD_CFG
+	bool "Support syslog.conf"
+	default BUSYBOX_DEFAULT_FEATURE_SYSLOGD_CFG
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	help
+	  Supports restricted syslogd config. See docs/syslog.conf.txt
+
+config BUSYBOX_CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE
+	int "Read buffer size in bytes"
+	default BUSYBOX_DEFAULT_FEATURE_SYSLOGD_READ_BUFFER_SIZE
+	range 256 20000
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	help
+	  This option sets the size of the syslog read buffer.
+	  Actual memory usage increases around five times the
+	  change done here.
+
+config BUSYBOX_CONFIG_FEATURE_IPC_SYSLOG
+	bool "Circular Buffer support"
+	default BUSYBOX_DEFAULT_FEATURE_IPC_SYSLOG
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	help
+	  When you enable this feature, the syslogd utility will
+	  use a circular buffer to record system log messages.
+	  When the buffer is filled it will continue to overwrite
+	  the oldest messages. This can be very useful for
+	  systems with little or no permanent storage, since
+	  otherwise system logs can eventually fill up your
+	  entire filesystem, which may cause your system to
+	  break badly.
+
+config BUSYBOX_CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE
+	int "Circular buffer size in Kbytes (minimum 4KB)"
+	default BUSYBOX_DEFAULT_FEATURE_IPC_SYSLOG_BUFFER_SIZE
+	range 4 2147483647
+	depends on BUSYBOX_CONFIG_FEATURE_IPC_SYSLOG
+	help
+	  This option sets the size of the circular buffer
+	  used to record system log messages.
+
+config BUSYBOX_CONFIG_FEATURE_KMSG_SYSLOG
+	bool "Linux kernel printk buffer support"
+	default BUSYBOX_DEFAULT_FEATURE_KMSG_SYSLOG
+	depends on BUSYBOX_CONFIG_SYSLOGD
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  When you enable this feature, the syslogd utility will
+	  write system log message to the Linux kernel's printk buffer.
+	  This can be used as a smaller alternative to the syslogd IPC
+	  support, as klogd and logread aren't needed.
+
+	  NOTICE: Syslog facilities in log entries needs kernel 3.5+.
+
+endmenu
diff --git a/package/utils/busybox/config/util-linux/Config.in b/package/utils/busybox/config/util-linux/Config.in
new file mode 100644
index 0000000000..08bddf819a
--- /dev/null
+++ b/package/utils/busybox/config/util-linux/Config.in
@@ -0,0 +1,830 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+menu "Linux System Utilities"
+
+config BUSYBOX_CONFIG_BLKDISCARD
+	bool "blkdiscard"
+	default BUSYBOX_DEFAULT_BLKDISCARD
+	help
+	  blkdiscard discards sectors on a given device.
+config BUSYBOX_CONFIG_BLOCKDEV
+	bool "blockdev"
+	default BUSYBOX_DEFAULT_BLOCKDEV
+	help
+	  Performs some ioctls with block devices.
+config BUSYBOX_CONFIG_FATATTR
+	bool "fatattr"
+	default BUSYBOX_DEFAULT_FATATTR
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  fatattr lists or changes the file attributes on a fat file system.
+config BUSYBOX_CONFIG_FSTRIM
+	bool "fstrim"
+	default BUSYBOX_DEFAULT_FSTRIM
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Discard unused blocks on a mounted filesystem.
+config BUSYBOX_CONFIG_MDEV
+	bool "mdev"
+	default BUSYBOX_DEFAULT_MDEV
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  mdev is a mini-udev implementation for dynamically creating device
+	  nodes in the /dev directory.
+
+	  For more information, please see docs/mdev.txt
+
+config BUSYBOX_CONFIG_FEATURE_MDEV_CONF
+	bool "Support /etc/mdev.conf"
+	default BUSYBOX_DEFAULT_FEATURE_MDEV_CONF
+	depends on BUSYBOX_CONFIG_MDEV
+	help
+	  Add support for the mdev config file to control ownership and
+	  permissions of the device nodes.
+
+	  For more information, please see docs/mdev.txt
+
+config BUSYBOX_CONFIG_FEATURE_MDEV_RENAME
+	bool "Support subdirs/symlinks"
+	default BUSYBOX_DEFAULT_FEATURE_MDEV_RENAME
+	depends on BUSYBOX_CONFIG_FEATURE_MDEV_CONF
+	help
+	  Add support for renaming devices and creating symlinks.
+
+	  For more information, please see docs/mdev.txt
+
+config BUSYBOX_CONFIG_FEATURE_MDEV_RENAME_REGEXP
+	bool "Support regular expressions substitutions when renaming device"
+	default BUSYBOX_DEFAULT_FEATURE_MDEV_RENAME_REGEXP
+	depends on BUSYBOX_CONFIG_FEATURE_MDEV_RENAME
+	help
+	  Add support for regular expressions substitutions when renaming
+	  device.
+
+config BUSYBOX_CONFIG_FEATURE_MDEV_EXEC
+	bool "Support command execution at device addition/removal"
+	default BUSYBOX_DEFAULT_FEATURE_MDEV_EXEC
+	depends on BUSYBOX_CONFIG_FEATURE_MDEV_CONF
+	help
+	  This adds support for an optional field to /etc/mdev.conf for
+	  executing commands when devices are created/removed.
+
+	  For more information, please see docs/mdev.txt
+
+config BUSYBOX_CONFIG_FEATURE_MDEV_LOAD_FIRMWARE
+	bool "Support loading of firmwares"
+	default BUSYBOX_DEFAULT_FEATURE_MDEV_LOAD_FIRMWARE
+	depends on BUSYBOX_CONFIG_MDEV
+	help
+	  Some devices need to load firmware before they can be usable.
+
+	  These devices will request userspace look up the files in
+	  /lib/firmware/ and if it exists, send it to the kernel for
+	  loading into the hardware.
+config BUSYBOX_CONFIG_MOUNT
+	bool "mount"
+	default BUSYBOX_DEFAULT_MOUNT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  All files and filesystems in Unix are arranged into one big directory
+	  tree. The 'mount' utility is used to graft a filesystem onto a
+	  particular part of the tree. A filesystem can either live on a block
+	  device, or it can be accessible over the network, as is the case with
+	  NFS filesystems. Most people using BusyBox will also want to enable
+	  the 'mount' utility.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_FAKE
+	bool "Support option -f"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_FAKE
+	depends on BUSYBOX_CONFIG_MOUNT
+	help
+	  Enable support for faking a file system mount.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_VERBOSE
+	bool "Support option -v"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_VERBOSE
+	depends on BUSYBOX_CONFIG_MOUNT
+	help
+	  Enable multi-level -v[vv...] verbose messages. Useful if you
+	  debug mount problems and want to see what is exactly passed
+	  to the kernel.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_HELPERS
+	bool "Support mount helpers"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_HELPERS
+	depends on BUSYBOX_CONFIG_MOUNT
+	help
+	  Enable mounting of virtual file systems via external helpers.
+	  E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call
+	  "obexfs -b00.11.22.33.44.55 /mnt"
+	  Also "mount -t sometype [-o opts] fs /mnt" will try
+	  "sometype [-o opts] fs /mnt" if simple mount syscall fails.
+	  The idea is to use such virtual filesystems in /etc/fstab.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_LABEL
+	bool "Support specifying devices by label or UUID"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_LABEL
+	depends on BUSYBOX_CONFIG_MOUNT
+	select BUSYBOX_CONFIG_VOLUMEID
+	help
+	  This allows for specifying a device by label or uuid, rather than by
+	  name. This feature utilizes the same functionality as blkid/findfs.
+	  This also enables label or uuid support for swapon.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_NFS
+	bool "Support mounting NFS file systems on Linux < 2.6.23"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_NFS
+	depends on BUSYBOX_CONFIG_MOUNT
+	select BUSYBOX_CONFIG_FEATURE_HAVE_RPC
+	select BUSYBOX_CONFIG_FEATURE_SYSLOG
+	help
+	  Enable mounting of NFS file systems on Linux kernels prior
+	  to version 2.6.23. Note that in this case mounting of NFS
+	  over IPv6 will not be possible.
+
+	  Note that this option links in RPC support from libc,
+	  which is rather large (~10 kbytes on uclibc).
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_CIFS
+	bool "Support mounting CIFS/SMB file systems"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_CIFS
+	depends on BUSYBOX_CONFIG_MOUNT
+	help
+	  Enable support for samba mounts.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_FLAGS
+	depends on BUSYBOX_CONFIG_MOUNT
+	bool "Support lots of -o flags in mount"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_FLAGS
+	help
+	  Without this, mount only supports ro/rw/remount. With this, it
+	  supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
+	  noatime, diratime, nodiratime, loud, bind, move, shared, slave,
+	  private, unbindable, rshared, rslave, rprivate, and runbindable.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_FSTAB
+	depends on BUSYBOX_CONFIG_MOUNT
+	bool "Support /etc/fstab and -a"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_FSTAB
+	help
+	  Support mount all and looking for files in /etc/fstab.
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_OTHERTAB
+	depends on BUSYBOX_CONFIG_FEATURE_MOUNT_FSTAB
+	bool "Support -T <alt_fstab>"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_OTHERTAB
+	help
+	  Support mount -T (specifying an alternate fstab)
+config BUSYBOX_CONFIG_NSENTER
+	bool "nsenter"
+	default BUSYBOX_DEFAULT_NSENTER
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Run program with namespaces of other processes.
+
+config BUSYBOX_CONFIG_FEATURE_NSENTER_LONG_OPTS
+	bool "Enable long options"
+	default BUSYBOX_DEFAULT_FEATURE_NSENTER_LONG_OPTS
+	depends on BUSYBOX_CONFIG_NSENTER && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  Support long options for the nsenter applet. This makes
+	  the busybox implementation more compatible with upstream.
+config BUSYBOX_CONFIG_REV
+	bool "rev"
+	default BUSYBOX_DEFAULT_REV
+	help
+	  Reverse lines of a file or files.
+config BUSYBOX_CONFIG_SETARCH
+	bool "setarch"
+	default BUSYBOX_DEFAULT_SETARCH
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The linux32 utility is used to create a 32bit environment for the
+	  specified program (usually a shell). It only makes sense to have
+	  this util on a system that supports both 64bit and 32bit userland
+	  (like amd64/x86, ppc64/ppc, sparc64/sparc, etc...).
+config BUSYBOX_CONFIG_UEVENT
+	bool "uevent"
+	default BUSYBOX_DEFAULT_UEVENT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  uevent is a netlink listener for kernel uevent notifications
+	  sent via netlink. It is usually used for dynamic device creation.
+config BUSYBOX_CONFIG_UNSHARE
+	bool "unshare"
+	default BUSYBOX_DEFAULT_UNSHARE
+	depends on BUSYBOX_CONFIG_LONG_OPTS && !BUSYBOX_CONFIG_NOMMU
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Run program with some namespaces unshared from parent.
+
+config BUSYBOX_CONFIG_ACPID
+	bool "acpid"
+	default BUSYBOX_DEFAULT_ACPID
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  acpid listens to ACPI events coming either in textual form from
+	  /proc/acpi/event (though it is marked deprecated it is still widely
+	  used and _is_ a standard) or in binary form from specified evdevs
+	  (just use /dev/input/event*).
+
+	  It parses the event to retrieve ACTION and a possible PARAMETER.
+	  It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
+	  (if the resulting path is a directory) or directly as an executable.
+
+	  N.B. acpid relies on run-parts so have the latter installed.
+
+config BUSYBOX_CONFIG_FEATURE_ACPID_COMPAT
+	bool "Accept and ignore redundant options"
+	default BUSYBOX_DEFAULT_FEATURE_ACPID_COMPAT
+	depends on BUSYBOX_CONFIG_ACPID
+	help
+	  Accept and ignore compatibility options -g -m -s -S -v.
+
+config BUSYBOX_CONFIG_BLKID
+	bool "blkid"
+	default BUSYBOX_DEFAULT_BLKID
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	select BUSYBOX_CONFIG_VOLUMEID
+	help
+	  Lists labels and UUIDs of all filesystems.
+	  WARNING:
+	  With all submodules selected, it will add ~8k to busybox.
+
+config BUSYBOX_CONFIG_FEATURE_BLKID_TYPE
+	bool "Print filesystem type"
+	default BUSYBOX_DEFAULT_FEATURE_BLKID_TYPE
+	depends on BUSYBOX_CONFIG_BLKID
+	help
+	  Show TYPE="filesystem type"
+
+config BUSYBOX_CONFIG_DMESG
+	bool "dmesg"
+	default BUSYBOX_DEFAULT_DMESG
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  dmesg is used to examine or control the kernel ring buffer. When the
+	  Linux kernel prints messages to the system log, they are stored in
+	  the kernel ring buffer. You can use dmesg to print the kernel's ring
+	  buffer, clear the kernel ring buffer, change the size of the kernel
+	  ring buffer, and change the priority level at which kernel messages
+	  are also logged to the system console. Enable this option if you
+	  wish to enable the 'dmesg' utility.
+
+config BUSYBOX_CONFIG_FEATURE_DMESG_PRETTY
+	bool "Pretty dmesg output"
+	default BUSYBOX_DEFAULT_FEATURE_DMESG_PRETTY
+	depends on BUSYBOX_CONFIG_DMESG
+	help
+	  If you wish to scrub the syslog level from the output, say 'Y' here.
+	  The syslog level is a string prefixed to every line with the form
+	  "<#>".
+
+	  With this option you will see:
+	    # dmesg
+	    Linux version 2.6.17.4 .....
+	    BIOS-provided physical RAM map:
+	     BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
+
+	  Without this option you will see:
+	    # dmesg
+	    <5>Linux version 2.6.17.4 .....
+	    <6>BIOS-provided physical RAM map:
+	    <6> BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
+
+config BUSYBOX_CONFIG_FBSET
+	bool "fbset"
+	default BUSYBOX_DEFAULT_FBSET
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  fbset is used to show or change the settings of a Linux frame buffer
+	  device. The frame buffer device provides a simple and unique
+	  interface to access a graphics display. Enable this option
+	  if you wish to enable the 'fbset' utility.
+
+config BUSYBOX_CONFIG_FEATURE_FBSET_FANCY
+	bool "Turn on extra fbset options"
+	default BUSYBOX_DEFAULT_FEATURE_FBSET_FANCY
+	depends on BUSYBOX_CONFIG_FBSET
+	help
+	  This option enables extended fbset options, allowing one to set the
+	  framebuffer size, color depth, etc. interface to access a graphics
+	  display. Enable this option if you wish to enable extended fbset
+	  options.
+
+config BUSYBOX_CONFIG_FEATURE_FBSET_READMODE
+	bool "Turn on fbset readmode support"
+	default BUSYBOX_DEFAULT_FEATURE_FBSET_READMODE
+	depends on BUSYBOX_CONFIG_FBSET
+	help
+	  This option allows fbset to read the video mode database stored by
+	  default BUSYBOX_DEFAULT_FEATURE_FBSET_READMODE /etc/fb.modes, which can be used to set frame buffer
+	  device to pre-defined video modes.
+
+config BUSYBOX_CONFIG_FDFLUSH
+	bool "fdflush"
+	default BUSYBOX_DEFAULT_FDFLUSH
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  fdflush is only needed when changing media on slightly-broken
+	  removable media drives. It is used to make Linux believe that a
+	  hardware disk-change switch has been actuated, which causes Linux to
+	  forget anything it has cached from the previous media. If you have
+	  such a slightly-broken drive, you will need to run fdflush every time
+	  you change a disk. Most people have working hardware and can safely
+	  leave this disabled.
+
+config BUSYBOX_CONFIG_FDFORMAT
+	bool "fdformat"
+	default BUSYBOX_DEFAULT_FDFORMAT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  fdformat is used to low-level format a floppy disk.
+
+config BUSYBOX_CONFIG_FDISK
+	bool "fdisk"
+	default BUSYBOX_DEFAULT_FDISK
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The fdisk utility is used to divide hard disks into one or more
+	  logical disks, which are generally called partitions. This utility
+	  can be used to list and edit the set of partitions or BSD style
+	  'disk slices' that are defined on a hard drive.
+
+config BUSYBOX_CONFIG_FDISK_SUPPORT_LARGE_DISKS
+	bool "Support over 4GB disks"
+	default BUSYBOX_DEFAULT_FDISK_SUPPORT_LARGE_DISKS
+	depends on BUSYBOX_CONFIG_FDISK
+	depends on !BUSYBOX_CONFIG_LFS   # with LFS no special code is needed
+	help
+	  Enable this option to support large disks > 4GB.
+
+config BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	bool "Write support"
+	default BUSYBOX_DEFAULT_FEATURE_FDISK_WRITABLE
+	depends on BUSYBOX_CONFIG_FDISK
+	help
+	  Enabling this option allows you to create or change a partition table
+	  and write those changes out to disk. If you leave this option
+	  disabled, you will only be able to view the partition table.
+
+config BUSYBOX_CONFIG_FEATURE_AIX_LABEL
+	bool "Support AIX disklabels"
+	default BUSYBOX_DEFAULT_FEATURE_AIX_LABEL
+	depends on BUSYBOX_CONFIG_FDISK && BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	help
+	  Enabling this option allows you to create or change AIX disklabels.
+	  Most people can safely leave this option disabled.
+
+config BUSYBOX_CONFIG_FEATURE_SGI_LABEL
+	bool "Support SGI disklabels"
+	default BUSYBOX_DEFAULT_FEATURE_SGI_LABEL
+	depends on BUSYBOX_CONFIG_FDISK && BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	help
+	  Enabling this option allows you to create or change SGI disklabels.
+	  Most people can safely leave this option disabled.
+
+config BUSYBOX_CONFIG_FEATURE_SUN_LABEL
+	bool "Support SUN disklabels"
+	default BUSYBOX_DEFAULT_FEATURE_SUN_LABEL
+	depends on BUSYBOX_CONFIG_FDISK && BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	help
+	  Enabling this option allows you to create or change SUN disklabels.
+	  Most people can safely leave this option disabled.
+
+config BUSYBOX_CONFIG_FEATURE_OSF_LABEL
+	bool "Support BSD disklabels"
+	default BUSYBOX_DEFAULT_FEATURE_OSF_LABEL
+	depends on BUSYBOX_CONFIG_FDISK && BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	help
+	  Enabling this option allows you to create or change BSD disklabels
+	  and define and edit BSD disk slices.
+
+config BUSYBOX_CONFIG_FEATURE_GPT_LABEL
+	bool "Support GPT disklabels"
+	default BUSYBOX_DEFAULT_FEATURE_GPT_LABEL
+	depends on BUSYBOX_CONFIG_FDISK && BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	help
+	  Enabling this option allows you to view GUID Partition Table
+	  disklabels.
+
+config BUSYBOX_CONFIG_FEATURE_FDISK_ADVANCED
+	bool "Support expert mode"
+	default BUSYBOX_DEFAULT_FEATURE_FDISK_ADVANCED
+	depends on BUSYBOX_CONFIG_FDISK && BUSYBOX_CONFIG_FEATURE_FDISK_WRITABLE
+	help
+	  Enabling this option allows you to do terribly unsafe things like
+	  define arbitrary drive geometry, move the beginning of data in a
+	  partition, and similarly evil things. Unless you have a very good
+	  reason you would be wise to leave this disabled.
+
+config BUSYBOX_CONFIG_FINDFS
+	bool "findfs"
+	default BUSYBOX_DEFAULT_FINDFS
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	select BUSYBOX_CONFIG_VOLUMEID
+	help
+	  Prints the name of a filesystem with given label or UUID.
+	  WARNING:
+	  With all submodules selected, it will add ~8k to busybox.
+
+config BUSYBOX_CONFIG_FLOCK
+	bool "flock"
+	default BUSYBOX_DEFAULT_FLOCK
+	help
+	  Manage locks from shell scripts
+
+config BUSYBOX_CONFIG_FREERAMDISK
+	bool "freeramdisk"
+	default BUSYBOX_DEFAULT_FREERAMDISK
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Linux allows you to create ramdisks. This utility allows you to
+	  delete them and completely free all memory that was used for the
+	  ramdisk. For example, if you boot Linux into a ramdisk and later
+	  pivot_root, you may want to free the memory that is allocated to the
+	  ramdisk. If you have no use for freeing memory from a ramdisk, leave
+	  this disabled.
+
+config BUSYBOX_CONFIG_FSCK_MINIX
+	bool "fsck_minix"
+	default BUSYBOX_DEFAULT_FSCK_MINIX
+	help
+	  The minix filesystem is a nice, small, compact, read-write filesystem
+	  with little overhead. It is not a journaling filesystem however and
+	  can experience corruption if it is not properly unmounted or if the
+	  power goes off in the middle of a write. This utility allows you to
+	  check for and attempt to repair any corruption that occurs to a minix
+	  filesystem.
+
+config BUSYBOX_CONFIG_MKFS_EXT2
+	bool "mkfs_ext2"
+	default BUSYBOX_DEFAULT_MKFS_EXT2
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Utility to create EXT2 filesystems.
+
+config BUSYBOX_CONFIG_MKFS_MINIX
+	bool "mkfs_minix"
+	default BUSYBOX_DEFAULT_MKFS_MINIX
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The minix filesystem is a nice, small, compact, read-write filesystem
+	  with little overhead. If you wish to be able to create minix
+	  filesystems this utility will do the job for you.
+
+config BUSYBOX_CONFIG_FEATURE_MINIX2
+	bool "Support Minix fs v2 (fsck_minix/mkfs_minix)"
+	default BUSYBOX_DEFAULT_FEATURE_MINIX2
+	depends on BUSYBOX_CONFIG_FSCK_MINIX || BUSYBOX_CONFIG_MKFS_MINIX
+	help
+	  If you wish to be able to create version 2 minix filesystems, enable
+	  this. If you enabled 'mkfs_minix' then you almost certainly want to
+	  be using the version 2 filesystem support.
+
+config BUSYBOX_CONFIG_MKFS_REISER
+	bool "mkfs_reiser"
+	default BUSYBOX_DEFAULT_MKFS_REISER
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Utility to create ReiserFS filesystems.
+	  Note: this applet needs a lot of testing and polishing.
+
+config BUSYBOX_CONFIG_MKFS_VFAT
+	bool "mkfs_vfat"
+	default BUSYBOX_DEFAULT_MKFS_VFAT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Utility to create FAT32 filesystems.
+
+config BUSYBOX_CONFIG_GETOPT
+	bool "getopt"
+	default BUSYBOX_DEFAULT_GETOPT
+	help
+	  The getopt utility is used to break up (parse) options in command
+	  lines to make it easy to write complex shell scripts that also check
+	  for legal (and illegal) options. If you want to write horribly
+	  complex shell scripts, or use some horribly complex shell script
+	  written by others, this utility may be for you. Most people will
+	  wisely leave this disabled.
+
+config BUSYBOX_CONFIG_FEATURE_GETOPT_LONG
+	bool "Support option -l"
+	default BUSYBOX_DEFAULT_FEATURE_GETOPT_LONG if BUSYBOX_CONFIG_LONG_OPTS
+	depends on BUSYBOX_CONFIG_GETOPT
+	help
+	  Enable support for long options (option -l).
+
+config BUSYBOX_CONFIG_HEXDUMP
+	bool "hexdump"
+	default BUSYBOX_DEFAULT_HEXDUMP
+	help
+	  The hexdump utility is used to display binary data in a readable
+	  way that is comparable to the output from most hex editors.
+
+config BUSYBOX_CONFIG_FEATURE_HEXDUMP_REVERSE
+	bool "Support -R, reverse of 'hexdump -Cv'"
+	default BUSYBOX_DEFAULT_FEATURE_HEXDUMP_REVERSE
+	depends on BUSYBOX_CONFIG_HEXDUMP
+	help
+	  The hexdump utility is used to display binary data in an ascii
+	  readable way. This option creates binary data from an ascii input.
+	  NB: this option is non-standard. It's unwise to use it in scripts
+	  aimed to be portable.
+
+config BUSYBOX_CONFIG_HD
+	bool "hd"
+	default BUSYBOX_DEFAULT_HD
+	depends on BUSYBOX_CONFIG_HEXDUMP
+	help
+	  hd is an alias to hexdump -C.
+
+config BUSYBOX_CONFIG_HWCLOCK
+	bool "hwclock"
+	default BUSYBOX_DEFAULT_HWCLOCK
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The hwclock utility is used to read and set the hardware clock
+	  on a system. This is primarily used to set the current time on
+	  shutdown in the hardware clock, so the hardware will keep the
+	  correct time when Linux is _not_ running.
+
+config BUSYBOX_CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS
+	bool "Support long options (--hctosys,...)"
+	default BUSYBOX_DEFAULT_FEATURE_HWCLOCK_LONG_OPTIONS
+	depends on BUSYBOX_CONFIG_HWCLOCK && BUSYBOX_CONFIG_LONG_OPTS
+	help
+	  By default, the hwclock utility only uses short options. If you
+	  are overly fond of its long options, such as --hctosys, --utc, etc)
+	  then enable this option.
+
+config BUSYBOX_CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS
+	bool "Use FHS /var/lib/hwclock/adjtime"
+	default BUSYBOX_DEFAULT_FEATURE_HWCLOCK_ADJTIME_FHS  # util-linux-ng in Fedora 13 still uses /etc/adjtime
+	depends on BUSYBOX_CONFIG_HWCLOCK
+	help
+	  Starting with FHS 2.3, the adjtime state file is supposed to exist
+	  at /var/lib/hwclock/adjtime instead of /etc/adjtime. If you wish
+	  to use the FHS behavior, answer Y here, otherwise answer N for the
+	  classic /etc/adjtime path.
+
+	  pathname.com/fhs/pub/fhs-2.3.html#VARLIBHWCLOCKSTATEDIRECTORYFORHWCLO
+
+config BUSYBOX_CONFIG_IPCRM
+	bool "ipcrm"
+	default BUSYBOX_DEFAULT_IPCRM
+	help
+	  The ipcrm utility allows the removal of System V interprocess
+	  communication (IPC) objects and the associated data structures
+	  from the system.
+
+config BUSYBOX_CONFIG_IPCS
+	bool "ipcs"
+	default BUSYBOX_DEFAULT_IPCS
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The ipcs utility is used to provide information on the currently
+	  allocated System V interprocess (IPC) objects in the system.
+
+config BUSYBOX_CONFIG_LOSETUP
+	bool "losetup"
+	default BUSYBOX_DEFAULT_LOSETUP
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  losetup is used to associate or detach a loop device with a regular
+	  file or block device, and to query the status of a loop device. This
+	  version does not currently support enabling data encryption.
+
+config BUSYBOX_CONFIG_LSPCI
+	bool "lspci"
+	default BUSYBOX_DEFAULT_LSPCI
+	#select PLATFORM_LINUX
+	help
+	  lspci is a utility for displaying information about PCI buses in the
+	  system and devices connected to them.
+
+	  This version uses sysfs (/sys/bus/pci/devices) only.
+
+config BUSYBOX_CONFIG_LSUSB
+	bool "lsusb"
+	default BUSYBOX_DEFAULT_LSUSB
+	#select PLATFORM_LINUX
+	help
+	  lsusb is a utility for displaying information about USB buses in the
+	  system and devices connected to them.
+
+	  This version uses sysfs (/sys/bus/usb/devices) only.
+
+config BUSYBOX_CONFIG_MKSWAP
+	bool "mkswap"
+	default BUSYBOX_DEFAULT_MKSWAP
+	help
+	  The mkswap utility is used to configure a file or disk partition as
+	  Linux swap space. This allows Linux to use the entire file or
+	  partition as if it were additional RAM, which can greatly increase
+	  the capability of low-memory machines. This additional memory is
+	  much slower than real RAM, but can be very helpful at preventing your
+	  applications being killed by the Linux out of memory (OOM) killer.
+	  Once you have created swap space using 'mkswap' you need to enable
+	  the swap space using the 'swapon' utility.
+
+config BUSYBOX_CONFIG_FEATURE_MKSWAP_UUID
+	bool "UUID support"
+	default BUSYBOX_DEFAULT_FEATURE_MKSWAP_UUID
+	depends on BUSYBOX_CONFIG_MKSWAP
+	help
+	  Generate swap spaces with universally unique identifiers.
+
+config BUSYBOX_CONFIG_MORE
+	bool "more"
+	default BUSYBOX_DEFAULT_MORE
+	help
+	  more is a simple utility which allows you to read text one screen
+	  sized page at a time. If you want to read text that is larger than
+	  the screen, and you are using anything faster than a 300 baud modem,
+	  you will probably find this utility very helpful. If you don't have
+	  any need to reading text files, you can leave this disabled.
+
+config BUSYBOX_CONFIG_PIVOT_ROOT
+	bool "pivot_root"
+	default BUSYBOX_DEFAULT_PIVOT_ROOT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The pivot_root utility swaps the mount points for the root filesystem
+	  with some other mounted filesystem. This allows you to do all sorts
+	  of wild and crazy things with your Linux system and is far more
+	  powerful than 'chroot'.
+
+	  Note: This is for initrd in linux 2.4. Under initramfs (introduced
+	  in linux 2.6) use switch_root instead.
+
+config BUSYBOX_CONFIG_RDATE
+	bool "rdate"
+	default BUSYBOX_DEFAULT_RDATE
+	help
+	  The rdate utility allows you to synchronize the date and time of your
+	  system clock with the date and time of a remote networked system using
+	  the RFC868 protocol, which is built into the inetd daemon on most
+	  systems.
+
+config BUSYBOX_CONFIG_RDEV
+	bool "rdev"
+	default BUSYBOX_DEFAULT_RDEV
+	help
+	  Print the device node associated with the filesystem mounted at '/'.
+
+config BUSYBOX_CONFIG_READPROFILE
+	bool "readprofile"
+	default BUSYBOX_DEFAULT_READPROFILE
+	#select PLATFORM_LINUX
+	help
+	  This allows you to parse /proc/profile for basic profiling.
+
+config BUSYBOX_CONFIG_RTCWAKE
+	bool "rtcwake"
+	default BUSYBOX_DEFAULT_RTCWAKE
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  Enter a system sleep state until specified wakeup time.
+
+config BUSYBOX_CONFIG_SCRIPT
+	bool "script"
+	default BUSYBOX_DEFAULT_SCRIPT
+	help
+	  The script makes typescript of terminal session.
+
+config BUSYBOX_CONFIG_SCRIPTREPLAY
+	bool "scriptreplay"
+	default BUSYBOX_DEFAULT_SCRIPTREPLAY
+	help
+	  This program replays a typescript, using timing information
+	  given by script -t.
+
+config BUSYBOX_CONFIG_SWAPONOFF
+	bool "swaponoff"
+	default BUSYBOX_DEFAULT_SWAPONOFF
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  This option enables both the 'swapon' and the 'swapoff' utilities.
+	  Once you have created some swap space using 'mkswap', you also need
+	  to enable your swap space with the 'swapon' utility. The 'swapoff'
+	  utility is used, typically at system shutdown, to disable any swap
+	  space. If you are not using any swap space, you can leave this
+	  option disabled.
+
+config BUSYBOX_CONFIG_FEATURE_SWAPON_DISCARD
+	bool "Support discard option -d"
+	default BUSYBOX_DEFAULT_FEATURE_SWAPON_DISCARD
+	depends on BUSYBOX_CONFIG_SWAPONOFF
+	help
+	  Enable support for discarding swap area blocks at swapon and/or as
+	  the kernel frees them. This option enables both the -d option on
+	  'swapon' and the 'discard' option for swap entries in /etc/fstab.
+
+config BUSYBOX_CONFIG_FEATURE_SWAPON_PRI
+	bool "Support priority option -p"
+	default BUSYBOX_DEFAULT_FEATURE_SWAPON_PRI
+	depends on BUSYBOX_CONFIG_SWAPONOFF
+	help
+	  Enable support for setting swap device priority in swapon.
+
+config BUSYBOX_CONFIG_SWITCH_ROOT
+	bool "switch_root"
+	default BUSYBOX_DEFAULT_SWITCH_ROOT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  The switch_root utility is used from initramfs to select a new
+	  root device. Under initramfs, you have to use this instead of
+	  pivot_root. (Stop reading here if you don't care why.)
+
+	  Booting with initramfs extracts a gzipped cpio archive into rootfs
+	  (which is a variant of ramfs/tmpfs). Because rootfs can't be moved
+	  or unmounted*, pivot_root will not work from initramfs. Instead,
+	  switch_root deletes everything out of rootfs (including itself),
+	  does a mount --move that overmounts rootfs with the new root, and
+	  then execs the specified init program.
+
+	  * Because the Linux kernel uses rootfs internally as the starting
+	  and ending point for searching through the kernel's doubly linked
+	  list of active mount points. That's why.
+
+config BUSYBOX_CONFIG_UMOUNT
+	bool "umount"
+	default BUSYBOX_DEFAULT_UMOUNT
+	select BUSYBOX_CONFIG_PLATFORM_LINUX
+	help
+	  When you want to remove a mounted filesystem from its current mount
+	  point, for example when you are shutting down the system, the
+	  'umount' utility is the tool to use. If you enabled the 'mount'
+	  utility, you almost certainly also want to enable 'umount'.
+
+config BUSYBOX_CONFIG_FEATURE_UMOUNT_ALL
+	bool "Support option -a"
+	default BUSYBOX_DEFAULT_FEATURE_UMOUNT_ALL
+	depends on BUSYBOX_CONFIG_UMOUNT
+	help
+	  Support -a option to unmount all currently mounted filesystems.
+
+comment "Common options for mount/umount"
+	depends on BUSYBOX_CONFIG_MOUNT || BUSYBOX_CONFIG_UMOUNT
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_LOOP
+	bool "Support loopback mounts"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_LOOP
+	depends on BUSYBOX_CONFIG_MOUNT || BUSYBOX_CONFIG_UMOUNT
+	help
+	  Enabling this feature allows automatic mounting of files (containing
+	  filesystem images) via the linux kernel's loopback devices.
+	  The mount command will detect you are trying to mount a file instead
+	  of a block device, and transparently associate the file with a
+	  loopback device. The umount command will also free that loopback
+	  device.
+
+	  You can still use the 'losetup' utility (to manually associate files
+	  with loop devices) if you need to do something advanced, such as
+	  specify an offset or cryptographic options to the loopback device.
+	  (If you don't want umount to free the loop device, use "umount -D".)
+
+config BUSYBOX_CONFIG_FEATURE_MOUNT_LOOP_CREATE
+	bool "Create new loopback devices if needed"
+	default BUSYBOX_DEFAULT_FEATURE_MOUNT_LOOP_CREATE
+	depends on BUSYBOX_CONFIG_FEATURE_MOUNT_LOOP
+	help
+	  Linux kernels >= 2.6.24 support unlimited loopback devices. They are
+	  allocated for use when trying to use a loop device. The loop device
+	  must however exist.
+
+	  This feature lets mount to try to create next /dev/loopN device
+	  if it does not find a free one.
+
+config BUSYBOX_CONFIG_FEATURE_MTAB_SUPPORT
+	bool "Support for the old /etc/mtab file"
+	default BUSYBOX_DEFAULT_FEATURE_MTAB_SUPPORT
+	depends on BUSYBOX_CONFIG_MOUNT || BUSYBOX_CONFIG_UMOUNT
+	select BUSYBOX_CONFIG_FEATURE_MOUNT_FAKE
+	help
+	  Historically, Unix systems kept track of the currently mounted
+	  partitions in the file "/etc/mtab". These days, the kernel exports
+	  the list of currently mounted partitions in "/proc/mounts", rendering
+	  the old mtab file obsolete. (In modern systems, /etc/mtab should be
+	  a symlink to /proc/mounts.)
+
+	  The only reason to have mount maintain an /etc/mtab file itself is if
+	  your stripped-down embedded system does not have a /proc directory.
+	  If you must use this, keep in mind it's inherently brittle (for
+	  example a mount under chroot won't update it), can't handle modern
+	  features like separate per-process filesystem namespaces, requires
+	  that your /etc directory be writable, tends to get easily confused
+	  by --bind or --move mounts, won't update if you rename a directory
+	  that contains a mount point, and so on. (In brief: avoid.)
+
+	  About the only reason to use this is if you've removed /proc from
+	  your kernel.
+
+source volume_id/Config.in
+
+endmenu
diff --git a/package/utils/busybox/config/util-linux/volume_id/Config.in b/package/utils/busybox/config/util-linux/volume_id/Config.in
new file mode 100644
index 0000000000..6153314d6f
--- /dev/null
+++ b/package/utils/busybox/config/util-linux/volume_id/Config.in
@@ -0,0 +1,312 @@
+# DO NOT EDIT. This file is generated from Config.src
+#
+# For a description of the syntax of this configuration file,
+# see scripts/kbuild/config-language.txt.
+#
+
+config BUSYBOX_CONFIG_VOLUMEID
+	bool #No description makes it a hidden option
+	default BUSYBOX_DEFAULT_VOLUMEID
+
+menu "Filesystem/Volume identification"
+	depends on BUSYBOX_CONFIG_VOLUMEID
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_BCACHE
+	bool "bcache filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_BCACHE
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_BTRFS
+	bool "btrfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_BTRFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_CRAMFS
+	bool "cramfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_CRAMFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_EXFAT
+	bool "exFAT filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_EXFAT
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  exFAT (extended FAT) is a proprietary file system designed especially
+	  for flash drives. It has many features from NTFS, but with less
+	  overhead. exFAT is used on most SDXC cards for consumer electronics.
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_EXT
+	bool "Ext filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_EXT
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_F2FS
+	bool "f2fs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_F2FS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  F2FS (aka Flash-Friendly File System) is a log-structured file system,
+	  which is adapted to newer forms of storage. F2FS also remedies some
+	  known issues of the older log structured file systems, such as high
+	  cleaning overhead.
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_FAT
+	bool "fat filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_FAT
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_HFS
+	bool "hfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_HFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_ISO9660
+	bool "iso9660 filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_ISO9660
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_JFS
+	bool "jfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_JFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_LINUXRAID
+	bool "linuxraid"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_LINUXRAID
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_LINUXSWAP
+	bool "linux swap filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_LINUXSWAP
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_LUKS
+	bool "luks filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_LUKS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_NILFS
+	bool "nilfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_NILFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  NILFS is a New Implementation of a Log-Structured File System (LFS)
+	  that supports continuous snapshots. This provides features like
+	  versioning of the entire filesystem, restoration of files that
+	  were deleted a few minutes ago. NILFS keeps consistency like
+	  conventional LFS, so it provides quick recovery after system crashes.
+
+	  The possible use of NILFS includes versioning, tamper detection,
+	  SOX compliance logging, and so forth. It can serve as an alternative
+	  filesystem for Linux desktop environment, or as a basis of advanced
+	  storage appliances.
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_NTFS
+	bool "ntfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_NTFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_OCFS2
+	bool "ocfs2 filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_OCFS2
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_REISERFS
+	bool "Reiser filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_REISERFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_ROMFS
+	bool "romfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_ROMFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_SQUASHFS
+	bool "SquashFS filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_SQUASHFS
+	depends on BUSYBOX_CONFIG_VOLUMEID && BUSYBOX_CONFIG_FEATURE_BLKID_TYPE
+	help
+	  Squashfs is a compressed read-only filesystem for Linux. Squashfs is
+	  intended for general read-only filesystem use and in constrained block
+	  device/memory systems (e.g. embedded systems) where low overhead is
+	  needed.
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_SYSV
+	bool "sysv filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_SYSV
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_UDF
+	bool "udf filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_UDF
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+### config FEATURE_VOLUMEID_HIGHPOINTRAID
+###	bool "highpoint raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_HPFS
+###	bool "hpfs filesystem"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_ISWRAID
+###	bool "intel raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_LSIRAID
+###	bool "lsi raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_LVM
+###	bool "lvm"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_MAC
+###	bool "mac filesystem"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_MINIX
+###	bool "minix filesystem"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_MSDOS
+###	bool "msdos filesystem"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_NVIDIARAID
+###	bool "nvidia raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_PROMISERAID
+###	bool "promise raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_SILICONRAID
+###	bool "silicon raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_UFS
+###	bool "ufs filesystem"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+### config FEATURE_VOLUMEID_VIARAID
+###	bool "via raid"
+###	default y
+###	depends on VOLUMEID
+###	help
+###	  TODO
+
+
+config BUSYBOX_CONFIG_FEATURE_VOLUMEID_XFS
+	bool "xfs filesystem"
+	default BUSYBOX_DEFAULT_FEATURE_VOLUMEID_XFS
+	depends on BUSYBOX_CONFIG_VOLUMEID
+	help
+	  TODO
+
+
+endmenu
diff --git a/package/utils/busybox/convert_defaults.pl b/package/utils/busybox/convert_defaults.pl
new file mode 100755
index 0000000000..dada6ef031
--- /dev/null
+++ b/package/utils/busybox/convert_defaults.pl
@@ -0,0 +1,13 @@
+#!/usr/bin/env perl
+
+while (<>) {
+	/^(# )?CONFIG_([^=]+)(=(.+)| is not set)/ and do {
+		my $default = $4;
+		$1 and $default = "n";
+		my $name = $2;
+		my $type = "bool";
+		$default =~ /^\"/ and $type = "string";
+		$default =~ /^\d/ and $type = "int";
+		print "config BUSYBOX_DEFAULT_$name\n\t$type\n\tdefault $default\n";
+	};
+}
diff --git a/package/utils/busybox/convert_menuconfig.pl b/package/utils/busybox/convert_menuconfig.pl
new file mode 100755
index 0000000000..70518809aa
--- /dev/null
+++ b/package/utils/busybox/convert_menuconfig.pl
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+use strict;
+my $PATH = $ARGV[0];
+($PATH and -d $PATH) or die 'invalid path';
+
+my %config;
+
+open FIND, "find \"$PATH\" -name Config.in |";
+while (<FIND>) {
+	chomp;
+	my $input = $_;
+	my $output = $input;
+	my $replace = quotemeta($PATH);
+	$output =~ s/^$replace\///g;
+	$output =~ s/sysdeps\/linux\///g;
+	print STDERR "$input => $output\n";
+	$output =~ /^(.+)\/[^\/]+$/ and system("mkdir -p $1");
+
+	open INPUT, $input;
+	open OUTPUT, ">$output";
+	my ($cur, $default_set, $line);
+	while ($line = <INPUT>) {
+		next if $line =~ /^\s*mainmenu/;
+
+		# FIXME: make this dynamic
+		$line =~ s/default FEATURE_BUFFERS_USE_MALLOC/default FEATURE_BUFFERS_GO_ON_STACK/;
+		$line =~ s/default FEATURE_SH_IS_NONE/default FEATURE_SH_IS_ASH/;
+
+		if ($line =~ /^\s*config\s*([\w_]+)/) {
+			$cur = $1;
+			undef $default_set;
+		}
+		if ($line =~ /^\s*(menu|choice|end|source)/) {
+			undef $cur;
+			undef $default_set;
+		}
+		$line =~ s/^(\s*source\s+)([^\/]+\/)*([^\/]+\/[^\/]+)$/$1$3/;
+		if ($line =~ /^(\s*range\s*)(\w+)(\s+)(\w+)\s*$/) {
+			my $prefix = $1;
+			my $r1 = $2;
+			my $r2 = $4;
+			$r1 =~ s/^([a-zA-Z]+)/BUSYBOX_CONFIG_$1/;
+			$r2 =~ s/^([a-zA-Z]+)/BUSYBOX_CONFIG_$1/;
+			$line = "$prefix$r1 $r2\n";
+		}
+
+		$line =~ s/^(\s*(prompt "[^"]+" if|config|depends|depends on|select|default|default \w if)\s+\!?)([A-Z_])/$1BUSYBOX_CONFIG_$3/g;
+		$line =~ s/(( \|\| | \&\& | \( )!?)([A-Z_])/$1BUSYBOX_CONFIG_$3/g;
+		$line =~ s/(\( ?!?)([A-Z_]+ (\|\||&&))/$1BUSYBOX_CONFIG_$2/g;
+
+		if ($cur) {
+			($cur eq 'LFS') and do {
+				$line =~ s/^(\s*(bool|tristate|string))\s*".+"$/$1/;
+			};
+			if ($line =~ /^\s*default/) {
+				my $c;
+				$default_set = 1;
+				$c = "BUSYBOX_DEFAULT_$cur";
+
+				$line =~ s/^(\s*default\s*)(\w+|"[^"]*")(.*)/$1$c$3/;
+			}
+		}
+
+		print OUTPUT $line;
+	}
+	close OUTPUT;
+	close INPUT;
+}
+close FIND;
diff --git a/package/utils/busybox/files/cron b/package/utils/busybox/files/cron
new file mode 100755
index 0000000000..a201374276
--- /dev/null
+++ b/package/utils/busybox/files/cron
@@ -0,0 +1,38 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006-2011 OpenWrt.org
+
+START=50
+
+USE_PROCD=1
+PROG=/usr/sbin/crond
+
+validate_cron_section() {
+	uci_validate_section system system "${1}" \
+		'cronloglevel:uinteger'
+}
+
+start_service () {
+	[ -z "$(ls /etc/crontabs/)" ] && return 1
+
+	loglevel="$(uci_get "system.@system[0].cronloglevel")"
+
+	[ -z "${loglevel}" ] || {
+		/sbin/validate_data uinteger "${loglevel}" 2>/dev/null
+		[ "$?" -eq 0 ] || {
+			echo "validation failed"
+			return 1
+		}
+	}
+
+	mkdir -p /var/spool/cron
+	ln -s /etc/crontabs /var/spool/cron/ 2>/dev/null
+
+	procd_open_instance
+	procd_set_param command "$PROG" -f -c /etc/crontabs -l "${loglevel:-5}"
+	procd_close_instance
+}
+
+service_triggers()
+{
+	procd_add_validation validate_cron_section
+}
diff --git a/package/utils/busybox/files/ntpd-hotplug b/package/utils/busybox/files/ntpd-hotplug
new file mode 100755
index 0000000000..8d6d609166
--- /dev/null
+++ b/package/utils/busybox/files/ntpd-hotplug
@@ -0,0 +1,2 @@
+#!/bin/sh
+ACTION="$1" /sbin/hotplug-call ntp
diff --git a/package/utils/busybox/files/sysntpd b/package/utils/busybox/files/sysntpd
new file mode 100755
index 0000000000..98260be608
--- /dev/null
+++ b/package/utils/busybox/files/sysntpd
@@ -0,0 +1,86 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2011 OpenWrt.org
+
+START=98
+
+USE_PROCD=1
+PROG=/usr/sbin/ntpd
+HOTPLUG_SCRIPT=/usr/sbin/ntpd-hotplug
+
+get_dhcp_ntp_servers() {
+	local interfaces="$1"
+	local filter="*"
+	local interface ntpservers ntpserver
+
+	for interface in $interfaces; do
+		[ "$filter" = "*" ] && filter="@.interface='$interface'" || filter="$filter,@.interface='$interface'"
+	done
+
+	ntpservers=$(ubus call network.interface dump | jsonfilter -e "@.interface[$filter]['data']['ntpserver']")
+
+	for ntpserver in $ntpservers; do
+		local duplicate=0
+		local entry
+		for entry in $server; do
+			[ "$ntpserver" = "$entry" ] && duplicate=1
+		done
+		[ "$duplicate" = 0 ] && server="$server $ntpserver"
+	done
+}
+
+validate_ntp_section() {
+	uci_validate_section system timeserver "${1}" \
+		'server:list(host)' 'enabled:bool:1' 'enable_server:bool:0' 'use_dhcp:bool:1' 'dhcp_interface:list(string)'
+}
+
+start_service() {
+	local server enabled enable_server use_dhcp dhcp_interface peer
+
+	validate_ntp_section ntp || {
+		echo "validation failed"
+		return 1
+	}
+
+	[ $enabled = 0 ] && return
+
+	[ $use_dhcp = 1 ] && get_dhcp_ntp_servers "$dhcp_interface"
+
+	[ -z "$server" ] && return
+
+	procd_open_instance
+	procd_set_param command "$PROG" -n -N
+	[ "$enable_server" = "1" ] && procd_append_param command -l
+	[ -x "$HOTPLUG_SCRIPT" ] && procd_append_param command -S "$HOTPLUG_SCRIPT"
+	for peer in $server; do
+		procd_append_param command -p $peer
+	done
+	procd_set_param respawn
+	procd_close_instance
+}
+
+service_triggers() {
+	local script name use_dhcp
+
+	script=$(readlink -f "$initscript")
+	name=$(basename ${script:-$initscript})
+
+	procd_add_config_trigger "config.change" "system" /etc/init.d/$name reload
+
+	config_load system
+	config_get use_dhcp ntp use_dhcp 1
+
+	[ $use_dhcp = 1 ] && {
+		local dhcp_interface
+		config_get dhcp_interface ntp dhcp_interface
+
+		if [ -n "$dhcp_interface" ]; then
+			for n in $dhcp_interface; do
+				procd_add_interface_trigger "interface.*" $n /etc/init.d/$name reload
+			done
+		else
+			procd_add_raw_trigger "interface.*" 1000 /etc/init.d/$name reload
+		fi
+	}
+
+	procd_add_validation validate_ntp_section
+}
diff --git a/package/utils/busybox/patches/001-resource_h_include.patch b/package/utils/busybox/patches/001-resource_h_include.patch
new file mode 100644
index 0000000000..33e12c8bd4
--- /dev/null
+++ b/package/utils/busybox/patches/001-resource_h_include.patch
@@ -0,0 +1,10 @@
+--- a/include/libbb.h
++++ b/include/libbb.h
+@@ -41,6 +41,7 @@
+ #include <poll.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
++#include <sys/resource.h>
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ #include <sys/time.h>
diff --git a/package/utils/busybox/patches/002-libbb-send_to_from-do-not-require-that-to-should-hav.patch b/package/utils/busybox/patches/002-libbb-send_to_from-do-not-require-that-to-should-hav.patch
new file mode 100644
index 0000000000..f33c3b22e1
--- /dev/null
+++ b/package/utils/busybox/patches/002-libbb-send_to_from-do-not-require-that-to-should-hav.patch
@@ -0,0 +1,37 @@
+From 7cef4817d6d6d61a1166ed7dfc13537b95c65970 Mon Sep 17 00:00:00 2001
+From: Denys Vlasenko <vda.linux@googlemail.com>
+Date: Thu, 15 Sep 2016 13:20:51 +0200
+Subject: [PATCH] libbb:/send_to_from: do not require that "to" should have the
+ same AF. Closes 9146
+
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+---
+ libbb/udp_io.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/libbb/udp_io.c
++++ b/libbb/udp_io.c
+@@ -70,7 +70,13 @@ send_to_from(int fd, void *buf, size_t l
+ 	msg.msg_flags = flags;
+ 
+ 	cmsgptr = CMSG_FIRSTHDR(&msg);
+-	if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
++	/*
++	 * Users report that to->sa_family can be AF_INET6 too,
++	 * if "to" was acquired by recv_from_to(). IOW: recv_from_to()
++	 * was seen showing IPv6 "from" even when the destination
++	 * of received packet (our local address) was IPv4.
++	 */
++	if (/* to->sa_family == AF_INET && */ from->sa_family == AF_INET) {
+ 		struct in_pktinfo *pktptr;
+ 		cmsgptr->cmsg_level = IPPROTO_IP;
+ 		cmsgptr->cmsg_type = IP_PKTINFO;
+@@ -86,7 +92,7 @@ send_to_from(int fd, void *buf, size_t l
+ 		pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
+ 	}
+ # if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
+-	else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
++	else if (/* to->sa_family == AF_INET6 && */ from->sa_family == AF_INET6) {
+ 		struct in6_pktinfo *pktptr;
+ 		cmsgptr->cmsg_level = IPPROTO_IPV6;
+ 		cmsgptr->cmsg_type = IPV6_PKTINFO;
diff --git a/package/utils/busybox/patches/100-trylink_bash.patch b/package/utils/busybox/patches/100-trylink_bash.patch
new file mode 100644
index 0000000000..f9571fcbc8
--- /dev/null
+++ b/package/utils/busybox/patches/100-trylink_bash.patch
@@ -0,0 +1,8 @@
+--- a/scripts/trylink
++++ b/scripts/trylink
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/env bash
+ 
+ debug=false
+ 
diff --git a/package/utils/busybox/patches/101-gen_build_files_bash.patch b/package/utils/busybox/patches/101-gen_build_files_bash.patch
new file mode 100644
index 0000000000..d258fb8bc4
--- /dev/null
+++ b/package/utils/busybox/patches/101-gen_build_files_bash.patch
@@ -0,0 +1,8 @@
+--- a/scripts/gen_build_files.sh
++++ b/scripts/gen_build_files.sh
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/env bash
+ 
+ # Note: was using sed OPTS CMD -- FILES
+ # but users complain that many sed implementations
diff --git a/package/utils/busybox/patches/102-trylink_mktemp_fix.patch b/package/utils/busybox/patches/102-trylink_mktemp_fix.patch
new file mode 100644
index 0000000000..ed1dcbb66f
--- /dev/null
+++ b/package/utils/busybox/patches/102-trylink_mktemp_fix.patch
@@ -0,0 +1,20 @@
+--- a/scripts/trylink
++++ b/scripts/trylink
+@@ -46,7 +46,7 @@ try() {
+ }
+ 
+ check_cc() {
+-    local tempname="$(mktemp)"
++    local tempname="$(mktemp /tmp/tmp.XXXXXXXXXX)"
+     local r
+     echo "int main(int argc,char**argv){return argv?argc:0;}" >"$tempname".c
+     # Can use "-o /dev/null", but older gcc tend to *unlink it* on failure! :(
+@@ -61,7 +61,7 @@ check_cc() {
+ }
+ 
+ check_libc_is_glibc() {
+-    local tempname="$(mktemp)"
++    local tempname="$(mktemp /tmp/tmp.XXXXXXXXXX)"
+     local r
+     echo "\
+ 	#include <stdlib.h>
diff --git a/package/utils/busybox/patches/110-no_static_libgcc.patch b/package/utils/busybox/patches/110-no_static_libgcc.patch
new file mode 100644
index 0000000000..2148a09e00
--- /dev/null
+++ b/package/utils/busybox/patches/110-no_static_libgcc.patch
@@ -0,0 +1,11 @@
+--- a/Makefile.flags
++++ b/Makefile.flags
+@@ -51,7 +51,7 @@ CFLAGS += $(call cc-option,-fno-builtin-
+ # -fno-guess-branch-probability: prohibit pseudo-random guessing
+ # of branch probabilities (hopefully makes bloatcheck more stable):
+ CFLAGS += $(call cc-option,-fno-guess-branch-probability,)
+-CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,)
++CFLAGS += $(call cc-option,-funsigned-char,)
+ CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,)
+ # Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary):
+ CFLAGS += $(call cc-option,-fno-unwind-tables,)
diff --git a/package/utils/busybox/patches/120-remove_uclibc_rpc_check.patch b/package/utils/busybox/patches/120-remove_uclibc_rpc_check.patch
new file mode 100644
index 0000000000..4825bc8a67
--- /dev/null
+++ b/package/utils/busybox/patches/120-remove_uclibc_rpc_check.patch
@@ -0,0 +1,12 @@
+--- a/util-linux/mount.c
++++ b/util-linux/mount.c
+@@ -237,9 +237,6 @@
+ #if ENABLE_FEATURE_MOUNT_NFS
+ /* This is just a warning of a common mistake.  Possibly this should be a
+  * uclibc faq entry rather than in busybox... */
+-# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
+-#  error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
+-# endif
+ # include <rpc/rpc.h>
+ # include <rpc/pmap_prot.h>
+ # include <rpc/pmap_clnt.h>
diff --git a/package/utils/busybox/patches/130-mconf_missing_sigwinch.patch b/package/utils/busybox/patches/130-mconf_missing_sigwinch.patch
new file mode 100644
index 0000000000..54f878a6c1
--- /dev/null
+++ b/package/utils/busybox/patches/130-mconf_missing_sigwinch.patch
@@ -0,0 +1,13 @@
+--- a/scripts/kconfig/mconf.c
++++ b/scripts/kconfig/mconf.c
+@@ -27,6 +27,10 @@
+ #include <unistd.h>
+ #include <locale.h>
+ 
++#ifndef SIGWINCH
++#define SIGWINCH 28
++#endif
++
+ #define LKC_DIRECT_LINK
+ #include "lkc.h"
+ 
diff --git a/package/utils/busybox/patches/200-udhcpc_reduce_msgs.patch b/package/utils/busybox/patches/200-udhcpc_reduce_msgs.patch
new file mode 100644
index 0000000000..0fdaed502a
--- /dev/null
+++ b/package/utils/busybox/patches/200-udhcpc_reduce_msgs.patch
@@ -0,0 +1,18 @@
+--- a/networking/udhcp/dhcpc.c
++++ b/networking/udhcp/dhcpc.c
+@@ -697,6 +697,7 @@ static int bcast_or_ucast(struct dhcp_pa
+ static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
+ {
+ 	struct dhcp_packet packet;
++	static int msgs = 0;
+ 
+ 	/* Fill in: op, htype, hlen, cookie, chaddr fields,
+ 	 * random xid field (we override it below),
+@@ -714,6 +715,7 @@ static NOINLINE int send_discover(uint32
+ 	 */
+ 	add_client_options(&packet);
+ 
++	if (msgs++ < 3)
+ 	bb_error_msg("sending %s", "discover");
+ 	return raw_bcast_from_client_config_ifindex(&packet, INADDR_ANY);
+ }
diff --git a/package/utils/busybox/patches/201-udhcpc_changed_ifindex.patch b/package/utils/busybox/patches/201-udhcpc_changed_ifindex.patch
new file mode 100644
index 0000000000..4a9ae9813e
--- /dev/null
+++ b/package/utils/busybox/patches/201-udhcpc_changed_ifindex.patch
@@ -0,0 +1,15 @@
+--- a/networking/udhcp/dhcpc.c
++++ b/networking/udhcp/dhcpc.c
+@@ -1422,6 +1422,12 @@ int udhcpc_main(int argc UNUSED_PARAM, c
+ 		/* silence "uninitialized!" warning */
+ 		unsigned timestamp_before_wait = timestamp_before_wait;
+ 
++		/* When running on a bridge, the ifindex may have changed (e.g. if
++		 * member interfaces were added/removed or if the status of the
++		 * bridge changed).
++		 * Workaround: refresh it here before processing the next packet */
++		udhcp_read_interface(client_config.interface, &client_config.ifindex, NULL, client_config.client_mac);
++
+ 		//bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
+ 
+ 		/* Was opening raw or udp socket here
diff --git a/package/utils/busybox/patches/203-udhcpc_renew_no_deconfig.patch b/package/utils/busybox/patches/203-udhcpc_renew_no_deconfig.patch
new file mode 100644
index 0000000000..1e44552c13
--- /dev/null
+++ b/package/utils/busybox/patches/203-udhcpc_renew_no_deconfig.patch
@@ -0,0 +1,10 @@
+--- a/networking/udhcp/dhcpc.c
++++ b/networking/udhcp/dhcpc.c
+@@ -1103,7 +1103,6 @@ static void perform_renew(void)
+ 		state = RENEW_REQUESTED;
+ 		break;
+ 	case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
+-		udhcp_run_script(NULL, "deconfig");
+ 	case REQUESTING:
+ 	case RELEASED:
+ 		change_listen_mode(LISTEN_RAW);
diff --git a/package/utils/busybox/patches/210-add_netmsg_util.patch b/package/utils/busybox/patches/210-add_netmsg_util.patch
new file mode 100644
index 0000000000..2382698d0f
--- /dev/null
+++ b/package/utils/busybox/patches/210-add_netmsg_util.patch
@@ -0,0 +1,103 @@
+--- a/include/applets.src.h
++++ b/include/applets.src.h
+@@ -229,6 +229,7 @@ IF_MT(APPLET(mt, BB_DIR_BIN, BB_SUID_DRO
+ IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP))
+ IF_NAMEIF(APPLET(nameif, BB_DIR_SBIN, BB_SUID_DROP))
+ IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP))
++IF_NETMSG(APPLET(netmsg, BB_DIR_BIN, BB_SUID_REQUIRE))
+ IF_NETSTAT(APPLET(netstat, BB_DIR_BIN, BB_SUID_DROP))
+ IF_NICE(APPLET(nice, BB_DIR_BIN, BB_SUID_DROP))
+ IF_NOHUP(APPLET(nohup, BB_DIR_USR_BIN, BB_SUID_DROP))
+--- a/networking/Config.src
++++ b/networking/Config.src
+@@ -639,6 +639,12 @@ config FEATURE_IPCALC_LONG_OPTIONS
+ 	help
+ 	  Support long options for the ipcalc applet.
+ 
++config NETMSG
++	bool "netmsg"
++	default n
++	help
++	  simple program for sending udp broadcast messages
++
+ config NETSTAT
+ 	bool "netstat"
+ 	default y
+--- a/networking/Kbuild.src
++++ b/networking/Kbuild.src
+@@ -27,6 +27,7 @@ lib-$(CONFIG_IP)           += ip.o
+ lib-$(CONFIG_IPCALC)       += ipcalc.o
+ lib-$(CONFIG_NAMEIF)       += nameif.o
+ lib-$(CONFIG_NC)           += nc.o
++lib-$(CONFIG_NETMSG)       += netmsg.o
+ lib-$(CONFIG_NETSTAT)      += netstat.o
+ lib-$(CONFIG_NSLOOKUP)     += nslookup.o
+ lib-$(CONFIG_NTPD)         += ntpd.o
+--- /dev/null
++++ b/networking/netmsg.c
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
++ *
++ * This is free software, licensed under the GNU General Public License v2.
++ */
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <netdb.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "busybox.h"
++
++//usage:#define netmsg_trivial_usage NOUSAGE_STR
++//usage:#define netmsg_full_usage ""
++
++#ifndef CONFIG_NETMSG
++int main(int argc, char **argv)
++#else
++int netmsg_main(int argc, char **argv)
++#endif
++{
++	int s;
++	struct sockaddr_in addr;
++	int optval = 1;
++	unsigned char buf[1001];
++
++	if (argc != 3) {
++		fprintf(stderr, "usage: %s <ip> \"<message>\"\n", argv[0]);
++		exit(1);
++	}
++
++	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
++		perror("Opening socket");
++		exit(1);
++	}
++
++	memset(&addr, 0, sizeof(addr));
++	addr.sin_family = AF_INET;
++	addr.sin_addr.s_addr = inet_addr(argv[1]);
++	addr.sin_port = htons(0x1337);
++
++	memset(buf, 0, 1001);
++	buf[0] = 0xde;
++	buf[1] = 0xad;
++
++	strncpy(buf + 2, argv[2], 998);
++
++	if (setsockopt (s, SOL_SOCKET, SO_BROADCAST, (caddr_t) &optval, sizeof (optval)) < 0) {
++		perror("setsockopt()");
++		goto fail;
++	}
++
++	if (sendto(s, buf, 1001, 0, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
++		perror("sendto()");
++		goto fail;
++	}
++
++	return 0;
++
++fail:
++	close(s);
++	exit(1);
++}
diff --git a/package/utils/busybox/patches/220-add_lock_util.patch b/package/utils/busybox/patches/220-add_lock_util.patch
new file mode 100644
index 0000000000..c60f5db392
--- /dev/null
+++ b/package/utils/busybox/patches/220-add_lock_util.patch
@@ -0,0 +1,182 @@
+--- a/include/applets.src.h
++++ b/include/applets.src.h
+@@ -196,6 +196,7 @@ IF_LN(APPLET_NOEXEC(ln, ln, BB_DIR_BIN,
+ IF_LOAD_POLICY(APPLET(load_policy, BB_DIR_USR_SBIN, BB_SUID_DROP))
+ IF_LOADFONT(APPLET(loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP))
+ IF_LOADKMAP(APPLET(loadkmap, BB_DIR_SBIN, BB_SUID_DROP))
++IF_LOCK(APPLET(lock, BB_DIR_BIN, BB_SUID_DROP))
+ IF_LOGNAME(APPLET_NOFORK(logname, logname, BB_DIR_USR_BIN, BB_SUID_DROP, logname))
+ IF_LOSETUP(APPLET(losetup, BB_DIR_SBIN, BB_SUID_DROP))
+ IF_LS(APPLET_NOEXEC(ls, ls, BB_DIR_BIN, BB_SUID_DROP, ls))
+--- a/miscutils/Config.src
++++ b/miscutils/Config.src
+@@ -375,6 +375,12 @@ config FEATURE_HDPARM_HDIO_GETSET_DMA
+ 	help
+ 	  Enables the 'hdparm -d' option to get/set using_dma flag.
+ 
++config LOCK
++	bool "lock"
++	default n
++	help
++	  Small utility for using locks in scripts
++
+ config MAKEDEVS
+ 	bool "makedevs"
+ 	default y
+--- a/miscutils/Kbuild.src
++++ b/miscutils/Kbuild.src
+@@ -33,6 +33,7 @@ lib-$(CONFIG_LAST)        += last.o
+ endif
+ 
+ lib-$(CONFIG_LESS)        += less.o
++lib-$(CONFIG_LOCK)        += lock.o
+ lib-$(CONFIG_MAKEDEVS)    += makedevs.o
+ lib-$(CONFIG_MAN)         += man.o
+ lib-$(CONFIG_MICROCOM)    += microcom.o
+--- /dev/null
++++ b/miscutils/lock.c
+@@ -0,0 +1,144 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
++ *
++ * This is free software, licensed under the GNU General Public License v2.
++ */
++#include <sys/types.h>
++#include <sys/file.h>
++#include <sys/stat.h>
++#include <signal.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <stdio.h>
++#include "busybox.h"
++
++//usage:#define lock_trivial_usage NOUSAGE_STR
++//usage:#define lock_full_usage ""
++
++static int unlock = 0;
++static int shared = 0;
++static int waitonly = 0;
++static int try_lock = 0;
++static int fd;
++static char *file;
++
++static void usage(char *name)
++{
++	fprintf(stderr, "Usage: %s [-suw] <filename>\n"
++	                "	-s	Use shared locking\n"
++	                "	-u	Unlock\n"
++	                "	-w	Wait for the lock to become free, don't acquire lock\n"
++			"	-n	Don't wait for the lock to become free. Fail with exit code\n"
++					"\n", name);
++	exit(1);
++}
++
++static void exit_unlock(int sig)
++{
++	flock(fd, LOCK_UN);
++	exit(0);
++}
++
++static int do_unlock(void)
++{
++	FILE *f;
++	int i;
++
++	if ((f = fopen(file, "r")) == NULL)
++		return 0;
++
++	fscanf(f, "%d", &i);
++	if (i > 0)
++		kill(i, SIGTERM);
++
++	fclose(f);
++
++	return 0;
++}
++
++static int do_lock(void)
++{
++	int pid;
++	int flags;
++	char pidstr[8];
++
++	if ((fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
++		if ((fd = open(file, O_RDWR)) < 0) {
++			fprintf(stderr, "Can't open %s\n", file);
++			return 1;
++		}
++	}
++
++	flags = shared ? LOCK_SH : LOCK_EX;
++	flags |= try_lock ? LOCK_NB : 0;
++
++	if (flock(fd, flags) < 0) {
++		fprintf(stderr, "Can't lock %s\n", file);
++		return 1;
++	}
++
++	pid = fork();
++
++	if (pid < 0)
++		return -1;
++
++	if (pid == 0) {
++		signal(SIGKILL, exit_unlock);
++		signal(SIGTERM, exit_unlock);
++		signal(SIGINT, exit_unlock);
++		if (waitonly)
++			exit_unlock(0);
++		else
++			while (1)
++				sleep(1);
++	} else {
++		if (!waitonly) {
++			lseek(fd, 0, SEEK_SET);
++			ftruncate(fd, 0);
++			sprintf(pidstr, "%d\n", pid);
++			write(fd, pidstr, strlen(pidstr));
++			close(fd);
++		}
++
++		return 0;
++	}
++	return 0;
++}
++
++int lock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
++int lock_main(int argc, char **argv)
++{
++	char **args = &argv[1];
++	int c = argc - 1;
++
++	while ((*args != NULL) && (*args)[0] == '-') {
++		char *ch = *args;
++		while (*(++ch) > 0) {
++			switch(*ch) {
++				case 'w':
++					waitonly = 1;
++					break;
++				case 's':
++					shared = 1;
++					break;
++				case 'u':
++					unlock = 1;
++					break;
++				case 'n':
++					try_lock = 1;
++					break;
++			}
++		}
++		c--;
++		args++;
++	}
++
++	if (c != 1)
++		usage(argv[0]);
++
++	file = *args;
++	if (unlock)
++		return do_unlock();
++	else
++		return do_lock();
++}
diff --git a/package/utils/busybox/patches/240-telnetd_intr.patch b/package/utils/busybox/patches/240-telnetd_intr.patch
new file mode 100644
index 0000000000..d52ea3fcc1
--- /dev/null
+++ b/package/utils/busybox/patches/240-telnetd_intr.patch
@@ -0,0 +1,10 @@
+--- a/networking/telnetd.c
++++ b/networking/telnetd.c
+@@ -333,6 +333,7 @@ make_new_session(
+ 
+ 	/* Restore default signal handling ASAP */
+ 	bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
++	signal(SIGINT, SIG_DFL);
+ 
+ 	pid = getpid();
+ 
diff --git a/package/utils/busybox/patches/250-date-k-flag.patch b/package/utils/busybox/patches/250-date-k-flag.patch
new file mode 100644
index 0000000000..b2681a17f9
--- /dev/null
+++ b/package/utils/busybox/patches/250-date-k-flag.patch
@@ -0,0 +1,91 @@
+--- a/coreutils/date.c
++++ b/coreutils/date.c
+@@ -123,6 +123,7 @@
+ //usage:	IF_FEATURE_DATE_ISOFMT(
+ //usage:     "\n	-D FMT		Use FMT for -d TIME conversion"
+ //usage:	)
++//usage:     "\n	-k		Set Kernel timezone from localtime and exit"
+ //usage:     "\n"
+ //usage:     "\nRecognized TIME formats:"
+ //usage:     "\n	hh:mm[:ss]"
+@@ -139,9 +140,8 @@
+ 
+ #include "libbb.h"
+ #include "common_bufsiz.h"
+-#if ENABLE_FEATURE_DATE_NANO
+-# include <sys/syscall.h>
+-#endif
++#include <sys/time.h>
++#include <sys/syscall.h>
+ 
+ enum {
+ 	OPT_RFC2822   = (1 << 0), /* R */
+@@ -149,8 +149,9 @@ enum {
+ 	OPT_UTC       = (1 << 2), /* u */
+ 	OPT_DATE      = (1 << 3), /* d */
+ 	OPT_REFERENCE = (1 << 4), /* r */
+-	OPT_TIMESPEC  = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* I */
+-	OPT_HINT      = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */
++	OPT_KERNELTZ  = (1 << 5), /* k */
++	OPT_TIMESPEC  = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* I */
++	OPT_HINT      = (1 << 7) * ENABLE_FEATURE_DATE_ISOFMT, /* D */
+ };
+ 
+ static void maybe_set_utc(int opt)
+@@ -168,12 +169,15 @@ static const char date_longopts[] ALIGN1
+ 	/*	"universal\0" No_argument       "u" */
+ 		"date\0"      Required_argument "d"
+ 		"reference\0" Required_argument "r"
++		"set-kernel-tz\0" No_argument   "k"
+ 		;
+ #endif
+ 
+ int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+ int date_main(int argc UNUSED_PARAM, char **argv)
+ {
++	time_t tt;
++	struct timezone tz;
+ 	struct timespec ts;
+ 	struct tm tm_time;
+ 	char buf_fmt_dt2str[64];
+@@ -188,7 +192,7 @@ int date_main(int argc UNUSED_PARAM, cha
+ 	opt_complementary = "d--s:s--d"
+ 		IF_FEATURE_DATE_ISOFMT(":R--I:I--R");
+ 	IF_LONG_OPTS(applet_long_options = date_longopts;)
+-	opt = getopt32(argv, "Rs:ud:r:"
++	opt = getopt32(argv, "Rs:ud:r:k"
+ 			IF_FEATURE_DATE_ISOFMT("I::D:"),
+ 			&date_str, &date_str, &filename
+ 			IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
+@@ -245,6 +249,31 @@ int date_main(int argc UNUSED_PARAM, cha
+ 	if (*argv)
+ 		bb_show_usage();
+ 
++	/* Setting of kernel timezone was requested */
++	if (opt & OPT_KERNELTZ) {
++		tt = time(NULL);
++		localtime_r(&tt, &tm_time);
++
++		/* workaround warp_clock() on first invocation */
++		memset(&tz, 0, sizeof(tz));
++		syscall(SYS_settimeofday, NULL, &tz);
++
++		memset(&tz, 0, sizeof(tz));
++#ifdef __USE_MISC
++		tz.tz_minuteswest = -(tm_time.tm_gmtoff / 60);
++#else
++		tz.tz_minuteswest = -(tm_time.__tm_gmtoff / 60);
++#endif
++
++		if (syscall(SYS_settimeofday, NULL, &tz))
++		{
++			bb_perror_msg("can't set kernel time zone");
++			return EXIT_FAILURE;
++		}
++
++		return EXIT_SUCCESS;
++	}
++
+ 	/* Now we have parsed all the information except the date format
+ 	 * which depends on whether the clock is being set or read */
+ 
diff --git a/package/utils/busybox/patches/270-libbb_make_unicode_printable.patch b/package/utils/busybox/patches/270-libbb_make_unicode_printable.patch
new file mode 100644
index 0000000000..0ae8340568
--- /dev/null
+++ b/package/utils/busybox/patches/270-libbb_make_unicode_printable.patch
@@ -0,0 +1,20 @@
+--- a/libbb/printable_string.c
++++ b/libbb/printable_string.c
+@@ -28,8 +28,6 @@ const char* FAST_FUNC printable_string(u
+ 		}
+ 		if (c < ' ')
+ 			break;
+-		if (c >= 0x7f)
+-			break;
+ 		s++;
+ 	}
+ 
+@@ -42,7 +40,7 @@ const char* FAST_FUNC printable_string(u
+ 			unsigned char c = *d;
+ 			if (c == '\0')
+ 				break;
+-			if (c < ' ' || c >= 0x7f)
++			if (c < ' ')
+ 				*d = '?';
+ 			d++;
+ 		}
diff --git a/package/utils/busybox/patches/301-ip-link-fix-netlink-msg-size.patch b/package/utils/busybox/patches/301-ip-link-fix-netlink-msg-size.patch
new file mode 100644
index 0000000000..360324bf7c
--- /dev/null
+++ b/package/utils/busybox/patches/301-ip-link-fix-netlink-msg-size.patch
@@ -0,0 +1,11 @@
+--- a/networking/libiproute/iplink.c
++++ b/networking/libiproute/iplink.c
+@@ -470,7 +470,7 @@ static int do_add_or_delete(char **argv,
+ 	}
+ 	xrtnl_open(&rth);
+ 	ll_init_map(&rth);
+-	if (type_str) {
++	if (type_str && rtm == RTM_NEWLINK) {
+ 		struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
+ 
+ 		addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
diff --git a/package/utils/busybox/patches/302-netlink-alignment.patch b/package/utils/busybox/patches/302-netlink-alignment.patch
new file mode 100644
index 0000000000..4cd25b1872
--- /dev/null
+++ b/package/utils/busybox/patches/302-netlink-alignment.patch
@@ -0,0 +1,100 @@
+From a843f09a4d4428cf11ca02307e60058251b05743 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 16 Sep 2016 21:52:03 +0200
+Subject: [PATCH] libnetlink: fix alignment of netlink messages
+
+An padding to align a message should not only be added between
+different attributes of a netlink message, but also at the end of the
+message to pad it to the correct size.
+
+Without this patch the following command does not work and returns an
+error code:
+ip link add type nlmon
+
+Without this ip from busybox sends this:
+sendmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{len=45, type=0x10 /* NLMSG_??? */, flags=NLM_F_REQUEST|NLM_F_ACK|0x600, seq=1474057401, pid=0}, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\22\0\t\0\1nlmon"}, iov_len=45}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 45
+return value: 2
+
+The normal ip utile from iproute2 sends this:
+sendmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{len=48, type=0x10 /* NLMSG_??? */, flags=NLM_F_REQUEST|NLM_F_ACK|0x600, seq=1473716938, pid=0}, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\22\0\t\0\1nlmon\0\0\0"}, iov_len=48}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 48
+return value: 0
+
+With this patch ip from busybox sends this:
+sendmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{len=48, type=0x10 /* NLMSG_??? */, flags=NLM_F_REQUEST|NLM_F_ACK|0x600, seq=1473716908, pid=0}, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\22\0\t\0\1nlmon\0\0\0"}, iov_len=48}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 48
+return value: 0
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ networking/libiproute/libnetlink.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/networking/libiproute/libnetlink.c
++++ b/networking/libiproute/libnetlink.c
+@@ -338,14 +338,14 @@ int FAST_FUNC addattr32(struct nlmsghdr
+ 	int len = RTA_LENGTH(4);
+ 	struct rtattr *rta;
+ 
+-	if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
++	if ((int)(NLMSG_ALIGN(n->nlmsg_len + len)) > maxlen) {
+ 		return -1;
+ 	}
+ 	rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+ 	rta->rta_type = type;
+ 	rta->rta_len = len;
+ 	move_to_unaligned32(RTA_DATA(rta), data);
+-	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
++	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len + len);
+ 	return 0;
+ }
+ 
+@@ -354,14 +354,14 @@ int FAST_FUNC addattr_l(struct nlmsghdr
+ 	int len = RTA_LENGTH(alen);
+ 	struct rtattr *rta;
+ 
+-	if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
++	if ((int)(NLMSG_ALIGN(n->nlmsg_len + len)) > maxlen) {
+ 		return -1;
+ 	}
+ 	rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+ 	rta->rta_type = type;
+ 	rta->rta_len = len;
+ 	memcpy(RTA_DATA(rta), data, alen);
+-	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
++	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len + len);
+ 	return 0;
+ }
+ 
+@@ -370,14 +370,14 @@ int FAST_FUNC rta_addattr32(struct rtatt
+ 	int len = RTA_LENGTH(4);
+ 	struct rtattr *subrta;
+ 
+-	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
++	if (RTA_ALIGN(rta->rta_len + len) > maxlen) {
+ 		return -1;
+ 	}
+ 	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
+ 	subrta->rta_type = type;
+ 	subrta->rta_len = len;
+ 	move_to_unaligned32(RTA_DATA(subrta), data);
+-	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
++	rta->rta_len = NLMSG_ALIGN(rta->rta_len + len);
+ 	return 0;
+ }
+ 
+@@ -386,14 +386,14 @@ int FAST_FUNC rta_addattr_l(struct rtatt
+ 	struct rtattr *subrta;
+ 	int len = RTA_LENGTH(alen);
+ 
+-	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
++	if (RTA_ALIGN(rta->rta_len + len) > maxlen) {
+ 		return -1;
+ 	}
+ 	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
+ 	subrta->rta_type = type;
+ 	subrta->rta_len = len;
+ 	memcpy(RTA_DATA(subrta), data, alen);
+-	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
++	rta->rta_len = NLMSG_ALIGN(rta->rta_len + len);
+ 	return 0;
+ }
+ 
diff --git a/package/utils/busybox/patches/303-ip-route-fix-high-table-ids.patch b/package/utils/busybox/patches/303-ip-route-fix-high-table-ids.patch
new file mode 100644
index 0000000000..d7a38f632e
--- /dev/null
+++ b/package/utils/busybox/patches/303-ip-route-fix-high-table-ids.patch
@@ -0,0 +1,486 @@
+From 485fcc89b99eae9cc7501eaff344b104e52ab7bf Mon Sep 17 00:00:00 2001
+From: Jo-Philipp Wich <jo@mein.io>
+Date: Mon, 26 Sep 2016 17:48:22 +0200
+Subject: [PATCH] iproute: properly support high routing table IDs
+
+The Linux kernel uses two distinct fields to denote the routing table ID in
+use by network routes; the 8 bit `rtm_table` member of `struct rtmsg` and the
+32 bit `RTA_TABLE` netlink attribute.
+
+If a routing table ID is larger than 255, the `RT_TABLE` attribute must be used
+and the `rtm_table` field has to be set to the special `RT_TABLE_UNSPEC` value.
+
+This commit ...
+ - switches the *_n2a() and *_a2n() functions of rt_names.c to use dynamically
+   sized, name-sorted arrays instead of fixed arrays limited to 1024 slots in
+   order to support IDs up to 65535
+ - adds proper handling of high table IDs to iprule.c and iproute.c when
+   adding, removing and dumping ip rules and network routes
+
+After this change, the Busybox ip applet fully supports IP rules with high ID
+numbers, using the same logic as the full iproute2.
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+---
+ networking/libiproute/iproute.c  |  75 ++++++++------
+ networking/libiproute/iprule.c   |   4 +-
+ networking/libiproute/rt_names.c | 204 +++++++++++++++++++++++----------------
+ 3 files changed, 169 insertions(+), 114 deletions(-)
+
+--- a/networking/libiproute/iproute.c
++++ b/networking/libiproute/iproute.c
+@@ -66,6 +66,7 @@ static int FAST_FUNC print_route(const s
+ 	inet_prefix dst;
+ 	inet_prefix src;
+ 	int host_len = -1;
++	uint32_t rtable;
+ 
+ 	if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
+ 		fprintf(stderr, "Not a route: %08x %08x %08x\n",
+@@ -83,34 +84,6 @@ static int FAST_FUNC print_route(const s
+ 	else if (r->rtm_family == AF_INET)
+ 		host_len = 32;
+ 
+-	if (r->rtm_family == AF_INET6) {
+-		if (G_filter.tb) {
+-			if (G_filter.tb < 0) {
+-				if (!(r->rtm_flags & RTM_F_CLONED)) {
+-					return 0;
+-				}
+-			} else {
+-				if (r->rtm_flags & RTM_F_CLONED) {
+-					return 0;
+-				}
+-				if (G_filter.tb == RT_TABLE_LOCAL) {
+-					if (r->rtm_type != RTN_LOCAL) {
+-						return 0;
+-					}
+-				} else if (G_filter.tb == RT_TABLE_MAIN) {
+-					if (r->rtm_type == RTN_LOCAL) {
+-						return 0;
+-					}
+-				} else {
+-					return 0;
+-				}
+-			}
+-		}
+-	} else {
+-		if (G_filter.tb > 0 && G_filter.tb != r->rtm_table) {
+-			return 0;
+-		}
+-	}
+ 	if (G_filter.rdst.family
+ 	 && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
+ 	) {
+@@ -141,6 +114,37 @@ static int FAST_FUNC print_route(const s
+ 	memset(&dst, 0, sizeof(dst));
+ 	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+ 
++	rtable = tb[RTA_TABLE] ? *(uint32_t*)RTA_DATA(tb[RTA_TABLE]) : r->rtm_table;
++
++	if (G_filter.tb) {
++		if (r->rtm_family == AF_INET6) {
++			if (G_filter.tb < 0) {
++				if (!(r->rtm_flags & RTM_F_CLONED)) {
++					return 0;
++				}
++			} else {
++				if (r->rtm_flags & RTM_F_CLONED) {
++					return 0;
++				}
++				if (G_filter.tb == RT_TABLE_LOCAL) {
++					if (r->rtm_type != RTN_LOCAL) {
++						return 0;
++					}
++				} else if (G_filter.tb == RT_TABLE_MAIN) {
++					if (r->rtm_type == RTN_LOCAL) {
++						return 0;
++					}
++				} else if (G_filter.tb != rtable) {
++					return 0;
++				}
++			}
++		} else {
++			if (G_filter.tb != rtable) {
++				return 0;
++			}
++		}
++	}
++
+ 	if (tb[RTA_SRC]) {
+ 		src.bitlen = r->rtm_src_len;
+ 		src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
+@@ -349,7 +353,9 @@ IF_FEATURE_IP_RULE(ARG_table,)
+ 	smalluint ok = 0;
+ 	smalluint scope_ok = 0;
+ 	int arg;
+-
++#if ENABLE_FEATURE_IP_RULE
++	uint32_t rtable = 0;
++#endif
+ 	memset(&req, 0, sizeof(req));
+ 
+ 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+@@ -419,7 +425,7 @@ IF_FEATURE_IP_RULE(ARG_table,)
+ 			NEXT_ARG();
+ 			if (rtnl_rttable_a2n(&tid, *argv))
+ 				invarg_1_to_2(*argv, "table");
+-			req.r.rtm_table = tid;
++			rtable = tid;
+ #endif
+ 		} else if (arg == ARG_dev || arg == ARG_oif) {
+ 			NEXT_ARG();
+@@ -475,6 +481,15 @@ IF_FEATURE_IP_RULE(ARG_table,)
+ 		}
+ 	}
+ 
++#if ENABLE_FEATURE_IP_RULE
++	if (rtable >= 256) {
++		addattr32(&req.n, sizeof(req), RTA_TABLE, rtable);
++		req.r.rtm_table = RT_TABLE_UNSPEC;
++	} else if (rtable > 0) {
++		req.r.rtm_table = rtable;
++	}
++#endif
++
+ 	if (mxrta->rta_len > RTA_LENGTH(0)) {
+ 		if (mxlock) {
+ 			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
+--- a/networking/libiproute/iprule.c
++++ b/networking/libiproute/iprule.c
+@@ -114,7 +114,9 @@ static int FAST_FUNC print_rule(const st
+ 		printf("iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
+ 	}
+ 
+-	if (r->rtm_table)
++	if (tb[RTA_TABLE])
++		printf("lookup %s ", rtnl_rttable_n2a(*(uint32_t*)RTA_DATA(tb[RTA_TABLE])));
++	else if (r->rtm_table)
+ 		printf("lookup %s ", rtnl_rttable_n2a(r->rtm_table));
+ 
+ 	if (tb[RTA_FLOW]) {
+--- a/networking/libiproute/rt_names.c
++++ b/networking/libiproute/rt_names.c
+@@ -11,21 +11,26 @@
+ #include "rt_names.h"
+ 
+ #define CONFDIR          CONFIG_FEATURE_IP_ROUTE_DIR
++#define RT_TABLE_MAX	65535
++
++struct rtnl_tab_entry {
++	unsigned int id;
++	const char *name;
++};
+ 
+ typedef struct rtnl_tab_t {
+-	const char *cached_str;
+-	unsigned cached_result;
+-	/* upstream version switched to a hash table and removed
+-	 * id < 256 limit. For now bbox bumps this array size from 256
+-	 * to 1024. If you plan to change this to a hash table,
+-	 * consider merging several hash tables we have (for example,
+-	 * awk has resizable one!
+-	 */
+-#define RT_TABLE_MAX 1023
+-	const char *tab[RT_TABLE_MAX+1];
++	struct rtnl_tab_entry *tab;
++	size_t length;
+ } rtnl_tab_t;
+ 
+-static void rtnl_tab_initialize(const char *file, const char **tab)
++static int tabcmp(const void *p1, const void *p2)
++{
++	const struct rtnl_tab_entry *e1 = p1;
++	const struct rtnl_tab_entry *e2 = p2;
++	return strcmp(e1->name, e2->name);
++}
++
++static void rtnl_tab_initialize(const char *file, rtnl_tab_t *tab)
+ {
+ 	char *token[2];
+ 	char fullname[sizeof(CONFDIR"/rt_dsfield") + 8];
+@@ -40,34 +45,42 @@ static void rtnl_tab_initialize(const ch
+ 				file, parser->lineno);
+ 			break;
+ 		}
+-		tab[id] = xstrdup(token[1]);
++
++		tab->tab = xrealloc(tab->tab, (tab->length + 1) * sizeof(*tab->tab));
++		tab->tab[tab->length].id = id;
++		tab->tab[tab->length].name = xstrdup(token[1]);
++		tab->length++;
+ 	}
+ 	config_close(parser);
++	qsort(tab->tab, tab->length, sizeof(*tab->tab), tabcmp);
+ }
+ 
+ static int rtnl_a2n(rtnl_tab_t *tab, uint32_t *id, const char *arg, int base)
+ {
+-	unsigned i;
+-
+-	if (tab->cached_str && strcmp(tab->cached_str, arg) == 0) {
+-		*id = tab->cached_result;
+-		return 0;
+-	}
++	int delta;
++	ssize_t l = 0;
++	ssize_t r = tab->length - 1;
++	ssize_t m;
++	uint32_t i;
++
++	while (l <= r) {
++		m = l + (r - l) / 2;
++		delta = strcmp(tab->tab[m].name, arg);
+ 
+-	for (i = 0; i <= RT_TABLE_MAX; i++) {
+-		if (tab->tab[i]
+-		 && strcmp(tab->tab[i], arg) == 0
+-		) {
+-			tab->cached_str = tab->tab[i];
+-			tab->cached_result = i;
+-			*id = i;
++		if (delta == 0) {
++			*id = tab->tab[m].id;
+ 			return 0;
++		} else if (delta < 0) {
++			l = m + 1;
++		} else {
++			r = m - 1;
+ 		}
+ 	}
+ 
+ 	i = bb_strtou(arg, NULL, base);
+ 	if (i > RT_TABLE_MAX)
+ 		return -1;
++
+ 	*id = i;
+ 	return 0;
+ }
+@@ -77,40 +90,39 @@ static rtnl_tab_t *rtnl_rtprot_tab;
+ 
+ static void rtnl_rtprot_initialize(void)
+ {
+-	static const char *const init_tab[] = {
+-		"none",
+-		"redirect",
+-		"kernel",
+-		"boot",
+-		"static",
+-		NULL,
+-		NULL,
+-		NULL,
+-		"gated",
+-		"ra",
+-		"mrt",
+-		"zebra",
+-		"bird",
++	static const struct rtnl_tab_entry init_tab[] = {
++		{  0, "none"     },
++		{  1, "redirect" },
++		{  2, "kernel"   },
++		{  3, "boot"     },
++		{  4, "static"   },
++		{  8, "gated"    },
++		{  9, "ra"       },
++		{ 10, "mrt"      },
++		{ 11, "zebra"    },
++		{ 12, "bird"     }
+ 	};
+ 
+ 	if (rtnl_rtprot_tab)
+ 		return;
+ 	rtnl_rtprot_tab = xzalloc(sizeof(*rtnl_rtprot_tab));
++	rtnl_rtprot_tab->tab = xzalloc(sizeof(init_tab));
++	rtnl_rtprot_tab->length = sizeof(init_tab) / sizeof(init_tab[0]);
+ 	memcpy(rtnl_rtprot_tab->tab, init_tab, sizeof(init_tab));
+-	rtnl_tab_initialize("protos", rtnl_rtprot_tab->tab);
++	rtnl_tab_initialize("protos", rtnl_rtprot_tab);
+ }
+ 
+ #if 0 /* UNUSED */
+ const char* FAST_FUNC rtnl_rtprot_n2a(int id)
+ {
+-	if (id < 0 || id > RT_TABLE_MAX) {
+-		return itoa(id);
+-	}
++	size_t i;
+ 
+ 	rtnl_rtprot_initialize();
+ 
+-	if (rtnl_rtprot_tab->tab[id])
+-		return rtnl_rtprot_tab->tab[id];
++	for (i = 0; i < rtnl_rtprot_tab->length; i++)
++		if (rtnl_rtprot_tab->tab[i].id == id)
++			return rtnl_rtprot_tab->tab[i].name;
++
+ 	return itoa(id);
+ }
+ #endif
+@@ -126,27 +138,33 @@ static rtnl_tab_t *rtnl_rtscope_tab;
+ 
+ static void rtnl_rtscope_initialize(void)
+ {
++	static const struct rtnl_tab_entry init_tab[] = {
++		{   0, "global"  },
++		{ 200, "site"    },
++		{ 253, "link"    },
++		{ 254, "host"    },
++		{ 255, "nowhere" }
++	};
++
+ 	if (rtnl_rtscope_tab)
+ 		return;
+ 	rtnl_rtscope_tab = xzalloc(sizeof(*rtnl_rtscope_tab));
+-	rtnl_rtscope_tab->tab[0] = "global";
+-	rtnl_rtscope_tab->tab[255] = "nowhere";
+-	rtnl_rtscope_tab->tab[254] = "host";
+-	rtnl_rtscope_tab->tab[253] = "link";
+-	rtnl_rtscope_tab->tab[200] = "site";
+-	rtnl_tab_initialize("scopes", rtnl_rtscope_tab->tab);
++	rtnl_rtscope_tab->tab = xzalloc(sizeof(init_tab));
++	rtnl_rtscope_tab->length = sizeof(init_tab) / sizeof(init_tab[0]);
++	memcpy(rtnl_rtscope_tab->tab, init_tab, sizeof(init_tab));
++	rtnl_tab_initialize("scopes", rtnl_rtscope_tab);
+ }
+ 
+ const char* FAST_FUNC rtnl_rtscope_n2a(int id)
+ {
+-	if (id < 0 || id > RT_TABLE_MAX) {
+-		return itoa(id);
+-	}
++	size_t i;
+ 
+ 	rtnl_rtscope_initialize();
+ 
+-	if (rtnl_rtscope_tab->tab[id])
+-		return rtnl_rtscope_tab->tab[id];
++	for (i = 0; i < rtnl_rtscope_tab->length; i++)
++		if (rtnl_rtscope_tab->tab[i].id == id)
++			return rtnl_rtscope_tab->tab[i].name;
++
+ 	return itoa(id);
+ }
+ 
+@@ -161,10 +179,17 @@ static rtnl_tab_t *rtnl_rtrealm_tab;
+ 
+ static void rtnl_rtrealm_initialize(void)
+ {
+-	if (rtnl_rtrealm_tab) return;
++	static const struct rtnl_tab_entry init_tab[] = {
++		{ 0, "unknown" }
++	};
++
++	if (rtnl_rtrealm_tab)
++		return;
+ 	rtnl_rtrealm_tab = xzalloc(sizeof(*rtnl_rtrealm_tab));
+-	rtnl_rtrealm_tab->tab[0] = "unknown";
+-	rtnl_tab_initialize("realms", rtnl_rtrealm_tab->tab);
++	rtnl_rtrealm_tab->tab = xzalloc(sizeof(init_tab));
++	rtnl_rtrealm_tab->length = sizeof(init_tab) / sizeof(init_tab[0]);
++	memcpy(rtnl_rtrealm_tab->tab, init_tab, sizeof(init_tab));
++	rtnl_tab_initialize("realms", rtnl_rtrealm_tab);
+ }
+ 
+ int FAST_FUNC rtnl_rtrealm_a2n(uint32_t *id, char *arg)
+@@ -176,14 +201,14 @@ int FAST_FUNC rtnl_rtrealm_a2n(uint32_t
+ #if ENABLE_FEATURE_IP_RULE
+ const char* FAST_FUNC rtnl_rtrealm_n2a(int id)
+ {
+-	if (id < 0 || id > RT_TABLE_MAX) {
+-		return itoa(id);
+-	}
++	size_t i;
+ 
+ 	rtnl_rtrealm_initialize();
+ 
+-	if (rtnl_rtrealm_tab->tab[id])
+-		return rtnl_rtrealm_tab->tab[id];
++	for (i = 0; i < rtnl_rtrealm_tab->length; i++)
++		if (rtnl_rtrealm_tab->tab[i].id == id)
++			return rtnl_rtrealm_tab->tab[i].name;
++
+ 	return itoa(id);
+ }
+ #endif
+@@ -193,22 +218,29 @@ static rtnl_tab_t *rtnl_rtdsfield_tab;
+ 
+ static void rtnl_rtdsfield_initialize(void)
+ {
+-	if (rtnl_rtdsfield_tab) return;
++	static const struct rtnl_tab_entry init_tab[] = {
++		{ 0, "0" }
++	};
++
++	if (rtnl_rtdsfield_tab)
++		return;
+ 	rtnl_rtdsfield_tab = xzalloc(sizeof(*rtnl_rtdsfield_tab));
+-	rtnl_rtdsfield_tab->tab[0] = "0";
+-	rtnl_tab_initialize("dsfield", rtnl_rtdsfield_tab->tab);
++	rtnl_rtdsfield_tab->tab = xzalloc(sizeof(init_tab));
++	rtnl_rtdsfield_tab->length = sizeof(init_tab) / sizeof(init_tab[0]);
++	memcpy(rtnl_rtdsfield_tab->tab, init_tab, sizeof(init_tab));
++	rtnl_tab_initialize("dsfield", rtnl_rtdsfield_tab);
+ }
+ 
+ const char* FAST_FUNC rtnl_dsfield_n2a(int id)
+ {
+-	if (id < 0 || id > RT_TABLE_MAX) {
+-		return itoa(id);
+-	}
++	size_t i;
+ 
+ 	rtnl_rtdsfield_initialize();
+ 
+-	if (rtnl_rtdsfield_tab->tab[id])
+-		return rtnl_rtdsfield_tab->tab[id];
++	for (i = 0; i < rtnl_rtdsfield_tab->length; i++)
++		if (rtnl_rtdsfield_tab->tab[i].id == id)
++			return rtnl_rtdsfield_tab->tab[i].name;
++
+ 	return itoa(id);
+ }
+ 
+@@ -224,27 +256,33 @@ static rtnl_tab_t *rtnl_rttable_tab;
+ 
+ static void rtnl_rttable_initialize(void)
+ {
++	static const struct rtnl_tab_entry tab_init[] = {
++		{   0, "unspec"  },
++		{ 253, "default" },
++		{ 254, "main"    },
++		{ 255, "local"   }
++	};
++
+ 	if (rtnl_rttable_tab)
+ 		return;
+ 
+ 	rtnl_rttable_tab = xzalloc(sizeof(*rtnl_rttable_tab));
+-	rtnl_rttable_tab->tab[0] = "unspec";
+-	rtnl_rttable_tab->tab[255] = "local";
+-	rtnl_rttable_tab->tab[254] = "main";
+-	rtnl_rttable_tab->tab[253] = "default";
+-	rtnl_tab_initialize("tables", rtnl_rttable_tab->tab);
++	rtnl_rttable_tab->tab = xzalloc(sizeof(tab_init));
++	rtnl_rttable_tab->length = sizeof(tab_init) / sizeof(tab_init[0]);
++	memcpy(rtnl_rttable_tab->tab, tab_init, sizeof(tab_init));
++	rtnl_tab_initialize("tables", rtnl_rttable_tab);
+ }
+ 
+ const char* FAST_FUNC rtnl_rttable_n2a(int id)
+ {
+-	if (id < 0 || id > RT_TABLE_MAX) {
+-		return itoa(id);
+-	}
++	size_t i;
+ 
+ 	rtnl_rttable_initialize();
+ 
+-	if (rtnl_rttable_tab->tab[id])
+-		return rtnl_rttable_tab->tab[id];
++	for (i = 0; i < rtnl_rttable_tab->length; i++)
++		if (rtnl_rttable_tab->tab[i].id == id)
++			return rtnl_rttable_tab->tab[i].name;
++
+ 	return itoa(id);
+ }
+ 
diff --git a/package/utils/bzip2/Makefile b/package/utils/bzip2/Makefile
new file mode 100644
index 0000000000..958b3c88c4
--- /dev/null
+++ b/package/utils/bzip2/Makefile
@@ -0,0 +1,106 @@
+#
+# Copyright (C) 2007-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bzip2
+PKG_VERSION:=1.0.6
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.bzip.org/$(PKG_VERSION)
+PKG_MD5SUM:=00b516f4704d4a7cb50a1d97e6e8e15b
+PKG_MAINTAINER:=Steven Barth <cyrus@openwrt.org>
+
+PKG_LICENSE:=BZIP2
+PKG_LICENSE_FILES:=LICENSE
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/bzip2/Default
+  SUBMENU:=Compression
+  URL:=http://www.bzip.org/
+endef
+
+define Package/libbz2
+$(call Package/bzip2/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=
+  TITLE:=bzip2 library.
+endef
+
+define Package/libbz2/description
+	bzip2 is a freely available, patent free, high-quality
+	data compressor. This packages provides libbz2 library.
+endef
+
+define Package/bzip2
+$(call Package/bzip2/Default)
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libbz2
+  TITLE:=bzip2 is a compression utility.
+endef
+
+define Package/bzip2/description
+	bzip2 is a freely available, patent free, high-quality
+	data compressor. This package provides the binary.
+endef
+
+TARGET_CFLAGS += \
+	$(FPIC) \
+	$(TARGET_LDFLAGS)
+
+CONFIGURE_ARGS += --prefix=/usr
+
+MAKE_FLAGS += \
+	-f Makefile-libbz2_so \
+	CFLAGS="$(TARGET_CFLAGS)" \
+	all
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_BUILD_DIR)/bzlib.h $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/libbz2.so.$(PKG_VERSION) $(1)/usr/lib/
+	$(LN) libbz2.so.$(PKG_VERSION) $(1)/usr/lib/libbz2.so.1.0
+	$(LN) libbz2.so.$(PKG_VERSION) $(1)/usr/lib/libbz2.so
+endef
+
+define Package/libbz2/install
+	$(INSTALL_DIR) $(1)/usr/lib/
+	$(CP) $(PKG_BUILD_DIR)/libbz2.so.$(PKG_VERSION) $(1)/usr/lib/
+	$(LN) libbz2.so.$(PKG_VERSION) $(1)/usr/lib/libbz2.so.1.0
+endef
+
+define Package/bzip2/install
+	$(INSTALL_DIR) $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bzip2-shared $(1)/usr/bin/bzip2
+endef
+
+HOST_CFLAGS += \
+	$(FPIC) \
+	$(HOST_LDFLAGS)
+
+HOST_MAKE_FLAGS+= \
+	CFLAGS="$(HOST_CFLAGS)" \
+	all
+
+HOST_CONFIGURE_ARGS+= \
+	--prefix=$(STAGING_DIR)/host
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR)/host/bin/
+	$(MAKE) -C $(HOST_BUILD_DIR) PREFIX=$(STAGING_DIR)/host/ install
+endef
+
+$(eval $(call HostBuild))
+
+$(eval $(call BuildPackage,libbz2))
+$(eval $(call BuildPackage,bzip2))
diff --git a/package/utils/e2fsprogs/Makefile b/package/utils/e2fsprogs/Makefile
new file mode 100644
index 0000000000..cf84c260c7
--- /dev/null
+++ b/package/utils/e2fsprogs/Makefile
@@ -0,0 +1,259 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+# Copyright 2010 Vertical Communications
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=e2fsprogs
+PKG_VERSION:=1.43.3
+PKG_MD5SUM:=ce8ef1bbb0d4730f170167284fda156ac9d6bf18db2750eb94af619a81b19927
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/e2fsprogs
+
+PKG_BUILD_DEPENDS:=util-linux
+PKG_INSTALL:=1
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/e2fsprogs/Default
+  URL:=http://e2fsprogs.sourceforge.net/
+  SUBMENU:=Filesystem
+endef
+
+define Package/e2fsprogs
+$(call Package/e2fsprogs/Default)
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Ext2/3/4 filesystem utilities
+  DEPENDS:=+libuuid +libext2fs
+endef
+
+define Package/e2fsprogs/description
+ This package contains essential ext2 filesystem utilities which consists of
+ e2fsck, mke2fs and most of the other core ext2 filesystem utilities.
+endef
+
+define Package/libext2fs
+$(call Package/e2fsprogs/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+libuuid
+  TITLE:=ext2/3/4 filesystem library
+endef
+
+define Package/libext2fs/description
+ libext2fs is a library which can access ext2, ext3 and ext4 filesystems.
+endef
+
+define Package/tune2fs
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem tune utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/resize2fs
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem resize utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/badblocks
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem badblocks utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/dumpe2fs
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem information dumping utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/e2freefrag
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem free space fragmentation information utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/filefrag
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem file fragmentation report utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/debugfs
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem debugger
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/chattr
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem chattr utility
+  DEPENDS:= +e2fsprogs
+endef
+
+define Package/lsattr
+$(call Package/e2fsprogs)
+  TITLE:=Ext2 Filesystem lsattr utility
+  DEPENDS:= +e2fsprogs
+endef
+
+TARGET_CFLAGS += $(FPIC) -ffunction-sections -fdata-sections
+
+CONFIGURE_VARS += \
+	ac_cv_lib_pthread_sem_init=no
+
+CONFIGURE_ARGS += \
+	--disable-testio-debug \
+	--enable-elf-shlibs	\
+	--disable-libuuid	\
+	--enable-libblkid	\
+	--disable-uuidd		\
+	--disable-tls		\
+	--disable-nls		\
+	--disable-rpath
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+	$(CP) $(SCRIPT_DIR)/config.{guess,sub} $(PKG_BUILD_DIR)/config/
+endef
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/util \
+		BUILDCC="$(HOSTCC)" \
+		CFLAGS="" \
+		CPPFLAGS="" \
+		LDFLAGS="" \
+		V=$(if $(findstring c,$(OPENWRT_VERBOSE)),1,) \
+		subst
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		LDFLAGS=-Wl,--gc-sections \
+		BUILDCC="$(HOSTCC)" \
+		DESTDIR="$(PKG_INSTALL_DIR)" \
+		LIBBLKID="$(PKG_BUILD_DIR)/lib/libblkid.a -luuid" \
+		ELF_OTHER_LIBS="$(TARGET_LDFLAGS) -luuid" \
+		SYSLIBS="$(TARGET_LDFLAGS) -ldl -L$(PKG_BUILD_DIR)/lib/ -l:libcom_err.so.0.0" \
+		V=$(if $(findstring c,$(OPENWRT_VERBOSE)),1,) \
+		all
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_BUILD_DIR)/lib/ext2fs/ext2fs.pc $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_BUILD_DIR)/lib/et/com_err.pc $(1)/usr/lib/pkgconfig
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/lib/libext2fs.{so,a}* $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/lib/libcom_err.{so,a}* $(1)/usr/lib
+
+	$(INSTALL_DIR) $(1)/usr/include/ext2fs
+	$(CP) $(PKG_BUILD_DIR)/lib/ext2fs/*.h $(1)/usr/include/ext2fs
+	$(INSTALL_DIR) $(1)/usr/include/et
+	$(CP) $(PKG_BUILD_DIR)/lib/et/*.h $(1)/usr/include/et
+endef
+
+define Package/e2fsprogs/conffiles
+/etc/e2fsck.conf
+endef
+
+define Package/e2fsprogs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/e2fsck $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/mke2fs $(1)/usr/sbin/
+	$(LN) mke2fs $(1)/usr/sbin/mkfs.ext2
+	$(LN) mke2fs $(1)/usr/sbin/mkfs.ext3
+	$(LN) mke2fs $(1)/usr/sbin/mkfs.ext4
+	$(LN) e2fsck $(1)/usr/sbin/fsck.ext2
+	$(LN) e2fsck $(1)/usr/sbin/fsck.ext3
+	$(LN) e2fsck $(1)/usr/sbin/fsck.ext4
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libe2p.so.* $(1)/usr/lib/
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_DIR) $(1)/lib/functions/fsck
+	$(INSTALL_DATA) ./files/e2fsck.sh $(1)/lib/functions/fsck/
+	$(INSTALL_DATA) ./files/e2fsck.conf $(1)/etc/e2fsck.conf
+endef
+
+define Package/libcom_err/install
+endef
+
+define Package/libext2fs/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libext2fs.so.* \
+		$(PKG_INSTALL_DIR)/usr/lib/libcom_err.so.* \
+		$(1)/usr/lib/
+endef
+
+define Package/libext2fs/install_lib
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_BUILD_DIR)/lib/ext2fs/libext2fs.a $(1)/usr/lib/libext2fs_pic.a
+endef
+
+define Package/tune2fs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/tune2fs $(1)/usr/sbin/
+	$(LN) tune2fs $(1)/usr/sbin/findfs
+endef
+
+define Package/resize2fs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/resize2fs $(1)/usr/sbin/
+endef
+
+define Package/badblocks/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/badblocks $(1)/usr/sbin/
+endef
+
+define Package/dumpe2fs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/dumpe2fs $(1)/usr/sbin/
+endef
+
+define Package/e2freefrag/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/e2freefrag $(1)/usr/sbin/
+endef
+
+define Package/filefrag/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/filefrag $(1)/usr/sbin/
+endef
+
+define Package/debugfs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/debugfs $(1)/usr/sbin/
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libss.so.* $(1)/usr/lib/
+endef
+
+define Package/chattr/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/chattr $(1)/usr/bin/
+endef
+
+define Package/lsattr/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/lsattr $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,e2fsprogs))
+$(eval $(call BuildPackage,libext2fs))
+$(eval $(call BuildPackage,tune2fs))
+$(eval $(call BuildPackage,resize2fs))
+$(eval $(call BuildPackage,badblocks))
+$(eval $(call BuildPackage,dumpe2fs))
+$(eval $(call BuildPackage,e2freefrag))
+$(eval $(call BuildPackage,filefrag))
+$(eval $(call BuildPackage,debugfs))
+$(eval $(call BuildPackage,chattr))
+$(eval $(call BuildPackage,lsattr))
diff --git a/package/utils/e2fsprogs/files/e2fsck.conf b/package/utils/e2fsprogs/files/e2fsck.conf
new file mode 100644
index 0000000000..9c96b49585
--- /dev/null
+++ b/package/utils/e2fsprogs/files/e2fsck.conf
@@ -0,0 +1,3 @@
+[options]
+broken_system_clock = true
+
diff --git a/package/utils/e2fsprogs/files/e2fsck.sh b/package/utils/e2fsprogs/files/e2fsck.sh
new file mode 100644
index 0000000000..22031edb67
--- /dev/null
+++ b/package/utils/e2fsprogs/files/e2fsck.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright 2010 Vertical Communications
+# Copyright 2012 OpenWrt.org
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+fsck_e2fsck() {
+	set -o pipefail
+	e2fsck -p "$device" 2>&1 | logger -t "fstab: e2fsck ($device)"
+	local status="$?"
+	set +o pipefail
+	case "$status" in
+		0|1) ;; #success
+		2) reboot;;
+		4) echo "e2fsck ($device): Warning! Uncorrected errors."| logger -t fstab
+			return 1
+			;;
+		*) echo "e2fsck ($device): Error $status. Check not complete."| logger -t fstab;;
+	esac
+	return 0
+}
+
+fsck_ext2() {
+	fsck_e2fsck "$@"
+}
+
+fsck_ext3() {
+	fsck_e2fsck "$@"
+}
+
+fsck_ext4() {
+	fsck_e2fsck "$@"
+}
+
+append libmount_known_fsck "ext2"
+append libmount_known_fsck "ext3"
+append libmount_known_fsck "ext4"
diff --git a/package/utils/e2fsprogs/patches/001-com_err_version.patch b/package/utils/e2fsprogs/patches/001-com_err_version.patch
new file mode 100644
index 0000000000..62f1e08e71
--- /dev/null
+++ b/package/utils/e2fsprogs/patches/001-com_err_version.patch
@@ -0,0 +1,13 @@
+--- a/lib/et/Makefile.in
++++ b/lib/et/Makefile.in
+@@ -25,8 +25,8 @@ SHARE_FILES= et_c.awk et_h.awk
+ LIBRARY= libcom_err
+ LIBDIR= et
+ 
+-ELF_VERSION = 2.1
+-ELF_SO_VERSION = 2
++ELF_VERSION = 0.0
++ELF_SO_VERSION = 0
+ ELF_IMAGE = libcom_err
+ ELF_MYDIR = et
+ ELF_INSTALL_DIR = $(root_libdir)
diff --git a/package/utils/e2fsprogs/patches/002-fix-subst-host-build.patch b/package/utils/e2fsprogs/patches/002-fix-subst-host-build.patch
new file mode 100644
index 0000000000..c92e2280e9
--- /dev/null
+++ b/package/utils/e2fsprogs/patches/002-fix-subst-host-build.patch
@@ -0,0 +1,10 @@
+--- a/util/subst.c
++++ b/util/subst.c
+@@ -9,6 +9,7 @@
+ #include "config.h"
+ #else
+ #define HAVE_SYS_TIME_H
++#define HAVE_SYS_STAT_H
+ #endif
+ #include <stdio.h>
+ #include <errno.h>
diff --git a/package/utils/f2fs-tools/Makefile b/package/utils/f2fs-tools/Makefile
new file mode 100644
index 0000000000..8414052339
--- /dev/null
+++ b/package/utils/f2fs-tools/Makefile
@@ -0,0 +1,90 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=f2fs-tools
+PKG_VERSION:=1.7.0
+PKG_RELEASE:=1
+
+PKG_LICENSE:=GPLv2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://git.kernel.org/cgit/linux/kernel/git/jaegeuk/f2fs-tools.git/snapshot/
+PKG_MD5SUM:=9db22274264f0c88dbee012f257917b1
+
+PKG_FIXUP:=autoreconf
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/f2fs-tools/Default
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Filesystem
+  DEPENDS:=+libf2fs
+  URL:=http://git.kernel.org/cgit/linux/kernel/git/jaegeuk/f2fs-tools.git
+endef
+
+define Package/mkf2fs
+  $(Package/f2fs-tools/Default)
+  TITLE:=Utility for creating a Flash-Friendly File System (F2FS)
+endef
+
+define Package/f2fsck
+  $(Package/f2fs-tools/Default)
+  TITLE:=Utility for checking/repairing a Flash-Friendly File System (F2FS)
+endef
+
+define Package/f2fs-tools
+  $(Package/f2fs-tools/Default)
+  TITLE:=Tools for Flash-Friendly File System (F2FS)
+  DEPENDS += +mkf2fs +f2fsck
+endef
+
+define Package/libf2fs
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Library for Flash-Friendly File System (F2FS) tools
+  DEPENDS:=+libuuid
+endef
+
+define Package/libf2fs/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) \
+		$(PKG_INSTALL_DIR)/usr/lib/libf2fs.so* $(1)/usr/lib/
+endef
+
+define Package/mkf2fs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/mkfs.f2fs $(1)/usr/sbin
+endef
+
+define Package/f2fsck/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/fsck.f2fs $(1)/usr/sbin
+	ln -s /usr/sbin/fsck.f2fs $(1)/usr/sbin/defrag.f2fs
+	ln -s /usr/sbin/fsck.f2fs $(1)/usr/sbin/dump.f2fs
+	ln -s /usr/sbin/fsck.f2fs $(1)/usr/sbin/sload.f2fs
+	ln -s /usr/sbin/fsck.f2fs $(1)/usr/sbin/resize.f2fs
+endef
+
+define Package/f2fs-tools/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/f2fstat $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/fibmap.f2fs $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/parse.f2fs $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,libf2fs))
+$(eval $(call BuildPackage,mkf2fs))
+$(eval $(call BuildPackage,f2fsck))
+$(eval $(call BuildPackage,f2fs-tools))
diff --git a/package/utils/f2fs-tools/patches/001-compile.patch b/package/utils/f2fs-tools/patches/001-compile.patch
new file mode 100644
index 0000000000..2ff6ee832d
--- /dev/null
+++ b/package/utils/f2fs-tools/patches/001-compile.patch
@@ -0,0 +1,19 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -20,14 +20,9 @@ AC_DEFINE([F2FS_MINOR_VERSION], m4_bpats
+ 				[\([0-9]*\).\([0-9]*\)\(\w\|\W\)*], [\2]),
+ 				[Minor version for f2fs-tools])
+ 
+-AC_CHECK_FILE(.git,
+-	AC_DEFINE([F2FS_TOOLS_DATE],
+-		"m4_bpatsubst(f2fs_tools_gitdate,
+-		[\([0-9-]*\)\(\w\|\W\)*], [\1])",
+-		[f2fs-tools date based on Git commits]),
+-	AC_DEFINE([F2FS_TOOLS_DATE],
++AC_DEFINE([F2FS_TOOLS_DATE],
+ 		"f2fs_tools_date",
+-		[f2fs-tools date based on Source releases]))
++		[f2fs-tools date based on Source releases])
+ 
+ AC_CONFIG_SRCDIR([config.h.in])
+ AC_CONFIG_HEADER([config.h])
diff --git a/package/utils/f2fs-tools/patches/010-include-byteswap-h.patch b/package/utils/f2fs-tools/patches/010-include-byteswap-h.patch
new file mode 100644
index 0000000000..ff7e4e7d3e
--- /dev/null
+++ b/package/utils/f2fs-tools/patches/010-include-byteswap-h.patch
@@ -0,0 +1,10 @@
+--- a/include/f2fs_fs.h
++++ b/include/f2fs_fs.h
+@@ -15,6 +15,7 @@
+ #include <inttypes.h>
+ #include <linux/types.h>
+ #include <sys/types.h>
++#include <byteswap.h>
+ 
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
diff --git a/package/utils/f2fs-tools/patches/020-no_selinux.patch b/package/utils/f2fs-tools/patches/020-no_selinux.patch
new file mode 100644
index 0000000000..dcb3bd24c4
--- /dev/null
+++ b/package/utils/f2fs-tools/patches/020-no_selinux.patch
@@ -0,0 +1,55 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -49,7 +49,7 @@ AC_PATH_PROG([LDCONFIG], [ldconfig],
+ 
+ # Checks for libraries.
+ PKG_CHECK_MODULES([libuuid], [uuid])
+-PKG_CHECK_MODULES([libselinux], [libselinux])
++# PKG_CHECK_MODULES([libselinux], [libselinux])
+ 
+ # Checks for header files.
+ AC_CHECK_HEADERS([linux/fs.h fcntl.h mntent.h stdlib.h string.h \
+--- a/fsck/sload.c
++++ b/fsck/sload.c
+@@ -16,10 +16,11 @@
+ #include <libgen.h>
+ #include <dirent.h>
+ #include <mntent.h>
++
++#ifdef WITH_ANDROID
+ #include <selinux/selinux.h>
+ #include <selinux/label.h>
+ 
+-#ifdef WITH_ANDROID
+ #include <selinux/label.h>
+ #include <private/android_filesystem_config.h>
+ 
+@@ -110,10 +111,12 @@ static int build_directory(struct f2fs_s
+ 		handle_selabel(dentries + i, S_ISDIR(stat.st_mode),
+ 							target_out_dir);
+ 
++#ifdef WITH_ANDROID
+ 		if (sehnd && selabel_lookup(sehnd, &dentries[i].secon,
+ 					dentries[i].path, stat.st_mode) < 0)
+ 			ERR_MSG("Cannot lookup security context for %s\n",
+ 						dentries[i].path);
++#endif
+ 
+ 		dentries[i].pino = dir_ino;
+ 
+@@ -218,6 +221,7 @@ int f2fs_sload(struct f2fs_sb_info *sbi,
+ 		return ret;
+ 	}
+ 
++#ifdef WITH_ANDROID
+ 	if (sehnd) {
+ 		char *secontext = NULL;
+ 
+@@ -233,6 +237,7 @@ int f2fs_sload(struct f2fs_sb_info *sbi,
+ 		}
+ 		free(secontext);
+ 	}
++#endif
+ 
+ 	/* update curseg info; can update sit->types */
+ 	move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
diff --git a/package/utils/fbtest/Makefile b/package/utils/fbtest/Makefile
new file mode 100644
index 0000000000..464b34f9f2
--- /dev/null
+++ b/package/utils/fbtest/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fbtest
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/fbtest
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Frame buffer device testing tool
+  DEPENDS:=@DISPLAY_SUPPORT
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall" \
+		LDFLAGS="$(TARGET_LDFLAGS)"
+endef
+
+define Package/fbtest/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/fbtest $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,fbtest))
diff --git a/package/utils/fbtest/src/Makefile b/package/utils/fbtest/src/Makefile
new file mode 100644
index 0000000000..075bc0ecbf
--- /dev/null
+++ b/package/utils/fbtest/src/Makefile
@@ -0,0 +1,14 @@
+CC = gcc
+CFLAGS = -Wall
+OBJS = fbtest.o
+
+all: fbtest
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+fbtest: $(OBJS)
+	$(CC) -o $@ $(OBJS)
+
+clean:
+	rm -f rbcfg *.o
diff --git a/package/utils/fbtest/src/fbtest.c b/package/utils/fbtest/src/fbtest.c
new file mode 100644
index 0000000000..021b80303c
--- /dev/null
+++ b/package/utils/fbtest/src/fbtest.c
@@ -0,0 +1,446 @@
+/******************************************************************************
+ *	fbtest - fbtest.c
+ *	test program for the tuxbox-framebuffer device
+ *	tests all GTX/eNX supported modes
+ *                                                                            
+ *	(c) 2003 Carsten Juttner (carjay@gmx.net)
+ *
+ * 	This program is free software; you can redistribute it and/or modify
+ * 	it under the terms of the GNU General Public License as published by
+ * 	The Free Software Foundation; either version 2 of the License, or
+ * 	(at your option) any later version.
+ *
+ * 	This program is distributed in the hope that it will be useful,
+ * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 	GNU General Public License for more details.
+ *
+ * 	You should have received a copy of the GNU General Public License
+ * 	along with this program; if not, write to the Free Software
+ * 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  									      
+ ******************************************************************************
+ * $Id: fbtest.c,v 1.5 2005/01/14 23:14:41 carjay Exp $
+ ******************************************************************************/
+
+// TODO: - should restore the colour map and mode to what it was before
+//	 - is colour map handled correctly?
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include <linux/fb.h>
+
+#define FBDEV "/dev/fb0"
+
+struct vidsize{
+	int width;
+	int height;
+};
+static
+const struct vidsize vidsizetable[]={	// all supported sizes
+	{720,576},{720,480},{720,288},{720,240},
+	{640,576},{640,480},{640,288},{640,240},
+	{360,576},{360,480},{360,288},{360,240},
+	{320,576},{320,480},{320,288},{320,240}
+};
+#define VIDSIZENUM (sizeof(vidsizetable)/sizeof(struct vidsize))
+
+enum pixenum{	// keep in sync with pixname !
+	CLUT4=0,
+	CLUT8,
+	RGB565,
+	ARGB1555,
+	ARGB
+};
+const char *pixname[] = {
+	"CLUT4",
+	"CLUT8",
+	"RGB565",
+	"ARGB1555",
+	"ARGB"
+};
+
+struct pixelformat{
+	char *name;
+	struct fb_bitfield red;
+	struct fb_bitfield green;
+	struct fb_bitfield blue;
+	struct fb_bitfield transp;
+	char bpp;
+	char pixenum;
+};
+
+static		// so far these are all modes supported by the eNX (only partially by GTX)
+const struct pixelformat pixelformattable[] = {
+	{ .name = "CLUT4 ARGB8888", 	// CLUT4 (ARGB8888)
+		.bpp = 4, .pixenum = CLUT4,
+		.red = 	 { .offset = 0, .length=8, .msb_right =0 },
+		.green = { .offset = 0, .length=8, .msb_right =0 },
+		.blue =  { .offset = 0, .length=8, .msb_right =0 },
+		.transp=  { .offset = 0, .length=8, .msb_right =0 }
+	},
+	{ .name = "CLUT4 ARGB1555", 	// CLUT4 (ARGB1555)
+		.bpp = 4, .pixenum = CLUT4,
+		.red = 	 { .offset = 0, .length=5, .msb_right =0 },
+		.green = { .offset = 0, .length=5, .msb_right =0 },
+		.blue =  { .offset = 0, .length=5, .msb_right =0 },
+		.transp=  { .offset = 0, .length=1, .msb_right =0 }
+	},
+	{ .name = "CLUT8 ARGB8888",	// CLUT8 (ARGB8888)
+		.bpp = 8, .pixenum = CLUT8,
+		.red = 	 { .offset = 0, .length=8, .msb_right =0 },
+		.green = { .offset = 0, .length=8, .msb_right =0 },
+		.blue =  { .offset = 0, .length=8, .msb_right =0 },
+		.transp=  { .offset = 0, .length=8, .msb_right =0 }
+	},
+	{ .name = "CLUT8 ARGB1555",	// CLUT8 (ARGB1555)
+		.bpp = 8, .pixenum = CLUT8,
+		.red = 	 { .offset = 0, .length=5, .msb_right =0 },
+		.green = { .offset = 0, .length=5, .msb_right =0 },
+		.blue =  { .offset = 0, .length=5, .msb_right =0 },
+		.transp=  { .offset = 0, .length=1, .msb_right =0 }
+	},
+	{ .name = "ARGB1555", 	// ARGB1555
+		.bpp = 16, .pixenum = ARGB1555,
+		.red = 	 { .offset = 10, .length=5, .msb_right =0 },
+		.green = { .offset = 5,  .length=5, .msb_right =0 },
+		.blue =  { .offset = 0,  .length=5, .msb_right =0 },
+		.transp=  { .offset = 15, .length=1, .msb_right =0 }
+	},
+	{ .name = "RGB565", 		// RGB565
+		.bpp = 16, .pixenum = RGB565,
+		.red = 	 { .offset = 11, .length=5, .msb_right =0 },
+		.green = { .offset = 5,  .length=6, .msb_right =0 },
+		.blue =  { .offset = 0,  .length=5, .msb_right =0 },
+		.transp=  { .offset = 0,  .length=0, .msb_right =0 }
+	},
+	{ .name = "ARGB",	// 32 f*cking bits, the real McCoy :)
+		.bpp = 32, .pixenum = ARGB,
+		.red = 	 { .offset = 16, .length=8, .msb_right =0 },
+		.green = { .offset = 8,  .length=8, .msb_right =0 },
+		.blue =  { .offset = 0,  .length=8, .msb_right =0 },
+		.transp=  { .offset = 24, .length=8, .msb_right =0 }
+	}
+};
+#define PIXELFORMATNUM (sizeof(pixelformattable)/sizeof(struct pixelformat))
+
+struct colour {
+	__u16 r;
+	__u16 g;
+	__u16 b;
+	__u16 a;
+};
+static
+struct colour colourtable[] = {
+	{.r =0xffff, .g = 0xffff, .b=0xffff, .a=0xffff},	// fully transparent white
+	{.r =0xffff, .g = 0x0000, .b=0x0000, .a=0x0000},	// red
+	{.r =0x0000, .g = 0xffff, .b=0x0000, .a=0x0000},	// green
+	{.r =0x0000, .g = 0x0000, .b=0xffff, .a=0x0000},	// blue
+	{.r =0x0000, .g = 0x0000, .b=0x0000, .a=0x0000}		// black
+};
+#define COLOURNUM (sizeof(colourtable)/sizeof(struct colour))
+
+struct rect{
+	int x;
+	int y;
+	int width;
+	int height;
+	const struct colour *col;
+};
+struct pixel{		// up to 32 bits of pixel information
+	char byte[4];
+};
+
+void col2pixel (struct pixel *pix, const struct pixelformat *pixf, const struct colour *col){
+	switch (pixf->pixenum){
+		case RGB565:
+			pix->byte[0]=(col->r&0xf8)|(col->g&0xfc)>>5;
+			pix->byte[1]=(col->g&0xfc)<<3|(col->b&0xf8)>>3;
+			break;
+		case ARGB1555:
+			pix->byte[0]=(col->a&0x80)|(col->r&0xf8)>>1|(col->g&0xf8)>>6;
+			pix->byte[1]=(col->g&0xf8)<<2|(col->b&0xf8)>>3;
+			break;
+		case ARGB:
+			pix->byte[0]=col->a;
+			pix->byte[1]=col->r;
+			pix->byte[2]=col->g;
+			pix->byte[3]=col->b;
+			break;
+		default:
+			printf ("unknown pixelformat\n");
+			exit(1);
+	}
+}
+
+int setmode(int fbd, const struct pixelformat *pixf,const struct vidsize *vids){
+	struct fb_var_screeninfo var;
+	int stat;
+	stat = ioctl (fbd, FBIOGET_VSCREENINFO,&var);
+	if (stat<0) return -2;
+	
+	var.xres= vids->width;
+	var.xres_virtual = vids->width;
+	var.yres= vids->height;
+	var.yres_virtual = vids->height;
+	
+	var.bits_per_pixel = pixf->bpp;
+	var.red = pixf->red;
+	var.green = pixf->green;
+	var.blue = pixf->blue;
+	var.transp = pixf->transp;
+
+	stat = ioctl (fbd, FBIOPUT_VSCREENINFO,&var);
+	if (stat<0) return -1;
+	return 0;
+}
+
+// unefficient implementation, do NOT use it for your next ego shooter, please :)
+// for 4-Bit only rectangles with even width are supported
+// CLUT-modes use value of red component as index
+void drawrect(void *videoram, struct rect *r, const struct pixelformat *pixf, const struct vidsize *vids){
+	int x,y,corwidth, bpp = 0, tocopy = 1;
+	struct pixel pix;
+	unsigned char *pmem = videoram;
+	corwidth = r->width;	// actually only "corrected" for 4 Bit
+
+	if (pixf->pixenum!=CLUT4&&pixf->pixenum!=CLUT8){
+		switch (pixf->pixenum){
+			case ARGB1555:
+			case RGB565:
+				bpp = 16;
+				tocopy = 2;
+				break;
+			case ARGB:
+				bpp = 32;
+				tocopy = 4;
+				break;
+			default:
+				printf ("drawrect: unknown pixelformat(%d) bpp:%d\n",pixf->pixenum,pixf->bpp);
+				exit(1);
+		}
+		col2pixel(&pix,pixf,r->col);
+	} else {
+		switch (pixf->pixenum){	// CLUT = Colour LookUp Table (palette)
+			case CLUT4:	// take red value as index in this case
+				pix.byte[0]=(r->col->r)<<4|(r->col->r&0xf);	// slightly cryptic... "rect->colour->red"
+				corwidth>>=1;	// we copy bytes
+				bpp=4;
+				tocopy=1;
+				break;
+			case CLUT8:
+				pix.byte[0]=(r->col->r&0xff);
+				bpp=8;
+				tocopy=1;
+				break;
+		}
+	}
+	pmem=videoram+((((r->y*vids->width)+r->x)*bpp)>>3);
+	for (y=0;y<r->height;y++){
+		int offset = 0;
+		for (x=0;x<corwidth;x++){
+			memcpy (pmem+offset,pix.byte,tocopy);
+			offset+=tocopy;
+		}
+		pmem +=((vids->width*bpp)>>3);	// skip one whole line, actually should be taken from "fix-info"
+	}
+}
+			
+// create quick little test image, 4 colours from table
+void draw4field(void *videoram, const struct pixelformat *pixf, const struct vidsize *vids){
+	struct rect r;
+	struct colour c;
+	int height, width;
+	c.r = 1;	// only used for the indexed modes, r is taken as index
+	height = vids->height;
+	width = vids->width;
+
+	r.height = height>>1;
+	r.width = width>>1;
+	r.x = 0;	r.y = 0;
+	if (pixf->pixenum==CLUT4||pixf->pixenum==CLUT8) r.col = &c;
+	else r.col = &colourtable[1];
+	drawrect (videoram, &r, pixf, vids);
+
+	r.x = width/2;	r.y = 0;
+	if (pixf->pixenum==CLUT4||pixf->pixenum==CLUT8) c.r = 2;
+	else r.col = &colourtable[2];
+	drawrect (videoram, &r, pixf, vids);
+
+	r.x = 0;	r.y = height/2;
+	if (pixf->pixenum==CLUT4||pixf->pixenum==CLUT8) c.r = 3;
+	else r.col = &colourtable[3];
+	drawrect (videoram, &r, pixf, vids);
+
+	r.x = width/2;	r.y = height/2;
+	if (pixf->pixenum==CLUT4||pixf->pixenum==CLUT8) c.r = 0;
+	else r.col = &colourtable[0];
+	drawrect (videoram, &r, pixf, vids);
+}
+
+void usage(char *name){
+ 	printf ("Usage: %s [options]\n"
+		"Options: -f<pixelformat>\n"
+		"            where format is one of:\n"
+		"              CLUT4,CLUT8,ARGB1555,RGB565,ARGB\n"
+		"         -s<width>x<heigth>\n"
+		"            where width is either 720,640,360,320\n"
+		"                  and height is either 288,240,480,576\n"
+		"         -n\n"
+		"            disables clearing the framebuffer after drawing\n"
+		"            the testimage. This can be useful to keep the last\n"
+		"            drawn image onscreen.\n"
+		"\nExample: %s -fRGB322\n",name,name);
+	exit(0);
+}
+
+int main (int argc,char **argv){
+	struct fb_fix_screeninfo fix;
+	struct fb_var_screeninfo var;
+	struct fb_cmap cmap;
+	struct rect r;
+	int fbd;
+	unsigned char *pfb;
+	int stat;
+	int optchar,fmode=-1,smode=-1,clear=1;
+	int i_cmap,i_size,i_pix;
+	extern char *optarg;
+	
+	if (argc!=0&&argc>4) usage(argv[0]);
+	while ( (optchar = getopt (argc,argv,"f:s:n"))!= -1){
+		int i,height,width;
+		switch (optchar){
+			case 'f':
+				for (i=0;i<(sizeof(pixname)/sizeof(char*));i++){
+					if (!strncmp (optarg,pixname[i],strlen(pixname[i]))){
+						fmode=i;
+						printf ("displaying only %s-modes\n",pixname[i]);
+						break;
+					}
+				}
+				if (fmode==-1){
+					printf ("unknown pixelformat\n");
+					exit(0);
+				}
+				break;
+			case 's':
+				if (sscanf (optarg,"%dx%d",&width,&height)!=2){
+					printf ("parsing size failed\n");
+					exit(0);
+				} else {
+					printf ("requested size %dx%d\n",width,height);
+					for (i=0;i<VIDSIZENUM;i++){
+						if (vidsizetable[i].width == width &&
+							vidsizetable[i].height == height){
+							smode = i;
+							break;
+						}
+					}
+					if (smode==-1){
+						printf ("this size is not supported\n");
+						exit(0);
+					}
+				}
+				break;
+			case 'n':
+				clear = 0;
+				printf ("clearing framebuffer after drawing is disabled\n");
+				break;
+			case '?':
+				usage (argv[0]);
+		}
+	}
+	
+	fbd = open (FBDEV, O_RDWR);
+	if (fbd<0){
+		perror ("Error opening framebuffer device");
+		return 1;
+	}
+	stat = ioctl (fbd, FBIOGET_FSCREENINFO,&fix);
+	if (stat<0){
+		perror ("Error getting fix screeninfo");
+		return 1;
+	}
+	stat = ioctl (fbd, FBIOGET_VSCREENINFO,&var);
+	if (stat<0){
+		perror ("Error getting var screeninfo");
+		return 1;
+	}
+	stat = ioctl (fbd, FBIOPUT_VSCREENINFO,&var);
+	if (stat<0){
+		perror ("Error setting mode");
+		return 1;
+	}
+	pfb = mmap (0, fix.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fbd, 0);
+	if (pfb == MAP_FAILED){
+		perror ("Error mmap'ing framebuffer device");
+		return 1;
+	}
+
+	// iterate over all modes
+	for (i_pix=0;i_pix<PIXELFORMATNUM;i_pix++){
+		if (fmode!=-1 && pixelformattable[i_pix].pixenum != fmode) continue;
+		printf ("testing: %s",pixelformattable[i_pix].name);
+		printf (" for sizes: \n");
+		for (i_size=0;i_size<VIDSIZENUM;i_size++){
+			if (smode!=-1 && i_size!=smode) continue;
+			printf ("%dx%d ",vidsizetable[i_size].width,vidsizetable[i_size].height);
+			fflush(stdout);
+			if ((i_size%4)==3) printf ("\n");
+			
+			// try to set mode
+			stat = setmode(fbd,&pixelformattable[i_pix],&vidsizetable[i_size]);
+			if (stat==-2) perror ("fbtest: could not get fb_var-screeninfo from fb-device");
+			else if (stat==-1){
+				printf ("\nCould not set mode %s (%dx%d), possible reasons:\n"
+					"- you have a GTX (soz m8)\n"
+					"- your configuration does not have enough graphics RAM\n"
+					"- you found a bug\n"
+					"choose your poison accordingly...\n",
+					pixelformattable[i_pix].name,vidsizetable[i_size].width,vidsizetable[i_size].height);
+					continue;
+			}
+			// fill cmap;
+			cmap.len = 1;
+			if ((pixelformattable[i_pix].bpp==4)||
+				((pixelformattable[i_pix].bpp==8)&&(pixelformattable[i_pix].red.length!=3))){
+				for (i_cmap=0;i_cmap<COLOURNUM;i_cmap++){
+					cmap.start=i_cmap;
+					cmap.red=&colourtable[i_cmap].r;
+					cmap.green=&colourtable[i_cmap].g;
+					cmap.blue=&colourtable[i_cmap].b;
+					cmap.transp=&colourtable[i_cmap].a;
+					stat = ioctl (fbd, FBIOPUTCMAP, &cmap);
+					if (stat<0) printf ("setting colourmap failed\n");
+				}
+			}
+			// create the test image
+			draw4field(pfb,&pixelformattable[i_pix],&vidsizetable[i_size]);
+			usleep (500000);
+			// clear screen
+			if (clear){
+				r.x=r.y=0;r.width = vidsizetable[i_size].width; r.height = vidsizetable[i_size].height;
+				r.col = &colourtable[4];
+				drawrect(pfb,&r,&pixelformattable[i_pix],&vidsizetable[i_size]);
+			}
+		}
+		printf ("\n");
+	}
+
+	stat = munmap (pfb,fix.smem_len);
+	if (stat<0){
+		perror ("Error munmap'ing framebuffer device");
+		return 1;
+	}
+	close (fbd);
+	return 0;
+}
diff --git a/package/utils/fuse/Makefile b/package/utils/fuse/Makefile
new file mode 100644
index 0000000000..19eba3c18d
--- /dev/null
+++ b/package/utils/fuse/Makefile
@@ -0,0 +1,101 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=fuse
+PKG_VERSION:=2.9.7
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/libfuse/libfuse/releases/download/$(PKG_NAME)-$(PKG_VERSION)
+PKG_MD5SUM:=9bd4ce8184745fd3d000ca2692adacdb
+
+PKG_LICENSE:=LGPLv2.1 GPLv2
+PKG_LICENSE_FILES:=COPYING.LIB COPYING
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/fuse/Default
+  TITLE:=FUSE
+  URL:=http://fuse.sourceforge.net/
+endef
+
+define Package/fuse/Default/description
+ FUSE (Filesystem in UserSpacE)
+endef
+
+define Package/fuse-utils
+$(call Package/fuse/Default)
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libfuse
+  TITLE+= (utilities)
+  SUBMENU:=Filesystem
+endef
+
+define Package/fuse-utils/description
+$(call Package/fuse/Default/description)
+ This package contains the FUSE utilities.
+ - fusermount
+ - ulockmgr_server
+endef
+
+define Package/libfuse
+$(call Package/fuse/Default)
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= (library)
+  DEPENDS:=+kmod-fuse +libpthread
+  SUBMENU:=Filesystem
+endef
+
+define Package/libfuse/description
+$(call Package/fuse/Default/description)
+ This package contains the FUSE shared libraries, needed by other programs.
+ - libfuse
+ - libulockmgr
+endef
+
+# generic args
+CONFIGURE_ARGS += \
+	--enable-shared \
+	--enable-static \
+	--enable-lib \
+	--enable-util \
+	--disable-rpath \
+	--disable-example \
+	--disable-mtab
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP)	$(PKG_INSTALL_DIR)/usr/include/{fuse,fuse.h,ulockmgr.h} $(1)/usr/include/
+	$(INSTALL_DIR)  $(1)/usr/lib
+	$(CP)	$(PKG_INSTALL_DIR)/usr/lib/lib{fuse,ulockmgr}.{a,so*} $(1)/usr/lib/
+	$(INSTALL_DIR)  $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/fuse.pc $(1)/usr/lib/pkgconfig/
+	$(SED) 's,-I$$$${includedir}/fuse,,g' $(1)/usr/lib/pkgconfig/fuse.pc
+	$(SED) 's,-L$$$${libdir},,g' $(1)/usr/lib/pkgconfig/fuse.pc
+endef
+
+define Package/fuse-utils/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(CP) $(PKG_INSTALL_DIR)/sbin/mount.fuse $(1)/sbin/
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(CP) $(PKG_INSTALL_DIR)/usr/bin/{fusermount,ulockmgr_server} $(1)/usr/bin/
+endef
+
+define Package/libfuse/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/lib{fuse,ulockmgr}.so.* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,fuse-utils))
+$(eval $(call BuildPackage,libfuse))
diff --git a/package/utils/fuse/patches/100-missing_includes.patch b/package/utils/fuse/patches/100-missing_includes.patch
new file mode 100644
index 0000000000..e74a1870f0
--- /dev/null
+++ b/package/utils/fuse/patches/100-missing_includes.patch
@@ -0,0 +1,10 @@
+--- a/include/fuse.h
++++ b/include/fuse.h
+@@ -32,6 +32,7 @@
+ #include <sys/stat.h>
+ #include <sys/statvfs.h>
+ #include <sys/uio.h>
++#include <sys/file.h>
+ 
+ #ifdef __cplusplus
+ extern "C" {
diff --git a/package/utils/fuse/patches/112-no_break_on_mknod.patch b/package/utils/fuse/patches/112-no_break_on_mknod.patch
new file mode 100644
index 0000000000..f679c4116d
--- /dev/null
+++ b/package/utils/fuse/patches/112-no_break_on_mknod.patch
@@ -0,0 +1,11 @@
+--- a/util/Makefile.in
++++ b/util/Makefile.in
+@@ -723,7 +723,7 @@ mount_util.c: $(top_srcdir)/lib/mount_ut
+ 
+ install-exec-hook:
+ 	-chmod u+s $(DESTDIR)$(bindir)/fusermount
+-	@if test ! -e $(DESTDIR)/dev/fuse; then \
++	-@if test ! -e $(DESTDIR)/dev/fuse; then \
+ 		$(MKDIR_P) $(DESTDIR)/dev; \
+ 		echo "mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true"; \
+ 		mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true; \
diff --git a/package/utils/fuse/patches/200-backport_arm64_fuse_kernel_h_clean_includes.patch b/package/utils/fuse/patches/200-backport_arm64_fuse_kernel_h_clean_includes.patch
new file mode 100644
index 0000000000..d45da84cca
--- /dev/null
+++ b/package/utils/fuse/patches/200-backport_arm64_fuse_kernel_h_clean_includes.patch
@@ -0,0 +1,30 @@
+From 914871b20a901e3e1e981c92bc42b1c93b7ab81b Mon Sep 17 00:00:00 2001
+From: Riku Voipio <riku.voipio@linaro.org>
+Date: Thu, 07 Feb 2013 11:04:21 +0000
+Subject: fuse_kernel.h: clean includes
+
+Use <linux/types.h> for linux and define types used for other operating systems
+using <stdint.h> types.
+---
+(limited to 'include/fuse_kernel.h')
+
+--- a/include/fuse_kernel.h
++++ b/include/fuse_kernel.h
+@@ -88,12 +88,16 @@
+ #ifndef _LINUX_FUSE_H
+ #define _LINUX_FUSE_H
+ 
+-#include <sys/types.h>
++#ifdef __linux__
++#include <linux/types.h>
++#else
++#include <stdint.h>
+ #define __u64 uint64_t
+ #define __s64 int64_t
+ #define __u32 uint32_t
+ #define __s32 int32_t
+ #define __u16 uint16_t
++#endif
+ 
+ /*
+  * Version negotiation:
diff --git a/package/utils/jsonfilter/Makefile b/package/utils/jsonfilter/Makefile
new file mode 100644
index 0000000000..d26370e939
--- /dev/null
+++ b/package/utils/jsonfilter/Makefile
@@ -0,0 +1,34 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=jsonfilter
+PKG_VERSION:=2016-07-02
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/jsonpath.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=dea067ad67d977c247c300c06676a06adf21e0c7
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=44c6c1eeaf7adb5f08e6770d5f6c4dfd43b55e1590f90b972be64125a4ae5db0
+CMAKE_INSTALL:=1
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_LICENSE:=ISC
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/jsonfilter
+  SECTION:=base
+  CATEGORY:=Base system
+  DEPENDS:=+libubox +libjson-c
+  TITLE:=OpenWrt JSON filter utility
+  URL:=http://git.openwrt.org/?p=project/jsonpath.git
+endef
+
+define Package/jsonfilter/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/jsonpath $(1)/usr/bin/jsonfilter
+endef
+
+$(eval $(call BuildPackage,jsonfilter))
diff --git a/package/utils/lua/Makefile b/package/utils/lua/Makefile
new file mode 100644
index 0000000000..4985452e4f
--- /dev/null
+++ b/package/utils/lua/Makefile
@@ -0,0 +1,177 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lua
+PKG_VERSION:=5.1.5
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.lua.org/ftp/ \
+	http://ftp.gwdg.de/pub/languages/lua/ \
+	http://mirrors.dotsrc.org/lua/ \
+	http://www.tecgraf.puc-rio.br/lua/ftp/
+PKG_MD5SUM:=2e115fe26e435e33b0d5c022e4490567
+PKG_BUILD_PARALLEL:=1
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=COPYRIGHT
+
+HOST_PATCH_DIR := ./patches-host
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/lua/Default
+  SUBMENU:=Lua
+  SECTION:=lang
+  CATEGORY:=Languages
+  TITLE:=Lua programming language
+  URL:=http://www.lua.org/
+  MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+endef
+
+define Package/lua/Default/description
+ Lua is a powerful light-weight programming language designed for extending 
+ applications. Lua is also frequently used as a general-purpose, stand-alone 
+ language. Lua is free software.
+endef
+
+define Package/liblua
+$(call Package/lua/Default)
+  SUBMENU:=
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE+= (libraries)
+endef
+
+define Package/liblua/description
+$(call Package/lua/Default/description)
+ This package contains the Lua shared libraries, needed by other programs.
+endef
+
+define Package/lua
+$(call Package/lua/Default)
+  DEPENDS:=+liblua
+  TITLE+= (interpreter)
+endef
+
+define Package/lua/description
+$(call Package/lua/Default/description)
+ This package contains the Lua language interpreter.
+endef
+
+define Package/luac
+$(call Package/lua/Default)
+  DEPENDS:=+liblua
+  TITLE+= (compiler)
+endef
+
+define Package/luac/description
+$(call Package/lua/Default/description)
+ This package contains the Lua language compiler.
+endef
+
+define Package/lua-examples
+$(call Package/lua/Default)
+  DEPENDS:=lua
+  TITLE+= (examples)
+endef
+
+define Package/lua-examples/description
+$(call Package/lua/Default/description)
+ This package contains Lua language examples.
+endef
+
+define Build/Configure
+endef
+
+TARGET_CFLAGS += -DLUA_USE_LINUX $(FPIC) -std=gnu99
+
+define Build/Compile
+	$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CROSS)gcc" \
+		AR="$(TARGET_CROSS)ar rcu" \
+		RANLIB="$(TARGET_CROSS)ranlib" \
+		INSTALL_ROOT=/usr \
+		CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
+		MYLDFLAGS="$(TARGET_LDFLAGS)" \
+		PKG_VERSION=$(PKG_VERSION) \
+		linux
+	rm -rf $(PKG_INSTALL_DIR)
+	mkdir -p $(PKG_INSTALL_DIR)
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		INSTALL_TOP="$(PKG_INSTALL_DIR)/usr" \
+		install
+endef
+
+define Host/Configure
+	$(SED) 's,"/usr/local/","$(STAGING_DIR)/host/",' $(HOST_BUILD_DIR)/src/luaconf.h
+endef
+
+ifeq ($(HOST_OS),Darwin)
+	LUA_OS:=macosx
+else
+	ifeq ($(HOST_OS),FreeBSD)
+		LUA_OS:=freebsd
+	else
+		LUA_OS:=linux
+	endif
+endif
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		CC="$(HOSTCC) -std=gnu99" \
+		$(LUA_OS)
+endef
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		INSTALL_TOP="$(STAGING_DIR)/host" \
+		install
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/include
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/lua{,lib,conf}.h $(1)/usr/include/
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/lauxlib.h $(1)/usr/include/
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/lnum_config.h $(1)/usr/include/
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/liblua.{a,so*} $(1)/usr/lib/
+	$(LN) liblua.so.$(PKG_VERSION) $(1)/usr/lib/liblualib.so
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_BUILD_DIR)/etc/lua.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/liblua/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/liblua.so.* $(1)/usr/lib/
+endef
+
+define Package/lua/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/lua $(1)/usr/bin/
+endef
+
+define Package/luac/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/luac $(1)/usr/bin/
+endef
+
+define Package/lua-examples/install
+	$(INSTALL_DIR) $(1)/usr/share/lua/examples
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/test/*.lua \
+		$(1)/usr/share/lua/examples/
+endef
+
+$(eval $(call BuildPackage,liblua))
+$(eval $(call BuildPackage,lua))
+$(eval $(call BuildPackage,luac))
+$(eval $(call BuildPackage,lua-examples))
+$(eval $(call HostBuild))
+
diff --git a/package/utils/lua/patches-host/010-lua-5.1.3-lnum-full-260308.patch b/package/utils/lua/patches-host/010-lua-5.1.3-lnum-full-260308.patch
new file mode 100644
index 0000000000..2a04ce02df
--- /dev/null
+++ b/package/utils/lua/patches-host/010-lua-5.1.3-lnum-full-260308.patch
@@ -0,0 +1,3747 @@
+--- a/Makefile
++++ b/Makefile
+@@ -42,7 +42,7 @@
+ 
+ # What to install.
+ TO_BIN= lua luac
+-TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp
++TO_INC= lua.h luaconf.h lualib.h lauxlib.h lnum_config.h ../etc/lua.hpp
+ TO_LIB= liblua.a
+ TO_MAN= lua.1 luac.1
+ 
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -25,7 +25,7 @@ PLATS= aix ansi bsd freebsd generic linu
+ LUA_A=	liblua.a
+ CORE_O=	lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
+ 	lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o  \
+-	lundump.o lvm.o lzio.o
++	lundump.o lvm.o lzio.o lnum.o
+ LIB_O=	lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
+ 	lstrlib.o loadlib.o linit.o
+ 
+@@ -148,6 +148,7 @@ llex.o: llex.c lua.h luaconf.h ldo.h lob
+ lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
+ lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+   ltm.h lzio.h lmem.h ldo.h
++lnum.o: lnum.c lua.h llex.h lnum.h
+ loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
+ lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \
+   ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h
+@@ -179,4 +180,18 @@ lzio.o: lzio.c lua.h luaconf.h llimits.h
+ print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \
+   ltm.h lzio.h lmem.h lopcodes.h lundump.h
+ 
++luaconf.h: lnum_config.h
++lapi.c: lnum.h
++lauxlib.c: llimits.h
++lbaselib.c: llimits.h lobject.h lapi.h
++lcode.c: lnum.h
++liolib.c: lnum.h llex.h
++llex.c: lnum.h
++lnum.h: lobject.h
++lobject.c: llex.h lnum.h
++ltable.c: lnum.h
++lua.c: llimits.h
++lvm.c: llex.h lnum.h
++print.c: lnum.h
++
+ # (end of Makefile)
+--- a/src/lapi.c
++++ b/src/lapi.c
+@@ -28,7 +28,7 @@
+ #include "ltm.h"
+ #include "lundump.h"
+ #include "lvm.h"
+-
++#include "lnum.h"
+ 
+ 
+ const char lua_ident[] =
+@@ -241,12 +241,13 @@ LUA_API void lua_pushvalue (lua_State *L
+ 
+ LUA_API int lua_type (lua_State *L, int idx) {
+   StkId o = index2adr(L, idx);
+-  return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
++  return (o == luaO_nilobject) ? LUA_TNONE : ttype_ext(o);
+ }
+ 
+ 
+ LUA_API const char *lua_typename (lua_State *L, int t) {
+   UNUSED(L);
++  lua_assert( t!= LUA_TINT );
+   return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
+ }
+ 
+@@ -264,6 +265,14 @@ LUA_API int lua_isnumber (lua_State *L, 
+ }
+ 
+ 
++LUA_API int lua_isinteger (lua_State *L, int idx) {
++  TValue tmp;
++  lua_Integer dum;
++  const TValue *o = index2adr(L, idx);
++  return tonumber(o,&tmp) && (ttisint(o) || tt_integer_valued(o,&dum));
++}
++
++
+ LUA_API int lua_isstring (lua_State *L, int idx) {
+   int t = lua_type(L, idx);
+   return (t == LUA_TSTRING || t == LUA_TNUMBER);
+@@ -309,31 +318,66 @@ LUA_API int lua_lessthan (lua_State *L, 
+ }
+ 
+ 
+-
+ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
+   TValue n;
+   const TValue *o = index2adr(L, idx);
+-  if (tonumber(o, &n))
++  if (tonumber(o, &n)) {
++#ifdef LNUM_COMPLEX
++    if (nvalue_img(o) != 0)
++      luaG_runerror(L, "expecting a real number");
++#endif
+     return nvalue(o);
+-  else
+-    return 0;
++  }
++  return 0;
+ }
+ 
+ 
+ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
+   TValue n;
++    /* Lua 5.1 documented behaviour is to return nonzero for non-integer:
++     * "If the number is not an integer, it is truncated in some non-specified way." 
++     * I would suggest to change this, to return 0 for anything that would
++     * not fit in 'lua_Integer'.
++     */
++#ifdef LUA_COMPAT_TOINTEGER
++  /* Lua 5.1 compatible */
+   const TValue *o = index2adr(L, idx);
+   if (tonumber(o, &n)) {
+-    lua_Integer res;
+-    lua_Number num = nvalue(o);
+-    lua_number2integer(res, num);
+-    return res;
++    lua_Integer i;
++    lua_Number d;
++    if (ttisint(o)) return ivalue(o);
++    d= nvalue_fast(o);
++# ifdef LNUM_COMPLEX
++    if (nvalue_img_fast(o) != 0)
++      luaG_runerror(L, "expecting a real number");
++# endif
++    lua_number2integer(i, d);
++    return i;
+   }
+-  else
+-    return 0;
++#else
++  /* New suggestion */
++  const TValue *o = index2adr(L, idx);
++  if (tonumber(o, &n)) {
++    lua_Integer i;
++    if (ttisint(o)) return ivalue(o);
++    if (tt_integer_valued(o,&i)) return i;
++  }
++#endif
++  return 0;
+ }
+ 
+ 
++#ifdef LNUM_COMPLEX
++LUA_API lua_Complex lua_tocomplex (lua_State *L, int idx) {
++  TValue tmp;
++  const TValue *o = index2adr(L, idx);
++  if (tonumber(o, &tmp))
++    return nvalue_complex(o);
++  return 0;
++}
++#endif
++
++
+ LUA_API int lua_toboolean (lua_State *L, int idx) {
+   const TValue *o = index2adr(L, idx);
+   return !l_isfalse(o);
+@@ -364,6 +408,7 @@ LUA_API size_t lua_objlen (lua_State *L,
+     case LUA_TSTRING: return tsvalue(o)->len;
+     case LUA_TUSERDATA: return uvalue(o)->len;
+     case LUA_TTABLE: return luaH_getn(hvalue(o));
++    case LUA_TINT:
+     case LUA_TNUMBER: {
+       size_t l;
+       lua_lock(L);  /* `luaV_tostring' may create a new string */
+@@ -426,6 +471,8 @@ LUA_API void lua_pushnil (lua_State *L) 
+ }
+ 
+ 
++/* 'lua_pushnumber()' may lose accuracy on integers, 'lua_pushinteger' will not.
++ */
+ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
+   lua_lock(L);
+   setnvalue(L->top, n);
+@@ -434,12 +481,22 @@ LUA_API void lua_pushnumber (lua_State *
+ }
+ 
+ 
+-LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
++LUA_API void lua_pushinteger (lua_State *L, lua_Integer i) {
++  lua_lock(L);
++  setivalue(L->top, i);
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++#ifdef LNUM_COMPLEX
++LUA_API void lua_pushcomplex (lua_State *L, lua_Complex v) {
+   lua_lock(L);
+-  setnvalue(L->top, cast_num(n));
++  setnvalue_complex( L->top, v );
+   api_incr_top(L);
+   lua_unlock(L);
+ }
++#endif
+ 
+ 
+ LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
+@@ -569,7 +626,7 @@ LUA_API void lua_rawgeti (lua_State *L, 
+   lua_lock(L);
+   o = index2adr(L, idx);
+   api_check(L, ttistable(o));
+-  setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
++  setobj2s(L, L->top, luaH_getint(hvalue(o), n));
+   api_incr_top(L);
+   lua_unlock(L);
+ }
+@@ -597,6 +654,9 @@ LUA_API int lua_getmetatable (lua_State 
+     case LUA_TUSERDATA:
+       mt = uvalue(obj)->metatable;
+       break;
++    case LUA_TINT:
++      mt = G(L)->mt[LUA_TNUMBER];
++      break;
+     default:
+       mt = G(L)->mt[ttype(obj)];
+       break;
+@@ -687,7 +747,7 @@ LUA_API void lua_rawseti (lua_State *L, 
+   api_checknelems(L, 1);
+   o = index2adr(L, idx);
+   api_check(L, ttistable(o));
+-  setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
++  setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1);
+   luaC_barriert(L, hvalue(o), L->top-1);
+   L->top--;
+   lua_unlock(L);
+@@ -721,7 +781,7 @@ LUA_API int lua_setmetatable (lua_State 
+       break;
+     }
+     default: {
+-      G(L)->mt[ttype(obj)] = mt;
++      G(L)->mt[ttype_ext(obj)] = mt;
+       break;
+     }
+   }
+@@ -1085,3 +1145,32 @@ LUA_API const char *lua_setupvalue (lua_
+   return name;
+ }
+ 
++
++/* Help function for 'luaB_tonumber()', avoids multiple str->number
++ * conversions for Lua "tonumber()".
++ *
++ * Also pushes floating point numbers with integer value as integer, which
++ * can be used by 'tonumber()' in scripts to bring values back to integer
++ * realm.
++ *
++ * Note: The 'back to integer realm' is _not_ to affect string conversions:
++ * 'tonumber("4294967295.1")' should give a floating point value, although
++ * the value would be 4294967296 (and storable in int64 realm).
++ */
++int lua_pushvalue_as_number (lua_State *L, int idx)
++{
++  const TValue *o = index2adr(L, idx);
++  TValue tmp;
++  lua_Integer i;
++  if (ttisnumber(o)) {
++    if ( (!ttisint(o)) && tt_integer_valued(o,&i)) {
++      lua_pushinteger( L, i );
++      return 1;
++    }
++  } else if (!tonumber(o, &tmp)) {
++    return 0;
++  }
++  if (ttisint(o)) lua_pushinteger( L, ivalue(o) );
++  else lua_pushnumber( L, nvalue_fast(o) );
++  return 1;
++}
+--- a/src/lapi.h
++++ b/src/lapi.h
+@@ -13,4 +13,6 @@
+ 
+ LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
+ 
++int lua_pushvalue_as_number (lua_State *L, int idx);
++
+ #endif
+--- a/src/lauxlib.c
++++ b/src/lauxlib.c
+@@ -23,7 +23,7 @@
+ #include "lua.h"
+ 
+ #include "lauxlib.h"
+-
++#include "llimits.h"
+ 
+ #define FREELIST_REF	0	/* free list of references */
+ 
+@@ -66,7 +66,7 @@ LUALIB_API int luaL_typerror (lua_State 
+ 
+ 
+ static void tag_error (lua_State *L, int narg, int tag) {
+-  luaL_typerror(L, narg, lua_typename(L, tag));
++  luaL_typerror(L, narg, tag==LUA_TINT ? "integer" : lua_typename(L, tag));
+ }
+ 
+ 
+@@ -188,8 +188,8 @@ LUALIB_API lua_Number luaL_optnumber (lu
+ 
+ LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
+   lua_Integer d = lua_tointeger(L, narg);
+-  if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
+-    tag_error(L, narg, LUA_TNUMBER);
++  if (d == 0 && !lua_isinteger(L, narg))  /* avoid extra test when d is not 0 */
++    tag_error(L, narg, LUA_TINT);
+   return d;
+ }
+ 
+@@ -200,6 +200,16 @@ LUALIB_API lua_Integer luaL_optinteger (
+ }
+ 
+ 
++#ifdef LNUM_COMPLEX
++LUALIB_API lua_Complex luaL_checkcomplex (lua_State *L, int narg) {
++  lua_Complex c = lua_tocomplex(L, narg);
++  if (c == 0 && !lua_isnumber(L, narg))  /* avoid extra test when c is not 0 */
++    tag_error(L, narg, LUA_TNUMBER);
++  return c;
++}
++#endif
++
++
+ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
+   if (!lua_getmetatable(L, obj))  /* no metatable? */
+     return 0;
+--- a/src/lauxlib.h
++++ b/src/lauxlib.h
+@@ -57,6 +57,12 @@ LUALIB_API lua_Number (luaL_optnumber) (
+ LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
+ LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
+                                           lua_Integer def);
++#define luaL_checkint32(L,narg) ((int)luaL_checkinteger(L,narg))
++#define luaL_optint32(L,narg,def) ((int)luaL_optinteger(L,narg,def))
++
++#ifdef LNUM_COMPLEX
++  LUALIB_API lua_Complex (luaL_checkcomplex) (lua_State *L, int narg);
++#endif
+ 
+ LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+ LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
+--- a/src/lbaselib.c
++++ b/src/lbaselib.c
+@@ -18,7 +18,9 @@
+ 
+ #include "lauxlib.h"
+ #include "lualib.h"
+-
++#include "llimits.h"
++#include "lobject.h"
++#include "lapi.h"
+ 
+ 
+ 
+@@ -54,20 +56,25 @@ static int luaB_tonumber (lua_State *L) 
+   int base = luaL_optint(L, 2, 10);
+   if (base == 10) {  /* standard conversion */
+     luaL_checkany(L, 1);
+-    if (lua_isnumber(L, 1)) {
+-      lua_pushnumber(L, lua_tonumber(L, 1));
++    if (lua_isnumber(L, 1)) {       /* numeric string, or a number */
++      lua_pushvalue_as_number(L,1);     /* API extension (not to lose accuracy here) */
+       return 1;
+-    }
++	}
+   }
+   else {
+     const char *s1 = luaL_checkstring(L, 1);
+     char *s2;
+-    unsigned long n;
++    unsigned LUA_INTEGER n;
+     luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+-    n = strtoul(s1, &s2, base);
++    n = lua_str2ul(s1, &s2, base);
+     if (s1 != s2) {  /* at least one valid digit? */
+       while (isspace((unsigned char)(*s2))) s2++;  /* skip trailing spaces */
+       if (*s2 == '\0') {  /* no invalid trailing characters? */
++	  
++		/* Push as number, there needs to be separate 'luaB_tointeger' for
++		 * when the caller wants to preserve the bits (matters if unsigned
++		 * values are used).
++		 */
+         lua_pushnumber(L, (lua_Number)n);
+         return 1;
+       }
+@@ -144,7 +151,7 @@ static int luaB_setfenv (lua_State *L) {
+   luaL_checktype(L, 2, LUA_TTABLE);
+   getfunc(L, 0);
+   lua_pushvalue(L, 2);
+-  if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
++  if (lua_isnumber(L, 1) && lua_tointeger(L, 1) == 0) {
+     /* change environment of current thread */
+     lua_pushthread(L);
+     lua_insert(L, -2);
+@@ -209,7 +216,7 @@ static int luaB_collectgarbage (lua_Stat
+       return 1;
+     }
+     default: {
+-      lua_pushnumber(L, res);
++      lua_pushinteger(L, res);
+       return 1;
+     }
+   }
+@@ -631,6 +638,8 @@ static void base_open (lua_State *L) {
+   luaL_register(L, "_G", base_funcs);
+   lua_pushliteral(L, LUA_VERSION);
+   lua_setglobal(L, "_VERSION");  /* set global _VERSION */
++  lua_pushliteral(L, LUA_LNUM);
++  lua_setglobal(L, "_LNUM");  /* "[complex] double|float|ldouble int32|int64" */
+   /* `ipairs' and `pairs' need auxiliary functions as upvalues */
+   auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
+   auxopen(L, "pairs", luaB_pairs, luaB_next);
+--- a/src/lcode.c
++++ b/src/lcode.c
+@@ -22,13 +22,18 @@
+ #include "lopcodes.h"
+ #include "lparser.h"
+ #include "ltable.h"
++#include "lnum.h"
+ 
+ 
+ #define hasjumps(e)	((e)->t != (e)->f)
+ 
+-
+ static int isnumeral(expdesc *e) {
+-  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
++  int ek=
++#ifdef LNUM_COMPLEX
++    (e->k == VKNUM2) ||
++#endif
++    (e->k == VKINT) || (e->k == VKNUM);
++  return (ek && e->t == NO_JUMP && e->f == NO_JUMP);
+ }
+ 
+ 
+@@ -231,12 +236,16 @@ static int addk (FuncState *fs, TValue *
+   TValue *idx = luaH_set(L, fs->h, k);
+   Proto *f = fs->f;
+   int oldsize = f->sizek;
+-  if (ttisnumber(idx)) {
+-    lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
+-    return cast_int(nvalue(idx));
++  if (ttype(idx)==LUA_TNUMBER) {
++    luai_normalize(idx);
++    lua_assert( ttype(idx)==LUA_TINT );     /* had no fraction */
++  }
++  if (ttisint(idx)) {
++    lua_assert(luaO_rawequalObj(&fs->f->k[ivalue(idx)], v));
++    return cast_int(ivalue(idx));
+   }
+   else {  /* constant not found; create a new entry */
+-    setnvalue(idx, cast_num(fs->nk));
++    setivalue(idx, fs->nk);
+     luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
+                     MAXARG_Bx, "constant table overflow");
+     while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
+@@ -261,6 +270,21 @@ int luaK_numberK (FuncState *fs, lua_Num
+ }
+ 
+ 
++int luaK_integerK (FuncState *fs, lua_Integer r) {
++  TValue o;
++  setivalue(&o, r);
++  return addk(fs, &o, &o);
++}
++
++
++#ifdef LNUM_COMPLEX
++static int luaK_imagK (FuncState *fs, lua_Number r) {
++  TValue o;
++  setnvalue_complex(&o, r*I);
++  return addk(fs, &o, &o);
++}
++#endif
++
+ static int boolK (FuncState *fs, int b) {
+   TValue o;
+   setbvalue(&o, b);
+@@ -359,6 +383,16 @@ static void discharge2reg (FuncState *fs
+       luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
+       break;
+     }
++    case VKINT: {
++      luaK_codeABx(fs, OP_LOADK, reg, luaK_integerK(fs, e->u.ival));
++      break;
++    }
++#ifdef LNUM_COMPLEX
++    case VKNUM2: {
++      luaK_codeABx(fs, OP_LOADK, reg, luaK_imagK(fs, e->u.nval));
++      break;
++    }
++#endif
+     case VRELOCABLE: {
+       Instruction *pc = &getcode(fs, e);
+       SETARG_A(*pc, reg);
+@@ -444,6 +478,10 @@ void luaK_exp2val (FuncState *fs, expdes
+ int luaK_exp2RK (FuncState *fs, expdesc *e) {
+   luaK_exp2val(fs, e);
+   switch (e->k) {
++#ifdef LNUM_COMPLEX
++    case VKNUM2:
++#endif
++    case VKINT:
+     case VKNUM:
+     case VTRUE:
+     case VFALSE:
+@@ -451,6 +489,10 @@ int luaK_exp2RK (FuncState *fs, expdesc 
+       if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
+         e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
+                       (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
++                      (e->k == VKINT) ? luaK_integerK(fs, e->u.ival) :
++#ifdef LNUM_COMPLEX
++                      (e->k == VKNUM2) ? luaK_imagK(fs, e->u.nval) :
++#endif
+                                         boolK(fs, (e->k == VTRUE));
+         e->k = VK;
+         return RKASK(e->u.s.info);
+@@ -540,7 +582,10 @@ void luaK_goiftrue (FuncState *fs, expde
+   int pc;  /* pc of last jump */
+   luaK_dischargevars(fs, e);
+   switch (e->k) {
+-    case VK: case VKNUM: case VTRUE: {
++#ifdef LNUM_COMPLEX
++    case VKNUM2:
++#endif
++    case VKINT: case VK: case VKNUM: case VTRUE: {
+       pc = NO_JUMP;  /* always true; do nothing */
+       break;
+     }
+@@ -590,7 +635,10 @@ static void codenot (FuncState *fs, expd
+       e->k = VTRUE;
+       break;
+     }
+-    case VK: case VKNUM: case VTRUE: {
++#ifdef LNUM_COMPLEX
++    case VKNUM2:
++#endif
++    case VKINT: case VK: case VKNUM: case VTRUE: {
+       e->k = VFALSE;
+       break;
+     }
+@@ -626,25 +674,70 @@ void luaK_indexed (FuncState *fs, expdes
+ 
+ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
+   lua_Number v1, v2, r;
++  int vkres= VKNUM;
+   if (!isnumeral(e1) || !isnumeral(e2)) return 0;
+-  v1 = e1->u.nval;
+-  v2 = e2->u.nval;
++
++  /* real and imaginary parts don't mix. */
++#ifdef LNUM_COMPLEX
++  if (e1->k == VKNUM2) {
++    if ((op != OP_UNM) && (e2->k != VKNUM2)) return 0; 
++    vkres= VKNUM2; }
++  else if (e2->k == VKNUM2) { return 0; }
++#endif
++  if ((e1->k == VKINT) && (e2->k == VKINT)) {
++    lua_Integer i1= e1->u.ival, i2= e2->u.ival;
++    lua_Integer rr;
++    int done= 0;
++    /* Integer/integer calculations (may end up producing floating point) */
++    switch (op) {
++      case OP_ADD: done= try_addint( &rr, i1, i2 ); break;
++      case OP_SUB: done= try_subint( &rr, i1, i2 ); break;
++      case OP_MUL: done= try_mulint( &rr, i1, i2 ); break;
++      case OP_DIV: done= try_divint( &rr, i1, i2 ); break;
++      case OP_MOD: done= try_modint( &rr, i1, i2 ); break;
++      case OP_POW: done= try_powint( &rr, i1, i2 ); break;
++      case OP_UNM: done= try_unmint( &rr, i1 ); break;
++      default:     done= 0; break;
++    }
++    if (done) {
++      e1->u.ival = rr;  /* remained within integer range */
++      return 1;
++    }
++  }
++  v1 = (e1->k == VKINT) ? ((lua_Number)e1->u.ival) : e1->u.nval;
++  v2 = (e2->k == VKINT) ? ((lua_Number)e2->u.ival) : e2->u.nval;
++
+   switch (op) {
+     case OP_ADD: r = luai_numadd(v1, v2); break;
+     case OP_SUB: r = luai_numsub(v1, v2); break;
+-    case OP_MUL: r = luai_nummul(v1, v2); break;
++    case OP_MUL: 
++#ifdef LNUM_COMPLEX
++        if (vkres==VKNUM2) return 0;    /* leave to runtime (could do here, but not worth it?) */
++#endif
++        r = luai_nummul(v1, v2); break;
+     case OP_DIV:
+       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
+-      r = luai_numdiv(v1, v2); break;
++#ifdef LNUM_COMPLEX
++        if (vkres==VKNUM2) return 0;    /* leave to runtime */
++#endif
++        r = luai_numdiv(v1, v2); break;
+     case OP_MOD:
+       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
++#ifdef LNUM_COMPLEX
++      if (vkres==VKNUM2) return 0;    /* leave to runtime */
++#endif
+       r = luai_nummod(v1, v2); break;
+-    case OP_POW: r = luai_numpow(v1, v2); break;
++    case OP_POW: 
++#ifdef LNUM_COMPLEX
++      if (vkres==VKNUM2) return 0;    /* leave to runtime */
++#endif
++      r = luai_numpow(v1, v2); break;
+     case OP_UNM: r = luai_numunm(v1); break;
+     case OP_LEN: return 0;  /* no constant folding for 'len' */
+     default: lua_assert(0); r = 0; break;
+   }
+   if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */
++  e1->k = cast(expkind,vkres);
+   e1->u.nval = r;
+   return 1;
+ }
+@@ -688,7 +781,8 @@ static void codecomp (FuncState *fs, OpC
+ 
+ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+   expdesc e2;
+-  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
++  e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
++
+   switch (op) {
+     case OPR_MINUS: {
+       if (!isnumeral(e))
+--- a/src/lcode.h
++++ b/src/lcode.h
+@@ -71,6 +71,6 @@ LUAI_FUNC void luaK_prefix (FuncState *f
+ LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+ LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
+ LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
+-
++LUAI_FUNC int luaK_integerK (FuncState *fs, lua_Integer r);
+ 
+ #endif
+--- a/src/ldebug.c
++++ b/src/ldebug.c
+@@ -183,7 +183,7 @@ static void collectvalidlines (lua_State
+     int *lineinfo = f->l.p->lineinfo;
+     int i;
+     for (i=0; i<f->l.p->sizelineinfo; i++)
+-      setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
++      setbvalue(luaH_setint(L, t, lineinfo[i]), 1);
+     sethvalue(L, L->top, t); 
+   }
+   incr_top(L);
+@@ -566,7 +566,7 @@ static int isinstack (CallInfo *ci, cons
+ 
+ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+   const char *name = NULL;
+-  const char *t = luaT_typenames[ttype(o)];
++  const char *t = luaT_typenames[ttype_ext(o)];
+   const char *kind = (isinstack(L->ci, o)) ?
+                          getobjname(L, L->ci, cast_int(o - L->base), &name) :
+                          NULL;
+@@ -594,8 +594,8 @@ void luaG_aritherror (lua_State *L, cons
+ 
+ 
+ int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
+-  const char *t1 = luaT_typenames[ttype(p1)];
+-  const char *t2 = luaT_typenames[ttype(p2)];
++  const char *t1 = luaT_typenames[ttype_ext(p1)];
++  const char *t2 = luaT_typenames[ttype_ext(p2)];
+   if (t1[2] == t2[2])
+     luaG_runerror(L, "attempt to compare two %s values", t1);
+   else
+--- a/src/ldo.c
++++ b/src/ldo.c
+@@ -220,9 +220,9 @@ static StkId adjust_varargs (lua_State *
+     luaD_checkstack(L, p->maxstacksize);
+     htab = luaH_new(L, nvar, 1);  /* create `arg' table */
+     for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */
+-      setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
++      setobj2n(L, luaH_setint(L, htab, i+1), L->top - nvar + i);
+     /* store counter in field `n' */
+-    setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
++    setivalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), nvar);
+   }
+ #endif
+   /* move fixed parameters to final position */
+--- a/src/ldump.c
++++ b/src/ldump.c
+@@ -52,6 +52,11 @@ static void DumpNumber(lua_Number x, Dum
+  DumpVar(x,D);
+ }
+ 
++static void DumpInteger(lua_Integer x, DumpState* D)
++{
++ DumpVar(x,D);
++}
++
+ static void DumpVector(const void* b, int n, size_t size, DumpState* D)
+ {
+  DumpInt(n,D);
+@@ -93,8 +98,11 @@ static void DumpConstants(const Proto* f
+ 	DumpChar(bvalue(o),D);
+ 	break;
+    case LUA_TNUMBER:
+-	DumpNumber(nvalue(o),D);
++	DumpNumber(nvalue_fast(o),D);
+ 	break;
++   case LUA_TINT:
++	DumpInteger(ivalue(o),D);
++    break;
+    case LUA_TSTRING:
+ 	DumpString(rawtsvalue(o),D);
+ 	break;
+--- a/src/liolib.c
++++ b/src/liolib.c
+@@ -9,6 +9,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <ctype.h>
+ 
+ #define liolib_c
+ #define LUA_LIB
+@@ -18,7 +19,8 @@
+ #include "lauxlib.h"
+ #include "lualib.h"
+ 
+-
++#include "lnum.h"
++#include "llex.h"
+ 
+ #define IO_INPUT	1
+ #define IO_OUTPUT	2
+@@ -269,6 +271,13 @@ static int io_lines (lua_State *L) {
+ ** =======================================================
+ */
+ 
++/*
++* Many problems if we intend the same 'n' format specifier (see 'file:read()')
++* to work for both FP and integer numbers, without losing their accuracy. So
++* we don't. 'n' reads numbers as floating points, 'i' as integers. Old code
++* remains valid, but won't provide full integer accuracy (this only matters
++* with float FP and/or 64-bit integers).
++*/
+ 
+ static int read_number (lua_State *L, FILE *f) {
+   lua_Number d;
+@@ -282,6 +291,43 @@ static int read_number (lua_State *L, FI
+   }
+ }
+ 
++static int read_integer (lua_State *L, FILE *f) {
++  lua_Integer i;
++  if (fscanf(f, LUA_INTEGER_SCAN, &i) == 1) {
++    lua_pushinteger(L, i);
++    return 1;
++  }
++  else return 0;  /* read fails */
++}
++
++#ifdef LNUM_COMPLEX
++static int read_complex (lua_State *L, FILE *f) {
++  /* NNN / NNNi / NNN+MMMi / NNN-MMMi */
++  lua_Number a,b;
++  if (fscanf(f, LUA_NUMBER_SCAN, &a) == 1) {
++    int c=fgetc(f);
++    switch(c) {
++        case 'i':
++            lua_pushcomplex(L, a*I);
++            return 1;
++        case '+':
++        case '-':
++            /* "i" is consumed if at the end; just 'NNN+MMM' will most likely
++             * behave as if "i" was there? (TBD: test)
++             */
++            if (fscanf(f, LUA_NUMBER_SCAN "i", &b) == 1) {
++                lua_pushcomplex(L, a+ (c=='+' ? b:-b)*I);
++                return 1;
++            }
++    }
++    ungetc( c,f );
++    lua_pushnumber(L,a);  /*real part only*/
++    return 1;
++  }
++  return 0;  /* read fails */
++}
++#endif
++
+ 
+ static int test_eof (lua_State *L, FILE *f) {
+   int c = getc(f);
+@@ -355,6 +401,14 @@ static int g_read (lua_State *L, FILE *f
+           case 'n':  /* number */
+             success = read_number(L, f);
+             break;
++          case 'i':  /* integer (full accuracy) */
++            success = read_integer(L, f);
++            break;
++#ifdef LNUM_COMPLEX
++          case 'c':  /* complex */
++            success = read_complex(L, f);
++            break;
++#endif
+           case 'l':  /* line */
+             success = read_line(L, f);
+             break;
+@@ -415,9 +469,10 @@ static int g_write (lua_State *L, FILE *
+   int status = 1;
+   for (; nargs--; arg++) {
+     if (lua_type(L, arg) == LUA_TNUMBER) {
+-      /* optimization: could be done exactly as for strings */
+-      status = status &&
+-          fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
++      if (lua_isinteger(L,arg))
++          status = status && fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) > 0;
++      else
++          status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
+     }
+     else {
+       size_t l;
+@@ -460,7 +515,7 @@ static int f_setvbuf (lua_State *L) {
+   static const char *const modenames[] = {"no", "full", "line", NULL};
+   FILE *f = tofile(L);
+   int op = luaL_checkoption(L, 2, NULL, modenames);
+-  lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
++  size_t sz = luaL_optint32(L, 3, LUAL_BUFFERSIZE);
+   int res = setvbuf(f, NULL, mode[op], sz);
+   return pushresult(L, res == 0, NULL);
+ }
+--- a/src/llex.c
++++ b/src/llex.c
+@@ -22,6 +22,7 @@
+ #include "lstring.h"
+ #include "ltable.h"
+ #include "lzio.h"
++#include "lnum.h"
+ 
+ 
+ 
+@@ -34,13 +35,17 @@
+ 
+ 
+ /* ORDER RESERVED */
+-const char *const luaX_tokens [] = {
++static const char *const luaX_tokens [] = {
+     "and", "break", "do", "else", "elseif",
+     "end", "false", "for", "function", "if",
+     "in", "local", "nil", "not", "or", "repeat",
+     "return", "then", "true", "until", "while",
+     "..", "...", "==", ">=", "<=", "~=",
+     "<number>", "<name>", "<string>", "<eof>",
++    "<integer>",
++#ifdef LNUM_COMPLEX
++    "<number2>",
++#endif
+     NULL
+ };
+ 
+@@ -90,7 +95,11 @@ static const char *txtToken (LexState *l
+   switch (token) {
+     case TK_NAME:
+     case TK_STRING:
++    case TK_INT:
+     case TK_NUMBER:
++#ifdef LNUM_COMPLEX
++    case TK_NUMBER2:
++#endif
+       save(ls, '\0');
+       return luaZ_buffer(ls->buff);
+     default:
+@@ -175,23 +184,27 @@ static void buffreplace (LexState *ls, c
+     if (p[n] == from) p[n] = to;
+ }
+ 
+-
+-static void trydecpoint (LexState *ls, SemInfo *seminfo) {
++/* TK_NUMBER (/ TK_NUMBER2) */
++static int trydecpoint (LexState *ls, SemInfo *seminfo) {
+   /* format error: try to update decimal point separator */
+   struct lconv *cv = localeconv();
+   char old = ls->decpoint;
++  int ret;
+   ls->decpoint = (cv ? cv->decimal_point[0] : '.');
+   buffreplace(ls, old, ls->decpoint);  /* try updated decimal separator */
+-  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
++  ret= luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r, NULL);
++  if (!ret) {
+     /* format error with correct decimal point: no more options */
+     buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */
+     luaX_lexerror(ls, "malformed number", TK_NUMBER);
+   }
++  return ret;
+ }
+ 
+ 
+-/* LUA_NUMBER */
+-static void read_numeral (LexState *ls, SemInfo *seminfo) {
++/* TK_NUMBER / TK_INT (/TK_NUMBER2) */
++static int read_numeral (LexState *ls, SemInfo *seminfo) {
++  int ret;
+   lua_assert(isdigit(ls->current));
+   do {
+     save_and_next(ls);
+@@ -202,8 +215,9 @@ static void read_numeral (LexState *ls, 
+     save_and_next(ls);
+   save(ls, '\0');
+   buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */
+-  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r))  /* format error? */
+-    trydecpoint(ls, seminfo); /* try to update decimal point separator */
++  ret= luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r, &seminfo->i );
++  if (!ret) return trydecpoint(ls, seminfo); /* try to update decimal point separator */
++  return ret;
+ }
+ 
+ 
+@@ -331,6 +345,7 @@ static void read_string (LexState *ls, i
+ }
+ 
+ 
++/* char / TK_* */
+ static int llex (LexState *ls, SemInfo *seminfo) {
+   luaZ_resetbuffer(ls->buff);
+   for (;;) {
+@@ -402,8 +417,7 @@ static int llex (LexState *ls, SemInfo *
+         }
+         else if (!isdigit(ls->current)) return '.';
+         else {
+-          read_numeral(ls, seminfo);
+-          return TK_NUMBER;
++          return read_numeral(ls, seminfo);
+         }
+       }
+       case EOZ: {
+@@ -416,8 +430,7 @@ static int llex (LexState *ls, SemInfo *
+           continue;
+         }
+         else if (isdigit(ls->current)) {
+-          read_numeral(ls, seminfo);
+-          return TK_NUMBER;
++          return read_numeral(ls, seminfo);
+         }
+         else if (isalpha(ls->current) || ls->current == '_') {
+           /* identifier or reserved word */
+--- a/src/llex.h
++++ b/src/llex.h
+@@ -29,19 +29,22 @@ enum RESERVED {
+   TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
+   /* other terminal symbols */
+   TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
+-  TK_NAME, TK_STRING, TK_EOS
++  TK_NAME, TK_STRING, TK_EOS, TK_INT
++#ifdef LNUM_COMPLEX
++  , TK_NUMBER2   /* imaginary constants: Ni */ 
++#endif
+ };
+ 
+ /* number of reserved words */
+ #define NUM_RESERVED	(cast(int, TK_WHILE-FIRST_RESERVED+1))
+ 
+ 
+-/* array with token `names' */
+-LUAI_DATA const char *const luaX_tokens [];
+-
+-
++/* SemInfo is a local data structure of 'llex.c', used for carrying a string
++ * or a number. A separate token (TK_*) will tell, how to interpret the data.
++ */      
+ typedef union {
+   lua_Number r;
++  lua_Integer i;
+   TString *ts;
+ } SemInfo;  /* semantics information */
+ 
+--- a/src/llimits.h
++++ b/src/llimits.h
+@@ -49,6 +49,7 @@ typedef LUAI_USER_ALIGNMENT_T L_Umaxalig
+ 
+ /* result of a `usual argument conversion' over lua_Number */
+ typedef LUAI_UACNUMBER l_uacNumber;
++typedef LUAI_UACINTEGER l_uacInteger;
+ 
+ 
+ /* internal assertions for in-house debugging */
+@@ -80,7 +81,6 @@ typedef LUAI_UACNUMBER l_uacNumber;
+ #define cast_int(i)	cast(int, (i))
+ 
+ 
+-
+ /*
+ ** type for virtual-machine instructions
+ ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+--- a/src/lmathlib.c
++++ b/src/lmathlib.c
+@@ -4,7 +4,6 @@
+ ** See Copyright Notice in lua.h
+ */
+ 
+-
+ #include <stdlib.h>
+ #include <math.h>
+ 
+@@ -16,113 +15,210 @@
+ #include "lauxlib.h"
+ #include "lualib.h"
+ 
++/* 'luai_vectpow()' as a replacement for 'cpow()'. Defined in the header; we
++ * don't intrude the code libs internal functions.
++ */
++#ifdef LNUM_COMPLEX
++# include "lnum.h"    
++#endif
+ 
+ #undef PI
+-#define PI (3.14159265358979323846)
+-#define RADIANS_PER_DEGREE (PI/180.0)
+-
++#ifdef LNUM_FLOAT
++# define PI (3.14159265358979323846F)
++#elif defined(M_PI)
++# define PI M_PI
++#else
++# define PI (3.14159265358979323846264338327950288)
++#endif
++#define RADIANS_PER_DEGREE (PI/180)
+ 
++#undef HUGE
++#ifdef LNUM_FLOAT
++# define HUGE HUGE_VALF
++#elif defined(LNUM_LDOUBLE)
++# define HUGE HUGE_VALL
++#else
++# define HUGE HUGE_VAL
++#endif
+ 
+ static int math_abs (lua_State *L) {
+-  lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushnumber(L, _LF(cabs) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(fabs) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_sin (lua_State *L) {
+-  lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(csin) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(sin) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_sinh (lua_State *L) {
+-  lua_pushnumber(L, sinh(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(csinh) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(sinh) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_cos (lua_State *L) {
+-  lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ccos) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(cos) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_cosh (lua_State *L) {
+-  lua_pushnumber(L, cosh(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ccosh) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(cosh) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_tan (lua_State *L) {
+-  lua_pushnumber(L, tan(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ctan) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(tan) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_tanh (lua_State *L) {
+-  lua_pushnumber(L, tanh(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ctanh) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(tanh) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_asin (lua_State *L) {
+-  lua_pushnumber(L, asin(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(casin) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(asin) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_acos (lua_State *L) {
+-  lua_pushnumber(L, acos(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(cacos) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(acos) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_atan (lua_State *L) {
+-  lua_pushnumber(L, atan(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(catan) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(atan) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_atan2 (lua_State *L) {
+-  lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++  /* scalars only */
++  lua_pushnumber(L, _LF(atan2) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+   return 1;
+ }
+ 
+ static int math_ceil (lua_State *L) {
+-  lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_Complex v= luaL_checkcomplex(L, 1);
++  lua_pushcomplex(L, _LF(ceil) (_LF(creal)(v)) + _LF(ceil) (_LF(cimag)(v))*I);
++#else
++  lua_pushnumber(L, _LF(ceil) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_floor (lua_State *L) {
+-  lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_Complex v= luaL_checkcomplex(L, 1);
++  lua_pushcomplex(L, _LF(floor) (_LF(creal)(v)) + _LF(floor) (_LF(cimag)(v))*I);
++#else
++  lua_pushnumber(L, _LF(floor) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+-static int math_fmod (lua_State *L) {
+-  lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++static int math_fmod (lua_State *L) {  
++  /* scalars only */
++  lua_pushnumber(L, _LF(fmod) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+   return 1;
+ }
+ 
+ static int math_modf (lua_State *L) {
+-  double ip;
+-  double fp = modf(luaL_checknumber(L, 1), &ip);
++  /* scalars only */
++  lua_Number ip;
++  lua_Number fp = _LF(modf) (luaL_checknumber(L, 1), &ip);
+   lua_pushnumber(L, ip);
+   lua_pushnumber(L, fp);
+   return 2;
+ }
+ 
+ static int math_sqrt (lua_State *L) {
+-  lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(csqrt) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(sqrt) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_pow (lua_State *L) {
+-  lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++#ifdef LNUM_COMPLEX
++  /* C99 'cpow' gives somewhat inaccurate results (i.e. (-1)^2 = -1+1.2246467991474e-16i). 
++  * 'luai_vectpow' smoothens such, reusing it is the reason we need to #include "lnum.h".
++  */
++  lua_pushcomplex(L, luai_vectpow(luaL_checkcomplex(L,1), luaL_checkcomplex(L,2)));
++#else
++  lua_pushnumber(L, _LF(pow) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++#endif
+   return 1;
+ }
+ 
+ static int math_log (lua_State *L) {
+-  lua_pushnumber(L, log(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(clog) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(log) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_log10 (lua_State *L) {
+-  lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  /* Not in standard <complex.h> , but easy to calculate: log_a(x) = log_b(x) / log_b(a) 
++  */
++  lua_pushcomplex(L, _LF(clog) (luaL_checkcomplex(L,1)) / _LF(log) (10));
++#else
++  lua_pushnumber(L, _LF(log10) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_exp (lua_State *L) {
+-  lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(cexp) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(exp) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+@@ -138,19 +234,20 @@ static int math_rad (lua_State *L) {
+ 
+ static int math_frexp (lua_State *L) {
+   int e;
+-  lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
++  lua_pushnumber(L, _LF(frexp) (luaL_checknumber(L, 1), &e));
+   lua_pushinteger(L, e);
+   return 2;
+ }
+ 
+ static int math_ldexp (lua_State *L) {
+-  lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
++  lua_pushnumber(L, _LF(ldexp) (luaL_checknumber(L, 1), luaL_checkint(L, 2)));
+   return 1;
+ }
+ 
+ 
+ 
+ static int math_min (lua_State *L) {
++  /* scalars only */
+   int n = lua_gettop(L);  /* number of arguments */
+   lua_Number dmin = luaL_checknumber(L, 1);
+   int i;
+@@ -165,6 +262,7 @@ static int math_min (lua_State *L) {
+ 
+ 
+ static int math_max (lua_State *L) {
++  /* scalars only */
+   int n = lua_gettop(L);  /* number of arguments */
+   lua_Number dmax = luaL_checknumber(L, 1);
+   int i;
+@@ -182,25 +280,20 @@ static int math_random (lua_State *L) {
+   /* the `%' avoids the (rare) case of r==1, and is needed also because on
+      some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
+   lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
+-  switch (lua_gettop(L)) {  /* check number of arguments */
+-    case 0: {  /* no arguments */
+-      lua_pushnumber(L, r);  /* Number between 0 and 1 */
+-      break;
+-    }
+-    case 1: {  /* only upper limit */
+-      int u = luaL_checkint(L, 1);
+-      luaL_argcheck(L, 1<=u, 1, "interval is empty");
+-      lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */
+-      break;
+-    }
+-    case 2: {  /* lower and upper limits */
+-      int l = luaL_checkint(L, 1);
+-      int u = luaL_checkint(L, 2);
+-      luaL_argcheck(L, l<=u, 2, "interval is empty");
+-      lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */
+-      break;
+-    }
+-    default: return luaL_error(L, "wrong number of arguments");
++  int n= lua_gettop(L);  /* number of arguments */
++  if (n==0) {	/* no arguments: range [0,1) */
++    lua_pushnumber(L, r);
++  } else if (n<=2) {	/* int range [1,u] or [l,u] */
++    int l= n==1 ? 1 : luaL_checkint(L, 1);
++    int u = luaL_checkint(L, n);
++    int tmp;
++    lua_Number d;
++    luaL_argcheck(L, l<=u, n, "interval is empty");
++    d= _LF(floor)(r*(u-l+1));
++    lua_number2int(tmp,d);
++    lua_pushinteger(L, l+tmp);
++  } else {
++    return luaL_error(L, "wrong number of arguments");
+   }
+   return 1;
+ }
+@@ -211,6 +304,66 @@ static int math_randomseed (lua_State *L
+   return 0;
+ }
+ 
++/* 
++* Lua 5.1 does not have acosh, asinh, atanh for scalars (not ANSI C)
++*/
++#if __STDC_VERSION__ >= 199901L
++static int math_acosh (lua_State *L) {
++# ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(cacosh) (luaL_checkcomplex(L,1)));
++# else
++  lua_pushnumber(L, _LF(acosh) (luaL_checknumber(L,1)));
++# endif
++  return 1;
++}
++static int math_asinh (lua_State *L) {
++# ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(casinh) (luaL_checkcomplex(L,1)));
++# else
++  lua_pushnumber(L, _LF(asinh) (luaL_checknumber(L,1)));
++# endif
++  return 1;
++}
++static int math_atanh (lua_State *L) {
++# ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(catanh) (luaL_checkcomplex(L,1)));
++# else
++  lua_pushnumber(L, _LF(atanh) (luaL_checknumber(L,1)));
++# endif
++  return 1;
++}
++#endif
++
++/* 
++ * C99 complex functions, not covered above.
++*/
++#ifdef LNUM_COMPLEX
++static int math_arg (lua_State *L) {
++  lua_pushnumber(L, _LF(carg) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_imag (lua_State *L) {
++  lua_pushnumber(L, _LF(cimag) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_real (lua_State *L) {
++  lua_pushnumber(L, _LF(creal) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_conj (lua_State *L) {
++  lua_pushcomplex(L, _LF(conj) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_proj (lua_State *L) {
++  lua_pushcomplex(L, _LF(cproj) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++#endif
++
+ 
+ static const luaL_Reg mathlib[] = {
+   {"abs",   math_abs},
+@@ -241,6 +394,18 @@ static const luaL_Reg mathlib[] = {
+   {"sqrt",  math_sqrt},
+   {"tanh",   math_tanh},
+   {"tan",   math_tan},
++#if __STDC_VERSION__ >= 199901L
++  {"acosh",  math_acosh},
++  {"asinh",  math_asinh},
++  {"atanh",  math_atanh},
++#endif
++#ifdef LNUM_COMPLEX
++  {"arg",   math_arg},
++  {"imag",  math_imag},
++  {"real",  math_real},
++  {"conj",  math_conj},
++  {"proj",  math_proj},
++#endif
+   {NULL, NULL}
+ };
+ 
+@@ -252,8 +417,10 @@ LUALIB_API int luaopen_math (lua_State *
+   luaL_register(L, LUA_MATHLIBNAME, mathlib);
+   lua_pushnumber(L, PI);
+   lua_setfield(L, -2, "pi");
+-  lua_pushnumber(L, HUGE_VAL);
++  lua_pushnumber(L, HUGE);
+   lua_setfield(L, -2, "huge");
++  lua_pushinteger(L, LUA_INTEGER_MAX );
++  lua_setfield(L, -2, "hugeint");
+ #if defined(LUA_COMPAT_MOD)
+   lua_getfield(L, -1, "fmod");
+   lua_setfield(L, -2, "mod");
+--- /dev/null
++++ b/src/lnum.c
+@@ -0,0 +1,312 @@
++/*
++** $Id: lnum.c,v ... $
++** Internal number model
++** See Copyright Notice in lua.h
++*/
++
++#include <stdlib.h>
++#include <math.h>
++#include <ctype.h>
++#include <string.h>
++#include <stdio.h>
++#include <errno.h>
++
++#define lnum_c
++#define LUA_CORE
++
++#include "lua.h"
++#include "llex.h"
++#include "lnum.h"
++
++/*
++** lua_real2str converts a (non-complex) number to a string.
++** lua_str2real converts a string to a (non-complex) number.
++*/
++#define lua_real2str(s,n)  sprintf((s), LUA_NUMBER_FMT, (n))
++
++/*
++* Note: Only 'strtod()' is part of ANSI C; others are C99 and
++* may need '--std=c99' compiler setting (at least on Ubuntu 7.10).
++* 
++* Visual C++ 2008 Express does not have 'strtof()', nor 'strtold()'.
++* References to '_strtold()' exist but don't compile. It seems best
++* to leave Windows users with DOUBLE only (or compile with MinGW).
++*
++* In practise, using '(long double)strtod' is a risky thing, since
++* it will cause accuracy loss in reading in numbers, and such losses
++* will pile up in later processing. Get a real 'strtold()' or don't
++* use that mode at all.
++*/
++#ifdef LNUM_DOUBLE
++# define lua_str2real	strtod
++#elif defined(LNUM_FLOAT)
++# define lua_str2real	strtof
++#elif defined(LNUM_LDOUBLE)
++# define lua_str2real	strtold
++#endif
++
++#define lua_integer2str(s,v) sprintf((s), LUA_INTEGER_FMT, (v))
++
++/* 's' is expected to be LUAI_MAXNUMBER2STR long (enough for any number)
++*/
++void luaO_num2buf( char *s, const TValue *o )
++{
++  lua_Number n;
++  lua_assert( ttisnumber(o) );
++
++  /* Reason to handle integers differently is not only speed, but accuracy as
++   * well. We want to make any integer tostring() without roundings, at all.
++   */
++  if (ttisint(o)) {
++    lua_integer2str( s, ivalue(o) );
++    return;
++  }
++  n= nvalue_fast(o);
++  lua_real2str(s, n);
++
++#ifdef LNUM_COMPLEX
++  lua_Number n2= nvalue_img_fast(o);
++  if (n2!=0) {   /* Postfix with +-Ni */
++      int re0= (n == 0);
++      char *s2= re0 ? s : strchr(s,'\0'); 
++      if ((!re0) && (n2>0)) *s2++= '+';
++      lua_real2str( s2, n2 );
++      strcat(s2,"i");
++  }
++#endif
++}
++
++/*
++* If a LUA_TNUMBER has integer value, give it.
++*/
++int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref ) {
++  lua_Number d;
++  lua_Integer i;
++
++  lua_assert( ttype(o)==LUA_TNUMBER );
++  lua_assert( ref );
++#ifdef LNUM_COMPLEX
++  if (nvalue_img_fast(o)!=0) return 0;
++#endif
++  d= nvalue_fast(o);
++  lua_number2integer(i, d);
++  if (cast_num(i) == d) {
++    *ref= i; return 1;
++  }
++  return 0;
++}
++
++/* 
++ * Lua 5.1.3 (using 'strtod()') allows 0x+hex but not 0+octal. This is good,
++ * and we should NOT use 'autobase' 0 with 'strtoul[l]()' for this reason.
++ *
++ * Lua 5.1.3 allows '0x...' numbers to overflow and lose precision; this is not
++ * good. On Visual C++ 2008, 'strtod()' does not even take them in. Better to
++ * require hex values to fit 'lua_Integer' or give an error that they don't?
++ *
++ * Full hex range (0 .. 0xff..ff) is stored as integers, not to lose any bits.
++ * Numerical value of 0xff..ff will be -1, if used in calculations.
++ * 
++ * Returns: TK_INT for a valid integer, '*endptr_ref' updated
++ *          TK_NUMBER for seemingly numeric, to be parsed as floating point
++ *          0 for bad characters, not a number (or '0x' out of range)
++ */
++static int luaO_str2i (const char *s, lua_Integer *res, char **endptr_ref) {
++  char *endptr;
++  /* 'v' gets ULONG_MAX on possible overflow (which is > LUA_INTEGER_MAX);
++   * we don't have to check 'errno' here.
++   */
++  unsigned LUA_INTEGER v= lua_str2ul(s, &endptr, 10);
++  if (endptr == s) return 0;  /* nothing numeric */
++  if (v==0 && *endptr=='x') {
++    errno= 0;   /* needs to be set, 'strtoul[l]' does not clear it */
++    v= lua_str2ul(endptr+1, &endptr, 16);  /* retry as hex, unsigned range */
++    if (errno==ERANGE) {   /* clamped to 0xff..ff */
++#if (defined(LNUM_INT32) && !defined(LNUM_FLOAT)) || defined(LNUM_LDOUBLE)
++      return TK_NUMBER; /* Allow to be read as floating point (has more integer range) */
++#else
++      return 0;  /* Reject the number */
++#endif
++    }
++  } else if ((v > LUA_INTEGER_MAX) || (*endptr && (!isspace(*endptr)))) {
++    return TK_NUMBER;	/* not in signed range, or has '.', 'e' etc. trailing */
++  }
++  *res= (lua_Integer)v;
++  *endptr_ref= endptr;
++  return TK_INT;
++}
++
++/* 0 / TK_NUMBER / TK_INT (/ TK_NUMBER2) */
++int luaO_str2d (const char *s, lua_Number *res_n, lua_Integer *res_i) {
++  char *endptr;
++  int ret= TK_NUMBER;
++  /* Check integers first, if caller is allowing. 
++   * If 'res2'==NULL, they're only looking for floating point. 
++   */
++  if (res_i) {
++    ret= luaO_str2i(s,res_i,&endptr);
++    if (ret==0) return 0;
++  }
++  if (ret==TK_NUMBER) {
++    lua_assert(res_n);
++    /* Note: Visual C++ 2008 Express 'strtod()' does not read in "0x..."
++     *       numbers; it will read '0' and spit 'x' as endptr.
++     *       This means hex constants not fitting in 'lua_Integer' won't 
++     *       be read in at all. What to do?
++     */
++    *res_n = lua_str2real(s, &endptr);
++    if (endptr == s) return 0;  /* conversion failed */
++    /* Visual C++ 2008 'strtod()' does not allow "0x..." input. */
++#if defined(_MSC_VER) && !defined(LNUM_FLOAT) && !defined(LNUM_INT64)
++    if (*res_n==0 && *endptr=='x') {
++      /* Hex constant too big for 'lua_Integer' but that could fit in 'lua_Number'
++       * integer bits 
++       */
++      unsigned __int64 v= _strtoui64( s, &endptr, 16 );
++      /* We just let > 64 bit values be clamped to _UI64_MAX (MSDN does not say 'errno'==ERANGE would be set) */
++      *res_n= cast_num(v);
++      if (*res_n != v) return 0;    /* Would have lost accuracy */
++    }
++#endif
++#ifdef LNUM_COMPLEX
++    if (*endptr == 'i') { endptr++; ret= TK_NUMBER2; }
++#endif
++  }
++  if (*endptr) {
++    while (isspace(cast(unsigned char, *endptr))) endptr++;
++    if (*endptr) return 0;  /* invalid trail */
++  }
++  return ret;
++}
++
++
++/* Functions for finding out, when integer operations remain in range
++ * (and doing them).
++ */
++int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  lua_Integer v= ib+ic; /* may overflow */
++  if (ib>0 && ic>0)      { if (v < 0) return 0; /*overflow, use floats*/ }
++  else if (ib<0 && ic<0) { if (v >= 0) return 0; }
++  *r= v;
++  return 1;
++}
++
++int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  lua_Integer v= ib-ic; /* may overflow */
++  if (ib>=0 && ic<0)     { if (v < 0) return 0; /*overflow, use floats*/ }
++  else if (ib<0 && ic>0) { if (v >= 0) return 0; }
++  *r= v;
++  return 1;
++}
++
++int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  if (ib!=LUA_INTEGER_MIN && ic!=LUA_INTEGER_MIN) {
++    lua_Integer b= luai_abs(ib), c= luai_abs(ic);
++    if ( (ib==0) || (LUA_INTEGER_MAX/b >= c) ) {
++      *r= ib*ic;  /* no overflow */
++      return 1;
++    }
++  } else if (ib==0 || ic==0) {
++    *r= 0; return 1;
++  }
++
++  /* Result can be LUA_INTEGER_MIN; if it is, calculating it using floating 
++   * point will not cause accuracy loss.
++   */
++  if ( luai_nummul( cast_num(ib), cast_num(ic) ) == LUA_INTEGER_MIN ) {
++    *r= LUA_INTEGER_MIN;
++    return 1;
++  }
++  return 0;
++}
++
++int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  /* N/0: leave to float side, to give an error
++  */
++  if (ic==0) return 0;
++
++  /* N/LUA_INTEGER_MIN: always non-integer results, or 0 or +1
++  */
++  if (ic==LUA_INTEGER_MIN) {
++    if (ib==LUA_INTEGER_MIN) { *r=1; return 1; }
++    if (ib==0) { *r=0; return 1; }
++
++  /* LUA_INTEGER_MIN (-2^31|63)/N: calculate using float side (either the division 
++   *    causes non-integer results, or there is no accuracy loss in int->fp->int
++   *    conversions (N=2,4,8,..,256 and N=2^30,2^29,..2^23).
++   */
++  } else if (ib==LUA_INTEGER_MIN) {
++    lua_Number d= luai_numdiv( cast_num(LUA_INTEGER_MIN), cast_num(ic) );
++    lua_Integer i; lua_number2integer(i,d);
++    if (cast_num(i)==d) { *r= i; return 1; }
++  
++  } else {
++    /* Note: We _can_ use ANSI C mod here, even on negative values, since
++     *       we only test for == 0 (the sign would be implementation dependent).
++     */
++     if (ib%ic == 0) { *r= ib/ic; return 1; }
++  }
++
++  return 0;
++}
++
++int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  if (ic!=0) {
++    /* ANSI C can be trusted when b%c==0, or when values are non-negative. 
++     * b - (floor(b/c) * c)
++     *   -->
++     * + +: b - (b/c) * c (b % c can be used)
++     * - -: b - (b/c) * c (b % c could work, but not defined by ANSI C)
++     * 0 -: b - (b/c) * c (=0, b % c could work, but not defined by ANSI C)
++     * - +: b - (b/c-1) * c (when b!=-c)
++     * + -: b - (b/c-1) * c (when b!=-c)
++     *
++     * o MIN%MIN ends up 0, via overflow in calcs but that does not matter.
++     * o MIN%MAX ends up MAX-1 (and other such numbers), also after overflow,
++     *   but that does not matter, results do.
++     */
++    lua_Integer v= ib % ic;
++    if ( v!=0 && (ib<0 || ic<0) ) {
++      v= ib - ((ib/ic) - ((ib<=0 && ic<0) ? 0:1)) * ic;
++    }      
++    /* Result should always have same sign as 2nd argument. (PIL2) */
++    lua_assert( (v<0) ? (ic<0) : (v>0) ? (ic>0) : 1 );
++    *r= v;
++    return 1;
++  }
++  return 0;  /* let float side return NaN */
++}
++
++int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++
++    /* In FLOAT/INT32 or FLOAT|DOUBLE/INT64 modes, calculating integer powers 
++     * via FP realm may lose accuracy (i.e. 7^11 = 1977326743, which fits int32
++     * but not 23-bit float mantissa). 
++     *
++     * The current solution is dumb, but it works and uses little code. Use of
++     * integer powers is not anticipated to be very frequent (apart from 2^x,
++     * which is separately optimized).
++     */
++  if (ib==0) *r=0;
++  else if (ic<0) return 0;  /* FP realm */
++  else if (ib==2 && ic < (int)sizeof(lua_Integer)*8-1) *r= ((lua_Integer)1)<<ic;   /* 1,2,4,...2^30 | 2^62 optimization */
++  else if (ic==0) *r=1;
++  else if (luai_abs(ib)==1) *r= (ic%2) ? ib:1;
++  else {
++    lua_Integer x= ib;
++    while( --ic ) {
++      if (!try_mulint( &x, x, ib ))
++        return 0; /* FP realm */
++    }
++    *r= x;
++  }
++  return 1;
++}
++
++int try_unmint( lua_Integer *r, lua_Integer ib ) {
++  /* Negating LUA_INTEGER_MIN leaves the range. */
++  if ( ib != LUA_INTEGER_MIN )  
++    { *r= -ib; return 1; }
++  return 0;
++}
++
+--- /dev/null
++++ b/src/lnum.h
+@@ -0,0 +1,116 @@
++/*
++** $Id: lnum.h,v ... $
++** Internal Number model
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lnum_h
++#define lnum_h
++
++#include <math.h>
++
++#include "lobject.h"
++
++/*
++** The luai_num* macros define the primitive operations over 'lua_Number's
++** (not 'lua_Integer's, not 'lua_Complex').
++*/
++#define luai_numadd(a,b)	((a)+(b))
++#define luai_numsub(a,b)	((a)-(b))
++#define luai_nummul(a,b)	((a)*(b))
++#define luai_numdiv(a,b)	((a)/(b))
++#define luai_nummod(a,b)	((a) - _LF(floor)((a)/(b))*(b))
++#define luai_numpow(a,b)	(_LF(pow)(a,b))
++#define luai_numunm(a)		(-(a))
++#define luai_numeq(a,b)	    ((a)==(b))
++#define luai_numlt(a,b)	    ((a)<(b))
++#define luai_numle(a,b)	    ((a)<=(b))
++#define luai_numisnan(a)	(!luai_numeq((a), (a)))
++
++int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_unmint( lua_Integer *r, lua_Integer ib );
++
++#ifdef LNUM_COMPLEX
++  static inline lua_Complex luai_vectunm( lua_Complex a ) { return -a; }
++  static inline lua_Complex luai_vectadd( lua_Complex a, lua_Complex b ) { return a+b; }
++  static inline lua_Complex luai_vectsub( lua_Complex a, lua_Complex b ) { return a-b; }
++  static inline lua_Complex luai_vectmul( lua_Complex a, lua_Complex b ) { return a*b; }
++  static inline lua_Complex luai_vectdiv( lua_Complex a, lua_Complex b ) { return a/b; }
++
++/* 
++ * C99 does not provide modulus for complex numbers. It most likely is not
++ * meaningful at all.
++ */
++
++/* 
++ * Complex power
++ *
++ * C99 'cpow' gives inaccurate results for many common cases s.a. (1i)^2 -> 
++ * -1+1.2246467991474e-16i (OS X 10.4, gcc 4.0.1 build 5367)
++ * 
++ * [(a+bi)^(c+di)] = (r^c) * exp(-d*t) * cos(c*t + d*ln(r)) +
++ *                 = (r^c) * exp(-d*t) * sin(c*t + d*ln(r)) *i
++ * r = sqrt(a^2+b^2), t = arctan( b/a )
++ * 
++ * Reference: <http://home.att.net/~srschmitt/complexnumbers.html>
++ * Could also be calculated using: x^y = exp(ln(x)*y)
++ *
++ * Note: Defined here (and not in .c) so 'lmathlib.c' can share the 
++ *       implementation.
++ */
++  static inline
++  lua_Complex luai_vectpow( lua_Complex a, lua_Complex b )
++  {
++# if 1
++    lua_Number ar= _LF(creal)(a), ai= _LF(cimag)(a);
++    lua_Number br= _LF(creal)(b), bi= _LF(cimag)(b);
++    
++    if (ai==0 && bi==0) {     /* a^c (real) */
++        return luai_numpow( ar, br );
++    } 
++
++    int br_int= (int)br;
++    
++    if ( ai!=0 && bi==0 && br_int==br && br_int!=0 && br_int!=INT_MIN ) { 
++        /* (a+bi)^N, N = { +-1,+-2, ... +-INT_MAX } 
++        */
++        lua_Number k= luai_numpow( _LF(sqrt) (ar*ar + ai*ai), br );
++        lua_Number cos_z, sin_z;
++
++        /* Situation depends upon c (N) in the following manner:
++         * 
++         * N%4==0                                => cos(c*t)=1, sin(c*t)=0
++         * (N*sign(b))%4==1 or (N*sign(b))%4==-3 => cos(c*t)=0, sin(c*t)=1
++         * N%4==2 or N%4==-2                     => cos(c*t)=-1, sin(c*t)=0
++         * (N*sign(b))%4==-1 or (N*sign(b))%4==3 => cos(c*t)=0, sin(c*t)=-1
++         */
++      int br_int_abs = br_int<0 ? -br_int:br_int;
++      
++      switch( (br_int_abs%4) * (br_int<0 ? -1:1) * (ai<0 ? -1:1) ) {
++        case 0:             cos_z=1, sin_z=0; break;
++        case 2: case -2:    cos_z=-1, sin_z=0; break;
++        case 1: case -3:    cos_z=0, sin_z=1; break;
++        case 3: case -1:    cos_z=0, sin_z=-1; break;
++        default:            lua_assert(0); return 0;
++      }
++      return k*cos_z + (k*sin_z)*I;
++    }
++# endif
++    return _LF(cpow) ( a, b );
++  }
++#endif
++
++LUAI_FUNC int luaO_str2d (const char *s, lua_Number *res1, lua_Integer *res2);
++LUAI_FUNC void luaO_num2buf( char *s, const TValue *o );
++
++LUAI_FUNC int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref );
++
++#define luai_normalize(o) \
++{ lua_Integer _i; if (tt_integer_valued(o,&_i)) setivalue(o,_i); }
++
++#endif
+--- /dev/null
++++ b/src/lnum_config.h
+@@ -0,0 +1,221 @@
++/*
++** $Id: lnum_config.h,v ... $
++** Internal Number model
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lnum_config_h
++#define lnum_config_h
++
++/*
++** Default number modes
++*/
++#if (!defined LNUM_DOUBLE) && (!defined LNUM_FLOAT) && (!defined LNUM_LDOUBLE)
++# define LNUM_FLOAT
++#endif
++#if (!defined LNUM_INT16) && (!defined LNUM_INT32) && (!defined LNUM_INT64)
++# define LNUM_INT32
++#endif
++
++/*
++** Require C99 mode for COMPLEX, FLOAT and LDOUBLE (only DOUBLE is ANSI C).
++*/
++#if defined(LNUM_COMPLEX) && (__STDC_VERSION__ < 199901L)
++# error "Need C99 for complex (use '--std=c99' or similar)"
++#elif defined(LNUM_LDOUBLE) && (__STDC_VERSION__ < 199901L) && !defined(_MSC_VER)
++# error "Need C99 for 'long double' (use '--std=c99' or similar)"
++#elif defined(LNUM_FLOAT) && (__STDC_VERSION__ < 199901L)
++/* LNUM_FLOAT not supported on Windows */
++# error "Need C99 for 'float' (use '--std=c99' or similar)"
++#endif
++ 
++/*
++** Number mode identifier to accompany the version string.
++*/
++#ifdef LNUM_COMPLEX
++# define _LNUM1 "complex "
++#else
++# define _LNUM1 ""
++#endif
++#ifdef LNUM_DOUBLE
++# define _LNUM2 "double"
++#elif defined(LNUM_FLOAT)
++# define _LNUM2 "float"
++#elif defined(LNUM_LDOUBLE)
++# define _LNUM2 "ldouble"
++#endif
++#ifdef LNUM_INT32
++# define _LNUM3 "int32"
++#elif defined(LNUM_INT64)
++# define _LNUM3 "int64"
++#elif defined(LNUM_INT16)
++# define _LNUM3 "int16"
++#endif
++#define LUA_LNUM _LNUM1 _LNUM2 " " _LNUM3
++
++/*
++** LUA_NUMBER is the type of floating point number in Lua
++** LUA_NUMBER_SCAN is the format for reading numbers.
++** LUA_NUMBER_FMT is the format for writing numbers.
++*/
++#ifdef LNUM_FLOAT
++# define LUA_NUMBER         float
++# define LUA_NUMBER_SCAN    "%f"
++# define LUA_NUMBER_FMT     "%g"  
++#elif (defined LNUM_DOUBLE)
++# define LUA_NUMBER	        double
++# define LUA_NUMBER_SCAN    "%lf"
++# define LUA_NUMBER_FMT     "%.14g"
++#elif (defined LNUM_LDOUBLE)
++# define LUA_NUMBER         long double
++# define LUA_NUMBER_SCAN    "%Lg"
++# define LUA_NUMBER_FMT     "%.20Lg"
++#endif
++
++
++/* 
++** LUAI_MAXNUMBER2STR: size of a buffer fitting any number->string result.
++**
++**  double:  24 (sign, x.xxxxxxxxxxxxxxe+nnnn, and \0)
++**  int64:   21 (19 digits, sign, and \0)
++**  long double: 43 for 128-bit (sign, x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe+nnnn, and \0)
++**           30 for 80-bit (sign, x.xxxxxxxxxxxxxxxxxxxxe+nnnn, and \0)
++*/
++#ifdef LNUM_LDOUBLE
++# define _LUAI_MN2S 44
++#else
++# define _LUAI_MN2S 24
++#endif
++
++#ifdef LNUM_COMPLEX
++# define LUAI_MAXNUMBER2STR (2*_LUAI_MN2S)
++#else
++# define LUAI_MAXNUMBER2STR _LUAI_MN2S
++#endif
++
++/*
++** LUA_INTEGER is the integer type used by lua_pushinteger/lua_tointeger/lua_isinteger.
++** LUA_INTEGER_SCAN is the format for reading integers
++** LUA_INTEGER_FMT is the format for writing integers
++**
++** Note: Visual C++ 2005 does not have 'strtoull()', use '_strtoui64()' instead.
++*/
++#ifdef LNUM_INT32
++# if LUAI_BITSINT > 16
++#  define LUA_INTEGER   int
++#  define LUA_INTEGER_SCAN "%d"
++#  define LUA_INTEGER_FMT "%d"
++# else
++/* Note: 'LUA_INTEGER' being 'ptrdiff_t' (as in Lua 5.1) causes problems with
++ *       'printf()' operations. Also 'unsigned ptrdiff_t' is invalid.
++ */
++#  define LUA_INTEGER   long
++#  define LUA_INTEGER_SCAN "%ld"
++#  define LUA_INTEGER_FMT "%ld"
++# endif
++# define LUA_INTEGER_MAX 0x7FFFFFFF             /* 2^31-1 */
++/* */
++#elif defined(LNUM_INT64)
++# define LUA_INTEGER	long long
++# ifdef _MSC_VER
++#  define lua_str2ul    _strtoui64
++# else
++#  define lua_str2ul    strtoull
++# endif
++# define LUA_INTEGER_SCAN "%lld"
++# define LUA_INTEGER_FMT "%lld"
++# define LUA_INTEGER_MAX 0x7fffffffffffffffLL       /* 2^63-1 */ 
++# define LUA_INTEGER_MIN (-LUA_INTEGER_MAX - 1LL)   /* -2^63 */
++/* */
++#elif defined(LNUM_INT16)
++# if LUAI_BITSINT > 16
++#  define LUA_INTEGER    short
++#  define LUA_INTEGER_SCAN "%hd"
++#  define LUA_INTEGER_FMT "%hd"
++# else
++#  define LUA_INTEGER    int
++#  define LUA_INTEGER_SCAN "%d"
++#  define LUA_INTEGER_FMT "%d"
++# endif
++# define LUA_INTEGER_MAX 0x7FFF             /* 2^16-1 */
++#endif
++
++#ifndef lua_str2ul
++# define lua_str2ul (unsigned LUA_INTEGER)strtoul
++#endif
++#ifndef LUA_INTEGER_MIN
++# define LUA_INTEGER_MIN (-LUA_INTEGER_MAX -1)  /* -2^16|32 */
++#endif
++
++/*
++@@ lua_number2int is a macro to convert lua_Number to int.
++@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
++** CHANGE them if you know a faster way to convert a lua_Number to
++** int (with any rounding method and without throwing errors) in your
++** system. In Pentium machines, a naive typecast from double to int
++** in C is extremely slow, so any alternative is worth trying.
++*/
++
++/* On a Pentium, resort to a trick */
++#if defined(LNUM_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
++    (defined(__i386) || defined (_M_IX86) || defined(__i386__))
++
++/* On a Microsoft compiler, use assembler */
++# if defined(_MSC_VER)
++#  define lua_number2int(i,d)   __asm fld d   __asm fistp i
++# else
++
++/* the next trick should work on any Pentium, but sometimes clashes
++   with a DirectX idiosyncrasy */
++union luai_Cast { double l_d; long l_l; };
++#  define lua_number2int(i,d) \
++  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
++# endif
++
++# ifndef LNUM_INT64
++#  define lua_number2integer    lua_number2int
++# endif
++
++/* this option always works, but may be slow */
++#else
++# define lua_number2int(i,d)        ((i)=(int)(d))
++#endif
++
++/* Note: Some compilers (OS X gcc 4.0?) may choke on double->long long conversion 
++ *       since it can lose precision. Others do require 'long long' there.  
++ */
++#ifndef lua_number2integer
++# define lua_number2integer(i,d)    ((i)=(lua_Integer)(d))
++#endif
++
++/*
++** 'luai_abs()' to give absolute value of 'lua_Integer'
++*/
++#ifdef LNUM_INT32
++# define luai_abs abs
++#elif defined(LNUM_INT64) && (__STDC_VERSION__ >= 199901L)
++# define luai_abs llabs
++#else
++# define luai_abs(v) ((v) >= 0 ? (v) : -(v))
++#endif
++
++/*
++** LUAI_UACNUMBER is the result of an 'usual argument conversion' over a number.
++** LUAI_UACINTEGER the same, over an integer.
++*/
++#define LUAI_UACNUMBER	double
++#define LUAI_UACINTEGER long
++
++/* ANSI C only has math funcs for 'double. C99 required for float and long double
++ * variants.
++ */
++#ifdef LNUM_DOUBLE
++# define _LF(name) name
++#elif defined(LNUM_FLOAT)
++# define _LF(name) name ## f
++#elif defined(LNUM_LDOUBLE)
++# define _LF(name) name ## l
++#endif
++
++#endif
++
+--- a/src/lobject.c
++++ b/src/lobject.c
+@@ -21,7 +21,8 @@
+ #include "lstate.h"
+ #include "lstring.h"
+ #include "lvm.h"
+-
++#include "llex.h"
++#include "lnum.h"
+ 
+ 
+ const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL};
+@@ -70,12 +71,31 @@ int luaO_log2 (unsigned int x) {
+ 
+ 
+ int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
+-  if (ttype(t1) != ttype(t2)) return 0;
++  if (!ttype_ext_same(t1,t2)) return 0;
+   else switch (ttype(t1)) {
+     case LUA_TNIL:
+       return 1;
++    case LUA_TINT:
++      if (ttype(t2)==LUA_TINT)
++        return ivalue(t1) == ivalue(t2);
++      else {  /* t1:int, t2:num */
++#ifdef LNUM_COMPLEX
++        if (nvalue_img_fast(t2) != 0) return 0;
++#endif
++        /* Avoid doing accuracy losing cast, if possible. */
++        lua_Integer tmp;
++        if (tt_integer_valued(t2,&tmp)) 
++          return ivalue(t1) == tmp;
++        else
++          return luai_numeq( cast_num(ivalue(t1)), nvalue_fast(t2) );
++        }
+     case LUA_TNUMBER:
+-      return luai_numeq(nvalue(t1), nvalue(t2));
++        if (ttype(t2)==LUA_TINT)
++          return luaO_rawequalObj(t2, t1);  /* swap LUA_TINT to left */
++#ifdef LNUM_COMPLEX
++        if (!luai_numeq(nvalue_img_fast(t1), nvalue_img_fast(t2))) return 0;
++#endif
++        return luai_numeq(nvalue_fast(t1), nvalue_fast(t2));
+     case LUA_TBOOLEAN:
+       return bvalue(t1) == bvalue(t2);  /* boolean true must be 1 !! */
+     case LUA_TLIGHTUSERDATA:
+@@ -86,21 +106,6 @@ int luaO_rawequalObj (const TValue *t1, 
+   }
+ }
+ 
+-
+-int luaO_str2d (const char *s, lua_Number *result) {
+-  char *endptr;
+-  *result = lua_str2number(s, &endptr);
+-  if (endptr == s) return 0;  /* conversion failed */
+-  if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */
+-    *result = cast_num(strtoul(s, &endptr, 16));
+-  if (*endptr == '\0') return 1;  /* most common case */
+-  while (isspace(cast(unsigned char, *endptr))) endptr++;
+-  if (*endptr != '\0') return 0;  /* invalid trailing characters? */
+-  return 1;
+-}
+-
+-
+-
+ static void pushstr (lua_State *L, const char *str) {
+   setsvalue2s(L, L->top, luaS_new(L, str));
+   incr_top(L);
+@@ -131,7 +136,11 @@ const char *luaO_pushvfstring (lua_State
+         break;
+       }
+       case 'd': {
+-        setnvalue(L->top, cast_num(va_arg(argp, int)));
++        /* This is tricky for 64-bit integers; maybe they even cannot be
++         * supported on all compilers; depends on the conversions applied to
++         * variable argument lists. TBD: test!
++         */
++        setivalue(L->top, (lua_Integer) va_arg(argp, l_uacInteger));
+         incr_top(L);
+         break;
+       }
+@@ -212,3 +221,4 @@ void luaO_chunkid (char *out, const char
+     }
+   }
+ }
++
+--- a/src/lobject.h
++++ b/src/lobject.h
+@@ -17,7 +17,11 @@
+ 
+ 
+ /* tags for values visible from Lua */
+-#define LAST_TAG	LUA_TTHREAD
++#if LUA_TINT > LUA_TTHREAD
++# define LAST_TAG   LUA_TINT
++#else
++# define LAST_TAG	LUA_TTHREAD
++#endif
+ 
+ #define NUM_TAGS	(LAST_TAG+1)
+ 
+@@ -59,7 +63,12 @@ typedef struct GCheader {
+ typedef union {
+   GCObject *gc;
+   void *p;
++#ifdef LNUM_COMPLEX
++  lua_Complex n;
++#else
+   lua_Number n;
++#endif
++  lua_Integer i;
+   int b;
+ } Value;
+ 
+@@ -77,7 +86,11 @@ typedef struct lua_TValue {
+ 
+ /* Macros to test type */
+ #define ttisnil(o)	(ttype(o) == LUA_TNIL)
+-#define ttisnumber(o)	(ttype(o) == LUA_TNUMBER)
++#define ttisint(o) (ttype(o) == LUA_TINT)
++#define ttisnumber(o) ((ttype(o) == LUA_TINT) || (ttype(o) == LUA_TNUMBER))
++#ifdef LNUM_COMPLEX
++# define ttiscomplex(o) ((ttype(o) == LUA_TNUMBER) && (nvalue_img_fast(o)!=0))
++#endif
+ #define ttisstring(o)	(ttype(o) == LUA_TSTRING)
+ #define ttistable(o)	(ttype(o) == LUA_TTABLE)
+ #define ttisfunction(o)	(ttype(o) == LUA_TFUNCTION)
+@@ -90,7 +103,25 @@ typedef struct lua_TValue {
+ #define ttype(o)	((o)->tt)
+ #define gcvalue(o)	check_exp(iscollectable(o), (o)->value.gc)
+ #define pvalue(o)	check_exp(ttislightuserdata(o), (o)->value.p)
+-#define nvalue(o)	check_exp(ttisnumber(o), (o)->value.n)
++
++#define ttype_ext(o) ( ttype(o) == LUA_TINT ? LUA_TNUMBER : ttype(o) )
++#define ttype_ext_same(o1,o2) ( (ttype(o1)==ttype(o2)) || (ttisnumber(o1) && ttisnumber(o2)) )
++
++/* '_fast' variants are for cases where 'ttype(o)' is known to be LUA_TNUMBER.
++ */
++#ifdef LNUM_COMPLEX
++#  define nvalue_complex_fast(o) check_exp( ttype(o)==LUA_TNUMBER, (o)->value.n )   
++#  define nvalue_fast(o)     ( _LF(creal) ( nvalue_complex_fast(o) ) )
++#  define nvalue_img_fast(o) ( _LF(cimag) ( nvalue_complex_fast(o) ) )
++#  define nvalue_complex(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? (o)->value.i : (o)->value.n )
++#  define nvalue_img(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? 0 : _LF(cimag)( (o)->value.n ) ) 
++#  define nvalue(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? cast_num((o)->value.i) : _LF(creal)((o)->value.n) ) 
++#else
++# define nvalue(o)	check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? cast_num((o)->value.i) : (o)->value.n )
++# define nvalue_fast(o) check_exp( ttype(o)==LUA_TNUMBER, (o)->value.n )   
++#endif
++#define ivalue(o)	check_exp( ttype(o)==LUA_TINT, (o)->value.i )
++
+ #define rawtsvalue(o)	check_exp(ttisstring(o), &(o)->value.gc->ts)
+ #define tsvalue(o)	(&rawtsvalue(o)->tsv)
+ #define rawuvalue(o)	check_exp(ttisuserdata(o), &(o)->value.gc->u)
+@@ -116,8 +147,27 @@ typedef struct lua_TValue {
+ /* Macros to set values */
+ #define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
+ 
+-#define setnvalue(obj,x) \
+-  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
++/* Must not have side effects, 'x' may be expression.
++*/
++#define setivalue(obj,x) \
++    { TValue *i_o=(obj); i_o->value.i=(x); i_o->tt=LUA_TINT; }
++
++# define setnvalue(obj,x) \
++    { TValue *i_o=(obj); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; }
++
++/* Note: Complex always has "inline", both are C99.
++*/
++#ifdef LNUM_COMPLEX
++  static inline void setnvalue_complex_fast( TValue *obj, lua_Complex x ) {
++    lua_assert( _LF(cimag)(x) != 0 );
++    obj->value.n= x; obj->tt= LUA_TNUMBER;
++  }
++  static inline void setnvalue_complex( TValue *obj, lua_Complex x ) {
++    if (_LF(cimag)(x) == 0) { setnvalue(obj, _LF(creal)(x)); }
++    else { obj->value.n= x; obj->tt= LUA_TNUMBER; }
++  }
++#endif
++
+ 
+ #define setpvalue(obj,x) \
+   { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
+@@ -155,9 +205,6 @@ typedef struct lua_TValue {
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
+     checkliveness(G(L),i_o); }
+ 
+-
+-
+-
+ #define setobj(L,obj1,obj2) \
+   { const TValue *o2=(obj2); TValue *o1=(obj1); \
+     o1->value = o2->value; o1->tt=o2->tt; \
+@@ -185,8 +232,11 @@ typedef struct lua_TValue {
+ 
+ #define setttype(obj, tt) (ttype(obj) = (tt))
+ 
+-
+-#define iscollectable(o)	(ttype(o) >= LUA_TSTRING)
++#if LUA_TINT >= LUA_TSTRING
++# define iscollectable(o)	((ttype(o) >= LUA_TSTRING) && (ttype(o) != LUA_TINT))
++#else
++# define iscollectable(o)	(ttype(o) >= LUA_TSTRING)
++#endif
+ 
+ 
+ 
+@@ -370,12 +420,10 @@ LUAI_FUNC int luaO_log2 (unsigned int x)
+ LUAI_FUNC int luaO_int2fb (unsigned int x);
+ LUAI_FUNC int luaO_fb2int (int x);
+ LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
+-LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
+ LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
+                                                        va_list argp);
+ LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
+ LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
+ 
+-
+ #endif
+ 
+--- a/src/loslib.c
++++ b/src/loslib.c
+@@ -186,15 +186,30 @@ static int os_time (lua_State *L) {
+   }
+   if (t == (time_t)(-1))
+     lua_pushnil(L);
+-  else
+-    lua_pushnumber(L, (lua_Number)t);
++  else {
++     /* On float systems the pushed value must be an integer, NOT a number.
++      * Otherwise, accuracy is lost in the time_t->float conversion.
++      */
++#ifdef LNUM_FLOAT
++     lua_pushinteger(L, (lua_Integer) t);
++#else
++     lua_pushnumber(L, (lua_Number) t);
++#endif
++     }
+   return 1;
+ }
+ 
+ 
+ static int os_difftime (lua_State *L) {
++#ifdef LNUM_FLOAT
++  lua_Integer i= (lua_Integer)
++    difftime( (time_t)(luaL_checkinteger(L, 1)),
++              (time_t)(luaL_optinteger(L, 2, 0)));
++  lua_pushinteger(L, i);
++#else
+   lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
+                              (time_t)(luaL_optnumber(L, 2, 0))));
++#endif
+   return 1;
+ }
+ 
+--- a/src/lparser.c
++++ b/src/lparser.c
+@@ -33,7 +33,6 @@
+ 
+ #define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) errorlimit(fs,l,m)
+ 
+-
+ /*
+ ** nodes for block list (list of active blocks)
+ */
+@@ -72,7 +71,7 @@ static void errorlimit (FuncState *fs, i
+   const char *msg = (fs->f->linedefined == 0) ?
+     luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
+     luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
+-                            fs->f->linedefined, limit, what);
++                            (fs->f->linedefined), limit, what);
+   luaX_lexerror(fs->ls, msg, 0);
+ }
+ 
+@@ -733,6 +732,18 @@ static void simpleexp (LexState *ls, exp
+       v->u.nval = ls->t.seminfo.r;
+       break;
+     }
++    case TK_INT: {
++      init_exp(v, VKINT, 0);
++      v->u.ival = ls->t.seminfo.i;
++      break;
++    }
++#ifdef LNUM_COMPLEX
++    case TK_NUMBER2: {
++      init_exp(v, VKNUM2, 0);
++      v->u.nval = ls->t.seminfo.r;
++      break;
++    }
++#endif
+     case TK_STRING: {
+       codestring(ls, v, ls->t.seminfo.ts);
+       break;
+@@ -1079,7 +1090,7 @@ static void fornum (LexState *ls, TStrin
+   if (testnext(ls, ','))
+     exp1(ls);  /* optional step */
+   else {  /* default step = 1 */
+-    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
++    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_integerK(fs, 1));
+     luaK_reserveregs(fs, 1);
+   }
+   forbody(ls, base, line, 1, 1);
+--- a/src/lparser.h
++++ b/src/lparser.h
+@@ -31,7 +31,11 @@ typedef enum {
+   VRELOCABLE,	/* info = instruction pc */
+   VNONRELOC,	/* info = result register */
+   VCALL,	/* info = instruction pc */
+-  VVARARG	/* info = instruction pc */
++  VVARARG,	/* info = instruction pc */
++  VKINT     /* ival = integer value */
++#ifdef LNUM_COMPLEX
++  ,VKNUM2   /* nval = imaginary value */
++#endif
+ } expkind;
+ 
+ typedef struct expdesc {
+@@ -39,6 +43,7 @@ typedef struct expdesc {
+   union {
+     struct { int info, aux; } s;
+     lua_Number nval;
++    lua_Integer ival;
+   } u;
+   int t;  /* patch list of `exit when true' */
+   int f;  /* patch list of `exit when false' */
+--- a/src/lstrlib.c
++++ b/src/lstrlib.c
+@@ -43,8 +43,8 @@ static ptrdiff_t posrelat (ptrdiff_t pos
+ static int str_sub (lua_State *L) {
+   size_t l;
+   const char *s = luaL_checklstring(L, 1, &l);
+-  ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
+-  ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
++  ptrdiff_t start = posrelat(luaL_checkint32(L, 2), l);
++  ptrdiff_t end = posrelat(luaL_optint32(L, 3, -1), l);
+   if (start < 1) start = 1;
+   if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
+   if (start <= end)
+@@ -106,8 +106,8 @@ static int str_rep (lua_State *L) {
+ static int str_byte (lua_State *L) {
+   size_t l;
+   const char *s = luaL_checklstring(L, 1, &l);
+-  ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
+-  ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
++  ptrdiff_t posi = posrelat(luaL_optint32(L, 2, 1), l);
++  ptrdiff_t pose = posrelat(luaL_optint32(L, 3, posi), l);
+   int n, i;
+   if (posi <= 0) posi = 1;
+   if ((size_t)pose > l) pose = l;
+@@ -496,7 +496,7 @@ static int str_find_aux (lua_State *L, i
+   size_t l1, l2;
+   const char *s = luaL_checklstring(L, 1, &l1);
+   const char *p = luaL_checklstring(L, 2, &l2);
+-  ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
++  ptrdiff_t init = posrelat(luaL_optint32(L, 3, 1), l1) - 1;
+   if (init < 0) init = 0;
+   else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
+   if (find && (lua_toboolean(L, 4) ||  /* explicit request? */
+@@ -690,7 +690,7 @@ static int str_gsub (lua_State *L) {
+ ** maximum size of each format specification (such as '%-099.99d')
+ ** (+10 accounts for %99.99x plus margin of error)
+ */
+-#define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
++#define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTEGER_FMT)-2 + 10)
+ 
+ 
+ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+@@ -747,9 +747,9 @@ static const char *scanformat (lua_State
+ static void addintlen (char *form) {
+   size_t l = strlen(form);
+   char spec = form[l - 1];
+-  strcpy(form + l - 1, LUA_INTFRMLEN);
+-  form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
+-  form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
++  const char *tmp= LUA_INTEGER_FMT;   /* "%lld" or "%ld" */
++  strcpy(form + l - 1, tmp+1);
++  form[l + sizeof(LUA_INTEGER_FMT)-4] = spec;
+ }
+ 
+ 
+@@ -779,12 +779,12 @@ static int str_format (lua_State *L) {
+         }
+         case 'd':  case 'i': {
+           addintlen(form);
+-          sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
++          sprintf(buff, form, luaL_checkinteger(L, arg));
+           break;
+         }
+         case 'o':  case 'u':  case 'x':  case 'X': {
+           addintlen(form);
+-          sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
++          sprintf(buff, form, (unsigned LUA_INTEGER)luaL_checkinteger(L, arg));
+           break;
+         }
+         case 'e':  case 'E': case 'f':
+--- a/src/ltable.c
++++ b/src/ltable.c
+@@ -33,6 +33,7 @@
+ #include "lobject.h"
+ #include "lstate.h"
+ #include "ltable.h"
++#include "lnum.h"
+ 
+ 
+ /*
+@@ -51,25 +52,15 @@
+   
+ #define hashstr(t,str)  hashpow2(t, (str)->tsv.hash)
+ #define hashboolean(t,p)        hashpow2(t, p)
+-
++#define hashint(t,i)    hashpow2(t,i)
+ 
+ /*
+ ** for some types, it is better to avoid modulus by power of 2, as
+ ** they tend to have many 2 factors.
+ */
+ #define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))
+-
+-
+ #define hashpointer(t,p)	hashmod(t, IntPoint(p))
+ 
+-
+-/*
+-** number of ints inside a lua_Number
+-*/
+-#define numints		cast_int(sizeof(lua_Number)/sizeof(int))
+-
+-
+-
+ #define dummynode		(&dummynode_)
+ 
+ static const Node dummynode_ = {
+@@ -80,27 +71,46 @@ static const Node dummynode_ = {
+ 
+ /*
+ ** hash for lua_Numbers
++**
++** for non-complex modes, never called with 'lua_Integer' value range (s.a. 0)
+ */
+ static Node *hashnum (const Table *t, lua_Number n) {
+-  unsigned int a[numints];
+-  int i;
+-  if (luai_numeq(n, 0))  /* avoid problems with -0 */
+-    return gnode(t, 0);
+-  memcpy(a, &n, sizeof(a));
+-  for (i = 1; i < numints; i++) a[0] += a[i];
+-  return hashmod(t, a[0]);
++  const unsigned int *p= cast(const unsigned int *,&n);
++  unsigned int sum= *p;
++  unsigned int m= sizeof(lua_Number)/sizeof(int);
++  unsigned int i;
++  /* OS X Intel has 'm'==4 and gives "Bus error" if the last integer of 
++   * 'n' is read; the actual size of long double is only 80 bits = 10 bytes.
++   * Linux x86 has 'm'==3, and does not require reduction.
++   */
++#if defined(LNUM_LDOUBLE) && defined(__i386__)
++  if (m>3) m--;
++#endif
++  for (i = 1; i < m; i++) sum += p[i];
++  return hashmod(t, sum);
+ }
+ 
+ 
+-
+ /*
+ ** returns the `main' position of an element in a table (that is, the index
+ ** of its hash value)
++**
++** Floating point numbers with integer value give the hash position of the
++** integer (so they use the same table position).
+ */
+ static Node *mainposition (const Table *t, const TValue *key) {
++  lua_Integer i;
+   switch (ttype(key)) {
+     case LUA_TNUMBER:
+-      return hashnum(t, nvalue(key));
++      if (tt_integer_valued(key,&i)) 
++        return hashint(t, i);
++#ifdef LNUM_COMPLEX
++      if (nvalue_img_fast(key)!=0 && luai_numeq(nvalue_fast(key),0))
++        return gnode(t, 0);  /* 0 and -0 to give same hash */
++#endif
++      return hashnum(t, nvalue_fast(key));
++    case LUA_TINT:
++      return hashint(t, ivalue(key));
+     case LUA_TSTRING:
+       return hashstr(t, rawtsvalue(key));
+     case LUA_TBOOLEAN:
+@@ -116,16 +126,20 @@ static Node *mainposition (const Table *
+ /*
+ ** returns the index for `key' if `key' is an appropriate key to live in
+ ** the array part of the table, -1 otherwise.
++**
++** Anything <=0 is taken as not being in the array part.
+ */
+-static int arrayindex (const TValue *key) {
+-  if (ttisnumber(key)) {
+-    lua_Number n = nvalue(key);
+-    int k;
+-    lua_number2int(k, n);
+-    if (luai_numeq(cast_num(k), n))
+-      return k;
++static int arrayindex (const TValue *key, int max) {
++  lua_Integer k;
++  switch( ttype(key) ) {
++    case LUA_TINT:
++      k= ivalue(key); break;
++    case LUA_TNUMBER:
++      if (tt_integer_valued(key,&k)) break;
++    default:
++      return -1;  /* not to be used as array index */
+   }
+-  return -1;  /* `key' did not match some condition */
++  return ((k>0) && (k <= max)) ? cast_int(k) : -1;
+ }
+ 
+ 
+@@ -137,8 +151,8 @@ static int arrayindex (const TValue *key
+ static int findindex (lua_State *L, Table *t, StkId key) {
+   int i;
+   if (ttisnil(key)) return -1;  /* first iteration */
+-  i = arrayindex(key);
+-  if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */
++  i = arrayindex(key, t->sizearray);
++  if (i>0)  /* inside array part? */
+     return i-1;  /* yes; that's the index (corrected to C) */
+   else {
+     Node *n = mainposition(t, key);
+@@ -163,7 +177,7 @@ int luaH_next (lua_State *L, Table *t, S
+   int i = findindex(L, t, key);  /* find original element */
+   for (i++; i < t->sizearray; i++) {  /* try first array part */
+     if (!ttisnil(&t->array[i])) {  /* a non-nil value? */
+-      setnvalue(key, cast_num(i+1));
++      setivalue(key, i+1);
+       setobj2s(L, key+1, &t->array[i]);
+       return 1;
+     }
+@@ -209,8 +223,8 @@ static int computesizes (int nums[], int
+ 
+ 
+ static int countint (const TValue *key, int *nums) {
+-  int k = arrayindex(key);
+-  if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */
++  int k = arrayindex(key,MAXASIZE);
++  if (k>0) {  /* appropriate array index? */
+     nums[ceillog2(k)]++;  /* count as such */
+     return 1;
+   }
+@@ -308,7 +322,7 @@ static void resize (lua_State *L, Table 
+     /* re-insert elements from vanishing slice */
+     for (i=nasize; i<oldasize; i++) {
+       if (!ttisnil(&t->array[i]))
+-        setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
++        setobjt2t(L, luaH_setint(L, t, i+1), &t->array[i]);
+     }
+     /* shrink array */
+     luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
+@@ -409,7 +423,9 @@ static TValue *newkey (lua_State *L, Tab
+     othern = mainposition(t, key2tval(mp));
+     if (othern != mp) {  /* is colliding node out of its main position? */
+       /* yes; move colliding node into free position */
+-      while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */
++      while (gnext(othern) != mp) {
++        othern = gnext(othern);  /* find previous */
++      }
+       gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
+       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
+       gnext(mp) = NULL;  /* now `mp' is free */
+@@ -432,17 +448,18 @@ static TValue *newkey (lua_State *L, Tab
+ /*
+ ** search function for integers
+ */
+-const TValue *luaH_getnum (Table *t, int key) {
++const TValue *luaH_getint (Table *t, lua_Integer key) {
+   /* (1 <= key && key <= t->sizearray) */
+   if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
+     return &t->array[key-1];
+   else {
+-    lua_Number nk = cast_num(key);
+-    Node *n = hashnum(t, nk);
++    Node *n = hashint(t, key);
+     do {  /* check whether `key' is somewhere in the chain */
+-      if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
++      if (ttisint(gkey(n)) && (ivalue(gkey(n)) == key)) {
+         return gval(n);  /* that's it */
+-      else n = gnext(n);
++      } else { 
++      n = gnext(n);
++    }
+     } while (n);
+     return luaO_nilobject;
+   }
+@@ -470,14 +487,12 @@ const TValue *luaH_get (Table *t, const 
+   switch (ttype(key)) {
+     case LUA_TNIL: return luaO_nilobject;
+     case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
++    case LUA_TINT: return luaH_getint(t, ivalue(key));
+     case LUA_TNUMBER: {
+-      int k;
+-      lua_Number n = nvalue(key);
+-      lua_number2int(k, n);
+-      if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
+-        return luaH_getnum(t, k);  /* use specialized version */
+-      /* else go through */
+-    }
++      lua_Integer i;
++      if (tt_integer_valued(key,&i))
++        return luaH_getint(t,i);
++    } /* pass through */
+     default: {
+       Node *n = mainposition(t, key);
+       do {  /* check whether `key' is somewhere in the chain */
+@@ -498,20 +513,25 @@ TValue *luaH_set (lua_State *L, Table *t
+     return cast(TValue *, p);
+   else {
+     if (ttisnil(key)) luaG_runerror(L, "table index is nil");
+-    else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
+-      luaG_runerror(L, "table index is NaN");
++    else if (ttype(key)==LUA_TNUMBER) {
++      lua_Integer k;
++      if (luai_numisnan(nvalue_fast(key)))
++        luaG_runerror(L, "table index is NaN");
++      if (tt_integer_valued(key,&k))
++        return luaH_setint(L, t, k);
++    }
+     return newkey(L, t, key);
+   }
+ }
+ 
+ 
+-TValue *luaH_setnum (lua_State *L, Table *t, int key) {
+-  const TValue *p = luaH_getnum(t, key);
++TValue *luaH_setint (lua_State *L, Table *t, lua_Integer key) {
++  const TValue *p = luaH_getint(t, key);
+   if (p != luaO_nilobject)
+     return cast(TValue *, p);
+   else {
+     TValue k;
+-    setnvalue(&k, cast_num(key));
++    setivalue(&k, key);
+     return newkey(L, t, &k);
+   }
+ }
+@@ -533,20 +553,21 @@ static int unbound_search (Table *t, uns
+   unsigned int i = j;  /* i is zero or a present index */
+   j++;
+   /* find `i' and `j' such that i is present and j is not */
+-  while (!ttisnil(luaH_getnum(t, j))) {
++  while (!ttisnil(luaH_getint(t, j))) {
+     i = j;
+     j *= 2;
+     if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */
+       /* table was built with bad purposes: resort to linear search */
+-      i = 1;
+-      while (!ttisnil(luaH_getnum(t, i))) i++;
+-      return i - 1;
++      for( i = 1; i<MAX_INT+1; i++ ) {
++        if (ttisnil(luaH_getint(t, i))) break;
++      }
++      return i - 1;  /* up to MAX_INT */
+     }
+   }
+   /* now do a binary search between them */
+   while (j - i > 1) {
+     unsigned int m = (i+j)/2;
+-    if (ttisnil(luaH_getnum(t, m))) j = m;
++    if (ttisnil(luaH_getint(t, m))) j = m;
+     else i = m;
+   }
+   return i;
+--- a/src/ltable.h
++++ b/src/ltable.h
+@@ -18,8 +18,8 @@
+ #define key2tval(n)	(&(n)->i_key.tvk)
+ 
+ 
+-LUAI_FUNC const TValue *luaH_getnum (Table *t, int key);
+-LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
++LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
++LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, lua_Integer key);
+ LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
+ LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
+ LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
+--- a/src/ltm.c
++++ b/src/ltm.c
+@@ -19,7 +19,6 @@
+ #include "ltm.h"
+ 
+ 
+-
+ const char *const luaT_typenames[] = {
+   "nil", "boolean", "userdata", "number",
+   "string", "table", "function", "userdata", "thread",
+@@ -67,6 +66,9 @@ const TValue *luaT_gettmbyobj (lua_State
+     case LUA_TUSERDATA:
+       mt = uvalue(o)->metatable;
+       break;
++    case LUA_TINT:
++      mt = G(L)->mt[LUA_TNUMBER];
++      break;
+     default:
+       mt = G(L)->mt[ttype(o)];
+   }
+--- a/src/lua.c
++++ b/src/lua.c
+@@ -16,7 +16,7 @@
+ 
+ #include "lauxlib.h"
+ #include "lualib.h"
+-
++#include "llimits.h"
+ 
+ 
+ static lua_State *globalL = NULL;
+@@ -382,6 +382,15 @@ int main (int argc, char **argv) {
+     l_message(argv[0], "cannot create state: not enough memory");
+     return EXIT_FAILURE;
+   }
++  /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
++  */
++#ifdef LNUM_INT16
++  lua_assert( sizeof(lua_Integer) == 2 );
++#elif defined(LNUM_INT32)
++  lua_assert( sizeof(lua_Integer) == 4 );
++#elif defined(LNUM_INT64)
++  lua_assert( sizeof(lua_Integer) == 8 );
++#endif
+   s.argc = argc;
+   s.argv = argv;
+   status = lua_cpcall(L, &pmain, &s);
+--- a/src/lua.h
++++ b/src/lua.h
+@@ -19,7 +19,7 @@
+ #define LUA_VERSION	"Lua 5.1"
+ #define LUA_RELEASE	"Lua 5.1.5"
+ #define LUA_VERSION_NUM	501
+-#define LUA_COPYRIGHT	"Copyright (C) 1994-2012 Lua.org, PUC-Rio"
++#define LUA_COPYRIGHT	"Copyright (C) 1994-2012 Lua.org, PUC-Rio" " (" LUA_LNUM ")"
+ #define LUA_AUTHORS 	"R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
+ 
+ 
+@@ -71,6 +71,16 @@ typedef void * (*lua_Alloc) (void *ud, v
+ */
+ #define LUA_TNONE		(-1)
+ 
++/* LUA_TINT is an internal type, not visible to applications. There are three
++ * potential values where it can be tweaked to (code autoadjusts to these):
++ *
++ * -2: not 'usual' type value; good since 'LUA_TINT' is not part of the API
++ * LUA_TNUMBER+1: shifts other type values upwards, breaking binary compatibility
++ *     not acceptable for 5.1, maybe 5.2 onwards?
++ *  9: greater than existing (5.1) type values.
++*/
++#define LUA_TINT (-2)
++
+ #define LUA_TNIL		0
+ #define LUA_TBOOLEAN		1
+ #define LUA_TLIGHTUSERDATA	2
+@@ -139,6 +149,8 @@ LUA_API int             (lua_isuserdata)
+ LUA_API int             (lua_type) (lua_State *L, int idx);
+ LUA_API const char     *(lua_typename) (lua_State *L, int tp);
+ 
++LUA_API int             (lua_isinteger) (lua_State *L, int idx);
++
+ LUA_API int            (lua_equal) (lua_State *L, int idx1, int idx2);
+ LUA_API int            (lua_rawequal) (lua_State *L, int idx1, int idx2);
+ LUA_API int            (lua_lessthan) (lua_State *L, int idx1, int idx2);
+@@ -244,6 +256,19 @@ LUA_API lua_Alloc (lua_getallocf) (lua_S
+ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+ 
+ 
++/*
++* It is unnecessary to break Lua C API 'lua_tonumber()' compatibility, just
++* because the Lua number type is complex. Most C modules would use scalars
++* only. We'll introduce new 'lua_tocomplex' and 'lua_pushcomplex' for when
++* the module really wants to use them.
++*/
++#ifdef LNUM_COMPLEX
++  #include <complex.h>
++  typedef LUA_NUMBER complex lua_Complex;
++  LUA_API lua_Complex (lua_tocomplex) (lua_State *L, int idx);
++  LUA_API void (lua_pushcomplex) (lua_State *L, lua_Complex v);
++#endif
++
+ 
+ /* 
+ ** ===============================================================
+@@ -268,7 +293,12 @@ LUA_API void lua_setallocf (lua_State *L
+ #define lua_isboolean(L,n)	(lua_type(L, (n)) == LUA_TBOOLEAN)
+ #define lua_isthread(L,n)	(lua_type(L, (n)) == LUA_TTHREAD)
+ #define lua_isnone(L,n)		(lua_type(L, (n)) == LUA_TNONE)
+-#define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0)
++
++#if LUA_TINT < 0
++# define lua_isnoneornil(L, n)	( (lua_type(L,(n)) <= 0) && (lua_type(L,(n)) != LUA_TINT) )
++#else
++# define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0)
++#endif
+ 
+ #define lua_pushliteral(L, s)	\
+ 	lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
+@@ -386,3 +416,4 @@ struct lua_Debug {
+ 
+ 
+ #endif
++
+--- a/src/luaconf.h
++++ b/src/luaconf.h
+@@ -10,7 +10,9 @@
+ 
+ #include <limits.h>
+ #include <stddef.h>
+-
++#ifdef lua_assert
++# include <assert.h>
++#endif
+ 
+ /*
+ ** ==================================================================
+@@ -136,14 +138,38 @@
+ 
+ 
+ /*
+-@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
+-** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
+-** machines, ptrdiff_t gives a good choice between int or long.)
++@@ LUAI_BITSINT defines the number of bits in an int.
++** CHANGE here if Lua cannot automatically detect the number of bits of
++** your machine. Probably you do not need to change this.
+ */
+-#define LUA_INTEGER	ptrdiff_t
++/* avoid overflows in comparison */
++#if INT_MAX-20 < 32760
++#define LUAI_BITSINT	16
++#elif INT_MAX > 2147483640L
++/* int has at least 32 bits */
++#define LUAI_BITSINT	32
++#else
++#error "you must define LUA_BITSINT with number of bits in an integer"
++#endif
+ 
+ 
+ /*
++@@ LNUM_DOUBLE | LNUM_FLOAT | LNUM_LDOUBLE: Generic Lua number mode
++@@ LNUM_INT32 | LNUM_INT64: Integer type
++@@ LNUM_COMPLEX: Define for using 'a+bi' numbers
++@@
++@@ You can combine LNUM_xxx but only one of each group. I.e. '-DLNUM_FLOAT
++@@ -DLNUM_INT32 -DLNUM_COMPLEX' gives float range complex numbers, with 
++@@ 32-bit scalar integer range optimized.
++**
++** These are kept in a separate configuration file mainly for ease of patching
++** (can be changed if integerated to Lua proper).
++*/
++/*#define LNUM_DOUBLE*/
++/*#define LNUM_INT32*/
++#include "lnum_config.h"
++
++/*
+ @@ LUA_API is a mark for all core API functions.
+ @@ LUALIB_API is a mark for all standard library functions.
+ ** CHANGE them if you need to define those functions in some special way.
+@@ -383,22 +409,6 @@
+ 
+ 
+ /*
+-@@ LUAI_BITSINT defines the number of bits in an int.
+-** CHANGE here if Lua cannot automatically detect the number of bits of
+-** your machine. Probably you do not need to change this.
+-*/
+-/* avoid overflows in comparison */
+-#if INT_MAX-20 < 32760
+-#define LUAI_BITSINT	16
+-#elif INT_MAX > 2147483640L
+-/* int has at least 32 bits */
+-#define LUAI_BITSINT	32
+-#else
+-#error "you must define LUA_BITSINT with number of bits in an integer"
+-#endif
+-
+-
+-/*
+ @@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
+ @@ LUAI_INT32 is an signed integer with at least 32 bits.
+ @@ LUAI_UMEM is an unsigned integer big enough to count the total
+@@ -425,6 +435,15 @@
+ #define LUAI_MEM	long
+ #endif
+ 
++/*
++@@ LUAI_BOOL carries 0 and nonzero (normally 1). It may be defined as 'char'
++** (to save memory), 'int' (for speed), 'bool' (for C++) or '_Bool' (C99)
++*/
++#ifdef __cplusplus
++# define LUAI_BOOL bool
++#else
++# define LUAI_BOOL int
++#endif
+ 
+ /*
+ @@ LUAI_MAXCALLS limits the number of nested calls.
+@@ -490,101 +509,6 @@
+ /* }================================================================== */
+ 
+ 
+-
+-
+-/*
+-** {==================================================================
+-@@ LUA_NUMBER is the type of numbers in Lua.
+-** CHANGE the following definitions only if you want to build Lua
+-** with a number type different from double. You may also need to
+-** change lua_number2int & lua_number2integer.
+-** ===================================================================
+-*/
+-
+-#define LUA_NUMBER_DOUBLE
+-#define LUA_NUMBER	double
+-
+-/*
+-@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+-@* over a number.
+-*/
+-#define LUAI_UACNUMBER	double
+-
+-
+-/*
+-@@ LUA_NUMBER_SCAN is the format for reading numbers.
+-@@ LUA_NUMBER_FMT is the format for writing numbers.
+-@@ lua_number2str converts a number to a string.
+-@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
+-@@ lua_str2number converts a string to a number.
+-*/
+-#define LUA_NUMBER_SCAN		"%lf"
+-#define LUA_NUMBER_FMT		"%.14g"
+-#define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n))
+-#define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */
+-#define lua_str2number(s,p)	strtod((s), (p))
+-
+-
+-/*
+-@@ The luai_num* macros define the primitive operations over numbers.
+-*/
+-#if defined(LUA_CORE)
+-#include <math.h>
+-#define luai_numadd(a,b)	((a)+(b))
+-#define luai_numsub(a,b)	((a)-(b))
+-#define luai_nummul(a,b)	((a)*(b))
+-#define luai_numdiv(a,b)	((a)/(b))
+-#define luai_nummod(a,b)	((a) - floor((a)/(b))*(b))
+-#define luai_numpow(a,b)	(pow(a,b))
+-#define luai_numunm(a)		(-(a))
+-#define luai_numeq(a,b)		((a)==(b))
+-#define luai_numlt(a,b)		((a)<(b))
+-#define luai_numle(a,b)		((a)<=(b))
+-#define luai_numisnan(a)	(!luai_numeq((a), (a)))
+-#endif
+-
+-
+-/*
+-@@ lua_number2int is a macro to convert lua_Number to int.
+-@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
+-** CHANGE them if you know a faster way to convert a lua_Number to
+-** int (with any rounding method and without throwing errors) in your
+-** system. In Pentium machines, a naive typecast from double to int
+-** in C is extremely slow, so any alternative is worth trying.
+-*/
+-
+-/* On a Pentium, resort to a trick */
+-#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
+-    (defined(__i386) || defined (_M_IX86) || defined(__i386__))
+-
+-/* On a Microsoft compiler, use assembler */
+-#if defined(_MSC_VER)
+-
+-#define lua_number2int(i,d)   __asm fld d   __asm fistp i
+-#define lua_number2integer(i,n)		lua_number2int(i, n)
+-
+-/* the next trick should work on any Pentium, but sometimes clashes
+-   with a DirectX idiosyncrasy */
+-#else
+-
+-union luai_Cast { double l_d; long l_l; };
+-#define lua_number2int(i,d) \
+-  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
+-#define lua_number2integer(i,n)		lua_number2int(i, n)
+-
+-#endif
+-
+-
+-/* this option always works, but may be slow */
+-#else
+-#define lua_number2int(i,d)	((i)=(int)(d))
+-#define lua_number2integer(i,d)	((i)=(lua_Integer)(d))
+-
+-#endif
+-
+-/* }================================================================== */
+-
+-
+ /*
+ @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
+ ** CHANGE it if your system requires alignments larger than double. (For
+@@ -728,28 +652,6 @@ union luai_Cast { double l_d; long l_l; 
+ #define luai_userstateyield(L,n)	((void)L)
+ 
+ 
+-/*
+-@@ LUA_INTFRMLEN is the length modifier for integer conversions
+-@* in 'string.format'.
+-@@ LUA_INTFRM_T is the integer type correspoding to the previous length
+-@* modifier.
+-** CHANGE them if your system supports long long or does not support long.
+-*/
+-
+-#if defined(LUA_USELONGLONG)
+-
+-#define LUA_INTFRMLEN		"ll"
+-#define LUA_INTFRM_T		long long
+-
+-#else
+-
+-#define LUA_INTFRMLEN		"l"
+-#define LUA_INTFRM_T		long
+-
+-#endif
+-
+-
+-
+ /* =================================================================== */
+ 
+ /*
+--- a/src/lundump.c
++++ b/src/lundump.c
+@@ -73,6 +73,13 @@ static lua_Number LoadNumber(LoadState* 
+  return x;
+ }
+ 
++static lua_Integer LoadInteger(LoadState* S)
++{
++ lua_Integer x;
++ LoadVar(S,x);
++ return x;
++}
++
+ static TString* LoadString(LoadState* S)
+ {
+  size_t size;
+@@ -119,6 +126,9 @@ static void LoadConstants(LoadState* S, 
+    case LUA_TNUMBER:
+ 	setnvalue(o,LoadNumber(S));
+ 	break;
++   case LUA_TINT:   /* Integer type saved in bytecode (see lcode.c) */
++	setivalue(o,LoadInteger(S));
++	break;
+    case LUA_TSTRING:
+ 	setsvalue2n(S->L,o,LoadString(S));
+ 	break;
+@@ -223,5 +233,22 @@ void luaU_header (char* h)
+  *h++=(char)sizeof(size_t);
+  *h++=(char)sizeof(Instruction);
+  *h++=(char)sizeof(lua_Number);
+- *h++=(char)(((lua_Number)0.5)==0);		/* is lua_Number integral? */
++
++ /* 
++  * Last byte of header (0/1 in unpatched Lua 5.1.3):
++  *
++  * 0: lua_Number is float or double, lua_Integer not used. (nonpatched only)
++  * 1: lua_Number is integer (nonpatched only)
++  *
++  * +2: LNUM_INT16: sizeof(lua_Integer)
++  * +4: LNUM_INT32: sizeof(lua_Integer)
++  * +8: LNUM_INT64: sizeof(lua_Integer)
++  *
++  * +0x80: LNUM_COMPLEX
++  */
++ *h++ = (char)(sizeof(lua_Integer)
++#ifdef LNUM_COMPLEX
++    | 0x80
++#endif
++    );
+ }
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -25,22 +25,35 @@
+ #include "ltable.h"
+ #include "ltm.h"
+ #include "lvm.h"
+-
+-
++#include "llex.h"
++#include "lnum.h"
+ 
+ /* limit for table tag-method chains (to avoid loops) */
+ #define MAXTAGLOOP	100
+ 
+ 
+-const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
+-  lua_Number num;
++/*
++ * If 'obj' is a string, it is tried to be interpreted as a number.
++ */
++const TValue *luaV_tonumber ( const TValue *obj, TValue *n) {
++  lua_Number d;
++  lua_Integer i;
++  
+   if (ttisnumber(obj)) return obj;
+-  if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
+-    setnvalue(n, num);
+-    return n;
+-  }
+-  else
+-    return NULL;
++
++  if (ttisstring(obj)) {
++    switch( luaO_str2d( svalue(obj), &d, &i ) ) {
++        case TK_INT:
++            setivalue(n,i); return n;
++        case TK_NUMBER: 
++            setnvalue(n,d); return n;
++#ifdef LNUM_COMPLEX
++        case TK_NUMBER2:    /* "N.NNNi", != 0 */
++            setnvalue_complex_fast(n, d*I); return n;
++#endif
++        }
++    }
++  return NULL;
+ }
+ 
+ 
+@@ -49,8 +62,7 @@ int luaV_tostring (lua_State *L, StkId o
+     return 0;
+   else {
+     char s[LUAI_MAXNUMBER2STR];
+-    lua_Number n = nvalue(obj);
+-    lua_number2str(s, n);
++    luaO_num2buf(s,obj);
+     setsvalue2s(L, obj, luaS_new(L, s));
+     return 1;
+   }
+@@ -222,59 +234,127 @@ static int l_strcmp (const TString *ls, 
+ }
+ 
+ 
++#ifdef LNUM_COMPLEX
++void error_complex( lua_State *L, const TValue *l, const TValue *r )
++{
++  char buf1[ LUAI_MAXNUMBER2STR ];
++  char buf2[ LUAI_MAXNUMBER2STR ];
++  luaO_num2buf( buf1, l );
++  luaO_num2buf( buf2, r );
++  luaG_runerror( L, "unable to compare: %s with %s", buf1, buf2 );
++  /* no return */
++}
++#endif
++
++
+ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
+   int res;
+-  if (ttype(l) != ttype(r))
++  int tl,tr;
++  lua_Integer tmp;
++
++  if (!ttype_ext_same(l,r))
+     return luaG_ordererror(L, l, r);
+-  else if (ttisnumber(l))
+-    return luai_numlt(nvalue(l), nvalue(r));
+-  else if (ttisstring(l))
+-    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
+-  else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
++#ifdef LNUM_COMPLEX
++  if ( (nvalue_img(l)!=0) || (nvalue_img(r)!=0) )
++    error_complex( L, l, r );
++#endif
++  tl= ttype(l); tr= ttype(r);
++  if (tl==tr) {  /* clear arithmetics */
++    switch(tl) {
++      case LUA_TINT:      return ivalue(l) < ivalue(r);
++      case LUA_TNUMBER:   return luai_numlt(nvalue_fast(l), nvalue_fast(r));
++      case LUA_TSTRING:   return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
++    }
++  } else if (tl==LUA_TINT) {  /* l:int, r:num */
++    /* Avoid accuracy losing casts: if 'r' is integer by value, do comparisons
++     * in integer realm. Only otherwise cast 'l' to FP (which might change its
++     * value).
++     */
++    if (tt_integer_valued(r,&tmp)) 
++        return ivalue(l) < tmp;
++    else 
++        return luai_numlt( cast_num(ivalue(l)), nvalue_fast(r) );
++
++  } else if (tl==LUA_TNUMBER) {  /* l:num, r:int */
++    if (tt_integer_valued(l,&tmp)) 
++        return tmp < ivalue(r);
++    else
++        return luai_numlt( nvalue_fast(l), cast_num(ivalue(r)) );
++
++  } else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+     return res;
++
+   return luaG_ordererror(L, l, r);
+ }
+ 
+ 
+ static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
+   int res;
+-  if (ttype(l) != ttype(r))
++  int tl, tr;
++  lua_Integer tmp;
++
++  if (!ttype_ext_same(l,r))
+     return luaG_ordererror(L, l, r);
+-  else if (ttisnumber(l))
+-    return luai_numle(nvalue(l), nvalue(r));
+-  else if (ttisstring(l))
+-    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
+-  else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
++#ifdef LNUM_COMPLEX
++  if ( (nvalue_img(l)!=0) || (nvalue_img(r)!=0) )
++    error_complex( L, l, r );
++#endif
++  tl= ttype(l); tr= ttype(r);
++  if (tl==tr) {  /* clear arithmetics */
++    switch(tl) {
++      case LUA_TINT:      return ivalue(l) <= ivalue(r);
++      case LUA_TNUMBER:   return luai_numle(nvalue_fast(l), nvalue_fast(r));
++      case LUA_TSTRING:   return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
++    }
++  }
++  if (tl==LUA_TINT) {  /* l:int, r:num */
++    if (tt_integer_valued(r,&tmp)) 
++        return ivalue(l) <= tmp;
++    else
++        return luai_numle( cast_num(ivalue(l)), nvalue_fast(r) );
++
++  } else if (tl==LUA_TNUMBER) {  /* l:num, r:int */
++    if (tt_integer_valued(l,&tmp)) 
++        return tmp <= ivalue(r);
++    else
++        return luai_numle( nvalue_fast(l), cast_num(ivalue(r)) );
++
++  } else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
+     return res;
+   else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */
+     return !res;
++
+   return luaG_ordererror(L, l, r);
+ }
+ 
+ 
+-int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
++/* Note: 'luaV_equalval()' and 'luaO_rawequalObj()' have largely overlapping
++ *       implementation. LUA_TNIL..LUA_TLIGHTUSERDATA cases could be handled
++ *       simply by the 'default' case here.
++ */
++int luaV_equalval (lua_State *L, const TValue *l, const TValue *r) {
+   const TValue *tm;
+-  lua_assert(ttype(t1) == ttype(t2));
+-  switch (ttype(t1)) {
++  lua_assert(ttype_ext_same(l,r));
++  switch (ttype(l)) {
+     case LUA_TNIL: return 1;
+-    case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
+-    case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */
+-    case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
++    case LUA_TINT:
++    case LUA_TNUMBER: return luaO_rawequalObj(l,r);
++    case LUA_TBOOLEAN: return bvalue(l) == bvalue(r);  /* true must be 1 !! */
++    case LUA_TLIGHTUSERDATA: return pvalue(l) == pvalue(r);
+     case LUA_TUSERDATA: {
+-      if (uvalue(t1) == uvalue(t2)) return 1;
+-      tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
+-                         TM_EQ);
++      if (uvalue(l) == uvalue(r)) return 1;
++      tm = get_compTM(L, uvalue(l)->metatable, uvalue(r)->metatable, TM_EQ);
+       break;  /* will try TM */
+     }
+     case LUA_TTABLE: {
+-      if (hvalue(t1) == hvalue(t2)) return 1;
+-      tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
++      if (hvalue(l) == hvalue(r)) return 1;
++      tm = get_compTM(L, hvalue(l)->metatable, hvalue(r)->metatable, TM_EQ);
+       break;  /* will try TM */
+     }
+-    default: return gcvalue(t1) == gcvalue(t2);
++    default: return gcvalue(l) == gcvalue(r);
+   }
+   if (tm == NULL) return 0;  /* no TM? */
+-  callTMres(L, L->top, tm, t1, t2);  /* call TM */
++  callTMres(L, L->top, tm, l, r);  /* call TM */
+   return !l_isfalse(L->top);
+ }
+ 
+@@ -314,30 +394,6 @@ void luaV_concat (lua_State *L, int tota
+ }
+ 
+ 
+-static void Arith (lua_State *L, StkId ra, const TValue *rb,
+-                   const TValue *rc, TMS op) {
+-  TValue tempb, tempc;
+-  const TValue *b, *c;
+-  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
+-      (c = luaV_tonumber(rc, &tempc)) != NULL) {
+-    lua_Number nb = nvalue(b), nc = nvalue(c);
+-    switch (op) {
+-      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
+-      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
+-      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
+-      case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
+-      case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
+-      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
+-      case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
+-      default: lua_assert(0); break;
+-    }
+-  }
+-  else if (!call_binTM(L, rb, rc, ra, op))
+-    luaG_aritherror(L, rb, rc);
+-}
+-
+-
+-
+ /*
+ ** some macros for common tasks in `luaV_execute'
+ */
+@@ -361,17 +417,154 @@ static void Arith (lua_State *L, StkId r
+ #define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; }
+ 
+ 
+-#define arith_op(op,tm) { \
+-        TValue *rb = RKB(i); \
+-        TValue *rc = RKC(i); \
+-        if (ttisnumber(rb) && ttisnumber(rc)) { \
+-          lua_Number nb = nvalue(rb), nc = nvalue(rc); \
+-          setnvalue(ra, op(nb, nc)); \
+-        } \
+-        else \
+-          Protect(Arith(L, ra, rb, rc, tm)); \
++/* Note: if called for unary operations, 'rc'=='rb'.
++ */
++static void Arith (lua_State *L, StkId ra, const TValue *rb,
++                   const TValue *rc, TMS op) {
++  TValue tempb, tempc;
++  const TValue *b, *c;
++  lua_Number nb,nc;
++
++  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
++      (c = luaV_tonumber(rc, &tempc)) != NULL) {
++
++    /* Keep integer arithmetics in the integer realm, if possible.
++     */
++    if (ttisint(b) && ttisint(c)) {
++      lua_Integer ib = ivalue(b), ic = ivalue(c);
++      lua_Integer *ri = &ra->value.i;
++      ra->tt= LUA_TINT;  /* part of 'setivalue(ra)' */
++      switch (op) {
++        case TM_ADD: if (try_addint( ri, ib, ic)) return; break;
++        case TM_SUB: if (try_subint( ri, ib, ic)) return; break;
++        case TM_MUL: if (try_mulint( ri, ib, ic)) return; break;
++        case TM_DIV: if (try_divint( ri, ib, ic)) return; break;
++        case TM_MOD: if (try_modint( ri, ib, ic)) return; break;
++        case TM_POW: if (try_powint( ri, ib, ic)) return; break;
++        case TM_UNM: if (try_unmint( ri, ib)) return; break;
++        default: lua_assert(0);
++      }
++    }
++    /* Fallback to floating point, when leaving range. */
++
++#ifdef LNUM_COMPLEX
++    if ((nvalue_img(b)!=0) || (nvalue_img(c)!=0)) {
++      lua_Complex r;
++      if (op==TM_UNM) {
++        r= -nvalue_complex_fast(b);     /* never an integer (or scalar) */
++        setnvalue_complex_fast( ra, r );
++      } else {
++        lua_Complex bb= nvalue_complex(b), cc= nvalue_complex(c);
++        switch (op) {
++          case TM_ADD: r= bb + cc; break;
++          case TM_SUB: r= bb - cc; break;
++          case TM_MUL: r= bb * cc; break;
++          case TM_DIV: r= bb / cc; break;
++          case TM_MOD: 
++            luaG_runerror(L, "attempt to use %% on complex numbers");  /* no return */
++          case TM_POW: r= luai_vectpow( bb, cc ); break;
++          default: lua_assert(0); r=0;
++        }
++        setnvalue_complex( ra, r );
+       }
++      return;
++    }
++#endif
++    nb = nvalue(b); nc = nvalue(c);
++    switch (op) {
++      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); return;
++      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); return;
++      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); return;
++      case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); return;
++      case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); return;
++      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); return;
++      case TM_UNM: setnvalue(ra, luai_numunm(nb)); return;
++      default: lua_assert(0);
++    }
++  }
++  
++  /* Either operand not a number */
++  if (!call_binTM(L, rb, rc, ra, op))
++    luaG_aritherror(L, rb, rc);
++}
+ 
++/* Helper macro to sort arithmetic operations into four categories:
++ *  TK_INT: integer - integer operands
++ *  TK_NUMBER: number - number (non complex, either may be integer)
++ *  TK_NUMBER2: complex numbers (at least the other)
++ *  0: non-numeric (at least the other)
++*/
++#ifdef LNUM_COMPLEX
++static inline int arith_mode( const TValue *rb, const TValue *rc ) {
++  if (ttisint(rb) && ttisint(rc)) return TK_INT;
++  if (ttiscomplex(rb) || ttiscomplex(rc)) return TK_NUMBER2;
++  if (ttisnumber(rb) && ttisnumber(rc)) return TK_NUMBER;
++  return 0;
++}
++#else
++# define arith_mode(rb,rc) \
++    ( (ttisint(rb) && ttisint(rc)) ? TK_INT : \
++      (ttisnumber(rb) && ttisnumber(rc)) ? TK_NUMBER : 0 )
++#endif
++
++/* arith_op macro for two operators:
++ * automatically chooses, which function (number, integer, complex) to use
++ */
++#define ARITH_OP2_START( op_num, op_int ) \
++  int failed= 0; \
++  switch( arith_mode(rb,rc) ) { \
++    case TK_INT: \
++      if (op_int ( &(ra)->value.i, ivalue(rb), ivalue(rc) )) \
++        { ra->tt= LUA_TINT; break; } /* else flow through */ \
++    case TK_NUMBER: \
++      setnvalue(ra, op_num ( nvalue(rb), nvalue(rc) )); break;
++
++#define ARITH_OP2_END \
++    default: \
++      failed= 1; break; \
++  } if (!failed) continue;
++
++#define arith_op_continue_scalar( op_num, op_int ) \
++    ARITH_OP2_START( op_num, op_int ) \
++    ARITH_OP2_END
++
++#ifdef LNUM_COMPLEX
++# define arith_op_continue( op_num, op_int, op_complex ) \
++    ARITH_OP2_START( op_num, op_int ) \
++      case TK_NUMBER2: \
++        setnvalue_complex( ra, op_complex ( nvalue_complex(rb), nvalue_complex(rc) ) ); break; \
++    ARITH_OP2_END
++#else
++# define arith_op_continue(op_num,op_int,_) arith_op_continue_scalar(op_num,op_int)
++#endif
++
++/* arith_op macro for one operator:
++ */
++#define ARITH_OP1_START( op_num, op_int ) \
++  int failed= 0; \
++  switch( arith_mode(rb,rb) ) { \
++    case TK_INT: \
++      if (op_int ( &(ra)->value.i, ivalue(rb) )) \
++        { ra->tt= LUA_TINT; break; } /* else flow through */ \
++      case TK_NUMBER: \
++        setnvalue(ra, op_num (nvalue(rb))); break; \
++
++#define ARITH_OP1_END \
++      default: \
++        failed= 1; break; \
++  } if (!failed) continue;
++
++#ifdef LNUM_COMPLEX
++# define arith_op1_continue( op_num, op_int, op_complex ) \
++    ARITH_OP1_START( op_num, op_int ) \
++      case TK_NUMBER2: \
++        setnvalue_complex( ra, op_complex ( nvalue_complex_fast(rb) )); break; \
++    ARITH_OP1_END
++#else
++# define arith_op1_continue( op_num, op_int, _ ) \
++    ARITH_OP1_START( op_num, op_int ) \
++    ARITH_OP1_END
++#endif
+ 
+ 
+ void luaV_execute (lua_State *L, int nexeccalls) {
+@@ -472,38 +665,45 @@ void luaV_execute (lua_State *L, int nex
+         continue;
+       }
+       case OP_ADD: {
+-        arith_op(luai_numadd, TM_ADD);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue( luai_numadd, try_addint, luai_vectadd );
++        Protect(Arith(L, ra, rb, rc, TM_ADD)); \
+         continue;
+       }
+       case OP_SUB: {
+-        arith_op(luai_numsub, TM_SUB);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue( luai_numsub, try_subint, luai_vectsub );
++        Protect(Arith(L, ra, rb, rc, TM_SUB));
+         continue;
+       }
+       case OP_MUL: {
+-        arith_op(luai_nummul, TM_MUL);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue(luai_nummul, try_mulint, luai_vectmul);
++        Protect(Arith(L, ra, rb, rc, TM_MUL));
+         continue;
+       }
+       case OP_DIV: {
+-        arith_op(luai_numdiv, TM_DIV);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue(luai_numdiv, try_divint, luai_vectdiv);
++        Protect(Arith(L, ra, rb, rc, TM_DIV));
+         continue;
+       }
+       case OP_MOD: {
+-        arith_op(luai_nummod, TM_MOD);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue_scalar(luai_nummod, try_modint);  /* scalars only */
++        Protect(Arith(L, ra, rb, rc, TM_MOD));
+         continue;
+       }
+       case OP_POW: {
+-        arith_op(luai_numpow, TM_POW);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue(luai_numpow, try_powint, luai_vectpow);
++        Protect(Arith(L, ra, rb, rc, TM_POW));
+         continue;
+       }
+       case OP_UNM: {
+         TValue *rb = RB(i);
+-        if (ttisnumber(rb)) {
+-          lua_Number nb = nvalue(rb);
+-          setnvalue(ra, luai_numunm(nb));
+-        }
+-        else {
+-          Protect(Arith(L, ra, rb, rb, TM_UNM));
+-        }
++        arith_op1_continue(luai_numunm, try_unmint, luai_vectunm);
++        Protect(Arith(L, ra, rb, rb, TM_UNM));
+         continue;
+       }
+       case OP_NOT: {
+@@ -515,11 +715,11 @@ void luaV_execute (lua_State *L, int nex
+         const TValue *rb = RB(i);
+         switch (ttype(rb)) {
+           case LUA_TTABLE: {
+-            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
++            setivalue(ra, luaH_getn(hvalue(rb)));
+             break;
+           }
+           case LUA_TSTRING: {
+-            setnvalue(ra, cast_num(tsvalue(rb)->len));
++            setivalue(ra, tsvalue(rb)->len);
+             break;
+           }
+           default: {  /* try metamethod */
+@@ -652,14 +852,30 @@ void luaV_execute (lua_State *L, int nex
+         }
+       }
+       case OP_FORLOOP: {
+-        lua_Number step = nvalue(ra+2);
+-        lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
+-        lua_Number limit = nvalue(ra+1);
+-        if (luai_numlt(0, step) ? luai_numle(idx, limit)
+-                                : luai_numle(limit, idx)) {
+-          dojump(L, pc, GETARG_sBx(i));  /* jump back */
+-          setnvalue(ra, idx);  /* update internal index... */
+-          setnvalue(ra+3, idx);  /* ...and external index */
++        /* If start,step and limit are all integers, we don't need to check
++         * against overflow in the looping.
++         */
++        if (ttisint(ra) && ttisint(ra+1) && ttisint(ra+2)) {
++          lua_Integer step = ivalue(ra+2);
++          lua_Integer idx = ivalue(ra) + step; /* increment index */
++          lua_Integer limit = ivalue(ra+1);
++          if (step > 0 ? (idx <= limit) : (limit <= idx)) {
++            dojump(L, pc, GETARG_sBx(i));  /* jump back */
++            setivalue(ra, idx);  /* update internal index... */
++            setivalue(ra+3, idx);  /* ...and external index */
++          }
++        } else {
++          /* non-integer looping (don't use 'nvalue_fast', some may be integer!) 
++          */
++          lua_Number step = nvalue(ra+2);
++          lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
++          lua_Number limit = nvalue(ra+1);
++          if (luai_numlt(0, step) ? luai_numle(idx, limit)
++                                  : luai_numle(limit, idx)) {
++            dojump(L, pc, GETARG_sBx(i));  /* jump back */
++            setnvalue(ra, idx);  /* update internal index... */
++            setnvalue(ra+3, idx);  /* ...and external index */
++          }
+         }
+         continue;
+       }
+@@ -668,13 +884,21 @@ void luaV_execute (lua_State *L, int nex
+         const TValue *plimit = ra+1;
+         const TValue *pstep = ra+2;
+         L->savedpc = pc;  /* next steps may throw errors */
++        /* Using same location for tonumber's both arguments, effectively does
++         * in-place modification (string->number). */
+         if (!tonumber(init, ra))
+           luaG_runerror(L, LUA_QL("for") " initial value must be a number");
+         else if (!tonumber(plimit, ra+1))
+           luaG_runerror(L, LUA_QL("for") " limit must be a number");
+         else if (!tonumber(pstep, ra+2))
+           luaG_runerror(L, LUA_QL("for") " step must be a number");
+-        setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
++        /* Step back one value (keep within integers if we can)
++         */
++        if (!( ttisint(ra) && ttisint(pstep) &&
++               try_subint( &ra->value.i, ivalue(ra), ivalue(pstep) ) )) {
++            /* don't use 'nvalue_fast()', values may be integer */
++            setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
++        }
+         dojump(L, pc, GETARG_sBx(i));
+         continue;
+       }
+@@ -711,7 +935,7 @@ void luaV_execute (lua_State *L, int nex
+           luaH_resizearray(L, h, last);  /* pre-alloc it at once */
+         for (; n > 0; n--) {
+           TValue *val = ra+n;
+-          setobj2t(L, luaH_setnum(L, h, last--), val);
++          setobj2t(L, luaH_setint(L, h, last--), val);
+           luaC_barriert(L, h, val);
+         }
+         continue;
+--- a/src/lvm.h
++++ b/src/lvm.h
+@@ -15,11 +15,9 @@
+ 
+ #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
+ 
+-#define tonumber(o,n)	(ttype(o) == LUA_TNUMBER || \
+-                         (((o) = luaV_tonumber(o,n)) != NULL))
++#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL))
+ 
+-#define equalobj(L,o1,o2) \
+-	(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
++#define equalobj(L,o1,o2) (ttype_ext_same(o1,o2) && luaV_equalval(L, o1, o2))
+ 
+ 
+ LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
+--- a/src/print.c
++++ b/src/print.c
+@@ -14,6 +14,7 @@
+ #include "lobject.h"
+ #include "lopcodes.h"
+ #include "lundump.h"
++#include "lnum.h"
+ 
+ #define PrintFunction	luaU_print
+ 
+@@ -59,8 +60,16 @@ static void PrintConstant(const Proto* f
+   case LUA_TBOOLEAN:
+ 	printf(bvalue(o) ? "true" : "false");
+ 	break;
++  case LUA_TINT:
++	printf(LUA_INTEGER_FMT,ivalue(o));
++	break;
+   case LUA_TNUMBER:
+-	printf(LUA_NUMBER_FMT,nvalue(o));
++#ifdef LNUM_COMPLEX
++    // TBD: Do we get complex values here?
++    { lua_Number b= nvalue_img_fast(o);
++	  printf( LUA_NUMBER_FMT "%s" LUA_NUMBER_FMT "i", nvalue_fast(o), b>=0 ? "+":"", b ); }
++#endif
++	printf(LUA_NUMBER_FMT,nvalue_fast(o));
+ 	break;
+   case LUA_TSTRING:
+ 	PrintString(rawtsvalue(o));
diff --git a/package/utils/lua/patches-host/011-lnum-use-double.patch b/package/utils/lua/patches-host/011-lnum-use-double.patch
new file mode 100644
index 0000000000..14c720bf19
--- /dev/null
+++ b/package/utils/lua/patches-host/011-lnum-use-double.patch
@@ -0,0 +1,11 @@
+--- a/src/lnum_config.h
++++ b/src/lnum_config.h
+@@ -11,7 +11,7 @@
+ ** Default number modes
+ */
+ #if (!defined LNUM_DOUBLE) && (!defined LNUM_FLOAT) && (!defined LNUM_LDOUBLE)
+-# define LNUM_FLOAT
++# define LNUM_DOUBLE
+ #endif
+ #if (!defined LNUM_INT16) && (!defined LNUM_INT32) && (!defined LNUM_INT64)
+ # define LNUM_INT32
diff --git a/package/utils/lua/patches-host/012-lnum-fix-ltle-relational-operators.patch b/package/utils/lua/patches-host/012-lnum-fix-ltle-relational-operators.patch
new file mode 100644
index 0000000000..937fc137e8
--- /dev/null
+++ b/package/utils/lua/patches-host/012-lnum-fix-ltle-relational-operators.patch
@@ -0,0 +1,22 @@
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -284,7 +284,8 @@ int luaV_lessthan (lua_State *L, const T
+     else
+         return luai_numlt( nvalue_fast(l), cast_num(ivalue(r)) );
+ 
+-  } else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
++  } 
++  if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+     return res;
+ 
+   return luaG_ordererror(L, l, r);
+@@ -322,7 +323,8 @@ static int lessequal (lua_State *L, cons
+     else
+         return luai_numle( nvalue_fast(l), cast_num(ivalue(r)) );
+ 
+-  } else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
++  } 
++  if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
+     return res;
+   else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */
+     return !res;
diff --git a/package/utils/lua/patches-host/015-lnum-ppc-compat.patch b/package/utils/lua/patches-host/015-lnum-ppc-compat.patch
new file mode 100644
index 0000000000..2ea59f1769
--- /dev/null
+++ b/package/utils/lua/patches-host/015-lnum-ppc-compat.patch
@@ -0,0 +1,11 @@
+--- a/src/lua.h
++++ b/src/lua.h
+@@ -79,7 +79,7 @@ typedef void * (*lua_Alloc) (void *ud, v
+  *     not acceptable for 5.1, maybe 5.2 onwards?
+  *  9: greater than existing (5.1) type values.
+ */
+-#define LUA_TINT (-2)
++#define LUA_TINT 9
+ 
+ #define LUA_TNIL		0
+ #define LUA_TBOOLEAN		1
diff --git a/package/utils/lua/patches-host/030-archindependent-bytecode.patch b/package/utils/lua/patches-host/030-archindependent-bytecode.patch
new file mode 100644
index 0000000000..8dfef85d0d
--- /dev/null
+++ b/package/utils/lua/patches-host/030-archindependent-bytecode.patch
@@ -0,0 +1,111 @@
+--- a/src/ldump.c
++++ b/src/ldump.c
+@@ -67,12 +67,12 @@ static void DumpString(const TString* s,
+ {
+  if (s==NULL || getstr(s)==NULL)
+  {
+-  size_t size=0;
++  unsigned int size=0;
+   DumpVar(size,D);
+  }
+  else
+  {
+-  size_t size=s->tsv.len+1;		/* include trailing '\0' */
++  unsigned int size=s->tsv.len+1;		/* include trailing '\0' */
+   DumpVar(size,D);
+   DumpBlock(getstr(s),size,D);
+  }
+--- a/src/lundump.c
++++ b/src/lundump.c
+@@ -25,6 +25,7 @@ typedef struct {
+  ZIO* Z;
+  Mbuffer* b;
+  const char* name;
++ int swap;
+ } LoadState;
+ 
+ #ifdef LUAC_TRUST_BINARIES
+@@ -40,7 +41,6 @@ static void error(LoadState* S, const ch
+ }
+ #endif
+ 
+-#define LoadMem(S,b,n,size)	LoadBlock(S,b,(n)*(size))
+ #define	LoadByte(S)		(lu_byte)LoadChar(S)
+ #define LoadVar(S,x)		LoadMem(S,&x,1,sizeof(x))
+ #define LoadVector(S,b,n,size)	LoadMem(S,b,n,size)
+@@ -51,6 +51,49 @@ static void LoadBlock(LoadState* S, void
+  IF (r!=0, "unexpected end");
+ }
+ 
++static void LoadMem (LoadState* S, void* b, int n, size_t size)
++{
++ LoadBlock(S,b,n*size);
++ if (S->swap)
++ {
++  char* p=(char*) b;
++  char c;
++  switch (size)
++  {
++   case 1:
++  	break;
++   case 2:
++	while (n--)
++	{
++	 c=p[0]; p[0]=p[1]; p[1]=c;
++	 p+=2;
++	}
++  	break;
++   case 4:
++	while (n--)
++	{
++	 c=p[0]; p[0]=p[3]; p[3]=c;
++	 c=p[1]; p[1]=p[2]; p[2]=c;
++	 p+=4;
++	}
++  	break;
++   case 8:
++	while (n--)
++	{
++	 c=p[0]; p[0]=p[7]; p[7]=c;
++	 c=p[1]; p[1]=p[6]; p[6]=c;
++	 c=p[2]; p[2]=p[5]; p[5]=c;
++	 c=p[3]; p[3]=p[4]; p[4]=c;
++	 p+=8;
++	}
++  	break;
++   default:
++   	IF(1, "bad size");
++  	break;
++  }
++ }
++}
++
+ static int LoadChar(LoadState* S)
+ {
+  char x;
+@@ -82,7 +125,7 @@ static lua_Integer LoadInteger(LoadState
+ 
+ static TString* LoadString(LoadState* S)
+ {
+- size_t size;
++ unsigned int size;
+  LoadVar(S,size);
+  if (size==0)
+   return NULL;
+@@ -196,6 +239,7 @@ static void LoadHeader(LoadState* S)
+  char s[LUAC_HEADERSIZE];
+  luaU_header(h);
+  LoadBlock(S,s,LUAC_HEADERSIZE);
++ S->swap=(s[6]!=h[6]); s[6]=h[6];
+  IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header");
+ }
+ 
+@@ -230,7 +274,7 @@ void luaU_header (char* h)
+  *h++=(char)LUAC_FORMAT;
+  *h++=(char)*(char*)&x;				/* endianness */
+  *h++=(char)sizeof(int);
+- *h++=(char)sizeof(size_t);
++ *h++=(char)sizeof(unsigned int);
+  *h++=(char)sizeof(Instruction);
+  *h++=(char)sizeof(lua_Number);
+ 
diff --git a/package/utils/lua/patches-host/100-no_readline.patch b/package/utils/lua/patches-host/100-no_readline.patch
new file mode 100644
index 0000000000..209c302bb7
--- /dev/null
+++ b/package/utils/lua/patches-host/100-no_readline.patch
@@ -0,0 +1,49 @@
+--- a/src/luaconf.h
++++ b/src/luaconf.h
+@@ -38,7 +38,6 @@
+ #if defined(LUA_USE_LINUX)
+ #define LUA_USE_POSIX
+ #define LUA_USE_DLOPEN		/* needs an extra library: -ldl */
+-#define LUA_USE_READLINE	/* needs some extra libraries */
+ #endif
+ 
+ #if defined(LUA_USE_MACOSX)
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -17,6 +17,7 @@
+ MYCFLAGS=
+ MYLDFLAGS=
+ MYLIBS=
++# USE_READLINE=1
+ 
+ # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE =========
+ 
+@@ -75,7 +76,7 @@
+ 	@echo "MYLIBS = $(MYLIBS)"
+ 
+ # convenience targets for popular platforms
+-
++RFLAG=$(if $(USE_READLINE),-DLUA_USE_READLINE)
+ none:
+ 	@echo "Please choose a platform:"
+ 	@echo "   $(PLATS)"
+@@ -90,16 +91,16 @@
+ 	$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E"
+ 
+ freebsd:
+-	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline"
++	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" $(RFLAG)" MYLIBS="-Wl,-E$(if $(USE_READLINE), -lreadline)"
+ 
+ generic:
+ 	$(MAKE) all MYCFLAGS=
+ 
+ linux:
+-	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses"
++	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX $(RFLAG)" MYLIBS="-Wl,-E -ldl $(if $(USE_READLINE), -lreadline -lhistory -lncurses)"
+ 
+ macosx:
+-	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline"
++	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX $(if $(USE_READLINE), MYLIBS="-lreadline")
+ # use this on Mac OS X 10.3-
+ #	$(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX
+ 
diff --git a/package/utils/lua/patches/010-lua-5.1.3-lnum-full-260308.patch b/package/utils/lua/patches/010-lua-5.1.3-lnum-full-260308.patch
new file mode 100644
index 0000000000..74b8c6f8f0
--- /dev/null
+++ b/package/utils/lua/patches/010-lua-5.1.3-lnum-full-260308.patch
@@ -0,0 +1,3736 @@
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -25,7 +25,7 @@ PLATS= aix ansi bsd freebsd generic linu
+ LUA_A=	liblua.a
+ CORE_O=	lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
+ 	lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o  \
+-	lundump.o lvm.o lzio.o
++	lundump.o lvm.o lzio.o lnum.o
+ LIB_O=	lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
+ 	lstrlib.o loadlib.o linit.o
+ 
+@@ -148,6 +148,7 @@ llex.o: llex.c lua.h luaconf.h ldo.h lob
+ lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
+ lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+   ltm.h lzio.h lmem.h ldo.h
++lnum.o: lnum.c lua.h llex.h lnum.h
+ loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
+ lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \
+   ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h
+@@ -179,4 +180,18 @@ lzio.o: lzio.c lua.h luaconf.h llimits.h
+ print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \
+   ltm.h lzio.h lmem.h lopcodes.h lundump.h
+ 
++luaconf.h: lnum_config.h
++lapi.c: lnum.h
++lauxlib.c: llimits.h
++lbaselib.c: llimits.h lobject.h lapi.h
++lcode.c: lnum.h
++liolib.c: lnum.h llex.h
++llex.c: lnum.h
++lnum.h: lobject.h
++lobject.c: llex.h lnum.h
++ltable.c: lnum.h
++lua.c: llimits.h
++lvm.c: llex.h lnum.h
++print.c: lnum.h
++
+ # (end of Makefile)
+--- a/src/lapi.c
++++ b/src/lapi.c
+@@ -28,7 +28,7 @@
+ #include "ltm.h"
+ #include "lundump.h"
+ #include "lvm.h"
+-
++#include "lnum.h"
+ 
+ 
+ const char lua_ident[] =
+@@ -241,12 +241,13 @@ LUA_API void lua_pushvalue (lua_State *L
+ 
+ LUA_API int lua_type (lua_State *L, int idx) {
+   StkId o = index2adr(L, idx);
+-  return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
++  return (o == luaO_nilobject) ? LUA_TNONE : ttype_ext(o);
+ }
+ 
+ 
+ LUA_API const char *lua_typename (lua_State *L, int t) {
+   UNUSED(L);
++  lua_assert( t!= LUA_TINT );
+   return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
+ }
+ 
+@@ -264,6 +265,14 @@ LUA_API int lua_isnumber (lua_State *L, 
+ }
+ 
+ 
++LUA_API int lua_isinteger (lua_State *L, int idx) {
++  TValue tmp;
++  lua_Integer dum;
++  const TValue *o = index2adr(L, idx);
++  return tonumber(o,&tmp) && (ttisint(o) || tt_integer_valued(o,&dum));
++}
++
++
+ LUA_API int lua_isstring (lua_State *L, int idx) {
+   int t = lua_type(L, idx);
+   return (t == LUA_TSTRING || t == LUA_TNUMBER);
+@@ -309,31 +318,66 @@ LUA_API int lua_lessthan (lua_State *L, 
+ }
+ 
+ 
+-
+ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
+   TValue n;
+   const TValue *o = index2adr(L, idx);
+-  if (tonumber(o, &n))
++  if (tonumber(o, &n)) {
++#ifdef LNUM_COMPLEX
++    if (nvalue_img(o) != 0)
++      luaG_runerror(L, "expecting a real number");
++#endif
+     return nvalue(o);
+-  else
+-    return 0;
++  }
++  return 0;
+ }
+ 
+ 
+ LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
+   TValue n;
++    /* Lua 5.1 documented behaviour is to return nonzero for non-integer:
++     * "If the number is not an integer, it is truncated in some non-specified way." 
++     * I would suggest to change this, to return 0 for anything that would
++     * not fit in 'lua_Integer'.
++     */
++#ifdef LUA_COMPAT_TOINTEGER
++  /* Lua 5.1 compatible */
+   const TValue *o = index2adr(L, idx);
+   if (tonumber(o, &n)) {
+-    lua_Integer res;
+-    lua_Number num = nvalue(o);
+-    lua_number2integer(res, num);
+-    return res;
++    lua_Integer i;
++    lua_Number d;
++    if (ttisint(o)) return ivalue(o);
++    d= nvalue_fast(o);
++# ifdef LNUM_COMPLEX
++    if (nvalue_img_fast(o) != 0)
++      luaG_runerror(L, "expecting a real number");
++# endif
++    lua_number2integer(i, d);
++    return i;
+   }
+-  else
+-    return 0;
++#else
++  /* New suggestion */
++  const TValue *o = index2adr(L, idx);
++  if (tonumber(o, &n)) {
++    lua_Integer i;
++    if (ttisint(o)) return ivalue(o);
++    if (tt_integer_valued(o,&i)) return i;
++  }
++#endif
++  return 0;
+ }
+ 
+ 
++#ifdef LNUM_COMPLEX
++LUA_API lua_Complex lua_tocomplex (lua_State *L, int idx) {
++  TValue tmp;
++  const TValue *o = index2adr(L, idx);
++  if (tonumber(o, &tmp))
++    return nvalue_complex(o);
++  return 0;
++}
++#endif
++
++
+ LUA_API int lua_toboolean (lua_State *L, int idx) {
+   const TValue *o = index2adr(L, idx);
+   return !l_isfalse(o);
+@@ -364,6 +408,7 @@ LUA_API size_t lua_objlen (lua_State *L,
+     case LUA_TSTRING: return tsvalue(o)->len;
+     case LUA_TUSERDATA: return uvalue(o)->len;
+     case LUA_TTABLE: return luaH_getn(hvalue(o));
++    case LUA_TINT:
+     case LUA_TNUMBER: {
+       size_t l;
+       lua_lock(L);  /* `luaV_tostring' may create a new string */
+@@ -426,6 +471,8 @@ LUA_API void lua_pushnil (lua_State *L) 
+ }
+ 
+ 
++/* 'lua_pushnumber()' may lose accuracy on integers, 'lua_pushinteger' will not.
++ */
+ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
+   lua_lock(L);
+   setnvalue(L->top, n);
+@@ -434,12 +481,22 @@ LUA_API void lua_pushnumber (lua_State *
+ }
+ 
+ 
+-LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
++LUA_API void lua_pushinteger (lua_State *L, lua_Integer i) {
++  lua_lock(L);
++  setivalue(L->top, i);
++  api_incr_top(L);
++  lua_unlock(L);
++}
++
++
++#ifdef LNUM_COMPLEX
++LUA_API void lua_pushcomplex (lua_State *L, lua_Complex v) {
+   lua_lock(L);
+-  setnvalue(L->top, cast_num(n));
++  setnvalue_complex( L->top, v );
+   api_incr_top(L);
+   lua_unlock(L);
+ }
++#endif
+ 
+ 
+ LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
+@@ -569,7 +626,7 @@ LUA_API void lua_rawgeti (lua_State *L, 
+   lua_lock(L);
+   o = index2adr(L, idx);
+   api_check(L, ttistable(o));
+-  setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
++  setobj2s(L, L->top, luaH_getint(hvalue(o), n));
+   api_incr_top(L);
+   lua_unlock(L);
+ }
+@@ -597,6 +654,9 @@ LUA_API int lua_getmetatable (lua_State 
+     case LUA_TUSERDATA:
+       mt = uvalue(obj)->metatable;
+       break;
++    case LUA_TINT:
++      mt = G(L)->mt[LUA_TNUMBER];
++      break;
+     default:
+       mt = G(L)->mt[ttype(obj)];
+       break;
+@@ -687,7 +747,7 @@ LUA_API void lua_rawseti (lua_State *L, 
+   api_checknelems(L, 1);
+   o = index2adr(L, idx);
+   api_check(L, ttistable(o));
+-  setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
++  setobj2t(L, luaH_setint(L, hvalue(o), n), L->top-1);
+   luaC_barriert(L, hvalue(o), L->top-1);
+   L->top--;
+   lua_unlock(L);
+@@ -721,7 +781,7 @@ LUA_API int lua_setmetatable (lua_State 
+       break;
+     }
+     default: {
+-      G(L)->mt[ttype(obj)] = mt;
++      G(L)->mt[ttype_ext(obj)] = mt;
+       break;
+     }
+   }
+@@ -1085,3 +1145,32 @@ LUA_API const char *lua_setupvalue (lua_
+   return name;
+ }
+ 
++
++/* Help function for 'luaB_tonumber()', avoids multiple str->number
++ * conversions for Lua "tonumber()".
++ *
++ * Also pushes floating point numbers with integer value as integer, which
++ * can be used by 'tonumber()' in scripts to bring values back to integer
++ * realm.
++ *
++ * Note: The 'back to integer realm' is _not_ to affect string conversions:
++ * 'tonumber("4294967295.1")' should give a floating point value, although
++ * the value would be 4294967296 (and storable in int64 realm).
++ */
++int lua_pushvalue_as_number (lua_State *L, int idx)
++{
++  const TValue *o = index2adr(L, idx);
++  TValue tmp;
++  lua_Integer i;
++  if (ttisnumber(o)) {
++    if ( (!ttisint(o)) && tt_integer_valued(o,&i)) {
++      lua_pushinteger( L, i );
++      return 1;
++    }
++  } else if (!tonumber(o, &tmp)) {
++    return 0;
++  }
++  if (ttisint(o)) lua_pushinteger( L, ivalue(o) );
++  else lua_pushnumber( L, nvalue_fast(o) );
++  return 1;
++}
+--- a/src/lapi.h
++++ b/src/lapi.h
+@@ -13,4 +13,6 @@
+ 
+ LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
+ 
++int lua_pushvalue_as_number (lua_State *L, int idx);
++
+ #endif
+--- a/src/lauxlib.c
++++ b/src/lauxlib.c
+@@ -23,7 +23,7 @@
+ #include "lua.h"
+ 
+ #include "lauxlib.h"
+-
++#include "llimits.h"
+ 
+ #define FREELIST_REF	0	/* free list of references */
+ 
+@@ -66,7 +66,7 @@ LUALIB_API int luaL_typerror (lua_State 
+ 
+ 
+ static void tag_error (lua_State *L, int narg, int tag) {
+-  luaL_typerror(L, narg, lua_typename(L, tag));
++  luaL_typerror(L, narg, tag==LUA_TINT ? "integer" : lua_typename(L, tag));
+ }
+ 
+ 
+@@ -188,8 +188,8 @@ LUALIB_API lua_Number luaL_optnumber (lu
+ 
+ LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
+   lua_Integer d = lua_tointeger(L, narg);
+-  if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
+-    tag_error(L, narg, LUA_TNUMBER);
++  if (d == 0 && !lua_isinteger(L, narg))  /* avoid extra test when d is not 0 */
++    tag_error(L, narg, LUA_TINT);
+   return d;
+ }
+ 
+@@ -200,6 +200,16 @@ LUALIB_API lua_Integer luaL_optinteger (
+ }
+ 
+ 
++#ifdef LNUM_COMPLEX
++LUALIB_API lua_Complex luaL_checkcomplex (lua_State *L, int narg) {
++  lua_Complex c = lua_tocomplex(L, narg);
++  if (c == 0 && !lua_isnumber(L, narg))  /* avoid extra test when c is not 0 */
++    tag_error(L, narg, LUA_TNUMBER);
++  return c;
++}
++#endif
++
++
+ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
+   if (!lua_getmetatable(L, obj))  /* no metatable? */
+     return 0;
+--- a/src/lauxlib.h
++++ b/src/lauxlib.h
+@@ -57,6 +57,12 @@ LUALIB_API lua_Number (luaL_optnumber) (
+ LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
+ LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
+                                           lua_Integer def);
++#define luaL_checkint32(L,narg) ((int)luaL_checkinteger(L,narg))
++#define luaL_optint32(L,narg,def) ((int)luaL_optinteger(L,narg,def))
++
++#ifdef LNUM_COMPLEX
++  LUALIB_API lua_Complex (luaL_checkcomplex) (lua_State *L, int narg);
++#endif
+ 
+ LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+ LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
+--- a/src/lbaselib.c
++++ b/src/lbaselib.c
+@@ -18,7 +18,9 @@
+ 
+ #include "lauxlib.h"
+ #include "lualib.h"
+-
++#include "llimits.h"
++#include "lobject.h"
++#include "lapi.h"
+ 
+ 
+ 
+@@ -54,20 +56,25 @@ static int luaB_tonumber (lua_State *L) 
+   int base = luaL_optint(L, 2, 10);
+   if (base == 10) {  /* standard conversion */
+     luaL_checkany(L, 1);
+-    if (lua_isnumber(L, 1)) {
+-      lua_pushnumber(L, lua_tonumber(L, 1));
++    if (lua_isnumber(L, 1)) {       /* numeric string, or a number */
++      lua_pushvalue_as_number(L,1);     /* API extension (not to lose accuracy here) */
+       return 1;
+-    }
++	}
+   }
+   else {
+     const char *s1 = luaL_checkstring(L, 1);
+     char *s2;
+-    unsigned long n;
++    unsigned LUA_INTEGER n;
+     luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+-    n = strtoul(s1, &s2, base);
++    n = lua_str2ul(s1, &s2, base);
+     if (s1 != s2) {  /* at least one valid digit? */
+       while (isspace((unsigned char)(*s2))) s2++;  /* skip trailing spaces */
+       if (*s2 == '\0') {  /* no invalid trailing characters? */
++	  
++		/* Push as number, there needs to be separate 'luaB_tointeger' for
++		 * when the caller wants to preserve the bits (matters if unsigned
++		 * values are used).
++		 */
+         lua_pushnumber(L, (lua_Number)n);
+         return 1;
+       }
+@@ -144,7 +151,7 @@ static int luaB_setfenv (lua_State *L) {
+   luaL_checktype(L, 2, LUA_TTABLE);
+   getfunc(L, 0);
+   lua_pushvalue(L, 2);
+-  if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
++  if (lua_isnumber(L, 1) && lua_tointeger(L, 1) == 0) {
+     /* change environment of current thread */
+     lua_pushthread(L);
+     lua_insert(L, -2);
+@@ -209,7 +216,7 @@ static int luaB_collectgarbage (lua_Stat
+       return 1;
+     }
+     default: {
+-      lua_pushnumber(L, res);
++      lua_pushinteger(L, res);
+       return 1;
+     }
+   }
+@@ -631,6 +638,8 @@ static void base_open (lua_State *L) {
+   luaL_register(L, "_G", base_funcs);
+   lua_pushliteral(L, LUA_VERSION);
+   lua_setglobal(L, "_VERSION");  /* set global _VERSION */
++  lua_pushliteral(L, LUA_LNUM);
++  lua_setglobal(L, "_LNUM");  /* "[complex] double|float|ldouble int32|int64" */
+   /* `ipairs' and `pairs' need auxiliary functions as upvalues */
+   auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
+   auxopen(L, "pairs", luaB_pairs, luaB_next);
+--- a/src/lcode.c
++++ b/src/lcode.c
+@@ -22,13 +22,18 @@
+ #include "lopcodes.h"
+ #include "lparser.h"
+ #include "ltable.h"
++#include "lnum.h"
+ 
+ 
+ #define hasjumps(e)	((e)->t != (e)->f)
+ 
+-
+ static int isnumeral(expdesc *e) {
+-  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
++  int ek=
++#ifdef LNUM_COMPLEX
++    (e->k == VKNUM2) ||
++#endif
++    (e->k == VKINT) || (e->k == VKNUM);
++  return (ek && e->t == NO_JUMP && e->f == NO_JUMP);
+ }
+ 
+ 
+@@ -231,12 +236,16 @@ static int addk (FuncState *fs, TValue *
+   TValue *idx = luaH_set(L, fs->h, k);
+   Proto *f = fs->f;
+   int oldsize = f->sizek;
+-  if (ttisnumber(idx)) {
+-    lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
+-    return cast_int(nvalue(idx));
++  if (ttype(idx)==LUA_TNUMBER) {
++    luai_normalize(idx);
++    lua_assert( ttype(idx)==LUA_TINT );     /* had no fraction */
++  }
++  if (ttisint(idx)) {
++    lua_assert(luaO_rawequalObj(&fs->f->k[ivalue(idx)], v));
++    return cast_int(ivalue(idx));
+   }
+   else {  /* constant not found; create a new entry */
+-    setnvalue(idx, cast_num(fs->nk));
++    setivalue(idx, fs->nk);
+     luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
+                     MAXARG_Bx, "constant table overflow");
+     while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
+@@ -261,6 +270,21 @@ int luaK_numberK (FuncState *fs, lua_Num
+ }
+ 
+ 
++int luaK_integerK (FuncState *fs, lua_Integer r) {
++  TValue o;
++  setivalue(&o, r);
++  return addk(fs, &o, &o);
++}
++
++
++#ifdef LNUM_COMPLEX
++static int luaK_imagK (FuncState *fs, lua_Number r) {
++  TValue o;
++  setnvalue_complex(&o, r*I);
++  return addk(fs, &o, &o);
++}
++#endif
++
+ static int boolK (FuncState *fs, int b) {
+   TValue o;
+   setbvalue(&o, b);
+@@ -359,6 +383,16 @@ static void discharge2reg (FuncState *fs
+       luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
+       break;
+     }
++    case VKINT: {
++      luaK_codeABx(fs, OP_LOADK, reg, luaK_integerK(fs, e->u.ival));
++      break;
++    }
++#ifdef LNUM_COMPLEX
++    case VKNUM2: {
++      luaK_codeABx(fs, OP_LOADK, reg, luaK_imagK(fs, e->u.nval));
++      break;
++    }
++#endif
+     case VRELOCABLE: {
+       Instruction *pc = &getcode(fs, e);
+       SETARG_A(*pc, reg);
+@@ -444,6 +478,10 @@ void luaK_exp2val (FuncState *fs, expdes
+ int luaK_exp2RK (FuncState *fs, expdesc *e) {
+   luaK_exp2val(fs, e);
+   switch (e->k) {
++#ifdef LNUM_COMPLEX
++    case VKNUM2:
++#endif
++    case VKINT:
+     case VKNUM:
+     case VTRUE:
+     case VFALSE:
+@@ -451,6 +489,10 @@ int luaK_exp2RK (FuncState *fs, expdesc 
+       if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
+         e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
+                       (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
++                      (e->k == VKINT) ? luaK_integerK(fs, e->u.ival) :
++#ifdef LNUM_COMPLEX
++                      (e->k == VKNUM2) ? luaK_imagK(fs, e->u.nval) :
++#endif
+                                         boolK(fs, (e->k == VTRUE));
+         e->k = VK;
+         return RKASK(e->u.s.info);
+@@ -540,7 +582,10 @@ void luaK_goiftrue (FuncState *fs, expde
+   int pc;  /* pc of last jump */
+   luaK_dischargevars(fs, e);
+   switch (e->k) {
+-    case VK: case VKNUM: case VTRUE: {
++#ifdef LNUM_COMPLEX
++    case VKNUM2:
++#endif
++    case VKINT: case VK: case VKNUM: case VTRUE: {
+       pc = NO_JUMP;  /* always true; do nothing */
+       break;
+     }
+@@ -590,7 +635,10 @@ static void codenot (FuncState *fs, expd
+       e->k = VTRUE;
+       break;
+     }
+-    case VK: case VKNUM: case VTRUE: {
++#ifdef LNUM_COMPLEX
++    case VKNUM2:
++#endif
++    case VKINT: case VK: case VKNUM: case VTRUE: {
+       e->k = VFALSE;
+       break;
+     }
+@@ -626,25 +674,70 @@ void luaK_indexed (FuncState *fs, expdes
+ 
+ static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
+   lua_Number v1, v2, r;
++  int vkres= VKNUM;
+   if (!isnumeral(e1) || !isnumeral(e2)) return 0;
+-  v1 = e1->u.nval;
+-  v2 = e2->u.nval;
++
++  /* real and imaginary parts don't mix. */
++#ifdef LNUM_COMPLEX
++  if (e1->k == VKNUM2) {
++    if ((op != OP_UNM) && (e2->k != VKNUM2)) return 0; 
++    vkres= VKNUM2; }
++  else if (e2->k == VKNUM2) { return 0; }
++#endif
++  if ((e1->k == VKINT) && (e2->k == VKINT)) {
++    lua_Integer i1= e1->u.ival, i2= e2->u.ival;
++    lua_Integer rr;
++    int done= 0;
++    /* Integer/integer calculations (may end up producing floating point) */
++    switch (op) {
++      case OP_ADD: done= try_addint( &rr, i1, i2 ); break;
++      case OP_SUB: done= try_subint( &rr, i1, i2 ); break;
++      case OP_MUL: done= try_mulint( &rr, i1, i2 ); break;
++      case OP_DIV: done= try_divint( &rr, i1, i2 ); break;
++      case OP_MOD: done= try_modint( &rr, i1, i2 ); break;
++      case OP_POW: done= try_powint( &rr, i1, i2 ); break;
++      case OP_UNM: done= try_unmint( &rr, i1 ); break;
++      default:     done= 0; break;
++    }
++    if (done) {
++      e1->u.ival = rr;  /* remained within integer range */
++      return 1;
++    }
++  }
++  v1 = (e1->k == VKINT) ? ((lua_Number)e1->u.ival) : e1->u.nval;
++  v2 = (e2->k == VKINT) ? ((lua_Number)e2->u.ival) : e2->u.nval;
++
+   switch (op) {
+     case OP_ADD: r = luai_numadd(v1, v2); break;
+     case OP_SUB: r = luai_numsub(v1, v2); break;
+-    case OP_MUL: r = luai_nummul(v1, v2); break;
++    case OP_MUL: 
++#ifdef LNUM_COMPLEX
++        if (vkres==VKNUM2) return 0;    /* leave to runtime (could do here, but not worth it?) */
++#endif
++        r = luai_nummul(v1, v2); break;
+     case OP_DIV:
+       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
+-      r = luai_numdiv(v1, v2); break;
++#ifdef LNUM_COMPLEX
++        if (vkres==VKNUM2) return 0;    /* leave to runtime */
++#endif
++        r = luai_numdiv(v1, v2); break;
+     case OP_MOD:
+       if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
++#ifdef LNUM_COMPLEX
++      if (vkres==VKNUM2) return 0;    /* leave to runtime */
++#endif
+       r = luai_nummod(v1, v2); break;
+-    case OP_POW: r = luai_numpow(v1, v2); break;
++    case OP_POW: 
++#ifdef LNUM_COMPLEX
++      if (vkres==VKNUM2) return 0;    /* leave to runtime */
++#endif
++      r = luai_numpow(v1, v2); break;
+     case OP_UNM: r = luai_numunm(v1); break;
+     case OP_LEN: return 0;  /* no constant folding for 'len' */
+     default: lua_assert(0); r = 0; break;
+   }
+   if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */
++  e1->k = cast(expkind,vkres);
+   e1->u.nval = r;
+   return 1;
+ }
+@@ -688,7 +781,8 @@ static void codecomp (FuncState *fs, OpC
+ 
+ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+   expdesc e2;
+-  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
++  e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
++
+   switch (op) {
+     case OPR_MINUS: {
+       if (!isnumeral(e))
+--- a/src/lcode.h
++++ b/src/lcode.h
+@@ -71,6 +71,6 @@ LUAI_FUNC void luaK_prefix (FuncState *f
+ LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+ LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
+ LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
+-
++LUAI_FUNC int luaK_integerK (FuncState *fs, lua_Integer r);
+ 
+ #endif
+--- a/src/ldebug.c
++++ b/src/ldebug.c
+@@ -183,7 +183,7 @@ static void collectvalidlines (lua_State
+     int *lineinfo = f->l.p->lineinfo;
+     int i;
+     for (i=0; i<f->l.p->sizelineinfo; i++)
+-      setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
++      setbvalue(luaH_setint(L, t, lineinfo[i]), 1);
+     sethvalue(L, L->top, t); 
+   }
+   incr_top(L);
+@@ -566,7 +566,7 @@ static int isinstack (CallInfo *ci, cons
+ 
+ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+   const char *name = NULL;
+-  const char *t = luaT_typenames[ttype(o)];
++  const char *t = luaT_typenames[ttype_ext(o)];
+   const char *kind = (isinstack(L->ci, o)) ?
+                          getobjname(L, L->ci, cast_int(o - L->base), &name) :
+                          NULL;
+@@ -594,8 +594,8 @@ void luaG_aritherror (lua_State *L, cons
+ 
+ 
+ int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
+-  const char *t1 = luaT_typenames[ttype(p1)];
+-  const char *t2 = luaT_typenames[ttype(p2)];
++  const char *t1 = luaT_typenames[ttype_ext(p1)];
++  const char *t2 = luaT_typenames[ttype_ext(p2)];
+   if (t1[2] == t2[2])
+     luaG_runerror(L, "attempt to compare two %s values", t1);
+   else
+--- a/src/ldo.c
++++ b/src/ldo.c
+@@ -220,9 +220,9 @@ static StkId adjust_varargs (lua_State *
+     luaD_checkstack(L, p->maxstacksize);
+     htab = luaH_new(L, nvar, 1);  /* create `arg' table */
+     for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */
+-      setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
++      setobj2n(L, luaH_setint(L, htab, i+1), L->top - nvar + i);
+     /* store counter in field `n' */
+-    setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
++    setivalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), nvar);
+   }
+ #endif
+   /* move fixed parameters to final position */
+--- a/src/ldump.c
++++ b/src/ldump.c
+@@ -52,6 +52,11 @@ static void DumpNumber(lua_Number x, Dum
+  DumpVar(x,D);
+ }
+ 
++static void DumpInteger(lua_Integer x, DumpState* D)
++{
++ DumpVar(x,D);
++}
++
+ static void DumpVector(const void* b, int n, size_t size, DumpState* D)
+ {
+  DumpInt(n,D);
+@@ -93,8 +98,11 @@ static void DumpConstants(const Proto* f
+ 	DumpChar(bvalue(o),D);
+ 	break;
+    case LUA_TNUMBER:
+-	DumpNumber(nvalue(o),D);
++	DumpNumber(nvalue_fast(o),D);
+ 	break;
++   case LUA_TINT:
++	DumpInteger(ivalue(o),D);
++    break;
+    case LUA_TSTRING:
+ 	DumpString(rawtsvalue(o),D);
+ 	break;
+--- a/src/liolib.c
++++ b/src/liolib.c
+@@ -9,6 +9,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <ctype.h>
+ 
+ #define liolib_c
+ #define LUA_LIB
+@@ -18,7 +19,8 @@
+ #include "lauxlib.h"
+ #include "lualib.h"
+ 
+-
++#include "lnum.h"
++#include "llex.h"
+ 
+ #define IO_INPUT	1
+ #define IO_OUTPUT	2
+@@ -269,6 +271,13 @@ static int io_lines (lua_State *L) {
+ ** =======================================================
+ */
+ 
++/*
++* Many problems if we intend the same 'n' format specifier (see 'file:read()')
++* to work for both FP and integer numbers, without losing their accuracy. So
++* we don't. 'n' reads numbers as floating points, 'i' as integers. Old code
++* remains valid, but won't provide full integer accuracy (this only matters
++* with float FP and/or 64-bit integers).
++*/
+ 
+ static int read_number (lua_State *L, FILE *f) {
+   lua_Number d;
+@@ -282,6 +291,43 @@ static int read_number (lua_State *L, FI
+   }
+ }
+ 
++static int read_integer (lua_State *L, FILE *f) {
++  lua_Integer i;
++  if (fscanf(f, LUA_INTEGER_SCAN, &i) == 1) {
++    lua_pushinteger(L, i);
++    return 1;
++  }
++  else return 0;  /* read fails */
++}
++
++#ifdef LNUM_COMPLEX
++static int read_complex (lua_State *L, FILE *f) {
++  /* NNN / NNNi / NNN+MMMi / NNN-MMMi */
++  lua_Number a,b;
++  if (fscanf(f, LUA_NUMBER_SCAN, &a) == 1) {
++    int c=fgetc(f);
++    switch(c) {
++        case 'i':
++            lua_pushcomplex(L, a*I);
++            return 1;
++        case '+':
++        case '-':
++            /* "i" is consumed if at the end; just 'NNN+MMM' will most likely
++             * behave as if "i" was there? (TBD: test)
++             */
++            if (fscanf(f, LUA_NUMBER_SCAN "i", &b) == 1) {
++                lua_pushcomplex(L, a+ (c=='+' ? b:-b)*I);
++                return 1;
++            }
++    }
++    ungetc( c,f );
++    lua_pushnumber(L,a);  /*real part only*/
++    return 1;
++  }
++  return 0;  /* read fails */
++}
++#endif
++
+ 
+ static int test_eof (lua_State *L, FILE *f) {
+   int c = getc(f);
+@@ -355,6 +401,14 @@ static int g_read (lua_State *L, FILE *f
+           case 'n':  /* number */
+             success = read_number(L, f);
+             break;
++          case 'i':  /* integer (full accuracy) */
++            success = read_integer(L, f);
++            break;
++#ifdef LNUM_COMPLEX
++          case 'c':  /* complex */
++            success = read_complex(L, f);
++            break;
++#endif
+           case 'l':  /* line */
+             success = read_line(L, f);
+             break;
+@@ -415,9 +469,10 @@ static int g_write (lua_State *L, FILE *
+   int status = 1;
+   for (; nargs--; arg++) {
+     if (lua_type(L, arg) == LUA_TNUMBER) {
+-      /* optimization: could be done exactly as for strings */
+-      status = status &&
+-          fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
++      if (lua_isinteger(L,arg))
++          status = status && fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) > 0;
++      else
++          status = status && fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
+     }
+     else {
+       size_t l;
+@@ -460,7 +515,7 @@ static int f_setvbuf (lua_State *L) {
+   static const char *const modenames[] = {"no", "full", "line", NULL};
+   FILE *f = tofile(L);
+   int op = luaL_checkoption(L, 2, NULL, modenames);
+-  lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
++  size_t sz = luaL_optint32(L, 3, LUAL_BUFFERSIZE);
+   int res = setvbuf(f, NULL, mode[op], sz);
+   return pushresult(L, res == 0, NULL);
+ }
+--- a/src/llex.c
++++ b/src/llex.c
+@@ -22,6 +22,7 @@
+ #include "lstring.h"
+ #include "ltable.h"
+ #include "lzio.h"
++#include "lnum.h"
+ 
+ 
+ 
+@@ -34,13 +35,17 @@
+ 
+ 
+ /* ORDER RESERVED */
+-const char *const luaX_tokens [] = {
++static const char *const luaX_tokens [] = {
+     "and", "break", "do", "else", "elseif",
+     "end", "false", "for", "function", "if",
+     "in", "local", "nil", "not", "or", "repeat",
+     "return", "then", "true", "until", "while",
+     "..", "...", "==", ">=", "<=", "~=",
+     "<number>", "<name>", "<string>", "<eof>",
++    "<integer>",
++#ifdef LNUM_COMPLEX
++    "<number2>",
++#endif
+     NULL
+ };
+ 
+@@ -90,7 +95,11 @@ static const char *txtToken (LexState *l
+   switch (token) {
+     case TK_NAME:
+     case TK_STRING:
++    case TK_INT:
+     case TK_NUMBER:
++#ifdef LNUM_COMPLEX
++    case TK_NUMBER2:
++#endif
+       save(ls, '\0');
+       return luaZ_buffer(ls->buff);
+     default:
+@@ -175,23 +184,27 @@ static void buffreplace (LexState *ls, c
+     if (p[n] == from) p[n] = to;
+ }
+ 
+-
+-static void trydecpoint (LexState *ls, SemInfo *seminfo) {
++/* TK_NUMBER (/ TK_NUMBER2) */
++static int trydecpoint (LexState *ls, SemInfo *seminfo) {
+   /* format error: try to update decimal point separator */
+   struct lconv *cv = localeconv();
+   char old = ls->decpoint;
++  int ret;
+   ls->decpoint = (cv ? cv->decimal_point[0] : '.');
+   buffreplace(ls, old, ls->decpoint);  /* try updated decimal separator */
+-  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
++  ret= luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r, NULL);
++  if (!ret) {
+     /* format error with correct decimal point: no more options */
+     buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */
+     luaX_lexerror(ls, "malformed number", TK_NUMBER);
+   }
++  return ret;
+ }
+ 
+ 
+-/* LUA_NUMBER */
+-static void read_numeral (LexState *ls, SemInfo *seminfo) {
++/* TK_NUMBER / TK_INT (/TK_NUMBER2) */
++static int read_numeral (LexState *ls, SemInfo *seminfo) {
++  int ret;
+   lua_assert(isdigit(ls->current));
+   do {
+     save_and_next(ls);
+@@ -202,8 +215,9 @@ static void read_numeral (LexState *ls, 
+     save_and_next(ls);
+   save(ls, '\0');
+   buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */
+-  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r))  /* format error? */
+-    trydecpoint(ls, seminfo); /* try to update decimal point separator */
++  ret= luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r, &seminfo->i );
++  if (!ret) return trydecpoint(ls, seminfo); /* try to update decimal point separator */
++  return ret;
+ }
+ 
+ 
+@@ -331,6 +345,7 @@ static void read_string (LexState *ls, i
+ }
+ 
+ 
++/* char / TK_* */
+ static int llex (LexState *ls, SemInfo *seminfo) {
+   luaZ_resetbuffer(ls->buff);
+   for (;;) {
+@@ -402,8 +417,7 @@ static int llex (LexState *ls, SemInfo *
+         }
+         else if (!isdigit(ls->current)) return '.';
+         else {
+-          read_numeral(ls, seminfo);
+-          return TK_NUMBER;
++          return read_numeral(ls, seminfo);
+         }
+       }
+       case EOZ: {
+@@ -416,8 +430,7 @@ static int llex (LexState *ls, SemInfo *
+           continue;
+         }
+         else if (isdigit(ls->current)) {
+-          read_numeral(ls, seminfo);
+-          return TK_NUMBER;
++          return read_numeral(ls, seminfo);
+         }
+         else if (isalpha(ls->current) || ls->current == '_') {
+           /* identifier or reserved word */
+--- a/src/llex.h
++++ b/src/llex.h
+@@ -29,19 +29,22 @@ enum RESERVED {
+   TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
+   /* other terminal symbols */
+   TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
+-  TK_NAME, TK_STRING, TK_EOS
++  TK_NAME, TK_STRING, TK_EOS, TK_INT
++#ifdef LNUM_COMPLEX
++  , TK_NUMBER2   /* imaginary constants: Ni */ 
++#endif
+ };
+ 
+ /* number of reserved words */
+ #define NUM_RESERVED	(cast(int, TK_WHILE-FIRST_RESERVED+1))
+ 
+ 
+-/* array with token `names' */
+-LUAI_DATA const char *const luaX_tokens [];
+-
+-
++/* SemInfo is a local data structure of 'llex.c', used for carrying a string
++ * or a number. A separate token (TK_*) will tell, how to interpret the data.
++ */      
+ typedef union {
+   lua_Number r;
++  lua_Integer i;
+   TString *ts;
+ } SemInfo;  /* semantics information */
+ 
+--- a/src/llimits.h
++++ b/src/llimits.h
+@@ -49,6 +49,7 @@ typedef LUAI_USER_ALIGNMENT_T L_Umaxalig
+ 
+ /* result of a `usual argument conversion' over lua_Number */
+ typedef LUAI_UACNUMBER l_uacNumber;
++typedef LUAI_UACINTEGER l_uacInteger;
+ 
+ 
+ /* internal assertions for in-house debugging */
+@@ -80,7 +81,6 @@ typedef LUAI_UACNUMBER l_uacNumber;
+ #define cast_int(i)	cast(int, (i))
+ 
+ 
+-
+ /*
+ ** type for virtual-machine instructions
+ ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+--- a/src/lmathlib.c
++++ b/src/lmathlib.c
+@@ -4,7 +4,6 @@
+ ** See Copyright Notice in lua.h
+ */
+ 
+-
+ #include <stdlib.h>
+ #include <math.h>
+ 
+@@ -16,113 +15,210 @@
+ #include "lauxlib.h"
+ #include "lualib.h"
+ 
++/* 'luai_vectpow()' as a replacement for 'cpow()'. Defined in the header; we
++ * don't intrude the code libs internal functions.
++ */
++#ifdef LNUM_COMPLEX
++# include "lnum.h"    
++#endif
+ 
+ #undef PI
+-#define PI (3.14159265358979323846)
+-#define RADIANS_PER_DEGREE (PI/180.0)
+-
++#ifdef LNUM_FLOAT
++# define PI (3.14159265358979323846F)
++#elif defined(M_PI)
++# define PI M_PI
++#else
++# define PI (3.14159265358979323846264338327950288)
++#endif
++#define RADIANS_PER_DEGREE (PI/180)
+ 
++#undef HUGE
++#ifdef LNUM_FLOAT
++# define HUGE HUGE_VALF
++#elif defined(LNUM_LDOUBLE)
++# define HUGE HUGE_VALL
++#else
++# define HUGE HUGE_VAL
++#endif
+ 
+ static int math_abs (lua_State *L) {
+-  lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushnumber(L, _LF(cabs) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(fabs) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_sin (lua_State *L) {
+-  lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(csin) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(sin) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_sinh (lua_State *L) {
+-  lua_pushnumber(L, sinh(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(csinh) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(sinh) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_cos (lua_State *L) {
+-  lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ccos) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(cos) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_cosh (lua_State *L) {
+-  lua_pushnumber(L, cosh(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ccosh) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(cosh) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_tan (lua_State *L) {
+-  lua_pushnumber(L, tan(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ctan) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(tan) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_tanh (lua_State *L) {
+-  lua_pushnumber(L, tanh(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(ctanh) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(tanh) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_asin (lua_State *L) {
+-  lua_pushnumber(L, asin(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(casin) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(asin) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_acos (lua_State *L) {
+-  lua_pushnumber(L, acos(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(cacos) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(acos) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_atan (lua_State *L) {
+-  lua_pushnumber(L, atan(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(catan) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(atan) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_atan2 (lua_State *L) {
+-  lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++  /* scalars only */
++  lua_pushnumber(L, _LF(atan2) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+   return 1;
+ }
+ 
+ static int math_ceil (lua_State *L) {
+-  lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_Complex v= luaL_checkcomplex(L, 1);
++  lua_pushcomplex(L, _LF(ceil) (_LF(creal)(v)) + _LF(ceil) (_LF(cimag)(v))*I);
++#else
++  lua_pushnumber(L, _LF(ceil) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_floor (lua_State *L) {
+-  lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_Complex v= luaL_checkcomplex(L, 1);
++  lua_pushcomplex(L, _LF(floor) (_LF(creal)(v)) + _LF(floor) (_LF(cimag)(v))*I);
++#else
++  lua_pushnumber(L, _LF(floor) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+-static int math_fmod (lua_State *L) {
+-  lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++static int math_fmod (lua_State *L) {  
++  /* scalars only */
++  lua_pushnumber(L, _LF(fmod) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+   return 1;
+ }
+ 
+ static int math_modf (lua_State *L) {
+-  double ip;
+-  double fp = modf(luaL_checknumber(L, 1), &ip);
++  /* scalars only */
++  lua_Number ip;
++  lua_Number fp = _LF(modf) (luaL_checknumber(L, 1), &ip);
+   lua_pushnumber(L, ip);
+   lua_pushnumber(L, fp);
+   return 2;
+ }
+ 
+ static int math_sqrt (lua_State *L) {
+-  lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(csqrt) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(sqrt) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_pow (lua_State *L) {
+-  lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++#ifdef LNUM_COMPLEX
++  /* C99 'cpow' gives somewhat inaccurate results (i.e. (-1)^2 = -1+1.2246467991474e-16i). 
++  * 'luai_vectpow' smoothens such, reusing it is the reason we need to #include "lnum.h".
++  */
++  lua_pushcomplex(L, luai_vectpow(luaL_checkcomplex(L,1), luaL_checkcomplex(L,2)));
++#else
++  lua_pushnumber(L, _LF(pow) (luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
++#endif
+   return 1;
+ }
+ 
+ static int math_log (lua_State *L) {
+-  lua_pushnumber(L, log(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(clog) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(log) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_log10 (lua_State *L) {
+-  lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  /* Not in standard <complex.h> , but easy to calculate: log_a(x) = log_b(x) / log_b(a) 
++  */
++  lua_pushcomplex(L, _LF(clog) (luaL_checkcomplex(L,1)) / _LF(log) (10));
++#else
++  lua_pushnumber(L, _LF(log10) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+ static int math_exp (lua_State *L) {
+-  lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
++#ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(cexp) (luaL_checkcomplex(L,1)));
++#else
++  lua_pushnumber(L, _LF(exp) (luaL_checknumber(L, 1)));
++#endif
+   return 1;
+ }
+ 
+@@ -138,19 +234,20 @@ static int math_rad (lua_State *L) {
+ 
+ static int math_frexp (lua_State *L) {
+   int e;
+-  lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
++  lua_pushnumber(L, _LF(frexp) (luaL_checknumber(L, 1), &e));
+   lua_pushinteger(L, e);
+   return 2;
+ }
+ 
+ static int math_ldexp (lua_State *L) {
+-  lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
++  lua_pushnumber(L, _LF(ldexp) (luaL_checknumber(L, 1), luaL_checkint(L, 2)));
+   return 1;
+ }
+ 
+ 
+ 
+ static int math_min (lua_State *L) {
++  /* scalars only */
+   int n = lua_gettop(L);  /* number of arguments */
+   lua_Number dmin = luaL_checknumber(L, 1);
+   int i;
+@@ -165,6 +262,7 @@ static int math_min (lua_State *L) {
+ 
+ 
+ static int math_max (lua_State *L) {
++  /* scalars only */
+   int n = lua_gettop(L);  /* number of arguments */
+   lua_Number dmax = luaL_checknumber(L, 1);
+   int i;
+@@ -182,25 +280,20 @@ static int math_random (lua_State *L) {
+   /* the `%' avoids the (rare) case of r==1, and is needed also because on
+      some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
+   lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
+-  switch (lua_gettop(L)) {  /* check number of arguments */
+-    case 0: {  /* no arguments */
+-      lua_pushnumber(L, r);  /* Number between 0 and 1 */
+-      break;
+-    }
+-    case 1: {  /* only upper limit */
+-      int u = luaL_checkint(L, 1);
+-      luaL_argcheck(L, 1<=u, 1, "interval is empty");
+-      lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */
+-      break;
+-    }
+-    case 2: {  /* lower and upper limits */
+-      int l = luaL_checkint(L, 1);
+-      int u = luaL_checkint(L, 2);
+-      luaL_argcheck(L, l<=u, 2, "interval is empty");
+-      lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */
+-      break;
+-    }
+-    default: return luaL_error(L, "wrong number of arguments");
++  int n= lua_gettop(L);  /* number of arguments */
++  if (n==0) {	/* no arguments: range [0,1) */
++    lua_pushnumber(L, r);
++  } else if (n<=2) {	/* int range [1,u] or [l,u] */
++    int l= n==1 ? 1 : luaL_checkint(L, 1);
++    int u = luaL_checkint(L, n);
++    int tmp;
++    lua_Number d;
++    luaL_argcheck(L, l<=u, n, "interval is empty");
++    d= _LF(floor)(r*(u-l+1));
++    lua_number2int(tmp,d);
++    lua_pushinteger(L, l+tmp);
++  } else {
++    return luaL_error(L, "wrong number of arguments");
+   }
+   return 1;
+ }
+@@ -211,6 +304,66 @@ static int math_randomseed (lua_State *L
+   return 0;
+ }
+ 
++/* 
++* Lua 5.1 does not have acosh, asinh, atanh for scalars (not ANSI C)
++*/
++#if __STDC_VERSION__ >= 199901L
++static int math_acosh (lua_State *L) {
++# ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(cacosh) (luaL_checkcomplex(L,1)));
++# else
++  lua_pushnumber(L, _LF(acosh) (luaL_checknumber(L,1)));
++# endif
++  return 1;
++}
++static int math_asinh (lua_State *L) {
++# ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(casinh) (luaL_checkcomplex(L,1)));
++# else
++  lua_pushnumber(L, _LF(asinh) (luaL_checknumber(L,1)));
++# endif
++  return 1;
++}
++static int math_atanh (lua_State *L) {
++# ifdef LNUM_COMPLEX
++  lua_pushcomplex(L, _LF(catanh) (luaL_checkcomplex(L,1)));
++# else
++  lua_pushnumber(L, _LF(atanh) (luaL_checknumber(L,1)));
++# endif
++  return 1;
++}
++#endif
++
++/* 
++ * C99 complex functions, not covered above.
++*/
++#ifdef LNUM_COMPLEX
++static int math_arg (lua_State *L) {
++  lua_pushnumber(L, _LF(carg) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_imag (lua_State *L) {
++  lua_pushnumber(L, _LF(cimag) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_real (lua_State *L) {
++  lua_pushnumber(L, _LF(creal) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_conj (lua_State *L) {
++  lua_pushcomplex(L, _LF(conj) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++
++static int math_proj (lua_State *L) {
++  lua_pushcomplex(L, _LF(cproj) (luaL_checkcomplex(L,1)));
++  return 1;
++}
++#endif
++
+ 
+ static const luaL_Reg mathlib[] = {
+   {"abs",   math_abs},
+@@ -241,6 +394,18 @@ static const luaL_Reg mathlib[] = {
+   {"sqrt",  math_sqrt},
+   {"tanh",   math_tanh},
+   {"tan",   math_tan},
++#if __STDC_VERSION__ >= 199901L
++  {"acosh",  math_acosh},
++  {"asinh",  math_asinh},
++  {"atanh",  math_atanh},
++#endif
++#ifdef LNUM_COMPLEX
++  {"arg",   math_arg},
++  {"imag",  math_imag},
++  {"real",  math_real},
++  {"conj",  math_conj},
++  {"proj",  math_proj},
++#endif
+   {NULL, NULL}
+ };
+ 
+@@ -252,8 +417,10 @@ LUALIB_API int luaopen_math (lua_State *
+   luaL_register(L, LUA_MATHLIBNAME, mathlib);
+   lua_pushnumber(L, PI);
+   lua_setfield(L, -2, "pi");
+-  lua_pushnumber(L, HUGE_VAL);
++  lua_pushnumber(L, HUGE);
+   lua_setfield(L, -2, "huge");
++  lua_pushinteger(L, LUA_INTEGER_MAX );
++  lua_setfield(L, -2, "hugeint");
+ #if defined(LUA_COMPAT_MOD)
+   lua_getfield(L, -1, "fmod");
+   lua_setfield(L, -2, "mod");
+--- /dev/null
++++ b/src/lnum.c
+@@ -0,0 +1,312 @@
++/*
++** $Id: lnum.c,v ... $
++** Internal number model
++** See Copyright Notice in lua.h
++*/
++
++#include <stdlib.h>
++#include <math.h>
++#include <ctype.h>
++#include <string.h>
++#include <stdio.h>
++#include <errno.h>
++
++#define lnum_c
++#define LUA_CORE
++
++#include "lua.h"
++#include "llex.h"
++#include "lnum.h"
++
++/*
++** lua_real2str converts a (non-complex) number to a string.
++** lua_str2real converts a string to a (non-complex) number.
++*/
++#define lua_real2str(s,n)  sprintf((s), LUA_NUMBER_FMT, (n))
++
++/*
++* Note: Only 'strtod()' is part of ANSI C; others are C99 and
++* may need '--std=c99' compiler setting (at least on Ubuntu 7.10).
++* 
++* Visual C++ 2008 Express does not have 'strtof()', nor 'strtold()'.
++* References to '_strtold()' exist but don't compile. It seems best
++* to leave Windows users with DOUBLE only (or compile with MinGW).
++*
++* In practise, using '(long double)strtod' is a risky thing, since
++* it will cause accuracy loss in reading in numbers, and such losses
++* will pile up in later processing. Get a real 'strtold()' or don't
++* use that mode at all.
++*/
++#ifdef LNUM_DOUBLE
++# define lua_str2real	strtod
++#elif defined(LNUM_FLOAT)
++# define lua_str2real	strtof
++#elif defined(LNUM_LDOUBLE)
++# define lua_str2real	strtold
++#endif
++
++#define lua_integer2str(s,v) sprintf((s), LUA_INTEGER_FMT, (v))
++
++/* 's' is expected to be LUAI_MAXNUMBER2STR long (enough for any number)
++*/
++void luaO_num2buf( char *s, const TValue *o )
++{
++  lua_Number n;
++  lua_assert( ttisnumber(o) );
++
++  /* Reason to handle integers differently is not only speed, but accuracy as
++   * well. We want to make any integer tostring() without roundings, at all.
++   */
++  if (ttisint(o)) {
++    lua_integer2str( s, ivalue(o) );
++    return;
++  }
++  n= nvalue_fast(o);
++  lua_real2str(s, n);
++
++#ifdef LNUM_COMPLEX
++  lua_Number n2= nvalue_img_fast(o);
++  if (n2!=0) {   /* Postfix with +-Ni */
++      int re0= (n == 0);
++      char *s2= re0 ? s : strchr(s,'\0'); 
++      if ((!re0) && (n2>0)) *s2++= '+';
++      lua_real2str( s2, n2 );
++      strcat(s2,"i");
++  }
++#endif
++}
++
++/*
++* If a LUA_TNUMBER has integer value, give it.
++*/
++int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref ) {
++  lua_Number d;
++  lua_Integer i;
++
++  lua_assert( ttype(o)==LUA_TNUMBER );
++  lua_assert( ref );
++#ifdef LNUM_COMPLEX
++  if (nvalue_img_fast(o)!=0) return 0;
++#endif
++  d= nvalue_fast(o);
++  lua_number2integer(i, d);
++  if (cast_num(i) == d) {
++    *ref= i; return 1;
++  }
++  return 0;
++}
++
++/* 
++ * Lua 5.1.3 (using 'strtod()') allows 0x+hex but not 0+octal. This is good,
++ * and we should NOT use 'autobase' 0 with 'strtoul[l]()' for this reason.
++ *
++ * Lua 5.1.3 allows '0x...' numbers to overflow and lose precision; this is not
++ * good. On Visual C++ 2008, 'strtod()' does not even take them in. Better to
++ * require hex values to fit 'lua_Integer' or give an error that they don't?
++ *
++ * Full hex range (0 .. 0xff..ff) is stored as integers, not to lose any bits.
++ * Numerical value of 0xff..ff will be -1, if used in calculations.
++ * 
++ * Returns: TK_INT for a valid integer, '*endptr_ref' updated
++ *          TK_NUMBER for seemingly numeric, to be parsed as floating point
++ *          0 for bad characters, not a number (or '0x' out of range)
++ */
++static int luaO_str2i (const char *s, lua_Integer *res, char **endptr_ref) {
++  char *endptr;
++  /* 'v' gets ULONG_MAX on possible overflow (which is > LUA_INTEGER_MAX);
++   * we don't have to check 'errno' here.
++   */
++  unsigned LUA_INTEGER v= lua_str2ul(s, &endptr, 10);
++  if (endptr == s) return 0;  /* nothing numeric */
++  if (v==0 && *endptr=='x') {
++    errno= 0;   /* needs to be set, 'strtoul[l]' does not clear it */
++    v= lua_str2ul(endptr+1, &endptr, 16);  /* retry as hex, unsigned range */
++    if (errno==ERANGE) {   /* clamped to 0xff..ff */
++#if (defined(LNUM_INT32) && !defined(LNUM_FLOAT)) || defined(LNUM_LDOUBLE)
++      return TK_NUMBER; /* Allow to be read as floating point (has more integer range) */
++#else
++      return 0;  /* Reject the number */
++#endif
++    }
++  } else if ((v > LUA_INTEGER_MAX) || (*endptr && (!isspace(*endptr)))) {
++    return TK_NUMBER;	/* not in signed range, or has '.', 'e' etc. trailing */
++  }
++  *res= (lua_Integer)v;
++  *endptr_ref= endptr;
++  return TK_INT;
++}
++
++/* 0 / TK_NUMBER / TK_INT (/ TK_NUMBER2) */
++int luaO_str2d (const char *s, lua_Number *res_n, lua_Integer *res_i) {
++  char *endptr;
++  int ret= TK_NUMBER;
++  /* Check integers first, if caller is allowing. 
++   * If 'res2'==NULL, they're only looking for floating point. 
++   */
++  if (res_i) {
++    ret= luaO_str2i(s,res_i,&endptr);
++    if (ret==0) return 0;
++  }
++  if (ret==TK_NUMBER) {
++    lua_assert(res_n);
++    /* Note: Visual C++ 2008 Express 'strtod()' does not read in "0x..."
++     *       numbers; it will read '0' and spit 'x' as endptr.
++     *       This means hex constants not fitting in 'lua_Integer' won't 
++     *       be read in at all. What to do?
++     */
++    *res_n = lua_str2real(s, &endptr);
++    if (endptr == s) return 0;  /* conversion failed */
++    /* Visual C++ 2008 'strtod()' does not allow "0x..." input. */
++#if defined(_MSC_VER) && !defined(LNUM_FLOAT) && !defined(LNUM_INT64)
++    if (*res_n==0 && *endptr=='x') {
++      /* Hex constant too big for 'lua_Integer' but that could fit in 'lua_Number'
++       * integer bits 
++       */
++      unsigned __int64 v= _strtoui64( s, &endptr, 16 );
++      /* We just let > 64 bit values be clamped to _UI64_MAX (MSDN does not say 'errno'==ERANGE would be set) */
++      *res_n= cast_num(v);
++      if (*res_n != v) return 0;    /* Would have lost accuracy */
++    }
++#endif
++#ifdef LNUM_COMPLEX
++    if (*endptr == 'i') { endptr++; ret= TK_NUMBER2; }
++#endif
++  }
++  if (*endptr) {
++    while (isspace(cast(unsigned char, *endptr))) endptr++;
++    if (*endptr) return 0;  /* invalid trail */
++  }
++  return ret;
++}
++
++
++/* Functions for finding out, when integer operations remain in range
++ * (and doing them).
++ */
++int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  lua_Integer v= ib+ic; /* may overflow */
++  if (ib>0 && ic>0)      { if (v < 0) return 0; /*overflow, use floats*/ }
++  else if (ib<0 && ic<0) { if (v >= 0) return 0; }
++  *r= v;
++  return 1;
++}
++
++int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  lua_Integer v= ib-ic; /* may overflow */
++  if (ib>=0 && ic<0)     { if (v < 0) return 0; /*overflow, use floats*/ }
++  else if (ib<0 && ic>0) { if (v >= 0) return 0; }
++  *r= v;
++  return 1;
++}
++
++int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  if (ib!=LUA_INTEGER_MIN && ic!=LUA_INTEGER_MIN) {
++    lua_Integer b= luai_abs(ib), c= luai_abs(ic);
++    if ( (ib==0) || (LUA_INTEGER_MAX/b >= c) ) {
++      *r= ib*ic;  /* no overflow */
++      return 1;
++    }
++  } else if (ib==0 || ic==0) {
++    *r= 0; return 1;
++  }
++
++  /* Result can be LUA_INTEGER_MIN; if it is, calculating it using floating 
++   * point will not cause accuracy loss.
++   */
++  if ( luai_nummul( cast_num(ib), cast_num(ic) ) == LUA_INTEGER_MIN ) {
++    *r= LUA_INTEGER_MIN;
++    return 1;
++  }
++  return 0;
++}
++
++int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  /* N/0: leave to float side, to give an error
++  */
++  if (ic==0) return 0;
++
++  /* N/LUA_INTEGER_MIN: always non-integer results, or 0 or +1
++  */
++  if (ic==LUA_INTEGER_MIN) {
++    if (ib==LUA_INTEGER_MIN) { *r=1; return 1; }
++    if (ib==0) { *r=0; return 1; }
++
++  /* LUA_INTEGER_MIN (-2^31|63)/N: calculate using float side (either the division 
++   *    causes non-integer results, or there is no accuracy loss in int->fp->int
++   *    conversions (N=2,4,8,..,256 and N=2^30,2^29,..2^23).
++   */
++  } else if (ib==LUA_INTEGER_MIN) {
++    lua_Number d= luai_numdiv( cast_num(LUA_INTEGER_MIN), cast_num(ic) );
++    lua_Integer i; lua_number2integer(i,d);
++    if (cast_num(i)==d) { *r= i; return 1; }
++  
++  } else {
++    /* Note: We _can_ use ANSI C mod here, even on negative values, since
++     *       we only test for == 0 (the sign would be implementation dependent).
++     */
++     if (ib%ic == 0) { *r= ib/ic; return 1; }
++  }
++
++  return 0;
++}
++
++int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++  if (ic!=0) {
++    /* ANSI C can be trusted when b%c==0, or when values are non-negative. 
++     * b - (floor(b/c) * c)
++     *   -->
++     * + +: b - (b/c) * c (b % c can be used)
++     * - -: b - (b/c) * c (b % c could work, but not defined by ANSI C)
++     * 0 -: b - (b/c) * c (=0, b % c could work, but not defined by ANSI C)
++     * - +: b - (b/c-1) * c (when b!=-c)
++     * + -: b - (b/c-1) * c (when b!=-c)
++     *
++     * o MIN%MIN ends up 0, via overflow in calcs but that does not matter.
++     * o MIN%MAX ends up MAX-1 (and other such numbers), also after overflow,
++     *   but that does not matter, results do.
++     */
++    lua_Integer v= ib % ic;
++    if ( v!=0 && (ib<0 || ic<0) ) {
++      v= ib - ((ib/ic) - ((ib<=0 && ic<0) ? 0:1)) * ic;
++    }      
++    /* Result should always have same sign as 2nd argument. (PIL2) */
++    lua_assert( (v<0) ? (ic<0) : (v>0) ? (ic>0) : 1 );
++    *r= v;
++    return 1;
++  }
++  return 0;  /* let float side return NaN */
++}
++
++int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) {
++
++    /* In FLOAT/INT32 or FLOAT|DOUBLE/INT64 modes, calculating integer powers 
++     * via FP realm may lose accuracy (i.e. 7^11 = 1977326743, which fits int32
++     * but not 23-bit float mantissa). 
++     *
++     * The current solution is dumb, but it works and uses little code. Use of
++     * integer powers is not anticipated to be very frequent (apart from 2^x,
++     * which is separately optimized).
++     */
++  if (ib==0) *r=0;
++  else if (ic<0) return 0;  /* FP realm */
++  else if (ib==2 && ic < (int)sizeof(lua_Integer)*8-1) *r= ((lua_Integer)1)<<ic;   /* 1,2,4,...2^30 | 2^62 optimization */
++  else if (ic==0) *r=1;
++  else if (luai_abs(ib)==1) *r= (ic%2) ? ib:1;
++  else {
++    lua_Integer x= ib;
++    while( --ic ) {
++      if (!try_mulint( &x, x, ib ))
++        return 0; /* FP realm */
++    }
++    *r= x;
++  }
++  return 1;
++}
++
++int try_unmint( lua_Integer *r, lua_Integer ib ) {
++  /* Negating LUA_INTEGER_MIN leaves the range. */
++  if ( ib != LUA_INTEGER_MIN )  
++    { *r= -ib; return 1; }
++  return 0;
++}
++
+--- /dev/null
++++ b/src/lnum.h
+@@ -0,0 +1,116 @@
++/*
++** $Id: lnum.h,v ... $
++** Internal Number model
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lnum_h
++#define lnum_h
++
++#include <math.h>
++
++#include "lobject.h"
++
++/*
++** The luai_num* macros define the primitive operations over 'lua_Number's
++** (not 'lua_Integer's, not 'lua_Complex').
++*/
++#define luai_numadd(a,b)	((a)+(b))
++#define luai_numsub(a,b)	((a)-(b))
++#define luai_nummul(a,b)	((a)*(b))
++#define luai_numdiv(a,b)	((a)/(b))
++#define luai_nummod(a,b)	((a) - _LF(floor)((a)/(b))*(b))
++#define luai_numpow(a,b)	(_LF(pow)(a,b))
++#define luai_numunm(a)		(-(a))
++#define luai_numeq(a,b)	    ((a)==(b))
++#define luai_numlt(a,b)	    ((a)<(b))
++#define luai_numle(a,b)	    ((a)<=(b))
++#define luai_numisnan(a)	(!luai_numeq((a), (a)))
++
++int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic );
++int try_unmint( lua_Integer *r, lua_Integer ib );
++
++#ifdef LNUM_COMPLEX
++  static inline lua_Complex luai_vectunm( lua_Complex a ) { return -a; }
++  static inline lua_Complex luai_vectadd( lua_Complex a, lua_Complex b ) { return a+b; }
++  static inline lua_Complex luai_vectsub( lua_Complex a, lua_Complex b ) { return a-b; }
++  static inline lua_Complex luai_vectmul( lua_Complex a, lua_Complex b ) { return a*b; }
++  static inline lua_Complex luai_vectdiv( lua_Complex a, lua_Complex b ) { return a/b; }
++
++/* 
++ * C99 does not provide modulus for complex numbers. It most likely is not
++ * meaningful at all.
++ */
++
++/* 
++ * Complex power
++ *
++ * C99 'cpow' gives inaccurate results for many common cases s.a. (1i)^2 -> 
++ * -1+1.2246467991474e-16i (OS X 10.4, gcc 4.0.1 build 5367)
++ * 
++ * [(a+bi)^(c+di)] = (r^c) * exp(-d*t) * cos(c*t + d*ln(r)) +
++ *                 = (r^c) * exp(-d*t) * sin(c*t + d*ln(r)) *i
++ * r = sqrt(a^2+b^2), t = arctan( b/a )
++ * 
++ * Reference: <http://home.att.net/~srschmitt/complexnumbers.html>
++ * Could also be calculated using: x^y = exp(ln(x)*y)
++ *
++ * Note: Defined here (and not in .c) so 'lmathlib.c' can share the 
++ *       implementation.
++ */
++  static inline
++  lua_Complex luai_vectpow( lua_Complex a, lua_Complex b )
++  {
++# if 1
++    lua_Number ar= _LF(creal)(a), ai= _LF(cimag)(a);
++    lua_Number br= _LF(creal)(b), bi= _LF(cimag)(b);
++    
++    if (ai==0 && bi==0) {     /* a^c (real) */
++        return luai_numpow( ar, br );
++    } 
++
++    int br_int= (int)br;
++    
++    if ( ai!=0 && bi==0 && br_int==br && br_int!=0 && br_int!=INT_MIN ) { 
++        /* (a+bi)^N, N = { +-1,+-2, ... +-INT_MAX } 
++        */
++        lua_Number k= luai_numpow( _LF(sqrt) (ar*ar + ai*ai), br );
++        lua_Number cos_z, sin_z;
++
++        /* Situation depends upon c (N) in the following manner:
++         * 
++         * N%4==0                                => cos(c*t)=1, sin(c*t)=0
++         * (N*sign(b))%4==1 or (N*sign(b))%4==-3 => cos(c*t)=0, sin(c*t)=1
++         * N%4==2 or N%4==-2                     => cos(c*t)=-1, sin(c*t)=0
++         * (N*sign(b))%4==-1 or (N*sign(b))%4==3 => cos(c*t)=0, sin(c*t)=-1
++         */
++      int br_int_abs = br_int<0 ? -br_int:br_int;
++      
++      switch( (br_int_abs%4) * (br_int<0 ? -1:1) * (ai<0 ? -1:1) ) {
++        case 0:             cos_z=1, sin_z=0; break;
++        case 2: case -2:    cos_z=-1, sin_z=0; break;
++        case 1: case -3:    cos_z=0, sin_z=1; break;
++        case 3: case -1:    cos_z=0, sin_z=-1; break;
++        default:            lua_assert(0); return 0;
++      }
++      return k*cos_z + (k*sin_z)*I;
++    }
++# endif
++    return _LF(cpow) ( a, b );
++  }
++#endif
++
++LUAI_FUNC int luaO_str2d (const char *s, lua_Number *res1, lua_Integer *res2);
++LUAI_FUNC void luaO_num2buf( char *s, const TValue *o );
++
++LUAI_FUNC int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref );
++
++#define luai_normalize(o) \
++{ lua_Integer _i; if (tt_integer_valued(o,&_i)) setivalue(o,_i); }
++
++#endif
+--- /dev/null
++++ b/src/lnum_config.h
+@@ -0,0 +1,221 @@
++/*
++** $Id: lnum_config.h,v ... $
++** Internal Number model
++** See Copyright Notice in lua.h
++*/
++
++#ifndef lnum_config_h
++#define lnum_config_h
++
++/*
++** Default number modes
++*/
++#if (!defined LNUM_DOUBLE) && (!defined LNUM_FLOAT) && (!defined LNUM_LDOUBLE)
++# define LNUM_FLOAT
++#endif
++#if (!defined LNUM_INT16) && (!defined LNUM_INT32) && (!defined LNUM_INT64)
++# define LNUM_INT32
++#endif
++
++/*
++** Require C99 mode for COMPLEX, FLOAT and LDOUBLE (only DOUBLE is ANSI C).
++*/
++#if defined(LNUM_COMPLEX) && (__STDC_VERSION__ < 199901L)
++# error "Need C99 for complex (use '--std=c99' or similar)"
++#elif defined(LNUM_LDOUBLE) && (__STDC_VERSION__ < 199901L) && !defined(_MSC_VER)
++# error "Need C99 for 'long double' (use '--std=c99' or similar)"
++#elif defined(LNUM_FLOAT) && (__STDC_VERSION__ < 199901L)
++/* LNUM_FLOAT not supported on Windows */
++# error "Need C99 for 'float' (use '--std=c99' or similar)"
++#endif
++ 
++/*
++** Number mode identifier to accompany the version string.
++*/
++#ifdef LNUM_COMPLEX
++# define _LNUM1 "complex "
++#else
++# define _LNUM1 ""
++#endif
++#ifdef LNUM_DOUBLE
++# define _LNUM2 "double"
++#elif defined(LNUM_FLOAT)
++# define _LNUM2 "float"
++#elif defined(LNUM_LDOUBLE)
++# define _LNUM2 "ldouble"
++#endif
++#ifdef LNUM_INT32
++# define _LNUM3 "int32"
++#elif defined(LNUM_INT64)
++# define _LNUM3 "int64"
++#elif defined(LNUM_INT16)
++# define _LNUM3 "int16"
++#endif
++#define LUA_LNUM _LNUM1 _LNUM2 " " _LNUM3
++
++/*
++** LUA_NUMBER is the type of floating point number in Lua
++** LUA_NUMBER_SCAN is the format for reading numbers.
++** LUA_NUMBER_FMT is the format for writing numbers.
++*/
++#ifdef LNUM_FLOAT
++# define LUA_NUMBER         float
++# define LUA_NUMBER_SCAN    "%f"
++# define LUA_NUMBER_FMT     "%g"  
++#elif (defined LNUM_DOUBLE)
++# define LUA_NUMBER	        double
++# define LUA_NUMBER_SCAN    "%lf"
++# define LUA_NUMBER_FMT     "%.14g"
++#elif (defined LNUM_LDOUBLE)
++# define LUA_NUMBER         long double
++# define LUA_NUMBER_SCAN    "%Lg"
++# define LUA_NUMBER_FMT     "%.20Lg"
++#endif
++
++
++/* 
++** LUAI_MAXNUMBER2STR: size of a buffer fitting any number->string result.
++**
++**  double:  24 (sign, x.xxxxxxxxxxxxxxe+nnnn, and \0)
++**  int64:   21 (19 digits, sign, and \0)
++**  long double: 43 for 128-bit (sign, x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe+nnnn, and \0)
++**           30 for 80-bit (sign, x.xxxxxxxxxxxxxxxxxxxxe+nnnn, and \0)
++*/
++#ifdef LNUM_LDOUBLE
++# define _LUAI_MN2S 44
++#else
++# define _LUAI_MN2S 24
++#endif
++
++#ifdef LNUM_COMPLEX
++# define LUAI_MAXNUMBER2STR (2*_LUAI_MN2S)
++#else
++# define LUAI_MAXNUMBER2STR _LUAI_MN2S
++#endif
++
++/*
++** LUA_INTEGER is the integer type used by lua_pushinteger/lua_tointeger/lua_isinteger.
++** LUA_INTEGER_SCAN is the format for reading integers
++** LUA_INTEGER_FMT is the format for writing integers
++**
++** Note: Visual C++ 2005 does not have 'strtoull()', use '_strtoui64()' instead.
++*/
++#ifdef LNUM_INT32
++# if LUAI_BITSINT > 16
++#  define LUA_INTEGER   int
++#  define LUA_INTEGER_SCAN "%d"
++#  define LUA_INTEGER_FMT "%d"
++# else
++/* Note: 'LUA_INTEGER' being 'ptrdiff_t' (as in Lua 5.1) causes problems with
++ *       'printf()' operations. Also 'unsigned ptrdiff_t' is invalid.
++ */
++#  define LUA_INTEGER   long
++#  define LUA_INTEGER_SCAN "%ld"
++#  define LUA_INTEGER_FMT "%ld"
++# endif
++# define LUA_INTEGER_MAX 0x7FFFFFFF             /* 2^31-1 */
++/* */
++#elif defined(LNUM_INT64)
++# define LUA_INTEGER	long long
++# ifdef _MSC_VER
++#  define lua_str2ul    _strtoui64
++# else
++#  define lua_str2ul    strtoull
++# endif
++# define LUA_INTEGER_SCAN "%lld"
++# define LUA_INTEGER_FMT "%lld"
++# define LUA_INTEGER_MAX 0x7fffffffffffffffLL       /* 2^63-1 */ 
++# define LUA_INTEGER_MIN (-LUA_INTEGER_MAX - 1LL)   /* -2^63 */
++/* */
++#elif defined(LNUM_INT16)
++# if LUAI_BITSINT > 16
++#  define LUA_INTEGER    short
++#  define LUA_INTEGER_SCAN "%hd"
++#  define LUA_INTEGER_FMT "%hd"
++# else
++#  define LUA_INTEGER    int
++#  define LUA_INTEGER_SCAN "%d"
++#  define LUA_INTEGER_FMT "%d"
++# endif
++# define LUA_INTEGER_MAX 0x7FFF             /* 2^16-1 */
++#endif
++
++#ifndef lua_str2ul
++# define lua_str2ul (unsigned LUA_INTEGER)strtoul
++#endif
++#ifndef LUA_INTEGER_MIN
++# define LUA_INTEGER_MIN (-LUA_INTEGER_MAX -1)  /* -2^16|32 */
++#endif
++
++/*
++@@ lua_number2int is a macro to convert lua_Number to int.
++@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
++** CHANGE them if you know a faster way to convert a lua_Number to
++** int (with any rounding method and without throwing errors) in your
++** system. In Pentium machines, a naive typecast from double to int
++** in C is extremely slow, so any alternative is worth trying.
++*/
++
++/* On a Pentium, resort to a trick */
++#if defined(LNUM_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
++    (defined(__i386) || defined (_M_IX86) || defined(__i386__))
++
++/* On a Microsoft compiler, use assembler */
++# if defined(_MSC_VER)
++#  define lua_number2int(i,d)   __asm fld d   __asm fistp i
++# else
++
++/* the next trick should work on any Pentium, but sometimes clashes
++   with a DirectX idiosyncrasy */
++union luai_Cast { double l_d; long l_l; };
++#  define lua_number2int(i,d) \
++  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
++# endif
++
++# ifndef LNUM_INT64
++#  define lua_number2integer    lua_number2int
++# endif
++
++/* this option always works, but may be slow */
++#else
++# define lua_number2int(i,d)        ((i)=(int)(d))
++#endif
++
++/* Note: Some compilers (OS X gcc 4.0?) may choke on double->long long conversion 
++ *       since it can lose precision. Others do require 'long long' there.  
++ */
++#ifndef lua_number2integer
++# define lua_number2integer(i,d)    ((i)=(lua_Integer)(d))
++#endif
++
++/*
++** 'luai_abs()' to give absolute value of 'lua_Integer'
++*/
++#ifdef LNUM_INT32
++# define luai_abs abs
++#elif defined(LNUM_INT64) && (__STDC_VERSION__ >= 199901L)
++# define luai_abs llabs
++#else
++# define luai_abs(v) ((v) >= 0 ? (v) : -(v))
++#endif
++
++/*
++** LUAI_UACNUMBER is the result of an 'usual argument conversion' over a number.
++** LUAI_UACINTEGER the same, over an integer.
++*/
++#define LUAI_UACNUMBER	double
++#define LUAI_UACINTEGER long
++
++/* ANSI C only has math funcs for 'double. C99 required for float and long double
++ * variants.
++ */
++#ifdef LNUM_DOUBLE
++# define _LF(name) name
++#elif defined(LNUM_FLOAT)
++# define _LF(name) name ## f
++#elif defined(LNUM_LDOUBLE)
++# define _LF(name) name ## l
++#endif
++
++#endif
++
+--- a/src/lobject.c
++++ b/src/lobject.c
+@@ -21,7 +21,8 @@
+ #include "lstate.h"
+ #include "lstring.h"
+ #include "lvm.h"
+-
++#include "llex.h"
++#include "lnum.h"
+ 
+ 
+ const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL};
+@@ -70,12 +71,31 @@ int luaO_log2 (unsigned int x) {
+ 
+ 
+ int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
+-  if (ttype(t1) != ttype(t2)) return 0;
++  if (!ttype_ext_same(t1,t2)) return 0;
+   else switch (ttype(t1)) {
+     case LUA_TNIL:
+       return 1;
++    case LUA_TINT:
++      if (ttype(t2)==LUA_TINT)
++        return ivalue(t1) == ivalue(t2);
++      else {  /* t1:int, t2:num */
++#ifdef LNUM_COMPLEX
++        if (nvalue_img_fast(t2) != 0) return 0;
++#endif
++        /* Avoid doing accuracy losing cast, if possible. */
++        lua_Integer tmp;
++        if (tt_integer_valued(t2,&tmp)) 
++          return ivalue(t1) == tmp;
++        else
++          return luai_numeq( cast_num(ivalue(t1)), nvalue_fast(t2) );
++        }
+     case LUA_TNUMBER:
+-      return luai_numeq(nvalue(t1), nvalue(t2));
++        if (ttype(t2)==LUA_TINT)
++          return luaO_rawequalObj(t2, t1);  /* swap LUA_TINT to left */
++#ifdef LNUM_COMPLEX
++        if (!luai_numeq(nvalue_img_fast(t1), nvalue_img_fast(t2))) return 0;
++#endif
++        return luai_numeq(nvalue_fast(t1), nvalue_fast(t2));
+     case LUA_TBOOLEAN:
+       return bvalue(t1) == bvalue(t2);  /* boolean true must be 1 !! */
+     case LUA_TLIGHTUSERDATA:
+@@ -86,21 +106,6 @@ int luaO_rawequalObj (const TValue *t1, 
+   }
+ }
+ 
+-
+-int luaO_str2d (const char *s, lua_Number *result) {
+-  char *endptr;
+-  *result = lua_str2number(s, &endptr);
+-  if (endptr == s) return 0;  /* conversion failed */
+-  if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */
+-    *result = cast_num(strtoul(s, &endptr, 16));
+-  if (*endptr == '\0') return 1;  /* most common case */
+-  while (isspace(cast(unsigned char, *endptr))) endptr++;
+-  if (*endptr != '\0') return 0;  /* invalid trailing characters? */
+-  return 1;
+-}
+-
+-
+-
+ static void pushstr (lua_State *L, const char *str) {
+   setsvalue2s(L, L->top, luaS_new(L, str));
+   incr_top(L);
+@@ -131,7 +136,11 @@ const char *luaO_pushvfstring (lua_State
+         break;
+       }
+       case 'd': {
+-        setnvalue(L->top, cast_num(va_arg(argp, int)));
++        /* This is tricky for 64-bit integers; maybe they even cannot be
++         * supported on all compilers; depends on the conversions applied to
++         * variable argument lists. TBD: test!
++         */
++        setivalue(L->top, (lua_Integer) va_arg(argp, l_uacInteger));
+         incr_top(L);
+         break;
+       }
+@@ -212,3 +221,4 @@ void luaO_chunkid (char *out, const char
+     }
+   }
+ }
++
+--- a/src/lobject.h
++++ b/src/lobject.h
+@@ -17,7 +17,11 @@
+ 
+ 
+ /* tags for values visible from Lua */
+-#define LAST_TAG	LUA_TTHREAD
++#if LUA_TINT > LUA_TTHREAD
++# define LAST_TAG   LUA_TINT
++#else
++# define LAST_TAG	LUA_TTHREAD
++#endif
+ 
+ #define NUM_TAGS	(LAST_TAG+1)
+ 
+@@ -59,7 +63,12 @@ typedef struct GCheader {
+ typedef union {
+   GCObject *gc;
+   void *p;
++#ifdef LNUM_COMPLEX
++  lua_Complex n;
++#else
+   lua_Number n;
++#endif
++  lua_Integer i;
+   int b;
+ } Value;
+ 
+@@ -77,7 +86,11 @@ typedef struct lua_TValue {
+ 
+ /* Macros to test type */
+ #define ttisnil(o)	(ttype(o) == LUA_TNIL)
+-#define ttisnumber(o)	(ttype(o) == LUA_TNUMBER)
++#define ttisint(o) (ttype(o) == LUA_TINT)
++#define ttisnumber(o) ((ttype(o) == LUA_TINT) || (ttype(o) == LUA_TNUMBER))
++#ifdef LNUM_COMPLEX
++# define ttiscomplex(o) ((ttype(o) == LUA_TNUMBER) && (nvalue_img_fast(o)!=0))
++#endif
+ #define ttisstring(o)	(ttype(o) == LUA_TSTRING)
+ #define ttistable(o)	(ttype(o) == LUA_TTABLE)
+ #define ttisfunction(o)	(ttype(o) == LUA_TFUNCTION)
+@@ -90,7 +103,25 @@ typedef struct lua_TValue {
+ #define ttype(o)	((o)->tt)
+ #define gcvalue(o)	check_exp(iscollectable(o), (o)->value.gc)
+ #define pvalue(o)	check_exp(ttislightuserdata(o), (o)->value.p)
+-#define nvalue(o)	check_exp(ttisnumber(o), (o)->value.n)
++
++#define ttype_ext(o) ( ttype(o) == LUA_TINT ? LUA_TNUMBER : ttype(o) )
++#define ttype_ext_same(o1,o2) ( (ttype(o1)==ttype(o2)) || (ttisnumber(o1) && ttisnumber(o2)) )
++
++/* '_fast' variants are for cases where 'ttype(o)' is known to be LUA_TNUMBER.
++ */
++#ifdef LNUM_COMPLEX
++#  define nvalue_complex_fast(o) check_exp( ttype(o)==LUA_TNUMBER, (o)->value.n )   
++#  define nvalue_fast(o)     ( _LF(creal) ( nvalue_complex_fast(o) ) )
++#  define nvalue_img_fast(o) ( _LF(cimag) ( nvalue_complex_fast(o) ) )
++#  define nvalue_complex(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? (o)->value.i : (o)->value.n )
++#  define nvalue_img(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? 0 : _LF(cimag)( (o)->value.n ) ) 
++#  define nvalue(o) check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? cast_num((o)->value.i) : _LF(creal)((o)->value.n) ) 
++#else
++# define nvalue(o)	check_exp( ttisnumber(o), (ttype(o)==LUA_TINT) ? cast_num((o)->value.i) : (o)->value.n )
++# define nvalue_fast(o) check_exp( ttype(o)==LUA_TNUMBER, (o)->value.n )   
++#endif
++#define ivalue(o)	check_exp( ttype(o)==LUA_TINT, (o)->value.i )
++
+ #define rawtsvalue(o)	check_exp(ttisstring(o), &(o)->value.gc->ts)
+ #define tsvalue(o)	(&rawtsvalue(o)->tsv)
+ #define rawuvalue(o)	check_exp(ttisuserdata(o), &(o)->value.gc->u)
+@@ -116,8 +147,27 @@ typedef struct lua_TValue {
+ /* Macros to set values */
+ #define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
+ 
+-#define setnvalue(obj,x) \
+-  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
++/* Must not have side effects, 'x' may be expression.
++*/
++#define setivalue(obj,x) \
++    { TValue *i_o=(obj); i_o->value.i=(x); i_o->tt=LUA_TINT; }
++
++# define setnvalue(obj,x) \
++    { TValue *i_o=(obj); i_o->value.n= (x); i_o->tt=LUA_TNUMBER; }
++
++/* Note: Complex always has "inline", both are C99.
++*/
++#ifdef LNUM_COMPLEX
++  static inline void setnvalue_complex_fast( TValue *obj, lua_Complex x ) {
++    lua_assert( _LF(cimag)(x) != 0 );
++    obj->value.n= x; obj->tt= LUA_TNUMBER;
++  }
++  static inline void setnvalue_complex( TValue *obj, lua_Complex x ) {
++    if (_LF(cimag)(x) == 0) { setnvalue(obj, _LF(creal)(x)); }
++    else { obj->value.n= x; obj->tt= LUA_TNUMBER; }
++  }
++#endif
++
+ 
+ #define setpvalue(obj,x) \
+   { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
+@@ -155,9 +205,6 @@ typedef struct lua_TValue {
+     i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
+     checkliveness(G(L),i_o); }
+ 
+-
+-
+-
+ #define setobj(L,obj1,obj2) \
+   { const TValue *o2=(obj2); TValue *o1=(obj1); \
+     o1->value = o2->value; o1->tt=o2->tt; \
+@@ -185,8 +232,11 @@ typedef struct lua_TValue {
+ 
+ #define setttype(obj, tt) (ttype(obj) = (tt))
+ 
+-
+-#define iscollectable(o)	(ttype(o) >= LUA_TSTRING)
++#if LUA_TINT >= LUA_TSTRING
++# define iscollectable(o)	((ttype(o) >= LUA_TSTRING) && (ttype(o) != LUA_TINT))
++#else
++# define iscollectable(o)	(ttype(o) >= LUA_TSTRING)
++#endif
+ 
+ 
+ 
+@@ -370,12 +420,10 @@ LUAI_FUNC int luaO_log2 (unsigned int x)
+ LUAI_FUNC int luaO_int2fb (unsigned int x);
+ LUAI_FUNC int luaO_fb2int (int x);
+ LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
+-LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
+ LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
+                                                        va_list argp);
+ LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
+ LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
+ 
+-
+ #endif
+ 
+--- a/src/loslib.c
++++ b/src/loslib.c
+@@ -186,15 +186,30 @@ static int os_time (lua_State *L) {
+   }
+   if (t == (time_t)(-1))
+     lua_pushnil(L);
+-  else
+-    lua_pushnumber(L, (lua_Number)t);
++  else {
++     /* On float systems the pushed value must be an integer, NOT a number.
++      * Otherwise, accuracy is lost in the time_t->float conversion.
++      */
++#ifdef LNUM_FLOAT
++     lua_pushinteger(L, (lua_Integer) t);
++#else
++     lua_pushnumber(L, (lua_Number) t);
++#endif
++     }
+   return 1;
+ }
+ 
+ 
+ static int os_difftime (lua_State *L) {
++#ifdef LNUM_FLOAT
++  lua_Integer i= (lua_Integer)
++    difftime( (time_t)(luaL_checkinteger(L, 1)),
++              (time_t)(luaL_optinteger(L, 2, 0)));
++  lua_pushinteger(L, i);
++#else
+   lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
+                              (time_t)(luaL_optnumber(L, 2, 0))));
++#endif
+   return 1;
+ }
+ 
+--- a/src/lparser.c
++++ b/src/lparser.c
+@@ -33,7 +33,6 @@
+ 
+ #define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) errorlimit(fs,l,m)
+ 
+-
+ /*
+ ** nodes for block list (list of active blocks)
+ */
+@@ -72,7 +71,7 @@ static void errorlimit (FuncState *fs, i
+   const char *msg = (fs->f->linedefined == 0) ?
+     luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
+     luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
+-                            fs->f->linedefined, limit, what);
++                            (fs->f->linedefined), limit, what);
+   luaX_lexerror(fs->ls, msg, 0);
+ }
+ 
+@@ -733,6 +732,18 @@ static void simpleexp (LexState *ls, exp
+       v->u.nval = ls->t.seminfo.r;
+       break;
+     }
++    case TK_INT: {
++      init_exp(v, VKINT, 0);
++      v->u.ival = ls->t.seminfo.i;
++      break;
++    }
++#ifdef LNUM_COMPLEX
++    case TK_NUMBER2: {
++      init_exp(v, VKNUM2, 0);
++      v->u.nval = ls->t.seminfo.r;
++      break;
++    }
++#endif
+     case TK_STRING: {
+       codestring(ls, v, ls->t.seminfo.ts);
+       break;
+@@ -1079,7 +1090,7 @@ static void fornum (LexState *ls, TStrin
+   if (testnext(ls, ','))
+     exp1(ls);  /* optional step */
+   else {  /* default step = 1 */
+-    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
++    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_integerK(fs, 1));
+     luaK_reserveregs(fs, 1);
+   }
+   forbody(ls, base, line, 1, 1);
+--- a/src/lparser.h
++++ b/src/lparser.h
+@@ -31,7 +31,11 @@ typedef enum {
+   VRELOCABLE,	/* info = instruction pc */
+   VNONRELOC,	/* info = result register */
+   VCALL,	/* info = instruction pc */
+-  VVARARG	/* info = instruction pc */
++  VVARARG,	/* info = instruction pc */
++  VKINT     /* ival = integer value */
++#ifdef LNUM_COMPLEX
++  ,VKNUM2   /* nval = imaginary value */
++#endif
+ } expkind;
+ 
+ typedef struct expdesc {
+@@ -39,6 +43,7 @@ typedef struct expdesc {
+   union {
+     struct { int info, aux; } s;
+     lua_Number nval;
++    lua_Integer ival;
+   } u;
+   int t;  /* patch list of `exit when true' */
+   int f;  /* patch list of `exit when false' */
+--- a/src/lstrlib.c
++++ b/src/lstrlib.c
+@@ -43,8 +43,8 @@ static ptrdiff_t posrelat (ptrdiff_t pos
+ static int str_sub (lua_State *L) {
+   size_t l;
+   const char *s = luaL_checklstring(L, 1, &l);
+-  ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
+-  ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
++  ptrdiff_t start = posrelat(luaL_checkint32(L, 2), l);
++  ptrdiff_t end = posrelat(luaL_optint32(L, 3, -1), l);
+   if (start < 1) start = 1;
+   if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
+   if (start <= end)
+@@ -106,8 +106,8 @@ static int str_rep (lua_State *L) {
+ static int str_byte (lua_State *L) {
+   size_t l;
+   const char *s = luaL_checklstring(L, 1, &l);
+-  ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
+-  ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
++  ptrdiff_t posi = posrelat(luaL_optint32(L, 2, 1), l);
++  ptrdiff_t pose = posrelat(luaL_optint32(L, 3, posi), l);
+   int n, i;
+   if (posi <= 0) posi = 1;
+   if ((size_t)pose > l) pose = l;
+@@ -496,7 +496,7 @@ static int str_find_aux (lua_State *L, i
+   size_t l1, l2;
+   const char *s = luaL_checklstring(L, 1, &l1);
+   const char *p = luaL_checklstring(L, 2, &l2);
+-  ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
++  ptrdiff_t init = posrelat(luaL_optint32(L, 3, 1), l1) - 1;
+   if (init < 0) init = 0;
+   else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
+   if (find && (lua_toboolean(L, 4) ||  /* explicit request? */
+@@ -690,7 +690,7 @@ static int str_gsub (lua_State *L) {
+ ** maximum size of each format specification (such as '%-099.99d')
+ ** (+10 accounts for %99.99x plus margin of error)
+ */
+-#define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
++#define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTEGER_FMT)-2 + 10)
+ 
+ 
+ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+@@ -747,9 +747,9 @@ static const char *scanformat (lua_State
+ static void addintlen (char *form) {
+   size_t l = strlen(form);
+   char spec = form[l - 1];
+-  strcpy(form + l - 1, LUA_INTFRMLEN);
+-  form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
+-  form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
++  const char *tmp= LUA_INTEGER_FMT;   /* "%lld" or "%ld" */
++  strcpy(form + l - 1, tmp+1);
++  form[l + sizeof(LUA_INTEGER_FMT)-4] = spec;
+ }
+ 
+ 
+@@ -779,12 +779,12 @@ static int str_format (lua_State *L) {
+         }
+         case 'd':  case 'i': {
+           addintlen(form);
+-          sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
++          sprintf(buff, form, luaL_checkinteger(L, arg));
+           break;
+         }
+         case 'o':  case 'u':  case 'x':  case 'X': {
+           addintlen(form);
+-          sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
++          sprintf(buff, form, (unsigned LUA_INTEGER)luaL_checkinteger(L, arg));
+           break;
+         }
+         case 'e':  case 'E': case 'f':
+--- a/src/ltable.c
++++ b/src/ltable.c
+@@ -33,6 +33,7 @@
+ #include "lobject.h"
+ #include "lstate.h"
+ #include "ltable.h"
++#include "lnum.h"
+ 
+ 
+ /*
+@@ -51,25 +52,15 @@
+   
+ #define hashstr(t,str)  hashpow2(t, (str)->tsv.hash)
+ #define hashboolean(t,p)        hashpow2(t, p)
+-
++#define hashint(t,i)    hashpow2(t,i)
+ 
+ /*
+ ** for some types, it is better to avoid modulus by power of 2, as
+ ** they tend to have many 2 factors.
+ */
+ #define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))
+-
+-
+ #define hashpointer(t,p)	hashmod(t, IntPoint(p))
+ 
+-
+-/*
+-** number of ints inside a lua_Number
+-*/
+-#define numints		cast_int(sizeof(lua_Number)/sizeof(int))
+-
+-
+-
+ #define dummynode		(&dummynode_)
+ 
+ static const Node dummynode_ = {
+@@ -80,27 +71,46 @@ static const Node dummynode_ = {
+ 
+ /*
+ ** hash for lua_Numbers
++**
++** for non-complex modes, never called with 'lua_Integer' value range (s.a. 0)
+ */
+ static Node *hashnum (const Table *t, lua_Number n) {
+-  unsigned int a[numints];
+-  int i;
+-  if (luai_numeq(n, 0))  /* avoid problems with -0 */
+-    return gnode(t, 0);
+-  memcpy(a, &n, sizeof(a));
+-  for (i = 1; i < numints; i++) a[0] += a[i];
+-  return hashmod(t, a[0]);
++  const unsigned int *p= cast(const unsigned int *,&n);
++  unsigned int sum= *p;
++  unsigned int m= sizeof(lua_Number)/sizeof(int);
++  unsigned int i;
++  /* OS X Intel has 'm'==4 and gives "Bus error" if the last integer of 
++   * 'n' is read; the actual size of long double is only 80 bits = 10 bytes.
++   * Linux x86 has 'm'==3, and does not require reduction.
++   */
++#if defined(LNUM_LDOUBLE) && defined(__i386__)
++  if (m>3) m--;
++#endif
++  for (i = 1; i < m; i++) sum += p[i];
++  return hashmod(t, sum);
+ }
+ 
+ 
+-
+ /*
+ ** returns the `main' position of an element in a table (that is, the index
+ ** of its hash value)
++**
++** Floating point numbers with integer value give the hash position of the
++** integer (so they use the same table position).
+ */
+ static Node *mainposition (const Table *t, const TValue *key) {
++  lua_Integer i;
+   switch (ttype(key)) {
+     case LUA_TNUMBER:
+-      return hashnum(t, nvalue(key));
++      if (tt_integer_valued(key,&i)) 
++        return hashint(t, i);
++#ifdef LNUM_COMPLEX
++      if (nvalue_img_fast(key)!=0 && luai_numeq(nvalue_fast(key),0))
++        return gnode(t, 0);  /* 0 and -0 to give same hash */
++#endif
++      return hashnum(t, nvalue_fast(key));
++    case LUA_TINT:
++      return hashint(t, ivalue(key));
+     case LUA_TSTRING:
+       return hashstr(t, rawtsvalue(key));
+     case LUA_TBOOLEAN:
+@@ -116,16 +126,20 @@ static Node *mainposition (const Table *
+ /*
+ ** returns the index for `key' if `key' is an appropriate key to live in
+ ** the array part of the table, -1 otherwise.
++**
++** Anything <=0 is taken as not being in the array part.
+ */
+-static int arrayindex (const TValue *key) {
+-  if (ttisnumber(key)) {
+-    lua_Number n = nvalue(key);
+-    int k;
+-    lua_number2int(k, n);
+-    if (luai_numeq(cast_num(k), n))
+-      return k;
++static int arrayindex (const TValue *key, int max) {
++  lua_Integer k;
++  switch( ttype(key) ) {
++    case LUA_TINT:
++      k= ivalue(key); break;
++    case LUA_TNUMBER:
++      if (tt_integer_valued(key,&k)) break;
++    default:
++      return -1;  /* not to be used as array index */
+   }
+-  return -1;  /* `key' did not match some condition */
++  return ((k>0) && (k <= max)) ? cast_int(k) : -1;
+ }
+ 
+ 
+@@ -137,8 +151,8 @@ static int arrayindex (const TValue *key
+ static int findindex (lua_State *L, Table *t, StkId key) {
+   int i;
+   if (ttisnil(key)) return -1;  /* first iteration */
+-  i = arrayindex(key);
+-  if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */
++  i = arrayindex(key, t->sizearray);
++  if (i>0)  /* inside array part? */
+     return i-1;  /* yes; that's the index (corrected to C) */
+   else {
+     Node *n = mainposition(t, key);
+@@ -163,7 +177,7 @@ int luaH_next (lua_State *L, Table *t, S
+   int i = findindex(L, t, key);  /* find original element */
+   for (i++; i < t->sizearray; i++) {  /* try first array part */
+     if (!ttisnil(&t->array[i])) {  /* a non-nil value? */
+-      setnvalue(key, cast_num(i+1));
++      setivalue(key, i+1);
+       setobj2s(L, key+1, &t->array[i]);
+       return 1;
+     }
+@@ -209,8 +223,8 @@ static int computesizes (int nums[], int
+ 
+ 
+ static int countint (const TValue *key, int *nums) {
+-  int k = arrayindex(key);
+-  if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */
++  int k = arrayindex(key,MAXASIZE);
++  if (k>0) {  /* appropriate array index? */
+     nums[ceillog2(k)]++;  /* count as such */
+     return 1;
+   }
+@@ -308,7 +322,7 @@ static void resize (lua_State *L, Table 
+     /* re-insert elements from vanishing slice */
+     for (i=nasize; i<oldasize; i++) {
+       if (!ttisnil(&t->array[i]))
+-        setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
++        setobjt2t(L, luaH_setint(L, t, i+1), &t->array[i]);
+     }
+     /* shrink array */
+     luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
+@@ -409,7 +423,9 @@ static TValue *newkey (lua_State *L, Tab
+     othern = mainposition(t, key2tval(mp));
+     if (othern != mp) {  /* is colliding node out of its main position? */
+       /* yes; move colliding node into free position */
+-      while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */
++      while (gnext(othern) != mp) {
++        othern = gnext(othern);  /* find previous */
++      }
+       gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
+       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
+       gnext(mp) = NULL;  /* now `mp' is free */
+@@ -432,17 +448,18 @@ static TValue *newkey (lua_State *L, Tab
+ /*
+ ** search function for integers
+ */
+-const TValue *luaH_getnum (Table *t, int key) {
++const TValue *luaH_getint (Table *t, lua_Integer key) {
+   /* (1 <= key && key <= t->sizearray) */
+   if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
+     return &t->array[key-1];
+   else {
+-    lua_Number nk = cast_num(key);
+-    Node *n = hashnum(t, nk);
++    Node *n = hashint(t, key);
+     do {  /* check whether `key' is somewhere in the chain */
+-      if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
++      if (ttisint(gkey(n)) && (ivalue(gkey(n)) == key)) {
+         return gval(n);  /* that's it */
+-      else n = gnext(n);
++      } else { 
++      n = gnext(n);
++    }
+     } while (n);
+     return luaO_nilobject;
+   }
+@@ -470,14 +487,12 @@ const TValue *luaH_get (Table *t, const 
+   switch (ttype(key)) {
+     case LUA_TNIL: return luaO_nilobject;
+     case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
++    case LUA_TINT: return luaH_getint(t, ivalue(key));
+     case LUA_TNUMBER: {
+-      int k;
+-      lua_Number n = nvalue(key);
+-      lua_number2int(k, n);
+-      if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
+-        return luaH_getnum(t, k);  /* use specialized version */
+-      /* else go through */
+-    }
++      lua_Integer i;
++      if (tt_integer_valued(key,&i))
++        return luaH_getint(t,i);
++    } /* pass through */
+     default: {
+       Node *n = mainposition(t, key);
+       do {  /* check whether `key' is somewhere in the chain */
+@@ -498,20 +513,25 @@ TValue *luaH_set (lua_State *L, Table *t
+     return cast(TValue *, p);
+   else {
+     if (ttisnil(key)) luaG_runerror(L, "table index is nil");
+-    else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
+-      luaG_runerror(L, "table index is NaN");
++    else if (ttype(key)==LUA_TNUMBER) {
++      lua_Integer k;
++      if (luai_numisnan(nvalue_fast(key)))
++        luaG_runerror(L, "table index is NaN");
++      if (tt_integer_valued(key,&k))
++        return luaH_setint(L, t, k);
++    }
+     return newkey(L, t, key);
+   }
+ }
+ 
+ 
+-TValue *luaH_setnum (lua_State *L, Table *t, int key) {
+-  const TValue *p = luaH_getnum(t, key);
++TValue *luaH_setint (lua_State *L, Table *t, lua_Integer key) {
++  const TValue *p = luaH_getint(t, key);
+   if (p != luaO_nilobject)
+     return cast(TValue *, p);
+   else {
+     TValue k;
+-    setnvalue(&k, cast_num(key));
++    setivalue(&k, key);
+     return newkey(L, t, &k);
+   }
+ }
+@@ -533,20 +553,21 @@ static int unbound_search (Table *t, uns
+   unsigned int i = j;  /* i is zero or a present index */
+   j++;
+   /* find `i' and `j' such that i is present and j is not */
+-  while (!ttisnil(luaH_getnum(t, j))) {
++  while (!ttisnil(luaH_getint(t, j))) {
+     i = j;
+     j *= 2;
+     if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */
+       /* table was built with bad purposes: resort to linear search */
+-      i = 1;
+-      while (!ttisnil(luaH_getnum(t, i))) i++;
+-      return i - 1;
++      for( i = 1; i<MAX_INT+1; i++ ) {
++        if (ttisnil(luaH_getint(t, i))) break;
++      }
++      return i - 1;  /* up to MAX_INT */
+     }
+   }
+   /* now do a binary search between them */
+   while (j - i > 1) {
+     unsigned int m = (i+j)/2;
+-    if (ttisnil(luaH_getnum(t, m))) j = m;
++    if (ttisnil(luaH_getint(t, m))) j = m;
+     else i = m;
+   }
+   return i;
+--- a/src/ltable.h
++++ b/src/ltable.h
+@@ -18,8 +18,8 @@
+ #define key2tval(n)	(&(n)->i_key.tvk)
+ 
+ 
+-LUAI_FUNC const TValue *luaH_getnum (Table *t, int key);
+-LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
++LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
++LUAI_FUNC TValue *luaH_setint (lua_State *L, Table *t, lua_Integer key);
+ LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
+ LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
+ LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
+--- a/src/ltm.c
++++ b/src/ltm.c
+@@ -19,7 +19,6 @@
+ #include "ltm.h"
+ 
+ 
+-
+ const char *const luaT_typenames[] = {
+   "nil", "boolean", "userdata", "number",
+   "string", "table", "function", "userdata", "thread",
+@@ -67,6 +66,9 @@ const TValue *luaT_gettmbyobj (lua_State
+     case LUA_TUSERDATA:
+       mt = uvalue(o)->metatable;
+       break;
++    case LUA_TINT:
++      mt = G(L)->mt[LUA_TNUMBER];
++      break;
+     default:
+       mt = G(L)->mt[ttype(o)];
+   }
+--- a/src/lua.c
++++ b/src/lua.c
+@@ -16,7 +16,7 @@
+ 
+ #include "lauxlib.h"
+ #include "lualib.h"
+-
++#include "llimits.h"
+ 
+ 
+ static lua_State *globalL = NULL;
+@@ -382,6 +382,15 @@ int main (int argc, char **argv) {
+     l_message(argv[0], "cannot create state: not enough memory");
+     return EXIT_FAILURE;
+   }
++  /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
++  */
++#ifdef LNUM_INT16
++  lua_assert( sizeof(lua_Integer) == 2 );
++#elif defined(LNUM_INT32)
++  lua_assert( sizeof(lua_Integer) == 4 );
++#elif defined(LNUM_INT64)
++  lua_assert( sizeof(lua_Integer) == 8 );
++#endif
+   s.argc = argc;
+   s.argv = argv;
+   status = lua_cpcall(L, &pmain, &s);
+--- a/src/lua.h
++++ b/src/lua.h
+@@ -19,7 +19,7 @@
+ #define LUA_VERSION	"Lua 5.1"
+ #define LUA_RELEASE	"Lua 5.1.5"
+ #define LUA_VERSION_NUM	501
+-#define LUA_COPYRIGHT	"Copyright (C) 1994-2012 Lua.org, PUC-Rio"
++#define LUA_COPYRIGHT	"Copyright (C) 1994-2012 Lua.org, PUC-Rio" " (" LUA_LNUM ")"
+ #define LUA_AUTHORS 	"R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
+ 
+ 
+@@ -71,6 +71,16 @@ typedef void * (*lua_Alloc) (void *ud, v
+ */
+ #define LUA_TNONE		(-1)
+ 
++/* LUA_TINT is an internal type, not visible to applications. There are three
++ * potential values where it can be tweaked to (code autoadjusts to these):
++ *
++ * -2: not 'usual' type value; good since 'LUA_TINT' is not part of the API
++ * LUA_TNUMBER+1: shifts other type values upwards, breaking binary compatibility
++ *     not acceptable for 5.1, maybe 5.2 onwards?
++ *  9: greater than existing (5.1) type values.
++*/
++#define LUA_TINT (-2)
++
+ #define LUA_TNIL		0
+ #define LUA_TBOOLEAN		1
+ #define LUA_TLIGHTUSERDATA	2
+@@ -139,6 +149,8 @@ LUA_API int             (lua_isuserdata)
+ LUA_API int             (lua_type) (lua_State *L, int idx);
+ LUA_API const char     *(lua_typename) (lua_State *L, int tp);
+ 
++LUA_API int             (lua_isinteger) (lua_State *L, int idx);
++
+ LUA_API int            (lua_equal) (lua_State *L, int idx1, int idx2);
+ LUA_API int            (lua_rawequal) (lua_State *L, int idx1, int idx2);
+ LUA_API int            (lua_lessthan) (lua_State *L, int idx1, int idx2);
+@@ -244,6 +256,19 @@ LUA_API lua_Alloc (lua_getallocf) (lua_S
+ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+ 
+ 
++/*
++* It is unnecessary to break Lua C API 'lua_tonumber()' compatibility, just
++* because the Lua number type is complex. Most C modules would use scalars
++* only. We'll introduce new 'lua_tocomplex' and 'lua_pushcomplex' for when
++* the module really wants to use them.
++*/
++#ifdef LNUM_COMPLEX
++  #include <complex.h>
++  typedef LUA_NUMBER complex lua_Complex;
++  LUA_API lua_Complex (lua_tocomplex) (lua_State *L, int idx);
++  LUA_API void (lua_pushcomplex) (lua_State *L, lua_Complex v);
++#endif
++
+ 
+ /* 
+ ** ===============================================================
+@@ -268,7 +293,12 @@ LUA_API void lua_setallocf (lua_State *L
+ #define lua_isboolean(L,n)	(lua_type(L, (n)) == LUA_TBOOLEAN)
+ #define lua_isthread(L,n)	(lua_type(L, (n)) == LUA_TTHREAD)
+ #define lua_isnone(L,n)		(lua_type(L, (n)) == LUA_TNONE)
+-#define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0)
++
++#if LUA_TINT < 0
++# define lua_isnoneornil(L, n)	( (lua_type(L,(n)) <= 0) && (lua_type(L,(n)) != LUA_TINT) )
++#else
++# define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0)
++#endif
+ 
+ #define lua_pushliteral(L, s)	\
+ 	lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
+@@ -386,3 +416,4 @@ struct lua_Debug {
+ 
+ 
+ #endif
++
+--- a/src/luaconf.h
++++ b/src/luaconf.h
+@@ -10,7 +10,9 @@
+ 
+ #include <limits.h>
+ #include <stddef.h>
+-
++#ifdef lua_assert
++# include <assert.h>
++#endif
+ 
+ /*
+ ** ==================================================================
+@@ -136,14 +138,38 @@
+ 
+ 
+ /*
+-@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
+-** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
+-** machines, ptrdiff_t gives a good choice between int or long.)
++@@ LUAI_BITSINT defines the number of bits in an int.
++** CHANGE here if Lua cannot automatically detect the number of bits of
++** your machine. Probably you do not need to change this.
+ */
+-#define LUA_INTEGER	ptrdiff_t
++/* avoid overflows in comparison */
++#if INT_MAX-20 < 32760
++#define LUAI_BITSINT	16
++#elif INT_MAX > 2147483640L
++/* int has at least 32 bits */
++#define LUAI_BITSINT	32
++#else
++#error "you must define LUA_BITSINT with number of bits in an integer"
++#endif
+ 
+ 
+ /*
++@@ LNUM_DOUBLE | LNUM_FLOAT | LNUM_LDOUBLE: Generic Lua number mode
++@@ LNUM_INT32 | LNUM_INT64: Integer type
++@@ LNUM_COMPLEX: Define for using 'a+bi' numbers
++@@
++@@ You can combine LNUM_xxx but only one of each group. I.e. '-DLNUM_FLOAT
++@@ -DLNUM_INT32 -DLNUM_COMPLEX' gives float range complex numbers, with 
++@@ 32-bit scalar integer range optimized.
++**
++** These are kept in a separate configuration file mainly for ease of patching
++** (can be changed if integerated to Lua proper).
++*/
++/*#define LNUM_DOUBLE*/
++/*#define LNUM_INT32*/
++#include "lnum_config.h"
++
++/*
+ @@ LUA_API is a mark for all core API functions.
+ @@ LUALIB_API is a mark for all standard library functions.
+ ** CHANGE them if you need to define those functions in some special way.
+@@ -383,22 +409,6 @@
+ 
+ 
+ /*
+-@@ LUAI_BITSINT defines the number of bits in an int.
+-** CHANGE here if Lua cannot automatically detect the number of bits of
+-** your machine. Probably you do not need to change this.
+-*/
+-/* avoid overflows in comparison */
+-#if INT_MAX-20 < 32760
+-#define LUAI_BITSINT	16
+-#elif INT_MAX > 2147483640L
+-/* int has at least 32 bits */
+-#define LUAI_BITSINT	32
+-#else
+-#error "you must define LUA_BITSINT with number of bits in an integer"
+-#endif
+-
+-
+-/*
+ @@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
+ @@ LUAI_INT32 is an signed integer with at least 32 bits.
+ @@ LUAI_UMEM is an unsigned integer big enough to count the total
+@@ -425,6 +435,15 @@
+ #define LUAI_MEM	long
+ #endif
+ 
++/*
++@@ LUAI_BOOL carries 0 and nonzero (normally 1). It may be defined as 'char'
++** (to save memory), 'int' (for speed), 'bool' (for C++) or '_Bool' (C99)
++*/
++#ifdef __cplusplus
++# define LUAI_BOOL bool
++#else
++# define LUAI_BOOL int
++#endif
+ 
+ /*
+ @@ LUAI_MAXCALLS limits the number of nested calls.
+@@ -490,101 +509,6 @@
+ /* }================================================================== */
+ 
+ 
+-
+-
+-/*
+-** {==================================================================
+-@@ LUA_NUMBER is the type of numbers in Lua.
+-** CHANGE the following definitions only if you want to build Lua
+-** with a number type different from double. You may also need to
+-** change lua_number2int & lua_number2integer.
+-** ===================================================================
+-*/
+-
+-#define LUA_NUMBER_DOUBLE
+-#define LUA_NUMBER	double
+-
+-/*
+-@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+-@* over a number.
+-*/
+-#define LUAI_UACNUMBER	double
+-
+-
+-/*
+-@@ LUA_NUMBER_SCAN is the format for reading numbers.
+-@@ LUA_NUMBER_FMT is the format for writing numbers.
+-@@ lua_number2str converts a number to a string.
+-@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
+-@@ lua_str2number converts a string to a number.
+-*/
+-#define LUA_NUMBER_SCAN		"%lf"
+-#define LUA_NUMBER_FMT		"%.14g"
+-#define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n))
+-#define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */
+-#define lua_str2number(s,p)	strtod((s), (p))
+-
+-
+-/*
+-@@ The luai_num* macros define the primitive operations over numbers.
+-*/
+-#if defined(LUA_CORE)
+-#include <math.h>
+-#define luai_numadd(a,b)	((a)+(b))
+-#define luai_numsub(a,b)	((a)-(b))
+-#define luai_nummul(a,b)	((a)*(b))
+-#define luai_numdiv(a,b)	((a)/(b))
+-#define luai_nummod(a,b)	((a) - floor((a)/(b))*(b))
+-#define luai_numpow(a,b)	(pow(a,b))
+-#define luai_numunm(a)		(-(a))
+-#define luai_numeq(a,b)		((a)==(b))
+-#define luai_numlt(a,b)		((a)<(b))
+-#define luai_numle(a,b)		((a)<=(b))
+-#define luai_numisnan(a)	(!luai_numeq((a), (a)))
+-#endif
+-
+-
+-/*
+-@@ lua_number2int is a macro to convert lua_Number to int.
+-@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
+-** CHANGE them if you know a faster way to convert a lua_Number to
+-** int (with any rounding method and without throwing errors) in your
+-** system. In Pentium machines, a naive typecast from double to int
+-** in C is extremely slow, so any alternative is worth trying.
+-*/
+-
+-/* On a Pentium, resort to a trick */
+-#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
+-    (defined(__i386) || defined (_M_IX86) || defined(__i386__))
+-
+-/* On a Microsoft compiler, use assembler */
+-#if defined(_MSC_VER)
+-
+-#define lua_number2int(i,d)   __asm fld d   __asm fistp i
+-#define lua_number2integer(i,n)		lua_number2int(i, n)
+-
+-/* the next trick should work on any Pentium, but sometimes clashes
+-   with a DirectX idiosyncrasy */
+-#else
+-
+-union luai_Cast { double l_d; long l_l; };
+-#define lua_number2int(i,d) \
+-  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
+-#define lua_number2integer(i,n)		lua_number2int(i, n)
+-
+-#endif
+-
+-
+-/* this option always works, but may be slow */
+-#else
+-#define lua_number2int(i,d)	((i)=(int)(d))
+-#define lua_number2integer(i,d)	((i)=(lua_Integer)(d))
+-
+-#endif
+-
+-/* }================================================================== */
+-
+-
+ /*
+ @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
+ ** CHANGE it if your system requires alignments larger than double. (For
+@@ -728,28 +652,6 @@ union luai_Cast { double l_d; long l_l; 
+ #define luai_userstateyield(L,n)	((void)L)
+ 
+ 
+-/*
+-@@ LUA_INTFRMLEN is the length modifier for integer conversions
+-@* in 'string.format'.
+-@@ LUA_INTFRM_T is the integer type correspoding to the previous length
+-@* modifier.
+-** CHANGE them if your system supports long long or does not support long.
+-*/
+-
+-#if defined(LUA_USELONGLONG)
+-
+-#define LUA_INTFRMLEN		"ll"
+-#define LUA_INTFRM_T		long long
+-
+-#else
+-
+-#define LUA_INTFRMLEN		"l"
+-#define LUA_INTFRM_T		long
+-
+-#endif
+-
+-
+-
+ /* =================================================================== */
+ 
+ /*
+--- a/src/lundump.c
++++ b/src/lundump.c
+@@ -73,6 +73,13 @@ static lua_Number LoadNumber(LoadState* 
+  return x;
+ }
+ 
++static lua_Integer LoadInteger(LoadState* S)
++{
++ lua_Integer x;
++ LoadVar(S,x);
++ return x;
++}
++
+ static TString* LoadString(LoadState* S)
+ {
+  size_t size;
+@@ -119,6 +126,9 @@ static void LoadConstants(LoadState* S, 
+    case LUA_TNUMBER:
+ 	setnvalue(o,LoadNumber(S));
+ 	break;
++   case LUA_TINT:   /* Integer type saved in bytecode (see lcode.c) */
++	setivalue(o,LoadInteger(S));
++	break;
+    case LUA_TSTRING:
+ 	setsvalue2n(S->L,o,LoadString(S));
+ 	break;
+@@ -223,5 +233,22 @@ void luaU_header (char* h)
+  *h++=(char)sizeof(size_t);
+  *h++=(char)sizeof(Instruction);
+  *h++=(char)sizeof(lua_Number);
+- *h++=(char)(((lua_Number)0.5)==0);		/* is lua_Number integral? */
++
++ /* 
++  * Last byte of header (0/1 in unpatched Lua 5.1.3):
++  *
++  * 0: lua_Number is float or double, lua_Integer not used. (nonpatched only)
++  * 1: lua_Number is integer (nonpatched only)
++  *
++  * +2: LNUM_INT16: sizeof(lua_Integer)
++  * +4: LNUM_INT32: sizeof(lua_Integer)
++  * +8: LNUM_INT64: sizeof(lua_Integer)
++  *
++  * +0x80: LNUM_COMPLEX
++  */
++ *h++ = (char)(sizeof(lua_Integer)
++#ifdef LNUM_COMPLEX
++    | 0x80
++#endif
++    );
+ }
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -25,22 +25,35 @@
+ #include "ltable.h"
+ #include "ltm.h"
+ #include "lvm.h"
+-
+-
++#include "llex.h"
++#include "lnum.h"
+ 
+ /* limit for table tag-method chains (to avoid loops) */
+ #define MAXTAGLOOP	100
+ 
+ 
+-const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
+-  lua_Number num;
++/*
++ * If 'obj' is a string, it is tried to be interpreted as a number.
++ */
++const TValue *luaV_tonumber ( const TValue *obj, TValue *n) {
++  lua_Number d;
++  lua_Integer i;
++  
+   if (ttisnumber(obj)) return obj;
+-  if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
+-    setnvalue(n, num);
+-    return n;
+-  }
+-  else
+-    return NULL;
++
++  if (ttisstring(obj)) {
++    switch( luaO_str2d( svalue(obj), &d, &i ) ) {
++        case TK_INT:
++            setivalue(n,i); return n;
++        case TK_NUMBER: 
++            setnvalue(n,d); return n;
++#ifdef LNUM_COMPLEX
++        case TK_NUMBER2:    /* "N.NNNi", != 0 */
++            setnvalue_complex_fast(n, d*I); return n;
++#endif
++        }
++    }
++  return NULL;
+ }
+ 
+ 
+@@ -49,8 +62,7 @@ int luaV_tostring (lua_State *L, StkId o
+     return 0;
+   else {
+     char s[LUAI_MAXNUMBER2STR];
+-    lua_Number n = nvalue(obj);
+-    lua_number2str(s, n);
++    luaO_num2buf(s,obj);
+     setsvalue2s(L, obj, luaS_new(L, s));
+     return 1;
+   }
+@@ -222,59 +234,127 @@ static int l_strcmp (const TString *ls, 
+ }
+ 
+ 
++#ifdef LNUM_COMPLEX
++void error_complex( lua_State *L, const TValue *l, const TValue *r )
++{
++  char buf1[ LUAI_MAXNUMBER2STR ];
++  char buf2[ LUAI_MAXNUMBER2STR ];
++  luaO_num2buf( buf1, l );
++  luaO_num2buf( buf2, r );
++  luaG_runerror( L, "unable to compare: %s with %s", buf1, buf2 );
++  /* no return */
++}
++#endif
++
++
+ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
+   int res;
+-  if (ttype(l) != ttype(r))
++  int tl,tr;
++  lua_Integer tmp;
++
++  if (!ttype_ext_same(l,r))
+     return luaG_ordererror(L, l, r);
+-  else if (ttisnumber(l))
+-    return luai_numlt(nvalue(l), nvalue(r));
+-  else if (ttisstring(l))
+-    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
+-  else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
++#ifdef LNUM_COMPLEX
++  if ( (nvalue_img(l)!=0) || (nvalue_img(r)!=0) )
++    error_complex( L, l, r );
++#endif
++  tl= ttype(l); tr= ttype(r);
++  if (tl==tr) {  /* clear arithmetics */
++    switch(tl) {
++      case LUA_TINT:      return ivalue(l) < ivalue(r);
++      case LUA_TNUMBER:   return luai_numlt(nvalue_fast(l), nvalue_fast(r));
++      case LUA_TSTRING:   return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
++    }
++  } else if (tl==LUA_TINT) {  /* l:int, r:num */
++    /* Avoid accuracy losing casts: if 'r' is integer by value, do comparisons
++     * in integer realm. Only otherwise cast 'l' to FP (which might change its
++     * value).
++     */
++    if (tt_integer_valued(r,&tmp)) 
++        return ivalue(l) < tmp;
++    else 
++        return luai_numlt( cast_num(ivalue(l)), nvalue_fast(r) );
++
++  } else if (tl==LUA_TNUMBER) {  /* l:num, r:int */
++    if (tt_integer_valued(l,&tmp)) 
++        return tmp < ivalue(r);
++    else
++        return luai_numlt( nvalue_fast(l), cast_num(ivalue(r)) );
++
++  } else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+     return res;
++
+   return luaG_ordererror(L, l, r);
+ }
+ 
+ 
+ static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
+   int res;
+-  if (ttype(l) != ttype(r))
++  int tl, tr;
++  lua_Integer tmp;
++
++  if (!ttype_ext_same(l,r))
+     return luaG_ordererror(L, l, r);
+-  else if (ttisnumber(l))
+-    return luai_numle(nvalue(l), nvalue(r));
+-  else if (ttisstring(l))
+-    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
+-  else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
++#ifdef LNUM_COMPLEX
++  if ( (nvalue_img(l)!=0) || (nvalue_img(r)!=0) )
++    error_complex( L, l, r );
++#endif
++  tl= ttype(l); tr= ttype(r);
++  if (tl==tr) {  /* clear arithmetics */
++    switch(tl) {
++      case LUA_TINT:      return ivalue(l) <= ivalue(r);
++      case LUA_TNUMBER:   return luai_numle(nvalue_fast(l), nvalue_fast(r));
++      case LUA_TSTRING:   return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
++    }
++  }
++  if (tl==LUA_TINT) {  /* l:int, r:num */
++    if (tt_integer_valued(r,&tmp)) 
++        return ivalue(l) <= tmp;
++    else
++        return luai_numle( cast_num(ivalue(l)), nvalue_fast(r) );
++
++  } else if (tl==LUA_TNUMBER) {  /* l:num, r:int */
++    if (tt_integer_valued(l,&tmp)) 
++        return tmp <= ivalue(r);
++    else
++        return luai_numle( nvalue_fast(l), cast_num(ivalue(r)) );
++
++  } else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
+     return res;
+   else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */
+     return !res;
++
+   return luaG_ordererror(L, l, r);
+ }
+ 
+ 
+-int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
++/* Note: 'luaV_equalval()' and 'luaO_rawequalObj()' have largely overlapping
++ *       implementation. LUA_TNIL..LUA_TLIGHTUSERDATA cases could be handled
++ *       simply by the 'default' case here.
++ */
++int luaV_equalval (lua_State *L, const TValue *l, const TValue *r) {
+   const TValue *tm;
+-  lua_assert(ttype(t1) == ttype(t2));
+-  switch (ttype(t1)) {
++  lua_assert(ttype_ext_same(l,r));
++  switch (ttype(l)) {
+     case LUA_TNIL: return 1;
+-    case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
+-    case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */
+-    case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
++    case LUA_TINT:
++    case LUA_TNUMBER: return luaO_rawequalObj(l,r);
++    case LUA_TBOOLEAN: return bvalue(l) == bvalue(r);  /* true must be 1 !! */
++    case LUA_TLIGHTUSERDATA: return pvalue(l) == pvalue(r);
+     case LUA_TUSERDATA: {
+-      if (uvalue(t1) == uvalue(t2)) return 1;
+-      tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
+-                         TM_EQ);
++      if (uvalue(l) == uvalue(r)) return 1;
++      tm = get_compTM(L, uvalue(l)->metatable, uvalue(r)->metatable, TM_EQ);
+       break;  /* will try TM */
+     }
+     case LUA_TTABLE: {
+-      if (hvalue(t1) == hvalue(t2)) return 1;
+-      tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
++      if (hvalue(l) == hvalue(r)) return 1;
++      tm = get_compTM(L, hvalue(l)->metatable, hvalue(r)->metatable, TM_EQ);
+       break;  /* will try TM */
+     }
+-    default: return gcvalue(t1) == gcvalue(t2);
++    default: return gcvalue(l) == gcvalue(r);
+   }
+   if (tm == NULL) return 0;  /* no TM? */
+-  callTMres(L, L->top, tm, t1, t2);  /* call TM */
++  callTMres(L, L->top, tm, l, r);  /* call TM */
+   return !l_isfalse(L->top);
+ }
+ 
+@@ -314,30 +394,6 @@ void luaV_concat (lua_State *L, int tota
+ }
+ 
+ 
+-static void Arith (lua_State *L, StkId ra, const TValue *rb,
+-                   const TValue *rc, TMS op) {
+-  TValue tempb, tempc;
+-  const TValue *b, *c;
+-  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
+-      (c = luaV_tonumber(rc, &tempc)) != NULL) {
+-    lua_Number nb = nvalue(b), nc = nvalue(c);
+-    switch (op) {
+-      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
+-      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
+-      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
+-      case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
+-      case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
+-      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
+-      case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
+-      default: lua_assert(0); break;
+-    }
+-  }
+-  else if (!call_binTM(L, rb, rc, ra, op))
+-    luaG_aritherror(L, rb, rc);
+-}
+-
+-
+-
+ /*
+ ** some macros for common tasks in `luaV_execute'
+ */
+@@ -361,17 +417,154 @@ static void Arith (lua_State *L, StkId r
+ #define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; }
+ 
+ 
+-#define arith_op(op,tm) { \
+-        TValue *rb = RKB(i); \
+-        TValue *rc = RKC(i); \
+-        if (ttisnumber(rb) && ttisnumber(rc)) { \
+-          lua_Number nb = nvalue(rb), nc = nvalue(rc); \
+-          setnvalue(ra, op(nb, nc)); \
+-        } \
+-        else \
+-          Protect(Arith(L, ra, rb, rc, tm)); \
++/* Note: if called for unary operations, 'rc'=='rb'.
++ */
++static void Arith (lua_State *L, StkId ra, const TValue *rb,
++                   const TValue *rc, TMS op) {
++  TValue tempb, tempc;
++  const TValue *b, *c;
++  lua_Number nb,nc;
++
++  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
++      (c = luaV_tonumber(rc, &tempc)) != NULL) {
++
++    /* Keep integer arithmetics in the integer realm, if possible.
++     */
++    if (ttisint(b) && ttisint(c)) {
++      lua_Integer ib = ivalue(b), ic = ivalue(c);
++      lua_Integer *ri = &ra->value.i;
++      ra->tt= LUA_TINT;  /* part of 'setivalue(ra)' */
++      switch (op) {
++        case TM_ADD: if (try_addint( ri, ib, ic)) return; break;
++        case TM_SUB: if (try_subint( ri, ib, ic)) return; break;
++        case TM_MUL: if (try_mulint( ri, ib, ic)) return; break;
++        case TM_DIV: if (try_divint( ri, ib, ic)) return; break;
++        case TM_MOD: if (try_modint( ri, ib, ic)) return; break;
++        case TM_POW: if (try_powint( ri, ib, ic)) return; break;
++        case TM_UNM: if (try_unmint( ri, ib)) return; break;
++        default: lua_assert(0);
++      }
++    }
++    /* Fallback to floating point, when leaving range. */
++
++#ifdef LNUM_COMPLEX
++    if ((nvalue_img(b)!=0) || (nvalue_img(c)!=0)) {
++      lua_Complex r;
++      if (op==TM_UNM) {
++        r= -nvalue_complex_fast(b);     /* never an integer (or scalar) */
++        setnvalue_complex_fast( ra, r );
++      } else {
++        lua_Complex bb= nvalue_complex(b), cc= nvalue_complex(c);
++        switch (op) {
++          case TM_ADD: r= bb + cc; break;
++          case TM_SUB: r= bb - cc; break;
++          case TM_MUL: r= bb * cc; break;
++          case TM_DIV: r= bb / cc; break;
++          case TM_MOD: 
++            luaG_runerror(L, "attempt to use %% on complex numbers");  /* no return */
++          case TM_POW: r= luai_vectpow( bb, cc ); break;
++          default: lua_assert(0); r=0;
++        }
++        setnvalue_complex( ra, r );
+       }
++      return;
++    }
++#endif
++    nb = nvalue(b); nc = nvalue(c);
++    switch (op) {
++      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); return;
++      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); return;
++      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); return;
++      case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); return;
++      case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); return;
++      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); return;
++      case TM_UNM: setnvalue(ra, luai_numunm(nb)); return;
++      default: lua_assert(0);
++    }
++  }
++  
++  /* Either operand not a number */
++  if (!call_binTM(L, rb, rc, ra, op))
++    luaG_aritherror(L, rb, rc);
++}
+ 
++/* Helper macro to sort arithmetic operations into four categories:
++ *  TK_INT: integer - integer operands
++ *  TK_NUMBER: number - number (non complex, either may be integer)
++ *  TK_NUMBER2: complex numbers (at least the other)
++ *  0: non-numeric (at least the other)
++*/
++#ifdef LNUM_COMPLEX
++static inline int arith_mode( const TValue *rb, const TValue *rc ) {
++  if (ttisint(rb) && ttisint(rc)) return TK_INT;
++  if (ttiscomplex(rb) || ttiscomplex(rc)) return TK_NUMBER2;
++  if (ttisnumber(rb) && ttisnumber(rc)) return TK_NUMBER;
++  return 0;
++}
++#else
++# define arith_mode(rb,rc) \
++    ( (ttisint(rb) && ttisint(rc)) ? TK_INT : \
++      (ttisnumber(rb) && ttisnumber(rc)) ? TK_NUMBER : 0 )
++#endif
++
++/* arith_op macro for two operators:
++ * automatically chooses, which function (number, integer, complex) to use
++ */
++#define ARITH_OP2_START( op_num, op_int ) \
++  int failed= 0; \
++  switch( arith_mode(rb,rc) ) { \
++    case TK_INT: \
++      if (op_int ( &(ra)->value.i, ivalue(rb), ivalue(rc) )) \
++        { ra->tt= LUA_TINT; break; } /* else flow through */ \
++    case TK_NUMBER: \
++      setnvalue(ra, op_num ( nvalue(rb), nvalue(rc) )); break;
++
++#define ARITH_OP2_END \
++    default: \
++      failed= 1; break; \
++  } if (!failed) continue;
++
++#define arith_op_continue_scalar( op_num, op_int ) \
++    ARITH_OP2_START( op_num, op_int ) \
++    ARITH_OP2_END
++
++#ifdef LNUM_COMPLEX
++# define arith_op_continue( op_num, op_int, op_complex ) \
++    ARITH_OP2_START( op_num, op_int ) \
++      case TK_NUMBER2: \
++        setnvalue_complex( ra, op_complex ( nvalue_complex(rb), nvalue_complex(rc) ) ); break; \
++    ARITH_OP2_END
++#else
++# define arith_op_continue(op_num,op_int,_) arith_op_continue_scalar(op_num,op_int)
++#endif
++
++/* arith_op macro for one operator:
++ */
++#define ARITH_OP1_START( op_num, op_int ) \
++  int failed= 0; \
++  switch( arith_mode(rb,rb) ) { \
++    case TK_INT: \
++      if (op_int ( &(ra)->value.i, ivalue(rb) )) \
++        { ra->tt= LUA_TINT; break; } /* else flow through */ \
++      case TK_NUMBER: \
++        setnvalue(ra, op_num (nvalue(rb))); break; \
++
++#define ARITH_OP1_END \
++      default: \
++        failed= 1; break; \
++  } if (!failed) continue;
++
++#ifdef LNUM_COMPLEX
++# define arith_op1_continue( op_num, op_int, op_complex ) \
++    ARITH_OP1_START( op_num, op_int ) \
++      case TK_NUMBER2: \
++        setnvalue_complex( ra, op_complex ( nvalue_complex_fast(rb) )); break; \
++    ARITH_OP1_END
++#else
++# define arith_op1_continue( op_num, op_int, _ ) \
++    ARITH_OP1_START( op_num, op_int ) \
++    ARITH_OP1_END
++#endif
+ 
+ 
+ void luaV_execute (lua_State *L, int nexeccalls) {
+@@ -472,38 +665,45 @@ void luaV_execute (lua_State *L, int nex
+         continue;
+       }
+       case OP_ADD: {
+-        arith_op(luai_numadd, TM_ADD);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue( luai_numadd, try_addint, luai_vectadd );
++        Protect(Arith(L, ra, rb, rc, TM_ADD)); \
+         continue;
+       }
+       case OP_SUB: {
+-        arith_op(luai_numsub, TM_SUB);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue( luai_numsub, try_subint, luai_vectsub );
++        Protect(Arith(L, ra, rb, rc, TM_SUB));
+         continue;
+       }
+       case OP_MUL: {
+-        arith_op(luai_nummul, TM_MUL);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue(luai_nummul, try_mulint, luai_vectmul);
++        Protect(Arith(L, ra, rb, rc, TM_MUL));
+         continue;
+       }
+       case OP_DIV: {
+-        arith_op(luai_numdiv, TM_DIV);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue(luai_numdiv, try_divint, luai_vectdiv);
++        Protect(Arith(L, ra, rb, rc, TM_DIV));
+         continue;
+       }
+       case OP_MOD: {
+-        arith_op(luai_nummod, TM_MOD);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue_scalar(luai_nummod, try_modint);  /* scalars only */
++        Protect(Arith(L, ra, rb, rc, TM_MOD));
+         continue;
+       }
+       case OP_POW: {
+-        arith_op(luai_numpow, TM_POW);
++        TValue *rb = RKB(i), *rc= RKC(i);
++        arith_op_continue(luai_numpow, try_powint, luai_vectpow);
++        Protect(Arith(L, ra, rb, rc, TM_POW));
+         continue;
+       }
+       case OP_UNM: {
+         TValue *rb = RB(i);
+-        if (ttisnumber(rb)) {
+-          lua_Number nb = nvalue(rb);
+-          setnvalue(ra, luai_numunm(nb));
+-        }
+-        else {
+-          Protect(Arith(L, ra, rb, rb, TM_UNM));
+-        }
++        arith_op1_continue(luai_numunm, try_unmint, luai_vectunm);
++        Protect(Arith(L, ra, rb, rb, TM_UNM));
+         continue;
+       }
+       case OP_NOT: {
+@@ -515,11 +715,11 @@ void luaV_execute (lua_State *L, int nex
+         const TValue *rb = RB(i);
+         switch (ttype(rb)) {
+           case LUA_TTABLE: {
+-            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
++            setivalue(ra, luaH_getn(hvalue(rb)));
+             break;
+           }
+           case LUA_TSTRING: {
+-            setnvalue(ra, cast_num(tsvalue(rb)->len));
++            setivalue(ra, tsvalue(rb)->len);
+             break;
+           }
+           default: {  /* try metamethod */
+@@ -652,14 +852,30 @@ void luaV_execute (lua_State *L, int nex
+         }
+       }
+       case OP_FORLOOP: {
+-        lua_Number step = nvalue(ra+2);
+-        lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
+-        lua_Number limit = nvalue(ra+1);
+-        if (luai_numlt(0, step) ? luai_numle(idx, limit)
+-                                : luai_numle(limit, idx)) {
+-          dojump(L, pc, GETARG_sBx(i));  /* jump back */
+-          setnvalue(ra, idx);  /* update internal index... */
+-          setnvalue(ra+3, idx);  /* ...and external index */
++        /* If start,step and limit are all integers, we don't need to check
++         * against overflow in the looping.
++         */
++        if (ttisint(ra) && ttisint(ra+1) && ttisint(ra+2)) {
++          lua_Integer step = ivalue(ra+2);
++          lua_Integer idx = ivalue(ra) + step; /* increment index */
++          lua_Integer limit = ivalue(ra+1);
++          if (step > 0 ? (idx <= limit) : (limit <= idx)) {
++            dojump(L, pc, GETARG_sBx(i));  /* jump back */
++            setivalue(ra, idx);  /* update internal index... */
++            setivalue(ra+3, idx);  /* ...and external index */
++          }
++        } else {
++          /* non-integer looping (don't use 'nvalue_fast', some may be integer!) 
++          */
++          lua_Number step = nvalue(ra+2);
++          lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
++          lua_Number limit = nvalue(ra+1);
++          if (luai_numlt(0, step) ? luai_numle(idx, limit)
++                                  : luai_numle(limit, idx)) {
++            dojump(L, pc, GETARG_sBx(i));  /* jump back */
++            setnvalue(ra, idx);  /* update internal index... */
++            setnvalue(ra+3, idx);  /* ...and external index */
++          }
+         }
+         continue;
+       }
+@@ -668,13 +884,21 @@ void luaV_execute (lua_State *L, int nex
+         const TValue *plimit = ra+1;
+         const TValue *pstep = ra+2;
+         L->savedpc = pc;  /* next steps may throw errors */
++        /* Using same location for tonumber's both arguments, effectively does
++         * in-place modification (string->number). */
+         if (!tonumber(init, ra))
+           luaG_runerror(L, LUA_QL("for") " initial value must be a number");
+         else if (!tonumber(plimit, ra+1))
+           luaG_runerror(L, LUA_QL("for") " limit must be a number");
+         else if (!tonumber(pstep, ra+2))
+           luaG_runerror(L, LUA_QL("for") " step must be a number");
+-        setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
++        /* Step back one value (keep within integers if we can)
++         */
++        if (!( ttisint(ra) && ttisint(pstep) &&
++               try_subint( &ra->value.i, ivalue(ra), ivalue(pstep) ) )) {
++            /* don't use 'nvalue_fast()', values may be integer */
++            setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
++        }
+         dojump(L, pc, GETARG_sBx(i));
+         continue;
+       }
+@@ -711,7 +935,7 @@ void luaV_execute (lua_State *L, int nex
+           luaH_resizearray(L, h, last);  /* pre-alloc it at once */
+         for (; n > 0; n--) {
+           TValue *val = ra+n;
+-          setobj2t(L, luaH_setnum(L, h, last--), val);
++          setobj2t(L, luaH_setint(L, h, last--), val);
+           luaC_barriert(L, h, val);
+         }
+         continue;
+--- a/src/lvm.h
++++ b/src/lvm.h
+@@ -15,11 +15,9 @@
+ 
+ #define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
+ 
+-#define tonumber(o,n)	(ttype(o) == LUA_TNUMBER || \
+-                         (((o) = luaV_tonumber(o,n)) != NULL))
++#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL))
+ 
+-#define equalobj(L,o1,o2) \
+-	(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
++#define equalobj(L,o1,o2) (ttype_ext_same(o1,o2) && luaV_equalval(L, o1, o2))
+ 
+ 
+ LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
+--- a/src/print.c
++++ b/src/print.c
+@@ -14,6 +14,7 @@
+ #include "lobject.h"
+ #include "lopcodes.h"
+ #include "lundump.h"
++#include "lnum.h"
+ 
+ #define PrintFunction	luaU_print
+ 
+@@ -59,8 +60,16 @@ static void PrintConstant(const Proto* f
+   case LUA_TBOOLEAN:
+ 	printf(bvalue(o) ? "true" : "false");
+ 	break;
++  case LUA_TINT:
++	printf(LUA_INTEGER_FMT,ivalue(o));
++	break;
+   case LUA_TNUMBER:
+-	printf(LUA_NUMBER_FMT,nvalue(o));
++#ifdef LNUM_COMPLEX
++    // TBD: Do we get complex values here?
++    { lua_Number b= nvalue_img_fast(o);
++	  printf( LUA_NUMBER_FMT "%s" LUA_NUMBER_FMT "i", nvalue_fast(o), b>=0 ? "+":"", b ); }
++#endif
++	printf(LUA_NUMBER_FMT,nvalue_fast(o));
+ 	break;
+   case LUA_TSTRING:
+ 	PrintString(rawtsvalue(o));
diff --git a/package/utils/lua/patches/011-lnum-use-double.patch b/package/utils/lua/patches/011-lnum-use-double.patch
new file mode 100644
index 0000000000..14c720bf19
--- /dev/null
+++ b/package/utils/lua/patches/011-lnum-use-double.patch
@@ -0,0 +1,11 @@
+--- a/src/lnum_config.h
++++ b/src/lnum_config.h
+@@ -11,7 +11,7 @@
+ ** Default number modes
+ */
+ #if (!defined LNUM_DOUBLE) && (!defined LNUM_FLOAT) && (!defined LNUM_LDOUBLE)
+-# define LNUM_FLOAT
++# define LNUM_DOUBLE
+ #endif
+ #if (!defined LNUM_INT16) && (!defined LNUM_INT32) && (!defined LNUM_INT64)
+ # define LNUM_INT32
diff --git a/package/utils/lua/patches/012-lnum-fix-ltle-relational-operators.patch b/package/utils/lua/patches/012-lnum-fix-ltle-relational-operators.patch
new file mode 100644
index 0000000000..937fc137e8
--- /dev/null
+++ b/package/utils/lua/patches/012-lnum-fix-ltle-relational-operators.patch
@@ -0,0 +1,22 @@
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -284,7 +284,8 @@ int luaV_lessthan (lua_State *L, const T
+     else
+         return luai_numlt( nvalue_fast(l), cast_num(ivalue(r)) );
+ 
+-  } else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
++  } 
++  if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+     return res;
+ 
+   return luaG_ordererror(L, l, r);
+@@ -322,7 +323,8 @@ static int lessequal (lua_State *L, cons
+     else
+         return luai_numle( nvalue_fast(l), cast_num(ivalue(r)) );
+ 
+-  } else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
++  } 
++  if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
+     return res;
+   else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */
+     return !res;
diff --git a/package/utils/lua/patches/015-lnum-ppc-compat.patch b/package/utils/lua/patches/015-lnum-ppc-compat.patch
new file mode 100644
index 0000000000..2ea59f1769
--- /dev/null
+++ b/package/utils/lua/patches/015-lnum-ppc-compat.patch
@@ -0,0 +1,11 @@
+--- a/src/lua.h
++++ b/src/lua.h
+@@ -79,7 +79,7 @@ typedef void * (*lua_Alloc) (void *ud, v
+  *     not acceptable for 5.1, maybe 5.2 onwards?
+  *  9: greater than existing (5.1) type values.
+ */
+-#define LUA_TINT (-2)
++#define LUA_TINT 9
+ 
+ #define LUA_TNIL		0
+ #define LUA_TBOOLEAN		1
diff --git a/package/utils/lua/patches/020-shared_liblua.patch b/package/utils/lua/patches/020-shared_liblua.patch
new file mode 100644
index 0000000000..bcd410f690
--- /dev/null
+++ b/package/utils/lua/patches/020-shared_liblua.patch
@@ -0,0 +1,140 @@
+--- a/Makefile
++++ b/Makefile
+@@ -42,8 +42,8 @@ PLATS= aix ansi bsd freebsd generic linu
+ 
+ # What to install.
+ TO_BIN= lua luac
+-TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp
+-TO_LIB= liblua.a
++TO_INC= lua.h luaconf.h lualib.h lauxlib.h ../etc/lua.hpp lnum_config.h
++TO_LIB= liblua.a liblua.so.$R
+ TO_MAN= lua.1 luac.1
+ 
+ # Lua version and release.
+@@ -63,6 +63,7 @@ install: dummy
+ 	cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
+ 	cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
+ 	cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
++	ln -s liblua.so.$R $(INSTALL_LIB)/liblua.so
+ 	cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
+ 
+ ranlib:
+--- a/src/ldo.h
++++ b/src/ldo.h
+@@ -46,7 +46,7 @@ LUAI_FUNC int luaD_pcall (lua_State *L, 
+ LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
+ LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
+ LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
+-LUAI_FUNC void luaD_growstack (lua_State *L, int n);
++LUA_API void luaD_growstack (lua_State *L, int n);
+ 
+ LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
+ LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
+--- a/src/lfunc.h
++++ b/src/lfunc.h
+@@ -18,7 +18,7 @@
+                          cast(int, sizeof(TValue *)*((n)-1)))
+ 
+ 
+-LUAI_FUNC Proto *luaF_newproto (lua_State *L);
++LUA_API Proto *luaF_newproto (lua_State *L);
+ LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
+ LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
+ LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
+--- a/src/lmem.h
++++ b/src/lmem.h
+@@ -38,9 +38,9 @@
+    ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
+ 
+ 
+-LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
++LUA_API void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
+                                                           size_t size);
+-LUAI_FUNC void *luaM_toobig (lua_State *L);
++LUA_API void *luaM_toobig (lua_State *L);
+ LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
+                                size_t size_elem, int limit,
+                                const char *errormsg);
+--- a/src/lstring.h
++++ b/src/lstring.h
+@@ -25,7 +25,7 @@
+ 
+ LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+ LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
+-LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
++LUA_API TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+ 
+ 
+ #endif
+--- a/src/lundump.h
++++ b/src/lundump.h
+@@ -17,7 +17,7 @@ LUAI_FUNC Proto* luaU_undump (lua_State*
+ LUAI_FUNC void luaU_header (char* h);
+ 
+ /* dump one chunk; from ldump.c */
+-LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
++LUA_API int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
+ 
+ #ifdef luac_c
+ /* print one chunk; from print.c */
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -23,6 +23,7 @@ MYLIBS=
+ PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
+ 
+ LUA_A=	liblua.a
++LUA_SO= liblua.so
+ CORE_O=	lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
+ 	lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o  \
+ 	lundump.o lvm.o lzio.o lnum.o
+@@ -33,11 +34,12 @@ LUA_T=	lua
+ LUA_O=	lua.o
+ 
+ LUAC_T=	luac
+-LUAC_O=	luac.o print.o
++LUAC_O=	luac.o print.o lopcodes.o
+ 
+ ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O)
+-ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
++ALL_T= $(LUA_A) $(LUA_SO) $(LUA_T) $(LUAC_T)
+ ALL_A= $(LUA_A)
++ALL_SO= $(LUA_SO)
+ 
+ default: $(PLAT)
+ 
+@@ -47,14 +49,23 @@ o:	$(ALL_O)
+ 
+ a:	$(ALL_A)
+ 
++so:	$(ALL_SO)
++
+ $(LUA_A): $(CORE_O) $(LIB_O)
+ 	$(AR) $@ $(CORE_O) $(LIB_O)	# DLL needs all object files
+ 	$(RANLIB) $@
+ 
+-$(LUA_T): $(LUA_O) $(LUA_A)
+-	$(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
++$(LUA_SO): $(CORE_O) $(LIB_O)
++	$(CC) -o $@.$(PKG_VERSION) -shared -Wl,-soname="$@.$(PKG_VERSION)" $?
++	ln -fs $@.$(PKG_VERSION) $@
++
++$(LUA_T): $(LUA_O) $(LUA_SO)
++	$(CC) -o $@ -L. -llua $(MYLDFLAGS) $(LUA_O) $(LIBS)
++
++$(LUAC_T): $(LUAC_O) $(LUA_SO)
++	$(CC) -o $@ -L. -llua $(MYLDFLAGS) $(LUAC_O) $(LIBS)
+ 
+-$(LUAC_T): $(LUAC_O) $(LUA_A)
++$(LUAC_T)-host: $(LUAC_O) $(LUA_A)
+ 	$(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
+ 
+ clean:
+@@ -96,7 +107,7 @@ generic:
+ 	$(MAKE) all MYCFLAGS=
+ 
+ linux:
+-	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses"
++	$(MAKE) all MYCFLAGS+=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses"
+ 
+ macosx:
+ 	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline"
diff --git a/package/utils/lua/patches/030-archindependent-bytecode.patch b/package/utils/lua/patches/030-archindependent-bytecode.patch
new file mode 100644
index 0000000000..8dfef85d0d
--- /dev/null
+++ b/package/utils/lua/patches/030-archindependent-bytecode.patch
@@ -0,0 +1,111 @@
+--- a/src/ldump.c
++++ b/src/ldump.c
+@@ -67,12 +67,12 @@ static void DumpString(const TString* s,
+ {
+  if (s==NULL || getstr(s)==NULL)
+  {
+-  size_t size=0;
++  unsigned int size=0;
+   DumpVar(size,D);
+  }
+  else
+  {
+-  size_t size=s->tsv.len+1;		/* include trailing '\0' */
++  unsigned int size=s->tsv.len+1;		/* include trailing '\0' */
+   DumpVar(size,D);
+   DumpBlock(getstr(s),size,D);
+  }
+--- a/src/lundump.c
++++ b/src/lundump.c
+@@ -25,6 +25,7 @@ typedef struct {
+  ZIO* Z;
+  Mbuffer* b;
+  const char* name;
++ int swap;
+ } LoadState;
+ 
+ #ifdef LUAC_TRUST_BINARIES
+@@ -40,7 +41,6 @@ static void error(LoadState* S, const ch
+ }
+ #endif
+ 
+-#define LoadMem(S,b,n,size)	LoadBlock(S,b,(n)*(size))
+ #define	LoadByte(S)		(lu_byte)LoadChar(S)
+ #define LoadVar(S,x)		LoadMem(S,&x,1,sizeof(x))
+ #define LoadVector(S,b,n,size)	LoadMem(S,b,n,size)
+@@ -51,6 +51,49 @@ static void LoadBlock(LoadState* S, void
+  IF (r!=0, "unexpected end");
+ }
+ 
++static void LoadMem (LoadState* S, void* b, int n, size_t size)
++{
++ LoadBlock(S,b,n*size);
++ if (S->swap)
++ {
++  char* p=(char*) b;
++  char c;
++  switch (size)
++  {
++   case 1:
++  	break;
++   case 2:
++	while (n--)
++	{
++	 c=p[0]; p[0]=p[1]; p[1]=c;
++	 p+=2;
++	}
++  	break;
++   case 4:
++	while (n--)
++	{
++	 c=p[0]; p[0]=p[3]; p[3]=c;
++	 c=p[1]; p[1]=p[2]; p[2]=c;
++	 p+=4;
++	}
++  	break;
++   case 8:
++	while (n--)
++	{
++	 c=p[0]; p[0]=p[7]; p[7]=c;
++	 c=p[1]; p[1]=p[6]; p[6]=c;
++	 c=p[2]; p[2]=p[5]; p[5]=c;
++	 c=p[3]; p[3]=p[4]; p[4]=c;
++	 p+=8;
++	}
++  	break;
++   default:
++   	IF(1, "bad size");
++  	break;
++  }
++ }
++}
++
+ static int LoadChar(LoadState* S)
+ {
+  char x;
+@@ -82,7 +125,7 @@ static lua_Integer LoadInteger(LoadState
+ 
+ static TString* LoadString(LoadState* S)
+ {
+- size_t size;
++ unsigned int size;
+  LoadVar(S,size);
+  if (size==0)
+   return NULL;
+@@ -196,6 +239,7 @@ static void LoadHeader(LoadState* S)
+  char s[LUAC_HEADERSIZE];
+  luaU_header(h);
+  LoadBlock(S,s,LUAC_HEADERSIZE);
++ S->swap=(s[6]!=h[6]); s[6]=h[6];
+  IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header");
+ }
+ 
+@@ -230,7 +274,7 @@ void luaU_header (char* h)
+  *h++=(char)LUAC_FORMAT;
+  *h++=(char)*(char*)&x;				/* endianness */
+  *h++=(char)sizeof(int);
+- *h++=(char)sizeof(size_t);
++ *h++=(char)sizeof(unsigned int);
+  *h++=(char)sizeof(Instruction);
+  *h++=(char)sizeof(lua_Number);
+ 
diff --git a/package/utils/lua/patches/040-use-symbolic-functions.patch b/package/utils/lua/patches/040-use-symbolic-functions.patch
new file mode 100644
index 0000000000..f59069557d
--- /dev/null
+++ b/package/utils/lua/patches/040-use-symbolic-functions.patch
@@ -0,0 +1,11 @@
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -56,7 +56,7 @@ $(LUA_A): $(CORE_O) $(LIB_O)
+ 	$(RANLIB) $@
+ 
+ $(LUA_SO): $(CORE_O) $(LIB_O)
+-	$(CC) -o $@.$(PKG_VERSION) -shared -Wl,-soname="$@.$(PKG_VERSION)" $?
++	$(CC) -o $@.$(PKG_VERSION) -Wl,-Bsymbolic-functions -shared -Wl,-soname="$@.$(PKG_VERSION)" $?
+ 	ln -fs $@.$(PKG_VERSION) $@
+ 
+ $(LUA_T): $(LUA_O) $(LUA_SO)
diff --git a/package/utils/lua/patches/050-honor-cflags.patch b/package/utils/lua/patches/050-honor-cflags.patch
new file mode 100644
index 0000000000..dd65791482
--- /dev/null
+++ b/package/utils/lua/patches/050-honor-cflags.patch
@@ -0,0 +1,11 @@
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -56,7 +56,7 @@ $(LUA_A): $(CORE_O) $(LIB_O)
+ 	$(RANLIB) $@
+ 
+ $(LUA_SO): $(CORE_O) $(LIB_O)
+-	$(CC) -o $@.$(PKG_VERSION) -Wl,-Bsymbolic-functions -shared -Wl,-soname="$@.$(PKG_VERSION)" $?
++	$(CC) -o $@.$(PKG_VERSION) -Wl,-Bsymbolic-functions $(MYLDFLAGS) -shared -Wl,-soname="$@.$(PKG_VERSION)" $?
+ 	ln -fs $@.$(PKG_VERSION) $@
+ 
+
diff --git a/package/utils/lua/patches/100-no_readline.patch b/package/utils/lua/patches/100-no_readline.patch
new file mode 100644
index 0000000000..0350e470ad
--- /dev/null
+++ b/package/utils/lua/patches/100-no_readline.patch
@@ -0,0 +1,49 @@
+--- a/src/luaconf.h
++++ b/src/luaconf.h
+@@ -38,7 +38,6 @@
+ #if defined(LUA_USE_LINUX)
+ #define LUA_USE_POSIX
+ #define LUA_USE_DLOPEN		/* needs an extra library: -ldl */
+-#define LUA_USE_READLINE	/* needs some extra libraries */
+ #endif
+ 
+ #if defined(LUA_USE_MACOSX)
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -17,6 +17,7 @@ LIBS= -lm $(MYLIBS)
+ MYCFLAGS=
+ MYLDFLAGS=
+ MYLIBS=
++# USE_READLINE=1
+ 
+ # == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE =========
+ 
+@@ -86,7 +87,7 @@ echo:
+ 	@echo "MYLIBS = $(MYLIBS)"
+ 
+ # convenience targets for popular platforms
+-
++RFLAG=$(if $(USE_READLINE),-DLUA_USE_READLINE)
+ none:
+ 	@echo "Please choose a platform:"
+ 	@echo "   $(PLATS)"
+@@ -101,16 +102,16 @@ bsd:
+ 	$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E"
+ 
+ freebsd:
+-	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline"
++	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX $(RFLAG)" MYLIBS="-Wl,-E$(if $(USE_READLINE), -lreadline)"
+ 
+ generic:
+ 	$(MAKE) all MYCFLAGS=
+ 
+ linux:
+-	$(MAKE) all MYCFLAGS+=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses"
++	$(MAKE) all MYCFLAGS+="-DLUA_USE_LINUX $(RFLAG)" MYLIBS="-Wl,-E -ldl $(if $(USE_READLINE), -lreadline -lhistory -lncurses)"
+ 
+ macosx:
+-	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline"
++	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX $(if $(USE_READLINE), MYLIBS="-lreadline")
+ # use this on Mac OS X 10.3-
+ #	$(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX
+ 
diff --git a/package/utils/lua/patches/200-lua-path.patch b/package/utils/lua/patches/200-lua-path.patch
new file mode 100644
index 0000000000..054457744a
--- /dev/null
+++ b/package/utils/lua/patches/200-lua-path.patch
@@ -0,0 +1,15 @@
+--- a/src/luaconf.h
++++ b/src/luaconf.h
+@@ -95,9 +95,9 @@
+ 	".\\?.dll;"  LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
+ 
+ #else
+-#define LUA_ROOT	"/usr/local/"
+-#define LUA_LDIR	LUA_ROOT "share/lua/5.1/"
+-#define LUA_CDIR	LUA_ROOT "lib/lua/5.1/"
++#define LUA_ROOT	"/usr/"
++#define LUA_LDIR	LUA_ROOT "share/lua/"
++#define LUA_CDIR	LUA_ROOT "lib/lua/"
+ #define LUA_PATH_DEFAULT  \
+ 		"./?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?/init.lua;" \
+ 		            LUA_CDIR"?.lua;"  LUA_CDIR"?/init.lua"
diff --git a/package/utils/lua/patches/300-opcode_performance.patch b/package/utils/lua/patches/300-opcode_performance.patch
new file mode 100644
index 0000000000..5fbb87388a
--- /dev/null
+++ b/package/utils/lua/patches/300-opcode_performance.patch
@@ -0,0 +1,363 @@
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -31,6 +31,9 @@
+ /* limit for table tag-method chains (to avoid loops) */
+ #define MAXTAGLOOP	100
+ 
++#ifdef __GNUC__
++#define COMPUTED_GOTO 1
++#endif
+ 
+ /*
+  * If 'obj' is a string, it is tried to be interpreted as a number.
+@@ -566,12 +569,63 @@ static inline int arith_mode( const TVal
+     ARITH_OP1_END
+ #endif
+ 
++#ifdef COMPUTED_GOTO
++#define OPCODE_TARGET(op) DO_OP_##op:
++#define CALL_OPCODE(op) goto *opcodes[op];
++#define OPCODE_PTR(op) [OP_##op] = &&DO_OP_##op
++#else
++#define OPCODE_TARGET(op) case OP_##op:
++#define CALL_OPCODE(op) switch (op)
++#endif
++
+ 
+ void luaV_execute (lua_State *L, int nexeccalls) {
+   LClosure *cl;
+   StkId base;
+   TValue *k;
+   const Instruction *pc;
++#ifdef COMPUTED_GOTO
++  static const void *opcodes[] = {
++   OPCODE_PTR(MOVE),
++   OPCODE_PTR(LOADK),
++   OPCODE_PTR(LOADBOOL),
++   OPCODE_PTR(LOADNIL),
++   OPCODE_PTR(GETUPVAL),
++   OPCODE_PTR(GETGLOBAL),
++   OPCODE_PTR(GETTABLE),
++   OPCODE_PTR(SETGLOBAL),
++   OPCODE_PTR(SETUPVAL),
++   OPCODE_PTR(SETTABLE),
++   OPCODE_PTR(NEWTABLE),
++   OPCODE_PTR(SELF),
++   OPCODE_PTR(ADD),
++   OPCODE_PTR(SUB),
++   OPCODE_PTR(MUL),
++   OPCODE_PTR(DIV),
++   OPCODE_PTR(MOD),
++   OPCODE_PTR(POW),
++   OPCODE_PTR(UNM),
++   OPCODE_PTR(NOT),
++   OPCODE_PTR(LEN),
++   OPCODE_PTR(CONCAT),
++   OPCODE_PTR(JMP),
++   OPCODE_PTR(EQ),
++   OPCODE_PTR(LT),
++   OPCODE_PTR(LE),
++   OPCODE_PTR(TEST),
++   OPCODE_PTR(TESTSET),
++   OPCODE_PTR(CALL),
++   OPCODE_PTR(TAILCALL),
++   OPCODE_PTR(RETURN),
++   OPCODE_PTR(FORLOOP),
++   OPCODE_PTR(FORPREP),
++   OPCODE_PTR(TFORLOOP),
++   OPCODE_PTR(SETLIST),
++   OPCODE_PTR(CLOSE),
++   OPCODE_PTR(CLOSURE),
++   OPCODE_PTR(VARARG)
++  };
++#endif
+  reentry:  /* entry point */
+   lua_assert(isLua(L->ci));
+   pc = L->savedpc;
+@@ -596,33 +650,33 @@ void luaV_execute (lua_State *L, int nex
+     lua_assert(base == L->base && L->base == L->ci->base);
+     lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
+     lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
+-    switch (GET_OPCODE(i)) {
+-      case OP_MOVE: {
++    CALL_OPCODE(GET_OPCODE(i)) {
++      OPCODE_TARGET(MOVE) {
+         setobjs2s(L, ra, RB(i));
+         continue;
+       }
+-      case OP_LOADK: {
++      OPCODE_TARGET(LOADK) {
+         setobj2s(L, ra, KBx(i));
+         continue;
+       }
+-      case OP_LOADBOOL: {
++      OPCODE_TARGET(LOADBOOL) {
+         setbvalue(ra, GETARG_B(i));
+         if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
+         continue;
+       }
+-      case OP_LOADNIL: {
++      OPCODE_TARGET(LOADNIL) {
+         TValue *rb = RB(i);
+         do {
+           setnilvalue(rb--);
+         } while (rb >= ra);
+         continue;
+       }
+-      case OP_GETUPVAL: {
++      OPCODE_TARGET(GETUPVAL) {
+         int b = GETARG_B(i);
+         setobj2s(L, ra, cl->upvals[b]->v);
+         continue;
+       }
+-      case OP_GETGLOBAL: {
++      OPCODE_TARGET(GETGLOBAL) {
+         TValue g;
+         TValue *rb = KBx(i);
+         sethvalue(L, &g, cl->env);
+@@ -630,88 +684,88 @@ void luaV_execute (lua_State *L, int nex
+         Protect(luaV_gettable(L, &g, rb, ra));
+         continue;
+       }
+-      case OP_GETTABLE: {
++      OPCODE_TARGET(GETTABLE) {
+         Protect(luaV_gettable(L, RB(i), RKC(i), ra));
+         continue;
+       }
+-      case OP_SETGLOBAL: {
++      OPCODE_TARGET(SETGLOBAL) {
+         TValue g;
+         sethvalue(L, &g, cl->env);
+         lua_assert(ttisstring(KBx(i)));
+         Protect(luaV_settable(L, &g, KBx(i), ra));
+         continue;
+       }
+-      case OP_SETUPVAL: {
++      OPCODE_TARGET(SETUPVAL) {
+         UpVal *uv = cl->upvals[GETARG_B(i)];
+         setobj(L, uv->v, ra);
+         luaC_barrier(L, uv, ra);
+         continue;
+       }
+-      case OP_SETTABLE: {
++      OPCODE_TARGET(SETTABLE) {
+         Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
+         continue;
+       }
+-      case OP_NEWTABLE: {
++      OPCODE_TARGET(NEWTABLE) {
+         int b = GETARG_B(i);
+         int c = GETARG_C(i);
+         sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
+         Protect(luaC_checkGC(L));
+         continue;
+       }
+-      case OP_SELF: {
++      OPCODE_TARGET(SELF) {
+         StkId rb = RB(i);
+         setobjs2s(L, ra+1, rb);
+         Protect(luaV_gettable(L, rb, RKC(i), ra));
+         continue;
+       }
+-      case OP_ADD: {
++      OPCODE_TARGET(ADD) {
+         TValue *rb = RKB(i), *rc= RKC(i);
+         arith_op_continue( luai_numadd, try_addint, luai_vectadd );
+         Protect(Arith(L, ra, rb, rc, TM_ADD)); \
+         continue;
+       }
+-      case OP_SUB: {
++      OPCODE_TARGET(SUB) {
+         TValue *rb = RKB(i), *rc= RKC(i);
+         arith_op_continue( luai_numsub, try_subint, luai_vectsub );
+         Protect(Arith(L, ra, rb, rc, TM_SUB));
+         continue;
+       }
+-      case OP_MUL: {
++      OPCODE_TARGET(MUL) {
+         TValue *rb = RKB(i), *rc= RKC(i);
+         arith_op_continue(luai_nummul, try_mulint, luai_vectmul);
+         Protect(Arith(L, ra, rb, rc, TM_MUL));
+         continue;
+       }
+-      case OP_DIV: {
++      OPCODE_TARGET(DIV) {
+         TValue *rb = RKB(i), *rc= RKC(i);
+         arith_op_continue(luai_numdiv, try_divint, luai_vectdiv);
+         Protect(Arith(L, ra, rb, rc, TM_DIV));
+         continue;
+       }
+-      case OP_MOD: {
++      OPCODE_TARGET(MOD) {
+         TValue *rb = RKB(i), *rc= RKC(i);
+         arith_op_continue_scalar(luai_nummod, try_modint);  /* scalars only */
+         Protect(Arith(L, ra, rb, rc, TM_MOD));
+         continue;
+       }
+-      case OP_POW: {
++      OPCODE_TARGET(POW) {
+         TValue *rb = RKB(i), *rc= RKC(i);
+         arith_op_continue(luai_numpow, try_powint, luai_vectpow);
+         Protect(Arith(L, ra, rb, rc, TM_POW));
+         continue;
+       }
+-      case OP_UNM: {
++      OPCODE_TARGET(UNM) {
+         TValue *rb = RB(i);
+         arith_op1_continue(luai_numunm, try_unmint, luai_vectunm);
+         Protect(Arith(L, ra, rb, rb, TM_UNM));
+         continue;
+       }
+-      case OP_NOT: {
++      OPCODE_TARGET(NOT) {
+         int res = l_isfalse(RB(i));  /* next assignment may change this value */
+         setbvalue(ra, res);
+         continue;
+       }
+-      case OP_LEN: {
++      OPCODE_TARGET(LEN) {
+         const TValue *rb = RB(i);
+         switch (ttype(rb)) {
+           case LUA_TTABLE: {
+@@ -731,18 +785,18 @@ void luaV_execute (lua_State *L, int nex
+         }
+         continue;
+       }
+-      case OP_CONCAT: {
++      OPCODE_TARGET(CONCAT) {
+         int b = GETARG_B(i);
+         int c = GETARG_C(i);
+         Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
+         setobjs2s(L, RA(i), base+b);
+         continue;
+       }
+-      case OP_JMP: {
++      OPCODE_TARGET(JMP) {
+         dojump(L, pc, GETARG_sBx(i));
+         continue;
+       }
+-      case OP_EQ: {
++      OPCODE_TARGET(EQ) {
+         TValue *rb = RKB(i);
+         TValue *rc = RKC(i);
+         Protect(
+@@ -752,7 +806,7 @@ void luaV_execute (lua_State *L, int nex
+         pc++;
+         continue;
+       }
+-      case OP_LT: {
++      OPCODE_TARGET(LT) {
+         Protect(
+           if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
+             dojump(L, pc, GETARG_sBx(*pc));
+@@ -760,7 +814,7 @@ void luaV_execute (lua_State *L, int nex
+         pc++;
+         continue;
+       }
+-      case OP_LE: {
++      OPCODE_TARGET(LE) {
+         Protect(
+           if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
+             dojump(L, pc, GETARG_sBx(*pc));
+@@ -768,13 +822,13 @@ void luaV_execute (lua_State *L, int nex
+         pc++;
+         continue;
+       }
+-      case OP_TEST: {
++      OPCODE_TARGET(TEST) {
+         if (l_isfalse(ra) != GETARG_C(i))
+           dojump(L, pc, GETARG_sBx(*pc));
+         pc++;
+         continue;
+       }
+-      case OP_TESTSET: {
++      OPCODE_TARGET(TESTSET) {
+         TValue *rb = RB(i);
+         if (l_isfalse(rb) != GETARG_C(i)) {
+           setobjs2s(L, ra, rb);
+@@ -783,7 +837,7 @@ void luaV_execute (lua_State *L, int nex
+         pc++;
+         continue;
+       }
+-      case OP_CALL: {
++      OPCODE_TARGET(CALL) {
+         int b = GETARG_B(i);
+         int nresults = GETARG_C(i) - 1;
+         if (b != 0) L->top = ra+b;  /* else previous instruction set top */
+@@ -804,7 +858,7 @@ void luaV_execute (lua_State *L, int nex
+           }
+         }
+       }
+-      case OP_TAILCALL: {
++      OPCODE_TARGET(TAILCALL) {
+         int b = GETARG_B(i);
+         if (b != 0) L->top = ra+b;  /* else previous instruction set top */
+         L->savedpc = pc;
+@@ -836,7 +890,7 @@ void luaV_execute (lua_State *L, int nex
+           }
+         }
+       }
+-      case OP_RETURN: {
++      OPCODE_TARGET(RETURN) {
+         int b = GETARG_B(i);
+         if (b != 0) L->top = ra+b-1;
+         if (L->openupval) luaF_close(L, base);
+@@ -851,7 +905,7 @@ void luaV_execute (lua_State *L, int nex
+           goto reentry;
+         }
+       }
+-      case OP_FORLOOP: {
++      OPCODE_TARGET(FORLOOP) {
+         /* If start,step and limit are all integers, we don't need to check
+          * against overflow in the looping.
+          */
+@@ -879,7 +933,7 @@ void luaV_execute (lua_State *L, int nex
+         }
+         continue;
+       }
+-      case OP_FORPREP: {
++      OPCODE_TARGET(FORPREP) {
+         const TValue *init = ra;
+         const TValue *plimit = ra+1;
+         const TValue *pstep = ra+2;
+@@ -902,7 +956,7 @@ void luaV_execute (lua_State *L, int nex
+         dojump(L, pc, GETARG_sBx(i));
+         continue;
+       }
+-      case OP_TFORLOOP: {
++      OPCODE_TARGET(TFORLOOP) {
+         StkId cb = ra + 3;  /* call base */
+         setobjs2s(L, cb+2, ra+2);
+         setobjs2s(L, cb+1, ra+1);
+@@ -918,7 +972,7 @@ void luaV_execute (lua_State *L, int nex
+         pc++;
+         continue;
+       }
+-      case OP_SETLIST: {
++      OPCODE_TARGET(SETLIST) {
+         int n = GETARG_B(i);
+         int c = GETARG_C(i);
+         int last;
+@@ -940,11 +994,11 @@ void luaV_execute (lua_State *L, int nex
+         }
+         continue;
+       }
+-      case OP_CLOSE: {
++      OPCODE_TARGET(CLOSE) {
+         luaF_close(L, ra);
+         continue;
+       }
+-      case OP_CLOSURE: {
++      OPCODE_TARGET(CLOSURE) {
+         Proto *p;
+         Closure *ncl;
+         int nup, j;
+@@ -964,7 +1018,7 @@ void luaV_execute (lua_State *L, int nex
+         Protect(luaC_checkGC(L));
+         continue;
+       }
+-      case OP_VARARG: {
++      OPCODE_TARGET(VARARG) {
+         int b = GETARG_B(i) - 1;
+         int j;
+         CallInfo *ci = L->ci;
diff --git a/package/utils/mdadm/Makefile b/package/utils/mdadm/Makefile
new file mode 100644
index 0000000000..8980b846b5
--- /dev/null
+++ b/package/utils/mdadm/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2008-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mdadm
+PKG_VERSION:=3.2.5
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL:=@KERNEL/linux/utils/raid/mdadm
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MD5SUM:=2fd33dedcdb06f0d1461f50ddabb7e4a
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mdadm
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Disc
+  TITLE:=A tool for managing Soft RAID under Linux
+  URL:=http://www.kernel.org/pub/linux/utils/raid/mdadm/
+  DEPENDS:=+@KERNEL_DIRECT_IO
+endef
+
+define Package/mdadm/description
+ A tool for managing Linux Software RAID arrays.
+endef
+
+define Package/mdadm/conffiles
+/etc/mdadm.conf
+/etc/config/mdadm
+endef
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -DHAVE_STDINT_H" \
+		LDFLAGS="$(TARGET_LDFLAGS)" \
+		mdadm
+endef
+
+define Package/mdadm/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mdadm $(1)/sbin
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/mdadm.init $(1)/etc/init.d/mdadm
+	$(INSTALL_DIR) $(1)/etc/config
+	$(INSTALL_DATA) ./files/mdadm.config $(1)/etc/config/mdadm
+endef
+
+$(eval $(call BuildPackage,mdadm))
diff --git a/package/utils/mdadm/files/mdadm.config b/package/utils/mdadm/files/mdadm.config
new file mode 100644
index 0000000000..536228fae4
--- /dev/null
+++ b/package/utils/mdadm/files/mdadm.config
@@ -0,0 +1,3 @@
+config mdadm
+	option email root
+
diff --git a/package/utils/mdadm/files/mdadm.init b/package/utils/mdadm/files/mdadm.init
new file mode 100644
index 0000000000..9da4684fb1
--- /dev/null
+++ b/package/utils/mdadm/files/mdadm.init
@@ -0,0 +1,34 @@
+#!/bin/sh /etc/rc.common
+
+START=13
+STOP=98
+
+USE_PROCD=1
+PROG=/sbin/mdadm
+NAME=mdadm
+
+mdadm_email() {
+	local cfg="$1"
+	if [ ! -x /sbin/sendmail ]; then
+		return
+	fi
+	config_get email "$cfg" email
+}
+
+start_service() {
+	local email
+
+	config_load mdadm
+	config_foreach mdadm_email mdadm
+
+	$PROG --assemble --scan
+
+	procd_open_instance
+	procd_set_param command "$PROG" --monitor ${email:+--mail=$email} --syslog --scan
+	procd_close_instance
+}
+
+stop_service() {
+	$PROG --stop --scan
+}
+
diff --git a/package/utils/mdadm/patches/000-compile.patch b/package/utils/mdadm/patches/000-compile.patch
new file mode 100644
index 0000000000..6d47489163
--- /dev/null
+++ b/package/utils/mdadm/patches/000-compile.patch
@@ -0,0 +1,11 @@
+--- a/sha1.h
++++ b/sha1.h
+@@ -26,8 +26,6 @@
+ # include <limits.h>
+ #endif
+ 
+-#include "ansidecl.h"
+-
+ /* The following contortions are an attempt to use the C preprocessor
+    to determine an unsigned integral type that is 32 bits wide.  An
+    alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
diff --git a/package/utils/mdadm/patches/100-cross_compile.patch b/package/utils/mdadm/patches/100-cross_compile.patch
new file mode 100644
index 0000000000..8709e57816
--- /dev/null
+++ b/package/utils/mdadm/patches/100-cross_compile.patch
@@ -0,0 +1,19 @@
+--- a/Makefile
++++ b/Makefile
+@@ -76,7 +76,6 @@ FAILED_SLOTS_DIR = /run/mdadm/failed-slo
+ DIRFLAGS = -DMAP_DIR=\"$(MAP_DIR)\" -DMAP_FILE=\"$(MAP_FILE)\"
+ DIRFLAGS += -DMDMON_DIR=\"$(MDMON_DIR)\"
+ DIRFLAGS += -DFAILED_SLOTS_DIR=\"$(FAILED_SLOTS_DIR)\"
+-CFLAGS = $(CWFLAGS) $(CXFLAGS) -DSendmail=\""$(MAILCMD)"\" $(CONFFILEFLAGS) $(DIRFLAGS)
+ 
+ # The glibc TLS ABI requires applications that call clone(2) to set up
+ # TLS data structures, use pthreads until mdmon implements this support
+@@ -183,7 +182,7 @@ raid6check : raid6check.o mdadm.h $(CHEC
+ 
+ mdassemble : $(ASSEMBLE_SRCS) $(INCL)
+ 	rm -f $(OBJS)
+-	$(DIET_GCC) $(ASSEMBLE_FLAGS) -o mdassemble $(ASSEMBLE_SRCS)  $(STATICSRC)
++	$(CC) $(ASSEMBLE_FLAGS) -o mdassemble $(ASSEMBLE_SRCS)  $(STATICSRC)
+ 
+ mdassemble.static : $(ASSEMBLE_SRCS) $(INCL)
+ 	rm -f $(OBJS)
diff --git a/package/utils/mdadm/patches/200-reduce_size.patch b/package/utils/mdadm/patches/200-reduce_size.patch
new file mode 100644
index 0000000000..3d8c2f421c
--- /dev/null
+++ b/package/utils/mdadm/patches/200-reduce_size.patch
@@ -0,0 +1,25 @@
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -1508,6 +1508,10 @@ static int Incremental_container(struct 
+ 	if (ra_all == ra_blocked)
+ 		return 0;
+ 
++#ifndef MDADM_FULL
++	return 0;
++#endif
++
+ 	/* Now move all suitable spares from spare container */
+ 	domains = domain_from_array(list, st->ss->name);
+ 	memcpy(suuid, uuid_zero, sizeof(int[4]));
+--- a/util.c
++++ b/util.c
+@@ -928,7 +928,9 @@ void wait_for(char *dev, int fd)
+ struct superswitch *superlist[] =
+ {
+ 	&super0, &super1,
++#ifdef MDADM_FULL
+ 	&super_ddf, &super_imsm,
++#endif
+ 	&mbr, &gpt,
+ 	NULL };
+ 
diff --git a/package/utils/mtd-utils/Makefile b/package/utils/mtd-utils/Makefile
new file mode 100644
index 0000000000..70706fb7e9
--- /dev/null
+++ b/package/utils/mtd-utils/Makefile
@@ -0,0 +1,80 @@
+#
+# Copyright (C) 2009-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mtd-utils
+PKG_REV:=aea36417067dade75192bafa03af70b6eb2677b1
+PKG_VERSION:=1.5.2
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=git://git.infradead.org/mtd-utils.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=$(PKG_REV)
+PKG_MIRROR_MD5SUM:=e11b342b85a36b2e438a8412ec52f87621d3046aec1a93039f8c72de9990b2a7
+
+PKG_INSTALL:=1
+
+PKG_BUILD_DEPENDS:=util-linux liblzo zlib
+
+PKG_LICENSE:=GPLv2
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/mtd-utils/Default
+  SECTION:=utils
+  CATEGORY:=Utilities
+  URL:=http://www.linux-mtd.infradead.org/
+  DEPENDS:=@NAND_SUPPORT
+endef
+
+define Package/ubi-utils
+ $(call Package/mtd-utils/Default)
+  TITLE:=Utilities for ubi info/debug
+endef
+
+define Package/ubi-utils/description
+  Utilities for manipulating memory technology devices.
+endef
+
+define Package/nand-utils
+ $(call Package/mtd-utils/Default)
+  TITLE:=Utilities for nand flash read/write/test
+endef
+
+define Package/nand-utils/description
+  Utilities for NAND devices.
+endef
+
+MAKE_FLAGS += \
+	DESTDIR="$(PKG_INSTALL_DIR)" \
+	BUILDDIR="$(PKG_BUILD_DIR)" \
+	LDLIBS+="$(LIBGCC_S)" \
+	WITHOUT_XATTR=1 \
+	WITHOUT_LZO=1
+
+define Package/ubi-utils/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) \
+		$(PKG_INSTALL_DIR)/usr/sbin/{ubiattach,ubicrc32,ubiblock,ubidetach,ubiformat,ubimkvol} $(1)/usr/sbin/
+	$(INSTALL_BIN) \
+		$(PKG_INSTALL_DIR)/usr/sbin/{ubinfo,ubinize,ubirename,ubirmvol,ubirsvol,ubiupdatevol} $(1)/usr/sbin/
+endef
+
+define Package/nand-utils/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) \
+	$(PKG_INSTALL_DIR)/usr/sbin/{nanddump,nandwrite,nandtest,mtdinfo} $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,ubi-utils))
+$(eval $(call BuildPackage,nand-utils))
diff --git a/package/utils/mtd-utils/patches/010-fix-rpmatch.patch b/package/utils/mtd-utils/patches/010-fix-rpmatch.patch
new file mode 100644
index 0000000000..9d0de7f521
--- /dev/null
+++ b/package/utils/mtd-utils/patches/010-fix-rpmatch.patch
@@ -0,0 +1,19 @@
+--- a/include/common.h
++++ b/include/common.h
+@@ -137,10 +137,12 @@ static inline bool prompt(const char *ms
+ 		}
+ 
+ 		if (strcmp("\n", line) != 0) {
+-			switch (rpmatch(line)) {
+-			case 0: ret = false; break;
+-			case 1: ret = true; break;
+-			case -1:
++			switch (line[0]) {
++			case 'N':
++			case 'n': ret = false; break;
++			case 'Y':
++			case 'y': ret = true; break;
++			default:
+ 				puts("unknown response; please try again");
+ 				continue;
+ 			}
diff --git a/package/utils/mtd-utils/patches/100-fix_includes.patch b/package/utils/mtd-utils/patches/100-fix_includes.patch
new file mode 100644
index 0000000000..7dad28b472
--- /dev/null
+++ b/package/utils/mtd-utils/patches/100-fix_includes.patch
@@ -0,0 +1,10 @@
+--- a/lib/libfec.c
++++ b/lib/libfec.c
+@@ -45,6 +45,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <sys/types.h>
+ 
+ /*
+  * stuff used for testing purposes only
diff --git a/package/utils/mtd-utils/patches/130-lzma_jffs2.patch b/package/utils/mtd-utils/patches/130-lzma_jffs2.patch
new file mode 100644
index 0000000000..8c3794d769
--- /dev/null
+++ b/package/utils/mtd-utils/patches/130-lzma_jffs2.patch
@@ -0,0 +1,5029 @@
+--- a/Makefile
++++ b/Makefile
+@@ -3,7 +3,7 @@
+ 
+ VERSION = 1.5.1
+ 
+-CPPFLAGS += -D_GNU_SOURCE -I./include -I$(BUILDDIR)/include -I./ubi-utils/include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS)
++CPPFLAGS += -D_GNU_SOURCE -I./include -I$(BUILDDIR)/include -I./ubi-utils/include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS) -I./include/linux/lzma
+ 
+ ifeq ($(WITHOUT_XATTR), 1)
+   CPPFLAGS += -DWITHOUT_XATTR
+@@ -84,7 +84,7 @@ $(BUILDDIR)/include/version.h.tmp:
+ #
+ # Utils in top level
+ #
+-obj-mkfs.jffs2 = compr_rtime.o compr_zlib.o compr_lzo.o compr.o rbtree.o
++obj-mkfs.jffs2 = compr_rtime.o compr_zlib.o $(if $(WITHOUT_LZO),,compr_lzo.o) compr_lzma.o lzma/LzFind.o lzma/LzmaEnc.o lzma/LzmaDec.o compr.o rbtree.o
+ LDFLAGS_mkfs.jffs2 = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+ LDLIBS_mkfs.jffs2  = -lz $(LZOLDLIBS)
+ 
+--- a/compr.c
++++ b/compr.c
+@@ -520,6 +520,9 @@ int jffs2_compressors_init(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_init();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++	jffs2_lzma_init();
++#endif
+ 	return 0;
+ }
+ 
+@@ -534,5 +537,8 @@ int jffs2_compressors_exit(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_exit();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++	jffs2_lzma_exit();
++#endif
+ 	return 0;
+ }
+--- a/compr.h
++++ b/compr.h
+@@ -18,13 +18,14 @@
+ 
+ #define CONFIG_JFFS2_ZLIB
+ #define CONFIG_JFFS2_RTIME
+-#define CONFIG_JFFS2_LZO
++#define CONFIG_JFFS2_LZMA
+ 
+ #define JFFS2_RUBINMIPS_PRIORITY 10
+ #define JFFS2_DYNRUBIN_PRIORITY  20
+ #define JFFS2_RTIME_PRIORITY     50
+-#define JFFS2_ZLIB_PRIORITY      60
+-#define JFFS2_LZO_PRIORITY       80
++#define JFFS2_LZMA_PRIORITY      70
++#define JFFS2_ZLIB_PRIORITY      80
++#define JFFS2_LZO_PRIORITY       90
+ 
+ #define JFFS2_COMPR_MODE_NONE       0
+ #define JFFS2_COMPR_MODE_PRIORITY   1
+@@ -115,5 +116,10 @@ void jffs2_rtime_exit(void);
+ int jffs2_lzo_init(void);
+ void jffs2_lzo_exit(void);
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++int jffs2_lzma_init(void);
++void jffs2_lzma_exit(void);
++#endif
++
+ 
+ #endif /* __JFFS2_COMPR_H__ */
+--- /dev/null
++++ b/compr_lzma.c
+@@ -0,0 +1,128 @@
++/*
++ * JFFS2 -- Journalling Flash File System, Version 2.
++ *
++ * For licensing information, see the file 'LICENCE' in this directory.
++ *
++ * JFFS2 wrapper to the LZMA C SDK
++ *
++ */
++
++#include <linux/lzma.h>
++#include "compr.h"
++
++#ifdef __KERNEL__
++	static DEFINE_MUTEX(deflate_mutex);
++#endif
++
++CLzmaEncHandle *p;
++Byte propsEncoded[LZMA_PROPS_SIZE];
++SizeT propsSize = sizeof(propsEncoded);
++
++STATIC void lzma_free_workspace(void)
++{
++	LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
++}
++
++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
++{
++	if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
++	{
++		PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
++		return -ENOMEM;
++	}
++
++	if (LzmaEnc_SetProps(p, props) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++	
++	if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
++			      uint32_t *sourcelen, uint32_t *dstlen, void *model)
++{
++	SizeT compress_size = (SizeT)(*dstlen);
++	int ret;
++
++	#ifdef __KERNEL__
++		mutex_lock(&deflate_mutex);
++	#endif
++
++	ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
++		0, NULL, &lzma_alloc, &lzma_alloc);
++
++	#ifdef __KERNEL__
++		mutex_unlock(&deflate_mutex);
++	#endif
++
++	if (ret != SZ_OK)
++		return -1;
++
++	*dstlen = (uint32_t)compress_size;
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
++				 uint32_t srclen, uint32_t destlen, void *model)
++{
++	int ret;
++	SizeT dl = (SizeT)destlen;
++	SizeT sl = (SizeT)srclen;
++	ELzmaStatus status;
++	
++	ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
++		propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
++
++	if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
++		return -1;
++
++	return 0;
++}
++
++static struct jffs2_compressor jffs2_lzma_comp = {
++	.priority = JFFS2_LZMA_PRIORITY,
++	.name = "lzma",
++	.compr = JFFS2_COMPR_LZMA,
++	.compress = &jffs2_lzma_compress,
++	.decompress = &jffs2_lzma_decompress,
++	.disabled = 0,
++};
++
++int INIT jffs2_lzma_init(void)
++{
++	int ret;
++	CLzmaEncProps props;
++	LzmaEncProps_Init(&props);
++
++	props.dictSize = LZMA_BEST_DICT(0x2000);
++	props.level = LZMA_BEST_LEVEL;
++	props.lc = LZMA_BEST_LC;
++	props.lp = LZMA_BEST_LP;
++	props.pb = LZMA_BEST_PB;
++	props.fb = LZMA_BEST_FB;
++
++	ret = lzma_alloc_workspace(&props);
++	if (ret < 0)
++	return ret;
++
++	ret = jffs2_register_compressor(&jffs2_lzma_comp);
++	if (ret)
++		lzma_free_workspace();
++	
++	return ret;
++}
++
++void jffs2_lzma_exit(void)
++{
++	jffs2_unregister_compressor(&jffs2_lzma_comp);
++	lzma_free_workspace();
++}
+--- a/include/linux/jffs2.h
++++ b/include/linux/jffs2.h
+@@ -47,6 +47,7 @@
+ #define JFFS2_COMPR_DYNRUBIN	0x05
+ #define JFFS2_COMPR_ZLIB	0x06
+ #define JFFS2_COMPR_LZO		0x07
++#define JFFS2_COMPR_LZMA	0x08
+ /* Compatibility flags. */
+ #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+ #define JFFS2_NODE_ACCURATE 0x2000
+--- /dev/null
++++ b/include/linux/lzma.h
+@@ -0,0 +1,61 @@
++#ifndef __LZMA_H__
++#define __LZMA_H__
++
++#ifdef __KERNEL__
++	#include <linux/kernel.h>
++	#include <linux/sched.h>
++	#include <linux/slab.h>
++	#include <linux/vmalloc.h>
++	#include <linux/init.h>
++	#define LZMA_MALLOC vmalloc
++	#define LZMA_FREE vfree
++	#define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
++	#define INIT __init
++	#define STATIC static
++#else
++	#include <stdint.h>
++	#include <stdlib.h>
++	#include <stdio.h>
++	#include <unistd.h>
++	#include <string.h>
++	#include <errno.h>
++	#include <linux/jffs2.h>
++	#ifndef PAGE_SIZE
++		extern int page_size;
++		#define PAGE_SIZE page_size
++	#endif
++	#define LZMA_MALLOC malloc
++	#define LZMA_FREE free
++	#define PRINT_ERROR(msg) fprintf(stderr, msg)
++	#define INIT
++	#define STATIC
++#endif
++
++#include "lzma/LzmaDec.h"
++#include "lzma/LzmaEnc.h"
++
++#define LZMA_BEST_LEVEL (9)
++#define LZMA_BEST_LC    (0)
++#define LZMA_BEST_LP    (0)
++#define LZMA_BEST_PB    (0)
++#define LZMA_BEST_FB  (273)
++
++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
++
++static void *p_lzma_malloc(void *p, size_t size)
++{
++	if (size == 0)
++		return NULL;
++
++	return LZMA_MALLOC(size);
++}
++
++static void p_lzma_free(void *p, void *address)
++{
++	if (address != NULL)
++		LZMA_FREE(address);
++}
++
++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free};
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzFind.h
+@@ -0,0 +1,116 @@
++/* LzFind.h  -- Match finder for LZ algorithms
++2008-04-04
++Copyright (c) 1999-2008 Igor Pavlov
++You can use any of the following license options:
++  1) GNU Lesser General Public License (GNU LGPL)
++  2) Common Public License (CPL)
++  3) Common Development and Distribution License (CDDL) Version 1.0 
++  4) Igor Pavlov, as the author of this code, expressly permits you to 
++     statically or dynamically link your code (or bind by name) to this file, 
++     while you keep this file unmodified.
++*/
++
++#ifndef __LZFIND_H
++#define __LZFIND_H
++
++#include "Types.h"
++
++typedef UInt32 CLzRef;
++
++typedef struct _CMatchFinder
++{
++  Byte *buffer;
++  UInt32 pos;
++  UInt32 posLimit;
++  UInt32 streamPos;
++  UInt32 lenLimit;
++
++  UInt32 cyclicBufferPos;
++  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
++
++  UInt32 matchMaxLen;
++  CLzRef *hash;
++  CLzRef *son;
++  UInt32 hashMask;
++  UInt32 cutValue;
++
++  Byte *bufferBase;
++  ISeqInStream *stream;
++  int streamEndWasReached;
++
++  UInt32 blockSize;
++  UInt32 keepSizeBefore;
++  UInt32 keepSizeAfter;
++
++  UInt32 numHashBytes;
++  int directInput;
++  int btMode;
++  /* int skipModeBits; */
++  int bigHash;
++  UInt32 historySize;
++  UInt32 fixedHashSize;
++  UInt32 hashSizeSum;
++  UInt32 numSons;
++  SRes result;
++  UInt32 crc[256];
++} CMatchFinder;
++
++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
++
++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
++
++int MatchFinder_NeedMove(CMatchFinder *p);
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
++void MatchFinder_MoveBlock(CMatchFinder *p);
++void MatchFinder_ReadIfRequired(CMatchFinder *p);
++
++void MatchFinder_Construct(CMatchFinder *p);
++
++/* Conditions:
++     historySize <= 3 GB
++     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
++*/
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc);
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
++    UInt32 *distances, UInt32 maxLen);
++
++/* 
++Conditions:
++  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
++  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
++*/
++
++typedef void (*Mf_Init_Func)(void *object);
++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
++typedef void (*Mf_Skip_Func)(void *object, UInt32);
++
++typedef struct _IMatchFinder
++{
++  Mf_Init_Func Init;
++  Mf_GetIndexByte_Func GetIndexByte;
++  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
++  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
++  Mf_GetMatches_Func GetMatches;
++  Mf_Skip_Func Skip;
++} IMatchFinder;
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
++
++void MatchFinder_Init(CMatchFinder *p);
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzHash.h
+@@ -0,0 +1,56 @@
++/* LzHash.h  -- HASH functions for LZ algorithms
++2008-03-26
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzFind.h for license options */
++
++#ifndef __LZHASH_H
++#define __LZHASH_H
++
++#define kHash2Size (1 << 10)
++#define kHash3Size (1 << 16)
++#define kHash4Size (1 << 20)
++
++#define kFix3HashSize (kHash2Size)
++#define kFix4HashSize (kHash2Size + kHash3Size)
++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
++
++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
++
++#define HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
++
++#define HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
++
++#define HASH5_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
++  hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
++  hash4Value &= (kHash4Size - 1); }
++
++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
++
++
++#define MT_HASH2_CALC \
++  hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
++
++#define MT_HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
++
++#define MT_HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaDec.h
+@@ -0,0 +1,232 @@
++/* LzmaDec.h -- LZMA Decoder
++2008-04-29
++Copyright (c) 1999-2008 Igor Pavlov
++You can use any of the following license options:
++  1) GNU Lesser General Public License (GNU LGPL)
++  2) Common Public License (CPL)
++  3) Common Development and Distribution License (CDDL) Version 1.0 
++  4) Igor Pavlov, as the author of this code, expressly permits you to 
++     statically or dynamically link your code (or bind by name) to this file, 
++     while you keep this file unmodified.
++*/
++
++#ifndef __LZMADEC_H
++#define __LZMADEC_H
++
++#include "Types.h"
++
++/* #define _LZMA_PROB32 */
++/* _LZMA_PROB32 can increase the speed on some CPUs, 
++   but memory usage for CLzmaDec::probs will be doubled in that case */
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++
++/* ---------- LZMA Properties ---------- */  
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaProps
++{
++  unsigned lc, lp, pb;
++  UInt32 dicSize;
++} CLzmaProps;
++
++/* LzmaProps_Decode - decodes properties
++Returns:
++  SZ_OK
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
++
++
++/* ---------- LZMA Decoder state ---------- */  
++
++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
++   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
++
++#define LZMA_REQUIRED_INPUT_MAX 20
++
++typedef struct
++{
++  CLzmaProps prop;
++  CLzmaProb *probs;
++  Byte *dic;
++  const Byte *buf;
++  UInt32 range, code;
++  SizeT dicPos;
++  SizeT dicBufSize;
++  UInt32 processedPos;
++  UInt32 checkDicSize;
++  unsigned state;
++  UInt32 reps[4];
++  unsigned remainLen;
++  int needFlush;
++  int needInitState;
++  UInt32 numProbs;
++  unsigned tempBufSize;
++  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
++} CLzmaDec;
++
++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
++
++void LzmaDec_Init(CLzmaDec *p);
++
++/* There are two types of LZMA streams:
++     0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
++     1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
++
++typedef enum 
++{
++  LZMA_FINISH_ANY,   /* finish at any point */      
++  LZMA_FINISH_END    /* block must be finished at the end */
++} ELzmaFinishMode;
++
++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
++
++   You must use LZMA_FINISH_END, when you know that current output buffer 
++   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
++
++   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
++   and output value of destLen will be less than output buffer size limit.
++   You can check status result also.
++
++   You can use multiple checks to test data integrity after full decompression:
++     1) Check Result and "status" variable.
++     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
++     3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 
++        You must use correct finish mode in that case. */ 
++
++typedef enum 
++{
++  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
++  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
++  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
++  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */   
++  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
++} ELzmaStatus;
++
++/* ELzmaStatus is used only as output value for function call */
++
++
++/* ---------- Interfaces ---------- */  
++
++/* There are 3 levels of interfaces:
++     1) Dictionary Interface
++     2) Buffer Interface
++     3) One Call Interface
++   You can select any of these interfaces, but don't mix functions from different 
++   groups for same object. */
++
++
++/* There are two variants to allocate state for Dictionary Interface:
++     1) LzmaDec_Allocate / LzmaDec_Free
++     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
++   You can use variant 2, if you set dictionary buffer manually. 
++   For Buffer Interface you must always use variant 1. 
++
++LzmaDec_Allocate* can return:
++  SZ_OK
++  SZ_ERROR_MEM         - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++   
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
++
++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
++
++/* ---------- Dictionary Interface ---------- */  
++
++/* You can use it, if you want to eliminate the overhead for data copying from 
++   dictionary to some other external buffer.
++   You must work with CLzmaDec variables directly in this interface.
++
++   STEPS:
++     LzmaDec_Constr()
++     LzmaDec_Allocate()
++     for (each new stream)
++     {
++       LzmaDec_Init()
++       while (it needs more decompression)
++       {
++         LzmaDec_DecodeToDic()
++         use data from CLzmaDec::dic and update CLzmaDec::dicPos
++       }
++     }
++     LzmaDec_Free()
++*/
++
++/* LzmaDec_DecodeToDic
++   
++   The decoding to internal dictionary buffer (CLzmaDec::dic).
++   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! 
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (dicLimit).
++  LZMA_FINISH_ANY - Decode just dicLimit bytes.
++  LZMA_FINISH_END - Stream must be finished after dicLimit.
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED 
++      LZMA_STATUS_NEEDS_MORE_INPUT
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++*/
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, 
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- Buffer Interface ---------- */  
++
++/* It's zlib-like interface.
++   See LzmaDec_DecodeToDic description for information about STEPS and return results,
++   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
++   to work with CLzmaDec variables manually.
++
++finishMode: 
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++*/
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, 
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- One Call Interface ---------- */  
++
++/* LzmaDecode
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED 
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++  SZ_ERROR_MEM  - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
++*/
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 
++    ELzmaStatus *status, ISzAlloc *alloc);
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -0,0 +1,74 @@
++/*  LzmaEnc.h -- LZMA Encoder
++2008-04-27
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzFind.h for license options */
++
++#ifndef __LZMAENC_H
++#define __LZMAENC_H
++
++#include "Types.h"
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaEncProps
++{
++  int level;       /*  0 <= level <= 9 */ 
++  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
++                      (1 << 12) <= dictSize <= (1 << 30) for 64-bit version 
++                       default = (1 << 24) */
++  int lc;          /* 0 <= lc <= 8, default = 3 */ 
++  int lp;          /* 0 <= lp <= 4, default = 0 */ 
++  int pb;          /* 0 <= pb <= 4, default = 2 */ 
++  int algo;        /* 0 - fast, 1 - normal, default = 1 */
++  int fb;          /* 5 <= fb <= 273, default = 32 */
++  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
++  int numHashBytes; /* 2, 3 or 4, default = 4 */
++  UInt32 mc;        /* 1 <= mc <= (1 << 30), default = 32 */
++  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
++  int numThreads;  /* 1 or 2, default = 2 */
++} CLzmaEncProps;
++
++void LzmaEncProps_Init(CLzmaEncProps *p);
++void LzmaEncProps_Normalize(CLzmaEncProps *p);
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
++
++
++/* ---------- CLzmaEncHandle Interface ---------- */
++
++/* LzmaEnc_* functions can return the following exit codes:
++Returns:
++  SZ_OK           - OK
++  SZ_ERROR_MEM    - Memory allocation error 
++  SZ_ERROR_PARAM  - Incorrect paramater in props
++  SZ_ERROR_WRITE  - Write callback error.
++  SZ_ERROR_PROGRESS - some break from progress callback
++  SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
++*/
++
++typedef void * CLzmaEncHandle;
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, 
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaEncode
++Return code:
++  SZ_OK               - OK
++  SZ_ERROR_MEM        - Memory allocation error 
++  SZ_ERROR_PARAM      - Incorrect paramater
++  SZ_ERROR_OUTPUT_EOF - output buffer overflow
++  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
++*/
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, 
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/Types.h
+@@ -0,0 +1,130 @@
++/* Types.h -- Basic types
++2008-04-11
++Igor Pavlov
++Public domain */
++
++#ifndef __7Z_TYPES_H
++#define __7Z_TYPES_H
++
++#define SZ_OK 0
++
++#define SZ_ERROR_DATA 1
++#define SZ_ERROR_MEM 2
++#define SZ_ERROR_CRC 3
++#define SZ_ERROR_UNSUPPORTED 4
++#define SZ_ERROR_PARAM 5
++#define SZ_ERROR_INPUT_EOF 6
++#define SZ_ERROR_OUTPUT_EOF 7
++#define SZ_ERROR_READ 8
++#define SZ_ERROR_WRITE 9
++#define SZ_ERROR_PROGRESS 10
++#define SZ_ERROR_FAIL 11
++#define SZ_ERROR_THREAD 12
++
++#define SZ_ERROR_ARCHIVE 16
++#define SZ_ERROR_NO_ARCHIVE 17
++
++typedef int SRes;
++
++#ifndef RINOK
++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
++#endif
++
++typedef unsigned char Byte;
++typedef short Int16;
++typedef unsigned short UInt16;
++
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef long Int32;
++typedef unsigned long UInt32;
++#else
++typedef int Int32;
++typedef unsigned int UInt32;
++#endif
++
++/* #define _SZ_NO_INT_64 */
++/* define it if your compiler doesn't support 64-bit integers */
++
++#ifdef _SZ_NO_INT_64
++
++typedef long Int64;
++typedef unsigned long UInt64;
++
++#else
++
++#if defined(_MSC_VER) || defined(__BORLANDC__)
++typedef __int64 Int64;
++typedef unsigned __int64 UInt64;
++#else
++typedef long long int Int64;
++typedef unsigned long long int UInt64;
++#endif
++
++#endif
++
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++#include <stddef.h>
++typedef size_t SizeT;
++#endif
++
++typedef int Bool;
++#define True 1
++#define False 0
++
++
++#ifdef _MSC_VER
++
++#if _MSC_VER >= 1300
++#define MY_NO_INLINE __declspec(noinline)
++#else
++#define MY_NO_INLINE
++#endif
++
++#define MY_CDECL __cdecl
++#define MY_STD_CALL __stdcall 
++#define MY_FAST_CALL MY_NO_INLINE __fastcall 
++
++#else
++
++#define MY_CDECL
++#define MY_STD_CALL
++#define MY_FAST_CALL
++
++#endif
++
++
++/* The following interfaces use first parameter as pointer to structure */
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) < input(*size)) is allowed */
++} ISeqInStream;
++
++typedef struct
++{
++  size_t (*Write)(void *p, const void *buf, size_t size);
++    /* Returns: result - the number of actually written bytes.
++      (result < size) means error */
++} ISeqOutStream;
++
++typedef struct
++{
++  SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
++    /* Returns: result. (result != SZ_OK) means break.
++       Value (UInt64)(Int64)-1 for size means unknown value. */
++} ICompressProgress;
++
++typedef struct
++{
++  void *(*Alloc)(void *p, size_t size);
++  void (*Free)(void *p, void *address); /* address can be 0 */
++} ISzAlloc;
++
++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
++#define IAlloc_Free(p, a) (p)->Free((p), a)
++
++#endif
+--- /dev/null
++++ b/lzma/LzFind.c
+@@ -0,0 +1,753 @@
++/* LzFind.c  -- Match finder for LZ algorithms
++2008-04-04
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzFind.h for license options */
++
++#include <string.h>
++
++#include "LzFind.h"
++#include "LzHash.h"
++
++#define kEmptyHashValue 0
++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
++#define kNormalizeMask (~(kNormalizeStepMin - 1))
++#define kMaxHistorySize ((UInt32)3 << 30)
++
++#define kStartMaxLen 3
++
++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  if (!p->directInput)
++  {
++    alloc->Free(alloc, p->bufferBase);
++    p->bufferBase = 0;
++  }
++}
++
++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
++
++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
++{
++  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
++  if (p->directInput)
++  {
++    p->blockSize = blockSize;
++    return 1;
++  }
++  if (p->bufferBase == 0 || p->blockSize != blockSize)
++  {
++    LzInWindow_Free(p, alloc);
++    p->blockSize = blockSize;
++    p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
++  }
++  return (p->bufferBase != 0);
++}
++
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++
++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++{
++  p->posLimit -= subValue;
++  p->pos -= subValue;
++  p->streamPos -= subValue;
++}
++
++static void MatchFinder_ReadBlock(CMatchFinder *p)
++{
++  if (p->streamEndWasReached || p->result != SZ_OK)
++    return;
++  for (;;)
++  {
++    Byte *dest = p->buffer + (p->streamPos - p->pos);
++    size_t size = (p->bufferBase + p->blockSize - dest);
++    if (size == 0)
++      return;
++    p->result = p->stream->Read(p->stream, dest, &size);
++    if (p->result != SZ_OK)
++      return;
++    if (size == 0)
++    {
++      p->streamEndWasReached = 1;
++      return;
++    }
++    p->streamPos += (UInt32)size;
++    if (p->streamPos - p->pos > p->keepSizeAfter)
++      return;
++  }
++}
++
++void MatchFinder_MoveBlock(CMatchFinder *p)
++{
++  memmove(p->bufferBase, 
++    p->buffer - p->keepSizeBefore, 
++    (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
++  p->buffer = p->bufferBase + p->keepSizeBefore;
++}
++
++int MatchFinder_NeedMove(CMatchFinder *p)
++{
++  /* if (p->streamEndWasReached) return 0; */
++  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
++}
++
++void MatchFinder_ReadIfRequired(CMatchFinder *p)
++{
++  if (p->streamEndWasReached) 
++    return;
++  if (p->keepSizeAfter >= p->streamPos - p->pos)
++    MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
++{
++  if (MatchFinder_NeedMove(p))
++    MatchFinder_MoveBlock(p);
++  MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
++{
++  p->cutValue = 32;
++  p->btMode = 1;
++  p->numHashBytes = 4;
++  /* p->skipModeBits = 0; */
++  p->directInput = 0;
++  p->bigHash = 0;
++}
++
++#define kCrcPoly 0xEDB88320
++
++void MatchFinder_Construct(CMatchFinder *p)
++{
++  UInt32 i;
++  p->bufferBase = 0;
++  p->directInput = 0;
++  p->hash = 0;
++  MatchFinder_SetDefaultSettings(p);
++
++  for (i = 0; i < 256; i++)
++  {
++    UInt32 r = i;
++    int j;
++    for (j = 0; j < 8; j++)
++      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
++    p->crc[i] = r;
++  }
++}
++
++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->hash);
++  p->hash = 0;
++}
++
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  MatchFinder_FreeThisClassMemory(p, alloc);
++  LzInWindow_Free(p, alloc);
++}
++
++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
++{
++  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
++  if (sizeInBytes / sizeof(CLzRef) != num)
++    return 0;
++  return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
++}
++
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc)
++{
++  UInt32 sizeReserv;
++  if (historySize > kMaxHistorySize)
++  {
++    MatchFinder_Free(p, alloc);
++    return 0;
++  }
++  sizeReserv = historySize >> 1;
++  if (historySize > ((UInt32)2 << 30))
++    sizeReserv = historySize >> 2;
++  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
++
++  p->keepSizeBefore = historySize + keepAddBufferBefore + 1; 
++  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
++  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
++  if (LzInWindow_Create(p, sizeReserv, alloc))
++  {
++    UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
++    UInt32 hs;
++    p->matchMaxLen = matchMaxLen;
++    {
++      p->fixedHashSize = 0;
++      if (p->numHashBytes == 2)
++        hs = (1 << 16) - 1;
++      else
++      {
++        hs = historySize - 1;
++        hs |= (hs >> 1);
++        hs |= (hs >> 2);
++        hs |= (hs >> 4);
++        hs |= (hs >> 8);
++        hs >>= 1;
++        /* hs >>= p->skipModeBits; */
++        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
++        if (hs > (1 << 24))
++        {
++          if (p->numHashBytes == 3)
++            hs = (1 << 24) - 1;
++          else
++            hs >>= 1;
++        }
++      }
++      p->hashMask = hs;
++      hs++;
++      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
++      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
++      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
++      hs += p->fixedHashSize;
++    }
++
++    {
++      UInt32 prevSize = p->hashSizeSum + p->numSons;
++      UInt32 newSize;
++      p->historySize = historySize;
++      p->hashSizeSum = hs;
++      p->cyclicBufferSize = newCyclicBufferSize;
++      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
++      newSize = p->hashSizeSum + p->numSons;
++      if (p->hash != 0 && prevSize == newSize)
++        return 1;
++      MatchFinder_FreeThisClassMemory(p, alloc);
++      p->hash = AllocRefs(newSize, alloc);
++      if (p->hash != 0)
++      {
++        p->son = p->hash + p->hashSizeSum;
++        return 1;
++      }
++    }
++  }
++  MatchFinder_Free(p, alloc);
++  return 0;
++}
++
++static void MatchFinder_SetLimits(CMatchFinder *p)
++{
++  UInt32 limit = kMaxValForNormalize - p->pos;
++  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
++  if (limit2 < limit) 
++    limit = limit2;
++  limit2 = p->streamPos - p->pos;
++  if (limit2 <= p->keepSizeAfter)
++  {
++    if (limit2 > 0)
++      limit2 = 1;
++  }
++  else
++    limit2 -= p->keepSizeAfter;
++  if (limit2 < limit) 
++    limit = limit2;
++  {
++    UInt32 lenLimit = p->streamPos - p->pos;
++    if (lenLimit > p->matchMaxLen)
++      lenLimit = p->matchMaxLen;
++    p->lenLimit = lenLimit;
++  }
++  p->posLimit = p->pos + limit;
++}
++
++void MatchFinder_Init(CMatchFinder *p)
++{
++  UInt32 i;
++  for(i = 0; i < p->hashSizeSum; i++)
++    p->hash[i] = kEmptyHashValue;
++  p->cyclicBufferPos = 0;
++  p->buffer = p->bufferBase;
++  p->pos = p->streamPos = p->cyclicBufferSize;
++  p->result = SZ_OK;
++  p->streamEndWasReached = 0;
++  MatchFinder_ReadBlock(p);
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) 
++{ 
++  return (p->pos - p->historySize - 1) & kNormalizeMask; 
++}
++
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++{
++  UInt32 i;
++  for (i = 0; i < numItems; i++)
++  {
++    UInt32 value = items[i];
++    if (value <= subValue)
++      value = kEmptyHashValue;
++    else
++      value -= subValue;
++    items[i] = value;
++  }
++}
++
++static void MatchFinder_Normalize(CMatchFinder *p)
++{
++  UInt32 subValue = MatchFinder_GetSubValue(p);
++  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
++  MatchFinder_ReduceOffsets(p, subValue);
++}
++
++static void MatchFinder_CheckLimits(CMatchFinder *p)
++{
++  if (p->pos == kMaxValForNormalize)
++    MatchFinder_Normalize(p);
++  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
++    MatchFinder_CheckAndMoveAndRead(p);
++  if (p->cyclicBufferPos == p->cyclicBufferSize)
++    p->cyclicBufferPos = 0;
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
++    UInt32 *distances, UInt32 maxLen)
++{
++  son[_cyclicBufferPos] = curMatch;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++      return distances;
++    {
++      const Byte *pb = cur - delta;
++      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
++      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
++      {
++        UInt32 len = 0;
++        while(++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++            return distances;
++        }
++      }
++    }
++  }
++}
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
++    UInt32 *distances, UInt32 maxLen)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return distances;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        if (++len != lenLimit && pb[len] == cur[len])
++          while(++len != lenLimit)
++            if (pb[len] != cur[len])
++              break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return distances;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        while(++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        {
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++#define MOVE_POS \
++  ++p->cyclicBufferPos; \
++  p->buffer++; \
++  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
++
++#define MOVE_POS_RET MOVE_POS return offset;
++
++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
++
++#define GET_MATCHES_HEADER2(minLen, ret_op) \
++  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
++  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
++  cur = p->buffer;
++
++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
++#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
++
++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
++
++#define GET_MATCHES_FOOTER(offset, maxLen) \
++  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
++  distances + offset, maxLen) - distances); MOVE_POS_RET;
++
++#define SKIP_FOOTER \
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
++
++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(2)
++  HASH2_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 1)
++}
++
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 2)
++}
++
++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, delta2, maxLen, offset;
++  GET_MATCHES_HEADER(3)
++
++  HASH3_CALC;
++
++  delta2 = p->pos - p->hash[hash2Value];
++  curMatch = p->hash[kFix3HashSize + hashValue];
++  
++  p->hash[hash2Value] = 
++  p->hash[kFix3HashSize + hashValue] = p->pos;
++
++
++  maxLen = 2;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[0] = maxLen;
++    distances[1] = delta2 - 1;
++    offset = 2;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET; 
++    }
++  }
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++  
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET; 
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      p->son[p->cyclicBufferPos] = curMatch;
++      MOVE_POS_RET; 
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances + offset, maxLen) - (distances));
++  MOVE_POS_RET
++}
++
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances, 2) - (distances));
++  MOVE_POS_RET
++}
++
++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(2) 
++    HASH2_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value;
++    SKIP_HEADER(3)
++    HASH3_CALC;
++    curMatch = p->hash[kFix3HashSize + hashValue];
++    p->hash[hash2Value] =
++    p->hash[kFix3HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4) 
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] = p->pos;
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] =
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
++{
++  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
++  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
++  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
++  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
++  if (!p->btMode)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 2)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 3)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
++  }
++  else
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
++  }
++}
+--- /dev/null
++++ b/lzma/LzmaDec.c
+@@ -0,0 +1,1014 @@
++/* LzmaDec.c -- LZMA Decoder
++2008-04-29
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzmaDec.h for license options */
++
++#include "LzmaDec.h"
++
++#include <string.h>
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_INIT_SIZE 5
++
++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
++  { UPDATE_0(p); i = (i + i); A0; } else \
++  { UPDATE_1(p); i = (i + i) + 1; A1; } 
++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)               
++
++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
++#define TREE_DECODE(probs, limit, i) \
++  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
++
++/* #define _LZMA_SIZE_OPT */
++
++#ifdef _LZMA_SIZE_OPT
++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
++#else
++#define TREE_6_DECODE(probs, i) \
++  { i = 1; \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  i -= 0x40; }
++#endif
++
++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0_CHECK range = bound;
++#define UPDATE_1_CHECK range -= bound; code -= bound;
++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
++  { UPDATE_0_CHECK; i = (i + i); A0; } else \
++  { UPDATE_1_CHECK; i = (i + i) + 1; A1; } 
++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)               
++#define TREE_DECODE_CHECK(probs, limit, i) \
++  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while(i < limit); i -= limit; }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++/*
++#define LZMA_STREAM_WAS_FINISHED_ID (-1)
++#define LZMA_SPEC_LEN_OFFSET (-3)
++*/
++
++Byte kLiteralNextStates[kNumStates * 2] = 
++{
++  0, 0, 0, 0, 1, 2, 3,  4,  5,  6,  4,  5, 
++  7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10
++};
++
++#define LZMA_DIC_MIN (1 << 12)
++
++/* First LZMA-symbol is always decoded. 
++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization 
++Out:
++  Result:
++    0 - OK
++    1 - Error
++  p->remainLen:
++    < kMatchSpecLenStart : normal remain
++    = kMatchSpecLenStart : finished
++    = kMatchSpecLenStart + 1 : Flush marker
++    = kMatchSpecLenStart + 2 : State Init Marker
++*/
++
++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  CLzmaProb *probs = p->probs;
++
++  unsigned state = p->state;
++  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
++  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
++  unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
++  unsigned lc = p->prop.lc;
++
++  Byte *dic = p->dic;
++  SizeT dicBufSize = p->dicBufSize;
++  SizeT dicPos = p->dicPos;
++  
++  UInt32 processedPos = p->processedPos;
++  UInt32 checkDicSize = p->checkDicSize;
++  unsigned len = 0;
++
++  const Byte *buf = p->buf;
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++
++  do
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = processedPos & pbMask;
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0(prob)
++    {
++      unsigned symbol;
++      UPDATE_0(prob);
++      prob = probs + Literal;
++      if (checkDicSize != 0 || processedPos != 0)
++        prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + 
++        (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
++
++      if (state < kNumLitStates)
++      {
++        symbol = 1;
++        do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++        unsigned offs = 0x100;
++        symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      dic[dicPos++] = (Byte)symbol;
++      processedPos++;
++
++      state = kLiteralNextStates[state];
++      /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */
++      continue;
++    }
++    else             
++    {
++      UPDATE_1(prob);
++      prob = probs + IsRep + state;
++      IF_BIT_0(prob)
++      {
++        UPDATE_0(prob);
++        state += kNumStates;
++        prob = probs + LenCoder;
++      }
++      else
++      {
++        UPDATE_1(prob);
++        if (checkDicSize == 0 && processedPos == 0)
++          return SZ_ERROR_DATA;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0(prob)
++        {
++          UPDATE_0(prob);
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++            dicPos++;
++            processedPos++;
++            state = state < kNumLitStates ? 9 : 11;
++            continue;
++          }
++          UPDATE_1(prob);
++        }
++        else
++        {
++          UInt32 distance;
++          UPDATE_1(prob);
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            distance = rep1;
++          }
++          else 
++          {
++            UPDATE_1(prob);
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0(prob)
++            {
++              UPDATE_0(prob);
++              distance = rep2;
++            }
++            else
++            {
++              UPDATE_1(prob);
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        state = state < kNumLitStates ? 8 : 11;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0(probLen)
++        {
++          UPDATE_0(probLen);
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = (1 << kLenNumLowBits);
++        }
++        else
++        {
++          UPDATE_1(probLen);
++          probLen = prob + LenChoice2;
++          IF_BIT_0(probLen)
++          {
++            UPDATE_0(probLen);
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = (1 << kLenNumMidBits);
++          }
++          else
++          {
++            UPDATE_1(probLen);
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = (1 << kLenNumHighBits);
++          }
++        }
++        TREE_DECODE(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state >= kNumStates)
++      {
++        UInt32 distance;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
++        TREE_6_DECODE(prob, distance);
++        if (distance >= kStartPosModelIndex)
++        {
++          unsigned posSlot = (unsigned)distance; 
++          int numDirectBits = (int)(((distance >> 1) - 1));
++          distance = (2 | (distance & 1));
++          if (posSlot < kEndPosModelIndex)
++          {
++            distance <<= numDirectBits;
++            prob = probs + SpecPos + distance - posSlot - 1;
++            {
++              UInt32 mask = 1;
++              unsigned i = 1;
++              do
++              {
++                GET_BIT2(prob + i, i, ; , distance |= mask);
++                mask <<= 1;
++              }
++              while(--numDirectBits != 0);
++            }
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE
++              range >>= 1;
++              
++              {
++                UInt32 t;
++                code -= range;
++                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
++                distance = (distance << 1) + (t + 1);
++                code += range & t;
++              }
++              /*
++              distance <<= 1;
++              if (code >= range)
++              {
++                code -= range;
++                distance |= 1;
++              }
++              */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            distance <<= kNumAlignBits;
++            {
++              unsigned i = 1;
++              GET_BIT2(prob + i, i, ; , distance |= 1);
++              GET_BIT2(prob + i, i, ; , distance |= 2);
++              GET_BIT2(prob + i, i, ; , distance |= 4);
++              GET_BIT2(prob + i, i, ; , distance |= 8);
++            }
++            if (distance == (UInt32)0xFFFFFFFF)
++            {
++              len += kMatchSpecLenStart;
++              state -= kNumStates;
++              break;
++            }
++          }
++        }
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        rep0 = distance + 1; 
++        if (checkDicSize == 0)
++        {
++          if (distance >= processedPos)
++            return SZ_ERROR_DATA;
++        }
++        else if (distance >= checkDicSize)
++          return SZ_ERROR_DATA;
++        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
++        /* state = kLiteralNextStates[state]; */
++      }
++
++      len += kMatchMinLen;
++
++      {
++        SizeT rem = limit - dicPos;
++        unsigned curLen = ((rem < len) ? (unsigned)rem : len);
++        SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
++
++        processedPos += curLen;
++
++        len -= curLen;
++        if (pos + curLen <= dicBufSize)
++        {
++          Byte *dest = dic + dicPos;
++          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
++          const Byte *lim = dest + curLen;
++          dicPos += curLen;
++          do 
++            *(dest) = (Byte)*(dest + src); 
++          while (++dest != lim);
++        }
++        else
++        {
++          do
++          {
++            dic[dicPos++] = dic[pos];
++            if (++pos == dicBufSize)
++              pos = 0;
++          }
++          while (--curLen != 0);
++        }
++      }
++    }
++  }
++  while (dicPos < limit && buf < bufLimit);
++  NORMALIZE;
++  p->buf = buf;
++  p->range = range;
++  p->code = code;
++  p->remainLen = len;
++  p->dicPos = dicPos;
++  p->processedPos = processedPos;
++  p->reps[0] = rep0;
++  p->reps[1] = rep1;
++  p->reps[2] = rep2;
++  p->reps[3] = rep3;
++  p->state = state;
++
++  return SZ_OK;
++}
++
++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
++{
++  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
++  {
++    Byte *dic = p->dic;
++    SizeT dicPos = p->dicPos;
++    SizeT dicBufSize = p->dicBufSize;
++    unsigned len = p->remainLen;
++    UInt32 rep0 = p->reps[0];
++    if (limit - dicPos < len)
++      len = (unsigned)(limit - dicPos);
++
++    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
++      p->checkDicSize = p->prop.dicSize;
++
++    p->processedPos += len;
++    p->remainLen -= len;
++    while (len-- != 0)
++    {
++      dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++      dicPos++;
++    }
++    p->dicPos = dicPos;
++  }
++}
++
++/* LzmaDec_DecodeReal2 decodes LZMA-symbols and sets p->needFlush and p->needInit, if required. */
++
++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  do
++  {
++    SizeT limit2 = limit;
++    if (p->checkDicSize == 0)
++    {
++      UInt32 rem = p->prop.dicSize - p->processedPos;
++      if (limit - p->dicPos > rem)
++        limit2 = p->dicPos + rem;
++    }
++    RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
++    if (p->processedPos >= p->prop.dicSize)
++      p->checkDicSize = p->prop.dicSize;
++    LzmaDec_WriteRem(p, limit);
++  }
++  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
++
++  if (p->remainLen > kMatchSpecLenStart)
++  {
++    p->remainLen = kMatchSpecLenStart;
++  }
++  return 0;
++}
++
++typedef enum 
++{
++  DUMMY_ERROR, /* unexpected end of input stream */
++  DUMMY_LIT,
++  DUMMY_MATCH,
++  DUMMY_REP
++} ELzmaDummy;
++
++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
++{
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++  const Byte *bufLimit = buf + inSize;
++  CLzmaProb *probs = p->probs;
++  unsigned state = p->state;
++  ELzmaDummy res;
++
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0_CHECK(prob)
++    {
++      UPDATE_0_CHECK
++
++      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
++
++      prob = probs + Literal;
++      if (p->checkDicSize != 0 || p->processedPos != 0)
++        prob += (LZMA_LIT_SIZE * 
++          ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + 
++          (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
++
++      if (state < kNumLitStates)
++      {
++        unsigned symbol = 1;
++        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[p->dicPos - p->reps[0] + 
++            ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
++        unsigned offs = 0x100;
++        unsigned symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      res = DUMMY_LIT;
++    }
++    else             
++    {
++      unsigned len;
++      UPDATE_1_CHECK;
++
++      prob = probs + IsRep + state;
++      IF_BIT_0_CHECK(prob)
++      {
++        UPDATE_0_CHECK;
++        state = 0;
++        prob = probs + LenCoder;
++        res = DUMMY_MATCH;
++      }
++      else
++      {
++        UPDATE_1_CHECK;
++        res = DUMMY_REP;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0_CHECK(prob)
++        {
++          UPDATE_0_CHECK;
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++            NORMALIZE_CHECK;
++            return DUMMY_REP;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++          }
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++          }
++          else 
++          {
++            UPDATE_1_CHECK;
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0_CHECK(prob)
++            {
++              UPDATE_0_CHECK;
++            }
++            else
++            {
++              UPDATE_1_CHECK;
++            }
++          }
++        }
++        state = kNumStates;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0_CHECK(probLen)
++        {
++          UPDATE_0_CHECK;
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = 1 << kLenNumLowBits;
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          probLen = prob + LenChoice2;
++          IF_BIT_0_CHECK(probLen)
++          {
++            UPDATE_0_CHECK;
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = 1 << kLenNumMidBits;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = 1 << kLenNumHighBits;
++          }
++        }
++        TREE_DECODE_CHECK(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state < 4)
++      {
++        unsigned posSlot;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
++            kNumPosSlotBits);
++        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++
++          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
++
++          if (posSlot < kEndPosModelIndex)
++          {
++            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE_CHECK
++              range >>= 1;
++              code -= range & (((code - range) >> 31) - 1);
++              /* if (code >= range) code -= range; */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            numDirectBits = kNumAlignBits;
++          }
++          {
++            unsigned i = 1;
++            do
++            {
++              GET_BIT_CHECK(prob + i, i);
++            }
++            while(--numDirectBits != 0);
++          }
++        }
++      }
++    }
++  }
++  NORMALIZE_CHECK;
++  return res;
++}
++
++
++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
++{
++  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->range = 0xFFFFFFFF;
++  p->needFlush = 0;
++}
++
++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) 
++{ 
++  p->needFlush = 1; 
++  p->remainLen = 0; 
++  p->tempBufSize = 0; 
++
++  if (initDic)
++  {
++    p->processedPos = 0;
++    p->checkDicSize = 0;
++    p->needInitState = 1;
++  }
++  if (initState)
++    p->needInitState = 1;
++}
++
++void LzmaDec_Init(CLzmaDec *p) 
++{ 
++  p->dicPos = 0; 
++  LzmaDec_InitDicAndState(p, True, True);
++}
++
++static void LzmaDec_InitStateReal(CLzmaDec *p)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
++  UInt32 i;
++  CLzmaProb *probs = p->probs;
++  for (i = 0; i < numProbs; i++)
++    probs[i] = kBitModelTotal >> 1; 
++  p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
++  p->state = 0;
++  p->needInitState = 0;
++}
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, 
++    ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT inSize = *srcLen;
++  (*srcLen) = 0;
++  LzmaDec_WriteRem(p, dicLimit);
++  
++  *status = LZMA_STATUS_NOT_SPECIFIED;
++
++  while (p->remainLen != kMatchSpecLenStart)
++  {
++      int checkEndMarkNow;
++
++      if (p->needFlush != 0)
++      {
++        for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
++          p->tempBuf[p->tempBufSize++] = *src++;
++        if (p->tempBufSize < RC_INIT_SIZE)
++        {
++          *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++          return SZ_OK;
++        }
++        if (p->tempBuf[0] != 0)
++          return SZ_ERROR_DATA;
++
++        LzmaDec_InitRc(p, p->tempBuf);
++        p->tempBufSize = 0;
++      }
++
++      checkEndMarkNow = 0;
++      if (p->dicPos >= dicLimit)
++      {
++        if (p->remainLen == 0 && p->code == 0)
++        {
++          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
++          return SZ_OK;
++        }
++        if (finishMode == LZMA_FINISH_ANY)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_OK;
++        }
++        if (p->remainLen != 0)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_ERROR_DATA;
++        }
++        checkEndMarkNow = 1;
++      }
++
++      if (p->needInitState)
++        LzmaDec_InitStateReal(p);
++  
++      if (p->tempBufSize == 0)
++      {
++        SizeT processed;
++        const Byte *bufLimit;
++        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            memcpy(p->tempBuf, src, inSize);
++            p->tempBufSize = (unsigned)inSize;
++            (*srcLen) += inSize;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++          bufLimit = src;
++        }
++        else
++          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
++        p->buf = src;
++        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
++          return SZ_ERROR_DATA;
++        processed = p->buf - src;
++        (*srcLen) += processed;
++        src += processed;
++        inSize -= processed;
++      }
++      else
++      {
++        unsigned rem = p->tempBufSize, lookAhead = 0;
++        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
++          p->tempBuf[rem++] = src[lookAhead++];
++        p->tempBufSize = rem;
++        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            (*srcLen) += lookAhead;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++        }
++        p->buf = p->tempBuf;
++        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
++          return SZ_ERROR_DATA;
++        lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
++        (*srcLen) += lookAhead;
++        src += lookAhead;
++        inSize -= lookAhead;
++        p->tempBufSize = 0;
++      }
++  }
++  if (p->code == 0) 
++    *status = LZMA_STATUS_FINISHED_WITH_MARK;
++  return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
++}
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT outSize = *destLen;
++  SizeT inSize = *srcLen;
++  *srcLen = *destLen = 0;
++  for (;;)
++  {
++    SizeT inSizeCur = inSize, outSizeCur, dicPos;
++    ELzmaFinishMode curFinishMode;
++    SRes res;
++    if (p->dicPos == p->dicBufSize)
++      p->dicPos = 0;
++    dicPos = p->dicPos;
++    if (outSize > p->dicBufSize - dicPos)
++    {
++      outSizeCur = p->dicBufSize;
++      curFinishMode = LZMA_FINISH_ANY;
++    }
++    else
++    {
++      outSizeCur = dicPos + outSize;
++      curFinishMode = finishMode;
++    }
++
++    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
++    src += inSizeCur;
++    inSize -= inSizeCur;
++    *srcLen += inSizeCur;
++    outSizeCur = p->dicPos - dicPos;
++    memcpy(dest, p->dic + dicPos, outSizeCur);
++    dest += outSizeCur;
++    outSize -= outSizeCur;
++    *destLen += outSizeCur;
++    if (res != 0)
++      return res;
++    if (outSizeCur == 0 || outSize == 0)
++      return SZ_OK;
++  }
++}
++
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) 
++{ 
++  alloc->Free(alloc, p->probs);  
++  p->probs = 0; 
++}
++
++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) 
++{ 
++  alloc->Free(alloc, p->dic); 
++  p->dic = 0; 
++}
++
++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
++{
++  LzmaDec_FreeProbs(p, alloc);
++  LzmaDec_FreeDict(p, alloc);
++}
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++{
++  UInt32 dicSize; 
++  Byte d;
++  
++  if (size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_UNSUPPORTED;
++  else
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++ 
++  if (dicSize < LZMA_DIC_MIN)
++    dicSize = LZMA_DIC_MIN;
++  p->dicSize = dicSize;
++
++  d = data[0];
++  if (d >= (9 * 5 * 5))
++    return SZ_ERROR_UNSUPPORTED;
++
++  p->lc = d % 9;
++  d /= 9;
++  p->pb = d / 5;
++  p->lp = d % 5;
++
++  return SZ_OK;
++}
++
++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
++{
++  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
++  if (p->probs == 0 || numProbs != p->numProbs)
++  {
++    LzmaDec_FreeProbs(p, alloc);
++    p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
++    p->numProbs = numProbs;
++    if (p->probs == 0)
++      return SZ_ERROR_MEM;
++  }
++  return SZ_OK;
++}
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  SizeT dicBufSize;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  dicBufSize = propNew.dicSize;
++  if (p->dic == 0 || dicBufSize != p->dicBufSize)
++  {
++    LzmaDec_FreeDict(p, alloc);
++    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
++    if (p->dic == 0)
++    {
++      LzmaDec_FreeProbs(p, alloc);
++      return SZ_ERROR_MEM;
++    }
++  }
++  p->dicBufSize = dicBufSize;
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 
++    ELzmaStatus *status, ISzAlloc *alloc)
++{
++  CLzmaDec p;
++  SRes res;
++  SizeT inSize = *srcLen;
++  SizeT outSize = *destLen;
++  *srcLen = *destLen = 0;
++  if (inSize < RC_INIT_SIZE)
++    return SZ_ERROR_INPUT_EOF;
++
++  LzmaDec_Construct(&p);
++  res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
++  if (res != 0)
++    return res;
++  p.dic = dest;
++  p.dicBufSize = outSize;
++
++  LzmaDec_Init(&p);
++  
++  *srcLen = inSize;
++  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
++
++  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
++    res = SZ_ERROR_INPUT_EOF;
++
++  (*destLen) = p.dicPos;
++  LzmaDec_FreeProbs(&p, alloc);
++  return res;
++}
+--- /dev/null
++++ b/lzma/LzmaEnc.c
+@@ -0,0 +1,2335 @@
++/* LzmaEnc.c -- LZMA Encoder
++2008-04-28
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzmaEnc.h for license options */
++
++#if defined(SHOW_STAT) || defined(SHOW_STAT2)
++#include <stdio.h>
++#endif
++
++#include <string.h>
++
++#include "LzmaEnc.h"
++
++#include "LzFind.h"
++#ifdef COMPRESS_MF_MT
++#include "LzFindMt.h"
++#endif
++
++/* #define SHOW_STAT */
++/* #define SHOW_STAT2 */
++
++#ifdef SHOW_STAT
++static int ttt = 0;
++#endif
++
++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
++
++#define kBlockSize (9 << 10)
++#define kUnpackBlockSize (1 << 18)
++#define kMatchArraySize (1 << 21)
++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
++
++#define kNumMaxDirectBits (31)
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++#define kProbInitValue (kBitModelTotal >> 1)
++
++#define kNumMoveReducingBits 4
++#define kNumBitPriceShiftBits 4
++#define kBitPrice (1 << kNumBitPriceShiftBits)
++
++void LzmaEncProps_Init(CLzmaEncProps *p)
++{
++  p->level = 5;
++  p->dictSize = p->mc = 0;
++  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
++  p->writeEndMark = 0;
++}
++
++void LzmaEncProps_Normalize(CLzmaEncProps *p)
++{
++  int level = p->level;
++  if (level < 0) level = 5;
++  p->level = level;
++  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
++  if (p->lc < 0) p->lc = 3; 
++  if (p->lp < 0) p->lp = 0; 
++  if (p->pb < 0) p->pb = 2; 
++  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); 
++  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); 
++  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); 
++  if (p->numHashBytes < 0) p->numHashBytes = 4; 
++  if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
++  if (p->numThreads < 0) p->numThreads = ((p->btMode && p->algo) ? 2 : 1);
++}
++
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++{
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++  return props.dictSize;
++}
++
++/* #define LZMA_LOG_BSR */
++/* Define it for Intel's CPU */
++
++
++#ifdef LZMA_LOG_BSR
++
++#define kDicLogSizeMaxCompress 30
++
++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
++
++UInt32 GetPosSlot1(UInt32 pos) 
++{ 
++  UInt32 res; 
++  BSR2_RET(pos, res); 
++  return res; 
++}
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
++
++#else
++
++#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
++
++void LzmaEnc_FastPosInit(Byte *g_FastPos)
++{
++  int c = 2, slotFast;
++  g_FastPos[0] = 0;
++  g_FastPos[1] = 1;
++  
++  for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
++  {
++    UInt32 k = (1 << ((slotFast >> 1) - 1));
++    UInt32 j;
++    for (j = 0; j < k; j++, c++)
++      g_FastPos[c] = (Byte)slotFast;
++  }
++}
++
++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
++  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
++  res = p->g_FastPos[pos >> i] + (i * 2); }
++/*
++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
++  p->g_FastPos[pos >> 6] + 12 : \
++  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
++*/
++
++#define GetPosSlot1(pos) p->g_FastPos[pos]
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
++
++#endif
++
++
++#define LZMA_NUM_REPS 4
++
++typedef unsigned CState;
++
++typedef struct _COptimal
++{
++  UInt32 price;    
++
++  CState state;
++  int prev1IsChar;
++  int prev2;
++
++  UInt32 posPrev2;
++  UInt32 backPrev2;     
++
++  UInt32 posPrev;
++  UInt32 backPrev;     
++  UInt32 backs[LZMA_NUM_REPS];
++} COptimal;
++
++#define kNumOpts (1 << 12)
++
++#define kNumLenToPosStates 4
++#define kNumPosSlotBits 6 
++#define kDicLogSizeMin 0 
++#define kDicLogSizeMax 32 
++#define kDistTableSizeMax (kDicLogSizeMax * 2)
++
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++#define kAlignMask (kAlignTableSize - 1)
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
++
++#define kNumFullDistances (1 << (kEndPosModelIndex / 2))
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++#define LZMA_PB_MAX 4
++#define LZMA_LC_MAX 8
++#define LZMA_LP_MAX 4
++
++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
++
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define LZMA_MATCH_LEN_MIN 2
++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
++
++#define kNumStates 12
++
++typedef struct
++{
++  CLzmaProb choice;
++  CLzmaProb choice2;
++  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
++  CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
++  CLzmaProb high[kLenNumHighSymbols];
++} CLenEnc;
++
++typedef struct
++{
++  CLenEnc p;
++  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
++  UInt32 tableSize;
++  UInt32 counters[LZMA_NUM_PB_STATES_MAX];
++} CLenPriceEnc;
++
++typedef struct _CRangeEnc
++{
++  UInt32 range;
++  Byte cache;
++  UInt64 low;
++  UInt64 cacheSize;
++  Byte *buf;
++  Byte *bufLim;
++  Byte *bufBase;
++  ISeqOutStream *outStream;
++  UInt64 processed;
++  SRes res;
++} CRangeEnc;
++
++typedef struct _CSeqInStreamBuf
++{
++  ISeqInStream funcTable;
++  const Byte *data;
++  SizeT rem;
++} CSeqInStreamBuf;
++
++static SRes MyRead(void *pp, void *data, size_t *size)
++{
++  size_t curSize = *size;
++  CSeqInStreamBuf *p = (CSeqInStreamBuf *)pp;
++  if (p->rem < curSize)
++    curSize = p->rem;
++  memcpy(data, p->data, curSize);
++  p->rem -= curSize;
++  p->data += curSize;
++  *size = curSize;
++  return SZ_OK;
++}
++
++typedef struct 
++{
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++} CSaveState;
++
++typedef struct _CLzmaEnc
++{
++  IMatchFinder matchFinder;
++  void *matchFinderObj;
++
++  #ifdef COMPRESS_MF_MT
++  Bool mtMode;
++  CMatchFinderMt matchFinderMt;
++  #endif
++
++  CMatchFinder matchFinderBase;
++
++  #ifdef COMPRESS_MF_MT
++  Byte pad[128];
++  #endif
++  
++  UInt32 optimumEndIndex;
++  UInt32 optimumCurrentIndex;
++
++  Bool longestMatchWasFound;
++  UInt32 longestMatchLength;    
++  UInt32 numDistancePairs;
++
++  COptimal opt[kNumOpts];
++  
++  #ifndef LZMA_LOG_BSR
++  Byte g_FastPos[1 << kNumLogBits];
++  #endif
++
++  UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
++  UInt32 matchDistances[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
++  UInt32 numFastBytes;
++  UInt32 additionalOffset;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++
++  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
++  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
++  UInt32 alignPrices[kAlignTableSize];
++  UInt32 alignPriceCount;
++
++  UInt32 distTableSize;
++
++  unsigned lc, lp, pb;
++  unsigned lpMask, pbMask;
++
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  unsigned lclp;
++
++  Bool fastMode;
++  
++  CRangeEnc rc;
++
++  Bool writeEndMark;
++  UInt64 nowPos64;
++  UInt32 matchPriceCount;
++  Bool finished;
++  Bool multiThread;
++
++  SRes result;
++  UInt32 dictSize;
++  UInt32 matchFinderCycles;
++
++  ISeqInStream *inStream;
++  CSeqInStreamBuf seqBufInStream;
++
++  CSaveState saveState;
++} CLzmaEnc;
++
++void LzmaEnc_SaveState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CSaveState *dest = &p->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
++}
++
++void LzmaEnc_RestoreState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *dest = (CLzmaEnc *)pp;
++  const CSaveState *p = &dest->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
++}
++
++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++
++  if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
++      props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
++    return SZ_ERROR_PARAM;
++  p->dictSize = props.dictSize;
++  p->matchFinderCycles = props.mc;
++  {
++    unsigned fb = props.fb;
++    if (fb < 5)
++      fb = 5;
++    if (fb > LZMA_MATCH_LEN_MAX)
++      fb = LZMA_MATCH_LEN_MAX;
++    p->numFastBytes = fb;
++  }
++  p->lc = props.lc;
++  p->lp = props.lp;
++  p->pb = props.pb;
++  p->fastMode = (props.algo == 0);
++  p->matchFinderBase.btMode = props.btMode;
++  {
++    UInt32 numHashBytes = 4;
++    if (props.btMode)
++    {
++      if (props.numHashBytes < 2)
++        numHashBytes = 2;
++      else if (props.numHashBytes < 4)
++        numHashBytes = props.numHashBytes;
++    }
++    p->matchFinderBase.numHashBytes = numHashBytes;
++  }
++
++  p->matchFinderBase.cutValue = props.mc;
++
++  p->writeEndMark = props.writeEndMark;
++
++  #ifdef COMPRESS_MF_MT
++  /*
++  if (newMultiThread != _multiThread)
++  {
++    ReleaseMatchFinder();
++    _multiThread = newMultiThread;
++  }
++  */
++  p->multiThread = (props.numThreads > 1);
++  #endif
++
++  return SZ_OK;
++}
++
++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
++static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
++static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
++
++/*
++  void UpdateChar() { Index = kLiteralNextStates[Index]; }
++  void UpdateMatch() { Index = kMatchNextStates[Index]; }
++  void UpdateRep() { Index = kRepNextStates[Index]; }
++  void UpdateShortRep() { Index = kShortRepNextStates[Index]; }
++*/
++
++#define IsCharState(s) ((s) < 7)
++
++
++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
++
++#define kInfinityPrice (1 << 30)
++
++static void RangeEnc_Construct(CRangeEnc *p)
++{
++  p->outStream = 0;
++  p->bufBase = 0;
++}
++
++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
++
++#define RC_BUF_SIZE (1 << 16)
++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
++{
++  if (p->bufBase == 0)
++  {
++    p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
++    if (p->bufBase == 0)
++      return 0;
++    p->bufLim = p->bufBase + RC_BUF_SIZE;
++  }
++  return 1;
++}
++
++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->bufBase);
++  p->bufBase = 0;
++}
++
++static void RangeEnc_Init(CRangeEnc *p)
++{
++  /* Stream.Init(); */
++  p->low = 0;
++  p->range = 0xFFFFFFFF;
++  p->cacheSize = 1;
++  p->cache = 0;
++
++  p->buf = p->bufBase;
++
++  p->processed = 0;
++  p->res = SZ_OK;
++}
++
++static void RangeEnc_FlushStream(CRangeEnc *p)
++{
++  size_t num;
++  if (p->res != SZ_OK)
++    return;
++  num = p->buf - p->bufBase;
++  if (num != p->outStream->Write(p->outStream, p->bufBase, num))
++    p->res = SZ_ERROR_WRITE;
++  p->processed += num;
++  p->buf = p->bufBase;
++}
++
++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
++{
++  if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) 
++  {
++    Byte temp = p->cache;
++    do
++    {
++      Byte *buf = p->buf;
++      *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
++      p->buf = buf;
++      if (buf == p->bufLim)
++        RangeEnc_FlushStream(p);
++      temp = 0xFF;
++    }
++    while (--p->cacheSize != 0);
++    p->cache = (Byte)((UInt32)p->low >> 24);                      
++  } 
++  p->cacheSize++;                               
++  p->low = (UInt32)p->low << 8;                           
++}
++
++static void RangeEnc_FlushData(CRangeEnc *p)
++{
++  int i;
++  for (i = 0; i < 5; i++)
++    RangeEnc_ShiftLow(p);
++}
++
++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
++{
++  do
++  {
++    p->range >>= 1;
++    p->low += p->range & (0 - ((value >> --numBits) & 1));
++    if (p->range < kTopValue)
++    {
++      p->range <<= 8;
++      RangeEnc_ShiftLow(p);
++    }
++  }
++  while (numBits != 0);
++}
++
++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
++{
++  UInt32 ttt = *prob;
++  UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
++  if (symbol == 0)
++  {
++    p->range = newBound;
++    ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
++  }
++  else
++  {
++    p->low += newBound;
++    p->range -= newBound;
++    ttt -= ttt >> kNumMoveBits;
++  }
++  *prob = (CLzmaProb)ttt;
++  if (p->range < kTopValue)
++  {
++    p->range <<= 8;
++    RangeEnc_ShiftLow(p);
++  }
++}
++
++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
++{
++  symbol |= 0x100;
++  do 
++  {
++    RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++}
++
++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
++{
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do 
++  {
++    matchByte <<= 1;
++    RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++}
++
++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++{
++  UInt32 i;
++  for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
++  {
++    const int kCyclesBits = kNumBitPriceShiftBits;
++    UInt32 w = i;
++    UInt32 bitCount = 0;
++    int j;
++    for (j = 0; j < kCyclesBits; j++)
++    {
++      w = w * w;
++      bitCount <<= 1;
++      while (w >= ((UInt32)1 << 16))
++      {
++        w >>= 1;
++        bitCount++;
++      }
++    }
++    ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
++  }
++}
++
++
++#define GET_PRICE(prob, symbol) \
++  p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICEa(prob, symbol) \
++  ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= 0x100;
++  do
++  {
++    price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++  return price;
++};
++
++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do 
++  {
++    matchByte <<= 1;
++    price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++  return price;
++};
++
++
++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0 ;)
++  {
++    UInt32 bit;
++    i--;
++    bit = (symbol >> i) & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++  }
++};
++
++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = 0; i < numBitLevels; i++)
++  {
++    UInt32 bit = symbol & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++    symbol >>= 1;
++  }
++}
++
++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= (1 << numBitLevels);
++  while (symbol != 1)
++  {
++    price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
++    symbol >>= 1;
++  }
++  return price;
++}
++
++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0; i--)
++  {
++    UInt32 bit = symbol & 1;
++    symbol >>= 1;
++    price += GET_PRICEa(probs[m], bit);
++    m = (m << 1) | bit;
++  }
++  return price;
++}
++
++
++static void LenEnc_Init(CLenEnc *p)
++{
++  unsigned i;
++  p->choice = p->choice2 = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
++    p->low[i] = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
++    p->mid[i] = kProbInitValue;
++  for (i = 0; i < kLenNumHighSymbols; i++)
++    p->high[i] = kProbInitValue;
++}
++
++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
++{
++  if (symbol < kLenNumLowSymbols)
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 0);
++    RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
++  }
++  else
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 1);
++    if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 0);
++      RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
++    }
++    else
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 1);
++      RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
++    }
++  }
++}
++
++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
++{
++  UInt32 a0 = GET_PRICE_0a(p->choice);
++  UInt32 a1 = GET_PRICE_1a(p->choice);
++  UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
++  UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
++  UInt32 i = 0;
++  for (i = 0; i < kLenNumLowSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
++  }
++  for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
++  }
++  for (; i < numSymbols; i++)
++    prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
++}
++
++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
++{
++  LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
++  p->counters[posState] = p->tableSize;
++}
++
++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
++{
++  UInt32 posState;
++  for (posState = 0; posState < numPosStates; posState++)
++    LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
++{
++  LenEnc_Encode(&p->p, rc, symbol, posState);
++  if (updatePrice)
++    if (--p->counters[posState] == 0)
++      LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++
++
++
++static void MovePos(CLzmaEnc *p, UInt32 num)
++{
++  #ifdef SHOW_STAT
++  ttt += num;
++  printf("\n MovePos %d", num);
++  #endif
++  if (num != 0)
++  {
++    p->additionalOffset += num;
++    p->matchFinder.Skip(p->matchFinderObj, num);
++  }
++}
++
++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
++{
++  UInt32 lenRes = 0, numDistancePairs;
++  numDistancePairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matchDistances);
++  #ifdef SHOW_STAT
++  printf("\n i = %d numPairs = %d    ", ttt, numDistancePairs / 2);
++  if (ttt >= 61994)
++    ttt = ttt;
++
++  ttt++;
++  {
++    UInt32 i;
++  for (i = 0; i < numDistancePairs; i += 2)
++    printf("%2d %6d   | ", p->matchDistances[i], p->matchDistances[i + 1]);
++  }
++  #endif
++  if (numDistancePairs > 0)
++  {
++    lenRes = p->matchDistances[numDistancePairs - 2];
++    if (lenRes == p->numFastBytes)
++    {
++      UInt32 numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) + 1;
++      const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++      UInt32 distance = p->matchDistances[numDistancePairs - 1] + 1;
++      if (numAvail > LZMA_MATCH_LEN_MAX)
++        numAvail = LZMA_MATCH_LEN_MAX;
++
++      {
++        const Byte *pby2 = pby - distance;
++        for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
++      }
++    }
++  }
++  p->additionalOffset++;
++  *numDistancePairsRes = numDistancePairs;
++  return lenRes;
++}
++
++
++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
++#define IsShortRep(p) ((p)->backPrev == 0)
++
++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
++{
++  return 
++    GET_PRICE_0(p->isRepG0[state]) +
++    GET_PRICE_0(p->isRep0Long[state][posState]);
++}
++
++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
++{
++  UInt32 price;
++  if (repIndex == 0)
++  {
++    price = GET_PRICE_0(p->isRepG0[state]);
++    price += GET_PRICE_1(p->isRep0Long[state][posState]);
++  }
++  else
++  {
++    price = GET_PRICE_1(p->isRepG0[state]);
++    if (repIndex == 1)
++      price += GET_PRICE_0(p->isRepG1[state]);
++    else
++    {
++      price += GET_PRICE_1(p->isRepG1[state]);
++      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
++    }
++  }
++  return price;
++}
++
++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
++{
++  return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
++    GetPureRepPrice(p, repIndex, state, posState);
++}
++
++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
++{
++  UInt32 posMem = p->opt[cur].posPrev;
++  UInt32 backMem = p->opt[cur].backPrev;
++  p->optimumEndIndex = cur;
++  do
++  {
++    if (p->opt[cur].prev1IsChar)
++    {
++      MakeAsChar(&p->opt[posMem])
++      p->opt[posMem].posPrev = posMem - 1;
++      if (p->opt[cur].prev2)
++      {
++        p->opt[posMem - 1].prev1IsChar = False;
++        p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
++        p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
++      }
++    }
++    {
++      UInt32 posPrev = posMem;
++      UInt32 backCur = backMem;
++      
++      backMem = p->opt[posPrev].backPrev;
++      posMem = p->opt[posPrev].posPrev;
++      
++      p->opt[posPrev].backPrev = backCur;
++      p->opt[posPrev].posPrev = cur;
++      cur = posPrev;
++    }
++  }
++  while (cur != 0);
++  *backRes = p->opt[0].backPrev;
++  p->optimumCurrentIndex  = p->opt[0].posPrev;
++  return p->optimumCurrentIndex; 
++}
++
++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
++
++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
++{
++  UInt32 numAvailableBytes, lenMain, numDistancePairs;
++  const Byte *data;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 repLens[LZMA_NUM_REPS];
++  UInt32 repMaxIndex, i;
++  UInt32 *matchDistances;
++  Byte currentByte, matchByte; 
++  UInt32 posState;
++  UInt32 matchPrice, repMatchPrice;
++  UInt32 lenEnd;
++  UInt32 len;
++  UInt32 normalMatchPrice;
++  UInt32 cur;
++  if (p->optimumEndIndex != p->optimumCurrentIndex)
++  {
++    const COptimal *opt = &p->opt[p->optimumCurrentIndex];
++    UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
++    *backRes = opt->backPrev;
++    p->optimumCurrentIndex = opt->posPrev;
++    return lenRes;
++  }
++  p->optimumCurrentIndex = p->optimumEndIndex = 0;
++  
++  numAvailableBytes = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++
++  if (!p->longestMatchWasFound)
++  {
++    lenMain = ReadMatchDistances(p, &numDistancePairs);
++  }
++  else
++  {
++    lenMain = p->longestMatchLength;
++    numDistancePairs = p->numDistancePairs;
++    p->longestMatchWasFound = False;
++  }
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  if (numAvailableBytes < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++  if (numAvailableBytes > LZMA_MATCH_LEN_MAX)
++    numAvailableBytes = LZMA_MATCH_LEN_MAX;
++
++  repMaxIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 lenTest;
++    const Byte *data2;
++    reps[i] = p->reps[i];
++    data2 = data - (reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
++    repLens[i] = lenTest;
++    if (lenTest > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  if (repLens[repMaxIndex] >= p->numFastBytes)
++  {
++    UInt32 lenRes;
++    *backRes = repMaxIndex;
++    lenRes = repLens[repMaxIndex];
++    MovePos(p, lenRes - 1);
++    return lenRes;
++  }
++
++  matchDistances = p->matchDistances;
++  if (lenMain >= p->numFastBytes)
++  {
++    *backRes = matchDistances[numDistancePairs - 1] + LZMA_NUM_REPS; 
++    MovePos(p, lenMain - 1);
++    return lenMain;
++  }
++  currentByte = *data;
++  matchByte = *(data - (reps[0] + 1));
++
++  if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
++  {
++    *backRes = (UInt32)-1;
++    return 1;
++  }
++
++  p->opt[0].state = (CState)p->state;
++
++  posState = (position & p->pbMask);
++
++  {
++    const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++    p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + 
++        (!IsCharState(p->state) ? 
++          LitEnc_GetPriceMatched(probs, currentByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, currentByte, p->ProbPrices));
++  }
++
++  MakeAsChar(&p->opt[1]);
++
++  matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
++  repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
++
++  if (matchByte == currentByte)
++  {
++    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
++    if (shortRepPrice < p->opt[1].price)
++    {
++      p->opt[1].price = shortRepPrice;
++      MakeAsShortRep(&p->opt[1]);
++    }
++  }
++  lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
++
++  if (lenEnd < 2)
++  {
++    *backRes = p->opt[1].backPrev;
++    return 1;
++  }
++
++  p->opt[1].posPrev = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++    p->opt[0].backs[i] = reps[i];
++
++  len = lenEnd;
++  do
++    p->opt[len--].price = kInfinityPrice;
++  while (len >= 2);
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 repLen = repLens[i];
++    UInt32 price;
++    if (repLen < 2)
++      continue;
++    price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
++    do
++    {
++      UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
++      COptimal *opt = &p->opt[repLen];
++      if (curAndLenPrice < opt->price) 
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = i;
++        opt->prev1IsChar = False;
++      }
++    }
++    while (--repLen >= 2);
++  }
++
++  normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
++
++  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
++  if (len <= lenMain)
++  {
++    UInt32 offs = 0;
++    while (len > matchDistances[offs])
++      offs += 2;
++    for (; ; len++)
++    {
++      COptimal *opt;
++      UInt32 distance = matchDistances[offs + 1];
++
++      UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
++      UInt32 lenToPosState = GetLenToPosState(len);
++      if (distance < kNumFullDistances)
++        curAndLenPrice += p->distancesPrices[lenToPosState][distance];
++      else
++      {
++        UInt32 slot;
++        GetPosSlot2(distance, slot);
++        curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
++      }
++      opt = &p->opt[len];
++      if (curAndLenPrice < opt->price) 
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = distance + LZMA_NUM_REPS;
++        opt->prev1IsChar = False;
++      }
++      if (len == matchDistances[offs])
++      {
++        offs += 2;
++        if (offs == numDistancePairs)
++          break;
++      }
++    }
++  }
++
++  cur = 0;
++
++    #ifdef SHOW_STAT2
++    if (position >= 0)
++    {
++      unsigned i;
++      printf("\n pos = %4X", position);
++      for (i = cur; i <= lenEnd; i++)
++      printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
++    }
++    #endif
++
++  for (;;)
++  {
++    UInt32 numAvailableBytesFull, newLen, numDistancePairs;
++    COptimal *curOpt;
++    UInt32 posPrev;
++    UInt32 state;
++    UInt32 curPrice;
++    Bool nextIsChar;
++    const Byte *data;
++    Byte currentByte, matchByte;
++    UInt32 posState;
++    UInt32 curAnd1Price;
++    COptimal *nextOpt;
++    UInt32 matchPrice, repMatchPrice;  
++    UInt32 numAvailableBytes;
++    UInt32 startLen;
++
++    cur++;
++    if (cur == lenEnd)
++      return Backward(p, backRes, cur);
++
++    numAvailableBytesFull = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++    newLen = ReadMatchDistances(p, &numDistancePairs);
++    if (newLen >= p->numFastBytes)
++    {
++      p->numDistancePairs = numDistancePairs;
++      p->longestMatchLength = newLen;
++      p->longestMatchWasFound = True;
++      return Backward(p, backRes, cur);
++    }
++    position++;
++    curOpt = &p->opt[cur];
++    posPrev = curOpt->posPrev;
++    if (curOpt->prev1IsChar)
++    {
++      posPrev--;
++      if (curOpt->prev2)
++      {
++        state = p->opt[curOpt->posPrev2].state;
++        if (curOpt->backPrev2 < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      else
++        state = p->opt[posPrev].state;
++      state = kLiteralNextStates[state];
++    }
++    else
++      state = p->opt[posPrev].state;
++    if (posPrev == cur - 1)
++    {
++      if (IsShortRep(curOpt))
++        state = kShortRepNextStates[state];
++      else
++        state = kLiteralNextStates[state];
++    }
++    else
++    {
++      UInt32 pos;
++      const COptimal *prevOpt;
++      if (curOpt->prev1IsChar && curOpt->prev2)
++      {
++        posPrev = curOpt->posPrev2;
++        pos = curOpt->backPrev2;
++        state = kRepNextStates[state];
++      }
++      else
++      {
++        pos = curOpt->backPrev;
++        if (pos < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      prevOpt = &p->opt[posPrev];
++      if (pos < LZMA_NUM_REPS)
++      {
++        UInt32 i;
++        reps[0] = prevOpt->backs[pos];
++        for (i = 1; i <= pos; i++)
++          reps[i] = prevOpt->backs[i - 1];
++        for (; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i];
++      }
++      else
++      {
++        UInt32 i;
++        reps[0] = (pos - LZMA_NUM_REPS);
++        for (i = 1; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i - 1];
++      }
++    }
++    curOpt->state = (CState)state;
++
++    curOpt->backs[0] = reps[0];
++    curOpt->backs[1] = reps[1];
++    curOpt->backs[2] = reps[2];
++    curOpt->backs[3] = reps[3];
++
++    curPrice = curOpt->price; 
++    nextIsChar = False;
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    currentByte = *data;
++    matchByte = *(data - (reps[0] + 1));
++
++    posState = (position & p->pbMask);
++
++    curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
++    {
++      const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++      curAnd1Price += 
++        (!IsCharState(state) ? 
++          LitEnc_GetPriceMatched(probs, currentByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, currentByte, p->ProbPrices));
++    }   
++
++    nextOpt = &p->opt[cur + 1];
++
++    if (curAnd1Price < nextOpt->price) 
++    {
++      nextOpt->price = curAnd1Price;
++      nextOpt->posPrev = cur;
++      MakeAsChar(nextOpt);
++      nextIsChar = True;
++    }
++
++    matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
++    repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
++    
++    if (matchByte == currentByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
++    {
++      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
++      if (shortRepPrice <= nextOpt->price)
++      {
++        nextOpt->price = shortRepPrice;
++        nextOpt->posPrev = cur;
++        MakeAsShortRep(nextOpt);
++        nextIsChar = True;
++      }
++    }
++
++    {
++      UInt32 temp = kNumOpts - 1 - cur;
++      if (temp <  numAvailableBytesFull)
++        numAvailableBytesFull = temp;
++    }
++    numAvailableBytes = numAvailableBytesFull;
++
++    if (numAvailableBytes < 2)
++      continue;
++    if (numAvailableBytes > p->numFastBytes)
++      numAvailableBytes = p->numFastBytes;
++    if (!nextIsChar && matchByte != currentByte) /* speed optimization */
++    {
++      /* try Literal + rep0 */
++      UInt32 temp;
++      UInt32 lenTest2;
++      const Byte *data2 = data - (reps[0] + 1);
++      UInt32 limit = p->numFastBytes + 1;
++      if (limit > numAvailableBytesFull)
++        limit = numAvailableBytesFull;
++
++      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
++      lenTest2 = temp - 1;
++      if (lenTest2 >= 2)
++      {
++        UInt32 state2 = kLiteralNextStates[state];
++        UInt32 posStateNext = (position + 1) & p->pbMask;
++        UInt32 nextRepMatchPrice = curAnd1Price + 
++            GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++            GET_PRICE_1(p->isRep[state2]);
++        /* for (; lenTest2 >= 2; lenTest2--) */
++        {
++          UInt32 curAndLenPrice;
++          COptimal *opt;
++          UInt32 offset = cur + 1 + lenTest2;
++          while (lenEnd < offset)
++            p->opt[++lenEnd].price = kInfinityPrice;
++          curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++          opt = &p->opt[offset];
++          if (curAndLenPrice < opt->price) 
++          {
++            opt->price = curAndLenPrice;
++            opt->posPrev = cur + 1;
++            opt->backPrev = 0;
++            opt->prev1IsChar = True;
++            opt->prev2 = False;
++          }
++        }
++      }
++    }
++    
++    startLen = 2; /* speed optimization */
++    {
++    UInt32 repIndex;
++    for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
++    {
++      UInt32 lenTest;
++      UInt32 lenTestTemp;
++      UInt32 price;
++      const Byte *data2 = data - (reps[repIndex] + 1);
++      if (data[0] != data2[0] || data[1] != data2[1])
++        continue;
++      for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
++      while (lenEnd < cur + lenTest)
++        p->opt[++lenEnd].price = kInfinityPrice;
++      lenTestTemp = lenTest;
++      price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
++      do
++      {
++        UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
++        COptimal *opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price) 
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = repIndex;
++          opt->prev1IsChar = False;
++        }
++      }
++      while (--lenTest >= 2);
++      lenTest = lenTestTemp;
++      
++      if (repIndex == 0)
++        startLen = lenTest + 1;
++        
++      /* if (_maxMode) */
++        {
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailableBytesFull)
++            limit = numAvailableBytesFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kRepNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = 
++                price + p->repLenEnc.prices[posState][lenTest - 2] + 
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (position + lenTest + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice + 
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price) 
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = repIndex;
++              }
++            }
++          }
++        }
++    }
++    }
++    /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
++    if (newLen > numAvailableBytes)
++    {
++      newLen = numAvailableBytes;
++      for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
++      matchDistances[numDistancePairs] = newLen;
++      numDistancePairs += 2;
++    }
++    if (newLen >= startLen)
++    {
++      UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
++      UInt32 offs, curBack, posSlot;
++      UInt32 lenTest;
++      while (lenEnd < cur + newLen)
++        p->opt[++lenEnd].price = kInfinityPrice;
++
++      offs = 0;
++      while (startLen > matchDistances[offs])
++        offs += 2;
++      curBack = matchDistances[offs + 1];
++      GetPosSlot2(curBack, posSlot);
++      for (lenTest = /*2*/ startLen; ; lenTest++)
++      {
++        UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
++        UInt32 lenToPosState = GetLenToPosState(lenTest);
++        COptimal *opt;
++        if (curBack < kNumFullDistances)
++          curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
++        else
++          curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
++        
++        opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price) 
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = curBack + LZMA_NUM_REPS;
++          opt->prev1IsChar = False;
++        }
++
++        if (/*_maxMode && */lenTest == matchDistances[offs])
++        {
++          /* Try Match + Literal + Rep0 */
++          const Byte *data2 = data - (curBack + 1);
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailableBytesFull)
++            limit = numAvailableBytesFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kMatchNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = curAndLenPrice + 
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (posStateNext + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice + 
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price) 
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = curBack + LZMA_NUM_REPS;
++              }
++            }
++          }
++          offs += 2;
++          if (offs == numDistancePairs)
++            break;
++          curBack = matchDistances[offs + 1];
++          if (curBack >= kNumFullDistances)
++            GetPosSlot2(curBack, posSlot);
++        }
++      }
++    }
++  }
++}
++
++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
++
++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
++{
++  UInt32 numAvailableBytes = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++  UInt32 lenMain, numDistancePairs;
++  const Byte *data;
++  UInt32 repLens[LZMA_NUM_REPS];
++  UInt32 repMaxIndex, i;
++  UInt32 *matchDistances;
++  UInt32 backMain;
++
++  if (!p->longestMatchWasFound)
++  {
++    lenMain = ReadMatchDistances(p, &numDistancePairs);
++  }
++  else
++  {
++    lenMain = p->longestMatchLength;
++    numDistancePairs = p->numDistancePairs;
++    p->longestMatchWasFound = False;
++  }
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  if (numAvailableBytes > LZMA_MATCH_LEN_MAX)
++    numAvailableBytes = LZMA_MATCH_LEN_MAX;
++  if (numAvailableBytes < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++
++  repMaxIndex = 0;
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    const Byte *data2 = data - (p->reps[i] + 1);
++    UInt32 len;
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
++    if (len >= p->numFastBytes)
++    {
++      *backRes = i;
++      MovePos(p, len - 1);
++      return len;
++    }
++    repLens[i] = len;
++    if (len > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  matchDistances = p->matchDistances;
++  if (lenMain >= p->numFastBytes)
++  {
++    *backRes = matchDistances[numDistancePairs - 1] + LZMA_NUM_REPS; 
++    MovePos(p, lenMain - 1);
++    return lenMain;
++  }
++
++  backMain = 0; /* for GCC */
++  if (lenMain >= 2)
++  {
++    backMain = matchDistances[numDistancePairs - 1];
++    while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
++    {
++      if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
++        break;
++      numDistancePairs -= 2;
++      lenMain = matchDistances[numDistancePairs - 2];
++      backMain = matchDistances[numDistancePairs - 1];
++    }
++    if (lenMain == 2 && backMain >= 0x80)
++      lenMain = 1;
++  }
++
++  if (repLens[repMaxIndex] >= 2)
++  {
++    if (repLens[repMaxIndex] + 1 >= lenMain || 
++        (repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9))) ||
++        (repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15))))
++    {
++      UInt32 lenRes;
++      *backRes = repMaxIndex;
++      lenRes = repLens[repMaxIndex];
++      MovePos(p, lenRes - 1);
++      return lenRes;
++    }
++  }
++  
++  if (lenMain >= 2 && numAvailableBytes > 2)
++  {
++    UInt32 i;
++    numAvailableBytes = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++    p->longestMatchLength = ReadMatchDistances(p, &p->numDistancePairs);
++    if (p->longestMatchLength >= 2)
++    {
++      UInt32 newDistance = matchDistances[p->numDistancePairs - 1];
++      if ((p->longestMatchLength >= lenMain && newDistance < backMain) || 
++          (p->longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance)) ||
++          (p->longestMatchLength > lenMain + 1) ||
++          (p->longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain)))
++      {
++        p->longestMatchWasFound = True;
++        *backRes = (UInt32)(-1);
++        return 1;
++      }
++    }
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    for (i = 0; i < LZMA_NUM_REPS; i++)
++    {
++      UInt32 len;
++      const Byte *data2 = data - (p->reps[i] + 1);
++      if (data[1] != data2[1] || data[2] != data2[2])
++      {
++        repLens[i] = 0;
++        continue;
++      }
++      for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
++      if (len + 1 >= lenMain)
++      {
++        p->longestMatchWasFound = True;
++        *backRes = (UInt32)(-1);
++        return 1;
++      }
++    }
++    *backRes = backMain + LZMA_NUM_REPS; 
++    MovePos(p, lenMain - 2);
++    return lenMain;
++  }
++  *backRes = (UInt32)(-1);
++  return 1;
++}
++
++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
++{
++  UInt32 len;
++  RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++  RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++  p->state = kMatchNextStates[p->state];
++  len = LZMA_MATCH_LEN_MIN;
++  LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++  RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
++  RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
++  RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
++}
++
++static SRes CheckErrors(CLzmaEnc *p)
++{
++  if (p->result != SZ_OK)
++    return p->result;
++  if (p->rc.res != SZ_OK)
++    p->result = SZ_ERROR_WRITE;
++  if (p->matchFinderBase.result != SZ_OK)
++    p->result = SZ_ERROR_READ;
++  if (p->result != SZ_OK)
++    p->finished = True;
++  return p->result;
++}
++
++static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
++{
++  /* ReleaseMFStream(); */
++  p->finished = True;
++  if (p->writeEndMark)
++    WriteEndMarker(p, nowPos & p->pbMask);
++  RangeEnc_FlushData(&p->rc);
++  RangeEnc_FlushStream(&p->rc);
++  return CheckErrors(p);
++}
++
++static void FillAlignPrices(CLzmaEnc *p)
++{
++  UInt32 i;
++  for (i = 0; i < kAlignTableSize; i++)
++    p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
++  p->alignPriceCount = 0;
++}
++
++static void FillDistancesPrices(CLzmaEnc *p)
++{
++  UInt32 tempPrices[kNumFullDistances];
++  UInt32 i, lenToPosState;
++  for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
++  { 
++    UInt32 posSlot = GetPosSlot1(i);
++    UInt32 footerBits = ((posSlot >> 1) - 1);
++    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++    tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
++  }
++
++  for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
++  {
++    UInt32 posSlot;
++    const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
++    UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
++    for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
++    for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
++
++    {
++      UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
++      UInt32 i;
++      for (i = 0; i < kStartPosModelIndex; i++)
++        distancesPrices[i] = posSlotPrices[i];
++      for (; i < kNumFullDistances; i++)
++        distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
++    }
++  }
++  p->matchPriceCount = 0;
++}
++
++void LzmaEnc_Construct(CLzmaEnc *p)
++{
++  RangeEnc_Construct(&p->rc);
++  MatchFinder_Construct(&p->matchFinderBase);
++  #ifdef COMPRESS_MF_MT
++  MatchFinderMt_Construct(&p->matchFinderMt);
++  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
++  #endif
++
++  {
++    CLzmaEncProps props;
++    LzmaEncProps_Init(&props);
++    LzmaEnc_SetProps(p, &props);
++  }
++
++  #ifndef LZMA_LOG_BSR
++  LzmaEnc_FastPosInit(p->g_FastPos);
++  #endif
++
++  LzmaEnc_InitPriceTables(p->ProbPrices);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
++{
++  void *p;
++  p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
++  if (p != 0)
++    LzmaEnc_Construct((CLzmaEnc *)p);
++  return p;
++}
++
++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->litProbs);
++  alloc->Free(alloc, p->saveState.litProbs);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  #ifdef COMPRESS_MF_MT
++  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
++  #endif
++  MatchFinder_Free(&p->matchFinderBase, allocBig);
++  LzmaEnc_FreeLits(p, alloc);
++  RangeEnc_Free(&p->rc, alloc);
++}
++
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
++  alloc->Free(alloc, p);
++}
++
++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
++{
++  UInt32 nowPos32, startPos32;
++  if (p->inStream != 0)
++  {
++    p->matchFinderBase.stream = p->inStream;
++    p->matchFinder.Init(p->matchFinderObj);
++    p->inStream = 0;
++  }
++
++  if (p->finished)
++    return p->result;
++  RINOK(CheckErrors(p));
++
++  nowPos32 = (UInt32)p->nowPos64;
++  startPos32 = nowPos32;
++
++  if (p->nowPos64 == 0)
++  {
++    UInt32 numDistancePairs;
++    Byte curByte;
++    if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++      return Flush(p, nowPos32);
++    ReadMatchDistances(p, &numDistancePairs);
++    RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
++    p->state = kLiteralNextStates[p->state];
++    curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
++    LitEnc_Encode(&p->rc, p->litProbs, curByte);
++    p->additionalOffset--;
++    nowPos32++;
++  }
++
++  if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
++  for (;;)
++  {
++    UInt32 pos, len, posState;
++
++    if (p->fastMode)
++      len = GetOptimumFast(p, &pos);
++    else
++      len = GetOptimum(p, nowPos32, &pos);
++
++    #ifdef SHOW_STAT2
++    printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
++    #endif
++
++    posState = nowPos32 & p->pbMask;
++    if (len == 1 && pos == 0xFFFFFFFF)
++    {
++      Byte curByte;
++      CLzmaProb *probs;
++      const Byte *data;
++
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
++      data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++      curByte = *data;
++      probs = LIT_PROBS(nowPos32, *(data - 1));
++      if (IsCharState(p->state))
++        LitEnc_Encode(&p->rc, probs, curByte);
++      else
++        LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
++      p->state = kLiteralNextStates[p->state];
++    }
++    else
++    {
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++      if (pos < LZMA_NUM_REPS)
++      {
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
++        if (pos == 0)
++        {
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
++          RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
++        }
++        else
++        {
++          UInt32 distance = p->reps[pos];
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
++          if (pos == 1)
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
++          else
++          {
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
++            if (pos == 3)
++              p->reps[3] = p->reps[2];
++            p->reps[2] = p->reps[1];
++          }
++          p->reps[1] = p->reps[0];
++          p->reps[0] = distance;
++        }
++        if (len == 1)
++          p->state = kShortRepNextStates[p->state];
++        else
++        {
++          LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++          p->state = kRepNextStates[p->state];
++        }
++      }
++      else
++      {
++        UInt32 posSlot;
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++        p->state = kMatchNextStates[p->state];
++        LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++        pos -= LZMA_NUM_REPS;
++        GetPosSlot(pos, posSlot);
++        RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
++        
++        if (posSlot >= kStartPosModelIndex)
++        {
++          UInt32 footerBits = ((posSlot >> 1) - 1);
++          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++          UInt32 posReduced = pos - base;
++
++          if (posSlot < kEndPosModelIndex)
++            RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
++          else
++          {
++            RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
++            RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
++            p->alignPriceCount++;
++          }
++        }
++        p->reps[3] = p->reps[2];
++        p->reps[2] = p->reps[1];
++        p->reps[1] = p->reps[0];
++        p->reps[0] = pos;
++        p->matchPriceCount++;
++      }
++    }
++    p->additionalOffset -= len;
++    nowPos32 += len;
++    if (p->additionalOffset == 0)
++    {
++      UInt32 processed;
++      if (!p->fastMode)
++      {
++        if (p->matchPriceCount >= (1 << 7))
++          FillDistancesPrices(p);
++        if (p->alignPriceCount >= kAlignTableSize)
++          FillAlignPrices(p);
++      }
++      if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++        break;
++      processed = nowPos32 - startPos32;
++      if (useLimits)
++      {
++        if (processed + kNumOpts + 300 >= maxUnpackSize ||
++            RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
++          break;
++      }
++      else if (processed >= (1 << 15))
++      {
++        p->nowPos64 += nowPos32 - startPos32;
++        return CheckErrors(p);
++      }
++    }
++  }
++  p->nowPos64 += nowPos32 - startPos32;
++  return Flush(p, nowPos32);
++}
++
++#define kBigHashDicLimit ((UInt32)1 << 24)
++
++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 beforeSize = kNumOpts;
++  Bool btMode;
++  if (!RangeEnc_Alloc(&p->rc, alloc))
++    return SZ_ERROR_MEM;
++  btMode = (p->matchFinderBase.btMode != 0);
++  #ifdef COMPRESS_MF_MT
++  p->mtMode = (p->multiThread && !p->fastMode && btMode);
++  #endif
++
++  {
++    unsigned lclp = p->lc + p->lp;
++    if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
++    {
++      LzmaEnc_FreeLits(p, alloc);
++      p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      if (p->litProbs == 0 || p->saveState.litProbs == 0)
++      {
++        LzmaEnc_FreeLits(p, alloc);
++        return SZ_ERROR_MEM;
++      }
++      p->lclp = lclp;
++    }
++  }
++
++  p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
++
++  if (beforeSize + p->dictSize < keepWindowSize)
++    beforeSize = keepWindowSize - p->dictSize;
++
++  #ifdef COMPRESS_MF_MT
++  if (p->mtMode)
++  {
++    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
++    p->matchFinderObj = &p->matchFinderMt;
++    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
++  }
++  else
++  #endif
++  {
++    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
++      return SZ_ERROR_MEM;
++    p->matchFinderObj = &p->matchFinderBase;
++    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
++  }
++  return SZ_OK;
++}
++
++void LzmaEnc_Init(CLzmaEnc *p)
++{
++  UInt32 i;
++  p->state = 0;
++  for(i = 0 ; i < LZMA_NUM_REPS; i++)
++    p->reps[i] = 0;
++
++  RangeEnc_Init(&p->rc);
++
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    UInt32 j;
++    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
++    {
++      p->isMatch[i][j] = kProbInitValue;
++      p->isRep0Long[i][j] = kProbInitValue;
++    }
++    p->isRep[i] = kProbInitValue;
++    p->isRepG0[i] = kProbInitValue;
++    p->isRepG1[i] = kProbInitValue;
++    p->isRepG2[i] = kProbInitValue;
++  }
++
++  {
++    UInt32 num = 0x300 << (p->lp + p->lc);
++    for (i = 0; i < num; i++)
++      p->litProbs[i] = kProbInitValue;
++  }
++
++  {
++    for (i = 0; i < kNumLenToPosStates; i++)
++    {
++      CLzmaProb *probs = p->posSlotEncoder[i];
++      UInt32 j;
++      for (j = 0; j < (1 << kNumPosSlotBits); j++)
++        probs[j] = kProbInitValue;
++    }
++  }
++  {
++    for(i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
++      p->posEncoders[i] = kProbInitValue;
++  }
++
++  LenEnc_Init(&p->lenEnc.p);
++  LenEnc_Init(&p->repLenEnc.p);
++
++  for (i = 0; i < (1 << kNumAlignBits); i++)
++    p->posAlignEncoder[i] = kProbInitValue;
++
++  p->longestMatchWasFound = False;
++  p->optimumEndIndex = 0;
++  p->optimumCurrentIndex = 0;
++  p->additionalOffset = 0;
++
++  p->pbMask = (1 << p->pb) - 1;
++  p->lpMask = (1 << p->lp) - 1;
++}
++
++void LzmaEnc_InitPrices(CLzmaEnc *p)
++{
++  if (!p->fastMode)
++  {
++    FillDistancesPrices(p);
++    FillAlignPrices(p);
++  }
++
++  p->lenEnc.tableSize = 
++  p->repLenEnc.tableSize = 
++      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
++  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
++  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
++}
++
++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 i;
++  for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
++    if (p->dictSize <= ((UInt32)1 << i))
++      break;
++  p->distTableSize = i * 2;
++
++  p->finished = False;
++  p->result = SZ_OK;
++  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
++  LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  p->nowPos64 = 0;
++  return SZ_OK;
++}
++
++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqInStream *inStream, ISeqOutStream *outStream,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->inStream = inStream;
++  p->rc.outStream = outStream;
++  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
++}
++
++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, 
++    ISeqInStream *inStream, UInt32 keepWindowSize,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->inStream = inStream;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
++{
++  p->seqBufInStream.funcTable.Read = MyRead;
++  p->seqBufInStream.data = src;
++  p->seqBufInStream.rem = srcLen;
++}
++
++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++    UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++  p->inStream = &p->seqBufInStream.funcTable;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++void LzmaEnc_Finish(CLzmaEncHandle pp)
++{
++  #ifdef COMPRESS_MF_MT
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  if (p->mtMode)
++    MatchFinderMt_ReleaseStream(&p->matchFinderMt);
++  #endif
++}
++
++typedef struct _CSeqOutStreamBuf
++{
++  ISeqOutStream funcTable;
++  Byte *data;
++  SizeT rem;
++  Bool overflow;
++} CSeqOutStreamBuf;
++
++static size_t MyWrite(void *pp, const void *data, size_t size)
++{
++  CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
++  if (p->rem < size)
++  {
++    size = p->rem;
++    p->overflow = True;
++  }
++  memcpy(p->data, data, size);
++  p->rem -= size;
++  p->data += size;
++  return size;
++}
++
++
++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++}
++
++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++}
++
++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, 
++    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  UInt64 nowPos64;
++  SRes res;
++  CSeqOutStreamBuf outStream;
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = False;
++  p->finished = False;
++  p->result = SZ_OK;
++
++  if (reInit)
++    LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  nowPos64 = p->nowPos64;
++  RangeEnc_Init(&p->rc);
++  p->rc.outStream = &outStream.funcTable;
++
++  res = LzmaEnc_CodeOneBlock(pp, True, desiredPackSize, *unpackSize);
++  
++  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++
++  return res;
++}
++
++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  SRes res = SZ_OK;
++
++  #ifdef COMPRESS_MF_MT
++  Byte allocaDummy[0x300];
++  int i = 0;
++  for (i = 0; i < 16; i++)
++    allocaDummy[i] = (Byte)i;
++  #endif
++
++  RINOK(LzmaEnc_Prepare(pp, inStream, outStream, alloc, allocBig));
++
++  for (;;)
++  {
++    res = LzmaEnc_CodeOneBlock(pp, False, 0, 0);
++    if (res != SZ_OK || p->finished != 0)
++      break;
++    if (progress != 0)
++    {
++      res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
++      if (res != SZ_OK)
++      {
++        res = SZ_ERROR_PROGRESS;
++        break;
++      }
++    }
++  }
++  LzmaEnc_Finish(pp);
++  return res;
++}
++
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  int i;
++  UInt32 dictSize = p->dictSize;
++  if (*size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_PARAM;
++  *size = LZMA_PROPS_SIZE;
++  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
++
++  for (i = 11; i <= 30; i++)
++  {
++    if (dictSize <= ((UInt32)2 << i))
++    {
++      dictSize = (2 << i);
++      break;
++    }
++    if (dictSize <= ((UInt32)3 << i))
++    {
++      dictSize = (3 << i);
++      break;
++    }
++  }
++
++  for (i = 0; i < 4; i++)
++    props[1 + i] = (Byte)(dictSize >> (8 * i));
++  return SZ_OK;
++}
++
++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  SRes res;
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++
++  CSeqOutStreamBuf outStream;
++
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = writeEndMark;
++  res = LzmaEnc_Encode(pp, &outStream.funcTable, &p->seqBufInStream.funcTable, 
++      progress, alloc, allocBig);
++
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++  return res;
++}
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, 
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
++  SRes res;
++  if (p == 0)
++    return SZ_ERROR_MEM;
++
++  res = LzmaEnc_SetProps(p, props);
++  if (res == SZ_OK)
++  {
++    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
++    if (res == SZ_OK)
++      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
++          writeEndMark, progress, alloc, allocBig);
++  }
++
++  LzmaEnc_Destroy(p, alloc, allocBig);
++  return res;
++}
+--- a/mkfs.jffs2.c
++++ b/mkfs.jffs2.c
+@@ -1659,11 +1659,11 @@ int main(int argc, char **argv)
+ 						  }
+ 						  erase_block_size *= units;
+ 
+-						  /* If it's less than 8KiB, they're not allowed */
+-						  if (erase_block_size < 0x2000) {
+-							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
++						  /* If it's less than 4KiB, they're not allowed */
++						  if (erase_block_size < 0x1000) {
++							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 4KiB minimum\n",
+ 									  erase_block_size);
+-							  erase_block_size = 0x2000;
++							  erase_block_size = 0x1000;
+ 						  }
+ 						  break;
+ 					  }
diff --git a/package/utils/nvram/Makefile b/package/utils/nvram/Makefile
new file mode 100644
index 0000000000..acefe8aec1
--- /dev/null
+++ b/package/utils/nvram/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=nvram
+PKG_RELEASE:=10
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/nvram
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=Userspace port of the Broadcom NVRAM manipulation tool
+  MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+  DEPENDS:=@TARGET_brcm47xx||@TARGET_bcm53xx||@TARGET_ar71xx
+endef
+
+define Package/nvram/description
+ This package contains an utility to manipulate NVRAM on Broadcom based devices.
+ It works on bcm47xx (Linux 2.6) without using the kernel api.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall" \
+		LDFLAGS="$(TARGET_LDFLAGS)"
+endef
+
+define Package/nvram/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/nvram $(1)/usr/sbin/
+ifneq ($(CONFIG_TARGET_brcm47xx),)
+	$(INSTALL_DIR) $(1)/etc/init.d
+	$(INSTALL_BIN) ./files/nvram.init $(1)/etc/init.d/nvram
+endif
+endef
+
+$(eval $(call BuildPackage,nvram))
diff --git a/package/utils/nvram/files/nvram.init b/package/utils/nvram/files/nvram.init
new file mode 100755
index 0000000000..467ab28195
--- /dev/null
+++ b/package/utils/nvram/files/nvram.init
@@ -0,0 +1,98 @@
+#!/bin/sh /etc/rc.common
+# NVRAM setup
+#
+# This file handles the NVRAM quirks of various hardware.
+
+START=02
+alias debug=${DEBUG:-:}
+
+nvram_default() {
+	[ -z "$(nvram get $1)" ] && nvram set "$1=$2"
+}
+
+nvram_set() { # for the linksys fixup part
+	[ "$(nvram get "$1")" = "$2" -a "$2" != "" ] || {
+		COMMIT=1
+		/usr/sbin/nvram set "$1=$2"
+	}
+}
+
+fixup_linksys() {
+	# work around braindead CFE defaults in linksys routers
+	boardtype=$(nvram get boardtype)
+	boardnum=$(nvram get boardnum)
+	boardflags=$(($(nvram get boardflags)))
+	adm_switch="$(( ($boardflags & 0x80) >> 7 ))"
+
+	[ -n "$(nvram get vxkilled)" ] && boardtype=0 # don't mess with the ram settings on the hacked cfe
+	case "$(( $boardtype ))" in
+		"1800") #0x708
+			if [ "$adm_switch" = 0 ]; then
+				nvram_set sdram_init "$(printf 0x%04x $(( $(/usr/sbin/nvram get sdram_init) | 0x0100 )))"
+				[ "$COMMIT" = 1 ] && {
+					nvram_set clkfreq 216
+					nvram_set sdram_ncdl 0x0
+					nvram_set pa0itssit 62
+					nvram_set pa0b0 0x15eb
+					nvram_set pa0b1 0xfa82
+					nvram_set pa0b2 0xfe66
+					nvram_set pa0maxpwr 0x4e
+				}
+			fi
+		;;
+		"1127") #0x467
+			nvram_set sdram_init "$(printf 0x%04x $(( $(/usr/sbin/nvram get sdram_init) | 0x0100 )))"
+			[ "$COMMIT" = 1 ] && {
+				nvram_set sdram_ncdl 0x0
+				nvram_set pa0itssit 62
+				nvram_set pa0b0 0x168b
+				nvram_set pa0b1 0xfabf
+				nvram_set pa0b2 0xfeaf
+				nvram_set pa0maxpwr 0x4e
+			}
+		;;
+		"1071") #0x042f
+			# do sanity check first! max 0x0011 = 128mb
+			SDRAM_INIT=$(printf %d $(/usr/sbin/nvram get sdram_init))
+			[ "$SDRAM_INIT" -lt "9" -o "$SDRAM_INIT" -gt "17" ] && {
+				# set this to default: 0x09 only if value is invaild like 16MB on Asus WL-500GP
+				echo "sdram_init is invaild: $(printf 0x%04x $SDRAM_INIT), force to default!"
+				nvram_set sdram_init 0x0009
+			}
+			# on WRT54G3GV2 set flag, so checksum errors of firmware image 2 don't stop the boot process
+			noset_try_flag=$(nvram get noset_try_flag)
+			[ "$noset_try_flag" = 0 ] && {
+				echo "setting noset_try_flag to 1."
+				nvram_set noset_try_flag 1
+			}
+			[ "$COMMIT" = 1 ] && {
+				nvram_set sdram_ncdl 0x0
+			}
+	esac
+}
+
+start() {
+	# Don't do any fixups on the WGT634U
+	[ "$(cat /proc/diag/model)" = "Netgear WGT634U" ] && return
+
+	fixup_linksys
+
+	# OFDM Power Offset is set incorrectly on many boards.
+	# Setting it to 0 will increase the tx power to normal levels.
+	nvram_set opo 0x0
+
+	[ "$(nvram get il0macaddr)" = "00:90:4c:5f:00:2a" ] && {
+		# if default wifi mac, set two higher than the lan mac
+		nvram set il0macaddr=$(nvram get et0macaddr|
+		awk '{OFS=FS=":";for(x=7,y=2;--x;){$x=sprintf("%02x",(y+="0x"$x)%256);y/=256}print}')
+	}
+
+	[ "$(nvram get et0macaddr)" = "00:90:4c:c0:00:08" ] && {
+		# OvisLink WL-1600GL mac workaround
+		nvram set et0macaddr=$(hexdump -n 6 -s 130976 -e '5/1 "%02x:" "%02x" ' /dev/mtd/0)
+		nvram set il0macaddr=$(nvram get et0macaddr|
+		awk '{OFS=FS=":";for(x=7,y=2;--x;){$x=sprintf("%02x",(y+="0x"$x)%256);y/=256}print}')
+	}
+
+	[ "$COMMIT" = "1" ] && nvram commit
+}
diff --git a/package/utils/nvram/src/Makefile b/package/utils/nvram/src/Makefile
new file mode 100644
index 0000000000..68a6354c00
--- /dev/null
+++ b/package/utils/nvram/src/Makefile
@@ -0,0 +1,7 @@
+all: nvram
+
+nvram:
+	$(CC) $(CFLAGS) -o $@ cli.c crc.c nvram.c $(LDFLAGS)
+
+clean:
+	rm -f nvram
diff --git a/package/utils/nvram/src/cli.c b/package/utils/nvram/src/cli.c
new file mode 100644
index 0000000000..488d641cfc
--- /dev/null
+++ b/package/utils/nvram/src/cli.c
@@ -0,0 +1,246 @@
+/*
+ * Command line interface for libnvram
+ *
+ * Copyright 2009, Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * The libnvram code is based on Broadcom code for Linux 2.4.x .
+ *
+ */
+
+#include "nvram.h"
+
+
+static nvram_handle_t * nvram_open_rdonly(void)
+{
+	const char *file = nvram_find_staging();
+
+	if( file == NULL )
+		file = nvram_find_mtd();
+
+	if( file != NULL )
+		return nvram_open(file, NVRAM_RO);
+
+	return NULL;
+}
+
+static nvram_handle_t * nvram_open_staging(void)
+{
+	if( nvram_find_staging() != NULL || nvram_to_staging() == 0 )
+		return nvram_open(NVRAM_STAGING, NVRAM_RW);
+
+	return NULL;
+}
+
+static int do_show(nvram_handle_t *nvram)
+{
+	nvram_tuple_t *t;
+	int stat = 1;
+
+	if( (t = nvram_getall(nvram)) != NULL )
+	{
+		while( t )
+		{
+			printf("%s=%s\n", t->name, t->value);
+			t = t->next;
+		}
+
+		stat = 0;
+	}
+
+	return stat;
+}
+
+static int do_get(nvram_handle_t *nvram, const char *var)
+{
+	const char *val;
+	int stat = 1;
+
+	if( (val = nvram_get(nvram, var)) != NULL )
+	{
+		printf("%s\n", val);
+		stat = 0;
+	}
+
+	return stat;
+}
+
+static int do_unset(nvram_handle_t *nvram, const char *var)
+{
+	return nvram_unset(nvram, var);
+}
+
+static int do_set(nvram_handle_t *nvram, const char *pair)
+{
+	char *val = strstr(pair, "=");
+	char var[strlen(pair)];
+	int stat = 1;
+
+	if( val != NULL )
+	{
+		memset(var, 0, sizeof(var));
+		strncpy(var, pair, (int)(val-pair));
+		stat = nvram_set(nvram, var, (char *)(val + 1));
+	}
+
+	return stat;
+}
+
+static int do_info(nvram_handle_t *nvram)
+{
+	nvram_header_t *hdr = nvram_header(nvram);
+
+	/* CRC8 over the last 11 bytes of the header and data bytes */
+	uint8_t crc = hndcrc8((unsigned char *) &hdr[0] + NVRAM_CRC_START_POSITION,
+		hdr->len - NVRAM_CRC_START_POSITION, 0xff);
+
+	/* Show info */
+	printf("Magic:         0x%08X\n",   hdr->magic);
+	printf("Length:        0x%08X\n",   hdr->len);
+	printf("Offset:        0x%08X\n",   nvram->offset);
+
+	printf("CRC8:          0x%02X (calculated: 0x%02X)\n",
+		hdr->crc_ver_init & 0xFF, crc);
+
+	printf("Version:       0x%02X\n",   (hdr->crc_ver_init >> 8) & 0xFF);
+	printf("SDRAM init:    0x%04X\n",   (hdr->crc_ver_init >> 16) & 0xFFFF);
+	printf("SDRAM config:  0x%04X\n",   hdr->config_refresh & 0xFFFF);
+	printf("SDRAM refresh: 0x%04X\n",   (hdr->config_refresh >> 16) & 0xFFFF);
+	printf("NCDL values:   0x%08X\n\n", hdr->config_ncdl);
+
+	printf("%i bytes used / %i bytes available (%.2f%%)\n",
+		hdr->len, nvram->length - nvram->offset - hdr->len,
+		(100.00 / (double)(nvram->length - nvram->offset)) * (double)hdr->len);
+
+	return 0;
+}
+
+
+int main( int argc, const char *argv[] )
+{
+	nvram_handle_t *nvram;
+	int commit = 0;
+	int write = 0;
+	int stat = 1;
+	int done = 0;
+	int i;
+
+	/* Ugly... iterate over arguments to see whether we can expect a write */
+	for( i = 1; i < argc; i++ )
+		if( ( !strcmp(argv[i], "set")   && ++i < argc ) ||
+			( !strcmp(argv[i], "unset") && ++i < argc ) ||
+			!strcmp(argv[i], "commit") )
+		{
+			write = 1;
+			break;
+		}
+
+
+	nvram = write ? nvram_open_staging() : nvram_open_rdonly();
+
+	if( nvram != NULL && argc > 1 )
+	{
+		for( i = 1; i < argc; i++ )
+		{
+			if( !strcmp(argv[i], "show") )
+			{
+				stat = do_show(nvram);
+				done++;
+			}
+			else if( !strcmp(argv[i], "info") )
+			{
+				stat = do_info(nvram);
+				done++;
+			}
+			else if( !strcmp(argv[i], "get") || !strcmp(argv[i], "unset") || !strcmp(argv[i], "set") )
+			{
+				if( (i+1) < argc )
+				{
+					switch(argv[i++][0])
+					{
+						case 'g':
+							stat = do_get(nvram, argv[i]);
+							break;
+
+						case 'u':
+							stat = do_unset(nvram, argv[i]);
+							break;
+
+						case 's':
+							stat = do_set(nvram, argv[i]);
+							break;
+					}
+					done++;
+				}
+				else
+				{
+					fprintf(stderr, "Command '%s' requires an argument!\n", argv[i]);
+					done = 0;
+					break;
+				}
+			}
+			else if( !strcmp(argv[i], "commit") )
+			{
+				commit = 1;
+				done++;
+			}
+			else
+			{
+				fprintf(stderr, "Unknown option '%s' !\n", argv[i]);
+				done = 0;
+				break;
+			}
+		}
+
+		if( write )
+			stat = nvram_commit(nvram);
+
+		nvram_close(nvram);
+
+		if( commit )
+			stat = staging_to_nvram();
+	}
+
+	if( !nvram )
+	{
+		fprintf(stderr,
+			"Could not open nvram! Possible reasons are:\n"
+			"	- No device found (/proc not mounted or no nvram present)\n"
+			"	- Insufficient permissions to open mtd device\n"
+			"	- Insufficient memory to complete operation\n"
+			"	- Memory mapping failed or not supported\n"
+		);
+
+		stat = 1;
+	}
+	else if( !done )
+	{
+		fprintf(stderr,
+			"Usage:\n"
+			"	nvram show\n"
+			"	nvram info\n"
+			"	nvram get variable\n"
+			"	nvram set variable=value [set ...]\n"
+			"	nvram unset variable [unset ...]\n"
+			"	nvram commit\n"
+		);
+
+		stat = 1;
+	}
+
+	return stat;
+}
diff --git a/package/utils/nvram/src/crc.c b/package/utils/nvram/src/crc.c
new file mode 100644
index 0000000000..22a36652aa
--- /dev/null
+++ b/package/utils/nvram/src/crc.c
@@ -0,0 +1,69 @@
+#include "nvram.h"
+
+/*******************************************************************************
+ * crc8
+ *
+ * Computes a crc8 over the input data using the polynomial:
+ *
+ *       x^8 + x^7 +x^6 + x^4 + x^2 + 1
+ *
+ * The caller provides the initial value (either CRC8_INIT_VALUE
+ * or the previous returned value) to allow for processing of
+ * discontiguous blocks of data.  When generating the CRC the
+ * caller is responsible for complementing the final return value
+ * and inserting it into the byte stream.  When checking, a final
+ * return value of CRC8_GOOD_VALUE indicates a valid CRC.
+ *
+ * Reference: Dallas Semiconductor Application Note 27
+ *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
+ *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
+ *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
+ *
+ * ****************************************************************************
+ */
+
+static const uint8_t crc8_table[256] = {
+	0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+	0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+	0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+	0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+	0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+	0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+	0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+	0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+	0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+	0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+	0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+	0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+	0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+	0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+	0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+	0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+	0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+	0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+	0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+	0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+	0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+	0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+	0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+	0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+	0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+	0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+	0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+	0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+	0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+	0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+	0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+	0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
+};
+
+uint8_t hndcrc8 (
+	uint8_t * pdata,  /* pointer to array of data to process */
+	uint32_t nbytes,  /* number of input data bytes to process */
+	uint8_t crc       /* either CRC8_INIT_VALUE or previous return value */
+) {
+	while (nbytes-- > 0)
+		crc = crc8_table[(crc ^ *pdata++) & 0xff];
+
+	return crc;
+}
diff --git a/package/utils/nvram/src/nvram.c b/package/utils/nvram/src/nvram.c
new file mode 100644
index 0000000000..0e4294391a
--- /dev/null
+++ b/package/utils/nvram/src/nvram.c
@@ -0,0 +1,540 @@
+/*
+ * NVRAM variable manipulation (common)
+ *
+ * Copyright 2004, Broadcom Corporation
+ * Copyright 2009-2010, OpenWrt.org
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#include "nvram.h"
+
+#define TRACE(msg) \
+	printf("%s(%i) in %s(): %s\n", \
+		__FILE__, __LINE__, __FUNCTION__, msg ? msg : "?")
+
+/* Size of "nvram" MTD partition */
+size_t nvram_part_size = 0;
+
+
+/*
+ * -- Helper functions --
+ */
+
+/* String hash */
+static uint32_t hash(const char *s)
+{
+	uint32_t hash = 0;
+
+	while (*s)
+		hash = 31 * hash + *s++;
+
+	return hash;
+}
+
+/* Free all tuples. */
+static void _nvram_free(nvram_handle_t *h)
+{
+	uint32_t i;
+	nvram_tuple_t *t, *next;
+
+	/* Free hash table */
+	for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
+		for (t = h->nvram_hash[i]; t; t = next) {
+			next = t->next;
+			free(t);
+		}
+		h->nvram_hash[i] = NULL;
+	}
+
+	/* Free dead table */
+	for (t = h->nvram_dead; t; t = next) {
+		next = t->next;
+		free(t);
+	}
+
+	h->nvram_dead = NULL;
+}
+
+/* (Re)allocate NVRAM tuples. */
+static nvram_tuple_t * _nvram_realloc( nvram_handle_t *h, nvram_tuple_t *t,
+	const char *name, const char *value )
+{
+	if ((strlen(value) + 1) > h->length - h->offset)
+		return NULL;
+
+	if (!t) {
+		if (!(t = malloc(sizeof(nvram_tuple_t) + strlen(name) + 1)))
+			return NULL;
+
+		/* Copy name */
+		t->name = (char *) &t[1];
+		strcpy(t->name, name);
+
+		t->value = NULL;
+	}
+
+	/* Copy value */
+	if (!t->value || strcmp(t->value, value))
+	{
+		if(!(t->value = (char *) realloc(t->value, strlen(value)+1)))
+			return NULL;
+
+		strcpy(t->value, value);
+		t->value[strlen(value)] = '\0';
+	}
+
+	return t;
+}
+
+/* (Re)initialize the hash table. */
+static int _nvram_rehash(nvram_handle_t *h)
+{
+	nvram_header_t *header = nvram_header(h);
+	char buf[] = "0xXXXXXXXX", *name, *value, *eq;
+
+	/* (Re)initialize hash table */
+	_nvram_free(h);
+
+	/* Parse and set "name=value\0 ... \0\0" */
+	name = (char *) &header[1];
+
+	for (; *name; name = value + strlen(value) + 1) {
+		if (!(eq = strchr(name, '=')))
+			break;
+		*eq = '\0';
+		value = eq + 1;
+		nvram_set(h, name, value);
+		*eq = '=';
+	}
+
+	/* Set special SDRAM parameters */
+	if (!nvram_get(h, "sdram_init")) {
+		sprintf(buf, "0x%04X", (uint16_t)(header->crc_ver_init >> 16));
+		nvram_set(h, "sdram_init", buf);
+	}
+	if (!nvram_get(h, "sdram_config")) {
+		sprintf(buf, "0x%04X", (uint16_t)(header->config_refresh & 0xffff));
+		nvram_set(h, "sdram_config", buf);
+	}
+	if (!nvram_get(h, "sdram_refresh")) {
+		sprintf(buf, "0x%04X",
+			(uint16_t)((header->config_refresh >> 16) & 0xffff));
+		nvram_set(h, "sdram_refresh", buf);
+	}
+	if (!nvram_get(h, "sdram_ncdl")) {
+		sprintf(buf, "0x%08X", header->config_ncdl);
+		nvram_set(h, "sdram_ncdl", buf);
+	}
+
+	return 0;
+}
+
+
+/*
+ * -- Public functions --
+ */
+
+/* Get nvram header. */
+nvram_header_t * nvram_header(nvram_handle_t *h)
+{
+	return (nvram_header_t *) &h->mmap[h->offset];
+}
+
+/* Get the value of an NVRAM variable. */
+char * nvram_get(nvram_handle_t *h, const char *name)
+{
+	uint32_t i;
+	nvram_tuple_t *t;
+	char *value;
+
+	if (!name)
+		return NULL;
+
+	/* Hash the name */
+	i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
+
+	/* Find the associated tuple in the hash table */
+	for (t = h->nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
+
+	value = t ? t->value : NULL;
+
+	return value;
+}
+
+/* Set the value of an NVRAM variable. */
+int nvram_set(nvram_handle_t *h, const char *name, const char *value)
+{
+	uint32_t i;
+	nvram_tuple_t *t, *u, **prev;
+
+	/* Hash the name */
+	i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
+
+	/* Find the associated tuple in the hash table */
+	for (prev = &h->nvram_hash[i], t = *prev;
+		 t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
+	/* (Re)allocate tuple */
+	if (!(u = _nvram_realloc(h, t, name, value)))
+		return -12; /* -ENOMEM */
+
+	/* Value reallocated */
+	if (t && t == u)
+		return 0;
+
+	/* Move old tuple to the dead table */
+	if (t) {
+		*prev = t->next;
+		t->next = h->nvram_dead;
+		h->nvram_dead = t;
+	}
+
+	/* Add new tuple to the hash table */
+	u->next = h->nvram_hash[i];
+	h->nvram_hash[i] = u;
+
+	return 0;
+}
+
+/* Unset the value of an NVRAM variable. */
+int nvram_unset(nvram_handle_t *h, const char *name)
+{
+	uint32_t i;
+	nvram_tuple_t *t, **prev;
+
+	if (!name)
+		return 0;
+
+	/* Hash the name */
+	i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
+
+	/* Find the associated tuple in the hash table */
+	for (prev = &h->nvram_hash[i], t = *prev;
+		 t && strcmp(t->name, name); prev = &t->next, t = *prev);
+
+	/* Move it to the dead table */
+	if (t) {
+		*prev = t->next;
+		t->next = h->nvram_dead;
+		h->nvram_dead = t;
+	}
+
+	return 0;
+}
+
+/* Get all NVRAM variables. */
+nvram_tuple_t * nvram_getall(nvram_handle_t *h)
+{
+	int i;
+	nvram_tuple_t *t, *l, *x;
+
+	l = NULL;
+
+	for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
+		for (t = h->nvram_hash[i]; t; t = t->next) {
+			if( (x = (nvram_tuple_t *) malloc(sizeof(nvram_tuple_t))) != NULL )
+			{
+				x->name  = t->name;
+				x->value = t->value;
+				x->next  = l;
+				l = x;
+			}
+			else
+			{
+				break;
+			}
+		}
+	}
+
+	return l;
+}
+
+/* Regenerate NVRAM. */
+int nvram_commit(nvram_handle_t *h)
+{
+	nvram_header_t *header = nvram_header(h);
+	char *init, *config, *refresh, *ncdl;
+	char *ptr, *end;
+	int i;
+	nvram_tuple_t *t;
+	nvram_header_t tmp;
+	uint8_t crc;
+
+	/* Regenerate header */
+	header->magic = NVRAM_MAGIC;
+	header->crc_ver_init = (NVRAM_VERSION << 8);
+	if (!(init = nvram_get(h, "sdram_init")) ||
+		!(config = nvram_get(h, "sdram_config")) ||
+		!(refresh = nvram_get(h, "sdram_refresh")) ||
+		!(ncdl = nvram_get(h, "sdram_ncdl"))) {
+		header->crc_ver_init |= SDRAM_INIT << 16;
+		header->config_refresh = SDRAM_CONFIG;
+		header->config_refresh |= SDRAM_REFRESH << 16;
+		header->config_ncdl = 0;
+	} else {
+		header->crc_ver_init |= (strtoul(init, NULL, 0) & 0xffff) << 16;
+		header->config_refresh = strtoul(config, NULL, 0) & 0xffff;
+		header->config_refresh |= (strtoul(refresh, NULL, 0) & 0xffff) << 16;
+		header->config_ncdl = strtoul(ncdl, NULL, 0);
+	}
+
+	/* Clear data area */
+	ptr = (char *) header + sizeof(nvram_header_t);
+	memset(ptr, 0xFF, nvram_part_size - h->offset - sizeof(nvram_header_t));
+	memset(&tmp, 0, sizeof(nvram_header_t));
+
+	/* Leave space for a double NUL at the end */
+	end = (char *) header + nvram_part_size - h->offset - 2;
+
+	/* Write out all tuples */
+	for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
+		for (t = h->nvram_hash[i]; t; t = t->next) {
+			if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
+				break;
+			ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
+		}
+	}
+
+	/* End with a double NULL and pad to 4 bytes */
+	*ptr = '\0';
+	ptr++;
+
+	if( (int)ptr % 4 )
+		memset(ptr, 0, 4 - ((int)ptr % 4));
+
+	ptr++;
+
+	/* Set new length */
+	header->len = NVRAM_ROUNDUP(ptr - (char *) header, 4);
+
+	/* Little-endian CRC8 over the last 11 bytes of the header */
+	tmp.crc_ver_init   = header->crc_ver_init;
+	tmp.config_refresh = header->config_refresh;
+	tmp.config_ncdl    = header->config_ncdl;
+	crc = hndcrc8((unsigned char *) &tmp + NVRAM_CRC_START_POSITION,
+		sizeof(nvram_header_t) - NVRAM_CRC_START_POSITION, 0xff);
+
+	/* Continue CRC8 over data bytes */
+	crc = hndcrc8((unsigned char *) &header[0] + sizeof(nvram_header_t),
+		header->len - sizeof(nvram_header_t), crc);
+
+	/* Set new CRC8 */
+	header->crc_ver_init |= crc;
+
+	/* Write out */
+	msync(h->mmap, h->length, MS_SYNC);
+	fsync(h->fd);
+
+	/* Reinitialize hash table */
+	return _nvram_rehash(h);
+}
+
+/* Open NVRAM and obtain a handle. */
+nvram_handle_t * nvram_open(const char *file, int rdonly)
+{
+	int i;
+	int fd;
+	char *mtd = NULL;
+	nvram_handle_t *h;
+	nvram_header_t *header;
+	int offset = -1;
+
+	/* If erase size or file are undefined then try to define them */
+	if( (nvram_part_size == 0) || (file == NULL) )
+	{
+		/* Finding the mtd will set the appropriate erase size */
+		if( (mtd = nvram_find_mtd()) == NULL || nvram_part_size == 0 )
+		{
+			free(mtd);
+			return NULL;
+		}
+	}
+
+	if( (fd = open(file ? file : mtd, O_RDWR)) > -1 )
+	{
+		char *mmap_area = (char *) mmap(
+			NULL, nvram_part_size, PROT_READ | PROT_WRITE,
+			(( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED) | MAP_LOCKED, fd, 0);
+
+		if( mmap_area != MAP_FAILED )
+		{
+			/*
+			 * Start looking for NVRAM_MAGIC at beginning of MTD
+			 * partition. Stop if there is less than NVRAM_MIN_SPACE
+			 * to check, that was the lowest used size.
+			 */
+			for( i = 0; i <= ((nvram_part_size - NVRAM_MIN_SPACE) / sizeof(uint32_t)); i++ )
+			{
+				if( ((uint32_t *)mmap_area)[i] == NVRAM_MAGIC )
+				{
+					offset = i * sizeof(uint32_t);
+					break;
+				}
+			}
+
+			if( offset < 0 )
+			{
+				free(mtd);
+				return NULL;
+			}
+			else if( (h = malloc(sizeof(nvram_handle_t))) != NULL )
+			{
+				memset(h, 0, sizeof(nvram_handle_t));
+
+				h->fd     = fd;
+				h->mmap   = mmap_area;
+				h->length = nvram_part_size;
+				h->offset = offset;
+
+				header = nvram_header(h);
+
+				if (header->magic == NVRAM_MAGIC &&
+				    (rdonly || header->len < h->length - h->offset)) {
+					_nvram_rehash(h);
+					free(mtd);
+					return h;
+				}
+				else
+				{
+					munmap(h->mmap, h->length);
+					free(h);
+				}
+			}
+		}
+	}
+
+	free(mtd);
+	return NULL;
+}
+
+/* Close NVRAM and free memory. */
+int nvram_close(nvram_handle_t *h)
+{
+	_nvram_free(h);
+	munmap(h->mmap, h->length);
+	close(h->fd);
+	free(h);
+
+	return 0;
+}
+
+/* Determine NVRAM device node. */
+char * nvram_find_mtd(void)
+{
+	FILE *fp;
+	int i, part_size;
+	char dev[PATH_MAX];
+	char *path = NULL;
+	struct stat s;
+
+	if ((fp = fopen("/proc/mtd", "r")))
+	{
+		while( fgets(dev, sizeof(dev), fp) )
+		{
+			if( strstr(dev, "nvram") && sscanf(dev, "mtd%d: %08x", &i, &part_size) )
+			{
+				nvram_part_size = part_size;
+
+				sprintf(dev, "/dev/mtdblock%d", i);
+				if( stat(dev, &s) > -1 && (s.st_mode & S_IFBLK) )
+				{
+					if( (path = (char *) malloc(strlen(dev)+1)) != NULL )
+					{
+						strncpy(path, dev, strlen(dev)+1);
+						break;
+					}
+				}
+			}
+		}
+		fclose(fp);
+	}
+
+	return path;
+}
+
+/* Check NVRAM staging file. */
+char * nvram_find_staging(void)
+{
+	struct stat s;
+
+	if( (stat(NVRAM_STAGING, &s) > -1) && (s.st_mode & S_IFREG) )
+	{
+		return NVRAM_STAGING;
+	}
+
+	return NULL;
+}
+
+/* Copy NVRAM contents to staging file. */
+int nvram_to_staging(void)
+{
+	int fdmtd, fdstg, stat;
+	char *mtd = nvram_find_mtd();
+	char buf[nvram_part_size];
+
+	stat = -1;
+
+	if( (mtd != NULL) && (nvram_part_size > 0) )
+	{
+		if( (fdmtd = open(mtd, O_RDONLY)) > -1 )
+		{
+			if( read(fdmtd, buf, sizeof(buf)) == sizeof(buf) )
+			{
+				if((fdstg = open(NVRAM_STAGING, O_WRONLY | O_CREAT, 0600)) > -1)
+				{
+					write(fdstg, buf, sizeof(buf));
+					fsync(fdstg);
+					close(fdstg);
+
+					stat = 0;
+				}
+			}
+
+			close(fdmtd);
+		}
+	}
+
+	free(mtd);
+	return stat;
+}
+
+/* Copy staging file to NVRAM device. */
+int staging_to_nvram(void)
+{
+	int fdmtd, fdstg, stat;
+	char *mtd = nvram_find_mtd();
+	char buf[nvram_part_size];
+
+	stat = -1;
+
+	if( (mtd != NULL) && (nvram_part_size > 0) )
+	{
+		if( (fdstg = open(NVRAM_STAGING, O_RDONLY)) > -1 )
+		{
+			if( read(fdstg, buf, sizeof(buf)) == sizeof(buf) )
+			{
+				if( (fdmtd = open(mtd, O_WRONLY | O_SYNC)) > -1 )
+				{
+					write(fdmtd, buf, sizeof(buf));
+					fsync(fdmtd);
+					close(fdmtd);
+					stat = 0;
+				}
+			}
+
+			close(fdstg);
+
+			if( !stat )
+				stat = unlink(NVRAM_STAGING) ? 1 : 0;
+		}
+	}
+
+	free(mtd);
+	return stat;
+}
diff --git a/package/utils/nvram/src/nvram.h b/package/utils/nvram/src/nvram.h
new file mode 100644
index 0000000000..724f33b811
--- /dev/null
+++ b/package/utils/nvram/src/nvram.h
@@ -0,0 +1,123 @@
+/*
+ * NVRAM variable manipulation
+ *
+ * Copyright 2007, Broadcom Corporation
+ * Copyright 2009, OpenWrt.org
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#ifndef _nvram_h_
+#define _nvram_h_
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <linux/limits.h>
+
+#include "sdinitvals.h"
+
+
+struct nvram_header {
+	uint32_t magic;
+	uint32_t len;
+	uint32_t crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+	uint32_t config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
+	uint32_t config_ncdl;	/* ncdl values for memc */
+} __attribute__((__packed__));
+
+struct nvram_tuple {
+	char *name;
+	char *value;
+	struct nvram_tuple *next;
+};
+
+struct nvram_handle {
+	int fd;
+	char *mmap;
+	unsigned int length;
+	unsigned int offset;
+	struct nvram_tuple *nvram_hash[257];
+	struct nvram_tuple *nvram_dead;
+};
+
+typedef struct nvram_handle nvram_handle_t;
+typedef struct nvram_header nvram_header_t;
+typedef struct nvram_tuple  nvram_tuple_t;
+
+
+/* Get nvram header. */
+nvram_header_t * nvram_header(nvram_handle_t *h);
+
+/* Set the value of an NVRAM variable */
+int nvram_set(nvram_handle_t *h, const char *name, const char *value);
+
+/* Get the value of an NVRAM variable. */
+char * nvram_get(nvram_handle_t *h, const char *name);
+
+/* Unset the value of an NVRAM variable. */
+int nvram_unset(nvram_handle_t *h, const char *name);
+
+/* Get all NVRAM variables. */
+nvram_tuple_t * nvram_getall(nvram_handle_t *h);
+
+/* Regenerate NVRAM. */
+int nvram_commit(nvram_handle_t *h);
+
+/* Open NVRAM and obtain a handle. */
+nvram_handle_t * nvram_open(const char *file, int rdonly);
+
+/* Close NVRAM and free memory. */
+int nvram_close(nvram_handle_t *h);
+
+/* Get the value of an NVRAM variable in a safe way, use "" instead of NULL. */
+#define nvram_safe_get(h, name) (nvram_get(h, name) ? : "")
+
+/* Computes a crc8 over the input data. */
+uint8_t hndcrc8 (uint8_t * pdata, uint32_t nbytes, uint8_t crc);
+
+/* Returns the crc value of the nvram. */
+uint8_t nvram_calc_crc(nvram_header_t * nvh);
+
+/* Determine NVRAM device node. */
+char * nvram_find_mtd(void);
+
+/* Copy NVRAM contents to staging file. */
+int nvram_to_staging(void);
+
+/* Copy staging file to NVRAM device. */
+int staging_to_nvram(void);
+
+/* Check NVRAM staging file. */
+char * nvram_find_staging(void);
+
+
+/* Staging file for NVRAM */
+#define NVRAM_STAGING		"/tmp/.nvram"
+#define NVRAM_RO			1
+#define NVRAM_RW			0
+
+/* Helper macros */
+#define NVRAM_ARRAYSIZE(a)	sizeof(a)/sizeof(a[0])
+#define	NVRAM_ROUNDUP(x, y)	((((x)+((y)-1))/(y))*(y))
+
+/* NVRAM constants */
+#define NVRAM_MIN_SPACE			0x8000
+#define NVRAM_MAGIC			0x48534C46	/* 'FLSH' */
+#define NVRAM_VERSION		1
+
+#define NVRAM_CRC_START_POSITION	9 /* magic, len, crc8 to be skipped */
+
+
+#endif /* _nvram_h_ */
diff --git a/package/utils/nvram/src/sdinitvals.h b/package/utils/nvram/src/sdinitvals.h
new file mode 100644
index 0000000000..5a289adece
--- /dev/null
+++ b/package/utils/nvram/src/sdinitvals.h
@@ -0,0 +1,30 @@
+/*
+ * SDRAM init values
+ *
+ * Copyright 2007, Broadcom Corporation
+ * Copyright 2009, OpenWrt.org
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ */
+
+#ifndef _sdinitvals_h_
+#define _sdinitvals_h_
+
+/* SDRAM refresh control (refresh) register bits */
+#define SDRAM_REF(p)    (((p)&0xff) | SDRAM_REF_EN)     /* Refresh period */
+#define SDRAM_REF_EN    0x8000          /* Writing 1 enables periodic refresh */
+
+/* SDRAM Core default Init values (OCP ID 0x803) */
+#define MEM4MX16X2      0x419   /* 16 MB */
+
+#define SDRAM_INIT	MEM4MX16X2
+#define SDRAM_BURSTFULL 0x0000  /* Use full page bursts */
+#define SDRAM_CONFIG    SDRAM_BURSTFULL
+#define SDRAM_REFRESH   SDRAM_REF(0x40)
+
+#endif /* _sdinitvals_h_ */
diff --git a/package/utils/osafeloader/Makefile b/package/utils/osafeloader/Makefile
new file mode 100644
index 0000000000..883d7ae603
--- /dev/null
+++ b/package/utils/osafeloader/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=osafeloader
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/osafeloader
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=Utility for handling TP-LINK SafeLoader images
+  MAINTAINER:=Rafał Miłecki <rafal@milecki.pl>
+  DEPENDS:=@TARGET_bcm53xx
+endef
+
+define Package/osafeloader/description
+ This package contains an utility that allows handling SafeLoader images.
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall"
+endef
+
+define Package/osafeloader/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/osafeloader $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,osafeloader))
diff --git a/package/utils/osafeloader/src/Makefile b/package/utils/osafeloader/src/Makefile
new file mode 100644
index 0000000000..acc6f0fe65
--- /dev/null
+++ b/package/utils/osafeloader/src/Makefile
@@ -0,0 +1,7 @@
+all: osafeloader
+
+osafeloader:
+	$(CC) $(CFLAGS) -Wall osafeloader.c md5.c -o $@ $^
+
+clean:
+	rm -f osafeloader
diff --git a/package/utils/osafeloader/src/md5.c b/package/utils/osafeloader/src/md5.c
new file mode 100644
index 0000000000..52d96accd3
--- /dev/null
+++ b/package/utils/osafeloader/src/md5.c
@@ -0,0 +1,296 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's.  No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible.  Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#ifndef HAVE_OPENSSL
+
+#include <string.h>
+
+#include "md5.h"
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z)			((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)			((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z)			(((x) ^ (y)) ^ (z))
+#define H2(x, y, z)			((x) ^ ((y) ^ (z)))
+#define I(x, y, z)			((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+	(a) += f((b), (c), (d)) + (x) + (t); \
+	(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+	(a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+	(*(MD5_u32plus *)&ptr[(n) * 4])
+#define GET(n) \
+	SET(n)
+#else
+#define SET(n) \
+	(ctx->block[(n)] = \
+	(MD5_u32plus)ptr[(n) * 4] | \
+	((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+	((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+	((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+	(ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There are no alignment requirements.
+ */
+static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+	const unsigned char *ptr;
+	MD5_u32plus a, b, c, d;
+	MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+	ptr = (const unsigned char *)data;
+
+	a = ctx->a;
+	b = ctx->b;
+	c = ctx->c;
+	d = ctx->d;
+
+	do {
+		saved_a = a;
+		saved_b = b;
+		saved_c = c;
+		saved_d = d;
+
+/* Round 1 */
+		STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+		STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+		STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+		STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+		STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+		STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+		STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+		STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+		STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+		STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+		STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+		STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+		STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+		STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+		STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+		STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+		STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+		STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+		STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+		STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+		STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+		STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+		STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+		STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+		STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+		STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+		STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+		STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+		STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+		STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+		STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+		STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+		STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+		STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+		STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+		STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+		STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+		STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+		STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+		STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+		STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+		STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+		STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+		STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+		STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+		STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+		STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+		STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+		STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+		STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+		STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+		STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+		STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+		STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+		STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+		STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+		STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+		STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+		STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+		STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+		STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+		STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+		STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+		STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+		a += saved_a;
+		b += saved_b;
+		c += saved_c;
+		d += saved_d;
+
+		ptr += 64;
+	} while (size -= 64);
+
+	ctx->a = a;
+	ctx->b = b;
+	ctx->c = c;
+	ctx->d = d;
+
+	return ptr;
+}
+
+void MD5_Init(MD5_CTX *ctx)
+{
+	ctx->a = 0x67452301;
+	ctx->b = 0xefcdab89;
+	ctx->c = 0x98badcfe;
+	ctx->d = 0x10325476;
+
+	ctx->lo = 0;
+	ctx->hi = 0;
+}
+
+void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+	MD5_u32plus saved_lo;
+	unsigned long used, available;
+
+	saved_lo = ctx->lo;
+	if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+		ctx->hi++;
+	ctx->hi += size >> 29;
+
+	used = saved_lo & 0x3f;
+
+	if (used) {
+		available = 64 - used;
+
+		if (size < available) {
+			memcpy(&ctx->buffer[used], data, size);
+			return;
+		}
+
+		memcpy(&ctx->buffer[used], data, available);
+		data = (const unsigned char *)data + available;
+		size -= available;
+		body(ctx, ctx->buffer, 64);
+	}
+
+	if (size >= 64) {
+		data = body(ctx, data, size & ~(unsigned long)0x3f);
+		size &= 0x3f;
+	}
+
+	memcpy(ctx->buffer, data, size);
+}
+
+void MD5_Final(unsigned char *result, MD5_CTX *ctx)
+{
+	unsigned long used, available;
+
+	used = ctx->lo & 0x3f;
+
+	ctx->buffer[used++] = 0x80;
+
+	available = 64 - used;
+
+	if (available < 8) {
+		memset(&ctx->buffer[used], 0, available);
+		body(ctx, ctx->buffer, 64);
+		used = 0;
+		available = 64;
+	}
+
+	memset(&ctx->buffer[used], 0, available - 8);
+
+	ctx->lo <<= 3;
+	ctx->buffer[56] = ctx->lo;
+	ctx->buffer[57] = ctx->lo >> 8;
+	ctx->buffer[58] = ctx->lo >> 16;
+	ctx->buffer[59] = ctx->lo >> 24;
+	ctx->buffer[60] = ctx->hi;
+	ctx->buffer[61] = ctx->hi >> 8;
+	ctx->buffer[62] = ctx->hi >> 16;
+	ctx->buffer[63] = ctx->hi >> 24;
+
+	body(ctx, ctx->buffer, 64);
+
+	result[0] = ctx->a;
+	result[1] = ctx->a >> 8;
+	result[2] = ctx->a >> 16;
+	result[3] = ctx->a >> 24;
+	result[4] = ctx->b;
+	result[5] = ctx->b >> 8;
+	result[6] = ctx->b >> 16;
+	result[7] = ctx->b >> 24;
+	result[8] = ctx->c;
+	result[9] = ctx->c >> 8;
+	result[10] = ctx->c >> 16;
+	result[11] = ctx->c >> 24;
+	result[12] = ctx->d;
+	result[13] = ctx->d >> 8;
+	result[14] = ctx->d >> 16;
+	result[15] = ctx->d >> 24;
+
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif
diff --git a/package/utils/osafeloader/src/md5.h b/package/utils/osafeloader/src/md5.h
new file mode 100644
index 0000000000..2da44bf355
--- /dev/null
+++ b/package/utils/osafeloader/src/md5.h
@@ -0,0 +1,45 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
+ */
+
+#ifdef HAVE_OPENSSL
+#include <openssl/md5.h>
+#elif !defined(_MD5_H)
+#define _MD5_H
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+typedef struct {
+	MD5_u32plus lo, hi;
+	MD5_u32plus a, b, c, d;
+	unsigned char buffer[64];
+	MD5_u32plus block[16];
+} MD5_CTX;
+
+extern void MD5_Init(MD5_CTX *ctx);
+extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
+extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
+
+#endif
diff --git a/package/utils/osafeloader/src/osafeloader.c b/package/utils/osafeloader/src/osafeloader.c
new file mode 100644
index 0000000000..9ffa5fe3cf
--- /dev/null
+++ b/package/utils/osafeloader/src/osafeloader.c
@@ -0,0 +1,263 @@
+/*
+ * osafeloader
+ *
+ * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * 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 <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "md5.h"
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x)	(x)
+#define be32_to_cpu(x)	(x)
+#define cpu_to_be16(x)	(x)
+#define be16_to_cpu(x)	(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_be32(x)	bswap_32(x)
+#define be32_to_cpu(x)	bswap_32(x)
+#define cpu_to_be16(x)	bswap_16(x)
+#define be16_to_cpu(x)	bswap_16(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+struct safeloader_header {
+	uint32_t imagesize;
+	uint8_t md5[16];
+} __attribute__ ((packed));
+
+char *safeloader_path;
+char *partition_name;
+char *out_path;
+
+static inline size_t osafeloader_min(size_t x, size_t y) {
+	return x < y ? x : y;
+}
+
+static const uint8_t md5_salt[16] = {
+	0x7a, 0x2b, 0x15, 0xed,
+	0x9b, 0x98, 0x59, 0x6d,
+	0xe5, 0x04, 0xab, 0x44,
+	0xac, 0x2a, 0x9f, 0x4e,
+};
+
+/**************************************************
+ * Info
+ **************************************************/
+
+static int osafeloader_info(int argc, char **argv) {
+	FILE *safeloader;
+	struct safeloader_header hdr;
+	MD5_CTX ctx;
+	size_t bytes, imagesize;
+	uint8_t buf[1024];
+	uint8_t md5[16];
+	char name[32];
+	int base, size, i;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No SafeLoader file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	safeloader_path = argv[2];
+
+	safeloader = fopen(safeloader_path, "r");
+	if (!safeloader) {
+		fprintf(stderr, "Couldn't open %s\n", safeloader_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	bytes = fread(&hdr, 1, sizeof(hdr), safeloader);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", safeloader_path);
+		err =  -EIO;
+		goto err_close;
+	}
+	imagesize = be32_to_cpu(hdr.imagesize);
+
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, md5_salt, sizeof(md5_salt));
+	while ((bytes = fread(buf, 1, osafeloader_min(sizeof(buf), imagesize), safeloader)) > 0) {
+		MD5_Update(&ctx, buf, bytes);
+		imagesize -= bytes;
+	}
+	MD5_Final(md5, &ctx);
+
+	if (memcmp(md5, hdr.md5, 16)) {
+		fprintf(stderr, "Broken SafeLoader file with invalid MD5\n");
+		err =  -EIO;
+		goto err_close;
+	}
+
+	printf("%10s: %d\n", "Image size", be32_to_cpu(hdr.imagesize));
+	printf("%10s: ", "MD5");
+	for (i = 0; i < 16; i++)
+		printf("%02x", md5[i]);
+	printf("\n");
+
+	/* Skip header & vendor info */
+	fseek(safeloader, 0x1014, SEEK_SET);
+
+	while (fscanf(safeloader, "fwup-ptn %s base 0x%x size 0x%x\t\r\n", name, &base, &size) == 3) {
+		printf("%10s: %s (0x%x - 0x%x)\n", "Partition", name, base, base + size);
+	}
+
+err_close:
+	fclose(safeloader);
+out:
+	return err;
+}
+
+/**************************************************
+ * Extract
+ **************************************************/
+
+static void osafeloader_extract_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "p:o:")) != -1) {
+		switch (c) {
+		case 'p':
+			partition_name = optarg;
+			break;
+		case 'o':
+			out_path = optarg;
+			break;
+		}
+	}
+}
+
+static int osafeloader_extract(int argc, char **argv) {
+	FILE *safeloader;
+	FILE *out;
+	struct safeloader_header hdr;
+	size_t bytes;
+	char name[32];
+	int base, size;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No SafeLoader file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	safeloader_path = argv[2];
+
+	optind = 3;
+	osafeloader_extract_parse_options(argc, argv);
+	if (!partition_name) {
+		fprintf(stderr, "No partition name specified\n");
+		err = -EINVAL;
+		goto out;
+	} else if (!out_path) {
+		fprintf(stderr, "No output file specified\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	safeloader = fopen(safeloader_path, "r");
+	if (!safeloader) {
+		fprintf(stderr, "Couldn't open %s\n", safeloader_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	out = fopen(out_path, "w");
+	if (!out) {
+		fprintf(stderr, "Couldn't open %s\n", out_path);
+		err = -EACCES;
+		goto err_close_safeloader;
+	}
+
+	bytes = fread(&hdr, 1, sizeof(hdr), safeloader);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", safeloader_path);
+		err =  -EIO;
+		goto err_close_out;
+	}
+
+	/* Skip vendor info */
+	fseek(safeloader, 0x1000, SEEK_CUR);
+
+	err = -ENOENT;
+	while (fscanf(safeloader, "fwup-ptn %s base 0x%x size 0x%x\t\r\n", name, &base, &size) == 3) {
+		uint8_t buf[1024];
+
+		if (strcmp(name, partition_name))
+			continue;
+
+		err = 0;
+
+		fseek(safeloader, sizeof(hdr) + 0x1000 + base, SEEK_SET);
+
+		while ((bytes = fread(buf, 1, osafeloader_min(sizeof(buf), size), safeloader)) > 0) {
+			if (fwrite(buf, 1, bytes, out) != bytes) {
+				fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+				err = -EIO;
+				break;
+			}
+			size -= bytes;
+		}
+
+		if (size) {
+			fprintf(stderr, "Couldn't extract whole partition %s from %s (%d B left)\n", partition_name, safeloader_path, size);
+			err = -EIO;
+		}
+
+		break;
+	}
+
+err_close_out:
+	fclose(out);
+err_close_safeloader:
+	fclose(safeloader);
+out:
+	return err;
+}
+
+/**************************************************
+ * Start
+ **************************************************/
+
+static void usage() {
+	printf("Usage:\n");
+	printf("\n");
+	printf("Info about SafeLoader:\n");
+	printf("\tosafeloader info <file>\n");
+	printf("\n");
+	printf("Extract from SafeLoader:\n");
+	printf("\tosafeloader extract <file> [options]\n");
+	printf("\t-p name\t\t\t\tname of partition to extract\n");
+	printf("\t-o file\t\t\t\toutput file\n");
+}
+
+int main(int argc, char **argv) {
+	if (argc > 1) {
+		if (!strcmp(argv[1], "info"))
+			return osafeloader_info(argc, argv);
+		else if (!strcmp(argv[1], "extract"))
+			return osafeloader_extract(argc, argv);
+	}
+
+	usage();
+	return 0;
+}
diff --git a/package/utils/oseama/Makefile b/package/utils/oseama/Makefile
new file mode 100644
index 0000000000..7d9303b92d
--- /dev/null
+++ b/package/utils/oseama/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=oseama
+PKG_RELEASE:=1
+
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/oseama
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=Utility for handling Seama firmware images
+  MAINTAINER:=Rafał Miłecki <zajec5@gmail.com>
+  DEPENDS:=@TARGET_bcm53xx
+endef
+
+define Package/oseama/description
+ This package contains an utility that allows handling Seama images.
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall"
+endef
+
+define Package/oseama/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/oseama $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,oseama))
diff --git a/package/utils/oseama/src/Makefile b/package/utils/oseama/src/Makefile
new file mode 100644
index 0000000000..ca35e6ee99
--- /dev/null
+++ b/package/utils/oseama/src/Makefile
@@ -0,0 +1,7 @@
+all: oseama
+
+oseama:
+	$(CC) $(CFLAGS) -Wall oseama.c md5.c -o $@ $^
+
+clean:
+	rm -f oseama
diff --git a/package/utils/oseama/src/md5.c b/package/utils/oseama/src/md5.c
new file mode 100644
index 0000000000..52d96accd3
--- /dev/null
+++ b/package/utils/oseama/src/md5.c
@@ -0,0 +1,296 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's.  No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible.  Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#ifndef HAVE_OPENSSL
+
+#include <string.h>
+
+#include "md5.h"
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z)			((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)			((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z)			(((x) ^ (y)) ^ (z))
+#define H2(x, y, z)			((x) ^ ((y) ^ (z)))
+#define I(x, y, z)			((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+	(a) += f((b), (c), (d)) + (x) + (t); \
+	(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+	(a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+	(*(MD5_u32plus *)&ptr[(n) * 4])
+#define GET(n) \
+	SET(n)
+#else
+#define SET(n) \
+	(ctx->block[(n)] = \
+	(MD5_u32plus)ptr[(n) * 4] | \
+	((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+	((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+	((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+	(ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There are no alignment requirements.
+ */
+static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+	const unsigned char *ptr;
+	MD5_u32plus a, b, c, d;
+	MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+	ptr = (const unsigned char *)data;
+
+	a = ctx->a;
+	b = ctx->b;
+	c = ctx->c;
+	d = ctx->d;
+
+	do {
+		saved_a = a;
+		saved_b = b;
+		saved_c = c;
+		saved_d = d;
+
+/* Round 1 */
+		STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+		STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+		STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+		STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+		STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+		STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+		STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+		STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+		STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+		STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+		STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+		STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+		STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+		STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+		STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+		STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+		STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+		STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+		STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+		STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+		STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+		STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+		STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+		STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+		STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+		STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+		STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+		STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+		STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+		STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+		STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+		STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+		STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+		STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+		STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+		STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+		STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+		STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+		STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+		STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+		STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+		STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+		STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+		STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+		STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+		STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+		STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+		STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+		STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+		STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+		STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+		STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+		STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+		STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+		STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+		STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+		STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+		STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+		STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+		STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+		STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+		STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+		STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+		STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+		a += saved_a;
+		b += saved_b;
+		c += saved_c;
+		d += saved_d;
+
+		ptr += 64;
+	} while (size -= 64);
+
+	ctx->a = a;
+	ctx->b = b;
+	ctx->c = c;
+	ctx->d = d;
+
+	return ptr;
+}
+
+void MD5_Init(MD5_CTX *ctx)
+{
+	ctx->a = 0x67452301;
+	ctx->b = 0xefcdab89;
+	ctx->c = 0x98badcfe;
+	ctx->d = 0x10325476;
+
+	ctx->lo = 0;
+	ctx->hi = 0;
+}
+
+void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+	MD5_u32plus saved_lo;
+	unsigned long used, available;
+
+	saved_lo = ctx->lo;
+	if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+		ctx->hi++;
+	ctx->hi += size >> 29;
+
+	used = saved_lo & 0x3f;
+
+	if (used) {
+		available = 64 - used;
+
+		if (size < available) {
+			memcpy(&ctx->buffer[used], data, size);
+			return;
+		}
+
+		memcpy(&ctx->buffer[used], data, available);
+		data = (const unsigned char *)data + available;
+		size -= available;
+		body(ctx, ctx->buffer, 64);
+	}
+
+	if (size >= 64) {
+		data = body(ctx, data, size & ~(unsigned long)0x3f);
+		size &= 0x3f;
+	}
+
+	memcpy(ctx->buffer, data, size);
+}
+
+void MD5_Final(unsigned char *result, MD5_CTX *ctx)
+{
+	unsigned long used, available;
+
+	used = ctx->lo & 0x3f;
+
+	ctx->buffer[used++] = 0x80;
+
+	available = 64 - used;
+
+	if (available < 8) {
+		memset(&ctx->buffer[used], 0, available);
+		body(ctx, ctx->buffer, 64);
+		used = 0;
+		available = 64;
+	}
+
+	memset(&ctx->buffer[used], 0, available - 8);
+
+	ctx->lo <<= 3;
+	ctx->buffer[56] = ctx->lo;
+	ctx->buffer[57] = ctx->lo >> 8;
+	ctx->buffer[58] = ctx->lo >> 16;
+	ctx->buffer[59] = ctx->lo >> 24;
+	ctx->buffer[60] = ctx->hi;
+	ctx->buffer[61] = ctx->hi >> 8;
+	ctx->buffer[62] = ctx->hi >> 16;
+	ctx->buffer[63] = ctx->hi >> 24;
+
+	body(ctx, ctx->buffer, 64);
+
+	result[0] = ctx->a;
+	result[1] = ctx->a >> 8;
+	result[2] = ctx->a >> 16;
+	result[3] = ctx->a >> 24;
+	result[4] = ctx->b;
+	result[5] = ctx->b >> 8;
+	result[6] = ctx->b >> 16;
+	result[7] = ctx->b >> 24;
+	result[8] = ctx->c;
+	result[9] = ctx->c >> 8;
+	result[10] = ctx->c >> 16;
+	result[11] = ctx->c >> 24;
+	result[12] = ctx->d;
+	result[13] = ctx->d >> 8;
+	result[14] = ctx->d >> 16;
+	result[15] = ctx->d >> 24;
+
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif
diff --git a/package/utils/oseama/src/md5.h b/package/utils/oseama/src/md5.h
new file mode 100644
index 0000000000..2da44bf355
--- /dev/null
+++ b/package/utils/oseama/src/md5.h
@@ -0,0 +1,45 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
+ */
+
+#ifdef HAVE_OPENSSL
+#include <openssl/md5.h>
+#elif !defined(_MD5_H)
+#define _MD5_H
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+typedef struct {
+	MD5_u32plus lo, hi;
+	MD5_u32plus a, b, c, d;
+	unsigned char buffer[64];
+	MD5_u32plus block[16];
+} MD5_CTX;
+
+extern void MD5_Init(MD5_CTX *ctx);
+extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
+extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
+
+#endif
diff --git a/package/utils/oseama/src/oseama.c b/package/utils/oseama/src/oseama.c
new file mode 100644
index 0000000000..4434b11162
--- /dev/null
+++ b/package/utils/oseama/src/oseama.c
@@ -0,0 +1,556 @@
+/*
+ * oseama
+ *
+ * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "md5.h"
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x)	(x)
+#define be32_to_cpu(x)	(x)
+#define cpu_to_be16(x)	(x)
+#define be16_to_cpu(x)	(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_be32(x)	bswap_32(x)
+#define be32_to_cpu(x)	bswap_32(x)
+#define cpu_to_be16(x)	bswap_16(x)
+#define be16_to_cpu(x)	bswap_16(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define SEAMA_MAGIC			0x5ea3a417
+
+struct seama_seal_header {
+	uint32_t magic;
+	uint16_t reserved;
+	uint16_t metasize;
+	uint32_t imagesize;
+} __attribute__ ((packed));
+
+struct seama_entity_header {
+	uint32_t magic;
+	uint16_t reserved;
+	uint16_t metasize;
+	uint32_t imagesize;
+	uint8_t md5[16];
+} __attribute__ ((packed));
+
+char *seama_path;
+int entity_idx = -1;
+char *out_path;
+
+static inline size_t oseama_min(size_t x, size_t y) {
+	return x < y ? x : y;
+}
+
+/**************************************************
+ * Info
+ **************************************************/
+
+static void oseama_info_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "e:")) != -1) {
+		switch (c) {
+		case 'e':
+			entity_idx = atoi(optarg);
+			break;
+		}
+	}
+}
+
+static int oseama_info_entities(FILE *seama) {
+	struct seama_entity_header hdr;
+	size_t bytes, metasize, imagesize;
+	uint8_t buf[1024];
+	char *end, *tmp;
+	int i = 0;
+	int err = 0;
+
+	while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
+		if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+			fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+			err =  -EINVAL;
+			goto err_out;
+		}
+		metasize = be16_to_cpu(hdr.metasize);
+		imagesize = be32_to_cpu(hdr.imagesize);
+
+		if (entity_idx >= 0 && i != entity_idx) {
+			fseek(seama, metasize + imagesize, SEEK_CUR);
+			i++;
+			continue;
+		}
+
+		if (metasize >= sizeof(buf)) {
+			fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
+			err =  -EINVAL;
+			goto err_out;
+		}
+
+		if (entity_idx < 0)
+			printf("\n");
+		printf("Entity offset:\t%ld\n", ftell(seama) - sizeof(hdr));
+		printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
+		printf("Meta size:\t%zd\n", metasize);
+		printf("Image size:\t%zd\n", imagesize);
+
+		bytes = fread(buf, 1, metasize, seama);
+		if (bytes != metasize) {
+			fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
+			err =  -EIO;
+			goto err_out;
+		}
+
+		end = (char *)&buf[metasize - 1];
+		*end = '\0';
+		for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
+			printf("Meta entry:\t%s\n", tmp);
+		}
+
+		fseek(seama, imagesize, SEEK_CUR);
+		i++;
+	}
+
+err_out:
+	return err;
+}
+
+static int oseama_info(int argc, char **argv) {
+	FILE *seama;
+	struct seama_seal_header hdr;
+	size_t bytes;
+	uint16_t metasize;
+	uint32_t imagesize;
+	uint8_t buf[1024];
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No Seama file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	seama_path = argv[2];
+
+	optind = 3;
+	oseama_info_parse_options(argc, argv);
+
+	seama = fopen(seama_path, "r");
+	if (!seama) {
+		fprintf(stderr, "Couldn't open %s\n", seama_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	bytes = fread(&hdr, 1, sizeof(hdr), seama);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", seama_path);
+		err =  -EIO;
+		goto err_close;
+	}
+	metasize = be16_to_cpu(hdr.metasize);
+	imagesize = be32_to_cpu(hdr.imagesize);
+
+	if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+		fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	if (metasize >= sizeof(buf)) {
+		fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	if (imagesize) {
+		fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	bytes = fread(buf, 1, metasize, seama);
+	if (bytes != metasize) {
+		fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
+		err =  -EIO;
+		goto err_close;
+	}
+
+	if (entity_idx < 0) {
+		char *end, *tmp;
+
+		printf("Meta size:\t%d\n", metasize);
+		printf("Image size:\t%d\n", imagesize);
+
+		end = (char *)&buf[metasize - 1];
+		*end = '\0';
+		for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
+			printf("Meta entry:\t%s\n", tmp);
+		}
+	}
+
+	oseama_info_entities(seama);
+
+err_close:
+	fclose(seama);
+out:
+	return err;
+}
+
+/**************************************************
+ * Create
+ **************************************************/
+
+static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) {
+	FILE *in;
+	size_t bytes;
+	ssize_t length = 0;
+	uint8_t buf[128];
+
+	in = fopen(in_path, "r");
+	if (!in) {
+		fprintf(stderr, "Couldn't open %s\n", in_path);
+		return -EACCES;
+	}
+
+	while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (fwrite(buf, 1, bytes, seama) != bytes) {
+			fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path);
+			length = -EIO;
+			break;
+		}
+		length += bytes;
+	}
+
+	fclose(in);
+
+	return length;
+}
+
+static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) {
+	uint8_t *buf;
+
+	buf = malloc(length);
+	if (!buf)
+		return -ENOMEM;
+	memset(buf, 0, length);
+
+	if (fwrite(buf, 1, length, seama) != length) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path);
+		return -EIO;
+	}
+
+	return length;
+}
+
+static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) {
+	if (curr_offset & (alignment - 1)) {
+		size_t length = alignment - (curr_offset % alignment);
+
+		return oseama_entity_append_zeros(seama, length);
+	}
+
+	return 0;
+}
+
+static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) {
+	struct seama_entity_header hdr = {};
+	uint8_t buf[128];
+	size_t length = imagesize;
+	size_t bytes;
+	MD5_CTX ctx;
+
+	fseek(seama, sizeof(hdr) + metasize, SEEK_SET);
+	MD5_Init(&ctx);
+	while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
+		MD5_Update(&ctx, buf, bytes);
+		length -= bytes;
+	}
+	MD5_Final(hdr.md5, &ctx);
+
+	hdr.magic = cpu_to_be32(SEAMA_MAGIC);
+	hdr.metasize = cpu_to_be16(metasize);
+	hdr.imagesize = cpu_to_be32(imagesize);
+
+	fseek(seama, 0, SEEK_SET);
+	bytes = fwrite(&hdr, 1, sizeof(hdr), seama);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int oseama_entity(int argc, char **argv) {
+	FILE *seama;
+	ssize_t sbytes;
+	size_t curr_offset = sizeof(struct seama_entity_header);
+	size_t metasize = 0, imagesize = 0;
+	int c;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No Seama file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	seama_path = argv[2];
+
+	seama = fopen(seama_path, "w+");
+	if (!seama) {
+		fprintf(stderr, "Couldn't open %s\n", seama_path);
+		err = -EACCES;
+		goto out;
+	}
+	fseek(seama, curr_offset, SEEK_SET);
+
+	optind = 3;
+	while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
+		switch (c) {
+		case 'm':
+			sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to write meta %s\n", optarg);
+			} else {
+				curr_offset += sbytes;
+				metasize += sbytes;
+			}
+
+			sbytes = oseama_entity_align(seama, curr_offset, 4);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to append zeros\n");
+			} else {
+				curr_offset += sbytes;
+				metasize += sbytes;
+			}
+
+			break;
+		case 'f':
+		case 'b':
+			break;
+		}
+	}
+
+	optind = 3;
+	while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
+		switch (c) {
+		case 'm':
+			break;
+		case 'f':
+			sbytes = oseama_entity_append_file(seama, optarg);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to append file %s\n", optarg);
+			} else {
+				curr_offset += sbytes;
+				imagesize += sbytes;
+			}
+			break;
+		case 'b':
+			sbytes = strtol(optarg, NULL, 0) - curr_offset;
+			if (sbytes < 0) {
+				fprintf(stderr, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
+			} else {
+				sbytes = oseama_entity_append_zeros(seama, sbytes);
+				if (sbytes < 0) {
+					fprintf(stderr, "Failed to append zeros\n");
+				} else {
+					curr_offset += sbytes;
+					imagesize += sbytes;
+				}
+			}
+			break;
+		}
+		if (err)
+			break;
+	}
+
+	oseama_entity_write_hdr(seama, metasize, imagesize);
+
+	fclose(seama);
+out:
+	return err;
+}
+
+/**************************************************
+ * Extract
+ **************************************************/
+
+static void oseama_extract_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "e:o:")) != -1) {
+		switch (c) {
+		case 'e':
+			entity_idx = atoi(optarg);
+			break;
+		case 'o':
+			out_path = optarg;
+			break;
+		}
+	}
+}
+
+static int oseama_extract_entity(FILE *seama, FILE *out) {
+	struct seama_entity_header hdr;
+	size_t bytes, metasize, imagesize, length;
+	uint8_t buf[1024];
+	int i = 0;
+	int err = 0;
+
+	while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
+		if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+			fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+			err =  -EINVAL;
+			break;
+		}
+		metasize = be16_to_cpu(hdr.metasize);
+		imagesize = be32_to_cpu(hdr.imagesize);
+
+		if (i != entity_idx) {
+			fseek(seama, metasize + imagesize, SEEK_CUR);
+			i++;
+			continue;
+		}
+
+		fseek(seama, -sizeof(hdr), SEEK_CUR);
+
+		length = sizeof(hdr) + metasize + imagesize;
+		while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
+			if (fwrite(buf, 1, bytes, out) != bytes) {
+				fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+				err = -EIO;
+				break;
+			}
+			length -= bytes;
+		}
+
+		if (length) {
+			fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length);
+			err = -EIO;
+			break;
+		}
+
+		break;
+	}
+
+	return err;
+}
+
+static int oseama_extract(int argc, char **argv) {
+	FILE *seama;
+	FILE *out;
+	struct seama_seal_header hdr;
+	size_t bytes;
+	uint16_t metasize;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No Seama file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	seama_path = argv[2];
+
+	optind = 3;
+	oseama_extract_parse_options(argc, argv);
+	if (entity_idx < 0) {
+		fprintf(stderr, "No entity specified\n");
+		err = -EINVAL;
+		goto out;
+	} else if (!out_path) {
+		fprintf(stderr, "No output file specified\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	seama = fopen(seama_path, "r");
+	if (!seama) {
+		fprintf(stderr, "Couldn't open %s\n", seama_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	out = fopen(out_path, "w");
+	if (!out) {
+		fprintf(stderr, "Couldn't open %s\n", out_path);
+		err = -EACCES;
+		goto err_close_seama;
+	}
+
+	bytes = fread(&hdr, 1, sizeof(hdr), seama);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", seama_path);
+		err =  -EIO;
+		goto err_close_out;
+	}
+	metasize = be16_to_cpu(hdr.metasize);
+
+	fseek(seama, metasize, SEEK_CUR);
+
+	oseama_extract_entity(seama, out);
+
+err_close_out:
+	fclose(out);
+err_close_seama:
+	fclose(seama);
+out:
+	return err;
+}
+
+/**************************************************
+ * Start
+ **************************************************/
+
+static void usage() {
+	printf("Usage:\n");
+	printf("\n");
+	printf("Info about Seama seal (container):\n");
+	printf("\toseama info <file> [options]\n");
+	printf("\t-e\t\t\t\tprint info about specified entity only\n");
+	printf("\n");
+	printf("Create Seama entity:\n");
+	printf("\toseama entity <file> [options]\n");
+	printf("\t-m meta\t\t\t\tmeta into to put in header\n");
+	printf("\t-f file\t\t\t\tappend content from file\n");
+	printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
+	printf("\n");
+	printf("Extract from Seama seal (container):\n");
+	printf("\toseama extract <file> [options]\n");
+	printf("\t-e\t\t\t\tindex of entity to extract\n");
+	printf("\t-o file\t\t\t\toutput file\n");
+}
+
+int main(int argc, char **argv) {
+	if (argc > 1) {
+		if (!strcmp(argv[1], "info"))
+			return oseama_info(argc, argv);
+		else if (!strcmp(argv[1], "entity"))
+			return oseama_entity(argc, argv);
+		else if (!strcmp(argv[1], "extract"))
+			return oseama_extract(argc, argv);
+	}
+
+	usage();
+	return 0;
+}
diff --git a/package/utils/otrx/Makefile b/package/utils/otrx/Makefile
new file mode 100644
index 0000000000..9cb76c171b
--- /dev/null
+++ b/package/utils/otrx/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=otrx
+PKG_RELEASE:=1
+
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/otrx
+  SECTION:=utils
+  CATEGORY:=Base system
+  TITLE:=Utility for opening (analyzing) TRX firmware images
+  MAINTAINER:=Rafał Miłecki <zajec5@gmail.com>
+  DEPENDS:=@TARGET_brcm47xx||@TARGET_bcm53xx
+endef
+
+define Package/otrx/description
+ This package contains an utility that allows validating TRX images.
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" \
+		CFLAGS="$(TARGET_CFLAGS) -Wall"
+endef
+
+define Package/otrx/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/otrx $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,otrx))
diff --git a/package/utils/otrx/src/Makefile b/package/utils/otrx/src/Makefile
new file mode 100644
index 0000000000..df50ea446d
--- /dev/null
+++ b/package/utils/otrx/src/Makefile
@@ -0,0 +1,7 @@
+all: otrx
+
+otrx:
+	$(CC) $(CFLAGS) -o $@ otrx.c -Wall
+
+clean:
+	rm -f otrx
diff --git a/package/utils/otrx/src/otrx.c b/package/utils/otrx/src/otrx.c
new file mode 100644
index 0000000000..101a31004d
--- /dev/null
+++ b/package/utils/otrx/src/otrx.c
@@ -0,0 +1,577 @@
+/*
+ * otrx
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le32(x)	bswap_32(x)
+#define le32_to_cpu(x)	bswap_32(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le32(x)	(x)
+#define le32_to_cpu(x)	(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define TRX_MAGIC			0x30524448
+#define TRX_FLAGS_OFFSET		12
+#define TRX_MAX_PARTS			3
+
+struct trx_header {
+	uint32_t magic;
+	uint32_t length;
+	uint32_t crc32;
+	uint16_t flags;
+	uint16_t version;
+	uint32_t offset[3];
+};
+
+char *trx_path;
+size_t trx_offset = 0;
+char *partition[TRX_MAX_PARTS] = {};
+
+static inline size_t otrx_min(size_t x, size_t y) {
+	return x < y ? x : y;
+}
+
+/**************************************************
+ * CRC32
+ **************************************************/
+
+static const uint32_t crc32_tbl[] = {
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+uint32_t otrx_crc32(uint8_t *buf, size_t len) {
+	uint32_t crc = 0xffffffff;
+
+	while (len) {
+		crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+		buf++;
+		len--;
+	}
+
+	return crc;
+}
+
+/**************************************************
+ * Check
+ **************************************************/
+
+static void otrx_check_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "o:")) != -1) {
+		switch (c) {
+		case 'o':
+			trx_offset = atoi(optarg);
+			break;
+		}
+	}
+}
+
+static int otrx_check(int argc, char **argv) {
+	FILE *trx;
+	struct trx_header hdr;
+	size_t bytes, length;
+	uint8_t buf[1024];
+	uint32_t crc32;
+	int i;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No TRX file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	trx_path = argv[2];
+
+	optind = 3;
+	otrx_check_parse_options(argc, argv);
+
+	trx = fopen(trx_path, "r");
+	if (!trx) {
+		fprintf(stderr, "Couldn't open %s\n", trx_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	fseek(trx, trx_offset, SEEK_SET);
+	bytes = fread(&hdr, 1, sizeof(hdr), trx);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", trx_path);
+		err =  -EIO;
+		goto err_close;
+	}
+
+	if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
+		fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	length = le32_to_cpu(hdr.length);
+	if (length < sizeof(hdr)) {
+		fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
+		err = -EINVAL;
+		goto err_close;
+	}
+
+	crc32 = 0xffffffff;
+	fseek(trx, trx_offset + TRX_FLAGS_OFFSET, SEEK_SET);
+	length -= TRX_FLAGS_OFFSET;
+	while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
+		for (i = 0; i < bytes; i++)
+			crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
+		length -= bytes;
+	}
+
+	if (length) {
+		fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path);
+		err = -EIO;
+		goto err_close;
+	}
+
+	if (crc32 != le32_to_cpu(hdr.crc32)) {
+		fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
+
+err_close:
+	fclose(trx);
+out:
+	return err;
+}
+
+/**************************************************
+ * Create
+ **************************************************/
+
+static void otrx_create_parse_options(int argc, char **argv) {
+}
+
+static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
+	FILE *in;
+	size_t bytes;
+	ssize_t length = 0;
+	uint8_t buf[128];
+
+	in = fopen(in_path, "r");
+	if (!in) {
+		fprintf(stderr, "Couldn't open %s\n", in_path);
+		return -EACCES;
+	}
+
+	while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (fwrite(buf, 1, bytes, trx) != bytes) {
+			fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
+			length = -EIO;
+			break;
+		}
+		length += bytes;
+	}
+
+	fclose(in);
+
+	return length;
+}
+
+static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
+	uint8_t *buf;
+
+	buf = malloc(length);
+	if (!buf)
+		return -ENOMEM;
+	memset(buf, 0, length);
+
+	if (fwrite(buf, 1, length, trx) != length) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
+		return -EIO;
+	}
+
+	return length;
+}
+
+static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
+	if (curr_offset & (alignment - 1)) {
+		size_t length = alignment - (curr_offset % alignment);
+		return otrx_create_append_zeros(trx, length);
+	}
+
+	return 0;
+}
+
+static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
+	size_t bytes, length;
+	uint8_t *buf;
+	uint32_t crc32;
+
+	hdr->magic = cpu_to_le32(TRX_MAGIC);
+	hdr->version = 1;
+
+	fseek(trx, 0, SEEK_SET);
+	bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
+	if (bytes != sizeof(struct trx_header)) {
+		fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
+		return -EIO;
+	}
+
+	length = le32_to_cpu(hdr->length);
+
+	buf = malloc(length);
+	if (!buf) {
+		fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
+		return -ENOMEM;
+	}
+
+	fseek(trx, 0, SEEK_SET);
+	bytes = fread(buf, 1, length, trx);
+	if (bytes != length) {
+		fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
+		return -ENOMEM;
+	}
+
+	crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
+	hdr->crc32 = cpu_to_le32(crc32);
+
+	fseek(trx, 0, SEEK_SET);
+	bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
+	if (bytes != sizeof(struct trx_header)) {
+		fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int otrx_create(int argc, char **argv) {
+	FILE *trx;
+	struct trx_header hdr = {};
+	ssize_t sbytes;
+	size_t curr_idx = 0;
+	size_t curr_offset = sizeof(hdr);
+	int c;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No TRX file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	trx_path = argv[2];
+
+	optind = 3;
+	otrx_create_parse_options(argc, argv);
+
+	trx = fopen(trx_path, "w+");
+	if (!trx) {
+		fprintf(stderr, "Couldn't open %s\n", trx_path);
+		err = -EACCES;
+		goto out;
+	}
+	fseek(trx, curr_offset, SEEK_SET);
+
+	optind = 3;
+	while ((c = getopt(argc, argv, "f:b:")) != -1) {
+		switch (c) {
+		case 'f':
+			if (curr_idx >= TRX_MAX_PARTS) {
+				err = -ENOSPC;
+				fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
+				goto err_close;
+			}
+
+			sbytes = otrx_create_append_file(trx, optarg);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to append file %s\n", optarg);
+			} else {
+				hdr.offset[curr_idx++] = curr_offset;
+				curr_offset += sbytes;
+			}
+
+			sbytes = otrx_create_align(trx, curr_offset, 4);
+			if (sbytes < 0)
+				fprintf(stderr, "Failed to append zeros\n");
+			else
+				curr_offset += sbytes;
+
+			break;
+		case 'b':
+			sbytes = strtol(optarg, NULL, 0) - curr_offset;
+			if (sbytes < 0) {
+				fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
+			} else {
+				sbytes = otrx_create_append_zeros(trx, sbytes);
+				if (sbytes < 0)
+					fprintf(stderr, "Failed to append zeros\n");
+				else
+					curr_offset += sbytes;
+			}
+			break;
+		}
+		if (err)
+			break;
+	}
+
+	hdr.length = curr_offset;
+	otrx_create_write_hdr(trx, &hdr);
+err_close:
+	fclose(trx);
+out:
+	return err;
+}
+
+/**************************************************
+ * Extract
+ **************************************************/
+
+static void otrx_extract_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
+		switch (c) {
+		case 'o':
+			trx_offset = atoi(optarg);
+			break;
+		case '1':
+			partition[0] = optarg;
+			break;
+		case '2':
+			partition[1] = optarg;
+			break;
+		case '3':
+			partition[2] = optarg;
+			break;
+		}
+	}
+}
+
+static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
+	FILE *out;
+	size_t bytes;
+	uint8_t *buf;
+	int err = 0;
+
+	out = fopen(out_path, "w");
+	if (!out) {
+		fprintf(stderr, "Couldn't open %s\n", out_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	buf = malloc(length);
+	if (!buf) {
+		fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
+		err =  -ENOMEM;
+		goto err_close;
+	}
+
+	fseek(trx, offset, SEEK_SET);
+	bytes = fread(buf, 1, length, trx);
+	if (bytes != length) {
+		fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
+		err =  -ENOMEM;
+		goto err_free_buf;
+	};
+
+	bytes = fwrite(buf, 1, length, out);
+	if (bytes != length) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
+		err =  -ENOMEM;
+		goto err_free_buf;
+	}
+
+	printf("Extracted 0x%zx bytes into %s\n", length, out_path);
+
+err_free_buf:
+	free(buf);
+err_close:
+	fclose(out);
+out:
+	return err;
+}
+
+static int otrx_extract(int argc, char **argv) {
+	FILE *trx;
+	struct trx_header hdr;
+	size_t bytes;
+	int i;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No TRX file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	trx_path = argv[2];
+
+	optind = 3;
+	otrx_extract_parse_options(argc, argv);
+
+	trx = fopen(trx_path, "r");
+	if (!trx) {
+		fprintf(stderr, "Couldn't open %s\n", trx_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	fseek(trx, trx_offset, SEEK_SET);
+	bytes = fread(&hdr, 1, sizeof(hdr), trx);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", trx_path);
+		err =  -EIO;
+		goto err_close;
+	}
+
+	if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
+		fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	for (i = 0; i < TRX_MAX_PARTS; i++) {
+		size_t length;
+
+		if (!partition[i])
+			continue;
+		if (!hdr.offset[i]) {
+			printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
+			continue;
+		}
+
+		if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
+			length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
+		else
+			length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
+
+		otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
+	}
+
+err_close:
+	fclose(trx);
+out:
+	return err;
+}
+
+/**************************************************
+ * Start
+ **************************************************/
+
+static void usage() {
+	printf("Usage:\n");
+	printf("\n");
+	printf("Checking TRX file:\n");
+	printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
+	printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
+	printf("\n");
+	printf("Creating new TRX file:\n");
+	printf("\totrx create <file> [options] [partitions]\n");
+	printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
+	printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
+	printf("\n");
+	printf("Extracting from TRX file:\n");
+	printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
+	printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
+	printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
+	printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
+	printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
+}
+
+int main(int argc, char **argv) {
+	if (argc > 1) {
+		if (!strcmp(argv[1], "check"))
+			return otrx_check(argc, argv);
+		else if (!strcmp(argv[1], "create"))
+			return otrx_create(argc, argv);
+		else if (!strcmp(argv[1], "extract"))
+			return otrx_extract(argc, argv);
+	}
+
+	usage();
+	return 0;
+}
diff --git a/package/utils/px5g-standalone/Makefile b/package/utils/px5g-standalone/Makefile
new file mode 100644
index 0000000000..9b878ae336
--- /dev/null
+++ b/package/utils/px5g-standalone/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2010-2014 Jo-Philipp Wich <xm@subsignal.org>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=px5g-standalone
+PKG_RELEASE:=2
+
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/px5g-standalone
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Encryption
+  TITLE:=X.509 certificate generator (standalone version)
+  MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+endef
+
+define Package/px5g-standalone/description
+ Px5g is a tiny standalone X.509 certificate generator.
+ It suitable to create key files and certificates in DER
+ and PEM format for use with stunnel, uhttpd and others.
+endef
+
+define Package/px5g-standalone/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/px5g $(1)/usr/sbin/px5g
+endef
+
+$(eval $(call BuildPackage,px5g-standalone))
diff --git a/package/utils/px5g-standalone/src/Makefile b/package/utils/px5g-standalone/src/Makefile
new file mode 100644
index 0000000000..2bd95739cb
--- /dev/null
+++ b/package/utils/px5g-standalone/src/Makefile
@@ -0,0 +1,14 @@
+CFLAGS?=-O2
+CFLAGS+=
+SFLAGS:=--std=gnu99
+WFLAGS:=-Wall -Werror -pedantic
+LDFLAGS?=
+BINARY:=px5g
+
+all: $(BINARY)
+
+$(BINARY): *.c library/*.c
+	$(CC) -I. $(CFLAGS) $(SFLAGS) $(WFLAGS) $(LDFLAGS) -o $@ $+
+
+clean:
+	rm -f $(BINARY)
diff --git a/package/utils/px5g-standalone/src/library/base64.c b/package/utils/px5g-standalone/src/library/base64.c
new file mode 100644
index 0000000000..b7cc5b84ea
--- /dev/null
+++ b/package/utils/px5g-standalone/src/library/base64.c
@@ -0,0 +1,264 @@
+/*
+ *  RFC 1521 base64 encoding/decoding
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_BASE64_C)
+
+#include "polarssl/base64.h"
+
+static const unsigned char base64_enc_map[64] =
+{
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+    'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+    'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+    '8', '9', '+', '/'
+};
+
+static const unsigned char base64_dec_map[128] =
+{
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+    127, 127, 127,  62, 127, 127, 127,  63,  52,  53,
+     54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
+    127,  64, 127, 127, 127,   0,   1,   2,   3,   4,
+      5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
+     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
+     25, 127, 127, 127, 127, 127, 127,  26,  27,  28,
+     29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
+     39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+     49,  50,  51, 127, 127, 127, 127, 127
+};
+
+/*
+ * Encode a buffer into base64 format
+ */
+int base64_encode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen )
+{
+    int i, n;
+    int C1, C2, C3;
+    unsigned char *p;
+
+    if( slen == 0 )
+        return( 0 );
+
+    n = (slen << 3) / 6;
+
+    switch( (slen << 3) - (n * 6) )
+    {
+        case  2: n += 3; break;
+        case  4: n += 2; break;
+        default: break;
+    }
+
+    if( *dlen < n + 1 )
+    {
+        *dlen = n + 1;
+        return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
+    }
+
+    n = (slen / 3) * 3;
+
+    for( i = 0, p = dst; i < n; i += 3 )
+    {
+        C1 = *src++;
+        C2 = *src++;
+        C3 = *src++;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
+        *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+        *p++ = base64_enc_map[C3 & 0x3F];
+    }
+
+    if( i < slen )
+    {
+        C1 = *src++;
+        C2 = ((i + 1) < slen) ? *src++ : 0;
+
+        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
+        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+
+        if( (i + 1) < slen )
+             *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+        else *p++ = '=';
+
+        *p++ = '=';
+    }
+
+    *dlen = p - dst;
+    *p = 0;
+
+    return( 0 );
+}
+
+/*
+ * Decode a base64-formatted buffer
+ */
+int base64_decode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen )
+{
+    int i, j, n;
+    unsigned long x;
+    unsigned char *p;
+
+    for( i = j = n = 0; i < slen; i++ )
+    {
+        if( ( slen - i ) >= 2 &&
+            src[i] == '\r' && src[i + 1] == '\n' )
+            continue;
+
+        if( src[i] == '\n' )
+            continue;
+
+        if( src[i] == '=' && ++j > 2 )
+            return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
+
+        if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+            return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
+
+        if( base64_dec_map[src[i]] < 64 && j != 0 )
+            return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
+
+        n++;
+    }
+
+    if( n == 0 )
+        return( 0 );
+
+    n = ((n * 6) + 7) >> 3;
+
+    if( *dlen < n )
+    {
+        *dlen = n;
+        return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
+    }
+
+   for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
+   {
+        if( *src == '\r' || *src == '\n' )
+            continue;
+
+        j -= ( base64_dec_map[*src] == 64 );
+        x  = (x << 6) | ( base64_dec_map[*src] & 0x3F );
+
+        if( ++n == 4 )
+        {
+            n = 0;
+            if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
+            if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
+            if( j > 2 ) *p++ = (unsigned char)( x       );
+        }
+    }
+
+    *dlen = p - dst;
+
+    return( 0 );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include <string.h>
+#include <stdio.h>
+
+static const unsigned char base64_test_dec[64] =
+{
+    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
+    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
+    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
+    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
+    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
+    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
+    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
+    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
+};
+
+static const unsigned char base64_test_enc[] =
+    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
+    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
+
+/*
+ * Checkup routine
+ */
+int base64_self_test( int verbose )
+{
+    int len;
+    unsigned char *src, buffer[128];
+
+    if( verbose != 0 )
+        printf( "  Base64 encoding test: " );
+
+    len = sizeof( buffer );
+    src = (unsigned char *) base64_test_dec;
+
+    if( base64_encode( buffer, &len, src, 64 ) != 0 ||
+         memcmp( base64_test_enc, buffer, 88 ) != 0 ) 
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  Base64 decoding test: " );
+
+    len = sizeof( buffer );
+    src = (unsigned char *) base64_test_enc;
+
+    if( base64_decode( buffer, &len, src, 88 ) != 0 ||
+         memcmp( base64_test_dec, buffer, 64 ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/package/utils/px5g-standalone/src/library/bignum.c b/package/utils/px5g-standalone/src/library/bignum.c
new file mode 100644
index 0000000000..8b7c12ff00
--- /dev/null
+++ b/package/utils/px5g-standalone/src/library/bignum.c
@@ -0,0 +1,2010 @@
+/*
+ *  Multi-precision integer library
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+/*
+ *  This MPI implementation is based on:
+ *
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
+ *  http://www.stillhq.com/extracted/gnupg-api/mpi/
+ *  http://math.libtomcrypt.com/files/tommath.pdf
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_BIGNUM_C)
+
+#include "polarssl/bignum.h"
+#include "polarssl/bn_mul.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define ciL    ((int) sizeof(t_int))    /* chars in limb  */
+#define biL    (ciL << 3)               /* bits  in limb  */
+#define biH    (ciL << 2)               /* half limb size */
+
+/*
+ * Convert between bits/chars and number of limbs
+ */
+#define BITS_TO_LIMBS(i)  (((i) + biL - 1) / biL)
+#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL)
+
+/*
+ * Initialize one or more mpi
+ */
+void mpi_init( mpi *X, ... )
+{
+    va_list args;
+
+    va_start( args, X );
+
+    while( X != NULL )
+    {
+        X->s = 1;
+        X->n = 0;
+        X->p = NULL;
+
+        X = va_arg( args, mpi* );
+    }
+
+    va_end( args );
+}
+
+/*
+ * Unallocate one or more mpi
+ */
+void mpi_free( mpi *X, ... )
+{
+    va_list args;
+
+    va_start( args, X );
+
+    while( X != NULL )
+    {
+        if( X->p != NULL )
+        {
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        X->s = 1;
+        X->n = 0;
+        X->p = NULL;
+
+        X = va_arg( args, mpi* );
+    }
+
+    va_end( args );
+}
+
+/*
+ * Enlarge to the specified number of limbs
+ */
+int mpi_grow( mpi *X, int nblimbs )
+{
+    t_int *p;
+
+    if( X->n < nblimbs )
+    {
+        if( ( p = (t_int *) malloc( nblimbs * ciL ) ) == NULL )
+            return( 1 );
+
+        memset( p, 0, nblimbs * ciL );
+
+        if( X->p != NULL )
+        {
+            memcpy( p, X->p, X->n * ciL );
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        X->n = nblimbs;
+        X->p = p;
+    }
+
+    return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mpi_copy( mpi *X, mpi *Y )
+{
+    int ret, i;
+
+    if( X == Y )
+        return( 0 );
+
+    for( i = Y->n - 1; i > 0; i-- )
+        if( Y->p[i] != 0 )
+            break;
+    i++;
+
+    X->s = Y->s;
+
+    MPI_CHK( mpi_grow( X, i ) );
+
+    memset( X->p, 0, X->n * ciL );
+    memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y )
+{
+    mpi T;
+
+    memcpy( &T,  X, sizeof( mpi ) );
+    memcpy(  X,  Y, sizeof( mpi ) );
+    memcpy(  Y, &T, sizeof( mpi ) );
+}
+
+/*
+ * Set value from integer
+ */
+int mpi_lset( mpi *X, int z )
+{
+    int ret;
+
+    MPI_CHK( mpi_grow( X, 1 ) );
+    memset( X->p, 0, X->n * ciL );
+
+    X->p[0] = ( z < 0 ) ? -z : z;
+    X->s    = ( z < 0 ) ? -1 : 1;
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Return the number of least significant bits
+ */
+int mpi_lsb( mpi *X )
+{
+    int i, j, count = 0;
+
+    for( i = 0; i < X->n; i++ )
+        for( j = 0; j < (int) biL; j++, count++ )
+            if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+                return( count );
+
+    return( 0 );
+}
+
+/*
+ * Return the number of most significant bits
+ */
+int mpi_msb( mpi *X )
+{
+    int i, j;
+
+    for( i = X->n - 1; i > 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = biL - 1; j >= 0; j-- )
+        if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+            break;
+
+    return( ( i * biL ) + j + 1 );
+}
+
+/*
+ * Return the total size in bytes
+ */
+int mpi_size( mpi *X )
+{
+    return( ( mpi_msb( X ) + 7 ) >> 3 );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( t_int *d, int radix, char c )
+{
+    *d = 255;
+
+    if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
+    if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
+    if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
+
+    if( *d >= (t_int) radix )
+        return( POLARSSL_ERR_MPI_INVALID_CHARACTER );
+
+    return( 0 );
+}
+
+/*
+ * Import from an ASCII string
+ */
+int mpi_read_string( mpi *X, int radix, char *s )
+{
+    int ret, i, j, n;
+    t_int d;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &T, NULL );
+
+    if( radix == 16 )
+    {
+        n = BITS_TO_LIMBS( strlen( s ) << 2 );
+
+        MPI_CHK( mpi_grow( X, n ) );
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                break;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+            X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_lset( X, 0 ) );
+
+        for( i = 0; i < (int) strlen( s ); i++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                continue;
+            }
+
+            MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+            MPI_CHK( mpi_mul_int( &T, X, radix ) );
+            MPI_CHK( mpi_add_int( X, &T, d ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    return( ret );
+}
+
+/*
+ * Helper to write the digits high-order first
+ */
+static int mpi_write_hlp( mpi *X, int radix, char **p )
+{
+    int ret;
+    t_int r;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    MPI_CHK( mpi_mod_int( &r, X, radix ) );
+    MPI_CHK( mpi_div_int( X, NULL, X, radix ) );
+
+    if( mpi_cmp_int( X, 0 ) != 0 )
+        MPI_CHK( mpi_write_hlp( X, radix, p ) );
+
+    if( r < 10 )
+        *(*p)++ = (char)( r + 0x30 );
+    else
+        *(*p)++ = (char)( r + 0x37 );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export into an ASCII string
+ */
+int mpi_write_string( mpi *X, int radix, char *s, int *slen )
+{
+    int ret = 0, n;
+    char *p;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    n = mpi_msb( X );
+    if( radix >=  4 ) n >>= 1;
+    if( radix >= 16 ) n >>= 1;
+    n += 3;
+
+    if( *slen < n )
+    {
+        *slen = n;
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+    }
+
+    p = s;
+    mpi_init( &T, NULL );
+
+    if( X->s == -1 )
+        *p++ = '-';
+
+    if( radix == 16 )
+    {
+        int c, i, j, k;
+
+        for( i = X->n - 1, k = 0; i >= 0; i-- )
+        {
+            for( j = ciL - 1; j >= 0; j-- )
+            {
+                c = ( X->p[i] >> (j << 3) ) & 0xFF;
+
+                if( c == 0 && k == 0 && (i + j) != 0 )
+                    continue;
+
+                p += sprintf( p, "%02X", c );
+                k = 1;
+            }
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_copy( &T, X ) );
+        MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+    }
+
+    *p++ = '\0';
+    *slen = p - s;
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    return( ret );
+}
+
+/*
+ * Read X from an opened file
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin )
+{
+    t_int d;
+    int slen;
+    char *p;
+    char s[1024];
+
+    memset( s, 0, sizeof( s ) );
+    if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
+        return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
+
+    slen = strlen( s );
+    if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
+    if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
+
+    p = s + slen;
+    while( --p >= s )
+        if( mpi_get_digit( &d, radix, *p ) != 0 )
+            break;
+
+    return( mpi_read_string( X, radix, p + 1 ) );
+}
+
+/*
+ * Write X into an opened file (or stdout if fout == NULL)
+ */
+int mpi_write_file( char *p, mpi *X, int radix, FILE *fout )
+{
+    int n, ret;
+    size_t slen;
+    size_t plen;
+    char s[1024];
+
+    n = sizeof( s );
+    memset( s, 0, n );
+    n -= 2;
+
+    MPI_CHK( mpi_write_string( X, radix, s, (int *) &n ) );
+
+    if( p == NULL ) p = "";
+
+    plen = strlen( p );
+    slen = strlen( s );
+    s[slen++] = '\r';
+    s[slen++] = '\n';
+
+    if( fout != NULL )
+    {
+        if( fwrite( p, 1, plen, fout ) != plen ||
+            fwrite( s, 1, slen, fout ) != slen )
+            return( POLARSSL_ERR_MPI_FILE_IO_ERROR );
+    }
+    else
+        printf( "%s%s", p, s );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Import X from unsigned binary data, big endian
+ */
+int mpi_read_binary( mpi *X, unsigned char *buf, int buflen )
+{
+    int ret, i, j, n;
+
+    for( n = 0; n < buflen; n++ )
+        if( buf[n] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i = buflen - 1, j = 0; i >= n; i--, j++ )
+        X->p[j / ciL] |= ((t_int) buf[i]) << ((j % ciL) << 3);
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export X into unsigned binary data, big endian
+ */
+int mpi_write_binary( mpi *X, unsigned char *buf, int buflen )
+{
+    int i, j, n;
+
+    n = mpi_size( X );
+
+    if( buflen < n )
+        return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL );
+
+    memset( buf, 0, buflen );
+
+    for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
+        buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+
+    return( 0 );
+}
+
+/*
+ * Left-shift: X <<= count
+ */
+int mpi_shift_l( mpi *X, int count )
+{
+    int ret, i, v0, t1;
+    t_int r0 = 0, r1;
+
+    v0 = count / (biL    );
+    t1 = count & (biL - 1);
+
+    i = mpi_msb( X ) + count;
+
+    if( X->n * (int) biL < i )
+        MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) );
+
+    ret = 0;
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = X->n - 1; i >= v0; i-- )
+            X->p[i] = X->p[i - v0];
+
+        for( ; i >= 0; i-- )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( t1 > 0 )
+    {
+        for( i = v0; i < X->n; i++ )
+        {
+            r1 = X->p[i] >> (biL - t1);
+            X->p[i] <<= t1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Right-shift: X >>= count
+ */
+int mpi_shift_r( mpi *X, int count )
+{
+    int i, v0, v1;
+    t_int r0 = 0, r1;
+
+    v0 = count /  biL;
+    v1 = count & (biL - 1);
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = 0; i < X->n - v0; i++ )
+            X->p[i] = X->p[i + v0];
+
+        for( ; i < X->n; i++ )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( v1 > 0 )
+    {
+        for( i = X->n - 1; i >= 0; i-- )
+        {
+            r1 = X->p[i] << (biL - v1);
+            X->p[i] >>= v1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare unsigned values
+ */
+int mpi_cmp_abs( mpi *X, mpi *Y )
+{
+    int i, j;
+
+    for( i = X->n - 1; i >= 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = Y->n - 1; j >= 0; j-- )
+        if( Y->p[j] != 0 )
+            break;
+
+    if( i < 0 && j < 0 )
+        return( 0 );
+
+    if( i > j ) return(  1 );
+    if( j > i ) return( -1 );
+
+    for( ; i >= 0; i-- )
+    {
+        if( X->p[i] > Y->p[i] ) return(  1 );
+        if( X->p[i] < Y->p[i] ) return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_mpi( mpi *X, mpi *Y )
+{
+    int i, j;
+
+    for( i = X->n - 1; i >= 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = Y->n - 1; j >= 0; j-- )
+        if( Y->p[j] != 0 )
+            break;
+
+    if( i < 0 && j < 0 )
+        return( 0 );
+
+    if( i > j ) return(  X->s );
+    if( j > i ) return( -X->s );
+
+    if( X->s > 0 && Y->s < 0 ) return(  1 );
+    if( Y->s > 0 && X->s < 0 ) return( -1 );
+
+    for( ; i >= 0; i-- )
+    {
+        if( X->p[i] > Y->p[i] ) return(  X->s );
+        if( X->p[i] < Y->p[i] ) return( -X->s );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_int( mpi *X, int z )
+{
+    mpi Y;
+    t_int p[1];
+
+    *p  = ( z < 0 ) ? -z : z;
+    Y.s = ( z < 0 ) ? -1 : 1;
+    Y.n = 1;
+    Y.p = p;
+
+    return( mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B|  (HAC 14.7)
+ */
+int mpi_add_abs( mpi *X, mpi *A, mpi *B )
+{
+    int ret, i, j;
+    t_int *o, *p, c;
+
+    if( X == B )
+    {
+        mpi *T = A; A = X; B = T;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+
+    for( j = B->n - 1; j >= 0; j-- )
+        if( B->p[j] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, j + 1 ) );
+
+    o = B->p; p = X->p; c = 0;
+
+    for( i = 0; i <= j; i++, o++, p++ )
+    {
+        *p +=  c; c  = ( *p <  c );
+        *p += *o; c += ( *p < *o );
+    }
+
+    while( c != 0 )
+    {
+        if( i >= X->n )
+        {
+            MPI_CHK( mpi_grow( X, i + 1 ) );
+            p = X->p + i;
+        }
+
+        *p += c; c = ( *p < c ); i++;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Helper for mpi substraction
+ */
+static void mpi_sub_hlp( int n, t_int *s, t_int *d )
+{
+    int i;
+    t_int c, z;
+
+    for( i = c = 0; i < n; i++, s++, d++ )
+    {
+        z = ( *d <  c );     *d -=  c;
+        c = ( *d < *s ) + z; *d -= *s;
+    }
+
+    while( c != 0 )
+    {
+        z = ( *d < c ); *d -= c;
+        c = z; i++; d++;
+    }
+}
+
+/*
+ * Unsigned substraction: X = |A| - |B|  (HAC 14.9)
+ */
+int mpi_sub_abs( mpi *X, mpi *A, mpi *B )
+{
+    mpi TB;
+    int ret, n;
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+        return( POLARSSL_ERR_MPI_NEGATIVE_VALUE );
+
+    mpi_init( &TB, NULL );
+
+    if( X == B )
+    {
+        MPI_CHK( mpi_copy( &TB, B ) );
+        B = &TB;
+    }
+
+    if( X != A )
+        MPI_CHK( mpi_copy( X, A ) );
+
+    ret = 0;
+
+    for( n = B->n - 1; n >= 0; n-- )
+        if( B->p[n] != 0 )
+            break;
+
+    mpi_sub_hlp( n + 1, B->p, X->p );
+
+cleanup:
+
+    mpi_free( &TB, NULL );
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mpi_add_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s < 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed substraction: X = A - B
+ */
+int mpi_sub_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s > 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mpi_add_int( mpi *X, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed substraction: X = A - b
+ */
+int mpi_sub_int( mpi *X, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mpi multiplication
+ */ 
+static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b )
+{
+    t_int c = 0, t = 0;
+
+#if defined(MULADDC_HUIT)
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_HUIT
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#else
+    for( ; i >= 16; i -= 16 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+#endif
+
+    t++;
+
+    do {
+        *d += c; c = ( *d < c ); d++;
+    }
+    while( c != 0 );
+}
+
+/*
+ * Baseline multiplication: X = A * B  (HAC 14.12)
+ */
+int mpi_mul_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, i, j;
+    mpi TA, TB;
+
+    mpi_init( &TA, &TB, NULL );
+
+    if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; }
+    if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; }
+
+    for( i = A->n - 1; i >= 0; i-- )
+        if( A->p[i] != 0 )
+            break;
+
+    for( j = B->n - 1; j >= 0; j-- )
+        if( B->p[j] != 0 )
+            break;
+
+    MPI_CHK( mpi_grow( X, i + j + 2 ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    for( i++; j >= 0; j-- )
+        mpi_mul_hlp( i, A->p, X->p + j, B->p[j] );
+
+    X->s = A->s * B->s;
+
+cleanup:
+
+    mpi_free( &TB, &TA, NULL );
+
+    return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mpi_mul_int( mpi *X, mpi *A, t_int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    _B.s = 1;
+    _B.n = 1;
+    _B.p = p;
+    p[0] = b;
+
+    return( mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Division by mpi: A = Q * B + R  (HAC 14.20)
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B )
+{
+    int ret, i, n, t, k;
+    mpi X, Y, Z, T1, T2;
+
+    if( mpi_cmp_int( B, 0 ) == 0 )
+        return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    mpi_init( &X, &Y, &Z, &T1, &T2, NULL );
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+    {
+        if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) );
+        if( R != NULL ) MPI_CHK( mpi_copy( R, A ) );
+        return( 0 );
+    }
+
+    MPI_CHK( mpi_copy( &X, A ) );
+    MPI_CHK( mpi_copy( &Y, B ) );
+    X.s = Y.s = 1;
+
+    MPI_CHK( mpi_grow( &Z, A->n + 2 ) );
+    MPI_CHK( mpi_lset( &Z,  0 ) );
+    MPI_CHK( mpi_grow( &T1, 2 ) );
+    MPI_CHK( mpi_grow( &T2, 3 ) );
+
+    k = mpi_msb( &Y ) % biL;
+    if( k < (int) biL - 1 )
+    {
+        k = biL - 1 - k;
+        MPI_CHK( mpi_shift_l( &X, k ) );
+        MPI_CHK( mpi_shift_l( &Y, k ) );
+    }
+    else k = 0;
+
+    n = X.n - 1;
+    t = Y.n - 1;
+    mpi_shift_l( &Y, biL * (n - t) );
+
+    while( mpi_cmp_mpi( &X, &Y ) >= 0 )
+    {
+        Z.p[n - t]++;
+        mpi_sub_mpi( &X, &X, &Y );
+    }
+    mpi_shift_r( &Y, biL * (n - t) );
+
+    for( i = n; i > t ; i-- )
+    {
+        if( X.p[i] >= Y.p[t] )
+            Z.p[i - t - 1] = ~0;
+        else
+        {
+#if defined(POLARSSL_HAVE_LONGLONG)
+            t_dbl r;
+
+            r  = (t_dbl) X.p[i] << biL;
+            r |= (t_dbl) X.p[i - 1];
+            r /= Y.p[t];
+            if( r > ((t_dbl) 1 << biL) - 1)
+                r = ((t_dbl) 1 << biL) - 1;
+
+            Z.p[i - t - 1] = (t_int) r;
+#else
+            /*
+             * __udiv_qrnnd_c, from gmp/longlong.h
+             */
+            t_int q0, q1, r0, r1;
+            t_int d0, d1, d, m;
+
+            d  = Y.p[t];
+            d0 = ( d << biH ) >> biH;
+            d1 = ( d >> biH );
+
+            q1 = X.p[i] / d1;
+            r1 = X.p[i] - d1 * q1;
+            r1 <<= biH;
+            r1 |= ( X.p[i - 1] >> biH );
+
+            m = q1 * d0;
+            if( r1 < m )
+            {
+                q1--, r1 += d;
+                while( r1 >= d && r1 < m )
+                    q1--, r1 += d;
+            }
+            r1 -= m;
+
+            q0 = r1 / d1;
+            r0 = r1 - d1 * q0;
+            r0 <<= biH;
+            r0 |= ( X.p[i - 1] << biH ) >> biH;
+
+            m = q0 * d0;
+            if( r0 < m )
+            {
+                q0--, r0 += d;
+                while( r0 >= d && r0 < m )
+                    q0--, r0 += d;
+            }
+            r0 -= m;
+
+            Z.p[i - t - 1] = ( q1 << biH ) | q0;
+#endif
+        }
+
+        Z.p[i - t - 1]++;
+        do
+        {
+            Z.p[i - t - 1]--;
+
+            MPI_CHK( mpi_lset( &T1, 0 ) );
+            T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
+            T1.p[1] = Y.p[t];
+            MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+            MPI_CHK( mpi_lset( &T2, 0 ) );
+            T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
+            T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
+            T2.p[2] = X.p[i];
+        }
+        while( mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+        MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+        MPI_CHK( mpi_shift_l( &T1,  biL * (i - t - 1) ) );
+        MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) );
+
+        if( mpi_cmp_int( &X, 0 ) < 0 )
+        {
+            MPI_CHK( mpi_copy( &T1, &Y ) );
+            MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
+            MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) );
+            Z.p[i - t - 1]--;
+        }
+    }
+
+    if( Q != NULL )
+    {
+        mpi_copy( Q, &Z );
+        Q->s = A->s * B->s;
+    }
+
+    if( R != NULL )
+    {
+        mpi_shift_r( &X, k );
+        mpi_copy( R, &X );
+
+        R->s = A->s;
+        if( mpi_cmp_int( R, 0 ) == 0 )
+            R->s = 1;
+    }
+
+cleanup:
+
+    mpi_free( &X, &Y, &Z, &T1, &T2, NULL );
+
+    return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ *
+ * Returns 0 if successful
+ *         1 if memory allocation failed
+ *         POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ */
+int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mpi_mod_mpi( mpi *R, mpi *A, mpi *B )
+{
+    int ret;
+
+    MPI_CHK( mpi_div_mpi( NULL, R, A, B ) );
+
+    while( mpi_cmp_int( R, 0 ) < 0 )
+      MPI_CHK( mpi_add_mpi( R, R, B ) );
+
+    while( mpi_cmp_mpi( R, B ) >= 0 )
+      MPI_CHK( mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mpi_mod_int( t_int *r, mpi *A, int b )
+{
+    int i;
+    t_int x, y, z;
+
+    if( b == 0 )
+        return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
+
+    if( b < 0 )
+        b = -b;
+
+    /*
+     * handle trivial cases
+     */
+    if( b == 1 )
+    {
+        *r = 0;
+        return( 0 );
+    }
+
+    if( b == 2 )
+    {
+        *r = A->p[0] & 1;
+        return( 0 );
+    }
+
+    /*
+     * general case
+     */
+    for( i = A->n - 1, y = 0; i >= 0; i-- )
+    {
+        x  = A->p[i];
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+
+        x <<= biH;
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+    }
+
+    *r = y;
+
+    return( 0 );
+}
+
+/*
+ * Fast Montgomery initialization (thanks to Tom St Denis)
+ */
+static void mpi_montg_init( t_int *mm, mpi *N )
+{
+    t_int x, m0 = N->p[0];
+
+    x  = m0;
+    x += ( ( m0 + 2 ) & 4 ) << 1;
+    x *= ( 2 - ( m0 * x ) );
+
+    if( biL >= 16 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 32 ) x *= ( 2 - ( m0 * x ) );
+    if( biL >= 64 ) x *= ( 2 - ( m0 * x ) );
+
+    *mm = ~x + 1;
+}
+
+/*
+ * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
+ */
+static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T )
+{
+    int i, n, m;
+    t_int u0, u1, *d;
+
+    memset( T->p, 0, T->n * ciL );
+
+    d = T->p;
+    n = N->n;
+    m = ( B->n < n ) ? B->n : n;
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * T = (T + u0*B + u1*N) / 2^biL
+         */
+        u0 = A->p[i];
+        u1 = ( d[0] + u0 * B->p[0] ) * mm;
+
+        mpi_mul_hlp( m, B->p, d, u0 );
+        mpi_mul_hlp( n, N->p, d, u1 );
+
+        *d++ = u0; d[n + 1] = 0;
+    }
+
+    memcpy( A->p, d, (n + 1) * ciL );
+
+    if( mpi_cmp_abs( A, N ) >= 0 )
+        mpi_sub_hlp( n, N->p, A->p );
+    else
+        /* prevent timing attacks */
+        mpi_sub_hlp( n, A->p, T->p );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T )
+{
+    t_int z = 1;
+    mpi U;
+
+    U.n = U.s = z;
+    U.p = &z;
+
+    mpi_montmul( A, &U, N, mm, T );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
+ */
+int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR )
+{
+    int ret, i, j, wsize, wbits;
+    int bufsize, nblimbs, nbits;
+    t_int ei, mm, state;
+    mpi RR, T, W[64];
+
+    if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    /*
+     * Init temps and window size
+     */
+    mpi_montg_init( &mm, N );
+    mpi_init( &RR, &T, NULL );
+    memset( W, 0, sizeof( W ) );
+
+    i = mpi_msb( E );
+
+    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+            ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
+
+    j = N->n + 1;
+    MPI_CHK( mpi_grow( X, j ) );
+    MPI_CHK( mpi_grow( &W[1],  j ) );
+    MPI_CHK( mpi_grow( &T, j * 2 ) );
+
+    /*
+     * If 1st call, pre-compute R^2 mod N
+     */
+    if( _RR == NULL || _RR->p == NULL )
+    {
+        MPI_CHK( mpi_lset( &RR, 1 ) );
+        MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) );
+        MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) );
+
+        if( _RR != NULL )
+            memcpy( _RR, &RR, sizeof( mpi ) );
+    }
+    else
+        memcpy( &RR, _RR, sizeof( mpi ) );
+
+    /*
+     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+     */
+    if( mpi_cmp_mpi( A, N ) >= 0 )
+        mpi_mod_mpi( &W[1], A, N );
+    else   mpi_copy( &W[1], A );
+
+    mpi_montmul( &W[1], &RR, N, mm, &T );
+
+    /*
+     * X = R^2 * R^-1 mod N = R mod N
+     */
+    MPI_CHK( mpi_copy( X, &RR ) );
+    mpi_montred( X, N, mm, &T );
+
+    if( wsize > 1 )
+    {
+        /*
+         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+         */
+        j =  1 << (wsize - 1);
+
+        MPI_CHK( mpi_grow( &W[j], N->n + 1 ) );
+        MPI_CHK( mpi_copy( &W[j], &W[1]    ) );
+
+        for( i = 0; i < wsize - 1; i++ )
+            mpi_montmul( &W[j], &W[j], N, mm, &T );
+    
+        /*
+         * W[i] = W[i - 1] * W[1]
+         */
+        for( i = j + 1; i < (1 << wsize); i++ )
+        {
+            MPI_CHK( mpi_grow( &W[i], N->n + 1 ) );
+            MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) );
+
+            mpi_montmul( &W[i], &W[1], N, mm, &T );
+        }
+    }
+
+    nblimbs = E->n;
+    bufsize = 0;
+    nbits   = 0;
+    wbits   = 0;
+    state   = 0;
+
+    while( 1 )
+    {
+        if( bufsize == 0 )
+        {
+            if( nblimbs-- == 0 )
+                break;
+
+            bufsize = sizeof( t_int ) << 3;
+        }
+
+        bufsize--;
+
+        ei = (E->p[nblimbs] >> bufsize) & 1;
+
+        /*
+         * skip leading 0s
+         */
+        if( ei == 0 && state == 0 )
+            continue;
+
+        if( ei == 0 && state == 1 )
+        {
+            /*
+             * out of window, square X
+             */
+            mpi_montmul( X, X, N, mm, &T );
+            continue;
+        }
+
+        /*
+         * add ei to current window
+         */
+        state = 2;
+
+        nbits++;
+        wbits |= (ei << (wsize - nbits));
+
+        if( nbits == wsize )
+        {
+            /*
+             * X = X^wsize R^-1 mod N
+             */
+            for( i = 0; i < wsize; i++ )
+                mpi_montmul( X, X, N, mm, &T );
+
+            /*
+             * X = X * W[wbits] R^-1 mod N
+             */
+            mpi_montmul( X, &W[wbits], N, mm, &T );
+
+            state--;
+            nbits = 0;
+            wbits = 0;
+        }
+    }
+
+    /*
+     * process the remaining bits
+     */
+    for( i = 0; i < nbits; i++ )
+    {
+        mpi_montmul( X, X, N, mm, &T );
+
+        wbits <<= 1;
+
+        if( (wbits & (1 << wsize)) != 0 )
+            mpi_montmul( X, &W[1], N, mm, &T );
+    }
+
+    /*
+     * X = A^E * R * R^-1 mod N = A^E mod N
+     */
+    mpi_montred( X, N, mm, &T );
+
+cleanup:
+
+    for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ )
+        mpi_free( &W[i], NULL );
+
+    if( _RR != NULL )
+         mpi_free( &W[1], &T, NULL );
+    else mpi_free( &W[1], &T, &RR, NULL );
+
+    return( ret );
+}
+
+/*
+ * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
+ */
+int mpi_gcd( mpi *G, mpi *A, mpi *B )
+{
+    int ret, lz, lzt;
+    mpi TG, TA, TB;
+
+    mpi_init( &TG, &TA, &TB, NULL );
+
+    MPI_CHK( mpi_copy( &TA, A ) );
+    MPI_CHK( mpi_copy( &TB, B ) );
+
+    lz = mpi_lsb( &TA );
+    lzt = mpi_lsb( &TB );
+
+    if ( lzt < lz )
+        lz = lzt;
+
+    MPI_CHK( mpi_shift_r( &TA, lz ) );
+    MPI_CHK( mpi_shift_r( &TB, lz ) );
+
+    TA.s = TB.s = 1;
+
+    while( mpi_cmp_int( &TA, 0 ) != 0 )
+    {
+        MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) );
+        MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) );
+
+        if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) );
+            MPI_CHK( mpi_shift_r( &TA, 1 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) );
+            MPI_CHK( mpi_shift_r( &TB, 1 ) );
+        }
+    }
+
+    MPI_CHK( mpi_shift_l( &TB, lz ) );
+    MPI_CHK( mpi_copy( G, &TB ) );
+
+cleanup:
+
+    mpi_free( &TB, &TA, &TG, NULL );
+
+    return( ret );
+}
+
+#if defined(POLARSSL_GENPRIME)
+
+/*
+ * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
+ */
+int mpi_inv_mod( mpi *X, mpi *A, mpi *N )
+{
+    int ret;
+    mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+    if( mpi_cmp_int( N, 0 ) <= 0 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &TA, &TU, &U1, &U2, &G,
+              &TB, &TV, &V1, &V2, NULL );
+
+    MPI_CHK( mpi_gcd( &G, A, N ) );
+
+    if( mpi_cmp_int( &G, 1 ) != 0 )
+    {
+        ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
+        goto cleanup;
+    }
+
+    MPI_CHK( mpi_mod_mpi( &TA, A, N ) );
+    MPI_CHK( mpi_copy( &TU, &TA ) );
+    MPI_CHK( mpi_copy( &TB, N ) );
+    MPI_CHK( mpi_copy( &TV, N ) );
+
+    MPI_CHK( mpi_lset( &U1, 1 ) );
+    MPI_CHK( mpi_lset( &U2, 0 ) );
+    MPI_CHK( mpi_lset( &V1, 0 ) );
+    MPI_CHK( mpi_lset( &V2, 1 ) );
+
+    do
+    {
+        while( ( TU.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TU, 1 ) );
+
+            if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &U1, 1 ) );
+            MPI_CHK( mpi_shift_r( &U2, 1 ) );
+        }
+
+        while( ( TV.p[0] & 1 ) == 0 )
+        {
+            MPI_CHK( mpi_shift_r( &TV, 1 ) );
+
+            if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+            {
+                MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) );
+                MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) );
+            }
+
+            MPI_CHK( mpi_shift_r( &V1, 1 ) );
+            MPI_CHK( mpi_shift_r( &V2, 1 ) );
+        }
+
+        if( mpi_cmp_mpi( &TU, &TV ) >= 0 )
+        {
+            MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) );
+            MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) );
+            MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) );
+        }
+        else
+        {
+            MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) );
+            MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) );
+            MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) );
+        }
+    }
+    while( mpi_cmp_int( &TU, 0 ) != 0 );
+
+    while( mpi_cmp_int( &V1, 0 ) < 0 )
+        MPI_CHK( mpi_add_mpi( &V1, &V1, N ) );
+
+    while( mpi_cmp_mpi( &V1, N ) >= 0 )
+        MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) );
+
+    MPI_CHK( mpi_copy( X, &V1 ) );
+
+cleanup:
+
+    mpi_free( &V2, &V1, &TV, &TB, &G,
+              &U2, &U1, &TU, &TA, NULL );
+
+    return( ret );
+}
+
+static const int small_prime[] =
+{
+        3,    5,    7,   11,   13,   17,   19,   23,
+       29,   31,   37,   41,   43,   47,   53,   59,
+       61,   67,   71,   73,   79,   83,   89,   97,
+      101,  103,  107,  109,  113,  127,  131,  137,
+      139,  149,  151,  157,  163,  167,  173,  179,
+      181,  191,  193,  197,  199,  211,  223,  227,
+      229,  233,  239,  241,  251,  257,  263,  269,
+      271,  277,  281,  283,  293,  307,  311,  313,
+      317,  331,  337,  347,  349,  353,  359,  367,
+      373,  379,  383,  389,  397,  401,  409,  419,
+      421,  431,  433,  439,  443,  449,  457,  461,
+      463,  467,  479,  487,  491,  499,  503,  509,
+      521,  523,  541,  547,  557,  563,  569,  571,
+      577,  587,  593,  599,  601,  607,  613,  617,
+      619,  631,  641,  643,  647,  653,  659,  661,
+      673,  677,  683,  691,  701,  709,  719,  727,
+      733,  739,  743,  751,  757,  761,  769,  773,
+      787,  797,  809,  811,  821,  823,  827,  829,
+      839,  853,  857,  859,  863,  877,  881,  883,
+      887,  907,  911,  919,  929,  937,  941,  947,
+      953,  967,  971,  977,  983,  991,  997, -103
+};
+
+/*
+ * Miller-Rabin primality test  (HAC 4.24)
+ */
+int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
+{
+    int ret, i, j, n, s, xs;
+    mpi W, R, T, A, RR;
+    unsigned char *p;
+
+    if( mpi_cmp_int( X, 0 ) == 0 )
+        return( 0 );
+
+    mpi_init( &W, &R, &T, &A, &RR, NULL );
+
+    xs = X->s; X->s = 1;
+
+    /*
+     * test trivial factors first
+     */
+    if( ( X->p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+    for( i = 0; small_prime[i] > 0; i++ )
+    {
+        t_int r;
+
+        if( mpi_cmp_int( X, small_prime[i] ) <= 0 )
+            return( 0 );
+
+        MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) );
+
+        if( r == 0 )
+            return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+    }
+
+    /*
+     * W = |X| - 1
+     * R = W >> lsb( W )
+     */
+    s = mpi_lsb( &W );
+    MPI_CHK( mpi_sub_int( &W, X, 1 ) );
+    MPI_CHK( mpi_copy( &R, &W ) );
+    MPI_CHK( mpi_shift_r( &R, s ) );
+
+    i = mpi_msb( X );
+    /*
+     * HAC, table 4.4
+     */
+    n = ( ( i >= 1300 ) ?  2 : ( i >=  850 ) ?  3 :
+          ( i >=  650 ) ?  4 : ( i >=  350 ) ?  8 :
+          ( i >=  250 ) ? 12 : ( i >=  150 ) ? 18 : 27 );
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * pick a random A, 1 < A < |X| - 1
+         */
+        MPI_CHK( mpi_grow( &A, X->n ) );
+
+        p = (unsigned char *) A.p;
+        for( j = 0; j < A.n * ciL; j++ )
+            *p++ = (unsigned char) f_rng( p_rng );
+
+        j = mpi_msb( &A ) - mpi_msb( &W );
+        MPI_CHK( mpi_shift_r( &A, j + 1 ) );
+        A.p[0] |= 3;
+
+        /*
+         * A = A^R mod |X|
+         */
+        MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+        if( mpi_cmp_mpi( &A, &W ) == 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+            continue;
+
+        j = 1;
+        while( j < s && mpi_cmp_mpi( &A, &W ) != 0 )
+        {
+            /*
+             * A = A * A mod |X|
+             */
+            MPI_CHK( mpi_mul_mpi( &T, &A, &A ) );
+            MPI_CHK( mpi_mod_mpi( &A, &T, X  ) );
+
+            if( mpi_cmp_int( &A, 1 ) == 0 )
+                break;
+
+            j++;
+        }
+
+        /*
+         * not prime if A != |X| - 1 or A == 1
+         */
+        if( mpi_cmp_mpi( &A, &W ) != 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+        {
+            ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE;
+            break;
+        }
+    }
+
+cleanup:
+
+    X->s = xs;
+
+    mpi_free( &RR, &A, &T, &R, &W, NULL );
+
+    return( ret );
+}
+
+/*
+ * Prime number generation
+ */
+int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
+                   int (*f_rng)(void *), void *p_rng )
+{
+    int ret, k, n;
+    unsigned char *p;
+    mpi Y;
+
+    if( nbits < 3 )
+        return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
+
+    mpi_init( &Y, NULL );
+
+    n = BITS_TO_LIMBS( nbits );
+
+    MPI_CHK( mpi_grow( X, n ) );
+    MPI_CHK( mpi_lset( X, 0 ) );
+
+    p = (unsigned char *) X->p;
+    for( k = 0; k < X->n * ciL; k++ )
+        *p++ = (unsigned char) f_rng( p_rng );
+
+    k = mpi_msb( X );
+    if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );
+    if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) );
+
+    X->p[0] |= 3;
+
+    if( dh_flag == 0 )
+    {
+        while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
+        {
+            if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( X, X, 2 ) );
+        }
+    }
+    else
+    {
+        MPI_CHK( mpi_sub_int( &Y, X, 1 ) );
+        MPI_CHK( mpi_shift_r( &Y, 1 ) );
+
+        while( 1 )
+        {
+            if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 )
+            {
+                if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 )
+                    break;
+
+                if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                    goto cleanup;
+            }
+
+            if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE )
+                goto cleanup;
+
+            MPI_CHK( mpi_add_int( &Y, X, 1 ) );
+            MPI_CHK( mpi_add_int(  X, X, 2 ) );
+            MPI_CHK( mpi_shift_r( &Y, 1 ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &Y, NULL );
+
+    return( ret );
+}
+
+#endif
+
+#if defined(POLARSSL_SELF_TEST)
+
+#define GCD_PAIR_COUNT	3
+
+static const int gcd_pairs[GCD_PAIR_COUNT][3] =
+{
+    { 693, 609, 21 },
+    { 1764, 868, 28 },
+    { 768454923, 542167814, 1 }
+};
+
+/*
+ * Checkup routine
+ */
+int mpi_self_test( int verbose )
+{
+    int ret, i;
+    mpi A, E, N, X, Y, U, V;
+
+    mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL );
+
+    MPI_CHK( mpi_read_string( &A, 16,
+        "EFE021C2645FD1DC586E69184AF4A31E" \
+        "D5F53E93B5F123FA41680867BA110131" \
+        "944FE7952E2517337780CB0DB80E61AA" \
+        "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
+
+    MPI_CHK( mpi_read_string( &E, 16,
+        "B2E7EFD37075B9F03FF989C7C5051C20" \
+        "34D2A323810251127E7BF8625A4F49A5" \
+        "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+        "5B5C25763222FEFCCFC38B832366C29E" ) );
+
+    MPI_CHK( mpi_read_string( &N, 16,
+        "0066A198186C18C10B2F5ED9B522752A" \
+        "9830B69916E535C8F047518A889A43A5" \
+        "94B6BED27A168D31D4A52F88925AA8F5" ) );
+
+    MPI_CHK( mpi_mul_mpi( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "602AB7ECA597A3D6B56FF9829A5E8B85" \
+        "9E857EA95A03512E2BAE7391688D264A" \
+        "A5663B0341DB9CCFD2C4C5F421FEC814" \
+        "8001B72E848A38CAE1C65F78E56ABDEF" \
+        "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+        "ECF677152EF804370C1A305CAF3B5BF1" \
+        "30879B56C61DE584A0F53A2447A51E" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #1 (mul_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "256567336059E52CAE22925474705F39A94" ) );
+
+    MPI_CHK( mpi_read_string( &V, 16,
+        "6613F26162223DF488E9CD48CC132C7A" \
+        "0AC93C701B001B092E4E5B9F73BCD27B" \
+        "9EE50D0657C77F374E903CDFA4C642" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #2 (div_mpi): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 ||
+        mpi_cmp_mpi( &Y, &V ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "36E139AEA55215609D2816998ED020BB" \
+        "BD96C37890F65171D948E9BC7CBAA4D9" \
+        "325D24D6A3C12710F10A09FA08AB87" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #3 (exp_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    MPI_CHK( mpi_inv_mod( &X, &A, &N ) );
+
+    MPI_CHK( mpi_read_string( &U, 16,
+        "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+        "C3DBA76456363A10869622EAC2DD84EC" \
+        "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
+
+    if( verbose != 0 )
+        printf( "  MPI test #4 (inv_mod): " );
+
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+    if( verbose != 0 )
+        printf( "  MPI test #5 (simple gcd): " );
+
+    for ( i = 0; i < GCD_PAIR_COUNT; i++)
+    {
+        MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) );
+	MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) );
+
+	MPI_CHK( mpi_gcd( &A, &X, &Y ) );
+
+	if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
+	{
+		if( verbose != 0 )
+			printf( "failed at %d\n", i );
+
+		return( 1 );
+	}
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n" );
+
+cleanup:
+
+    if( ret != 0 && verbose != 0 )
+        printf( "Unexpected error, return code = %08X\n", ret );
+
+    mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL );
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( ret );
+}
+
+#endif
+
+#endif
diff --git a/package/utils/px5g-standalone/src/library/rsa.c b/package/utils/px5g-standalone/src/library/rsa.c
new file mode 100644
index 0000000000..131b6c6c9c
--- /dev/null
+++ b/package/utils/px5g-standalone/src/library/rsa.c
@@ -0,0 +1,750 @@
+/*
+ *  The RSA public-key cryptosystem
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+/*
+ *  RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
+ *
+ *  http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_RSA_C)
+
+#include "polarssl/rsa.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Initialize an RSA context
+ */
+void rsa_init( rsa_context *ctx,
+               int padding,
+               int hash_id,
+               int (*f_rng)(void *),
+               void *p_rng )
+{
+    memset( ctx, 0, sizeof( rsa_context ) );
+
+    ctx->padding = padding;
+    ctx->hash_id = hash_id;
+
+    ctx->f_rng = f_rng;
+    ctx->p_rng = p_rng;
+}
+
+#if defined(POLARSSL_GENPRIME)
+
+/*
+ * Generate an RSA keypair
+ */
+int rsa_gen_key( rsa_context *ctx, int nbits, int exponent )
+{
+    int ret;
+    mpi P1, Q1, H, G;
+
+    if( ctx->f_rng == NULL || nbits < 128 || exponent < 3 )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    mpi_init( &P1, &Q1, &H, &G, NULL );
+
+    /*
+     * find primes P and Q with Q < P so that:
+     * GCD( E, (P-1)*(Q-1) ) == 1
+     */
+    MPI_CHK( mpi_lset( &ctx->E, exponent ) );
+
+    do
+    {
+        MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, 
+                                ctx->f_rng, ctx->p_rng ) );
+
+        MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0,
+                                ctx->f_rng, ctx->p_rng ) );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
+            mpi_swap( &ctx->P, &ctx->Q );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
+            continue;
+
+        MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
+        if( mpi_msb( &ctx->N ) != nbits )
+            continue;
+
+        MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+        MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+        MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+        MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+    }
+    while( mpi_cmp_int( &G, 1 ) != 0 );
+
+    /*
+     * D  = E^-1 mod ((P-1)*(Q-1))
+     * DP = D mod (P - 1)
+     * DQ = D mod (Q - 1)
+     * QP = Q^-1 mod P
+     */
+    MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H  ) );
+    MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
+    MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
+    MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
+
+    ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
+
+cleanup:
+
+    mpi_free( &G, &H, &Q1, &P1, NULL );
+
+    if( ret != 0 )
+    {
+        rsa_free( ctx );
+        return( POLARSSL_ERR_RSA_KEY_GEN_FAILED | ret );
+    }
+
+    return( 0 );   
+}
+
+#endif
+
+/*
+ * Check a public RSA key
+ */
+int rsa_check_pubkey( rsa_context *ctx )
+{
+    if( ( ctx->N.p[0] & 1 ) == 0 || 
+        ( ctx->E.p[0] & 1 ) == 0 )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( mpi_msb( &ctx->N ) < 128 ||
+        mpi_msb( &ctx->N ) > 4096 )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    if( mpi_msb( &ctx->E ) < 2 ||
+        mpi_msb( &ctx->E ) > 64 )
+        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
+
+    return( 0 );
+}
+
+/*
+ * Check a private RSA key
+ */
+int rsa_check_privkey( rsa_context *ctx )
+{
+    int ret;
+    mpi PQ, DE, P1, Q1, H, I, G;
+
+    if( ( ret = rsa_check_pubkey( ctx ) ) != 0 )
+        return( ret );
+
+    mpi_init( &PQ, &DE, &P1, &Q1, &H, &I, &G, NULL );
+
+    MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
+    MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
+    MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+    MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+    MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+    MPI_CHK( mpi_mod_mpi( &I, &DE, &H  ) );
+    MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+
+    if( mpi_cmp_mpi( &PQ, &ctx->N ) == 0 &&
+        mpi_cmp_int( &I, 1 ) == 0 &&
+        mpi_cmp_int( &G, 1 ) == 0 )
+    {
+        mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, NULL );
+        return( 0 );
+    }
+
+cleanup:
+
+    mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, NULL );
+    return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret );
+}
+
+/*
+ * Do an RSA public key operation
+ */
+int rsa_public( rsa_context *ctx,
+                unsigned char *input,
+                unsigned char *output )
+{
+    int ret, olen;
+    mpi T;
+
+    mpi_init( &T, NULL );
+
+    MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T, NULL );
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    olen = ctx->len;
+    MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
+    MPI_CHK( mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    if( ret != 0 )
+        return( POLARSSL_ERR_RSA_PUBLIC_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA private key operation
+ */
+int rsa_private( rsa_context *ctx,
+                 unsigned char *input,
+                 unsigned char *output )
+{
+    int ret, olen;
+    mpi T, T1, T2;
+
+    mpi_init( &T, &T1, &T2, NULL );
+
+    MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T, NULL );
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+#if 0
+    MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) );
+#else
+    /*
+     * faster decryption using the CRT
+     *
+     * T1 = input ^ dP mod P
+     * T2 = input ^ dQ mod Q
+     */
+    MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) );
+    MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) );
+
+    /*
+     * T = (T1 - T2) * (Q^-1 mod P) mod P
+     */
+    MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
+    MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
+    MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );
+
+    /*
+     * output = T2 + T * Q
+     */
+    MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
+    MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) );
+#endif
+
+    olen = ctx->len;
+    MPI_CHK( mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T, &T1, &T2, NULL );
+
+    if( ret != 0 )
+        return( POLARSSL_ERR_RSA_PRIVATE_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Add the message padding, then do an RSA operation
+ */
+int rsa_pkcs1_encrypt( rsa_context *ctx,
+                       int mode, int  ilen,
+                       unsigned char *input,
+                       unsigned char *output )
+{
+    int nb_pad, olen;
+    unsigned char *p = output;
+
+    olen = ctx->len;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            if( ilen < 0 || olen < ilen + 11 )
+                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+            nb_pad = olen - 3 - ilen;
+
+            *p++ = 0;
+            *p++ = RSA_CRYPT;
+
+            while( nb_pad-- > 0 )
+            {
+                do {
+                    *p = (unsigned char) rand();
+                } while( *p == 0 );
+                p++;
+            }
+            *p++ = 0;
+            memcpy( p, input, ilen );
+            break;
+
+        default:
+
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, output, output )
+            : rsa_private( ctx, output, output ) );
+}
+
+/*
+ * Do an RSA operation, then remove the message padding
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, int *olen,
+                       unsigned char *input,
+                       unsigned char *output,
+		       int output_max_len)
+{
+    int ret, ilen;
+    unsigned char *p;
+    unsigned char buf[512];
+
+    ilen = ctx->len;
+
+    if( ilen < 16 || ilen > (int) sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, input, buf )
+          : rsa_private( ctx, input, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            if( *p++ != 0 || *p++ != RSA_CRYPT )
+                return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+            while( *p != 0 )
+            {
+                if( p >= buf + ilen - 1 )
+                    return( POLARSSL_ERR_RSA_INVALID_PADDING );
+                p++;
+            }
+            p++;
+            break;
+
+        default:
+
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    if (ilen - (int)(p - buf) > output_max_len)
+    	return( POLARSSL_ERR_RSA_OUTPUT_TO_LARGE );
+
+    *olen = ilen - (int)(p - buf);
+    memcpy( output, p, *olen );
+
+    return( 0 );
+}
+
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int rsa_pkcs1_sign( rsa_context *ctx,
+                    int mode,
+                    int hash_id,
+                    int hashlen,
+                    unsigned char *hash,
+                    unsigned char *sig )
+{
+    int nb_pad, olen;
+    unsigned char *p = sig;
+
+    olen = ctx->len;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            switch( hash_id )
+            {
+                case RSA_RAW:
+                    nb_pad = olen - 3 - hashlen;
+                    break;
+
+                case RSA_MD2:
+                case RSA_MD4:
+                case RSA_MD5:
+                    nb_pad = olen - 3 - 34;
+                    break;
+
+                case RSA_SHA1:
+                    nb_pad = olen - 3 - 35;
+                    break;
+
+                default:
+                    return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+            }
+
+            if( nb_pad < 8 )
+                return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+            *p++ = 0;
+            *p++ = RSA_SIGN;
+            memset( p, 0xFF, nb_pad );
+            p += nb_pad;
+            *p++ = 0;
+            break;
+
+        default:
+
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    switch( hash_id )
+    {
+        case RSA_RAW:
+            memcpy( p, hash, hashlen );
+            break;
+
+        case RSA_MD2:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 2; break;
+
+        case RSA_MD4:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 4; break;
+
+        case RSA_MD5:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 5; break;
+
+        case RSA_SHA1:
+            memcpy( p, ASN1_HASH_SHA1, 15 );
+            memcpy( p + 15, hash, 20 );
+            break;
+
+        default:
+            return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    return( ( mode == RSA_PUBLIC )
+            ? rsa_public(  ctx, sig, sig )
+            : rsa_private( ctx, sig, sig ) );
+}
+
+/*
+ * Do an RSA operation and check the message digest
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      int hashlen,
+                      unsigned char *hash,
+                      unsigned char *sig )
+{
+    int ret, len, siglen;
+    unsigned char *p, c;
+    unsigned char buf[512];
+
+    siglen = ctx->len;
+
+    if( siglen < 16 || siglen > (int) sizeof( buf ) )
+        return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+    ret = ( mode == RSA_PUBLIC )
+          ? rsa_public(  ctx, sig, buf )
+          : rsa_private( ctx, sig, buf );
+
+    if( ret != 0 )
+        return( ret );
+
+    p = buf;
+
+    switch( ctx->padding )
+    {
+        case RSA_PKCS_V15:
+
+            if( *p++ != 0 || *p++ != RSA_SIGN )
+                return( POLARSSL_ERR_RSA_INVALID_PADDING );
+
+            while( *p != 0 )
+            {
+                if( p >= buf + siglen - 1 || *p != 0xFF )
+                    return( POLARSSL_ERR_RSA_INVALID_PADDING );
+                p++;
+            }
+            p++;
+            break;
+
+        default:
+
+            return( POLARSSL_ERR_RSA_INVALID_PADDING );
+    }
+
+    len = siglen - (int)( p - buf );
+
+    if( len == 34 )
+    {
+        c = p[13];
+        p[13] = 0;
+
+        if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+
+        if( ( c == 2 && hash_id == RSA_MD2 ) ||
+            ( c == 4 && hash_id == RSA_MD4 ) ||
+            ( c == 5 && hash_id == RSA_MD5 ) )
+        {
+            if( memcmp( p + 18, hash, 16 ) == 0 ) 
+                return( 0 );
+            else
+                return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+        }
+    }
+
+    if( len == 35 && hash_id == RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
+            memcmp( p + 15, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    if( len == hashlen && hash_id == RSA_RAW )
+    {
+        if( memcmp( p, hash, hashlen ) == 0 )
+            return( 0 );
+        else
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+    }
+
+    return( POLARSSL_ERR_RSA_INVALID_PADDING );
+}
+
+/*
+ * Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx )
+{
+    mpi_free( &ctx->RQ, &ctx->RP, &ctx->RN,
+              &ctx->QP, &ctx->DQ, &ctx->DP,
+              &ctx->Q,  &ctx->P,  &ctx->D,
+              &ctx->E,  &ctx->N,  NULL );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include "polarssl/sha1.h"
+
+/*
+ * Example RSA-1024 keypair, for test purposes
+ */
+#define KEY_LEN 128
+
+#define RSA_N   "9292758453063D803DD603D5E777D788" \
+                "8ED1D5BF35786190FA2F23EBC0848AEA" \
+                "DDA92CA6C3D80B32C4D109BE0F36D6AE" \
+                "7130B9CED7ACDF54CFC7555AC14EEBAB" \
+                "93A89813FBF3C4F8066D2D800F7C38A8" \
+                "1AE31942917403FF4946B0A83D3D3E05" \
+                "EE57C6F5F5606FB5D4BC6CD34EE0801A" \
+                "5E94BB77B07507233A0BC7BAC8F90F79"
+
+#define RSA_E   "10001"
+
+#define RSA_D   "24BF6185468786FDD303083D25E64EFC" \
+                "66CA472BC44D253102F8B4A9D3BFA750" \
+                "91386C0077937FE33FA3252D28855837" \
+                "AE1B484A8A9A45F7EE8C0C634F99E8CD" \
+                "DF79C5CE07EE72C7F123142198164234" \
+                "CABB724CF78B8173B9F880FC86322407" \
+                "AF1FEDFDDE2BEB674CA15F3E81A1521E" \
+                "071513A1E85B5DFA031F21ECAE91A34D"
+
+#define RSA_P   "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
+                "2C01CAD19EA484A87EA4377637E75500" \
+                "FCB2005C5C7DD6EC4AC023CDA285D796" \
+                "C3D9E75E1EFC42488BB4F1D13AC30A57"
+
+#define RSA_Q   "C000DF51A7C77AE8D7C7370C1FF55B69" \
+                "E211C2B9E5DB1ED0BF61D0D9899620F4" \
+                "910E4168387E3C30AA1E00C339A79508" \
+                "8452DD96A9A5EA5D9DCA68DA636032AF"
+
+#define RSA_DP  "C1ACF567564274FB07A0BBAD5D26E298" \
+                "3C94D22288ACD763FD8E5600ED4A702D" \
+                "F84198A5F06C2E72236AE490C93F07F8" \
+                "3CC559CD27BC2D1CA488811730BB5725"
+
+#define RSA_DQ  "4959CBF6F8FEF750AEE6977C155579C7" \
+                "D8AAEA56749EA28623272E4F7D0592AF" \
+                "7C1F1313CAC9471B5C523BFE592F517B" \
+                "407A1BD76C164B93DA2D32A383E58357"
+
+#define RSA_QP  "9AE7FBC99546432DF71896FC239EADAE" \
+                "F38D18D2B2F0E2DD275AA977E2BF4411" \
+                "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
+                "A74206CEC169D74BF5A8C50D6F48EA08"
+
+#define PT_LEN  24
+#define RSA_PT  "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
+                "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
+
+/*
+ * Checkup routine
+ */
+int rsa_self_test( int verbose )
+{
+    int len;
+    rsa_context rsa;
+    unsigned char sha1sum[20];
+    unsigned char rsa_plaintext[PT_LEN];
+    unsigned char rsa_decrypted[PT_LEN];
+    unsigned char rsa_ciphertext[KEY_LEN];
+
+    memset( &rsa, 0, sizeof( rsa_context ) );
+
+    rsa.len = KEY_LEN;
+    mpi_read_string( &rsa.N , 16, RSA_N  );
+    mpi_read_string( &rsa.E , 16, RSA_E  );
+    mpi_read_string( &rsa.D , 16, RSA_D  );
+    mpi_read_string( &rsa.P , 16, RSA_P  );
+    mpi_read_string( &rsa.Q , 16, RSA_Q  );
+    mpi_read_string( &rsa.DP, 16, RSA_DP );
+    mpi_read_string( &rsa.DQ, 16, RSA_DQ );
+    mpi_read_string( &rsa.QP, 16, RSA_QP );
+
+    if( verbose != 0 )
+        printf( "  RSA key validation: " );
+
+    if( rsa_check_pubkey(  &rsa ) != 0 ||
+        rsa_check_privkey( &rsa ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 encryption : " );
+
+    memcpy( rsa_plaintext, RSA_PT, PT_LEN );
+
+    if( rsa_pkcs1_encrypt( &rsa, RSA_PUBLIC, PT_LEN,
+                           rsa_plaintext, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 decryption : " );
+
+    if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len,
+                           rsa_ciphertext, rsa_decrypted,
+			   sizeof(rsa_decrypted) ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 data sign  : " );
+
+    sha1( rsa_plaintext, PT_LEN, sha1sum );
+
+    if( rsa_pkcs1_sign( &rsa, RSA_PRIVATE, RSA_SHA1, 20,
+                        sha1sum, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n  PKCS#1 sig. verify: " );
+
+    if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, RSA_SHA1, 20,
+                          sha1sum, rsa_ciphertext ) != 0 )
+    {
+        if( verbose != 0 )
+            printf( "failed\n" );
+
+        return( 1 );
+    }
+
+    if( verbose != 0 )
+        printf( "passed\n\n" );
+
+    rsa_free( &rsa );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/package/utils/px5g-standalone/src/library/sha1.c b/package/utils/px5g-standalone/src/library/sha1.c
new file mode 100644
index 0000000000..54a4416f31
--- /dev/null
+++ b/package/utils/px5g-standalone/src/library/sha1.c
@@ -0,0 +1,622 @@
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_SHA1_C)
+
+#include "polarssl/sha1.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_ULONG_BE
+#define GET_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
+        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
+        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
+        | ( (unsigned long) (b)[(i) + 3]       );       \
+}
+#endif
+
+#ifndef PUT_ULONG_BE
+#define PUT_ULONG_BE(n,b,i)                             \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * SHA-1 context setup
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+static void sha1_process( sha1_context *ctx, unsigned char data[64] )
+{
+    unsigned long temp, W[16], A, B, C, D, E;
+
+    GET_ULONG_BE( W[ 0], data,  0 );
+    GET_ULONG_BE( W[ 1], data,  4 );
+    GET_ULONG_BE( W[ 2], data,  8 );
+    GET_ULONG_BE( W[ 3], data, 12 );
+    GET_ULONG_BE( W[ 4], data, 16 );
+    GET_ULONG_BE( W[ 5], data, 20 );
+    GET_ULONG_BE( W[ 6], data, 24 );
+    GET_ULONG_BE( W[ 7], data, 28 );
+    GET_ULONG_BE( W[ 8], data, 32 );
+    GET_ULONG_BE( W[ 9], data, 36 );
+    GET_ULONG_BE( W[10], data, 40 );
+    GET_ULONG_BE( W[11], data, 44 );
+    GET_ULONG_BE( W[12], data, 48 );
+    GET_ULONG_BE( W[13], data, 52 );
+    GET_ULONG_BE( W[14], data, 56 );
+    GET_ULONG_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void sha1_update( sha1_context *ctx, unsigned char *input, int ilen )
+{
+    int fill;
+    unsigned long left;
+
+    if( ilen <= 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (unsigned long) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha1_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha1_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, ilen );
+    }
+}
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned long last, padn;
+    unsigned long high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_ULONG_BE( high, msglen, 0 );
+    PUT_ULONG_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, (unsigned char *) sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_ULONG_BE( ctx->state[0], output,  0 );
+    PUT_ULONG_BE( ctx->state[1], output,  4 );
+    PUT_ULONG_BE( ctx->state[2], output,  8 );
+    PUT_ULONG_BE( ctx->state[3], output, 12 );
+    PUT_ULONG_BE( ctx->state[4], output, 16 );
+}
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void sha1( unsigned char *input, int ilen, unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, input, ilen );
+    sha1_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+/*
+ * output = SHA-1( file contents )
+ */
+int sha1_file( char *path, unsigned char output[20] )
+{
+    FILE *f;
+    size_t n;
+    sha1_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha1_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha1_update( &ctx, buf, (int) n );
+
+    sha1_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( 2 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * SHA-1 HMAC context setup
+ */
+void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen )
+{
+    int i;
+    unsigned char sum[20];
+
+    if( keylen > 64 )
+    {
+        sha1( key, keylen, sum );
+        keylen = 20;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->ipad, 64 );
+
+    memset( sum, 0, sizeof( sum ) );
+}
+
+/*
+ * SHA-1 HMAC process buffer
+ */
+void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen )
+{
+    sha1_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-1 HMAC final digest
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned char tmpbuf[20];
+
+    sha1_finish( ctx, tmpbuf );
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->opad, 64 );
+    sha1_update( ctx, tmpbuf, 20 );
+    sha1_finish( ctx, output );
+
+    memset( tmpbuf, 0, sizeof( tmpbuf ) );
+}
+
+/*
+ * output = HMAC-SHA-1( hmac key, input buffer )
+ */
+void sha1_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_hmac_starts( &ctx, key, keylen );
+    sha1_hmac_update( &ctx, input, ilen );
+    sha1_hmac_finish( &ctx, output );
+
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+/*
+ * FIPS-180-1 test vectors
+ */
+static unsigned char sha1_test_buf[3][57] = 
+{
+    { "abc" },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+    { "" }
+};
+
+static const int sha1_test_buflen[3] =
+{
+    3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] =
+{
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * RFC 2202 test vectors
+ */
+static unsigned char sha1_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+      "\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+      "\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+      "\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 80 times */
+    { "" }
+};
+
+static const int sha1_hmac_test_keylen[7] =
+{
+    20, 4, 20, 25, 20, 80, 80
+};
+
+static unsigned char sha1_hmac_test_buf[7][74] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "Test Using Larger Than Block-Size Key and Larger"
+      " Than One Block-Size Data" }
+};
+
+static const int sha1_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 73
+};
+
+static const unsigned char sha1_hmac_test_sum[7][20] =
+{
+    { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
+      0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
+    { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
+      0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
+    { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
+      0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
+    { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
+      0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
+    { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
+      0x7B, 0xE1 },
+    { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
+      0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
+    { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
+      0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( int verbose )
+{
+    int i, j, buflen;
+    unsigned char buf[1024];
+    unsigned char sha1sum[20];
+    sha1_context ctx;
+
+    /*
+     * SHA-1
+     */
+    for( i = 0; i < 3; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  SHA-1 test #%d: ", i + 1 );
+
+        sha1_starts( &ctx );
+
+        if( i == 2 )
+        {
+            memset( buf, 'a', buflen = 1000 );
+
+            for( j = 0; j < 1000; j++ )
+                sha1_update( &ctx, buf, buflen );
+        }
+        else
+            sha1_update( &ctx, sha1_test_buf[i],
+                               sha1_test_buflen[i] );
+
+        sha1_finish( &ctx, sha1sum );
+
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            printf( "  HMAC-SHA-1 test #%d: ", i + 1 );
+
+        if( i == 5 || i == 6 )
+        {
+            memset( buf, '\xAA', buflen = 80 );
+            sha1_hmac_starts( &ctx, buf, buflen );
+        }
+        else
+            sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
+                                    sha1_hmac_test_keylen[i] );
+
+        sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
+                                sha1_hmac_test_buflen[i] );
+
+        sha1_hmac_finish( &ctx, sha1sum );
+
+        buflen = ( i == 4 ) ? 12 : 20;
+
+        if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                printf( "failed\n" );
+
+            return( 1 );
+        }
+
+        if( verbose != 0 )
+            printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        printf( "\n" );
+
+    return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/package/utils/px5g-standalone/src/library/timing.c b/package/utils/px5g-standalone/src/library/timing.c
new file mode 100644
index 0000000000..6b7ab740e1
--- /dev/null
+++ b/package/utils/px5g-standalone/src/library/timing.c
@@ -0,0 +1,265 @@
+/*
+ *  Portable interface to the CPU cycle counter
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *
+ *  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
+ *  OWNER 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.
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_TIMING_C)
+
+#include "polarssl/timing.h"
+
+#if defined(WIN32)
+
+#include <windows.h>
+#include <winbase.h>
+
+struct _hr_time
+{
+    LARGE_INTEGER start;
+};
+
+#else
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <time.h>
+
+struct _hr_time
+{
+    struct timeval start;
+};
+
+#endif
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+unsigned long hardclock( void )
+{
+    unsigned long tsc;
+    __asm   rdtsc
+    __asm   mov  [tsc], eax
+    return( tsc );
+}
+
+#else
+#if defined(__GNUC__) && defined(__i386__)
+
+unsigned long hardclock( void )
+{
+    unsigned long tsc;
+    asm( "rdtsc" : "=a" (tsc) );
+    return( tsc );
+}
+
+#else
+#if defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
+
+unsigned long hardclock( void )
+{
+    unsigned long lo, hi;
+    asm( "rdtsc" : "=a" (lo), "=d" (hi) );
+    return( lo | (hi << 32) );
+}
+
+#else
+#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
+
+unsigned long hardclock( void )
+{
+    unsigned long tbl, tbu0, tbu1;
+
+    do
+    {
+        asm( "mftbu %0" : "=r" (tbu0) );
+        asm( "mftb  %0" : "=r" (tbl ) );
+        asm( "mftbu %0" : "=r" (tbu1) );
+    }
+    while( tbu0 != tbu1 );
+
+    return( tbl );
+}
+
+#else
+#if defined(__GNUC__) && defined(__sparc__)
+
+unsigned long hardclock( void )
+{
+    unsigned long tick;
+    asm( ".byte 0x83, 0x41, 0x00, 0x00" );
+    asm( "mov   %%g1, %0" : "=r" (tick) );
+    return( tick );
+}
+
+#else
+#if defined(__GNUC__) && defined(__alpha__)
+
+unsigned long hardclock( void )
+{
+    unsigned long cc;
+    asm( "rpcc %0" : "=r" (cc) );
+    return( cc & 0xFFFFFFFF );
+}
+
+#else
+#if defined(__GNUC__) && defined(__ia64__)
+
+unsigned long hardclock( void )
+{
+    unsigned long itc;
+    asm( "mov %0 = ar.itc" : "=r" (itc) );
+    return( itc );
+}
+
+#else
+
+static int hardclock_init = 0;
+static struct timeval tv_init;
+
+unsigned long hardclock( void )
+{
+    struct timeval tv_cur;
+
+    if( hardclock_init == 0 )
+    {
+        gettimeofday( &tv_init, NULL );
+        hardclock_init = 1;
+    }
+
+    gettimeofday( &tv_cur, NULL );
+    return( ( tv_cur.tv_sec  - tv_init.tv_sec  ) * 1000000
+          + ( tv_cur.tv_usec - tv_init.tv_usec ) );
+}
+
+#endif /* generic */
+#endif /* IA-64   */
+#endif /* Alpha   */
+#endif /* SPARC8  */
+#endif /* PowerPC */
+#endif /* AMD64   */
+#endif /* i586+   */
+
+int alarmed = 0;
+
+#if defined(WIN32)
+
+unsigned long get_timer( struct hr_time *val, int reset )
+{
+    unsigned long delta;
+    LARGE_INTEGER offset, hfreq;
+    struct _hr_time *t = (struct _hr_time *) val;
+
+    QueryPerformanceCounter(  &offset );
+    QueryPerformanceFrequency( &hfreq );
+
+    delta = (unsigned long)( ( 1000 *
+        ( offset.QuadPart - t->start.QuadPart ) ) /
+           hfreq.QuadPart );
+
+    if( reset )
+        QueryPerformanceCounter( &t->start );
+
+    return( delta );
+}
+
+DWORD WINAPI TimerProc( LPVOID uElapse )
+{
+    Sleep( (DWORD) uElapse );
+    alarmed = 1;
+    return( TRUE );
+}
+
+void set_alarm( int seconds )
+{
+    DWORD ThreadId;
+
+    alarmed = 0;
+    CloseHandle( CreateThread( NULL, 0, TimerProc,
+        (LPVOID) ( seconds * 1000 ), 0, &ThreadId ) );
+}
+
+void m_sleep( int milliseconds )
+{
+    Sleep( milliseconds );
+}
+
+#else
+
+unsigned long get_timer( struct hr_time *val, int reset )
+{
+    unsigned long delta;
+    struct timeval offset;
+    struct _hr_time *t = (struct _hr_time *) val;
+
+    gettimeofday( &offset, NULL );
+
+    delta = ( offset.tv_sec  - t->start.tv_sec  ) * 1000
+          + ( offset.tv_usec - t->start.tv_usec ) / 1000;
+
+    if( reset )
+    {
+        t->start.tv_sec  = offset.tv_sec;
+        t->start.tv_usec = offset.tv_usec;
+    }
+
+    return( delta );
+}
+
+static void sighandler( int signum )
+{
+    alarmed = 1;
+    signal( signum, sighandler );
+}
+
+void set_alarm( int seconds )
+{
+    alarmed = 0;
+    signal( SIGALRM, sighandler );
+    alarm( seconds );
+}
+
+void m_sleep( int milliseconds )
+{
+    struct timeval tv;
+
+    tv.tv_sec  = milliseconds / 1000;
+    tv.tv_usec = milliseconds * 1000;
+
+    select( 0, NULL, NULL, NULL, &tv );
+}
+
+#endif
+
+#endif
diff --git a/package/utils/px5g-standalone/src/library/x509write.c b/package/utils/px5g-standalone/src/library/x509write.c
new file mode 100644
index 0000000000..2b0eb71563
--- /dev/null
+++ b/package/utils/px5g-standalone/src/library/x509write.c
@@ -0,0 +1,1162 @@
+/*
+ *  X.509 certificate and private key writing
+ *
+ *  Copyright (C) 2006-2007  Pascal Vizeli <pvizeli@yahoo.de>
+ *  Modifications (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+/*
+ *  The ITU-T X.509 standard defines a certificat format for PKI.
+ *
+ *  http://www.ietf.org/rfc/rfc2459.txt
+ *  http://www.ietf.org/rfc/rfc3279.txt
+ *
+ *  ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ *
+ *  For CRS:
+ *  http://www.faqs.org/rfcs/rfc2314.html
+ */
+#include "polarssl/config.h"
+#include "polarssl/x509.h"
+#include "polarssl/base64.h"
+#include "polarssl/sha1.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+
+#define and &&
+#define or ||
+
+#if defined _MSC_VER && !defined snprintf
+#define snprintf _snprintf
+#endif
+
+static int x509write_realloc_node(x509_node *node, size_t larger);
+static int x509write_file(x509_node *node, char *path, int format, const char* pem_prolog, const char* pem_epilog);
+
+/*
+ * evaluate how mani octet have this integer
+ */
+static int asn1_eval_octet(unsigned int digit)
+{
+    int i, byte;
+
+    for (byte = 4, i = 24; i >= 0; i -= 8, --byte)
+        if (((digit >> i) & 0xFF) != 0)
+            return byte;
+
+    return 0;
+}
+
+/*
+ * write the asn.1 lenght form into p
+ */
+static int asn1_add_len(unsigned int size, x509_node *node)
+{
+    if (size > 127) {
+
+        /* long size */
+        int byte = asn1_eval_octet(size);
+        int i = 0;
+
+        *(node->p) = (0x80 | byte) & 0xFF;
+        ++node->p;
+
+        for (i = byte; i > 0; --i) {
+
+            *(node->p) = (size >> ((i - 1) * 8)) & 0xFF;
+            ++node->p;
+        }
+
+    } else {
+
+        /* short size */
+        *(node->p) = size & 0xFF;
+        if (size != 0)
+            ++node->p;
+    }
+
+    return 0;
+}
+
+/*
+ * write a ans.1 object into p
+ */
+static int asn1_add_obj(unsigned char *value, unsigned int size, int tag,
+        x509_node *node)
+{
+    int tl = 2;
+
+    if (tag == ASN1_BIT_STRING)
+        ++tl;
+
+    if (size > 127)
+        x509write_realloc_node(node, (size_t) size + tl +
+                asn1_eval_octet(size));
+    else
+        x509write_realloc_node(node, (size_t) size + tl);
+
+    if (node->data == NULL)
+        return 1;
+
+    /* tag */
+    *(node->p) = tag & 0xFF;
+    ++node->p;
+
+    /* len */
+    if (tag == ASN1_BIT_STRING) {
+        asn1_add_len((unsigned int) size + 1, node);
+        *(node->p) = 0x00;
+        ++node->p;
+    } else {
+        asn1_add_len((unsigned int) size, node);
+    }
+
+    /* value */
+    if (size > 0) {
+
+        memcpy(node->p, value, (size_t) size);
+        if ((node->p += size -1) != node->end)
+            return POLARSSL_ERR_X509_POINT_ERROR;
+    } else {
+        /* make nothing -> NULL */
+    }
+
+    return 0;
+}
+
+/*
+ * write a asn.1 conform integer object
+ */
+static int asn1_add_int(signed int value, x509_node *node)
+{
+    signed int i = 0, neg = 1;
+    unsigned int byte, u_val = 0, tmp_val = 0;
+
+    /* if negate? */
+    if (value < 0) {
+        neg = -1;
+        u_val = ~value;
+    } else {
+        u_val = value;
+    }
+
+    byte = asn1_eval_octet(u_val);
+    /* 0 isn't NULL */
+    if (byte == 0)
+        byte = 1;
+
+    /* ASN.1 integer is signed! */
+    if (byte < 4 and ((u_val >> ((byte -1) * 8)) & 0xFF) == 0x80)
+        byte += 1;
+
+    if (x509write_realloc_node(node, (size_t) byte + 2) != 0)
+        return 1;
+
+    /* tag */
+    *(node->p) = ASN1_INTEGER;
+    ++node->p;
+
+    /* len */
+    asn1_add_len(byte, node);
+
+    /* value */
+    for (i = byte; i > 0; --i) {
+
+        tmp_val = (u_val >> ((i - 1) * 8)) & 0xFF;
+        if (neg == 1)
+            *(node->p) = tmp_val;
+        else
+            *(node->p) = ~tmp_val;
+
+        if (i > 1)
+          ++node->p;
+    }
+
+    if (node->p != node->end)
+        return POLARSSL_ERR_X509_POINT_ERROR;
+
+    return 0;
+}
+
+/*
+ * write a asn.1 conform mpi object
+ */
+static int asn1_add_mpi(mpi *value, int tag, x509_node *node)
+{
+    size_t size = (mpi_msb(value) / 8) + 1;
+    unsigned char *buf;
+    int buf_len = (int) size, tl = 2;
+
+    if (tag == ASN1_BIT_STRING)
+        ++tl;
+
+    if (size > 127)
+        x509write_realloc_node(node, size + (size_t) tl +
+            asn1_eval_octet((unsigned int)size));
+    else
+        x509write_realloc_node(node, size + (size_t) tl);
+
+    if (node->data == NULL)
+        return 1;
+
+    buf = (unsigned char*) malloc(size);
+    if (mpi_write_binary(value, buf, buf_len) != 0)
+        return POLARSSL_ERR_MPI_BUFFER_TOO_SMALL;
+
+    /* tag */
+    *(node->p) = tag & 0xFF;
+    ++node->p;
+
+    /* len */
+    if (tag == ASN1_BIT_STRING) {
+        asn1_add_len((unsigned int) size + 1, node);
+        *(node->p) = 0x00;
+        ++node->p;
+    } else {
+        asn1_add_len((unsigned int) size, node);
+    }
+
+    /* value */
+    memcpy(node->p, buf, size);
+    free(buf);
+
+    if ((node->p += (int) size -1) != node->end)
+        return POLARSSL_ERR_X509_POINT_ERROR;
+
+    return 0;
+}
+
+/*
+ * write a node into asn.1 conform object
+ */
+static int asn1_append_tag(x509_node *node, int tag)
+{
+    int tl = 2;
+
+    x509_node tmp;
+    x509write_init_node(&tmp);
+
+    if (tag == ASN1_BIT_STRING)
+        ++tl;
+
+    if (node->len > 127)
+        x509write_realloc_node(&tmp, node->len + (size_t) tl +
+            asn1_eval_octet((unsigned int)node->len));
+    else
+        x509write_realloc_node(&tmp, node->len + (size_t) tl);
+
+    if (tmp.data == NULL) {
+        x509write_free_node(&tmp);
+        return 1;
+    }
+
+    /* tag */
+    *(tmp.p) = tag & 0xFF;
+    ++tmp.p;
+
+    /* len */
+    if (tag == ASN1_BIT_STRING) {
+        asn1_add_len((unsigned int) node->len + 1, &tmp);
+        *(tmp.p) = 0x00;
+        ++tmp.p;
+    } else {
+        asn1_add_len((unsigned int) node->len, &tmp);
+    }
+
+    /* value */
+    memcpy(tmp.p, node->data, node->len);
+
+    /* good? */
+    if ((tmp.p += (int) node->len -1) != tmp.end) {
+        x509write_free_node(&tmp);
+        return POLARSSL_ERR_X509_POINT_ERROR;
+    }
+
+    free(node->data);
+    node->data = tmp.data;
+    node->p = tmp.p;
+    node->end = tmp.end;
+    node->len = tmp.len;
+
+    return 0;
+}
+
+/*
+ * write nodes into a asn.1 object
+ */
+static int asn1_append_nodes(x509_node *node, int tag, int anz, ...)
+{
+    va_list ap;
+    size_t size = 0;
+    x509_node *tmp;
+    int count;
+
+    va_start(ap, anz);
+    count = anz;
+
+    while (count--) {
+
+        tmp = va_arg(ap, x509_node*);
+        if (tmp->data != NULL)
+            size += tmp->len;
+    }
+
+    if ( size > 127) {
+        if (x509write_realloc_node(node, size + (size_t) 2 +
+                    asn1_eval_octet(size)) != 0)
+            return 1;
+    } else {
+        if (x509write_realloc_node(node, size + (size_t) 2) != 0)
+            return 1;
+    }
+
+    /* tag */
+    *(node->p) = tag & 0xFF;
+    ++node->p;
+
+    /* len */
+    asn1_add_len(size, node);
+
+    /* value */
+    va_start(ap, anz);
+    count = anz;
+
+    while (count--) {
+
+        tmp = va_arg(ap, x509_node*);
+        if (tmp->data != NULL) {
+
+            memcpy(node->p, tmp->data, tmp->len);
+            if ((node->p += (int) tmp->len -1) != node->end)
+                ++node->p;
+        }
+    }
+
+    va_end(ap);
+    return 0;
+}
+
+/*
+ * write a ASN.1 conform object identifiere include a "tag"
+ */
+static int asn1_add_oid(x509_node *node, unsigned char *oid, size_t len,
+        int tag, int tag_val, unsigned char *value, size_t val_len)
+{
+    int ret;
+    x509_node tmp;
+
+    x509write_init_node(&tmp);
+
+    /* OBJECT IDENTIFIER */
+    if ((ret = asn1_add_obj(oid, len, ASN1_OID, &tmp)) != 0) {
+        x509write_free_node(&tmp);
+        return ret;
+    }
+
+    /* value */
+    if ((ret = asn1_add_obj(value, val_len, tag_val, &tmp)) != 0) {
+        x509write_free_node(&tmp);
+        return ret;
+    }
+
+    /* SET/SEQUENCE */
+    if ((ret = asn1_append_nodes(node, tag, 1, &tmp)) != 0) {
+        x509write_free_node(&tmp);
+        return ret;
+    }
+
+    x509write_free_node(&tmp);
+    return 0;
+}
+
+/*
+ *  utcTime        UTCTime
+ */
+static int asn1_add_date_utc(unsigned char *time, x509_node *node)
+{
+    unsigned char date[13], *sp;
+    x509_time xtime;
+    int ret;
+
+    sscanf((char*)time, "%d-%d-%d %d:%d:%d", &xtime.year, &xtime.mon,
+    	&xtime.day, &xtime.hour, &xtime.min, &xtime.sec);
+
+    /* convert to YY */
+    if (xtime.year > 2000)
+        xtime.year -= 2000;
+    else
+        xtime.year -= 1900;
+
+    snprintf((char*)date, 13, "%2d%2d%2d%2d%2d%2d", xtime.year, xtime.mon, xtime.day,
+        xtime.hour, xtime.min, xtime.sec);
+
+    /* replace ' ' to '0' */
+    for (sp = date; *sp != '\0'; ++sp)
+        if (*sp == '\x20')
+            *sp = '\x30';
+
+    date[12] = 'Z';
+
+    if ((ret = asn1_add_obj(date, 13, ASN1_UTC_TIME, node)) != 0)
+        return ret;
+
+    return 0;
+}
+
+/*
+ * serialize an rsa key into DER
+ */
+
+int x509write_serialize_key(rsa_context *rsa, x509_node *node)
+{
+    int ret = 0;
+    x509write_init_node(node);
+
+    /* vers, n, e, d, p, q, dp, dq, pq */
+    if ((ret = asn1_add_int(rsa->ver, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->N, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->E, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->D, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->P, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->Q, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->DP, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->DQ, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_add_mpi(&rsa->QP, ASN1_INTEGER, node)) != 0)
+        return ret;
+    if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+        return ret;
+
+    return 0;
+}
+
+/*
+ * write a der/pem encoded rsa private key into a file
+ */
+int x509write_keyfile(rsa_context *rsa, char *path, int out_flag)
+{
+    int ret = 0;
+    const char	key_beg[] = "-----BEGIN RSA PRIVATE KEY-----\n",
+                key_end[] = "-----END RSA PRIVATE KEY-----\n";
+    x509_node node;
+
+    x509write_init_node(&node);
+    if ((ret = x509write_serialize_key(rsa,&node)) != 0) {
+        x509write_free_node(&node);
+	      return ret;
+    }
+
+    ret = x509write_file(&node,path,out_flag,key_beg,key_end);
+    x509write_free_node(&node);
+
+    return ret;
+}
+
+
+/*
+ * reasize the memory for node
+ */
+static int x509write_realloc_node(x509_node *node, size_t larger)
+{
+    /* init len */
+    if (node->data == NULL) {
+        node->len = 0;
+        node->data = malloc(larger);
+        if(node->data == NULL)
+            return 1;
+    } else {
+        /* realloc memory */
+        if ((node->data = realloc(node->data, node->len + larger)) == NULL)
+            return 1;
+    }
+
+    /* init pointer */
+    node->p = &node->data[node->len];
+    node->len += larger;
+    node->end = &node->data[node->len -1];
+
+    return 0;
+}
+
+/*
+ * init node
+ */
+void x509write_init_node(x509_node *node)
+{
+    memset(node, 0, sizeof(x509_node));
+}
+
+/*
+ * clean memory
+ */
+void x509write_free_node(x509_node *node)
+{
+    if (node->data != NULL)
+        free(node->data);
+    node->p = NULL;
+    node->end = NULL;
+    node->len = 0;
+}
+
+/*
+ * write a x509 certificate into file
+ */
+int x509write_crtfile(x509_raw *chain, unsigned char *path, int out_flag)
+{
+    const char	cer_beg[] = "-----BEGIN CERTIFICATE-----\n",
+		cer_end[] = "-----END CERTIFICATE-----\n";
+
+    return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end);
+}
+
+/*
+ * write a x509 certificate into file
+ */
+int x509write_csrfile(x509_raw *chain, unsigned char *path, int out_flag)
+{
+    const char	cer_beg[] = "-----BEGIN CERTIFICATE REQUEST-----\n",
+		cer_end[] = "-----END CERTIFICATE REQUEST-----\n";
+
+    return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end);
+}
+
+/*
+ * write an x509 file
+ */
+static int x509write_file(x509_node *node, char *path, int format,
+        const char* pem_prolog, const char* pem_epilog)
+{
+    FILE *ofstream = stdout;
+    int is_err = 1, buf_len, i, n;
+    unsigned char* base_buf;
+
+    if (path) {
+    	if ((ofstream = fopen(path, "wb")) == NULL)
+    		return 1;
+    }
+
+    switch (format) {
+        case X509_OUTPUT_DER:
+            if (fwrite(node->data, 1, node->len, ofstream)
+                != node->len)
+                is_err = -1;
+            break;
+
+        case X509_OUTPUT_PEM:
+            if (fprintf(ofstream, "%s", pem_prolog)<0) {
+                is_err = -1;
+                break;
+            }
+
+            buf_len = node->len << 1;
+            base_buf = (unsigned char*) malloc((size_t)buf_len);
+            memset(base_buf,0,buf_len);
+            if (base64_encode(base_buf, &buf_len, node->data,
+                        (int) node->len) != 0) {
+                is_err = -1;
+                break;
+            }
+
+            n=strlen((char*)base_buf);
+            for(i=0;i<n;i+=64) {
+                fprintf(ofstream,"%.64s\n",&base_buf[i]);
+            }
+
+            if (fprintf(ofstream, "%s", pem_epilog)<0) {
+                is_err = -1;
+                break;
+            }
+
+            free(base_buf);
+    }
+
+    fclose(ofstream);
+
+    if (is_err == -1)
+        return 1;
+
+    return 0;
+}
+
+
+/*
+ * add the owner public key to x509 certificate
+ */
+int x509write_add_pubkey(x509_raw *chain, rsa_context *pubkey)
+{
+    x509_node n_tmp, n_tmp2, *node;
+    int ret;
+
+    node = &chain->subpubkey;
+
+    x509write_init_node(&n_tmp);
+    x509write_init_node(&n_tmp2);
+
+    /*
+    *  RSAPublicKey ::= SEQUENCE {
+    *      modulus           INTEGER,  -- n
+    *      publicExponent    INTEGER   -- e
+    *  }
+    */
+    if ((ret = asn1_add_mpi(&pubkey->N, ASN1_INTEGER, &n_tmp)) != 0) {
+        x509write_free_node(&n_tmp);
+        x509write_free_node(&n_tmp2);
+        return ret;
+    }
+    if ((ret = asn1_add_mpi(&pubkey->E, ASN1_INTEGER, &n_tmp)) != 0) {
+        x509write_free_node(&n_tmp);
+        x509write_free_node(&n_tmp2);
+        return ret;
+    }
+    if ((ret = asn1_append_tag(&n_tmp, ASN1_CONSTRUCTED | ASN1_SEQUENCE))
+            != 0) {
+        x509write_free_node(&n_tmp);
+        x509write_free_node(&n_tmp2);
+        return ret;
+    }
+
+    /*
+     *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
+     *       algorithm            AlgorithmIdentifier,
+     *       subjectPublicKey     BIT STRING }
+     */
+    if ((ret = asn1_append_tag(&n_tmp, ASN1_BIT_STRING)) != 0) {
+        x509write_free_node(&n_tmp);
+        x509write_free_node(&n_tmp2);
+       return ret;
+    }
+    if ((ret = asn1_add_oid(&n_tmp2, (unsigned char*)OID_PKCS1_RSA, 9,
+                  ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL,
+                  (unsigned char *)"", 0)) != 0) {
+        x509write_free_node(&n_tmp);
+        x509write_free_node(&n_tmp2);
+        return ret;
+    }
+
+    if ((ret = asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE, 2,
+                   &n_tmp2, &n_tmp))) {
+        x509write_free_node(&n_tmp);
+        x509write_free_node(&n_tmp2);
+        return ret;
+    }
+
+    x509write_free_node(&n_tmp);
+    x509write_free_node(&n_tmp2);
+    return 0;
+}
+
+/*
+ *  RelativeDistinguishedName ::=
+ *    SET OF AttributeTypeAndValue
+ *
+ *  AttributeTypeAndValue ::= SEQUENCE {
+ *    type     AttributeType,
+ *    value    AttributeValue }
+ */
+static int x509write_add_name(x509_node *node, unsigned char *oid,
+        unsigned int oid_len, unsigned char *value, int len, int value_tag)
+{
+    int ret;
+    x509_node n_tmp;
+
+    x509write_init_node(&n_tmp);
+
+    if ((ret = asn1_add_oid(&n_tmp, oid, oid_len,
+                ASN1_CONSTRUCTED | ASN1_SEQUENCE, value_tag,
+                value, len))) {
+        x509write_free_node(&n_tmp);
+        return ret;
+    }
+
+    if ((asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SET, 1, &n_tmp))
+            != 0) {
+        x509write_free_node(&n_tmp);
+        return ret;
+    }
+
+    x509write_free_node(&n_tmp);
+    return 0;
+}
+
+/*
+ * Parse the name string and add to node
+ */
+static int x509write_parse_names(x509_node *node, unsigned char *names)
+{
+    unsigned char *sp, *begin = NULL;
+    unsigned char oid[3] = OID_X520, tag[4], *tag_sp = tag;
+    unsigned char *C = NULL, *CN = NULL, *O = NULL, *OU = NULL,
+                  *ST = NULL, *L = NULL, *R = NULL;
+    int C_len = 0, CN_len = 0, O_len = 0, OU_len = 0, ST_len = 0,
+		L_len = 0, R_len = 0;
+    int ret = 0, is_tag = 1, is_begin = -1, len = 0;
+
+
+    for (sp = names; ; ++sp) {
+
+        /* filter tag */
+        if (is_tag == 1) {
+
+            if (tag_sp == &tag[3])
+                return POLARSSL_ERR_X509_VALUE_TO_LENGTH;
+
+            /* is tag end? */
+            if (*sp == '=') {
+                is_tag = -1;
+                *tag_sp = '\0';
+                is_begin = 1;
+                /* set len 0 (reset) */
+                len = 0;
+            } else {
+                /* tag hasn't ' '! */
+                if (*sp != ' ') {
+                    *tag_sp = *sp;
+                    ++tag_sp;
+                }
+            }
+        /* filter value */
+        } else {
+
+            /* set pointer of value begin */
+            if (is_begin == 1) {
+                begin = sp;
+                is_begin = -1;
+            }
+
+            /* is value at end? */
+            if (*sp == ';' or *sp == '\0') {
+                is_tag = 1;
+
+                /* common name */
+                if (tag[0] == 'C' and tag[1] == 'N') {
+                    CN = begin;
+                    CN_len = len;
+
+                /* organization */
+                } else if (tag[0] == 'O' and tag[1] == '\0') {
+                    O = begin;
+                    O_len = len;
+
+                /* country */
+                } else if (tag[0] == 'C' and tag[1] == '\0') {
+                    C = begin;
+                    C_len = len;
+
+                /* organisation unit */
+                } else if (tag[0] == 'O' and tag[1] == 'U') {
+                    OU = begin;
+                    OU_len = len;
+
+                /* state */
+                } else if (tag[0] == 'S' and tag[1] == 'T') {
+                    ST = begin;
+                    ST_len = len;
+
+                /* locality */
+                } else if (tag[0] == 'L' and tag[1] == '\0') {
+                    L = begin;
+                    L_len = len;
+
+                /* email */
+                } else if (tag[0] == 'R' and tag[1] == '\0') {
+                    R = begin;
+                    R_len = len;
+                }
+
+                /* set tag poiner to begin */
+                tag_sp = tag;
+
+                /* is at end? */
+                if (*sp == '\0' or *(sp +1) == '\0')
+                    break;
+            } else {
+                ++len;
+            }
+        }
+
+        /* make saver */
+        if (*sp == '\0')
+          break;
+    } /* end for */
+
+    /* country */
+    if (C != NULL) {
+        oid[2] = X520_COUNTRY;
+        if ((ret = x509write_add_name(node, oid, 3, C, C_len,
+                        ASN1_PRINTABLE_STRING)) != 0)
+            return ret;
+    }
+
+    /* state */
+    if (ST != NULL) {
+        oid[2] = X520_STATE;
+        if ((ret = x509write_add_name(node, oid, 3, ST, ST_len,
+                        ASN1_PRINTABLE_STRING)) != 0)
+            return ret;
+    }
+
+    /* locality */
+    if (L != NULL) {
+        oid[2] = X520_LOCALITY;
+        if ((ret = x509write_add_name(node, oid, 3, L, L_len,
+                        ASN1_PRINTABLE_STRING)) != 0)
+            return ret;
+    }
+
+    /* organization */
+    if (O != NULL) {
+        oid[2] = X520_ORGANIZATION;
+        if ((ret = x509write_add_name(node, oid, 3, O, O_len,
+                        ASN1_PRINTABLE_STRING)) != 0)
+            return ret;
+    }
+
+    /* organisation unit */
+    if (OU != NULL) {
+        oid[2] = X520_ORG_UNIT;
+        if ((ret = x509write_add_name(node, oid, 3, OU, OU_len,
+                        ASN1_PRINTABLE_STRING)) != 0)
+            return ret;
+    }
+
+    /* common name */
+    if (CN != NULL) {
+        oid[2] = X520_COMMON_NAME;
+        if ((ret = x509write_add_name(node, oid, 3, CN, CN_len,
+                        ASN1_PRINTABLE_STRING)) != 0)
+            return ret;
+    }
+
+    /* email */
+    if (R != NULL) {
+        if ((ret = x509write_add_name(node, (unsigned char*)OID_PKCS9_EMAIL,
+        		9, R, R_len, ASN1_IA5_STRING)) != 0)
+            return ret;
+    }
+
+    if ((asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+        return ret;
+
+    return 0;
+}
+
+/*
+ * Copy raw data from orginal ca to node
+ */
+static int x509write_copy_from_raw(x509_node *node, x509_buf *raw)
+{
+    if (x509write_realloc_node(node, raw->len) != 0)
+        return 1;
+
+    memcpy(node->p, raw->p, (size_t)raw->len);
+    if ((node->p += raw->len -1) != node->end)
+        return POLARSSL_ERR_X509_POINT_ERROR;
+
+    return 0;
+}
+
+/*
+ * Add the issuer
+ */
+
+int x509write_add_issuer(x509_raw *crt, unsigned char *issuer)
+{
+    return x509write_parse_names(&crt->issuer, issuer);
+}
+
+/*
+ * Add the subject
+ */
+int x509write_add_subject(x509_raw *crt, unsigned char *subject)
+{
+    return x509write_parse_names(&crt->subject, subject);
+}
+
+/*
+ * Copy issuer line from another cert to issuer
+ */
+int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt)
+{
+    return x509write_copy_from_raw(&crt->issuer, &from_crt->issuer_raw);
+}
+
+/*
+ * Copy subject line from another cert
+ */
+int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt)
+{
+    return x509write_copy_from_raw(&crt->subject, &from_crt->subject_raw);
+}
+
+/*
+ * Copy subject line form antoher cert into issuer
+ */
+int x509write_copy_issuer_form_subject(x509_raw *crt,
+        x509_cert *from_crt)
+{
+    return x509write_copy_from_raw(&crt->issuer, &from_crt->subject_raw);
+}
+
+/*
+ * Copy issuer line from another cert into subject
+ */
+int x509write_copy_subject_from_issuer(x509_raw *crt,
+        x509_cert * from_crt)
+{
+    return x509write_copy_from_raw(&crt->subject, &from_crt->issuer_raw);
+}
+
+/*
+ *  Validity ::= SEQUENCE {
+ *       notBefore      Time,
+ *       notAfter       Time }
+ *
+ *  Time ::= CHOICE {
+ *       utcTime        UTCTime,
+ *       generalTime    GeneralizedTime }
+ */
+/* TODO: No handle GeneralizedTime! */
+int x509write_add_validity(x509_raw *chain, unsigned char *befor,
+        unsigned char *after)
+{
+    int ret;
+
+    x509_node *node = &chain->validity;
+
+    /* notBefore */
+    if ((ret = asn1_add_date_utc(befor, node)) != 0)
+        return ret;
+
+    /* notAfter */
+    if ((ret = asn1_add_date_utc(after, node)) != 0)
+        return ret;
+
+    if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0)
+        return ret;
+
+    return 0;
+}
+
+/*
+ * make hash from tbs and sign that with private key
+ */
+static int x509write_make_sign(x509_raw *chain, rsa_context *privkey)
+{
+    int ret;
+    unsigned char hash[20], *sign;
+    size_t sign_len = (size_t) mpi_size(&privkey->N);
+
+    /* make hash */
+    sha1(chain->tbs.data, chain->tbs.len, hash);
+
+    /* create sign */
+    sign = (unsigned char *) malloc(sign_len);
+    if (sign == NULL)
+        return 1;
+
+    if ((ret = rsa_pkcs1_sign(privkey, RSA_PRIVATE, RSA_SHA1, 20, hash,
+                    sign)) != 0)
+        return ret;
+
+    if ((ret = asn1_add_obj(sign, sign_len, ASN1_BIT_STRING,
+                    &chain->sign)) != 0)
+        return ret;
+
+    /*
+     *  AlgorithmIdentifier  ::=  SEQUENCE  {
+     *       algorithm               OBJECT IDENTIFIER,
+     *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     */
+    return asn1_add_oid(&chain->signalg, (unsigned char*)OID_PKCS1_RSA_SHA, 9,
+                  ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL,
+                  (unsigned char*)"", 0);
+}
+
+/*
+ * Create a random serial
+ */
+static int get_random_serial(void)
+{
+    int random = 0;
+    FILE *fd;
+
+    fd = fopen("/dev/urandom", "r");
+
+    if (fd) {
+	if (fread(&random, 1, sizeof(random), fd) != sizeof(random))
+            random = 0;
+
+        fclose(fd);
+    }
+
+    return random;
+}
+
+/*
+ * Create a self signed certificate
+ */
+int x509write_create_sign(x509_raw *chain, rsa_context *privkey)
+{
+    int ret, serial;
+
+    /*
+     *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+     */
+    if ((ret = asn1_add_int(2, &chain->version)) != 0)
+        return ret;
+
+    if ((ret = asn1_append_tag(&chain->version, ASN1_CONTEXT_SPECIFIC |
+                    ASN1_CONSTRUCTED)) != 0)
+        return ret;
+
+
+    /*
+     *  CertificateSerialNumber  ::=  INTEGER
+     */
+    serial = get_random_serial();
+
+    if (serial == 0)
+        return 1;
+
+    if ((ret = asn1_add_int(serial, &chain->serial)) != 0)
+        return ret;
+
+    /*
+     *  AlgorithmIdentifier  ::=  SEQUENCE  {
+     *       algorithm               OBJECT IDENTIFIER,
+     *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     */
+    if ((ret = asn1_add_oid(&chain->tbs_signalg,
+				(unsigned char*)OID_PKCS1_RSA_SHA, 9, ASN1_CONSTRUCTED |
+				ASN1_SEQUENCE, ASN1_NULL, (unsigned char*)"", 0)) != 0)
+        return ret;
+
+   /*
+    *  Create the tbs
+    */
+    if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED |
+                    ASN1_SEQUENCE, 7, &chain->version, &chain->serial,
+                    &chain->tbs_signalg, &chain->issuer, &chain->validity,
+                    &chain->subject, &chain->subpubkey)) != 0)
+        return ret;
+
+    /* make signing */
+    if ((ret = x509write_make_sign(chain, privkey)) != 0)
+        return ret;
+
+    /* finishing */
+    if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED |
+                    ASN1_SEQUENCE, 3, &chain->tbs, &chain->signalg,
+                    &chain->sign)) != 0)
+        return ret;
+
+    return 0;
+}
+
+int x509write_create_selfsign(x509_raw *chain, rsa_context *privkey)
+{
+    /*
+     * On self signed certificate are subject and issuer the same
+     */
+    x509write_free_node(&chain->issuer);
+    chain->issuer = chain->subject;
+    return x509write_create_sign(chain, privkey);
+}
+
+/*
+ * CertificationRequestInfo ::= SEQUENCE                    {
+ *    version                       Version,
+ *    subject                       Name,
+ *    subjectPublicKeyInfo          SubjectPublicKeyInfo,
+ *    attributes                    [0] IMPLICIT Attributes }
+ *
+ * CertificationRequest ::=   SEQUENCE                      {
+ *    certificationRequestInfo  CertificationRequestInfo,
+ *    signatureAlgorithm        SignatureAlgorithmIdentifier,
+ *    signature                 Signature                   }
+ *
+ * It use chain.serail for attributes!
+ *
+ */
+int x509write_create_csr(x509_raw *chain, rsa_context *privkey)
+{
+    int ret;
+
+    /* version ::= INTEGER */
+    if ((ret = asn1_add_int(0, &chain->version)) != 0)
+        return ret;
+
+    /* write attributes */
+    if ((ret = asn1_add_obj((unsigned char*)"", 0, ASN1_CONTEXT_SPECIFIC |
+                    ASN1_CONSTRUCTED, &chain->serial)) != 0)
+        return ret;
+
+    /* create CertificationRequestInfo */
+    if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED |
+                    ASN1_SEQUENCE, 4, &chain->version, &chain->subject,
+                    &chain->subpubkey, &chain->serial)) != 0)
+        return ret;
+
+    /* make signing */
+    if ((ret = x509write_make_sign(chain, privkey)) != 0)
+        return ret;
+
+    /* finish */
+    if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED | ASN1_SEQUENCE,
+                    3, &chain->tbs, &chain->signalg, &chain->sign)) != 0)
+        return ret;
+
+    return ret;
+}
+
+/*
+ * Free memory
+ */
+void x509write_free_raw(x509_raw *chain)
+{
+    x509write_free_node(&chain->raw);
+    x509write_free_node(&chain->tbs);
+    x509write_free_node(&chain->version);
+    x509write_free_node(&chain->serial);
+    x509write_free_node(&chain->tbs_signalg);
+    x509write_free_node(&chain->issuer);
+    x509write_free_node(&chain->validity);
+    if (chain->subject.data != chain->issuer.data)
+        x509write_free_node(&chain->subject);
+    x509write_free_node(&chain->subpubkey);
+    x509write_free_node(&chain->signalg);
+    x509write_free_node(&chain->sign);
+}
+
+void x509write_init_raw(x509_raw *chain)
+{
+    memset((void *) chain, 0, sizeof(x509_raw));
+}
+
diff --git a/package/utils/px5g-standalone/src/polarssl/base64.h b/package/utils/px5g-standalone/src/polarssl/base64.h
new file mode 100644
index 0000000000..c48267b1b5
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/base64.h
@@ -0,0 +1,93 @@
+/**
+ * \file base64.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+#ifndef POLARSSL_BASE64_H
+#define POLARSSL_BASE64_H
+
+#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL               -0x0010
+#define POLARSSL_ERR_BASE64_INVALID_CHARACTER              -0x0012
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Encode a buffer into base64 format
+ *
+ * \param dst      destination buffer
+ * \param dlen     size of the buffer
+ * \param src      source buffer
+ * \param slen     amount of data to be encoded
+ *
+ * \return         0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL.
+ *                 *dlen is always updated to reflect the amount
+ *                 of data that has (or would have) been written.
+ *
+ * \note           Call this function with *dlen = 0 to obtain the
+ *                 required buffer size in *dlen
+ */
+int base64_encode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen );
+
+/**
+ * \brief          Decode a base64-formatted buffer
+ *
+ * \param dst      destination buffer
+ * \param dlen     size of the buffer
+ * \param src      source buffer
+ * \param slen     amount of data to be decoded
+ *
+ * \return         0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
+ *                 POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not
+ *                 correct. *dlen is always updated to reflect the amount
+ *                 of data that has (or would have) been written.
+ *
+ * \note           Call this function with *dlen = 0 to obtain the
+ *                 required buffer size in *dlen
+ */
+int base64_decode( unsigned char *dst, int *dlen,
+                   unsigned char *src, int  slen );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int base64_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* base64.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/bignum.h b/package/utils/px5g-standalone/src/polarssl/bignum.h
new file mode 100644
index 0000000000..c667303329
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/bignum.h
@@ -0,0 +1,437 @@
+/**
+ * \file bignum.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+#ifndef POLARSSL_BIGNUM_H
+#define POLARSSL_BIGNUM_H
+
+#include <stdio.h>
+
+#define POLARSSL_ERR_MPI_FILE_IO_ERROR                     -0x0002
+#define POLARSSL_ERR_MPI_BAD_INPUT_DATA                    -0x0004
+#define POLARSSL_ERR_MPI_INVALID_CHARACTER                 -0x0006
+#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL                  -0x0008
+#define POLARSSL_ERR_MPI_NEGATIVE_VALUE                    -0x000A
+#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO                  -0x000C
+#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE                    -0x000E
+
+#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
+
+/*
+ * Define the base integer type, architecture-wise
+ */
+#if defined(POLARSSL_HAVE_INT8)
+typedef unsigned char  t_int;
+typedef unsigned short t_dbl;
+#else
+#if defined(POLARSSL_HAVE_INT16)
+typedef unsigned short t_int;
+typedef unsigned long  t_dbl;
+#else
+  typedef unsigned long t_int;
+  #if defined(_MSC_VER) && defined(_M_IX86)
+  typedef unsigned __int64 t_dbl;
+  #else
+    #if defined(__amd64__) || defined(__x86_64__)    || \
+        defined(__ppc64__) || defined(__powerpc64__) || \
+        defined(__ia64__)  || defined(__alpha__)
+    typedef unsigned int t_dbl __attribute__((mode(TI)));
+    #else
+    typedef unsigned long long t_dbl;
+    #endif
+  #endif
+#endif
+#endif
+
+/**
+ * \brief          MPI structure
+ */
+typedef struct
+{
+    int s;              /*!<  integer sign      */
+    int n;              /*!<  total # of limbs  */
+    t_int *p;           /*!<  pointer to limbs  */
+}
+mpi;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Initialize one or more mpi
+ */
+void mpi_init( mpi *X, ... );
+
+/**
+ * \brief          Unallocate one or more mpi
+ */
+void mpi_free( mpi *X, ... );
+
+/**
+ * \brief          Enlarge to the specified number of limbs
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_grow( mpi *X, int nblimbs );
+
+/**
+ * \brief          Copy the contents of Y into X
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_copy( mpi *X, mpi *Y );
+
+/**
+ * \brief          Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y );
+
+/**
+ * \brief          Set value from integer
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_lset( mpi *X, int z );
+
+/**
+ * \brief          Return the number of least significant bits
+ */
+int mpi_lsb( mpi *X );
+
+/**
+ * \brief          Return the number of most significant bits
+ */
+int mpi_msb( mpi *X );
+
+/**
+ * \brief          Return the total size in bytes
+ */
+int mpi_size( mpi *X );
+
+/**
+ * \brief          Import from an ASCII string
+ *
+ * \param X        destination mpi
+ * \param radix    input numeric base
+ * \param s        null-terminated string buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_string( mpi *X, int radix, char *s );
+
+/**
+ * \brief          Export into an ASCII string
+ *
+ * \param X        source mpi
+ * \param radix    output numeric base
+ * \param s        string buffer
+ * \param slen     string buffer size
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_MPI_XXX error code
+ *
+ * \note           Call this function with *slen = 0 to obtain the
+ *                 minimum required buffer size in *slen.
+ */
+int mpi_write_string( mpi *X, int radix, char *s, int *slen );
+
+/**
+ * \brief          Read X from an opened file
+ *
+ * \param X        destination mpi
+ * \param radix    input numeric base
+ * \param fin      input file handle
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_MPI_XXX error code
+ */
+int mpi_read_file( mpi *X, int radix, FILE *fin );
+
+/**
+ * \brief          Write X into an opened file, or stdout
+ *
+ * \param p        prefix, can be NULL
+ * \param X        source mpi
+ * \param radix    output numeric base
+ * \param fout     output file handle
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_MPI_XXX error code
+ *
+ * \note           Set fout == NULL to print X on the console.
+ */
+int mpi_write_file( char *p, mpi *X, int radix, FILE *fout );
+
+/**
+ * \brief          Import X from unsigned binary data, big endian
+ *
+ * \param X        destination mpi
+ * \param buf      input buffer
+ * \param buflen   input buffer size
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_read_binary( mpi *X, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Export X into unsigned binary data, big endian
+ *
+ * \param X        source mpi
+ * \param buf      output buffer
+ * \param buflen   output buffer size
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
+ *
+ * \note           Call this function with *buflen = 0 to obtain the
+ *                 minimum required buffer size in *buflen.
+ */
+int mpi_write_binary( mpi *X, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Left-shift: X <<= count
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_shift_l( mpi *X, int count );
+
+/**
+ * \brief          Right-shift: X >>= count
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_shift_r( mpi *X, int count );
+
+/**
+ * \brief          Compare unsigned values
+ *
+ * \return         1 if |X| is greater than |Y|,
+ *                -1 if |X| is lesser  than |Y| or
+ *                 0 if |X| is equal to |Y|
+ */
+int mpi_cmp_abs( mpi *X, mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \return         1 if X is greater than Y,
+ *                -1 if X is lesser  than Y or
+ *                 0 if X is equal to Y
+ */
+int mpi_cmp_mpi( mpi *X, mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \return         1 if X is greater than z,
+ *                -1 if X is lesser  than z or
+ *                 0 if X is equal to z
+ */
+int mpi_cmp_int( mpi *X, int z );
+
+/**
+ * \brief          Unsigned addition: X = |A| + |B|
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_abs( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Unsigned substraction: X = |A| - |B|
+ *
+ * \return         0 if successful,
+ *                 POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
+ */
+int mpi_sub_abs( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed substraction: X = A - B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_sub_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_int( mpi *X, mpi *A, int b );
+
+/**
+ * \brief          Signed substraction: X = A - b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_sub_int( mpi *X, mpi *A, int b );
+
+/**
+ * \brief          Baseline multiplication: X = A * B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_mul_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Baseline multiplication: X = A * b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_mul_int( mpi *X, mpi *A, t_int b );
+
+/**
+ * \brief          Division by mpi: A = Q * B + R
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B );
+
+/**
+ * \brief          Division by int: A = Q * b + R
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b );
+
+/**
+ * \brief          Modulo: R = A mod B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ */
+int mpi_mod_mpi( mpi *R, mpi *A, mpi *B );
+
+/**
+ * \brief          Modulo: r = A mod b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ */
+int mpi_mod_int( t_int *r, mpi *A, int b );
+
+/**
+ * \brief          Sliding-window exponentiation: X = A^E mod N
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even
+ *
+ * \note           _RR is used to avoid re-computing R*R mod N across
+ *                 multiple calls, which speeds up things a bit. It can
+ *                 be set to NULL if the extra performance is unneeded.
+ */
+int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR );
+
+/**
+ * \brief          Greatest common divisor: G = gcd(A, B)
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_gcd( mpi *G, mpi *A, mpi *B );
+
+/**
+ * \brief          Modular inverse: X = A^-1 mod N
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
+ *                 POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
+ */
+int mpi_inv_mod( mpi *X, mpi *A, mpi *N );
+
+/**
+ * \brief          Miller-Rabin primality test
+ *
+ * \return         0 if successful (probably prime),
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
+ */
+int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
+
+/**
+ * \brief          Prime number generation
+ *
+ * \param X        destination mpi
+ * \param nbits    required size of X in bits
+ * \param dh_flag  if 1, then (X-1)/2 will be prime too
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \return         0 if successful (probably prime),
+ *                 1 if memory allocation failed,
+ *                 POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
+ */
+int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
+                   int (*f_rng)(void *), void *p_rng );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mpi_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* bignum.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/bn_mul.h b/package/utils/px5g-standalone/src/polarssl/bn_mul.h
new file mode 100644
index 0000000000..f6d34da58a
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/bn_mul.h
@@ -0,0 +1,731 @@
+/**
+ * \file bn_mul.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+/*
+ *      Multiply source vector [s] with b, add result
+ *       to destination vector [d] and set carry c.
+ *
+ *      Currently supports:
+ *
+ *         . IA-32 (386+)         . AMD64 / EM64T
+ *         . IA-32 (SSE2)         . Motorola 68000
+ *         . PowerPC, 32-bit      . MicroBlaze
+ *         . PowerPC, 64-bit      . TriCore
+ *         . SPARC v8             . ARM v3+
+ *         . Alpha                . MIPS32
+ *         . C, longlong          . C, generic
+ */
+#ifndef POLARSSL_BN_MUL_H
+#define POLARSSL_BN_MUL_H
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_HAVE_ASM)
+
+#if defined(__GNUC__)
+#if defined(__i386__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %%ebx, %0      " : "=m" (t));  \
+    asm( "movl   %0, %%esi      " :: "m" (s));  \
+    asm( "movl   %0, %%edi      " :: "m" (d));  \
+    asm( "movl   %0, %%ecx      " :: "m" (c));  \
+    asm( "movl   %0, %%ebx      " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lodsl                 " );            \
+    asm( "mull   %ebx           " );            \
+    asm( "addl   %ecx,   %eax   " );            \
+    asm( "adcl   $0,     %edx   " );            \
+    asm( "addl   (%edi), %eax   " );            \
+    asm( "adcl   $0,     %edx   " );            \
+    asm( "movl   %edx,   %ecx   " );            \
+    asm( "stosl                 " );
+
+#if defined(POLARSSL_HAVE_SSE2)
+
+#define MULADDC_HUIT                            \
+    asm( "movd     %ecx,     %mm1     " );      \
+    asm( "movd     %ebx,     %mm0     " );      \
+    asm( "movd     (%edi),   %mm3     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     (%esi),   %mm2     " );      \
+    asm( "pmuludq  %mm0,     %mm2     " );      \
+    asm( "movd     4(%esi),  %mm4     " );      \
+    asm( "pmuludq  %mm0,     %mm4     " );      \
+    asm( "movd     8(%esi),  %mm6     " );      \
+    asm( "pmuludq  %mm0,     %mm6     " );      \
+    asm( "movd     12(%esi), %mm7     " );      \
+    asm( "pmuludq  %mm0,     %mm7     " );      \
+    asm( "paddq    %mm2,     %mm1     " );      \
+    asm( "movd     4(%edi),  %mm3     " );      \
+    asm( "paddq    %mm4,     %mm3     " );      \
+    asm( "movd     8(%edi),  %mm5     " );      \
+    asm( "paddq    %mm6,     %mm5     " );      \
+    asm( "movd     12(%edi), %mm4     " );      \
+    asm( "paddq    %mm4,     %mm7     " );      \
+    asm( "movd     %mm1,     (%edi)   " );      \
+    asm( "movd     16(%esi), %mm2     " );      \
+    asm( "pmuludq  %mm0,     %mm2     " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     20(%esi), %mm4     " );      \
+    asm( "pmuludq  %mm0,     %mm4     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     24(%esi), %mm6     " );      \
+    asm( "pmuludq  %mm0,     %mm6     " );      \
+    asm( "movd     %mm1,     4(%edi)  " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     28(%esi), %mm3     " );      \
+    asm( "pmuludq  %mm0,     %mm3     " );      \
+    asm( "paddq    %mm5,     %mm1     " );      \
+    asm( "movd     16(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm2     " );      \
+    asm( "movd     %mm1,     8(%edi)  " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm7,     %mm1     " );      \
+    asm( "movd     20(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm4     " );      \
+    asm( "movd     %mm1,     12(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm2,     %mm1     " );      \
+    asm( "movd     24(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm6     " );      \
+    asm( "movd     %mm1,     16(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm4,     %mm1     " );      \
+    asm( "movd     28(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm3     " );      \
+    asm( "movd     %mm1,     20(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm6,     %mm1     " );      \
+    asm( "movd     %mm1,     24(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     %mm1,     28(%edi) " );      \
+    asm( "addl     $32,      %edi     " );      \
+    asm( "addl     $32,      %esi     " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     %mm1,     %ecx     " );
+
+#define MULADDC_STOP                            \
+    asm( "emms                        " );      \
+    asm( "movl   %0, %%ebx      " :: "m" (t));  \
+    asm( "movl   %%ecx, %0      " : "=m" (c));  \
+    asm( "movl   %%edi, %0      " : "=m" (d));  \
+    asm( "movl   %%esi, %0      " : "=m" (s) :: \
+    "eax", "ecx", "edx", "esi", "edi" );
+
+#else
+
+#define MULADDC_STOP                            \
+    asm( "movl   %0, %%ebx      " :: "m" (t));  \
+    asm( "movl   %%ecx, %0      " : "=m" (c));  \
+    asm( "movl   %%edi, %0      " : "=m" (d));  \
+    asm( "movl   %%esi, %0      " : "=m" (s) :: \
+    "eax", "ecx", "edx", "esi", "edi" );
+
+#endif /* SSE2 */
+#endif /* i386 */
+
+#if defined(__amd64__) || defined (__x86_64__)
+
+#define MULADDC_INIT                            \
+    asm( "movq   %0, %%rsi      " :: "m" (s));  \
+    asm( "movq   %0, %%rdi      " :: "m" (d));  \
+    asm( "movq   %0, %%rcx      " :: "m" (c));  \
+    asm( "movq   %0, %%rbx      " :: "m" (b));  \
+    asm( "xorq   %r8, %r8       " );
+
+#define MULADDC_CORE                            \
+    asm( "movq  (%rsi),%rax     " );            \
+    asm( "mulq   %rbx           " );            \
+    asm( "addq   $8,   %rsi     " );            \
+    asm( "addq   %rcx, %rax     " );            \
+    asm( "movq   %r8,  %rcx     " );            \
+    asm( "adcq   $0,   %rdx     " );            \
+    asm( "nop                   " );            \
+    asm( "addq   %rax, (%rdi)   " );            \
+    asm( "adcq   %rdx, %rcx     " );            \
+    asm( "addq   $8,   %rdi     " );
+
+#define MULADDC_STOP                            \
+    asm( "movq   %%rcx, %0      " : "=m" (c));  \
+    asm( "movq   %%rdi, %0      " : "=m" (d));  \
+    asm( "movq   %%rsi, %0      " : "=m" (s) :: \
+    "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
+
+#endif /* AMD64 */
+
+#if defined(__mc68020__) || defined(__mcpu32__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %0, %%a2       " :: "m" (s));  \
+    asm( "movl   %0, %%a3       " :: "m" (d));  \
+    asm( "movl   %0, %%d3       " :: "m" (c));  \
+    asm( "movl   %0, %%d2       " :: "m" (b));  \
+    asm( "moveq  #0, %d0        " );
+
+#define MULADDC_CORE                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addl   %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "moveq  #0,  %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d4, %d3       " );
+
+#define MULADDC_STOP                            \
+    asm( "movl   %%d3, %0       " : "=m" (c));  \
+    asm( "movl   %%a3, %0       " : "=m" (d));  \
+    asm( "movl   %%a2, %0       " : "=m" (s) :: \
+    "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
+
+#define MULADDC_HUIT                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d0, %d3       " );
+
+#endif /* MC68000 */
+
+#if defined(__powerpc__)   || defined(__ppc__)
+#if defined(__powerpc64__) || defined(__ppc64__)
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     r3, %0         " :: "m" (s));  \
+    asm( "ld     r4, %0         " :: "m" (d));  \
+    asm( "ld     r5, %0         " :: "m" (c));  \
+    asm( "ld     r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -8     " );            \
+    asm( "addi   r4, r4, -8     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    r7, 8(r3)      " );            \
+    asm( "mulld  r8, r7, r6     " );            \
+    asm( "mulhdu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "ld     r7, 8(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stdu   r8, 8(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 8      " );            \
+    asm( "addi   r3, r3, 8      " );            \
+    asm( "std    r5, %0         " : "=m" (c));  \
+    asm( "std    r4, %0         " : "=m" (d));  \
+    asm( "std    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "ld     %%r3, %0       " :: "m" (s));  \
+    asm( "ld     %%r4, %0       " :: "m" (d));  \
+    asm( "ld     %%r5, %0       " :: "m" (c));  \
+    asm( "ld     %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -8   " );            \
+    asm( "addi   %r4, %r4, -8   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    %r7, 8(%r3)    " );            \
+    asm( "mulld  %r8, %r7, %r6  " );            \
+    asm( "mulhdu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "ld     %r7, 8(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stdu   %r8, 8(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 8    " );            \
+    asm( "addi   %r3, %r3, 8    " );            \
+    asm( "std    %%r5, %0       " : "=m" (c));  \
+    asm( "std    %%r4, %0       " : "=m" (d));  \
+    asm( "std    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#else /* PPC32 */
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT                            \
+    asm( "lwz    r3, %0         " :: "m" (s));  \
+    asm( "lwz    r4, %0         " :: "m" (d));  \
+    asm( "lwz    r5, %0         " :: "m" (c));  \
+    asm( "lwz    r6, %0         " :: "m" (b));  \
+    asm( "addi   r3, r3, -4     " );            \
+    asm( "addi   r4, r4, -4     " );            \
+    asm( "addic  r5, r5,  0     " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   r7, 4(r3)      " );            \
+    asm( "mullw  r8, r7, r6     " );            \
+    asm( "mulhwu r9, r7, r6     " );            \
+    asm( "adde   r8, r8, r5     " );            \
+    asm( "lwz    r7, 4(r4)      " );            \
+    asm( "addze  r5, r9         " );            \
+    asm( "addc   r8, r8, r7     " );            \
+    asm( "stwu   r8, 4(r4)      " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  r5, r5         " );            \
+    asm( "addi   r4, r4, 4      " );            \
+    asm( "addi   r3, r3, 4      " );            \
+    asm( "stw    r5, %0         " : "=m" (c));  \
+    asm( "stw    r4, %0         " : "=m" (d));  \
+    asm( "stw    r3, %0         " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "lwz    %%r3, %0       " :: "m" (s));  \
+    asm( "lwz    %%r4, %0       " :: "m" (d));  \
+    asm( "lwz    %%r5, %0       " :: "m" (c));  \
+    asm( "lwz    %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -4   " );            \
+    asm( "addi   %r4, %r4, -4   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   %r7, 4(%r3)    " );            \
+    asm( "mullw  %r8, %r7, %r6  " );            \
+    asm( "mulhwu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "lwz    %r7, 4(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stwu   %r8, 4(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 4    " );            \
+    asm( "addi   %r3, %r3, 4    " );            \
+    asm( "stw    %%r5, %0       " : "=m" (c));  \
+    asm( "stw    %%r4, %0       " : "=m" (d));  \
+    asm( "stw    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif
+
+#endif /* PPC32 */
+#endif /* PPC64 */
+
+#if defined(__sparc__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     %0, %%o0       " :: "m" (s));  \
+    asm( "ld     %0, %%o1       " :: "m" (d));  \
+    asm( "ld     %0, %%o2       " :: "m" (c));  \
+    asm( "ld     %0, %%o3       " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ld    [%o0], %o4      " );            \
+    asm( "inc      4,  %o0      " );            \
+    asm( "ld    [%o1], %o5      " );            \
+    asm( "umul   %o3,  %o4, %o4 " );            \
+    asm( "addcc  %o4,  %o2, %o4 " );            \
+    asm( "rd      %y,  %g1      " );            \
+    asm( "addx   %g1,    0, %g1 " );            \
+    asm( "addcc  %o4,  %o5, %o4 " );            \
+    asm( "st     %o4, [%o1]     " );            \
+    asm( "addx   %g1,    0, %o2 " );            \
+    asm( "inc      4,  %o1      " );
+
+#define MULADDC_STOP                            \
+    asm( "st     %%o2, %0       " : "=m" (c));  \
+    asm( "st     %%o1, %0       " : "=m" (d));  \
+    asm( "st     %%o0, %0       " : "=m" (s) :: \
+    "g1", "o0", "o1", "o2", "o3", "o4", "o5" );
+
+#endif /* SPARCv8 */
+
+#if defined(__microblaze__) || defined(microblaze)
+
+#define MULADDC_INIT                            \
+    asm( "lwi   r3,   %0        " :: "m" (s));  \
+    asm( "lwi   r4,   %0        " :: "m" (d));  \
+    asm( "lwi   r5,   %0        " :: "m" (c));  \
+    asm( "lwi   r6,   %0        " :: "m" (b));  \
+    asm( "andi  r7,   r6, 0xffff" );            \
+    asm( "bsrli r6,   r6, 16    " );
+
+#define MULADDC_CORE                            \
+    asm( "lhui  r8,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "lhui  r9,   r3,   0   " );            \
+    asm( "addi  r3,   r3,   2   " );            \
+    asm( "mul   r10,  r9,  r6   " );            \
+    asm( "mul   r11,  r8,  r7   " );            \
+    asm( "mul   r12,  r9,  r7   " );            \
+    asm( "mul   r13,  r8,  r6   " );            \
+    asm( "bsrli  r8, r10,  16   " );            \
+    asm( "bsrli  r9, r11,  16   " );            \
+    asm( "add   r13, r13,  r8   " );            \
+    asm( "add   r13, r13,  r9   " );            \
+    asm( "bslli r10, r10,  16   " );            \
+    asm( "bslli r11, r11,  16   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12, r11   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "lwi   r10,  r4,   0   " );            \
+    asm( "add   r12, r12, r10   " );            \
+    asm( "addc  r13, r13,  r0   " );            \
+    asm( "add   r12, r12,  r5   " );            \
+    asm( "addc   r5, r13,  r0   " );            \
+    asm( "swi   r12,  r4,   0   " );            \
+    asm( "addi   r4,  r4,   4   " );
+
+#define MULADDC_STOP                            \
+    asm( "swi   r5,   %0        " : "=m" (c));  \
+    asm( "swi   r4,   %0        " : "=m" (d));  \
+    asm( "swi   r3,   %0        " : "=m" (s) :: \
+     "r3", "r4" , "r5" , "r6" , "r7" , "r8" ,   \
+     "r9", "r10", "r11", "r12", "r13" );
+
+#endif /* MicroBlaze */
+
+#if defined(__tricore__)
+
+#define MULADDC_INIT                            \
+    asm( "ld.a   %%a2, %0       " :: "m" (s));  \
+    asm( "ld.a   %%a3, %0       " :: "m" (d));  \
+    asm( "ld.w   %%d4, %0       " :: "m" (c));  \
+    asm( "ld.w   %%d1, %0       " :: "m" (b));  \
+    asm( "xor    %d5, %d5       " );
+
+#define MULADDC_CORE                            \
+    asm( "ld.w   %d0,   [%a2+]      " );        \
+    asm( "madd.u %e2, %e4, %d0, %d1 " );        \
+    asm( "ld.w   %d0,   [%a3]       " );        \
+    asm( "addx   %d2,    %d2,  %d0  " );        \
+    asm( "addc   %d3,    %d3,    0  " );        \
+    asm( "mov    %d4,    %d3        " );        \
+    asm( "st.w  [%a3+],  %d2        " );
+
+#define MULADDC_STOP                            \
+    asm( "st.w   %0, %%d4       " : "=m" (c));  \
+    asm( "st.a   %0, %%a3       " : "=m" (d));  \
+    asm( "st.a   %0, %%a2       " : "=m" (s) :: \
+    "d0", "d1", "e2", "d4", "a2", "a3" );
+
+#endif /* TriCore */
+
+#if defined(__arm__)
+
+#define MULADDC_INIT                            \
+    asm( "ldr    r0, %0         " :: "m" (s));  \
+    asm( "ldr    r1, %0         " :: "m" (d));  \
+    asm( "ldr    r2, %0         " :: "m" (c));  \
+    asm( "ldr    r3, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldr    r4, [r0], #4   " );            \
+    asm( "mov    r5, #0         " );            \
+    asm( "ldr    r6, [r1]       " );            \
+    asm( "umlal  r2, r5, r3, r4 " );            \
+    asm( "adds   r7, r6, r2     " );            \
+    asm( "adc    r2, r5, #0     " );            \
+    asm( "str    r7, [r1], #4   " );
+
+#define MULADDC_STOP                            \
+    asm( "str    r2, %0         " : "=m" (c));  \
+    asm( "str    r1, %0         " : "=m" (d));  \
+    asm( "str    r0, %0         " : "=m" (s) :: \
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
+
+#endif /* ARMv3 */
+
+#if defined(__alpha__)
+
+#define MULADDC_INIT                            \
+    asm( "ldq    $1, %0         " :: "m" (s));  \
+    asm( "ldq    $2, %0         " :: "m" (d));  \
+    asm( "ldq    $3, %0         " :: "m" (c));  \
+    asm( "ldq    $4, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldq    $6,  0($1)     " );            \
+    asm( "addq   $1,  8, $1     " );            \
+    asm( "mulq   $6, $4, $7     " );            \
+    asm( "umulh  $6, $4, $6     " );            \
+    asm( "addq   $7, $3, $7     " );            \
+    asm( "cmpult $7, $3, $3     " );            \
+    asm( "ldq    $5,  0($2)     " );            \
+    asm( "addq   $7, $5, $7     " );            \
+    asm( "cmpult $7, $5, $5     " );            \
+    asm( "stq    $7,  0($2)     " );            \
+    asm( "addq   $2,  8, $2     " );            \
+    asm( "addq   $6, $3, $3     " );            \
+    asm( "addq   $5, $3, $3     " );
+
+#define MULADDC_STOP                            \
+    asm( "stq    $3, %0         " : "=m" (c));  \
+    asm( "stq    $2, %0         " : "=m" (d));  \
+    asm( "stq    $1, %0         " : "=m" (s) :: \
+    "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
+
+#endif /* Alpha */
+
+#if defined(__mips__)
+
+#define MULADDC_INIT                            \
+    asm( "lw     $10, %0        " :: "m" (s));  \
+    asm( "lw     $11, %0        " :: "m" (d));  \
+    asm( "lw     $12, %0        " :: "m" (c));  \
+    asm( "lw     $13, %0        " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lw     $14, 0($10)    " );            \
+    asm( "multu  $13, $14       " );            \
+    asm( "addi   $10, $10, 4    " );            \
+    asm( "mflo   $14            " );            \
+    asm( "mfhi   $9             " );            \
+    asm( "addu   $14, $12, $14  " );            \
+    asm( "lw     $15, 0($11)    " );            \
+    asm( "sltu   $12, $14, $12  " );            \
+    asm( "addu   $15, $14, $15  " );            \
+    asm( "sltu   $14, $15, $14  " );            \
+    asm( "addu   $12, $12, $9   " );            \
+    asm( "sw     $15, 0($11)    " );            \
+    asm( "addu   $12, $12, $14  " );            \
+    asm( "addi   $11, $11, 4    " );
+
+#define MULADDC_STOP                            \
+    asm( "sw     $12, %0        " : "=m" (c));  \
+    asm( "sw     $11, %0        " : "=m" (d));  \
+    asm( "sw     $10, %0        " : "=m" (s) :: \
+    "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
+
+#endif /* MIPS */
+#endif /* GNUC */
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+#define MULADDC_INIT                            \
+    __asm   mov     esi, s                      \
+    __asm   mov     edi, d                      \
+    __asm   mov     ecx, c                      \
+    __asm   mov     ebx, b
+
+#define MULADDC_CORE                            \
+    __asm   lodsd                               \
+    __asm   mul     ebx                         \
+    __asm   add     eax, ecx                    \
+    __asm   adc     edx, 0                      \
+    __asm   add     eax, [edi]                  \
+    __asm   adc     edx, 0                      \
+    __asm   mov     ecx, edx                    \
+    __asm   stosd
+
+#if defined(POLARSSL_HAVE_SSE2)
+
+#define EMIT __asm _emit
+
+#define MULADDC_HUIT                            \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
+    EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
+    EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
+
+#define MULADDC_STOP                            \
+    EMIT 0x0F  EMIT 0x77                        \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#else
+
+#define MULADDC_STOP                            \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#endif /* SSE2 */
+#endif /* MSVC */
+
+#endif /* POLARSSL_HAVE_ASM */
+
+#if !defined(MULADDC_CORE)
+#if defined(POLARSSL_HAVE_LONGLONG)
+
+#define MULADDC_INIT                    \
+{                                       \
+    t_dbl r;                            \
+    t_int r0, r1;
+
+#define MULADDC_CORE                    \
+    r   = *(s++) * (t_dbl) b;           \
+    r0  = r;                            \
+    r1  = r >> biL;                     \
+    r0 += c;  r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#else
+#define MULADDC_INIT                    \
+{                                       \
+    t_int s0, s1, b0, b1;               \
+    t_int r0, r1, rx, ry;               \
+    b0 = ( b << biH ) >> biH;           \
+    b1 = ( b >> biH );
+
+#define MULADDC_CORE                    \
+    s0 = ( *s << biH ) >> biH;          \
+    s1 = ( *s >> biH ); s++;            \
+    rx = s0 * b1; r0 = s0 * b0;         \
+    ry = s1 * b0; r1 = s1 * b1;         \
+    r1 += ( rx >> biH );                \
+    r1 += ( ry >> biH );                \
+    rx <<= biH; ry <<= biH;             \
+    r0 += rx; r1 += (r0 < rx);          \
+    r0 += ry; r1 += (r0 < ry);          \
+    r0 +=  c; r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#endif /* C (generic)  */
+#endif /* C (longlong) */
+
+#endif /* bn_mul.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/config.h b/package/utils/px5g-standalone/src/polarssl/config.h
new file mode 100644
index 0000000000..79cd3dba9d
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/config.h
@@ -0,0 +1,329 @@
+/**
+ * \file config.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ *
+ * This set of compile-time options may be used to enable
+ * or disable features selectively, and reduce the global
+ * memory footprint.
+ */
+#ifndef POLARSSL_CONFIG_H
+#define POLARSSL_CONFIG_H
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+/*
+ * Uncomment if native integers are 8-bit wide.
+ *
+#define POLARSSL_HAVE_INT8
+ */
+
+/*
+ * Uncomment if native integers are 16-bit wide.
+ *
+#define POLARSSL_HAVE_INT16
+ */
+
+/*
+ * Uncomment if the compiler supports long long.
+#define POLARSSL_HAVE_LONGLONG
+ */
+
+
+/*
+ * Uncomment to enable the use of assembly code.
+ */
+/* #define POLARSSL_HAVE_ASM */
+
+/*
+ * Uncomment if the CPU supports SSE2 (IA-32 specific).
+ *
+#define POLARSSL_HAVE_SSE2
+ */
+
+/*
+ * Enable all SSL/TLS debugging messages.
+ */
+#define POLARSSL_DEBUG_MSG
+
+/*
+ * Enable the checkup functions (*_self_test).
+ */
+#define POLARSSL_SELF_TEST
+
+/*
+ * Enable the prime-number generation code.
+ */
+#define POLARSSL_GENPRIME
+
+/*
+ * Uncomment this macro to store the AES tables in ROM.
+ *
+#define POLARSSL_AES_ROM_TABLES
+ */
+
+/*
+ * Module:  library/aes.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_RSA_AES_128_SHA
+ *      SSL_RSA_AES_256_SHA
+ *      SSL_EDH_RSA_AES_256_SHA
+ */
+#define POLARSSL_AES_C
+
+/*
+ * Module:  library/arc4.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_RSA_RC4_128_MD5
+ *      SSL_RSA_RC4_128_SHA
+ */
+#define POLARSSL_ARC4_C
+
+/*
+ * Module:  library/base64.c
+ * Caller:  library/x509parse.c
+ *
+ * This module is required for X.509 support.
+ */
+#define POLARSSL_BASE64_C
+
+/*
+ * Module:  library/bignum.c
+ * Caller:  library/dhm.c
+ *          library/rsa.c
+ *          library/ssl_tls.c
+ *          library/x509parse.c
+ *
+ * This module is required for RSA and DHM support.
+ */
+#define POLARSSL_BIGNUM_C
+
+/*
+ * Module:  library/camellia.c
+ * Caller:
+ *
+ * This module enabled the following cipher suites:
+ */
+#define POLARSSL_CAMELLIA_C
+
+/*
+ * Module:  library/certs.c
+ * Caller:
+ *
+ * This module is used for testing (ssl_client/server).
+ */
+#define POLARSSL_CERTS_C
+
+/*
+ * Module:  library/debug.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module provides debugging functions.
+ */
+#define POLARSSL_DEBUG_C
+
+/*
+ * Module:  library/des.c
+ * Caller:  library/ssl_tls.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_RSA_DES_168_SHA
+ *      SSL_EDH_RSA_DES_168_SHA
+ */
+#define POLARSSL_DES_C
+
+/*
+ * Module:  library/dhm.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module enables the following ciphersuites:
+ *      SSL_EDH_RSA_DES_168_SHA
+ *      SSL_EDH_RSA_AES_256_SHA
+ */
+#define POLARSSL_DHM_C
+
+/*
+ * Module:  library/havege.c
+ * Caller:
+ *
+ * This module enables the HAVEGE random number generator.
+ */
+#define POLARSSL_HAVEGE_C
+
+/*
+ * Module:  library/md2.c
+ * Caller:  library/x509parse.c
+ *
+ * Uncomment to enable support for (rare) MD2-signed X.509 certs.
+ *
+#define POLARSSL_MD2_C
+ */
+
+/*
+ * Module:  library/md4.c
+ * Caller:  library/x509parse.c
+ *
+ * Uncomment to enable support for (rare) MD4-signed X.509 certs.
+ *
+#define POLARSSL_MD4_C
+ */
+
+/*
+ * Module:  library/md5.c
+ * Caller:  library/ssl_tls.c
+ *          library/x509parse.c
+ *
+ * This module is required for SSL/TLS and X.509.
+ */
+#define POLARSSL_MD5_C
+
+/*
+ * Module:  library/net.c
+ * Caller:
+ *
+ * This module provides TCP/IP networking routines.
+ */
+#define POLARSSL_NET_C
+
+/*
+ * Module:  library/padlock.c
+ * Caller:  library/aes.c
+ *
+ * This modules adds support for the VIA PadLock on x86.
+ */
+#define POLARSSL_PADLOCK_C
+
+/*
+ * Module:  library/rsa.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509.c
+ *
+ * This module is required for SSL/TLS and MD5-signed certificates.
+ */
+#define POLARSSL_RSA_C
+
+/*
+ * Module:  library/sha1.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509parse.c
+ *
+ * This module is required for SSL/TLS and SHA1-signed certificates.
+ */
+#define POLARSSL_SHA1_C
+
+/*
+ * Module:  library/sha2.c
+ * Caller:
+ *
+ * This module adds support for SHA-224 and SHA-256.
+ */
+#define POLARSSL_SHA2_C
+
+/*
+ * Module:  library/sha4.c
+ * Caller:
+ *
+ * This module adds support for SHA-384 and SHA-512.
+ */
+#define POLARSSL_SHA4_C
+
+/*
+ * Module:  library/ssl_cli.c
+ * Caller:
+ *
+ * This module is required for SSL/TLS client support.
+ */
+#define POLARSSL_SSL_CLI_C
+
+/*
+ * Module:  library/ssl_srv.c
+ * Caller:
+ *
+ * This module is required for SSL/TLS server support.
+ */
+#define POLARSSL_SSL_SRV_C
+
+/*
+ * Module:  library/ssl_tls.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *
+ * This module is required for SSL/TLS.
+ */
+#define POLARSSL_SSL_TLS_C
+
+/*
+ * Module:  library/timing.c
+ * Caller:  library/havege.c
+ *
+ * This module is used by the HAVEGE random number generator.
+ */
+#define POLARSSL_TIMING_C
+
+/*
+ * Module:  library/x509parse.c
+ * Caller:  library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *
+ * This module is required for X.509 certificate parsing.
+ */
+#define POLARSSL_X509_PARSE_C
+
+/*
+ * Module:  library/x509_write.c
+ * Caller:
+ *
+ * This module is required for X.509 certificate writing.
+ */
+#define POLARSSL_X509_WRITE_C
+
+/*
+ * Module:  library/xtea.c
+ * Caller:
+ */
+#define POLARSSL_XTEA_C
+
+#endif /* config.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/rsa.h b/package/utils/px5g-standalone/src/polarssl/rsa.h
new file mode 100644
index 0000000000..b31dc2f144
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/rsa.h
@@ -0,0 +1,309 @@
+/**
+ * \file rsa.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+#ifndef POLARSSL_RSA_H
+#define POLARSSL_RSA_H
+
+#include "polarssl/bignum.h"
+
+#define POLARSSL_ERR_RSA_BAD_INPUT_DATA                    -0x0400
+#define POLARSSL_ERR_RSA_INVALID_PADDING                   -0x0410
+#define POLARSSL_ERR_RSA_KEY_GEN_FAILED                    -0x0420
+#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED                  -0x0430
+#define POLARSSL_ERR_RSA_PUBLIC_FAILED                     -0x0440
+#define POLARSSL_ERR_RSA_PRIVATE_FAILED                    -0x0450
+#define POLARSSL_ERR_RSA_VERIFY_FAILED                     -0x0460
+#define POLARSSL_ERR_RSA_OUTPUT_TO_LARGE                   -0x0470
+
+/*
+ * PKCS#1 constants
+ */
+#define RSA_RAW         0
+#define RSA_MD2         2
+#define RSA_MD4         3
+#define RSA_MD5         4
+#define RSA_SHA1        5
+#define RSA_SHA256      6
+
+#define RSA_PUBLIC      0
+#define RSA_PRIVATE     1
+
+#define RSA_PKCS_V15    0
+#define RSA_PKCS_V21    1
+
+#define RSA_SIGN        1
+#define RSA_CRYPT       2
+
+/*
+ * DigestInfo ::= SEQUENCE {
+ *   digestAlgorithm DigestAlgorithmIdentifier,
+ *   digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+#define ASN1_HASH_MDX                       \
+    "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48"  \
+    "\x86\xF7\x0D\x02\x00\x05\x00\x04\x10"
+
+#define ASN1_HASH_SHA1                      \
+    "\x30\x21\x30\x09\x06\x05\x2B\x0E\x03"  \
+    "\x02\x1A\x05\x00\x04\x14"
+
+/**
+ * \brief          RSA context structure
+ */
+typedef struct
+{
+    int ver;                    /*!<  always 0          */
+    int len;                    /*!<  size(N) in chars  */
+
+    mpi N;                      /*!<  public modulus    */
+    mpi E;                      /*!<  public exponent   */
+
+    mpi D;                      /*!<  private exponent  */
+    mpi P;                      /*!<  1st prime factor  */
+    mpi Q;                      /*!<  2nd prime factor  */
+    mpi DP;                     /*!<  D % (P - 1)       */
+    mpi DQ;                     /*!<  D % (Q - 1)       */
+    mpi QP;                     /*!<  1 / (Q % P)       */
+
+    mpi RN;                     /*!<  cached R^2 mod N  */
+    mpi RP;                     /*!<  cached R^2 mod P  */
+    mpi RQ;                     /*!<  cached R^2 mod Q  */
+
+    int padding;                /*!<  1.5 or OAEP/PSS   */
+    int hash_id;                /*!<  hash identifier   */
+    int (*f_rng)(void *);       /*!<  RNG function      */
+    void *p_rng;                /*!<  RNG parameter     */
+}
+rsa_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Initialize an RSA context
+ *
+ * \param ctx      RSA context to be initialized
+ * \param padding  RSA_PKCS_V15 or RSA_PKCS_V21
+ * \param hash_id  RSA_PKCS_V21 hash identifier
+ * \param f_rng    RNG function
+ * \param p_rng    RNG parameter
+ *
+ * \note           The hash_id parameter is actually ignored
+ *                 when using RSA_PKCS_V15 padding.
+ *
+ * \note           Currently (xyssl-0.8), RSA_PKCS_V21 padding
+ *                 is not supported.
+ */
+void rsa_init( rsa_context *ctx,
+               int padding,
+               int hash_id,
+               int (*f_rng)(void *),
+               void *p_rng );
+
+/**
+ * \brief          Generate an RSA keypair
+ *
+ * \param ctx      RSA context that will hold the key
+ * \param nbits    size of the public key in bits
+ * \param exponent public exponent (e.g., 65537)
+ *
+ * \note           rsa_init() must be called beforehand to setup
+ *                 the RSA context (especially f_rng and p_rng).
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ */
+int rsa_gen_key( rsa_context *ctx, int nbits, int exponent );
+
+/**
+ * \brief          Check a public RSA key
+ *
+ * \param ctx      RSA context to be checked
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ */
+int rsa_check_pubkey( rsa_context *ctx );
+
+/**
+ * \brief          Check a private RSA key
+ *
+ * \param ctx      RSA context to be checked
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ */
+int rsa_check_privkey( rsa_context *ctx );
+
+/**
+ * \brief          Do an RSA public key operation
+ *
+ * \param ctx      RSA context
+ * \param input    input buffer
+ * \param output   output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           This function does NOT take care of message
+ *                 padding. Also, be sure to set input[0] = 0.
+ *
+ * \note           The input and output buffers must be large
+ *                 enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_public( rsa_context *ctx,
+                unsigned char *input,
+                unsigned char *output );
+
+/**
+ * \brief          Do an RSA private key operation
+ *
+ * \param ctx      RSA context
+ * \param input    input buffer
+ * \param output   output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The input and output buffers must be large
+ *                 enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_private( rsa_context *ctx,
+                 unsigned char *input,
+                 unsigned char *output );
+
+/**
+ * \brief          Add the message padding, then do an RSA operation
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param ilen     contains the the plaintext length
+ * \param input    buffer holding the data to be encrypted
+ * \param output   buffer that will hold the ciphertext
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_encrypt( rsa_context *ctx,
+                       int mode, int  ilen,
+                       unsigned char *input,
+                       unsigned char *output );
+
+/**
+ * \brief          Do an RSA operation, then remove the message padding
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param input    buffer holding the encrypted data
+ * \param output   buffer that will hold the plaintext
+ * \param olen     will contain the plaintext length
+ * \param output_max_len	maximum length of the output buffer
+ *
+ * \return         0 if successful, or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The output buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
+ *                 an error is thrown.
+ */
+int rsa_pkcs1_decrypt( rsa_context *ctx,
+                       int mode, int *olen,
+                       unsigned char *input,
+                       unsigned char *output,
+		       int output_max_len);
+
+/**
+ * \brief          Do a private RSA to sign a message digest
+ *
+ * \param ctx      RSA context
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  RSA_RAW, RSA_MD{2,4,5} or RSA_SHA{1,256}
+ * \param hashlen  message digest length (for RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer that will hold the ciphertext
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_sign( rsa_context *ctx,
+                    int mode,
+                    int hash_id,
+                    int hashlen,
+                    unsigned char *hash,
+                    unsigned char *sig );
+
+/**
+ * \brief          Do a public RSA and check the message digest
+ *
+ * \param ctx      points to an RSA public key
+ * \param mode     RSA_PUBLIC or RSA_PRIVATE
+ * \param hash_id  RSA_RAW, RSA_MD{2,4,5} or RSA_SHA{1,256}
+ * \param hashlen  message digest length (for RSA_RAW only)
+ * \param hash     buffer holding the message digest
+ * \param sig      buffer holding the ciphertext
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an POLARSSL_ERR_RSA_XXX error code
+ *
+ * \note           The "sig" buffer must be as large as the size
+ *                 of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int rsa_pkcs1_verify( rsa_context *ctx,
+                      int mode,
+                      int hash_id,
+                      int hashlen,
+                      unsigned char *hash,
+                      unsigned char *sig );
+
+/**
+ * \brief          Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int rsa_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* rsa.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/sha1.h b/package/utils/px5g-standalone/src/polarssl/sha1.h
new file mode 100644
index 0000000000..3ca7dc3195
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/sha1.h
@@ -0,0 +1,150 @@
+/**
+ * \file sha1.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+#ifndef POLARSSL_SHA1_H
+#define POLARSSL_SHA1_H
+
+/**
+ * \brief          SHA-1 context structure
+ */
+typedef struct
+{
+    unsigned long total[2];     /*!< number of bytes processed  */
+    unsigned long state[5];     /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+}
+sha1_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SHA-1 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void sha1_starts( sha1_context *ctx );
+
+/**
+ * \brief          SHA-1 process buffer
+ *
+ * \param ctx      SHA-1 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_update( sha1_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-1 final digest
+ *
+ * \param ctx      SHA-1 context
+ * \param output   SHA-1 checksum result
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] );
+
+/**
+ * \brief          Output = SHA-1( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-1 checksum result
+ */
+void sha1( unsigned char *input, int ilen, unsigned char output[20] );
+
+/**
+ * \brief          Output = SHA-1( file contents )
+ *
+ * \param path     input file name
+ * \param output   SHA-1 checksum result
+ *
+ * \return         0 if successful, 1 if fopen failed,
+ *                 or 2 if fread failed
+ */
+int sha1_file( char *path, unsigned char output[20] );
+
+/**
+ * \brief          SHA-1 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief          SHA-1 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief          SHA-1 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   SHA-1 HMAC checksum result
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );
+
+/**
+ * \brief          Output = HMAC-SHA-1( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-SHA-1 result
+ */
+void sha1_hmac( unsigned char *key, int keylen,
+                unsigned char *input, int ilen,
+                unsigned char output[20] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sha1_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha1.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/timing.h b/package/utils/px5g-standalone/src/polarssl/timing.h
new file mode 100644
index 0000000000..62d627f61b
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/timing.h
@@ -0,0 +1,81 @@
+/**
+ * \file timing.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+#ifndef POLARSSL_TIMING_H
+#define POLARSSL_TIMING_H
+
+/**
+ * \brief          timer structure
+ */
+struct hr_time
+{
+    unsigned char opaque[32];
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int alarmed;
+
+/**
+ * \brief          Return the CPU cycle counter value
+ */
+unsigned long hardclock( void );
+
+/**
+ * \brief          Return the elapsed time in milliseconds
+ *
+ * \param val      points to a timer structure
+ * \param reset    if set to 1, the timer is restarted
+ */
+unsigned long get_timer( struct hr_time *val, int reset );
+
+/**
+ * \brief          Setup an alarm clock
+ *
+ * \param seconds  delay before the "alarmed" flag is set
+ */
+void set_alarm( int seconds );
+
+/**
+ * \brief          Sleep for a certain amount of time
+ */
+void m_sleep( int milliseconds );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* timing.h */
diff --git a/package/utils/px5g-standalone/src/polarssl/x509.h b/package/utils/px5g-standalone/src/polarssl/x509.h
new file mode 100644
index 0000000000..908a1dbf51
--- /dev/null
+++ b/package/utils/px5g-standalone/src/polarssl/x509.h
@@ -0,0 +1,549 @@
+/**
+ * \file x509.h
+ *
+ *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
+ *
+ *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
+ *
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * 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.
+ *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *  
+ *  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
+ *  OWNER 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.
+ */
+#ifndef POLARSSL_X509_H
+#define POLARSSL_X509_H
+
+#include "polarssl/rsa.h"
+
+#define POLARSSL_ERR_ASN1_OUT_OF_DATA                      -0x0014
+#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG                   -0x0016
+#define POLARSSL_ERR_ASN1_INVALID_LENGTH                   -0x0018
+#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH                  -0x001A
+#define POLARSSL_ERR_ASN1_INVALID_DATA                     -0x001C
+
+#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE              -0x0020
+#define POLARSSL_ERR_X509_CERT_INVALID_PEM                 -0x0040
+#define POLARSSL_ERR_X509_CERT_INVALID_FORMAT              -0x0060
+#define POLARSSL_ERR_X509_CERT_INVALID_VERSION             -0x0080
+#define POLARSSL_ERR_X509_CERT_INVALID_SERIAL              -0x00A0
+#define POLARSSL_ERR_X509_CERT_INVALID_ALG                 -0x00C0
+#define POLARSSL_ERR_X509_CERT_INVALID_NAME                -0x00E0
+#define POLARSSL_ERR_X509_CERT_INVALID_DATE                -0x0100
+#define POLARSSL_ERR_X509_CERT_INVALID_PUBKEY              -0x0120
+#define POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE           -0x0140
+#define POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS          -0x0160
+#define POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION             -0x0180
+#define POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG             -0x01A0
+#define POLARSSL_ERR_X509_CERT_UNKNOWN_PK_ALG              -0x01C0
+#define POLARSSL_ERR_X509_CERT_SIG_MISMATCH                -0x01E0
+#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED               -0x0200
+#define POLARSSL_ERR_X509_KEY_INVALID_PEM                  -0x0220
+#define POLARSSL_ERR_X509_KEY_INVALID_VERSION              -0x0240
+#define POLARSSL_ERR_X509_KEY_INVALID_FORMAT               -0x0260
+#define POLARSSL_ERR_X509_KEY_INVALID_ENC_IV               -0x0280
+#define POLARSSL_ERR_X509_KEY_UNKNOWN_ENC_ALG              -0x02A0
+#define POLARSSL_ERR_X509_KEY_PASSWORD_REQUIRED            -0x02C0
+#define POLARSSL_ERR_X509_KEY_PASSWORD_MISMATCH            -0x02E0
+#define POLARSSL_ERR_X509_POINT_ERROR                      -0x0300
+#define POLARSSL_ERR_X509_VALUE_TO_LENGTH                  -0x0320
+
+#define BADCERT_EXPIRED                 1
+#define BADCERT_REVOKED                 2
+#define BADCERT_CN_MISMATCH             4
+#define BADCERT_NOT_TRUSTED             8
+
+/*
+ * DER constants
+ */
+#define ASN1_BOOLEAN                 0x01
+#define ASN1_INTEGER                 0x02
+#define ASN1_BIT_STRING              0x03
+#define ASN1_OCTET_STRING            0x04
+#define ASN1_NULL                    0x05
+#define ASN1_OID                     0x06
+#define ASN1_UTF8_STRING             0x0C
+#define ASN1_SEQUENCE                0x10
+#define ASN1_SET                     0x11
+#define ASN1_PRINTABLE_STRING        0x13
+#define ASN1_T61_STRING              0x14
+#define ASN1_IA5_STRING              0x16
+#define ASN1_UTC_TIME                0x17
+#define ASN1_UNIVERSAL_STRING        0x1C
+#define ASN1_BMP_STRING              0x1E
+#define ASN1_PRIMITIVE               0x00
+#define ASN1_CONSTRUCTED             0x20
+#define ASN1_CONTEXT_SPECIFIC        0x80
+
+/*
+ * various object identifiers
+ */
+#define X520_COMMON_NAME                3
+#define X520_COUNTRY                    6
+#define X520_LOCALITY                   7
+#define X520_STATE                      8
+#define X520_ORGANIZATION              10
+#define X520_ORG_UNIT                  11
+#define PKCS9_EMAIL                     1
+
+#define X509_OUTPUT_DER              0x01
+#define X509_OUTPUT_PEM              0x02
+#define PEM_LINE_LENGTH                72
+#define X509_ISSUER                  0x01
+#define X509_SUBJECT                 0x02
+
+#define OID_X520                "\x55\x04"
+#define OID_CN                  "\x55\x04\x03"
+#define OID_PKCS1               "\x2A\x86\x48\x86\xF7\x0D\x01\x01"
+#define OID_PKCS1_RSA           "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"
+#define OID_PKCS1_RSA_SHA       "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05"
+#define OID_PKCS9               "\x2A\x86\x48\x86\xF7\x0D\x01\x09"
+#define OID_PKCS9_EMAIL         "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"
+
+/*
+ * Structures for parsing X.509 certificates
+ */
+typedef struct _x509_buf
+{
+    int tag;
+    int len;
+    unsigned char *p;
+}
+x509_buf;
+
+typedef struct _x509_name
+{
+    x509_buf oid;
+    x509_buf val;
+    struct _x509_name *next;
+}
+x509_name;
+
+typedef struct _x509_time
+{
+    int year, mon, day;
+    int hour, min, sec;
+}
+x509_time;
+
+typedef struct _x509_cert
+{
+    x509_buf raw;
+    x509_buf tbs;
+
+    int version;
+    x509_buf serial;
+    x509_buf sig_oid1;
+
+    x509_buf issuer_raw;
+    x509_buf subject_raw;
+
+    x509_name issuer;
+    x509_name subject;
+
+    x509_time valid_from;
+    x509_time valid_to;
+
+    x509_buf pk_oid;
+    rsa_context rsa;
+
+    x509_buf issuer_id;
+    x509_buf subject_id;
+    x509_buf v3_ext;
+
+    int ca_istrue;
+    int max_pathlen;
+
+    x509_buf sig_oid2;
+    x509_buf sig;
+
+    struct _x509_cert *next; 
+}
+x509_cert;
+
+/*
+ * Structures for writing X.509 certificates
+ */
+typedef struct _x509_node
+{
+    unsigned char *data;
+    unsigned char *p;
+    unsigned char *end;
+
+    size_t len;
+}
+x509_node;
+
+typedef struct _x509_raw
+{
+    x509_node raw;
+    x509_node tbs;
+
+    x509_node version;
+    x509_node serial;
+    x509_node tbs_signalg;
+    x509_node issuer;
+    x509_node validity;
+    x509_node subject;
+    x509_node subpubkey;
+
+    x509_node signalg;
+    x509_node sign;
+}
+x509_raw;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Parse one or more certificates and add them
+ *                 to the chained list
+ *
+ * \param chain    points to the start of the chain
+ * \param buf      buffer holding the certificate data
+ * \param buflen   size of the buffer
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_crt( x509_cert *crt, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Load one or more certificates and add them
+ *                 to the chained list
+ *
+ * \param chain    points to the start of the chain
+ * \param path     filename to read the certificates from
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_crtfile( x509_cert *crt, char *path );
+
+/**
+ * \brief          Parse a private RSA key
+ *
+ * \param rsa      RSA context to be initialized
+ * \param buf      input buffer
+ * \param buflen   size of the buffer
+ * \param pwd      password for decryption (optional)
+ * \param pwdlen   size of the password
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_key( rsa_context *rsa,
+                   unsigned char *buf, int buflen,
+                   unsigned char *pwd, int pwdlen );
+
+/**
+ * \brief          Load and parse a private RSA key
+ *
+ * \param rsa      RSA context to be initialized
+ * \param path     filename to read the private key from
+ * \param pwd      password to decrypt the file (can be NULL)
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509parse_keyfile( rsa_context *rsa, char *path, char *password );
+
+/**
+ * \brief          Store the certificate DN in printable form into buf;
+ *                 no more than (end - buf) characters will be written.
+ */
+int x509parse_dn_gets( char *buf, char *end, x509_name *dn );
+
+/**
+ * \brief          Returns an informational string about the
+ *                 certificate.
+ */
+char *x509parse_cert_info( char *prefix, x509_cert *crt );
+
+/**
+ * \brief          Return 0 if the certificate is still valid,
+ *                 or BADCERT_EXPIRED
+ */
+int x509parse_expired( x509_cert *crt );
+
+/**
+ * \brief          Verify the certificate signature
+ *
+ * \param crt      a certificate to be verified
+ * \param trust_ca the trusted CA chain
+ * \param cn       expected Common Name (can be set to
+ *                 NULL if the CN must not be verified)
+ * \param flags    result of the verification
+ *
+ * \return         0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED,
+ *                 in which case *flags will have one or more of
+ *                 the following values set:
+ *                      BADCERT_EXPIRED --
+ *                      BADCERT_REVOKED --
+ *                      BADCERT_CN_MISMATCH --
+ *                      BADCERT_NOT_TRUSTED
+ *
+ * \note           TODO: add two arguments, depth and crl
+ */
+int x509parse_verify( x509_cert *crt,
+                      x509_cert *trust_ca,
+                      char *cn, int *flags );
+
+/**
+ * \brief          Unallocate all certificate data
+ */
+void x509_free( x509_cert *crt );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int x509_self_test( int verbose );
+
+/**
+ * \brief          Write a certificate info file
+ *
+ * \param chain    points to the raw certificate data
+ * \param path     filename to write the certificate to
+ * \param format   X509_OUTPUT_DER or X509_OUTPUT_PEM
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_crtfile( x509_raw *chain,
+                       unsigned char *path,
+                       int format );
+
+/**
+ * \brief          Write a certificate signing request message format file
+ *
+ * \param chain    points to the raw certificate (with x509write_create_csr) data
+ * \param path     filename to write the certificate to
+ * \param format   X509_OUTPUT_DER or X509_OUTPUT_PEM
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_csrfile( x509_raw *chain,
+                       unsigned char *path,
+                       int format );
+
+/*
+ * \brief          Write a private RSA key into a file
+ *
+ * \param rsa      points to an RSA key
+ * \param path     filename to write the key to
+ * \param format   X509_OUTPUT_DER or X509_OUTPUT_PEM
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_keyfile( rsa_context *rsa,
+                       char *path,
+                       int format );
+
+/**
+ * \brief          Add a public key to certificate
+ *
+ * \param chain    points to the raw certificate data
+ * \param pubkey   points to an RSA key
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_add_pubkey( x509_raw *chain, rsa_context *pubkey );
+
+/**
+ * \brief          Create x509 subject/issuer field to raw certificate
+ *                 from string or CA cert. Make string NULL if you will
+ *                 use the CA copy function or make CA NULL then used
+ *                 the string parse.
+ *
+ * \param chain    points to the raw certificate data
+ * \param names    a string that can hold (separete with ";"):
+ *                     CN=CommonName
+ *                 --   O=Organization
+ *                 --  OU=OrgUnit
+ *                 --  ST=State
+ *                 --   L=Locality
+ *                 --   R=Email
+ *                 --   C=Country
+ *                 . Make that NULL if you didn't need that.
+ * \param flag     flag is X509_ISSUER or X509_SUBJECT that defined
+ *                 where change
+ * \param ca       the certificate for copy data. Make that NULL if you
+ *                 didn't need that.
+ * \param ca_flag  set the ca field from copy to crt
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_add_customize ( x509_raw *crt, 
+                          unsigned char *names, 
+                          int flag, 
+                          x509_cert *ca, 
+                          int ca_flag );
+
+/**
+* \brief          Add x509 issuer field
+*
+* \param chain    points to the raw certificate data
+* \param issuer   a string holding (separete with ";"):
+*                     CN=CommonName
+*                 --   O=Organization
+*                 --  OU=OrgUnit
+*                 --  ST=State
+*                 --   L=Locality
+*                 --   R=Email
+*                 --   C=Country
+*                 . Set this to NULL if not needed.
+* \return         0 if successful, or a specific X509 error code
+*/
+int x509write_add_issuer( x509_raw *crt, unsigned char *issuer);
+
+/**
+ * \brief          Add x509 subject field
+ *
+ * \param chain    points to the raw certificate data
+ * \param subject  a string holding (separete with ";"):
+ *                     CN=CommonName
+ *                 --   O=Organization
+ *                 --  OU=OrgUnit
+ *                 --  ST=State
+ *                 --   L=Locality
+ *                 --   R=Email
+ *                 --   C=Country
+ *                 . Set this to NULL if not needed.
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_add_subject( x509_raw *crt, unsigned char *subject);
+
+/**
+* \brief          Copy x509 issuer field from another certificate
+*
+* \param chain    points to the raw certificate data
+* \param from_crt the certificate whose issuer is to be copied.
+* \return         0 if successful, or a specific X509 error code
+*/
+int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt);
+
+/**
+* \brief          Copy x509 subject field from another certificate
+*
+* \param chain    points to the raw certificate data
+* \param from_crt the certificate whose subject is to be copied.
+* \return         0 if successful, or a specific X509 error code
+*/
+int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt);
+
+/**
+* \brief          Copy x509 issuer field from the subject of another certificate
+*
+* \param chain    points to the raw certificate data
+* \param from_crt the certificate whose subject is to be copied.
+* \return         0 if successful, or a specific X509 error code
+*/
+int x509write_copy_issuer_from_subject(x509_raw *crt, x509_cert *from_crt);
+
+/**
+* \brief          Copy x509 subject field from the issuer of another certificate
+*
+* \param chain    points to the raw certificate data
+* \param from_crt the certificate whose issuer is to be copied.
+* \return         0 if successful, or a specific X509 error code
+*/
+int x509write_copy_subject_from_issuer(x509_raw *crt, x509_cert *from_crt);
+
+/**
+ * \brief          Create x509 validity time in UTC
+ *
+ * \param chain    points to the raw certificate data
+ * \param before   valid not before in format YYYY-MM-DD hh:mm:ss
+ * \param after    valid not after  in format YYYY-MM-DD hh:mm:ss
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_add_validity( x509_raw *crt,
+                               unsigned char *before,
+                               unsigned char *after );
+
+/**
+ * \brief          Create a self-signed certificate
+ *
+ * \param chain    points to the raw certificate data
+ * \param rsa      a private key to sign the certificate
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_create_selfsign( x509_raw *crt, rsa_context *raw );
+
+/**
+ * \brief          Create a certificate
+ *
+ * \param chain    points to the raw certificate data
+ * \param rsa      a private key to sign the certificate
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_create_sign( x509_raw *crt, rsa_context *raw );
+
+/**
+ * \brief          Create a certificate signing request
+ *
+ * \param chain    points to the raw certificate data. Didn't use the
+ *                 same chain that u have use for certificate.
+ * \param privkey  a rsa private key
+ *
+ * \return         0 if successful, or a specific X509 error code
+ */
+int x509write_create_csr( x509_raw *chain, rsa_context *privkey );
+
+/**
+ * \brief           Serialize an rsa key into DER
+ *
+ * \param rsa       a rsa key for output
+ * \param node      a x509 node for write into
+ *
+ * \return          0 if successful, or a specific X509 error code
+ */
+int x509write_serialize_key( rsa_context *rsa, x509_node *node );
+
+/**
+ * \brief          Unallocate all raw certificate data
+ */
+void x509write_free_raw( x509_raw *crt );
+
+/**
+ * \brief          Allocate all raw certificate data
+ */
+void x509write_init_raw( x509_raw *crt );
+
+/**
+ * \brief          Unallocate all node certificate data
+ */
+void x509write_free_node( x509_node *crt_node );
+
+/**
+ * \brief          Allocate all node certificate data
+ */
+void x509write_init_node( x509_node *crt_node );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* x509.h */
diff --git a/package/utils/px5g-standalone/src/px5g.c b/package/utils/px5g-standalone/src/px5g.c
new file mode 100644
index 0000000000..34ab34f32d
--- /dev/null
+++ b/package/utils/px5g-standalone/src/px5g.c
@@ -0,0 +1,213 @@
+/*
+ * px5g - Embedded x509 key and certificate generator based on PolarSSL
+ *
+ *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "polarssl/bignum.h"
+#include "polarssl/x509.h"
+#include "polarssl/rsa.h"
+
+#define PX5G_VERSION "0.1"
+#define PX5G_COPY "Copyright (c) 2009 Steven Barth <steven@midlink.org>"
+#define PX5G_LICENSE "Licensed under the GNU Lesser General Public License v2.1"
+
+static int urandom_fd;
+
+static int _urandom(void *ctx)
+{
+	int ret;
+	read(urandom_fd, &ret, sizeof(ret));
+	return ret;
+}
+
+
+int rsakey(char **arg) {
+	rsa_context rsa;
+
+	unsigned int ksize = 512;
+	int exp = 65537;
+	char *path = NULL;
+	int flag = X509_OUTPUT_PEM;
+
+	while (*arg && **arg == '-') {
+		if (!strcmp(*arg, "-out") && arg[1]) {
+			path = arg[1];
+			arg++;
+		} else if (!strcmp(*arg, "-3")) {
+			exp = 3;
+		} else if (!strcmp(*arg, "-der")) {
+			flag = X509_OUTPUT_DER;
+		}
+		arg++;
+	}
+
+	if (*arg) {
+		ksize = (unsigned int)atoi(*arg);
+	}
+
+	rsa_init(&rsa, RSA_PKCS_V15, 0, _urandom, NULL);
+
+	fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
+	if (rsa_gen_key(&rsa, ksize, exp)) {
+		fprintf(stderr, "error: key generation failed\n");
+		return 1;
+	}
+
+	if (x509write_keyfile(&rsa, path, flag)) {
+		fprintf(stderr, "error: I/O error\n");
+		return 1;
+	}
+
+	rsa_free(&rsa);
+	return 0;
+}
+
+int selfsigned(char **arg) {
+	rsa_context rsa;
+	x509_node node;
+
+	char *subject = "";
+	unsigned int ksize = 512;
+	int exp = 65537;
+	unsigned int days = 30;
+	char *keypath = NULL, *certpath = NULL;
+	int flag = X509_OUTPUT_PEM;
+	time_t from = time(NULL), to;
+	char fstr[20], tstr[20];
+
+	while (*arg && **arg == '-') {
+		if (!strcmp(*arg, "-der")) {
+			flag = X509_OUTPUT_DER;
+		} else if (!strcmp(*arg, "-newkey") && arg[1]) {
+			if (strncmp(arg[1], "rsa:", 4)) {
+				fprintf(stderr, "error: invalid algorithm");
+				return 1;
+			}
+			ksize = (unsigned int)atoi(arg[1] + 4);
+			arg++;
+		} else if (!strcmp(*arg, "-days") && arg[1]) {
+			days = (unsigned int)atoi(arg[1]);
+			arg++;
+		} else if (!strcmp(*arg, "-keyout") && arg[1]) {
+			keypath = arg[1];
+			arg++;
+		} else if (!strcmp(*arg, "-out") && arg[1]) {
+			certpath = arg[1];
+			arg++;
+		} else if (!strcmp(*arg, "-subj") && arg[1]) {
+			if (arg[1][0] != '/' || strchr(arg[1], ';')) {
+				fprintf(stderr, "error: invalid subject");
+				return 1;
+			}
+			subject = calloc(strlen(arg[1]) + 1, 1);
+			char *oldc = arg[1] + 1, *newc = subject, *delim;
+			do {
+				delim = strchr(oldc, '=');
+				if (!delim) {
+					fprintf(stderr, "error: invalid subject");
+					return 1;
+				}
+				memcpy(newc, oldc, delim - oldc + 1);
+				newc += delim - oldc + 1;
+				oldc = delim + 1;
+
+				delim = strchr(oldc, '/');
+				if (!delim) {
+					delim = arg[1] + strlen(arg[1]);
+				}
+				memcpy(newc, oldc, delim - oldc);
+				newc += delim - oldc;
+				*newc++ = ';';
+				oldc = delim + 1;
+			} while(*delim);
+			arg++;
+		}
+		arg++;
+	}
+
+	rsa_init(&rsa, RSA_PKCS_V15, 0, _urandom, NULL);
+	x509write_init_node(&node);
+	fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
+	if (rsa_gen_key(&rsa, ksize, exp)) {
+		fprintf(stderr, "error: key generation failed\n");
+		return 1;
+	}
+
+	if (keypath) {
+		if (x509write_keyfile(&rsa, keypath, flag)) {
+			fprintf(stderr, "error: I/O error\n");
+			return 1;
+		}
+	}
+
+	from = (from < 1000000000) ? 1000000000 : from;
+	strftime(fstr, sizeof(fstr), "%F %H:%M:%S", gmtime(&from));
+	to = from + 60 * 60 * 24 * days;
+	if (to < from)
+		to = INT_MAX;
+	strftime(tstr, sizeof(tstr), "%F %H:%M:%S", gmtime(&to));
+
+	x509_raw cert;
+	x509write_init_raw(&cert);
+	x509write_add_pubkey(&cert, &rsa);
+	x509write_add_subject(&cert, (unsigned char*)subject);
+	x509write_add_validity(&cert, (unsigned char*)fstr, (unsigned char*)tstr);
+	fprintf(stderr, "Generating selfsigned certificate with subject '%s'"
+			" and validity %s-%s\n", subject, fstr, tstr);
+	if (x509write_create_selfsign(&cert, &rsa)) {
+		fprintf(stderr, "error: certificate generation failed\n");
+	}
+
+	if (x509write_crtfile(&cert, (unsigned char*)certpath, flag)) {
+		fprintf(stderr, "error: I/O error\n");
+		return 1;
+	}
+
+	x509write_free_raw(&cert);
+	rsa_free(&rsa);
+	return 0;
+}
+
+int main(int argc, char *argv[]) {
+	urandom_fd = open("/dev/urandom", O_RDONLY);
+	if (urandom_fd < 0) {
+		perror("open(/dev/urandom)");
+		return 1;
+	}
+
+	if (!argv[1]) {
+		//Usage
+	} else if (!strcmp(argv[1], "rsakey")) {
+		return rsakey(argv+2);
+	} else if (!strcmp(argv[1], "selfsigned")) {
+		return selfsigned(argv+2);
+	}
+
+	fprintf(stderr,
+		"PX5G X.509 Certificate Generator Utility v" PX5G_VERSION "\n" PX5G_COPY
+		"\nbased on PolarSSL by Christophe Devine and Paul Bakker\n\n");
+	fprintf(stderr, "Usage: %s [rsakey|selfsigned]\n", *argv);
+	return 1;
+}
diff --git a/package/utils/px5g/Makefile b/package/utils/px5g/Makefile
new file mode 100644
index 0000000000..c5de03a02c
--- /dev/null
+++ b/package/utils/px5g/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2010-2015 Jo-Philipp Wich <jo@mein.io>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=px5g
+PKG_RELEASE:=4
+PKG_LICENSE:=LGPL-2.1
+PKG_BUILD_DIR:=$(BUILD_DIR)/px5g-$(BUILD_VARIANT)
+
+PKG_USE_MIPS16:=0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/px5g/Template
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Encryption
+  TITLE:=X.509 certificate generator (using $(1))
+  MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+  DEPENDS:=+lib$(1)
+  PROVIDES:=px5g
+  VARIANT:=$(1)
+endef
+
+define Package/px5g-polarssl/description
+ Px5g is a tiny standalone X.509 certificate generator.
+ It suitable to create key files and certificates in DER
+ and PEM format for use with stunnel, uhttpd and others.
+endef
+
+Package/px5g-mbedtls=$(call Package/px5g/Template,mbedtls)
+Package/px5g-polarssl=$(call Package/px5g/Template,polarssl)
+Package/px5g-mbedtls/description=$(Package/px5g-polarssl/description)
+
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+endef
+
+ifeq ($(BUILD_VARIANT),mbedtls)
+TARGET_CFLAGS += -DMBEDTLS
+TARGET_LDFLAGS := -lmbedtls -lmbedx509 -lmbedcrypto
+else
+TARGET_LDFLAGS := -lpolarssl
+endif
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/px5g px5g.c $(TARGET_LDFLAGS)
+endef
+
+define Package/px5g-polarssl/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/px5g $(1)/usr/sbin/px5g
+endef
+
+Package/px5g-mbedtls/install=$(Package/px5g-polarssl/install)
+
+$(eval $(call BuildPackage,px5g-polarssl))
+$(eval $(call BuildPackage,px5g-mbedtls))
diff --git a/package/utils/px5g/px5g.c b/package/utils/px5g/px5g.c
new file mode 100644
index 0000000000..af8a5da87f
--- /dev/null
+++ b/package/utils/px5g/px5g.c
@@ -0,0 +1,289 @@
+/*
+ * px5g - Embedded x509 key and certificate generator based on PolarSSL
+ *
+ *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *   Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+
+#ifdef MBEDTLS
+#include <mbedtls/bignum.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/rsa.h>
+#include <mbedtls/pk.h>
+#define lib_wrapper(x) mbedtls_##x
+#define MD_SHA256	MBEDTLS_MD_SHA256
+#else
+#include <polarssl/bignum.h>
+#include <polarssl/x509_crt.h>
+#include <polarssl/rsa.h>
+#define lib_wrapper(x)	x
+#define MD_SHA256	POLARSSL_MD_SHA256
+#endif
+
+#define PX5G_VERSION "0.2"
+#define PX5G_COPY "Copyright (c) 2009 Steven Barth <steven@midlink.org>"
+#define PX5G_LICENSE "Licensed under the GNU Lesser General Public License v2.1"
+
+static int urandom_fd;
+static char buf[16384];
+
+static int _urandom(void *ctx, unsigned char *out, size_t len)
+{
+	read(urandom_fd, out, len);
+	return 0;
+}
+
+static void write_file(const char *path, int len, bool pem)
+{
+	FILE *f = stdout;
+	const char *buf_start = buf;
+
+	if (!pem)
+		buf_start += sizeof(buf) - len;
+
+	if (!len) {
+		fprintf(stderr, "No data to write\n");
+		exit(1);
+	}
+
+	if (!f) {
+		fprintf(stderr, "error: I/O error\n");
+		exit(1);
+	}
+
+	if (path)
+		f = fopen(path, "w");
+
+	fwrite(buf_start, 1, len, f);
+	fclose(f);
+}
+
+static void write_key(lib_wrapper(pk_context) *key, const char *path, bool pem)
+{
+	int len = 0;
+
+	if (pem) {
+		if (lib_wrapper(pk_write_key_pem(key, (void *) buf, sizeof(buf)) == 0))
+			len = strlen(buf);
+	} else {
+		len = lib_wrapper(pk_write_key_der(key, (void *) buf, sizeof(buf)));
+		if (len < 0)
+			len = 0;
+	}
+
+	write_file(path, len, pem);
+}
+
+static void gen_key(lib_wrapper(pk_context) *key, int ksize, int exp, bool pem)
+{
+	lib_wrapper(pk_init(key));
+	fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
+#ifdef MBEDTLS
+	mbedtls_pk_setup(key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
+	if (mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), _urandom, NULL, ksize, exp)) {
+#else
+	pk_init_ctx(key, lib_wrapper(pk_info_from_type(POLARSSL_PK_RSA)));
+	if (rsa_gen_key(pk_rsa(*key), _urandom, NULL, ksize, exp)) {
+#endif
+		fprintf(stderr, "error: key generation failed\n");
+		exit(1);
+	}
+}
+
+int rsakey(char **arg)
+{
+	lib_wrapper(pk_context) key;
+	unsigned int ksize = 512;
+	int exp = 65537;
+	char *path = NULL;
+	bool pem = true;
+
+	while (*arg && **arg == '-') {
+		if (!strcmp(*arg, "-out") && arg[1]) {
+			path = arg[1];
+			arg++;
+		} else if (!strcmp(*arg, "-3")) {
+			exp = 3;
+		} else if (!strcmp(*arg, "-der")) {
+			pem = false;
+		}
+		arg++;
+	}
+
+	if (*arg)
+		ksize = (unsigned int)atoi(*arg);
+
+	gen_key(&key, ksize, exp, pem);
+	write_key(&key, path, pem);
+
+	lib_wrapper(pk_free(&key));
+
+	return 0;
+}
+
+int selfsigned(char **arg)
+{
+	lib_wrapper(pk_context) key;
+	lib_wrapper(x509write_cert) cert;
+	lib_wrapper(mpi) serial;
+
+	char *subject = "";
+	unsigned int ksize = 512;
+	int exp = 65537;
+	unsigned int days = 30;
+	char *keypath = NULL, *certpath = NULL;
+	bool pem = true;
+	time_t from = time(NULL), to;
+	char fstr[20], tstr[20], sstr[17];
+	int len;
+
+	while (*arg && **arg == '-') {
+		if (!strcmp(*arg, "-der")) {
+			pem = false;
+		} else if (!strcmp(*arg, "-newkey") && arg[1]) {
+			if (strncmp(arg[1], "rsa:", 4)) {
+				fprintf(stderr, "error: invalid algorithm");
+				return 1;
+			}
+			ksize = (unsigned int)atoi(arg[1] + 4);
+			arg++;
+		} else if (!strcmp(*arg, "-days") && arg[1]) {
+			days = (unsigned int)atoi(arg[1]);
+			arg++;
+		} else if (!strcmp(*arg, "-keyout") && arg[1]) {
+			keypath = arg[1];
+			arg++;
+		} else if (!strcmp(*arg, "-out") && arg[1]) {
+			certpath = arg[1];
+			arg++;
+		} else if (!strcmp(*arg, "-subj") && arg[1]) {
+			if (arg[1][0] != '/' || strchr(arg[1], ';')) {
+				fprintf(stderr, "error: invalid subject");
+				return 1;
+			}
+			subject = calloc(strlen(arg[1]) + 1, 1);
+			char *oldc = arg[1] + 1, *newc = subject, *delim;
+			do {
+				delim = strchr(oldc, '=');
+				if (!delim) {
+					fprintf(stderr, "error: invalid subject");
+					return 1;
+				}
+				memcpy(newc, oldc, delim - oldc + 1);
+				newc += delim - oldc + 1;
+				oldc = delim + 1;
+
+				delim = strchr(oldc, '/');
+				if (!delim) {
+					delim = arg[1] + strlen(arg[1]);
+				}
+				memcpy(newc, oldc, delim - oldc);
+				newc += delim - oldc;
+				*newc++ = ',';
+				oldc = delim + 1;
+			} while(*delim);
+			arg++;
+		}
+		arg++;
+	}
+
+	gen_key(&key, ksize, exp, pem);
+
+	if (keypath)
+		write_key(&key, keypath, pem);
+
+	from = (from < 1000000000) ? 1000000000 : from;
+	strftime(fstr, sizeof(fstr), "%Y%m%d%H%M%S", gmtime(&from));
+	to = from + 60 * 60 * 24 * days;
+	if (to < from)
+		to = INT_MAX;
+	strftime(tstr, sizeof(tstr), "%Y%m%d%H%M%S", gmtime(&to));
+
+	fprintf(stderr, "Generating selfsigned certificate with subject '%s'"
+			" and validity %s-%s\n", subject, fstr, tstr);
+
+	lib_wrapper(x509write_crt_init(&cert));
+	lib_wrapper(x509write_crt_set_md_alg(&cert, MD_SHA256));
+	lib_wrapper(x509write_crt_set_issuer_key(&cert, &key));
+	lib_wrapper(x509write_crt_set_subject_key(&cert, &key));
+	lib_wrapper(x509write_crt_set_subject_name(&cert, subject));
+	lib_wrapper(x509write_crt_set_issuer_name(&cert, subject));
+	lib_wrapper(x509write_crt_set_validity(&cert, fstr, tstr));
+	lib_wrapper(x509write_crt_set_basic_constraints(&cert, 0, -1));
+	lib_wrapper(x509write_crt_set_subject_key_identifier(&cert));
+	lib_wrapper(x509write_crt_set_authority_key_identifier(&cert));
+
+	_urandom(NULL, buf, 8);
+	for (len = 0; len < 8; len++)
+		sprintf(sstr + len*2, "%02x", (unsigned char) buf[len]);
+
+	lib_wrapper(mpi_init(&serial));
+	lib_wrapper(mpi_read_string(&serial, 16, sstr));
+	lib_wrapper(x509write_crt_set_serial(&cert, &serial));
+
+	if (pem) {
+		if (lib_wrapper(x509write_crt_pem(&cert, (void *) buf, sizeof(buf), _urandom, NULL) < 0)) {
+			fprintf(stderr, "Failed to generate certificate\n");
+			return 1;
+		}
+
+		len = strlen(buf);
+	} else {
+		len = lib_wrapper(x509write_crt_der(&cert, (void *) buf, sizeof(buf), _urandom, NULL));
+		if (len < 0) {
+			fprintf(stderr, "Failed to generate certificate: %d\n", len);
+			return 1;
+		}
+	}
+	write_file(certpath, len, pem);
+
+	lib_wrapper(x509write_crt_free(&cert));
+	lib_wrapper(mpi_free(&serial));
+	lib_wrapper(pk_free(&key));
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	urandom_fd = open("/dev/urandom", O_RDONLY);
+
+	if (!argv[1]) {
+		//Usage
+	} else if (!strcmp(argv[1], "rsakey")) {
+		return rsakey(argv+2);
+	} else if (!strcmp(argv[1], "selfsigned")) {
+		return selfsigned(argv+2);
+	}
+
+	fprintf(stderr,
+		"PX5G X.509 Certificate Generator Utility v" PX5G_VERSION "\n" PX5G_COPY
+		"\nbased on PolarSSL by Christophe Devine and Paul Bakker\n\n");
+	fprintf(stderr, "Usage: %s [rsakey|selfsigned]\n", *argv);
+	return 1;
+}
diff --git a/package/utils/spidev_test/Makefile b/package/utils/spidev_test/Makefile
new file mode 100644
index 0000000000..b7c5227f91
--- /dev/null
+++ b/package/utils/spidev_test/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=spidev-test
+PKG_RELEASE:=$(LINUX_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/spidev-test
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+kmod-spi-dev
+  TITLE:=SPI testing utility
+  VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE)
+  URL:=http://www.kernel.org
+  MAINTAINER:=Florian Fainelli <florian@openwrt.org>
+endef
+
+define Package/spidev-test/description
+  SPI testing utility.
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/spidev_test \
+		$(PKG_BUILD_DIR)/spidev_test.c
+endef
+
+define Package/spidev-test/install
+	$(INSTALL_DIR) $(1)/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/spidev_test $(1)/sbin/
+endef
+
+$(eval $(call BuildPackage,spidev-test))
diff --git a/package/utils/spidev_test/src/spidev_test.c b/package/utils/spidev_test/src/spidev_test.c
new file mode 100644
index 0000000000..135b3f592b
--- /dev/null
+++ b/package/utils/spidev_test/src/spidev_test.c
@@ -0,0 +1,318 @@
+/*
+ * SPI testing utility (using spidev driver)
+ *
+ * Copyright (c) 2007  MontaVista Software, Inc.
+ * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static void pabort(const char *s)
+{
+	perror(s);
+	abort();
+}
+
+static const char *device = "/dev/spidev1.1";
+static uint32_t mode;
+static uint8_t bits = 8;
+static uint32_t speed = 500000;
+static uint16_t delay;
+static int verbose;
+
+uint8_t default_tx[] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0x0D,
+};
+
+uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
+char *input_tx;
+
+static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix)
+{
+	int i = 0;
+	const unsigned char *address = src;
+	const unsigned char *line = address;
+	unsigned char c;
+
+	printf("%s | ", prefix);
+	while (length-- > 0) {
+		printf("%02X ", *address++);
+		if (!(++i % line_size) || (length == 0 && i % line_size)) {
+			if (length == 0) {
+				while (i++ % line_size)
+					printf("__ ");
+			}
+			printf(" | ");  /* right close */
+			while (line < address) {
+				c = *line++;
+				printf("%c", (c < 33 || c == 255) ? 0x2E : c);
+			}
+			printf("\n");
+			if (length > 0)
+				printf("%s | ", prefix);
+		}
+	}
+}
+
+/*
+ *  Unescape - process hexadecimal escape character
+ *      converts shell input "\x23" -> 0x23
+ */
+static int unescape(char *_dst, char *_src, size_t len)
+{
+	int ret = 0;
+	char *src = _src;
+	char *dst = _dst;
+	unsigned int ch;
+
+	while (*src) {
+		if (*src == '\\' && *(src+1) == 'x') {
+			sscanf(src + 2, "%2x", &ch);
+			src += 4;
+			*dst++ = (unsigned char)ch;
+		} else {
+			*dst++ = *src++;
+		}
+		ret++;
+	}
+	return ret;
+}
+
+static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
+{
+	int ret;
+
+	struct spi_ioc_transfer tr = {
+		.tx_buf = (unsigned long)tx,
+		.rx_buf = (unsigned long)rx,
+		.len = len,
+		.delay_usecs = delay,
+		.speed_hz = speed,
+		.bits_per_word = bits,
+	};
+
+	if (mode & SPI_TX_QUAD)
+		tr.tx_nbits = 4;
+	else if (mode & SPI_TX_DUAL)
+		tr.tx_nbits = 2;
+	if (mode & SPI_RX_QUAD)
+		tr.rx_nbits = 4;
+	else if (mode & SPI_RX_DUAL)
+		tr.rx_nbits = 2;
+	if (!(mode & SPI_LOOP)) {
+		if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
+			tr.rx_buf = 0;
+		else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
+			tr.tx_buf = 0;
+	}
+
+	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+	if (ret < 1)
+		pabort("can't send spi message");
+
+	if (verbose)
+		hex_dump(tx, len, 32, "TX");
+	hex_dump(rx, len, 32, "RX");
+}
+
+static void print_usage(const char *prog)
+{
+	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
+	puts("  -D --device   device to use (default /dev/spidev1.1)\n"
+	     "  -s --speed    max speed (Hz)\n"
+	     "  -d --delay    delay (usec)\n"
+	     "  -b --bpw      bits per word \n"
+	     "  -l --loop     loopback\n"
+	     "  -H --cpha     clock phase\n"
+	     "  -O --cpol     clock polarity\n"
+	     "  -L --lsb      least significant bit first\n"
+	     "  -C --cs-high  chip select active high\n"
+	     "  -3 --3wire    SI/SO signals shared\n"
+	     "  -v --verbose  Verbose (show tx buffer)\n"
+	     "  -p            Send data (e.g. \"1234\\xde\\xad\")\n"
+	     "  -N --no-cs    no chip select\n"
+	     "  -R --ready    slave pulls low to pause\n"
+	     "  -2 --dual     dual transfer\n"
+	     "  -4 --quad     quad transfer\n");
+	exit(1);
+}
+
+static void parse_opts(int argc, char *argv[])
+{
+	while (1) {
+		static const struct option lopts[] = {
+			{ "device",  1, 0, 'D' },
+			{ "speed",   1, 0, 's' },
+			{ "delay",   1, 0, 'd' },
+			{ "bpw",     1, 0, 'b' },
+			{ "loop",    0, 0, 'l' },
+			{ "cpha",    0, 0, 'H' },
+			{ "cpol",    0, 0, 'O' },
+			{ "lsb",     0, 0, 'L' },
+			{ "cs-high", 0, 0, 'C' },
+			{ "3wire",   0, 0, '3' },
+			{ "no-cs",   0, 0, 'N' },
+			{ "ready",   0, 0, 'R' },
+			{ "dual",    0, 0, '2' },
+			{ "verbose", 0, 0, 'v' },
+			{ "quad",    0, 0, '4' },
+			{ NULL, 0, 0, 0 },
+		};
+		int c;
+
+		c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24p:v", lopts, NULL);
+
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'D':
+			device = optarg;
+			break;
+		case 's':
+			speed = atoi(optarg);
+			break;
+		case 'd':
+			delay = atoi(optarg);
+			break;
+		case 'b':
+			bits = atoi(optarg);
+			break;
+		case 'l':
+			mode |= SPI_LOOP;
+			break;
+		case 'H':
+			mode |= SPI_CPHA;
+			break;
+		case 'O':
+			mode |= SPI_CPOL;
+			break;
+		case 'L':
+			mode |= SPI_LSB_FIRST;
+			break;
+		case 'C':
+			mode |= SPI_CS_HIGH;
+			break;
+		case '3':
+			mode |= SPI_3WIRE;
+			break;
+		case 'N':
+			mode |= SPI_NO_CS;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		case 'R':
+			mode |= SPI_READY;
+			break;
+		case 'p':
+			input_tx = optarg;
+			break;
+		case '2':
+			mode |= SPI_TX_DUAL;
+			break;
+		case '4':
+			mode |= SPI_TX_QUAD;
+			break;
+		default:
+			print_usage(argv[0]);
+			break;
+		}
+	}
+	if (mode & SPI_LOOP) {
+		if (mode & SPI_TX_DUAL)
+			mode |= SPI_RX_DUAL;
+		if (mode & SPI_TX_QUAD)
+			mode |= SPI_RX_QUAD;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = 0;
+	int fd;
+	uint8_t *tx;
+	uint8_t *rx;
+	int size;
+
+	parse_opts(argc, argv);
+
+	fd = open(device, O_RDWR);
+	if (fd < 0)
+		pabort("can't open device");
+
+	/*
+	 * spi mode
+	 */
+	ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
+	if (ret == -1)
+		pabort("can't set spi mode");
+
+	ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
+	if (ret == -1)
+		pabort("can't get spi mode");
+
+	/*
+	 * bits per word
+	 */
+	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
+	if (ret == -1)
+		pabort("can't set bits per word");
+
+	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
+	if (ret == -1)
+		pabort("can't get bits per word");
+
+	/*
+	 * max speed hz
+	 */
+	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
+	if (ret == -1)
+		pabort("can't set max speed hz");
+
+	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
+	if (ret == -1)
+		pabort("can't get max speed hz");
+
+	printf("spi mode: 0x%x\n", mode);
+	printf("bits per word: %d\n", bits);
+	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
+
+	if (input_tx) {
+		size = strlen(input_tx+1);
+		tx = malloc(size);
+		rx = malloc(size);
+		size = unescape((char *)tx, input_tx, size);
+		transfer(fd, tx, rx, size);
+		free(rx);
+		free(tx);
+	} else {
+		transfer(fd, default_tx, default_rx, sizeof(default_tx));
+	}
+
+	close(fd);
+
+	return ret;
+}
diff --git a/package/utils/ugps/Makefile b/package/utils/ugps/Makefile
new file mode 100644
index 0000000000..e85f9326c4
--- /dev/null
+++ b/package/utils/ugps/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ugps
+PKG_VERSION:=2016-10-24
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_URL=$(LEDE_GIT)/project/ugps.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=32a6b2b702c3b9f8c425f3d9dc9f4273e276029c
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=a353c722c3fe490dec1b6180c215e6a1d502e843c780dd97d556d1b346e8fa49
+
+PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+PKG_LICENSE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/ugps
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=OpenWrt GPS Daemon
+  DEPENDS:=+libubox +libubus
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+ifneq ($(CONFIG_USE_GLIBC),)
+  TARGET_CFLAGS += -D_DEFAULT_SOURCE
+endif
+
+define Package/ugps/conffiles
+/etc/config/gps
+endef
+
+define Package/ugps/install
+	$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/ugps $(1)/usr/sbin/
+	$(INSTALL_BIN) ./files/ugps.init $(1)/etc/init.d/ugps
+	$(INSTALL_CONF) ./files/gps.config $(1)/etc/config/gps
+endef
+
+$(eval $(call BuildPackage,ugps))
diff --git a/package/utils/ugps/files/gps.config b/package/utils/ugps/files/gps.config
new file mode 100644
index 0000000000..eb00d79c60
--- /dev/null
+++ b/package/utils/ugps/files/gps.config
@@ -0,0 +1,3 @@
+config gps
+	option	'tty'	'ttyACM0'
+	option	'adjust_time '	'1'
diff --git a/package/utils/ugps/files/ugps.init b/package/utils/ugps/files/ugps.init
new file mode 100644
index 0000000000..a7a88c2258
--- /dev/null
+++ b/package/utils/ugps/files/ugps.init
@@ -0,0 +1,24 @@
+#!/bin/sh /etc/rc.common
+# Copyright (c) 2014 OpenWrt.org
+
+START=80
+
+USE_PROCD=1
+PROG=/usr/sbin/ugps
+
+service_triggers() {
+	procd_add_reload_trigger gps
+}
+
+start_service() {
+	local tty="$(uci get gps.@gps[-1].tty)"
+	local atime="$(uci get gps.@gps[-1].adjust_time)"
+
+	[ -d "/sys/class/tty/$tty/" ] || return
+
+	procd_open_instance
+	procd_set_param command "$PROG" "/dev/$tty"
+	[ "$atime" -eq 0 ] || procd_append_param command "-a"
+	procd_set_param respawn
+	procd_close_instance
+}
diff --git a/package/utils/usbmode/Makefile b/package/utils/usbmode/Makefile
new file mode 100644
index 0000000000..d835d373ba
--- /dev/null
+++ b/package/utils/usbmode/Makefile
@@ -0,0 +1,71 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=usbmode
+PKG_VERSION:=2014-08-26
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(LEDE_GIT)/project/usbmode.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=993a9a542791953c4804f7ddbb3a07756738e37a
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=4ba4ed629ef4530fd5a60b84cf5bf7a7194f60b69068882d47c1d3c55e06fc8c
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=
+
+PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+PKG_DATA_VERSION:=20150115
+PKG_DATA_URL:=http://www.draisberghof.de/usb_modeswitch
+PKG_DATA_PATH:=usb-modeswitch-data-$(PKG_DATA_VERSION)
+PKG_DATA_FILENAME:=$(PKG_DATA_PATH).tar.bz2
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Download/data
+  FILE:=$(PKG_DATA_FILENAME)
+  URL:=$(PKG_DATA_URL)
+  MD5SUM:=662bcd56a97e560ea974bc710822de51
+endef
+$(eval $(call Download,data))
+
+define Package/usb-modeswitch
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libubox +libblobmsg-json +libusb-1.0
+  TITLE:=USB mode switching utility
+endef
+
+define Build/Prepare
+	$(Build/Prepare/Default)
+	tar xvfj $(DL_DIR)/$(PKG_DATA_FILENAME) -C $(PKG_BUILD_DIR)
+	rm -f \
+		$(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/05c6:1000:sVe=GT
+	cp ./data/* $(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/
+	#in order to keep the Lede GIT repo free of filenames with colons,
+	#we name the files xxxx-yyyy
+	# and rename here after copying to the build directory
+	for filevar in $(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/*-* ; \
+	do \
+		[ -f "$$$$filevar" ] || continue ; \
+		FILENAME=$$$$(basename $$$$filevar) ; \
+		NEWNAME=$$$${FILENAME//-/:} ; \
+		rm "$(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/$$$$NEWNAME" ; \
+		mv "$(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/$$$$FILENAME" "$(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/$$$$NEWNAME" ; \
+	done
+endef
+
+define Package/usb-modeswitch/install
+	$(INSTALL_DIR) $(1)/etc/hotplug.d/usb $(1)/etc/init.d $(1)/sbin
+	perl $(PKG_BUILD_DIR)/convert-modeswitch.pl \
+		$(PKG_BUILD_DIR)/$(PKG_DATA_PATH)/usb_modeswitch.d/* \
+		> $(1)/etc/usb-mode.json
+	$(INSTALL_DATA) ./files/usbmode.hotplug $(1)/etc/hotplug.d/usb/20-usb_mode
+	$(INSTALL_BIN) ./files/usbmode.init $(1)/etc/init.d/usbmode
+	$(CP) $(PKG_INSTALL_DIR)/usr/sbin/usbmode $(1)/sbin/
+endef
+
+$(eval $(call BuildPackage,usb-modeswitch))
diff --git a/package/utils/usbmode/data/12d1-1f16 b/package/utils/usbmode/data/12d1-1f16
new file mode 100644
index 0000000000..beda01fba9
--- /dev/null
+++ b/package/utils/usbmode/data/12d1-1f16
@@ -0,0 +1,2 @@
+# Vodafone K5150
+MBIM=1
diff --git a/package/utils/usbmode/files/usbmode.hotplug b/package/utils/usbmode/files/usbmode.hotplug
new file mode 100644
index 0000000000..b238894b1d
--- /dev/null
+++ b/package/utils/usbmode/files/usbmode.hotplug
@@ -0,0 +1 @@
+/etc/init.d/usbmode start
diff --git a/package/utils/usbmode/files/usbmode.init b/package/utils/usbmode/files/usbmode.init
new file mode 100755
index 0000000000..43e8ec564d
--- /dev/null
+++ b/package/utils/usbmode/files/usbmode.init
@@ -0,0 +1,12 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2013 OpenWrt.org
+
+START=20
+USE_PROCD=1
+
+start_service()
+{
+	procd_open_instance
+	procd_set_param command "/sbin/usbmode" -s
+	procd_close_instance
+}
diff --git a/package/utils/usbreset/Makefile b/package/utils/usbreset/Makefile
new file mode 100644
index 0000000000..5324e9d045
--- /dev/null
+++ b/package/utils/usbreset/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2011-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=usbreset
+PKG_RELEASE:=4
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/usbreset
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Utility to send a USB port reset to a USB device
+  MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
+endef
+
+define Package/usbreset/description
+ This package contains the small usbreset utility which
+ can be used to send a USB port reset to a USB device -
+ useful for debugging or to force re-detection of particular
+ devices.
+endef
+
+define Build/Compile
+	$(TARGET_CC) $(TARGET_CFLAGS) -Wall \
+		-o $(PKG_BUILD_DIR)/usbreset $(PKG_BUILD_DIR)/usbreset.c
+endef
+
+define Package/usbreset/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/usbreset $(1)/usr/bin/
+endef
+
+$(eval $(call BuildPackage,usbreset))
diff --git a/package/utils/usbreset/src/usbreset.c b/package/utils/usbreset/src/usbreset.c
new file mode 100644
index 0000000000..ead30b1d82
--- /dev/null
+++ b/package/utils/usbreset/src/usbreset.c
@@ -0,0 +1,235 @@
+/* usbreset -- send a USB port reset to a USB device */
+
+/*
+
+http://marc.info/?l=linux-usb-users&m=116827193506484&w=2
+
+and needs mounted usbfs filesystem
+
+	sudo mount -t usbfs none /proc/bus/usb
+
+There is a way to suspend a USB device.  In order to use it,
+you must have a kernel with CONFIG_PM_SYSFS_DEPRECATED turned on.  To
+suspend a device, do (as root):
+
+	echo -n 2 >/sys/bus/usb/devices/.../power/state
+
+where the "..." is the ID for your device.  To unsuspend, do the same
+thing but with a "0" instead of the "2" above.
+
+Note that this mechanism is slated to be removed from the kernel within
+the next year.  Hopefully some other mechanism will take its place.
+
+> To reset a
+> device?
+
+Here's a program to do it.  You invoke it as either
+
+	usbreset /proc/bus/usb/BBB/DDD
+or
+	usbreset /dev/usbB.D
+
+depending on how your system is set up, where BBB and DDD are the bus and
+device address numbers.
+
+Alan Stern
+
+*/
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <linux/usbdevice_fs.h>
+
+
+static char *usbfs = NULL;
+
+struct usbentry {
+	int bus_num;
+	int dev_num;
+	int vendor_id;
+	int product_id;
+	char vendor_name[128];
+	char product_name[128];
+};
+
+
+static char *sysfs_attr(const char *dev, const char *attr)
+{
+	int fd, len = 0;
+	char path[PATH_MAX];
+	static char buf[129];
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(path, sizeof(path) - 1, "/sys/bus/usb/devices/%s/%s", dev, attr);
+
+	if ((fd = open(path, O_RDONLY)) >= 0)
+	{
+		len = read(fd, buf, sizeof(buf) - 1);
+		close(fd);
+	}
+
+	while (--len > 0 && isspace(buf[len]))
+		buf[len] = 0;
+
+	return (len >= 0) ? buf : NULL;
+}
+
+static struct usbentry * parse_devlist(DIR *d)
+{
+	char *attr;
+	struct dirent *e;
+	static struct usbentry dev;
+
+	do {
+		e = readdir(d);
+
+		if (!e)
+			return NULL;
+	}
+	while(!isdigit(e->d_name[0]) || strchr(e->d_name, ':'));
+
+	memset(&dev, 0, sizeof(dev));
+
+	if ((attr = sysfs_attr(e->d_name, "busnum")) != NULL)
+		dev.bus_num = strtoul(attr, NULL, 10);
+
+	if ((attr = sysfs_attr(e->d_name, "devnum")) != NULL)
+		dev.dev_num = strtoul(attr, NULL, 10);
+
+	if ((attr = sysfs_attr(e->d_name, "idVendor")) != NULL)
+		dev.vendor_id = strtoul(attr, NULL, 16);
+
+	if ((attr = sysfs_attr(e->d_name, "idProduct")) != NULL)
+		dev.product_id = strtoul(attr, NULL, 16);
+
+	if ((attr = sysfs_attr(e->d_name, "manufacturer")) != NULL)
+		strcpy(dev.vendor_name, attr);
+
+	if ((attr = sysfs_attr(e->d_name, "product")) != NULL)
+		strcpy(dev.product_name, attr);
+
+	if (dev.bus_num && dev.dev_num && dev.vendor_id && dev.product_id)
+		return &dev;
+
+	return NULL;
+}
+
+static void list_devices(void)
+{
+	DIR *devs = opendir("/sys/bus/usb/devices");
+	struct usbentry *dev;
+
+	if (!devs)
+		return;
+
+	while ((dev = parse_devlist(devs)) != NULL)
+	{
+		printf("  Number %03d/%03d  ID %04x:%04x  %s\n",
+			   dev->bus_num, dev->dev_num,
+			   dev->vendor_id, dev->product_id,
+			   dev->product_name);
+	}
+
+	closedir(devs);
+}
+
+struct usbentry * find_device(int *bus, int *dev,
+                              int *vid, int *pid,
+                              const char *product)
+{
+	DIR *devs = opendir("/sys/bus/usb/devices");
+
+	struct usbentry *e, *match = NULL;
+
+	if (!devs)
+		return NULL;
+
+	while ((e = parse_devlist(devs)) != NULL)
+	{
+		if ((bus && (e->bus_num == *bus) && (e->dev_num == *dev)) ||
+			(vid && (e->vendor_id == *vid) && (e->product_id == *pid)) ||
+			(product && !strcasecmp(e->product_name, product)))
+		{
+			match = e;
+			break;
+		}
+	}
+
+	closedir(devs);
+
+	return match;
+}
+
+static void reset_device(struct usbentry *dev)
+{
+	int fd;
+	char path[PATH_MAX];
+
+	snprintf(path, sizeof(path) - 1, "/dev/bus/usb/%03d/%03d",
+	         dev->bus_num, dev->dev_num);
+
+	printf("Resetting %s ... ", dev->product_name);
+
+	if ((fd = open(path, O_WRONLY)) > -1)
+	{
+		if (ioctl(fd, USBDEVFS_RESET, 0) < 0)
+			printf("failed [%s]\n", strerror(errno));
+		else
+			printf("ok\n");
+
+		close(fd);
+	}
+	else
+	{
+		printf("can't open [%s]\n", strerror(errno));
+	}
+}
+
+
+int main(int argc, char **argv)
+{
+	int id1, id2;
+	struct usbentry *dev;
+
+	if ((argc == 2) && (sscanf(argv[1], "%3d/%3d", &id1, &id2) == 2))
+	{
+		dev = find_device(&id1, &id2, NULL, NULL, NULL);
+	}
+	else if ((argc == 2) && (sscanf(argv[1], "%4x:%4x", &id1, &id2) == 2))
+	{
+		dev = find_device(NULL, NULL, &id1, &id2, NULL);
+	}
+	else if ((argc == 2) && strlen(argv[1]) < 128)
+	{
+		dev = find_device(NULL, NULL, NULL, NULL, argv[1]);
+	}
+	else
+	{
+		printf("Usage:\n"
+		       "  usbreset PPPP:VVVV - reset by product and vendor id\n"
+		       "  usbreset BBB/DDD   - reset by bus and device number\n"
+		       "  usbreset \"Product\" - reset by product name\n\n"
+		       "Devices:\n");
+		list_devices();
+		return 1;
+	}
+
+	if (!dev)
+	{
+		fprintf(stderr, "No such device found\n");
+		return 1;
+	}
+
+	reset_device(dev);
+	return 0;
+}
diff --git a/package/utils/usbutils/Makefile b/package/utils/usbutils/Makefile
new file mode 100644
index 0000000000..482d4c4352
--- /dev/null
+++ b/package/utils/usbutils/Makefile
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2007-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=usbutils
+PKG_VERSION:=007
+PKG_RELEASE:=5
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/linux/utils/usb/usbutils
+PKG_MD5SUM:=7593a01724bbc0fd9fe48e62bc721ceb61c76654f1d7b231b3c65f6dfbbaefa4
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
+
+USB_IDS_VERSION:=2016-07-21
+USB_IDS_MD5SUM:=49214de0abe87ed2f1d854a38387d97ddda61bb0a4bd41b91b3deb72242dfa68
+USB_IDS_FILE:=usb.ids
+
+PKG_BUILD_PARALLEL:=1
+PKG_INSTALL:=1
+
+PKG_MAINTAINER := Felix Fietkau <nbd@nbd.name>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/usbutils
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:=+libusb-1.0 +librt +libpthread
+  TITLE:=USB devices listing utilities
+  URL:=http://www.linux-usb.org/
+endef
+
+define Download/usb_ids
+  FILE:=$(USB_IDS_FILE)
+  URL:=@GITHUB/gentoo/hwids/83b7c8958d17329ee6c0224b38e41c0bc4c66bcd
+  MD5SUM:=$(USB_IDS_MD5SUM)
+endef
+$(eval $(call Download,usb_ids))
+
+define Build/Prepare
+	$(Build/Prepare/Default)
+	$(CP) $(DL_DIR)/$(USB_IDS_FILE) $(PKG_BUILD_DIR)
+endef
+
+CONFIGURE_ARGS += \
+	--disable-zlib
+
+define Package/usbutils/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/lsusb $(1)/usr/bin/
+	$(INSTALL_DIR) $(1)/usr/share
+	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/usb.ids $(1)/usr/share/
+endef
+
+$(eval $(call BuildPackage,usbutils))
diff --git a/package/utils/util-linux/Makefile b/package/utils/util-linux/Makefile
new file mode 100644
index 0000000000..6d5f47c434
--- /dev/null
+++ b/package/utils/util-linux/Makefile
@@ -0,0 +1,701 @@
+#
+# Copyright (C) 2007-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=util-linux
+PKG_VERSION:=2.28
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/linux/utils/$(PKG_NAME)/v2.28
+PKG_MD5SUM:=e534e6ccc49107e5d31c329af798ef7d
+
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=	COPYING					\
+			getopt/COPYING				\
+			libblkid/COPYING			\
+			libmount/COPYING			\
+			Documentation/licenses/COPYING.GPLv2	\
+			Documentation/licenses/COPYING.LGPLv2.1	\
+			libuuid/COPYING				\
+			Documentation/licenses/COPYING.BSD-3
+
+PKG_BUILD_PARALLEL:=0
+
+PKG_CONFIG_DEPENDS:= \
+	CONFIG_PACKAGE_cal \
+	CONFIG_PACKAGE_cfdisk \
+	CONFIG_PACKAGE_setterm
+
+PKG_FIXUP:=autoreconf
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/util-linux/Default
+  SECTION:=utils
+  CATEGORY:=Utilities
+  DEPENDS:= +librt
+  URL:=http://www.kernel.org/pub/linux/utils/util-linux/
+endef
+
+define Package/libblkid
+$(call Package/util-linux/Default)
+  DEPENDS:=+libuuid
+  TITLE:=block device id library
+  SECTION:=libs
+  CATEGORY:=Libraries
+endef
+
+define Package/libblkid/description
+ The libblkid library is used to identify block devices (disks) as to their
+ content (e.g. filesystem type, partitions) as well as extracting additional
+ information such as filesystem labels/volume names, partitions, unique
+ identifiers/serial numbers...
+endef
+
+define Package/libfdisk
+$(call Package/util-linux/Default)
+  DEPENDS:=+libuuid +libblkid
+  TITLE:=partition manipulating library
+  SECTION:=libs
+  CATEGORY:=Libraries
+endef
+
+define Package/libfdisk/description
+  The libfdisk library is used for manipulating with partition tables.
+endef
+
+define Package/libmount
+$(call Package/util-linux/Default)
+  DEPENDS:=+libblkid
+  TITLE:=mount library
+  SECTION:=libs
+  CATEGORY:=Libraries
+endef
+
+define Package/libmount/description
+ The libmount library is used to parse /etc/fstab, /etc/mtab and
+ /proc/self/mountinfo files, manage the mtab file, evaluate mount options...
+endef
+
+define Package/libuuid
+$(call Package/util-linux/Default)
+  TITLE:=DCE compatible Universally Unique Identifier library
+  SECTION:=libs
+  CATEGORY:=Libraries
+endef
+
+define Package/libuuid/description
+ The UUID library is used to generate unique identifiers for objects
+ that may be accessible beyond the local system. This library
+ generates UUIDs compatible with those created by the Open Software
+ Foundation (OSF) Distributed Computing Environment (DCE) utility.
+endef
+
+define Package/libsmartcols
+$(call Package/util-linux/Default)
+  TITLE:=table or tree library
+  SECTION:=libs
+  CATEGORY:=Libraries
+endef
+
+define Package/libsmartcols/description
+ The smartcols library is used to print tables and trees in a pretty way.
+endef
+
+define Package/agetty
+$(call Package/util-linux/Default)
+  TITLE:=alternative Linux getty
+  SUBMENU=Terminal
+endef
+
+define Package/agetty/description
+ agetty opens a tty port, prompts for a login name and invokes the
+ /bin/login command
+endef
+
+define Package/blkdiscard
+$(call Package/util-linux/Default)
+  TITLE:=discard sectors on a device
+  SUBMENU=Disc
+endef
+
+define Package/blkdiscard/description
+ The blkdiscard is used to discard device sectors. This is useful for
+ solid-state drivers (SSDs) and thinly-provisioned storage. Unlike fstrim,
+ this command is used directly on the block device.
+endef
+
+define Package/blkid
+$(call Package/util-linux/Default)
+  TITLE:=locate and print block device attributes
+  DEPENDS:= +libblkid +libuuid
+  SUBMENU=Disc
+endef
+
+define Package/blkid/description
+ The blkid program is the command-line interface to working with the libblkid
+ library.
+endef
+
+define Package/cal
+$(call Package/util-linux/Default)
+  TITLE:=display a calendar
+  DEPENDS:= +libncurses
+endef
+
+define Package/cal/description
+ cal displays a simple calendar
+endef
+
+define Package/cfdisk
+$(call Package/util-linux/Default)
+  TITLE:=display or manipulate disk partition table
+  DEPENDS:= +libblkid +libncurses +libsmartcols +libfdisk +libmount
+  SUBMENU:=Disc
+endef
+
+define Package/cfdisk/description
+ cfdisk is a curses-based program for partitioning any hard disk drive
+endef
+
+define Package/dmesg
+$(call Package/util-linux/Default)
+  TITLE:=print or control the kernel ring buffer
+endef
+
+define Package/dmesg/description
+ dmesg  is used to examine or control the kernel ring buffer
+endef
+
+define Package/fdisk
+$(call Package/util-linux/Default)
+  TITLE:=manipulate disk partition table
+  DEPENDS:= +libblkid +libsmartcols +libfdisk
+  SUBMENU=Disc
+endef
+
+define Package/fdisk/description
+ a menu-driven program for creation and manipulation of partition tables
+endef
+
+define Package/findfs
+$(call Package/util-linux/Default)
+  TITLE:=find a filesystem by label or UUID
+  DEPENDS:= +libblkid
+  SUBMENU=Disc
+endef
+
+define Package/findfs/description
+ findfs will search the disks in the system looking for a filesystem which has
+ a label matching label or a UUID equal to uuid
+endef
+
+define Package/flock
+$(call Package/util-linux/Default)
+  TITLE:=manage locks from shell scripts
+endef
+
+define Package/flock/description
+  manages flock locks from within shell scripts or the command line
+endef
+
+define Package/getopt
+$(call Package/util-linux/Default)
+  TITLE:=parse command options (enhanced)
+endef
+
+define Package/getopt/description
+ getopt is used to break up (parse) options in command lines for easy parsing
+ by shell procedures, and to check for legal options
+endef
+
+define Package/hwclock
+$(call Package/util-linux/Default)
+  TITLE:=query or set the hardware clock
+endef
+
+define Package/hwclock/description
+ hwclock is a tool for accessing the Hardware Clock
+endef
+
+define Package/logger
+$(call Package/util-linux/Default)
+  TITLE:=a shell command interface to the syslog system log module
+endef
+
+define Package/logger/description
+ logger makes entries in the system log, it provides a shell command interface
+ to the syslog system log module
+endef
+
+define Package/look
+$(call Package/util-linux/Default)
+  TITLE:=display lines beginning with a given string
+endef
+
+define Package/look/description
+ look utility displays any lines in file which contain string
+endef
+
+define Package/losetup
+$(call Package/util-linux/Default)
+  TITLE:=set up and control loop devices
+  DEPENDS:= +libsmartcols
+endef
+
+define Package/losetup/description
+ losetup is used to associate loop devices with regular files or block devices,
+ to detach loop devices and to query the status of a loop device
+endef
+
+define Package/lsblk
+$(call Package/util-linux/Default)
+  TITLE:=list block devices
+  DEPENDS:= +libblkid +libmount +libsmartcols
+  SUBMENU=Disc
+endef
+
+define Package/lsblk/description
+ lsblk lists information about all or the specified block devices
+endef
+
+define Package/mcookie
+$(call Package/util-linux/Default)
+  TITLE:=generate magic cookies for xauth
+endef
+
+define Package/mcookie/description
+ mcookie generates a 128-bit random hexadecimal number for use with the X
+ authority system
+endef
+
+define Package/mount-utils
+$(call Package/util-linux/Default)
+  TITLE:=related (u)mount utilities
+  DEPENDS+= +libmount +libsmartcols
+endef
+
+define Package/mount-utils/description
+ contains: mount, umount, findmnt
+endef
+
+define Package/namei
+$(call Package/util-linux/Default)
+  TITLE:=follow a pathname until a terminal point is found
+endef
+
+define Package/namei/description
+ namei uses its arguments as pathnames to any type of Unix file (symlinks,
+ files, directories, and so forth)
+endef
+
+define Package/prlimit
+$(call Package/util-linux/Default)
+  TITLE:=get and set process resource limits
+  DEPENDS:= +libsmartcols
+endef
+
+define Package/prlimit/description
+  Given a process id and one or more resources, prlimit tries to retrieve
+  and/or modify the limits.
+endef
+
+define Package/rename
+$(call Package/util-linux/Default)
+  TITLE:=rename files
+endef
+
+define Package/rename/description
+ rename will rename the specified files by replacing the first occurrence of
+ expression in their name by replacement
+endef
+
+define Package/partx-utils
+$(call Package/util-linux/Default)
+  TITLE:=inform kernel about the presence and numbering of on-disk partitions
+  DEPENDS:= +libblkid +libsmartcols
+  SUBMENU=Disc
+endef
+
+define Package/partx-utils/description
+ contains partx, addpart, delpart
+endef
+
+define Package/script-utils
+$(call Package/util-linux/Default)
+  TITLE:=make and replay typescript of terminal session
+  SUBMENU=Terminal
+endef
+
+define Package/script-utils/description
+ contains: script, scriptreplay
+endef
+
+define Package/setterm
+$(call Package/util-linux/Default)
+  TITLE:=set terminal attributes
+  DEPENDS:= +libncurses
+  SUBMENU:=Terminal
+endef
+
+define Package/setterm/description
+ setterm writes to standard output a character string that will invoke the
+ specified terminal capabilities
+endef
+
+define Package/sfdisk
+$(call Package/util-linux/Default)
+  TITLE:=partition table manipulator for Linux
+  SUBMENU=Disc
+  DEPENDS:= +libblkid +libfdisk +libsmartcols
+endef
+
+define Package/sfdisk/description
+ list the size of a partition, list the partitions on a device, check the
+ partitions on a device and repartition a device
+endef
+
+define Package/swap-utils
+$(call Package/util-linux/Default)
+  TITLE:=swap space management utilities
+  DEPENDS+= +libblkid
+  SUBMENU:=Filesystem
+endef
+
+define Package/swap-utils/description
+ contains: mkswap, swaplabel
+endef
+
+define Package/uuidd
+$(call Package/util-linux/Default)
+  TITLE:=UUID generation daemon
+  DEPENDS:= +libuuid
+endef
+
+define Package/uuidd/description
+ The uuidd daemon is used by the UUID library to generate universally unique
+ identifiers (UUIDs), especially time-based UUIDs, in a secure and
+ guaranteed-unique fashion, even in the face of large numbers of threads
+ running on different CPUs trying to grab UUIDs.
+endef
+
+define Package/uuidgen
+$(call Package/util-linux/Default)
+  TITLE:=create a new UUID value
+  DEPENDS:= +libuuid
+endef
+
+define Package/uuidgen/description
+ The uuidgen program creates (and prints) a new universally unique identifier
+ (UUID) using the libuuid library. The new UUID can reasonably be considered
+ unique among all UUIDs created on the local system, and among UUIDs created on
+ other systems in the past and in the future.
+endef
+
+define Package/wall
+$(call Package/util-linux/Default)
+  TITLE:=send a message to everybody's terminal
+  SUBMENU=Terminal
+endef
+
+define Package/wall/description
+ wall sends a message to everybody logged in with their mesg permission
+ set to yes
+endef
+
+define Package/whereis
+$(call Package/util-linux/Default)
+  TITLE:=locate the binary, source, and manual page files for a command
+endef
+
+define Package/whereis/description
+ whereis locates source/binary and manuals sections for specified files
+endef
+
+define Package/wipefs
+$(call Package/util-linux/Default)
+  TITLE:=wipe a signature from a device
+  DEPENDS:= +libblkid
+  SUBMENU:=Disc
+endef
+
+define Package/wipefs/description
+ wipefs can erase filesystem, raid or partition table signatures (magic
+ strings) from the specified device to make the signature invisible for
+ libblkid.
+endef
+
+CONFIGURE_ARGS += \
+	--disable-use-tty-group \
+	--disable-rpath \
+	--disable-tls		\
+	--disable-sulogin	\
+	--without-python	\
+	--without-udev		\
+	--without-readline	\
+	$(if $(CONFIG_PACKAGE_cal)$(CONFIG_PACKAGE_cfdisk)$(CONFIG_PACKAGE_setterm),--with-ncurses,--without-ncurses)
+
+TARGET_CFLAGS += $(FPIC) -std=gnu99
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/blkid.pc $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/fdisk.pc $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/mount.pc $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/smartcols.pc $(1)/usr/lib/pkgconfig
+	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/uuid.pc $(1)/usr/lib/pkgconfig
+
+	$(INSTALL_DIR) $(1)/usr/include/blkid
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/blkid/blkid.h $(1)/usr/include/blkid
+	$(INSTALL_DIR) $(1)/usr/include/libfdisk
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libfdisk/libfdisk.h $(1)/usr/include/libfdisk
+	$(INSTALL_DIR) $(1)/usr/include/libmount
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libmount/libmount.h $(1)/usr/include/libmount
+	$(INSTALL_DIR) $(1)/usr/include/uuid
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/uuid/uuid.h $(1)/usr/include/uuid
+	$(INSTALL_DIR) $(1)/usr/include/libsmartcols
+	$(CP) $(PKG_INSTALL_DIR)/usr/include/libsmartcols/libsmartcols.h $(1)/usr/include/libsmartcols
+
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libblkid.so* $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libfdisk.so* $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libmount.so* $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libuuid.so* $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libsmartcols.so* $(1)/usr/lib
+
+	$(LN) libblkid.so.1 $(1)/usr/lib/libblkid.so
+	$(LN) libfdisk.so.1 $(1)/usr/lib/libfdisk.so
+	$(LN) libmount.so.1 $(1)/usr/lib/libmount.so
+	$(LN) libuuid.so.1 $(1)/usr/lib/libuuid.so
+	$(LN) libsmartcols.so.1 $(1)/usr/lib/libsmartcols.so
+endef
+
+
+define Package/libfdisk/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libfdisk.so* $(1)/usr/lib/
+	$(LN) libfdisk.so.1 $(1)/usr/lib/libfdisk.so
+endef
+
+define Package/libblkid/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libblkid.so* $(1)/usr/lib/
+	$(LN) libblkid.so.1 $(1)/usr/lib/libblkid.so
+endef
+
+define Package/libmount/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libmount.so* $(1)/usr/lib/
+	$(LN) libmount.so.1 $(1)/usr/lib/libmount.so
+endef
+
+define Package/libsmartcols/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libsmartcols.so* $(1)/usr/lib/
+	$(LN) libsmartcols.so.1 $(1)/usr/lib/libsmartcols.so
+endef
+
+define Package/libuuid/install
+	$(INSTALL_DIR) $(1)/usr/lib
+	$(CP) $(PKG_INSTALL_DIR)/lib/libuuid.so* $(1)/usr/lib/
+	$(LN) libuuid.so.1 $(1)/usr/lib/libuuid.so
+endef
+
+define Package/agetty/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/agetty $(1)/usr/sbin/
+endef
+
+define Package/blkdiscard/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/blkdiscard $(1)/usr/sbin/
+endef
+
+define Package/blkid/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/blkid $(1)/usr/sbin/
+endef
+
+define Package/cal/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/cal $(1)/usr/bin/
+endef
+
+define Package/cfdisk/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/cfdisk $(1)/usr/sbin/
+endef
+
+define Package/dmesg/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dmesg $(1)/usr/bin/
+endef
+
+define Package/fdisk/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/fdisk $(1)/usr/sbin/
+endef
+
+define Package/findfs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/findfs $(1)/usr/sbin/
+endef
+
+define Package/flock/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/flock $(1)/usr/bin/
+endef
+
+define Package/getopt/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/getopt $(1)/usr/bin/
+endef
+
+define Package/hwclock/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/hwclock $(1)/usr/sbin/
+endef
+
+define Package/logger/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/logger $(1)/usr/bin/
+endef
+
+define Package/look/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/look $(1)/usr/bin/
+endef
+
+define Package/losetup/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/losetup $(1)/usr/sbin/
+endef
+
+define Package/lsblk/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/lsblk $(1)/usr/bin/
+endef
+
+define Package/mcookie/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/mcookie $(1)/usr/bin/
+endef
+
+define Package/mount-utils/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/{u,}mount $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/mountpoint $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/findmnt $(1)/usr/bin/
+endef
+
+define Package/namei/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/namei $(1)/usr/bin/
+endef
+
+define Package/prlimit/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/prlimit $(1)/usr/bin/
+endef
+
+define Package/rename/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/rename $(1)/usr/bin/
+endef
+
+define Package/partx-utils/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/partx $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/addpart $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/delpart $(1)/usr/sbin/
+endef
+
+define Package/script-utils/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/script $(1)/usr/bin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/scriptreplay $(1)/usr/bin/
+endef
+
+define Package/setterm/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/setterm $(1)/usr/bin/
+endef
+
+define Package/sfdisk/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/sfdisk $(1)/usr/sbin/
+endef
+
+define Package/swap-utils/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/mkswap $(1)/usr/sbin/
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/swaplabel $(1)/usr/sbin/
+endef
+
+define Package/uuidd/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin//uuidd $(1)/usr/sbin/
+endef
+
+define Package/uuidgen/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin//uuidgen $(1)/usr/bin/
+endef
+
+define Package/wall/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/wall $(1)/usr/bin/
+endef
+
+define Package/whereis/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/whereis $(1)/usr/bin/
+endef
+
+define Package/wipefs/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/wipefs $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,libblkid))
+$(eval $(call BuildPackage,libfdisk))
+$(eval $(call BuildPackage,libmount))
+$(eval $(call BuildPackage,libsmartcols))
+$(eval $(call BuildPackage,libuuid))
+$(eval $(call BuildPackage,agetty))
+$(eval $(call BuildPackage,blkdiscard))
+$(eval $(call BuildPackage,blkid))
+$(eval $(call BuildPackage,cal))
+$(eval $(call BuildPackage,cfdisk))
+$(eval $(call BuildPackage,dmesg))
+$(eval $(call BuildPackage,fdisk))
+$(eval $(call BuildPackage,findfs))
+$(eval $(call BuildPackage,flock))
+$(eval $(call BuildPackage,getopt))
+$(eval $(call BuildPackage,hwclock))
+$(eval $(call BuildPackage,logger))
+$(eval $(call BuildPackage,look))
+$(eval $(call BuildPackage,losetup))
+$(eval $(call BuildPackage,lsblk))
+$(eval $(call BuildPackage,mcookie))
+$(eval $(call BuildPackage,mount-utils))
+$(eval $(call BuildPackage,namei))
+$(eval $(call BuildPackage,prlimit))
+$(eval $(call BuildPackage,rename))
+$(eval $(call BuildPackage,partx-utils))
+$(eval $(call BuildPackage,script-utils))
+$(eval $(call BuildPackage,setterm))
+$(eval $(call BuildPackage,sfdisk))
+$(eval $(call BuildPackage,swap-utils))
+$(eval $(call BuildPackage,uuidd))
+$(eval $(call BuildPackage,uuidgen))
+$(eval $(call BuildPackage,wall))
+$(eval $(call BuildPackage,whereis))
+$(eval $(call BuildPackage,wipefs))
diff --git a/package/utils/util-linux/patches/0001-fix-uClibc-ng-scanf-check.patch b/package/utils/util-linux/patches/0001-fix-uClibc-ng-scanf-check.patch
new file mode 100644
index 0000000000..2da95f6cdb
--- /dev/null
+++ b/package/utils/util-linux/patches/0001-fix-uClibc-ng-scanf-check.patch
@@ -0,0 +1,34 @@
+From 180c908e2e80552b19bf3552667fc197d6edf7b3 Mon Sep 17 00:00:00 2001
+From: Waldemar Brodkorb <wbx@uclibc-ng.org>
+Date: Fri, 3 Jun 2016 04:13:08 +0200
+Subject: [PATCH] fix uClibc-ng scanf check
+
+uClibc-ng tries to be compatible with GNU libc and defines
+__GLIBC__ and pretend to be version 2.2.
+We once changed it to 2.10, but then some hard to fix problems
+in different software packages (gcc) occured.
+It would be better if we disable the special GNU libc checks
+for uClibc-ng here. uClibc-ng implements the required scanf
+functionality.
+
+Signed-off-by: Waldemar Brodkorb <wbx@uclibc-ng.org>
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index f36b18c..4661c0d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -581,7 +581,7 @@ AC_CACHE_VAL([scanf_cv_alloc_modifier],
+      #include <stdio.h>
+      #include <unistd.h>
+ 
+-     #ifdef __GLIBC__
++     #if defined(__GLIBC__) && !defined(__UCLIBC__)
+ 
+      #if !(__GLIBC_PREREQ(2, 7))
+      #error %m is not available
+-- 
+2.1.4
+
diff --git a/package/utils/util-linux/patches/003-fix_pkgconfig_files.patch b/package/utils/util-linux/patches/003-fix_pkgconfig_files.patch
new file mode 100644
index 0000000000..cc9cd11188
--- /dev/null
+++ b/package/utils/util-linux/patches/003-fix_pkgconfig_files.patch
@@ -0,0 +1,76 @@
+--- a/libuuid/Makemodule.am
++++ b/libuuid/Makemodule.am
+@@ -4,7 +4,6 @@ include libuuid/man/Makemodule.am
+ include libuuid/src/Makemodule.am
+ 
+ pkgconfig_DATA += libuuid/uuid.pc
+-PATHFILES      += libuuid/uuid.pc
+ EXTRA_DIST     += libuuid/COPYING
+ 
+ endif # BUILD_LIBUUID
+--- a/configure.ac
++++ b/configure.ac
+@@ -2122,18 +2122,23 @@ AC_CONFIG_HEADERS([config.h])
+ #
+ AC_CONFIG_FILES([
+ Makefile
++libblkid/blkid.pc
+ libblkid/docs/Makefile
+ libblkid/docs/version.xml
+ libblkid/src/blkid.h
++libfdisk/fdisk.pc
+ libfdisk/docs/Makefile
+ libfdisk/docs/version.xml
+ libfdisk/src/libfdisk.h
++libmount/mount.pc
+ libmount/docs/Makefile
+ libmount/docs/version.xml
+ libmount/src/libmount.h
++libsmartcols/smartcols.pc
+ libsmartcols/docs/Makefile
+ libsmartcols/docs/version.xml
+ libsmartcols/src/libsmartcols.h
++libuuid/uuid.pc
+ po/Makefile.in
+ ])
+ 
+--- a/libblkid/Makemodule.am
++++ b/libblkid/Makemodule.am
+@@ -9,7 +9,6 @@ SUBDIRS += libblkid/docs
+ endif
+ 
+ pkgconfig_DATA += libblkid/blkid.pc
+-PATHFILES      += libblkid/blkid.pc
+ dist_man_MANS  += libblkid/libblkid.3
+ EXTRA_DIST     += libblkid/libblkid.3 libblkid/COPYING
+ 
+--- a/libmount/Makemodule.am
++++ b/libmount/Makemodule.am
+@@ -9,7 +9,6 @@ SUBDIRS += libmount/docs
+ endif
+ 
+ pkgconfig_DATA += libmount/mount.pc
+-PATHFILES      += libmount/mount.pc
+ EXTRA_DIST     += libmount/COPYING
+ 
+ endif # BUILD_LIBMOUNT
+--- a/libsmartcols/Makemodule.am
++++ b/libsmartcols/Makemodule.am
+@@ -9,7 +9,6 @@ SUBDIRS += libsmartcols/docs
+ endif
+ 
+ pkgconfig_DATA += libsmartcols/smartcols.pc
+-PATHFILES      += libsmartcols/smartcols.pc
+ EXTRA_DIST     += libsmartcols/COPYING
+ 
+ endif # BUILD_LIBSMARTCOLS
+--- a/libfdisk/Makemodule.am
++++ b/libfdisk/Makemodule.am
+@@ -8,7 +8,6 @@ SUBDIRS += libfdisk/docs
+ endif
+ 
+ pkgconfig_DATA += libfdisk/fdisk.pc
+-PATHFILES      += libfdisk/fdisk.pc
+ EXTRA_DIST     += libfdisk/COPYING
+ 
+ endif # BUILD_LIBFDISK
diff --git a/package/utils/xfsprogs/Makefile b/package/utils/xfsprogs/Makefile
new file mode 100644
index 0000000000..cd9d5f9d38
--- /dev/null
+++ b/package/utils/xfsprogs/Makefile
@@ -0,0 +1,89 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=xfsprogs
+PKG_RELEASE:=1
+PKG_VERSION:=3.1.7
+PKG_SOURCE_URL:=ftp://oss.sgi.com/projects/xfs/previous/
+PKG_MD5SUM:=049cf9873794ea49d0bb3f12d45748a4
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_INSTALL:=1
+PKG_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/nls.mk
+
+define Package/xfsprogs/default
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Filesystem
+  DEPENDS:=+libuuid +libpthread +librt
+  URL:=http://oss.sgi.com/projects/xfs
+endef
+
+define Package/xfs-mkfs
+$(call Package/xfsprogs/default)
+  TITLE:=Utility for creating XFS filesystems
+endef
+
+define Package/xfs-fsck
+$(call Package/xfsprogs/default)
+  TITLE:=Utilities for checking and repairing XFS filesystems
+endef
+
+define Package/xfs-growfs
+$(call Package/xfsprogs/default)
+  TITLE:=Utility for increasing the size of XFS filesystems
+endef
+
+CONFIGURE_ARGS += \
+	--enable-gettext=no \
+	--enable-lib64=no \
+	--enable-blkid=no
+
+TARGET_CFLAGS += \
+	-I$(STAGING_DIR)/usr/include \
+	-D_LARGEFILE64_SOURCE \
+	-D_FILE_OFFSET_BITS=64 \
+	-D_GNU_SOURCE
+
+MAKE_FLAGS += \
+	DEBUG= Q= \
+	PCFLAGS="-Wall" \
+	PKG_PLATFORM=linux \
+	ENABLE_GETTEXT=no \
+	prefix=$(PKG_INSTALL_DIR)/usr \
+	exec_prefix=$(PKG_INSTALL_DIR)/usr \
+	PKG_SBIN_DIR=$(PKG_INSTALL_DIR)/usr/sbin \
+	PKG_ROOT_SBIN_DIR=$(PKG_INSTALL_DIR)/sbin \
+	PKG_MAN_DIR=$(PKG_INSTALL_DIR)/usr/man \
+	PKG_LOCALE_DIR=$(PKG_INSTALL_DIR)/usr/share/locale \
+	PKG_ROOT_LIB_DIR=$(PKG_INSTALL_DIR)/lib \
+	PKG_DOC_DIR=$(PKG_INSTALL_DIR)/usr/share/doc/xfsprogs
+
+define Package/xfs-mkfs/install
+	mkdir -p $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/sbin/mkfs.xfs $(1)/usr/sbin
+endef
+
+define Package/xfs-fsck/install
+	mkdir -p $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/sbin/xfs_repair $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/xfs_db $(1)/usr/sbin
+endef
+
+define Package/xfs-growfs/install
+	mkdir -p $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/xfs_growfs $(1)/usr/sbin
+endef
+
+$(eval $(call BuildPackage,xfs-mkfs))
+$(eval $(call BuildPackage,xfs-fsck))
+$(eval $(call BuildPackage,xfs-growfs))
diff --git a/package/utils/xfsprogs/patches/001-automake-compat.patch b/package/utils/xfsprogs/patches/001-automake-compat.patch
new file mode 100644
index 0000000000..ce9289a4af
--- /dev/null
+++ b/package/utils/xfsprogs/patches/001-automake-compat.patch
@@ -0,0 +1,78 @@
+commit 2222aa77e11b959e0e5a0ded3482e56799593bc2
+Author: Jens Muecke <jens@nons.de>
+Date:   Thu Jan 26 00:34:15 2012 +0100
+
+    001-automake-compat
+
+--- a/configure.in
++++ b/configure.in
+@@ -2,7 +2,8 @@ AC_INIT(include/libxfs.h)
+ AC_PREREQ(2.50)
+ AC_CONFIG_AUX_DIR([.])
+ AC_CONFIG_MACRO_DIR([m4])
+-AC_CONFIG_HEADER(include/platform_defs.h)
++# Put a dummy here (http://www.mail-archive.com/automake@gnu.org/msg09241.html)
++AC_CONFIG_HEADERS([doesnotexist.h include/platform_defs.h])
+ AC_PREFIX_DEFAULT(/usr)
+ 
+ AC_PROG_LIBTOOL
+--- a/include/builddefs.in
++++ b/include/builddefs.in
+@@ -20,6 +20,8 @@
+ ifndef _BUILDDEFS_INCLUDED_
+ _BUILDDEFS_INCLUDED_ = 1
+ 
++SHELL = @SHELL@
++
+ DEBUG = @debug_build@
+ OPTIMIZER = @opt_build@
+ MALLOCLIB = @malloc_lib@
+--- a/m4/package_types.m4
++++ b/m4/package_types.m4
+@@ -9,7 +9,7 @@ AC_DEFUN([AC_TYPE_PSINT],
+ #include <stddef.h>
+     ], [
+          __psint_t  psint;
+-    ], AC_DEFINE(HAVE___PSINT_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no))
++    ], AC_DEFINE([HAVE___PSINT_T], [1], [Define if __psint_t exists]) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no))
+   ])
+ 
+ # 
+@@ -23,7 +23,7 @@ AC_DEFUN([AC_TYPE_PSUNSIGNED],
+ #include <stddef.h>
+     ], [
+         __psunsigned_t  psuint;
+-    ], AC_DEFINE(HAVE___PSUNSIGNED_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no))
++    ], AC_DEFINE([HAVE___PSUNSIGNED_T], [1], [Define if __psunsigned_t exists]) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no))
+   ])
+ 
+ # 
+@@ -37,7 +37,7 @@ AC_DEFUN([AC_TYPE_U32],
+ #include <stddef.h>
+     ], [
+          __u32  u32;
+-    ], AC_DEFINE(HAVE___U32) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no))
++    ], AC_DEFINE([HAVE___U32], [1], [Define if __u32 exists]) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no))
+   ])
+ 
+ # 
+@@ -50,15 +50,15 @@ AC_DEFUN([AC_SIZEOF_POINTERS_AND_LONG],
+     AC_CHECK_SIZEOF(long, 4)
+     AC_CHECK_SIZEOF(char *, 4)
+     if test $ac_cv_sizeof_long -eq 4 -o $ac_cv_sizeof_long -eq 0; then
+-      AC_DEFINE(HAVE_32BIT_LONG)
++      AC_DEFINE([HAVE_32BIT_LONG], [1], [Define if long is 32bit])
+     fi
+     if test $ac_cv_sizeof_long -eq 8; then
+-      AC_DEFINE(HAVE_64BIT_LONG)
++      AC_DEFINE([HAVE_64BIT_LONG], [1], [Define if long is 64bit])
+     fi
+     if test $ac_cv_sizeof_char_p -eq 4 -o $ac_cv_sizeof_char_p -eq 0; then
+-      AC_DEFINE(HAVE_32BIT_PTR)
++      AC_DEFINE([HAVE_32BIT_PTR], [1], [Define if char* is 32bit])
+     fi
+     if test $ac_cv_sizeof_char_p -eq 8; then
+-      AC_DEFINE(HAVE_64BIT_PTR)
++      AC_DEFINE([HAVE_64BIT_PTR], [1], [Define if char* is 64bit])
+     fi
+   ])
diff --git a/package/utils/xfsprogs/patches/100-no_aio.patch b/package/utils/xfsprogs/patches/100-no_aio.patch
new file mode 100644
index 0000000000..4cc85d7deb
--- /dev/null
+++ b/package/utils/xfsprogs/patches/100-no_aio.patch
@@ -0,0 +1,19 @@
+commit e72b7bd12fdef06c3494b919376bfe886aa8bb4d
+Author: Jens Muecke <jens@nons.de>
+Date:   Thu Jan 26 00:35:43 2012 +0100
+
+    100-no_aio
+
+--- a/configure.in
++++ b/configure.in
+@@ -92,8 +92,8 @@ AC_PACKAGE_GLOBALS(xfsprogs)
+ AC_PACKAGE_UTILITIES(xfsprogs)
+ AC_MULTILIB($enable_lib64)
+ 
+-AC_PACKAGE_NEED_AIO_H
+-AC_PACKAGE_NEED_LIO_LISTIO
++librt="-lrt"
++AC_SUBST(librt)
+ 
+ AC_PACKAGE_NEED_UUID_H
+ AC_PACKAGE_NEED_UUIDCOMPARE
diff --git a/package/utils/xfsprogs/patches/110-uclibc_no_ustat.patch b/package/utils/xfsprogs/patches/110-uclibc_no_ustat.patch
new file mode 100644
index 0000000000..5d5d08c8d6
--- /dev/null
+++ b/package/utils/xfsprogs/patches/110-uclibc_no_ustat.patch
@@ -0,0 +1,32 @@
+commit 7b1d0a98e779170232c0a81b4749ab934ec67a7e
+Author: Jens Muecke <jens@nons.de>
+Date:   Thu Jan 26 00:36:42 2012 +0100
+
+    110-uclibc_no_ustat
+
+--- a/libxfs/linux.c
++++ b/libxfs/linux.c
+@@ -21,7 +21,6 @@
+ #include <mntent.h>
+ #include <sys/stat.h>
+ #undef ustat
+-#include <sys/ustat.h>
+ #include <sys/mount.h>
+ #include <sys/ioctl.h>
+ #include <sys/sysinfo.h>
+@@ -49,6 +48,7 @@ static int max_block_alignment;
+ int
+ platform_check_ismounted(char *name, char *block, struct stat64 *s, int verbose)
+ {
++#if 0
+ 	/* Pad ust; pre-2.6.28 linux copies out too much in 32bit compat mode */
+ 	struct ustat	ust[2];
+ 	struct stat64	st;
+@@ -68,6 +68,7 @@ platform_check_ismounted(char *name, cha
+ 				progname, name);
+ 		return 1;
+ 	}
++#endif
+ 	return 0;
+ }
+ 
diff --git a/package/utils/xfsprogs/patches/120-portability.patch b/package/utils/xfsprogs/patches/120-portability.patch
new file mode 100644
index 0000000000..1d5905a67d
--- /dev/null
+++ b/package/utils/xfsprogs/patches/120-portability.patch
@@ -0,0 +1,45 @@
+commit d2aef8b3967e53fe58178f5af50fef488ee0faed
+Author: Jens Muecke <jens@nons.de>
+Date:   Thu Jan 26 00:37:52 2012 +0100
+
+    120-portability
+
+--- a/copy/xfs_copy.c
++++ b/copy/xfs_copy.c
+@@ -463,6 +463,15 @@ read_ag_header(int fd, xfs_agnumber_t ag
+ }
+ 
+ 
++static void sig_mask(int type)
++{
++	sigset_t mask;
++	sigemptyset(&mask);
++	sigaddset(&mask, SIGCHLD);
++	sigprocmask(type, &mask, NULL);
++}
++
++
+ void
+ write_wbuf(void)
+ {
+@@ -478,9 +487,9 @@ write_wbuf(void)
+ 		if (target[i].state != INACTIVE)
+ 			pthread_mutex_unlock(&targ[i].wait);	/* wake up */
+ 
+-	sigrelse(SIGCHLD);
++	sig_mask(SIG_UNBLOCK);
+ 	pthread_mutex_lock(&mainwait);
+-	sighold(SIGCHLD);
++	sig_mask(SIG_BLOCK);
+ }
+ 
+ 
+@@ -847,7 +856,7 @@ main(int argc, char **argv)
+ 	/* set up sigchild signal handler */
+ 
+ 	signal(SIGCHLD, handler);
+-	sighold(SIGCHLD);
++	sig_mask(SIG_BLOCK);
+ 
+ 	/* make children */
+ 
diff --git a/package/utils/xfsprogs/patches/130-uclibc_no_xattr.patch b/package/utils/xfsprogs/patches/130-uclibc_no_xattr.patch
new file mode 100644
index 0000000000..c5c4a2a2ad
--- /dev/null
+++ b/package/utils/xfsprogs/patches/130-uclibc_no_xattr.patch
@@ -0,0 +1,32 @@
+commit 10d6058b24f18cb31889154f830b191849f45106
+Author: Jens Muecke <jens@nons.de>
+Date:   Thu Jan 26 00:38:27 2012 +0100
+
+    130-uclibc_no_xattr
+
+--- a/fsr/xfs_fsr.c
++++ b/fsr/xfs_fsr.c
+@@ -35,7 +35,6 @@
+ #include <sys/wait.h>
+ #include <sys/vfs.h>
+ #include <sys/statvfs.h>
+-#include <sys/xattr.h>
+ 
+ 
+ #ifndef XFS_XFLAG_NODEFRAG
+@@ -990,6 +989,7 @@ fsr_setup_attr_fork(
+ 	int		tfd,
+ 	xfs_bstat_t	*bstatp)
+ {
++#if 0
+ 	struct stat64	tstatbuf;
+ 	int		i;
+ 	int		last_forkoff = 0;
+@@ -1108,6 +1108,7 @@ fsr_setup_attr_fork(
+ out:
+ 	if (dflag)
+ 		fsrprintf(_("set temp attr\n"));
++#endif
+ 	return 0;
+ }
+ 
diff --git a/package/utils/xfsprogs/patches/140-no_po.patch b/package/utils/xfsprogs/patches/140-no_po.patch
new file mode 100644
index 0000000000..6407744536
--- /dev/null
+++ b/package/utils/xfsprogs/patches/140-no_po.patch
@@ -0,0 +1,19 @@
+--- a/Makefile
++++ b/Makefile
+@@ -41,7 +41,7 @@ endif
+ 
+ LIB_SUBDIRS = libxfs libxlog libxcmd libhandle libdisk
+ TOOL_SUBDIRS = copy db estimate fsck fsr growfs io logprint mkfs quota \
+-		mdrestore repair rtcp m4 man doc po debian
++		mdrestore repair rtcp m4 man doc debian
+ 
+ SUBDIRS = include $(LIB_SUBDIRS) $(TOOL_SUBDIRS)
+ 
+@@ -135,7 +135,6 @@ ifeq ($(HAVE_BUILDDEFS), no)
+ 	$(Q)$(MAKE) $(MAKEOPTS) -C . $@
+ else
+ 	$(Q)$(MAKE) $(MAKEOPTS) $(SRCDIR)
+-	$(Q)$(MAKE) $(MAKEOPTS) -C po
+ 	$(Q)$(MAKE) $(MAKEOPTS) source-link
+ 	$(Q)cd $(SRCDIR) && dpkg-buildpackage
+ endif
diff --git a/package/utils/xfsprogs/patches/150-include_fixes.patch b/package/utils/xfsprogs/patches/150-include_fixes.patch
new file mode 100644
index 0000000000..793622a160
--- /dev/null
+++ b/package/utils/xfsprogs/patches/150-include_fixes.patch
@@ -0,0 +1,72 @@
+--- a/libhandle/handle.c
++++ b/libhandle/handle.c
+@@ -20,6 +20,7 @@
+ #include <xfs/xfs.h>
+ #include <xfs/handle.h>
+ #include <xfs/parent.h>
++#include <linux/limits.h>
+ 
+ /* just pick a value we know is more than big enough */
+ #define	MAXHANSIZ	64
+--- a/libhandle/jdm.c
++++ b/libhandle/jdm.c
+@@ -20,6 +20,7 @@
+ #include <xfs/handle.h>
+ #include <xfs/jdm.h>
+ #include <xfs/parent.h>
++#include <linux/limits.h>
+ 
+ /* internal fshandle - typecast to a void for external use */
+ #define FSHANDLE_SZ		8
+--- a/libdisk/evms.c
++++ b/libdisk/evms.c
+@@ -22,6 +22,7 @@
+ #include <fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/sysmacros.h>
++#include <sys/stat.h>
+ #include <disk/volume.h>
+ #include "evms.h"
+ 
+--- a/libdisk/evms.h
++++ b/libdisk/evms.h
+@@ -16,6 +16,8 @@
+  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  */
+ 
++#include <sys/types.h>
++
+ #define EVMS_MAJOR			117
+ #define EVMS_GET_VOL_STRIPE_INFO	\
+ 		_IOR(EVMS_MAJOR, 0xF0, struct evms_vol_stripe_info_s)
+--- a/libdisk/fstype.h
++++ b/libdisk/fstype.h
+@@ -192,7 +192,7 @@ struct adfs_super_block {
+ 	char    s_dummy2[62];
+ 	char    s_checksum[1];
+ };
+-#define adfsblksize(s)	((uint) s.s_blksize[0])
++#define adfsblksize(s)	((unsigned int) s.s_blksize[0])
+ 
+ /* found in first 4 bytes of block 1 */
+ struct vxfs_super_block {
+--- a/fsr/xfs_fsr.c
++++ b/fsr/xfs_fsr.c
+@@ -25,6 +25,7 @@
+ #include <xfs/xfs_dinode.h>
+ #include <xfs/xfs_attr_sf.h>
+ 
++#include <paths.h>
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <malloc.h>
+--- a/libdisk/xvm.c
++++ b/libdisk/xvm.c
+@@ -22,6 +22,7 @@
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
++#include <sys/types.h>
+ #include <disk/volume.h>
+ #include "xvm.h"
+ 
diff --git a/package/utils/xfsprogs/patches/160-format-security.patch b/package/utils/xfsprogs/patches/160-format-security.patch
new file mode 100644
index 0000000000..5ae627d4a1
--- /dev/null
+++ b/package/utils/xfsprogs/patches/160-format-security.patch
@@ -0,0 +1,29 @@
+From: Ben Myers <bpm@sgi.com>
+Date: Fri, 1 Feb 2013 21:50:22 +0000 (-0600)
+Subject: xfsprogs: fix warning in libxcmd/input.c
+X-Git-Tag: v3.1.11~25
+X-Git-Url: http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs%2Fcmds%2Fxfsprogs.git;a=commitdiff_plain;h=50a3aa8977821ad072f3aa5b63645827f9b8ca1d
+
+xfsprogs: fix warning in libxcmd/input.c
+
+Fix an error when building with -Werror=format-security.
+
+input.c: In function 'fetchline':
+input.c:91:2: error: format not a string literal and no format arguments [-Werror=format-security]
+
+Signed-off-by: Ben Myers <bpm@sgi.com>
+Reported by: Arkadiusz Miśkiewicz <arekm@maven.pl>
+Reviewed-by: Mark Tinguely <tinguely@sgi.com>
+---
+
+--- a/libxcmd/input.c
++++ b/libxcmd/input.c
+@@ -88,7 +88,7 @@ fetchline(void)
+ 
+ 	if (!line)
+ 		return NULL;
+-	printf(get_prompt());
++	printf("%s", get_prompt());
+ 	fflush(stdout);
+ 	if (!fgets(line, MAXREADLINESZ, stdin)) {
+ 		free(line);
diff --git a/rules.mk b/rules.mk
new file mode 100644
index 0000000000..d455f0d960
--- /dev/null
+++ b/rules.mk
@@ -0,0 +1,401 @@
+#
+# Copyright (C) 2006-2010 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+ifneq ($(__rules_inc),1)
+__rules_inc=1
+
+ifeq ($(DUMP),)
+  -include $(TOPDIR)/.config
+endif
+include $(TOPDIR)/include/debug.mk
+include $(TOPDIR)/include/verbose.mk
+
+export TMP_DIR:=$(TOPDIR)/tmp
+
+qstrip=$(strip $(subst ",,$(1)))
+#"))
+
+empty:=
+space:= $(empty) $(empty)
+comma:=,
+merge=$(subst $(space),,$(1))
+confvar=$(call merge,$(foreach v,$(1),$(if $($(v)),y,n)))
+strip_last=$(patsubst %.$(lastword $(subst .,$(space),$(1))),%,$(1))
+
+paren_left = (
+paren_right = )
+chars_lower = a b c d e f g h i j k l m n o p q r s t u v w x y z
+chars_upper = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+
+define sep
+
+endef
+
+define newline
+
+
+endef
+
+__tr_list = $(join $(join $(1),$(foreach char,$(1),$(comma))),$(2))
+__tr_head_stripped = $(subst $(space),,$(foreach cv,$(call __tr_list,$(1),$(2)),$$$(paren_left)subst$(cv)$(comma)))
+__tr_head = $(subst $(paren_left)subst,$(paren_left)subst$(space),$(__tr_head_stripped))
+__tr_tail = $(subst $(space),,$(foreach cv,$(1),$(paren_right)))
+__tr_template = $(__tr_head)$$(1)$(__tr_tail)
+
+$(eval toupper = $(call __tr_template,$(chars_lower),$(chars_upper)))
+$(eval tolower = $(call __tr_template,$(chars_upper),$(chars_lower)))
+
+_SINGLE=export MAKEFLAGS=$(space);
+CFLAGS:=
+ARCH:=$(subst i486,i386,$(subst i586,i386,$(subst i686,i386,$(call qstrip,$(CONFIG_ARCH)))))
+ARCH_PACKAGES:=$(call qstrip,$(CONFIG_TARGET_ARCH_PACKAGES))
+BOARD:=$(call qstrip,$(CONFIG_TARGET_BOARD))
+SUBTARGET:=$(call qstrip,$(CONFIG_TARGET_SUBTARGET))
+TARGET_OPTIMIZATION:=$(call qstrip,$(CONFIG_TARGET_OPTIMIZATION))
+export EXTRA_OPTIMIZATION:=$(filter-out -fno-plt,$(call qstrip,$(CONFIG_EXTRA_OPTIMIZATION)))
+TARGET_SUFFIX=$(call qstrip,$(CONFIG_TARGET_SUFFIX))
+BUILD_SUFFIX:=$(call qstrip,$(CONFIG_BUILD_SUFFIX))
+SUBDIR:=$(patsubst $(TOPDIR)/%,%,${CURDIR})
+BUILD_SUBDIR:=$(patsubst $(TOPDIR)/%,%,${CURDIR})
+export SHELL:=/usr/bin/env bash
+
+IS_PACKAGE_BUILD := $(if $(filter package/%,$(BUILD_SUBDIR)),1)
+
+OPTIMIZE_FOR_CPU=$(subst i386,i486,$(ARCH))
+
+ifeq ($(ARCH),powerpc)
+  FPIC:=-fPIC
+else
+  FPIC:=-fpic
+endif
+
+HOST_FPIC:=-fPIC
+
+ARCH_SUFFIX:=$(call qstrip,$(CONFIG_CPU_TYPE))
+GCC_ARCH:=
+
+ifneq ($(ARCH_SUFFIX),)
+  ARCH_SUFFIX:=_$(ARCH_SUFFIX)
+endif
+ifneq ($(filter -march=armv%,$(TARGET_OPTIMIZATION)),)
+  GCC_ARCH:=$(patsubst -march=%,%,$(filter -march=armv%,$(TARGET_OPTIMIZATION)))
+endif
+ifdef CONFIG_HAS_SPE_FPU
+  TARGET_SUFFIX:=$(TARGET_SUFFIX)spe
+endif
+ifdef CONFIG_MIPS64_ABI
+  ifneq ($(CONFIG_MIPS64_ABI_O32),y)
+     ARCH_SUFFIX:=$(ARCH_SUFFIX)_$(call qstrip,$(CONFIG_MIPS64_ABI))
+  endif
+endif
+
+DL_DIR:=$(if $(call qstrip,$(CONFIG_DOWNLOAD_FOLDER)),$(call qstrip,$(CONFIG_DOWNLOAD_FOLDER)),$(TOPDIR)/dl)
+OUTPUT_DIR:=$(if $(call qstrip,$(CONFIG_BINARY_FOLDER)),$(call qstrip,$(CONFIG_BINARY_FOLDER)),$(TOPDIR)/bin)
+BIN_DIR:=$(OUTPUT_DIR)/targets/$(BOARD)/$(SUBTARGET)
+INCLUDE_DIR:=$(TOPDIR)/include
+SCRIPT_DIR:=$(TOPDIR)/scripts
+BUILD_DIR_BASE:=$(TOPDIR)/build_dir
+ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+  GCCV:=$(call qstrip,$(CONFIG_GCC_VERSION))
+  LIBC:=$(call qstrip,$(CONFIG_LIBC))
+  LIBCV:=$(call qstrip,$(CONFIG_LIBC_VERSION))
+  REAL_GNU_TARGET_NAME=$(OPTIMIZE_FOR_CPU)-openwrt-linux$(if $(TARGET_SUFFIX),-$(TARGET_SUFFIX))
+  GNU_TARGET_NAME=$(OPTIMIZE_FOR_CPU)-openwrt-linux
+  DIR_SUFFIX:=_$(LIBC)-$(LIBCV)$(if $(CONFIG_arm),_eabi)
+  BIN_DIR:=$(BIN_DIR)$(if $(CONFIG_USE_MUSL),,-$(LIBC))
+  TARGET_DIR_NAME = target-$(ARCH)$(ARCH_SUFFIX)$(DIR_SUFFIX)$(if $(BUILD_SUFFIX),_$(BUILD_SUFFIX))
+  TOOLCHAIN_DIR_NAME = toolchain-$(ARCH)$(ARCH_SUFFIX)_gcc-$(GCCV)$(DIR_SUFFIX)
+else
+  ifeq ($(CONFIG_NATIVE_TOOLCHAIN),)
+    GNU_TARGET_NAME=$(call qstrip,$(CONFIG_TARGET_NAME))
+  else
+    GNU_TARGET_NAME=$(shell gcc -dumpmachine)
+  endif
+  REAL_GNU_TARGET_NAME=$(GNU_TARGET_NAME)
+  TARGET_DIR_NAME:=target-$(GNU_TARGET_NAME)$(if $(BUILD_SUFFIX),_$(BUILD_SUFFIX))
+  TOOLCHAIN_DIR_NAME:=toolchain-$(GNU_TARGET_NAME)
+endif
+
+ifeq ($(or $(CONFIG_EXTERNAL_TOOLCHAIN),$(CONFIG_GCC_VERSION_4_8),$(CONFIG_TARGET_uml)),)
+  iremap = -iremap $(1):$(2)
+endif
+
+PACKAGE_DIR:=$(BIN_DIR)/packages
+BUILD_DIR:=$(BUILD_DIR_BASE)/$(TARGET_DIR_NAME)
+STAGING_DIR:=$(TOPDIR)/staging_dir/$(TARGET_DIR_NAME)
+BUILD_DIR_TOOLCHAIN:=$(BUILD_DIR_BASE)/$(TOOLCHAIN_DIR_NAME)
+TOOLCHAIN_DIR:=$(TOPDIR)/staging_dir/$(TOOLCHAIN_DIR_NAME)
+STAMP_DIR:=$(BUILD_DIR)/stamp
+STAMP_DIR_HOST=$(BUILD_DIR_HOST)/stamp
+TARGET_ROOTFS_DIR?=$(if $(call qstrip,$(CONFIG_TARGET_ROOTFS_DIR)),$(call qstrip,$(CONFIG_TARGET_ROOTFS_DIR)),$(BUILD_DIR))
+TARGET_DIR:=$(TARGET_ROOTFS_DIR)/root-$(BOARD)
+STAGING_DIR_ROOT:=$(STAGING_DIR)/root-$(BOARD)
+BUILD_LOG_DIR:=$(TOPDIR)/logs
+PKG_INFO_DIR := $(STAGING_DIR)/pkginfo
+
+BUILD_DIR_HOST:=$(if $(IS_PACKAGE_BUILD),$(BUILD_DIR)/host,$(BUILD_DIR_BASE)/host)
+STAGING_DIR_HOST:=$(TOPDIR)/staging_dir/host
+STAGING_DIR_HOSTPKG:=$(STAGING_DIR)/host
+
+TARGET_PATH:=$(subst $(space),:,$(filter-out .,$(filter-out ./,$(subst :,$(space),$(PATH)))))
+TARGET_INIT_PATH:=$(call qstrip,$(CONFIG_TARGET_INIT_PATH))
+TARGET_INIT_PATH:=$(if $(TARGET_INIT_PATH),$(TARGET_INIT_PATH),/usr/sbin:/sbin:/usr/bin:/bin)
+TARGET_CFLAGS:=$(TARGET_OPTIMIZATION)$(if $(CONFIG_DEBUG), -g3) $(call qstrip,$(CONFIG_EXTRA_OPTIMIZATION))
+TARGET_CXXFLAGS = $(TARGET_CFLAGS)
+TARGET_ASFLAGS_DEFAULT = $(TARGET_CFLAGS)
+TARGET_ASFLAGS = $(TARGET_ASFLAGS_DEFAULT)
+TARGET_CPPFLAGS:=-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include
+TARGET_LDFLAGS:=-L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/lib
+ifneq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+LIBGCC_S_PATH=$(realpath $(wildcard $(call qstrip,$(CONFIG_LIBGCC_ROOT_DIR))/$(call qstrip,$(CONFIG_LIBGCC_FILE_SPEC))))
+LIBGCC_S=$(if $(LIBGCC_S_PATH),-L$(dir $(LIBGCC_S_PATH)) -lgcc_s)
+LIBGCC_A=$(realpath $(lastword $(wildcard $(dir $(LIBGCC_S_PATH))/gcc/*/*/libgcc.a)))
+else
+LIBGCC_A=$(lastword $(wildcard $(TOOLCHAIN_DIR)/lib/gcc/*/*/libgcc.a))
+LIBGCC_S=$(if $(wildcard $(TOOLCHAIN_DIR)/lib/libgcc_s.so),-L$(TOOLCHAIN_DIR)/lib -lgcc_s,$(LIBGCC_A))
+endif
+LIBRPC=-lrpc
+LIBRPC_DEPENDS=+librpc
+
+ifeq ($(CONFIG_ARCH_64BIT),y)
+  LIB_SUFFIX:=64
+endif
+
+ifndef DUMP
+  ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+    -include $(TOOLCHAIN_DIR)/info.mk
+    export GCC_HONOUR_COPTS:=0
+    TARGET_CROSS:=$(if $(TARGET_CROSS),$(TARGET_CROSS),$(OPTIMIZE_FOR_CPU)-openwrt-linux$(if $(TARGET_SUFFIX),-$(TARGET_SUFFIX))-)
+    TARGET_CFLAGS+= -fhonour-copts -Wno-error=unused-but-set-variable -Wno-error=unused-result
+    TARGET_CPPFLAGS+= -I$(TOOLCHAIN_DIR)/usr/include
+    ifeq ($(CONFIG_USE_MUSL),y)
+      TARGET_CPPFLAGS+= -I$(TOOLCHAIN_DIR)/include/fortify
+    endif
+    TARGET_CPPFLAGS+= -I$(TOOLCHAIN_DIR)/include
+    TARGET_LDFLAGS+= -L$(TOOLCHAIN_DIR)/usr/lib -L$(TOOLCHAIN_DIR)/lib
+    TARGET_PATH:=$(TOOLCHAIN_DIR)/bin:$(TARGET_PATH)
+  else
+    ifeq ($(CONFIG_NATIVE_TOOLCHAIN),)
+      TARGET_CROSS:=$(call qstrip,$(CONFIG_TOOLCHAIN_PREFIX))
+      TOOLCHAIN_ROOT_DIR:=$(call qstrip,$(CONFIG_TOOLCHAIN_ROOT))
+      TOOLCHAIN_BIN_DIRS:=$(patsubst ./%,$(TOOLCHAIN_ROOT_DIR)/%,$(call qstrip,$(CONFIG_TOOLCHAIN_BIN_PATH)))
+      TOOLCHAIN_INC_DIRS:=$(patsubst ./%,$(TOOLCHAIN_ROOT_DIR)/%,$(call qstrip,$(CONFIG_TOOLCHAIN_INC_PATH)))
+      TOOLCHAIN_LIB_DIRS:=$(patsubst ./%,$(TOOLCHAIN_ROOT_DIR)/%,$(call qstrip,$(CONFIG_TOOLCHAIN_LIB_PATH)))
+      ifneq ($(TOOLCHAIN_BIN_DIRS),)
+        TARGET_PATH:=$(subst $(space),:,$(TOOLCHAIN_BIN_DIRS)):$(TARGET_PATH)
+      endif
+      ifneq ($(TOOLCHAIN_INC_DIRS),)
+        TARGET_CPPFLAGS+= $(patsubst %,-I%,$(TOOLCHAIN_INC_DIRS))
+      endif
+      ifneq ($(TOOLCHAIN_LIB_DIRS),)
+        TARGET_LDFLAGS+= $(patsubst %,-L%,$(TOOLCHAIN_LIB_DIRS))
+      endif
+      TARGET_PATH:=$(TOOLCHAIN_DIR)/bin:$(TARGET_PATH)
+    endif
+  endif
+endif
+TARGET_PATH_PKG:=$(STAGING_DIR)/host/bin:$(TARGET_PATH)
+
+ifeq ($(CONFIG_SOFT_FLOAT),y)
+  SOFT_FLOAT_CONFIG_OPTION:=--with-float=soft
+  ifeq ($(CONFIG_arm),y)
+    TARGET_CFLAGS+= -mfloat-abi=soft
+  else
+    TARGET_CFLAGS+= -msoft-float
+  endif
+else
+  SOFT_FLOAT_CONFIG_OPTION:=
+  ifeq ($(CONFIG_arm),y)
+    TARGET_CFLAGS+= -mfloat-abi=hard
+  endif
+endif
+
+export PATH:=$(TARGET_PATH)
+export STAGING_DIR STAGING_DIR_HOST
+export SH_FUNC:=. $(INCLUDE_DIR)/shell.sh;
+
+PKG_CONFIG:=$(STAGING_DIR_HOST)/bin/pkg-config
+
+export PKG_CONFIG
+
+HOSTCC:=gcc
+HOSTCXX:=g++
+HOST_CPPFLAGS:=-I$(STAGING_DIR_HOST)/include -I$(STAGING_DIR_HOST)/usr/include $(if $(IS_PACKAGE_BUILD),-I$(STAGING_DIR)/host/include)
+HOST_CFLAGS:=-O2 $(HOST_CPPFLAGS)
+HOST_LDFLAGS:=-L$(STAGING_DIR_HOST)/lib -L$(STAGING_DIR_HOST)/usr/lib $(if $(IS_PACKAGE_BUILD),-L$(STAGING_DIR)/host/lib)
+
+ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+  TARGET_AR:=$(TARGET_CROSS)gcc-ar
+  TARGET_RANLIB:=$(TARGET_CROSS)gcc-ranlib
+  TARGET_NM:=$(TARGET_CROSS)gcc-nm
+else
+  TARGET_AR:=$(TARGET_CROSS)ar
+  TARGET_RANLIB:=$(TARGET_CROSS)ranlib
+  TARGET_NM:=$(TARGET_CROSS)nm
+endif
+
+BUILD_KEY=$(TOPDIR)/key-build
+
+TARGET_CC:=$(TARGET_CROSS)gcc
+TARGET_CXX:=$(TARGET_CROSS)g++
+KPATCH:=$(SCRIPT_DIR)/patch-kernel.sh
+SED:=$(STAGING_DIR_HOST)/bin/sed -i -e
+CP:=cp -fpR
+LN:=ln -sf
+XARGS:=xargs -r
+
+BASH:=bash
+TAR:=tar
+FIND:=find
+PATCH:=patch
+PYTHON:=python
+
+INSTALL_BIN:=install -m0755
+INSTALL_DIR:=install -d -m0755
+INSTALL_DATA:=install -m0644
+INSTALL_CONF:=install -m0600
+
+TARGET_CC_NOCACHE:=$(TARGET_CC)
+TARGET_CXX_NOCACHE:=$(TARGET_CXX)
+HOSTCC_NOCACHE:=$(HOSTCC)
+HOSTCXX_NOCACHE:=$(HOSTCXX)
+export TARGET_CC_NOCACHE
+export TARGET_CXX_NOCACHE
+export HOSTCC_NOCACHE
+
+ifneq ($(CONFIG_CCACHE),)
+  TARGET_CC:= ccache_cc
+  TARGET_CXX:= ccache_cxx
+  HOSTCC:= ccache $(HOSTCC)
+  HOSTCXX:= ccache $(HOSTCXX)
+endif
+
+TARGET_CONFIGURE_OPTS = \
+  AR="$(TARGET_AR)" \
+  AS="$(TARGET_CC) -c $(TARGET_ASFLAGS)" \
+  LD=$(TARGET_CROSS)ld \
+  NM="$(TARGET_NM)" \
+  CC="$(TARGET_CC)" \
+  GCC="$(TARGET_CC)" \
+  CXX="$(TARGET_CXX)" \
+  RANLIB="$(TARGET_RANLIB)" \
+  STRIP=$(TARGET_CROSS)strip \
+  OBJCOPY=$(TARGET_CROSS)objcopy \
+  OBJDUMP=$(TARGET_CROSS)objdump \
+  SIZE=$(TARGET_CROSS)size
+
+# strip an entire directory
+ifneq ($(CONFIG_NO_STRIP),)
+  RSTRIP:=:
+  STRIP:=:
+else
+  ifneq ($(CONFIG_USE_STRIP),)
+    STRIP:=$(TARGET_CROSS)strip $(call qstrip,$(CONFIG_STRIP_ARGS))
+  else
+    ifneq ($(CONFIG_USE_SSTRIP),)
+      STRIP:=$(STAGING_DIR_HOST)/bin/sstrip
+    endif
+  endif
+  RSTRIP= \
+    export CROSS="$(TARGET_CROSS)" \
+		$(if $(PKG_BUILD_ID),KEEP_BUILD_ID=1) \
+		$(if $(CONFIG_KERNEL_KALLSYMS),NO_RENAME=1) \
+		$(if $(CONFIG_KERNEL_PROFILING),KEEP_SYMBOLS=1); \
+    NM="$(TARGET_CROSS)nm" \
+    STRIP="$(STRIP)" \
+    STRIP_KMOD="$(SCRIPT_DIR)/strip-kmod.sh" \
+    PATCHELF="$(STAGING_DIR_HOST)/bin/patchelf" \
+    $(SCRIPT_DIR)/rstrip.sh
+endif
+
+ifeq ($(CONFIG_IPV6),y)
+  DISABLE_IPV6:=
+else
+  DISABLE_IPV6:=--disable-ipv6
+endif
+
+TAR_OPTIONS:=-xf -
+
+ifeq ($(CONFIG_BUILD_LOG),y)
+  BUILD_LOG:=1
+endif
+
+export BISON_PKGDATADIR:=$(STAGING_DIR_HOST)/share/bison
+export M4:=$(STAGING_DIR_HOST)/bin/m4
+
+define shvar
+V_$(subst .,_,$(subst -,_,$(subst /,_,$(1))))
+endef
+
+define shexport
+export $(call shvar,$(1))=$$(call $(1))
+endef
+
+define include_mk
+$(eval -include $(if $(DUMP),,$(STAGING_DIR)/mk/$(strip $(1))))
+endef
+
+# Execute commands under flock
+# $(1) => The shell expression.
+# $(2) => The lock name. If not given, the global lock will be used.
+ifneq ($(wildcard $(STAGING_DIR_HOST)/bin/flock),)
+  define locked
+	SHELL= \
+	flock \
+		$(TMP_DIR)/.$(if $(2),$(strip $(2)),global).flock \
+		-c '$(subst ','\'',$(1))'
+  endef
+else
+  locked=$(1)
+endif
+
+# Recursively copy paths into another directory, purge dangling
+# symlinks before.
+# $(1) => File glob expression
+# $(2) => Destination directory
+define file_copy
+	for src_dir in $(sort $(foreach d,$(wildcard $(1)),$(dir $(d)))); do \
+		( cd $$src_dir; find -type f -or -type d ) | \
+			( cd $(2); while :; do \
+				read FILE; \
+				[ -z "$$FILE" ] && break; \
+				[ -L "$$FILE" ] || continue; \
+				echo "Removing symlink $(2)/$$FILE"; \
+				rm -f "$$FILE"; \
+			done; ); \
+	done; \
+	$(CP) $(1) $(2)
+endef
+
+# Calculate sha256sum of any plain file within a given directory
+# $(1) => Input directory
+define sha256sums
+	(cd $(1); find . -maxdepth 1 -type f -not -name 'sha256sums' -printf "%P\n" | sort | \
+		xargs openssl dgst -sha256 | sed -ne 's!^SHA256(\(.*\))= \(.*\)$$!\2 *\1!p' > sha256sums)
+endef
+
+# file extension
+ext=$(word $(words $(subst ., ,$(1))),$(subst ., ,$(1)))
+
+all:
+FORCE: ;
+.PHONY: FORCE
+
+val.%:
+	@$(if $(filter undefined,$(origin $*)),\
+		echo "$* undefined" >&2, \
+		echo '$(subst ','"'"',$($*))' \
+	)
+
+var.%:
+	@$(if $(filter undefined,$(origin $*)),\
+		echo "$* undefined" >&2, \
+		echo "$*='"'$(subst ','"'\"'\"'"',$($*))'"'" \
+	)
+
+endif #__rules_inc
diff --git a/scripts/arm-magic.sh b/scripts/arm-magic.sh
new file mode 100755
index 0000000000..29ec88ab2f
--- /dev/null
+++ b/scripts/arm-magic.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+#
+#   Empty/wrong machtype-workaround generator
+#
+#   Copyright (C) 2006-2012 Imre Kaloz <kaloz@openwrt.org>
+#   based on linux/arch/arm/boot/compressed/head-xscale.S
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+# NOTE: for now it's for only IXP4xx in big endian mode
+
+# list of supported boards, in "boardname machtypeid" format
+for board in "avila 526" "gateway7001 731" "nslu2 597" "nas100d 865" "wg302v1 889" "wg302v2 890" "pronghorn 928" "pronghornmetro 1040" "compex 1273" "wrt300nv2 1077" "loft 849" "dsmg600 964" "fsg3 1091" "ap1000 1543" "tw2662 1658" "tw5334 1664" "ixdpg425 604" "cambria 1468" "sidewinder 1041" "ap42x 4418"
+do
+  set -- $board
+  hexid=$(printf %x\\n $2)
+  if [ "$2" -lt "256" ]; then
+    # we have a low machtypeid, we just need a "mov" (e3a)
+    printf "\xe3\xa0\x10\x$hexid" > $BIN_DIR/$IMG_PREFIX-$1-zImage
+  else
+    # we have a high machtypeid, we need a "mov" (e3a) and an "orr" (e38)
+    if [ "$2" -lt "4096" ]; then
+      printf "\xe3\xa0\x10\x$(echo $hexid|cut -b "2 3")\xe3\x81\x1c\x$(echo $hexid|cut -b 1)" > $BIN_DIR/$IMG_PREFIX-$1-zImage
+    else
+      printf "\xe3\xa0\x10\x$(echo $hexid|cut -b "3 4")\xe3\x81\x1c\x$(echo $hexid|cut -b "1 2")" > $BIN_DIR/$IMG_PREFIX-$1-zImage
+    fi
+  fi
+    # generate the image
+    cat $BIN_DIR/$IMG_PREFIX-zImage >> $BIN_DIR/$IMG_PREFIX-$1-zImage
+done
diff --git a/scripts/brcmImage.pl b/scripts/brcmImage.pl
new file mode 100755
index 0000000000..aab86d6d91
--- /dev/null
+++ b/scripts/brcmImage.pl
@@ -0,0 +1,162 @@
+#!/usr/bin/env perl
+#
+#    Copyright (C) 2009	Henk Vergonet <Henk.Vergonet@gmail.com>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Description:
+#   Replacement for brcmImagebuilder
+#
+# Disclaimer:
+#   Use this software at your own risk.
+#
+# Changelog:
+#   2009-01-01	Henk.Vergonet at gmail.com
+#
+use strict;
+use Getopt::Std;
+use Compress::Zlib;
+
+my $version = "0.1";
+my %arg = (
+	o => 'bcm963xx_fs_kernel',
+	b => 'LEDE',
+	c => '6348',
+	s => 64,
+	f => 0xbfc00000,
+	x => 0x00010000,
+	a => 0x80010000,
+	e => 0x80010000,
+	i => 2,
+);
+my $prog = $0;
+$prog =~ s/^.*\///;
+getopts("r:k:o:lc:b:s:f:i:a:e:tpvh", \%arg);
+
+die "usage: $prog ~opts~
+
+  -r <file>	: input rootfs file
+  -k <file>	: input kernel file
+  -o <file>	: output image file, default $arg{o}
+  -l		: littleendian system, default ".($arg{l} ? 'yes' : 'no')."
+  -c <chipid>	: default $arg{c} 
+  -b <boardid>	: default $arg{b} 
+  -s <size_kb>	: erase sise flash, default $arg{s} 
+  -f <baseaddr>	: flash base, default ".sprintf('0x%x', $arg{f})."
+  -x <cfelen>	: length of cfe, default ".sprintf('0x%x', $arg{x})."
+  -i		: 2=dual image, default $arg{i}
+
+  -a <loadaddr>	: Kernel load address, default ".sprintf('0x%x', $arg{a})."
+  -e <entryaddr>: Kernel entry address, default ".sprintf('0x%x', $arg{e})."
+  -t		: Prefix kernel with load,entry,size
+
+  -p		: Add a 'gOtO' partition 
+
+  -v		: be more verbose
+  -h		: help, version $version
+
+EXAMPLES:
+    $prog -k kern -r rootfs
+" if $arg{h} || !$arg{k} || !$arg{r};
+
+sub Read_Image
+{
+	open my $fh, $_[0] or die "open $_[0]: $!";
+	local $/;	# Set input to "slurp" mode.
+	my $buf = <$fh>;
+	close $fh;
+	return $buf;
+}
+
+sub Padlen
+{
+	my $p = $_[0] % $_[1];
+	return ($p ? $_[1] - $p : 0);
+}
+
+sub Pad
+{
+	my ($buf, $off, $bs) = @_[0..2];
+	$buf .= chr(255) x Padlen(length($buf) + $off, $bs);
+	return $buf;
+}
+
+sub bcmImage
+{
+	my ($k, $f) = @_[0..1];
+	my $tmp = $arg{x} + 0x100 + $arg{f};
+	
+	# regular: rootfs+kernel
+	my ($img, $fa, $ka) = ( $f.$k, $tmp, $tmp + length($f) );
+
+	# test: kernel+rootfs
+#	my ($img, $fa, $ka) = ( $k.$f, $tmp + length($k), $tmp );
+
+	$fa = 0 unless length($f);
+
+	my $hdr = pack("a4a20a14a6a16a2a10a12a10a12a10a12a10a2a2a74Na16",
+		'6',
+		'LinuxInside', 
+		'ver. 2.0', 
+		$arg{c},
+		$arg{b},
+		($arg{l} ? '0' : '1'),
+		length($img),
+		'0',
+		'0',
+		$fa,
+		length($f),
+		$ka,
+		length($k),
+		($arg{i}==2 ? '1' : '0'),
+		'',		# if 1, the image is INACTIVE; if 0, active
+		'',
+		~crc32($k, crc32($f)),
+		'');
+	$hdr .= pack('Na16', ~crc32($hdr), '');
+
+	printf "kernel at 0x%x length 0x%x(%u)\n", $ka, length($k), length($k)
+		if $arg{v};
+	printf "rootfs at 0x%x length 0x%x(%u)\n", $fa, length($f), length($f)
+		if $arg{v};
+
+	open(FO, ">$arg{o}");
+	print FO $hdr;
+	print FO $img;
+	close FO;
+}
+
+# MAIN
+
+my $kern = Read_Image $arg{k};
+my $root = Read_Image $arg{r};
+
+$kern = pack('NNN', $arg{a}, $arg{e}, length($kern)).$kern if $arg{t};
+
+# specific fixup for the CFE that expects rootfs-kernel order
+if ($arg{p}) {
+	$kern = Pad($kern, 0x10c, $arg{s} * 1024);
+	my $dummy_root = pack('a4NN',
+			'gOtO',
+			length($kern)+12,
+			length($root)+Padlen(length($root), $arg{s} * 1024)
+	);
+	$kern .= $root;
+	$root = $dummy_root;
+}
+
+bcmImage($kern, $root);
+
diff --git a/scripts/bundle-libraries.sh b/scripts/bundle-libraries.sh
new file mode 100755
index 0000000000..aba1cd6268
--- /dev/null
+++ b/scripts/bundle-libraries.sh
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+#
+#   Script to install host system binaries along with required libraries.
+#
+#   Copyright (C) 2012-2013 Jo-Philipp Wich <jo@mein.io>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+DIR="$1"; shift
+
+_cp() {
+	cp ${VERBOSE:+-v} -L "$1" "$2" || {
+		echo "cp($1 $2) failed" >&2
+		exit 1
+	}
+}
+
+_md() {
+	mkdir ${VERBOSE:+-v} -p "$1" || {
+		echo "mkdir($1) failed" >&2
+		exit 2
+	}
+}
+
+_ln() {
+	ln ${VERBOSE:+-v} -sf "$1" "$2" || {
+		echo "ln($1 $2) failed" >&2
+		exit 3
+	}
+}
+
+for LDD in ${PATH//://ldd }/ldd; do
+	"$LDD" --version >/dev/null 2>/dev/null && break
+	LDD=""
+done
+
+[ -n "$LDD" -a -x "$LDD" ] || LDD=
+
+for BIN in "$@"; do
+	[ -n "$BIN" -a -x "$BIN" -a -n "$DIR" ] || {
+		echo "Usage: $0 <destdir> <executable> ..." >&2
+		exit 1
+	}
+
+	[ ! -d "$DIR/bundled/lib" ] && {
+		_md "$DIR/bundled/lib"
+		_md "$DIR/bundled/usr"
+		_ln "../lib" "$DIR/bundled/usr/lib"
+	}
+
+	LDSO=""
+
+	echo "Bundling ${BIN##*/}"
+	[ -n "$LDD" ] && {
+		for token in $("$LDD" "$BIN" 2>/dev/null); do
+			case "$token" in */*.so*)
+				case "$token" in
+					*ld-*.so*) LDSO="${token##*/}" ;;
+					*) echo " * lib: ${token##*/}" ;;
+				esac
+
+				dest="$DIR/bundled/lib/${token##*/}"
+				ddir="${dest%/*}"
+
+				[ -f "$token" -a ! -f "$dest" ] && {
+					_md "$ddir"
+					_cp "$token" "$dest"
+				}
+			;; esac
+		done
+	}
+
+	_md "$DIR"
+
+	# is a dynamically linked executable
+	if [ -n "$LDSO" ]; then
+		_cp "$BIN" "$DIR/bundled/${BIN##*/}"
+
+		RUN="${LDSO#ld-}"; RUN="run-${RUN%%.so*}.sh"
+
+		[ -x "$DIR/bundled/$RUN" ] || {
+			cat <<-EOF > "$DIR/bundled/$RUN"
+				#!/usr/bin/env bash
+				dir="\$(dirname "\$0")"
+				bin="\$(basename "\$0")"
+				exec -a "\$0" "\$dir/bundled/lib/$LDSO" --library-path "\$dir/bundled/lib" "\$dir/bundled/\$bin" "\$@"
+			EOF
+			chmod ${VERBOSE:+-v} 0755 "$DIR/bundled/$RUN"
+		}
+
+		_ln "./bundled/$RUN" "$DIR/${BIN##*/}"
+
+	# is a static executable or non-elf binary
+	else
+		[ -n "$LDD" ] && echo " * not dynamically linked"
+		_cp "$BIN" "$DIR/${BIN##*/}"
+	fi
+done
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
new file mode 100755
index 0000000000..c4b7437b90
--- /dev/null
+++ b/scripts/checkpatch.pl
@@ -0,0 +1,3490 @@
+#!/usr/bin/perl -w
+# (c) 2001, Dave Jones. (the file handling bit)
+# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
+# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
+# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
+# (c) 2013 Vasilis Tsiligiannis <acinonyx@openwrt.gr> (adapt for OpenWrt tree)
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ s@.*/@@g;
+
+my $V = '0.32-openwrt';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $quiet = 0;
+my $tree = 1;
+my $chk_signoff = 1;
+my $chk_patch = 1;
+my $tst_only;
+my $emacs = 0;
+my $terse = 0;
+my $file = 0;
+my $check = 0;
+my $summary = 1;
+my $mailback = 0;
+my $summary_file = 0;
+my $show_types = 0;
+my $root;
+my %debug;
+my %ignore_type = ();
+my @ignore = ();
+my $help = 0;
+my $configuration_file = ".checkpatch.conf";
+
+sub help {
+	my ($exitcode) = @_;
+
+	print << "EOM";
+Usage: $P [OPTION]... [FILE]...
+Version: $V
+
+Options:
+  -q, --quiet                quiet
+  --no-tree                  run without a kernel tree
+  --no-signoff               do not check for 'Signed-off-by' line
+  --patch                    treat FILE as patchfile (default)
+  --emacs                    emacs compile window format
+  --terse                    one line per report
+  -f, --file                 treat FILE as regular source file
+  --subjective, --strict     enable more subjective tests
+  --ignore TYPE(,TYPE2...)   ignore various comma separated message types
+  --show-types               show the message "types" in the output
+  --root=PATH                PATH to the kernel tree root
+  --no-summary               suppress the per-file summary
+  --mailback                 only produce a report in case of warnings/errors
+  --summary-file             include the filename in summary
+  --debug KEY=[0|1]          turn on/off debugging of KEY, where KEY is one of
+                             'values', 'possible', 'type', and 'attr' (default
+                             is all off)
+  --test-only=WORD           report only warnings/errors containing WORD
+                             literally
+  -h, --help, --version      display this help and exit
+
+When FILE is - read standard input.
+EOM
+
+	exit($exitcode);
+}
+
+my $conf = which_conf($configuration_file);
+if (-f $conf) {
+	my @conf_args;
+	open(my $conffile, '<', "$conf")
+	    or warn "$P: Can't find a readable $configuration_file file $!\n";
+
+	while (<$conffile>) {
+		my $line = $_;
+
+		$line =~ s/\s*\n?$//g;
+		$line =~ s/^\s*//g;
+		$line =~ s/\s+/ /g;
+
+		next if ($line =~ m/^\s*#/);
+		next if ($line =~ m/^\s*$/);
+
+		my @words = split(" ", $line);
+		foreach my $word (@words) {
+			last if ($word =~ m/^#/);
+			push (@conf_args, $word);
+		}
+	}
+	close($conffile);
+	unshift(@ARGV, @conf_args) if @conf_args;
+}
+
+GetOptions(
+	'q|quiet+'	=> \$quiet,
+	'tree!'		=> \$tree,
+	'signoff!'	=> \$chk_signoff,
+	'patch!'	=> \$chk_patch,
+	'emacs!'	=> \$emacs,
+	'terse!'	=> \$terse,
+	'f|file!'	=> \$file,
+	'subjective!'	=> \$check,
+	'strict!'	=> \$check,
+	'ignore=s'	=> \@ignore,
+	'show-types!'	=> \$show_types,
+	'root=s'	=> \$root,
+	'summary!'	=> \$summary,
+	'mailback!'	=> \$mailback,
+	'summary-file!'	=> \$summary_file,
+
+	'debug=s'	=> \%debug,
+	'test-only=s'	=> \$tst_only,
+	'h|help'	=> \$help,
+	'version'	=> \$help
+) or help(1);
+
+help(0) if ($help);
+
+my $exit = 0;
+
+if ($#ARGV < 0) {
+	print "$P: no input files\n";
+	exit(1);
+}
+
+@ignore = split(/,/, join(',',@ignore));
+foreach my $word (@ignore) {
+	$word =~ s/\s*\n?$//g;
+	$word =~ s/^\s*//g;
+	$word =~ s/\s+/ /g;
+	$word =~ tr/[a-z]/[A-Z]/;
+
+	next if ($word =~ m/^\s*#/);
+	next if ($word =~ m/^\s*$/);
+
+	$ignore_type{$word}++;
+}
+
+my $dbg_values = 0;
+my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
+for my $key (keys %debug) {
+	## no critic
+	eval "\${dbg_$key} = '$debug{$key}';";
+	die "$@" if ($@);
+}
+
+my $rpt_cleaners = 0;
+
+if ($terse) {
+	$emacs = 1;
+	$quiet++;
+}
+
+if ($tree) {
+	if (defined $root) {
+		if (!top_of_openwrt_tree($root)) {
+			die "$P: $root: --root does not point at a valid tree\n";
+		}
+	} else {
+		if (top_of_openwrt_tree('.')) {
+			$root = '.';
+		} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
+						top_of_openwrt_tree($1)) {
+			$root = $1;
+		}
+	}
+
+	if (!defined $root) {
+		print "Must be run from the top-level dir. of a LEDE tree\n";
+		exit(2);
+	}
+}
+
+my $emitted_corrupt = 0;
+
+our $Ident	= qr{
+			[A-Za-z_][A-Za-z\d_]*
+			(?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
+		}x;
+our $Storage	= qr{extern|static|asmlinkage};
+our $Sparse	= qr{
+			__user|
+			__kernel|
+			__force|
+			__iomem|
+			__must_check|
+			__init_refok|
+			__kprobes|
+			__ref|
+			__rcu
+		}x;
+
+# Notes to $Attribute:
+# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
+our $Attribute	= qr{
+			const|
+			__percpu|
+			__nocast|
+			__safe|
+			__bitwise__|
+			__packed__|
+			__packed2__|
+			__naked|
+			__maybe_unused|
+			__always_unused|
+			__noreturn|
+			__used|
+			__cold|
+			__noclone|
+			__deprecated|
+			__read_mostly|
+			__kprobes|
+			__(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+			____cacheline_aligned|
+			____cacheline_aligned_in_smp|
+			____cacheline_internodealigned_in_smp|
+			__weak
+		  }x;
+our $Modifier;
+our $Inline	= qr{inline|__always_inline|noinline};
+our $Member	= qr{->$Ident|\.$Ident|\[[^]]*\]};
+our $Lval	= qr{$Ident(?:$Member)*};
+
+our $Constant	= qr{(?i:(?:[0-9]+|0x[0-9a-f]+)[ul]*)};
+our $Assignment	= qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
+our $Compare    = qr{<=|>=|==|!=|<|>};
+our $Operators	= qr{
+			<=|>=|==|!=|
+			=>|->|<<|>>|<|>|!|~|
+			&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+		  }x;
+
+our $NonptrType;
+our $Type;
+our $Declare;
+
+our $NON_ASCII_UTF8	= qr{
+	[\xC2-\xDF][\x80-\xBF]               # non-overlong 2-byte
+	|  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
+	| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
+	|  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
+	|  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
+	| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
+	|  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
+}x;
+
+our $UTF8	= qr{
+	[\x09\x0A\x0D\x20-\x7E]              # ASCII
+	| $NON_ASCII_UTF8
+}x;
+
+our $typeTypedefs = qr{(?x:
+	(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
+	atomic_t
+)};
+
+our $logFunctions = qr{(?x:
+	printk(?:_ratelimited|_once|)|
+	[a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
+	WARN(?:_RATELIMIT|_ONCE|)|
+	panic|
+	MODULE_[A-Z_]+
+)};
+
+our $signature_tags = qr{(?xi:
+	Signed-off-by:|
+	Acked-by:|
+	Tested-by:|
+	Reviewed-by:|
+	Reported-by:|
+	To:|
+	Cc:
+)};
+
+our @typeList = (
+	qr{void},
+	qr{(?:unsigned\s+)?char},
+	qr{(?:unsigned\s+)?short},
+	qr{(?:unsigned\s+)?int},
+	qr{(?:unsigned\s+)?long},
+	qr{(?:unsigned\s+)?long\s+int},
+	qr{(?:unsigned\s+)?long\s+long},
+	qr{(?:unsigned\s+)?long\s+long\s+int},
+	qr{unsigned},
+	qr{float},
+	qr{double},
+	qr{bool},
+	qr{struct\s+$Ident},
+	qr{union\s+$Ident},
+	qr{enum\s+$Ident},
+	qr{${Ident}_t},
+	qr{${Ident}_handler},
+	qr{${Ident}_handler_fn},
+);
+our @modifierList = (
+	qr{fastcall},
+);
+
+our $allowed_asm_includes = qr{(?x:
+	irq|
+	memory
+)};
+# memory.h: ARM has a custom one
+
+sub build_types {
+	my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
+	my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
+	$Modifier	= qr{(?:$Attribute|$Sparse|$mods)};
+	$NonptrType	= qr{
+			(?:$Modifier\s+|const\s+)*
+			(?:
+				(?:typeof|__typeof__)\s*\([^\)]*\)|
+				(?:$typeTypedefs\b)|
+				(?:${all}\b)
+			)
+			(?:\s+$Modifier|\s+const)*
+		  }x;
+	$Type	= qr{
+			$NonptrType
+			(?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
+			(?:\s+$Inline|\s+$Modifier)*
+		  }x;
+	$Declare	= qr{(?:$Storage\s+)?$Type};
+}
+build_types();
+
+
+our $Typecast	= qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
+
+# Using $balanced_parens, $LvalOrFunc, or $FuncArg
+# requires at least perl version v5.10.0
+# Any use must be runtime checked with $^V
+
+our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
+our $LvalOrFunc	= qr{($Lval)\s*($balanced_parens{0,1})\s*};
+our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
+
+sub deparenthesize {
+	my ($string) = @_;
+	return "" if (!defined($string));
+	$string =~ s@^\s*\(\s*@@g;
+	$string =~ s@\s*\)\s*$@@g;
+	$string =~ s@\s+@ @g;
+	return $string;
+}
+
+$chk_signoff = 0 if ($file);
+
+my @rawlines = ();
+my @lines = ();
+my $vname;
+for my $filename (@ARGV) {
+	my $FILE;
+	if ($file) {
+		open($FILE, '-|', "diff -u /dev/null $filename") ||
+			die "$P: $filename: diff failed - $!\n";
+	} elsif ($filename eq '-') {
+		open($FILE, '<&STDIN');
+	} else {
+		open($FILE, '<', "$filename") ||
+			die "$P: $filename: open failed - $!\n";
+	}
+	if ($filename eq '-') {
+		$vname = 'Your patch';
+	} else {
+		$vname = $filename;
+	}
+	while (<$FILE>) {
+		chomp;
+		push(@rawlines, $_);
+	}
+	close($FILE);
+	if (!process($filename)) {
+		$exit = 1;
+	}
+	@rawlines = ();
+	@lines = ();
+}
+
+exit($exit);
+
+sub top_of_openwrt_tree {
+	my ($root) = @_;
+
+	my @tree_check = (
+		"BSDmakefile", "Config.in", "LICENSE", "Makefile", "README",
+		"feeds.conf.default", "include", "package", "rules.mk",
+		"scripts", "target", "toolchain", "tools"
+	);
+
+	foreach my $check (@tree_check) {
+		if (! -e $root . '/' . $check) {
+			return 0;
+		}
+	}
+	return 1;
+    }
+
+sub parse_email {
+	my ($formatted_email) = @_;
+
+	my $name = "";
+	my $address = "";
+	my $comment = "";
+
+	if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) {
+		$name = $1;
+		$address = $2;
+		$comment = $3 if defined $3;
+	} elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) {
+		$address = $1;
+		$comment = $2 if defined $2;
+	} elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) {
+		$address = $1;
+		$comment = $2 if defined $2;
+		$formatted_email =~ s/$address.*$//;
+		$name = $formatted_email;
+		$name =~ s/^\s+|\s+$//g;
+		$name =~ s/^\"|\"$//g;
+		# If there's a name left after stripping spaces and
+		# leading quotes, and the address doesn't have both
+		# leading and trailing angle brackets, the address
+		# is invalid. ie:
+		#   "joe smith joe@smith.com" bad
+		#   "joe smith <joe@smith.com" bad
+		if ($name ne "" && $address !~ /^<[^>]+>$/) {
+			$name = "";
+			$address = "";
+			$comment = "";
+		}
+	}
+
+	$name =~ s/^\s+|\s+$//g;
+	$name =~ s/^\"|\"$//g;
+	$address =~ s/^\s+|\s+$//g;
+	$address =~ s/^\<|\>$//g;
+
+	if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
+		$name =~ s/(?<!\\)"/\\"/g; ##escape quotes
+		$name = "\"$name\"";
+	}
+
+	return ($name, $address, $comment);
+}
+
+sub format_email {
+	my ($name, $address) = @_;
+
+	my $formatted_email;
+
+	$name =~ s/^\s+|\s+$//g;
+	$name =~ s/^\"|\"$//g;
+	$address =~ s/^\s+|\s+$//g;
+
+	if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
+		$name =~ s/(?<!\\)"/\\"/g; ##escape quotes
+		$name = "\"$name\"";
+	}
+
+	if ("$name" eq "") {
+		$formatted_email = "$address";
+	} else {
+		$formatted_email = "$name <$address>";
+	}
+
+	return $formatted_email;
+}
+
+sub which_conf {
+	my ($conf) = @_;
+
+	foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+		if (-e "$path/$conf") {
+			return "$path/$conf";
+		}
+	}
+
+	return "";
+}
+
+sub expand_tabs {
+	my ($str) = @_;
+
+	my $res = '';
+	my $n = 0;
+	for my $c (split(//, $str)) {
+		if ($c eq "\t") {
+			$res .= ' ';
+			$n++;
+			for (; ($n % 8) != 0; $n++) {
+				$res .= ' ';
+			}
+			next;
+		}
+		$res .= $c;
+		$n++;
+	}
+
+	return $res;
+}
+sub copy_spacing {
+	(my $res = shift) =~ tr/\t/ /c;
+	return $res;
+}
+
+sub line_stats {
+	my ($line) = @_;
+
+	# Drop the diff line leader and expand tabs
+	$line =~ s/^.//;
+	$line = expand_tabs($line);
+
+	# Pick the indent from the front of the line.
+	my ($white) = ($line =~ /^(\s*)/);
+
+	return (length($line), length($white));
+}
+
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+	my ($in_comment) = @_;
+
+	if ($in_comment) {
+		$sanitise_quote = '*/';
+	} else {
+		$sanitise_quote = '';
+	}
+}
+sub sanitise_line {
+	my ($line) = @_;
+
+	my $res = '';
+	my $l = '';
+
+	my $qlen = 0;
+	my $off = 0;
+	my $c;
+
+	# Always copy over the diff marker.
+	$res = substr($line, 0, 1);
+
+	for ($off = 1; $off < length($line); $off++) {
+		$c = substr($line, $off, 1);
+
+		# Comments we are wacking completly including the begin
+		# and end, all to $;.
+		if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+			$sanitise_quote = '*/';
+
+			substr($res, $off, 2, "$;$;");
+			$off++;
+			next;
+		}
+		if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
+			$sanitise_quote = '';
+			substr($res, $off, 2, "$;$;");
+			$off++;
+			next;
+		}
+		if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
+			$sanitise_quote = '//';
+
+			substr($res, $off, 2, $sanitise_quote);
+			$off++;
+			next;
+		}
+
+		# A \ in a string means ignore the next character.
+		if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+		    $c eq "\\") {
+			substr($res, $off, 2, 'XX');
+			$off++;
+			next;
+		}
+		# Regular quotes.
+		if ($c eq "'" || $c eq '"') {
+			if ($sanitise_quote eq '') {
+				$sanitise_quote = $c;
+
+				substr($res, $off, 1, $c);
+				next;
+			} elsif ($sanitise_quote eq $c) {
+				$sanitise_quote = '';
+			}
+		}
+
+		#print "c<$c> SQ<$sanitise_quote>\n";
+		if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+			substr($res, $off, 1, $;);
+		} elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
+			substr($res, $off, 1, $;);
+		} elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+			substr($res, $off, 1, 'X');
+		} else {
+			substr($res, $off, 1, $c);
+		}
+	}
+
+	if ($sanitise_quote eq '//') {
+		$sanitise_quote = '';
+	}
+
+	# The pathname on a #include may be surrounded by '<' and '>'.
+	if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
+		my $clean = 'X' x length($1);
+		$res =~ s@\<.*\>@<$clean>@;
+
+	# The whole of a #error is a string.
+	} elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
+		my $clean = 'X' x length($1);
+		$res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
+	}
+
+	return $res;
+}
+
+sub ctx_statement_block {
+	my ($linenr, $remain, $off) = @_;
+	my $line = $linenr - 1;
+	my $blk = '';
+	my $soff = $off;
+	my $coff = $off - 1;
+	my $coff_set = 0;
+
+	my $loff = 0;
+
+	my $type = '';
+	my $level = 0;
+	my @stack = ();
+	my $p;
+	my $c;
+	my $len = 0;
+
+	my $remainder;
+	while (1) {
+		@stack = (['', 0]) if ($#stack == -1);
+
+		#warn "CSB: blk<$blk> remain<$remain>\n";
+		# If we are about to drop off the end, pull in more
+		# context.
+		if ($off >= $len) {
+			for (; $remain > 0; $line++) {
+				last if (!defined $lines[$line]);
+				next if ($lines[$line] =~ /^-/);
+				$remain--;
+				$loff = $len;
+				$blk .= $lines[$line] . "\n";
+				$len = length($blk);
+				$line++;
+				last;
+			}
+			# Bail if there is no further context.
+			#warn "CSB: blk<$blk> off<$off> len<$len>\n";
+			if ($off >= $len) {
+				last;
+			}
+			if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) {
+				$level++;
+				$type = '#';
+			}
+		}
+		$p = $c;
+		$c = substr($blk, $off, 1);
+		$remainder = substr($blk, $off);
+
+		#warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
+
+		# Handle nested #if/#else.
+		if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
+			push(@stack, [ $type, $level ]);
+		} elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
+			($type, $level) = @{$stack[$#stack - 1]};
+		} elsif ($remainder =~ /^#\s*endif\b/) {
+			($type, $level) = @{pop(@stack)};
+		}
+
+		# Statement ends at the ';' or a close '}' at the
+		# outermost level.
+		if ($level == 0 && $c eq ';') {
+			last;
+		}
+
+		# An else is really a conditional as long as its not else if
+		if ($level == 0 && $coff_set == 0 &&
+				(!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+				$remainder =~ /^(else)(?:\s|{)/ &&
+				$remainder !~ /^else\s+if\b/) {
+			$coff = $off + length($1) - 1;
+			$coff_set = 1;
+			#warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+			#warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
+		}
+
+		if (($type eq '' || $type eq '(') && $c eq '(') {
+			$level++;
+			$type = '(';
+		}
+		if ($type eq '(' && $c eq ')') {
+			$level--;
+			$type = ($level != 0)? '(' : '';
+
+			if ($level == 0 && $coff < $soff) {
+				$coff = $off;
+				$coff_set = 1;
+				#warn "CSB: mark coff<$coff>\n";
+			}
+		}
+		if (($type eq '' || $type eq '{') && $c eq '{') {
+			$level++;
+			$type = '{';
+		}
+		if ($type eq '{' && $c eq '}') {
+			$level--;
+			$type = ($level != 0)? '{' : '';
+
+			if ($level == 0) {
+				if (substr($blk, $off + 1, 1) eq ';') {
+					$off++;
+				}
+				last;
+			}
+		}
+		# Preprocessor commands end at the newline unless escaped.
+		if ($type eq '#' && $c eq "\n" && $p ne "\\") {
+			$level--;
+			$type = '';
+			$off++;
+			last;
+		}
+		$off++;
+	}
+	# We are truly at the end, so shuffle to the next line.
+	if ($off == $len) {
+		$loff = $len + 1;
+		$line++;
+		$remain--;
+	}
+
+	my $statement = substr($blk, $soff, $off - $soff + 1);
+	my $condition = substr($blk, $soff, $coff - $soff + 1);
+
+	#warn "STATEMENT<$statement>\n";
+	#warn "CONDITION<$condition>\n";
+
+	#print "coff<$coff> soff<$off> loff<$loff>\n";
+
+	return ($statement, $condition,
+			$line, $remain + 1, $off - $loff + 1, $level);
+}
+
+sub statement_lines {
+	my ($stmt) = @_;
+
+	# Strip the diff line prefixes and rip blank lines at start and end.
+	$stmt =~ s/(^|\n)./$1/g;
+	$stmt =~ s/^\s*//;
+	$stmt =~ s/\s*$//;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+
+	return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+	my ($stmt) = @_;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+
+	return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+	my ($stmt) = @_;
+
+	$stmt =~ s/(^|\n)./$1/g;
+	$stmt =~ s/^\s*{//;
+	$stmt =~ s/}\s*$//;
+	$stmt =~ s/^\s*//;
+	$stmt =~ s/\s*$//;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+	my @stmt_statements = ($stmt =~ /;/g);
+
+	my $stmt_lines = $#stmt_lines + 2;
+	my $stmt_statements = $#stmt_statements + 1;
+
+	if ($stmt_lines > $stmt_statements) {
+		return $stmt_lines;
+	} else {
+		return $stmt_statements;
+	}
+}
+
+sub ctx_statement_full {
+	my ($linenr, $remain, $off) = @_;
+	my ($statement, $condition, $level);
+
+	my (@chunks);
+
+	# Grab the first conditional/block pair.
+	($statement, $condition, $linenr, $remain, $off, $level) =
+				ctx_statement_block($linenr, $remain, $off);
+	#print "F: c<$condition> s<$statement> remain<$remain>\n";
+	push(@chunks, [ $condition, $statement ]);
+	if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+		return ($level, $linenr, @chunks);
+	}
+
+	# Pull in the following conditional/block pairs and see if they
+	# could continue the statement.
+	for (;;) {
+		($statement, $condition, $linenr, $remain, $off, $level) =
+				ctx_statement_block($linenr, $remain, $off);
+		#print "C: c<$condition> s<$statement> remain<$remain>\n";
+		last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+		#print "C: push\n";
+		push(@chunks, [ $condition, $statement ]);
+	}
+
+	return ($level, $linenr, @chunks);
+}
+
+sub ctx_block_get {
+	my ($linenr, $remain, $outer, $open, $close, $off) = @_;
+	my $line;
+	my $start = $linenr - 1;
+	my $blk = '';
+	my @o;
+	my @c;
+	my @res = ();
+
+	my $level = 0;
+	my @stack = ($level);
+	for ($line = $start; $remain > 0; $line++) {
+		next if ($rawlines[$line] =~ /^-/);
+		$remain--;
+
+		$blk .= $rawlines[$line];
+
+		# Handle nested #if/#else.
+		if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+			push(@stack, $level);
+		} elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+			$level = $stack[$#stack - 1];
+		} elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
+			$level = pop(@stack);
+		}
+
+		foreach my $c (split(//, $lines[$line])) {
+			##print "C<$c>L<$level><$open$close>O<$off>\n";
+			if ($off > 0) {
+				$off--;
+				next;
+			}
+
+			if ($c eq $close && $level > 0) {
+				$level--;
+				last if ($level == 0);
+			} elsif ($c eq $open) {
+				$level++;
+			}
+		}
+
+		if (!$outer || $level <= 1) {
+			push(@res, $rawlines[$line]);
+		}
+
+		last if ($level == 0);
+	}
+
+	return ($level, @res);
+}
+sub ctx_block_outer {
+	my ($linenr, $remain) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+	return @r;
+}
+sub ctx_block {
+	my ($linenr, $remain) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+	return @r;
+}
+sub ctx_statement {
+	my ($linenr, $remain, $off) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+	return @r;
+}
+sub ctx_block_level {
+	my ($linenr, $remain) = @_;
+
+	return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+}
+sub ctx_statement_level {
+	my ($linenr, $remain, $off) = @_;
+
+	return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+}
+
+sub ctx_locate_comment {
+	my ($first_line, $end_line) = @_;
+
+	# Catch a comment on the end of the line itself.
+	my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@);
+	return $current_comment if (defined $current_comment);
+
+	# Look through the context and try and figure out if there is a
+	# comment.
+	my $in_comment = 0;
+	$current_comment = '';
+	for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+		my $line = $rawlines[$linenr - 1];
+		#warn "           $line\n";
+		if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+			$in_comment = 1;
+		}
+		if ($line =~ m@/\*@) {
+			$in_comment = 1;
+		}
+		if (!$in_comment && $current_comment ne '') {
+			$current_comment = '';
+		}
+		$current_comment .= $line . "\n" if ($in_comment);
+		if ($line =~ m@\*/@) {
+			$in_comment = 0;
+		}
+	}
+
+	chomp($current_comment);
+	return($current_comment);
+}
+sub ctx_has_comment {
+	my ($first_line, $end_line) = @_;
+	my $cmt = ctx_locate_comment($first_line, $end_line);
+
+	##print "LINE: $rawlines[$end_line - 1 ]\n";
+	##print "CMMT: $cmt\n";
+
+	return ($cmt ne '');
+}
+
+sub raw_line {
+	my ($linenr, $cnt) = @_;
+
+	my $offset = $linenr - 1;
+	$cnt++;
+
+	my $line;
+	while ($cnt) {
+		$line = $rawlines[$offset++];
+		next if (defined($line) && $line =~ /^-/);
+		$cnt--;
+	}
+
+	return $line;
+}
+
+sub cat_vet {
+	my ($vet) = @_;
+	my ($res, $coded);
+
+	$res = '';
+	while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
+		$res .= $1;
+		if ($2 ne '') {
+			$coded = sprintf("^%c", unpack('C', $2) + 64);
+			$res .= $coded;
+		}
+	}
+	$res =~ s/$/\$/;
+
+	return $res;
+}
+
+my $av_preprocessor = 0;
+my $av_pending;
+my @av_paren_type;
+my $av_pend_colon;
+
+sub annotate_reset {
+	$av_preprocessor = 0;
+	$av_pending = '_';
+	@av_paren_type = ('E');
+	$av_pend_colon = 'O';
+}
+
+sub annotate_values {
+	my ($stream, $type) = @_;
+
+	my $res;
+	my $var = '_' x length($stream);
+	my $cur = $stream;
+
+	print "$stream\n" if ($dbg_values > 1);
+
+	while (length($cur)) {
+		@av_paren_type = ('E') if ($#av_paren_type < 0);
+		print " <" . join('', @av_paren_type) .
+				"> <$type> <$av_pending>" if ($dbg_values > 1);
+		if ($cur =~ /^(\s+)/o) {
+			print "WS($1)\n" if ($dbg_values > 1);
+			if ($1 =~ /\n/ && $av_preprocessor) {
+				$type = pop(@av_paren_type);
+				$av_preprocessor = 0;
+			}
+
+		} elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
+			print "CAST($1)\n" if ($dbg_values > 1);
+			push(@av_paren_type, $type);
+			$type = 'c';
+
+		} elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
+			print "DECLARE($1)\n" if ($dbg_values > 1);
+			$type = 'T';
+
+		} elsif ($cur =~ /^($Modifier)\s*/) {
+			print "MODIFIER($1)\n" if ($dbg_values > 1);
+			$type = 'T';
+
+		} elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
+			print "DEFINE($1,$2)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+			push(@av_paren_type, $type);
+			if ($2 ne '') {
+				$av_pending = 'N';
+			}
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
+			print "UNDEF($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+			push(@av_paren_type, $type);
+
+		} elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
+			print "PRE_START($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+
+			push(@av_paren_type, $type);
+			push(@av_paren_type, $type);
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
+			print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+
+			push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:endif))/o) {
+			print "PRE_END($1)\n" if ($dbg_values > 1);
+
+			$av_preprocessor = 1;
+
+			# Assume all arms of the conditional end as this
+			# one does, and continue as if the #endif was not here.
+			pop(@av_paren_type);
+			push(@av_paren_type, $type);
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\\\n)/o) {
+			print "PRECONT($1)\n" if ($dbg_values > 1);
+
+		} elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+			print "ATTR($1)\n" if ($dbg_values > 1);
+			$av_pending = $type;
+			$type = 'N';
+
+		} elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
+			print "SIZEOF($1)\n" if ($dbg_values > 1);
+			if (defined $2) {
+				$av_pending = 'V';
+			}
+			$type = 'N';
+
+		} elsif ($cur =~ /^(if|while|for)\b/o) {
+			print "COND($1)\n" if ($dbg_values > 1);
+			$av_pending = 'E';
+			$type = 'N';
+
+		} elsif ($cur =~/^(case)/o) {
+			print "CASE($1)\n" if ($dbg_values > 1);
+			$av_pend_colon = 'C';
+			$type = 'N';
+
+		} elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
+			print "KEYWORD($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(\()/o) {
+			print "PAREN('$1')\n" if ($dbg_values > 1);
+			push(@av_paren_type, $av_pending);
+			$av_pending = '_';
+			$type = 'N';
+
+		} elsif ($cur =~ /^(\))/o) {
+			my $new_type = pop(@av_paren_type);
+			if ($new_type ne '_') {
+				$type = $new_type;
+				print "PAREN('$1') -> $type\n"
+							if ($dbg_values > 1);
+			} else {
+				print "PAREN('$1')\n" if ($dbg_values > 1);
+			}
+
+		} elsif ($cur =~ /^($Ident)\s*\(/o) {
+			print "FUNC($1)\n" if ($dbg_values > 1);
+			$type = 'V';
+			$av_pending = 'V';
+
+		} elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
+			if (defined $2 && $type eq 'C' || $type eq 'T') {
+				$av_pend_colon = 'B';
+			} elsif ($type eq 'E') {
+				$av_pend_colon = 'L';
+			}
+			print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
+			$type = 'V';
+
+		} elsif ($cur =~ /^($Ident|$Constant)/o) {
+			print "IDENT($1)\n" if ($dbg_values > 1);
+			$type = 'V';
+
+		} elsif ($cur =~ /^($Assignment)/o) {
+			print "ASSIGN($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~/^(;|{|})/) {
+			print "END($1)\n" if ($dbg_values > 1);
+			$type = 'E';
+			$av_pend_colon = 'O';
+
+		} elsif ($cur =~/^(,)/) {
+			print "COMMA($1)\n" if ($dbg_values > 1);
+			$type = 'C';
+
+		} elsif ($cur =~ /^(\?)/o) {
+			print "QUESTION($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(:)/o) {
+			print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
+
+			substr($var, length($res), 1, $av_pend_colon);
+			if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
+				$type = 'E';
+			} else {
+				$type = 'N';
+			}
+			$av_pend_colon = 'O';
+
+		} elsif ($cur =~ /^(\[)/o) {
+			print "CLOSE($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
+			my $variant;
+
+			print "OPV($1)\n" if ($dbg_values > 1);
+			if ($type eq 'V') {
+				$variant = 'B';
+			} else {
+				$variant = 'U';
+			}
+
+			substr($var, length($res), 1, $variant);
+			$type = 'N';
+
+		} elsif ($cur =~ /^($Operators)/o) {
+			print "OP($1)\n" if ($dbg_values > 1);
+			if ($1 ne '++' && $1 ne '--') {
+				$type = 'N';
+			}
+
+		} elsif ($cur =~ /(^.)/o) {
+			print "C($1)\n" if ($dbg_values > 1);
+		}
+		if (defined $1) {
+			$cur = substr($cur, length($1));
+			$res .= $type x length($1);
+		}
+	}
+
+	return ($res, $var);
+}
+
+sub possible {
+	my ($possible, $line) = @_;
+	my $notPermitted = qr{(?:
+		^(?:
+			$Modifier|
+			$Storage|
+			$Type|
+			DEFINE_\S+
+		)$|
+		^(?:
+			goto|
+			return|
+			case|
+			else|
+			asm|__asm__|
+			do|
+			\#|
+			\#\#|
+		)(?:\s|$)|
+		^(?:typedef|struct|enum)\b
+	    )}x;
+	warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+	if ($possible !~ $notPermitted) {
+		# Check for modifiers.
+		$possible =~ s/\s*$Storage\s*//g;
+		$possible =~ s/\s*$Sparse\s*//g;
+		if ($possible =~ /^\s*$/) {
+
+		} elsif ($possible =~ /\s/) {
+			$possible =~ s/\s*$Type\s*//g;
+			for my $modifier (split(' ', $possible)) {
+				if ($modifier !~ $notPermitted) {
+					warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
+					push(@modifierList, $modifier);
+				}
+			}
+
+		} else {
+			warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
+			push(@typeList, $possible);
+		}
+		build_types();
+	} else {
+		warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
+	}
+}
+
+my $prefix = '';
+
+sub show_type {
+       return !defined $ignore_type{$_[0]};
+}
+
+sub report {
+	if (!show_type($_[1]) ||
+	    (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) {
+		return 0;
+	}
+	my $line;
+	if ($show_types) {
+		$line = "$prefix$_[0]:$_[1]: $_[2]\n";
+	} else {
+		$line = "$prefix$_[0]: $_[2]\n";
+	}
+	$line = (split('\n', $line))[0] . "\n" if ($terse);
+
+	push(our @report, $line);
+
+	return 1;
+}
+sub report_dump {
+	our @report;
+}
+
+sub ERROR {
+	if (report("ERROR", $_[0], $_[1])) {
+		our $clean = 0;
+		our $cnt_error++;
+	}
+}
+sub WARN {
+	if (report("WARNING", $_[0], $_[1])) {
+		our $clean = 0;
+		our $cnt_warn++;
+	}
+}
+sub CHK {
+	if ($check && report("CHECK", $_[0], $_[1])) {
+		our $clean = 0;
+		our $cnt_chk++;
+	}
+}
+
+sub check_absolute_file {
+	my ($absolute, $herecurr) = @_;
+	my $file = $absolute;
+
+	##print "absolute<$absolute>\n";
+
+	# See if any suffix of this path is a path within the tree.
+	while ($file =~ s@^[^/]*/@@) {
+		if (-f "$root/$file") {
+			##print "file<$file>\n";
+			last;
+		}
+	}
+	if (! -f _)  {
+		return 0;
+	}
+
+	# It is, so see if the prefix is acceptable.
+	my $prefix = $absolute;
+	substr($prefix, -length($file)) = '';
+
+	##print "prefix<$prefix>\n";
+	if ($prefix ne ".../") {
+		WARN("USE_RELATIVE_PATH",
+		     "use relative pathname instead of absolute in changelog text\n" . $herecurr);
+	}
+}
+
+sub pos_last_openparen {
+	my ($line) = @_;
+
+	my $pos = 0;
+
+	my $opens = $line =~ tr/\(/\(/;
+	my $closes = $line =~ tr/\)/\)/;
+
+	my $last_openparen = 0;
+
+	if (($opens == 0) || ($closes >= $opens)) {
+		return -1;
+	}
+
+	my $len = length($line);
+
+	for ($pos = 0; $pos < $len; $pos++) {
+		my $string = substr($line, $pos);
+		if ($string =~ /^($FuncArg|$balanced_parens)/) {
+			$pos += length($1) - 1;
+		} elsif (substr($line, $pos, 1) eq '(') {
+			$last_openparen = $pos;
+		} elsif (index($string, '(') == -1) {
+			last;
+		}
+	}
+
+	return $last_openparen + 1;
+}
+
+sub process {
+	my $filename = shift;
+
+	my $linenr=0;
+	my $prevline="";
+	my $prevrawline="";
+	my $stashline="";
+	my $stashrawline="";
+
+	my $length;
+	my $indent;
+	my $previndent=0;
+	my $stashindent=0;
+
+	our $clean = 1;
+	my $signoff = 0;
+	my $is_patch = 0;
+
+	my $in_header_lines = 1;
+	my $in_commit_log = 0;		#Scanning lines before patch
+
+	our @report = ();
+	our $cnt_lines = 0;
+	our $cnt_error = 0;
+	our $cnt_warn = 0;
+	our $cnt_chk = 0;
+
+	# Trace the real file/line as we go.
+	my $realfile = '';
+	my $realline = 0;
+	my $realcnt = 0;
+	my $here = '';
+	my $in_comment = 0;
+	my $comment_edge = 0;
+	my $first_line = 0;
+	my $p1_prefix = '';
+
+	my $prev_values = 'E';
+
+	# suppression flags
+	my %suppress_ifbraces;
+	my %suppress_whiletrailers;
+	my %suppress_export;
+	my $suppress_statement = 0;
+
+	# Pre-scan the patch sanitizing the lines.
+	sanitise_line_reset();
+	my $line;
+	foreach my $rawline (@rawlines) {
+		$linenr++;
+		$line = $rawline;
+
+		if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+			$realline=$1-1;
+			if (defined $2) {
+				$realcnt=$3+1;
+			} else {
+				$realcnt=1+1;
+			}
+			$in_comment = 0;
+
+			# Guestimate if this is a continuing comment.  Run
+			# the context looking for a comment "edge".  If this
+			# edge is a close comment then we must be in a comment
+			# at context start.
+			my $edge;
+			my $cnt = $realcnt;
+			for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+				next if (defined $rawlines[$ln - 1] &&
+					 $rawlines[$ln - 1] =~ /^-/);
+				$cnt--;
+				#print "RAW<$rawlines[$ln - 1]>\n";
+				last if (!defined $rawlines[$ln - 1]);
+				if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
+				    $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
+					($edge) = $1;
+					last;
+				}
+			}
+			if (defined $edge && $edge eq '*/') {
+				$in_comment = 1;
+			}
+
+			# Guestimate if this is a continuing comment.  If this
+			# is the start of a diff block and this line starts
+			# ' *' then it is very likely a comment.
+			if (!defined $edge &&
+			    $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
+			{
+				$in_comment = 1;
+			}
+
+			##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+			sanitise_line_reset($in_comment);
+
+		} elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
+			# Standardise the strings and chars within the input to
+			# simplify matching -- only bother with positive lines.
+			$line = sanitise_line($rawline);
+		}
+		push(@lines, $line);
+
+		if ($realcnt > 1) {
+			$realcnt-- if ($line =~ /^(?:\+| |$)/);
+		} else {
+			$realcnt = 0;
+		}
+
+		#print "==>$rawline\n";
+		#print "-->$line\n";
+	}
+
+	$prefix = '';
+
+	$realcnt = 0;
+	$linenr = 0;
+	foreach my $line (@lines) {
+		$linenr++;
+
+		my $rawline = $rawlines[$linenr - 1];
+
+#extract the line range in the file after the patch is applied
+		if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+			$is_patch = 1;
+			$first_line = $linenr + 1;
+			$realline=$1-1;
+			if (defined $2) {
+				$realcnt=$3+1;
+			} else {
+				$realcnt=1+1;
+			}
+			annotate_reset();
+			$prev_values = 'E';
+
+			%suppress_ifbraces = ();
+			%suppress_whiletrailers = ();
+			%suppress_export = ();
+			$suppress_statement = 0;
+			next;
+
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+		} elsif ($line =~ /^( |\+|$)/) {
+			$realline++;
+			$realcnt-- if ($realcnt != 0);
+
+			# Measure the line length and indent.
+			($length, $indent) = line_stats($rawline);
+
+			# Track the previous line.
+			($prevline, $stashline) = ($stashline, $line);
+			($previndent, $stashindent) = ($stashindent, $indent);
+			($prevrawline, $stashrawline) = ($stashrawline, $rawline);
+
+			#warn "line<$line>\n";
+
+		} elsif ($realcnt == 1) {
+			$realcnt--;
+		}
+
+		my $hunk_line = ($realcnt != 0);
+
+#make up the handle for any error we report on this line
+		$prefix = "$filename:$realline: " if ($emacs && $file);
+		$prefix = "$filename:$linenr: " if ($emacs && !$file);
+
+		$here = "#$linenr: " if (!$file);
+		$here = "#$realline: " if ($file);
+
+		# extract the filename as it passes
+		if ($line =~ /^diff --git.*?(\S+)$/) {
+			$realfile = $1;
+			$realfile =~ s@^([^/]*)/@@;
+			$in_commit_log = 0;
+		} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
+			$realfile = $1;
+			$realfile =~ s@^([^/]*)/@@;
+			$in_commit_log = 0;
+
+			$p1_prefix = $1;
+			if (!$file && $tree && $p1_prefix ne '' &&
+			    -e "$root/$p1_prefix") {
+				WARN("PATCH_PREFIX",
+				     "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
+			}
+
+			if ($realfile =~ m@^include/asm/@) {
+				ERROR("MODIFIED_INCLUDE_ASM",
+				      "do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+			}
+			next;
+		}
+
+		$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
+
+		my $hereline = "$here\n$rawline\n";
+		my $herecurr = "$here\n$rawline\n";
+		my $hereprev = "$here\n$prevrawline\n$rawline\n";
+
+		$cnt_lines++ if ($realcnt != 0);
+
+# Check for incorrect file permissions
+		if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+			my $permhere = $here . "FILE: $realfile\n";
+			if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+				ERROR("EXECUTE_PERMISSIONS",
+				      "do not set execute permissions for source files\n" . $permhere);
+			}
+		}
+
+# Check the patch for a signoff:
+		if ($line =~ /^\s*signed-off-by:/i) {
+			$signoff++;
+			$in_commit_log = 0;
+		}
+
+# Check signature styles
+		if (!$in_header_lines &&
+		    $line =~ /^(\s*)($signature_tags)(\s*)(.*)/) {
+			my $space_before = $1;
+			my $sign_off = $2;
+			my $space_after = $3;
+			my $email = $4;
+			my $ucfirst_sign_off = ucfirst(lc($sign_off));
+
+			if (defined $space_before && $space_before ne "") {
+				WARN("BAD_SIGN_OFF",
+				     "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr);
+			}
+			if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) {
+				WARN("BAD_SIGN_OFF",
+				     "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr);
+			}
+			if (!defined $space_after || $space_after ne " ") {
+				WARN("BAD_SIGN_OFF",
+				     "Use a single space after $ucfirst_sign_off\n" . $herecurr);
+			}
+
+			my ($email_name, $email_address, $comment) = parse_email($email);
+			my $suggested_email = format_email(($email_name, $email_address));
+			if ($suggested_email eq "") {
+				ERROR("BAD_SIGN_OFF",
+				      "Unrecognized email address: '$email'\n" . $herecurr);
+			} else {
+				my $dequoted = $suggested_email;
+				$dequoted =~ s/^"//;
+				$dequoted =~ s/" </ </;
+				# Don't force email to have quotes
+				# Allow just an angle bracketed address
+				if ("$dequoted$comment" ne $email &&
+				    "<$email_address>$comment" ne $email &&
+				    "$suggested_email$comment" ne $email) {
+					WARN("BAD_SIGN_OFF",
+					     "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr);
+				}
+			}
+		}
+
+# Check for wrappage within a valid hunk of the file
+		if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
+			ERROR("CORRUPTED_PATCH",
+			      "patch seems to be corrupt (line wrapped?)\n" .
+				$herecurr) if (!$emitted_corrupt++);
+		}
+
+# Check for absolute kernel paths.
+		if ($tree) {
+			while ($line =~ m{(?:^|\s)(/\S*)}g) {
+				my $file = $1;
+
+				if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+				    check_absolute_file($1, $herecurr)) {
+					#
+				} else {
+					check_absolute_file($file, $herecurr);
+				}
+			}
+		}
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+		if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+		    $rawline !~ m/^$UTF8*$/) {
+			my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+			my $blank = copy_spacing($rawline);
+			my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+			my $hereptr = "$hereline$ptr\n";
+
+			CHK("INVALID_UTF8",
+			    "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
+		}
+
+# Check if it's the start of a commit log
+# (not a header line and we haven't seen the patch filename)
+		if ($in_header_lines && $realfile =~ /^$/ &&
+		    $rawline !~ /^(commit\b|from\b|[\w-]+:).+$/i) {
+			$in_header_lines = 0;
+			$in_commit_log = 1;
+		}
+
+# Still not yet in a patch, check for any UTF-8
+		if ($in_commit_log && $realfile =~ /^$/ &&
+		    $rawline =~ /$NON_ASCII_UTF8/) {
+			CHK("UTF8_BEFORE_PATCH",
+			    "8-bit UTF-8 used in possible commit log\n" . $herecurr);
+		}
+
+# ignore non-hunk lines and lines being removed
+		next if (!$hunk_line || $line =~ /^-/);
+
+#trailing whitespace
+		if ($line =~ /^\+.*\015/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("DOS_LINE_ENDINGS",
+			      "DOS line endings\n" . $herevet);
+
+		} elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("TRAILING_WHITESPACE",
+			      "trailing whitespace\n" . $herevet);
+			$rpt_cleaners = 1;
+		}
+
+# check for Kconfig help text having a real description
+# Only applies when adding the entry originally, after that we do not have
+# sufficient context to determine whether it is indeed long enough.
+		if ($realfile =~ /Kconfig/ &&
+		    $line =~ /.\s*config\s+/) {
+			my $length = 0;
+			my $cnt = $realcnt;
+			my $ln = $linenr + 1;
+			my $f;
+			my $is_start = 0;
+			my $is_end = 0;
+			for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) {
+				$f = $lines[$ln - 1];
+				$cnt-- if ($lines[$ln - 1] !~ /^-/);
+				$is_end = $lines[$ln - 1] =~ /^\+/;
+
+				next if ($f =~ /^-/);
+
+				if ($lines[$ln - 1] =~ /.\s*(?:bool|tristate)\s*\"/) {
+					$is_start = 1;
+				} elsif ($lines[$ln - 1] =~ /.\s*(?:---)?help(?:---)?$/) {
+					$length = -1;
+				}
+
+				$f =~ s/^.//;
+				$f =~ s/#.*//;
+				$f =~ s/^\s+//;
+				next if ($f =~ /^$/);
+				if ($f =~ /^\s*config\s/) {
+					$is_end = 1;
+					last;
+				}
+				$length++;
+			}
+			WARN("CONFIG_DESCRIPTION",
+			     "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_start && $is_end && $length < 4);
+			#print "is_start<$is_start> is_end<$is_end> length<$length>\n";
+		}
+
+		if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) &&
+		    ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) {
+			my $flag = $1;
+			my $replacement = {
+				'EXTRA_AFLAGS' =>   'asflags-y',
+				'EXTRA_CFLAGS' =>   'ccflags-y',
+				'EXTRA_CPPFLAGS' => 'cppflags-y',
+				'EXTRA_LDFLAGS' =>  'ldflags-y',
+			};
+
+			WARN("DEPRECATED_VARIABLE",
+			     "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag});
+		}
+
+# check we are in a valid source file if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
+#80 column limit
+		if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
+		    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+		    !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ ||
+		    $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
+		    $length > 80)
+		{
+			WARN("LONG_LINE",
+			     "line over 80 characters\n" . $herecurr);
+		}
+
+# Check for user-visible strings broken across lines, which breaks the ability
+# to grep for the string.  Limited to strings used as parameters (those
+# following an open parenthesis), which almost completely eliminates false
+# positives, as well as warning only once per parameter rather than once per
+# line of the string.  Make an exception when the previous string ends in a
+# newline (multiple lines in one string constant) or \n\t (common in inline
+# assembly to indent the instruction on the following line).
+		if ($line =~ /^\+\s*"/ &&
+		    $prevline =~ /"\s*$/ &&
+		    $prevline =~ /\(/ &&
+		    $prevrawline !~ /\\n(?:\\t)*"\s*$/) {
+			WARN("SPLIT_STRING",
+			     "quoted string split across lines\n" . $hereprev);
+		}
+
+# check for spaces before a quoted newline
+		if ($rawline =~ /^.*\".*\s\\n/) {
+			WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
+			     "unnecessary whitespace before a quoted newline\n" . $herecurr);
+		}
+
+# check for adding lines without a newline.
+		if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
+			WARN("MISSING_EOF_NEWLINE",
+			     "adding a line without newline at end of file\n" . $herecurr);
+		}
+
+# Blackfin: use hi/lo macros
+		if ($realfile =~ m@arch/blackfin/.*\.S$@) {
+			if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
+				my $herevet = "$here\n" . cat_vet($line) . "\n";
+				ERROR("LO_MACRO",
+				      "use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
+			}
+			if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
+				my $herevet = "$here\n" . cat_vet($line) . "\n";
+				ERROR("HI_MACRO",
+				      "use the HI() macro, not (... >> 16)\n" . $herevet);
+			}
+		}
+
+# check we are in a valid source file C or perl if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c|pl)$/);
+
+# at the beginning of a line any tabs must come first and anything
+# more than 8 must use tabs.
+		if ($rawline =~ /^\+\s* \t\s*\S/ ||
+		    $rawline =~ /^\+\s*        \s*/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("CODE_INDENT",
+			      "code indent should use tabs where possible\n" . $herevet);
+			$rpt_cleaners = 1;
+		}
+
+# check for space before tabs.
+		if ($rawline =~ /^\+/ && $rawline =~ / \t/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			WARN("SPACE_BEFORE_TAB",
+			     "please, no space before tabs\n" . $herevet);
+		}
+
+# check for && or || at the start of a line
+		if ($rawline =~ /^\+\s*(&&|\|\|)/) {
+			CHK("LOGICAL_CONTINUATIONS",
+			    "Logical continuations should be on the previous line\n" . $hereprev);
+		}
+
+# check multi-line statement indentation matches previous line
+		if ($^V && $^V ge 5.10.0 &&
+		    $prevline =~ /^\+(\t*)(if \(|$Ident\().*(\&\&|\|\||,)\s*$/) {
+			$prevline =~ /^\+(\t*)(.*)$/;
+			my $oldindent = $1;
+			my $rest = $2;
+
+			my $pos = pos_last_openparen($rest);
+			if ($pos >= 0) {
+				$line =~ /^\+([ \t]*)/;
+				my $newindent = $1;
+
+				my $goodtabindent = $oldindent .
+					"\t" x ($pos / 8) .
+					" "  x ($pos % 8);
+				my $goodspaceindent = $oldindent . " "  x $pos;
+
+				if ($newindent ne $goodtabindent &&
+				    $newindent ne $goodspaceindent) {
+					CHK("PARENTHESIS_ALIGNMENT",
+					    "Alignment should match open parenthesis\n" . $hereprev);
+				}
+			}
+		}
+
+		if ($line =~ /^\+.*\*[ \t]*\)[ \t]+/) {
+			CHK("SPACING",
+			    "No space is necessary after a cast\n" . $hereprev);
+		}
+
+		if ($rawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
+		    $prevrawline =~ /^\+[ \t]*$/) {
+			CHK("BLOCK_COMMENT_STYLE",
+			    "Don't begin block comments with only a /* line, use /* comment...\n" . $hereprev);
+		}
+
+# check for spaces at the beginning of a line.
+# Exceptions:
+#  1) within comments
+#  2) indented preprocessor commands
+#  3) hanging labels
+		if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/)  {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			WARN("LEADING_SPACE",
+			     "please, no spaces at the start of a line\n" . $herevet);
+		}
+
+# check we are in a valid C source file if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c)$/);
+
+# check for RCS/CVS revision markers
+		if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
+			WARN("CVS_KEYWORD",
+			     "CVS style keyword markers, these will _not_ be updated\n". $herecurr);
+		}
+
+# Blackfin: don't use __builtin_bfin_[cs]sync
+		if ($line =~ /__builtin_bfin_csync/) {
+			my $herevet = "$here\n" . cat_vet($line) . "\n";
+			ERROR("CSYNC",
+			      "use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
+		}
+		if ($line =~ /__builtin_bfin_ssync/) {
+			my $herevet = "$here\n" . cat_vet($line) . "\n";
+			ERROR("SSYNC",
+			      "use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
+		}
+
+# Check for potential 'bare' types
+		my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
+		    $realline_next);
+#print "LINE<$line>\n";
+		if ($linenr >= $suppress_statement &&
+		    $realcnt && $line =~ /.\s*\S/) {
+			($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+				ctx_statement_block($linenr, $realcnt, 0);
+			$stat =~ s/\n./\n /g;
+			$cond =~ s/\n./\n /g;
+
+#print "linenr<$linenr> <$stat>\n";
+			# If this statement has no statement boundaries within
+			# it there is no point in retrying a statement scan
+			# until we hit end of it.
+			my $frag = $stat; $frag =~ s/;+\s*$//;
+			if ($frag !~ /(?:{|;)/) {
+#print "skip<$line_nr_next>\n";
+				$suppress_statement = $line_nr_next;
+			}
+
+			# Find the real next line.
+			$realline_next = $line_nr_next;
+			if (defined $realline_next &&
+			    (!defined $lines[$realline_next - 1] ||
+			     substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) {
+				$realline_next++;
+			}
+
+			my $s = $stat;
+			$s =~ s/{.*$//s;
+
+			# Ignore goto labels.
+			if ($s =~ /$Ident:\*$/s) {
+
+			# Ignore functions being called
+			} elsif ($s =~ /^.\s*$Ident\s*\(/s) {
+
+			} elsif ($s =~ /^.\s*else\b/s) {
+
+			# declarations always start with types
+			} elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
+				my $type = $1;
+				$type =~ s/\s+/ /g;
+				possible($type, "A:" . $s);
+
+			# definitions in global scope can only start with types
+			} elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
+				possible($1, "B:" . $s);
+			}
+
+			# any (foo ... *) is a pointer cast, and foo is a type
+			while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) {
+				possible($1, "C:" . $s);
+			}
+
+			# Check for any sort of function declaration.
+			# int foo(something bar, other baz);
+			# void (*store_gdt)(x86_descr_ptr *);
+			if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
+				my ($name_len) = length($1);
+
+				my $ctx = $s;
+				substr($ctx, 0, $name_len + 1, '');
+				$ctx =~ s/\)[^\)]*$//;
+
+				for my $arg (split(/\s*,\s*/, $ctx)) {
+					if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {
+
+						possible($1, "D:" . $s);
+					}
+				}
+			}
+
+		}
+
+#
+# Checks which may be anchored in the context.
+#
+
+# Check for switch () and associated case and default
+# statements should be at the same indent.
+		if ($line=~/\bswitch\s*\(.*\)/) {
+			my $err = '';
+			my $sep = '';
+			my @ctx = ctx_block_outer($linenr, $realcnt);
+			shift(@ctx);
+			for my $ctx (@ctx) {
+				my ($clen, $cindent) = line_stats($ctx);
+				if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+							$indent != $cindent) {
+					$err .= "$sep$ctx\n";
+					$sep = '';
+				} else {
+					$sep = "[...]\n";
+				}
+			}
+			if ($err ne '') {
+				ERROR("SWITCH_CASE_INDENT_LEVEL",
+				      "switch and case should be at the same indent\n$hereline$err");
+			}
+		}
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+		if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+			my $pre_ctx = "$1$2";
+
+			my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
+
+			if ($line =~ /^\+\t{6,}/) {
+				WARN("DEEP_INDENTATION",
+				     "Too many leading tabs - consider code refactoring\n" . $herecurr);
+			}
+
+			my $ctx_cnt = $realcnt - $#ctx - 1;
+			my $ctx = join("\n", @ctx);
+
+			my $ctx_ln = $linenr;
+			my $ctx_skip = $realcnt;
+
+			while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+					defined $lines[$ctx_ln - 1] &&
+					$lines[$ctx_ln - 1] =~ /^-/)) {
+				##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+				$ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
+				$ctx_ln++;
+			}
+
+			#print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+			#print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+			if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+				ERROR("OPEN_BRACE",
+				      "that open brace { should be on the previous line\n" .
+					"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+			}
+			if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+			    $ctx =~ /\)\s*\;\s*$/ &&
+			    defined $lines[$ctx_ln - 1])
+			{
+				my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
+				if ($nindent > $indent) {
+					WARN("TRAILING_SEMICOLON",
+					     "trailing semicolon indicates no statements, indent implies otherwise\n" .
+						"$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+				}
+			}
+		}
+
+# Check relative indent for conditionals and blocks.
+		if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+			($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+				ctx_statement_block($linenr, $realcnt, 0)
+					if (!defined $stat);
+			my ($s, $c) = ($stat, $cond);
+
+			substr($s, 0, length($c), '');
+
+			# Make sure we remove the line prefixes as we have
+			# none on the first line, and are going to readd them
+			# where necessary.
+			$s =~ s/\n./\n/gs;
+
+			# Find out how long the conditional actually is.
+			my @newlines = ($c =~ /\n/gs);
+			my $cond_lines = 1 + $#newlines;
+
+			# We want to check the first line inside the block
+			# starting at the end of the conditional, so remove:
+			#  1) any blank line termination
+			#  2) any opening brace { on end of the line
+			#  3) any do (...) {
+			my $continuation = 0;
+			my $check = 0;
+			$s =~ s/^.*\bdo\b//;
+			$s =~ s/^\s*{//;
+			if ($s =~ s/^\s*\\//) {
+				$continuation = 1;
+			}
+			if ($s =~ s/^\s*?\n//) {
+				$check = 1;
+				$cond_lines++;
+			}
+
+			# Also ignore a loop construct at the end of a
+			# preprocessor statement.
+			if (($prevline =~ /^.\s*#\s*define\s/ ||
+			    $prevline =~ /\\\s*$/) && $continuation == 0) {
+				$check = 0;
+			}
+
+			my $cond_ptr = -1;
+			$continuation = 0;
+			while ($cond_ptr != $cond_lines) {
+				$cond_ptr = $cond_lines;
+
+				# If we see an #else/#elif then the code
+				# is not linear.
+				if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+					$check = 0;
+				}
+
+				# Ignore:
+				#  1) blank lines, they should be at 0,
+				#  2) preprocessor lines, and
+				#  3) labels.
+				if ($continuation ||
+				    $s =~ /^\s*?\n/ ||
+				    $s =~ /^\s*#\s*?/ ||
+				    $s =~ /^\s*$Ident\s*:/) {
+					$continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+					if ($s =~ s/^.*?\n//) {
+						$cond_lines++;
+					}
+				}
+			}
+
+			my (undef, $sindent) = line_stats("+" . $s);
+			my $stat_real = raw_line($linenr, $cond_lines);
+
+			# Check if either of these lines are modified, else
+			# this is not this patch's fault.
+			if (!defined($stat_real) ||
+			    $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+				$check = 0;
+			}
+			if (defined($stat_real) && $cond_lines > 1) {
+				$stat_real = "[...]\n$stat_real";
+			}
+
+			#print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+			if ($check && (($sindent % 8) != 0 ||
+			    ($sindent <= $indent && $s ne ''))) {
+				WARN("SUSPECT_CODE_INDENT",
+				     "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+			}
+		}
+
+		# Track the 'values' across context and added lines.
+		my $opline = $line; $opline =~ s/^./ /;
+		my ($curr_values, $curr_vars) =
+				annotate_values($opline . "\n", $prev_values);
+		$curr_values = $prev_values . $curr_values;
+		if ($dbg_values) {
+			my $outline = $opline; $outline =~ s/\t/ /g;
+			print "$linenr > .$outline\n";
+			print "$linenr > $curr_values\n";
+			print "$linenr >  $curr_vars\n";
+		}
+		$prev_values = substr($curr_values, -1);
+
+#ignore lines not being added
+		if ($line=~/^[^\+]/) {next;}
+
+# TEST: allow direct testing of the type matcher.
+		if ($dbg_type) {
+			if ($line =~ /^.\s*$Declare\s*$/) {
+				ERROR("TEST_TYPE",
+				      "TEST: is type\n" . $herecurr);
+			} elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+				ERROR("TEST_NOT_TYPE",
+				      "TEST: is not type ($1 is)\n". $herecurr);
+			}
+			next;
+		}
+# TEST: allow direct testing of the attribute matcher.
+		if ($dbg_attr) {
+			if ($line =~ /^.\s*$Modifier\s*$/) {
+				ERROR("TEST_ATTR",
+				      "TEST: is attr\n" . $herecurr);
+			} elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
+				ERROR("TEST_NOT_ATTR",
+				      "TEST: is not attr ($1 is)\n". $herecurr);
+			}
+			next;
+		}
+
+# check for initialisation to aggregates open brace on the next line
+		if ($line =~ /^.\s*{/ &&
+		    $prevline =~ /(?:^|[^=])=\s*$/) {
+			ERROR("OPEN_BRACE",
+			      "that open brace { should be on the previous line\n" . $hereprev);
+		}
+
+#
+# Checks which are anchored on the added line.
+#
+
+# check for malformed paths in #include statements (uses RAW line)
+		if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
+			my $path = $1;
+			if ($path =~ m{//}) {
+				ERROR("MALFORMED_INCLUDE",
+				      "malformed #include filename\n" .
+					$herecurr);
+			}
+		}
+
+# no C99 // comments
+		if ($line =~ m{//}) {
+			ERROR("C99_COMMENTS",
+			      "do not use C99 // comments\n" . $herecurr);
+		}
+		# Remove C99 comments.
+		$line =~ s@//.*@@;
+		$opline =~ s@//.*@@;
+
+# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
+# the whole statement.
+#print "APW <$lines[$realline_next - 1]>\n";
+		if (defined $realline_next &&
+		    exists $lines[$realline_next - 1] &&
+		    !defined $suppress_export{$realline_next} &&
+		    ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+		     $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+			# Handle definitions which produce identifiers with
+			# a prefix:
+			#   XXX(foo);
+			#   EXPORT_SYMBOL(something_foo);
+			my $name = $1;
+			if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
+			    $name =~ /^${Ident}_$2/) {
+#print "FOO C name<$name>\n";
+				$suppress_export{$realline_next} = 1;
+
+			} elsif ($stat !~ /(?:
+				\n.}\s*$|
+				^.DEFINE_$Ident\(\Q$name\E\)|
+				^.DECLARE_$Ident\(\Q$name\E\)|
+				^.LIST_HEAD\(\Q$name\E\)|
+				^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+				\b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
+			    )/x) {
+#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
+				$suppress_export{$realline_next} = 2;
+			} else {
+				$suppress_export{$realline_next} = 1;
+			}
+		}
+		if (!defined $suppress_export{$linenr} &&
+		    $prevline =~ /^.\s*$/ &&
+		    ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+		     $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+#print "FOO B <$lines[$linenr - 1]>\n";
+			$suppress_export{$linenr} = 2;
+		}
+		if (defined $suppress_export{$linenr} &&
+		    $suppress_export{$linenr} == 2) {
+			WARN("EXPORT_SYMBOL",
+			     "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
+		}
+
+# check for global initialisers.
+		if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
+			ERROR("GLOBAL_INITIALISERS",
+			      "do not initialise globals to 0 or NULL\n" .
+				$herecurr);
+		}
+# check for static initialisers.
+		if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+			ERROR("INITIALISED_STATIC",
+			      "do not initialise statics to 0 or NULL\n" .
+				$herecurr);
+		}
+
+# check for static const char * arrays.
+		if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
+			WARN("STATIC_CONST_CHAR_ARRAY",
+			     "static const char * array should probably be static const char * const\n" .
+				$herecurr);
+               }
+
+# check for static char foo[] = "bar" declarations.
+		if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
+			WARN("STATIC_CONST_CHAR_ARRAY",
+			     "static char array declaration should probably be static const char\n" .
+				$herecurr);
+               }
+
+# check for declarations of struct pci_device_id
+		if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) {
+			WARN("DEFINE_PCI_DEVICE_TABLE",
+			     "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr);
+		}
+
+# check for new typedefs, only function parameters and sparse annotations
+# make sense.
+		if ($line =~ /\btypedef\s/ &&
+		    $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
+		    $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
+		    $line !~ /\b$typeTypedefs\b/ &&
+		    $line !~ /\b__bitwise(?:__|)\b/) {
+			WARN("NEW_TYPEDEFS",
+			     "do not add new typedefs\n" . $herecurr);
+		}
+
+# * goes on variable not on type
+		# (char*[ const])
+		while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) {
+			#print "AA<$1>\n";
+			my ($from, $to) = ($2, $2);
+
+			# Should start with a space.
+			$to =~ s/^(\S)/ $1/;
+			# Should not end with a space.
+			$to =~ s/\s+$//;
+			# '*'s should not have spaces between.
+			while ($to =~ s/\*\s+\*/\*\*/) {
+			}
+
+			#print "from<$from> to<$to>\n";
+			if ($from ne $to) {
+				ERROR("POINTER_LOCATION",
+				      "\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
+			}
+		}
+		while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
+			#print "BB<$1>\n";
+			my ($from, $to, $ident) = ($2, $2, $3);
+
+			# Should start with a space.
+			$to =~ s/^(\S)/ $1/;
+			# Should not end with a space.
+			$to =~ s/\s+$//;
+			# '*'s should not have spaces between.
+			while ($to =~ s/\*\s+\*/\*\*/) {
+			}
+			# Modifiers should have spaces.
+			$to =~ s/(\b$Modifier$)/$1 /;
+
+			#print "from<$from> to<$to> ident<$ident>\n";
+			if ($from ne $to && $ident !~ /^$Modifier$/) {
+				ERROR("POINTER_LOCATION",
+				      "\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr);
+			}
+		}
+
+# # no BUG() or BUG_ON()
+#		if ($line =~ /\b(BUG|BUG_ON)\b/) {
+#			print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
+#			print "$herecurr";
+#			$clean = 0;
+#		}
+
+		if ($line =~ /\bLINUX_VERSION_CODE\b/) {
+			WARN("LINUX_VERSION_CODE",
+			     "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
+		}
+
+# check for uses of printk_ratelimit
+		if ($line =~ /\bprintk_ratelimit\s*\(/) {
+			WARN("PRINTK_RATELIMITED",
+"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
+		}
+
+# printk should use KERN_* levels.  Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk.  In summary the current
+# printk includes all preceding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
+		if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
+			my $ok = 0;
+			for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+				#print "CHECK<$lines[$ln - 1]\n";
+				# we have a preceding printk if it ends
+				# with "\n" ignore it, else it is to blame
+				if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+					if ($rawlines[$ln - 1] !~ m{\\n"}) {
+						$ok = 1;
+					}
+					last;
+				}
+			}
+			if ($ok == 0) {
+				WARN("PRINTK_WITHOUT_KERN_LEVEL",
+				     "printk() should include KERN_ facility level\n" . $herecurr);
+			}
+		}
+
+# function brace can't be on same line, except for #defines of do while,
+# or if closed on same line
+		if (($line=~/$Type\s*$Ident\(.*\).*\s\{/) and
+		    !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) {
+			ERROR("OPEN_BRACE",
+			      "open brace '{' following function declarations go on the next line\n" . $herecurr);
+		}
+
+# open braces for enum, union and struct go on the same line.
+		if ($line =~ /^.\s*{/ &&
+		    $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
+			ERROR("OPEN_BRACE",
+			      "open brace '{' following $1 go on the same line\n" . $hereprev);
+		}
+
+# missing space after union, struct or enum definition
+		if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
+		    WARN("SPACING",
+			 "missing space after $1 definition\n" . $herecurr);
+		}
+
+# check for spacing round square brackets; allowed:
+#  1. with a type on the left -- int [] a;
+#  2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+#  3. inside a curly brace -- = { [0...10] = 5 }
+		while ($line =~ /(.*?\s)\[/g) {
+			my ($where, $prefix) = ($-[1], $1);
+			if ($prefix !~ /$Type\s+$/ &&
+			    ($where != 0 || $prefix !~ /^.\s+$/) &&
+			    $prefix !~ /[{,]\s+$/) {
+				ERROR("BRACKET_SPACE",
+				      "space prohibited before open square bracket '['\n" . $herecurr);
+			}
+		}
+
+# check for spaces between functions and their parentheses.
+		while ($line =~ /($Ident)\s+\(/g) {
+			my $name = $1;
+			my $ctx_before = substr($line, 0, $-[1]);
+			my $ctx = "$ctx_before$name";
+
+			# Ignore those directives where spaces _are_ permitted.
+			if ($name =~ /^(?:
+				if|for|while|switch|return|case|
+				volatile|__volatile__|
+				__attribute__|format|__extension__|
+				asm|__asm__)$/x)
+			{
+
+			# cpp #define statements have non-optional spaces, ie
+			# if there is a space between the name and the open
+			# parenthesis it is simply not a parameter group.
+			} elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {
+
+			# cpp #elif statement condition may start with a (
+			} elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
+
+			# If this whole things ends with a type its most
+			# likely a typedef for a function.
+			} elsif ($ctx =~ /$Type$/) {
+
+			} else {
+				WARN("SPACING",
+				     "space prohibited between function name and open parenthesis '('\n" . $herecurr);
+			}
+		}
+# Check operator spacing.
+		if (!($line=~/\#\s*include/)) {
+			my $ops = qr{
+				<<=|>>=|<=|>=|==|!=|
+				\+=|-=|\*=|\/=|%=|\^=|\|=|&=|
+				=>|->|<<|>>|<|>|=|!|~|
+				&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+				\?|:
+			}x;
+			my @elements = split(/($ops|;)/, $opline);
+			my $off = 0;
+
+			my $blank = copy_spacing($opline);
+
+			for (my $n = 0; $n < $#elements; $n += 2) {
+				$off += length($elements[$n]);
+
+				# Pick up the preceding and succeeding characters.
+				my $ca = substr($opline, 0, $off);
+				my $cc = '';
+				if (length($opline) >= ($off + length($elements[$n + 1]))) {
+					$cc = substr($opline, $off + length($elements[$n + 1]));
+				}
+				my $cb = "$ca$;$cc";
+
+				my $a = '';
+				$a = 'V' if ($elements[$n] ne '');
+				$a = 'W' if ($elements[$n] =~ /\s$/);
+				$a = 'C' if ($elements[$n] =~ /$;$/);
+				$a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+				$a = 'O' if ($elements[$n] eq '');
+				$a = 'E' if ($ca =~ /^\s*$/);
+
+				my $op = $elements[$n + 1];
+
+				my $c = '';
+				if (defined $elements[$n + 2]) {
+					$c = 'V' if ($elements[$n + 2] ne '');
+					$c = 'W' if ($elements[$n + 2] =~ /^\s/);
+					$c = 'C' if ($elements[$n + 2] =~ /^$;/);
+					$c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+					$c = 'O' if ($elements[$n + 2] eq '');
+					$c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
+				} else {
+					$c = 'E';
+				}
+
+				my $ctx = "${a}x${c}";
+
+				my $at = "(ctx:$ctx)";
+
+				my $ptr = substr($blank, 0, $off) . "^";
+				my $hereptr = "$hereline$ptr\n";
+
+				# Pull out the value of this operator.
+				my $op_type = substr($curr_values, $off + 1, 1);
+
+				# Get the full operator variant.
+				my $opv = $op . substr($curr_vars, $off, 1);
+
+				# Ignore operators passed as parameters.
+				if ($op_type ne 'V' &&
+				    $ca =~ /\s$/ && $cc =~ /^\s*,/) {
+
+#				# Ignore comments
+#				} elsif ($op =~ /^$;+$/) {
+
+				# ; should have either the end of line or a space or \ after it
+				} elsif ($op eq ';') {
+					if ($ctx !~ /.x[WEBC]/ &&
+					    $cc !~ /^\\/ && $cc !~ /^;/) {
+						ERROR("SPACING",
+						      "space required after that '$op' $at\n" . $hereptr);
+					}
+
+				# // is a comment
+				} elsif ($op eq '//') {
+
+				# No spaces for:
+				#   ->
+				#   :   when part of a bitfield
+				} elsif ($op eq '->' || $opv eq ':B') {
+					if ($ctx =~ /Wx.|.xW/) {
+						ERROR("SPACING",
+						      "spaces prohibited around that '$op' $at\n" . $hereptr);
+					}
+
+				# , must have a space on the right.
+				} elsif ($op eq ',') {
+					if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+						ERROR("SPACING",
+						      "space required after that '$op' $at\n" . $hereptr);
+					}
+
+				# '*' as part of a type definition -- reported already.
+				} elsif ($opv eq '*_') {
+					#warn "'*' is part of type\n";
+
+				# unary operators should have a space before and
+				# none after.  May be left adjacent to another
+				# unary operator, or a cast
+				} elsif ($op eq '!' || $op eq '~' ||
+					 $opv eq '*U' || $opv eq '-U' ||
+					 $opv eq '&U' || $opv eq '&&U') {
+					if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+						ERROR("SPACING",
+						      "space required before that '$op' $at\n" . $hereptr);
+					}
+					if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
+						# A unary '*' may be const
+
+					} elsif ($ctx =~ /.xW/) {
+						ERROR("SPACING",
+						      "space prohibited after that '$op' $at\n" . $hereptr);
+					}
+
+				# unary ++ and unary -- are allowed no space on one side.
+				} elsif ($op eq '++' or $op eq '--') {
+					if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+						ERROR("SPACING",
+						      "space required one side of that '$op' $at\n" . $hereptr);
+					}
+					if ($ctx =~ /Wx[BE]/ ||
+					    ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+						ERROR("SPACING",
+						      "space prohibited before that '$op' $at\n" . $hereptr);
+					}
+					if ($ctx =~ /ExW/) {
+						ERROR("SPACING",
+						      "space prohibited after that '$op' $at\n" . $hereptr);
+					}
+
+
+				# << and >> may either have or not have spaces both sides
+				} elsif ($op eq '<<' or $op eq '>>' or
+					 $op eq '&' or $op eq '^' or $op eq '|' or
+					 $op eq '+' or $op eq '-' or
+					 $op eq '*' or $op eq '/' or
+					 $op eq '%')
+				{
+					if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+						ERROR("SPACING",
+						      "need consistent spacing around '$op' $at\n" .
+							$hereptr);
+					}
+
+				# A colon needs no spaces before when it is
+				# terminating a case value or a label.
+				} elsif ($opv eq ':C' || $opv eq ':L') {
+					if ($ctx =~ /Wx./) {
+						ERROR("SPACING",
+						      "space prohibited before that '$op' $at\n" . $hereptr);
+					}
+
+				# All the others need spaces both sides.
+				} elsif ($ctx !~ /[EWC]x[CWE]/) {
+					my $ok = 0;
+
+					# Ignore email addresses <foo@bar>
+					if (($op eq '<' &&
+					     $cc =~ /^\S+\@\S+>/) ||
+					    ($op eq '>' &&
+					     $ca =~ /<\S+\@\S+$/))
+					{
+						$ok = 1;
+					}
+
+					# Ignore ?:
+					if (($opv eq ':O' && $ca =~ /\?$/) ||
+					    ($op eq '?' && $cc =~ /^:/)) {
+						$ok = 1;
+					}
+
+					if ($ok == 0) {
+						ERROR("SPACING",
+						      "spaces required around that '$op' $at\n" . $hereptr);
+					}
+				}
+				$off += length($elements[$n + 1]);
+			}
+		}
+
+# check for multiple assignments
+		if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+			CHK("MULTIPLE_ASSIGNMENTS",
+			    "multiple assignments should be avoided\n" . $herecurr);
+		}
+
+## # check for multiple declarations, allowing for a function declaration
+## # continuation.
+##		if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+##		    $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+##
+##			# Remove any bracketed sections to ensure we do not
+##			# falsly report the parameters of functions.
+##			my $ln = $line;
+##			while ($ln =~ s/\([^\(\)]*\)//g) {
+##			}
+##			if ($ln =~ /,/) {
+##				WARN("MULTIPLE_DECLARATION",
+##				     "declaring multiple variables together should be avoided\n" . $herecurr);
+##			}
+##		}
+
+#need space before brace following if, while, etc
+		if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) ||
+		    $line =~ /do\{/) {
+			ERROR("SPACING",
+			      "space required before the open brace '{'\n" . $herecurr);
+		}
+
+# closing brace should have a space following it when it has anything
+# on the line
+		if ($line =~ /}(?!(?:,|;|\)))\S/) {
+			ERROR("SPACING",
+			      "space required after that close brace '}'\n" . $herecurr);
+		}
+
+# check spacing on square brackets
+		if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
+			ERROR("SPACING",
+			      "space prohibited after that open square bracket '['\n" . $herecurr);
+		}
+		if ($line =~ /\s\]/) {
+			ERROR("SPACING",
+			      "space prohibited before that close square bracket ']'\n" . $herecurr);
+		}
+
+# check spacing on parentheses
+		if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
+		    $line !~ /for\s*\(\s+;/) {
+			ERROR("SPACING",
+			      "space prohibited after that open parenthesis '('\n" . $herecurr);
+		}
+		if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
+		    $line !~ /for\s*\(.*;\s+\)/ &&
+		    $line !~ /:\s+\)/) {
+			ERROR("SPACING",
+			      "space prohibited before that close parenthesis ')'\n" . $herecurr);
+		}
+
+#goto labels aren't indented, allow a single space however
+		if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+		   !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+			WARN("INDENTED_LABEL",
+			     "labels should not be indented\n" . $herecurr);
+		}
+
+# Return is not a function.
+		if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
+			my $spacing = $1;
+			my $value = $2;
+
+			# Flatten any parentheses
+			$value =~ s/\(/ \(/g;
+			$value =~ s/\)/\) /g;
+			while ($value =~ s/\[[^\[\]]*\]/1/ ||
+			       $value !~ /(?:$Ident|-?$Constant)\s*
+					     $Compare\s*
+					     (?:$Ident|-?$Constant)/x &&
+			       $value =~ s/\([^\(\)]*\)/1/) {
+			}
+#print "value<$value>\n";
+			if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
+				ERROR("RETURN_PARENTHESES",
+				      "return is not a function, parentheses are not required\n" . $herecurr);
+
+			} elsif ($spacing !~ /\s+/) {
+				ERROR("SPACING",
+				      "space required before the open parenthesis '('\n" . $herecurr);
+			}
+		}
+# Return of what appears to be an errno should normally be -'ve
+		if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
+			my $name = $1;
+			if ($name ne 'EOF' && $name ne 'ERROR') {
+				WARN("USE_NEGATIVE_ERRNO",
+				     "return of an errno should typically be -ve (return -$1)\n" . $herecurr);
+			}
+		}
+
+# Need a space before open parenthesis after if, while etc
+		if ($line=~/\b(if|while|for|switch)\(/) {
+			ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr);
+		}
+
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+		if ($line =~ /do\s*(?!{)/) {
+			($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+				ctx_statement_block($linenr, $realcnt, 0)
+					if (!defined $stat);
+			my ($stat_next) = ctx_statement_block($line_nr_next,
+						$remain_next, $off_next);
+			$stat_next =~ s/\n./\n /g;
+			##print "stat<$stat> stat_next<$stat_next>\n";
+
+			if ($stat_next =~ /^\s*while\b/) {
+				# If the statement carries leading newlines,
+				# then count those as offsets.
+				my ($whitespace) =
+					($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+				my $offset =
+					statement_rawlines($whitespace) - 1;
+
+				$suppress_whiletrailers{$line_nr_next +
+								$offset} = 1;
+			}
+		}
+		if (!defined $suppress_whiletrailers{$linenr} &&
+		    $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+			my ($s, $c) = ($stat, $cond);
+
+			if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
+				ERROR("ASSIGN_IN_IF",
+				      "do not use assignment in if condition\n" . $herecurr);
+			}
+
+			# Find out what is on the end of the line after the
+			# conditional.
+			substr($s, 0, length($c), '');
+			$s =~ s/\n.*//g;
+			$s =~ s/$;//g;	# Remove any comments
+			if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+			    $c !~ /}\s*while\s*/)
+			{
+				# Find out how long the conditional actually is.
+				my @newlines = ($c =~ /\n/gs);
+				my $cond_lines = 1 + $#newlines;
+				my $stat_real = '';
+
+				$stat_real = raw_line($linenr, $cond_lines)
+							. "\n" if ($cond_lines);
+				if (defined($stat_real) && $cond_lines > 1) {
+					$stat_real = "[...]\n$stat_real";
+				}
+
+				ERROR("TRAILING_STATEMENTS",
+				      "trailing statements should be on next line\n" . $herecurr . $stat_real);
+			}
+		}
+
+# Check for bitwise tests written as boolean
+		if ($line =~ /
+			(?:
+				(?:\[|\(|\&\&|\|\|)
+				\s*0[xX][0-9]+\s*
+				(?:\&\&|\|\|)
+			|
+				(?:\&\&|\|\|)
+				\s*0[xX][0-9]+\s*
+				(?:\&\&|\|\||\)|\])
+			)/x)
+		{
+			WARN("HEXADECIMAL_BOOLEAN_TEST",
+			     "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
+		}
+
+# if and else should not have general statements after it
+		if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
+			my $s = $1;
+			$s =~ s/$;//g;	# Remove any comments
+			if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
+				ERROR("TRAILING_STATEMENTS",
+				      "trailing statements should be on next line\n" . $herecurr);
+			}
+		}
+# if should not continue a brace
+		if ($line =~ /}\s*if\b/) {
+			ERROR("TRAILING_STATEMENTS",
+			      "trailing statements should be on next line\n" .
+				$herecurr);
+		}
+# case and default should not have general statements after them
+		if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+		    $line !~ /\G(?:
+			(?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+			\s*return\s+
+		    )/xg)
+		{
+			ERROR("TRAILING_STATEMENTS",
+			      "trailing statements should be on next line\n" . $herecurr);
+		}
+
+		# Check for }<nl>else {, these must be at the same
+		# indent level to be relevant to each other.
+		if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
+						$previndent == $indent) {
+			ERROR("ELSE_AFTER_BRACE",
+			      "else should follow close brace '}'\n" . $hereprev);
+		}
+
+		if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
+						$previndent == $indent) {
+			my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+
+			# Find out what is on the end of the line after the
+			# conditional.
+			substr($s, 0, length($c), '');
+			$s =~ s/\n.*//g;
+
+			if ($s =~ /^\s*;/) {
+				ERROR("WHILE_AFTER_BRACE",
+				      "while should follow close brace '}'\n" . $hereprev);
+			}
+		}
+
+#studly caps, commented out until figure out how to distinguish between use of existing and adding new
+#		if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
+#		    print "No studly caps, use _\n";
+#		    print "$herecurr";
+#		    $clean = 0;
+#		}
+
+#no spaces allowed after \ in define
+		if ($line=~/\#\s*define.*\\\s$/) {
+			WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
+			     "Whitepspace after \\ makes next lines useless\n" . $herecurr);
+		}
+
+#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
+		if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
+			my $file = "$1.h";
+			my $checkfile = "include/linux/$file";
+			if (-f "$root/$checkfile" &&
+			    $realfile ne $checkfile &&
+			    $1 !~ /$allowed_asm_includes/)
+			{
+				if ($realfile =~ m{^arch/}) {
+					CHK("ARCH_INCLUDE_LINUX",
+					    "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+				} else {
+					WARN("INCLUDE_LINUX",
+					     "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+				}
+			}
+		}
+
+# multi-statement macros should be enclosed in a do while loop, grab the
+# first statement and ensure its the whole macro if its not enclosed
+# in a known good container
+		if ($realfile !~ m@/vmlinux.lds.h$@ &&
+		    $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+			my $ln = $linenr;
+			my $cnt = $realcnt;
+			my ($off, $dstat, $dcond, $rest);
+			my $ctx = '';
+			($dstat, $dcond, $ln, $cnt, $off) =
+				ctx_statement_block($linenr, $realcnt, 0);
+			$ctx = $dstat;
+			#print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
+			#print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
+
+			$dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
+			$dstat =~ s/$;//g;
+			$dstat =~ s/\\\n.//g;
+			$dstat =~ s/^\s*//s;
+			$dstat =~ s/\s*$//s;
+
+			# Flatten any parentheses and braces
+			while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+			       $dstat =~ s/\{[^\{\}]*\}/1/ ||
+			       $dstat =~ s/\[[^\[\]]*\]/1/)
+			{
+			}
+
+			# Flatten any obvious string concatentation.
+			while ($dstat =~ s/("X*")\s*$Ident/$1/ ||
+			       $dstat =~ s/$Ident\s*("X*")/$1/)
+			{
+			}
+
+			my $exceptions = qr{
+				$Declare|
+				module_param_named|
+				MODULE_PARAM_DESC|
+				DECLARE_PER_CPU|
+				DEFINE_PER_CPU|
+				__typeof__\(|
+				union|
+				struct|
+				\.$Ident\s*=\s*|
+				^\"|\"$
+			}x;
+			#print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
+			if ($dstat ne '' &&
+			    $dstat !~ /^(?:$Ident|-?$Constant),$/ &&			# 10, // foo(),
+			    $dstat !~ /^(?:$Ident|-?$Constant);$/ &&			# foo();
+			    $dstat !~ /^[!~-]?(?:$Ident|$Constant)$/ &&		# 10 // foo() // !foo // ~foo // -foo
+			    $dstat !~ /^'X'$/ &&					# character constants
+			    $dstat !~ /$exceptions/ &&
+			    $dstat !~ /^\.$Ident\s*=/ &&				# .foo =
+			    $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ &&	# do {...} while (...); // do {...} while (...)
+			    $dstat !~ /^for\s*$Constant$/ &&				# for (...)
+			    $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ &&	# for (...) bar()
+			    $dstat !~ /^do\s*{/ &&					# do {...
+			    $dstat !~ /^\(\{/)						# ({...
+			{
+				$ctx =~ s/\n*$//;
+				my $herectx = $here . "\n";
+				my $cnt = statement_rawlines($ctx);
+
+				for (my $n = 0; $n < $cnt; $n++) {
+					$herectx .= raw_line($linenr, $n) . "\n";
+				}
+
+				if ($dstat =~ /;/) {
+					ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
+					      "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
+				} else {
+					ERROR("COMPLEX_MACRO",
+					      "Macros with complex values should be enclosed in parenthesis\n" . "$herectx");
+				}
+			}
+		}
+
+# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
+# all assignments may have only one of the following with an assignment:
+#	.
+#	ALIGN(...)
+#	VMLINUX_SYMBOL(...)
+		if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
+			WARN("MISSING_VMLINUX_SYMBOL",
+			     "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
+		}
+
+# check for redundant bracing round if etc
+		if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
+			my ($level, $endln, @chunks) =
+				ctx_statement_full($linenr, $realcnt, 1);
+			#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+			#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+			if ($#chunks > 0 && $level == 0) {
+				my @allowed = ();
+				my $allow = 0;
+				my $seen = 0;
+				my $herectx = $here . "\n";
+				my $ln = $linenr - 1;
+				for my $chunk (@chunks) {
+					my ($cond, $block) = @{$chunk};
+
+					# If the condition carries leading newlines, then count those as offsets.
+					my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+					my $offset = statement_rawlines($whitespace) - 1;
+
+					$allowed[$allow] = 0;
+					#print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
+
+					# We have looked at and allowed this specific line.
+					$suppress_ifbraces{$ln + $offset} = 1;
+
+					$herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+					$ln += statement_rawlines($block) - 1;
+
+					substr($block, 0, length($cond), '');
+
+					$seen++ if ($block =~ /^\s*{/);
+
+					#print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
+					if (statement_lines($cond) > 1) {
+						#print "APW: ALLOWED: cond<$cond>\n";
+						$allowed[$allow] = 1;
+					}
+					if ($block =~/\b(?:if|for|while)\b/) {
+						#print "APW: ALLOWED: block<$block>\n";
+						$allowed[$allow] = 1;
+					}
+					if (statement_block_size($block) > 1) {
+						#print "APW: ALLOWED: lines block<$block>\n";
+						$allowed[$allow] = 1;
+					}
+					$allow++;
+				}
+				if ($seen) {
+					my $sum_allowed = 0;
+					foreach (@allowed) {
+						$sum_allowed += $_;
+					}
+					if ($sum_allowed == 0) {
+						WARN("BRACES",
+						     "braces {} are not necessary for any arm of this statement\n" . $herectx);
+					} elsif ($sum_allowed != $allow &&
+						 $seen != $allow) {
+						CHK("BRACES",
+						    "braces {} should be used on all arms of this statement\n" . $herectx);
+					}
+				}
+			}
+		}
+		if (!defined $suppress_ifbraces{$linenr - 1} &&
+					$line =~ /\b(if|while|for|else)\b/) {
+			my $allowed = 0;
+
+			# Check the pre-context.
+			if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+				#print "APW: ALLOWED: pre<$1>\n";
+				$allowed = 1;
+			}
+
+			my ($level, $endln, @chunks) =
+				ctx_statement_full($linenr, $realcnt, $-[0]);
+
+			# Check the condition.
+			my ($cond, $block) = @{$chunks[0]};
+			#print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+			if (defined $cond) {
+				substr($block, 0, length($cond), '');
+			}
+			if (statement_lines($cond) > 1) {
+				#print "APW: ALLOWED: cond<$cond>\n";
+				$allowed = 1;
+			}
+			if ($block =~/\b(?:if|for|while)\b/) {
+				#print "APW: ALLOWED: block<$block>\n";
+				$allowed = 1;
+			}
+			if (statement_block_size($block) > 1) {
+				#print "APW: ALLOWED: lines block<$block>\n";
+				$allowed = 1;
+			}
+			# Check the post-context.
+			if (defined $chunks[1]) {
+				my ($cond, $block) = @{$chunks[1]};
+				if (defined $cond) {
+					substr($block, 0, length($cond), '');
+				}
+				if ($block =~ /^\s*\{/) {
+					#print "APW: ALLOWED: chunk-1 block<$block>\n";
+					$allowed = 1;
+				}
+			}
+			if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
+				my $herectx = $here . "\n";
+				my $cnt = statement_rawlines($block);
+
+				for (my $n = 0; $n < $cnt; $n++) {
+					$herectx .= raw_line($linenr, $n) . "\n";
+				}
+
+				WARN("BRACES",
+				     "braces {} are not necessary for single statement blocks\n" . $herectx);
+			}
+		}
+
+# no volatiles please
+		my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
+		if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
+			WARN("VOLATILE",
+			     "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+		}
+
+# warn about #if 0
+		if ($line =~ /^.\s*\#\s*if\s+0\b/) {
+			CHK("REDUNDANT_CODE",
+			    "if this code is redundant consider removing it\n" .
+				$herecurr);
+		}
+
+# check for needless kfree() checks
+		if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+			my $expr = $1;
+			if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+				WARN("NEEDLESS_KFREE",
+				     "kfree(NULL) is safe this check is probably not required\n" . $hereprev);
+			}
+		}
+# check for needless usb_free_urb() checks
+		if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+			my $expr = $1;
+			if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+				WARN("NEEDLESS_USB_FREE_URB",
+				     "usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev);
+			}
+		}
+
+# prefer usleep_range over udelay
+		if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) {
+			# ignore udelay's < 10, however
+			if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) {
+				CHK("USLEEP_RANGE",
+				    "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line);
+			}
+		}
+
+# warn about unexpectedly long msleep's
+		if ($line =~ /\bmsleep\s*\((\d+)\);/) {
+			if ($1 < 20) {
+				WARN("MSLEEP",
+				     "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line);
+			}
+		}
+
+# warn about #ifdefs in C files
+#		if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+#			print "#ifdef in C files should be avoided\n";
+#			print "$herecurr";
+#			$clean = 0;
+#		}
+
+# warn about spacing in #ifdefs
+		if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
+			ERROR("SPACING",
+			      "exactly one space required after that #$1\n" . $herecurr);
+		}
+
+# check for spinlock_t definitions without a comment.
+		if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+		    $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
+			my $which = $1;
+			if (!ctx_has_comment($first_line, $linenr)) {
+				CHK("UNCOMMENTED_DEFINITION",
+				    "$1 definition without comment\n" . $herecurr);
+			}
+		}
+# check for memory barriers without a comment.
+		if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+			if (!ctx_has_comment($first_line, $linenr)) {
+				CHK("MEMORY_BARRIER",
+				    "memory barrier without comment\n" . $herecurr);
+			}
+		}
+# check of hardware specific defines
+		if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
+			CHK("ARCH_DEFINES",
+			    "architecture specific defines should be avoided\n" .  $herecurr);
+		}
+
+# Check that the storage class is at the beginning of a declaration
+		if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+			WARN("STORAGE_CLASS",
+			     "storage class should be at the beginning of the declaration\n" . $herecurr)
+		}
+
+# check the location of the inline attribute, that it is between
+# storage class and type.
+		if ($line =~ /\b$Type\s+$Inline\b/ ||
+		    $line =~ /\b$Inline\s+$Storage\b/) {
+			ERROR("INLINE_LOCATION",
+			      "inline keyword should sit between storage class and type\n" . $herecurr);
+		}
+
+# Check for __inline__ and __inline, prefer inline
+		if ($line =~ /\b(__inline__|__inline)\b/) {
+			WARN("INLINE",
+			     "plain inline is preferred over $1\n" . $herecurr);
+		}
+
+# Check for __attribute__ packed, prefer __packed
+		if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) {
+			WARN("PREFER_PACKED",
+			     "__packed is preferred over __attribute__((packed))\n" . $herecurr);
+		}
+
+# Check for __attribute__ aligned, prefer __aligned
+		if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) {
+			WARN("PREFER_ALIGNED",
+			     "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr);
+		}
+
+# Check for __attribute__ format(printf, prefer __printf
+		if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
+			WARN("PREFER_PRINTF",
+			     "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr);
+		}
+
+# Check for __attribute__ format(scanf, prefer __scanf
+		if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
+			WARN("PREFER_SCANF",
+			     "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr);
+		}
+
+# check for sizeof(&)
+		if ($line =~ /\bsizeof\s*\(\s*\&/) {
+			WARN("SIZEOF_ADDRESS",
+			     "sizeof(& should be avoided\n" . $herecurr);
+		}
+
+# check for line continuations in quoted strings with odd counts of "
+		if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+			WARN("LINE_CONTINUATIONS",
+			     "Avoid line continuations in quoted strings\n" . $herecurr);
+		}
+
+# Check for misused memsets
+		if ($^V && $^V ge 5.10.0 &&
+		    defined $stat &&
+		    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) {
+
+			my $ms_addr = $2;
+			my $ms_val = $7;
+			my $ms_size = $12;
+
+			if ($ms_size =~ /^(0x|)0$/i) {
+				ERROR("MEMSET",
+				      "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n");
+			} elsif ($ms_size =~ /^(0x|)1$/i) {
+				WARN("MEMSET",
+				     "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n");
+			}
+		}
+
+# typecasts on min/max could be min_t/max_t
+		if ($^V && $^V ge 5.10.0 &&
+		    defined $stat &&
+		    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
+			if (defined $2 || defined $7) {
+				my $call = $1;
+				my $cast1 = deparenthesize($2);
+				my $arg1 = $3;
+				my $cast2 = deparenthesize($7);
+				my $arg2 = $8;
+				my $cast;
+
+				if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) {
+					$cast = "$cast1 or $cast2";
+				} elsif ($cast1 ne "") {
+					$cast = $cast1;
+				} else {
+					$cast = $cast2;
+				}
+				WARN("MINMAX",
+				     "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n");
+			}
+		}
+
+# check for new externs in .c files.
+		if ($realfile =~ /\.c$/ && defined $stat &&
+		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
+		{
+			my $function_name = $1;
+			my $paren_space = $2;
+
+			my $s = $stat;
+			if (defined $cond) {
+				substr($s, 0, length($cond), '');
+			}
+			if ($s =~ /^\s*;/ &&
+			    $function_name ne 'uninitialized_var')
+			{
+				WARN("AVOID_EXTERNS",
+				     "externs should be avoided in .c files\n" .  $herecurr);
+			}
+
+			if ($paren_space =~ /\n/) {
+				WARN("FUNCTION_ARGUMENTS",
+				     "arguments for function declarations should follow identifier\n" . $herecurr);
+			}
+
+		} elsif ($realfile =~ /\.c$/ && defined $stat &&
+		    $stat =~ /^.\s*extern\s+/)
+		{
+			WARN("AVOID_EXTERNS",
+			     "externs should be avoided in .c files\n" .  $herecurr);
+		}
+
+# check for pointless casting of kmalloc return
+		if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) {
+			WARN("UNNECESSARY_CASTS",
+			     "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
+		}
+
+# check for multiple semicolons
+		if ($line =~ /;\s*;\s*$/) {
+		    WARN("ONE_SEMICOLON",
+			 "Statements terminations use 1 semicolon\n" . $herecurr);
+		}
+
+# check for gcc specific __FUNCTION__
+		if ($line =~ /__FUNCTION__/) {
+			WARN("USE_FUNC",
+			     "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
+		}
+
+# check for use of yield()
+		if ($line =~ /\byield\s*\(\s*\)/) {
+			WARN("YIELD",
+			     "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n"  . $herecurr);
+		}
+
+# check for semaphores initialized locked
+		if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
+			WARN("CONSIDER_COMPLETION",
+			     "consider using a completion\n" . $herecurr);
+		}
+
+# recommend kstrto* over simple_strto* and strict_strto*
+		if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
+			WARN("CONSIDER_KSTRTO",
+			     "$1 is obsolete, use k$3 instead\n" . $herecurr);
+		}
+
+# check for __initcall(), use device_initcall() explicitly please
+		if ($line =~ /^.\s*__initcall\s*\(/) {
+			WARN("USE_DEVICE_INITCALL",
+			     "please use device_initcall() instead of __initcall()\n" . $herecurr);
+		}
+
+# check for various ops structs, ensure they are const.
+		my $struct_ops = qr{acpi_dock_ops|
+				address_space_operations|
+				backlight_ops|
+				block_device_operations|
+				dentry_operations|
+				dev_pm_ops|
+				dma_map_ops|
+				extent_io_ops|
+				file_lock_operations|
+				file_operations|
+				hv_ops|
+				ide_dma_ops|
+				intel_dvo_dev_ops|
+				item_operations|
+				iwl_ops|
+				kgdb_arch|
+				kgdb_io|
+				kset_uevent_ops|
+				lock_manager_operations|
+				microcode_ops|
+				mtrr_ops|
+				neigh_ops|
+				nlmsvc_binding|
+				pci_raw_ops|
+				pipe_buf_operations|
+				platform_hibernation_ops|
+				platform_suspend_ops|
+				proto_ops|
+				rpc_pipe_ops|
+				seq_operations|
+				snd_ac97_build_ops|
+				soc_pcmcia_socket_ops|
+				stacktrace_ops|
+				sysfs_ops|
+				tty_operations|
+				usb_mon_operations|
+				wd_ops}x;
+		if ($line !~ /\bconst\b/ &&
+		    $line =~ /\bstruct\s+($struct_ops)\b/) {
+			WARN("CONST_STRUCT",
+			     "struct $1 should normally be const\n" .
+				$herecurr);
+		}
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+		if ($line =~ /\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+		    $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+		    $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
+		{
+			WARN("NR_CPUS",
+			     "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+		}
+
+# check for %L{u,d,i} in strings
+		my $string;
+		while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+			$string = substr($rawline, $-[1], $+[1] - $-[1]);
+			$string =~ s/%%/__/g;
+			if ($string =~ /(?<!%)%L[udi]/) {
+				WARN("PRINTF_L",
+				     "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+				last;
+			}
+		}
+
+# whine mightly about in_atomic
+		if ($line =~ /\bin_atomic\s*\(/) {
+			if ($realfile =~ m@^drivers/@) {
+				ERROR("IN_ATOMIC",
+				      "do not use in_atomic in drivers\n" . $herecurr);
+			} elsif ($realfile !~ m@^kernel/@) {
+				WARN("IN_ATOMIC",
+				     "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
+			}
+		}
+
+# check for lockdep_set_novalidate_class
+		if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
+		    $line =~ /__lockdep_no_validate__\s*\)/ ) {
+			if ($realfile !~ m@^kernel/lockdep@ &&
+			    $realfile !~ m@^include/linux/lockdep@ &&
+			    $realfile !~ m@^drivers/base/core@) {
+				ERROR("LOCKDEP",
+				      "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
+			}
+		}
+
+		if ($line =~ /debugfs_create_file.*S_IWUGO/ ||
+		    $line =~ /DEVICE_ATTR.*S_IWUGO/ ) {
+			WARN("EXPORTED_WORLD_WRITABLE",
+			     "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
+		}
+	}
+
+	# If we have no input at all, then there is nothing to report on
+	# so just keep quiet.
+	if ($#rawlines == -1) {
+		exit(0);
+	}
+
+	# In mailback mode only produce a report in the negative, for
+	# things that appear to be patches.
+	if ($mailback && ($clean == 1 || !$is_patch)) {
+		exit(0);
+	}
+
+	# This is not a patch, and we are are in 'no-patch' mode so
+	# just keep quiet.
+	if (!$chk_patch && !$is_patch) {
+		exit(0);
+	}
+
+	if (!$is_patch) {
+		ERROR("NOT_UNIFIED_DIFF",
+		      "Does not appear to be a unified-diff format patch\n");
+	}
+	if ($is_patch && $chk_signoff && $signoff == 0) {
+		ERROR("MISSING_SIGN_OFF",
+		      "Missing Signed-off-by: line(s)\n");
+	}
+
+	print report_dump();
+	if ($summary && !($clean == 1 && $quiet == 1)) {
+		print "$filename " if ($summary_file);
+		print "total: $cnt_error errors, $cnt_warn warnings, " .
+			(($check)? "$cnt_chk checks, " : "") .
+			"$cnt_lines lines checked\n";
+		print "\n" if ($quiet == 0);
+	}
+
+	if ($quiet == 0) {
+
+		if ($^V lt 5.10.0) {
+			print("NOTE: perl $^V is not modern enough to detect all possible issues.\n");
+			print("An upgrade to at least perl v5.10.0 is suggested.\n\n");
+		}
+
+		# If there were whitespace errors which cleanpatch can fix
+		# then suggest that.
+		if ($rpt_cleaners) {
+			print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
+			print "      scripts/cleanfile\n\n";
+			$rpt_cleaners = 0;
+		}
+	}
+
+	if ($quiet == 0 && keys %ignore_type) {
+	    print "NOTE: Ignored message types:";
+	    foreach my $ignore (sort keys %ignore_type) {
+		print " $ignore";
+	    }
+	    print "\n\n";
+	}
+
+	if ($clean == 1 && $quiet == 0) {
+		print "$vname has no obvious style problems and is ready for submission.\n"
+	}
+	if ($clean == 0 && $quiet == 0) {
+		print << "EOM";
+$vname has style problems, please review.
+
+If any of these errors are false positives, please report
+them to the maintainer, see CHECKPATCH in MAINTAINERS.
+EOM
+	}
+
+	return $clean;
+}
diff --git a/scripts/clang-gcc-wrapper b/scripts/clang-gcc-wrapper
new file mode 100755
index 0000000000..9e668418a9
--- /dev/null
+++ b/scripts/clang-gcc-wrapper
@@ -0,0 +1,12 @@
+#!/bin/sh
+_cc="${HOSTCC_REAL:-gcc}"
+case "$1" in
+	-print-file-name=*)
+		dirs="$($_cc -print-search-dirs | grep -m1 libraries | sed -e 's,:, ,' -e 's,.* =,,')"
+		dirs="$dirs /usr/lib /usr/local/lib"
+		find $dirs -name "${1#*=}" | head -n1
+	;;
+	*)
+		exec $_cc "$@"
+	;;
+esac
diff --git a/scripts/clean-package.sh b/scripts/clean-package.sh
new file mode 100755
index 0000000000..d1a257889d
--- /dev/null
+++ b/scripts/clean-package.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+[ -n "$1" -a -n "$2" ] || {
+	echo "Usage: $0 <file> <directory>"
+	exit 1
+}
+[ -f "$1" -a -d "$2" ] || {
+	echo "File/directory not found"
+	exit 1
+}
+cat "$1" | (
+	cd "$2"
+	while read entry; do
+		[ -n "$entry" ] || break
+		[ -f "$entry" ] && rm -f $entry
+	done
+)
+cat "$1" | (
+	cd "$2"
+	while read entry; do
+		[ -n "$entry" ] || break
+		[ -d "$entry" ] && rmdir "$entry" > /dev/null 2>&1
+	done
+)
+true
diff --git a/scripts/cleanfile b/scripts/cleanfile
new file mode 100755
index 0000000000..cefd29e522
--- /dev/null
+++ b/scripts/cleanfile
@@ -0,0 +1,176 @@
+#!/usr/bin/perl -w
+#
+# Clean a text file -- or directory of text files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation.  Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+# Default options
+$max_width = 79;
+
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+    no bytes;			# Tab alignment depends on characters
+
+    my($li) = @_;
+    my($lo) = '';
+    my $pos = 0;
+    my $nsp = 0;
+    my($i, $c);
+
+    for ($i = 0; $i < length($li); $i++) {
+	$c = substr($li, $i, 1);
+	if ($c eq "\t") {
+	    my $npos = ($pos+$nsp+8) & ~7;
+	    my $ntab = ($npos >> 3) - ($pos >> 3);
+	    $lo .= "\t" x $ntab;
+	    $pos = $npos;
+	    $nsp = 0;
+	} elsif ($c eq "\n" || $c eq "\r") {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos = 0;
+	} elsif ($c eq " ") {
+	    $nsp++;
+	} else {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos++;
+	}
+    }
+    $lo .= " " x $nsp;
+    return $lo;
+}
+
+# Compute the visual width of a string
+sub strwidth($) {
+    no bytes;			# Tab alignment depends on characters
+
+    my($li) = @_;
+    my($c, $i);
+    my $pos = 0;
+    my $mlen = 0;
+
+    for ($i = 0; $i < length($li); $i++) {
+	$c = substr($li,$i,1);
+	if ($c eq "\t") {
+	    $pos = ($pos+8) & ~7;
+	} elsif ($c eq "\n") {
+	    $mlen = $pos if ($pos > $mlen);
+	    $pos = 0;
+	} else {
+	    $pos++;
+	}
+    }
+
+    $mlen = $pos if ($pos > $mlen);
+    return $mlen;
+}
+
+$name = basename($0);
+
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+    if ($a =~ /^-/) {
+	if ($a eq '-width' || $a eq '-w') {
+	    $max_width = shift(@ARGV)+0;
+	} else {
+	    print STDERR "Usage: $name [-width #] files...\n";
+	    exit 1;
+	}
+    } else {
+	push(@files, $a);
+    }
+}
+
+foreach $f ( @files ) {
+    print STDERR "$name: $f\n";
+
+    if (! -f $f) {
+	print STDERR "$f: not a file\n";
+	next;
+    }
+
+    if (!open(FILE, '+<', $f)) {
+	print STDERR "$name: Cannot open file: $f: $!\n";
+	next;
+    }
+
+    binmode FILE;
+
+    # First, verify that it is not a binary file; consider any file
+    # with a zero byte to be a binary file.  Is there any better, or
+    # additional, heuristic that should be applied?
+    $is_binary = 0;
+
+    while (read(FILE, $data, 65536) > 0) {
+	if ($data =~ /\0/) {
+	    $is_binary = 1;
+	    last;
+	}
+    }
+
+    if ($is_binary) {
+	print STDERR "$name: $f: binary file\n";
+	next;
+    }
+
+    seek(FILE, 0, 0);
+
+    $in_bytes = 0;
+    $out_bytes = 0;
+    $blank_bytes = 0;
+
+    @blanks = ();
+    @lines  = ();
+    $lineno = 0;
+
+    while ( defined($line = <FILE>) ) {
+	$lineno++;
+	$in_bytes += length($line);
+	$line =~ s/[ \t\r]*$//;		# Remove trailing spaces
+	$line = clean_space_tabs($line);
+
+	if ( $line eq "\n" ) {
+	    push(@blanks, $line);
+	    $blank_bytes += length($line);
+	} else {
+	    push(@lines, @blanks);
+	    $out_bytes += $blank_bytes;
+	    push(@lines, $line);
+	    $out_bytes += length($line);
+	    @blanks = ();
+	    $blank_bytes = 0;
+	}
+
+	$l_width = strwidth($line);
+	if ($max_width && $l_width > $max_width) {
+	    print STDERR
+		"$f:$lineno: line exceeds $max_width characters ($l_width)\n";
+	}
+    }
+
+    # Any blanks at the end of the file are discarded
+
+    if ($in_bytes != $out_bytes) {
+	# Only write to the file if changed
+	seek(FILE, 0, 0);
+	print FILE @lines;
+
+	if ( !defined($where = tell(FILE)) ||
+	     !truncate(FILE, $where) ) {
+	    die "$name: Failed to truncate modified file: $f: $!\n";
+	}
+    }
+
+    close(FILE);
+}
diff --git a/scripts/cleanpatch b/scripts/cleanpatch
new file mode 100755
index 0000000000..9680d03ad2
--- /dev/null
+++ b/scripts/cleanpatch
@@ -0,0 +1,258 @@
+#!/usr/bin/perl -w
+#
+# Clean a patch file -- or directory of patch files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation.  Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+# Default options
+$max_width = 79;
+
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+    no bytes;			# Tab alignment depends on characters
+
+    my($li) = @_;
+    my($lo) = '';
+    my $pos = 0;
+    my $nsp = 0;
+    my($i, $c);
+
+    for ($i = 0; $i < length($li); $i++) {
+	$c = substr($li, $i, 1);
+	if ($c eq "\t") {
+	    my $npos = ($pos+$nsp+8) & ~7;
+	    my $ntab = ($npos >> 3) - ($pos >> 3);
+	    $lo .= "\t" x $ntab;
+	    $pos = $npos;
+	    $nsp = 0;
+	} elsif ($c eq "\n" || $c eq "\r") {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos = 0;
+	} elsif ($c eq " ") {
+	    $nsp++;
+	} else {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos++;
+	}
+    }
+    $lo .= " " x $nsp;
+    return $lo;
+}
+
+# Compute the visual width of a string
+sub strwidth($) {
+    no bytes;			# Tab alignment depends on characters
+
+    my($li) = @_;
+    my($c, $i);
+    my $pos = 0;
+    my $mlen = 0;
+
+    for ($i = 0; $i < length($li); $i++) {
+	$c = substr($li,$i,1);
+	if ($c eq "\t") {
+	    $pos = ($pos+8) & ~7;
+	} elsif ($c eq "\n") {
+	    $mlen = $pos if ($pos > $mlen);
+	    $pos = 0;
+	} else {
+	    $pos++;
+	}
+    }
+
+    $mlen = $pos if ($pos > $mlen);
+    return $mlen;
+}
+
+$name = basename($0);
+
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+    if ($a =~ /^-/) {
+	if ($a eq '-width' || $a eq '-w') {
+	    $max_width = shift(@ARGV)+0;
+	} else {
+	    print STDERR "Usage: $name [-width #] files...\n";
+	    exit 1;
+	}
+    } else {
+	push(@files, $a);
+    }
+}
+
+foreach $f ( @files ) {
+    print STDERR "$name: $f\n";
+
+    if (! -f $f) {
+	print STDERR "$f: not a file\n";
+	next;
+    }
+
+    if (!open(FILE, '+<', $f)) {
+	print STDERR "$name: Cannot open file: $f: $!\n";
+	next;
+    }
+
+    binmode FILE;
+
+    # First, verify that it is not a binary file; consider any file
+    # with a zero byte to be a binary file.  Is there any better, or
+    # additional, heuristic that should be applied?
+    $is_binary = 0;
+
+    while (read(FILE, $data, 65536) > 0) {
+	if ($data =~ /\0/) {
+	    $is_binary = 1;
+	    last;
+	}
+    }
+
+    if ($is_binary) {
+	print STDERR "$name: $f: binary file\n";
+	next;
+    }
+
+    seek(FILE, 0, 0);
+
+    $in_bytes = 0;
+    $out_bytes = 0;
+    $lineno = 0;
+
+    @lines  = ();
+
+    $in_hunk = 0;
+    $err = 0;
+
+    while ( defined($line = <FILE>) ) {
+	$lineno++;
+	$in_bytes += length($line);
+
+	if (!$in_hunk) {
+	    if ($line =~
+		/^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
+		$minus_lines = $2;
+		$plus_lines = $4;
+		if ($minus_lines || $plus_lines) {
+		    $in_hunk = 1;
+		    @hunk_lines = ($line);
+		}
+	    } else {
+		push(@lines, $line);
+		$out_bytes += length($line);
+	    }
+	} else {
+	    # We're in a hunk
+
+	    if ($line =~ /^\+/) {
+		$plus_lines--;
+
+		$text = substr($line, 1);
+		$text =~ s/[ \t\r]*$//;		# Remove trailing spaces
+		$text = clean_space_tabs($text);
+
+		$l_width = strwidth($text);
+		if ($max_width && $l_width > $max_width) {
+		    print STDERR
+			"$f:$lineno: adds line exceeds $max_width ",
+			"characters ($l_width)\n";
+		}
+
+		push(@hunk_lines, '+'.$text);
+	    } elsif ($line =~ /^\-/) {
+		$minus_lines--;
+		push(@hunk_lines, $line);
+	    } elsif ($line =~ /^ /) {
+		$plus_lines--;
+		$minus_lines--;
+		push(@hunk_lines, $line);
+	    } else {
+		print STDERR "$name: $f: malformed patch\n";
+		$err = 1;
+		last;
+	    }
+
+	    if ($plus_lines < 0 || $minus_lines < 0) {
+		print STDERR "$name: $f: malformed patch\n";
+		$err = 1;
+		last;
+	    } elsif ($plus_lines == 0 && $minus_lines == 0) {
+		# End of a hunk.  Process this hunk.
+		my $i;
+		my $l;
+		my @h = ();
+		my $adj = 0;
+		my $done = 0;
+
+		for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
+		    $l = $hunk_lines[$i];
+		    if (!$done && $l eq "+\n") {
+			$adj++; # Skip this line
+		    } elsif ($l =~ /^[ +]/) {
+			$done = 1;
+			unshift(@h, $l);
+		    } else {
+			unshift(@h, $l);
+		    }
+		}
+
+		$l = $hunk_lines[0];  # Hunk header
+		undef @hunk_lines;    # Free memory
+
+		if ($adj) {
+		    die unless
+			($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
+		    my $mstart = $1;
+		    my $mlin = $2;
+		    my $pstart = $3;
+		    my $plin = $4;
+		    my $tail = $5; # doesn't include the final newline
+
+		    $l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
+				 $mstart, $mlin, $pstart, $plin-$adj,
+				 $tail);
+		}
+		unshift(@h, $l);
+
+		# Transfer to the output array
+		foreach $l (@h) {
+		    $out_bytes += length($l);
+		    push(@lines, $l);
+		}
+
+		$in_hunk = 0;
+	    }
+	}
+    }
+
+    if ($in_hunk) {
+	print STDERR "$name: $f: malformed patch\n";
+	$err = 1;
+    }
+
+    if (!$err) {
+	if ($in_bytes != $out_bytes) {
+	    # Only write to the file if changed
+	    seek(FILE, 0, 0);
+	    print FILE @lines;
+
+	    if ( !defined($where = tell(FILE)) ||
+		 !truncate(FILE, $where) ) {
+		die "$name: Failed to truncate modified file: $f: $!\n";
+	    }
+	}
+    }
+
+    close(FILE);
+}
diff --git a/scripts/combined-ext-image.sh b/scripts/combined-ext-image.sh
new file mode 100755
index 0000000000..374fe6e344
--- /dev/null
+++ b/scripts/combined-ext-image.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+# Write image header followed by all specified files
+# The header is padded to 64k, format is:
+#  CE               magic word ("Combined Extended Image") (2 bytes)
+#  <CE_VERSION>     file format version field (2 bytes) 
+#  <TYPE>           short description of the target device (32 bytes)
+#  <NUM FILES>      number of files following the header (2 byte)
+#  <file1_name>     name of the first file (32 bytes)
+#  <file1_length>   length of the first file encoded as zero padded 8 digit hex (8 bytes)
+#  <file1_md5>      md5 checksum of the first file (32 bytes)
+#  <fileN_name>     name of the Nth file (32 bytes)
+#  <fileN_length>   length of the Nth file encoded as zero padded 8 digit hex (8 bytes)
+#  <fileN_md5>      md5 checksum of the Nth file (32 bytes)
+
+## version history
+# * version 1: initial file format with num files / name / length / md5 checksum 
+
+ME="${0##*/}"
+
+usage() {
+	echo "Usage: $ME <type> <ext filename> <file1> <filename1> [<file2> <filename2> <fileN> <filenameN>]"
+	[ "$IMG_OUT" ] && rm -f "$IMG_OUT"
+	exit 1
+}
+
+[ "$#" -lt 4 ] && usage
+
+CE_VERSION=1
+IMG_TYPE=$1; shift
+IMG_OUT=$1; shift
+FILE_NUM=$(($# / 2))
+FILES=""
+
+printf "CE%02x%-32s%02x" $CE_VERSION "$IMG_TYPE" $FILE_NUM > $IMG_OUT
+
+while [ "$#" -gt 1 ]
+   do
+      file=$1
+      filename=$2
+
+      [ ! -f "$file" ] && echo "$ME: Not a valid file: $file" && usage
+      FILES="$FILES $file"
+      md5=$(cat "$file" | md5sum -)
+      printf "%-32s%08x%32s" "$filename" $(stat -c "%s" "$file") "${md5%% *}" >> $IMG_OUT
+      shift 2
+   done
+
+[ "$#" -eq 1 ] && echo "$ME: Filename not specified: $1" && usage
+
+mv $IMG_OUT $IMG_OUT.tmp
+dd if="$IMG_OUT.tmp" of="$IMG_OUT" bs=65536 conv=sync 2>/dev/null
+rm $IMG_OUT.tmp
+
+cat $FILES >> $IMG_OUT
diff --git a/scripts/combined-image.sh b/scripts/combined-image.sh
new file mode 100644
index 0000000000..5472b2cfd2
--- /dev/null
+++ b/scripts/combined-image.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+BLKSZ=65536
+
+[ -f "$1" -a -f "$2" ] || {
+	echo "Usage: $0 <kernel image> <rootfs image> [output file]"
+	exit 1
+}
+
+IMAGE=${3:-openwrt-combined.img}
+
+# Make sure provided images are 64k aligned.
+kern="${IMAGE}.kernel"
+root="${IMAGE}.rootfs"
+dd if="$1" of="$kern" bs=$BLKSZ conv=sync 2>/dev/null
+dd if="$2" of="$root" bs=$BLKSZ conv=sync 2>/dev/null
+
+# Calculate md5sum over combined kernel and rootfs image.
+md5=$(cat "$kern" "$root" | md5sum -)
+
+# Write image header followed by kernel and rootfs image.
+# The header is padded to 64k, format is:
+#  CI               magic word ("Combined Image")
+#  <kernel length>  length of kernel encoded as zero padded 8 digit hex
+#  <rootfs length>  length of rootfs encoded as zero padded 8 digit hex
+#  <md5sum>         checksum of the combined kernel and rootfs image
+( printf "CI%08x%08x%32s" \
+	$(stat -c "%s" "$kern") $(stat -c "%s" "$root") "${md5%% *}" | \
+	dd bs=$BLKSZ conv=sync;
+  cat "$kern" "$root"
+) > ${IMAGE} 2>/dev/null
+
+# Clean up.
+rm -f "$kern" "$root"
diff --git a/scripts/config.guess b/scripts/config.guess
new file mode 100755
index 0000000000..fddac4281a
--- /dev/null
+++ b/scripts/config.guess
@@ -0,0 +1,1438 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-07-03'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	    /sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || \
+	    echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    earmv*)
+		arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine=${arch}${endian}-unknown
+		;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# Determine ABI tags.
+	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}${abi}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    *:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    e2k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
+	fi
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/scripts/config.rpath b/scripts/config.rpath
new file mode 100755
index 0000000000..c547c68825
--- /dev/null
+++ b/scripts/config.rpath
@@ -0,0 +1,666 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+#   Copyright 1996-2007 Free Software Foundation, Inc.
+#   Taken from GNU libtool, 2001
+#   Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+#   This file is free software; the Free Software Foundation gives
+#   unlimited permission to copy and/or distribute it, with or without
+#   modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+#    CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+#    CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+#   than 256 bytes, otherwise the compiler driver will dump core. The only
+#   known workaround is to choose shorter directory names for the build
+#   directory and/or the installation directory.
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+# Code taken from libtool.m4's _LT_CC_BASENAME.
+
+for cc_temp in $CC""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+  wl='-Wl,'
+else
+  case "$host_os" in
+    aix*)
+      wl='-Wl,'
+      ;;
+    darwin*)
+      case $cc_basename in
+        xlc*)
+          wl='-Wl,'
+          ;;
+      esac
+      ;;
+    mingw* | cygwin* | pw32* | os2*)
+      ;;
+    hpux9* | hpux10* | hpux11*)
+      wl='-Wl,'
+      ;;
+    irix5* | irix6* | nonstopux*)
+      wl='-Wl,'
+      ;;
+    newsos6)
+      ;;
+    linux* | k*bsd*-gnu)
+      case $cc_basename in
+        icc* | ecc*)
+          wl='-Wl,'
+          ;;
+        pgcc | pgf77 | pgf90)
+          wl='-Wl,'
+          ;;
+        ccc*)
+          wl='-Wl,'
+          ;;
+        como)
+          wl='-lopt='
+          ;;
+        *)
+          case `$CC -V 2>&1 | sed 5q` in
+            *Sun\ C*)
+              wl='-Wl,'
+              ;;
+          esac
+          ;;
+      esac
+      ;;
+    osf3* | osf4* | osf5*)
+      wl='-Wl,'
+      ;;
+    rdos*)
+      ;;
+    solaris*)
+      wl='-Wl,'
+      ;;
+    sunos4*)
+      wl='-Qoption ld '
+      ;;
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      wl='-Wl,'
+      ;;
+    sysv4*MP*)
+      ;;
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      wl='-Wl,'
+      ;;
+    unicos*)
+      wl='-Wl,'
+      ;;
+    uts4*)
+      ;;
+  esac
+fi
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+  # Set some defaults for GNU ld with shared library support. These
+  # are reset later if shared libraries are not supported. Putting them
+  # here allows them to be overridden if necessary.
+  # Unlike libtool, we use -rpath here, not --rpath, since the documented
+  # option of GNU ld is called -rpath, not --rpath.
+  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+  case "$host_os" in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+        ld_shlibs=no
+      fi
+      ;;
+    amigaos*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we cannot use
+      # them.
+      ld_shlibs=no
+      ;;
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    cygwin* | mingw* | pw32*)
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      ;;
+    gnu* | linux* | k*bsd*-gnu)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    netbsd*)
+      ;;
+    solaris*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+        ld_shlibs=no
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+          ld_shlibs=no
+          ;;
+        *)
+          if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+            hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+          else
+            ld_shlibs=no
+          fi
+          ;;
+      esac
+      ;;
+    sunos4*)
+      hardcode_direct=yes
+      ;;
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+  esac
+  if test "$ld_shlibs" = no; then
+    hardcode_libdir_flag_spec=
+  fi
+else
+  case "$host_os" in
+    aix3*)
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes; then
+        # Neither direct hardcoding nor static linking is supported with a
+        # broken collect2.
+        hardcode_direct=unsupported
+      fi
+      ;;
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+        # On IA64, the linker does run time linking by default, so we don't
+        # have to do anything special.
+        aix_use_runtimelinking=no
+      else
+        aix_use_runtimelinking=no
+        # Test if we are trying to use run time linking or normal
+        # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+        # need to do runtime linking.
+        case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+          for ld_flag in $LDFLAGS; do
+            if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+              aix_use_runtimelinking=yes
+              break
+            fi
+          done
+          ;;
+        esac
+      fi
+      hardcode_direct=yes
+      hardcode_libdir_separator=':'
+      if test "$GCC" = yes; then
+        case $host_os in aix4.[012]|aix4.[012].*)
+          collect2name=`${CC} -print-prog-name=collect2`
+          if test -f "$collect2name" && \
+            strings "$collect2name" | grep resolve_lib_name >/dev/null
+          then
+            # We have reworked collect2
+            :
+          else
+            # We have old collect2
+            hardcode_direct=unsupported
+            hardcode_minus_L=yes
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_libdir_separator=
+          fi
+          ;;
+        esac
+      fi
+      # Begin _LT_AC_SYS_LIBPATH_AIX.
+      echo 'int main () { return 0; }' > conftest.c
+      ${CC} ${LDFLAGS} conftest.c -o conftest
+      aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+      if test -z "$aix_libpath"; then
+        aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+      fi
+      if test -z "$aix_libpath"; then
+        aix_libpath="/usr/lib:/lib"
+      fi
+      rm -f conftest.c conftest
+      # End _LT_AC_SYS_LIBPATH_AIX.
+      if test "$aix_use_runtimelinking" = yes; then
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+      else
+        if test "$host_cpu" = ia64; then
+          hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+        else
+          hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        fi
+      fi
+      ;;
+    amigaos*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # see comment about different semantics on the GNU ld section
+      ld_shlibs=no
+      ;;
+    bsdi[45]*)
+      ;;
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec=' '
+      libext=lib
+      ;;
+    darwin* | rhapsody*)
+      hardcode_direct=no
+      if test "$GCC" = yes ; then
+        :
+      else
+        case $cc_basename in
+          xlc*)
+            ;;
+          *)
+            ld_shlibs=no
+            ;;
+        esac
+      fi
+      ;;
+    dgux*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      ;;
+    freebsd1*)
+      ld_shlibs=no
+      ;;
+    freebsd2.2*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    freebsd2*)
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      ;;
+    freebsd* | dragonfly*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    hpux9*)
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      ;;
+    hpux10*)
+      if test "$with_gnu_ld" = no; then
+        hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+        hardcode_libdir_separator=:
+        hardcode_direct=yes
+        # hardcode_minus_L: Not really in the search PATH,
+        # but as the default location of the library.
+        hardcode_minus_L=yes
+      fi
+      ;;
+    hpux11*)
+      if test "$with_gnu_ld" = no; then
+        hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+        hardcode_libdir_separator=:
+        case $host_cpu in
+          hppa*64*|ia64*)
+            hardcode_direct=no
+            ;;
+          *)
+            hardcode_direct=yes
+            # hardcode_minus_L: Not really in the search PATH,
+            # but as the default location of the library.
+            hardcode_minus_L=yes
+            ;;
+        esac
+      fi
+      ;;
+    irix5* | irix6* | nonstopux*)
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    netbsd*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    newsos6)
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+        hardcode_direct=yes
+        if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+          hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+        else
+          case "$host_os" in
+            openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+              hardcode_libdir_flag_spec='-R$libdir'
+              ;;
+            *)
+              hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+              ;;
+          esac
+        fi
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      ;;
+    osf3*)
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    osf4* | osf5*)
+      if test "$GCC" = yes; then
+        hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+        # Both cc and cxx compiler support -rpath directly
+        hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      hardcode_libdir_separator=:
+      ;;
+    solaris*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      ;;
+    sunos4*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      ;;
+    sysv4)
+      case $host_vendor in
+        sni)
+          hardcode_direct=yes # is this really true???
+          ;;
+        siemens)
+          hardcode_direct=no
+          ;;
+        motorola)
+          hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+          ;;
+      esac
+      ;;
+    sysv4.3*)
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+        ld_shlibs=yes
+      fi
+      ;;
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      ;;
+    sysv5* | sco3.2v5* | sco5v6*)
+      hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+      hardcode_libdir_separator=':'
+      ;;
+    uts4*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      ;;
+    *)
+      ld_shlibs=no
+      ;;
+  esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
+# Unlike libtool.m4, here we don't care about _all_ names of the library, but
+# only about the one the linker finds when passed -lNAME. This is the last
+# element of library_names_spec in libtool.m4, or possibly two of them if the
+# linker has special search rules.
+library_names_spec=      # the last element of library_names_spec in libtool.m4
+libname_spec='lib$name'
+case "$host_os" in
+  aix3*)
+    library_names_spec='$libname.a'
+    ;;
+  aix4* | aix5*)
+    library_names_spec='$libname$shrext'
+    ;;
+  amigaos*)
+    library_names_spec='$libname.a'
+    ;;
+  beos*)
+    library_names_spec='$libname$shrext'
+    ;;
+  bsdi[45]*)
+    library_names_spec='$libname$shrext'
+    ;;
+  cygwin* | mingw* | pw32*)
+    shrext=.dll
+    library_names_spec='$libname.dll.a $libname.lib'
+    ;;
+  darwin* | rhapsody*)
+    shrext=.dylib
+    library_names_spec='$libname$shrext'
+    ;;
+  dgux*)
+    library_names_spec='$libname$shrext'
+    ;;
+  freebsd1*)
+    ;;
+  freebsd* | dragonfly*)
+    case "$host_os" in
+      freebsd[123]*)
+        library_names_spec='$libname$shrext$versuffix' ;;
+      *)
+        library_names_spec='$libname$shrext' ;;
+    esac
+    ;;
+  gnu*)
+    library_names_spec='$libname$shrext'
+    ;;
+  hpux9* | hpux10* | hpux11*)
+    case $host_cpu in
+      ia64*)
+        shrext=.so
+        ;;
+      hppa*64*)
+        shrext=.sl
+        ;;
+      *)
+        shrext=.sl
+        ;;
+    esac
+    library_names_spec='$libname$shrext'
+    ;;
+  interix[3-9]*)
+    library_names_spec='$libname$shrext'
+    ;;
+  irix5* | irix6* | nonstopux*)
+    library_names_spec='$libname$shrext'
+    case "$host_os" in
+      irix5* | nonstopux*)
+        libsuff= shlibsuff=
+        ;;
+      *)
+        case $LD in
+          *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+          *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+          *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+          *) libsuff= shlibsuff= ;;
+        esac
+        ;;
+    esac
+    ;;
+  linux*oldld* | linux*aout* | linux*coff*)
+    ;;
+  linux* | k*bsd*-gnu)
+    library_names_spec='$libname$shrext'
+    ;;
+  knetbsd*-gnu)
+    library_names_spec='$libname$shrext'
+    ;;
+  netbsd*)
+    library_names_spec='$libname$shrext'
+    ;;
+  newsos6)
+    library_names_spec='$libname$shrext'
+    ;;
+  nto-qnx*)
+    library_names_spec='$libname$shrext'
+    ;;
+  openbsd*)
+    library_names_spec='$libname$shrext$versuffix'
+    ;;
+  os2*)
+    libname_spec='$name'
+    shrext=.dll
+    library_names_spec='$libname.a'
+    ;;
+  osf3* | osf4* | osf5*)
+    library_names_spec='$libname$shrext'
+    ;;
+  rdos*)
+    ;;
+  solaris*)
+    library_names_spec='$libname$shrext'
+    ;;
+  sunos4*)
+    library_names_spec='$libname$shrext$versuffix'
+    ;;
+  sysv4 | sysv4.3*)
+    library_names_spec='$libname$shrext'
+    ;;
+  sysv4*MP*)
+    library_names_spec='$libname$shrext'
+    ;;
+  sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+    library_names_spec='$libname$shrext'
+    ;;
+  uts4*)
+    library_names_spec='$libname$shrext'
+    ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Format of library name prefix.
+libname_spec="$escaped_libname_spec"
+
+# Library names that the linker finds when passed -lNAME.
+library_names_spec="$escaped_library_names_spec"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/scripts/config.sub b/scripts/config.sub
new file mode 100755
index 0000000000..f018151c64
--- /dev/null
+++ b/scripts/config.sub
@@ -0,0 +1,1813 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-07-28'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze*)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| ba \
+	| be32 | be64 \
+	| bfin \
+	| c4x | c8051 | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| e2k | epiphany \
+	| fido | fr30 | frv | ft32 \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| k1om \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa32r6 | mipsisa32r6el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64r6 | mipsisa64r6el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
+	| ns16k | ns32k \
+	| open8 | or1k | or1knd | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pyramid \
+	| riscv32 | riscv64 \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| visium \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	leon|leon[3-9])
+		basic_machine=sparc-$basic_machine
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| ba-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| e2k-* | elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| k1om-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa32r6-* | mipsisa32r6el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64r6-* | mipsisa64r6el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| or1k*-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pyramid-* \
+	| riscv32-* | riscv64-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| visium-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+        asmjs)
+		basic_machine=asmjs-unknown
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16 | cr16-*)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	leon-*|leon[3-9]-*)
+		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	microblaze*)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
+	mingw32)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	moxiebox)
+		basic_machine=moxie-unknown
+		os=-moxiebox
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i686-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tile*)
+		basic_machine=$basic_machine-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# First match some system type aliases
+	# that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-auroraux)
+		os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* | -cloudabi* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	score-*)
+		os=-elf
+		;;
+	spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	c8051-*)
+		os=-elf
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/scripts/config/.gitignore b/scripts/config/.gitignore
new file mode 100644
index 0000000000..0326e060bb
--- /dev/null
+++ b/scripts/config/.gitignore
@@ -0,0 +1,9 @@
+*.o
+conf*
+!conf*.c
+!conf*.h
+mconf*
+!mconf*.c
+!mconf*.h
+mconf_check
+*.*.c
diff --git a/scripts/config/Makefile b/scripts/config/Makefile
new file mode 100644
index 0000000000..3de98082b5
--- /dev/null
+++ b/scripts/config/Makefile
@@ -0,0 +1,52 @@
+# ===========================================================================
+# OpenWrt configuration targets
+# These targets are used from top-level makefile
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf:	  Used for defconfig, oldconfig and related targets
+# mconf:  Used for the mconfig target.
+#         Utilizes the lxdialog package
+# object files used by all kconfig flavours
+
+
+# Platform specific fixes
+#
+# FreeBSD
+
+check_lxdialog = $(shell $(SHELL) $(CURDIR)/lxdialog/check-lxdialog.sh -$(1))
+export CFLAGS += -DKBUILD_NO_NLS -I. $(call check_lxdialog,ccflags)
+
+conf-objs	:= conf.o zconf.tab.o
+mconf-objs	:= mconf.o zconf.tab.o
+lxdialog-objs := \
+	lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o \
+	lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+clean-files	:= zconf.tab.c lex.zconf.c zconf.hash.c
+
+all: conf mconf
+
+conf: $(conf-objs)
+mconf: $(mconf-objs) $(lxdialog-objs)
+	$(CC) -o $@ $^ $(call check_lxdialog,ldflags $(CC))
+
+clean:
+	rm -f *.o lxdialog/*.o $(clean-files) conf mconf
+
+zconf.tab.o: zconf.lex.c zconf.hash.c confdata.c
+
+kconfig_load.o: lkc_defs.h
+
+zconf.tab.c: zconf.y
+zconf.lex.c: zconf.l
+zconf.hash.c: zconf.gperf
+
+%.tab.c: %.y
+	cp $@_shipped $@ || bison -l -b $* -p $(notdir $*) $<
+
+%.lex.c: %.l
+	cp $@_shipped $@ || flex -L -P$(notdir $*) -o$@ $<
+
+%.hash.c: %.gperf
+	cp $@_shipped $@ || gperf < $< > $@
diff --git a/scripts/config/README b/scripts/config/README
new file mode 100644
index 0000000000..ea911be6a7
--- /dev/null
+++ b/scripts/config/README
@@ -0,0 +1,2 @@
+These files were taken from the Linux 3.9 Kernel
+Configuration System and modified for the OpenWrt Buildroot.
diff --git a/scripts/config/conf.c b/scripts/config/conf.c
new file mode 100644
index 0000000000..6d35957afe
--- /dev/null
+++ b/scripts/config/conf.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+static void xfgets(char *str, int size, FILE *in);
+
+enum input_mode {
+	oldaskconfig,
+	silentoldconfig,
+	oldconfig,
+	allnoconfig,
+	allyesconfig,
+	allmodconfig,
+	alldefconfig,
+	randconfig,
+	defconfig,
+	savedefconfig,
+	listnewconfig,
+	olddefconfig,
+} input_mode = oldaskconfig;
+
+static int indent = 1;
+static int tty_stdio;
+static int valid_stdin = 1;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[PATH_MAX];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+
+	menu_get_ext_help(menu, &help);
+
+	printf("\n%s\n", str_get(&help));
+	str_free(&help);
+}
+
+static void strip(char *str)
+{
+	char *p = str;
+	int l;
+
+	while ((isspace(*p)))
+		p++;
+	l = strlen(p);
+	if (p != str)
+		memmove(str, p, l + 1);
+	if (!l)
+		return;
+	p = str + l - 1;
+	while ((isspace(*p)))
+		*p-- = 0;
+}
+
+static void check_stdin(void)
+{
+	if (!valid_stdin) {
+		printf(_("aborted!\n\n"));
+		printf(_("Console input/output is redirected. "));
+		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+		exit(1);
+	}
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+	enum symbol_type type = sym_get_type(sym);
+
+	if (!sym_has_value(sym))
+		printf(_("(NEW) "));
+
+	line[0] = '\n';
+	line[1] = 0;
+
+	if (!sym_is_changable(sym)) {
+		printf("%s\n", def);
+		line[0] = '\n';
+		line[1] = 0;
+		return 0;
+	}
+
+	switch (input_mode) {
+	case oldconfig:
+	case silentoldconfig:
+		if (sym_has_value(sym)) {
+			printf("%s\n", def);
+			return 0;
+		}
+		check_stdin();
+		/* fall through */
+	case oldaskconfig:
+		fflush(stdout);
+		xfgets(line, sizeof(line), stdin);
+		if (!tty_stdio)
+			printf("\n");
+		return 1;
+	default:
+		break;
+	}
+
+	switch (type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		printf("%s\n", def);
+		return 1;
+	default:
+		;
+	}
+	printf("%s", line);
+	return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	const char *def;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+		printf("(%s) ", sym->name);
+		def = sym_get_string_value(sym);
+		if (sym_get_string_value(sym))
+			printf("[%s] ", def);
+		if (!conf_askvalue(sym, def))
+			return 0;
+		switch (line[0]) {
+		case '\n':
+			break;
+		case '?':
+			/* print help */
+			if (line[1] == '\n') {
+				print_help(menu);
+				def = NULL;
+				break;
+			}
+			/* fall through */
+		default:
+			line[strlen(line)-1] = 0;
+			def = line;
+		}
+		if (def && sym_set_string_value(sym, def))
+			return 0;
+	}
+}
+
+static int conf_sym(struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	tristate oldval, newval;
+
+	while (1) {
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+		if (sym->name)
+			printf("(%s) ", sym->name);
+		putchar('[');
+		oldval = sym_get_tristate_value(sym);
+		switch (oldval) {
+		case no:
+			putchar('N');
+			break;
+		case mod:
+			putchar('M');
+			break;
+		case yes:
+			putchar('Y');
+			break;
+		}
+		if (oldval != no && sym_tristate_within_range(sym, no))
+			printf("/n");
+		if (oldval != mod && sym_tristate_within_range(sym, mod))
+			printf("/m");
+		if (oldval != yes && sym_tristate_within_range(sym, yes))
+			printf("/y");
+		if (menu_has_help(menu))
+			printf("/?");
+		printf("] ");
+		if (!conf_askvalue(sym, sym_get_string_value(sym)))
+			return 0;
+		strip(line);
+
+		switch (line[0]) {
+		case 'n':
+		case 'N':
+			newval = no;
+			if (!line[1] || !strcmp(&line[1], "o"))
+				break;
+			continue;
+		case 'm':
+		case 'M':
+			newval = mod;
+			if (!line[1])
+				break;
+			continue;
+		case 'y':
+		case 'Y':
+			newval = yes;
+			if (!line[1] || !strcmp(&line[1], "es"))
+				break;
+			continue;
+		case 0:
+			newval = oldval;
+			break;
+		case '?':
+			goto help;
+		default:
+			continue;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			return 0;
+help:
+		print_help(menu);
+	}
+}
+
+static int conf_choice(struct menu *menu)
+{
+	struct symbol *sym, *def_sym;
+	struct menu *child;
+	bool is_new;
+
+	sym = menu->sym;
+	is_new = !sym_has_value(sym);
+	if (sym_is_changable(sym)) {
+		conf_sym(menu);
+		sym_calc_value(sym);
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			return 0;
+		case yes:
+			break;
+		}
+	} else {
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
+			printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+			return 0;
+		case yes:
+			break;
+		}
+	}
+
+	while (1) {
+		int cnt, def;
+
+		printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+		def_sym = sym_get_choice_value(sym);
+		cnt = def = 0;
+		line[0] = 0;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			if (!child->sym) {
+				printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+				continue;
+			}
+			cnt++;
+			if (child->sym == def_sym) {
+				def = cnt;
+				printf("%*c", indent, '>');
+			} else
+				printf("%*c", indent, ' ');
+			printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+			if (child->sym->name)
+				printf(" (%s)", child->sym->name);
+			if (!sym_has_value(child->sym))
+				printf(_(" (NEW)"));
+			printf("\n");
+		}
+		printf(_("%*schoice"), indent - 1, "");
+		if (cnt == 1) {
+			printf("[1]: 1\n");
+			goto conf_childs;
+		}
+		printf("[1-%d", cnt);
+		if (menu_has_help(menu))
+			printf("?");
+		printf("]: ");
+		switch (input_mode) {
+		case oldconfig:
+		case silentoldconfig:
+			if (!is_new) {
+				cnt = def;
+				printf("%d\n", cnt);
+				break;
+			}
+			check_stdin();
+			/* fall through */
+		case oldaskconfig:
+			fflush(stdout);
+			xfgets(line, sizeof(line), stdin);
+			strip(line);
+			if (line[0] == '?') {
+				print_help(menu);
+				continue;
+			}
+			if (!line[0])
+				cnt = def;
+			else if (isdigit(line[0]))
+				cnt = atoi(line);
+			else
+				continue;
+			break;
+		default:
+			break;
+		}
+
+	conf_childs:
+		for (child = menu->list; child; child = child->next) {
+			if (!child->sym || !menu_is_visible(child))
+				continue;
+			if (!--cnt)
+				break;
+		}
+		if (!child)
+			continue;
+		if (line[0] && line[strlen(line) - 1] == '?') {
+			print_help(child);
+			continue;
+		}
+		sym_set_choice_value(sym, child->sym);
+		for (child = child->list; child; child = child->next) {
+			indent += 2;
+			conf(child);
+			indent -= 2;
+		}
+		return 1;
+	}
+}
+
+static void conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (prop) {
+		const char *prompt;
+
+		switch (prop->type) {
+		case P_MENU:
+			if ((input_mode == silentoldconfig ||
+			     input_mode == listnewconfig ||
+			     input_mode == olddefconfig) &&
+			    rootEntry != menu) {
+				check_conf(menu);
+				return;
+			}
+			/* fall through */
+		case P_COMMENT:
+			prompt = menu_get_prompt(menu);
+			if (prompt)
+				printf("%*c\n%*c %s\n%*c\n",
+					indent, '*',
+					indent, '*', _(prompt),
+					indent, '*');
+		default:
+			;
+		}
+	}
+
+	if (!sym)
+		goto conf_childs;
+
+	if (sym_is_choice(sym)) {
+		conf_choice(menu);
+		if (sym->curr.tri != mod)
+			return;
+		goto conf_childs;
+	}
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		conf_string(menu);
+		break;
+	default:
+		conf_sym(menu);
+		break;
+	}
+
+conf_childs:
+	if (sym)
+		indent += 2;
+	for (child = menu->list; child; child = child->next)
+		conf(child);
+	if (sym)
+		indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct menu *child;
+
+	if (!menu_is_visible(menu))
+		return;
+
+	sym = menu->sym;
+	if (sym && !sym_has_value(sym)) {
+		if (sym_is_changable(sym) ||
+		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+			if (input_mode == listnewconfig) {
+				if (sym->name && !sym_is_choice_value(sym)) {
+					printf("%s%s\n", CONFIG_, sym->name);
+				}
+			} else if (input_mode != olddefconfig) {
+				if (!conf_cnt++)
+					printf(_("*\n* Restart config...\n*\n"));
+				rootEntry = menu_get_parent_menu(menu);
+				conf(rootEntry);
+			}
+		}
+	}
+
+	for (child = menu->list; child; child = child->next)
+		check_conf(child);
+}
+
+static struct option long_opts[] = {
+	{"oldaskconfig",    no_argument,       NULL, oldaskconfig},
+	{"oldconfig",       no_argument,       NULL, oldconfig},
+	{"silentoldconfig", no_argument,       NULL, silentoldconfig},
+	{"defconfig",       optional_argument, NULL, defconfig},
+	{"savedefconfig",   required_argument, NULL, savedefconfig},
+	{"allnoconfig",     no_argument,       NULL, allnoconfig},
+	{"allyesconfig",    no_argument,       NULL, allyesconfig},
+	{"allmodconfig",    no_argument,       NULL, allmodconfig},
+	{"alldefconfig",    no_argument,       NULL, alldefconfig},
+	{"randconfig",      no_argument,       NULL, randconfig},
+	{"listnewconfig",   no_argument,       NULL, listnewconfig},
+	{"olddefconfig",    no_argument,       NULL, olddefconfig},
+	/*
+	 * oldnoconfig is an alias of olddefconfig, because people already
+	 * are dependent on its behavior(sets new symbols to their default
+	 * value but not 'n') with the counter-intuitive name.
+	 */
+	{"oldnoconfig",     no_argument,       NULL, olddefconfig},
+	{NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+
+	printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
+	printf("[option] is _one_ of the following:\n");
+	printf("  --listnewconfig         List new options\n");
+	printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
+	printf("  --oldconfig             Update a configuration using a provided .config as base\n");
+	printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
+	printf("  --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
+	printf("  --oldnoconfig           An alias of olddefconfig\n");
+	printf("  --defconfig <file>      New config with default defined in <file>\n");
+	printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
+	printf("  --allnoconfig           New config where all options are answered with no\n");
+	printf("  --allyesconfig          New config where all options are answered with yes\n");
+	printf("  --allmodconfig          New config where all options are answered with mod\n");
+	printf("  --alldefconfig          New config with all symbols set to default\n");
+	printf("  --randconfig            New config with random answer to all options\n");
+}
+
+int main(int ac, char **av)
+{
+	const char *progname = av[0];
+	int opt;
+	const char *name, *defconfig_file = NULL /* gcc uninit */;
+	struct stat tmpstat;
+	const char *input_file = NULL, *output_file = NULL;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	tty_stdio = isatty(0) && isatty(1) && isatty(2);
+
+	while ((opt = getopt_long(ac, av, "r:w:s", long_opts, NULL)) != -1) {
+		if (opt == 's') {
+			conf_set_message_callback(NULL);
+			continue;
+		}
+		switch (opt) {
+		case silentoldconfig:
+			sync_kconfig = 1;
+			break;
+		case defconfig:
+		case savedefconfig:
+			defconfig_file = optarg;
+			break;
+		case randconfig:
+		{
+			struct timeval now;
+			unsigned int seed;
+			char *seed_env;
+
+			/*
+			 * Use microseconds derived seed,
+			 * compensate for systems where it may be zero
+			 */
+			gettimeofday(&now, NULL);
+			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+
+			seed_env = getenv("KCONFIG_SEED");
+			if( seed_env && *seed_env ) {
+				char *endp;
+				int tmp = (int)strtol(seed_env, &endp, 0);
+				if (*endp == '\0') {
+					seed = tmp;
+				}
+			}
+			fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
+			srand(seed);
+			break;
+		}
+		case oldaskconfig:
+		case oldconfig:
+		case allnoconfig:
+		case allyesconfig:
+		case allmodconfig:
+		case alldefconfig:
+		case listnewconfig:
+		case olddefconfig:
+			break;
+		case 'r':
+			input_file = optarg;
+			continue;
+		case 'w':
+			output_file = optarg;
+			continue;
+		case '?':
+			conf_usage(progname);
+			exit(1);
+			break;
+		}
+		input_mode = (enum input_mode)opt;
+	}
+	if (ac == optind) {
+		printf(_("%s: Kconfig file missing\n"), av[0]);
+		conf_usage(progname);
+		exit(1);
+	}
+	name = av[optind];
+	conf_parse(name);
+	//zconfdump(stdout);
+	if (sync_kconfig) {
+		name = conf_get_configname();
+		if (stat(name, &tmpstat)) {
+			fprintf(stderr, _("***\n"
+				"*** Configuration file \"%s\" not found!\n"
+				"***\n"
+				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+				"*** \"make menuconfig\" or \"make xconfig\").\n"
+				"***\n"), name);
+			exit(1);
+		}
+	}
+
+	switch (input_mode) {
+	case defconfig:
+		if (!defconfig_file)
+			defconfig_file = conf_get_default_confname();
+		if (conf_read(defconfig_file)) {
+			printf(_("***\n"
+				"*** Can't find default configuration \"%s\"!\n"
+				"***\n"), defconfig_file);
+			exit(1);
+		}
+		break;
+	case savedefconfig:
+	case silentoldconfig:
+	case oldaskconfig:
+	case oldconfig:
+	case listnewconfig:
+	case olddefconfig:
+	case allnoconfig:
+	case allyesconfig:
+	case allmodconfig:
+	case alldefconfig:
+	case randconfig:
+		conf_read(input_file);
+		break;
+	default:
+		break;
+	}
+
+	if (sync_kconfig) {
+		if (conf_get_changed()) {
+			name = getenv("KCONFIG_NOSILENTUPDATE");
+			if (name && *name) {
+				fprintf(stderr,
+					_("\n*** The configuration requires explicit update.\n\n"));
+				return 1;
+			}
+		}
+		valid_stdin = tty_stdio;
+	}
+
+	switch (input_mode) {
+	case allnoconfig:
+		conf_set_all_new_symbols(def_no);
+		break;
+	case allyesconfig:
+		conf_set_all_new_symbols(def_yes);
+		break;
+	case allmodconfig:
+		conf_set_all_new_symbols(def_mod);
+		break;
+	case alldefconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case randconfig:
+		/* Really nothing to do in this loop */
+		while (conf_set_all_new_symbols(def_random)) ;
+		break;
+	case defconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case savedefconfig:
+		break;
+	case oldaskconfig:
+		rootEntry = &rootmenu;
+		conf(&rootmenu);
+		input_mode = silentoldconfig;
+		/* fall through */
+	case oldconfig:
+	case listnewconfig:
+	case olddefconfig:
+	case silentoldconfig:
+		/* Update until a loop caused no more changes */
+		do {
+			conf_cnt = 0;
+			check_conf(&rootmenu);
+		} while (conf_cnt &&
+			 (input_mode != listnewconfig &&
+			  input_mode != olddefconfig));
+		break;
+	}
+
+	if (sync_kconfig) {
+		/* silentoldconfig is used during the build so we shall update autoconf.
+		 * All other commands are only used to generate a config.
+		 */
+		if ((output_file || conf_get_changed()) &&
+		    conf_write(output_file)) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			exit(1);
+		}
+		if (conf_write_autoconf()) {
+			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
+			return 1;
+		}
+	} else if (input_mode == savedefconfig) {
+		if (conf_write_defconfig(defconfig_file)) {
+			fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+				defconfig_file);
+			return 1;
+		}
+	} else if (input_mode != listnewconfig) {
+		if (conf_write(output_file)) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			exit(1);
+		}
+	}
+	return 0;
+}
+
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(char *str, int size, FILE *in)
+{
+	if (fgets(str, size, in) == NULL)
+		fprintf(stderr, "\nError in reading or end of file.\n");
+}
diff --git a/scripts/config/confdata.c b/scripts/config/confdata.c
new file mode 100644
index 0000000000..3a3a4bff43
--- /dev/null
+++ b/scripts/config/confdata.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+struct conf_printer {
+	void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+	void (*print_comment)(FILE *, const char *, void *);
+};
+
+static void conf_warning(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+	__attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *fmt, va_list ap)
+{
+	printf("#\n# ");
+	vprintf(fmt, ap);
+	printf("\n#\n");
+}
+
+static void (*conf_message_callback) (const char *fmt, va_list ap) =
+	conf_default_message_callback;
+void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+{
+	conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (conf_message_callback)
+		conf_message_callback(fmt, ap);
+	va_end(ap);
+}
+
+const char *conf_get_configname(void)
+{
+	char *name = getenv("KCONFIG_CONFIG");
+
+	return name ? name : ".config";
+}
+
+const char *conf_get_autoconfig_name(void)
+{
+	char *name = getenv("KCONFIG_AUTOCONFIG");
+
+	return name ? name : "include/config/auto.conf";
+}
+
+static char *conf_expand_value(const char *in)
+{
+	struct symbol *sym;
+	const char *src;
+	static char res_value[SYMBOL_MAXLENGTH];
+	char *dst, name[SYMBOL_MAXLENGTH];
+
+	res_value[0] = 0;
+	dst = name;
+	while ((src = strchr(in, '$'))) {
+		strncat(res_value, in, src - in);
+		src++;
+		dst = name;
+		while (isalnum(*src) || *src == '_')
+			*dst++ = *src++;
+		*dst = 0;
+		sym = sym_lookup(name, 0);
+		sym_calc_value(sym);
+		strcat(res_value, sym_get_string_value(sym));
+		in = src;
+	}
+	strcat(res_value, in);
+
+	return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+	struct stat buf;
+	static char fullname[PATH_MAX+1];
+	char *env, *name;
+
+	name = conf_expand_value(conf_defname);
+	env = getenv(SRCTREE);
+	if (env) {
+		sprintf(fullname, "%s/%s", env, name);
+		if (!stat(fullname, &buf))
+			return fullname;
+	}
+	return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+	char *p2;
+
+	switch (sym->type) {
+	case S_TRISTATE:
+		if (p[0] == 'm') {
+			sym->def[def].tri = mod;
+			sym->flags |= def_flags;
+			break;
+		}
+		/* fall through */
+	case S_BOOLEAN:
+		if (p[0] == 'y') {
+			sym->def[def].tri = yes;
+			sym->flags |= def_flags;
+			break;
+		}
+		if (p[0] == 'n') {
+			sym->def[def].tri = no;
+			sym->flags |= def_flags;
+			break;
+		}
+		if (def != S_DEF_AUTO)
+			conf_warning("symbol value '%s' invalid for %s",
+				     p, sym->name);
+		return 1;
+	case S_OTHER:
+		if (*p != '"') {
+			for (p2 = p; *p2 && !isspace(*p2); p2++)
+				;
+			sym->type = S_STRING;
+			goto done;
+		}
+		/* fall through */
+	case S_STRING:
+		if (*p++ != '"')
+			break;
+		for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+			if (*p2 == '"') {
+				*p2 = 0;
+				break;
+			}
+			memmove(p2, p2 + 1, strlen(p2));
+		}
+		if (!p2) {
+			if (def != S_DEF_AUTO)
+				conf_warning("invalid string found");
+			return 1;
+		}
+		/* fall through */
+	case S_INT:
+	case S_HEX:
+	done:
+		if (sym_string_valid(sym, p)) {
+			sym->def[def].val = strdup(p);
+			sym->flags |= def_flags;
+		} else {
+			if (def != S_DEF_AUTO)
+				conf_warning("symbol value '%s' invalid for %s",
+					     p, sym->name);
+			return 1;
+		}
+		break;
+	default:
+		;
+	}
+	return 0;
+}
+
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+	char *nline;
+	size_t new_size = slen + 1;
+	if (new_size > *n) {
+		new_size += LINE_GROWTH - 1;
+		new_size *= 2;
+		nline = realloc(*lineptr, new_size);
+		if (!nline)
+			return -1;
+
+		*lineptr = nline;
+		*n = new_size;
+	}
+
+	(*lineptr)[slen] = c;
+
+	return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+	char *line = *lineptr;
+	size_t slen = 0;
+
+	for (;;) {
+		int c = getc(stream);
+
+		switch (c) {
+		case '\n':
+			if (add_byte(c, &line, slen, n) < 0)
+				goto e_out;
+			slen++;
+			/* fall through */
+		case EOF:
+			if (add_byte('\0', &line, slen, n) < 0)
+				goto e_out;
+			*lineptr = line;
+			if (slen == 0)
+				return -1;
+			return slen;
+		default:
+			if (add_byte(c, &line, slen, n) < 0)
+				goto e_out;
+			slen++;
+		}
+	}
+
+e_out:
+	line[slen-1] = '\0';
+	*lineptr = line;
+	return -1;
+}
+
+void conf_reset(int def)
+{
+	struct symbol *sym;
+	int i, def_flags;
+
+	def_flags = SYMBOL_DEF << def;
+	for_all_symbols(i, sym) {
+		sym->flags |= SYMBOL_CHANGED;
+		sym->flags &= ~(def_flags|SYMBOL_VALID);
+		if (sym_is_choice(sym))
+			sym->flags |= def_flags;
+		switch (sym->type) {
+		case S_INT:
+		case S_HEX:
+		case S_STRING:
+			if (sym->def[def].val)
+				free(sym->def[def].val);
+			/* fall through */
+		default:
+			sym->def[def].val = NULL;
+			sym->def[def].tri = no;
+		}
+	}
+}
+
+int conf_read_simple(const char *name, int def)
+{
+	FILE *in = NULL;
+	char   *line = NULL;
+	size_t  line_asize = 0;
+	char *p, *p2;
+	struct symbol *sym;
+	int def_flags;
+
+	if (name) {
+		in = zconf_fopen(name);
+	} else {
+		struct property *prop;
+
+		name = conf_get_configname();
+		in = zconf_fopen(name);
+		if (in)
+			goto load;
+		sym_add_change_count(1);
+		if (!sym_defconfig_list)
+			return 1;
+
+		for_all_defaults(sym_defconfig_list, prop) {
+			if (expr_calc_value(prop->visible.expr) == no ||
+			    prop->expr->type != E_SYMBOL)
+				continue;
+			name = conf_expand_value(prop->expr->left.sym->name);
+			in = zconf_fopen(name);
+			if (in) {
+				conf_message(_("using defaults found in %s"),
+					 name);
+				goto load;
+			}
+		}
+	}
+	if (!in)
+		return 1;
+
+load:
+	conf_filename = name;
+	conf_lineno = 0;
+	conf_warnings = 0;
+	conf_unsaved = 0;
+
+	def_flags = SYMBOL_DEF << def;
+	conf_reset(def);
+
+	while (compat_getline(&line, &line_asize, in) != -1) {
+		conf_lineno++;
+		sym = NULL;
+		if (line[0] == '#') {
+			if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+				continue;
+			p = strchr(line + 2 + strlen(CONFIG_), ' ');
+			if (!p)
+				continue;
+			*p++ = 0;
+			if (strncmp(p, "is not set", 10))
+				continue;
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 2 + strlen(CONFIG_));
+				if (!sym) {
+					sym_add_change_count(1);
+					goto setsym;
+				}
+			} else {
+				sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_BOOLEAN;
+			}
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				sym->def[def].tri = no;
+				sym->flags |= def_flags;
+				break;
+			default:
+				;
+			}
+		} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+			p = strchr(line + strlen(CONFIG_), '=');
+			if (!p)
+				continue;
+			*p++ = 0;
+			p2 = strchr(p, '\n');
+			if (p2) {
+				*p2-- = 0;
+				if (*p2 == '\r')
+					*p2 = 0;
+			}
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + strlen(CONFIG_));
+				if (!sym) {
+					sym_add_change_count(1);
+					goto setsym;
+				}
+			} else {
+				sym = sym_lookup(line + strlen(CONFIG_), 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_OTHER;
+			}
+			if (conf_set_sym_val(sym, def, def_flags, p))
+				continue;
+		} else {
+			if (line[0] != '\r' && line[0] != '\n')
+				conf_warning("unexpected data: %.*s",
+					     (int)strcspn(line, "\r\n"), line);
+
+			continue;
+		}
+setsym:
+		if (sym && sym_is_choice_value(sym)) {
+			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+			switch (sym->def[def].tri) {
+			case no:
+				break;
+			case mod:
+				if (cs->def[def].tri == yes) {
+					conf_warning("%s creates inconsistent choice state", sym->name);
+					cs->flags &= ~def_flags;
+				}
+				break;
+			case yes:
+				if (cs->def[def].tri != no)
+					conf_warning("override: %s changes choice state", sym->name);
+				cs->def[def].val = sym;
+				break;
+			}
+			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+		}
+	}
+	free(line);
+	fclose(in);
+	return 0;
+}
+
+int conf_read(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	sym_set_change_count(0);
+
+	if (conf_read_simple(name, S_DEF_USER)) {
+		sym_calc_value(modules_sym);
+		return 1;
+	}
+
+	sym_calc_value(modules_sym);
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+			continue;
+		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+			/* check that calculated value agrees with saved value */
+			switch (sym->type) {
+			case S_BOOLEAN:
+			case S_TRISTATE:
+				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+					break;
+				if (!sym_is_choice(sym))
+					continue;
+				/* fall through */
+			default:
+				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+					continue;
+				break;
+			}
+		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+			/* no previous value and not saved */
+			continue;
+		conf_unsaved++;
+		/* maybe print value in verbose mode... */
+	}
+
+	for_all_symbols(i, sym) {
+		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+			/* Reset values of generates values, so they'll appear
+			 * as new, if they should become visible, but that
+			 * doesn't quite work if the Kconfig and the saved
+			 * configuration disagree.
+			 */
+			if (sym->visible == no && !conf_unsaved)
+				sym->flags &= ~SYMBOL_DEF_USER;
+			switch (sym->type) {
+			case S_STRING:
+			case S_INT:
+			case S_HEX:
+				/* Reset a string value if it's out of range */
+				if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+					break;
+				sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+				conf_unsaved++;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	sym_add_change_count(conf_warnings || conf_unsaved);
+
+	return 0;
+}
+
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		if (*value == 'n') {
+			bool skip_unset = (arg != NULL);
+
+			if (!skip_unset)
+				fprintf(fp, "# %s%s is not set\n",
+				    CONFIG_, sym->name);
+			return;
+		}
+		break;
+	default:
+		break;
+	}
+
+	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+	const char *p = value;
+	size_t l;
+
+	for (;;) {
+		l = strcspn(p, "\n");
+		fprintf(fp, "#");
+		if (l) {
+			fprintf(fp, " ");
+			xfwrite(p, l, 1, fp);
+			p += l;
+		}
+		fprintf(fp, "\n");
+		if (*p++ == '\0')
+			break;
+	}
+}
+
+static struct conf_printer kconfig_printer_cb =
+{
+	.print_symbol = kconfig_print_symbol,
+	.print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE: {
+		const char *suffix = "";
+
+		switch (*value) {
+		case 'n':
+			break;
+		case 'm':
+			suffix = "_MODULE";
+			/* fall through */
+		default:
+			fprintf(fp, "#define %s%s%s 1\n",
+			    CONFIG_, sym->name, suffix);
+		}
+		break;
+	}
+	case S_HEX: {
+		const char *prefix = "";
+
+		if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+			prefix = "0x";
+		fprintf(fp, "#define %s%s %s%s\n",
+		    CONFIG_, sym->name, prefix, value);
+		break;
+	}
+	case S_STRING:
+	case S_INT:
+		fprintf(fp, "#define %s%s %s\n",
+		    CONFIG_, sym->name, value);
+		break;
+	default:
+		break;
+	}
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+	const char *p = value;
+	size_t l;
+
+	fprintf(fp, "/*\n");
+	for (;;) {
+		l = strcspn(p, "\n");
+		fprintf(fp, " *");
+		if (l) {
+			fprintf(fp, " ");
+			xfwrite(p, l, 1, fp);
+			p += l;
+		}
+		fprintf(fp, "\n");
+		if (*p++ == '\0')
+			break;
+	}
+	fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+	.print_symbol = header_print_symbol,
+	.print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+	if (sym->type == S_TRISTATE && *value != 'n')
+		fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+	.print_symbol = tristate_print_symbol,
+	.print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+			      struct conf_printer *printer, void *printer_arg)
+{
+	const char *str;
+
+	switch (sym->type) {
+	case S_OTHER:
+	case S_UNKNOWN:
+		break;
+	case S_STRING:
+		str = sym_get_string_value(sym);
+		str = sym_escape_string_value(str);
+		printer->print_symbol(fp, sym, str, printer_arg);
+		free((void *)str);
+		break;
+	default:
+		str = sym_get_string_value(sym);
+		printer->print_symbol(fp, sym, str, printer_arg);
+	}
+}
+
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+	char buf[256];
+
+	snprintf(buf, sizeof(buf),
+	    "\n"
+	    "Automatically generated file; DO NOT EDIT.\n"
+	    "%s\n",
+	    rootmenu.prompt->text);
+
+	printer->print_comment(fp, buf, printer_arg);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+	struct symbol *sym;
+	struct menu *menu;
+	FILE *out;
+
+	out = fopen(filename, "w");
+	if (!out)
+		return 1;
+
+	sym_clear_all_valid();
+
+	/* Traverse all menus to find all relevant symbols */
+	menu = rootmenu.list;
+
+	while (menu != NULL)
+	{
+		sym = menu->sym;
+		if (sym == NULL) {
+			if (!menu_is_visible(menu))
+				goto next_menu;
+		} else if (!sym_is_choice(sym)) {
+			sym_calc_value(sym);
+			if (!(sym->flags & SYMBOL_WRITE))
+				goto next_menu;
+			sym->flags &= ~SYMBOL_WRITE;
+			/* If we cannot change the symbol - skip */
+			if (!sym_is_changable(sym))
+				goto next_menu;
+			/* If symbol equals to default value - skip */
+			if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+				goto next_menu;
+
+			/*
+			 * If symbol is a choice value and equals to the
+			 * default for a choice - skip.
+			 * But only if value is bool and equal to "y" and
+			 * choice is not "optional".
+			 * (If choice is "optional" then all values can be "n")
+			 */
+			if (sym_is_choice_value(sym)) {
+				struct symbol *cs;
+				struct symbol *ds;
+
+				cs = prop_get_symbol(sym_get_choice_prop(sym));
+				ds = sym_choice_default(cs);
+				if (!sym_is_optional(cs) && sym == ds) {
+					if ((sym->type == S_BOOLEAN) &&
+					    sym_get_tristate_value(sym) == yes)
+						goto next_menu;
+				}
+			}
+			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+		}
+next_menu:
+		if (menu->list != NULL) {
+			menu = menu->list;
+		}
+		else if (menu->next != NULL) {
+			menu = menu->next;
+		} else {
+			while ((menu = menu->parent)) {
+				if (menu->next != NULL) {
+					menu = menu->next;
+					break;
+				}
+			}
+		}
+	}
+	fclose(out);
+	return 0;
+}
+
+int conf_write(const char *name)
+{
+	FILE *out;
+	struct symbol *sym;
+	struct menu *menu;
+	const char *basename;
+	const char *str;
+	char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+	char *env;
+
+	dirname[0] = 0;
+	if (name && name[0]) {
+		struct stat st;
+		char *slash;
+
+		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+			strcpy(dirname, name);
+			strcat(dirname, "/");
+			basename = conf_get_configname();
+		} else if ((slash = strrchr(name, '/'))) {
+			int size = slash - name + 1;
+			memcpy(dirname, name, size);
+			dirname[size] = 0;
+			if (slash[1])
+				basename = slash + 1;
+			else
+				basename = conf_get_configname();
+		} else
+			basename = name;
+	} else
+		basename = conf_get_configname();
+
+	sprintf(newname, "%s%s", dirname, basename);
+	env = getenv("KCONFIG_OVERWRITECONFIG");
+	if (!env || !*env) {
+		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+		out = fopen(tmpname, "w");
+	} else {
+		*tmpname = 0;
+		out = fopen(newname, "w");
+	}
+	if (!out)
+		return 1;
+
+	conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+	if (!conf_get_changed())
+		sym_clear_all_valid();
+
+	menu = rootmenu.list;
+	while (menu) {
+		sym = menu->sym;
+		if (!sym) {
+			if (!menu_is_visible(menu))
+				goto next;
+			str = menu_get_prompt(menu);
+			fprintf(out, "\n"
+				     "#\n"
+				     "# %s\n"
+				     "#\n", str);
+		} else if (!(sym->flags & SYMBOL_CHOICE)) {
+			sym_calc_value(sym);
+			if (!(sym->flags & SYMBOL_WRITE))
+				goto next;
+			sym->flags &= ~SYMBOL_WRITE;
+
+			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+		}
+
+next:
+		if (menu->list) {
+			menu = menu->list;
+			continue;
+		}
+		if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+	fclose(out);
+
+	if (*tmpname) {
+		strcat(dirname, basename);
+		strcat(dirname, ".old");
+		rename(newname, dirname);
+		if (rename(tmpname, newname))
+			return 1;
+	}
+
+	conf_message(_("configuration written to %s"), newname);
+
+	sym_set_change_count(0);
+
+	return 0;
+}
+
+static int conf_split_config(void)
+{
+	const char *name;
+	char path[PATH_MAX+1];
+	char *s, *d, c;
+	struct symbol *sym;
+	struct stat sb;
+	int res, i, fd;
+
+	name = conf_get_autoconfig_name();
+	conf_read_simple(name, S_DEF_AUTO);
+	sym_calc_value(modules_sym);
+
+	if (chdir("include/config"))
+		return 1;
+
+	res = 0;
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+			continue;
+		if (sym->flags & SYMBOL_WRITE) {
+			if (sym->flags & SYMBOL_DEF_AUTO) {
+				/*
+				 * symbol has old and new value,
+				 * so compare them...
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) ==
+					    sym->def[S_DEF_AUTO].tri)
+						continue;
+					break;
+				case S_STRING:
+				case S_HEX:
+				case S_INT:
+					if (!strcmp(sym_get_string_value(sym),
+						    sym->def[S_DEF_AUTO].val))
+						continue;
+					break;
+				default:
+					break;
+				}
+			} else {
+				/*
+				 * If there is no old value, only 'no' (unset)
+				 * is allowed as new value.
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) == no)
+						continue;
+					break;
+				default:
+					break;
+				}
+			}
+		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
+			/* There is neither an old nor a new value. */
+			continue;
+		/* else
+		 *	There is an old value, but no new value ('no' (unset)
+		 *	isn't saved in auto.conf, so the old value is always
+		 *	different from 'no').
+		 */
+
+		/* Replace all '_' and append ".h" */
+		s = sym->name;
+		d = path;
+		while ((c = *s++)) {
+			c = tolower(c);
+			*d++ = (c == '_') ? '/' : c;
+		}
+		strcpy(d, ".h");
+
+		/* Assume directory path already exists. */
+		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+		if (fd == -1) {
+			if (errno != ENOENT) {
+				res = 1;
+				break;
+			}
+			/*
+			 * Create directory components,
+			 * unless they exist already.
+			 */
+			d = path;
+			while ((d = strchr(d, '/'))) {
+				*d = 0;
+				if (stat(path, &sb) && mkdir(path, 0755)) {
+					res = 1;
+					goto out;
+				}
+				*d++ = '/';
+			}
+			/* Try it again. */
+			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+			if (fd == -1) {
+				res = 1;
+				break;
+			}
+		}
+		close(fd);
+	}
+out:
+	if (chdir("../.."))
+		return 1;
+
+	return res;
+}
+
+int conf_write_autoconf(void)
+{
+	struct symbol *sym;
+	const char *name;
+	FILE *out, *tristate, *out_h;
+	int i;
+
+	sym_clear_all_valid();
+
+	file_write_dep("include/config/auto.conf.cmd");
+
+	if (conf_split_config())
+		return 1;
+
+	out = fopen(".tmpconfig", "w");
+	if (!out)
+		return 1;
+
+	tristate = fopen(".tmpconfig_tristate", "w");
+	if (!tristate) {
+		fclose(out);
+		return 1;
+	}
+
+	out_h = fopen(".tmpconfig.h", "w");
+	if (!out_h) {
+		fclose(out);
+		fclose(tristate);
+		return 1;
+	}
+
+	conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+	conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+	conf_write_heading(out_h, &header_printer_cb, NULL);
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+			continue;
+
+		/* write symbol to auto.conf, tristate and header files */
+		conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
+
+		conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+		conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
+	}
+	fclose(out);
+	fclose(tristate);
+	fclose(out_h);
+
+	name = getenv("KCONFIG_AUTOHEADER");
+	if (!name)
+		name = "include/generated/autoconf.h";
+	if (rename(".tmpconfig.h", name))
+		return 1;
+	name = getenv("KCONFIG_TRISTATE");
+	if (!name)
+		name = "include/config/tristate.conf";
+	if (rename(".tmpconfig_tristate", name))
+		return 1;
+	name = conf_get_autoconfig_name();
+	/*
+	 * This must be the last step, kbuild has a dependency on auto.conf
+	 * and this marks the successful completion of the previous steps.
+	 */
+	if (rename(".tmpconfig", name))
+		return 1;
+
+	return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+	int _sym_change_count = sym_change_count;
+	sym_change_count = count;
+	if (conf_changed_callback &&
+	    (bool)_sym_change_count != (bool)count)
+		conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+	sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+	return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+	conf_changed_callback = fn;
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct expr *e;
+	int cnt, def;
+
+	/*
+	 * If choice is mod then we may have more items selected
+	 * and if no then no-one.
+	 * In both cases stop.
+	 */
+	if (csym->curr.tri != yes)
+		return false;
+
+	prop = sym_get_choice_prop(csym);
+
+	/* count entries in choice block */
+	cnt = 0;
+	expr_list_for_each_sym(prop->expr, e, sym)
+		cnt++;
+
+	/*
+	 * find a random value and set it to yes,
+	 * set the rest to no so we have only one set
+	 */
+	def = (rand() % cnt);
+
+	cnt = 0;
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		if (def == cnt++) {
+			sym->def[S_DEF_USER].tri = yes;
+			csym->def[S_DEF_USER].val = sym;
+		}
+		else {
+			sym->def[S_DEF_USER].tri = no;
+		}
+		sym->flags |= SYMBOL_DEF_USER;
+		/* clear VALID to get value calculated */
+		sym->flags &= ~SYMBOL_VALID;
+	}
+	csym->flags |= SYMBOL_DEF_USER;
+	/* clear VALID to get value calculated */
+	csym->flags &= ~(SYMBOL_VALID);
+
+	return true;
+}
+
+void set_all_choice_values(struct symbol *csym)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct expr *e;
+
+	prop = sym_get_choice_prop(csym);
+
+	/*
+	 * Set all non-assinged choice values to no
+	 */
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		if (!sym_has_value(sym))
+			sym->def[S_DEF_USER].tri = no;
+	}
+	csym->flags |= SYMBOL_DEF_USER;
+	/* clear VALID to get value calculated */
+	csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
+}
+
+bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+	struct symbol *sym, *csym;
+	int i, cnt, pby, pty, ptm;	/* pby: probability of boolean  = y
+					 * pty: probability of tristate = y
+					 * ptm: probability of tristate = m
+					 */
+
+	pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
+				   * below, otherwise gcc whines about
+				   * -Wmaybe-uninitialized */
+	if (mode == def_random) {
+		int n, p[3];
+		char *env = getenv("KCONFIG_PROBABILITY");
+		n = 0;
+		while( env && *env ) {
+			char *endp;
+			int tmp = strtol( env, &endp, 10 );
+			if( tmp >= 0 && tmp <= 100 ) {
+				p[n++] = tmp;
+			} else {
+				errno = ERANGE;
+				perror( "KCONFIG_PROBABILITY" );
+				exit( 1 );
+			}
+			env = (*endp == ':') ? endp+1 : endp;
+			if( n >=3 ) {
+				break;
+			}
+		}
+		switch( n ) {
+		case 1:
+			pby = p[0]; ptm = pby/2; pty = pby-ptm;
+			break;
+		case 2:
+			pty = p[0]; ptm = p[1]; pby = pty + ptm;
+			break;
+		case 3:
+			pby = p[0]; pty = p[1]; ptm = p[2];
+			break;
+		}
+
+		if( pty+ptm > 100 ) {
+			errno = ERANGE;
+			perror( "KCONFIG_PROBABILITY" );
+			exit( 1 );
+		}
+	}
+	bool has_changed = false;
+
+	sym_clear_all_valid();
+
+	for_all_symbols(i, sym) {
+		if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
+			continue;
+		switch (sym_get_type(sym)) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			has_changed = true;
+			switch (mode) {
+			case def_yes:
+				sym->def[S_DEF_USER].tri = yes;
+				break;
+			case def_mod:
+				sym->def[S_DEF_USER].tri = mod;
+				break;
+			case def_no:
+				if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
+					sym->def[S_DEF_USER].tri = yes;
+				else
+					sym->def[S_DEF_USER].tri = no;
+				break;
+			case def_random:
+				sym->def[S_DEF_USER].tri = no;
+				cnt = rand() % 100;
+				if (sym->type == S_TRISTATE) {
+					if (cnt < pty)
+						sym->def[S_DEF_USER].tri = yes;
+					else if (cnt < (pty+ptm))
+						sym->def[S_DEF_USER].tri = mod;
+				} else if (cnt < pby)
+					sym->def[S_DEF_USER].tri = yes;
+				break;
+			default:
+				continue;
+			}
+			if (!(sym_is_choice(sym) && mode == def_random))
+				sym->flags |= SYMBOL_DEF_USER;
+			break;
+		default:
+			break;
+		}
+
+	}
+
+	/*
+	 * We have different type of choice blocks.
+	 * If curr.tri equals to mod then we can select several
+	 * choice symbols in one block.
+	 * In this case we do nothing.
+	 * If curr.tri equals yes then only one symbol can be
+	 * selected in a choice block and we set it to yes,
+	 * and the rest to no.
+	 */
+	if (mode != def_random) {
+		for_all_symbols(i, csym) {
+			if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+			    sym_is_choice_value(csym))
+				csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+		}
+	}
+
+	for_all_symbols(i, csym) {
+		if (sym_has_value(csym) || !sym_is_choice(csym))
+			continue;
+
+		sym_calc_value(csym);
+		if (mode == def_random)
+			has_changed = randomize_choice_values(csym);
+		else {
+			set_all_choice_values(csym);
+			has_changed = true;
+		}
+	}
+
+	return has_changed;
+}
diff --git a/scripts/config/expr.c b/scripts/config/expr.c
new file mode 100644
index 0000000000..cbf4996dd9
--- /dev/null
+++ b/scripts/config/expr.c
@@ -0,0 +1,1206 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+#define DEBUG_EXPR	0
+
+static int expr_eq(struct expr *e1, struct expr *e2);
+static struct expr *expr_eliminate_yn(struct expr *e);
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+	struct expr *e = xcalloc(1, sizeof(*e));
+	e->type = E_SYMBOL;
+	e->left.sym = sym;
+	return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+	struct expr *e = xcalloc(1, sizeof(*e));
+	e->type = type;
+	e->left.expr = ce;
+	return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+	struct expr *e = xcalloc(1, sizeof(*e));
+	e->type = type;
+	e->left.expr = e1;
+	e->right.expr = e2;
+	return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+	struct expr *e = xcalloc(1, sizeof(*e));
+	e->type = type;
+	e->left.sym = s1;
+	e->right.sym = s2;
+	return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+	if (!e1)
+		return e2;
+	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(const struct expr *org)
+{
+	struct expr *e;
+
+	if (!org)
+		return NULL;
+
+	e = xmalloc(sizeof(*org));
+	memcpy(e, org, sizeof(*org));
+	switch (org->type) {
+	case E_SYMBOL:
+		e->left = org->left;
+		break;
+	case E_NOT:
+		e->left.expr = expr_copy(org->left.expr);
+		break;
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+		e->left.sym = org->left.sym;
+		e->right.sym = org->right.sym;
+		break;
+	case E_AND:
+	case E_OR:
+	case E_LIST:
+		e->left.expr = expr_copy(org->left.expr);
+		e->right.expr = expr_copy(org->right.expr);
+		break;
+	default:
+		printf("can't copy type %d\n", e->type);
+		free(e);
+		e = NULL;
+		break;
+	}
+
+	return e;
+}
+
+void expr_free(struct expr *e)
+{
+	if (!e)
+		return;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		break;
+	case E_NOT:
+		expr_free(e->left.expr);
+		return;
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+		break;
+	case E_OR:
+	case E_AND:
+		expr_free(e->left.expr);
+		expr_free(e->right.expr);
+		break;
+	default:
+		printf("how to free type %d?\n", e->type);
+		break;
+	}
+	free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+	if (e1->type == type) {
+		__expr_eliminate_eq(type, &e1->left.expr, &e2);
+		__expr_eliminate_eq(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		__expr_eliminate_eq(type, &e1, &e2->left.expr);
+		__expr_eliminate_eq(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+	    e1->left.sym == e2->left.sym &&
+	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+		return;
+	if (!expr_eq(e1, e2))
+		return;
+	trans_count++;
+	expr_free(e1); expr_free(e2);
+	switch (type) {
+	case E_OR:
+		e1 = expr_alloc_symbol(&symbol_no);
+		e2 = expr_alloc_symbol(&symbol_no);
+		break;
+	case E_AND:
+		e1 = expr_alloc_symbol(&symbol_yes);
+		e2 = expr_alloc_symbol(&symbol_yes);
+		break;
+	default:
+		;
+	}
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+	if (!e1 || !e2)
+		return;
+	switch (e1->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e1->type, ep1, ep2);
+	default:
+		;
+	}
+	if (e1->type != e2->type) switch (e2->type) {
+	case E_OR:
+	case E_AND:
+		__expr_eliminate_eq(e2->type, ep1, ep2);
+	default:
+		;
+	}
+	e1 = expr_eliminate_yn(e1);
+	e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+static int expr_eq(struct expr *e1, struct expr *e2)
+{
+	int res, old_count;
+
+	if (e1->type != e2->type)
+		return 0;
+	switch (e1->type) {
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+		return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+	case E_SYMBOL:
+		return e1->left.sym == e2->left.sym;
+	case E_NOT:
+		return expr_eq(e1->left.expr, e2->left.expr);
+	case E_AND:
+	case E_OR:
+		e1 = expr_copy(e1);
+		e2 = expr_copy(e2);
+		old_count = trans_count;
+		expr_eliminate_eq(&e1, &e2);
+		res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+		       e1->left.sym == e2->left.sym);
+		expr_free(e1);
+		expr_free(e2);
+		trans_count = old_count;
+		return res;
+	case E_LIST:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+
+	if (DEBUG_EXPR) {
+		expr_fprint(e1, stdout);
+		printf(" = ");
+		expr_fprint(e2, stdout);
+		printf(" ?\n");
+	}
+
+	return 0;
+}
+
+static struct expr *expr_eliminate_yn(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (e) switch (e->type) {
+	case E_AND:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				e->right.expr = NULL;
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			}
+		}
+		break;
+	case E_OR:
+		e->left.expr = expr_eliminate_yn(e->left.expr);
+		e->right.expr = expr_eliminate_yn(e->right.expr);
+		if (e->left.expr->type == E_SYMBOL) {
+			if (e->left.expr->left.sym == &symbol_no) {
+				free(e->left.expr);
+				tmp = e->right.expr;
+				*e = *(e->right.expr);
+				free(tmp);
+				return e;
+			} else if (e->left.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		if (e->right.expr->type == E_SYMBOL) {
+			if (e->right.expr->left.sym == &symbol_no) {
+				free(e->right.expr);
+				tmp = e->left.expr;
+				*e = *(e->left.expr);
+				free(tmp);
+				return e;
+			} else if (e->right.expr->left.sym == &symbol_yes) {
+				expr_free(e->left.expr);
+				expr_free(e->right.expr);
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				e->right.expr = NULL;
+				return e;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_AND:
+	case E_OR:
+	case E_NOT:
+		e->left.expr = expr_trans_bool(e->left.expr);
+		e->right.expr = expr_trans_bool(e->right.expr);
+		break;
+	case E_UNEQUAL:
+		// FOO!=n -> FOO
+		if (e->left.sym->type == S_TRISTATE) {
+			if (e->right.sym == &symbol_no) {
+				e->type = E_SYMBOL;
+				e->right.sym = NULL;
+			}
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+		     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='m') -> (a!='n')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+			// (a='y') || (a='n') -> (a!='m')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+		}
+		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+		    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+			// (a='m') || (a='n') -> (a!='y')
+			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+		}
+	}
+	if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+		if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+		    (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+			return expr_alloc_symbol(&symbol_yes);
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") || (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+	struct expr *tmp;
+	struct symbol *sym1, *sym2;
+
+	if (expr_eq(e1, e2))
+		return expr_copy(e1);
+	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+		return NULL;
+	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+		return NULL;
+	if (e1->type == E_NOT) {
+		tmp = e1->left.expr;
+		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+			return NULL;
+		sym1 = tmp->left.sym;
+	} else
+		sym1 = e1->left.sym;
+	if (e2->type == E_NOT) {
+		if (e2->left.expr->type != E_SYMBOL)
+			return NULL;
+		sym2 = e2->left.expr->left.sym;
+	} else
+		sym2 = e2->left.sym;
+	if (sym1 != sym2)
+		return NULL;
+	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+		return NULL;
+
+	if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+	    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+		// (a) && (a='y') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+		// (a) && (a!='n') -> (a)
+		return expr_alloc_symbol(sym1);
+
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+		// (a) && (a!='m') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+	if (sym1->type == S_TRISTATE) {
+		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e1->right.sym;
+			if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+			sym2 = e2->right.sym;
+			if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+				return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+							     : expr_alloc_symbol(&symbol_no);
+		}
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+			    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+			// (a!='y') && (a!='m') -> (a='n')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+			   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+			// (a!='m') && (a!='n') -> (a='m')
+			return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+		if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+		    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+		    (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+			return NULL;
+	}
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") && (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
+	return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+	struct expr *tmp;
+
+	if (e1->type == type) {
+		expr_eliminate_dups1(type, &e1->left.expr, &e2);
+		expr_eliminate_dups1(type, &e1->right.expr, &e2);
+		return;
+	}
+	if (e2->type == type) {
+		expr_eliminate_dups1(type, &e1, &e2->left.expr);
+		expr_eliminate_dups1(type, &e1, &e2->right.expr);
+		return;
+	}
+	if (e1 == e2)
+		return;
+
+	switch (e1->type) {
+	case E_OR: case E_AND:
+		expr_eliminate_dups1(e1->type, &e1, &e1);
+	default:
+		;
+	}
+
+	switch (type) {
+	case E_OR:
+		tmp = expr_join_or(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_no);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	case E_AND:
+		tmp = expr_join_and(e1, e2);
+		if (tmp) {
+			expr_free(e1); expr_free(e2);
+			e1 = expr_alloc_symbol(&symbol_yes);
+			e2 = tmp;
+			trans_count++;
+		}
+		break;
+	default:
+		;
+	}
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+	int oldcount;
+	if (!e)
+		return e;
+
+	oldcount = trans_count;
+	while (1) {
+		trans_count = 0;
+		switch (e->type) {
+		case E_OR: case E_AND:
+			expr_eliminate_dups1(e->type, &e, &e);
+		default:
+			;
+		}
+		if (!trans_count)
+			break;
+		e = expr_eliminate_yn(e);
+	}
+	trans_count = oldcount;
+	return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+	struct expr *tmp;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+	case E_SYMBOL:
+	case E_LIST:
+		break;
+	default:
+		e->left.expr = expr_transform(e->left.expr);
+		e->right.expr = expr_transform(e->right.expr);
+	}
+
+	switch (e->type) {
+	case E_EQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_no;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->type != S_BOOLEAN)
+			break;
+		if (e->right.sym == &symbol_no) {
+			e->type = E_SYMBOL;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_mod) {
+			printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+			e->type = E_SYMBOL;
+			e->left.sym = &symbol_yes;
+			e->right.sym = NULL;
+			break;
+		}
+		if (e->right.sym == &symbol_yes) {
+			e->type = E_NOT;
+			e->left.expr = expr_alloc_symbol(e->left.sym);
+			e->right.sym = NULL;
+			break;
+		}
+		break;
+	case E_NOT:
+		switch (e->left.expr->type) {
+		case E_NOT:
+			// !!a -> a
+			tmp = e->left.expr->left.expr;
+			free(e->left.expr);
+			free(e);
+			e = tmp;
+			e = expr_transform(e);
+			break;
+		case E_EQUAL:
+		case E_UNEQUAL:
+			// !a='x' -> a!='x'
+			tmp = e->left.expr;
+			free(e);
+			e = tmp;
+			e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+			break;
+		case E_LEQ:
+		case E_GEQ:
+			// !a<='x' -> a>'x'
+			tmp = e->left.expr;
+			free(e);
+			e = tmp;
+			e->type = e->type == E_LEQ ? E_GTH : E_LTH;
+			break;
+		case E_LTH:
+		case E_GTH:
+			// !a<'x' -> a>='x'
+			tmp = e->left.expr;
+			free(e);
+			e = tmp;
+			e->type = e->type == E_LTH ? E_GEQ : E_LEQ;
+			break;
+		case E_OR:
+			// !(a || b) -> !a && !b
+			tmp = e->left.expr;
+			e->type = E_AND;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_AND:
+			// !(a && b) -> !a || !b
+			tmp = e->left.expr;
+			e->type = E_OR;
+			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+			tmp->type = E_NOT;
+			tmp->right.expr = NULL;
+			e = expr_transform(e);
+			break;
+		case E_SYMBOL:
+			if (e->left.expr->left.sym == &symbol_yes) {
+				// !'y' -> 'n'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_no;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_mod) {
+				// !'m' -> 'm'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_mod;
+				break;
+			}
+			if (e->left.expr->left.sym == &symbol_no) {
+				// !'n' -> 'y'
+				tmp = e->left.expr;
+				free(e);
+				e = tmp;
+				e->type = E_SYMBOL;
+				e->left.sym = &symbol_yes;
+				break;
+			}
+			break;
+		default:
+			;
+		}
+		break;
+	default:
+		;
+	}
+	return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return 0;
+
+	switch (dep->type) {
+	case E_AND:
+	case E_OR:
+		return expr_contains_symbol(dep->left.expr, sym) ||
+		       expr_contains_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+		return dep->left.sym == sym ||
+		       dep->right.sym == sym;
+	case E_NOT:
+		return expr_contains_symbol(dep->left.expr, sym);
+	default:
+		;
+	}
+	return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+	if (!dep)
+		return false;
+
+	switch (dep->type) {
+	case E_AND:
+		return expr_depends_symbol(dep->left.expr, sym) ||
+		       expr_depends_symbol(dep->right.expr, sym);
+	case E_SYMBOL:
+		return dep->left.sym == sym;
+	case E_EQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+				return true;
+		}
+		break;
+	case E_UNEQUAL:
+		if (dep->left.sym == sym) {
+			if (dep->right.sym == &symbol_no)
+				return true;
+		}
+		break;
+	default:
+		;
+	}
+ 	return false;
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+	struct expr *e1, *e2;
+
+	if (!e) {
+		e = expr_alloc_symbol(sym);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	}
+	switch (e->type) {
+	case E_AND:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_OR:
+		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+		if (sym == &symbol_yes)
+			e = expr_alloc_two(E_OR, e1, e2);
+		if (sym == &symbol_no)
+			e = expr_alloc_two(E_AND, e1, e2);
+		if (type == E_UNEQUAL)
+			e = expr_alloc_one(E_NOT, e);
+		return e;
+	case E_NOT:
+		return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+	case E_UNEQUAL:
+	case E_LTH:
+	case E_LEQ:
+	case E_GTH:
+	case E_GEQ:
+	case E_EQUAL:
+		if (type == E_EQUAL) {
+			if (sym == &symbol_yes)
+				return expr_copy(e);
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_no);
+			if (sym == &symbol_no)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+		} else {
+			if (sym == &symbol_yes)
+				return expr_alloc_one(E_NOT, expr_copy(e));
+			if (sym == &symbol_mod)
+				return expr_alloc_symbol(&symbol_yes);
+			if (sym == &symbol_no)
+				return expr_copy(e);
+		}
+		break;
+	case E_SYMBOL:
+		return expr_alloc_comp(type, e->left.sym, sym);
+	case E_LIST:
+	case E_RANGE:
+	case E_NONE:
+		/* panic */;
+	}
+	return NULL;
+}
+
+enum string_value_kind {
+	k_string,
+	k_signed,
+	k_unsigned,
+	k_invalid
+};
+
+union string_value {
+	unsigned long long u;
+	signed long long s;
+};
+
+static enum string_value_kind expr_parse_string(const char *str,
+						enum symbol_type type,
+						union string_value *val)
+{
+	char *tail;
+	enum string_value_kind kind;
+
+	errno = 0;
+	switch (type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		return k_string;
+	case S_INT:
+		val->s = strtoll(str, &tail, 10);
+		kind = k_signed;
+		break;
+	case S_HEX:
+		val->u = strtoull(str, &tail, 16);
+		kind = k_unsigned;
+		break;
+	case S_STRING:
+	case S_UNKNOWN:
+		val->s = strtoll(str, &tail, 0);
+		kind = k_signed;
+		break;
+	default:
+		return k_invalid;
+	}
+	return !errno && !*tail && tail > str && isxdigit(tail[-1])
+	       ? kind : k_string;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+	tristate val1, val2;
+	const char *str1, *str2;
+	enum string_value_kind k1 = k_string, k2 = k_string;
+	union string_value lval = {}, rval = {};
+	int res;
+
+	if (!e)
+		return yes;
+
+	switch (e->type) {
+	case E_SYMBOL:
+		sym_calc_value(e->left.sym);
+		return e->left.sym->curr.tri;
+	case E_AND:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return EXPR_AND(val1, val2);
+	case E_OR:
+		val1 = expr_calc_value(e->left.expr);
+		val2 = expr_calc_value(e->right.expr);
+		return EXPR_OR(val1, val2);
+	case E_NOT:
+		val1 = expr_calc_value(e->left.expr);
+		return EXPR_NOT(val1);
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+		break;
+	default:
+		printf("expr_calc_value: %d?\n", e->type);
+		return no;
+	}
+
+	sym_calc_value(e->left.sym);
+	sym_calc_value(e->right.sym);
+	str1 = sym_get_string_value(e->left.sym);
+	str2 = sym_get_string_value(e->right.sym);
+
+	if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) {
+		k1 = expr_parse_string(str1, e->left.sym->type, &lval);
+		k2 = expr_parse_string(str2, e->right.sym->type, &rval);
+	}
+
+	if (k1 == k_string || k2 == k_string)
+		res = strcmp(str1, str2);
+	else if (k1 == k_invalid || k2 == k_invalid) {
+		if (e->type != E_EQUAL && e->type != E_UNEQUAL) {
+			printf("Cannot compare \"%s\" and \"%s\"\n", str1, str2);
+			return no;
+		}
+		res = strcmp(str1, str2);
+	} else if (k1 == k_unsigned || k2 == k_unsigned)
+		res = (lval.u > rval.u) - (lval.u < rval.u);
+	else /* if (k1 == k_signed && k2 == k_signed) */
+		res = (lval.s > rval.s) - (lval.s < rval.s);
+
+	switch(e->type) {
+	case E_EQUAL:
+		return res ? no : yes;
+	case E_GEQ:
+		return res >= 0 ? yes : no;
+	case E_GTH:
+		return res > 0 ? yes : no;
+	case E_LEQ:
+		return res <= 0 ? yes : no;
+	case E_LTH:
+		return res < 0 ? yes : no;
+	case E_UNEQUAL:
+		return res ? yes : no;
+	default:
+		printf("expr_calc_value: relation %d?\n", e->type);
+		return no;
+	}
+}
+
+static int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+	if (t1 == t2)
+		return 0;
+	switch (t1) {
+	case E_LEQ:
+	case E_LTH:
+	case E_GEQ:
+	case E_GTH:
+		if (t2 == E_EQUAL || t2 == E_UNEQUAL)
+			return 1;
+	case E_EQUAL:
+	case E_UNEQUAL:
+		if (t2 == E_NOT)
+			return 1;
+	case E_NOT:
+		if (t2 == E_AND)
+			return 1;
+	case E_AND:
+		if (t2 == E_OR)
+			return 1;
+	case E_OR:
+		if (t2 == E_LIST)
+			return 1;
+	case E_LIST:
+		if (t2 == 0)
+			return 1;
+	default:
+		return -1;
+	}
+	printf("[%dgt%d?]", t1, t2);
+	return 0;
+}
+
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+	if (e == NULL)
+		return NULL;
+
+	while (e->type != E_SYMBOL)
+		e = e->left.expr;
+
+	return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+	struct expr *ret;
+
+	switch (e1->type) {
+	case E_OR:
+		return expr_alloc_and(
+		    expr_simplify_unmet_dep(e1->left.expr, e2),
+		    expr_simplify_unmet_dep(e1->right.expr, e2));
+	case E_AND: {
+		struct expr *e;
+		e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+		e = expr_eliminate_dups(e);
+		ret = (!expr_eq(e, e1)) ? e1 : NULL;
+		expr_free(e);
+		break;
+		}
+	default:
+		ret = e1;
+		break;
+	}
+
+	return expr_get_leftmost_symbol(ret);
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+	if (!e) {
+		fn(data, NULL, "y");
+		return;
+	}
+
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, "(");
+	switch (e->type) {
+	case E_SYMBOL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		break;
+	case E_NOT:
+		fn(data, NULL, "!");
+		expr_print(e->left.expr, fn, data, E_NOT);
+		break;
+	case E_EQUAL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, "=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_LEQ:
+	case E_LTH:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, e->type == E_LEQ ? "<=" : "<");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_GEQ:
+	case E_GTH:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_UNEQUAL:
+		if (e->left.sym->name)
+			fn(data, e->left.sym, e->left.sym->name);
+		else
+			fn(data, NULL, "<choice>");
+		fn(data, NULL, "!=");
+		fn(data, e->right.sym, e->right.sym->name);
+		break;
+	case E_OR:
+		expr_print(e->left.expr, fn, data, E_OR);
+		fn(data, NULL, " || ");
+		expr_print(e->right.expr, fn, data, E_OR);
+		break;
+	case E_AND:
+		expr_print(e->left.expr, fn, data, E_AND);
+		fn(data, NULL, " && ");
+		expr_print(e->right.expr, fn, data, E_AND);
+		break;
+	case E_LIST:
+		fn(data, e->right.sym, e->right.sym->name);
+		if (e->left.expr) {
+			fn(data, NULL, " ^ ");
+			expr_print(e->left.expr, fn, data, E_LIST);
+		}
+		break;
+	case E_RANGE:
+		fn(data, NULL, "[");
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, " ");
+		fn(data, e->right.sym, e->right.sym->name);
+		fn(data, NULL, "]");
+		break;
+	default:
+	  {
+		char buf[32];
+		sprintf(buf, "<unknown type %d>", e->type);
+		fn(data, NULL, buf);
+		break;
+	  }
+	}
+	if (expr_compare_type(prevtoken, e->type) > 0)
+		fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+	xfwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+	expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+	struct gstr *gs = (struct gstr*)data;
+	const char *sym_str = NULL;
+
+	if (sym)
+		sym_str = sym_get_string_value(sym);
+
+	if (gs->max_width) {
+		unsigned extra_length = strlen(str);
+		const char *last_cr = strrchr(gs->s, '\n');
+		unsigned last_line_length;
+
+		if (sym_str)
+			extra_length += 4 + strlen(sym_str);
+
+		if (!last_cr)
+			last_cr = gs->s;
+
+		last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+		if ((last_line_length + extra_length) > gs->max_width)
+			str_append(gs, "\\\n");
+	}
+
+	str_append(gs, str);
+	if (sym && sym->type != S_UNKNOWN)
+		str_printf(gs, " [=%s]", sym_str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+	expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/scripts/config/expr.h b/scripts/config/expr.h
new file mode 100644
index 0000000000..d21bbe3b31
--- /dev/null
+++ b/scripts/config/expr.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include "list.h"
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+	struct file *next;
+	struct file *parent;
+	const char *name;
+	int lineno;
+};
+
+typedef enum tristate {
+	no, mod, yes
+} tristate;
+
+enum expr_type {
+	E_NONE, E_OR, E_AND, E_NOT,
+	E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
+	E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+	struct expr *expr;
+	struct symbol *sym;
+};
+
+struct expr {
+	enum expr_type type;
+	union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep)		(2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+	for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+	struct expr *expr;
+	tristate tri;
+};
+
+struct symbol_value {
+	void *val;
+	tristate tri;
+};
+
+enum symbol_type {
+	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+/* enum values are used as index to symbol.def[] */
+enum {
+	S_DEF_USER,		/* main user value */
+	S_DEF_AUTO,		/* values read from auto.conf */
+	S_DEF_DEF3,		/* Reserved for UI usage */
+	S_DEF_DEF4,		/* Reserved for UI usage */
+	S_DEF_COUNT
+};
+
+struct symbol {
+	struct symbol *next;
+	char *name;
+	enum symbol_type type;
+	struct symbol_value curr;
+	struct symbol_value def[S_DEF_COUNT];
+	tristate visible;
+	int flags;
+	struct property *prop;
+	struct expr_value dir_dep;
+	struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST      0x0001  /* symbol is const */
+#define SYMBOL_CHECK      0x0008  /* used during dependency checking */
+#define SYMBOL_CHOICE     0x0010  /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL  0x0020  /* used as a value in a choice block */
+#define SYMBOL_VALID      0x0080  /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL   0x0100  /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE      0x0200  /* write symbol to file (KCONFIG_CONFIG) */
+#define SYMBOL_CHANGED    0x0400  /* ? */
+#define SYMBOL_AUTO       0x1000  /* value from environment variable */
+#define SYMBOL_CHECKED    0x2000  /* used during dependency checking */
+#define SYMBOL_WARNED     0x8000  /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF        0x10000  /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER   0x10000  /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO   0x20000  /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
+
+/* choice values need to be set before calculating this symbol value */
+#define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000
+
+/* Set symbol to y if allnoconfig; used for symbols that hide others */
+#define SYMBOL_ALLNOCONFIG_Y 0x200000
+
+#define SYMBOL_MAXLENGTH	256
+#define SYMBOL_HASHSIZE		9973
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ *         default y
+ *         prompt "foo prompt"
+ *         select BAR
+ * config BAZ
+ *         int "BAZ Value"
+ *         range 1..255
+ */
+enum prop_type {
+	P_UNKNOWN,
+	P_PROMPT,   /* prompt "foo prompt" or "BAZ Value" */
+	P_COMMENT,  /* text associated with a comment */
+	P_MENU,     /* prompt associated with a menuconfig option */
+	P_DEFAULT,  /* default y */
+	P_CHOICE,   /* choice value */
+	P_SELECT,   /* select BAR */
+	P_RANGE,    /* range 7..100 (for a symbol) */
+	P_ENV,      /* value from environment variable */
+	P_SYMBOL,   /* where a symbol is defined */
+	P_RESET,	/* reset to defaults condition */
+};
+
+struct property {
+	struct property *next;     /* next property - null if last */
+	struct symbol *sym;        /* the symbol for which the property is associated */
+	enum prop_type type;       /* type of property */
+	const char *text;          /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
+	struct expr_value visible;
+	struct expr *expr;         /* the optional conditional part of the property */
+	struct menu *menu;         /* the menu the property are associated with
+	                            * valid for: P_SELECT, P_RANGE, P_CHOICE,
+	                            * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+	struct file *file;         /* what file was this property defined */
+	int lineno;                /* what lineno was this property defined */
+};
+
+#define for_all_properties(sym, st, tok) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+	for (st = sym->prop; st; st = st->next) \
+		if (st->text)
+
+struct menu {
+	struct menu *next;
+	struct menu *parent;
+	struct menu *list;
+	struct symbol *sym;
+	struct property *prompt;
+	struct expr *visibility;
+	struct expr *dep;
+	unsigned int flags;
+	char *help;
+	struct file *file;
+	int lineno;
+	void *data;
+};
+
+#define MENU_CHANGED		0x0001
+#define MENU_ROOT		0x0002
+
+struct jump_key {
+	struct list_head entries;
+	size_t offset;
+	struct menu *target;
+	int index;
+};
+
+#define JUMP_NB			9
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(const struct expr *org);
+void expr_free(struct expr *e);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+	return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/scripts/config/list.h b/scripts/config/list.h
new file mode 100644
index 0000000000..2cf23f002d
--- /dev/null
+++ b/scripts/config/list.h
@@ -0,0 +1,131 @@
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Copied from include/linux/...
+ */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:        the pointer to the member.
+ * @type:       the type of the container struct this is embedded in.
+ * @member:     the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                      \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *_new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = _new;
+	_new->next = next;
+	_new->prev = prev;
+	prev->next = _new;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+	__list_add(_new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = (struct list_head*)LIST_POISON1;
+	entry->prev = (struct list_head*)LIST_POISON2;
+}
+#endif
diff --git a/scripts/config/lkc.h b/scripts/config/lkc.h
new file mode 100644
index 0000000000..6d2400bf25
--- /dev/null
+++ b/scripts/config/lkc.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lkc_proto.h"
+
+#define SRCTREE "srctree"
+
+#ifndef PACKAGE
+#define PACKAGE "linux"
+#endif
+
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+static inline const char *CONFIG_prefix(void)
+{
+	return getenv( "CONFIG_" ) ?: CONFIG_;
+}
+#undef CONFIG_
+#define CONFIG_ CONFIG_prefix()
+
+#define TF_COMMAND	0x0001
+#define TF_PARAM	0x0002
+#define TF_OPTION	0x0004
+
+enum conf_def_mode {
+	def_default,
+	def_yes,
+	def_mod,
+	def_no,
+	def_random
+};
+
+#define T_OPT_MODULES		1
+#define T_OPT_DEFCONFIG_LIST	2
+#define T_OPT_ENV		3
+#define T_OPT_ALLNOCONFIG_Y	4
+
+struct kconf_id {
+	int name;
+	int token;
+	unsigned int flags;
+	enum symbol_type stype;
+};
+
+void zconfdump(FILE *out);
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+const char *zconf_curname(void);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+bool conf_set_all_new_symbols(enum conf_def_mode mode);
+void set_all_choice_values(struct symbol *csym);
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+	assert(len != 0);
+
+	if (fwrite(str, len, count, out) != count)
+		fprintf(stderr, "Error in writing or end of file.\n");
+}
+
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+void *xmalloc(size_t size);
+void *xcalloc(size_t nmemb, size_t size);
+
+struct gstr {
+	size_t len;
+	char  *s;
+	/*
+	* when max_width is not zero long lines in string s (if any) get
+	* wrapped not to exceed the max_width value
+	*/
+	int max_width;
+};
+struct gstr str_new(void);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+	return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+	return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+	return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+	return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/scripts/config/lkc_proto.h b/scripts/config/lkc_proto.h
new file mode 100644
index 0000000000..e4c2fea2d0
--- /dev/null
+++ b/scripts/config/lkc_proto.h
@@ -0,0 +1,53 @@
+#include <stdarg.h>
+
+/* confdata.c */
+void conf_parse(const char *name);
+int conf_read(const char *name);
+int conf_read_simple(const char *name, int);
+void conf_reset(int def);
+int conf_write_defconfig(const char *name);
+int conf_write(const char *name);
+int conf_write_autoconf(void);
+bool conf_get_changed(void);
+void conf_set_changed_callback(void (*fn)(void));
+void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap));
+
+/* menu.c */
+extern struct menu rootmenu;
+
+bool menu_is_empty(struct menu *menu);
+bool menu_is_visible(struct menu *menu);
+bool menu_has_prompt(struct menu *menu);
+const char * menu_get_prompt(struct menu *menu);
+struct menu * menu_get_root_menu(struct menu *menu);
+struct menu * menu_get_parent_menu(struct menu *menu);
+bool menu_has_help(struct menu *menu);
+const char * menu_get_help(struct menu *menu);
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
+void menu_get_ext_help(struct menu *menu, struct gstr *help);
+
+/* symbol.c */
+extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
+
+struct symbol * sym_lookup(const char *name, int flags);
+struct symbol * sym_find(const char *name);
+const char * sym_expand_string_value(const char *in);
+const char * sym_escape_string_value(const char *in);
+struct symbol ** sym_re_search(const char *pattern);
+const char * sym_type_name(enum symbol_type type);
+void sym_calc_value(struct symbol *sym);
+enum symbol_type sym_get_type(struct symbol *sym);
+bool sym_tristate_within_range(struct symbol *sym,tristate tri);
+bool sym_set_tristate_value(struct symbol *sym,tristate tri);
+tristate sym_toggle_tristate_value(struct symbol *sym);
+bool sym_string_valid(struct symbol *sym, const char *newval);
+bool sym_string_within_range(struct symbol *sym, const char *str);
+bool sym_set_string_value(struct symbol *sym, const char *newval);
+bool sym_is_changable(struct symbol *sym);
+struct property * sym_get_choice_prop(struct symbol *sym);
+const char * sym_get_string_value(struct symbol *sym);
+
+const char * prop_get_type_name(enum prop_type type);
+
+/* expr.c */
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);
diff --git a/scripts/config/lxdialog/.gitignore b/scripts/config/lxdialog/.gitignore
new file mode 100644
index 0000000000..405824dbd7
--- /dev/null
+++ b/scripts/config/lxdialog/.gitignore
@@ -0,0 +1,2 @@
+lxdialog
+*.o
diff --git a/scripts/config/lxdialog/check-lxdialog.sh b/scripts/config/lxdialog/check-lxdialog.sh
new file mode 100644
index 0000000000..5075ebf2d3
--- /dev/null
+++ b/scripts/config/lxdialog/check-lxdialog.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+	pkg-config --libs ncursesw 2>/dev/null && exit
+	pkg-config --libs ncurses 2>/dev/null && exit
+	for ext in so a dll.a dylib ; do
+		for lib in ncursesw ncurses curses ; do
+			$cc -print-file-name=lib${lib}.${ext} | grep -q /
+			if [ $? -eq 0 ]; then
+				echo "-l${lib}"
+				exit
+			fi
+		done
+	done
+	exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+	if pkg-config --cflags ncursesw 2>/dev/null; then
+		echo '-DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1'
+	elif pkg-config --cflags ncurses 2>/dev/null; then
+		echo '-DCURSES_LOC="<ncurses.h>"'
+	elif [ -f /usr/include/ncursesw/curses.h ]; then
+		echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
+		echo ' -DNCURSES_WIDECHAR=1'
+	elif [ -f /usr/include/ncurses/ncurses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+	elif [ -f /usr/include/ncurses/curses.h ]; then
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
+	elif [ -f /usr/include/ncurses.h ]; then
+		echo '-DCURSES_LOC="<ncurses.h>"'
+	else
+		echo '-DCURSES_LOC="<curses.h>"'
+	fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+        $cc -x c - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
+	if [ $? != 0 ]; then
+	    echo " *** Unable to find the ncurses libraries or the"       1>&2
+	    echo " *** required header files."                            1>&2
+	    echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+	    echo " *** "                                                  1>&2
+	    echo " *** Install ncurses (ncurses-devel) and try again."    1>&2
+	    echo " *** "                                                  1>&2
+	    exit 1
+	fi
+}
+
+usage() {
+	printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
+}
+
+if [ $# -eq 0 ]; then
+	usage
+	exit 1
+fi
+
+cc=""
+case "$1" in
+	"-check")
+		shift
+		cc="$@"
+		check
+		;;
+	"-ccflags")
+		ccflags
+		;;
+	"-ldflags")
+		shift
+		cc="$@"
+		ldflags
+		;;
+	"*")
+		usage
+		exit 1
+		;;
+esac
diff --git a/scripts/config/lxdialog/checklist.c b/scripts/config/lxdialog/checklist.c
new file mode 100644
index 0000000000..8d016faa28
--- /dev/null
+++ b/scripts/config/lxdialog/checklist.c
@@ -0,0 +1,332 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+	int i;
+	char *list_item = malloc(list_width + 1);
+
+	strncpy(list_item, item_str(), list_width - item_x);
+	list_item[list_width - item_x] = '\0';
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, choice, 0);
+	for (i = 0; i < list_width; i++)
+		waddch(win, ' ');
+
+	wmove(win, choice, check_x);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	if (!item_is_tag(':'))
+		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, list_item[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, list_item + 1);
+	if (selected) {
+		wmove(win, choice, check_x + 1);
+		wrefresh(win);
+	}
+	free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+	     int y, int x, int height)
+{
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+
+	if ((height < item_no) && (scroll + choice < item_no - 1)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("Select"), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height)
+{
+	int i, x, y, box_x, box_y;
+	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+	WINDOW *dialog, *list;
+
+	/* which item to highlight */
+	item_foreach() {
+		if (item_is_tag('X'))
+			choice = item_n();
+		if (item_is_selected()) {
+			choice = item_n();
+			break;
+		}
+	}
+
+do_resize:
+	if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+
+	max_choice = MIN(list_height, item_count());
+
+	/* center dialog box on screen */
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	list_width = width - 6;
+	box_y = height - list_height - 5;
+	box_x = (width - list_width) / 2 - 1;
+
+	/* create new window for the list */
+	list = subwin(dialog, list_height, list_width, y + box_y + 1,
+		      x + box_x + 1);
+
+	keypad(list, TRUE);
+
+	/* draw a box around the list items */
+	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	/* Find length of longest item in order to center checklist */
+	check_x = 0;
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+	check_x = MIN(check_x, list_width);
+
+	check_x = (list_width - check_x) / 2;
+	item_x = check_x + 4;
+
+	if (choice >= list_height) {
+		scroll = choice - list_height + 1;
+		choice -= scroll;
+	}
+
+	/* Print the list */
+	for (i = 0; i < max_choice; i++) {
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
+	}
+
+	print_arrows(dialog, choice, item_count(), scroll,
+		     box_y, box_x + check_x + 5, list_height);
+
+	print_buttons(dialog, height, width, 0);
+
+	wnoutrefresh(dialog);
+	wnoutrefresh(list);
+	doupdate();
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
+				break;
+		}
+
+		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+		    key == '+' || key == '-') {
+			if (key == KEY_UP || key == '-') {
+				if (!choice) {
+					if (!scroll)
+						continue;
+					/* Scroll list down */
+					if (list_height > 1) {
+						/* De-highlight current first item */
+						item_set(scroll);
+						print_item(list, 0, FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, -1);
+						scrollok(list, FALSE);
+					}
+					scroll--;
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice - 1;
+			} else if (key == KEY_DOWN || key == '+') {
+				if (choice == max_choice - 1) {
+					if (scroll + choice >= item_count() - 1)
+						continue;
+					/* Scroll list up */
+					if (list_height > 1) {
+						/* De-highlight current last item before scrolling up */
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, 1);
+						scrollok(list, FALSE);
+					}
+					scroll++;
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
+
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice + 1;
+			}
+			if (i != choice) {
+				/* De-highlight current item */
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
+				/* Highlight new item */
+				choice = i;
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
+			}
+			continue;	/* wait for another key press */
+		}
+		switch (key) {
+		case 'H':
+		case 'h':
+		case '?':
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_foreach()
+				item_set_selected(0);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			delwin(list);
+			delwin(dialog);
+			return button;
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+
+		/* Now, update everything... */
+		doupdate();
+	}
+	delwin(list);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/scripts/config/lxdialog/dialog.h b/scripts/config/lxdialog/dialog.h
new file mode 100644
index 0000000000..fcffd5b41f
--- /dev/null
+++ b/scripts/config/lxdialog/dialog.h
@@ -0,0 +1,257 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)		/*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ *   Color definitions
+ */
+struct dialog_color {
+	chtype atr;	/* Color attribute */
+	int fg;		/* foreground */
+	int bg;		/* background */
+	int hl;		/* highlight this item */
+};
+
+struct subtitle_list {
+	struct subtitle_list *next;
+	const char *text;
+};
+
+struct dialog_info {
+	const char *backtitle;
+	struct subtitle_list *subtitles;
+	struct dialog_color screen;
+	struct dialog_color shadow;
+	struct dialog_color dialog;
+	struct dialog_color title;
+	struct dialog_color border;
+	struct dialog_color button_active;
+	struct dialog_color button_inactive;
+	struct dialog_color button_key_active;
+	struct dialog_color button_key_inactive;
+	struct dialog_color button_label_active;
+	struct dialog_color button_label_inactive;
+	struct dialog_color inputbox;
+	struct dialog_color inputbox_border;
+	struct dialog_color searchbox;
+	struct dialog_color searchbox_title;
+	struct dialog_color searchbox_border;
+	struct dialog_color position_indicator;
+	struct dialog_color menubox;
+	struct dialog_color menubox_border;
+	struct dialog_color item;
+	struct dialog_color item_selected;
+	struct dialog_color tag;
+	struct dialog_color tag_selected;
+	struct dialog_color tag_key;
+	struct dialog_color tag_key_selected;
+	struct dialog_color check;
+	struct dialog_color check_selected;
+	struct dialog_color uarrow;
+	struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+extern int saved_x, saved_y;		/* Needed in signal handler in mconf.c */
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+	char str[MAXITEMSTR];	/* prompt displayed */
+	char tag;
+	void *data;	/* pointer to menu item - used by menubox+checklist */
+	int selected;	/* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+	struct dialog_item node;
+	struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+	for (item_cur = item_head ? item_head: item_cur; \
+	     item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+/* minimum (re)size values */
+#define CHECKLIST_HEIGTH_MIN 6	/* For dialog_checklist() */
+#define CHECKLIST_WIDTH_MIN 6
+#define INPUTBOX_HEIGTH_MIN 2	/* For dialog_inputbox() */
+#define INPUTBOX_WIDTH_MIN 2
+#define MENUBOX_HEIGTH_MIN 15	/* For dialog_menu() */
+#define MENUBOX_WIDTH_MIN 65
+#define TEXTBOX_HEIGTH_MIN 8	/* For dialog_textbox() */
+#define TEXTBOX_WIDTH_MIN 8
+#define YESNO_HEIGTH_MIN 4	/* For dialog_yesno() */
+#define YESNO_WIDTH_MIN 4
+#define WINDOW_HEIGTH_MIN 19	/* For init_dialog() */
+#define WINDOW_WIDTH_MIN 80
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void set_dialog_subtitles(struct subtitle_list *subtitles);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+	      chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+		  int width, int pause);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+			       *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data);
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height);
+int dialog_inputbox(const char *title, const char *prompt, int height,
+		    int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
diff --git a/scripts/config/lxdialog/inputbox.c b/scripts/config/lxdialog/inputbox.c
new file mode 100644
index 0000000000..d58de1dc53
--- /dev/null
+++ b/scripts/config/lxdialog/inputbox.c
@@ -0,0 +1,301 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+		    const char *init)
+{
+	int i, x, y, box_y, box_x, box_width;
+	int input_x = 0, key = 0, button = -1;
+	int show_x, len, pos;
+	char *instr = dialog_input_result;
+	WINDOW *dialog;
+
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	/* Draw the input field box */
+	box_width = width - 6;
+	getyx(dialog, y, x);
+	box_y = y + 2;
+	box_x = (width - box_width) / 2;
+	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	print_buttons(dialog, height, width, 0);
+
+	/* Set up the initial value */
+	wmove(dialog, box_y, box_x);
+	wattrset(dialog, dlg.inputbox.atr);
+
+	len = strlen(instr);
+	pos = len;
+
+	if (len >= box_width) {
+		show_x = len - box_width + 1;
+		input_x = box_width - 1;
+		for (i = 0; i < box_width - 1; i++)
+			waddch(dialog, instr[show_x + i]);
+	} else {
+		show_x = 0;
+		input_x = len;
+		waddstr(dialog, instr);
+	}
+
+	wmove(dialog, box_y, box_x + input_x);
+
+	wrefresh(dialog);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		if (button == -1) {	/* Input box selected */
+			switch (key) {
+			case TAB:
+			case KEY_UP:
+			case KEY_DOWN:
+				break;
+			case KEY_BACKSPACE:
+			case 127:
+				if (pos) {
+					wattrset(dialog, dlg.inputbox.atr);
+					if (input_x == 0) {
+						show_x--;
+					} else
+						input_x--;
+
+					if (pos < len) {
+						for (i = pos - 1; i < len; i++) {
+							instr[i] = instr[i+1];
+						}
+					}
+
+					pos--;
+					len--;
+					instr[len] = '\0';
+					wmove(dialog, box_y, box_x);
+					for (i = 0; i < box_width; i++) {
+						if (!instr[show_x + i]) {
+							waddch(dialog, ' ');
+							break;
+						}
+						waddch(dialog, instr[show_x + i]);
+					}
+					wmove(dialog, box_y, input_x + box_x);
+					wrefresh(dialog);
+				}
+				continue;
+			case KEY_LEFT:
+				if (pos > 0) {
+					if (input_x > 0) {
+						wmove(dialog, box_y, --input_x + box_x);
+					} else if (input_x == 0) {
+						show_x--;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, box_x);
+					}
+					pos--;
+				}
+				continue;
+			case KEY_RIGHT:
+				if (pos < len) {
+					if (input_x < box_width - 1) {
+						wmove(dialog, box_y, ++input_x + box_x);
+					} else if (input_x == box_width - 1) {
+						show_x++;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
+					}
+					pos++;
+				}
+				continue;
+			default:
+				if (key < 0x100 && isprint(key)) {
+					if (len < MAX_LEN) {
+						wattrset(dialog, dlg.inputbox.atr);
+						if (pos < len) {
+							for (i = len; i > pos; i--)
+								instr[i] = instr[i-1];
+							instr[pos] = key;
+						} else {
+							instr[len] = key;
+						}
+						pos++;
+						len++;
+						instr[len] = '\0';
+
+						if (input_x == box_width - 1) {
+							show_x++;
+						} else {
+							input_x++;
+						}
+
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
+						wrefresh(dialog);
+					} else
+						flash();	/* Alarm user about overflow */
+					continue;
+				}
+			}
+		}
+		switch (key) {
+		case 'O':
+		case 'o':
+			delwin(dialog);
+			return 0;
+		case 'H':
+		case 'h':
+			delwin(dialog);
+			return 1;
+		case KEY_UP:
+		case KEY_LEFT:
+			switch (button) {
+			case -1:
+				button = 1;	/* Indicates "Help" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 0:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			case 1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			}
+			break;
+		case TAB:
+		case KEY_DOWN:
+		case KEY_RIGHT:
+			switch (button) {
+			case -1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			case 0:
+				button = 1;	/* Indicates "Help" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 1:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			}
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return (button == -1 ? 0 : button);
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return KEY_ESC;		/* ESC pressed */
+}
diff --git a/scripts/config/lxdialog/menubox.c b/scripts/config/lxdialog/menubox.c
new file mode 100644
index 0000000000..11ae9ad7ac
--- /dev/null
+++ b/scripts/config/lxdialog/menubox.c
@@ -0,0 +1,437 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god@clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+			  int selected, int hotkey)
+{
+	int j;
+	char *menu_item = malloc(menu_width + 1);
+
+	strncpy(menu_item, item, menu_width - item_x);
+	menu_item[menu_width - item_x] = '\0';
+	j = first_alpha(menu_item, "YyNnMmHh");
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, line_y, 0);
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < menu_width; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	mvwaddstr(win, line_y, item_x, menu_item);
+	if (hotkey) {
+		wattrset(win, selected ? dlg.tag_key_selected.atr
+			 : dlg.tag_key.atr);
+		mvwaddch(win, line_y, item_x + j, menu_item[j]);
+	}
+	if (selected) {
+		wmove(win, line_y, item_x + 1);
+	}
+	free(menu_item);
+	wrefresh(win);
+}
+
+#define print_item(index, choice, selected)				\
+do {									\
+	item_set(index);						\
+	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+			 int height)
+{
+	int cur_y, cur_x;
+
+	getyx(win, cur_y, cur_x);
+
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+	wrefresh(win);
+
+	if ((height < item_no) && (scroll + height < item_no)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	wmove(win, cur_y, cur_x);
+	wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+	int x = width / 2 - 28;
+	int y = height - 2;
+
+	print_button(win, gettext("Select"), y, x, selected == 0);
+	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+	print_button(win, gettext(" Save "), y, x + 36, selected == 3);
+	print_button(win, gettext(" Load "), y, x + 48, selected == 4);
+
+	wmove(win, y, x + 1 + 12 * selected);
+	wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+	/* Scroll menu up */
+	scrollok(win, TRUE);
+	wscrl(win, n);
+	scrollok(win, FALSE);
+	*scroll = *scroll + n;
+	wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll)
+{
+	int i, j, x, y, box_x, box_y;
+	int height, width, menu_height;
+	int key = 0, button = 0, scroll = 0, choice = 0;
+	int first_item =  0, max_choice;
+	WINDOW *dialog, *menu;
+
+do_resize:
+	height = getmaxy(stdscr);
+	width = getmaxx(stdscr);
+	if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 10;
+
+	max_choice = MIN(menu_height, item_count());
+
+	/* center dialog box on screen */
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	menu_width = width - 6;
+	box_y = height - menu_height - 5;
+	box_x = (width - menu_width) / 2 - 1;
+
+	/* create new window for the menu */
+	menu = subwin(dialog, menu_height, menu_width,
+		      y + box_y + 1, x + box_x + 1);
+	keypad(menu, TRUE);
+
+	/* draw a box around the menu items */
+	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	if (menu_width >= 80)
+		item_x = (menu_width - 70) / 2;
+	else
+		item_x = 4;
+
+	/* Set choice to default item */
+	item_foreach()
+		if (selected && (selected == item_data()))
+			choice = item_n();
+	/* get the saved scroll info */
+	scroll = *s_scroll;
+	if ((scroll <= choice) && (scroll + max_choice > choice) &&
+	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
+		first_item = scroll;
+		choice = choice - scroll;
+	} else {
+		scroll = 0;
+	}
+	if ((choice >= max_choice)) {
+		if (choice >= item_count() - max_choice / 2)
+			scroll = first_item = item_count() - max_choice;
+		else
+			scroll = first_item = choice - max_choice / 2;
+		choice = choice - scroll;
+	}
+
+	/* Print the menu */
+	for (i = 0; i < max_choice; i++) {
+		print_item(first_item + i, i, i == choice);
+	}
+
+	wnoutrefresh(menu);
+
+	print_arrows(dialog, item_count(), scroll,
+		     box_y, box_x + item_x + 1, menu_height);
+
+	print_buttons(dialog, height, width, 0);
+	wmove(menu, choice, item_x + 1);
+	wrefresh(menu);
+
+	while (key != KEY_ESC) {
+		key = wgetch(menu);
+
+		if (key < 256 && isalpha(key))
+			key = tolower(key);
+
+		if (strchr("ynmh", key))
+			i = max_choice;
+		else {
+			for (i = choice + 1; i < max_choice; i++) {
+				item_set(scroll + i);
+				j = first_alpha(item_str(), "YyNnMmHh");
+				if (key == tolower(item_str()[j]))
+					break;
+			}
+			if (i == max_choice)
+				for (i = 0; i < max_choice; i++) {
+					item_set(scroll + i);
+					j = first_alpha(item_str(), "YyNnMmHh");
+					if (key == tolower(item_str()[j]))
+						break;
+				}
+		}
+
+		if (item_count() != 0 &&
+		    (i < max_choice ||
+		     key == KEY_UP || key == KEY_DOWN ||
+		     key == '-' || key == '+' ||
+		     key == KEY_PPAGE || key == KEY_NPAGE)) {
+			/* Remove highligt of current item */
+			print_item(scroll + choice, choice, FALSE);
+
+			if (key == KEY_UP || key == '-') {
+				if (choice < 2 && scroll) {
+					/* Scroll menu down */
+					do_scroll(menu, &scroll, -1);
+
+					print_item(scroll, 0, FALSE);
+				} else
+					choice = MAX(choice - 1, 0);
+
+			} else if (key == KEY_DOWN || key == '+') {
+				print_item(scroll+choice, choice, FALSE);
+
+				if ((choice > max_choice - 3) &&
+				    (scroll + max_choice < item_count())) {
+					/* Scroll menu up */
+					do_scroll(menu, &scroll, 1);
+
+					print_item(scroll+max_choice - 1,
+						   max_choice - 1, FALSE);
+				} else
+					choice = MIN(choice + 1, max_choice - 1);
+
+			} else if (key == KEY_PPAGE) {
+				scrollok(menu, TRUE);
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll > 0) {
+						do_scroll(menu, &scroll, -1);
+						print_item(scroll, 0, FALSE);
+					} else {
+						if (choice > 0)
+							choice--;
+					}
+				}
+
+			} else if (key == KEY_NPAGE) {
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll + max_choice < item_count()) {
+						do_scroll(menu, &scroll, 1);
+						print_item(scroll+max_choice-1,
+							   max_choice - 1, FALSE);
+					} else {
+						if (choice + 1 < max_choice)
+							choice++;
+					}
+				}
+			} else
+				choice = i;
+
+			print_item(scroll + choice, choice, TRUE);
+
+			print_arrows(dialog, item_count(), scroll,
+				     box_y, box_x + item_x + 1, menu_height);
+
+			wnoutrefresh(dialog);
+			wrefresh(menu);
+
+			continue;	/* wait for another key press */
+		}
+
+		switch (key) {
+		case KEY_LEFT:
+		case TAB:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 4 : (button > 4 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(menu);
+			break;
+		case ' ':
+		case 's':
+		case 'y':
+		case 'n':
+		case 'm':
+		case '/':
+		case 'h':
+		case '?':
+		case 'z':
+		case '\n':
+			/* save scroll info */
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			switch (key) {
+			case 'h':
+			case '?':
+				return 2;
+			case 's':
+			case 'y':
+				return 5;
+			case 'n':
+				return 6;
+			case 'm':
+				return 7;
+			case ' ':
+				return 8;
+			case '/':
+				return 9;
+			case 'z':
+				return 10;
+			case '\n':
+				return button;
+			}
+			return 0;
+		case 'e':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(menu);
+			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
+		}
+	}
+	delwin(menu);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/scripts/config/lxdialog/textbox.c b/scripts/config/lxdialog/textbox.c
new file mode 100644
index 0000000000..1773319b95
--- /dev/null
+++ b/scripts/config/lxdialog/textbox.c
@@ -0,0 +1,408 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static char *buf;
+static char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+			     int cur_y, int cur_x, update_text_fn update_text,
+			     void *data)
+{
+	print_page(box, boxh, boxw, update_text, data);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
+ */
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data)
+{
+	int i, x, y, cur_x, cur_y, key = 0;
+	int height, width, boxh, boxw;
+	WINDOW *dialog, *box;
+	bool done = false;
+
+	begin_reached = 1;
+	end_reached = 0;
+	page_length = 0;
+	hscroll = 0;
+	buf = tbuf;
+	page = buf;	/* page is pointer to start of page to be displayed */
+
+	if (_vscroll && *_vscroll) {
+		begin_reached = 0;
+
+		for (i = 0; i < *_vscroll; i++)
+			get_line();
+	}
+	if (_hscroll)
+		hscroll = *_hscroll;
+
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
+
+	/* center dialog box on screen */
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+	keypad(box, TRUE);
+
+	/* register the new window, along with its borders */
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+	wnoutrefresh(dialog);
+	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
+
+	/* Print first page of text */
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+			 data);
+
+	while (!done) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'E':	/* Exit */
+		case 'e':
+		case 'X':
+		case 'x':
+		case 'q':
+		case '\n':
+			done = true;
+			break;
+		case 'g':	/* First page */
+		case KEY_HOME:
+			if (!begin_reached) {
+				begin_reached = 1;
+				page = buf;
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x, update_text,
+						 data);
+			}
+			break;
+		case 'G':	/* Last page */
+		case KEY_END:
+
+			end_reached = 1;
+			/* point to last char in buf */
+			page = buf + strlen(buf);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'K':	/* Previous line */
+		case 'k':
+		case KEY_UP:
+			if (begin_reached)
+				break;
+
+			back_lines(page_length + 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'B':	/* Previous page */
+		case 'b':
+		case 'u':
+		case KEY_PPAGE:
+			if (begin_reached)
+				break;
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'J':	/* Next line */
+		case 'j':
+		case KEY_DOWN:
+			if (end_reached)
+				break;
+
+			back_lines(page_length - 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case KEY_NPAGE:	/* Next page */
+		case ' ':
+		case 'd':
+			if (end_reached)
+				break;
+
+			begin_reached = 0;
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case '0':	/* Beginning of line */
+		case 'H':	/* Scroll left */
+		case 'h':
+		case KEY_LEFT:
+			if (hscroll <= 0)
+				break;
+
+			if (key == '0')
+				hscroll = 0;
+			else
+				hscroll--;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'L':	/* Scroll right */
+		case 'l':
+		case KEY_RIGHT:
+			if (hscroll >= MAX_LEN)
+				break;
+			hscroll++;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case KEY_ESC:
+			if (on_key_esc(dialog) == KEY_ESC)
+				done = true;
+			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		default:
+			for (i = 0; keys[i]; i++) {
+				if (key == keys[i]) {
+					done = true;
+					break;
+				}
+			}
+		}
+	}
+	delwin(box);
+	delwin(dialog);
+	if (_vscroll) {
+		const char *s;
+
+		s = buf;
+		*_vscroll = 0;
+		back_lines(page_length);
+		while (s < page && (s = strchr(s, '\n'))) {
+			(*_vscroll)++;
+			s++;
+		}
+	}
+	if (_hscroll)
+		*_hscroll = hscroll;
+	return key;
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+	int i;
+
+	begin_reached = 0;
+	/* Go back 'n' lines */
+	for (i = 0; i < n; i++) {
+		if (*page == '\0') {
+			if (end_reached) {
+				end_reached = 0;
+				continue;
+			}
+		}
+		if (page == buf) {
+			begin_reached = 1;
+			return;
+		}
+		page--;
+		do {
+			if (page == buf) {
+				begin_reached = 1;
+				return;
+			}
+			page--;
+		} while (*page != '\n');
+		page++;
+	}
+}
+
+/*
+ * Print a new page of text.
+ */
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data)
+{
+	int i, passed_end = 0;
+
+	if (update_text) {
+		char *end;
+
+		for (i = 0; i < height; i++)
+			get_line();
+		end = page;
+		back_lines(height);
+		update_text(buf, page - buf, end - buf, data);
+	}
+
+	page_length = 0;
+	for (i = 0; i < height; i++) {
+		print_line(win, i, width);
+		if (!passed_end)
+			page_length++;
+		if (end_reached && !passed_end)
+			passed_end = 1;
+	}
+	wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text.
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+	char *line;
+
+	line = get_line();
+	line += MIN(strlen(line), hscroll);	/* Scroll horizontally */
+	wmove(win, row, 0);	/* move cursor to correct line */
+	waddch(win, ' ');
+	waddnstr(win, line, MIN(strlen(line), width - 2));
+
+	/* Clear 'residue' of previous line */
+#if OLD_NCURSES
+	{
+		int x = getcurx(win);
+		int i;
+		for (i = 0; i < width - x; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+	int i = 0;
+	static char line[MAX_LEN + 1];
+
+	end_reached = 0;
+	while (*page != '\n') {
+		if (*page == '\0') {
+			end_reached = 1;
+			break;
+		} else if (i < MAX_LEN)
+			line[i++] = *(page++);
+		else {
+			/* Truncate lines longer than MAX_LEN characters */
+			if (i == MAX_LEN)
+				line[i++] = '\0';
+			page++;
+		}
+	}
+	if (i <= MAX_LEN)
+		line[i] = '\0';
+	if (!end_reached)
+		page++;		/* move past '\n' */
+
+	return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+	int percent;
+
+	wattrset(win, dlg.position_indicator.atr);
+	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+	percent = (page - buf) * 100 / strlen(buf);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+	wprintw(win, "(%3d%%)", percent);
+}
diff --git a/scripts/config/lxdialog/util.c b/scripts/config/lxdialog/util.c
new file mode 100644
index 0000000000..f7abdeb92a
--- /dev/null
+++ b/scripts/config/lxdialog/util.c
@@ -0,0 +1,713 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+	dlg.screen.atr = A_NORMAL;
+	dlg.shadow.atr = A_NORMAL;
+	dlg.dialog.atr = A_NORMAL;
+	dlg.title.atr = A_BOLD;
+	dlg.border.atr = A_NORMAL;
+	dlg.button_active.atr = A_REVERSE;
+	dlg.button_inactive.atr = A_DIM;
+	dlg.button_key_active.atr = A_REVERSE;
+	dlg.button_key_inactive.atr = A_BOLD;
+	dlg.button_label_active.atr = A_REVERSE;
+	dlg.button_label_inactive.atr = A_NORMAL;
+	dlg.inputbox.atr = A_NORMAL;
+	dlg.inputbox_border.atr = A_NORMAL;
+	dlg.searchbox.atr = A_NORMAL;
+	dlg.searchbox_title.atr = A_BOLD;
+	dlg.searchbox_border.atr = A_NORMAL;
+	dlg.position_indicator.atr = A_BOLD;
+	dlg.menubox.atr = A_NORMAL;
+	dlg.menubox_border.atr = A_NORMAL;
+	dlg.item.atr = A_NORMAL;
+	dlg.item_selected.atr = A_REVERSE;
+	dlg.tag.atr = A_BOLD;
+	dlg.tag_selected.atr = A_REVERSE;
+	dlg.tag_key.atr = A_BOLD;
+	dlg.tag_key_selected.atr = A_REVERSE;
+	dlg.check.atr = A_BOLD;
+	dlg.check_selected.atr = A_REVERSE;
+	dlg.uarrow.atr = A_BOLD;
+	dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+	dlg.dialog.fg = (f);       \
+	dlg.dialog.bg = (b);       \
+	dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
+
+	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+	set_classic_theme();
+	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+	int use_color = 1;
+	if (!theme)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "classic") == 0)
+		set_classic_theme();
+	else if (strcmp(theme, "bluetitle") == 0)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "blackbg") == 0)
+		set_blackbg_theme();
+	else if (strcmp(theme, "mono") == 0)
+		use_color = 0;
+
+	return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+	static int pair = 0;
+
+	pair++;
+	init_pair(pair, color->fg, color->bg);
+	if (color->hl)
+		color->atr = A_BOLD | COLOR_PAIR(pair);
+	else
+		color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+	init_one_color(&dlg.screen);
+	init_one_color(&dlg.shadow);
+	init_one_color(&dlg.dialog);
+	init_one_color(&dlg.title);
+	init_one_color(&dlg.border);
+	init_one_color(&dlg.button_active);
+	init_one_color(&dlg.button_inactive);
+	init_one_color(&dlg.button_key_active);
+	init_one_color(&dlg.button_key_inactive);
+	init_one_color(&dlg.button_label_active);
+	init_one_color(&dlg.button_label_inactive);
+	init_one_color(&dlg.inputbox);
+	init_one_color(&dlg.inputbox_border);
+	init_one_color(&dlg.searchbox);
+	init_one_color(&dlg.searchbox_title);
+	init_one_color(&dlg.searchbox_border);
+	init_one_color(&dlg.position_indicator);
+	init_one_color(&dlg.menubox);
+	init_one_color(&dlg.menubox_border);
+	init_one_color(&dlg.item);
+	init_one_color(&dlg.item_selected);
+	init_one_color(&dlg.tag);
+	init_one_color(&dlg.tag_selected);
+	init_one_color(&dlg.tag_key);
+	init_one_color(&dlg.tag_key_selected);
+	init_one_color(&dlg.check);
+	init_one_color(&dlg.check_selected);
+	init_one_color(&dlg.uarrow);
+	init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+	int use_color;
+
+	use_color = set_theme(theme);
+	if (use_color && has_colors()) {
+		start_color();
+		init_dialog_colors();
+	} else
+		set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+	int i, j;
+
+	wattrset(win, attr);
+	for (i = 0; i < height; i++) {
+		wmove(win, i, 0);
+		for (j = 0; j < width; j++)
+			waddch(win, ' ');
+	}
+	touchwin(win);
+}
+
+void dialog_clear(void)
+{
+	int lines, columns;
+
+	lines = getmaxy(stdscr);
+	columns = getmaxx(stdscr);
+
+	attr_clear(stdscr, lines, columns, dlg.screen.atr);
+	/* Display background title if it exists ... - SLH */
+	if (dlg.backtitle != NULL) {
+		int i, len = 0, skip = 0;
+		struct subtitle_list *pos;
+
+		wattrset(stdscr, dlg.screen.atr);
+		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+
+		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+			/* 3 is for the arrow and spaces */
+			len += strlen(pos->text) + 3;
+		}
+
+		wmove(stdscr, 1, 1);
+		if (len > columns - 2) {
+			const char *ellipsis = "[...] ";
+			waddstr(stdscr, ellipsis);
+			skip = len - (columns - 2 - strlen(ellipsis));
+		}
+
+		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+			if (skip == 0)
+				waddch(stdscr, ACS_RARROW);
+			else
+				skip--;
+
+			if (skip == 0)
+				waddch(stdscr, ' ');
+			else
+				skip--;
+
+			if (skip < strlen(pos->text)) {
+				waddstr(stdscr, pos->text + skip);
+				skip = 0;
+			} else
+				skip -= strlen(pos->text);
+
+			if (skip == 0)
+				waddch(stdscr, ' ');
+			else
+				skip--;
+		}
+
+		for (i = len + 1; i < columns - 1; i++)
+			waddch(stdscr, ACS_HLINE);
+	}
+	wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+	int height, width;
+
+	initscr();		/* Init curses */
+
+	/* Get current cursor position for signal handler in mconf.c */
+	getyx(stdscr, saved_y, saved_x);
+
+	getmaxyx(stdscr, height, width);
+	if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
+		endwin();
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	dlg.backtitle = backtitle;
+	color_setup(getenv("MENUCONFIG_COLOR"));
+
+	keypad(stdscr, TRUE);
+	cbreak();
+	noecho();
+	dialog_clear();
+
+	return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+	dlg.backtitle = backtitle;
+}
+
+void set_dialog_subtitles(struct subtitle_list *subtitles)
+{
+	dlg.subtitles = subtitles;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+	/* move cursor back to original position */
+	move(y, x);
+	refresh();
+	endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+	if (title) {
+		int tlen = MIN(width - 2, strlen(title));
+		wattrset(dialog, dlg.title.atr);
+		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+		waddch(dialog, ' ');
+	}
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are propperly processed.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+	int newl, cur_x, cur_y;
+	int prompt_len, room, wlen;
+	char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
+
+	strcpy(tempstr, prompt);
+
+	prompt_len = strlen(tempstr);
+
+	if (prompt_len <= width - x * 2) {	/* If prompt is short */
+		wmove(win, y, (width - prompt_len) / 2);
+		waddstr(win, tempstr);
+	} else {
+		cur_x = x;
+		cur_y = y;
+		newl = 1;
+		word = tempstr;
+		while (word && *word) {
+			sp = strpbrk(word, "\n ");
+			if (sp && *sp == '\n')
+				newline_separator = sp;
+
+			if (sp)
+				*sp++ = 0;
+
+			/* Wrap to next line if either the word does not fit,
+			   or it is the first word of a new sentence, and it is
+			   short, and the next word does not fit. */
+			room = width - cur_x;
+			wlen = strlen(word);
+			if (wlen > room ||
+			    (newl && wlen < 4 && sp
+			     && wlen + 1 + strlen(sp) > room
+			     && (!(sp2 = strpbrk(sp, "\n "))
+				 || wlen + 1 + (sp2 - sp) > room))) {
+				cur_y++;
+				cur_x = x;
+			}
+			wmove(win, cur_y, cur_x);
+			waddstr(win, word);
+			getyx(win, cur_y, cur_x);
+
+			/* Move to the next line if the word separator was a newline */
+			if (newline_separator) {
+				cur_y++;
+				cur_x = x;
+				newline_separator = 0;
+			} else
+				cur_x++;
+
+			if (sp && *sp == ' ') {
+				cur_x++;	/* double space */
+				while (*++sp == ' ') ;
+				newl = 1;
+			} else
+				newl = 0;
+			word = sp;
+		}
+	}
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+	int i, temp;
+
+	wmove(win, y, x);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, "<");
+	temp = strspn(label, " ");
+	label += temp;
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	for (i = 0; i < temp; i++)
+		waddch(win, ' ');
+	wattrset(win, selected ? dlg.button_key_active.atr
+		 : dlg.button_key_inactive.atr);
+	waddch(win, label[0]);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	waddstr(win, (char *)label + 1);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, ">");
+	wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+	 chtype box, chtype border)
+{
+	int i, j;
+
+	wattrset(win, 0);
+	for (i = 0; i < height; i++) {
+		wmove(win, y + i, x);
+		for (j = 0; j < width; j++)
+			if (!i && !j)
+				waddch(win, border | ACS_ULCORNER);
+			else if (i == height - 1 && !j)
+				waddch(win, border | ACS_LLCORNER);
+			else if (!i && j == width - 1)
+				waddch(win, box | ACS_URCORNER);
+			else if (i == height - 1 && j == width - 1)
+				waddch(win, box | ACS_LRCORNER);
+			else if (!i)
+				waddch(win, border | ACS_HLINE);
+			else if (i == height - 1)
+				waddch(win, box | ACS_HLINE);
+			else if (!j)
+				waddch(win, border | ACS_VLINE);
+			else if (j == width - 1)
+				waddch(win, box | ACS_VLINE);
+			else
+				waddch(win, box | ' ');
+	}
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+	int i;
+
+	if (has_colors()) {	/* Whether terminal supports color? */
+		wattrset(win, dlg.shadow.atr);
+		wmove(win, y + height, x + 2);
+		for (i = 0; i < width; i++)
+			waddch(win, winch(win) & A_CHARTEXT);
+		for (i = y + 1; i < y + height + 1; i++) {
+			wmove(win, i, x + width);
+			waddch(win, winch(win) & A_CHARTEXT);
+			waddch(win, winch(win) & A_CHARTEXT);
+		}
+		wnoutrefresh(win);
+	}
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+	int i, in_paren = 0, c;
+
+	for (i = 0; i < strlen(string); i++) {
+		c = tolower(string[i]);
+
+		if (strchr("<[(", c))
+			++in_paren;
+		if (strchr(">])", c) && in_paren > 0)
+			--in_paren;
+
+		if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+			return i;
+	}
+
+	return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+	int key;
+	int key2;
+	int key3;
+
+	nodelay(win, TRUE);
+	keypad(win, FALSE);
+	key = wgetch(win);
+	key2 = wgetch(win);
+	do {
+		key3 = wgetch(win);
+	} while (key3 != ERR);
+	nodelay(win, FALSE);
+	keypad(win, TRUE);
+	if (key == KEY_ESC && key2 == ERR)
+		return KEY_ESC;
+	else if (key != ERR && key != KEY_ESC && key2 == ERR)
+		ungetch(key);
+
+	return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+	struct dialog_list *p, *next;
+
+	for (p = item_head; p; p = next) {
+		next = p->next;
+		free(p);
+	}
+	item_head = NULL;
+	item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+	va_list ap;
+	struct dialog_list *p = malloc(sizeof(*p));
+
+	if (item_head)
+		item_cur->next = p;
+	else
+		item_head = p;
+	item_cur = p;
+	memset(p, 0, sizeof(*p));
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+	va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+	size_t avail;
+
+	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+		  avail, fmt, ap);
+	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+	va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+	item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+	item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+	item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+	item_foreach()
+		if (item_is_selected())
+			return 1;
+	return 0;
+}
+
+void *item_data(void)
+{
+	return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+	return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next)
+		n++;
+	return n;
+}
+
+void item_set(int n)
+{
+	int i = 0;
+	item_foreach()
+		if (i++ == n)
+			return;
+}
+
+int item_n(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next) {
+		if (p == item_cur)
+			return n;
+		n++;
+	}
+	return 0;
+}
+
+const char *item_str(void)
+{
+	return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+	return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+	return (item_cur->node.tag == tag);
+}
diff --git a/scripts/config/lxdialog/yesno.c b/scripts/config/lxdialog/yesno.c
new file mode 100644
index 0000000000..676fb2f824
--- /dev/null
+++ b/scripts/config/lxdialog/yesno.c
@@ -0,0 +1,114 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 10;
+	int y = height - 2;
+
+	print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+	print_button(dialog, gettext("  No  "), y, x + 13, selected == 1);
+
+	wmove(dialog, y, x + 1 + 13 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+	int i, x, y, key = 0, button = 0;
+	WINDOW *dialog;
+
+do_resize:
+	if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	print_buttons(dialog, height, width, 0);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'Y':
+		case 'y':
+			delwin(dialog);
+			return 0;
+		case 'N':
+		case 'n':
+			delwin(dialog);
+			return 1;
+
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return button;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}
diff --git a/scripts/config/mconf.c b/scripts/config/mconf.c
new file mode 100644
index 0000000000..c366e21fba
--- /dev/null
+++ b/scripts/config/mconf.c
@@ -0,0 +1,1053 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"Some LEDE features may be built directly into the image.\n"
+"Some may be made into installable ipkg packages. Some features\n"
+"may be completely removed altogether.\n"
+"\n"
+"Menu items beginning with [*], <M> or [ ] represent features\n"
+"configured to be included, built as package or removed respectively.\n"
+"Pointed brackets <> represent packaging capable features.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to remove it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (i.e. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o  Use the Up/Down arrow keys (cursor keys) to highlight the item you\n"
+"   wish to change or the submenu you wish to select and press <Enter>.\n"
+"   Submenus are designated by \"--->\", empty ones by \"----\".\n"
+"\n"
+"   Shortcut: Press the option's highlighted letter (hotkey).\n"
+"             Pressing a hotkey more than once will sequence\n"
+"             through all visible items which use that hotkey.\n"
+"\n"
+"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+"   unseen options into view.\n"
+"\n"
+"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+"             using those letters.  You may press a single <ESC>, but\n"
+"             there is a delayed response which you may find annoying.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+"   <Exit>, <Help>, <Save>, and <Load>.\n"
+"\n"
+"o  To get help with an item, use the cursor keys to highlight <Help>\n"
+"   and press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"o  To toggle the display of hidden options, press <Z>.\n"
+"\n"
+"\n"
+"Radiolists  (Choice lists)\n"
+"-----------\n"
+"o  Use the cursor keys to select the option you wish to set and press\n"
+"   <S> or the <SPACE BAR>.\n"
+"\n"
+"   Shortcut: Press the first letter of the option you wish to set then\n"
+"             press <S> or <SPACE BAR>.\n"
+"\n"
+"o  To see available help for the item, use the cursor keys to highlight\n"
+"   <Help> and Press <ENTER>.\n"
+"\n"
+"   Shortcut: Press <H> or <?>.\n"
+"\n"
+"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+"   <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o  Enter the requested information and press <ENTER>\n"
+"   If you are entering hexadecimal values, it is not necessary to\n"
+"   add the '0x' prefix to the entry.\n"
+"\n"
+"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
+"   and press <ENTER>.  You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box    (Help Window)\n"
+"--------\n"
+"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
+"   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n"
+"   those who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"The <Save> button will let you save the current configuration to\n"
+"a file of your choosing.  Use the <Load> button to load a previously\n"
+"saved alternate configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you find\n"
+"during a Menuconfig session that you have completely messed up your\n"
+"settings, you may use the <Load> button to restore your previously\n"
+"saved settings from \".config\" without restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window, make sure you have your\n"
+"$TERM variable set to point to an xterm definition which supports\n"
+"color.  Otherwise, Menuconfig will look rather bad.  Menuconfig will\n"
+"not display correctly in an RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry.  I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment.  Some distributions\n"
+"export those variables via /etc/profile.  Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single menu,\n"
+"rather than the default multimenu hierarchy, run the menuconfig with\n"
+"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono       => selects colors suitable for monochrome displays\n"
+" blackbg    => selects a color scheme with black background\n"
+" classic    => theme with blue background. The classic look\n"
+" bluetitle  => an LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+	"Arrow keys navigate the menu.  "
+	"<Enter> selects submenus ---> (or empty submenus ----).  "
+	"Highlighted letters are hotkeys.  "
+	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
+	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
+	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
+radiolist_instructions[] = N_(
+	"Use the arrow keys to navigate this window or "
+	"press the hotkey of the item you wish to select "
+	"followed by the <SPACE BAR>. "
+	"Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+	"Please enter a decimal value. "
+	"Fractions will not be accepted.  "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+	"Please enter a hexadecimal value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+	"Please enter a string value. "
+	"Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+	"This feature depends on another which has been configured as a module.\n"
+	"As a result, this feature will be built as a module."),
+load_config_text[] = N_(
+	"Enter the name of the configuration file you wish to load.  "
+	"Accept the name shown to restore the configuration you "
+	"last retrieved.  Leave blank to abort."),
+load_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep several different\n"
+	"configurations available on a single machine.\n"
+	"\n"
+	"If you have saved a previous configuration in a file other than the\n"
+	"default one, entering its name here will allow you to modify that\n"
+	"configuration.\n"
+	"\n"
+	"If you are uncertain, then you have probably never used alternate\n"
+	"configuration files. You should therefore leave this blank to abort.\n"),
+save_config_text[] = N_(
+	"Enter a filename to which this configuration should be saved "
+	"as an alternate.  Leave blank to abort."),
+save_config_help[] = N_(
+	"\n"
+	"For various reasons, one may wish to keep different configurations\n"
+	"available on a single machine.\n"
+	"\n"
+	"Entering a file name here will allow you to later retrieve, modify\n"
+	"and use the current configuration as an alternate to whatever\n"
+	"configuration options you have selected at that time.\n"
+	"\n"
+	"If you are uncertain what all this means then you should probably\n"
+	"leave this blank.\n"),
+search_help[] = N_(
+	"\n"
+	"Search for symbols and display their relations.\n"
+	"Regular expressions are allowed.\n"
+	"Example: search for \"^FOO\"\n"
+	"Result:\n"
+	"-----------------------------------------------------------------\n"
+	"Symbol: FOO [=m]\n"
+	"Type  : tristate\n"
+	"Prompt: Foo bus is used to drive the bar HW\n"
+	"  Location:\n"
+	"    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+	"      -> PCI support (PCI [=y])\n"
+	"(1)     -> PCI access mode (<choice> [=y])\n"
+	"  Defined at drivers/pci/Kconfig:47\n"
+	"  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+	"  Selects: LIBCRC32\n"
+	"  Selected by: BAR [=n]\n"
+	"-----------------------------------------------------------------\n"
+	"o The line 'Type:' shows the type of the configuration option for\n"
+	"  this symbol (boolean, tristate, string, ...)\n"
+	"o The line 'Prompt:' shows the text used in the menu structure for\n"
+	"  this symbol\n"
+	"o The 'Defined at' line tells at what file / line number the symbol\n"
+	"  is defined\n"
+	"o The 'Depends on:' line tells what symbols need to be defined for\n"
+	"  this symbol to be visible in the menu (selectable)\n"
+	"o The 'Location:' lines tells where in the menu structure this symbol\n"
+	"  is located\n"
+	"    A location followed by a [=y] indicates that this is a\n"
+	"    selectable menu item - and the current value is displayed inside\n"
+	"    brackets.\n"
+	"    Press the key in the (#) prefix to jump directly to that\n"
+	"    location. You will be returned to the current search results\n"
+	"    after exiting this new menu.\n"
+	"o The 'Selects:' line tells what symbols will be automatically\n"
+	"  selected if this symbol is selected (y or m)\n"
+	"o The 'Selected by' line tells what symbol has selected this symbol\n"
+	"\n"
+	"Only relevant lines are shown.\n"
+	"\n\n"
+	"Search examples:\n"
+	"Examples: USB	=> find all symbols containing USB\n"
+	"          ^USB => find all symbols starting with USB\n"
+	"          USB$ => find all symbols ending with USB\n"
+	"\n");
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+static int show_all_options;
+static int save_and_exit;
+static int silent;
+
+static void conf(struct menu *menu, struct menu *active_menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static int show_textbox_ext(const char *title, char *text, int r, int c,
+			    int *keys, int *vscroll, int *hscroll,
+			    update_text_fn update_text, void *data);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+	static char menu_backtitle[PATH_MAX+128];
+	int size;
+
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+			"%s - %s", config_filename, rootmenu.prompt->text);
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+	set_dialog_backtitle(menu_backtitle);
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+}
+
+struct subtitle_part {
+	struct list_head entries;
+	const char *text;
+};
+static LIST_HEAD(trail);
+
+static struct subtitle_list *subtitles;
+static void set_subtitle(void)
+{
+	struct subtitle_part *sp;
+	struct subtitle_list *pos, *tmp;
+
+	for (pos = subtitles; pos != NULL; pos = tmp) {
+		tmp = pos->next;
+		free(pos);
+	}
+
+	subtitles = NULL;
+	list_for_each_entry(sp, &trail, entries) {
+		if (sp->text) {
+			if (pos) {
+				pos->next = xcalloc(1, sizeof(*pos));
+				pos = pos->next;
+			} else {
+				subtitles = pos = xcalloc(1, sizeof(*pos));
+			}
+			pos->text = sp->text;
+		}
+	}
+
+	set_dialog_subtitles(subtitles);
+}
+
+static void reset_subtitle(void)
+{
+	struct subtitle_list *pos, *tmp;
+
+	for (pos = subtitles; pos != NULL; pos = tmp) {
+		tmp = pos->next;
+		free(pos);
+	}
+	subtitles = NULL;
+	set_dialog_subtitles(subtitles);
+}
+
+struct search_data {
+	struct list_head *head;
+	struct menu **targets;
+	int *keys;
+};
+
+static void update_text(char *buf, size_t start, size_t end, void *_data)
+{
+	struct search_data *data = _data;
+	struct jump_key *pos;
+	int k = 0;
+
+	list_for_each_entry(pos, data->head, entries) {
+		if (pos->offset >= start && pos->offset < end) {
+			char header[4];
+
+			if (k < JUMP_NB) {
+				int key = '0' + (pos->index % JUMP_NB) + 1;
+
+				sprintf(header, "(%c)", key);
+				data->keys[k] = key;
+				data->targets[k] = pos->target;
+				k++;
+			} else {
+				sprintf(header, "   ");
+			}
+
+			memcpy(buf + pos->offset, header, sizeof(header) - 1);
+		}
+	}
+	data->keys[k] = 0;
+}
+
+static void search_conf(void)
+{
+	struct symbol **sym_arr;
+	struct gstr res;
+	struct gstr title;
+	char *dialog_input;
+	int dres, vscroll = 0, hscroll = 0;
+	bool again;
+	struct gstr sttext;
+	struct subtitle_part stpart;
+
+	title = str_new();
+	str_printf( &title, _("Enter (sub)string or regexp to search for "
+			      "(with or without \"%s\")"), CONFIG_);
+
+again:
+	dialog_clear();
+	dres = dialog_inputbox(_("Search Configuration Parameter"),
+			      str_get(&title),
+			      10, 75, "");
+	switch (dres) {
+	case 0:
+		break;
+	case 1:
+		show_helptext(_("Search Configuration"), search_help);
+		goto again;
+	default:
+		str_free(&title);
+		return;
+	}
+
+	/* strip the prefix if necessary */
+	dialog_input = dialog_input_result;
+	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+		dialog_input += strlen(CONFIG_);
+
+	sttext = str_new();
+	str_printf(&sttext, "Search (%s)", dialog_input_result);
+	stpart.text = str_get(&sttext);
+	list_add_tail(&stpart.entries, &trail);
+
+	sym_arr = sym_re_search(dialog_input);
+	do {
+		LIST_HEAD(head);
+		struct menu *targets[JUMP_NB];
+		int keys[JUMP_NB + 1], i;
+		struct search_data data = {
+			.head = &head,
+			.targets = targets,
+			.keys = keys,
+		};
+		struct jump_key *pos, *tmp;
+
+		res = get_relations_str(sym_arr, &head);
+		set_subtitle();
+		dres = show_textbox_ext(_("Search Results"), (char *)
+					str_get(&res), 0, 0, keys, &vscroll,
+					&hscroll, &update_text, (void *)
+					&data);
+		again = false;
+		for (i = 0; i < JUMP_NB && keys[i]; i++)
+			if (dres == keys[i]) {
+				conf(targets[i]->parent, targets[i]);
+				again = true;
+			}
+		str_free(&res);
+		list_for_each_entry_safe(pos, tmp, &head, entries)
+			free(pos);
+	} while (again);
+	free(sym_arr);
+	str_free(&title);
+	list_del(trail.prev);
+	str_free(&sttext);
+}
+
+static void build_conf(struct menu *menu)
+{
+	struct symbol *sym;
+	struct property *prop;
+	struct menu *child;
+	int type, tmp, doint = 2;
+	tristate val;
+	char ch;
+	bool visible;
+
+	/*
+	 * note: menu_is_visible() has side effect that it will
+	 * recalc the value of the symbol.
+	 */
+	visible = menu_is_visible(menu);
+	if (show_all_options && !menu_has_prompt(menu))
+		return;
+	else if (!show_all_options && !visible)
+		return;
+
+	sym = menu->sym;
+	prop = menu->prompt;
+	if (!sym) {
+		if (prop && menu != current_menu) {
+			const char *prompt = menu_get_prompt(menu);
+			switch (prop->type) {
+			case P_MENU:
+				child_count++;
+				prompt = _(prompt);
+				if (single_menu_mode) {
+					item_make("%s%*c%s",
+						  menu->data ? "-->" : "++>",
+						  indent + 1, ' ', prompt);
+				} else
+					item_make("   %*c%s  %s",
+						  indent + 1, ' ', prompt,
+						  menu_is_empty(menu) ? "----" : "--->");
+				item_set_tag('m');
+				item_set_data(menu);
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
+				return;
+			case P_COMMENT:
+				if (prompt) {
+					child_count++;
+					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+				break;
+			default:
+				if (prompt) {
+					child_count++;
+					item_make("---%*c%s", indent + 1, ' ', _(prompt));
+					item_set_tag(':');
+					item_set_data(menu);
+				}
+			}
+		} else
+			doint = 0;
+		goto conf_childs;
+	}
+
+	type = sym_get_type(sym);
+	if (sym_is_choice(sym)) {
+		struct symbol *def_sym = sym_get_choice_value(sym);
+		struct menu *def_menu = NULL;
+
+		child_count++;
+		for (child = menu->list; child; child = child->next) {
+			if (menu_is_visible(child) && child->sym == def_sym)
+				def_menu = child;
+		}
+
+		val = sym_get_tristate_value(sym);
+		if (sym_is_changable(sym)) {
+			switch (type) {
+			case S_BOOLEAN:
+				item_make("[%c]", val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				item_make("<%c>", ch);
+				break;
+			}
+			item_set_tag('t');
+			item_set_data(menu);
+		} else {
+			item_make("   ");
+			item_set_tag(def_menu ? 't' : ':');
+			item_set_data(menu);
+		}
+
+		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+		if (val == yes) {
+			if (def_menu) {
+				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
+				item_add_str("  --->");
+				if (def_menu->list) {
+					indent += 2;
+					build_conf(def_menu);
+					indent -= 2;
+				}
+			}
+			return;
+		}
+	} else {
+		if (menu == current_menu) {
+			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+			item_set_tag(':');
+			item_set_data(menu);
+			goto conf_childs;
+		}
+		child_count++;
+		val = sym_get_tristate_value(sym);
+		if (sym_is_choice_value(sym) && val == yes) {
+			item_make("   ");
+			item_set_tag(':');
+			item_set_data(menu);
+		} else {
+			switch (type) {
+			case S_BOOLEAN:
+				if (sym_is_changable(sym))
+					item_make("[%c]", val == no ? ' ' : '*');
+				else
+					item_make("-%c-", val == no ? ' ' : '*');
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes: ch = '*'; break;
+				case mod: ch = 'M'; break;
+				default:  ch = ' '; break;
+				}
+				if (sym_is_changable(sym)) {
+					if (sym->rev_dep.tri == mod)
+						item_make("{%c}", ch);
+					else
+						item_make("<%c>", ch);
+				} else
+					item_make("-%c-", ch);
+				item_set_tag('t');
+				item_set_data(menu);
+				break;
+			default:
+				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+				item_make("(%s)", sym_get_string_value(sym));
+				tmp = indent - tmp + 4;
+				if (tmp < 0)
+					tmp = 0;
+				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
+					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
+					     "" : _(" (NEW)"));
+				item_set_tag('s');
+				item_set_data(menu);
+				goto conf_childs;
+			}
+		}
+		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
+			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
+			  "" : _(" (NEW)"));
+		if (menu->prompt->type == P_MENU) {
+			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
+			return;
+		}
+	}
+
+conf_childs:
+	indent += doint;
+	for (child = menu->list; child; child = child->next)
+		build_conf(child);
+	indent -= doint;
+}
+
+static void conf(struct menu *menu, struct menu *active_menu)
+{
+	struct menu *submenu;
+	const char *prompt = menu_get_prompt(menu);
+	struct subtitle_part stpart;
+	struct symbol *sym;
+	int res;
+	int s_scroll = 0;
+
+	if (menu != &rootmenu)
+		stpart.text = menu_get_prompt(menu);
+	else
+		stpart.text = NULL;
+	list_add_tail(&stpart.entries, &trail);
+
+	while (1) {
+		item_reset();
+		current_menu = menu;
+		build_conf(menu);
+		if (!child_count)
+			break;
+		set_subtitle();
+		dialog_clear();
+		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
+				  _(menu_instructions),
+				  active_menu, &s_scroll);
+		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+			break;
+		if (item_count() != 0) {
+			if (!item_activate_selected())
+				continue;
+			if (!item_tag())
+				continue;
+		}
+		submenu = item_data();
+		active_menu = item_data();
+		if (submenu)
+			sym = submenu->sym;
+		else
+			sym = NULL;
+
+		switch (res) {
+		case 0:
+			switch (item_tag()) {
+			case 'm':
+				if (single_menu_mode)
+					submenu->data = (void *) (long) !submenu->data;
+				else
+					conf(submenu, NULL);
+				break;
+			case 't':
+				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+					conf_choice(submenu);
+				else if (submenu->prompt->type == P_MENU)
+					conf(submenu, NULL);
+				break;
+			case 's':
+				conf_string(submenu);
+				break;
+			}
+			break;
+		case 2:
+			if (sym)
+				show_help(submenu);
+			else {
+				reset_subtitle();
+				show_helptext(_("README"), _(mconf_readme));
+			}
+			break;
+		case 3:
+			reset_subtitle();
+			conf_save();
+			break;
+		case 4:
+			reset_subtitle();
+			conf_load();
+			break;
+		case 5:
+			if (item_is_tag('t')) {
+				if (sym_set_tristate_value(sym, yes))
+					break;
+				if (sym_set_tristate_value(sym, mod))
+					show_textbox(NULL, setmod_text, 6, 74);
+			}
+			break;
+		case 6:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, no);
+			break;
+		case 7:
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, mod);
+			break;
+		case 8:
+			if (item_is_tag('t'))
+				sym_toggle_tristate_value(sym);
+			else if (item_is_tag('m'))
+				conf(submenu, NULL);
+			break;
+		case 9:
+			search_conf();
+			break;
+		case 10:
+			show_all_options = !show_all_options;
+			break;
+		}
+	}
+
+	list_del(trail.prev);
+}
+
+static int show_textbox_ext(const char *title, char *text, int r, int c, int
+			    *keys, int *vscroll, int *hscroll, update_text_fn
+			    update_text, void *data)
+{
+	dialog_clear();
+	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
+			      update_text, data);
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+	show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
+			 NULL, NULL);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+	show_textbox(title, text, 0, 0);
+}
+
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+	char buf[PATH_MAX+1];
+
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	if (save_and_exit) {
+		if (!silent)
+			printf("%s", buf);
+	} else {
+		show_textbox(NULL, buf, 6, 60);
+	}
+}
+
+static void show_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+
+	help.max_width = getmaxx(stdscr) - 10;
+	menu_get_ext_help(menu, &help);
+
+	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
+	str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+	const char *prompt = _(menu_get_prompt(menu));
+	struct menu *child;
+	struct symbol *active;
+	struct property *prop;
+
+	active = sym_get_choice_value(menu->sym);
+	while (1) {
+		int res;
+		int selected;
+		item_reset();
+
+		current_menu = menu;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
+				continue;
+			if (child->sym)
+				item_make("%s", _(menu_get_prompt(child)));
+			else {
+				item_make("*** %s ***", _(menu_get_prompt(child)));
+				item_set_tag(':');
+			}
+			item_set_data(child);
+			if (child->sym == active)
+				item_set_selected(1);
+			if (child->sym == sym_get_choice_value(menu->sym))
+				item_set_tag('X');
+		}
+		dialog_clear();
+		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
+					_(radiolist_instructions),
+					MENUBOX_HEIGTH_MIN,
+					MENUBOX_WIDTH_MIN,
+					CHECKLIST_HEIGTH_MIN);
+		selected = item_activate_selected();
+		switch (res) {
+		case 0:
+			if (selected) {
+				child = item_data();
+				if (!child->sym)
+					break;
+
+				if (sym_get_tristate_value(child->sym) != yes) {
+					for_all_properties(menu->sym, prop, P_RESET) {
+						if (expr_calc_value(prop->visible.expr) == no)
+							continue;
+
+						conf_reset(S_DEF_USER);
+						break;
+					}
+				}
+				sym_set_tristate_value(child->sym, yes);
+			}
+			return;
+		case 1:
+			if (selected) {
+				child = item_data();
+				show_help(child);
+				active = child->sym;
+			} else
+				show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		case -ERRDISPLAYTOOSMALL:
+			return;
+		}
+	}
+}
+
+static void conf_string(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+
+	while (1) {
+		int res;
+		const char *heading;
+
+		switch (sym_get_type(menu->sym)) {
+		case S_INT:
+			heading = _(inputbox_instructions_int);
+			break;
+		case S_HEX:
+			heading = _(inputbox_instructions_hex);
+			break;
+		case S_STRING:
+			heading = _(inputbox_instructions_string);
+			break;
+		default:
+			heading = _("Internal mconf error!");
+		}
+		dialog_clear();
+		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
+				      heading, 10, 75,
+				      sym_get_string_value(menu->sym));
+		switch (res) {
+		case 0:
+			if (sym_set_string_value(menu->sym, dialog_input_result))
+				return;
+			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+			break;
+		case 1:
+			show_help(menu);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_load(void)
+{
+
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, load_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_read(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				sym_set_change_count(1);
+				return;
+			}
+			show_textbox(NULL, _("File does not exist!"), 5, 38);
+			break;
+		case 1:
+			show_helptext(_("Load Alternate Configuration"), load_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static void conf_save(void)
+{
+	while (1) {
+		int res;
+		dialog_clear();
+		res = dialog_inputbox(NULL, save_config_text,
+				      11, 55, filename);
+		switch(res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_write(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				return;
+			}
+			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
+			break;
+		case 1:
+			show_helptext(_("Save Alternate Configuration"), save_config_help);
+			break;
+		case KEY_ESC:
+			return;
+		}
+	}
+}
+
+static int handle_exit(void)
+{
+	int res;
+
+	save_and_exit = 1;
+	reset_subtitle();
+	dialog_clear();
+	if (conf_get_changed())
+		res = dialog_yesno(NULL,
+				   _("Do you wish to save your new configuration?\n"
+				     "(Press <ESC><ESC> to continue kernel configuration.)"),
+				   6, 60);
+	else
+		res = -1;
+
+	end_dialog(saved_x, saved_y);
+
+	switch (res) {
+	case 0:
+		if (conf_write(filename)) {
+			fprintf(stderr, _("\n\n"
+					  "Error while writing of the configuration.\n"
+					  "Your configuration changes were NOT saved."
+					  "\n\n"));
+			return 1;
+		}
+		/* fall through */
+	case -1:
+		if (!silent)
+			printf(_("\n\n"
+				 "*** End of the configuration.\n"
+				 "*** Execute 'make' to start the build or try 'make help'."
+				 "\n\n"));
+		res = 0;
+		break;
+	default:
+		if (!silent)
+			fprintf(stderr, _("\n\n"
+					  "Your configuration changes were NOT saved."
+					  "\n\n"));
+		if (res != KEY_ESC)
+			res = 0;
+	}
+
+	return res;
+}
+
+static void sig_handler(int signo)
+{
+	exit(handle_exit());
+}
+
+int main(int ac, char **av)
+{
+	char *mode;
+	int res;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	signal(SIGINT, sig_handler);
+
+	if (ac > 1 && strcmp(av[1], "-s") == 0) {
+		silent = 1;
+		/* Silence conf_read() until the real callback is set up */
+		conf_set_message_callback(NULL);
+		av++;
+	}
+	conf_parse(av[1]);
+	conf_read(NULL);
+
+	mode = getenv("MENUCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
+
+	if (init_dialog(NULL)) {
+		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+		return 1;
+	}
+
+	set_config_filename(conf_get_configname());
+	conf_set_message_callback(conf_message_callback);
+	do {
+		conf(&rootmenu, NULL);
+		res = handle_exit();
+	} while (res == KEY_ESC);
+
+	return res;
+}
diff --git a/scripts/config/menu.c b/scripts/config/menu.c
new file mode 100644
index 0000000000..3d89dc178d
--- /dev/null
+++ b/scripts/config/menu.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+static const char nohelp_text[] = "There is no help available for this option.";
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+void _menu_init(void)
+{
+	current_entry = current_menu = &rootmenu;
+	last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+	struct menu *menu;
+
+	menu = xmalloc(sizeof(*menu));
+	memset(menu, 0, sizeof(*menu));
+	menu->sym = sym;
+	menu->parent = current_menu;
+	menu->file = current_file;
+	menu->lineno = zconf_lineno();
+
+	*last_entry_ptr = menu;
+	last_entry_ptr = &menu->next;
+	current_entry = menu;
+	if (sym)
+		menu_add_symbol(P_SYMBOL, sym, NULL);
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+	menu_end_entry();
+	last_entry_ptr = &current_entry->list;
+	return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+	last_entry_ptr = &current_menu->next;
+	current_menu = current_menu->parent;
+}
+
+static struct expr *menu_check_dep(struct expr *e)
+{
+	if (!e)
+		return e;
+
+	switch (e->type) {
+	case E_NOT:
+		e->left.expr = menu_check_dep(e->left.expr);
+		break;
+	case E_OR:
+	case E_AND:
+		e->left.expr = menu_check_dep(e->left.expr);
+		e->right.expr = menu_check_dep(e->right.expr);
+		break;
+	case E_SYMBOL:
+		/* change 'm' into 'm' && MODULES */
+		if (e->left.sym == &symbol_mod)
+			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+		break;
+	default:
+		break;
+	}
+	return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+	struct symbol *sym = current_entry->sym;
+
+	if (sym->type == type)
+		return;
+	if (sym->type == S_UNKNOWN) {
+		sym->type = type;
+		return;
+	}
+	menu_warn(current_entry,
+		"ignoring type redefinition of '%s' from '%s' to '%s'",
+		sym->name ? sym->name : "<choice>",
+		sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+	struct property *prop = prop_alloc(type, current_entry->sym);
+
+	prop->menu = current_entry;
+	prop->expr = expr;
+	prop->visible.expr = menu_check_dep(dep);
+
+	if (prompt) {
+		if (isspace(*prompt)) {
+			prop_warn(prop, "leading whitespace ignored");
+			while (isspace(*prompt))
+				prompt++;
+		}
+		if (current_entry->prompt && current_entry != &rootmenu)
+			prop_warn(prop, "prompt redefined");
+
+		/* Apply all upper menus' visibilities to actual prompts. */
+		if(type == P_PROMPT) {
+			struct menu *menu = current_entry;
+
+			while ((menu = menu->parent) != NULL) {
+				struct expr *dup_expr;
+
+				if (!menu->visibility)
+					continue;
+				/*
+				 * Do not add a reference to the
+				 * menu's visibility expression but
+				 * use a copy of it.  Otherwise the
+				 * expression reduction functions
+				 * will modify expressions that have
+				 * multiple references which can
+				 * cause unwanted side effects.
+				 */
+				dup_expr = expr_copy(menu->visibility);
+
+				prop->visible.expr
+					= expr_alloc_and(prop->visible.expr,
+							 dup_expr);
+			}
+		}
+
+		current_entry->prompt = prop;
+	}
+	prop->text = prompt;
+
+	return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+	return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_visibility(struct expr *expr)
+{
+	current_entry->visibility = expr_alloc_and(current_entry->visibility,
+	    expr);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+	switch (token) {
+	case T_OPT_MODULES:
+		if (modules_sym)
+			zconf_error("symbol '%s' redefines option 'modules'"
+				    " already defined by symbol '%s'",
+				    current_entry->sym->name,
+				    modules_sym->name
+				    );
+		modules_sym = current_entry->sym;
+		break;
+	case T_OPT_DEFCONFIG_LIST:
+		if (!sym_defconfig_list)
+			sym_defconfig_list = current_entry->sym;
+		else if (sym_defconfig_list != current_entry->sym)
+			zconf_error("trying to redefine defconfig symbol");
+		break;
+	case T_OPT_ENV:
+		prop_add_env(arg);
+		break;
+	case T_OPT_ALLNOCONFIG_Y:
+		current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
+		break;
+	}
+}
+
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
+{
+	return sym2->type == S_INT || sym2->type == S_HEX ||
+	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+static void sym_check_prop(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *sym2;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_DEFAULT:
+			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+			    prop->expr->type != E_SYMBOL)
+				prop_warn(prop,
+				    "default for config symbol '%s'"
+				    " must be a single symbol", sym->name);
+			if (prop->expr->type != E_SYMBOL)
+				break;
+			sym2 = prop_get_symbol(prop);
+			if (sym->type == S_HEX || sym->type == S_INT) {
+				if (!menu_validate_number(sym, sym2))
+					prop_warn(prop,
+					    "'%s': number is invalid",
+					    sym->name);
+			}
+			break;
+		case P_SELECT:
+			sym2 = prop_get_symbol(prop);
+			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+				prop_warn(prop,
+				    "config symbol '%s' uses select, but is "
+				    "not boolean or tristate", sym->name);
+			else if (sym2->type != S_UNKNOWN &&
+				 sym2->type != S_BOOLEAN &&
+				 sym2->type != S_TRISTATE)
+				prop_warn(prop,
+				    "'%s' has wrong type. 'select' only "
+				    "accept arguments of boolean and "
+				    "tristate type", sym2->name);
+			break;
+		case P_RANGE:
+			if (sym->type != S_INT && sym->type != S_HEX)
+				prop_warn(prop, "range is only allowed "
+						"for int or hex symbols");
+			if (!menu_validate_number(sym, prop->expr->left.sym) ||
+			    !menu_validate_number(sym, prop->expr->right.sym))
+				prop_warn(prop, "range is invalid");
+			break;
+		default:
+			;
+		}
+	}
+}
+
+void menu_finalize(struct menu *parent)
+{
+	struct menu *menu, *last_menu;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+	sym = parent->sym;
+	if (parent->list) {
+		if (sym && sym_is_choice(sym)) {
+			if (sym->type == S_UNKNOWN) {
+				/* find the first choice value to find out choice type */
+				current_entry = parent;
+				for (menu = parent->list; menu; menu = menu->next) {
+					if (menu->sym && menu->sym->type != S_UNKNOWN) {
+						menu_set_type(menu->sym->type);
+						break;
+					}
+				}
+			}
+			/* set the type of the remaining choice values */
+			for (menu = parent->list; menu; menu = menu->next) {
+				current_entry = menu;
+				if (menu->sym && menu->sym->type == S_UNKNOWN)
+					menu_set_type(sym->type);
+			}
+			parentdep = expr_alloc_symbol(sym);
+		} else if (parent->prompt)
+			parentdep = parent->prompt->visible.expr;
+		else
+			parentdep = parent->dep;
+
+		for (menu = parent->list; menu; menu = menu->next) {
+			basedep = expr_transform(menu->dep);
+			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+			basedep = expr_eliminate_dups(basedep);
+			menu->dep = basedep;
+			if (menu->sym)
+				prop = menu->sym->prop;
+			else
+				prop = menu->prompt;
+			for (; prop; prop = prop->next) {
+				if (prop->menu != menu)
+					continue;
+				dep = expr_transform(prop->visible.expr);
+				dep = expr_alloc_and(expr_copy(basedep), dep);
+				dep = expr_eliminate_dups(dep);
+				if (menu->sym && menu->sym->type != S_TRISTATE)
+					dep = expr_trans_bool(dep);
+				prop->visible.expr = dep;
+				if (prop->type == P_SELECT) {
+					struct symbol *es = prop_get_symbol(prop);
+					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+				}
+			}
+		}
+		for (menu = parent->list; menu; menu = menu->next)
+			menu_finalize(menu);
+	} else if (sym) {
+		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+		basedep = expr_eliminate_dups(expr_transform(basedep));
+		last_menu = NULL;
+		for (menu = parent->next; menu; menu = menu->next) {
+			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+			if (!expr_contains_symbol(dep, sym))
+				break;
+			if (expr_depends_symbol(dep, sym))
+				goto next;
+			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+			dep = expr_eliminate_dups(expr_transform(dep));
+			dep2 = expr_copy(basedep);
+			expr_eliminate_eq(&dep, &dep2);
+			expr_free(dep);
+			if (!expr_is_yes(dep2)) {
+				expr_free(dep2);
+				break;
+			}
+			expr_free(dep2);
+		next:
+			menu_finalize(menu);
+			menu->parent = parent;
+			last_menu = menu;
+		}
+		if (last_menu) {
+			parent->list = parent->next;
+			parent->next = last_menu->next;
+			last_menu->next = NULL;
+		}
+
+		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
+	}
+	for (menu = parent->list; menu; menu = menu->next) {
+		if (sym && sym_is_choice(sym) &&
+		    menu->sym && !sym_is_choice_value(menu->sym)) {
+			current_entry = menu;
+			menu->sym->flags |= SYMBOL_CHOICEVAL;
+			if (!menu->prompt)
+				menu_warn(menu, "choice value must have a prompt");
+			for (prop = menu->sym->prop; prop; prop = prop->next) {
+				if (prop->type == P_DEFAULT)
+					prop_warn(prop, "defaults for choice "
+						  "values not supported");
+				if (prop->menu == menu)
+					continue;
+				if (prop->type == P_PROMPT &&
+				    prop->menu->parent->sym != sym)
+					prop_warn(prop, "choice value used outside its choice group");
+			}
+			/* Non-tristate choice values of tristate choices must
+			 * depend on the choice being set to Y. The choice
+			 * values' dependencies were propagated to their
+			 * properties above, so the change here must be re-
+			 * propagated.
+			 */
+			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+				menu->dep = expr_alloc_and(basedep, menu->dep);
+				for (prop = menu->sym->prop; prop; prop = prop->next) {
+					if (prop->menu != menu)
+						continue;
+					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+									    prop->visible.expr);
+				}
+			}
+			menu_add_symbol(P_CHOICE, sym, NULL);
+			prop = sym_get_choice_prop(sym);
+			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+				;
+			*ep = expr_alloc_one(E_LIST, NULL);
+			(*ep)->right.sym = menu->sym;
+		}
+		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+			for (last_menu = menu->list; ; last_menu = last_menu->next) {
+				last_menu->parent = parent;
+				if (!last_menu->next)
+					break;
+			}
+			last_menu->next = menu->next;
+			menu->next = menu->list;
+			menu->list = NULL;
+		}
+	}
+
+	if (sym && !(sym->flags & SYMBOL_WARNED)) {
+		if (sym->type == S_UNKNOWN)
+			menu_warn(parent, "config symbol defined without type");
+
+		if (sym_is_choice(sym) && !parent->prompt)
+			menu_warn(parent, "choice must have a prompt");
+
+		/* Check properties connected to this symbol */
+		sym_check_prop(sym);
+		sym->flags |= SYMBOL_WARNED;
+	}
+
+	if (sym && !sym_is_optional(sym) && parent->prompt) {
+		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+				expr_alloc_and(parent->prompt->visible.expr,
+					expr_alloc_symbol(&symbol_mod)));
+	}
+}
+
+bool menu_has_prompt(struct menu *menu)
+{
+	if (!menu->prompt)
+		return false;
+	return true;
+}
+
+/*
+ * Determine if a menu is empty.
+ * A menu is considered empty if it contains no or only
+ * invisible entries.
+ */
+bool menu_is_empty(struct menu *menu)
+{
+	struct menu *child;
+
+	for (child = menu->list; child; child = child->next) {
+		if (menu_is_visible(child))
+			return(false);
+	}
+	return(true);
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+	struct menu *child;
+	struct symbol *sym;
+	tristate visible;
+
+	if (!menu->prompt)
+		return false;
+
+	if (menu->visibility) {
+		if (expr_calc_value(menu->visibility) == no)
+			return false;
+	}
+
+	sym = menu->sym;
+	if (sym) {
+		sym_calc_value(sym);
+		visible = menu->prompt->visible.tri;
+	} else
+		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+	if (visible != no)
+		return true;
+
+	if (!sym || sym_get_tristate_value(menu->sym) == no)
+		return false;
+
+	for (child = menu->list; child; child = child->next) {
+		if (menu_is_visible(child)) {
+			if (sym)
+				sym->flags |= SYMBOL_DEF_USER;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+	if (menu->prompt)
+		return menu->prompt->text;
+	else if (menu->sym)
+		return menu->sym->name;
+	return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+	return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+	enum prop_type type;
+
+	for (; menu != &rootmenu; menu = menu->parent) {
+		type = menu->prompt ? menu->prompt->type : 0;
+		if (type == P_MENU)
+			break;
+	}
+	return menu;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+	return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+	if (menu->help)
+		return menu->help;
+	else
+		return "";
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop,
+			   struct list_head *head)
+{
+	int i, j;
+	struct menu *submenu[8], *menu, *location = NULL;
+	struct jump_key *jump = NULL;
+
+	str_printf(r, _("Prompt: %s\n"), _(prop->text));
+	menu = prop->menu->parent;
+	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+		bool accessible = menu_is_visible(menu);
+
+		submenu[i++] = menu;
+		if (location == NULL && accessible)
+			location = menu;
+	}
+	if (head && location) {
+		jump = xmalloc(sizeof(struct jump_key));
+
+		if (menu_is_visible(prop->menu)) {
+			/*
+			 * There is not enough room to put the hint at the
+			 * beginning of the "Prompt" line. Put the hint on the
+			 * last "Location" line even when it would belong on
+			 * the former.
+			 */
+			jump->target = prop->menu;
+		} else
+			jump->target = location;
+
+		if (list_empty(head))
+			jump->index = 0;
+		else
+			jump->index = list_entry(head->prev, struct jump_key,
+						 entries)->index + 1;
+
+		list_add_tail(&jump->entries, head);
+	}
+
+	if (i > 0) {
+		str_printf(r, _("  Location:\n"));
+		for (j = 4; --i >= 0; j += 2) {
+			menu = submenu[i];
+			if (jump && menu == location)
+				jump->offset = strlen(r->s);
+			str_printf(r, "%*c-> %s", j, ' ',
+				   _(menu_get_prompt(menu)));
+			if (menu->sym) {
+				str_printf(r, " (%s [=%s])", menu->sym->name ?
+					menu->sym->name : _("<choice>"),
+					sym_get_string_value(menu->sym));
+			}
+			str_append(r, "\n");
+		}
+	}
+}
+
+/*
+ * get property of type P_SYMBOL
+ */
+static struct property *get_symbol_prop(struct symbol *sym)
+{
+	struct property *prop = NULL;
+
+	for_all_properties(sym, prop, P_SYMBOL)
+		break;
+	return prop;
+}
+
+/*
+ * head is optional and may be NULL
+ */
+static void get_symbol_str(struct gstr *r, struct symbol *sym,
+		    struct list_head *head)
+{
+	bool hit;
+	struct property *prop;
+
+	if (sym && sym->name) {
+		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+			   sym_get_string_value(sym));
+		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
+		if (sym->type == S_INT || sym->type == S_HEX) {
+			prop = sym_get_range_prop(sym);
+			if (prop) {
+				str_printf(r, "Range : ");
+				expr_gstr_print(prop->expr, r);
+				str_append(r, "\n");
+			}
+		}
+	}
+	for_all_prompts(sym, prop)
+		get_prompt_str(r, prop, head);
+
+	prop = get_symbol_prop(sym);
+	if (prop) {
+		str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+			prop->menu->lineno);
+		if (!expr_is_yes(prop->visible.expr)) {
+			str_append(r, _("  Depends on: "));
+			expr_gstr_print(prop->visible.expr, r);
+			str_append(r, "\n");
+		}
+	}
+
+	hit = false;
+	for_all_properties(sym, prop, P_SELECT) {
+		if (!hit) {
+			str_append(r, "  Selects: ");
+			hit = true;
+		} else
+			str_printf(r, " && ");
+		expr_gstr_print(prop->expr, r);
+	}
+	if (hit)
+		str_append(r, "\n");
+	if (sym->rev_dep.expr) {
+		str_append(r, _("  Selected by: "));
+		expr_gstr_print(sym->rev_dep.expr, r);
+		str_append(r, "\n");
+	}
+	str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
+{
+	struct symbol *sym;
+	struct gstr res = str_new();
+	int i;
+
+	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+		get_symbol_str(&res, sym, head);
+	if (!i)
+		str_append(&res, _("No matches found.\n"));
+	return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+	struct symbol *sym = menu->sym;
+	const char *help_text = nohelp_text;
+
+	if (menu_has_help(menu)) {
+		if (sym->name)
+			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+		help_text = menu_get_help(menu);
+	}
+	str_printf(help, "%s\n", _(help_text));
+	if (sym)
+		get_symbol_str(help, sym, NULL);
+}
diff --git a/scripts/config/symbol.c b/scripts/config/symbol.c
new file mode 100644
index 0000000000..31f268a4ee
--- /dev/null
+++ b/scripts/config/symbol.c
@@ -0,0 +1,1386 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+	.name = "y",
+	.curr = { "y", yes },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+	.name = "m",
+	.curr = { "m", mod },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+	.name = "n",
+	.curr = { "n", no },
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+	.name = "",
+	.curr = { "", no },
+	.flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
+{
+	struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+	prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
+}
+
+void sym_init(void)
+{
+	struct symbol *sym;
+	struct utsname uts;
+	static bool inited = false;
+
+	if (inited)
+		return;
+	inited = true;
+
+	uname(&uts);
+
+	sym = sym_lookup("UNAME_RELEASE", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+	enum symbol_type type = sym->type;
+
+	if (type == S_TRISTATE) {
+		if (sym_is_choice_value(sym) && sym->visible == yes)
+			type = S_BOOLEAN;
+		else if (modules_val == no)
+			type = S_BOOLEAN;
+	}
+	return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+	switch (type) {
+	case S_BOOLEAN:
+		return "boolean";
+	case S_TRISTATE:
+		return "tristate";
+	case S_INT:
+		return "integer";
+	case S_HEX:
+		return "hex";
+	case S_STRING:
+		return "string";
+	case S_UNKNOWN:
+		return "unknown";
+	case S_OTHER:
+		break;
+	}
+	return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_choices(sym, prop)
+		return prop;
+	return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_ENV)
+		return prop;
+	return NULL;
+}
+
+static struct property *sym_get_default_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+static struct property *sym_get_range_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_RANGE) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+static long long sym_get_range_val(struct symbol *sym, int base)
+{
+	sym_calc_value(sym);
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		break;
+	}
+	return strtoll(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+	struct property *prop;
+	int base;
+	long long val, val2;
+	char str[64];
+
+	switch (sym->type) {
+	case S_INT:
+		base = 10;
+		break;
+	case S_HEX:
+		base = 16;
+		break;
+	default:
+		return;
+	}
+	prop = sym_get_range_prop(sym);
+	if (!prop)
+		return;
+	val = strtoll(sym->curr.val, NULL, base);
+	val2 = sym_get_range_val(prop->expr->left.sym, base);
+	if (val >= val2) {
+		val2 = sym_get_range_val(prop->expr->right.sym, base);
+		if (val <= val2)
+			return;
+	}
+	if (sym->type == S_INT)
+		sprintf(str, "%lld", val2);
+	else
+		sprintf(str, "0x%llx", val2);
+	sym->curr.val = strdup(str);
+}
+
+static void sym_set_changed(struct symbol *sym)
+{
+	struct property *prop;
+
+	sym->flags |= SYMBOL_CHANGED;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu)
+			prop->menu->flags |= MENU_CHANGED;
+	}
+}
+
+static void sym_set_all_changed(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym_set_changed(sym);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *choice_sym = NULL;
+	tristate tri;
+
+	/* any prompt visible? */
+	tri = no;
+
+	if (sym_is_choice_value(sym))
+		choice_sym = prop_get_symbol(sym_get_choice_prop(sym));
+
+	for_all_prompts(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		/*
+		 * Tristate choice_values with visibility 'mod' are
+		 * not visible if the corresponding choice's value is
+		 * 'yes'.
+		 */
+		if (choice_sym && sym->type == S_TRISTATE &&
+		    prop->visible.tri == mod && choice_sym->curr.tri == yes)
+			prop->visible.tri = no;
+
+		tri = EXPR_OR(tri, prop->visible.tri);
+	}
+	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+		tri = yes;
+	if (sym->visible != tri) {
+		sym->visible = tri;
+		sym_set_changed(sym);
+	}
+	if (sym_is_choice_value(sym))
+		return;
+	/* defaulting to "yes" if no explicit "depends on" are given */
+	tri = yes;
+	if (sym->dir_dep.expr)
+		tri = expr_calc_value(sym->dir_dep.expr);
+	if (tri == mod)
+		tri = yes;
+	if (sym->dir_dep.tri != tri) {
+		sym->dir_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+	tri = no;
+	if (sym->rev_dep.expr)
+		tri = expr_calc_value(sym->rev_dep.expr);
+	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+		tri = yes;
+	if (sym->rev_dep.tri != tri) {
+		sym->rev_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+}
+
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+
+	/* any of the defaults visible? */
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri == no)
+			continue;
+		def_sym = prop_get_symbol(prop);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* just get the first visible value */
+	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym)
+		if (def_sym->visible != no)
+			return def_sym;
+
+	/* failed to locate any defaults */
+	return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+	int flags;
+
+	/* first calculate all choice values' visibilities */
+	flags = sym->flags;
+	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym) {
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			flags &= def_sym->flags;
+	}
+
+	sym->flags &= flags | ~SYMBOL_DEF_USER;
+
+	/* is the user choice visible? */
+	def_sym = sym->def[S_DEF_USER].val;
+	if (def_sym && def_sym->visible != no)
+		return def_sym;
+
+	def_sym = sym_choice_default(sym);
+
+	if (def_sym == NULL)
+		/* no choice? reset tristate value */
+		sym->curr.tri = no;
+
+	return def_sym;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+	struct symbol_value newval, oldval;
+	struct property *prop;
+	struct expr *e;
+
+	if (!sym)
+		return;
+
+	if (sym->flags & SYMBOL_VALID)
+		return;
+
+	if (sym_is_choice_value(sym) &&
+	    sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
+		sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
+		prop = sym_get_choice_prop(sym);
+		sym_calc_value(prop_get_symbol(prop));
+	}
+
+	sym->flags |= SYMBOL_VALID;
+
+	oldval = sym->curr;
+
+	switch (sym->type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		newval = symbol_empty.curr;
+		break;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		newval = symbol_no.curr;
+		break;
+	default:
+		sym->curr.val = sym->name;
+		sym->curr.tri = no;
+		return;
+	}
+	if (!sym_is_choice_value(sym))
+		sym->flags &= ~SYMBOL_WRITE;
+
+	sym_calc_visibility(sym);
+
+	/* set default if recursively called */
+	sym->curr = newval;
+
+	switch (sym_get_type(sym)) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		if (sym_is_choice_value(sym) && sym->visible == yes) {
+			prop = sym_get_choice_prop(sym);
+			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+		} else {
+			if (sym->visible != no) {
+				/* if the symbol is visible use the user value
+				 * if available, otherwise try the default value
+				 */
+				sym->flags |= SYMBOL_WRITE;
+				if (sym_has_value(sym)) {
+					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+							      sym->visible);
+					goto calc_newval;
+				}
+			}
+			if (sym->rev_dep.tri != no)
+				sym->flags |= SYMBOL_WRITE;
+			if (!sym_is_choice(sym)) {
+				prop = sym_get_default_prop(sym);
+				if (prop) {
+					sym->flags |= SYMBOL_WRITE;
+					newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+							      prop->visible.tri);
+				}
+			}
+		calc_newval:
+			if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+				newval.tri = no;
+			} else {
+				newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
+			}
+		}
+		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+			newval.tri = yes;
+		break;
+	case S_STRING:
+	case S_HEX:
+	case S_INT:
+		if (sym->visible != no) {
+			sym->flags |= SYMBOL_WRITE;
+			if (sym_has_value(sym)) {
+				newval.val = sym->def[S_DEF_USER].val;
+				break;
+			}
+		}
+		prop = sym_get_default_prop(sym);
+		if (prop) {
+			struct symbol *ds = prop_get_symbol(prop);
+			if (ds) {
+				sym->flags |= SYMBOL_WRITE;
+				sym_calc_value(ds);
+				newval.val = ds->curr.val;
+			}
+		}
+		break;
+	default:
+		;
+	}
+
+	sym->curr = newval;
+	if (sym_is_choice(sym) && newval.tri == yes)
+		sym->curr.val = sym_calc_choice(sym);
+	sym_validate_range(sym);
+
+	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+		sym_set_changed(sym);
+		if (modules_sym == sym) {
+			sym_set_all_changed();
+			modules_val = modules_sym->curr.tri;
+		}
+	}
+
+	if (sym_is_choice(sym)) {
+		struct symbol *choice_sym;
+
+		prop = sym_get_choice_prop(sym);
+		expr_list_for_each_sym(prop->expr, e, choice_sym) {
+			if ((sym->flags & SYMBOL_WRITE) &&
+			    choice_sym->visible != no)
+				choice_sym->flags |= SYMBOL_WRITE;
+			if (sym->flags & SYMBOL_CHANGED)
+				sym_set_changed(choice_sym);
+		}
+	}
+
+	if (sym->flags & SYMBOL_AUTO)
+		sym->flags &= ~SYMBOL_WRITE;
+
+	if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
+		set_all_choice_values(sym);
+}
+
+void sym_clear_all_valid(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym->flags &= ~SYMBOL_VALID;
+	sym_add_change_count(1);
+	sym_calc_value(modules_sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+	int type = sym_get_type(sym);
+
+	if (sym->visible == no)
+		return false;
+
+	if (type != S_BOOLEAN && type != S_TRISTATE)
+		return false;
+
+	if (type == S_BOOLEAN && val == mod)
+		return false;
+	if (sym->visible <= sym->rev_dep.tri)
+		return false;
+	if (sym_is_choice_value(sym) && sym->visible == yes)
+		return val == yes;
+	return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+	tristate oldval = sym_get_tristate_value(sym);
+
+	if (oldval != val && !sym_tristate_within_range(sym, val))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+	/*
+	 * setting a choice value also resets the new flag of the choice
+	 * symbol and all other choice values.
+	 */
+	if (sym_is_choice_value(sym) && val == yes) {
+		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+		struct property *prop;
+		struct expr *e;
+
+		cs->def[S_DEF_USER].val = sym;
+		cs->flags |= SYMBOL_DEF_USER;
+		prop = sym_get_choice_prop(cs);
+		for (e = prop->expr; e; e = e->left.expr) {
+			if (e->right.sym->visible != no)
+				e->right.sym->flags |= SYMBOL_DEF_USER;
+		}
+	}
+
+	sym->def[S_DEF_USER].tri = val;
+	if (oldval != val)
+		sym_clear_all_valid();
+
+	return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+	tristate oldval, newval;
+
+	oldval = newval = sym_get_tristate_value(sym);
+	do {
+		switch (newval) {
+		case no:
+			newval = mod;
+			break;
+		case mod:
+			newval = yes;
+			break;
+		case yes:
+			newval = no;
+			break;
+		}
+		if (sym_set_tristate_value(sym, newval))
+			break;
+	} while (oldval != newval);
+	return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+	signed char ch;
+
+	switch (sym->type) {
+	case S_STRING:
+		return true;
+	case S_INT:
+		ch = *str++;
+		if (ch == '-')
+			ch = *str++;
+		if (!isdigit(ch))
+			return false;
+		if (ch == '0' && *str != 0)
+			return false;
+		while ((ch = *str++)) {
+			if (!isdigit(ch))
+				return false;
+		}
+		return true;
+	case S_HEX:
+		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+			str += 2;
+		ch = *str++;
+		do {
+			if (!isxdigit(ch))
+				return false;
+		} while ((ch = *str++));
+		return true;
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+		case 'm': case 'M':
+		case 'n': case 'N':
+			return true;
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+	struct property *prop;
+	long long val;
+
+	switch (sym->type) {
+	case S_STRING:
+		return sym_string_valid(sym, str);
+	case S_INT:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtoll(str, NULL, 10);
+		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 10);
+	case S_HEX:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtoll(str, NULL, 16);
+		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+		       val <= sym_get_range_val(prop->expr->right.sym, 16);
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (str[0]) {
+		case 'y': case 'Y':
+			return sym_tristate_within_range(sym, yes);
+		case 'm': case 'M':
+			return sym_tristate_within_range(sym, mod);
+		case 'n': case 'N':
+			return sym_tristate_within_range(sym, no);
+		}
+		return false;
+	default:
+		return false;
+	}
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+	const char *oldval;
+	char *val;
+	int size;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (newval[0]) {
+		case 'y': case 'Y':
+			return sym_set_tristate_value(sym, yes);
+		case 'm': case 'M':
+			return sym_set_tristate_value(sym, mod);
+		case 'n': case 'N':
+			return sym_set_tristate_value(sym, no);
+		}
+		return false;
+	default:
+		;
+	}
+
+	if (!sym_string_within_range(sym, newval))
+		return false;
+
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
+		sym_set_changed(sym);
+	}
+
+	oldval = sym->def[S_DEF_USER].val;
+	size = strlen(newval) + 1;
+	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+		size += 2;
+		sym->def[S_DEF_USER].val = val = xmalloc(size);
+		*val++ = '0';
+		*val++ = 'x';
+	} else if (!oldval || strcmp(oldval, newval))
+		sym->def[S_DEF_USER].val = val = xmalloc(size);
+	else
+		return true;
+
+	strcpy(val, newval);
+	free((void *)oldval);
+	sym_clear_all_valid();
+
+	return true;
+}
+
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *ds;
+	const char *str;
+	tristate val;
+
+	sym_calc_visibility(sym);
+	sym_calc_value(modules_sym);
+	val = symbol_no.curr.tri;
+	str = symbol_empty.curr.val;
+
+	/* If symbol has a default value look it up */
+	prop = sym_get_default_prop(sym);
+	if (prop != NULL) {
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			/* The visibility may limit the value from yes => mod */
+			val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+			break;
+		default:
+			/*
+			 * The following fails to handle the situation
+			 * where a default value is further limited by
+			 * the valid range.
+			 */
+			ds = prop_get_symbol(prop);
+			if (ds != NULL) {
+				sym_calc_value(ds);
+				str = (const char *)ds->curr.val;
+			}
+		}
+	}
+
+	/* Handle select statements */
+	val = EXPR_OR(val, sym->rev_dep.tri);
+
+	/* transpose mod to yes if modules are not enabled */
+	if (val == mod)
+		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+			val = yes;
+
+	/* transpose mod to yes if type is bool */
+	if (sym->type == S_BOOLEAN && val == mod)
+		val = yes;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (val) {
+		case no: return "n";
+		case mod: return "m";
+		case yes: return "y";
+		}
+	case S_INT:
+	case S_HEX:
+		return str;
+	case S_STRING:
+		return str;
+	case S_OTHER:
+	case S_UNKNOWN:
+		break;
+	}
+	return "";
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+	tristate val;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		val = sym_get_tristate_value(sym);
+		switch (val) {
+		case no:
+			return "n";
+		case mod:
+			sym_calc_value(modules_sym);
+			return (modules_sym->curr.tri == no) ? "n" : "m";
+		case yes:
+			return "y";
+		}
+		break;
+	default:
+		;
+	}
+	return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+	return sym->visible > sym->rev_dep.tri;
+}
+
+static unsigned strhash(const char *s)
+{
+	/* fnv32 hash */
+	unsigned hash = 2166136261U;
+	for (; *s; s++)
+		hash = (hash ^ *s) * 0x01000193;
+	return hash;
+}
+
+struct symbol *sym_lookup(const char *name, int flags)
+{
+	struct symbol *symbol;
+	char *new_name;
+	int hash;
+
+	if (name) {
+		if (name[0] && !name[1]) {
+			switch (name[0]) {
+			case 'y': return &symbol_yes;
+			case 'm': return &symbol_mod;
+			case 'n': return &symbol_no;
+			}
+		}
+		hash = strhash(name) % SYMBOL_HASHSIZE;
+
+		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+			if (symbol->name &&
+			    !strcmp(symbol->name, name) &&
+			    (flags ? symbol->flags & flags
+				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+				return symbol;
+		}
+		new_name = strdup(name);
+	} else {
+		new_name = NULL;
+		hash = 0;
+	}
+
+	symbol = xmalloc(sizeof(*symbol));
+	memset(symbol, 0, sizeof(*symbol));
+	symbol->name = new_name;
+	symbol->type = S_UNKNOWN;
+	symbol->flags |= flags;
+
+	symbol->next = symbol_hash[hash];
+	symbol_hash[hash] = symbol;
+
+	return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+	struct symbol *symbol = NULL;
+	int hash = 0;
+
+	if (!name)
+		return NULL;
+
+	if (name[0] && !name[1]) {
+		switch (name[0]) {
+		case 'y': return &symbol_yes;
+		case 'm': return &symbol_mod;
+		case 'n': return &symbol_no;
+		}
+	}
+	hash = strhash(name) % SYMBOL_HASHSIZE;
+
+	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+		if (symbol->name &&
+		    !strcmp(symbol->name, name) &&
+		    !(symbol->flags & SYMBOL_CONST))
+				break;
+	}
+
+	return symbol;
+}
+
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+	const char *src;
+	char *res;
+	size_t reslen;
+
+	reslen = strlen(in) + 1;
+	res = xmalloc(reslen);
+	res[0] = '\0';
+
+	while ((src = strchr(in, '$'))) {
+		char *p, name[SYMBOL_MAXLENGTH];
+		const char *symval = "";
+		struct symbol *sym;
+		size_t newlen;
+
+		strncat(res, in, src - in);
+		src++;
+
+		p = name;
+		while (isalnum(*src) || *src == '_')
+			*p++ = *src++;
+		*p = '\0';
+
+		sym = sym_find(name);
+		if (sym != NULL) {
+			sym_calc_value(sym);
+			symval = sym_get_string_value(sym);
+		}
+
+		newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+		if (newlen > reslen) {
+			reslen = newlen;
+			res = realloc(res, reslen);
+		}
+
+		strcat(res, symval);
+		in = src;
+	}
+	strcat(res, in);
+
+	return res;
+}
+
+const char *sym_escape_string_value(const char *in)
+{
+	const char *p;
+	size_t reslen;
+	char *res;
+	size_t l;
+
+	reslen = strlen(in) + strlen("\"\"") + 1;
+
+	p = in;
+	for (;;) {
+		l = strcspn(p, "\"\\");
+		p += l;
+
+		if (p[0] == '\0')
+			break;
+
+		reslen++;
+		p++;
+	}
+
+	res = xmalloc(reslen);
+	res[0] = '\0';
+
+	strcat(res, "\"");
+
+	p = in;
+	for (;;) {
+		l = strcspn(p, "\"\\");
+		strncat(res, p, l);
+		p += l;
+
+		if (p[0] == '\0')
+			break;
+
+		strcat(res, "\\");
+		strncat(res, p++, 1);
+	}
+
+	strcat(res, "\"");
+	return res;
+}
+
+struct sym_match {
+	struct symbol	*sym;
+	off_t		so, eo;
+};
+
+/* Compare matched symbols as thus:
+ * - first, symbols that match exactly
+ * - then, alphabetical sort
+ */
+static int sym_rel_comp(const void *sym1, const void *sym2)
+{
+	const struct sym_match *s1 = sym1;
+	const struct sym_match *s2 = sym2;
+	int exact1, exact2;
+
+	/* Exact match:
+	 * - if matched length on symbol s1 is the length of that symbol,
+	 *   then this symbol should come first;
+	 * - if matched length on symbol s2 is the length of that symbol,
+	 *   then this symbol should come first.
+	 * Note: since the search can be a regexp, both symbols may match
+	 * exactly; if this is the case, we can't decide which comes first,
+	 * and we fallback to sorting alphabetically.
+	 */
+	exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
+	exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
+	if (exact1 && !exact2)
+		return -1;
+	if (!exact1 && exact2)
+		return 1;
+
+	/* As a fallback, sort symbols alphabetically */
+	return strcmp(s1->sym->name, s2->sym->name);
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+	struct symbol *sym, **sym_arr = NULL;
+	struct sym_match *sym_match_arr = NULL;
+	int i, cnt, size;
+	regex_t re;
+	regmatch_t match[1];
+
+	cnt = size = 0;
+	/* Skip if empty */
+	if (strlen(pattern) == 0)
+		return NULL;
+	if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
+		return NULL;
+
+	for_all_symbols(i, sym) {
+		if (sym->flags & SYMBOL_CONST || !sym->name)
+			continue;
+		if (regexec(&re, sym->name, 1, match, 0))
+			continue;
+		if (cnt >= size) {
+			void *tmp;
+			size += 16;
+			tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
+			if (!tmp)
+				goto sym_re_search_free;
+			sym_match_arr = tmp;
+		}
+		sym_calc_value(sym);
+		/* As regexec returned 0, we know we have a match, so
+		 * we can use match[0].rm_[se]o without further checks
+		 */
+		sym_match_arr[cnt].so = match[0].rm_so;
+		sym_match_arr[cnt].eo = match[0].rm_eo;
+		sym_match_arr[cnt++].sym = sym;
+	}
+	if (sym_match_arr) {
+		qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
+		sym_arr = malloc((cnt+1) * sizeof(struct symbol));
+		if (!sym_arr)
+			goto sym_re_search_free;
+		for (i = 0; i < cnt; i++)
+			sym_arr[i] = sym_match_arr[i].sym;
+		sym_arr[cnt] = NULL;
+	}
+sym_re_search_free:
+	/* sym_match_arr can be NULL if no match, but free(NULL) is OK */
+	free(sym_match_arr);
+	regfree(&re);
+
+	return sym_arr;
+}
+
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note insert() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+	struct dep_stack *prev, *next;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+	memset(stack, 0, sizeof(*stack));
+	if (check_top)
+		check_top->next = stack;
+	stack->prev = check_top;
+	stack->sym = sym;
+	check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+	check_top = check_top->prev;
+	if (check_top)
+		check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+	struct dep_stack *stack;
+	struct symbol *sym, *next_sym;
+	struct menu *menu = NULL;
+	struct property *prop;
+	struct dep_stack cv_stack;
+
+	if (sym_is_choice_value(last_sym)) {
+		dep_stack_insert(&cv_stack, last_sym);
+		last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+	}
+
+	for (stack = check_top; stack != NULL; stack = stack->prev)
+		if (stack->sym == last_sym)
+			break;
+	if (!stack) {
+		fprintf(stderr, "unexpected recursive dependency error\n");
+		return;
+	}
+
+	for (; stack; stack = stack->next) {
+		sym = stack->sym;
+		next_sym = stack->next ? stack->next->sym : last_sym;
+		prop = stack->prop;
+		if (prop == NULL)
+			prop = stack->sym->prop;
+
+		/* for choice values find the menu entry (used below) */
+		if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+			for (prop = sym->prop; prop; prop = prop->next) {
+				menu = prop->menu;
+				if (prop->menu)
+					break;
+			}
+		}
+		if (stack->sym == last_sym)
+			fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+				prop->file->name, prop->lineno);
+			fprintf(stderr, "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n");
+			fprintf(stderr, "subsection \"Kconfig recursive dependency limitations\"\n");
+		if (stack->expr) {
+			fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				prop_get_type_name(prop->type),
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (stack->prop) {
+			fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice(sym)) {
+			fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice_value(sym)) {
+			fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else {
+			fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		}
+	}
+
+	if (check_top == &cv_stack)
+		dep_stack_remove();
+}
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+	struct symbol *sym;
+
+	if (!e)
+		return NULL;
+	switch (e->type) {
+	case E_OR:
+	case E_AND:
+		sym = sym_check_expr_deps(e->left.expr);
+		if (sym)
+			return sym;
+		return sym_check_expr_deps(e->right.expr);
+	case E_NOT:
+		return sym_check_expr_deps(e->left.expr);
+	case E_EQUAL:
+	case E_GEQ:
+	case E_GTH:
+	case E_LEQ:
+	case E_LTH:
+	case E_UNEQUAL:
+		sym = sym_check_deps(e->left.sym);
+		if (sym)
+			return sym;
+		return sym_check_deps(e->right.sym);
+	case E_SYMBOL:
+		return sym_check_deps(e->left.sym);
+	default:
+		break;
+	}
+	printf("Oops! How to check %d?\n", e->type);
+	return NULL;
+}
+
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, sym);
+
+	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+	if (sym2)
+		goto out;
+
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->type == P_CHOICE || prop->type == P_SELECT)
+			continue;
+		stack.prop = prop;
+		sym2 = sym_check_expr_deps(prop->visible.expr);
+		if (sym2)
+			break;
+		if (prop->type != P_DEFAULT || sym_is_choice(sym))
+			continue;
+		stack.expr = prop->expr;
+		sym2 = sym_check_expr_deps(prop->expr);
+		if (sym2)
+			break;
+		stack.expr = NULL;
+	}
+
+out:
+	dep_stack_remove();
+
+	return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	struct expr *e;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, choice);
+
+	prop = sym_get_choice_prop(choice);
+	expr_list_for_each_sym(prop->expr, e, sym)
+		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+	choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+	sym2 = sym_check_sym_deps(choice);
+	choice->flags &= ~SYMBOL_CHECK;
+	if (sym2)
+		goto out;
+
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		sym2 = sym_check_sym_deps(sym);
+		if (sym2)
+			break;
+	}
+out:
+	expr_list_for_each_sym(prop->expr, e, sym)
+		sym->flags &= ~SYMBOL_CHECK;
+
+	if (sym2 && sym_is_choice_value(sym2) &&
+	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+		sym2 = choice;
+
+	dep_stack_remove();
+
+	return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+
+	if (sym->flags & SYMBOL_CHECK) {
+		sym_check_print_recursive(sym);
+		return sym;
+	}
+	if (sym->flags & SYMBOL_CHECKED)
+		return NULL;
+
+	if (sym_is_choice_value(sym)) {
+		struct dep_stack stack;
+
+		/* for choice groups start the check with main choice symbol */
+		dep_stack_insert(&stack, sym);
+		prop = sym_get_choice_prop(sym);
+		sym2 = sym_check_deps(prop_get_symbol(prop));
+		dep_stack_remove();
+	} else if (sym_is_choice(sym)) {
+		sym2 = sym_check_choice_deps(sym);
+	} else {
+		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+		sym2 = sym_check_sym_deps(sym);
+		sym->flags &= ~SYMBOL_CHECK;
+	}
+
+	if (sym2 && sym2 == sym)
+		sym2 = NULL;
+
+	return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+	struct property *prop;
+	struct property **propp;
+
+	prop = xmalloc(sizeof(*prop));
+	memset(prop, 0, sizeof(*prop));
+	prop->type = type;
+	prop->sym = sym;
+	prop->file = current_file;
+	prop->lineno = zconf_lineno();
+
+	/* append property to the prop list of symbol */
+	if (sym) {
+		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+			;
+		*propp = prop;
+	}
+
+	return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+	if (prop->expr && (prop->expr->type == E_SYMBOL ||
+			   prop->expr->type == E_LIST))
+		return prop->expr->left.sym;
+	return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+	switch (type) {
+	case P_PROMPT:
+		return "prompt";
+	case P_ENV:
+		return "env";
+	case P_COMMENT:
+		return "comment";
+	case P_MENU:
+		return "menu";
+	case P_DEFAULT:
+		return "default";
+	case P_CHOICE:
+		return "choice";
+	case P_SELECT:
+		return "select";
+	case P_RANGE:
+		return "range";
+	case P_SYMBOL:
+		return "symbol";
+	case P_RESET:
+		return "reset";
+	case P_UNKNOWN:
+		break;
+	}
+	return "unknown";
+}
+
+static void prop_add_env(const char *env)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	char *p;
+
+	sym = current_entry->sym;
+	sym->flags |= SYMBOL_AUTO;
+	for_all_properties(sym, prop, P_ENV) {
+		sym2 = prop_get_symbol(prop);
+		if (strcmp(sym2->name, env))
+			menu_warn(current_entry, "redefining environment symbol from %s",
+				  sym2->name);
+		return;
+	}
+
+	prop = prop_alloc(P_ENV, sym);
+	prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+	sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+	sym_env_list->right.sym = sym;
+
+	p = getenv(env);
+	if (p)
+		sym_add_default(sym, p);
+	else
+		menu_warn(current_entry, "environment variable %s undefined", env);
+}
diff --git a/scripts/config/util.c b/scripts/config/util.c
new file mode 100644
index 0000000000..0e76042473
--- /dev/null
+++ b/scripts/config/util.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+	struct file *file;
+	const char *file_name = sym_expand_string_value(name);
+
+	for (file = file_list; file; file = file->next) {
+		if (!strcmp(name, file->name)) {
+			free((void *)file_name);
+			return file;
+		}
+	}
+
+	file = xmalloc(sizeof(*file));
+	memset(file, 0, sizeof(*file));
+	file->name = file_name;
+	file->next = file_list;
+	file_list = file;
+	return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+	struct symbol *sym, *env_sym;
+	struct expr *e;
+	struct file *file;
+	FILE *out;
+
+	if (!name)
+		name = ".kconfig.d";
+	out = fopen("..config.tmp", "w");
+	if (!out)
+		return 1;
+	fprintf(out, "deps_config := \\\n");
+	for (file = file_list; file; file = file->next) {
+		if (file->next)
+			fprintf(out, "\t%s \\\n", file->name);
+		else
+			fprintf(out, "\t%s\n", file->name);
+	}
+	fprintf(out, "\n%s: \\\n"
+		     "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+	expr_list_for_each_sym(sym_env_list, e, sym) {
+		struct property *prop;
+		const char *value;
+
+		prop = sym_get_env_prop(sym);
+		env_sym = prop_get_symbol(prop);
+		if (!env_sym)
+			continue;
+		value = getenv(env_sym->name);
+		if (!value)
+			value = "";
+		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+		fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
+		fprintf(out, "endif\n");
+	}
+
+	fprintf(out, "\n$(deps_config): ;\n");
+	fclose(out);
+	rename("..config.tmp", name);
+	return 0;
+}
+
+
+/* Allocate initial growable string */
+struct gstr str_new(void)
+{
+	struct gstr gs;
+	gs.s = xmalloc(sizeof(char) * 64);
+	gs.len = 64;
+	gs.max_width = 0;
+	strcpy(gs.s, "\0");
+	return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+	if (gs->s)
+		free(gs->s);
+	gs->s = NULL;
+	gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+	size_t l;
+	if (s) {
+		l = strlen(gs->s) + strlen(s) + 1;
+		if (l > gs->len) {
+			gs->s   = realloc(gs->s, l);
+			gs->len = l;
+		}
+		strcat(gs->s, s);
+	}
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+	va_list ap;
+	char s[10000]; /* big enough... */
+	va_start(ap, fmt);
+	vsnprintf(s, sizeof(s), fmt, ap);
+	str_append(gs, s);
+	va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+	return gs->s;
+}
+
+void *xmalloc(size_t size)
+{
+	void *p = malloc(size);
+	if (p)
+		return p;
+	fprintf(stderr, "Out of memory.\n");
+	exit(1);
+}
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+	void *p = calloc(nmemb, size);
+	if (p)
+		return p;
+	fprintf(stderr, "Out of memory.\n");
+	exit(1);
+}
diff --git a/scripts/config/zconf.gperf b/scripts/config/zconf.gperf
new file mode 100644
index 0000000000..1a5c6728ed
--- /dev/null
+++ b/scripts/config/zconf.gperf
@@ -0,0 +1,49 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+
+%%
+mainmenu,	T_MAINMENU,	TF_COMMAND
+menu,		T_MENU,		TF_COMMAND
+endmenu,	T_ENDMENU,	TF_COMMAND
+source,		T_SOURCE,	TF_COMMAND
+choice,		T_CHOICE,	TF_COMMAND
+endchoice,	T_ENDCHOICE,	TF_COMMAND
+comment,	T_COMMENT,	TF_COMMAND
+config,		T_CONFIG,	TF_COMMAND
+menuconfig,	T_MENUCONFIG,	TF_COMMAND
+help,		T_HELP,		TF_COMMAND
+---help---,	T_HELP,		TF_COMMAND
+if,		T_IF,		TF_COMMAND|TF_PARAM
+endif,		T_ENDIF,	TF_COMMAND
+depends,	T_DEPENDS,	TF_COMMAND
+optional,	T_OPTIONAL,	TF_COMMAND
+default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN
+prompt,		T_PROMPT,	TF_COMMAND
+tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE
+def_tristate,	T_DEFAULT,	TF_COMMAND, S_TRISTATE
+bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN
+boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN
+def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
+int,		T_TYPE,		TF_COMMAND, S_INT
+hex,		T_TYPE,		TF_COMMAND, S_HEX
+string,		T_TYPE,		TF_COMMAND, S_STRING
+select,		T_SELECT,	TF_COMMAND
+range,		T_RANGE,	TF_COMMAND
+visible,	T_VISIBLE,	TF_COMMAND
+option,		T_OPTION,	TF_COMMAND
+on,		T_ON,		TF_PARAM
+modules,	T_OPT_MODULES,	TF_OPTION
+defconfig_list,	T_OPT_DEFCONFIG_LIST,TF_OPTION
+env,		T_OPT_ENV,	TF_OPTION
+allnoconfig_y,	T_OPT_ALLNOCONFIG_Y,TF_OPTION
+reset,		T_RESET,	TF_COMMAND
+%%
diff --git a/scripts/config/zconf.hash.c_shipped b/scripts/config/zconf.hash.c_shipped
new file mode 100644
index 0000000000..2c6ae7be1c
--- /dev/null
+++ b/scripts/config/zconf.hash.c_shipped
@@ -0,0 +1,250 @@
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 47, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 10, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 20, 40,  5,
+       0,  0,  5, 49,  5, 20, 49, 49,  5, 20,
+       5,  0, 35, 49,  0, 15,  0, 10, 15, 49,
+      25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("env")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str20[sizeof("reset")];
+    char kconf_id_strings_str21[sizeof("string")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str26[sizeof("select")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str30[sizeof("---help---")];
+    char kconf_id_strings_str31[sizeof("source")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("hex")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str37[sizeof("visible")];
+    char kconf_id_strings_str38[sizeof("allnoconfig_y")];
+    char kconf_id_strings_str41[sizeof("prompt")];
+    char kconf_id_strings_str42[sizeof("depends")];
+    char kconf_id_strings_str44[sizeof("bool")];
+    char kconf_id_strings_str47[sizeof("boolean")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "endif",
+    "option",
+    "endmenu",
+    "optional",
+    "endchoice",
+    "range",
+    "choice",
+    "default",
+    "def_bool",
+    "help",
+    "config",
+    "def_tristate",
+    "env",
+    "defconfig_list",
+    "reset",
+    "string",
+    "if",
+    "int",
+    "select",
+    "modules",
+    "tristate",
+    "menu",
+    "---help---",
+    "source",
+    "comment",
+    "hex",
+    "menuconfig",
+    "visible",
+    "allnoconfig_y",
+    "prompt",
+    "depends",
+    "bool",
+    "boolean",
+    "mainmenu"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 35,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 48
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_OPTION,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_ENDMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_OPTIONAL,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_CHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,		T_HELP,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,		T_OPT_ENV,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,		T_RESET,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,		T_TYPE,		TF_COMMAND, S_INT},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str30,	T_HELP,		TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SOURCE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,		T_TYPE,		TF_COMMAND, S_HEX},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_VISIBLE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str38,	T_OPT_ALLNOCONFIG_Y,TF_OPTION},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_DEPENDS,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,	T_MAINMENU,	TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
diff --git a/scripts/config/zconf.l b/scripts/config/zconf.l
new file mode 100644
index 0000000000..44d895fb24
--- /dev/null
+++ b/scripts/config/zconf.l
@@ -0,0 +1,427 @@
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault perf-report perf-report
+%option noinput
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <glob.h>
+#include <libgen.h>
+
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+	struct buffer *parent;
+	YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+	text = xmalloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+	text = xmalloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+
+static void warn_ignored_character(char chr)
+{
+	fprintf(stderr,
+	        "%s:%d:warning: ignoring unsupported character '%c'\n",
+	        zconf_curname(), zconf_lineno(), chr);
+}
+%}
+
+n	[A-Za-z0-9_-]
+
+%%
+	int str = 0;
+	int ts, i;
+
+[ \t]*#.*\n	|
+[ \t]*\n	{
+	current_file->lineno++;
+	return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+	{
+	BEGIN(COMMAND);
+}
+
+.	{
+	unput(yytext[0]);
+	BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+	{n}+	{
+		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	.	warn_ignored_character(*yytext);
+	\n	{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+}
+
+<PARAM>{
+	"&&"	return T_AND;
+	"||"	return T_OR;
+	"("	return T_OPEN_PAREN;
+	")"	return T_CLOSE_PAREN;
+	"!"	return T_NOT;
+	"="	return T_EQUAL;
+	"!="	return T_UNEQUAL;
+	"<="	return T_LESS_EQUAL;
+	">="	return T_GREATER_EQUAL;
+	"<"	return T_LESS;
+	">"	return T_GREATER;
+	\"|\'	{
+		str = yytext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	({n}|[/.])+	{
+		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	#.*	/* comment */
+	\\\n	current_file->lineno++;
+	[[:blank:]]+
+	.	warn_ignored_character(*yytext);
+	<<EOF>> {
+		BEGIN(INITIAL);
+	}
+}
+
+<STRING>{
+	[^'"\\\n]+/\n	{
+		append_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	[^'"\\\n]+	{
+		append_string(yytext, yyleng);
+	}
+	\\.?/\n	{
+		append_string(yytext + 1, yyleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	\\.?	{
+		append_string(yytext + 1, yyleng - 1);
+	}
+	\'|\"	{
+		if (str == yytext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(yytext, 1);
+	}
+	\n	{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	<<EOF>>	{
+		BEGIN(INITIAL);
+	}
+}
+
+<HELP>{
+	[ \t]+	{
+		ts = 0;
+		for (i = 0; i < yyleng; i++) {
+			if (yytext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	[ \t]*\n/[^ \t\n] {
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	[ \t]*\n	{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	[^ \t\n].* {
+		while (yyleng) {
+			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+				break;
+			yyleng--;
+		}
+		append_string(yytext, yyleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	<<EOF>>	{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+}
+
+<<EOF>>	{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(yyin);
+	yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name != NULL && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	yyin = zconf_fopen(name);
+	if (!yyin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = xmalloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+}
+
+static void __zconf_nextfile(const char *name)
+{
+	struct file *iter;
+	struct file *file = file_lookup(name);
+	struct buffer *buf = xmalloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	yyin = zconf_fopen(file->name);
+	if (!yyin) {
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
+		exit(1);
+	}
+	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	for (iter = current_file->parent; iter; iter = iter->parent ) {
+		if (!strcmp(current_file->name,iter->name) ) {
+			printf("%s:%d: recursive inclusion detected. "
+			       "Inclusion path:\n  current file : '%s'\n",
+			       zconf_curname(), zconf_lineno(),
+			       zconf_curname());
+			iter = current_file->parent;
+			while (iter && \
+			       strcmp(iter->name,current_file->name)) {
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno-1);
+				iter = iter->parent;
+			}
+			if (iter)
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno+1);
+			exit(1);
+		}
+	}
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+void zconf_nextfile(const char *name)
+{
+	glob_t gl;
+	int err;
+	int i;
+	char path[PATH_MAX], *p;
+
+	err = glob(name, GLOB_ERR | GLOB_MARK, NULL, &gl);
+
+	/* ignore wildcard patterns that return no result */
+	if (err == GLOB_NOMATCH && strchr(name, '*')) {
+		err = 0;
+		gl.gl_pathc = 0;
+	}
+
+	if (err == GLOB_NOMATCH) {
+		p = strdup(current_file->name);
+		if (p) {
+			snprintf(path, sizeof(path), "%s/%s", dirname(p), name);
+			err = glob(path, GLOB_ERR | GLOB_MARK, NULL, &gl);
+			free(p);
+		}
+	}
+
+	if (err) {
+		const char *reason = "unknown error";
+
+		switch (err) {
+		case GLOB_NOSPACE:
+			reason = "out of memory";
+			break;
+		case GLOB_ABORTED:
+			reason = "read error";
+			break;
+		case GLOB_NOMATCH:
+			reason = "No files found";
+			break;
+		default:
+			break;
+		}
+
+		printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
+			reason, name);
+
+		exit(1);
+	}
+
+	for (i = 0; i < gl.gl_pathc; i++)
+		__zconf_nextfile(gl.gl_pathv[i]);
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(yyin);
+		yy_delete_buffer(YY_CURRENT_BUFFER);
+		yy_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}
diff --git a/scripts/config/zconf.lex.c_shipped b/scripts/config/zconf.lex.c_shipped
new file mode 100644
index 0000000000..f1d6528293
--- /dev/null
+++ b/scripts/config/zconf.lex.c_shipped
@@ -0,0 +1,2474 @@
+
+#line 3 "zconf.lex.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via zconfrestart()), so that the user can continue scanning by
+	 * just pointing zconfin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */
+yy_size_t zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file  );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  );
+void zconf_delete_buffer (YY_BUFFER_STATE b  );
+void zconf_flush_buffer (YY_BUFFER_STATE b  );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,yy_size_t len  );
+
+void *zconfalloc (yy_size_t  );
+void *zconfrealloc (void *,yy_size_t  );
+void zconffree (void *  );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        zconfensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+    {
+    {
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+    },
+
+    {
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
+
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+
+    },
+
+    {
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
+    },
+
+    {
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
+    },
+
+    {
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
+    },
+
+    {
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
+    },
+
+    {
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
+
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
+    },
+
+    {
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
+    },
+
+    {
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
+    },
+
+    {
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+
+    },
+
+    {
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
+    },
+
+    {
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
+    },
+
+    {
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
+    },
+
+    {
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
+
+    },
+
+    {
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
+    },
+
+    {
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
+    },
+
+    {
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
+    },
+
+    {
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
+    },
+
+    {
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
+
+    },
+
+    {
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+    },
+
+    {
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
+    },
+
+    {
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
+    },
+
+    {
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
+    },
+
+    {
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
+
+    },
+
+    {
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
+    },
+
+    {
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
+    },
+
+    {
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
+    },
+
+    {
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
+    },
+
+    {
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
+
+    },
+
+    {
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
+    },
+
+    {
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
+    },
+
+    {
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
+
+    },
+
+    {
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
+    },
+
+    {
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
+    },
+
+    {
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
+    },
+
+    {
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
+    },
+
+    {
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
+
+    },
+
+    {
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
+    },
+
+    {
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
+    },
+
+    {
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
+    },
+
+    {
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
+    },
+
+    {
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
+
+    },
+
+    {
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
+    },
+
+    {
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
+    },
+
+    {
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
+    },
+
+    {
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
+    },
+
+    {
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
+
+    },
+
+    {
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
+    },
+
+    } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	zconfleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[61] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    8,    9,
+       10,    1,    1,    1,   11,   12,   12,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,    1,    1,    1,
+       14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
+
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+#define YY_NO_INPUT 1
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <glob.h>
+#include <libgen.h>
+
+#include "lkc.h"
+
+#define START_STRSIZE	16
+
+static struct {
+	struct file *file;
+	int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+	struct buffer *parent;
+	YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+	text = xmalloc(START_STRSIZE);
+	text_asize = START_STRSIZE;
+	text_size = 0;
+	*text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+	int new_size = text_size + size + 1;
+	if (new_size > text_asize) {
+		new_size += START_STRSIZE - 1;
+		new_size &= -START_STRSIZE;
+		text = realloc(text, new_size);
+		text_asize = new_size;
+	}
+	memcpy(text + text_size, str, size);
+	text_size += size;
+	text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+	text = xmalloc(size + 1);
+	memcpy(text, str, size);
+	text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int zconflex_destroy (void );
+
+int zconfget_debug (void );
+
+void zconfset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE zconfget_extra (void );
+
+void zconfset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *zconfget_in (void );
+
+void zconfset_in  (FILE * in_str  );
+
+FILE *zconfget_out (void );
+
+void zconfset_out  (FILE * out_str  );
+
+yy_size_t zconfget_leng (void );
+
+char *zconfget_text (void );
+
+int zconfget_lineno (void );
+
+void zconfset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  );
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	errno=0; \
+	while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+	{ \
+		if( errno != EINTR) \
+		{ \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+			break; \
+		} \
+		errno=0; \
+		clearerr(zconfin); \
+	}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+    
+	int str = 0;
+	int ts, i;
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! zconfin )
+			zconfin = stdin;
+
+		if ( ! zconfout )
+			zconfout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			zconfensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				zconf_create_buffer(zconfin,YY_BUF_SIZE );
+		}
+
+		zconf_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of zconftext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
+			++yy_cp;
+
+		yy_current_state = -yy_current_state;
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+	current_file->lineno++;
+	return T_EOL;
+}
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+	unput(zconftext[0]);
+	BEGIN(COMMAND);
+}
+	YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		BEGIN(PARAM);
+		current_pos.file = current_file;
+		current_pos.lineno = current_file->lineno;
+		if (id && id->flags & TF_COMMAND) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+	YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+		BEGIN(INITIAL);
+		current_file->lineno++;
+		return T_EOL;
+	}
+	YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+		str = zconftext[0];
+		new_string();
+		BEGIN(STRING);
+	}
+	YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		if (id && id->flags & TF_PARAM) {
+			zconflval.id = id;
+			return id->token;
+		}
+		alloc_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD;
+	}
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+	YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+	YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+		append_string(zconftext, zconfleng);
+	}
+	YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+		zconflval.string = text;
+		return T_WORD_QUOTE;
+	}
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+		append_string(zconftext + 1, zconfleng - 1);
+	}
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+		if (str == zconftext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_WORD_QUOTE;
+		} else
+			append_string(zconftext, 1);
+	}
+	YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		current_file->lineno++;
+		BEGIN(INITIAL);
+		return T_EOL;
+	}
+	YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+		ts = 0;
+		for (i = 0; i < zconfleng; i++) {
+			if (zconftext[i] == '\t')
+				ts = (ts & ~7) + 8;
+			else
+				ts++;
+		}
+		last_ts = ts;
+		if (first_ts) {
+			if (ts < first_ts) {
+				zconf_endhelp();
+				return T_HELPTEXT;
+			}
+			ts -= first_ts;
+			while (ts > 8) {
+				append_string("        ", 8);
+				ts -= 8;
+			}
+			append_string("        ", ts);
+		}
+	}
+	YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+		current_file->lineno++;
+		append_string("\n", 1);
+	}
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+		while (zconfleng) {
+			if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+				break;
+			zconfleng--;
+		}
+		append_string(zconftext, zconfleng);
+		if (!first_ts)
+			first_ts = last_ts;
+	}
+	YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+		zconf_endhelp();
+		return T_HELPTEXT;
+	}
+	YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+	if (current_file) {
+		zconf_endfile();
+		return T_EOL;
+	}
+	fclose(zconfin);
+	yyterminate();
+}
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+	YY_BREAK
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed zconfin at a new source and called
+			 * zconflex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( zconfwrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * zconftext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	register char *source = (yytext_ptr);
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			zconfrestart(zconfin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	register int yy_is_jam;
+    
+	yy_current_state = yy_nxt[yy_current_state][1];
+	yy_is_jam = (yy_current_state <= 0);
+
+		return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp )
+{
+	register char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up zconftext */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register yy_size_t number_to_move = (yy_n_chars) + 2;
+		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		register char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					zconfrestart(zconfin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( zconfwrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve zconftext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void zconfrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        zconfensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            zconf_create_buffer(zconfin,YY_BUF_SIZE );
+	}
+
+	zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+	zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		zconfpop_buffer_state();
+	 *		zconfpush_buffer_state(new_buffer);
+     */
+	zconfensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	zconf_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (zconfwrap()) processing, but the only time this flag
+	 * is looked at is after zconfwrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	zconf_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ * 
+ */
+    void zconf_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		zconffree((void *) b->yy_ch_buf  );
+
+	zconffree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	zconf_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then zconf_init_buffer was _probably_
+     * called from zconfrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void zconf_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	zconfensure_buffer_stack();
+
+	/* This block is copied from zconf_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from zconf_switch_to_buffer. */
+	zconf_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void zconfpop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	zconf_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		zconf_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+	yy_size_t num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	zconf_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+    
+	return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) zconfalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = zconf_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up zconftext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		zconftext[zconfleng] = (yy_hold_char); \
+		(yy_c_buf_p) = zconftext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		zconfleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int zconfget_lineno  (void)
+{
+        
+    return zconflineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *zconfget_in  (void)
+{
+        return zconfin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *zconfget_out  (void)
+{
+        return zconfout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+yy_size_t zconfget_leng  (void)
+{
+        return zconfleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *zconfget_text  (void)
+{
+        return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void zconfset_lineno (int  line_number )
+{
+    
+    zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE *  in_str )
+{
+        zconfin = in_str ;
+}
+
+void zconfset_out (FILE *  out_str )
+{
+        zconfout = out_str ;
+}
+
+int zconfget_debug  (void)
+{
+        return zconf_flex_debug;
+}
+
+void zconfset_debug (int  bdebug )
+{
+        zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		zconf_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		zconfpop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	zconffree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *zconfrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+	free( (char *) ptr );	/* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+	new_string();
+	last_ts = first_ts = 0;
+	BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+	zconflval.string = text;
+	BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+	char *env, fullname[PATH_MAX+1];
+	FILE *f;
+
+	f = fopen(name, "r");
+	if (!f && name != NULL && name[0] != '/') {
+		env = getenv(SRCTREE);
+		if (env) {
+			sprintf(fullname, "%s/%s", env, name);
+			f = fopen(fullname, "r");
+		}
+	}
+	return f;
+}
+
+void zconf_initscan(const char *name)
+{
+	zconfin = zconf_fopen(name);
+	if (!zconfin) {
+		printf("can't find file %s\n", name);
+		exit(1);
+	}
+
+	current_buf = xmalloc(sizeof(*current_buf));
+	memset(current_buf, 0, sizeof(*current_buf));
+
+	current_file = file_lookup(name);
+	current_file->lineno = 1;
+}
+
+static void __zconf_nextfile(const char *name)
+{
+	struct file *iter;
+	struct file *file = file_lookup(name);
+	struct buffer *buf = xmalloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
+
+	current_buf->state = YY_CURRENT_BUFFER;
+	zconfin = zconf_fopen(file->name);
+	if (!zconfin) {
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
+		exit(1);
+	}
+	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	for (iter = current_file->parent; iter; iter = iter->parent ) {
+		if (!strcmp(current_file->name,iter->name) ) {
+			printf("%s:%d: recursive inclusion detected. "
+			       "Inclusion path:\n  current file : '%s'\n",
+			       zconf_curname(), zconf_lineno(),
+			       zconf_curname());
+			iter = current_file->parent;
+			while (iter && \
+			       strcmp(iter->name,current_file->name)) {
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno-1);
+				iter = iter->parent;
+			}
+			if (iter)
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno+1);
+			exit(1);
+		}
+	}
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
+
+void zconf_nextfile(const char *name)
+{
+	glob_t gl;
+	int err;
+	int i;
+	char path[PATH_MAX], *p;
+
+	err = glob(name, GLOB_ERR | GLOB_MARK, NULL, &gl);
+
+	/* ignore wildcard patterns that return no result */
+	if (err == GLOB_NOMATCH && strchr(name, '*')) {
+		err = 0;
+		gl.gl_pathc = 0;
+	}
+
+	if (err == GLOB_NOMATCH) {
+		p = strdup(current_file->name);
+		if (p) {
+			snprintf(path, sizeof(path), "%s/%s", dirname(p), name);
+			err = glob(path, GLOB_ERR | GLOB_MARK, NULL, &gl);
+			free(p);
+		}
+	}
+
+	if (err) {
+		const char *reason = "unknown error";
+
+		switch (err) {
+		case GLOB_NOSPACE:
+			reason = "out of memory";
+			break;
+		case GLOB_ABORTED:
+			reason = "read error";
+			break;
+		case GLOB_NOMATCH:
+			reason = "No files found";
+			break;
+		default:
+			break;
+		}
+
+		printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
+			reason, name);
+
+		exit(1);
+	}
+
+	for (i = 0; i < gl.gl_pathc; i++)
+		__zconf_nextfile(gl.gl_pathv[i]);
+}
+
+static void zconf_endfile(void)
+{
+	struct buffer *parent;
+
+	current_file = current_file->parent;
+
+	parent = current_buf->parent;
+	if (parent) {
+		fclose(zconfin);
+		zconf_delete_buffer(YY_CURRENT_BUFFER);
+		zconf_switch_to_buffer(parent->state);
+	}
+	free(current_buf);
+	current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+	return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+	return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/scripts/config/zconf.tab.c_shipped b/scripts/config/zconf.tab.c_shipped
new file mode 100644
index 0000000000..52c9d40a05
--- /dev/null
+++ b/scripts/config/zconf.tab.c_shipped
@@ -0,0 +1,2478 @@
+/* A Bison parser, made by GNU Bison 3.0.4.  */
+
+/* Bison implementation for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "3.0.4"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names.  */
+#define yyparse         zconfparse
+#define yylex           zconflex
+#define yyerror         zconferror
+#define yydebug         zconfdebug
+#define yynerrs         zconfnerrs
+
+#define yylval          zconflval
+#define yychar          zconfchar
+
+/* Copy the first part of user declarations.  */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+
+
+
+# ifndef YY_NULLPTR
+#  if defined __cplusplus && 201103L <= __cplusplus
+#   define YY_NULLPTR nullptr
+#  else
+#   define YY_NULLPTR 0
+#  endif
+# endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int zconfdebug;
+#endif
+
+/* Token type.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    T_MAINMENU = 258,
+    T_MENU = 259,
+    T_ENDMENU = 260,
+    T_SOURCE = 261,
+    T_CHOICE = 262,
+    T_ENDCHOICE = 263,
+    T_COMMENT = 264,
+    T_CONFIG = 265,
+    T_MENUCONFIG = 266,
+    T_HELP = 267,
+    T_HELPTEXT = 268,
+    T_IF = 269,
+    T_ENDIF = 270,
+    T_DEPENDS = 271,
+    T_OPTIONAL = 272,
+    T_PROMPT = 273,
+    T_TYPE = 274,
+    T_DEFAULT = 275,
+    T_SELECT = 276,
+    T_RANGE = 277,
+    T_VISIBLE = 278,
+    T_OPTION = 279,
+    T_ON = 280,
+    T_RESET = 281,
+    T_WORD = 282,
+    T_WORD_QUOTE = 283,
+    T_UNEQUAL = 284,
+    T_LESS = 285,
+    T_LESS_EQUAL = 286,
+    T_GREATER = 287,
+    T_GREATER_EQUAL = 288,
+    T_CLOSE_PAREN = 289,
+    T_OPEN_PAREN = 290,
+    T_EOL = 291,
+    T_OR = 292,
+    T_AND = 293,
+    T_EQUAL = 294,
+    T_NOT = 295
+  };
+#endif
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+union YYSTYPE
+{
+
+
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	const struct kconf_id *id;
+
+
+};
+
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE zconflval;
+
+int zconfparse (void);
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+#  define _Noreturn __declspec (noreturn)
+# else
+#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+             && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  11
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   313
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  41
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  50
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  125
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  205
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+   by yylex, with out-of-bounds checking.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   295
+
+#define YYTRANSLATE(YYX)                                                \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, without out-of-bounds checking.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40
+};
+
+#if YYDEBUG
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   109,   109,   109,   111,   111,   113,   115,   116,   117,
+     118,   119,   120,   124,   128,   128,   128,   128,   128,   128,
+     128,   128,   128,   132,   133,   134,   135,   136,   137,   141,
+     142,   148,   156,   162,   170,   180,   182,   183,   184,   185,
+     186,   187,   190,   198,   204,   214,   220,   226,   229,   231,
+     242,   243,   248,   257,   262,   270,   273,   275,   276,   277,
+     278,   279,   282,   288,   299,   305,   310,   320,   322,   327,
+     335,   343,   346,   348,   349,   350,   355,   362,   369,   374,
+     382,   385,   387,   388,   389,   392,   400,   407,   414,   420,
+     427,   429,   430,   431,   434,   438,   446,   448,   449,   452,
+     459,   461,   466,   467,   470,   471,   472,   476,   477,   480,
+     481,   484,   485,   486,   487,   488,   489,   490,   491,   492,
+     493,   494,   497,   498,   501,   502
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+  "T_VISIBLE", "T_OPTION", "T_ON", "T_RESET", "T_WORD", "T_WORD_QUOTE",
+  "T_UNEQUAL", "T_LESS", "T_LESS_EQUAL", "T_GREATER", "T_GREATER_EQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "start", "stmt_list", "option_name",
+  "common_stmt", "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "choice", "choice_entry", "choice_end",
+  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+  "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu",
+  "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt",
+  "comment", "comment_stmt", "help_start", "help", "depends_list",
+  "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt",
+  "end", "nl", "if_expr", "expr", "symbol", "word_opt", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295
+};
+# endif
+
+#define YYPACT_NINF -119
+
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-119)))
+
+#define YYTABLE_NINF -88
+
+#define yytable_value_is_error(Yytable_value) \
+  0
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int16 yypact[] =
+{
+       6,    44,  -119,    13,  -119,   173,  -119,    19,  -119,  -119,
+      -9,  -119,     5,    44,    21,    44,     9,    29,    44,    41,
+      48,    62,    56,  -119,  -119,  -119,  -119,  -119,  -119,  -119,
+    -119,  -119,    79,  -119,    95,  -119,  -119,  -119,  -119,  -119,
+    -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,
+    -119,  -119,   206,  -119,  -119,    64,  -119,    67,  -119,    69,
+    -119,   105,  -119,   116,   128,   140,  -119,  -119,    62,    62,
+      98,   266,  -119,   149,   150,   106,   139,   253,    73,    24,
+      22,    24,   230,  -119,  -119,  -119,  -119,  -119,  -119,    57,
+    -119,    62,    62,    64,    58,    58,    58,    58,    58,    58,
+    -119,  -119,   161,   165,    34,    44,    44,    62,   104,    58,
+    -119,   201,  -119,  -119,  -119,  -119,   190,  -119,  -119,   168,
+      44,    44,   178,   194,  -119,  -119,  -119,  -119,  -119,  -119,
+    -119,  -119,  -119,  -119,  -119,  -119,  -119,   194,  -119,   277,
+    -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,
+     180,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,
+      62,   131,   194,   183,   194,    12,   194,    58,    16,   207,
+    -119,  -119,   194,   219,   194,    62,   224,  -119,   134,  -119,
+     238,  -119,  -119,   239,   240,   194,   251,  -119,  -119,   241,
+    -119,   258,   100,  -119,  -119,  -119,  -119,  -119,   264,    44,
+    -119,  -119,  -119,  -119,  -119
+};
+
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       6,     0,   107,     0,     3,     0,     6,     6,   102,   103,
+       0,     1,     0,     0,     0,     0,   124,     0,     0,     0,
+       0,     0,     0,    14,    18,    15,    16,    20,    17,    19,
+      21,    22,     0,    23,     0,     7,    35,    26,    35,    27,
+      56,    67,     8,    72,    24,    96,    81,     9,    28,    90,
+      25,    10,     0,   108,     2,    76,    13,     0,   104,     0,
+     125,     0,   105,     0,     0,     0,   122,   123,     0,     0,
+       0,   111,   106,     0,     0,     0,     0,     0,     0,     0,
+      90,     0,     0,    77,    85,    52,    86,    31,    33,     0,
+     119,     0,     0,    69,     0,     0,     0,     0,     0,     0,
+      11,    12,     0,     0,     0,     0,   100,     0,     0,     0,
+      48,     0,    41,    40,    36,    37,     0,    39,    38,     0,
+       0,   100,     0,   109,    60,    61,    57,    59,    58,    68,
+      55,    54,    73,    75,    71,    74,    70,   109,    98,     0,
+      97,    82,    84,    80,    83,    79,    92,    93,    91,   118,
+     120,   121,   117,   112,   113,   114,   115,   116,    30,    88,
+       0,     0,   109,     0,   109,   109,   109,     0,     0,     0,
+      89,    64,   109,     0,   109,     0,     0,    99,     0,    95,
+       0,    42,   101,     0,     0,   109,    50,    47,    29,     0,
+      63,     0,   110,    65,    94,    43,    44,    45,     0,     0,
+      49,    62,    66,    46,    51
+};
+
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -119,  -119,   294,   296,  -119,   -15,   -66,  -119,  -119,  -119,
+    -119,   265,  -119,  -119,  -119,  -119,  -119,  -119,  -119,   -58,
+    -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,  -119,
+    -119,   -28,  -119,  -119,  -119,  -119,  -119,   229,   227,   -62,
+    -119,  -119,   187,    -1,    20,     0,  -118,   -67,   -91,  -119
+};
+
+  /* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     3,     4,     5,    34,    35,   113,    36,    37,    38,
+      39,    75,   114,   115,   168,   200,    40,    41,   130,    42,
+      77,   126,    78,    43,   134,    44,    79,     6,    45,    46,
+     143,    47,    81,    48,    49,    50,   116,   117,    82,   118,
+      80,   140,   163,   164,    51,     7,   176,    70,    71,    61
+};
+
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
+static const yytype_int16 yytable[] =
+{
+      10,    89,    90,   152,   153,   154,   155,   156,   157,     1,
+      55,   125,    57,    11,    59,   128,   147,    63,   167,   177,
+     148,   133,     1,   142,   150,   151,   175,     2,    13,    14,
+      15,    16,    17,    18,    19,    20,    60,   161,    21,    22,
+     165,    56,     2,   186,   180,   137,   182,   183,   184,    91,
+      92,   135,   187,   144,   189,    53,   191,    58,   138,   160,
+      33,    66,    67,   129,   132,    62,   141,   198,    64,    68,
+      93,     8,     9,   147,    69,    65,   185,   148,    14,    15,
+      73,    17,    18,    19,    20,    66,    67,    21,    22,    66,
+      67,   149,    72,   178,    91,    92,    74,    68,   131,   136,
+      53,   145,    69,    83,   162,    84,   -32,   102,   192,    33,
+     -32,   -32,   -32,   -32,   -32,   -32,   -32,   -32,   103,   172,
+     -32,   -32,   104,   -32,   105,   106,   107,   108,   109,   -32,
+     110,   166,   -32,   111,     2,    91,    92,    91,    92,   -34,
+     102,    85,   112,   -34,   -34,   -34,   -34,   -34,   -34,   -34,
+     -34,   103,    86,   -34,   -34,   104,   -34,   105,   106,   107,
+     108,   109,   -34,   110,    87,   -34,   111,   179,    91,    92,
+     194,    91,    92,    -5,    12,   112,    88,    13,    14,    15,
+      16,    17,    18,    19,    20,   100,   101,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,   158,   204,    31,
+      32,   159,   169,   170,   171,   174,    -4,    12,   175,    33,
+      13,    14,    15,    16,    17,    18,    19,    20,    92,   181,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+     -87,   102,    31,    32,   -87,   -87,   -87,   -87,   -87,   -87,
+     -87,   -87,    33,   188,   -87,   -87,   104,   -87,   -87,   -87,
+     -87,   -87,   -87,   -87,   102,   190,   -87,   111,   -53,   -53,
+     193,   -53,   -53,   -53,   -53,   103,   146,   -53,   -53,   104,
+     119,   120,   121,   122,   195,   196,   197,   201,   102,   123,
+     111,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   124,
+     199,   -78,   -78,   104,   202,    94,    95,    96,    97,    98,
+     203,    54,    52,    76,   111,    99,   127,   139,   173,     0,
+       0,     0,     0,   146
+};
+
+static const yytype_int16 yycheck[] =
+{
+       1,    68,    69,    94,    95,    96,    97,    98,    99,     3,
+      10,    77,    13,     0,    15,    77,    82,    18,   109,   137,
+      82,    79,     3,    81,    91,    92,    14,    36,     4,     5,
+       6,     7,     8,     9,    10,    11,    27,   104,    14,    15,
+     107,    36,    36,    27,   162,    23,   164,   165,   166,    37,
+      38,    79,    36,    81,   172,    36,   174,    36,    36,    25,
+      36,    27,    28,    78,    79,    36,    81,   185,    27,    35,
+      70,    27,    28,   139,    40,    27,   167,   139,     5,     6,
+       1,     8,     9,    10,    11,    27,    28,    14,    15,    27,
+      28,    34,    36,   160,    37,    38,     1,    35,    78,    79,
+      36,    81,    40,    36,   105,    36,     0,     1,   175,    36,
+       4,     5,     6,     7,     8,     9,    10,    11,    12,   120,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    27,    26,    27,    36,    37,    38,    37,    38,     0,
+       1,    36,    36,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    36,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    36,    26,    27,    36,    37,    38,
+      36,    37,    38,     0,     1,    36,    36,     4,     5,     6,
+       7,     8,     9,    10,    11,    36,    36,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    36,   199,    26,
+      27,    36,     1,    13,    36,    27,     0,     1,    14,    36,
+       4,     5,     6,     7,     8,     9,    10,    11,    38,    36,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+       0,     1,    26,    27,     4,     5,     6,     7,     8,     9,
+      10,    11,    36,    36,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,     1,    36,    26,    27,     5,     6,
+      36,     8,     9,    10,    11,    12,    36,    14,    15,    16,
+      17,    18,    19,    20,    36,    36,    36,    36,     1,    26,
+      27,     4,     5,     6,     7,     8,     9,    10,    11,    36,
+      39,    14,    15,    16,    36,    29,    30,    31,    32,    33,
+      36,     7,     6,    38,    27,    39,    77,    80,   121,    -1,
+      -1,    -1,    -1,    36
+};
+
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,     3,    36,    42,    43,    44,    68,    86,    27,    28,
+      84,     0,     1,     4,     5,     6,     7,     8,     9,    10,
+      11,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    26,    27,    36,    45,    46,    48,    49,    50,    51,
+      57,    58,    60,    64,    66,    69,    70,    72,    74,    75,
+      76,    85,    44,    36,    43,    86,    36,    84,    36,    84,
+      27,    90,    36,    84,    27,    27,    27,    28,    35,    40,
+      88,    89,    36,     1,     1,    52,    52,    61,    63,    67,
+      81,    73,    79,    36,    36,    36,    36,    36,    36,    88,
+      88,    37,    38,    86,    29,    30,    31,    32,    33,    39,
+      36,    36,     1,    12,    16,    18,    19,    20,    21,    22,
+      24,    27,    36,    47,    53,    54,    77,    78,    80,    17,
+      18,    19,    20,    26,    36,    47,    62,    78,    80,    46,
+      59,    85,    46,    60,    65,    72,    85,    23,    36,    79,
+      82,    46,    60,    71,    72,    85,    36,    47,    80,    34,
+      88,    88,    89,    89,    89,    89,    89,    89,    36,    36,
+      25,    88,    84,    83,    84,    88,    27,    89,    55,     1,
+      13,    36,    84,    83,    27,    14,    87,    87,    88,    36,
+      87,    36,    87,    87,    87,    89,    27,    36,    36,    87,
+      36,    87,    88,    36,    36,    36,    36,    36,    87,    39,
+      56,    36,    36,    36,    84
+};
+
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    41,    42,    42,    43,    43,    44,    44,    44,    44,
+      44,    44,    44,    44,    45,    45,    45,    45,    45,    45,
+      45,    45,    45,    46,    46,    46,    46,    46,    46,    47,
+      47,    48,    49,    50,    51,    52,    52,    52,    52,    52,
+      52,    52,    53,    53,    53,    53,    53,    54,    55,    55,
+      56,    56,    57,    58,    59,    60,    61,    61,    61,    61,
+      61,    61,    62,    62,    62,    62,    62,    63,    63,    64,
+      65,    66,    67,    67,    67,    67,    68,    69,    70,    71,
+      72,    73,    73,    73,    73,    74,    75,    76,    77,    78,
+      79,    79,    79,    79,    80,    80,    81,    81,    81,    82,
+      83,    83,    84,    84,    85,    85,    85,    86,    86,    87,
+      87,    88,    88,    88,    88,    88,    88,    88,    88,    88,
+      88,    88,    89,    89,    90,    90
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     2,     1,     2,     1,     0,     2,     2,     2,
+       2,     4,     4,     3,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     3,
+       2,     3,     2,     3,     2,     0,     2,     2,     2,     2,
+       2,     2,     3,     4,     4,     4,     5,     3,     0,     3,
+       0,     2,     3,     2,     1,     3,     0,     2,     2,     2,
+       2,     2,     4,     3,     2,     3,     4,     0,     2,     3,
+       1,     3,     0,     2,     2,     2,     3,     3,     3,     1,
+       3,     0,     2,     2,     2,     3,     3,     2,     2,     2,
+       0,     2,     2,     2,     4,     3,     0,     2,     2,     2,
+       0,     2,     1,     1,     2,     2,     2,     1,     2,     0,
+       2,     1,     3,     3,     3,     3,     3,     3,     3,     2,
+       3,     3,     1,     1,     0,     1
+};
+
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY)                                        \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      YYPOPSTACK (yylen);                                       \
+      yystate = *yyssp;                                         \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
+
+/* Error token number */
+#define YYTERROR        1
+#define YYERRCODE       256
+
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT.  |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+  YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+  YYFPRINTF (yyoutput, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
+{
+  unsigned long int yylno = yyrline[yyrule];
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+             yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &(yyvsp[(yyi + 1) - (yynrhs)])
+                                              );
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            /* Fall through.  */
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
+    {
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                {
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+                  if (! (yysize <= yysize1
+                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  yysize = yysize1;
+                }
+              }
+        }
+    }
+
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
+
+  {
+    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    yysize = yysize1;
+  }
+
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
+    }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+{
+  YYUSE (yyvaluep);
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  switch (yytype)
+    {
+          case 58: /* choice_entry  */
+
+      {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
+	if (current_menu == ((*yyvaluep).menu))
+		menu_end_menu();
+}
+
+        break;
+
+    case 64: /* if_entry  */
+
+      {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
+	if (current_menu == ((*yyvaluep).menu))
+		menu_end_menu();
+}
+
+        break;
+
+    case 70: /* menu_entry  */
+
+      {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
+	if (current_menu == ((*yyvaluep).menu))
+		menu_end_menu();
+}
+
+        break;
+
+
+      default:
+        break;
+    }
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+int
+yyparse (void)
+{
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       'yyss': related to states.
+       'yyvs': related to semantic values.
+
+       Refer to the stacks through separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yyssp = yyss = yyssa;
+  yyvsp = yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        yytype_int16 *yyss1 = yyss;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yystacksize);
+
+        yyss = yyss1;
+        yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = yylex ();
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     '$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 10:
+
+    { zconf_error("unexpected end statement"); }
+
+    break;
+
+  case 11:
+
+    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); }
+
+    break;
+
+  case 12:
+
+    {
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name);
+}
+
+    break;
+
+  case 13:
+
+    { zconf_error("invalid statement"); }
+
+    break;
+
+  case 29:
+
+    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); }
+
+    break;
+
+  case 30:
+
+    { zconf_error("invalid option"); }
+
+    break;
+
+  case 31:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+}
+
+    break;
+
+  case 32:
+
+    {
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 33:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+}
+
+    break;
+
+  case 34:
+
+    {
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 42:
+
+    {
+	menu_set_type((yyvsp[-2].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[-2].id)->stype);
+}
+
+    break;
+
+  case 43:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 44:
+
+    {
+	menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
+	if ((yyvsp[-3].id)->stype != S_UNKNOWN)
+		menu_set_type((yyvsp[-3].id)->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		(yyvsp[-3].id)->stype);
+}
+
+    break;
+
+  case 45:
+
+    {
+	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 46:
+
+    {
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 49:
+
+    {
+	const struct kconf_id *id = kconf_id_lookup((yyvsp[-1].string), strlen((yyvsp[-1].string)));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, (yyvsp[0].string));
+	else
+		zconfprint("warning: ignoring unknown option %s", (yyvsp[-1].string));
+	free((yyvsp[-1].string));
+}
+
+    break;
+
+  case 50:
+
+    { (yyval.string) = NULL; }
+
+    break;
+
+  case 51:
+
+    { (yyval.string) = (yyvsp[0].string); }
+
+    break;
+
+  case 52:
+
+    {
+	struct symbol *sym = sym_lookup((yyvsp[-1].string), SYMBOL_CHOICE);
+	sym->flags |= SYMBOL_AUTO;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 53:
+
+    {
+	(yyval.menu) = menu_add_menu();
+}
+
+    break;
+
+  case 54:
+
+    {
+	if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+}
+
+    break;
+
+  case 62:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 63:
+
+    {
+	if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
+		menu_set_type((yyvsp[-2].id)->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			(yyvsp[-2].id)->stype);
+	} else
+		YYERROR;
+}
+
+    break;
+
+  case 64:
+
+    {
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 65:
+
+    {
+	menu_add_prop(P_RESET, NULL, NULL, (yyvsp[-1].expr));
+}
+
+    break;
+
+  case 66:
+
+    {
+	if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+}
+
+    break;
+
+  case 69:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep((yyvsp[-1].expr));
+	(yyval.menu) = menu_add_menu();
+}
+
+    break;
+
+  case 70:
+
+    {
+	if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+}
+
+    break;
+
+  case 76:
+
+    {
+	menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
+}
+
+    break;
+
+  case 77:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 78:
+
+    {
+	(yyval.menu) = menu_add_menu();
+}
+
+    break;
+
+  case 79:
+
+    {
+	if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+}
+
+    break;
+
+  case 85:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+	zconf_nextfile((yyvsp[-1].string));
+}
+
+    break;
+
+  case 86:
+
+    {
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 87:
+
+    {
+	menu_end_entry();
+}
+
+    break;
+
+  case 88:
+
+    {
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+}
+
+    break;
+
+  case 89:
+
+    {
+	current_entry->help = (yyvsp[0].string);
+}
+
+    break;
+
+  case 94:
+
+    {
+	menu_add_dep((yyvsp[-1].expr));
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+}
+
+    break;
+
+  case 95:
+
+    {
+	menu_add_dep((yyvsp[-1].expr));
+	zconfprint("warning: deprecated 'depends' syntax, use 'depends on' instead.");
+}
+
+    break;
+
+  case 99:
+
+    {
+	menu_add_visibility((yyvsp[0].expr));
+}
+
+    break;
+
+  case 101:
+
+    {
+	menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
+}
+
+    break;
+
+  case 104:
+
+    { (yyval.id) = (yyvsp[-1].id); }
+
+    break;
+
+  case 105:
+
+    { (yyval.id) = (yyvsp[-1].id); }
+
+    break;
+
+  case 106:
+
+    { (yyval.id) = (yyvsp[-1].id); }
+
+    break;
+
+  case 109:
+
+    { (yyval.expr) = NULL; }
+
+    break;
+
+  case 110:
+
+    { (yyval.expr) = (yyvsp[0].expr); }
+
+    break;
+
+  case 111:
+
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); }
+
+    break;
+
+  case 112:
+
+    { (yyval.expr) = expr_alloc_comp(E_LTH, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
+    break;
+
+  case 113:
+
+    { (yyval.expr) = expr_alloc_comp(E_LEQ, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
+    break;
+
+  case 114:
+
+    { (yyval.expr) = expr_alloc_comp(E_GTH, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
+    break;
+
+  case 115:
+
+    { (yyval.expr) = expr_alloc_comp(E_GEQ, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
+    break;
+
+  case 116:
+
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
+    break;
+
+  case 117:
+
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); }
+
+    break;
+
+  case 118:
+
+    { (yyval.expr) = (yyvsp[-1].expr); }
+
+    break;
+
+  case 119:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); }
+
+    break;
+
+  case 120:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); }
+
+    break;
+
+  case 121:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); }
+
+    break;
+
+  case 122:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); }
+
+    break;
+
+  case 123:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), SYMBOL_CONST); free((yyvsp[0].string)); }
+
+    break;
+
+  case 124:
+
+    { (yyval.string) = NULL; }
+
+    break;
+
+
+
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+  /* Now 'shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error.  |
+`--------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
+      {
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+         error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
+      else
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval);
+          yychar = YYEMPTY;
+        }
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+        YYABORT;
+
+
+      yydestruct ("Error: popping",
+                  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  return yyresult;
+}
+
+
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	_menu_init();
+	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym)
+		modules_sym = sym_find( "n" );
+
+	rootmenu.prompt->text = _(rootmenu.prompt->text);
+	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		if (sym_check_deps(sym))
+			zconfnerrs++;
+	}
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	case T_VISIBLE:		return "visible";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "\nchoice\n");
+	else
+		fprintf(out, "\nconfig %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		case P_SELECT:
+			fputs( "  select ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_RANGE:
+			fputs( "  range ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_MENU:
+			fputs( "  menu ", out);
+			print_quoted_string(out, prop->text);
+			fputc('\n', out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
+	}
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "zconf.lex.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/scripts/config/zconf.y b/scripts/config/zconf.y
new file mode 100644
index 0000000000..81645a75b0
--- /dev/null
+++ b/scripts/config/zconf.y
@@ -0,0 +1,754 @@
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD		0x0001
+#define DEBUG_PARSE	0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+%}
+%expect 30
+
+%union
+{
+	char *string;
+	struct file *file;
+	struct symbol *symbol;
+	struct expr *expr;
+	struct menu *menu;
+	const struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_VISIBLE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <id>T_RESET
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_LESS
+%token T_LESS_EQUAL
+%token T_GREATER
+%token T_GREATER_EQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
+
+%destructor {
+	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+		$$->file->name, $$->lineno);
+	if (current_menu == $$)
+		menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+%}
+
+%%
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
+
+stmt_list:
+	  /* empty */
+	| stmt_list common_stmt
+	| stmt_list choice_stmt
+	| stmt_list menu_stmt
+	| stmt_list end			{ zconf_error("unexpected end statement"); }
+	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
+	| stmt_list option_name error T_EOL
+{
+	zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+	| stmt_list error T_EOL		{ zconf_error("invalid statement"); }
+;
+
+option_name:
+	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE | T_RESET
+;
+
+common_stmt:
+	  T_EOL
+	| if_stmt
+	| comment_stmt
+	| config_stmt
+	| menuconfig_stmt
+	| source_stmt
+;
+
+option_error:
+	  T_WORD error T_EOL		{ zconf_error("unknown option \"%s\"", $1); }
+	| error T_EOL			{ zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+	struct symbol *sym = sym_lookup($2, 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+	struct symbol *sym = sym_lookup($2, 0);
+	sym->flags |= SYMBOL_OPTIONAL;
+	menu_add_entry(sym);
+	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+	if (current_entry->prompt)
+		current_entry->prompt->type = P_MENU;
+	else
+		zconfprint("warning: menuconfig statement without prompt");
+	menu_end_entry();
+	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+	  /* empty */
+	| config_option_list config_option
+	| config_option_list symbol_option
+	| config_option_list depends
+	| config_option_list help
+	| config_option_list option_error
+	| config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+	menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+	menu_add_prompt(P_PROMPT, $2, $3);
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+	menu_add_expr(P_DEFAULT, $2, $3);
+	if ($1->stype != S_UNKNOWN)
+		menu_set_type($1->stype);
+	printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+		zconf_curname(), zconf_lineno(),
+		$1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+	menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+	  /* empty */
+	| symbol_option_list T_WORD symbol_option_arg
+{
+	const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, $3);
+	else
+		zconfprint("warning: ignoring unknown option %s", $2);
+	free($2);
+};
+
+symbol_option_arg:
+	  /* empty */		{ $$ = NULL; }
+	| T_EQUAL prompt	{ $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE word_opt T_EOL
+{
+	struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+	sym->flags |= SYMBOL_AUTO;
+	menu_add_entry(sym);
+	menu_add_expr(P_CHOICE, NULL, NULL);
+	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+	$$ = menu_add_menu();
+};
+
+choice_end: end
+{
+	if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+	  /* empty */
+	| choice_option_list choice_option
+	| choice_option_list depends
+	| choice_option_list help
+	| choice_option_list T_EOL
+	| choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+	menu_add_prompt(P_PROMPT, $2, $3);
+	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+	if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+		menu_set_type($1->stype);
+		printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+			zconf_curname(), zconf_lineno(),
+			$1->stype);
+	} else
+		YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+	current_entry->sym->flags |= SYMBOL_OPTIONAL;
+	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_RESET if_expr T_EOL
+{
+	menu_add_prop(P_RESET, NULL, NULL, $2);
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+	if ($1->stype == S_UNKNOWN) {
+		menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+		printd(DEBUG_PARSE, "%s:%d:default\n",
+			zconf_curname(), zconf_lineno());
+	} else
+		YYERROR;
+};
+
+choice_block:
+	  /* empty */
+	| choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+	menu_add_entry(NULL);
+	menu_add_dep($2);
+	$$ = menu_add_menu();
+};
+
+if_end: end
+{
+	if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+	  /* empty */
+	| if_block common_stmt
+	| if_block menu_stmt
+	| if_block choice_stmt
+;
+
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+	menu_add_prompt(P_MENU, $2, NULL);
+};
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, $2, NULL);
+	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu visibility_list depends_list
+{
+	$$ = menu_add_menu();
+};
+
+menu_end: end
+{
+	if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+		menu_end_menu();
+		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+	}
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+	  /* empty */
+	| menu_block common_stmt
+	| menu_block menu_stmt
+	| menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+	zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+	menu_add_entry(NULL);
+	menu_add_prompt(P_COMMENT, $2, NULL);
+	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+	menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+	zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+	current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+	  /* empty */
+	| depends_list depends
+	| depends_list T_EOL
+	| depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+	menu_add_dep($3);
+	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+} | T_DEPENDS expr T_EOL
+{
+	menu_add_dep($2);
+	zconfprint("warning: deprecated 'depends' syntax, use 'depends on' instead.");
+};
+
+/* visibility option */
+
+visibility_list:
+	  /* empty */
+	| visibility_list visible
+	| visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+	menu_add_visibility($2);
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+	  /* empty */
+	| prompt if_expr
+{
+	menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt:	  T_WORD
+	| T_WORD_QUOTE
+;
+
+end:	  T_ENDMENU T_EOL	{ $$ = $1; }
+	| T_ENDCHOICE T_EOL	{ $$ = $1; }
+	| T_ENDIF T_EOL		{ $$ = $1; }
+;
+
+nl:
+	  T_EOL
+	| nl T_EOL
+;
+
+if_expr:  /* empty */			{ $$ = NULL; }
+	| T_IF expr			{ $$ = $2; }
+;
+
+expr:	  symbol				{ $$ = expr_alloc_symbol($1); }
+	| symbol T_LESS symbol			{ $$ = expr_alloc_comp(E_LTH, $1, $3); }
+	| symbol T_LESS_EQUAL symbol		{ $$ = expr_alloc_comp(E_LEQ, $1, $3); }
+	| symbol T_GREATER symbol		{ $$ = expr_alloc_comp(E_GTH, $1, $3); }
+	| symbol T_GREATER_EQUAL symbol		{ $$ = expr_alloc_comp(E_GEQ, $1, $3); }
+	| symbol T_EQUAL symbol			{ $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+	| symbol T_UNEQUAL symbol		{ $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+	| T_OPEN_PAREN expr T_CLOSE_PAREN	{ $$ = $2; }
+	| T_NOT expr				{ $$ = expr_alloc_one(E_NOT, $2); }
+	| expr T_OR expr			{ $$ = expr_alloc_two(E_OR, $1, $3); }
+	| expr T_AND expr			{ $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); }
+	| T_WORD_QUOTE	{ $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
+;
+
+word_opt: /* empty */			{ $$ = NULL; }
+	| T_WORD
+
+%%
+
+void conf_parse(const char *name)
+{
+	struct symbol *sym;
+	int i;
+
+	zconf_initscan(name);
+
+	sym_init();
+	_menu_init();
+	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+	if (getenv("ZCONF_DEBUG"))
+		zconfdebug = 1;
+#endif
+	zconfparse();
+	if (zconfnerrs)
+		exit(1);
+	if (!modules_sym)
+		modules_sym = sym_find( "n" );
+
+	rootmenu.prompt->text = _(rootmenu.prompt->text);
+	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+	menu_finalize(&rootmenu);
+	for_all_symbols(i, sym) {
+		if (sym_check_deps(sym))
+			zconfnerrs++;
+	}
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+	switch (token) {
+	case T_MENU:		return "menu";
+	case T_ENDMENU:		return "endmenu";
+	case T_CHOICE:		return "choice";
+	case T_ENDCHOICE:	return "endchoice";
+	case T_IF:		return "if";
+	case T_ENDIF:		return "endif";
+	case T_DEPENDS:		return "depends";
+	case T_VISIBLE:		return "visible";
+	}
+	return "<token>";
+}
+
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
+{
+	if (id->token != endtoken) {
+		zconf_error("unexpected '%s' within %s block",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	if (current_menu->file != current_file) {
+		zconf_error("'%s' in different file than '%s'",
+			kconf_id_strings + id->name, zconf_tokenname(starttoken));
+		fprintf(stderr, "%s:%d: location of the '%s'\n",
+			current_menu->file->name, current_menu->lineno,
+			zconf_tokenname(starttoken));
+		zconfnerrs++;
+		return false;
+	}
+	return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+	va_list ap;
+
+	zconfnerrs++;
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	va_start(ap, err);
+	vfprintf(stderr, err, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+	const char *p;
+	int len;
+
+	putc('"', out);
+	while ((p = strchr(str, '"'))) {
+		len = p - str;
+		if (len)
+			fprintf(out, "%.*s", len, str);
+		fputs("\\\"", out);
+		str = p + 1;
+	}
+	fputs(str, out);
+	putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+	struct symbol *sym = menu->sym;
+	struct property *prop;
+
+	if (sym_is_choice(sym))
+		fprintf(out, "\nchoice\n");
+	else
+		fprintf(out, "\nconfig %s\n", sym->name);
+	switch (sym->type) {
+	case S_BOOLEAN:
+		fputs("  boolean\n", out);
+		break;
+	case S_TRISTATE:
+		fputs("  tristate\n", out);
+		break;
+	case S_STRING:
+		fputs("  string\n", out);
+		break;
+	case S_INT:
+		fputs("  integer\n", out);
+		break;
+	case S_HEX:
+		fputs("  hex\n", out);
+		break;
+	default:
+		fputs("  ???\n", out);
+		break;
+	}
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu != menu)
+			continue;
+		switch (prop->type) {
+		case P_PROMPT:
+			fputs("  prompt ", out);
+			print_quoted_string(out, prop->text);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_DEFAULT:
+			fputs( "  default ", out);
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs(" if ", out);
+				expr_fprint(prop->visible.expr, out);
+			}
+			fputc('\n', out);
+			break;
+		case P_CHOICE:
+			fputs("  #choice value\n", out);
+			break;
+		case P_SELECT:
+			fputs( "  select ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_RANGE:
+			fputs( "  range ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_MENU:
+			fputs( "  menu ", out);
+			print_quoted_string(out, prop->text);
+			fputc('\n', out);
+			break;
+		default:
+			fprintf(out, "  unknown prop %d!\n", prop->type);
+			break;
+		}
+	}
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
+	}
+}
+
+void zconfdump(FILE *out)
+{
+	struct property *prop;
+	struct symbol *sym;
+	struct menu *menu;
+
+	menu = rootmenu.list;
+	while (menu) {
+		if ((sym = menu->sym))
+			print_symbol(out, menu);
+		else if ((prop = menu->prompt)) {
+			switch (prop->type) {
+			case P_COMMENT:
+				fputs("\ncomment ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			case P_MENU:
+				fputs("\nmenu ", out);
+				print_quoted_string(out, prop->text);
+				fputs("\n", out);
+				break;
+			default:
+				;
+			}
+			if (!expr_is_yes(prop->visible.expr)) {
+				fputs("  depends ", out);
+				expr_fprint(prop->visible.expr, out);
+				fputc('\n', out);
+			}
+		}
+
+		if (menu->list)
+			menu = menu->list;
+		else if (menu->next)
+			menu = menu->next;
+		else while ((menu = menu->parent)) {
+			if (menu->prompt && menu->prompt->type == P_MENU)
+				fputs("\nendmenu\n", out);
+			if (menu->next) {
+				menu = menu->next;
+				break;
+			}
+		}
+	}
+}
+
+#include "zconf.lex.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/scripts/deptest.sh b/scripts/deptest.sh
new file mode 100755
index 0000000000..03da9f568e
--- /dev/null
+++ b/scripts/deptest.sh
@@ -0,0 +1,211 @@
+#!/usr/bin/env bash
+#
+# Automated OpenWrt package dependency checker
+#
+# Copyright (C) 2009-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+SCRIPTDIR="$(dirname "$0")"
+[ "${SCRIPTDIR:0:1}" = "/" ] || SCRIPTDIR="$PWD/$SCRIPTDIR"
+BASEDIR="$SCRIPTDIR/.."
+
+DIR="$BASEDIR/tmp/deptest"
+STAMP_DIR_SUCCESS="$DIR/stamp-success"
+STAMP_DIR_FAILED="$DIR/stamp-failed"
+STAMP_DIR_BLACKLIST="$DIR/stamp-blacklist"
+BUILD_DIR="$DIR/build_dir/target"
+BUILD_DIR_HOST="$DIR/build_dir/host"
+KERNEL_BUILD_DIR="$DIR/build_dir/linux"
+STAGING_DIR="$DIR/staging_dir/target"
+STAGING_DIR_HOST="$DIR/staging_dir/host"
+STAGING_DIR_HOST_TMPL="$DIR/staging_dir_host_tmpl"
+BIN_DIR="$DIR/staging_dir/bin_dir"
+LOG_DIR_NAME="logs"
+LOG_DIR="$DIR/$LOG_DIR_NAME"
+
+die()
+{
+	echo "$@"
+	exit 1
+}
+
+usage()
+{
+	echo "deptest.sh [OPTIONS] [PACKAGES]"
+	echo
+	echo "OPTIONS:"
+	echo "  --lean       Run a lean test. Do not clean the build directory for each"
+	echo "               package test."
+	echo "  --force      Force a test, even if a success/blacklist stamp is available"
+	echo "  -j X         Number of make jobs"
+	echo
+	echo "PACKAGES are packages to test. If not specified, all installed packages"
+	echo "will be tested."
+}
+
+deptest_make()
+{
+	local target="$1"
+	shift
+	local logfile="$1"
+	shift
+	make -j$nrjobs "$target" \
+		BUILD_DIR="$BUILD_DIR" \
+		BUILD_DIR_HOST="$BUILD_DIR_HOST" \
+		KERNEL_BUILD_DIR="$KERNEL_BUILD_DIR" \
+		BIN_DIR="$BIN_DIR" \
+		STAGING_DIR="$STAGING_DIR" \
+		STAGING_DIR_HOST="$STAGING_DIR_HOST" \
+		FORCE_HOST_INSTALL=1 \
+		V=99 "$@" >"$LOG_DIR/$logfile" 2>&1
+}
+
+clean_kernel_build_dir()
+{
+	# delete everything, except the kernel build dir "linux-X.X.X"
+	(
+		cd "$KERNEL_BUILD_DIR" || die "Failed to enter kernel build dir"
+		for entry in *; do
+			[ -z "$(echo "$entry" | egrep -e '^linux-*.*.*$')" ] || continue
+			rm -rf "$entry" || die "Failed to clean kernel build dir"
+		done
+	)
+}
+
+stamp_exists() # $1=stamp
+{
+	[ -e "$1" -o -L "$1" ]
+}
+
+test_package() # $1=pkgname
+{
+	local pkg="$1"
+	[ -n "$pkg" -a -z "$(echo "$pkg" | grep -e '/')" -a "$pkg" != "." -a "$pkg" != ".." ] || \
+		die "Package name \"$pkg\" contains illegal characters"
+	local SELECTED=
+	for conf in `grep CONFIG_PACKAGE tmp/.packagedeps | grep -E "[ /]$pkg\$" | sed -e 's,package-$(\(CONFIG_PACKAGE_.*\)).*,\1,'`; do
+		grep "$conf=" .config > /dev/null && SELECTED=1 && break
+	done
+	local STAMP_SUCCESS="$STAMP_DIR_SUCCESS/$pkg"
+	local STAMP_FAILED="$STAMP_DIR_FAILED/$pkg"
+	local STAMP_BLACKLIST="$STAMP_DIR_BLACKLIST/$pkg"
+	rm -f "$STAMP_FAILED"
+	stamp_exists "$STAMP_SUCCESS" && [ $force -eq 0 ] && return
+	rm -f "$STAMP_SUCCESS"
+	[ -n "$SELECTED" ] || {
+		echo "Package $pkg is not selected"
+		return
+	}
+	stamp_exists "$STAMP_BLACKLIST" && [ $force -eq 0 ] && {
+		echo "Package $pkg is blacklisted"
+		return
+	}
+	echo "Testing package $pkg..."
+	rm -rf "$STAGING_DIR" "$STAGING_DIR_HOST"
+	mkdir -p "$STAGING_DIR"
+	cp -al "$STAGING_DIR_HOST_TMPL" "$STAGING_DIR_HOST"
+	[ $lean_test -eq 0 ] && {
+		rm -rf "$BUILD_DIR" "$BUILD_DIR_HOST"
+		clean_kernel_build_dir
+	}
+	mkdir -p "$BUILD_DIR" "$BUILD_DIR_HOST"
+	local logfile="$(basename $pkg).log"
+	deptest_make "package/$pkg/compile" "$logfile"
+	if [ $? -eq 0 ]; then
+		( cd "$STAMP_DIR_SUCCESS"; ln -s "../$LOG_DIR_NAME/$logfile" "./$pkg" )
+	else
+		( cd "$STAMP_DIR_FAILED"; ln -s "../$LOG_DIR_NAME/$logfile" "./$pkg" )
+		echo "Building package $pkg FAILED"
+	fi
+}
+
+# parse commandline options
+packages=
+lean_test=0
+force=0
+nrjobs=1
+while [ $# -ne 0 ]; do
+	case "$1" in
+	--help|-h)
+		usage
+		exit 0
+		;;
+	--lean)
+		lean_test=1
+		;;
+	--force)
+		force=1
+		;;
+	-j*)
+		if [ -n "${1:2}" ]; then
+			nrjobs="${1:2}"
+		else
+			shift
+			nrjobs="$1"
+		fi
+		;;
+	*)
+		packages="$packages $1"
+		;;
+	esac
+	shift
+done
+
+[ -f "$BASEDIR/include/toplevel.mk" ] || \
+	die "Error: Could not find buildsystem base directory"
+[ -f "$BASEDIR/.config" ] || \
+	die "The buildsystem is not configured. Please run make menuconfig."
+cd "$BASEDIR" || die "Failed to enter base directory"
+
+mkdir -p "$STAMP_DIR_SUCCESS" "$STAMP_DIR_FAILED" "$STAMP_DIR_BLACKLIST" \
+	"$BIN_DIR" "$LOG_DIR"
+
+bootstrap_deptest_make()
+{
+	local target="$1"
+	shift
+	local logfile="bootstrap-deptest-$(echo "$target" | tr / -).log"
+	echo "deptest-make $target"
+	deptest_make "$target" "$logfile" "$@" || \
+		die "make $target failed, please check $logfile"
+}
+
+bootstrap_native_make()
+{
+	local target="$1"
+	shift
+	local logfile="bootstrap-native-$(echo "$target" | tr / -).log"
+	echo "make $target"
+	make -j$nrjobs "$target" \
+		V=99 "$@" >"$LOG_DIR/$logfile" 2>&1 || \
+		die "make $target failed, please check $logfile"
+}
+
+[ -d "$STAGING_DIR_HOST_TMPL" ] || {
+	echo "Bootstrapping build environment..."
+	rm -rf "$STAGING_DIR" "$STAGING_DIR_HOST" "$BUILD_DIR" "$BUILD_DIR_HOST" "$KERNEL_BUILD_DIR"
+	mkdir -p "$STAGING_DIR" "$STAGING_DIR_HOST" \
+		"$BUILD_DIR" "$BUILD_DIR_HOST" "$KERNEL_BUILD_DIR"
+	bootstrap_native_make tools/install
+	bootstrap_native_make toolchain/install
+	bootstrap_deptest_make tools/install
+	bootstrap_deptest_make target/linux/install
+	cp -al "$STAGING_DIR_HOST" "$STAGING_DIR_HOST_TMPL"
+	rm -rf "$STAGING_DIR" "$STAGING_DIR_HOST" "$BUILD_DIR" "$BUILD_DIR_HOST"
+	echo "Build environment OK."
+}
+
+if [ -z "$packages" ]; then
+	# iterate over all packages
+	for pkg in `cat tmp/.packagedeps  | grep CONFIG_PACKAGE | grep -v curdir | sed -e 's,.*[/=]\s*,,' | sort -u`; do
+		test_package "$pkg"
+	done
+else
+	# only check the specified packages
+	for pkg in $packages; do
+		test_package "$pkg"
+	done
+fi
diff --git a/scripts/diffconfig.sh b/scripts/diffconfig.sh
new file mode 100755
index 0000000000..5f9fec5600
--- /dev/null
+++ b/scripts/diffconfig.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+grep \^CONFIG_TARGET_ .config | head -n3 > tmp/.diffconfig.head
+grep \^CONFIG_TARGET_DEVICE_ .config >> tmp/.diffconfig.head
+grep '^CONFIG_ALL=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_ALL_KMODS=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_ALL_NONSHARED=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_DEVEL=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_TOOLCHAINOPTS=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_BUSYBOX_CUSTOM=y' .config >> tmp/.diffconfig.head
+grep '^CONFIG_TARGET_PER_DEVICE_ROOTFS=y' .config >> tmp/.diffconfig.head
+./scripts/config/conf --defconfig=tmp/.diffconfig.head -w tmp/.diffconfig.stage1 Config.in >/dev/null
+./scripts/kconfig.pl '>+' tmp/.diffconfig.stage1 .config >> tmp/.diffconfig.head
+./scripts/config/conf --defconfig=tmp/.diffconfig.head -w tmp/.diffconfig.stage2 Config.in >/dev/null
+./scripts/kconfig.pl '>' tmp/.diffconfig.stage2 .config >> tmp/.diffconfig.head
+cat tmp/.diffconfig.head
+rm -f tmp/.diffconfig tmp/.diffconfig.head
diff --git a/scripts/dl_cleanup.py b/scripts/dl_cleanup.py
new file mode 100755
index 0000000000..d086761dc7
--- /dev/null
+++ b/scripts/dl_cleanup.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python3
+"""
+# OpenWrt download directory cleanup utility.
+# Delete all but the very last version of the program tarballs.
+#
+# Copyright (C) 2010-2015 Michael Buesch <m@bues.ch>
+# Copyright (C) 2013-2015 OpenWrt.org
+"""
+
+from __future__ import print_function
+
+import sys
+import os
+import re
+import getopt
+
+# Commandline options
+opt_dryrun = False
+
+
+def parseVer_1234(match, filepath):
+	progname = match.group(1)
+	progversion = (int(match.group(2)) << 64) |\
+		      (int(match.group(3)) << 48) |\
+		      (int(match.group(4)) << 32) |\
+		      (int(match.group(5)) << 16)
+	return (progname, progversion)
+
+def parseVer_123(match, filepath):
+	progname = match.group(1)
+	try:
+		patchlevel = match.group(5)
+	except IndexError as e:
+		patchlevel = None
+	if patchlevel:
+		patchlevel = ord(patchlevel[0])
+	else:
+		patchlevel = 0
+	progversion = (int(match.group(2)) << 64) |\
+		      (int(match.group(3)) << 48) |\
+		      (int(match.group(4)) << 32) |\
+		      patchlevel
+	return (progname, progversion)
+
+def parseVer_12(match, filepath):
+	progname = match.group(1)
+	try:
+		patchlevel = match.group(4)
+	except IndexError as e:
+		patchlevel = None
+	if patchlevel:
+		patchlevel = ord(patchlevel[0])
+	else:
+		patchlevel = 0
+	progversion = (int(match.group(2)) << 64) |\
+		      (int(match.group(3)) << 48) |\
+		      patchlevel
+	return (progname, progversion)
+
+def parseVer_r(match, filepath):
+	progname = match.group(1)
+	progversion = (int(match.group(2)) << 64)
+	return (progname, progversion)
+
+def parseVer_ymd(match, filepath):
+	progname = match.group(1)
+	progversion = (int(match.group(2)) << 64) |\
+		      (int(match.group(3)) << 48) |\
+		      (int(match.group(4)) << 32)
+	return (progname, progversion)
+
+def parseVer_GIT(match, filepath):
+	progname = match.group(1)
+	st = os.stat(filepath)
+	progversion = int(st.st_mtime) << 64
+	return (progname, progversion)
+
+extensions = (
+	".tar.gz",
+	".tar.bz2",
+	".tar.xz",
+	".orig.tar.gz",
+	".orig.tar.bz2",
+	".orig.tar.xz",
+	".zip",
+	".tgz",
+	".tbz",
+	".txz",
+)
+
+versionRegex = (
+	(re.compile(r"(.+)[-_](\d+)\.(\d+)\.(\d+)\.(\d+)"), parseVer_1234),	# xxx-1.2.3.4
+	(re.compile(r"(.+)[-_](\d\d\d\d)-?(\d\d)-?(\d\d)"), parseVer_ymd),	# xxx-YYYY-MM-DD
+	(re.compile(r"(.+)[-_]([0-9a-fA-F]{40,40})"), parseVer_GIT),		# xxx-GIT_SHASUM
+	(re.compile(r"(.+)[-_](\d+)\.(\d+)\.(\d+)(\w?)"), parseVer_123),	# xxx-1.2.3a
+	(re.compile(r"(.+)[-_](\d+)_(\d+)_(\d+)"), parseVer_123),		# xxx-1_2_3
+	(re.compile(r"(.+)[-_](\d+)\.(\d+)(\w?)"), parseVer_12),		# xxx-1.2a
+	(re.compile(r"(.+)[-_]r?(\d+)"), parseVer_r),				# xxx-r1111
+)
+
+blacklist = [
+	("linux",		re.compile(r"linux-\d.*")),
+	("gcc",			re.compile(r"gcc-.*")),
+	("wl_apsta",		re.compile(r"wl_apsta.*")),
+	(".fw",			re.compile(r".*\.fw")),
+	(".arm",		re.compile(r".*\.arm")),
+	(".bin",		re.compile(r".*\.bin")),
+	("rt-firmware",		re.compile(r"RT[\d\w]+_Firmware.*")),
+]
+
+class EntryParseError(Exception): pass
+
+class Entry:
+	def __init__(self, directory, filename):
+		self.directory = directory
+		self.filename = filename
+		self.progname = ""
+		self.fileext = ""
+
+		for ext in extensions:
+			if filename.endswith(ext):
+				filename = filename[0:0-len(ext)]
+				self.fileext = ext
+				break
+		else:
+			print(self.filename, "has an unknown file-extension")
+			raise EntryParseError("ext")
+		for (regex, parseVersion) in versionRegex:
+			match = regex.match(filename)
+			if match:
+				(self.progname, self.version) = parseVersion(
+					match, directory + "/" + filename + self.fileext)
+				break
+		else:
+			print(self.filename, "has an unknown version pattern")
+			raise EntryParseError("ver")
+
+	def getPath(self):
+		return (self.directory + "/" + self.filename).replace("//", "/")
+
+	def deleteFile(self):
+		path = self.getPath()
+		print("Deleting", path)
+		if not opt_dryrun:
+			os.unlink(path)
+
+	def __ge__(self, y):
+		return self.version >= y.version
+
+def usage():
+	print("OpenWrt download directory cleanup utility")
+	print("Usage: " + sys.argv[0] + " [OPTIONS] <path/to/dl>")
+	print("")
+	print(" -d|--dry-run            Do a dry-run. Don't delete any files")
+	print(" -B|--show-blacklist     Show the blacklist and exit")
+	print(" -w|--whitelist ITEM     Remove ITEM from blacklist")
+
+def main(argv):
+	global opt_dryrun
+
+	try:
+		(opts, args) = getopt.getopt(argv[1:],
+			"hdBw:",
+			[ "help", "dry-run", "show-blacklist", "whitelist=", ])
+		if len(args) != 1:
+			usage()
+			return 1
+	except getopt.GetoptError as e:
+		usage()
+		return 1
+	directory = args[0]
+	for (o, v) in opts:
+		if o in ("-h", "--help"):
+			usage()
+			return 0
+		if o in ("-d", "--dry-run"):
+			opt_dryrun = True
+		if o in ("-w", "--whitelist"):
+			for i in range(0, len(blacklist)):
+				(name, regex) = blacklist[i]
+				if name == v:
+					del blacklist[i]
+					break
+			else:
+				print("Whitelist error: Item", v,\
+				      "is not in blacklist")
+				return 1
+		if o in ("-B", "--show-blacklist"):
+			for (name, regex) in blacklist:
+				sep = "\t\t"
+				if len(name) >= 8:
+					sep = "\t"
+				print("%s%s(%s)" % (name, sep, regex.pattern))
+			return 0
+
+	# Create a directory listing and parse the file names.
+	entries = []
+	for filename in os.listdir(directory):
+		if filename == "." or filename == "..":
+			continue
+		for (name, regex) in blacklist:
+			if regex.match(filename):
+				if opt_dryrun:
+					print(filename, "is blacklisted")
+				break
+		else:
+			try:
+				entries.append(Entry(directory, filename))
+			except EntryParseError as e:
+				pass
+
+	# Create a map of programs
+	progmap = {}
+	for entry in entries:
+		if entry.progname in progmap.keys():
+			progmap[entry.progname].append(entry)
+		else:
+			progmap[entry.progname] = [entry,]
+
+	# Traverse the program map and delete everything but the last version
+	for prog in progmap:
+		lastVersion = None
+		versions = progmap[prog]
+		for version in versions:
+			if lastVersion is None or version >= lastVersion:
+				lastVersion = version
+		if lastVersion:
+			for version in versions:
+				if version is not lastVersion:
+					version.deleteFile()
+			if opt_dryrun:
+				print("Keeping", lastVersion.getPath())
+
+	return 0
+
+if __name__ == "__main__":
+	sys.exit(main(sys.argv))
diff --git a/scripts/download.pl b/scripts/download.pl
new file mode 100755
index 0000000000..c8149800d3
--- /dev/null
+++ b/scripts/download.pl
@@ -0,0 +1,268 @@
+#!/usr/bin/env perl
+# 
+# Copyright (C) 2006 OpenWrt.org
+# Copyright (C) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+use strict;
+use warnings;
+use File::Basename;
+use File::Copy;
+
+@ARGV > 2 or die "Syntax: $0 <target dir> <filename> <hash> <url filename> [<mirror> ...]\n";
+
+my $url_filename;
+my $target = shift @ARGV;
+my $filename = shift @ARGV;
+my $file_hash = shift @ARGV;
+$url_filename = shift @ARGV unless $ARGV[0] =~ /:\/\//;
+my $scriptdir = dirname($0);
+my @mirrors;
+my $ok;
+
+$url_filename or $url_filename = $filename;
+
+sub localmirrors {
+	my @mlist;
+	open LM, "$scriptdir/localmirrors" and do {
+	    while (<LM>) {
+			chomp $_;
+			push @mlist, $_ if $_;
+		}
+		close LM;
+	};
+	open CONFIG, "<".$ENV{'TOPDIR'}."/.config" and do {
+		while (<CONFIG>) {
+			/^CONFIG_LOCALMIRROR="(.+)"/ and do {
+				chomp;
+				my @local_mirrors = split(/;/, $1);
+				push @mlist, @local_mirrors;
+			};
+		}
+		close CONFIG;
+	};
+
+	my $mirror = $ENV{'DOWNLOAD_MIRROR'};
+	$mirror and push @mlist, split(/;/, $mirror);
+
+	return @mlist;
+}
+
+sub which($) {
+	my $prog = shift;
+	my $res = `which $prog`;
+	$res or return undef;
+	$res =~ /^no / and return undef;
+	$res =~ /not found/ and return undef;
+	return $res;
+}
+
+sub hash_cmd() {
+	my $len = length($file_hash);
+	my $cmd;
+
+	$len == 64 and return "openssl dgst -sha256 | sed -e 's,.*= ,,'";
+	$len == 32 and do {
+		my $cmd = which("md5sum") || which("md5") || die 'no md5 checksum program found, please install md5 or md5sum';
+		chomp $cmd;
+		return $cmd;
+	};
+	return undef;
+}
+
+my $hash_cmd = hash_cmd();
+
+sub download
+{
+	my $mirror = shift;
+	my $options = $ENV{WGET_OPTIONS} || "";
+
+	$mirror =~ s!/$!!;
+
+	if ($mirror =~ s!^file://!!) {
+		if (! -d "$mirror") {
+			print STDERR "Wrong local cache directory -$mirror-.\n";
+			cleanup();
+			return;
+		}
+
+		if (! -d "$target") {
+			system("mkdir", "-p", "$target/");
+		}
+
+		if (! open TMPDLS, "find $mirror -follow -name $filename 2>/dev/null |") {
+			print("Failed to search for $filename in $mirror\n");
+			return;
+		}
+
+		my $link;
+
+		while (defined(my $line = readline TMPDLS)) {
+			chomp ($link = $line);
+			if ($. > 1) {
+				print("$. or more instances of $filename in $mirror found . Only one instance allowed.\n");
+				return;
+			}
+		}
+
+		close TMPDLS;
+
+		if (! $link) {
+			print("No instances of $filename found in $mirror.\n");
+			return;
+		}
+
+		print("Copying $filename from $link\n");
+		copy($link, "$target/$filename.dl");
+
+		$hash_cmd and do {
+			if (system("cat '$target/$filename.dl' | $hash_cmd > '$target/$filename.hash'")) {
+				print("Failed to generate hash for $filename\n");
+				return;
+			}
+		};
+	} else {
+		open WGET, "wget -t5 --timeout=20 --no-check-certificate $options -O- '$mirror/$url_filename' |" or die "Cannot launch wget.\n";
+		$hash_cmd and do {
+			open MD5SUM, "| $hash_cmd > '$target/$filename.hash'" or die "Cannot launch $hash_cmd.\n";
+		};
+		open OUTPUT, "> $target/$filename.dl" or die "Cannot create file $target/$filename.dl: $!\n";
+		my $buffer;
+		while (read WGET, $buffer, 1048576) {
+			$hash_cmd and print MD5SUM $buffer;
+			print OUTPUT $buffer;
+		}
+		$hash_cmd and close MD5SUM;
+		close WGET;
+		close OUTPUT;
+
+		if ($? >> 8) {
+			print STDERR "Download failed.\n";
+			cleanup();
+			return;
+		}
+	}
+
+	$hash_cmd and do {
+		my $sum = `cat "$target/$filename.hash"`;
+		$sum =~ /^(\w+)\s*/ or die "Could not generate file hash\n";
+		$sum = $1;
+
+		if ($sum ne $file_hash) {
+			print STDERR "MD5 sum of the downloaded file does not match (file: $sum, requested: $file_hash) - deleting download.\n";
+			cleanup();
+			return;
+		}
+	};
+
+	unlink "$target/$filename";
+	system("mv", "$target/$filename.dl", "$target/$filename");
+	cleanup();
+}
+
+sub cleanup
+{
+	unlink "$target/$filename.dl";
+	unlink "$target/$filename.hash";
+}
+
+@mirrors = localmirrors();
+
+foreach my $mirror (@ARGV) {
+	if ($mirror =~ /^\@SF\/(.+)$/) {
+		# give sourceforge a few more tries, because it redirects to different mirrors
+		for (1 .. 5) {
+			push @mirrors, "http://downloads.sourceforge.net/$1";
+		}
+	} elsif ($mirror =~ /^\@APACHE\/(.+)$/) {
+		push @mirrors, "https://mirror.netcologne.de/apache.org/$1";
+		push @mirrors, "https://mirror.aarnet.edu.au/pub/apache/$1";
+		push @mirrors, "http://mirror.cogentco.com/pub/apache/$1";
+		push @mirrors, "http://mirror.csclub.uwaterloo.ca/apache/$1";
+		push @mirrors, "http://mirror.navercorp.com/apache/$1";
+		push @mirrors, "http://ftp.jaist.ac.jp/pub/apache/$1";
+		push @mirrors, "ftp://apache.cs.utah.edu/apache.org/$1";
+		push @mirrors, "ftp://apache.mirrors.ovh.net/ftp.apache.org/dist/$1";
+	} elsif ($mirror =~ /^\@GITHUB\/(.+)$/) {
+		# give github a few more tries (different mirrors)
+		for (1 .. 5) {
+			push @mirrors, "https://raw.githubusercontent.com/$1";
+		}
+	} elsif ($mirror =~ /^\@GNU\/(.+)$/) {
+		push @mirrors, "https://mirrors.rit.edu/gnu/$1";
+		push @mirrors, "https://mirror.netcologne.de/gnu/$1";
+		push @mirrors, "http://ftp.kddilabs.jp/GNU/gnu/$1";
+		push @mirrors, "http://www.nic.funet.fi/pub/gnu/gnu/$1";
+		push @mirrors, "http://mirror.internode.on.net/pub/gnu/$1";
+		push @mirrors, "http://mirror.navercorp.com/gnu/$1";
+		push @mirrors, "ftp://mirror.csclub.uwaterloo.ca/gnu/$1";
+		push @mirrors, "ftp://download.xs4all.nl/pub/gnu/";
+	} elsif ($mirror =~ /^\@SAVANNAH\/(.+)$/) {
+		push @mirrors, "https://mirror.netcologne.de/savannah/$1";
+		push @mirrors, "http://mirror.csclub.uwaterloo.ca/nongnu/$1";
+		push @mirrors, "http://ftp.acc.umu.se/mirror/gnu.org/savannah/$1";
+		push @mirrors, "http://nongnu.uib.no/$1";
+		push @mirrors, "http://ftp.igh.cnrs.fr/pub/nongnu/$1";
+		push @mirrors, "http://public.p-knowledge.co.jp/Savannah-nongnu-mirror/$1";
+		push @mirrors, "ftp://cdimage.debian.org/mirror/gnu.org/savannah/$1";
+		push @mirrors, "ftp://ftp.acc.umu.se/mirror/gnu.org/savannah/$1";
+	} elsif ($mirror =~ /^\@KERNEL\/(.+)$/) {
+		my @extra = ( $1 );
+		if ($filename =~ /linux-\d+\.\d+(?:\.\d+)?-rc/) {
+			push @extra, "$extra[0]/testing";
+		} elsif ($filename =~ /linux-(\d+\.\d+(?:\.\d+)?)/) {
+			push @extra, "$extra[0]/longterm/v$1";
+		}		
+		foreach my $dir (@extra) {
+			push @mirrors, "https://cdn.kernel.org/pub/$dir";
+			push @mirrors, "https://mirror.rackspace.com/kernel.org/$dir";
+			push @mirrors, "http://download.xs4all.nl/ftp.kernel.org/pub/$dir";
+			push @mirrors, "http://mirrors.mit.edu/kernel/$dir";
+			push @mirrors, "http://ftp.nara.wide.ad.jp/pub/kernel.org/$dir";
+			push @mirrors, "http://www.ring.gr.jp/archives/linux/kernel.org/$dir";
+			push @mirrors, "ftp://ftp.riken.jp/Linux/kernel.org/$dir";
+			push @mirrors, "ftp://www.mirrorservice.org/sites/ftp.kernel.org/pub/$dir";
+		}
+	} elsif ($mirror =~ /^\@KERNEL_LIBRE\/(.+)$/) {
+                my @extra = ( $1 );
+                if ($filename =~ /linux-libre-\d+\.\d+(?:\.\d+)?-rc-gnu/) {
+                        push @extra, "$extra[0]/testing";
+                } elsif ($filename =~ /linux-libre-(\d+\.\d+(?:\.\d+)?)-gnu/) {
+                        push @extra, "$extra[0]/v$1";
+                }
+                foreach my $dir (@extra) {
+                        push @mirrors, "http://linux-libre.fsfla.org/pub/linux-libre/releases/$dir";
+                }
+	} elsif ($mirror =~ /^\@GNOME\/(.+)$/) {
+		push @mirrors, "http://mirror.csclub.uwaterloo.ca/gnome/sources/$1";
+		push @mirrors, "http://ftp.acc.umu.se/pub/GNOME/sources/$1";
+		push @mirrors, "http://ftp.kaist.ac.kr/gnome/sources/$1";
+		push @mirrors, "http://www.mirrorservice.org/sites/ftp.gnome.org/pub/GNOME/sources/$1";
+		push @mirrors, "http://mirror.internode.on.net/pub/gnome/sources/$1";
+		push @mirrors, "http://ftp.belnet.be/ftp.gnome.org/sources/$1";
+		push @mirrors, "ftp://ftp.cse.buffalo.edu/pub/Gnome/sources/$1";
+		push @mirrors, "ftp://ftp.nara.wide.ad.jp/pub/X11/GNOME/sources/$1";
+    }
+    else {
+		push @mirrors, $mirror;
+	}
+}
+
+#push @mirrors, 'http://mirror1.openwrt.org';
+push @mirrors, 'http://sources.lede-project.org';
+push @mirrors, 'http://mirror2.openwrt.org/sources';
+push @mirrors, 'http://downloads.openwrt.org/sources';
+
+while (!$ok) {
+	my $mirror = shift @mirrors;
+	$mirror or die "No more mirrors to try - giving up.\n";
+
+	download($mirror);
+	-f "$target/$filename" and $ok = 1;
+}
+
+$SIG{INT} = \&cleanup;
+
diff --git a/scripts/env b/scripts/env
new file mode 100755
index 0000000000..63e26eb154
--- /dev/null
+++ b/scripts/env
@@ -0,0 +1,226 @@
+#!/usr/bin/env bash
+BASEDIR="$PWD"
+ENVDIR="$PWD/env"
+export GREP_OPTIONS=
+
+usage() {
+	cat <<EOF
+Usage: $0 [options] <command> [arguments]
+Commands:
+	help              This help text
+	list              List environments
+	clear             Delete all environment and revert to flat config/files
+	new <name>        Create a new environment
+	switch <name>     Switch to a different environment
+	delete <name>     Delete an environment
+	rename <newname>  Rename the current environment
+	diff              Show differences between current state and environment
+	save [message]    Save your changes to the environment, optionally using
+	                  the given commit message
+	revert            Revert your changes since last save
+
+Options:
+
+EOF
+	exit ${1:-1}
+}
+
+error() {
+	echo "$0: $*"
+	exit 1
+}
+
+ask_bool() {
+	local DEFAULT="$1"; shift
+	local def defstr val
+	case "$DEFAULT" in
+		1) def=0; defstr="Y/n";;
+		0) def=1; defstr="y/N";;
+		*) def=;  defstr="y/n";;
+	esac
+	while [ -z "$val" ]; do
+		local VAL
+
+		echo -n "$* ($defstr): "
+		read VAL
+		case "$VAL" in
+			y*|Y*) val=0;;
+			n*|N*) val=1;;
+			*) val="$def";;
+		esac
+	done
+	return "$val"
+}
+
+env_init() {
+	local CREATE="$1"
+	if [ -z "$CREATE" ]; then
+		[ -d "$ENVDIR" ] || exit 0
+	fi
+	[ -x "$(which git 2>/dev/null)" ] || error "Git is not installed"
+	mkdir -p "$ENVDIR" || error "Failed to create the environment directory"
+	cd "$ENVDIR" || error "Failed to switch to the environment directory"
+	[ -d .git ] || { 
+		git init &&
+		touch .config &&
+		mkdir files &&
+		git add . && 
+		git commit -q -m "Initial import"
+	} || {
+		rm -rf .git
+		error "Failed to initialize the environment directory"
+	}
+}
+
+env_sync_data() {
+	[ \! -L "$BASEDIR/.config" -a -f "$BASEDIR/.config" ] && mv "$BASEDIR/.config" "$ENVDIR"
+	git add .
+	git add -u
+}
+
+env_sync() {
+	local STR="$1"
+	env_sync_data
+	git commit -m "${STR:-Update} at $(date)"
+}
+
+env_link_config() {
+	rm -f "$BASEDIR/.config"
+	ln -s env/.config "$BASEDIR/.config"
+	mkdir -p "$ENVDIR/files"
+	[ -L "$BASEDIR/files" ] || ln -s env/files "$BASEDIR/files"
+}
+
+env_do_reset() {
+	git reset --hard HEAD
+	git clean -d -f
+}
+
+env_list() {
+	env_init
+	git branch --color | grep -vE '^. master$'
+}
+
+env_diff() {
+	env_init
+	env_sync_data
+	git diff --cached --color
+	env_link_config
+}
+
+env_save() {
+	env_init
+	env_sync "$@"
+	env_link_config
+}
+
+env_revert() {
+	env_init
+	env_do_reset
+	env_link_config
+}
+
+env_ask_sync() {
+	env_sync_data
+	LINES="$(env_diff | wc -l)" # implies env_init
+	[ "$LINES" -gt 0 ] && {
+		if ask_bool 1 "Do you want to save your changes"; then
+			env_sync
+		else
+			env_do_reset
+		fi
+	}
+}
+
+env_clear() {
+	env_init
+	[ -L "$BASEDIR/.config" ] && rm -f "$BASEDIR/.config"
+	[ -L "$BASEDIR/files" ] && rm -f "$BASEDIR/files"
+	[ -f "$ENVDIR/.config" ] || ( cd "$ENVDIR/files" && find | grep -vE '^\.$' > /dev/null )
+	env_sync_data
+	if ask_bool 1 "Do you want to keep your current config and files"; then
+		mkdir -p "$BASEDIR/files"
+		shopt -s dotglob
+		cp -a "$ENVDIR/files/"* "$BASEDIR/files" 2>/dev/null >/dev/null
+		shopt -u dotglob
+		cp "$ENVDIR/.config" "$BASEDIR/"
+	else
+		rm -rf "$BASEDIR/files" "$BASEDIR/.config"
+	fi
+	cd "$BASEDIR"
+	rm -rf "$ENVDIR"
+}
+
+env_delete() {
+	local name="${1##*/}"
+	env_init
+	[ -z "$name" ] && usage
+	branch="$(git branch | grep '^\* ' | awk '{print $2}')"
+	[ "$name" = "$branch" ] && error "cannot delete the currently selected environment"
+	git branch -D "$name"
+}
+
+env_switch() {
+	local name="${1##*/}"
+	[ -z "$name" ] && usage
+
+	env_init
+	env_ask_sync
+	git checkout "$name" || error "environment '$name' not found"
+	env_link_config
+}
+
+env_rename() {
+	local NAME="${1##*/}"
+	env_init
+	git branch -m "$NAME"
+}
+
+env_new() {
+	local NAME="$1"
+	local branch
+	local from="master"
+
+	[ -z "$NAME" ] && usage
+	env_init 1
+	
+	branch="$(git branch | grep '^\* ' | awk '{print $2}')"
+	if [ -n "$branch" -a "$branch" != "master" ]; then
+		env_ask_sync
+		if ask_bool 0 "Do you want to clone the current environment?"; then
+			from="$branch"
+		fi
+		rm -f "$BASEDIR/.config" "$BASEDIR/files"
+	fi
+	git checkout -b "$1" "$from"
+	if [ -f "$BASEDIR/.config" -o -d "$BASEDIR/files" ]; then
+		if ask_bool 1 "Do you want to start your configuration repository with the current configuration?"; then
+			[ -d "$BASEDIR/files" -a \! -L "$BASEDIR/files" ] && {
+				mkdir -p "$ENVDIR/files"
+				shopt -s dotglob
+				mv "$BASEDIR/files/"* "$ENVDIR/files/" 2>/dev/null
+				shopt -u dotglob
+				rmdir "$BASEDIR/files"
+			}
+			env_sync
+		else
+			rm -rf "$BASEDIR/.config" "$BASEDIR/files"
+		fi
+	fi
+	env_link_config
+}
+
+COMMAND="$1"; shift
+case "$COMMAND" in
+	help) usage 0;;
+	new) env_new "$@";;
+	list) env_list "$@";;
+	clear) env_clear "$@";;
+	switch) env_switch "$@";;
+	delete) env_delete "$@";;
+	rename) env_rename "$@";;
+	diff) env_diff "$@";;
+	save) env_save "$@";;
+	revert) env_revert "$@";;
+	*) usage;;
+esac
diff --git a/scripts/ext-toolchain.sh b/scripts/ext-toolchain.sh
new file mode 100755
index 0000000000..09390c5e0d
--- /dev/null
+++ b/scripts/ext-toolchain.sh
@@ -0,0 +1,581 @@
+#!/usr/bin/env bash
+#
+#   Script for various external toolchain tasks, refer to
+#   the --help output for more information.
+#
+#   Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+CC=""
+CXX=""
+CPP=""
+
+CFLAGS=""
+TOOLCHAIN="."
+
+LIBC_TYPE=""
+
+
+# Library specs
+LIB_SPECS="
+	c:        ld-* lib{anl,c,cidn,crypt,dl,m,nsl,nss_dns,nss_files,resolv,util}
+	rt:       librt-* librt
+	pthread:  libpthread-* libpthread
+	stdcpp:   libstdc++
+	gcc:      libgcc_s
+	ssp:      libssp
+	gfortran: libgfortran
+"
+
+# Binary specs
+BIN_SPECS="
+	ldd:       ldd
+	ldconfig:  ldconfig
+	gdb:       gdb
+	gdbserver: gdbserver
+"
+
+
+test_c() {
+	cat <<-EOT | "${CC:-false}" $CFLAGS -o /dev/null -x c - 2>/dev/null
+		#include <stdio.h>
+
+		int main(int argc, char **argv)
+		{
+			printf("Hello, world!\n");
+			return 0;
+		}
+	EOT
+}
+
+test_cxx() {
+	cat <<-EOT | "${CXX:-false}" $CFLAGS -o /dev/null -x c++ - 2>/dev/null
+		#include <iostream>
+
+		using namespace std;
+
+		int main()
+		{
+			cout << "Hello, world!" << endl;
+			return 0;
+		}
+	EOT
+}
+
+test_softfloat() {
+	cat <<-EOT | "$CC" $CFLAGS -msoft-float -o /dev/null -x c - 2>/dev/null
+		int main(int argc, char **argv)
+		{
+			double a = 0.1;
+			double b = 0.2;
+			double c = (a + b) / (a * b);
+			return 1;
+		}
+	EOT
+}
+
+test_uclibc() {
+	local sysroot="$("$CC" $CFLAGS -print-sysroot 2>/dev/null)"
+	if [ -d "${sysroot:-$TOOLCHAIN}" ]; then
+		local lib
+		for lib in "${sysroot:-$TOOLCHAIN}"/{lib,usr/lib,usr/local/lib}/ld*-uClibc*.so*; do
+			if [ -f "$lib" ] && [ ! -h "$lib" ]; then
+				return 0
+			fi
+		done
+	fi
+	return 1
+}
+
+test_feature() {
+	local feature="$1"; shift
+
+	# find compilers, libc type
+	probe_cc
+	probe_cxx
+	probe_libc
+
+	# common toolchain feature tests
+	case "$feature" in
+		c)     test_c;         return $? ;;
+		c++)   test_cxx;       return $? ;;
+		soft*) test_softfloat; return $? ;;
+	esac
+
+	# assume eglibc/glibc supports all libc features
+	if [ "$LIBC_TYPE" != "uclibc" ]; then
+		return 0
+	fi
+
+	# uclibc feature tests
+	local inc
+	local sysroot="$("$CC" "$@" -muclibc -print-sysroot 2>/dev/null)"
+	for inc in "include" "usr/include" "usr/local/include"; do
+		local conf="${sysroot:-$TOOLCHAIN}/$inc/bits/uClibc_config.h"
+		if [ -f "$conf" ]; then
+			case "$feature" in
+				lfs)     grep -q '__UCLIBC_HAS_LFS__ 1'     "$conf"; return $?;;
+				ipv6)    grep -q '__UCLIBC_HAS_IPV6__ 1'    "$conf"; return $?;;
+				rpc)     grep -q '__UCLIBC_HAS_RPC__ 1'     "$conf"; return $?;;
+				locale)  grep -q '__UCLIBC_HAS_LOCALE__ 1'  "$conf"; return $?;;
+				wchar)   grep -q '__UCLIBC_HAS_WCHAR__ 1'   "$conf"; return $?;;
+				threads) grep -q '__UCLIBC_HAS_THREADS__ 1' "$conf"; return $?;;
+			esac
+		fi
+	done
+
+	return 1
+}
+
+
+find_libs() {
+	local spec="$(echo "$LIB_SPECS" | sed -ne "s#^[[:space:]]*$1:##ip")"
+
+	if [ -n "$spec" ] && probe_cpp; then
+		local libdir libdirs
+		for libdir in $(
+			"$CPP" $CFLAGS -v -x c /dev/null 2>&1 | \
+				sed -ne 's#:# #g; s#^LIBRARY_PATH=##p'
+		); do
+			if [ -d "$libdir" ]; then
+				libdirs="$libdirs $(cd "$libdir"; pwd)/"
+			fi
+		done
+
+		local pattern
+		for pattern in $(eval echo $spec); do
+			find $libdirs -name "$pattern.so*" | sort -u
+		done
+
+		return 0
+	fi
+
+	return 1
+}
+
+find_bins() {
+	local spec="$(echo "$BIN_SPECS" | sed -ne "s#^[[:space:]]*$1:##ip")"
+
+	if [ -n "$spec" ] && probe_cpp; then
+		local sysroot="$("$CPP" -print-sysroot)"
+
+		local bindir bindirs
+		for bindir in $(
+			echo "${sysroot:-$TOOLCHAIN}/bin";
+			echo "${sysroot:-$TOOLCHAIN}/usr/bin";
+			echo "${sysroot:-$TOOLCHAIN}/usr/local/bin";
+ 			"$CPP" $CFLAGS -v -x c /dev/null 2>&1 | \
+				sed -ne 's#:# #g; s#^COMPILER_PATH=##p'
+		); do
+			if [ -d "$bindir" ]; then
+				bindirs="$bindirs $(cd "$bindir"; pwd)/"
+			fi
+		done
+
+		local pattern
+		for pattern in $(eval echo $spec); do
+			find $bindirs -name "$pattern" | sort -u
+		done
+
+		return 0
+	fi
+
+	return 1
+}
+
+
+wrap_bin_cc() {
+	local out="$1"
+	local bin="$2"
+
+	echo    '#!/bin/sh'                                                > "$out"
+	echo    'for arg in "$@"; do'                                     >> "$out"
+	echo    ' case "$arg" in -l*|-L*|-shared|-static)'                >> "$out"
+	echo -n '  exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+'           >> "$out"
+	echo -n '-idirafter "$STAGING_DIR/usr/include" '                  >> "$out"
+	echo -n '-L "$STAGING_DIR/usr/lib" '                              >> "$out"
+	echo    '-Wl,-rpath-link,"$STAGING_DIR/usr/lib"} "$@" ;;'         >> "$out"
+	echo    ' esac'                                                   >> "$out"
+	echo    'done'                                                    >> "$out"
+	echo -n 'exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+'             >> "$out"
+	echo    '-idirafter "$STAGING_DIR/usr/include"} "$@"'             >> "$out"
+
+	chmod +x "$out"
+}
+
+wrap_bin_ld() {
+	local out="$1"
+	local bin="$2"
+
+	echo    '#!/bin/sh'                                                > "$out"
+	echo -n 'exec "'"$bin"'" ${STAGING_DIR:+'                         >> "$out"
+	echo -n '-L "$STAGING_DIR/usr/lib" '                              >> "$out"
+	echo    '-rpath-link "$STAGING_DIR/usr/lib"} "$@"'                >> "$out"
+
+	chmod +x "$out"
+}
+
+wrap_bin_other() {
+	local out="$1"
+	local bin="$2"
+
+	echo    '#!/bin/sh'                                                > "$out"
+	echo    'exec "'"$bin"'" "$@"'                                    >> "$out"
+
+	chmod +x "$out"
+}
+
+wrap_bins() {
+	if probe_cc; then
+		mkdir -p "$1" || return 1
+
+		local cmd
+		for cmd in "${CC%-*}-"*; do
+			if [ -x "$cmd" ]; then
+				local out="$1/${cmd##*/}"
+				local bin="$cmd"
+
+				if [ -x "$out" ] && ! grep -q STAGING_DIR "$out"; then
+					mv "$out" "$out.bin"
+					bin='$(dirname "$0")/'"${out##*/}"'.bin'
+				fi
+
+				case "${cmd##*/}" in
+					*-*cc|*-*cc-*|*-*++|*-*++-*|*-cpp)
+						wrap_bin_cc "$out" "$bin"
+					;;
+					*-ld)
+						wrap_bin_ld "$out" "$bin"
+					;;
+					*)
+						wrap_bin_other "$out" "$bin"
+					;;
+				esac
+			fi
+		done
+
+		return 0
+	fi
+
+	return 1
+}
+
+
+print_config() {
+	local mktarget="$1"
+	local mksubtarget
+
+	local target="$("$CC" $CFLAGS -dumpmachine)"
+	local cpuarch="${target%%-*}"
+	local prefix="${CC##*/}"; prefix="${prefix%-*}-"
+	local config="${0%/scripts/*}/.config"
+
+	# if no target specified, print choice list and exit
+	if [ -z "$mktarget" ]; then
+		# prepare metadata
+		if [ ! -f "${0%/scripts/*}/tmp/.targetinfo" ]; then
+			"${0%/*}/scripts/config/mconf" prepare-tmpinfo
+		fi
+
+		local mktargets=$(
+			sed -ne "
+				/^Target: / { h };
+				/^Target-Arch: $cpuarch\$/ { x; s#^Target: ##p }
+			" "${0%/scripts/*}/tmp/.targetinfo" | sort -u
+		)
+
+		for mktarget in $mktargets; do
+			case "$mktarget" in */*)
+				mktargets=$(echo "$mktargets" | sed -e "/^${mktarget%/*}\$/d")
+			esac
+		done
+
+		if [ -n "$mktargets" ]; then
+			echo "Available targets:"                               >&2
+			echo $mktargets                                         >&2
+		else
+			echo -e "Could not find a suitable OpenWrt target for " >&2
+			echo -e "CPU architecture '$cpuarch' - you need to "    >&2
+			echo -e "define one first!"                             >&2
+		fi
+		return 1
+	fi
+
+	# bail out if there is a .config already
+	if [ -f "${0%/scripts/*}/.config" ]; then
+		echo "There already is a .config file, refusing to overwrite!" >&2
+		return 1
+	fi
+
+	case "$mktarget" in */*)
+		mksubtarget="${mktarget#*/}"
+		mktarget="${mktarget%/*}"
+	;; esac
+
+
+	echo "CONFIG_TARGET_${mktarget}=y" > "$config"
+
+	if [ -n "$mksubtarget" ]; then
+		echo "CONFIG_TARGET_${mktarget}_${mksubtarget}=y" >> "$config"
+	fi
+
+	if test_feature "softfloat"; then
+		echo "CONFIG_SOFT_FLOAT=y" >> "$config"
+	else
+		echo "# CONFIG_SOFT_FLOAT is not set" >> "$config"
+	fi
+
+	if test_feature "ipv6"; then
+		echo "CONFIG_IPV6=y" >> "$config"
+	else
+		echo "# CONFIG_IPV6 is not set" >> "$config"
+	fi
+
+	if test_feature "locale"; then
+		echo "CONFIG_BUILD_NLS=y" >> "$config"
+	else
+		echo "# CONFIG_BUILD_NLS is not set" >> "$config"
+	fi
+
+	echo "CONFIG_DEVEL=y" >> "$config"
+	echo "CONFIG_EXTERNAL_TOOLCHAIN=y" >> "$config"
+	echo "CONFIG_TOOLCHAIN_ROOT=\"$TOOLCHAIN\"" >> "$config"
+	echo "CONFIG_TOOLCHAIN_PREFIX=\"$prefix\"" >> "$config"
+	echo "CONFIG_TARGET_NAME=\"$target\"" >> "$config"
+
+	if [ "$LIBC_TYPE" != glibc ]; then
+		echo "CONFIG_TOOLCHAIN_LIBC=\"$LIBC_TYPE\"" >> "$config"
+	fi
+
+	local lib
+	for lib in C RT PTHREAD GCC STDCPP SSP GFORTRAN; do
+		local file
+		local spec=""
+		local llib="$(echo "$lib" | sed -e 's#.*#\L&#')"
+		for file in $(find_libs "$lib"); do
+			spec="${spec:+$spec }$(echo "$file" | sed -e "s#^$TOOLCHAIN#.#")"
+		done
+		if [ -n "$spec" ]; then
+			echo "CONFIG_PACKAGE_lib${llib}=y" >> "$config"
+			echo "CONFIG_LIB${lib}_FILE_SPEC=\"$spec\"" >> "$config"
+		else
+			echo "# CONFIG_PACKAGE_lib${llib} is not set" >> "$config"
+		fi
+	done
+
+	local bin
+	for bin in LDD LDCONFIG; do
+		local file
+		local spec=""
+		local lbin="$(echo "$bin" | sed -e 's#.*#\L&#')"
+		for file in $(find_bins "$bin"); do
+			spec="${spec:+$spec }$(echo "$file" | sed -e "s#^$TOOLCHAIN#.#")"
+		done
+		if [ -n "$spec" ]; then
+			echo "CONFIG_PACKAGE_${lbin}=y" >> "$config"
+			echo "CONFIG_${bin}_FILE_SPEC=\"$spec\"" >> "$config"
+		else
+			echo "# CONFIG_PACKAGE_${lbin} is not set" >> "$config"
+		fi
+	done
+
+	# inflate
+	make -C "${0%/scripts/*}" defconfig
+	return 0
+}
+
+
+probe_cc() {
+	if [ -z "$CC" ]; then
+		local bin
+		for bin in "bin" "usr/bin" "usr/local/bin"; do
+			local cmd
+			for cmd in "$TOOLCHAIN/$bin/"*-*cc*; do
+				if [ -x "$cmd" ] && [ ! -h "$cmd" ]; then
+					CC="$(cd "${cmd%/*}"; pwd)/${cmd##*/}"
+					return 0
+				fi
+			done
+		done
+		return 1
+	fi
+	return 0
+}
+
+probe_cxx() {
+	if [ -z "$CXX" ]; then
+		local bin
+		for bin in "bin" "usr/bin" "usr/local/bin"; do
+			local cmd
+			for cmd in "$TOOLCHAIN/$bin/"*-*++*; do
+				if [ -x "$cmd" ] && [ ! -h "$cmd" ]; then
+					CXX="$(cd "${cmd%/*}"; pwd)/${cmd##*/}"
+					return 0
+				fi
+			done
+		done
+		return 1
+	fi
+	return 0
+}
+
+probe_cpp() {
+	if [ -z "$CPP" ]; then
+		local bin
+		for bin in "bin" "usr/bin" "usr/local/bin"; do
+			local cmd
+			for cmd in "$TOOLCHAIN/$bin/"*-cpp*; do
+				if [ -x "$cmd" ] && [ ! -h "$cmd" ]; then
+					CPP="$(cd "${cmd%/*}"; pwd)/${cmd##*/}"
+					return 0
+				fi
+			done
+		done
+		return 1
+	fi
+	return 0
+}
+
+probe_libc() {
+	if [ -z "$LIBC_TYPE" ]; then
+		if test_uclibc; then
+			LIBC_TYPE="uclibc"
+		else
+			LIBC_TYPE="glibc"
+		fi
+	fi
+	return 0
+}
+
+
+while [ -n "$1" ]; do
+	arg="$1"; shift
+	case "$arg" in
+		--toolchain)
+			[ -d "$1" ] || {
+				echo "Toolchain directory '$1' does not exist." >&2
+				exit 1
+			}
+			TOOLCHAIN="$(cd "$1"; pwd)"; shift
+		;;
+
+		--cflags)
+			CFLAGS="${CFLAGS:+$CFLAGS }$1"; shift
+		;;
+
+		--print-libc)
+			if probe_cc; then
+				probe_libc
+				echo "$LIBC_TYPE"
+				exit 0
+			fi
+			echo "No C compiler found in '$TOOLCHAIN'." >&2
+			exit 1
+		;;
+
+		--print-target)
+			if probe_cc; then
+				exec "$CC" $CFLAGS -dumpmachine
+			fi
+			echo "No C compiler found in '$TOOLCHAIN'." >&2
+			exit 1
+		;;
+
+		--print-bin)
+			if [ -z "$1" ]; then
+				echo "Available programs:"                      >&2
+				echo $(echo "$BIN_SPECS" | sed -ne 's#:.*$##p') >&2
+				exit 1
+			fi
+
+			find_bins "$1" || exec "$0" --toolchain "$TOOLCHAIN" --print-bin
+			exit 0
+		;;
+
+		--print-libs)
+			if [ -z "$1" ]; then
+				echo "Available libraries:"                     >&2
+				echo $(echo "$LIB_SPECS" | sed -ne 's#:.*$##p') >&2
+				exit 1
+			fi
+
+			find_libs "$1" || exec "$0" --toolchain "$TOOLCHAIN" --print-libs
+			exit 0
+		;;
+
+		--test)
+			test_feature "$1"
+			exit $?
+		;;
+
+		--wrap)
+			[ -n "$1" ] || exec "$0" --help
+			wrap_bins "$1"
+			exit $?
+		;;
+
+		--config)
+			if probe_cc; then
+				print_config "$1"
+				exit $?
+			fi
+			echo "No C compiler found in '$TOOLCHAIN'." >&2
+			exit 1
+		;;
+
+		-h|--help)
+			me="$(basename "$0")"
+			echo -e "\nUsage:\n"                                            >&2
+			echo -e "  $me --toolchain {directory} --print-libc"            >&2
+			echo -e "    Print the libc implementation and exit.\n"         >&2
+			echo -e "  $me --toolchain {directory} --print-target"          >&2
+			echo -e "    Print the GNU target name and exit.\n"             >&2
+			echo -e "  $me --toolchain {directory} --print-bin {program}"   >&2
+			echo -e "    Print executables belonging to given program,"     >&2
+			echo -e "    omit program argument to get a list of names.\n"   >&2
+			echo -e "  $me --toolchain {directory} --print-libs {library}"  >&2
+			echo -e "    Print shared objects belonging to given library,"  >&2
+			echo -e "    omit library argument to get a list of names.\n"   >&2
+			echo -e "  $me --toolchain {directory} --test {feature}"        >&2
+			echo -e "    Test given feature, exit code indicates success."  >&2
+			echo -e "    Possible features are 'c', 'c++', 'softfloat',"    >&2
+			echo -e "    'lfs', 'rpc', 'ipv6', 'wchar', 'locale' and "      >&2
+			echo -e "    'threads'.\n"                                      >&2
+			echo -e "  $me --toolchain {directory} --wrap {directory}"      >&2
+			echo -e "    Create wrapper scripts for C and C++ compiler, "   >&2
+			echo -e "    linker, assembler and other key executables in "   >&2
+			echo -e "    the directory given with --wrap.\n"                >&2
+			echo -e "  $me --toolchain {directory} --config {target}"       >&2
+			echo -e "    Analyze the given toolchain and print a suitable"  >&2
+			echo -e "    .config for the given target. Omit target "        >&2
+			echo -e "    argument to get a list of names.\n"                >&2
+			echo -e "  $me --help"                                          >&2
+			echo -e "    Display this help text and exit.\n\n"              >&2
+			echo -e "  Most commands also take a --cflags parameter which " >&2
+			echo -e "  is used to specify C flags to be passed to the "     >&2
+			echo -e "  cross compiler when performing tests."               >&2
+			echo -e "  This paremter may be repeated multiple times."       >&2
+			exit 1
+		;;
+
+		*)
+			echo "Unknown argument '$arg'" >&2
+			exec $0 --help
+		;;
+	esac
+done
+
+exec $0 --help
diff --git a/scripts/feeds b/scripts/feeds
new file mode 100755
index 0000000000..83007f5e16
--- /dev/null
+++ b/scripts/feeds
@@ -0,0 +1,825 @@
+#!/usr/bin/env perl
+use Getopt::Std;
+use FindBin;
+use Cwd;
+use lib "$FindBin::Bin";
+use metadata;
+use warnings;
+use strict;
+use Cwd 'abs_path';
+
+chdir "$FindBin::Bin/..";
+$ENV{TOPDIR}=getcwd();
+$ENV{GIT_CONFIG_PARAMETERS}="'core.autocrlf=false'";
+$ENV{GREP_OPTIONS}="";
+
+my $mk=`which gmake 2>/dev/null`;	# select the right 'make' program
+chomp($mk);		# trim trailing newline
+$mk or $mk = "make";	# default to 'make'
+
+# check version of make
+my @mkver = split /\s+/, `$mk -v`, 4;
+my $valid_mk = 1;
+$mkver[0] =~ /^GNU/ or $valid_mk = 0;
+$mkver[1] =~ /^Make/ or $valid_mk = 0;
+
+my ($mkv1, $mkv2) = split /\./, $mkver[2];
+($mkv1 >= 4 || ($mkv1 == 3 && $mkv2 >= 81)) or $valid_mk = 0;
+
+$valid_mk or die "Unsupported version of make found: $mk\n";
+
+my @feeds;
+my %build_packages;
+my %installed;
+my %installed_targets;
+my %feed_cache;
+
+my $feed_package = {};
+my $feed_src = {};
+my $feed_target = {};
+
+sub parse_config() {
+	my $line = 0;
+	my %name;
+
+	open FEEDS, "feeds.conf" or
+		open FEEDS, "feeds.conf.default" or
+		die "Unable to open feeds configuration";
+	while (<FEEDS>) {
+		chomp;
+		s/#.+$//;
+		next unless /\S/;
+		my @line = split /\s+/, $_, 3;
+		my @src;
+		$line++;
+
+		my $valid = 1;
+		$line[0] =~ /^src-[\w-]+$/ or $valid = 0;
+		$line[1] =~ /^\w+$/ or $valid = 0;
+		@src = split /\s+/, $line[2];
+		$valid or die "Syntax error in feeds.conf, line: $line\n";
+
+		$name{$line[1]} and die "Duplicate feed name '$line[1]', line: $line\n";
+		$name{$line[1]} = 1;
+
+		push @feeds, [$line[0], $line[1], \@src];
+	}
+	close FEEDS;
+}
+
+sub update_location($$)
+{
+	my $name = shift;
+	my $url  = shift;
+	my $old_url;
+
+	-d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1;
+
+	if( open LOC, "< ./feeds/$name.tmp/location" )
+	{
+		chomp($old_url = readline LOC);
+		close LOC;
+	}
+
+	if( !$old_url || $old_url ne $url )
+	{
+		if( open LOC, "> ./feeds/$name.tmp/location" )
+		{
+			print LOC $url, "\n";
+			close LOC;
+		}
+		return $old_url ? 1 : 0;
+	}
+
+	return 0;
+}
+
+sub update_index($)
+{
+	my $name = shift;
+
+	-d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1;
+	-d "./feeds/$name.tmp/info" or mkdir "./feeds/$name.tmp/info" or return 1;
+
+	system("$mk -s prepare-mk OPENWRT_BUILD= TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
+	system("$mk -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"packageinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"package\" SCAN_DEPS=\"$ENV{TOPDIR}/include/package*.mk\" SCAN_DEPTH=5 SCAN_EXTRA=\"\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
+	system("$mk -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"targetinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"target\" SCAN_DEPS=\"profiles/*.mk $ENV{TOPDIR}/include/target.mk\" SCAN_DEPTH=5 SCAN_EXTRA=\"\" SCAN_MAKEOPTS=\"TARGET_BUILD=1\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
+	system("ln -sf $name.tmp/.packageinfo ./feeds/$name.index");
+	system("ln -sf $name.tmp/.targetinfo ./feeds/$name.targetindex");
+
+	return 0;
+}
+
+my %update_method = (
+	'src-svn' => {
+		'init'		=> "svn checkout '%s' '%s'",
+		'update'	=> "svn update",
+		'controldir'	=> ".svn",
+		'revision'	=> "svn info | grep 'Revision' | cut -d ' ' -f 2 | tr -d '\n'"},
+	'src-cpy' => {
+		'init'		=> "cp -Rf '%s' '%s'",
+		'update'	=> "",
+		'revision'	=> "echo -n 'local'"},
+	'src-link' => {
+		'init'		=> "ln -s '%s' '%s'",
+		'update'	=> "",
+		'revision'	=> "echo -n 'local'"},
+	'src-git' => {
+		'init'          => "git clone --depth 1 '%s' '%s'",
+		'init_branch'   => "git clone --depth 1 --branch '%s' '%s' '%s'",
+		'init_commit'   => "git clone '%s' '%s' && cd '%s' && git checkout -b '%s' '%s' && cd -",
+		'update'	=> "git pull --ff",
+		'controldir'	=> ".git",
+		'revision'	=> "git rev-parse --short HEAD | tr -d '\n'"},
+	'src-git-full' => {
+		'init'          => "git clone '%s' '%s'",
+		'init_branch'   => "git clone --branch '%s' '%s' '%s'",
+		'init_commit'   => "git clone '%s' '%s' && cd '%s' && git checkout -b '%s' '%s' && cd -",
+		'update'	=> "git pull --ff",
+		'controldir'	=> ".git",
+		'revision'	=> "git rev-parse --short HEAD | tr -d '\n'"},
+	'src-gitsvn' => {
+		'init'	=> "git svn clone -r HEAD '%s' '%s'",
+		'update'	=> "git svn rebase",
+		'controldir'	=> ".git",
+		'revision'	=> "git rev-parse --short HEAD | tr -d '\n'"},
+	'src-bzr' => {
+		'init'		=> "bzr checkout --lightweight '%s' '%s'",
+		'update'	=> "bzr update",
+		'controldir'	=> ".bzr"},
+	'src-hg' => {
+		'init'		=> "hg clone '%s' '%s'",
+		'update'	=> "hg pull --update",
+		'controldir'	=> ".hg"},
+	'src-darcs' => {
+		'init'    => "darcs get '%s' '%s'",
+		'update'  => "darcs pull -a",
+		'controldir' => "_darcs"},
+);
+
+# src-git: pull broken
+# src-cpy: broken if `basename $src` != $name
+
+sub update_feed_via($$$$) {
+	my $type = shift;
+	my $name = shift;
+	my $src = shift;
+	my $relocate = shift;
+
+	my $m = $update_method{$type};
+	my $localpath = "./feeds/$name";
+	my $safepath = $localpath;
+	$safepath =~ s/'/'\\''/;
+	my ($base_branch, $branch) = split(/;/, $src, 2);
+	my ($base_commit, $commit) = split(/\^/, $src, 2);
+
+	if( $relocate || !$m->{'update'} || !-d "$localpath/$m->{'controldir'}" ) {
+		system("rm -rf '$safepath'");
+		if ($m->{'init_branch'} and $branch) {
+			system(sprintf($m->{'init_branch'}, $branch, $base_branch, $safepath)) == 0 or return 1;
+		} elsif ($m->{'init_commit'} and $commit) {
+			system(sprintf($m->{'init_commit'}, $base_commit, $safepath, $safepath, $commit, $commit)) == 0 or return 1;
+		} else {
+			system(sprintf($m->{'init'}, $src, $safepath)) == 0 or return 1;
+		}
+	} elsif ($m->{'init_commit'} and $commit) {
+		# in case git hash has been provided don't update the feed
+	} else {
+		system("cd '$safepath'; $m->{'update'}") == 0 or return 1;
+	}
+
+	return 0;
+}
+
+sub get_targets($) {
+	my $file = shift;
+	my @target = parse_target_metadata($file);
+	my %target;
+	foreach my $target (@target) {
+		$target{$target->{id}} = $target;
+	}
+	return %target
+}
+
+sub get_feed($) {
+	my $feed = shift;
+
+	if (!defined($feed_cache{$feed})) {
+		my $file = "./feeds/$feed.index";
+
+		clear_packages();
+		-f $file or do {
+			print "Ignoring feed '$feed' - index missing\n";
+			return;
+		};
+		parse_package_metadata($file) or return;
+		my %target = get_targets("./feeds/$feed.targetindex");
+
+		$feed_cache{$feed} = [ { %package }, { %srcpackage }, { %target } ];
+	}
+
+	$feed_package = $feed_cache{$feed}->[0];
+	$feed_src = $feed_cache{$feed}->[1];
+	$feed_target = $feed_cache{$feed}->[2];
+	return $feed_cache{$feed}->[0];
+}
+
+sub get_installed() {
+	system("$mk -s prepare-tmpinfo OPENWRT_BUILD=");
+	clear_packages();
+	parse_package_metadata("./tmp/.packageinfo");
+	%installed = %package;
+	%installed_targets = get_targets("./tmp/.targetinfo");
+}
+
+sub search_feed {
+	my $feed = shift;
+	my @substr = @_;
+	my $display;
+
+	return unless @substr > 0;
+	get_feed($feed);
+	foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) {
+		my $pkg = $feed_package->{$name};
+		my $substr;
+		my $pkgmatch = 1;
+
+		next if $pkg->{vdepends};
+		foreach my $substr (@substr) {
+			my $match;
+			foreach my $key (qw(name title description src)) {
+				$pkg->{$key} and $substr and $pkg->{$key} =~ m/$substr/i and $match = 1;
+			}
+			$match or undef $pkgmatch;
+		};
+		$pkgmatch and do {
+			$display or do {
+				print "Search results in feed '$feed':\n";
+				$display = 1;
+			};
+			printf "\%-25s\t\%s\n", $pkg->{name}, $pkg->{title};
+		};
+	}
+
+	foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_target) {
+		my $target = $feed_target->{$name};
+		my $targetmatch = 1;
+
+		foreach my $substr (@substr) {
+			my $match;
+			foreach my $key (qw(id name description)) {
+				$target->{$key} and $substr and $target->{$key} =~ m/$substr/i and $match = 1;
+			}
+			$match or undef $targetmatch;
+		};
+		$targetmatch and do {
+			$display or do {
+				print "Search results in feed '$feed':\n";
+				$display = 1;
+			};
+			printf "TARGET: \%-17s\t\%s\n", $target->{id}, $target->{name};
+		};
+	}
+	return 0;
+}
+
+sub search {
+	my %opts;
+
+	getopt('r:', \%opts);
+	foreach my $feed (@feeds) {
+		search_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]);
+	}
+}
+
+sub list_feed {
+	my $feed = shift;
+
+	get_feed($feed);
+	foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) {
+		my $pkg = $feed_package->{$name};
+		next if $pkg->{vdepends};
+		if($pkg->{name}) {
+			printf "\%-32s\t\%s\n", $pkg->{name}, $pkg->{title};
+		}
+	}
+
+	foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_target) {
+		my $target = $feed_target->{$name};
+		if($target->{name}) {
+			printf "TARGET: \%-24s\t\%s\n", $target->{id}, $target->{name};
+		}
+	}
+
+	return 0;
+}
+
+sub list {
+	my %opts;
+
+	getopts('r:d:nshf', \%opts);
+	if ($opts{h}) {
+		usage();
+		return 0;
+	}
+	if ($opts{n}) {
+		foreach my $feed (@feeds) {
+			printf "%s\n", $feed->[1];
+		}
+		return 0;
+	}
+	if ($opts{s}) {
+		foreach my $feed (@feeds) {
+			my $localpath = "./feeds/$feed->[1]";
+			my $m = $update_method{$feed->[0]};
+			my $revision;
+			if (!-d "$localpath" || !$m->{'revision'}) {
+				$revision = "X";
+			}
+			elsif( $m->{'controldir'} && -d "$localpath/$m->{'controldir'}" ) {
+				$revision = `cd '$localpath'; $m->{'revision'}`;
+			}
+			else {
+				$revision = "local";
+			}
+			if ($opts{d}) {
+				printf "%s%s%s%s%s%s%s\n", $feed->[1], $opts{d}, $feed->[0], $opts{d}, $revision, $opts{d}, join(", ", @{$feed->[2]});
+			}
+			elsif ($opts{f}) {
+				my $uri = join(", ", @{$feed->[2]});
+				if ($revision ne "local" && $revision ne "X") {
+					$uri =~ s/[;^].*//;
+					$uri .= "^" . $revision;
+				}
+				printf "%s %s %s\n", $feed->[0], $feed->[1], $uri;
+			}
+			else {
+				printf "\%-10s \%-8s \%-8s \%s\n", $feed->[1], $feed->[0], $revision, join(", ", @{$feed->[2]});
+			}
+		}
+		return 0;
+	}
+	foreach my $feed (@feeds) {
+		list_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]);
+	}
+	return 0;
+}
+
+sub do_install_package($$) {
+	my $feed = shift;
+	my $pkg = shift;
+	my $path = $pkg->{makefile};
+
+	if($path) {
+		$path =~ s/\/Makefile$//;
+
+		-d "./package/feeds" or mkdir "./package/feeds";
+		-d "./package/feeds/$feed->[1]" or mkdir "./package/feeds/$feed->[1]";
+		system("ln -sf ../../../$path ./package/feeds/$feed->[1]/");
+	} else {
+		warn "Package is not valid\n";
+		return 1;
+	}
+
+	return 0;
+}
+
+sub do_install_target($) {
+	my $target = shift;
+	my $path = $target->{makefile};
+
+	if ($path) {
+		$path =~ s/\/Makefile$//;
+		my $name = $path;
+		$name =~ s/.*\///;
+		my $dest = "./target/linux/$name";
+
+		-e $dest and do {
+			warn "Path $dest already exists";
+			return 1;
+		};
+
+		system("ln -sf ../../$path ./target/linux/");
+	} else {
+		warn "Target is not valid\n";
+		return 1;
+	}
+
+	return 0;
+}
+
+sub lookup_package($$) {
+	my $feed = shift;
+	my $package = shift;
+
+	foreach my $feed ($feed, @feeds) {
+		next unless $feed->[1];
+		next unless $feed_cache{$feed->[1]};
+		$feed_cache{$feed->[1]}->[0]->{$package} and return $feed;
+	}
+	return;
+}
+
+sub lookup_target($$) {
+	my $feed = shift;
+	my $target = shift;
+
+	foreach my $feed ($feed, @feeds) {
+		next unless $feed->[1];
+		next unless $feed_cache{$feed->[1]};
+		$feed_cache{$feed->[1]}->[2]->{$target} and return $feed;
+	}
+	return;
+}
+
+sub is_core_package($) {
+	my $package = shift;
+	foreach my $file ("tmp/info/.packageinfo-$package", glob("tmp/info/.packageinfo-*_$package")) {
+		next unless index($file, "tmp/info/.packageinfo-feeds_");
+		return 1 if -s $file;
+	}
+	return 0;
+}
+
+sub install_target {
+	my $feed = shift;
+	my $name = shift;
+
+	$feed = $feed_cache{$feed->[1]}->[2];
+	$feed or return 0;
+
+	my $target = $feed->{$name};
+	$target or return 0;
+
+	warn "Installing target '$name'\n";
+	return do_install_target($target);
+}
+
+sub install_package {
+	my $feed = shift;
+	my $name = shift;
+	my $force = shift;
+	my $ret = 0;
+
+	my $this_feed_target = lookup_target($feed, $name);
+	$this_feed_target and do {
+		$installed_targets{$name} and return 0;
+		install_target($this_feed_target, $name);
+		return 0;
+	};
+
+	$feed = lookup_package($feed, $name);
+	$feed or do {
+		$installed{$name} and return 0;
+		# TODO: check if it's already installed within ./package directory
+		$feed_src->{$name} or is_core_package($name) or warn "WARNING: No feed for package '$name' found, maybe it's already part of the standard packages?\n";
+		return 0;
+	};
+
+	# switch to the metadata for the selected feed
+	my $cur = get_feed($feed->[1]);
+
+	my $pkg = $cur->{$name} or return 1;
+	$pkg->{name} or do {
+		$installed{$name} and return 0;
+		# TODO: check if this is an alias package, maybe it's known by another name
+		warn "WARNING: Package '$name' is not available in feed $feed->[1].\n";
+		return 0;
+	};
+	my $src = $pkg->{src};
+	my $type = $feed->[0];
+	$src or $src = $name;
+
+	# If it's a core package and we don't want to override, just return
+	!$force and is_core_package($src) and return 0;
+
+	# previously installed packages set the runtime package
+	# newly installed packages set the source package to 1
+	$installed{$src} and $installed{$src} == 1 and return 0;
+
+	# we'll trigger the override only with the 3 conditions below:
+	# - override is allowed by command line (-f)
+	# - a package with the same src exists in the core packages list
+	# - the package previously installed is not from a feed
+	my $override = 1 if ($force and is_core_package($src) and !$installed{$name}->{feed});
+
+	# check previously installed packages
+	$installed{$name} and !$override and return 0;
+	$installed{$src} = 1;
+
+	defined($override) and $override == 1
+		and warn "Overriding core package '$src' with version from $feed->[1]\n"
+		or warn "Installing package '$src' from $feed->[1]\n";
+
+	do_install_package($feed, $pkg) == 0 or do {
+		warn "failed.\n";
+		return 1;
+	};
+
+	# install all dependencies referenced from the source package
+	foreach my $vpkg (@{$feed_src->{$src}}) {
+		foreach my $dep (@{$vpkg->{depends}}, @{$vpkg->{builddepends}}, @{$vpkg->{"builddepends/host"}}) {
+			next if $dep =~ /@/;
+			$dep =~ s/^\+//;
+			$dep =~ s/^.+://;
+			$dep =~ s/\/.+$//;
+			next unless $dep;
+			install_package($feed, $dep, 0) == 0 or $ret = 1;
+		}
+	}
+
+	return $ret;
+}
+
+sub refresh_config {
+	my $default = shift;
+
+	# Don't create .config if it doesn't already exist so that making a
+	# config only occurs when the user intends it do (however we do
+	# want to refresh an existing config).
+	return if not (-e '.config');
+
+	# workaround for timestamp check
+	system("rm -f tmp/.packageinfo");
+
+	# refresh the config
+	if ($default) {
+		system("$mk oldconfig CONFDEFAULT=\"$default\" Config.in >/dev/null 2>/dev/null");
+	} else {
+		system("$mk defconfig Config.in >/dev/null 2>/dev/null");
+	}
+}
+
+sub install {
+	my $name;
+	my %opts;
+	my $feed;
+	my $ret = 0;
+
+	getopts('ap:d:fh', \%opts);
+
+	if ($opts{h}) {
+		usage();
+		return 0;
+	}
+
+	get_installed();
+
+	foreach my $f (@feeds) {
+		# fetch all feeds
+		get_feed($f->[1]);
+
+		# look up the preferred feed
+		$opts{p} and $f->[1] eq $opts{p} and $feed = $f;
+	}
+
+	if($opts{a}) {
+		foreach my $f (@feeds) {
+			if (!defined($opts{p}) or $opts{p} eq $f->[1]) {
+				printf "Installing all packages from feed %s.\n", $f->[1];
+				get_feed($f->[1]);
+				foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) {
+					my $p = $feed_package->{$name};
+					next if $p->{vdepends};
+					if( $p->{name} ) {
+						install_package($feed, $p->{name}, exists($opts{f})) == 0 or $ret = 1;
+						get_feed($f->[1]);
+					}
+				}
+			}
+		}
+	} else {
+		while ($name = shift @ARGV) {
+			install_package($feed, $name, exists($opts{f})) == 0 or $ret = 1;
+		}
+	}
+
+	# workaround for timestamp check
+
+	# set the defaults
+	if ($opts{d} and $opts{d} =~ /^[ymn]$/) {
+		refresh_config($opts{d});
+	}
+
+	return $ret;
+}
+
+sub uninstall_target($) {
+	my $dir = shift;
+	my $name = $dir;
+	$name =~ s/.*\///g;
+
+	my $dest = readlink $dir;
+	return unless $dest =~ /..\/..\/feeds/;
+	warn "Uninstalling target '$name'\n";
+	unlink "$dir";
+}
+
+sub uninstall {
+	my %opts;
+	my $name;
+	my $uninstall;
+
+	getopts('ah', \%opts);
+
+	if ($opts{h}) {
+		usage();
+		return 0;
+	}
+
+	if ($opts{a}) {
+		system("rm -rvf ./package/feeds");
+		foreach my $dir (glob "target/linux/*") {
+			next unless -l $dir;
+			uninstall_target($dir);
+		}
+		$uninstall = 1;
+	} else {
+		if($#ARGV == -1) {
+			warn "WARNING: no package to uninstall\n";
+			return 0;
+		}
+		get_installed();
+		while ($name = shift @ARGV) {
+			my $target = "target/linux/$name";
+			-l "$target" and do {
+				uninstall_target($target);
+				$uninstall = 1;
+				next;
+			};
+
+			my $pkg = $installed{$name};
+			$pkg or do {
+				warn "WARNING: $name not installed\n";
+				next;
+			};
+			$pkg->{src} and $name = $pkg->{src};
+			warn "Uninstalling package '$name'\n";
+			system("rm -f ./package/feeds/*/$name");
+			$uninstall = 1;
+		}
+	}
+	$uninstall and refresh_config();
+	return 0;
+}
+
+sub update_feed($$$$)
+{
+	my $type=shift;
+	my $name=shift;
+	my $src=shift;
+	my $perform_update=shift;
+	my $force_relocate=update_location( $name, "@$src" );
+
+	if( $force_relocate ) {
+		warn "Source of feed $name has changed, replacing copy\n";
+	}
+	$update_method{$type} or do {
+		warn "Unknown type '$type' in feed $name\n";
+		return 1;
+	};
+	$perform_update and do {
+		my $failed = 1;
+		foreach my $feedsrc (@$src) {
+			warn "Updating feed '$name' from '$feedsrc' ...\n";
+			next unless update_feed_via($type, $name, $feedsrc, $force_relocate) == 0;
+			$failed = 0;
+			last;
+		}
+		$failed and do {
+			warn "failed.\n";
+			return 1;
+		};
+	};
+	warn "Create index file './feeds/$name.index' \n";
+	update_index($name) == 0 or do {
+		warn "failed.\n";
+		return 1;
+	};
+	return 0;
+}
+
+sub update {
+	my %opts;
+	my $feed_name;
+	my $perform_update=1;
+	my $failed=0;
+
+	$ENV{SCAN_COOKIE} = $$;
+	$ENV{OPENWRT_VERBOSE} = 's';
+
+	getopts('ahi', \%opts);
+
+	if ($opts{h}) {
+		usage();
+		return 0;
+	}
+
+	if ($opts{i}) {
+		# don't update from (remote) repository
+		# only re-create index information
+		$perform_update=0;
+	}
+
+	-d "feeds" or do {
+			mkdir "feeds" or die "Unable to create the feeds directory";
+		};
+
+	if ( ($#ARGV == -1) or $opts{a}) {
+		foreach my $feed (@feeds) {
+			my ($type, $name, $src) = @$feed;
+			update_feed($type, $name, $src, $perform_update) == 0 or $failed=1;
+		}
+	} else {
+		while ($feed_name = shift @ARGV) {
+			foreach my $feed (@feeds) {
+				my ($type, $name, $src) = @$feed;
+				if($feed_name ne $name) {
+					next;
+				}
+				update_feed($type, $name, $src, $perform_update) == 0 or $failed=1;
+			}
+		}
+	}
+
+	refresh_config();
+
+	return $failed;
+}
+
+sub feed_config() {
+	foreach my $feed (@feeds) {
+		my $installed = (-f "feeds/$feed->[1].index");
+
+		printf "\tconfig FEED_%s\n", $feed->[1];
+		printf "\t\tbool \"Enable feed %s\"\n", $feed->[1];
+		printf "\t\tdepends on PER_FEED_REPO\n";
+		printf "\t\tdefault y\n" if $installed;
+		printf "\t\thelp\n";
+		printf "\t\t Enable the \\\"%s\\\" feed at %s.\n", $feed->[1], $feed->[2][0];
+		printf "\n";
+	}
+
+	return 0;
+}
+
+sub usage() {
+	print <<EOF;
+Usage: $0 <command> [options]
+
+Commands:
+	list [options]: List feeds, their content and revisions (if installed)
+	Options:
+	    -n :            List of feed names.
+	    -s :            List of feed names and their URL.
+	    -r <feedname>:  List packages of specified feed.
+	    -d <delimiter>: Use specified delimiter to distinguish rows (default: spaces)
+	    -f :            List feeds in feeds.conf compatible format (when using -s).
+
+	install [options] <package>: Install a package
+	Options:
+	    -a :           Install all packages from all feeds or from the specified feed using the -p option.
+	    -p <feedname>: Prefer this feed when installing packages.
+	    -d <y|m|n>:    Set default for newly installed packages.
+	    -f :           Install will be forced even if the package exists in core OpenWrt (override)
+
+	search [options] <substring>: Search for a package
+	Options:
+	    -r <feedname>: Only search in this feed
+
+	uninstall -a|<package>: Uninstall a package
+	Options:
+	    -a :           Uninstalls all packages.
+
+	update -a|<feedname(s)>: Update packages and lists of feeds in feeds.conf .
+	Options:
+	    -a :           Update all feeds listed within feeds.conf. Otherwise the specified feeds will be updated.
+	    -i :           Recreate the index only. No feed update from repository is performed.
+
+	clean:             Remove downloaded/generated files.
+
+EOF
+	exit(1);
+}
+
+my %commands = (
+	'list' => \&list,
+	'update' => \&update,
+	'install' => \&install,
+	'search' => \&search,
+	'uninstall' => \&uninstall,
+	'feed_config' => \&feed_config,
+	'clean' => sub {
+		system("rm -rf ./feeds ./package/feeds");
+	}
+);
+
+my $arg = shift @ARGV;
+$arg or usage();
+parse_config;
+foreach my $cmd (keys %commands) {
+	$arg eq $cmd and do {
+		exit(&{$commands{$cmd}}());
+	};
+}
+usage();
diff --git a/scripts/flashing/adam2flash-502T.pl b/scripts/flashing/adam2flash-502T.pl
new file mode 100755
index 0000000000..0c4c9d7d5a
--- /dev/null
+++ b/scripts/flashing/adam2flash-502T.pl
@@ -0,0 +1,342 @@
+#!/usr/bin/env perl
+#
+#   D-Link DSL-502T flash utility
+#
+#   Copyright (c) 2007 Oliver Jowett <oliver@opencloud.com>
+#
+#   Based on adam2flash.pl for the D-Link DSL-G6x4T, which is:
+#   Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
+#   based on fbox recovery util by Enrik Berkhan
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+# The default DSL-502T mtd map looks like this:
+#
+# mtd0 0x90091000,0x903f0000    # filesystem
+# mtd1 0x90010090,0x90091000    # kernel
+# mtd2 0x90000000,0x90010000    # bootloader - DO NOT MODIFY
+# mtd3 0x903f0000,0x90400000    # config space - DO NOT MODIFY
+# mtd4 0x90010000,0x903f0000    # firmware signature + kernel + filesystem, used to flash new firmware
+#
+# i.e. the flash layout is:
+#
+# 90000000-9000FFFF mtd2 bootloader
+# 90010000-9001008F ---- firmware signature )
+# 90010090-90090FFF mtd1 kernel             ) mtd4 spans these three regions
+# 90091000-903EFFFF mtd0 filesystem         )
+# 903F0000-903FFFFF mtd3 config space
+#
+# The ADAM2 bootloader uses the mtd1 settings to find the start of the image to boot.
+# The image to load contains information about the loadable size of the image. If ADAM2 sees
+# that the image appears to extend beyond the end of mtd1, it will refuse to load it. On
+# the DSL-502T, this manifests as the USB light blinking rapidly on boot.
+#
+# The OpenWRT kernel does not follow quite the same layout:
+#  (a) it does not have a 0x90-byte firmware signature prefix
+#  (b) it is larger than the default mtd1 size
+#
+# (a) would be avoidable (build a custom image with a 0x90-byte prefix) but (b) is unavoidable.
+# So we *have* to change mtd1. The simplest thing to do seems to make it span all of
+# the flashable area, producing this layout:
+#
+# mtd0 0x90091000,0x903f0000    # filesystem
+# mtd1 0x90010000,0x903f0000    # kernel (CHANGED)
+# mtd2 0x90000000,0x90010000    # bootloader - DO NOT MODIFY
+# mtd3 0x903f0000,0x90400000    # config space - DO NOT MODIFY
+# mtd4 0x90010000,0x903f0000    # kernel + filesystem, used to flash new firmware
+#
+# *** NOTE NOTE NOTE NOTE ***
+#
+# /dev/mtd0 .. /dev/mtd4 when using OpenWRT do **NOT** correspond to the ADAM2 mtd0-4 settings!
+# Instead, OpenWRT scans the MTD itself and determines its own boundaries which are arranged
+# quite differently to ADAM2. It will look something like this, see dmsg on boot:
+#
+# (/dev/mtd0) 0x00000000-0x00010000 : "loader"        # Bootloader, read-only
+# (/dev/mtd1) 0x003f0000-0x00400000 : "config"        # Config space
+# (/dev/mtd2) 0x00010000-0x003f0000 : "linux"         # Firmware area (kernel + root fs + JFFS area)
+# (/dev/mtd3) 0x000d0d58-0x003f0000 : "rootfs"        # Root FS, starts immediately after kernel
+# (/dev/mtd4) 0x00280000-0x003f0000 : "rootfs_data"   # If rootfs is squashfs, start of JFFS area.
+#
+# All of those boundaries are autodetected by examining the data in flash.
+#
+# *** NOTE NOTE NOTE NOTE ***
+
+use IO::Socket::INET;
+use Socket;
+use strict;
+use warnings;
+
+sub usage() {
+	print STDERR "Usage: $0 <ip> [-setmtd1] [-noflash] [firmware.bin]\n\n";
+	print STDERR "Acquires the ADAM2 bootloader of a D-Link DSL-504T at <ip>\n";
+	print STDERR "Power off the device, start this script, then power it on.\n";
+	print STDERR "<ip> may be any spare address on the local subnet.\n\n";
+	print STDERR "If a firmware file is specified, MTD settings are verified and\n";
+	print STDERR "then the firmware is written to the router's flash.\n";
+	print STDERR "The firmware type (D-Link or OpenWRT) is automatically detected.\n\n";
+	print STDERR "  -setmtd1  update mtd1 if it is not the appropriate value for this firmware\n";
+	print STDERR "  -noflash  does normal checks, updates mtd1 if requested, but does not actually write firmware\n\n";
+	exit 0;
+}
+
+my $ip = shift @ARGV;
+$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
+
+my $probe = IO::Socket::INET->new(Proto => 'udp',
+                                  Broadcast => 1,
+                                  LocalPort => 5035) or die "socket: $!";
+my $setip = unpack("N", inet_aton($ip));
+$setip > 0 or usage();
+
+my @packets;
+foreach my $ver ([18, 1], [22, 2]) {
+	push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
+}
+print STDERR "Looking for device: ";
+my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
+my $scanning;
+my $box;
+
+$SIG{"ALRM"} = sub {
+	return if --$scanning <= 0;
+	foreach my $packet (@packets) {
+		$probe->send($packet, 0, $broadcast);
+	}
+	print STDERR ".";
+};
+
+$scanning = 15;
+foreach my $packet (@packets) {
+	$probe->send($packet, 0, $broadcast);
+}
+print STDERR ".";
+
+while($scanning) {
+	my $reply;
+
+	alarm(1);
+	if (my $peer = $probe->recv($reply, 16)) {
+		next if (length($reply) < 16);
+		my ($port, $addr) = sockaddr_in($peer);
+		my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
+		$addr2 = pack("N", $addr2);
+		if ($code == 2) {
+			$scanning = 0;
+			printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2);
+			$box = inet_ntoa($addr);
+		}
+	}
+}
+
+$box or die " not found!\n";
+
+alarm(0);
+
+{
+	package ADAM2FTP;
+	use base qw(Net::FTP);
+	
+	# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
+	sub _USER {
+		shift->command("USER",@_)->response()
+	}
+	
+	sub _GETENV {
+		my $ftp = shift;
+		my ($ok, $name, $value);
+		
+		$ftp->command("GETENV",@_);
+			while(length($ok = $ftp->response()) < 1) {
+			my $line = $ftp->getline();
+			unless (defined($value)) {
+				chomp($line);
+				($name, $value) = split(/\s+/, $line, 2);
+			}
+		}
+		$ftp->debug_print(0, "getenv: $value\n")
+		if $ftp->debug();
+		return $value;
+	}
+	
+	sub getenv {
+		my $ftp = shift;
+		my $name = shift;
+		return $ftp->_GETENV($name);
+	}
+	
+	sub _REBOOT {
+		shift->command("REBOOT")->response() == Net::FTP::CMD_OK
+	}
+	
+	sub reboot {
+		my $ftp = shift;
+		$ftp->_REBOOT;
+		$ftp->close;
+	}
+}
+
+my $file;
+my $arg;
+my $noflash = 0;
+my $setmtd1 = 0;
+while ($arg = shift @ARGV) {
+  if ($arg eq "-noflash") { $noflash = 1; }
+  elsif ($arg eq "-setmtd1") { $setmtd1 = 1; }
+  else { $file = $arg; }
+}
+
+if (!$file) {
+  print STDERR "No firmware file specified, exiting.\n";
+  exit 0;
+}
+
+#
+# Firmware checks
+#
+
+open FILE, "<$file" or die "can't open firmware file\n";
+
+# D-Link firmware starts with "MTD4" little-endian, then has an image header at 0x90
+# OpenWRT firmware just starts with an image header at 0x00
+
+my $signature;
+my $sbytes = read FILE, $signature, 4;
+($sbytes == 4) or die "can't read firmware signature: $!";
+
+my $expectedmtd4 = "0x90010000,0x903f0000";
+my $fwtype;
+my $expectedmtd1;
+
+if ($signature eq "4DTM") {
+  seek FILE, 0x90, 0 or die "can't read firmware signature: $!";
+  $sbytes = read FILE, $signature, 4;
+  ($sbytes == 4) or die "can't read firmware signature: $!";
+  if ($signature eq "\x42\xfa\xed\xfe") {
+    $fwtype = "D-Link (little-endian)";
+    $expectedmtd1 = "0x90010090,0x90091000";
+  } elsif ($signature eq "\xde\xad\xbe\x42") {
+    $fwtype = "D-Link (big-endian)";
+    $expectedmtd1 = "0x90010090,0x90091000";
+  }
+} elsif ($signature eq "\x42\xfa\xed\xfe") {
+  $fwtype = "OpenWRT (little-endian)";
+  $expectedmtd1 = "0x90010000,0x903f0000";
+} elsif ($signature eq "\xde\xad\xbe\x42") {
+  $fwtype = "OpenWRT (big-endian)";
+  $expectedmtd1 = "0x90010000,0x903f0000";
+}
+
+$fwtype or die "Unknown firmware signature (are you sure that's the right firmware?)";
+print STDERR "Firmware type: $fwtype\n";
+
+#
+# Bootloader login
+#
+
+print STDERR "logging into ADAM2 bootloader.. ";
+my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
+$ftp->login("adam2", "adam2") or die "can't login\n";
+print STDERR "ok.\n";
+
+#
+# Hardware checks
+#
+
+print STDERR "checking hardware.. ";
+my $prd = $ftp->getenv("ProductID");
+my $usb = $ftp->getenv("usb_prod");
+print STDERR "$prd / $usb.\n";
+($prd eq "AR7RD" || $prd eq "AR7DB") or die "doesn't look like a DSL-502T?";
+($usb eq "DSL-502T") or die "doesn't look like a DSL-502T?";
+
+#
+# MTD checks and update
+#
+
+print STDERR "checking MTD settings.. ";
+
+my $mtd4 = $ftp->getenv("mtd4");
+($mtd4 eq $expectedmtd4) or die "MTD4 was not as expected (should be '$expectedmtd4', was '$mtd4'). Cowardly refusing to do anything about it!";
+
+# check MTD1 setting and update if needed
+my $mtd1 = $ftp->getenv("mtd1");
+if ($mtd1 ne $expectedmtd1) {
+  die "MTD1 was not as expected (should be '$expectedmtd1', was '$mtd1'). Run with -setmtd1 to reset mtd1" unless ($setmtd1);
+  print STDERR "Setting mtd1.. ";
+  ($ftp->command("SETENV","mtd1,$expectedmtd1")->response() == Net::FTP::CMD_OK) or die "can't set mtd1";
+  $file = shift @ARGV;
+}
+
+print STDERR "ok.\n";
+
+#
+# Firmware size check
+#
+
+my $fwsize = (stat(FILE))[7];
+printf STDERR "Firmware size: 0x%08x\n", $fwsize;
+my $flashsize;
+$mtd4 =~ /^(0x\w+),(0x\w+)$/ and $flashsize = hex($2) - hex($1);
+printf STDERR "Available flash space: 0x%08x\n", $flashsize;
+die "firmware is too large" if ($flashsize < $fwsize);
+
+#
+# Flash it!
+#
+
+if ($noflash) {
+  print STDERR "Not flashing firmware as -noflash was specified.\n";
+  exit 0;
+}
+
+seek FILE, 0, 0, or die "can't seek in firmware: $!";
+
+print STDERR "Preparing to flash.. ";
+($ftp->command("MEDIA FLSH")->response() == Net::FTP::CMD_OK) or die "can't set MEDIA FLSH";
+$ftp->binary() or die "can't set binary mode";
+print STDERR "ok.\n";
+print STDERR "Erasing flash and establishing data connection (this may take a while): ";
+
+my $dc = $ftp->stor("fs mtd4");
+$dc or die "can't open data connection: $!\n";
+print STDERR "ok.\n";
+
+print STDERR "Writing firmware: ";
+while ($fwsize > 0) {
+	my $buffer;
+	my $len = ($fwsize > 1024 ? 1024 : $fwsize);
+
+	my $rbytes = read FILE, $buffer, $len;
+	($rbytes < 0) and die "read error on firmware file: $!";
+	($rbytes == $len) or die "short read on firmware file ($rbytes < $len)";
+
+	my $wbytes = $dc->write($buffer, $len, 600);
+	($wbytes < 0) and die "write error on FTP data connection: $!";
+	($rbytes == $wbytes) or die "short write on FTP data connection ($wbytes < $rbytes)";
+
+	$fwsize -= $len;
+	print STDERR ".";
+}
+
+$dc->close();
+print STDERR " done.\n";
+
+#
+# Reboot
+#
+
+print STDERR "Rebooting device.\n";
+$ftp->reboot();
diff --git a/scripts/flashing/adam2flash-fritzbox.pl b/scripts/flashing/adam2flash-fritzbox.pl
new file mode 100755
index 0000000000..f8d745f678
--- /dev/null
+++ b/scripts/flashing/adam2flash-fritzbox.pl
@@ -0,0 +1,209 @@
+#!/usr/bin/env perl
+#
+#   D-Link DSL-G6x4T flash utility
+#
+#   Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
+#   based on fbox recovery util by Enrik Berkhan
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+use IO::Socket::INET;
+use IO::Select;
+use Socket;
+use strict;
+use warnings;
+
+sub usage() {
+	print STDERR "Usage: $0 <ip> [firmware.bin]\n\n";
+	exit 0;
+}
+
+my $ip = shift @ARGV;
+$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
+
+my $setip = unpack("N", inet_aton($ip));
+$setip > 0 or usage();
+
+my @packets;
+foreach my $ver ([18, 1], [22, 2]) {
+	push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
+}
+print STDERR "Looking for device: ";
+my $scanning;
+my $box;
+
+my $probe = IO::Socket::INET->new(Proto => 'udp',
+                                  Broadcast => 1,
+                                  LocalAddr => $ip,
+                                  LocalPort => 5035) or die "socket: $!";
+my $sel = IO::Select->new($probe);
+my $packet = pack("vCCVNV", 0, 18, 1, 1, 0, 0);
+my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
+
+$probe->send($packet, 0, $broadcast);
+
+
+scan_again:
+print "Looking for Fritz!Box ";
+my @boxes = ();
+my $peer;
+$scanning = 100;
+print "o";
+while($scanning) {
+  my $reply;
+  my @ready;
+
+  if (@ready = $sel->can_read(0.2)) {
+    $peer = $probe->recv($reply, 16);
+    next if (length($reply) < 16);
+    my ($port, $addr) = sockaddr_in($peer);
+    my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
+    $addr2 = pack("N", $addr2);
+    if ($code == 2) {
+      print "O";
+      push @boxes, [$major, $minor1, $minor2, $addr, $addr2];
+      $scanning = 2 if ($scanning > 2);
+    }
+  } else {
+    $scanning--;
+    if (scalar @boxes == 0) {
+      $probe->send($packet, 0, $broadcast);
+      print "o";
+    } else {
+      print ".";
+    }
+  }
+}
+
+if (scalar @boxes == 0) {
+  print " none found, giving up.\n";
+  exit 1;
+} else {
+  print " found!\n";
+}
+
+{
+  package ADAM2FTP;
+  use base qw(Net::FTP);
+  # ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
+  sub _USER { shift->command("USER",@_)->response() }
+  sub _PASV { shift->command("P\@SW")->response() == Net::FTP::CMD_OK }
+  sub _GETENV {
+    my $ftp = shift;
+    my ($ok, $name, $value);
+
+    $ftp->command("GETENV",@_);
+    while(length($ok = $ftp->response()) < 1) {
+      my $line = $ftp->getline();
+      unless (defined($value)) {
+        chomp($line);
+        ($name, $value) = split(/\s+/, $line, 2);
+      }
+    }
+    $ftp->debug_print(0, "getenv: $value\n")
+      if $ftp->debug();
+    return $value;
+  }
+  sub getenv {
+    my $ftp = shift;
+    my $name = shift;
+    return $ftp->_GETENV($name);
+  }
+  sub _REBOOT { shift->command("REBOOT")->response() == Net::FTP::CMD_OK }
+  sub reboot {
+    my $ftp = shift;
+    $ftp->_REBOOT;
+    $ftp->close;
+  }
+  sub check {
+    my $ftp = shift;
+    
+    delete ${*$ftp}{'net_ftp_port'};
+    delete ${*$ftp}{'net_ftp_pasv'};
+
+    my $data = $ftp->_data_cmd('CHECK' ,@_) or return undef;
+    my $sum;
+    if (${${*$ftp}{'net_cmd_resp'}}[0] =~ /^Flash check 0x([0-9A-F]{8})/) {
+      $sum = hex($1);
+    }
+    $data->_close();
+    return $sum;
+  }
+}
+
+# passive mode geht mit Net::FTP nicht, connected zu spaet fuer ADAM2!
+my $ftp = ADAM2FTP->new($ip, Passive => 0, Debug => 0, Timeout => 600)
+  or die "can't FTP ADAM2";
+$ftp->login("adam2", "adam2") or die "can't login adam2";
+$ftp->binary();
+my $pid   = $ftp->getenv('ProductID');
+my $hwrev = $ftp->getenv('HWRevision');
+my $fwrev = $ftp->getenv('firmware_info');
+my $ulrev = $ftp->getenv('urlader-version');
+
+print "Product ID: $pid\n";
+print "Hardware Revision: $hwrev\n";
+print "Urlader  Revision: $ulrev\n";
+print "Firmware Revision: $fwrev\n";
+
+$ftp->hash(\*STDOUT, 64 * 1024);
+
+my $file = shift @ARGV;
+$file || exit 0;
+
+open FILE, "<$file" or die "can't open firmware file\n";
+
+my $mtd0 = $ftp->getenv("mtd0");
+my $mtd1 = $ftp->getenv("mtd1");
+my ($ksize, $fssize);
+
+$mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
+$mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
+$ksize and $fssize or die 'cannot read partition offsets';
+printf STDERR "Available flash space: 0x%08x (0x%08x + 0x%08x)\n", $ksize + $fssize, $ksize, $fssize;
+
+$ftp->command("MEDIA FLSH")->response();
+$ftp->binary();
+print STDERR "Writing to mtd1...\n";
+
+my $dc = $ftp->stor("fs mtd1");
+$dc or die "can't open data connection\n";
+my $rbytes = 1;
+
+while (($ksize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($ksize > 1024 ? 1024 : $ksize);
+	$rbytes = read FILE, $buffer, $len;
+	$rbytes and $ksize -= $dc->write($buffer, $rbytes, 600);
+}
+
+$dc->close();
+$rbytes or die "no more data left to write\n";
+
+print STDERR "Writing to mtd0...\n";
+
+$dc = $ftp->stor("fs mtd0");
+$dc or die "can't open data connection\n";
+
+while (($fssize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($fssize > 1024 ? 1024 : $fssize);
+	$rbytes = read FILE, $buffer, $len;
+	$rbytes and $fssize -= $dc->write($buffer, $rbytes, 600);
+}
+
+$dc->close();
+$ftp->reboot();
diff --git a/scripts/flashing/adam2flash.pl b/scripts/flashing/adam2flash.pl
new file mode 100755
index 0000000000..8550f80a8a
--- /dev/null
+++ b/scripts/flashing/adam2flash.pl
@@ -0,0 +1,174 @@
+#!/usr/bin/env perl
+#
+#   D-Link DSL-G6x4T flash utility
+#
+#   Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
+#   based on fbox recovery util by Enrik Berkhan
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+use IO::Socket::INET;
+use Socket;
+use strict;
+use warnings;
+
+sub usage() {
+	print STDERR "Usage: $0 <ip> [firmware.bin]\n\n";
+	exit 0;
+}
+
+my $ip = shift @ARGV;
+$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
+
+my $probe = IO::Socket::INET->new(Proto => 'udp',
+                                  Broadcast => 1,
+                                  LocalPort => 5035) or die "socket: $!";
+my $setip = unpack("N", inet_aton($ip));
+$setip > 0 or usage();
+
+my @packets;
+foreach my $ver ([18, 1], [22, 2]) {
+	push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
+}
+print STDERR "Looking for device: ";
+my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
+my $scanning;
+my $box;
+
+$SIG{"ALRM"} = sub {
+	return if --$scanning <= 0;
+	foreach my $packet (@packets) {
+		$probe->send($packet, 0, $broadcast);
+	}
+	print STDERR ".";
+};
+
+$scanning = 10;
+foreach my $packet (@packets) {
+	$probe->send($packet, 0, $broadcast);
+}
+print STDERR ".";
+
+while($scanning) {
+	my $reply;
+
+	alarm(1);
+	if (my $peer = $probe->recv($reply, 16)) {
+		next if (length($reply) < 16);
+		my ($port, $addr) = sockaddr_in($peer);
+		my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
+		$addr2 = pack("N", $addr2);
+		if ($code == 2) {
+			$scanning = 0;
+			printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2);
+			$box = inet_ntoa($addr);
+		}
+	}
+}
+
+$box or die " not found!\n";
+
+{
+	package ADAM2FTP;
+	use base qw(Net::FTP);
+	
+	# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
+	sub _USER {
+		shift->command("USER",@_)->response()
+	}
+	
+	sub _GETENV {
+		my $ftp = shift;
+		my ($ok, $name, $value);
+		
+		$ftp->command("GETENV",@_);
+			while(length($ok = $ftp->response()) < 1) {
+			my $line = $ftp->getline();
+			unless (defined($value)) {
+				chomp($line);
+				($name, $value) = split(/\s+/, $line, 2);
+			}
+		}
+		$ftp->debug_print(0, "getenv: $value\n")
+		if $ftp->debug();
+		return $value;
+	}
+	
+	sub getenv {
+		my $ftp = shift;
+		my $name = shift;
+		return $ftp->_GETENV($name);
+	}
+	
+	sub _REBOOT {
+		shift->command("REBOOT")->response() == Net::FTP::CMD_OK
+	}
+	
+	sub reboot {
+		my $ftp = shift;
+		$ftp->_REBOOT;
+		$ftp->close;
+	}
+}
+
+my $file = shift @ARGV;
+$file || exit 0;
+
+open FILE, "<$file" or die "can't open firmware file\n";
+my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
+$ftp->login("adam2", "adam2") or die "can't login\n";
+
+my $mtd0 = $ftp->getenv("mtd0");
+my $mtd1 = $ftp->getenv("mtd1");
+my ($ksize, $fssize);
+
+$mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
+$mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
+$ksize and $fssize or die 'cannot read partition offsets';
+printf STDERR "Available flash space: 0x%08x (0x%08x + 0x%08x)\n", $ksize + $fssize, $ksize, $fssize;
+
+$ftp->command("MEDIA FLSH")->response();
+$ftp->binary();
+print STDERR "Writing to mtd1...\n";
+
+my $dc = $ftp->stor("fs mtd1");
+$dc or die "can't open data connection\n";
+my $rbytes = 1;
+
+while (($ksize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($ksize > 1024 ? 1024 : $ksize);
+	$rbytes = read FILE, $buffer, $len;
+	$rbytes and $ksize -= $dc->write($buffer, $rbytes, 600);
+}
+
+$dc->close();
+$rbytes or die "no more data left to write\n";
+
+print STDERR "Writing to mtd0...\n";
+
+$dc = $ftp->stor("fs mtd0");
+$dc or die "can't open data connection\n";
+
+while (($fssize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($fssize > 1024 ? 1024 : $fssize);
+	$rbytes = read FILE, $buffer, $len;
+	$rbytes and $fssize -= $dc->write($buffer, $rbytes, 600);
+}
+
+$dc->close();
+$ftp->reboot();
diff --git a/scripts/flashing/adsl2mue_flash.pl b/scripts/flashing/adsl2mue_flash.pl
new file mode 100755
index 0000000000..c206c471fd
--- /dev/null
+++ b/scripts/flashing/adsl2mue_flash.pl
@@ -0,0 +1,170 @@
+#!/usr/bin/perl
+#
+#   Linksys ADSL2MUE Flash utility.
+#
+#   Copyright (C) 2008 Alexandre Lissy <alexandrelissy@free.fr>
+#   based on D-Link DSL-G6x4T flash utility by Felix Fietkau <mailto@nbd.name>
+#   based on fbox recovery util by Enrik Berkhan
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+use IO::Socket::INET;
+use Socket;
+use strict;
+use warnings;
+
+sub usage() {
+	print STDERR "Usage: $0 <ip> [firmware.bin] [partition]\n\n";
+	exit 0;
+}
+
+my $ip = shift @ARGV;
+$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
+
+my $probe = IO::Socket::INET->new(Proto => 'udp',
+                                  Broadcast => 1,
+                                  LocalPort => 5035) or die "socket: $!";
+my $setip = unpack("N", inet_aton($ip));
+$setip > 0 or usage();
+
+my @packets;
+foreach my $ver ([18, 1], [22, 2]) {
+	push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
+}
+print STDERR "Looking for device: ";
+my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
+my $scanning;
+my $box;
+
+$SIG{"ALRM"} = sub {
+	return if --$scanning <= 0;
+	foreach my $packet (@packets) {
+		$probe->send($packet, 0, $broadcast);
+	}
+	print STDERR ".";
+};
+
+$scanning = 10;
+foreach my $packet (@packets) {
+	$probe->send($packet, 0, $broadcast);
+}
+print STDERR ".";
+
+while($scanning) {
+	my $reply;
+
+	alarm(1);
+	if (my $peer = $probe->recv($reply, 16)) {
+		next if (length($reply) < 16);
+		my ($port, $addr) = sockaddr_in($peer);
+		my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVN", $reply);
+		$addr2 = pack("N", $addr2);
+		if ($code == 1) {
+			$scanning = 0;
+			printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr2), inet_ntoa($addr);
+			$box = inet_ntoa($addr2);
+		}
+	}
+}
+
+$box or die " not found!\n";
+
+{
+	package ADAM2FTP;
+	use base qw(Net::FTP);
+	
+	# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
+	sub _USER {
+		shift->command("USER",@_)->response()
+	}
+	
+	sub _GETENV {
+		my $ftp = shift;
+		my ($ok, $name, $value);
+		
+		$ftp->command("GETENV",@_);
+			while(length($ok = $ftp->response()) < 1) {
+			my $line = $ftp->getline();
+			unless (defined($value)) {
+				chomp($line);
+				($name, $value) = split(/\s+/, $line, 2);
+			}
+		}
+		$ftp->debug_print(0, "getenv: $value\n")
+		if $ftp->debug();
+		return $value;
+	}
+	
+	sub getenv {
+		my $ftp = shift;
+		my $name = shift;
+		return $ftp->_GETENV($name);
+	}
+	
+	sub _REBOOT {
+		shift->command("REBOOT")->response() == Net::FTP::CMD_OK
+	}
+	
+	sub reboot {
+		my $ftp = shift;
+		$ftp->_REBOOT;
+		$ftp->close;
+	}
+}
+
+my $file = shift @ARGV;
+my $part = shift @ARGV;
+$file || exit 0;
+$part || exit 0;
+
+open FILE, "<$file" or die "can't open firmware file\n";
+my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
+$ftp->login("adam2", "adam2") or die "can't login\n";
+
+# my $mtd0 = $ftp->getenv("mtd0");
+# my $mtd1 = $ftp->getenv("mtd1");
+my $mtd4 = $ftp->getenv($part);
+# my ($ksize, $fssize);
+my ($ossize, $mtd_start, $mtd_end);
+
+# $mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
+# $mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
+$mtd4 =~ /^(0x\w+),(0x\w+)$/;
+$ossize = hex($2) - hex($1);
+$mtd_start = hex($1);
+$mtd_end = hex($2);
+$ossize and $mtd_start and $mtd_end or die 'cannot read partition offsets';
+printf STDERR "Available flash space: 0x%08x ($part: 0x%08x to 0x%08x)\n", $ossize, $mtd_start, $mtd_end;
+
+$ftp->command("MEDIA FLSH")->response();
+$ftp->binary();
+
+print STDERR "Writing to $part ...\n";
+my $dc = $ftp->stor("data $part");
+$dc or die "can't open data connection\n";
+my $rbytes = 1;
+
+while (($ossize > 0) and ($rbytes > 0)) {
+	my $buffer;
+	my $len = ($ossize > 1024 ? 1024 : $ossize);
+	$rbytes = read FILE, $buffer, $len;
+	printf STDERR ".";
+	$rbytes and $ossize -= $dc->write($buffer, $rbytes, 600);
+}
+
+printf STDERR "\nDone.\n";
+
+$dc->close();
diff --git a/scripts/flashing/flash.sh b/scripts/flashing/flash.sh
new file mode 100755
index 0000000000..3499581ef4
--- /dev/null
+++ b/scripts/flashing/flash.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# tftp flash script for wireless routers 
+#
+# Copyright (C) 2004 by Oleg I. Vdovikin <oleg@cs.msu.su>
+# Copyright (C) 2005 by Waldemar Brodkorb <wbx@openwrt.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+if [ -z "$1" ] || [ ! -f $1 ] || [ -z $2 ]; then
+    echo Usage: $0 firmware vendor
+cat << EOF
+IMPORTANT:
+Notes for Linksys / Asus WL500gx router: 
+   be sure you have set boot_wait to yes. Power on your router
+   after executing this script.
+ 
+Notes for Asus WL500g router:
+   be sure POWER led is flashing (If this is not the case
+   poweroff the device, push the reset button & power on
+   it again, then release button)
+
+1) connect your pc to the LAN port
+2) be sure your link is up and has an address in the
+   192.168.1.0/24 address range (and not the 192.168.1.1)
+
+Notes for Toshiba router:
+   boot_wait is enabled by default on these units.
+
+1) connect your pc to any of the four LAN ports
+2) be sure your link is up and has an address in the
+   192.168.10.1/24 address range (and not the 192.168.10.1)
+3) run this script (unit will only accept .trx images)
+4) Turn unit power on.
+
+EOF
+    exit 0
+fi
+if [ "$2" = "asus" ]; then
+echo Confirming IP address setting...
+echo -en "get ASUSSPACELINK\x01\x01\xa8\xc0 /dev/null\nquit\n" | tftp 192.168.1.1
+echo Flashing 192.168.1.1 using $1...
+echo -en "binary\nput $1 ASUSSPACELINK\nquit\n" | tftp 192.168.1.1
+echo Please wait until leds stops flashing. 
+elif [ "$2" = "linksys" ]; then
+echo Flashing 192.168.1.1 using $1...
+echo -en "rexmt 1\ntrace\nbinary\nput $1\nquit\n" | tftp 192.168.1.1
+echo Please wait until power led stops flashing. Do not poweroff! Then you can login via telnet 192.168.1.1.
+elif [ "$2" = "toshiba" ]; then
+echo Flashing 192.168.10.1 using $1...
+echo -en "rexmt 1\ntrace\nbinary\nput $1\nquit\n" | tftp 192.168.10.1
+echo Unit will automatically reboot within 5 minutes.  Do not power off.  Then you can login via telnet 192.168.10.1.
+fi
diff --git a/scripts/flashing/jungo-image.py b/scripts/flashing/jungo-image.py
new file mode 100755
index 0000000000..9947e7c720
--- /dev/null
+++ b/scripts/flashing/jungo-image.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, 2009 (C) Jose Vasconcellos <jvasco@verizon.net>
+#
+# A script that can communicate with jungo-based routers
+# (such as MI424-WR, USR8200 and WRV54G) to backup the installed
+# firmware and replace the boot loader.
+#
+# Tested with Python 2.5 on Linux and Windows
+#
+"""Usage: %s [options] <IP_address> [image.bin | url]
+Valid options:
+\t-h | --help: usage statement
+\t-d | --dump: create a flash dump
+\t-f | --file: use <filename> to store dump contents
+\t-u | --user: provide username (default admin)
+\t-p | --pass: provide password (default password1)
+\t     --port: set port for http (default 8080)
+\t-q | --quiet: don't display unnecessary information
+\t-r | --reboot: reboot target on successful transfer
+\t-V | --version: display version information
+
+If no image (or url) is given, a flash dump is created.
+A built-in http server is used when an image file is provided.
+"""
+
+import os
+import sys
+import getopt
+import getpass
+import telnetlib
+import string
+import binascii
+import socket
+import thread
+import SocketServer
+import SimpleHTTPServer
+
+reboot = 0
+HOST = "192.168.1.1"
+PORT = 8080
+user = "admin"
+#password = getpass.getpass()
+password = "password1"
+proto = "http"
+url = ""
+imagefile = ""
+dumpfile = ""
+verbose = 1
+do_dump = 0
+dumplen = 0x10000
+flashsize=4*1024*1024
+#device="br0"
+device="ixp0"
+
+####################
+
+def start_server(server):
+    httpd = SocketServer.TCPServer((server,PORT),SimpleHTTPServer.SimpleHTTPRequestHandler)
+    thread.start_new_thread(httpd.serve_forever,())
+
+####################
+
+def get_flash_size():
+    # make sure we don't have an A0 stepping
+    tn.write("cat /proc/cpuinfo\n")
+    buf = tn.read_until("Returned 0", 3)
+    if not buf:
+        print "Unable to obtain CPU information; make sure to not use A0 stepping!"
+    elif buf.find('rev 0') > 0:
+        print "Warning: IXP42x stepping A0 detected!"
+        if imagefile or url:
+            print "Error: No linux support for A0 stepping!"
+            sys.exit(2)
+
+    # now get flash size
+    tn.write("cat /proc/mtd\n")
+    buf = tn.read_until("Returned 0", 3)
+    if buf:
+        i = buf.find('mtd0:')
+        if i > 0:
+            return int(buf[i+6:].split()[0],16)
+        # use different command
+        tn.write("flash_layout\n")
+        buf = tn.read_until("Returned 0", 3)
+        i = buf.rfind('Range ')
+        if i > 0:
+            return int(buf[i+17:].split()[0],16)
+        print "Can't determine flash size!"
+    else:
+        print "Unable to obtain flash size!"
+    sys.exit(2)
+
+def image_dump(tn, dumpfile):
+    if not dumpfile:
+        tn.write("ver\n");
+        buf = tn.read_until("Returned 0",2)
+        i = buf.find("Platform:")
+        if i < 0:
+	    platform="jungo"
+	else:
+	    line=buf[i+9:]
+	    i=line.find('\n')
+	    platform=line[:i].split()[-1]
+
+        tn.write("rg_conf_print /dev/%s/mac\n" % device);
+        buf = tn.read_until("Returned 0",3)
+
+	i = buf.find("mac(")
+	if i > 0:
+	    i += 4
+	else:
+	    print "No MAC address found! (use -f option)"
+	    sys.exit(1)
+        dumpfile = "%s-%s.bin" % (platform, buf[i:i+17].replace(':',''))
+    else:
+        tn.write("\n")
+
+    print "Dumping flash contents (%dMB) to %s" % (flashsize/1048576, dumpfile)
+    f = open(dumpfile, "wb")
+
+    t=flashsize/dumplen
+    for addr in range(t):
+	if verbose:
+	    sys.stdout.write('\r%d%%'%(100*addr/t))
+	    sys.stdout.flush()
+
+        tn.write("flash_dump -r 0x%x -l %d -4\n" % (addr*dumplen, dumplen))
+	tn.read_until("\n")
+
+	count = addr*dumplen
+        while 1:
+            buf = tn.read_until("\n")
+            if buf.strip() == "Returned 0":
+                break
+            s = buf.split()
+            if s and s[0][-1] == ':':
+		a=int(s[0][:-1],16)
+		if a != count:
+		    print "Format error: %x != %x"%(a,count)
+		    sys.exit(2)
+	    	count += 16
+		f.write(binascii.a2b_hex(string.join(s[1:],'')))
+	tn.read_until(">",1)
+
+    f.close()
+    if verbose:
+	print ""
+
+def telnet_option(sock,cmd,option):
+    #print "Option: %d %d" % (ord(cmd), ord(option))
+    if cmd == telnetlib.DO:
+        c=telnetlib.WILL
+    elif cmd == telnetlib.WILL:
+        c=telnetlib.DO
+    sock.sendall(telnetlib.IAC + c + option)
+
+def telnet_timeout():
+    print "Fatal error: telnet timeout!"
+    sys.exit(1)
+
+def usage():
+    print __doc__ % os.path.basename(sys.argv[0])
+
+####################
+
+try:
+    opts, args = getopt.getopt(sys.argv[1:], "hdf:qp:P:rvV", \
+	["help", "dump", "file=", "user=", "pass=", "port=",
+	 "quiet=", "reboot", "verbose", "version"])
+except getopt.GetoptError:
+    # print help information and exit:
+    usage()
+    sys.exit(1)
+
+for o, a in opts:
+    if o in ("-h", "--help"):
+	usage()
+	sys.exit(1)
+    elif o in ("-V", "--version"):
+	print "%s: 0.11" % sys.argv[0]
+	sys.exit(1)
+    elif o in ("-d", "--no-dump"):
+	do_dump = 1
+    elif o in ("-f", "--file"):
+	dumpfile = a
+    elif o in ("-u", "--user"):
+	user = a
+    elif o in ("-p", "--pass"):
+	password = a
+    elif o == "--port":
+	PORT = int(a)
+    elif o in ("-q", "--quiet"):
+	verbose = 0
+    elif o in ("-r", "--reboot"):
+	reboot = 1
+    elif o in ("-v", "--verbose"):
+	verbose = 1
+
+# make sure we have enough arguments
+if len(args) > 0:
+    HOST = args[0]
+
+if len(args) == 2:
+    if args[1].split(':')[0] in ("tftp", "http", "ftp"):
+        url = args[1]
+    else:
+        imagefile = args[1]
+else:
+    do_dump = 1;
+
+####################
+# create a telnet session to the router
+try:
+    tn = telnetlib.Telnet(HOST)
+except socket.error, msg:
+    print "Unable to establish telnet session to %s: %s" % (HOST, msg)
+    sys.exit(1)
+
+tn.set_option_negotiation_callback(telnet_option)
+
+buf = tn.read_until("Username: ", 3)
+if not buf:
+    telnet_timeout()
+tn.write(user+"\n")
+if password:
+    buf = tn.read_until("Password: ", 3)
+    if not buf:
+        telnet_timeout()
+    tn.write(password+"\n")
+
+# wait for prompt
+buf = tn.read_until("> ", 3)
+if not buf:
+    telnet_timeout()
+
+flashsize = get_flash_size()
+
+if do_dump:
+    image_dump(tn, dumpfile)
+
+if imagefile or url:
+    splitpath = os.path.split(imagefile)
+
+    # create load command
+    if url:
+        cmd = "load -u %s -r 0\n" % (url)
+    else:
+        server = tn.get_socket().getsockname()[0]
+        cmd = "load -u http://%s:%d/%s -r 0\n" % (server, PORT, splitpath[1])
+
+        if not os.access(imagefile, os.R_OK):
+            print "File access error: %s" % (imagefile)
+            sys.exit(3)
+
+        # make sure we're in the directory where the image is located
+        if splitpath[0]:
+            os.chdir(splitpath[0])
+
+        start_server(server)
+
+    if verbose:
+	print "Unlocking flash..."
+    tn.write("unlock 0 0x%x\n" % flashsize)
+    buf = tn.read_until("Returned 0",5)
+
+    if verbose:
+	print "Writing new image..."
+    print cmd,
+    tn.write(cmd)
+    buf = tn.read_until("Returned 0",10)
+
+    # wait till the transfer completed
+    buf = tn.read_until("Download completed successfully",20)
+    if buf:
+	print "Flash update complete!"
+        if reboot:
+            tn.write("reboot\n")
+            print "Rebooting..."
+
+tn.write("exit\n")
+tn.close()
+
diff --git a/scripts/gen-dependencies.sh b/scripts/gen-dependencies.sh
new file mode 100755
index 0000000000..c6b6f75f55
--- /dev/null
+++ b/scripts/gen-dependencies.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+SELF=${0##*/}
+
+READELF="${READELF:-readelf}"
+OBJCOPY="${OBJCOPY:-objcopy}"
+TARGETS=$*
+XARGS="${XARGS:-xargs -r}"
+
+[ -z "$TARGETS" ] && {
+  echo "$SELF: no directories / files specified"
+  echo "usage: $SELF [PATH...]"
+  exit 1
+}
+
+find $TARGETS -type f -a -exec file {} \; | \
+  sed -n -e 's/^\(.*\):.*ELF.*\(executable\|shared object\).*,.* stripped/\1/p' | \
+  $XARGS -n1 $READELF -d | \
+  awk '$2 ~ /NEEDED/ && $NF !~ /interpreter/ && $NF ~ /^\[?lib.*\.so/ { gsub(/[\[\]]/, "", $NF); print $NF }' | \
+  sort -u
+
+tmp=`mktemp $TMP_DIR/dep.XXXXXXXX`
+for kmod in `find $TARGETS -type f -name \*.ko`; do
+	$OBJCOPY -O binary -j .modinfo $kmod $tmp
+	sed -e 's,\x00,\n,g' $tmp | \
+		sed -ne '/^depends=.\+/ { s/^depends=//; s/,/.ko\n/g; s/$/.ko/p; q }'
+done | sort -u
+rm -f $tmp
diff --git a/scripts/get_source_date_epoch.sh b/scripts/get_source_date_epoch.sh
new file mode 100755
index 0000000000..ea8d930109
--- /dev/null
+++ b/scripts/get_source_date_epoch.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+export LANG=C
+export LC_ALL=C
+[ -n "$TOPDIR" ] && cd $TOPDIR
+
+try_version() {
+	[ -f version.date ] || return 1
+	SOURCE_DATE_EPOCH="$(cat version.date)"
+	[ -n "$SOURCE_DATE_EPOCH" ]
+}
+
+try_git() {
+	[ -e .git ] || return 1
+	SOURCE_DATE_EPOCH="$(git log -1 --format=format:%ct)"
+	[ -n "$SOURCE_DATE_EPOCH" ]
+}
+
+try_hg() {
+	[ -d .hg ] || return 1
+	SOURCE_DATE_EPOCH=""
+	[ -n "$SOURCE_DATE_EPOCH" ]
+}
+
+try_version || try_git || try_hg || SOURCE_DATE_EPOCH=""
+echo "$SOURCE_DATE_EPOCH"
diff --git a/scripts/getver.sh b/scripts/getver.sh
new file mode 100755
index 0000000000..e6693bf6d0
--- /dev/null
+++ b/scripts/getver.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+export LANG=C
+export LC_ALL=C
+[ -n "$TOPDIR" ] && cd $TOPDIR
+
+GET_REV=$1
+
+try_version() {
+	[ -f version ] || return 1
+	REV="$(cat version)"
+	[ -n "$REV" ]
+}
+
+try_git() {
+	REBOOT=f0237bfe997ba0d8f3344be6e0f0e4763410b73d
+	git rev-parse --git-dir >/dev/null 2>&1 || return 1
+
+	[ -n "$GET_REV" ] || GET_REV="HEAD"
+
+	case "$GET_REV" in
+	r*)
+		GET_REV="$(echo $GET_REV | tr -d 'r')"
+		BASE_REV="$(git rev-list ${REBOOT}..HEAD | wc -l | awk '{print $1}')"
+		REV="$(git rev-parse HEAD~$((BASE_REV - GET_REV)))"
+		;;
+	*)
+		BRANCH="$(git rev-parse --abbrev-ref HEAD)"
+		ORIGIN="$(git rev-parse --verify --symbolic-full-name ${BRANCH}@{u} 2>/dev/null)"
+		[ -n "$ORIGIN" ] || ORIGIN="$(git rev-parse --verify --symbolic-full-name master@{u} 2>/dev/null)"
+		REV="$(git rev-list ${REBOOT}..$GET_REV | wc -l | awk '{print $1}')"
+
+		if [ -n "$ORIGIN" ]; then
+			UPSTREAM_BASE="$(git merge-base $GET_REV $ORIGIN)"
+			UPSTREAM_REV="$(git rev-list ${REBOOT}..$UPSTREAM_BASE | wc -l | awk '{print $1}')"
+		else
+			UPSTREAM_REV=0
+		fi
+
+		if [ "$REV" -gt "$UPSTREAM_REV" ]; then
+			REV="${UPSTREAM_REV}+$((REV - UPSTREAM_REV))"
+		fi
+
+		REV="${REV:+r$REV-$(git log --format="%h" -1)}"
+		;;
+	esac
+
+	[ -n "$REV" ]
+}
+
+try_hg() {
+	[ -d .hg ] || return 1
+	REV="$(hg log -r-1 --template '{desc}' | awk '{print $2}' | sed 's/\].*//')"
+	REV="${REV:+r$REV}"
+	[ -n "$REV" ]
+}
+
+try_version || try_git || try_hg || REV="unknown"
+echo "$REV"
diff --git a/scripts/ipkg-build b/scripts/ipkg-build
new file mode 100755
index 0000000000..845a6ed04e
--- /dev/null
+++ b/scripts/ipkg-build
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+# ipkg-build -- construct a .ipk from a directory
+# Carl Worth <cworth@east.isi.edu>
+# based on a script by Steve Redler IV, steve@sr-tech.com 5-21-2001
+# 2003-04-25 rea@sr.unh.edu
+#   Updated to work on Familiar Pre0.7rc1, with busybox tar.
+#   Note it Requires: binutils-ar (since the busybox ar can't create)
+#   For UID debugging it needs a better "find".
+set -e
+
+version=1.0
+FIND="$(which find)"
+FIND="${FIND:-$(which gfind)}"
+TAR="${TAR:-$(which tar)}"
+GZIP="$(which gzip)"
+
+# look up date of last commit
+if [ -d "$TOPDIR/.git" ]; then
+	GIT="$(which git)"
+	TIMESTAMP=$(cd $TOPDIR; $GIT log -1 -s --format=%ci)
+elif [ -d "$TOPDIR/.svn" ]; then
+	SVN="$(which svn)"
+	TIMESTAMP=$($SVN info "$TOPDIR" | sed -n "s/^Last Changed Date: \(.*\)/\1/p")
+else
+	TIMESTAMP=$(date)
+fi
+
+ipkg_extract_value() {
+	sed -e "s/^[^:]*:[[:space:]]*//"
+}
+
+required_field() {
+	field=$1
+
+	grep "^$field:" < $CONTROL/control | ipkg_extract_value
+}
+
+pkg_appears_sane() {
+	local pkg_dir=$1
+
+	local owd=$PWD
+	cd $pkg_dir
+
+	PKG_ERROR=0
+	pkg=`required_field Package`
+	version=`required_field Version | sed 's/Version://; s/^.://g;'`
+	arch=`required_field Architecture`
+
+	if echo $pkg | grep '[^a-zA-Z0-9_.+-]'; then
+		echo "*** Error: Package name $name contains illegal characters, (other than [a-z0-9.+-])" >&2
+		PKG_ERROR=1;
+	fi
+
+	if [ -f $CONTROL/conffiles ]; then
+		rm -f $CONTROL/conffiles.resolved
+
+		for cf in `$FIND $(sed -e "s!^/!$pkg_dir/!" $CONTROL/conffiles) -type f`; do
+			echo "${cf#$pkg_dir}" >> $CONTROL/conffiles.resolved
+		done
+
+		rm $CONTROL/conffiles
+		mv $CONTROL/conffiles.resolved $CONTROL/conffiles
+		chmod 0644 $CONTROL/conffiles
+	fi
+
+	cd $owd
+	return $PKG_ERROR
+}
+
+###
+# ipkg-build "main"
+###
+ogargs=""
+noclean=0
+usage="Usage: $0 [-c] [-C] [-o owner] [-g group] <pkg_directory> [<destination_directory>]"
+while getopts "cg:ho:v" opt; do
+    case $opt in
+	o ) owner=$OPTARG
+	    ogargs="--owner=$owner"
+	    ;;
+	g ) group=$OPTARG
+	    ogargs="$ogargs --group=$group"
+	    ;;
+	c ) ;;
+	C ) noclean=1;;
+	v ) echo $version
+	    exit 0
+	    ;;
+	h ) 	echo $usage  >&2 ;;
+	\? ) 	echo $usage  >&2
+	esac
+done
+
+
+shift $(($OPTIND - 1))
+
+# continue on to process additional arguments
+
+case $# in
+1)
+	dest_dir=$PWD
+	;;
+2)
+	dest_dir=$2
+	if [ "$dest_dir" = "." -o "$dest_dir" = "./" ] ; then
+	    dest_dir=$PWD
+	fi
+	;;
+*)
+	echo $usage >&2
+	exit 1 
+	;;
+esac
+
+pkg_dir=$1
+
+if [ ! -d $pkg_dir ]; then
+	echo "*** Error: Directory $pkg_dir does not exist" >&2
+	exit 1
+fi
+
+# CONTROL is second so that it takes precedence
+CONTROL=
+[ -d $pkg_dir/CONTROL ] && CONTROL=CONTROL
+if [ -z "$CONTROL" ]; then
+	echo "*** Error: Directory $pkg_dir has no CONTROL subdirectory." >&2
+	exit 1
+fi
+
+if ! pkg_appears_sane $pkg_dir; then
+	echo >&2
+	echo "ipkg-build: Please fix the above errors and try again." >&2
+	exit 1
+fi
+
+tmp_dir=$dest_dir/IPKG_BUILD.$$
+mkdir $tmp_dir
+
+echo $CONTROL > $tmp_dir/tarX
+# Preserve permissions (-p) when creating data.tar.gz as non-root user
+( cd $pkg_dir && $TAR $ogargs -X $tmp_dir/tarX --format=gnu --sort=name -cpf -  --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/data.tar.gz )
+
+installed_size=`stat -c "%s" $tmp_dir/data.tar.gz`
+sed -i -e "s/^Installed-Size: .*/Installed-Size: $installed_size/" \
+	$pkg_dir/$CONTROL/control
+
+( cd $pkg_dir/$CONTROL && $TAR $ogargs --format=gnu --sort=name -cf -  --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/control.tar.gz )
+rm $tmp_dir/tarX
+
+echo "2.0" > $tmp_dir/debian-binary
+
+pkg_file=$dest_dir/${pkg}_${version}_${arch}.ipk
+rm -f $pkg_file
+( cd $tmp_dir && $TAR $ogargs --format=gnu --sort=name -cf -  --mtime="$TIMESTAMP" ./debian-binary ./data.tar.gz ./control.tar.gz | $GZIP -n - > $pkg_file )
+
+rm $tmp_dir/debian-binary $tmp_dir/data.tar.gz $tmp_dir/control.tar.gz
+rmdir $tmp_dir
+
+echo "Packaged contents of $pkg_dir into $pkg_file"
diff --git a/scripts/ipkg-make-index.sh b/scripts/ipkg-make-index.sh
new file mode 100755
index 0000000000..1822227413
--- /dev/null
+++ b/scripts/ipkg-make-index.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+set -e
+
+pkg_dir=$1
+
+if [ -z $pkg_dir ] || [ ! -d $pkg_dir ]; then
+	echo "Usage: ipkg-make-index <package_directory>" >&2
+	exit 1
+fi
+
+which md5sum >/dev/null 2>&1 || alias md5sum=md5
+empty=1
+
+for pkg in `find $pkg_dir -name '*.ipk' | sort`; do
+	empty=
+	name="${pkg##*/}"
+	name="${name%%_*}"
+	[[ "$name" = "kernel" ]] && continue
+	[[ "$name" = "libc" ]] && continue
+	echo "Generating index for package $pkg" >&2
+	file_size=$(ls -l $pkg | awk '{print $5}')
+	md5sum=$(md5sum $pkg | awk '{print $1}')
+	sha256sum=$(openssl dgst -sha256 $pkg | awk '{print $2}')
+	# Take pains to make variable value sed-safe
+	sed_safe_pkg=`echo $pkg | sed -e 's/^\.\///g' -e 's/\\//\\\\\\//g'`
+	tar -xzOf $pkg ./control.tar.gz | tar xzOf - ./control | sed -e "s/^Description:/Filename: $sed_safe_pkg\\
+Size: $file_size\\
+MD5Sum: $md5sum\\
+SHA256sum: $sha256sum\\
+Description:/"
+	echo ""
+done
+[ -n "$empty" ] && echo
+exit 0
diff --git a/scripts/kconfig.pl b/scripts/kconfig.pl
new file mode 100755
index 0000000000..6a6bbd2747
--- /dev/null
+++ b/scripts/kconfig.pl
@@ -0,0 +1,182 @@
+#!/usr/bin/env perl
+# 
+# Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+use warnings;
+use strict;
+
+my @arg;
+my $PREFIX = "CONFIG_";
+
+sub set_config($$$$) {
+	my $config = shift;
+	my $idx = shift;
+	my $newval = shift;
+	my $mod_plus = shift;
+
+	if (!defined($config->{$idx}) or !$mod_plus or
+	    $config->{$idx} eq '#undef' or $newval eq 'y') {
+		$config->{$idx} = $newval;
+	}
+}
+
+sub load_config($$) {
+	my $file = shift;
+	my $mod_plus = shift;
+	my %config;
+
+	open FILE, "$file" or die "can't open file '$file'";
+	while (<FILE>) {
+		chomp;
+		/^$PREFIX(.+?)=(.+)/ and do {
+			set_config(\%config, $1, $2, $mod_plus);
+			next;
+		};
+		/^# $PREFIX(.+?) is not set/ and do {
+			set_config(\%config, $1, "#undef", $mod_plus);
+			next;
+		};
+		/^#/ and next;
+		/^(.+)$/ and warn "WARNING: can't parse line: $1\n";
+	}
+	return \%config;
+}
+
+
+sub config_and($$) {
+	my $cfg1 = shift;
+	my $cfg2 = shift;
+	my %config;
+
+	foreach my $config (keys %$cfg1) {
+		my $val1 = $cfg1->{$config};
+		my $val2 = $cfg2->{$config};
+		$val2 and ($val1 eq $val2) and do {
+			$config{$config} = $val1;
+		};
+	}
+	return \%config;
+}
+
+
+sub config_add($$$) {
+	my $cfg1 = shift;
+	my $cfg2 = shift;
+	my $mod_plus = shift;
+	my %config;
+	
+	for ($cfg1, $cfg2) {
+		my %cfg = %$_;
+		
+		foreach my $config (keys %cfg) {
+			if ($mod_plus and $config{$config}) {
+				next if $config{$config} eq "y";
+				next if $cfg{$config} eq '#undef';
+			}
+			$config{$config} = $cfg{$config};
+		}
+	}
+	return \%config;
+}
+
+sub config_diff($$$) {
+	my $cfg1 = shift;
+	my $cfg2 = shift;
+	my $new_only = shift;
+	my %config;
+	
+	foreach my $config (keys %$cfg2) {
+		if (!defined($cfg1->{$config}) or $cfg1->{$config} ne $cfg2->{$config}) {
+			next if $new_only and !defined($cfg1->{$config}) and $cfg2->{$config} eq '#undef';
+			$config{$config} = $cfg2->{$config};
+		}
+	}
+	return \%config
+}
+
+sub config_sub($$) {
+	my $cfg1 = shift;
+	my $cfg2 = shift;
+	my %config = %{$cfg1};
+	
+	foreach my $config (keys %$cfg2) {
+		delete $config{$config};
+	}
+	return \%config;
+}
+
+sub print_cfgline($$) {
+	my $name = shift;
+	my $val = shift;
+	if ($val eq '#undef' or $val eq 'n') {
+		print "# $PREFIX$name is not set\n";
+	} else {
+		print "$PREFIX$name=$val\n";
+	}
+}
+
+
+sub dump_config($) {
+	my $cfg = shift;
+	die "argument error in dump_config" unless ($cfg);
+	my %config = %$cfg;
+	foreach my $config (sort keys %config) {
+		print_cfgline($config, $config{$config});
+	}
+}
+
+sub parse_expr {
+	my $pos = shift;
+	my $mod_plus = shift;
+	my $arg = $arg[$$pos++];
+
+	die "Parse error" if (!$arg);
+
+	if ($arg eq '&') {
+		my $arg1 = parse_expr($pos);
+		my $arg2 = parse_expr($pos);
+		return config_and($arg1, $arg2);
+	} elsif ($arg =~ /^\+/) {
+		my $arg1 = parse_expr($pos);
+		my $arg2 = parse_expr($pos);
+		return config_add($arg1, $arg2, 0);
+	} elsif ($arg =~ /^m\+/) {
+		my $arg1 = parse_expr($pos);
+		my $arg2 = parse_expr($pos, 1);
+		return config_add($arg1, $arg2, 1);
+	} elsif ($arg eq '>') {
+		my $arg1 = parse_expr($pos);
+		my $arg2 = parse_expr($pos);
+		return config_diff($arg1, $arg2, 0);
+	} elsif ($arg eq '>+') {
+		my $arg1 = parse_expr($pos);
+		my $arg2 = parse_expr($pos);
+		return config_diff($arg1, $arg2, 1);
+	} elsif ($arg eq '-') {
+		my $arg1 = parse_expr($pos);
+		my $arg2 = parse_expr($pos);
+		return config_sub($arg1, $arg2);
+	} else {
+		return load_config($arg, $mod_plus);
+	}
+}
+
+while (@ARGV > 0 and $ARGV[0] =~ /^-\w+$/) {
+	my $cmd = shift @ARGV;
+	if ($cmd =~ /^-n$/) {
+		$PREFIX = "";
+	} elsif ($cmd =~ /^-p$/) {
+		$PREFIX = shift @ARGV;
+	} else {
+		die "Invalid option: $cmd\n";
+	}
+}
+@arg = @ARGV;
+
+my $pos = 0;
+dump_config(parse_expr(\$pos));
+die "Parse error" if ($arg[$pos]);
diff --git a/scripts/make-ipkg-dir.sh b/scripts/make-ipkg-dir.sh
new file mode 100755
index 0000000000..529e430ad9
--- /dev/null
+++ b/scripts/make-ipkg-dir.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+BASE=http://svn.openwrt.org/openwrt/trunk/openwrt
+TARGET=$1
+CONTROL=$2
+VERSION=$3
+ARCH=$4
+
+WD=$(pwd)
+
+mkdir -p "$TARGET/CONTROL"
+grep '^[^(Version|Architecture)]' "$CONTROL" > "$TARGET/CONTROL/control"
+grep '^Maintainer' "$CONTROL" 2>&1 >/dev/null || \
+        echo "Maintainer: LEDE Community <lede-dev@lists.infradead.org>" >> "$TARGET/CONTROL/control"
+grep '^Source' "$CONTROL" 2>&1 >/dev/null || {
+        pkgbase=$(echo "$WD" | sed -e "s|^$TOPDIR/||g")
+        [ "$pkgbase" = "$WD" ] && src="N/A" || src="$BASE/$pkgbase"
+        echo "Source: $src" >> "$TARGET/CONTROL/control"
+}
+echo "Version: $VERSION" >> "$TARGET/CONTROL/control"
+echo "Architecture: $ARCH" >> "$TARGET/CONTROL/control"
+chmod 644 "$TARGET/CONTROL/control"
diff --git a/scripts/md5sum b/scripts/md5sum
new file mode 100755
index 0000000000..a5779c42e6
--- /dev/null
+++ b/scripts/md5sum
@@ -0,0 +1,2 @@
+#!/bin/sh
+cat "$@" | md5
diff --git a/scripts/metadata.pm b/scripts/metadata.pm
new file mode 100644
index 0000000000..8334f26d31
--- /dev/null
+++ b/scripts/metadata.pm
@@ -0,0 +1,270 @@
+package metadata;
+use base 'Exporter';
+use strict;
+use warnings;
+our @EXPORT = qw(%package %srcpackage %category %subdir %preconfig %features %overrides clear_packages parse_package_metadata parse_target_metadata get_multiline @ignore);
+
+our %package;
+our %preconfig;
+our %srcpackage;
+our %category;
+our %subdir;
+our %features;
+our %overrides;
+our @ignore;
+
+sub get_multiline {
+	my $fh = shift;
+	my $prefix = shift;
+	my $str;
+	while (<$fh>) {
+		last if /^@@/;
+		$str .= (($_ and $prefix) ? $prefix . $_ : $_);
+	}
+
+	return $str ? $str : "";
+}
+
+sub confstr($) {
+	my $conf = shift;
+	$conf =~ tr#/\.\-/#___#;
+	return $conf;
+}
+
+sub parse_target_metadata($) {
+	my $file = shift;
+	my ($target, @target, $profile);
+	my %target;
+	my $makefile;
+
+	open FILE, "<$file" or do {
+		warn "Can't open file '$file': $!\n";
+		return;
+	};
+	while (<FILE>) {
+		chomp;
+		/^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and $makefile = $1;
+		/^Target:\s*(.+)\s*$/ and do {
+			my $name = $1;
+			$target = {
+				id => $name,
+				board => $name,
+				makefile => $makefile,
+				boardconf => confstr($name),
+				conf => confstr($name),
+				profiles => [],
+				features => [],
+				depends => [],
+				subtargets => []
+			};
+			push @target, $target;
+			$target{$name} = $target;
+			if ($name =~ /([^\/]+)\/([^\/]+)/) {
+				push @{$target{$1}->{subtargets}}, $2;
+				$target->{board} = $1;
+				$target->{boardconf} = confstr($1);
+				$target->{subtarget} = 1;
+				$target->{parent} = $target{$1};
+			}
+		};
+		/^Target-Name:\s*(.+)\s*$/ and $target->{name} = $1;
+		/^Target-Arch:\s*(.+)\s*$/ and $target->{arch} = $1;
+		/^Target-Arch-Packages:\s*(.+)\s*$/ and $target->{arch_packages} = $1;
+		/^Target-Features:\s*(.+)\s*$/ and $target->{features} = [ split(/\s+/, $1) ];
+		/^Target-Depends:\s*(.+)\s*$/ and $target->{depends} = [ split(/\s+/, $1) ];
+		/^Target-Description:/ and $target->{desc} = get_multiline(*FILE);
+		/^Target-Optimization:\s*(.+)\s*$/ and $target->{cflags} = $1;
+		/^CPU-Type:\s*(.+)\s*$/ and $target->{cputype} = $1;
+		/^Linux-Version:\s*(.+)\s*$/ and $target->{version} = $1;
+		/^Linux-Release:\s*(.+)\s*$/ and $target->{release} = $1;
+		/^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1;
+		/^Default-Subtarget:\s*(.+)\s*$/ and $target->{def_subtarget} = $1;
+		/^Default-Packages:\s*(.+)\s*$/ and $target->{packages} = [ split(/\s+/, $1) ];
+		/^Target-Profile:\s*(.+)\s*$/ and do {
+			$profile = {
+				id => $1,
+				name => $1,
+				priority => 999,
+				packages => []
+			};
+			$1 =~ /^DEVICE_/ and $target->{has_devices} = 1;
+			push @{$target->{profiles}}, $profile;
+		};
+		/^Target-Profile-Name:\s*(.+)\s*$/ and $profile->{name} = $1;
+		/^Target-Profile-Priority:\s*(\d+)\s*$/ and do {
+			$profile->{priority} = $1;
+			$target->{sort} = 1;
+		};
+		/^Target-Profile-Packages:\s*(.*)\s*$/ and $profile->{packages} = [ split(/\s+/, $1) ];
+		/^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline(*FILE);
+	}
+	close FILE;
+	foreach my $target (@target) {
+		if (@{$target->{subtargets}} > 0) {
+			$target->{profiles} = [];
+			next;
+		}
+		@{$target->{profiles}} > 0 or $target->{profiles} = [
+			{
+				id => 'Default',
+				name => 'Default',
+				packages => []
+			}
+		];
+
+		$target->{sort} and @{$target->{profiles}} = sort {
+			$a->{priority} <=> $b->{priority} or
+			$a->{name} cmp $b->{name};
+		} @{$target->{profiles}};
+	}
+	return @target;
+}
+
+sub clear_packages() {
+	%subdir = ();
+	%preconfig = ();
+	%package = ();
+	%srcpackage = ();
+	%category = ();
+	%features = ();
+	%overrides = ();
+}
+
+sub parse_package_metadata($) {
+	my $file = shift;
+	my $pkg;
+	my $feature;
+	my $makefile;
+	my $preconfig;
+	my $subdir;
+	my $src;
+	my $override;
+	my %ignore = map { $_ => 1 } @ignore;
+
+	open FILE, "<$file" or do {
+		warn "Cannot open '$file': $!\n";
+		return undef;
+	};
+	while (<FILE>) {
+		chomp;
+		/^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and do {
+			$makefile = $1;
+			$subdir = $2;
+			$src = $3;
+			$subdir =~ s/^package\///;
+			$subdir{$src} = $subdir;
+			$srcpackage{$src} = [];
+			$override = "";
+			undef $pkg;
+		};
+		/^Override: \s*(.+?)\s*$/ and do {
+			$override = $1;
+			$overrides{$src} = 1;
+		};
+		next unless $src;
+		/^Package:\s*(.+?)\s*$/ and do {
+			undef $feature;
+			$pkg = {};
+			$pkg->{ignore} = $ignore{$src};
+			$pkg->{src} = $src;
+			$pkg->{makefile} = $makefile;
+			$pkg->{name} = $1;
+			$pkg->{title} = "";
+			$pkg->{depends} = [];
+			$pkg->{mdepends} = [];
+			$pkg->{builddepends} = [];
+			$pkg->{buildtypes} = [];
+			$pkg->{subdir} = $subdir;
+			$pkg->{tristate} = 1;
+			$pkg->{override} = $override;
+			$package{$1} = $pkg;
+			push @{$srcpackage{$src}}, $pkg;
+		};
+		/^Feature:\s*(.+?)\s*$/ and do {
+			undef $pkg;
+			$feature = {};
+			$feature->{name} = $1;
+			$feature->{priority} = 0;
+		};
+		$feature and do {
+			/^Target-Name:\s*(.+?)\s*$/ and do {
+				$features{$1} or $features{$1} = [];
+				push @{$features{$1}}, $feature unless $ignore{$src};
+			};
+			/^Target-Title:\s*(.+?)\s*$/ and $feature->{target_title} = $1;
+			/^Feature-Priority:\s*(\d+)\s*$/ and $feature->{priority} = $1;
+			/^Feature-Name:\s*(.+?)\s*$/ and $feature->{title} = $1;
+			/^Feature-Description:/ and $feature->{description} = get_multiline(\*FILE, "\t\t\t");
+			next;
+		};
+		next unless $pkg;
+		/^Version: \s*(.+)\s*$/ and $pkg->{version} = $1;
+		/^Title: \s*(.+)\s*$/ and $pkg->{title} = $1;
+		/^Menu: \s*(.+)\s*$/ and $pkg->{menu} = $1;
+		/^Submenu: \s*(.+)\s*$/ and $pkg->{submenu} = $1;
+		/^Submenu-Depends: \s*(.+)\s*$/ and $pkg->{submenudep} = $1;
+		/^Source: \s*(.+)\s*$/ and $pkg->{source} = $1;
+		/^License: \s*(.+)\s*$/ and $pkg->{license} = $1;
+		/^LicenseFiles: \s*(.+)\s*$/ and $pkg->{licensefiles} = $1;
+		/^Default: \s*(.+)\s*$/ and $pkg->{default} = $1;
+		/^Provides: \s*(.+)\s*$/ and do {
+			my @vpkg = split /\s+/, $1;
+			foreach my $vpkg (@vpkg) {
+				$package{$vpkg} or $package{$vpkg} = {
+					name => $vpkg,
+					vdepends => [],
+					src => $src,
+					subdir => $subdir,
+					makefile => $makefile
+				};
+				push @{$package{$vpkg}->{vdepends}}, $pkg->{name};
+			}
+		};
+		/^Menu-Depends: \s*(.+)\s*$/ and $pkg->{mdepends} = [ split /\s+/, $1 ];
+		/^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1 ];
+		/^Conflicts: \s*(.+)\s*$/ and $pkg->{conflicts} = [ split /\s+/, $1 ];
+		/^Hidden: \s*(.+)\s*$/ and $pkg->{hidden} = 1;
+		/^Build-Variant: \s*([\w\-]+)\s*/ and $pkg->{variant} = $1;
+		/^Default-Variant: .*/ and $pkg->{variant_default} = 1;
+		/^Build-Only: \s*(.+)\s*$/ and $pkg->{buildonly} = 1;
+		/^Build-Depends: \s*(.+)\s*$/ and $pkg->{builddepends} = [ split /\s+/, $1 ];
+		/^Build-Depends\/(\w+): \s*(.+)\s*$/ and $pkg->{"builddepends/$1"} = [ split /\s+/, $2 ];
+		/^Build-Types:\s*(.+)\s*$/ and $pkg->{buildtypes} = [ split /\s+/, $1 ];
+		/^Repository:\s*(.+?)\s*$/ and $pkg->{repository} = $1;
+		/^Category: \s*(.+)\s*$/ and do {
+			$pkg->{category} = $1;
+			defined $category{$1} or $category{$1} = {};
+			defined $category{$1}->{$src} or $category{$1}->{$src} = [];
+			push @{$category{$1}->{$src}}, $pkg;
+		};
+		/^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline(*FILE, "\t\t ");
+		/^Type: \s*(.+)\s*$/ and do {
+			$pkg->{type} = [ split /\s+/, $1 ];
+			undef $pkg->{tristate};
+			foreach my $type (@{$pkg->{type}}) {
+				$type =~ /ipkg/ and $pkg->{tristate} = 1;
+			}
+		};
+		/^Config:\s*(.*)\s*$/ and $pkg->{config} = "$1\n".get_multiline(*FILE, "\t");
+		/^Prereq-Check:/ and $pkg->{prereq} = 1;
+		/^Preconfig:\s*(.+)\s*$/ and do {
+			my $pkgname = $pkg->{name};
+			$preconfig{$pkgname} or $preconfig{$pkgname} = {};
+			if (exists $preconfig{$pkgname}->{$1}) {
+				$preconfig = $preconfig{$pkgname}->{$1};
+			} else {
+				$preconfig = {
+					id => $1
+				};
+				$preconfig{$pkgname}->{$1} = $preconfig unless $ignore{$src};
+			}
+		};
+		/^Preconfig-Type:\s*(.*?)\s*$/ and $preconfig->{type} = $1;
+		/^Preconfig-Label:\s*(.*?)\s*$/ and $preconfig->{label} = $1;
+		/^Preconfig-Default:\s*(.*?)\s*$/ and $preconfig->{default} = $1;
+	}
+	close FILE;
+	return 1;
+}
+
+1;
diff --git a/scripts/mkits.sh b/scripts/mkits.sh
new file mode 100755
index 0000000000..8857996eba
--- /dev/null
+++ b/scripts/mkits.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+#
+# Licensed under the terms of the GNU GPL License version 2 or later.
+#
+# Author: Peter Tyser <ptyser@xes-inc.com>
+#
+# U-Boot firmware supports the booting of images in the Flattened Image
+# Tree (FIT) format.  The FIT format uses a device tree structure to
+# describe a kernel image, device tree blob, ramdisk, etc.  This script
+# creates an Image Tree Source (.its file) which can be passed to the
+# 'mkimage' utility to generate an Image Tree Blob (.itb file).  The .itb
+# file can then be booted by U-Boot (or other bootloaders which support
+# FIT images).  See doc/uImage.FIT/howto.txt in U-Boot source code for
+# additional information on FIT images.
+#
+
+usage() {
+	echo "Usage: `basename $0` -A arch -C comp -a addr -e entry" \
+		"-v version -k kernel [-D name -d dtb] -o its_file"
+	echo -e "\t-A ==> set architecture to 'arch'"
+	echo -e "\t-C ==> set compression type 'comp'"
+	echo -e "\t-a ==> set load address to 'addr' (hex)"
+	echo -e "\t-e ==> set entry point to 'entry' (hex)"
+	echo -e "\t-v ==> set kernel version to 'version'"
+	echo -e "\t-k ==> include kernel image 'kernel'"
+	echo -e "\t-D ==> human friendly Device Tree Blob 'name'"
+	echo -e "\t-d ==> include Device Tree Blob 'dtb'"
+	echo -e "\t-o ==> create output file 'its_file'"
+	exit 1
+}
+
+while getopts ":A:a:C:D:d:e:k:o:v:" OPTION
+do
+	case $OPTION in
+		A ) ARCH=$OPTARG;;
+		a ) LOAD_ADDR=$OPTARG;;
+		C ) COMPRESS=$OPTARG;;
+		D ) DEVICE=$OPTARG;;
+		d ) DTB=$OPTARG;;
+		e ) ENTRY_ADDR=$OPTARG;;
+		k ) KERNEL=$OPTARG;;
+		o ) OUTPUT=$OPTARG;;
+		v ) VERSION=$OPTARG;;
+		* ) echo "Invalid option passed to '$0' (options:$@)"
+		usage;;
+	esac
+done
+
+# Make sure user entered all required parameters
+if [ -z "${ARCH}" ] || [ -z "${COMPRESS}" ] || [ -z "${LOAD_ADDR}" ] || \
+	[ -z "${ENTRY_ADDR}" ] || [ -z "${VERSION}" ] || [ -z "${KERNEL}" ] || \
+	[ -z "${OUTPUT}" ]; then
+	usage
+fi
+
+ARCH_UPPER=`echo $ARCH | tr '[:lower:]' '[:upper:]'`
+
+# Conditionally create fdt information
+if [ -n "${DTB}" ]; then
+	FDT="
+		fdt@1 {
+			description = \"${ARCH_UPPER} OpenWrt ${DEVICE} device tree blob\";
+			data = /incbin/(\"${DTB}\");
+			type = \"flat_dt\";
+			arch = \"${ARCH}\";
+			compression = \"none\";
+			hash@1 {
+				algo = \"crc32\";
+			};
+			hash@2 {
+				algo = \"sha1\";
+			};
+		};
+"
+fi
+
+# Create a default, fully populated DTS file
+DATA="/dts-v1/;
+
+/ {
+	description = \"${ARCH_UPPER} OpenWrt FIT (Flattened Image Tree)\";
+	#address-cells = <1>;
+
+	images {
+		kernel@1 {
+			description = \"${ARCH_UPPER} OpenWrt Linux-${VERSION}\";
+			data = /incbin/(\"${KERNEL}\");
+			type = \"kernel\";
+			arch = \"${ARCH}\";
+			os = \"linux\";
+			compression = \"${COMPRESS}\";
+			load = <${LOAD_ADDR}>;
+			entry = <${ENTRY_ADDR}>;
+			hash@1 {
+				algo = \"crc32\";
+			};
+			hash@2 {
+				algo = \"sha1\";
+			};
+		};
+
+${FDT}
+
+	};
+
+	configurations {
+		default = \"config@1\";
+		config@1 {
+			description = \"OpenWrt\";
+			kernel = \"kernel@1\";
+			fdt = \"fdt@1\";
+		};
+	};
+};"
+
+# Write .its file to disk
+echo "$DATA" > ${OUTPUT}
diff --git a/scripts/om-fwupgradecfg-gen.sh b/scripts/om-fwupgradecfg-gen.sh
new file mode 100644
index 0000000000..6c3b74cc1c
--- /dev/null
+++ b/scripts/om-fwupgradecfg-gen.sh
@@ -0,0 +1,77 @@
+#/bin/sh
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+usage() {
+	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750> <out file path> <kernel path> <rootfs path>"
+	rm -f $CFG_OUT
+	exit 1
+}
+
+[ "$#" -lt 4 ] && usage
+
+CE_TYPE=$1
+CFG_OUT=$2
+KERNEL_PATH=$3
+ROOTFS_PATH=$4
+
+case $CE_TYPE in
+	OM2P)
+		MAX_PART_SIZE=7168
+		KERNEL_FLASH_ADDR=0x1c0000
+		FLASH_BS=262144
+		MD5_SKIP_BLOCKS=1
+		;;
+	OM5P|OM5PAC|MR600|MR900|MR1750)
+		MAX_PART_SIZE=7808
+		KERNEL_FLASH_ADDR=0xb0000
+		FLASH_BS=65536
+		MD5_SKIP_BLOCKS=4
+		;;
+	*)
+		echo "Error - unsupported ce type: $CE_TYPE"
+		exit 1
+		;;
+esac
+
+CHECK_BS=65536
+
+KERNEL_SIZE=$(stat -c%s "$KERNEL_PATH")
+KERNEL_MD5=$(md5=$(md5sum $KERNEL_PATH); echo ${md5%% *})
+KERNEL_SHA256=$(openssl dgst -sha256 $KERNEL_PATH | awk '{print $2}')
+KERNEL_PART_SIZE=$(size=$(($KERNEL_SIZE / $FLASH_BS)); [ $(($size * $FLASH_BS)) -lt $KERNEL_SIZE ] && size=$(($size + 1)); echo $(($size * $FLASH_BS / 1024)))
+
+ROOTFS_FLASH_ADDR=$(addr=$(($KERNEL_FLASH_ADDR + ($KERNEL_PART_SIZE * 1024))); printf "0x%x" $addr)
+ROOTFS_SIZE=$(stat -c%s "$ROOTFS_PATH")
+ROOTFS_CHECK_BLOCKS=$((($ROOTFS_SIZE / $CHECK_BS) - $MD5_SKIP_BLOCKS))
+ROOTFS_MD5=$(md5=$(dd if=$ROOTFS_PATH bs=$CHECK_BS count=$ROOTFS_CHECK_BLOCKS 2>&- | md5sum); echo ${md5%% *})
+ROOTFS_MD5_FULL=$(md5=$(md5sum $ROOTFS_PATH); echo ${md5%% *})
+ROOTFS_SHA256_FULL=$(openssl dgst -sha256 $ROOTFS_PATH | awk '{print $2}')
+ROOTFS_CHECK_SIZE=$(printf '0x%x' $(($ROOTFS_CHECK_BLOCKS * $CHECK_BS)))
+ROOTFS_PART_SIZE=$(($MAX_PART_SIZE - $KERNEL_PART_SIZE))
+
+cat << EOF > $CFG_OUT
+[vmlinux]
+filename=kernel
+md5sum=$KERNEL_MD5
+filemd5sum=$KERNEL_MD5
+filesha256sum=$KERNEL_SHA256
+flashaddr=$KERNEL_FLASH_ADDR
+checksize=0x0
+cmd_success=setenv bootseq 1,2; setenv kernel_size_1 $KERNEL_PART_SIZE; saveenv
+cmd_fail=reset
+
+[rootfs]
+filename=rootfs
+md5sum=$ROOTFS_MD5
+filemd5sum=$ROOTFS_MD5_FULL
+filesha256sum=$ROOTFS_SHA256_FULL
+flashaddr=$ROOTFS_FLASH_ADDR
+checksize=$ROOTFS_CHECK_SIZE
+cmd_success=setenv bootseq 1,2; setenv kernel_size_1 $KERNEL_PART_SIZE; setenv rootfs_size_1 $ROOTFS_PART_SIZE; saveenv
+cmd_fail=reset
+EOF
diff --git a/scripts/openbsd.sh b/scripts/openbsd.sh
new file mode 100644
index 0000000000..dc88d28ed7
--- /dev/null
+++ b/scripts/openbsd.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+ver=$(uname -r)
+arch=$(uname -m)
+echo "Preparing OpenBSD $arch $ver for LEDE"
+PKG_PATH="http://ftp.openbsd.org/pub/OpenBSD/${ver}/packages/${arch}/"
+export PKG_PATH
+pkg_add -v gmake
+pkg_add -v findutils
+pkg_add -v coreutils
+pkg_add -v gdiff
+pkg_add -v rsync--
+pkg_add -v git
+pkg_add -v bash
+pkg_add -v unzip
+pkg_add -v wget
+pkg_add -v gtar--
+pkg_add -v ggrep
+pkg_add -v gawk
+pkg_add -v gsed
+pkg_add -v xz
+pkg_add -v apr-util--
+pkg_add -v cyrus-sasl--
+pkg_add -v subversion
+pkg_add -v gnugetopt
diff --git a/scripts/package-metadata.pl b/scripts/package-metadata.pl
new file mode 100755
index 0000000000..f8f16f07fa
--- /dev/null
+++ b/scripts/package-metadata.pl
@@ -0,0 +1,662 @@
+#!/usr/bin/env perl
+use FindBin;
+use lib "$FindBin::Bin";
+use strict;
+use metadata;
+use Getopt::Long;
+
+my %board;
+
+sub version_to_num($) {
+	my $str = shift;
+	my $num = 0;
+
+	if (defined($str) && $str =~ /^\d+(?:\.\d+)+$/)
+	{
+		my @n = (split(/\./, $str), 0, 0, 0, 0);
+		$num = ($n[0] << 24) | ($n[1] << 16) | ($n[2] << 8) | $n[3];
+	}
+
+	return $num;
+}
+
+sub version_filter_list(@) {
+	my $cmpver = version_to_num(shift @_);
+	my @items;
+
+	foreach my $item (@_)
+	{
+		if ($item =~ s/@(lt|le|gt|ge|eq|ne)(\d+(?:\.\d+)+)\b//)
+		{
+			my $op = $1;
+			my $symver = version_to_num($2);
+
+			if ($symver > 0 && $cmpver > 0)
+			{
+				next unless (($op eq 'lt' && $cmpver <  $symver) ||
+				             ($op eq 'le' && $cmpver <= $symver) ||
+				             ($op eq 'gt' && $cmpver >  $symver) ||
+				             ($op eq 'ge' && $cmpver >= $symver) ||
+				             ($op eq 'eq' && $cmpver == $symver) ||
+				             ($op eq 'ne' && $cmpver != $symver));
+			}
+		}
+
+		push @items, $item;
+	}
+
+	return @items;
+}
+
+sub gen_kconfig_overrides() {
+	my %config;
+	my %kconfig;
+	my $package;
+	my $pkginfo = shift @ARGV;
+	my $cfgfile = shift @ARGV;
+	my $patchver = shift @ARGV;
+
+	# parameter 2: build system config
+	open FILE, "<$cfgfile" or return;
+	while (<FILE>) {
+		/^(CONFIG_.+?)=(.+)$/ and $config{$1} = 1;
+	}
+	close FILE;
+
+	# parameter 1: package metadata
+	open FILE, "<$pkginfo" or return;
+	while (<FILE>) {
+		/^Package:\s*(.+?)\s*$/ and $package = $1;
+		/^Kernel-Config:\s*(.+?)\s*$/ and do {
+			my @config = split /\s+/, $1;
+			foreach my $config (version_filter_list($patchver, @config)) {
+				my $val = 'm';
+				my $override;
+				if ($config =~ /^(.+?)=(.+)$/) {
+					$config = $1;
+					$override = 1;
+					$val = $2;
+				}
+				if ($config{"CONFIG_PACKAGE_$package"} and ($config ne 'n')) {
+					next if $kconfig{$config} eq 'y';
+					$kconfig{$config} = $val;
+				} elsif (!$override) {
+					$kconfig{$config} or $kconfig{$config} = 'n';
+				}
+			}
+		};
+	};
+	close FILE;
+
+	foreach my $kconfig (sort keys %kconfig) {
+		if ($kconfig{$kconfig} eq 'n') {
+			print "# $kconfig is not set\n";
+		} else {
+			print "$kconfig=$kconfig{$kconfig}\n";
+		}
+	}
+}
+
+my %dep_check;
+sub __find_package_dep($$) {
+	my $pkg = shift;
+	my $name = shift;
+	my $deps = ($pkg->{vdepends} or $pkg->{depends});
+
+	return 0 unless defined $deps;
+	foreach my $dep (@{$deps}) {
+		next if $dep_check{$dep};
+		$dep_check{$dep} = 1;
+		return 1 if $dep eq $name;
+		return 1 if ($package{$dep} and (__find_package_dep($package{$dep},$name) == 1));
+	}
+	return 0;
+}
+
+# wrapper to avoid infinite recursion
+sub find_package_dep($$) {
+	my $pkg = shift;
+	my $name = shift;
+
+	%dep_check = ();
+	return __find_package_dep($pkg, $name);
+}
+
+sub package_depends($$) {
+	my $a = shift;
+	my $b = shift;
+	my $ret;
+
+	return 0 if ($a->{submenu} ne $b->{submenu});
+	if (find_package_dep($a, $b->{name}) == 1) {
+		$ret = 1;
+	} elsif (find_package_dep($b, $a->{name}) == 1) {
+		$ret = -1;
+	} else {
+		return 0;
+	}
+	return $ret;
+}
+
+sub mconf_depends {
+	my $pkgname = shift;
+	my $depends = shift;
+	my $only_dep = shift;
+	my $res;
+	my $dep = shift;
+	my $seen = shift;
+	my $parent_condition = shift;
+	$dep or $dep = {};
+	$seen or $seen = {};
+	my @t_depends;
+
+	$depends or return;
+	my @depends = @$depends;
+	foreach my $depend (@depends) {
+		my $m = "depends on";
+		my $flags = "";
+		$depend =~ s/^([@\+]+)// and $flags = $1;
+		my $vdep;
+		my $condition = $parent_condition;
+
+		next if $condition eq $depend;
+		next if $seen->{"$parent_condition:$depend"};
+		next if $seen->{":$depend"};
+		$seen->{"$parent_condition:$depend"} = 1;
+		if ($depend =~ /^(.+):(.+)$/) {
+			if ($1 ne "PACKAGE_$pkgname") {
+				if ($condition) {
+					$condition = "$condition && $1";
+				} else {
+					$condition = $1;
+				}
+			}
+			$depend = $2;
+		}
+		next if $package{$depend} and $package{$depend}->{buildonly};
+		if ($flags =~ /\+/) {
+			if ($vdep = $package{$depend}->{vdepends}) {
+				my @vdeps;
+				$depend = undef;
+
+				foreach my $v (@$vdep) {
+					if ($package{$v} && $package{$v}->{variant_default}) {
+						$depend = $v;
+					} else {
+						push @vdeps, $v;
+					}
+				}
+
+				if (!$depend) {
+					$depend = shift @vdeps;
+				}
+
+				if (@vdeps > 1) {
+					$condition = ($condition ? "$condition && " : '') . '!('.join("||", map { "PACKAGE_".$_ } @vdeps).')';
+				} elsif (@vdeps > 0) {
+					$condition = ($condition ? "$condition && " : '') . '!PACKAGE_'.$vdeps[0];
+				}
+			}
+
+			# Menuconfig will not treat 'select FOO' as a real dependency
+			# thus if FOO depends on other config options, these dependencies
+			# will not be checked. To fix this, we simply emit all of FOO's
+			# depends here as well.
+			$package{$depend} and push @t_depends, [ $package{$depend}->{depends}, $condition ];
+
+			$m = "select";
+			next if $only_dep;
+
+			$flags =~ /@/ or $depend = "PACKAGE_$depend";
+		} else {
+			if ($vdep = $package{$depend}->{vdepends}) {
+				$depend = join("||", map { "PACKAGE_".$_ } @$vdep);
+			} else {
+				$flags =~ /@/ or $depend = "PACKAGE_$depend";
+			}
+		}
+		if ($condition) {
+			if ($m =~ /select/) {
+				next if $depend eq $condition;
+				$depend = "$depend if $condition";
+			} else {
+				$depend = "!($condition) || $depend" unless $dep->{$condition} eq 'select';
+			}
+		}
+		$dep->{$depend} =~ /select/ or $dep->{$depend} = $m;
+	}
+
+	foreach my $tdep (@t_depends) {
+		mconf_depends($pkgname, $tdep->[0], 1, $dep, $seen, $tdep->[1]);
+	}
+
+	foreach my $depend (keys %$dep) {
+		my $m = $dep->{$depend};
+		$res .= "\t\t$m $depend\n";
+	}
+	return $res;
+}
+
+sub mconf_conflicts {
+	my $pkgname = shift;
+	my $depends = shift;
+	my $res = "";
+
+	foreach my $depend (@$depends) {
+		next unless $package{$depend};
+		$res .= "\t\tdepends on m || (PACKAGE_$depend != y)\n";
+	}
+	return $res;
+}
+
+sub print_package_config_category($) {
+	my $cat = shift;
+	my %menus;
+	my %menu_dep;
+
+	return unless $category{$cat};
+
+	print "menu \"$cat\"\n\n";
+	my %spkg = %{$category{$cat}};
+
+	foreach my $spkg (sort {uc($a) cmp uc($b)} keys %spkg) {
+		foreach my $pkg (@{$spkg{$spkg}}) {
+			next if $pkg->{buildonly};
+			my $menu = $pkg->{submenu};
+			if ($menu) {
+				$menu_dep{$menu} or $menu_dep{$menu} = $pkg->{submenudep};
+			} else {
+				$menu = 'undef';
+			}
+			$menus{$menu} or $menus{$menu} = [];
+			push @{$menus{$menu}}, $pkg;
+		}
+	}
+	my @menus = sort {
+		($a eq 'undef' ?  1 : 0) or
+		($b eq 'undef' ? -1 : 0) or
+		($a cmp $b)
+	} keys %menus;
+
+	foreach my $menu (@menus) {
+		my @pkgs = sort {
+			package_depends($a, $b) or
+			($a->{name} cmp $b->{name})
+		} @{$menus{$menu}};
+		if ($menu ne 'undef') {
+			$menu_dep{$menu} and print "if $menu_dep{$menu}\n";
+			print "menu \"$menu\"\n";
+		}
+		foreach my $pkg (@pkgs) {
+			next if $pkg->{ignore};
+			my $title = $pkg->{name};
+			my $c = (72 - length($pkg->{name}) - length($pkg->{title}));
+			if ($c > 0) {
+				$title .= ("." x $c). " ". $pkg->{title};
+			}
+			$title = "\"$title\"";
+			print "\t";
+			$pkg->{menu} and print "menu";
+			print "config PACKAGE_".$pkg->{name}."\n";
+			$pkg->{hidden} and $title = "";
+			print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." $title\n";
+			print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n";
+			unless ($pkg->{hidden}) {
+				my @def = ("ALL");
+				if (!exists($pkg->{repository})) {
+					push @def, "ALL_NONSHARED";
+				}
+				if ($pkg->{name} =~ /^kmod-/) {
+					push @def, "ALL_KMODS";
+				}
+				$pkg->{default} ||= "m if " . join("||", @def);
+			}
+			if ($pkg->{default}) {
+				foreach my $default (split /\s*,\s*/, $pkg->{default}) {
+					print "\t\tdefault $default\n";
+				}
+			}
+			print mconf_depends($pkg->{name}, $pkg->{depends}, 0);
+			print mconf_depends($pkg->{name}, $pkg->{mdepends}, 0);
+			print mconf_conflicts($pkg->{name}, $pkg->{conflicts});
+			print "\t\thelp\n";
+			print $pkg->{description};
+			print "\n";
+
+			$pkg->{config} and print $pkg->{config}."\n";
+		}
+		if ($menu ne 'undef') {
+			print "endmenu\n";
+			$menu_dep{$menu} and print "endif\n";
+		}
+	}
+	print "endmenu\n\n";
+
+	undef $category{$cat};
+}
+
+sub print_package_features() {
+	keys %features > 0 or return;
+	print "menu \"Package features\"\n";
+	foreach my $n (keys %features) {
+		my @features = sort { $b->{priority} <=> $a->{priority} or $a->{title} cmp $b->{title} } @{$features{$n}};
+		print <<EOF;
+choice
+	prompt "$features[0]->{target_title}"
+	default FEATURE_$features[0]->{name}
+EOF
+
+		foreach my $feature (@features) {
+			print <<EOF;
+	config FEATURE_$feature->{name}
+		bool "$feature->{title}"
+EOF
+			$feature->{description} =~ /\w/ and do {
+				print "\t\thelp\n".$feature->{description}."\n";
+			};
+		}
+		print "endchoice\n"
+	}
+	print "endmenu\n\n";
+}
+
+sub print_package_overrides() {
+	keys %overrides > 0 or return;
+	print "\tconfig OVERRIDE_PKGS\n";
+	print "\t\tstring\n";
+	print "\t\tdefault \"".join(" ", sort keys %overrides)."\"\n\n";
+}
+
+sub gen_package_config() {
+	parse_package_metadata($ARGV[0]) or exit 1;
+	print "menuconfig IMAGEOPT\n\tbool \"Image configuration\"\n\tdefault n\n";
+	foreach my $preconfig (keys %preconfig) {
+		foreach my $cfg (keys %{$preconfig{$preconfig}}) {
+			my $conf = $preconfig{$preconfig}->{$cfg}->{id};
+			$conf =~ tr/\.-/__/;
+			print <<EOF
+	config UCI_PRECONFIG_$conf
+		string "$preconfig{$preconfig}->{$cfg}->{label}" if IMAGEOPT
+		depends on PACKAGE_$preconfig
+		default "$preconfig{$preconfig}->{$cfg}->{default}"
+
+EOF
+		}
+	}
+	print "source \"package/*/image-config.in\"\n";
+	if (scalar glob "package/feeds/*/*/image-config.in") {
+	    print "source \"package/feeds/*/*/image-config.in\"\n";
+	}
+	print_package_features();
+	print_package_config_category 'Base system';
+	foreach my $cat (sort {uc($a) cmp uc($b)} keys %category) {
+		print_package_config_category $cat;
+	}
+	print_package_overrides();
+}
+
+sub get_conditional_dep($$) {
+	my $condition = shift;
+	my $depstr = shift;
+	if ($condition) {
+		if ($condition =~ /^!(.+)/) {
+			return "\$(if \$(CONFIG_$1),,$depstr)";
+		} else {
+			return "\$(if \$(CONFIG_$condition),$depstr)";
+		}
+	} else {
+		return $depstr;
+	}
+}
+
+sub gen_package_mk() {
+	my %conf;
+	my %dep;
+	my %done;
+	my $line;
+
+	parse_package_metadata($ARGV[0]) or exit 1;
+	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
+		my $config;
+		my $pkg = $package{$name};
+		my @srcdeps;
+
+		next if defined $pkg->{vdepends};
+
+		$config = "\$(CONFIG_PACKAGE_$name)";
+		if ($config) {
+			$pkg->{buildonly} and $config = "";
+			print "package-$config += $pkg->{subdir}$pkg->{src}\n";
+			if ($pkg->{variant}) {
+				if (!defined($done{$pkg->{src}}) or $pkg->{variant_default}) {
+					print "\$(curdir)/$pkg->{subdir}$pkg->{src}/default-variant := $pkg->{variant}\n";
+				}
+				print "\$(curdir)/$pkg->{subdir}$pkg->{src}/variants += \$(if $config,$pkg->{variant})\n"
+			}
+			$pkg->{prereq} and print "prereq-$config += $pkg->{subdir}$pkg->{src}\n";
+		}
+
+		next if $done{$pkg->{src}};
+		$done{$pkg->{src}} = 1;
+
+		if (@{$pkg->{buildtypes}} > 0) {
+			print "buildtypes-$pkg->{subdir}$pkg->{src} = ".join(' ', @{$pkg->{buildtypes}})."\n";
+		}
+
+		foreach my $spkg (@{$srcpackage{$pkg->{src}}}) {
+			foreach my $dep (@{$spkg->{depends}}, @{$spkg->{builddepends}}) {
+				$dep =~ /@/ or do {
+					$dep =~ s/\+//g;
+					push @srcdeps, $dep;
+				};
+			}
+		}
+		foreach my $type (@{$pkg->{buildtypes}}) {
+			my @extra_deps;
+			my %deplines;
+
+			next unless $pkg->{"builddepends/$type"};
+			foreach my $dep (@{$pkg->{"builddepends/$type"}}) {
+				my $suffix = "";
+				my $condition;
+
+				if ($dep =~ /^(.+):(.+)/) {
+					$condition = $1;
+					$dep = $2;
+				}
+				if ($dep =~ /^(.+)(\/.+)/) {
+					$dep = $1;
+					$suffix = $2;
+				}
+
+				my $idx = "";
+				my $pkg_dep = $package{$dep};
+				if (defined($pkg_dep) && defined($pkg_dep->{src})) {
+					$idx = $pkg_dep->{subdir}.$pkg_dep->{src};
+				} elsif (defined($srcpackage{$dep})) {
+					$idx = $subdir{$dep}.$dep;
+				} else {
+					next;
+				}
+				my $depstr = "\$(curdir)/$idx$suffix/compile";
+				my $depline = get_conditional_dep($condition, $depstr);
+				if ($depline) {
+					$deplines{$depline}++;
+				}
+			}
+			my $depline = join(" ", sort keys %deplines);
+			if ($depline) {
+				$line .= "\$(curdir)/".$pkg->{subdir}."$pkg->{src}/$type/compile += $depline\n";
+			}
+		}
+
+		my $hasdeps = 0;
+		my %deplines;
+		foreach my $deps (@srcdeps) {
+			my $idx;
+			my $condition;
+			my $prefix = "";
+			my $suffix = "";
+
+			if ($deps =~ /^(.+):(.+)/) {
+				$condition = $1;
+				$deps = $2;
+			}
+			if ($deps =~ /^(.+)(\/.+)/) {
+				$deps = $1;
+				$suffix = $2;
+			}
+
+			my $pkg_dep = $package{$deps};
+			my @deps;
+
+			if ($pkg_dep->{vdepends}) {
+				@deps = @{$pkg_dep->{vdepends}};
+			} else {
+				@deps = ($deps);
+			}
+
+			foreach my $dep (@deps) {
+				$pkg_dep = $package{$deps};
+				if (defined $pkg_dep->{src}) {
+					($pkg->{src} ne $pkg_dep->{src}.$suffix) and $idx = $pkg_dep->{subdir}.$pkg_dep->{src};
+				} elsif (defined($srcpackage{$dep})) {
+					$idx = $subdir{$dep}.$dep;
+				}
+				undef $idx if $idx eq 'base-files';
+				if ($idx) {
+					$idx .= $suffix;
+
+					my $depline;
+					next if $pkg->{src} eq $pkg_dep->{src}.$suffix;
+					next if $dep{$condition.":".$pkg->{src}."->".$idx};
+					next if $dep{$pkg->{src}."->($dep)".$idx} and $pkg_dep->{vdepends};
+					my $depstr;
+
+					if ($pkg_dep->{vdepends}) {
+						$depstr = "\$(if \$(CONFIG_PACKAGE_$dep),\$(curdir)/$idx/compile)";
+						$dep{$pkg->{src}."->($dep)".$idx} = 1;
+					} else {
+						$depstr = "\$(curdir)/$idx/compile";
+						$dep{$pkg->{src}."->".$idx} = 1;
+					}
+					$depline = get_conditional_dep($condition, $depstr);
+					if ($depline) {
+						$deplines{$depline}++;
+					}
+				}
+			}
+		}
+		my $depline = join(" ", sort keys %deplines);
+		if ($depline) {
+			$line .= "\$(curdir)/".$pkg->{subdir}."$pkg->{src}/compile += $depline\n";
+		}
+	}
+
+	if ($line ne "") {
+		print "\n$line";
+	}
+	foreach my $preconfig (keys %preconfig) {
+		my $cmds;
+		foreach my $cfg (keys %{$preconfig{$preconfig}}) {
+			my $conf = $preconfig{$preconfig}->{$cfg}->{id};
+			$conf =~ tr/\.-/__/;
+			$cmds .= "\techo \"uci set '$preconfig{$preconfig}->{$cfg}->{id}=\$(subst \",,\$(CONFIG_UCI_PRECONFIG_$conf))'\"; \\\n";
+		}
+		next unless $cmds;
+		print <<EOF
+
+ifndef DUMP_TARGET_DB
+\$(TARGET_DIR)/etc/uci-defaults/$preconfig: FORCE
+	( \\
+$cmds \\
+	) > \$@
+	
+ifneq (\$(IMAGEOPT)\$(CONFIG_IMAGEOPT),)
+  package/preconfig: \$(TARGET_DIR)/etc/uci-defaults/$preconfig
+endif
+endif
+
+EOF
+	}
+}
+
+sub gen_package_source() {
+	parse_package_metadata($ARGV[0]) or exit 1;
+	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
+		my $pkg = $package{$name};
+		if ($pkg->{name} && $pkg->{source}) {
+			print "$pkg->{name}: ";
+			print "$pkg->{source}\n";
+		}
+	}
+}
+
+sub gen_package_subdirs() {
+	parse_package_metadata($ARGV[0]) or exit 1;
+	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
+		my $pkg = $package{$name};
+		if ($pkg->{name} && $pkg->{repository}) {
+			print "Package/$name/subdir = $pkg->{repository}\n";
+		}
+	}
+}
+
+sub gen_package_license($) {
+	my $level = shift;
+	parse_package_metadata($ARGV[0]) or exit 1;
+	foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
+		my $pkg = $package{$name};
+		if ($pkg->{name}) {
+			if ($pkg->{license}) {
+				print "$pkg->{name}: ";
+				print "$pkg->{license}\n";
+				if ($pkg->{licensefiles} && $level == 0) {
+					print "\tFiles: $pkg->{licensefiles}\n";
+				}
+			} else {
+				if ($level == 1) {
+					print "$pkg->{name}: Missing license! ";
+					print "Please fix $pkg->{makefile}\n";
+				}
+			}
+		}
+	}
+}
+
+sub gen_version_filtered_list() {
+	foreach my $item (version_filter_list(@ARGV)) {
+		print "$item\n";
+	}
+}
+
+sub parse_command() {
+	GetOptions("ignore=s", \@ignore);
+	my $cmd = shift @ARGV;
+	for ($cmd) {
+		/^mk$/ and return gen_package_mk();
+		/^config$/ and return gen_package_config();
+		/^kconfig/ and return gen_kconfig_overrides();
+		/^source$/ and return gen_package_source();
+		/^subdirs$/ and return gen_package_subdirs();
+		/^license$/ and return gen_package_license(0);
+		/^licensefull$/ and return gen_package_license(1);
+		/^version_filter$/ and return gen_version_filtered_list();
+	}
+	die <<EOF
+Available Commands:
+	$0 mk [file]				Package metadata in makefile format
+	$0 config [file] 			Package metadata in Kconfig format
+	$0 kconfig [file] [config] [patchver]	Kernel config overrides
+	$0 source [file] 			Package source file information
+	$0 subdirs [file]			Package subdir information in makefile format
+	$0 license [file] 			Package license information
+	$0 licensefull [file] 			Package license information (full list)
+	$0 version_filter [patchver] [list...]	Filter list of version tagged strings
+
+Options:
+	--ignore <name>				Ignore the source package <name>
+EOF
+}
+
+parse_command();
diff --git a/scripts/pad_image b/scripts/pad_image
new file mode 100755
index 0000000000..b1941a28d8
--- /dev/null
+++ b/scripts/pad_image
@@ -0,0 +1,100 @@
+#!/usr/bin/env bash
+
+function usage {
+  echo "Usage: prepare_image image_type kernel_image rootfs_image header_size"
+  echo "Padd root and kernel image to the correct size and append the jffs2 start marker as needed"
+  exit 1
+}
+
+function pad_file {
+	echo "Padding $1 to size $2"
+	dd if=$1 of=$1.paddingtempfile bs=$2 count=1 conv=sync &> /dev/null
+	mv $1.paddingtempfile $1
+}
+
+#filesize filestart padding
+function calc_pad {
+	[  $((($1 + $2) & ($3 - 1))) == 0 ] && {
+		echo $1
+		return 0
+        }
+	echo $(((($1 + $2) | ($3 - 1)) + 1 - $2))
+}
+
+function prep_squash {
+	echo "kernel_size: $kernel_size"
+	echo "header_size: $header_size"
+	kernel_pad_size=$(calc_pad $kernel_size $header_size 32)
+	kernel_end=$(($header_size + $kernel_pad_size))
+	pad_file $kernel_image $kernel_pad_size
+
+	#4k
+	rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 4096)
+	pad_file $rootfs_image $rootfs_pad_size
+	echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
+	
+	#8k
+	rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 8192)
+	[ $rootfs_pad_size == rootfs_old_padsize ] || {
+		pad_file $rootfs_image $rootfs_pad_size
+		rootfs_old_padsize=$rootfs_pad_size
+		echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
+	}
+
+	#64k
+	rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 65536)
+	[ $rootfs_pad_size == rootfs_old_padsize ] || {
+		pad_file $rootfs_image $rootfs_pad_size
+		rootfs_old_padsize=$rootfs_pad_size
+		echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
+	}
+
+	#128k
+	rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 131072)
+	[ $rootfs_pad_size == rootfs_old_padsize ] || {
+		pad_file $rootfs_image $rootfs_pad_size
+		rootfs_old_padsize=$rootfs_pad_size
+		echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
+	}
+	
+}
+
+function prep_jffs2 {
+	kernel_pad_size=$(calc_pad $kernel_size $header_size $1)
+	pad_file $kernel_image $kernel_pad_size
+}
+
+image_type=$1
+kernel_image=$2
+rootfs_image=$3
+header_size=$4
+
+if [ -z "$image_type" ] || [ -z "$rootfs_image" ] || [ -z "$kernel_image" ] || [ -z "$header_size" ]; then
+	usage
+fi
+
+if [ ! -e "$rootfs_image" ] || [ -z "$kernel_image" ]; then
+	echo "input file not found"
+	exit 1
+fi
+
+kernel_size=$(stat -c "%s" "$kernel_image")
+rootfs_size=$(stat -c "%s" "$rootfs_image")
+
+if [ $kernel_size == 0 ] || [ $rootfs_size == 0 ]; then
+	echo "kernel or rootfs empty"
+	exit 1
+fi
+
+case $image_type in
+	squashfs )
+		prep_squash ;;
+	jffs2-64k )
+		prep_jffs2 65536 ;;
+	jffs2-128k )
+		prep_jffs2 131072 ;;
+	* )
+		echo "Unknown image type"
+		exit 1 ;;
+esac
+
diff --git a/scripts/patch-kernel.sh b/scripts/patch-kernel.sh
new file mode 100755
index 0000000000..c2b7e72049
--- /dev/null
+++ b/scripts/patch-kernel.sh
@@ -0,0 +1,54 @@
+#! /bin/sh
+# A little script I whipped up to make it easy to
+# patch source trees and have sane error handling
+# -Erik
+#
+# (c) 2002 Erik Andersen <andersen@codepoet.org>
+
+# Set directories from arguments, or use defaults.
+targetdir=${1-.}
+patchdir=${2-../kernel-patches}
+patchpattern=${3-*}
+
+if [ ! -d "${targetdir}" ] ; then
+    echo "Aborting.  '${targetdir}' is not a directory."
+    exit 1
+fi
+if [ ! -d "${patchdir}" ] ; then
+    echo "Aborting.  '${patchdir}' is not a directory."
+    exit 1
+fi
+    
+for i in ${patchdir}/${patchpattern} ; do 
+    case "$i" in
+	*.gz)
+	type="gzip"; uncomp="gunzip -dc"; ;; 
+	*.bz)
+	type="bzip"; uncomp="bunzip -dc"; ;; 
+	*.bz2)
+	type="bzip2"; uncomp="bunzip2 -dc"; ;; 
+	*.zip)
+	type="zip"; uncomp="unzip -d"; ;; 
+	*.Z)
+	type="compress"; uncomp="uncompress -c"; ;; 
+	*)
+	type="plaintext"; uncomp="cat"; ;; 
+    esac
+    [ -d "${i}" ] && echo "Ignoring subdirectory ${i}" && continue	
+    echo ""
+    echo "Applying ${i} using ${type}: " 
+    ${uncomp} ${i} | ${PATCH:-patch} -f -p1 -d ${targetdir}
+    if [ $? != 0 ] ; then
+        echo "Patch failed!  Please fix $i!"
+	exit 1
+    fi
+done
+
+# Check for rejects...
+if [ "`find $targetdir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] ; then
+    echo "Aborting.  Reject files found."
+    exit 1
+fi
+
+# Remove backup files
+find $targetdir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;
diff --git a/scripts/patch-specs.sh b/scripts/patch-specs.sh
new file mode 100755
index 0000000000..3307b6b090
--- /dev/null
+++ b/scripts/patch-specs.sh
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+
+DIR="$1"
+
+if [ -d "$DIR" ]; then
+	DIR="$(cd "$DIR"; pwd)"
+else
+	echo "Usage: $0 toolchain-dir"
+	exit 1
+fi
+
+echo -n "Locating cpp ... "
+for bin in bin usr/bin usr/local/bin; do
+	for cmd in "$DIR/$bin/"*-cpp; do
+		if [ -x "$cmd" ]; then
+			echo "$cmd"
+			CPP="$cmd"
+			break
+		fi
+	done
+done
+
+if [ ! -x "$CPP" ]; then
+	echo "Can't locate a cpp executable in '$DIR' !"
+	exit 1
+fi
+
+patch_specs() {
+	local found=0
+
+	for lib in $(STAGING_DIR="$DIR" "$CPP" -x c -v /dev/null 2>&1 | sed -ne 's#:# #g; s#^LIBRARY_PATH=##p'); do
+		if [ -d "$lib" ]; then
+			grep -qs "STAGING_DIR" "$lib/specs" && rm -f "$lib/specs"
+			if [ $found -lt 1 ]; then
+				echo -n "Patching specs ... "
+				STAGING_DIR="$DIR" "$CPP" -dumpspecs | awk '
+					mode ~ "link" {
+						sub("%{L.}", "%{L*} -L %:getenv(STAGING_DIR /usr/lib) -rpath-link %:getenv(STAGING_DIR /usr/lib)")
+					}
+					mode ~ "cpp" {
+						$0 = $0 " -idirafter %:getenv(STAGING_DIR /usr/include)"
+					}
+					{
+						print $0
+						mode = ""
+					}
+					/^\*cpp:/ {
+						mode = "cpp"
+					}
+					/^\*link.*:/ {
+						mode = "link"
+					}
+				' > "$lib/specs"
+				echo "ok"
+				found=1
+			fi
+		fi
+	done
+
+	[ $found -gt 0 ]
+	return $?
+}
+
+
+VERSION="$(STAGING_DIR="$DIR" "$CPP" --version | sed -ne 's/^.* (.*) //; s/ .*$//; 1p')"
+VERSION="${VERSION:-unknown}"
+
+case "${VERSION##* }" in
+	2.*|3.*|4.0.*|4.1.*|4.2.*)
+		echo "The compiler version does not support getenv() in spec files."
+		echo -n "Wrapping binaries instead ... "
+
+		if "${0%/*}/ext-toolchain.sh" --toolchain "$DIR" --wrap "${CPP%/*}"; then
+			echo "ok"
+			exit 0
+		else
+			echo "failed"
+			exit $?
+		fi
+	;;
+	*)
+		if patch_specs; then
+			echo "Toolchain successfully patched."
+			exit 0
+		else
+			echo "Failed to locate library directory!"
+			exit 1
+		fi
+	;;
+esac
diff --git a/scripts/portable_date.sh b/scripts/portable_date.sh
new file mode 100755
index 0000000000..84b56382e0
--- /dev/null
+++ b/scripts/portable_date.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+case $(uname) in
+	NetBSD|OpenBSD|DragonFly|FreeBSD|Darwin)
+		date -j -f "%Y-%m-%d %H:%M:%S %z" "$1" "$2" 2>/dev/null
+		;;
+	*)
+		date -d "$1" "$2"
+esac
+
+exit $?
diff --git a/scripts/redboot-script.pl b/scripts/redboot-script.pl
new file mode 100755
index 0000000000..e2d1264705
--- /dev/null
+++ b/scripts/redboot-script.pl
@@ -0,0 +1,111 @@
+#!/usr/bin/env perl
+#
+# Script for generating redboot configs, based on brcmImage.pl
+#
+# Copyright (C) 2015 Álvaro Fernández Rojas <noltari@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+use strict;
+use Getopt::Std;
+use File::stat;
+
+my $version = "0.1";
+my %arg = (
+	o => 'redboot.script',
+	s => 0x1000,
+	f => 0xbe430000,
+	a => 0x80010000,
+	l => 0x7c0000,
+	t => 20,
+);
+my $prog = $0;
+$prog =~ s/^.*\///;
+getopts("r:k:o:s:f:a:l:t:vh", \%arg);
+
+die "usage: $prog ~opts~
+
+  -r <file>	: input rootfs file
+  -k <file>	: input kernel file
+  -o <file>	: output image file, default $arg{o}
+  -s <size_kb>	: redboot script size, default ".sprintf('%d', parse_num($arg{s}))."
+  -f <baseaddr>	: flash base, default ".sprintf('0x%x', parse_num($arg{f}))."
+  -a <loadaddr>	: Kernel load address, default ".sprintf('0x%x', parse_num($arg{a}))."
+  -l <linux_kb>	: linux partition size, default ".sprintf('0x%x', parse_num($arg{l}))."
+  -t <timeout> 	: redboot script timeout, default ".sprintf('%d', parse_num($arg{t}))."
+  -v		: be more verbose
+  -h		: help, version $version
+
+EXAMPLES:
+    $prog -k kern -r rootfs
+" if $arg{h} || !$arg{k} || !$arg{r};
+
+sub parse_num
+{
+	my $num = @_[0];
+	if (index(lc($num), lc("0x")) == 0) {
+		return hex($num);
+	} else {
+		return $num + 0;
+	}
+}
+
+sub gen_script
+{
+	my $kernel_off = parse_num($arg{s});
+	my $kernel_addr = parse_num($arg{f});
+	my $kernel_len = stat($arg{k})->size;
+
+	my $rootfs_off = $kernel_off + $kernel_len;
+	my $rootfs_addr = $kernel_addr + $kernel_len;
+	my $rootfs_len = parse_num($arg{l}) - $kernel_len;
+	my $rootfs_size = stat($arg{r})->size;
+
+	my $load_addr = parse_num($arg{a});
+
+	my $timeout = parse_num($arg{t});
+
+	if ($arg{v}) {
+		printf "kernel_off: 0x%x(%u)\n", $kernel_off, $kernel_off;
+		printf "kernel_addr: 0x%x(%u)\n", $kernel_addr, $kernel_addr;
+		printf "kernel_len: 0x%x(%u)\n", $kernel_len, $kernel_len;
+
+		printf "rootfs_off: 0x%x(%u)\n", $rootfs_off, $rootfs_off;
+		printf "rootfs_addr: 0x%x(%u)\n", $rootfs_addr, $rootfs_addr;
+		printf "rootfs_len: 0x%x(%u)\n", $rootfs_len, $rootfs_len;
+		printf "rootfs_size: 0x%x(%u)\n", $rootfs_size, $rootfs_size;
+	}
+
+	open(FO, ">$arg{o}");
+	printf FO "fis init -f\n";
+	printf FO "\n";
+	printf FO "fconfig boot_script true\n";
+	printf FO "fconfig boot_script_data\n";
+	printf FO "fis load -b 0x%x -d kernel\n", $load_addr;
+	printf FO "exec -c \"noinitrd\" 0x%x\n", $load_addr;
+	printf FO "\n";
+	printf FO "fconfig boot_script_timeout %d\n", $timeout;
+	printf FO "\n";
+	printf FO "fis create -o 0x%x -f 0x%x -l 0x%x kernel\n", $kernel_off, $kernel_addr, $kernel_len;
+	printf FO "\n";
+	printf FO "fis create -o 0x%x -s 0x%x -f 0x%x -l 0x%x rootfs\n", $rootfs_off, $rootfs_size, $rootfs_addr, $rootfs_len;
+	printf FO "\n";
+	printf FO "reset\n";
+	close FO;
+}
+
+# MAIN
+gen_script();
diff --git a/scripts/relink-lib.sh b/scripts/relink-lib.sh
new file mode 100755
index 0000000000..5367b70935
--- /dev/null
+++ b/scripts/relink-lib.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+[ $# -lt 4 -o -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ] && {
+	echo "Usage: $0 <cross> <reference> <pic .a> <destination>"
+	exit 1
+}
+
+cross="$1"; shift
+ref="$1"; shift
+pic="$1"; shift
+dest="$1"; shift
+
+SYMBOLS="$(${cross}nm "$ref" | grep -E '........ [TW] ' | awk '$3 {printf "-u%s ", $3}')"
+set -x
+${cross}gcc -nostdlib -nostartfiles -shared -Wl,--gc-sections -o "$dest" $SYMBOLS "$pic" "$@"
diff --git a/scripts/remote-gdb b/scripts/remote-gdb
new file mode 100755
index 0000000000..efb321c243
--- /dev/null
+++ b/scripts/remote-gdb
@@ -0,0 +1,89 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use FindBin '$Bin';
+use File::Temp 'tempfile';
+
+@ARGV == 2 || do {
+	die "Usage: $0 <corefile|host:port> <executable>\n";
+	exit 1;
+};
+
+if( opendir SD, "$Bin/../staging_dir" )
+{
+	my ( $tid, $arch, $libc, @arches );
+
+	if( $ARGV[1] =~ m!\btarget-(.+?)_(([^/_]+libc|musl)[^/_]+)\b!i )
+	{
+		print("Using target $1 ($2)\n");
+		($arch, $libc) = ($1, $2);
+	}
+	else
+	{
+		# Find arches
+		print("Choose target:\n");
+
+		while( defined( my $e = readdir SD ) )
+		{
+			if( -d "$Bin/../staging_dir/$e" && $e =~ /^target-(.+?)_(([^_]+libc|musl).+)/i )
+			{
+				push @arches, [ $1, $2 ];
+				printf(" %2d) %s (%s)\n", @arches + 0, $1, $2);
+			}
+		}
+
+		if( @arches > 1 )
+		{
+			# Query arch
+			do {
+				print("Target? > ");
+				chomp($tid = <STDIN>);
+			} while( !defined($tid) || $tid !~ /^\d+$/ || $tid < 1 || $tid > @arches );
+
+			($arch, $libc) = @{$arches[$tid-1]};
+		}
+		else
+		{
+			($arch, $libc) = @{$arches[0]};
+		}
+	}
+
+	closedir SD;
+
+	# Find gdb
+	my ($gdb) = glob("$Bin/../staging_dir/toolchain-${arch}_*_${libc}*/bin/*-gdb");
+	if( defined($gdb) && -x $gdb )
+	{
+		my ( $fh, $fp ) = tempfile();
+
+		# Find sysroot
+		my ($sysroot) = glob("$Bin/../staging_dir/target-${arch}_${libc}*/root-*/");
+
+		print $fh "set sysroot $sysroot\n" if $sysroot;
+		my $cmd = "target extended-remote";
+		-f $ARGV[0] and $cmd = "core-file";
+		print $fh "$cmd $ARGV[0]\n";
+
+		# History settings
+		print $fh "set history filename $Bin/../tmp/.gdb_history\n";
+		print $fh "set history size 100000000\n";
+		print $fh "set history save on\n";
+
+		my $file = -f "$sysroot/$ARGV[1]" ? "$sysroot/$ARGV[1]" : $ARGV[1];
+		system($gdb, '-x', $fp, $file);
+
+		close($fh);
+		unlink($fp);
+	}
+	else
+	{
+		print("No gdb found! Make sure that CONFIG_GDB is set!\n");
+		exit(1);
+	}
+}
+else
+{
+	print("No staging_dir found! You need to compile at least once!\n");
+	exit(1);
+}
diff --git a/scripts/rstrip.sh b/scripts/rstrip.sh
new file mode 100755
index 0000000000..4e4232db60
--- /dev/null
+++ b/scripts/rstrip.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+SELF=${0##*/}
+
+[ -z "$STRIP" ] && {
+  echo "$SELF: strip command not defined (STRIP variable not set)"
+  exit 1
+}
+
+TARGETS=$*
+
+[ -z "$TARGETS" ] && {
+  echo "$SELF: no directories / files specified"
+  echo "usage: $SELF [PATH...]"
+  exit 1
+}
+
+find $TARGETS -type f -a -exec file {} \; | \
+  sed -n -e 's/^\(.*\):.*ELF.*\(executable\|relocatable\|shared object\).*,.* stripped/\1:\2/p' | \
+(
+  IFS=":"
+  while read F S; do
+    echo "$SELF: $F: $S"
+	[ "${S}" = "relocatable" ] && {
+		eval "$STRIP_KMOD $F"
+	} || {
+		b=$(stat -c '%a' $F)
+		[ -z "$PATCHELF" ] || [ -z "$TOPDIR" ] || {
+			old_rpath="$($PATCHELF --print-rpath $F)"; new_rpath=""
+			for path in $old_rpath; do
+				case "$path" in
+					/lib/[^/]*|/usr/lib/[^/]*|\$ORIGIN/*) new_rpath="${new_rpath:+$new_rpath:}$path" ;;
+					*) echo "$SELF: $F: removing rpath $path" ;;
+				esac
+			done
+			[ "$new_rpath" = "$old_rpath" ] || $PATCHELF --set-rpath "$new_rpath" $F
+		}
+		eval "$STRIP $F"
+		a=$(stat -c '%a' $F)
+		[ "$a" = "$b" ] || chmod $b $F
+	}
+  done
+  true
+)
diff --git a/scripts/slugimage.pl b/scripts/slugimage.pl
new file mode 100755
index 0000000000..deac6ac6dd
--- /dev/null
+++ b/scripts/slugimage.pl
@@ -0,0 +1,1217 @@
+#!/usr/bin/env perl
+# 
+# SlugImage : Manipulate NSLU2 firmware images
+#             Dwayne Fontenot (jacques)
+#             Rod Whitby (rwhitby)
+#	      www.nslu2-linux.org
+#
+# Copyright (c) 2004, 2006, Dwayne Fontenot & Rod Whitby
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+# Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 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.
+# Neither the name of the NSLU2-Linux Development Team nor the names
+# of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+# 
+# 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 OWNER 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.
+#
+
+use strict;
+use warnings;
+
+use Getopt::Long qw(:config no_ignore_case);
+use POSIX qw(tmpnam);
+
+my($debug) = 0;
+my($quiet) = 0;
+my($flash_start)    = 0x50000000;
+my($flash_len)      = 0x00800000;
+my($block_size)     = 0x00020000;
+my($kernel_offset)  = 0x00060000;
+my($kernel_size)    = 0x00100000;
+my($ramdisk_offset) = 0x00160000;
+my(@cleanup);
+
+# The last 70 bytes of the SercommRedBootTrailer (i.e. excluding MAC
+# address).  Needed to create an image with an empty RedBoot partition
+# since the Sercomm upgrade tool checks for this trailer.
+# http://www.nslu2-linux.org/wiki/Info/SercommRedBootTrailer
+my @sercomm_redboot_trailer = (0x4573, 0x4372, 0x4d6f, 0x006d, 0x0001,
+       0x0400, 0x3170, 0x5895, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0003, 0x2300,
+       0x0063, 0x0000, 0x7320, 0x7245, 0x6f43, 0x6d4d);
+
+# There's a 16 byte Sercomm trailer at the end of the flash. It is used
+# by RedBoot to detect a Sercomm flash layout and to configure the
+# Sercomm upgrade system.
+# http://www.nslu2-linux.org/wiki/Info/SercommFlashTrailer
+my @sercomm_flash_trailer = (0x0100, 0x0000, 0x6323, 0xf790, 0x5265,
+                             0x4f63, 0x4d6d, 0xb400);
+
+# Take $data, and pad it out to $total_len bytes, appending 0xff's.
+sub padBytes {
+    my($data,$total_len) = @_;
+
+    # 0xFF is used to pad, as it's the erase value of the flash.
+    my($pad_char) = pack("C",0xff);
+    my($pad_len) = $total_len - length($data);
+
+    # A request for negative padding is indicative of a logic error ...
+    if (length($data) > $total_len) {
+	die sprintf("padBytes error: data (%d) is longer than total_len (%d)", length($data), $total_len);
+    }
+
+    return $data . ($pad_char x $pad_len);
+}
+
+# Return the next multiple of block_size larger than or equal to $data_len.
+sub paddedSize {
+    my($data_len) = @_;
+
+    use integer;
+    return (($data_len - 1) / $block_size) * $block_size + $block_size;
+}
+
+# Return the number of block_size blocks required to hold $data_len.
+sub numBlocks {
+    my($data_len) = @_;
+
+    use integer;
+    return (($data_len - 1) / $block_size) + 1;
+}
+
+# Pack the name, address, size and optional skip regions of a partition entry into binary form.
+sub createPartitionEntry {
+    my($name, $flash_base, $size, $skips) = @_;
+    my $entry;
+
+    my($zero_long) = 0x0000;
+
+    # Pack the partition entry according to the format that RedBoot (and the MTD partition parsing code) requires.
+    $entry = pack("a16N5x212N2",$name,$flash_base,$zero_long,$size,$zero_long,$zero_long,$zero_long,$zero_long);
+
+    # Optionally put a skip header into the padding area.
+    if (defined $skips) {
+	my $i = scalar(@$skips);
+	foreach my $region (@$skips) {
+	    substr($entry, -8 - 12*$i, 12) =
+		pack("a4N2", "skip", $region->{'offset'}, $region->{'size'});
+	    $i--;
+	}
+    }
+
+    return $entry;
+}
+
+# Parse partition entry and return anon array ref [$name, $offset, $size, $skip] or return 0 on partition terminator.
+sub parsePartitionEntry {
+    my($partition_entry) = @_;
+
+    my($entry_len) = 0x100;
+    length($partition_entry) eq $entry_len or die "parsePartitionEntry: partition entry length is not $entry_len!\n";
+
+    # Unpack the partition table entry, saving those values in which we are interested.
+    my($name, $flash_base, $size, $dummy_long, $padding, $skips);
+    ($name, $flash_base, $dummy_long, $size, $dummy_long, $dummy_long, $padding, $dummy_long, $dummy_long) =
+	unpack("a16N5a212N2",$partition_entry);
+
+    # A partition entry starting with 0xFF terminates the table.
+    if (unpack("C", $name) eq 0xff) {
+	# %%% FIXME: This should only skip, not terminate. %%%
+	$debug and print "Found terminator for <FIS directory>\n";
+	return 0;
+    }
+
+    # Remove trailing nulls from the partition name.
+    $name =~ s/\000+//;
+
+    # Extract the skip regions out of the padding area.
+    $padding =~ s/^\000+//;
+    $padding =~ s/\000*skip(........)\000*/$1/g;
+    $padding =~ s/\000+$//;
+
+    # Store the skip regions in an array for later use.
+    while (length($padding)) {
+	my $region = {};
+	($region->{'offset'}, $region->{'size'}) =
+	    unpack("N2", $padding);
+	$debug and printf("Found skip region at 0x%05X, size 0x%05X\n",
+			  $region->{'offset'}, $region->{'size'});
+	push(@$skips, $region);
+	$padding = substr($padding,8);
+    }
+
+    return [$name, $flash_base - $flash_start, $size, $skips];
+}
+
+# Return partition table from data is one exists, otherwise return 0.
+sub findPartitionTable {
+    my($data_buf) = @_;
+
+    unpack("a7", $data_buf) eq 'RedBoot' or return 0;
+    return substr($data_buf, 0, 0x1000)
+}
+
+# Parse partition table and return array of anonymous array references ([$name, $offset, $size, $skips], ...).
+sub parsePartitionTable {
+    my($partition_table) = @_;
+
+    my(@partitions, $fields_ref);
+    my($entry_len) = 0x100;
+    my($partition_count) = 0;
+
+    # Loop through the fixed size partition table entries, and store the entries in @partitions.
+    # %%% FIXME: This doesn't handle the case of a completely full partition table. %%%
+    while ($fields_ref = parsePartitionEntry(substr($partition_table, $partition_count * $entry_len, $entry_len))) {
+	$debug and printf("Found <%s> at 0x%08X (%s)%s\n", $fields_ref->[0], $fields_ref->[1],
+			  ($fields_ref->[2] >= $block_size ?
+			   sprintf("%d blocks", numBlocks($fields_ref->[2])) :
+			   sprintf("0x%05X bytes", $fields_ref->[2])),
+			  (defined $fields_ref->[3] ?
+			   sprintf(" [%s]",
+				   join(", ",
+					map { sprintf("0x%05X/0x%05X", $_->{'offset'},$_->{'size'}) }
+					@{$fields_ref->[3]})) :
+			   ""));
+	$partitions[$partition_count++] = $fields_ref;
+    }
+    return(@partitions);
+}
+
+# Create an empty jffs2 block.
+sub jffs2Block {
+    return padBytes(pack("N3", 0x19852003, 0x0000000c, 0xf060dc98), $block_size);
+}
+
+# Write out $data to $filename,
+sub writeOut {
+    my($data, $filename) = @_;
+
+    open FILE,">$filename" or die "Can't open file \"$filename\": $!\n";
+
+    if (defined($data)) { print FILE $data;}
+
+    close FILE or die "Can't close file \"$filename\": $!\n";
+}
+
+# Not used at the moment.
+sub trailerData {
+    my($product_id)       = 0x0001;
+    my($protocol_id)      = 0x0000;
+    my($firmware_version) = 0x2325;
+    my($unknown1)         = 0x90f7;
+    my($magic_number)     = 'eRcOmM';
+    my($unknown2)         = 0x00b9;
+
+    return pack("n4a6n",$product_id,$protocol_id,$firmware_version,$unknown1,$magic_number,$unknown2);
+}
+
+# Print the contents of the Sercomm RedBoot trailer.
+sub printRedbootTrailer {
+    my($redboot_data) = @_;
+
+    my($correct_redboot_len) = 0x40000;
+    my($redboot_data_len) = length($redboot_data);
+
+    if ($redboot_data_len != $correct_redboot_len) {
+	printf("Redboot length (0x%08X) is not 0x%08X\n", $redboot_data_len, $correct_redboot_len);
+	return;
+    }
+
+    # The trailer is the last 80 bytes of the redboot partition.
+    my($redboot_trailer) = substr($redboot_data, -80);
+
+    writeOut($redboot_trailer, 'RedbootTrailer');
+
+    my($mac_addr0, $mac_addr1, $mac_addr2, $unknown, $prefix, $ver_ctrl, $down_ctrl, $hid, $hver, $prodid, $prodidmask,
+       $protid, $protidmask, $funcid, $funcidmask, $fver, $cseg, $csize, $postfix) =
+	   unpack("n3Na7n2a32n10a7",$redboot_trailer);
+
+    printf("MAC address is %04X%04X%04X\n", $mac_addr0, $mac_addr1, $mac_addr2);
+    printf("unknown: %08X\n", $unknown);
+    printf("%s:%04X:%04X:%s\n", $prefix, $ver_ctrl, $down_ctrl, $postfix);
+    printf("VerControl: %04X\nDownControl: %04X\n", $ver_ctrl, $down_ctrl);
+    printf("hid: %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X\n", unpack("n16", $hid));
+    printf("Hver: %04X\nProdID: %04X\nProtID: %04X\nFuncID: %04X\nFver: %04X\nCseg: %04X\nCsize: %04X\n",
+	   $hver, $prodid, $protid, $funcid, $fver, $cseg, $csize);
+}
+
+# remove the optional Loader partition
+sub removeOptionalLoader {
+    my($partitions_ref) = @_;
+
+    my $index;
+    my $count = 0;
+    map {
+	if (not defined $index) {
+	    if ($_->{'name'} eq "Loader") {
+		$index = $count;
+	    }
+	    $count++;
+	}
+    } @$partitions_ref;
+    
+    defined $index or die "Cannot find the Loader partition\n";
+
+    splice(@$partitions_ref, $index, 1);
+
+    # Set fixed offsets and sizes for Kernel and Ramdisk
+    map {
+	if ($_->{'name'} eq 'Kernel') {
+	    $_->{'offset'}   = $kernel_offset;
+	    $_->{'size'}     = $kernel_size;
+	    $_->{'variable'} = 0;
+	}
+	if ($_->{'name'} eq 'Ramdisk') {
+	    $_->{'offset'}   = $ramdisk_offset;
+	}
+    } @$partitions_ref;
+
+    return;
+}
+
+
+# populate @partitions based on the firmware's partition table
+sub spliceFirmwarePartitions {
+    my($firmware_buf, $partitions_ref) = @_;
+
+    # we know that partition table, if it exists, begins at start of 'FIS directory' and has max length 0x1000
+    my($partition_table);
+    map {
+	$_->{'name'} eq 'FIS directory' and
+	    $partition_table = findPartitionTable(substr($firmware_buf, $_->{'offset'}, $_->{'size'}));
+    } @$partitions_ref;
+
+    # return 0 here if no partition table in FIS directory
+    return if not $partition_table;
+
+    my @new_partitions = parsePartitionTable($partition_table);
+
+    # Remove the optional second stage bootloader if it is not found in the FIS directory.
+    if (not grep { $_->[0] eq 'Loader' } @new_partitions) {
+	removeOptionalLoader($partitions_ref);
+    }
+
+    my($partition_count) = 0;
+    my($splice) = 0;
+    map {
+
+	# Skip pseudo partitions.
+	while (($partition_count < scalar(@$partitions_ref)) and
+	       $partitions_ref->[$partition_count]->{'pseudo'}) {
+	    $debug and printf("Skipped <%s> (pseudo partition)\n", $partitions_ref->[$partition_count]->{'name'});
+	    $partition_count++;
+	}
+
+	# If we are in a variable area, and we haven't reached the end of it,
+	# then splice in another partition for use by the later code.
+	if ($splice and ($partitions_ref->[$partition_count]->{'name'} ne $_->[0])) {
+	    $debug and printf("Splicing new partition <%s> before <%s>\n",
+			      $_->[0], $partitions_ref->[$partition_count]->{'name'});
+	    splice(@{$partitions_ref}, $partition_count, 0, ({'name' => "",'variable'=>1,'header'=>0}));
+	}
+
+	my $partition = $partitions_ref->[$partition_count];
+
+	# Variable partitions can be overridden by the real FIS directory
+	if ($partition->{'variable'}) {
+
+	    # Only override the filename if the partition name is not set or doesn't match
+	    if ($partition->{'name'} ne $_->[0]) {
+
+		if (length($partition->{'name'})) {
+		    $debug and printf("Overwriting <%s> with <%s>\n",
+				      $partitions_ref->[$partition_count]->{'name'}, $_->[0]);
+		}
+
+		$partition->{'name'} = $_->[0];
+		$partition->{'file'} = $_->[0];
+	    }
+
+	    # Set the offset, size and skips based on the real partition table
+	    $partition->{'offset'} = $_->[1];
+	    $partition->{'size'}   = $_->[2];
+	    $partition->{'skips'}  = $_->[3];
+
+	    $debug and printf("Locating <%s> at 0x%08X (%s)\n",
+			      $partition->{'name'}, $partition->{'offset'},
+			      ($partition->{'size'} >= $block_size ?
+			       sprintf("%d blocks", numBlocks($partition->{'size'})) :
+			       sprintf("0x%05X bytes", $partition->{'size'})));
+
+	    $splice = 1;
+	}
+
+	# Fixed partitions cannot be overridden
+	else {
+	    ($partition->{'name'} eq $_->[0]) or
+		die "Unexpected partition <",$_->[0],"> (expecting <",$partition->{'name'},">)\n";
+
+	    $debug and printf("Locating <%s> at 0x%08X (%s)\n",
+			      $partition->{'name'}, $partition->{'offset'},
+			      ($partition->{'size'} >= $block_size ?
+			       sprintf("%d blocks", numBlocks($partition->{'size'})) :
+			       sprintf("0x%05X bytes", $partition->{'size'})));
+	    
+	    $splice = 0;
+	}
+	
+	$partition_count++;
+
+    } @new_partitions;
+
+    return;
+}
+
+# Read in an 8MB firmware file, and store the data into @partitions.
+# Note that the data is only stored in a partition if 'offset' and 'size' are defined,
+# and it does not already have data stored in it.
+sub readInFirmware {
+    my($filename, $partitions_ref) = @_;
+
+    my($firmware_buf);
+
+    open FILE,$filename or die "Can't find firmware image \"$filename\": $!\n";
+    read FILE,$firmware_buf,$flash_len or die "Can't read $flash_len bytes from \"$filename\": $!\n";
+    close FILE or die "Can't close \"$filename\": $!\n";
+
+    $debug and printf("Read 0x%08X bytes from \"%s\"\n", length($firmware_buf), $filename);
+
+    spliceFirmwarePartitions($firmware_buf, $partitions_ref);
+
+    # Read the parts of the firmware file into the partitions table.
+    map {
+	if (defined $_->{'offset'} and defined $_->{'size'}) {
+
+	    if (defined $_->{'data'}) {
+		$debug and printf("Not overwriting data in <%s>\n", $_->{'name'});
+	    }
+	    else {
+
+		# Slurp up the data, based on whether a header and/or data is present or not
+		if ($_->{'header'}) {
+
+		    # Read the length, and grab the data based on the length.
+		    my($data_len) = unpack("N", substr($firmware_buf, $_->{'offset'}));
+
+		    # A length of 0xFFFFFFFF means that the area is not initialised
+		    if ($data_len != 0xFFFFFFFF) {
+			$debug and printf("Found header size of 0x%08X bytes for <%s>\n", $data_len, $_->{'name'});
+			$_->{'data'} = substr($firmware_buf, $_->{'offset'} + $_->{'header'}, $data_len);
+		    }
+		}
+		elsif ($_->{'pseudo'} and not defined $_->{'file'} and
+		       (substr($firmware_buf, $_->{'offset'}, $_->{'size'}) eq
+			(pack("C", 0xff) x $_->{'size'}))) {
+		    $debug and printf("Skipping empty pseudo partition <%s>\n", $_->{'name'});
+		}
+		else {
+
+		    # Grab the whole partition, using the maximum size.
+		    $_->{'data'} = substr($firmware_buf, $_->{'offset'}, $_->{'size'});
+		}
+
+		# If skip regions are defined, remove them from the data.
+		if (defined $_->{'skips'}) {
+		    my $removed = 0;
+		    foreach my $region (@{$_->{'skips'}}) {
+			if (($region->{'offset'} > 0) or
+			    not ($_->{'header'} > 0)) {
+			    $debug and printf("Removing 0x%05X bytes from offset 0x%05X\n",
+					      $region->{'size'}, $region->{'offset'});
+			    $region->{'data'} = substr($_->{'data'}, $region->{'offset'} - $removed, $region->{'size'}, '');
+			}
+			$removed += $region->{'size'};
+		    }
+		}
+
+		$quiet or defined $_->{'data'} and printf("Read %s into <%s>\n",
+							  (length($_->{'data'}) >= $block_size ?
+							   sprintf("%d blocks", numBlocks(length($_->{'data'}))) :
+							   sprintf("0x%05X bytes", length($_->{'data'}))), $_->{'name'});
+	    }
+	}
+    } @$partitions_ref;
+}
+
+# Write the partition data stored in memory out into the files associated with each.
+sub writeOutFirmwareParts {
+    my(@partitions) = @_;
+
+    # Write out the parts of the firmware file.
+    map {
+
+	# We can only write if 'data' and 'file' are defined.
+	if (defined $_->{'file'} and defined $_->{'data'} and length($_->{'data'})) {
+	    writeOut($_->{'data'}, $_->{'file'});
+	    $quiet or printf("Wrote 0x%08X bytes from <%s> into \"%s\"\n",
+			      length($_->{'data'}), $_->{'name'}, $_->{'file'});
+	}
+	else {
+	    $debug and printf("Skipping <%s> (%s)\n", $_->{'name'},
+			      (not defined $_->{'file'}) ?
+			      "no filename specified" :
+			      "no data to write");
+	}
+
+    } @partitions;
+
+    return;
+}
+
+# Read in the partition data from the files associated with each and store in memory.
+sub readInFirmwareParts {
+    my(@partitions) = (@_);
+    
+    undef $/; # we want to slurp
+
+    map {
+
+	my $file = $_->{'file'};
+	if (defined $file) {
+	    open FILE,$file or die "Can't find firmware part \"$file\": $!\n";
+
+	    # Slurp in the data
+	    $_->{'data'} = <FILE>;
+
+	    # close the file
+	    close FILE or die "Can't close file \"$file\": $!\n";
+
+	    # Optionally byteswap the data
+	    if ($_->{'byteswap'}) {
+		# Byte swap the data (which has to be padded to a multiple of 4 bytes).
+		$_->{'data'} = pack("N*", unpack("V*", $_->{'data'}.pack("CCC", 0)));
+	    }
+
+	    # Keep track of the actual size.
+	    my $size;
+
+	    if ($_->{'header'}) {
+		if ($_->{'pseudo'}) {
+		    $size = $_->{'header'} + length($_->{'data'});
+		}
+		else {
+		    $size = paddedSize($_->{'header'} + length($_->{'data'}));
+		}
+	    }
+	    elsif (not $_->{'pseudo'}) {
+		$size = paddedSize(length($_->{'data'}));
+	    }
+	    else {
+		$size = length($_->{'data'});
+	    }
+
+	    # Check to make sure the file contents are not too large.
+	    if (defined $_->{'size'} and ($size > $_->{'size'})) {
+		die sprintf("Ran out of flash space in <%s> - %s too large.\n", $_->{'name'},
+			    sprintf("0x%05X bytes", ($size - $_->{'size'})));
+	    }
+
+	    # If the partition does not have a fixed size, the calculate the size.
+	    if (not defined $_->{'size'}) {
+		$_->{'size'} = $size;
+	    }
+
+	    # Keep the user appraised ...
+	    $quiet or printf("Read 0x%08X bytes from \"%s\" into <%s> (%s / %s)%s\n",
+			     length($_->{'data'}), $_->{'file'}, $_->{'name'},
+			     ($size >= $block_size ?
+			      sprintf("%d blocks", numBlocks($size)) :
+			      sprintf("0x%05X bytes", $size)),
+			     ($_->{'size'} >= $block_size ?
+			      sprintf("%d blocks", numBlocks($_->{'size'})) :
+			      sprintf("0x%05X bytes", $_->{'size'})),
+			     ($_->{'byteswap'} ? " (byte-swapped)" : ""));
+	}
+
+    } @partitions;
+
+    return;
+}
+
+# layoutPartitions : this function must be ugly - it needs to verify RedBoot, SysConf, Kernel, Ramdisk, and
+#     FIS directory partitions exist, are in the correct order, and do not have more data than can fit in
+#     their lengths (fixed for all but Ramdisk, which has a minimum length of one block).
+#     If Rootdisk and/or Userdisk exist, it must also verify that their block padded lengths are not
+#     too great for the available space.
+# input : an array of hashes, some of which are populated with data
+# output: same reference with start and size (partition not data) also populated. this populated structure
+#         can then be passed to buildPartitionTable() to generate the actual partition table data
+sub layoutPartitions {
+    my(@partitions) = @_;
+
+    # Find the kernel partition, and save a pointer to it for later use
+    my $kernel;
+    map { ($_->{'name'} eq "Kernel") && ($kernel = $_); } @partitions;
+    $kernel or die "Couldn't find the kernel partition\n";
+
+    # Find the last variable size partition, and save a pointer to it for later use
+    my $lastdisk;
+    my $directory_offset;
+    my $curdisk = $partitions[0];
+    map {
+	if (not defined $lastdisk) {
+	    if ($_->{'name'} eq "FIS directory") {
+		$lastdisk = $curdisk;
+		$directory_offset = $_->{'offset'};
+	    }
+	    else {
+		$curdisk = $_;
+	    }
+	}
+    } @partitions;
+
+    $lastdisk or die "Couldn't find the last variable size partition\n";
+
+    $debug and printf("Last variable size partition is <%s>\n", $lastdisk->{'name'});
+
+    #
+    # here we go through the $partitions array ref and fill in all the values
+    #
+
+    # This points to where the next partition should be placed.
+    my $pointer = $flash_start;
+
+    map {
+
+	$debug and printf("Pointer is 0x%08X\n", $pointer);
+
+	# Determine the start and offset of the current partition.
+	if (defined $_->{'offset'}) {
+	    $_->{'start'} = $flash_start + $_->{'offset'};
+	    # Check for running past the defined start of the partition.
+	    if (($pointer > $_->{'start'}) and not $_->{'pseudo'}) {
+		die sprintf("Ran out of flash space before <%s> - %s too large.\n", $_->{'name'},
+			    sprintf("0x%05X bytes", ($pointer - $_->{'start'})));
+	    }
+	}
+
+	# If offset is not defined, then calculate it.
+	else {
+	    $_->{'start'} = $pointer;
+	    $_->{'offset'} = $_->{'start'} - $flash_start;
+	}
+
+	my $size = defined $_->{'data'} ? length($_->{'data'}) : 0;
+
+	# Add skip regions for the partitions with headers.
+	if ($_->{'header'} > 0) {
+	    # Define the skip region for the initial Sercomm header.
+	    push(@{$_->{'skips'}},
+		 { 'offset' => 0, 'size' => $_->{'header'}, 'data' => undef });
+	    # Allow for the Sercomm header to be prepended to the data.
+	    $size += $_->{'header'};
+
+	    # Determine if the partition overlaps the ramdisk boundary.
+	    if (($_->{'offset'} < $ramdisk_offset) and
+		(($_->{'offset'} + $size) > $ramdisk_offset)) {
+		# Define the skip region for the inline Sercomm header.
+		push(@{$_->{'skips'}},
+		     { 'offset' => ($ramdisk_offset - $_->{'offset'}), 'size' => 16,
+		       'data' => pack("N4", $block_size) });
+		# Allow for the Sercomm header to be inserted in the data.
+		$size += 16;
+	    }
+	}
+
+	# Partitions without headers cannot have skip regions.
+	elsif (($_->{'offset'} <= $ramdisk_offset) and
+	       (($_->{'offset'} + $size) > $ramdisk_offset)) {
+	    # Pad the kernel until it extends past the ramdisk offset.
+	    push(@{$kernel->{'skips'}},
+		 { 'offset' => ($ramdisk_offset - $kernel->{'offset'}), 'size' => 16,
+		   'data' => pack("N4", $block_size) });
+	    $kernel->{'size'} = $ramdisk_offset - $kernel->{'offset'} + $block_size;
+	    $kernel->{'data'} = padBytes($kernel->{'data'},
+					 $kernel->{'size'} - $kernel->{'header'} - 16);
+	    $_->{'offset'} = $ramdisk_offset + $block_size;
+	    $_->{'start'} = $flash_start + $_->{'offset'};
+	    $pointer = $_->{'start'};
+	    $debug and printf("Extending kernel partition past ramdisk offset.\n");
+	}
+
+	# If this is the last variable size partition, then fill the rest of the space.
+	if ($_->{'name'} eq $lastdisk->{'name'}) {
+	    $_->{'size'} = paddedSize($directory_offset + $flash_start - $pointer);
+	    $debug and printf("Padding last variable partition <%s> to 0x%08X bytes\n", $_->{'name'}, $_->{'size'});
+	}
+
+	die sprintf("Partition size not defined in <%s>.\n", $_->{'name'})
+	    unless defined $_->{'size'};
+
+	# Extend to another block if required.
+	if ($size > $_->{'size'}) {
+	    if ($_->{'name'} eq $lastdisk->{'name'}) {
+		die sprintf("Ran out of flash space in <%s> - %s too large.\n", $_->{'name'},
+			    sprintf("0x%05X bytes", ($size - $_->{'size'})));
+	    }
+	    $_->{'size'} = $size;
+	    printf("Extending partition <%s> to 0x%08X bytes\n", $_->{'name'}, $_->{'size'});
+	}
+
+	# Keep the user appraised ...
+	$debug and printf("Allocated <%s> from 0x%08X to 0x%08X (%s / %s)\n",
+			  $_->{'name'}, $_->{'start'}, $_->{'start'} + $_->{'size'},
+			  ($size >= $block_size ?
+			   sprintf("%d blocks", numBlocks($size)) :
+			   sprintf("0x%05X bytes", $size)),
+			  ($_->{'size'} >= $block_size ?
+			   sprintf("%d blocks", numBlocks($_->{'size'})) :
+			   sprintf("0x%05X bytes", $_->{'size'})));
+
+	# Check to make sure we have not run out of room.
+	if (($_->{'start'} + $_->{'size'}) > ($flash_start + $flash_len)) {
+	    die "Ran out of flash space in <", $_->{'name'}, ">\n";
+	}
+
+	$debug and printf("Moving pointer from 0x%08X to 0x%08X (0x%08X + 0x%08X)\n",
+			  $pointer, paddedSize($_->{'start'} + $_->{'size'}),
+			  $_->{'start'}, $_->{'size'});
+
+	# Move the pointer up, in preparation for the next partition.
+	$pointer = paddedSize($_->{'start'} + $_->{'size'});
+
+    } @partitions;
+
+    return;
+}
+
+sub buildPartitionTable {
+    my(@partitions) = @_;
+
+    my($flash_start) = 0x50000000;
+    my($partition_data) = '';
+
+    map {
+
+	# Collate the partition data for all known partitions.
+	if (not $_->{'pseudo'} and defined $_->{'offset'} and defined $_->{'size'}) {
+
+	    # Pack and append the binary table entry for this partition.
+	    $partition_data .= createPartitionEntry($_->{'name'}, $_->{'offset'} + $flash_start,
+						    $_->{'size'}, $_->{'skips'});
+
+	    # If this is the FIS directory, then write the partition table data into it.
+	    if ($_->{'name'} eq "FIS directory") {
+		# Explicitly terminate the partition data.
+		$partition_data .= pack("C",0xff) x 0x100;
+		$_->{'data'} = padBytes($partition_data, $_->{'size'});
+	    }
+
+	    my $size = length($_->{'data'});
+
+	    # Keep the user appraised ...
+	    $debug and printf("Table entry <%s> from 0x%08X to 0x%08X (%s / %s)%s\n",
+			      $_->{'name'}, $_->{'start'}, $_->{'start'} + $_->{'size'},
+			      ($size >= $block_size ?
+			       sprintf("%d blocks", numBlocks($size)) :
+			       sprintf("0x%05X bytes", $size)),
+			      ($_->{'size'} >= $block_size ?
+			       sprintf("%d blocks", numBlocks($_->{'size'})) :
+			       sprintf("0x%05X bytes", $_->{'size'})),
+			      (defined $_->{'skips'} ?
+			       sprintf("\nTable entry <%s> skip %s", $_->{'name'},
+				       join(", ",
+					    map { sprintf("0x%08X to 0x%08X", $_->{'offset'},
+							  $_->{'offset'} + $_->{'size'} - 1) }
+					    @{$_->{'skips'}})) :
+			       "")
+			      );
+	}
+	else {
+	    $debug and print "No table entry required for <", $_->{'name'}, ">\n";
+	}
+
+    } @partitions;
+
+    return;
+}
+
+sub writeOutFirmware {
+    my($filename, @partitions) = @_;
+
+    # Clear the image to start.
+    my $image_buf = "";
+
+    map {
+
+	# We can only write a partition if it has an offset, a size, and some data to write.
+	if (defined $_->{'offset'} and defined $_->{'size'} and defined $_->{'data'}) {
+
+	    # Keep track of the end of the image.
+	    my $end_point = length($image_buf);
+
+	    # If the next partition is well past the end of the current image, then pad it.
+	    if ($_->{'offset'} > $end_point) {
+		$image_buf .= padBytes("", $_->{'offset'} - $end_point);
+		$quiet or printf("Padded %s before <%s> in \"%s\"\n",
+				 ((length($image_buf) - $end_point) >= $block_size ?
+				  sprintf("%d blocks", numBlocks(length($image_buf) - $end_point)) :
+				  sprintf("0x%05X bytes", length($image_buf) - $end_point)),
+				 $_->{'name'}, $filename);
+	    }
+
+	    # If the next parition is before the end of the current image, then rewind.
+	    elsif ($_->{'offset'} < $end_point) {
+		$debug and printf("Rewound %s before <%s> in \"%s\"\n",
+				  (($end_point - $_->{'offset'}) >= $block_size ?
+				   sprintf("%d blocks", numBlocks($end_point - $_->{'offset'})) :
+				   sprintf("0x%05X bytes", $end_point - $_->{'offset'})),
+				  $_->{'name'}, $filename);
+# 		if (($end_point - $_->{'offset'}) >= $block_size) {
+# 		    die "Allocation error: rewound a full block or more ...\n";
+# 		}
+	    }
+
+	    # If skip regions are defined, add them to the data.
+	    if (defined $_->{'skips'}) {
+		my $added = 0;
+		foreach my $region (@{$_->{'skips'}}) {
+		    if (($region->{'offset'} > 0) or
+			not ($_->{'header'} > 0)) {
+			$debug and printf("Inserted 0x%05X bytes (at offset 0x%05X) into <%s>\n",
+					  $region->{'size'}, $region->{'offset'}, $_->{'name'});
+			substr($_->{'data'},
+			       $region->{'offset'} + $added - $_->{'header'},
+			       0, $region->{'data'});
+			$added += $region->{'size'};
+		    }
+		}
+	    }
+
+	    # Splice the data into the image at the appropriate place, padding as required.
+	    substr($image_buf, $_->{'offset'}, $_->{'size'},
+		   $_->{'header'} ?
+		   padBytes(pack("N4",length($_->{'data'})).$_->{'data'}, $_->{'size'}) :
+		   padBytes($_->{'data'}, $_->{'size'}));
+	    
+	    # Keep the user appraised ...
+	    $quiet or printf("Wrote %s (0x%08X to 0x%08X) from <%s> into \"%s\"\n",
+			     ($_->{'size'} >= $block_size ?
+			      sprintf("%2d blocks", numBlocks($_->{'size'})) :
+			      sprintf("0x%05X bytes", $_->{'size'})),
+			     $_->{'offset'}, $_->{'offset'}+$_->{'size'}, $_->{'name'}, $filename);
+	}
+
+	# If we are not able to write a partition, then give debug information about why.
+	else {
+	    $debug and printf("Skipping <%s> (%s)\n", $_->{'name'},
+			      (not defined $_->{'offset'}) ? "no offset defined" :
+			      ((not defined $_->{'size'}) ? "no size defined" :
+			       "no data available"));
+	}
+
+    } @partitions;
+
+    # Write the image to the specified file.
+    writeOut($image_buf, $filename);
+
+    return;
+}
+
+# checkPartitionTable: sanity check partition table - for testing but might evolve into setting @partitions
+#    so that we can write out jffs2 partitions from a read image
+#    currently not nearly paranoid enough
+sub checkPartitionTable {
+    my($data) = @_;
+
+    my($pointer) = 0;
+    my($entry);
+
+    my($name, $flash_base, $size, $done, $dummy_long, $padding);
+    do {
+	$entry = substr($data, $pointer, 0x100);
+
+	($name,$flash_base,$dummy_long,$size,$dummy_long,$dummy_long,$padding,$dummy_long,$dummy_long) = unpack("a16N5x212N2",$entry);
+	$name =~ s/\0//g;
+	$debug and printf("pointer: %d\tname: %s%sflash_base: 0x%08X\tsize: 0x%08X\n",
+			  $pointer, $name, (" " x (16 - length($name))), $flash_base, $size);
+	$pointer += 0x100;
+	$debug and printf("terminator: 0x%08X\n", unpack("C", substr($data, $pointer, 1)));
+	if (unpack("C", substr($data, $pointer, 1)) eq 0xff) {
+	    $done = 1;
+	}
+    } until $done;
+}
+
+sub printPartitions {
+    my(@partitions) = @_;
+
+    my($offset, $size, $skips);
+    map {
+#	defined $_->{'size'} ? $size = $_->{'size'} : $size = undef;
+
+	if (defined  $_->{'size'}) {
+	    $size = $_->{'size'};
+	}
+	else {
+	    $size = undef;
+	}
+	if (defined  $_->{'offset'}) {
+	    $offset = $_->{'offset'};
+	}
+	else {
+	    $offset = undef;
+	}
+	if (defined  $_->{'skips'}) {
+	    $skips = $_->{'skips'};
+	}
+	else {
+	    $skips = undef;
+	}
+	printf("%s%s", $_->{'name'}, (" " x (16 - length($_->{'name'}))));
+	if (defined $offset) { printf("0x%08X\t", $offset); } else { printf("(undefined)\t");   };
+	if (defined $size)   { printf("0x%08X", $size); } else { printf("(undefined)"); };
+	if (defined $skips) {
+	    printf("\t[%s]",
+		   join(", ",
+			map { sprintf("0x%05X/0x%05X", $_->{'offset'}, $_->{'size'}); }
+			@$skips));
+	}
+	printf("\n");
+    } @partitions;
+}
+
+sub defaultPartitions {
+
+    return ({'name'=>'RedBoot',          'file'=>'RedBoot',
+	     'offset'=>0x00000000,        'size'=>0x00040000,
+	     'variable'=>0, 'header'=>0,  'pseudo'=>0, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'EthAddr',           'file'=>undef,
+	     'offset'=>0x0003ffb0,        'size'=>0x00000006,
+	     'variable'=>0, 'header'=>0,  'pseudo'=>1, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'SysConf',           'file'=>'SysConf',
+	     'offset'=>0x00040000,        'size'=>0x00020000,
+	     'variable'=>0, 'header'=>0,  'pseudo'=>0, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'Loader',            'file'=>'apex.bin',
+	     'offset'=>undef,             'size'=>undef,
+	     'variable'=>1, 'header'=>16, 'pseudo'=>0, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'Kernel',            'file'=>'vmlinuz',
+	     'offset'=>undef,             'size'=>undef,
+	     'variable'=>1, 'header'=>16, 'pseudo'=>0, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'Ramdisk',           'file'=>'ramdisk.gz',
+	     'offset'=>undef,             'size'=>undef,
+	     'variable'=>1, 'header'=>16, 'pseudo'=>0, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'FIS directory',     'file'=>undef,
+	     'offset'=>0x007e0000,        'size'=>0x00020000,
+	     'variable'=>0, 'header'=>0,  'pseudo'=>0, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'Loader config',	  'file'=>undef,
+	     'offset'=>0x007f8000,        'size'=>0x00004000,
+	     'variable'=>0, 'header'=>0,  'pseudo'=>1, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'Microcode',	  'file'=>'NPE-B',
+	     'offset'=>0x007fc000,        'size'=>0x00003fe0,
+	     'variable'=>0, 'header'=>16, 'pseudo'=>1, 'data'=>undef, 'byteswap'=>0},
+	    {'name'=>'Trailer',           'file'=>'Trailer',
+	     'offset'=>0x007ffff0,        'size'=>0x00000010,
+	     'variable'=>0, 'header'=>0,  'pseudo'=>1, 'data'=>undef, 'byteswap'=>0});
+}
+
+# Main routine starts here ...
+
+my($unpack, $pack, $little, $fatflash, $input, $output, $redboot);
+my($kernel, $sysconf, $ramdisk, $fisdir);
+my($microcode, $trailer, $ethaddr, $loader);
+
+END {
+    # Remove temporary files
+    for my $file (@cleanup) {
+	unlink $file;
+    }
+}
+
+if (!GetOptions("d|debug"       => \$debug,
+		"q|quiet"       => \$quiet,
+		"u|unpack"      => \$unpack,
+		"p|pack"        => \$pack,
+		"l|little"      => \$little,
+		"F|fatflash"    => \$fatflash,
+		"i|input=s"     => \$input,
+		"o|output=s"    => \$output,
+		"b|redboot=s"   => \$redboot,
+		"k|kernel=s"    => \$kernel,
+		"s|sysconf=s"   => \$sysconf,
+		"r|ramdisk=s"   => \$ramdisk,
+		"f|fisdir=s"    => \$fisdir,
+		"m|microcode=s" => \$microcode,
+		"t|trailer=s"   => \$trailer,
+		"e|ethaddr=s"   => \$ethaddr,
+		"L|loader=s"    => \$loader,
+		) or (not defined $pack and not defined $unpack)) {
+    print "Usage: slugimage <options>\n";
+    print "\n";
+    print "  [-d|--debug]			Turn on debugging output\n";
+    print "  [-q|--quiet]			Turn off status messages\n";
+    print "  [-u|--unpack]			Unpack a firmware image\n";
+    print "  [-p|--pack]			Pack a firmware image\n";
+    print "  [-l|--little]			Convert Kernel and Ramdisk to little-endian\n";
+    print "  [-F|--fatflash]			Generate an image for 16MB flash\n";
+    print "  [-i|--input]     <file>		Input firmware image filename\n";
+    print "  [-o|--output]    <file>		Output firmware image filename\n";
+    print "  [-b|--redboot]   <file>		Input/Output RedBoot filename\n";
+    print "  [-s|--sysconf]   <file>		Input/Output SysConf filename\n";
+    print "  [-L|--loader]    <file>		Second stage boot loader filename\n";
+    print "  [-k|--kernel]    <file>		Input/Ouptut Kernel filename\n";
+    print "  [-r|--ramdisk]   <file>		Input/Output Ramdisk filename(s)\n";
+    print "  [-f|--fisdir]    <file>		Input/Output FIS directory filename\n";
+    print "  [-m|--microcode] <file>		Input/Output Microcode filename\n";
+    print "  [-t|--trailer]   <file>		Input/Output Trailer filename\n";
+    print "  [-e|--ethaddr]   <AABBCCDDEEFF>	Set the Ethernet address\n";
+
+    # %%% TODO %%% Document --ramdisk syntax
+
+    exit 1;
+}
+
+my(@partitions) = defaultPartitions();
+
+if ($pack) {
+    die "Output filename must be specified\n" unless defined $output;
+
+    # If we're creating an image and no RedBoot, SysConf partition is
+    # explicitly specified, simply write an empty one as the upgrade tools
+    # don't touch RedBoot and SysConf anyway.  If no Trailer is specified,
+    # put in one.
+    if (not defined $redboot and not -e "RedBoot") {
+	$redboot = tmpnam();
+	open TMP, ">$redboot" or die "Cannot open file $redboot: $!";
+	push @cleanup, $redboot;
+	# The RedBoot partition is 256 * 1024 = 262144; the trailer we add
+	# is 70 bytes.
+	print TMP "\0"x(262144-70);
+	# Upgrade tools check for an appropriate Sercomm trailer.
+	for my $i (@sercomm_redboot_trailer) {
+	    print TMP pack "S", $i;
+	}
+	close TMP;
+    }
+    if (not defined $sysconf and not -e "SysConf") {
+	$sysconf = tmpnam();
+	open TMP, ">$sysconf" or die "Cannot open file $sysconf: $!";
+	push @cleanup, $sysconf;
+	# The SysConf partition is 128 * 1024 = 131072
+	print TMP "\0"x131072;
+	close TMP;
+    }
+    if (not defined $trailer and not -e "Trailer") {
+	$trailer = tmpnam();
+	open TMP, ">$trailer" or die "Cannot open file $trailer: $!";
+	push @cleanup, $trailer;
+	for my $i (@sercomm_flash_trailer) {
+	    print TMP pack "S", $i;
+	}
+	close TMP;
+    }
+
+    # If the microcode was not specified, then don't complain that it's missing.
+    if (not defined $microcode and not -e "NPE-B") {
+	map { ($_->{'name'} eq 'Microcode') && ($_->{'file'} = undef);   } @partitions;
+    }
+}
+
+# Go through the partition options, and set the names and files in @partitions
+if (defined $redboot)   { map { ($_->{'name'} eq 'RedBoot')	  && ($_->{'file'} = $redboot);   } @partitions; }
+if (defined $sysconf)   { map { ($_->{'name'} eq 'SysConf')	  && ($_->{'file'} = $sysconf);   } @partitions; }
+if (defined $loader)    { map { ($_->{'name'} eq 'Loader')	  && ($_->{'file'} = $loader);    } @partitions; }
+if (defined $kernel)    { map { ($_->{'name'} eq 'Kernel')	  && ($_->{'file'} = $kernel);    } @partitions; }
+if (defined $fisdir)    { map { ($_->{'name'} eq 'FIS directory') && ($_->{'file'} = $fisdir);    } @partitions; }
+if (defined $microcode) { map { ($_->{'name'} eq 'Microcode')	  && ($_->{'file'} = $microcode); } @partitions; }
+if (defined $trailer)   { map { ($_->{'name'} eq 'Trailer')	  && ($_->{'file'} = $trailer);   } @partitions; }
+
+if (defined $little)  {
+    map {
+	if (($_->{'name'} eq 'Loader') or
+	    ($_->{'name'} eq 'Kernel') or
+	    ($_->{'name'} eq 'Ramdisk')) {
+	    $_->{'byteswap'} = 1;
+	}
+    } @partitions;
+}
+
+if (defined $fatflash)  {
+    $flash_len = 0x01000000;
+    map {
+	if (($_->{'name'} eq 'FIS directory') or
+	    ($_->{'name'} eq 'Loader config') or
+	    ($_->{'name'} eq 'Microcode') or
+	    ($_->{'name'} eq 'Trailer')) {
+	    $_->{'offset'} += 0x00800000;
+	}
+    } @partitions;
+}
+
+if (defined $ethaddr) {
+    map {
+	if ($_->{'name'} eq 'EthAddr') {
+	    $ethaddr =~ s/://g;
+	    if (($ethaddr !~ m/^[0-9A-Fa-f]+$/) or (length($ethaddr) != 12)) {
+		die "Invalid ethernet address specification: '".$ethaddr."'\n";
+	    }
+	    $_->{'data'} = pack("H12", $ethaddr);
+	}
+    } @partitions;
+}
+
+if (defined $ramdisk) {
+
+    # A single filename is used for the ramdisk filename
+    if ($ramdisk !~ m/[:,]/) {
+	map { ($_->{'name'} eq 'Ramdisk') && ($_->{'file'} = $ramdisk); } @partitions;
+    }
+
+    # otherwise, it's a list of name:file mappings
+    else {
+	my @mappings = split(',', $ramdisk);
+
+	# Find the index of the Ramdisk entry
+	my $index;
+	my $count = 0;
+	map {
+	    if (not defined $index) {
+		if ($_->{'name'} eq "Ramdisk") {
+		    $index = $count;
+		}
+		$count++;
+	    }
+	} @partitions;
+
+	defined $index or die "Cannot find the Ramdisk partition\n";
+
+	# Replace the Ramdisk entry with the new mappings
+	splice(@partitions, $index, 1, map {
+
+	    # Preserve the information from the ramdisk entry
+	    my %entry = %{$partitions[$index]};
+
+	    # Parse the mapping
+	    ($_ =~ m/^([^:]+):([^:]+)(:([^:]+))?$/) or die "Invalid syntax in --ramdisk\n";
+	    $entry{'name'} = $1; $entry{'file'} = $2; my $size = $4;
+
+	    # If the mapping is not for the ramdisk, then undefine its attributes
+	    if ($entry{'name'} ne 'Ramdisk') {
+		$entry{'offset'} = undef;
+		$entry{'size'} = undef;
+		$entry{'variable'} = 1;
+		$entry{'header'} = 0;
+		$entry{'pseudo'} = 0;
+		$entry{'data'} = undef;
+		$entry{'byteswap'} = 0;
+	    }
+
+	    # Support specification of the number of blocks for empty jffs2
+	    if ($entry{'file'} =~ m/^[0-9]+$/) {
+		$size = $entry{'file'};
+		$entry{'file'} = undef;
+	    }
+
+	    # If the user has specified a size, then respect their wishes
+	    if (defined $size) {
+		$entry{'size'} = $size * $block_size;
+		# Create an empty partition of the requested size.
+		$entry{'data'} = padBytes("", $entry{'size'} - $entry{'header'});
+	    }
+
+	    \%entry;
+
+	} @mappings);
+    }
+}
+
+# Read in the firmware image
+if ($input) {
+    if ($debug) {
+	print "Initial partition map:\n";
+	printPartitions(@partitions);
+    }
+    
+    my $result = readInFirmware($input, \@partitions);
+
+    if ($debug) {
+	print "After reading firmware:\n";
+	printPartitions(@partitions);
+    }
+}
+
+# Unpack the firmware if requested
+if ($unpack) {
+    die "Input filename must be specified\n" unless defined $input;
+
+#    map {
+#	($_->{'name'} eq 'FIS directory') and @partitions = checkPartitionTable($_->{'data'});
+#    } @partitions;
+
+    writeOutFirmwareParts(@partitions);
+
+}
+
+# Pack the firmware if requested
+if ($pack) {
+
+    if (!defined $loader) {
+	removeOptionalLoader(\@partitions);
+    }
+
+    if ($debug) {
+	print "Initial partition map:\n";
+	printPartitions(@partitions);
+    }
+    
+    my $result = readInFirmwareParts(@partitions);
+
+    if ($debug) {
+	print "after readInFirmwareParts():\n";
+	printPartitions(@partitions);
+# 	map {
+# 	    ($_->{'name'} eq 'RedBoot') && (printRedbootTrailer($_->{'data'}));
+# 	} @partitions;
+    }
+    
+    layoutPartitions(@partitions);
+
+    if ($debug) {
+ 	print "after layoutPartitions():\n";
+ 	printPartitions(@partitions);
+    }
+    
+    buildPartitionTable(@partitions);
+
+    if ($debug) {
+ 	print "after buildPartitionTable():\n";
+ 	printPartitions(@partitions);
+
+#  	my($lastblock);
+#  	map {
+#  	    if ($_->{'name'} eq 'FIS directory') {
+#  		$lastblock = $_->{'data'};
+#  	    }
+#  	} @partitions;
+
+#  	print "checkPartitionTable():\n";
+#  	checkPartitionTable($lastblock);
+    }
+    
+    writeOutFirmware($output, @partitions);
+
+}
+
+exit 0;
diff --git a/scripts/srecimage.pl b/scripts/srecimage.pl
new file mode 100755
index 0000000000..b9e2a843bf
--- /dev/null
+++ b/scripts/srecimage.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/env perl
+#
+# srecimage.pl - script to convert a binary image into srec
+# Copyright (c) 2015 - Jo-Philipp Wich <jo@mein.io>
+#
+# This script is in the public domain.
+
+use strict;
+
+my ($input, $output, $offset) = @ARGV;
+
+if (!defined($input) || !-f $input || !defined($output) ||
+    !defined($offset) || $offset !~ /^(0x)?[a-fA-F0-9]+$/) {
+	die "Usage: $0 <input file> <output file> <load address>\n";
+}
+
+sub srec
+{
+	my ($type, $addr, $data, $len) = @_;
+	my @addrtypes = qw(%04X %04X %06X %08X %08X %04X %06X %08X %06X %04X);
+	my $addrstr = sprintf $addrtypes[$type], $addr;
+
+	$len = length($data) if ($len <= 0);
+	$len += 1 + (length($addrstr) / 2);
+
+	my $sum = $len;
+
+	foreach my $byte (unpack('C*', pack('H*', $addrstr)), unpack('C*', $data))
+	{
+		$sum += $byte;
+	}
+
+	return sprintf "S%d%02X%s%s%02X\r\n",
+	       $type, $len, $addrstr, uc(unpack('H*', $data)), ~($sum & 0xFF) & 0xFF;
+}
+
+
+open(IN, '<:raw', $input) || die "Unable to open $input: $!\n";
+open(OUT, '>:raw', $output) || die "Unable to open $output: $!\n";
+
+my ($basename) = $output =~ m!([^/]+)$!;
+
+print OUT srec(0, 0, $basename, 0);
+
+my $off = hex($offset);
+my $len;
+
+while (defined($len = read(IN, my $buf, 16)) && $len > 0)
+{
+	print OUT srec(3, $off, $buf, $len);
+	$off += $len;
+}
+
+print OUT srec(7, hex($offset), "", 0);
+
+close OUT;
+close IN;
diff --git a/scripts/strip-kmod.sh b/scripts/strip-kmod.sh
new file mode 100755
index 0000000000..313015b909
--- /dev/null
+++ b/scripts/strip-kmod.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+[ -n "$CROSS" ] || {
+	echo "The variable CROSS must be set to point to the cross-compiler prefix"
+	exit 1
+}
+
+MODULE="$1"
+
+[ "$#" -ne 1 ] && {
+	echo "Usage: $0 <module>"
+	exit 1
+}
+
+ARGS=
+if [ -n "$KEEP_SYMBOLS" ]; then
+	ARGS="-X --strip-debug"
+else
+	ARGS="-x -G __this_module --strip-unneeded"
+fi
+
+if [ -z "$KEEP_BUILD_ID" ]; then
+    ARGS="$ARGS -R .note.gnu.build-id"
+fi
+
+${CROSS}objcopy \
+	-R .comment \
+	-R .pdr \
+	-R .mdebug.abi32 \
+	-R .gnu.attributes \
+	-R .reginfo \
+	-R .MIPS.abiflags \
+	-R .note.GNU-stack \
+	$ARGS \
+	"$MODULE" "$MODULE.tmp"
+
+[ -n "$NO_RENAME" ] && {
+	mv "${MODULE}.tmp" "$MODULE"
+	exit 0
+}
+
+${CROSS}nm "$MODULE.tmp" | awk '
+BEGIN {
+	n = 0
+}
+
+$3 && $2 ~ /[brtd]/ && $3 !~ /\$LC/ && !def[$3] {
+	print "--redefine-sym "$3"=_"n;
+	n = n + 1
+	def[$3] = 1
+}
+' > "$MODULE.tmp1"
+
+${CROSS}objcopy `cat ${MODULE}.tmp1` ${MODULE}.tmp ${MODULE}.out
+mv "${MODULE}.out" "${MODULE}"
+rm -f "${MODULE}".t*
diff --git a/scripts/symlink-tree.sh b/scripts/symlink-tree.sh
new file mode 100755
index 0000000000..aa169e2455
--- /dev/null
+++ b/scripts/symlink-tree.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# Create a new openwrt tree with symlinks pointing at the current tree
+# Usage: ./scripts/symlink-tree.sh <destination>
+
+FILES="
+	BSDmakefile
+	config
+	Config.in
+	LICENSE
+	Makefile
+	README
+	dl
+	feeds.conf.default
+	include
+	package
+	rules.mk
+	scripts
+	target
+	toolchain
+	tools"
+
+OPTIONAL_FILES="
+	.git"
+
+if [ -f feeds.conf ] ; then
+	FILES="$FILES feeds.conf"
+fi
+
+if [ -z "$1" ]; then
+	echo "Syntax: $0 <destination>" >&2
+	exit 1
+fi
+
+if [ -e "$1" ]; then
+	echo "Error: $1 already exists" >&2
+	exit 1
+fi
+
+set -e # fail if any commands fails
+mkdir -p dl "$1"
+for file in $FILES; do
+	[ -e "$PWD/$file" ] || {
+		echo "ERROR: $file does not exist in the current tree" >&2
+		exit 1
+	}
+	ln -s "$PWD/$file" "$1/"
+done
+for file in $OPTIONAL_FILES; do
+	[ -e "$PWD/$file" ] && ln -s "$PWD/$file" "$1/"
+done
+exit 0
diff --git a/scripts/sysupgrade-tar.sh b/scripts/sysupgrade-tar.sh
new file mode 100755
index 0000000000..45b17daccd
--- /dev/null
+++ b/scripts/sysupgrade-tar.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+board=""
+kernel=""
+rootfs=""
+outfile=""
+err=""
+
+while [ "$1" ]; do
+	case "$1" in
+	"--board")
+		board="$2"
+		shift
+		shift
+		continue
+		;;
+	"--kernel")
+		kernel="$2"
+		shift
+		shift
+		continue
+		;;
+	"--rootfs")
+		rootfs="$2"
+		shift
+		shift
+		continue
+		;;
+	*)
+		if [ ! "$outfile" ]; then
+			outfile=$1
+			shift
+			continue
+		fi
+		;;
+	esac
+done
+
+if [ ! -n "$board" -o ! -r "$kernel" -a  ! -r "$rootfs" -o ! "$outfile" ]; then
+	echo "syntax: $0 [--board boardname] [--kernel kernelimage] [--rootfs rootfs] out"
+	exit 1
+fi
+
+tmpdir="$( mktemp -d 2> /dev/null )"
+if [ -z "$tmpdir" ]; then
+	# try OSX signature
+	tmpdir="$( mktemp -t 'ubitmp' -d )"
+fi
+
+if [ -z "$tmpdir" ]; then
+	exit 1
+fi
+
+mkdir -p "${tmpdir}/sysupgrade-${board}"
+echo "BOARD=${board}" > "${tmpdir}/sysupgrade-${board}/CONTROL"
+[ -z "${rootfs}" ] || cp "${rootfs}" "${tmpdir}/sysupgrade-${board}/root"
+[ -z "${kernel}" ] || cp "${kernel}" "${tmpdir}/sysupgrade-${board}/kernel"
+
+mtime=""
+if [ -n "$SOURCE_DATE_EPOCH" ]; then
+	mtime="--mtime=@${SOURCE_DATE_EPOCH}"
+fi
+
+(cd "$tmpdir"; tar cvf sysupgrade.tar sysupgrade-${board} ${mtime})
+err="$?"
+if [ -e "$tmpdir/sysupgrade.tar" ]; then
+	cp "$tmpdir/sysupgrade.tar" "$outfile"
+else
+	err=2
+fi
+rm -rf "$tmpdir"
+
+exit $err
diff --git a/scripts/target-metadata.pl b/scripts/target-metadata.pl
new file mode 100755
index 0000000000..7f7dc6d4ee
--- /dev/null
+++ b/scripts/target-metadata.pl
@@ -0,0 +1,440 @@
+#!/usr/bin/env perl
+use FindBin;
+use lib "$FindBin::Bin";
+use strict;
+use metadata;
+use Getopt::Long;
+
+sub target_config_features(@) {
+	my $ret;
+
+	while ($_ = shift @_) {
+		/arm_v(\w+)/ and $ret .= "\tselect arm_v$1\n";
+		/broken/ and $ret .= "\tdepends on BROKEN\n";
+		/audio/ and $ret .= "\tselect AUDIO_SUPPORT\n";
+		/display/ and $ret .= "\tselect DISPLAY_SUPPORT\n";
+		/dt/ and $ret .= "\tselect USES_DEVICETREE\n";
+		/gpio/ and $ret .= "\tselect GPIO_SUPPORT\n";
+		/pci/ and $ret .= "\tselect PCI_SUPPORT\n";
+		/pcie/ and $ret .= "\tselect PCIE_SUPPORT\n";
+		/usb/ and $ret .= "\tselect USB_SUPPORT\n";
+		/usbgadget/ and $ret .= "\tselect USB_GADGET_SUPPORT\n";
+		/pcmcia/ and $ret .= "\tselect PCMCIA_SUPPORT\n";
+		/rtc/ and $ret .= "\tselect RTC_SUPPORT\n";
+		/squashfs/ and $ret .= "\tselect USES_SQUASHFS\n";
+		/jffs2$/ and $ret .= "\tselect USES_JFFS2\n";
+		/jffs2_nand/ and $ret .= "\tselect USES_JFFS2_NAND\n";
+		/ext4/ and $ret .= "\tselect USES_EXT4\n";
+		/targz/ and $ret .= "\tselect USES_TARGZ\n";
+		/cpiogz/ and $ret .= "\tselect USES_CPIOGZ\n";
+		/minor/ and $ret .= "\tselect USES_MINOR\n";
+		/ubifs/ and $ret .= "\tselect USES_UBIFS\n";
+		/fpu/ and $ret .= "\tselect HAS_FPU\n";
+		/spe_fpu/ and $ret .= "\tselect HAS_SPE_FPU\n";
+		/ramdisk/ and $ret .= "\tselect USES_INITRAMFS\n";
+		/powerpc64/ and $ret .= "\tselect powerpc64\n";
+		/nommu/ and $ret .= "\tselect NOMMU\n";
+		/mips16/ and $ret .= "\tselect HAS_MIPS16\n";
+		/rfkill/ and $ret .= "\tselect RFKILL_SUPPORT\n";
+		/low_mem/ and $ret .= "\tselect LOW_MEMORY_FOOTPRINT\n";
+		/small_flash/ and $ret .= "\tselect SMALL_FLASH\n";
+		/nand/ and $ret .= "\tselect NAND_SUPPORT\n";
+		/virtio/ and $ret .= "\tselect VIRTIO_SUPPORT\n";
+	}
+	return $ret;
+}
+
+sub target_name($) {
+	my $target = shift;
+	my $parent = $target->{parent};
+	if ($parent) {
+		return $target->{parent}->{name}." - ".$target->{name};
+	} else {
+		return $target->{name};
+	}
+}
+
+sub kver($) {
+	my $v = shift;
+	$v =~ tr/\./_/;
+	if (substr($v,0,2) eq "2_") {
+		$v =~ /(\d+_\d+_\d+)(_\d+)?/ and $v = $1;
+	} else {
+		$v =~ /(\d+_\d+)(_\d+)?/ and $v = $1;
+	}
+	return $v;
+}
+
+sub print_target($) {
+	my $target = shift;
+	my $features = target_config_features(@{$target->{features}});
+	my $help = $target->{desc};
+	my $confstr;
+
+	chomp $features;
+	$features .= "\n";
+	if ($help =~ /\w+/) {
+		$help =~ s/^\s*/\t  /mg;
+		$help = "\thelp\n$help";
+	} else {
+		undef $help;
+	}
+
+	my $v = kver($target->{version});
+	if (@{$target->{subtargets}} == 0) {
+	$confstr = <<EOF;
+config TARGET_$target->{conf}
+	bool "$target->{name}"
+	select LINUX_$v
+EOF
+	}
+	else {
+		$confstr = <<EOF;
+config TARGET_$target->{conf}
+	bool "$target->{name}"
+EOF
+	}
+	if ($target->{subtarget}) {
+		$confstr .= "\tdepends on TARGET_$target->{boardconf}\n";
+	}
+	if (@{$target->{subtargets}} > 0) {
+		$confstr .= "\tselect HAS_SUBTARGETS\n";
+		grep { /broken/ } @{$target->{features}} and $confstr .= "\tdepends on BROKEN\n";
+	} else {
+		$confstr .= $features;
+		if ($target->{arch} =~ /\w/) {
+			$confstr .= "\tselect $target->{arch}\n";
+		}
+		if ($target->{has_devices}) {
+			$confstr .= "\tselect HAS_DEVICES\n";
+		}
+	}
+
+	foreach my $dep (@{$target->{depends}}) {
+		my $mode = "depends on";
+		my $flags;
+		my $name;
+
+		$dep =~ /^([@\+\-]+)(.+)$/;
+		$flags = $1;
+		$name = $2;
+
+		next if $name =~ /:/;
+		$flags =~ /-/ and $mode = "deselect";
+		$flags =~ /\+/ and $mode = "select";
+		$flags =~ /@/ and $confstr .= "\t$mode $name\n";
+	}
+	$confstr .= "$help\n\n";
+	print $confstr;
+}
+
+sub merge_package_lists($$) {
+	my $list1 = shift;
+	my $list2 = shift;
+	my @l = ();
+	my %pkgs;
+
+	foreach my $pkg (@$list1, @$list2) {
+		$pkgs{$pkg} = 1;
+	}
+	foreach my $pkg (keys %pkgs) {
+		push @l, $pkg unless ($pkg =~ /^-/ or $pkgs{"-$pkg"});
+	}
+	return sort(@l);
+}
+
+sub gen_target_config() {
+	my $file = shift @ARGV;
+	my @target = parse_target_metadata($file);
+	my %defaults;
+
+	my @target_sort = sort {
+		target_name($a) cmp target_name($b);
+	} @target;
+
+	foreach my $target (@target_sort) {
+		next if @{$target->{subtargets}} > 0;
+		print <<EOF;
+config DEFAULT_TARGET_$target->{conf}
+	bool
+	depends on TARGET_PER_DEVICE_ROOTFS
+	default y if TARGET_$target->{conf}
+EOF
+		foreach my $pkg (@{$target->{packages}}) {
+			print "\tselect DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
+		}
+	}
+
+	print <<EOF;
+choice
+	prompt "Target System"
+	default TARGET_ar71xx
+	reset if !DEVEL
+	
+EOF
+
+	foreach my $target (@target_sort) {
+		next if $target->{subtarget};
+		print_target($target);
+	}
+
+	print <<EOF;
+endchoice
+
+choice
+	prompt "Subtarget" if HAS_SUBTARGETS
+EOF
+	foreach my $target (@target) {
+		next unless $target->{def_subtarget};
+		print <<EOF;
+	default TARGET_$target->{conf}_$target->{def_subtarget} if TARGET_$target->{conf}
+EOF
+	}
+	print <<EOF;
+
+EOF
+	foreach my $target (@target) {
+		next unless $target->{subtarget};
+		print_target($target);
+	}
+
+print <<EOF;
+endchoice
+
+choice
+	prompt "Target Profile"
+
+EOF
+	foreach my $target (@target) {
+		my $profile = $target->{profiles}->[0];
+		$profile or next;
+		print <<EOF;
+	default TARGET_$target->{conf}_$profile->{id} if TARGET_$target->{conf}
+EOF
+	}
+
+	print <<EOF;
+
+config TARGET_MULTI_PROFILE
+	bool "Multiple devices"
+	depends on HAS_DEVICES
+	help
+	Instead of only building a single image, or all images, this allows you
+	to select images to be built for multiple devices in one build.
+
+EOF
+
+	foreach my $target (@target) {
+		my $profiles = $target->{profiles};
+		foreach my $profile (@{$target->{profiles}}) {
+			print <<EOF;
+config TARGET_$target->{conf}_$profile->{id}
+	bool "$profile->{name}"
+	depends on TARGET_$target->{conf}
+EOF
+			my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
+			foreach my $pkg (@pkglist) {
+				print "\tselect DEFAULT_$pkg\n";
+				$defaults{$pkg} = 1;
+			}
+			my $help = $profile->{desc};
+			if ($help =~ /\w+/) {
+				$help =~ s/^\s*/\t  /mg;
+				$help = "\thelp\n$help";
+			} else {
+				undef $help;
+			}
+			print "$help\n";
+		}
+	}
+
+	print <<EOF;
+endchoice
+
+menu "Target Devices"
+	depends on TARGET_MULTI_PROFILE
+
+	config TARGET_ALL_PROFILES
+		bool "Enable all profiles by default"
+
+	config TARGET_PER_DEVICE_ROOTFS
+		bool "Use a per-device root filesystem that adds profile packages"
+		help
+		When disabled, all device packages from all selected devices
+		will be included in all images by default. (Marked as <*>) You will
+		still be able to manually deselect any/all packages.
+		When enabled, each device builds it's own image, including only the
+		profile packages for that device.  (Marked as {M}) You will be able
+		to change a package to included in all images by marking as {*}, but
+		will not be able to disable a profile package completely.
+		
+		To get the most use of this setting, you must set in a .config stub
+		before calling "make defconfig".  Selecting TARGET_MULTI_PROFILE and
+		then manually selecting (via menuconfig for instance) this option
+		will have pre-defaulted all profile packages to included, making this
+		option appear to have had no effect.
+
+EOF
+	foreach my $target (@target) {
+		my @profiles = sort {
+			my $x = $a->{name};
+			my $y = $b->{name};
+			"\L$x" cmp "\L$y";
+		} @{$target->{profiles}};
+		foreach my $profile (@profiles) {
+			next unless $profile->{id} =~ /^DEVICE_/;
+			print <<EOF;
+menuconfig TARGET_DEVICE_$target->{conf}_$profile->{id}
+	bool "$profile->{name}"
+	depends on TARGET_$target->{conf}
+	default y if TARGET_ALL_PROFILES
+EOF
+			my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
+			foreach my $pkg (@pkglist) {
+				print "\tselect DEFAULT_$pkg if !TARGET_PER_DEVICE_ROOTFS\n";
+				print "\tselect MODULE_DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
+				$defaults{$pkg} = 1;
+			}
+
+			print <<EOF;
+
+
+	config TARGET_DEVICE_PACKAGES_$target->{conf}_$profile->{id}
+		string "$profile->{name} additional packages"
+		default ""
+		depends on TARGET_PER_DEVICE_ROOTFS
+		depends on TARGET_DEVICE_$target->{conf}_$profile->{id}
+
+EOF
+		}
+	}
+
+	print <<EOF;
+
+endmenu
+
+config HAS_SUBTARGETS
+	bool
+
+config HAS_DEVICES
+	bool
+
+config TARGET_BOARD
+	string
+
+EOF
+	foreach my $target (@target) {
+		$target->{subtarget} or	print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n";
+	}
+	print <<EOF;
+config TARGET_SUBTARGET
+	string
+	default "generic" if !HAS_SUBTARGETS
+
+EOF
+
+	foreach my $target (@target) {
+		foreach my $subtarget (@{$target->{subtargets}}) {
+			print "\t\tdefault \"$subtarget\" if TARGET_".$target->{conf}."_$subtarget\n";
+		}
+	}
+	print <<EOF;
+config TARGET_PROFILE
+	string
+EOF
+	foreach my $target (@target) {
+		my $profiles = $target->{profiles};
+		foreach my $profile (@$profiles) {
+			print "\tdefault \"$profile->{id}\" if TARGET_$target->{conf}_$profile->{id}\n";
+		}
+	}
+
+	print <<EOF;
+
+config TARGET_ARCH_PACKAGES
+	string
+	
+EOF
+	foreach my $target (@target) {
+		next if @{$target->{subtargets}} > 0;
+		print "\t\tdefault \"".($target->{arch_packages} || $target->{board})."\" if TARGET_".$target->{conf}."\n";
+	}
+	print <<EOF;
+
+config DEFAULT_TARGET_OPTIMIZATION
+	string
+EOF
+	foreach my $target (@target) {
+		next if @{$target->{subtargets}} > 0;
+		print "\tdefault \"".$target->{cflags}."\" if TARGET_".$target->{conf}."\n";
+	}
+	print "\tdefault \"-Os -pipe -funit-at-a-time\"\n";
+	print <<EOF;
+
+config CPU_TYPE
+	string
+EOF
+	foreach my $target (@target) {
+		next if @{$target->{subtargets}} > 0;
+		print "\tdefault \"".$target->{cputype}."\" if TARGET_".$target->{conf}."\n";
+	}
+	print "\tdefault \"\"\n";
+
+	my %kver;
+	foreach my $target (@target) {
+		my $v = kver($target->{version});
+		next if $kver{$v};
+		$kver{$v} = 1;
+		print <<EOF;
+
+config LINUX_$v
+	bool
+
+EOF
+	}
+	foreach my $def (sort keys %defaults) {
+		print <<EOF;
+	config DEFAULT_$def
+		bool
+
+	config MODULE_DEFAULT_$def
+		tristate
+		depends on TARGET_PER_DEVICE_ROOTFS
+		depends on m
+		default m if DEFAULT_$def
+		select PACKAGE_$def
+
+EOF
+	}
+}
+
+sub gen_profile_mk() {
+	my $file = shift @ARGV;
+	my $target = shift @ARGV;
+	my @targets = parse_target_metadata($file);
+	foreach my $cur (@targets) {
+		next unless $cur->{id} eq $target;
+		print "PROFILE_NAMES = ".join(" ", map { $_->{id} } @{$cur->{profiles}})."\n";
+		foreach my $profile (@{$cur->{profiles}}) {
+			print $profile->{id}.'_NAME:='.$profile->{name}."\n";
+			print $profile->{id}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n";
+		}
+	}
+}
+
+sub parse_command() {
+	GetOptions("ignore=s", \@ignore);
+	my $cmd = shift @ARGV;
+	for ($cmd) {
+		/^config$/ and return gen_target_config();
+		/^profile_mk$/ and return gen_profile_mk();
+	}
+	die <<EOF
+Available Commands:
+	$0 config [file] 			Target metadata in Kconfig format
+	$0 profile_mk [file] [target]		Profile metadata in makefile format
+
+EOF
+}
+
+parse_command();
diff --git a/scripts/timestamp.pl b/scripts/timestamp.pl
new file mode 100755
index 0000000000..e24d8149d9
--- /dev/null
+++ b/scripts/timestamp.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/env perl
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+use strict;
+
+sub get_ts($$) {
+	my $path = shift;
+	my $options = shift;
+	my $ts = 0;
+	my $fn = "";
+	$path .= "/" if( -d $path);
+	open FIND, "find $path -type f -and -not -path \\*/.svn\\* -and -not -path \\*CVS\\* $options 2>/dev/null |";
+	while (<FIND>) {
+		chomp;
+		my $file = $_;
+		next if -l $file;
+		my $mt = (stat $file)[9];
+		if ($mt > $ts) {
+			$ts = $mt;
+			$fn = $file;
+		}
+	}
+	close FIND;
+	return ($ts, $fn);
+}
+
+(@ARGV > 0) or push @ARGV, ".";
+my $ts = 0;
+my $n = ".";
+my %options;
+while (@ARGV > 0) {
+	my $path = shift @ARGV;
+	if ($path =~ /^-x/) {
+		my $str = shift @ARGV;
+		$options{"findopts"} .= " -and -not -path '".$str."'"
+	} elsif ($path =~ /^-f/) {
+		$options{"findopts"} .= " -follow";
+	} elsif ($path =~ /^-n/) {
+		my $arg = $ARGV[0];
+		$options{$path} = $arg;
+	} elsif ($path =~ /^-/) {
+		$options{$path} = 1;
+	} else {
+		my ($tmp, $fname) = get_ts($path, $options{"findopts"});
+		if ($tmp > $ts) {
+			if ($options{'-F'}) {
+				$n = $fname;
+			} else {
+				$n = $path;
+			}
+			$ts = $tmp;
+		}
+	}
+}
+
+if ($options{"-n"}) {
+	exit ($n eq $options{"-n"} ? 0 : 1);
+} elsif ($options{"-p"}) {
+	print "$n\n";
+} elsif ($options{"-t"}) {
+	print "$ts\n";
+} else {
+	print "$n\t$ts\n";
+}
diff --git a/scripts/ubinize-image.sh b/scripts/ubinize-image.sh
new file mode 100755
index 0000000000..09a00b1898
--- /dev/null
+++ b/scripts/ubinize-image.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+
+part=""
+ubootenv=""
+ubinize_param=""
+kernel=""
+rootfs=""
+outfile=""
+err=""
+
+get_magic_word() {
+	dd if=$1 bs=2 count=1 2>/dev/null | hexdump -v -n 2 -e '1/1 "%02x"'
+}
+
+is_ubifs() {
+	if [ "$( get_magic_word $1 )" = "3118" ]; then
+		echo "1"
+	fi
+}
+
+ubivol() {
+	volid=$1
+	name=$2
+	image=$3
+	autoresize=$4
+	size="$5"
+	echo "[$name]"
+	echo "mode=ubi"
+	echo "vol_id=$volid"
+	echo "vol_type=dynamic"
+	echo "vol_name=$name"
+	if [ "$image" ]; then
+		echo "image=$image"
+		[ -n "$size" ] && echo "vol_size=${size}MiB"
+	else
+		echo "vol_size=1MiB"
+	fi
+	if [ "$autoresize" ]; then
+		echo "vol_flags=autoresize"
+	fi
+}
+
+ubilayout() {
+	local vol_id=0
+	local root_is_ubifs="$( is_ubifs "$2" )"
+	if [ "$1" = "ubootenv" ]; then
+		ubivol $vol_id ubootenv
+		vol_id=$(( $vol_id + 1 ))
+		ubivol $vol_id ubootenv2
+		vol_id=$(( $vol_id + 1 ))
+	fi
+	for part in $parts; do
+		name="${part%%=*}"
+		prev="$part"
+		part="${part#*=}"
+		[ "$prev" = "$part" ] && part=
+
+		image="${part%%=*}"
+		prev="$part"
+		part="${part#*=}"
+		[ "$prev" = "$part" ] && part=
+
+		size="$part"
+
+		ubivol $vol_id "$name" "$image" "" "$size"
+		vol_id=$(( $vol_id + 1 ))
+	done
+	if [ "$3" ]; then
+		ubivol $vol_id kernel "$3"
+		vol_id=$(( $vol_id + 1 ))
+	fi
+	ubivol $vol_id rootfs "$2" $root_is_ubifs
+	vol_id=$(( $vol_id + 1 ))
+	[ "$root_is_ubifs" ] || ubivol $vol_id rootfs_data "" 1
+}
+
+while [ "$1" ]; do
+	case "$1" in
+	"--uboot-env")
+		ubootenv="ubootenv"
+		shift
+		continue
+		;;
+	"--kernel")
+		kernel="$2"
+		shift
+		shift
+		continue
+		;;
+	"--part")
+		parts="$parts $2"
+		shift
+		shift
+		continue
+		;;
+	"-"*)
+		ubinize_param="$@"
+		break
+		;;
+	*)
+		if [ ! "$rootfs" ]; then
+			rootfs=$1
+			shift
+			continue
+		fi
+		if [ ! "$outfile" ]; then
+			outfile=$1
+			shift
+			continue
+		fi
+		;;
+	esac
+done
+
+if [ ! -r "$rootfs" -o ! -r "$kernel" -a ! "$outfile" ]; then
+	echo "syntax: $0 [--uboot-env] [--part <name>=<file>] [--kernel kernelimage] rootfs out [ubinize opts]"
+	exit 1
+fi
+
+ubinize="$( which ubinize )"
+if [ ! -x "$ubinize" ]; then
+	echo "ubinize tool not found or not usable"
+	exit 1
+fi
+
+ubinizecfg="$( mktemp 2> /dev/null )"
+if [ -z "$ubinizecfg" ]; then
+	# try OSX signature
+	ubinizecfg="$( mktemp -t 'ubitmp' )"
+fi
+ubilayout "$ubootenv" "$rootfs" "$kernel" > "$ubinizecfg"
+
+cat "$ubinizecfg"
+ubinize -o "$outfile" $ubinize_param "$ubinizecfg"
+err="$?"
+[ ! -e "$outfile" ] && err=2
+rm "$ubinizecfg"
+
+exit $err
diff --git a/scripts/update-package-md5sum b/scripts/update-package-md5sum
new file mode 100755
index 0000000000..1cf17163e0
--- /dev/null
+++ b/scripts/update-package-md5sum
@@ -0,0 +1,38 @@
+#!/usr/bin/env sh
+#
+# update-package-md5sum - Updates md5sum of OpenWrt packages
+#
+# update-package-md5sum will update the md5sum for all recusivly found OpenWrt packages
+# in a given directory.
+#
+# Usage: scripts/update-package-md5sum <package directory>
+#
+# Example: `scripts/update-package-md5sum feeds/packages/python`
+
+DL_FOLDER=`grep -Eo '^CONFIG_DOWNLOAD_FOLDER=".*"$' .config | \
+    sed 's,^CONFIG_DOWNLOAD_FOLDER="\(.*\)"$,\1,'`
+if test -z ${DL_FOLDER}; then
+    DL_FOLDER=./dl
+fi
+
+if test -z "$1"; then
+	echo "Usage: $0 <package directory>"
+	exit
+fi
+
+for file in `find $1 -name Makefile`; do
+    if grep BuildPackage ${file} > /dev/null; then
+        source=`DUMP=1 TOPDIR=\`pwd\` make -f ${file} | grep -m 1 Source | cut -f 2 -d ' '`
+        if test -n "${source}"; then
+			if test ! -f "${DL_FOLDER}/${source}"; then
+				make package/`basename \`dirname ${file}\``/download
+			fi
+            sum=`md5sum ${DL_FOLDER}/${source} 2> /dev/null` || continue
+            echo Updating ${file}...
+            sum=`echo ${sum} | cut -d ' ' -f 1`
+            sed -i "s,^PKG_MD5SUM:=.*,PKG_MD5SUM:=${sum}," ${file}
+        else
+            echo No source for ${file}
+        fi
+    fi
+done
diff --git a/target/Config.in b/target/Config.in
new file mode 100644
index 0000000000..9ff7096880
--- /dev/null
+++ b/target/Config.in
@@ -0,0 +1,207 @@
+source "tmp/.config-target.in"
+
+# Kernel/Hardware features
+
+config HAS_SPE_FPU
+	depends on powerpc
+	select HAS_FPU
+	bool
+
+config HAS_FPU
+	bool
+
+config AUDIO_SUPPORT
+	bool
+
+config GPIO_SUPPORT
+	bool
+
+config PCI_SUPPORT
+	select AUDIO_SUPPORT
+	bool
+
+config PCIE_SUPPORT
+	bool
+
+config PCMCIA_SUPPORT
+	bool
+
+config USB_SUPPORT
+	select AUDIO_SUPPORT
+	bool
+
+config USB_GADGET_SUPPORT
+	bool
+
+config RTC_SUPPORT
+	bool
+
+config BIG_ENDIAN
+	bool
+
+config USES_DEVICETREE
+	bool
+
+config USES_INITRAMFS
+	bool
+
+config USES_SQUASHFS
+	bool
+
+config USES_JFFS2
+	bool
+
+config USES_JFFS2_NAND
+	bool
+
+config USES_EXT4
+	bool
+
+config USES_TARGZ
+	bool
+
+config USES_CPIOGZ
+	bool
+
+config USES_MINOR
+	bool
+
+config USES_UBIFS
+	bool
+	select NAND_SUPPORT
+
+config LOW_MEMORY_FOOTPRINT
+	bool
+
+config SMALL_FLASH
+	bool
+
+config NOMMU
+	bool
+
+config HAS_MIPS16
+	depends on (mips || mipsel || mips64 || mips64el)
+	bool
+
+config RFKILL_SUPPORT
+	bool
+
+config NAND_SUPPORT
+	bool
+
+config ARCH_64BIT
+	bool
+
+config VIRTIO_SUPPORT
+	bool
+
+# Architecture selection
+
+config aarch64
+	select ARCH_64BIT
+	bool
+
+config aarch64_be
+	select ARCH_64BIT
+	select BIG_ENDIAN
+	bool
+
+config arc
+	bool
+
+config arceb
+	select BIG_ENDIAN
+	bool
+
+config arm
+	bool
+
+config armeb
+	select BIG_ENDIAN
+	bool
+
+config arm_v6
+	bool
+
+config arm_v7
+	bool
+
+config i386
+	bool
+
+config i686
+	bool 
+
+config m68k
+	bool
+
+config mips
+	select BIG_ENDIAN
+	bool
+
+config mipsel
+	bool
+
+config mips64
+	select BIG_ENDIAN
+	select ARCH_64BIT
+	bool
+
+config mips64el
+	select ARCH_64BIT
+	bool
+
+config powerpc
+	select BIG_ENDIAN
+	bool
+
+config powerpc64
+	select BIG_ENDIAN
+	select ARCH_64BIT
+	bool
+
+config sh3
+	bool
+
+config sh3eb
+	select BIG_ENDIAN
+	bool
+
+config sh4
+	bool
+
+config sh4eb
+	select BIG_ENDIAN
+	bool
+
+config sparc
+	select BIG_ENDIAN
+	bool
+
+config x86_64
+	select ARCH_64BIT
+	bool
+
+config ARCH
+	string
+	default "aarch64"   if aarch64
+	default "aarch64_be" if aarch64_be
+	default "arc"       if arc
+	default "arceb"     if arceb
+	default "arm"       if arm
+	default "armeb"     if armeb
+	default "i386"      if i386
+	default "i686"      if i686
+	default "m68k"      if m68k
+	default "mips"      if mips
+	default "mipsel"    if mipsel
+	default "mips64"    if mips64
+	default "mips64el"  if mips64el
+	default "powerpc"   if powerpc
+	default "sh3"       if sh3
+	default "sh3eb"     if sh3eb
+	default "sh4"       if sh4
+	default "sh4eb"     if sh4eb
+	default "sparc"     if sparc
+	default "x86_64"    if x86_64
+
diff --git a/target/Makefile b/target/Makefile
new file mode 100644
index 0000000000..db87c78aae
--- /dev/null
+++ b/target/Makefile
@@ -0,0 +1,22 @@
+# 
+# Copyright (C) 2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+curdir:=target
+
+$(curdir)/builddirs:=linux sdk imagebuilder toolchain
+$(curdir)/builddirs-default:=linux
+$(curdir)/builddirs-install:=linux $(if $(CONFIG_SDK),sdk) $(if $(CONFIG_IB),imagebuilder) $(if $(CONFIG_MAKE_TOOLCHAIN),toolchain)
+
+$(curdir)/sdk/install:=$(curdir)/linux/install
+$(curdir)/imagebuilder/install:=$(curdir)/linux/install
+
+$(eval $(call stampfile,$(curdir),target,prereq,.config))
+$(eval $(call stampfile,$(curdir),target,compile,$(TMP_DIR)/.build))
+$(eval $(call stampfile,$(curdir),target,install,$(TMP_DIR)/.build))
+
+$($(curdir)/stamp-install): $($(curdir)/stamp-compile) 
+
+$(eval $(call subdir,$(curdir)))
diff --git a/target/imagebuilder/Config.in b/target/imagebuilder/Config.in
new file mode 100644
index 0000000000..0862f36032
--- /dev/null
+++ b/target/imagebuilder/Config.in
@@ -0,0 +1,16 @@
+config IB
+	bool "Build the libreCMC Image Builder"
+	depends on !EXTERNAL_TOOLCHAIN
+	help
+	  This is essentially a stripped-down version of the buildroot
+	  with precompiled packages, kernel image and image building tools.
+	  You can use it to generate custom images without compiling anything
+
+config IB_STANDALONE
+	bool "Include package repositories"
+	default y
+	depends on IB
+	help
+	  Disabling this option will cause the ImageBuilder to embed only
+	  toolchain and kmod packages while all other ipk archives will be
+	  fetched from online repositories.
diff --git a/target/imagebuilder/Makefile b/target/imagebuilder/Makefile
new file mode 100644
index 0000000000..b43662b6ac
--- /dev/null
+++ b/target/imagebuilder/Makefile
@@ -0,0 +1,88 @@
+# 
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/version.mk
+include $(INCLUDE_DIR)/feeds.mk
+
+override MAKEFLAGS=
+
+IB_NAME:=$(VERSION_DIST_SANITIZED)-imagebuilder-$(if $(CONFIG_VERSION_FILENAMES),$(VERSION_NUMBER)-)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET)).$(HOST_OS)-$(HOST_ARCH)
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(IB_NAME)
+IB_KDIR:=$(patsubst $(TOPDIR)/%,$(PKG_BUILD_DIR)/%,$(KERNEL_BUILD_DIR))
+IB_LDIR:=$(patsubst $(TOPDIR)/%,$(PKG_BUILD_DIR)/%,$(LINUX_DIR))
+IB_DTSDIR:=$(patsubst $(TOPDIR)/%,$(PKG_BUILD_DIR)/%,$(LINUX_DIR))/arch/$(ARCH)/boot/dts/
+
+all: compile
+
+$(BIN_DIR)/$(IB_NAME).tar.xz: clean
+	rm -rf $(PKG_BUILD_DIR)
+	mkdir -p $(IB_KDIR) $(IB_LDIR) $(PKG_BUILD_DIR)/staging_dir/host/lib \
+		$(PKG_BUILD_DIR)/target $(PKG_BUILD_DIR)/scripts $(IB_DTSDIR)
+	-cp $(TOPDIR)/.config $(PKG_BUILD_DIR)/.config
+	$(CP) -L \
+		$(INCLUDE_DIR) $(SCRIPT_DIR) \
+		$(TOPDIR)/rules.mk \
+		./files/Makefile \
+		./files/repositories.conf \
+		$(TMP_DIR)/.targetinfo \
+		$(TMP_DIR)/.packageinfo \
+		$(PKG_BUILD_DIR)/
+
+ifeq ($(CONFIG_IB_STANDALONE),)
+	echo '## Remote package repositories' >> $(PKG_BUILD_DIR)/repositories.conf
+	$(call FeedSourcesAppend,$(PKG_BUILD_DIR)/repositories.conf)
+endif
+
+	echo ''                                                        >> $(PKG_BUILD_DIR)/repositories.conf
+	echo '## This is the local package repository, do not remove!' >> $(PKG_BUILD_DIR)/repositories.conf
+	echo 'src imagebuilder file:packages'                          >> $(PKG_BUILD_DIR)/repositories.conf
+
+	$(VERSION_SED) $(PKG_BUILD_DIR)/repositories.conf
+
+ifeq ($(CONFIG_IB_STANDALONE),)
+	(cd $(call FeedPackageDir,libc); $(FIND) -type f -name 'libc_*.ipk' -or -name 'kernel_*.ipk' -or -name 'kmod-*.ipk') | \
+		while read path; do \
+			mkdir -p "$(PKG_BUILD_DIR)/packages/$${path%/*}"; \
+			cp "$(call FeedPackageDir,libc)/$$path" "$(PKG_BUILD_DIR)/packages/$$path"; \
+		done
+else
+	$(INSTALL_DIR) $(PKG_BUILD_DIR)/packages
+	find $(wildcard $(PACKAGE_SUBDIRS)) -type f -name '*.ipk' -exec $(CP) {} $(PKG_BUILD_DIR)/packages/ \;
+endif
+
+	$(CP) $(TOPDIR)/target/linux $(PKG_BUILD_DIR)/target/
+	if [ -d $(TOPDIR)/staging_dir/host/lib/grub ]; then \
+		$(CP) $(TOPDIR)/staging_dir/host/lib/grub/ $(PKG_BUILD_DIR)/staging_dir/host/lib; \
+	fi
+	rm -rf \
+		$(PKG_BUILD_DIR)/target/linux/*/files{,-*} \
+		$(PKG_BUILD_DIR)/target/linux/*/patches{,-*}
+	-cp $(KERNEL_BUILD_DIR)/* $(IB_KDIR)/ # don't copy subdirectories here
+	-cp $(LINUX_DIR)/.config $(IB_LDIR)/
+	-$(SCRIPT_DIR)/bundle-libraries.sh $(IB_LDIR)/scripts/dtc \
+	  $(LINUX_DIR)/scripts/dtc/dtc
+	if [ -d $(LINUX_DIR)/arch/$(ARCH)/boot/dts ]; then \
+		$(CP) $(LINUX_DIR)/arch/$(ARCH)/boot/dts/* $(IB_DTSDIR); \
+	fi
+	$(SED) 's,^# REVISION:=.*,REVISION:=$(REVISION),g' $(PKG_BUILD_DIR)/include/version.mk
+	find $(PKG_BUILD_DIR) -name CVS -o -name .git -o -name .svn \
+	  | $(XARGS) rm -rf
+	find $(STAGING_DIR_HOST)/bin -maxdepth 1 -type f -perm -u=x \
+	  | $(XARGS) $(SCRIPT_DIR)/bundle-libraries.sh $(PKG_BUILD_DIR)/staging_dir/host/bin/
+	STRIP=sstrip $(SCRIPT_DIR)/rstrip.sh $(PKG_BUILD_DIR)/staging_dir/host/bin/
+	$(TAR) -cf - -C $(BUILD_DIR) $(IB_NAME) | xz -zc -7e > $@
+
+download:
+prepare:
+compile: $(BIN_DIR)/$(IB_NAME).tar.xz
+install: compile
+
+clean: FORCE
+	rm -rf $(PKG_BUILD_DIR) $(BIN_DIR)/$(IB_NAME).tar.xz
diff --git a/target/imagebuilder/files/Makefile b/target/imagebuilder/files/Makefile
new file mode 100644
index 0000000000..493012ff72
--- /dev/null
+++ b/target/imagebuilder/files/Makefile
@@ -0,0 +1,204 @@
+# Makefile for OpenWrt
+#
+# Copyright (C) 2007-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+TOPDIR:=${CURDIR}
+LC_ALL:=C
+LANG:=C
+export TOPDIR LC_ALL LANG
+export OPENWRT_VERBOSE=s
+all: help
+
+include $(TOPDIR)/include/host.mk
+
+ifneq ($(OPENWRT_BUILD),1)
+  override OPENWRT_BUILD=1
+  export OPENWRT_BUILD
+endif
+
+include rules.mk
+include $(INCLUDE_DIR)/debug.mk
+include $(INCLUDE_DIR)/depends.mk
+
+include $(INCLUDE_DIR)/version.mk
+export REVISION
+
+define Helptext
+Available Commands:
+	help:	This help text
+	info:	Show a list of available target profiles
+	clean:	Remove images and temporary build files
+	image:	Build an image (see below for more information).
+
+Building images:
+	By default 'make image' will create an image with the default
+	target profile and package set. You can use the following parameters
+	to change that:
+
+	make image PROFILE="<profilename>" # override the default target profile
+	make image PACKAGES="<pkg1> [<pkg2> [<pkg3> ...]]" # include extra packages
+	make image FILES="<path>" # include extra files from <path>
+	make image BIN_DIR="<path>" # alternative output directory for the images
+	make image EXTRA_IMAGE_NAME="<string>" # Add this to the output image filename (sanitized)
+endef
+$(eval $(call shexport,Helptext))
+
+help: FORCE
+	echo "$$$(call shvar,Helptext)"
+
+
+# override variables from rules.mk
+PACKAGE_DIR:=$(TOPDIR)/packages
+LISTS_DIR:=$(subst $(space),/,$(patsubst %,..,$(subst /,$(space),$(TARGET_DIR))))$(DL_DIR)
+OPKG:= \
+  IPKG_NO_SCRIPT=1 \
+  IPKG_INSTROOT="$(TARGET_DIR)" \
+  $(STAGING_DIR_HOST)/bin/opkg \
+	-f $(TOPDIR)/repositories.conf \
+	--force-depends \
+	--force-overwrite \
+	--force-postinstall \
+	--cache $(DL_DIR) \
+	--lists-dir $(LISTS_DIR) \
+	--offline-root $(TARGET_DIR) \
+	--add-dest root:/ \
+	--add-arch all:100 \
+	--add-arch $(ARCH_PACKAGES):200
+
+include $(INCLUDE_DIR)/target.mk
+-include .profiles.mk
+
+USER_PROFILE ?= $(firstword $(PROFILE_NAMES))
+PROFILE_LIST = $(foreach p,$(PROFILE_NAMES), \
+	echo '$(patsubst DEVICE_%,%,$(p)):'; $(if $($(p)_NAME),echo '    $($(p)_NAME)'; ) echo '    Packages: $($(p)_PACKAGES)'; \
+)
+
+.profiles.mk: .targetinfo
+	$(SCRIPT_DIR)/target-metadata.pl profile_mk $< '$(BOARD)$(if $(SUBTARGET),/$(SUBTARGET))' > $@
+
+staging_dir/host/.prereq-build: include/prereq-build.mk
+	mkdir -p tmp
+	rm -f tmp/.host.mk
+	@$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prereq-build.mk prereq 2>/dev/null || { \
+		echo "Prerequisite check failed. Use FORCE=1 to override."; \
+		false; \
+	}
+  ifneq ($(realpath $(TOPDIR)/include/prepare.mk),)
+	@$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f $(TOPDIR)/include/prepare.mk prepare 2>/dev/null || { \
+		echo "Preparation failed."; \
+		false; \
+	}
+  endif
+	touch $@
+
+_call_info: FORCE
+	echo 'Current Target: "$(BOARD)$(if $(SUBTARGET), ($(BOARDNAME)))"'
+	echo 'Default Packages: $(DEFAULT_PACKAGES)'
+	echo 'Available Profiles:'
+	echo; $(PROFILE_LIST)
+
+BUILD_PACKAGES:=$(USER_PACKAGES) $(sort $(DEFAULT_PACKAGES) $($(USER_PROFILE)_PACKAGES) kernel)
+# "-pkgname" in the package list means remove "pkgname" from the package list
+BUILD_PACKAGES:=$(filter-out $(filter -%,$(BUILD_PACKAGES)) $(patsubst -%,%,$(filter -%,$(BUILD_PACKAGES))),$(BUILD_PACKAGES))
+PACKAGES:=
+
+_call_image: staging_dir/host/.prereq-build
+	echo 'Building images for $(BOARD)$(if $($(USER_PROFILE)_NAME), - $($(USER_PROFILE)_NAME))'
+	echo 'Packages: $(BUILD_PACKAGES)'
+	echo
+	rm -rf $(TARGET_DIR)
+	mkdir -p $(TARGET_DIR) $(BIN_DIR) $(TMP_DIR) $(DL_DIR)
+	if [ ! -f "$(PACKAGE_DIR)/Packages" ] || [ ! -f "$(PACKAGE_DIR)/Packages.gz" ] || [ "`find $(PACKAGE_DIR) -cnewer $(PACKAGE_DIR)/Packages.gz`" ]; then \
+		echo "Package list missing or not up-to-date, generating it.";\
+		$(MAKE) package_index; \
+	else \
+		mkdir -p $(TARGET_DIR)/tmp; \
+		$(OPKG) update || true; \
+	fi
+	$(MAKE) package_install
+ifneq ($(USER_FILES),)
+	$(MAKE) copy_files
+endif
+	$(MAKE) package_postinst
+	$(MAKE) build_image
+	$(MAKE) checksum
+
+package_index: FORCE
+	@echo
+	@echo Building package index...
+	@mkdir -p $(TMP_DIR) $(TARGET_DIR)/tmp
+	(cd $(PACKAGE_DIR); $(SCRIPT_DIR)/ipkg-make-index.sh . > Packages && \
+		gzip -9nc Packages > Packages.gz \
+	) >/dev/null 2>/dev/null
+	$(OPKG) update || true
+
+package_install: FORCE
+	@echo
+	@echo Installing packages...
+	$(OPKG) install $(firstword $(wildcard $(PACKAGE_DIR)/libc_*.ipk $(PACKAGE_DIR)/base/libc_*.ipk))
+	$(OPKG) install $(firstword $(wildcard $(PACKAGE_DIR)/kernel_*.ipk $(PACKAGE_DIR)/base/kernel_*.ipk))
+	$(OPKG) install $(BUILD_PACKAGES)
+	rm -f $(TARGET_DIR)/usr/lib/opkg/lists/*
+
+copy_files: FORCE
+	@echo
+	@echo Copying extra files
+	@$(call file_copy,$(USER_FILES)/*,$(TARGET_DIR)/)
+
+package_postinst: FORCE
+	@echo
+	@echo Cleaning up
+	@rm -f $(TARGET_DIR)/tmp/opkg.lock
+	@echo
+	@echo Activating init scripts
+	@mkdir -p $(TARGET_DIR)/etc/rc.d
+	@( \
+		cd $(TARGET_DIR); \
+		for script in ./usr/lib/opkg/info/*.postinst; do \
+			IPKG_INSTROOT=$(TARGET_DIR) $$(which bash) $$script; \
+		done || true \
+	)
+	rm -f $(TARGET_DIR)/usr/lib/opkg/info/*.postinst
+	$(if $(CONFIG_CLEAN_IPKG),rm -rf $(TARGET_DIR)/usr/lib/opkg)
+
+build_image: FORCE
+	@echo
+	@echo Building images...
+	$(NO_TRACE_MAKE) -C target/linux/$(BOARD)/image install TARGET_BUILD=1 IB=1 EXTRA_IMAGE_NAME="$(EXTRA_IMAGE_NAME)" \
+		$(if $(USER_PROFILE),PROFILE="$(USER_PROFILE)")
+
+checksum: FORCE
+	@echo
+	@echo Calculating checksums...
+	@$(call sha256sums,$(BIN_DIR))
+
+clean:
+	rm -rf $(TMP_DIR) $(DL_DIR) $(TARGET_DIR) $(BIN_DIR)
+
+
+info:
+	(unset PROFILE FILES PACKAGES MAKEFLAGS; $(MAKE) -s _call_info)
+
+PROFILE_FILTER = $(filter DEVICE_$(PROFILE) $(PROFILE),$(PROFILE_NAMES))
+
+image:
+ifneq ($(PROFILE),)
+  ifeq ($(PROFILE_FILTER),)
+	@echo 'Profile "$(PROFILE)" does not exist!'
+	@echo 'Use "make info" to get a list of available profile names.'
+	@exit 1
+  endif
+endif
+	(unset PROFILE FILES PACKAGES MAKEFLAGS; \
+	$(MAKE) _call_image \
+		$(if $(PROFILE),USER_PROFILE="$(PROFILE_FILTER)") \
+		$(if $(FILES),USER_FILES="$(FILES)") \
+		$(if $(PACKAGES),USER_PACKAGES="$(PACKAGES)") \
+		$(if $(BIN_DIR),BIN_DIR="$(BIN_DIR)"))
+
+.SILENT: help info image
+
diff --git a/target/imagebuilder/files/repositories.conf b/target/imagebuilder/files/repositories.conf
new file mode 100644
index 0000000000..93ed97b290
--- /dev/null
+++ b/target/imagebuilder/files/repositories.conf
@@ -0,0 +1,4 @@
+## Place your custom repositories here, they must match the architecture and version.
+# src/gz %n %U
+# src custom file:///usr/src/lede/bin/%T/packages
+
diff --git a/target/linux/Makefile b/target/linux/Makefile
new file mode 100644
index 0000000000..f7bbdffbf8
--- /dev/null
+++ b/target/linux/Makefile
@@ -0,0 +1,13 @@
+# 
+# Copyright (C) 2006-2007 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+export TARGET_BUILD=1
+
+prereq clean download prepare compile install menuconfig nconfig oldconfig update refresh: FORCE
+	@+$(NO_TRACE_MAKE) -C $(BOARD) $@
diff --git a/target/linux/ar71xx/Makefile b/target/linux/ar71xx/Makefile
new file mode 100644
index 0000000000..a8df2b036e
--- /dev/null
+++ b/target/linux/ar71xx/Makefile
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2008-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=mips
+BOARD:=ar71xx
+BOARDNAME:=Atheros AR7xxx/AR9xxx
+FEATURES:=mips16
+CPU_TYPE:=24kc
+SUBTARGETS:=generic nand mikrotik
+
+KERNEL_PATCHVER:=4.4
+
+include $(INCLUDE_DIR)/target.mk
+
+DEFAULT_PACKAGES += \
+	kmod-gpio-button-hotplug swconfig \
+	kmod-ath9k wpad-mini uboot-envtools
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/ar71xx/base-files/etc/board.d/01_leds b/target/linux/ar71xx/base-files/etc/board.d/01_leds
new file mode 100755
index 0000000000..a93ea1d578
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/board.d/01_leds
@@ -0,0 +1,763 @@
+#!/bin/sh
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+
+. /lib/functions/uci-defaults.sh
+. /lib/ar71xx.sh
+
+board_config_update
+
+board=$(ar71xx_board_name)
+
+case "$board" in
+airgateway|\
+airgatewaypro)
+	ucidef_set_led_wlan "wlan" "WLAN" "ubnt:blue:wlan" "phy0tpt"
+	;;
+alfa-nx)
+	ucidef_set_led_netdev "wan" "WAN" "alfa:green:led_2" "eth0"
+	ucidef_set_led_netdev "lan" "LAN" "alfa:green:led_3" "eth1"
+	;;
+all0258n|\
+all0315n)
+	ucidef_set_rssimon "wlan0" "200000" "1"
+	ucidef_set_led_rssi "rssilow" "RSSILOW" "$board:red:rssilow" "wlan0" "1" "40" "0" "6"
+	ucidef_set_led_rssi "rssimedium" "RSSIMEDIUM" "$board:yellow:rssimedium" "wlan0" "30" "80" "-29" "5"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "$board:green:rssihigh" "wlan0" "70" "100" "-69" "8"
+	;;
+antminer-s1|\
+antminer-s3)
+	ucidef_set_led_default "sys" "SYS" "$board:green:sys" "0"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
+
+	case "$board" in
+	antminer-s3)
+		ucidef_set_led_default "lan" "LAN" "$board:yellow:lan" "0"
+		;;
+	esac
+	;;
+antrouter-r1)
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
+	ucidef_set_led_default "btc" "BTC" "$board:green:btc" "0"
+	;;
+arduino-yun)
+	ucidef_set_led_wlan "wlan" "WLAN" "arduino:blue:wlan" "phy0tpt"
+	ucidef_set_led_usbdev "usb" "USB" "arduino:white:usb" "1-1.1"
+	;;
+ap113|\
+db120)
+	ucidef_set_led_usbdev "usb" "USB" "$board:green:usb" "1-1"
+	;;
+ap147-010)
+	ucidef_set_led_netdev "wan" "WAN" "ap147:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "ap147:green:lan1" "switch0" "0x10"
+	ucidef_set_led_switch "lan2" "LAN2" "ap147:green:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "ap147:green:lan3" "switch0" "0x04"
+	ucidef_set_led_switch "lan4" "LAN4" "ap147:green:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "ap147:green:wlan-2g" "phy0tpt"
+	;;
+ap90q|\
+cpe830|\
+cpe870|\
+dr531)
+	ucidef_set_led_netdev "lan" "LAN" "$board:green:lan" "eth0"
+	ucidef_set_led_netdev "wan" "WAN" "$board:green:wan" "eth1"
+
+	case "$board" in
+	ap90q)
+		ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
+		;;
+	cpe830|\
+	cpe870)
+		ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
+		ucidef_set_rssimon "wlan0" "200000" "1"
+		ucidef_set_led_rssi "rssilow" "RSSILOW" "$board:green:link1" "wlan0" "1" "100" "0" "13"
+		ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "$board:green:link2" "wlan0" "26" "100" "-25" "13"
+		ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "$board:green:link3" "wlan0" "51" "100" "-50" "13"
+		ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "$board:green:link4" "wlan0" "76" "100" "-75" "13"
+		;;
+	esac
+	;;
+bhr-4grv2)
+	ucidef_set_led_default "power" "POWER" "buffalo:green:power" "1"
+	ucidef_set_led_default "diag" "DIAG" "buffalo:red:diag" "0"
+	;;
+bsb)
+	ucidef_set_led_default "sys" "SYS" "$board:red:sys" "1"
+	;;
+bullet-m|\
+nanostation-m|\
+rocket-m|\
+rocket-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"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "ubnt:green:link4" "wlan0" "76" "100" "-75" "13"
+	;;
+rocket-m-ti)
+	ucidef_set_led_rssi "rssiverylow" "RSSIVERYLOW" "ubnt:green:link1" "wlan0" "1" "100" "0" "13"
+	ucidef_set_led_rssi "rssilow" "RSSILOW" "ubnt:green:link2" "wlan0" "26" "100" "-25" "13"
+	ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "ubnt:green:link3" "wlan0" "51" "100" "-50" "13"
+	ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "ubnt:green:link4" "wlan0" "76" "100" "-75" "13"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "ubnt:green:link5" "wlan0" "76" "100" "-75" "13"
+	ucidef_set_led_rssi "rssiveryhigh" "RSSIVERYHIGH" "ubnt:green:link4" "wlan0" "76" "100" "-75" "13"
+	;;
+bxu2000n-2-a1)
+	ucidef_set_led_wlan "wlan" "WLAN" "bhu:green:wlan" "phy0tpt"
+	;;
+cap324)
+	ucidef_set_led_netdev "lan" "LAN" "pcs:green:lan" "eth0"
+	ucidef_set_led_wlan "wlan_amber" "WLAN_AMBER" "pcs:amber:wlan" "phy0tpt"
+	ucidef_set_led_wlan "wlan_green" "WLAN_GREEN" "pcs:green:wlan" "phy1tpt"
+	;;
+c-55)
+	ucidef_set_led_netdev "lan_green" "LAN_GREEN" "$board:green:lan" "eth0"
+	ucidef_set_led_wlan "wlan_amber" "WLAN_AMBER" "$board:amber:wlan" "phy0tpt"
+	ucidef_set_led_wlan "wlan_green" "WLAN_GREEN" "$board:green:wlan" "phy1tpt"
+	;;
+c-60)
+	ucidef_set_led_wlan "wlan1_green" "WLAN1_GREEN" "$board:green:wlan1" "phy0tpt"
+	ucidef_set_led_wlan "wlan2_green" "WLAN2_GREEN" "$board:green:wlan2" "phy1tpt"
+	;;
+cap4200ag)
+	ucidef_set_led_default "lan_green" "LAN_GREEN" "senao:green:lan" "1"
+	ucidef_set_led_wlan "wlan_amber" "WLAN_AMBER" "senao:amber:wlan" "phy0tpt"
+	ucidef_set_led_wlan "wlan_green" "WLAN_GREEN" "senao:green:wlan" "phy1tpt"
+	;;
+carambola2)
+	ucidef_set_led_netdev "lan" "LAN" "$board:orange:eth0" "eth0"
+	ucidef_set_led_netdev "wan" "WAN" "$board:orange:eth1" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
+	;;
+cf-e316n-v2)
+	ucidef_set_led_netdev "lan" "LAN" "$board:blue:lan" "eth0"
+	ucidef_set_led_netdev "wan" "WAN" "$board:blue:wan" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:blue:wlan" "phy0tpt"
+	;;
+cf-e320n-v2)
+	ucidef_set_led_netdev "lan" "LAN" "$board:green:lan" "eth0"
+	ucidef_set_led_netdev "wan" "WAN" "$board:red:wan" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:blue:wlan" "phy0tpt"
+	;;
+cf-e380ac-v1|\
+cf-e380ac-v2)
+	ucidef_set_led_netdev "lan" "LAN" "$board:green:lan" "eth0"
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "$board:blue:wlan2g" "phy1tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN5G" "$board:red:wlan5g" "phy0tpt"
+	;;
+cf-e520n|\
+cf-e530n)
+	ucidef_set_led_netdev "wan" "WAN" "$board:blue:wan" "eth1"
+	;;
+cpe210|\
+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" "200000" "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"
+	;;
+cr3000)
+	ucidef_set_led_netdev "wan" "WAN" "pcs:blue:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "pcs:blue:lan1" "switch0" "0x04"
+	ucidef_set_led_switch "lan2" "LAN2" "pcs:blue:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "pcs:blue:lan3" "switch0" "0x10"
+	ucidef_set_led_switch "lan4" "LAN4" "pcs:blue:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "pcs:blue:wlan" "phy0tpt"
+	;;
+cr5000)
+	ucidef_set_led_wlan "wlan" "WLAN" "pcs:blue:wlan" "phy0tpt"
+	ucidef_set_led_usbdev "usb" "USB" "pcs:white:wps" "1-1"
+	;;
+dragino2)
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:red:wlan" "phy0tpt"
+	ucidef_set_led_netdev "lan" "LAN" "$board:red:lan" "eth0"
+	ucidef_set_led_netdev "wan" "WAN" "$board:red:wan" "eth1"
+	;;
+dw33d)
+	ucidef_set_led_usbdev "mmc" "MMC" "$board:blue:mmc" "1-1"
+	ucidef_set_led_usbdev "usb" "USB" "$board:blue:usb" "2-1"
+	ucidef_set_led_netdev "internet" "INTERNET" "$board:blue:internet" "eth0"
+	ucidef_set_led_wlan "wlan2g" "WLAN-2.4G" "$board:blue:wlan-2g" "phy1tpt"
+	;;
+eap300v2)
+	ucidef_set_led_netdev "lan" "LAN" "engenius:blue:lan" "eth0"
+	ucidef_set_led_wlan "wlan" "WLAN" "engenius:blue:wlan" "phy0tpt"
+	;;
+f9k1115v2)
+	ucidef_set_led_usbdev "usb2" "USB2" "belkin:green:usb2" "1-1"
+	;;
+rb-750)
+	ucidef_set_led_default "act" "act" "rb750:green:act" "1"
+	ucidef_set_led_netdev "port1" "port1" "rb750:green:port1" "eth1"
+	ucidef_set_led_switch "port2" "port2" "rb750:green:port2" "switch0" "0x10"
+	ucidef_set_led_switch "port3" "port3" "rb750:green:port3" "switch0" "0x08"
+	ucidef_set_led_switch "port4" "port4" "rb750:green:port4" "switch0" "0x04"
+	ucidef_set_led_switch "port5" "port5" "rb750:green:port5" "switch0" "0x02"
+	;;
+rb-2011l|\
+rb-2011uas|\
+rb-2011uias|\
+rb-2011uas-2hnd|\
+rb-2011uias-2hnd)
+	ucidef_set_led_switch "eth6" "ETH6" "rb:green:eth6" "switch1" "0x20"
+	ucidef_set_led_switch "eth7" "ETH7" "rb:green:eth7" "switch1" "0x10"
+	ucidef_set_led_switch "eth8" "ETH8" "rb:green:eth8" "switch1" "0x08"
+	ucidef_set_led_switch "eth9" "ETH9" "rb:green:eth9" "switch1" "0x04"
+	ucidef_set_led_switch "eth10" "ETH10" "rb:green:eth10" "switch1" "0x02"
+	;;
+dap-2695-a1)
+	ucidef_set_led_default "power" "POWER" "d-link:green:power" "1"
+	ucidef_set_led_default "diag" "DIAG" "d-link:red:power" "0"
+	ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "d-link:green:wlan2g" "phy1tpt"
+	;;
+dhp-1565-a1)
+	ucidef_set_led_switch "wan" "WAN" "d-link:green:planet" "switch0" "0x20"
+	;;
+dir-600-a1|\
+dir-615-e1|\
+dir-615-e4)
+	ucidef_set_led_netdev "wan" "WAN" "d-link:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "d-link:green:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2" "LAN2" "d-link:green:lan2" "switch0" "0x04"
+	ucidef_set_led_switch "lan3" "LAN3" "d-link:green:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4" "LAN4" "d-link:green:lan4" "switch0" "0x10"
+	;;
+dir-615-c1)
+	ucidef_set_led_netdev "wan" "WAN" "d-link:green:wan" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "d-link:green:wlan" "phy0tpt"
+	;;
+dir-825-b1|\
+dir-825-c1)
+	ucidef_set_led_usbdev "usb" "USB" "d-link:blue:usb" "1-1"
+
+	case "$board" in
+	dir-825-c1)
+		ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "d-link:blue:wlan2g" "phy0tpt"
+		;;
+	esac
+	;;
+dir-615-i1)
+	ucidef_set_led_default "power" "POWER" "d-link:green:power" "1"
+	ucidef_set_led_default "diag" "DIAG" "d-link:amber:power" "0"
+	ucidef_set_led_default "wps" "WPS" "d-link:blue:wps" "0"
+	ucidef_set_led_netdev "wan" "WAN" "d-link:green:wan" "eth0"
+	ucidef_set_led_wlan "wlan" "WLAN" "d-link:green:wlan" "phy0tpt"
+	;;
+dlan-hotspot)
+	ucidef_set_led_wlan "wlan" "WLAN" "devolo:green:wifi" "phy0tpt"
+	;;
+dlan-pro-500-wp)
+	ucidef_set_led_default "power" "System Power" "devolo:green:status" "1"
+	ucidef_set_led_netdev "lan" "Ethernet Activity" "devolo:green:eth" "br-lan"
+	ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "devolo:green:wlan-2g" "phy0tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN 5 GHz" "devolo:blue:wlan-5g" "none"
+	;;
+dlan-pro-1200-ac)
+	ucidef_set_led_wlan "wlan" "WLAN" "devolo:status:wlan" "phy0radio"
+	ucidef_set_led_gpio "plcw" "dLAN" "devolo:status:dlan" "17" "0"
+	ucidef_set_led_gpio "plcr" "dLAN" "devolo:error:dlan" "16" "0"
+	;;
+gl-ar150|\
+gl-ar300|\
+gl-ar300m|\
+gl-mifi)
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:wlan" "phy0tpt"
+
+	case "$board" in
+	gl-mifi)
+		ucidef_set_led_netdev "wan" "WAN" "$board:wan" "eth0"
+		ucidef_set_led_netdev "lan" "LAN" "$board:lan" "eth1"
+		ucidef_set_led_netdev "3gnet" "3GNET" "$board:net" "3g-wan"
+		;;
+	esac
+	;;
+gl-domino|\
+wrt160nl)
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:blue:wlan" "phy0tpt"
+	;;
+gl-inet)
+	ucidef_set_led_netdev "lan" "LAN" "$board:green:lan" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:red:wlan" "phy0tpt"
+	;;
+esr900)
+	ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "engenius:blue:wlan-2g" "phy0tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN 5 GHz" "engenius:blue:wlan-5g" "phy1tpt"
+	;;
+esr1750|\
+epg5000)
+	ucidef_set_led_wlan "wlan2g" "WLAN 2.4 GHz" "$board:blue:wlan-2g" "phy1tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN 5 GHz" "$board:blue:wlan-5g" "phy0tpt"
+	;;
+hiwifi-hc6361)
+	ucidef_set_led_netdev "inet" "INET" "hiwifi:blue:internet" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "hiwifi:blue:wlan-2p4" "phy0tpt"
+	;;
+hornet-ub|\
+hornet-ub-x2)
+	ucidef_set_led_netdev "lan" "LAN" "alfa:blue:lan" "eth0"
+	ucidef_set_led_netdev "wan" "WAN" "alfa:blue:wan" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "alfa:blue:wlan" "phy0tpt"
+	ucidef_set_led_usbdev "usb" "USB" "alfa:blue:usb" "1-1"
+	;;
+mc-mac1200r)
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "mercury:green:wlan2g" "phy1tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN5G" "mercury:green:wlan5g" "phy0tpt"
+	;;
+mr12|\
+mr16)
+	ucidef_set_led_netdev "wan" "WAN" "$board:green:wan" "eth0"
+	ucidef_set_led_wlan "wlan1" "WLAN1" "$board:green:wifi1" "phy0assoc"
+	ucidef_set_led_wlan "wlan2" "WLAN2" "$board:green:wifi2" "phy0assoc"
+	ucidef_set_led_wlan "wlan3" "WLAN3" "$board:green:wifi3" "phy0assoc"
+	ucidef_set_led_wlan "wlan4" "WLAN4" "$board:green:wifi4" "phy0tpt"
+	;;
+mr18)
+	ucidef_set_led_netdev "wlan0" "WLAN0" "$board:blue:tricolor0" "wlan0"
+	;;
+mr600)
+	ucidef_set_led_wlan "wlan58" "WLAN58" "$board:green:wlan58" "phy0tpt"
+	ucidef_set_led_default "wps" "WPS" "mr600:blue:wps" "0"
+	;;
+mr600v2)
+	ucidef_set_led_default "wlan24-red" "WLAN 2.4GHz (red)" "mr600:red:wlan24" "0"
+	ucidef_set_led_default "wlan24-yellow" "WLAN 2.4GHz (yellow)" "mr600:yellow:wlan24" "0"
+	ucidef_set_led_wlan "wlan24-green" "WLAN 4GHz (green)" "mr600:green:wlan24" "phy1tpt"
+	ucidef_set_led_default "wlan5-red" "WLAN 5GHz (red)" "mr600:red:wlan58" "0"
+	ucidef_set_led_default "wlan5-yellow" "WLAN 5GHz (yellow)" "mr600:yellow:wlan58" "0"
+	ucidef_set_led_wlan "wlan5-green" "WLAN 5GHz (green)" "mr600:green:wlan58" "phy0tpt"
+	;;
+mr1750|\
+mr1750v2)
+	ucidef_set_led_netdev "lan" "LAN" "mr1750:blue:wan" "eth0"
+	ucidef_set_led_wlan "wlan58" "WLAN58" "mr1750:blue:wlan58" "phy0tpt"
+	ucidef_set_led_wlan "wlan24" "WLAN24" "mr1750:blue:wlan24" "phy1tpt"
+	ucidef_set_led_default "status-red" "Status (red)" "mr1750:red:wifi" "0"
+	ucidef_set_led_default "status-green" "Status (green)" "mr1750:green:wifi" "0"
+	;;
+mr900|\
+mr900v2)
+	ucidef_set_led_netdev "lan" "LAN" "mr900:blue:wan" "eth0"
+	ucidef_set_led_wlan "wlan24" "WLAN24" "mr900:blue:wlan24" "phy0tpt"
+	ucidef_set_led_wlan "wlan58" "WLAN58" "mr900:blue:wlan58" "phy1tpt"
+	ucidef_set_led_default "status-red" "Status (red)" "mr900:red:wifi" "0"
+	ucidef_set_led_default "status-green" "Status (green)" "mr900:green:wifi" "0"
+	;;
+mynet-n600)
+	ucidef_set_led_netdev "wan" "WAN" "wd:blue:internet" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "wd:green:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2" "LAN2" "wd:green:lan2" "switch0" "0x10"
+	ucidef_set_led_switch "lan3" "LAN3" "wd:green:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4" "LAN4" "wd:green:lan4" "switch0" "0x04"
+	;;
+mynet-rext)
+	ucidef_set_led_netdev "lan" "LAN" "wd:blue:ethernet" "eth0"
+	ucidef_set_rssimon "wlan0" "200000" "1"
+	ucidef_set_led_rssi "rssilow" "RSSILOW" "wd:blue:quality1" "wlan0" "1" "40" "0" "6"
+	ucidef_set_led_rssi "rssimedium" "RSSIMEDIUM" "wd:blue:quality2" "wlan0" "30" "80" "-29" "5"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "wd:blue:quality3" "wlan0" "70" "100" "-69" "8"
+	ucidef_set_led_wlan "wlan" "WLAN" "wd:blue:wireless" "phy0tpt"
+	;;
+mzk-w04u)
+	ucidef_set_led_usbdev "usb" "USB" "planex:green:usb" "1-1"
+	;;
+mzk-w300nh)
+	ucidef_set_led_wlan "wlan" "WLAN" "planex:green:wlan" "phy0tpt"
+	;;
+nbg460n_550n_550nh)
+	ucidef_set_led_wlan "wlan" "WLAN" "nbg460n:green:wlan" "phy0tpt"
+	;;
+nbg6616)
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wifi2g" "phy1tpt"
+	ucidef_set_led_wlan "wlan5" "WLAN5" "$board:green:wifi5g" "phy0tpt"
+	ucidef_set_led_usbdev "usb1" "USB1" "$board:green:usb1" "1-1"
+	ucidef_set_led_usbdev "usb2" "USB2" "$board:green:usb2" "2-1"
+	;;
+nbg6716)
+	ucidef_set_led_netdev "wan" "WAN" "$board:white:internet" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:white:wifi2g" "phy1tpt"
+	ucidef_set_led_wlan "wlan5" "WLAN5" "$board:white:wifi5g" "phy0tpt"
+	ucidef_set_led_usbdev "usb1" "USB1" "$board:white:usb1" "1-1"
+	ucidef_set_led_usbdev "usb2" "USB2" "$board:white:usb2" "2-1"
+	;;
+om2p|\
+om2pv2|\
+om2p-hs|\
+om2p-hsv2|\
+om2p-hsv3|\
+om2p-lc)
+	ucidef_set_led_netdev "port1" "port1" "om2p:blue:wan" "eth0"
+	ucidef_set_led_netdev "port2" "port2" "om2p:blue:lan" "eth1"
+	ucidef_set_led_default "wlan-red" "WLAN (red)" "om2p:red:wifi" "0"
+	ucidef_set_led_default "wlan-yellow" "WLAN (yellow)" "om2p:yellow:wifi" "0"
+	ucidef_set_led_default "wlan-green" "WLAN (green)" "om2p:green:wifi" "0"
+	;;
+om5p|\
+om5p-an)
+	ucidef_set_led_netdev "port1" "port1" "om5p:blue:wan" "eth0"
+	ucidef_set_led_netdev "port2" "port2" "om5p:blue:lan" "eth1"
+	ucidef_set_led_default "wlan-red" "WLAN (red)" "om5p:red:wifi" "0"
+	ucidef_set_led_default "wlan-yellow" "WLAN (yellow)" "om5p:yellow:wifi" "0"
+	ucidef_set_led_default "wlan-green" "WLAN (green)" "om5p:green:wifi" "0"
+	;;
+om5p-ac)
+	ucidef_set_led_netdev "port1" "port1" "om5pac:blue:lan" "eth0"
+	ucidef_set_led_netdev "port2" "port2" "om5pac:blue:wan" "eth1"
+	ucidef_set_led_default "wlan-red" "WLAN (red)" "om5pac:red:wifi" "0"
+	ucidef_set_led_default "wlan-yellow" "WLAN (yellow)" "om5pac:yellow:wifi" "0"
+	ucidef_set_led_default "wlan-green" "WLAN (green)" "om5pac:green:wifi" "0"
+	;;
+om5p-acv2)
+	ucidef_set_led_default "wlan-red" "WLAN (red)" "om5pac:red:wifi" "0"
+	ucidef_set_led_default "wlan-yellow" "WLAN (yellow)" "om5pac:yellow:wifi" "0"
+	ucidef_set_led_default "wlan-green" "WLAN (green)" "om5pac:green:wifi" "0"
+	;;
+omy-g1)
+	ucidef_set_led_wlan "wlan" "WLAN" "omy:green:wlan" "phy0tpt"
+	ucidef_set_led_netdev "wan" "WAN" "omy:green:wan" "eth0"
+	ucidef_set_led_netdev "lan" "LAN" "omy:green:lan" "eth1"
+	;;
+omy-x1)
+	ucidef_set_led_default "power" "POWER" "omy:green:power" "1"
+	ucidef_set_led_default "wan" "WAN" "omy:green:wan" "eth0"
+	;;
+qihoo-c301)
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "qihoo:red:status" "phy1tpt"
+	;;
+smart-300)
+	ucidef_set_led_netdev "wan" "WAN" "nc-link:green:wan" "eth0"
+	ucidef_set_led_switch "lan1" "LAN1" "nc-link:green:lan1" "switch0" "0x04"
+	ucidef_set_led_switch "lan2" "LAN2" "nc-link:green:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "nc-link:green:lan3" "switch0" "0x10"
+	ucidef_set_led_switch "lan4" "LAN4" "nc-link:green:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "nc-link:green:wlan" "phy0tpt"
+	;;
+som9331)
+	ucidef_set_led_netdev "wan" "WAN" "$board:orange:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "$board:orange:lan1" "switch0" "0x08"
+	ucidef_set_led_switch "lan2" "LAN2" "$board:orange:lan2" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:red:wlan" "phy0tpt"
+	ucidef_set_led_usbdev "usb" "USB" "$board:green:system" "1-1"
+	;;
+tellstick-znet-lite)
+	ucidef_set_led_netdev "lan_act" "LANACT" "tellstick:green:lan" "eth0" "tx rx"
+	ucidef_set_led_netdev "lan_link" "LANLINK" "tellstick:orange:lan" "eth0" "link"
+	;;
+tew-712br)
+	ucidef_set_led_netdev "wan" "WAN" "trendnet:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "trendnet:green:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2" "LAN2" "trendnet:green:lan2" "switch0" "0x04"
+	ucidef_set_led_switch "lan3" "LAN3" "trendnet:green:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4" "LAN4" "trendnet:green:lan4" "switch0" "0x10"
+	ucidef_set_led_wlan "wlan" "WLAN" "trendnet:green:wlan" "phy0tpt"
+	;;
+tew-732br)
+	ucidef_set_led_netdev "wan" "WAN" "trendnet:green:wan" "eth1"
+	;;
+tew-823dru)
+	ucidef_set_led_netdev "wan" "WAN" "trendnet:green:planet" "eth0"
+	;;
+tl-mr11u|\
+tl-mr3020|\
+tl-mr3040|\
+tl-mr3040-v2)
+	ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan" "eth0"
+	;;
+tl-mr3220|\
+tl-mr3420)
+	ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
+	;;
+tl-mr3220-v2|\
+tl-wr741nd-v4)
+	ucidef_set_led_netdev "wan" "WAN" "tp-link:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x04"
+	ucidef_set_led_switch "lan2" "LAN2" "tp-link:green:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "tp-link:green:lan3" "switch0" "0x10"
+	ucidef_set_led_switch "lan4" "LAN4" "tp-link:green:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+
+	case "$board" in
+	tl-mr3220-v2)
+		ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
+		;;
+	esac
+	;;
+tl-mr3420-v2|\
+tl-wr841n-v8|\
+tl-wr842n-v2|\
+tl-wr941nd-v5)
+	ucidef_set_led_netdev "wan" "WAN" "tp-link:green:wan" "eth0"
+	ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x04"
+	ucidef_set_led_switch "lan2" "LAN2" "tp-link:green:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "tp-link:green:lan3" "switch0" "0x10"
+	ucidef_set_led_switch "lan4" "LAN4" "tp-link:green:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+
+	case "$board" in
+	tl-wr842n-v2|\
+	tl-mr3420-v2)
+		ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
+		;;
+	esac
+	;;
+tl-wa7210n-v2)
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan" "eth0"
+	ucidef_set_rssimon "wlan0" "200000" "1"
+	ucidef_set_led_rssi "rssilow" "RSSILOW" "tp-link:green:signal1" "wlan0" "1" "100" "0" "13"
+	ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "tp-link:green:signal2" "wlan0" "26" "100" "-25" "13"
+	ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "tp-link:green:signal3" "wlan0" "51" "100" "-50" "13"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "tp-link:green:signal4" "wlan0" "76" "100" "-75" "13"
+	;;
+tl-wa750re)
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:orange:lan" "eth0"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:orange:wlan" "phy0tpt"
+	ucidef_set_rssimon "wlan0" "200000" "1"
+	ucidef_set_led_rssi "rssilow" "RSSILOW" "tp-link:orange:signal1" "wlan0" "1" "100" "0" "13"
+	ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "tp-link:orange:signal2" "wlan0" "20" "100" "-19" "13"
+	ucidef_set_led_rssi "rssimedium" "RSSIMEDIUM" "tp-link:orange:signal3" "wlan0" "40" "100" "-39" "13"
+	ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "tp-link:orange:signal4" "wlan0" "60" "100" "-59" "13"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "tp-link:orange:signal5" "wlan0" "80" "100" "-79" "13"
+	;;
+tl-wa801nd-v3)
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan" "eth1"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+	;;
+tl-wa850re)
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:blue:lan" "eth0"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:blue:wlan" "phy0tpt"
+	ucidef_set_rssimon "wlan0" "200000" "1"
+	ucidef_set_led_rssi "rssilow" "RSSILOW" "tp-link:blue:signal1" "wlan0" "1" "100" "0" "13"
+	ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "tp-link:blue:signal2" "wlan0" "20" "100" "-19" "13"
+	ucidef_set_led_rssi "rssimedium" "RSSIMEDIUM" "tp-link:blue:signal3" "wlan0" "40" "100" "-39" "13"
+	ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "tp-link:blue:signal4" "wlan0" "60" "100" "-59" "13"
+	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "tp-link:blue:signal5" "wlan0" "80" "100" "-79" "13"
+	;;
+tl-wa701nd-v2|\
+tl-wa860re|\
+tl-wa830re-v2|\
+tl-wa801nd-v2|\
+tl-wa901nd-v3|\
+tl-wa901nd-v4)
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan" "eth0"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+	;;
+tl-wa901nd)
+	ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan" "eth0"
+	;;
+tl-wa901nd-v2|\
+tl-wr941nd|\
+tl-wr1041n-v2)
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+	;;
+tl-wdr3320-v2)
+	ucidef_set_led_wlan "wlan5g" "WLAN5G" "tp-link:green:wlan5g" "phy0tpt"
+	;;
+tl-wdr3500)
+	ucidef_set_led_usbdev "usb" "USB" "tp-link:green:usb" "1-1"
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "tp-link:green:wlan2g" "phy0tpt"
+	;;
+tl-wdr4300)
+	ucidef_set_led_usbdev "usb1" "USB1" "tp-link:green:usb1" "1-1.1"
+	ucidef_set_led_usbdev "usb2" "USB2" "tp-link:green:usb2" "1-1.2"
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "tp-link:blue:wlan2g" "phy0tpt"
+	;;
+tl-wdr4900-v2)
+	ucidef_set_led_usbdev "usb1" "USB1" "tp-link:green:usb1" "1-1"
+	ucidef_set_led_usbdev "usb2" "USB2" "tp-link:green:usb2" "2-1"
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "tp-link:blue:wlan2g" "phy0tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN5G" "tp-link:blue:wlan5g" "phy1tpt"
+	;;
+tl-wdr6500-v2|\
+tl-wr741nd)
+	ucidef_set_led_netdev "wan" "WAN" "tp-link:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2" "LAN2" "tp-link:green:lan2" "switch0" "0x04"
+	ucidef_set_led_switch "lan3" "LAN3" "tp-link:green:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4" "LAN4" "tp-link:green:lan4" "switch0" "0x10"
+	;;
+archer-c5|\
+archer-c7)
+	ucidef_set_led_usbdev "usb1" "USB1" "tp-link:green:usb1" "1-1"
+	ucidef_set_led_usbdev "usb2" "USB2" "tp-link:green:usb2" "2-1"
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "tp-link:blue:wlan2g" "phy1tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN5G" "tp-link:blue:wlan5g" "phy0tpt"
+	;;
+tl-wpa8630)
+	ucidef_set_led_netdev "lan" "LAN" "$board:green:lan" "eth0"
+	ucidef_set_led_netdev "wlan" "WLAN" "$board:green:wlan" "wlan1"
+	ucidef_set_led_netdev "wlan5" "WLAN5" "$board:green:wlan5" "wlan0"
+	;;
+tl-wr802n-v1)
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:blue:system" "phy0tpt"
+	;;
+tl-wr941nd-v6)
+	ucidef_set_led_netdev "wan" "WAN" "tp-link:blue:wan" "eth0"
+	ucidef_set_led_switch "lan1" "LAN1" "tp-link:blue:lan1" "switch0" "0x10"
+	ucidef_set_led_switch "lan2" "LAN2" "tp-link:blue:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "tp-link:blue:lan3" "switch0" "0x04"
+	ucidef_set_led_switch "lan4" "LAN4" "tp-link:blue:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:blue:wlan" "phy0tpt"
+	;;
+tl-wr841n-v9|\
+tl-wr841n-v11|\
+tl-wr842n-v3)
+	ucidef_set_led_netdev "wan" "WAN" "tp-link:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
+	ucidef_set_led_switch "lan2" "LAN2" "tp-link:green:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "tp-link:green:lan3" "switch0" "0x04"
+	ucidef_set_led_switch "lan4" "LAN4" "tp-link:green:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+
+	case "$board" in
+	tl-wr842n-v3)
+		ucidef_set_led_usbdev "usb" "USB" "tp-link:green:3g" "1-1"
+		;;
+	esac
+	;;
+tl-wr1043nd|\
+tl-wr1043nd-v2)
+	ucidef_set_led_usbdev "usb" "USB" "tp-link:green:usb" "1-1"
+	ucidef_set_led_wlan "wlan" "WLAN" "tp-link:green:wlan" "phy0tpt"
+	;;
+tl-wr2543n)
+	ucidef_set_led_usbdev "usb" "USB" "tp-link:green:usb" "1-1"
+	;;
+tube2h)
+	ucidef_set_led_netdev "lan" "LAN" "alfa:blue:lan" "eth0"
+	ucidef_set_rssimon "wlan0" "200000" "1"
+	ucidef_set_led_rssi "signal1" "SIGNAL1" "alfa:red:signal1" "wlan0" "1" "100" "0" "13"
+	ucidef_set_led_rssi "signal2" "SIGNAL2" "alfa:orange:signal2" "wlan0" "26" "100" "-25" "13"
+	ucidef_set_led_rssi "signal3" "SIGNAL3" "alfa:green:signal3" "wlan0" "51" "100" "-50" "13"
+	ucidef_set_led_rssi "signal4" "SIGNAL4" "alfa:green:signal4" "wlan0" "76" "100" "-75" "13"
+	;;
+wndap360)
+	ucidef_set_led_power "power" "POWER GREEN" "netgear:green:power" "1"
+	;;
+wndr3700)
+	ucidef_set_led_default "wan" "WAN LED (green)" "netgear:green:wan" "0"
+	ucidef_set_led_usbdev "usb" "USB" "netgear:green:usb" "1-1"
+	;;
+r6100)
+	ucidef_set_led_netdev "wan" "WAN (green)" "netgear:green:wan" "eth0"
+	ucidef_set_led_usbdev "usb" "USB" "netgear:blue:usb" "1-1"
+	ucidef_set_led_wlan "wlan" "WLAN" "netgear:blue:wlan" "phy1tpt"
+	;;
+wndr3700v4|\
+wndr4300)
+	ucidef_set_led_netdev "wan" "WAN (green)" "netgear:green:wan" "eth0.2"
+	ucidef_set_led_usbdev "usb" "USB" "netgear:green:usb" "1-1"
+	ucidef_set_led_wlan "wlan2g" "WLAN2G" "netgear:green:wlan2g" "phy0tpt"
+	ucidef_set_led_wlan "wlan5g" "WLAN5G" "netgear:blue:wlan5g" "phy1tpt"
+	;;
+whr-g301n|\
+whr-hp-g300n|\
+whr-hp-gn)
+	ucidef_set_led_netdev "wan" "WAN" "buffalo:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "buffalo:green:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2" "LAN2" "buffalo:green:lan2" "switch0" "0x04"
+	ucidef_set_led_switch "lan3" "LAN3" "buffalo:green:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4" "LAN4" "buffalo:green:lan4" "switch0" "0x10"
+	;;
+wlae-ag300n)
+	ucidef_set_led_netdev "wireless" "WIRELESS" "buffalo:green:wireless" "wlan0"
+	;;
+wnr1000-v2|\
+wnr2000-v3)
+	ucidef_set_led_netdev "wan-amber" "WAN (amber)" "netgear:amber:wan" "eth0"
+	ucidef_set_led_default "wan-green" "WAN (green)" "netgear:green:wan" "0"
+	ucidef_set_led_netdev "wlan" "WLAN" "netgear:blue:wlan" "wlan0"
+	ucidef_set_led_switch "lan1green" "LAN1 (green)" "netgear:green:lan1" "switch0" "0x02" "0x04"
+	ucidef_set_led_switch "lan2green" "LAN2 (green)" "netgear:green:lan2" "switch0" "0x04" "0x04"
+	ucidef_set_led_switch "lan3green" "LAN3 (green)" "netgear:green:lan3" "switch0" "0x08" "0x04"
+	ucidef_set_led_switch "lan4green" "LAN4 (green)" "netgear:green:lan4" "switch0" "0x10" "0x04"
+	ucidef_set_led_switch "lan1amber" "LAN1 (amber)" "netgear:amber:lan1" "switch0" "0x02" "0x02"
+	ucidef_set_led_switch "lan2amber" "LAN2 (amber)" "netgear:amber:lan2" "switch0" "0x04" "0x02"
+	ucidef_set_led_switch "lan3amber" "LAN3 (amber)" "netgear:amber:lan3" "switch0" "0x08" "0x02"
+	ucidef_set_led_switch "lan4amber" "LAN4 (amber)" "netgear:amber:lan4" "switch0" "0x10" "0x02"
+	;;
+wnr2000-v4)
+	ucidef_set_led_netdev "wan" "WAN" "netgear:green:wan" "eth0"
+	ucidef_set_led_netdev "wlan" "WLAN" "netgear:blue:wlan" "wlan0"
+	ucidef_set_led_switch "lan1" "LAN1" "netgear:amber:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2" "LAN2" "netgear:amber:lan2" "switch0" "0x04"
+	ucidef_set_led_switch "lan3" "LAN3" "netgear:amber:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4" "LAN4" "netgear:amber:lan4" "switch0" "0x10"
+	ucidef_set_led_usbdev "usb" "USB" "netgear:amber:status" "1-1"
+	;;
+wnr2200)
+	ucidef_set_led_netdev "wan-amber" "WAN (amber)" "netgear:amber:wan" "eth0"
+	ucidef_set_led_default "wan-green" "WAN (green)" "netgear:green:wan" "0"
+	ucidef_set_led_netdev "wlan" "WLAN" "netgear:blue:wlan" "wlan0"
+	ucidef_set_led_switch "lan1green" "LAN1 (green)" "netgear:green:lan1" "switch0" "0x02" "0x04"
+	ucidef_set_led_switch "lan2green" "LAN2 (green)" "netgear:green:lan2" "switch0" "0x04" "0x04"
+	ucidef_set_led_switch "lan3green" "LAN3 (green)" "netgear:green:lan3" "switch0" "0x08" "0x04"
+	ucidef_set_led_switch "lan4green" "LAN4 (green)" "netgear:green:lan4" "switch0" "0x10" "0x04"
+	ucidef_set_led_switch "lan1amber" "LAN1 (amber)" "netgear:amber:lan1" "switch0" "0x02" "0x02"
+	ucidef_set_led_switch "lan2amber" "LAN2 (amber)" "netgear:amber:lan2" "switch0" "0x04" "0x02"
+	ucidef_set_led_switch "lan3amber" "LAN3 (amber)" "netgear:amber:lan3" "switch0" "0x08" "0x02"
+	ucidef_set_led_switch "lan4amber" "LAN4 (amber)" "netgear:amber:lan4" "switch0" "0x10" "0x02"
+	ucidef_set_led_usbdev "usb" "USB" "netgear:green:usb" "1-1"
+	;;
+wnr612-v2)
+	ucidef_set_led_netdev "wan" "WAN" "netgear:green:wan" "eth0"
+	ucidef_set_led_netdev "wlan" "WLAN" "netgear:green:wlan" "wlan0"
+	ucidef_set_led_switch "lan1" "LAN1" "netgear:green:lan1" "switch0" "0x02" "0x0f"
+	ucidef_set_led_switch "lan2" "LAN2" "netgear:green:lan2" "switch0" "0x04" "0x0f"
+	;;
+wpn824n)
+	ucidef_set_led_netdev "wan-amber" "WAN (amber)" "netgear:amber:wan" "eth0"
+	ucidef_set_led_wlan "wlan" "WLAN" "netgear:blue:wlan" "phy0tpt"
+	ucidef_set_led_switch "lan1amber" "LAN1 (amber)" "netgear:amber:lan1" "switch0" "0x02"
+	ucidef_set_led_switch "lan2amber" "LAN2 (amber)" "netgear:amber:lan2" "switch0" "0x04"
+	ucidef_set_led_switch "lan3amber" "LAN3 (amber)" "netgear:amber:lan3" "switch0" "0x08"
+	ucidef_set_led_switch "lan4amber" "LAN4 (amber)" "netgear:amber:lan4" "switch0" "0x10"
+	ucidef_set_led_default "lan1green" "LAN1 (green)" "netgear:green:lan1" "0"
+	ucidef_set_led_default "lan2green" "LAN2 (green)" "netgear:green:lan2" "0"
+	ucidef_set_led_default "lan3green" "LAN3 (green)" "netgear:green:lan3" "0"
+	ucidef_set_led_default "lan4green" "LAN4 (green)" "netgear:green:lan4" "0"
+	ucidef_set_led_default "wan-green" "WAN (green)" "netgear:green:wan" "0"
+	ucidef_set_led_default "wps1" "WPS1" "netgear:blue:wps1" "0"
+	ucidef_set_led_default "wps2" "WPS2" "netgear:blue:wps2" "0"
+	ucidef_set_led_default "status" "STATUS" "netgear:amber:status" "0"
+	ucidef_set_led_default "test" "TEST" "netgear:amber:test" "0"
+	;;
+wzr-hp-ag300h)
+	ucidef_set_led_default "diag" "DIAG" "buffalo:red:diag" "0"
+	ucidef_set_led_netdev "router" "ROUTER" "buffalo:green:router" "eth1"
+	ucidef_set_led_usbdev "usb" "USB" "buffalo:green:usb" "1-1"
+	;;
+wzr-hp-g300nh)
+	ucidef_set_led_wlan "wlan" "Wireless" "buffalo:green:wireless" "phy0tpt"
+	ucidef_set_led_netdev "router" "Router" "buffalo:green:router" "eth1"
+	ucidef_set_led_usbdev "usb" "USB" "buffalo:blue:usb" "1-1"
+	;;
+z1)
+	ucidef_set_led_netdev "wlan1" "WLAN1" "$board:blue:tricolor0" "wlan1"
+	;;
+zbt-we1526)
+	ucidef_set_led_netdev "wan" "WAN" "$board:green:wan" "eth1"
+	ucidef_set_led_switch "lan1" "LAN1" "$board:green:lan1" "switch0" "0x10"
+	ucidef_set_led_switch "lan2" "LAN2" "$board:green:lan2" "switch0" "0x08"
+	ucidef_set_led_switch "lan3" "LAN3" "$board:green:lan3" "switch0" "0x04"
+	ucidef_set_led_switch "lan4" "LAN4" "$board:green:lan4" "switch0" "0x02"
+	ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
+	;;
+zcn-1523h-2)
+	ucidef_set_led_netdev "lan1" "lan1" "zcn-1523h:green:lan1" "eth0"
+	;;
+zcn-1523h-5)
+	ucidef_set_led_netdev "lan1" "lan1" "zcn-1523h:green:lan1" "eth0"
+	ucidef_set_led_netdev "lan2" "lan2" "zcn-1523h:green:lan2" "eth1"
+	;;
+esac
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/ar71xx/base-files/etc/board.d/02_network b/target/linux/ar71xx/base-files/etc/board.d/02_network
new file mode 100755
index 0000000000..949f161c9c
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/board.d/02_network
@@ -0,0 +1,477 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2015 OpenWrt.org
+#
+
+. /lib/functions/system.sh
+. /lib/functions/uci-defaults.sh
+. /lib/ar71xx.sh
+
+ar71xx_setup_interfaces()
+{
+	local board="$1"
+
+	case "$board" in
+	airgatewaypro)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "4:lan" "5:wan"
+		;;
+	airrouter|\
+	ap121|\
+	ap121-mini|\
+	ap96|\
+	dir-600-a1|\
+	dir-615-c1|\
+	dir-615-e1|\
+	dir-615-e4|\
+	hiwifi-hc6361|\
+	ja76pf|\
+	mc-mac1200r|\
+	minibox-v1|\
+	mynet-n600|\
+	oolite|\
+	qihoo-c301|\
+	rb-750|\
+	rb-751|\
+	som9331|\
+	tew-632brp|\
+	tew-712br|\
+	tew-732br|\
+	tl-mr3220|\
+	tl-mr3220-v2|\
+	tl-mr3420|\
+	tl-wdr3320-v2|\
+	tl-wdr3500|\
+	tl-wr741nd|\
+	tl-wr741nd-v4|\
+	tl-wr841n-v11|\
+	tl-wr841n-v7|\
+	tl-wr841n-v9|\
+	tl-wr842n-v3|\
+	whr-g301n|\
+	whr-hp-g300n|\
+	whr-hp-gn|\
+	wzr-hp-ag300h|\
+	zbt-we1526)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1"
+		;;
+	alfa-ap120c|\
+	all0305|\
+	antminer-s1|\
+	antminer-s3|\
+	antrouter-r1|\
+	aw-nr580|\
+	bullet-m|\
+	c-55|\
+	cap4200ag|\
+	cf-e380ac-v1|\
+	cf-e380ac-v2|\
+	eap120|\
+	eap300v2|\
+	eap7660d|\
+	el-mini|\
+	loco-m-xw|\
+	mr12|\
+	mr16|\
+	mr1750|\
+	mr1750v2|\
+	mr18|\
+	mr600|\
+	mr600v2|\
+	mr900|\
+	mr900v2|\
+	mynet-rext|\
+	rb-411|\
+	rb-911g-2hpnd|\
+	rb-911g-5hpacd|\
+	rb-911g-5hpnd|\
+	rb-912uag-2hpnd|\
+	rb-912uag-5hpnd|\
+	rb-sxt2n|\
+	rb-sxt5n|\
+	rocket-m-xw|\
+	tl-mr10u|\
+	tl-mr11u|\
+	tl-mr12u|\
+	tl-mr13u|\
+	tl-mr3020|\
+	tl-mr3040|\
+	tl-mr3040-v2|\
+	tl-wa701nd-v2|\
+	tl-wa7210n-v2|\
+	tl-wa750re|\
+	tl-wa801nd-v2|\
+	tl-wa830re-v2|\
+	tl-wa850re|\
+	tl-wa901nd|\
+	tl-wa901nd-v2|\
+	tl-wa901nd-v3|\
+	tl-wa901nd-v4|\
+	tl-wr703n|\
+	tl-wr802n-v1|\
+	tube2h|\
+	unifiac-lite|\
+	wndap360|\
+	wp543)
+		ucidef_set_interface_lan "eth0"
+		;;
+	alfa-ap96|\
+	alfa-nx|\
+	ap83|\
+	gl-ar150|\
+	gl-ar300m|\
+	gl-domino|\
+	gl-inet|\
+	gl-mifi|\
+	jwap003|\
+	pb42|\
+	pb44|\
+	rb-951ui-2hnd|\
+	routerstation|\
+	tl-wr710n|\
+	tl-wr720n-v3|\
+	tl-wr810n|\
+	wpe72|\
+	wrtnode2q)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		;;
+	all0258n|\
+	all0315n|\
+	dlan-hotspot|\
+	dlan-pro-500-wp|\
+	dr344|\
+	ja76pf2|\
+	rocket-m-ti|\
+	ubnt-unifi-outdoor)
+		ucidef_set_interface_lan "eth0 eth1"
+		;;
+	ap113|\
+	pb92|\
+	wzr-hp-g300nh2)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan:1" "3:lan:2" "4:lan:3" "5:lan:4" "2:wan"
+		;;
+	ap132|\
+	ap136|\
+	ap152|\
+	rb-750gl|\
+	rb-751g|\
+	rb-951g-2hnd|\
+	wlr8100|\
+	wzr-hp-g450h)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan" "3:lan" "4:lan" "5:lan" "1:wan"
+		;;
+	ap135-020|\
+	ap136-020|\
+	bhr-4grv2|\
+	tew-823dru|\
+	tl-wr1043nd-v2|\
+	wzr-450hp2)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "5:wan" "6@eth0"
+		;;
+	ap136-010|\
+	ap147-010|\
+	nbg6616|\
+	nbg6716)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan" "6@eth1"
+		;;
+	ap143|\
+	rb-433|\
+	rb-433u)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"1:lan" "2:lan" "5@eth1"
+		;;
+	archer-c5|\
+	archer-c7|\
+	tl-wdr4900-v2)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "2:lan" "3:lan" "4:lan" "5:lan" "6@eth0" "1:wan"
+		;;
+	arduino-yun|\
+	dir-505-a1|\
+	tl-wa801nd-v3)
+		ucidef_set_interface_lan "eth1"
+		;;
+	bsb)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "1:lan" "3:lan"
+		;;
+	c-60)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "3:wan" "4:lan"
+		;;
+	cap324)
+		ucidef_set_interface_lan "eth0" "dhcp"
+		;;
+	cpe210|\
+	cpe510)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "5:lan" "4:wan"
+		;;
+	cr3000)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan:1" "2:lan:4" "3:lan:3" "4:lan:2"
+		;;
+	cr5000|\
+	dgl-5500-a1|\
+	dhp-1565-a1|\
+	dir-825-c1|\
+	dir-835-a1|\
+	esr900|\
+	mynet-n750|\
+	wndr3700v4|\
+	wndr4300)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan"
+		;;
+	dap-2695-a1)
+		ucidef_add_switch "switch0" "0@eth0" "2:lan" "3:wan" "6@eth1"
+		;;
+	db120|\
+	rb-2011l|\
+	rb-2011uas|\
+	rb-2011uas-2hnd|\
+	rb-2011uias|\
+	rb-2011uias-2hnd)
+		case "$board" in
+		rb-2011uas*|\
+		rb-2011uias|\
+		rb-2011uias-2hnd)
+			ucidef_add_switch "switch0" \
+				"0@eth0" "2:lan" "3:lan" "4:lan" "5:lan" "1:wan" "6:sfp"
+		;;
+		*)
+			ucidef_add_switch "switch0" \
+				"0@eth0" "2:lan" "3:lan" "4:lan" "5:lan" "1:wan"
+		;;
+		esac
+
+		ucidef_add_switch "switch1" \
+			"0@eth1" "1:lan" "2:lan" "3:lan" "4:lan" "5:lan"
+		;;
+	dir-615-i1|\
+	omy-g1|\
+	r6100|\
+	smart-300|\
+	tl-mr3420-v2|\
+	tl-wdr6500-v2|\
+	tl-wr841n-v8|\
+	tl-wr842n-v2|\
+	tl-wr941nd-v5|\
+	tl-wr941nd-v6|\
+	wnr1000-v2|\
+	wnr2000-v3|\
+	wnr2000-v4|\
+	wnr2200|\
+	wnr612-v2|\
+	wpn824n)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0:lan:4" "1:lan:3" "2:lan:2" "3:lan:1" "4@eth1"
+		;;
+	dir-825-b1|\
+	nbg460n_550n_550nh|\
+	tew-673gru|\
+	wzr-hp-g300nh)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0:lan" "1:lan" "2:lan" "3:lan" "5@eth0"
+		;;
+	dlan-pro-1200-ac)
+		ucidef_set_interface_lan "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan" "3:lan" "4:lan"
+		ucidef_add_switch_attr "switch0" "enable" "false"
+		;;
+	el-m150)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0:lan" "1:lan" "3@eth1"
+		;;
+	dir-869-a1|\
+	epg5000|\
+	esr1750)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "5:wan"
+		;;
+	ew-dorin)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan" "2:lan" "3:wan"
+		;;
+	ew-dorin-router)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan" "3:lan"
+		;;
+	dw33d|\
+	f9k1115v2)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"2:lan" "3:lan" "4:lan" "5:lan" "6@eth1" "0@eth0" "1:wan"
+		;;
+	gl-ar300)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "1:lan" "2:lan" "3:lan" "4:lan"
+		;;
+	jwap230)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan" "5:wan" "6@eth1"
+		;;
+	nanostation-m-xw)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "5:lan" "1:wan"
+		;;
+	onion-omega)
+		ucidef_set_interface_lan "wlan0"
+		;;
+	rb-435g)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "1:lan" "2:lan"
+		;;
+	rb-450)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0:lan:4" "1:lan:3" "2:lan:2" "3:lan:1" "5@eth1"
+		;;
+	rb-450g)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "1:lan:1" "2:lan:4" "3:lan:3" "4:lan:2"
+		;;
+	routerstation-pro)
+		ucidef_set_interfaces_lan_wan "eth1" "eth0"
+		ucidef_add_switch "switch0" \
+			"0@eth1" "2:lan:3" "3:lan:2" "4:lan:1"
+		;;
+	rb-493g)
+		ucidef_set_interfaces_lan_wan "eth0 eth1.1" "eth1.2"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan" "2:lan" "3:lan" "4:lan"
+		ucidef_add_switch "switch1" \
+			"0@eth1" "1:lan" "2:lan" "3:lan" "4:lan" "5:wan"
+		;;
+	tellstick-znet-lite)
+		ucidef_set_interface_wan "eth0"
+		ucidef_set_interface_raw "wlan" "wlan0" "dhcp"
+		;;
+	tl-wdr4300|\
+	tl-wr1041n-v2)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan:1" "3:lan:2" "4:lan:3" "5:lan:4" "1:wan"
+		;;
+	tl-wpa8630)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan:3" "3:lan:2" "4:lan:1" "5:lan:4"
+		;;
+	tl-wr1043nd)
+		ucidef_add_switch "switch0" \
+			"1:lan" "2:lan" "3:lan" "4:lan" "0:wan" "5@eth0"
+		;;
+	tl-wr2543n)
+		ucidef_add_switch "switch0" \
+			"1:lan" "2:lan" "3:lan" "4:lan" "0:wan" "9@eth0"
+		;;
+	tl-wr841n-v1|\
+	tl-wr941nd)
+		ucidef_set_interface_raw "eth" "eth0"
+		ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan"
+		;;
+	uap-pro|\
+	wpj342)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan" "2:wan"
+		;;
+	unifiac-pro)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan" "3:wan"
+		;;
+	wndr3700)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0:lan" "1:lan" "2:lan" "3:lan" "5@eth0"
+
+		ucidef_add_switch_attr "switch0" "blinkrate" 2
+		ucidef_add_switch_port_attr "switch0" 1 led 6
+		ucidef_add_switch_port_attr "switch0" 2 led 9
+		ucidef_add_switch_port_attr "switch0" 5 led 2
+		;;
+	wpj344)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "3:lan" "2:wan"
+		;;
+	wpj558)
+		ucidef_add_switch "switch0" \
+			"5:lan" "1:wan" "6@eth0"
+		;;
+	wrt160nl)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0:lan:4" "1:lan:3" "2:lan:2" "3:lan:1" "4@eth0"
+		;;
+	wzr-hp-g450h)
+		ucidef_add_switch "switch0" \
+			"0@eth0" "2:lan:1 3:lan:2 4:lan:3 5:lan:4" "1:wan"
+		;;
+	z1)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		ucidef_add_switch "switch0" \
+			"0@eth0" "1:lan:1" "2:lan:2" "3:lan:3" "4:lan:4" "5:wan"
+		;;
+	*)
+		ucidef_set_interfaces_lan_wan "eth0" "eth1"
+		;;
+	esac
+}
+
+ar71xx_setup_macs()
+{
+	local board="$1"
+	local lan_mac=""
+	local wan_mac=""
+
+	case $board in
+	dgl-5500-a1|\
+	dir-825-c1)
+		wan_mac=$(mtd_get_mac_ascii nvram "wan_mac")
+		;;
+	dhp-1565-a1|\
+	dir-835-a1|\
+	wndr3700v4|\
+	wndr4300)
+		lan_mac=$(mtd_get_mac_binary caldata 0)
+		wan_mac=$(mtd_get_mac_binary caldata 6)
+		;;
+	esr900)
+		wan_mac=$(mtd_get_mac_ascii u-boot-env "wanaddr")
+		;;
+	dir-869-a1|\
+	mynet-n750)
+		wan_mac=$(mtd_get_mac_ascii devdata "wanmac")
+		;;
+	esac
+
+	[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
+	[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac
+}
+
+board_config_update
+board=$(ar71xx_board_name)
+ar71xx_setup_interfaces $board
+ar71xx_setup_macs $board
+board_config_flush
+
+exit 0
diff --git a/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches b/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches
new file mode 100755
index 0000000000..5b95f155cf
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/board.d/03_gpio_switches
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+
+. /lib/functions/uci-defaults.sh
+. /lib/ar71xx.sh
+
+board_config_update
+
+board=$(ar71xx_board_name)
+
+case "$board" in
+nanostation-m)
+	ucidef_add_gpio_switch "poe_passthrough" "PoE Passthrough" "8"
+	;;
+nanostation-m-xw)
+	ucidef_add_gpio_switch "poe_passthrough" "PoE Passthrough" "2"
+	;;
+cpe210|\
+cpe510)
+	ucidef_add_gpio_switch "poe_passthrough" "PoE Passthrough" "20"
+	;;
+rb-912uag-2hpnd|\
+rb-912uag-5hpnd)
+	ucidef_add_gpio_switch "usb_power_switch" "USB Power Switch" "52"
+	;;
+esac
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh
new file mode 100644
index 0000000000..9b9aea8a77
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/diag.sh
@@ -0,0 +1,475 @@
+#!/bin/sh
+# Copyright (C) 2009-2013 OpenWrt.org
+
+. /lib/functions/leds.sh
+. /lib/ar71xx.sh
+
+get_status_led() {
+	local board=$(ar71xx_board_name)
+
+	case $board in
+	alfa-nx)
+		status_led="alfa:green:led_8"
+		;;
+	all0305)
+		status_led="eap7660d:green:ds4"
+		;;
+	antminer-s1|\
+	antminer-s3|\
+	antminer-r1|\
+	minibox-v1|\
+	som9331)
+		status_led="$board:green:system"
+		;;
+	ap132|\
+	ap81|\
+	db120|\
+	dr344|\
+	tew-632brp|\
+	wpj344|\
+	zbt-we1526)
+		status_led="$board:green:status"
+		;;
+	ap136-010|\
+	ap136-020)
+		status_led="ap136:green:status"
+		;;
+	ap147-010)
+		status_led="ap147:green:status"
+		;;
+	ap135-020)
+		status_led="ap135:green:status"
+		;;
+	ap83|\
+	mr12|\
+	mr16|\
+	nbg6616|\
+	tl-wpa8630)
+		status_led="$board:green:power"
+		;;
+	ap90q|\
+	cpe830|\
+	cpe870|\
+	gl-inet)
+		status_led="$board:green:lan"
+		;;
+	ap96)
+		status_led="$board:green:led2"
+		;;
+	aw-nr580)
+		status_led="$board:green:ready"
+		;;
+	bhr-4grv2|\
+	wzr-hp-ag300h|\
+	wzr-hp-g300nh2)
+		status_led="buffalo:red:diag"
+		;;
+	bsb)
+		status_led="$board:red:sys"
+		;;
+	bullet-m|\
+	rocket-m|\
+	rocket-m-xw|\
+	nano-m|\
+	nanostation-m|\
+	nanostation-m-xw|\
+	loco-m-xw)
+		status_led="ubnt:green:link4"
+		;;
+	rocket-m-ti)
+		status_led="ubnt:green:link6"
+		;;
+	bxu2000n-2-a1)
+		status_led="bhu:green:status"
+		;;
+	cap324)
+		status_led="pcs:green:power"
+		;;
+	c-55|\
+	c-60)
+		status_led="$board:green:pwr"
+		;;
+	cap4200ag)
+		status_led="senao:green:pwr"
+		;;
+	cf-e316n-v2|\
+	cf-e520n|\
+	cf-e530n)
+		status_led="$board:blue:wan"
+		;;
+	cf-e320n-v2)
+		status_led="$board:blue:wlan"
+		;;
+	cf-e380ac-v1|\
+	cf-e380ac-v2)
+		status_led="$board:blue:wlan2g"
+		;;
+	cpe510)
+		status_led="tp-link:green:link4"
+		;;
+	cr3000)
+		status_led="pcs:amber:power"
+		;;
+	cr5000)
+		status_led="pcs:amber:power"
+		;;
+	dgl-5500-a1|\
+	dhp-1565-a1|\
+	dir-505-a1|\
+	dir-600-a1|\
+	dir-615-e1|\
+	dir-615-i1|\
+	dir-615-e4)
+		status_led="d-link:green:power"
+		;;
+	dir-615-c1)
+		status_led="d-link:green:status"
+		;;
+	dir-825-b1)
+		status_led="d-link:orange:power"
+		;;
+	dir-825-c1|\
+	dir-835-a1)
+		status_led="d-link:amber:power"
+		;;
+	dir-869-a1)
+		status_led="d-link:white:status"
+		;;
+	dlan-hotspot)
+		status_led="devolo:green:wifi"
+		;;
+	dlan-pro-500-wp)
+		status_led="devolo:green:wlan-2g"
+		;;
+	dlan-pro-1200-ac)
+		status_led="devolo:status:wlan"
+		;;
+	dr531)
+		status_led="$board:green:sig4"
+		;;
+	dragino2|\
+	oolite)
+		status_led="$board:red:system"
+		;;
+	dw33d)
+		status_led="$board:blue:status"
+		;;
+	eap120)
+		status_led="$(ar71xx_board_name):green:system"
+		;;
+	eap300v2)
+		status_led="engenius:blue:power"
+		;;
+	eap7660d)
+		status_led="$board:green:ds4"
+		;;
+	el-mini|\
+	el-m150)
+		status_led="easylink:green:system"
+		;;
+	ew-dorin|\
+	ew-dorin-router)
+		status_led="dorin:green:status"
+		;;
+	f9k1115v2)
+		status_led="belkin:blue:status"
+		;;
+	epg5000|\
+	esr1750)
+		status_led="$board:amber:power"
+		;;
+	esr900)
+		status_led="engenius:amber:power"
+		;;
+	hiwifi-hc6361)
+		status_led="hiwifi:blue:system"
+		;;
+	hornet-ub|\
+	hornet-ub-x2)
+		status_led="alfa:blue:wps"
+		;;
+	ja76pf|\
+	ja76pf2)
+		status_led="jjplus:green:led1"
+		;;
+	jwap230)
+		status_led="$board:green:led1"
+		;;
+	ls-sr71)
+		status_led="ubnt:green:d22"
+		;;
+	mc-mac1200r)
+		status_led="mercury:green:system"
+		;;
+	mr18|\
+	z1)
+		status_led="$board:green:tricolor0"
+		;;
+	mr600)
+		status_led="$board:orange:power"
+		;;
+	mr600v2)
+		status_led="mr600:blue:power"
+		;;
+	mr1750|\
+	mr1750v2)
+		status_led="mr1750:blue:power"
+		;;
+	mr900|\
+	mr900v2)
+		status_led="mr900:blue:power"
+		;;
+	mynet-n600|\
+	mynet-n750)
+		status_led="wd:blue:power"
+		;;
+	mynet-rext)
+		status_led="wd:blue:power"
+		;;
+	mzk-w04nu|\
+	mzk-w300nh)
+		status_led="planex:green:status"
+		;;
+	nbg460n_550n_550nh)
+		status_led="nbg460n:green:power"
+		;;
+	nbg6716)
+		status_led="$board:white:power"
+		;;
+	om2p|\
+	om2pv2|\
+	om2p-hs|\
+	om2p-hsv2|\
+	om2p-hsv3|\
+	om2p-lc)
+		status_led="om2p:blue:power"
+		;;
+	om5p|\
+	om5p-an)
+		status_led="om5p:blue:power"
+		;;
+	om5p-ac|\
+	om5p-acv2)
+		status_led="om5pac:blue:power"
+		;;
+	omy-g1)
+		status_led="omy:green:wlan"
+		;;
+	omy-x1)
+		status_led="omy:green:power"
+		;;
+	onion-omega)
+		status_led="onion:amber:system"
+		;;
+	pb44)
+		status_led="$board:amber:jump1"
+		;;
+	rb-2011l|\
+	rb-2011uas|\
+	rb-2011uas-2hnd)
+		status_led="rb:green:usr"
+		;;
+	rb-411|\
+	rb-411u|\
+	rb-433|\
+	rb-433u|\
+	rb-450|\
+	rb-450g|\
+	rb-493)
+		status_led="rb4xx:yellow:user"
+		;;
+	rb-750)
+		status_led="rb750:green:act"
+		;;
+	rb-911g-2hpnd|\
+	rb-911g-5hpacd|\
+	rb-911g-5hpnd|\
+	rb-912uag-2hpnd|\
+	rb-912uag-5hpnd)
+		status_led="rb:green:user"
+		;;
+	rb-951ui-2hnd)
+		status_led="rb:green:act"
+		;;
+	rb-sxt2n|\
+	rb-sxt5n)
+		status_led="rb:green:power"
+		;;
+	routerstation|\
+	routerstation-pro)
+		status_led="ubnt:green:rf"
+		;;
+	rw2458n)
+		status_led="$board:green:d3"
+		;;
+	smart-300)
+		status_led="nc-link:green:system"
+		;;
+	qihoo-c301)
+		status_led="qihoo:green:status"
+		;;
+	tellstick-znet-lite)
+		status_led="tellstick:white:system"
+		;;
+	tew-673gru)
+		status_led="trendnet:blue:wps"
+		;;
+	tew-712br|\
+	tew-732br|\
+	tew-823dru)
+		status_led="trendnet:green:power"
+		;;
+	tl-mr3020)
+		status_led="tp-link:green:wps"
+		;;
+	tl-wa750re)
+		status_led="tp-link:orange:re"
+		;;
+	tl-wa850re)
+		status_led="tp-link:blue:re"
+		;;
+	tl-wa860re)
+		status_led="tp-link:green:power"
+		;;
+	tl-mr3220|\
+	tl-mr3220-v2|\
+	tl-mr3420|\
+	tl-mr3420-v2|\
+	tl-wa701nd-v2|\
+	tl-wa801nd-v2|\
+	tl-wa901nd|\
+	tl-wa901nd-v2|\
+	tl-wa901nd-v3|\
+	tl-wa901nd-v4|\
+	tl-wdr3320-v2|\
+	tl-wdr3500|\
+	tl-wr1041n-v2|\
+	tl-wr1043nd|\
+	tl-wr1043nd-v2|\
+	tl-wr741nd|\
+	tl-wr741nd-v4|\
+	tl-wa801nd-v3|\
+	tl-wr841n-v1|\
+	tl-wr841n-v7|\
+	tl-wr841n-v8|\
+	tl-wr841n-v11|\
+	tl-wa830re-v2|\
+	tl-wr842n-v2|\
+	tl-wr842n-v3|\
+	tl-wr941nd|\
+	tl-wr941nd-v5)
+		status_led="tp-link:green:system"
+		;;
+	archer-c5|\
+	archer-c7|\
+	tl-wdr4900-v2|\
+	tl-mr10u|\
+	tl-mr12u|\
+	tl-mr13u|\
+	tl-wdr4300|\
+	tl-wr703n|\
+	tl-wr710n|\
+	tl-wr720n-v3|\
+	tl-wr802n-v1|\
+	tl-wr810n|\
+	tl-wr941nd-v6)
+		status_led="tp-link:blue:system"
+		;;
+	tl-wr841n-v9)
+		status_led="tp-link:green:qss"
+		;;
+	tl-wr2543n)
+		status_led="tp-link:green:wps"
+		;;
+	tl-wdr6500-v2)
+		status_led="tp-link:white:system"
+		;;
+	tube2h)
+		status_led="alfa:green:signal4"
+		;;
+	unifi)
+		status_led="ubnt:green:dome"
+		;;
+	uap-pro|\
+	unifiac-lite|\
+	unifiac-pro)
+		status_led="ubnt:white:dome"
+		;;
+	unifi-outdoor-plus)
+		status_led="ubnt:white:front"
+		;;
+	airgateway|\
+	airgatewaypro)
+		status_led="ubnt:white:status"
+		;;
+	whr-g301n|\
+	whr-hp-g300n|\
+	whr-hp-gn|\
+	wzr-hp-g300nh)
+		status_led="buffalo:green:router"
+		;;
+	wlae-ag300n)
+		status_led="buffalo:green:status"
+		;;
+	r6100|\
+	wndap360|\
+	wndr3700|\
+	wndr3700v4|\
+	wndr4300|\
+	wnr2000|\
+	wnr2000-v3|\
+	wnr2200|\
+	wnr612-v2|\
+	wnr1000-v2|\
+	wpn824n)
+		status_led="netgear:green:power"
+		;;
+	wp543)
+		status_led="$board:green:diag"
+		;;
+	wpj342|\
+	wpj531|\
+	wpj558)
+		status_led="$board:green:sig3"
+		;;
+	wrt400n|\
+	wrt160nl)
+		status_led="$board:blue:wps"
+		;;
+	zcn-1523h-2|\
+	zcn-1523h-5)
+		status_led="zcn-1523h:amber:init"
+		;;
+	wlr8100)
+		status_led="sitecom:amber:status"
+		;;
+	esac
+}
+
+set_state() {
+	get_status_led
+
+	case "$1" in
+	preinit)
+		status_led_blink_preinit
+		;;
+	failsafe)
+		status_led_blink_failsafe
+		;;
+	preinit_regular)
+		status_led_blink_preinit_regular
+		;;
+	done)
+		status_led_on
+		case $(ar71xx_board_name) in
+		gl-ar300m)
+			fw_printenv lc >/dev/null 2>&1 && fw_setenv "bootcount" 0
+			;;
+		qihoo-c301)
+			local n=$(fw_printenv activeregion | cut -d = -f 2)
+			fw_setenv "image${n}trynum" 0
+			;;
+		esac
+		;;
+	esac
+}
diff --git a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
new file mode 100644
index 0000000000..945167bee6
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
@@ -0,0 +1,147 @@
+#!/bin/sh
+
+[ -e /lib/firmware/$FIRMWARE ] && exit 0
+
+. /lib/ar71xx.sh
+. /lib/functions.sh
+. /lib/functions/system.sh
+
+ath9k_eeprom_die() {
+	echo "ath9k eeprom: " "$*"
+	exit 1
+}
+
+ath9k_eeprom_extract() {
+	local part=$1
+	local offset=$2
+	local count=$3
+	local mtd
+
+	mtd=$(find_mtd_chardev $part)
+	[ -n "$mtd" ] || \
+		ath9k_eeprom_die "no mtd device found for partition $part"
+
+	dd if=$mtd of=/lib/firmware/$FIRMWARE bs=1 skip=$offset count=$count 2>/dev/null || \
+		ath9k_eeprom_die "failed to extract from $mtd"
+}
+
+ath9k_ubi_eeprom_extract() {
+	local part=$1
+	local offset=$2
+	local count=$3
+	local ubidev=$(nand_find_ubi $CI_UBIPART)
+	local ubi
+
+	ubi=$(nand_find_volume $ubidev $part)
+	[ -n "$ubi" ] || \
+		ath9k_eeprom_die "no UBI volume found for $part"
+
+	dd if=/dev/$ubi of=/lib/firmware/$FIRMWARE bs=1 skip=$offset count=$count 2>/dev/null || \
+		ath9k_eeprom_die "failed to extract from $ubi"
+}
+
+ath9k_patch_firmware_mac() {
+	local mac=$1
+
+	[ -z "$mac" ] && return
+
+	macaddr_2bin $mac | dd of=/lib/firmware/$FIRMWARE conv=notrunc bs=1 seek=2 count=6
+}
+
+board=$(ar71xx_board_name)
+
+case "$FIRMWARE" in
+"soc_wmac.eeprom")
+	case $board in
+	c-55|\
+	c-60)
+		ath9k_eeprom_extract "art" 4096 2048
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary art 0) +1)
+		;;
+	mr18)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			ath9k_ubi_eeprom_extract "caldata" 4096 2048
+		else
+			ath9k_eeprom_extract "odm-caldata" 4096 2048
+		fi
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +1)
+		;;
+	r6100 | \
+	wndr3700v4 | \
+	wndr4300)
+		ath9k_eeprom_extract "caldata" 4096 2048
+		ath9k_patch_firmware_mac $(mtd_get_mac_binary caldata 0)
+		;;
+	z1)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			ath9k_ubi_eeprom_extract "caldata" 4096 2048
+		else
+			ath9k_eeprom_extract "origcaldata" 4096 2048
+		fi
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +2)
+		;;
+	*)
+		ath9k_eeprom_die "board $board is not supported yet"
+		;;
+	esac
+	;;
+
+"pci_wmac0.eeprom")
+	case $board in
+	c-55)
+		ath9k_eeprom_extract "art" 20480 2048
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary art 0) +2)
+		;;
+	mr18)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			ath9k_ubi_eeprom_extract "caldata" 20480 2048
+		else
+			ath9k_eeprom_extract "odm-caldata" 20480 2048
+		fi
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +2)
+		;;
+	wndr3700v4 | \
+	wndr4300)
+		ath9k_eeprom_extract "caldata" 20480 2048
+		ath9k_patch_firmware_mac $(mtd_get_mac_binary caldata 12)
+		;;
+	z1)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			ath9k_ubi_eeprom_extract "caldata" 86016 4096
+		else
+			ath9k_eeprom_extract "origcaldata" 86016 4096
+		fi
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +3)
+		;;
+	*)
+		ath9k_eeprom_die "board $board is not supported yet"
+		;;
+	esac
+	;;
+
+"pci_wmac1.eeprom")
+	case $board in
+	mr18)
+		. /lib/upgrade/nand.sh
+
+		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
+			ath9k_ubi_eeprom_extract "caldata" 36864 2048
+		else
+			ath9k_eeprom_extract "odm-caldata" 36864 2048
+		fi
+		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +3)
+		;;
+	*)
+		ath9k_eeprom_die "board $board is not supported yet"
+		;;
+	esac
+	;;
+esac
diff --git a/target/linux/ar71xx/base-files/etc/hotplug.d/net/10-ar922x-led-fix b/target/linux/ar71xx/base-files/etc/hotplug.d/net/10-ar922x-led-fix
new file mode 100644
index 0000000000..102415009b
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/hotplug.d/net/10-ar922x-led-fix
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# For AR9220 and AR9223, GPIO JTAG must explicit be disabled
+# before LEDs start working. Do this when wifi device is
+# detected.
+
+#
+# $DEVPATH is not valid for some boards (including WZR-HP-AG300H).
+# Manipulate the $DEVPATH to reach the corresponding phyN.
+#
+
+devdir=`dirname $DEVPATH`
+devdir=`dirname $devdir`
+phydir=/sys$devdir/ieee80211
+phyname=`cat $phydir/phy*/name`
+
+if [ -z $phyname -o $ACTION != "add" ]; then exit 0; fi
+
+#
+# ar922x_disable_gpio_jtag():
+#
+# Emulate
+#       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+# for AR9220 and AR9223.
+#
+
+ar922x_disable_gpio_jtag()                 
+{                                          
+        local regidx=0x4054               
+        
+	[ -f /sys/kernel/debug/ieee80211/$1/ath9k/regidx ] && {
+		echo $regidx > /sys/kernel/debug/ieee80211/$1/ath9k/regidx
+        	regval=`cat /sys/kernel/debug/ieee80211/$1/ath9k/regval`
+        	regval=$((regval | 0x20000))
+        	echo regval $regval
+    		echo $regval > /sys/kernel/debug/ieee80211/$1/ath9k/regval
+        }
+}
+
+if [ $phyname -a $ACTION = "add" ]; then
+
+	. /lib/ar71xx.sh
+	
+	case $(ar71xx_board_name) in
+		wzr-hp-ag300h)
+			ar922x_disable_gpio_jtag $phyname
+			;;
+	esac;
+fi
+
+exit 0
diff --git a/target/linux/ar71xx/base-files/etc/inittab b/target/linux/ar71xx/base-files/etc/inittab
new file mode 100644
index 0000000000..9820e7144b
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/inittab
@@ -0,0 +1,3 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+::askconsole:/usr/libexec/login.sh
diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/03_network-switchX-migration b/target/linux/ar71xx/base-files/etc/uci-defaults/03_network-switchX-migration
new file mode 100644
index 0000000000..c6b91b7737
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/uci-defaults/03_network-switchX-migration
@@ -0,0 +1,109 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+SWITCH_NAME_CHANGED=
+
+do_change_switch_name() {
+	local config="$1"
+	local option=$2
+	local oldname=$3
+	local newname=$4
+	local val
+
+	config_get val "$config" $option
+	[ "$val" != "$oldname" ] && return 0
+
+	uci_set network "$config" $option $newname
+	SWITCH_NAME_CHANGED=1
+
+	return 0
+}
+
+migrate_switch_name() {
+	local oldname=$1
+	local newname=$2
+
+	. /lib/functions.sh
+
+	config_load network
+
+	logger -t migrate-switchX "Updating switch names in network configuration"
+
+	config_foreach do_change_switch_name switch name $oldname $newname
+	config_foreach do_change_switch_name switch_vlan device $oldname $newname
+
+	[ "$SWITCH_NAME_CHANGED" = "1" ] && {
+		logger -t migrate-switchX "Switch names updated, saving network configuration"
+		uci commit network
+	}
+}
+
+. /lib/ar71xx.sh
+
+board=$(ar71xx_board_name)
+
+case "$board" in
+dir-825-c1|\
+wzr-hp-g300nh2|\
+pb92|\
+ap113|\
+tl-wdr4300|\
+tl-wr1041n-v2|\
+wrt160nl|\
+ap121|\
+ap121-mini|\
+ap96|\
+airrouter|\
+dir-600-a1|\
+dir-615-c1|\
+dir-615-e1|\
+dir-615-e4|\
+ja76pf|\
+rb-750|\
+rb-751|\
+tew-632brp|\
+tew-712br|\
+tl-mr3220|\
+tl-mr3220-v2 |\
+tl-mr3420|\
+tl-wr741nd|\
+tl-wr741nd-v4|\
+tl-wr841n-v7|\
+whr-g301n|\
+whr-hp-g300n|\
+whr-hp-gn|\
+wzr-hp-ag300h|\
+wzr-hp-g450h|\
+z1|\
+ew-dorin|\
+ew-dorin-router)
+	migrate_switch_name "eth0" "switch0"
+	;;
+
+el-m150|\
+rb-450)
+	migrate_switch_name "eth1" "switch0"
+	;;
+
+db120 |\
+rb-2011l | \
+rb-2011uas-2hnd)
+	migrate_switch_name "eth0" "switch0"
+	migrate_switch_name "eth1" "switch1"
+	;;
+
+dir-825-b1|\
+tew-673gru|\
+nbg460n_550n_550nh)
+	migrate_switch_name "rtl8366s" "switch0"
+	;;
+
+tl-wr1043nd)
+	migrate_switch_name "rtl8366rb" "switch0"
+	;;
+
+esac
+
+exit 0
diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/03_network-vlan-migration b/target/linux/ar71xx/base-files/etc/uci-defaults/03_network-vlan-migration
new file mode 100644
index 0000000000..259d240610
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/uci-defaults/03_network-vlan-migration
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+
+dev="$(uci -q get network.@switch_vlan[0].device)"
+vlan="$(uci -q get network.@switch_vlan[0].vlan)"
+
+if [ "$dev" = "rtl8366s" ] && [ "$vlan" = 0 ]; then
+	logger -t vlan-migration "VLAN 0 is invalid for RTL8366s, changing to 1"
+	uci set network.@switch_vlan[0].vlan=1
+	uci commit network
+fi
diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/04_led_migration b/target/linux/ar71xx/base-files/etc/uci-defaults/04_led_migration
new file mode 100644
index 0000000000..d578f59f7c
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/uci-defaults/04_led_migration
@@ -0,0 +1,90 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+LED_OPTIONS_CHANGED=0
+
+. /lib/functions.sh
+
+do_led_update_sysfs()
+{
+	local cfg=$1; shift
+	local tuples="$@"
+	local sysfs
+	local name
+
+	config_get sysfs $cfg sysfs
+	config_get name $cfg name
+
+	[ -z "$sysfs" ] && return
+
+	for tuple in $tuples; do
+		local old=${tuple%=*}
+		local new=${tuple#*=}
+		local new_sysfs
+
+		new_sysfs=$(echo ${sysfs} | sed "s/${old}/${new}/")
+
+		[ "$new_sysfs" = "$sysfs" ] && continue
+
+		uci set system.${cfg}.sysfs="${new_sysfs}"
+		LED_OPTIONS_CHANGED=1
+
+		logger -t led-migration "sysfs option of LED \"${name}\" updated to ${new_sysfs}"
+	done;
+}
+
+migrate_leds()
+{
+	config_load system
+	config_foreach do_led_update_sysfs led "$@"
+}
+
+. /lib/ar71xx.sh
+
+board=$(ar71xx_board_name)
+
+case "$board" in
+dhp-1565-a1|\
+dir-825-c1|\
+dir-835-a1)
+	migrate_leds ":orange:=:amber:" ":wifi_bgn=:wlan2g"
+	;;
+
+wndap360)
+	migrate_leds "wndap360:=netgear:"
+	;;
+
+wndr3700)
+	migrate_leds "wndr3700:=netgear:"
+	;;
+
+wndr3700v4 | \
+wndr4300)
+	migrate_leds ":orange:=:amber:"
+	;;
+
+wnr2000)
+	migrate_leds "wnr2000:=netgear:"
+	;;
+
+wnr2200)
+	migrate_leds "wnr2200:=netgear:"
+	;;
+
+wnr612-v2)
+	migrate_leds "wnr612v2:=netgear:"
+	;;
+
+wnr1000-v2)
+	migrate_leds "wnr1000v2:=netgear:"
+	;;
+
+*)
+	;;
+esac
+
+[ "$LED_OPTIONS_CHANGED" = "1" ] && uci commit system
+
+exit 0
diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-checksum b/target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-checksum
new file mode 100644
index 0000000000..057afe0193
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-checksum
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+
+. /lib/ar71xx.sh
+
+board=$(ar71xx_board_name)
+
+fixtrx() {
+	mtd -o 32 fixtrx firmware
+}
+
+fixwrgg() {
+	local kernel_size=$(sed -n 's/mtd[0-9]*: \([0-9a-f]*\).*"kernel".*/\1/p' /proc/mtd)
+
+	[ "$kernel_size" ] && mtd -c 0x$kernel_size fixwrgg firmware
+}
+
+case "$board" in
+mynet-rext |\
+wrt160nl)
+	fixtrx
+	;;
+dap-2695-a1)
+	fixwrgg
+	;;
+esac
diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-seama-header b/target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-seama-header
new file mode 100644
index 0000000000..ebe9c1c90f
--- /dev/null
+++ b/target/linux/ar71xx/base-files/etc/uci-defaults/09_fix-seama-header
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. /lib/ar71xx.sh
+
+fix_seama_header() {
+	local kernel_size=$(sed -n 's/mtd[0-9]*: \([0-9a-f]*\).*"kernel".*/\1/p' /proc/mtd)
+
+	[ "$kernel_size" ] && mtd -c 0x$kernel_size fixseama firmware
+}
+
+board=$(ar71xx_board_name)
+
+case "$board" in
+dir-869-a1)
+	fix_seama_header
+	;;
+esac
diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh
new file mode 100755
index 0000000000..526d03344b
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh
@@ -0,0 +1,1246 @@
+#!/bin/sh
+#
+# Copyright (C) 2009-2011 OpenWrt.org
+#
+
+AR71XX_BOARD_NAME=
+AR71XX_MODEL=
+
+ar71xx_get_mtd_offset_size_format() {
+	local mtd="$1"
+	local offset="$2"
+	local size="$3"
+	local format="$4"
+	local dev
+
+	dev=$(find_mtd_part $mtd)
+	[ -z "$dev" ] && return
+
+	dd if=$dev bs=1 skip=$offset count=$size 2>/dev/null | hexdump -v -e "1/1 \"$format\""
+}
+
+ar71xx_get_mtd_part_magic() {
+	local mtd="$1"
+	ar71xx_get_mtd_offset_size_format "$mtd" 0 4 %02x
+}
+
+wndr3700_board_detect() {
+	local machine="$1"
+	local magic
+	local name
+
+	name="wndr3700"
+
+	magic="$(ar71xx_get_mtd_part_magic firmware)"
+	case $magic in
+	"33373030")
+		machine="NETGEAR WNDR3700"
+		;;
+	"33373031")
+		model="$(ar71xx_get_mtd_offset_size_format art 41 32 %c)"
+		# Use awk to remove everything unprintable
+		model_stripped="$(ar71xx_get_mtd_offset_size_format art 41 32 %c | LC_CTYPE=C awk -v 'FS=[^[:print:]]' '{print $1; exit}')"
+		case $model in
+		$'\xff'*)
+			if [ "${model:24:1}" = 'N' ]; then
+				machine="NETGEAR WNDRMAC"
+			else
+				machine="NETGEAR WNDR3700v2"
+			fi
+			;;
+		'29763654+16+64'*)
+			machine="NETGEAR ${model_stripped:14}"
+			;;
+		'29763654+16+128'*)
+			machine="NETGEAR ${model_stripped:15}"
+			;;
+		*)
+			# Unknown ID
+			machine="NETGEAR ${model_stripped}"
+		esac
+	esac
+
+	AR71XX_BOARD_NAME="$name"
+	AR71XX_MODEL="$machine"
+}
+
+ubnt_get_mtd_part_magic() {
+	ar71xx_get_mtd_offset_size_format EEPROM 4118 2 %02x
+}
+
+ubnt_xm_board_detect() {
+	local model
+	local magic
+
+	magic="$(ubnt_get_mtd_part_magic)"
+	case ${magic:0:3} in
+		"e00"|\
+		"e01"|\
+		"e80")
+			model="Ubiquiti NanoStation M"
+			;;
+		"e0a")
+			model="Ubiquiti NanoStation loco M"
+			;;
+		"e1b"|\
+		"e1d")
+			model="Ubiquiti Rocket M"
+			;;
+		"e20"|\
+		"e2d")
+			model="Ubiquiti Bullet M"
+			;;
+		"e30")
+			model="Ubiquiti PicoStation M"
+			;;
+	esac
+
+	[ -z "$model" ] || AR71XX_MODEL="${model}${magic:3:1}"
+}
+
+cybertan_get_hw_magic() {
+	local part
+
+	part=$(find_mtd_part firmware)
+	[ -z "$part" ] && return 1
+
+	dd bs=8 count=1 skip=0 if=$part 2>/dev/null | hexdump -v -n 8 -e '1/1 "%02x"'
+}
+
+dir505_board_detect() {
+	local dev=$(find_mtd_part 'mac')
+	[ -z "$dev" ] && return
+
+	# The revision is stored at the beginning of the "mac" partition
+	local rev="$(LC_CTYPE=C awk -v 'FS=[^[:print:]]' '{print $1; exit}' $dev)"
+	AR71XX_MODEL="D-Link DIR-505 rev. $rev"
+}
+
+tplink_get_hwid() {
+	local part
+
+	part=$(find_mtd_part firmware)
+	[ -z "$part" ] && return 1
+
+	dd if=$part bs=4 count=1 skip=16 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+tplink_get_mid() {
+	local part
+
+	part=$(find_mtd_part firmware)
+	[ -z "$part" ] && return 1
+
+	dd if=$part bs=4 count=1 skip=17 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+tplink_board_detect() {
+	local model="$1"
+	local hwid
+	local hwver
+
+	hwid=$(tplink_get_hwid)
+	mid=$(tplink_get_mid)
+	hwver=${hwid:6:2}
+	hwver=" v${hwver#0}"
+
+	case "$hwid" in
+	"015000"*)
+		model="EasyLink EL-M150"
+		;;
+	"015300"*)
+		model="EasyLink EL-MINI"
+		;;
+	"044401"*)
+		model="ANTMINER-S1"
+		;;
+	"044403"*)
+		model="ANTMINER-S3"
+		;;
+	"44440101"*)
+		model="ANTROUTER-R1"
+		;;
+	"120000"*)
+		model="MERCURY MAC1200R"
+		;;
+	"007260"*)
+		model="TellStick ZNet Lite"
+		;;
+	"066601"*)
+		model="OMYlink OMY-G1"
+		;;
+	"066602"*)
+		model="OMYlink OMY-X1"
+		;;
+	"3C0001"*)
+		model="OOLITE"
+		;;
+	"3C0002"*)
+		model="MINIBOX_V1"
+		;;
+	"070301"*)
+		model="TP-Link TL-WR703N"
+		;;
+	"071000"*)
+		model="TP-Link TL-WR710N"
+
+		if [ "$hwid" = '07100002' -a "$mid" = '00000002' ]; then
+			hwver=' v2.1'
+		fi
+		;;
+	"072001"*)
+		model="TP-Link TL-WR720N"
+		;;
+	"070100"*)
+		model="TP-Link TL-WA701N/ND"
+		;;
+	"073000"*)
+		model="TP-Link TL-WA730RE"
+		;;
+	"074000"*)
+		model="TP-Link TL-WR740N/ND"
+		;;
+	"074100"*)
+		model="TP-Link TL-WR741N/ND"
+		;;
+	"074300"*)
+		model="TP-Link TL-WR743N/ND"
+		;;
+	"075000"*)
+		model="TP-Link TL-WA750RE"
+		;;
+	"721000"*)
+		model="TP-Link TL-WA7210N"
+		;;
+	"751000"*)
+		model="TP-Link TL-WA7510N"
+		;;
+	"080100"*)
+		model="TP-Link TL-WA801N/ND"
+		;;
+	"080200"*)
+		model="TP-Link TL-WR802N"
+		;;
+	"083000"*)
+		model="TP-Link TL-WA830RE"
+
+		if [ "$hwver" = ' v10' ]; then
+			hwver=' v1'
+		fi
+		;;
+	"084100"*)
+		model="TP-Link TL-WR841N/ND"
+
+		if [ "$hwid" = '08410002' -a "$mid" = '00000002' ]; then
+			hwver=' v1.5'
+		fi
+		;;
+	"084200"*)
+		model="TP-Link TL-WR842N/ND"
+		;;
+	"084300"*)
+		model="TP-Link TL-WR843N/ND"
+		;;
+	"085000"*)
+		model="TP-Link TL-WA850RE"
+		;;
+	"086000"*)
+		model="TP-Link TL-WA860RE"
+		;;
+	"090100"*)
+		model="TP-Link TL-WA901N/ND"
+		;;
+	"094100"*)
+		if [ "$hwid" = "09410002" -a "$mid" = "00420001" ]; then
+			model="Rosewill RNX-N360RT"
+			hwver=""
+		else
+			model="TP-Link TL-WR941N/ND"
+		fi
+		;;
+	"104100"*)
+		model="TP-Link TL-WR1041N/ND"
+		;;
+	"104300"*)
+		model="TP-Link TL-WR1043N/ND"
+		;;
+	"254300"*)
+		model="TP-Link TL-WR2543N/ND"
+		;;
+	"001001"*)
+		model="TP-Link TL-MR10U"
+		;;
+	"001101"*)
+		model="TP-Link TL-MR11U"
+		;;
+	"001201"*)
+		model="TP-Link TL-MR12U"
+		;;
+	"001301"*)
+		model="TP-Link TL-MR13U"
+		;;
+	"302000"*)
+		model="TP-Link TL-MR3020"
+		;;
+	"304000"*)
+		model="TP-Link TL-MR3040"
+		;;
+	"322000"*)
+		model="TP-Link TL-MR3220"
+		;;
+	"342000"*)
+		model="TP-Link TL-MR3420"
+		;;
+	"332000"*)
+		model="TP-Link TL-WDR3320"
+		;;
+	"350000"*)
+		model="TP-Link TL-WDR3500"
+		;;
+	"360000"*)
+		model="TP-Link TL-WDR3600"
+		;;
+	"430000"*)
+		model="TP-Link TL-WDR4300"
+		;;
+	"430080"*)
+		iw reg set IL
+		model="TP-Link TL-WDR4300 (IL)"
+		;;
+	"431000"*)
+		model="TP-Link TL-WDR4310"
+		;;
+	"49000002")
+		model="TP-Link TL-WDR4900"
+		;;
+	"65000002")
+		model="TP-Link TL-WDR6500"
+		;;
+	"453000"*)
+		model="Mercury MW4530R"
+		;;
+	"934100"*)
+		model="NC-LINK SMART-300"
+		;;
+	"c50000"*)
+		model="TP-Link Archer C5"
+		;;
+	"750000"*|\
+	"c70000"*)
+		model="TP-Link Archer C7"
+		;;
+	*)
+		hwver=""
+		;;
+	esac
+
+	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'
+		;;
+	'EAP120(TP-LINK|UN|N300-2)')
+		model='TP-Link EAP120'
+		;;
+	esac
+
+	[ -n "$model" ] && AR71XX_MODEL="$model v$2"
+}
+
+gl_inet_board_detect() {
+	local size="$(mtd_get_part_size 'firmware')"
+
+	case "$size" in
+	8192000)
+		AR71XX_MODEL='GL-iNet 6408A v1'
+		;;
+	16580608)
+		AR71XX_MODEL='GL-iNet 6416A v1'
+		;;
+	esac
+}
+
+ar71xx_board_detect() {
+	local machine
+	local name
+
+	machine=$(awk 'BEGIN{FS="[ \t]+:[ \t]"} /machine/ {print $2}' /proc/cpuinfo)
+
+	case "$machine" in
+	*"Oolite V1.0")
+		name="oolite"
+		;;
+	*"AC1750DB")
+		name="f9k1115v2"
+		;;
+	*"AirGateway")
+		name="airgateway"
+		;;
+	*"AirGateway Pro")
+		name="airgatewaypro"
+		;;
+	*"AirRouter")
+		name="airrouter"
+		;;
+	*"ALFA Network AP120C")
+		name="alfa-ap120c"
+		;;
+	*"ALFA Network AP96")
+		name="alfa-ap96"
+		;;
+	*"ALFA Network N2/N5")
+		name="alfa-nx"
+		;;
+	*ALL0258N)
+		name="all0258n"
+		;;
+	*ALL0305)
+		name="all0305"
+		;;
+	*ALL0315N)
+		name="all0315n"
+		;;
+	*Antminer-S1)
+		name="antminer-s1"
+		;;
+	*Antminer-S3)
+		name="antminer-s3"
+		;;
+	*"Arduino Yun")
+		name="arduino-yun"
+		;;
+	*AP113)
+		name="ap113"
+		;;
+	*"AP121 reference board")
+		name="ap121"
+		;;
+	*AP121-MINI)
+		name="ap121-mini"
+		;;
+	*"AP132 reference board")
+		name="ap132"
+		;;
+	*"AP136-010 reference board")
+		name="ap136-010"
+		;;
+	*"AP136-020 reference board")
+		name="ap136-020"
+		;;
+	*"AP135-020 reference board")
+		name="ap135-020"
+		;;
+	*"AP143 reference board")
+		name="ap143"
+		;;
+	*"AP147-010 reference board")
+		name="ap147-010"
+		;;
+	*"AP152 reference board")
+		name="ap152"
+		;;
+	*AP81)
+		name="ap81"
+		;;
+	*AP83)
+		name="ap83"
+		;;
+	*AP90Q)
+		name="ap90q"
+		;;
+	*"Archer C5")
+		name="archer-c5"
+		;;
+	*"Archer C7")
+		name="archer-c7"
+		;;
+	*"Atheros AP96")
+		name="ap96"
+		;;
+	*AW-NR580)
+		name="aw-nr580"
+		;;
+	*BHR-4GRV2)
+		name="bhr-4grv2"
+		;;
+	*CAP324)
+		name="cap324"
+		;;
+	*C-55)
+		name="c-55"
+		;;
+	*C-60)
+		name="c-60"
+		;;
+	*CAP4200AG)
+		name="cap4200ag"
+		;;
+	*"CF-E316N v2")
+		name="cf-e316n-v2"
+		;;
+	*"CF-E320N v2")
+		name="cf-e320n-v2"
+		;;
+	*"CF-E380AC v1")
+		name="cf-e380ac-v1"
+		;;
+	*"CF-E380AC v2")
+		name="cf-e380ac-v2"
+		;;
+	*CF-E520N)
+		name="cf-e520n"
+		;;
+	*CF-E530N)
+		name="cf-e530n"
+		;;
+	*"CPE210/220")
+		name="cpe210"
+		tplink_pharos_board_detect
+		;;
+	*"CPE510/520")
+		name="cpe510"
+		tplink_pharos_board_detect
+		;;
+	*CPE830)
+		name="cpe830"
+		;;
+	*CPE870)
+		name="cpe870"
+		;;
+	*CR3000)
+		name="cr3000"
+		;;
+	*CR5000)
+		name="cr5000"
+		;;
+	*"DAP-2695 rev. A1")
+		name="dap-2695-a1"
+		;;
+	*"DB120 reference board")
+		name="db120"
+		;;
+	*"DGL-5500 rev. A1")
+		name="dgl-5500-a1"
+		;;
+	*"DHP-1565 rev. A1")
+		name="dhp-1565-a1"
+		;;
+	*"DIR-505 rev. A1")
+		name="dir-505-a1"
+		dir505_board_detect
+		;;
+	*"DIR-600 rev. A1")
+		name="dir-600-a1"
+		;;
+	*"DIR-615 rev. E1")
+		name="dir-615-e1"
+		;;
+	*"DIR-615 rev. E4")
+		name="dir-615-e4"
+		;;
+	*"DIR-615 rev. I1")
+		name="dir-615-i1"
+		;;
+	*"DIR-825 rev. B1")
+		name="dir-825-b1"
+		;;
+	*"DIR-825 rev. C1")
+		name="dir-825-c1"
+		;;
+	*"DIR-835 rev. A1")
+		name="dir-835-a1"
+		;;
+	*"DIR-869 rev. A1")
+		name="dir-869-a1"
+		;;
+	*"dLAN Hotspot")
+		name="dlan-hotspot"
+		;;
+	*"dLAN pro 500 Wireless+")
+		name="dlan-pro-500-wp"
+		;;
+	*"dLAN pro 1200+ WiFi ac")
+		name="dlan-pro-1200-ac"
+		;;
+	*DR344)
+		name="dr344"
+		;;
+	*DR531)
+		name="dr531"
+		;;
+	*"Dragino v2")
+		name="dragino2"
+		;;
+	*"Domino Pi")
+		name="gl-domino"
+		;;
+	*"DW33D")
+		name="dw33d"
+		;;
+	*"EAP120")
+		name="eap120"
+		tplink_pharos_board_detect
+		;;
+	*"EAP300 v2")
+		name="eap300v2"
+		;;
+	*EAP7660D)
+		name="eap7660d"
+		;;
+	*EL-M150)
+		name="el-m150"
+		;;
+	*EL-MINI)
+		name="el-mini"
+		;;
+	*"GL-CONNECT INET v1")
+		name="gl-inet"
+		gl_inet_board_detect
+		;;
+	*"GL AR150")
+		name="gl-ar150"
+		;;
+	*"GL AR300")
+		name="gl-ar300"
+		;;
+	*"GL-AR300M")
+		name="gl-ar300m"
+		;;
+	*"GL-MIFI")
+		name="gl-mifi"
+		;;
+	*"EnGenius EPG5000")
+		name="epg5000"
+		;;
+	*"EnGenius ESR1750")
+		name="esr1750"
+		;;
+	*"EnGenius ESR900")
+		name="esr900"
+		;;
+	*JA76PF)
+		name="ja76pf"
+		;;
+	*JA76PF2)
+		name="ja76pf2"
+		;;
+	*"Bullet M")
+		name="bullet-m"
+		ubnt_xm_board_detect
+		;;
+	*"Loco M XW")
+		name="loco-m-xw"
+		;;
+	*"Nanostation M")
+		name="nanostation-m"
+		ubnt_xm_board_detect
+		;;
+	*"Nanostation M XW")
+		name="nanostation-m-xw"
+		;;
+	*JWAP003)
+		name="jwap003"
+		;;
+	*JWAP230)
+		name="jwap230"
+		;;
+	*"Hornet-UB")
+		local size
+		size=$(awk '/firmware/ { print $2 }' /proc/mtd)
+
+		if [ "x$size" = "x00790000" ]; then
+			name="hornet-ub"
+		fi
+
+		if [ "x$size" = "x00f90000" ]; then
+			name="hornet-ub-x2"
+		fi
+		;;
+	*LS-SR71)
+		name="ls-sr71"
+		;;
+	*"MAC1200R")
+		name="mc-mac1200r"
+		;;
+	*"MiniBox V1.0")
+		name="minibox-v1"
+		;;
+	*MR12)
+		name="mr12"
+		;;
+	*MR16)
+		name="mr16"
+		;;
+	*MR18)
+		name="mr18"
+		;;
+	*MR600v2)
+		name="mr600v2"
+		;;
+	*MR1750)
+		name="mr1750"
+		;;
+	*MR1750v2)
+		name="mr1750v2"
+		;;
+	*MR600)
+		name="mr600"
+		;;
+	*MR900)
+		name="mr900"
+		;;
+	*MR900v2)
+		name="mr900v2"
+		;;
+	*"My Net N600")
+		name="mynet-n600"
+		;;
+	*"My Net N750")
+		name="mynet-n750"
+		;;
+	*"WD My Net Wi-Fi Range Extender")
+		name="mynet-rext"
+		;;
+	*MZK-W04NU)
+		name="mzk-w04nu"
+		;;
+	*MZK-W300NH)
+		name="mzk-w300nh"
+		;;
+	*"NBG460N/550N/550NH")
+		name="nbg460n_550n_550nh"
+		;;
+	*"Zyxel NBG6616")
+		name="nbg6616"
+		;;
+	*"Zyxel NBG6716")
+		name="nbg6716"
+		;;
+	*OM2P)
+		name="om2p"
+		;;
+	*OM2Pv2)
+		name="om2pv2"
+		;;
+	*"OM2P HS")
+		name="om2p-hs"
+		;;
+	*"OM2P HSv2")
+		name="om2p-hsv2"
+		;;
+	*"OM2P HSv3")
+		name="om2p-hsv3"
+		;;
+	*"OM2P LC")
+		name="om2p-lc"
+		;;
+	*OM5P)
+		name="om5p"
+		;;
+	*"OM5P AN")
+		name="om5p-an"
+		;;
+	*"OM5P AC")
+		name="om5p-ac"
+		;;
+	*"OM5P ACv2")
+		name="om5p-acv2"
+		;;
+	*"OMY-X1")
+		name="omy-x1"
+		;;
+	*"OMY-G1")
+		name="omy-g1"
+		;;
+	*"Onion Omega")
+		name="onion-omega"
+		;;
+	*PB42)
+		name="pb42"
+		;;
+	*"PB44 reference board")
+		name="pb44"
+		;;
+	*PB92)
+		name="pb92"
+		;;
+	*"Qihoo 360 C301")
+		name="qihoo-c301"
+		;;
+	*"RouterBOARD 411/A/AH")
+		name="rb-411"
+		;;
+	*"RouterBOARD 411U")
+		name="rb-411u"
+		;;
+	*"RouterBOARD 433/AH")
+		name="rb-433"
+		;;
+	*"RouterBOARD 433UAH")
+		name="rb-433u"
+		;;
+	*"RouterBOARD 435G")
+		name="rb-435g"
+		;;
+	*"RouterBOARD 450")
+		name="rb-450"
+		;;
+	*"RouterBOARD 450G")
+		name="rb-450g"
+		;;
+	*"RouterBOARD 493/AH")
+		name="rb-493"
+		;;
+	*"RouterBOARD 493G")
+		name="rb-493g"
+		;;
+	*"RouterBOARD 750")
+		name="rb-750"
+		;;
+	*"RouterBOARD 750GL")
+		name="rb-750gl"
+		;;
+	*"RouterBOARD 751")
+		name="rb-751"
+		;;
+	*"RouterBOARD 751G")
+		name="rb-751g"
+		;;
+	*"RouterBOARD 911G-2HPnD")
+		name="rb-911g-2hpnd"
+		;;
+	*"RouterBOARD 911G-5HPnD")
+		name="rb-911g-5hpnd"
+		;;
+	*"RouterBOARD 911G-5HPacD")
+		name="rb-911g-5hpacd"
+		;;
+	*"RouterBOARD 912UAG-2HPnD")
+		name="rb-912uag-2hpnd"
+		;;
+	*"RouterBOARD 912UAG-5HPnD")
+		name="rb-912uag-5hpnd"
+		;;
+	*"RouterBOARD 951G-2HnD")
+		name="rb-951g-2hnd"
+		;;
+	*"RouterBOARD 951Ui-2HnD")
+		name="rb-951ui-2hnd"
+		;;
+	*"RouterBOARD 2011L")
+		name="rb-2011l"
+		;;
+	*"RouterBOARD 2011UAS")
+		name="rb-2011uas"
+		;;
+	*"RouterBOARD 2011UiAS")
+		name="rb-2011uias"
+		;;
+	*"RouterBOARD 2011UAS-2HnD")
+		name="rb-2011uas-2hnd"
+		;;
+	*"RouterBOARD 2011UiAS-2HnD")
+		name="rb-2011uias-2hnd"
+		;;
+	*"RouterBOARD SXT Lite2")
+		name="rb-sxt2n"
+		;;
+	*"RouterBOARD SXT Lite5")
+		name="rb-sxt5n"
+		;;
+	*"Rocket M")
+		name="rocket-m"
+		ubnt_xm_board_detect
+		;;
+	*"Rocket M TI")
+		name="rocket-m-ti"
+		;;
+	*"Rocket M XW")
+		name="rocket-m-xw"
+		;;
+	*RouterStation)
+		name="routerstation"
+		;;
+	*"RouterStation Pro")
+		name="routerstation-pro"
+		;;
+	*RW2458N)
+		name="rw2458n"
+		;;
+	*"SMART-300")
+		name="smart-300"
+		;;
+	"Smart Electronics Black Swift board"*)
+		name="bsb"
+		;;
+	*"Telldus TellStick ZNet Lite")
+		name="tellstick-znet-lite"
+		;;
+	*SOM9331)
+		name="som9331"
+		;;
+	*TEW-632BRP)
+		name="tew-632brp"
+		;;
+	*TEW-673GRU)
+		name="tew-673gru"
+		;;
+	*TEW-712BR)
+		name="tew-712br"
+		;;
+	*TEW-732BR)
+		name="tew-732br"
+		;;
+	*TEW-823DRU)
+		name="tew-823dru"
+		;;
+	*"TL-WR1041N v2")
+		name="tl-wr1041n-v2"
+		;;
+	*TL-WR1043ND)
+		name="tl-wr1043nd"
+		;;
+	*"TL-WR1043ND v2")
+		name="tl-wr1043nd-v2"
+		;;
+	*TL-WR2543N*)
+		name="tl-wr2543n"
+		;;
+	*"DIR-615 rev. C1")
+		name="dir-615-c1"
+		;;
+	*TL-MR3020)
+		name="tl-mr3020"
+		;;
+	*TL-MR3040)
+		name="tl-mr3040"
+		;;
+	*"TL-MR3040 v2")
+		name="tl-mr3040-v2"
+		;;
+	*TL-MR3220)
+		name="tl-mr3220"
+		;;
+	*"TL-MR3220 v2")
+		name="tl-mr3220-v2"
+		;;
+	*TL-MR3420)
+		name="tl-mr3420"
+		;;
+	*"TL-MR3420 v2")
+		name="tl-mr3420-v2"
+		;;
+	*"TL-WA701ND v2")
+		name="tl-wa701nd-v2"
+		;;
+	*"TL-WA7210N v2")
+		name="tl-wa7210n-v2"
+		;;
+	*TL-WA750RE)
+		name="tl-wa750re"
+		;;
+	*"TL-WA7510N v1")
+		name="tl-wa7510n"
+		;;
+	*TL-WA850RE)
+		name="tl-wa850re"
+		;;
+	*TL-WA860RE)
+		name="tl-wa860re"
+		;;
+	*"TL-WA830RE v2")
+		name="tl-wa830re-v2"
+		;;
+	*"TL-WA801ND v2")
+		name="tl-wa801nd-v2"
+		;;
+	*"TL-WA801ND v3")
+		name="tl-wa801nd-v3"
+		;;
+	*"TL-WR802N v1")
+		name="tl-wr802n-v1"
+		;;
+	*TL-WA901ND)
+		name="tl-wa901nd"
+		;;
+	*"TL-WA901ND v2")
+		name="tl-wa901nd-v2"
+		;;
+	*"TL-WA901ND v3")
+		name="tl-wa901nd-v3"
+		;;
+	*"TL-WA901ND v4")
+		name="tl-wa901nd-v4"
+		;;
+	*"TL-WDR3320 v2")
+		name="tl-wdr3320-v2"
+		;;
+	*"TL-WDR3500")
+		name="tl-wdr3500"
+		;;
+	*"TL-WDR3600/4300/4310")
+		name="tl-wdr4300"
+		;;
+	*"TL-WDR4900 v2")
+		name="tl-wdr4900-v2"
+		;;
+	*"TL-WDR6500 v2")
+		name="tl-wdr6500-v2"
+		;;
+	*TL-WPA8630)
+		name="tl-wpa8630"
+		;;
+	*TL-WR741ND)
+		name="tl-wr741nd"
+		;;
+	*"TL-WR741ND v4")
+		name="tl-wr741nd-v4"
+		;;
+	*"TL-WR841N v1")
+		name="tl-wr841n-v1"
+		;;
+	*"TL-WR841N/ND v7")
+		name="tl-wr841n-v7"
+		;;
+	*"TL-WR841N/ND v8")
+		name="tl-wr841n-v8"
+		;;
+	*"TL-WR841N/ND v9")
+		name="tl-wr841n-v9"
+		;;
+	*"TL-WR841N/ND v11")
+		name="tl-wr841n-v11"
+		;;
+	*"TL-WR842N/ND v2")
+		name="tl-wr842n-v2"
+		;;
+	*"TL-WR842N/ND v3")
+		name="tl-wr842n-v3"
+		;;
+	*TL-WR941ND)
+		name="tl-wr941nd"
+		;;
+	*"TL-WR941N/ND v5")
+		name="tl-wr941nd-v5"
+		;;
+	*"TL-WR941N/ND v6")
+		name="tl-wr941nd-v6"
+		;;
+	*"TL-WR703N v1")
+		name="tl-wr703n"
+		;;
+	*"TL-WR710N v1")
+		name="tl-wr710n"
+		;;
+	*"TL-WR720N"*)
+		name="tl-wr720n-v3"
+		;;
+	*"TL-WR810N")
+		name="tl-wr810n"
+		;;
+	*"TL-MR10U")
+		name="tl-mr10u"
+		;;
+	*"TL-MR11U")
+		name="tl-mr11u"
+		;;
+	*"TL-MR12U")
+		name="tl-mr12u"
+		;;
+	*"TL-MR13U v1")
+		name="tl-mr13u"
+		;;
+	*"Tube2H")
+		name="tube2h"
+		;;
+	*UniFi)
+		name="unifi"
+		;;
+	*"UniFi-AC-LITE")
+		name="unifiac-lite"
+		;;
+	*"UniFi-AC-PRO")
+		name="unifiac-pro"
+		;;
+	*"UniFi AP Pro")
+		name="uap-pro"
+		;;
+	"WeIO"*)
+		name="weio"
+		;;
+	*WHR-G301N)
+		name="whr-g301n"
+		;;
+	*WHR-HP-GN)
+		name="whr-hp-gn"
+		;;
+	*WLAE-AG300N)
+		name="wlae-ag300n"
+		;;
+	*"UniFiAP Outdoor")
+		name="unifi-outdoor"
+		;;
+	*"UniFiAP Outdoor+")
+		name="unifi-outdoor-plus"
+		;;
+	*WP543)
+		name="wp543"
+		;;
+	*WPE72)
+		name="wpe72"
+		;;
+	*WPJ342)
+		name="wpj342"
+		;;
+	*WPJ344)
+		name="wpj344"
+		;;
+	*WPJ531)
+		name="wpj531"
+		;;
+	*WPJ558)
+		name="wpj558"
+		;;
+	*WNDAP360)
+		name="wndap360"
+		;;
+	*"WNDR3700/WNDR3800/WNDRMAC")
+		wndr3700_board_detect "$machine"
+		;;
+	*"R6100")
+		name="r6100"
+		;;
+	*"WNDR3700v4")
+		name="wndr3700v4"
+		;;
+	*"WNDR4300")
+		name="wndr4300"
+		;;
+	*"WNR2000 V4")
+		name="wnr2000-v4"
+		;;
+	*"WNR2000 V3")
+		name="wnr2000-v3"
+		;;
+	*WNR2000)
+		name="wnr2000"
+		;;
+	*WNR2200)
+		name="wnr2200"
+		;;
+	*"WNR612 V2")
+		name="wnr612-v2"
+		;;
+	*"WNR1000 V2")
+		name="wnr1000-v2"
+		;;
+	*WPN824N)
+		name="wpn824n"
+		;;
+	*WRT160NL)
+		name="wrt160nl"
+		;;
+	*WRT400N)
+		name="wrt400n"
+		;;
+	*"WRTnode2Q board")
+		name="wrtnode2q"
+		;;
+	*"WZR-450HP2")
+		name="wzr-450hp2"
+		;;
+	*"WZR-HP-AG300H/WZR-600DHP")
+		name="wzr-hp-ag300h"
+		;;
+	*WZR-HP-G300NH)
+		name="wzr-hp-g300nh"
+		;;
+	*WZR-HP-G450H)
+		name="wzr-hp-g450h"
+		;;
+	*WZR-HP-G300NH2)
+		name="wzr-hp-g300nh2"
+		;;
+	*WHR-HP-G300N)
+		name="whr-hp-g300n"
+		;;
+	*Z1)
+		name="z1"
+		;;
+	*ZBT-WE1526)
+		name="zbt-we1526"
+		;;
+	*ZCN-1523H-2)
+		name="zcn-1523h-2"
+		;;
+	*ZCN-1523H-5)
+		name="zcn-1523h-5"
+		;;
+	*EmbWir-Dorin)
+		name="ew-dorin"
+		;;
+	*EmbWir-Dorin-Router)
+		name="ew-dorin-router"
+		;;
+	"8devices Carambola2"*)
+		name="carambola2"
+		;;
+	*"Sitecom WLR-8100")
+		name="wlr8100"
+		;;
+	*"BHU BXU2000n-2 rev. A1")
+		name="bxu2000n-2-a1"
+		;;
+	*"HiWiFi HC6361")
+		name="hiwifi-hc6361"
+		;;
+	esac
+
+	[ -z "$AR71XX_MODEL" ] && [ "${machine:0:8}" = 'TP-LINK ' ] && \
+		tplink_board_detect "$machine"
+
+	[ -z "$name" ] && name="unknown"
+
+	[ -z "$AR71XX_BOARD_NAME" ] && AR71XX_BOARD_NAME="$name"
+	[ -z "$AR71XX_MODEL" ] && AR71XX_MODEL="$machine"
+
+	[ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/"
+
+	echo "$AR71XX_BOARD_NAME" > /tmp/sysinfo/board_name
+	echo "$AR71XX_MODEL" > /tmp/sysinfo/model
+}
+
+ar71xx_board_name() {
+	local name
+
+	[ -f /tmp/sysinfo/board_name ] && name=$(cat /tmp/sysinfo/board_name)
+	[ -z "$name" ] && name="unknown"
+
+	echo "$name"
+}
diff --git a/target/linux/ar71xx/base-files/lib/preinit/03_preinit_do_ar71xx.sh b/target/linux/ar71xx/base-files/lib/preinit/03_preinit_do_ar71xx.sh
new file mode 100644
index 0000000000..ff5407a0d4
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/preinit/03_preinit_do_ar71xx.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+do_ar71xx() {
+	. /lib/ar71xx.sh
+
+	ar71xx_board_detect
+}
+
+boot_hook_add preinit_main do_ar71xx
diff --git a/target/linux/ar71xx/base-files/lib/preinit/05_set_iface_mac_ar71xx b/target/linux/ar71xx/base-files/lib/preinit/05_set_iface_mac_ar71xx
new file mode 100644
index 0000000000..50f59defe1
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/preinit/05_set_iface_mac_ar71xx
@@ -0,0 +1,60 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+
+. /lib/ar71xx.sh
+
+fetch_mac_from_mtd() {
+	local mtd_part=$1
+	local lan_env=$2
+	local wan_env=$3
+	local mtd mac
+
+	mtd=$(grep $mtd_part /proc/mtd | cut -d: -f1)
+	[ -z $mtd ] && return
+
+	mac=$(grep $lan_env /dev/$mtd | cut -d= -f2)
+	[ ! -z $mac ] && ifconfig eth0 hw ether $mac 2>/dev/null
+
+	mac=$(grep $wan_env /dev/$mtd | cut -d= -f2)
+	[ ! -z $mac ] && ifconfig eth1 hw ether $mac 2>/dev/null
+}
+
+preinit_set_mac_address() {
+	case $(ar71xx_board_name) in
+		c-55|\
+		c-60)
+			mac_lan=$(mtd_get_mac_binary art 0)
+			[ -n "$mac_lan" ] && ifconfig eth0 hw ether "$mac_lan"
+			;;
+		dir-615-c1)
+			fetch_mac_from_mtd config lan_mac wan_mac
+			echo 1 > /sys/class/leds/dir-615-c1:green:wancpu/brightness
+			;;
+		dir-615-i1)
+			fetch_mac_from_mtd nvram sys_lan_mac sys_wan_mac
+			;;
+		mr18)
+			mac_lan=$(mtd_get_mac_binary_ubi board-config 102)
+			[ -n "$mac_lan" ] && ifconfig eth0 hw ether "$mac_lan"
+			;;
+		r6100)
+			mac_lan=$(mtd_get_mac_binary caldata 0)
+			[ -n "$mac_lan" ] && ifconfig eth1 hw ether "$mac_lan"
+			mac_wan=$(mtd_get_mac_binary caldata 6)
+			[ -n "$mac_wan" ] && ifconfig eth0 hw ether "$mac_wan"
+			;;
+		tew-632brp)
+			fetch_mac_from_mtd config lan_mac wan_mac
+			;;
+		wrt160nl)
+			fetch_mac_from_mtd nvram lan_hwaddr wan_hwaddr
+			;;
+		z1)
+			mac_lan=$(mtd_get_mac_binary_ubi board-config 102)
+			[ -n "$mac_lan" ] && ifconfig eth0 hw ether "$mac_lan"
+			;;
+	esac
+}
+
+boot_hook_add preinit_main preinit_set_mac_address
diff --git a/target/linux/ar71xx/base-files/lib/preinit/05_set_preinit_iface_ar71xx b/target/linux/ar71xx/base-files/lib/preinit/05_set_preinit_iface_ar71xx
new file mode 100644
index 0000000000..e2a70b82dd
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/preinit/05_set_preinit_iface_ar71xx
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+
+. /lib/ar71xx.sh
+
+set_preinit_iface() {
+	case $(ar71xx_board_name) in
+	alfa-ap96 |\
+	alfa-nx |\
+	ap135-020 |\
+	ap136-020 |\
+	ap147-010 |\
+	ap83 |\
+	archer-c5 |\
+	archer-c7 |\
+	bhr-4grv2 |\
+	dir-505-a1 |\
+	gl-inet |\
+	jwap003 |\
+	pb42 |\
+	pb44 |\
+	rb-433 |\
+	rb-433u |\
+	rb-435g |\
+	rb-450 |\
+	rb-450g |\
+	routerstation |\
+	routerstation-pro |\
+	smart-300 |\
+	tl-mr3420-v2 |\
+	tl-wdr4900-v2 |\
+	tl-wr1043nd-v2 |\
+	tl-wr710n |\
+	tl-wr720n-v3 |\
+	tl-wr841n-v8 |\
+	tl-wr842n-v2 |\
+	tl-wr941nd-v6 |\
+	wnr2000-v3 |\
+	wnr2200 |\
+	wnr612-v2 |\
+	wnr1000-v2 |\
+	wpn824n |\
+	wpe72)
+		ifname=eth1
+		;;
+	*)
+		ifname=eth0
+		;;
+	esac
+}
+
+boot_hook_add preinit_main set_preinit_iface
+
+
+
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/allnet.sh b/target/linux/ar71xx/base-files/lib/upgrade/allnet.sh
new file mode 100644
index 0000000000..98b368d150
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/upgrade/allnet.sh
@@ -0,0 +1,162 @@
+# The U-Boot loader of the some Allnet devices requires image sizes and
+# checksums to be provided in the U-Boot environment.
+# In case the check fails during boot, a failsafe-system is started to provide
+# a minimal web-interface for flashing a new firmware.
+
+# make sure we got uboot-envtools and fw_env.config copied over to the ramfs
+# create /var/lock for the lock "fw_setenv.lock" of fw_setenv
+platform_add_ramfs_ubootenv() {
+	[ -e /usr/sbin/fw_printenv ] && install_bin /usr/sbin/fw_printenv /usr/sbin/fw_setenv
+	[ -e /etc/fw_env.config ] && install_file /etc/fw_env.config
+	mkdir -p $RAM_ROOT/var/lock
+}
+append sysupgrade_pre_upgrade platform_add_ramfs_ubootenv
+
+# determine size of the main firmware partition
+platform_get_firmware_size() {
+	local dev size erasesize name
+	while read dev size erasesize name; do
+		name=${name#'"'}; name=${name%'"'}
+		case "$name" in
+			firmware)
+				printf "%d" "0x$size"
+				break
+			;;
+		esac
+	done < /proc/mtd
+}
+
+# get the first 4 bytes (magic) of a given file starting at offset in hex format
+get_magic_long_at() {
+	dd if="$1" skip=$(( $CI_BLKSZ / 4 * $2 )) bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+get_filesize() {
+	wc -c "$1" | while read image_size _n ; do echo $image_size ; break; done
+}
+
+# scan through the update image pages until matching a magic
+platform_get_offset() {
+	offsetcount=0
+	magiclong="x"
+	if [ -n "$3" ]; then
+		offsetcount=$3
+	fi
+	while magiclong=$( get_magic_long_at "$1" "$offsetcount" ) && [ -n "$magiclong" ]; do
+		case "$magiclong" in
+			"2705"*)
+				# U-Boot image magic
+				if [ "$2" = "uImage" ]; then
+					echo $offsetcount
+					return
+				fi
+			;;
+			"68737173"|"73717368")
+				# SquashFS
+				if [ "$2" = "rootfs" ]; then
+					echo $offsetcount
+					return
+				fi
+			;;
+			"deadc0de"|"19852003")
+				# JFFS2 empty page
+				if [ "$2" = "rootfs-data" ]; then
+					echo $offsetcount
+					return
+				fi
+			;;
+		esac
+		offsetcount=$(( $offsetcount + 1 ))
+	done
+}
+
+platform_check_image_allnet() {
+	local fw_printenv=/usr/sbin/fw_printenv
+	[ ! -n "$fw_printenv" -o ! -x "$fw_printenv" ] && {
+		echo "Please install uboot-envtools!"
+		return 1
+	}
+
+	[ ! -r "/etc/fw_env.config" ] && {
+		echo "/etc/fw_env.config is missing"
+		return 1
+	}
+
+	local image_size=$( get_filesize "$1" )
+	local firmware_size=$( platform_get_firmware_size )
+	[ $image_size -ge $firmware_size ] &&
+	{
+		echo "upgrade image is too big (${image_size}b > ${firmware_size}b)"
+	}
+
+	local vmlinux_blockoffset=$( platform_get_offset "$1" uImage )
+	[ -z $vmlinux_blockoffset ] && {
+		echo "vmlinux-uImage not found"
+		return 1
+	}
+
+	local rootfs_blockoffset=$( platform_get_offset "$1" rootfs "$vmlinux_blockoffset" )
+	[ -z $rootfs_blockoffset ] && {
+		echo "missing rootfs"
+		return 1
+	}
+
+	local data_blockoffset=$( platform_get_offset "$1" rootfs-data "$rootfs_blockoffset" )
+	[ -z $data_blockoffset ] && {
+		echo "rootfs doesn't have JFFS2 end marker"
+		return 1
+	}
+
+	return 0
+}
+
+platform_do_upgrade_allnet() {
+	local firmware_base_addr=$( printf "%d" "$1" )
+	local vmlinux_blockoffset=$( platform_get_offset "$2" uImage )
+	if [ ! -n "$vmlinux_blockoffset" ]; then
+		echo "can't determine uImage offset"
+		return 1
+	fi
+	local rootfs_blockoffset=$( platform_get_offset "$2" rootfs $(( $vmlinux_blockoffset + 1 )) )
+	local vmlinux_offset=$(( $vmlinux_blockoffset * $CI_BLKSZ ))
+	local vmlinux_addr=$(( $firmware_base_addr + $vmlinux_offset ))
+	local vmlinux_hexaddr=0x$( printf "%08x" "$vmlinux_addr" )
+	if [ ! -n "$rootfs_blockoffset" ]; then
+		echo "can't determine rootfs offset"
+		return 1
+	fi
+	local rootfs_offset=$(( $rootfs_blockoffset * $CI_BLKSZ ))
+	local rootfs_addr=$(( $firmware_base_addr + $rootfs_offset ))
+	local rootfs_hexaddr=0x$( printf "%08x" "$rootfs_addr" )
+	local vmlinux_blockcount=$(( $rootfs_blockoffset - $vmlinux_blockoffset ))
+	local vmlinux_size=$(( $rootfs_offset - $vmlinux_offset ))
+	local vmlinux_hexsize=0x$( printf "%08x" "$vmlinux_size" )
+	local data_blockoffset=$( platform_get_offset "$2" rootfs-data $(( $rootfs_blockoffset + 1 )) )
+	if [ ! -n "$data_blockoffset" ]; then
+		echo "can't determine rootfs size"
+		return 1
+	fi
+	local data_offset=$(( $data_blockoffset * $CI_BLKSZ ))
+	local rootfs_blockcount=$(( $data_blockoffset - $rootfs_blockoffset ))
+	local rootfs_size=$(( $data_offset - $rootfs_offset ))
+	local rootfs_hexsize=0x$( printf "%08x" "$rootfs_size" )
+
+	local rootfs_md5=$( dd if="$2" bs=$CI_BLKSZ skip=$rootfs_blockoffset count=$rootfs_blockcount 2>/dev/null | md5sum -); rootfs_md5="${rootfs_md5%% *}"
+	local vmlinux_md5=$( dd if="$2" bs=$CI_BLKSZ skip=$vmlinux_blockoffset count=$vmlinux_blockcount 2>/dev/null | md5sum -); vmlinux_md5="${vmlinux_md5%% *}"
+	# this needs a recent version of uboot-envtools!
+	cat >/tmp/fw_env_upgrade <<EOF
+vmlinux_start_addr $vmlinux_hexaddr
+vmlinux_size $vmlinux_hexsize
+vmlinux_checksum $vmlinux_md5
+rootfs_start_addr $rootfs_hexaddr
+rootfs_size $rootfs_hexsize
+rootfs_checksum $rootfs_md5
+bootcmd bootm $vmlinux_hexaddr
+EOF
+	fw_setenv -s /tmp/fw_env_upgrade || {
+		echo "failed to update U-Boot environment"
+		return 1
+	}
+	shift
+	default_do_upgrade "$@"
+}
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/dir825.sh b/target/linux/ar71xx/base-files/lib/upgrade/dir825.sh
new file mode 100644
index 0000000000..7ad3dd8e1f
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/upgrade/dir825.sh
@@ -0,0 +1,165 @@
+#!/bin/sh
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+
+. /lib/functions.sh
+. /lib/ar71xx.sh
+
+get_magic_at() {
+	local mtddev=$1
+	local pos=$2
+	dd bs=1 count=2 skip=$pos if=$mtddev 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+dir825b_is_caldata_valid() {
+	local mtddev=$1
+	local magic
+
+	magic=$(get_magic_at $mtddev 4096)
+	[ "$magic" != "a55a" ] && return 0
+
+	magic=$(get_magic_at $mtddev 20480)
+	[ "$magic" != "a55a" ] && return 0
+
+	return 1
+}
+
+dir825b_copy_caldata() {
+	local cal_src=$1
+	local cal_dst=$2
+	local mtd_src
+	local mtd_dst
+	local md5_src
+	local md5_dst
+
+	mtd_src=$(find_mtd_part $cal_src)
+	[ -z "$mtd_src" ] && {
+		echo "no $cal_src partition found"
+		return 1
+	}
+
+	mtd_dst=$(find_mtd_part $cal_dst)
+	[ -z "$mtd_dst" ] && {
+		echo "no $cal_dst partition found"
+		return 1
+	}
+
+	dir825b_is_caldata_valid "$mtd_src" && {
+		echo "no valid calibration data found in $cal_src"
+		return 1
+	}
+
+	dir825b_is_caldata_valid "$mtd_dst" && {
+		echo "Copying calibration data from $cal_src to $cal_dst..."
+		dd if="$mtd_src" 2>/dev/null | mtd -q -q write - "$cal_dst"
+	}
+
+        md5_src=$(md5sum "$mtd_src") && md5_src="${md5_src%% *}"
+        md5_dst=$(md5sum "$mtd_dst") && md5_dst="${md5_dst%% *}"
+
+	[ "$md5_src" != "$md5_dst" ] && {
+		echo "calibration data mismatch $cal_src:$md5_src $cal_dst:$md5_dst"
+		return 1
+	}
+
+	return 0
+}
+
+dir825b_do_upgrade_combined() {
+	local fw_part=$1
+	local fw_file=$2
+	local fw_mtd=$(find_mtd_part $fw_part)
+	local fw_length=0x$(dd if="$fw_file" bs=2 skip=1 count=4 2>/dev/null)
+	local fw_blocks=$(($fw_length / 65536))
+
+	if [ -n "$fw_mtd" ] &&  [ ${fw_blocks:-0} -gt 0 ]; then
+		local append=""
+		[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR"
+
+		sync
+		dd if="$fw_file" bs=64k skip=1 count=$fw_blocks 2>/dev/null | \
+			mtd $append write - "$fw_part"
+	fi
+}
+
+dir825b_check_image() {
+	local magic="$(get_magic_long "$1")"
+	local fw_mtd=$(find_mtd_part "firmware_orig")
+
+	case "$magic" in
+	"27051956")
+		;;
+	"43493030")
+		local md5_img=$(dd if="$1" bs=2 skip=9 count=16 2>/dev/null)
+		local md5_chk=$(dd if="$1" bs=64k skip=1 2>/dev/null | md5sum -); md5_chk="${md5_chk%% *}"
+		local fw_len=$(dd if="$1" bs=2 skip=1 count=4 2>/dev/null)
+		local fw_part_len=$(mtd_get_part_size "firmware")
+
+		if [ -z "$fw_mtd" ]; then
+			ask_bool 0 "Do you have a backup of the caldata partition?" || {
+				echo "Warning, please make sure that you have a backup of the caldata partition."
+				echo "Once you have that, use 'sysupgrade -i' for upgrading to the 'fat' firmware."
+				return 1
+			}
+		fi
+
+		if [ -z "$md5_img" -o -z "$md5_chk" ]; then
+			echo "Unable to get image checksums. Maybe you are using a streamed image?"
+			return 1
+		fi
+
+		if [ "$md5_img" != "$md5_chk" ]; then
+			echo "Invalid image. Contents do not match checksum (image:$md5_img calculated:$md5_chk)"
+			return 1
+		fi
+
+		fw_len=$((0x$fw_len))
+		fw_part_len=${fw_part_len:-0}
+
+		if [ $fw_part_len -lt $fw_len ]; then
+			echo "The upgrade image is too big (size:$fw_len available:$fw_part_len)"
+			return 1
+		fi
+		;;
+	*)
+		echo "Unsupported image format."
+		return 1
+		;;
+	esac
+
+	return 0
+}
+
+platform_do_upgrade_dir825b() {
+	local magic="$(get_magic_long "$1")"
+	local fw_mtd=$(find_mtd_part "firmware_orig")
+
+	case "$magic" in
+	"27051956")
+		if [ -n "$fw_mtd" ]; then
+			# restore calibration data before downgrading to
+			# the normal image
+			dir825b_copy_caldata "caldata" "caldata_orig" || {
+				echo "unable to restore calibration data"
+				exit 1
+			}
+			PART_NAME="firmware_orig"
+		else
+			PART_NAME="firmware"
+		fi
+		default_do_upgrade "$ARGV"
+		;;
+	"43493030")
+		if [ -z "$fw_mtd" ]; then
+			# backup calibration data before upgrading to the
+			# fat image
+			dir825b_copy_caldata "caldata" "caldata_copy" || {
+				echo "unable to backup calibration data"
+				exit 1
+			}
+		fi
+		dir825b_do_upgrade_combined "firmware" "$ARGV"
+		;;
+	esac
+}
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh b/target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh
new file mode 100644
index 0000000000..78cde20a13
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/upgrade/merakinand.sh
@@ -0,0 +1,165 @@
+#!/bin/sh
+#
+# Copyright (C) 2015-2016 Chris Blake <chrisrblake93@gmail.com>
+#
+# Custom upgrade script for Meraki NAND devices (ex. MR18)
+# Based on dir825.sh and stock nand functions
+#
+. /lib/ar71xx.sh
+. /lib/functions.sh
+
+get_magic_at() {
+	local mtddev=$1
+	local pos=$2
+	dd bs=1 count=2 skip=$pos if=$mtddev 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+meraki_is_caldata_valid() {
+	local board=$1
+	local mtddev=$2
+	local magic
+
+	case "$board" in
+	"mr18")
+		magic=$(get_magic_at $mtddev 4096)
+		[ "$magic" != "0202" ] && return 0
+
+		magic=$(get_magic_at $mtddev 20480)
+		[ "$magic" != "0202" ] && return 0
+
+		magic=$(get_magic_at $mtddev 36864)
+		[ "$magic" != "0202" ] && return 0
+
+		return 1
+		;;
+	"z1")
+		magic=$(get_magic_at $mtddev 4096)
+		[ "$magic" != "0202" ] && return 0
+
+		magic=$(get_magic_at $mtddev 86016)
+		[ "$magic" != "a55a" ] && return 0
+
+		return 1
+		;;
+	*)
+		return 1
+		;;
+	esac
+}
+
+merakinand_copy_caldata() {
+	local cal_src=$1
+	local cal_dst=$2
+	local ubidev="$(nand_find_ubi $CI_UBIPART)"
+	local board_name="$(cat /tmp/sysinfo/board_name)"
+	local rootfs_size="$(ubinfo /dev/ubi0 -N rootfs_data | grep "Size" | awk '{ print $6 }')"
+
+	# Setup partitions using board name, in case of future platforms
+	case "$board_name" in
+	"mr18"|\
+	"z1")
+		# Src is MTD
+		mtd_src="$(find_mtd_chardev $cal_src)"
+		[ -n "$mtd_src" ] || {
+			echo "no mtd device found for partition $cal_src"
+			exit 1
+		}
+
+		# Dest is UBI
+		# TODO: possibly add create (hard to do when rootfs_data is expanded & mounted)
+		# Would need to be done from ramdisk
+		mtd_dst="$(nand_find_volume $ubidev $cal_dst)"
+		[ -n "$mtd_dst" ] || {
+			echo "no ubi device found for partition $cal_dst"
+			exit 1
+		}
+
+		meraki_is_caldata_valid "$board_name" "$mtd_src" && {
+			echo "no valid calibration data found in $cal_src"
+			exit 1
+		}
+
+		meraki_is_caldata_valid "$board_name" "/dev/$mtd_dst" && {
+			echo "Copying calibration data from $cal_src to $cal_dst..."
+			dd if="$mtd_src" of=/tmp/caldata.tmp 2>/dev/null
+			ubiupdatevol "/dev/$mtd_dst" /tmp/caldata.tmp
+			rm /tmp/caldata.tmp
+			sync
+		}
+		return 0
+		;;
+	*)
+		echo "Unsupported device $board_name";
+		return 1
+		;;
+	esac
+}
+
+merakinand_do_kernel_check() {
+	local board_name="$1"
+	local tar_file="$2"
+	local image_magic_word=`(tar xf $tar_file sysupgrade-$board_name/kernel -O 2>/dev/null | dd bs=1 count=4 skip=0 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"')`
+
+	# What is our kernel magic string?
+	case "$board_name" in
+	"mr18")
+		[ "$image_magic_word" == "8e73ed8a" ] && {
+			echo "pass" && return 0
+		}
+		;;
+	"z1")
+		[ "$image_magic_word" == "4d495053" ] && {
+			echo "pass" && return 0
+		}
+		;;
+	esac
+
+	exit 1
+}
+
+merakinand_do_platform_check() {
+	local board_name="$1"
+	local tar_file="$2"
+	local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
+	local file_type="$(identify_tar $2 sysupgrade-$board_name/root)"
+	local kernel_magic="$(merakinand_do_kernel_check $1 $2)"
+
+	case "$board_name" in
+	"mr18"|\
+	"z1")
+		[ "$control_length" = 0 -o "$file_type" != "squashfs" -o "$kernel_magic" != "pass" ] && {
+			echo "Invalid sysupgrade file for $board_name"
+			return 1
+		}
+		;;
+	*)
+		echo "Unsupported device $board_name";
+		return 1
+		;;
+	esac
+
+	return 0
+}
+
+merakinand_do_upgrade() {
+	local tar_file="$1"
+	local board_name="$(cat /tmp/sysinfo/board_name)"
+
+	# Do we need to do any platform tweaks?
+	case "$board_name" in
+	"mr18")
+		# Check and create UBI caldata if it's invalid
+		merakinand_copy_caldata "odm-caldata" "caldata"
+		nand_do_upgrade $1
+		;;
+	"z1")
+		# Check and create UBI caldata if it's invalid
+		merakinand_copy_caldata "origcaldata" "caldata"
+		nand_do_upgrade $1
+		;;
+	*)
+		echo "Unsupported device $board_name";
+		exit 1
+		;;
+	esac
+}
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh b/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh
new file mode 100644
index 0000000000..87b65165b4
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/upgrade/openmesh.sh
@@ -0,0 +1,233 @@
+# The U-Boot loader of the OpenMesh devices requires image sizes and
+# checksums to be provided in the U-Boot environment.
+# The OpenMesh devices come with 2 main partitions - while one is active
+# sysupgrade will flash the other. The boot order is changed to boot the
+# newly flashed partition. If the new partition can't be booted due to
+# upgrade failures the previously used partition is loaded.
+
+trim()
+{
+	echo $1
+}
+
+cfg_value_get()
+{
+	local cfg=$1 cfg_opt
+	local section=$2 our_section=0
+	local param=$3 our_param=
+
+	for cfg_opt in $cfg
+		do
+			[ "$cfg_opt" = "[$section]" ] && our_section=1 && continue
+			[ "$our_section" = "1" ] || continue
+
+			our_param=$(echo ${cfg_opt%%=*})
+			[ "$param" = "$our_param" ] && echo ${cfg_opt##*=} && break
+		done
+}
+
+# make sure we got uboot-envtools and fw_env.config copied over to the ramfs
+# create /var/lock for the lock "fw_setenv.lock" of fw_setenv
+platform_add_ramfs_ubootenv()
+{
+	[ -e /usr/sbin/fw_printenv ] && install_bin /usr/sbin/fw_printenv /usr/sbin/fw_setenv
+	[ -e /etc/fw_env.config ] && install_file /etc/fw_env.config
+	mkdir -p $RAM_ROOT/var/lock
+}
+append sysupgrade_pre_upgrade platform_add_ramfs_ubootenv
+
+platform_check_image_target_openmesh()
+{
+	img_board_target="$1"
+
+	case "$img_board_target" in
+		OM2P)
+			[ "$board" = "om2p" ] && return 0
+			[ "$board" = "om2pv2" ] && return 0
+			[ "$board" = "om2p-lc" ] && return 0
+			[ "$board" = "om2p-hs" ] && return 0
+			[ "$board" = "om2p-hsv2" ] && return 0
+			[ "$board" = "om2p-hsv3" ] && return 0
+			echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
+			return 1
+			;;
+		OM5P)
+			[ "$board" = "om5p" ] && return 0
+			[ "$board" = "om5p-an" ] && return 0
+			echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
+			return 1
+			;;
+		OM5PAC)
+			[ "$board" = "om5p-ac" ] && return 0
+			[ "$board" = "om5p-acv2" ] && return 0
+			echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
+			return 1
+			;;
+		MR1750)
+			[ "$board" = "mr1750" ] && return 0
+			[ "$board" = "mr1750v2" ] && return 0
+			echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
+			return 1
+			;;
+		MR600)
+			[ "$board" = "mr600" ] && return 0
+			[ "$board" = "mr600v2" ] && return 0
+			echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
+			return 1
+			;;
+		MR900)
+			[ "$board" = "mr900" ] && return 0
+			[ "$board" = "mr900v2" ] && return 0
+			echo "Invalid image board target ($img_board_target) for this platform: $board. Use the correct image for this platform"
+			return 1
+			;;
+		*)
+			echo "Invalid board target ($img_board_target). Use the correct image for this platform"
+			return 1
+			;;
+	esac
+}
+
+platform_check_image_openmesh()
+{
+	local img_magic=$1
+	local img_path=$2
+	local fw_printenv=/usr/sbin/fw_printenv
+	local img_board_target= img_num_files= i=0
+	local cfg_name= kernel_name= rootfs_name=
+
+	case "$img_magic" in
+		# Combined Extended Image v1
+		43453031)
+			img_board_target=$(trim $(dd if="$img_path" bs=4 skip=1 count=8 2>/dev/null))
+			img_num_files=$(trim $(dd if="$img_path" bs=2 skip=18 count=1 2>/dev/null))
+			;;
+		*)
+			echo "Invalid image ($img_magic). Use combined extended images on this platform"
+			return 1
+			;;
+	esac
+
+	platform_check_image_target_openmesh "$img_board_target" || return 1
+
+	[ $img_num_files -lt 3 ] && {
+		echo "Invalid number of embedded images ($img_num_files). Use the correct image for this platform"
+		return 1
+	}
+
+	cfg_name=$(trim $(dd if="$img_path" bs=2 skip=19 count=16 2>/dev/null))
+
+	[ "$cfg_name" != "fwupgrade.cfg" ] && {
+		echo "Invalid embedded config file ($cfg_name). Use the correct image for this platform"
+		return 1
+	}
+
+	kernel_name=$(trim $(dd if="$img_path" bs=2 skip=55 count=16 2>/dev/null))
+
+	[ "$kernel_name" != "kernel" ] && {
+		echo "Invalid embedded kernel file ($kernel_name). Use the correct image for this platform"
+		return 1
+	}
+
+	rootfs_name=$(trim $(dd if="$img_path" bs=2 skip=91 count=16 2>/dev/null))
+
+	[ "$rootfs_name" != "rootfs" ] && {
+		echo "Invalid embedded kernel file ($rootfs_name). Use the correct image for this platform"
+		return 1
+	}
+
+	[ ! -x "$fw_printenv" ] && {
+		echo "Please install uboot-envtools!"
+		return 1
+	}
+
+	[ ! -r "/etc/fw_env.config" ] && {
+		echo "/etc/fw_env.config is missing"
+		return 1
+	}
+
+	return 0
+}
+
+platform_do_upgrade_openmesh()
+{
+	local img_path=$1 img_board_target=
+	local kernel_start_addr= kernel_start_addr1= kernel_start_addr2=
+	local kernel_size= kernel_md5=
+	local rootfs_size= rootfs_checksize= rootfs_md5=
+	local kernel_bsize= total_size=
+	local data_offset=$((64 * 1024)) block_size= offset=
+	local uboot_env_upgrade="/tmp/fw_env_upgrade"
+	local cfg_size= kernel_size= rootfs_size=
+	local append=""
+
+	[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR"
+
+	cfg_size=$(dd if="$img_path" bs=2 skip=35 count=4 2>/dev/null)
+	kernel_size=$(dd if="$img_path" bs=2 skip=71 count=4 2>/dev/null)
+	rootfs_size=$(dd if="$img_path" bs=2 skip=107 count=4 2>/dev/null)
+
+	img_board_target=$(trim $(dd if="$img_path" bs=4 skip=1 count=8 2>/dev/null))
+	cfg_content=$(dd if="$img_path" bs=1 skip=$data_offset count=$(echo $((0x$cfg_size))) 2>/dev/null)
+
+	case $img_board_target in
+		OM2P)
+			block_size=$((256 * 1024))
+			total_size=7340032
+			kernel_start_addr1=0x9f1c0000
+			kernel_start_addr2=0x9f8c0000
+			;;
+		OM5P|OM5PAC|MR600|MR900|MR1750)
+			block_size=$((64 * 1024))
+			total_size=7995392
+			kernel_start_addr1=0x9f0b0000
+			kernel_start_addr2=0x9f850000
+			;;
+	esac
+
+	kernel_md5=$(cfg_value_get "$cfg_content" "vmlinux" "md5sum")
+	rootfs_md5=$(cfg_value_get "$cfg_content" "rootfs" "md5sum")
+	rootfs_checksize=$(cfg_value_get "$cfg_content" "rootfs" "checksize")
+
+	if [ "$((0x$kernel_size % $block_size))" = "0" ]
+		then
+			kernel_bsize=$(echo $((0x$kernel_size)))
+		else
+			kernel_bsize=$((0x$kernel_size + ($block_size - (0x$kernel_size % $block_size))))
+	fi
+
+	mtd -q erase inactive
+
+	offset=$(echo $(($data_offset + 0x$cfg_size + 0x$kernel_size)))
+	dd if="$img_path" bs=1 skip=$offset count=$(echo $((0x$rootfs_size))) 2>&- | mtd -n -p $kernel_bsize $append write - "inactive"
+
+	offset=$(echo $(($data_offset + 0x$cfg_size)))
+	dd if="$img_path" bs=1 skip=$offset count=$(echo $((0x$kernel_size))) 2>&- | mtd -n write - "inactive"
+
+	rm $uboot_env_upgrade 2>&-
+
+	if [ "$(grep 'mtd3:.*inactive' /proc/mtd)" ]
+		then
+			printf "kernel_size_1 %u\n" $(($kernel_bsize / 1024)) >> $uboot_env_upgrade
+			printf "rootfs_size_1 %u\n" $((($total_size - $kernel_bsize) / 1024)) >> $uboot_env_upgrade
+			printf "bootseq 1,2\n" >> $uboot_env_upgrade
+			kernel_start_addr=$kernel_start_addr1
+		else
+			printf "kernel_size_2 %u\n" $(($kernel_bsize / 1024)) >> $uboot_env_upgrade
+			printf "rootfs_size_2 %u\n" $((($total_size - $kernel_bsize) / 1024)) >> $uboot_env_upgrade
+			printf "bootseq 2,1\n" >> $uboot_env_upgrade
+			kernel_start_addr=$kernel_start_addr2
+	fi
+
+	printf "vmlinux_start_addr %s\n" $kernel_start_addr >> $uboot_env_upgrade
+	printf "vmlinux_size 0x%s\n" $kernel_size >> $uboot_env_upgrade
+	printf "vmlinux_checksum %s\n" $kernel_md5 >> $uboot_env_upgrade
+	printf "rootfs_start_addr 0x%x\n" $(($kernel_start_addr + $kernel_bsize)) >> $uboot_env_upgrade
+	printf "rootfs_size %s\n" $rootfs_checksize >> $uboot_env_upgrade
+	printf "rootfs_checksum %s\n" $rootfs_md5 >> $uboot_env_upgrade
+
+	fw_setenv -s $uboot_env_upgrade || {
+		echo "failed to update U-Boot environment"
+		return 1
+	}
+}
diff --git a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
new file mode 100755
index 0000000000..5f4375da6a
--- /dev/null
+++ b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
@@ -0,0 +1,653 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+
+. /lib/functions/system.sh
+. /lib/ar71xx.sh
+
+PART_NAME=firmware
+RAMFS_COPY_DATA=/lib/ar71xx.sh
+
+CI_BLKSZ=65536
+CI_LDADR=0x80060000
+
+platform_find_partitions() {
+	local first dev size erasesize name
+	while read dev size erasesize name; do
+		name=${name#'"'}; name=${name%'"'}
+		case "$name" in
+			vmlinux.bin.l7|vmlinux|kernel|linux|linux.bin|rootfs|filesystem)
+				if [ -z "$first" ]; then
+					first="$name"
+				else
+					echo "$erasesize:$first:$name"
+					break
+				fi
+			;;
+		esac
+	done < /proc/mtd
+}
+
+platform_find_kernelpart() {
+	local part
+	for part in "${1%:*}" "${1#*:}"; do
+		case "$part" in
+			vmlinux.bin.l7|vmlinux|kernel|linux|linux.bin)
+				echo "$part"
+				break
+			;;
+		esac
+	done
+}
+
+platform_do_upgrade_combined() {
+	local partitions=$(platform_find_partitions)
+	local kernelpart=$(platform_find_kernelpart "${partitions#*:}")
+	local erase_size=$((0x${partitions%%:*})); partitions="${partitions#*:}"
+	local kern_length=0x$(dd if="$1" bs=2 skip=1 count=4 2>/dev/null)
+	local kern_blocks=$(($kern_length / $CI_BLKSZ))
+	local root_blocks=$((0x$(dd if="$1" bs=2 skip=5 count=4 2>/dev/null) / $CI_BLKSZ))
+
+	if [ -n "$partitions" ] && [ -n "$kernelpart" ] && \
+	   [ ${kern_blocks:-0} -gt 0 ] && \
+	   [ ${root_blocks:-0} -gt 0 ] && \
+	   [ ${erase_size:-0} -gt 0 ];
+	then
+		local append=""
+		[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR"
+
+		( dd if="$1" bs=$CI_BLKSZ skip=1 count=$kern_blocks 2>/dev/null; \
+		  dd if="$1" bs=$CI_BLKSZ skip=$((1+$kern_blocks)) count=$root_blocks 2>/dev/null ) | \
+			mtd -r $append -F$kernelpart:$kern_length:$CI_LDADR,rootfs write - $partitions
+	fi
+}
+
+tplink_get_image_hwid() {
+	get_image "$@" | dd bs=4 count=1 skip=16 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+tplink_get_image_mid() {
+	get_image "$@" | dd bs=4 count=1 skip=17 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+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"'
+}
+
+wrgg_get_image_magic() {
+	get_image "$@" | dd bs=4 count=1 skip=8 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+}
+
+cybertan_get_image_magic() {
+	get_image "$@" | dd bs=8 count=1 skip=0  2>/dev/null | hexdump -v -n 8 -e '1/1 "%02x"'
+}
+
+cybertan_check_image() {
+	local magic="$(cybertan_get_image_magic "$1")"
+	local fw_magic="$(cybertan_get_hw_magic)"
+
+	[ "$fw_magic" != "$magic" ] && {
+		echo "Invalid image, ID mismatch, got:$magic, but need:$fw_magic"
+		return 1
+	}
+
+	return 0
+}
+
+platform_do_upgrade_compex() {
+	local fw_file=$1
+	local fw_part=$PART_NAME
+	local fw_mtd=$(find_mtd_part $fw_part)
+	local fw_length=0x$(dd if="$fw_file" bs=2 skip=1 count=4 2>/dev/null)
+	local fw_blocks=$(($fw_length / 65536))
+
+	if [ -n "$fw_mtd" ] &&  [ ${fw_blocks:-0} -gt 0 ]; then
+		local append=""
+		[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 ] && append="-j $CONF_TAR"
+
+		sync
+		dd if="$fw_file" bs=64k skip=1 count=$fw_blocks 2>/dev/null | \
+			mtd $append write - "$fw_part"
+	fi
+}
+
+alfa_check_image() {
+	local magic_long="$(get_magic_long "$1")"
+	local fw_part_size=$(mtd_get_part_size firmware)
+
+	case "$magic_long" in
+	"27051956")
+		[ "$fw_part_size" != "16318464" ] && {
+			echo "Invalid image magic \"$magic_long\" for $fw_part_size bytes"
+			return 1
+		}
+		;;
+	"68737173")
+		[ "$fw_part_size" != "7929856" ] && {
+			echo "Invalid image magic \"$magic_long\" for $fw_part_size bytes"
+			return 1
+		}
+		;;
+	esac
+
+	return 0
+}
+
+platform_check_image() {
+	local board=$(ar71xx_board_name)
+	local magic="$(get_magic_word "$1")"
+	local magic_long="$(get_magic_long "$1")"
+
+	[ "$#" -gt 1 ] && return 1
+
+	case "$board" in
+	airgatewaypro|\
+	airgateway|\
+	airrouter|\
+	ap132|\
+	ap81|\
+	ap83|\
+	ap90q|\
+	bullet-m|\
+	c-55|\
+	carambola2|\
+	cf-e316n-v2|\
+	cf-e320n-v2|\
+	cf-e380ac-v1|\
+	cf-e380ac-v2|\
+	cf-e520n|\
+	cf-e530n|\
+	cpe830|\
+	cpe870|\
+	dgl-5500-a1|\
+	dhp-1565-a1|\
+	dir-505-a1|\
+	dir-600-a1|\
+	dir-615-c1|\
+	dir-615-e1|\
+	dir-615-e4|\
+	dir-615-i1|\
+	dir-825-c1|\
+	dir-835-a1|\
+	dlan-hotspot|\
+	dlan-pro-1200-ac|\
+	dlan-pro-500-wp|\
+	dr531|\
+	dragino2|\
+	epg5000|\
+	esr1750|\
+	esr900|\
+	ew-dorin-router|\
+	ew-dorin|\
+	gl-ar150|\
+	gl-ar300m|\
+	gl-ar300|\
+	gl-domino|\
+	gl-mifi|\
+	hiwifi-hc6361|\
+	hornet-ub-x2|\
+	jwap230|\
+	loco-m-xw|\
+	mzk-w04nu|\
+	mzk-w300nh|\
+	nanostation-m-xw|\
+	nanostation-m|\
+	nbg460n_550n_550nh|\
+	rocket-m-ti|\
+	rocket-m-xw|\
+	rocket-m|\
+	rw2458n|\
+	tew-632brp|\
+	tew-712br|\
+	tew-732br|\
+	tew-823dru|\
+	unifi-outdoor|\
+	unifiac-lite|\
+	unifiac-pro|\
+	unifi|\
+	weio|\
+	whr-g301n|\
+	whr-hp-g300n|\
+	whr-hp-gn|\
+	wlae-ag300n|\
+	wndap360|\
+	wpj342|\
+	wpj344|\
+	wpj531|\
+	wrt400n|\
+	wrtnode2q|\
+	wzr-450hp2|\
+	wzr-hp-ag300h|\
+	wzr-hp-g300nh2|\
+	wzr-hp-g300nh|\
+	wzr-hp-g450h)
+		[ "$magic" != "2705" ] && {
+			echo "Invalid image type."
+			return 1
+		}
+
+		return 0
+		;;
+	alfa-ap96|\
+	alfa-nx|\
+	ap113|\
+	ap121-mini|\
+	ap121|\
+	ap135-020|\
+	ap136-010|\
+	ap136-020|\
+	ap147-010|\
+	ap152|\
+	ap96|\
+	arduino-yun|\
+	bhr-4grv2|\
+	bxu2000n-2-a1|\
+	db120|\
+	dr344|\
+	dw33d|\
+	f9k1115v2|\
+	hornet-ub|\
+	mr12|\
+	mr16|\
+	wpj558|\
+	zbt-we1526|\
+	zcn-1523h-2|\
+	zcn-1523h-5)
+		[ "$magic_long" != "68737173" -a "$magic_long" != "19852003" ] && {
+			echo "Invalid image type."
+			return 1
+		}
+
+		return 0
+		;;
+	all0258n|\
+	all0315n|\
+	cap324|\
+	cap4200ag|\
+	cr3000|\
+	cr5000)
+		platform_check_image_allnet "$1" && return 0
+		return 1
+		;;
+	all0305|\
+	eap300v2|\
+	eap7660d|\
+	ja76pf2|\
+	ja76pf|\
+	jwap003|\
+	ls-sr71|\
+	pb42|\
+	pb44|\
+	routerstation-pro|\
+	routerstation|\
+	wp543|\
+	wpe72)
+		[ "$magic" != "4349" ] && {
+			echo "Invalid image. Use *-sysupgrade.bin files on this board"
+			return 1
+		}
+
+		local md5_img=$(dd if="$1" bs=2 skip=9 count=16 2>/dev/null)
+		local md5_chk=$(dd if="$1" bs=$CI_BLKSZ skip=1 2>/dev/null | md5sum -); md5_chk="${md5_chk%% *}"
+
+		if [ -n "$md5_img" -a -n "$md5_chk" ] && [ "$md5_img" = "$md5_chk" ]; then
+			return 0
+		else
+			echo "Invalid image. Contents do not match checksum (image:$md5_img calculated:$md5_chk)"
+			return 1
+		fi
+
+		return 0
+		;;
+	antminer-s1|\
+	antminer-s3|\
+	antrouter-r1|\
+	archer-c5|\
+	archer-c7|\
+	el-m150|\
+	el-mini|\
+	gl-inet|\
+	mc-mac1200r|\
+	minibox-v1|\
+	omy-g1|\
+	omy-x1|\
+	onion-omega|\
+	oolite|\
+	smart-300|\
+	som9331|\
+	tellstick-znet-lite|\
+	tl-mr10u|\
+	tl-mr11u|\
+	tl-mr12u|\
+	tl-mr13u|\
+	tl-mr3020|\
+	tl-mr3040-v2|\
+	tl-mr3040|\
+	tl-mr3220-v2|\
+	tl-mr3220|\
+	tl-mr3420-v2|\
+	tl-mr3420|\
+	tl-wa701nd-v2|\
+	tl-wa7210n-v2|\
+	tl-wa750re|\
+	tl-wa7510n|\
+	tl-wa801nd-v2|\
+	tl-wa801nd-v3|\
+	tl-wa830re-v2|\
+	tl-wa850re|\
+	tl-wa860re|\
+	tl-wa901nd-v2|\
+	tl-wa901nd-v3|\
+	tl-wa901nd-v4|\
+	tl-wa901nd|\
+	tl-wdr3320-v2|\
+	tl-wdr3500|\
+	tl-wdr4300|\
+	tl-wdr4900-v2|\
+	tl-wdr6500-v2|\
+	tl-wpa8630|\
+	tl-wr1041n-v2|\
+	tl-wr1043nd-v2|\
+	tl-wr1043nd|\
+	tl-wr2543n|\
+	tl-wr703n|\
+	tl-wr710n|\
+	tl-wr720n-v3|\
+	tl-wr741nd-v4|\
+	tl-wr741nd|\
+	tl-wr802n-v1|\
+	tl-wr810n|\
+	tl-wr841n-v11|\
+	tl-wr841n-v1|\
+	tl-wr841n-v7|\
+	tl-wr841n-v8|\
+	tl-wr841n-v9|\
+	tl-wr842n-v2|\
+	tl-wr842n-v3|\
+	tl-wr941nd-v5|\
+	tl-wr941nd-v6|\
+	tl-wr941nd)
+		local magic_ver="0100"
+
+		case "$board" in
+		tl-wdr6500-v2)
+			magic_ver="0200"
+			;;
+		esac
+
+		[ "$magic" != "$magic_ver" ] && {
+			echo "Invalid image type."
+			return 1
+		}
+
+		local hwid
+		local mid
+		local imagehwid
+		local imagemid
+
+		hwid=$(tplink_get_hwid)
+		mid=$(tplink_get_mid)
+		imagehwid=$(tplink_get_image_hwid "$1")
+		imagemid=$(tplink_get_image_mid "$1")
+
+		[ "$hwid" != "$imagehwid" -o "$mid" != "$imagemid" ] && {
+			echo "Invalid image, hardware ID mismatch, hw:$hwid $mid image:$imagehwid $imagemid."
+			return 1
+		}
+
+		local boot_size
+
+		boot_size=$(tplink_get_image_boot_size "$1")
+		[ "$boot_size" != "00000000" ] && {
+			echo "Invalid image, it contains a bootloader."
+			return 1
+		}
+
+		return 0
+		;;
+	bsb|\
+	dir-825-b1|\
+	tew-673gru)
+		dir825b_check_image "$1" && return 0
+		;;
+	c-60|\
+	nbg6716|\
+	r6100|\
+	wndr3700v4|\
+	wndr4300)
+		nand_do_platform_check $board $1
+		return $?
+		;;
+	cpe210|\
+	cpe510|\
+	eap120)
+		tplink_pharos_check_image "$1" && return 0
+		return 1
+		;;
+	mr1750v2|\
+	mr1750|\
+	mr600v2|\
+	mr600|\
+	mr900v2|\
+	mr900|\
+	om2p-hsv2|\
+	om2p-hsv3|\
+	om2p-hs|\
+	om2p-lc|\
+	om2pv2|\
+	om2p|\
+	om5p-acv2|\
+	om5p-ac|\
+	om5p-an|\
+	om5p)
+		platform_check_image_openmesh "$magic_long" "$1" && return 0
+		return 1
+		;;
+	mr18|\
+	z1)
+		merakinand_do_platform_check $board $1
+		return $?
+		;;
+	dir-869-a1|\
+	mynet-n600|\
+	mynet-n750|\
+	qihoo-c301)
+		[ "$magic_long" != "5ea3a417" ] && {
+			echo "Invalid image, bad magic: $magic_long"
+			return 1
+		}
+
+		local typemagic=$(seama_get_type_magic "$1")
+		[ "$typemagic" != "6669726d" ] && {
+			echo "Invalid image, bad type: $typemagic"
+			return 1
+		}
+
+		return 0
+		;;
+	mynet-rext|\
+	wrt160nl)
+		cybertan_check_image "$1" && return 0
+		return 1
+		;;
+	nbg6616|\
+	uap-pro|\
+	unifi-outdoor-plus)
+		[ "$magic_long" != "19852003" ] && {
+			echo "Invalid image type."
+			return 1
+		}
+
+		return 0
+		;;
+	tube2h)
+		alfa_check_image "$1" && return 0
+		return 1
+		;;
+	wndr3700|\
+	wnr1000-v2|\
+	wnr2000-v3|\
+	wnr612-v2|\
+	wpn824n)
+		local hw_magic
+
+		hw_magic="$(ar71xx_get_mtd_part_magic firmware)"
+		[ "$magic_long" != "$hw_magic" ] && {
+			echo "Invalid image, hardware ID mismatch, hw:$hw_magic image:$magic_long."
+			return 1
+		}
+
+		return 0
+		;;
+	wnr2000-v4)
+		[ "$magic_long" != "32303034" ] && {
+			echo "Invalid image type."
+			return 1
+		}
+
+		return 0
+		;;
+	wnr2200)
+		[ "$magic_long" != "32323030" ] && {
+			echo "Invalid image type."
+			return 1
+		}
+
+		return 0
+		;;
+	dap-2695-a1)
+		local magic=$(wrgg_get_image_magic "$1")
+		[ "$magic" != "21030820" ] && {
+			echo "Invalid image, bad type: $magic"
+			return 1
+		}
+
+		return 0;
+		;;
+	esac
+
+	echo "Sysupgrade is not yet supported on $board."
+	return 1
+}
+
+platform_pre_upgrade() {
+	local board=$(ar71xx_board_name)
+
+	case "$board" in
+	c-60|\
+	nbg6716|\
+	r6100|\
+	wndr3700v4|\
+	wndr4300)
+		nand_do_upgrade "$1"
+		;;
+	mr18|\
+	z1)
+		merakinand_do_upgrade "$1"
+		;;
+	esac
+}
+
+platform_do_upgrade() {
+	local board=$(ar71xx_board_name)
+
+	case "$board" in
+	all0258n)
+		platform_do_upgrade_allnet "0x9f050000" "$ARGV"
+		;;
+	all0305|\
+	eap7660d|\
+	ja76pf2|\
+	ja76pf|\
+	jwap003|\
+	ls-sr71|\
+	pb42|\
+	pb44|\
+	routerstation-pro|\
+	routerstation)
+		platform_do_upgrade_combined "$ARGV"
+		;;
+	all0315n)
+		platform_do_upgrade_allnet "0x9f080000" "$ARGV"
+		;;
+	cap4200ag|\
+	eap300v2)
+		platform_do_upgrade_allnet "0xbf0a0000" "$ARGV"
+		;;
+	dir-825-b1|\
+	tew-673gru)
+		platform_do_upgrade_dir825b "$ARGV"
+		;;
+	mr1750v2|\
+	mr1750|\
+	mr600v2|\
+	mr600|\
+	mr900v2|\
+	mr900|\
+	om2p-hsv2|\
+	om2p-hsv3|\
+	om2p-hs|\
+	om2p-lc|\
+	om2pv2|\
+	om2p|\
+	om5p-acv2|\
+	om5p-ac|\
+	om5p-an|\
+	om5p)
+		platform_do_upgrade_openmesh "$ARGV"
+		;;
+	uap-pro|\
+	unifi-outdoor-plus)
+		MTD_CONFIG_ARGS="-s 0x180000"
+		default_do_upgrade "$ARGV"
+		;;
+	wp543|\
+	wpe72)
+		platform_do_upgrade_compex "$ARGV"
+		;;
+	*)
+		default_do_upgrade "$ARGV"
+		;;
+	esac
+}
+
+disable_watchdog() {
+	killall watchdog
+	( ps | grep -v 'grep' | grep '/dev/watchdog' ) && {
+		echo 'Could not disable watchdog'
+		return 1
+	}
+}
+
+append sysupgrade_pre_upgrade disable_watchdog
diff --git a/target/linux/ar71xx/base-files/sbin/wget2nand b/target/linux/ar71xx/base-files/sbin/wget2nand
new file mode 100755
index 0000000000..c80e21ccc7
--- /dev/null
+++ b/target/linux/ar71xx/base-files/sbin/wget2nand
@@ -0,0 +1,85 @@
+#!/bin/sh
+# wget2nand
+# This script can be used to download a TGZ file from your build system which
+# contains the files to be installed on the NAND flash on your RB1xx card.
+# The one parameter is the URL of the TGZ file to be downloaded.
+# Licence GPL V2
+# Author david.goodenough@linkchoose.co.uk
+# Based on cf2nand from RB532 support
+. /lib/functions.sh
+
+wget2nand_dir=/tmp/wget2nand
+mnt_kernel=$wget2nand_dir/mnt_kernel
+mnt_rootfs=$wget2nand_dir/mnt_rootfs
+src_rootfs=$wget2nand_dir/rootfs.tgz
+src_kernel=$wget2nand_dir/kernel
+
+[ -d "$wget2nand_dir" ] && {
+	echo "$wget2nand_dir already exists"
+	exit 1
+}
+
+# need to find the wget server from the command line
+url=$1
+[ -z "$url" ] && {
+        echo "No URL specified for image TGZ"
+        echo "Usage : $0 URL"
+        exit 1
+}
+
+url_kernel=$url/lede-ar71xx-mikrotik-vmlinux-lzma.elf
+url_rootfs=$url/lede-ar71xx-mikrotik-defaultnowifi-rootfs.tar.gz
+
+mtd_kernel="$(find_mtd_part 'kernel')"
+mtd_rootfs="$(find_mtd_part 'rootfs')"
+[ -z "$mtd_kernel" -o -z "$mtd_rootfs" ] && {
+	echo "Cannot find NAND Flash partitions"
+	exit 1
+}
+
+mkdir "$wget2nand_dir"
+wget $url_kernel -O "$src_kernel" || {
+	echo "Unable to download $url_kernel"
+	exit 1
+}
+
+wget $url_rootfs -O "$src_rootfs" || {
+	echo "Unable to download $url_rootfs"
+	exit 1
+}
+
+echo "Erasing filesystem..."
+mtd erase kernel 2>/dev/null >/dev/null
+mtd erase rootfs 2>/dev/null >/dev/null
+
+echo "Mounting $mtd_rootfs as new root and $mtd_kernel as kernel partition"
+
+mkdir "$mnt_kernel"
+mkdir "$mnt_rootfs"
+mount -t yaffs2 "$mtd_kernel" "$mnt_kernel"
+mount -t yaffs2 "$mtd_rootfs" "$mnt_rootfs"
+
+echo "Copying kernel..."
+cp $src_kernel $mnt_kernel/kernel || {
+       echo "Error occured while copying the kernel"
+       exit 1
+}
+chmod +x $mnt_kernel/kernel
+
+echo "Preparing filesystem..."
+( cd "$mnt_rootfs"; tar xvz -f "$src_rootfs" )
+
+# make sure everything is written before we unmount the partitions
+echo "chmod ugo+x /" > $mnt_rootfs/etc/uci-defaults/set_root_permission
+sync
+ls $mnt_kernel >/dev/null
+ls $mnt_rootfs >/dev/null
+
+echo "Cleaning up..."
+# unmount the partitions and remove the directories into which they were mounted
+umount $mnt_kernel
+umount $mnt_rootfs
+rm -rf $wget2nand_dir
+
+# all done
+echo "Image written, you can now reboot.  Remember to change the boot source to Boot from Nand"
diff --git a/target/linux/ar71xx/config-4.4 b/target/linux/ar71xx/config-4.4
new file mode 100644
index 0000000000..c6a757a7eb
--- /dev/null
+++ b/target/linux/ar71xx/config-4.4
@@ -0,0 +1,443 @@
+CONFIG_AG71XX=y
+CONFIG_AG71XX_AR8216_SUPPORT=y
+# CONFIG_AG71XX_DEBUG is not set
+# CONFIG_AG71XX_DEBUG_FS is not set
+CONFIG_AR8216_PHY=y
+CONFIG_AR8216_PHY_LEDS=y
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_AT803X_PHY=y
+CONFIG_ATH79=y
+CONFIG_ATH79_DEV_AP9X_PCI=y
+CONFIG_ATH79_DEV_DSA=y
+CONFIG_ATH79_DEV_ETH=y
+CONFIG_ATH79_DEV_GPIO_BUTTONS=y
+CONFIG_ATH79_DEV_LEDS_GPIO=y
+CONFIG_ATH79_DEV_M25P80=y
+CONFIG_ATH79_DEV_NFC=y
+CONFIG_ATH79_DEV_SPI=y
+CONFIG_ATH79_DEV_USB=y
+CONFIG_ATH79_DEV_WMAC=y
+CONFIG_ATH79_MACH_ALFA_AP120C=y
+CONFIG_ATH79_MACH_ALFA_AP96=y
+CONFIG_ATH79_MACH_ALFA_NX=y
+CONFIG_ATH79_MACH_ALL0258N=y
+CONFIG_ATH79_MACH_ALL0315N=y
+CONFIG_ATH79_MACH_ANTMINER_S1=y
+CONFIG_ATH79_MACH_ANTMINER_S3=y
+CONFIG_ATH79_MACH_ANTROUTER_R1=y
+CONFIG_ATH79_MACH_AP113=y
+CONFIG_ATH79_MACH_AP121=y
+CONFIG_ATH79_MACH_AP132=y
+CONFIG_ATH79_MACH_AP136=y
+CONFIG_ATH79_MACH_AP143=y
+CONFIG_ATH79_MACH_AP147=y
+CONFIG_ATH79_MACH_AP152=y
+CONFIG_ATH79_MACH_AP81=y
+CONFIG_ATH79_MACH_AP83=y
+CONFIG_ATH79_MACH_AP90Q=y
+CONFIG_ATH79_MACH_AP96=y
+CONFIG_ATH79_MACH_ARCHER_C7=y
+CONFIG_ATH79_MACH_ARDUINO_YUN=y
+CONFIG_ATH79_MACH_AW_NR580=y
+CONFIG_ATH79_MACH_BHR_4GRV2=y
+CONFIG_ATH79_MACH_BHU_BXU2000N2_A=y
+CONFIG_ATH79_MACH_BSB=y
+CONFIG_ATH79_MACH_C55=y
+CONFIG_ATH79_MACH_C60=y
+CONFIG_ATH79_MACH_CAP324=y
+CONFIG_ATH79_MACH_CAP4200AG=y
+CONFIG_ATH79_MACH_CARAMBOLA2=y
+CONFIG_ATH79_MACH_CF_E316N_V2=y
+CONFIG_ATH79_MACH_CF_E320N_V2=y
+CONFIG_ATH79_MACH_CF_E380AC_V1=y
+CONFIG_ATH79_MACH_CF_E380AC_V2=y
+CONFIG_ATH79_MACH_CF_E520N=y
+CONFIG_ATH79_MACH_CF_E530N=y
+CONFIG_ATH79_MACH_CPE510=y
+CONFIG_ATH79_MACH_CPE830=y
+CONFIG_ATH79_MACH_CPE870=y
+CONFIG_ATH79_MACH_CR3000=y
+CONFIG_ATH79_MACH_CR5000=y
+CONFIG_ATH79_MACH_DAP_2695_A1=y
+CONFIG_ATH79_MACH_DB120=y
+CONFIG_ATH79_MACH_DGL_5500_A1=y
+CONFIG_ATH79_MACH_DHP_1565_A1=y
+CONFIG_ATH79_MACH_DIR_505_A1=y
+CONFIG_ATH79_MACH_DIR_600_A1=y
+CONFIG_ATH79_MACH_DIR_615_C1=y
+CONFIG_ATH79_MACH_DIR_615_I1=y
+CONFIG_ATH79_MACH_DIR_825_B1=y
+CONFIG_ATH79_MACH_DIR_825_C1=y
+CONFIG_ATH79_MACH_DIR_869_A1=y
+CONFIG_ATH79_MACH_DLAN_HOTSPOT=y
+CONFIG_ATH79_MACH_DLAN_PRO_1200_AC=y
+CONFIG_ATH79_MACH_DLAN_PRO_500_WP=y
+CONFIG_ATH79_MACH_DOMYWIFI_DW33D=y
+CONFIG_ATH79_MACH_DR344=y
+CONFIG_ATH79_MACH_DR531=y
+CONFIG_ATH79_MACH_DRAGINO2=y
+CONFIG_ATH79_MACH_EAP120=y
+CONFIG_ATH79_MACH_EAP300V2=y
+CONFIG_ATH79_MACH_EAP7660D=y
+CONFIG_ATH79_MACH_EL_M150=y
+CONFIG_ATH79_MACH_EL_MINI=y
+CONFIG_ATH79_MACH_EPG5000=y
+CONFIG_ATH79_MACH_ESR1750=y
+CONFIG_ATH79_MACH_ESR900=y
+CONFIG_ATH79_MACH_EW_DORIN=y
+CONFIG_ATH79_MACH_F9K1115V2=y
+CONFIG_ATH79_MACH_GL_AR150=y
+CONFIG_ATH79_MACH_GL_AR300=y
+CONFIG_ATH79_MACH_GL_AR300M=y
+CONFIG_ATH79_MACH_GL_DOMINO=y
+CONFIG_ATH79_MACH_GL_INET=y
+CONFIG_ATH79_MACH_GL_MIFI=y
+CONFIG_ATH79_MACH_GS_MINIBOX_V1=y
+CONFIG_ATH79_MACH_GS_OOLITE=y
+CONFIG_ATH79_MACH_HIWIFI_HC6361=y
+CONFIG_ATH79_MACH_HORNET_UB=y
+CONFIG_ATH79_MACH_JA76PF=y
+CONFIG_ATH79_MACH_JWAP003=y
+CONFIG_ATH79_MACH_JWAP230=y
+CONFIG_ATH79_MACH_MC_MAC1200R=y
+CONFIG_ATH79_MACH_MR12=y
+CONFIG_ATH79_MACH_MR16=y
+CONFIG_ATH79_MACH_MR1750=y
+CONFIG_ATH79_MACH_MR18=y
+CONFIG_ATH79_MACH_MR600=y
+CONFIG_ATH79_MACH_MR900=y
+CONFIG_ATH79_MACH_MYNET_N600=y
+CONFIG_ATH79_MACH_MYNET_N750=y
+CONFIG_ATH79_MACH_MYNET_REXT=y
+CONFIG_ATH79_MACH_MZK_W04NU=y
+CONFIG_ATH79_MACH_MZK_W300NH=y
+CONFIG_ATH79_MACH_NBG460N=y
+CONFIG_ATH79_MACH_NBG6716=y
+CONFIG_ATH79_MACH_OM2P=y
+CONFIG_ATH79_MACH_OM5P=y
+CONFIG_ATH79_MACH_OM5P_AC=y
+CONFIG_ATH79_MACH_OM5P_ACv2=y
+CONFIG_ATH79_MACH_OMY_G1=y
+CONFIG_ATH79_MACH_OMY_X1=y
+CONFIG_ATH79_MACH_ONION_OMEGA=y
+CONFIG_ATH79_MACH_PB42=y
+CONFIG_ATH79_MACH_PB44=y
+CONFIG_ATH79_MACH_PB92=y
+CONFIG_ATH79_MACH_QIHOO_C301=y
+CONFIG_ATH79_MACH_R6100=y
+# CONFIG_ATH79_MACH_RB2011 is not set
+# CONFIG_ATH79_MACH_RB4XX is not set
+# CONFIG_ATH79_MACH_RB750 is not set
+# CONFIG_ATH79_MACH_RB91X is not set
+# CONFIG_ATH79_MACH_RB922 is not set
+# CONFIG_ATH79_MACH_RB95X is not set
+# CONFIG_ATH79_MACH_RBSXTLITE is not set
+CONFIG_ATH79_MACH_RW2458N=y
+CONFIG_ATH79_MACH_SMART_300=y
+CONFIG_ATH79_MACH_SOM9331=y
+CONFIG_ATH79_MACH_TELLSTICK_ZNET_LITE=y
+CONFIG_ATH79_MACH_TEW_632BRP=y
+CONFIG_ATH79_MACH_TEW_673GRU=y
+CONFIG_ATH79_MACH_TEW_712BR=y
+CONFIG_ATH79_MACH_TEW_732BR=y
+CONFIG_ATH79_MACH_TEW_823DRU=y
+CONFIG_ATH79_MACH_TL_MR11U=y
+CONFIG_ATH79_MACH_TL_MR13U=y
+CONFIG_ATH79_MACH_TL_MR3020=y
+CONFIG_ATH79_MACH_TL_MR3X20=y
+CONFIG_ATH79_MACH_TL_WA701ND_V2=y
+CONFIG_ATH79_MACH_TL_WA7210N_V2=y
+CONFIG_ATH79_MACH_TL_WA801ND_V3=y
+CONFIG_ATH79_MACH_TL_WA830RE_V2=y
+CONFIG_ATH79_MACH_TL_WA901ND=y
+CONFIG_ATH79_MACH_TL_WA901ND_V2=y
+CONFIG_ATH79_MACH_TL_WA901ND_V4=y
+CONFIG_ATH79_MACH_TL_WAX50RE=y
+CONFIG_ATH79_MACH_TL_WDR3320_V2=y
+CONFIG_ATH79_MACH_TL_WDR3500=y
+CONFIG_ATH79_MACH_TL_WDR4300=y
+CONFIG_ATH79_MACH_TL_WDR6500_V2=y
+CONFIG_ATH79_MACH_TL_WPA8630=y
+CONFIG_ATH79_MACH_TL_WR1041N_V2=y
+CONFIG_ATH79_MACH_TL_WR1043ND=y
+CONFIG_ATH79_MACH_TL_WR1043ND_V2=y
+CONFIG_ATH79_MACH_TL_WR2543N=y
+CONFIG_ATH79_MACH_TL_WR703N=y
+CONFIG_ATH79_MACH_TL_WR720N_V3=y
+CONFIG_ATH79_MACH_TL_WR741ND=y
+CONFIG_ATH79_MACH_TL_WR741ND_V4=y
+CONFIG_ATH79_MACH_TL_WR802N_V1=y
+CONFIG_ATH79_MACH_TL_WR810N=y
+CONFIG_ATH79_MACH_TL_WR841N_V1=y
+CONFIG_ATH79_MACH_TL_WR841N_V8=y
+CONFIG_ATH79_MACH_TL_WR841N_V9=y
+CONFIG_ATH79_MACH_TL_WR941ND=y
+CONFIG_ATH79_MACH_TL_WR941ND_V6=y
+CONFIG_ATH79_MACH_TUBE2H=y
+CONFIG_ATH79_MACH_UBNT=y
+CONFIG_ATH79_MACH_UBNT_UNIFIAC=y
+CONFIG_ATH79_MACH_UBNT_XM=y
+CONFIG_ATH79_MACH_WEIO=y
+CONFIG_ATH79_MACH_WHR_HP_G300N=y
+CONFIG_ATH79_MACH_WLAE_AG300N=y
+CONFIG_ATH79_MACH_WLR8100=y
+CONFIG_ATH79_MACH_WNDAP360=y
+CONFIG_ATH79_MACH_WNDR3700=y
+CONFIG_ATH79_MACH_WNDR4300=y
+CONFIG_ATH79_MACH_WNR2000=y
+CONFIG_ATH79_MACH_WNR2000_V3=y
+CONFIG_ATH79_MACH_WNR2000_V4=y
+CONFIG_ATH79_MACH_WNR2200=y
+CONFIG_ATH79_MACH_WP543=y
+CONFIG_ATH79_MACH_WPE72=y
+CONFIG_ATH79_MACH_WPJ342=y
+CONFIG_ATH79_MACH_WPJ344=y
+CONFIG_ATH79_MACH_WPJ531=y
+CONFIG_ATH79_MACH_WPJ558=y
+CONFIG_ATH79_MACH_WRT160NL=y
+CONFIG_ATH79_MACH_WRT400N=y
+CONFIG_ATH79_MACH_WRTNODE2Q=y
+CONFIG_ATH79_MACH_WZR_450HP2=y
+CONFIG_ATH79_MACH_WZR_HP_AG300H=y
+CONFIG_ATH79_MACH_WZR_HP_G300NH=y
+CONFIG_ATH79_MACH_WZR_HP_G300NH2=y
+CONFIG_ATH79_MACH_WZR_HP_G450H=y
+CONFIG_ATH79_MACH_Z1=y
+CONFIG_ATH79_MACH_ZBT_WE1526=y
+CONFIG_ATH79_MACH_ZCN_1523H=y
+CONFIG_ATH79_NVRAM=y
+CONFIG_ATH79_PCI_ATH9K_FIXUP=y
+# CONFIG_ATH79_ROUTERBOOT is not set
+CONFIG_ATH79_WDT=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2 noinitrd"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMMON_CLK=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_GPIO_LATCH is not set
+CONFIG_GPIO_NXP_74HC153=y
+CONFIG_GPIO_PCF857X=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KVM=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HW_HAS_PCI=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_GPIO=y
+CONFIG_IMAGE_CMDLINE_HACK=y
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_SOURCE="../../root"
+CONFIG_IP17XX_PHY=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_NU801=y
+# CONFIG_LEDS_WNDR3700_USB is not set
+CONFIG_LIBFDT=y
+CONFIG_MARVELL_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MDIO_GPIO=y
+CONFIG_MICREL_PHY=y
+CONFIG_MIPS=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER=y
+# CONFIG_MIPS_CMDLINE_FROM_DTB is not set
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_MACHINE=y
+CONFIG_MIPS_NO_APPENDED_DTB=y
+# CONFIG_MIPS_RAW_APPENDED_DTB is not set
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CYBERTAN_PARTS=y
+CONFIG_MTD_M25P80=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+CONFIG_MTD_MYLOADER_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_LZMA_FW=y
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_MTD_SPLIT_WRGG_FW=y
+CONFIG_MTD_TPLINK_PARTS=y
+CONFIG_MYLOADER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6063=y
+CONFIG_NET_DSA_TAG_TRAILER=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+# CONFIG_NO_IOPORT_MAP is not set
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_PCI=y
+CONFIG_PCI_AR724X=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_RATIONAL=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RTL8306_PHY=y
+CONFIG_RTL8366RB_PHY=y
+CONFIG_RTL8366S_PHY=y
+CONFIG_RTL8366_SMI=y
+CONFIG_RTL8367_PHY=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250_FSL is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_AR933X=y
+CONFIG_SERIAL_AR933X_CONSOLE=y
+CONFIG_SERIAL_AR933X_NR_UARTS=2
+CONFIG_SOC_AR71XX=y
+CONFIG_SOC_AR724X=y
+CONFIG_SOC_AR913X=y
+CONFIG_SOC_AR933X=y
+CONFIG_SOC_AR934X=y
+CONFIG_SOC_QCA953X=y
+CONFIG_SOC_QCA955X=y
+CONFIG_SOC_QCA956X=y
+CONFIG_SPI=y
+CONFIG_SPI_AP83=y
+CONFIG_SPI_ATH79=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_MASTER=y
+# CONFIG_SPI_RB4XX is not set
+# CONFIG_SPI_VSC7385 is not set
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt b/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
new file mode 100644
index 0000000000..f1bfcb80a4
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
@@ -0,0 +1,1803 @@
+config ATH79_MACH_ALFA_AP120C
+	bool "ALFA Network AP120C board support"
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ALFA_AP96
+	bool "ALFA Network AP96 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_HORNET_UB
+	bool "ALFA Network Hornet-UB board support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ALFA_NX
+	bool "ALFA Network N2/N5 board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_TUBE2H
+	bool "ALFA Network Tube2H board support"
+	select SOC_AR933X
+	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_ALL0258N
+	bool "Allnet ALL0258N support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_ALL0315N
+	bool "Allnet ALL0315N support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_ANTMINER_S1
+	bool "Bitmain Antminer S1 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ANTMINER_S3
+	bool "Bitmain Antminer S3 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ANTROUTER_R1
+	bool "Bitmain Antrouter R1 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ARDUINO_YUN
+	bool "Arduino Yun"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Arduino Yun.
+
+config ATH79_MACH_AP113
+	bool "Atheros AP113 board support"
+	select SOC_AR724X
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_PB9X_PCI if PCI
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_USB
+	select ATH79_DEV_ETH
+
+config ATH79_MACH_AP132
+	bool "Atheros AP132 reference board"
+	select SOC_QCA955X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Atheros AP132 reference boards.
+
+config ATH79_MACH_AP143
+	bool "Atheros AP143 reference board"
+	select SOC_QCA953X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_SPI
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_ETH
+	select ATH79_DEV_M25P80
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Atheros AP143 reference board.
+
+config ATH79_MACH_AP147
+	bool "Atheros AP147 reference board"
+	select SOC_QCA953X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_AP9X_PCI if PCI
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  QCA AP147 reference boards.
+
+config ATH79_MACH_AP152
+	bool "Atheros AP152 reference board"
+	select SOC_QCA956X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_AP9X_PCI if PCI
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  QCA AP152 reference boards.
+
+
+config ATH79_MACH_AP83
+	bool "Atheros AP83 board support"
+	select SOC_AR913X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_AP90Q
+	bool "YunCore AP90Q support"
+	select SOC_QCA953X
+	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_AP96
+	bool "Atheros AP96 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_PB42
+	bool "Atheros PB42 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_PB92
+	bool "Atheros PB92 board support"
+	select SOC_AR724X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_PB9X_PCI if PCI
+	select ATH79_DEV_USB
+
+config ATH79_MACH_C55
+	bool "AirTight Networks C-55 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_C60
+	bool "AirTight Networks C-60 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+
+config ATH79_MACH_AW_NR580
+	bool "AzureWave AW-NR580 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_F9K1115V2
+	bool "Belkin AC1750DB board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_EPG5000
+	bool "EnGenius EPG5000 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_ESR1750
+	bool "EnGenius ESR1750 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_SOM9331
+	bool "SOM9331 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_BHR_4GRV2
+	bool "Buffalo BHR-4GRV2 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_WHR_HP_G300N
+	bool "Buffalo WHR-HP-G300N board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_WLAE_AG300N
+	bool "Buffalo WLAE-AG300N board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_WLR8100
+	bool "Sitecom WLR-8100 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WZR_HP_AG300H
+	bool "Buffalo WZR-HP-AG300H board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_WZR_HP_G300NH
+	bool "Buffalo WZR-HP-G300NH board support"
+	select SOC_AR913X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select RTL8366_SMI
+
+config ATH79_MACH_WZR_HP_G300NH2
+	bool "Buffalo WZR-HP-G300NH2 board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_WZR_HP_G450H
+	bool "Buffalo WZR-HP-G450H board support"
+	select SOC_AR724X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_WZR_450HP2
+	bool "Buffalo WZR-450HP2 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WP543
+	bool "Compex WP543/WPJ543 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select MYLOADER
+
+config ATH79_MACH_WPE72
+	bool "Compex WPE72/WPE72NX board support"
+	select SOC_AR724X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select MYLOADER
+
+config ATH79_MACH_WPJ342
+	bool "Compex WPJ342 board support"
+	select SOC_AS934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WPJ344
+	bool "Compex WPJ344 board support"
+	select SOC_AS934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WPJ531
+       bool "Compex WPJ531 board support"
+       select SOC_QCA953X
+       select ATH79_DEV_ETH
+       select ATH79_DEV_GPIO_BUTTONS
+       select ATH79_DEV_LEDS_GPIO
+       select ATH79_DEV_M25P80
+       select ATH79_DEV_USB
+       select ATH79_DEV_WMAC
+
+config ATH79_MACH_WPJ558
+	bool "Compex WPJ558 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_DGL_5500_A1
+	bool "D-Link DGL-5500 A1 support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_USB
+
+config ATH79_MACH_DHP_1565_A1
+	bool "D-Link DHP-1565 rev. A1 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_DIR_505_A1
+	bool "D-Link DIR-505-A1 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_DIR_600_A1
+	bool "D-Link DIR-600 A1/DIR-615 E1/DIR-615 E4 support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_NVRAM
+
+config ATH79_MACH_DIR_615_C1
+	bool "D-Link DIR-615 rev. C1 support"
+	select SOC_AR913X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_DIR_615_I1
+	bool "D-Link DIR-615 rev. I1 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_DIR_825_B1
+	bool "D-Link DIR-825 rev. B1 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_DIR_825_C1
+	bool "D-Link DIR-825 rev. C1/DIR-835 rev. A1 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_DIR_869_A1
+	bool "D-Link DIR-869 rev. A1"
+	select SOC_QCA956X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_DLAN_HOTSPOT
+	bool "devolo dLAN Hotspot support"
+	select SOC_AR933X
+	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_DLAN_PRO_500_WP
+	bool "devolo dLAN pro 500 Wireless+ support"
+	select SOC_AR934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_SPI
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_USB
+
+config ATH79_MACH_DLAN_PRO_1200_AC
+	bool "devolo dLAN pro 1200+ WiFi ac support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_SPI
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+
+config ATH79_MACH_DOMYWIFI_DW33D
+	bool "DomyWifi DW33D support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_NFC
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_USB
+
+config ATH79_MACH_DR344
+	bool "Wallys DR344 board support"
+	select SOC_AS934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_DR531
+	bool "Wallys DR531 board support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_DRAGINO2
+	bool "DRAGINO V2 support"
+	select SOC_AR933X
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_ETH
+	select ATH79_DEV_USB
+
+config ATH79_MACH_ESR900
+	bool "EnGenius ESR900 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_EW_DORIN
+	bool "embedded wireless Dorin Platform support"
+	select SOC_AR933X
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_ETH
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Dorin Platform from www.80211.de .
+
+config ATH79_MACH_EL_M150
+	bool "EasyLink EL-M150 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_EL_MINI
+	bool "EasyLink EL-MINI support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GL_AR150
+	bool "GL AR150 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GL_AR300
+	bool "GL_AR300 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_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GL_AR300M
+	bool "GL_AR300M support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GL_DOMINO
+	bool "DOMINO support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GL_MIFI
+	bool "GL MIFI support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GL_INET
+	bool "GL-INET support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_EAP120
+	bool "TP-LINK EAP120 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_EAP300V2
+	bool "EnGenius EAP300 v2 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_GS_MINIBOX_V1
+	bool "Gainstrong MiniBox V1.0 support"
+	select SOC_AR933X
+	select ARH79_DEV_ETH
+	select ARH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_GS_OOLITE
+       bool "GS Oolite V1 support"
+       select SOC_AR933X
+       select ARH79_DEV_ETH
+       select ARH79_DEV_GPIO_BUTTONS
+       select ATH79_DEV_LEDS_GPIO
+       select ATH79_DEV_M25P80
+       select ATH79_DEV_USB
+       select ATH79_DEV_WMAC
+
+config ATH79_MACH_HIWIFI_HC6361
+	bool "HiWiFi HC6361 board support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_JA76PF
+	bool "jjPlus JA76PF board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_JWAP003
+	bool "jjPlus JWAP003 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_JWAP230
+	bool "jjPlus JWAP230 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WRT160NL
+	bool "Linksys WRT160NL board support"
+	select SOC_AR913X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_WRT400N
+	bool "Linksys WRT400N board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_WRTNODE2Q
+	bool "WRTnode2Q board support"
+	select SOC_QCA953X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_R6100
+	bool "NETGEAR R6100 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_MC_MAC1200R
+	bool "MERCURY MAC1200R board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_RB4XX
+	bool "MikroTik RouterBOARD 4xx series support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_USB
+
+config ATH79_MACH_RB750
+	bool "MikroTik RouterBOARD 750 support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_USB
+	select ATH79_ROUTERBOOT
+
+config ATH79_MACH_RB91X
+	bool "MikroTik RouterBOARD 91X support"
+	select SOC_AR934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_SPI
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_USB
+	select ATH79_ROUTERBOOT
+
+config ATH79_MACH_RB922
+	bool "MikroTik RouterBOARD 922 support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+	select ATH79_ROUTERBOOT
+	select RLE_DECOMPRESS
+
+config ATH79_MACH_RB95X
+       bool "MikroTik RouterBOARD 95X support"
+       select SOC_AR934X
+       select ATH79_DEV_ETH
+       select ATH79_DEV_NFC
+       select ATH79_DEV_WMAC
+       select ATH79_DEV_USB
+       select ATH79_ROUTERBOOT
+
+config ATH79_MACH_RB2011
+	bool "MikroTik RouterBOARD 2011 support"
+	select SOC_AR934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select ATH79_ROUTERBOOT
+
+config ATH79_MACH_RBSXTLITE
+	bool "MikroTik RouterBOARD SXT Lite"
+	select SOC_AR934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_NFC
+	select ATH79_DEV_WMAC
+	select ATH79_ROUTERBOOT
+
+config ATH79_MACH_SMART_300
+	bool "NC-LINK SMART-300 board 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_TELLSTICK_ZNET_LITE
+	bool "TellStick ZNet Lite"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WNDAP360
+	bool "NETGEAR WNDAP360 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_WNDR3700
+	bool "NETGEAR WNDR3700 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_WNDR4300
+	bool "NETGEAR WNDR3700v4/WNDR4300 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_WNR2000
+	bool "NETGEAR WNR2000 board support"
+	select SOC_AR913X
+	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_WNR2000_V3
+	bool "NETGEAR WNR2000 V3/WNR612 v2/WNR1000 v2/WPN824N board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+	config ATH79_MACH_WNR2200
+	bool "NETGEAR WNR2200 board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_WNR2000_V4
+	bool "NETGEAR WNR2000 V4"
+	select SOC_AR934X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_OM2P
+	bool "OpenMesh OM2P board support"
+	select SOC_AR724X
+	select SOC_AR933X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_OM5P
+	bool "OpenMesh OM5P board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_OM5P_AC
+	bool "OpenMesh OM5P-AC board support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_OM5P_ACv2
+	bool "OpenMesh OM5P-ACv2 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_OMY_G1
+	bool "OMYlink OMY G1 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_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_OMY_X1
+	bool "OMYlink OMY X1 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_ONION_OMEGA
+	bool "ONION OMEGA support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_MR12
+	bool "Meraki MR12 board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_MR16
+	bool "Meraki MR16 board support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_MR18
+	bool "Meraki MR18 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_NFC
+	select ATH79_DEV_WMAC
+	select LEDS_NU801
+
+config ATH79_MACH_MR600
+	bool "OpenMesh MR600 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_MZK_W04NU
+	bool "Planex MZK-W04NU board support"
+	select SOC_AR913X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_MZK_W300NH
+	bool "Planex MZK-W300NH board support"
+	select SOC_AR913X
+	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_RW2458N
+	bool "Redwave RW2458N board support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_CAP324
+	bool "PowerCloud CAP324 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_CAP4200AG
+	bool "Senao CAP4200AG support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_CR3000
+	bool "PowerCloud CR3000 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_CR5000
+	bool "PowerCloud CR5000 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_MR1750
+	bool "OpenMesh MR1750 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_MR900
+	bool "OpenMesh MR900 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	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_EAP7660D
+	bool "Senao EAP7660D support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_BSB
+	bool "Smart Electronics Black Swift board"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ARCHER_C7
+	bool "TP-LINK Archer C5/C7/TL-WDR4900 v2 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+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_CPE830
+	bool "YunCore CPE830 support"
+	select SOC_QCA953X
+	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_CPE870
+	bool "YunCore CPE870 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
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_MR13U
+	bool "TP-LINK TL-MR13U support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_MR3020
+	bool "TP-LINK TL-MR3020 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_MR3X20
+	bool "TP-LINK TL-MR3220/3420 support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_TL_WAX50RE
+	bool "TP-LINK TL-WA750/850RE 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_WA701ND_V2
+	bool "TP-LINK TL-WA701ND v2 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WA7210N_V2
+       bool "TP-LINK TL-WA7210N v2 support"
+       select SOC_AR724X
+       select ATH79_DEV_AP9X_PCI if PCI
+       select ATH79_DEV_ETH
+       select ATH79_DEV_LEDS_GPIO
+       select ATH79_DEV_GPIO_BUTTONS
+       select ATH79_DEV_M25P80
+       select ATH79_DEV_WMAC
+config ATH79_MACH_TL_WA801ND_V3
+       bool "TP-LINK TL-WA801ND v3 support"
+       select SOC_QCA953X
+       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_WA830RE_V2
+	bool "TP-LINK TL-WA830RE v2 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_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WA901ND
+	bool "TP-LINK TL-WA901ND/TL-WA7510N support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_TL_WA901ND_V2
+	bool "TP-LINK TL-WA901ND v2 support"
+	select SOC_AR913X
+	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_WA901ND_V4
+	bool "TP-LINK TL-WA901ND v4 support"
+	select SOC_QCA956X
+	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_WDR3320_V2
+	bool "TP-LINK TL-WDR3320 v2 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WDR3500
+	bool "TP-LINK TL-WDR3500 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WDR4300
+	bool "TP-LINK TL-WDR3600/4300/4310 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WDR6500_V2
+	bool "TP-LINK TL-WDR6500 v2 board support"
+	select SOC_QCA956X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR703N
+	bool "TP-LINK TL-WR703N/TL-WR710N/TL-MR10U support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR720N_V3
+	bool "TP-LINK TL-WR720N v3/v4 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR741ND
+	bool "TP-LINK TL-WR741ND support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_TL_WR741ND_V4
+	bool "TP-LINK TL-WR741ND v4/TL-MR3220 v2 support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR802N_V1
+	bool "TP-LINK TL-WR802N v1 support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_TL_WR810N
+	bool "TP-LINK TL-WR810N support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR841N_V1
+	bool "TP-LINK TL-WR841N v1 support"
+	select SOC_AR71XX
+	select ATH79_DEV_DSA
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_TL_WR841N_V8
+	bool "TP-LINK TL-WR841N/ND v8/TL-MR3420 v2 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_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR841N_V9
+	bool "TP-LINK TL-WR841N/ND v9/TL-WR842N/ND v3 support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR941ND
+	bool "TP-LINK TL-WR941ND support"
+	select SOC_AR913X
+	select ATH79_DEV_DSA
+	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_WR941ND_V6
+	bool "TP-LINK TL-WR941ND v6 support"
+	select SOC_QCA956X
+	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_WR1041N_V2
+	bool "TP-LINK TL-WR1041N v2 support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR1043ND
+	bool "TP-LINK TL-WR1043ND support"
+	select SOC_AR913X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR1043ND_V2
+	bool "TP-LINK TL-WR1043ND v2 support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_TL_WR2543N
+	bool "TP-LINK TL-WR2543N/ND support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_TEW_632BRP
+	bool "TRENDnet TEW-632BRP support"
+	select SOC_AR913X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_TEW_673GRU
+	bool "TRENDnet TEW-673GRU support"
+	select SOC_AR71XX
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_NVRAM
+
+config ATH79_MACH_TEW_712BR
+	bool "TRENDnet TEW-712BR support"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_TEW_732BR
+	bool "TRENDnet TEW-732BR 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_TEW_823DRU
+	bool "TRENDnet TEW-823DRU support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_UBNT
+	bool "Ubiquiti AR71xx based boards support"
+	select SOC_AR71XX
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+
+config ATH79_MACH_UBNT_UNIFIAC
+	bool "Ubiquiti UniFi AC (LITE/LR/PRO) support"
+	select SOC_QCA956X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_DEV_USB
+
+config ATH79_MACH_WEIO
+	bool "WeIO board"
+	select SOC_AR933X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_MYNET_N600
+	bool "WD My Net N600 board 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
+	select ATH79_NVRAM
+
+config ATH79_MACH_MYNET_N750
+	bool "WD My Net N750 board 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
+	select ATH79_NVRAM
+
+config ATH79_MACH_MYNET_REXT
+	bool "WD My Net Wi-Fi Range Extender board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+	select ATH79_NVRAM
+
+config ATH79_MACH_Z1
+	bool "Meraki Z1 board support"
+	select SOC_AR934X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	select LEDS_NU801
+
+config ATH79_MACH_ZBT_WE1526
+	bool "Zbtlink ZBT-WE1526 board support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_ZCN_1523H
+	bool "Zcomax ZCN-1523H support"
+	select SOC_AR724X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+
+config ATH79_MACH_NBG460N
+	bool "Zyxel NBG460N/550N/550NH board support"
+	select SOC_AR913X
+	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_NBG6716
+	bool "Zyxel NBG6616/NBG6716 board support"
+	select SOC_QCA955X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_NFC
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CARAMBOLA2
+	bool "8devices Carambola2 board"
+	select SOC_AR933X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CF_E316N_V2
+	bool "COMFAST CF-E316N v2 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_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CF_E320N_V2
+	bool "COMFAST CF-E320N v2 support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CF_E380AC_V1
+	bool "COMFAST CF-E380AC v1 support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CF_E380AC_V2
+	bool "COMFAST CF-E380AC v2 support"
+	select SOC_QCA955X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CF_E520N
+	bool "COMFAST CF-E520N support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_CF_E530N
+	bool "COMFAST CF-E530N support"
+	select SOC_QCA953X
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_BHU_BXU2000N2_A
+	bool "BHU BXU2000n-2 rev. A 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_USB
+	select ATH79_DEV_WMAC
+
+config ATH79_MACH_QIHOO_C301
+	bool "Qihoo 360 C301 board 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
+	select ATH79_DEV_USB
+	select ATH79_NVRAM
+
+config ATH79_MACH_DAP_2695_A1
+	bool "D-Link DAP-2695 rev. A1 support"
+	select SOC_QCA955X
+	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_WPA8630
+	bool "TP-Link TL-WPA8630 support"
+	select SOC_QCA956X
+	select ATH79_DEV_AP9X_PCI if PCI
+	select ATH79_DEV_ETH
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_M25P80
+	select ATH79_DEV_WMAC
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/Makefile b/target/linux/ar71xx/files/arch/mips/ath79/Makefile
new file mode 100644
index 0000000000..ac2dbbb23f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/Makefile
@@ -0,0 +1,228 @@
+#
+# Makefile for the Atheros AR71XX/AR724X/AR913X specific parts of the kernel
+#
+# Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+#
+# 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.
+
+obj-y	:= prom.o setup.o irq.o common.o clock.o gpio.o
+
+obj-$(CONFIG_EARLY_PRINTK)		+= early_printk.o
+obj-$(CONFIG_PCI)			+= pci.o
+
+#
+# Devices
+#
+obj-y					+= dev-common.o
+obj-$(CONFIG_ATH79_DEV_AP9X_PCI)	+= dev-ap9x-pci.o
+obj-$(CONFIG_ATH79_DEV_DSA)		+= dev-dsa.o
+obj-$(CONFIG_ATH79_DEV_ETH)		+= dev-eth.o
+obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS)	+= dev-gpio-buttons.o
+obj-$(CONFIG_ATH79_DEV_LEDS_GPIO)	+= dev-leds-gpio.o
+obj-$(CONFIG_ATH79_DEV_M25P80)		+= dev-m25p80.o
+obj-$(CONFIG_ATH79_DEV_NFC)		+= dev-nfc.o
+obj-$(CONFIG_ATH79_DEV_SPI)		+= dev-spi.o
+obj-$(CONFIG_ATH79_DEV_USB)		+= dev-usb.o
+obj-$(CONFIG_ATH79_DEV_WMAC)		+= dev-wmac.o
+
+#
+# Miscellaneous objects
+#
+obj-$(CONFIG_ATH79_NVRAM)		+= nvram.o
+obj-$(CONFIG_ATH79_PCI_ATH9K_FIXUP)	+= pci-ath9k-fixup.o
+obj-$(CONFIG_ATH79_ROUTERBOOT)		+= routerboot.o
+
+#
+# Machines
+#
+obj-$(CONFIG_ATH79_MACH_ALFA_AP120C)		+= mach-alfa-ap120c.o
+obj-$(CONFIG_ATH79_MACH_ALFA_AP96)		+= mach-alfa-ap96.o
+obj-$(CONFIG_ATH79_MACH_ALFA_NX)		+= mach-alfa-nx.o
+obj-$(CONFIG_ATH79_MACH_ALL0258N)		+= mach-all0258n.o
+obj-$(CONFIG_ATH79_MACH_ALL0315N)		+= mach-all0315n.o
+obj-$(CONFIG_ATH79_MACH_ANTMINER_S1)		+= mach-antminer-s1.o
+obj-$(CONFIG_ATH79_MACH_ANTMINER_S3)		+= mach-antminer-s3.o
+obj-$(CONFIG_ATH79_MACH_ANTROUTER_R1)		+= mach-antrouter-r1.o
+obj-$(CONFIG_ATH79_MACH_AP113)			+= mach-ap113.o
+obj-$(CONFIG_ATH79_MACH_AP121)			+= mach-ap121.o
+obj-$(CONFIG_ATH79_MACH_AP132)			+= mach-ap132.o
+obj-$(CONFIG_ATH79_MACH_AP136)			+= mach-ap136.o
+obj-$(CONFIG_ATH79_MACH_AP143)			+= mach-ap143.o
+obj-$(CONFIG_ATH79_MACH_AP147)			+= mach-ap147.o
+obj-$(CONFIG_ATH79_MACH_AP152)			+= mach-ap152.o
+obj-$(CONFIG_ATH79_MACH_AP81)			+= mach-ap81.o
+obj-$(CONFIG_ATH79_MACH_AP83)			+= mach-ap83.o
+obj-$(CONFIG_ATH79_MACH_AP90Q)			+= mach-ap90q.o
+obj-$(CONFIG_ATH79_MACH_AP96)			+= mach-ap96.o
+obj-$(CONFIG_ATH79_MACH_ARCHER_C7)		+= mach-archer-c7.o
+obj-$(CONFIG_ATH79_MACH_ARDUINO_YUN)		+= mach-arduino-yun.o
+obj-$(CONFIG_ATH79_MACH_AW_NR580)		+= mach-aw-nr580.o
+obj-$(CONFIG_ATH79_MACH_BHR_4GRV2)		+= mach-bhr-4grv2.o
+obj-$(CONFIG_ATH79_MACH_BHU_BXU2000N2_A)	+= mach-bhu-bxu2000n2-a.o
+obj-$(CONFIG_ATH79_MACH_BSB)			+= mach-bsb.o
+obj-$(CONFIG_ATH79_MACH_C55)			+= mach-c55.o
+obj-$(CONFIG_ATH79_MACH_C60)			+= mach-c60.o
+obj-$(CONFIG_ATH79_MACH_CAP324)			+= mach-cap324.o
+obj-$(CONFIG_ATH79_MACH_CAP4200AG)		+= mach-cap4200ag.o
+obj-$(CONFIG_ATH79_MACH_CARAMBOLA2)		+= mach-carambola2.o
+obj-$(CONFIG_ATH79_MACH_CF_E316N_V2)		+= mach-cf-e316n-v2.o
+obj-$(CONFIG_ATH79_MACH_CF_E320N_V2)		+= mach-cf-e316n-v2.o
+obj-$(CONFIG_ATH79_MACH_CF_E380AC_V1)		+= mach-cf-e316n-v2.o
+obj-$(CONFIG_ATH79_MACH_CF_E380AC_V2)		+= mach-cf-e316n-v2.o
+obj-$(CONFIG_ATH79_MACH_CF_E520N)		+= mach-cf-e316n-v2.o
+obj-$(CONFIG_ATH79_MACH_CF_E530N)		+= mach-cf-e316n-v2.o
+obj-$(CONFIG_ATH79_MACH_CPE510)			+= mach-cpe510.o
+obj-$(CONFIG_ATH79_MACH_CPE830)			+= mach-ap90q.o
+obj-$(CONFIG_ATH79_MACH_CPE870)			+= mach-cpe870.o
+obj-$(CONFIG_ATH79_MACH_CR3000)			+= mach-cr3000.o
+obj-$(CONFIG_ATH79_MACH_CR5000)			+= mach-cr5000.o
+obj-$(CONFIG_ATH79_MACH_DAP_2695_A1)		+= mach-dap-2695-a1.o
+obj-$(CONFIG_ATH79_MACH_DB120)			+= mach-db120.o
+obj-$(CONFIG_ATH79_MACH_DGL_5500_A1)		+= mach-dgl-5500-a1.o
+obj-$(CONFIG_ATH79_MACH_DHP_1565_A1)		+= mach-dhp-1565-a1.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
+obj-$(CONFIG_ATH79_MACH_DIR_615_C1)		+= mach-dir-615-c1.o
+obj-$(CONFIG_ATH79_MACH_DIR_615_I1)		+= mach-dir-615-i1.o
+obj-$(CONFIG_ATH79_MACH_DIR_825_B1)		+= mach-dir-825-b1.o
+obj-$(CONFIG_ATH79_MACH_DIR_825_C1)		+= mach-dir-825-c1.o
+obj-$(CONFIG_ATH79_MACH_DIR_869_A1)		+= mach-dir-869-a1.o
+obj-$(CONFIG_ATH79_MACH_DLAN_HOTSPOT)		+= mach-dlan-hotspot.o
+obj-$(CONFIG_ATH79_MACH_DLAN_PRO_1200_AC)	+= mach-dlan-pro-1200-ac.o
+obj-$(CONFIG_ATH79_MACH_DLAN_PRO_500_WP)	+= mach-dlan-pro-500-wp.o
+obj-$(CONFIG_ATH79_MACH_DOMYWIFI_DW33D)		+= mach-domywifi-dw33d.o
+obj-$(CONFIG_ATH79_MACH_DR344)			+= mach-dr344.o
+obj-$(CONFIG_ATH79_MACH_DR531)			+= mach-dr531.o
+obj-$(CONFIG_ATH79_MACH_DRAGINO2)		+= mach-dragino2.o
+obj-$(CONFIG_ATH79_MACH_EAP120)			+= mach-eap120.o
+obj-$(CONFIG_ATH79_MACH_EAP300V2)		+= mach-eap300v2.o
+obj-$(CONFIG_ATH79_MACH_EAP7660D)		+= mach-eap7660d.o
+obj-$(CONFIG_ATH79_MACH_EL_M150)		+= mach-el-m150.o
+obj-$(CONFIG_ATH79_MACH_EL_MINI)		+= mach-el-mini.o
+obj-$(CONFIG_ATH79_MACH_EPG5000)		+= mach-epg5000.o
+obj-$(CONFIG_ATH79_MACH_ESR1750)		+= mach-esr1750.o
+obj-$(CONFIG_ATH79_MACH_ESR900)			+= mach-esr900.o
+obj-$(CONFIG_ATH79_MACH_EW_DORIN)		+= mach-ew-dorin.o
+obj-$(CONFIG_ATH79_MACH_F9K1115V2)		+= mach-f9k1115v2.o
+obj-$(CONFIG_ATH79_MACH_GL_AR150)		+= mach-gl-ar150.o
+obj-$(CONFIG_ATH79_MACH_GL_AR300)		+= mach-gl-ar300.o
+obj-$(CONFIG_ATH79_MACH_GL_AR300M)		+= mach-gl-ar300m.o
+obj-$(CONFIG_ATH79_MACH_GL_DOMINO)		+= mach-gl-domino.o
+obj-$(CONFIG_ATH79_MACH_GL_INET)		+= mach-gl-inet.o
+obj-$(CONFIG_ATH79_MACH_GL_MIFI)		+= mach-gl-mifi.o
+obj-$(CONFIG_ATH79_MACH_GS_MINIBOX_V1)		+= mach-gs-minibox-v1.o
+obj-$(CONFIG_ATH79_MACH_GS_OOLITE)		+= mach-gs-oolite.o
+obj-$(CONFIG_ATH79_MACH_HIWIFI_HC6361)		+= mach-hiwifi-hc6361.o
+obj-$(CONFIG_ATH79_MACH_HORNET_UB)		+= mach-hornet-ub.o
+obj-$(CONFIG_ATH79_MACH_JA76PF)			+= mach-ja76pf.o
+obj-$(CONFIG_ATH79_MACH_JWAP003)		+= mach-jwap003.o
+obj-$(CONFIG_ATH79_MACH_JWAP230)		+= mach-jwap230.o
+obj-$(CONFIG_ATH79_MACH_MC_MAC1200R)		+= mach-mc-mac1200r.o
+obj-$(CONFIG_ATH79_MACH_MR12)			+= mach-mr12.o
+obj-$(CONFIG_ATH79_MACH_MR16)			+= mach-mr16.o
+obj-$(CONFIG_ATH79_MACH_MR1750)			+= mach-mr1750.o
+obj-$(CONFIG_ATH79_MACH_MR18)			+= mach-mr18.o
+obj-$(CONFIG_ATH79_MACH_MR600)			+= mach-mr600.o
+obj-$(CONFIG_ATH79_MACH_MR900)			+= mach-mr900.o
+obj-$(CONFIG_ATH79_MACH_MYNET_N600)		+= mach-mynet-n600.o
+obj-$(CONFIG_ATH79_MACH_MYNET_N750)		+= mach-mynet-n750.o
+obj-$(CONFIG_ATH79_MACH_MYNET_REXT)		+= mach-mynet-rext.o
+obj-$(CONFIG_ATH79_MACH_MZK_W04NU)		+= mach-mzk-w04nu.o
+obj-$(CONFIG_ATH79_MACH_MZK_W300NH)		+= mach-mzk-w300nh.o
+obj-$(CONFIG_ATH79_MACH_NBG460N)		+= mach-nbg460n.o
+obj-$(CONFIG_ATH79_MACH_NBG6716)		+= mach-nbg6716.o
+obj-$(CONFIG_ATH79_MACH_OM2P)			+= mach-om2p.o
+obj-$(CONFIG_ATH79_MACH_OM5P)			+= mach-om5p.o
+obj-$(CONFIG_ATH79_MACH_OM5P_AC)		+= mach-om5pac.o
+obj-$(CONFIG_ATH79_MACH_OM5P_ACv2)		+= mach-om5pacv2.o
+obj-$(CONFIG_ATH79_MACH_OMY_G1)			+= mach-omy-g1.o
+obj-$(CONFIG_ATH79_MACH_OMY_X1)			+= mach-omy-x1.o
+obj-$(CONFIG_ATH79_MACH_ONION_OMEGA)		+= mach-onion-omega.o
+obj-$(CONFIG_ATH79_MACH_PB42)			+= mach-pb42.o
+obj-$(CONFIG_ATH79_MACH_PB44)			+= mach-pb44.o
+obj-$(CONFIG_ATH79_MACH_PB92)			+= mach-pb92.o
+obj-$(CONFIG_ATH79_MACH_QIHOO_C301)		+= mach-qihoo-c301.o
+obj-$(CONFIG_ATH79_MACH_R6100)			+= mach-r6100.o
+obj-$(CONFIG_ATH79_MACH_RB2011)			+= mach-rb2011.o
+obj-$(CONFIG_ATH79_MACH_RB4XX)			+= mach-rb4xx.o
+obj-$(CONFIG_ATH79_MACH_RB750)			+= mach-rb750.o
+obj-$(CONFIG_ATH79_MACH_RB91X)			+= mach-rb91x.o
+obj-$(CONFIG_ATH79_MACH_RB922)			+= mach-rb922.o
+obj-$(CONFIG_ATH79_MACH_RB95X)			+= mach-rb95x.o
+obj-$(CONFIG_ATH79_MACH_RBSXTLITE)		+= mach-rbsxtlite.o
+obj-$(CONFIG_ATH79_MACH_RW2458N)		+= mach-rw2458n.o
+obj-$(CONFIG_ATH79_MACH_SMART_300)		+= mach-smart-300.o
+obj-$(CONFIG_ATH79_MACH_SOM9331)		+= mach-som9331.o
+obj-$(CONFIG_ATH79_MACH_TELLSTICK_ZNET_LITE)	+= mach-tellstick-znet-lite.o
+obj-$(CONFIG_ATH79_MACH_TEW_632BRP)		+= mach-tew-632brp.o
+obj-$(CONFIG_ATH79_MACH_TEW_673GRU)		+= mach-tew-673gru.o
+obj-$(CONFIG_ATH79_MACH_TEW_712BR)		+= mach-tew-712br.o
+obj-$(CONFIG_ATH79_MACH_TEW_732BR)		+= mach-tew-732br.o
+obj-$(CONFIG_ATH79_MACH_TEW_823DRU)		+= mach-tew-823dru.o
+obj-$(CONFIG_ATH79_MACH_TL_MR11U)		+= mach-tl-mr11u.o
+obj-$(CONFIG_ATH79_MACH_TL_MR13U)		+= mach-tl-mr13u.o
+obj-$(CONFIG_ATH79_MACH_TL_MR3020)		+= mach-tl-mr3020.o
+obj-$(CONFIG_ATH79_MACH_TL_MR3X20)		+= mach-tl-mr3x20.o
+obj-$(CONFIG_ATH79_MACH_TL_WA701ND_V2)		+= mach-tl-wa701nd-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WA7210N_V2)		+= mach-tl-wa7210n-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WA801ND_V3)		+= mach-tl-wa801nd-v3.o
+obj-$(CONFIG_ATH79_MACH_TL_WA830RE_V2)		+= mach-tl-wa830re-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WA901ND)		+= mach-tl-wa901nd.o
+obj-$(CONFIG_ATH79_MACH_TL_WA901ND_V2)		+= mach-tl-wa901nd-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WA901ND_V4)		+= mach-tl-wa901nd-v4.o
+obj-$(CONFIG_ATH79_MACH_TL_WAX50RE)		+= mach-tl-wax50re.o
+obj-$(CONFIG_ATH79_MACH_TL_WDR3320_V2)		+= mach-tl-wdr3320-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WDR3500)		+= mach-tl-wdr3500.o
+obj-$(CONFIG_ATH79_MACH_TL_WDR4300)		+= mach-tl-wdr4300.o
+obj-$(CONFIG_ATH79_MACH_TL_WDR6500_V2)		+= mach-tl-wdr6500-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WPA8630)		+= mach-tl-wpa8630.o
+obj-$(CONFIG_ATH79_MACH_TL_WR1041N_V2)		+= mach-tl-wr1041n-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WR1043ND)		+= mach-tl-wr1043nd.o
+obj-$(CONFIG_ATH79_MACH_TL_WR1043ND_V2)		+= mach-tl-wr1043nd-v2.o
+obj-$(CONFIG_ATH79_MACH_TL_WR2543N)		+= mach-tl-wr2543n.o
+obj-$(CONFIG_ATH79_MACH_TL_WR703N)		+= mach-tl-wr703n.o
+obj-$(CONFIG_ATH79_MACH_TL_WR720N_V3)		+= mach-tl-wr720n-v3.o
+obj-$(CONFIG_ATH79_MACH_TL_WR741ND)		+= mach-tl-wr741nd.o
+obj-$(CONFIG_ATH79_MACH_TL_WR741ND_V4)		+= mach-tl-wr741nd-v4.o
+obj-$(CONFIG_ATH79_MACH_TL_WR802N_V1)		+= mach-tl-wr802n.o
+obj-$(CONFIG_ATH79_MACH_TL_WR810N)		+= mach-tl-wr810n.o
+obj-$(CONFIG_ATH79_MACH_TL_WR841N_V1)		+= mach-tl-wr841n.o
+obj-$(CONFIG_ATH79_MACH_TL_WR841N_V8)		+= mach-tl-wr841n-v8.o
+obj-$(CONFIG_ATH79_MACH_TL_WR841N_V9)		+= mach-tl-wr841n-v9.o
+obj-$(CONFIG_ATH79_MACH_TL_WR941ND)		+= mach-tl-wr941nd.o
+obj-$(CONFIG_ATH79_MACH_TL_WR941ND_V6)		+= mach-tl-wr941nd-v6.o
+obj-$(CONFIG_ATH79_MACH_TUBE2H)			+= mach-tube2h.o
+obj-$(CONFIG_ATH79_MACH_UBNT)			+= mach-ubnt.o
+obj-$(CONFIG_ATH79_MACH_UBNT_UNIFIAC)		+= mach-ubnt-unifiac.o
+obj-$(CONFIG_ATH79_MACH_UBNT_XM)		+= mach-ubnt-xm.o
+obj-$(CONFIG_ATH79_MACH_WEIO)			+= mach-weio.o
+obj-$(CONFIG_ATH79_MACH_WHR_HP_G300N)		+= mach-whr-hp-g300n.o
+obj-$(CONFIG_ATH79_MACH_WLAE_AG300N)		+= mach-wlae-ag300n.o
+obj-$(CONFIG_ATH79_MACH_WLR8100)		+= mach-wlr8100.o
+obj-$(CONFIG_ATH79_MACH_WNDAP360)		+= mach-wndap360.o
+obj-$(CONFIG_ATH79_MACH_WNDR3700)		+= mach-wndr3700.o
+obj-$(CONFIG_ATH79_MACH_WNDR4300)		+= mach-wndr4300.o
+obj-$(CONFIG_ATH79_MACH_WNR2000)		+= mach-wnr2000.o
+obj-$(CONFIG_ATH79_MACH_WNR2000_V3)		+= mach-wnr2000-v3.o
+obj-$(CONFIG_ATH79_MACH_WNR2000_V4)		+= mach-wnr2000-v4.o
+obj-$(CONFIG_ATH79_MACH_WNR2200)		+= mach-wnr2200.o
+obj-$(CONFIG_ATH79_MACH_WP543)			+= mach-wp543.o
+obj-$(CONFIG_ATH79_MACH_WPE72)			+= mach-wpe72.o
+obj-$(CONFIG_ATH79_MACH_WPJ342)			+= mach-wpj342.o
+obj-$(CONFIG_ATH79_MACH_WPJ344)			+= mach-wpj344.o
+obj-$(CONFIG_ATH79_MACH_WPJ531)			+= mach-wpj531.o
+obj-$(CONFIG_ATH79_MACH_WPJ558)			+= mach-wpj558.o
+obj-$(CONFIG_ATH79_MACH_WRT160NL)		+= mach-wrt160nl.o
+obj-$(CONFIG_ATH79_MACH_WRT400N)		+= mach-wrt400n.o
+obj-$(CONFIG_ATH79_MACH_WRTNODE2Q)		+= mach-wrtnode2q.o
+obj-$(CONFIG_ATH79_MACH_WZR_450HP2)		+= mach-wzr-450hp2.o
+obj-$(CONFIG_ATH79_MACH_WZR_HP_AG300H)		+= mach-wzr-hp-ag300h.o
+obj-$(CONFIG_ATH79_MACH_WZR_HP_G300NH)		+= mach-wzr-hp-g300nh.o
+obj-$(CONFIG_ATH79_MACH_WZR_HP_G300NH2)		+= mach-wzr-hp-g300nh2.o
+obj-$(CONFIG_ATH79_MACH_WZR_HP_G450H)		+= mach-wzr-hp-g450h.o
+obj-$(CONFIG_ATH79_MACH_Z1)			+= mach-z1.o
+obj-$(CONFIG_ATH79_MACH_ZBT_WE1526)		+= mach-zbt-we1526.o
+obj-$(CONFIG_ATH79_MACH_ZCN_1523H)		+= mach-zcn-1523h.o
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.c
new file mode 100644
index 0000000000..20bb06e486
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.c
@@ -0,0 +1,185 @@
+/*
+ *  Atheros AP9X reference board PCI initialization
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/ath9k_platform.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "pci-ath9k-fixup.h"
+#include "pci.h"
+
+static struct ath9k_platform_data ap9x_wmac0_data = {
+	.led_pin = -1,
+};
+static struct ath9k_platform_data ap9x_wmac1_data = {
+	.led_pin = -1,
+};
+static char ap9x_wmac0_mac[6];
+static char ap9x_wmac1_mac[6];
+
+__init void ap9x_pci_setup_wmac_led_pin(unsigned wmac, int pin)
+{
+	switch (wmac) {
+	case 0:
+		ap9x_wmac0_data.led_pin = pin;
+		break;
+	case 1:
+		ap9x_wmac1_data.led_pin = pin;
+		break;
+	}
+}
+
+__init void ap9x_pci_setup_wmac_led_name(unsigned wmac, const char *led_name)
+{
+	switch (wmac) {
+	case 0:
+		ap9x_wmac0_data.led_name = led_name;
+		break;
+	case 1:
+		ap9x_wmac1_data.led_name = led_name;
+		break;
+	}
+}
+
+__init struct ath9k_platform_data *ap9x_pci_get_wmac_data(unsigned wmac)
+{
+	switch (wmac) {
+	case 0:
+		return &ap9x_wmac0_data;
+
+	case 1:
+		return &ap9x_wmac1_data;
+	}
+
+	return NULL;
+}
+
+__init void ap9x_pci_setup_wmac_gpio(unsigned wmac, u32 mask, u32 val)
+{
+	switch (wmac) {
+	case 0:
+		ap9x_wmac0_data.gpio_mask = mask;
+		ap9x_wmac0_data.gpio_val = val;
+		break;
+	case 1:
+		ap9x_wmac1_data.gpio_mask = mask;
+		ap9x_wmac1_data.gpio_val = val;
+		break;
+	}
+}
+
+__init void ap9x_pci_setup_wmac_leds(unsigned wmac, struct gpio_led *leds,
+				     int num_leds)
+{
+	switch (wmac) {
+	case 0:
+		ap9x_wmac0_data.leds = leds;
+		ap9x_wmac0_data.num_leds = num_leds;
+		break;
+	case 1:
+		ap9x_wmac1_data.leds = leds;
+		ap9x_wmac1_data.num_leds = num_leds;
+		break;
+	}
+}
+
+__init void ap9x_pci_setup_wmac_btns(unsigned wmac,
+				     struct gpio_keys_button *btns,
+				     unsigned num_btns, unsigned poll_interval)
+{
+	struct ath9k_platform_data *ap9x_wmac_data;
+
+	if (!(ap9x_wmac_data = ap9x_pci_get_wmac_data(wmac)))
+		return;
+
+	ap9x_wmac_data->btns = btns;
+	ap9x_wmac_data->num_btns = num_btns;
+	ap9x_wmac_data->btn_poll_interval = poll_interval;
+}
+
+static int ap91_pci_plat_dev_init(struct pci_dev *dev)
+{
+	switch (PCI_SLOT(dev->devfn)) {
+	case 0:
+		dev->dev.platform_data = &ap9x_wmac0_data;
+		break;
+	}
+
+	return 0;
+}
+
+__init void ap91_pci_init(u8 *cal_data, u8 *mac_addr)
+{
+	if (cal_data)
+		memcpy(ap9x_wmac0_data.eeprom_data, cal_data,
+		       sizeof(ap9x_wmac0_data.eeprom_data));
+
+	if (mac_addr) {
+		memcpy(ap9x_wmac0_mac, mac_addr, sizeof(ap9x_wmac0_mac));
+		ap9x_wmac0_data.macaddr = ap9x_wmac0_mac;
+	}
+
+	ath79_pci_set_plat_dev_init(ap91_pci_plat_dev_init);
+	ath79_register_pci();
+
+	pci_enable_ath9k_fixup(0, ap9x_wmac0_data.eeprom_data);
+}
+
+__init void ap91_pci_init_simple(void)
+{
+	ap91_pci_init(NULL, NULL);
+	ap9x_wmac0_data.eeprom_name = "pci_wmac0.eeprom";
+}
+
+static int ap94_pci_plat_dev_init(struct pci_dev *dev)
+{
+	switch (PCI_SLOT(dev->devfn)) {
+	case 17:
+		dev->dev.platform_data = &ap9x_wmac0_data;
+		break;
+
+	case 18:
+		dev->dev.platform_data = &ap9x_wmac1_data;
+		break;
+	}
+
+	return 0;
+}
+
+__init void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
+			  u8 *cal_data1, u8 *mac_addr1)
+{
+	if (cal_data0)
+		memcpy(ap9x_wmac0_data.eeprom_data, cal_data0,
+		       sizeof(ap9x_wmac0_data.eeprom_data));
+
+	if (cal_data1)
+		memcpy(ap9x_wmac1_data.eeprom_data, cal_data1,
+		       sizeof(ap9x_wmac1_data.eeprom_data));
+
+	if (mac_addr0) {
+		memcpy(ap9x_wmac0_mac, mac_addr0, sizeof(ap9x_wmac0_mac));
+		ap9x_wmac0_data.macaddr = ap9x_wmac0_mac;
+	}
+
+	if (mac_addr1) {
+		memcpy(ap9x_wmac1_mac, mac_addr1, sizeof(ap9x_wmac1_mac));
+		ap9x_wmac1_data.macaddr = ap9x_wmac1_mac;
+	}
+
+	ath79_pci_set_plat_dev_init(ap94_pci_plat_dev_init);
+	ath79_register_pci();
+
+	pci_enable_ath9k_fixup(17, ap9x_wmac0_data.eeprom_data);
+	pci_enable_ath9k_fixup(18, ap9x_wmac1_data.eeprom_data);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.h b/target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.h
new file mode 100644
index 0000000000..d7c018565e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-ap9x-pci.h
@@ -0,0 +1,58 @@
+/*
+ *  Atheros AP9X reference board PCI initialization
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_DEV_AP9X_PCI_H
+#define _ATH79_DEV_AP9X_PCI_H
+
+struct gpio_led;
+struct gpio_keys_button;
+struct ath9k_platform_data;
+
+#if defined(CONFIG_ATH79_DEV_AP9X_PCI)
+void ap9x_pci_setup_wmac_led_pin(unsigned wmac, int pin);
+void ap9x_pci_setup_wmac_gpio(unsigned wmac, u32 mask, u32 val);
+void ap9x_pci_setup_wmac_leds(unsigned wmac, struct gpio_led *leds,
+			      int num_leds);
+void ap9x_pci_setup_wmac_led_name(unsigned wmac, const char *led_name);
+void ap9x_pci_setup_wmac_btns(unsigned wmac, struct gpio_keys_button *btns,
+			      unsigned num_btns, unsigned poll_interval);
+struct ath9k_platform_data *ap9x_pci_get_wmac_data(unsigned wmac);
+
+void ap91_pci_init(u8 *cal_data, u8 *mac_addr);
+void ap91_pci_init_simple(void);
+void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
+		   u8 *cal_data1, u8 *mac_addr1);
+
+#else
+static inline void ap9x_pci_setup_wmac_led_pin(unsigned wmac, int pin) {}
+static inline void ap9x_pci_setup_wmac_gpio(unsigned wmac,
+					    u32 mask, u32 val) {}
+static inline void ap9x_pci_setup_wmac_leds(unsigned wmac,
+					    struct gpio_led *leds,
+					    int num_leds) {}
+static inline void ap9x_pci_setup_wmac_led_name(unsigned wmac,
+						const char *led_name) {}
+static inline void ap9x_pci_setup_wmac_btns(unsigned wmac,
+					    struct gpio_keys_button *btns,
+					    unsigned num_btns,
+					    unsigned poll_interval) {}
+static inline struct ath9k_platform_data *ap9x_pci_get_wmac_data(unsigned wmac)
+{
+	return NULL;
+}
+
+static inline void ap91_pci_init(u8 *cal_data, u8 *mac_addr) {}
+static inline void ap91_pci_init_simple(void) {}
+static inline void ap94_pci_init(u8 *cal_data0, u8 *mac_addr0,
+				 u8 *cal_data1, u8 *mac_addr1) {}
+#endif
+
+#endif /* _ATH79_DEV_AP9X_PCI_H */
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.c
new file mode 100644
index 0000000000..a9bb334a20
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.c
@@ -0,0 +1,41 @@
+/*
+ *  Atheros AR71xx DSA switch device support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/init.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-dsa.h"
+
+static struct platform_device ar71xx_dsa_switch_device = {
+	.name		= "dsa",
+	.id		= 0,
+};
+
+void __init ath79_register_dsa(struct device *netdev,
+			       struct device *miidev,
+			       struct dsa_platform_data *d)
+{
+	int i;
+
+	d->netdev = netdev;
+	for (i = 0; i < d->nr_chips; i++)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
+		d->chip[i].mii_bus = miidev;
+#else
+		d->chip[i].host_dev = miidev;
+#endif
+
+	ar71xx_dsa_switch_device.dev.platform_data = d;
+	platform_device_register(&ar71xx_dsa_switch_device);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.h b/target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.h
new file mode 100644
index 0000000000..3730202e8d
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-dsa.h
@@ -0,0 +1,21 @@
+/*
+ *  Atheros AR71xx DSA switch device support
+ *
+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_DEV_DSA_H
+#define _ATH79_DEV_DSA_H
+
+#include <net/dsa.h>
+
+void ath79_register_dsa(struct device *netdev,
+			struct device *miidev,
+			struct dsa_platform_data *d);
+
+#endif /* _ATH79_DEV_DSA_H */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
new file mode 100644
index 0000000000..07cb12c8e9
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
@@ -0,0 +1,1262 @@
+/*
+ *  Atheros AR71xx SoC platform devices
+ *
+ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Parts of this file are based on Atheros 2.6.15 BSP
+ *  Parts of this file are based on Atheros 2.6.31 BSP
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/sizes.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/irq.h>
+
+#include "common.h"
+#include "dev-eth.h"
+
+unsigned char ath79_mac_base[ETH_ALEN] __initdata;
+
+static struct resource ath79_mdio0_resources[] = {
+	{
+		.name	= "mdio_base",
+		.flags	= IORESOURCE_MEM,
+		.start	= AR71XX_GE0_BASE,
+		.end	= AR71XX_GE0_BASE + 0x200 - 1,
+	}
+};
+
+struct ag71xx_mdio_platform_data ath79_mdio0_data;
+
+struct platform_device ath79_mdio0_device = {
+	.name		= "ag71xx-mdio",
+	.id		= 0,
+	.resource	= ath79_mdio0_resources,
+	.num_resources	= ARRAY_SIZE(ath79_mdio0_resources),
+	.dev = {
+		.platform_data = &ath79_mdio0_data,
+	},
+};
+
+static struct resource ath79_mdio1_resources[] = {
+	{
+		.name	= "mdio_base",
+		.flags	= IORESOURCE_MEM,
+		.start	= AR71XX_GE1_BASE,
+		.end	= AR71XX_GE1_BASE + 0x200 - 1,
+	}
+};
+
+struct ag71xx_mdio_platform_data ath79_mdio1_data;
+
+struct platform_device ath79_mdio1_device = {
+	.name		= "ag71xx-mdio",
+	.id		= 1,
+	.resource	= ath79_mdio1_resources,
+	.num_resources	= ARRAY_SIZE(ath79_mdio1_resources),
+	.dev = {
+		.platform_data = &ath79_mdio1_data,
+	},
+};
+
+static void ath79_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+
+	t = __raw_readl(base + cfg_reg);
+	t &= ~(3 << shift);
+	t |=  (2 << shift);
+	__raw_writel(t, base + cfg_reg);
+	udelay(100);
+
+	__raw_writel(pll_val, base + pll_reg);
+
+	t |= (3 << shift);
+	__raw_writel(t, base + cfg_reg);
+	udelay(100);
+
+	t &= ~(3 << shift);
+	__raw_writel(t, base + cfg_reg);
+	udelay(100);
+
+	printk(KERN_DEBUG "ar71xx: pll_reg %#x: %#x\n",
+		(unsigned int)(base + pll_reg), __raw_readl(base + pll_reg));
+
+	iounmap(base);
+}
+
+static void __init ath79_mii_ctrl_set_if(unsigned int reg,
+					  unsigned int mii_if)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
+
+	t = __raw_readl(base + reg);
+	t &= ~(AR71XX_MII_CTRL_IF_MASK);
+	t |= (mii_if & AR71XX_MII_CTRL_IF_MASK);
+	__raw_writel(t, base + reg);
+
+	iounmap(base);
+}
+
+static void ath79_mii_ctrl_set_speed(unsigned int reg, unsigned int speed)
+{
+	void __iomem *base;
+	unsigned int mii_speed;
+	u32 t;
+
+	switch (speed) {
+	case SPEED_10:
+		mii_speed =  AR71XX_MII_CTRL_SPEED_10;
+		break;
+	case SPEED_100:
+		mii_speed =  AR71XX_MII_CTRL_SPEED_100;
+		break;
+	case SPEED_1000:
+		mii_speed =  AR71XX_MII_CTRL_SPEED_1000;
+		break;
+	default:
+		BUG();
+	}
+
+	base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
+
+	t = __raw_readl(base + reg);
+	t &= ~(AR71XX_MII_CTRL_SPEED_MASK << AR71XX_MII_CTRL_SPEED_SHIFT);
+	t |= mii_speed  << AR71XX_MII_CTRL_SPEED_SHIFT;
+	__raw_writel(t, base + reg);
+
+	iounmap(base);
+}
+
+static unsigned long ar934x_get_mdio_ref_clock(void)
+{
+	void __iomem *base;
+	unsigned long ret;
+	u32 t;
+
+	base = ioremap(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+
+	ret = 0;
+	t = __raw_readl(base + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+	if (t & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL) {
+		ret = 100 * 1000 * 1000;
+	} else {
+		struct clk *clk;
+
+		clk = clk_get(NULL, "ref");
+		if (!IS_ERR(clk))
+			ret = clk_get_rate(clk);
+	}
+
+	iounmap(base);
+
+	return ret;
+}
+
+void __init ath79_register_mdio(unsigned int id, u32 phy_mask)
+{
+	struct platform_device *mdio_dev;
+	struct ag71xx_mdio_platform_data *mdio_data;
+	unsigned int max_id;
+
+	if (ath79_soc == ATH79_SOC_AR9341 ||
+	    ath79_soc == ATH79_SOC_AR9342 ||
+	    ath79_soc == ATH79_SOC_AR9344 ||
+	    ath79_soc == ATH79_SOC_QCA9556 ||
+	    ath79_soc == ATH79_SOC_QCA9558 ||
+	    ath79_soc == ATH79_SOC_QCA956X)
+		max_id = 1;
+	else
+		max_id = 0;
+
+	if (id > max_id) {
+		printk(KERN_ERR "ar71xx: invalid MDIO id %u\n", id);
+		return;
+	}
+
+	switch (ath79_soc) {
+	case ATH79_SOC_AR7241:
+	case ATH79_SOC_AR9330:
+	case ATH79_SOC_AR9331:
+	case ATH79_SOC_QCA9533:
+	case ATH79_SOC_TP9343:
+		mdio_dev = &ath79_mdio1_device;
+		mdio_data = &ath79_mdio1_data;
+		break;
+
+	case ATH79_SOC_AR9341:
+	case ATH79_SOC_AR9342:
+	case ATH79_SOC_AR9344:
+	case ATH79_SOC_QCA9556:
+	case ATH79_SOC_QCA9558:
+	case ATH79_SOC_QCA956X:
+		if (id == 0) {
+			mdio_dev = &ath79_mdio0_device;
+			mdio_data = &ath79_mdio0_data;
+		} else {
+			mdio_dev = &ath79_mdio1_device;
+			mdio_data = &ath79_mdio1_data;
+		}
+		break;
+
+	case ATH79_SOC_AR7242:
+		ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG,
+			       AR7242_PLL_REG_ETH0_INT_CLOCK, 0x62000000,
+			       AR71XX_ETH0_PLL_SHIFT);
+		/* fall through */
+	default:
+		mdio_dev = &ath79_mdio0_device;
+		mdio_data = &ath79_mdio0_data;
+		break;
+	}
+
+	mdio_data->phy_mask = phy_mask;
+
+	switch (ath79_soc) {
+	case ATH79_SOC_AR7240:
+		mdio_data->is_ar7240 = 1;
+		/* fall through */
+	case ATH79_SOC_AR7241:
+		mdio_data->builtin_switch = 1;
+		break;
+
+	case ATH79_SOC_AR9330:
+		mdio_data->is_ar9330 = 1;
+		/* fall through */
+	case ATH79_SOC_AR9331:
+		mdio_data->builtin_switch = 1;
+		break;
+
+	case ATH79_SOC_AR9341:
+	case ATH79_SOC_AR9342:
+	case ATH79_SOC_AR9344:
+		if (id == 1) {
+			mdio_data->builtin_switch = 1;
+			mdio_data->ref_clock = ar934x_get_mdio_ref_clock();
+			mdio_data->mdio_clock = 6250000;
+		}
+		mdio_data->is_ar934x = 1;
+		break;
+
+	case ATH79_SOC_QCA9533:
+	case ATH79_SOC_TP9343:
+		mdio_data->builtin_switch = 1;
+		break;
+
+	case ATH79_SOC_QCA9556:
+	case ATH79_SOC_QCA9558:
+		mdio_data->is_ar934x = 1;
+		break;
+
+	case ATH79_SOC_QCA956X:
+		if (id == 1)
+			mdio_data->builtin_switch = 1;
+		mdio_data->is_ar934x = 1;
+		break;
+
+	default:
+		break;
+	}
+
+	platform_device_register(mdio_dev);
+}
+
+struct ath79_eth_pll_data ath79_eth0_pll_data;
+struct ath79_eth_pll_data ath79_eth1_pll_data;
+
+static u32 ath79_get_eth_pll(unsigned int mac, int speed)
+{
+	struct ath79_eth_pll_data *pll_data;
+	u32 pll_val;
+
+	switch (mac) {
+	case 0:
+		pll_data = &ath79_eth0_pll_data;
+		break;
+	case 1:
+		pll_data = &ath79_eth1_pll_data;
+		break;
+	default:
+		BUG();
+	}
+
+	switch (speed) {
+	case SPEED_10:
+		pll_val = pll_data->pll_10;
+		break;
+	case SPEED_100:
+		pll_val = pll_data->pll_100;
+		break;
+	case SPEED_1000:
+		pll_val = pll_data->pll_1000;
+		break;
+	default:
+		BUG();
+	}
+
+	return pll_val;
+}
+
+static void ath79_set_speed_ge0(int speed)
+{
+	u32 val = ath79_get_eth_pll(0, speed);
+
+	ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH0_INT_CLOCK,
+			val, AR71XX_ETH0_PLL_SHIFT);
+	ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
+}
+
+static void ath79_set_speed_ge1(int speed)
+{
+	u32 val = ath79_get_eth_pll(1, speed);
+
+	ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH1_INT_CLOCK,
+			 val, AR71XX_ETH1_PLL_SHIFT);
+	ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
+}
+
+static void ar7242_set_speed_ge0(int speed)
+{
+	u32 val = ath79_get_eth_pll(0, speed);
+	void __iomem *base;
+
+	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+	__raw_writel(val, base + AR7242_PLL_REG_ETH0_INT_CLOCK);
+	iounmap(base);
+}
+
+static void ar91xx_set_speed_ge0(int speed)
+{
+	u32 val = ath79_get_eth_pll(0, speed);
+
+	ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH0_INT_CLOCK,
+			 val, AR913X_ETH0_PLL_SHIFT);
+	ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
+}
+
+static void ar91xx_set_speed_ge1(int speed)
+{
+	u32 val = ath79_get_eth_pll(1, speed);
+
+	ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH1_INT_CLOCK,
+			 val, AR913X_ETH1_PLL_SHIFT);
+	ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
+}
+
+static void ar934x_set_speed_ge0(int speed)
+{
+	void __iomem *base;
+	u32 val = ath79_get_eth_pll(0, speed);
+
+	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+	__raw_writel(val, base + AR934X_PLL_ETH_XMII_CONTROL_REG);
+	iounmap(base);
+}
+
+static void qca955x_set_speed_xmii(int speed)
+{
+	void __iomem *base;
+	u32 val = ath79_get_eth_pll(0, speed);
+
+	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+	__raw_writel(val, base + QCA955X_PLL_ETH_XMII_CONTROL_REG);
+	iounmap(base);
+}
+
+static void qca955x_set_speed_sgmii(int speed)
+{
+	void __iomem *base;
+	u32 val = ath79_get_eth_pll(1, speed);
+
+	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+	__raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
+	iounmap(base);
+}
+
+static void qca956x_set_speed_sgmii(int speed)
+{
+	void __iomem *base;
+	u32 val = ath79_get_eth_pll(0, speed);
+
+	base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+	__raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
+	iounmap(base);
+}
+
+static void ath79_set_speed_dummy(int speed)
+{
+}
+
+static void ath79_ddr_flush_ge0(void)
+{
+	ath79_ddr_wb_flush(0);
+}
+
+static void ath79_ddr_flush_ge1(void)
+{
+	ath79_ddr_wb_flush(1);
+}
+
+static struct resource ath79_eth0_resources[] = {
+	{
+		.name	= "mac_base",
+		.flags	= IORESOURCE_MEM,
+		.start	= AR71XX_GE0_BASE,
+		.end	= AR71XX_GE0_BASE + 0x200 - 1,
+	}, {
+		.name	= "mac_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= ATH79_CPU_IRQ(4),
+		.end	= ATH79_CPU_IRQ(4),
+	},
+};
+
+struct ag71xx_platform_data ath79_eth0_data = {
+	.reset_bit	= AR71XX_RESET_GE0_MAC,
+};
+
+struct platform_device ath79_eth0_device = {
+	.name		= "ag71xx",
+	.id		= 0,
+	.resource	= ath79_eth0_resources,
+	.num_resources	= ARRAY_SIZE(ath79_eth0_resources),
+	.dev = {
+		.platform_data = &ath79_eth0_data,
+	},
+};
+
+static struct resource ath79_eth1_resources[] = {
+	{
+		.name	= "mac_base",
+		.flags	= IORESOURCE_MEM,
+		.start	= AR71XX_GE1_BASE,
+		.end	= AR71XX_GE1_BASE + 0x200 - 1,
+	}, {
+		.name	= "mac_irq",
+		.flags	= IORESOURCE_IRQ,
+		.start	= ATH79_CPU_IRQ(5),
+		.end	= ATH79_CPU_IRQ(5),
+	},
+};
+
+struct ag71xx_platform_data ath79_eth1_data = {
+	.reset_bit	= AR71XX_RESET_GE1_MAC,
+};
+
+struct platform_device ath79_eth1_device = {
+	.name		= "ag71xx",
+	.id		= 1,
+	.resource	= ath79_eth1_resources,
+	.num_resources	= ARRAY_SIZE(ath79_eth1_resources),
+	.dev = {
+		.platform_data = &ath79_eth1_data,
+	},
+};
+
+struct ag71xx_switch_platform_data ath79_switch_data;
+
+#define AR71XX_PLL_VAL_1000	0x00110000
+#define AR71XX_PLL_VAL_100	0x00001099
+#define AR71XX_PLL_VAL_10	0x00991099
+
+#define AR724X_PLL_VAL_1000	0x00110000
+#define AR724X_PLL_VAL_100	0x00001099
+#define AR724X_PLL_VAL_10	0x00991099
+
+#define AR7242_PLL_VAL_1000	0x16000000
+#define AR7242_PLL_VAL_100	0x00000101
+#define AR7242_PLL_VAL_10	0x00001616
+
+#define AR913X_PLL_VAL_1000	0x1a000000
+#define AR913X_PLL_VAL_100	0x13000a44
+#define AR913X_PLL_VAL_10	0x00441099
+
+#define AR933X_PLL_VAL_1000	0x00110000
+#define AR933X_PLL_VAL_100	0x00001099
+#define AR933X_PLL_VAL_10	0x00991099
+
+#define AR934X_PLL_VAL_1000	0x16000000
+#define AR934X_PLL_VAL_100	0x00000101
+#define AR934X_PLL_VAL_10	0x00001616
+
+#define QCA956X_PLL_VAL_1000	0x03000000
+#define QCA956X_PLL_VAL_100	0x00000101
+#define QCA956X_PLL_VAL_10	0x00001919
+
+static void __init ath79_init_eth_pll_data(unsigned int id)
+{
+	struct ath79_eth_pll_data *pll_data;
+	u32 pll_10, pll_100, pll_1000;
+
+	switch (id) {
+	case 0:
+		pll_data = &ath79_eth0_pll_data;
+		break;
+	case 1:
+		pll_data = &ath79_eth1_pll_data;
+		break;
+	default:
+		BUG();
+	}
+
+	switch (ath79_soc) {
+	case ATH79_SOC_AR7130:
+	case ATH79_SOC_AR7141:
+	case ATH79_SOC_AR7161:
+		pll_10 = AR71XX_PLL_VAL_10;
+		pll_100 = AR71XX_PLL_VAL_100;
+		pll_1000 = AR71XX_PLL_VAL_1000;
+		break;
+
+	case ATH79_SOC_AR7240:
+	case ATH79_SOC_AR7241:
+		pll_10 = AR724X_PLL_VAL_10;
+		pll_100 = AR724X_PLL_VAL_100;
+		pll_1000 = AR724X_PLL_VAL_1000;
+		break;
+
+	case ATH79_SOC_AR7242:
+		pll_10 = AR7242_PLL_VAL_10;
+		pll_100 = AR7242_PLL_VAL_100;
+		pll_1000 = AR7242_PLL_VAL_1000;
+		break;
+
+	case ATH79_SOC_AR9130:
+	case ATH79_SOC_AR9132:
+		pll_10 = AR913X_PLL_VAL_10;
+		pll_100 = AR913X_PLL_VAL_100;
+		pll_1000 = AR913X_PLL_VAL_1000;
+		break;
+
+	case ATH79_SOC_AR9330:
+	case ATH79_SOC_AR9331:
+		pll_10 = AR933X_PLL_VAL_10;
+		pll_100 = AR933X_PLL_VAL_100;
+		pll_1000 = AR933X_PLL_VAL_1000;
+		break;
+
+	case ATH79_SOC_AR9341:
+	case ATH79_SOC_AR9342:
+	case ATH79_SOC_AR9344:
+	case ATH79_SOC_QCA9533:
+	case ATH79_SOC_QCA9556:
+	case ATH79_SOC_QCA9558:
+	case ATH79_SOC_TP9343:
+		pll_10 = AR934X_PLL_VAL_10;
+		pll_100 = AR934X_PLL_VAL_100;
+		pll_1000 = AR934X_PLL_VAL_1000;
+		break;
+
+	case ATH79_SOC_QCA956X:
+		pll_10 = QCA956X_PLL_VAL_10;
+		pll_100 = QCA956X_PLL_VAL_100;
+		pll_1000 = QCA956X_PLL_VAL_1000;
+		break;
+
+	default:
+		BUG();
+	}
+
+	if (!pll_data->pll_10)
+		pll_data->pll_10 = pll_10;
+
+	if (!pll_data->pll_100)
+		pll_data->pll_100 = pll_100;
+
+	if (!pll_data->pll_1000)
+		pll_data->pll_1000 = pll_1000;
+}
+
+static int __init ath79_setup_phy_if_mode(unsigned int id,
+					   struct ag71xx_platform_data *pdata)
+{
+	unsigned int mii_if;
+
+	switch (id) {
+	case 0:
+		switch (ath79_soc) {
+		case ATH79_SOC_AR7130:
+		case ATH79_SOC_AR7141:
+		case ATH79_SOC_AR7161:
+		case ATH79_SOC_AR9130:
+		case ATH79_SOC_AR9132:
+			switch (pdata->phy_if_mode) {
+			case PHY_INTERFACE_MODE_MII:
+				mii_if = AR71XX_MII0_CTRL_IF_MII;
+				break;
+			case PHY_INTERFACE_MODE_GMII:
+				mii_if = AR71XX_MII0_CTRL_IF_GMII;
+				break;
+			case PHY_INTERFACE_MODE_RGMII:
+				mii_if = AR71XX_MII0_CTRL_IF_RGMII;
+				break;
+			case PHY_INTERFACE_MODE_RMII:
+				mii_if = AR71XX_MII0_CTRL_IF_RMII;
+				break;
+			default:
+				return -EINVAL;
+			}
+			ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII0_CTRL, mii_if);
+			break;
+
+		case ATH79_SOC_AR7240:
+		case ATH79_SOC_AR7241:
+		case ATH79_SOC_AR9330:
+		case ATH79_SOC_AR9331:
+		case ATH79_SOC_QCA9533:
+		case ATH79_SOC_TP9343:
+			pdata->phy_if_mode = PHY_INTERFACE_MODE_MII;
+			break;
+
+		case ATH79_SOC_AR7242:
+			/* FIXME */
+
+		case ATH79_SOC_AR9341:
+		case ATH79_SOC_AR9342:
+		case ATH79_SOC_AR9344:
+			switch (pdata->phy_if_mode) {
+			case PHY_INTERFACE_MODE_MII:
+			case PHY_INTERFACE_MODE_GMII:
+			case PHY_INTERFACE_MODE_RGMII:
+			case PHY_INTERFACE_MODE_RMII:
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+
+		case ATH79_SOC_QCA9556:
+		case ATH79_SOC_QCA9558:
+		case ATH79_SOC_QCA956X:
+			switch (pdata->phy_if_mode) {
+			case PHY_INTERFACE_MODE_MII:
+			case PHY_INTERFACE_MODE_RGMII:
+			case PHY_INTERFACE_MODE_SGMII:
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+
+		default:
+			BUG();
+		}
+		break;
+	case 1:
+		switch (ath79_soc) {
+		case ATH79_SOC_AR7130:
+		case ATH79_SOC_AR7141:
+		case ATH79_SOC_AR7161:
+		case ATH79_SOC_AR9130:
+		case ATH79_SOC_AR9132:
+			switch (pdata->phy_if_mode) {
+			case PHY_INTERFACE_MODE_RMII:
+				mii_if = AR71XX_MII1_CTRL_IF_RMII;
+				break;
+			case PHY_INTERFACE_MODE_RGMII:
+				mii_if = AR71XX_MII1_CTRL_IF_RGMII;
+				break;
+			default:
+				return -EINVAL;
+			}
+			ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII1_CTRL, mii_if);
+			break;
+
+		case ATH79_SOC_AR7240:
+		case ATH79_SOC_AR7241:
+		case ATH79_SOC_AR9330:
+		case ATH79_SOC_AR9331:
+		case ATH79_SOC_QCA956X:
+		case ATH79_SOC_TP9343:
+			pdata->phy_if_mode = PHY_INTERFACE_MODE_GMII;
+			break;
+
+		case ATH79_SOC_AR7242:
+			/* FIXME */
+
+		case ATH79_SOC_AR9341:
+		case ATH79_SOC_AR9342:
+		case ATH79_SOC_AR9344:
+		case ATH79_SOC_QCA9533:
+			switch (pdata->phy_if_mode) {
+			case PHY_INTERFACE_MODE_MII:
+			case PHY_INTERFACE_MODE_GMII:
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+
+		case ATH79_SOC_QCA9556:
+		case ATH79_SOC_QCA9558:
+			switch (pdata->phy_if_mode) {
+			case PHY_INTERFACE_MODE_MII:
+			case PHY_INTERFACE_MODE_RGMII:
+			case PHY_INTERFACE_MODE_SGMII:
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+
+		default:
+			BUG();
+		}
+		break;
+	}
+
+	return 0;
+}
+
+void __init ath79_setup_ar933x_phy4_switch(bool mac, bool mdio)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(AR933X_GMAC_BASE, AR933X_GMAC_SIZE);
+
+	t = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
+	t &= ~(AR933X_ETH_CFG_SW_PHY_SWAP | AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
+	if (mac)
+		t |= AR933X_ETH_CFG_SW_PHY_SWAP;
+	if (mdio)
+		t |= AR933X_ETH_CFG_SW_PHY_ADDR_SWAP;
+	__raw_writel(t, base + AR933X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+void __init ath79_setup_ar934x_eth_cfg(u32 mask)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
+
+	t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+	t &= ~(AR934X_ETH_CFG_RGMII_GMAC0 |
+	       AR934X_ETH_CFG_MII_GMAC0 |
+	       AR934X_ETH_CFG_GMII_GMAC0 |
+	       AR934X_ETH_CFG_SW_ONLY_MODE |
+	       AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	t |= mask;
+
+	__raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
+	/* flush write */
+	__raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+void __init ath79_setup_ar934x_eth_rx_delay(unsigned int rxd,
+					    unsigned int rxdv)
+{
+	void __iomem *base;
+	u32 t;
+
+	rxd &= AR934X_ETH_CFG_RXD_DELAY_MASK;
+	rxdv &= AR934X_ETH_CFG_RDV_DELAY_MASK;
+
+	base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
+
+	t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+	t &= ~(AR934X_ETH_CFG_RXD_DELAY_MASK << AR934X_ETH_CFG_RXD_DELAY_SHIFT |
+	       AR934X_ETH_CFG_RDV_DELAY_MASK << AR934X_ETH_CFG_RDV_DELAY_SHIFT);
+
+	t |= (rxd << AR934X_ETH_CFG_RXD_DELAY_SHIFT |
+	      rxdv << AR934X_ETH_CFG_RDV_DELAY_SHIFT);
+
+	__raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
+	/* flush write */
+	__raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+void __init ath79_setup_qca955x_eth_cfg(u32 mask)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+	t = __raw_readl(base + QCA955X_GMAC_REG_ETH_CFG);
+
+	t &= ~(QCA955X_ETH_CFG_RGMII_EN | QCA955X_ETH_CFG_GE0_SGMII);
+
+	t |= mask;
+
+	__raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+static int ath79_eth_instance __initdata;
+void __init ath79_register_eth(unsigned int id)
+{
+	struct platform_device *pdev;
+	struct ag71xx_platform_data *pdata;
+	int err;
+
+	if (id > 1) {
+		printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
+		return;
+	}
+
+	ath79_init_eth_pll_data(id);
+
+	if (id == 0)
+		pdev = &ath79_eth0_device;
+	else
+		pdev = &ath79_eth1_device;
+
+	pdata = pdev->dev.platform_data;
+
+	pdata->max_frame_len = 1540;
+	pdata->desc_pktlen_mask = 0xfff;
+
+	err = ath79_setup_phy_if_mode(id, pdata);
+	if (err) {
+		printk(KERN_ERR
+		       "ar71xx: invalid PHY interface mode for GE%u\n", id);
+		return;
+	}
+
+	if (id == 0)
+		pdata->ddr_flush = ath79_ddr_flush_ge0;
+	else
+		pdata->ddr_flush = ath79_ddr_flush_ge1;
+
+	switch (ath79_soc) {
+	case ATH79_SOC_AR7130:
+		if (id == 0)
+			pdata->set_speed = ath79_set_speed_ge0;
+		else
+			pdata->set_speed = ath79_set_speed_ge1;
+		break;
+
+	case ATH79_SOC_AR7141:
+	case ATH79_SOC_AR7161:
+		if (id == 0)
+			pdata->set_speed = ath79_set_speed_ge0;
+		else
+			pdata->set_speed = ath79_set_speed_ge1;
+		pdata->has_gbit = 1;
+		break;
+
+	case ATH79_SOC_AR7242:
+		if (id == 0) {
+			pdata->reset_bit |= AR724X_RESET_GE0_MDIO |
+					    AR71XX_RESET_GE0_PHY;
+			pdata->set_speed = ar7242_set_speed_ge0;
+		} else {
+			pdata->reset_bit |= AR724X_RESET_GE1_MDIO |
+					    AR71XX_RESET_GE1_PHY;
+			pdata->set_speed = ath79_set_speed_dummy;
+		}
+		pdata->has_gbit = 1;
+		pdata->is_ar724x = 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	case ATH79_SOC_AR7241:
+		if (id == 0)
+			pdata->reset_bit |= AR724X_RESET_GE0_MDIO;
+		else
+			pdata->reset_bit |= AR724X_RESET_GE1_MDIO;
+		/* fall through */
+	case ATH79_SOC_AR7240:
+		if (id == 0) {
+			pdata->reset_bit |= AR71XX_RESET_GE0_PHY;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->phy_mask = BIT(4);
+		} else {
+			pdata->reset_bit |= AR71XX_RESET_GE1_PHY;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->speed = SPEED_1000;
+			pdata->duplex = DUPLEX_FULL;
+			pdata->switch_data = &ath79_switch_data;
+			pdata->use_flow_control = 1;
+
+			ath79_switch_data.phy_poll_mask |= BIT(4);
+		}
+		pdata->has_gbit = 1;
+		pdata->is_ar724x = 1;
+		if (ath79_soc == ATH79_SOC_AR7240)
+			pdata->is_ar7240 = 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	case ATH79_SOC_AR9132:
+		pdata->has_gbit = 1;
+		/* fall through */
+	case ATH79_SOC_AR9130:
+		if (id == 0)
+			pdata->set_speed = ar91xx_set_speed_ge0;
+		else
+			pdata->set_speed = ar91xx_set_speed_ge1;
+		pdata->is_ar91xx = 1;
+		break;
+
+	case ATH79_SOC_AR9330:
+	case ATH79_SOC_AR9331:
+		if (id == 0) {
+			pdata->reset_bit = AR933X_RESET_GE0_MAC |
+					   AR933X_RESET_GE0_MDIO;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->phy_mask = BIT(4);
+		} else {
+			pdata->reset_bit = AR933X_RESET_GE1_MAC |
+					   AR933X_RESET_GE1_MDIO;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->speed = SPEED_1000;
+			pdata->has_gbit = 1;
+			pdata->duplex = DUPLEX_FULL;
+			pdata->switch_data = &ath79_switch_data;
+			pdata->use_flow_control = 1;
+
+			ath79_switch_data.phy_poll_mask |= BIT(4);
+		}
+
+		pdata->is_ar724x = 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	case ATH79_SOC_AR9341:
+	case ATH79_SOC_AR9342:
+	case ATH79_SOC_AR9344:
+	case ATH79_SOC_QCA9533:
+		if (id == 0) {
+			pdata->reset_bit = AR934X_RESET_GE0_MAC |
+					   AR934X_RESET_GE0_MDIO;
+			pdata->set_speed = ar934x_set_speed_ge0;
+		} else {
+			pdata->reset_bit = AR934X_RESET_GE1_MAC |
+					   AR934X_RESET_GE1_MDIO;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->switch_data = &ath79_switch_data;
+
+			/* reset the built-in switch */
+			ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
+			ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
+		}
+
+		pdata->has_gbit = 1;
+		pdata->is_ar724x = 1;
+
+		pdata->max_frame_len = SZ_16K - 1;
+		pdata->desc_pktlen_mask = SZ_16K - 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	case ATH79_SOC_TP9343:
+		if (id == 0) {
+			pdata->reset_bit = AR933X_RESET_GE0_MAC |
+					   AR933X_RESET_GE0_MDIO;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			if (!pdata->phy_mask)
+				pdata->phy_mask = BIT(4);
+		} else {
+			pdata->reset_bit = AR933X_RESET_GE1_MAC |
+					   AR933X_RESET_GE1_MDIO;
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->speed = SPEED_1000;
+			pdata->duplex = DUPLEX_FULL;
+			pdata->switch_data = &ath79_switch_data;
+			pdata->use_flow_control = 1;
+
+			ath79_switch_data.phy_poll_mask |= BIT(4);
+		}
+
+		pdata->has_gbit = 1;
+		pdata->is_ar724x = 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	case ATH79_SOC_QCA9556:
+	case ATH79_SOC_QCA9558:
+		if (id == 0) {
+			pdata->reset_bit = QCA955X_RESET_GE0_MAC |
+					   QCA955X_RESET_GE0_MDIO;
+			pdata->set_speed = qca955x_set_speed_xmii;
+		} else {
+			pdata->reset_bit = QCA955X_RESET_GE1_MAC |
+					   QCA955X_RESET_GE1_MDIO;
+			pdata->set_speed = qca955x_set_speed_sgmii;
+		}
+
+		pdata->has_gbit = 1;
+		pdata->is_ar724x = 1;
+
+		/*
+		 * Limit the maximum frame length to 4095 bytes.
+		 * Although the documentation says that the hardware
+		 * limit is 16383 bytes but that does not work in
+		 * practice. It seems that the hardware only updates
+		 * the lowest 12 bits of the packet length field
+		 * in the RX descriptor.
+		 */
+		pdata->max_frame_len = SZ_4K - 1;
+		pdata->desc_pktlen_mask = SZ_16K - 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	case ATH79_SOC_QCA956X:
+		if (id == 0) {
+			pdata->reset_bit = QCA955X_RESET_GE0_MAC |
+					   QCA955X_RESET_GE0_MDIO;
+
+			if (pdata->phy_if_mode == PHY_INTERFACE_MODE_SGMII)
+				pdata->set_speed = qca956x_set_speed_sgmii;
+			else
+				pdata->set_speed = ath79_set_speed_ge0;
+		} else {
+			pdata->reset_bit = QCA955X_RESET_GE1_MAC |
+					   QCA955X_RESET_GE1_MDIO;
+
+			pdata->set_speed = ath79_set_speed_dummy;
+
+			pdata->switch_data = &ath79_switch_data;
+
+			pdata->speed = SPEED_1000;
+			pdata->duplex = DUPLEX_FULL;
+			pdata->use_flow_control = 1;
+
+			/* reset the built-in switch */
+			ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
+			ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
+		}
+
+		pdata->has_gbit = 1;
+		pdata->is_ar724x = 1;
+
+		if (!pdata->fifo_cfg1)
+			pdata->fifo_cfg1 = 0x0010ffff;
+		if (!pdata->fifo_cfg2)
+			pdata->fifo_cfg2 = 0x015500aa;
+		if (!pdata->fifo_cfg3)
+			pdata->fifo_cfg3 = 0x01f00140;
+		break;
+
+	default:
+		BUG();
+	}
+
+	switch (pdata->phy_if_mode) {
+	case PHY_INTERFACE_MODE_GMII:
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_SGMII:
+		if (!pdata->has_gbit) {
+			printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
+					id);
+			return;
+		}
+		/* fallthrough */
+	default:
+		break;
+	}
+
+	if (!is_valid_ether_addr(pdata->mac_addr)) {
+		random_ether_addr(pdata->mac_addr);
+		printk(KERN_DEBUG
+			"ar71xx: using random MAC address for eth%d\n",
+			ath79_eth_instance);
+	}
+
+	if (pdata->mii_bus_dev == NULL) {
+		switch (ath79_soc) {
+		case ATH79_SOC_AR9341:
+		case ATH79_SOC_AR9342:
+		case ATH79_SOC_AR9344:
+			if (id == 0)
+				pdata->mii_bus_dev = &ath79_mdio0_device.dev;
+			else
+				pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+			break;
+
+		case ATH79_SOC_AR7241:
+		case ATH79_SOC_AR9330:
+		case ATH79_SOC_AR9331:
+		case ATH79_SOC_QCA9533:
+		case ATH79_SOC_TP9343:
+			pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+			break;
+
+		case ATH79_SOC_QCA9556:
+		case ATH79_SOC_QCA9558:
+			/* don't assign any MDIO device by default */
+			break;
+
+		case ATH79_SOC_QCA956X:
+			if (pdata->phy_if_mode != PHY_INTERFACE_MODE_SGMII)
+				pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+			break;
+
+		default:
+			pdata->mii_bus_dev = &ath79_mdio0_device.dev;
+			break;
+		}
+	}
+
+	/* Reset the device */
+	ath79_device_reset_set(pdata->reset_bit);
+	msleep(100);
+
+	ath79_device_reset_clear(pdata->reset_bit);
+	msleep(100);
+
+	platform_device_register(pdev);
+	ath79_eth_instance++;
+}
+
+void __init ath79_set_mac_base(unsigned char *mac)
+{
+	memcpy(ath79_mac_base, mac, ETH_ALEN);
+}
+
+void __init ath79_parse_ascii_mac(char *mac_str, u8 *mac)
+{
+	int t;
+
+	t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+		   &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+
+	if (t != ETH_ALEN)
+		t = sscanf(mac_str, "%02hhx.%02hhx.%02hhx.%02hhx.%02hhx.%02hhx",
+			&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+
+	if (t != ETH_ALEN || !is_valid_ether_addr(mac)) {
+		memset(mac, 0, ETH_ALEN);
+		printk(KERN_DEBUG "ar71xx: invalid mac address \"%s\"\n",
+		       mac_str);
+	}
+}
+
+static void __init ath79_set_mac_base_ascii(char *str)
+{
+	u8 mac[ETH_ALEN];
+
+	ath79_parse_ascii_mac(str, mac);
+	ath79_set_mac_base(mac);
+}
+
+static int __init ath79_ethaddr_setup(char *str)
+{
+	ath79_set_mac_base_ascii(str);
+	return 1;
+}
+__setup("ethaddr=", ath79_ethaddr_setup);
+
+static int __init ath79_kmac_setup(char *str)
+{
+	ath79_set_mac_base_ascii(str);
+	return 1;
+}
+__setup("kmac=", ath79_kmac_setup);
+
+void __init ath79_init_mac(unsigned char *dst, const unsigned char *src,
+			    int offset)
+{
+	int t;
+
+	if (!dst)
+		return;
+
+	if (!src || !is_valid_ether_addr(src)) {
+		memset(dst, '\0', ETH_ALEN);
+		return;
+	}
+
+	t = (((u32) src[3]) << 16) + (((u32) src[4]) << 8) + ((u32) src[5]);
+	t += offset;
+
+	dst[0] = src[0];
+	dst[1] = src[1];
+	dst[2] = src[2];
+	dst[3] = (t >> 16) & 0xff;
+	dst[4] = (t >> 8) & 0xff;
+	dst[5] = t & 0xff;
+}
+
+void __init ath79_init_local_mac(unsigned char *dst, const unsigned char *src)
+{
+	int i;
+
+	if (!dst)
+		return;
+
+	if (!src || !is_valid_ether_addr(src)) {
+		memset(dst, '\0', ETH_ALEN);
+		return;
+	}
+
+	for (i = 0; i < ETH_ALEN; i++)
+		dst[i] = src[i];
+	dst[0] |= 0x02;
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h
new file mode 100644
index 0000000000..5a226e4028
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.h
@@ -0,0 +1,53 @@
+/*
+ *  Atheros AR71xx SoC device definitions
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_DEV_ETH_H
+#define _ATH79_DEV_ETH_H
+
+#include <asm/mach-ath79/ag71xx_platform.h>
+
+struct platform_device;
+
+extern unsigned char ath79_mac_base[] __initdata;
+void ath79_parse_ascii_mac(char *mac_str, u8 *mac);
+void ath79_init_mac(unsigned char *dst, const unsigned char *src,
+		    int offset);
+void ath79_init_local_mac(unsigned char *dst, const unsigned char *src);
+
+struct ath79_eth_pll_data {
+	u32	pll_10;
+	u32	pll_100;
+	u32	pll_1000;
+};
+
+extern struct ath79_eth_pll_data ath79_eth0_pll_data;
+extern struct ath79_eth_pll_data ath79_eth1_pll_data;
+
+extern struct ag71xx_platform_data ath79_eth0_data;
+extern struct ag71xx_platform_data ath79_eth1_data;
+extern struct platform_device ath79_eth0_device;
+extern struct platform_device ath79_eth1_device;
+void ath79_register_eth(unsigned int id);
+
+extern struct ag71xx_switch_platform_data ath79_switch_data;
+
+extern struct ag71xx_mdio_platform_data ath79_mdio0_data;
+extern struct ag71xx_mdio_platform_data ath79_mdio1_data;
+extern struct platform_device ath79_mdio0_device;
+extern struct platform_device ath79_mdio1_device;
+void ath79_register_mdio(unsigned int id, u32 phy_mask);
+
+void ath79_setup_ar933x_phy4_switch(bool mac, bool mdio);
+void ath79_setup_ar934x_eth_cfg(u32 mask);
+void ath79_setup_ar934x_eth_rx_delay(unsigned int rxd, unsigned int rxdv);
+void ath79_setup_qca955x_eth_cfg(u32 mask);
+
+#endif /* _ATH79_DEV_ETH_H */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
new file mode 100644
index 0000000000..e5831d4883
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/init.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include "dev-spi.h"
+#include "dev-m25p80.h"
+
+static struct ath79_spi_controller_data ath79_spi0_cdata =
+{
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 0,
+};
+
+static struct ath79_spi_controller_data ath79_spi1_cdata =
+{
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 1,
+};
+
+static struct spi_board_info ath79_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 25000000,
+		.modalias	= "m25p80",
+		.controller_data = &ath79_spi0_cdata,
+	},
+	{
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz   = 25000000,
+		.modalias	= "m25p80",
+		.controller_data = &ath79_spi1_cdata,
+	}
+};
+
+static struct ath79_spi_platform_data ath79_spi_data;
+
+void __init ath79_register_m25p80(struct flash_platform_data *pdata)
+{
+	ath79_spi_data.bus_num = 0;
+	ath79_spi_data.num_chipselect = 1;
+	ath79_spi0_cdata.is_flash = true;
+	ath79_spi_info[0].platform_data = pdata;
+	ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
+}
+
+static struct flash_platform_data *multi_pdata;
+
+static struct mtd_info *concat_devs[2] = { NULL, NULL };
+static struct work_struct mtd_concat_work;
+
+static void mtd_concat_add_work(struct work_struct *work)
+{
+	struct mtd_info *mtd;
+
+	mtd = mtd_concat_create(concat_devs, ARRAY_SIZE(concat_devs), "flash");
+
+	mtd_device_register(mtd, multi_pdata->parts, multi_pdata->nr_parts);
+}
+
+static void mtd_concat_add(struct mtd_info *mtd)
+{
+	static bool registered = false;
+
+	if (registered)
+		return;
+
+	if (!strcmp(mtd->name, "spi0.0"))
+		concat_devs[0] = mtd;
+	else if (!strcmp(mtd->name, "spi0.1"))
+		concat_devs[1] = mtd;
+	else
+		return;
+
+	if (!concat_devs[0] || !concat_devs[1])
+		return;
+
+	registered = true;
+	INIT_WORK(&mtd_concat_work, mtd_concat_add_work);
+	schedule_work(&mtd_concat_work);
+}
+
+static void mtd_concat_remove(struct mtd_info *mtd)
+{
+}
+
+static void add_mtd_concat_notifier(void)
+{
+	static struct mtd_notifier not = {
+		.add = mtd_concat_add,
+		.remove = mtd_concat_remove,
+	};
+
+	register_mtd_user(&not);
+}
+
+void __init ath79_register_m25p80_large(struct flash_platform_data *pdata)
+{
+	ath79_spi_data.bus_num = 0;
+	ath79_spi_data.num_chipselect = 1;
+	ath79_spi0_cdata.is_flash = false;
+	ath79_spi_info[0].platform_data = pdata;
+	ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
+}
+
+void __init ath79_register_m25p80_multi(struct flash_platform_data *pdata)
+{
+	multi_pdata = pdata;
+	add_mtd_concat_notifier();
+	ath79_spi_data.bus_num = 0;
+	ath79_spi_data.num_chipselect = 2;
+	ath79_spi0_cdata.is_flash = true;
+	ath79_register_spi(&ath79_spi_data, ath79_spi_info, 2);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.h b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.h
new file mode 100644
index 0000000000..5e66016301
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.h
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_DEV_M25P80_H
+#define _ATH79_DEV_M25P80_H
+
+#include <linux/spi/flash.h>
+
+void ath79_register_m25p80(struct flash_platform_data *pdata) __init;
+void ath79_register_m25p80_large(struct flash_platform_data *pdata) __init;
+void ath79_register_m25p80_multi(struct flash_platform_data *pdata) __init;
+
+#endif /* _ATH79_DEV_M25P80_H */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.c
new file mode 100644
index 0000000000..9b5256ecc2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.c
@@ -0,0 +1,141 @@
+/*
+ *  Atheros AR934X SoCs built-in NAND flash controller support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/platform/ar934x_nfc.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "dev-nfc.h"
+
+static struct resource ath79_nfc_resources[2];
+static u64 ar934x_nfc_dmamask = DMA_BIT_MASK(32);
+static struct ar934x_nfc_platform_data ath79_nfc_data;
+
+static struct platform_device ath79_nfc_device = {
+	.name		= AR934X_NFC_DRIVER_NAME,
+	.id		= -1,
+	.resource	= ath79_nfc_resources,
+	.num_resources	= ARRAY_SIZE(ath79_nfc_resources),
+	.dev = {
+		.dma_mask = &ar934x_nfc_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &ath79_nfc_data,
+	},
+};
+
+static void __init ath79_nfc_init_resource(struct resource res[2],
+					   unsigned long base,
+					   unsigned long size,
+					   int irq)
+{
+	memset(res, 0, sizeof(struct resource) * 2);
+
+	res[0].flags = IORESOURCE_MEM;
+	res[0].start = base;
+	res[0].end = base + size - 1;
+
+	res[1].flags = IORESOURCE_IRQ;
+	res[1].start = irq;
+	res[1].end = irq;
+}
+
+static void ar934x_nfc_hw_reset(bool active)
+{
+	if (active) {
+		ath79_device_reset_set(AR934X_RESET_NANDF);
+		udelay(100);
+
+		ath79_device_reset_set(AR934X_RESET_ETH_SWITCH_ANALOG);
+		udelay(250);
+	} else {
+		ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH_ANALOG);
+		udelay(250);
+
+		ath79_device_reset_clear(AR934X_RESET_NANDF);
+		udelay(100);
+	}
+}
+
+static void ar934x_nfc_setup(void)
+{
+	ath79_nfc_data.hw_reset = ar934x_nfc_hw_reset;
+
+	ath79_nfc_init_resource(ath79_nfc_resources,
+				AR934X_NFC_BASE, AR934X_NFC_SIZE,
+				ATH79_MISC_IRQ(21));
+
+	platform_device_register(&ath79_nfc_device);
+}
+
+static void qca955x_nfc_hw_reset(bool active)
+{
+	if (active) {
+		ath79_device_reset_set(QCA955X_RESET_NANDF);
+		udelay(250);
+	} else {
+		ath79_device_reset_clear(QCA955X_RESET_NANDF);
+		udelay(100);
+	}
+}
+
+static void qca955x_nfc_setup(void)
+{
+	ath79_nfc_data.hw_reset = qca955x_nfc_hw_reset;
+
+	ath79_nfc_init_resource(ath79_nfc_resources,
+				QCA955X_NFC_BASE, QCA955X_NFC_SIZE,
+				ATH79_MISC_IRQ(21));
+
+	platform_device_register(&ath79_nfc_device);
+}
+
+void __init ath79_nfc_set_select_chip(void (*f)(int chip_no))
+{
+	ath79_nfc_data.select_chip = f;
+}
+
+void __init ath79_nfc_set_scan_fixup(int (*f)(struct mtd_info *mtd))
+{
+	ath79_nfc_data.scan_fixup = f;
+}
+
+void __init ath79_nfc_set_swap_dma(bool enable)
+{
+	ath79_nfc_data.swap_dma = enable;
+}
+
+void __init ath79_nfc_set_ecc_mode(enum ar934x_nfc_ecc_mode mode)
+{
+	ath79_nfc_data.ecc_mode = mode;
+}
+
+void __init ath79_nfc_set_parts(struct mtd_partition *parts, int nr_parts)
+{
+	ath79_nfc_data.parts = parts;
+	ath79_nfc_data.nr_parts = nr_parts;
+}
+
+void __init ath79_register_nfc(void)
+{
+	if (soc_is_ar934x())
+		ar934x_nfc_setup();
+	else if (soc_is_qca955x())
+		qca955x_nfc_setup();
+	else
+		BUG();
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.h b/target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.h
new file mode 100644
index 0000000000..3a1c88fe98
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-nfc.h
@@ -0,0 +1,34 @@
+/*
+ *  Atheros AR934X SoCs built-in NAND Flash Controller support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_DEV_NFC_H
+#define _ATH79_DEV_NFC_H
+
+struct mtd_partition;
+enum ar934x_nfc_ecc_mode;
+
+#ifdef CONFIG_ATH79_DEV_NFC
+void ath79_nfc_set_parts(struct mtd_partition *parts, int nr_parts);
+void ath79_nfc_set_select_chip(void (*f)(int chip_no));
+void ath79_nfc_set_scan_fixup(int (*f)(struct mtd_info *mtd));
+void ath79_nfc_set_swap_dma(bool enable);
+void ath79_nfc_set_ecc_mode(enum ar934x_nfc_ecc_mode mode);
+void ath79_register_nfc(void);
+#else
+static inline void ath79_nfc_set_parts(struct mtd_partition *parts,
+				       int nr_parts) {}
+static inline void ath79_nfc_set_select_chip(void (*f)(int chip_no)) {}
+static inline void ath79_nfc_set_scan_fixup(int (*f)(struct mtd_info *mtd)) {}
+static inline void ath79_nfc_set_swap_dma(bool enable) {}
+static inline void ath79_nfc_set_ecc_mode(enum ar934x_nfc_ecc_mode mode) {}
+static inline void ath79_register_nfc(void) {}
+#endif
+
+#endif /* _ATH79_DEV_NFC_H */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap120c.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap120c.c
new file mode 100644
index 0000000000..524f93d264
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap120c.c
@@ -0,0 +1,147 @@
+/*
+ *  ALFA Network AP120C board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2016 Luka Perkov <luka@openwrt.org>
+ *
+ *  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/init.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/ar8216_platform.h>
+#include <linux/ath9k_platform.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-spi.h"
+#include "dev-ap9x-pci.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define ALFA_AP120C_GPIO_LED	0
+
+#define ALFA_AP120C_GPIO_BUTTON_WIFI	16
+
+#define ALFA_AP120C_GPIO_WATCH_DOG	20
+
+#define ALFA_AP120C_KEYS_POLL_INTERVAL		20	/* msecs */
+#define ALFA_AP120C_KEYS_DEBOUNCE_INTERVAL	(3 * ALFA_AP120C_KEYS_POLL_INTERVAL)
+
+#define ALFA_AP120C_MAC_OFFSET		0x1002
+#define ALFA_AP120C_CAL0_OFFSET		0x1000
+
+static struct gpio_keys_button alfa_ap120c_gpio_keys[] __initdata = {
+	{
+		.desc		= "Wireless button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = ALFA_AP120C_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ALFA_AP120C_GPIO_BUTTON_WIFI,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led alfa_ap120c_leds_gpio[] __initdata = {
+	{
+			.name		= "ap120c:red:wlan",
+			.gpio		= ALFA_AP120C_GPIO_LED,
+			.active_low = 0,
+	}
+};
+
+static struct ar8327_pad_cfg ap120c_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data ap120c_ar8327_data = {
+	.pad0_cfg = &ap120c_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info ap120c_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &ap120c_ar8327_data,
+	},
+};
+
+static struct flash_platform_data flash __initdata = { NULL, NULL, 0 };
+
+#define ALFA_AP120C_LAN_PHYMASK		BIT(5)
+#define ALFA_AP120C_MDIO_PHYMASK	ALFA_AP120C_LAN_PHYMASK
+
+static void __init alfa_ap120c_init(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 mac[ETH_ALEN];
+
+	struct ath9k_platform_data *pdata;
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(alfa_ap120c_leds_gpio),
+							 alfa_ap120c_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, ALFA_AP120C_KEYS_POLL_INTERVAL,
+									ARRAY_SIZE(alfa_ap120c_gpio_keys),
+									alfa_ap120c_gpio_keys);
+
+	ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
+							   AR71XX_GPIO_FUNC_SPI_CS2_EN);
+
+	ath79_register_m25p80_multi(&flash);
+
+	ath79_init_mac(mac, art + ALFA_AP120C_MAC_OFFSET, 1);
+	ath79_register_wmac(art + ALFA_AP120C_CAL0_OFFSET, mac);
+
+	ath79_init_mac(mac, art + ALFA_AP120C_MAC_OFFSET, 2);
+	ap91_pci_init(NULL, mac);
+	pdata = ap9x_pci_get_wmac_data(0);
+	if (!pdata) {
+		pr_err("ap120c: unable to get address of wlan data\n");
+		return;
+	}
+	pdata->use_eeprom = true;
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+							   BIT(15) | BIT(17) | BIT(19) | BIT(21));
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + ALFA_AP120C_MAC_OFFSET, 0);
+
+	mdiobus_register_board_info(ap120c_mdio0_info, ARRAY_SIZE(ap120c_mdio0_info));
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = ALFA_AP120C_LAN_PHYMASK;
+
+	ath79_eth0_pll_data.pll_1000 = 0x42000000;
+	ath79_eth0_pll_data.pll_10 = 0x00001313;
+
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_ALFA_AP120C, "ALFA-AP120C", "ALFA Network AP120C",
+			 alfa_ap120c_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap96.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap96.c
new file mode 100644
index 0000000000..f7cd6aedfd
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-ap96.c
@@ -0,0 +1,151 @@
+/*
+ *  ALFA Network AP96 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/init.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.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-spi.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define ALFA_AP96_GPIO_PCIE_RESET	2
+#define ALFA_AP96_GPIO_SIM_DETECT	3
+#define ALFA_AP96_GPIO_MICROSD_CD	4
+#define ALFA_AP96_GPIO_PCIE_W_DISABLE	5
+
+#define ALFA_AP96_GPIO_BUTTON_RESET	11
+
+#define ALFA_AP96_KEYS_POLL_INTERVAL		20	/* msecs */
+#define ALFA_AP96_KEYS_DEBOUNCE_INTERVAL	(3 * ALFA_AP96_KEYS_POLL_INTERVAL)
+
+static struct gpio_keys_button alfa_ap96_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ALFA_AP96_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ALFA_AP96_GPIO_BUTTON_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct mmc_spi_platform_data alfa_ap96_mmc_data = {
+	.flags		= MMC_SPI_USE_CD_GPIO,
+	.cd_gpio	= ALFA_AP96_GPIO_MICROSD_CD,
+	.cd_debounce	= 1,
+	.caps		= MMC_CAP_NEEDS_POLL,
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct ath79_spi_controller_data ap96_spi0_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 0,
+	.is_flash = true,
+};
+
+static struct ath79_spi_controller_data ap96_spi1_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 1,
+};
+
+static struct ath79_spi_controller_data ap96_spi2_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 2,
+};
+
+static struct spi_board_info alfa_ap96_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 25000000,
+		.modalias	= "m25p80",
+		.controller_data = &ap96_spi0_cdata
+	}, {
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz	= 25000000,
+		.modalias	= "mmc_spi",
+		.platform_data	= &alfa_ap96_mmc_data,
+		.controller_data = &ap96_spi1_cdata
+	}, {
+		.bus_num	= 0,
+		.chip_select	= 2,
+		.max_speed_hz	= 6250000,
+		.modalias	= "rtc-pcf2123",
+		.controller_data = &ap96_spi2_cdata
+	},
+};
+
+static struct ath79_spi_platform_data alfa_ap96_spi_data = {
+	.bus_num		= 0,
+	.num_chipselect		= 3,
+};
+
+static void __init alfa_ap96_gpio_setup(void)
+{
+	ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
+				   AR71XX_GPIO_FUNC_SPI_CS2_EN);
+
+	gpio_request(ALFA_AP96_GPIO_MICROSD_CD, "microSD CD");
+	gpio_direction_input(ALFA_AP96_GPIO_MICROSD_CD);
+	gpio_request(ALFA_AP96_GPIO_PCIE_RESET, "PCIe reset");
+	gpio_direction_output(ALFA_AP96_GPIO_PCIE_RESET, 1);
+	gpio_request(ALFA_AP96_GPIO_PCIE_W_DISABLE, "PCIe write disable");
+	gpio_direction_output(ALFA_AP96_GPIO_PCIE_W_DISABLE, 1);
+}
+
+#define ALFA_AP96_WAN_PHYMASK	BIT(4)
+#define ALFA_AP96_LAN_PHYMASK	BIT(5)
+#define ALFA_AP96_MDIO_PHYMASK	(ALFA_AP96_LAN_PHYMASK | ALFA_AP96_WAN_PHYMASK)
+
+static void __init alfa_ap96_init(void)
+{
+	alfa_ap96_gpio_setup();
+
+	ath79_register_mdio(0, ~ALFA_AP96_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = ALFA_AP96_WAN_PHYMASK;
+	ath79_eth1_pll_data.pll_1000 = 0x110000;
+
+	ath79_register_eth(0);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = ALFA_AP96_LAN_PHYMASK;
+	ath79_eth1_pll_data.pll_1000 = 0x110000;
+
+	ath79_register_eth(1);
+
+	ath79_register_pci();
+	ath79_register_spi(&alfa_ap96_spi_data, alfa_ap96_spi_info,
+			   ARRAY_SIZE(alfa_ap96_spi_info));
+
+	ath79_register_gpio_keys_polled(-1, ALFA_AP96_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(alfa_ap96_gpio_keys),
+					 alfa_ap96_gpio_keys);
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_ALFA_AP96, "ALFA-AP96", "ALFA Network AP96",
+	     alfa_ap96_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-nx.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-nx.c
new file mode 100644
index 0000000000..a515f4f540
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-alfa-nx.c
@@ -0,0 +1,113 @@
+/*
+ *  ALFA Network N2/N5 board support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define ALFA_NX_GPIO_LED_2		17
+#define ALFA_NX_GPIO_LED_3		16
+#define ALFA_NX_GPIO_LED_5		12
+#define ALFA_NX_GPIO_LED_6		8
+#define ALFA_NX_GPIO_LED_7		6
+#define ALFA_NX_GPIO_LED_8		7
+
+#define ALFA_NX_GPIO_BTN_RESET		11
+
+#define ALFA_NX_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ALFA_NX_KEYS_DEBOUNCE_INTERVAL (3 * ALFA_NX_KEYS_POLL_INTERVAL)
+
+#define ALFA_NX_MAC0_OFFSET		0
+#define ALFA_NX_MAC1_OFFSET		6
+#define ALFA_NX_CALDATA_OFFSET		0x1000
+
+static struct gpio_keys_button alfa_nx_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ALFA_NX_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ALFA_NX_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led alfa_nx_leds_gpio[] __initdata = {
+	{
+		.name		= "alfa:green:led_2",
+		.gpio		= ALFA_NX_GPIO_LED_2,
+		.active_low	= 1,
+	}, {
+		.name		= "alfa:green:led_3",
+		.gpio		= ALFA_NX_GPIO_LED_3,
+		.active_low	= 1,
+	}, {
+		.name		= "alfa:red:led_5",
+		.gpio		= ALFA_NX_GPIO_LED_5,
+		.active_low	= 1,
+	}, {
+		.name		= "alfa:amber:led_6",
+		.gpio		= ALFA_NX_GPIO_LED_6,
+		.active_low	= 1,
+	}, {
+		.name		= "alfa:green:led_7",
+		.gpio		= ALFA_NX_GPIO_LED_7,
+		.active_low	= 1,
+	}, {
+		.name		= "alfa:green:led_8",
+		.gpio		= ALFA_NX_GPIO_LED_8,
+		.active_low	= 1,
+	}
+};
+
+static void __init alfa_nx_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE,
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(0, ARRAY_SIZE(alfa_nx_leds_gpio),
+				 alfa_nx_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ALFA_NX_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(alfa_nx_gpio_keys),
+					alfa_nx_gpio_keys);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + ALFA_NX_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr,
+		       art + ALFA_NX_MAC1_OFFSET, 0);
+
+	/* WAN port */
+	ath79_register_eth(0);
+	/* LAN port */
+	ath79_register_eth(1);
+
+	ap91_pci_init(art + ALFA_NX_CALDATA_OFFSET, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_ALFA_NX, "ALFA-NX", "ALFA Network N2/N5",
+	     alfa_nx_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-all0258n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-all0258n.c
new file mode 100644
index 0000000000..2495bcba79
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-all0258n.c
@@ -0,0 +1,88 @@
+/*
+ *  Allnet ALL0258N support
+ *
+ *  Copyright (C) 2011 Daniel Golle <dgolle@allnet.de>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+/* found via /sys/gpio/... try and error */
+#define ALL0258N_GPIO_BTN_RESET		1
+#define ALL0258N_GPIO_LED_RSSIHIGH	13
+#define ALL0258N_GPIO_LED_RSSIMEDIUM	15
+#define ALL0258N_GPIO_LED_RSSILOW	14
+
+/* defaults taken from others machs */
+#define ALL0258N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ALL0258N_KEYS_DEBOUNCE_INTERVAL (3 * ALL0258N_KEYS_POLL_INTERVAL)
+
+/* showed up in the original firmware's bootlog */
+#define ALL0258N_SEC_PHYMASK BIT(3)
+
+static struct gpio_led all0258n_leds_gpio[] __initdata = {
+	{
+		.name		= "all0258n:green:rssihigh",
+		.gpio		= ALL0258N_GPIO_LED_RSSIHIGH,
+		.active_low	= 1,
+	}, {
+		.name		= "all0258n:yellow:rssimedium",
+		.gpio		= ALL0258N_GPIO_LED_RSSIMEDIUM,
+		.active_low	= 1,
+	}, {
+		.name		= "all0258n:red:rssilow",
+		.gpio		= ALL0258N_GPIO_LED_RSSILOW,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button all0258n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ALL0258N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ALL0258N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init all0258n_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f7f0000);
+	u8 *ee =  (u8 *) KSEG1ADDR(0x1f7f1000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(all0258n_leds_gpio),
+				 all0258n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ALL0258N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(all0258n_gpio_keys),
+					all0258n_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	ath79_eth1_data.phy_mask = ALL0258N_SEC_PHYMASK;
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ap91_pci_init(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_ALL0258N, "ALL0258N", "Allnet ALL0258N",
+	     all0258n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-all0315n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-all0315n.c
new file mode 100644
index 0000000000..387ee7f9ea
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-all0315n.c
@@ -0,0 +1,85 @@
+/*
+ *  Allnet ALL0315N support
+ *
+ *  Copyright (C) 2012 Daniel Golle <dgolle@allnet.de>
+ *
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-m25p80.h"
+#include "dev-leds-gpio.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define ALL0315N_GPIO_BTN_RESET		0
+#define ALL0315N_GPIO_LED_RSSIHIGH	14
+#define ALL0315N_GPIO_LED_RSSIMEDIUM	15
+#define ALL0315N_GPIO_LED_RSSILOW	16
+
+#define ALL0315N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ALL0315N_KEYS_DEBOUNCE_INTERVAL	(3 * ALL0315N_KEYS_POLL_INTERVAL)
+
+static struct gpio_led all0315n_leds_gpio[] __initdata = {
+	{
+		.name		= "all0315n:green:rssihigh",
+		.gpio		= ALL0315N_GPIO_LED_RSSIHIGH,
+		.active_low	= 1,
+	}, {
+		.name		= "all0315n:yellow:rssimedium",
+		.gpio		= ALL0315N_GPIO_LED_RSSIMEDIUM,
+		.active_low	= 1,
+	}, {
+		.name		= "all0315n:red:rssilow",
+		.gpio		= ALL0315N_GPIO_LED_RSSILOW,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button all0315n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ALL0315N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ALL0315N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init all0315n_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1ffc0000);
+	u8 *ee =  (u8 *) KSEG1ADDR(0x1ffc1000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(all0315n_leds_gpio),
+					all0315n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ALL0315N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(all0315n_gpio_keys),
+					all0315n_gpio_keys);
+
+	ap9x_pci_setup_wmac_led_pin(0, 1);
+	ap91_pci_init(ee, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_ALL0315N, "ALL0315N", "Allnet ALL0315N",
+	     all0315n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s1.c
new file mode 100644
index 0000000000..0a81227b51
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s1.c
@@ -0,0 +1,98 @@
+/*
+ *   Bitmain Antminer S1 board support
+ *
+ *  Copyright (C) 2015 L. D. Pinney <ldpinney@gmail.com>
+ *
+ *  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 <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"
+#include "dev-usb.h"
+
+#define ANTMINER_S1_GPIO_BTN_RESET		11
+
+#define ANTMINER_S1_GPIO_LED_SYSTEM		23
+#define ANTMINER_S1_GPIO_LED_WLAN		0
+#define ANTMINER_S1_GPIO_USB_POWER		26
+
+#define ANTMINER_S1_KEYSPOLL_INTERVAL	20	/* msecs */
+#define ANTMINER_S1_KEYSDEBOUNCE_INTERVAL (3 * ANTMINER_S1_KEYSPOLL_INTERVAL)
+
+static const char *ANTMINER_S1_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data ANTMINER_S1_flash_data = {
+	.part_probes	= ANTMINER_S1_part_probes,
+};
+
+static struct gpio_led ANTMINER_S1_leds_gpio[] __initdata = {
+	{
+		.name		= "antminer-s1:green:system",
+		.gpio		= ANTMINER_S1_GPIO_LED_SYSTEM,
+		.active_low	= 0,
+	},{
+		.name		= "antminer-s1:green:wlan",
+		.gpio		= ANTMINER_S1_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button ANTMINER_S1_GPIO_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ANTMINER_S1_KEYSDEBOUNCE_INTERVAL,
+		.gpio		= ANTMINER_S1_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+};
+
+static void __init antminer_s1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ANTMINER_S1_leds_gpio),
+				 ANTMINER_S1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ANTMINER_S1_KEYSPOLL_INTERVAL,
+					ARRAY_SIZE(ANTMINER_S1_GPIO_keys),
+					ANTMINER_S1_GPIO_keys);
+
+	gpio_request_one(ANTMINER_S1_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_m25p80(&ANTMINER_S1_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_ANTMINER_S1, "ANTMINER-S1",
+	     "Antminer-S1", antminer_s1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s3.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s3.c
new file mode 100644
index 0000000000..b77a6ccc4e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-antminer-s3.c
@@ -0,0 +1,103 @@
+/*
+ *   Bitmain Antminer S3 board support
+ *
+ *  Copyright (C) 2015 L. D. Pinney <ldpinney@gmail.com>
+ *
+ *  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 <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"
+#include "dev-usb.h"
+
+#define ANTMINER_S3_GPIO_LED_WLAN		0
+#define ANTMINER_S3_GPIO_LED_SYSTEM		17
+#define ANTMINER_S3_GPIO_LED_LAN		22
+#define ANTMINER_S3_GPIO_USB_POWER		26
+
+#define ANTMINER_S3_GPIO_BTN_RESET		11
+
+#define ANTMINER_S3_KEYSPOLL_INTERVAL	88	/* msecs */
+#define ANTMINER_S3_KEYSDEBOUNCE_INTERVAL (3 * ANTMINER_S3_KEYSPOLL_INTERVAL)
+
+static const char *ANTMINER_S3_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data ANTMINER_S3_flash_data = {
+	.part_probes	= ANTMINER_S3_part_probes,
+};
+
+static struct gpio_led ANTMINER_S3_leds_gpio[] __initdata = {
+	{
+		.name		= "antminer-s3:green:wlan",
+		.gpio		= ANTMINER_S3_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},{
+		.name		= "antminer-s3:green:system",
+		.gpio		= ANTMINER_S3_GPIO_LED_SYSTEM,
+		.active_low	= 0,
+	},{
+		.name		= "antminer-s3:yellow:lan",
+		.gpio		= ANTMINER_S3_GPIO_LED_LAN,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button ANTMINER_S3_GPIO_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ANTMINER_S3_KEYSDEBOUNCE_INTERVAL,
+		.gpio		= ANTMINER_S3_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+};
+
+static void __init antminer_s3_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ANTMINER_S3_leds_gpio),
+				 ANTMINER_S3_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ANTMINER_S3_KEYSPOLL_INTERVAL,
+					ARRAY_SIZE(ANTMINER_S3_GPIO_keys),
+					ANTMINER_S3_GPIO_keys);
+
+	gpio_request_one(ANTMINER_S3_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_m25p80(&ANTMINER_S3_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_ANTMINER_S3, "ANTMINER-S3",
+	     "Antminer-S3", antminer_s3_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-antrouter-r1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-antrouter-r1.c
new file mode 100644
index 0000000000..a8f7b5d687
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-antrouter-r1.c
@@ -0,0 +1,98 @@
+/*
+ *  Bitmain Antrouter R1 board support
+ *
+ *  Copyright (C) 2015 L. D. Pinney <ldpinney@gmail.com>
+ *
+ *  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 <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"
+#include "dev-usb.h"
+
+#define ANTROUTER_R1_GPIO_BTN_RESET		11
+
+#define ANTROUTER_R1_GPIO_LED_WLAN		0
+#define ANTROUTER_R1_GPIO_LED_BTC		22
+#define ANTROUTER_R1_GPIO_USB_POWER		18
+
+#define ANTROUTER_R1_KEYSPOLL_INTERVAL	44	/* msecs */
+#define ANTROUTER_R1_KEYSDEBOUNCE_INTERVAL (4 * ANTROUTER_R1_KEYSPOLL_INTERVAL)
+
+static const char *ANTROUTER_R1_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data ANTROUTER_R1_flash_data = {
+	.part_probes	= ANTROUTER_R1_part_probes,
+};
+
+static struct gpio_led ANTROUTER_R1_leds_gpio[] __initdata = {
+	{
+		.name		= "antrouter-r1:green:wlan",
+		.gpio		= ANTROUTER_R1_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},{
+		.name		= "antrouter-r1:green:system",
+		.gpio		= ANTROUTER_R1_GPIO_LED_BTC,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button ANTROUTER_R1_GPIO_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ANTROUTER_R1_KEYSDEBOUNCE_INTERVAL,
+		.gpio		= ANTROUTER_R1_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+};
+
+static void __init antrouter_r1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ANTROUTER_R1_leds_gpio),
+				 ANTROUTER_R1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ANTROUTER_R1_KEYSPOLL_INTERVAL,
+					ARRAY_SIZE(ANTROUTER_R1_GPIO_keys),
+					ANTROUTER_R1_GPIO_keys);
+
+	gpio_request_one(ANTROUTER_R1_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_m25p80(&ANTROUTER_R1_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_ANTROUTER_R1, "ANTROUTER-R1",
+	     "Antrouter-R1", antrouter_r1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap113.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap113.c
new file mode 100644
index 0000000000..9b38faa47c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap113.c
@@ -0,0 +1,84 @@
+/*
+ *  Atheros AP113 board support
+ *
+ *  Copyright (C) 2011 Florian Fainelli <florian@openwrt.org>
+ *
+ *  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 "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "pci.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define AP113_GPIO_LED_USB		0
+#define AP113_GPIO_LED_STATUS		1
+#define AP113_GPIO_LED_ST		11
+
+#define AP113_GPIO_BTN_JUMPSTART	12
+
+#define AP113_KEYS_POLL_INTERVAL	20	/* msecs */
+#define AP113_KEYS_DEBOUNCE_INTERVAL	(3 * AP113_KEYS_POLL_INTERVAL)
+
+static struct gpio_led ap113_leds_gpio[] __initdata = {
+	{
+		.name		= "ap113:green:usb",
+		.gpio		= AP113_GPIO_LED_USB,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap113:green:status",
+		.gpio		= AP113_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap113:green:st",
+		.gpio		= AP113_GPIO_LED_ST,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button ap113_gpio_keys[] __initdata = {
+	{
+		.desc		= "jumpstart button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP113_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP113_GPIO_BTN_JUMPSTART,
+		.active_low	= 1,
+	},
+};
+
+static void __init ap113_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_mdio(0, ~BIT(0));
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_register_eth(0);
+
+	ath79_register_gpio_keys_polled(-1, AP113_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(ap113_gpio_keys),
+					 ap113_gpio_keys);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap113_leds_gpio),
+					ap113_leds_gpio);
+
+	ath79_register_pci();
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_AP113, "AP113", "Atheros AP113",
+	     ap113_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap132.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap132.c
new file mode 100644
index 0000000000..86fd8bd7a9
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap132.c
@@ -0,0 +1,189 @@
+/*
+ * Atheros AP132 reference board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2013 Embedded Wireless GmbH <info@embeddedwireless.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define AP132_GPIO_LED_USB		4
+#define AP132_GPIO_LED_WLAN_5G		12
+#define AP132_GPIO_LED_WLAN_2G		13
+#define AP132_GPIO_LED_STATUS_RED	14
+#define AP132_GPIO_LED_WPS_RED		15
+
+#define AP132_GPIO_BTN_WPS		16
+
+#define AP132_KEYS_POLL_INTERVAL	20	/* msecs */
+#define AP132_KEYS_DEBOUNCE_INTERVAL	(3 * AP132_KEYS_POLL_INTERVAL)
+
+#define AP132_MAC0_OFFSET		0
+#define AP132_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led ap132_leds_gpio[] __initdata = {
+	{
+		.name		= "ap132:red:status",
+		.gpio		= AP132_GPIO_LED_STATUS_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap132:red:wps",
+		.gpio		= AP132_GPIO_LED_WPS_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap132:red:wlan-2g",
+		.gpio		= AP132_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap132:red:usb",
+		.gpio		= AP132_GPIO_LED_USB,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button ap132_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP132_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP132_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg ap132_ar8327_pad0_cfg;
+
+static struct ar8327_platform_data ap132_ar8327_data = {
+	.pad0_cfg = &ap132_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info ap132_mdio1_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.1",
+		.phy_addr = 0,
+		.platform_data = &ap132_ar8327_data,
+	},
+};
+
+static void __init ap132_mdio_setup(void)
+{
+	void __iomem *base;
+	u32 t;
+
+#define GPIO_IN_ENABLE3_ADDRESS                                      0x0050
+#define GPIO_IN_ENABLE3_MII_GE1_MDI_MASK                             0x00ff0000
+#define GPIO_IN_ENABLE3_MII_GE1_MDI_LSB                              16
+#define GPIO_IN_ENABLE3_MII_GE1_MDI_SET(x)                           (((x) << GPIO_IN_ENABLE3_MII_GE1_MDI_LSB) & GPIO_IN_ENABLE3_MII_GE1_MDI_MASK)
+#define GPIO_OUT_FUNCTION4_ADDRESS                                   0x003c
+#define GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_MASK                       0xff000000
+#define GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_LSB                        24
+#define GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_SET(x)                     (((x) << GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_LSB) & GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_MASK)
+#define GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_MASK                       0x0000ff00
+#define GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_LSB                        8
+#define GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_SET(x)                     (((x) << GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_LSB) & GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_MASK)
+
+	base = ioremap(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
+
+	t = __raw_readl(base + GPIO_IN_ENABLE3_ADDRESS);
+	t &= ~GPIO_IN_ENABLE3_MII_GE1_MDI_MASK;
+	t |= GPIO_IN_ENABLE3_MII_GE1_MDI_SET(19);
+	__raw_writel(t, base + GPIO_IN_ENABLE3_ADDRESS);
+
+
+	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << 19), base + AR71XX_GPIO_REG_OE);
+
+	__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << 17), base + AR71XX_GPIO_REG_OE);
+
+
+	t = __raw_readl(base + GPIO_OUT_FUNCTION4_ADDRESS);
+	t &= ~(GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_MASK | GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_MASK);
+	t |= GPIO_OUT_FUNCTION4_ENABLE_GPIO_19_SET(0x20) | GPIO_OUT_FUNCTION4_ENABLE_GPIO_17_SET(0x21);
+	__raw_writel(t, base + GPIO_OUT_FUNCTION4_ADDRESS);
+
+	iounmap(base);
+
+}
+
+static void __init ap132_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap132_leds_gpio),
+				 ap132_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, AP132_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ap132_gpio_keys),
+					ap132_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(art + AP132_WMAC_CALDATA_OFFSET, NULL);
+
+	/* GMAC0 of the AR8327 switch is connected to GMAC1 via SGMII */
+	ap132_ar8327_pad0_cfg.mode = AR8327_PAD_MAC_SGMII;
+	ap132_ar8327_pad0_cfg.sgmii_delay_en = true;
+
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ap132_mdio_setup();
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + AP132_MAC0_OFFSET, 0);
+
+	mdiobus_register_board_info(ap132_mdio1_info,
+				    ARRAY_SIZE(ap132_mdio1_info));
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_mask = BIT(0);
+	ath79_eth1_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP132, "AP132",
+	     "Atheros AP132 reference board",
+	     ap132_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap143.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap143.c
new file mode 100644
index 0000000000..098420b92f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap143.c
@@ -0,0 +1,142 @@
+/*
+ * Atheros AP143 reference board support
+ *
+ * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define AP143_GPIO_LED_WLAN		12
+#define AP143_GPIO_LED_WPS		13
+#define AP143_GPIO_LED_STATUS		13
+
+#define AP143_GPIO_LED_WAN		4
+#define AP143_GPIO_LED_LAN1		16
+#define AP143_GPIO_LED_LAN2		15
+#define AP143_GPIO_LED_LAN3		14
+#define AP143_GPIO_LED_LAN4		11
+
+#define AP143_GPIO_BTN_WPS		17
+
+#define AP143_KEYS_POLL_INTERVAL	20	/* msecs */
+#define AP143_KEYS_DEBOUNCE_INTERVAL	(3 * AP143_KEYS_POLL_INTERVAL)
+
+#define AP143_MAC0_OFFSET		0
+#define AP143_MAC1_OFFSET		6
+#define AP143_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led ap143_leds_gpio[] __initdata = {
+	{
+		.name		= "ap143:green:status",
+		.gpio		= AP143_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap143:green:wlan",
+		.gpio		= AP143_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button ap143_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP143_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP143_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static void __init ap143_gpio_led_setup(void)
+{
+	ath79_gpio_direction_select(AP143_GPIO_LED_WAN, true);
+	ath79_gpio_direction_select(AP143_GPIO_LED_LAN1, true);
+	ath79_gpio_direction_select(AP143_GPIO_LED_LAN2, true);
+	ath79_gpio_direction_select(AP143_GPIO_LED_LAN3, true);
+	ath79_gpio_direction_select(AP143_GPIO_LED_LAN4, true);
+
+	ath79_gpio_output_select(AP143_GPIO_LED_WAN,
+			QCA953X_GPIO_OUT_MUX_LED_LINK5);
+	ath79_gpio_output_select(AP143_GPIO_LED_LAN1,
+			QCA953X_GPIO_OUT_MUX_LED_LINK1);
+	ath79_gpio_output_select(AP143_GPIO_LED_LAN2,
+			QCA953X_GPIO_OUT_MUX_LED_LINK2);
+	ath79_gpio_output_select(AP143_GPIO_LED_LAN3,
+			QCA953X_GPIO_OUT_MUX_LED_LINK3);
+	ath79_gpio_output_select(AP143_GPIO_LED_LAN4,
+			QCA953X_GPIO_OUT_MUX_LED_LINK4);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap143_leds_gpio),
+			ap143_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, AP143_KEYS_POLL_INTERVAL,
+			ARRAY_SIZE(ap143_gpio_keys),
+			ap143_gpio_keys);
+}
+
+static void __init ap143_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ap143_gpio_led_setup();
+
+	ath79_register_usb();
+
+	ath79_wmac_set_led_pin(AP143_GPIO_LED_WLAN);
+	ath79_register_wmac(art + AP143_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + AP143_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + AP143_MAC1_OFFSET, 0);
+
+	/* WAN port */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_register_eth(0);
+
+	/* LAN ports */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP143, "AP143", "Qualcomm Atheros AP143 reference board",
+	     ap143_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap147.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap147.c
new file mode 100644
index 0000000000..7b45da4711
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap147.c
@@ -0,0 +1,125 @@
+/*
+ *  Atheros AP147 reference board support
+ *
+ *  Copyright (C) 2014 Matthias Schiffer <mschiffer@universe-factory.net>
+ *  Copyright (C) 2015 Sven Eckelmann <sven@open-mesh.com>
+ *
+ *  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/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define AP147_GPIO_LED_WAN	4
+#define AP147_GPIO_LED_LAN1	16
+#define AP147_GPIO_LED_LAN2	15
+#define AP147_GPIO_LED_LAN3	14
+#define AP147_GPIO_LED_LAN4	11
+#define AP147_GPIO_LED_STATUS	13
+#define AP147_GPIO_LED_WLAN_2G	12
+
+#define AP147_GPIO_BTN_WPS	17
+
+#define AP147_KEYS_POLL_INTERVAL	20	/* msecs */
+#define AP147_KEYS_DEBOUNCE_INTERVAL	(3 * AP147_KEYS_POLL_INTERVAL)
+
+#define AP147_MAC0_OFFSET	0x1000
+
+static struct gpio_led ap147_leds_gpio[] __initdata = {
+	{
+		.name		= "ap147:green:status",
+		.gpio		= AP147_GPIO_LED_STATUS,
+		.active_low	= 1,
+	}, {
+		.name		= "ap147:green:wlan-2g",
+		.gpio		= AP147_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	}, {
+		.name		= "ap147:green:lan1",
+		.gpio		= AP147_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "ap147:green:lan2",
+		.gpio		= AP147_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "ap147:green:lan3",
+		.gpio		= AP147_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "ap147:green:lan4",
+		.gpio		= AP147_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "ap147:green:wan",
+		.gpio		= AP147_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button ap147_gpio_keys[] __initdata = {
+	{
+		.desc		= "wps button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP147_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP147_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static void __init ap147_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap147_leds_gpio),
+				 ap147_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, AP147_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ap147_gpio_keys),
+					ap147_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_pci();
+
+	ath79_register_wmac(art + AP147_MAC0_OFFSET, NULL);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art, 0);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, art, 1);
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP147_010, "AP147-010", "Atheros AP147-010 reference board", ap147_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap152.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap152.c
new file mode 100644
index 0000000000..e669325f50
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap152.c
@@ -0,0 +1,140 @@
+
+/*
+ * Qualcomm Atheros AP152 reference board support
+ *
+ * Copyright (c) 2015 Qualcomm Atheros
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+#include "pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+
+#define AP152_GPIO_LED_USB0		7
+#define AP152_GPIO_LED_USB1		8
+
+#define AP152_GPIO_BTN_RESET            2
+#define AP152_GPIO_BTN_WPS              1
+#define AP152_KEYS_POLL_INTERVAL        20     /* msecs */
+#define AP152_KEYS_DEBOUNCE_INTERVAL    (3 * AP152_KEYS_POLL_INTERVAL)
+
+#define AP152_MAC0_OFFSET               0
+#define AP152_WMAC_CALDATA_OFFSET       0x1000
+
+static struct gpio_led ap152_leds_gpio[] __initdata = {
+	{
+		.name		= "ap152:green:usb0",
+		.gpio		= AP152_GPIO_LED_USB0,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap152:green:usb1",
+		.gpio		= AP152_GPIO_LED_USB1,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button ap152_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP152_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP152_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = AP152_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP152_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg ap152_ar8337_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data ap152_ar8337_data = {
+	.pad0_cfg = &ap152_ar8337_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info ap152_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &ap152_ar8337_data,
+	},
+};
+
+static void __init ap152_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap152_leds_gpio),
+				 ap152_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, AP152_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ap152_gpio_keys),
+					ap152_gpio_keys);
+
+	ath79_register_usb();
+
+	platform_device_register(&ath79_mdio0_device);
+
+	mdiobus_register_board_info(ap152_mdio0_info,
+				    ARRAY_SIZE(ap152_mdio0_info));
+
+	ath79_register_wmac(art + AP152_WMAC_CALDATA_OFFSET, NULL);
+	ath79_register_pci();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + AP152_MAC0_OFFSET, 0);
+
+	/* GMAC0 is connected to an AR8337 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP152, "AP152", "Qualcomm Atheros AP152 reference board",
+	     ap152_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap83.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap83.c
new file mode 100644
index 0000000000..8519a9d9a6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap83.c
@@ -0,0 +1,275 @@
+/*
+ *  Atheros AP83 board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/spi/vsc7385.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define AP83_GPIO_LED_WLAN	6
+#define AP83_GPIO_LED_POWER	14
+#define AP83_GPIO_LED_JUMPSTART	15
+#define AP83_GPIO_BTN_JUMPSTART	12
+#define AP83_GPIO_BTN_RESET	21
+
+#define AP83_050_GPIO_VSC7385_CS	1
+#define AP83_050_GPIO_VSC7385_MISO	3
+#define AP83_050_GPIO_VSC7385_MOSI	16
+#define AP83_050_GPIO_VSC7385_SCK	17
+
+#define AP83_KEYS_POLL_INTERVAL		20	/* msecs */
+#define AP83_KEYS_DEBOUNCE_INTERVAL	(3 * AP83_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition ap83_flash_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x040000,
+		.size		= 0x020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "kernel",
+		.offset		= 0x060000,
+		.size		= 0x140000,
+	}, {
+		.name		= "rootfs",
+		.offset		= 0x1a0000,
+		.size		= 0x650000,
+	}, {
+		.name		= "art",
+		.offset		= 0x7f0000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x060000,
+		.size		= 0x790000,
+	}
+};
+
+static struct physmap_flash_data ap83_flash_data = {
+	.width		= 2,
+	.parts		= ap83_flash_partitions,
+	.nr_parts	= ARRAY_SIZE(ap83_flash_partitions),
+};
+
+static struct resource ap83_flash_resources[] = {
+	[0] = {
+		.start	= AR71XX_SPI_BASE,
+		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ap83_flash_device = {
+	.name		= "ar91xx-flash",
+	.id		= -1,
+	.resource	= ap83_flash_resources,
+	.num_resources	= ARRAY_SIZE(ap83_flash_resources),
+	.dev		= {
+		.platform_data = &ap83_flash_data,
+	}
+};
+
+static struct gpio_led ap83_leds_gpio[] __initdata = {
+	{
+		.name		= "ap83:green:jumpstart",
+		.gpio		= AP83_GPIO_LED_JUMPSTART,
+		.active_low	= 0,
+	}, {
+		.name		= "ap83:green:power",
+		.gpio		= AP83_GPIO_LED_POWER,
+		.active_low	= 0,
+	}, {
+		.name		= "ap83:green:wlan",
+		.gpio		= AP83_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button ap83_gpio_keys[] __initdata = {
+	{
+		.desc		= "soft_reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = AP83_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP83_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "jumpstart",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP83_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP83_GPIO_BTN_JUMPSTART,
+		.active_low	= 1,
+	}
+};
+
+static struct resource ap83_040_spi_resources[] = {
+	[0] = {
+		.start	= AR71XX_SPI_BASE,
+		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ap83_040_spi_device = {
+	.name		= "ap83-spi",
+	.id		= 0,
+	.resource	= ap83_040_spi_resources,
+	.num_resources	= ARRAY_SIZE(ap83_040_spi_resources),
+};
+
+static struct spi_gpio_platform_data ap83_050_spi_data = {
+	.miso	= AP83_050_GPIO_VSC7385_MISO,
+	.mosi	= AP83_050_GPIO_VSC7385_MOSI,
+	.sck	= AP83_050_GPIO_VSC7385_SCK,
+	.num_chipselect = 1,
+};
+
+static struct platform_device ap83_050_spi_device = {
+	.name		= "spi_gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &ap83_050_spi_data,
+	}
+};
+
+static void ap83_vsc7385_reset(void)
+{
+	ath79_device_reset_set(AR71XX_RESET_GE1_PHY);
+	udelay(10);
+	ath79_device_reset_clear(AR71XX_RESET_GE1_PHY);
+	mdelay(50);
+}
+
+static struct vsc7385_platform_data ap83_vsc7385_data = {
+	.reset		= ap83_vsc7385_reset,
+	.ucode_name	= "vsc7385_ucode_ap83.bin",
+	.mac_cfg = {
+		.tx_ipg		= 6,
+		.bit2		= 0,
+		.clk_sel	= 3,
+	},
+};
+
+static struct spi_board_info ap83_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 25000000,
+		.modalias	= "spi-vsc7385",
+		.platform_data	= &ap83_vsc7385_data,
+		.controller_data = (void *) AP83_050_GPIO_VSC7385_CS,
+	}
+};
+
+static void __init ap83_generic_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_mdio(0, 0xfffffffe);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, eeprom, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = 0x1;
+
+	ath79_register_eth(0);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, eeprom, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_eth1_pll_data.pll_1000 = 0x1f000000;
+
+	ath79_register_eth(1);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap83_leds_gpio),
+					ap83_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, AP83_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(ap83_gpio_keys),
+					 ap83_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(eeprom, NULL);
+
+	platform_device_register(&ap83_flash_device);
+
+	spi_register_board_info(ap83_spi_info, ARRAY_SIZE(ap83_spi_info));
+}
+
+static void ap83_040_flash_lock(struct platform_device *pdev)
+{
+	ath79_flash_acquire();
+}
+
+static void ap83_040_flash_unlock(struct platform_device *pdev)
+{
+	ath79_flash_release();
+}
+
+static void __init ap83_040_setup(void)
+{
+	ap83_flash_data.lock = ap83_040_flash_lock;
+	ap83_flash_data.unlock = ap83_040_flash_unlock;
+	ap83_generic_setup();
+	platform_device_register(&ap83_040_spi_device);
+}
+
+static void __init ap83_050_setup(void)
+{
+	ap83_generic_setup();
+	platform_device_register(&ap83_050_spi_device);
+}
+
+static void __init ap83_setup(void)
+{
+	u8 *board_id = (u8 *) KSEG1ADDR(0x1fff1244);
+	unsigned int board_version;
+
+	board_version = (unsigned int)(board_id[0] - '0');
+	board_version += ((unsigned int)(board_id[1] - '0')) * 10;
+
+	switch (board_version) {
+	case 40:
+		ap83_040_setup();
+		break;
+	case 50:
+		ap83_050_setup();
+		break;
+	default:
+		printk(KERN_WARNING "AP83-%03u board is not yet supported\n",
+		       board_version);
+	}
+}
+
+MIPS_MACHINE(ATH79_MACH_AP83, "AP83", "Atheros AP83", ap83_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap90q.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap90q.c
new file mode 100644
index 0000000000..2e9d34d658
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap90q.c
@@ -0,0 +1,201 @@
+/*
+ * Support for YunCore boards:
+ * - AP90Q
+ * - CPE830
+ *
+ * Copyright (C) 2016 Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * 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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+/* AP90Q */
+#define AP90Q_GPIO_LED_WAN	4
+#define AP90Q_GPIO_LED_WLAN	12
+#define AP90Q_GPIO_LED_LAN	16
+
+#define AP90Q_GPIO_BTN_RESET	17
+
+#define AP90Q_KEYS_POLL_INTERVAL	20
+#define AP90Q_KEYS_DEBOUNCE_INTERVAL	(3 * AP90Q_KEYS_POLL_INTERVAL)
+
+static struct gpio_led ap90q_leds_gpio[] __initdata = {
+	{
+		.name		= "ap90q:green:lan",
+		.gpio		= AP90Q_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap90q:green:wan",
+		.gpio		= AP90Q_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "ap90q:green:wlan",
+		.gpio		= AP90Q_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button ap90q_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = AP90Q_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP90Q_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+/* CPE830 */
+#define CPE830_GPIO_LED_LINK4	0
+#define CPE830_GPIO_LED_LINK1	1
+#define CPE830_GPIO_LED_LINK2	2
+#define CPE830_GPIO_LED_LINK3	3
+#define CPE830_GPIO_LED_WAN	4
+#define CPE830_GPIO_LED_WLAN	12
+#define CPE830_GPIO_LED_LAN	16
+
+#define CPE830_GPIO_BTN_RESET	17
+
+static struct gpio_led cpe830_leds_gpio[] __initdata = {
+	{
+		.name		= "cpe830:green:lan",
+		.gpio		= CPE830_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe830:green:wan",
+		.gpio		= CPE830_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe830:green:wlan",
+		.gpio		= CPE830_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe830:green:link1",
+		.gpio		= CPE830_GPIO_LED_LINK1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe830:green:link2",
+		.gpio		= CPE830_GPIO_LED_LINK2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe830:green:link3",
+		.gpio		= CPE830_GPIO_LED_LINK3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe830:green:link4",
+		.gpio		= CPE830_GPIO_LED_LINK4,
+		.active_low	= 1,
+	},
+};
+
+static void __init ap90q_cpe830_common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+
+	/* LAN */
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art, NULL);
+
+	/* For LED on GPIO4 */
+	ath79_gpio_function_disable(AR934X_GPIO_FUNC_CLK_OBS4_EN);
+
+	ath79_gpio_direction_select(AP90Q_GPIO_LED_LAN, true);
+	ath79_gpio_direction_select(AP90Q_GPIO_LED_WAN, true);
+	ath79_gpio_direction_select(AP90Q_GPIO_LED_WLAN, true);
+
+	/* Mute LEDs on boot */
+	gpio_set_value(AP90Q_GPIO_LED_LAN, 1);
+	gpio_set_value(AP90Q_GPIO_LED_WAN, 1);
+
+	ath79_gpio_output_select(AP90Q_GPIO_LED_LAN, 0);
+	ath79_gpio_output_select(AP90Q_GPIO_LED_WAN, 0);
+	ath79_gpio_output_select(AP90Q_GPIO_LED_WLAN, 0);
+
+	ath79_register_gpio_keys_polled(-1, AP90Q_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ap90q_gpio_keys),
+					ap90q_gpio_keys);
+}
+
+static void __init ap90q_setup(void)
+{
+	ap90q_cpe830_common_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap90q_leds_gpio),
+				 ap90q_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP90Q, "AP90Q", "YunCore AP90Q", ap90q_setup);
+
+static void __init cpe830_setup(void)
+{
+	ap90q_cpe830_common_setup();
+
+	ath79_gpio_direction_select(CPE830_GPIO_LED_LINK1, true);
+	ath79_gpio_direction_select(CPE830_GPIO_LED_LINK2, true);
+	ath79_gpio_direction_select(CPE830_GPIO_LED_LINK3, true);
+	ath79_gpio_direction_select(CPE830_GPIO_LED_LINK4, true);
+
+	/* Mute LEDs on boot */
+	gpio_set_value(CPE830_GPIO_LED_LINK1, 1);
+	gpio_set_value(CPE830_GPIO_LED_LINK2, 1);
+	gpio_set_value(CPE830_GPIO_LED_LINK3, 1);
+	gpio_set_value(CPE830_GPIO_LED_LINK4, 1);
+
+	ath79_gpio_output_select(CPE830_GPIO_LED_LINK1, 0);
+	ath79_gpio_output_select(CPE830_GPIO_LED_LINK2, 0);
+	ath79_gpio_output_select(CPE830_GPIO_LED_LINK3, 0);
+	ath79_gpio_output_select(CPE830_GPIO_LED_LINK4, 0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cpe830_leds_gpio),
+				 cpe830_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_CPE830, "CPE830", "YunCore CPE830", cpe830_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ap96.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap96.c
new file mode 100644
index 0000000000..35120d3e2e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ap96.c
@@ -0,0 +1,142 @@
+/*
+ *  Atheros AP96 board support
+ *
+ *  Copyright (C) 2009 Marco Porsch
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Atheros Communications
+ *
+ *  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/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define AP96_GPIO_LED_12_GREEN		0
+#define AP96_GPIO_LED_3_GREEN		1
+#define AP96_GPIO_LED_2_GREEN		2
+#define AP96_GPIO_LED_WPS_GREEN		4
+#define AP96_GPIO_LED_5_GREEN		5
+#define AP96_GPIO_LED_4_ORANGE		6
+
+/* Reset button - next to the power connector */
+#define AP96_GPIO_BTN_RESET		3
+/* WPS button - next to a led on right */
+#define AP96_GPIO_BTN_WPS		8
+
+#define AP96_KEYS_POLL_INTERVAL		20	/* msecs */
+#define AP96_KEYS_DEBOUNCE_INTERVAL	(3 * AP96_KEYS_POLL_INTERVAL)
+
+#define AP96_WMAC0_MAC_OFFSET		0x120c
+#define AP96_WMAC1_MAC_OFFSET		0x520c
+#define AP96_CALDATA0_OFFSET		0x1000
+#define AP96_CALDATA1_OFFSET		0x5000
+
+/*
+ * AP96 has 12 unlabeled leds in the front; these are numbered from 1 to 12
+ * below (from left to right on the board). Led 1 seems to be on whenever the
+ * board is powered. Led 11 shows LAN link activity actity. Led 3 is orange;
+ * others are green.
+ *
+ * In addition, there is one led next to a button on the right side for WPS.
+ */
+static struct gpio_led ap96_leds_gpio[] __initdata = {
+	{
+		.name		= "ap96:green:led2",
+		.gpio		= AP96_GPIO_LED_2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "ap96:green:led3",
+		.gpio		= AP96_GPIO_LED_3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "ap96:orange:led4",
+		.gpio		= AP96_GPIO_LED_4_ORANGE,
+		.active_low	= 1,
+	}, {
+		.name		= "ap96:green:led5",
+		.gpio		= AP96_GPIO_LED_5_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "ap96:green:led12",
+		.gpio		= AP96_GPIO_LED_12_GREEN,
+		.active_low	= 1,
+	}, { /* next to a button on right */
+		.name		= "ap96:green:wps",
+		.gpio		= AP96_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button ap96_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = AP96_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP96_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP96_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP96_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+#define AP96_WAN_PHYMASK 0x10
+#define AP96_LAN_PHYMASK 0x0f
+
+static void __init ap96_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_mdio(0, ~(AP96_WAN_PHYMASK | AP96_LAN_PHYMASK));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = AP96_LAN_PHYMASK;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = AP96_WAN_PHYMASK;
+
+	ath79_eth1_pll_data.pll_1000 = 0x1f000000;
+
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap96_leds_gpio),
+					ap96_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, AP96_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(ap96_gpio_keys),
+					 ap96_gpio_keys);
+
+	ap94_pci_init(art + AP96_CALDATA0_OFFSET,
+		      art + AP96_WMAC0_MAC_OFFSET,
+		      art + AP96_CALDATA1_OFFSET,
+		      art + AP96_WMAC1_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP96, "AP96", "Atheros AP96", ap96_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c
new file mode 100644
index 0000000000..f00998c669
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-archer-c7.c
@@ -0,0 +1,302 @@
+/*
+ * TP-LINK Archer C5/C7/TL-WDR4900 v2 board support
+ *
+ * Copyright (c) 2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2014 施康成 <tenninjas@tenninjas.ca>
+ * Copyright (c) 2014 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Based on the Qualcomm Atheros AP135/AP136 reference board support code
+ *   Copyright (c) 2012 Qualcomm Atheros
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define ARCHER_C7_GPIO_LED_WLAN2G	12
+#define ARCHER_C7_GPIO_LED_SYSTEM	14
+#define ARCHER_C7_GPIO_LED_QSS		15
+#define ARCHER_C7_GPIO_LED_WLAN5G	17
+#define ARCHER_C7_GPIO_LED_USB1		18
+#define ARCHER_C7_GPIO_LED_USB2		19
+
+#define ARCHER_C7_GPIO_BTN_RFKILL	13
+#define ARCHER_C7_V2_GPIO_BTN_RFKILL	23
+#define ARCHER_C7_GPIO_BTN_RESET	16
+
+#define ARCHER_C7_GPIO_USB1_POWER	22
+#define ARCHER_C7_GPIO_USB2_POWER	21
+
+#define ARCHER_C7_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ARCHER_C7_KEYS_DEBOUNCE_INTERVAL (3 * ARCHER_C7_KEYS_POLL_INTERVAL)
+
+#define ARCHER_C7_WMAC_CALDATA_OFFSET	0x1000
+#define ARCHER_C7_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *archer_c7_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data archer_c7_flash_data = {
+	.part_probes	= archer_c7_part_probes,
+};
+
+static struct gpio_led archer_c7_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:qss",
+		.gpio		= ARCHER_C7_GPIO_LED_QSS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= ARCHER_C7_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:wlan2g",
+		.gpio		= ARCHER_C7_GPIO_LED_WLAN2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:wlan5g",
+		.gpio		= ARCHER_C7_GPIO_LED_WLAN5G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:usb1",
+		.gpio		= ARCHER_C7_GPIO_LED_USB1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:usb2",
+		.gpio		= ARCHER_C7_GPIO_LED_USB2,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button archer_c7_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = ARCHER_C7_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ARCHER_C7_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = ARCHER_C7_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ARCHER_C7_GPIO_BTN_RFKILL,
+	},
+};
+
+static struct gpio_keys_button archer_c7_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = ARCHER_C7_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ARCHER_C7_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = ARCHER_C7_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ARCHER_C7_V2_GPIO_BTN_RFKILL,
+	},
+};
+
+static const struct ar8327_led_info archer_c7_leds_ar8327[] __initconst = {
+	AR8327_LED_INFO(PHY0_0, HW, "tp-link:blue:wan"),
+	AR8327_LED_INFO(PHY1_0, HW, "tp-link:blue:lan1"),
+	AR8327_LED_INFO(PHY2_0, HW, "tp-link:blue:lan2"),
+	AR8327_LED_INFO(PHY3_0, HW, "tp-link:blue:lan3"),
+	AR8327_LED_INFO(PHY4_0, HW, "tp-link:blue:lan4"),
+};
+
+/* GMAC0 of the AR8327 switch is connected to the QCA9558 SoC via SGMII */
+static struct ar8327_pad_cfg archer_c7_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+/* GMAC6 of the AR8327 switch is connected to the QCA9558 SoC via RGMII */
+static struct ar8327_pad_cfg archer_c7_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg archer_c7_ar8327_led_cfg = {
+	.led_ctrl0 = 0xc737c737,
+	.led_ctrl1 = 0x00000000,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x0030c300,
+	.open_drain = false,
+};
+
+static struct ar8327_platform_data archer_c7_ar8327_data = {
+	.pad0_cfg = &archer_c7_ar8327_pad0_cfg,
+	.pad6_cfg = &archer_c7_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &archer_c7_ar8327_led_cfg,
+	.num_leds = ARRAY_SIZE(archer_c7_leds_ar8327),
+	.leds = archer_c7_leds_ar8327,
+};
+
+static struct mdio_board_info archer_c7_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &archer_c7_ar8327_data,
+	},
+};
+
+static void __init common_setup(bool pcie_slot)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&archer_c7_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(archer_c7_leds_gpio),
+				 archer_c7_leds_gpio);
+
+	ath79_init_mac(tmpmac, mac, -1);
+	ath79_register_wmac(art + ARCHER_C7_WMAC_CALDATA_OFFSET, tmpmac);
+
+	if (pcie_slot) {
+		ath79_register_pci();
+	} else {
+		ath79_init_mac(tmpmac, mac, -1);
+		ap9x_pci_setup_wmac_led_pin(0, 0);
+		ap91_pci_init(art + ARCHER_C7_PCIE_CALDATA_OFFSET, tmpmac);
+	}
+
+	mdiobus_register_board_info(archer_c7_mdio0_info,
+				    ARRAY_SIZE(archer_c7_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_eth(1);
+
+	gpio_request_one(ARCHER_C7_GPIO_USB1_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB1 power");
+	gpio_request_one(ARCHER_C7_GPIO_USB2_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB2 power");
+	ath79_register_usb();
+}
+
+static void __init archer_c5_setup(void)
+{
+	ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(archer_c7_gpio_keys),
+					archer_c7_gpio_keys);
+	common_setup(true);
+}
+
+MIPS_MACHINE(ATH79_MACH_ARCHER_C5, "ARCHER-C5", "TP-LINK Archer C5",
+	     archer_c5_setup);
+
+static void __init archer_c7_setup(void)
+{
+	ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(archer_c7_gpio_keys),
+					archer_c7_gpio_keys);
+	common_setup(true);
+}
+
+MIPS_MACHINE(ATH79_MACH_ARCHER_C7, "ARCHER-C7", "TP-LINK Archer C7",
+	     archer_c7_setup);
+
+static void __init archer_c7_v2_setup(void)
+{
+	ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(archer_c7_v2_gpio_keys),
+					archer_c7_v2_gpio_keys);
+	common_setup(true);
+}
+
+MIPS_MACHINE(ATH79_MACH_ARCHER_C7_V2, "ARCHER-C7-V2", "TP-LINK Archer C7",
+	     archer_c7_v2_setup);
+
+static void __init tl_wdr4900_v2_setup(void)
+{
+	ath79_register_gpio_keys_polled(-1, ARCHER_C7_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(archer_c7_gpio_keys),
+					archer_c7_gpio_keys);
+	common_setup(false);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WDR4900_V2, "TL-WDR4900-v2", "TP-LINK TL-WDR4900 v2",
+	     tl_wdr4900_v2_setup)
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-arduino-yun.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-arduino-yun.c
new file mode 100644
index 0000000000..5873248edf
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-arduino-yun.c
@@ -0,0 +1,157 @@
+/*
+ *  Arduino Yun support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2015 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ *  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 "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include <linux/gpio.h>
+#include "common.h"
+
+// Uncomment to have reset on gpio18 instead of gipo7
+#define DS2_B
+
+#define DS_GPIO_LED_WLAN		0
+#define DS_GPIO_LED_USB			1
+
+#define DS_GPIO_OE			21
+#define DS_GPIO_AVR_RESET		18
+
+// Maintained to have the console in the previous version of DS2 working
+#define DS_GPIO_AVR_RESET_DS2		7
+
+#define DS_GPIO_OE2			22
+#define DS_GPIO_UART_ENA		23
+#define DS_GPIO_CONF_BTN		20
+
+#define DS_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DS_KEYS_DEBOUNCE_INTERVAL	(3 * DS_KEYS_POLL_INTERVAL)
+
+#define DS_MAC0_OFFSET			0x0000
+#define DS_MAC1_OFFSET			0x0006
+#define DS_CALDATA_OFFSET		0x1000
+#define DS_WMAC_MAC_OFFSET		0x1002
+
+
+static struct gpio_led ds_leds_gpio[] __initdata = {
+	{
+		.name		= "arduino:white:usb",
+		.gpio		= DS_GPIO_LED_USB,
+		.active_low	= 0,
+	},
+	{
+		.name		= "arduino:blue:wlan",
+		.gpio		= DS_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button ds_gpio_keys[] __initdata = {
+	{
+		.desc		= "configuration button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DS_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DS_GPIO_CONF_BTN,
+		.active_low	= 1,
+	},
+};
+
+static void __init ds_common_setup(void)
+{
+	static u8 mac[6];
+
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	ath79_register_m25p80(NULL);
+
+	if (ar93xx_wmac_read_mac_address(mac)) {
+		ath79_register_wmac(NULL, NULL);
+	} else {
+		ath79_register_wmac(art + DS_CALDATA_OFFSET,
+				    art + DS_WMAC_MAC_OFFSET);
+		memcpy(mac, art + DS_WMAC_MAC_OFFSET, sizeof(mac));
+	}
+
+	mac[3] |= 0x08;
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	mac[3] &= 0xF7;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+}
+
+static void __init ds_setup(void)
+{
+	u32 t;
+
+	ds_common_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ds_leds_gpio),
+				 ds_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DS_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ds_gpio_keys),
+					ds_gpio_keys);
+	ath79_register_usb();
+
+	/* use the swtich_led directly form sysfs */
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+								AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+								AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+								AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+								AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	//Disable the Function for some pins to have GPIO functionality active
+	// GPIO6-7-8 and GPIO11
+	ath79_gpio_function_setup(AR933X_GPIO_FUNC_JTAG_DISABLE | AR933X_GPIO_FUNC_I2S_MCK_EN, 0);
+
+	ath79_gpio_function2_setup(AR933X_GPIO_FUNC2_JUMPSTART_DISABLE, 0);
+
+	printk("Setting DogStick2 GPIO\n");
+
+	t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+	t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
+	ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
+
+	// Put the avr reset to high 
+	if (gpio_request_one(DS_GPIO_AVR_RESET_DS2,
+	    GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED, "OE-1") != 0)
+		printk("Error setting GPIO OE\n");
+	gpio_unexport(DS_GPIO_AVR_RESET_DS2);
+	gpio_free(DS_GPIO_AVR_RESET_DS2);
+
+	// enable OE of level shifter
+	if (gpio_request_one(DS_GPIO_OE,
+	    GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED, "OE-1") != 0)
+		printk("Error setting GPIO OE\n");
+
+	if (gpio_request_one(DS_GPIO_UART_ENA,
+	    GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED, "UART-ENA") != 0)
+		printk("Error setting GPIO Uart Enable\n");
+
+	// enable OE of level shifter
+	if (gpio_request_one(DS_GPIO_OE2,
+	    GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED, "OE-2") != 0)
+		printk("Error setting GPIO OE2\n");
+}
+
+MIPS_MACHINE(ATH79_MACH_ARDUINO_YUN, "Yun", "Arduino Yun", ds_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-aw-nr580.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-aw-nr580.c
new file mode 100644
index 0000000000..281129b787
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-aw-nr580.c
@@ -0,0 +1,107 @@
+/*
+ *  AzureWave AW-NR580 board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define AW_NR580_GPIO_LED_READY_RED	0
+#define AW_NR580_GPIO_LED_WLAN		1
+#define AW_NR580_GPIO_LED_READY_GREEN	2
+#define AW_NR580_GPIO_LED_WPS_GREEN	4
+#define AW_NR580_GPIO_LED_WPS_AMBER	5
+
+#define AW_NR580_GPIO_BTN_WPS		3
+#define AW_NR580_GPIO_BTN_RESET		11
+
+#define AW_NR580_KEYS_POLL_INTERVAL	20	/* msecs */
+#define AW_NR580_KEYS_DEBOUNCE_INTERVAL	(3 * AW_NR580_KEYS_POLL_INTERVAL)
+
+static struct gpio_led aw_nr580_leds_gpio[] __initdata = {
+	{
+		.name		= "aw-nr580:red:ready",
+		.gpio		= AW_NR580_GPIO_LED_READY_RED,
+		.active_low	= 0,
+	}, {
+		.name		= "aw-nr580:green:ready",
+		.gpio		= AW_NR580_GPIO_LED_READY_GREEN,
+		.active_low	= 0,
+	}, {
+		.name		= "aw-nr580:green:wps",
+		.gpio		= AW_NR580_GPIO_LED_WPS_GREEN,
+		.active_low	= 0,
+	}, {
+		.name		= "aw-nr580:amber:wps",
+		.gpio		= AW_NR580_GPIO_LED_WPS_AMBER,
+		.active_low	= 0,
+	}, {
+		.name		= "aw-nr580:green:wlan",
+		.gpio		= AW_NR580_GPIO_LED_WLAN,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button aw_nr580_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = AW_NR580_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AW_NR580_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AW_NR580_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AW_NR580_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static const char *aw_nr580_part_probes[] = {
+	"RedBoot",
+	NULL,
+};
+
+static struct flash_platform_data aw_nr580_flash_data = {
+	.part_probes	= aw_nr580_part_probes,
+};
+
+static void __init aw_nr580_setup(void)
+{
+	ath79_register_mdio(0, 0x0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+
+	ath79_register_pci();
+
+	ath79_register_m25p80(&aw_nr580_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(aw_nr580_leds_gpio),
+				 aw_nr580_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, AW_NR580_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(aw_nr580_gpio_keys),
+					aw_nr580_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_AW_NR580, "AW-NR580", "AzureWave AW-NR580",
+	     aw_nr580_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-bhr-4grv2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-bhr-4grv2.c
new file mode 100644
index 0000000000..5b4cf5ff2f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-bhr-4grv2.c
@@ -0,0 +1,171 @@
+/*
+ * Buffalo BHR-4GRV2 board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2016 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * Based on mach-ap136.c and mach-wzr-450hp2.c
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.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 "machtypes.h"
+
+#define BHR_4GRV2_GPIO_LED_VPN_RED	3
+#define BHR_4GRV2_GPIO_LED_VPN_GREEN	18
+#define BHR_4GRV2_GPIO_LED_POWER_GREEN	19
+#define BHR_4GRV2_GPIO_LED_DIAG_RED	20
+
+#define BHR_4GRV2_GPIO_BTN_RESET	17
+#define BHR_4GRV2_GPIO_BTN_ECO		21
+
+#define BHR_4GRV2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define BHR_4GRV2_KEYS_DEBOUNCE_INTERVAL	(3 * BHR_4GRV2_KEYS_POLL_INTERVAL)
+#define BHR_4GRV2_MAC0_OFFSET		0
+#define BHR_4GRV2_MAC1_OFFSET		6
+
+static struct gpio_led bhr_4grv2_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:red:vpn",
+		.gpio		= BHR_4GRV2_GPIO_LED_VPN_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:green:vpn",
+		.gpio		= BHR_4GRV2_GPIO_LED_VPN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:green:power",
+		.gpio		= BHR_4GRV2_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:red:diag",
+		.gpio		= BHR_4GRV2_GPIO_LED_DIAG_RED,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button bhr_4grv2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = BHR_4GRV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= BHR_4GRV2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "ECO button",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = BHR_4GRV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= BHR_4GRV2_GPIO_BTN_ECO,
+		.active_low	= 1,
+	},
+};
+
+/* GMAC0 of the AR8327 switch is connected to GMAC1 via SGMII */
+static struct ar8327_pad_cfg bhr_4grv2_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+/* GMAC6 of the AR8327 switch is connected to GMAC0 via RGMII */
+static struct ar8327_pad_cfg bhr_4grv2_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data bhr_4grv2_ar8327_data = {
+	.pad0_cfg = &bhr_4grv2_ar8327_pad0_cfg,
+	.pad6_cfg = &bhr_4grv2_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info bhr_4grv2_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &bhr_4grv2_ar8327_data,
+	},
+};
+
+static void __init bhr_4grv2_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(bhr_4grv2_leds_gpio),
+				 bhr_4grv2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, BHR_4GRV2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(bhr_4grv2_gpio_keys),
+					bhr_4grv2_gpio_keys);
+
+	mdiobus_register_board_info(bhr_4grv2_mdio0_info,
+				    ARRAY_SIZE(bhr_4grv2_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* GMAC0 is connected to the RGMII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + BHR_4GRV2_MAC0_OFFSET, 0);
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + BHR_4GRV2_MAC1_OFFSET, 0);
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_BHR_4GRV2, "BHR-4GRV2",
+	     "Buffalo BHR-4GRV2", bhr_4grv2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-bhu-bxu2000n2-a.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-bhu-bxu2000n2-a.c
new file mode 100644
index 0000000000..8d7c6112d7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-bhu-bxu2000n2-a.c
@@ -0,0 +1,120 @@
+/*
+ *  BHU BXU2000n-2 A1 board support
+ *
+ *  Copyright (C) 2013 Terry Yang <yangbo@bhunetworks.com>
+ *
+ *  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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define BHU_BXU2000N2_A1_GPIO_LED_WLAN		13
+#define BHU_BXU2000N2_A1_GPIO_LED_WAN		19
+#define BHU_BXU2000N2_A1_GPIO_LED_LAN		21
+#define BHU_BXU2000N2_A1_GPIO_LED_SYSTEM	14
+
+#define BHU_BXU2000N2_A1_GPIO_BTN_RESET		17
+
+#define BHU_BXU2000N2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define BHU_BXU2000N2_KEYS_DEBOUNCE_INTERVAL	\
+	(3 * BHU_BXU2000N2_KEYS_POLL_INTERVAL)
+
+static const char *bhu_bxu2000n2_part_probes[] = {
+	"cmdlinepart",
+	NULL,
+};
+
+static struct flash_platform_data bhu_bxu2000n2_flash_data = {
+	.part_probes	= bhu_bxu2000n2_part_probes,
+};
+
+static struct gpio_led bhu_bxu2000n2_a1_leds_gpio[] __initdata = {
+	{
+		.name		= "bhu:green:status",
+		.gpio		= BHU_BXU2000N2_A1_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "bhu:green:lan",
+		.gpio		= BHU_BXU2000N2_A1_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "bhu:green:wan",
+		.gpio		= BHU_BXU2000N2_A1_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "bhu:green:wlan",
+		.gpio		= BHU_BXU2000N2_A1_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button bhu_bxu2000n2_a1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = BHU_BXU2000N2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= BHU_BXU2000N2_A1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init bhu_ap123_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&bhu_bxu2000n2_flash_data);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	/* GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch. Only use PHY3 */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.phy_mask = BIT(3);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, ee+2);
+}
+
+static void __init bhu_bxu2000n2_a1_setup(void)
+{
+	bhu_ap123_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(bhu_bxu2000n2_a1_leds_gpio),
+				 bhu_bxu2000n2_a1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, BHU_BXU2000N2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(bhu_bxu2000n2_a1_gpio_keys),
+					bhu_bxu2000n2_a1_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_BHU_BXU2000N2_A1, "BXU2000n-2-A1",
+	     "BHU BXU2000n-2 rev. A1",
+	     bhu_bxu2000n2_a1_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-bsb.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-bsb.c
new file mode 100644
index 0000000000..9f9be02eb3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-bsb.c
@@ -0,0 +1,83 @@
+/*
+ *  Smart Electronics Black Swift board support
+ *
+ *  Copyright (C) 2014 Dmitriy Zherebkov dzh@black-swift.com
+ *
+ *  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 <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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define BSB_GPIO_LED_SYS		27
+
+#define BSB_GPIO_BTN_RESET		11
+
+#define BSB_KEYS_POLL_INTERVAL		20	/* msecs */
+#define BSB_KEYS_DEBOUNCE_INTERVAL	(3 * BSB_KEYS_POLL_INTERVAL)
+
+#define BSB_MAC_OFFSET			0x0000
+#define BSB_CALDATA_OFFSET		0x1000
+
+static struct gpio_led bsb_leds_gpio[] __initdata = {
+	{
+		.name		= "bsb:red:sys",
+		.gpio		= BSB_GPIO_LED_SYS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button bsb_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = BSB_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= BSB_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init bsb_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false,false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(bsb_leds_gpio),
+				 bsb_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, BSB_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(bsb_gpio_keys),
+					bsb_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(NULL);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + BSB_MAC_OFFSET, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + BSB_MAC_OFFSET, 2);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(art + BSB_CALDATA_OFFSET,
+			    art + BSB_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_BSB, "BSB", "Smart Electronics Black Swift board",
+		bsb_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-c55.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-c55.c
new file mode 100644
index 0000000000..cbee18e395
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-c55.c
@@ -0,0 +1,132 @@
+/*
+ *  AirTight Networks C-55 board support
+ *
+ *  Copyright (C) 2014-2015 Chris Blake <chrisrblake93@gmail.com>
+ *
+ *  Based on Senao CAP4200AG board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define C55_GPIO_LED_PWR_GREEN	12
+#define C55_GPIO_LED_PWR_AMBER	13
+#define C55_GPIO_LED_LAN_GREEN	14
+#define C55_GPIO_LED_LAN_AMBER	15
+#define C55_GPIO_LED_WLAN_GREEN	18
+#define C55_GPIO_LED_WLAN_AMBER	19
+
+#define C55_GPIO_BTN_RESET	17
+
+#define C55_KEYS_POLL_INTERVAL	20	/* msecs */
+#define C55_KEYS_DEBOUNCE_INTERVAL (3 * C55_KEYS_POLL_INTERVAL)
+
+#define C55_MAC_OFFSET		0
+#define C55_WMAC_CALDATA_OFFSET	0x1000
+#define C55_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led c55_leds_gpio[] __initdata = {
+	{
+		.name		= "c-55:green:pwr",
+		.gpio		= C55_GPIO_LED_PWR_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-55:amber:pwr",
+		.gpio		= C55_GPIO_LED_PWR_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-55:green:lan",
+		.gpio		= C55_GPIO_LED_LAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-55:amber:lan",
+		.gpio		= C55_GPIO_LED_LAN_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-55:green:wlan",
+		.gpio		= C55_GPIO_LED_WLAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-55:amber:wlan",
+		.gpio		= C55_GPIO_LED_WLAN_AMBER,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button c55_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = C55_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= C55_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init c55_setup(void)
+{
+	/* SPI Storage*/
+	ath79_register_m25p80_large(NULL);
+
+	/* MDIO Interface */
+	ath79_register_mdio(0, 0x0);
+
+	/* AR8035-A Ethernet */
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+	ath79_init_mac(ath79_eth0_data.mac_addr, NULL, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	/* LEDs & GPIO */
+	ath79_gpio_output_select(C55_GPIO_LED_LAN_GREEN,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(C55_GPIO_LED_LAN_AMBER,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(c55_leds_gpio),
+				 c55_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, C55_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(c55_gpio_keys),
+					c55_gpio_keys);
+
+	/* WiFi */
+	ath79_wmac_disable_2ghz();
+	ath79_register_wmac_simple();
+	ap91_pci_init_simple();
+
+}
+MIPS_MACHINE(ATH79_MACH_C55, "C-55", "AirTight Networks C-55",
+	     c55_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-c60.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-c60.c
new file mode 100644
index 0000000000..2a9e7211b5
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-c60.c
@@ -0,0 +1,200 @@
+/*
+ *  AirTight Networks C-60 board support
+ *
+ *  Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
+ *
+ *  Based on AirTight Networks C-55 board support
+ *
+ *  Copyright (C) 2014-2015 Chris Blake <chrisrblake93@gmail.com>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/platform/ar934x_nfc.h>
+#include <linux/ar8216_platform.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "dev-usb.h"
+#include "dev-nfc.h"
+#include "machtypes.h"
+
+#define C60_GPIO_LED_PWR_AMBER		11
+#define C60_GPIO_LED_WLAN2_GREEN	12
+#define C60_GPIO_LED_WLAN2_AMBER	13
+#define C60_GPIO_LED_PWR_GREEN		16
+
+#define C60_GPIO_BTN_RESET		17
+
+/* GPIOs of the AR9300 PCIe chip */
+#define C60_GPIO_WMAC_LED_WLAN1_AMBER	0
+#define C60_GPIO_WMAC_LED_WLAN1_GREEN	3
+
+#define C60_KEYS_POLL_INTERVAL		20	/* msecs */
+#define C60_KEYS_DEBOUNCE_INTERVAL (3 * C60_KEYS_POLL_INTERVAL)
+
+#define C60_ART_ADDR			0x1f7f0000
+#define C60_ART_SIZE			0xffff
+#define C60_MAC_OFFSET			0
+#define C60_WMAC_CALDATA_OFFSET		0x1000
+#define C60_PCIE_CALDATA_OFFSET		0x5000
+
+static struct gpio_led c60_leds_gpio[] __initdata = {
+	{
+		.name		= "c-60:amber:pwr",
+		.gpio		= C60_GPIO_LED_PWR_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-60:green:pwr",
+		.gpio		= C60_GPIO_LED_PWR_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-60:green:wlan2",
+		.gpio		= C60_GPIO_LED_WLAN2_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-60:amber:wlan2",
+		.gpio		= C60_GPIO_LED_WLAN2_AMBER,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button c60_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = C60_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= C60_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg c60_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data c60_ar8327_data = {
+	.pad0_cfg = &c60_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	}
+};
+
+static struct mdio_board_info c60_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &c60_ar8327_data,
+	},
+};
+
+static struct nand_ecclayout c60_nand_ecclayout = {
+	.eccbytes       = 7,
+	.eccpos         = { 4, 8, 9, 10, 13, 14, 15 },
+	.oobavail       = 9,
+	.oobfree        = { { 0, 3 }, { 6, 2 }, { 11, 2 }, }
+};
+
+static int c60_nand_scan_fixup(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	chip->ecc.size = 512;
+	chip->ecc.strength = 4;
+	chip->ecc.layout = &c60_nand_ecclayout;
+	return 0;
+}
+
+static struct gpio_led c60_wmac0_leds_gpio[] = {
+	{
+		.name		= "c-60:amber:wlan1",
+		.gpio		= C60_GPIO_WMAC_LED_WLAN1_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "c-60:green:wlan1",
+		.gpio		= C60_GPIO_WMAC_LED_WLAN1_GREEN,
+		.active_low	= 1,
+	},
+};
+
+static void __init c60_setup(void)
+{
+	u8 tmpmac[6];
+	u8 *art = (u8 *) KSEG1ADDR(C60_ART_ADDR);
+
+	/* NAND */
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_SOFT_BCH);
+	ath79_nfc_set_scan_fixup(c60_nand_scan_fixup);
+	ath79_register_nfc();
+
+	/* SPI Storage*/
+	ath79_register_m25p80_large(NULL);
+
+	/* AR8327 Switch Ethernet */
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	mdiobus_register_board_info(c60_mdio0_info,
+				    ARRAY_SIZE(c60_mdio0_info));
+
+	ath79_register_mdio(0, 0x0);
+
+	/* GMAC0 is connected to an AR8327N switch */
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + C60_MAC_OFFSET, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	/* LEDs & GPIO */
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(c60_leds_gpio),
+				 c60_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, C60_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(c60_gpio_keys),
+					c60_gpio_keys);
+	ap9x_pci_setup_wmac_leds(0, c60_wmac0_leds_gpio,
+				 ARRAY_SIZE(c60_wmac0_leds_gpio));
+	/* USB */
+	ath79_register_usb();
+
+	/* WiFi */
+	ath79_init_mac(tmpmac, art + C60_MAC_OFFSET, 1);
+	ap91_pci_init(art + C60_PCIE_CALDATA_OFFSET, tmpmac);
+	ath79_init_mac(tmpmac, art + C60_MAC_OFFSET, 2);
+	ath79_register_wmac(art + C60_WMAC_CALDATA_OFFSET, tmpmac);
+}
+MIPS_MACHINE(ATH79_MACH_C60, "C-60", "AirTight Networks C-60",
+	     c60_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cap324.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cap324.c
new file mode 100644
index 0000000000..2a6aed5b4c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cap324.c
@@ -0,0 +1,133 @@
+/*
+ *  PowerCloud Systems CAP324 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2012-2013 PowerCloud Systems
+ *  Copyright (C) 2015 Daniel Dickinson
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define CAP324_GPIO_LED_POWER_GREEN	12
+#define CAP324_GPIO_LED_POWER_AMBER	13
+#define CAP324_GPIO_LED_LAN_GREEN	14
+#define CAP324_GPIO_LED_LAN_AMBER	15
+#define CAP324_GPIO_LED_WLAN_GREEN	18
+#define CAP324_GPIO_LED_WLAN_AMBER	19
+
+#define CAP324_GPIO_BTN_RESET	17
+
+#define CAP324_KEYS_POLL_INTERVAL	20	/* msecs */
+#define CAP324_KEYS_DEBOUNCE_INTERVAL (3 * CAP324_KEYS_POLL_INTERVAL)
+
+#define CAP324_MAC_OFFSET		0
+#define CAP324_WMAC_CALDATA_OFFSET	0x1000
+#define CAP324_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led cap324_leds_gpio[] __initdata = {
+	{
+		.name		= "pcs:green:power",
+		.gpio		= CAP324_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:amber:power",
+		.gpio		= CAP324_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:green:lan",
+		.gpio		= CAP324_GPIO_LED_LAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:amber:lan",
+		.gpio		= CAP324_GPIO_LED_LAN_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:green:wlan",
+		.gpio		= CAP324_GPIO_LED_WLAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:amber:wlan",
+		.gpio		= CAP324_GPIO_LED_WLAN_AMBER,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button cap324_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = CAP324_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CAP324_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init cap324_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	ath79_gpio_output_select(CAP324_GPIO_LED_LAN_GREEN,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(CAP324_GPIO_LED_LAN_AMBER,
+				 AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cap324_leds_gpio),
+				 cap324_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, CAP324_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cap324_gpio_keys),
+					cap324_gpio_keys);
+
+	ath79_init_mac(mac, art + CAP324_MAC_OFFSET, -1);
+	ath79_wmac_disable_2ghz();
+	ath79_register_wmac(art + CAP324_WMAC_CALDATA_OFFSET, mac);
+
+	ath79_init_mac(mac, art + CAP324_MAC_OFFSET, -2);
+	ap91_pci_init(art + CAP324_PCIE_CALDATA_OFFSET, mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + CAP324_MAC_OFFSET, -2);
+
+	/* GMAC0 is connected to an external PHY */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_CAP324, "CAP324", "PowerCloud CAP324",
+	     cap324_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cap4200ag.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cap4200ag.c
new file mode 100644
index 0000000000..18944c40fa
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cap4200ag.c
@@ -0,0 +1,131 @@
+/*
+ *  Senao CAP4200AG board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define CAP4200AG_GPIO_LED_PWR_GREEN	12
+#define CAP4200AG_GPIO_LED_PWR_AMBER	13
+#define CAP4200AG_GPIO_LED_LAN_GREEN	14
+#define CAP4200AG_GPIO_LED_LAN_AMBER	15
+#define CAP4200AG_GPIO_LED_WLAN_GREEN	18
+#define CAP4200AG_GPIO_LED_WLAN_AMBER	19
+
+#define CAP4200AG_GPIO_BTN_RESET	17
+
+#define CAP4200AG_KEYS_POLL_INTERVAL	20	/* msecs */
+#define CAP4200AG_KEYS_DEBOUNCE_INTERVAL (3 * CAP4200AG_KEYS_POLL_INTERVAL)
+
+#define CAP4200AG_MAC_OFFSET		0
+#define CAP4200AG_WMAC_CALDATA_OFFSET	0x1000
+#define CAP4200AG_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led cap4200ag_leds_gpio[] __initdata = {
+	{
+		.name		= "senao:green:pwr",
+		.gpio		= CAP4200AG_GPIO_LED_PWR_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "senao:amber:pwr",
+		.gpio		= CAP4200AG_GPIO_LED_PWR_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "senao:green:lan",
+		.gpio		= CAP4200AG_GPIO_LED_LAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "senao:amber:lan",
+		.gpio		= CAP4200AG_GPIO_LED_LAN_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "senao:green:wlan",
+		.gpio		= CAP4200AG_GPIO_LED_WLAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "senao:amber:wlan",
+		.gpio		= CAP4200AG_GPIO_LED_WLAN_AMBER,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button cap4200ag_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = CAP4200AG_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CAP4200AG_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init cap4200ag_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	ath79_gpio_output_select(CAP4200AG_GPIO_LED_LAN_GREEN,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(CAP4200AG_GPIO_LED_LAN_AMBER,
+				 AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cap4200ag_leds_gpio),
+				 cap4200ag_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, CAP4200AG_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cap4200ag_gpio_keys),
+					cap4200ag_gpio_keys);
+
+	ath79_init_mac(mac, art + CAP4200AG_MAC_OFFSET, -1);
+	ath79_wmac_disable_2ghz();
+	ath79_register_wmac(art + CAP4200AG_WMAC_CALDATA_OFFSET, mac);
+
+	ath79_init_mac(mac, art + CAP4200AG_MAC_OFFSET, -2);
+	ap91_pci_init(art + CAP4200AG_PCIE_CALDATA_OFFSET, mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + CAP4200AG_MAC_OFFSET, -2);
+
+	/* GMAC0 is connected to an external PHY */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_CAP4200AG, "CAP4200AG", "Senao CAP4200AG",
+	     cap4200ag_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-carambola2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-carambola2.c
new file mode 100644
index 0000000000..babe101141
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-carambola2.c
@@ -0,0 +1,105 @@
+/*
+ *  8devices Carambola2 board support
+ *
+ *  Copyright (C) 2013 Darius Augulis <darius@8devices.com>
+ *
+ *  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 <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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define CARAMBOLA2_GPIO_LED_WLAN		0
+#define CARAMBOLA2_GPIO_LED_ETH0		14
+#define CARAMBOLA2_GPIO_LED_ETH1		13
+
+#define CARAMBOLA2_GPIO_BTN_JUMPSTART		11
+
+#define CARAMBOLA2_KEYS_POLL_INTERVAL		20	/* msecs */
+#define CARAMBOLA2_KEYS_DEBOUNCE_INTERVAL	(3 * CARAMBOLA2_KEYS_POLL_INTERVAL)
+
+#define CARAMBOLA2_MAC0_OFFSET			0x0000
+#define CARAMBOLA2_MAC1_OFFSET			0x0006
+#define CARAMBOLA2_CALDATA_OFFSET		0x1000
+#define CARAMBOLA2_WMAC_MAC_OFFSET		0x1002
+
+static struct gpio_led carambola2_leds_gpio[] __initdata = {
+	{
+		.name		= "carambola2:green:wlan",
+		.gpio		= CARAMBOLA2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "carambola2:orange:eth0",
+		.gpio		= CARAMBOLA2_GPIO_LED_ETH0,
+		.active_low	= 0,
+	}, {
+		.name		= "carambola2:orange:eth1",
+		.gpio		= CARAMBOLA2_GPIO_LED_ETH1,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button carambola2_gpio_keys[] __initdata = {
+	{
+		.desc		= "jumpstart button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = CARAMBOLA2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CARAMBOLA2_GPIO_BTN_JUMPSTART,
+		.active_low	= 1,
+	},
+};
+
+static void __init carambola2_common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_wmac(art + CARAMBOLA2_CALDATA_OFFSET,
+			    art + CARAMBOLA2_WMAC_MAC_OFFSET);
+
+	ath79_setup_ar933x_phy4_switch(true, true);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + CARAMBOLA2_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + CARAMBOLA2_MAC1_OFFSET, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+}
+
+static void __init carambola2_setup(void)
+{
+	carambola2_common_setup();
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(carambola2_leds_gpio),
+				 carambola2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, CARAMBOLA2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(carambola2_gpio_keys),
+					carambola2_gpio_keys);
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_CARAMBOLA2, "CARAMBOLA2", "8devices Carambola2 board",
+		carambola2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cf-e316n-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cf-e316n-v2.c
new file mode 100644
index 0000000000..2c202e3754
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cf-e316n-v2.c
@@ -0,0 +1,462 @@
+/*
+ *  Support for COMFAST boards:
+ *  - CF-E316N v2 (AR9341)
+ *  - CF-E320N v2 (QCA9531)
+ *  - CF-E380AC v1/v2 (QCA9558)
+ *  - CF-E520N/CF-E530N (QCA9531)
+ *
+ *  Copyright (C) 2016 Piotr Dymacz <pepe2k@gmail.com>
+ *  Copyright (C) 2016 Gareth Parker <gareth41@orcon.net.nz>
+ *  Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com>
+ *
+ *  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_data/phy-at803x.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-wmac.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define CF_EXXXN_KEYS_POLL_INTERVAL	20
+#define CF_EXXXN_KEYS_DEBOUNCE_INTERVAL	(3 * CF_EXXXN_KEYS_POLL_INTERVAL)
+
+/* CF-E316N v2 */
+#define CF_E316N_V2_GPIO_LED_DIAG_B	0
+#define CF_E316N_V2_GPIO_LED_DIAG_R	2
+#define CF_E316N_V2_GPIO_LED_DIAG_G	3
+#define CF_E316N_V2_GPIO_LED_WLAN	12
+#define CF_E316N_V2_GPIO_LED_WAN	17
+#define CF_E316N_V2_GPIO_LED_LAN	19
+
+#define CF_E316N_V2_GPIO_EXT_WDT	16
+
+#define CF_E316N_V2_GPIO_EXTERNAL_PA0	13
+#define CF_E316N_V2_GPIO_EXTERNAL_PA1	14
+
+#define CF_E316N_V2_GPIO_BTN_RESET	20
+
+static struct gpio_led cf_e316n_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "cf-e316n-v2:blue:diag",
+		.gpio		= CF_E316N_V2_GPIO_LED_DIAG_B,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e316n-v2:red:diag",
+		.gpio		= CF_E316N_V2_GPIO_LED_DIAG_R,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e316n-v2:green:diag",
+		.gpio		= CF_E316N_V2_GPIO_LED_DIAG_G,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e316n-v2:blue:wlan",
+		.gpio		= CF_E316N_V2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "cf-e316n-v2:blue:wan",
+		.gpio		= CF_E316N_V2_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "cf-e316n-v2:blue:lan",
+		.gpio		= CF_E316N_V2_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button cf_e316n_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = CF_EXXXN_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CF_E316N_V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+/* CF-E320N v2 */
+#define CF_E320N_V2_GPIO_LED_WLAN	0
+#define CF_E320N_V2_GPIO_LED_WAN	2
+#define CF_E320N_V2_GPIO_LED_LAN	3
+
+#define CF_E320N_V2_GPIO_HEADER_J9_1	14
+#define CF_E320N_V2_GPIO_HEADER_J9_2	12
+#define CF_E320N_V2_GPIO_HEADER_J9_3	11
+#define CF_E320N_V2_GPIO_HEADER_J9_4	16
+
+#define CF_E320N_V2_GPIO_EXT_WDT	13
+
+#define CF_E320N_V2_GPIO_BTN_RESET	17
+
+static struct gpio_led cf_e320n_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "cf-e320n-v2:green:lan",
+		.gpio		= CF_E320N_V2_GPIO_LED_LAN,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e320n-v2:red:wan",
+		.gpio		= CF_E320N_V2_GPIO_LED_WAN,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e320n-v2:blue:wlan",
+		.gpio		= CF_E320N_V2_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button cf_e320n_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = CF_EXXXN_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CF_E320N_V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+/* CF-E380AC v1/v2 */
+#define CF_E380AC_V1V2_GPIO_LED_LAN	0
+#define CF_E380AC_V1V2_GPIO_LED_WLAN2G	2
+#define CF_E380AC_V1V2_GPIO_LED_WLAN5G	3
+
+#define CF_E380AC_V1V2_GPIO_EXT_WDT	17
+
+#define CF_E380AC_V1V2_GPIO_BTN_RESET	19
+
+static struct gpio_led cf_e380ac_v1_leds_gpio[] __initdata = {
+	{
+		.name		= "cf-e380ac-v1:green:lan",
+		.gpio		= CF_E380AC_V1V2_GPIO_LED_LAN,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e380ac-v1:blue:wlan2g",
+		.gpio		= CF_E380AC_V1V2_GPIO_LED_WLAN2G,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e380ac-v1:red:wlan5g",
+		.gpio		= CF_E380AC_V1V2_GPIO_LED_WLAN5G,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_led cf_e380ac_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "cf-e380ac-v2:green:lan",
+		.gpio		= CF_E380AC_V1V2_GPIO_LED_LAN,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e380ac-v2:blue:wlan2g",
+		.gpio		= CF_E380AC_V1V2_GPIO_LED_WLAN2G,
+		.active_low	= 0,
+	}, {
+		.name		= "cf-e380ac-v2:red:wlan5g",
+		.gpio		= CF_E380AC_V1V2_GPIO_LED_WLAN5G,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button cf_e380ac_v1v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = CF_EXXXN_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CF_E380AC_V1V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct at803x_platform_data cf_e380ac_v1v2_at803x_data = {
+	.disable_smarteee = 1,
+};
+
+static struct mdio_board_info cf_e380ac_v1v2_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &cf_e380ac_v1v2_at803x_data,
+	},
+};
+
+/* CF-E520N/CF-E530N */
+#define CF_E5X0N_GPIO_LED_WAN		11
+#define CF_E5X0N_GPIO_BTN_RESET		17
+
+static struct gpio_led cf_e520n_leds_gpio[] __initdata = {
+	{
+		.name		= "cf-e520n:blue:wan",
+		.gpio		= CF_E5X0N_GPIO_LED_WAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led cf_e530n_leds_gpio[] __initdata = {
+	{
+		.name		= "cf-e530n:blue:wan",
+		.gpio		= CF_E5X0N_GPIO_LED_WAN,
+		.active_low	= 1,
+	}
+};
+
+/*
+ * Some COMFAST devices include external hardware watchdog chip,
+ * Pericon Technology PT7A7514, connected to a selected GPIO
+ * and WiSoC RESET_L input. Watchdog time-out is ~1.6 s.
+ */
+#define CF_EXXXN_EXT_WDT_TIMEOUT_MS	500
+
+static struct timer_list gpio_wdt_timer;
+
+static void gpio_wdt_toggle(unsigned long gpio)
+{
+	static int state;
+
+	state = !state;
+	gpio_set_value(gpio, state);
+
+	mod_timer(&gpio_wdt_timer,
+		  jiffies + msecs_to_jiffies(CF_EXXXN_EXT_WDT_TIMEOUT_MS));
+}
+
+static void __init cf_exxxn_common_setup(unsigned long art_ofs, int gpio_wdt)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1f001000 + art_ofs);
+
+	if (gpio_wdt > -1) {
+		gpio_request_one(gpio_wdt, GPIOF_OUT_INIT_HIGH,
+				 "PT7A7514 watchdog");
+
+		setup_timer(&gpio_wdt_timer, gpio_wdt_toggle, gpio_wdt);
+		gpio_wdt_toggle(gpio_wdt);
+	}
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_wmac(art, NULL);
+
+	ath79_register_usb();
+}
+
+static void __init cf_e316n_v2_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f010000);
+
+	cf_exxxn_common_setup(0x10000, CF_E316N_V2_GPIO_EXT_WDT);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 2);
+	ath79_register_eth(1);
+
+	/* Enable 2x Skyworks SE2576L WLAN power amplifiers */
+	gpio_request_one(CF_E316N_V2_GPIO_EXTERNAL_PA0, GPIOF_OUT_INIT_HIGH,
+			 "WLAN PA0");
+	gpio_request_one(CF_E316N_V2_GPIO_EXTERNAL_PA1, GPIOF_OUT_INIT_HIGH,
+			 "WLAN PA1");
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cf_e316n_v2_leds_gpio),
+				 cf_e316n_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, CF_EXXXN_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cf_e316n_v2_gpio_keys),
+					cf_e316n_v2_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_CF_E316N_V2, "CF-E316N-V2", "COMFAST CF-E316N v2",
+	     cf_e316n_v2_setup);
+
+static void __init cf_exxxn_qca953x_eth_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f010000);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+
+	/* LAN */
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 2);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_eth(0);
+}
+
+static void __init cf_e320n_v2_setup(void)
+{
+	cf_exxxn_common_setup(0x10000, CF_E320N_V2_GPIO_EXT_WDT);
+
+	cf_exxxn_qca953x_eth_setup();
+
+	/* Disable JTAG (enables GPIO0-3) */
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+
+	ath79_gpio_direction_select(CF_E320N_V2_GPIO_LED_LAN, true);
+	ath79_gpio_direction_select(CF_E320N_V2_GPIO_LED_WAN, true);
+	ath79_gpio_direction_select(CF_E320N_V2_GPIO_LED_WLAN, true);
+
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_LED_LAN, 0);
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_LED_WAN, 0);
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_LED_WLAN, 0);
+
+	/* Enable GPIO function for GPIOs in J9 header */
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_HEADER_J9_1, 0);
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_HEADER_J9_2, 0);
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_HEADER_J9_3, 0);
+	ath79_gpio_output_select(CF_E320N_V2_GPIO_HEADER_J9_4, 0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cf_e320n_v2_leds_gpio),
+				 cf_e320n_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, CF_EXXXN_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cf_e320n_v2_gpio_keys),
+					cf_e320n_v2_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_CF_E320N_V2, "CF-E320N-V2", "COMFAST CF-E320N v2",
+	     cf_e320n_v2_setup);
+
+static void __init cf_e380ac_v1v2_common_setup(unsigned long art_ofs)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f000000 + art_ofs);
+
+	cf_exxxn_common_setup(art_ofs, CF_E380AC_V1V2_GPIO_EXT_WDT);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+	mdiobus_register_board_info(cf_e380ac_v1v2_mdio0_info,
+				    ARRAY_SIZE(cf_e380ac_v1v2_mdio0_info));
+
+	/* LAN */
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_pll_data.pll_1000 = 0xbe000000;
+	ath79_eth0_pll_data.pll_100 = 0xb0000101;
+	ath79_eth0_pll_data.pll_10 = 0xb0001313;
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_eth(0);
+
+	ap91_pci_init(mac + 0x5000, NULL);
+
+	/* Disable JTAG (enables GPIO0-3) */
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+
+	ath79_gpio_direction_select(CF_E380AC_V1V2_GPIO_LED_LAN, true);
+	ath79_gpio_direction_select(CF_E380AC_V1V2_GPIO_LED_WLAN2G, true);
+	ath79_gpio_direction_select(CF_E380AC_V1V2_GPIO_LED_WLAN5G, true);
+
+	ath79_gpio_output_select(CF_E380AC_V1V2_GPIO_LED_LAN, 0);
+	ath79_gpio_output_select(CF_E380AC_V1V2_GPIO_LED_WLAN2G, 0);
+	ath79_gpio_output_select(CF_E380AC_V1V2_GPIO_LED_WLAN5G, 0);
+
+	/* For J7-4 */
+	ath79_gpio_function_disable(AR934X_GPIO_FUNC_CLK_OBS4_EN);
+
+	ath79_register_gpio_keys_polled(-1, CF_EXXXN_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cf_e380ac_v1v2_gpio_keys),
+					cf_e380ac_v1v2_gpio_keys);
+}
+
+static void __init cf_e380ac_v1_setup(void)
+{
+	cf_e380ac_v1v2_common_setup(0x20000);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cf_e380ac_v1_leds_gpio),
+				 cf_e380ac_v1_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_CF_E380AC_V1, "CF-E380AC-V1", "COMFAST CF-E380AC v1",
+	     cf_e380ac_v1_setup);
+
+static void __init cf_e380ac_v2_setup(void)
+{
+	cf_e380ac_v1v2_common_setup(0x40000);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cf_e380ac_v2_leds_gpio),
+				 cf_e380ac_v2_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_CF_E380AC_V2, "CF-E380AC-V2", "COMFAST CF-E380AC v2",
+	     cf_e380ac_v2_setup);
+
+static void __init cf_e5x0n_gpio_setup(void)
+{
+	ath79_gpio_direction_select(CF_E5X0N_GPIO_LED_WAN, true);
+
+	ath79_gpio_output_select(CF_E5X0N_GPIO_LED_WAN, 0);
+
+	ath79_register_gpio_keys_polled(-1, CF_EXXXN_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cf_e320n_v2_gpio_keys),
+					cf_e320n_v2_gpio_keys);
+}
+
+static void __init cf_e520n_setup(void)
+{
+	cf_exxxn_common_setup(0x10000, -1);
+
+	cf_exxxn_qca953x_eth_setup();
+
+	cf_e5x0n_gpio_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cf_e520n_leds_gpio),
+				 cf_e520n_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_CF_E520N, "CF-E520N", "COMFAST CF-E520N",
+	     cf_e520n_setup);
+
+static void __init cf_e530n_setup(void)
+{
+	cf_exxxn_common_setup(0x10000, -1);
+
+	cf_exxxn_qca953x_eth_setup();
+
+	cf_e5x0n_gpio_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cf_e530n_leds_gpio),
+				 cf_e530n_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_CF_E530N, "CF-E530N", "COMFAST CF-E530N",
+	     cf_e530n_setup);
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 0000000000..74daf434e6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
@@ -0,0 +1,131 @@
+/*
+ *  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_EXTERNAL_LNA0	18
+#define CPE510_GPIO_EXTERNAL_LNA1	19
+
+#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 cpe_setup(u8 *mac)
+{
+	/* 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_wmac_set_ext_lna_gpio(0, CPE510_GPIO_EXTERNAL_LNA0);
+	ath79_wmac_set_ext_lna_gpio(1, CPE510_GPIO_EXTERNAL_LNA1);
+
+	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);
+}
+
+
+static void __init cpe210_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	cpe_setup(mac);
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void __init cpe510_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	cpe_setup(mac);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_CPE210, "CPE210", "TP-LINK CPE210/220",
+	     cpe210_setup);
+
+MIPS_MACHINE(ATH79_MACH_CPE510, "CPE510", "TP-LINK CPE510/520",
+	     cpe510_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe870.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe870.c
new file mode 100644
index 0000000000..284cdc71c2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe870.c
@@ -0,0 +1,152 @@
+/*
+ * YunCore CPE870 board support
+ *
+ * Copyright (C) 2016 Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * 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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define CPE870_GPIO_LED_LINK1	0
+#define CPE870_GPIO_LED_LINK2	1
+#define CPE870_GPIO_LED_LINK3	2
+#define CPE870_GPIO_LED_LINK4	3
+#define CPE870_GPIO_LED_WLAN	13
+#define CPE870_GPIO_LED_WAN	19
+#define CPE870_GPIO_LED_LAN	20
+
+#define CPE870_GPIO_BTN_RESET	16
+
+#define CPE870_KEYS_POLL_INTERVAL	20
+#define CPE870_KEYS_DEBOUNCE_INTERVAL	(3 * CPE870_KEYS_POLL_INTERVAL)
+
+static struct gpio_led cpe870_leds_gpio[] __initdata = {
+	{
+		.name		= "cpe870:green:lan",
+		.gpio		= CPE870_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe870:green:wan",
+		.gpio		= CPE870_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe870:green:wlan",
+		.gpio		= CPE870_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe870:green:link1",
+		.gpio		= CPE870_GPIO_LED_LINK1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe870:green:link2",
+		.gpio		= CPE870_GPIO_LED_LINK2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe870:green:link3",
+		.gpio		= CPE870_GPIO_LED_LINK3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "cpe870:green:link4",
+		.gpio		= CPE870_GPIO_LED_LINK4,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button cpe870_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = CPE870_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CPE870_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init cpe870_gpio_setup(void)
+{
+	/* Disable JTAG (enables GPIO0-3) */
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+
+	ath79_gpio_direction_select(CPE870_GPIO_LED_LINK1, true);
+	ath79_gpio_direction_select(CPE870_GPIO_LED_LINK2, true);
+	ath79_gpio_direction_select(CPE870_GPIO_LED_LINK3, true);
+	ath79_gpio_direction_select(CPE870_GPIO_LED_LINK4, true);
+
+	/* Mute LEDs on boot */
+	gpio_set_value(CPE870_GPIO_LED_LAN, 1);
+	gpio_set_value(CPE870_GPIO_LED_WAN, 1);
+	gpio_set_value(CPE870_GPIO_LED_LINK1, 1);
+	gpio_set_value(CPE870_GPIO_LED_LINK2, 1);
+	gpio_set_value(CPE870_GPIO_LED_LINK3, 1);
+	gpio_set_value(CPE870_GPIO_LED_LINK4, 1);
+
+	ath79_gpio_output_select(CPE870_GPIO_LED_LINK1, 0);
+	ath79_gpio_output_select(CPE870_GPIO_LED_LINK2, 0);
+	ath79_gpio_output_select(CPE870_GPIO_LED_LINK3, 0);
+	ath79_gpio_output_select(CPE870_GPIO_LED_LINK4, 0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cpe870_leds_gpio),
+				 cpe870_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, CPE870_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cpe870_gpio_keys),
+					cpe870_gpio_keys);
+}
+
+static void __init cpe870_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	cpe870_gpio_setup();
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+
+	/* LAN */
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_CPE870, "CPE870", "YunCore CPE870", cpe870_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cr3000.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cr3000.c
new file mode 100644
index 0000000000..b351ae59c5
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cr3000.c
@@ -0,0 +1,161 @@
+/*
+ * PowerCloud Systems CR3000 support
+ *
+ * Copyright (c) 2011 Qualcomm Atheros
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2012-2013 PowerCloud Systems
+ * Copyright (c) 2015 Daniel Dickinson <openwrt@daniel.thecshore.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define CR3000_GPIO_LED_WLAN_2G		13
+#define CR3000_GPIO_LED_POWER_AMBER	15
+#define CR3000_GPIO_LED_WAN             18
+#define CR3000_GPIO_LED_LAN1            19
+#define CR3000_GPIO_LED_LAN2            20
+#define CR3000_GPIO_LED_LAN3            21
+#define CR3000_GPIO_LED_LAN4            22
+
+#define CR3000_GPIO_BTN_WPS		16
+#define CR3000_GPIO_BTN_RESET		17
+
+#define CR3000_KEYS_POLL_INTERVAL	20	/* msecs */
+#define CR3000_KEYS_DEBOUNCE_INTERVAL	(3 * CR3000_KEYS_POLL_INTERVAL)
+
+#define CR3000_MAC0_OFFSET		0
+#define CR3000_MAC1_OFFSET		6
+#define CR3000_WMAC_CALDATA_OFFSET	0x1000
+#define CR3000_WMAC_MAC_OFFSET	        0x1002
+#define CR3000_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led cr3000_leds_gpio[] __initdata = {
+	{
+		.name		= "pcs:amber:power",
+		.gpio		= CR3000_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:wlan",
+		.gpio		= CR3000_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:wan",
+		.gpio		= CR3000_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:lan1",
+		.gpio		= CR3000_GPIO_LED_LAN1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:lan2",
+		.gpio		= CR3000_GPIO_LED_LAN2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:lan3",
+		.gpio		= CR3000_GPIO_LED_LAN3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:lan4",
+		.gpio		= CR3000_GPIO_LED_LAN4,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button cr3000_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = CR3000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CR3000_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = CR3000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CR3000_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init cr3000_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cr3000_leds_gpio),
+				 cr3000_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, CR3000_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cr3000_gpio_keys),
+					cr3000_gpio_keys);
+
+	/* WLAN 2GHz onboard */
+	ath79_register_wmac(art + CR3000_WMAC_CALDATA_OFFSET, art + CR3000_WMAC_MAC_OFFSET);
+	
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	/* Lan 4-port switch attached to GMAC1 internal switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + CR3000_MAC0_OFFSET, 0);
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_register_eth(1);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + CR3000_MAC1_OFFSET, 0);
+
+	/* WAN Fast Ethernet interface attached to GMAC0 */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_CR3000, "CR3000", "PowerCloud CR3000",
+	     cr3000_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cr5000.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cr5000.c
new file mode 100644
index 0000000000..f393ed1113
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cr5000.c
@@ -0,0 +1,176 @@
+/*
+ * PowerCloud CR5000 support
+ *
+ * Copyright (c) 2011 Qualcomm Atheros
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2012-2013 PowerCloud Systems
+ * Copyright (c) 2015 Daniel Dickinson <openwrt@daniel.thecshore.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define CR5000_GPIO_LED_WLAN_2G		14
+#define CR5000_GPIO_LED_WPS		12
+#define CR5000_GPIO_LED_POWER_AMBER      4
+/* GPIO2 has to have JTAG disabled as it is also to
+ * power led
+ */
+#define CR5000_GPIO_LED_POWER_ENABLE     2
+#define CR5000_GPIO_BTN_WPS		16
+#define CR5000_GPIO_BTN_RESET		17
+
+#define CR5000_KEYS_POLL_INTERVAL	20	/* msecs */
+#define CR5000_KEYS_DEBOUNCE_INTERVAL	(3 * CR5000_KEYS_POLL_INTERVAL)
+
+#define CR5000_MAC0_OFFSET		0
+#define CR5000_WMAC_CALDATA_OFFSET	0x1000
+#define CR5000_WMAC_MAC_OFFSET	        0x1002
+#define CR5000_PCIE_CALDATA_OFFSET	0x5000
+#define CR5000_PCIE_MAC_OFFSET	        0x5002
+
+static struct gpio_led cr5000_leds_gpio[] __initdata = {
+	{
+		.name		= "pcs:amber:power",
+		.gpio		= CR5000_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:white:wps",
+		.gpio		= CR5000_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "pcs:blue:wlan",
+		.gpio		= CR5000_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button cr5000_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = CR5000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CR5000_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = CR5000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= CR5000_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg cr5000_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg cr5000_ar8327_led_cfg = {
+	.led_ctrl0 = 0x00000000,
+	.led_ctrl1 = 0xc737c737,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x00c30c00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data cr5000_ar8327_data = {
+	.pad0_cfg = &cr5000_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &cr5000_ar8327_led_cfg,
+};
+
+static struct mdio_board_info cr5000_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &cr5000_ar8327_data,
+	},
+};
+
+static void __init cr5000_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+	gpio_request_one(CR5000_GPIO_LED_POWER_ENABLE,
+	GPIOF_OUT_INIT_LOW, "Power LED enable");
+	ath79_gpio_output_select(CR5000_GPIO_LED_POWER_AMBER, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(CR5000_GPIO_LED_WLAN_2G, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(CR5000_GPIO_LED_WPS, AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(cr5000_leds_gpio),
+				 cr5000_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, CR5000_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(cr5000_gpio_keys),
+					cr5000_gpio_keys);
+	ath79_register_usb();
+	ath79_register_wmac(art + CR5000_WMAC_CALDATA_OFFSET, art + CR5000_WMAC_MAC_OFFSET);
+	ap94_pci_init(NULL, NULL, NULL, art + CR5000_PCIE_MAC_OFFSET);
+
+        ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + CR5000_MAC0_OFFSET, 0);
+
+	mdiobus_register_board_info(cr5000_mdio0_info,
+				    ARRAY_SIZE(cr5000_mdio0_info));
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_CR5000, "CR5000", "PowerCloud CR5000",
+	     cr5000_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dap-2695-a1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dap-2695-a1.c
new file mode 100644
index 0000000000..f0ed911c81
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dap-2695-a1.c
@@ -0,0 +1,191 @@
+/*
+ * D-Link DAP-2695 rev. A1 support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2016 Stijn Tintel <stijn@linux-ipv6.be>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define DAP2695_GPIO_LED_GREEN_POWER	23
+#define DAP2695_GPIO_LED_RED_POWER	14
+#define DAP2695_GPIO_LED_WLAN_2G	13
+
+#define DAP2695_GPIO_BTN_RESET		17
+
+#define DAP2695_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DAP2695_KEYS_DEBOUNCE_INTERVAL	(3 * DAP2695_KEYS_POLL_INTERVAL)
+
+#define DAP2695_NVRAM_ADDR		0x1f040000
+#define DAP2695_NVRAM_SIZE		0x10000
+
+#define DAP2695_MAC0_OFFSET		1
+#define DAP2695_MAC1_OFFSET		2
+#define DAP2695_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led dap2695_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DAP2695_GPIO_LED_GREEN_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:red:power",
+		.gpio		= DAP2695_GPIO_LED_RED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:green:wlan2g",
+		.gpio		= DAP2695_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button dap2695_gpio_keys[] __initdata = {
+	{
+		.desc			= "Soft reset",
+		.type			= EV_KEY,
+		.code			= KEY_RESTART,
+		.debounce_interval	= DAP2695_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= DAP2695_GPIO_BTN_RESET,
+		.active_low		= 1,
+	},
+};
+
+static struct ar8327_pad_cfg dap2695_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+	.mac06_exchange_dis = true,
+};
+
+static struct ar8327_pad_cfg dap2695_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data dap2695_ar8327_data = {
+	.pad0_cfg = &dap2695_ar8327_pad0_cfg,
+	.pad6_cfg = &dap2695_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info dap2695_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dap2695_ar8327_data,
+	},
+};
+
+static struct flash_platform_data dap2695_flash_data = {
+	.type = "mx25l12805d",
+};
+
+static void dap2695_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(DAP2695_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, DAP2695_NVRAM_SIZE,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+static void __init dap2695_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 mac0[ETH_ALEN], mac1[ETH_ALEN], wmac0[ETH_ALEN];
+
+	dap2695_get_mac("lanmac=", mac0);
+	dap2695_get_mac("wanmac=", mac1);
+	dap2695_get_mac("wlanmac=", wmac0);
+
+	ath79_register_m25p80(&dap2695_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dap2695_leds_gpio),
+				 dap2695_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DAP2695_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dap2695_gpio_keys),
+					dap2695_gpio_keys);
+
+	ath79_register_wmac(art + DAP2695_WMAC_CALDATA_OFFSET, wmac0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(dap2695_mdio0_info,
+					ARRAY_SIZE(dap2695_mdio0_info));
+
+	/* GMAC0 is connected to the RGMII interface */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac0, DAP2695_MAC0_OFFSET);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac1, DAP2695_MAC1_OFFSET);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_register_eth(1);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_DAP_2695_A1, "DAP-2695-A1",
+		"D-Link DAP-2695 rev. A1",
+		dap2695_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dgl-5500-a1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dgl-5500-a1.c
new file mode 100644
index 0000000000..91b554e527
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dgl-5500-a1.c
@@ -0,0 +1,150 @@
+/*
+ *  D-Link DGL-5500 board support
+ *
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DGL_5500_A1_GPIO_LED_POWER_ORANGE	14
+#define DGL_5500_A1_GPIO_LED_POWER_GREEN	19
+#define DGL_5500_A1_GPIO_LED_PLANET_GREEN	22
+#define DGL_5500_A1_GPIO_LED_PLANET_ORANGE	23
+
+#define DGL_5500_A1_GPIO_BTN_WPS		16
+#define DGL_5500_A1_GPIO_BTN_RESET		17
+
+#define DGL_5500_A1_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DGL_5500_A1_KEYS_DEBOUNCE_INTERVAL	\
+					(3 * DGL_5500_A1_KEYS_POLL_INTERVAL)
+
+#define DGL_5500_A1_WMAC_CALDATA_OFFSET		0x1000
+
+#define DGL_5500_A1_LAN_MAC_OFFSET	0x04
+#define DGL_5500_A1_WAN_MAC_OFFSET	0x16
+
+static struct gpio_led dgl_5500_a1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DGL_5500_A1_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:orange:power",
+		.gpio		= DGL_5500_A1_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:green:planet",
+		.gpio		= DGL_5500_A1_GPIO_LED_PLANET_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:orange:planet",
+		.gpio		= DGL_5500_A1_GPIO_LED_PLANET_ORANGE,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button dgl_5500_a1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DGL_5500_A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DGL_5500_A1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DGL_5500_A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DGL_5500_A1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg dgl_5500_a1_ar8327_pad0_cfg = {
+	/* Use the SGMII interface for the GMAC0 of the AR8327 switch */
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data dgl_5500_a1_ar8327_data = {
+	.pad0_cfg = &dgl_5500_a1_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info dgl_5500_a1_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dgl_5500_a1_ar8327_data,
+	},
+};
+
+static void __init dgl_5500_a1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1ffe0000);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 lan_mac[ETH_ALEN];
+
+	ath79_parse_ascii_mac(mac + DGL_5500_A1_LAN_MAC_OFFSET, lan_mac);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dgl_5500_a1_leds_gpio),
+				 dgl_5500_a1_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DGL_5500_A1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dgl_5500_a1_gpio_keys),
+					dgl_5500_a1_gpio_keys);
+
+	ath79_register_wmac(art + DGL_5500_A1_WMAC_CALDATA_OFFSET, lan_mac);
+
+	ath79_register_mdio(0, 0x0);
+	mdiobus_register_board_info(dgl_5500_a1_mdio0_info,
+				    ARRAY_SIZE(dgl_5500_a1_mdio0_info));
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, lan_mac, 0);
+
+	/* GMAC1 is connected to an AR8327N switch via the SMGII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.phy_mask = BIT(0);
+	ath79_eth1_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_DGL_5500_A1, "DGL-5500-A1", "D-Link DGL-5500 rev. A1",
+	     dgl_5500_a1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dhp-1565-a1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dhp-1565-a1.c
new file mode 100644
index 0000000000..ae477642c0
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dhp-1565-a1.c
@@ -0,0 +1,170 @@
+/*
+ *  D-Link DHP-1565 rev. A1 board support
+ *
+ *  Copyright (C) 2014 Jacek Kikiewicz
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DHP1565A1_GPIO_LED_BLUE_USB		11
+#define DHP1565A1_GPIO_LED_AMBER_POWER		14
+#define DHP1565A1_GPIO_LED_BLUE_POWER		22
+#define DHP1565A1_GPIO_LED_BLUE_WPS		15
+#define DHP1565A1_GPIO_LED_AMBER_PLANET		19
+#define DHP1565A1_GPIO_LED_BLUE_PLANET		18
+#define DHP1565A1_GPIO_LED_WLAN_2G		13
+
+#define DHP1565A1_GPIO_WAN_LED_ENABLE		20
+
+#define DHP1565A1_GPIO_BTN_RESET			17
+#define DHP1565A1_GPIO_BTN_WPS			16
+
+#define DHP1565A1_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DHP1565A1_KEYS_DEBOUNCE_INTERVAL		(3 * DHP1565A1_KEYS_POLL_INTERVAL)
+
+#define DHP1565A1_MAC0_OFFSET			0xFFA0
+#define DHP1565A1_MAC1_OFFSET			0xFFB4
+#define DHP1565A1_WMAC0_OFFSET			0x5
+#define DHP1565A1_WMAC_CALDATA_OFFSET		0x1000
+#define DHP1565A1_PCIE_CALDATA_OFFSET		0x5000
+
+static struct gpio_led dhp1565a1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:amber:power",
+		.gpio		= DHP1565A1_GPIO_LED_AMBER_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DHP1565A1_GPIO_LED_BLUE_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:amber:planet",
+		.gpio		= DHP1565A1_GPIO_LED_AMBER_PLANET,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:green:planet",
+		.gpio		= DHP1565A1_GPIO_LED_BLUE_PLANET,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button dhp1565a1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Soft reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DHP1565A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DHP1565A1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DHP1565A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DHP1565A1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg dhp1565a1_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data dhp1565a1_ar8327_data = {
+	.pad0_cfg = &dhp1565a1_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info dhp1565a1_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dhp1565a1_ar8327_data,
+	},
+};
+
+static void __init dhp1565a1_generic_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1ffe0000);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 mac0[ETH_ALEN], mac1[ETH_ALEN];
+	u8 wmac0[ETH_ALEN];
+
+	ath79_parse_ascii_mac(mac + DHP1565A1_MAC0_OFFSET, mac0);
+	ath79_parse_ascii_mac(mac + DHP1565A1_MAC1_OFFSET, mac1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_gpio_keys_polled(-1, DHP1565A1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dhp1565a1_gpio_keys),
+					dhp1565a1_gpio_keys);
+
+	ath79_init_mac(wmac0, mac0, 0);
+	ath79_register_wmac(art + DHP1565A1_WMAC_CALDATA_OFFSET, wmac0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	mdiobus_register_board_info(dhp1565a1_mdio0_info,
+				    ARRAY_SIZE(dhp1565a1_mdio0_info));
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac0, 1);
+
+	/* GMAC0 is connected to an AR8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+}
+
+static void __init dhp1565a1_setup(void)
+{
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dhp1565a1_leds_gpio),
+				 dhp1565a1_leds_gpio);
+
+	dhp1565a1_generic_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_DHP_1565_A1, "DHP-1565-A1",
+	     "D-Link DHP-1565 rev. A1",
+	     dhp1565a1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-505-a1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-505-a1.c
new file mode 100644
index 0000000000..1367b64a8f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-505-a1.c
@@ -0,0 +1,116 @@
+/*
+ *  DLink DIR-505 A1 board support
+ *
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <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 "dev-usb.h"
+#include "machtypes.h"
+
+#define DIR_505A1_GPIO_BTN_WPS         11 /* verify */
+#define DIR_505A1_GPIO_BTN_RESET       12 /* verify */
+
+#define DIR_505A1_GPIO_LED_RED         26 /* unused, fyi */
+#define DIR_505A1_GPIO_LED_GREEN       27
+
+#define DIR_505A1_GPIO_WAN_LED_ENABLE  1
+
+#define DIR_505A1_KEYS_POLL_INTERVAL   20      /* msecs */
+#define DIR_505A1_KEYS_DEBOUNCE_INTERVAL (3 * DIR_505A1_KEYS_POLL_INTERVAL)
+
+#define DIR_505A1_ART_ADDRESS          0x1f010000
+#define DIR_505A1_CALDATA_OFFSET       0x1000
+
+#define DIR_505A1_MAC_PART_ADDRESS	0x1f020000
+#define DIR_505A1_LAN_MAC_OFFSET	0x04
+#define DIR_505A1_WAN_MAC_OFFSET	0x16
+
+static struct gpio_led dir_505_a1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DIR_505A1_GPIO_LED_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:red:status",
+		.gpio		= DIR_505A1_GPIO_LED_RED,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button dir_505_a1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR_505A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_505A1_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}, {
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR_505A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_505A1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static void __init dir_505_a1_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(DIR_505A1_ART_ADDRESS);
+	u8 *mac = (u8 *) KSEG1ADDR(DIR_505A1_MAC_PART_ADDRESS);
+	u8 lan_mac[ETH_ALEN];
+	u8 wan_mac[ETH_ALEN];
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	gpio_request_one(DIR_505A1_GPIO_WAN_LED_ENABLE,
+		GPIOF_OUT_INIT_LOW, "WAN LED enable");
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir_505_a1_leds_gpio),
+		dir_505_a1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, DIR_505A1_KEYS_POLL_INTERVAL,
+		ARRAY_SIZE(dir_505_a1_gpio_keys),
+		dir_505_a1_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_usb();
+
+	ath79_parse_ascii_mac(mac + DIR_505A1_LAN_MAC_OFFSET, lan_mac);
+	ath79_parse_ascii_mac(mac + DIR_505A1_WAN_MAC_OFFSET, wan_mac);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, wan_mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, lan_mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art + DIR_505A1_CALDATA_OFFSET, lan_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_505_A1, "DIR-505-A1",
+		"D-Link DIR-505 rev. A1", dir_505_a1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-600-a1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-600-a1.c
new file mode 100644
index 0000000000..321fdce708
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-600-a1.c
@@ -0,0 +1,159 @@
+/*
+ *  D-Link DIR-600 rev. A1 board support
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2012 Vadim Girlin <vadimgirlin@gmail.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define DIR_600_A1_GPIO_LED_WPS			0
+#define DIR_600_A1_GPIO_LED_POWER_AMBER		1
+#define DIR_600_A1_GPIO_LED_POWER_GREEN		6
+#define DIR_600_A1_GPIO_LED_LAN1		13
+#define DIR_600_A1_GPIO_LED_LAN2		14
+#define DIR_600_A1_GPIO_LED_LAN3		15
+#define DIR_600_A1_GPIO_LED_LAN4		16
+#define DIR_600_A1_GPIO_LED_WAN_AMBER		7
+#define DIR_600_A1_GPIO_LED_WAN_GREEN		17
+
+#define DIR_600_A1_GPIO_BTN_RESET		8
+#define DIR_600_A1_GPIO_BTN_WPS			12
+
+#define DIR_600_A1_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DIR_600_A1_KEYS_DEBOUNCE_INTERVAL (3 * DIR_600_A1_KEYS_POLL_INTERVAL)
+
+#define DIR_600_A1_NVRAM_ADDR	0x1f030000
+#define DIR_600_A1_NVRAM_SIZE	0x10000
+
+static struct gpio_led dir_600_a1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DIR_600_A1_GPIO_LED_POWER_GREEN,
+	}, {
+		.name		= "d-link:amber:power",
+		.gpio		= DIR_600_A1_GPIO_LED_POWER_AMBER,
+	}, {
+		.name		= "d-link:amber:wan",
+		.gpio		= DIR_600_A1_GPIO_LED_WAN_AMBER,
+	}, {
+		.name		= "d-link:green:wan",
+		.gpio		= DIR_600_A1_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:lan1",
+		.gpio		= DIR_600_A1_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:lan2",
+		.gpio		= DIR_600_A1_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:lan3",
+		.gpio		= DIR_600_A1_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:lan4",
+		.gpio		= DIR_600_A1_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:blue:wps",
+		.gpio		= DIR_600_A1_GPIO_LED_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button dir_600_a1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR_600_A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_600_A1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR_600_A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_600_A1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static void __init dir_600_a1_setup(void)
+{
+	const char *nvram = (char *) KSEG1ADDR(DIR_600_A1_NVRAM_ADDR);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac_buff[6];
+	u8 *mac = NULL;
+
+	if (ath79_nvram_parse_mac_addr(nvram, DIR_600_A1_NVRAM_SIZE,
+				       "lan_mac=", mac_buff) == 0) {
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac_buff, 0);
+		ath79_init_mac(ath79_eth1_data.mac_addr, mac_buff, 1);
+		mac = mac_buff;
+	}
+
+	ath79_register_m25p80(NULL);
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir_600_a1_leds_gpio),
+				 dir_600_a1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DIR_600_A1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dir_600_a1_gpio_keys),
+					dir_600_a1_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+
+	ap91_pci_init(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_600_A1, "DIR-600-A1", "D-Link DIR-600 rev. A1",
+	     dir_600_a1_setup);
+
+static void __init dir_615_e1_setup(void)
+{
+	dir_600_a1_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_615_E1, "DIR-615-E1", "D-Link DIR-615 rev. E1",
+	     dir_615_e1_setup);
+
+static void __init dir_615_e4_setup(void)
+{
+	dir_600_a1_setup();
+	ap9x_pci_setup_wmac_led_pin(0, 1);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_615_E4, "DIR-615-E4", "D-Link DIR-615 rev. E4",
+	     dir_615_e4_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-c1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-c1.c
new file mode 100644
index 0000000000..e55a43f9c7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-c1.c
@@ -0,0 +1,135 @@
+/*
+ *  D-Link DIR-615 rev C1 board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.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"
+#include "nvram.h"
+
+#define DIR_615C1_GPIO_LED_ORANGE_STATUS 1	/* ORANGE:STATUS:TRICOLOR */
+#define DIR_615C1_GPIO_LED_BLUE_WPS	3	/* BLUE:WPS */
+#define DIR_615C1_GPIO_LED_GREEN_WAN	4       /* GREEN:WAN:TRICOLOR */
+#define DIR_615C1_GPIO_LED_GREEN_WANCPU	5       /* GREEN:WAN:CPU:TRICOLOR */
+#define DIR_615C1_GPIO_LED_GREEN_WLAN	6	/* GREEN:WLAN */
+#define DIR_615C1_GPIO_LED_GREEN_STATUS	14	/* GREEN:STATUS:TRICOLOR */
+#define DIR_615C1_GPIO_LED_ORANGE_WAN	15	/* ORANGE:WAN:TRICOLOR */
+
+/* buttons may need refinement */
+
+#define DIR_615C1_GPIO_BTN_WPS		12
+#define DIR_615C1_GPIO_BTN_RESET	21
+
+#define DIR_615C1_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DIR_615C1_KEYS_DEBOUNCE_INTERVAL (3 * DIR_615C1_KEYS_POLL_INTERVAL)
+
+#define DIR_615C1_CONFIG_ADDR		0x1f020000
+#define DIR_615C1_CONFIG_SIZE		0x10000
+
+#define DIR_615C1_WLAN_MAC_ADDR		0x1f3fffb4
+
+static struct gpio_led dir_615c1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:orange:status",
+		.gpio		= DIR_615C1_GPIO_LED_ORANGE_STATUS,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:blue:wps",
+		.gpio		= DIR_615C1_GPIO_LED_BLUE_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:wan",
+		.gpio		= DIR_615C1_GPIO_LED_GREEN_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:wancpu",
+		.gpio		= DIR_615C1_GPIO_LED_GREEN_WANCPU,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:wlan",
+		.gpio		= DIR_615C1_GPIO_LED_GREEN_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:green:status",
+		.gpio		= DIR_615C1_GPIO_LED_GREEN_STATUS,
+		.active_low     = 1,
+	}, {
+		.name		= "d-link:orange:wan",
+		.gpio		= DIR_615C1_GPIO_LED_ORANGE_WAN,
+		.active_low	= 1,
+	}
+
+};
+
+static struct gpio_keys_button dir_615c1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR_615C1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_615C1_GPIO_BTN_RESET,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR_615C1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_615C1_GPIO_BTN_WPS,
+	}
+};
+
+#define DIR_615C1_LAN_PHYMASK	BIT(0)
+#define DIR_615C1_WAN_PHYMASK	BIT(4)
+#define DIR_615C1_MDIO_MASK	(~(DIR_615C1_LAN_PHYMASK | \
+				   DIR_615C1_WAN_PHYMASK))
+
+static void __init dir_615c1_setup(void)
+{
+	const char *config = (char *) KSEG1ADDR(DIR_615C1_CONFIG_ADDR);
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac[ETH_ALEN], wlan_mac[ETH_ALEN];
+
+	if (ath79_nvram_parse_mac_addr(config, DIR_615C1_CONFIG_SIZE,
+				       "lan_mac=", mac) == 0) {
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+		ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+	}
+
+	ath79_parse_ascii_mac((char *) KSEG1ADDR(DIR_615C1_WLAN_MAC_ADDR), wlan_mac);
+
+	ath79_register_mdio(0, DIR_615C1_MDIO_MASK);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.phy_mask = DIR_615C1_LAN_PHYMASK;
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = DIR_615C1_WAN_PHYMASK;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir_615c1_leds_gpio),
+				 dir_615c1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DIR_615C1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dir_615c1_gpio_keys),
+					dir_615c1_gpio_keys);
+
+	ath79_register_wmac(eeprom, wlan_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_615_C1, "DIR-615-C1", "D-Link DIR-615 rev. C1",
+	     dir_615c1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-i1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-i1.c
new file mode 100644
index 0000000000..64fe438dcb
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-615-i1.c
@@ -0,0 +1,133 @@
+/*
+ *  D-Link DIR-615 rev. I1 board support
+ *  Copyright (C) 2013-2015 Jaehoon You <teslamint@gmail.com>
+ *
+ *  based on the DIR-600 rev. A1 board support code
+ *    Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *    Copyright (C) 2012 Vadim Girlin <vadimgirlin@gmail.com>
+ *
+ *  based on the TP-LINK TL-WR841N/ND v8/TL-MR3420 v2 board support code
+ *    Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/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 DIR_615_I1_GPIO_LED_WPS				15
+#define DIR_615_I1_GPIO_LED_POWER_AMBER		14
+#define DIR_615_I1_GPIO_LED_POWER_GREEN		4
+#define DIR_615_I1_GPIO_LED_WAN_AMBER		22
+#define DIR_615_I1_GPIO_LED_WAN_GREEN		12
+#define DIR_615_I1_GPIO_LED_WLAN_GREEN		13
+
+#define DIR_615_I1_GPIO_BTN_WPS				16
+#define DIR_615_I1_GPIO_BTN_RESET			17
+
+#define DIR_615_I1_KEYS_POLL_INTERVAL		20 /* msecs */
+#define DIR_615_I1_KEYS_DEBOUNCE_INTERVAL	(3 * DIR_615_I1_KEYS_POLL_INTERVAL)
+
+#define DIR_615_I1_LAN_PHYMASK	BIT(0)
+#define DIR_615_I1_WAN_PHYMASK	BIT(4)
+#define DIR_615_I1_WLAN_MAC_ADDR	0x1fffffb4
+
+static struct gpio_led dir_615_i1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DIR_615_I1_GPIO_LED_POWER_GREEN,
+	}, {
+		.name		= "d-link:amber:power",
+		.gpio		= DIR_615_I1_GPIO_LED_POWER_AMBER,
+	}, {
+		.name		= "d-link:amber:wan",
+		.gpio		= DIR_615_I1_GPIO_LED_WAN_AMBER,
+	}, {
+		.name		= "d-link:green:wan",
+		.gpio		= DIR_615_I1_GPIO_LED_WAN_GREEN,
+		.active_low = 1,
+	}, {
+		.name		= "d-link:green:wlan",
+		.gpio		= DIR_615_I1_GPIO_LED_WLAN_GREEN,
+		.active_low = 1,
+	}, {
+		.name		= "d-link:blue:wps",
+		.gpio		= DIR_615_I1_GPIO_LED_WPS,
+		.active_low = 1,
+	}
+};
+
+static struct gpio_keys_button dir_615_i1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR_615_I1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_615_I1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR_615_I1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR_615_I1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static void __init dir_615_i1_setup(void)
+{
+	u8 *eeprom  = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac[ETH_ALEN];
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_mdio(1, ~(DIR_615_I1_WAN_PHYMASK));
+
+	ath79_parse_ascii_mac((char *) KSEG1ADDR(DIR_615_I1_WLAN_MAC_ADDR), mac);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = DIR_615_I1_WAN_PHYMASK;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_mask = DIR_615_I1_LAN_PHYMASK;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	/* 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(dir_615_i1_leds_gpio),
+					dir_615_i1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DIR_615_I1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dir_615_i1_gpio_keys),
+					dir_615_i1_gpio_keys);
+
+	ath79_register_wmac(eeprom, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_615_I1, "DIR-615-I1", "D-Link DIR-615 rev. I1",
+		dir_615_i1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-b1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-b1.c
new file mode 100644
index 0000000000..9b82990b13
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-b1.c
@@ -0,0 +1,191 @@
+/*
+ *  D-Link DIR-825 rev. B1 board support
+ *
+ *  Copyright (C) 2009-2011 Lukas Kuna, Evkanet, s.r.o.
+ *
+ *  based on mach-wndr3700.c
+ *
+ *  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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/rtl8366.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define DIR825B1_GPIO_LED_BLUE_USB		0
+#define DIR825B1_GPIO_LED_ORANGE_POWER		1
+#define DIR825B1_GPIO_LED_BLUE_POWER		2
+#define DIR825B1_GPIO_LED_BLUE_WPS		4
+#define DIR825B1_GPIO_LED_ORANGE_PLANET		6
+#define DIR825B1_GPIO_LED_BLUE_PLANET		11
+
+#define DIR825B1_GPIO_BTN_RESET			3
+#define DIR825B1_GPIO_BTN_WPS			8
+
+#define DIR825B1_GPIO_RTL8366_SDA		5
+#define DIR825B1_GPIO_RTL8366_SCK		7
+
+#define DIR825B1_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DIR825B1_KEYS_DEBOUNCE_INTERVAL		(3 * DIR825B1_KEYS_POLL_INTERVAL)
+
+#define DIR825B1_CAL0_OFFSET			0x1000
+#define DIR825B1_CAL1_OFFSET			0x5000
+#define DIR825B1_MAC0_OFFSET			0xffa0
+#define DIR825B1_MAC1_OFFSET			0xffb4
+
+#define DIR825B1_CAL_LOCATION_0			0x1f660000
+#define DIR825B1_CAL_LOCATION_1			0x1f7f0000
+
+static struct gpio_led dir825b1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:blue:usb",
+		.gpio		= DIR825B1_GPIO_LED_BLUE_USB,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:orange:power",
+		.gpio		= DIR825B1_GPIO_LED_ORANGE_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:blue:power",
+		.gpio		= DIR825B1_GPIO_LED_BLUE_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:blue:wps",
+		.gpio		= DIR825B1_GPIO_LED_BLUE_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:orange:planet",
+		.gpio		= DIR825B1_GPIO_LED_ORANGE_PLANET,
+		.active_low	= 1,
+	}, {
+		.name		= "d-link:blue:planet",
+		.gpio		= DIR825B1_GPIO_LED_BLUE_PLANET,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button dir825b1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR825B1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR825B1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR825B1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR825B1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct rtl8366_initval dir825b1_rtl8366s_initvals[] = {
+	{ .reg = 0x06, .val = 0x0108 },
+};
+
+static struct rtl8366_platform_data dir825b1_rtl8366s_data = {
+	.gpio_sda	= DIR825B1_GPIO_RTL8366_SDA,
+	.gpio_sck	= DIR825B1_GPIO_RTL8366_SCK,
+	.num_initvals	= ARRAY_SIZE(dir825b1_rtl8366s_initvals),
+	.initvals	= dir825b1_rtl8366s_initvals,
+};
+
+static struct platform_device dir825b1_rtl8366s_device = {
+	.name		= RTL8366S_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &dir825b1_rtl8366s_data,
+	}
+};
+
+static bool __init dir825b1_is_caldata_valid(u8 *p)
+{
+	u16 *magic0, *magic1;
+
+	magic0 = (u16 *)(p + DIR825B1_CAL0_OFFSET);
+	magic1 = (u16 *)(p + DIR825B1_CAL1_OFFSET);
+
+	return (*magic0 == 0xa55a && *magic1 == 0xa55a);
+}
+
+static void __init dir825b1_wlan_init(void)
+{
+	u8 *caldata;
+	u8 mac0[ETH_ALEN], mac1[ETH_ALEN];
+	u8 wmac0[ETH_ALEN], wmac1[ETH_ALEN];
+
+	caldata = (u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_0);
+	if (!dir825b1_is_caldata_valid(caldata)) {
+		caldata = (u8 *)KSEG1ADDR(DIR825B1_CAL_LOCATION_1);
+		if (!dir825b1_is_caldata_valid(caldata)) {
+			pr_err("no calibration data found\n");
+			return;
+		}
+	}
+
+	ath79_parse_ascii_mac(caldata + DIR825B1_MAC0_OFFSET, mac0);
+	ath79_parse_ascii_mac(caldata + DIR825B1_MAC1_OFFSET, mac1);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac0, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac1, 0);
+	ath79_init_mac(wmac0, mac0, 0);
+	ath79_init_mac(wmac1, mac1, 1);
+
+	ap9x_pci_setup_wmac_led_pin(0, 5);
+	ap9x_pci_setup_wmac_led_pin(1, 5);
+
+	ap94_pci_init(caldata + DIR825B1_CAL0_OFFSET, wmac0,
+		      caldata + DIR825B1_CAL1_OFFSET, wmac1);
+}
+
+static void __init dir825b1_setup(void)
+{
+	dir825b1_wlan_init();
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_eth0_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_pll_data.pll_1000 = 0x11110000;
+
+	ath79_eth1_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = 0x10;
+	ath79_eth1_pll_data.pll_1000 = 0x11110000;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir825b1_leds_gpio),
+				 dir825b1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DIR825B1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dir825b1_gpio_keys),
+					dir825b1_gpio_keys);
+
+	ath79_register_usb();
+
+	platform_device_register(&dir825b1_rtl8366s_device);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_825_B1, "DIR-825-B1", "D-Link DIR-825 rev. B1",
+	     dir825b1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-c1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-c1.c
new file mode 100644
index 0000000000..9c4c1a8b3f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-825-c1.c
@@ -0,0 +1,241 @@
+/*
+ *  D-Link DIR-825 rev. C1 board support
+ *
+ *  Copyright (C) 2013 Alexander Stadler
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DIR825C1_GPIO_LED_BLUE_USB		11
+#define DIR825C1_GPIO_LED_AMBER_POWER		14
+#define DIR825C1_GPIO_LED_BLUE_POWER		22
+#define DIR825C1_GPIO_LED_BLUE_WPS		15
+#define DIR825C1_GPIO_LED_AMBER_PLANET		19
+#define DIR825C1_GPIO_LED_BLUE_PLANET		18
+#define DIR825C1_GPIO_LED_WLAN_2G		13
+
+#define DIR825C1_GPIO_WAN_LED_ENABLE		20
+
+#define DIR825C1_GPIO_BTN_RESET			17
+#define DIR825C1_GPIO_BTN_WPS			16
+
+#define DIR825C1_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DIR825C1_KEYS_DEBOUNCE_INTERVAL		(3 * DIR825C1_KEYS_POLL_INTERVAL)
+
+#define DIR825C1_MAC0_OFFSET			0x4
+#define DIR825C1_MAC1_OFFSET			0x18
+#define DIR825C1_WMAC_CALDATA_OFFSET		0x1000
+#define DIR825C1_PCIE_CALDATA_OFFSET		0x5000
+
+static struct gpio_led dir825c1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:blue:usb",
+		.gpio		= DIR825C1_GPIO_LED_BLUE_USB,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:amber:power",
+		.gpio		= DIR825C1_GPIO_LED_AMBER_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:blue:power",
+		.gpio		= DIR825C1_GPIO_LED_BLUE_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:blue:wps",
+		.gpio		= DIR825C1_GPIO_LED_BLUE_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:amber:planet",
+		.gpio		= DIR825C1_GPIO_LED_AMBER_PLANET,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:blue:wlan2g",
+		.gpio		= DIR825C1_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led dir835a1_leds_gpio[] __initdata = {
+	{
+		.name		= "d-link:amber:power",
+		.gpio		= DIR825C1_GPIO_LED_AMBER_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:green:power",
+		.gpio		= DIR825C1_GPIO_LED_BLUE_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:blue:wps",
+		.gpio		= DIR825C1_GPIO_LED_BLUE_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:amber:planet",
+		.gpio		= DIR825C1_GPIO_LED_AMBER_PLANET,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:green:planet",
+		.gpio		= DIR825C1_GPIO_LED_BLUE_PLANET,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button dir825c1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Soft reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR825C1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR825C1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR825C1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR825C1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg dir825c1_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg dir825c1_ar8327_led_cfg = {
+	.led_ctrl0 = 0x00000000,
+	.led_ctrl1 = 0xc737c737,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x00c30c00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data dir825c1_ar8327_data = {
+	.pad0_cfg = &dir825c1_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &dir825c1_ar8327_led_cfg,
+};
+
+static struct mdio_board_info dir825c1_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dir825c1_ar8327_data,
+	},
+};
+
+static void __init dir825c1_generic_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1ffe0000);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 mac0[ETH_ALEN], mac1[ETH_ALEN];
+	u8 wmac0[ETH_ALEN], wmac1[ETH_ALEN];
+
+	ath79_parse_ascii_mac(mac + DIR825C1_MAC0_OFFSET, mac0);
+	ath79_parse_ascii_mac(mac + DIR825C1_MAC1_OFFSET, mac1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_gpio_keys_polled(-1, DIR825C1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dir825c1_gpio_keys),
+					dir825c1_gpio_keys);
+
+	ath79_init_mac(wmac0, mac0, 0);
+	ath79_register_wmac(art + DIR825C1_WMAC_CALDATA_OFFSET, wmac0);
+
+	ath79_init_mac(wmac1, mac1, 1);
+	ap91_pci_init(art + DIR825C1_PCIE_CALDATA_OFFSET, wmac1);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	mdiobus_register_board_info(dir825c1_mdio0_info,
+				    ARRAY_SIZE(dir825c1_mdio0_info));
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac0, 0);
+
+	/* GMAC0 is connected to an AR8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+}
+
+static void __init dir825c1_setup(void)
+{
+	ath79_gpio_output_select(DIR825C1_GPIO_LED_BLUE_USB,
+				 AR934X_GPIO_OUT_GPIO);
+
+	gpio_request_one(DIR825C1_GPIO_WAN_LED_ENABLE,
+			 GPIOF_OUT_INIT_LOW, "WAN LED enable");
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir825c1_leds_gpio),
+				 dir825c1_leds_gpio);
+
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+
+	dir825c1_generic_setup();
+}
+
+static void __init dir835a1_setup(void)
+{
+	dir825c1_ar8327_data.led_cfg = NULL;
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir835a1_leds_gpio),
+				 dir835a1_leds_gpio);
+
+	dir825c1_generic_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_825_C1, "DIR-825-C1",
+	     "D-Link DIR-825 rev. C1",
+	     dir825c1_setup);
+
+MIPS_MACHINE(ATH79_MACH_DIR_835_A1, "DIR-835-A1",
+	     "D-Link DIR-835 rev. A1",
+	     dir835a1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-869-a1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-869-a1.c
new file mode 100644
index 0000000000..5847423891
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dir-869-a1.c
@@ -0,0 +1,178 @@
+/*
+ *  D-Link DIR-869 A1 support
+ *
+ *  Copyright (C) 2015-2016 P. Wassi <p.wassi at gmx.at>
+ *  Copyright (C) 2016 Matthias Schiffer <mschiffer@universe-factory.net>
+ *
+ *  Derived from: mach-ubnt-unifiac.c
+ *
+ *  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/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/irq.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/platform_data/phy-at803x.h>
+#include <linux/ar8216_platform.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.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"
+#include "nvram.h"
+
+
+#define DIR869A1_GPIO_BTN_RESET		1
+#define DIR869A1_GPIO_BTN_WPS		2
+#define DIR869A1_GPIO_SWITCH_MODE	8
+
+#define DIR869A1_GPIO_ENABLE_SWITCH	11
+
+#define DIR869A1_GPIO_LED_POWER		15
+#define DIR869A1_GPIO_LED_ORANGE	16
+
+#define DIR869A1_KEYS_POLL_INTERVAL	20 /* msecs */
+#define DIR869A1_KEYS_DEBOUNCE_INTERVAL	(3 * DIR869A1_KEYS_POLL_INTERVAL)
+
+
+#define DIR869A1_DEVDATA_ADDR		0x1f050000
+#define DIR869A1_DEVDATA_SIZE		0x10000
+
+#define DIR869A1_EEPROM_ADDR		0x1fff0000
+#define DIR869A1_WMAC_CALDATA_OFFSET	0x1000
+#define DIR869A1_PCI_CALDATA_OFFSET	0x5000
+
+
+static struct gpio_led dir869a1_leds_gpio[] __initdata = {
+	{
+		/* Actually, this GPIO controls the LED power,
+		 * while d-link:orange:status switches it between
+		 * orange and white */
+		.name		= "d-link:white:status",
+		.gpio		= DIR869A1_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "d-link:orange:status",
+		.gpio		= DIR869A1_GPIO_LED_ORANGE,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button dir869a1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DIR869A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR869A1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DIR869A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR869A1_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "mode",
+		.type		= EV_SW,
+		.code		= BTN_0,
+		.debounce_interval = DIR869A1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DIR869A1_GPIO_SWITCH_MODE,
+		.active_low	= 0,
+	},
+};
+
+
+static struct ar8327_pad_cfg dir869a1_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data dir869a1_ar8327_data = {
+	.pad0_cfg = &dir869a1_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+
+static struct mdio_board_info dir869a1_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dir869a1_ar8327_data,
+	},
+};
+
+
+static void dir869a1_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(DIR869A1_DEVDATA_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, DIR869A1_DEVDATA_SIZE,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+static void __init dir869a1_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(DIR869A1_EEPROM_ADDR);
+	u8 wlan24mac[ETH_ALEN] = {}, wlan5mac[ETH_ALEN] = {};
+
+	ath79_register_m25p80(NULL);
+
+	gpio_request_one(DIR869A1_GPIO_ENABLE_SWITCH,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "Switch power");
+
+	dir869a1_get_mac("lanmac=", ath79_eth0_data.mac_addr);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	mdiobus_register_board_info(dir869a1_mdio0_info,
+	                            ARRAY_SIZE(dir869a1_mdio0_info));
+
+	ath79_register_mdio(0, 0);
+	ath79_register_eth(0);
+
+	dir869a1_get_mac("wlan24mac=", wlan24mac);
+	ath79_register_wmac(eeprom + DIR869A1_WMAC_CALDATA_OFFSET, wlan24mac);
+
+	dir869a1_get_mac("wlan5mac=", wlan5mac);
+	ap91_pci_init(eeprom + DIR869A1_PCI_CALDATA_OFFSET, wlan5mac);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dir869a1_leds_gpio),
+	                         dir869a1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DIR869A1_KEYS_POLL_INTERVAL,
+	                                ARRAY_SIZE(dir869a1_gpio_keys),
+	                                dir869a1_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_DIR_869_A1, "DIR-869-A1", "D-Link DIR-869 rev. A1",
+             dir869a1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-hotspot.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-hotspot.c
new file mode 100644
index 0000000000..3ae46514fc
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-hotspot.c
@@ -0,0 +1,117 @@
+/*
+ *  devolo dLAN Hotspot board support
+ *
+ *  Copyright (C) 2015 Torsten Schnuis <torsten.schnuis@gik.de>
+ *  Copyright (C) 2015 devolo AG
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DLAN_HOTSPOT_GPIO_LED_WIFI                0
+
+#define DLAN_HOTSPOT_GPIO_BTN_RESET              11
+#define DLAN_HOTSPOT_GPIO_BTN_PLC_PAIRING        12
+#define DLAN_HOTSPOT_GPIO_BTN_WIFI               21
+
+#define DLAN_HOTSPOT_GPIO_PLC_POWER              22
+#define DLAN_HOTSPOT_GPIO_PLC_RESET              20
+#define DLAN_HOTSPOT_GPIO_PLC_DISABLE_LEDS       18
+
+#define DLAN_HOTSPOT_KEYS_POLL_INTERVAL          20    /* msecs */
+#define DLAN_HOTSPOT_KEYS_DEBOUNCE_INTERVAL      (3 * DLAN_HOTSPOT_KEYS_POLL_INTERVAL)
+
+#define DLAN_HOTSPOT_ART_ADDRESS                 0x1fff0000
+#define DLAN_HOTSPOT_CALDATA_OFFSET              0x00001000
+#define DLAN_HOTSPOT_MAC_ADDRESS_OFFSET          0x00001002
+
+static struct gpio_led dlan_hotspot_leds_gpio[] __initdata = {
+	{
+		.name		= "devolo:green:wifi",
+		.gpio		= DLAN_HOTSPOT_GPIO_LED_WIFI,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button dlan_hotspot_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DLAN_HOTSPOT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_HOTSPOT_GPIO_BTN_RESET,
+		.active_low     = 0,
+	},
+	{
+		.desc		= "Pairing button",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = DLAN_HOTSPOT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_HOTSPOT_GPIO_BTN_PLC_PAIRING,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "WLAN button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DLAN_HOTSPOT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_HOTSPOT_GPIO_BTN_WIFI,
+		.active_low	= 0,
+	}
+};
+
+static void __init dlan_hotspot_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(DLAN_HOTSPOT_ART_ADDRESS);
+	u8 *cal = art + DLAN_HOTSPOT_CALDATA_OFFSET;
+	u8 *wifi_mac = art + DLAN_HOTSPOT_MAC_ADDRESS_OFFSET;
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dlan_hotspot_leds_gpio),
+				 dlan_hotspot_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DLAN_HOTSPOT_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dlan_hotspot_gpio_keys),
+					dlan_hotspot_gpio_keys);
+
+	gpio_request_one(DLAN_HOTSPOT_GPIO_PLC_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "PLC power");
+	gpio_request_one(DLAN_HOTSPOT_GPIO_PLC_RESET,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "PLC reset");
+	gpio_request_one(DLAN_HOTSPOT_GPIO_PLC_DISABLE_LEDS,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "PLC LEDs");
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(NULL);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, wifi_mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, wifi_mac, 2);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(cal, wifi_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_DLAN_HOTSPOT, "dLAN-Hotspot",
+	     "dLAN Hotspot", dlan_hotspot_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-1200-ac.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-1200-ac.c
new file mode 100644
index 0000000000..4dc7b994ff
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-1200-ac.c
@@ -0,0 +1,190 @@
+/*
+ * devolo dLAN pro 500 Wireless+ support
+ *
+ * Copyright (c) 2013-2015 devolo AG
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DLAN_PRO_1200_AC_GPIO_DLAN_POWER_ENABLE		13
+#define DLAN_PRO_1200_AC_GPIO_WLAN_POWER_ENABLE		21
+#define DLAN_PRO_1200_AC_GPIO_LED_WLAN		12
+#define DLAN_PRO_1200_AC_GPIO_LED_DLAN			14
+#define DLAN_PRO_1200_AC_GPIO_LED_DLAN_ERR			15
+
+#define DLAN_PRO_1200_AC_GPIO_BTN_WLAN			20
+#define DLAN_PRO_1200_AC_GPIO_BTN_DLAN			22
+#define DLAN_PRO_1200_AC_GPIO_BTN_RESET			4
+#define DLAN_PRO_1200_AC_GPIO_DLAN_IND          17
+#define DLAN_PRO_1200_AC_GPIO_DLAN_ERR_IND      16
+
+#define DLAN_PRO_1200_AC_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DLAN_PRO_1200_AC_KEYS_DEBOUNCE_INTERVAL		(3 * DLAN_PRO_1200_AC_KEYS_POLL_INTERVAL)
+
+#define DLAN_PRO_1200_AC_ART_ADDRESS			0x1fff0000
+#define DLAN_PRO_1200_AC_CALDATA_OFFSET			0x1000
+#define DLAN_PRO_1200_AC_WIFIMAC_OFFSET			0x1002
+#define DLAN_PRO_1200_AC_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led dlan_pro_1200_ac_leds_gpio[] __initdata = {
+	{
+		.name		        = "devolo:status:wlan",
+		.gpio		        = DLAN_PRO_1200_AC_GPIO_LED_WLAN,
+		.active_low	        = 1,
+	},
+	{
+		.name		        = "devolo:status:dlan",
+		.gpio		        = DLAN_PRO_1200_AC_GPIO_LED_DLAN,
+		.active_low	        = 1,
+	},
+	{
+		.name		        = "devolo:error:dlan",
+		.gpio		        = DLAN_PRO_1200_AC_GPIO_LED_DLAN_ERR,
+		.active_low	        = 0,
+	}
+};
+
+static struct gpio_keys_button dlan_pro_1200_ac_gpio_keys[] __initdata = {
+	{
+		.desc		= "dLAN button",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = DLAN_PRO_1200_AC_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_1200_AC_GPIO_BTN_DLAN,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WLAN button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DLAN_PRO_1200_AC_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_1200_AC_GPIO_BTN_WLAN,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DLAN_PRO_1200_AC_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_1200_AC_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct ar8327_pad_cfg dlan_pro_1200_ac_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = false,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+	.mac06_exchange_dis = true,
+};
+
+static struct ar8327_pad_cfg dlan_pro_1200_ac_ar8327_pad5_cfg = {
+	.mode = 0,
+	.txclk_delay_en = 0,
+	.rxclk_delay_en = 0,
+	.txclk_delay_sel = 0,
+	.rxclk_delay_sel = 0,
+};
+
+static struct ar8327_platform_data dlan_pro_1200_ac_ar8327_data = {
+	.pad0_cfg = &dlan_pro_1200_ac_ar8327_pad0_cfg,
+	.pad5_cfg = &dlan_pro_1200_ac_ar8327_pad5_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info dlan_pro_1200_ac_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dlan_pro_1200_ac_ar8327_data,
+	},
+};
+
+static void __init dlan_pro_1200_ac_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(DLAN_PRO_1200_AC_ART_ADDRESS);
+	u8 *cal = art + DLAN_PRO_1200_AC_CALDATA_OFFSET;
+	u8 *wifi_mac = art + DLAN_PRO_1200_AC_WIFIMAC_OFFSET;
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dlan_pro_1200_ac_leds_gpio),
+				 dlan_pro_1200_ac_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DLAN_PRO_1200_AC_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dlan_pro_1200_ac_gpio_keys),
+					dlan_pro_1200_ac_gpio_keys);
+
+	/* dLAN power must be enabled from user-space as soon as the boot-from-host daemon is running */
+	gpio_request_one(DLAN_PRO_1200_AC_GPIO_DLAN_POWER_ENABLE,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "dLAN power");
+
+	/* WLAN power is turned on initially to allow the PCI bus scan to succeed */
+	gpio_request_one(DLAN_PRO_1200_AC_GPIO_WLAN_POWER_ENABLE,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "WLAN power");
+
+	ath79_register_wmac(cal, wifi_mac);
+	ap91_pci_init(art + DLAN_PRO_1200_AC_PCIE_CALDATA_OFFSET, NULL);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 | AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, wifi_mac, 2);
+
+	mdiobus_register_board_info(dlan_pro_1200_ac_mdio0_info,
+				    ARRAY_SIZE(dlan_pro_1200_ac_mdio0_info));
+
+	/* GMAC0 is connected to an AR8337 */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x02000000;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_DLAN_PRO_1200_AC, "dLAN-pro-1200-ac", "devolo dLAN pro 1200+ WiFi ac",
+	     dlan_pro_1200_ac_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-500-wp.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-500-wp.c
new file mode 100644
index 0000000000..ae6f443dcb
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dlan-pro-500-wp.c
@@ -0,0 +1,203 @@
+/*
+ * devolo dLAN pro 500 Wireless+ support
+ *
+ * Copyright (c) 2013-2015 devolo AG
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DLAN_PRO_500_WP_GPIO_DLAN_POWER_ENABLE		13
+#define DLAN_PRO_500_WP_GPIO_DLAN_LED_ENABLE		17
+#define DLAN_PRO_500_WP_GPIO_LED_WLAN_5G		11
+#define DLAN_PRO_500_WP_GPIO_LED_WLAN_2G		12
+#define DLAN_PRO_500_WP_GPIO_LED_STATUS			16
+#define DLAN_PRO_500_WP_GPIO_LED_ETH			14
+
+#define DLAN_PRO_500_WP_GPIO_BTN_WPS			20
+#define DLAN_PRO_500_WP_GPIO_BTN_WLAN			22
+#define DLAN_PRO_500_WP_GPIO_BTN_DLAN			21
+#define DLAN_PRO_500_WP_GPIO_BTN_RESET			4
+
+#define DLAN_PRO_500_WP_KEYS_POLL_INTERVAL		20	/* msecs */
+#define DLAN_PRO_500_WP_KEYS_DEBOUNCE_INTERVAL		(3 * DLAN_PRO_500_WP_KEYS_POLL_INTERVAL)
+
+#define DLAN_PRO_500_WP_ART_ADDRESS			0x1fff0000
+#define DLAN_PRO_500_WP_CALDATA_OFFSET			0x1000
+#define DLAN_PRO_500_WP_MAC_ADDRESS_OFFSET		0x1002
+#define DLAN_PRO_500_WP_PCIE_CALDATA_OFFSET		0x5000
+
+static struct gpio_led dlan_pro_500_wp_leds_gpio[] __initdata = {
+	{
+		.name		= "devolo:green:status",
+		.gpio		= DLAN_PRO_500_WP_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "devolo:green:eth",
+		.gpio		= DLAN_PRO_500_WP_GPIO_LED_ETH,
+		.active_low	= 1,
+	},
+	{
+		.name		= "devolo:blue:wlan-5g",
+		.gpio		= DLAN_PRO_500_WP_GPIO_LED_WLAN_5G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "devolo:green:wlan-2g",
+		.gpio		= DLAN_PRO_500_WP_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button dlan_pro_500_wp_gpio_keys[] __initdata = {
+	{
+		.desc		= "dLAN button",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = DLAN_PRO_500_WP_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_500_WP_GPIO_BTN_DLAN,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DLAN_PRO_500_WP_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_500_WP_GPIO_BTN_WPS,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "WLAN button",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = DLAN_PRO_500_WP_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_500_WP_GPIO_BTN_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code           = KEY_RESTART,
+		.debounce_interval = DLAN_PRO_500_WP_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DLAN_PRO_500_WP_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct ar8327_pad_cfg dlan_pro_500_wp_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_PHY_RGMII,
+	.txclk_delay_en = false,
+	.rxclk_delay_en = false,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+};
+
+static struct ar8327_led_cfg dlan_pro_500_wp_ar8327_led_cfg = {
+	.led_ctrl0 = 0x00000000,
+	.led_ctrl1 = 0xc737c737,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x00c30c00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data dlan_pro_500_wp_ar8327_data = {
+	.pad0_cfg = &dlan_pro_500_wp_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 0,
+		.rxpause = 0,
+	},
+	.led_cfg = &dlan_pro_500_wp_ar8327_led_cfg,
+};
+
+static struct mdio_board_info dlan_pro_500_wp_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dlan_pro_500_wp_ar8327_data,
+	},
+};
+
+static void __init dlan_pro_500_wp_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(DLAN_PRO_500_WP_ART_ADDRESS);
+	u8 *cal = art + DLAN_PRO_500_WP_CALDATA_OFFSET;
+	u8 *wifi_mac = art + DLAN_PRO_500_WP_MAC_ADDRESS_OFFSET;
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dlan_pro_500_wp_leds_gpio),
+				 dlan_pro_500_wp_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DLAN_PRO_500_WP_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dlan_pro_500_wp_gpio_keys),
+					dlan_pro_500_wp_gpio_keys);
+
+	gpio_request_one(DLAN_PRO_500_WP_GPIO_DLAN_POWER_ENABLE,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "PLC power");
+	gpio_request_one(DLAN_PRO_500_WP_GPIO_DLAN_LED_ENABLE,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "PLC LEDs");
+
+	ath79_register_wmac(cal, wifi_mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(dlan_pro_500_wp_mdio0_info,
+				    ARRAY_SIZE(dlan_pro_500_wp_mdio0_info));
+
+	/* GMAC0 is connected to a AR7400 PLC in PHY mode */
+	ath79_init_mac(ath79_eth0_data.mac_addr, wifi_mac, 2);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_pll_data.pll_1000 = 0x0e000000;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, wifi_mac, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_DLAN_PRO_500_WP, "dLAN-pro-500-wp", "devolo dLAN pro 500 Wireless+",
+	     dlan_pro_500_wp_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-domywifi-dw33d.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-domywifi-dw33d.c
new file mode 100644
index 0000000000..52d9da4792
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-domywifi-dw33d.c
@@ -0,0 +1,187 @@
+/*
+ * DomyWifi DW33D support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/platform/ar934x_nfc.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DW33D_GPIO_LED_MMC		4
+#define DW33D_GPIO_LED_WLAN_2G		13
+#define DW33D_GPIO_LED_STATUS		14
+#define DW33D_GPIO_LED_USB		15
+#define DW33D_GPIO_LED_INTERNET		22
+
+#define DW33D_GPIO_BTN_RESET		17
+
+#define DW33D_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DW33D_KEYS_DEBOUNCE_INTERVAL	(3 * DW33D_KEYS_POLL_INTERVAL)
+
+#define DW33D_MAC0_OFFSET		0
+#define DW33D_MAC1_OFFSET		6
+#define DW33D_WMAC_OFFSET		12
+#define DW33D_WMAC_CALDATA_OFFSET	0x1000
+#define DW33D_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led dw33d_leds_gpio[] __initdata = {
+	{
+		.name		= "dw33d:blue:status",
+		.gpio		= DW33D_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dw33d:blue:mmc",
+		.gpio		= DW33D_GPIO_LED_MMC,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dw33d:blue:usb",
+		.gpio		= DW33D_GPIO_LED_USB,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dw33d:blue:wlan-2g",
+		.gpio		= DW33D_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dw33d:blue:internet",
+		.gpio		= DW33D_GPIO_LED_INTERNET,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button dw33d_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DW33D_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DW33D_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+/* GMAC6 of the QCA8337 switch is connected to the QCA9558 SoC via SGMII */
+static struct ar8327_pad_cfg dw33d_qca8337_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+/* GMAC0 of the QCA8337 switch is connected to the QCA9558 SoC via RGMII */
+static struct ar8327_pad_cfg dw33d_qca8337_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data dw33d_qca8337_data = {
+	.pad0_cfg = &dw33d_qca8337_pad0_cfg,
+	.pad6_cfg = &dw33d_qca8337_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info dw33d_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dw33d_qca8337_data,
+	},
+};
+
+static void __init dw33d_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dw33d_leds_gpio),
+				 dw33d_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DW33D_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dw33d_gpio_keys),
+					dw33d_gpio_keys);
+
+	ath79_register_usb();
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_HW);
+	ath79_register_nfc();
+	ath79_register_pci();
+
+	ath79_register_wmac(art + DW33D_WMAC_CALDATA_OFFSET, art + DW33D_WMAC_OFFSET);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + DW33D_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + DW33D_MAC1_OFFSET, 0);
+
+	mdiobus_register_board_info(dw33d_mdio0_info,
+				    ARRAY_SIZE(dw33d_mdio0_info));
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+        ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected tot eh SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+        ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_DOMYWIFI_DW33D, "DW33D",
+	     "DomyWifi DW33D",
+	     dw33d_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dr344.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dr344.c
new file mode 100644
index 0000000000..e2155e3ec3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dr344.c
@@ -0,0 +1,184 @@
+/*
+ * Wallys DR344 board support
+ *
+ * Copyright (c) 2011 Qualcomm Atheros
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2015 Philippe Duchein <wireless-dev@duchein.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-usb.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DR344_GPIO_LED_SIG1	15
+#define DR344_GPIO_LED_SIG2	11
+#define DR344_GPIO_LED_SIG3	12
+#define DR344_GPIO_LED_SIG4	13
+#define DR344_GPIO_EXTERNAL_LNA0       18
+#define DR344_GPIO_EXTERNAL_LNA1       19
+#define DR344_GPIO_LED_STATUS	14
+
+#define DR344_GPIO_BTN_RESET	12
+
+#define DR344_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DR344_KEYS_DEBOUNCE_INTERVAL	(3 * DR344_KEYS_POLL_INTERVAL)
+
+#define DR344_MAC0_OFFSET		0
+#define DR344_MAC1_OFFSET		8
+#define DR344_WMAC_CALDATA_OFFSET	0x1000
+#define DR344_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led dr344_leds_gpio[] __initdata = {
+	{
+		.name		= "dr344:green:status",
+		.gpio		= DR344_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr344:red:sig1",
+		.gpio		= DR344_GPIO_LED_SIG1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr344:yellow:sig2",
+		.gpio		= DR344_GPIO_LED_SIG2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr344:green:sig3",
+		.gpio		= DR344_GPIO_LED_SIG3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr344:green:sig4",
+		.gpio		= DR344_GPIO_LED_SIG4,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button dr344_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DR344_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DR344_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg dr344_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg dr344_ar8327_led_cfg = {
+	.led_ctrl0 = 0x00000000,
+	.led_ctrl1 = 0xc737c737,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x00c30c00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data dr344_ar8327_data = {
+	.pad0_cfg = &dr344_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &dr344_ar8327_led_cfg,
+};
+
+static struct mdio_board_info dr344_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &dr344_ar8327_data,
+	},
+};
+
+static void __init dr344_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dr344_leds_gpio),
+				 dr344_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DR344_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dr344_gpio_keys),
+					dr344_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_wmac_set_ext_lna_gpio(0, DR344_GPIO_EXTERNAL_LNA0);
+
+	ath79_wmac_set_ext_lna_gpio(1, DR344_GPIO_EXTERNAL_LNA1);
+
+	ath79_register_wmac(art + DR344_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+
+	mdiobus_register_board_info(dr344_mdio0_info,
+					ARRAY_SIZE(dr344_mdio0_info));
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + DR344_MAC0_OFFSET, 0);
+       ath79_init_mac(ath79_eth1_data.mac_addr, art + DR344_MAC1_OFFSET, 0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x0e000000;
+	ath79_eth0_pll_data.pll_100 = 0x0101;
+	ath79_eth0_pll_data.pll_10 = 0x1313;
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_DR344, "DR344", "Wallys DR344", dr344_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dr531.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dr531.c
new file mode 100644
index 0000000000..b638a9001c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dr531.c
@@ -0,0 +1,155 @@
+/*
+ * Wallys DR531 board support
+ *
+ * Copyright (C) 2016 Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * Based on mach-wpj531.c
+ *
+ * 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/pci.h>
+#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-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define DR531_GPIO_BUZZER	4
+#define DR531_GPIO_LED_WAN	11
+#define DR531_GPIO_LED_LAN	14
+#define DR531_GPIO_LED_SIG1	12
+#define DR531_GPIO_LED_SIG2	16
+#define DR531_GPIO_LED_SIG3	15
+#define DR531_GPIO_LED_SIG4	13
+
+#define DR531_GPIO_BTN_RESET	17
+
+#define DR531_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DR531_KEYS_DEBOUNCE_INTERVAL	(3 * DR531_KEYS_POLL_INTERVAL)
+
+#define DR531_MAC0_OFFSET		0x0
+#define DR531_MAC1_OFFSET		0x8
+#define DR531_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led dr531_leds_gpio[] __initdata = {
+	{
+		.name		= "dr531:green:wan",
+		.gpio		= DR531_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr531:green:lan",
+		.gpio		= DR531_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr531:green:sig1",
+		.gpio		= DR531_GPIO_LED_SIG1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr531:green:sig2",
+		.gpio		= DR531_GPIO_LED_SIG2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr531:green:sig3",
+		.gpio		= DR531_GPIO_LED_SIG3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr531:green:sig4",
+		.gpio		= DR531_GPIO_LED_SIG4,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dr531:buzzer",
+		.gpio		= DR531_GPIO_BUZZER,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button dr531_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DR531_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DR531_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init dr531_gpio_setup(void)
+{
+	ath79_gpio_direction_select(DR531_GPIO_BUZZER, true);
+	ath79_gpio_direction_select(DR531_GPIO_LED_WAN, true);
+	ath79_gpio_direction_select(DR531_GPIO_LED_LAN, true);
+	ath79_gpio_direction_select(DR531_GPIO_LED_SIG1, true);
+	ath79_gpio_direction_select(DR531_GPIO_LED_SIG2, true);
+	ath79_gpio_direction_select(DR531_GPIO_LED_SIG3, true);
+	ath79_gpio_direction_select(DR531_GPIO_LED_SIG4, true);
+
+	ath79_gpio_output_select(DR531_GPIO_BUZZER, 0);
+	ath79_gpio_output_select(DR531_GPIO_LED_WAN, 0);
+	ath79_gpio_output_select(DR531_GPIO_LED_LAN, 0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dr531_leds_gpio),
+				 dr531_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, DR531_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dr531_gpio_keys),
+					dr531_gpio_keys);
+}
+
+static void __init dr531_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f03f810);
+
+	ath79_register_m25p80(NULL);
+
+	dr531_gpio_setup();
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN */
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac + DR531_MAC1_OFFSET, 0);
+	ath79_register_eth(0);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac + DR531_MAC0_OFFSET, 0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(art + DR531_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_DR531, "DR531", "Wallys DR531", dr531_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-dragino2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-dragino2.c
new file mode 100644
index 0000000000..95bd6f41a3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-dragino2.c
@@ -0,0 +1,136 @@
+/*
+ *  DRAGINO V2 board support, based on Atheros AP121 board support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2012 Elektra Wagenrad <elektra@villagetelco.org>
+ *  Copyright (C) 2014 Vittorio Gambaletta <openwrt@vittgam.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 <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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DRAGINO2_GPIO_LED_WLAN		0
+#define DRAGINO2_GPIO_LED_LAN		13
+#define DRAGINO2_GPIO_LED_WAN		17
+
+/*
+ * The following GPIO is named "SYS" on newer revisions of the the board.
+ * It was previously used to indicate USB activity, even though it was
+ * named "Router".
+ */
+
+#define DRAGINO2_GPIO_LED_SYS		28
+#define DRAGINO2_GPIO_BTN_JUMPSTART	11
+#define DRAGINO2_GPIO_BTN_RESET		12
+
+#define DRAGINO2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DRAGINO2_KEYS_DEBOUNCE_INTERVAL	(3 * DRAGINO2_KEYS_POLL_INTERVAL)
+
+#define DRAGINO2_MAC0_OFFSET		0x0000
+#define DRAGINO2_MAC1_OFFSET		0x0006
+#define DRAGINO2_CALDATA_OFFSET		0x1000
+#define DRAGINO2_WMAC_MAC_OFFSET	0x1002
+
+static struct gpio_led dragino2_leds_gpio[] __initdata = {
+	{
+		.name		= "dragino2:red:wlan",
+		.gpio		= DRAGINO2_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "dragino2:red:wan",
+		.gpio		= DRAGINO2_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dragino2:red:lan",
+		.gpio		= DRAGINO2_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dragino2:red:system",
+		.gpio		= DRAGINO2_GPIO_LED_SYS,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button dragino2_gpio_keys[] __initdata = {
+	{
+		.desc		= "jumpstart button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DRAGINO2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DRAGINO2_GPIO_BTN_JUMPSTART,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DRAGINO2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DRAGINO2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init dragino2_common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_wmac(art + DRAGINO2_CALDATA_OFFSET,
+			    art + DRAGINO2_WMAC_MAC_OFFSET);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + DRAGINO2_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + DRAGINO2_MAC1_OFFSET, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* Enable GPIO13, GPIO14, GPIO15, GPIO16 and GPIO17 */
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	/* LAN port */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+
+	/* Enable GPIO26 and GPIO27 */
+	ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP,
+		       ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP) |
+		       AR933X_BOOTSTRAP_MDIO_GPIO_EN);
+}
+
+static void __init dragino2_setup(void)
+{
+	dragino2_common_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dragino2_leds_gpio),
+				 dragino2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DRAGINO2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dragino2_gpio_keys),
+					dragino2_gpio_keys);
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_DRAGINO2, "DRAGINO2", "Dragino Dragino v2",
+	     dragino2_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-eap120.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-eap120.c
new file mode 100644
index 0000000000..130c7706a6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-eap120.c
@@ -0,0 +1,126 @@
+/*
+ *  TP-LINK EAP120 board support
+ *
+ * Copyright (C) 2016 Henryk Heisig <hyniu@o2.pl>
+ *
+ * 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 <linux/platform_data/mdio-gpio.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <linux/platform_data/phy-at803x.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 EAP120_GPIO_LED_RED	12
+#define EAP120_GPIO_LED_YEL	13
+#define EAP120_GPIO_LED_GRN	15
+#define EAP120_GPIO_BTN_RESET	4
+
+#define EAP120_KEYS_POLL_INTERVAL	20 /* msecs */
+#define EAP120_KEYS_DEBOUNCE_INTERVAL	(3 * EAP120_KEYS_POLL_INTERVAL)
+
+#define EAP120_GPIO_SMI_MDIO		16
+#define EAP120_GPIO_SMI_MDC		17
+
+#define EAP120_LAN_PHYADDR		4
+
+static struct gpio_led eap120_leds_gpio[] __initdata = {
+	{
+		.name		= "eap120:red:system",
+		.gpio		= EAP120_GPIO_LED_RED,
+		.active_low	= 1,
+	}, {
+		.name		= "eap120:yellow:system",
+		.gpio		= EAP120_GPIO_LED_YEL,
+		.active_low	= 1,
+	}, {
+		.name		= "eap120:green:system",
+		.gpio		= EAP120_GPIO_LED_GRN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button eap120_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = EAP120_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EAP120_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct mdio_gpio_platform_data eap120_mdio = {
+	.mdc		= EAP120_GPIO_SMI_MDC,
+	.mdio		= EAP120_GPIO_SMI_MDIO,
+	.phy_mask	= ~BIT(EAP120_LAN_PHYADDR),
+};
+
+static struct at803x_platform_data eap120_ar8035_data = {
+	.disable_smarteee = 0,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 0,
+	.fixup_rgmii_tx_delay = 1,
+};
+
+static struct platform_device eap120_phy_device = {
+	.name	= "mdio-gpio",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &eap120_mdio, &eap120_ar8035_data
+	},
+};
+
+static void __init eap_setup(u8 *mac)
+{
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(eap120_leds_gpio),
+				 eap120_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, EAP120_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(eap120_gpio_keys),
+					eap120_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+
+	/* MDIO Interface */
+	platform_device_register(&eap120_phy_device);
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	/* GMAC0 is connected to the RGMII interface to an Atheros AR8035-A */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.mii_bus_dev = &eap120_phy_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(EAP120_LAN_PHYADDR);
+	ath79_eth0_pll_data.pll_1000 = 0x0e000000;
+	ath79_eth0_pll_data.pll_100 = 0x00000101;
+	ath79_eth0_pll_data.pll_10 = 0x00001313;
+	ath79_register_eth(0);
+}
+
+static void __init eap120_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f030008);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	eap_setup(mac);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_EAP120, "EAP120", "TP-LINK EAP120",
+		eap120_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-eap300v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-eap300v2.c
new file mode 100644
index 0000000000..ba577e2517
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-eap300v2.c
@@ -0,0 +1,101 @@
+/*
+ * EnGenius EAP300 v2 board support
+ *
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.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 EAP300V2_GPIO_LED_POWER		0
+#define EAP300V2_GPIO_LED_LAN		16
+#define EAP300V2_GPIO_LED_WLAN		17
+
+#define EAP300V2_GPIO_BTN_RESET		1
+
+#define EAP300V2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define EAP300V2_KEYS_DEBOUNCE_INTERVAL	(3 * EAP300V2_KEYS_POLL_INTERVAL)
+
+static struct gpio_led eap300v2_leds_gpio[] __initdata = {
+	{
+		.name		= "engenius:blue:power",
+		.gpio		= EAP300V2_GPIO_LED_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "engenius:blue:lan",
+		.gpio		= EAP300V2_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "engenius:blue:wlan",
+		.gpio		= EAP300V2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button eap300v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = EAP300V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EAP300V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+#define EAP300V2_ART_MAC_OFFSET		2
+
+#define EAP300V2_LAN_PHYMASK		BIT(0)
+
+static void __init eap300v2_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff1000);
+
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+
+	ath79_gpio_output_select(EAP300V2_GPIO_LED_POWER, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(EAP300V2_GPIO_LED_LAN, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(EAP300V2_GPIO_LED_WLAN, AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(eap300v2_leds_gpio),
+				 eap300v2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, EAP300V2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(eap300v2_gpio_keys),
+					eap300v2_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_wmac(art, NULL);
+	ath79_register_mdio(1, 0x0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + EAP300V2_ART_MAC_OFFSET, 0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = EAP300V2_LAN_PHYMASK;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = EAP300V2_LAN_PHYMASK;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_EAP300V2, "EAP300V2", "EnGenius EAP300 v2",
+	     eap300v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-eap7660d.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-eap7660d.c
new file mode 100644
index 0000000000..787e6275d6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-eap7660d.c
@@ -0,0 +1,181 @@
+/*
+ *  Senao EAP7660D board support
+ *
+ *  Copyright (C) 2010 Daniel Golle <daniel.golle@gmail.com>
+ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/ath5k_platform.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define EAP7660D_KEYS_POLL_INTERVAL	20	/* msecs */
+#define EAP7660D_KEYS_DEBOUNCE_INTERVAL	(3 * EAP7660D_KEYS_POLL_INTERVAL)
+
+#define EAP7660D_GPIO_DS4		7
+#define EAP7660D_GPIO_DS5		2
+#define EAP7660D_GPIO_DS7		0
+#define EAP7660D_GPIO_DS8		4
+#define EAP7660D_GPIO_SW1		3
+#define EAP7660D_GPIO_SW3		8
+#define EAP7660D_PHYMASK		BIT(20)
+#define EAP7660D_BOARDCONFIG		0x1F7F0000
+#define EAP7660D_GBIC_MAC_OFFSET	0x1000
+#define EAP7660D_WMAC0_MAC_OFFSET	0x1010
+#define EAP7660D_WMAC1_MAC_OFFSET	0x1016
+#define EAP7660D_WMAC0_CALDATA_OFFSET	0x2000
+#define EAP7660D_WMAC1_CALDATA_OFFSET	0x3000
+
+#ifdef CONFIG_PCI
+static struct ath5k_platform_data eap7660d_wmac0_data;
+static struct ath5k_platform_data eap7660d_wmac1_data;
+static char eap7660d_wmac0_mac[6];
+static char eap7660d_wmac1_mac[6];
+static u16 eap7660d_wmac0_eeprom[ATH5K_PLAT_EEP_MAX_WORDS];
+static u16 eap7660d_wmac1_eeprom[ATH5K_PLAT_EEP_MAX_WORDS];
+
+static int eap7660d_pci_plat_dev_init(struct pci_dev *dev)
+{
+	switch (PCI_SLOT(dev->devfn)) {
+	case 17:
+		dev->dev.platform_data = &eap7660d_wmac0_data;
+		break;
+
+	case 18:
+		dev->dev.platform_data = &eap7660d_wmac1_data;
+		break;
+	}
+
+	return 0;
+}
+
+void __init eap7660d_pci_init(u8 *cal_data0, u8 *mac_addr0,
+			      u8 *cal_data1, u8 *mac_addr1)
+{
+	if (cal_data0 && *cal_data0 == 0xa55a) {
+		memcpy(eap7660d_wmac0_eeprom, cal_data0,
+			ATH5K_PLAT_EEP_MAX_WORDS);
+		eap7660d_wmac0_data.eeprom_data = eap7660d_wmac0_eeprom;
+	}
+
+	if (cal_data1 && *cal_data1 == 0xa55a) {
+		memcpy(eap7660d_wmac1_eeprom, cal_data1,
+			ATH5K_PLAT_EEP_MAX_WORDS);
+		eap7660d_wmac1_data.eeprom_data = eap7660d_wmac1_eeprom;
+	}
+
+	if (mac_addr0) {
+		memcpy(eap7660d_wmac0_mac, mac_addr0,
+			sizeof(eap7660d_wmac0_mac));
+		eap7660d_wmac0_data.macaddr = eap7660d_wmac0_mac;
+	}
+
+	if (mac_addr1) {
+		memcpy(eap7660d_wmac1_mac, mac_addr1,
+			sizeof(eap7660d_wmac1_mac));
+		eap7660d_wmac1_data.macaddr = eap7660d_wmac1_mac;
+	}
+
+	ath79_pci_set_plat_dev_init(eap7660d_pci_plat_dev_init);
+	ath79_register_pci();
+}
+#else
+static inline void eap7660d_pci_init(u8 *cal_data0, u8 *mac_addr0,
+				     u8 *cal_data1, u8 *mac_addr1)
+{
+}
+#endif /* CONFIG_PCI */
+
+static struct gpio_led eap7660d_leds_gpio[] __initdata = {
+	{
+		.name		= "eap7660d:green:ds8",
+		.gpio		= EAP7660D_GPIO_DS8,
+		.active_low	= 0,
+	},
+	{
+		.name		= "eap7660d:green:ds5",
+		.gpio		= EAP7660D_GPIO_DS5,
+		.active_low	= 0,
+	},
+	{
+		.name		= "eap7660d:green:ds7",
+		.gpio		= EAP7660D_GPIO_DS7,
+		.active_low	= 0,
+	},
+	{
+		.name		= "eap7660d:green:ds4",
+		.gpio		= EAP7660D_GPIO_DS4,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button eap7660d_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = EAP7660D_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EAP7660D_GPIO_SW1,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = EAP7660D_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EAP7660D_GPIO_SW3,
+		.active_low	= 1,
+	}
+};
+
+static const char *eap7660d_part_probes[] = {
+	"RedBoot",
+	NULL,
+};
+
+static struct flash_platform_data eap7660d_flash_data = {
+	.part_probes	= eap7660d_part_probes,
+};
+
+static void __init eap7660d_setup(void)
+{
+	u8 *boardconfig = (u8 *) KSEG1ADDR(EAP7660D_BOARDCONFIG);
+
+	ath79_register_mdio(0, ~EAP7660D_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+			boardconfig + EAP7660D_GBIC_MAC_OFFSET, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = EAP7660D_PHYMASK;
+	ath79_register_eth(0);
+	ath79_register_m25p80(&eap7660d_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(eap7660d_leds_gpio),
+					eap7660d_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, EAP7660D_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(eap7660d_gpio_keys),
+					 eap7660d_gpio_keys);
+	eap7660d_pci_init(boardconfig + EAP7660D_WMAC0_CALDATA_OFFSET,
+			  boardconfig + EAP7660D_WMAC0_MAC_OFFSET,
+			  boardconfig + EAP7660D_WMAC1_CALDATA_OFFSET,
+			  boardconfig + EAP7660D_WMAC1_MAC_OFFSET);
+};
+
+MIPS_MACHINE(ATH79_MACH_EAP7660D, "EAP7660D", "Senao EAP7660D",
+	     eap7660d_setup);
+
+MIPS_MACHINE(ATH79_MACH_ALL0305, "ALL0305", "Allnet ALL0305",
+	     eap7660d_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-el-m150.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-el-m150.c
new file mode 100644
index 0000000000..b95d6c2f68
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-el-m150.c
@@ -0,0 +1,112 @@
+/*
+ *  Easy-Link EL-M150 board support
+ *
+ *  Copyright (C) 2012 huangfc <huangfangcheng@163.com>
+ *  Copyright (C) 2012 HYS <550663898@qq.com>
+ *
+ *  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 <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"
+#include "dev-usb.h"
+
+#define EL_M150_GPIO_BTN6		6
+#define EL_M150_GPIO_BTN7		7
+#define EL_M150_GPIO_BTN_RESET		11
+
+#define EL_M150_GPIO_LED_SYSTEM		27
+#define EL_M150_GPIO_USB_POWER		8
+
+#define EL_M150_KEYS_POLL_INTERVAL	20	/* msecs */
+#define EL_M150_KEYS_DEBOUNCE_INTERVAL (3 * EL_M150_KEYS_POLL_INTERVAL)
+
+static const char *EL_M150_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data EL_M150_flash_data = {
+	.part_probes	= EL_M150_part_probes,
+};
+
+static struct gpio_led EL_M150_leds_gpio[] __initdata = {
+	{
+		.name		= "easylink:green:system",
+		.gpio		= EL_M150_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button EL_M150_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = EL_M150_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EL_M150_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "BTN_6",
+		.type		= EV_KEY,
+		.code		= BTN_6,
+		.debounce_interval = EL_M150_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EL_M150_GPIO_BTN6,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "BTN_7",
+		.type		= EV_KEY,
+		.code		= BTN_7,
+		.debounce_interval = EL_M150_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EL_M150_GPIO_BTN7,
+		.active_low	= 1,
+	},
+};
+
+static void __init el_m150_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(EL_M150_leds_gpio),
+				 EL_M150_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, EL_M150_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(EL_M150_gpio_keys),
+					EL_M150_gpio_keys);
+
+	gpio_request_one(EL_M150_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_m25p80(&EL_M150_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_EL_M150, "EL-M150",
+	     "EasyLink EL-M150", el_m150_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-el-mini.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-el-mini.c
new file mode 100644
index 0000000000..9879b18f7c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-el-mini.c
@@ -0,0 +1,86 @@
+/*
+ *  Easy-Link EL-MINI board support
+ *
+ *  Copyright (C) 2012 huangfc <huangfangcheng@163.com>
+ *  Copyright (C) 2011 hys <550663898@qq.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define MINI_GPIO_LED_SYSTEM	27
+#define MINI_GPIO_BTN_RESET	11
+
+#define MINI_GPIO_USB_POWER	8
+
+#define MINI_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MINI_KEYS_DEBOUNCE_INTERVAL	(3 * MINI_KEYS_POLL_INTERVAL)
+
+static const char *mini_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data mini_flash_data = {
+	.part_probes	= mini_part_probes,
+};
+
+static struct gpio_led mini_leds_gpio[] __initdata = {
+	{
+		.name		= "easylink:green:system",
+		.gpio		= MINI_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mini_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MINI_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MINI_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}
+};
+
+static void __init el_mini_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&mini_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mini_leds_gpio),
+				 mini_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MINI_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mini_gpio_keys),
+					mini_gpio_keys);
+
+	gpio_request_one(MINI_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_EL_MINI, "EL-MINI", "EasyLink EL-MINI",
+	     el_mini_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-epg5000.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-epg5000.c
new file mode 100644
index 0000000000..3d60afc408
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-epg5000.c
@@ -0,0 +1,177 @@
+/*
+ *  EnGenius EPG5000 board support
+ *
+ *  Copyright (c) 2014 Jon Suphammer <jon@suphammer.net>
+ *  Copyright (c) 2015 Christian Beier <cb@shoutrlabs.com>
+ *
+ *  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/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define EPG5000_GPIO_LED_WLAN_5G	23
+#define EPG5000_GPIO_LED_WLAN_2G	13
+#define EPG5000_GPIO_LED_POWER_AMBER	2
+#define EPG5000_GPIO_LED_WPS_AMBER	22
+#define EPG5000_GPIO_LED_WPS_BLUE	19
+
+#define EPG5000_GPIO_BTN_WPS		16
+#define EPG5000_GPIO_BTN_RESET		17
+
+#define EPG5000_KEYS_POLL_INTERVAL	20	/* msecs */
+#define EPG5000_KEYS_DEBOUNCE_INTERVAL	(3 * EPG5000_KEYS_POLL_INTERVAL)
+
+#define EPG5000_CALDATA_ADDR 0x1fff0000
+#define EPG5000_WMAC_CALDATA_OFFSET	0x1000
+#define EPG5000_PCIE_CALDATA_OFFSET	0x5000
+
+#define EPG5000_NVRAM_ADDR	0x1f030000
+#define EPG5000_NVRAM_SIZE	0x10000
+
+static struct gpio_led epg5000_leds_gpio[] __initdata = {
+	{
+		.name		= "epg5000:amber:power",
+		.gpio		= EPG5000_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "epg5000:blue:wps",
+		.gpio		= EPG5000_GPIO_LED_WPS_BLUE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "epg5000:amber:wps",
+		.gpio		= EPG5000_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "epg5000:blue:wlan-2g",
+		.gpio		= EPG5000_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "epg5000:blue:wlan-5g",
+		.gpio		= EPG5000_GPIO_LED_WLAN_5G,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button epg5000_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = EPG5000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EPG5000_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = EPG5000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= EPG5000_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg epg5000_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data epg5000_ar8327_data = {
+	.pad0_cfg = &epg5000_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info epg5000_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &epg5000_ar8327_data,
+	},
+};
+
+static int epg5000_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(EPG5000_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, EPG5000_NVRAM_SIZE,
+					 name, mac);
+	if (err) {
+		pr_err("no MAC address found for %s\n", name);
+		return false;
+	}
+
+	return true;
+}
+
+static void __init epg5000_setup(void)
+{
+	u8 *caldata = (u8 *) KSEG1ADDR(EPG5000_CALDATA_ADDR);
+	u8 mac1[ETH_ALEN];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(epg5000_leds_gpio),
+					epg5000_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, EPG5000_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(epg5000_gpio_keys),
+					epg5000_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(epg5000_mdio0_info,
+					ARRAY_SIZE(epg5000_mdio0_info));
+
+	/* GMAC0 is connected to an QCA8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	if (epg5000_get_mac("ethaddr=", mac1))
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_register_eth(0);
+
+	ath79_register_wmac(caldata + EPG5000_WMAC_CALDATA_OFFSET, mac1);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_EPG5000, "EPG5000",
+	     "EnGenius EPG5000",
+	     epg5000_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-esr1750.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-esr1750.c
new file mode 100644
index 0000000000..2a34b3a2e9
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-esr1750.c
@@ -0,0 +1,176 @@
+/*
+ *  EnGenius ESR1750 board support
+ *
+ *  Copyright (c) 2014 Jon Suphammer <jon@suphammer.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/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define ESR1750_GPIO_LED_WLAN_5G	23
+#define ESR1750_GPIO_LED_WLAN_2G	13
+#define ESR1750_GPIO_LED_POWER_AMBER	2
+#define ESR1750_GPIO_LED_WPS_AMBER	22
+#define ESR1750_GPIO_LED_WPS_BLUE	19
+
+#define ESR1750_GPIO_BTN_WPS		16
+#define ESR1750_GPIO_BTN_RESET		17
+
+#define ESR1750_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ESR1750_KEYS_DEBOUNCE_INTERVAL	(3 * ESR1750_KEYS_POLL_INTERVAL)
+
+#define ESR1750_CALDATA_ADDR 0x1fff0000
+#define ESR1750_WMAC_CALDATA_OFFSET	0x1000
+#define ESR1750_PCIE_CALDATA_OFFSET	0x5000
+
+#define ESR1750_NVRAM_ADDR	0x1f030000
+#define ESR1750_NVRAM_SIZE	0x10000
+
+static struct gpio_led esr1750_leds_gpio[] __initdata = {
+	{
+		.name		= "esr1750:amber:power",
+		.gpio		= ESR1750_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "esr1750:blue:wps",
+		.gpio		= ESR1750_GPIO_LED_WPS_BLUE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "esr1750:amber:wps",
+		.gpio		= ESR1750_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "esr1750:blue:wlan-2g",
+		.gpio		= ESR1750_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "esr1750:blue:wlan-5g",
+		.gpio		= ESR1750_GPIO_LED_WLAN_5G,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button esr1750_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = ESR1750_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ESR1750_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ESR1750_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ESR1750_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg esr1750_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data esr1750_ar8327_data = {
+	.pad0_cfg = &esr1750_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info esr1750_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &esr1750_ar8327_data,
+	},
+};
+
+static int esr1750_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(ESR1750_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, ESR1750_NVRAM_SIZE,
+					 name, mac);
+	if (err) {
+		pr_err("no MAC address found for %s\n", name);
+		return false;
+	}
+
+	return true;
+}
+
+static void __init esr1750_setup(void)
+{
+	u8 *caldata = (u8 *) KSEG1ADDR(ESR1750_CALDATA_ADDR);
+	u8 mac1[ETH_ALEN];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(esr1750_leds_gpio),
+					esr1750_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, ESR1750_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(esr1750_gpio_keys),
+					esr1750_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(esr1750_mdio0_info,
+					ARRAY_SIZE(esr1750_mdio0_info));
+
+	/* GMAC0 is connected to an QCA8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	if (esr1750_get_mac("ethaddr=", mac1))
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_register_eth(0);
+
+	ath79_register_wmac(caldata + ESR1750_WMAC_CALDATA_OFFSET, mac1);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_ESR1750, "ESR1750",
+	     "EnGenius ESR1750",
+	     esr1750_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-esr900.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-esr900.c
new file mode 100644
index 0000000000..aa2e7f7f4e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-esr900.c
@@ -0,0 +1,200 @@
+/*
+ *  EnGenius ESR900 board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) "esr900: " fmt
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define ESR900_GPIO_LED_POWER           2
+#define ESR900_GPIO_LED_WLAN_2G         13
+#define ESR900_GPIO_LED_WPS_BLUE        19
+#define ESR900_GPIO_LED_WPS_AMBER       22
+#define ESR900_GPIO_LED_WLAN_5G         23
+
+#define ESR900_GPIO_BTN_WPS             16
+#define ESR900_GPIO_BTN_RESET           17
+
+#define ESR900_KEYS_POLL_INTERVAL       20 /* msecs */
+#define ESR900_KEYS_DEBOUNCE_INTERVAL   (3 * ESR900_KEYS_POLL_INTERVAL)
+
+#define ESR900_CALDATA_ADDR             0x1fff0000
+#define ESR900_WMAC_CALDATA_OFFSET      0x1000
+#define ESR900_PCIE_CALDATA_OFFSET      0x5000
+
+#define ESR900_CONFIG_ADDR              0x1f030000
+#define ESR900_CONFIG_SIZE              0x10000
+
+#define ESR900_LAN_PHYMASK              BIT(0)
+#define ESR900_WAN_PHYMASK              BIT(5)
+#define ESR900_MDIO_MASK                (~(ESR900_LAN_PHYMASK | ESR900_WAN_PHYMASK))
+
+static struct gpio_led esr900_leds_gpio[] __initdata = {
+	{
+		.name		= "engenius:amber:power",
+		.gpio		= ESR900_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "engenius:blue:wlan-2g",
+		.gpio		= ESR900_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "engenius:blue:wps",
+		.gpio		= ESR900_GPIO_LED_WPS_BLUE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "engenius:amber:wps",
+		.gpio		= ESR900_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "engenius:blue:wlan-5g",
+		.gpio		= ESR900_GPIO_LED_WLAN_5G,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button esr900_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = ESR900_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ESR900_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ESR900_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ESR900_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg esr900_ar8327_pad0_cfg = {
+	/* GMAC0 of the AR8337 switch is connected to GMAC0 via RGMII */
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_pad_cfg esr900_ar8327_pad6_cfg = {
+	/* GMAC6 of the AR8337 switch is connected to GMAC1 via SGMII */
+	.mode = AR8327_PAD_MAC_SGMII,
+	.rxclk_delay_en = true,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+};
+
+static struct ar8327_platform_data esr900_ar8327_data = {
+	.pad0_cfg = &esr900_ar8327_pad0_cfg,
+	.pad6_cfg = &esr900_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info esr900_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &esr900_ar8327_data,
+	},
+};
+
+static void __init esr900_setup(void)
+{
+	const char *config = (char *) KSEG1ADDR(ESR900_CONFIG_ADDR);
+	u8 *art = (u8 *) KSEG1ADDR(ESR900_CALDATA_ADDR);
+	u8 lan_mac[ETH_ALEN];
+	u8 wlan0_mac[ETH_ALEN];
+	u8 wlan1_mac[ETH_ALEN];
+
+	if (ath79_nvram_parse_mac_addr(config, ESR900_CONFIG_SIZE,
+				       "ethaddr=", lan_mac) == 0) {
+		ath79_init_local_mac(ath79_eth0_data.mac_addr, lan_mac);
+		ath79_init_mac(wlan0_mac, lan_mac, 0);
+		ath79_init_mac(wlan1_mac, lan_mac, 1);
+	} else {
+		pr_err("could not find ethaddr in u-boot environment\n");
+	}
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(esr900_leds_gpio),
+					esr900_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, ESR900_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(esr900_gpio_keys),
+					esr900_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(art + ESR900_WMAC_CALDATA_OFFSET, wlan0_mac);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(esr900_mdio0_info,
+				    ARRAY_SIZE(esr900_mdio0_info));
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = ESR900_LAN_PHYMASK;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+	ath79_register_eth(1);
+
+	ap91_pci_init(art + ESR900_PCIE_CALDATA_OFFSET, wlan1_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_ESR900, "ESR900", "EnGenius ESR900", esr900_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ew-dorin.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ew-dorin.c
new file mode 100644
index 0000000000..e686b5fa6f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ew-dorin.c
@@ -0,0 +1,150 @@
+/*
+ *  EW Dorin board support
+ *  (based on Atheros Ref. Design AP121)
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2012-2015 Embedded Wireless GmbH    www.80211.de
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DORIN_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DORIN_KEYS_DEBOUNCE_INTERVAL	(3 * DORIN_KEYS_POLL_INTERVAL)
+
+#define DORIN_CALDATA_OFFSET		0x1000
+#define DORIN_WMAC_MAC_OFFSET		0x1002
+
+#define DORIN_GPIO_LED_21		21
+#define DORIN_GPIO_LED_22		22
+#define DORIN_GPIO_LED_STATUS	23
+
+#define DORIN_GPIO_BTN_JUMPSTART	11
+#define DORIN_GPIO_BTN_RESET		6
+
+static struct gpio_led dorin_leds_gpio[] __initdata = {
+	{
+		.name		= "dorin:green:led21",
+		.gpio		= DORIN_GPIO_LED_21,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dorin:green:led22",
+		.gpio		= DORIN_GPIO_LED_22,
+		.active_low	= 1,
+	},
+	{
+		.name		= "dorin:green:status",
+		.gpio		= DORIN_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button dorin_gpio_keys[] __initdata = {
+	{
+		.desc		= "jumpstart button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = DORIN_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DORIN_GPIO_BTN_JUMPSTART,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = DORIN_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= DORIN_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}
+};
+
+static void __init ew_dorin_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	static u8 mac[6];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_usb();
+
+	if (ar93xx_wmac_read_mac_address(mac)) {
+		ath79_register_wmac(NULL, NULL);
+	} else {
+		ath79_register_wmac(art + DORIN_CALDATA_OFFSET,
+				    art + DORIN_WMAC_MAC_OFFSET);
+		memcpy(mac, art + DORIN_WMAC_MAC_OFFSET, sizeof(mac));
+	}
+
+	mac[3] |= 0x40;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dorin_leds_gpio),
+				 dorin_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DORIN_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dorin_gpio_keys),
+					dorin_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_EW_DORIN, "EW-DORIN", "EmbWir-Dorin",
+	     ew_dorin_setup);
+
+
+static void __init ew_dorin_router_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	static u8 mac[6];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_usb();
+
+	if (ar93xx_wmac_read_mac_address(mac)) {
+		ath79_register_wmac(NULL, NULL);
+	} else {
+		ath79_register_wmac(art + DORIN_CALDATA_OFFSET,
+				    art + DORIN_WMAC_MAC_OFFSET);
+		memcpy(mac, art + DORIN_WMAC_MAC_OFFSET, sizeof(mac));
+	}
+
+	mac[3] |= 0x40;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	mac[3] &= 0x3F;
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_setup_ar933x_phy4_switch(true, true);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(dorin_leds_gpio),
+				 dorin_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DORIN_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(dorin_gpio_keys),
+					dorin_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_EW_DORIN_ROUTER, "EW-DORIN-ROUTER",
+	     "EmbWir-Dorin-Router", ew_dorin_router_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-f9k1115v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-f9k1115v2.c
new file mode 100644
index 0000000000..69d005d795
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-f9k1115v2.c
@@ -0,0 +1,189 @@
+/*
+ *  Belkin AC1750DB (F9K1115V2) board support
+ *
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define F9K1115V2_GPIO_LED_USB2		4
+#define F9K1115V2_GPIO_LED_WPS_AMBER	14
+#define F9K1115V2_GPIO_LED_STATUS_AMBER	15
+#define F9K1115V2_GPIO_LED_WPS_BLUE	19
+#define F9K1115V2_GPIO_LED_STATUS_BLUE	20
+
+#define F9K1115V2_GPIO_BTN_WPS		16
+#define F9K1115V2_GPIO_BTN_RESET	17
+
+#define F9K1115V2_GPIO_USB2_POWER	21
+
+#define F9K1115V2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define F9K1115V2_KEYS_DEBOUNCE_INTERVAL (3 * F9K1115V2_KEYS_POLL_INTERVAL)
+
+#define F9K1115V2_WAN_MAC_OFFSET	0
+#define F9K1115V2_LAN_MAC_OFFSET	6
+#define F9K1115V2_WMAC_CALDATA_OFFSET	0x1000
+#define F9K1115V2_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led f9k1115v2_leds_gpio[] __initdata = {
+	{
+		.name		= "belkin:amber:status",
+		.gpio		= F9K1115V2_GPIO_LED_STATUS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "belkin:blue:status",
+		.gpio		= F9K1115V2_GPIO_LED_STATUS_BLUE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "belkin:blue:wps",
+		.gpio		= F9K1115V2_GPIO_LED_WPS_BLUE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "belkin:amber:wps",
+		.gpio		= F9K1115V2_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "belkin:green:usb2",
+		.gpio		= F9K1115V2_GPIO_LED_USB2,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button f9k1115v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = F9K1115V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= F9K1115V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = F9K1115V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= F9K1115V2_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg f9k1115v2_ar8327_pad0_cfg = {
+	/* Use the RGMII interface for the GMAC0 of the AR8337 switch */
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_pad_cfg f9k1115v2_ar8327_pad6_cfg = {
+	/* Use the SGMII interface for the GMAC6 of the AR8337 switch */
+	.mode = AR8327_PAD_MAC_SGMII,
+	.rxclk_delay_en = true,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+};
+
+static struct ar8327_platform_data f9k1115v2_ar8327_data = {
+	.pad0_cfg = &f9k1115v2_ar8327_pad0_cfg,
+	.pad6_cfg = &f9k1115v2_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info f9k1115v2_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &f9k1115v2_ar8327_data,
+	},
+};
+
+static void __init f9k1115v2_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(f9k1115v2_leds_gpio),
+				 f9k1115v2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, F9K1115V2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(f9k1115v2_gpio_keys),
+					f9k1115v2_gpio_keys);
+
+	ath79_register_wmac(art + F9K1115V2_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_mdio(0, 0x0);
+	mdiobus_register_board_info(f9k1115v2_mdio0_info,
+				    ARRAY_SIZE(f9k1115v2_mdio0_info));
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + F9K1115V2_WAN_MAC_OFFSET, 0);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr,
+		       art + F9K1115V2_LAN_MAC_OFFSET, 0);
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(1);
+
+	ath79_register_pci();
+
+	ath79_register_usb();
+	gpio_request_one(F9K1115V2_GPIO_USB2_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB2 power");
+}
+
+MIPS_MACHINE(ATH79_MACH_F9K1115V2, "F9K1115V2", "Belkin AC1750DB",
+	     f9k1115v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar150.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar150.c
new file mode 100644
index 0000000000..e0d1ea4381
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar150.c
@@ -0,0 +1,125 @@
+/*
+ *  GL_ar150 board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 alzhao <alzhao@gmail.com>
+ *  Copyright (C) 2014 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define GL_AR150_GPIO_LED_WLAN		   0
+#define GL_AR150_GPIO_LED_LAN		   13
+#define GL_AR150_GPIO_LED_WAN		   15 
+
+#define GL_AR150_GPIO_BIN_USB         6
+#define GL_AR150_GPIO_BTN_MANUAL      7
+#define GL_AR150_GPIO_BTN_AUTO	   	   8
+#define GL_AR150_GPIO_BTN_RESET	   11
+
+#define GL_AR150_KEYS_POLL_INTERVAL   20	/* msecs */
+#define GL_AR150_KEYS_DEBOUNCE_INTERVAL	(3 * GL_AR150_KEYS_POLL_INTERVAL)
+
+#define GL_AR150_MAC0_OFFSET	0x0000
+#define GL_AR150_MAC1_OFFSET	0x0000
+#define GL_AR150_CALDATA_OFFSET	0x1000
+#define GL_AR150_WMAC_MAC_OFFSET	0x0000
+
+static struct gpio_led gl_ar150_leds_gpio[] __initdata = {
+	{
+		.name = "gl-ar150:wlan",
+		.gpio = GL_AR150_GPIO_LED_WLAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-ar150:lan",
+		.gpio = GL_AR150_GPIO_LED_LAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-ar150:wan",
+		.gpio = GL_AR150_GPIO_LED_WAN,
+		.active_low = 0,
+ 		.default_state = 1,
+	},
+};
+
+static struct gpio_keys_button gl_ar150_gpio_keys[] __initdata = {
+	{
+		.desc = "BTN_7",
+		.type = EV_KEY,
+		.code = BTN_7,
+		.debounce_interval = GL_AR150_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = GL_AR150_GPIO_BTN_MANUAL,
+		.active_low = 0,
+	},
+	{
+		.desc = "BTN_8",
+		.type = EV_KEY,
+		.code = BTN_8,
+		.debounce_interval = GL_AR150_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = GL_AR150_GPIO_BTN_AUTO,
+		.active_low = 0,
+	},
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = GL_AR150_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = GL_AR150_GPIO_BTN_RESET,
+		.active_low = 0,
+	},
+};
+
+static void __init gl_ar150_setup(void)
+{
+
+	/* ART base address */
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	/* register flash. */
+	ath79_register_m25p80(NULL);
+
+	/* register gpio LEDs and keys */
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(gl_ar150_leds_gpio),
+				 gl_ar150_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, GL_AR150_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(gl_ar150_gpio_keys),
+					gl_ar150_gpio_keys);
+
+	/* enable usb */
+	gpio_request_one(GL_AR150_GPIO_BIN_USB,
+				 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+	 			 "USB power");
+	ath79_register_usb();
+	
+	/* register eth0 as WAN, eth1 as LAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, art+GL_AR150_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art+GL_AR150_MAC1_OFFSET, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	/* register wireless mac with cal data */
+	ath79_register_wmac(art + GL_AR150_CALDATA_OFFSET, art + GL_AR150_WMAC_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_GL_AR150, "GL-AR150", "GL AR150",gl_ar150_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300.c
new file mode 100644
index 0000000000..6f01b9e4de
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300.c
@@ -0,0 +1,103 @@
+/*
+ *  Domino board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 alzhao <alzhao@gmail.com>
+ *  Copyright (C) 2014 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ *  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 <linux/ath9k_platform.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define GL_AR300_GPIO_LED_WLAN	13
+#define GL_AR300_GPIO_LED_WAN	14
+#define GL_AR300_GPIO_BTN_RESET	16
+
+
+#define GL_AR300_KEYS_POLL_INTERVAL	20	/* msecs */
+#define GL_AR300_KEYS_DEBOUNCE_INTERVAL	(3 * GL_AR300_KEYS_POLL_INTERVAL)
+
+#define GL_AR300_MAC0_OFFSET	0x0000
+#define	GL_AR300_MAC1_OFFSET	0x0000
+#define GL_AR300_CALDATA_OFFSET	0x1000
+#define GL_AR300_WMAC_MAC_OFFSET	0x0000
+
+static struct gpio_led gl_ar300_leds_gpio[] __initdata = {
+	{
+		.name = "gl-ar300:wlan",
+		.gpio = GL_AR300_GPIO_LED_WLAN,
+		.active_low = 1,
+	},
+	{
+		.name = "gl-ar300:wan",
+		.gpio = GL_AR300_GPIO_LED_WAN,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_keys_button gl_ar300_gpio_keys[] __initdata = {
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = GL_AR300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = GL_AR300_GPIO_BTN_RESET,
+		.active_low = 1,
+	},
+};
+
+static void __init gl_ar300_setup(void)
+{
+
+	/* ART base address */
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/* register flash. */
+	ath79_register_m25p80(NULL);
+
+	/* register gpio LEDs and keys */
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(gl_ar300_leds_gpio),
+				 gl_ar300_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, GL_AR300_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(gl_ar300_gpio_keys),
+					gl_ar300_gpio_keys);
+
+	/* enable usb */
+	ath79_register_usb();
+	ath79_register_mdio(1, 0x0);
+
+	/* register eth0 as WAN, eth1 as LAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, art+GL_AR300_MAC0_OFFSET, 0);
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art+GL_AR300_MAC1_OFFSET, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	/* register wireless mac with cal data */
+	ath79_register_wmac(art + GL_AR300_CALDATA_OFFSET, art + GL_AR300_WMAC_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_GL_AR300, "GL-AR300", "GL AR300",gl_ar300_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300m.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300m.c
new file mode 100644
index 0000000000..d0f993c032
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-ar300m.c
@@ -0,0 +1,182 @@
+/*
+ *  GLI AR300M(D) board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 alzhao <alzhao@gmail.com>
+ *  Copyright (C) 2014 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ *  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/pci.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define GL_AR300M_GPIO_LED_USB		2
+#define GL_AR300M_GPIO_LED_WLAN		14
+#define GL_AR300M_GPIO_LED_LAN		13
+#define GL_AR300M_GPIO_LED_SYSTEM	12
+#define GL_AR300M_GPIO_BTN_RESET	3
+#define GL_AR300M_GPIO_BTN_LEFT		0
+#define GL_AR300M_GPIO_BTN_RIGHT	1
+
+#define GL_AR300M_KEYS_POLL_INTERVAL        20  /* msecs */
+#define GL_AR300M_KEYS_DEBOUNCE_INTERVAL    (3 * GL_AR300M_KEYS_POLL_INTERVAL)
+
+#define GL_AR300M_MAC0_OFFSET   0
+#define GL_AR300M_MAC1_OFFSET   6
+#define GL_AR300M_WMAC_CALDATA_OFFSET   0x1000
+#define GL_AR300M_PCIE_CALDATA_OFFSET   0x5000
+
+static struct gpio_led gl_ar300m_leds_gpio[] __initdata = {
+    {
+        .name = "gl-ar300m:usb",
+        .gpio = GL_AR300M_GPIO_LED_USB,
+        .active_low = 0,
+        .default_state = 1,
+    },
+    {
+        .name = "gl-ar300m:wlan",
+        .gpio = GL_AR300M_GPIO_LED_WLAN,
+        .active_low = 1,
+    },
+    {
+        .name = "gl-ar300m:lan",
+        .gpio = GL_AR300M_GPIO_LED_LAN,
+        .active_low = 1,
+    },
+    {
+        .name = "gl-ar300m:system",
+        .gpio = GL_AR300M_GPIO_LED_SYSTEM,
+        .active_low = 1,
+        .default_state = 1,
+    },
+};
+
+static struct gpio_keys_button gl_ar300m_gpio_keys[] __initdata = {
+    {
+        .desc = "reset",
+        .type = EV_KEY,
+        .code = KEY_RESTART,
+        .debounce_interval = GL_AR300M_KEYS_DEBOUNCE_INTERVAL,
+        .gpio = GL_AR300M_GPIO_BTN_RESET,
+        .active_low = 1,
+    },
+    {
+        .desc = "button right",
+        .type = EV_KEY,
+        .code = BTN_0,
+        .debounce_interval = GL_AR300M_KEYS_DEBOUNCE_INTERVAL,
+        .gpio = GL_AR300M_GPIO_BTN_LEFT,
+        .active_low = 0,
+    },
+    {
+        .desc = "button left",
+        .type = EV_KEY,
+        .code = BTN_1,
+        .debounce_interval = GL_AR300M_KEYS_DEBOUNCE_INTERVAL,
+        .gpio = GL_AR300M_GPIO_BTN_RIGHT,
+        .active_low = 0,
+    },
+};
+
+static struct ath79_spi_controller_data gl_ar300m_spi0_cdata =
+{
+    .cs_type    = ATH79_SPI_CS_TYPE_INTERNAL,
+    .is_flash   = true,
+    .cs_line    = 0,
+};
+
+static struct ath79_spi_controller_data gl_ar300m_spi1_cdata =
+{
+    .cs_type    = ATH79_SPI_CS_TYPE_INTERNAL,
+    .is_flash   = false,
+    .cs_line    = 1,
+};
+
+static struct spi_board_info gl_ar300m_spi_info[] = {
+    {
+        .bus_num    = 0,
+        .chip_select    = 0,
+        .max_speed_hz   = 25000000,
+        .modalias   = "m25p80",
+        .controller_data = &gl_ar300m_spi0_cdata,
+        .platform_data  = NULL,
+    },
+    {
+        .bus_num    = 0,
+        .chip_select    = 1,
+        .max_speed_hz   = 25000000,
+        .modalias   = "ath79-spinand",
+        .controller_data = &gl_ar300m_spi1_cdata,
+        .platform_data  = NULL,
+    }
+};
+
+static struct ath79_spi_platform_data gl_ar300m_spi_data = {
+    .bus_num        = 0,
+    .num_chipselect     = 2,
+};
+
+static void __init gl_ar300m_setup(void)
+{
+    u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+    u8 tmpmac[ETH_ALEN];
+
+    ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+    ath79_register_spi(&gl_ar300m_spi_data, gl_ar300m_spi_info, 2);
+
+    /* register gpio LEDs and keys */
+    ath79_register_leds_gpio(-1, ARRAY_SIZE(gl_ar300m_leds_gpio),
+                 gl_ar300m_leds_gpio);
+    ath79_register_gpio_keys_polled(-1, GL_AR300M_KEYS_POLL_INTERVAL,
+                    ARRAY_SIZE(gl_ar300m_gpio_keys),
+                    gl_ar300m_gpio_keys);
+
+    ath79_register_mdio(0, 0x0);
+
+    /* WAN */
+    ath79_init_mac(ath79_eth0_data.mac_addr, art + GL_AR300M_MAC0_OFFSET, 0);
+    ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+    ath79_eth0_data.speed = SPEED_100;
+    ath79_eth0_data.duplex = DUPLEX_FULL;
+    ath79_eth0_data.phy_mask = BIT(4);
+    ath79_register_eth(0);
+
+    /* LAN */
+    ath79_init_mac(ath79_eth1_data.mac_addr, art + GL_AR300M_MAC1_OFFSET, 0);
+    ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+    ath79_eth1_data.speed = SPEED_1000;
+    ath79_eth1_data.duplex = DUPLEX_FULL;
+    ath79_switch_data.phy_poll_mask |= BIT(4);
+    ath79_switch_data.phy4_mii_en = 1;
+    ath79_register_eth(1);
+
+    ath79_init_mac(tmpmac, art + GL_AR300M_WMAC_CALDATA_OFFSET + 2, 0);
+    ath79_register_wmac(art + GL_AR300M_WMAC_CALDATA_OFFSET, tmpmac);
+
+    /* enable usb */
+    ath79_register_usb();
+    /* enable pci */
+    ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_GL_AR300M, "GL-AR300M", "GL-AR300M",
+         gl_ar300m_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-domino.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-domino.c
new file mode 100644
index 0000000000..4ff8ff637e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-domino.c
@@ -0,0 +1,136 @@
+/*
+ *  Domino board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 alzhao <alzhao@gmail.com>
+ *  Copyright (C) 2014 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define DOMINO_GPIO_LED_WLAN		0
+#define DOMINO_GPIO_LED_WAN			17
+#define DOMINO_GPIO_LED_USB			1
+#define DOMINO_GPIO_LED_LAN1		13
+#define DOMINO_GPIO_LED_LAN2		14
+#define DOMINO_GPIO_LED_LAN3		15
+#define DOMINO_GPIO_LED_LAN4		16
+#define DOMINO_GPIO_LED_SYS			27
+#define DOMINO_GPIO_LED_WPS			26
+#define DOMINO_GPIO_USB_POWER		6
+
+#define DOMINO_GPIO_BTN_RESET		11
+#define DOMINO_GPIO_BTN_WPS			20
+
+#define DOMINO_KEYS_POLL_INTERVAL	20	/* msecs */
+#define DOMINO_KEYS_DEBOUNCE_INTERVAL	(3 * DOMINO_KEYS_POLL_INTERVAL)
+
+#define DOMINO_MAC0_OFFSET	0x0000
+#define	DOMINO_MAC1_OFFSET	0x0000
+#define DOMINO_CALDATA_OFFSET	0x1000
+#define DOMINO_WMAC_MAC_OFFSET	0x0000
+
+static struct gpio_led domino_leds_gpio[] __initdata = {
+	{
+		.name = "gl-domino:blue:wlan",
+		.gpio = DOMINO_GPIO_LED_WLAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-domino:red:wan",
+		.gpio = DOMINO_GPIO_LED_WAN,
+		.active_low = 1,
+	},
+	{
+		.name = "gl-domino:white:usb",
+		.gpio = DOMINO_GPIO_LED_USB,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-domino:green:lan1",
+		.gpio = DOMINO_GPIO_LED_LAN1,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-domino:yellow:wps",
+		.gpio = DOMINO_GPIO_LED_WPS,
+		.active_low = 1,
+	},
+	{
+		.name = "gl-domino:orange:sys",
+		.gpio = DOMINO_GPIO_LED_SYS,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_keys_button domino_gpio_keys[] __initdata = {
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = DOMINO_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = DOMINO_GPIO_BTN_RESET,
+		.active_low = 0,
+	},
+	{
+		.desc = "wps",
+		.type = EV_KEY,
+		.code = KEY_WPS_BUTTON,
+		.debounce_interval = DOMINO_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = DOMINO_GPIO_BTN_WPS,
+		.active_low = 0,
+	}
+};
+
+static void __init domino_setup(void)
+{
+
+	/* ART base address */
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	/* register flash. */
+	ath79_register_m25p80(NULL);
+
+	/* register gpio LEDs and keys */
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(domino_leds_gpio),
+				 domino_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, DOMINO_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(domino_gpio_keys),
+					domino_gpio_keys);
+
+	gpio_request_one(DOMINO_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	/* enable usb */
+	ath79_register_usb();
+
+	/* register eth0 as WAN, eth1 as LAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, art+DOMINO_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art+DOMINO_MAC1_OFFSET, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	/* register wireless mac with cal data */
+	ath79_register_wmac(art + DOMINO_CALDATA_OFFSET, art + DOMINO_WMAC_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_GL_DOMINO, "DOMINO", "Domino Pi", domino_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-inet.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-inet.c
new file mode 100644
index 0000000000..6f603d9579
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-inet.c
@@ -0,0 +1,104 @@
+/*
+ *  GL-CONNECT iNet board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 alzhao <alzhao@gmail.com>
+ *  Copyright (C) 2014 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define GL_INET_GPIO_LED_WLAN		0
+#define GL_INET_GPIO_LED_LAN		13
+#define GL_INET_GPIO_BTN_RESET		11
+
+#define GL_INET_KEYS_POLL_INTERVAL	20	/* msecs */
+#define GL_INET_KEYS_DEBOUNCE_INTERVAL	(3 * GL_INET_KEYS_POLL_INTERVAL)
+
+static const char * gl_inet_part_probes[] = {
+	"tp-link", /* dont change, this will use tplink parser */
+	NULL ,
+};
+
+static struct flash_platform_data gl_inet_flash_data = {
+	.part_probes = gl_inet_part_probes,
+};
+
+static struct gpio_led gl_inet_leds_gpio[] __initdata = {
+	{
+		.name = "gl-inet:red:wlan",
+		.gpio = GL_INET_GPIO_LED_WLAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-inet:green:lan",
+		.gpio = GL_INET_GPIO_LED_LAN,
+		.active_low = 0,
+		.default_state = 1,
+	},
+};
+
+static struct gpio_keys_button gl_inet_gpio_keys[] __initdata = {
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = GL_INET_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = GL_INET_GPIO_BTN_RESET,
+		.active_low = 0,
+	}
+};
+
+static void __init gl_inet_setup(void)
+{
+	/* get the mac address which is stored in the 1st 64k uboot MTD */
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+
+	/* get the art address, which is the last 64K. By using
+	   0x1fff1000, it doesn't matter it is 4M, 8M or 16M flash */
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	/* register flash. MTD will use tp-link parser to parser MTD */
+	ath79_register_m25p80(&gl_inet_flash_data);
+
+	/* register gpio LEDs and keys */
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(gl_inet_leds_gpio),
+				 gl_inet_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, GL_INET_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(gl_inet_gpio_keys),
+					gl_inet_gpio_keys);
+
+	/* enable usb */
+	ath79_register_usb();
+
+	/* register eth0 as WAN, eth1 as LAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_eth(1);
+
+	/* register wireless mac with cal data */
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_GL_INET, "GL-INET", "GL-CONNECT INET v1",
+	     gl_inet_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-mifi.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-mifi.c
new file mode 100644
index 0000000000..42f4415d7f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gl-mifi.c
@@ -0,0 +1,114 @@
+/*
+ *  Mifi board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 alzhao <alzhao@gmail.com>
+ *  Copyright (C) 2014 Michel Stempin <michel.stempin@wanadoo.fr>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define GL_MIFI_GPIO_LED_WAN		27
+#define GL_MIFI_GPIO_LED_LAN		16
+#define GL_MIFI_GPIO_LED_WLAN		1
+#define GL_MIFI_GPIO_LED_NET		0
+#define GL_MIFI_GPIO_LED_3GCONTROL	7
+
+#define GL_MIFI_GPIO_BTN_RESET    11
+
+#define GL_MIFI_KEYS_POLL_INTERVAL	20	/* msecs */
+#define GL_MIFI_KEYS_DEBOUNCE_INTERVAL	(3 * GL_MIFI_KEYS_POLL_INTERVAL)
+
+#define GL_MIFI_MAC0_OFFSET	    0x0000
+#define GL_MIFI_MAC1_OFFSET	    0x0000
+#define GL_MIFI_CALDATA_OFFSET	0x1000
+#define GL_MIFI_WMAC_MAC_OFFSET	0x0000
+
+static struct gpio_led gl_mifi_leds_gpio[] __initdata = {
+	{
+		.name = "gl-mifi:wan",
+		.gpio = GL_MIFI_GPIO_LED_WAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-mifi:lan",
+		.gpio = GL_MIFI_GPIO_LED_LAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-mifi:wlan",
+		.gpio = GL_MIFI_GPIO_LED_WLAN,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-mifi:net",
+		.gpio = GL_MIFI_GPIO_LED_NET,
+		.active_low = 0,
+	},
+	{
+		.name = "gl-mifi:3gcontrol",
+		.gpio = GL_MIFI_GPIO_LED_3GCONTROL,
+		.active_low = 0,
+	}
+};
+
+static struct gpio_keys_button gl_mifi_gpio_keys[] __initdata = {
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = GL_MIFI_KEYS_DEBOUNCE_INTERVAL,
+		.gpio = GL_MIFI_GPIO_BTN_RESET,
+		.active_low = 0,
+	},
+};
+
+static void __init gl_mifi_setup(void)
+{
+
+	/* ART base address */
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	/* register flash. */
+	ath79_register_m25p80(NULL);
+
+	/* register gpio LEDs and keys */
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(gl_mifi_leds_gpio),
+				 gl_mifi_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, GL_MIFI_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(gl_mifi_gpio_keys),
+					gl_mifi_gpio_keys);
+
+	/* enable usb */
+	ath79_register_usb();
+
+	/* register eth0 as WAN, eth1 as LAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, art+GL_MIFI_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art+GL_MIFI_MAC1_OFFSET, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	/* register wireless mac with cal data */
+	ath79_register_wmac(art + GL_MIFI_CALDATA_OFFSET, art + GL_MIFI_WMAC_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_GL_MIFI, "GL-MIFI", "GL-MIFI",gl_mifi_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gs-minibox-v1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gs-minibox-v1.c
new file mode 100644
index 0000000000..47eeb65de8
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gs-minibox-v1.c
@@ -0,0 +1,85 @@
+/*
+ *  Gainstrong MiniBox V1.0 board support
+ *
+ *
+ *  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 <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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define GS_MINIBOX_V1_GPIO_BTN_RESET	11
+
+#define GS_MINIBOX_V1_GPIO_LED_SYSTEM	1
+
+#define GS_MINIBOX_V1_KEYS_POLL_INTERVAL	20	/* msecs */
+#define GS_MINIBOX_V1_KEYS_DEBOUNCE_INTERVAL (3 * GS_MINIBOX_V1_KEYS_POLL_INTERVAL)
+
+static const char *gs_minibox_v1_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data gs_minibox_v1_flash_data = {
+	.part_probes	= gs_minibox_v1_part_probes,
+};
+
+static struct gpio_led gs_minibox_v1_leds_gpio[] __initdata = {
+	{
+		.name		= "minibox-v1:green:system",
+		.gpio		= GS_MINIBOX_V1_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button gs_minibox_v1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = GS_MINIBOX_V1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= GS_MINIBOX_V1_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+};
+
+static void __init gs_minibox_v1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(gs_minibox_v1_leds_gpio),
+				 gs_minibox_v1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, GS_MINIBOX_V1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(gs_minibox_v1_gpio_keys),
+					gs_minibox_v1_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(&gs_minibox_v1_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_GS_MINIBOX_V1, "MINIBOX-V1",
+	     "MiniBox V1.0", gs_minibox_v1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-gs-oolite.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-gs-oolite.c
new file mode 100644
index 0000000000..c6cb61c366
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-gs-oolite.c
@@ -0,0 +1,103 @@
+/*
+ *  Oolite board support
+ *
+ *
+ *  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 <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"
+#include "dev-usb.h"
+
+#define GS_OOLITE_GPIO_BTN6		6
+#define GS_OOLITE_GPIO_BTN7		7
+#define GS_OOLITE_GPIO_BTN_RESET	11
+
+#define GS_OOLITE_GPIO_LED_SYSTEM	27
+
+#define GS_OOLITE_KEYS_POLL_INTERVAL	20	/* msecs */
+#define GS_OOLITE_KEYS_DEBOUNCE_INTERVAL (3 * GS_OOLITE_KEYS_POLL_INTERVAL)
+
+static const char *gs_oolite_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data gs_oolite_flash_data = {
+	.part_probes	= gs_oolite_part_probes,
+};
+
+static struct gpio_led gs_oolite_leds_gpio[] __initdata = {
+	{
+		.name		= "oolite:red:system",
+		.gpio		= GS_OOLITE_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button gs_oolite_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = GS_OOLITE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= GS_OOLITE_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "BTN_6",
+		.type		= EV_KEY,
+		.code		= BTN_6,
+		.debounce_interval = GS_OOLITE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= GS_OOLITE_GPIO_BTN6,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "BTN_7",
+		.type		= EV_KEY,
+		.code		= BTN_7,
+		.debounce_interval = GS_OOLITE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= GS_OOLITE_GPIO_BTN7,
+		.active_low	= 0,
+	},
+};
+
+static void __init gs_oolite_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(gs_oolite_leds_gpio),
+				 gs_oolite_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, GS_OOLITE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(gs_oolite_gpio_keys),
+					gs_oolite_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(&gs_oolite_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_GS_OOLITE, "GS-OOLITE",
+	     "Oolite V1.0", gs_oolite_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-hiwifi-hc6361.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-hiwifi-hc6361.c
new file mode 100644
index 0000000000..6600595c05
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-hiwifi-hc6361.c
@@ -0,0 +1,115 @@
+/*
+ *  HiWiFi HC6361 board support
+ *
+ *  Copyright (C) 2012-2013 eric
+ *  Copyright (C) 2014 Yousong Zhou <yszhou4tech@gmail.com>
+ *
+ *  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/proc_fs.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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define HIWIFI_HC6361_GPIO_LED_WLAN_2P4		0	/* 2.4G WLAN LED */
+#define HIWIFI_HC6361_GPIO_LED_SYSTEM		1	/* System LED */
+#define HIWIFI_HC6361_GPIO_LED_INTERNET		27	/* Internet LED */
+
+#define HIWIFI_HC6361_GPIO_USBPOWER		20	/* USB power control */
+#define HIWIFI_HC6361_GPIO_BTN_RST		11	/* Reset button */
+
+#define HIWIFI_HC6361_KEYS_POLL_INTERVAL	20	/* msecs */
+#define HIWIFI_HC6361_KEYS_DEBOUNCE_INTERVAL	\
+	(3 * HIWIFI_HC6361_KEYS_POLL_INTERVAL)
+
+static struct gpio_led hiwifi_leds_gpio[] __initdata = {
+	{
+		.name		= "hiwifi:blue:wlan-2p4",
+		.gpio		= HIWIFI_HC6361_GPIO_LED_WLAN_2P4,
+		.active_low	= 1,
+	}, {
+		.name		= "hiwifi:blue:system",
+		.gpio		= HIWIFI_HC6361_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "hiwifi:blue:internet",
+		.gpio		= HIWIFI_HC6361_GPIO_LED_INTERNET,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button hiwifi_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = HIWIFI_HC6361_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= HIWIFI_HC6361_GPIO_BTN_RST,
+		.active_low	= 1,
+	}
+};
+
+static void __init get_mac_from_bdinfo(u8 *mac, void *bdinfo)
+{
+	if (sscanf(bdinfo, "fac_mac = %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
+				&mac[0], &mac[1], &mac[2], &mac[3],
+				&mac[4], &mac[5]) == 6) {
+		return;
+	}
+
+	printk(KERN_WARNING "Parsing MAC address failed.\n");
+	memcpy(mac, "\x00\xba\xbe\x00\x00\x00", 6);
+}
+
+static void __init hiwifi_hc6361_setup(void)
+{
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac[6];
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(NULL);
+	ath79_gpio_function_enable(
+			AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+			AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+			AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+			AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+			AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(hiwifi_leds_gpio),
+			hiwifi_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, HIWIFI_HC6361_KEYS_POLL_INTERVAL,
+			ARRAY_SIZE(hiwifi_gpio_keys),
+			hiwifi_gpio_keys);
+	gpio_request_one(HIWIFI_HC6361_GPIO_USBPOWER,
+			GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			"USB power");
+	ath79_register_usb();
+
+	get_mac_from_bdinfo(mac, (void *) KSEG1ADDR(0x1f010180));
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_HIWIFI_HC6361, "HiWiFi-HC6361",
+		"HiWiFi HC6361", hiwifi_hc6361_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-hornet-ub.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-hornet-ub.c
new file mode 100644
index 0000000000..1d21424585
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-hornet-ub.c
@@ -0,0 +1,142 @@
+/*
+ *  ALFA NETWORK Hornet-UB board support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define HORNET_UB_GPIO_LED_WLAN		0
+#define HORNET_UB_GPIO_LED_USB		1
+#define HORNET_UB_GPIO_LED_LAN		13
+#define HORNET_UB_GPIO_LED_WAN		17
+#define HORNET_UB_GPIO_LED_WPS		27
+#define HORNET_UB_GPIO_EXT_LNA		28
+
+#define HORNET_UB_GPIO_BTN_RESET	12
+#define HORNET_UB_GPIO_BTN_WPS		11
+
+#define HORNET_UB_GPIO_USB_POWER	26
+
+#define HORNET_UB_KEYS_POLL_INTERVAL	20	/* msecs */
+#define HORNET_UB_KEYS_DEBOUNCE_INTERVAL	(3 * HORNET_UB_KEYS_POLL_INTERVAL)
+
+#define HORNET_UB_MAC0_OFFSET		0x0000
+#define HORNET_UB_MAC1_OFFSET		0x0006
+#define HORNET_UB_CALDATA_OFFSET	0x1000
+
+static struct gpio_led hornet_ub_leds_gpio[] __initdata = {
+	{
+		.name		= "alfa:blue:lan",
+		.gpio		= HORNET_UB_GPIO_LED_LAN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "alfa:blue:usb",
+		.gpio		= HORNET_UB_GPIO_LED_USB,
+		.active_low	= 0,
+	},
+	{
+		.name		= "alfa:blue:wan",
+		.gpio		= HORNET_UB_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "alfa:blue:wlan",
+		.gpio		= HORNET_UB_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "alfa:blue:wps",
+		.gpio		= HORNET_UB_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button hornet_ub_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = HORNET_UB_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= HORNET_UB_GPIO_BTN_WPS,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = HORNET_UB_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= HORNET_UB_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init hornet_ub_gpio_setup(void)
+{
+	u32 t;
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+	t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
+	ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
+
+	gpio_request_one(HORNET_UB_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	gpio_request_one(HORNET_UB_GPIO_EXT_LNA,
+			GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			"external LNA0");
+
+}
+
+static void __init hornet_ub_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	hornet_ub_gpio_setup();
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(hornet_ub_leds_gpio),
+					hornet_ub_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, HORNET_UB_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(hornet_ub_gpio_keys),
+					 hornet_ub_gpio_keys);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr,
+			art + HORNET_UB_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+			art + HORNET_UB_MAC1_OFFSET, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art + HORNET_UB_CALDATA_OFFSET, NULL);
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_HORNET_UB, "HORNET-UB", "ALFA NETWORK Hornet-UB",
+	     hornet_ub_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ja76pf.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ja76pf.c
new file mode 100644
index 0000000000..d1fe0f8a26
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ja76pf.c
@@ -0,0 +1,190 @@
+/*
+ *  jjPlus JA76PF board support
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define JA76PF_KEYS_POLL_INTERVAL	20	/* msecs */
+#define JA76PF_KEYS_DEBOUNCE_INTERVAL	(3 * JA76PF_KEYS_POLL_INTERVAL)
+
+#define JA76PF_GPIO_I2C_SCL		0
+#define JA76PF_GPIO_I2C_SDA		1
+#define JA76PF_GPIO_LED_1		5
+#define JA76PF_GPIO_LED_2		4
+#define JA76PF_GPIO_LED_3		3
+#define JA76PF_GPIO_BTN_RESET		11
+
+static struct gpio_led ja76pf_leds_gpio[] __initdata = {
+	{
+		.name		= "jjplus:green:led1",
+		.gpio		= JA76PF_GPIO_LED_1,
+		.active_low	= 1,
+	}, {
+		.name		= "jjplus:green:led2",
+		.gpio		= JA76PF_GPIO_LED_2,
+		.active_low	= 1,
+	}, {
+		.name		= "jjplus:green:led3",
+		.gpio		= JA76PF_GPIO_LED_3,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button ja76pf_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = JA76PF_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= JA76PF_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct i2c_gpio_platform_data ja76pf_i2c_gpio_data = {
+	.sda_pin	= JA76PF_GPIO_I2C_SDA,
+	.scl_pin	= JA76PF_GPIO_I2C_SCL,
+};
+
+static struct platform_device ja76pf_i2c_gpio_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev = {
+		.platform_data  = &ja76pf_i2c_gpio_data,
+	}
+};
+
+static const char *ja76pf_part_probes[] = {
+	"RedBoot",
+	NULL,
+};
+
+static struct flash_platform_data ja76pf_flash_data = {
+	.part_probes	= ja76pf_part_probes,
+};
+
+#define JA76PF_WAN_PHYMASK	(1 << 4)
+#define JA76PF_LAN_PHYMASK	((1 << 0) | (1 << 1) | (1 << 2) | (1 < 3))
+#define JA76PF_MDIO_PHYMASK	(JA76PF_LAN_PHYMASK | JA76PF_WAN_PHYMASK)
+
+static void __init ja76pf_init(void)
+{
+	ath79_register_m25p80(&ja76pf_flash_data);
+
+	ath79_register_mdio(0, ~JA76PF_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = JA76PF_LAN_PHYMASK;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = JA76PF_WAN_PHYMASK;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	platform_device_register(&ja76pf_i2c_gpio_device);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ja76pf_leds_gpio),
+					ja76pf_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, JA76PF_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(ja76pf_gpio_keys),
+					 ja76pf_gpio_keys);
+
+	ath79_register_usb();
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_JA76PF, "JA76PF", "jjPlus JA76PF", ja76pf_init);
+
+#define JA76PF2_GPIO_LED_D2		5
+#define JA76PF2_GPIO_LED_D3		4
+#define JA76PF2_GPIO_LED_D4		3
+#define JA76PF2_GPIO_BTN_RESET		7
+#define JA76PF2_GPIO_BTN_WPS		8
+
+static struct gpio_led ja76pf2_leds_gpio[] __initdata = {
+	{
+		.name		= "jjplus:green:led1",
+		.gpio		= JA76PF2_GPIO_LED_D2,
+		.active_low	= 1,
+	}, {
+		.name		= "jjplus:green:led2",
+		.gpio		= JA76PF2_GPIO_LED_D3,
+		.active_low	= 0,
+	}, {
+		.name		= "jjplus:green:led3",
+		.gpio		= JA76PF2_GPIO_LED_D4,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button ja76pf2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = JA76PF_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= JA76PF2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = JA76PF_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= JA76PF2_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+#define JA76PF2_LAN_PHYMASK	BIT(0)
+#define JA76PF2_WAN_PHYMASK	BIT(4)
+#define JA76PF2_MDIO_PHYMASK	(JA76PF2_LAN_PHYMASK | JA76PF2_WAN_PHYMASK)
+
+static void __init ja76pf2_init(void)
+{
+	ath79_register_m25p80(&ja76pf_flash_data);
+
+	ath79_register_mdio(0, ~JA76PF2_MDIO_PHYMASK);
+
+	/* MAC0 is connected to the CPU port of the AR8316 switch */
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	/* MAC1 is connected to the PHY4 of the AR8316 switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = BIT(4);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ja76pf2_leds_gpio),
+				 ja76pf2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, JA76PF_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ja76pf2_gpio_keys),
+					ja76pf2_gpio_keys);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_JA76PF2, "JA76PF2", "jjPlus JA76PF2", ja76pf2_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-jwap003.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-jwap003.c
new file mode 100644
index 0000000000..a3c93ccd90
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-jwap003.c
@@ -0,0 +1,95 @@
+/*
+ *  jjPlus JWAP003 board support
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-gpio-buttons.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define JWAP003_KEYS_POLL_INTERVAL	20	/* msecs */
+#define JWAP003_KEYS_DEBOUNCE_INTERVAL	(3 * JWAP003_KEYS_POLL_INTERVAL)
+
+#define JWAP003_GPIO_WPS	11
+#define JWAP003_GPIO_I2C_SCL	0
+#define JWAP003_GPIO_I2C_SDA	1
+
+static struct gpio_keys_button jwap003_gpio_keys[] __initdata = {
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = JWAP003_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= JWAP003_GPIO_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct i2c_gpio_platform_data jwap003_i2c_gpio_data = {
+	.sda_pin	= JWAP003_GPIO_I2C_SDA,
+	.scl_pin	= JWAP003_GPIO_I2C_SCL,
+};
+
+static struct platform_device jwap003_i2c_gpio_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev = {
+		.platform_data  = &jwap003_i2c_gpio_data,
+	}
+};
+
+static const char *jwap003_part_probes[] = {
+	"RedBoot",
+	NULL,
+};
+
+static struct flash_platform_data jwap003_flash_data = {
+	.part_probes	= jwap003_part_probes,
+};
+
+#define JWAP003_WAN_PHYMASK	BIT(0)
+#define JWAP003_LAN_PHYMASK	BIT(4)
+
+static void __init jwap003_init(void)
+{
+	ath79_register_m25p80(&jwap003_flash_data);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.phy_mask = JWAP003_WAN_PHYMASK;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.has_ar8216 = 1;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = JWAP003_LAN_PHYMASK;
+	ath79_eth1_data.speed = SPEED_100;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	platform_device_register(&jwap003_i2c_gpio_device);
+
+	ath79_register_usb();
+
+	ath79_register_gpio_keys_polled(-1, JWAP003_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(jwap003_gpio_keys),
+					 jwap003_gpio_keys);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_JWAP003, "JWAP003", "jjPlus JWAP003", jwap003_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-jwap230.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-jwap230.c
new file mode 100644
index 0000000000..f94e5b450c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-jwap230.c
@@ -0,0 +1,158 @@
+/*
+ * jjPlus JWAP230 board support
+ *
+ * Copyright (C) 2016 Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * Based on mach-wpj558.c and mach-tl-wr1043nd-v2.c
+ *
+ * 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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define JWAP230_GPIO_LED_LED1		23
+#define JWAP230_GPIO_LED_LED2		22
+#define JWAP230_GPIO_LED_LED3		21
+
+#define JWAP230_MAC0_OFFSET		0x0
+#define JWAP230_MAC1_OFFSET		0x6
+#define JWAP230_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led jwap230_leds_gpio[] __initdata = {
+	{
+		.name		= "jwap230:green:led1",
+		.gpio		= JWAP230_GPIO_LED_LED1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "jwap230:green:led2",
+		.gpio		= JWAP230_GPIO_LED_LED2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "jwap230:green:led3",
+		.gpio		= JWAP230_GPIO_LED_LED3,
+		.active_low	= 1,
+	}
+};
+
+static const struct ar8327_led_info jwap230_leds_qca8337[] = {
+	AR8327_LED_INFO(PHY0_0, HW, "jwap230:green:lan"),
+	AR8327_LED_INFO(PHY4_0, HW, "jwap230:green:wan"),
+};
+
+/* Blink rate: 1 Gbps -> 8 hz, 100 Mbs -> 4 Hz, 10 Mbps -> 2 Hz */
+static struct ar8327_led_cfg jwap230_qca8337_led_cfg = {
+	.led_ctrl0 = 0xcf37cf37,
+	.led_ctrl1 = 0xcf37cf37,
+	.led_ctrl2 = 0xcf37cf37,
+	.led_ctrl3 = 0x0,
+	.open_drain = true,
+};
+
+/* QCA8337 GMAC0 is connected with QCA9558 over RGMII */
+static struct ar8327_pad_cfg jwap230_qca8337_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+	.mac06_exchange_dis = true,
+};
+
+/* QCA8337 GMAC6 is connected with QCA9558 over SGMII */
+static struct ar8327_pad_cfg jwap230_qca8337_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+};
+
+static struct ar8327_platform_data jwap230_qca8337_data = {
+	.pad0_cfg = &jwap230_qca8337_pad0_cfg,
+	.pad6_cfg = &jwap230_qca8337_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &jwap230_qca8337_led_cfg,
+	.num_leds = ARRAY_SIZE(jwap230_leds_qca8337),
+	.leds = jwap230_leds_qca8337,
+};
+
+static struct mdio_board_info jwap230_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &jwap230_qca8337_data,
+	},
+};
+
+static void __init jwap230_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(jwap230_leds_gpio),
+				 jwap230_leds_gpio);
+
+	mdiobus_register_board_info(jwap230_mdio0_info,
+				    ARRAY_SIZE(jwap230_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* QCA9558 GMAC0 is connected to RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + JWAP230_MAC0_OFFSET, 0);
+	ath79_register_eth(0);
+
+	/* QCA9558 GMAC1 is connected to SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + JWAP230_MAC1_OFFSET, 0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(art + JWAP230_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_JWAP230, "JWAP230", "jjPlus JWAP230", jwap230_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mc-mac1200r.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mc-mac1200r.c
new file mode 100644
index 0000000000..70051cff47
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mc-mac1200r.c
@@ -0,0 +1,155 @@
+/*
+ *  MERCURY MAC1200R board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 Gui Iribarren <gui@altermundi.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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define MAC1200R_GPIO_LED_WLAN2G	13
+#define MAC1200R_GPIO_LED_WLAN5G	17
+#define MAC1200R_GPIO_LED_SYSTEM	14
+#define MAC1200R_GPIO_LED_WPS		11
+#define MAC1200R_GPIO_LED_WAN		12
+#define MAC1200R_GPIO_LED_LAN1		15
+#define MAC1200R_GPIO_LED_LAN2		21
+#define MAC1200R_GPIO_LED_LAN3		22
+#define MAC1200R_GPIO_LED_LAN4		20
+
+#define MAC1200R_GPIO_BTN_WPS		16
+
+#define MAC1200R_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MAC1200R_KEYS_DEBOUNCE_INTERVAL	(3 * MAC1200R_KEYS_POLL_INTERVAL)
+
+#define MAC1200R_MAC0_OFFSET		0
+#define MAC1200R_MAC1_OFFSET		6
+#define MAC1200R_WMAC_CALDATA_OFFSET	0x1000
+#define MAC1200R_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *mac1200r_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data mac1200r_flash_data = {
+	.part_probes	= mac1200r_part_probes,
+};
+
+static struct gpio_led mac1200r_leds_gpio[] __initdata = {
+	{
+		.name		= "mercury:green:wps",
+		.gpio		= MAC1200R_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mercury:green:system",
+		.gpio		= MAC1200R_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mercury:green:wlan2g",
+		.gpio		= MAC1200R_GPIO_LED_WLAN2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mercury:green:wlan5g",
+		.gpio		= MAC1200R_GPIO_LED_WLAN5G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mac1200r_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MAC1200R_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MAC1200R_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+
+static void __init mac1200r_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&mac1200r_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mac1200r_leds_gpio),
+					mac1200r_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, MAC1200R_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mac1200r_gpio_keys),
+					mac1200r_gpio_keys);
+
+	ath79_init_mac(tmpmac, mac, 0);
+	ath79_wmac_disable_5ghz();
+	ath79_register_wmac(art + MAC1200R_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_init_mac(tmpmac, mac, 1);
+	ap91_pci_init(art + MAC1200R_PCIE_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* LAN */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 2);
+
+	/* GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(0);
+
+	ath79_gpio_output_select(MAC1200R_GPIO_LED_LAN1,
+				 AR934X_GPIO_OUT_LED_LINK3);
+	ath79_gpio_output_select(MAC1200R_GPIO_LED_LAN2,
+				 AR934X_GPIO_OUT_LED_LINK2);
+	ath79_gpio_output_select(MAC1200R_GPIO_LED_LAN3,
+				 AR934X_GPIO_OUT_LED_LINK1);
+	ath79_gpio_output_select(MAC1200R_GPIO_LED_LAN4,
+				 AR934X_GPIO_OUT_LED_LINK0);
+	ath79_gpio_output_select(MAC1200R_GPIO_LED_WAN,
+				 AR934X_GPIO_OUT_LED_LINK4);
+}
+
+MIPS_MACHINE(ATH79_MACH_MC_MAC1200R, "MC-MAC1200R",
+	     "MERCURY MAC1200R",
+	     mac1200r_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr12.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr12.c
new file mode 100644
index 0000000000..5a337e5c9f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr12.c
@@ -0,0 +1,114 @@
+/*
+ *  Cisco Meraki MR12 board support
+ *
+ *  Copyright (C) 2014-2015 Chris Blake <chrisrblake93@gmail.com>
+ *
+ *  Based on Atheros AP96 board support configuration
+ *
+ *  Copyright (C) 2009 Marco Porsch
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Atheros Communications
+ *
+ *  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/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define MR12_GPIO_LED_W4_GREEN		14
+#define MR12_GPIO_LED_W3_GREEN		13
+#define MR12_GPIO_LED_W2_GREEN		12
+#define MR12_GPIO_LED_W1_GREEN		11
+
+#define MR12_GPIO_LED_WAN		15
+
+#define MR12_GPIO_LED_POWER_ORANGE		16
+#define MR12_GPIO_LED_POWER_GREEN		17
+
+#define MR12_GPIO_BTN_RESET		8
+#define MR12_KEYS_POLL_INTERVAL		20	/* msecs */
+#define MR12_KEYS_DEBOUNCE_INTERVAL	(3 * MR12_KEYS_POLL_INTERVAL)
+
+#define MR12_WAN_PHYMASK    BIT(4)
+
+#define MR12_CALDATA0_OFFSET            0x21000
+
+static struct gpio_led MR12_leds_gpio[] __initdata = {
+	{
+		.name		= "mr12:green:wan",
+		.gpio		= MR12_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr12:orange:power",
+		.gpio		= MR12_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+	}, {
+		.name		= "mr12:green:power",
+		.gpio		= MR12_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr12:green:wifi4",
+		.gpio		= MR12_GPIO_LED_W4_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr12:green:wifi3",
+		.gpio		= MR12_GPIO_LED_W3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr12:green:wifi2",
+		.gpio		= MR12_GPIO_LED_W2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr12:green:wifi1",
+		.gpio		= MR12_GPIO_LED_W1_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button MR12_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MR12_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MR12_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init MR12_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0xbffd0000);
+	u8 wlan_mac[ETH_ALEN];
+
+	ath79_register_mdio(0,0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = MR12_WAN_PHYMASK;
+	ath79_register_eth(0);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(MR12_leds_gpio),
+					MR12_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MR12_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(MR12_gpio_keys),
+					MR12_gpio_keys);
+
+	ath79_init_mac(wlan_mac, mac, 1);
+	ap91_pci_init(mac + MR12_CALDATA0_OFFSET, wlan_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_MR12, "MR12", "Meraki MR12", MR12_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr16.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr16.c
new file mode 100644
index 0000000000..9da21eab5a
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr16.c
@@ -0,0 +1,118 @@
+/*
+ *  Cisco Meraki MR16 board support
+ *
+ *  Copyright (C) 2015 Chris Blake <chrisrblake93@gmail.com>
+ *
+ *  Based on Atheros AP96 board support configuration
+ *
+ *  Copyright (C) 2009 Marco Porsch
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Atheros Communications
+ *
+ *  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/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define MR16_GPIO_LED_W4_GREEN		3
+#define MR16_GPIO_LED_W3_GREEN		2
+#define MR16_GPIO_LED_W2_GREEN		1
+#define MR16_GPIO_LED_W1_GREEN		0
+
+#define MR16_GPIO_LED_WAN		4
+
+#define MR16_GPIO_LED_POWER_ORANGE		5
+#define MR16_GPIO_LED_POWER_GREEN		6
+
+#define MR16_GPIO_BTN_RESET		7
+#define MR16_KEYS_POLL_INTERVAL		20	/* msecs */
+#define MR16_KEYS_DEBOUNCE_INTERVAL	(3 * MR16_KEYS_POLL_INTERVAL)
+
+#define MR16_WAN_PHYMASK    BIT(0)
+
+#define MR16_CALDATA0_OFFSET		0x21000
+#define MR16_CALDATA1_OFFSET		0x25000
+
+static struct gpio_led MR16_leds_gpio[] __initdata = {
+	{
+		.name		= "mr16:green:wan",
+		.gpio		= MR16_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr16:orange:power",
+		.gpio		= MR16_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+	}, {
+		.name		= "mr16:green:power",
+		.gpio		= MR16_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr16:green:wifi4",
+		.gpio		= MR16_GPIO_LED_W4_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr16:green:wifi3",
+		.gpio		= MR16_GPIO_LED_W3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr16:green:wifi2",
+		.gpio		= MR16_GPIO_LED_W2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "mr16:green:wifi1",
+		.gpio		= MR16_GPIO_LED_W1_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button MR16_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MR16_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MR16_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init MR16_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0xbffd0000);
+	u8 wlan0_mac[ETH_ALEN];
+	u8 wlan1_mac[ETH_ALEN];
+
+	ath79_register_mdio(0,0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = MR16_WAN_PHYMASK;
+	ath79_register_eth(0);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(MR16_leds_gpio),
+					MR16_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MR16_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(MR16_gpio_keys),
+					MR16_gpio_keys);
+
+	ath79_init_mac(wlan0_mac, mac, 1);
+	ath79_init_mac(wlan1_mac, mac, 2);
+	ap94_pci_init(mac + MR16_CALDATA0_OFFSET, wlan0_mac,
+		    mac + MR16_CALDATA1_OFFSET, wlan1_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_MR16, "MR16", "Meraki MR16", MR16_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c
new file mode 100644
index 0000000000..18101ce8e4
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr1750.c
@@ -0,0 +1,171 @@
+/*
+ * MR1750 board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Marek Lindner <marek@open-mesh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define MR1750_GPIO_LED_LAN		12
+#define MR1750_GPIO_LED_WLAN_2G		13
+#define MR1750_GPIO_LED_STATUS_GREEN	19
+#define MR1750_GPIO_LED_STATUS_RED	21
+#define MR1750_GPIO_LED_POWER		22
+#define MR1750_GPIO_LED_WLAN_5G		23
+
+#define MR1750_GPIO_BTN_RESET		17
+
+#define MR1750_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MR1750_KEYS_DEBOUNCE_INTERVAL	(3 * MR1750_KEYS_POLL_INTERVAL)
+
+#define MR1750_MAC0_OFFSET		0
+#define MR1750_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led mr1750_leds_gpio[] __initdata = {
+	{
+		.name		= "mr1750:blue:power",
+		.gpio		= MR1750_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr1750:blue:wan",
+		.gpio		= MR1750_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr1750:blue:wlan24",
+		.gpio		= MR1750_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr1750:blue:wlan58",
+		.gpio		= MR1750_GPIO_LED_WLAN_5G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr1750:green:status",
+		.gpio		= MR1750_GPIO_LED_STATUS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr1750:red:status",
+		.gpio		= MR1750_GPIO_LED_STATUS_RED,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mr1750_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MR1750_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MR1750_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct at803x_platform_data mr1750_at803x_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 0,
+	.fixup_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info mr1750_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 5,
+		.platform_data = &mr1750_at803x_data,
+	},
+};
+
+static void __init mr1750_setup_qca955x_eth_cfg(u32 mask,
+						unsigned int rxd,
+						unsigned int rxdv,
+						unsigned int txd,
+						unsigned int txe)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+	t = mask;
+	t |= rxd << QCA955X_ETH_CFG_RXD_DELAY_SHIFT;
+	t |= rxdv << QCA955X_ETH_CFG_RDV_DELAY_SHIFT;
+	t |= txd << QCA955X_ETH_CFG_TXD_DELAY_SHIFT;
+	t |= txe << QCA955X_ETH_CFG_TXE_DELAY_SHIFT;
+
+	__raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+static void __init mr1750_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	ath79_eth0_pll_data.pll_1000 = 0xae000000;
+	ath79_eth0_pll_data.pll_100 = 0xa0000101;
+	ath79_eth0_pll_data.pll_10 = 0xa0001313;
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mr1750_leds_gpio),
+				 mr1750_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MR1750_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mr1750_gpio_keys),
+					mr1750_gpio_keys);
+
+	ath79_init_mac(mac, art + MR1750_MAC0_OFFSET, 1);
+	ath79_register_wmac(art + MR1750_WMAC_CALDATA_OFFSET, mac);
+	ath79_register_pci();
+
+	mr1750_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN, 3, 3, 0, 0);
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(mr1750_mdio0_info,
+				    ARRAY_SIZE(mr1750_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + MR1750_MAC0_OFFSET, 0);
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(5);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_MR1750, "MR1750", "OpenMesh MR1750", mr1750_setup);
+MIPS_MACHINE(ATH79_MACH_MR1750V2, "MR1750v2", "OpenMesh MR1750v2", mr1750_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c
new file mode 100644
index 0000000000..a24cb3fce6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr18.c
@@ -0,0 +1,297 @@
+/*
+ *  Cisco Meraki MR18 board support
+ *
+ *  Copyright (C) 2015 Chris Blake <chrisrblake93@gmail.com>
+ *  Copyright (C) 2015 Christian Lamparter <chunkeey@googlemail.com>
+ *  Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
+ *
+ *  Based on Cisco Meraki GPL Release r23-20150601 MR18 Device Config
+ *
+ *  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/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/platform/ar934x_nfc.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/leds-nu801.h>
+#include <linux/pci.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define MR18_GPIO_LED_POWER_WHITE    18
+#define MR18_GPIO_LED_POWER_ORANGE    21
+
+#define MR18_GPIO_BTN_RESET    17
+#define MR18_KEYS_POLL_INTERVAL    20  /* msecs */
+#define MR18_KEYS_DEBOUNCE_INTERVAL  (3 * MR18_KEYS_POLL_INTERVAL)
+
+#define MR18_WAN_PHYADDR    3
+
+/* used for eth calibration */
+#define MR18_OTP_BASE			(AR71XX_APB_BASE + 0x130000)
+#define MR18_OTP_SIZE			(0x2000) /* just a guess */
+#define MR18_OTP_MEM_0_REG		(0x0000)
+#define MR18_OTP_INTF2_REG		(0x1008)
+#define MR18_OTP_STATUS0_REG		(0x1018)
+#define MR18_OTP_STATUS0_EFUSE_VALID	BIT(2)
+
+#define MR18_OTP_STATUS1_REG		(0x101c)
+#define MR18_OTP_LDO_CTRL_REG		(0x1024)
+#define MR18_OTP_LDO_STATUS_REG		(0x102c)
+#define MR18_OTP_LDO_STATUS_POWER_ON	BIT(0)
+
+static struct gpio_led MR18_leds_gpio[] __initdata = {
+	{
+		.name = "mr18:white:power",
+		.gpio = MR18_GPIO_LED_POWER_WHITE,
+		.active_low  = 1,
+	}, {
+		.name = "mr18:orange:power",
+		.gpio = MR18_GPIO_LED_POWER_ORANGE,
+		.active_low  = 0,
+	},
+};
+
+static struct gpio_keys_button MR18_gpio_keys[] __initdata = {
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = MR18_KEYS_DEBOUNCE_INTERVAL,
+		.gpio    = MR18_GPIO_BTN_RESET,
+		.active_low  = 1,
+	},
+};
+
+static struct led_nu801_template tricolor_led_template = {
+	.device_name = "mr18",
+	.name = "tricolor",
+	.num_leds = 1,
+	.cki = 11,
+	.sdi = 12,
+	.lei = -1,
+	.ndelay = 500,
+	.init_brightness = {
+		LED_OFF,
+		LED_OFF,
+		LED_OFF,
+	},
+	.default_trigger = "none",
+	.led_colors = { "red", "green", "blue" },
+};
+
+static struct led_nu801_platform_data tricolor_led_data = {
+	.num_controllers = 1,
+	.template = &tricolor_led_template,
+};
+
+static struct platform_device tricolor_leds = {
+	.name = "leds-nu801",
+	.id = -1,
+	.dev.platform_data = &tricolor_led_data,
+};
+
+static int mr18_extract_sgmii_res_cal(void)
+{
+	void __iomem *base;
+	unsigned int reversed_sgmii_value;
+
+	unsigned int otp_value, otp_per_val, rbias_per, read_data;
+	unsigned int rbias_pos_or_neg;
+	unsigned int sgmii_res_cal_value;
+	int res_cal_val;
+
+	base = ioremap_nocache(MR18_OTP_BASE, MR18_OTP_SIZE);
+	if (!base)
+		return -EIO;
+
+	__raw_writel(0x7d, base + MR18_OTP_INTF2_REG);
+	__raw_writel(0x00, base + MR18_OTP_LDO_CTRL_REG);
+
+	while (__raw_readl(base + MR18_OTP_LDO_STATUS_REG) &
+		MR18_OTP_LDO_STATUS_POWER_ON);
+
+	__raw_readl(base + MR18_OTP_MEM_0_REG + 4);
+
+	while (!(__raw_readl(base + MR18_OTP_STATUS0_REG) &
+		MR18_OTP_STATUS0_EFUSE_VALID));
+
+	read_data = __raw_readl(base + MR18_OTP_STATUS1_REG);
+
+	iounmap(base);
+
+	if (!(read_data & 0x1fff))
+		return -ENODEV;
+
+	if (read_data & 0x00001000)
+		otp_value = (read_data & 0xfc0) >> 6;
+	else
+		otp_value = read_data & 0x3f;
+
+	if (otp_value > 31) {
+		otp_per_val = 63 - otp_value;
+		rbias_pos_or_neg = 1;
+	} else {
+		otp_per_val = otp_value;
+		rbias_pos_or_neg = 0;
+	}
+
+	rbias_per = otp_per_val * 15;
+
+	if (rbias_pos_or_neg == 1)
+		res_cal_val = (rbias_per + 34) / 21;
+	else if (rbias_per > 34)
+		res_cal_val = -((rbias_per - 34) / 21);
+	else
+		res_cal_val = (34 - rbias_per) / 21;
+
+	sgmii_res_cal_value = (8 + res_cal_val) & 0xf;
+
+	reversed_sgmii_value  = (sgmii_res_cal_value & 8) >> 3;
+	reversed_sgmii_value |= (sgmii_res_cal_value & 4) >> 1;
+	reversed_sgmii_value |= (sgmii_res_cal_value & 2) << 1;
+	reversed_sgmii_value |= (sgmii_res_cal_value & 1) << 3;
+	printk(KERN_INFO "SGMII cal value = 0x%x\n", reversed_sgmii_value);
+	return reversed_sgmii_value;
+}
+
+#define QCA955X_PLL_ETH_SGMII_SERDES_REG		0x004c
+#define QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT	BIT(2)
+#define QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK		BIT(1)
+#define QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL		BIT(0)
+
+#define QCA955X_GMAC_REG_SGMII_SERDES			0x0018
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION		BIT(23)
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK	0xf
+#define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT	23
+#define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS		BIT(15)
+
+static void mr18_setup_qca955x_eth_serdes_cal(unsigned int sgmii_value)
+{
+	void __iomem *ethbase, *pllbase;
+	u32 t;
+
+	ethbase = ioremap_nocache(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+	pllbase = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
+
+	/* To Check the locking of the SGMII PLL */
+	t = __raw_readl(ethbase + QCA955X_GMAC_REG_SGMII_SERDES);
+	t &= ~(QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK <<
+	       QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT);
+	t |= (sgmii_value & QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK) <<
+	     QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT;
+	__raw_writel(t, ethbase + QCA955X_GMAC_REG_SGMII_SERDES);
+
+	__raw_writel(QCA955X_PLL_ETH_SGMII_SERDES_LOCK_DETECT |
+		     QCA955X_PLL_ETH_SGMII_SERDES_PLL_REFCLK |
+		     QCA955X_PLL_ETH_SGMII_SERDES_EN_PLL,
+		     pllbase + QCA955X_PLL_ETH_SGMII_SERDES_REG);
+
+	ath79_device_reset_clear(QCA955X_RESET_SGMII_ANALOG);
+	ath79_device_reset_clear(QCA955X_RESET_SGMII);
+
+	while (!(__raw_readl(ethbase + QCA955X_GMAC_REG_SGMII_SERDES) &
+		QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS));
+
+	iounmap(ethbase);
+	iounmap(pllbase);
+}
+
+static struct ath9k_platform_data pci_main_wifi_data = {
+	.led_pin = -1,
+};
+static struct ath9k_platform_data pci_scan_wifi_data = {
+	.led_pin = -1,
+};
+
+static int mr18_dual_pci_plat_dev_init(struct pci_dev *dev)
+{
+	/* The PCIE devices are attached to different busses but they
+	 * both share the same slot number. Checking the PCI_SLOT vals
+	 * does not work.
+	 */
+	switch (dev->bus->number) {
+	case 0:
+		dev->dev.platform_data = &pci_main_wifi_data;
+		break;
+	case 1:
+		dev->dev.platform_data = &pci_scan_wifi_data;
+		break;
+	}
+
+	return 0;
+}
+
+static void __init mr18_setup(void)
+{
+	int res;
+
+	/* NAND */
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_SOFT_BCH);
+	ath79_register_nfc();
+
+	/* even though, the PHY is connected via RGMII,
+	 * the SGMII/SERDES PLLs need to be calibrated and locked.
+	 * Or else, the PHY won't be working for this platfrom.
+	 *
+	 * Figuring this out took such a long time, that we want to
+	 * point this quirk out, before someone wants to remove it.
+	 */
+	res = mr18_extract_sgmii_res_cal();
+	if (res >= 0) {
+		/* Setup SoC Eth Config */
+		ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN |
+			(3 << QCA955X_ETH_CFG_RXD_DELAY_SHIFT) |
+			(3 << QCA955X_ETH_CFG_RDV_DELAY_SHIFT));
+
+		/* MDIO Interface */
+		ath79_register_mdio(0, 0x0);
+
+		mr18_setup_qca955x_eth_serdes_cal(res);
+
+		/* GMAC0 is connected to an Atheros AR8035-A */
+		ath79_init_mac(ath79_eth0_data.mac_addr, NULL, 0);
+		ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+		ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+		ath79_eth0_data.phy_mask = BIT(MR18_WAN_PHYADDR);
+		ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+		ath79_eth0_pll_data.pll_100 = 0xa0000101;
+		ath79_eth0_pll_data.pll_10 = 0x80001313;
+		ath79_register_eth(0);
+	} else {
+		printk(KERN_ERR "failed to read EFUSE for ethernet cal\n");
+	}
+
+	/* LEDs and Buttons */
+	platform_device_register(&tricolor_leds);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(MR18_leds_gpio),
+				 MR18_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MR18_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(MR18_gpio_keys),
+					MR18_gpio_keys);
+
+	/* Clear RTC reset (Needed by SoC WiFi) */
+	ath79_device_reset_clear(QCA955X_RESET_RTC);
+
+	/* WiFi */
+	ath79_register_wmac_simple();
+
+	pci_main_wifi_data.eeprom_name = "pci_wmac0.eeprom";
+	pci_scan_wifi_data.eeprom_name = "pci_wmac1.eeprom";
+	ath79_pci_set_plat_dev_init(mr18_dual_pci_plat_dev_init);
+	ath79_register_pci();
+}
+MIPS_MACHINE(ATH79_MACH_MR18, "MR18", "Meraki MR18", mr18_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr600.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr600.c
new file mode 100644
index 0000000000..701330cebd
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr600.c
@@ -0,0 +1,177 @@
+/*
+ * OpenMesh OM2P board support
+ *
+ * Copyright (C) 2012 Marek Lindner <marek@open-mesh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define MR600_GPIO_LED_WLAN58		12
+#define MR600_GPIO_LED_WPS			13
+#define MR600_GPIO_LED_POWER			14
+
+#define MR600V2_GPIO_LED_WLAN58_RED		12
+#define MR600V2_GPIO_LED_WPS			13
+#define MR600V2_GPIO_LED_POWER			14
+#define MR600V2_GPIO_LED_WLAN24_GREEN		18
+#define MR600V2_GPIO_LED_WLAN24_YELLOW		19
+#define MR600V2_GPIO_LED_WLAN24_RED		20
+#define MR600V2_GPIO_LED_WLAN58_GREEN		21
+#define MR600V2_GPIO_LED_WLAN58_YELLOW		22
+
+#define MR600_GPIO_BTN_RESET		17
+
+#define MR600_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MR600_KEYS_DEBOUNCE_INTERVAL (3 * MR600_KEYS_POLL_INTERVAL)
+
+#define MR600_MAC_OFFSET		0
+#define MR600_WMAC_CALDATA_OFFSET	0x1000
+#define MR600_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led mr600_leds_gpio[] __initdata = {
+	{
+		.name		= "mr600:orange:power",
+		.gpio		= MR600_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:blue:wps",
+		.gpio		= MR600_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:green:wlan58",
+		.gpio		= MR600_GPIO_LED_WLAN58,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led mr600v2_leds_gpio[] __initdata = {
+	{
+		.name		= "mr600:blue:power",
+		.gpio		= MR600V2_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:blue:wps",
+		.gpio		= MR600V2_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:red:wlan24",
+		.gpio		= MR600V2_GPIO_LED_WLAN24_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:yellow:wlan24",
+		.gpio		= MR600V2_GPIO_LED_WLAN24_YELLOW,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:green:wlan24",
+		.gpio		= MR600V2_GPIO_LED_WLAN24_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:red:wlan58",
+		.gpio		= MR600V2_GPIO_LED_WLAN58_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:yellow:wlan58",
+		.gpio		= MR600V2_GPIO_LED_WLAN58_YELLOW,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr600:green:wlan58",
+		.gpio		= MR600V2_GPIO_LED_WLAN58_GREEN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mr600_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MR600_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MR600_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init mr600_base_setup(unsigned num_leds, struct gpio_led *leds)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, num_leds, leds);
+	ath79_register_gpio_keys_polled(-1, MR600_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mr600_gpio_keys),
+					mr600_gpio_keys);
+
+	ath79_init_mac(mac, art + MR600_MAC_OFFSET, 1);
+	ath79_register_wmac(art + MR600_WMAC_CALDATA_OFFSET, mac);
+
+	ath79_init_mac(mac, art + MR600_MAC_OFFSET, 8);
+	ap91_pci_init(art + MR600_PCIE_CALDATA_OFFSET, mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + MR600_MAC_OFFSET, 0);
+
+	/* GMAC0 is connected to an external PHY */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+static void __init mr600_setup(void)
+{
+	mr600_base_setup(ARRAY_SIZE(mr600_leds_gpio), mr600_leds_gpio);
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+}
+
+MIPS_MACHINE(ATH79_MACH_MR600, "MR600", "OpenMesh MR600", mr600_setup);
+
+static void __init mr600v2_setup(void)
+{
+	mr600_base_setup(ARRAY_SIZE(mr600v2_leds_gpio), mr600v2_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_MR600V2, "MR600v2", "OpenMesh MR600v2", mr600v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mr900.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr900.c
new file mode 100644
index 0000000000..b439f58892
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mr900.c
@@ -0,0 +1,181 @@
+/*
+ * MR900 board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Marek Lindner <marek@open-mesh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define MR900_GPIO_LED_LAN		12
+#define MR900_GPIO_LED_WLAN_2G		13
+#define MR900_GPIO_LED_STATUS_GREEN	19
+#define MR900_GPIO_LED_STATUS_RED	21
+#define MR900_GPIO_LED_POWER		22
+#define MR900_GPIO_LED_WLAN_5G		23
+
+#define MR900_GPIO_BTN_RESET		17
+
+#define MR900_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MR900_KEYS_DEBOUNCE_INTERVAL	(3 * MR900_KEYS_POLL_INTERVAL)
+
+#define MR900_MAC0_OFFSET		0
+#define MR900_WMAC_CALDATA_OFFSET	0x1000
+#define MR900_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led mr900_leds_gpio[] __initdata = {
+	{
+		.name		= "mr900:blue:power",
+		.gpio		= MR900_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr900:blue:wan",
+		.gpio		= MR900_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr900:blue:wlan24",
+		.gpio		= MR900_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr900:blue:wlan58",
+		.gpio		= MR900_GPIO_LED_WLAN_5G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr900:green:status",
+		.gpio		= MR900_GPIO_LED_STATUS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "mr900:red:status",
+		.gpio		= MR900_GPIO_LED_STATUS_RED,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mr900_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MR900_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MR900_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct at803x_platform_data mr900_at803x_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 0,
+	.fixup_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info mr900_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 5,
+		.platform_data = &mr900_at803x_data,
+	},
+};
+
+static void __init mr900_setup_qca955x_eth_cfg(u32 mask,
+					       unsigned int rxd,
+					       unsigned int rxdv,
+					       unsigned int txd,
+					       unsigned int txe)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+	t = mask;
+	t |= rxd << QCA955X_ETH_CFG_RXD_DELAY_SHIFT;
+	t |= rxdv << QCA955X_ETH_CFG_RDV_DELAY_SHIFT;
+	t |= txd << QCA955X_ETH_CFG_TXD_DELAY_SHIFT;
+	t |= txe << QCA955X_ETH_CFG_TXE_DELAY_SHIFT;
+
+	__raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+static void __init mr900_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6], pcie_mac[6];
+	struct ath9k_platform_data *pdata;
+
+	ath79_eth0_pll_data.pll_1000 = 0xae000000;
+	ath79_eth0_pll_data.pll_100 = 0xa0000101;
+	ath79_eth0_pll_data.pll_10 = 0xa0001313;
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mr900_leds_gpio),
+				 mr900_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MR900_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mr900_gpio_keys),
+					mr900_gpio_keys);
+
+	ath79_init_mac(mac, art + MR900_MAC0_OFFSET, 1);
+	ath79_register_wmac(art + MR900_WMAC_CALDATA_OFFSET, mac);
+	ath79_init_mac(pcie_mac, art + MR900_MAC0_OFFSET, 16);
+	ap91_pci_init(art + MR900_PCIE_CALDATA_OFFSET, pcie_mac);
+	pdata = ap9x_pci_get_wmac_data(0);
+	if (!pdata) {
+		pr_err("mr900: unable to get address of wlan data\n");
+		return;
+	}
+	pdata->use_eeprom = true;
+
+	mr900_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN, 3, 3, 0, 0);
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(mr900_mdio0_info,
+				    ARRAY_SIZE(mr900_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + MR900_MAC0_OFFSET, 0);
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(5);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_MR900, "MR900", "OpenMesh MR900", mr900_setup);
+MIPS_MACHINE(ATH79_MACH_MR900v2, "MR900v2", "OpenMesh MR900v2", mr900_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n600.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n600.c
new file mode 100644
index 0000000000..a87413d201
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n600.c
@@ -0,0 +1,202 @@
+/*
+ *  WD My Net N600 board support
+ *
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define MYNET_N600_GPIO_LED_WIFI	0
+#define MYNET_N600_GPIO_LED_POWER	11
+#define MYNET_N600_GPIO_LED_INTERNET	12
+#define MYNET_N600_GPIO_LED_WPS		13
+
+#define MYNET_N600_GPIO_LED_LAN1	4
+#define MYNET_N600_GPIO_LED_LAN2	3
+#define MYNET_N600_GPIO_LED_LAN3	2
+#define MYNET_N600_GPIO_LED_LAN4	1
+
+#define MYNET_N600_GPIO_BTN_RESET	16
+#define MYNET_N600_GPIO_BTN_WPS		17
+
+#define MYNET_N600_GPIO_EXTERNAL_LNA0	14
+#define MYNET_N600_GPIO_EXTERNAL_LNA1	15
+
+#define MYNET_N600_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MYNET_N600_KEYS_DEBOUNCE_INTERVAL (3 * MYNET_N600_KEYS_POLL_INTERVAL)
+
+#define MYNET_N600_MAC0_OFFSET		0
+#define MYNET_N600_MAC1_OFFSET		6
+#define MYNET_N600_WMAC_CALDATA_OFFSET	0x1000
+#define MYNET_N600_PCIE_CALDATA_OFFSET	0x5000
+
+#define MYNET_N600_NVRAM_ADDR		0x1f058010
+#define MYNET_N600_NVRAM_SIZE		0x7ff0
+
+static struct gpio_led mynet_n600_leds_gpio[] __initdata = {
+	{
+		.name		= "wd:blue:power",
+		.gpio		= MYNET_N600_GPIO_LED_POWER,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:wps",
+		.gpio		= MYNET_N600_GPIO_LED_WPS,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:wireless",
+		.gpio		= MYNET_N600_GPIO_LED_WIFI,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:internet",
+		.gpio		= MYNET_N600_GPIO_LED_INTERNET,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:green:lan1",
+		.gpio		= MYNET_N600_GPIO_LED_LAN1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:green:lan2",
+		.gpio		= MYNET_N600_GPIO_LED_LAN2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:green:lan3",
+		.gpio		= MYNET_N600_GPIO_LED_LAN3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:green:lan4",
+		.gpio		= MYNET_N600_GPIO_LED_LAN4,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mynet_n600_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MYNET_N600_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MYNET_N600_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = MYNET_N600_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MYNET_N600_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static void mynet_n600_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(MYNET_N600_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, MYNET_N600_NVRAM_SIZE,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+#define MYNET_N600_WAN_PHY_MASK	BIT(0)
+
+static void __init mynet_n600_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_gpio_output_select(MYNET_N600_GPIO_LED_LAN1,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_N600_GPIO_LED_LAN2,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_N600_GPIO_LED_LAN3,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_N600_GPIO_LED_LAN4,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_N600_GPIO_LED_INTERNET,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mynet_n600_leds_gpio),
+				 mynet_n600_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, MYNET_N600_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mynet_n600_gpio_keys),
+					mynet_n600_gpio_keys);
+
+	/*
+	 * Control signal for external LNAs 0 and 1
+	 * Taken from GPL bootloader source:
+	 *   board/ar7240/db12x/alpha_gpio.c
+	 */
+	ath79_wmac_set_ext_lna_gpio(0, MYNET_N600_GPIO_EXTERNAL_LNA0);
+	ath79_wmac_set_ext_lna_gpio(1, MYNET_N600_GPIO_EXTERNAL_LNA1);
+
+	mynet_n600_get_mac("wlan24mac=", tmpmac);
+	ath79_register_wmac(art + MYNET_N600_WMAC_CALDATA_OFFSET, tmpmac);
+
+	mynet_n600_get_mac("wlan5mac=", tmpmac);
+	ap91_pci_init(art + MYNET_N600_PCIE_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE |
+				   AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* LAN */
+	mynet_n600_get_mac("lanmac=", ath79_eth1_data.mac_addr);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(1);
+
+	/* WAN */
+	mynet_n600_get_mac("wanmac=", ath79_eth0_data.mac_addr);
+
+	/* GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = MYNET_N600_WAN_PHY_MASK;
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = MYNET_N600_WAN_PHY_MASK;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_MYNET_N600, "MYNET-N600", "WD My Net N600",
+	     mynet_n600_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n750.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n750.c
new file mode 100644
index 0000000000..9d69dc53fc
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-n750.c
@@ -0,0 +1,226 @@
+/*
+ *  WD My Net N750 board support
+ *
+ *  Copyright (C) 2013 Felix Kaechele <felix@fetzig.org>
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+
+/*
+ * Taken from GPL bootloader source:
+ *   board/ar7240/db12x/alpha_gpio.c
+ */
+#define MYNET_N750_GPIO_LED_WIFI	11
+#define MYNET_N750_GPIO_LED_INTERNET	12
+#define MYNET_N750_GPIO_LED_WPS		13
+#define MYNET_N750_GPIO_LED_POWER	14
+
+#define MYNET_N750_GPIO_BTN_RESET	17
+#define MYNET_N750_GPIO_BTN_WPS		19
+
+#define MYNET_N750_GPIO_EXTERNAL_LNA0	15
+#define MYNET_N750_GPIO_EXTERNAL_LNA1	18
+
+#define MYNET_N750_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MYNET_N750_KEYS_DEBOUNCE_INTERVAL (3 * MYNET_N750_KEYS_POLL_INTERVAL)
+
+#define MYNET_N750_WMAC_CALDATA_OFFSET	0x1000
+#define MYNET_N750_PCIE_CALDATA_OFFSET	0x5000
+
+#define MYNET_N750_NVRAM_ADDR		0x1f058010
+#define MYNET_N750_NVRAM_SIZE		0x7ff0
+
+static struct gpio_led mynet_n750_leds_gpio[] __initdata = {
+	{
+		.name		= "wd:blue:power",
+		.gpio		= MYNET_N750_GPIO_LED_POWER,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:wps",
+		.gpio		= MYNET_N750_GPIO_LED_WPS,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:wireless",
+		.gpio		= MYNET_N750_GPIO_LED_WIFI,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:internet",
+		.gpio		= MYNET_N750_GPIO_LED_INTERNET,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button mynet_n750_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MYNET_N750_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MYNET_N750_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = MYNET_N750_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MYNET_N750_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static const struct ar8327_led_info mynet_n750_leds_ar8327[] __initconst = {
+	AR8327_LED_INFO(PHY0_0, HW, "wd:green:lan1"),
+	AR8327_LED_INFO(PHY1_0, HW, "wd:green:lan2"),
+	AR8327_LED_INFO(PHY2_0, HW, "wd:green:lan3"),
+	AR8327_LED_INFO(PHY3_0, HW, "wd:green:lan4"),
+	AR8327_LED_INFO(PHY4_0, HW, "wd:green:wan"),
+	AR8327_LED_INFO(PHY0_1, HW, "wd:yellow:lan1"),
+	AR8327_LED_INFO(PHY1_1, HW, "wd:yellow:lan2"),
+	AR8327_LED_INFO(PHY2_1, HW, "wd:yellow:lan3"),
+	AR8327_LED_INFO(PHY3_1, HW, "wd:yellow:lan4"),
+	AR8327_LED_INFO(PHY4_1, HW, "wd:yellow:wan"),
+};
+
+static struct ar8327_pad_cfg mynet_n750_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg mynet_n750_ar8327_led_cfg = {
+	.led_ctrl0 = 0xcc35cc35,
+	.led_ctrl1 = 0xca35ca35,
+	.led_ctrl2 = 0xc935c935,
+	.led_ctrl3 = 0x03ffff00,
+	.open_drain = false,
+};
+
+static struct ar8327_platform_data mynet_n750_ar8327_data = {
+	.pad0_cfg = &mynet_n750_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &mynet_n750_ar8327_led_cfg,
+	.num_leds = ARRAY_SIZE(mynet_n750_leds_ar8327),
+	.leds = mynet_n750_leds_ar8327,
+};
+
+static struct mdio_board_info mynet_n750_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &mynet_n750_ar8327_data,
+	},
+};
+
+static void mynet_n750_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(MYNET_N750_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, MYNET_N750_NVRAM_SIZE,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+/*
+ * The bootloader on this board powers down all PHYs on the switch
+ * before booting the kernel. We bring all PHYs back up so that they are
+ * discoverable by the mdio bus scan and the switch is detected
+ * correctly.
+ */
+static void mynet_n750_mdio_fixup(struct mii_bus *bus)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		bus->write(bus, i, MII_BMCR,
+			   (BMCR_RESET | BMCR_ANENABLE | BMCR_SPEED1000));
+
+	mdelay(1000);
+}
+
+static void __init mynet_n750_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mynet_n750_leds_gpio),
+				 mynet_n750_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, MYNET_N750_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mynet_n750_gpio_keys),
+					mynet_n750_gpio_keys);
+	/*
+	 * Control signal for external LNAs 0 and 1
+	 * Taken from GPL bootloader source:
+	 *   board/ar7240/db12x/alpha_gpio.c
+	 */
+	ath79_wmac_set_ext_lna_gpio(0, MYNET_N750_GPIO_EXTERNAL_LNA0);
+	ath79_wmac_set_ext_lna_gpio(1, MYNET_N750_GPIO_EXTERNAL_LNA1);
+
+	mynet_n750_get_mac("wlan24mac=", tmpmac);
+	ath79_register_wmac(art + MYNET_N750_WMAC_CALDATA_OFFSET, tmpmac);
+
+	mynet_n750_get_mac("wlan5mac=", tmpmac);
+	ap91_pci_init(art + MYNET_N750_PCIE_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	mdiobus_register_board_info(mynet_n750_mdio0_info,
+				    ARRAY_SIZE(mynet_n750_mdio0_info));
+
+	ath79_mdio0_data.reset = mynet_n750_mdio_fixup;
+	ath79_register_mdio(0, 0x0);
+
+	mynet_n750_get_mac("lanmac=", ath79_eth0_data.mac_addr);
+
+	/* GMAC0 is connected to an AR8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_MYNET_N750, "MYNET-N750", "WD My Net N750",
+	     mynet_n750_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-rext.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-rext.c
new file mode 100644
index 0000000000..3d48ca8fa5
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mynet-rext.c
@@ -0,0 +1,208 @@
+/*
+ *  WD My Net WI-FI Range Extender (Codename:Starfish db12x) board support
+ *
+ *  Copyright (C) 2013 Christian Lamparter <chunkeey@googlemail.com>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define MYNET_REXT_GPIO_LED_POWER	11
+#define MYNET_REXT_GPIO_LED_ETHERNET	12
+#define MYNET_REXT_GPIO_LED_WIFI	19
+
+#define MYNET_REXT_GPIO_LED_RF_QTY1	20
+#define MYNET_REXT_GPIO_LED_RF_QTY2	21
+#define MYNET_REXT_GPIO_LED_RF_QTY3	22
+
+#define MYNET_REXT_GPIO_BTN_RESET	13
+#define MYNET_REXT_GPIO_BTN_WPS		15
+#define MYNET_REXT_GPIO_SW_RF		14
+
+#define MYNET_REXT_GPIO_PHY_SWRST	16	/* disables Ethernet PHY */
+#define MYNET_REXT_GPIO_PHY_INT		17
+#define MYNET_REXT_GPIO_18		18
+
+#define MYNET_REXT_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MYNET_REXT_KEYS_DEBOUNCE_INTERVAL (3 * MYNET_REXT_KEYS_POLL_INTERVAL)
+
+#define MYNET_REXT_WMAC_CALDATA_OFFSET	0x1000
+
+#define MYNET_REXT_NVRAM_ADDR		0x1f7e0010
+#define MYNET_REXT_NVRAM_SIZE		0xfff0
+
+#define MYNET_REXT_ART_ADDR		0x1f7f0000
+
+static const char *mynet_rext_part_probes[] = {
+	"cybertan",
+	NULL,
+};
+
+static struct flash_platform_data mynet_rext_flash_data = {
+	.type		= "s25fl064k",
+	.part_probes	= mynet_rext_part_probes,
+};
+
+static struct gpio_led mynet_rext_leds_gpio[] __initdata = {
+	{
+		.name		= "wd:blue:power",
+		.gpio		= MYNET_REXT_GPIO_LED_POWER,
+		.active_low	= 0,
+	},
+	{
+		.name		= "wd:blue:wireless",
+		.gpio		= MYNET_REXT_GPIO_LED_WIFI,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:blue:ethernet",
+		.gpio		= MYNET_REXT_GPIO_LED_ETHERNET,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:blue:quality1",
+		.gpio		= MYNET_REXT_GPIO_LED_RF_QTY1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:blue:quality2",
+		.gpio		= MYNET_REXT_GPIO_LED_RF_QTY2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wd:blue:quality3",
+		.gpio		= MYNET_REXT_GPIO_LED_RF_QTY3,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button mynet_rext_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MYNET_REXT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MYNET_REXT_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = MYNET_REXT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MYNET_REXT_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc           = "RF Band switch",
+		.type           = EV_SW,
+		.code           = BTN_1,
+		.debounce_interval = MYNET_REXT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio           = MYNET_REXT_GPIO_SW_RF,
+	},
+};
+
+static struct at803x_platform_data mynet_rext_at803x_data = {
+	.disable_smarteee = 0,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 0,
+	.fixup_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info mynet_rext_mdio0_info[] = {
+        {
+                .bus_id = "ag71xx-mdio.0",
+                .phy_addr = 4,
+                .platform_data = &mynet_rext_at803x_data,
+        },
+};
+
+static void mynet_rext_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(MYNET_REXT_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, MYNET_REXT_NVRAM_SIZE,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+static void __init mynet_rext_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(MYNET_REXT_ART_ADDR);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&mynet_rext_flash_data);
+
+	/* GPIO configuration from drivers/char/GPIO8.c */
+
+	ath79_gpio_output_select(MYNET_REXT_GPIO_LED_POWER,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_REXT_GPIO_LED_WIFI,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_REXT_GPIO_LED_RF_QTY1,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_REXT_GPIO_LED_RF_QTY2,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_REXT_GPIO_LED_RF_QTY3,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(MYNET_REXT_GPIO_LED_ETHERNET,
+				 AR934X_GPIO_OUT_GPIO);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mynet_rext_leds_gpio),
+				 mynet_rext_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, MYNET_REXT_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mynet_rext_gpio_keys),
+					mynet_rext_gpio_keys);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_RXD_DELAY |
+				   AR934X_ETH_CFG_RDV_DELAY);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(mynet_rext_mdio0_info,
+				    ARRAY_SIZE(mynet_rext_mdio0_info));
+
+	/* LAN */
+	mynet_rext_get_mac("et0macaddr=", ath79_eth0_data.mac_addr);
+
+	/* GMAC0 is connected to an external PHY on Port 4 */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_pll_data.pll_10   = 0x00001313; /* athrs_mac.c */
+	ath79_eth0_pll_data.pll_1000 = 0x0e000000; /* athrs_mac.c */
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_register_eth(0);
+
+	/* WLAN */
+	mynet_rext_get_mac("wl0_hwaddr=", tmpmac);
+	ap91_pci_init(art + MYNET_REXT_WMAC_CALDATA_OFFSET, tmpmac);
+}
+
+MIPS_MACHINE(ATH79_MACH_MYNET_REXT, "MYNET-REXT",
+	     "WD My Net Wi-Fi Range Extender", mynet_rext_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w04nu.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w04nu.c
new file mode 100644
index 0000000000..c2460ce33c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w04nu.c
@@ -0,0 +1,124 @@
+/*
+ *  Planex MZK-W04NU board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define MZK_W04NU_GPIO_LED_USB		0
+#define MZK_W04NU_GPIO_LED_STATUS	1
+#define MZK_W04NU_GPIO_LED_WPS		3
+#define MZK_W04NU_GPIO_LED_WLAN		6
+#define MZK_W04NU_GPIO_LED_AP		15
+#define MZK_W04NU_GPIO_LED_ROUTER	16
+
+#define MZK_W04NU_GPIO_BTN_APROUTER	5
+#define MZK_W04NU_GPIO_BTN_WPS		12
+#define MZK_W04NU_GPIO_BTN_RESET	21
+
+#define MZK_W04NU_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MZK_W04NU_KEYS_DEBOUNCE_INTERVAL (3 * MZK_W04NU_KEYS_POLL_INTERVAL)
+
+static struct gpio_led mzk_w04nu_leds_gpio[] __initdata = {
+	{
+		.name		= "planex:green:status",
+		.gpio		= MZK_W04NU_GPIO_LED_STATUS,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:blue:wps",
+		.gpio		= MZK_W04NU_GPIO_LED_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:green:wlan",
+		.gpio		= MZK_W04NU_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:green:usb",
+		.gpio		= MZK_W04NU_GPIO_LED_USB,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:green:ap",
+		.gpio		= MZK_W04NU_GPIO_LED_AP,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:green:router",
+		.gpio		= MZK_W04NU_GPIO_LED_ROUTER,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button mzk_w04nu_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MZK_W04NU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MZK_W04NU_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = MZK_W04NU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MZK_W04NU_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}, {
+		.desc		= "aprouter",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = MZK_W04NU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MZK_W04NU_GPIO_BTN_APROUTER,
+		.active_low	= 0,
+	}
+};
+
+#define MZK_W04NU_WAN_PHYMASK	BIT(4)
+#define MZK_W04NU_MDIO_MASK	(~MZK_W04NU_WAN_PHYMASK)
+
+static void __init mzk_w04nu_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_mdio(0, MZK_W04NU_MDIO_MASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, eeprom, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.has_ar8216 = 1;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, eeprom, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = MZK_W04NU_WAN_PHYMASK;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mzk_w04nu_leds_gpio),
+				 mzk_w04nu_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, MZK_W04NU_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mzk_w04nu_gpio_keys),
+					mzk_w04nu_gpio_keys);
+	ath79_register_usb();
+
+	ath79_register_wmac(eeprom, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_MZK_W04NU, "MZK-W04NU", "Planex MZK-W04NU",
+	     mzk_w04nu_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w300nh.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w300nh.c
new file mode 100644
index 0000000000..8c40365283
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-mzk-w300nh.c
@@ -0,0 +1,115 @@
+/*
+ *  Planex MZK-W300NH board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.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 MZK_W300NH_GPIO_LED_STATUS	1
+#define MZK_W300NH_GPIO_LED_WPS		3
+#define MZK_W300NH_GPIO_LED_WLAN	6
+#define MZK_W300NH_GPIO_LED_AP_GREEN	15
+#define MZK_W300NH_GPIO_LED_AP_AMBER	16
+
+#define MZK_W300NH_GPIO_BTN_APROUTER	5
+#define MZK_W300NH_GPIO_BTN_WPS		12
+#define MZK_W300NH_GPIO_BTN_RESET	21
+
+#define MZK_W300NH_KEYS_POLL_INTERVAL	20	/* msecs */
+#define MZK_W300NH_KEYS_DEBOUNCE_INTERVAL (3 * MZK_W300NH_KEYS_POLL_INTERVAL)
+
+static struct gpio_led mzk_w300nh_leds_gpio[] __initdata = {
+	{
+		.name		= "planex:green:status",
+		.gpio		= MZK_W300NH_GPIO_LED_STATUS,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:blue:wps",
+		.gpio		= MZK_W300NH_GPIO_LED_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:green:wlan",
+		.gpio		= MZK_W300NH_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "planex:green:aprouter",
+		.gpio		= MZK_W300NH_GPIO_LED_AP_GREEN,
+	}, {
+		.name		= "planex:amber:aprouter",
+		.gpio		= MZK_W300NH_GPIO_LED_AP_AMBER,
+	}
+};
+
+static struct gpio_keys_button mzk_w300nh_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = MZK_W300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MZK_W300NH_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = MZK_W300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MZK_W300NH_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}, {
+		.desc		= "aprouter",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = MZK_W300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= MZK_W300NH_GPIO_BTN_APROUTER,
+		.active_low	= 0,
+	}
+};
+
+#define MZK_W300NH_WAN_PHYMASK	BIT(4)
+#define MZK_W300NH_MDIO_MASK	(~MZK_W300NH_WAN_PHYMASK)
+
+static void __init mzk_w300nh_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_mdio(0, MZK_W300NH_MDIO_MASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, eeprom, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.has_ar8216 = 1;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, eeprom, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = MZK_W300NH_WAN_PHYMASK;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(mzk_w300nh_leds_gpio),
+				 mzk_w300nh_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, MZK_W300NH_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(mzk_w300nh_gpio_keys),
+					mzk_w300nh_gpio_keys);
+	ath79_register_wmac(eeprom, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_MZK_W300NH, "MZK-W300NH", "Planex MZK-W300NH",
+	     mzk_w300nh_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-nbg460n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-nbg460n.c
new file mode 100644
index 0000000000..ca007779ec
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-nbg460n.c
@@ -0,0 +1,220 @@
+/*
+ *  Zyxel NBG 460N/550N/550NH board support
+ *
+ *  Copyright (C) 2010 Michael Kurz <michi.kurz@googlemail.com>
+ *
+ *  based on mach-tl-wr1043nd.c
+ *
+ *  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/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/rtl8366.h>
+
+#include <asm/mach-ath79/ath79.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"
+
+/* LEDs */
+#define NBG460N_GPIO_LED_WPS		3
+#define NBG460N_GPIO_LED_WAN		6
+#define NBG460N_GPIO_LED_POWER		14
+#define NBG460N_GPIO_LED_WLAN		15
+
+/* Buttons */
+#define NBG460N_GPIO_BTN_WPS		12
+#define NBG460N_GPIO_BTN_RESET		21
+
+#define NBG460N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define NBG460N_KEYS_DEBOUNCE_INTERVAL	(3 * NBG460N_KEYS_POLL_INTERVAL)
+
+/* RTC chip PCF8563 I2C interface */
+#define NBG460N_GPIO_PCF8563_SDA	8
+#define NBG460N_GPIO_PCF8563_SCK	7
+
+/* Switch configuration I2C interface */
+#define NBG460N_GPIO_RTL8366_SDA	16
+#define NBG460N_GPIO_RTL8366_SCK	18
+
+static struct mtd_partition nbg460n_partitions[] = {
+	{
+		.name		= "Bootbase",
+		.offset		= 0,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "U-Boot Config",
+		.offset		= 0x010000,
+		.size		= 0x030000,
+	}, {
+		.name		= "U-Boot",
+		.offset		= 0x040000,
+		.size		= 0x030000,
+	}, {
+		.name		= "linux",
+		.offset		= 0x070000,
+		.size		= 0x0e0000,
+	}, {
+		.name		= "rootfs",
+		.offset		= 0x150000,
+		.size		= 0x2a0000,
+	}, {
+		.name		= "CalibData",
+		.offset		= 0x3f0000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x070000,
+		.size		= 0x380000,
+	}
+};
+
+static struct flash_platform_data nbg460n_flash_data = {
+	.parts		= nbg460n_partitions,
+	.nr_parts       = ARRAY_SIZE(nbg460n_partitions),
+};
+
+static struct gpio_led nbg460n_leds_gpio[] __initdata = {
+	{
+		.name		= "nbg460n:green:power",
+		.gpio		= NBG460N_GPIO_LED_POWER,
+		.active_low	= 0,
+		.default_trigger = "default-on",
+	}, {
+		.name		= "nbg460n:green:wps",
+		.gpio		= NBG460N_GPIO_LED_WPS,
+		.active_low	= 0,
+	}, {
+		.name		= "nbg460n:green:wlan",
+		.gpio		= NBG460N_GPIO_LED_WLAN,
+		.active_low	= 0,
+	}, {
+		/* Not really for controlling the LED,
+		   when set low the LED blinks uncontrollable  */
+		.name		= "nbg460n:green:wan",
+		.gpio		= NBG460N_GPIO_LED_WAN,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button nbg460n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = NBG460N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG460N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = NBG460N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG460N_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct i2c_gpio_platform_data nbg460n_i2c_device_platdata = {
+	.sda_pin	= NBG460N_GPIO_PCF8563_SDA,
+	.scl_pin	= NBG460N_GPIO_PCF8563_SCK,
+	.udelay		= 10,
+};
+
+static struct platform_device nbg460n_i2c_device = {
+	.name		= "i2c-gpio",
+	.id		= -1,
+	.num_resources	= 0,
+	.resource	= NULL,
+	.dev		= {
+		.platform_data	= &nbg460n_i2c_device_platdata,
+	},
+};
+
+static struct i2c_board_info nbg460n_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("pcf8563", 0x51),
+	},
+};
+
+static void nbg460n_i2c_init(void)
+{
+	/* The gpio interface */
+	platform_device_register(&nbg460n_i2c_device);
+	/* I2C devices */
+	i2c_register_board_info(0, nbg460n_i2c_devs,
+				ARRAY_SIZE(nbg460n_i2c_devs));
+}
+
+
+static struct rtl8366_platform_data nbg460n_rtl8366s_data = {
+	.gpio_sda	= NBG460N_GPIO_RTL8366_SDA,
+	.gpio_sck	= NBG460N_GPIO_RTL8366_SCK,
+};
+
+static struct platform_device nbg460n_rtl8366s_device = {
+	.name		= RTL8366S_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &nbg460n_rtl8366s_data,
+	}
+};
+
+static void __init nbg460n_setup(void)
+{
+	/* end of bootloader sector contains mac address */
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fc0fff8);
+	/* last sector contains wlan calib data */
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* LAN Port */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	/* WAN Port */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+	ath79_eth1_data.mii_bus_dev = &nbg460n_rtl8366s_device.dev;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	/* register the switch phy */
+	platform_device_register(&nbg460n_rtl8366s_device);
+
+	/* register flash */
+	ath79_register_m25p80(&nbg460n_flash_data);
+
+	ath79_register_wmac(eeprom, mac);
+
+	/* register RTC chip */
+	nbg460n_i2c_init();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(nbg460n_leds_gpio),
+				 nbg460n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, NBG460N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(nbg460n_gpio_keys),
+					nbg460n_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_NBG460N, "NBG460N", "Zyxel NBG460N/550N/550NH",
+	     nbg460n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-nbg6716.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-nbg6716.c
new file mode 100644
index 0000000000..c28a8a5118
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-nbg6716.c
@@ -0,0 +1,380 @@
+/*
+ * ZyXEL NBG6716/NBG6616 board support
+ *
+ * Based on the Qualcomm Atheros AP135/AP136 reference board support code
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2013 Andre Valentin <avalentin@marcant.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+#include <linux/gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/platform/ar934x_nfc.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define NBG6716_GPIO_LED_INTERNET	18
+#define NBG6716_GPIO_LED_POWER		15
+#define NBG6716_GPIO_LED_USB1		4
+#define NBG6716_GPIO_LED_USB2		13
+#define NBG6716_GPIO_LED_WIFI2G		19
+#define NBG6716_GPIO_LED_WIFI5G		17
+#define NBG6716_GPIO_LED_WPS		21
+
+#define NBG6716_GPIO_BTN_RESET		23
+#define NBG6716_GPIO_BTN_RFKILL		1
+#define NBG6716_GPIO_BTN_USB1		0
+#define NBG6716_GPIO_BTN_USB2		14
+#define NBG6716_GPIO_BTN_WPS		22
+
+#define NBG6716_GPIO_USB_POWER		16
+
+#define NBG6716_KEYS_POLL_INTERVAL	20	/* msecs */
+#define NBG6716_KEYS_DEBOUNCE_INTERVAL	(3 * NBG6716_KEYS_POLL_INTERVAL)
+
+#define NBG6716_MAC0_OFFSET		0
+#define NBG6716_MAC1_OFFSET		6
+#define NBG6716_WMAC_CALDATA_OFFSET	0x1000
+#define NBG6716_PCIE_CALDATA_OFFSET	0x5000
+
+/* NBG6616 has a different GPIO usage as it does not have USB Buttons */
+#define NBG6616_GPIO_LED_USB0		14
+#define NBG6616_GPIO_LED_USB1		21
+#define NBG6616_GPIO_LED_WPS		0
+
+static struct gpio_led nbg6716_leds_gpio[] __initdata = {
+	{
+		.name		= "nbg6716:white:internet",
+		.gpio		= NBG6716_GPIO_LED_INTERNET,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6716:white:power",
+		.gpio		= NBG6716_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6716:white:usb1",
+		.gpio		= NBG6716_GPIO_LED_USB1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6716:white:usb2",
+		.gpio		= NBG6716_GPIO_LED_USB2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6716:white:wifi2g",
+		.gpio		= NBG6716_GPIO_LED_WIFI2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6716:white:wifi5g",
+		.gpio		= NBG6716_GPIO_LED_WIFI5G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6716:white:wps",
+		.gpio		= NBG6716_GPIO_LED_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button nbg6716_gpio_keys[] __initdata = {
+	{
+		.desc		= "RESET button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL button",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_RFKILL,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "USB1 eject button",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_USB1,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "USB2 eject button",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_USB2,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+
+
+static struct gpio_led nbg6616_leds_gpio[] __initdata = {
+	{
+		.name		= "nbg6616:green:power",
+		.gpio		= NBG6716_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6616:green:usb2",
+		.gpio		= NBG6616_GPIO_LED_USB0,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6616:green:usb1",
+		.gpio		= NBG6616_GPIO_LED_USB1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6616:green:wifi2g",
+		.gpio		= NBG6716_GPIO_LED_WIFI2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6616:green:wifi5g",
+		.gpio		= NBG6716_GPIO_LED_WIFI5G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "nbg6616:green:wps",
+		.gpio		= NBG6616_GPIO_LED_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button nbg6616_gpio_keys[] __initdata = {
+	{
+		.desc		= "RESET button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_RFKILL,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = NBG6716_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= NBG6716_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+
+static struct ar8327_pad_cfg nbg6716_ar8327_pad0_cfg;
+static struct ar8327_pad_cfg nbg6716_ar8327_pad6_cfg;
+static struct ar8327_led_cfg nbg6716_ar8327_led_cfg;
+
+static struct ar8327_platform_data nbg6716_ar8327_data = {
+	.pad0_cfg = &nbg6716_ar8327_pad0_cfg,
+	.pad6_cfg = &nbg6716_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &nbg6716_ar8327_led_cfg
+};
+
+static struct mdio_board_info nbg6716_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &nbg6716_ar8327_data,
+	},
+};
+
+static void nbg6716_get_mac(void* nvram_addr, const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(nvram_addr);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, 0x10000,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+static void __init nbg6716_common_setup(u32 leds_num, struct gpio_led* leds,
+					u32 keys_num,
+					struct gpio_keys_button* keys,
+					void* art_addr, void* nvram)
+{
+	u8 *art = (u8 *) KSEG1ADDR(art_addr);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, leds_num, leds);
+	ath79_register_gpio_keys_polled(-1, NBG6716_KEYS_POLL_INTERVAL,
+					keys_num, keys);
+
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_HW);
+	ath79_register_nfc();
+
+	gpio_request_one(NBG6716_GPIO_USB_POWER,
+		GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+		"USB power");
+
+	ath79_register_usb();
+
+	nbg6716_get_mac(nvram, "ethaddr=", tmpmac);
+
+	ath79_register_pci();
+
+	ath79_register_wmac(art + NBG6716_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, tmpmac, 2);
+	ath79_init_mac(ath79_eth1_data.mac_addr, tmpmac, 3);
+
+	mdiobus_register_board_info(nbg6716_mdio0_info,
+				    ARRAY_SIZE(nbg6716_mdio0_info));
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(1);
+}
+
+static void __init nbg6716_010_setup(void)
+{
+	/* GMAC0 of the AR8337 switch is connected to GMAC0 via RGMII */
+	nbg6716_ar8327_pad0_cfg.mode = AR8327_PAD_MAC_RGMII;
+	nbg6716_ar8327_pad0_cfg.txclk_delay_en = true;
+	nbg6716_ar8327_pad0_cfg.rxclk_delay_en = true;
+	nbg6716_ar8327_pad0_cfg.txclk_delay_sel = AR8327_CLK_DELAY_SEL1;
+	nbg6716_ar8327_pad0_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2;
+
+	/* GMAC6 of the AR8337 switch is connected to GMAC1 via SGMII */
+	nbg6716_ar8327_pad6_cfg.mode = AR8327_PAD_MAC_SGMII;
+	nbg6716_ar8327_pad6_cfg.rxclk_delay_en = true;
+	nbg6716_ar8327_pad6_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0;
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	nbg6716_ar8327_led_cfg.open_drain = 0;
+	nbg6716_ar8327_led_cfg.led_ctrl0 = 0xffb7ffb7;
+	nbg6716_ar8327_led_cfg.led_ctrl1 = 0xffb7ffb7;
+	nbg6716_ar8327_led_cfg.led_ctrl2 = 0xffb7ffb7;
+	nbg6716_ar8327_led_cfg.led_ctrl3 = 0x03ffff00;
+
+	nbg6716_common_setup(ARRAY_SIZE(nbg6716_leds_gpio), nbg6716_leds_gpio,
+			     ARRAY_SIZE(nbg6716_gpio_keys), nbg6716_gpio_keys,
+			     (void*) 0x1f050000, (void*) 0x1f040000);
+}
+
+static void __init nbg6616_010_setup(void)
+{
+	/* GMAC0 of the AR8337 switch is connected to GMAC0 via RGMII */
+	nbg6716_ar8327_pad0_cfg.mode = AR8327_PAD_MAC_RGMII;
+	nbg6716_ar8327_pad0_cfg.txclk_delay_en = true;
+	nbg6716_ar8327_pad0_cfg.rxclk_delay_en = true;
+	nbg6716_ar8327_pad0_cfg.txclk_delay_sel = AR8327_CLK_DELAY_SEL1;
+	nbg6716_ar8327_pad0_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2;
+
+	/* GMAC6 of the AR8337 switch is connected to GMAC1 via SGMII */
+	nbg6716_ar8327_pad6_cfg.mode = AR8327_PAD_MAC_SGMII;
+	nbg6716_ar8327_pad6_cfg.rxclk_delay_en = true;
+	nbg6716_ar8327_pad6_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0;
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	nbg6716_ar8327_led_cfg.open_drain = 0;
+	nbg6716_ar8327_led_cfg.led_ctrl0 = 0xffb7ffb7;
+	nbg6716_ar8327_led_cfg.led_ctrl1 = 0xffb7ffb7;
+	nbg6716_ar8327_led_cfg.led_ctrl2 = 0xffb7ffb7;
+	nbg6716_ar8327_led_cfg.led_ctrl3 = 0x03ffff00;
+
+
+	nbg6716_common_setup(ARRAY_SIZE(nbg6616_leds_gpio), nbg6616_leds_gpio,
+			     ARRAY_SIZE(nbg6616_gpio_keys), nbg6616_gpio_keys,
+			     (void*) 0x1f040000, (void*) 0x1f030000);
+}
+
+
+MIPS_MACHINE(ATH79_MACH_NBG6716, "NBG6716",
+	     "Zyxel NBG6716",
+	     nbg6716_010_setup);
+
+MIPS_MACHINE(ATH79_MACH_NBG6616, "NBG6616",
+	     "Zyxel NBG6616",
+	     nbg6616_010_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c
new file mode 100644
index 0000000000..3b282a36ea
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-om2p.c
@@ -0,0 +1,226 @@
+/*
+ *  OpenMesh OM2P support
+ *
+ *  Copyright (C) 2011 Marek Lindner <marek@open-mesh.com>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.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 OM2P_GPIO_LED_POWER	0
+#define OM2P_GPIO_LED_GREEN	13
+#define OM2P_GPIO_LED_RED	14
+#define OM2P_GPIO_LED_YELLOW	15
+#define OM2P_GPIO_LED_LAN	16
+#define OM2P_GPIO_LED_WAN	17
+#define OM2P_GPIO_BTN_RESET	1
+
+#define OM2P_KEYS_POLL_INTERVAL		20	/* msecs */
+#define OM2P_KEYS_DEBOUNCE_INTERVAL	(3 * OM2P_KEYS_POLL_INTERVAL)
+
+#define OM2P_WAN_PHYMASK	BIT(4)
+
+#define OM2P_LC_GPIO_LED_POWER	1
+#define OM2P_LC_GPIO_LED_GREEN	15
+#define OM2P_LC_GPIO_LED_RED	16
+#define OM2P_LC_GPIO_LED_YELLOW	0
+#define OM2P_LC_GPIO_LED_LAN	13
+#define OM2P_LC_GPIO_LED_WAN	17
+#define OM2P_LC_GPIO_BTN_RESET	12
+
+static struct flash_platform_data om2p_flash_data = {
+	.type = "s25sl12800",
+	.name = "ar7240-nor0",
+};
+
+static struct gpio_led om2p_leds_gpio[] __initdata = {
+	{
+		.name		= "om2p:blue:power",
+		.gpio		= OM2P_GPIO_LED_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "om2p:red:wifi",
+		.gpio		= OM2P_GPIO_LED_RED,
+		.active_low	= 1,
+	}, {
+		.name		= "om2p:yellow:wifi",
+		.gpio		= OM2P_GPIO_LED_YELLOW,
+		.active_low	= 1,
+	}, {
+		.name		= "om2p:green:wifi",
+		.gpio		= OM2P_GPIO_LED_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "om2p:blue:lan",
+		.gpio		= OM2P_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "om2p:blue:wan",
+		.gpio		= OM2P_GPIO_LED_WAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button om2p_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = OM2P_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= OM2P_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init om2p_setup(void)
+{
+	u8 *mac1 = (u8 *)KSEG1ADDR(0x1ffc0000);
+	u8 *mac2 = (u8 *)KSEG1ADDR(0x1ffc0000 + ETH_ALEN);
+	u8 *ee = (u8 *)KSEG1ADDR(0x1ffc1000);
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_m25p80(&om2p_flash_data);
+
+	ath79_register_mdio(0, ~OM2P_WAN_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ap91_pci_init(ee, NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om2p_leds_gpio),
+				 om2p_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, OM2P_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(om2p_gpio_keys),
+					om2p_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_OM2P, "OM2P", "OpenMesh OM2P", om2p_setup);
+
+
+static struct flash_platform_data om2p_lc_flash_data = {
+	.type = "s25sl12800",
+};
+
+static void __init om2p_lc_setup(void)
+{
+	u8 *mac1 = (u8 *)KSEG1ADDR(0x1ffc0000);
+	u8 *mac2 = (u8 *)KSEG1ADDR(0x1ffc0000 + ETH_ALEN);
+	u8 *art = (u8 *)KSEG1ADDR(0x1ffc1000);
+	u32 t;
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+	t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
+	ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
+
+	ath79_register_m25p80(&om2p_lc_flash_data);
+
+	om2p_leds_gpio[0].gpio = OM2P_LC_GPIO_LED_POWER;
+	om2p_leds_gpio[1].gpio = OM2P_LC_GPIO_LED_RED;
+	om2p_leds_gpio[2].gpio = OM2P_LC_GPIO_LED_YELLOW;
+	om2p_leds_gpio[3].gpio = OM2P_LC_GPIO_LED_GREEN;
+	om2p_leds_gpio[4].gpio = OM2P_LC_GPIO_LED_LAN;
+	om2p_leds_gpio[5].gpio = OM2P_LC_GPIO_LED_WAN;
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om2p_leds_gpio),
+				 om2p_leds_gpio);
+
+	om2p_gpio_keys[0].gpio = OM2P_LC_GPIO_BTN_RESET;
+	ath79_register_gpio_keys_polled(-1, OM2P_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(om2p_gpio_keys),
+					om2p_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(art, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_OM2P_LC, "OM2P-LC", "OpenMesh OM2P LC", om2p_lc_setup);
+MIPS_MACHINE(ATH79_MACH_OM2Pv2, "OM2Pv2", "OpenMesh OM2Pv2", om2p_lc_setup);
+
+static void __init om2p_hs_setup(void)
+{
+	u8 *mac1 = (u8 *)KSEG1ADDR(0x1ffc0000);
+	u8 *mac2 = (u8 *)KSEG1ADDR(0x1ffc0000 + ETH_ALEN);
+	u8 *art = (u8 *)KSEG1ADDR(0x1ffc1000);
+
+	/* make lan / wan leds software controllable */
+	ath79_gpio_output_select(OM2P_GPIO_LED_LAN, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(OM2P_GPIO_LED_WAN, AR934X_GPIO_OUT_GPIO);
+
+	/* enable reset button */
+	ath79_gpio_output_select(OM2P_GPIO_BTN_RESET, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+
+	om2p_leds_gpio[4].gpio = OM2P_GPIO_LED_WAN;
+	om2p_leds_gpio[5].gpio = OM2P_GPIO_LED_LAN;
+
+	ath79_register_m25p80(&om2p_lc_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om2p_leds_gpio),
+				 om2p_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, OM2P_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(om2p_gpio_keys),
+					om2p_gpio_keys);
+
+	ath79_register_wmac(art, NULL);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_OM2P_HS, "OM2P-HS", "OpenMesh OM2P HS", om2p_hs_setup);
+MIPS_MACHINE(ATH79_MACH_OM2P_HSv2, "OM2P-HSv2", "OpenMesh OM2P HSv2", om2p_hs_setup);
+MIPS_MACHINE(ATH79_MACH_OM2P_HSv3, "OM2P-HSv3", "OpenMesh OM2P HSv3", om2p_hs_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-om5p.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-om5p.c
new file mode 100644
index 0000000000..49acd3b67f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-om5p.c
@@ -0,0 +1,218 @@
+/*
+ *  OpenMesh OM5P support
+ *
+ *  Copyright (C) 2013 Marek Lindner <marek@open-mesh.com>
+ *  Copyright (C) 2014 Sven Eckelmann <sven@open-mesh.com>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.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 OM5P_GPIO_LED_POWER	13
+#define OM5P_GPIO_LED_GREEN	16
+#define OM5P_GPIO_LED_RED	19
+#define OM5P_GPIO_LED_YELLOW	17
+#define OM5P_GPIO_LED_LAN	14
+#define OM5P_GPIO_LED_WAN	15
+#define OM5P_GPIO_BTN_RESET	4
+#define OM5P_GPIO_I2C_SCL	20
+#define OM5P_GPIO_I2C_SDA	21
+
+#define OM5P_KEYS_POLL_INTERVAL		20	/* msecs */
+#define OM5P_KEYS_DEBOUNCE_INTERVAL	(3 * OM5P_KEYS_POLL_INTERVAL)
+
+#define OM5P_WMAC_CALDATA_OFFSET	0x1000
+#define OM5P_PCI_CALDATA_OFFSET		0x5000
+
+static struct gpio_led om5p_leds_gpio[] __initdata = {
+	{
+		.name		= "om5p:blue:power",
+		.gpio		= OM5P_GPIO_LED_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "om5p:red:wifi",
+		.gpio		= OM5P_GPIO_LED_RED,
+		.active_low	= 1,
+	}, {
+		.name		= "om5p:yellow:wifi",
+		.gpio		= OM5P_GPIO_LED_YELLOW,
+		.active_low	= 1,
+	}, {
+		.name		= "om5p:green:wifi",
+		.gpio		= OM5P_GPIO_LED_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "om5p:blue:lan",
+		.gpio		= OM5P_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "om5p:blue:wan",
+		.gpio		= OM5P_GPIO_LED_WAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button om5p_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = OM5P_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= OM5P_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct flash_platform_data om5p_flash_data = {
+	.type = "mx25l12805d",
+};
+
+static void __init om5p_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	/* make lan / wan leds software controllable */
+	ath79_gpio_output_select(OM5P_GPIO_LED_LAN, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(OM5P_GPIO_LED_WAN, AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(&om5p_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om5p_leds_gpio),
+				 om5p_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, OM5P_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(om5p_gpio_keys),
+					om5p_gpio_keys);
+
+	ath79_init_mac(mac, art, 2);
+	ath79_register_wmac(art + OM5P_WMAC_CALDATA_OFFSET, mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art, 1);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_OM5P, "OM5P", "OpenMesh OM5P", om5p_setup);
+
+static struct i2c_gpio_platform_data om5pan_i2c_device_platdata = {
+	.sda_pin		= OM5P_GPIO_I2C_SDA,
+	.scl_pin		= OM5P_GPIO_I2C_SCL,
+	.udelay			= 10,
+	.sda_is_open_drain	= 1,
+	.scl_is_open_drain	= 1,
+};
+
+static struct platform_device om5pan_i2c_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &om5pan_i2c_device_platdata,
+	},
+};
+
+static struct i2c_board_info om5pan_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("tmp423", 0x4c),
+	},
+};
+
+static struct at803x_platform_data om5p_an_at803x_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info om5p_an_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 7,
+		.platform_data = &om5p_an_at803x_data,
+	},
+};
+
+static void __init om5p_an_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	/* temperature sensor */
+	platform_device_register(&om5pan_i2c_device);
+	i2c_register_board_info(0, om5pan_i2c_devs,
+				ARRAY_SIZE(om5pan_i2c_devs));
+
+	/* make lan / wan leds software controllable */
+	ath79_gpio_output_select(OM5P_GPIO_LED_LAN, AR934X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(OM5P_GPIO_LED_WAN, AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(&om5p_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om5p_leds_gpio),
+				 om5p_leds_gpio);
+
+	ath79_init_mac(mac, art, 0x02);
+	ath79_register_wmac(art + OM5P_WMAC_CALDATA_OFFSET, mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+	ath79_setup_ar934x_eth_rx_delay(2, 2);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_mdio(1, 0x0);
+
+	mdiobus_register_board_info(om5p_an_mdio0_info,
+				    ARRAY_SIZE(om5p_an_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art, 0x00);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art, 0x01);
+
+	/* GMAC0 is connected to the PHY7 */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = BIT(7);
+	ath79_eth0_pll_data.pll_1000 = 0x02000000;
+	ath79_eth0_pll_data.pll_100 = 0x00000101;
+	ath79_eth0_pll_data.pll_10 = 0x00001313;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(1);
+
+	ath79_init_mac(mac, art, 0x10);
+	ap91_pci_init(art + OM5P_PCI_CALDATA_OFFSET, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_OM5P_AN, "OM5P-AN", "OpenMesh OM5P AN", om5p_an_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-om5pac.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-om5pac.c
new file mode 100644
index 0000000000..f6974aff71
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-om5pac.c
@@ -0,0 +1,193 @@
+/*
+ *  OpenMesh OM5P-AC support
+ *
+ *  Copyright (C) 2013 Marek Lindner <marek@open-mesh.com>
+ *  Copyright (C) 2014 Sven Eckelmann <sven@open-mesh.com>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define OM5PAC_GPIO_LED_POWER	18
+#define OM5PAC_GPIO_LED_GREEN	21
+#define OM5PAC_GPIO_LED_RED	23
+#define OM5PAC_GPIO_LED_YELLOW	22
+#define OM5PAC_GPIO_LED_LAN	20
+#define OM5PAC_GPIO_LED_WAN	19
+#define OM5PAC_GPIO_I2C_SCL	12
+#define OM5PAC_GPIO_I2C_SDA	11
+
+#define OM5PAC_KEYS_POLL_INTERVAL	20	/* msecs */
+#define OM5PAC_KEYS_DEBOUNCE_INTERVAL	(3 * OM5PAC_KEYS_POLL_INTERVAL)
+
+#define OM5PAC_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led om5pac_leds_gpio[] __initdata = {
+	{
+		.name		= "om5pac:blue:power",
+		.gpio		= OM5PAC_GPIO_LED_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:red:wifi",
+		.gpio		= OM5PAC_GPIO_LED_RED,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:yellow:wifi",
+		.gpio		= OM5PAC_GPIO_LED_YELLOW,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:green:wifi",
+		.gpio		= OM5PAC_GPIO_LED_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:blue:lan",
+		.gpio		= OM5PAC_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:blue:wan",
+		.gpio		= OM5PAC_GPIO_LED_WAN,
+		.active_low	= 1,
+	}
+};
+
+static struct flash_platform_data om5pac_flash_data = {
+	.type = "mx25l12805d",
+};
+
+static struct i2c_gpio_platform_data om5pac_i2c_device_platdata = {
+	.sda_pin		= OM5PAC_GPIO_I2C_SDA,
+	.scl_pin		= OM5PAC_GPIO_I2C_SCL,
+	.udelay			= 10,
+	.sda_is_open_drain	= 1,
+	.scl_is_open_drain	= 1,
+};
+
+static struct platform_device om5pac_i2c_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &om5pac_i2c_device_platdata,
+	},
+};
+
+static struct i2c_board_info om5pac_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("tmp423", 0x4c),
+	},
+};
+
+static struct at803x_platform_data om5pac_at803x_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info om5pac_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 1,
+		.platform_data = &om5pac_at803x_data,
+	},
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 2,
+		.platform_data = &om5pac_at803x_data,
+	},
+};
+
+static void __init om5p_ac_setup_qca955x_eth_cfg(u32 mask,
+						 unsigned int rxd,
+						 unsigned int rxdv,
+						 unsigned int txd,
+						 unsigned int txe)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+	t = mask;
+	t |= rxd << QCA955X_ETH_CFG_RXD_DELAY_SHIFT;
+	t |= rxdv << QCA955X_ETH_CFG_RDV_DELAY_SHIFT;
+	t |= txd << QCA955X_ETH_CFG_TXD_DELAY_SHIFT;
+	t |= txe << QCA955X_ETH_CFG_TXE_DELAY_SHIFT;
+
+	__raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+static void __init om5p_ac_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	/* temperature sensor */
+	platform_device_register(&om5pac_i2c_device);
+	i2c_register_board_info(0, om5pac_i2c_devs,
+				ARRAY_SIZE(om5pac_i2c_devs));
+
+	ath79_gpio_output_select(OM5PAC_GPIO_LED_WAN, QCA955X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(&om5pac_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om5pac_leds_gpio),
+				 om5pac_leds_gpio);
+
+	ath79_init_mac(mac, art, 0x02);
+	ath79_register_wmac(art + OM5PAC_WMAC_CALDATA_OFFSET, mac);
+
+	om5p_ac_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN, 3, 3, 0, 0);
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(om5pac_mdio0_info,
+				    ARRAY_SIZE(om5pac_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art, 0x00);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art, 0x01);
+
+	/* GMAC0 is connected to the PHY1 */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = BIT(1);
+	ath79_eth0_pll_data.pll_1000 = 0x82000101;
+	ath79_eth0_pll_data.pll_100 = 0x80000101;
+	ath79_eth0_pll_data.pll_10 = 0x80001313;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to MDIO1 in SGMII mode */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth1_data.phy_mask = BIT(2);
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+	ath79_eth1_pll_data.pll_100 = 0x80000101;
+	ath79_eth1_pll_data.pll_10 = 0x80001313;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_register_eth(1);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_OM5P_AC, "OM5P-AC", "OpenMesh OM5P AC", om5p_ac_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-om5pacv2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-om5pacv2.c
new file mode 100644
index 0000000000..0480d01e2c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-om5pacv2.c
@@ -0,0 +1,221 @@
+/*
+ *  OpenMesh OM5P-ACv2 support
+ *
+ *  Copyright (C) 2013 Marek Lindner <marek@open-mesh.com>
+ *  Copyright (C) 2014-2016 Sven Eckelmann <sven@open-mesh.com>
+ *  Copyright (C) 2015 Open-Mesh - Jim Collar <jim.collar@eqware.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/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0)
+#include <linux/mdio-gpio.h>
+#else
+#include <linux/platform_data/mdio-gpio.h> 
+#endif
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.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"
+#include "pci.h"
+
+#define OM5PACV2_GPIO_LED_POWER	14
+#define OM5PACV2_GPIO_LED_GREEN	13
+#define OM5PACV2_GPIO_LED_RED	23
+#define OM5PACV2_GPIO_LED_YELLOW	15
+#define OM5PACV2_GPIO_BTN_RESET	1
+#define OM5PACV2_GPIO_I2C_SCL	18
+#define OM5PACV2_GPIO_I2C_SDA	19
+#define OM5PACV2_GPIO_PA_DCDC	2
+#define OM5PACV2_GPIO_PA_HIGH	16
+
+#define OM5PACV2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define OM5PACV2_KEYS_DEBOUNCE_INTERVAL	(3 * OM5PACV2_KEYS_POLL_INTERVAL)
+
+#define OM5PACV2_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led om5pacv2_leds_gpio[] __initdata = {
+	{
+		.name		= "om5pac:blue:power",
+		.gpio		= OM5PACV2_GPIO_LED_POWER,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:red:wifi",
+		.gpio		= OM5PACV2_GPIO_LED_RED,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:yellow:wifi",
+		.gpio		= OM5PACV2_GPIO_LED_YELLOW,
+		.active_low	= 1,
+	}, {
+		.name		= "om5pac:green:wifi",
+		.gpio		= OM5PACV2_GPIO_LED_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button om5pacv2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = OM5PACV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= OM5PACV2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct i2c_gpio_platform_data om5pacv2_i2c_device_platdata = {
+	.sda_pin		= OM5PACV2_GPIO_I2C_SDA,
+	.scl_pin		= OM5PACV2_GPIO_I2C_SCL,
+	.udelay			= 10,
+	.sda_is_open_drain	= 1,
+	.scl_is_open_drain	= 1,
+};
+
+static struct platform_device om5pacv2_i2c_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &om5pacv2_i2c_device_platdata,
+	},
+};
+
+static struct i2c_board_info om5pacv2_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("tmp423", 0x4e),
+	},
+};
+
+static struct flash_platform_data om5pacv2_flash_data = {
+	.type = "mx25l12805d",
+};
+
+static struct at803x_platform_data om5pacv2_an_at803x_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 1,
+};
+
+static struct at803x_platform_data om5pacv2_an_at8031_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info om5pacv2_an_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 4,
+		.platform_data = &om5pacv2_an_at803x_data,
+	},
+	{
+		.bus_id = "ag71xx-mdio.1",
+		.phy_addr = 1,
+		.platform_data = &om5pacv2_an_at8031_data,
+	},
+};
+
+static void __init om5p_acv2_setup_qca955x_eth_cfg(u32 mask,
+						   unsigned int rxd,
+						   unsigned int rxdv,
+						   unsigned int txd,
+						   unsigned int txe)
+{
+	void __iomem *base;
+	u32 t;
+
+	base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
+
+	t = mask;
+	t |= rxd << QCA955X_ETH_CFG_RXD_DELAY_SHIFT;
+	t |= rxdv << QCA955X_ETH_CFG_RDV_DELAY_SHIFT;
+	t |= txd << QCA955X_ETH_CFG_TXD_DELAY_SHIFT;
+	t |= txe << QCA955X_ETH_CFG_TXE_DELAY_SHIFT;
+
+	__raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
+
+	iounmap(base);
+}
+
+static void __init om5p_acv2_setup(void)
+{
+	u8 *art = (u8 *)KSEG1ADDR(0x1fff0000);
+	u8 mac[6];
+
+	/* power amplifier high power, 4.2V at RFFM4203/4503 instead of 3.3 */
+	ath79_gpio_function_enable(QCA955X_GPIO_FUNC_JTAG_DISABLE);
+	ath79_gpio_output_select(OM5PACV2_GPIO_PA_DCDC, QCA955X_GPIO_OUT_GPIO);
+	ath79_gpio_output_select(OM5PACV2_GPIO_PA_HIGH, QCA955X_GPIO_OUT_GPIO);
+	gpio_request_one(OM5PACV2_GPIO_PA_DCDC, GPIOF_OUT_INIT_HIGH,
+			 "PA DC/DC");
+	gpio_request_one(OM5PACV2_GPIO_PA_HIGH, GPIOF_OUT_INIT_HIGH, "PA HIGH");
+
+	/* temperature sensor */
+	platform_device_register(&om5pacv2_i2c_device);
+	i2c_register_board_info(0, om5pacv2_i2c_devs,
+				ARRAY_SIZE(om5pacv2_i2c_devs));
+
+	ath79_register_m25p80(&om5pacv2_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(om5pacv2_leds_gpio),
+				 om5pacv2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, OM5PACV2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(om5pacv2_gpio_keys),
+					om5pacv2_gpio_keys);
+
+	ath79_init_mac(mac, art, 0x02);
+	ath79_register_wmac(art + OM5PACV2_WMAC_CALDATA_OFFSET, mac);
+
+	om5p_acv2_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN, 2, 2, 0, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_mdio(1, 0x0);
+
+	mdiobus_register_board_info(om5pacv2_an_mdio0_info,
+				    ARRAY_SIZE(om5pacv2_an_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art, 0x00);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art, 0x01);
+
+	/* GMAC0 is connected to the PHY4 */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_pll_data.pll_1000 = 0x82000101;
+	ath79_eth0_pll_data.pll_100 = 0x80000101;
+	ath79_eth0_pll_data.pll_10 = 0x80001313;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to MDIO1 in SGMII mode */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_eth1_data.phy_mask = BIT(1);
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+	ath79_eth1_pll_data.pll_100 = 0x80000101;
+	ath79_eth1_pll_data.pll_10 = 0x80001313;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_register_eth(1);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_OM5P_ACv2, "OM5P-ACv2", "OpenMesh OM5P ACv2", om5p_acv2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-omy-g1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-omy-g1.c
new file mode 100644
index 0000000000..25ca27cba8
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-omy-g1.c
@@ -0,0 +1,123 @@
+/*
+ *  OMYlink OMY-G1 board support
+ *
+ *  Copyright (C) 2016 L. D. Pinney <ldpinney@gmail.com>
+ *
+ *  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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define OMY_G1_GPIO_LED_WLAN	13
+#define OMY_G1_GPIO_LED_WAN	18
+#define OMY_G1_GPIO_LED_LAN	19
+
+#define OMY_G1_GPIO_USB_POWER	4
+
+#define OMY_G1_GPIO_BTN_RESET	17
+
+#define OMY_G1_KEYS_POLL_INTERVAL	20	/* msecs */
+#define OMY_G1_KEYS_DEBOUNCE_INTERVAL (3 * OMY_G1_KEYS_POLL_INTERVAL)
+
+static const char *omy_g1_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data omy_g1_flash_data = {
+	.part_probes	= omy_g1_part_probes,
+};
+
+static struct gpio_led omy_g1_leds_gpio[] __initdata = {
+	{
+		.name		= "omy:green:wlan",
+		.gpio		= OMY_G1_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},{
+		.name		= "omy:green:wan",
+		.gpio		= OMY_G1_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "omy:green:lan",
+		.gpio		= OMY_G1_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button omy_g1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = OMY_G1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= OMY_G1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init omy_g1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_gpio_function_setup(AR934X_GPIO_FUNC_JTAG_DISABLE,
+				 AR934X_GPIO_FUNC_CLK_OBS4_EN);
+
+	ath79_register_m25p80(&omy_g1_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(omy_g1_leds_gpio),
+				omy_g1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, OMY_G1_KEYS_POLL_INTERVAL,
+				ARRAY_SIZE(omy_g1_gpio_keys),
+				omy_g1_gpio_keys);
+
+	ath79_gpio_output_select(OMY_G1_GPIO_USB_POWER,
+				 AR934X_GPIO_OUT_GPIO);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+
+	ath79_gpio_output_select(OMY_G1_GPIO_USB_POWER,
+				 AR934X_GPIO_OUT_GPIO);
+
+	gpio_request_one(OMY_G1_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_OMY_G1, "OMY-G1", "OMYlink OMY-G1",
+	     omy_g1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-omy-x1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-omy-x1.c
new file mode 100644
index 0000000000..c99e3d7457
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-omy-x1.c
@@ -0,0 +1,106 @@
+/*
+ *  OMYlink OMY-X1 board support
+ *
+ *  Copyright (C) 2016 L. D. Pinney <ldpinney@gmail.com>
+ *
+ *  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 OMY_X1_GPIO_LED_POWER	19
+#define OMY_X1_GPIO_LED_WAN	22
+
+#define OMY_X1_GPIO_BTN_RESET	17
+
+#define OMY_X1_KEYS_POLL_INTERVAL	20	/* msecs */
+#define OMY_X1_KEYS_DEBOUNCE_INTERVAL (3 * OMY_X1_KEYS_POLL_INTERVAL)
+
+static const char *omy_x1_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data omy_x1_flash_data = {
+	.part_probes	= omy_x1_part_probes,
+};
+
+static struct gpio_led omy_x1_leds_gpio[] __initdata = {
+	{
+		.name		= "omy:green:wan",
+		.gpio		= OMY_X1_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "omy:green:power",
+		.gpio		= OMY_X1_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button omy_x1_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = OMY_X1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= OMY_X1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init omy_x1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_gpio_function_setup(AR934X_GPIO_FUNC_JTAG_DISABLE,
+				 AR934X_GPIO_FUNC_CLK_OBS4_EN);
+
+	ath79_register_m25p80(&omy_x1_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(omy_x1_leds_gpio),
+				omy_x1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, OMY_X1_KEYS_POLL_INTERVAL,
+				ARRAY_SIZE(omy_x1_gpio_keys),
+				omy_x1_gpio_keys);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+
+}
+
+MIPS_MACHINE(ATH79_MACH_OMY_X1, "OMY-X1", "OMYlink OMY-X1",
+	     omy_x1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-onion-omega.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-onion-omega.c
new file mode 100644
index 0000000000..c739840377
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-onion-omega.c
@@ -0,0 +1,84 @@
+/*
+ *  Onion Omega board support
+ *
+ *  Copyright (C) 2015 Boken Lin <bl@onion.io>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define OMEGA_GPIO_LED_SYSTEM	27
+#define OMEGA_GPIO_BTN_RESET	11
+
+#define OMEGA_GPIO_USB_POWER	8
+
+#define OMEGA_KEYS_POLL_INTERVAL	20  /* msecs */
+#define OMEGA_KEYS_DEBOUNCE_INTERVAL	(3 * OMEGA_KEYS_POLL_INTERVAL)
+
+static const char *omega_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data omega_flash_data = {
+	.part_probes    = omega_part_probes,
+};
+
+static struct gpio_led omega_leds_gpio[] __initdata = {
+	{
+		.name       = "onion:amber:system",
+		.gpio       = OMEGA_GPIO_LED_SYSTEM,
+		.active_low = 1,
+	},
+};
+
+static struct gpio_keys_button omega_gpio_keys[] __initdata = {
+	{
+		.desc       = "reset",
+		.type       = EV_KEY,
+		.code       = KEY_RESTART,
+		.debounce_interval = OMEGA_KEYS_DEBOUNCE_INTERVAL,
+		.gpio       = OMEGA_GPIO_BTN_RESET,
+		.active_low = 0,
+	}
+};
+
+static void __init onion_omega_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&omega_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(omega_leds_gpio),
+				omega_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, OMEGA_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(omega_gpio_keys),
+					omega_gpio_keys);
+
+	gpio_request_one(OMEGA_GPIO_USB_POWER,
+			GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			"USB power");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_ONION_OMEGA, "ONION-OMEGA", "Onion Omega", onion_omega_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-pb42.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-pb42.c
new file mode 100644
index 0000000000..3a350e90a1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-pb42.c
@@ -0,0 +1,83 @@
+/*
+ *  Atheros PB42 board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define PB42_KEYS_POLL_INTERVAL		20	/* msecs */
+#define PB42_KEYS_DEBOUNCE_INTERVAL	(3 * PB42_KEYS_POLL_INTERVAL)
+
+#define PB42_GPIO_BTN_SW4	8
+#define PB42_GPIO_BTN_SW5	3
+
+static struct gpio_keys_button pb42_gpio_keys[] __initdata = {
+	{
+		.desc		= "sw4",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = PB42_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= PB42_GPIO_BTN_SW4,
+		.active_low	= 1,
+	}, {
+		.desc		= "sw5",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = PB42_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= PB42_GPIO_BTN_SW5,
+		.active_low	= 1,
+	}
+};
+
+static const char *pb42_part_probes[] = {
+	"RedBoot",
+	NULL,
+};
+
+static struct flash_platform_data pb42_flash_data = {
+	.part_probes	= pb42_part_probes,
+};
+
+#define PB42_WAN_PHYMASK	BIT(20)
+#define PB42_LAN_PHYMASK	(BIT(16) | BIT(17) | BIT(18) | BIT(19))
+#define PB42_MDIO_PHYMASK	(PB42_LAN_PHYMASK | PB42_WAN_PHYMASK)
+
+static void __init pb42_init(void)
+{
+	ath79_register_m25p80(&pb42_flash_data);
+
+	ath79_register_mdio(0, ~PB42_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = PB42_WAN_PHYMASK;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.speed = SPEED_100;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_gpio_keys_polled(-1, PB42_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(pb42_gpio_keys),
+					pb42_gpio_keys);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_PB42, "PB42", "Atheros PB42", pb42_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-pb92.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-pb92.c
new file mode 100644
index 0000000000..2440f0b6d3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-pb92.c
@@ -0,0 +1,70 @@
+/*
+ *  Atheros PB92 board support
+ *
+ *  Copyright (C) 2010 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define PB92_KEYS_POLL_INTERVAL		20	/* msecs */
+#define PB92_KEYS_DEBOUNCE_INTERVAL	(3 * PB92_KEYS_POLL_INTERVAL)
+
+#define PB92_GPIO_BTN_SW4	8
+#define PB92_GPIO_BTN_SW5	3
+
+static struct gpio_keys_button pb92_gpio_keys[] __initdata = {
+	{
+		.desc		= "sw4",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = PB92_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= PB92_GPIO_BTN_SW4,
+		.active_low	= 1,
+	}, {
+		.desc		= "sw5",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = PB92_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= PB92_GPIO_BTN_SW5,
+		.active_low	= 1,
+	}
+};
+
+static void __init pb92_init(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_mdio(0, ~BIT(0));
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_register_eth(0);
+
+	ath79_register_gpio_keys_polled(-1, PB92_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(pb92_gpio_keys),
+					 pb92_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_PB92, "PB92", "Atheros PB92", pb92_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-qihoo-c301.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-qihoo-c301.c
new file mode 100644
index 0000000000..a682f35e2c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-qihoo-c301.c
@@ -0,0 +1,166 @@
+/*
+ *  Qihoo 360 C301 board support
+ *
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Weijie Gao <hackpascal@gmail.com>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "nvram.h"
+
+#define QIHOO_C301_GPIO_LED_STATUS_GREEN	0
+#define QIHOO_C301_GPIO_LED_STATUS_RED		11
+
+#define QIHOO_C301_GPIO_LED_WAN			1
+#define QIHOO_C301_GPIO_LED_LAN1		2
+#define QIHOO_C301_GPIO_LED_LAN2		3
+#define QIHOO_C301_GPIO_ETH_LEN_EN		18
+
+#define QIHOO_C301_GPIO_BTN_RESET		16
+
+#define QIHOO_C301_GPIO_USB_POWER		19
+
+#define QIHOO_C301_GPIO_SPI_CS1			12
+
+#define QIHOO_C301_GPIO_EXTERNAL_LNA0		14
+#define QIHOO_C301_GPIO_EXTERNAL_LNA1		15
+
+#define QIHOO_C301_KEYS_POLL_INTERVAL		20	/* msecs */
+#define QIHOO_C301_KEYS_DEBOUNCE_INTERVAL	\
+	(3 * QIHOO_C301_KEYS_POLL_INTERVAL)
+
+#define QIHOO_C301_WMAC_CALDATA_OFFSET		0x1000
+
+#define QIHOO_C301_NVRAM_ADDR			0x1f058010
+#define QIHOO_C301_NVRAM_SIZE			0x7ff0
+
+static struct gpio_led qihoo_c301_leds_gpio[] __initdata = {
+	{
+		.name		= "qihoo:green:status",
+		.gpio		= QIHOO_C301_GPIO_LED_STATUS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "qihoo:red:status",
+		.gpio		= QIHOO_C301_GPIO_LED_STATUS_RED,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button qihoo_c301_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = QIHOO_C301_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= QIHOO_C301_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct flash_platform_data flash __initdata = {NULL, NULL, 0};
+
+static void qihoo_c301_get_mac(const char *name, char *mac)
+{
+	u8 *nvram = (u8 *) KSEG1ADDR(QIHOO_C301_NVRAM_ADDR);
+	int err;
+
+	err = ath79_nvram_parse_mac_addr(nvram, QIHOO_C301_NVRAM_SIZE,
+					 name, mac);
+	if (err)
+		pr_err("no MAC address found for %s\n", name);
+}
+
+static void __init qihoo_c301_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80_multi(&flash);
+
+	ath79_gpio_function_enable(AR934X_GPIO_FUNC_JTAG_DISABLE);
+
+	ath79_gpio_output_select(QIHOO_C301_GPIO_LED_WAN,
+				 AR934X_GPIO_OUT_LED_LINK4);
+	ath79_gpio_output_select(QIHOO_C301_GPIO_LED_LAN1,
+				 AR934X_GPIO_OUT_LED_LINK1);
+	ath79_gpio_output_select(QIHOO_C301_GPIO_LED_LAN2,
+				 AR934X_GPIO_OUT_LED_LINK2);
+
+	ath79_gpio_output_select(QIHOO_C301_GPIO_SPI_CS1,
+				 AR934X_GPIO_OUT_SPI_CS1);
+
+	gpio_request_one(QIHOO_C301_GPIO_ETH_LEN_EN,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "Ethernet LED enable");
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(qihoo_c301_leds_gpio),
+				 qihoo_c301_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, QIHOO_C301_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(qihoo_c301_gpio_keys),
+					qihoo_c301_gpio_keys);
+
+	ath79_wmac_set_ext_lna_gpio(0, QIHOO_C301_GPIO_EXTERNAL_LNA0);
+	ath79_wmac_set_ext_lna_gpio(1, QIHOO_C301_GPIO_EXTERNAL_LNA1);
+
+	qihoo_c301_get_mac("wlan24mac=", tmpmac);
+	ath79_register_wmac(art + QIHOO_C301_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_register_pci();
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE |
+				   AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* LAN */
+	qihoo_c301_get_mac("lanmac=", ath79_eth1_data.mac_addr);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(1);
+
+	/* WAN */
+	qihoo_c301_get_mac("wanmac=", ath79_eth0_data.mac_addr);
+
+	/* GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(0);
+
+	gpio_request_one(QIHOO_C301_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_QIHOO_C301, "QIHOO-C301", "Qihoo 360 C301",
+	     qihoo_c301_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-r6100.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-r6100.c
new file mode 100644
index 0000000000..c1f0e2c400
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-r6100.c
@@ -0,0 +1,146 @@
+/*
+ *  NETGEAR R6100 board support
+ *
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/platform/ar934x_nfc.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define R6100_GPIO_LED_WLAN		0
+#define R6100_GPIO_LED_USB		11
+#define R6100_GPIO_LED_WAN_GREEN	13
+#define R6100_GPIO_LED_POWER_AMBER	14
+#define R6100_GPIO_LED_WAN_AMBER	15
+#define R6100_GPIO_LED_POWER_GREEN	17
+
+#define R6100_GPIO_BTN_WIRELESS		1
+#define R6100_GPIO_BTN_WPS		3
+#define R6100_GPIO_BTN_RESET		12
+
+#define R6100_GPIO_USB_POWER		16
+
+#define R6100_KEYS_POLL_INTERVAL	20	/* msecs */
+#define R6100_KEYS_DEBOUNCE_INTERVAL	(3 * R6100_KEYS_POLL_INTERVAL)
+
+static struct gpio_led r6100_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= R6100_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:power",
+		.gpio		= R6100_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:wan",
+		.gpio		= R6100_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:wan",
+		.gpio		= R6100_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:blue:usb",
+		.gpio		= R6100_GPIO_LED_USB,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:blue:wlan",
+		.gpio		= R6100_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button r6100_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = R6100_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= R6100_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = R6100_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= R6100_GPIO_BTN_WPS,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = R6100_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= R6100_GPIO_BTN_WIRELESS,
+		.active_low	= 0,
+	},
+};
+
+static void __init r6100_setup(void)
+{
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(r6100_leds_gpio),
+				 r6100_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, R6100_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(r6100_gpio_keys),
+					r6100_gpio_keys);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	gpio_request_one(R6100_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_HW);
+	ath79_register_nfc();
+
+	ath79_register_usb();
+
+	ath79_register_wmac_simple();
+
+	ap91_pci_init_simple();
+}
+
+MIPS_MACHINE(ATH79_MACH_R6100, "R6100", "NETGEAR R6100",
+	     r6100_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb2011.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb2011.c
new file mode 100644
index 0000000000..afd56085c7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb2011.c
@@ -0,0 +1,338 @@
+/*
+ *  MikroTik RouterBOARD 2011 support
+ *
+ *  Copyright (C) 2012 Stijn Tintel <stijn@linux-ipv6.be>
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) "rb2011: " fmt
+
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/routerboot.h>
+#include <linux/gpio.h>
+
+#include <asm/prom.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "routerboot.h"
+
+#define RB2011_GPIO_NAND_NCE	14
+#define RB2011_GPIO_SFP_LOS	21
+
+#define RB_ROUTERBOOT_OFFSET	0x0000
+#define RB_ROUTERBOOT_MIN_SIZE	0xb000
+#define RB_HARD_CFG_SIZE	0x1000
+#define RB_BIOS_OFFSET		0xd000
+#define RB_BIOS_SIZE		0x1000
+#define RB_SOFT_CFG_OFFSET	0xf000
+#define RB_SOFT_CFG_SIZE	0x1000
+
+#define RB_ART_SIZE		0x10000
+
+#define RB2011_FLAG_SFP		BIT(0)
+#define RB2011_FLAG_USB		BIT(1)
+#define RB2011_FLAG_WLAN	BIT(2)
+
+static struct mtd_partition rb2011_spi_partitions[] = {
+	{
+		.name		= "routerboot",
+		.offset		= RB_ROUTERBOOT_OFFSET,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "hard_config",
+		.size		= RB_HARD_CFG_SIZE,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "bios",
+		.offset		= RB_BIOS_OFFSET,
+		.size		= RB_BIOS_SIZE,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "soft_config",
+		.size		= RB_SOFT_CFG_SIZE,
+	}
+};
+
+static void __init rb2011_init_partitions(const struct rb_info *info)
+{
+	rb2011_spi_partitions[0].size = info->hard_cfg_offs;
+	rb2011_spi_partitions[1].offset = info->hard_cfg_offs;
+	rb2011_spi_partitions[3].offset = info->soft_cfg_offs;
+}
+
+static struct mtd_partition rb2011_nand_partitions[] = {
+	{
+		.name	= "booter",
+		.offset	= 0,
+		.size	= (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	},
+	{
+		.name	= "kernel",
+		.offset	= (256 * 1024),
+		.size	= (4 * 1024 * 1024) - (256 * 1024),
+	},
+	{
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct flash_platform_data rb2011_spi_flash_data = {
+	.parts		= rb2011_spi_partitions,
+	.nr_parts	= ARRAY_SIZE(rb2011_spi_partitions),
+};
+
+static struct ar8327_pad_cfg rb2011_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL3,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0,
+};
+
+static struct ar8327_pad_cfg rb2011_ar8327_pad6_cfg;
+static struct ar8327_sgmii_cfg rb2011_ar8327_sgmii_cfg;
+
+static struct ar8327_led_cfg rb2011_ar8327_led_cfg = {
+	.led_ctrl0 = 0xc731c731,
+	.led_ctrl1 = 0x00000000,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x0030c300,
+	.open_drain = false,
+};
+
+static const struct ar8327_led_info rb2011_ar8327_leds[] __initconst = {
+	AR8327_LED_INFO(PHY0_0, HW, "rb:green:eth1"),
+	AR8327_LED_INFO(PHY1_0, HW, "rb:green:eth2"),
+	AR8327_LED_INFO(PHY2_0, HW, "rb:green:eth3"),
+	AR8327_LED_INFO(PHY3_0, HW, "rb:green:eth4"),
+	AR8327_LED_INFO(PHY4_0, HW, "rb:green:eth5"),
+	AR8327_LED_INFO(PHY0_1, SW, "rb:green:eth6"),
+	AR8327_LED_INFO(PHY1_1, SW, "rb:green:eth7"),
+	AR8327_LED_INFO(PHY2_1, SW, "rb:green:eth8"),
+	AR8327_LED_INFO(PHY3_1, SW, "rb:green:eth9"),
+	AR8327_LED_INFO(PHY4_1, SW, "rb:green:eth10"),
+	AR8327_LED_INFO(PHY4_2, SW, "rb:green:usr"),
+};
+
+static struct ar8327_platform_data rb2011_ar8327_data = {
+	.pad0_cfg = &rb2011_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &rb2011_ar8327_led_cfg,
+	.num_leds = ARRAY_SIZE(rb2011_ar8327_leds),
+	.leds = rb2011_ar8327_leds,
+};
+
+static struct mdio_board_info rb2011_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &rb2011_ar8327_data,
+	},
+};
+
+static void __init rb2011_wlan_init(void)
+{
+	char *art_buf;
+	u8 wlan_mac[ETH_ALEN];
+
+	art_buf = rb_get_wlan_data();
+	if (art_buf == NULL)
+		return;
+
+	ath79_init_mac(wlan_mac, ath79_mac_base, 11);
+	ath79_register_wmac(art_buf + 0x1000, wlan_mac);
+
+	kfree(art_buf);
+}
+
+static void rb2011_nand_select_chip(int chip_no)
+{
+	switch (chip_no) {
+	case 0:
+		gpio_set_value(RB2011_GPIO_NAND_NCE, 0);
+		break;
+	default:
+		gpio_set_value(RB2011_GPIO_NAND_NCE, 1);
+		break;
+	}
+	ndelay(500);
+}
+
+static struct nand_ecclayout rb2011_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos		= { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static int rb2011_nand_scan_fixup(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (mtd->writesize == 512) {
+		/*
+		 * Use the OLD Yaffs-1 OOB layout, otherwise RouterBoot
+		 * will not be able to find the kernel that we load.
+		 */
+		chip->ecc.layout = &rb2011_nand_ecclayout;
+	}
+
+	return 0;
+}
+
+static void __init rb2011_nand_init(void)
+{
+	gpio_request_one(RB2011_GPIO_NAND_NCE, GPIOF_OUT_INIT_HIGH, "NAND nCE");
+
+	ath79_nfc_set_scan_fixup(rb2011_nand_scan_fixup);
+	ath79_nfc_set_parts(rb2011_nand_partitions,
+			    ARRAY_SIZE(rb2011_nand_partitions));
+	ath79_nfc_set_select_chip(rb2011_nand_select_chip);
+	ath79_nfc_set_swap_dma(true);
+	ath79_register_nfc();
+}
+
+static int rb2011_get_port_link(unsigned port)
+{
+	if (port != 6)
+		return -EINVAL;
+
+	/* The Loss of signal line is active low */
+	return !gpio_get_value(RB2011_GPIO_SFP_LOS);
+}
+
+static void __init rb2011_sfp_init(void)
+{
+	gpio_request_one(RB2011_GPIO_SFP_LOS, GPIOF_IN, "SFP LOS");
+
+	rb2011_ar8327_pad6_cfg.mode = AR8327_PAD_MAC_SGMII;
+
+	rb2011_ar8327_data.pad6_cfg = &rb2011_ar8327_pad6_cfg;
+
+	rb2011_ar8327_sgmii_cfg.sgmii_ctrl = 0xc70167d0;
+	rb2011_ar8327_sgmii_cfg.serdes_aen = true;
+
+	rb2011_ar8327_data.sgmii_cfg = &rb2011_ar8327_sgmii_cfg;
+
+	rb2011_ar8327_data.port6_cfg.force_link = 1;
+	rb2011_ar8327_data.port6_cfg.speed = AR8327_PORT_SPEED_1000;
+	rb2011_ar8327_data.port6_cfg.duplex = 1;
+
+	rb2011_ar8327_data.get_port_link = rb2011_get_port_link;
+}
+
+static int __init rb2011_setup(u32 flags)
+{
+	const struct rb_info *info;
+	char buf[64];
+
+	info = rb_init_info((void *) KSEG1ADDR(0x1f000000), 0x10000);
+	if (!info)
+		return -ENODEV;
+
+	scnprintf(buf, sizeof(buf), "Mikrotik RouterBOARD %s",
+		  (info->board_name) ? info->board_name : "");
+	mips_set_machine_name(buf);
+
+	rb2011_init_partitions(info);
+
+	ath79_register_m25p80(&rb2011_spi_flash_data);
+	rb2011_nand_init();
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(rb2011_mdio0_info,
+				    ARRAY_SIZE(rb2011_mdio0_info));
+
+	/* GMAC0 is connected to an ar8327 switch */
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 5);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(1);
+
+	if (flags & RB2011_FLAG_SFP)
+		rb2011_sfp_init();
+
+	if (flags & RB2011_FLAG_WLAN)
+		rb2011_wlan_init();
+
+	if (flags & RB2011_FLAG_USB)
+		ath79_register_usb();
+
+	return 0;
+}
+
+static void __init rb2011l_setup(void)
+{
+	rb2011_setup(0);
+}
+
+MIPS_MACHINE_NONAME(ATH79_MACH_RB_2011L, "2011L", rb2011l_setup);
+
+static void __init rb2011us_setup(void)
+{
+	rb2011_setup(RB2011_FLAG_SFP | RB2011_FLAG_USB);
+}
+
+MIPS_MACHINE_NONAME(ATH79_MACH_RB_2011US, "2011US", rb2011us_setup);
+
+static void __init rb2011r5_setup(void)
+{
+	rb2011_setup(RB2011_FLAG_SFP | RB2011_FLAG_USB | RB2011_FLAG_WLAN);
+}
+
+MIPS_MACHINE_NONAME(ATH79_MACH_RB_2011R5, "2011r5", rb2011r5_setup);
+
+static void __init rb2011g_setup(void)
+{
+	rb2011_setup(RB2011_FLAG_SFP |
+		     RB2011_FLAG_USB |
+		     RB2011_FLAG_WLAN);
+}
+
+MIPS_MACHINE_NONAME(ATH79_MACH_RB_2011G, "2011G", rb2011g_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb4xx.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb4xx.c
new file mode 100644
index 0000000000..ae0a772d5b
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb4xx.c
@@ -0,0 +1,470 @@
+/*
+ *  MikroTik RouterBOARD 4xx series support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/irq.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0)
+#include <linux/mdio-gpio.h>
+#else
+#include <linux/platform_data/mdio-gpio.h> 
+#endif
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/mmc_spi.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/rb4xx_cpld.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define RB4XX_GPIO_USER_LED	4
+#define RB4XX_GPIO_RESET_SWITCH	7
+
+#define RB4XX_GPIO_CPLD_BASE	32
+#define RB4XX_GPIO_CPLD_LED1	(RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED1)
+#define RB4XX_GPIO_CPLD_LED2	(RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED2)
+#define RB4XX_GPIO_CPLD_LED3	(RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED3)
+#define RB4XX_GPIO_CPLD_LED4	(RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED4)
+#define RB4XX_GPIO_CPLD_LED5	(RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED5)
+
+#define RB4XX_KEYS_POLL_INTERVAL	20	/* msecs */
+#define RB4XX_KEYS_DEBOUNCE_INTERVAL	(3 * RB4XX_KEYS_POLL_INTERVAL)
+
+static struct gpio_led rb4xx_leds_gpio[] __initdata = {
+	{
+		.name		= "rb4xx:yellow:user",
+		.gpio		= RB4XX_GPIO_USER_LED,
+		.active_low	= 0,
+	}, {
+		.name		= "rb4xx:green:led1",
+		.gpio		= RB4XX_GPIO_CPLD_LED1,
+		.active_low	= 1,
+	}, {
+		.name		= "rb4xx:green:led2",
+		.gpio		= RB4XX_GPIO_CPLD_LED2,
+		.active_low	= 1,
+	}, {
+		.name		= "rb4xx:green:led3",
+		.gpio		= RB4XX_GPIO_CPLD_LED3,
+		.active_low	= 1,
+	}, {
+		.name		= "rb4xx:green:led4",
+		.gpio		= RB4XX_GPIO_CPLD_LED4,
+		.active_low	= 1,
+	}, {
+		.name		= "rb4xx:green:led5",
+		.gpio		= RB4XX_GPIO_CPLD_LED5,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button rb4xx_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset_switch",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = RB4XX_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= RB4XX_GPIO_RESET_SWITCH,
+		.active_low	= 1,
+	}
+};
+
+static struct platform_device rb4xx_nand_device = {
+	.name	= "rb4xx-nand",
+	.id	= -1,
+};
+
+static struct ath79_pci_irq rb4xx_pci_irqs[] __initdata = {
+	{
+		.slot	= 17,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(2),
+	}, {
+		.slot	= 18,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(0),
+	}, {
+		.slot	= 18,
+		.pin	= 2,
+		.irq	= ATH79_PCI_IRQ(1),
+	}, {
+		.slot	= 19,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(1),
+	}, {
+		.slot	= 19,
+		.pin	= 2,
+		.irq	= ATH79_PCI_IRQ(2),
+	}, {
+		.slot	= 20,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(2),
+	}, {
+		.slot	= 20,
+		.pin	= 2,
+		.irq	= ATH79_PCI_IRQ(0),
+	}, {
+		.slot	= 21,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(0),
+	}, {
+		.slot	= 22,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(1),
+	}, {
+		.slot	= 22,
+		.pin	= 2,
+		.irq	= ATH79_PCI_IRQ(2),
+	}, {
+		.slot	= 23,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(2),
+	}, {
+		.slot	= 23,
+		.pin	= 2,
+		.irq	= ATH79_PCI_IRQ(0),
+	}
+};
+
+static struct mtd_partition rb4xx_partitions[] = {
+	{
+		.name		= "routerboot",
+		.offset		= 0,
+		.size		= 0x0b000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "hard_config",
+		.offset		= 0x0b000,
+		.size		= 0x01000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "bios",
+		.offset		= 0x0d000,
+		.size		= 0x02000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "soft_config",
+		.offset		= 0x0f000,
+		.size		= 0x01000,
+	}
+};
+
+static struct flash_platform_data rb4xx_flash_data = {
+	.type		= "pm25lv512",
+	.parts		= rb4xx_partitions,
+	.nr_parts	= ARRAY_SIZE(rb4xx_partitions),
+};
+
+static struct rb4xx_cpld_platform_data rb4xx_cpld_data = {
+	.gpio_base	= RB4XX_GPIO_CPLD_BASE,
+};
+
+static struct mmc_spi_platform_data rb4xx_mmc_data = {
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct spi_board_info rb4xx_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 25000000,
+		.modalias	= "m25p80",
+		.platform_data	= &rb4xx_flash_data,
+	}, {
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz	= 25000000,
+		.modalias	= "spi-rb4xx-cpld",
+		.platform_data	= &rb4xx_cpld_data,
+	}
+};
+
+static struct spi_board_info rb4xx_microsd_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 2,
+		.max_speed_hz	= 25000000,
+		.modalias	= "mmc_spi",
+		.platform_data	= &rb4xx_mmc_data,
+	}
+};
+
+
+static struct resource rb4xx_spi_resources[] = {
+	{
+		.start	= AR71XX_SPI_BASE,
+		.end	= AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device rb4xx_spi_device = {
+	.name		= "rb4xx-spi",
+	.id		= -1,
+	.resource	= rb4xx_spi_resources,
+	.num_resources	= ARRAY_SIZE(rb4xx_spi_resources),
+};
+
+static void __init rb4xx_generic_setup(void)
+{
+	ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
+				   AR71XX_GPIO_FUNC_SPI_CS2_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio),
+					rb4xx_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, RB4XX_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(rb4xx_gpio_keys),
+					rb4xx_gpio_keys);
+
+	spi_register_board_info(rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
+	platform_device_register(&rb4xx_spi_device);
+	platform_device_register(&rb4xx_nand_device);
+}
+
+static void __init rb411_setup(void)
+{
+	rb4xx_generic_setup();
+	spi_register_board_info(rb4xx_microsd_info,
+				ARRAY_SIZE(rb4xx_microsd_info));
+
+	ath79_register_mdio(0, 0xfffffffc);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = 0x00000003;
+
+	ath79_register_eth(0);
+
+	ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_411, "411", "MikroTik RouterBOARD 411/A/AH",
+	     rb411_setup);
+
+static void __init rb411u_setup(void)
+{
+	rb411_setup();
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_411U, "411U", "MikroTik RouterBOARD 411U",
+	     rb411u_setup);
+
+#define RB433_LAN_PHYMASK	BIT(0)
+#define RB433_WAN_PHYMASK	BIT(4)
+#define RB433_MDIO_PHYMASK	(RB433_LAN_PHYMASK | RB433_WAN_PHYMASK)
+
+static void __init rb433_setup(void)
+{
+	rb4xx_generic_setup();
+	spi_register_board_info(rb4xx_microsd_info,
+				ARRAY_SIZE(rb4xx_microsd_info));
+
+	ath79_register_mdio(0, ~RB433_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = RB433_LAN_PHYMASK;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = RB433_WAN_PHYMASK;
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_433, "433", "MikroTik RouterBOARD 433/AH",
+	     rb433_setup);
+
+static void __init rb433u_setup(void)
+{
+	rb433_setup();
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_433U, "433U", "MikroTik RouterBOARD 433UAH",
+	     rb433u_setup);
+
+static void __init rb435g_setup(void)
+{
+	rb4xx_generic_setup();
+
+	spi_register_board_info(rb4xx_microsd_info,
+				ARRAY_SIZE(rb4xx_microsd_info));
+
+	ath79_register_mdio(0, ~RB433_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = RB433_LAN_PHYMASK;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = RB433_WAN_PHYMASK;
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+	ath79_register_pci();
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_435G, "435G", "MikroTik RouterBOARD 435G",
+	     rb435g_setup);
+
+#define RB450_LAN_PHYMASK	BIT(0)
+#define RB450_WAN_PHYMASK	BIT(4)
+#define RB450_MDIO_PHYMASK	(RB450_LAN_PHYMASK | RB450_WAN_PHYMASK)
+
+static void __init rb450_generic_setup(int gige)
+{
+	rb4xx_generic_setup();
+	ath79_register_mdio(0, ~RB450_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth0_data.phy_if_mode = (gige) ?
+		PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = RB450_LAN_PHYMASK;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth1_data.phy_if_mode = (gige) ?
+		PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = RB450_WAN_PHYMASK;
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+}
+
+static void __init rb450_setup(void)
+{
+	rb450_generic_setup(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_450, "450", "MikroTik RouterBOARD 450",
+	     rb450_setup);
+
+static void __init rb450g_setup(void)
+{
+	rb450_generic_setup(1);
+	spi_register_board_info(rb4xx_microsd_info,
+				ARRAY_SIZE(rb4xx_microsd_info));
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G",
+	     rb450g_setup);
+
+static void __init rb493_setup(void)
+{
+	rb4xx_generic_setup();
+
+	ath79_register_mdio(0, 0x3fffff00);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = 0x00000001;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_493, "493", "MikroTik RouterBOARD 493/AH",
+	     rb493_setup);
+
+#define RB493G_GPIO_MDIO_MDC		7
+#define RB493G_GPIO_MDIO_DATA		8
+
+#define RB493G_MDIO_PHYMASK		BIT(0)
+
+static struct mdio_gpio_platform_data rb493g_mdio_data = {
+	.mdc		= RB493G_GPIO_MDIO_MDC,
+	.mdio		= RB493G_GPIO_MDIO_DATA,
+
+	.phy_mask	= ~RB493G_MDIO_PHYMASK,
+};
+
+static struct platform_device rb493g_mdio_device = {
+	.name 		= "mdio-gpio",
+	.id 		= -1,
+	.dev 		= {
+		.platform_data	= &rb493g_mdio_data,
+	},
+};
+
+static void __init rb493g_setup(void)
+{
+	ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
+				    AR71XX_GPIO_FUNC_SPI_CS2_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio),
+				    rb4xx_leds_gpio);
+
+	spi_register_board_info(rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
+	spi_register_board_info(rb4xx_microsd_info,
+				ARRAY_SIZE(rb4xx_microsd_info));
+
+	platform_device_register(&rb4xx_spi_device);
+	platform_device_register(&rb4xx_nand_device);
+
+	ath79_register_mdio(0, ~RB493G_MDIO_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = RB493G_MDIO_PHYMASK;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.mii_bus_dev = &rb493g_mdio_device.dev;
+	ath79_eth1_data.phy_mask = RB493G_MDIO_PHYMASK;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	platform_device_register(&rb493g_mdio_device);
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+
+	ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_493G, "493G", "MikroTik RouterBOARD 493G",
+	     rb493g_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb750.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb750.c
new file mode 100644
index 0000000000..5656d3c1f1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb750.c
@@ -0,0 +1,346 @@
+/*
+ *  MikroTik RouterBOARD 750/750GL support
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/export.h>
+#include <linux/pci.h>
+#include <linux/ath9k_platform.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/ar8216_platform.h>
+#include <linux/rle.h>
+#include <linux/routerboot.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/irq.h>
+#include <asm/mach-ath79/mach-rb750.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-usb.h"
+#include "dev-eth.h"
+#include "machtypes.h"
+#include "routerboot.h"
+
+static struct rb750_led_data rb750_leds[] = {
+	{
+		.name		= "rb750:green:act",
+		.mask		= RB750_LED_ACT,
+		.active_low	= 1,
+	}, {
+		.name		= "rb750:green:port1",
+		.mask		= RB750_LED_PORT5,
+		.active_low	= 1,
+	}, {
+		.name		= "rb750:green:port2",
+		.mask		= RB750_LED_PORT4,
+		.active_low	= 1,
+	}, {
+		.name		= "rb750:green:port3",
+		.mask		= RB750_LED_PORT3,
+		.active_low	= 1,
+	}, {
+		.name		= "rb750:green:port4",
+		.mask		= RB750_LED_PORT2,
+		.active_low	= 1,
+	}, {
+		.name		= "rb750:green:port5",
+		.mask		= RB750_LED_PORT1,
+		.active_low	= 1,
+	}
+};
+
+static struct rb750_led_data rb750gr3_leds[] = {
+	{
+		.name		= "rb750:green:act",
+		.mask		= RB7XX_LED_ACT,
+		.active_low	= 1,
+	},
+};
+
+static struct rb750_led_platform_data rb750_leds_data;
+static struct platform_device rb750_leds_device = {
+	.name	= "leds-rb750",
+	.dev	= {
+		.platform_data = &rb750_leds_data,
+	}
+};
+
+static struct rb7xx_nand_platform_data rb750_nand_data;
+static struct platform_device rb750_nand_device = {
+	.name	= "rb750-nand",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &rb750_nand_data,
+	}
+};
+
+static void rb750_latch_change(u32 mask_clr, u32 mask_set)
+{
+	static DEFINE_SPINLOCK(lock);
+	static u32 latch_set = RB750_LED_BITS | RB750_LVC573_LE;
+	static u32 latch_oe;
+	static u32 latch_clr;
+	unsigned long flags;
+	u32 t;
+
+	spin_lock_irqsave(&lock, flags);
+
+	if ((mask_clr & BIT(31)) != 0 &&
+	    (latch_set & RB750_LVC573_LE) == 0) {
+		goto unlock;
+	}
+
+	latch_set = (latch_set | mask_set) & ~mask_clr;
+	latch_clr = (latch_clr | mask_clr) & ~mask_set;
+
+	if (latch_oe == 0)
+		latch_oe = __raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_OE);
+
+	if (likely(latch_set & RB750_LVC573_LE)) {
+		void __iomem *base = ath79_gpio_base;
+
+		t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+		t |= mask_clr | latch_oe | mask_set;
+
+		__raw_writel(t, base + AR71XX_GPIO_REG_OE);
+		__raw_writel(latch_clr, base + AR71XX_GPIO_REG_CLEAR);
+		__raw_writel(latch_set, base + AR71XX_GPIO_REG_SET);
+	} else if (mask_clr & RB750_LVC573_LE) {
+		void __iomem *base = ath79_gpio_base;
+
+		latch_oe = __raw_readl(base + AR71XX_GPIO_REG_OE);
+		__raw_writel(RB750_LVC573_LE, base + AR71XX_GPIO_REG_CLEAR);
+		/* flush write */
+		__raw_readl(base + AR71XX_GPIO_REG_CLEAR);
+	}
+
+unlock:
+	spin_unlock_irqrestore(&lock, flags);
+}
+
+static void rb750_nand_enable_pins(void)
+{
+	rb750_latch_change(RB750_LVC573_LE, 0);
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE,
+				  AR724X_GPIO_FUNC_SPI_EN);
+}
+
+static void rb750_nand_disable_pins(void)
+{
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_SPI_EN,
+				  AR724X_GPIO_FUNC_JTAG_DISABLE);
+	rb750_latch_change(0, RB750_LVC573_LE);
+}
+
+static void __init rb750_setup(void)
+{
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				     AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				     AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				     AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				     AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+
+	rb750_leds_data.num_leds = ARRAY_SIZE(rb750_leds);
+	rb750_leds_data.leds = rb750_leds;
+	rb750_leds_data.latch_change = rb750_latch_change;
+	platform_device_register(&rb750_leds_device);
+
+	rb750_nand_data.nce_line = RB750_NAND_NCE;
+	rb750_nand_data.enable_pins = rb750_nand_enable_pins;
+	rb750_nand_data.disable_pins = rb750_nand_disable_pins;
+	rb750_nand_data.latch_change = rb750_latch_change;
+	platform_device_register(&rb750_nand_device);
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_750, "750i", "MikroTik RouterBOARD 750",
+	     rb750_setup);
+
+static struct ar8327_pad_cfg rb750gr3_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data rb750gr3_ar8327_data = {
+	.pad0_cfg = &rb750gr3_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	}
+};
+
+static struct mdio_board_info rb750g3_mdio_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &rb750gr3_ar8327_data,
+	},
+};
+
+static void rb750gr3_nand_enable_pins(void)
+{
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE,
+				  AR724X_GPIO_FUNC_SPI_EN |
+				  AR724X_GPIO_FUNC_SPI_CS_EN2);
+}
+
+static void rb750gr3_nand_disable_pins(void)
+{
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_SPI_EN |
+				  AR724X_GPIO_FUNC_SPI_CS_EN2,
+				  AR724X_GPIO_FUNC_JTAG_DISABLE);
+}
+
+static void rb750gr3_latch_change(u32 mask_clr, u32 mask_set)
+{
+	static DEFINE_SPINLOCK(lock);
+	static u32 latch_set = RB7XX_LED_ACT;
+	static u32 latch_clr;
+	void __iomem *base = ath79_gpio_base;
+	unsigned long flags;
+	u32 t;
+
+	spin_lock_irqsave(&lock, flags);
+
+	latch_set = (latch_set | mask_set) & ~mask_clr;
+	latch_clr = (latch_clr | mask_clr) & ~mask_set;
+
+	mask_set = latch_set & (RB7XX_USB_POWERON | RB7XX_MONITOR);
+	mask_clr = latch_clr & (RB7XX_USB_POWERON | RB7XX_MONITOR);
+
+	if ((latch_set ^ RB7XX_LED_ACT) & RB7XX_LED_ACT) {
+		/* enable output mode */
+		t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+		t |= RB7XX_LED_ACT;
+		__raw_writel(t, base + AR71XX_GPIO_REG_OE);
+
+		mask_clr |= RB7XX_LED_ACT;
+	} else {
+		/* disable output mode */
+		t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+		t &= ~RB7XX_LED_ACT;
+		__raw_writel(t, base + AR71XX_GPIO_REG_OE);
+	}
+
+	__raw_writel(mask_set, base + AR71XX_GPIO_REG_SET);
+	__raw_writel(mask_clr, base + AR71XX_GPIO_REG_CLEAR);
+
+	spin_unlock_irqrestore(&lock, flags);
+}
+
+static void __init rb750gr3_setup(void)
+{
+	ath79_register_mdio(0, 0x0);
+	mdiobus_register_board_info(rb750g3_mdio_info,
+				    ARRAY_SIZE(rb750g3_mdio_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_pll_data.pll_1000 = 0x62000000;
+
+	ath79_register_eth(0);
+
+	rb750_leds_data.num_leds = ARRAY_SIZE(rb750gr3_leds);
+	rb750_leds_data.leds = rb750gr3_leds;
+	rb750_leds_data.latch_change = rb750gr3_latch_change;
+	platform_device_register(&rb750_leds_device);
+
+	rb750_nand_data.nce_line = RB7XX_NAND_NCE;
+	rb750_nand_data.enable_pins = rb750gr3_nand_enable_pins;
+	rb750_nand_data.disable_pins = rb750gr3_nand_disable_pins;
+	rb750_nand_data.latch_change = rb750gr3_latch_change;
+	platform_device_register(&rb750_nand_device);
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_750G_R3, "750Gr3", "MikroTik RouterBOARD 750GL",
+	     rb750gr3_setup);
+
+#define RB751_HARDCONFIG	0x1f00b000
+#define RB751_HARDCONFIG_SIZE	0x1000
+
+static void __init rb751_wlan_setup(void)
+{
+	u8 *hardconfig = (u8 *) KSEG1ADDR(RB751_HARDCONFIG);
+	struct ath9k_platform_data *wmac_data;
+	u16 tag_len;
+	u8 *tag;
+	u16 mac_len;
+	u8 *mac;
+	int err;
+
+	wmac_data = ap9x_pci_get_wmac_data(0);
+	if (!wmac_data) {
+		pr_err("rb75x: unable to get address of wlan data\n");
+		return;
+	}
+
+	ap9x_pci_setup_wmac_led_pin(0, 9);
+
+	err = routerboot_find_tag(hardconfig, RB751_HARDCONFIG_SIZE,
+				  RB_ID_WLAN_DATA, &tag, &tag_len);
+	if (err) {
+		pr_err("rb75x: no calibration data found\n");
+		return;
+	}
+
+	err = rle_decode(tag, tag_len, (unsigned char *) wmac_data->eeprom_data,
+			 sizeof(wmac_data->eeprom_data), NULL, NULL);
+	if (err) {
+		pr_err("rb75x: unable to decode wlan eeprom data\n");
+		return;
+	}
+
+	err = routerboot_find_tag(hardconfig, RB751_HARDCONFIG_SIZE,
+                                 RB_ID_MAC_ADDRESS_PACK, &mac, &mac_len);
+	if (err) {
+		pr_err("rb75x: no mac address found\n");
+		return;
+	}
+
+	ap91_pci_init(NULL, mac);
+}
+
+static void __init rb751_setup(void)
+{
+	rb750_setup();
+	ath79_register_usb();
+	rb751_wlan_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_751, "751", "MikroTik RouterBOARD 751",
+	     rb751_setup);
+
+static void __init rb751g_setup(void)
+{
+	rb750gr3_setup();
+	ath79_register_usb();
+	rb751_wlan_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_751G, "751g", "MikroTik RouterBOARD 751G",
+	     rb751g_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c
new file mode 100644
index 0000000000..9ef5c4455e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb91x.c
@@ -0,0 +1,349 @@
+/*
+ *  MikroTik RouterBOARD 91X support
+ *
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) "rb91x: " fmt
+
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/74x164.h>
+#include <linux/spi/flash.h>
+#include <linux/routerboot.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/gpio-latch.h>
+#include <linux/platform_data/rb91x_nand.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/prom.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ath79_spi_platform.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+#include "routerboot.h"
+
+#define RB_ROUTERBOOT_OFFSET	0x0000
+#define RB_ROUTERBOOT_MIN_SIZE	0xb000
+#define RB_HARD_CFG_SIZE	0x1000
+#define RB_BIOS_OFFSET		0xd000
+#define RB_BIOS_SIZE		0x1000
+#define RB_SOFT_CFG_OFFSET	0xf000
+#define RB_SOFT_CFG_SIZE	0x1000
+
+#define RB91X_FLAG_USB		BIT(0)
+#define RB91X_FLAG_PCIE		BIT(1)
+
+#define RB91X_LATCH_GPIO_BASE	AR934X_GPIO_COUNT
+#define RB91X_LATCH_GPIO(_x)	(RB91X_LATCH_GPIO_BASE + (_x))
+
+#define RB91X_SSR_GPIO_BASE	(RB91X_LATCH_GPIO_BASE + AR934X_GPIO_COUNT)
+#define RB91X_SSR_GPIO(_x)	(RB91X_SSR_GPIO_BASE + (_x))
+
+#define RB91X_SSR_BIT_LED1		0
+#define RB91X_SSR_BIT_LED2		1
+#define RB91X_SSR_BIT_LED3		2
+#define RB91X_SSR_BIT_LED4		3
+#define RB91X_SSR_BIT_LED5		4
+#define RB91X_SSR_BIT_5			5
+#define RB91X_SSR_BIT_USB_POWER		6
+#define RB91X_SSR_BIT_PCIE_POWER	7
+
+#define RB91X_GPIO_SSR_STROBE	RB91X_LATCH_GPIO(0)
+#define RB91X_GPIO_LED_POWER	RB91X_LATCH_GPIO(1)
+#define RB91X_GPIO_LED_USER	RB91X_LATCH_GPIO(2)
+#define RB91X_GPIO_NAND_READ	RB91X_LATCH_GPIO(3)
+#define RB91X_GPIO_NAND_RDY	RB91X_LATCH_GPIO(4)
+#define RB91X_GPIO_NLE		RB91X_LATCH_GPIO(11)
+#define RB91X_GPIO_NAND_NRW	RB91X_LATCH_GPIO(12)
+#define RB91X_GPIO_NAND_NCE	RB91X_LATCH_GPIO(13)
+#define RB91X_GPIO_NAND_CLE	RB91X_LATCH_GPIO(14)
+#define RB91X_GPIO_NAND_ALE	RB91X_LATCH_GPIO(15)
+
+#define RB91X_GPIO_LED_1	RB91X_SSR_GPIO(RB91X_SSR_BIT_LED1)
+#define RB91X_GPIO_LED_2	RB91X_SSR_GPIO(RB91X_SSR_BIT_LED2)
+#define RB91X_GPIO_LED_3	RB91X_SSR_GPIO(RB91X_SSR_BIT_LED3)
+#define RB91X_GPIO_LED_4	RB91X_SSR_GPIO(RB91X_SSR_BIT_LED4)
+#define RB91X_GPIO_LED_5	RB91X_SSR_GPIO(RB91X_SSR_BIT_LED5)
+#define RB91X_GPIO_USB_POWER	RB91X_SSR_GPIO(RB91X_SSR_BIT_USB_POWER)
+#define RB91X_GPIO_PCIE_POWER	RB91X_SSR_GPIO(RB91X_SSR_BIT_PCIE_POWER)
+
+struct rb_board_info {
+	const char *name;
+	u32 flags;
+};
+
+static struct mtd_partition rb711gr100_spi_partitions[] = {
+	{
+		.name		= "routerboot",
+		.offset		= RB_ROUTERBOOT_OFFSET,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "hard_config",
+		.size		= RB_HARD_CFG_SIZE,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "bios",
+		.offset		= RB_BIOS_OFFSET,
+		.size		= RB_BIOS_SIZE,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "soft_config",
+		.size		= RB_SOFT_CFG_SIZE,
+	}
+};
+
+static struct flash_platform_data rb711gr100_spi_flash_data = {
+	.parts		= rb711gr100_spi_partitions,
+	.nr_parts	= ARRAY_SIZE(rb711gr100_spi_partitions),
+};
+
+static int rb711gr100_gpio_latch_gpios[AR934X_GPIO_COUNT] __initdata = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+	12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
+};
+
+static struct gpio_latch_platform_data rb711gr100_gpio_latch_data __initdata = {
+	.base = RB91X_LATCH_GPIO_BASE,
+	.num_gpios = ARRAY_SIZE(rb711gr100_gpio_latch_gpios),
+	.gpios = rb711gr100_gpio_latch_gpios,
+	.le_gpio_index = 11,
+	.le_active_low = true,
+};
+
+static struct rb91x_nand_platform_data rb711gr100_nand_data __initdata = {
+	.gpio_nce = RB91X_GPIO_NAND_NCE,
+	.gpio_ale = RB91X_GPIO_NAND_ALE,
+	.gpio_cle = RB91X_GPIO_NAND_CLE,
+	.gpio_rdy = RB91X_GPIO_NAND_RDY,
+	.gpio_read = RB91X_GPIO_NAND_READ,
+	.gpio_nrw = RB91X_GPIO_NAND_NRW,
+	.gpio_nle = RB91X_GPIO_NLE,
+};
+
+static u8 rb711gr100_ssr_initdata[] __initdata = {
+	BIT(RB91X_SSR_BIT_PCIE_POWER) |
+	BIT(RB91X_SSR_BIT_USB_POWER) |
+	BIT(RB91X_SSR_BIT_5)
+};
+
+static struct gen_74x164_chip_platform_data rb711gr100_ssr_data = {
+	.base = RB91X_SSR_GPIO_BASE,
+	.num_registers = ARRAY_SIZE(rb711gr100_ssr_initdata),
+	.init_data = rb711gr100_ssr_initdata,
+};
+
+static struct ath79_spi_controller_data rb711gr100_spi0_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 0,
+	.is_flash = true,
+};
+
+static struct ath79_spi_controller_data rb711gr100_spi1_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_GPIO,
+	.cs_line = RB91X_GPIO_SSR_STROBE,
+};
+
+static struct spi_board_info rb711gr100_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 25000000,
+		.modalias	= "m25p80",
+		.platform_data  = &rb711gr100_spi_flash_data,
+		.controller_data = &rb711gr100_spi0_cdata
+	}, {
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz	= 10000000,
+		.modalias	= "74x164",
+		.platform_data	= &rb711gr100_ssr_data,
+		.controller_data = &rb711gr100_spi1_cdata
+	}
+};
+
+static struct ath79_spi_platform_data rb711gr100_spi_data __initdata = {
+	.bus_num = 0,
+	.num_chipselect = 2,
+};
+
+static struct gpio_led rb711gr100_leds[] __initdata = {
+	{
+		.name		= "rb:green:led1",
+		.gpio		= RB91X_GPIO_LED_1,
+		.active_low	= 0,
+	},
+	{
+		.name		= "rb:green:led2",
+		.gpio		= RB91X_GPIO_LED_2,
+		.active_low	= 0,
+	},
+	{
+		.name		= "rb:green:led3",
+		.gpio		= RB91X_GPIO_LED_3,
+		.active_low	= 0,
+	},
+	{
+		.name		= "rb:green:led4",
+		.gpio		= RB91X_GPIO_LED_4,
+		.active_low	= 0,
+	},
+	{
+		.name		= "rb:green:led5",
+		.gpio		= RB91X_GPIO_LED_5,
+		.active_low	= 0,
+	},
+	{
+		.name		= "rb:green:user",
+		.gpio		= RB91X_GPIO_LED_USER,
+		.active_low	= 0,
+	},
+	{
+		.name		= "rb:green:power",
+		.gpio		= RB91X_GPIO_LED_POWER,
+		.active_low	= 0,
+	},
+};
+
+static struct at803x_platform_data rb91x_at803x_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 1,
+};
+
+static struct mdio_board_info rb91x_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &rb91x_at803x_data,
+	},
+};
+
+static void __init rb711gr100_init_partitions(const struct rb_info *info)
+{
+	rb711gr100_spi_partitions[0].size = info->hard_cfg_offs;
+	rb711gr100_spi_partitions[1].offset = info->hard_cfg_offs;
+
+	rb711gr100_spi_partitions[3].offset = info->soft_cfg_offs;
+}
+
+void __init rb711gr100_wlan_init(void)
+{
+	char *caldata;
+	u8 wlan_mac[ETH_ALEN];
+
+	caldata = rb_get_wlan_data();
+	if (caldata == NULL)
+		return;
+
+	ath79_init_mac(wlan_mac, ath79_mac_base, 1);
+	ath79_register_wmac(caldata + 0x1000, wlan_mac);
+
+	kfree(caldata);
+}
+
+#define RB_BOARD_INFO(_name, _flags)	\
+	{				\
+		.name = (_name),	\
+		.flags = (_flags),	\
+	}
+
+static const struct rb_board_info rb711gr100_boards[] __initconst = {
+	RB_BOARD_INFO("911G-2HPnD", 0),
+	RB_BOARD_INFO("911G-5HPnD", 0),
+	RB_BOARD_INFO("912UAG-2HPnD", RB91X_FLAG_USB | RB91X_FLAG_PCIE),
+	RB_BOARD_INFO("912UAG-5HPnD", RB91X_FLAG_USB | RB91X_FLAG_PCIE),
+};
+
+static u32 rb711gr100_get_flags(const struct rb_info *info)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rb711gr100_boards); i++) {
+		const struct rb_board_info *bi;
+
+		bi = &rb711gr100_boards[i];
+		if (strcmp(info->board_name, bi->name) == 0)
+			return bi->flags;
+	}
+
+	return 0;
+}
+
+static void __init rb711gr100_setup(void)
+{
+	const struct rb_info *info;
+	char buf[64];
+	u32 flags;
+
+	info = rb_init_info((void *) KSEG1ADDR(0x1f000000), 0x10000);
+	if (!info)
+		return;
+
+	scnprintf(buf, sizeof(buf), "Mikrotik RouterBOARD %s",
+		  (info->board_name) ? info->board_name : "");
+	mips_set_machine_name(buf);
+
+	rb711gr100_init_partitions(info);
+	ath79_register_spi(&rb711gr100_spi_data, rb711gr100_spi_info,
+			   ARRAY_SIZE(rb711gr100_spi_info));
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_RXD_DELAY |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(rb91x_mdio0_info,
+				    ARRAY_SIZE(rb91x_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_pll_data.pll_1000 = 0x02000000;
+
+	ath79_register_eth(0);
+
+	rb711gr100_wlan_init();
+
+	platform_device_register_data(NULL, "rb91x-nand", -1,
+				      &rb711gr100_nand_data,
+				      sizeof(rb711gr100_nand_data));
+
+	platform_device_register_data(NULL, "gpio-latch", -1,
+				      &rb711gr100_gpio_latch_data,
+				      sizeof(rb711gr100_gpio_latch_data));
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rb711gr100_leds),
+				 rb711gr100_leds);
+
+	flags = rb711gr100_get_flags(info);
+
+	if (flags & RB91X_FLAG_USB)
+		ath79_register_usb();
+
+	if (flags & RB91X_FLAG_PCIE)
+		ath79_register_pci();
+
+}
+
+MIPS_MACHINE_NONAME(ATH79_MACH_RB_711GR100, "711Gr100", rb711gr100_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb922.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb922.c
new file mode 100644
index 0000000000..c88c522b80
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb922.c
@@ -0,0 +1,236 @@
+/*
+ *  MikroTik RouterBOARD 91X support
+ *
+ *  Copyright (C) 2015 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/phy.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/routerboot.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/prom.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-spi.h"
+#include "machtypes.h"
+#include "pci.h"
+#include "routerboot.h"
+
+#define RB922_GPIO_LED_USR	12
+#define RB922_GPIO_USB_POWER	13
+#define RB922_GPIO_FAN_CTRL	14
+#define RB922_GPIO_BTN_RESET	20
+#define RB922_GPIO_NAND_NCE	23
+
+#define RB922_PHY_ADDR		4
+
+#define RB922_KEYS_POLL_INTERVAL	20	/* msecs */
+#define RB922_KEYS_DEBOUNCE_INTERVAL	(3 * RB922_KEYS_POLL_INTERVAL)
+
+#define RB_ROUTERBOOT_OFFSET	0x0000
+#define RB_ROUTERBOOT_MIN_SIZE	0xb000
+#define RB_HARD_CFG_SIZE	0x1000
+#define RB_BIOS_OFFSET		0xd000
+#define RB_BIOS_SIZE		0x1000
+#define RB_SOFT_CFG_OFFSET	0xf000
+#define RB_SOFT_CFG_SIZE	0x1000
+
+static struct mtd_partition rb922gs_spi_partitions[] = {
+	{
+		.name		= "routerboot",
+		.offset		= RB_ROUTERBOOT_OFFSET,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "hard_config",
+		.size		= RB_HARD_CFG_SIZE,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "bios",
+		.offset		= RB_BIOS_OFFSET,
+		.size		= RB_BIOS_SIZE,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "soft_config",
+		.size		= RB_SOFT_CFG_SIZE,
+	}
+};
+
+static struct flash_platform_data rb922gs_spi_flash_data = {
+	.parts		= rb922gs_spi_partitions,
+	.nr_parts	= ARRAY_SIZE(rb922gs_spi_partitions),
+};
+
+static struct gpio_led rb922gs_leds[] __initdata = {
+	{
+		.name		= "rb:green:user",
+		.gpio		= RB922_GPIO_LED_USR,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button rb922gs_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = RB922_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= RB922_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct at803x_platform_data rb922gs_at803x_data = {
+	.disable_smarteee = 1,
+};
+
+static struct mdio_board_info rb922gs_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = RB922_PHY_ADDR,
+		.platform_data = &rb922gs_at803x_data,
+	},
+};
+
+static void __init rb922gs_init_partitions(const struct rb_info *info)
+{
+	rb922gs_spi_partitions[0].size = info->hard_cfg_offs;
+	rb922gs_spi_partitions[1].offset = info->hard_cfg_offs;
+	rb922gs_spi_partitions[3].offset = info->soft_cfg_offs;
+}
+
+static void rb922gs_nand_select_chip(int chip_no)
+{
+	switch (chip_no) {
+	case 0:
+		gpio_set_value(RB922_GPIO_NAND_NCE, 0);
+		break;
+	default:
+		gpio_set_value(RB922_GPIO_NAND_NCE, 1);
+		break;
+	}
+	ndelay(500);
+}
+
+static struct nand_ecclayout rb922gs_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos		= { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static int rb922gs_nand_scan_fixup(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (mtd->writesize == 512) {
+		/*
+		 * Use the OLD Yaffs-1 OOB layout, otherwise RouterBoot
+		 * will not be able to find the kernel that we load.
+		 */
+		chip->ecc.layout = &rb922gs_nand_ecclayout;
+	}
+
+	return 0;
+}
+
+static struct mtd_partition rb922gs_nand_partitions[] = {
+	{
+		.name	= "booter",
+		.offset	= 0,
+		.size	= (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	},
+	{
+		.name	= "kernel",
+		.offset	= (256 * 1024),
+		.size	= (4 * 1024 * 1024) - (256 * 1024),
+	},
+	{
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static void __init rb922gs_nand_init(void)
+{
+	gpio_request_one(RB922_GPIO_NAND_NCE, GPIOF_OUT_INIT_HIGH, "NAND nCE");
+
+	ath79_nfc_set_scan_fixup(rb922gs_nand_scan_fixup);
+	ath79_nfc_set_parts(rb922gs_nand_partitions,
+			    ARRAY_SIZE(rb922gs_nand_partitions));
+	ath79_nfc_set_select_chip(rb922gs_nand_select_chip);
+	ath79_nfc_set_swap_dma(true);
+	ath79_register_nfc();
+}
+
+static void __init rb922gs_setup(void)
+{
+	const struct rb_info *info;
+	char buf[64];
+
+	info = rb_init_info((void *) KSEG1ADDR(0x1f000000), 0x10000);
+	if (!info)
+		return;
+
+	scnprintf(buf, sizeof(buf), "Mikrotik RouterBOARD %s",
+		  (info->board_name) ? info->board_name : "");
+	mips_set_machine_name(buf);
+
+	rb922gs_init_partitions(info);
+	ath79_register_m25p80(&rb922gs_spi_flash_data);
+
+	rb922gs_nand_init();
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(rb922gs_mdio0_info,
+				    ARRAY_SIZE(rb922gs_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(RB922_PHY_ADDR);
+	ath79_eth0_pll_data.pll_10 = 0x81001313;
+	ath79_eth0_pll_data.pll_100 = 0x81000101;
+	ath79_eth0_pll_data.pll_1000 = 0x8f000000;
+
+	ath79_register_eth(0);
+
+	ath79_register_pci();
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rb922gs_leds), rb922gs_leds);
+	ath79_register_gpio_keys_polled(-1, RB922_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(rb922gs_gpio_keys),
+					rb922gs_gpio_keys);
+
+	/* NOTE:
+	 * This only supports the RB911G-5HPacD board for now. For other boards
+	 * more devices must be registered based on the hardware options which
+	 * can be found in the hardware configuration of RouterBOOT.
+	 */
+}
+
+MIPS_MACHINE_NONAME(ATH79_MACH_RB_922GS, "922gs", rb922gs_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rb95x.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb95x.c
new file mode 100644
index 0000000000..c2261ab9f1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rb95x.c
@@ -0,0 +1,258 @@
+/*
+ *  MikroTik RouterBOARD 95X support
+ *
+ *  Copyright (C) 2012 Stijn Tintel <stijn@linux-ipv6.be>
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 Kamil Trzcinski <ayufan@ayufan.eu>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) "rb95x: " fmt
+
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/routerboot.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "routerboot.h"
+#include "dev-leds-gpio.h"
+
+#define RB95X_GPIO_NAND_NCE	14
+
+static struct mtd_partition rb95x_nand_partitions[] = {
+	{
+		.name	= "booter",
+		.offset	= 0,
+		.size	= (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	},
+	{
+		.name	= "kernel",
+		.offset	= (256 * 1024),
+		.size	= (4 * 1024 * 1024) - (256 * 1024),
+	},
+	{
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct gpio_led rb951ui_leds_gpio[] __initdata = {
+	{
+		.name		= "rb:green:wlan",
+		.gpio		= 11,
+		.active_low	= 1,
+	}, {
+		.name		= "rb:green:act",
+		.gpio		= 3,
+		.active_low	= 1,
+	}, {
+		.name		= "rb:green:port1",
+		.gpio		= 13,
+		.active_low	= 1,
+	}, {
+		.name		= "rb:green:port2",
+		.gpio		= 12,
+		.active_low	= 1,
+	}, {
+		.name		= "rb:green:port3",
+		.gpio		= 4,
+		.active_low	= 1,
+	}, {
+		.name		= "rb:green:port4",
+		.gpio		= 21,
+		.active_low	= 1,
+	}, {
+		.name		= "rb:green:port5",
+		.gpio		= 16,
+		.active_low	= 1,
+	}
+};
+
+static struct ar8327_pad_cfg rb95x_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data rb95x_ar8327_data = {
+	.pad0_cfg = &rb95x_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	}
+};
+
+static struct mdio_board_info rb95x_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &rb95x_ar8327_data,
+	},
+};
+
+void __init rb95x_wlan_init(void)
+{
+	char *art_buf;
+	u8 wlan_mac[ETH_ALEN];
+
+	art_buf = rb_get_wlan_data();
+	if (art_buf == NULL)
+		return;
+
+	ath79_init_mac(wlan_mac, ath79_mac_base, 11);
+	ath79_register_wmac(art_buf + 0x1000, wlan_mac);
+
+	kfree(art_buf);
+}
+
+static void rb95x_nand_select_chip(int chip_no)
+{
+	switch (chip_no) {
+	case 0:
+		gpio_set_value(RB95X_GPIO_NAND_NCE, 0);
+		break;
+	default:
+		gpio_set_value(RB95X_GPIO_NAND_NCE, 1);
+		break;
+	}
+	ndelay(500);
+}
+
+static struct nand_ecclayout rb95x_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos		= { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static int rb95x_nand_scan_fixup(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (mtd->writesize == 512) {
+		/*
+		 * Use the OLD Yaffs-1 OOB layout, otherwise RouterBoot
+		 * will not be able to find the kernel that we load.
+		 */
+		chip->ecc.layout = &rb95x_nand_ecclayout;
+	}
+
+	return 0;
+}
+
+void __init rb95x_nand_init(void)
+{
+	gpio_request_one(RB95X_GPIO_NAND_NCE, GPIOF_OUT_INIT_HIGH, "NAND nCE");
+
+	ath79_nfc_set_scan_fixup(rb95x_nand_scan_fixup);
+	ath79_nfc_set_parts(rb95x_nand_partitions,
+			    ARRAY_SIZE(rb95x_nand_partitions));
+	ath79_nfc_set_select_chip(rb95x_nand_select_chip);
+	ath79_nfc_set_swap_dma(true);
+	ath79_register_nfc();
+}
+
+static int __init rb95x_setup(void)
+{
+	const struct rb_info *info;
+
+	info = rb_init_info((void *)(KSEG1ADDR(AR71XX_SPI_BASE)), 0x10000);
+	if (!info)
+		return -EINVAL;
+
+	rb95x_nand_init();
+
+	return 0;
+}
+
+static void __init rb951g_setup(void)
+{
+	if (rb95x_setup())
+		return;
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(0, 0x0);
+
+	mdiobus_register_board_info(rb95x_mdio0_info,
+				    ARRAY_SIZE(rb95x_mdio0_info));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_register_eth(0);
+
+	rb95x_wlan_init();
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_951G, "951G", "MikroTik RouterBOARD 951G-2HnD",
+	     rb951g_setup);
+
+static void __init rb951ui_setup(void)
+{
+	if (rb95x_setup())
+		return;
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	gpio_request_one(20, GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+
+	gpio_request_one(2, GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "POE power");
+
+	rb95x_wlan_init();
+	ath79_register_usb();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rb951ui_leds_gpio),
+				 rb951ui_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_951U, "951HnD", "MikroTik RouterBOARD 951Ui-2HnD",
+	     rb951ui_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rbsxtlite.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rbsxtlite.c
new file mode 100644
index 0000000000..94e0b4483e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rbsxtlite.c
@@ -0,0 +1,238 @@
+/*
+ *  MikroTik RouterBOARD SXT Lite support
+ *
+ *  Copyright (C) 2012 Stijn Tintel <stijn@linux-ipv6.be>
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 Vyacheslav Adamanov <adamanov@gmail.com>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) "sxtlite: " fmt
+
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/rle.h>
+#include <linux/routerboot.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-wmac.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "routerboot.h"
+#include <linux/ar8216_platform.h>
+
+#define SXTLITE_GPIO_NAND_NCE  14
+#define SXTLITE_GPIO_LED_USER 3
+#define SXTLITE_GPIO_LED_1 13
+#define SXTLITE_GPIO_LED_2 12
+#define SXTLITE_GPIO_LED_3 4
+#define SXTLITE_GPIO_LED_4 21
+#define SXTLITE_GPIO_LED_5 18
+#define SXTLITE_GPIO_LED_POWER 11
+
+#define SXTLITE_GPIO_BUZZER 19
+
+#define SXTLITE_GPIO_BTN_RESET 15
+
+#define SXTLITE_KEYS_POLL_INTERVAL 20
+#define SXTLITE_KEYS_DEBOUNCE_INTERVAL (3 * SXTLITE_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition rbsxtlite_nand_partitions[] = {
+	{
+		.name   = "booter",
+		.offset = 0,
+		.size   = (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	},
+	{
+		.name   = "kernel",
+		.offset = (256 * 1024),
+		.size   = (4 * 1024 * 1024) - (256 * 1024),
+	},
+	{
+		.name   = "rootfs",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size   = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct gpio_led rbsxtlite_leds_gpio[] __initdata = {
+	{
+		.name		=	"rb:green:user",
+		.gpio		=	SXTLITE_GPIO_LED_USER,
+		.active_low	=	1,
+	},
+	{
+		.name		=	"rb:green:led1",
+		.gpio		=	SXTLITE_GPIO_LED_1,
+		.active_low	=	1,
+	},
+	{
+		.name		=	"rb:green:led2",
+		.gpio		=	SXTLITE_GPIO_LED_2,
+		.active_low	=	1,
+	},
+	{
+		.name		=	"rb:green:led3",
+		.gpio		=	SXTLITE_GPIO_LED_3,
+		.active_low	=	1,
+	},
+	{
+		.name		=	"rb:green:led4",
+		.gpio		=	SXTLITE_GPIO_LED_4,
+		.active_low	=	1,
+	},
+	{
+		.name		=	"rb:green:led5",
+		.gpio		=	SXTLITE_GPIO_LED_5,
+		.active_low	=	1,
+	},
+	{
+		.name		=	"rb:green:power",
+		.gpio		=	SXTLITE_GPIO_LED_POWER,
+	},
+};
+
+static struct gpio_keys_button rbsxtlite_gpio_keys[] __initdata = {
+	{
+		.desc		=	"Reset button",
+		.type		=	EV_KEY,
+		.code		=	KEY_RESTART,
+		.debounce_interval	=	SXTLITE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		=	SXTLITE_GPIO_BTN_RESET,
+		.active_low	=	0,
+	},
+};
+
+static int __init rbsxtlite_rbinfo_init(void)
+{
+	const struct rb_info *info;
+
+	info = rb_init_info((void *)(KSEG1ADDR(AR71XX_SPI_BASE)), 0x10000);
+	if (!info)
+		return -EINVAL;
+	return 0;
+
+}
+
+void __init rbsxtlite_wlan_init(void)
+{
+	char *art_buf;
+	u8 wlan_mac[ETH_ALEN];
+
+	art_buf = rb_get_wlan_data();
+	if (art_buf == NULL)
+		return;
+
+	ath79_init_mac(wlan_mac, ath79_mac_base, 1);
+	ath79_register_wmac(art_buf + 0x1000, wlan_mac);
+
+	kfree(art_buf);
+}
+
+static void rbsxtlite_nand_select_chip(int chip_no)
+{
+	switch (chip_no) {
+	case 0:
+		gpio_set_value(SXTLITE_GPIO_NAND_NCE, 0);
+		break;
+	default:
+		gpio_set_value(SXTLITE_GPIO_NAND_NCE, 1);
+		break;
+	}
+	ndelay(500);
+}
+
+static struct nand_ecclayout rbsxtlite_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos	 = { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static int rbsxtlite_nand_scan_fixup(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	if (mtd->writesize == 512) {
+		/*
+		* Use the OLD Yaffs-1 OOB layout, otherwise RouterBoot
+		* will not be able to find the kernel that we load.
+		*/
+		chip->ecc.layout = &rbsxtlite_nand_ecclayout;
+	}
+
+	return 0;
+}
+
+void __init rbsxtlite_gpio_init(void)
+{
+	gpio_request_one(SXTLITE_GPIO_NAND_NCE, GPIOF_OUT_INIT_HIGH, "NAND nCE");
+}
+
+void __init rbsxtlite_nand_init(void)
+{
+	ath79_nfc_set_scan_fixup(rbsxtlite_nand_scan_fixup);
+	ath79_nfc_set_parts(rbsxtlite_nand_partitions,
+			   ARRAY_SIZE(rbsxtlite_nand_partitions));
+	ath79_nfc_set_select_chip(rbsxtlite_nand_select_chip);
+	ath79_nfc_set_swap_dma(true);
+	ath79_register_nfc();
+}
+
+
+static void __init rbsxtlite_setup(void)
+{
+	if(rbsxtlite_rbinfo_init())
+		return;
+	rbsxtlite_nand_init();
+	rbsxtlite_wlan_init();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rbsxtlite_leds_gpio),
+				 rbsxtlite_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, SXTLITE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(rbsxtlite_gpio_keys),
+					rbsxtlite_gpio_keys);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* GMAC0 is left unused */
+
+	/* GMAC1 is connected to MAC0 on the internal switch */
+	/* The ethernet port connects to PHY P0, which connects to MAC1
+	   on the internal switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+
+}
+
+
+MIPS_MACHINE(ATH79_MACH_RB_SXTLITE2ND, "sxt2n", "Mikrotik RouterBOARD SXT Lite2",
+	    rbsxtlite_setup);
+
+MIPS_MACHINE(ATH79_MACH_RB_SXTLITE5ND, "sxt5n", "Mikrotik RouterBOARD SXT Lite5",
+	    rbsxtlite_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-rw2458n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-rw2458n.c
new file mode 100644
index 0000000000..bb7c2475bd
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-rw2458n.c
@@ -0,0 +1,91 @@
+/*
+ *  Redwave RW2458N support
+ *
+ *  Copyright (C) 2011-2013 Cezary Jackiewicz <cezary@eko.one.pl>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define RW2458N_GPIO_LED_D3	1
+#define RW2458N_GPIO_LED_D4	0
+#define RW2458N_GPIO_LED_D5	11
+#define RW2458N_GPIO_LED_D6	7
+#define RW2458N_GPIO_BTN_RESET	12
+
+#define RW2458N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define RW2458N_KEYS_DEBOUNCE_INTERVAL	(3 * RW2458N_KEYS_POLL_INTERVAL)
+
+static struct gpio_keys_button rw2458n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = RW2458N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= RW2458N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+#define RW2458N_WAN_PHYMASK	BIT(4)
+
+static struct gpio_led rw2458n_leds_gpio[] __initdata = {
+	{
+		.name		= "rw2458n:green:d3",
+		.gpio		= RW2458N_GPIO_LED_D3,
+		.active_low	= 1,
+	}, {
+		.name		= "rw2458n:green:d4",
+		.gpio		= RW2458N_GPIO_LED_D4,
+		.active_low	= 1,
+	}, {
+		.name		= "rw2458n:green:d5",
+		.gpio		= RW2458N_GPIO_LED_D5,
+		.active_low	= 1,
+	}, {
+		.name		= "rw2458n:green:d6",
+		.gpio		= RW2458N_GPIO_LED_D6,
+		.active_low	= 1,
+	}
+};
+
+static void __init rw2458n_setup(void)
+{
+	u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_mdio(0, ~RW2458N_WAN_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(rw2458n_leds_gpio),
+				 rw2458n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, RW2458N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(rw2458n_gpio_keys),
+					rw2458n_gpio_keys);
+	ath79_register_usb();
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_RW2458N, "RW2458N", "Redwave RW2458N",
+	    rw2458n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-smart-300.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-smart-300.c
new file mode 100644
index 0000000000..2520e960d3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-smart-300.c
@@ -0,0 +1,135 @@
+/*
+ *  NC-LINK SMART-300 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/gpio.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ag71xx_platform.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 SMART_300_GPIO_LED_WLAN		13
+#define SMART_300_GPIO_LED_WAN		18
+#define SMART_300_GPIO_LED_LAN4		19
+#define SMART_300_GPIO_LED_LAN3		12
+#define SMART_300_GPIO_LED_LAN2		21
+#define SMART_300_GPIO_LED_LAN1		20
+#define SMART_300_GPIO_LED_SYSTEM	15
+#define SMART_300_GPIO_LED_POWER	14
+
+#define SMART_300_GPIO_BTN_RESET	17
+#define SMART_300_GPIO_SW_RFKILL	16
+
+#define SMART_300_KEYS_POLL_INTERVAL	20	/* msecs */
+#define SMART_300_KEYS_DEBOUNCE_INTERVAL (3 * SMART_300_KEYS_POLL_INTERVAL)
+
+#define SMART_300_GPIO_MASK        0x007fffff
+
+static const char *smart_300_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data smart_300_flash_data = {
+	.part_probes	= smart_300_part_probes,
+};
+
+static struct gpio_led smart_300_leds_gpio[] __initdata = {
+	{
+		.name		= "nc-link:green:lan1",
+		.gpio		= SMART_300_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "nc-link:green:lan2",
+		.gpio		= SMART_300_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "nc-link:green:lan3",
+		.gpio		= SMART_300_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "nc-link:green:lan4",
+		.gpio		= SMART_300_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "nc-link:green:system",
+		.gpio		= SMART_300_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "nc-link:green:wan",
+		.gpio		= SMART_300_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "nc-link:green:wlan",
+		.gpio		= SMART_300_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button smart_300_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = SMART_300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= SMART_300_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static void __init smart_300_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(smart_300_leds_gpio),
+				 smart_300_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, SMART_300_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(smart_300_gpio_keys),
+					smart_300_gpio_keys);
+
+	ath79_register_m25p80(&smart_300_flash_data);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+
+	gpio_request(SMART_300_GPIO_LED_POWER, "power");
+	gpio_direction_output(SMART_300_GPIO_LED_POWER, GPIOF_OUT_INIT_LOW);
+}
+
+MIPS_MACHINE(ATH79_MACH_SMART_300, "SMART-300", "NC-LINK SMART-300",
+	     smart_300_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c
new file mode 100644
index 0000000000..eef5bcedc2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-som9331.c
@@ -0,0 +1,125 @@
+/*
+ *  OpenEmbed SOM9331 board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  5/27/2016 - Modified by Allan Nick Pedrana <nik9993@gmail.com>
+ *
+ *  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 <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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define SOM9331_GPIO_LED_WLAN   27
+#define SOM9331_GPIO_LED_SYSTEM 0
+#define SOM9331_GPIO_LED_2  13
+#define SOM9331_GPIO_LED_3  14
+#define SOM9331_GPIO_LED_5  16
+#define SOM9331_GPIO_LED_WAN    SOM9331_GPIO_LED_2
+#define SOM9331_GPIO_LED_LAN1   SOM9331_GPIO_LED_3
+#define SOM9331_GPIO_LED_LAN2   SOM9331_GPIO_LED_5
+#define SOM9331_GPIO_BTN_RESET  11
+
+#define SOM9331_KEYS_POLL_INTERVAL  20  /* msecs */
+#define SOM9331_KEYS_DEBOUNCE_INTERVAL  (3 * SOM9331_KEYS_POLL_INTERVAL)
+
+static const char *som9331_part_probes[] = {
+    "tp-link",
+    NULL,
+};
+
+static struct flash_platform_data som9331_flash_data = {
+    .part_probes    = som9331_part_probes,
+};
+
+static struct gpio_led som9331_leds_gpio[] __initdata = {
+    {
+        .name       = "som9331:red:wlan",
+        .gpio       = SOM9331_GPIO_LED_WLAN,
+        .active_low = 1,
+    },
+    {
+        .name       = "som9331:orange:wan",
+        .gpio       = SOM9331_GPIO_LED_WAN,
+        .active_low = 0,
+    },
+    {
+        .name       = "som9331:orange:lan1",
+        .gpio       = SOM9331_GPIO_LED_LAN1,
+        .active_low = 0,
+    },
+    {
+        .name       = "som9331:orange:lan2",
+        .gpio       = SOM9331_GPIO_LED_LAN2,
+        .active_low = 0,
+    },
+    {
+        .name       = "som9331:blue:system",
+        .gpio       = SOM9331_GPIO_LED_SYSTEM,
+        .active_low = 0,
+    },
+};
+
+static struct gpio_keys_button som9331_gpio_keys[] __initdata = {
+    {
+        .desc       = "reset",
+        .type       = EV_KEY,
+        .code       = KEY_RESTART,
+        .debounce_interval = SOM9331_KEYS_DEBOUNCE_INTERVAL,
+        .gpio       = SOM9331_GPIO_BTN_RESET,
+        .active_low = 0,
+    }
+};
+
+static void __init som9331_setup(void)
+{
+    u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+    u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+    ath79_setup_ar933x_phy4_switch(true, true);
+
+    ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+                    AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+                    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+                    AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+                    AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+    ath79_register_m25p80(&som9331_flash_data);
+    ath79_register_leds_gpio(-1, ARRAY_SIZE(som9331_leds_gpio),
+                 som9331_leds_gpio);
+    ath79_register_gpio_keys_polled(-1, SOM9331_KEYS_POLL_INTERVAL,
+                    ARRAY_SIZE(som9331_gpio_keys),
+                    som9331_gpio_keys);
+
+    ath79_register_usb();
+
+    ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+    ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+    ath79_register_mdio(0, 0x0);
+
+    /* LAN ports */
+    ath79_register_eth(1);
+
+    /* WAN port */
+    ath79_register_eth(0);
+
+    ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_SOM9331, "SOM9331", "OpenEmbed SOM9331", som9331_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tellstick-znet-lite.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tellstick-znet-lite.c
new file mode 100644
index 0000000000..0950d9a99d
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tellstick-znet-lite.c
@@ -0,0 +1,129 @@
+/*
+ *  Telldus TellStick ZNet Lite board support
+ *
+ *  Copyright (C) 2016 Micke Prag <micke.prag@telldus.se>
+ *
+ *  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 <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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TELLSTICK_GPIO_LED_SYSTEM	27
+#define TELLSTICK_GPIO_LED_BLUE	0
+#define TELLSTICK_GPIO_LED_RED	14
+#define TELLSTICK_GPIO_LED_GREEN	15
+#define TELLSTICK_GPIO_LED_LAN_GREEN	16
+#define TELLSTICK_GPIO_LED_LAN_ORANGE	17
+
+#define TELLSTICK_GPIO_BTN_RESET	11
+
+#define TELLSTICK_GPIO_RF433_RESET	13
+
+#define TELLSTICK_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TELLSTICK_KEYS_DEBOUNCE_INTERVAL	(3 * TELLSTICK_KEYS_POLL_INTERVAL)
+
+static const char *tellstick_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tellstick_flash_data = {
+	.part_probes	= tellstick_part_probes,
+};
+
+static struct gpio_led tellstick_leds_gpio[] __initdata = {
+	{
+		.name		= "tellstick:white:system",
+		.gpio		= TELLSTICK_GPIO_LED_SYSTEM,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tellstick:blue:status",
+		.gpio		= TELLSTICK_GPIO_LED_BLUE,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tellstick:red:status",
+		.gpio		= TELLSTICK_GPIO_LED_RED,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tellstick:green:status",
+		.gpio		= TELLSTICK_GPIO_LED_GREEN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tellstick:green:lan",
+		.gpio		= TELLSTICK_GPIO_LED_LAN_GREEN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tellstick:orange:lan",
+		.gpio		= TELLSTICK_GPIO_LED_LAN_ORANGE,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tellstick_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TELLSTICK_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TELLSTICK_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}
+};
+
+static void __init tellstick_znet_lite_setup(void)
+{
+	u8 *ee =  (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac[ETH_ALEN];
+	memcpy(&mac, (u8 *) KSEG1ADDR(0x1f01fc00), sizeof(mac));
+
+	ath79_gpio_function_disable(
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+		AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN
+	);
+
+	ath79_register_m25p80(&tellstick_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tellstick_leds_gpio),
+				 tellstick_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TELLSTICK_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tellstick_gpio_keys),
+					tellstick_gpio_keys);
+
+	gpio_request_one(TELLSTICK_GPIO_RF433_RESET,
+			 GPIOF_OUT_INIT_LOW | GPIOF_EXPORT_DIR_FIXED,
+			 "rf433 reset");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, (u8 *)mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+
+	// wlan0 mac needs to be different then eth0
+	mac[3] += 1;
+	ath79_register_wmac(ee, (u8 *)mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TELLSTICK_ZNET_LITE, "TELLSTICK-ZNET-LITE", "Telldus TellStick ZNet Lite",
+	     tellstick_znet_lite_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-632brp.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-632brp.c
new file mode 100644
index 0000000000..855664e562
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-632brp.c
@@ -0,0 +1,111 @@
+/*
+ *  TrendNET TEW-632BRP board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.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"
+#include "nvram.h"
+
+#define TEW_632BRP_GPIO_LED_STATUS	1
+#define TEW_632BRP_GPIO_LED_WPS		3
+#define TEW_632BRP_GPIO_LED_WLAN	6
+#define TEW_632BRP_GPIO_BTN_WPS		12
+#define TEW_632BRP_GPIO_BTN_RESET	21
+
+#define TEW_632BRP_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TEW_632BRP_KEYS_DEBOUNCE_INTERVAL (3 * TEW_632BRP_KEYS_POLL_INTERVAL)
+
+#define TEW_632BRP_CONFIG_ADDR	0x1f020000
+#define TEW_632BRP_CONFIG_SIZE	0x10000
+
+static struct gpio_led tew_632brp_leds_gpio[] __initdata = {
+	{
+		.name		= "tew-632brp:green:status",
+		.gpio		= TEW_632BRP_GPIO_LED_STATUS,
+		.active_low	= 1,
+	}, {
+		.name		= "tew-632brp:blue:wps",
+		.gpio		= TEW_632BRP_GPIO_LED_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "tew-632brp:green:wlan",
+		.gpio		= TEW_632BRP_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tew_632brp_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TEW_632BRP_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_632BRP_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TEW_632BRP_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_632BRP_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+#define TEW_632BRP_LAN_PHYMASK	BIT(0)
+#define TEW_632BRP_WAN_PHYMASK	BIT(4)
+#define TEW_632BRP_MDIO_MASK	(~(TEW_632BRP_LAN_PHYMASK | \
+				   TEW_632BRP_WAN_PHYMASK))
+
+static void __init tew_632brp_setup(void)
+{
+	const char *config = (char *) KSEG1ADDR(TEW_632BRP_CONFIG_ADDR);
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac[6];
+	u8 *wlan_mac = NULL;
+
+	if (ath79_nvram_parse_mac_addr(config, TEW_632BRP_CONFIG_SIZE,
+				       "lan_mac=", mac) == 0) {
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+		ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+		wlan_mac = mac;
+	}
+
+	ath79_register_mdio(0, TEW_632BRP_MDIO_MASK);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.phy_mask = TEW_632BRP_LAN_PHYMASK;
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = TEW_632BRP_WAN_PHYMASK;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tew_632brp_leds_gpio),
+				 tew_632brp_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TEW_632BRP_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tew_632brp_gpio_keys),
+					tew_632brp_gpio_keys);
+
+	ath79_register_wmac(eeprom, wlan_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TEW_632BRP, "TEW-632BRP", "TRENDnet TEW-632BRP",
+	     tew_632brp_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-673gru.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-673gru.c
new file mode 100644
index 0000000000..80a5443c70
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-673gru.c
@@ -0,0 +1,198 @@
+/*
+ *  TRENDnet TEW-673GRU board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/rtl8366.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define TEW673GRU_GPIO_LCD_SCK		0
+#define TEW673GRU_GPIO_LCD_MOSI		1
+#define TEW673GRU_GPIO_LCD_MISO		2
+#define TEW673GRU_GPIO_LCD_CS		6
+
+#define TEW673GRU_GPIO_LED_WPS		9
+
+#define TEW673GRU_GPIO_BTN_RESET	3
+#define TEW673GRU_GPIO_BTN_WPS		8
+
+#define TEW673GRU_GPIO_RTL8366_SDA	5
+#define TEW673GRU_GPIO_RTL8366_SCK	7
+
+#define TEW673GRU_KEYS_POLL_INTERVAL	20 /* msecs */
+#define TEW673GRU_KEYS_DEBOUNCE_INTERVAL (3 * TEW673GRU_KEYS_POLL_INTERVAL)
+
+#define TEW673GRU_CAL0_OFFSET		0x1000
+#define TEW673GRU_CAL1_OFFSET		0x5000
+#define TEW673GRU_MAC0_OFFSET		0xffa0
+#define TEW673GRU_MAC1_OFFSET		0xffb4
+
+#define TEW673GRU_CAL_LOCATION_0	0x1f660000
+#define TEW673GRU_CAL_LOCATION_1	0x1f7f0000
+
+static struct gpio_led tew673gru_leds_gpio[] __initdata = {
+	{
+		.name		= "trendnet:blue:wps",
+		.gpio		= TEW673GRU_GPIO_LED_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tew673gru_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TEW673GRU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW673GRU_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TEW673GRU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW673GRU_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct rtl8366_initval tew673gru_rtl8366s_initvals[] = {
+	{ .reg = 0x06, .val = 0x0108 },
+};
+
+static struct rtl8366_platform_data tew673gru_rtl8366s_data = {
+	.gpio_sda	= TEW673GRU_GPIO_RTL8366_SDA,
+	.gpio_sck	= TEW673GRU_GPIO_RTL8366_SCK,
+	.num_initvals	= ARRAY_SIZE(tew673gru_rtl8366s_initvals),
+	.initvals	= tew673gru_rtl8366s_initvals,
+};
+
+static struct platform_device tew673gru_rtl8366s_device = {
+	.name		= RTL8366S_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &tew673gru_rtl8366s_data,
+	}
+};
+
+static struct spi_board_info tew673gru_spi_info[] = {
+	{
+		.bus_num	= 1,
+		.chip_select	= 0,
+		.max_speed_hz	= 400000,
+		.modalias	= "spidev",
+		.mode		= SPI_MODE_2,
+		.controller_data = (void *) TEW673GRU_GPIO_LCD_CS,
+	},
+};
+
+static struct spi_gpio_platform_data tew673gru_spi_data = {
+	.sck		= TEW673GRU_GPIO_LCD_SCK,
+	.miso		= TEW673GRU_GPIO_LCD_MISO,
+	.mosi		= TEW673GRU_GPIO_LCD_MOSI,
+	.num_chipselect = 1,
+};
+
+static struct platform_device tew673gru_spi_device = {
+	.name		= "spi_gpio",
+	.id		= 1,
+	.dev = {
+		.platform_data = &tew673gru_spi_data,
+	},
+};
+
+static bool __init tew673gru_is_caldata_valid(u8 *p)
+{
+	u16 *magic0, *magic1;
+
+	magic0 = (u16 *)(p + TEW673GRU_CAL0_OFFSET);
+	magic1 = (u16 *)(p + TEW673GRU_CAL1_OFFSET);
+
+	return (*magic0 == 0xa55a && *magic1 == 0xa55a);
+}
+
+static void __init tew673gru_wlan_init(void)
+{
+	u8 mac1[ETH_ALEN], mac2[ETH_ALEN];
+	u8 *caldata;
+
+	caldata = (u8 *) KSEG1ADDR(TEW673GRU_CAL_LOCATION_0);
+	if (!tew673gru_is_caldata_valid(caldata)) {
+		caldata = (u8 *)KSEG1ADDR(TEW673GRU_CAL_LOCATION_1);
+		if (!tew673gru_is_caldata_valid(caldata)) {
+			pr_err("no calibration data found\n");
+			return;
+		}
+	}
+
+	ath79_parse_ascii_mac(caldata + TEW673GRU_MAC0_OFFSET, mac1);
+	ath79_parse_ascii_mac(caldata + TEW673GRU_MAC1_OFFSET, mac2);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 2);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac1, 3);
+
+	ap9x_pci_setup_wmac_led_pin(0, 5);
+	ap9x_pci_setup_wmac_led_pin(1, 5);
+
+	ap94_pci_init(caldata + TEW673GRU_CAL0_OFFSET, mac1,
+		      caldata + TEW673GRU_CAL1_OFFSET, mac2);
+}
+
+static void __init tew673gru_setup(void)
+{
+	tew673gru_wlan_init();
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_eth0_data.mii_bus_dev = &tew673gru_rtl8366s_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_pll_data.pll_1000 = 0x11110000;
+
+	ath79_eth1_data.mii_bus_dev = &tew673gru_rtl8366s_device.dev;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = 0x10;
+	ath79_eth1_pll_data.pll_1000 = 0x11110000;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tew673gru_leds_gpio),
+				 tew673gru_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TEW673GRU_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tew673gru_gpio_keys),
+					tew673gru_gpio_keys);
+
+	ath79_register_usb();
+
+	platform_device_register(&tew673gru_rtl8366s_device);
+
+	spi_register_board_info(tew673gru_spi_info,
+				ARRAY_SIZE(tew673gru_spi_info));
+	platform_device_register(&tew673gru_spi_device);
+}
+
+MIPS_MACHINE(ATH79_MACH_TEW_673GRU, "TEW-673GRU", "TRENDnet TEW-673GRU",
+	     tew673gru_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-712br.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-712br.c
new file mode 100644
index 0000000000..304b994887
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-712br.c
@@ -0,0 +1,153 @@
+/*
+ *  TRENDnet TEW-712BR board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <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 TEW_712BR_GPIO_BTN_WPS		11
+#define TEW_712BR_GPIO_BTN_RESET	12
+
+#define TEW_712BR_GPIO_LED_LAN1		13
+#define TEW_712BR_GPIO_LED_LAN2		14
+#define TEW_712BR_GPIO_LED_LAN3		15
+#define TEW_712BR_GPIO_LED_LAN4		16
+#define TEW_712BR_GPIO_LED_POWER_GREEN	20
+#define TEW_712BR_GPIO_LED_POWER_ORANGE	27
+#define TEW_712BR_GPIO_LED_WAN_GREEN	17
+#define TEW_712BR_GPIO_LED_WAN_ORANGE	23
+#define TEW_712BR_GPIO_LED_WLAN		0
+#define TEW_712BR_GPIO_LED_WPS		26
+
+#define TEW_712BR_GPIO_WAN_LED_ENABLE	1
+
+#define TEW_712BR_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TEW_712BR_KEYS_DEBOUNCE_INTERVAL (3 * TEW_712BR_KEYS_POLL_INTERVAL)
+
+#define TEW_712BR_ART_ADDRESS		0x1f010000
+#define TEW_712BR_CALDATA_OFFSET	0x1000
+
+#define TEW_712BR_MAC_PART_ADDRESS	0x1f020000
+#define TEW_712BR_LAN_MAC_OFFSET	0x04
+#define TEW_712BR_WAN_MAC_OFFSET	0x16
+
+static struct gpio_led tew_712br_leds_gpio[] __initdata = {
+	{
+		.name		= "trendnet:green:lan1",
+		.gpio		= TEW_712BR_GPIO_LED_LAN1,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:green:lan2",
+		.gpio		= TEW_712BR_GPIO_LED_LAN2,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:green:lan3",
+		.gpio		= TEW_712BR_GPIO_LED_LAN3,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:green:lan4",
+		.gpio		= TEW_712BR_GPIO_LED_LAN4,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:blue:wps",
+		.gpio		= TEW_712BR_GPIO_LED_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "trendnet:green:power",
+		.gpio		= TEW_712BR_GPIO_LED_POWER_GREEN,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:orange:power",
+		.gpio		= TEW_712BR_GPIO_LED_POWER_ORANGE,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:green:wan",
+		.gpio		= TEW_712BR_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "trendnet:orange:wan",
+		.gpio		= TEW_712BR_GPIO_LED_WAN_ORANGE,
+		.active_low	= 0,
+	}, {
+		.name		= "trendnet:green:wlan",
+		.gpio		= TEW_712BR_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tew_712br_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TEW_712BR_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_712BR_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TEW_712BR_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_712BR_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static void __init tew_712br_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(TEW_712BR_ART_ADDRESS);
+	u8 *mac = (u8 *) KSEG1ADDR(TEW_712BR_MAC_PART_ADDRESS);
+	u8 lan_mac[ETH_ALEN];
+	u8 wan_mac[ETH_ALEN];
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	gpio_request_one(TEW_712BR_GPIO_WAN_LED_ENABLE,
+			 GPIOF_OUT_INIT_LOW, "WAN LED enable");
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tew_712br_leds_gpio),
+				 tew_712br_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TEW_712BR_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tew_712br_gpio_keys),
+					tew_712br_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_parse_ascii_mac(mac + TEW_712BR_LAN_MAC_OFFSET, lan_mac);
+	ath79_parse_ascii_mac(mac + TEW_712BR_WAN_MAC_OFFSET, wan_mac);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, wan_mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, lan_mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art + TEW_712BR_CALDATA_OFFSET, wan_mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TEW_712BR, "TEW-712BR",
+	     "TRENDnet TEW-712BR", tew_712br_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-732br.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-732br.c
new file mode 100644
index 0000000000..1f26f6f4b0
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-732br.c
@@ -0,0 +1,127 @@
+/*
+ *  TRENDnet TEW-732BR board support
+ *
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 TEW_732BR_GPIO_BTN_WPS		16
+#define TEW_732BR_GPIO_BTN_RESET	17
+
+#define TEW_732BR_GPIO_LED_POWER_GREEN	4
+#define TEW_732BR_GPIO_LED_POWER_AMBER	14
+#define TEW_732BR_GPIO_LED_PLANET_GREEN	12
+#define TEW_732BR_GPIO_LED_PLANET_AMBER 22
+
+#define TEW_732BR_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TEW_732BR_KEYS_DEBOUNCE_INTERVAL (3 * TEW_732BR_KEYS_POLL_INTERVAL)
+
+#define TEW_732BR_ART_ADDRESS		0x1fff0000
+#define TEW_732BR_CALDATA_OFFSET	0x1000
+#define TEW_732BR_LAN_MAC_OFFSET	0xffa0
+#define TEW_732BR_WAN_MAC_OFFSET	0xffb4
+
+static struct gpio_led tew_732br_leds_gpio[] __initdata = {
+	{
+		.name		= "trendnet:green:power",
+		.gpio		= TEW_732BR_GPIO_LED_POWER_GREEN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "trendnet:amber:power",
+		.gpio		= TEW_732BR_GPIO_LED_POWER_AMBER,
+		.active_low	= 0,
+	},
+	{
+		.name		= "trendnet:green:wan",
+		.gpio		= TEW_732BR_GPIO_LED_PLANET_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "trendnet:amber:wan",
+		.gpio		= TEW_732BR_GPIO_LED_PLANET_AMBER,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tew_732br_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TEW_732BR_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_732BR_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TEW_732BR_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_732BR_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static void __init tew_732br_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(TEW_732BR_ART_ADDRESS);
+	u8 lan_mac[ETH_ALEN];
+	u8 wan_mac[ETH_ALEN];
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tew_732br_leds_gpio),
+				 tew_732br_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TEW_732BR_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tew_732br_gpio_keys),
+					tew_732br_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_parse_ascii_mac(art + TEW_732BR_LAN_MAC_OFFSET, lan_mac);
+	ath79_parse_ascii_mac(art + TEW_732BR_WAN_MAC_OFFSET, wan_mac);
+
+	ath79_register_wmac(art + TEW_732BR_CALDATA_OFFSET, lan_mac);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	/* LAN: GMAC1 is connected to the internal switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, lan_mac, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(1);
+
+	/* WAN: GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_init_mac(ath79_eth0_data.mac_addr, wan_mac, 0);
+
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_TEW_732BR, "TEW-732BR", "TRENDnet TEW-732BR",
+	     tew_732br_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-823dru.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-823dru.c
new file mode 100644
index 0000000000..cf863ac666
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tew-823dru.c
@@ -0,0 +1,181 @@
+/*
+ *  TRENDnet TEW-823DRU board support
+ *
+ *  Copyright (C) 2015 Cezary Jackiewicz <cezary.jackiewicz@gmail.com>
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TEW_823DRU_GPIO_LED_POWER_ORANGE	14
+#define TEW_823DRU_GPIO_LED_POWER_GREEN		19
+#define TEW_823DRU_GPIO_LED_PLANET_GREEN	22
+#define TEW_823DRU_GPIO_LED_PLANET_ORANGE	23
+
+#define TEW_823DRU_GPIO_BTN_WPS			16
+#define TEW_823DRU_GPIO_BTN_RESET		17
+
+#define TEW_823DRU_KEYS_POLL_INTERVAL		20	/* msecs */
+#define TEW_823DRU_KEYS_DEBOUNCE_INTERVAL	\
+					(3 * TEW_823DRU_KEYS_POLL_INTERVAL)
+
+#define TEW_823DRU_WMAC_CALDATA_OFFSET		0x1000
+
+#define TEW_823DRU_LAN_MAC_OFFSET	0x04
+#define TEW_823DRU_WAN_MAC_OFFSET	0x18
+
+static struct gpio_led tew_823dru_leds_gpio[] __initdata = {
+	{
+		.name		= "trendnet:green:power",
+		.gpio		= TEW_823DRU_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "trendnet:orange:power",
+		.gpio		= TEW_823DRU_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+	},
+	{
+		.name		= "trendnet:green:planet",
+		.gpio		= TEW_823DRU_GPIO_LED_PLANET_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "trendnet:orange:planet",
+		.gpio		= TEW_823DRU_GPIO_LED_PLANET_ORANGE,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tew_823dru_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TEW_823DRU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_823DRU_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TEW_823DRU_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TEW_823DRU_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+/* GMAC0 of the AR8327 switch is connected to the QCA9558 SoC via SGMII */
+static struct ar8327_pad_cfg tew_823dru_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+/* GMAC6 of the AR8327 switch is connected to the QCA9558 SoC via RGMII */
+static struct ar8327_pad_cfg tew_823dru_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data tew_823dru_ar8327_data = {
+	.pad0_cfg = &tew_823dru_ar8327_pad0_cfg,
+	.pad6_cfg = &tew_823dru_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info tew_823dru_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &tew_823dru_ar8327_data,
+	},
+};
+
+static void __init tew_823dru_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1ffe0000);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 lan_mac[ETH_ALEN];
+	u8 wan_mac[ETH_ALEN];
+
+	ath79_parse_ascii_mac(mac + TEW_823DRU_LAN_MAC_OFFSET, lan_mac);
+	ath79_parse_ascii_mac(mac + TEW_823DRU_WAN_MAC_OFFSET, wan_mac);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tew_823dru_leds_gpio),
+				 tew_823dru_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TEW_823DRU_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tew_823dru_gpio_keys),
+					tew_823dru_gpio_keys);
+
+	ath79_register_wmac(art + TEW_823DRU_WMAC_CALDATA_OFFSET, lan_mac);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, lan_mac, 0);
+	ath79_init_mac(ath79_eth0_data.mac_addr, wan_mac, 0);
+
+
+	mdiobus_register_board_info(tew_823dru_mdio0_info,
+			ARRAY_SIZE(tew_823dru_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_TEW_823DRU, "TEW-823DRU", "TRENDnet TEW-823DRU",
+	     tew_823dru_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr11u.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr11u.c
new file mode 100644
index 0000000000..74ccf639e0
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr11u.c
@@ -0,0 +1,183 @@
+/*
+ *  TP-LINK TL-MR11U/TL-MR3040 board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_MR11U_GPIO_LED_3G		27
+#define TL_MR11U_GPIO_LED_WLAN		26
+#define TL_MR11U_GPIO_LED_LAN		17
+
+#define TL_MR11U_GPIO_BTN_WPS		20
+#define TL_MR11U_GPIO_BTN_RESET		11
+
+#define TL_MR11U_GPIO_USB_POWER		8
+#define TL_MR3040_GPIO_USB_POWER	18
+
+#define TL_MR3040_V2_GPIO_BTN_SW1	19
+#define TL_MR3040_V2_GPIO_BTN_SW2	20
+
+#define TL_MR11U_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_MR11U_KEYS_DEBOUNCE_INTERVAL	(3 * TL_MR11U_KEYS_POLL_INTERVAL)
+
+static const char *tl_mr11u_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_mr11u_flash_data = {
+	.part_probes	= tl_mr11u_part_probes,
+};
+
+static struct gpio_led tl_mr11u_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:3g",
+		.gpio		= TL_MR11U_GPIO_LED_3G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_MR11U_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_MR11U_GPIO_LED_LAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_mr11u_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_MR11U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR11U_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_MR11U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR11U_GPIO_BTN_WPS,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tl_mr3040_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_MR11U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR11U_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "sw1",
+		.type		= EV_SW,
+		.code		= BTN_0,
+		.debounce_interval = TL_MR11U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3040_V2_GPIO_BTN_SW1,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "sw2",
+		.type		= EV_SW,
+		.code		= BTN_1,
+		.debounce_interval = TL_MR11U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3040_V2_GPIO_BTN_SW2,
+		.active_low	= 0,
+	}
+};
+
+static void __init common_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* Disable hardware control LAN1 and LAN2 LEDs, enabling GPIO14 and GPIO15 */
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(&tl_mr11u_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_mr11u_leds_gpio),
+				 tl_mr11u_leds_gpio);
+
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void __init tl_mr11u_setup(void)
+{
+	common_setup();
+
+	ath79_register_gpio_keys_polled(-1, TL_MR11U_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_mr11u_gpio_keys),
+					tl_mr11u_gpio_keys);
+	gpio_request_one(TL_MR11U_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR11U, "TL-MR11U", "TP-LINK TL-MR11U",
+	     tl_mr11u_setup);
+
+static void __init tl_mr3040_setup(void)
+{
+	common_setup();
+
+	ath79_register_gpio_keys_polled(-1, TL_MR11U_KEYS_POLL_INTERVAL,
+					1, tl_mr11u_gpio_keys);
+	gpio_request_one(TL_MR3040_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3040, "TL-MR3040", "TP-LINK TL-MR3040",
+	     tl_mr3040_setup);
+
+static void __init tl_mr3040_v2_setup(void)
+{
+	common_setup();
+
+	ath79_register_gpio_keys_polled(-1, TL_MR11U_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_mr3040_v2_gpio_keys),
+					tl_mr3040_v2_gpio_keys);
+	gpio_request_one(TL_MR3040_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3040_V2, "TL-MR3040-v2", "TP-LINK TL-MR3040 v2",
+	     tl_mr3040_v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr13u.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr13u.c
new file mode 100644
index 0000000000..84b6937849
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr13u.c
@@ -0,0 +1,107 @@
+/*
+ *  TP-LINK TL-MR13U board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_MR13U_GPIO_LED_SYSTEM	27
+
+#define TL_MR13U_GPIO_BTN_RESET		11
+#define TL_MR13U_GPIO_BTN_SW1		6
+#define TL_MR13U_GPIO_BTN_SW2		7
+
+#define TL_MR13U_GPIO_USB_POWER		18
+
+#define TL_MR13U_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_MR13U_KEYS_DEBOUNCE_INTERVAL	(3 * TL_MR13U_KEYS_POLL_INTERVAL)
+
+static const char *tl_mr13u_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_mr13u_flash_data = {
+	.part_probes	= tl_mr13u_part_probes,
+};
+
+static struct gpio_led tl_mr13u_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= TL_MR13U_GPIO_LED_SYSTEM,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tl_mr13u_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_MR13U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR13U_GPIO_BTN_RESET,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "sw1",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = TL_MR13U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR13U_GPIO_BTN_SW1,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "sw2",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = TL_MR13U_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR13U_GPIO_BTN_SW2,
+		.active_low	= 0,
+	},
+};
+
+static void __init tl_mr13u_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(&tl_mr13u_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_mr13u_leds_gpio),
+				 tl_mr13u_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_MR13U_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_mr13u_gpio_keys),
+					tl_mr13u_gpio_keys);
+
+	gpio_request_one(TL_MR13U_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR13U, "TL-MR13U", "TP-LINK TL-MR13U v1",
+	     tl_mr13u_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c
new file mode 100644
index 0000000000..0a9dfbc8a0
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c
@@ -0,0 +1,126 @@
+/*
+ *  TP-LINK TL-MR3020 board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_MR3020_GPIO_LED_3G		27
+#define TL_MR3020_GPIO_LED_WLAN		0
+#define TL_MR3020_GPIO_LED_LAN		17
+#define TL_MR3020_GPIO_LED_WPS		26
+
+#define TL_MR3020_GPIO_BTN_WPS		11
+#define TL_MR3020_GPIO_BTN_SW1		18
+#define TL_MR3020_GPIO_BTN_SW2		20
+
+#define TL_MR3020_GPIO_USB_POWER	8
+
+#define TL_MR3020_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_MR3020_KEYS_DEBOUNCE_INTERVAL	(3 * TL_MR3020_KEYS_POLL_INTERVAL)
+
+static const char *tl_mr3020_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_mr3020_flash_data = {
+	.part_probes	= tl_mr3020_part_probes,
+};
+
+static struct gpio_led tl_mr3020_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:3g",
+		.gpio		= TL_MR3020_GPIO_LED_3G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_MR3020_GPIO_LED_WLAN,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_MR3020_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wps",
+		.gpio		= TL_MR3020_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_mr3020_gpio_keys[] __initdata = {
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_MR3020_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3020_GPIO_BTN_WPS,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "sw1",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = TL_MR3020_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3020_GPIO_BTN_SW1,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "sw2",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = TL_MR3020_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3020_GPIO_BTN_SW2,
+		.active_low	= 0,
+	}
+};
+
+static void __init tl_mr3020_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(&tl_mr3020_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_mr3020_leds_gpio),
+				 tl_mr3020_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_MR3020_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_mr3020_gpio_keys),
+					tl_mr3020_gpio_keys);
+
+	gpio_request_one(TL_MR3020_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3020, "TL-MR3020", "TP-LINK TL-MR3020",
+	     tl_mr3020_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
new file mode 100644
index 0000000000..5924ac5048
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
@@ -0,0 +1,147 @@
+/*
+ *  TP-LINK TL-MR3220/3420 board support
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define TL_MR3X20_GPIO_LED_QSS		0
+#define TL_MR3X20_GPIO_LED_SYSTEM	1
+#define TL_MR3X20_GPIO_LED_3G		8
+
+#define TL_MR3X20_GPIO_BTN_RESET	11
+#define TL_MR3X20_GPIO_BTN_QSS		12
+
+#define TL_MR3X20_GPIO_USB_POWER	6
+
+#define TL_MR3X20_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_MR3X20_KEYS_DEBOUNCE_INTERVAL (3 * TL_MR3X20_KEYS_POLL_INTERVAL)
+
+static const char *tl_mr3x20_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_mr3x20_flash_data = {
+	.part_probes	= tl_mr3x20_part_probes,
+};
+
+static struct gpio_led tl_mr3x20_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_MR3X20_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_MR3X20_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:3g",
+		.gpio		= TL_MR3X20_GPIO_LED_3G,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_mr3x20_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3X20_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3X20_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static void __init tl_ap99_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_mr3x20_flash_data);
+
+	ath79_register_gpio_keys_polled(-1, TL_MR3X20_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(tl_mr3x20_gpio_keys),
+					 tl_mr3x20_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+	/* WAN port */
+	ath79_register_eth(0);
+
+	ap91_pci_init(ee, mac);
+}
+
+static void __init tl_mr3x20_usb_setup(void)
+{
+	/* enable power for the USB port */
+	gpio_request_one(TL_MR3X20_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+}
+
+static void __init tl_mr3220_setup(void)
+{
+	tl_ap99_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_mr3x20_leds_gpio),
+				 tl_mr3x20_leds_gpio);
+	ap9x_pci_setup_wmac_led_pin(0, 1);
+	tl_mr3x20_usb_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3220, "TL-MR3220", "TP-LINK TL-MR3220",
+	     tl_mr3220_setup);
+
+static void __init tl_mr3420_setup(void)
+{
+	tl_ap99_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_mr3x20_leds_gpio),
+				 tl_mr3x20_leds_gpio);
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+	tl_mr3x20_usb_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3420, "TL-MR3420", "TP-LINK TL-MR3420",
+	     tl_mr3420_setup);
+
+static void __init tl_wr841n_v7_setup(void)
+{
+	tl_ap99_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_mr3x20_leds_gpio) - 1,
+				 tl_mr3x20_leds_gpio);
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR841N_V7, "TL-WR841N-v7",
+	     "TP-LINK TL-WR841N/ND v7", tl_wr841n_v7_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa701nd-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa701nd-v2.c
new file mode 100644
index 0000000000..aab92b30d4
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa701nd-v2.c
@@ -0,0 +1,116 @@
+/*
+ *  TP-LINK TL-WA701ND v2 board support
+ *
+ *  Copyright (C) 2015 Luigi Tarenga <luigi.tarenga@gmail.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WA701NDV2_GPIO_LED_WLAN	0
+#define TL_WA701NDV2_GPIO_LED_QSS	1
+#define TL_WA701NDV2_GPIO_LED_LAN	17
+#define TL_WA701NDV2_GPIO_LED_SYSTEM	27
+
+#define TL_WA701NDV2_GPIO_BTN_RESET	11
+#define TL_WA701NDV2_GPIO_BTN_QSS	26
+
+#define TL_WA701NDV2_GPIO_USB_POWER	8
+
+#define TL_WA701NDV2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WA701NDV2_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WA701NDV2_KEYS_POLL_INTERVAL)
+
+static const char *tl_wa701ndv2_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wa701ndv2_flash_data = {
+	.part_probes	= tl_wa701ndv2_part_probes,
+};
+
+static struct gpio_led tl_wa701ndv2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WA701NDV2_GPIO_LED_WLAN,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WA701NDV2_GPIO_LED_QSS,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA701NDV2_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA701NDV2_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+        }
+};
+
+static struct gpio_keys_button tl_wa701ndv2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WA701NDV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA701NDV2_GPIO_BTN_RESET,
+		.active_low	= 0,
+	} , {
+                .desc		= "qss",
+                .type		= EV_KEY,
+                .code		= KEY_WPS_BUTTON,
+                .debounce_interval = TL_WA701NDV2_KEYS_DEBOUNCE_INTERVAL,
+                .gpio		= TL_WA701NDV2_GPIO_BTN_QSS,
+                .active_low	= 0,
+        }
+
+};
+
+static void __init tl_wa701ndv2_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa701ndv2_leds_gpio),
+				 tl_wa701ndv2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WA701NDV2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wa701ndv2_gpio_keys),
+					tl_wa701ndv2_gpio_keys);
+
+	gpio_request_one(TL_WA701NDV2_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_m25p80(&tl_wa701ndv2_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	/* ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1); */
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA701ND_V2, "TL-WA701ND-v2",
+	     "TP-LINK TL-WA701ND v2", tl_wa701ndv2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa7210n-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa7210n-v2.c
new file mode 100644
index 0000000000..276353a6c3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa7210n-v2.c
@@ -0,0 +1,125 @@
+/*
+ *  TP-LINK TL-WA7210N v2.1 board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Nicolas Braud-Santoni <nicolas@braud-santoni.eu>
+ *  Copyright (C) 2014 Alexander List <alex@graz.funkfeuer.at>
+ *  Copyright (C) 2015 Hendrik Frenzel <hfrenzel@scunc.net>
+ *
+ *  rebased on TL-WA7510Nv1 support,
+ *    Copyright (C) 2012 Stefan Helmert <helst_listen@aol.de>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-dsa.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"
+#include "pci.h"
+
+#include "common.h"
+
+#define TL_WA7210N_V2_GPIO_BTN_RESET    11
+#define TL_WA7210N_V2_KEYS_POLL_INT     20
+#define TL_WA7210N_V2_KEYS_DEBOUNCE_INT (3 * TL_WA7210N_V2_KEYS_POLL_INT)
+
+#define TL_WA7210N_V2_GPIO_LED_LAN  17
+#define TL_WA7210N_V2_GPIO_LED_SIG1 0
+#define TL_WA7210N_V2_GPIO_LED_SIG2 1
+#define TL_WA7210N_V2_GPIO_LED_SIG3 27
+#define TL_WA7210N_V2_GPIO_LED_SIG4 26
+
+#define  TL_WA7210N_V2_GPIO_LNA_EN 28
+
+static const char *tl_wa7210n_v2_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct gpio_keys_button tl_wa7210n_v2_gpio_keys[] __initdata = {
+	{
+		.desc              = "reset",
+		.type              = EV_KEY,
+		.code              = KEY_RESTART,
+		.debounce_interval = TL_WA7210N_V2_KEYS_DEBOUNCE_INT,
+		.gpio              = TL_WA7210N_V2_GPIO_BTN_RESET,
+		.active_low        = 0,
+	},
+};
+
+static struct gpio_led tl_wa7210n_v2_leds_gpio[] __initdata = {
+	{
+		.name       = "tp-link:green:lan",
+		.gpio       = TL_WA7210N_V2_GPIO_LED_LAN,
+		.active_low = 1,
+	}, {
+		.name       = "tp-link:green:signal1",
+		.gpio       = TL_WA7210N_V2_GPIO_LED_SIG1,
+		.active_low = 0,
+	}, {
+		.name       = "tp-link:green:signal2",
+		.gpio       = TL_WA7210N_V2_GPIO_LED_SIG2,
+		.active_low = 0,
+	}, {
+		.name       = "tp-link:green:signal3",
+		.gpio       = TL_WA7210N_V2_GPIO_LED_SIG3,
+		.active_low = 1,
+	}, {
+		.name       = "tp-link:green:signal4",
+		.gpio       = TL_WA7210N_V2_GPIO_LED_SIG4,
+		.active_low = 1,
+	},
+};
+
+static struct flash_platform_data tl_wa7210n_v2_flash_data = {
+	.part_probes    = tl_wa7210n_v2_part_probes,
+};
+
+static void __init tl_wa7210n_v2_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_gpio_keys_polled(-1, TL_WA7210N_V2_KEYS_POLL_INT,
+			ARRAY_SIZE(tl_wa7210n_v2_gpio_keys),
+			tl_wa7210n_v2_gpio_keys);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa7210n_v2_leds_gpio),
+			tl_wa7210n_v2_leds_gpio);
+
+	ath79_gpio_function_enable(TL_WA7210N_V2_GPIO_LNA_EN);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_wmac(ee, mac);
+
+	ath79_register_m25p80(&tl_wa7210n_v2_flash_data);
+
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA7210N_V2, "TL-WA7210N-v2", "TP-LINK TL-WA7210N v2",
+	tl_wa7210n_v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa801nd-v3.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa801nd-v3.c
new file mode 100644
index 0000000000..054c14ee73
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa801nd-v3.c
@@ -0,0 +1,136 @@
+/*
+ *  TP-LINK TL-WA801ND v3 adapted from TP-LINK TL-WR841N/ND v9
+ *
+ *  Copyright (C) 2014 Matthias Schiffer <mschiffer@universe-factory.net>
+ *  Copyright (C) 2016 Tiziano Bacocco <tizbac2@gmail.com>
+ *
+ *  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 TL_WA801NDV3_GPIO_LED_WLAN	12
+#define TL_WA801NDV3_GPIO_LED_SYSTEM	13
+#define TL_WA801NDV3_GPIO_LED_SECURITY_RED 11
+#define TL_WA801NDV3_GPIO_LED_SECURITY_GREEN 15
+#define TL_WA801NDV3_GPIO_LED_LAN 3
+
+#define TL_WA801NDV3_GPIO_BTN_RESET	2
+#define TL_WA801NDV3_GPIO_BTN_WIFI	1
+
+#define TL_WA801NDV3_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WA801NDV3_KEYS_DEBOUNCE_INTERVAL (3 * TL_WA801NDV3_KEYS_POLL_INTERVAL)
+
+static const char *tl_wa801n_v3_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wa801n_v3_flash_data = {
+	.part_probes	= tl_wa801n_v3_part_probes,
+};
+
+static struct gpio_led tl_wa801n_v3_leds_gpio[] __initdata = {
+  {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA801NDV3_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA801NDV3_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WA801NDV3_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:red:security",
+		.gpio		= TL_WA801NDV3_GPIO_LED_SECURITY_RED,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:security",
+		.gpio		= TL_WA801NDV3_GPIO_LED_SECURITY_GREEN,
+		.active_low	= 0,
+	}
+
+};
+
+static struct gpio_keys_button tl_wa801n_v3_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WA801NDV3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA801NDV3_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "WIFI button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WA801NDV3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA801NDV3_GPIO_BTN_WIFI,
+		.active_low	= 1,
+	}
+};
+
+
+static void __init tl_ap143_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&tl_wa801n_v3_flash_data);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_register_eth(0);
+
+	ath79_init_mac(tmpmac, mac, 0);
+	ath79_register_wmac(ee, tmpmac);
+}
+
+static void __init tl_wa801n_v3_setup(void)
+{
+	tl_ap143_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa801n_v3_leds_gpio),
+				 tl_wa801n_v3_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WA801NDV3_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wa801n_v3_gpio_keys),
+					tl_wa801n_v3_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA801ND_V3, "TL-WA801ND-v3", "TP-LINK TL-WA801ND v3",
+	     tl_wa801n_v3_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa830re-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa830re-v2.c
new file mode 100644
index 0000000000..1c74fed98e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa830re-v2.c
@@ -0,0 +1,132 @@
+/*
+ *  TP-LINK TL-WA830RE v2 board support
+ *
+ *  Copyright (C) 2014 Fredrik Jonson <fredrik@famjonson.se>
+ *
+ *  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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WA830REV2_GPIO_LED_WLAN	13
+#define TL_WA830REV2_GPIO_LED_QSS	15
+#define TL_WA830REV2_GPIO_LED_LAN	18
+#define TL_WA830REV2_GPIO_LED_SYSTEM	14
+
+#define TL_WA830REV2_GPIO_BTN_RESET	17
+#define TL_WA830REV2_GPIO_SW_RFKILL	16	/* WPS for MR3420 v2 */
+
+#define TL_WA830REV2_GPIO_USB_POWER	4
+
+#define TL_WA830REV2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WA830REV2_KEYS_DEBOUNCE_INTERVAL (3 * TL_WA830REV2_KEYS_POLL_INTERVAL)
+
+static const char *tl_wa830re_v2_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wa830re_v2_flash_data = {
+	.part_probes	= tl_wa830re_v2_part_probes,
+};
+
+static struct gpio_led tl_wa830re_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WA830REV2_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA830REV2_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA830REV2_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WA830REV2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wa830re_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WA830REV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA830REV2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WA830REV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA830REV2_GPIO_SW_RFKILL,
+		.active_low	= 0,
+	}
+};
+
+static void __init tl_ap123_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	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);
+
+	/* config gpio4 as normal gpio function */
+	ath79_gpio_output_select(TL_WA830REV2_GPIO_USB_POWER,
+				 AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(&tl_wa830re_v2_flash_data);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void __init tl_wa830re_v2_setup(void)
+{
+	tl_ap123_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa830re_v2_leds_gpio) - 1,
+				 tl_wa830re_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WA830REV2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wa830re_v2_gpio_keys),
+					tl_wa830re_v2_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA830RE_V2, "TL-WA830RE-v2", "TP-LINK TL-WA830RE v2",
+	     tl_wa830re_v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v2.c
new file mode 100644
index 0000000000..b4fb2a9f91
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v2.c
@@ -0,0 +1,104 @@
+/*
+ *  TP-LINK TL-WA901N/ND v2 board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Pieter Hollants <pieter@hollants.com>
+ *  Copyright (C) 2011 Jonathan Bennett <jbscience87@gmail.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WA901ND_V2_GPIO_LED_QSS		4
+#define TL_WA901ND_V2_GPIO_LED_SYSTEM		2
+#define TL_WA901ND_V2_GPIO_LED_WLAN		9
+
+#define TL_WA901ND_V2_GPIO_BTN_RESET		3
+#define TL_WA901ND_V2_GPIO_BTN_QSS		7
+
+#define TL_WA901ND_V2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WA901ND_V2_KEYS_DEBOUNCE_INTERVAL	\
+					(3 * TL_WA901ND_V2_KEYS_POLL_INTERVAL)
+
+static const char *tl_wa901nd_v2_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wa901nd_v2_flash_data = {
+	.part_probes	= tl_wa901nd_v2_part_probes,
+};
+
+static struct gpio_led tl_wa901nd_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA901ND_V2_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WA901ND_V2_GPIO_LED_QSS,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WA901ND_V2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_wa901nd_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WA901ND_V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA901ND_V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WA901ND_V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA901ND_V2_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static void __init tl_wa901nd_v2_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *eeprom  = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = 0x00001000;
+	ath79_register_mdio(0, 0x0);
+
+	ath79_eth0_data.reset_bit = AR71XX_RESET_GE0_MAC |
+				    AR71XX_RESET_GE0_PHY;
+	ath79_register_eth(0);
+
+	ath79_register_m25p80(&tl_wa901nd_v2_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa901nd_v2_leds_gpio),
+				 tl_wa901nd_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WA901ND_V2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wa901nd_v2_gpio_keys),
+					tl_wa901nd_v2_gpio_keys);
+
+	ath79_register_wmac(eeprom, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA901ND_V2, "TL-WA901ND-v2",
+	     "TP-LINK TL-WA901ND v2", tl_wa901nd_v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v4.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v4.c
new file mode 100644
index 0000000000..9c651bb1d2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd-v4.c
@@ -0,0 +1,112 @@
+/*
+ *  TP-LINK TL-WA901ND v4 board
+ *
+ *  Copyright (C) 2015 Matthias Schiffer <mschiffer@universe-factory.net>
+ *  Copyright (C) 2016 Tiziano Bacocco <tizbac2@gmail.com>
+ *
+ *  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 TL_WA901ND_V4_GPIO_LED_QSS		3
+#define TL_WA901ND_V4_GPIO_LED_LAN		7
+#define TL_WA901ND_V4_GPIO_LED_WLAN		8
+#define TL_WA901ND_V4_GPIO_LED_SYSTEM		18
+
+#define TL_WA901ND_V4_GPIO_BTN_RESET		1
+
+#define TL_WA901ND_V4_KEYS_POLL_INTERVAL	20
+#define TL_WA901ND_V4_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WA901ND_V4_KEYS_POLL_INTERVAL)
+
+
+static struct gpio_led TL_WA901ND_V4_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WA901ND_V4_GPIO_LED_QSS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA901ND_V4_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WA901ND_V4_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA901ND_V4_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button TL_WA901ND_V4_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WA901ND_V4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA901ND_V4_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+
+static const char *tl_wa901nd_v4_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wa901nd_v4_flash_data = {
+	.part_probes	= tl_wa901nd_v4_part_probes,
+};
+
+
+static void __init TL_WA901ND_V4_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_wa901nd_v4_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(TL_WA901ND_V4_leds_gpio),
+				 TL_WA901ND_V4_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WA901ND_V4_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(TL_WA901ND_V4_gpio_keys),
+					TL_WA901ND_V4_gpio_keys);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_switch_data.phy4_mii_en = 1;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA901ND_V4, "TL-WA901ND-v4", "TP-LINK TL-WA901ND v4",
+	     TL_WA901ND_V4_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd.c
new file mode 100644
index 0000000000..957b92cba6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wa901nd.c
@@ -0,0 +1,127 @@
+/*
+ *  TP-LINK TL-WA901N/ND v1, TL-WA7510N v1 board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Pieter Hollants <pieter@hollants.com>
+ *  Copyright (C) 2012 Stefan Helmert <helst_listen@aol.de>
+ *
+ *  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 <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define TL_WA901ND_GPIO_LED_QSS		0
+#define TL_WA901ND_GPIO_LED_SYSTEM	1
+#define TL_WA901ND_GPIO_LED_LAN		13
+
+#define TL_WA901ND_GPIO_BTN_RESET	11
+#define TL_WA901ND_GPIO_BTN_QSS		12
+
+#define TL_WA901ND_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WA901ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WA901ND_KEYS_POLL_INTERVAL)
+
+static const char *tl_wa901nd_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wa901nd_flash_data = {
+	.part_probes	= tl_wa901nd_part_probes,
+};
+
+static struct gpio_led tl_wa901nd_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA901ND_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA901ND_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WA901ND_GPIO_LED_QSS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_wa901nd_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WA901ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA901ND_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WA901ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WA901ND_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static void __init common_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+
+	/*
+	 * ath79_eth0 would be the WAN port, but is not connected.
+	 * ath79_eth1 connects to the internal switch chip, however
+	 * we have a single LAN port only.
+	 */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(&tl_wa901nd_flash_data);
+}
+
+static void __init tl_wa901nd_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee  = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	common_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa901nd_leds_gpio),
+				 tl_wa901nd_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WA901ND_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wa901nd_gpio_keys),
+					tl_wa901nd_gpio_keys);
+
+	ap91_pci_init(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA901ND, "TL-WA901ND", "TP-LINK TL-WA901ND",
+	     tl_wa901nd_setup);
+
+static void __init tl_wa7510n_v1_setup(void)
+{
+	common_setup();
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA7510N_V1, "TL-WA7510N", "TP-LINK TL-WA7510N v1",
+	     tl_wa7510n_v1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wax50re.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wax50re.c
new file mode 100644
index 0000000000..965b1cd3b8
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wax50re.c
@@ -0,0 +1,313 @@
+/*
+ *  TP-LINK TL-WA750RE v1/TL-WA801ND v2/TL-WA850RE v1/TL-WA901ND v3
+ *  board support
+ *
+ *  Copyright (C) 2013 Martijn Zilverschoon <thefriedzombie@gmail.com>
+ *  Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
+ *
+ *  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 TL_WAX50RE_GPIO_LED_LAN		20
+#define TL_WAX50RE_GPIO_LED_WLAN	13
+#define TL_WAX50RE_GPIO_LED_RE		15
+#define TL_WAX50RE_GPIO_LED_SIGNAL1	0
+#define TL_WAX50RE_GPIO_LED_SIGNAL2	1
+#define TL_WAX50RE_GPIO_LED_SIGNAL3	2
+#define TL_WAX50RE_GPIO_LED_SIGNAL4	3
+#define TL_WAX50RE_GPIO_LED_SIGNAL5	4
+
+#define TL_WA860RE_GPIO_LED_WLAN_ORANGE	0
+#define TL_WA860RE_GPIO_LED_WLAN_GREEN	2
+#define TL_WA860RE_GPIO_LED_POWER_ORANGE	12
+#define TL_WA860RE_GPIO_LED_POWER_GREEN	14
+#define TL_WA860RE_GPIO_LED_LAN		20
+
+#define TL_WA801ND_V2_GPIO_LED_LAN	18
+#define TL_WA801ND_V2_GPIO_LED_SYSTEM	14
+
+#define TL_WAX50RE_GPIO_BTN_RESET	17
+#define TL_WAX50RE_GPIO_BTN_WPS		16
+
+#define TL_WA860RE_GPIO_BTN_RESET	17
+#define TL_WA860RE_GPIO_BTN_WPS		16
+#define TL_WA860RE_GPIO_BTN_ONOFF	11
+
+#define TL_WAX50RE_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WAX50RE_KEYS_DEBOUNCE_INTERVAL (3 * TL_WAX50RE_KEYS_POLL_INTERVAL)
+
+static const char *tl_wax50re_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wax50re_flash_data = {
+	.part_probes	= tl_wax50re_part_probes,
+};
+
+static struct gpio_led tl_wa750re_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:orange:lan",
+		.gpio		= TL_WAX50RE_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:wlan",
+		.gpio		= TL_WAX50RE_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:re",
+		.gpio		= TL_WAX50RE_GPIO_LED_RE,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:signal1",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:signal2",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:signal3",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:signal4",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:signal5",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL5,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led tl_wa850re_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:lan",
+		.gpio		= TL_WAX50RE_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:wlan",
+		.gpio		= TL_WAX50RE_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:re",
+		.gpio		= TL_WAX50RE_GPIO_LED_RE,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:signal1",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:signal2",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:signal3",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:signal4",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:blue:signal5",
+		.gpio		= TL_WAX50RE_GPIO_LED_SIGNAL5,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led tl_wa860re_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA860RE_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:power",
+		.gpio		= TL_WA860RE_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:power",
+		.gpio		= TL_WA860RE_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WA860RE_GPIO_LED_WLAN_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:orange:wlan",
+		.gpio		= TL_WA860RE_GPIO_LED_WLAN_ORANGE,
+		.active_low	= 1,
+	},
+};
+
+
+static struct gpio_keys_button tl_wax50re_gpio_keys[] __initdata = {
+	{
+		.desc		   = "Reset button",
+		.type		   = EV_KEY,
+		.code		   = KEY_RESTART,
+		.debounce_interval = TL_WAX50RE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		   = TL_WAX50RE_GPIO_BTN_RESET,
+		.active_low	   = 1,
+	}, {
+		.desc		   = "WPS",
+		.type		   = EV_KEY,
+		.code		   = KEY_WPS_BUTTON,
+		.debounce_interval = TL_WAX50RE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		   = TL_WAX50RE_GPIO_BTN_WPS,
+		.active_low	   = 1,
+	},
+};
+
+static struct gpio_keys_button tl_wa860re_gpio_keys[] __initdata = {
+	{
+		.desc		   = "Reset button",
+		.type		   = EV_KEY,
+		.code		   = KEY_RESTART,
+		.debounce_interval = TL_WAX50RE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		   = TL_WA860RE_GPIO_BTN_RESET,
+		.active_low	   = 1,
+	}, {
+		.desc		   = "WPS",
+		.type		   = EV_KEY,
+		.code		   = KEY_WPS_BUTTON,
+		.debounce_interval = TL_WAX50RE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		   = TL_WA860RE_GPIO_BTN_WPS,
+		.active_low	   = 1,
+	}, {
+		.desc		   = "ONOFF",
+		.type		   = EV_KEY,
+		.code		   = BTN_1,
+		.debounce_interval = TL_WAX50RE_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		   = TL_WA860RE_GPIO_BTN_ONOFF,
+		.active_low	   = 1,
+	},
+};
+
+static struct gpio_led tl_wa801nd_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan",
+		.gpio		= TL_WA801ND_V2_GPIO_LED_LAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WAX50RE_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WAX50RE_GPIO_LED_RE,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WA801ND_V2_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static void __init tl_ap123_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_wax50re_flash_data);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void  __init tl_wa750re_setup(void)
+{
+	tl_ap123_setup();
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa750re_leds_gpio),
+				 tl_wa750re_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WAX50RE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wax50re_gpio_keys),
+					tl_wax50re_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA750RE, "TL-WA750RE", "TP-LINK TL-WA750RE",
+	     tl_wa750re_setup);
+
+static void __init tl_wa801nd_v2_setup(void)
+{
+	tl_ap123_setup();
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa801nd_v2_leds_gpio),
+			tl_wa801nd_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WAX50RE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wax50re_gpio_keys),
+					tl_wax50re_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA801ND_V2, "TL-WA801ND-v2", "TP-LINK TL-WA801ND v2",
+	     tl_wa801nd_v2_setup);
+
+static void  __init tl_wa850re_setup(void)
+{
+	tl_ap123_setup();
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa850re_leds_gpio),
+				 tl_wa850re_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WAX50RE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wax50re_gpio_keys),
+					tl_wax50re_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA850RE, "TL-WA850RE", "TP-LINK TL-WA850RE",
+	     tl_wa850re_setup);
+
+static void  __init tl_wa860re_setup(void)
+{
+	tl_ap123_setup();
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa860re_leds_gpio),
+				 tl_wa860re_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WAX50RE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wa860re_gpio_keys),
+					tl_wa860re_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA860RE, "TL-WA860RE", "TP-LINK TL-WA860RE",
+	     tl_wa860re_setup);
+
+static void __init tl_wa901nd_v3_setup(void)
+{
+	tl_ap123_setup();
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wa801nd_v2_leds_gpio),
+			tl_wa801nd_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WAX50RE_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wax50re_gpio_keys) - 1,
+					tl_wax50re_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WA901ND_V3, "TL-WA901ND-v3", "TP-LINK TL-WA901ND v3",
+	     tl_wa901nd_v3_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3320-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3320-v2.c
new file mode 100644
index 0000000000..3e452f2a4a
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3320-v2.c
@@ -0,0 +1,146 @@
+/*
+ *  TP-LINK TL-WDR3320 v2 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2015 Weijie Gao <hackpascal@gmail.com>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WDR3320_GPIO_LED_WLAN5G		12
+#define WDR3320_GPIO_LED_SYSTEM		14
+#define WDR3320_GPIO_LED_QSS		15
+#define WDR3320_GPIO_LED_WAN		4
+#define WDR3320_GPIO_LED_LAN1		18
+#define WDR3320_GPIO_LED_LAN2		20
+#define WDR3320_GPIO_LED_LAN3		21
+#define WDR3320_GPIO_LED_LAN4		22
+
+#define WDR3320_GPIO_BTN_RESET		16
+
+#define WDR3320_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WDR3320_KEYS_DEBOUNCE_INTERVAL	(3 * WDR3320_KEYS_POLL_INTERVAL)
+
+#define WDR3320_WMAC_CALDATA_OFFSET	0x1000
+#define WDR3320_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *wdr3320_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data wdr3320_flash_data = {
+	.part_probes	= wdr3320_part_probes,
+};
+
+static struct gpio_led wdr3320_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:qss",
+		.gpio		= WDR3320_GPIO_LED_QSS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= WDR3320_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wlan5g",
+		.gpio		= WDR3320_GPIO_LED_WLAN5G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wdr3320_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WDR3320_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WDR3320_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init wdr3320_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&wdr3320_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wdr3320_leds_gpio),
+				 wdr3320_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WDR3320_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wdr3320_gpio_keys),
+					wdr3320_gpio_keys);
+
+	ath79_init_mac(tmpmac, mac, 0);
+	ath79_register_wmac(art + WDR3320_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_init_mac(tmpmac, mac, -1);
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+	ap91_pci_init(art + WDR3320_PCIE_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* LAN */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+
+	/* GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+
+	ath79_gpio_output_select(WDR3320_GPIO_LED_LAN1,
+				 AR934X_GPIO_OUT_LED_LINK0);
+	ath79_gpio_output_select(WDR3320_GPIO_LED_LAN2,
+				 AR934X_GPIO_OUT_LED_LINK1);
+	ath79_gpio_output_select(WDR3320_GPIO_LED_LAN3,
+				 AR934X_GPIO_OUT_LED_LINK2);
+	ath79_gpio_output_select(WDR3320_GPIO_LED_LAN4,
+				 AR934X_GPIO_OUT_LED_LINK3);
+	ath79_gpio_output_select(WDR3320_GPIO_LED_WAN,
+				 AR934X_GPIO_OUT_LED_LINK4);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WDR3320_V2, "TL-WDR3320-v2",
+	     "TP-LINK TL-WDR3320 v2",
+	     wdr3320_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3500.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3500.c
new file mode 100644
index 0000000000..452c20b777
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr3500.c
@@ -0,0 +1,169 @@
+/*
+ *  TP-LINK TL-WDR3500 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 Gui Iribarren <gui@altermundi.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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WDR3500_GPIO_LED_USB		11
+#define WDR3500_GPIO_LED_WLAN2G		13
+#define WDR3500_GPIO_LED_SYSTEM		14
+#define WDR3500_GPIO_LED_QSS		15
+#define WDR3500_GPIO_LED_WAN		18
+#define WDR3500_GPIO_LED_LAN1		19
+#define WDR3500_GPIO_LED_LAN2		20
+#define WDR3500_GPIO_LED_LAN3		21
+#define WDR3500_GPIO_LED_LAN4		22
+
+#define WDR3500_GPIO_BTN_WPS		16
+#define WDR3500_GPIO_BTN_RFKILL		17
+
+#define WDR3500_GPIO_USB_POWER		12
+
+#define WDR3500_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WDR3500_KEYS_DEBOUNCE_INTERVAL	(3 * WDR3500_KEYS_POLL_INTERVAL)
+
+#define WDR3500_MAC0_OFFSET		0
+#define WDR3500_MAC1_OFFSET		6
+#define WDR3500_WMAC_CALDATA_OFFSET	0x1000
+#define WDR3500_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *wdr3500_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data wdr3500_flash_data = {
+	.part_probes	= wdr3500_part_probes,
+};
+
+static struct gpio_led wdr3500_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:qss",
+		.gpio		= WDR3500_GPIO_LED_QSS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= WDR3500_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:usb",
+		.gpio		= WDR3500_GPIO_LED_USB,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wlan2g",
+		.gpio		= WDR3500_GPIO_LED_WLAN2G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wdr3500_gpio_keys[] __initdata = {
+	{
+		.desc		= "QSS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WDR3500_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WDR3500_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WDR3500_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WDR3500_GPIO_BTN_RFKILL,
+	},
+};
+
+
+static void __init wdr3500_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&wdr3500_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wdr3500_leds_gpio),
+				 wdr3500_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WDR3500_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wdr3500_gpio_keys),
+					wdr3500_gpio_keys);
+
+	ath79_init_mac(tmpmac, mac, 0);
+	ath79_register_wmac(art + WDR3500_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_init_mac(tmpmac, mac, 1);
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+	ap91_pci_init(art + WDR3500_PCIE_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* LAN */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 2);
+
+	/* GMAC0 is connected to the PHY4 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	ath79_register_eth(0);
+
+	gpio_request_one(WDR3500_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_gpio_output_select(WDR3500_GPIO_LED_LAN1,
+				 AR934X_GPIO_OUT_LED_LINK3);
+	ath79_gpio_output_select(WDR3500_GPIO_LED_LAN2,
+				 AR934X_GPIO_OUT_LED_LINK2);
+	ath79_gpio_output_select(WDR3500_GPIO_LED_LAN3,
+				 AR934X_GPIO_OUT_LED_LINK1);
+	ath79_gpio_output_select(WDR3500_GPIO_LED_LAN4,
+				 AR934X_GPIO_OUT_LED_LINK0);
+	ath79_gpio_output_select(WDR3500_GPIO_LED_WAN,
+				 AR934X_GPIO_OUT_LED_LINK4);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WDR3500, "TL-WDR3500",
+	     "TP-LINK TL-WDR3500",
+	     wdr3500_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr4300.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr4300.c
new file mode 100644
index 0000000000..3afc714620
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr4300.c
@@ -0,0 +1,206 @@
+/*
+ *  TP-LINK TL-WDR4300 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WDR4300_GPIO_LED_USB1		11
+#define WDR4300_GPIO_LED_USB2		12
+#define WDR4300_GPIO_LED_WLAN2G		13
+#define WDR4300_GPIO_LED_SYSTEM		14
+#define WDR4300_GPIO_LED_QSS		15
+
+#define WDR4300_GPIO_BTN_WPS		16
+#define WDR4300_GPIO_BTN_RFKILL		17
+
+#define WDR4300_GPIO_EXTERNAL_LNA0	18
+#define WDR4300_GPIO_EXTERNAL_LNA1	19
+
+#define WDR4300_GPIO_USB1_POWER		22
+#define WDR4300_GPIO_USB2_POWER		21
+
+#define WDR4300_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WDR4300_KEYS_DEBOUNCE_INTERVAL	(3 * WDR4300_KEYS_POLL_INTERVAL)
+
+#define WDR4300_MAC0_OFFSET		0
+#define WDR4300_MAC1_OFFSET		6
+#define WDR4300_WMAC_CALDATA_OFFSET	0x1000
+#define WDR4300_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *wdr4300_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data wdr4300_flash_data = {
+	.part_probes	= wdr4300_part_probes,
+};
+
+static struct gpio_led wdr4300_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:qss",
+		.gpio		= WDR4300_GPIO_LED_QSS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= WDR4300_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:usb1",
+		.gpio		= WDR4300_GPIO_LED_USB1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:usb2",
+		.gpio		= WDR4300_GPIO_LED_USB2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:wlan2g",
+		.gpio		= WDR4300_GPIO_LED_WLAN2G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wdr4300_gpio_keys[] __initdata = {
+	{
+		.desc		= "QSS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WDR4300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WDR4300_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WDR4300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WDR4300_GPIO_BTN_RFKILL,
+		.active_low	= 1,
+	},
+};
+
+static const struct ar8327_led_info wdr4300_leds_ar8327[] __initconst = {
+	AR8327_LED_INFO(PHY0_0, HW, "tp-link:blue:wan"),
+	AR8327_LED_INFO(PHY1_0, HW, "tp-link:blue:lan1"),
+	AR8327_LED_INFO(PHY2_0, HW, "tp-link:blue:lan2"),
+	AR8327_LED_INFO(PHY3_0, HW, "tp-link:blue:lan3"),
+	AR8327_LED_INFO(PHY4_0, HW, "tp-link:blue:lan4"),
+};
+
+static struct ar8327_pad_cfg wdr4300_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg wdr4300_ar8327_led_cfg = {
+	.led_ctrl0 = 0xc737c737,
+	.led_ctrl1 = 0x00000000,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x0030c300,
+	.open_drain = false,
+};
+
+static struct ar8327_platform_data wdr4300_ar8327_data = {
+	.pad0_cfg = &wdr4300_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &wdr4300_ar8327_led_cfg,
+	.num_leds = ARRAY_SIZE(wdr4300_leds_ar8327),
+	.leds = wdr4300_leds_ar8327,
+};
+
+static struct mdio_board_info wdr4300_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wdr4300_ar8327_data,
+	},
+};
+
+static void __init wdr4300_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&wdr4300_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wdr4300_leds_gpio),
+				 wdr4300_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WDR4300_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wdr4300_gpio_keys),
+					wdr4300_gpio_keys);
+
+	ath79_wmac_set_ext_lna_gpio(0, WDR4300_GPIO_EXTERNAL_LNA0);
+	ath79_wmac_set_ext_lna_gpio(1, WDR4300_GPIO_EXTERNAL_LNA1);
+
+	ath79_init_mac(tmpmac, mac, -1);
+	ath79_register_wmac(art + WDR4300_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_init_mac(tmpmac, mac, 0);
+	ap9x_pci_setup_wmac_led_pin(0, 0);
+	ap91_pci_init(art + WDR4300_PCIE_CALDATA_OFFSET, tmpmac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	mdiobus_register_board_info(wdr4300_mdio0_info,
+				    ARRAY_SIZE(wdr4300_mdio0_info));
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -2);
+
+	/* GMAC0 is connected to an AR8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	gpio_request_one(WDR4300_GPIO_USB1_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB1 power");
+	gpio_request_one(WDR4300_GPIO_USB2_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB2 power");
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WDR4300, "TL-WDR4300",
+	     "TP-LINK TL-WDR3600/4300/4310",
+	     wdr4300_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr6500-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr6500-v2.c
new file mode 100644
index 0000000000..1e72477646
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wdr6500-v2.c
@@ -0,0 +1,142 @@
+/*
+ *  TP-LINK TL-WDR6500 v2
+ *
+ *  Copyright (C) 2015 Weijie Gao <hackpascal@gmail.com>
+ *
+ *  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/pci.h>
+#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-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define TL_WDR6500_V2_GPIO_LED_SYS	21
+#define TL_WDR6500_V2_GPIO_LED_WAN	18
+#define TL_WDR6500_V2_GPIO_LED_LAN1	17
+#define TL_WDR6500_V2_GPIO_LED_LAN2	16
+#define TL_WDR6500_V2_GPIO_LED_LAN3	15
+#define TL_WDR6500_V2_GPIO_LED_LAN4	14
+
+#define TL_WDR6500_V2_GPIO_BTN_RESET	1
+
+#define TL_WDR6500_V2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WDR6500_V2_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WDR6500_V2_KEYS_POLL_INTERVAL)
+
+#define TL_WDR6500_V2_WMAC_CALDATA_OFFSET	0x1000
+#define TL_WDR6500_V2_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *tl_wdr6500_v2_part_probes[] = {
+	"tp-link-64k",
+	NULL,
+};
+
+static struct flash_platform_data tl_wdr6500_v2_flash_data = {
+	.part_probes	= tl_wdr6500_v2_part_probes,
+};
+
+static struct gpio_led tl_wdr6500_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WDR6500_V2_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WDR6500_V2_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WDR6500_V2_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WDR6500_V2_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WDR6500_V2_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:white:system",
+		.gpio		= TL_WDR6500_V2_GPIO_LED_SYS,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tl_wdr6500_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WDR6500_V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WDR6500_V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+
+static void __init tl_ap151_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f00fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&tl_wdr6500_v2_flash_data);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_register_eth(0);
+
+	/* LAN */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_eth(1);
+
+	ath79_init_mac(tmpmac, mac, -1);
+	ath79_register_wmac(ee + TL_WDR6500_V2_WMAC_CALDATA_OFFSET, tmpmac);
+
+	ath79_register_pci();
+
+	ath79_register_usb();
+}
+
+static void __init tl_wdr6500_v2_setup(void)
+{
+	tl_ap151_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wdr6500_v2_leds_gpio),
+				 tl_wdr6500_v2_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WDR6500_V2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wdr6500_v2_gpio_keys),
+					tl_wdr6500_v2_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WDR6500_V2, "TL-WDR6500-v2", "TP-LINK TL-WDR6500 v2",
+	     tl_wdr6500_v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wpa8630.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wpa8630.c
new file mode 100644
index 0000000000..0a1e6b4d91
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wpa8630.c
@@ -0,0 +1,172 @@
+/*
+ *  TP-Link TL-WPA8630 board support
+ *
+ *  Copyright (C) 2016 Henryk Heisig <hyniu@o2.pl>
+ *
+ *  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/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+
+#define TL_WPA8630_KEYS_POLL_INTERVAL	20
+#define TL_WPA8630_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WPA8630_KEYS_POLL_INTERVAL)
+
+#define TL_WPA8630_GPIO_LED_POWER		1
+#define TL_WPA8630_GPIO_LED_LAN		5
+#define TL_WPA8630_GPIO_LED_WLAN		19
+#define TL_WPA8630_GPIO_LED_WLAN5		21
+
+#define TL_WPA8630_GPIO_BTN_RESET		2
+#define TL_WPA8630_GPIO_BTN_RFKILL		8
+#define TL_WPA8630_GPIO_BTN_LED		6
+#define TL_WPA8630_GPIO_BTN_PAIR		7
+
+#define TL_WPA8630_MAC0_OFFSET		0x0000
+#define TL_WPA8630_WMAC_CALDATA_OFFSET	0x1000
+#define TL_WPA8630_PCI_CALDATA_OFFSET	0x5000
+
+static const char *tl_wpa8630_part_probes[] = {
+	"tp-link-64k",
+	NULL,
+};
+
+static struct flash_platform_data tl_wpa8630_flash_data = {
+	.part_probes	= tl_wpa8630_part_probes,
+	.type		= "s25fl064k",
+};
+
+static struct gpio_led tl_wpa8630_leds_gpio[] __initdata = {
+	{
+		.name		= "tl-wpa8630:green:power",
+		.gpio		= TL_WPA8630_GPIO_LED_POWER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tl-wpa8630:green:lan",
+		.gpio		= TL_WPA8630_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tl-wpa8630:green:wlan",
+		.gpio		= TL_WPA8630_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tl-wpa8630:green:wlan5",
+		.gpio		= TL_WPA8630_GPIO_LED_WLAN5,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wpa8630_gpio_keys[] __initdata = {
+	{
+		.desc			= "Reset button",
+		.type			= EV_KEY,
+		.code			= KEY_RESTART,
+		.debounce_interval	= TL_WPA8630_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= TL_WPA8630_GPIO_BTN_RESET,
+		.active_low		= 1,
+	},
+	{
+		.desc			= "RFKILL button",
+		.type			= EV_KEY,
+		.code			= KEY_RFKILL,
+		.debounce_interval	= TL_WPA8630_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= TL_WPA8630_GPIO_BTN_RFKILL,
+		.active_low		= 1,
+	},
+	{
+		.desc			= "LED",
+		.type			= EV_KEY,
+		.code			= BTN_0,
+		.debounce_interval	= TL_WPA8630_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= TL_WPA8630_GPIO_BTN_LED,
+		.active_low		= 1,
+	},
+	{
+		.desc			= "Pair",
+		.type			= EV_KEY,
+		.code			= BTN_1,
+		.debounce_interval	= TL_WPA8630_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= TL_WPA8630_GPIO_BTN_PAIR,
+		.active_low		= 1,
+	},
+};
+
+/* GMAC0 of the QCA8337 switch is connected to the QCA9563 SoC via SGMII */
+static struct ar8327_pad_cfg tl_wpa8630_qca8337_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data tl_wpa8630_qca8337_data = {
+	.pad0_cfg = &tl_wpa8630_qca8337_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info tl_wpa8630_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &tl_wpa8630_qca8337_data,
+	},
+};
+
+static void __init tl_wpa8630_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f00fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(&tl_wpa8630_flash_data);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		art + TL_WPA8630_MAC0_OFFSET, 0);
+
+	platform_device_register(&ath79_mdio0_device);
+
+	mdiobus_register_board_info(tl_wpa8630_mdio0_info,
+				    ARRAY_SIZE(tl_wpa8630_mdio0_info));
+
+	/* GMAC0 is connected to an AR8337 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = ~BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art + TL_WPA8630_WMAC_CALDATA_OFFSET, mac);
+
+	ap91_pci_init(art + TL_WPA8630_PCI_CALDATA_OFFSET, NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wpa8630_leds_gpio),
+				tl_wpa8630_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WPA8630_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wpa8630_gpio_keys),
+					tl_wpa8630_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WPA8630, "TL-WPA8630", "TP-Link TL-WPA8630",
+	tl_wpa8630_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1041n-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1041n-v2.c
new file mode 100644
index 0000000000..fa8c4749cd
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1041n-v2.c
@@ -0,0 +1,138 @@
+/*
+ *  TP-LINK TL-WR1041 v2 board support
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2011-2012 Anan Huang <axishero@foxmail.com>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR1041NV2_GPIO_BTN_RESET	14
+#define TL_WR1041NV2_GPIO_LED_WPS	13
+#define TL_WR1041NV2_GPIO_LED_WLAN	11
+
+#define TL_WR1041NV2_GPIO_LED_SYSTEM	12
+
+#define TL_WR1041NV2_KEYS_POLL_INTERVAL		20	/* msecs */
+#define TL_WR1041NV2_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WR1041NV2_KEYS_POLL_INTERVAL)
+
+#define TL_WR1041NV2_PCIE_CALDATA_OFFSET	0x5000
+
+static const char *tl_wr1041nv2_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr1041nv2_flash_data = {
+	.part_probes	= tl_wr1041nv2_part_probes,
+};
+
+static struct gpio_led tl_wr1041nv2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR1041NV2_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wps",
+		.gpio		= TL_WR1041NV2_GPIO_LED_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR1041NV2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_wr1041nv2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR1041NV2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR1041NV2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct ar8327_pad_cfg db120_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data db120_ar8327_data = {
+	.pad0_cfg = &db120_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	}
+};
+
+static struct mdio_board_info db120_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &db120_ar8327_data,
+	},
+};
+
+static void __init tl_wr1041nv2_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_wr1041nv2_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr1041nv2_leds_gpio),
+				 tl_wr1041nv2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_WR1041NV2_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(tl_wr1041nv2_gpio_keys),
+					 tl_wr1041nv2_gpio_keys);
+	ath79_register_wmac(ee, mac);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+
+	mdiobus_register_board_info(db120_mdio0_info,
+				    ARRAY_SIZE(db120_mdio0_info));
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR1041N_V2, "TL-WR1041N-v2",
+	     "TP-LINK TL-WR1041N v2", tl_wr1041nv2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd-v2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd-v2.c
new file mode 100644
index 0000000000..abdbde08d2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd-v2.c
@@ -0,0 +1,215 @@
+/*
+ * TP-LINK TL-WR1043ND v2 board support
+ *
+ * Copyright (c) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the Qualcomm Atheros AP135/AP136 reference board support code
+ *   Copyright (c) 2012 Qualcomm Atheros
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR1043_V2_GPIO_LED_WLAN	12
+#define TL_WR1043_V2_GPIO_LED_USB	15
+#define TL_WR1043_V2_GPIO_LED_WPS	18
+#define TL_WR1043_V2_GPIO_LED_SYSTEM	19
+
+#define TL_WR1043_V2_GPIO_BTN_RESET	16
+#define TL_WR1043_V2_GPIO_BTN_RFKILL	17
+
+#define TL_WR1043_V2_GPIO_USB_POWER	21
+
+#define TL_WR1043_V2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR1043_V2_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR1043_V2_KEYS_POLL_INTERVAL)
+
+#define TL_WR1043_V2_WMAC_CALDATA_OFFSET	0x1000
+
+static const char *wr1043nd_v2_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data wr1043nd_v2_flash_data = {
+	.part_probes	= wr1043nd_v2_part_probes,
+};
+
+static struct gpio_led tl_wr1043_v2_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:wps",
+		.gpio		= TL_WR1043_V2_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR1043_V2_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR1043_V2_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:green:usb",
+		.gpio		= TL_WR1043_V2_GPIO_LED_USB,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr1043_v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR1043_V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR1043_V2_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WR1043_V2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR1043_V2_GPIO_BTN_RFKILL,
+		.active_low	= 1,
+	},
+};
+
+static const struct ar8327_led_info tl_wr1043_leds_ar8327[] = {
+	AR8327_LED_INFO(PHY0_0, HW, "tp-link:green:lan4"),
+	AR8327_LED_INFO(PHY1_0, HW, "tp-link:green:lan3"),
+	AR8327_LED_INFO(PHY2_0, HW, "tp-link:green:lan2"),
+	AR8327_LED_INFO(PHY3_0, HW, "tp-link:green:lan1"),
+	AR8327_LED_INFO(PHY4_0, HW, "tp-link:green:wan"),
+};
+
+/* GMAC0 of the AR8327 switch is connected to the QCA9558 SoC via SGMII */
+static struct ar8327_pad_cfg wr1043nd_v2_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+/* GMAC6 of the AR8327 switch is connected to the QCA9558 SoC via RGMII */
+static struct ar8327_pad_cfg wr1043nd_v2_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg wr1043nd_v2_ar8327_led_cfg = {
+	.led_ctrl0 = 0xcc35cc35,
+	.led_ctrl1 = 0xca35ca35,
+	.led_ctrl2 = 0xc935c935,
+	.led_ctrl3 = 0x03ffff00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data wr1043nd_v2_ar8327_data = {
+	.pad0_cfg = &wr1043nd_v2_ar8327_pad0_cfg,
+	.pad6_cfg = &wr1043nd_v2_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &wr1043nd_v2_ar8327_led_cfg,
+	.num_leds = ARRAY_SIZE(tl_wr1043_leds_ar8327),
+	.leds = tl_wr1043_leds_ar8327,
+};
+
+static struct mdio_board_info wr1043nd_v2_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wr1043nd_v2_ar8327_data,
+	},
+};
+
+static void __init tl_wr1043nd_v2_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(&wr1043nd_v2_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr1043_v2_leds_gpio),
+				 tl_wr1043_v2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_WR1043_V2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr1043_v2_gpio_keys),
+					tl_wr1043_v2_gpio_keys);
+
+	ath79_register_wmac(art + TL_WR1043_V2_WMAC_CALDATA_OFFSET, mac);
+
+	mdiobus_register_board_info(wr1043nd_v2_mdio0_info,
+				    ARRAY_SIZE(wr1043nd_v2_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+
+	gpio_request_one(TL_WR1043_V2_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR1043ND_V2, "TL-WR1043ND-v2",
+	     "TP-LINK TL-WR1043ND v2", tl_wr1043nd_v2_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd.c
new file mode 100644
index 0000000000..61aeb52d02
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr1043nd.c
@@ -0,0 +1,141 @@
+/*
+ *  TP-LINK TL-WR1043N/ND board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/rtl8366.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR1043ND_GPIO_LED_USB        1
+#define TL_WR1043ND_GPIO_LED_SYSTEM     2
+#define TL_WR1043ND_GPIO_LED_QSS        5
+#define TL_WR1043ND_GPIO_LED_WLAN       9
+
+#define TL_WR1043ND_GPIO_BTN_RESET      3
+#define TL_WR1043ND_GPIO_BTN_QSS        7
+
+#define TL_WR1043ND_GPIO_RTL8366_SDA	18
+#define TL_WR1043ND_GPIO_RTL8366_SCK	19
+
+#define TL_WR1043ND_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR1043ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR1043ND_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr1043nd_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr1043nd_flash_data = {
+	.part_probes	= tl_wr1043nd_part_probes,
+};
+
+static struct gpio_led tl_wr1043nd_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:usb",
+		.gpio		= TL_WR1043ND_GPIO_LED_USB,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR1043ND_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR1043ND_GPIO_LED_QSS,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR1043ND_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_wr1043nd_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR1043ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR1043ND_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR1043ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR1043ND_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static void tl_wr1043nd_rtl8366rb_hw_reset(bool active)
+{
+	if (active)
+		ath79_device_reset_set(AR71XX_RESET_GE0_PHY);
+	else
+		ath79_device_reset_clear(AR71XX_RESET_GE0_PHY);
+}
+
+static struct rtl8366_platform_data tl_wr1043nd_rtl8366rb_data = {
+	.gpio_sda	= TL_WR1043ND_GPIO_RTL8366_SDA,
+	.gpio_sck	= TL_WR1043ND_GPIO_RTL8366_SCK,
+	.hw_reset	= tl_wr1043nd_rtl8366rb_hw_reset,
+};
+
+static struct platform_device tl_wr1043nd_rtl8366rb_device = {
+	.name		= RTL8366RB_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &tl_wr1043nd_rtl8366rb_data,
+	}
+};
+
+static void __init tl_wr1043nd_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	tl_wr1043nd_rtl8366rb_hw_reset(true);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.mii_bus_dev = &tl_wr1043nd_rtl8366rb_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_pll_data.pll_1000 = 0x1a000000;
+
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(&tl_wr1043nd_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr1043nd_leds_gpio),
+				 tl_wr1043nd_leds_gpio);
+
+	platform_device_register(&tl_wr1043nd_rtl8366rb_device);
+
+	ath79_register_gpio_keys_polled(-1, TL_WR1043ND_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr1043nd_gpio_keys),
+					tl_wr1043nd_gpio_keys);
+
+	ath79_register_wmac(eeprom, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR1043ND, "TL-WR1043ND", "TP-LINK TL-WR1043ND",
+	     tl_wr1043nd_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr2543n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr2543n.c
new file mode 100644
index 0000000000..8f6db5eda1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr2543n.c
@@ -0,0 +1,156 @@
+/*
+ *  TP-LINK TL-WR2543N/ND board support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/rtl8367.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define TL_WR2543N_GPIO_LED_WPS        0
+#define TL_WR2543N_GPIO_LED_USB        8
+
+/* The WLAN LEDs use GPIOs on the discrete AR9380 wmac */
+#define TL_WR2543N_GPIO_WMAC_LED_WLAN2G 0
+#define TL_WR2543N_GPIO_WMAC_LED_WLAN5G 1
+
+#define TL_WR2543N_GPIO_BTN_RESET      11
+#define TL_WR2543N_GPIO_BTN_WPS        12
+
+#define TL_WR2543N_GPIO_RTL8367_SDA	1
+#define TL_WR2543N_GPIO_RTL8367_SCK	6
+
+#define TL_WR2543N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR2543N_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR2543N_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr2543n_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr2543n_flash_data = {
+	.part_probes	= tl_wr2543n_part_probes,
+};
+
+static struct gpio_led tl_wr2543n_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:usb",
+		.gpio		= TL_WR2543N_GPIO_LED_USB,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wps",
+		.gpio		= TL_WR2543N_GPIO_LED_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led tl_wr2543n_wmac_leds_gpio[] = {
+	{
+		.name		= "tp-link:green:wlan5g",
+		.gpio		= TL_WR2543N_GPIO_WMAC_LED_WLAN5G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr2543n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR2543N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR2543N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR2543N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR2543N_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct rtl8367_extif_config tl_wr2543n_rtl8367_extif0_cfg = {
+	.mode = RTL8367_EXTIF_MODE_RGMII,
+	.txdelay = 1,
+	.rxdelay = 0,
+	.ability = {
+		.force_mode = 1,
+		.txpause = 1,
+		.rxpause = 1,
+		.link = 1,
+		.duplex = 1,
+		.speed = RTL8367_PORT_SPEED_1000,
+	},
+};
+
+static struct rtl8367_platform_data tl_wr2543n_rtl8367_data = {
+	.gpio_sda	= TL_WR2543N_GPIO_RTL8367_SDA,
+	.gpio_sck	= TL_WR2543N_GPIO_RTL8367_SCK,
+	.extif0_cfg	= &tl_wr2543n_rtl8367_extif0_cfg,
+};
+
+static struct platform_device tl_wr2543n_rtl8367_device = {
+	.name		= RTL8367_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &tl_wr2543n_rtl8367_data,
+	}
+};
+
+static void __init tl_wr2543n_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_wr2543n_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr2543n_leds_gpio),
+				 tl_wr2543n_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_WR2543N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr2543n_gpio_keys),
+					tl_wr2543n_gpio_keys);
+	ath79_register_usb();
+
+	/*
+	 * The ath9k driver uses this pin for its default led device, which is
+	 * named ath9k-phy0, and reflects activity on either the 2 GHz or 5 GHz
+	 * bands. This pin is connected to the WR2543's 2GHz WLAN LED.
+	 */
+	ap9x_pci_setup_wmac_led_pin(0, TL_WR2543N_GPIO_WMAC_LED_WLAN2G);
+
+	/*
+	 * We also have the driver set up an led device for the WR2543's
+	 * separate 5 GHz WLAN LED in case the user wants it.
+	 */
+	ap9x_pci_setup_wmac_leds(0, tl_wr2543n_wmac_leds_gpio,
+				 ARRAY_SIZE(tl_wr2543n_wmac_leds_gpio));
+	ap91_pci_init(eeprom, mac);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+	ath79_eth0_data.mii_bus_dev = &tl_wr2543n_rtl8367_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_pll_data.pll_1000 = 0x1a000000;
+
+	ath79_register_eth(0);
+
+	platform_device_register(&tl_wr2543n_rtl8367_device);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR2543N, "TL-WR2543N", "TP-LINK TL-WR2543N/ND",
+	     tl_wr2543n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr703n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr703n.c
new file mode 100644
index 0000000000..1d8d01cc63
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr703n.c
@@ -0,0 +1,118 @@
+/*
+ *  TP-LINK TL-WR703N/TL-MR10U board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR703N_GPIO_LED_SYSTEM	27
+#define TL_WR703N_GPIO_BTN_RESET	11
+
+#define TL_WR703N_GPIO_USB_POWER	8
+
+#define TL_MR10U_GPIO_USB_POWER		18
+
+#define TL_WR703N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR703N_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WR703N_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr703n_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr703n_flash_data = {
+	.part_probes	= tl_wr703n_part_probes,
+};
+
+static struct gpio_led tl_wr703n_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= TL_WR703N_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr703n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR703N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR703N_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}
+};
+
+static void __init common_setup(unsigned usb_power_gpio, bool sec_ethernet)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(&tl_wr703n_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr703n_leds_gpio),
+				 tl_wr703n_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_WR703N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr703n_gpio_keys),
+					tl_wr703n_gpio_keys);
+
+	gpio_request_one(usb_power_gpio,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+
+	if (sec_ethernet)
+	{
+		ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+		ath79_register_eth(1);
+	}
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void __init tl_mr10u_setup(void)
+{
+	common_setup(TL_MR10U_GPIO_USB_POWER, false);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR10U, "TL-MR10U", "TP-LINK TL-MR10U",
+	     tl_mr10u_setup);
+
+static void __init tl_wr703n_setup(void)
+{
+	common_setup(TL_WR703N_GPIO_USB_POWER, false);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR703N, "TL-WR703N", "TP-LINK TL-WR703N v1",
+	     tl_wr703n_setup);
+
+static void __init tl_wr710n_setup(void)
+{
+	common_setup(TL_WR703N_GPIO_USB_POWER, true);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR710N, "TL-WR710N", "TP-LINK TL-WR710N v1",
+	     tl_wr710n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr720n-v3.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr720n-v3.c
new file mode 100644
index 0000000000..2bb3b44a71
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr720n-v3.c
@@ -0,0 +1,108 @@
+/*
+ *  TP-LINK TL-WR720N board support
+ *
+ *  Copyright (C) 2011 dongyuqi <729650915@qq.com>
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2013 yousong <yszhou4tech@gmail.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR720N_GPIO_LED_SYSTEM	27
+#define TL_WR720N_GPIO_BTN_RESET	11
+#define TL_WR720N_GPIO_BTN_SW1		18
+#define TL_WR720N_GPIO_BTN_SW2		20
+
+#define TL_WR720N_GPIO_USB_POWER	8
+
+#define TL_WR720N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR720N_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WR720N_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr720n_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr720n_flash_data = {
+	.part_probes	= tl_wr720n_part_probes,
+};
+
+static struct gpio_led tl_wr720n_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= TL_WR720N_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr720n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR720N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR720N_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}, {
+		.desc		= "sw1",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = TL_WR720N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR720N_GPIO_BTN_SW1,
+		.active_low = 0,
+	}, {
+		.desc		= "sw2",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = TL_WR720N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR720N_GPIO_BTN_SW2,
+		.active_low = 0,
+	}
+};
+
+static void __init tl_wr720n_v3_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	/* disable PHY_SWAP and PHY_ADDR_SWAP bits */
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(&tl_wr720n_flash_data);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr720n_leds_gpio),
+					tl_wr720n_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TL_WR720N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr720n_gpio_keys),
+					tl_wr720n_gpio_keys);
+
+	gpio_request_one(TL_WR720N_GPIO_USB_POWER,
+			GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			"USB power");
+	ath79_register_usb();
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 2);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR720N_V3, "TL-WR720N-v3", "TP-LINK TL-WR720N v3/v4",
+		tl_wr720n_v3_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd-v4.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd-v4.c
new file mode 100644
index 0000000000..851b7624ff
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd-v4.c
@@ -0,0 +1,187 @@
+/*
+ *  TP-LINK TL-WR741ND v4/TL-MR3220 v2 board support
+ *
+ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR741NDV4_GPIO_BTN_RESET	11
+#define TL_WR741NDV4_GPIO_BTN_WPS	26
+
+#define TL_WR741NDV4_GPIO_LED_WLAN	0
+#define TL_WR741NDV4_GPIO_LED_QSS	1
+#define TL_WR741NDV4_GPIO_LED_WAN	13
+#define TL_WR741NDV4_GPIO_LED_LAN1	14
+#define TL_WR741NDV4_GPIO_LED_LAN2	15
+#define TL_WR741NDV4_GPIO_LED_LAN3	16
+#define TL_WR741NDV4_GPIO_LED_LAN4	17
+#define TL_WR741NDV4_GPIO_LED_SYSTEM	27
+
+#define TL_MR3220V2_GPIO_BTN_WPS	11
+#define TL_MR3220V2_GPIO_BTN_WIFI	24
+
+#define TL_MR3220V2_GPIO_LED_3G		26
+#define TL_MR3220V2_GPIO_USB_POWER	8
+
+#define TL_WR741NDV4_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR741NDV4_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR741NDV4_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr741ndv4_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr741ndv4_flash_data = {
+	.part_probes	= tl_wr741ndv4_part_probes,
+};
+
+static struct gpio_led tl_wr741ndv4_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR741NDV4_GPIO_LED_LAN1,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR741NDV4_GPIO_LED_LAN2,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR741NDV4_GPIO_LED_LAN3,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR741NDV4_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR741NDV4_GPIO_LED_QSS,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR741NDV4_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR741NDV4_GPIO_LED_WAN,
+		.active_low	= 0,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR741NDV4_GPIO_LED_WLAN,
+		.active_low	= 0,
+	}, {
+		/* the 3G LED is only present on the MR3220 v2 */
+		.name		= "tp-link:green:3g",
+		.gpio		= TL_MR3220V2_GPIO_LED_3G,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tl_wr741ndv4_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR741NDV4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR741NDV4_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}, {
+		.desc		= "WPS",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR741NDV4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR741NDV4_GPIO_BTN_WPS,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button tl_mr3220v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR741NDV4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3220V2_GPIO_BTN_WPS,
+		.active_low	= 0,
+	}, {
+		.desc		= "WIFI button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WR741NDV4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3220V2_GPIO_BTN_WIFI,
+		.active_low	= 0,
+	}
+};
+
+static void __init tl_ap121_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_setup_ar933x_phy4_switch(true, true);
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_m25p80(&tl_wr741ndv4_flash_data);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void __init tl_wr741ndv4_setup(void)
+{
+	tl_ap121_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr741ndv4_leds_gpio) - 1,
+				 tl_wr741ndv4_leds_gpio);
+	ath79_register_gpio_keys_polled(1, TL_WR741NDV4_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr741ndv4_gpio_keys),
+					tl_wr741ndv4_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR741ND_V4, "TL-WR741ND-v4",
+	     "TP-LINK TL-WR741ND v4", tl_wr741ndv4_setup);
+
+static void __init tl_mr3220v2_setup(void)
+{
+	tl_ap121_setup();
+
+	gpio_request_one(TL_MR3220V2_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr741ndv4_leds_gpio),
+				 tl_wr741ndv4_leds_gpio);
+	ath79_register_gpio_keys_polled(1, TL_WR741NDV4_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_mr3220v2_gpio_keys),
+					tl_mr3220v2_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3220_V2, "TL-MR3220-v2",
+	     "TP-LINK TL-MR3220 v2", tl_mr3220v2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd.c
new file mode 100644
index 0000000000..5931654bbd
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd.c
@@ -0,0 +1,130 @@
+/*
+ *  TP-LINK TL-WR741ND board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define TL_WR741ND_GPIO_LED_QSS		0
+#define TL_WR741ND_GPIO_LED_SYSTEM	1
+#define TL_WR741ND_GPIO_LED_LAN1	13
+#define TL_WR741ND_GPIO_LED_LAN2	14
+#define TL_WR741ND_GPIO_LED_LAN3	15
+#define TL_WR741ND_GPIO_LED_LAN4	16
+#define TL_WR741ND_GPIO_LED_WAN		17
+
+#define TL_WR741ND_GPIO_BTN_RESET	11
+#define TL_WR741ND_GPIO_BTN_QSS		12
+
+#define TL_WR741ND_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR741ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR741ND_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr741nd_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr741nd_flash_data = {
+	.part_probes	= tl_wr741nd_part_probes,
+};
+
+static struct gpio_led tl_wr741nd_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR741ND_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR741ND_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR741ND_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR741ND_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR741ND_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR741ND_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR741ND_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr741nd_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR741ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR741ND_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR741ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR741ND_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static void __init tl_wr741nd_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_wr741nd_flash_data);
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr741nd_leds_gpio),
+				 tl_wr741nd_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WR741ND_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr741nd_gpio_keys),
+					tl_wr741nd_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_register_eth(0);
+
+	ap9x_pci_setup_wmac_led_pin(0, 1);
+	ap91_pci_init(ee, mac);
+}
+MIPS_MACHINE(ATH79_MACH_TL_WR741ND, "TL-WR741ND", "TP-LINK TL-WR741ND",
+	     tl_wr741nd_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c
new file mode 100644
index 0000000000..21c628e0a3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c
@@ -0,0 +1,98 @@
+/*
+ *  TP-LINK TL-WR802N v1
+ *
+ *  Copyright (C) 2015 Rick Pannen <pannen@gmail.com <mailto:pannen@gmail.com>>
+ *
+ *  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 TL_WR802N_V1_GPIO_LED_SYSTEM	13
+#define TL_WR802N_V1_GPIO_BTN_RESET	11
+
+#define TL_WR802N_V1_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR802N_V1_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WR802N_V1_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr802n_v1_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr802n_v1_flash_data = {
+	.part_probes	= tl_wr802n_v1_part_probes,
+};
+
+static struct gpio_led tl_wr802n_v1_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= TL_WR802N_V1_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr802n_v1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR802N_V1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR802N_V1_GPIO_BTN_RESET,
+		.active_low	= 0,
+	}
+};
+
+static void __init tl_ap143_setup(void)
+{
+		u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+		u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+		u8 tmpmac[ETH_ALEN];
+
+		ath79_register_m25p80(&tl_wr802n_v1_flash_data);
+
+		ath79_setup_ar933x_phy4_switch(false, false);
+
+		ath79_register_mdio(0, 0x0);
+
+		/* LAN */
+		ath79_switch_data.phy4_mii_en = 1;
+		ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+		ath79_eth0_data.duplex = DUPLEX_FULL;
+		ath79_eth0_data.speed = SPEED_100;
+		ath79_eth0_data.phy_mask = BIT(4);
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+		ath79_register_eth(0);
+
+		ath79_init_mac(tmpmac, mac, 0);
+		ath79_register_wmac(ee, tmpmac);
+};
+
+static void __init tl_wr802n_v1_setup(void)
+{
+	tl_ap143_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr802n_v1_leds_gpio),
+		tl_wr802n_v1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR802N_V1_KEYS_POLL_INTERVAL,
+		ARRAY_SIZE(tl_wr802n_v1_gpio_keys),
+		tl_wr802n_v1_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR802N_V1, "TL-WR802N-v1", "TP-LINK TL-WR802N v1",
+		tl_wr802n_v1_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr810n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr810n.c
new file mode 100644
index 0000000000..906c5f8d4d
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr810n.c
@@ -0,0 +1,135 @@
+/*
+ * TP-LINK TL-WR810N board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2016 Jens Steinhauser <jens.steinhauser@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR810N_GPIO_SWITCH_B1	0
+#define TL_WR810N_GPIO_SWITCH_B0	1
+#define TL_WR810N_GPIO_USB_POWER	11
+#define TL_WR810N_GPIO_BTN_RESET	12
+#define TL_WR810N_GPIO_LED_SYSTEM	13
+
+#define TL_WR810N_KEYS_POLL_INTERVAL	20 /* msecs */
+#define TL_WR810N_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR810N_KEYS_POLL_INTERVAL)
+
+#define TL_WR810N_WMAC_CALDATA_OFFSET	0x1000
+
+static const char *tl_wr810n_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr810n_flash_data = {
+	.part_probes = tl_wr810n_part_probes,
+};
+
+static struct gpio_led tl_wr810n_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= TL_WR810N_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr810n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR810N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR810N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "switch_b0",
+		.type		= EV_SW,
+		.code		= BTN_0,
+		.debounce_interval = TL_WR810N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR810N_GPIO_SWITCH_B0,
+		.active_low	= 0,
+	},
+	{
+		.desc		= "switch_b1",
+		.type		= EV_SW,
+		.code		= BTN_1,
+		.debounce_interval = TL_WR810N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR810N_GPIO_SWITCH_B1,
+		.active_low	= 0,
+	},
+};
+
+static void __init tl_wr810n_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_m25p80(&tl_wr810n_flash_data);
+	ath79_register_leds_gpio(-1,
+				 ARRAY_SIZE(tl_wr810n_leds_gpio),
+				 tl_wr810n_leds_gpio);
+	ath79_register_gpio_keys_polled(-1,
+				        TL_WR810N_KEYS_POLL_INTERVAL,
+				        ARRAY_SIZE(tl_wr810n_gpio_keys),
+				        tl_wr810n_gpio_keys);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* WAN */
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_register_eth(0);
+
+	/* LAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(art + TL_WR810N_WMAC_CALDATA_OFFSET, mac);
+
+	gpio_request_one(TL_WR810N_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR810N, "TL-WR810N", "TP-LINK TL-WR810N",
+	     tl_wr810n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v8.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v8.c
new file mode 100644
index 0000000000..73cfdd9cc6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v8.c
@@ -0,0 +1,286 @@
+/*
+ *  TP-LINK TL-WR841N/ND v8/TL-MR3420 v2 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR841NV8_GPIO_LED_WLAN	13
+#define TL_WR841NV8_GPIO_LED_QSS	15
+#define TL_WR841NV8_GPIO_LED_WAN	18
+#define TL_WR841NV8_GPIO_LED_LAN1	19
+#define TL_WR841NV8_GPIO_LED_LAN2	20
+#define TL_WR841NV8_GPIO_LED_LAN3	21
+#define TL_WR841NV8_GPIO_LED_LAN4	12
+#define TL_WR841NV8_GPIO_LED_SYSTEM	14
+
+#define TL_WR841NV8_GPIO_BTN_RESET	17
+#define TL_WR841NV8_GPIO_SW_RFKILL	16	/* WPS for MR3420 v2 */
+
+#define TL_MR3420V2_GPIO_LED_3G	11
+#define TL_MR3420V2_GPIO_USB_POWER	4
+
+#define TL_WR941NDV5_GPIO_LED_WLAN	13
+#define TL_WR941NDV5_GPIO_LED_QSS	15
+#define TL_WR941NDV5_GPIO_LED_WAN	18
+#define TL_WR941NDV5_GPIO_LED_LAN1	19
+#define TL_WR941NDV5_GPIO_LED_LAN2	20
+#define TL_WR941NDV5_GPIO_LED_LAN3	2
+#define TL_WR941NDV5_GPIO_LED_LAN4	3
+#define TL_WR941NDV5_GPIO_LED_SYSTEM	14
+
+#define TL_WR841NV8_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR841NV8_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR841NV8_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr841n_v8_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr841n_v8_flash_data = {
+	.part_probes	= tl_wr841n_v8_part_probes,
+};
+
+static struct gpio_led tl_wr841n_v8_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR841NV8_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR841NV8_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR841NV8_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR841NV8_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR841NV8_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR841NV8_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR841NV8_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR841NV8_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		/* the 3G LED is only present on the MR3420 v2 */
+		.name		= "tp-link:green:3g",
+		.gpio		= TL_MR3420V2_GPIO_LED_3G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr841n_v8_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR841NV8_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841NV8_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "RFKILL switch",
+		.type		= EV_SW,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WR841NV8_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841NV8_GPIO_SW_RFKILL,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button tl_mr3420v2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR841NV8_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841NV8_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "WPS",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR841NV8_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841NV8_GPIO_SW_RFKILL,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_led tl_wr941nd_v5_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR941NDV5_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR941NDV5_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR941NDV5_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR941NDV5_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR941NDV5_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR941NDV5_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR941NDV5_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR941NDV5_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static void __init tl_ap123_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	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);
+
+	/* config gpio4 as normal gpio function */
+	ath79_gpio_output_select(TL_MR3420V2_GPIO_USB_POWER,
+				 AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_m25p80(&tl_wr841n_v8_flash_data);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_PHY_SWAP);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, -1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+}
+
+static void __init tl_wr841n_v8_setup(void)
+{
+	tl_ap123_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v8_leds_gpio) - 1,
+				 tl_wr841n_v8_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV8_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr841n_v8_gpio_keys),
+					tl_wr841n_v8_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR841N_V8, "TL-WR841N-v8", "TP-LINK TL-WR841N/ND v8",
+	     tl_wr841n_v8_setup);
+
+
+static void __init tl_wr842n_v2_setup(void)
+{
+	tl_ap123_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v8_leds_gpio),
+				 tl_wr841n_v8_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV8_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr841n_v8_gpio_keys),
+					tl_wr841n_v8_gpio_keys);
+
+	gpio_request_one(TL_MR3420V2_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR842N_V2, "TL-WR842N-v2", "TP-LINK TL-WR842N/ND v2",
+	     tl_wr842n_v2_setup);
+
+static void __init tl_mr3420v2_setup(void)
+{
+	tl_ap123_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v8_leds_gpio),
+				tl_wr841n_v8_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV8_KEYS_POLL_INTERVAL,
+				ARRAY_SIZE(tl_mr3420v2_gpio_keys),
+				tl_mr3420v2_gpio_keys);
+
+	/* enable power for the USB port */
+	gpio_request_one(TL_MR3420V2_GPIO_USB_POWER,
+			 GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_MR3420_V2, "TL-MR3420-v2", "TP-LINK TL-MR3420 v2",
+	     tl_mr3420v2_setup);
+
+
+static void __init tl_wr941nd_v5_setup(void)
+{
+	tl_ap123_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr941nd_v5_leds_gpio),
+				 tl_wr941nd_v5_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV8_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr841n_v8_gpio_keys),
+					tl_wr841n_v8_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR941ND_V5, "TL-WR941ND-v5", "TP-LINK TL-WR941N/ND v5",
+	     tl_wr941nd_v5_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c
new file mode 100644
index 0000000000..f806568f98
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n-v9.c
@@ -0,0 +1,308 @@
+/*
+ *  TP-LINK TL-WR841N/ND v9/v11 / TL-WR842N/ND v3
+ *
+ *  Copyright (C) 2014 Matthias Schiffer <mschiffer@universe-factory.net>
+ *  Copyright (C) 2016 Cezary Jackiewicz <cezary@eko.one.pl>
+ *  Copyright (C) 2016 Stijn Segers <francesco.borromini@gmail.com>
+ *
+ *  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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define TL_WR841NV9_GPIO_LED_WLAN	13
+#define TL_WR841NV9_GPIO_LED_QSS	3
+#define TL_WR841NV9_GPIO_LED_WAN	4
+#define TL_WR841NV9_GPIO_LED_LAN1	16
+#define TL_WR841NV9_GPIO_LED_LAN2	15
+#define TL_WR841NV9_GPIO_LED_LAN3	14
+#define TL_WR841NV9_GPIO_LED_LAN4	11
+
+#define TL_WR841NV9_GPIO_BTN_RESET	12
+#define TL_WR841NV9_GPIO_BTN_WIFI	17
+
+#define TL_WR841NV11_GPIO_LED_SYSTEM	1
+#define TL_WR841NV11_GPIO_LED_QSS	3
+#define TL_WR841NV11_GPIO_LED_WAN	4
+#define TL_WR841NV11_GPIO_LED_WAN_STATUS	2
+#define TL_WR841NV11_GPIO_LED_WLAN	13
+#define TL_WR841NV11_GPIO_LED_LAN1	16
+#define TL_WR841NV11_GPIO_LED_LAN2	15
+#define TL_WR841NV11_GPIO_LED_LAN3	14
+#define TL_WR841NV11_GPIO_LED_LAN4	11
+
+#define TL_WR841NV11_GPIO_BTN_RESET	12
+#define TL_WR841NV11_GPIO_BTN_WIFI	17
+
+#define TL_WR842NV3_GPIO_LED_SYSTEM	2
+#define TL_WR842NV3_GPIO_LED_WLAN	3
+#define TL_WR842NV3_GPIO_LED_WAN_RED	4
+#define TL_WR842NV3_GPIO_LED_WAN_GREEN	11
+#define TL_WR842NV3_GPIO_LED_LAN1	12
+#define TL_WR842NV3_GPIO_LED_LAN2	13
+#define TL_WR842NV3_GPIO_LED_LAN3	14
+#define TL_WR842NV3_GPIO_LED_LAN4	15
+#define TL_WR842NV3_GPIO_LED_3G		16
+#define TL_WR842NV3_GPIO_LED_WPS	17
+
+#define TL_WR842NV3_GPIO_BTN_RESET	1
+#define TL_WR842NV3_GPIO_BTN_WIFI	0
+
+#define TL_WR841NV9_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR841NV9_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr841n_v9_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr841n_v9_flash_data = {
+	.part_probes	= tl_wr841n_v9_part_probes,
+};
+
+static struct gpio_led tl_wr841n_v9_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR841NV9_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR841NV9_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR841NV9_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr841n_v9_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841NV9_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "WIFI button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841NV9_GPIO_BTN_WIFI,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led tl_wr841n_v11_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR841NV9_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR841NV9_GPIO_LED_QSS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR841NV11_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR841NV9_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan_status",
+		.gpio		= TL_WR841NV11_GPIO_LED_WAN_STATUS,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR841NV9_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led tl_wr842n_v3_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:lan1",
+		.gpio		= TL_WR842NV3_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan2",
+		.gpio		= TL_WR842NV3_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan3",
+		.gpio		= TL_WR842NV3_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:lan4",
+		.gpio		= TL_WR842NV3_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wan",
+		.gpio		= TL_WR842NV3_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:red:wan",
+		.gpio		= TL_WR842NV3_GPIO_LED_WAN_RED,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR842NV3_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR842NV3_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:3g",
+		.gpio		= TL_WR842NV3_GPIO_LED_3G,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:green:wps",
+		.gpio		= TL_WR842NV3_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr842n_v3_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR842NV3_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "WIFI button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WR841NV9_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR842NV3_GPIO_BTN_WIFI,
+		.active_low	= 1,
+	}
+};
+
+
+static void __init tl_ap143_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 tmpmac[ETH_ALEN];
+
+	ath79_register_m25p80(&tl_wr841n_v9_flash_data);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_register_eth(0);
+
+	ath79_init_mac(tmpmac, mac, 0);
+	ath79_register_wmac(ee, tmpmac);
+}
+
+static void __init tl_wr841n_v9_setup(void)
+{
+	tl_ap143_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v9_leds_gpio),
+				 tl_wr841n_v9_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV9_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr841n_v9_gpio_keys),
+					tl_wr841n_v9_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR841N_V9, "TL-WR841N-v9", "TP-LINK TL-WR841N/ND v9",
+	     tl_wr841n_v9_setup);
+
+static void __init tl_wr841n_v11_setup(void)
+{
+	tl_ap143_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v11_leds_gpio),
+				 tl_wr841n_v11_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV9_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr841n_v9_gpio_keys),
+					tl_wr841n_v9_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR841N_V11, "TL-WR841N-v11", "TP-LINK TL-WR841N/ND v11",
+	     tl_wr841n_v11_setup);
+
+static void __init tl_wr842n_v3_setup(void)
+{
+	tl_ap143_setup();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr842n_v3_leds_gpio),
+				 tl_wr842n_v3_leds_gpio);
+
+	ath79_register_gpio_keys_polled(1, TL_WR841NV9_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr842n_v3_gpio_keys),
+					tl_wr842n_v3_gpio_keys);
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR842N_V3, "TL-WR842N-v3", "TP-LINK TL-WR842N/ND v3",
+	     tl_wr842n_v3_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n.c
new file mode 100644
index 0000000000..11f853f057
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr841n.c
@@ -0,0 +1,140 @@
+/*
+ *  TP-LINK TL-WR841N/ND v1 board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-dsa.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define TL_WR841ND_V1_GPIO_LED_SYSTEM		2
+#define TL_WR841ND_V1_GPIO_LED_QSS_GREEN	4
+#define TL_WR841ND_V1_GPIO_LED_QSS_RED		5
+
+#define TL_WR841ND_V1_GPIO_BTN_RESET		3
+#define TL_WR841ND_V1_GPIO_BTN_QSS		7
+
+#define TL_WR841ND_V1_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR841ND_V1_KEYS_DEBOUNCE_INTERVAL \
+				(3 * TL_WR841ND_V1_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition tl_wr841n_v1_partitions[] = {
+	{
+		.name		= "redboot",
+		.offset		= 0,
+		.size		= 0x020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "kernel",
+		.offset		= 0x020000,
+		.size		= 0x140000,
+	}, {
+		.name		= "rootfs",
+		.offset		= 0x160000,
+		.size		= 0x280000,
+	}, {
+		.name		= "config",
+		.offset		= 0x3e0000,
+		.size		= 0x020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x020000,
+		.size		= 0x3c0000,
+	}
+};
+
+static struct flash_platform_data tl_wr841n_v1_flash_data = {
+	.parts		= tl_wr841n_v1_partitions,
+	.nr_parts	= ARRAY_SIZE(tl_wr841n_v1_partitions),
+};
+
+static struct gpio_led tl_wr841n_v1_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR841ND_V1_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:red:qss",
+		.gpio		= TL_WR841ND_V1_GPIO_LED_QSS_RED,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR841ND_V1_GPIO_LED_QSS_GREEN,
+	}
+};
+
+static struct gpio_keys_button tl_wr841n_v1_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR841ND_V1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841ND_V1_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR841ND_V1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR841ND_V1_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static struct dsa_chip_data tl_wr841n_v1_dsa_chip = {
+	.port_names[0]  = "wan",
+	.port_names[1]  = "lan1",
+	.port_names[2]  = "lan2",
+	.port_names[3]  = "lan3",
+	.port_names[4]  = "lan4",
+	.port_names[5]  = "cpu",
+};
+
+static struct dsa_platform_data tl_wr841n_v1_dsa_data = {
+	.nr_chips	= 1,
+	.chip		= &tl_wr841n_v1_dsa_chip,
+};
+
+static void __init tl_wr841n_v1_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_dsa(&ath79_eth0_device.dev, &ath79_mdio0_device.dev,
+			   &tl_wr841n_v1_dsa_data);
+
+	ath79_register_m25p80(&tl_wr841n_v1_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr841n_v1_leds_gpio),
+				 tl_wr841n_v1_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WR841ND_V1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr841n_v1_gpio_keys),
+					tl_wr841n_v1_gpio_keys);
+	ath79_register_pci();
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR841N_V1, "TL-WR841N-v1.5", "TP-LINK TL-WR841N v1",
+	     tl_wr841n_v1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd-v6.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd-v6.c
new file mode 100644
index 0000000000..8c788e2841
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd-v6.c
@@ -0,0 +1,149 @@
+/*
+ *  TP-LINK TL-WR941N/ND v6 board support
+ *
+ *  Copyright (C) 2015 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 TL_WR941ND_V6_GPIO_LED_QSS		3
+#define TL_WR941ND_V6_GPIO_LED_WAN		14
+#define TL_WR941ND_V6_GPIO_LED_WAN_RED		15
+#define TL_WR941ND_V6_GPIO_LED_LAN1		7
+#define TL_WR941ND_V6_GPIO_LED_LAN2		6
+#define TL_WR941ND_V6_GPIO_LED_LAN3		5
+#define TL_WR941ND_V6_GPIO_LED_LAN4		4
+#define TL_WR941ND_V6_GPIO_LED_WLAN		8
+#define TL_WR941ND_V6_GPIO_LED_SYSTEM		18
+
+#define TL_WR941ND_V6_GPIO_BTN_RESET		1
+#define TL_WR941ND_V6_GPIO_BTN_RFKILL		2
+
+#define TL_WR941ND_V6_KEYS_POLL_INTERVAL	20
+#define TL_WR941ND_V6_KEYS_DEBOUNCE_INTERVAL	(3 * TL_WR941ND_V6_KEYS_POLL_INTERVAL)
+
+
+static struct gpio_led tl_wr941nd_v6_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:blue:qss",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_QSS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:wan",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:red:wan",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_WAN_RED,
+		.active_low	= 0,
+	},
+	{
+		.name		= "tp-link:blue:lan1",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_LAN1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:lan2",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_LAN2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:lan3",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_LAN3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:lan4",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_LAN4,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:wlan",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "tp-link:blue:system",
+		.gpio		= TL_WR941ND_V6_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button tl_wr941nd_v6_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR941ND_V6_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR941ND_V6_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "RFKILL button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = TL_WR941ND_V6_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR941ND_V6_GPIO_BTN_RFKILL,
+		.active_low	= 1,
+	}
+};
+
+
+static const char *tl_wr941n_v6_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr941n_v6_flash_data = {
+	.part_probes	= tl_wr941n_v6_part_probes,
+};
+
+
+static void __init tl_wr941nd_v6_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(&tl_wr941n_v6_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr941nd_v6_leds_gpio),
+				 tl_wr941nd_v6_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WR941ND_V6_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr941nd_v6_gpio_keys),
+					tl_wr941nd_v6_gpio_keys);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, -1);
+
+	ath79_switch_data.phy4_mii_en = 1;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, mac);
+
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR941ND_V6, "TL-WR941ND-v6", "TP-LINK TL-WR941N/ND v6",
+	     tl_wr941nd_v6_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd.c
new file mode 100644
index 0000000000..1ddeec730e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr941nd.c
@@ -0,0 +1,121 @@
+/*
+ *  TP-LINK TL-WR941ND board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/platform_device.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-dsa.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 TL_WR941ND_GPIO_LED_SYSTEM	2
+#define TL_WR941ND_GPIO_LED_QSS_RED	4
+#define TL_WR941ND_GPIO_LED_QSS_GREEN	5
+#define TL_WR941ND_GPIO_LED_WLAN	9
+
+#define TL_WR941ND_GPIO_BTN_RESET	3
+#define TL_WR941ND_GPIO_BTN_QSS		7
+
+#define TL_WR941ND_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TL_WR941ND_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR941ND_KEYS_POLL_INTERVAL)
+
+static const char *tl_wr941nd_part_probes[] = {
+	"tp-link",
+	NULL,
+};
+
+static struct flash_platform_data tl_wr941nd_flash_data = {
+	.part_probes	= tl_wr941nd_part_probes,
+};
+
+static struct gpio_led tl_wr941nd_leds_gpio[] __initdata = {
+	{
+		.name		= "tp-link:green:system",
+		.gpio		= TL_WR941ND_GPIO_LED_SYSTEM,
+		.active_low	= 1,
+	}, {
+		.name		= "tp-link:red:qss",
+		.gpio		= TL_WR941ND_GPIO_LED_QSS_RED,
+	}, {
+		.name		= "tp-link:green:qss",
+		.gpio		= TL_WR941ND_GPIO_LED_QSS_GREEN,
+	}, {
+		.name		= "tp-link:green:wlan",
+		.gpio		= TL_WR941ND_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button tl_wr941nd_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TL_WR941ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR941ND_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "qss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = TL_WR941ND_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_WR941ND_GPIO_BTN_QSS,
+		.active_low	= 1,
+	}
+};
+
+static struct dsa_chip_data tl_wr941nd_dsa_chip = {
+	.port_names[0]  = "wan",
+	.port_names[1]  = "lan1",
+	.port_names[2]  = "lan2",
+	.port_names[3]  = "lan3",
+	.port_names[4]  = "lan4",
+	.port_names[5]  = "cpu",
+};
+
+static struct dsa_platform_data tl_wr941nd_dsa_data = {
+	.nr_chips	= 1,
+	.chip		= &tl_wr941nd_dsa_chip,
+};
+
+static void __init tl_wr941nd_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_dsa(&ath79_eth0_device.dev, &ath79_mdio0_device.dev,
+			   &tl_wr941nd_dsa_data);
+
+	ath79_register_m25p80(&tl_wr941nd_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tl_wr941nd_leds_gpio),
+				 tl_wr941nd_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, TL_WR941ND_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tl_wr941nd_gpio_keys),
+					tl_wr941nd_gpio_keys);
+	ath79_register_wmac(eeprom, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_TL_WR941ND, "TL-WR941ND", "TP-LINK TL-WR941ND",
+	     tl_wr941nd_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tube2h.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tube2h.c
new file mode 100644
index 0000000000..19b32e2256
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tube2h.c
@@ -0,0 +1,118 @@
+/*
+ *  ALFA NETWORK Tube2H board support
+ *
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <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 TUBE2H_GPIO_LED_SIGNAL4		0
+#define TUBE2H_GPIO_LED_SIGNAL3		1
+#define TUBE2H_GPIO_LED_SIGNAL2		13
+#define TUBE2H_GPIO_LED_LAN		17
+#define TUBE2H_GPIO_LED_SIGNAL1		27
+#define TUBE2H_GPIO_EXT_LNA		28
+
+#define TUBE2H_GPIO_BTN_RESET		12
+
+#define TUBE2H_KEYS_POLL_INTERVAL	20	/* msecs */
+#define TUBE2H_KEYS_DEBOUNCE_INTERVAL	(3 * TUBE2H_KEYS_POLL_INTERVAL)
+
+#define TUBE2H_ART_ADDRESS		0x1f7f0000
+#define TUBE2H_LAN_MAC_OFFSET		0x06
+#define TUBE2H_CALDATA_OFFSET		0x1000
+
+static struct gpio_led tube2h_leds_gpio[] __initdata = {
+	{
+		.name		= "alfa:blue:lan",
+		.gpio		= TUBE2H_GPIO_LED_LAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "alfa:red:signal1",
+		.gpio		= TUBE2H_GPIO_LED_SIGNAL1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "alfa:orange:signal2",
+		.gpio		= TUBE2H_GPIO_LED_SIGNAL2,
+		.active_low	= 0,
+	},
+	{
+		.name		= "alfa:green:signal3",
+		.gpio		= TUBE2H_GPIO_LED_SIGNAL3,
+		.active_low	= 0,
+	},
+	{
+		.name		= "alfa:green:signal4",
+		.gpio		= TUBE2H_GPIO_LED_SIGNAL4,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button tube2h_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = TUBE2H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TUBE2H_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init tube2h_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(TUBE2H_ART_ADDRESS);
+	u32 t;
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_JTAG_DISABLE |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	/* Ensure that GPIO26 and GPIO27 are controllable by software */
+	t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+	t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
+	ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
+
+	gpio_request_one(TUBE2H_GPIO_EXT_LNA,
+			GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			"external LNA0");
+
+	ath79_register_wmac(art + TUBE2H_CALDATA_OFFSET, NULL);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(tube2h_leds_gpio),
+				 tube2h_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, TUBE2H_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(tube2h_gpio_keys),
+					tube2h_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + TUBE2H_LAN_MAC_OFFSET, 0);
+	ath79_register_mdio(0, 0x0);
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_TUBE2H, "TUBE2H", "ALFA NETWORK Tube2H",
+	     tube2h_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c
new file mode 100644
index 0000000000..9194bc1c07
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-unifiac.c
@@ -0,0 +1,179 @@
+/*
+ *  Ubiquiti UniFi AC (LITE) board support
+ *
+ *  Copyright (C) 2015-2016 P. Wassi <p.wassi at gmx.at>
+ *
+ *  Derived from: mach-ubnt-xm.c
+ *
+ *  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/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/etherdevice.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/irq.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/platform_data/phy-at803x.h>
+#include <linux/ar8216_platform.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-wmac.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+
+#define UNIFIAC_KEYS_POLL_INTERVAL	20
+#define UNIFIAC_KEYS_DEBOUNCE_INTERVAL	(3 * UNIFIAC_KEYS_POLL_INTERVAL)
+
+#define UNIFIAC_GPIO_LED_WHITE		7
+#define UNIFIAC_GPIO_LED_BLUE		8
+
+#define UNIFIAC_GPIO_BTN_RESET		2
+
+#define UNIFIAC_MAC0_OFFSET             0x0000
+#define UNIFIAC_WMAC_CALDATA_OFFSET     0x1000
+#define UNIFIAC_PCI_CALDATA_OFFSET      0x5000
+
+
+static struct flash_platform_data ubnt_unifiac_flash_data = {
+	/* mx25l12805d and mx25l12835f have the same JEDEC ID */
+	.type = "mx25l12805d",
+};
+
+static struct gpio_led ubnt_unifiac_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:white:dome",
+		.gpio		= UNIFIAC_GPIO_LED_WHITE,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:blue:dome",
+		.gpio		= UNIFIAC_GPIO_LED_BLUE,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button ubnt_unifiac_gpio_keys[] __initdata = {
+	{
+		.desc			= "reset",
+		.type			= EV_KEY,
+		.code			= KEY_RESTART,
+		.debounce_interval	= UNIFIAC_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= UNIFIAC_GPIO_BTN_RESET,
+		.active_low		= 1,
+	}
+};
+
+static void __init ubnt_unifiac_lite_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(&ubnt_unifiac_flash_data);
+
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+	               eeprom + UNIFIAC_MAC0_OFFSET, 0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_pll_data.pll_10 = 0x00001313;
+
+	ath79_register_mdio(0, ~BIT(4));
+	ath79_register_eth(0);
+
+
+	ath79_register_wmac(eeprom + UNIFIAC_WMAC_CALDATA_OFFSET, NULL);
+
+
+	ap91_pci_init(eeprom + UNIFIAC_PCI_CALDATA_OFFSET, NULL);
+
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifiac_leds_gpio),
+	                         ubnt_unifiac_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UNIFIAC_KEYS_POLL_INTERVAL,
+	                                ARRAY_SIZE(ubnt_unifiac_gpio_keys),
+	                                ubnt_unifiac_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFIAC_LITE, "UBNT-UF-AC-LITE", "Ubiquiti UniFi-AC-LITE",
+	     ubnt_unifiac_lite_setup);
+
+static struct ar8327_pad_cfg ubnt_unifiac_pro_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_platform_data ubnt_unifiac_pro_ar8327_data = {
+	.pad0_cfg = &ubnt_unifiac_pro_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+
+static struct mdio_board_info ubnt_unifiac_pro_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &ubnt_unifiac_pro_ar8327_data,
+	},
+};
+
+static void __init ubnt_unifiac_pro_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(&ubnt_unifiac_flash_data);
+
+
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+	               eeprom + UNIFIAC_MAC0_OFFSET, 0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	mdiobus_register_board_info(ubnt_unifiac_pro_mdio0_info,
+	                            ARRAY_SIZE(ubnt_unifiac_pro_mdio0_info));
+
+	ath79_register_mdio(0, 0x00);
+	ath79_register_eth(0);
+
+
+	ath79_register_usb();
+
+
+	ath79_register_wmac(eeprom + UNIFIAC_WMAC_CALDATA_OFFSET, NULL);
+
+
+	ap91_pci_init(eeprom + UNIFIAC_PCI_CALDATA_OFFSET, NULL);
+
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifiac_leds_gpio),
+	                         ubnt_unifiac_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UNIFIAC_KEYS_POLL_INTERVAL,
+	                                ARRAY_SIZE(ubnt_unifiac_gpio_keys),
+	                                ubnt_unifiac_gpio_keys);
+}
+
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFIAC_PRO, "UBNT-UF-AC-PRO", "Ubiquiti UniFi-AC-PRO",
+	     ubnt_unifiac_pro_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c
new file mode 100644
index 0000000000..55cf52d19e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt-xm.c
@@ -0,0 +1,718 @@
+/*
+ *  Ubiquiti Networks XM (rev 1.0) board support
+ *
+ *  Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
+ *
+ *  Derived from: mach-pb44.c
+ *
+ *  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/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/etherdevice.h>
+#include <linux/ar8216_platform.h>
+#include <linux/platform_data/phy-at803x.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/irq.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/platform_data/phy-at803x.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define UBNT_XM_GPIO_LED_L1		0
+#define UBNT_XM_GPIO_LED_L2		1
+#define UBNT_XM_GPIO_LED_L3		11
+#define UBNT_XM_GPIO_LED_L4		7
+
+#define UBNT_XM_GPIO_BTN_RESET		12
+
+#define UBNT_XM_KEYS_POLL_INTERVAL	20
+#define UBNT_XM_KEYS_DEBOUNCE_INTERVAL	(3 * UBNT_XM_KEYS_POLL_INTERVAL)
+
+#define UBNT_XM_EEPROM_ADDR		0x1fff1000
+
+static struct gpio_led ubnt_xm_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:red:link1",
+		.gpio		= UBNT_XM_GPIO_LED_L1,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:orange:link2",
+		.gpio		= UBNT_XM_GPIO_LED_L2,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:link3",
+		.gpio		= UBNT_XM_GPIO_LED_L3,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:link4",
+		.gpio		= UBNT_XM_GPIO_LED_L4,
+		.active_low	= 0,
+	},
+};
+
+static struct gpio_keys_button ubnt_xm_gpio_keys[] __initdata = {
+	{
+		.desc			= "reset",
+		.type			= EV_KEY,
+		.code			= KEY_RESTART,
+		.debounce_interval	= UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= UBNT_XM_GPIO_BTN_RESET,
+		.active_low		= 1,
+	}
+};
+
+#define UBNT_M_WAN_PHYMASK	BIT(4)
+
+static void __init ubnt_xm_init(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(UBNT_XM_EEPROM_ADDR);
+	u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio),
+				 ubnt_xm_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ubnt_xm_gpio_keys),
+					ubnt_xm_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+	ap91_pci_init(eeprom, NULL);
+
+	ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_XM,
+	     "UBNT-XM",
+	     "Ubiquiti Networks XM (rev 1.0) board",
+	     ubnt_xm_init);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_BULLET_M, "UBNT-BM", "Ubiquiti Bullet M",
+	     ubnt_xm_init);
+
+static void __init ubnt_rocket_m_setup(void)
+{
+	ubnt_xm_init();
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M, "UBNT-RM", "Ubiquiti Rocket M",
+	     ubnt_rocket_m_setup);
+
+static void __init ubnt_nano_m_setup(void)
+{
+	ubnt_xm_init();
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M, "UBNT-NM", "Ubiquiti Nanostation M",
+	     ubnt_nano_m_setup);
+
+static struct gpio_led ubnt_airrouter_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:green:globe",
+		.gpio		= 0,
+		.active_low	= 1,
+	}, {
+	        .name		= "ubnt:green:power",
+		.gpio		= 11,
+		.active_low	= 1,
+		.default_state  = LEDS_GPIO_DEFSTATE_ON,
+	}
+};
+
+static void __init ubnt_airrouter_setup(void)
+{
+	u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_local_mac(ath79_eth1_data.mac_addr, mac1);
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+	ath79_register_usb();
+
+	ap91_pci_init(ee, NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airrouter_leds_gpio),
+				 ubnt_airrouter_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_AIRROUTER, "UBNT-AR", "Ubiquiti AirRouter",
+	     ubnt_airrouter_setup);
+
+static struct gpio_led ubnt_unifi_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:orange:dome",
+		.gpio		= 1,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:dome",
+		.gpio		= 0,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_led ubnt_unifi_outdoor_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:orange:front",
+		.gpio		= 1,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:front",
+		.gpio		= 0,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_led ubnt_unifi_outdoor_plus_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:white:front",
+		.gpio		= 1,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:blue:front",
+		.gpio		= 0,
+		.active_low	= 0,
+	}
+};
+
+
+static void __init ubnt_unifi_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_mdio(0, ~UBNT_M_WAN_PHYMASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_register_eth(0);
+
+	ap91_pci_init(ee, NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_leds_gpio),
+				 ubnt_unifi_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI, "UBNT-UF", "Ubiquiti UniFi",
+	     ubnt_unifi_setup);
+
+
+#define UBNT_UNIFIOD_PRI_PHYMASK	BIT(4)
+#define UBNT_UNIFIOD_2ND_PHYMASK	(BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+static void __init ubnt_unifi_outdoor_setup(void)
+{
+	u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_mdio(0, ~(UBNT_UNIFIOD_PRI_PHYMASK |
+				 UBNT_UNIFIOD_2ND_PHYMASK));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ap91_pci_init(ee, NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_outdoor_leds_gpio),
+				 ubnt_unifi_outdoor_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI_OUTDOOR, "UBNT-U20",
+	     "Ubiquiti UniFiAP Outdoor",
+	     ubnt_unifi_outdoor_setup);
+
+
+static void __init ubnt_unifi_outdoor_plus_setup(void)
+{
+	u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac2 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_mdio(0, ~(UBNT_UNIFIOD_PRI_PHYMASK |
+				 UBNT_UNIFIOD_2ND_PHYMASK));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 0);
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ap9x_pci_get_wmac_data(0)->ubnt_hsr = true;
+	ap91_pci_init(ee, NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_unifi_outdoor_plus_leds_gpio),
+				 ubnt_unifi_outdoor_plus_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UNIFI_OUTDOOR_PLUS, "UBNT-UOP",
+	     "Ubiquiti UniFiAP Outdoor+",
+	     ubnt_unifi_outdoor_plus_setup);
+
+
+static struct gpio_led ubnt_uap_pro_gpio_leds[] __initdata = {
+	{
+		.name		= "ubnt:white:dome",
+		.gpio		= 12,
+	}, {
+		.name		= "ubnt:blue:dome",
+		.gpio		= 13,
+	}
+};
+
+static struct gpio_keys_button uap_pro_gpio_keys[] __initdata = {
+	{
+		.desc			= "reset",
+		.type			= EV_KEY,
+		.code			= KEY_RESTART,
+		.debounce_interval	= UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= 17,
+		.active_low		= 1,
+	}
+};
+
+static struct ar8327_pad_cfg uap_pro_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data uap_pro_ar8327_data = {
+	.pad0_cfg = &uap_pro_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info uap_pro_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &uap_pro_ar8327_data,
+	},
+};
+
+#define UAP_PRO_MAC0_OFFSET		0x0000
+#define UAP_PRO_MAC1_OFFSET		0x0006
+#define UAP_PRO_WMAC_CALDATA_OFFSET	0x1000
+#define UAP_PRO_PCI_CALDATA_OFFSET	0x5000
+
+static void __init ubnt_uap_pro_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_uap_pro_gpio_leds),
+				 ubnt_uap_pro_gpio_leds);
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(uap_pro_gpio_keys),
+                                        uap_pro_gpio_keys);
+
+	ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+	ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+	ath79_register_mdio(0, 0x0);
+	mdiobus_register_board_info(uap_pro_mdio0_info,
+				    ARRAY_SIZE(uap_pro_mdio0_info));
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       eeprom + UAP_PRO_MAC0_OFFSET, 0);
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_UAP_PRO, "UAP-PRO", "Ubiquiti UniFi AP Pro",
+	     ubnt_uap_pro_setup);
+
+#define UBNT_XW_GPIO_LED_L1		11
+#define UBNT_XW_GPIO_LED_L2		16
+#define UBNT_XW_GPIO_LED_L3		13
+#define UBNT_XW_GPIO_LED_L4		14
+
+static struct gpio_led ubnt_xw_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:red:link1",
+		.gpio		= UBNT_XW_GPIO_LED_L1,
+		.active_low	= 1,
+	}, {
+		.name		= "ubnt:orange:link2",
+		.gpio		= UBNT_XW_GPIO_LED_L2,
+		.active_low	= 1,
+	}, {
+		.name		= "ubnt:green:link3",
+		.gpio		= UBNT_XW_GPIO_LED_L3,
+		.active_low	= 1,
+	}, {
+		.name		= "ubnt:green:link4",
+		.gpio		= UBNT_XW_GPIO_LED_L4,
+		.active_low	= 1,
+	},
+};
+
+#define UBNT_ROCKET_TI_GPIO_LED_L1	16
+#define UBNT_ROCKET_TI_GPIO_LED_L2	17
+#define UBNT_ROCKET_TI_GPIO_LED_L3	18
+#define UBNT_ROCKET_TI_GPIO_LED_L4	19
+#define UBNT_ROCKET_TI_GPIO_LED_L5	20
+#define UBNT_ROCKET_TI_GPIO_LED_L6	21
+static struct gpio_led ubnt_rocket_ti_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:green:link1",
+		.gpio		= UBNT_ROCKET_TI_GPIO_LED_L1,
+		.active_low	= 1,
+	}, {
+		.name		= "ubnt:green:link2",
+		.gpio		= UBNT_ROCKET_TI_GPIO_LED_L2,
+		.active_low	= 1,
+	}, {
+		.name		= "ubnt:green:link3",
+		.gpio		= UBNT_ROCKET_TI_GPIO_LED_L3,
+		.active_low	= 1,
+	}, {
+		.name		= "ubnt:green:link4",
+		.gpio		= UBNT_ROCKET_TI_GPIO_LED_L4,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:link5",
+		.gpio		= UBNT_ROCKET_TI_GPIO_LED_L5,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:link6",
+		.gpio		= UBNT_ROCKET_TI_GPIO_LED_L6,
+		.active_low	= 0,
+	},
+};
+
+static void __init ubnt_xw_init(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xw_leds_gpio),
+				 ubnt_xw_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+
+	ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+	ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+
+	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);
+
+	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_register_eth(0);
+}
+
+static struct at803x_platform_data ubnt_loco_m_xw_at803x_data = {
+	.has_reset_gpio = 1,
+	.reset_gpio = 0,
+};
+
+static struct mdio_board_info ubnt_loco_m_xw_mdio_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 1,
+		.platform_data = &ubnt_loco_m_xw_at803x_data,
+	},
+};
+
+static void __init ubnt_loco_m_xw_setup(void)
+{
+	ubnt_xw_init();
+
+	mdiobus_register_board_info(ubnt_loco_m_xw_mdio_info,
+				    ARRAY_SIZE(ubnt_loco_m_xw_mdio_info));
+
+	ath79_register_mdio(0, ~BIT(1));
+	ath79_eth0_data.phy_mask = BIT(1);
+	ath79_register_eth(0);
+}
+
+static void __init ubnt_rocket_m_xw_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xw_leds_gpio),
+				 ubnt_xw_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+
+	ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+	ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       eeprom + UAP_PRO_MAC0_OFFSET, 0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_mdio(0, ~BIT(4));
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+}
+
+static struct at803x_platform_data ubnt_rocket_m_ti_at803_data = {
+	.disable_smarteee = 1,
+	.enable_rgmii_rx_delay = 1,
+	.enable_rgmii_tx_delay = 1,
+};
+static struct mdio_board_info ubnt_rocket_m_ti_mdio_info[] = {
+        {
+                .bus_id = "ag71xx-mdio.0",
+                .phy_addr = 4,
+                .platform_data = &ubnt_rocket_m_ti_at803_data,
+        },
+};
+
+static void __init ubnt_rocket_m_ti_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_rocket_ti_leds_gpio),
+				 ubnt_rocket_ti_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                        ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                        ubnt_xm_gpio_keys);
+
+	ap91_pci_init(eeprom + 0x1000, NULL);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+	ath79_setup_ar934x_eth_rx_delay(3, 3);
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       eeprom + UAP_PRO_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr,
+		       eeprom + UAP_PRO_MAC1_OFFSET, 0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.mii_bus_dev = &ath79_mdio1_device.dev;
+
+	mdiobus_register_board_info(ubnt_rocket_m_ti_mdio_info,
+			ARRAY_SIZE(ubnt_rocket_m_ti_mdio_info));
+	ath79_register_mdio(0, 0x0);
+
+
+	ath79_eth0_data.phy_mask = BIT(4);
+	/* read out from vendor */
+	ath79_eth0_pll_data.pll_1000 = 0x2000000;
+	ath79_eth0_pll_data.pll_10 = 0x1313;
+	ath79_register_eth(0);
+
+	ath79_register_mdio(1, 0x0);
+	ath79_eth1_data.phy_mask = BIT(3);
+	ath79_register_eth(1);
+}
+
+
+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);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M_XW, "UBNT-RM-XW", "Ubiquiti Rocket M XW",
+	     ubnt_rocket_m_xw_setup);
+
+MIPS_MACHINE(ATH79_MACH_UBNT_ROCKET_M_TI, "UBNT-RM-TI", "Ubiquiti Rocket M TI",
+	     ubnt_rocket_m_ti_setup);
+
+static struct gpio_led ubnt_airgateway_gpio_leds[] __initdata = {
+	{
+		.name	   = "ubnt:blue:wlan",
+		.gpio	   = 0,
+	}, {
+		.name	   = "ubnt:white:status",
+		.gpio	   = 1,
+	},
+};
+
+static struct gpio_keys_button airgateway_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval	= UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 12,
+		.active_low	= 1,
+	}
+};
+
+static void __init ubnt_airgateway_setup(void)
+{
+	u32 t;
+	u8 *mac0 = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac1 = (u8 *) KSEG1ADDR(0x1fff0000 + ETH_ALEN);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				     AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+	t |= AR933X_BOOTSTRAP_MDIO_GPIO_EN;
+	ath79_reset_wr(AR933X_RESET_REG_BOOTSTRAP, t);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airgateway_gpio_leds),
+				 ubnt_airgateway_gpio_leds);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(airgateway_gpio_keys),
+					airgateway_gpio_keys);
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac0, 0);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_register_eth(1);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(ee, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_AIRGW, "UBNT-AGW", "Ubiquiti AirGateway",
+	     ubnt_airgateway_setup);
+
+static struct gpio_led ubnt_airgateway_pro_gpio_leds[] __initdata = {
+	{
+		.name	   = "ubnt:blue:wlan",
+		.gpio	   = 13,
+	}, {
+		.name	   = "ubnt:white:status",
+		.gpio	   = 17,
+	},
+};
+
+
+static struct gpio_keys_button airgateway_pro_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval	= UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 12,
+		.active_low	= 1,
+	}
+};
+
+static void __init ubnt_airgateway_pro_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac0 = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_airgateway_pro_gpio_leds),
+				 ubnt_airgateway_pro_gpio_leds);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(airgateway_pro_gpio_keys),
+					airgateway_pro_gpio_keys);
+
+	ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+	ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_register_mdio(1, 0x0);
+
+	/* GMAC0 is left unused in this configuration */
+
+	/* GMAC1 is connected to MAC0 on the internal switch */
+	/* The PoE/WAN port connects to port 5 on the internal switch */
+	/* The LAN port connects to port 4 on the internal switch */
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac0, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_AIRGWP, "UBNT-AGWP", "Ubiquiti AirGateway Pro",
+	     ubnt_airgateway_pro_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt.c
new file mode 100644
index 0000000000..e49ac23fd1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-ubnt.c
@@ -0,0 +1,205 @@
+/*
+ *  Ubiquiti RouterStation support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *  Copyright (C) 2008 Ubiquiti <support@ubnt.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define UBNT_RS_GPIO_LED_RF	2
+#define UBNT_RS_GPIO_SW4	8
+
+#define UBNT_LS_SR71_GPIO_LED_D25	0
+#define UBNT_LS_SR71_GPIO_LED_D26	1
+#define UBNT_LS_SR71_GPIO_LED_D24	2
+#define UBNT_LS_SR71_GPIO_LED_D23	4
+#define UBNT_LS_SR71_GPIO_LED_D22	5
+#define UBNT_LS_SR71_GPIO_LED_D27	6
+#define UBNT_LS_SR71_GPIO_LED_D28	7
+
+#define UBNT_KEYS_POLL_INTERVAL		20	/* msecs */
+#define UBNT_KEYS_DEBOUNCE_INTERVAL	(3 * UBNT_KEYS_POLL_INTERVAL)
+
+static struct gpio_led ubnt_rs_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:green:rf",
+		.gpio		= UBNT_RS_GPIO_LED_RF,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_led ubnt_ls_sr71_leds_gpio[] __initdata = {
+	{
+		.name		= "ubnt:green:d22",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D22,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:d23",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D23,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:d24",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D24,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:red:d25",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D25,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:red:d26",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D26,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:d27",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D27,
+		.active_low	= 0,
+	}, {
+		.name		= "ubnt:green:d28",
+		.gpio		= UBNT_LS_SR71_GPIO_LED_D28,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button ubnt_gpio_keys[] __initdata = {
+	{
+		.desc		= "sw4",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = UBNT_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= UBNT_RS_GPIO_SW4,
+		.active_low	= 1,
+	}
+};
+
+static const char *ubnt_part_probes[] = {
+	"RedBoot",
+	NULL,
+};
+
+static struct flash_platform_data ubnt_flash_data = {
+	.part_probes	= ubnt_part_probes,
+};
+
+static void __init ubnt_generic_setup(void)
+{
+	ath79_register_m25p80(&ubnt_flash_data);
+
+	ath79_register_gpio_keys_polled(-1, UBNT_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ubnt_gpio_keys),
+					ubnt_gpio_keys);
+	ath79_register_pci();
+}
+
+#define UBNT_RS_WAN_PHYMASK	BIT(20)
+#define UBNT_RS_LAN_PHYMASK	(BIT(16) | BIT(17) | BIT(18) | BIT(19))
+
+static void __init ubnt_rs_setup(void)
+{
+	ubnt_generic_setup();
+
+	ath79_register_mdio(0, ~(UBNT_RS_WAN_PHYMASK | UBNT_RS_LAN_PHYMASK));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = UBNT_RS_WAN_PHYMASK;
+
+	/*
+	 * There is Secondary MAC address duplicate problem with some
+	 * UBNT HW batches.  Do not increase Secondary MAC address by 1
+	 * but do workaround with 'Locally Administrated' bit.
+	 */
+	ath79_init_local_mac(ath79_eth1_data.mac_addr, ath79_mac_base);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.speed = SPEED_100;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_rs_leds_gpio),
+				 ubnt_rs_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_RS, "UBNT-RS", "Ubiquiti RouterStation",
+	     ubnt_rs_setup);
+
+#define UBNT_RSPRO_WAN_PHYMASK	BIT(4)
+#define UBNT_RSPRO_LAN_PHYMASK	(BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+static void __init ubnt_rspro_setup(void)
+{
+	ubnt_generic_setup();
+
+	ath79_register_mdio(0, ~(UBNT_RSPRO_WAN_PHYMASK |
+				 UBNT_RSPRO_LAN_PHYMASK));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = UBNT_RSPRO_WAN_PHYMASK;
+
+	/*
+	 * There is Secondary MAC address duplicate problem with some
+	 * UBNT HW batches.  Do not increase Secondary MAC address by 1
+	 * but do workaround with 'Locally Administrated' bit.
+	 */
+	ath79_init_local_mac(ath79_eth1_data.mac_addr, ath79_mac_base);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = UBNT_RSPRO_LAN_PHYMASK;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_rs_leds_gpio),
+				 ubnt_rs_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_RSPRO, "UBNT-RSPRO", "Ubiquiti RouterStation Pro",
+	     ubnt_rspro_setup);
+
+static void __init ubnt_lsx_setup(void)
+{
+	ubnt_generic_setup();
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_LSX, "UBNT-LSX", "Ubiquiti LSX", ubnt_lsx_setup);
+
+#define UBNT_LSSR71_PHY_MASK	BIT(1)
+
+static void __init ubnt_lssr71_setup(void)
+{
+	ubnt_generic_setup();
+
+	ath79_register_mdio(0, ~UBNT_LSSR71_PHY_MASK);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = UBNT_LSSR71_PHY_MASK;
+
+	ath79_register_eth(0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_ls_sr71_leds_gpio),
+				 ubnt_ls_sr71_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_LSSR71, "UBNT-LS-SR71", "Ubiquiti LS-SR71",
+	     ubnt_lssr71_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-weio.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-weio.c
new file mode 100644
index 0000000000..3973ada7c3
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-weio.c
@@ -0,0 +1,140 @@
+/**
+ * WEIO Web Of Things Platform
+ *
+ * Copyright (C) 2013 Drasko DRASKOVIC and Uros PETREVSKI
+ *
+ *              ##      ## ######## ####  #######  
+ *              ##  ##  ## ##        ##  ##     ## 
+ *              ##  ##  ## ##        ##  ##     ## 
+ *              ##  ##  ## ######    ##  ##     ## 
+ *              ##  ##  ## ##        ##  ##     ## 
+ *              ##  ##  ## ##        ##  ##     ## 
+ *               ###  ###  ######## ####  #######
+ *
+ *                   Web Of Things Platform
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors : 
+ * Drasko DRASKOVIC <drasko.draskovic@gmail.com>
+ * Uros PETREVSKI <uros@nodesign.net>
+ */
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_device.h>
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WEIO_GPIO_LED_STA		1
+#define WEIO_GPIO_LED_AP		16
+
+#define WEIO_GPIO_BTN_AP		20
+#define WEIO_GPIO_BTN_RESET		23
+
+#define WEIO_KEYS_POLL_INTERVAL		20	/* msecs */
+#define WEIO_KEYS_DEBOUNCE_INTERVAL	(3 * WEIO_KEYS_POLL_INTERVAL)
+
+#define WEIO_MAC0_OFFSET			0x0000
+#define WEIO_MAC1_OFFSET			0x0006
+#define WEIO_CALDATA_OFFSET			0x1000
+#define WEIO_WMAC_MAC_OFFSET		0x1002
+
+static struct gpio_led weio_leds_gpio[] __initdata = {
+	{
+		.name		= "weio:green:sta",
+		.gpio		= WEIO_GPIO_LED_STA,
+		.active_low	= 1,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	},
+	{
+		.name		= "weio:green:ap",
+		.gpio		= WEIO_GPIO_LED_AP,
+		.active_low	= 1,
+		.default_state = LEDS_GPIO_DEFSTATE_ON,
+	}
+};
+
+static struct gpio_keys_button weio_gpio_keys[] __initdata = {
+	{
+		.desc		= "ap button",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = WEIO_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WEIO_GPIO_BTN_AP,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "soft-reset button",
+		.type		= EV_KEY,
+		.code		= BTN_1,
+		.debounce_interval = WEIO_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WEIO_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct i2c_gpio_platform_data weio_i2c_gpio_data = {
+	.sda_pin        = 18,
+	.scl_pin        = 19,
+};
+
+static struct platform_device weio_i2c_gpio = {
+	.name           = "i2c-gpio",
+	.id             = 0,
+	.dev            = {
+		.platform_data  = &weio_i2c_gpio_data,
+	},
+};
+
+static void __init weio_common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_wmac(art + WEIO_CALDATA_OFFSET, art + WEIO_WMAC_MAC_OFFSET);
+}
+
+static void __init weio_setup(void)
+{
+	weio_common_setup();
+
+	ath79_gpio_function_disable(AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	platform_device_register(&weio_i2c_gpio);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(weio_leds_gpio),
+				weio_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WEIO_KEYS_POLL_INTERVAL,
+				ARRAY_SIZE(weio_gpio_keys),
+				weio_gpio_keys);
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_WEIO, "WEIO", "WeIO board", weio_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c
new file mode 100644
index 0000000000..48f49ad0f7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-whr-hp-g300n.c
@@ -0,0 +1,155 @@
+/*
+ *  Buffalo WHR-HP-G300N board support
+ *
+ *  based on ...
+ *
+ *  TP-LINK TL-WR741ND board support
+ *
+ *  Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define WHRHPG300N_GPIO_LED_SECURITY		0
+#define WHRHPG300N_GPIO_LED_DIAG		1
+#define WHRHPG300N_GPIO_LED_ROUTER		6
+
+#define WHRHPG300N_GPIO_BTN_ROUTER_ON		7
+#define WHRHPG300N_GPIO_BTN_ROUTER_AUTO		8
+#define WHRHPG300N_GPIO_BTN_RESET		11
+#define WHRHPG300N_GPIO_BTN_AOSS		12
+#define WHRHPG300N_GPIO_LED_LAN1		13
+#define WHRHPG300N_GPIO_LED_LAN2		14
+#define WHRHPG300N_GPIO_LED_LAN3		15
+#define WHRHPG300N_GPIO_LED_LAN4		16
+#define WHRHPG300N_GPIO_LED_WAN			17
+
+#define	WHRHPG300N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WHRHPG300N_KEYS_DEBOUNCE_INTERVAL (3 * WHRHPG300N_KEYS_POLL_INTERVAL)
+
+#define WHRHPG300N_MAC_OFFSET		0x20c
+
+static struct gpio_led whrhpg300n_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:orange:security",
+		.gpio		= WHRHPG300N_GPIO_LED_SECURITY,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:red:diag",
+		.gpio		= WHRHPG300N_GPIO_LED_DIAG,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:router",
+		.gpio		= WHRHPG300N_GPIO_LED_ROUTER,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:wan",
+		.gpio		= WHRHPG300N_GPIO_LED_WAN,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:lan1",
+		.gpio		= WHRHPG300N_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:lan2",
+		.gpio		= WHRHPG300N_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:lan3",
+		.gpio		= WHRHPG300N_GPIO_LED_LAN3,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:lan4",
+		.gpio		= WHRHPG300N_GPIO_LED_LAN4,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button whrhpg300n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WHRHPG300N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WHRHPG300N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "aoss/wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.gpio		= WHRHPG300N_GPIO_BTN_AOSS,
+		.debounce_interval = WHRHPG300N_KEYS_DEBOUNCE_INTERVAL,
+		.active_low	= 1,
+	}, {
+		.desc		= "router_on",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.gpio		= WHRHPG300N_GPIO_BTN_ROUTER_ON,
+		.debounce_interval = WHRHPG300N_KEYS_DEBOUNCE_INTERVAL,
+		.active_low	= 1,
+	}, {
+		.desc		= "router_auto",
+		.type		= EV_KEY,
+		.code		= BTN_3,
+		.gpio		= WHRHPG300N_GPIO_BTN_ROUTER_AUTO,
+		.debounce_interval = WHRHPG300N_KEYS_DEBOUNCE_INTERVAL,
+		.active_low	= 1,
+	}
+};
+
+static void __init whrhpg300n_setup(void)
+{
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 *mac = (u8 *) KSEG1ADDR(ee + WHRHPG300N_MAC_OFFSET);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(whrhpg300n_leds_gpio),
+				 whrhpg300n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WHRHPG300N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(whrhpg300n_gpio_keys),
+					whrhpg300n_gpio_keys);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN ports */
+	ath79_register_eth(1);
+	/* WAN port */
+	ath79_register_eth(0);
+
+	ap9x_pci_setup_wmac_led_pin(0, 1);
+
+	ap91_pci_init(ee, mac);
+}
+
+MIPS_MACHINE(ATH79_MACH_WHR_HP_G300N, "WHR-HP-G300N", "Buffalo WHR-HP-G300N",
+	     whrhpg300n_setup);
+
+MIPS_MACHINE(ATH79_MACH_WHR_G301N, "WHR-G301N", "Buffalo WHR-G301N",
+	     whrhpg300n_setup);
+
+MIPS_MACHINE(ATH79_MACH_WHR_HP_GN, "WHR-HP-GN", "Buffalo WHR-HP-GN",
+	     whrhpg300n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wlae-ag300n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wlae-ag300n.c
new file mode 100644
index 0000000000..11006fd1bc
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wlae-ag300n.c
@@ -0,0 +1,114 @@
+/*
+ *  Buffalo WLAE-AG300N board support
+ */
+
+#include <linux/gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define WLAEAG300N_MAC_OFFSET		0x20c
+#define WLAEAG300N_KEYS_POLL_INTERVAL	20      /* msecs */
+#define WLAEAG300N_KEYS_DEBOUNCE_INTERVAL (3 * WLAEAG300N_KEYS_POLL_INTERVAL)
+
+
+static struct gpio_led wlaeag300n_leds_gpio[] __initdata = {
+	/*
+	 * Note: Writing 1 into GPIO 13 will power down the device.
+	 */
+	{
+		.name		= "buffalo:green:wireless",
+		.gpio		= 14,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:red:wireless",
+		.gpio		= 15,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:status",
+		.gpio		= 16,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:red:status",
+		.gpio		= 17,
+		.active_low	= 1,
+	}
+};
+
+
+static struct gpio_keys_button wlaeag300n_gpio_keys[] __initdata = {
+	{
+		.desc		= "function",
+		.type		= EV_KEY,
+		.code		= KEY_MODE,
+		.debounce_interval = WLAEAG300N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 0,
+		.active_low	= 1,
+	}, {
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WLAEAG300N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 1,
+		.active_low	= 1,
+	}, {
+		.desc		= "power",
+		.type		= EV_KEY,
+		.code		= KEY_POWER,
+		.debounce_interval = WLAEAG300N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 11,
+		.active_low	= 1,
+	}, {
+		.desc		= "aoss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WLAEAG300N_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 12,
+		.active_low	= 1,
+	}
+};
+
+static void __init wlaeag300n_setup(void)
+{
+	u8 *eeprom1 = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 *mac1 = eeprom1 + WLAEAG300N_MAC_OFFSET;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac1, 1);
+
+	ath79_register_mdio(0, ~(BIT(0) | BIT(4)));
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = BIT(4);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wlaeag300n_leds_gpio),
+					wlaeag300n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WLAEAG300N_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(wlaeag300n_gpio_keys),
+					 wlaeag300n_gpio_keys);
+
+	ath79_register_m25p80(NULL);
+
+	ap91_pci_init(eeprom1, mac1);
+}
+
+MIPS_MACHINE(ATH79_MACH_WLAE_AG300N, "WLAE-AG300N",
+	     "Buffalo WLAE-AG300N", wlaeag300n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wlr8100.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wlr8100.c
new file mode 100644
index 0000000000..88022e7533
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wlr8100.c
@@ -0,0 +1,205 @@
+/*
+ * Sitecom X8 AC1750 WLR-8100 board support
+ *
+ * Based on the Qualcomm Atheros AP135/AP136 reference board support code
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WLR8100_GPIO_LED_USB		4
+#define WLR8100_GPIO_LED_WLAN_5G	12
+#define WLR8100_GPIO_LED_WLAN_2G	13
+#define WLR8100_GPIO_LED_STATUS_RED	14
+#define WLR8100_GPIO_LED_WPS_RED	15
+#define WLR8100_GPIO_LED_STATUS_AMBER	19
+#define WLR8100_GPIO_LED_WPS_GREEN	20
+
+#define WLR8100_GPIO_BTN_WPS		16
+#define WLR8100_GPIO_BTN_RFKILL		21
+
+#define WLR8100_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WLR8100_KEYS_DEBOUNCE_INTERVAL	(3 * WLR8100_KEYS_POLL_INTERVAL)
+
+#define WLR8100_MAC0_OFFSET		0
+#define WLR8100_MAC1_OFFSET		6
+#define WLR8100_WMAC_CALDATA_OFFSET	0x1000
+#define WLR8100_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led wlr8100_leds_gpio[] __initdata = {
+	{
+		.name		= "wlr8100:amber:status",
+		.gpio		= WLR8100_GPIO_LED_STATUS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wlr8100:red:status",
+		.gpio		= WLR8100_GPIO_LED_STATUS_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wlr8100:green:wps",
+		.gpio		= WLR8100_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wlr8100:red:wps",
+		.gpio		= WLR8100_GPIO_LED_WPS_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wlr8100:red:wlan-2g",
+		.gpio		= WLR8100_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wlr8100:red:usb",
+		.gpio		= WLR8100_GPIO_LED_USB,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wlr8100_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WLR8100_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WLR8100_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WLR8100_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WLR8100_GPIO_BTN_RFKILL,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg wlr8100_ar8327_pad0_cfg;
+static struct ar8327_pad_cfg wlr8100_ar8327_pad6_cfg;
+
+static struct ar8327_platform_data wlr8100_ar8327_data = {
+	.pad0_cfg = &wlr8100_ar8327_pad0_cfg,
+	.pad6_cfg = &wlr8100_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info wlr8100_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wlr8100_ar8327_data,
+	},
+};
+
+static void __init wlr8100_common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wlr8100_leds_gpio),
+				 wlr8100_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WLR8100_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wlr8100_gpio_keys),
+					wlr8100_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(art + WLR8100_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + WLR8100_MAC0_OFFSET, 0);
+
+	mdiobus_register_board_info(wlr8100_mdio0_info,
+				    ARRAY_SIZE(wlr8100_mdio0_info));
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected tot eh SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(1);
+}
+
+static void __init wlr8100_010_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/* GMAC0 of the AR8337 switch is connected to GMAC0 via RGMII */
+	wlr8100_ar8327_pad0_cfg.mode = AR8327_PAD_MAC_RGMII;
+	wlr8100_ar8327_pad0_cfg.txclk_delay_en = true;
+	wlr8100_ar8327_pad0_cfg.rxclk_delay_en = true;
+	wlr8100_ar8327_pad0_cfg.txclk_delay_sel = AR8327_CLK_DELAY_SEL1;
+	wlr8100_ar8327_pad0_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2;
+
+	/* GMAC6 of the AR8337 switch is connected to GMAC1 via SGMII */
+	wlr8100_ar8327_pad6_cfg.mode = AR8327_PAD_MAC_SGMII;
+	wlr8100_ar8327_pad6_cfg.rxclk_delay_en = true;
+	wlr8100_ar8327_pad6_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0;
+
+	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	wlr8100_common_setup();
+	ap91_pci_init(art + WLR8100_PCIE_CALDATA_OFFSET, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WLR8100, "WLR8100",
+	     "Sitecom WLR-8100",
+	     wlr8100_010_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wndap360.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wndap360.c
new file mode 100644
index 0000000000..e70d88b407
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wndap360.c
@@ -0,0 +1,105 @@
+/*
+ *  Netgear WNDAP360 board support (proper leds / button support missing)
+ *
+ *  Based on AP96
+ *  Copyright (C) 2013 Jacek Kikiewicz
+ *  Copyright (C) 2009 Marco Porsch
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Atheros Communications
+ *
+ *  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/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define WNDAP360_GPIO_LED_POWER_ORANGE		0
+#define WNDAP360_GPIO_LED_POWER_GREEN		2
+
+/* Reset button - next to the power connector */
+#define WNDAP360_GPIO_BTN_RESET			8
+
+#define WNDAP360_KEYS_POLL_INTERVAL		20	/* msecs */
+#define WNDAP360_KEYS_DEBOUNCE_INTERVAL	(3 * WNDAP360_KEYS_POLL_INTERVAL)
+
+#define WNDAP360_WMAC0_MAC_OFFSET		0x120c
+#define WNDAP360_WMAC1_MAC_OFFSET		0x520c
+#define WNDAP360_CALDATA0_OFFSET		0x1000
+#define WNDAP360_CALDATA1_OFFSET		0x5000
+
+/*
+ * WNDAP360 this still uses leds definitions from AP96
+ *
+ */
+static struct gpio_led wndap360_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNDAP360_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:orange:power",
+		.gpio		= WNDAP360_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+        }
+};
+
+static struct gpio_keys_button wndap360_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNDAP360_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDAP360_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+#define WNDAP360_LAN_PHYMASK 0x0f
+
+static void __init wndap360_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_mdio(0, ~(WNDAP360_LAN_PHYMASK));
+
+	/* Reusing wifi MAC with offset of 1 as eth0 MAC */
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + WNDAP360_WMAC0_MAC_OFFSET, 1);
+	ath79_eth0_pll_data.pll_1000 = 0x11110000;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = WNDAP360_LAN_PHYMASK;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wndap360_leds_gpio),
+					wndap360_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WNDAP360_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(wndap360_gpio_keys),
+					 wndap360_gpio_keys);
+
+	ap9x_pci_setup_wmac_led_pin(0, 5);
+	ap9x_pci_setup_wmac_led_pin(1, 5);
+
+	ap94_pci_init(art + WNDAP360_CALDATA0_OFFSET,
+		      art + WNDAP360_WMAC0_MAC_OFFSET,
+		      art + WNDAP360_CALDATA1_OFFSET,
+		      art + WNDAP360_WMAC1_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNDAP360, "WNDAP360", "Netgear WNDAP360", wndap360_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wndr3700.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wndr3700.c
new file mode 100644
index 0000000000..1315bab037
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wndr3700.c
@@ -0,0 +1,172 @@
+/*
+ *  Netgear WNDR3700 board support
+ *
+ *  Copyright (C) 2009 Marco Porsch
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <linux/rtl8366.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define WNDR3700_GPIO_LED_WPS_ORANGE	0
+#define WNDR3700_GPIO_LED_POWER_ORANGE	1
+#define WNDR3700_GPIO_LED_POWER_GREEN	2
+#define WNDR3700_GPIO_LED_WPS_GREEN	4
+#define WNDR3700_GPIO_LED_WAN_GREEN	6
+
+#define WNDR3700_GPIO_BTN_WPS		3
+#define WNDR3700_GPIO_BTN_RESET		8
+#define WNDR3700_GPIO_BTN_WIFI		11
+
+#define WNDR3700_GPIO_RTL8366_SDA	5
+#define WNDR3700_GPIO_RTL8366_SCK	7
+
+#define WNDR3700_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WNDR3700_KEYS_DEBOUNCE_INTERVAL (3 * WNDR3700_KEYS_POLL_INTERVAL)
+
+#define WNDR3700_ETH0_MAC_OFFSET	0
+#define WNDR3700_ETH1_MAC_OFFSET	0x6
+
+#define WNDR3700_WMAC0_MAC_OFFSET	0
+#define WNDR3700_WMAC1_MAC_OFFSET	0xc
+#define WNDR3700_CALDATA0_OFFSET	0x1000
+#define WNDR3700_CALDATA1_OFFSET	0x5000
+
+static struct gpio_led wndr3700_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNDR3700_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:orange:power",
+		.gpio		= WNDR3700_GPIO_LED_POWER_ORANGE,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wps",
+		.gpio		= WNDR3700_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:orange:wps",
+		.gpio		= WNDR3700_GPIO_LED_WPS_ORANGE,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wan",
+		.gpio		= WNDR3700_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wndr3700_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNDR3700_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDR3700_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNDR3700_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDR3700_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}, {
+		.desc		= "wifi",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = WNDR3700_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDR3700_GPIO_BTN_WIFI,
+		.active_low	= 1,
+	}
+};
+
+static struct rtl8366_platform_data wndr3700_rtl8366s_data = {
+	.gpio_sda	= WNDR3700_GPIO_RTL8366_SDA,
+	.gpio_sck	= WNDR3700_GPIO_RTL8366_SCK,
+};
+
+static struct platform_device wndr3700_rtl8366s_device = {
+	.name		= RTL8366S_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &wndr3700_rtl8366s_data,
+	}
+};
+
+static void __init wndr3700_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	/*
+	 * The eth0 and wmac0 interfaces share the same MAC address which
+	 * can lead to problems if operated unbridged. Set the locally
+	 * administered bit on the eth0 MAC to make it unique.
+	 */
+	ath79_init_local_mac(ath79_eth0_data.mac_addr,
+			     art + WNDR3700_ETH0_MAC_OFFSET);
+	ath79_eth0_pll_data.pll_1000 = 0x11110000;
+	ath79_eth0_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr,
+			art + WNDR3700_ETH1_MAC_OFFSET, 0);
+	ath79_eth1_pll_data.pll_1000 = 0x11110000;
+	ath79_eth1_data.mii_bus_dev = &wndr3700_rtl8366s_device.dev;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wndr3700_leds_gpio),
+				 wndr3700_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WNDR3700_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wndr3700_gpio_keys),
+					wndr3700_gpio_keys);
+
+	platform_device_register(&wndr3700_rtl8366s_device);
+	platform_device_register_simple("wndr3700-led-usb", -1, NULL, 0);
+
+	ap9x_pci_setup_wmac_led_pin(0, 5);
+	ap9x_pci_setup_wmac_led_pin(1, 5);
+
+	/* 2.4 GHz uses the first fixed antenna group (1, 0, 1, 0) */
+	ap9x_pci_setup_wmac_gpio(0, (0xf << 6), (0xa << 6));
+
+	/* 5 GHz uses the second fixed antenna group (0, 1, 1, 0) */
+	ap9x_pci_setup_wmac_gpio(1, (0xf << 6), (0x6 << 6));
+
+	ap94_pci_init(art + WNDR3700_CALDATA0_OFFSET,
+		      art + WNDR3700_WMAC0_MAC_OFFSET,
+		      art + WNDR3700_CALDATA1_OFFSET,
+		      art + WNDR3700_WMAC1_MAC_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNDR3700, "WNDR3700",
+	     "NETGEAR WNDR3700/WNDR3800/WNDRMAC",
+	     wndr3700_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wndr4300.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wndr4300.c
new file mode 100644
index 0000000000..2884c6c83a
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wndr4300.c
@@ -0,0 +1,210 @@
+/*
+ *  NETGEAR WNDR3700v4/WNDR4300 board support
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Ralph Perlich <rpsoft@arcor.de>
+ *
+ *  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/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/platform/ar934x_nfc.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+/* AR9344 GPIOs */
+#define WNDR4300_GPIO_LED_POWER_GREEN	0
+#define WNDR4300_GPIO_LED_POWER_AMBER	2
+#define WNDR4300_GPIO_LED_USB		13
+#define WNDR4300_GPIO_LED_WAN_GREEN	1
+#define WNDR4300_GPIO_LED_WAN_AMBER	3
+#define WNDR4300_GPIO_LED_WLAN2G	11
+#define WNDR4300_GPIO_LED_WLAN5G	14
+#define WNDR4300_GPIO_LED_WPS_GREEN	16
+#define WNDR4300_GPIO_LED_WPS_AMBER	17
+
+#define WNDR4300_GPIO_BTN_RESET		21
+#define WNDR4300_GPIO_BTN_WIRELESS	15
+#define WNDR4300_GPIO_BTN_WPS		12
+
+/* AR9580 GPIOs */
+#define WNDR4300_GPIO_USB_5V		0
+
+#define WNDR4300_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WNDR4300_KEYS_DEBOUNCE_INTERVAL	(3 * WNDR4300_KEYS_POLL_INTERVAL)
+
+static struct gpio_led wndr4300_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNDR4300_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:power",
+		.gpio		= WNDR4300_GPIO_LED_POWER_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:wan",
+		.gpio		= WNDR4300_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:wan",
+		.gpio		= WNDR4300_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:usb",
+		.gpio		= WNDR4300_GPIO_LED_USB,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:wps",
+		.gpio		= WNDR4300_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:wps",
+		.gpio		= WNDR4300_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:wlan2g",
+		.gpio		= WNDR4300_GPIO_LED_WLAN2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:blue:wlan5g",
+		.gpio		= WNDR4300_GPIO_LED_WLAN5G,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wndr4300_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNDR4300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDR4300_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNDR4300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDR4300_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Wireless button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WNDR4300_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNDR4300_GPIO_BTN_WIRELESS,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg wndr4300_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg wndr4300_ar8327_led_cfg = {
+	.led_ctrl0 = 0xc737c737,
+	.led_ctrl1 = 0x00000000,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x0030c300,
+	.open_drain = false,
+};
+
+static struct ar8327_platform_data wndr4300_ar8327_data = {
+	.pad0_cfg = &wndr4300_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &wndr4300_ar8327_led_cfg,
+};
+
+static struct mdio_board_info wndr4300_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wndr4300_ar8327_data,
+	},
+};
+
+static void __init wndr4300_setup(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wndr4300_leds_gpio); i++)
+		ath79_gpio_output_select(wndr4300_leds_gpio[i].gpio,
+					 AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wndr4300_leds_gpio),
+				 wndr4300_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WNDR4300_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wndr4300_gpio_keys),
+					wndr4300_gpio_keys);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0);
+
+	mdiobus_register_board_info(wndr4300_mdio0_info,
+				    ARRAY_SIZE(wndr4300_mdio0_info));
+
+	ath79_register_mdio(0, 0x0);
+
+	/* GMAC0 is connected to an AR8327N switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_HW);
+	ath79_register_nfc();
+	ath79_register_usb();
+
+	ath79_register_wmac_simple();
+
+	/* enable power for the USB port */
+	ap9x_pci_setup_wmac_gpio(0, BIT(WNDR4300_GPIO_USB_5V),
+				 BIT(WNDR4300_GPIO_USB_5V));
+
+	ap91_pci_init_simple();
+}
+
+MIPS_MACHINE(ATH79_MACH_WNDR3700_V4, "WNDR3700_V4", "NETGEAR WNDR3700v4",
+	     wndr4300_setup);
+MIPS_MACHINE(ATH79_MACH_WNDR4300, "WNDR4300", "NETGEAR WNDR4300",
+	     wndr4300_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v3.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v3.c
new file mode 100644
index 0000000000..4961026cbc
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v3.c
@@ -0,0 +1,636 @@
+/*
+ *  NETGEAR WNR2000v3/WNR612v2/WNR1000v2/WPN824N board support
+ *
+ *  Copyright (C) 2015 Hartmut Knaack <knaack.h@gmx.de>
+ *  Copyright (C) 2013 Mathieu Olivari <mathieu.olivari@gmail.com>
+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *  Copyright (C) 2008-2009 Andy Boyett <agb@openwrt.org>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/kernel.h> /* for max() macro */
+#include <linux/platform_device.h> /* PLATFORM_DEVID_AUTO is defined here */
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h> /* needed to disable switch LEDs */
+#include "common.h" /* needed to disable switch LEDs */
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+/* WNR2000v3 - connected through AR7241 */
+#define WNR2000V3_GPIO_LED_WAN_GREEN	0
+#define WNR2000V3_GPIO_LED_LAN1_AMBER	1
+#define WNR2000V3_GPIO_LED_LAN2_AMBER	6
+#define WNR2000V3_GPIO_LED_WPS_GREEN	7
+#define WNR2000V3_GPIO_LED_LAN3_AMBER	8
+#define WNR2000V3_GPIO_BTN_WPS		11
+#define WNR2000V3_GPIO_LED_LAN4_AMBER	12
+#define WNR2000V3_GPIO_LED_LAN1_GREEN	13
+#define WNR2000V3_GPIO_LED_LAN2_GREEN	14
+#define WNR2000V3_GPIO_LED_LAN3_GREEN	15
+#define WNR2000V3_GPIO_LED_LAN4_GREEN	16
+#define WNR2000V3_GPIO_LED_WAN_AMBER	17
+
+/* WNR2000v3 - connected through AR9287 */
+#define WNR2000V3_GPIO_WMAC_LED_WLAN_BLUE	1
+#define WNR2000V3_GPIO_WMAC_LED_TEST_AMBER	2
+#define WNR2000V3_GPIO_WMAC_LED_POWER_GREEN	3
+#define WNR2000V3_GPIO_WMAC_BTN_RESET		8
+#define WNR2000V3_GPIO_WMAC_BTN_RFKILL		9
+
+/* WNR612v2 - connected through AR7241 */
+#define WNR612V2_GPIO_LED_POWER_GREEN	11
+#define WNR612V2_GPIO_LED_LAN1_GREEN	13
+#define WNR612V2_GPIO_LED_LAN2_GREEN	14
+#define WNR612V2_GPIO_LED_WAN_GREEN	17
+
+/* WNR612v2 - connected through AR9285 */
+#define WNR612V2_GPIO_WMAC_LED_WLAN_GREEN	1
+#define WNR612V2_GPIO_WMAC_BTN_RESET		7
+
+/* WNR1000v2 - connected through AR7240 */
+#define WNR1000V2_GPIO_LED_WAN_AMBER	0
+#define WNR1000V2_GPIO_LED_TEST_AMBER	1
+#define WNR1000V2_GPIO_LED_LAN1_AMBER	6 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WNR1000V2_GPIO_LED_LAN2_AMBER	7 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WNR1000V2_GPIO_LED_LAN3_AMBER	8 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WNR1000V2_GPIO_LED_POWER_GREEN	11
+#define WNR1000V2_GPIO_LED_LAN4_AMBER	12
+#define WNR1000V2_GPIO_LED_LAN1_GREEN	13 /* AR724X_..._ETH_SWITCH_LED0 */
+#define WNR1000V2_GPIO_LED_LAN2_GREEN	14 /* AR724X_..._ETH_SWITCH_LED1 */
+#define WNR1000V2_GPIO_LED_LAN3_GREEN	15 /* AR724X_..._ETH_SWITCH_LED2 */
+#define WNR1000V2_GPIO_LED_LAN4_GREEN	16 /* AR724X_..._ETH_SWITCH_LED3 */
+#define WNR1000V2_GPIO_LED_WAN_GREEN	17 /* AR724X_..._ETH_SWITCH_LED4 */
+
+/* WNR1000v2 - connected through AR9285 */
+#define WNR1000V2_GPIO_WMAC_LED_WLAN_BLUE	1
+#define WNR1000V2_GPIO_WMAC_LED_WPS_GREEN	5
+#define WNR1000V2_GPIO_WMAC_BTN_WPS		6
+#define WNR1000V2_GPIO_WMAC_BTN_RESET		7
+#define WNR1000V2_GPIO_WMAC_BTN_RFKILL		8
+
+/* WPN824N - connected through AR7240 */
+#define WPN824N_GPIO_LED_WAN_AMBER	0
+#define WPN824N_GPIO_LED_STATUS_AMBER	1
+#define WPN824N_GPIO_LED_LAN1_AMBER	6 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WPN824N_GPIO_LED_LAN2_AMBER	7 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WPN824N_GPIO_LED_LAN3_AMBER	8 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WPN824N_GPIO_LED_LAN4_AMBER	12
+#define WPN824N_GPIO_LED_LAN1_GREEN	13
+#define WPN824N_GPIO_LED_LAN2_GREEN	14
+#define WPN824N_GPIO_LED_LAN3_GREEN	15 /* AR724X_GPIO_FUNC_CLK_OBS3_EN */
+#define WPN824N_GPIO_LED_LAN4_GREEN	16
+#define WPN824N_GPIO_LED_WAN_GREEN	17
+
+/* WPN824N - connected through AR9285 */
+#define WPN824N_WGPIO_LED_PWR_GREEN	0
+#define WPN824N_WGPIO_LED_WLAN_BLUE	1
+#define WPN824N_WGPIO_LED_WPS1_BLUE	5
+#define WPN824N_WGPIO_LED_WPS2_BLUE	9
+#define WPN824N_WGPIO_LED_TEST_AMBER	10
+#define WPN824N_WGPIO_BTN_WPS		6
+#define WPN824N_WGPIO_BTN_RESET		7
+#define WPN824N_WGPIO_BTN_WLAN		8
+
+#define WNR2000V3_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WNR2000V3_KEYS_DEBOUNCE_INTERVAL	(3 * WNR2000V3_KEYS_POLL_INTERVAL)
+
+/* ART offsets for: WNR2000v3, WNR612v2, WNR1000v2 */
+#define WNR2000V3_MAC0_OFFSET		0
+#define WNR2000V3_MAC1_OFFSET		6
+#define WNR2000V3_PCIE_CALDATA_OFFSET	0x1000
+#define WNR2000V3_WMAC_OFFSET		0x108c	/* wireless MAC is inside ART */
+
+static struct gpio_led wnr2000v3_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:wan",
+		.gpio		= WNR2000V3_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan1",
+		.gpio		= WNR2000V3_GPIO_LED_LAN1_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan2",
+		.gpio		= WNR2000V3_GPIO_LED_LAN2_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan3",
+		.gpio		= WNR2000V3_GPIO_LED_LAN3_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan4",
+		.gpio		= WNR2000V3_GPIO_LED_LAN4_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wps",
+		.gpio		= WNR2000V3_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan1",
+		.gpio		= WNR2000V3_GPIO_LED_LAN1_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan2",
+		.gpio		= WNR2000V3_GPIO_LED_LAN2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan3",
+		.gpio		= WNR2000V3_GPIO_LED_LAN3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan4",
+		.gpio		= WNR2000V3_GPIO_LED_LAN4_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:wan",
+		.gpio		= WNR2000V3_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led wnr2000v3_wmac_leds_gpio[] = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNR2000V3_GPIO_WMAC_LED_POWER_GREEN,
+		.active_low	= 1,
+		.default_state	= LEDS_GPIO_DEFSTATE_ON,
+	}, {
+		.name		= "netgear:amber:test",
+		.gpio		= WNR2000V3_GPIO_WMAC_LED_TEST_AMBER,
+		.active_low	= 1,
+	}
+};
+
+/* Blue WLAN LED for: WNR2000v3, WNR1000v2, WPN824N */
+static const char *wnr2000v3_wmac_led_name = "netgear:blue:wlan";
+
+static struct gpio_led wnr612v2_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNR612V2_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan1",
+		.gpio		= WNR612V2_GPIO_LED_LAN1_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan2",
+		.gpio		= WNR612V2_GPIO_LED_LAN2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wan",
+		.gpio		= WNR612V2_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static const char *wnr612v2_wmac_led_name = "netgear:green:wlan";
+
+static struct gpio_led wnr1000v2_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:amber:lan1",
+		.gpio		= WNR1000V2_GPIO_LED_LAN1_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan2",
+		.gpio		= WNR1000V2_GPIO_LED_LAN2_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan3",
+		.gpio		= WNR1000V2_GPIO_LED_LAN3_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan4",
+		.gpio		= WNR1000V2_GPIO_LED_LAN4_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:test",
+		.gpio		= WNR1000V2_GPIO_LED_TEST_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:wan",
+		.gpio		= WNR1000V2_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan1",
+		.gpio		= WNR1000V2_GPIO_LED_LAN1_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan2",
+		.gpio		= WNR1000V2_GPIO_LED_LAN2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan3",
+		.gpio		= WNR1000V2_GPIO_LED_LAN3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan4",
+		.gpio		= WNR1000V2_GPIO_LED_LAN4_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:power",
+		.gpio		= WNR1000V2_GPIO_LED_POWER_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wan",
+		.gpio		= WNR1000V2_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led wnr1000v2_wmac_leds_gpio[] = {
+	{
+		.name		= "netgear:green:wps",
+		.gpio		= WNR1000V2_GPIO_WMAC_LED_WPS_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led wpn824n_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:amber:wan",
+		.gpio		= WPN824N_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:status",
+		.gpio		= WPN824N_GPIO_LED_STATUS_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan1",
+		.gpio		= WPN824N_GPIO_LED_LAN1_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan2",
+		.gpio		= WPN824N_GPIO_LED_LAN2_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan3",
+		.gpio		= WPN824N_GPIO_LED_LAN3_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan4",
+		.gpio		= WPN824N_GPIO_LED_LAN4_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan1",
+		.gpio		= WPN824N_GPIO_LED_LAN1_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan2",
+		.gpio		= WPN824N_GPIO_LED_LAN2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan3",
+		.gpio		= WPN824N_GPIO_LED_LAN3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan4",
+		.gpio		= WPN824N_GPIO_LED_LAN4_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wan",
+		.gpio		= WPN824N_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led wpn824n_wmac_leds_gpio[] = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WPN824N_WGPIO_LED_PWR_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:blue:wps1",
+		.gpio		= WPN824N_WGPIO_LED_WPS1_BLUE,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:blue:wps2",
+		.gpio		= WPN824N_WGPIO_LED_WPS2_BLUE,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:test",
+		.gpio		= WPN824N_WGPIO_LED_TEST_AMBER,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wnr2000v3_keys_gpio[] __initdata = {
+	{
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000V3_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wnr2000v3_wmac_keys_gpio[] = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000V3_GPIO_WMAC_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "rfkill",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000V3_GPIO_WMAC_BTN_RFKILL,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wnr612v2_wmac_keys_gpio[] = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR612V2_GPIO_WMAC_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wnr1000v2_wmac_keys_gpio[] = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR1000V2_GPIO_WMAC_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "rfkill",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR1000V2_GPIO_WMAC_BTN_RFKILL,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR1000V2_GPIO_WMAC_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wpn824n_wmac_keys_gpio[] = {
+	{
+		.desc			= "reset",
+		.type			= EV_KEY,
+		.code			= KEY_RESTART,
+		.debounce_interval	= WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= WPN824N_WGPIO_BTN_RESET,
+		.active_low		= 1,
+	}, {
+		.desc			= "rfkill",
+		.type			= EV_KEY,
+		.code			= KEY_RFKILL,
+		.debounce_interval	= WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= WPN824N_WGPIO_BTN_WLAN,
+		.active_low		= 1,
+	}, {
+		.desc			= "wps",
+		.type			= EV_KEY,
+		.code			= KEY_WPS_BUTTON,
+		.debounce_interval	= WNR2000V3_KEYS_DEBOUNCE_INTERVAL,
+		.gpio			= WPN824N_WGPIO_BTN_WPS,
+		.active_low		= 1,
+	}
+};
+
+/*
+ * For WNR2000v3 ART flash area used for WLAN MAC is usually empty (0xff)
+ * so ath9k driver uses random MAC instead each time module is loaded.
+ * To fix that, assign permanent WLAN MAC equal to ethN's MAC plus 1,
+ * so network interfaces get sequential addresses.
+ * If ART wireless MAC address field has been filled by user, use it.
+ */
+static void __init wnr_get_wmac(u8 *wmac_gen_addr, int mac0_art_offset,
+				int mac1_art_offset, int wmac_art_offset)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *eth0_mac_addr = (u8 *) (art + mac0_art_offset);
+	u8 *eth1_mac_addr = (u8 *) (art + mac1_art_offset);
+	u8 *wlan_mac_addr = (u8 *) (art + wmac_art_offset);
+
+	/* only 0xff if all bits are set - address is invalid, empty area */
+	if ((wlan_mac_addr[0] & wlan_mac_addr[1] & wlan_mac_addr[2] &
+	     wlan_mac_addr[3] & wlan_mac_addr[4] & wlan_mac_addr[5]) == 0xff) {
+		memcpy(wmac_gen_addr, eth0_mac_addr, 5);
+		wmac_gen_addr[5] = max(eth0_mac_addr[5], eth1_mac_addr[5]) + 1;
+
+		/* Avoid potential conflict in case max(0xff,0x00)+1==0x00 */
+		if (!wmac_gen_addr[5])
+			wmac_gen_addr[5] = 1;
+	} else
+		memcpy(wmac_gen_addr, wlan_mac_addr, 6);
+}
+
+static void __init wnr_common_setup(u8 *wmac_addr)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art+WNR2000V3_MAC0_OFFSET, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art+WNR2000V3_MAC1_OFFSET, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+	ap91_pci_init(art + WNR2000V3_PCIE_CALDATA_OFFSET, wmac_addr);
+}
+
+static void __init wnr2000v3_setup(void)
+{
+	u8 wlan_mac_addr[6];
+
+	/*
+	 * Disable JTAG to use all AR724X GPIO LEDs.
+	 * Also disable CLKs and bit 20 as u-boot does.
+	 * Finally, allow OS to control all link LEDs.
+	 */
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE |
+				  AR724X_GPIO_FUNC_UART_EN,
+				  AR724X_GPIO_FUNC_CLK_OBS1_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS2_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS3_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS4_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS5_EN |
+				  AR724X_GPIO_FUNC_GE0_MII_CLK_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN |
+				  BIT(20));
+
+	wnr_get_wmac(wlan_mac_addr, WNR2000V3_MAC0_OFFSET,
+		     WNR2000V3_MAC1_OFFSET, WNR2000V3_WMAC_OFFSET);
+
+	wnr_common_setup(wlan_mac_addr);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wnr2000v3_leds_gpio),
+				 wnr2000v3_leds_gpio);
+
+	/* Do not use id=-1, we can have more GPIO key-polled devices */
+	ath79_register_gpio_keys_polled(PLATFORM_DEVID_AUTO,
+					WNR2000V3_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wnr2000v3_keys_gpio),
+					wnr2000v3_keys_gpio);
+
+	ap9x_pci_setup_wmac_led_pin(0, WNR2000V3_GPIO_WMAC_LED_WLAN_BLUE);
+	ap9x_pci_setup_wmac_led_name(0, wnr2000v3_wmac_led_name);
+
+	ap9x_pci_setup_wmac_leds(0, wnr2000v3_wmac_leds_gpio,
+				 ARRAY_SIZE(wnr2000v3_wmac_leds_gpio));
+
+	ap9x_pci_setup_wmac_btns(0, wnr2000v3_wmac_keys_gpio,
+				 ARRAY_SIZE(wnr2000v3_wmac_keys_gpio),
+				 WNR2000V3_KEYS_POLL_INTERVAL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNR2000_V3, "WNR2000V3", "NETGEAR WNR2000 V3", wnr2000v3_setup);
+
+static void __init wnr612v2_setup(void)
+{
+	u8 wlan_mac_addr[6];
+
+	/*
+	 * Disable JTAG and CLKs. Allow OS to control all link LEDs.
+	 * Note: U-Boot for WNR612v2 sets undocumented bit 15 but
+	 * we leave it for now.
+	 */
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE |
+				  AR724X_GPIO_FUNC_UART_EN,
+				  AR724X_GPIO_FUNC_CLK_OBS1_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS2_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS3_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS4_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS5_EN |
+				  AR724X_GPIO_FUNC_GE0_MII_CLK_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	wnr_get_wmac(wlan_mac_addr, WNR2000V3_MAC0_OFFSET,
+		     WNR2000V3_MAC1_OFFSET, WNR2000V3_WMAC_OFFSET);
+
+	wnr_common_setup(wlan_mac_addr);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wnr612v2_leds_gpio),
+				 wnr612v2_leds_gpio);
+
+	/*
+	 * This device has no buttons on AR7241 GPIO and no extra LEDs
+	 * connected to AR9285 so setup is simpler than for WNR2000v3.
+	 */
+	ap9x_pci_setup_wmac_led_pin(0, WNR612V2_GPIO_WMAC_LED_WLAN_GREEN);
+	ap9x_pci_setup_wmac_led_name(0, wnr612v2_wmac_led_name);
+
+	ap9x_pci_setup_wmac_leds(0, NULL, 0);
+
+	ap9x_pci_setup_wmac_btns(0, wnr612v2_wmac_keys_gpio,
+				 ARRAY_SIZE(wnr612v2_wmac_keys_gpio),
+				 WNR2000V3_KEYS_POLL_INTERVAL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNR612_V2, "WNR612V2", "NETGEAR WNR612 V2", wnr612v2_setup);
+
+static void __init wnr1000v2_setup(void)
+{
+	u8 wlan_mac_addr[6];
+
+	/*
+	 * Disable JTAG and CLKs. Allow OS to control all link LEDs.
+	 * Note: U-Boot for WNR1000v2 sets undocumented bit 15 but
+	 * we leave it for now.
+	 */
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE |
+				  AR724X_GPIO_FUNC_UART_EN,
+				  AR724X_GPIO_FUNC_CLK_OBS1_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS2_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS3_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS4_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS5_EN |
+				  AR724X_GPIO_FUNC_GE0_MII_CLK_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	wnr_get_wmac(wlan_mac_addr, WNR2000V3_MAC0_OFFSET,
+		     WNR2000V3_MAC1_OFFSET, WNR2000V3_WMAC_OFFSET);
+
+	wnr_common_setup(wlan_mac_addr);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wnr1000v2_leds_gpio),
+				 wnr1000v2_leds_gpio);
+
+	ap9x_pci_setup_wmac_led_pin(0, WNR1000V2_GPIO_WMAC_LED_WLAN_BLUE);
+	ap9x_pci_setup_wmac_led_name(0, wnr2000v3_wmac_led_name);
+
+	ap9x_pci_setup_wmac_leds(0, wnr1000v2_wmac_leds_gpio,
+				 ARRAY_SIZE(wnr1000v2_wmac_leds_gpio));
+
+	/* All 3 buttons are connected to wireless chip */
+	ap9x_pci_setup_wmac_btns(0, wnr1000v2_wmac_keys_gpio,
+				 ARRAY_SIZE(wnr1000v2_wmac_keys_gpio),
+				 WNR2000V3_KEYS_POLL_INTERVAL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNR1000_V2, "WNR1000V2", "NETGEAR WNR1000 V2", wnr1000v2_setup);
+
+static void __init wpn824n_setup(void)
+{
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE,
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS3_EN);
+
+	wnr_common_setup(NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wpn824n_leds_gpio),
+				 wpn824n_leds_gpio);
+
+	ap9x_pci_setup_wmac_led_pin(0, WPN824N_WGPIO_LED_WLAN_BLUE);
+	ap9x_pci_setup_wmac_led_name(0, wnr2000v3_wmac_led_name);
+	ap9x_pci_setup_wmac_leds(0, wpn824n_wmac_leds_gpio,
+				 ARRAY_SIZE(wpn824n_wmac_leds_gpio));
+	ap9x_pci_setup_wmac_btns(0, wpn824n_wmac_keys_gpio,
+				 ARRAY_SIZE(wpn824n_wmac_keys_gpio),
+				 WNR2000V3_KEYS_POLL_INTERVAL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WPN824N, "WPN824N", "NETGEAR WPN824N", wpn824n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v4.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v4.c
new file mode 100644
index 0000000000..c5159a30ca
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000-v4.c
@@ -0,0 +1,214 @@
+/*
+ *  NETGEAR WNR2000v4 board support
+ *
+ *  Copyright (C) 2015 Michael Bazzinotti <mbazzinotti@gmail.com>
+ *  Copyright (C) 2014 Michaël Burtin <mburtin@gmail.com>
+ *  Copyright (C) 2013 Mathieu Olivari <mathieu.olivari@gmail.com>
+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *  Copyright (C) 2008-2009 Andy Boyett <agb@openwrt.org>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+/* AR9341 GPIOs */
+#define WNR2000V4_GPIO_LED_PWR_GREEN      0
+#define WNR2000V4_GPIO_LED_PWR_AMBER      1
+#define WNR2000V4_GPIO_LED_WPS            2
+#define WNR2000V4_GPIO_LED_WLAN           12
+#define WNR2000V4_GPIO_LED_LAN1_GREEN     13
+#define WNR2000V4_GPIO_LED_LAN2_GREEN     14
+#define WNR2000V4_GPIO_LED_LAN3_GREEN     15
+#define WNR2000V4_GPIO_LED_LAN4_GREEN     16
+#define WNR2000V4_GPIO_LED_LAN1_AMBER     18
+#define WNR2000V4_GPIO_LED_LAN2_AMBER     19
+#define WNR2000V4_GPIO_LED_LAN3_AMBER     20
+#define WNR2000V4_GPIO_LED_LAN4_AMBER     21
+#define WNR2000V4_GPIO_LED_WAN_GREEN      17
+#define WNR2000V4_GPIO_LED_WAN_AMBER      22
+/* Buttons */
+#define WNR2000V4_GPIO_BTN_WPS            3
+#define WNR2000V4_GPIO_BTN_RESET          4
+#define WNR2000V4_GPIO_BTN_WLAN           11
+#define WNR2000V4_KEYS_POLL_INTERVAL      20      /* msecs */
+#define WNR2000V4_KEYS_DEBOUNCE_INTERVAL  (3 * WNR2000V4_KEYS_POLL_INTERVAL)
+
+
+/* ART offsets */
+#define WNR2000V4_MAC0_OFFSET             0       /* WAN/WLAN0 MAC   */
+#define WNR2000V4_MAC1_OFFSET             6       /* Eth-switch0 MAC */
+
+static struct gpio_led wnr2000v4_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNR2000V4_GPIO_LED_PWR_GREEN,
+		.active_low	= 1,
+		.default_trigger = "default-on",
+	},
+	{
+		.name		= "netgear:amber:status",
+		.gpio		= WNR2000V4_GPIO_LED_PWR_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:wan",
+		.gpio		= WNR2000V4_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:wan",
+		.gpio		= WNR2000V4_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:blue:wlan",
+		.gpio		= WNR2000V4_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+	/* LAN LEDS */
+	{
+		.name		= "netgear:green:lan1",
+		.gpio		= WNR2000V4_GPIO_LED_LAN1_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:lan2",
+		.gpio		= WNR2000V4_GPIO_LED_LAN2_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:lan3",
+		.gpio		= WNR2000V4_GPIO_LED_LAN3_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:lan4",
+		.gpio		= WNR2000V4_GPIO_LED_LAN4_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:lan1",
+		.gpio		= WNR2000V4_GPIO_LED_LAN1_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:lan2",
+		.gpio		= WNR2000V4_GPIO_LED_LAN2_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:lan3",
+		.gpio		= WNR2000V4_GPIO_LED_LAN3_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:amber:lan4",
+		.gpio		= WNR2000V4_GPIO_LED_LAN4_AMBER,
+		.active_low	= 1,
+	},
+	{
+		.name		= "netgear:green:wps",
+		.gpio		= WNR2000V4_GPIO_LED_WPS,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wnr2000v4_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNR2000V4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000V4_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNR2000V4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000V4_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "WLAN button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WNR2000V4_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000V4_GPIO_BTN_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static void __init wnr_common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *ee  = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_mdio(1, 0x0);
+
+	ath79_register_usb();
+
+	ath79_register_m25p80(NULL);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art+WNR2000V4_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art+WNR2000V4_MAC1_OFFSET, 0);
+
+	/* GMAC0 is connected to the PHY0 of the internal switch, GE0 */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_switch_data.phy_poll_mask = BIT(4);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio1_device.dev;
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the internal switch, GE1 */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_register_eth(1);
+
+	ath79_register_wmac(ee, art);
+}
+
+static void __init wnr2000v4_setup(void)
+{
+	int i;
+
+	wnr_common_setup();
+
+	/* Ensure no LED has an internal MUX signal, otherwise
+	control of LED could be lost... This is especially important
+	for most green LEDS (Eth,WAN).. who arrive in this function with
+	MUX signals set. */
+	for (i = 0; i < ARRAY_SIZE(wnr2000v4_leds_gpio); i++)
+		ath79_gpio_output_select(wnr2000v4_leds_gpio[i].gpio,
+					AR934X_GPIO_OUT_GPIO);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wnr2000v4_leds_gpio),
+				 wnr2000v4_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WNR2000V4_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wnr2000v4_gpio_keys),
+					wnr2000v4_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNR2000_V4, "WNR2000V4", "NETGEAR WNR2000 V4", wnr2000v4_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000.c
new file mode 100644
index 0000000000..b4da7ece32
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2000.c
@@ -0,0 +1,145 @@
+/*
+ *  NETGEAR WNR2000 board support
+ *
+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *  Copyright (C) 2008-2009 Andy Boyett <agb@openwrt.org>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-ath79/ath79.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 WNR2000_GPIO_LED_PWR_GREEN	14
+#define WNR2000_GPIO_LED_PWR_AMBER	7
+#define WNR2000_GPIO_LED_WPS		4
+#define WNR2000_GPIO_LED_WLAN		6
+#define WNR2000_GPIO_BTN_RESET		21
+#define WNR2000_GPIO_BTN_WPS		8
+
+#define WNR2000_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WNR2000_KEYS_DEBOUNCE_INTERVAL	(3 * WNR2000_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition wnr2000_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x040000,
+		.size		= 0x010000,
+	}, {
+		.name		= "rootfs",
+		.offset		= 0x050000,
+		.size		= 0x240000,
+	}, {
+		.name		= "user-config",
+		.offset		= 0x290000,
+		.size		= 0x010000,
+	}, {
+		.name		= "uImage",
+		.offset		= 0x2a0000,
+		.size		= 0x120000,
+	}, {
+		.name		= "language_table",
+		.offset		= 0x3c0000,
+		.size		= 0x020000,
+	}, {
+		.name		= "rootfs_checksum",
+		.offset		= 0x3e0000,
+		.size		= 0x010000,
+	}, {
+		.name		= "art",
+		.offset		= 0x3f0000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}
+};
+
+static struct flash_platform_data wnr2000_flash_data = {
+	.parts		= wnr2000_partitions,
+	.nr_parts	= ARRAY_SIZE(wnr2000_partitions),
+};
+
+static struct gpio_led wnr2000_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:green:power",
+		.gpio		= WNR2000_GPIO_LED_PWR_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:power",
+		.gpio		= WNR2000_GPIO_LED_PWR_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wps",
+		.gpio		= WNR2000_GPIO_LED_WPS,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:blue:wlan",
+		.gpio		= WNR2000_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wnr2000_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNR2000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000_GPIO_BTN_RESET,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNR2000_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2000_GPIO_BTN_WPS,
+	}
+};
+
+static void __init wnr2000_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, eeprom, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.has_ar8216 = 1;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, eeprom, 1);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(&wnr2000_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wnr2000_leds_gpio),
+				 wnr2000_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WNR2000_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wnr2000_gpio_keys),
+					wnr2000_gpio_keys);
+
+	ath79_register_wmac(eeprom, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WNR2000, "WNR2000", "NETGEAR WNR2000", wnr2000_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2200.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2200.c
new file mode 100644
index 0000000000..258d254cf4
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wnr2200.c
@@ -0,0 +1,246 @@
+/*
+ *  NETGEAR WNR2200 board support
+ *
+ *  Copyright (C) 2013 Aidan Kissane <aidankissane at googlemail.com>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/kernel.h> /* for max() macro */
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h> /* needed to disable switch LEDs */
+#include "common.h" /* needed to disable switch LEDs */
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+/* WNR2200 - connected through AR7241 */
+#define WNR2200_GPIO_LED_LAN2_AMBER	0
+#define WNR2200_GPIO_LED_LAN4_AMBER	1
+#define WNR2200_GPIO_LED_LAN1_AMBER	6 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WNR2200_GPIO_LED_WPS_GREEN	7 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WNR2200_GPIO_LED_USB_GREEN	8 /* AR724X_GPIO_FUNC_JTAG_DISABLE */
+#define WNR2200_GPIO_LED_LAN3_AMBER	11
+#define WNR2200_GPIO_LED_WAN_AMBER	12
+#define WNR2200_GPIO_LED_LAN1_GREEN	13 /* AR724X_..._ETH_SWITCH_LED0 */
+#define WNR2200_GPIO_LED_LAN2_GREEN	14 /* AR724X_..._ETH_SWITCH_LED1 */
+#define WNR2200_GPIO_LED_LAN3_GREEN	15 /* AR724X_..._ETH_SWITCH_LED2 */
+#define WNR2200_GPIO_LED_LAN4_GREEN	16 /* AR724X_..._ETH_SWITCH_LED3 */
+#define WNR2200_GPIO_LED_WAN_GREEN	17 /* AR724X_..._ETH_SWITCH_LED4 */
+
+/* WNR2200 - connected through AR9287 */
+#define WNR2200_GPIO_WMAC_LED_WLAN_BLUE		0
+#define WNR2200_GPIO_WMAC_LED_TEST_AMBER	1
+#define WNR2200_GPIO_WMAC_LED_POWER_GREEN	2
+#define WNR2200_GPIO_WMAC_BTN_RFKILL		3
+#define WNR2200_GPIO_WMAC_USB_5V		4
+#define WNR2200_GPIO_WMAC_BTN_WPS		5
+#define WNR2200_GPIO_WMAC_BTN_RESET		6
+
+#define WNR2200_KEYS_POLL_INTERVAL	20 /* msecs */
+#define WNR2200_KEYS_DEBOUNCE_INTERVAL	(3 * WNR2200_KEYS_POLL_INTERVAL)
+
+#define WNR2200_MAC0_OFFSET		0
+#define WNR2200_MAC1_OFFSET		6
+#define WNR2200_PCIE_CALDATA_OFFSET	0x1000
+#define WNR2200_WMAC_OFFSET		0x108c	/* wireless MAC is inside ART */
+
+static struct gpio_led wnr2200_leds_gpio[] __initdata = {
+	{
+		.name		= "netgear:amber:lan1",
+		.gpio		= WNR2200_GPIO_LED_LAN1_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan2",
+		.gpio		= WNR2200_GPIO_LED_LAN2_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan3",
+		.gpio		= WNR2200_GPIO_LED_LAN3_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:lan4",
+		.gpio		= WNR2200_GPIO_LED_LAN4_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:amber:wan",
+		.gpio		= WNR2200_GPIO_LED_WAN_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan1",
+		.gpio		= WNR2200_GPIO_LED_LAN1_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan2",
+		.gpio		= WNR2200_GPIO_LED_LAN2_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan3",
+		.gpio		= WNR2200_GPIO_LED_LAN3_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:lan4",
+		.gpio		= WNR2200_GPIO_LED_LAN4_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:usb",
+		.gpio		= WNR2200_GPIO_LED_USB_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wan",
+		.gpio		= WNR2200_GPIO_LED_WAN_GREEN,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:wps",
+		.gpio		= WNR2200_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	}
+};
+
+static const char *wnr2200_wmac_led_name = "netgear:blue:wlan";
+
+static struct gpio_led wnr2200_wmac_leds_gpio[] = {
+	{
+		.name		= "netgear:amber:test",
+		.gpio		= WNR2200_GPIO_WMAC_LED_TEST_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "netgear:green:power",
+		.gpio		= WNR2200_GPIO_WMAC_LED_POWER_GREEN,
+		.active_low	= 1,
+		.default_state	= LEDS_GPIO_DEFSTATE_ON,
+	}
+};
+
+static struct gpio_keys_button wnr2200_wmac_keys_gpio[] = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WNR2200_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2200_GPIO_WMAC_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "rfkill",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WNR2200_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2200_GPIO_WMAC_BTN_RFKILL,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WNR2200_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WNR2200_GPIO_WMAC_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+/*
+ * For WNR2200 ART flash area used for WLAN MAC is usually empty (0xff)
+ * so ath9k driver uses random MAC instead each time module is loaded.
+ * OpenWrt's original fix was to copy eth1 address to WLAN interface.
+ * New solution does not duplicate hardware addresses and is taken from
+ * WNR2000v3 code. It assigns permanent WLAN MAC equal to ethN's MAC
+ * plus 1, so network interfaces get sequential addresses.
+ * If ART wireless MAC address field has been filled by user, use it.
+ */
+static void __init wnr2200_get_wmac(u8 *wmac_gen_addr, int mac0_art_offset,
+				    int mac1_art_offset, int wmac_art_offset)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *eth0_mac_addr = (u8 *) (art + mac0_art_offset);
+	u8 *eth1_mac_addr = (u8 *) (art + mac1_art_offset);
+	u8 *wlan_mac_addr = (u8 *) (art + wmac_art_offset);
+
+	/* only 0xff if all bits are set - address is invalid, empty area */
+	if ((wlan_mac_addr[0] & wlan_mac_addr[1] & wlan_mac_addr[2] &
+	     wlan_mac_addr[3] & wlan_mac_addr[4] & wlan_mac_addr[5]) == 0xff) {
+		memcpy(wmac_gen_addr, eth0_mac_addr, 5);
+		wmac_gen_addr[5] = max(eth0_mac_addr[5], eth1_mac_addr[5]) + 1;
+
+		/* Avoid potential conflict in case max(0xff,0x00)+1==0x00 */
+		if (!wmac_gen_addr[5])
+			wmac_gen_addr[5] = 1;
+	} else
+		memcpy(wmac_gen_addr, wlan_mac_addr, 6);
+}
+
+static void __init wnr2200_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 wlan_mac_addr[6];
+
+	/*
+	 * Disable JTAG to use all AR724X GPIO LEDs. Disable CLKs.
+	 * Allow OS to control all link LEDs.
+	 */
+	ath79_gpio_function_setup(AR724X_GPIO_FUNC_JTAG_DISABLE |
+				  AR724X_GPIO_FUNC_UART_EN,
+				  AR724X_GPIO_FUNC_CLK_OBS1_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS2_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS3_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS4_EN |
+				  AR724X_GPIO_FUNC_CLK_OBS5_EN |
+				  AR724X_GPIO_FUNC_GE0_MII_CLK_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				  AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + WNR2200_MAC0_OFFSET, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + WNR2200_MAC1_OFFSET, 0);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(NULL);
+
+	wnr2200_get_wmac(wlan_mac_addr, WNR2200_MAC0_OFFSET,
+			 WNR2200_MAC1_OFFSET, WNR2200_WMAC_OFFSET);
+	ap91_pci_init(art + WNR2200_PCIE_CALDATA_OFFSET, wlan_mac_addr);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wnr2200_leds_gpio),
+				 wnr2200_leds_gpio);
+
+	ap9x_pci_setup_wmac_led_pin(0, WNR2200_GPIO_WMAC_LED_WLAN_BLUE);
+	ap9x_pci_setup_wmac_led_name(0, wnr2200_wmac_led_name);
+
+	ap9x_pci_setup_wmac_leds(0, wnr2200_wmac_leds_gpio,
+				 ARRAY_SIZE(wnr2200_wmac_leds_gpio));
+
+	/* All 3 buttons are connected to wireless chip */
+	ap9x_pci_setup_wmac_btns(0, wnr2200_wmac_keys_gpio,
+				 ARRAY_SIZE(wnr2200_wmac_keys_gpio),
+				 WNR2200_KEYS_POLL_INTERVAL);
+
+	/* enable power for the USB port */
+	ap9x_pci_setup_wmac_gpio(0, BIT(WNR2200_GPIO_WMAC_USB_5V),
+				 BIT(WNR2200_GPIO_WMAC_USB_5V));
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_WNR2200, "WNR2200", "NETGEAR WNR2200", wnr2200_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wp543.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wp543.c
new file mode 100644
index 0000000000..dc4aee0c1b
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wp543.c
@@ -0,0 +1,109 @@
+/*
+ *  Compex WP543/WPJ543 board support
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define WP543_GPIO_SW6		2
+#define WP543_GPIO_LED_1	3
+#define WP543_GPIO_LED_2	4
+#define WP543_GPIO_LED_WLAN	5
+#define WP543_GPIO_LED_CONN	6
+#define WP543_GPIO_LED_DIAG	7
+#define WP543_GPIO_SW4		8
+
+#define WP543_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WP543_KEYS_DEBOUNCE_INTERVAL	(3 * WP543_KEYS_POLL_INTERVAL)
+
+static struct gpio_led wp543_leds_gpio[] __initdata = {
+	{
+		.name		= "wp543:green:led1",
+		.gpio		= WP543_GPIO_LED_1,
+		.active_low	= 1,
+	}, {
+		.name		= "wp543:green:led2",
+		.gpio		= WP543_GPIO_LED_2,
+		.active_low	= 1,
+	}, {
+		.name		= "wp543:green:wlan",
+		.gpio		= WP543_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "wp543:green:conn",
+		.gpio		= WP543_GPIO_LED_CONN,
+		.active_low	= 1,
+	}, {
+		.name		= "wp543:green:diag",
+		.gpio		= WP543_GPIO_LED_DIAG,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wp543_gpio_keys[] __initdata = {
+	{
+		.desc		= "sw6",
+		.type		= EV_KEY,
+		.code		= BTN_0,
+		.debounce_interval = WP543_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WP543_GPIO_SW6,
+		.active_low	= 1,
+	}, {
+		.desc		= "sw4",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WP543_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WP543_GPIO_SW4,
+		.active_low	= 1,
+	}
+};
+
+static const char *wp543_part_probes[] = {
+	"MyLoader",
+	NULL,
+};
+
+static struct flash_platform_data wp543_flash_data = {
+	.part_probes	= wp543_part_probes,
+};
+
+static void __init wp543_setup(void)
+{
+	ath79_register_m25p80(&wp543_flash_data);
+
+	ath79_register_mdio(0, 0xfffffff0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = 0x0f;
+	ath79_eth0_data.reset_bit = AR71XX_RESET_GE0_MAC |
+				    AR71XX_RESET_GE0_PHY;
+	ath79_register_eth(0);
+
+	ath79_register_usb();
+	ath79_register_pci();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wp543_leds_gpio),
+					wp543_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WP543_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(wp543_gpio_keys),
+					 wp543_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_WP543, "WP543", "Compex WP543", wp543_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wpe72.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpe72.c
new file mode 100644
index 0000000000..9452484279
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpe72.c
@@ -0,0 +1,97 @@
+/*
+ *  Compex WPE72 board support
+ *
+ *  Copyright (C) 2012 Johnathan Boyce<jon.boyce@globalreach.eu.com>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define WPE72_GPIO_RESET	12
+#define WPE72_GPIO_LED_DIAG	13
+#define WPE72_GPIO_LED_1	14
+#define WPE72_GPIO_LED_2	15
+#define WPE72_GPIO_LED_3	16
+#define WPE72_GPIO_LED_4	17
+
+#define WPE72_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WPE72_KEYS_DEBOUNCE_INTERVAL	(3 * WPE72_KEYS_POLL_INTERVAL)
+
+static struct gpio_led wpe72_leds_gpio[] __initdata = {
+	{
+		.name		= "wpe72:green:led1",
+		.gpio		= WPE72_GPIO_LED_1,
+		.active_low	= 1,
+	}, {
+		.name		= "wpe72:green:led2",
+		.gpio		= WPE72_GPIO_LED_2,
+		.active_low	= 1,
+	}, {
+		.name		= "wpe72:green:led3",
+		.gpio		= WPE72_GPIO_LED_3,
+		.active_low	= 1,
+	}, {
+		.name		= "wpe72:green:led4",
+		.gpio		= WPE72_GPIO_LED_4,
+		.active_low	= 1,
+	}, {
+		.name		= "wpe72:green:diag",
+		.gpio		= WPE72_GPIO_LED_DIAG,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wpe72_gpio_keys[] __initdata = {
+	{
+		.desc           = "reset",
+		.type           = EV_KEY,
+		.code           = KEY_RESTART,
+		.debounce_interval = WPE72_KEYS_DEBOUNCE_INTERVAL,
+		.gpio           = WPE72_GPIO_RESET,
+		.active_low	= 1,
+	}
+};
+
+static const char *wpe72_part_probes[] = {
+	"MyLoader",
+	NULL,
+};
+
+static struct flash_platform_data wpe72_flash_data = {
+	.part_probes	= wpe72_part_probes,
+};
+
+static void __init wpe72_setup(void)
+{
+	ath79_register_m25p80(&wpe72_flash_data);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+	ath79_register_pci();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wpe72_leds_gpio),
+				 wpe72_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WPE72_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wpe72_gpio_keys),
+					wpe72_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_WPE72, "WPE72", "Compex WPE72", wpe72_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj342.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj342.c
new file mode 100644
index 0000000000..8cc1e70f82
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj342.c
@@ -0,0 +1,178 @@
+/*
+ * Compex WPJ342 board support
+ *
+ * Copyright (c) 2011 Qualcomm Atheros
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/export.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "pci.h"
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-nfc.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WPJ342_GPIO_LED_STATUS		11
+#define WPJ342_GPIO_LED_SIG1		14
+#define WPJ342_GPIO_LED_SIG2		13
+#define WPJ342_GPIO_LED_SIG3		12
+#define WPJ342_GPIO_LED_SIG4		11
+#define WPJ342_GPIO_BUZZER			15
+
+#define WPJ342_GPIO_BTN_RESET		17
+
+#define WPJ342_KEYS_POLL_INTERVAL	20 /* msecs */
+#define WPJ342_KEYS_DEBOUNCE_INTERVAL	(3 * WPJ342_KEYS_POLL_INTERVAL)
+
+#define WPJ342_MAC0_OFFSET		0x10
+#define WPJ342_MAC1_OFFSET		0x18
+#define WPJ342_WMAC_CALDATA_OFFSET	0x1000
+#define WPJ342_PCIE_CALDATA_OFFSET	0x5000
+
+#define WPJ342_ART_SIZE		0x8000
+
+static struct gpio_led wpj342_leds_gpio[] __initdata = {
+	{
+		.name		= "wpj342:red:sig1",
+		.gpio		= WPJ342_GPIO_LED_SIG1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj342:yellow:sig2",
+		.gpio		= WPJ342_GPIO_LED_SIG2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj342:green:sig3",
+		.gpio		= WPJ342_GPIO_LED_SIG3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj342:green:sig4",
+		.gpio		= WPJ342_GPIO_LED_SIG4,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj342:buzzer",
+		.gpio		= WPJ342_GPIO_BUZZER,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button wpj342_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WPJ342_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WPJ342_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg wpj342_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg wpj342_ar8327_led_cfg = {
+	.led_ctrl0 = 0x00000000,
+	.led_ctrl1 = 0xc737c737,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x00c30c00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data wpj342_ar8327_data = {
+	.pad0_cfg = &wpj342_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &wpj342_ar8327_led_cfg,
+};
+
+static struct mdio_board_info wpj342_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wpj342_ar8327_data,
+	},
+};
+
+
+static void __init wpj342_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f02e000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wpj342_leds_gpio),
+				wpj342_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WPJ342_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wpj342_gpio_keys),
+					wpj342_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(art + WPJ342_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+
+	mdiobus_register_board_info(wpj342_mdio0_info,
+				ARRAY_SIZE(wpj342_mdio0_info));
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac + WPJ342_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac + WPJ342_MAC1_OFFSET, 0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_MII_GMAC0);
+
+	/* GMAC0 is connected to an AR8236 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_WPJ342, "WPJ342", "Compex WPJ342", wpj342_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj344.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj344.c
new file mode 100644
index 0000000000..b3e2d06bba
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj344.c
@@ -0,0 +1,176 @@
+/*
+ * Compex WPJ344 board support
+ *
+ * Copyright (c) 2011 Qualcomm Atheros
+ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-usb.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WPJ344_GPIO_LED_SIG1	15
+#define WPJ344_GPIO_LED_SIG2	20
+#define WPJ344_GPIO_LED_SIG3	21
+#define WPJ344_GPIO_LED_SIG4	22
+#define WPJ344_GPIO_LED_STATUS	14
+
+#define WPJ344_GPIO_BTN_RESET	12
+
+#define WPJ344_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WPJ344_KEYS_DEBOUNCE_INTERVAL	(3 * WPJ344_KEYS_POLL_INTERVAL)
+
+#define WPJ344_MAC0_OFFSET		0
+#define WPJ344_MAC1_OFFSET		6
+#define WPJ344_WMAC_CALDATA_OFFSET	0x1000
+#define WPJ344_PCIE_CALDATA_OFFSET	0x5000
+
+static struct gpio_led wpj344_leds_gpio[] __initdata = {
+	{
+		.name		= "wpj344:green:status",
+		.gpio		= WPJ344_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj344:red:sig1",
+		.gpio		= WPJ344_GPIO_LED_SIG1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj344:yellow:sig2",
+		.gpio		= WPJ344_GPIO_LED_SIG2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj344:green:sig3",
+		.gpio		= WPJ344_GPIO_LED_SIG3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj344:green:sig4",
+		.gpio		= WPJ344_GPIO_LED_SIG4,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wpj344_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WPJ344_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WPJ344_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg wpj344_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+	.mac06_exchange_dis = true,
+};
+
+static struct ar8327_led_cfg wpj344_ar8327_led_cfg = {
+	.led_ctrl0 = 0x00000000,
+	.led_ctrl1 = 0xc737c737,
+	.led_ctrl2 = 0x00000000,
+	.led_ctrl3 = 0x00c30c00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data wpj344_ar8327_data = {
+	.pad0_cfg = &wpj344_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &wpj344_ar8327_led_cfg,
+};
+
+static struct mdio_board_info wpj344_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wpj344_ar8327_data,
+	},
+};
+
+static void __init wpj344_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wpj344_leds_gpio),
+				 wpj344_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WPJ344_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wpj344_gpio_keys),
+					wpj344_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(art + WPJ344_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+
+	mdiobus_register_board_info(wpj344_mdio0_info,
+					ARRAY_SIZE(wpj344_mdio0_info));
+
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + WPJ344_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + WPJ344_MAC1_OFFSET, 0);
+
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+
+	/* GMAC1 is connected to the internal switch */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_WPJ344, "WPJ344", "Compex WPJ344", wpj344_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj531.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj531.c
new file mode 100644
index 0000000000..8a238da7d5
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj531.c
@@ -0,0 +1,143 @@
+/*
+ * Compex WPJ531 board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "pci.h"
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WPJ531_GPIO_LED_SIG1    14
+#define WPJ531_GPIO_LED_SIG2    15
+#define WPJ531_GPIO_LED_SIG3    22
+#define WPJ531_GPIO_LED_SIG4    23
+#define WPJ531_GPIO_BUZZER      4
+
+#define WPJ531_GPIO_BTN_RESET   17
+
+#define WPJ531_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WPJ531_KEYS_DEBOUNCE_INTERVAL	(3 * WPJ531_KEYS_POLL_INTERVAL)
+
+#define WPJ531_MAC0_OFFSET		0x10
+#define WPJ531_MAC1_OFFSET		0x18
+#define WPJ531_WMAC_CALDATA_OFFSET	0x1000
+#define WPJ531_PCIE_CALDATA_OFFSET	0x5000
+
+#define WPJ531_ART_SIZE		0x8000
+
+static struct gpio_led wpj531_leds_gpio[] __initdata = {
+	{
+		.name		= "wpj531:red:sig1",
+		.gpio		= WPJ531_GPIO_LED_SIG1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj531:yellow:sig2",
+		.gpio		= WPJ531_GPIO_LED_SIG2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj531:green:sig3",
+		.gpio		= WPJ531_GPIO_LED_SIG3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj531:green:sig4",
+		.gpio		= WPJ531_GPIO_LED_SIG4,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj531:buzzer",
+		.gpio		= WPJ531_GPIO_BUZZER,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button wpj531_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WPJ531_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WPJ531_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init common_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f02e000);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN */
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac + WPJ531_MAC0_OFFSET, 0);
+	ath79_register_eth(0);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac + WPJ531_MAC1_OFFSET, 0);
+	ath79_register_eth(1);
+
+	ath79_register_wmac(art + WPJ531_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+	ath79_register_usb();
+}
+
+static void __init wpj531_setup(void)
+{
+	common_setup();
+
+	ath79_register_leds_gpio(-1,
+				ARRAY_SIZE(wpj531_leds_gpio),
+				wpj531_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1,
+					WPJ531_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wpj531_gpio_keys),
+					wpj531_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_WPJ531, "WPJ531", "Compex WPJ531", wpj531_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj558.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj558.c
new file mode 100644
index 0000000000..c7b120dc2e
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wpj558.c
@@ -0,0 +1,177 @@
+/*
+ * Compex WPJ558 board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "pci.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-eth.h"
+#include "dev-usb.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-spi.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WPJ558_GPIO_LED_SIG1	14
+#define WPJ558_GPIO_LED_SIG2	15
+#define WPJ558_GPIO_LED_SIG3	22
+#define WPJ558_GPIO_LED_SIG4	23
+#define WPJ558_GPIO_BUZZER		4
+
+#define WPJ558_GPIO_BTN_RESET	17
+
+#define WPJ558_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WPJ558_KEYS_DEBOUNCE_INTERVAL	(3 * WPJ558_KEYS_POLL_INTERVAL)
+
+#define WPJ558_MAC_OFFSET			0x1002
+#define WPJ558_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led wpj558_leds_gpio[] __initdata = {
+	{
+		.name		= "wpj558:red:sig1",
+		.gpio		= WPJ558_GPIO_LED_SIG1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj558:yellow:sig2",
+		.gpio		= WPJ558_GPIO_LED_SIG2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj558:green:sig3",
+		.gpio		= WPJ558_GPIO_LED_SIG3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj558:green:sig4",
+		.gpio		= WPJ558_GPIO_LED_SIG4,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wpj558:buzzer",
+		.gpio		= WPJ558_GPIO_BUZZER,
+		.active_low	= 0,
+	}
+};
+
+static struct gpio_keys_button wpj558_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WPJ558_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WPJ558_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static struct ar8327_pad_cfg wpj558_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+static struct ar8327_pad_cfg wpj558_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data wpj558_ar8327_data = {
+	.pad0_cfg = &wpj558_ar8327_pad0_cfg,
+	.pad6_cfg = &wpj558_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info wpj558_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wpj558_ar8327_data,
+	},
+};
+
+static void __init wpj558_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wpj558_leds_gpio),
+					wpj558_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WPJ558_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wpj558_gpio_keys),
+					wpj558_gpio_keys);
+
+	ath79_register_usb();
+
+	ath79_register_wmac(art + WPJ558_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_pci();
+
+	mdiobus_register_board_info(wpj558_mdio0_info,
+					ARRAY_SIZE(wpj558_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + WPJ558_MAC_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + WPJ558_MAC_OFFSET, 0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_WPJ558, "WPJ558", "Compex WPJ558", wpj558_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wrt160nl.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrt160nl.c
new file mode 100644
index 0000000000..ede3c214c2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrt160nl.c
@@ -0,0 +1,126 @@
+/*
+ *  Linksys WRT160NL board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "nvram.h"
+#include "machtypes.h"
+
+#define WRT160NL_GPIO_LED_POWER		14
+#define WRT160NL_GPIO_LED_WPS_AMBER	9
+#define WRT160NL_GPIO_LED_WPS_BLUE	8
+#define WRT160NL_GPIO_LED_WLAN		6
+
+#define WRT160NL_GPIO_BTN_WPS		7
+#define WRT160NL_GPIO_BTN_RESET		21
+
+#define WRT160NL_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WRT160NL_KEYS_DEBOUNCE_INTERVAL	(3 * WRT160NL_KEYS_POLL_INTERVAL)
+
+#define WRT160NL_NVRAM_ADDR	0x1f7e0000
+#define WRT160NL_NVRAM_SIZE	0x10000
+
+static const char *wrt160nl_part_probes[] = {
+	"cybertan",
+	NULL,
+};
+
+static struct flash_platform_data wrt160nl_flash_data = {
+	.part_probes	= wrt160nl_part_probes,
+};
+
+static struct gpio_led wrt160nl_leds_gpio[] __initdata = {
+	{
+		.name		= "wrt160nl:blue:power",
+		.gpio		= WRT160NL_GPIO_LED_POWER,
+		.active_low	= 1,
+		.default_trigger = "default-on",
+	}, {
+		.name		= "wrt160nl:amber:wps",
+		.gpio		= WRT160NL_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "wrt160nl:blue:wps",
+		.gpio		= WRT160NL_GPIO_LED_WPS_BLUE,
+		.active_low	= 1,
+	}, {
+		.name		= "wrt160nl:blue:wlan",
+		.gpio		= WRT160NL_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wrt160nl_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WRT160NL_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WRT160NL_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wps",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WRT160NL_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WRT160NL_GPIO_BTN_WPS,
+		.active_low	= 1,
+	}
+};
+
+static void __init wrt160nl_setup(void)
+{
+	const char *nvram = (char *) KSEG1ADDR(WRT160NL_NVRAM_ADDR);
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 mac[6];
+
+	if (ath79_nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE,
+				       "lan_hwaddr=", mac) == 0) {
+		ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+		ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+	}
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.phy_mask = 0x01;
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(&wrt160nl_flash_data);
+
+	ath79_register_usb();
+
+	if (ath79_nvram_parse_mac_addr(nvram, WRT160NL_NVRAM_SIZE,
+				       "wl0_hwaddr=", mac) == 0)
+		ath79_register_wmac(eeprom, mac);
+	else
+		ath79_register_wmac(eeprom, NULL);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wrt160nl_leds_gpio),
+				 wrt160nl_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WRT160NL_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wrt160nl_gpio_keys),
+					wrt160nl_gpio_keys);
+}
+
+MIPS_MACHINE(ATH79_MACH_WRT160NL, "WRT160NL", "Linksys WRT160NL",
+	     wrt160nl_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wrt400n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrt400n.c
new file mode 100644
index 0000000000..6c4c1cb0d6
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrt400n.c
@@ -0,0 +1,161 @@
+/*
+ *  Linksys WRT400N board support
+ *
+ *  Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "machtypes.h"
+
+#define WRT400N_GPIO_LED_POWER		1
+#define WRT400N_GPIO_LED_WPS_BLUE	4
+#define WRT400N_GPIO_LED_WPS_AMBER	5
+#define WRT400N_GPIO_LED_WLAN		6
+
+#define WRT400N_GPIO_BTN_RESET		8
+#define WRT400N_GPIO_BTN_WLSEC		3
+
+#define WRT400N_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WRT400N_KEYS_DEBOUNE_INTERVAL	(3 * WRT400N_KEYS_POLL_INTERVAL)
+
+#define WRT400N_MAC_ADDR_OFFSET		0x120c
+#define WRT400N_CALDATA0_OFFSET		0x1000
+#define WRT400N_CALDATA1_OFFSET		0x5000
+
+static struct mtd_partition wrt400n_partitions[] = {
+	{
+		.name		= "uboot",
+		.offset		= 0,
+		.size		= 0x030000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "env",
+		.offset		= 0x030000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "linux",
+		.offset		= 0x040000,
+		.size		= 0x140000,
+	}, {
+		.name		= "rootfs",
+		.offset		= 0x180000,
+		.size		= 0x630000,
+	}, {
+		.name		= "nvram",
+		.offset		= 0x7b0000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "factory",
+		.offset		= 0x7c0000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "language",
+		.offset		= 0x7d0000,
+		.size		= 0x020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "caldata",
+		.offset		= 0x7f0000,
+		.size		= 0x010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x040000,
+		.size		= 0x770000,
+	}
+};
+
+static struct flash_platform_data wrt400n_flash_data = {
+	.parts		= wrt400n_partitions,
+	.nr_parts	= ARRAY_SIZE(wrt400n_partitions),
+};
+
+static struct gpio_led wrt400n_leds_gpio[] __initdata = {
+	{
+		.name		= "wrt400n:blue:wps",
+		.gpio		= WRT400N_GPIO_LED_WPS_BLUE,
+		.active_low	= 1,
+	}, {
+		.name		= "wrt400n:amber:wps",
+		.gpio		= WRT400N_GPIO_LED_WPS_AMBER,
+		.active_low	= 1,
+	}, {
+		.name		= "wrt400n:blue:wlan",
+		.gpio		= WRT400N_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}, {
+		.name		= "wrt400n:blue:power",
+		.gpio		= WRT400N_GPIO_LED_POWER,
+		.active_low	= 0,
+		.default_trigger = "default-on",
+	}
+};
+
+static struct gpio_keys_button wrt400n_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WRT400N_KEYS_DEBOUNE_INTERVAL,
+		.gpio		= WRT400N_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "wlsec",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WRT400N_KEYS_DEBOUNE_INTERVAL,
+		.gpio		= WRT400N_GPIO_BTN_WLSEC,
+		.active_low	= 1,
+	}
+};
+
+static void __init wrt400n_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac = art + WRT400N_MAC_ADDR_OFFSET;
+
+	ath79_register_mdio(0, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 1);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 2);
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_m25p80(&wrt400n_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wrt400n_leds_gpio),
+				 wrt400n_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WRT400N_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wrt400n_gpio_keys),
+					wrt400n_gpio_keys);
+
+	ap94_pci_init(art + WRT400N_CALDATA0_OFFSET, NULL,
+		      art + WRT400N_CALDATA1_OFFSET, NULL);
+}
+
+MIPS_MACHINE(ATH79_MACH_WRT400N, "WRT400N", "Linksys WRT400N", wrt400n_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c
new file mode 100644
index 0000000000..150a28b0d7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wrtnode2q.c
@@ -0,0 +1,126 @@
+/*
+ * WRTnode2Q board support
+ *
+ * Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2015 Kelei <xzmu@wrtnode.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "pci.h"
+
+#define WRTNODE2Q_GPIO_LED_WLAN		12
+#define WRTNODE2Q_GPIO_LED_WPS		13
+#define WRTNODE2Q_GPIO_LED_STATUS		13
+
+#define WRTNODE2Q_GPIO_LED_WAN		4
+#define WRTNODE2Q_GPIO_LED_LAN1		16
+#define WRTNODE2Q_GPIO_LED_LAN2		15
+#define WRTNODE2Q_GPIO_LED_LAN3		14
+#define WRTNODE2Q_GPIO_LED_LAN4		11
+
+#define WRTNODE2Q_GPIO_BTN_WPS		17
+
+#define WRTNODE2Q_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WRTNODE2Q_KEYS_DEBOUNCE_INTERVAL	(3 * WRTNODE2Q_KEYS_POLL_INTERVAL)
+
+#define WRTNODE2Q_MAC0_OFFSET		0
+#define WRTNODE2Q_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led wrtnode2q_leds_gpio[] __initdata = {
+	{
+		.name		= "wrtnode2q:green:status",
+		.gpio		= WRTNODE2Q_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "wrtnode2q:green:wlan",
+		.gpio		= WRTNODE2Q_GPIO_LED_WLAN,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wrtnode2q_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WRTNODE2Q_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WRTNODE2Q_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+};
+
+static void __init wrtnode2q_gpio_led_setup(void)
+{
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wrtnode2q_leds_gpio),
+			wrtnode2q_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WRTNODE2Q_KEYS_POLL_INTERVAL,
+			ARRAY_SIZE(wrtnode2q_gpio_keys),
+			wrtnode2q_gpio_keys);
+}
+
+static void __init wrtnode2q_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1f040000);
+
+	ath79_register_m25p80(NULL);
+
+	wrtnode2q_gpio_led_setup();
+
+	ath79_register_pci();
+	ath79_register_usb();
+
+	ath79_register_wmac(art + WRTNODE2Q_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_mdio(0, 0x0);
+	ath79_register_mdio(1, 0x0);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, art + WRTNODE2Q_MAC0_OFFSET, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, art + WRTNODE2Q_MAC0_OFFSET, 1);
+
+	/* LAN ports */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_register_eth(1);
+
+	/* WAN port */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_register_eth(0);
+}
+
+MIPS_MACHINE(ATH79_MACH_WRTNODE2Q, "WRTNODE2Q", "WRTnode2Q board",
+	     wrtnode2q_setup);
\ No newline at end of file
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-450hp2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-450hp2.c
new file mode 100644
index 0000000000..428876fccb
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-450hp2.c
@@ -0,0 +1,221 @@
+/*
+ * Buffalo WZR-450HP2 board support
+ *
+ * Copyright (c) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the Qualcomm Atheros AP135/AP136 reference board support code
+ *   Copyright (c) 2012 Qualcomm Atheros
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/phy.h>
+#include <linux/gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/ar8216_platform.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-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WZR_450HP2_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WZR_450HP2_KEYS_DEBOUNCE_INTERVAL (3 * WZR_450HP2_KEYS_POLL_INTERVAL)
+
+#define WZR_450HP2_WMAC_CALDATA_OFFSET	0x1000
+
+static struct mtd_partition wzrhpg450h_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x0040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x0040000,
+		.size		= 0x0010000,
+	}, {
+		.name		= "ART",
+		.offset		= 0x0ff0000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x0050000,
+		.size		= 0x0f90000,
+	}, {
+		.name		= "user_property",
+		.offset		= 0x0fe0000,
+		.size		= 0x0010000,
+	}
+};
+
+static struct flash_platform_data wzr_450hp2_flash_data = {
+	.parts		= wzrhpg450h_partitions,
+	.nr_parts	= ARRAY_SIZE(wzrhpg450h_partitions),
+};
+
+static struct gpio_led wzr_450hp2_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:green:wps",
+		.gpio		= 3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:green:system",
+		.gpio		= 20,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:green:wlan",
+		.gpio		= 18,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wzr_450hp2_gpio_keys[] __initdata = {
+	{
+		.desc		= "Reset button",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WZR_450HP2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 17,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = WZR_450HP2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 21,
+		.active_low	= 1,
+	},
+};
+
+static const struct ar8327_led_info wzr_450hp2_leds_ar8327[] = {
+	AR8327_LED_INFO(PHY0_0, HW, "buffalo:green:lan1"),
+	AR8327_LED_INFO(PHY1_0, HW, "buffalo:green:lan2"),
+	AR8327_LED_INFO(PHY2_0, HW, "buffalo:green:lan3"),
+	AR8327_LED_INFO(PHY3_0, HW, "buffalo:green:lan4"),
+	AR8327_LED_INFO(PHY4_0, HW, "buffalo:green:wan"),
+};
+
+/* GMAC0 of the AR8327 switch is connected to the QCA9558 SoC via SGMII */
+static struct ar8327_pad_cfg wzr_450hp2_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_SGMII,
+	.sgmii_delay_en = true,
+};
+
+/* GMAC6 of the AR8327 switch is connected to the QCA9558 SoC via RGMII */
+static struct ar8327_pad_cfg wzr_450hp2_ar8327_pad6_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_led_cfg wzr_450hp2_ar8327_led_cfg = {
+	.led_ctrl0 = 0xcc35cc35,
+	.led_ctrl1 = 0xca35ca35,
+	.led_ctrl2 = 0xc935c935,
+	.led_ctrl3 = 0x03ffff00,
+	.open_drain = true,
+};
+
+static struct ar8327_platform_data wzr_450hp2_ar8327_data = {
+	.pad0_cfg = &wzr_450hp2_ar8327_pad0_cfg,
+	.pad6_cfg = &wzr_450hp2_ar8327_pad6_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.port6_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+	.led_cfg = &wzr_450hp2_ar8327_led_cfg,
+	.num_leds = ARRAY_SIZE(wzr_450hp2_leds_ar8327),
+	.leds = wzr_450hp2_leds_ar8327,
+};
+
+static struct mdio_board_info wzr_450hp2_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = 0,
+		.platform_data = &wzr_450hp2_ar8327_data,
+	},
+};
+
+static void __init wzr_450hp2_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+	u8 *mac_wan = art;
+	u8 *mac_lan = mac_wan + ETH_ALEN;
+
+	ath79_register_m25p80(&wzr_450hp2_flash_data);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wzr_450hp2_leds_gpio),
+				 wzr_450hp2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WZR_450HP2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wzr_450hp2_gpio_keys),
+					wzr_450hp2_gpio_keys);
+
+	ath79_register_wmac(art + WZR_450HP2_WMAC_CALDATA_OFFSET, mac_lan);
+
+	mdiobus_register_board_info(wzr_450hp2_mdio0_info,
+				    ARRAY_SIZE(wzr_450hp2_mdio0_info));
+	ath79_register_mdio(0, 0x0);
+
+	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+
+	/* GMAC0 is connected to the RMGII interface */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(0);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x56000000;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac_wan, 0);
+	ath79_register_eth(0);
+
+	/* GMAC1 is connected to the SGMII interface */
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
+	ath79_eth1_data.speed = SPEED_1000;
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_pll_data.pll_1000 = 0x03000101;
+
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac_lan, 0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_WZR_450HP2, "WZR-450HP2",
+	     "Buffalo WZR-450HP2", wzr_450hp2_setup);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-ag300h.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-ag300h.c
new file mode 100644
index 0000000000..ec3f1ff845
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-ag300h.c
@@ -0,0 +1,205 @@
+/*
+ *  Buffalo WZR-HP-AG300H board support
+ *
+ *  Copyright (C) 2011 Felix Fietkau <nbd@nbd.name>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define WZRHPAG300H_MAC_OFFSET		0x20c
+#define WZRHPAG300H_KEYS_POLL_INTERVAL	20      /* msecs */
+#define WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL (3 * WZRHPAG300H_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition wzrhpag300h_flash_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x0040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x0040000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "art",
+		.offset		= 0x0050000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x0060000,
+		.size		= 0x1f90000,
+	}, {
+		.name		= "user_property",
+		.offset		= 0x1ff0000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}
+};
+
+static struct flash_platform_data wzrhpag300h_flash_data = {
+	.parts      = wzrhpag300h_flash_partitions,
+	.nr_parts   = ARRAY_SIZE(wzrhpag300h_flash_partitions),
+};
+
+static struct gpio_led wzrhpag300h_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:red:diag",
+		.gpio		= 1,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led wzrhpag300h_wmac0_leds_gpio[] = {
+        {
+                .name           = "buffalo:amber:band2g",
+                .gpio           = 1,
+                .active_low     = 1,
+	},
+        {
+                .name           = "buffalo:green:usb",
+                .gpio           = 3,
+                .active_low     = 1,
+	},
+        {
+                .name           = "buffalo:green:band2g",
+                .gpio           = 5,
+                .active_low     = 1,
+	},
+};
+
+static struct gpio_led wzrhpag300h_wmac1_leds_gpio[] = {
+        {
+                .name           = "buffalo:green:band5g",
+                .gpio           = 1,
+                .active_low     = 1,
+	},
+        {
+                .name           = "buffalo:green:router",
+                .gpio           = 3,
+                .active_low     = 1,
+	},
+        {
+                .name           = "buffalo:blue:movie_engine",
+                .gpio           = 4,
+                .active_low     = 1,
+	},
+        {
+                .name           = "buffalo:amber:band5g",
+                .gpio           = 5,
+                .active_low     = 1,
+	},
+};
+
+static struct gpio_keys_button wzrhpag300h_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 11,
+		.active_low	= 1,
+	}, {
+		.desc		= "usb",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 3,
+		.active_low	= 1,
+	}, {
+		.desc		= "aoss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 5,
+		.active_low	= 1,
+	}, {
+		.desc		= "router_auto",
+		.type		= EV_SW,
+		.code		= BTN_6,
+		.debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 6,
+		.active_low	= 1,
+	}, {
+		.desc		= "router_off",
+		.type		= EV_SW,
+		.code		= BTN_5,
+		.debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 7,
+		.active_low	= 1,
+	}, {
+		.desc		= "movie_engine",
+		.type		= EV_SW,
+		.code		= BTN_7,
+		.debounce_interval = WZRHPAG300H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 8,
+		.active_low	= 1,
+	}
+};
+
+static void __init wzrhpag300h_setup(void)
+{
+	u8 *eeprom1 = (u8 *) KSEG1ADDR(0x1f051000);
+	u8 *eeprom2 = (u8 *) KSEG1ADDR(0x1f055000);
+	u8 *mac1 = eeprom1 + WZRHPAG300H_MAC_OFFSET;
+	u8 *mac2 = eeprom2 + WZRHPAG300H_MAC_OFFSET;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac1, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac2, 1);
+
+	ath79_register_mdio(0, ~(BIT(0) | BIT(4)));
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = BIT(4);
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	gpio_request_one(2, GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wzrhpag300h_leds_gpio),
+					wzrhpag300h_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WZRHPAG300H_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(wzrhpag300h_gpio_keys),
+					 wzrhpag300h_gpio_keys);
+
+	ath79_register_m25p80_multi(&wzrhpag300h_flash_data);
+
+	ap94_pci_init(eeprom1, mac1, eeprom2, mac2);
+
+	ap9x_pci_setup_wmac_led_pin(0, 1);
+	ap9x_pci_setup_wmac_led_pin(1, 5);
+
+	ap9x_pci_setup_wmac_leds(0, wzrhpag300h_wmac0_leds_gpio,
+				ARRAY_SIZE(wzrhpag300h_wmac0_leds_gpio));
+	ap9x_pci_setup_wmac_leds(1, wzrhpag300h_wmac1_leds_gpio,
+				ARRAY_SIZE(wzrhpag300h_wmac1_leds_gpio));
+}
+
+MIPS_MACHINE(ATH79_MACH_WZR_HP_AG300H, "WZR-HP-AG300H",
+	     "Buffalo WZR-HP-AG300H/WZR-600DHP", wzrhpag300h_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh.c
new file mode 100644
index 0000000000..0a3eba9f77
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh.c
@@ -0,0 +1,279 @@
+/*
+ *  Buffalo WZR-HP-G300NH board support
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/nxp_74hc153.h>
+#include <linux/rtl8366.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define WZRHPG300NH_GPIO_LED_USB	0
+#define WZRHPG300NH_GPIO_LED_DIAG	1
+#define WZRHPG300NH_GPIO_LED_WIRELESS	6
+#define WZRHPG300NH_GPIO_LED_SECURITY	17
+#define WZRHPG300NH_GPIO_LED_ROUTER	18
+
+#define WZRHPG300NH_GPIO_RTL8366_SDA	19
+#define WZRHPG300NH_GPIO_RTL8366_SCK	20
+
+#define WZRHPG300NH_GPIO_74HC153_S0	9
+#define WZRHPG300NH_GPIO_74HC153_S1	11
+#define WZRHPG300NH_GPIO_74HC153_1Y	12
+#define WZRHPG300NH_GPIO_74HC153_2Y	14
+
+#define WZRHPG300NH_GPIO_EXP_BASE	32
+#define WZRHPG300NH_GPIO_BTN_AOSS	(WZRHPG300NH_GPIO_EXP_BASE + 0)
+#define WZRHPG300NH_GPIO_BTN_RESET	(WZRHPG300NH_GPIO_EXP_BASE + 1)
+#define WZRHPG300NH_GPIO_BTN_ROUTER_ON	(WZRHPG300NH_GPIO_EXP_BASE + 2)
+#define WZRHPG300NH_GPIO_BTN_QOS_ON	(WZRHPG300NH_GPIO_EXP_BASE + 3)
+#define WZRHPG300NH_GPIO_BTN_USB	(WZRHPG300NH_GPIO_EXP_BASE + 5)
+#define WZRHPG300NH_GPIO_BTN_ROUTER_AUTO (WZRHPG300NH_GPIO_EXP_BASE + 6)
+#define WZRHPG300NH_GPIO_BTN_QOS_OFF	(WZRHPG300NH_GPIO_EXP_BASE + 7)
+
+#define WZRHPG300NH_KEYS_POLL_INTERVAL	20	/* msecs */
+#define WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL (3 * WZRHPG300NH_KEYS_POLL_INTERVAL)
+
+#define WZRHPG300NH_MAC_OFFSET		0x20c
+
+static struct mtd_partition wzrhpg300nh_flash_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x0040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x0040000,
+		.size		= 0x0020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x0060000,
+		.size		= 0x1f60000,
+	}, {
+		.name		= "user_property",
+		.offset		= 0x1fc0000,
+		.size		= 0x0020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "art",
+		.offset		= 0x1fe0000,
+		.size		= 0x0020000,
+		.mask_flags	= MTD_WRITEABLE,
+	}
+};
+
+static struct physmap_flash_data wzrhpg300nh_flash_data = {
+	.width		= 2,
+	.parts		= wzrhpg300nh_flash_partitions,
+	.nr_parts	= ARRAY_SIZE(wzrhpg300nh_flash_partitions),
+};
+
+#define WZRHPG300NH_FLASH_BASE	0x1e000000
+#define WZRHPG300NH_FLASH_SIZE	(32 * 1024 * 1024)
+
+static struct resource wzrhpg300nh_flash_resources[] = {
+	[0] = {
+		.start	= WZRHPG300NH_FLASH_BASE,
+		.end	= WZRHPG300NH_FLASH_BASE + WZRHPG300NH_FLASH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device wzrhpg300nh_flash_device = {
+	.name		= "physmap-flash",
+	.id		= -1,
+	.resource	= wzrhpg300nh_flash_resources,
+	.num_resources	= ARRAY_SIZE(wzrhpg300nh_flash_resources),
+	.dev		= {
+		.platform_data = &wzrhpg300nh_flash_data,
+	}
+};
+
+static struct gpio_led wzrhpg300nh_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:orange:security",
+		.gpio		= WZRHPG300NH_GPIO_LED_SECURITY,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:wireless",
+		.gpio		= WZRHPG300NH_GPIO_LED_WIRELESS,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:green:router",
+		.gpio		= WZRHPG300NH_GPIO_LED_ROUTER,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:red:diag",
+		.gpio		= WZRHPG300NH_GPIO_LED_DIAG,
+		.active_low	= 1,
+	}, {
+		.name		= "buffalo:blue:usb",
+		.gpio		= WZRHPG300NH_GPIO_LED_USB,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button wzrhpg300nh_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}, {
+		.desc		= "aoss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_AOSS,
+		.active_low	= 1,
+	}, {
+		.desc		= "usb",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_USB,
+		.active_low	= 1,
+	}, {
+		.desc		= "qos_on",
+		.type		= EV_KEY,
+		.code		= BTN_3,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_QOS_ON,
+		.active_low	= 0,
+	}, {
+		.desc		= "qos_off",
+		.type		= EV_KEY,
+		.code		= BTN_4,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_QOS_OFF,
+		.active_low	= 0,
+	}, {
+		.desc		= "router_on",
+		.type		= EV_KEY,
+		.code		= BTN_5,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_ROUTER_ON,
+		.active_low	= 0,
+	}, {
+		.desc		= "router_auto",
+		.type		= EV_KEY,
+		.code		= BTN_6,
+		.debounce_interval = WZRHPG300NH_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= WZRHPG300NH_GPIO_BTN_ROUTER_AUTO,
+		.active_low	= 0,
+	}
+};
+
+static struct nxp_74hc153_platform_data wzrhpg300nh_74hc153_data = {
+	.gpio_base	= WZRHPG300NH_GPIO_EXP_BASE,
+	.gpio_pin_s0	= WZRHPG300NH_GPIO_74HC153_S0,
+	.gpio_pin_s1	= WZRHPG300NH_GPIO_74HC153_S1,
+	.gpio_pin_1y	= WZRHPG300NH_GPIO_74HC153_1Y,
+	.gpio_pin_2y	= WZRHPG300NH_GPIO_74HC153_2Y,
+};
+
+static struct platform_device wzrhpg300nh_74hc153_device = {
+	.name		= NXP_74HC153_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &wzrhpg300nh_74hc153_data,
+	}
+};
+
+static struct rtl8366_platform_data wzrhpg300nh_rtl8366_data = {
+	.gpio_sda	= WZRHPG300NH_GPIO_RTL8366_SDA,
+	.gpio_sck	= WZRHPG300NH_GPIO_RTL8366_SCK,
+};
+
+static struct platform_device wzrhpg300nh_rtl8366s_device = {
+	.name		= RTL8366S_DRIVER_NAME,
+	.id		= -1,
+	.dev = {
+		.platform_data	= &wzrhpg300nh_rtl8366_data,
+	}
+};
+
+static struct platform_device wzrhpg300nh_rtl8366rb_device = {
+	.name           = RTL8366RB_DRIVER_NAME,
+	.id             = -1,
+	.dev = {
+		.platform_data  = &wzrhpg300nh_rtl8366_data,
+	}
+};
+
+static void __init wzrhpg300nh_setup(void)
+{
+	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff1000);
+	u8 *mac = eeprom + WZRHPG300NH_MAC_OFFSET;
+	bool hasrtl8366rb = false;
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	if (rtl8366_smi_detect(&wzrhpg300nh_rtl8366_data) == RTL8366_TYPE_RB)
+		hasrtl8366rb = true;
+
+	if (hasrtl8366rb) {
+		ath79_eth0_pll_data.pll_1000 = 0x1f000000;
+		ath79_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366rb_device.dev;
+		ath79_eth1_pll_data.pll_1000 = 0x100;
+		ath79_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366rb_device.dev;
+	} else {
+		ath79_eth0_pll_data.pll_1000 = 0x1e000100;
+		ath79_eth0_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev;
+		ath79_eth1_pll_data.pll_1000 = 0x1e000100;
+		ath79_eth1_data.mii_bus_dev = &wzrhpg300nh_rtl8366s_device.dev;
+	}
+
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth1_data.phy_mask = 0x10;
+
+	ath79_register_eth(0);
+	ath79_register_eth(1);
+
+	ath79_register_usb();
+	ath79_register_wmac(eeprom, NULL);
+
+	platform_device_register(&wzrhpg300nh_74hc153_device);
+	platform_device_register(&wzrhpg300nh_flash_device);
+
+	if (hasrtl8366rb)
+		platform_device_register(&wzrhpg300nh_rtl8366rb_device);
+	else
+		platform_device_register(&wzrhpg300nh_rtl8366s_device);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wzrhpg300nh_leds_gpio),
+					wzrhpg300nh_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WZRHPG300NH_KEYS_POLL_INTERVAL,
+					 ARRAY_SIZE(wzrhpg300nh_gpio_keys),
+					 wzrhpg300nh_gpio_keys);
+
+}
+
+MIPS_MACHINE(ATH79_MACH_WZR_HP_G300NH, "WZR-HP-G300NH",
+	     "Buffalo WZR-HP-G300NH", wzrhpg300nh_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh2.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh2.c
new file mode 100644
index 0000000000..296551348f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g300nh2.c
@@ -0,0 +1,170 @@
+/*
+ *  Buffalo WZR-HP-G300NH2 board support
+ *
+ *  Copyright (C) 2011 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2011 Mark Deneen <mdeneen@gmail.com>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define WZRHPG300NH2_MAC_OFFSET		0x20c
+#define WZRHPG300NH2_KEYS_POLL_INTERVAL     20      /* msecs */
+#define WZRHPG300NH2_KEYS_DEBOUNCE_INTERVAL (3 * WZRHPG300NH2_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition wzrhpg300nh2_flash_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x0040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x0040000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "art",
+		.offset		= 0x0050000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x0060000,
+		.size		= 0x1f90000,
+	}, {
+		.name		= "user_property",
+		.offset		= 0x1ff0000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}
+};
+
+static struct flash_platform_data wzrhpg300nh2_flash_data = {
+	.parts          = wzrhpg300nh2_flash_partitions,
+	.nr_parts       = ARRAY_SIZE(wzrhpg300nh2_flash_partitions),
+};
+
+static struct gpio_led wzrhpg300nh2_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:red:diag",
+		.gpio		= 16,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_led wzrhpg300nh2_wmac_leds_gpio[] = {
+	{
+		.name           = "buffalo:blue:usb",
+		.gpio           = 4,
+		.active_low     = 1,
+	},
+	{
+		.name           = "buffalo:orange:security",
+		.gpio           = 6,
+		.active_low     = 1,
+	},
+	{
+		.name           = "buffalo:green:router",
+		.gpio           = 7,
+		.active_low     = 1,
+	},
+	{
+		.name           = "buffalo:blue:movie_engine_on",
+		.gpio           = 8,
+		.active_low     = 1,
+	},
+	{
+		.name           = "buffalo:blue:movie_engine_off",
+		.gpio           = 9,
+		.active_low     = 1,
+	},
+};
+
+/* The AOSS button is wmac gpio 12 */
+static struct gpio_keys_button wzrhpg300nh2_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WZRHPG300NH2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 1,
+		.active_low	= 1,
+	}, {
+		.desc		= "usb",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = WZRHPG300NH2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 7,
+		.active_low	= 1,
+	}, {
+		.desc		= "qos",
+		.type		= EV_KEY,
+		.code		= BTN_3,
+		.debounce_interval = WZRHPG300NH2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 11,
+		.active_low	= 0,
+	}, {
+		.desc		= "router_on",
+		.type		= EV_KEY,
+		.code		= BTN_5,
+		.debounce_interval = WZRHPG300NH2_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 8,
+		.active_low	= 0,
+	},
+};
+
+static void __init wzrhpg300nh2_setup(void)
+{
+
+	u8 *eeprom = (u8 *)   KSEG1ADDR(0x1f051000);
+	u8 *mac0   = eeprom + WZRHPG300NH2_MAC_OFFSET;
+	/* There is an eth1 but it is not connected to the switch */
+
+	ath79_register_m25p80_multi(&wzrhpg300nh2_flash_data);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac0, 0);
+	ath79_register_mdio(0, ~(BIT(0)));
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac0, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_register_eth(0);
+
+	/* gpio13 is usb power.  Turn it on. */
+	gpio_request_one(13, GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wzrhpg300nh2_leds_gpio),
+				 wzrhpg300nh2_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, WZRHPG300NH2_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wzrhpg300nh2_gpio_keys),
+					wzrhpg300nh2_gpio_keys);
+	ap9x_pci_setup_wmac_led_pin(0, 5);
+	ap9x_pci_setup_wmac_leds(0, wzrhpg300nh2_wmac_leds_gpio,
+				ARRAY_SIZE(wzrhpg300nh2_wmac_leds_gpio));
+
+	ap91_pci_init(eeprom, mac0);
+}
+
+MIPS_MACHINE(ATH79_MACH_WZR_HP_G300NH2, "WZR-HP-G300NH2",
+	     "Buffalo WZR-HP-G300NH2", wzrhpg300nh2_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g450h.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g450h.c
new file mode 100644
index 0000000000..53f37b0981
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wzr-hp-g450h.c
@@ -0,0 +1,165 @@
+/*
+ *  Buffalo WZR-HP-G450G board support
+ *
+ *  Copyright (C) 2011 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-usb.h"
+#include "machtypes.h"
+
+#define WZRHPG450H_KEYS_POLL_INTERVAL     20      /* msecs */
+#define WZRHPG450H_KEYS_DEBOUNCE_INTERVAL (3 * WZRHPG450H_KEYS_POLL_INTERVAL)
+
+static struct mtd_partition wzrhpg450h_partitions[] = {
+	{
+		.name		= "u-boot",
+		.offset		= 0,
+		.size		= 0x0040000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "u-boot-env",
+		.offset		= 0x0040000,
+		.size		= 0x0010000,
+	}, {
+		.name		= "ART",
+		.offset		= 0x0050000,
+		.size		= 0x0010000,
+		.mask_flags	= MTD_WRITEABLE,
+	}, {
+		.name		= "firmware",
+		.offset		= 0x0060000,
+		.size		= 0x1f80000,
+	}, {
+		.name		= "user_property",
+		.offset		= 0x1fe0000,
+		.size		= 0x0020000,
+	}
+};
+
+static struct flash_platform_data wzrhpg450h_flash_data = {
+	.parts		= wzrhpg450h_partitions,
+	.nr_parts	= ARRAY_SIZE(wzrhpg450h_partitions),
+};
+
+static struct gpio_led wzrhpg450h_leds_gpio[] __initdata = {
+	{
+		.name		= "buffalo:red:diag",
+		.gpio		= 14,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:orange:security",
+		.gpio		= 13,
+		.active_low	= 1,
+	},
+};
+
+
+static struct gpio_led wzrhpg450h_wmac_leds_gpio[] = {
+	{
+		.name		= "buffalo:blue:movie_engine",
+		.gpio		= 13,
+		.active_low	= 1,
+	},
+	{
+		.name		= "buffalo:green:router",
+		.gpio		= 14,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button wzrhpg450h_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = WZRHPG450H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 6,
+		.active_low	= 1,
+	}, {
+		.desc		= "usb",
+		.type		= EV_KEY,
+		.code		= BTN_2,
+		.debounce_interval = WZRHPG450H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 1,
+		.active_low	= 1,
+	}, {
+		.desc		= "aoss",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = WZRHPG450H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 8,
+		.active_low	= 1,
+	}, {
+		.desc		= "movie_engine",
+		.type		= EV_KEY,
+		.code		= BTN_6,
+		.debounce_interval = WZRHPG450H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 7,
+		.active_low	= 0,
+	}, {
+		.desc		= "router_off",
+		.type		= EV_KEY,
+		.code		= BTN_5,
+		.debounce_interval = WZRHPG450H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= 12,
+		.active_low	= 0,
+	}
+};
+
+
+static void __init wzrhpg450h_init(void)
+{
+	u8 *ee = (u8 *) KSEG1ADDR(0x1f051000);
+	u8 *mac = (u8 *) ee + 2;
+
+	ath79_register_m25p80_multi(&wzrhpg450h_flash_data);
+
+	ath79_register_mdio(0, ~BIT(0));
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.speed = SPEED_1000;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_mask = BIT(0);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(wzrhpg450h_leds_gpio),
+				 wzrhpg450h_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, WZRHPG450H_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(wzrhpg450h_gpio_keys),
+					wzrhpg450h_gpio_keys);
+
+	ath79_register_eth(0);
+
+	gpio_request_one(16, GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_FIXED,
+			 "USB power");
+	ath79_register_usb();
+
+	ap91_pci_init(ee, NULL);
+	ap9x_pci_get_wmac_data(0)->tx_gain_buffalo = true;
+	ap9x_pci_get_wmac_data(1)->tx_gain_buffalo = true;
+	ap9x_pci_setup_wmac_led_pin(0, 15);
+	ap9x_pci_setup_wmac_leds(0, wzrhpg450h_wmac_leds_gpio,
+				 ARRAY_SIZE(wzrhpg450h_wmac_leds_gpio));
+}
+
+MIPS_MACHINE(ATH79_MACH_WZR_HP_G450H, "WZR-HP-G450H", "Buffalo WZR-HP-G450H",
+	     wzrhpg450h_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-z1.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-z1.c
new file mode 100644
index 0000000000..552d646370
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-z1.c
@@ -0,0 +1,164 @@
+/*
+ *  Cisco Meraki Z1 board support
+ *
+ *  Copyright (C) 2016 Chris Blake <chrisrblake93@gmail.com>
+ *  Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
+ *
+ *  Based on Cisco Meraki GPL Release r23-20150601 Z1 Device Config
+ *
+ *  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/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/ar8216_platform.h>
+#include <linux/platform/ar934x_nfc.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include <linux/leds-nu801.h>
+#include <linux/firmware.h>
+#include <linux/pci.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-nfc.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "dev-ap9x-pci.h"
+#include "machtypes.h"
+
+#define Z1_GPIO_LED_POWER_ORANGE	17
+
+#define Z1_GPIO_NU801_CKI		14
+#define Z1_GPIO_NU801_SDI		15
+
+#define Z1_GPIO_XLNA0			18
+#define Z1_GPIO_XLNA1			19
+
+#define Z1_GPIO_BTN_RESET		12
+#define Z1_KEYS_POLL_INTERVAL		20  /* msecs */
+#define Z1_KEYS_DEBOUNCE_INTERVAL	(3 * Z1_KEYS_POLL_INTERVAL)
+
+#define Z1_ETH_SWITCH_PHY		0
+
+static struct gpio_led Z1_leds_gpio[] __initdata = {
+	{
+		.name = "z1:orange:power",
+		.gpio = Z1_GPIO_LED_POWER_ORANGE,
+		.active_low  = 1,
+	},
+};
+
+static struct gpio_keys_button Z1_gpio_keys[] __initdata = {
+	{
+		.desc = "reset",
+		.type = EV_KEY,
+		.code = KEY_RESTART,
+		.debounce_interval = Z1_KEYS_DEBOUNCE_INTERVAL,
+		.gpio    = Z1_GPIO_BTN_RESET,
+		.active_low  = 1,
+	},
+};
+
+static struct led_nu801_template tricolor_led_template = {
+	.device_name = "z1",
+	.name = "tricolor",
+	.num_leds = 1,
+	.cki = Z1_GPIO_NU801_CKI,
+	.sdi = Z1_GPIO_NU801_SDI,
+	.lei = -1,
+	.ndelay = 500,
+	.init_brightness = {
+		LED_OFF,
+		LED_OFF,
+		LED_OFF,
+	},
+	.default_trigger = "none",
+};
+
+static struct led_nu801_platform_data tricolor_led_data = {
+	.num_controllers = 1,
+	.template = &tricolor_led_template,
+};
+
+static struct platform_device tricolor_leds = {
+	.name = "leds-nu801",
+	.id = -1,
+	.dev.platform_data = &tricolor_led_data,
+};
+
+static struct ar8327_pad_cfg z1_ar8327_pad0_cfg = {
+	.mode = AR8327_PAD_MAC_RGMII,
+	.txclk_delay_en = true,
+	.rxclk_delay_en = true,
+	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
+	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+};
+
+static struct ar8327_platform_data z1_ar8327_data = {
+	.pad0_cfg = &z1_ar8327_pad0_cfg,
+	.port0_cfg = {
+		.force_link = 1,
+		.speed = AR8327_PORT_SPEED_1000,
+		.duplex = 1,
+		.txpause = 1,
+		.rxpause = 1,
+	},
+};
+
+static struct mdio_board_info z1_mdio0_info[] = {
+	{
+		.bus_id = "ag71xx-mdio.0",
+		.phy_addr = Z1_ETH_SWITCH_PHY,
+		.platform_data = &z1_ar8327_data,
+	},
+};
+
+static void __init z1_setup(void)
+{
+	/* NAND */
+	ath79_nfc_set_ecc_mode(AR934X_NFC_ECC_SOFT_BCH);
+	ath79_register_nfc();
+
+	/* Eth Config */
+	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
+				   AR934X_ETH_CFG_SW_ONLY_MODE);
+
+	/* MDIO Interface */
+	ath79_register_mdio(1, 0x0);
+	ath79_register_mdio(0, 0x0);
+	mdiobus_register_board_info(z1_mdio0_info,
+				    ARRAY_SIZE(z1_mdio0_info));
+
+	/* GMAC0 is connected to an AR8327 switch */
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+	ath79_eth0_data.phy_mask = BIT(Z1_ETH_SWITCH_PHY);
+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+	ath79_eth0_pll_data.pll_1000 = 0x06000000;
+	ath79_register_eth(0);
+
+	/* XLNA */
+	ath79_wmac_set_ext_lna_gpio(0, Z1_GPIO_XLNA0);
+	ath79_wmac_set_ext_lna_gpio(1, Z1_GPIO_XLNA1);
+
+	/* LEDs and Buttons */
+	platform_device_register(&tricolor_leds);
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(Z1_leds_gpio),
+				 Z1_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, Z1_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(Z1_gpio_keys),
+					Z1_gpio_keys);
+
+	/* USB */
+	ath79_register_usb();
+
+	/* Wireless */
+	ath79_register_wmac_simple();
+	ap91_pci_init_simple();
+}
+MIPS_MACHINE(ATH79_MACH_Z1, "Z1", "Meraki Z1", z1_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-zbt-we1526.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-zbt-we1526.c
new file mode 100644
index 0000000000..42bad11905
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-zbt-we1526.c
@@ -0,0 +1,153 @@
+/*
+ * Zbtlink ZBT-WE1526 board support
+ *
+ * Copyright (C) 2016 Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * Based on mach-dr531.c and mach-tl-wr841n-v9.c
+ *
+ * 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-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+#define ZBT_WE1526_GPIO_LED_STATUS	13
+#define ZBT_WE1526_GPIO_LED_LAN1	16
+#define ZBT_WE1526_GPIO_LED_LAN2	15
+#define ZBT_WE1526_GPIO_LED_LAN3	14
+#define ZBT_WE1526_GPIO_LED_LAN4	11
+#define ZBT_WE1526_GPIO_LED_WAN		4
+#define ZBT_WE1526_GPIO_LED_WLAN	12
+
+#define ZBT_WE1526_GPIO_BTN_RESET	17
+
+#define ZBT_WE1526_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ZBT_WE1526_KEYS_DEBOUNCE_INTERVAL	\
+	(3 * ZBT_WE1526_KEYS_POLL_INTERVAL)
+
+#define ZBT_WE1526_MAC0_OFFSET		0x0
+#define ZBT_WE1526_MAC1_OFFSET		0x6
+#define ZBT_WE1526_WMAC_CALDATA_OFFSET	0x1000
+
+static struct gpio_led zbt_we1526_leds_gpio[] __initdata = {
+	{
+		.name		= "zbt-we1526:green:status",
+		.gpio		= ZBT_WE1526_GPIO_LED_STATUS,
+		.active_low	= 1,
+	},
+	{
+		.name		= "zbt-we1526:green:lan1",
+		.gpio		= ZBT_WE1526_GPIO_LED_LAN1,
+		.active_low	= 1,
+	},
+	{
+		.name		= "zbt-we1526:green:lan2",
+		.gpio		= ZBT_WE1526_GPIO_LED_LAN2,
+		.active_low	= 1,
+	},
+	{
+		.name		= "zbt-we1526:green:lan3",
+		.gpio		= ZBT_WE1526_GPIO_LED_LAN3,
+		.active_low	= 1,
+	},
+	{
+		.name		= "zbt-we1526:green:lan4",
+		.gpio		= ZBT_WE1526_GPIO_LED_LAN4,
+		.active_low	= 1,
+	},
+	{
+		.name		= "zbt-we1526:green:wan",
+		.gpio		= ZBT_WE1526_GPIO_LED_WAN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "zbt-we1526:green:wlan",
+		.gpio		= ZBT_WE1526_GPIO_LED_WLAN,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_button zbt_we1526_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ZBT_WE1526_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ZBT_WE1526_GPIO_BTN_RESET,
+		.active_low	= 1,
+	},
+};
+
+static void __init zbt_we1526_gpio_setup(void)
+{
+	/* For LED on GPIO4 */
+	ath79_gpio_function_disable(AR934X_GPIO_FUNC_CLK_OBS4_EN);
+	ath79_gpio_output_select(ZBT_WE1526_GPIO_LED_WAN, 0);
+
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_STATUS, true);
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_LAN1, true);
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_LAN2, true);
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_LAN3, true);
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_LAN4, true);
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_WAN, true);
+	ath79_gpio_direction_select(ZBT_WE1526_GPIO_LED_WLAN, true);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(zbt_we1526_leds_gpio),
+				 zbt_we1526_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ZBT_WE1526_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(zbt_we1526_gpio_keys),
+					zbt_we1526_gpio_keys);
+}
+
+static void __init zbt_we1526_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_m25p80(NULL);
+
+	zbt_we1526_gpio_setup();
+
+	ath79_setup_ar933x_phy4_switch(false, false);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN */
+	ath79_eth1_data.duplex = DUPLEX_FULL;
+	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
+	ath79_switch_data.phy_poll_mask |= BIT(4);
+	ath79_init_mac(ath79_eth1_data.mac_addr,
+		       art + ZBT_WE1526_MAC0_OFFSET, 0);
+	ath79_register_eth(1);
+
+	/* WAN */
+	ath79_switch_data.phy4_mii_en = 1;
+	ath79_eth0_data.duplex = DUPLEX_FULL;
+	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+	ath79_eth0_data.phy_mask = BIT(4);
+	ath79_eth0_data.speed = SPEED_100;
+	ath79_init_mac(ath79_eth0_data.mac_addr,
+		       art + ZBT_WE1526_MAC1_OFFSET, 0);
+	ath79_register_eth(0);
+
+	ath79_register_wmac(art + ZBT_WE1526_WMAC_CALDATA_OFFSET, NULL);
+
+	ath79_register_usb();
+}
+
+MIPS_MACHINE(ATH79_MACH_ZBT_WE1526, "ZBT-WE1526", "Zbtlink ZBT-WE1526",
+	     zbt_we1526_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-zcn-1523h.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-zcn-1523h.c
new file mode 100644
index 0000000000..bc79ab9953
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-zcn-1523h.c
@@ -0,0 +1,154 @@
+/*
+ *  Zcomax ZCN-1523H-2-8/5-16 board support
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-eth.h"
+#include "dev-m25p80.h"
+#include "dev-ap9x-pci.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "machtypes.h"
+
+#define ZCN_1523H_GPIO_BTN_RESET	0
+#define ZCN_1523H_GPIO_LED_INIT		11
+#define ZCN_1523H_GPIO_LED_LAN1		17
+
+#define ZCN_1523H_2_GPIO_LED_WEAK	13
+#define ZCN_1523H_2_GPIO_LED_MEDIUM	14
+#define ZCN_1523H_2_GPIO_LED_STRONG	15
+
+#define ZCN_1523H_5_GPIO_LAN2_POWER	1
+#define ZCN_1523H_5_GPIO_LED_LAN2	13
+#define ZCN_1523H_5_GPIO_LED_WEAK	14
+#define ZCN_1523H_5_GPIO_LED_MEDIUM	15
+#define ZCN_1523H_5_GPIO_LED_STRONG	16
+
+#define ZCN_1523H_KEYS_POLL_INTERVAL	20	/* msecs */
+#define ZCN_1523H_KEYS_DEBOUNCE_INTERVAL (3 * ZCN_1523H_KEYS_POLL_INTERVAL)
+
+static struct gpio_keys_button zcn_1523h_gpio_keys[] __initdata = {
+	{
+		.desc		= "reset",
+		.type		= EV_KEY,
+		.code		= KEY_RESTART,
+		.debounce_interval = ZCN_1523H_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= ZCN_1523H_GPIO_BTN_RESET,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led zcn_1523h_leds_gpio[] __initdata = {
+	{
+		.name		= "zcn-1523h:amber:init",
+		.gpio		= ZCN_1523H_GPIO_LED_INIT,
+		.active_low	= 1,
+	}, {
+		.name		= "zcn-1523h:green:lan1",
+		.gpio		= ZCN_1523H_GPIO_LED_LAN1,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led zcn_1523h_2_leds_gpio[] __initdata = {
+	{
+		.name		= "zcn-1523h:red:weak",
+		.gpio		= ZCN_1523H_2_GPIO_LED_WEAK,
+		.active_low	= 1,
+	}, {
+		.name		= "zcn-1523h:amber:medium",
+		.gpio		= ZCN_1523H_2_GPIO_LED_MEDIUM,
+		.active_low	= 1,
+	}, {
+		.name		= "zcn-1523h:green:strong",
+		.gpio		= ZCN_1523H_2_GPIO_LED_STRONG,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_led zcn_1523h_5_leds_gpio[] __initdata = {
+	{
+		.name		= "zcn-1523h:red:weak",
+		.gpio		= ZCN_1523H_5_GPIO_LED_WEAK,
+		.active_low	= 1,
+	}, {
+		.name		= "zcn-1523h:amber:medium",
+		.gpio		= ZCN_1523H_5_GPIO_LED_MEDIUM,
+		.active_low	= 1,
+	}, {
+		.name		= "zcn-1523h:green:strong",
+		.gpio		= ZCN_1523H_5_GPIO_LED_STRONG,
+		.active_low	= 1,
+	}, {
+		.name		= "zcn-1523h:green:lan2",
+		.gpio		= ZCN_1523H_5_GPIO_LED_LAN2,
+		.active_low	= 1,
+	}
+};
+
+static void __init zcn_1523h_generic_setup(void)
+{
+	u8 *mac = (u8 *) KSEG1ADDR(0x1f7e0004);
+	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+	ath79_gpio_function_disable(AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN |
+				    AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN);
+
+	ath79_register_m25p80(NULL);
+
+	ath79_register_leds_gpio(0, ARRAY_SIZE(zcn_1523h_leds_gpio),
+					zcn_1523h_leds_gpio);
+
+	ath79_register_gpio_keys_polled(-1, ZCN_1523H_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(zcn_1523h_gpio_keys),
+					zcn_1523h_gpio_keys);
+
+	ap91_pci_init(ee, mac);
+
+	ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 1);
+
+	ath79_register_mdio(0, 0x0);
+
+	/* LAN1 port */
+	ath79_register_eth(0);
+}
+
+static void __init zcn_1523h_2_setup(void)
+{
+	zcn_1523h_generic_setup();
+	ap9x_pci_setup_wmac_gpio(0, BIT(9), 0);
+
+	ath79_register_leds_gpio(1, ARRAY_SIZE(zcn_1523h_2_leds_gpio),
+				 zcn_1523h_2_leds_gpio);
+}
+
+MIPS_MACHINE(ATH79_MACH_ZCN_1523H_2, "ZCN-1523H-2", "Zcomax ZCN-1523H-2",
+	     zcn_1523h_2_setup);
+
+static void __init zcn_1523h_5_setup(void)
+{
+	zcn_1523h_generic_setup();
+	ap9x_pci_setup_wmac_gpio(0, BIT(8), 0);
+
+	ath79_register_leds_gpio(1, ARRAY_SIZE(zcn_1523h_5_leds_gpio),
+				 zcn_1523h_5_leds_gpio);
+
+	/* LAN2 port */
+	ath79_register_eth(1);
+}
+
+MIPS_MACHINE(ATH79_MACH_ZCN_1523H_5, "ZCN-1523H-5", "Zcomax ZCN-1523H-5",
+	     zcn_1523h_5_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h b/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
new file mode 100644
index 0000000000..9a8da22f65
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
@@ -0,0 +1,291 @@
+/*
+ *  Atheros AR71XX/AR724X/AR913X machine type definitions
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_MACHTYPE_H
+#define _ATH79_MACHTYPE_H
+
+#include <asm/mips_machine.h>
+
+enum ath79_mach_type {
+	ATH79_MACH_GENERIC_OF = -1,	/* Device tree board */
+	ATH79_MACH_GENERIC = 0,
+	ATH79_MACH_ALFA_AP120C,			/* ALFA Network AP120C board */
+	ATH79_MACH_ALFA_AP96,			/* ALFA Network AP96 board */
+	ATH79_MACH_ALFA_NX,			/* ALFA Network N2/N5 board */
+	ATH79_MACH_ALL0258N,			/* Allnet ALL0258N */
+	ATH79_MACH_ALL0305,			/* Allnet ALL0305 */
+	ATH79_MACH_ALL0315N,			/* Allnet ALL0315N */
+	ATH79_MACH_ANTMINER_S1,			/* Antminer S1 */
+	ATH79_MACH_ANTMINER_S3,			/* Antminer S3 */
+	ATH79_MACH_ANTROUTER_R1,		/* Antrouter R1 */
+	ATH79_MACH_AP113,			/* Atheros AP113 reference board */
+	ATH79_MACH_AP121,			/* Atheros AP121 reference board */
+	ATH79_MACH_AP121_MINI,			/* Atheros AP121-MINI reference board */
+	ATH79_MACH_AP132,			/* Atheros AP132 reference board */
+	ATH79_MACH_AP135_020,			/* Atheros AP135-020 reference board */
+	ATH79_MACH_AP136_010,			/* Atheros AP136-010 reference board */
+	ATH79_MACH_AP136_020,			/* Atheros AP136-020 reference board */
+	ATH79_MACH_AP143,			/* Atheros AP143 reference board */
+	ATH79_MACH_AP147_010,			/* Atheros AP147-010 reference board */
+	ATH79_MACH_AP152,			/* Atheros AP152 reference board */
+	ATH79_MACH_AP81,			/* Atheros AP81 reference board */
+	ATH79_MACH_AP83,			/* Atheros AP83 */
+	ATH79_MACH_AP90Q,			/* YunCore AP90Q */
+	ATH79_MACH_AP96,			/* Atheros AP96 */
+	ATH79_MACH_ARCHER_C5,			/* TP-LINK Archer C5 board */
+	ATH79_MACH_ARCHER_C7,			/* TP-LINK Archer C7 board */
+	ATH79_MACH_ARCHER_C7_V2,		/* TP-LINK Archer C7 V2 board */
+	ATH79_MACH_ARDUINO_YUN,			/* Yun */
+	ATH79_MACH_AW_NR580,			/* AzureWave AW-NR580 */
+	ATH79_MACH_BHR_4GRV2,			/* Buffalo BHR-4GRV2 */
+	ATH79_MACH_BHU_BXU2000N2_A1,		/* BHU BXU2000n-2 A1 */
+	ATH79_MACH_BSB,				/* Smart Electronics Black Swift board */
+	ATH79_MACH_C55,				/* AirTight Networks C-55 */
+	ATH79_MACH_C60,				/* AirTight Networks C-60 */
+	ATH79_MACH_CAP324,			/* PowerCloud CAP324 */
+	ATH79_MACH_CAP4200AG,			/* Senao CAP4200AG */
+	ATH79_MACH_CARAMBOLA2,			/* 8devices Carambola2 */
+	ATH79_MACH_CF_E316N_V2,			/* COMFAST CF-E316N v2 */
+	ATH79_MACH_CF_E320N_V2,			/* COMFAST CF-E320N v2 */
+	ATH79_MACH_CF_E380AC_V1,		/* COMFAST CF-E380AC v1 */
+	ATH79_MACH_CF_E380AC_V2,		/* COMFAST CF-E380AC v2 */
+	ATH79_MACH_CF_E520N,			/* COMFAST CF-E520N */
+	ATH79_MACH_CF_E530N,			/* COMFAST CF-E530N */
+	ATH79_MACH_CPE210,			/* TP-LINK CPE210 */
+	ATH79_MACH_CPE510,			/* TP-LINK CPE510 */
+	ATH79_MACH_CPE830,			/* YunCore CPE830 */
+	ATH79_MACH_CPE870,			/* YunCore CPE870 */
+	ATH79_MACH_CR3000,			/* PowerCloud CR3000 */
+	ATH79_MACH_CR5000,			/* PowerCloud CR5000 */
+	ATH79_MACH_DAP_2695_A1,			/* D-Link DAP-2695 rev. A1 */
+	ATH79_MACH_DB120,			/* Atheros DB120 reference board */
+	ATH79_MACH_DGL_5500_A1,			/* D-link DGL-5500 rev. A1 */
+	ATH79_MACH_DHP_1565_A1,			/* D-Link DHP-1565 rev. A1 */
+	ATH79_MACH_DIR_505_A1,			/* D-Link DIR-505 rev. A1 */
+	ATH79_MACH_DIR_600_A1,			/* D-Link DIR-600 rev. A1 */
+	ATH79_MACH_DIR_615_C1,			/* D-Link DIR-615 rev. C1 */
+	ATH79_MACH_DIR_615_E1,			/* D-Link DIR-615 rev. E1 */
+	ATH79_MACH_DIR_615_E4,			/* D-Link DIR-615 rev. E4 */
+	ATH79_MACH_DIR_615_I1,			/* D-Link DIR-615 rev. I1 */
+	ATH79_MACH_DIR_825_B1,			/* D-Link DIR-825 rev. B1 */
+	ATH79_MACH_DIR_825_C1,			/* D-Link DIR-825 rev. C1 */
+	ATH79_MACH_DIR_835_A1,			/* D-Link DIR-835 rev. A1 */
+	ATH79_MACH_DIR_869_A1,			/* D-Link DIR-869 rev. A1 */
+	ATH79_MACH_DLAN_HOTSPOT,		/* devolo dLAN Hotspot */
+	ATH79_MACH_DLAN_PRO_1200_AC,		/* devolo dLAN pro 1200+ WiFi ac*/
+	ATH79_MACH_DLAN_PRO_500_WP,		/* devolo dLAN pro 500 Wireless+ */
+	ATH79_MACH_DOMYWIFI_DW33D,		/* DomyWifi DW33D */
+	ATH79_MACH_DR344,			/* Wallys DR344 */
+	ATH79_MACH_DR531,			/* Wallys DR531 */
+	ATH79_MACH_DRAGINO2,			/* Dragino Version 2 */
+	ATH79_MACH_EAP120,			/* TP-LINK EAP120 */
+	ATH79_MACH_EAP300V2,			/* EnGenius EAP300 v2 */
+	ATH79_MACH_EAP7660D,			/* Senao EAP7660D */
+	ATH79_MACH_EL_M150,			/* EasyLink EL-M150 */
+	ATH79_MACH_EL_MINI,			/* EasyLink EL-MINI */
+	ATH79_MACH_EPG5000,			/* EnGenius EPG5000 */
+	ATH79_MACH_ESR1750,			/* EnGenius ESR1750 */
+	ATH79_MACH_ESR900,			/* EnGenius ESR900 */
+	ATH79_MACH_EW_DORIN,			/* embedded wireless Dorin Platform */
+	ATH79_MACH_EW_DORIN_ROUTER,		/* embedded wireless Dorin Router Platform */
+	ATH79_MACH_F9K1115V2,			/* Belkin AC1750DB */
+	ATH79_MACH_GL_AR150,			/* GL-AR150 support */
+	ATH79_MACH_GL_AR300,			/* GL-AR300 */
+	ATH79_MACH_GL_AR300M,			/* GL-AR300M */
+	ATH79_MACH_GL_DOMINO,			/* Domino */
+	ATH79_MACH_GL_INET,			/* GL-CONNECT GL-INET */
+	ATH79_MACH_GL_MIFI,			/* GL-MIFI support */
+	ATH79_MACH_GS_MINIBOX_V1,		/* Gainstrong MiniBox V1.0 */
+	ATH79_MACH_GS_OOLITE,			/* GS OOLITE V1.0 */
+	ATH79_MACH_HIWIFI_HC6361,		/* HiWiFi HC6361 */
+	ATH79_MACH_HORNET_UB,			/* ALFA Networks Hornet-UB */
+	ATH79_MACH_JA76PF,			/* jjPlus JA76PF */
+	ATH79_MACH_JA76PF2,			/* jjPlus JA76PF2 */
+	ATH79_MACH_JWAP003,			/* jjPlus JWAP003 */
+	ATH79_MACH_JWAP230,			/* jjPlus JWAP230 */
+	ATH79_MACH_MC_MAC1200R,			/* MERCURY MAC1200R */
+	ATH79_MACH_MR12,			/* Cisco Meraki MR12 */
+	ATH79_MACH_MR16,			/* Cisco Meraki MR16 */
+	ATH79_MACH_MR1750,			/* OpenMesh MR1750 */
+	ATH79_MACH_MR1750V2,			/* OpenMesh MR1750v2 */
+	ATH79_MACH_MR18,			/* Cisco Meraki MR18 */
+	ATH79_MACH_MR600,			/* OpenMesh MR600 */
+	ATH79_MACH_MR600V2,			/* OpenMesh MR600v2 */
+	ATH79_MACH_MR900,			/* OpenMesh MR900 */
+	ATH79_MACH_MR900v2,			/* OpenMesh MR900v2 */
+	ATH79_MACH_MYNET_N600,			/* WD My Net N600 */
+	ATH79_MACH_MYNET_N750,			/* WD My Net N750 */
+	ATH79_MACH_MYNET_REXT,			/* WD My Net Wi-Fi Range Extender */
+	ATH79_MACH_MZK_W04NU,			/* Planex MZK-W04NU */
+	ATH79_MACH_MZK_W300NH,			/* Planex MZK-W300NH */
+	ATH79_MACH_NBG460N,			/* Zyxel NBG460N/550N/550NH */
+	ATH79_MACH_NBG6616,			/* Zyxel NBG6616 */
+	ATH79_MACH_NBG6716,			/* Zyxel NBG6716 */
+	ATH79_MACH_OM2P,			/* OpenMesh OM2P */
+	ATH79_MACH_OM2Pv2,			/* OpenMesh OM2Pv2 */
+	ATH79_MACH_OM2P_HS,			/* OpenMesh OM2P-HS */
+	ATH79_MACH_OM2P_HSv2,			/* OpenMesh OM2P-HSv2 */
+	ATH79_MACH_OM2P_HSv3,			/* OpenMesh OM2P-HSv3 */
+	ATH79_MACH_OM2P_LC,			/* OpenMesh OM2P-LC */
+	ATH79_MACH_OM5P,			/* OpenMesh OM5P */
+	ATH79_MACH_OM5P_AC,			/* OpenMesh OM5P-AC */
+	ATH79_MACH_OM5P_ACv2,			/* OpenMesh OM5P-ACv2 */
+	ATH79_MACH_OM5P_AN,			/* OpenMesh OM5P-AN */
+	ATH79_MACH_OMY_G1,			/* OMYlink OMY-G1 */
+	ATH79_MACH_OMY_X1,			/* OMYlink OMY-X1 */
+	ATH79_MACH_ONION_OMEGA,			/* ONION OMEGA */
+	ATH79_MACH_PB42,			/* Atheros PB42 */
+	ATH79_MACH_PB44,			/* Atheros PB44 reference board */
+	ATH79_MACH_PB92,			/* Atheros PB92 */
+	ATH79_MACH_QIHOO_C301,			/* Qihoo 360 C301 */
+	ATH79_MACH_R6100,			/* NETGEAR R6100 */
+	ATH79_MACH_RB_2011G,			/* Mikrotik RouterBOARD 2011UAS-2HnD */
+	ATH79_MACH_RB_2011L,			/* Mikrotik RouterBOARD 2011L */
+	ATH79_MACH_RB_2011R5,			/* Mikrotik RouterBOARD 2011UiAS(-2Hnd) */
+	ATH79_MACH_RB_2011US,			/* Mikrotik RouterBOARD 2011UAS */
+	ATH79_MACH_RB_411,			/* MikroTik RouterBOARD 411/411A/411AH */
+	ATH79_MACH_RB_411U,			/* MikroTik RouterBOARD 411U */
+	ATH79_MACH_RB_433,			/* MikroTik RouterBOARD 433/433AH */
+	ATH79_MACH_RB_433U,			/* MikroTik RouterBOARD 433UAH */
+	ATH79_MACH_RB_435G,			/* MikroTik RouterBOARD 435G */
+	ATH79_MACH_RB_450,			/* MikroTik RouterBOARD 450 */
+	ATH79_MACH_RB_450G,			/* MikroTik RouterBOARD 450G */
+	ATH79_MACH_RB_493,			/* Mikrotik RouterBOARD 493/493AH */
+	ATH79_MACH_RB_493G,			/* Mikrotik RouterBOARD 493G */
+	ATH79_MACH_RB_711GR100,			/* Mikrotik RouterBOARD 911/912 boards */
+	ATH79_MACH_RB_750,			/* MikroTik RouterBOARD 750 */
+	ATH79_MACH_RB_750G_R3,			/* MikroTik RouterBOARD 750GL */
+	ATH79_MACH_RB_751,			/* MikroTik RouterBOARD 751 */
+	ATH79_MACH_RB_751G,			/* Mikrotik RouterBOARD 751G */
+	ATH79_MACH_RB_922GS,			/* Mikrotik RouterBOARD 911/922GS boards */
+	ATH79_MACH_RB_951G,			/* Mikrotik RouterBOARD 951G */
+	ATH79_MACH_RB_951U,			/* Mikrotik RouterBOARD 951Ui-2HnD */
+	ATH79_MACH_RB_SXTLITE2ND,		/* Mikrotik RouterBOARD SXT Lite 2nD */
+	ATH79_MACH_RB_SXTLITE5ND,		/* Mikrotik RouterBOARD SXT Lite 5nD */
+	ATH79_MACH_RW2458N,			/* Redwave RW2458N */
+	ATH79_MACH_SMART_300,			/* NC-LINK SMART-300 */
+	ATH79_MACH_SOM9331,			/* OpenEmbed SOM9331 */
+	ATH79_MACH_TELLSTICK_ZNET_LITE,		/* TellStick ZNet Lite */
+	ATH79_MACH_TEW_632BRP,			/* TRENDnet TEW-632BRP */
+	ATH79_MACH_TEW_673GRU,			/* TRENDnet TEW-673GRU */
+	ATH79_MACH_TEW_712BR,			/* TRENDnet TEW-712BR */
+	ATH79_MACH_TEW_732BR,			/* TRENDnet TEW-732BR */
+	ATH79_MACH_TEW_823DRU,			/* TRENDnet TEW-823DRU */
+	ATH79_MACH_TL_MR10U,			/* TP-LINK TL-MR10U */
+	ATH79_MACH_TL_MR11U,			/* TP-LINK TL-MR11U */
+	ATH79_MACH_TL_MR13U,			/* TP-LINK TL-MR13U */
+	ATH79_MACH_TL_MR3020,			/* TP-LINK TL-MR3020 */
+	ATH79_MACH_TL_MR3040,			/* TP-LINK TL-MR3040 */
+	ATH79_MACH_TL_MR3040_V2,		/* TP-LINK TL-MR3040 v2 */
+	ATH79_MACH_TL_MR3220,			/* TP-LINK TL-MR3220 */
+	ATH79_MACH_TL_MR3220_V2,		/* TP-LINK TL-MR3220 v2 */
+	ATH79_MACH_TL_MR3420,			/* TP-LINK TL-MR3420 */
+	ATH79_MACH_TL_MR3420_V2,		/* TP-LINK TL-MR3420 v2 */
+	ATH79_MACH_TL_WA701ND_V2,		/* TP-LINK TL-WA701ND v2 */
+	ATH79_MACH_TL_WA7210N_V2,		/* TP-LINK TL-WA7210N v2 */
+	ATH79_MACH_TL_WA750RE,			/* TP-LINK TL-WA750RE */
+	ATH79_MACH_TL_WA7510N_V1,		/* TP-LINK TL-WA7510N v1 */
+	ATH79_MACH_TL_WA801ND_V2,		/* TP-LINK TL-WA801ND v2 */
+	ATH79_MACH_TL_WA801ND_V3,		/* TP-LINK TL-WA801ND v3 */
+	ATH79_MACH_TL_WA830RE_V2,		/* TP-LINK TL-WA830RE v2 */
+	ATH79_MACH_TL_WA850RE,			/* TP-LINK TL-WA850RE */
+	ATH79_MACH_TL_WA860RE,			/* TP-LINK TL-WA860RE */
+	ATH79_MACH_TL_WA901ND,			/* TP-LINK TL-WA901ND */
+	ATH79_MACH_TL_WA901ND_V2,		/* TP-LINK TL-WA901ND v2 */
+	ATH79_MACH_TL_WA901ND_V3,		/* TP-LINK TL-WA901ND v3 */
+	ATH79_MACH_TL_WA901ND_V4,		/* TP-LINK TL-WA901ND v4 */
+	ATH79_MACH_TL_WDR3320_V2,		/* TP-LINK TL-WDR3320 v2 */
+	ATH79_MACH_TL_WDR3500,			/* TP-LINK TL-WDR3500 */
+	ATH79_MACH_TL_WDR4300,			/* TP-LINK TL-WDR4300 */
+	ATH79_MACH_TL_WDR4900_V2,		/* TP-LINK TL-WDR4900 v2 */
+	ATH79_MACH_TL_WDR6500_V2,		/* TP-LINK TL-WDR6500 v2 */
+	ATH79_MACH_TL_WPA8630,			/* TP-Link TL-WPA8630 */
+	ATH79_MACH_TL_WR1041N_V2,		/* TP-LINK TL-WR1041N v2 */
+	ATH79_MACH_TL_WR1043ND,			/* TP-LINK TL-WR1043ND */
+	ATH79_MACH_TL_WR1043ND_V2,		/* TP-LINK TL-WR1043ND v2 */
+	ATH79_MACH_TL_WR2543N,			/* TP-LINK TL-WR2543N/ND */
+	ATH79_MACH_TL_WR703N,			/* TP-LINK TL-WR703N */
+	ATH79_MACH_TL_WR710N,			/* TP-LINK TL-WR710N */
+	ATH79_MACH_TL_WR720N_V3,		/* TP-LINK TL-WR720N v3/v4 */
+	ATH79_MACH_TL_WR741ND,			/* TP-LINK TL-WR741ND */
+	ATH79_MACH_TL_WR741ND_V4,		/* TP-LINK TL-WR741ND v4 */
+	ATH79_MACH_TL_WR802N_V1,		/* TP-LINK TL-WR802N v1 */
+	ATH79_MACH_TL_WR810N,			/* TP-LINK TL-WR810N */
+	ATH79_MACH_TL_WR841N_V1,		/* TP-LINK TL-WR841N v1 */
+	ATH79_MACH_TL_WR841N_V11,		/* TP-LINK TL-WR841N/ND v11 */
+	ATH79_MACH_TL_WR841N_V7,		/* TP-LINK TL-WR841N/ND v7 */
+	ATH79_MACH_TL_WR841N_V8,		/* TP-LINK TL-WR841N/ND v8 */
+	ATH79_MACH_TL_WR841N_V9,		/* TP-LINK TL-WR841N/ND v9 */
+	ATH79_MACH_TL_WR842N_V2,		/* TP-LINK TL-WR842N/ND v2 */
+	ATH79_MACH_TL_WR842N_V3,		/* TP-LINK TL-WR842N/ND v3 */
+	ATH79_MACH_TL_WR941ND,			/* TP-LINK TL-WR941ND */
+	ATH79_MACH_TL_WR941ND_V5,		/* TP-LINK TL-WR941ND v5 */
+	ATH79_MACH_TL_WR941ND_V6,		/* TP-LINK TL-WR941ND v6 */
+	ATH79_MACH_TUBE2H,			/* Alfa Network Tube2H */
+	ATH79_MACH_UBNT_AIRGW,			/* Ubiquiti AirGateway */
+	ATH79_MACH_UBNT_AIRGWP,			/* Ubiquiti AirGateway Pro */
+	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 */
+	ATH79_MACH_UBNT_NANO_M_XW,		/* Ubiquiti NanoStation M XW */
+	ATH79_MACH_UBNT_ROCKET_M,		/* Ubiquiti Rocket M */
+	ATH79_MACH_UBNT_ROCKET_M_TI,		/* Ubiquiti Rocket M TI */
+	ATH79_MACH_UBNT_ROCKET_M_XW,		/* Ubiquiti Rocket M XW */
+	ATH79_MACH_UBNT_RS,			/* Ubiquiti RouterStation */
+	ATH79_MACH_UBNT_RSPRO,			/* Ubiquiti RouterStation Pro */
+	ATH79_MACH_UBNT_UAP_PRO,		/* Ubiquiti UniFi AP Pro */
+	ATH79_MACH_UBNT_UNIFI,			/* Ubiquiti Unifi */
+	ATH79_MACH_UBNT_UNIFIAC_LITE,		/* Ubiquiti Unifi AC LITE/LR */
+	ATH79_MACH_UBNT_UNIFIAC_PRO,		/* Ubiquiti Unifi AC PRO */
+	ATH79_MACH_UBNT_UNIFI_OUTDOOR,		/* Ubiquiti UnifiAP Outdoor */
+	ATH79_MACH_UBNT_UNIFI_OUTDOOR_PLUS,	/* Ubiquiti UnifiAP Outdoor+ */
+	ATH79_MACH_UBNT_XM,			/* Ubiquiti Networks XM board rev 1.0 */
+	ATH79_MACH_WEIO,			/* WeIO board */
+	ATH79_MACH_WHR_G301N,			/* Buffalo WHR-G301N */
+	ATH79_MACH_WHR_HP_G300N,		/* Buffalo WHR-HP-G300N */
+	ATH79_MACH_WHR_HP_GN,			/* Buffalo WHR-HP-GN */
+	ATH79_MACH_WLAE_AG300N,			/* Buffalo WLAE-AG300N */
+	ATH79_MACH_WLR8100,			/* SITECOM WLR-8100 */
+	ATH79_MACH_WNDAP360,			/* NETGEAR WNDAP360 */
+	ATH79_MACH_WNDR3700,			/* NETGEAR WNDR3700/WNDR3800/WNDRMAC */
+	ATH79_MACH_WNDR3700_V4,			/* NETGEAR WNDR3700v4 */
+	ATH79_MACH_WNDR4300,			/* NETGEAR WNDR4300 */
+	ATH79_MACH_WNR1000_V2,			/* NETGEAR WNR1000 v2 */
+	ATH79_MACH_WNR2000,			/* NETGEAR WNR2000 */
+	ATH79_MACH_WNR2000_V3,			/* NETGEAR WNR2000 v3 */
+	ATH79_MACH_WNR2000_V4,			/* NETGEAR WNR2000 v4 */
+	ATH79_MACH_WNR2200,			/* NETGEAR WNR2200 */
+	ATH79_MACH_WNR612_V2,			/* NETGEAR WNR612 v2 */
+	ATH79_MACH_WP543,			/* Compex WP543 */
+	ATH79_MACH_WPE72,			/* Compex WPE72 */
+	ATH79_MACH_WPJ342,			/* Compex WPJ342 */
+	ATH79_MACH_WPJ344,			/* Compex WPJ344 */
+	ATH79_MACH_WPJ531,			/* Compex WPJ531 */
+	ATH79_MACH_WPJ558,			/* Compex WPJ558 */
+	ATH79_MACH_WPN824N,			/* NETGEAR WPN824N */
+	ATH79_MACH_WRT160NL,			/* Linksys WRT160NL */
+	ATH79_MACH_WRT400N,			/* Linksys WRT400N */
+	ATH79_MACH_WRTNODE2Q,			/* WRTnode2Q */
+	ATH79_MACH_WZR_450HP2,			/* Buffalo WZR-450HP2 */
+	ATH79_MACH_WZR_HP_AG300H,		/* Buffalo WZR-HP-AG300H */
+	ATH79_MACH_WZR_HP_G300NH,		/* Buffalo WZR-HP-G300NH */
+	ATH79_MACH_WZR_HP_G300NH2,		/* Buffalo WZR-HP-G300NH2 */
+	ATH79_MACH_WZR_HP_G450H,		/* Buffalo WZR-HP-G450H */
+	ATH79_MACH_Z1,				/* Cisco Meraki Z1 */
+	ATH79_MACH_ZBT_WE1526,			/* Zbtlink ZBT-WE1526 */
+	ATH79_MACH_ZCN_1523H_2,			/* Zcomax ZCN-1523H-2-xx */
+	ATH79_MACH_ZCN_1523H_5,			/* Zcomax ZCN-1523H-5-xx */
+};
+
+#endif /* _ATH79_MACHTYPE_H */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/nvram.c b/target/linux/ar71xx/files/arch/mips/ath79/nvram.c
new file mode 100644
index 0000000000..e55af5abe2
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/nvram.c
@@ -0,0 +1,80 @@
+/*
+ *  Atheros AR71xx minimal nvram support
+ *
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include "nvram.h"
+
+char *ath79_nvram_find_var(const char *name, const char *buf, unsigned buf_len)
+{
+	unsigned len = strlen(name);
+	char *cur, *last;
+
+	if (buf_len == 0 || len == 0)
+		return NULL;
+
+	if (buf_len < len)
+		return NULL;
+
+	if (len == 1)
+		return memchr(buf, (int) *name, buf_len);
+
+	last = (char *) buf + buf_len - len;
+	for (cur = (char *) buf; cur <= last; cur++)
+		if (cur[0] == name[0] && memcmp(cur, name, len) == 0)
+			return cur + len;
+
+	return NULL;
+}
+
+int ath79_nvram_parse_mac_addr(const char *nvram, unsigned nvram_len,
+			       const char *name, char *mac)
+{
+	char *buf;
+	char *mac_str;
+	int ret;
+	int t;
+
+	buf = vmalloc(nvram_len);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy(buf, nvram, nvram_len);
+	buf[nvram_len - 1] = '\0';
+
+	mac_str = ath79_nvram_find_var(name, buf, nvram_len);
+	if (!mac_str) {
+		ret = -EINVAL;
+		goto free;
+	}
+
+	if (strlen(mac_str) == 19 && mac_str[0] == '"' && mac_str[18] == '"') {
+		mac_str[18] = 0;
+		mac_str++;
+	}
+
+	t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+		   &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+
+	if (t != 6) {
+		ret = -EINVAL;
+		goto free;
+	}
+
+	ret = 0;
+
+free:
+	vfree(buf);
+	return ret;
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/nvram.h b/target/linux/ar71xx/files/arch/mips/ath79/nvram.h
new file mode 100644
index 0000000000..75151d4a3c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/nvram.h
@@ -0,0 +1,19 @@
+/*
+ *  Atheros AR71xx minimal nvram support
+ *
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_NVRAM_H
+#define _ATH79_NVRAM_H
+
+char *ath79_nvram_find_var(const char *name, const char *buf,
+			   unsigned buf_len);
+int ath79_nvram_parse_mac_addr(const char *nvram, unsigned nvram_len,
+			       const char *name, char *mac);
+
+#endif /* _ATH79_NVRAM_H */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.c b/target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.c
new file mode 100644
index 0000000000..2202351806
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.c
@@ -0,0 +1,126 @@
+/*
+ *  Atheros AP94 reference board PCI initialization
+ *
+ *  Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/pci.h>
+#include <linux/delay.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+struct ath9k_fixup {
+	u16		*cal_data;
+	unsigned	slot;
+};
+
+static int ath9k_num_fixups;
+static struct ath9k_fixup ath9k_fixups[2];
+
+static void ath9k_pci_fixup(struct pci_dev *dev)
+{
+	void __iomem *mem;
+	u16 *cal_data = NULL;
+	u16 cmd;
+	u32 bar0;
+	u32 val;
+	unsigned i;
+
+	for (i = 0; i < ath9k_num_fixups; i++) {
+		if (ath9k_fixups[i].cal_data == NULL)
+			continue;
+
+		if (ath9k_fixups[i].slot != PCI_SLOT(dev->devfn))
+			continue;
+
+		cal_data = ath9k_fixups[i].cal_data;
+		break;
+	}
+
+	if (cal_data == NULL)
+		return;
+
+	if (*cal_data != 0xa55a) {
+		pr_err("pci %s: invalid calibration data\n", pci_name(dev));
+		return;
+	}
+
+	pr_info("pci %s: fixup device configuration\n", pci_name(dev));
+
+	mem = ioremap(AR71XX_PCI_MEM_BASE, 0x10000);
+	if (!mem) {
+		pr_err("pci %s: ioremap error\n", pci_name(dev));
+		return;
+	}
+
+	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
+
+	switch (ath79_soc) {
+	case ATH79_SOC_AR7161:
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+				       AR71XX_PCI_MEM_BASE);
+		break;
+	case ATH79_SOC_AR7240:
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffff);
+		break;
+
+	case ATH79_SOC_AR7241:
+	case ATH79_SOC_AR7242:
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x1000ffff);
+		break;
+	case ATH79_SOC_AR9344:
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0x1000ffff);
+		break;
+
+	default:
+		BUG();
+	}
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	/* set pointer to first reg address */
+	cal_data += 3;
+	while (*cal_data != 0xffff) {
+		u32 reg;
+		reg = *cal_data++;
+		val = *cal_data++;
+		val |= (*cal_data++) << 16;
+
+		__raw_writel(val, mem + reg);
+		udelay(100);
+	}
+
+	pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
+	dev->vendor = val & 0xffff;
+	dev->device = (val >> 16) & 0xffff;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
+	dev->revision = val & 0xff;
+	dev->class = val >> 8; /* upper 3 bytes */
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
+
+	iounmap(mem);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath9k_pci_fixup);
+
+void __init pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data)
+{
+	if (ath9k_num_fixups >= ARRAY_SIZE(ath9k_fixups))
+		return;
+
+	ath9k_fixups[ath9k_num_fixups].slot = slot;
+	ath9k_fixups[ath9k_num_fixups].cal_data = cal_data;
+	ath9k_num_fixups++;
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.h b/target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.h
new file mode 100644
index 0000000000..5794941f08
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/pci-ath9k-fixup.h
@@ -0,0 +1,6 @@
+#ifndef _PCI_ATH9K_FIXUP
+#define _PCI_ATH9K_FIXUP
+
+void pci_enable_ath9k_fixup(unsigned slot, u16 *cal_data) __init;
+
+#endif /* _PCI_ATH9K_FIXUP */
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c
new file mode 100644
index 0000000000..76776e1d84
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c
@@ -0,0 +1,358 @@
+/*
+ *  RouterBoot helper routines
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) "rb: " fmt
+
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/routerboot.h>
+#include <linux/rle.h>
+#include <linux/lzo.h>
+
+#include "routerboot.h"
+
+#define RB_BLOCK_SIZE		0x1000
+#define RB_ART_SIZE		0x10000
+#define RB_MAGIC_ERD		0x00455244	/* extended radio data */
+
+static struct rb_info rb_info;
+
+static u32 get_u32(void *buf)
+{
+	u8 *p = buf;
+
+	return ((u32) p[3] + ((u32) p[2] << 8) + ((u32) p[1] << 16) +
+	       ((u32) p[0] << 24));
+}
+
+static u16 get_u16(void *buf)
+{
+	u8 *p = buf;
+
+	return (u16) p[1] + ((u16) p[0] << 8);
+}
+
+__init int
+routerboot_find_magic(u8 *buf, unsigned int buflen, u32 *offset, bool hard)
+{
+	u32 magic_ref = hard ? RB_MAGIC_HARD : RB_MAGIC_SOFT;
+	u32 magic;
+	u32 cur = *offset;
+
+	while (cur < buflen) {
+		magic = get_u32(buf + cur);
+		if (magic == magic_ref) {
+			*offset = cur;
+			return 0;
+		}
+
+		cur += 0x1000;
+	}
+
+	return -ENOENT;
+}
+
+__init int
+routerboot_find_tag(u8 *buf, unsigned int buflen, u16 tag_id,
+		    u8 **tag_data, u16 *tag_len)
+{
+	uint32_t magic;
+	bool align = false;
+	int ret;
+
+	if (buflen < 4)
+		return -EINVAL;
+
+	magic = get_u32(buf);
+	switch (magic) {
+	case RB_MAGIC_ERD:
+		align = true;
+		/* fall trough */
+	case RB_MAGIC_HARD:
+		/* skip magic value */
+		buf += 4;
+		buflen -= 4;
+		break;
+
+	case RB_MAGIC_SOFT:
+		if (buflen < 8)
+			return -EINVAL;
+
+		/* skip magic and CRC value */
+		buf += 8;
+		buflen -= 8;
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	ret = -ENOENT;
+	while (buflen > 2) {
+		u16 id;
+		u16 len;
+
+		len = get_u16(buf);
+		buf += 2;
+		buflen -= 2;
+
+		if (buflen < 2)
+			break;
+
+		id = get_u16(buf);
+		buf += 2;
+		buflen -= 2;
+
+		if (id == RB_ID_TERMINATOR)
+			break;
+
+		if (buflen < len)
+			break;
+
+		if (id == tag_id) {
+			if (tag_len)
+				*tag_len = len;
+			if (tag_data)
+				*tag_data = buf;
+			ret = 0;
+			break;
+		}
+
+		if (align)
+			len = (len + 3) / 4;
+
+		buf += len;
+		buflen -= len;
+	}
+
+	return ret;
+}
+
+static inline int
+rb_find_hard_cfg_tag(u16 tag_id, u8 **tag_data, u16 *tag_len)
+{
+	if (!rb_info.hard_cfg_data ||
+	    !rb_info.hard_cfg_size)
+		return -ENOENT;
+
+	return routerboot_find_tag(rb_info.hard_cfg_data,
+				   rb_info.hard_cfg_size,
+				   tag_id, tag_data, tag_len);
+}
+
+__init const char *
+rb_get_board_name(void)
+{
+	u16 tag_len;
+	u8 *tag;
+	int err;
+
+	err = rb_find_hard_cfg_tag(RB_ID_BOARD_NAME, &tag, &tag_len);
+	if (err)
+		return NULL;
+
+	return tag;
+}
+
+__init u32
+rb_get_hw_options(void)
+{
+	u16 tag_len;
+	u8 *tag;
+	int err;
+
+	err = rb_find_hard_cfg_tag(RB_ID_HW_OPTIONS, &tag, &tag_len);
+	if (err)
+		return 0;
+
+	return get_u32(tag);
+}
+
+static void * __init
+__rb_get_wlan_data(u16 id)
+{
+	u16 tag_len;
+	u8 *tag;
+	void *buf;
+	int err;
+	u32 magic;
+	size_t src_done;
+	size_t dst_done;
+
+	err = rb_find_hard_cfg_tag(RB_ID_WLAN_DATA, &tag, &tag_len);
+	if (err) {
+		pr_err("no calibration data found\n");
+		goto err;
+	}
+
+	buf = kmalloc(RB_ART_SIZE, GFP_KERNEL);
+	if (buf == NULL) {
+		pr_err("no memory for calibration data\n");
+		goto err;
+	}
+
+	magic = get_u32(tag);
+	if (magic == RB_MAGIC_ERD) {
+		u8 *erd_data;
+		u16 erd_len;
+
+		if (id == 0)
+			goto err_free;
+
+		err = routerboot_find_tag(tag, tag_len, id,
+					  &erd_data, &erd_len);
+		if (err) {
+			pr_err("no ERD data found for id %u\n", id);
+			goto err_free;
+		}
+
+		dst_done = RB_ART_SIZE;
+		err = lzo1x_decompress_safe(erd_data, erd_len, buf, &dst_done);
+		if (err) {
+			pr_err("unable to decompress calibration data %d\n",
+			       err);
+			goto err_free;
+		}
+	} else {
+		if (id != 0)
+			goto err_free;
+
+		err = rle_decode((char *) tag, tag_len, buf, RB_ART_SIZE,
+				 &src_done, &dst_done);
+		if (err) {
+			pr_err("unable to decode calibration data\n");
+			goto err_free;
+		}
+	}
+
+	return buf;
+
+err_free:
+	kfree(buf);
+err:
+	return NULL;
+}
+
+__init void *
+rb_get_wlan_data(void)
+{
+	return __rb_get_wlan_data(0);
+}
+
+__init void *
+rb_get_ext_wlan_data(u16 id)
+{
+	return __rb_get_wlan_data(id);
+}
+
+__init const struct rb_info *
+rb_init_info(void *data, unsigned int size)
+{
+	unsigned int offset;
+
+	if (size == 0 || (size % RB_BLOCK_SIZE) != 0)
+		return NULL;
+
+	for (offset = 0; offset < size; offset += RB_BLOCK_SIZE) {
+		u32 magic;
+
+		magic = get_u32(data + offset);
+		switch (magic) {
+		case RB_MAGIC_HARD:
+			rb_info.hard_cfg_offs = offset;
+			break;
+
+		case RB_MAGIC_SOFT:
+			rb_info.soft_cfg_offs = offset;
+			break;
+		}
+	}
+
+	if (!rb_info.hard_cfg_offs) {
+		pr_err("could not find a valid RouterBOOT hard config\n");
+		return NULL;
+	}
+
+	if (!rb_info.soft_cfg_offs) {
+		pr_err("could not find a valid RouterBOOT soft config\n");
+		return NULL;
+	}
+
+	rb_info.hard_cfg_size = RB_BLOCK_SIZE;
+	rb_info.hard_cfg_data = kmemdup(data + rb_info.hard_cfg_offs,
+					RB_BLOCK_SIZE, GFP_KERNEL);
+	if (!rb_info.hard_cfg_data)
+		return NULL;
+
+	rb_info.board_name = rb_get_board_name();
+	rb_info.hw_options = rb_get_hw_options();
+
+	return &rb_info;
+}
+
+static char *rb_ext_wlan_data;
+
+static ssize_t
+rb_ext_wlan_data_read(struct file *filp, struct kobject *kobj,
+		      struct bin_attribute *attr, char *buf,
+		      loff_t off, size_t count)
+{
+         if (off + count > attr->size)
+                 return -EFBIG;
+
+         memcpy(buf, &rb_ext_wlan_data[off], count);
+
+         return count;
+}
+
+static const struct bin_attribute rb_ext_wlan_data_attr = {
+	.attr = {
+		.name = "ext_wlan_data",
+		.mode = S_IRUSR | S_IWUSR,
+	},
+	.read = rb_ext_wlan_data_read,
+	.size = RB_ART_SIZE,
+};
+
+static int __init rb_sysfs_init(void)
+{
+	struct kobject *rb_kobj;
+	int ret;
+
+	rb_ext_wlan_data = rb_get_ext_wlan_data(1);
+	if (rb_ext_wlan_data == NULL)
+		return -ENOENT;
+
+	rb_kobj = kobject_create_and_add("routerboot", firmware_kobj);
+	if (rb_kobj == NULL) {
+		ret = -ENOMEM;
+		pr_err("unable to create sysfs entry\n");
+		goto err_free_wlan_data;
+	}
+
+	ret = sysfs_create_bin_file(rb_kobj, &rb_ext_wlan_data_attr);
+	if (ret) {
+		pr_err("unable to create sysfs file, %d\n", ret);
+		goto err_put_kobj;
+	}
+
+	return 0;
+
+err_put_kobj:
+	kobject_put(rb_kobj);
+err_free_wlan_data:
+	kfree(rb_ext_wlan_data);
+	return ret;
+}
+
+late_initcall(rb_sysfs_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h
new file mode 100644
index 0000000000..c1d7fb9ee0
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h
@@ -0,0 +1,63 @@
+/*
+ *  RouterBoot definitions
+ *
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _ATH79_ROUTERBOOT_H_
+#define _ATH79_ROUTERBOOT_H_
+
+struct rb_info {
+	unsigned int hard_cfg_offs;
+	unsigned int hard_cfg_size;
+	void *hard_cfg_data;
+	unsigned int soft_cfg_offs;
+
+	const char *board_name;
+	u32 hw_options;
+};
+
+#ifdef CONFIG_ATH79_ROUTERBOOT
+const struct rb_info *rb_init_info(void *data, unsigned int size);
+void *rb_get_wlan_data(void);
+void *rb_get_ext_wlan_data(u16 id);
+
+int routerboot_find_tag(u8 *buf, unsigned int buflen, u16 tag_id,
+			u8 **tag_data, u16 *tag_len);
+int routerboot_find_magic(u8 *buf, unsigned int buflen, u32 *offset, bool hard);
+#else
+static inline const struct rb_info *
+rb_init_info(void *data, unsigned int size)
+{
+	return NULL;
+}
+
+static inline void *rb_get_wlan_data(void)
+{
+	return NULL;
+}
+
+static inline void *rb_get_wlan_data(u16 id)
+{
+	return NULL;
+}
+
+static inline int
+routerboot_find_tag(u8 *buf, unsigned int buflen, u16 tag_id,
+		    u8 **tag_data, u16 *tag_len)
+{
+	return -ENOENT;
+}
+
+static inline int
+routerboot_find_magic(u8 *buf, unsigned int buflen, u32 *offset, bool hard)
+{
+	return -ENOENT;
+}
+#endif
+
+#endif /* _ATH79_ROUTERBOOT_H_ */
diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/fw/myloader/myloader.h b/target/linux/ar71xx/files/arch/mips/include/asm/fw/myloader/myloader.h
new file mode 100644
index 0000000000..8a99d566d7
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/include/asm/fw/myloader/myloader.h
@@ -0,0 +1,34 @@
+/*
+ *  Compex's MyLoader specific definitions
+ *
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#ifndef _ASM_MIPS_FW_MYLOADER_H
+#define _ASM_MIPS_FW_MYLOADER_H
+
+#include <linux/myloader.h>
+
+struct myloader_info {
+	uint32_t	vid;
+	uint32_t	did;
+	uint32_t	svid;
+	uint32_t	sdid;
+	uint8_t		macs[MYLO_ETHADDR_COUNT][6];
+};
+
+#ifdef CONFIG_MYLOADER
+extern struct myloader_info *myloader_get_info(void) __init;
+#else
+static inline struct myloader_info *myloader_get_info(void)
+{
+	return NULL;
+}
+#endif /* CONFIG_MYLOADER */
+
+#endif /* _ASM_MIPS_FW_MYLOADER_H */
diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
new file mode 100644
index 0000000000..5fd352c638
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
@@ -0,0 +1,66 @@
+/*
+ *  Atheros AR71xx SoC specific platform data definitions
+ *
+ *  Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef __ASM_MACH_ATH79_PLATFORM_H
+#define __ASM_MACH_ATH79_PLATFORM_H
+
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/phy.h>
+#include <linux/spi/spi.h>
+
+struct ag71xx_switch_platform_data {
+	u8		phy4_mii_en:1;
+	u8		phy_poll_mask;
+};
+
+struct ag71xx_platform_data {
+	phy_interface_t	phy_if_mode;
+	u32		phy_mask;
+	int		speed;
+	int		duplex;
+	u32		reset_bit;
+	u8		mac_addr[ETH_ALEN];
+	struct device	*mii_bus_dev;
+
+	u8		has_gbit:1;
+	u8		is_ar91xx:1;
+	u8		is_ar7240:1;
+	u8		is_ar724x:1;
+	u8		has_ar8216:1;
+	u8		use_flow_control:1;
+
+	struct ag71xx_switch_platform_data *switch_data;
+
+	void		(*ddr_flush)(void);
+	void		(*set_speed)(int speed);
+
+	u32		fifo_cfg1;
+	u32		fifo_cfg2;
+	u32		fifo_cfg3;
+
+	unsigned int	max_frame_len;
+	unsigned int	desc_pktlen_mask;
+};
+
+struct ag71xx_mdio_platform_data {
+	u32		phy_mask;
+	u8		builtin_switch:1;
+	u8		is_ar7240:1;
+	u8		is_ar9330:1;
+	u8		is_ar934x:1;
+	unsigned long	mdio_clock;
+	unsigned long	ref_clock;
+
+	void		(*reset)(struct mii_bus *bus);
+};
+
+#endif /* __ASM_MACH_ATH79_PLATFORM_H */
diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/mach-rb750.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/mach-rb750.h
new file mode 100644
index 0000000000..50d5a20974
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/mach-rb750.h
@@ -0,0 +1,84 @@
+/*
+ *  MikroTik RouterBOARD 750 definitions
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+#ifndef _MACH_RB750_H
+#define _MACH_RB750_H
+
+#include <linux/bitops.h>
+
+#define RB750_GPIO_LVC573_LE	0	/* Latch enable on LVC573 */
+#define RB750_GPIO_NAND_IO0	1	/* NAND I/O 0 */
+#define RB750_GPIO_NAND_IO1	2	/* NAND I/O 1 */
+#define RB750_GPIO_NAND_IO2	3	/* NAND I/O 2 */
+#define RB750_GPIO_NAND_IO3	4	/* NAND I/O 3 */
+#define RB750_GPIO_NAND_IO4	5	/* NAND I/O 4 */
+#define RB750_GPIO_NAND_IO5	6	/* NAND I/O 5 */
+#define RB750_GPIO_NAND_IO6	7	/* NAND I/O 6 */
+#define RB750_GPIO_NAND_IO7	8	/* NAND I/O 7 */
+#define RB750_GPIO_NAND_NCE	11	/* NAND Chip Enable (active low) */
+#define RB750_GPIO_NAND_RDY	12	/* NAND Ready */
+#define RB750_GPIO_NAND_CLE	14	/* NAND Command Latch Enable */
+#define RB750_GPIO_NAND_ALE	15	/* NAND Address Latch Enable */
+#define RB750_GPIO_NAND_NRE	16	/* NAND Read Enable (active low) */
+#define RB750_GPIO_NAND_NWE	17	/* NAND Write Enable (active low) */
+
+#define RB750_GPIO_BTN_RESET	1
+#define RB750_GPIO_SPI_CS0	2
+#define RB750_GPIO_LED_ACT	12
+#define RB750_GPIO_LED_PORT1	13
+#define RB750_GPIO_LED_PORT2	14
+#define RB750_GPIO_LED_PORT3	15
+#define RB750_GPIO_LED_PORT4	16
+#define RB750_GPIO_LED_PORT5	17
+
+#define RB750_LED_ACT		BIT(RB750_GPIO_LED_ACT)
+#define RB750_LED_PORT1		BIT(RB750_GPIO_LED_PORT1)
+#define RB750_LED_PORT2		BIT(RB750_GPIO_LED_PORT2)
+#define RB750_LED_PORT3		BIT(RB750_GPIO_LED_PORT3)
+#define RB750_LED_PORT4		BIT(RB750_GPIO_LED_PORT4)
+#define RB750_LED_PORT5		BIT(RB750_GPIO_LED_PORT5)
+#define RB750_NAND_NCE		BIT(RB750_GPIO_NAND_NCE)
+
+#define RB750_LVC573_LE		BIT(RB750_GPIO_LVC573_LE)
+
+#define RB750_LED_BITS	(RB750_LED_PORT1 | RB750_LED_PORT2 | RB750_LED_PORT3 | \
+			 RB750_LED_PORT4 | RB750_LED_PORT5 | RB750_LED_ACT)
+
+#define RB7XX_GPIO_NAND_NCE	0
+#define RB7XX_GPIO_MON		9
+#define RB7XX_GPIO_LED_ACT	11
+#define RB7XX_GPIO_USB_POWERON	13
+
+#define RB7XX_NAND_NCE		BIT(RB7XX_GPIO_NAND_NCE)
+#define RB7XX_LED_ACT		BIT(RB7XX_GPIO_LED_ACT)
+#define RB7XX_MONITOR		BIT(RB7XX_GPIO_MON)
+#define RB7XX_USB_POWERON	BIT(RB7XX_GPIO_USB_POWERON)
+
+struct rb750_led_data {
+	char	*name;
+	char	*default_trigger;
+	u32	mask;
+	int	active_low;
+};
+
+struct rb750_led_platform_data {
+	int			num_leds;
+	struct rb750_led_data	*leds;
+	void			(*latch_change)(u32 clear, u32 set);
+};
+
+struct rb7xx_nand_platform_data {
+	u32 nce_line;
+
+	void (*enable_pins)(void);
+	void (*disable_pins)(void);
+	void (*latch_change)(u32, u32);
+};
+
+#endif /* _MACH_RB750_H */
\ No newline at end of file
diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
new file mode 100644
index 0000000000..5b17e94b64
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
@@ -0,0 +1,48 @@
+/*
+ * SPI driver definitions for the CPLD chip on the Mikrotik RB4xx boards
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file was based on the patches for Linux 2.6.27.39 published by
+ * MikroTik for their RouterBoard 4xx series devices.
+ *
+ * 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.
+ */
+
+#define CPLD_GPIO_nLED1		0
+#define CPLD_GPIO_nLED2		1
+#define CPLD_GPIO_nLED3		2
+#define CPLD_GPIO_nLED4		3
+#define CPLD_GPIO_FAN		4
+#define CPLD_GPIO_ALE		5
+#define CPLD_GPIO_CLE		6
+#define CPLD_GPIO_nCE		7
+#define CPLD_GPIO_nLED5		8
+
+#define CPLD_NUM_GPIOS		9
+
+#define CPLD_CFG_nLED1		BIT(CPLD_GPIO_nLED1)
+#define CPLD_CFG_nLED2		BIT(CPLD_GPIO_nLED2)
+#define CPLD_CFG_nLED3		BIT(CPLD_GPIO_nLED3)
+#define CPLD_CFG_nLED4		BIT(CPLD_GPIO_nLED4)
+#define CPLD_CFG_FAN		BIT(CPLD_GPIO_FAN)
+#define CPLD_CFG_ALE		BIT(CPLD_GPIO_ALE)
+#define CPLD_CFG_CLE		BIT(CPLD_GPIO_CLE)
+#define CPLD_CFG_nCE		BIT(CPLD_GPIO_nCE)
+#define CPLD_CFG_nLED5		BIT(CPLD_GPIO_nLED5)
+
+struct rb4xx_cpld_platform_data {
+	unsigned	gpio_base;
+};
+
+extern int rb4xx_cpld_change_cfg(unsigned mask, unsigned value);
+extern int rb4xx_cpld_read(unsigned char *rx_buf,
+			   const unsigned char *verify_buf,
+			   unsigned cnt);
+extern int rb4xx_cpld_read_from(unsigned addr,
+				unsigned char *rx_buf,
+				const unsigned char *verify_buf,
+				unsigned cnt);
+extern int rb4xx_cpld_write(const unsigned char *buf, unsigned count);
diff --git a/target/linux/ar71xx/files/drivers/gpio/gpio-latch.c b/target/linux/ar71xx/files/drivers/gpio/gpio-latch.c
new file mode 100644
index 0000000000..d911f6a2cb
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/gpio/gpio-latch.c
@@ -0,0 +1,220 @@
+/*
+ *  GPIO latch driver
+ *
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/platform_data/gpio-latch.h>
+
+struct gpio_latch_chip {
+	struct gpio_chip gc;
+
+	struct mutex mutex;
+	struct mutex latch_mutex;
+	bool latch_enabled;
+	int le_gpio;
+	bool le_active_low;
+	int *gpios;
+};
+
+static inline struct gpio_latch_chip *to_gpio_latch_chip(struct gpio_chip *gc)
+{
+	return container_of(gc, struct gpio_latch_chip, gc);
+}
+
+static void gpio_latch_lock(struct gpio_latch_chip *glc, bool enable)
+{
+	mutex_lock(&glc->mutex);
+
+	if (enable)
+		glc->latch_enabled = true;
+
+	if (glc->latch_enabled)
+		mutex_lock(&glc->latch_mutex);
+}
+
+static void gpio_latch_unlock(struct gpio_latch_chip *glc, bool disable)
+{
+	if (glc->latch_enabled)
+		mutex_unlock(&glc->latch_mutex);
+
+	if (disable)
+		glc->latch_enabled = true;
+
+	mutex_unlock(&glc->mutex);
+}
+
+static int
+gpio_latch_get(struct gpio_chip *gc, unsigned offset)
+{
+	struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
+	int ret;
+
+	gpio_latch_lock(glc, false);
+	ret = gpio_get_value(glc->gpios[offset]);
+	gpio_latch_unlock(glc, false);
+
+	return ret;
+}
+
+static void
+gpio_latch_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+	struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
+	bool enable_latch = false;
+	bool disable_latch = false;
+	int gpio;
+
+	gpio = glc->gpios[offset];
+
+	if (gpio == glc->le_gpio) {
+		enable_latch = value ^ glc->le_active_low;
+		disable_latch = !enable_latch;
+	}
+
+	gpio_latch_lock(glc, enable_latch);
+	gpio_set_value(gpio, value);
+	gpio_latch_unlock(glc, disable_latch);
+}
+
+static int
+gpio_latch_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
+	int ret;
+
+	gpio_latch_lock(glc, false);
+	ret = gpio_direction_input(glc->gpios[offset]);
+	gpio_latch_unlock(glc, false);
+
+	return ret;
+}
+
+static int
+gpio_latch_direction_output(struct gpio_chip *gc, unsigned offset, int value)
+{
+	struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
+	bool enable_latch = false;
+	bool disable_latch = false;
+	int gpio;
+	int ret;
+
+	gpio = glc->gpios[offset];
+
+	if (gpio == glc->le_gpio) {
+		enable_latch = value ^ glc->le_active_low;
+		disable_latch = !enable_latch;
+	}
+
+	gpio_latch_lock(glc, enable_latch);
+	ret = gpio_direction_output(gpio, value);
+	gpio_latch_unlock(glc, disable_latch);
+
+	return ret;
+}
+
+static int gpio_latch_probe(struct platform_device *pdev)
+{
+	struct gpio_latch_chip *glc;
+	struct gpio_latch_platform_data *pdata;
+	struct gpio_chip *gc;
+	int size;
+	int ret;
+	int i;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata)
+		return -EINVAL;
+
+	if (pdata->le_gpio_index >= pdata->num_gpios ||
+	    !pdata->num_gpios ||
+	    !pdata->gpios)
+		return -EINVAL;
+
+	for (i = 0; i < pdata->num_gpios; i++) {
+		int gpio = pdata->gpios[i];
+
+		ret = devm_gpio_request(&pdev->dev, gpio,
+					GPIO_LATCH_DRIVER_NAME);
+		if (ret)
+			return ret;
+	}
+
+	glc = devm_kzalloc(&pdev->dev, sizeof(*glc), GFP_KERNEL);
+	if (!glc)
+		return -ENOMEM;
+
+	mutex_init(&glc->mutex);
+	mutex_init(&glc->latch_mutex);
+
+	size = pdata->num_gpios * sizeof(glc->gpios[0]);
+	glc->gpios = devm_kzalloc(&pdev->dev, size , GFP_KERNEL);
+	if (!glc->gpios)
+		return -ENOMEM;
+
+	memcpy(glc->gpios, pdata->gpios, size);
+
+	glc->le_gpio = glc->gpios[pdata->le_gpio_index];
+	glc->le_active_low = pdata->le_active_low;
+
+	gc = &glc->gc;
+
+	gc->label = GPIO_LATCH_DRIVER_NAME;
+	gc->base = pdata->base;
+	gc->can_sleep = true;
+	gc->ngpio = pdata->num_gpios;
+	gc->get = gpio_latch_get;
+	gc->set = gpio_latch_set;
+	gc->direction_input = gpio_latch_direction_input,
+	gc->direction_output = gpio_latch_direction_output;
+
+	platform_set_drvdata(pdev, glc);
+
+	ret = gpiochip_add(&glc->gc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int gpio_latch_remove(struct platform_device *pdev)
+{
+	struct gpio_latch_chip *glc = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&glc->gc);
+	return 0;
+}
+
+
+static struct platform_driver gpio_latch_driver = {
+	.probe = gpio_latch_probe,
+	.remove = gpio_latch_remove,
+	.driver = {
+		.name = GPIO_LATCH_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init gpio_latch_init(void)
+{
+	return platform_driver_register(&gpio_latch_driver);
+}
+
+postcore_initcall(gpio_latch_init);
+
+MODULE_DESCRIPTION("GPIO latch driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" GPIO_LATCH_DRIVER_NAME);
diff --git a/target/linux/ar71xx/files/drivers/gpio/gpio-nxp-74hc153.c b/target/linux/ar71xx/files/drivers/gpio/gpio-nxp-74hc153.c
new file mode 100644
index 0000000000..8c01efe4a0
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/gpio/gpio-nxp-74hc153.c
@@ -0,0 +1,251 @@
+/*
+ *  NXP 74HC153 - Dual 4-input multiplexer GPIO driver
+ *
+ *  Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/nxp_74hc153.h>
+
+#define NXP_74HC153_NUM_GPIOS	8
+#define NXP_74HC153_S0_MASK	0x1
+#define NXP_74HC153_S1_MASK	0x2
+#define NXP_74HC153_BANK_MASK	0x4
+
+struct nxp_74hc153_chip {
+	struct device		*parent;
+	struct gpio_chip	gpio_chip;
+	struct mutex		lock;
+};
+
+static struct nxp_74hc153_chip *gpio_to_nxp(struct gpio_chip *gc)
+{
+	return container_of(gc, struct nxp_74hc153_chip, gpio_chip);
+}
+
+static int nxp_74hc153_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+	return 0;
+}
+
+static int nxp_74hc153_direction_output(struct gpio_chip *gc,
+					unsigned offset, int val)
+{
+	return -EINVAL;
+}
+
+static int nxp_74hc153_get_value(struct gpio_chip *gc, unsigned offset)
+{
+	struct nxp_74hc153_chip *nxp;
+	struct nxp_74hc153_platform_data *pdata;
+	unsigned s0;
+	unsigned s1;
+	unsigned pin;
+	int ret;
+
+	nxp = gpio_to_nxp(gc);
+	pdata = nxp->parent->platform_data;
+
+	s0 = !!(offset & NXP_74HC153_S0_MASK);
+	s1 = !!(offset & NXP_74HC153_S1_MASK);
+	pin = (offset & NXP_74HC153_BANK_MASK) ? pdata->gpio_pin_2y
+					       : pdata->gpio_pin_1y;
+
+	mutex_lock(&nxp->lock);
+	gpio_set_value(pdata->gpio_pin_s0, s0);
+	gpio_set_value(pdata->gpio_pin_s1, s1);
+	ret = gpio_get_value(pin);
+	mutex_unlock(&nxp->lock);
+
+	return ret;
+}
+
+static void nxp_74hc153_set_value(struct gpio_chip *gc,
+				  unsigned offset, int val)
+{
+	/* not supported */
+}
+
+static int nxp_74hc153_probe(struct platform_device *pdev)
+{
+	struct nxp_74hc153_platform_data *pdata;
+	struct nxp_74hc153_chip *nxp;
+	struct gpio_chip *gc;
+	int err;
+
+	pdata = pdev->dev.platform_data;
+	if (pdata == NULL) {
+		dev_dbg(&pdev->dev, "no platform data specified\n");
+		return -EINVAL;
+	}
+
+	nxp = kzalloc(sizeof(struct nxp_74hc153_chip), GFP_KERNEL);
+	if (nxp == NULL) {
+		dev_err(&pdev->dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	err = gpio_request(pdata->gpio_pin_s0, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			pdata->gpio_pin_s0, err);
+		goto err_free_nxp;
+	}
+
+	err = gpio_request(pdata->gpio_pin_s1, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			pdata->gpio_pin_s1, err);
+		goto err_free_s0;
+	}
+
+	err = gpio_request(pdata->gpio_pin_1y, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			pdata->gpio_pin_1y, err);
+		goto err_free_s1;
+	}
+
+	err = gpio_request(pdata->gpio_pin_2y, dev_name(&pdev->dev));
+	if (err) {
+		dev_err(&pdev->dev, "unable to claim gpio %u, err=%d\n",
+			pdata->gpio_pin_2y, err);
+		goto err_free_1y;
+	}
+
+	err = gpio_direction_output(pdata->gpio_pin_s0, 0);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			pdata->gpio_pin_s0, err);
+		goto err_free_2y;
+	}
+
+	err = gpio_direction_output(pdata->gpio_pin_s1, 0);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			pdata->gpio_pin_s1, err);
+		goto err_free_2y;
+	}
+
+	err = gpio_direction_input(pdata->gpio_pin_1y);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			pdata->gpio_pin_1y, err);
+		goto err_free_2y;
+	}
+
+	err = gpio_direction_input(pdata->gpio_pin_2y);
+	if (err) {
+		dev_err(&pdev->dev,
+			"unable to set direction of gpio %u, err=%d\n",
+			pdata->gpio_pin_2y, err);
+		goto err_free_2y;
+	}
+
+	nxp->parent = &pdev->dev;
+	mutex_init(&nxp->lock);
+
+	gc = &nxp->gpio_chip;
+
+	gc->direction_input  = nxp_74hc153_direction_input;
+	gc->direction_output = nxp_74hc153_direction_output;
+	gc->get = nxp_74hc153_get_value;
+	gc->set = nxp_74hc153_set_value;
+	gc->can_sleep = 1;
+
+	gc->base = pdata->gpio_base;
+	gc->ngpio = NXP_74HC153_NUM_GPIOS;
+	gc->label = dev_name(nxp->parent);
+	gc->dev = nxp->parent;
+	gc->owner = THIS_MODULE;
+
+	err = gpiochip_add(&nxp->gpio_chip);
+	if (err) {
+		dev_err(&pdev->dev, "unable to add gpio chip, err=%d\n", err);
+		goto err_free_2y;
+	}
+
+	platform_set_drvdata(pdev, nxp);
+	return 0;
+
+err_free_2y:
+	gpio_free(pdata->gpio_pin_2y);
+err_free_1y:
+	gpio_free(pdata->gpio_pin_1y);
+err_free_s1:
+	gpio_free(pdata->gpio_pin_s1);
+err_free_s0:
+	gpio_free(pdata->gpio_pin_s0);
+err_free_nxp:
+	kfree(nxp);
+	return err;
+}
+
+static int nxp_74hc153_remove(struct platform_device *pdev)
+{
+	struct nxp_74hc153_chip *nxp = platform_get_drvdata(pdev);
+	struct nxp_74hc153_platform_data *pdata = pdev->dev.platform_data;
+
+	if (nxp) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
+		int err;
+
+		err = gpiochip_remove(&nxp->gpio_chip);
+		if (err) {
+			dev_err(&pdev->dev,
+				"unable to remove gpio chip, err=%d\n",
+				err);
+			return err;
+		}
+#else
+		gpiochip_remove(&nxp->gpio_chip);
+#endif
+		gpio_free(pdata->gpio_pin_2y);
+		gpio_free(pdata->gpio_pin_1y);
+		gpio_free(pdata->gpio_pin_s1);
+		gpio_free(pdata->gpio_pin_s0);
+
+		kfree(nxp);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return 0;
+}
+
+static struct platform_driver nxp_74hc153_driver = {
+	.probe		= nxp_74hc153_probe,
+	.remove		= nxp_74hc153_remove,
+	.driver = {
+		.name	= NXP_74HC153_DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init nxp_74hc153_init(void)
+{
+	return platform_driver_register(&nxp_74hc153_driver);
+}
+subsys_initcall(nxp_74hc153_init);
+
+static void __exit nxp_74hc153_exit(void)
+{
+	platform_driver_unregister(&nxp_74hc153_driver);
+}
+module_exit(nxp_74hc153_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("GPIO expander driver for NXP 74HC153");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" NXP_74HC153_DRIVER_NAME);
diff --git a/target/linux/ar71xx/files/drivers/leds/leds-nu801.c b/target/linux/ar71xx/files/drivers/leds/leds-nu801.c
new file mode 100644
index 0000000000..f04df61c04
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/leds/leds-nu801.c
@@ -0,0 +1,396 @@
+/*
+ * LED driver for NU801
+ *
+ * Kevin Paul Herbert
+ * Copyright (c) 2012, Meraki, Inc.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/leds-nu801.h>
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#define MAX_NAME_LENGTH 24
+#define NUM_COLORS 3
+
+static const char * const led_nu801_colors[] = { "blue", "green", "red" };
+
+struct led_nu801_led_data {
+	struct led_classdev cdev;
+	struct led_nu801_data *controller;
+	enum led_brightness level;
+	char name[MAX_NAME_LENGTH];
+};
+
+struct led_nu801_data {
+	unsigned cki;
+	unsigned sdi;
+	int lei;
+	struct delayed_work work;
+	struct led_nu801_led_data *led_chain;
+	int num_leds;
+	const char *device_name;
+	const char *name;
+	u32 ndelay;
+	atomic_t pending;
+};
+
+static void led_nu801_work(struct work_struct *work)
+{
+	struct led_nu801_data	*controller =
+		container_of(work, struct led_nu801_data, work.work);
+	struct led_nu801_led_data *led;
+	u16 bit;
+	u16 brightness;
+	int index;
+
+	for (index = 0; index < controller->num_leds; index++) {
+		led = &controller->led_chain[index];
+		brightness = led->level << 8; /* To do: gamma correction */
+		for (bit = 0x8000; bit; bit = bit >> 1) {
+			gpio_set_value(controller->sdi,
+				       (brightness & bit) != 0);
+			gpio_set_value(controller->cki, 1);
+			if (unlikely(((index == (controller->num_leds - 1)) &&
+				      (bit == 1) &&
+				      (controller->lei < 0)))) {
+				udelay(600);
+			} else {
+				ndelay(controller->ndelay);
+			}
+			gpio_set_value(controller->cki, 0);
+			ndelay(controller->ndelay);
+		}
+	}
+	if (controller->lei >= 0) {
+		gpio_set_value(controller->lei, 1);
+		ndelay(controller->ndelay);
+		gpio_set_value(controller->lei, 0);
+	}
+	atomic_set(&controller->pending, 1);
+}
+
+static void led_nu801_set(struct led_classdev *led_cdev,
+			  enum led_brightness value)
+{
+	struct led_nu801_led_data *led_dat =
+		container_of(led_cdev, struct led_nu801_led_data, cdev);
+	struct led_nu801_data *controller = led_dat->controller;
+
+	if (led_dat->level != value) {
+		led_dat->level = value;
+		if (atomic_dec_and_test(&controller->pending))
+			schedule_delayed_work(&led_dat->controller->work,
+					      (HZ/1000) + 1);
+	}
+}
+
+static int __init led_nu801_create(struct led_nu801_data *controller,
+				    struct device *parent,
+				    int index,
+				    enum led_brightness brightness,
+#ifdef CONFIG_LEDS_TRIGGERS
+				    const char *default_trigger,
+#endif
+				    const char *color)
+{
+	struct led_nu801_led_data *led = &controller->led_chain[index];
+	int ret;
+
+	scnprintf(led->name, sizeof(led->name), "%s:%s:%s%d",
+		  controller->device_name, color, controller->name,
+		  (controller->num_leds - (index + 1)) / NUM_COLORS);
+	led->cdev.name = led->name;
+	led->cdev.brightness_set = led_nu801_set;
+#ifdef CONFIG_LEDS_TRIGGERS
+	led->cdev.default_trigger = default_trigger;
+#endif
+	led->level = brightness;
+	led->controller = controller;
+	ret = led_classdev_register(parent, &led->cdev);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	kfree(led);
+	return ret;
+}
+
+static int __init
+led_nu801_create_chain(const struct led_nu801_template *template,
+			struct led_nu801_data *controller,
+			struct device *parent)
+{
+	int ret;
+	int index;
+
+	controller->cki = template->cki;
+	controller->sdi = template->sdi;
+	controller->lei = template->lei;
+	controller->num_leds = template->num_leds * 3;
+	controller->device_name = template->device_name;
+	controller->name = template->name;
+	controller->ndelay = template->ndelay;
+	atomic_set(&controller->pending, 1);
+
+	controller->led_chain = kzalloc(sizeof(struct led_nu801_led_data) *
+					controller->num_leds, GFP_KERNEL);
+
+	if (!controller->led_chain)
+		return -ENOMEM;
+
+	ret = gpio_request(controller->cki, template->name);
+	if (ret < 0)
+		goto err_free_chain;
+
+	ret = gpio_request(controller->sdi, template->name);
+	if (ret < 0)
+		goto err_ret_cki;
+
+	if (controller->lei >= 0) {
+		ret = gpio_request(controller->lei, template->name);
+		if (ret < 0)
+			goto err_ret_sdi;
+		ret = gpio_direction_output(controller->lei, 0);
+		if (ret < 0)
+			goto err_ret_lei;
+	}
+
+	ret = gpio_direction_output(controller->cki, 0);
+	if (ret < 0)
+		goto err_ret_lei;
+
+	ret = gpio_direction_output(controller->sdi, 0);
+	if (ret < 0)
+		goto err_ret_lei;
+
+	for (index = 0; index < controller->num_leds; index++) {
+		ret = led_nu801_create(controller, parent, index,
+			template->init_brightness
+			[index % NUM_COLORS],
+#ifdef CONFIG_LEDS_TRIGGERS
+			template->default_trigger,
+#endif
+			template->led_colors[index % NUM_COLORS] ?
+			template->led_colors[index % NUM_COLORS] :
+			led_nu801_colors[index % NUM_COLORS]);
+		if (ret < 0)
+			goto err_ret_sdi;
+	}
+
+	INIT_DELAYED_WORK(&controller->work, led_nu801_work);
+	schedule_delayed_work(&controller->work, 0);
+
+	return 0;
+
+err_ret_lei:
+	if (controller->lei >= 0)
+		gpio_free(controller->lei);
+err_ret_sdi:
+	gpio_free(controller->sdi);
+err_ret_cki:
+	gpio_free(controller->cki);
+err_free_chain:
+	kfree(controller->led_chain);
+
+	return ret;
+}
+
+static void led_nu801_delete_chain(struct led_nu801_data *controller)
+{
+	struct led_nu801_led_data *led_chain;
+	struct led_nu801_led_data *led;
+	int index;
+	int num_leds;
+
+	led_chain = controller->led_chain;
+	controller->led_chain = 0;
+	num_leds = controller->num_leds;
+	controller->num_leds = 0;
+	cancel_delayed_work_sync(&controller->work);
+
+	for (index = 0; index < num_leds; index++) {
+		led = &led_chain[index];
+		led_classdev_unregister(&led->cdev);
+	}
+
+	gpio_free(controller->cki);
+	gpio_free(controller->sdi);
+	if (controller->lei >= 0)
+		gpio_free(controller->lei);
+
+	kfree(led_chain);
+}
+
+static struct led_nu801_data * __init
+leds_nu801_create_of(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node, *child;
+	struct led_nu801_data *controllers;
+	int count = 0, ret;
+	int i = 0;
+
+	for_each_child_of_node(np, child)
+		count++;
+	if (!count)
+		return NULL;
+
+	controllers = kzalloc(sizeof(struct led_nu801_data) * count,
+			      GFP_KERNEL);
+	if (!controllers)
+		return NULL;
+
+	for_each_child_of_node(np, child) {
+		const char *state;
+		struct led_nu801_template template = {};
+		struct device_node *colors;
+		int jj;
+
+		template.cki = of_get_named_gpio_flags(child, "cki", 0, NULL);
+		template.sdi = of_get_named_gpio_flags(child, "sdi", 0, NULL);
+		if (of_find_property(child, "lei", NULL)) {
+			template.lei = of_get_named_gpio_flags(child, "lei",
+							       0, NULL);
+		} else {
+			template.lei = -1;
+		}
+		of_property_read_u32(child, "ndelay", &template.ndelay);
+		of_property_read_u32(child, "num_leds", &template.num_leds);
+		template.name = of_get_property(child, "label", NULL) ? :
+			child->name;
+		template.default_trigger = of_get_property(child,
+			"default-trigger", NULL);
+
+		jj = 0;
+		for_each_child_of_node(child, colors) {
+			template.led_colors[jj] = of_get_property(colors,
+				 "label", NULL);
+			state = of_get_property(colors, "state", NULL);
+			if (!strncmp(state, "off", 3))
+				template.init_brightness[jj] = LED_OFF;
+			else if (!strncmp(state, "half", 4))
+				template.init_brightness[jj] = LED_HALF;
+			else if (!strncmp(state, "full", 4))
+				template.init_brightness[jj] = LED_FULL;
+			jj++;
+		}
+
+		ret = led_nu801_create_chain(&template,
+					     &controllers[i],
+					     &pdev->dev);
+		if (ret < 0)
+			goto err;
+		i++;
+	}
+
+	return controllers;
+
+err:
+	for (i = i - 1; i >= 0; i--)
+		led_nu801_delete_chain(&controllers[i]);
+	kfree(controllers);
+	return NULL;
+}
+
+static int __init led_nu801_probe(struct platform_device *pdev)
+{
+	struct led_nu801_platform_data *pdata = pdev->dev.platform_data;
+	struct led_nu801_data *controllers;
+	int i, ret = 0;
+
+	if (!(pdata && pdata->num_controllers)) {
+		controllers = leds_nu801_create_of(pdev);
+		if (!controllers)
+			return -ENODEV;
+	}
+
+	controllers = kzalloc(sizeof(struct led_nu801_data) *
+			      pdata->num_controllers, GFP_KERNEL);
+	if (!controllers)
+		return -ENOMEM;
+
+	for (i = 0; i < pdata->num_controllers; i++) {
+		ret = led_nu801_create_chain(&pdata->template[i],
+					      &controllers[i],
+					      &pdev->dev);
+		if (ret < 0)
+			goto err;
+	}
+
+	platform_set_drvdata(pdev, controllers);
+
+	return 0;
+
+err:
+	for (i = i - 1; i >= 0; i--)
+		led_nu801_delete_chain(&controllers[i]);
+
+	kfree(controllers);
+
+	return ret;
+}
+
+static int led_nu801_remove(struct platform_device *pdev)
+{
+	int i;
+	struct led_nu801_platform_data *pdata = pdev->dev.platform_data;
+	struct led_nu801_data *controllers;
+
+	controllers = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_controllers; i++)
+		led_nu801_delete_chain(&controllers[i]);
+
+	kfree(controllers);
+
+	return 0;
+}
+
+static const struct of_device_id of_numen_leds_match[] = {
+	{ .compatible = "numen,leds-nu801", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_pwm_leds_match);
+
+static struct platform_driver led_nu801_driver = {
+	.probe		= led_nu801_probe,
+	.remove		= led_nu801_remove,
+	.driver		= {
+		.name	= "leds-nu801",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_numen_leds_match,
+	},
+};
+
+static int __init led_nu801_init(void)
+{
+	return platform_driver_register(&led_nu801_driver);
+}
+
+static void __exit led_nu801_exit(void)
+{
+	platform_driver_unregister(&led_nu801_driver);
+}
+
+module_init(led_nu801_init);
+module_exit(led_nu801_exit);
+
+MODULE_AUTHOR("Kevin Paul Herbert <kph@meraki.net>");
+MODULE_DESCRIPTION("NU801 LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:leds-nu801");
diff --git a/target/linux/ar71xx/files/drivers/leds/leds-rb750.c b/target/linux/ar71xx/files/drivers/leds/leds-rb750.c
new file mode 100644
index 0000000000..79e98b4882
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/leds/leds-rb750.c
@@ -0,0 +1,144 @@
+/*
+ * LED driver for the RouterBOARD 750
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include <asm/mach-ath79/mach-rb750.h>
+
+#define DRV_NAME	"leds-rb750"
+
+struct rb750_led_dev {
+	struct led_classdev	cdev;
+	u32			mask;
+	int			active_low;
+	void			(*latch_change)(u32 clear, u32 set);
+};
+
+struct rb750_led_drvdata {
+	struct rb750_led_dev	*led_devs;
+	int			num_leds;
+};
+
+static inline struct rb750_led_dev *to_rbled(struct led_classdev *led_cdev)
+{
+	return (struct rb750_led_dev *)container_of(led_cdev,
+		struct rb750_led_dev, cdev);
+}
+
+static void rb750_led_brightness_set(struct led_classdev *led_cdev,
+				     enum led_brightness value)
+{
+	struct rb750_led_dev *rbled = to_rbled(led_cdev);
+	int level;
+
+	level = (value == LED_OFF) ? 0 : 1;
+	level ^= rbled->active_low;
+
+	if (level)
+		rbled->latch_change(0, rbled->mask);
+	else
+		rbled->latch_change(rbled->mask, 0);
+}
+
+static int rb750_led_probe(struct platform_device *pdev)
+{
+	struct rb750_led_platform_data *pdata;
+	struct rb750_led_drvdata *drvdata;
+	int ret = 0;
+	int i;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	drvdata = kzalloc(sizeof(struct rb750_led_drvdata) +
+			  sizeof(struct rb750_led_dev) * pdata->num_leds,
+			  GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->num_leds = pdata->num_leds;
+	drvdata->led_devs = (struct rb750_led_dev *) &drvdata[1];
+
+	for (i = 0; i < drvdata->num_leds; i++) {
+		struct rb750_led_dev *rbled = &drvdata->led_devs[i];
+		struct rb750_led_data *led_data = &pdata->leds[i];
+
+		rbled->cdev.name = led_data->name;
+		rbled->cdev.default_trigger = led_data->default_trigger;
+		rbled->cdev.brightness_set = rb750_led_brightness_set;
+		rbled->cdev.brightness = LED_OFF;
+
+		rbled->mask = led_data->mask;
+		rbled->active_low = !!led_data->active_low;
+		rbled->latch_change = pdata->latch_change;
+
+		ret = led_classdev_register(&pdev->dev, &rbled->cdev);
+		if (ret)
+			goto err;
+	}
+
+	platform_set_drvdata(pdev, drvdata);
+	return 0;
+
+err:
+	for (i = i - 1; i >= 0; i--)
+		led_classdev_unregister(&drvdata->led_devs[i].cdev);
+
+	kfree(drvdata);
+	return ret;
+}
+
+static int rb750_led_remove(struct platform_device *pdev)
+{
+	struct rb750_led_drvdata *drvdata;
+	int i;
+
+	drvdata = platform_get_drvdata(pdev);
+	for (i = 0; i < drvdata->num_leds; i++)
+		led_classdev_unregister(&drvdata->led_devs[i].cdev);
+
+	kfree(drvdata);
+	return 0;
+}
+
+static struct platform_driver rb750_led_driver = {
+	.probe		= rb750_led_probe,
+	.remove		= rb750_led_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+MODULE_ALIAS("platform:leds-rb750");
+
+static int __init rb750_led_init(void)
+{
+	return platform_driver_register(&rb750_led_driver);
+}
+
+static void __exit rb750_led_exit(void)
+{
+	platform_driver_unregister(&rb750_led_driver);
+}
+
+module_init(rb750_led_init);
+module_exit(rb750_led_exit);
+
+MODULE_DESCRIPTION(DRV_NAME);
+MODULE_DESCRIPTION("LED driver for the RouterBOARD 750");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/leds/leds-wndr3700-usb.c b/target/linux/ar71xx/files/drivers/leds/leds-wndr3700-usb.c
new file mode 100644
index 0000000000..6425b055da
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/leds/leds-wndr3700-usb.c
@@ -0,0 +1,76 @@
+/*
+ *  USB LED driver for the NETGEAR WNDR3700
+ *
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#define DRIVER_NAME	"wndr3700-led-usb"
+
+static void wndr3700_usb_led_set(struct led_classdev *cdev,
+				 enum led_brightness brightness)
+{
+	if (brightness)
+		ath79_device_reset_clear(AR71XX_RESET_GE1_PHY);
+	else
+		ath79_device_reset_set(AR71XX_RESET_GE1_PHY);
+}
+
+static enum led_brightness wndr3700_usb_led_get(struct led_classdev *cdev)
+{
+	return ath79_device_reset_get(AR71XX_RESET_GE1_PHY) ? LED_OFF : LED_FULL;
+}
+
+static struct led_classdev wndr3700_usb_led = {
+	.name = "netgear:green:usb",
+	.brightness_set = wndr3700_usb_led_set,
+	.brightness_get = wndr3700_usb_led_get,
+};
+
+static int wndr3700_usb_led_probe(struct platform_device *pdev)
+{
+	return led_classdev_register(&pdev->dev, &wndr3700_usb_led);
+}
+
+static int wndr3700_usb_led_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&wndr3700_usb_led);
+	return 0;
+}
+
+static struct platform_driver wndr3700_usb_led_driver = {
+	.probe = wndr3700_usb_led_probe,
+	.remove = wndr3700_usb_led_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init wndr3700_usb_led_init(void)
+{
+	return platform_driver_register(&wndr3700_usb_led_driver);
+}
+
+static void __exit wndr3700_usb_led_exit(void)
+{
+	platform_driver_unregister(&wndr3700_usb_led_driver);
+}
+
+module_init(wndr3700_usb_led_init);
+module_exit(wndr3700_usb_led_exit);
+
+MODULE_DESCRIPTION("USB LED driver for the NETGEAR WNDR3700");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/target/linux/ar71xx/files/drivers/mtd/cybertan_part.c b/target/linux/ar71xx/files/drivers/mtd/cybertan_part.c
new file mode 100644
index 0000000000..391411f8de
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/mtd/cybertan_part.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009 Christian Daniel <cd@maintech.de>
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * TRX flash partition table.
+ * Based on ar7 map by Felix Fietkau <nbd@nbd.name>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+struct cybertan_header {
+	char	magic[4];
+	u8	res1[4];
+	char	fw_date[3];
+	char	fw_ver[3];
+	char	id[4];
+	char	hw_ver;
+	char	unused;
+	u8	flags[2];
+	u8	res2[10];
+};
+
+#define TRX_PARTS	6
+#define TRX_MAGIC	0x30524448
+#define TRX_MAX_OFFSET	3
+
+struct trx_header {
+	uint32_t magic;           /* "HDR0" */
+	uint32_t len;             /* Length of file including header */
+	uint32_t crc32;           /* 32-bit CRC from flag_version to end of file */
+	uint32_t flag_version;    /* 0:15 flags, 16:31 version */
+	uint32_t offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
+};
+
+#define IH_MAGIC	0x27051956	/* Image Magic Number */
+#define IH_NMLEN	32		/* Image Name Length */
+
+struct uimage_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number */
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum */
+	uint32_t	ih_time;	/* Image Creation Timestamp */
+	uint32_t	ih_size;	/* Image Data Size */
+	uint32_t	ih_load;	/* Data» Load  Address */
+	uint32_t	ih_ep;		/* Entry Point Address */
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum */
+	uint8_t		ih_os;		/* Operating System */
+	uint8_t		ih_arch;	/* CPU architecture */
+	uint8_t		ih_type;	/* Image Type */
+	uint8_t		ih_comp;	/* Compression Type */
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name */
+};
+
+struct firmware_header {
+	struct cybertan_header	cybertan;
+	struct trx_header	trx;
+	struct uimage_header	uimage;
+} __packed;
+
+#define UBOOT_LEN	0x40000
+#define ART_LEN		0x10000
+#define NVRAM_LEN	0x10000
+
+static int cybertan_parse_partitions(struct mtd_info *master,
+				     struct mtd_partition **pparts,
+				     struct mtd_part_parser_data *data)
+{
+	struct firmware_header *header;
+	struct trx_header *theader;
+	struct uimage_header *uheader;
+	struct mtd_partition *trx_parts;
+	size_t retlen;
+	unsigned int kernel_len;
+	unsigned int uboot_len;
+	unsigned int nvram_len;
+	unsigned int art_len;
+	int ret;
+
+	uboot_len = max_t(unsigned int, master->erasesize, UBOOT_LEN);
+	nvram_len = max_t(unsigned int, master->erasesize, NVRAM_LEN);
+	art_len = max_t(unsigned int, master->erasesize, ART_LEN);
+
+	trx_parts = kzalloc(TRX_PARTS * sizeof(struct mtd_partition),
+			    GFP_KERNEL);
+	if (!trx_parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	header = vmalloc(sizeof(*header));
+	if (!header) {
+		return -ENOMEM;
+		goto free_parts;
+	}
+
+	ret = mtd_read(master, uboot_len, sizeof(*header),
+		       &retlen, (void *) header);
+	if (ret)
+		goto free_hdr;
+
+	if (retlen != sizeof(*header)) {
+		ret = -EIO;
+		goto free_hdr;
+	}
+
+	theader = &header->trx;
+	if (le32_to_cpu(theader->magic) != TRX_MAGIC) {
+		printk(KERN_NOTICE "%s: no TRX header found\n", master->name);
+		goto free_hdr;
+	}
+
+	uheader = &header->uimage;
+	if (uheader->ih_magic != IH_MAGIC) {
+		printk(KERN_NOTICE "%s: no uImage found\n", master->name);
+		goto free_hdr;
+	}
+
+	kernel_len = le32_to_cpu(theader->offsets[1]) +
+		sizeof(struct cybertan_header);
+
+	trx_parts[0].name = "u-boot";
+	trx_parts[0].offset = 0;
+	trx_parts[0].size = uboot_len;
+	trx_parts[0].mask_flags = MTD_WRITEABLE;
+
+	trx_parts[1].name = "kernel";
+	trx_parts[1].offset = trx_parts[0].offset + trx_parts[0].size;
+	trx_parts[1].size = kernel_len;
+	trx_parts[1].mask_flags = 0;
+
+	trx_parts[2].name = "rootfs";
+	trx_parts[2].offset = trx_parts[1].offset + trx_parts[1].size;
+	trx_parts[2].size = master->size - uboot_len - nvram_len - art_len -
+		trx_parts[1].size;
+	trx_parts[2].mask_flags = 0;
+
+	trx_parts[3].name = "nvram";
+	trx_parts[3].offset = master->size - nvram_len - art_len;
+	trx_parts[3].size = nvram_len;
+	trx_parts[3].mask_flags = MTD_WRITEABLE;
+
+	trx_parts[4].name = "art";
+	trx_parts[4].offset = master->size - art_len;
+	trx_parts[4].size = art_len;
+	trx_parts[4].mask_flags = MTD_WRITEABLE;
+
+	trx_parts[5].name = "firmware";
+	trx_parts[5].offset = uboot_len;
+	trx_parts[5].size = master->size - uboot_len - nvram_len - art_len;
+	trx_parts[5].mask_flags = 0;
+
+	vfree(header);
+
+	*pparts = trx_parts;
+	return TRX_PARTS;
+
+free_hdr:
+	vfree(header);
+free_parts:
+	kfree(trx_parts);
+out:
+	return ret;
+}
+
+static struct mtd_part_parser cybertan_parser = {
+	.owner		= THIS_MODULE,
+	.parse_fn	= cybertan_parse_partitions,
+	.name		= "cybertan",
+};
+
+static int __init cybertan_parser_init(void)
+{
+	register_mtd_parser(&cybertan_parser);
+
+	return 0;
+}
+
+module_init(cybertan_parser_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Daniel <cd@maintech.de>");
diff --git a/target/linux/ar71xx/files/drivers/mtd/nand/ar934x_nfc.c b/target/linux/ar71xx/files/drivers/mtd/nand/ar934x_nfc.c
new file mode 100644
index 0000000000..a47fc0468e
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/mtd/nand/ar934x_nfc.c
@@ -0,0 +1,1502 @@
+/*
+ * Driver for the built-in NAND controller of the Atheros AR934x SoCs
+ *
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <linux/platform/ar934x_nfc.h>
+
+#define AR934X_NFC_REG_CMD		0x00
+#define AR934X_NFC_REG_CTRL		0x04
+#define AR934X_NFC_REG_STATUS		0x08
+#define AR934X_NFC_REG_INT_MASK		0x0c
+#define AR934X_NFC_REG_INT_STATUS	0x10
+#define AR934X_NFC_REG_ECC_CTRL		0x14
+#define AR934X_NFC_REG_ECC_OFFSET	0x18
+#define AR934X_NFC_REG_ADDR0_0		0x1c
+#define AR934X_NFC_REG_ADDR0_1		0x24
+#define AR934X_NFC_REG_ADDR1_0		0x20
+#define AR934X_NFC_REG_ADDR1_1		0x28
+#define AR934X_NFC_REG_SPARE_SIZE	0x30
+#define AR934X_NFC_REG_PROTECT		0x38
+#define AR934X_NFC_REG_LOOKUP_EN	0x40
+#define AR934X_NFC_REG_LOOKUP(_x)	(0x44 + (_i) * 4)
+#define AR934X_NFC_REG_DMA_ADDR		0x64
+#define AR934X_NFC_REG_DMA_COUNT	0x68
+#define AR934X_NFC_REG_DMA_CTRL		0x6c
+#define AR934X_NFC_REG_MEM_CTRL		0x80
+#define AR934X_NFC_REG_DATA_SIZE	0x84
+#define AR934X_NFC_REG_READ_STATUS	0x88
+#define AR934X_NFC_REG_TIME_SEQ		0x8c
+#define AR934X_NFC_REG_TIMINGS_ASYN	0x90
+#define AR934X_NFC_REG_TIMINGS_SYN	0x94
+#define AR934X_NFC_REG_FIFO_DATA	0x98
+#define AR934X_NFC_REG_TIME_MODE	0x9c
+#define AR934X_NFC_REG_DMA_ADDR_OFFS	0xa0
+#define AR934X_NFC_REG_FIFO_INIT	0xb0
+#define AR934X_NFC_REG_GEN_SEQ_CTRL	0xb4
+
+#define AR934X_NFC_CMD_CMD_SEQ_S		0
+#define AR934X_NFC_CMD_CMD_SEQ_M		0x3f
+#define   AR934X_NFC_CMD_SEQ_1C			0x00
+#define   AR934X_NFC_CMD_SEQ_ERASE		0x0e
+#define   AR934X_NFC_CMD_SEQ_12			0x0c
+#define   AR934X_NFC_CMD_SEQ_1C1AXR		0x21
+#define   AR934X_NFC_CMD_SEQ_S			0x24
+#define   AR934X_NFC_CMD_SEQ_1C3AXR		0x27
+#define   AR934X_NFC_CMD_SEQ_1C5A1CXR		0x2a
+#define   AR934X_NFC_CMD_SEQ_18			0x32
+#define AR934X_NFC_CMD_INPUT_SEL_SIU		0
+#define AR934X_NFC_CMD_INPUT_SEL_DMA		BIT(6)
+#define AR934X_NFC_CMD_ADDR_SEL_0		0
+#define AR934X_NFC_CMD_ADDR_SEL_1		BIT(7)
+#define AR934X_NFC_CMD_CMD0_S			8
+#define AR934X_NFC_CMD_CMD0_M			0xff
+#define AR934X_NFC_CMD_CMD1_S			16
+#define AR934X_NFC_CMD_CMD1_M			0xff
+#define AR934X_NFC_CMD_CMD2_S			24
+#define AR934X_NFC_CMD_CMD2_M			0xff
+
+#define AR934X_NFC_CTRL_ADDR_CYCLE0_M		0x7
+#define AR934X_NFC_CTRL_ADDR_CYCLE0_S		0
+#define AR934X_NFC_CTRL_SPARE_EN		BIT(3)
+#define AR934X_NFC_CTRL_INT_EN			BIT(4)
+#define AR934X_NFC_CTRL_ECC_EN			BIT(5)
+#define AR934X_NFC_CTRL_BLOCK_SIZE_S		6
+#define AR934X_NFC_CTRL_BLOCK_SIZE_M		0x3
+#define   AR934X_NFC_CTRL_BLOCK_SIZE_32		0
+#define   AR934X_NFC_CTRL_BLOCK_SIZE_64		1
+#define   AR934X_NFC_CTRL_BLOCK_SIZE_128	2
+#define   AR934X_NFC_CTRL_BLOCK_SIZE_256	3
+#define AR934X_NFC_CTRL_PAGE_SIZE_S		8
+#define AR934X_NFC_CTRL_PAGE_SIZE_M		0x7
+#define   AR934X_NFC_CTRL_PAGE_SIZE_256		0
+#define   AR934X_NFC_CTRL_PAGE_SIZE_512		1
+#define   AR934X_NFC_CTRL_PAGE_SIZE_1024	2
+#define   AR934X_NFC_CTRL_PAGE_SIZE_2048	3
+#define   AR934X_NFC_CTRL_PAGE_SIZE_4096	4
+#define   AR934X_NFC_CTRL_PAGE_SIZE_8192	5
+#define   AR934X_NFC_CTRL_PAGE_SIZE_16384	6
+#define AR934X_NFC_CTRL_CUSTOM_SIZE_EN		BIT(11)
+#define AR934X_NFC_CTRL_IO_WIDTH_8BITS		0
+#define AR934X_NFC_CTRL_IO_WIDTH_16BITS		BIT(12)
+#define AR934X_NFC_CTRL_LOOKUP_EN		BIT(13)
+#define AR934X_NFC_CTRL_PROT_EN			BIT(14)
+#define AR934X_NFC_CTRL_WORK_MODE_ASYNC		0
+#define AR934X_NFC_CTRL_WORK_MODE_SYNC		BIT(15)
+#define AR934X_NFC_CTRL_ADDR0_AUTO_INC		BIT(16)
+#define AR934X_NFC_CTRL_ADDR1_AUTO_INC		BIT(17)
+#define AR934X_NFC_CTRL_ADDR_CYCLE1_M		0x7
+#define AR934X_NFC_CTRL_ADDR_CYCLE1_S		18
+#define AR934X_NFC_CTRL_SMALL_PAGE		BIT(21)
+
+#define AR934X_NFC_DMA_CTRL_DMA_START		BIT(7)
+#define AR934X_NFC_DMA_CTRL_DMA_DIR_WRITE	0
+#define AR934X_NFC_DMA_CTRL_DMA_DIR_READ	BIT(6)
+#define AR934X_NFC_DMA_CTRL_DMA_MODE_SG		BIT(5)
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_S		2
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_0		0
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_1		1
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_2		2
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_3		3
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_4		4
+#define AR934X_NFC_DMA_CTRL_DMA_BURST_5		5
+#define AR934X_NFC_DMA_CTRL_ERR_FLAG		BIT(1)
+#define AR934X_NFC_DMA_CTRL_DMA_READY		BIT(0)
+
+#define AR934X_NFC_INT_DEV_RDY(_x)		BIT(4 + (_x))
+#define AR934X_NFC_INT_CMD_END			BIT(1)
+
+#define AR934X_NFC_ECC_CTRL_ERR_THRES_S		8
+#define AR934X_NFC_ECC_CTRL_ERR_THRES_M		0x1f
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_S		5
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_M		0x7
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_2		0
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_4		1
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_6		2
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_8		3
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_10		4
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_12		5
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_14		6
+#define AR934X_NFC_ECC_CTRL_ECC_CAP_16		7
+#define AR934X_NFC_ECC_CTRL_ERR_OVER		BIT(2)
+#define AR934X_NFC_ECC_CTRL_ERR_UNCORRECT	BIT(1)
+#define AR934X_NFC_ECC_CTRL_ERR_CORRECT		BIT(0)
+
+#define AR934X_NFC_ECC_OFFS_OFSET_M		0xffff
+
+/* default timing values */
+#define AR934X_NFC_TIME_SEQ_DEFAULT	0x7fff
+#define AR934X_NFC_TIMINGS_ASYN_DEFAULT	0x22
+#define AR934X_NFC_TIMINGS_SYN_DEFAULT	0xf
+
+#define AR934X_NFC_ID_BUF_SIZE		8
+#define AR934X_NFC_DEV_READY_TIMEOUT	25 /* msecs */
+#define AR934X_NFC_DMA_READY_TIMEOUT	25 /* msecs */
+#define AR934X_NFC_DONE_TIMEOUT		1000
+#define AR934X_NFC_DMA_RETRIES		20
+
+#define AR934X_NFC_USE_IRQ		true
+#define AR934X_NFC_IRQ_MASK		AR934X_NFC_INT_DEV_RDY(0)
+
+#define  AR934X_NFC_GENSEQ_SMALL_PAGE_READ	0x30043
+
+#undef AR934X_NFC_DEBUG_DATA
+#undef AR934X_NFC_DEBUG
+
+struct ar934x_nfc;
+
+static inline  __attribute__ ((format (printf, 2, 3)))
+void _nfc_dbg(struct ar934x_nfc *nfc, const char *fmt, ...)
+{
+}
+
+#ifdef AR934X_NFC_DEBUG
+#define nfc_dbg(_nfc, fmt, ...) \
+	dev_info((_nfc)->parent, fmt, ##__VA_ARGS__)
+#else
+#define nfc_dbg(_nfc, fmt, ...) \
+	_nfc_dbg((_nfc), fmt, ##__VA_ARGS__)
+#endif /* AR934X_NFC_DEBUG */
+
+#ifdef AR934X_NFC_DEBUG_DATA
+static void
+nfc_debug_data(const char *label, void *data, int len)
+{
+	print_hex_dump(KERN_WARNING, label, DUMP_PREFIX_OFFSET, 16, 1,
+		       data, len, 0);
+}
+#else
+static inline void
+nfc_debug_data(const char *label, void *data, int len) {}
+#endif /* AR934X_NFC_DEBUG_DATA */
+
+struct ar934x_nfc {
+	struct mtd_info mtd;
+	struct nand_chip nand_chip;
+	struct device *parent;
+	void __iomem *base;
+	void (*select_chip)(int chip_no);
+	bool swap_dma;
+	int irq;
+	wait_queue_head_t irq_waitq;
+
+	bool spurious_irq_expected;
+	u32 irq_status;
+
+	u32 ctrl_reg;
+	u32 ecc_ctrl_reg;
+	u32 ecc_offset_reg;
+	u32 ecc_thres;
+	u32 ecc_oob_pos;
+
+	bool small_page;
+	unsigned int addr_count0;
+	unsigned int addr_count1;
+
+	u8 *buf;
+	dma_addr_t buf_dma;
+	unsigned int buf_size;
+	int buf_index;
+
+	bool read_id;
+
+	int erase1_page_addr;
+
+	int rndout_page_addr;
+	int rndout_read_cmd;
+
+	int seqin_page_addr;
+	int seqin_column;
+	int seqin_read_cmd;
+};
+
+static void ar934x_nfc_restart(struct ar934x_nfc *nfc);
+
+static inline bool
+is_all_ff(u8 *buf, int len)
+{
+	while (len--)
+		if (buf[len] != 0xff)
+			return false;
+
+	return true;
+}
+
+static inline void
+ar934x_nfc_wr(struct ar934x_nfc *nfc, unsigned reg, u32 val)
+{
+	__raw_writel(val, nfc->base + reg);
+}
+
+static inline u32
+ar934x_nfc_rr(struct ar934x_nfc *nfc, unsigned reg)
+{
+	return __raw_readl(nfc->base + reg);
+}
+
+static inline struct ar934x_nfc_platform_data *
+ar934x_nfc_get_platform_data(struct ar934x_nfc *nfc)
+{
+	return nfc->parent->platform_data;
+}
+
+static inline struct
+ar934x_nfc *mtd_to_ar934x_nfc(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct ar934x_nfc, mtd);
+}
+
+static inline bool ar934x_nfc_use_irq(struct ar934x_nfc *nfc)
+{
+	return AR934X_NFC_USE_IRQ;
+}
+
+static inline void ar934x_nfc_write_cmd_reg(struct ar934x_nfc *nfc, u32 cmd_reg)
+{
+	wmb();
+
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CMD, cmd_reg);
+	/* flush write */
+	ar934x_nfc_rr(nfc, AR934X_NFC_REG_CMD);
+}
+
+static bool
+__ar934x_nfc_dev_ready(struct ar934x_nfc *nfc)
+{
+	u32 status;
+
+	status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_STATUS);
+	return (status & 0xff) == 0xff;
+}
+
+static inline bool
+__ar934x_nfc_is_dma_ready(struct ar934x_nfc *nfc)
+{
+	u32 status;
+
+	status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_DMA_CTRL);
+	return (status & AR934X_NFC_DMA_CTRL_DMA_READY) != 0;
+}
+
+static int
+ar934x_nfc_wait_dev_ready(struct ar934x_nfc *nfc)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(AR934X_NFC_DEV_READY_TIMEOUT);
+	do {
+		if (__ar934x_nfc_dev_ready(nfc))
+			return 0;
+	} while time_before(jiffies, timeout);
+
+	nfc_dbg(nfc, "timeout waiting for device ready, status:%08x int:%08x\n",
+		ar934x_nfc_rr(nfc, AR934X_NFC_REG_STATUS),
+		ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS));
+	return -ETIMEDOUT;
+}
+
+static int
+ar934x_nfc_wait_dma_ready(struct ar934x_nfc *nfc)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(AR934X_NFC_DMA_READY_TIMEOUT);
+	do {
+		if (__ar934x_nfc_is_dma_ready(nfc))
+			return 0;
+	} while time_before(jiffies, timeout);
+
+	nfc_dbg(nfc, "timeout waiting for DMA ready, dma_ctrl:%08x\n",
+		ar934x_nfc_rr(nfc, AR934X_NFC_REG_DMA_CTRL));
+	return -ETIMEDOUT;
+}
+
+static int
+ar934x_nfc_wait_irq(struct ar934x_nfc *nfc)
+{
+	long timeout;
+	int ret;
+
+	timeout = wait_event_timeout(nfc->irq_waitq,
+				(nfc->irq_status & AR934X_NFC_IRQ_MASK) != 0,
+				msecs_to_jiffies(AR934X_NFC_DEV_READY_TIMEOUT));
+
+	ret = 0;
+	if (!timeout) {
+		ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_MASK, 0);
+		ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0);
+		/* flush write */
+		ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS);
+
+		nfc_dbg(nfc,
+			"timeout waiting for interrupt, status:%08x\n",
+			nfc->irq_status);
+		ret = -ETIMEDOUT;
+	}
+
+	nfc->irq_status = 0;
+	return ret;
+}
+
+static int
+ar934x_nfc_wait_done(struct ar934x_nfc *nfc)
+{
+	int ret;
+
+	if (ar934x_nfc_use_irq(nfc))
+		ret = ar934x_nfc_wait_irq(nfc);
+	else
+		ret = ar934x_nfc_wait_dev_ready(nfc);
+
+	if (ret)
+		return ret;
+
+	return ar934x_nfc_wait_dma_ready(nfc);
+}
+
+static int
+ar934x_nfc_alloc_buf(struct ar934x_nfc *nfc, unsigned size)
+{
+	nfc->buf = dma_alloc_coherent(nfc->parent, size,
+				      &nfc->buf_dma, GFP_KERNEL);
+	if (nfc->buf == NULL) {
+		dev_err(nfc->parent, "no memory for DMA buffer\n");
+		return -ENOMEM;
+	}
+
+	nfc->buf_size = size;
+	nfc_dbg(nfc, "buf:%p size:%u\n", nfc->buf, nfc->buf_size);
+
+	return 0;
+}
+
+static void
+ar934x_nfc_free_buf(struct ar934x_nfc *nfc)
+{
+	dma_free_coherent(nfc->parent, nfc->buf_size, nfc->buf, nfc->buf_dma);
+}
+
+static void
+ar934x_nfc_get_addr(struct ar934x_nfc *nfc, int column, int page_addr,
+		    u32 *addr0, u32 *addr1)
+{
+	u32 a0, a1;
+
+	a0 = 0;
+	a1 = 0;
+
+	if (column == -1) {
+		/* ERASE1 */
+		a0 = (page_addr & 0xffff) << 16;
+		a1 = (page_addr >> 16) & 0xf;
+	} else if (page_addr != -1) {
+		/* SEQIN, READ0, etc.. */
+
+		/* TODO: handle 16bit bus width */
+		if (nfc->small_page) {
+			a0 = column & 0xff;
+			a0 |= (page_addr & 0xff) << 8;
+			a0 |= ((page_addr >> 8) & 0xff) << 16;
+			a0 |= ((page_addr >> 16) & 0xff) << 24;
+		} else {
+			a0 = column & 0x0FFF;
+			a0 |= (page_addr & 0xffff) << 16;
+
+			if (nfc->addr_count0 > 4)
+				a1 = (page_addr >> 16) & 0xf;
+		}
+	}
+
+	*addr0 = a0;
+	*addr1 = a1;
+}
+
+static void
+ar934x_nfc_send_cmd(struct ar934x_nfc *nfc, unsigned command)
+{
+	u32 cmd_reg;
+
+	cmd_reg = AR934X_NFC_CMD_INPUT_SEL_SIU | AR934X_NFC_CMD_ADDR_SEL_0 |
+		  AR934X_NFC_CMD_SEQ_1C;
+	cmd_reg |= (command & AR934X_NFC_CMD_CMD0_M) << AR934X_NFC_CMD_CMD0_S;
+
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg);
+
+	ar934x_nfc_write_cmd_reg(nfc, cmd_reg);
+	ar934x_nfc_wait_dev_ready(nfc);
+}
+
+static int
+ar934x_nfc_do_rw_command(struct ar934x_nfc *nfc, int column, int page_addr,
+			 int len, u32 cmd_reg, u32 ctrl_reg, bool write)
+{
+	u32 addr0, addr1;
+	u32 dma_ctrl;
+	int dir;
+	int err;
+	int retries = 0;
+
+	WARN_ON(len & 3);
+
+	if (WARN_ON(len > nfc->buf_size))
+		dev_err(nfc->parent, "len=%d > buf_size=%d", len, nfc->buf_size);
+
+	if (write) {
+		dma_ctrl = AR934X_NFC_DMA_CTRL_DMA_DIR_WRITE;
+		dir = DMA_TO_DEVICE;
+	} else {
+		dma_ctrl = AR934X_NFC_DMA_CTRL_DMA_DIR_READ;
+		dir = DMA_FROM_DEVICE;
+	}
+
+	ar934x_nfc_get_addr(nfc, column, page_addr, &addr0, &addr1);
+
+	dma_ctrl |= AR934X_NFC_DMA_CTRL_DMA_START |
+		    (AR934X_NFC_DMA_CTRL_DMA_BURST_3 <<
+		     AR934X_NFC_DMA_CTRL_DMA_BURST_S);
+
+	cmd_reg |= AR934X_NFC_CMD_INPUT_SEL_DMA | AR934X_NFC_CMD_ADDR_SEL_0;
+	ctrl_reg |= AR934X_NFC_CTRL_INT_EN;
+
+	nfc_dbg(nfc, "%s a0:%08x a1:%08x len:%x cmd:%08x dma:%08x ctrl:%08x\n",
+		(write) ? "write" : "read",
+		addr0, addr1, len, cmd_reg, dma_ctrl, ctrl_reg);
+
+retry:
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_0, addr0);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_1, addr1);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_ADDR, nfc->buf_dma);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_COUNT, len);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_DATA_SIZE, len);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, ctrl_reg);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_CTRL, dma_ctrl);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_ECC_CTRL, nfc->ecc_ctrl_reg);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_ECC_OFFSET, nfc->ecc_offset_reg);
+
+	if (ar934x_nfc_use_irq(nfc)) {
+		ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_MASK, AR934X_NFC_IRQ_MASK);
+		/* flush write */
+		ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_MASK);
+	}
+
+	ar934x_nfc_write_cmd_reg(nfc, cmd_reg);
+	err = ar934x_nfc_wait_done(nfc);
+	if (err) {
+		dev_dbg(nfc->parent, "%s operation stuck at page %d\n",
+			(write) ? "write" : "read", page_addr);
+
+		ar934x_nfc_restart(nfc);
+		if (retries++ < AR934X_NFC_DMA_RETRIES)
+			goto retry;
+
+		dev_err(nfc->parent, "%s operation failed on page %d\n",
+			(write) ? "write" : "read", page_addr);
+	}
+
+	return err;
+}
+
+static int
+ar934x_nfc_send_readid(struct ar934x_nfc *nfc, unsigned command)
+{
+	u32 cmd_reg;
+	int err;
+
+	nfc_dbg(nfc, "readid, cmd:%02x\n", command);
+
+	cmd_reg = AR934X_NFC_CMD_SEQ_1C1AXR;
+	cmd_reg |= (command & AR934X_NFC_CMD_CMD0_M) << AR934X_NFC_CMD_CMD0_S;
+
+	err = ar934x_nfc_do_rw_command(nfc, -1, -1, AR934X_NFC_ID_BUF_SIZE,
+				       cmd_reg, nfc->ctrl_reg, false);
+
+	nfc_debug_data("[id] ", nfc->buf, AR934X_NFC_ID_BUF_SIZE);
+
+	return err;
+}
+
+static int
+ar934x_nfc_send_read(struct ar934x_nfc *nfc, unsigned command, int column,
+		     int page_addr, int len)
+{
+	u32 cmd_reg;
+	int err;
+
+	nfc_dbg(nfc, "read, column=%d page=%d len=%d\n",
+		column, page_addr, len);
+
+	cmd_reg = (command & AR934X_NFC_CMD_CMD0_M) << AR934X_NFC_CMD_CMD0_S;
+
+	if (nfc->small_page) {
+		cmd_reg |= AR934X_NFC_CMD_SEQ_18;
+	} else {
+		cmd_reg |= NAND_CMD_READSTART << AR934X_NFC_CMD_CMD1_S;
+		cmd_reg |= AR934X_NFC_CMD_SEQ_1C5A1CXR;
+	}
+
+	err = ar934x_nfc_do_rw_command(nfc, column, page_addr, len,
+				       cmd_reg, nfc->ctrl_reg, false);
+
+	nfc_debug_data("[data] ", nfc->buf, len);
+
+	return err;
+}
+
+static void
+ar934x_nfc_send_erase(struct ar934x_nfc *nfc, unsigned command, int column,
+		      int page_addr)
+{
+	u32 addr0, addr1;
+	u32 ctrl_reg;
+	u32 cmd_reg;
+
+	ar934x_nfc_get_addr(nfc, column, page_addr, &addr0, &addr1);
+
+	ctrl_reg = nfc->ctrl_reg;
+	if (nfc->small_page) {
+		/* override number of address cycles for the erase command */
+		ctrl_reg &= ~(AR934X_NFC_CTRL_ADDR_CYCLE0_M <<
+			      AR934X_NFC_CTRL_ADDR_CYCLE0_S);
+		ctrl_reg &= ~(AR934X_NFC_CTRL_ADDR_CYCLE1_M <<
+			      AR934X_NFC_CTRL_ADDR_CYCLE1_S);
+		ctrl_reg &= ~(AR934X_NFC_CTRL_SMALL_PAGE);
+		ctrl_reg |= (nfc->addr_count0 + 1) <<
+			    AR934X_NFC_CTRL_ADDR_CYCLE0_S;
+	}
+
+	cmd_reg = NAND_CMD_ERASE1 << AR934X_NFC_CMD_CMD0_S;
+	cmd_reg |= command << AR934X_NFC_CMD_CMD1_S;
+	cmd_reg |= AR934X_NFC_CMD_SEQ_ERASE;
+
+	nfc_dbg(nfc, "erase page %d, a0:%08x a1:%08x cmd:%08x ctrl:%08x\n",
+		page_addr, addr0, addr1, cmd_reg, ctrl_reg);
+
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, ctrl_reg);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_0, addr0);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_1, addr1);
+
+	ar934x_nfc_write_cmd_reg(nfc, cmd_reg);
+	ar934x_nfc_wait_dev_ready(nfc);
+}
+
+static int
+ar934x_nfc_send_write(struct ar934x_nfc *nfc, unsigned command, int column,
+		     int page_addr, int len)
+{
+	u32 cmd_reg;
+
+	nfc_dbg(nfc, "write, column=%d page=%d len=%d\n",
+		column, page_addr, len);
+
+	nfc_debug_data("[data] ", nfc->buf, len);
+
+	cmd_reg = NAND_CMD_SEQIN << AR934X_NFC_CMD_CMD0_S;
+	cmd_reg |= command << AR934X_NFC_CMD_CMD1_S;
+	cmd_reg |= AR934X_NFC_CMD_SEQ_12;
+
+	return ar934x_nfc_do_rw_command(nfc, column, page_addr, len,
+					cmd_reg, nfc->ctrl_reg, true);
+}
+
+static void
+ar934x_nfc_read_status(struct ar934x_nfc *nfc)
+{
+	u32 cmd_reg;
+	u32 status;
+
+	cmd_reg = NAND_CMD_STATUS << AR934X_NFC_CMD_CMD0_S;
+	cmd_reg |= AR934X_NFC_CMD_SEQ_S;
+
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg);
+
+	ar934x_nfc_write_cmd_reg(nfc, cmd_reg);
+	ar934x_nfc_wait_dev_ready(nfc);
+
+	status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_READ_STATUS);
+
+	nfc_dbg(nfc, "read status, cmd:%08x status:%02x\n",
+		cmd_reg, (status & 0xff));
+
+	if (nfc->swap_dma)
+		nfc->buf[0 ^ 3] = status;
+	else
+		nfc->buf[0] = status;
+}
+
+static void
+ar934x_nfc_cmdfunc(struct mtd_info *mtd, unsigned int command, int column,
+		   int page_addr)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	struct nand_chip *nand = mtd->priv;
+
+	nfc->read_id = false;
+	if (command != NAND_CMD_PAGEPROG)
+		nfc->buf_index = 0;
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		ar934x_nfc_send_cmd(nfc, command);
+		break;
+
+	case NAND_CMD_READID:
+		nfc->read_id = true;
+		ar934x_nfc_send_readid(nfc, command);
+		break;
+
+	case NAND_CMD_READ0:
+	case NAND_CMD_READ1:
+		if (nfc->small_page) {
+			ar934x_nfc_send_read(nfc, command, column, page_addr,
+					     mtd->writesize + mtd->oobsize);
+		} else {
+			ar934x_nfc_send_read(nfc, command, 0, page_addr,
+					     mtd->writesize + mtd->oobsize);
+			nfc->buf_index = column;
+			nfc->rndout_page_addr = page_addr;
+			nfc->rndout_read_cmd = command;
+		}
+		break;
+
+	case NAND_CMD_READOOB:
+		if (nfc->small_page)
+			ar934x_nfc_send_read(nfc, NAND_CMD_READOOB,
+					     column, page_addr,
+					     mtd->oobsize);
+		else
+			ar934x_nfc_send_read(nfc, NAND_CMD_READ0,
+					     mtd->writesize, page_addr,
+					     mtd->oobsize);
+		break;
+
+	case NAND_CMD_RNDOUT:
+		if (WARN_ON(nfc->small_page))
+			break;
+
+		/* emulate subpage read */
+		ar934x_nfc_send_read(nfc, nfc->rndout_read_cmd, 0,
+				     nfc->rndout_page_addr,
+				     mtd->writesize + mtd->oobsize);
+		nfc->buf_index = column;
+		break;
+
+	case NAND_CMD_ERASE1:
+		nfc->erase1_page_addr = page_addr;
+		break;
+
+	case NAND_CMD_ERASE2:
+		ar934x_nfc_send_erase(nfc, command, -1, nfc->erase1_page_addr);
+		break;
+
+	case NAND_CMD_STATUS:
+		ar934x_nfc_read_status(nfc);
+		break;
+
+	case NAND_CMD_SEQIN:
+		if (nfc->small_page) {
+			/* output read command */
+			if (column >= mtd->writesize) {
+				column -= mtd->writesize;
+				nfc->seqin_read_cmd = NAND_CMD_READOOB;
+			} else if (column < 256) {
+				nfc->seqin_read_cmd = NAND_CMD_READ0;
+			} else {
+				column -= 256;
+				nfc->seqin_read_cmd = NAND_CMD_READ1;
+			}
+		} else {
+			nfc->seqin_read_cmd = NAND_CMD_READ0;
+		}
+		nfc->seqin_column = column;
+		nfc->seqin_page_addr = page_addr;
+		break;
+
+	case NAND_CMD_PAGEPROG:
+		if (nand->ecc.mode == NAND_ECC_HW) {
+			/* the data is already written */
+			break;
+		}
+
+		if (nfc->small_page)
+			ar934x_nfc_send_cmd(nfc, nfc->seqin_read_cmd);
+
+		ar934x_nfc_send_write(nfc, command, nfc->seqin_column,
+				      nfc->seqin_page_addr,
+				      nfc->buf_index);
+		break;
+
+	default:
+		dev_err(nfc->parent,
+			"unsupported command: %x, column:%d page_addr=%d\n",
+			command, column, page_addr);
+		break;
+	}
+}
+
+static int
+ar934x_nfc_dev_ready(struct mtd_info *mtd)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+
+	return __ar934x_nfc_dev_ready(nfc);
+}
+
+static void
+ar934x_nfc_select_chip(struct mtd_info *mtd, int chip_no)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+
+	if (nfc->select_chip)
+		nfc->select_chip(chip_no);
+}
+
+static u8
+ar934x_nfc_read_byte(struct mtd_info *mtd)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	u8 data;
+
+	WARN_ON(nfc->buf_index >= nfc->buf_size);
+
+	if (nfc->swap_dma || nfc->read_id)
+		data = nfc->buf[nfc->buf_index ^ 3];
+	else
+		data = nfc->buf[nfc->buf_index];
+
+	nfc->buf_index++;
+
+	return data;
+}
+
+static void
+ar934x_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	int i;
+
+	WARN_ON(nfc->buf_index + len > nfc->buf_size);
+
+	if (nfc->swap_dma) {
+		for (i = 0; i < len; i++) {
+			nfc->buf[nfc->buf_index ^ 3] = buf[i];
+			nfc->buf_index++;
+		}
+	} else {
+		for (i = 0; i < len; i++) {
+			nfc->buf[nfc->buf_index] = buf[i];
+			nfc->buf_index++;
+		}
+	}
+}
+
+static void
+ar934x_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	int buf_index;
+	int i;
+
+	WARN_ON(nfc->buf_index + len > nfc->buf_size);
+
+	buf_index = nfc->buf_index;
+
+	if (nfc->swap_dma || nfc->read_id) {
+		for (i = 0; i < len; i++) {
+			buf[i] = nfc->buf[buf_index ^ 3];
+			buf_index++;
+		}
+	} else {
+		for (i = 0; i < len; i++) {
+			buf[i] = nfc->buf[buf_index];
+			buf_index++;
+		}
+	}
+
+	nfc->buf_index = buf_index;
+}
+
+static inline void
+ar934x_nfc_enable_hwecc(struct ar934x_nfc *nfc)
+{
+	nfc->ctrl_reg |= AR934X_NFC_CTRL_ECC_EN;
+	nfc->ctrl_reg &= ~AR934X_NFC_CTRL_CUSTOM_SIZE_EN;
+}
+
+static inline void
+ar934x_nfc_disable_hwecc(struct ar934x_nfc *nfc)
+{
+	nfc->ctrl_reg &= ~AR934X_NFC_CTRL_ECC_EN;
+	nfc->ctrl_reg |= AR934X_NFC_CTRL_CUSTOM_SIZE_EN;
+}
+
+static int
+ar934x_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+		    int page)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	int err;
+
+	nfc_dbg(nfc, "read_oob: page:%d\n", page);
+
+	err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, mtd->writesize, page,
+				   mtd->oobsize);
+	if (err)
+		return err;
+
+	memcpy(chip->oob_poi, nfc->buf, mtd->oobsize);
+
+	return 0;
+}
+
+static int
+ar934x_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+		     int page)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+
+	nfc_dbg(nfc, "write_oob: page:%d\n", page);
+
+	memcpy(nfc->buf, chip->oob_poi, mtd->oobsize);
+
+	return ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, mtd->writesize,
+				     page, mtd->oobsize);
+}
+
+static int
+ar934x_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+			 u8 *buf, int oob_required, int page)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	int len;
+	int err;
+
+	nfc_dbg(nfc, "read_page_raw: page:%d oob:%d\n", page, oob_required);
+
+	len = mtd->writesize;
+	if (oob_required)
+		len += mtd->oobsize;
+
+	err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, 0, page, len);
+	if (err)
+		return err;
+
+	memcpy(buf, nfc->buf, mtd->writesize);
+
+	if (oob_required)
+		memcpy(chip->oob_poi, &nfc->buf[mtd->writesize], mtd->oobsize);
+
+	return 0;
+}
+
+static int
+ar934x_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+		     u8 *buf, int oob_required, int page)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	u32 ecc_ctrl;
+	int max_bitflips = 0;
+	bool ecc_failed;
+	bool ecc_corrected;
+	int err;
+
+	nfc_dbg(nfc, "read_page: page:%d oob:%d\n", page, oob_required);
+
+	ar934x_nfc_enable_hwecc(nfc);
+	err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, 0, page,
+				   mtd->writesize);
+	ar934x_nfc_disable_hwecc(nfc);
+
+	if (err)
+		return err;
+
+	/* TODO: optimize to avoid memcpy */
+	memcpy(buf, nfc->buf, mtd->writesize);
+
+	/* read the ECC status */
+	ecc_ctrl = ar934x_nfc_rr(nfc, AR934X_NFC_REG_ECC_CTRL);
+	ecc_failed = ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_UNCORRECT;
+	ecc_corrected = ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_CORRECT;
+
+	if (oob_required || ecc_failed) {
+		err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, mtd->writesize,
+					   page, mtd->oobsize);
+		if (err)
+			return err;
+
+		if (oob_required)
+			memcpy(chip->oob_poi, nfc->buf, mtd->oobsize);
+	}
+
+	if (ecc_failed) {
+		/*
+		 * The hardware ECC engine reports uncorrectable errors
+		 * on empty pages. Check the ECC bytes and the data. If
+		 * both contains 0xff bytes only, dont report a failure.
+		 *
+		 * TODO: prebuild a buffer with 0xff bytes and use memcmp
+		 * for better performance?
+		 */
+		if (!is_all_ff(&nfc->buf[nfc->ecc_oob_pos], chip->ecc.total) ||
+		    !is_all_ff(buf, mtd->writesize))
+				mtd->ecc_stats.failed++;
+	} else if (ecc_corrected) {
+		/*
+		 * The hardware does not report the exact count of the
+		 * corrected bitflips, use assumptions based on the
+		 * threshold.
+		 */
+		if (ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_OVER) {
+			/*
+			 * The number of corrected bitflips exceeds the
+			 * threshold. Assume the maximum.
+			 */
+			max_bitflips = chip->ecc.strength * chip->ecc.steps;
+		} else {
+			max_bitflips = nfc->ecc_thres * chip->ecc.steps;
+		}
+
+		mtd->ecc_stats.corrected += max_bitflips;
+	}
+
+	return max_bitflips;
+}
+
+static int
+ar934x_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+			  const u8 *buf, int oob_required, int page)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	int len;
+
+	nfc_dbg(nfc, "write_page_raw: page:%d oob:%d\n", page, oob_required);
+
+	memcpy(nfc->buf, buf, mtd->writesize);
+	len = mtd->writesize;
+
+	if (oob_required) {
+		memcpy(&nfc->buf[mtd->writesize], chip->oob_poi, mtd->oobsize);
+		len += mtd->oobsize;
+	}
+
+	return ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, 0, page, len);
+}
+
+static int
+ar934x_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+		      const u8 *buf, int oob_required, int page)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	int err;
+
+	nfc_dbg(nfc, "write_page: page:%d oob:%d\n", page, oob_required);
+
+	/* write OOB first */
+	if (oob_required &&
+	    !is_all_ff(chip->oob_poi, mtd->oobsize)) {
+		err = ar934x_nfc_write_oob(mtd, chip, page);
+		if (err)
+			return err;
+	}
+
+	/* TODO: optimize to avoid memcopy */
+	memcpy(nfc->buf, buf, mtd->writesize);
+
+	ar934x_nfc_enable_hwecc(nfc);
+	err = ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, 0, page,
+				    mtd->writesize);
+	ar934x_nfc_disable_hwecc(nfc);
+
+	return err;
+}
+
+static void
+ar934x_nfc_hw_init(struct ar934x_nfc *nfc)
+{
+	struct ar934x_nfc_platform_data *pdata;
+
+	pdata = ar934x_nfc_get_platform_data(nfc);
+	if (pdata->hw_reset) {
+		pdata->hw_reset(true);
+		pdata->hw_reset(false);
+	}
+
+	/*
+	 * setup timings
+	 * TODO: make it configurable via platform data
+	 */
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_TIME_SEQ,
+		      AR934X_NFC_TIME_SEQ_DEFAULT);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_TIMINGS_ASYN,
+		      AR934X_NFC_TIMINGS_ASYN_DEFAULT);
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_TIMINGS_SYN,
+		      AR934X_NFC_TIMINGS_SYN_DEFAULT);
+
+	/* disable WP on all chips, and select chip 0 */
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_MEM_CTRL, 0xff00);
+
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_ADDR_OFFS, 0);
+
+	/* initialize Control register */
+	nfc->ctrl_reg = AR934X_NFC_CTRL_CUSTOM_SIZE_EN;
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg);
+
+	if (nfc->small_page) {
+		/*  Setup generic sequence register for small page reads. */
+		ar934x_nfc_wr(nfc, AR934X_NFC_REG_GEN_SEQ_CTRL,
+			      AR934X_NFC_GENSEQ_SMALL_PAGE_READ);
+	}
+}
+
+static void
+ar934x_nfc_restart(struct ar934x_nfc *nfc)
+{
+	u32 ctrl_reg;
+
+	if (nfc->select_chip)
+		nfc->select_chip(-1);
+
+	ctrl_reg = nfc->ctrl_reg;
+	ar934x_nfc_hw_init(nfc);
+	nfc->ctrl_reg = ctrl_reg;
+
+	if (nfc->select_chip)
+		nfc->select_chip(0);
+
+	ar934x_nfc_send_cmd(nfc, NAND_CMD_RESET);
+}
+
+static irqreturn_t
+ar934x_nfc_irq_handler(int irq, void *data)
+{
+	struct ar934x_nfc *nfc = data;
+	u32 status;
+
+	status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS);
+
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0);
+	/* flush write */
+	ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS);
+
+	status &= ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_MASK);
+	if (status) {
+		nfc_dbg(nfc, "got IRQ, status:%08x\n", status);
+
+		nfc->irq_status = status;
+		nfc->spurious_irq_expected = true;
+		wake_up(&nfc->irq_waitq);
+	} else {
+		if (nfc->spurious_irq_expected) {
+			nfc->spurious_irq_expected = false;
+		} else {
+			dev_warn(nfc->parent, "spurious interrupt\n");
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int
+ar934x_nfc_init_tail(struct mtd_info *mtd)
+{
+	struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd);
+	struct nand_chip *chip = &nfc->nand_chip;
+	u32 ctrl;
+	u32 t;
+	int err;
+
+	switch (mtd->oobsize) {
+	case 16:
+	case 64:
+	case 128:
+		ar934x_nfc_wr(nfc, AR934X_NFC_REG_SPARE_SIZE, mtd->oobsize);
+		break;
+
+	default:
+		dev_err(nfc->parent, "unsupported OOB size: %d bytes\n",
+			mtd->oobsize);
+		return -ENXIO;
+	}
+
+	ctrl = AR934X_NFC_CTRL_CUSTOM_SIZE_EN;
+
+	switch (mtd->erasesize / mtd->writesize) {
+	case 32:
+		t = AR934X_NFC_CTRL_BLOCK_SIZE_32;
+		break;
+
+	case 64:
+		t = AR934X_NFC_CTRL_BLOCK_SIZE_64;
+		break;
+
+	case 128:
+		t = AR934X_NFC_CTRL_BLOCK_SIZE_128;
+		break;
+
+	case 256:
+		t = AR934X_NFC_CTRL_BLOCK_SIZE_256;
+		break;
+
+	default:
+		dev_err(nfc->parent, "unsupported block size: %u\n",
+			mtd->erasesize / mtd->writesize);
+		return -ENXIO;
+	}
+
+	ctrl |= t << AR934X_NFC_CTRL_BLOCK_SIZE_S;
+
+	switch (mtd->writesize) {
+	case 256:
+		nfc->small_page = 1;
+		t = AR934X_NFC_CTRL_PAGE_SIZE_256;
+		break;
+
+	case 512:
+		nfc->small_page = 1;
+		t = AR934X_NFC_CTRL_PAGE_SIZE_512;
+		break;
+
+	case 1024:
+		t = AR934X_NFC_CTRL_PAGE_SIZE_1024;
+		break;
+
+	case 2048:
+		t = AR934X_NFC_CTRL_PAGE_SIZE_2048;
+		break;
+
+	case 4096:
+		t = AR934X_NFC_CTRL_PAGE_SIZE_4096;
+		break;
+
+	case 8192:
+		t = AR934X_NFC_CTRL_PAGE_SIZE_8192;
+		break;
+
+	case 16384:
+		t = AR934X_NFC_CTRL_PAGE_SIZE_16384;
+		break;
+
+	default:
+		dev_err(nfc->parent, "unsupported write size: %d bytes\n",
+			mtd->writesize);
+		return -ENXIO;
+	}
+
+	ctrl |= t << AR934X_NFC_CTRL_PAGE_SIZE_S;
+
+	if (nfc->small_page) {
+		ctrl |= AR934X_NFC_CTRL_SMALL_PAGE;
+
+		if (chip->chipsize > (32 << 20)) {
+			nfc->addr_count0 = 4;
+			nfc->addr_count1 = 3;
+		} else if (chip->chipsize > (2 << 16)) {
+			nfc->addr_count0 = 3;
+			nfc->addr_count1 = 2;
+		} else {
+			nfc->addr_count0 = 2;
+			nfc->addr_count1 = 1;
+		}
+	} else {
+		if (chip->chipsize > (128 << 20)) {
+			nfc->addr_count0 = 5;
+			nfc->addr_count1 = 3;
+		} else if (chip->chipsize > (8 << 16)) {
+			nfc->addr_count0 = 4;
+			nfc->addr_count1 = 2;
+		} else {
+			nfc->addr_count0 = 3;
+			nfc->addr_count1 = 1;
+		}
+	}
+
+	ctrl |= nfc->addr_count0 << AR934X_NFC_CTRL_ADDR_CYCLE0_S;
+	ctrl |= nfc->addr_count1 << AR934X_NFC_CTRL_ADDR_CYCLE1_S;
+
+	nfc->ctrl_reg = ctrl;
+	ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg);
+
+	ar934x_nfc_free_buf(nfc);
+	err = ar934x_nfc_alloc_buf(nfc, mtd->writesize + mtd->oobsize);
+
+	return err;
+}
+
+static struct nand_ecclayout ar934x_nfc_oob_64_hwecc = {
+	.eccbytes = 28,
+	.eccpos = {
+		20, 21, 22, 23, 24, 25, 26,
+		27, 28, 29, 30, 31, 32, 33,
+		34, 35, 36, 37, 38, 39, 40,
+		41, 42, 43, 44, 45, 46, 47,
+	},
+	.oobfree = {
+		{
+			.offset = 4,
+			.length = 16,
+		},
+		{
+			.offset = 48,
+			.length = 16,
+		},
+	},
+};
+
+static int
+ar934x_nfc_setup_hwecc(struct ar934x_nfc *nfc)
+{
+	struct nand_chip *nand = &nfc->nand_chip;
+	u32 ecc_cap;
+	u32 ecc_thres;
+
+	if (!config_enabled(CONFIG_MTD_NAND_AR934X_HW_ECC)) {
+		dev_err(nfc->parent, "hardware ECC support is disabled\n");
+		return -EINVAL;
+	}
+
+	switch (nfc->mtd.writesize) {
+	case 2048:
+		/*
+		 * Writing a subpage separately is not supported, because
+		 * the controller only does ECC on full-page accesses.
+		 */
+		nand->options = NAND_NO_SUBPAGE_WRITE;
+
+		nand->ecc.size = 512;
+		nand->ecc.bytes = 7;
+		nand->ecc.strength = 4;
+		nand->ecc.layout = &ar934x_nfc_oob_64_hwecc;
+		break;
+
+	default:
+		dev_err(nfc->parent,
+			"hardware ECC is not available for %d byte pages\n",
+			nfc->mtd.writesize);
+		return -EINVAL;
+	}
+
+	BUG_ON(!nand->ecc.layout);
+
+	switch (nand->ecc.strength) {
+	case 4:
+		ecc_cap = AR934X_NFC_ECC_CTRL_ECC_CAP_4;
+		ecc_thres = 4;
+		break;
+
+	default:
+		dev_err(nfc->parent, "unsupported ECC strength %u\n",
+			nand->ecc.strength);
+		return -EINVAL;
+	}
+
+	nfc->ecc_thres = ecc_thres;
+	nfc->ecc_oob_pos = nand->ecc.layout->eccpos[0];
+
+	nfc->ecc_ctrl_reg = ecc_cap << AR934X_NFC_ECC_CTRL_ECC_CAP_S;
+	nfc->ecc_ctrl_reg |= ecc_thres << AR934X_NFC_ECC_CTRL_ERR_THRES_S;
+
+	nfc->ecc_offset_reg = nfc->mtd.writesize + nfc->ecc_oob_pos;
+
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.read_page = ar934x_nfc_read_page;
+	nand->ecc.read_page_raw = ar934x_nfc_read_page_raw;
+	nand->ecc.write_page = ar934x_nfc_write_page;
+	nand->ecc.write_page_raw = ar934x_nfc_write_page_raw;
+	nand->ecc.read_oob = ar934x_nfc_read_oob;
+	nand->ecc.write_oob = ar934x_nfc_write_oob;
+
+	return 0;
+}
+
+static int
+ar934x_nfc_probe(struct platform_device *pdev)
+{
+	static const char *part_probes[] = { "cmdlinepart", NULL, };
+	struct ar934x_nfc_platform_data *pdata;
+	struct ar934x_nfc *nfc;
+	struct resource *res;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	struct mtd_part_parser_data ppdata;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get I/O memory\n");
+		return -EINVAL;
+	}
+
+	nfc = devm_kzalloc(&pdev->dev, sizeof(struct ar934x_nfc), GFP_KERNEL);
+	if (!nfc) {
+		dev_err(&pdev->dev, "failed to allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	nfc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(nfc->base)) {
+		dev_err(&pdev->dev, "failed to remap I/O memory\n");
+		return PTR_ERR(nfc->base);
+	}
+
+	nfc->irq = platform_get_irq(pdev, 0);
+	if (nfc->irq < 0) {
+		dev_err(&pdev->dev, "no IRQ resource specified\n");
+		return -EINVAL;
+	}
+
+	init_waitqueue_head(&nfc->irq_waitq);
+	ret = request_irq(nfc->irq, ar934x_nfc_irq_handler, 0,
+			  dev_name(&pdev->dev), nfc);
+	if (ret) {
+		dev_err(&pdev->dev, "requast_irq failed, err:%d\n", ret);
+		return ret;
+	}
+
+	nfc->parent = &pdev->dev;
+	nfc->select_chip = pdata->select_chip;
+	nfc->swap_dma = pdata->swap_dma;
+
+	nand = &nfc->nand_chip;
+	mtd = &nfc->mtd;
+
+	mtd->priv = nand;
+	mtd->owner = THIS_MODULE;
+	if (pdata->name)
+		mtd->name = pdata->name;
+	else
+		mtd->name = dev_name(&pdev->dev);
+
+	nand->chip_delay = 25;
+
+	nand->dev_ready = ar934x_nfc_dev_ready;
+	nand->cmdfunc = ar934x_nfc_cmdfunc;
+	nand->read_byte = ar934x_nfc_read_byte;
+	nand->write_buf = ar934x_nfc_write_buf;
+	nand->read_buf = ar934x_nfc_read_buf;
+	nand->select_chip = ar934x_nfc_select_chip;
+
+	ret = ar934x_nfc_alloc_buf(nfc, AR934X_NFC_ID_BUF_SIZE);
+	if (ret)
+		goto err_free_irq;
+
+	platform_set_drvdata(pdev, nfc);
+
+	ar934x_nfc_hw_init(nfc);
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "nand_scan_ident failed, err:%d\n", ret);
+		goto err_free_buf;
+	}
+
+	ret = ar934x_nfc_init_tail(mtd);
+	if (ret) {
+		dev_err(&pdev->dev, "init tail failed, err:%d\n", ret);
+		goto err_free_buf;
+	}
+
+	if (pdata->scan_fixup) {
+		ret = pdata->scan_fixup(mtd);
+		if (ret)
+			goto err_free_buf;
+	}
+
+	switch (pdata->ecc_mode) {
+	case AR934X_NFC_ECC_SOFT:
+		nand->ecc.mode = NAND_ECC_SOFT;
+		break;
+
+	case AR934X_NFC_ECC_SOFT_BCH:
+		nand->ecc.mode = NAND_ECC_SOFT_BCH;
+		break;
+
+	case AR934X_NFC_ECC_HW:
+		ret = ar934x_nfc_setup_hwecc(nfc);
+		if (ret)
+			goto err_free_buf;
+
+		break;
+
+	default:
+		dev_err(nfc->parent, "unknown ECC mode %d\n", pdata->ecc_mode);
+		return -EINVAL;
+	}
+
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(&pdev->dev, "scan tail failed, err:%d\n", ret);
+		goto err_free_buf;
+	}
+
+	memset(&ppdata, '\0', sizeof(ppdata));
+	ret = mtd_device_parse_register(mtd, part_probes, &ppdata,
+					pdata->parts, pdata->nr_parts);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register mtd, err:%d\n", ret);
+		goto err_free_buf;
+	}
+
+	return 0;
+
+err_free_buf:
+	ar934x_nfc_free_buf(nfc);
+err_free_irq:
+	free_irq(nfc->irq, nfc);
+	return ret;
+}
+
+static int
+ar934x_nfc_remove(struct platform_device *pdev)
+{
+	struct ar934x_nfc *nfc;
+
+	nfc = platform_get_drvdata(pdev);
+	if (nfc) {
+		nand_release(&nfc->mtd);
+		ar934x_nfc_free_buf(nfc);
+		free_irq(nfc->irq, nfc);
+	}
+
+	return 0;
+}
+
+static struct platform_driver ar934x_nfc_driver = {
+	.probe		= ar934x_nfc_probe,
+	.remove		= ar934x_nfc_remove,
+	.driver = {
+		.name	= AR934X_NFC_DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(ar934x_nfc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("Atheros AR934x NAND Flash Controller driver");
+MODULE_ALIAS("platform:" AR934X_NFC_DRIVER_NAME);
diff --git a/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c b/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c
new file mode 100644
index 0000000000..5b9841b76b
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c
@@ -0,0 +1,305 @@
+/*
+ *  NAND flash driver for the MikroTik RouterBoard 4xx series
+ *
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  This file was based on the driver for Linux 2.6.22 published by
+ *  MikroTik for their RouterBoard 4xx series devices.
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/rb4xx_cpld.h>
+
+#define DRV_NAME        "rb4xx-nand"
+#define DRV_VERSION     "0.2.0"
+#define DRV_DESC        "NAND flash driver for RouterBoard 4xx series"
+
+#define RB4XX_NAND_GPIO_READY	5
+#define RB4XX_NAND_GPIO_ALE	37
+#define RB4XX_NAND_GPIO_CLE	38
+#define RB4XX_NAND_GPIO_NCE	39
+
+struct rb4xx_nand_info {
+	struct nand_chip	chip;
+	struct mtd_info		mtd;
+};
+
+/*
+ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
+ * will not be able to find the kernel that we load.
+ */
+static struct nand_ecclayout rb4xx_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos		= { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static struct mtd_partition rb4xx_nand_partitions[] = {
+	{
+		.name	= "booter",
+		.offset	= 0,
+		.size	= (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	},
+	{
+		.name	= "kernel",
+		.offset	= (256 * 1024),
+		.size	= (4 * 1024 * 1024) - (256 * 1024),
+	},
+	{
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static int rb4xx_nand_dev_ready(struct mtd_info *mtd)
+{
+	return gpio_get_value_cansleep(RB4XX_NAND_GPIO_READY);
+}
+
+static void rb4xx_nand_write_cmd(unsigned char cmd)
+{
+	unsigned char data = cmd;
+	int err;
+
+	err = rb4xx_cpld_write(&data, 1);
+	if (err)
+		pr_err("rb4xx_nand: write cmd failed, err=%d\n", err);
+}
+
+static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	if (ctrl & NAND_CTRL_CHANGE) {
+		gpio_set_value_cansleep(RB4XX_NAND_GPIO_CLE,
+					(ctrl & NAND_CLE) ? 1 : 0);
+		gpio_set_value_cansleep(RB4XX_NAND_GPIO_ALE,
+					(ctrl & NAND_ALE) ? 1 : 0);
+		gpio_set_value_cansleep(RB4XX_NAND_GPIO_NCE,
+					(ctrl & NAND_NCE) ? 0 : 1);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		rb4xx_nand_write_cmd(cmd);
+}
+
+static unsigned char rb4xx_nand_read_byte(struct mtd_info *mtd)
+{
+	unsigned char data = 0;
+	int err;
+
+	err = rb4xx_cpld_read(&data, NULL, 1);
+	if (err) {
+		pr_err("rb4xx_nand: read data failed, err=%d\n", err);
+		data = 0xff;
+	}
+
+	return data;
+}
+
+static void rb4xx_nand_write_buf(struct mtd_info *mtd, const unsigned char *buf,
+				 int len)
+{
+	int err;
+
+	err = rb4xx_cpld_write(buf, len);
+	if (err)
+		pr_err("rb4xx_nand: write buf failed, err=%d\n", err);
+}
+
+static void rb4xx_nand_read_buf(struct mtd_info *mtd, unsigned char *buf,
+				int len)
+{
+	int err;
+
+	err = rb4xx_cpld_read(buf, NULL, len);
+	if (err)
+		pr_err("rb4xx_nand: read buf failed, err=%d\n", err);
+}
+
+static int rb4xx_nand_probe(struct platform_device *pdev)
+{
+	struct rb4xx_nand_info	*info;
+	int ret;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+	ret = gpio_request(RB4XX_NAND_GPIO_READY, "NAND RDY");
+	if (ret) {
+		dev_err(&pdev->dev, "unable to request gpio %d\n",
+			RB4XX_NAND_GPIO_READY);
+		goto err;
+	}
+
+	ret = gpio_direction_input(RB4XX_NAND_GPIO_READY);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to set input mode on gpio %d\n",
+			RB4XX_NAND_GPIO_READY);
+		goto err_free_gpio_ready;
+	}
+
+	ret = gpio_request(RB4XX_NAND_GPIO_ALE, "NAND ALE");
+	if (ret) {
+		dev_err(&pdev->dev, "unable to request gpio %d\n",
+			RB4XX_NAND_GPIO_ALE);
+		goto err_free_gpio_ready;
+	}
+
+	ret = gpio_direction_output(RB4XX_NAND_GPIO_ALE, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to set output mode on gpio %d\n",
+			RB4XX_NAND_GPIO_ALE);
+		goto err_free_gpio_ale;
+	}
+
+	ret = gpio_request(RB4XX_NAND_GPIO_CLE, "NAND CLE");
+	if (ret) {
+		dev_err(&pdev->dev, "unable to request gpio %d\n",
+			RB4XX_NAND_GPIO_CLE);
+		goto err_free_gpio_ale;
+	}
+
+	ret = gpio_direction_output(RB4XX_NAND_GPIO_CLE, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to set output mode on gpio %d\n",
+			RB4XX_NAND_GPIO_CLE);
+		goto err_free_gpio_cle;
+	}
+
+	ret = gpio_request(RB4XX_NAND_GPIO_NCE, "NAND NCE");
+	if (ret) {
+		dev_err(&pdev->dev, "unable to request gpio %d\n",
+			RB4XX_NAND_GPIO_NCE);
+		goto err_free_gpio_cle;
+	}
+
+	ret = gpio_direction_output(RB4XX_NAND_GPIO_NCE, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to set output mode on gpio %d\n",
+			RB4XX_NAND_GPIO_ALE);
+		goto err_free_gpio_nce;
+	}
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&pdev->dev, "rb4xx-nand: no memory for private data\n");
+		ret = -ENOMEM;
+		goto err_free_gpio_nce;
+	}
+
+	info->chip.priv	= &info;
+	info->mtd.priv	= &info->chip;
+	info->mtd.owner	= THIS_MODULE;
+
+	info->chip.cmd_ctrl	= rb4xx_nand_cmd_ctrl;
+	info->chip.dev_ready	= rb4xx_nand_dev_ready;
+	info->chip.read_byte	= rb4xx_nand_read_byte;
+	info->chip.write_buf	= rb4xx_nand_write_buf;
+	info->chip.read_buf	= rb4xx_nand_read_buf;
+
+	info->chip.chip_delay	= 25;
+	info->chip.ecc.mode	= NAND_ECC_SOFT;
+
+	platform_set_drvdata(pdev, info);
+
+	ret = nand_scan_ident(&info->mtd, 1, NULL);
+	if (ret) {
+		ret = -ENXIO;
+		goto err_free_info;
+	}
+
+	if (info->mtd.writesize == 512)
+		info->chip.ecc.layout = &rb4xx_nand_ecclayout;
+
+	ret = nand_scan_tail(&info->mtd);
+	if (ret) {
+		return -ENXIO;
+		goto err_set_drvdata;
+	}
+
+	mtd_device_register(&info->mtd, rb4xx_nand_partitions,
+				ARRAY_SIZE(rb4xx_nand_partitions));
+	if (ret)
+		goto err_release_nand;
+
+	return 0;
+
+err_release_nand:
+	nand_release(&info->mtd);
+err_set_drvdata:
+	platform_set_drvdata(pdev, NULL);
+err_free_info:
+	kfree(info);
+err_free_gpio_nce:
+	gpio_free(RB4XX_NAND_GPIO_NCE);
+err_free_gpio_cle:
+	gpio_free(RB4XX_NAND_GPIO_CLE);
+err_free_gpio_ale:
+	gpio_free(RB4XX_NAND_GPIO_ALE);
+err_free_gpio_ready:
+	gpio_free(RB4XX_NAND_GPIO_READY);
+err:
+	return ret;
+}
+
+static int rb4xx_nand_remove(struct platform_device *pdev)
+{
+	struct rb4xx_nand_info *info = platform_get_drvdata(pdev);
+
+	nand_release(&info->mtd);
+	platform_set_drvdata(pdev, NULL);
+	kfree(info);
+	gpio_free(RB4XX_NAND_GPIO_NCE);
+	gpio_free(RB4XX_NAND_GPIO_CLE);
+	gpio_free(RB4XX_NAND_GPIO_ALE);
+	gpio_free(RB4XX_NAND_GPIO_READY);
+
+	return 0;
+}
+
+static struct platform_driver rb4xx_nand_driver = {
+	.probe	= rb4xx_nand_probe,
+	.remove	= rb4xx_nand_remove,
+	.driver	= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rb4xx_nand_init(void)
+{
+	return platform_driver_register(&rb4xx_nand_driver);
+}
+
+static void __exit rb4xx_nand_exit(void)
+{
+	platform_driver_unregister(&rb4xx_nand_driver);
+}
+
+module_init(rb4xx_nand_init);
+module_exit(rb4xx_nand_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/mtd/nand/rb750_nand.c b/target/linux/ar71xx/files/drivers/mtd/nand/rb750_nand.c
new file mode 100644
index 0000000000..a20409b108
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/mtd/nand/rb750_nand.c
@@ -0,0 +1,354 @@
+/*
+ *  NAND flash driver for the MikroTik RouterBOARD 750
+ *
+ *  Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/mach-rb750.h>
+
+#define DRV_NAME	"rb750-nand"
+#define DRV_VERSION	"0.1.0"
+#define DRV_DESC	"NAND flash driver for the RouterBOARD 750"
+
+#define RB750_NAND_IO0		BIT(RB750_GPIO_NAND_IO0)
+#define RB750_NAND_ALE		BIT(RB750_GPIO_NAND_ALE)
+#define RB750_NAND_CLE		BIT(RB750_GPIO_NAND_CLE)
+#define RB750_NAND_NRE		BIT(RB750_GPIO_NAND_NRE)
+#define RB750_NAND_NWE		BIT(RB750_GPIO_NAND_NWE)
+#define RB750_NAND_RDY		BIT(RB750_GPIO_NAND_RDY)
+
+#define RB750_NAND_DATA_SHIFT	1
+#define RB750_NAND_DATA_BITS	(0xff << RB750_NAND_DATA_SHIFT)
+#define RB750_NAND_INPUT_BITS	(RB750_NAND_DATA_BITS | RB750_NAND_RDY)
+#define RB750_NAND_OUTPUT_BITS	(RB750_NAND_ALE | RB750_NAND_CLE | \
+				 RB750_NAND_NRE | RB750_NAND_NWE)
+
+struct rb750_nand_info {
+	struct nand_chip	chip;
+	struct mtd_info		mtd;
+	struct rb7xx_nand_platform_data *pdata;
+};
+
+static inline struct rb750_nand_info *mtd_to_rbinfo(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct rb750_nand_info, mtd);
+}
+
+/*
+ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
+ * will not be able to find the kernel that we load.
+ */
+static struct nand_ecclayout rb750_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos		= { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static struct mtd_partition rb750_nand_partitions[] = {
+	{
+		.name	= "booter",
+		.offset	= 0,
+		.size	= (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	}, {
+		.name	= "kernel",
+		.offset	= (256 * 1024),
+		.size	= (4 * 1024 * 1024) - (256 * 1024),
+	}, {
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static void rb750_nand_write(const u8 *buf, unsigned len)
+{
+	void __iomem *base = ath79_gpio_base;
+	u32 out;
+	u32 t;
+	unsigned i;
+
+	/* set data lines to output mode */
+	t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+	__raw_writel(t | RB750_NAND_DATA_BITS, base + AR71XX_GPIO_REG_OE);
+
+	out = __raw_readl(base + AR71XX_GPIO_REG_OUT);
+	out &= ~(RB750_NAND_DATA_BITS | RB750_NAND_NWE);
+	for (i = 0; i != len; i++) {
+		u32 data;
+
+		data = buf[i];
+		data <<= RB750_NAND_DATA_SHIFT;
+		data |= out;
+		__raw_writel(data, base + AR71XX_GPIO_REG_OUT);
+
+		__raw_writel(data | RB750_NAND_NWE, base + AR71XX_GPIO_REG_OUT);
+		/* flush write */
+		__raw_readl(base + AR71XX_GPIO_REG_OUT);
+	}
+
+	/* set data lines to input mode */
+	t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+	__raw_writel(t & ~RB750_NAND_DATA_BITS, base + AR71XX_GPIO_REG_OE);
+	/* flush write */
+	__raw_readl(base + AR71XX_GPIO_REG_OE);
+}
+
+static void rb750_nand_read(u8 *read_buf, unsigned len)
+{
+	void __iomem *base = ath79_gpio_base;
+	unsigned i;
+
+	for (i = 0; i < len; i++) {
+		u8 data;
+
+		/* activate RE line */
+		__raw_writel(RB750_NAND_NRE, base + AR71XX_GPIO_REG_CLEAR);
+		/* flush write */
+		__raw_readl(base + AR71XX_GPIO_REG_CLEAR);
+
+		/* read input lines */
+		data = __raw_readl(base + AR71XX_GPIO_REG_IN) >>
+		       RB750_NAND_DATA_SHIFT;
+
+		/* deactivate RE line */
+		__raw_writel(RB750_NAND_NRE, base + AR71XX_GPIO_REG_SET);
+
+		read_buf[i] = data;
+	}
+}
+
+static void rb750_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct rb750_nand_info *rbinfo = mtd_to_rbinfo(mtd);
+	void __iomem *base = ath79_gpio_base;
+	u32 t;
+
+	if (chip >= 0) {
+		rbinfo->pdata->enable_pins();
+
+		/* set input mode for data lines */
+		t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+		__raw_writel(t & ~RB750_NAND_INPUT_BITS,
+			     base + AR71XX_GPIO_REG_OE);
+
+		/* deactivate RE and WE lines */
+		__raw_writel(RB750_NAND_NRE | RB750_NAND_NWE,
+			     base + AR71XX_GPIO_REG_SET);
+		/* flush write */
+		(void) __raw_readl(base + AR71XX_GPIO_REG_SET);
+
+		/* activate CE line */
+		__raw_writel(rbinfo->pdata->nce_line,
+			     base + AR71XX_GPIO_REG_CLEAR);
+	} else {
+		/* deactivate CE line */
+		__raw_writel(rbinfo->pdata->nce_line,
+			     base + AR71XX_GPIO_REG_SET);
+		/* flush write */
+		(void) __raw_readl(base + AR71XX_GPIO_REG_SET);
+
+		t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+		__raw_writel(t | RB750_NAND_IO0 | RB750_NAND_RDY,
+			     base + AR71XX_GPIO_REG_OE);
+
+		rbinfo->pdata->disable_pins();
+	}
+}
+
+static int rb750_nand_dev_ready(struct mtd_info *mtd)
+{
+	void __iomem *base = ath79_gpio_base;
+
+	return !!(__raw_readl(base + AR71XX_GPIO_REG_IN) & RB750_NAND_RDY);
+}
+
+static void rb750_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	if (ctrl & NAND_CTRL_CHANGE) {
+		void __iomem *base = ath79_gpio_base;
+		u32 t;
+
+		t = __raw_readl(base + AR71XX_GPIO_REG_OUT);
+
+		t &= ~(RB750_NAND_CLE | RB750_NAND_ALE);
+		t |= (ctrl & NAND_CLE) ? RB750_NAND_CLE : 0;
+		t |= (ctrl & NAND_ALE) ? RB750_NAND_ALE : 0;
+
+		__raw_writel(t, base + AR71XX_GPIO_REG_OUT);
+		/* flush write */
+		__raw_readl(base + AR71XX_GPIO_REG_OUT);
+	}
+
+	if (cmd != NAND_CMD_NONE) {
+		u8 t = cmd;
+		rb750_nand_write(&t, 1);
+	}
+}
+
+static u8 rb750_nand_read_byte(struct mtd_info *mtd)
+{
+	u8 data = 0;
+	rb750_nand_read(&data, 1);
+	return data;
+}
+
+static void rb750_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	rb750_nand_read(buf, len);
+}
+
+static void rb750_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	rb750_nand_write(buf, len);
+}
+
+static void __init rb750_nand_gpio_init(struct rb750_nand_info *info)
+{
+	void __iomem *base = ath79_gpio_base;
+	u32 out;
+	u32 t;
+
+	out = __raw_readl(base + AR71XX_GPIO_REG_OUT);
+
+	/* setup output levels */
+	__raw_writel(RB750_NAND_NCE | RB750_NAND_NRE | RB750_NAND_NWE,
+		     base + AR71XX_GPIO_REG_SET);
+
+	__raw_writel(RB750_NAND_ALE | RB750_NAND_CLE,
+		     base + AR71XX_GPIO_REG_CLEAR);
+
+	/* setup input lines */
+	t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+	__raw_writel(t & ~(RB750_NAND_INPUT_BITS), base + AR71XX_GPIO_REG_OE);
+
+	/* setup output lines */
+	t = __raw_readl(base + AR71XX_GPIO_REG_OE);
+	t |= RB750_NAND_OUTPUT_BITS;
+	t |= info->pdata->nce_line;
+	__raw_writel(t, base + AR71XX_GPIO_REG_OE);
+
+	info->pdata->latch_change(~out & RB750_NAND_IO0, out & RB750_NAND_IO0);
+}
+
+static int rb750_nand_probe(struct platform_device *pdev)
+{
+	struct rb750_nand_info	*info;
+	struct rb7xx_nand_platform_data *pdata;
+	int ret;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->chip.priv	= &info;
+	info->mtd.priv	= &info->chip;
+	info->mtd.owner	= THIS_MODULE;
+
+	info->chip.select_chip	= rb750_nand_select_chip;
+	info->chip.cmd_ctrl	= rb750_nand_cmd_ctrl;
+	info->chip.dev_ready	= rb750_nand_dev_ready;
+	info->chip.read_byte	= rb750_nand_read_byte;
+	info->chip.write_buf	= rb750_nand_write_buf;
+	info->chip.read_buf	= rb750_nand_read_buf;
+
+	info->chip.chip_delay	= 25;
+	info->chip.ecc.mode	= NAND_ECC_SOFT;
+
+	info->pdata = pdata;
+
+	platform_set_drvdata(pdev, info);
+
+	rb750_nand_gpio_init(info);
+
+	ret = nand_scan_ident(&info->mtd, 1, NULL);
+	if (ret) {
+		ret = -ENXIO;
+		goto err_free_info;
+	}
+
+	if (info->mtd.writesize == 512)
+		info->chip.ecc.layout = &rb750_nand_ecclayout;
+
+	ret = nand_scan_tail(&info->mtd);
+	if (ret) {
+		return -ENXIO;
+		goto err_set_drvdata;
+	}
+
+	ret = mtd_device_register(&info->mtd, rb750_nand_partitions,
+				 ARRAY_SIZE(rb750_nand_partitions));
+	if (ret)
+		goto err_release_nand;
+
+	return 0;
+
+err_release_nand:
+	nand_release(&info->mtd);
+err_set_drvdata:
+	platform_set_drvdata(pdev, NULL);
+err_free_info:
+	kfree(info);
+	return ret;
+}
+
+static int rb750_nand_remove(struct platform_device *pdev)
+{
+	struct rb750_nand_info *info = platform_get_drvdata(pdev);
+
+	nand_release(&info->mtd);
+	platform_set_drvdata(pdev, NULL);
+	kfree(info);
+
+	return 0;
+}
+
+static struct platform_driver rb750_nand_driver = {
+	.probe	= rb750_nand_probe,
+	.remove	= rb750_nand_remove,
+	.driver	= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rb750_nand_init(void)
+{
+	return platform_driver_register(&rb750_nand_driver);
+}
+
+static void __exit rb750_nand_exit(void)
+{
+	platform_driver_unregister(&rb750_nand_driver);
+}
+
+module_init(rb750_nand_init);
+module_exit(rb750_nand_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/mtd/nand/rb91x_nand.c b/target/linux/ar71xx/files/drivers/mtd/nand/rb91x_nand.c
new file mode 100644
index 0000000000..f0aa3c3e79
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/mtd/nand/rb91x_nand.c
@@ -0,0 +1,377 @@
+/*
+ *  NAND flash driver for the MikroTik RouterBOARD 91x series
+ *
+ *  Copyright (C) 2013-2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/rb91x_nand.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#define DRV_DESC	"NAND flash driver for the RouterBOARD 91x series"
+
+#define RB91X_NAND_NRWE		BIT(12)
+
+#define RB91X_NAND_DATA_BITS	(BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) |\
+				 BIT(13) | BIT(14) | BIT(15))
+
+#define RB91X_NAND_INPUT_BITS	(RB91X_NAND_DATA_BITS | RB91X_NAND_RDY)
+#define RB91X_NAND_OUTPUT_BITS	(RB91X_NAND_DATA_BITS | RB91X_NAND_NRWE)
+
+#define RB91X_NAND_LOW_DATA_MASK	0x1f
+#define RB91X_NAND_HIGH_DATA_MASK	0xe0
+#define RB91X_NAND_HIGH_DATA_SHIFT	8
+
+struct rb91x_nand_info {
+	struct nand_chip chip;
+	struct mtd_info mtd;
+	struct device *dev;
+
+	int gpio_nce;
+	int gpio_ale;
+	int gpio_cle;
+	int gpio_rdy;
+	int gpio_read;
+	int gpio_nrw;
+	int gpio_nle;
+};
+
+static inline struct rb91x_nand_info *mtd_to_rbinfo(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct rb91x_nand_info, mtd);
+}
+
+/*
+ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
+ * will not be able to find the kernel that we load.
+ */
+static struct nand_ecclayout rb91x_nand_ecclayout = {
+	.eccbytes	= 6,
+	.eccpos		= { 8, 9, 10, 13, 14, 15 },
+	.oobavail	= 9,
+	.oobfree	= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+
+static struct mtd_partition rb91x_nand_partitions[] = {
+	{
+		.name	= "booter",
+		.offset	= 0,
+		.size	= (256 * 1024),
+		.mask_flags = MTD_WRITEABLE,
+	}, {
+		.name	= "kernel",
+		.offset	= (256 * 1024),
+		.size	= (4 * 1024 * 1024) - (256 * 1024),
+	}, {
+		.name	= "rootfs",
+		.offset	= MTDPART_OFS_NXTBLK,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static void rb91x_nand_write(struct rb91x_nand_info *rbni,
+			     const u8 *buf,
+			     unsigned len)
+{
+	void __iomem *base = ath79_gpio_base;
+	u32 oe_reg;
+	u32 out_reg;
+	u32 out;
+	unsigned i;
+
+	/* enable the latch */
+	gpio_set_value_cansleep(rbni->gpio_nle, 0);
+
+	oe_reg = __raw_readl(base + AR71XX_GPIO_REG_OE);
+	out_reg = __raw_readl(base + AR71XX_GPIO_REG_OUT);
+
+	/* set data lines to output mode */
+	__raw_writel(oe_reg & ~(RB91X_NAND_DATA_BITS | RB91X_NAND_NRWE),
+		     base + AR71XX_GPIO_REG_OE);
+
+	out = out_reg & ~(RB91X_NAND_DATA_BITS | RB91X_NAND_NRWE);
+	for (i = 0; i != len; i++) {
+		u32 data;
+
+		data = (buf[i] & RB91X_NAND_HIGH_DATA_MASK) <<
+			RB91X_NAND_HIGH_DATA_SHIFT;
+		data |= buf[i] & RB91X_NAND_LOW_DATA_MASK;
+		data |= out;
+		__raw_writel(data, base + AR71XX_GPIO_REG_OUT);
+
+		/* deactivate WE line */
+		data |= RB91X_NAND_NRWE;
+		__raw_writel(data, base + AR71XX_GPIO_REG_OUT);
+		/* flush write */
+		__raw_readl(base + AR71XX_GPIO_REG_OUT);
+	}
+
+	/* restore  registers */
+	__raw_writel(out_reg, base + AR71XX_GPIO_REG_OUT);
+	__raw_writel(oe_reg, base + AR71XX_GPIO_REG_OE);
+	/* flush write */
+	__raw_readl(base + AR71XX_GPIO_REG_OUT);
+
+	/* disable the latch */
+	gpio_set_value_cansleep(rbni->gpio_nle, 1);
+}
+
+static void rb91x_nand_read(struct rb91x_nand_info *rbni,
+			    u8 *read_buf,
+			    unsigned len)
+{
+	void __iomem *base = ath79_gpio_base;
+	u32 oe_reg;
+	u32 out_reg;
+	unsigned i;
+
+	/* enable read mode */
+	gpio_set_value_cansleep(rbni->gpio_read, 1);
+
+	/* enable latch */
+	gpio_set_value_cansleep(rbni->gpio_nle, 0);
+
+	/* save registers */
+	oe_reg = __raw_readl(base + AR71XX_GPIO_REG_OE);
+	out_reg = __raw_readl(base + AR71XX_GPIO_REG_OUT);
+
+	/* set data lines to input mode */
+	__raw_writel(oe_reg | RB91X_NAND_DATA_BITS,
+		     base + AR71XX_GPIO_REG_OE);
+
+	for (i = 0; i < len; i++) {
+		u32 in;
+		u8 data;
+
+		/* activate RE line */
+		__raw_writel(RB91X_NAND_NRWE, base + AR71XX_GPIO_REG_CLEAR);
+		/* flush write */
+		__raw_readl(base + AR71XX_GPIO_REG_CLEAR);
+
+		/* read input lines */
+		in = __raw_readl(base + AR71XX_GPIO_REG_IN);
+
+		/* deactivate RE line */
+		__raw_writel(RB91X_NAND_NRWE, base + AR71XX_GPIO_REG_SET);
+
+		data = (in & RB91X_NAND_LOW_DATA_MASK);
+		data |= (in >> RB91X_NAND_HIGH_DATA_SHIFT) &
+			RB91X_NAND_HIGH_DATA_MASK;
+
+		read_buf[i] = data;
+	}
+
+	/* restore  registers */
+	__raw_writel(out_reg, base + AR71XX_GPIO_REG_OUT);
+	__raw_writel(oe_reg, base + AR71XX_GPIO_REG_OE);
+	/* flush write */
+	__raw_readl(base + AR71XX_GPIO_REG_OUT);
+
+	/* disable latch */
+	gpio_set_value_cansleep(rbni->gpio_nle, 1);
+
+	/* disable read mode */
+	gpio_set_value_cansleep(rbni->gpio_read, 0);
+}
+
+static int rb91x_nand_dev_ready(struct mtd_info *mtd)
+{
+	struct rb91x_nand_info *rbni = mtd_to_rbinfo(mtd);
+
+	return gpio_get_value_cansleep(rbni->gpio_rdy);
+}
+
+static void rb91x_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				unsigned int ctrl)
+{
+	struct rb91x_nand_info *rbni = mtd_to_rbinfo(mtd);
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		gpio_set_value_cansleep(rbni->gpio_cle,
+					(ctrl & NAND_CLE) ? 1 : 0);
+		gpio_set_value_cansleep(rbni->gpio_ale,
+					(ctrl & NAND_ALE) ? 1 : 0);
+		gpio_set_value_cansleep(rbni->gpio_nce,
+					(ctrl & NAND_NCE) ? 0 : 1);
+	}
+
+	if (cmd != NAND_CMD_NONE) {
+		u8 t = cmd;
+
+		rb91x_nand_write(rbni, &t, 1);
+	}
+}
+
+static u8 rb91x_nand_read_byte(struct mtd_info *mtd)
+{
+	struct rb91x_nand_info *rbni = mtd_to_rbinfo(mtd);
+	u8 data = 0xff;
+
+	rb91x_nand_read(rbni, &data, 1);
+
+	return data;
+}
+
+static void rb91x_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct rb91x_nand_info *rbni = mtd_to_rbinfo(mtd);
+
+	rb91x_nand_read(rbni, buf, len);
+}
+
+static void rb91x_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct rb91x_nand_info *rbni = mtd_to_rbinfo(mtd);
+
+	rb91x_nand_write(rbni, buf, len);
+}
+
+static int rb91x_nand_gpio_init(struct rb91x_nand_info *info)
+{
+	int ret;
+
+	/*
+	 * Ensure that the LATCH is disabled before initializing
+	 * control lines.
+	 */
+	ret = devm_gpio_request_one(info->dev, info->gpio_nle,
+				    GPIOF_OUT_INIT_HIGH, "LATCH enable");
+	if (ret)
+		return ret;
+
+	ret = devm_gpio_request_one(info->dev, info->gpio_nce,
+				    GPIOF_OUT_INIT_HIGH, "NAND nCE");
+	if (ret)
+		return ret;
+
+	ret = devm_gpio_request_one(info->dev, info->gpio_nrw,
+				    GPIOF_OUT_INIT_HIGH, "NAND nRW");
+	if (ret)
+		return ret;
+
+	ret = devm_gpio_request_one(info->dev, info->gpio_cle,
+				    GPIOF_OUT_INIT_LOW, "NAND CLE");
+	if (ret)
+		return ret;
+
+	ret = devm_gpio_request_one(info->dev, info->gpio_ale,
+				    GPIOF_OUT_INIT_LOW, "NAND ALE");
+	if (ret)
+		return ret;
+
+	ret = devm_gpio_request_one(info->dev, info->gpio_read,
+				    GPIOF_OUT_INIT_LOW, "NAND READ");
+	if (ret)
+		return ret;
+
+	ret = devm_gpio_request_one(info->dev, info->gpio_rdy,
+				    GPIOF_IN, "NAND RDY");
+	return ret;
+}
+
+static int rb91x_nand_probe(struct platform_device *pdev)
+{
+	struct rb91x_nand_info	*rbni;
+	struct rb91x_nand_platform_data *pdata;
+	int ret;
+
+	pr_info(DRV_DESC "\n");
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata)
+		return -EINVAL;
+
+	rbni = devm_kzalloc(&pdev->dev, sizeof(*rbni), GFP_KERNEL);
+	if (!rbni)
+		return -ENOMEM;
+
+	rbni->dev = &pdev->dev;
+	rbni->gpio_nce = pdata->gpio_nce;
+	rbni->gpio_ale = pdata->gpio_ale;
+	rbni->gpio_cle = pdata->gpio_cle;
+	rbni->gpio_read = pdata->gpio_read;
+	rbni->gpio_nrw = pdata->gpio_nrw;
+	rbni->gpio_rdy = pdata->gpio_rdy;
+	rbni->gpio_nle = pdata->gpio_nle;
+
+	rbni->chip.priv	= &rbni;
+	rbni->mtd.priv	= &rbni->chip;
+	rbni->mtd.owner	= THIS_MODULE;
+
+	rbni->chip.cmd_ctrl	= rb91x_nand_cmd_ctrl;
+	rbni->chip.dev_ready	= rb91x_nand_dev_ready;
+	rbni->chip.read_byte	= rb91x_nand_read_byte;
+	rbni->chip.write_buf	= rb91x_nand_write_buf;
+	rbni->chip.read_buf	= rb91x_nand_read_buf;
+
+	rbni->chip.chip_delay	= 25;
+	rbni->chip.ecc.mode	= NAND_ECC_SOFT;
+
+	platform_set_drvdata(pdev, rbni);
+
+	ret = rb91x_nand_gpio_init(rbni);
+	if (ret)
+		return ret;
+
+	ret = nand_scan_ident(&rbni->mtd, 1, NULL);
+	if (ret)
+		return ret;
+
+	if (rbni->mtd.writesize == 512)
+		rbni->chip.ecc.layout = &rb91x_nand_ecclayout;
+
+	ret = nand_scan_tail(&rbni->mtd);
+	if (ret)
+		return ret;
+
+	ret = mtd_device_register(&rbni->mtd, rb91x_nand_partitions,
+				 ARRAY_SIZE(rb91x_nand_partitions));
+	if (ret)
+		goto err_release_nand;
+
+	return 0;
+
+err_release_nand:
+	nand_release(&rbni->mtd);
+	return ret;
+}
+
+static int rb91x_nand_remove(struct platform_device *pdev)
+{
+	struct rb91x_nand_info *info = platform_get_drvdata(pdev);
+
+	nand_release(&info->mtd);
+
+	return 0;
+}
+
+static struct platform_driver rb91x_nand_driver = {
+	.probe	= rb91x_nand_probe,
+	.remove	= rb91x_nand_remove,
+	.driver	= {
+		.name	= RB91X_NAND_DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(rb91x_nand_driver);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/mtd/tplinkpart.c b/target/linux/ar71xx/files/drivers/mtd/tplinkpart.c
new file mode 100644
index 0000000000..ac1efa1c22
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/mtd/tplinkpart.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/magic.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define TPLINK_NUM_PARTS	5
+#define TPLINK_HEADER_V1	0x01000000
+#define TPLINK_HEADER_V2	0x02000000
+#define MD5SUM_LEN		16
+
+#define TPLINK_ART_LEN		0x10000
+#define TPLINK_KERNEL_OFFS	0x20000
+#define TPLINK_64K_KERNEL_OFFS	0x10000
+
+struct tplink_fw_header {
+	uint32_t	version;	/* header version */
+	char		vendor_name[24];
+	char		fw_version[36];
+	uint32_t	hw_id;		/* hardware id */
+	uint32_t	hw_rev;		/* hardware revision */
+	uint32_t	unk1;
+	uint8_t		md5sum1[MD5SUM_LEN];
+	uint32_t	unk2;
+	uint8_t		md5sum2[MD5SUM_LEN];
+	uint32_t	unk3;
+	uint32_t	kernel_la;	/* kernel load address */
+	uint32_t	kernel_ep;	/* kernel entry point */
+	uint32_t	fw_length;	/* total length of the firmware */
+	uint32_t	kernel_ofs;	/* kernel data offset */
+	uint32_t	kernel_len;	/* kernel data length */
+	uint32_t	rootfs_ofs;	/* rootfs data offset */
+	uint32_t	rootfs_len;	/* rootfs data length */
+	uint32_t	boot_ofs;	/* bootloader data offset */
+	uint32_t	boot_len;	/* bootloader data length */
+	uint8_t		pad[360];
+} __attribute__ ((packed));
+
+static struct tplink_fw_header *
+tplink_read_header(struct mtd_info *mtd, size_t offset)
+{
+	struct tplink_fw_header *header;
+	size_t header_len;
+	size_t retlen;
+	int ret;
+	u32 t;
+
+	header = vmalloc(sizeof(*header));
+	if (!header)
+		goto err;
+
+	header_len = sizeof(struct tplink_fw_header);
+	ret = mtd_read(mtd, offset, header_len, &retlen,
+		       (unsigned char *) header);
+	if (ret)
+		goto err_free_header;
+
+	if (retlen != header_len)
+		goto err_free_header;
+
+	/* sanity checks */
+	t = be32_to_cpu(header->version);
+	if ((t != TPLINK_HEADER_V1) && (t != TPLINK_HEADER_V2))
+		goto err_free_header;
+
+	t = be32_to_cpu(header->kernel_ofs);
+	if (t != header_len)
+		goto err_free_header;
+
+	return header;
+
+err_free_header:
+	vfree(header);
+err:
+	return NULL;
+}
+
+static int tplink_check_rootfs_magic(struct mtd_info *mtd, size_t offset)
+{
+	u32 magic;
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, sizeof(magic), &retlen,
+		       (unsigned char *) &magic);
+	if (ret)
+		return ret;
+
+	if (retlen != sizeof(magic))
+		return -EIO;
+
+	if (le32_to_cpu(magic) != SQUASHFS_MAGIC &&
+	    magic != 0x19852003)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int tplink_parse_partitions_offset(struct mtd_info *master,
+				   struct mtd_partition **pparts,
+				   struct mtd_part_parser_data *data,
+				   size_t offset)
+{
+	struct mtd_partition *parts;
+	struct tplink_fw_header *header;
+	int nr_parts;
+	size_t art_offset;
+	size_t rootfs_offset;
+	size_t squashfs_offset;
+	int ret;
+
+	nr_parts = TPLINK_NUM_PARTS;
+	parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL);
+	if (!parts) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	header = tplink_read_header(master, offset);
+	if (!header) {
+		pr_notice("%s: no TP-Link header found\n", master->name);
+		ret = -ENODEV;
+		goto err_free_parts;
+	}
+
+	squashfs_offset = offset + sizeof(struct tplink_fw_header) +
+			  be32_to_cpu(header->kernel_len);
+
+	ret = tplink_check_rootfs_magic(master, squashfs_offset);
+	if (ret == 0)
+		rootfs_offset = squashfs_offset;
+	else
+		rootfs_offset = offset + be32_to_cpu(header->rootfs_ofs);
+
+	art_offset = master->size - TPLINK_ART_LEN;
+
+	parts[0].name = "u-boot";
+	parts[0].offset = 0;
+	parts[0].size = offset;
+	parts[0].mask_flags = MTD_WRITEABLE;
+
+	parts[1].name = "kernel";
+	parts[1].offset = offset;
+	parts[1].size = rootfs_offset - offset;
+
+	parts[2].name = "rootfs";
+	parts[2].offset = rootfs_offset;
+	parts[2].size = art_offset - rootfs_offset;
+
+	parts[3].name = "art";
+	parts[3].offset = art_offset;
+	parts[3].size = TPLINK_ART_LEN;
+	parts[3].mask_flags = MTD_WRITEABLE;
+
+	parts[4].name = "firmware";
+	parts[4].offset = offset;
+	parts[4].size = art_offset - offset;
+
+	vfree(header);
+
+	*pparts = parts;
+	return nr_parts;
+
+err_free_parts:
+	kfree(parts);
+err:
+	*pparts = NULL;
+	return ret;
+}
+
+static int tplink_parse_partitions(struct mtd_info *master,
+				   struct mtd_partition **pparts,
+				   struct mtd_part_parser_data *data)
+{
+	return tplink_parse_partitions_offset(master, pparts, data,
+		                              TPLINK_KERNEL_OFFS);
+}
+
+static int tplink_parse_64k_partitions(struct mtd_info *master,
+				   struct mtd_partition **pparts,
+				   struct mtd_part_parser_data *data)
+{
+	return tplink_parse_partitions_offset(master, pparts, data,
+		                              TPLINK_64K_KERNEL_OFFS);
+}
+
+static struct mtd_part_parser tplink_parser = {
+	.owner		= THIS_MODULE,
+	.parse_fn	= tplink_parse_partitions,
+	.name		= "tp-link",
+};
+
+static struct mtd_part_parser tplink_64k_parser = {
+	.owner		= THIS_MODULE,
+	.parse_fn	= tplink_parse_64k_partitions,
+	.name		= "tp-link-64k",
+};
+
+static int __init tplink_parser_init(void)
+{
+	register_mtd_parser(&tplink_parser);
+	register_mtd_parser(&tplink_64k_parser);
+
+	return 0;
+}
+
+module_init(tplink_parser_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
diff --git a/target/linux/ar71xx/files/drivers/net/dsa/mv88e6063.c b/target/linux/ar71xx/files/drivers/net/dsa/mv88e6063.c
new file mode 100644
index 0000000000..b9e9af35b8
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/dsa/mv88e6063.c
@@ -0,0 +1,311 @@
+/*
+ * net/dsa/mv88e6063.c - Driver for Marvell 88e6063 switch chips
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This driver was base on: net/dsa/mv88e6060.c
+ *   net/dsa/mv88e6063.c - Driver for Marvell 88e6060 switch chips
+ *   Copyright (c) 2008-2009 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <net/dsa.h>
+
+#define REG_BASE		0x10
+#define REG_PHY(p)		(REG_BASE + (p))
+#define REG_PORT(p)		(REG_BASE + 8 + (p))
+#define REG_GLOBAL		(REG_BASE + 0x0f)
+#define NUM_PORTS		7
+
+static int reg_read(struct dsa_switch *ds, int addr, int reg)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
+	return mdiobus_read(ds->master_mii_bus, addr, reg);
+#else
+	struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
+	return mdiobus_read(bus, addr, reg);
+#endif
+}
+
+#define REG_READ(addr, reg)					\
+	({							\
+		int __ret;					\
+								\
+		__ret = reg_read(ds, addr, reg);		\
+		if (__ret < 0)					\
+			return __ret;				\
+		__ret;						\
+	})
+
+
+static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
+	return mdiobus_write(ds->master_mii_bus, addr, reg, val);
+#else
+	struct mii_bus *bus = dsa_host_dev_to_mii_bus(ds->master_dev);
+	return mdiobus_write(bus, addr, reg, val);
+#endif
+}
+
+#define REG_WRITE(addr, reg, val)				\
+	({							\
+		int __ret;					\
+								\
+		__ret = reg_write(ds, addr, reg, val);		\
+		if (__ret < 0)					\
+			return __ret;				\
+	})
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
+static char *mv88e6063_probe(struct mii_bus *bus, int sw_addr)
+{
+#else
+static char *mv88e6063_probe(struct device *host_dev, int sw_addr)
+{
+	struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
+#endif
+	int ret;
+
+	ret = mdiobus_read(bus, REG_PORT(0), 0x03);
+	if (ret >= 0) {
+		ret &= 0xfff0;
+		if (ret == 0x1530)
+			return "Marvell 88E6063";
+	}
+
+	return NULL;
+}
+
+static int mv88e6063_switch_reset(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	/*
+	 * Set all ports to the disabled state.
+	 */
+	for (i = 0; i < NUM_PORTS; i++) {
+		ret = REG_READ(REG_PORT(i), 0x04);
+		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+	}
+
+	/*
+	 * Wait for transmit queues to drain.
+	 */
+	msleep(2);
+
+	/*
+	 * Reset the switch.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
+
+	/*
+	 * Wait up to one second for reset to complete.
+	 */
+	for (i = 0; i < 1000; i++) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		if ((ret & 0x8000) == 0x0000)
+			break;
+
+		msleep(1);
+	}
+	if (i == 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mv88e6063_setup_global(struct dsa_switch *ds)
+{
+	/*
+	 * Disable discarding of frames with excessive collisions,
+	 * set the maximum frame size to 1536 bytes, and mask all
+	 * interrupt sources.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
+
+	/*
+	 * Enable automatic address learning, set the address
+	 * database size to 1024 entries, and set the default aging
+	 * time to 5 minutes.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
+
+	return 0;
+}
+
+static int mv88e6063_setup_port(struct dsa_switch *ds, int p)
+{
+	int addr = REG_PORT(p);
+
+	/*
+	 * Do not force flow control, disable Ingress and Egress
+	 * Header tagging, disable VLAN tunneling, and set the port
+	 * state to Forwarding.  Additionally, if this is the CPU
+	 * port, enable Ingress and Egress Trailer tagging mode.
+	 */
+	REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
+
+	/*
+	 * Port based VLAN map: give each port its own address
+	 * database, allow the CPU port to talk to each of the 'real'
+	 * ports, and allow each of the 'real' ports to only talk to
+	 * the CPU port.
+	 */
+	REG_WRITE(addr, 0x06,
+			((p & 0xf) << 12) |
+			 (dsa_is_cpu_port(ds, p) ?
+				ds->phys_port_mask :
+				(1 << ds->dst->cpu_port)));
+
+	/*
+	 * Port Association Vector: when learning source addresses
+	 * of packets, add the address to the address database using
+	 * a port bitmap that has only the bit for this port set and
+	 * the other bits clear.
+	 */
+	REG_WRITE(addr, 0x0b, 1 << p);
+
+	return 0;
+}
+
+static int mv88e6063_setup(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	ret = mv88e6063_switch_reset(ds);
+	if (ret < 0)
+		return ret;
+
+	/* @@@ initialise atu */
+
+	ret = mv88e6063_setup_global(ds);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < NUM_PORTS; i++) {
+		ret = mv88e6063_setup_port(ds, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mv88e6063_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+	REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
+	REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
+	REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
+
+	return 0;
+}
+
+static int mv88e6063_port_to_phy_addr(int port)
+{
+	if (port >= 0 && port <= NUM_PORTS)
+		return REG_PHY(port);
+	return -1;
+}
+
+static int mv88e6063_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	int addr;
+
+	addr = mv88e6063_port_to_phy_addr(port);
+	if (addr == -1)
+		return 0xffff;
+
+	return reg_read(ds, addr, regnum);
+}
+
+static int
+mv88e6063_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
+{
+	int addr;
+
+	addr = mv88e6063_port_to_phy_addr(port);
+	if (addr == -1)
+		return 0xffff;
+
+	return reg_write(ds, addr, regnum, val);
+}
+
+static void mv88e6063_poll_link(struct dsa_switch *ds)
+{
+	int i;
+
+	for (i = 0; i < DSA_MAX_PORTS; i++) {
+		struct net_device *dev;
+		int uninitialized_var(port_status);
+		int link;
+		int speed;
+		int duplex;
+		int fc;
+
+		dev = ds->ports[i];
+		if (dev == NULL)
+			continue;
+
+		link = 0;
+		if (dev->flags & IFF_UP) {
+			port_status = reg_read(ds, REG_PORT(i), 0x00);
+			if (port_status < 0)
+				continue;
+
+			link = !!(port_status & 0x1000);
+		}
+
+		if (!link) {
+			if (netif_carrier_ok(dev)) {
+				printk(KERN_INFO "%s: link down\n", dev->name);
+				netif_carrier_off(dev);
+			}
+			continue;
+		}
+
+		speed = (port_status & 0x0100) ? 100 : 10;
+		duplex = (port_status & 0x0200) ? 1 : 0;
+		fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
+
+		if (!netif_carrier_ok(dev)) {
+			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
+					 "flow control %sabled\n", dev->name,
+					 speed, duplex ? "full" : "half",
+					 fc ? "en" : "dis");
+			netif_carrier_on(dev);
+		}
+	}
+}
+
+static struct dsa_switch_driver mv88e6063_switch_driver = {
+	.tag_protocol	= htons(ETH_P_TRAILER),
+	.probe		= mv88e6063_probe,
+	.setup		= mv88e6063_setup,
+	.set_addr	= mv88e6063_set_addr,
+	.phy_read	= mv88e6063_phy_read,
+	.phy_write	= mv88e6063_phy_write,
+	.poll_link	= mv88e6063_poll_link,
+};
+
+static int __init mv88e6063_init(void)
+{
+	register_switch_driver(&mv88e6063_switch_driver);
+	return 0;
+}
+module_init(mv88e6063_init);
+
+static void __exit mv88e6063_cleanup(void)
+{
+	unregister_switch_driver(&mv88e6063_switch_driver);
+}
+module_exit(mv88e6063_cleanup);
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Kconfig b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Kconfig
new file mode 100644
index 0000000000..42d544f731
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Kconfig
@@ -0,0 +1,33 @@
+config AG71XX
+	tristate "Atheros AR7XXX/AR9XXX built-in ethernet mac support"
+	depends on ATH79
+	select PHYLIB
+	help
+	  If you wish to compile a kernel for AR7XXX/91XXX and enable
+	  ethernet support, then you should always answer Y to this.
+
+if AG71XX
+
+config AG71XX_DEBUG
+	bool "Atheros AR71xx built-in ethernet driver debugging"
+	default n
+	help
+	  Atheros AR71xx built-in ethernet driver debugging messages.
+
+config AG71XX_DEBUG_FS
+	bool "Atheros AR71xx built-in ethernet driver debugfs support"
+	depends on DEBUG_FS
+	default n
+	help
+	  Say Y, if you need access to various statistics provided by
+	  the ag71xx driver.
+
+config AG71XX_AR8216_SUPPORT
+	bool "special support for the Atheros AR8216 switch"
+	default n
+	default y if ATH79_MACH_WNR2000 || ATH79_MACH_MZK_W04NU
+	help
+	  Say 'y' here if you want to enable special support for the
+	  Atheros AR8216 switch found on some boards.
+
+endif
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Makefile b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Makefile
new file mode 100644
index 0000000000..b3ec4084c8
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Atheros AR71xx built-in ethernet macs
+#
+
+ag71xx-y	+= ag71xx_main.o
+ag71xx-y	+= ag71xx_ethtool.o
+ag71xx-y	+= ag71xx_phy.o
+ag71xx-y	+= ag71xx_mdio.o
+ag71xx-y	+= ag71xx_ar7240.o
+
+ag71xx-$(CONFIG_AG71XX_DEBUG_FS)	+= ag71xx_debugfs.o
+ag71xx-$(CONFIG_AG71XX_AR8216_SUPPORT)	+= ag71xx_ar8216.o
+
+obj-$(CONFIG_AG71XX)	+= ag71xx.o
+
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
new file mode 100644
index 0000000000..898bde1d25
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
@@ -0,0 +1,493 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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.
+ */
+
+#ifndef __AG71XX_H
+#define __AG71XX_H
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+
+#include <linux/bitops.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ag71xx_platform.h>
+
+#define AG71XX_DRV_NAME		"ag71xx"
+#define AG71XX_DRV_VERSION	"0.5.35"
+
+#define AG71XX_NAPI_WEIGHT	64
+#define AG71XX_OOM_REFILL	(1 + HZ/10)
+
+#define AG71XX_INT_ERR	(AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
+#define AG71XX_INT_TX	(AG71XX_INT_TX_PS)
+#define AG71XX_INT_RX	(AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
+
+#define AG71XX_INT_POLL	(AG71XX_INT_RX | AG71XX_INT_TX)
+#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL)
+
+#define AG71XX_TX_MTU_LEN	1540
+
+#define AG71XX_TX_RING_SPLIT		512
+#define AG71XX_TX_RING_DS_PER_PKT	DIV_ROUND_UP(AG71XX_TX_MTU_LEN, \
+						     AG71XX_TX_RING_SPLIT)
+#define AG71XX_TX_RING_SIZE_DEFAULT	128
+#define AG71XX_RX_RING_SIZE_DEFAULT	256
+
+#define AG71XX_TX_RING_SIZE_MAX		128
+#define AG71XX_RX_RING_SIZE_MAX		256
+
+#ifdef CONFIG_AG71XX_DEBUG
+#define DBG(fmt, args...)	pr_debug(fmt, ## args)
+#else
+#define DBG(fmt, args...)	do {} while (0)
+#endif
+
+#define ag71xx_assert(_cond)						\
+do {									\
+	if (_cond)							\
+		break;							\
+	printk("%s,%d: assertion failed\n", __FILE__, __LINE__);	\
+	BUG();								\
+} while (0)
+
+struct ag71xx_desc {
+	u32	data;
+	u32	ctrl;
+#define DESC_EMPTY	BIT(31)
+#define DESC_MORE	BIT(24)
+#define DESC_PKTLEN_M	0xfff
+	u32	next;
+	u32	pad;
+} __attribute__((aligned(4)));
+
+#define AG71XX_DESC_SIZE	roundup(sizeof(struct ag71xx_desc), \
+					L1_CACHE_BYTES)
+
+struct ag71xx_buf {
+	union {
+		struct sk_buff	*skb;
+		void		*rx_buf;
+	};
+	union {
+		dma_addr_t	dma_addr;
+		unsigned long	timestamp;
+	};
+	unsigned int		len;
+};
+
+struct ag71xx_ring {
+	struct ag71xx_buf	*buf;
+	u8			*descs_cpu;
+	dma_addr_t		descs_dma;
+	u16			desc_split;
+	u16			order;
+	unsigned int		curr;
+	unsigned int		dirty;
+};
+
+struct ag71xx_mdio {
+	struct mii_bus		*mii_bus;
+	int			mii_irq[PHY_MAX_ADDR];
+	void __iomem		*mdio_base;
+	struct ag71xx_mdio_platform_data *pdata;
+};
+
+struct ag71xx_int_stats {
+	unsigned long		rx_pr;
+	unsigned long		rx_be;
+	unsigned long		rx_of;
+	unsigned long		tx_ps;
+	unsigned long		tx_be;
+	unsigned long		tx_ur;
+	unsigned long		total;
+};
+
+struct ag71xx_napi_stats {
+	unsigned long		napi_calls;
+	unsigned long		rx_count;
+	unsigned long		rx_packets;
+	unsigned long		rx_packets_max;
+	unsigned long		tx_count;
+	unsigned long		tx_packets;
+	unsigned long		tx_packets_max;
+
+	unsigned long		rx[AG71XX_NAPI_WEIGHT + 1];
+	unsigned long		tx[AG71XX_NAPI_WEIGHT + 1];
+};
+
+struct ag71xx_debug {
+	struct dentry		*debugfs_dir;
+
+	struct ag71xx_int_stats int_stats;
+	struct ag71xx_napi_stats napi_stats;
+};
+
+struct ag71xx {
+	void __iomem		*mac_base;
+
+	spinlock_t		lock;
+	struct platform_device	*pdev;
+	struct net_device	*dev;
+	struct napi_struct	napi;
+	u32			msg_enable;
+
+	struct ag71xx_desc	*stop_desc;
+	dma_addr_t		stop_desc_dma;
+
+	struct ag71xx_ring	rx_ring;
+	struct ag71xx_ring	tx_ring;
+
+	struct mii_bus		*mii_bus;
+	struct phy_device	*phy_dev;
+	void			*phy_priv;
+
+	unsigned int		link;
+	unsigned int		speed;
+	int			duplex;
+
+	unsigned int		max_frame_len;
+	unsigned int		desc_pktlen_mask;
+	unsigned int		rx_buf_size;
+
+	struct delayed_work	restart_work;
+	struct delayed_work	link_work;
+	struct timer_list	oom_timer;
+
+#ifdef CONFIG_AG71XX_DEBUG_FS
+	struct ag71xx_debug	debug;
+#endif
+};
+
+extern struct ethtool_ops ag71xx_ethtool_ops;
+void ag71xx_link_adjust(struct ag71xx *ag);
+
+int ag71xx_mdio_driver_init(void) __init;
+void ag71xx_mdio_driver_exit(void);
+
+int ag71xx_phy_connect(struct ag71xx *ag);
+void ag71xx_phy_disconnect(struct ag71xx *ag);
+void ag71xx_phy_start(struct ag71xx *ag);
+void ag71xx_phy_stop(struct ag71xx *ag);
+
+static inline struct ag71xx_platform_data *ag71xx_get_pdata(struct ag71xx *ag)
+{
+	return ag->pdev->dev.platform_data;
+}
+
+static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
+{
+	return (desc->ctrl & DESC_EMPTY) != 0;
+}
+
+static inline struct ag71xx_desc *
+ag71xx_ring_desc(struct ag71xx_ring *ring, int idx)
+{
+	return (struct ag71xx_desc *) &ring->descs_cpu[idx * AG71XX_DESC_SIZE];
+}
+
+static inline int
+ag71xx_ring_size_order(int size)
+{
+	return fls(size - 1);
+}
+
+/* Register offsets */
+#define AG71XX_REG_MAC_CFG1	0x0000
+#define AG71XX_REG_MAC_CFG2	0x0004
+#define AG71XX_REG_MAC_IPG	0x0008
+#define AG71XX_REG_MAC_HDX	0x000c
+#define AG71XX_REG_MAC_MFL	0x0010
+#define AG71XX_REG_MII_CFG	0x0020
+#define AG71XX_REG_MII_CMD	0x0024
+#define AG71XX_REG_MII_ADDR	0x0028
+#define AG71XX_REG_MII_CTRL	0x002c
+#define AG71XX_REG_MII_STATUS	0x0030
+#define AG71XX_REG_MII_IND	0x0034
+#define AG71XX_REG_MAC_IFCTL	0x0038
+#define AG71XX_REG_MAC_ADDR1	0x0040
+#define AG71XX_REG_MAC_ADDR2	0x0044
+#define AG71XX_REG_FIFO_CFG0	0x0048
+#define AG71XX_REG_FIFO_CFG1	0x004c
+#define AG71XX_REG_FIFO_CFG2	0x0050
+#define AG71XX_REG_FIFO_CFG3	0x0054
+#define AG71XX_REG_FIFO_CFG4	0x0058
+#define AG71XX_REG_FIFO_CFG5	0x005c
+#define AG71XX_REG_FIFO_RAM0	0x0060
+#define AG71XX_REG_FIFO_RAM1	0x0064
+#define AG71XX_REG_FIFO_RAM2	0x0068
+#define AG71XX_REG_FIFO_RAM3	0x006c
+#define AG71XX_REG_FIFO_RAM4	0x0070
+#define AG71XX_REG_FIFO_RAM5	0x0074
+#define AG71XX_REG_FIFO_RAM6	0x0078
+#define AG71XX_REG_FIFO_RAM7	0x007c
+
+#define AG71XX_REG_TX_CTRL	0x0180
+#define AG71XX_REG_TX_DESC	0x0184
+#define AG71XX_REG_TX_STATUS	0x0188
+#define AG71XX_REG_RX_CTRL	0x018c
+#define AG71XX_REG_RX_DESC	0x0190
+#define AG71XX_REG_RX_STATUS	0x0194
+#define AG71XX_REG_INT_ENABLE	0x0198
+#define AG71XX_REG_INT_STATUS	0x019c
+
+#define AG71XX_REG_FIFO_DEPTH	0x01a8
+#define AG71XX_REG_RX_SM	0x01b0
+#define AG71XX_REG_TX_SM	0x01b4
+
+#define MAC_CFG1_TXE		BIT(0)	/* Tx Enable */
+#define MAC_CFG1_STX		BIT(1)	/* Synchronize Tx Enable */
+#define MAC_CFG1_RXE		BIT(2)	/* Rx Enable */
+#define MAC_CFG1_SRX		BIT(3)	/* Synchronize Rx Enable */
+#define MAC_CFG1_TFC		BIT(4)	/* Tx Flow Control Enable */
+#define MAC_CFG1_RFC		BIT(5)	/* Rx Flow Control Enable */
+#define MAC_CFG1_LB		BIT(8)	/* Loopback mode */
+#define MAC_CFG1_SR		BIT(31)	/* Soft Reset */
+
+#define MAC_CFG2_FDX		BIT(0)
+#define MAC_CFG2_CRC_EN		BIT(1)
+#define MAC_CFG2_PAD_CRC_EN	BIT(2)
+#define MAC_CFG2_LEN_CHECK	BIT(4)
+#define MAC_CFG2_HUGE_FRAME_EN	BIT(5)
+#define MAC_CFG2_IF_1000	BIT(9)
+#define MAC_CFG2_IF_10_100	BIT(8)
+
+#define FIFO_CFG0_WTM		BIT(0)	/* Watermark Module */
+#define FIFO_CFG0_RXS		BIT(1)	/* Rx System Module */
+#define FIFO_CFG0_RXF		BIT(2)	/* Rx Fabric Module */
+#define FIFO_CFG0_TXS		BIT(3)	/* Tx System Module */
+#define FIFO_CFG0_TXF		BIT(4)	/* Tx Fabric Module */
+#define FIFO_CFG0_ALL	(FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
+			| FIFO_CFG0_TXS | FIFO_CFG0_TXF)
+
+#define FIFO_CFG0_ENABLE_SHIFT	8
+
+#define FIFO_CFG4_DE		BIT(0)	/* Drop Event */
+#define FIFO_CFG4_DV		BIT(1)	/* RX_DV Event */
+#define FIFO_CFG4_FC		BIT(2)	/* False Carrier */
+#define FIFO_CFG4_CE		BIT(3)	/* Code Error */
+#define FIFO_CFG4_CR		BIT(4)	/* CRC error */
+#define FIFO_CFG4_LM		BIT(5)	/* Length Mismatch */
+#define FIFO_CFG4_LO		BIT(6)	/* Length out of range */
+#define FIFO_CFG4_OK		BIT(7)	/* Packet is OK */
+#define FIFO_CFG4_MC		BIT(8)	/* Multicast Packet */
+#define FIFO_CFG4_BC		BIT(9)	/* Broadcast Packet */
+#define FIFO_CFG4_DR		BIT(10)	/* Dribble */
+#define FIFO_CFG4_LE		BIT(11)	/* Long Event */
+#define FIFO_CFG4_CF		BIT(12)	/* Control Frame */
+#define FIFO_CFG4_PF		BIT(13)	/* Pause Frame */
+#define FIFO_CFG4_UO		BIT(14)	/* Unsupported Opcode */
+#define FIFO_CFG4_VT		BIT(15)	/* VLAN tag detected */
+#define FIFO_CFG4_FT		BIT(16)	/* Frame Truncated */
+#define FIFO_CFG4_UC		BIT(17)	/* Unicast Packet */
+
+#define FIFO_CFG5_DE		BIT(0)	/* Drop Event */
+#define FIFO_CFG5_DV		BIT(1)	/* RX_DV Event */
+#define FIFO_CFG5_FC		BIT(2)	/* False Carrier */
+#define FIFO_CFG5_CE		BIT(3)	/* Code Error */
+#define FIFO_CFG5_LM		BIT(4)	/* Length Mismatch */
+#define FIFO_CFG5_LO		BIT(5)	/* Length Out of Range */
+#define FIFO_CFG5_OK		BIT(6)	/* Packet is OK */
+#define FIFO_CFG5_MC		BIT(7)	/* Multicast Packet */
+#define FIFO_CFG5_BC		BIT(8)	/* Broadcast Packet */
+#define FIFO_CFG5_DR		BIT(9)	/* Dribble */
+#define FIFO_CFG5_CF		BIT(10)	/* Control Frame */
+#define FIFO_CFG5_PF		BIT(11)	/* Pause Frame */
+#define FIFO_CFG5_UO		BIT(12)	/* Unsupported Opcode */
+#define FIFO_CFG5_VT		BIT(13)	/* VLAN tag detected */
+#define FIFO_CFG5_LE		BIT(14)	/* Long Event */
+#define FIFO_CFG5_FT		BIT(15)	/* Frame Truncated */
+#define FIFO_CFG5_16		BIT(16)	/* unknown */
+#define FIFO_CFG5_17		BIT(17)	/* unknown */
+#define FIFO_CFG5_SF		BIT(18)	/* Short Frame */
+#define FIFO_CFG5_BM		BIT(19)	/* Byte Mode */
+
+#define AG71XX_INT_TX_PS	BIT(0)
+#define AG71XX_INT_TX_UR	BIT(1)
+#define AG71XX_INT_TX_BE	BIT(3)
+#define AG71XX_INT_RX_PR	BIT(4)
+#define AG71XX_INT_RX_OF	BIT(6)
+#define AG71XX_INT_RX_BE	BIT(7)
+
+#define MAC_IFCTL_SPEED		BIT(16)
+
+#define MII_CFG_CLK_DIV_4	0
+#define MII_CFG_CLK_DIV_6	2
+#define MII_CFG_CLK_DIV_8	3
+#define MII_CFG_CLK_DIV_10	4
+#define MII_CFG_CLK_DIV_14	5
+#define MII_CFG_CLK_DIV_20	6
+#define MII_CFG_CLK_DIV_28	7
+#define MII_CFG_CLK_DIV_34	8
+#define MII_CFG_CLK_DIV_42	9
+#define MII_CFG_CLK_DIV_50	10
+#define MII_CFG_CLK_DIV_58	11
+#define MII_CFG_CLK_DIV_66	12
+#define MII_CFG_CLK_DIV_74	13
+#define MII_CFG_CLK_DIV_82	14
+#define MII_CFG_CLK_DIV_98	15
+#define MII_CFG_RESET		BIT(31)
+
+#define MII_CMD_WRITE		0x0
+#define MII_CMD_READ		0x1
+#define MII_ADDR_SHIFT		8
+#define MII_IND_BUSY		BIT(0)
+#define MII_IND_INVALID		BIT(2)
+
+#define TX_CTRL_TXE		BIT(0)	/* Tx Enable */
+
+#define TX_STATUS_PS		BIT(0)	/* Packet Sent */
+#define TX_STATUS_UR		BIT(1)	/* Tx Underrun */
+#define TX_STATUS_BE		BIT(3)	/* Bus Error */
+
+#define RX_CTRL_RXE		BIT(0)	/* Rx Enable */
+
+#define RX_STATUS_PR		BIT(0)	/* Packet Received */
+#define RX_STATUS_OF		BIT(2)	/* Rx Overflow */
+#define RX_STATUS_BE		BIT(3)	/* Bus Error */
+
+static inline void ag71xx_check_reg_offset(struct ag71xx *ag, unsigned reg)
+{
+	switch (reg) {
+	case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL:
+	case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_TX_SM:
+	case AG71XX_REG_MII_CFG:
+		break;
+
+	default:
+		BUG();
+	}
+}
+
+static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
+{
+	ag71xx_check_reg_offset(ag, reg);
+
+	__raw_writel(value, ag->mac_base + reg);
+	/* flush write */
+	(void) __raw_readl(ag->mac_base + reg);
+}
+
+static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
+{
+	ag71xx_check_reg_offset(ag, reg);
+
+	return __raw_readl(ag->mac_base + reg);
+}
+
+static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
+{
+	void __iomem *r;
+
+	ag71xx_check_reg_offset(ag, reg);
+
+	r = ag->mac_base + reg;
+	__raw_writel(__raw_readl(r) | mask, r);
+	/* flush write */
+	(void)__raw_readl(r);
+}
+
+static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
+{
+	void __iomem *r;
+
+	ag71xx_check_reg_offset(ag, reg);
+
+	r = ag->mac_base + reg;
+	__raw_writel(__raw_readl(r) & ~mask, r);
+	/* flush write */
+	(void) __raw_readl(r);
+}
+
+static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
+{
+	ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
+}
+
+static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
+{
+	ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
+}
+
+#ifdef CONFIG_AG71XX_AR8216_SUPPORT
+void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb);
+int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
+				int pktlen);
+static inline int ag71xx_has_ar8216(struct ag71xx *ag)
+{
+	return ag71xx_get_pdata(ag)->has_ar8216;
+}
+#else
+static inline void ag71xx_add_ar8216_header(struct ag71xx *ag,
+					   struct sk_buff *skb)
+{
+}
+
+static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag,
+					      struct sk_buff *skb,
+					      int pktlen)
+{
+	return 0;
+}
+static inline int ag71xx_has_ar8216(struct ag71xx *ag)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_AG71XX_DEBUG_FS
+int ag71xx_debugfs_root_init(void);
+void ag71xx_debugfs_root_exit(void);
+int ag71xx_debugfs_init(struct ag71xx *ag);
+void ag71xx_debugfs_exit(struct ag71xx *ag);
+void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status);
+void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx);
+#else
+static inline int ag71xx_debugfs_root_init(void) { return 0; }
+static inline void ag71xx_debugfs_root_exit(void) {}
+static inline int ag71xx_debugfs_init(struct ag71xx *ag) { return 0; }
+static inline void ag71xx_debugfs_exit(struct ag71xx *ag) {}
+static inline void ag71xx_debugfs_update_int_stats(struct ag71xx *ag,
+						   u32 status) {}
+static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
+						    int rx, int tx) {}
+#endif /* CONFIG_AG71XX_DEBUG_FS */
+
+void ag71xx_ar7240_start(struct ag71xx *ag);
+void ag71xx_ar7240_stop(struct ag71xx *ag);
+int ag71xx_ar7240_init(struct ag71xx *ag);
+void ag71xx_ar7240_cleanup(struct ag71xx *ag);
+
+int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg);
+void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val);
+
+u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr,
+		      unsigned reg_addr);
+int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr,
+		       unsigned reg_addr, u16 reg_val);
+
+#endif /* _AG71XX_H */
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
new file mode 100644
index 0000000000..c5aed0d2db
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
@@ -0,0 +1,1229 @@
+/*
+ *  Driver for the built-in ethernet switch of the Atheros AR7240 SoC
+ *  Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (c) 2010 Felix Fietkau <nbd@nbd.name>
+ *
+ *  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/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/mii.h>
+#include <linux/bitops.h>
+#include <linux/switch.h>
+#include "ag71xx.h"
+
+#define BITM(_count)	(BIT(_count) - 1)
+#define BITS(_shift, _count)	(BITM(_count) << _shift)
+
+#define AR7240_REG_MASK_CTRL		0x00
+#define AR7240_MASK_CTRL_REVISION_M	BITM(8)
+#define AR7240_MASK_CTRL_VERSION_M	BITM(8)
+#define AR7240_MASK_CTRL_VERSION_S	8
+#define   AR7240_MASK_CTRL_VERSION_AR7240 0x01
+#define   AR7240_MASK_CTRL_VERSION_AR934X 0x02
+#define AR7240_MASK_CTRL_SOFT_RESET	BIT(31)
+
+#define AR7240_REG_MAC_ADDR0		0x20
+#define AR7240_REG_MAC_ADDR1		0x24
+
+#define AR7240_REG_FLOOD_MASK		0x2c
+#define AR7240_FLOOD_MASK_BROAD_TO_CPU	BIT(26)
+
+#define AR7240_REG_GLOBAL_CTRL		0x30
+#define AR7240_GLOBAL_CTRL_MTU_M	BITM(11)
+#define AR9340_GLOBAL_CTRL_MTU_M	BITM(14)
+
+#define AR7240_REG_VTU			0x0040
+#define   AR7240_VTU_OP			BITM(3)
+#define   AR7240_VTU_OP_NOOP		0x0
+#define   AR7240_VTU_OP_FLUSH		0x1
+#define   AR7240_VTU_OP_LOAD		0x2
+#define   AR7240_VTU_OP_PURGE		0x3
+#define   AR7240_VTU_OP_REMOVE_PORT	0x4
+#define   AR7240_VTU_ACTIVE		BIT(3)
+#define   AR7240_VTU_FULL		BIT(4)
+#define   AR7240_VTU_PORT		BITS(8, 4)
+#define   AR7240_VTU_PORT_S		8
+#define   AR7240_VTU_VID		BITS(16, 12)
+#define   AR7240_VTU_VID_S		16
+#define   AR7240_VTU_PRIO		BITS(28, 3)
+#define   AR7240_VTU_PRIO_S		28
+#define   AR7240_VTU_PRIO_EN		BIT(31)
+
+#define AR7240_REG_VTU_DATA		0x0044
+#define   AR7240_VTUDATA_MEMBER		BITS(0, 10)
+#define   AR7240_VTUDATA_VALID		BIT(11)
+
+#define AR7240_REG_ATU			0x50
+#define AR7240_ATU_FLUSH_ALL		0x1
+
+#define AR7240_REG_AT_CTRL		0x5c
+#define AR7240_AT_CTRL_AGE_TIME		BITS(0, 15)
+#define AR7240_AT_CTRL_AGE_EN		BIT(17)
+#define AR7240_AT_CTRL_LEARN_CHANGE	BIT(18)
+#define AR7240_AT_CTRL_RESERVED		BIT(19)
+#define AR7240_AT_CTRL_ARP_EN		BIT(20)
+
+#define AR7240_REG_TAG_PRIORITY		0x70
+
+#define AR7240_REG_SERVICE_TAG		0x74
+#define AR7240_SERVICE_TAG_M		BITM(16)
+
+#define AR7240_REG_CPU_PORT		0x78
+#define AR7240_MIRROR_PORT_S		4
+#define AR7240_CPU_PORT_EN		BIT(8)
+
+#define AR7240_REG_MIB_FUNCTION0	0x80
+#define AR7240_MIB_TIMER_M		BITM(16)
+#define AR7240_MIB_AT_HALF_EN		BIT(16)
+#define AR7240_MIB_BUSY			BIT(17)
+#define AR7240_MIB_FUNC_S		24
+#define AR7240_MIB_FUNC_M		BITM(3)
+#define AR7240_MIB_FUNC_NO_OP		0x0
+#define AR7240_MIB_FUNC_FLUSH		0x1
+#define AR7240_MIB_FUNC_CAPTURE		0x3
+
+#define AR7240_REG_MDIO_CTRL		0x98
+#define AR7240_MDIO_CTRL_DATA_M		BITM(16)
+#define AR7240_MDIO_CTRL_REG_ADDR_S	16
+#define AR7240_MDIO_CTRL_PHY_ADDR_S	21
+#define AR7240_MDIO_CTRL_CMD_WRITE	0
+#define AR7240_MDIO_CTRL_CMD_READ	BIT(27)
+#define AR7240_MDIO_CTRL_MASTER_EN	BIT(30)
+#define AR7240_MDIO_CTRL_BUSY		BIT(31)
+
+#define AR7240_REG_PORT_BASE(_port)	(0x100 + (_port) * 0x100)
+
+#define AR7240_REG_PORT_STATUS(_port)	(AR7240_REG_PORT_BASE((_port)) + 0x00)
+#define AR7240_PORT_STATUS_SPEED_S	0
+#define AR7240_PORT_STATUS_SPEED_M	BITM(2)
+#define AR7240_PORT_STATUS_SPEED_10	0
+#define AR7240_PORT_STATUS_SPEED_100	1
+#define AR7240_PORT_STATUS_SPEED_1000	2
+#define AR7240_PORT_STATUS_TXMAC	BIT(2)
+#define AR7240_PORT_STATUS_RXMAC	BIT(3)
+#define AR7240_PORT_STATUS_TXFLOW	BIT(4)
+#define AR7240_PORT_STATUS_RXFLOW	BIT(5)
+#define AR7240_PORT_STATUS_DUPLEX	BIT(6)
+#define AR7240_PORT_STATUS_LINK_UP	BIT(8)
+#define AR7240_PORT_STATUS_LINK_AUTO	BIT(9)
+#define AR7240_PORT_STATUS_LINK_PAUSE	BIT(10)
+
+#define AR7240_REG_PORT_CTRL(_port)	(AR7240_REG_PORT_BASE((_port)) + 0x04)
+#define AR7240_PORT_CTRL_STATE_M	BITM(3)
+#define	AR7240_PORT_CTRL_STATE_DISABLED	0
+#define AR7240_PORT_CTRL_STATE_BLOCK	1
+#define AR7240_PORT_CTRL_STATE_LISTEN	2
+#define AR7240_PORT_CTRL_STATE_LEARN	3
+#define AR7240_PORT_CTRL_STATE_FORWARD	4
+#define AR7240_PORT_CTRL_LEARN_LOCK	BIT(7)
+#define AR7240_PORT_CTRL_VLAN_MODE_S	8
+#define AR7240_PORT_CTRL_VLAN_MODE_KEEP	0
+#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1
+#define AR7240_PORT_CTRL_VLAN_MODE_ADD	2
+#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3
+#define AR7240_PORT_CTRL_IGMP_SNOOP	BIT(10)
+#define AR7240_PORT_CTRL_HEADER		BIT(11)
+#define AR7240_PORT_CTRL_MAC_LOOP	BIT(12)
+#define AR7240_PORT_CTRL_SINGLE_VLAN	BIT(13)
+#define AR7240_PORT_CTRL_LEARN		BIT(14)
+#define AR7240_PORT_CTRL_DOUBLE_TAG	BIT(15)
+#define AR7240_PORT_CTRL_MIRROR_TX	BIT(16)
+#define AR7240_PORT_CTRL_MIRROR_RX	BIT(17)
+
+#define AR7240_REG_PORT_VLAN(_port)	(AR7240_REG_PORT_BASE((_port)) + 0x08)
+
+#define AR7240_PORT_VLAN_DEFAULT_ID_S	0
+#define AR7240_PORT_VLAN_DEST_PORTS_S	16
+#define AR7240_PORT_VLAN_MODE_S		30
+#define AR7240_PORT_VLAN_MODE_PORT_ONLY	0
+#define AR7240_PORT_VLAN_MODE_PORT_FALLBACK	1
+#define AR7240_PORT_VLAN_MODE_VLAN_ONLY	2
+#define AR7240_PORT_VLAN_MODE_SECURE	3
+
+
+#define AR7240_REG_STATS_BASE(_port)	(0x20000 + (_port) * 0x100)
+
+#define AR7240_STATS_RXBROAD		0x00
+#define AR7240_STATS_RXPAUSE		0x04
+#define AR7240_STATS_RXMULTI		0x08
+#define AR7240_STATS_RXFCSERR		0x0c
+#define AR7240_STATS_RXALIGNERR		0x10
+#define AR7240_STATS_RXRUNT		0x14
+#define AR7240_STATS_RXFRAGMENT		0x18
+#define AR7240_STATS_RX64BYTE		0x1c
+#define AR7240_STATS_RX128BYTE		0x20
+#define AR7240_STATS_RX256BYTE		0x24
+#define AR7240_STATS_RX512BYTE		0x28
+#define AR7240_STATS_RX1024BYTE		0x2c
+#define AR7240_STATS_RX1518BYTE		0x30
+#define AR7240_STATS_RXMAXBYTE		0x34
+#define AR7240_STATS_RXTOOLONG		0x38
+#define AR7240_STATS_RXGOODBYTE		0x3c
+#define AR7240_STATS_RXBADBYTE		0x44
+#define AR7240_STATS_RXOVERFLOW		0x4c
+#define AR7240_STATS_FILTERED		0x50
+#define AR7240_STATS_TXBROAD		0x54
+#define AR7240_STATS_TXPAUSE		0x58
+#define AR7240_STATS_TXMULTI		0x5c
+#define AR7240_STATS_TXUNDERRUN		0x60
+#define AR7240_STATS_TX64BYTE		0x64
+#define AR7240_STATS_TX128BYTE		0x68
+#define AR7240_STATS_TX256BYTE		0x6c
+#define AR7240_STATS_TX512BYTE		0x70
+#define AR7240_STATS_TX1024BYTE		0x74
+#define AR7240_STATS_TX1518BYTE		0x78
+#define AR7240_STATS_TXMAXBYTE		0x7c
+#define AR7240_STATS_TXOVERSIZE		0x80
+#define AR7240_STATS_TXBYTE		0x84
+#define AR7240_STATS_TXCOLLISION	0x8c
+#define AR7240_STATS_TXABORTCOL		0x90
+#define AR7240_STATS_TXMULTICOL		0x94
+#define AR7240_STATS_TXSINGLECOL	0x98
+#define AR7240_STATS_TXEXCDEFER		0x9c
+#define AR7240_STATS_TXDEFER		0xa0
+#define AR7240_STATS_TXLATECOL		0xa4
+
+#define AR7240_PORT_CPU		0
+#define AR7240_NUM_PORTS	6
+#define AR7240_NUM_PHYS		5
+
+#define AR7240_PHY_ID1		0x004d
+#define AR7240_PHY_ID2		0xd041
+
+#define AR934X_PHY_ID1		0x004d
+#define AR934X_PHY_ID2		0xd042
+
+#define AR7240_MAX_VLANS	16
+
+#define AR934X_REG_OPER_MODE0		0x04
+#define   AR934X_OPER_MODE0_MAC_GMII_EN	BIT(6)
+#define   AR934X_OPER_MODE0_PHY_MII_EN	BIT(10)
+
+#define AR934X_REG_OPER_MODE1		0x08
+#define   AR934X_REG_OPER_MODE1_PHY4_MII_EN	BIT(28)
+
+#define AR934X_REG_FLOOD_MASK		0x2c
+#define   AR934X_FLOOD_MASK_MC_DP(_p)	BIT(16 + (_p))
+#define   AR934X_FLOOD_MASK_BC_DP(_p)	BIT(25 + (_p))
+
+#define AR934X_REG_QM_CTRL		0x3c
+#define   AR934X_QM_CTRL_ARP_EN		BIT(15)
+
+#define AR934X_REG_AT_CTRL		0x5c
+#define   AR934X_AT_CTRL_AGE_TIME	BITS(0, 15)
+#define   AR934X_AT_CTRL_AGE_EN		BIT(17)
+#define   AR934X_AT_CTRL_LEARN_CHANGE	BIT(18)
+
+#define AR934X_MIB_ENABLE		BIT(30)
+
+#define AR934X_REG_PORT_BASE(_port)	(0x100 + (_port) * 0x100)
+
+#define AR934X_REG_PORT_VLAN1(_port)	(AR934X_REG_PORT_BASE((_port)) + 0x08)
+#define   AR934X_PORT_VLAN1_DEFAULT_SVID_S		0
+#define   AR934X_PORT_VLAN1_FORCE_DEFAULT_VID_EN 	BIT(12)
+#define   AR934X_PORT_VLAN1_PORT_TLS_MODE		BIT(13)
+#define   AR934X_PORT_VLAN1_PORT_VLAN_PROP_EN		BIT(14)
+#define   AR934X_PORT_VLAN1_PORT_CLONE_EN		BIT(15)
+#define   AR934X_PORT_VLAN1_DEFAULT_CVID_S		16
+#define   AR934X_PORT_VLAN1_FORCE_PORT_VLAN_EN		BIT(28)
+#define   AR934X_PORT_VLAN1_ING_PORT_PRI_S		29
+
+#define AR934X_REG_PORT_VLAN2(_port)	(AR934X_REG_PORT_BASE((_port)) + 0x0c)
+#define   AR934X_PORT_VLAN2_PORT_VID_MEM_S		16
+#define   AR934X_PORT_VLAN2_8021Q_MODE_S		30
+#define   AR934X_PORT_VLAN2_8021Q_MODE_PORT_ONLY	0
+#define   AR934X_PORT_VLAN2_8021Q_MODE_PORT_FALLBACK	1
+#define   AR934X_PORT_VLAN2_8021Q_MODE_VLAN_ONLY	2
+#define   AR934X_PORT_VLAN2_8021Q_MODE_SECURE		3
+
+#define sw_to_ar7240(_dev) container_of(_dev, struct ar7240sw, swdev)
+
+struct ar7240sw_port_stat {
+	unsigned long rx_broadcast;
+	unsigned long rx_pause;
+	unsigned long rx_multicast;
+	unsigned long rx_fcs_error;
+	unsigned long rx_align_error;
+	unsigned long rx_runt;
+	unsigned long rx_fragments;
+	unsigned long rx_64byte;
+	unsigned long rx_128byte;
+	unsigned long rx_256byte;
+	unsigned long rx_512byte;
+	unsigned long rx_1024byte;
+	unsigned long rx_1518byte;
+	unsigned long rx_maxbyte;
+	unsigned long rx_toolong;
+	unsigned long rx_good_byte;
+	unsigned long rx_bad_byte;
+	unsigned long rx_overflow;
+	unsigned long filtered;
+
+	unsigned long tx_broadcast;
+	unsigned long tx_pause;
+	unsigned long tx_multicast;
+	unsigned long tx_underrun;
+	unsigned long tx_64byte;
+	unsigned long tx_128byte;
+	unsigned long tx_256byte;
+	unsigned long tx_512byte;
+	unsigned long tx_1024byte;
+	unsigned long tx_1518byte;
+	unsigned long tx_maxbyte;
+	unsigned long tx_oversize;
+	unsigned long tx_byte;
+	unsigned long tx_collision;
+	unsigned long tx_abortcol;
+	unsigned long tx_multicol;
+	unsigned long tx_singlecol;
+	unsigned long tx_excdefer;
+	unsigned long tx_defer;
+	unsigned long tx_xlatecol;
+};
+
+struct ar7240sw {
+	struct mii_bus	*mii_bus;
+	struct ag71xx_switch_platform_data *swdata;
+	struct switch_dev swdev;
+	int num_ports;
+	u8 ver;
+	bool vlan;
+	u16 vlan_id[AR7240_MAX_VLANS];
+	u8 vlan_table[AR7240_MAX_VLANS];
+	u8 vlan_tagged;
+	u16 pvid[AR7240_NUM_PORTS];
+	char buf[80];
+
+	rwlock_t stats_lock;
+	struct ar7240sw_port_stat port_stats[AR7240_NUM_PORTS];
+};
+
+struct ar7240sw_hw_stat {
+	char string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int reg;
+};
+
+static DEFINE_MUTEX(reg_mutex);
+
+static inline int sw_is_ar7240(struct ar7240sw *as)
+{
+	return as->ver == AR7240_MASK_CTRL_VERSION_AR7240;
+}
+
+static inline int sw_is_ar934x(struct ar7240sw *as)
+{
+	return as->ver == AR7240_MASK_CTRL_VERSION_AR934X;
+}
+
+static inline u32 ar7240sw_port_mask(struct ar7240sw *as, int port)
+{
+	return BIT(port);
+}
+
+static inline u32 ar7240sw_port_mask_all(struct ar7240sw *as)
+{
+	return BIT(as->swdev.ports) - 1;
+}
+
+static inline u32 ar7240sw_port_mask_but(struct ar7240sw *as, int port)
+{
+	return ar7240sw_port_mask_all(as) & ~BIT(port);
+}
+
+static inline u16 mk_phy_addr(u32 reg)
+{
+	return 0x17 & ((reg >> 4) | 0x10);
+}
+
+static inline u16 mk_phy_reg(u32 reg)
+{
+	return (reg << 1) & 0x1e;
+}
+
+static inline u16 mk_high_addr(u32 reg)
+{
+	return (reg >> 7) & 0x1ff;
+}
+
+static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg)
+{
+	unsigned long flags;
+	u16 phy_addr;
+	u16 phy_reg;
+	u32 hi, lo;
+
+	reg = (reg & 0xfffffffc) >> 2;
+	phy_addr = mk_phy_addr(reg);
+	phy_reg = mk_phy_reg(reg);
+
+	local_irq_save(flags);
+	ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
+	lo = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg);
+	hi = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg + 1);
+	local_irq_restore(flags);
+
+	return (hi << 16) | lo;
+}
+
+static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val)
+{
+	unsigned long flags;
+	u16 phy_addr;
+	u16 phy_reg;
+
+	reg = (reg & 0xfffffffc) >> 2;
+	phy_addr = mk_phy_addr(reg);
+	phy_reg = mk_phy_reg(reg);
+
+	local_irq_save(flags);
+	ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
+	ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg + 1, (val >> 16));
+	ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg, (val & 0xffff));
+	local_irq_restore(flags);
+}
+
+static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr)
+{
+	u32 ret;
+
+	mutex_lock(&reg_mutex);
+	ret = __ar7240sw_reg_read(mii, reg_addr);
+	mutex_unlock(&reg_mutex);
+
+	return ret;
+}
+
+static void ar7240sw_reg_write(struct mii_bus *mii, u32 reg_addr, u32 reg_val)
+{
+	mutex_lock(&reg_mutex);
+	__ar7240sw_reg_write(mii, reg_addr, reg_val);
+	mutex_unlock(&reg_mutex);
+}
+
+static u32 ar7240sw_reg_rmw(struct mii_bus *mii, u32 reg, u32 mask, u32 val)
+{
+	u32 t;
+
+	mutex_lock(&reg_mutex);
+	t = __ar7240sw_reg_read(mii, reg);
+	t &= ~mask;
+	t |= val;
+	__ar7240sw_reg_write(mii, reg, t);
+	mutex_unlock(&reg_mutex);
+
+	return t;
+}
+
+static void ar7240sw_reg_set(struct mii_bus *mii, u32 reg, u32 val)
+{
+	u32 t;
+
+	mutex_lock(&reg_mutex);
+	t = __ar7240sw_reg_read(mii, reg);
+	t |= val;
+	__ar7240sw_reg_write(mii, reg, t);
+	mutex_unlock(&reg_mutex);
+}
+
+static int __ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val,
+			       unsigned timeout)
+{
+	int i;
+
+	for (i = 0; i < timeout; i++) {
+		u32 t;
+
+		t = __ar7240sw_reg_read(mii, reg);
+		if ((t & mask) == val)
+			return 0;
+
+		usleep_range(1000, 2000);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val,
+			     unsigned timeout)
+{
+	int ret;
+
+	mutex_lock(&reg_mutex);
+	ret = __ar7240sw_reg_wait(mii, reg, mask, val, timeout);
+	mutex_unlock(&reg_mutex);
+	return ret;
+}
+
+u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr,
+		      unsigned reg_addr)
+{
+	u32 t, val = 0xffff;
+	int err;
+
+	if (phy_addr >= AR7240_NUM_PHYS)
+		return 0xffff;
+
+	mutex_lock(&reg_mutex);
+	t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
+	    (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
+	    AR7240_MDIO_CTRL_MASTER_EN |
+	    AR7240_MDIO_CTRL_BUSY |
+	    AR7240_MDIO_CTRL_CMD_READ;
+
+	__ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t);
+	err = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL,
+				  AR7240_MDIO_CTRL_BUSY, 0, 5);
+	if (!err)
+		val = __ar7240sw_reg_read(mii, AR7240_REG_MDIO_CTRL);
+	mutex_unlock(&reg_mutex);
+
+	return val & AR7240_MDIO_CTRL_DATA_M;
+}
+
+int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr,
+		       unsigned reg_addr, u16 reg_val)
+{
+	u32 t;
+	int ret;
+
+	if (phy_addr >= AR7240_NUM_PHYS)
+		return -EINVAL;
+
+	mutex_lock(&reg_mutex);
+	t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
+	    (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
+	    AR7240_MDIO_CTRL_MASTER_EN |
+	    AR7240_MDIO_CTRL_BUSY |
+	    AR7240_MDIO_CTRL_CMD_WRITE |
+	    reg_val;
+
+	__ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t);
+	ret = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL,
+				  AR7240_MDIO_CTRL_BUSY, 0, 5);
+	mutex_unlock(&reg_mutex);
+
+	return ret;
+}
+
+static int ar7240sw_capture_stats(struct ar7240sw *as)
+{
+	struct mii_bus *mii = as->mii_bus;
+	int port;
+	int ret;
+
+	write_lock(&as->stats_lock);
+
+	/* Capture the hardware statistics for all ports */
+	ar7240sw_reg_rmw(mii, AR7240_REG_MIB_FUNCTION0,
+			 (AR7240_MIB_FUNC_M << AR7240_MIB_FUNC_S),
+			 (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S));
+
+	/* Wait for the capturing to complete. */
+	ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0,
+				AR7240_MIB_BUSY, 0, 10);
+
+	if (ret)
+		goto unlock;
+
+	for (port = 0; port < AR7240_NUM_PORTS; port++) {
+		unsigned int base;
+		struct ar7240sw_port_stat *stats;
+
+		base = AR7240_REG_STATS_BASE(port);
+		stats = &as->port_stats[port];
+
+#define READ_STAT(_r) ar7240sw_reg_read(mii, base + AR7240_STATS_ ## _r)
+
+		stats->rx_good_byte += READ_STAT(RXGOODBYTE);
+		stats->tx_byte += READ_STAT(TXBYTE);
+
+#undef READ_STAT
+	}
+
+	ret = 0;
+
+unlock:
+	write_unlock(&as->stats_lock);
+	return ret;
+}
+
+static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port)
+{
+	ar7240sw_reg_write(as->mii_bus, AR7240_REG_PORT_CTRL(port),
+			   AR7240_PORT_CTRL_STATE_DISABLED);
+}
+
+static void ar7240sw_setup(struct ar7240sw *as)
+{
+	struct mii_bus *mii = as->mii_bus;
+
+	/* Enable CPU port, and disable mirror port */
+	ar7240sw_reg_write(mii, AR7240_REG_CPU_PORT,
+			   AR7240_CPU_PORT_EN |
+			   (15 << AR7240_MIRROR_PORT_S));
+
+	/* Setup TAG priority mapping */
+	ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50);
+
+	if (sw_is_ar934x(as)) {
+		/* Enable aging, MAC replacing */
+		ar7240sw_reg_write(mii, AR934X_REG_AT_CTRL,
+			0x2b /* 5 min age time */ |
+			AR934X_AT_CTRL_AGE_EN |
+			AR934X_AT_CTRL_LEARN_CHANGE);
+		/* Enable ARP frame acknowledge */
+		ar7240sw_reg_set(mii, AR934X_REG_QM_CTRL,
+				 AR934X_QM_CTRL_ARP_EN);
+		/* Enable Broadcast/Multicast frames transmitted to the CPU */
+		ar7240sw_reg_set(mii, AR934X_REG_FLOOD_MASK,
+				 AR934X_FLOOD_MASK_BC_DP(0) |
+				 AR934X_FLOOD_MASK_MC_DP(0));
+
+		/* setup MTU */
+		ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL,
+				 AR9340_GLOBAL_CTRL_MTU_M,
+				 AR9340_GLOBAL_CTRL_MTU_M);
+
+		/* Enable MIB counters */
+		ar7240sw_reg_set(mii, AR7240_REG_MIB_FUNCTION0,
+				 AR934X_MIB_ENABLE);
+
+	} else {
+		/* Enable ARP frame acknowledge, aging, MAC replacing */
+		ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL,
+			AR7240_AT_CTRL_RESERVED |
+			0x2b /* 5 min age time */ |
+			AR7240_AT_CTRL_AGE_EN |
+			AR7240_AT_CTRL_ARP_EN |
+			AR7240_AT_CTRL_LEARN_CHANGE);
+		/* Enable Broadcast frames transmitted to the CPU */
+		ar7240sw_reg_set(mii, AR7240_REG_FLOOD_MASK,
+				 AR7240_FLOOD_MASK_BROAD_TO_CPU);
+
+		/* setup MTU */
+		ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL,
+				 AR7240_GLOBAL_CTRL_MTU_M,
+				 AR7240_GLOBAL_CTRL_MTU_M);
+	}
+
+	/* setup Service TAG */
+	ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0);
+}
+
+/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */
+static int
+ar7240sw_phy_poll_reset(struct mii_bus *bus)
+{
+	const unsigned int sleep_msecs = 20;
+	int ret, elapsed, i;
+
+	for (elapsed = sleep_msecs; elapsed <= 600;
+	     elapsed += sleep_msecs) {
+		msleep(sleep_msecs);
+		for (i = 0; i < AR7240_NUM_PHYS; i++) {
+			ret = ar7240sw_phy_read(bus, i, MII_BMCR);
+			if (ret < 0)
+				return ret;
+			if (ret & BMCR_RESET)
+				break;
+			if (i == AR7240_NUM_PHYS - 1) {
+				usleep_range(1000, 2000);
+				return 0;
+			}
+		}
+	}
+	return -ETIMEDOUT;
+}
+
+static int ar7240sw_reset(struct ar7240sw *as)
+{
+	struct mii_bus *mii = as->mii_bus;
+	int ret;
+	int i;
+
+	/* Set all ports to disabled state. */
+	for (i = 0; i < AR7240_NUM_PORTS; i++)
+		ar7240sw_disable_port(as, i);
+
+	/* Wait for transmit queues to drain. */
+	usleep_range(2000, 3000);
+
+	/* Reset the switch. */
+	ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL,
+			   AR7240_MASK_CTRL_SOFT_RESET);
+
+	ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL,
+				AR7240_MASK_CTRL_SOFT_RESET, 0, 1000);
+
+	/* setup PHYs */
+	for (i = 0; i < AR7240_NUM_PHYS; i++) {
+		ar7240sw_phy_write(mii, i, MII_ADVERTISE,
+				   ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
+				   ADVERTISE_PAUSE_ASYM);
+		ar7240sw_phy_write(mii, i, MII_BMCR,
+				   BMCR_RESET | BMCR_ANENABLE);
+	}
+	ret = ar7240sw_phy_poll_reset(mii);
+	if (ret)
+		return ret;
+
+	ar7240sw_setup(as);
+	return ret;
+}
+
+static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask)
+{
+	struct mii_bus *mii = as->mii_bus;
+	u32 ctrl;
+	u32 vid, mode;
+
+	ctrl = AR7240_PORT_CTRL_STATE_FORWARD | AR7240_PORT_CTRL_LEARN |
+		AR7240_PORT_CTRL_SINGLE_VLAN;
+
+	if (port == AR7240_PORT_CPU) {
+		ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port),
+				   AR7240_PORT_STATUS_SPEED_1000 |
+				   AR7240_PORT_STATUS_TXFLOW |
+				   AR7240_PORT_STATUS_RXFLOW |
+				   AR7240_PORT_STATUS_TXMAC |
+				   AR7240_PORT_STATUS_RXMAC |
+				   AR7240_PORT_STATUS_DUPLEX);
+	} else {
+		ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port),
+				   AR7240_PORT_STATUS_LINK_AUTO);
+	}
+
+	/* Set the default VID for this port */
+	if (as->vlan) {
+		vid = as->vlan_id[as->pvid[port]];
+		mode = AR7240_PORT_VLAN_MODE_SECURE;
+	} else {
+		vid = port;
+		mode = AR7240_PORT_VLAN_MODE_PORT_ONLY;
+	}
+
+	if (as->vlan) {
+		if (as->vlan_tagged & BIT(port))
+			ctrl |= AR7240_PORT_CTRL_VLAN_MODE_ADD <<
+				AR7240_PORT_CTRL_VLAN_MODE_S;
+		else
+			ctrl |= AR7240_PORT_CTRL_VLAN_MODE_STRIP <<
+				AR7240_PORT_CTRL_VLAN_MODE_S;
+	} else {
+		ctrl |= AR7240_PORT_CTRL_VLAN_MODE_KEEP <<
+			AR7240_PORT_CTRL_VLAN_MODE_S;
+	}
+
+	if (!portmask) {
+		if (port == AR7240_PORT_CPU)
+			portmask = ar7240sw_port_mask_but(as, AR7240_PORT_CPU);
+		else
+			portmask = ar7240sw_port_mask(as, AR7240_PORT_CPU);
+	}
+
+	/* allow the port to talk to all other ports, but exclude its
+	 * own ID to prevent frames from being reflected back to the
+	 * port that they came from */
+	portmask &= ar7240sw_port_mask_but(as, port);
+
+	ar7240sw_reg_write(mii, AR7240_REG_PORT_CTRL(port), ctrl);
+	if (sw_is_ar934x(as)) {
+		u32 vlan1, vlan2;
+
+		vlan1 = (vid << AR934X_PORT_VLAN1_DEFAULT_CVID_S);
+		vlan2 = (portmask << AR934X_PORT_VLAN2_PORT_VID_MEM_S) |
+			(mode << AR934X_PORT_VLAN2_8021Q_MODE_S);
+		ar7240sw_reg_write(mii, AR934X_REG_PORT_VLAN1(port), vlan1);
+		ar7240sw_reg_write(mii, AR934X_REG_PORT_VLAN2(port), vlan2);
+	} else {
+		u32 vlan;
+
+		vlan = vid | (mode << AR7240_PORT_VLAN_MODE_S) |
+		       (portmask << AR7240_PORT_VLAN_DEST_PORTS_S);
+
+		ar7240sw_reg_write(mii, AR7240_REG_PORT_VLAN(port), vlan);
+	}
+}
+
+static int ar7240_set_addr(struct ar7240sw *as, u8 *addr)
+{
+	struct mii_bus *mii = as->mii_bus;
+	u32 t;
+
+	t = (addr[4] << 8) | addr[5];
+	ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR0, t);
+
+	t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+	ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR1, t);
+
+	return 0;
+}
+
+static int
+ar7240_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	as->vlan_id[val->port_vlan] = val->value.i;
+	return 0;
+}
+
+static int
+ar7240_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	val->value.i = as->vlan_id[val->port_vlan];
+	return 0;
+}
+
+static int
+ar7240_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+
+	/* make sure no invalid PVIDs get set */
+
+	if (vlan >= dev->vlans)
+		return -EINVAL;
+
+	as->pvid[port] = vlan;
+	return 0;
+}
+
+static int
+ar7240_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	*vlan = as->pvid[port];
+	return 0;
+}
+
+static int
+ar7240_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	u8 ports = as->vlan_table[val->port_vlan];
+	int i;
+
+	val->len = 0;
+	for (i = 0; i < as->swdev.ports; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (as->vlan_tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int
+ar7240_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	u8 *vt = &as->vlan_table[val->port_vlan];
+	int i, j;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
+			as->vlan_tagged |= (1 << p->id);
+		else {
+			as->vlan_tagged &= ~(1 << p->id);
+			as->pvid[p->id] = val->port_vlan;
+
+			/* make sure that an untagged port does not
+			 * appear in other vlans */
+			for (j = 0; j < AR7240_MAX_VLANS; j++) {
+				if (j == val->port_vlan)
+					continue;
+				as->vlan_table[j] &= ~(1 << p->id);
+			}
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static int
+ar7240_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	as->vlan = !!val->value.i;
+	return 0;
+}
+
+static int
+ar7240_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	val->value.i = as->vlan;
+	return 0;
+}
+
+static void
+ar7240_vtu_op(struct ar7240sw *as, u32 op, u32 val)
+{
+	struct mii_bus *mii = as->mii_bus;
+
+	if (ar7240sw_reg_wait(mii, AR7240_REG_VTU, AR7240_VTU_ACTIVE, 0, 5))
+		return;
+
+	if ((op & AR7240_VTU_OP) == AR7240_VTU_OP_LOAD) {
+		val &= AR7240_VTUDATA_MEMBER;
+		val |= AR7240_VTUDATA_VALID;
+		ar7240sw_reg_write(mii, AR7240_REG_VTU_DATA, val);
+	}
+	op |= AR7240_VTU_ACTIVE;
+	ar7240sw_reg_write(mii, AR7240_REG_VTU, op);
+}
+
+static int
+ar7240_hw_apply(struct switch_dev *dev)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	u8 portmask[AR7240_NUM_PORTS];
+	int i, j;
+
+	/* flush all vlan translation unit entries */
+	ar7240_vtu_op(as, AR7240_VTU_OP_FLUSH, 0);
+
+	memset(portmask, 0, sizeof(portmask));
+	if (as->vlan) {
+		/* calculate the port destination masks and load vlans
+		 * into the vlan translation unit */
+		for (j = 0; j < AR7240_MAX_VLANS; j++) {
+			u8 vp = as->vlan_table[j];
+
+			if (!vp)
+				continue;
+
+			for (i = 0; i < as->swdev.ports; i++) {
+				u8 mask = (1 << i);
+				if (vp & mask)
+					portmask[i] |= vp & ~mask;
+			}
+
+			ar7240_vtu_op(as,
+				AR7240_VTU_OP_LOAD |
+				(as->vlan_id[j] << AR7240_VTU_VID_S),
+				as->vlan_table[j]);
+		}
+	} else {
+		/* vlan disabled:
+		 * isolate all ports, but connect them to the cpu port */
+		for (i = 0; i < as->swdev.ports; i++) {
+			if (i == AR7240_PORT_CPU)
+				continue;
+
+			portmask[i] = 1 << AR7240_PORT_CPU;
+			portmask[AR7240_PORT_CPU] |= (1 << i);
+		}
+	}
+
+	/* update the port destination mask registers and tag settings */
+	for (i = 0; i < as->swdev.ports; i++)
+		ar7240sw_setup_port(as, i, portmask[i]);
+
+	return 0;
+}
+
+static int
+ar7240_reset_switch(struct switch_dev *dev)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	ar7240sw_reset(as);
+	return 0;
+}
+
+static int
+ar7240_get_port_link(struct switch_dev *dev, int port,
+		     struct switch_port_link *link)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+	struct mii_bus *mii = as->mii_bus;
+	u32 status;
+
+	if (port > AR7240_NUM_PORTS)
+		return -EINVAL;
+
+	status = ar7240sw_reg_read(mii, AR7240_REG_PORT_STATUS(port));
+	link->aneg = !!(status & AR7240_PORT_STATUS_LINK_AUTO);
+	if (link->aneg) {
+		link->link = !!(status & AR7240_PORT_STATUS_LINK_UP);
+		if (!link->link)
+			return 0;
+	} else {
+		link->link = true;
+	}
+
+	link->duplex = !!(status & AR7240_PORT_STATUS_DUPLEX);
+	link->tx_flow = !!(status & AR7240_PORT_STATUS_TXFLOW);
+	link->rx_flow = !!(status & AR7240_PORT_STATUS_RXFLOW);
+	switch (status & AR7240_PORT_STATUS_SPEED_M) {
+	case AR7240_PORT_STATUS_SPEED_10:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case AR7240_PORT_STATUS_SPEED_100:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case AR7240_PORT_STATUS_SPEED_1000:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	}
+
+	return 0;
+}
+
+static int
+ar7240_get_port_stats(struct switch_dev *dev, int port,
+		      struct switch_port_stats *stats)
+{
+	struct ar7240sw *as = sw_to_ar7240(dev);
+
+	if (port > AR7240_NUM_PORTS)
+		return -EINVAL;
+
+	ar7240sw_capture_stats(as);
+
+	read_lock(&as->stats_lock);
+	stats->rx_bytes = as->port_stats[port].rx_good_byte;
+	stats->tx_bytes = as->port_stats[port].tx_byte;
+	read_unlock(&as->stats_lock);
+
+	return 0;
+}
+
+static struct switch_attr ar7240_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = ar7240_set_vlan,
+		.get = ar7240_get_vlan,
+		.max = 1
+	},
+};
+
+static struct switch_attr ar7240_port[] = {
+};
+
+static struct switch_attr ar7240_vlan[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "vid",
+		.description = "VLAN ID",
+		.set = ar7240_set_vid,
+		.get = ar7240_get_vid,
+		.max = 4094,
+	},
+};
+
+static const struct switch_dev_ops ar7240_ops = {
+	.attr_global = {
+		.attr = ar7240_globals,
+		.n_attr = ARRAY_SIZE(ar7240_globals),
+	},
+	.attr_port = {
+		.attr = ar7240_port,
+		.n_attr = ARRAY_SIZE(ar7240_port),
+	},
+	.attr_vlan = {
+		.attr = ar7240_vlan,
+		.n_attr = ARRAY_SIZE(ar7240_vlan),
+	},
+	.get_port_pvid = ar7240_get_pvid,
+	.set_port_pvid = ar7240_set_pvid,
+	.get_vlan_ports = ar7240_get_ports,
+	.set_vlan_ports = ar7240_set_ports,
+	.apply_config = ar7240_hw_apply,
+	.reset_switch = ar7240_reset_switch,
+	.get_port_link = ar7240_get_port_link,
+	.get_port_stats = ar7240_get_port_stats,
+};
+
+static struct ar7240sw *ar7240_probe(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	struct mii_bus *mii = ag->mii_bus;
+	struct ar7240sw *as;
+	struct switch_dev *swdev;
+	u32 ctrl;
+	u16 phy_id1;
+	u16 phy_id2;
+	int i;
+
+	phy_id1 = ar7240sw_phy_read(mii, 0, MII_PHYSID1);
+	phy_id2 = ar7240sw_phy_read(mii, 0, MII_PHYSID2);
+	if ((phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) &&
+	    (phy_id1 != AR934X_PHY_ID1 || phy_id2 != AR934X_PHY_ID2)) {
+		pr_err("%s: unknown phy id '%04x:%04x'\n",
+		       dev_name(&mii->dev), phy_id1, phy_id2);
+		return NULL;
+	}
+
+	as = kzalloc(sizeof(*as), GFP_KERNEL);
+	if (!as)
+		return NULL;
+
+	as->mii_bus = mii;
+	as->swdata = pdata->switch_data;
+
+	swdev = &as->swdev;
+
+	ctrl = ar7240sw_reg_read(mii, AR7240_REG_MASK_CTRL);
+	as->ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) &
+		  AR7240_MASK_CTRL_VERSION_M;
+
+	if (sw_is_ar7240(as)) {
+		swdev->name = "AR7240/AR9330 built-in switch";
+		swdev->ports = AR7240_NUM_PORTS - 1;
+	} else if (sw_is_ar934x(as)) {
+		swdev->name = "AR934X built-in switch";
+
+		if (pdata->phy_if_mode == PHY_INTERFACE_MODE_GMII) {
+			ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0,
+					 AR934X_OPER_MODE0_MAC_GMII_EN);
+		} else if (pdata->phy_if_mode == PHY_INTERFACE_MODE_MII) {
+			ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0,
+					 AR934X_OPER_MODE0_PHY_MII_EN);
+		} else {
+			pr_err("%s: invalid PHY interface mode\n",
+			       dev_name(&mii->dev));
+			goto err_free;
+		}
+
+		if (as->swdata->phy4_mii_en) {
+			ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE1,
+					 AR934X_REG_OPER_MODE1_PHY4_MII_EN);
+			swdev->ports = AR7240_NUM_PORTS - 1;
+		} else {
+			swdev->ports = AR7240_NUM_PORTS;
+		}
+	} else {
+		pr_err("%s: unsupported chip, ctrl=%08x\n",
+			dev_name(&mii->dev), ctrl);
+		goto err_free;
+	}
+
+	swdev->cpu_port = AR7240_PORT_CPU;
+	swdev->vlans = AR7240_MAX_VLANS;
+	swdev->ops = &ar7240_ops;
+
+	if (register_switch(&as->swdev, ag->dev) < 0)
+		goto err_free;
+
+	pr_info("%s: Found an %s\n", dev_name(&mii->dev), swdev->name);
+
+	/* initialize defaults */
+	for (i = 0; i < AR7240_MAX_VLANS; i++)
+		as->vlan_id[i] = i;
+
+	as->vlan_table[0] = ar7240sw_port_mask_all(as);
+
+	return as;
+
+err_free:
+	kfree(as);
+	return NULL;
+}
+
+static void link_function(struct work_struct *work) {
+	struct ag71xx *ag = container_of(work, struct ag71xx, link_work.work);
+	struct ar7240sw *as = ag->phy_priv;
+	unsigned long flags;
+	u8 mask;
+	int i;
+	int status = 0;
+
+	mask = ~as->swdata->phy_poll_mask;
+	for (i = 0; i < AR7240_NUM_PHYS; i++) {
+		int link;
+
+		if (!(mask & BIT(i)))
+			continue;
+
+		link = ar7240sw_phy_read(ag->mii_bus, i, MII_BMSR);
+		if (link & BMSR_LSTATUS) {
+			status = 1;
+			break;
+		}
+	}
+
+	spin_lock_irqsave(&ag->lock, flags);
+	if (status != ag->link) {
+		ag->link = status;
+		ag71xx_link_adjust(ag);
+	}
+	spin_unlock_irqrestore(&ag->lock, flags);
+
+	schedule_delayed_work(&ag->link_work, HZ / 2);
+}
+
+void ag71xx_ar7240_start(struct ag71xx *ag)
+{
+	struct ar7240sw *as = ag->phy_priv;
+
+	ar7240sw_reset(as);
+
+	ag->speed = SPEED_1000;
+	ag->duplex = 1;
+
+	ar7240_set_addr(as, ag->dev->dev_addr);
+	ar7240_hw_apply(&as->swdev);
+
+	schedule_delayed_work(&ag->link_work, HZ / 10);
+}
+
+void ag71xx_ar7240_stop(struct ag71xx *ag)
+{
+	cancel_delayed_work_sync(&ag->link_work);
+}
+
+int ag71xx_ar7240_init(struct ag71xx *ag)
+{
+	struct ar7240sw *as;
+
+	as = ar7240_probe(ag);
+	if (!as)
+		return -ENODEV;
+
+	ag->phy_priv = as;
+	ar7240sw_reset(as);
+
+	rwlock_init(&as->stats_lock);
+	INIT_DELAYED_WORK(&ag->link_work, link_function);
+
+	return 0;
+}
+
+void ag71xx_ar7240_cleanup(struct ag71xx *ag)
+{
+	struct ar7240sw *as = ag->phy_priv;
+
+	if (!as)
+		return;
+
+	unregister_switch(&as->swdev);
+	kfree(as);
+	ag->phy_priv = NULL;
+}
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c
new file mode 100644
index 0000000000..7ec43b7221
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c
@@ -0,0 +1,44 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *  Special support for the Atheros ar8216 switch chip
+ *
+ *  Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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 "ag71xx.h"
+
+#define AR8216_PACKET_TYPE_MASK		0xf
+#define AR8216_PACKET_TYPE_NORMAL	0
+
+#define AR8216_HEADER_LEN	2
+
+void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb)
+{
+	skb_push(skb, AR8216_HEADER_LEN);
+	skb->data[0] = 0x10;
+	skb->data[1] = 0x80;
+}
+
+int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
+				int pktlen)
+{
+	u8 type;
+
+	type = skb->data[1] & AR8216_PACKET_TYPE_MASK;
+	switch (type) {
+	case AR8216_PACKET_TYPE_NORMAL:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	skb_pull(skb, AR8216_HEADER_LEN);
+	return 0;
+}
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c
new file mode 100644
index 0000000000..c86803c9ce
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c
@@ -0,0 +1,287 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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/debugfs.h>
+
+#include "ag71xx.h"
+
+static struct dentry *ag71xx_debugfs_root;
+
+static int ag71xx_debugfs_generic_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status)
+{
+	if (status)
+		ag->debug.int_stats.total++;
+	if (status & AG71XX_INT_TX_PS)
+		ag->debug.int_stats.tx_ps++;
+	if (status & AG71XX_INT_TX_UR)
+		ag->debug.int_stats.tx_ur++;
+	if (status & AG71XX_INT_TX_BE)
+		ag->debug.int_stats.tx_be++;
+	if (status & AG71XX_INT_RX_PR)
+		ag->debug.int_stats.rx_pr++;
+	if (status & AG71XX_INT_RX_OF)
+		ag->debug.int_stats.rx_of++;
+	if (status & AG71XX_INT_RX_BE)
+		ag->debug.int_stats.rx_be++;
+}
+
+static ssize_t read_file_int_stats(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+#define PR_INT_STAT(_label, _field)					\
+	len += snprintf(buf + len, sizeof(buf) - len,			\
+		"%20s: %10lu\n", _label, ag->debug.int_stats._field);
+
+	struct ag71xx *ag = file->private_data;
+	char buf[256];
+	unsigned int len = 0;
+
+	PR_INT_STAT("TX Packet Sent", tx_ps);
+	PR_INT_STAT("TX Underrun", tx_ur);
+	PR_INT_STAT("TX Bus Error", tx_be);
+	PR_INT_STAT("RX Packet Received", rx_pr);
+	PR_INT_STAT("RX Overflow", rx_of);
+	PR_INT_STAT("RX Bus Error", rx_be);
+	len += snprintf(buf + len, sizeof(buf) - len, "\n");
+	PR_INT_STAT("Total", total);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+#undef PR_INT_STAT
+}
+
+static const struct file_operations ag71xx_fops_int_stats = {
+	.open	= ag71xx_debugfs_generic_open,
+	.read	= read_file_int_stats,
+	.owner	= THIS_MODULE
+};
+
+void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx)
+{
+	struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
+
+	if (rx) {
+		stats->rx_count++;
+		stats->rx_packets += rx;
+		if (rx <= AG71XX_NAPI_WEIGHT)
+			stats->rx[rx]++;
+		if (rx > stats->rx_packets_max)
+			stats->rx_packets_max = rx;
+	}
+
+	if (tx) {
+		stats->tx_count++;
+		stats->tx_packets += tx;
+		if (tx <= AG71XX_NAPI_WEIGHT)
+			stats->tx[tx]++;
+		if (tx > stats->tx_packets_max)
+			stats->tx_packets_max = tx;
+	}
+}
+
+static ssize_t read_file_napi_stats(struct file *file, char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ag71xx *ag = file->private_data;
+	struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
+	char *buf;
+	unsigned int buflen;
+	unsigned int len = 0;
+	unsigned long rx_avg = 0;
+	unsigned long tx_avg = 0;
+	int ret;
+	int i;
+
+	buflen = 2048;
+	buf = kmalloc(buflen, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (stats->rx_count)
+		rx_avg = stats->rx_packets / stats->rx_count;
+
+	if (stats->tx_count)
+		tx_avg = stats->tx_packets / stats->tx_count;
+
+	len += snprintf(buf + len, buflen - len, "%3s  %10s %10s\n",
+			"len", "rx", "tx");
+
+	for (i = 1; i <= AG71XX_NAPI_WEIGHT; i++)
+		len += snprintf(buf + len, buflen - len,
+				"%3d: %10lu %10lu\n",
+				i, stats->rx[i], stats->tx[i]);
+
+	len += snprintf(buf + len, buflen - len, "\n");
+
+	len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
+			"sum", stats->rx_count, stats->tx_count);
+	len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
+			"avg", rx_avg, tx_avg);
+	len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
+			"max", stats->rx_packets_max, stats->tx_packets_max);
+	len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
+			"pkt", stats->rx_packets, stats->tx_packets);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return ret;
+}
+
+static const struct file_operations ag71xx_fops_napi_stats = {
+	.open	= ag71xx_debugfs_generic_open,
+	.read	= read_file_napi_stats,
+	.owner	= THIS_MODULE
+};
+
+#define DESC_PRINT_LEN	64
+
+static ssize_t read_file_ring(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos,
+			      struct ag71xx *ag,
+			      struct ag71xx_ring *ring,
+			      unsigned desc_reg)
+{
+	int ring_size = BIT(ring->order);
+	int ring_mask = ring_size - 1;
+	char *buf;
+	unsigned int buflen;
+	unsigned int len = 0;
+	unsigned long flags;
+	ssize_t ret;
+	int curr;
+	int dirty;
+	u32 desc_hw;
+	int i;
+
+	buflen = (ring_size * DESC_PRINT_LEN);
+	buf = kmalloc(buflen, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	len += snprintf(buf + len, buflen - len,
+			"Idx ... %-8s %-8s %-8s %-8s . %-10s\n",
+			"desc", "next", "data", "ctrl", "timestamp");
+
+	spin_lock_irqsave(&ag->lock, flags);
+
+	curr = (ring->curr & ring_mask);
+	dirty = (ring->dirty & ring_mask);
+	desc_hw = ag71xx_rr(ag, desc_reg);
+	for (i = 0; i < ring_size; i++) {
+		struct ag71xx_buf *ab = &ring->buf[i];
+		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+		u32 desc_dma = ((u32) ring->descs_dma) + i * AG71XX_DESC_SIZE;
+
+		len += snprintf(buf + len, buflen - len,
+			"%3d %c%c%c %08x %08x %08x %08x %c %10lu\n",
+			i,
+			(i == curr) ? 'C' : ' ',
+			(i == dirty) ? 'D' : ' ',
+			(desc_hw == desc_dma) ? 'H' : ' ',
+			desc_dma,
+			desc->next,
+			desc->data,
+			desc->ctrl,
+			(desc->ctrl & DESC_EMPTY) ? 'E' : '*',
+			ab->timestamp);
+	}
+
+	spin_unlock_irqrestore(&ag->lock, flags);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t read_file_tx_ring(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	struct ag71xx *ag = file->private_data;
+
+	return read_file_ring(file, user_buf, count, ppos, ag, &ag->tx_ring,
+			      AG71XX_REG_TX_DESC);
+}
+
+static const struct file_operations ag71xx_fops_tx_ring = {
+	.open	= ag71xx_debugfs_generic_open,
+	.read	= read_file_tx_ring,
+	.owner	= THIS_MODULE
+};
+
+static ssize_t read_file_rx_ring(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	struct ag71xx *ag = file->private_data;
+
+	return read_file_ring(file, user_buf, count, ppos, ag, &ag->rx_ring,
+			      AG71XX_REG_RX_DESC);
+}
+
+static const struct file_operations ag71xx_fops_rx_ring = {
+	.open	= ag71xx_debugfs_generic_open,
+	.read	= read_file_rx_ring,
+	.owner	= THIS_MODULE
+};
+
+void ag71xx_debugfs_exit(struct ag71xx *ag)
+{
+	debugfs_remove_recursive(ag->debug.debugfs_dir);
+}
+
+int ag71xx_debugfs_init(struct ag71xx *ag)
+{
+	struct device *dev = &ag->pdev->dev;
+
+	ag->debug.debugfs_dir = debugfs_create_dir(dev_name(dev),
+						   ag71xx_debugfs_root);
+	if (!ag->debug.debugfs_dir) {
+		dev_err(dev, "unable to create debugfs directory\n");
+		return -ENOENT;
+	}
+
+	debugfs_create_file("int_stats", S_IRUGO, ag->debug.debugfs_dir,
+			    ag, &ag71xx_fops_int_stats);
+	debugfs_create_file("napi_stats", S_IRUGO, ag->debug.debugfs_dir,
+			    ag, &ag71xx_fops_napi_stats);
+	debugfs_create_file("tx_ring", S_IRUGO, ag->debug.debugfs_dir,
+			    ag, &ag71xx_fops_tx_ring);
+	debugfs_create_file("rx_ring", S_IRUGO, ag->debug.debugfs_dir,
+			    ag, &ag71xx_fops_rx_ring);
+
+	return 0;
+}
+
+int ag71xx_debugfs_root_init(void)
+{
+	if (ag71xx_debugfs_root)
+		return -EBUSY;
+
+	ag71xx_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (!ag71xx_debugfs_root)
+		return -ENOENT;
+
+	return 0;
+}
+
+void ag71xx_debugfs_root_exit(void)
+{
+	debugfs_remove(ag71xx_debugfs_root);
+	ag71xx_debugfs_root = NULL;
+}
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
new file mode 100644
index 0000000000..dfcbb54e93
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
@@ -0,0 +1,131 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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 "ag71xx.h"
+
+static int ag71xx_ethtool_get_settings(struct net_device *dev,
+				       struct ethtool_cmd *cmd)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	struct phy_device *phydev = ag->phy_dev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_gset(phydev, cmd);
+}
+
+static int ag71xx_ethtool_set_settings(struct net_device *dev,
+				       struct ethtool_cmd *cmd)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	struct phy_device *phydev = ag->phy_dev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_sset(phydev, cmd);
+}
+
+static void ag71xx_ethtool_get_drvinfo(struct net_device *dev,
+				       struct ethtool_drvinfo *info)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+
+	strcpy(info->driver, ag->pdev->dev.driver->name);
+	strcpy(info->version, AG71XX_DRV_VERSION);
+	strcpy(info->bus_info, dev_name(&ag->pdev->dev));
+}
+
+static u32 ag71xx_ethtool_get_msglevel(struct net_device *dev)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+
+	return ag->msg_enable;
+}
+
+static void ag71xx_ethtool_set_msglevel(struct net_device *dev, u32 msg_level)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+
+	ag->msg_enable = msg_level;
+}
+
+static void ag71xx_ethtool_get_ringparam(struct net_device *dev,
+					 struct ethtool_ringparam *er)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+
+	er->tx_max_pending = AG71XX_TX_RING_SIZE_MAX;
+	er->rx_max_pending = AG71XX_RX_RING_SIZE_MAX;
+	er->rx_mini_max_pending = 0;
+	er->rx_jumbo_max_pending = 0;
+
+	er->tx_pending = BIT(ag->tx_ring.order);
+	er->rx_pending = BIT(ag->rx_ring.order);
+	er->rx_mini_pending = 0;
+	er->rx_jumbo_pending = 0;
+
+	if (ag->tx_ring.desc_split)
+		er->tx_pending /= AG71XX_TX_RING_DS_PER_PKT;
+}
+
+static int ag71xx_ethtool_set_ringparam(struct net_device *dev,
+					struct ethtool_ringparam *er)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	unsigned tx_size;
+	unsigned rx_size;
+	int err;
+
+	if (er->rx_mini_pending != 0||
+	    er->rx_jumbo_pending != 0 ||
+	    er->rx_pending == 0 ||
+	    er->tx_pending == 0)
+		return -EINVAL;
+
+	tx_size = er->tx_pending < AG71XX_TX_RING_SIZE_MAX ?
+		  er->tx_pending : AG71XX_TX_RING_SIZE_MAX;
+
+	rx_size = er->rx_pending < AG71XX_RX_RING_SIZE_MAX ?
+		  er->rx_pending : AG71XX_RX_RING_SIZE_MAX;
+
+	if (netif_running(dev)) {
+		err = dev->netdev_ops->ndo_stop(dev);
+		if (err)
+			return err;
+	}
+
+	if (ag->tx_ring.desc_split)
+		tx_size *= AG71XX_TX_RING_DS_PER_PKT;
+
+	ag->tx_ring.order = ag71xx_ring_size_order(tx_size);
+	ag->rx_ring.order = ag71xx_ring_size_order(rx_size);
+
+	if (netif_running(dev))
+		err = dev->netdev_ops->ndo_open(dev);
+
+	return err;
+}
+
+struct ethtool_ops ag71xx_ethtool_ops = {
+	.set_settings	= ag71xx_ethtool_set_settings,
+	.get_settings	= ag71xx_ethtool_get_settings,
+	.get_drvinfo	= ag71xx_ethtool_get_drvinfo,
+	.get_msglevel	= ag71xx_ethtool_get_msglevel,
+	.set_msglevel	= ag71xx_ethtool_set_msglevel,
+	.get_ringparam	= ag71xx_ethtool_get_ringparam,
+	.set_ringparam	= ag71xx_ethtool_set_ringparam,
+	.get_link	= ethtool_op_get_link,
+	.get_ts_info	= ethtool_op_get_ts_info,
+};
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
new file mode 100644
index 0000000000..566e9513d8
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
@@ -0,0 +1,1478 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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 "ag71xx.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
+static inline void skb_free_frag(void *data)
+{
+	put_page(virt_to_head_page(data));
+}
+#endif
+
+#define AG71XX_DEFAULT_MSG_ENABLE	\
+	(NETIF_MSG_DRV			\
+	| NETIF_MSG_PROBE		\
+	| NETIF_MSG_LINK		\
+	| NETIF_MSG_TIMER		\
+	| NETIF_MSG_IFDOWN		\
+	| NETIF_MSG_IFUP		\
+	| NETIF_MSG_RX_ERR		\
+	| NETIF_MSG_TX_ERR)
+
+static int ag71xx_msg_level = -1;
+
+module_param_named(msg_level, ag71xx_msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
+
+#define ETH_SWITCH_HEADER_LEN	2
+
+static int ag71xx_tx_packets(struct ag71xx *ag, bool flush);
+
+static inline unsigned int ag71xx_max_frame_len(unsigned int mtu)
+{
+	return ETH_SWITCH_HEADER_LEN + ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
+}
+
+static void ag71xx_dump_dma_regs(struct ag71xx *ag)
+{
+	DBG("%s: dma_tx_ctrl=%08x, dma_tx_desc=%08x, dma_tx_status=%08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_TX_CTRL),
+		ag71xx_rr(ag, AG71XX_REG_TX_DESC),
+		ag71xx_rr(ag, AG71XX_REG_TX_STATUS));
+
+	DBG("%s: dma_rx_ctrl=%08x, dma_rx_desc=%08x, dma_rx_status=%08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_RX_CTRL),
+		ag71xx_rr(ag, AG71XX_REG_RX_DESC),
+		ag71xx_rr(ag, AG71XX_REG_RX_STATUS));
+}
+
+static void ag71xx_dump_regs(struct ag71xx *ag)
+{
+	DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_MAC_CFG1),
+		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
+		ag71xx_rr(ag, AG71XX_REG_MAC_IPG),
+		ag71xx_rr(ag, AG71XX_REG_MAC_HDX),
+		ag71xx_rr(ag, AG71XX_REG_MAC_MFL));
+	DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
+		ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1),
+		ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2));
+	DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
+	DBG("%s: fifo_cfg3=%08x, fifo_cfg4=%08x, fifo_cfg5=%08x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
+}
+
+static inline void ag71xx_dump_intr(struct ag71xx *ag, char *label, u32 intr)
+{
+	DBG("%s: %s intr=%08x %s%s%s%s%s%s\n",
+		ag->dev->name, label, intr,
+		(intr & AG71XX_INT_TX_PS) ? "TXPS " : "",
+		(intr & AG71XX_INT_TX_UR) ? "TXUR " : "",
+		(intr & AG71XX_INT_TX_BE) ? "TXBE " : "",
+		(intr & AG71XX_INT_RX_PR) ? "RXPR " : "",
+		(intr & AG71XX_INT_RX_OF) ? "RXOF " : "",
+		(intr & AG71XX_INT_RX_BE) ? "RXBE " : "");
+}
+
+static void ag71xx_ring_free(struct ag71xx_ring *ring)
+{
+	int ring_size = BIT(ring->order);
+	kfree(ring->buf);
+
+	if (ring->descs_cpu)
+		dma_free_coherent(NULL, ring_size * AG71XX_DESC_SIZE,
+				  ring->descs_cpu, ring->descs_dma);
+}
+
+static int ag71xx_ring_alloc(struct ag71xx_ring *ring)
+{
+	int ring_size = BIT(ring->order);
+	int err;
+
+	ring->descs_cpu = dma_alloc_coherent(NULL, ring_size * AG71XX_DESC_SIZE,
+					     &ring->descs_dma, GFP_ATOMIC);
+	if (!ring->descs_cpu) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+
+	ring->buf = kzalloc(ring_size * sizeof(*ring->buf), GFP_KERNEL);
+	if (!ring->buf) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return err;
+}
+
+static void ag71xx_ring_tx_clean(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->tx_ring;
+	struct net_device *dev = ag->dev;
+	int ring_mask = BIT(ring->order) - 1;
+	u32 bytes_compl = 0, pkts_compl = 0;
+
+	while (ring->curr != ring->dirty) {
+		struct ag71xx_desc *desc;
+		u32 i = ring->dirty & ring_mask;
+
+		desc = ag71xx_ring_desc(ring, i);
+		if (!ag71xx_desc_empty(desc)) {
+			desc->ctrl = 0;
+			dev->stats.tx_errors++;
+		}
+
+		if (ring->buf[i].skb) {
+			bytes_compl += ring->buf[i].len;
+			pkts_compl++;
+			dev_kfree_skb_any(ring->buf[i].skb);
+		}
+		ring->buf[i].skb = NULL;
+		ring->dirty++;
+	}
+
+	/* flush descriptors */
+	wmb();
+
+	netdev_completed_queue(dev, pkts_compl, bytes_compl);
+}
+
+static void ag71xx_ring_tx_init(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->tx_ring;
+	int ring_size = BIT(ring->order);
+	int ring_mask = ring_size - 1;
+	int i;
+
+	for (i = 0; i < ring_size; i++) {
+		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+
+		desc->next = (u32) (ring->descs_dma +
+			AG71XX_DESC_SIZE * ((i + 1) & ring_mask));
+
+		desc->ctrl = DESC_EMPTY;
+		ring->buf[i].skb = NULL;
+	}
+
+	/* flush descriptors */
+	wmb();
+
+	ring->curr = 0;
+	ring->dirty = 0;
+	netdev_reset_queue(ag->dev);
+}
+
+static void ag71xx_ring_rx_clean(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	int ring_size = BIT(ring->order);
+	int i;
+
+	if (!ring->buf)
+		return;
+
+	for (i = 0; i < ring_size; i++)
+		if (ring->buf[i].rx_buf) {
+			dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
+					 ag->rx_buf_size, DMA_FROM_DEVICE);
+			skb_free_frag(ring->buf[i].rx_buf);
+		}
+}
+
+static int ag71xx_buffer_offset(struct ag71xx *ag)
+{
+	int offset = NET_SKB_PAD;
+
+	/*
+	 * On AR71xx/AR91xx packets must be 4-byte aligned.
+	 *
+	 * When using builtin AR8216 support, hardware adds a 2-byte header,
+	 * so we don't need any extra alignment in that case.
+	 */
+	if (!ag71xx_get_pdata(ag)->is_ar724x || ag71xx_has_ar8216(ag))
+		return offset;
+
+	return offset + NET_IP_ALIGN;
+}
+
+static int ag71xx_buffer_size(struct ag71xx *ag)
+{
+	return ag->rx_buf_size +
+	       SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+}
+
+static bool ag71xx_fill_rx_buf(struct ag71xx *ag, struct ag71xx_buf *buf,
+			       int offset,
+			       void *(*alloc)(unsigned int size))
+{
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	struct ag71xx_desc *desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]);
+	void *data;
+
+	data = alloc(ag71xx_buffer_size(ag));
+	if (!data)
+		return false;
+
+	buf->rx_buf = data;
+	buf->dma_addr = dma_map_single(&ag->dev->dev, data, ag->rx_buf_size,
+				       DMA_FROM_DEVICE);
+	desc->data = (u32) buf->dma_addr + offset;
+	return true;
+}
+
+static int ag71xx_ring_rx_init(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	int ring_size = BIT(ring->order);
+	int ring_mask = BIT(ring->order) - 1;
+	unsigned int i;
+	int ret;
+	int offset = ag71xx_buffer_offset(ag);
+
+	ret = 0;
+	for (i = 0; i < ring_size; i++) {
+		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+
+		desc->next = (u32) (ring->descs_dma +
+			AG71XX_DESC_SIZE * ((i + 1) & ring_mask));
+
+		DBG("ag71xx: RX desc at %p, next is %08x\n",
+			desc, desc->next);
+	}
+
+	for (i = 0; i < ring_size; i++) {
+		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+
+		if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], offset,
+					netdev_alloc_frag)) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		desc->ctrl = DESC_EMPTY;
+	}
+
+	/* flush descriptors */
+	wmb();
+
+	ring->curr = 0;
+	ring->dirty = 0;
+
+	return ret;
+}
+
+static int ag71xx_ring_rx_refill(struct ag71xx *ag)
+{
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	int ring_mask = BIT(ring->order) - 1;
+	unsigned int count;
+	int offset = ag71xx_buffer_offset(ag);
+
+	count = 0;
+	for (; ring->curr - ring->dirty > 0; ring->dirty++) {
+		struct ag71xx_desc *desc;
+		unsigned int i;
+
+		i = ring->dirty & ring_mask;
+		desc = ag71xx_ring_desc(ring, i);
+
+		if (!ring->buf[i].rx_buf &&
+		    !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset,
+					napi_alloc_frag))
+			break;
+
+		desc->ctrl = DESC_EMPTY;
+		count++;
+	}
+
+	/* flush descriptors */
+	wmb();
+
+	DBG("%s: %u rx descriptors refilled\n", ag->dev->name, count);
+
+	return count;
+}
+
+static int ag71xx_rings_init(struct ag71xx *ag)
+{
+	int ret;
+
+	ret = ag71xx_ring_alloc(&ag->tx_ring);
+	if (ret)
+		return ret;
+
+	ag71xx_ring_tx_init(ag);
+
+	ret = ag71xx_ring_alloc(&ag->rx_ring);
+	if (ret)
+		return ret;
+
+	ret = ag71xx_ring_rx_init(ag);
+	return ret;
+}
+
+static void ag71xx_rings_cleanup(struct ag71xx *ag)
+{
+	ag71xx_ring_rx_clean(ag);
+	ag71xx_ring_free(&ag->rx_ring);
+
+	ag71xx_ring_tx_clean(ag);
+	netdev_reset_queue(ag->dev);
+	ag71xx_ring_free(&ag->tx_ring);
+}
+
+static unsigned char *ag71xx_speed_str(struct ag71xx *ag)
+{
+	switch (ag->speed) {
+	case SPEED_1000:
+		return "1000";
+	case SPEED_100:
+		return "100";
+	case SPEED_10:
+		return "10";
+	}
+
+	return "?";
+}
+
+static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
+{
+	u32 t;
+
+	t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16)
+	  | (((u32) mac[3]) << 8) | ((u32) mac[2]);
+
+	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
+
+	t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16);
+	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
+}
+
+static void ag71xx_dma_reset(struct ag71xx *ag)
+{
+	u32 val;
+	int i;
+
+	ag71xx_dump_dma_regs(ag);
+
+	/* stop RX and TX */
+	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+
+	/*
+	 * give the hardware some time to really stop all rx/tx activity
+	 * clearing the descriptors too early causes random memory corruption
+	 */
+	mdelay(1);
+
+	/* clear descriptor addresses */
+	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma);
+	ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma);
+
+	/* clear pending RX/TX interrupts */
+	for (i = 0; i < 256; i++) {
+		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
+		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
+	}
+
+	/* clear pending errors */
+	ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
+	ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
+
+	val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
+	if (val)
+		pr_alert("%s: unable to clear DMA Rx status: %08x\n",
+			 ag->dev->name, val);
+
+	val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
+
+	/* mask out reserved bits */
+	val &= ~0xff000000;
+
+	if (val)
+		pr_alert("%s: unable to clear DMA Tx status: %08x\n",
+			 ag->dev->name, val);
+
+	ag71xx_dump_dma_regs(ag);
+}
+
+#define MAC_CFG1_INIT	(MAC_CFG1_RXE | MAC_CFG1_TXE | \
+			 MAC_CFG1_SRX | MAC_CFG1_STX)
+
+#define FIFO_CFG0_INIT	(FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
+
+#define FIFO_CFG4_INIT	(FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
+			 FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
+			 FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
+			 FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
+			 FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
+			 FIFO_CFG4_VT)
+
+#define FIFO_CFG5_INIT	(FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
+			 FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
+			 FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
+			 FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
+			 FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
+			 FIFO_CFG5_17 | FIFO_CFG5_SF)
+
+static void ag71xx_hw_stop(struct ag71xx *ag)
+{
+	/* disable all interrupts and stop the rx/tx engine */
+	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
+	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+}
+
+static void ag71xx_hw_setup(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	u32 init = MAC_CFG1_INIT;
+
+	/* setup MAC configuration registers */
+	if (pdata->use_flow_control)
+		init |= MAC_CFG1_TFC | MAC_CFG1_RFC;
+	ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, init);
+
+	ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
+		  MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
+
+	/* setup max frame length to zero */
+	ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 0);
+
+	/* setup FIFO configuration registers */
+	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
+	if (pdata->is_ar724x) {
+		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, pdata->fifo_cfg1);
+		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, pdata->fifo_cfg2);
+	} else {
+		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000);
+		ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff);
+	}
+	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
+	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
+}
+
+static void ag71xx_hw_init(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	u32 reset_mask = pdata->reset_bit;
+
+	ag71xx_hw_stop(ag);
+
+	if (pdata->is_ar724x) {
+		u32 reset_phy = reset_mask;
+
+		reset_phy &= AR71XX_RESET_GE0_PHY | AR71XX_RESET_GE1_PHY;
+		reset_mask &= ~(AR71XX_RESET_GE0_PHY | AR71XX_RESET_GE1_PHY);
+
+		ath79_device_reset_set(reset_phy);
+		msleep(50);
+		ath79_device_reset_clear(reset_phy);
+		msleep(200);
+	}
+
+	ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
+	udelay(20);
+
+	ath79_device_reset_set(reset_mask);
+	msleep(100);
+	ath79_device_reset_clear(reset_mask);
+	msleep(200);
+
+	ag71xx_hw_setup(ag);
+
+	ag71xx_dma_reset(ag);
+}
+
+static void ag71xx_fast_reset(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	struct net_device *dev = ag->dev;
+	u32 reset_mask = pdata->reset_bit;
+	u32 rx_ds;
+	u32 mii_reg;
+
+	reset_mask &= AR71XX_RESET_GE0_MAC | AR71XX_RESET_GE1_MAC;
+
+	ag71xx_hw_stop(ag);
+	wmb();
+
+	mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG);
+	rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC);
+
+	ag71xx_tx_packets(ag, true);
+
+	ath79_device_reset_set(reset_mask);
+	udelay(10);
+	ath79_device_reset_clear(reset_mask);
+	udelay(10);
+
+	ag71xx_dma_reset(ag);
+	ag71xx_hw_setup(ag);
+	ag->tx_ring.curr = 0;
+	ag->tx_ring.dirty = 0;
+	netdev_reset_queue(ag->dev);
+
+	/* setup max frame length */
+	ag71xx_wr(ag, AG71XX_REG_MAC_MFL,
+		  ag71xx_max_frame_len(ag->dev->mtu));
+
+	ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds);
+	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
+	ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg);
+
+	ag71xx_hw_set_macaddr(ag, dev->dev_addr);
+}
+
+static void ag71xx_hw_start(struct ag71xx *ag)
+{
+	/* start RX engine */
+	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+
+	/* enable interrupts */
+	ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
+
+	netif_wake_queue(ag->dev);
+}
+
+static void
+__ag71xx_link_adjust(struct ag71xx *ag, bool update)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	u32 cfg2;
+	u32 ifctl;
+	u32 fifo5;
+	u32 fifo3;
+
+	if (!ag->link && update) {
+		ag71xx_hw_stop(ag);
+		netif_carrier_off(ag->dev);
+		if (netif_msg_link(ag))
+			pr_info("%s: link down\n", ag->dev->name);
+		return;
+	}
+
+	if (pdata->is_ar724x)
+		ag71xx_fast_reset(ag);
+
+	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
+	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
+	cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
+
+	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
+	ifctl &= ~(MAC_IFCTL_SPEED);
+
+	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
+	fifo5 &= ~FIFO_CFG5_BM;
+
+	switch (ag->speed) {
+	case SPEED_1000:
+		cfg2 |= MAC_CFG2_IF_1000;
+		fifo5 |= FIFO_CFG5_BM;
+		break;
+	case SPEED_100:
+		cfg2 |= MAC_CFG2_IF_10_100;
+		ifctl |= MAC_IFCTL_SPEED;
+		break;
+	case SPEED_10:
+		cfg2 |= MAC_CFG2_IF_10_100;
+		break;
+	default:
+		BUG();
+		return;
+	}
+
+	if (pdata->is_ar91xx)
+		fifo3 = 0x00780fff;
+	else if (pdata->is_ar724x)
+		fifo3 = pdata->fifo_cfg3;
+	else
+		fifo3 = 0x008001ff;
+
+	if (ag->tx_ring.desc_split) {
+		fifo3 &= 0xffff;
+		fifo3 |= ((2048 - ag->tx_ring.desc_split) / 4) << 16;
+	}
+
+	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, fifo3);
+
+	if (update && pdata->set_speed)
+		pdata->set_speed(ag->speed);
+
+	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
+	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
+	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
+	ag71xx_hw_start(ag);
+
+	netif_carrier_on(ag->dev);
+	if (update && netif_msg_link(ag))
+		pr_info("%s: link up (%sMbps/%s duplex)\n",
+			ag->dev->name,
+			ag71xx_speed_str(ag),
+			(DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
+
+	DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
+
+	DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
+		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
+
+	DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x\n",
+		ag->dev->name,
+		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
+		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL));
+}
+
+void ag71xx_link_adjust(struct ag71xx *ag)
+{
+	__ag71xx_link_adjust(ag, true);
+}
+
+static int ag71xx_hw_enable(struct ag71xx *ag)
+{
+	int ret;
+
+	ret = ag71xx_rings_init(ag);
+	if (ret)
+		return ret;
+
+	napi_enable(&ag->napi);
+	ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
+	ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
+	netif_start_queue(ag->dev);
+
+	return 0;
+}
+
+static void ag71xx_hw_disable(struct ag71xx *ag)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ag->lock, flags);
+
+	netif_stop_queue(ag->dev);
+
+	ag71xx_hw_stop(ag);
+	ag71xx_dma_reset(ag);
+
+	napi_disable(&ag->napi);
+	del_timer_sync(&ag->oom_timer);
+
+	spin_unlock_irqrestore(&ag->lock, flags);
+
+	ag71xx_rings_cleanup(ag);
+}
+
+static int ag71xx_open(struct net_device *dev)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	unsigned int max_frame_len;
+	int ret;
+
+	netif_carrier_off(dev);
+	max_frame_len = ag71xx_max_frame_len(dev->mtu);
+	ag->rx_buf_size = SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN);
+
+	/* setup max frame length */
+	ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
+	ag71xx_hw_set_macaddr(ag, dev->dev_addr);
+
+	ret = ag71xx_hw_enable(ag);
+	if (ret)
+		goto err;
+
+	ag71xx_phy_start(ag);
+
+	return 0;
+
+err:
+	ag71xx_rings_cleanup(ag);
+	return ret;
+}
+
+static int ag71xx_stop(struct net_device *dev)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+
+	netif_carrier_off(dev);
+	ag71xx_phy_stop(ag);
+	ag71xx_hw_disable(ag);
+
+	return 0;
+}
+
+static int ag71xx_fill_dma_desc(struct ag71xx_ring *ring, u32 addr, int len)
+{
+	int i;
+	struct ag71xx_desc *desc;
+	int ring_mask = BIT(ring->order) - 1;
+	int ndesc = 0;
+	int split = ring->desc_split;
+
+	if (!split)
+		split = len;
+
+	while (len > 0) {
+		unsigned int cur_len = len;
+
+		i = (ring->curr + ndesc) & ring_mask;
+		desc = ag71xx_ring_desc(ring, i);
+
+		if (!ag71xx_desc_empty(desc))
+			return -1;
+
+		if (cur_len > split) {
+			cur_len = split;
+
+			/*
+			 * TX will hang if DMA transfers <= 4 bytes,
+			 * make sure next segment is more than 4 bytes long.
+			 */
+			if (len <= split + 4)
+				cur_len -= 4;
+		}
+
+		desc->data = addr;
+		addr += cur_len;
+		len -= cur_len;
+
+		if (len > 0)
+			cur_len |= DESC_MORE;
+
+		/* prevent early tx attempt of this descriptor */
+		if (!ndesc)
+			cur_len |= DESC_EMPTY;
+
+		desc->ctrl = cur_len;
+		ndesc++;
+	}
+
+	return ndesc;
+}
+
+static netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
+					  struct net_device *dev)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	struct ag71xx_ring *ring = &ag->tx_ring;
+	int ring_mask = BIT(ring->order) - 1;
+	int ring_size = BIT(ring->order);
+	struct ag71xx_desc *desc;
+	dma_addr_t dma_addr;
+	int i, n, ring_min;
+
+	if (ag71xx_has_ar8216(ag))
+		ag71xx_add_ar8216_header(ag, skb);
+
+	if (skb->len <= 4) {
+		DBG("%s: packet len is too small\n", ag->dev->name);
+		goto err_drop;
+	}
+
+	dma_addr = dma_map_single(&dev->dev, skb->data, skb->len,
+				  DMA_TO_DEVICE);
+
+	i = ring->curr & ring_mask;
+	desc = ag71xx_ring_desc(ring, i);
+
+	/* setup descriptor fields */
+	n = ag71xx_fill_dma_desc(ring, (u32) dma_addr, skb->len & ag->desc_pktlen_mask);
+	if (n < 0)
+		goto err_drop_unmap;
+
+	i = (ring->curr + n - 1) & ring_mask;
+	ring->buf[i].len = skb->len;
+	ring->buf[i].skb = skb;
+	ring->buf[i].timestamp = jiffies;
+
+	netdev_sent_queue(dev, skb->len);
+
+	skb_tx_timestamp(skb);
+
+	desc->ctrl &= ~DESC_EMPTY;
+	ring->curr += n;
+
+	/* flush descriptor */
+	wmb();
+
+	ring_min = 2;
+	if (ring->desc_split)
+	    ring_min *= AG71XX_TX_RING_DS_PER_PKT;
+
+	if (ring->curr - ring->dirty >= ring_size - ring_min) {
+		DBG("%s: tx queue full\n", dev->name);
+		netif_stop_queue(dev);
+	}
+
+	DBG("%s: packet injected into TX queue\n", ag->dev->name);
+
+	/* enable TX engine */
+	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
+
+	return NETDEV_TX_OK;
+
+err_drop_unmap:
+	dma_unmap_single(&dev->dev, dma_addr, skb->len, DMA_TO_DEVICE);
+
+err_drop:
+	dev->stats.tx_dropped++;
+
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int ag71xx_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	int ret;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		if (ag->phy_dev == NULL)
+			break;
+
+		spin_lock_irq(&ag->lock);
+		ret = phy_ethtool_ioctl(ag->phy_dev, (void *) ifr->ifr_data);
+		spin_unlock_irq(&ag->lock);
+		return ret;
+
+	case SIOCSIFHWADDR:
+		if (copy_from_user
+			(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr)))
+			return -EFAULT;
+		return 0;
+
+	case SIOCGIFHWADDR:
+		if (copy_to_user
+			(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr)))
+			return -EFAULT;
+		return 0;
+
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		if (ag->phy_dev == NULL)
+			break;
+
+		return phy_mii_ioctl(ag->phy_dev, ifr, cmd);
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static void ag71xx_oom_timer_handler(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	struct ag71xx *ag = netdev_priv(dev);
+
+	napi_schedule(&ag->napi);
+}
+
+static void ag71xx_tx_timeout(struct net_device *dev)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+
+	if (netif_msg_tx_err(ag))
+		pr_info("%s: tx timeout\n", ag->dev->name);
+
+	schedule_delayed_work(&ag->restart_work, 1);
+}
+
+static void ag71xx_restart_work_func(struct work_struct *work)
+{
+	struct ag71xx *ag = container_of(work, struct ag71xx, restart_work.work);
+
+	rtnl_lock();
+	ag71xx_hw_disable(ag);
+	ag71xx_hw_enable(ag);
+	if (ag->link)
+		__ag71xx_link_adjust(ag, false);
+	rtnl_unlock();
+}
+
+static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)
+{
+	u32 rx_sm, tx_sm, rx_fd;
+
+	if (likely(time_before(jiffies, timestamp + HZ/10)))
+		return false;
+
+	if (!netif_carrier_ok(ag->dev))
+		return false;
+
+	rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM);
+	if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6)
+		return true;
+
+	tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM);
+	rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH);
+	if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) &&
+	    ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0)
+		return true;
+
+	return false;
+}
+
+static int ag71xx_tx_packets(struct ag71xx *ag, bool flush)
+{
+	struct ag71xx_ring *ring = &ag->tx_ring;
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	bool dma_stuck = false;
+	int ring_mask = BIT(ring->order) - 1;
+	int ring_size = BIT(ring->order);
+	int sent = 0;
+	int bytes_compl = 0;
+	int n = 0;
+
+	DBG("%s: processing TX ring\n", ag->dev->name);
+
+	while (ring->dirty + n != ring->curr) {
+		unsigned int i = (ring->dirty + n) & ring_mask;
+		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+		struct sk_buff *skb = ring->buf[i].skb;
+
+		if (!flush && !ag71xx_desc_empty(desc)) {
+			if (pdata->is_ar724x &&
+			    ag71xx_check_dma_stuck(ag, ring->buf[i].timestamp)) {
+				schedule_delayed_work(&ag->restart_work, HZ / 2);
+				dma_stuck = true;
+			}
+			break;
+		}
+
+		if (flush)
+			desc->ctrl |= DESC_EMPTY;
+
+		n++;
+		if (!skb)
+			continue;
+
+		dev_kfree_skb_any(skb);
+		ring->buf[i].skb = NULL;
+
+		bytes_compl += ring->buf[i].len;
+
+		sent++;
+		ring->dirty += n;
+
+		while (n > 0) {
+			ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
+			n--;
+		}
+	}
+
+	DBG("%s: %d packets sent out\n", ag->dev->name, sent);
+
+	ag->dev->stats.tx_bytes += bytes_compl;
+	ag->dev->stats.tx_packets += sent;
+
+	if (!sent)
+		return 0;
+
+	netdev_completed_queue(ag->dev, sent, bytes_compl);
+	if ((ring->curr - ring->dirty) < (ring_size * 3) / 4)
+		netif_wake_queue(ag->dev);
+
+	if (!dma_stuck)
+		cancel_delayed_work(&ag->restart_work);
+
+	return sent;
+}
+
+static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
+{
+	struct net_device *dev = ag->dev;
+	struct ag71xx_ring *ring = &ag->rx_ring;
+	int offset = ag71xx_buffer_offset(ag);
+	unsigned int pktlen_mask = ag->desc_pktlen_mask;
+	int ring_mask = BIT(ring->order) - 1;
+	int ring_size = BIT(ring->order);
+	struct sk_buff_head queue;
+	struct sk_buff *skb;
+	int done = 0;
+
+	DBG("%s: rx packets, limit=%d, curr=%u, dirty=%u\n",
+			dev->name, limit, ring->curr, ring->dirty);
+
+	skb_queue_head_init(&queue);
+
+	while (done < limit) {
+		unsigned int i = ring->curr & ring_mask;
+		struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
+		int pktlen;
+		int err = 0;
+
+		if (ag71xx_desc_empty(desc))
+			break;
+
+		if ((ring->dirty + ring_size) == ring->curr) {
+			ag71xx_assert(0);
+			break;
+		}
+
+		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
+
+		pktlen = desc->ctrl & pktlen_mask;
+		pktlen -= ETH_FCS_LEN;
+
+		dma_unmap_single(&dev->dev, ring->buf[i].dma_addr,
+				 ag->rx_buf_size, DMA_FROM_DEVICE);
+
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += pktlen;
+
+		skb = build_skb(ring->buf[i].rx_buf, ag71xx_buffer_size(ag));
+		if (!skb) {
+			skb_free_frag(ring->buf[i].rx_buf);
+			goto next;
+		}
+
+		skb_reserve(skb, offset);
+		skb_put(skb, pktlen);
+
+		if (ag71xx_has_ar8216(ag))
+			err = ag71xx_remove_ar8216_header(ag, skb, pktlen);
+
+		if (err) {
+			dev->stats.rx_dropped++;
+			kfree_skb(skb);
+		} else {
+			skb->dev = dev;
+			skb->ip_summed = CHECKSUM_NONE;
+			__skb_queue_tail(&queue, skb);
+		}
+
+next:
+		ring->buf[i].rx_buf = NULL;
+		done++;
+
+		ring->curr++;
+	}
+
+	ag71xx_ring_rx_refill(ag);
+
+	while ((skb = __skb_dequeue(&queue)) != NULL) {
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_receive_skb(skb);
+	}
+
+	DBG("%s: rx finish, curr=%u, dirty=%u, done=%d\n",
+		dev->name, ring->curr, ring->dirty, done);
+
+	return done;
+}
+
+static int ag71xx_poll(struct napi_struct *napi, int limit)
+{
+	struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	struct net_device *dev = ag->dev;
+	struct ag71xx_ring *rx_ring = &ag->rx_ring;
+	int rx_ring_size = BIT(rx_ring->order);
+	unsigned long flags;
+	u32 status;
+	int tx_done;
+	int rx_done;
+
+	pdata->ddr_flush();
+	tx_done = ag71xx_tx_packets(ag, false);
+
+	DBG("%s: processing RX ring\n", dev->name);
+	rx_done = ag71xx_rx_packets(ag, limit);
+
+	ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
+
+	if (rx_ring->buf[rx_ring->dirty % rx_ring_size].rx_buf == NULL)
+		goto oom;
+
+	status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
+	if (unlikely(status & RX_STATUS_OF)) {
+		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
+		dev->stats.rx_fifo_errors++;
+
+		/* restart RX */
+		ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+	}
+
+	if (rx_done < limit) {
+		if (status & RX_STATUS_PR)
+			goto more;
+
+		status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
+		if (status & TX_STATUS_PS)
+			goto more;
+
+		DBG("%s: disable polling mode, rx=%d, tx=%d,limit=%d\n",
+			dev->name, rx_done, tx_done, limit);
+
+		napi_complete(napi);
+
+		/* enable interrupts */
+		spin_lock_irqsave(&ag->lock, flags);
+		ag71xx_int_enable(ag, AG71XX_INT_POLL);
+		spin_unlock_irqrestore(&ag->lock, flags);
+		return rx_done;
+	}
+
+more:
+	DBG("%s: stay in polling mode, rx=%d, tx=%d, limit=%d\n",
+			dev->name, rx_done, tx_done, limit);
+	return limit;
+
+oom:
+	if (netif_msg_rx_err(ag))
+		pr_info("%s: out of memory\n", dev->name);
+
+	mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
+	napi_complete(napi);
+	return 0;
+}
+
+static irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct ag71xx *ag = netdev_priv(dev);
+	u32 status;
+
+	status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
+	ag71xx_dump_intr(ag, "raw", status);
+
+	if (unlikely(!status))
+		return IRQ_NONE;
+
+	if (unlikely(status & AG71XX_INT_ERR)) {
+		if (status & AG71XX_INT_TX_BE) {
+			ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
+			dev_err(&dev->dev, "TX BUS error\n");
+		}
+		if (status & AG71XX_INT_RX_BE) {
+			ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
+			dev_err(&dev->dev, "RX BUS error\n");
+		}
+	}
+
+	if (likely(status & AG71XX_INT_POLL)) {
+		ag71xx_int_disable(ag, AG71XX_INT_POLL);
+		DBG("%s: enable polling mode\n", dev->name);
+		napi_schedule(&ag->napi);
+	}
+
+	ag71xx_debugfs_update_int_stats(ag, status);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ag71xx_netpoll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	ag71xx_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
+}
+#endif
+
+static int ag71xx_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	unsigned int max_frame_len;
+
+	max_frame_len = ag71xx_max_frame_len(new_mtu);
+	if (new_mtu < 68 || max_frame_len > ag->max_frame_len)
+		return -EINVAL;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static const struct net_device_ops ag71xx_netdev_ops = {
+	.ndo_open		= ag71xx_open,
+	.ndo_stop		= ag71xx_stop,
+	.ndo_start_xmit		= ag71xx_hard_start_xmit,
+	.ndo_do_ioctl		= ag71xx_do_ioctl,
+	.ndo_tx_timeout		= ag71xx_tx_timeout,
+	.ndo_change_mtu		= ag71xx_change_mtu,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= ag71xx_netpoll,
+#endif
+};
+
+static const char *ag71xx_get_phy_if_mode_name(phy_interface_t mode)
+{
+	switch (mode) {
+	case PHY_INTERFACE_MODE_MII:
+		return "MII";
+	case PHY_INTERFACE_MODE_GMII:
+		return "GMII";
+	case PHY_INTERFACE_MODE_RMII:
+		return "RMII";
+	case PHY_INTERFACE_MODE_RGMII:
+		return "RGMII";
+	case PHY_INTERFACE_MODE_SGMII:
+		return "SGMII";
+	default:
+		break;
+	}
+
+	return "unknown";
+}
+
+
+static int ag71xx_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct resource *res;
+	struct ag71xx *ag;
+	struct ag71xx_platform_data *pdata;
+	int tx_size, err;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data specified\n");
+		err = -ENXIO;
+		goto err_out;
+	}
+
+	if (pdata->mii_bus_dev == NULL && pdata->phy_mask) {
+		dev_err(&pdev->dev, "no MII bus device specified\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	dev = alloc_etherdev(sizeof(*ag));
+	if (!dev) {
+		dev_err(&pdev->dev, "alloc_etherdev failed\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	if (!pdata->max_frame_len || !pdata->desc_pktlen_mask)
+		return -EINVAL;
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	ag = netdev_priv(dev);
+	ag->pdev = pdev;
+	ag->dev = dev;
+	ag->msg_enable = netif_msg_init(ag71xx_msg_level,
+					AG71XX_DEFAULT_MSG_ENABLE);
+	spin_lock_init(&ag->lock);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base");
+	if (!res) {
+		dev_err(&pdev->dev, "no mac_base resource found\n");
+		err = -ENXIO;
+		goto err_out;
+	}
+
+	ag->mac_base = ioremap_nocache(res->start, res->end - res->start + 1);
+	if (!ag->mac_base) {
+		dev_err(&pdev->dev, "unable to ioremap mac_base\n");
+		err = -ENOMEM;
+		goto err_free_dev;
+	}
+
+	dev->irq = platform_get_irq(pdev, 0);
+	err = request_irq(dev->irq, ag71xx_interrupt,
+			  0x0,
+			  dev->name, dev);
+	if (err) {
+		dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
+		goto err_unmap_base;
+	}
+
+	dev->base_addr = (unsigned long)ag->mac_base;
+	dev->netdev_ops = &ag71xx_netdev_ops;
+	dev->ethtool_ops = &ag71xx_ethtool_ops;
+
+	INIT_DELAYED_WORK(&ag->restart_work, ag71xx_restart_work_func);
+
+	init_timer(&ag->oom_timer);
+	ag->oom_timer.data = (unsigned long) dev;
+	ag->oom_timer.function = ag71xx_oom_timer_handler;
+
+	tx_size = AG71XX_TX_RING_SIZE_DEFAULT;
+	ag->rx_ring.order = ag71xx_ring_size_order(AG71XX_RX_RING_SIZE_DEFAULT);
+
+	ag->max_frame_len = pdata->max_frame_len;
+	ag->desc_pktlen_mask = pdata->desc_pktlen_mask;
+
+	if (!pdata->is_ar724x && !pdata->is_ar91xx) {
+		ag->tx_ring.desc_split = AG71XX_TX_RING_SPLIT;
+		tx_size *= AG71XX_TX_RING_DS_PER_PKT;
+	}
+	ag->tx_ring.order = ag71xx_ring_size_order(tx_size);
+
+	ag->stop_desc = dma_alloc_coherent(NULL,
+		sizeof(struct ag71xx_desc), &ag->stop_desc_dma, GFP_KERNEL);
+
+	if (!ag->stop_desc)
+		goto err_free_irq;
+
+	ag->stop_desc->data = 0;
+	ag->stop_desc->ctrl = 0;
+	ag->stop_desc->next = (u32) ag->stop_desc_dma;
+
+	memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
+
+	netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
+
+	ag71xx_dump_regs(ag);
+
+	ag71xx_hw_init(ag);
+
+	ag71xx_dump_regs(ag);
+
+	err = ag71xx_phy_connect(ag);
+	if (err)
+		goto err_free_desc;
+
+	err = ag71xx_debugfs_init(ag);
+	if (err)
+		goto err_phy_disconnect;
+
+	platform_set_drvdata(pdev, dev);
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(&pdev->dev, "unable to register net device\n");
+		goto err_debugfs_exit;
+	}
+
+	pr_info("%s: Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n",
+		dev->name, dev->base_addr, dev->irq,
+		ag71xx_get_phy_if_mode_name(pdata->phy_if_mode));
+
+	return 0;
+
+err_debugfs_exit:
+	ag71xx_debugfs_exit(ag);
+err_phy_disconnect:
+	ag71xx_phy_disconnect(ag);
+err_free_desc:
+	dma_free_coherent(NULL, sizeof(struct ag71xx_desc), ag->stop_desc,
+			  ag->stop_desc_dma);
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_unmap_base:
+	iounmap(ag->mac_base);
+err_free_dev:
+	kfree(dev);
+err_out:
+	platform_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static int ag71xx_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	if (dev) {
+		struct ag71xx *ag = netdev_priv(dev);
+
+		ag71xx_debugfs_exit(ag);
+		ag71xx_phy_disconnect(ag);
+		unregister_netdev(dev);
+		free_irq(dev->irq, dev);
+		iounmap(ag->mac_base);
+		kfree(dev);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return 0;
+}
+
+static struct platform_driver ag71xx_driver = {
+	.probe		= ag71xx_probe,
+	.remove		= ag71xx_remove,
+	.driver = {
+		.name	= AG71XX_DRV_NAME,
+	}
+};
+
+static int __init ag71xx_module_init(void)
+{
+	int ret;
+
+	ret = ag71xx_debugfs_root_init();
+	if (ret)
+		goto err_out;
+
+	ret = ag71xx_mdio_driver_init();
+	if (ret)
+		goto err_debugfs_exit;
+
+	ret = platform_driver_register(&ag71xx_driver);
+	if (ret)
+		goto err_mdio_exit;
+
+	return 0;
+
+err_mdio_exit:
+	ag71xx_mdio_driver_exit();
+err_debugfs_exit:
+	ag71xx_debugfs_root_exit();
+err_out:
+	return ret;
+}
+
+static void __exit ag71xx_module_exit(void)
+{
+	platform_driver_unregister(&ag71xx_driver);
+	ag71xx_mdio_driver_exit();
+	ag71xx_debugfs_root_exit();
+}
+
+module_init(ag71xx_module_init);
+module_exit(ag71xx_module_exit);
+
+MODULE_VERSION(AG71XX_DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" AG71XX_DRV_NAME);
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
new file mode 100644
index 0000000000..71ae8258b2
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
@@ -0,0 +1,318 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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 "ag71xx.h"
+
+#define AG71XX_MDIO_RETRY	1000
+#define AG71XX_MDIO_DELAY	5
+
+static inline void ag71xx_mdio_wr(struct ag71xx_mdio *am, unsigned reg,
+				  u32 value)
+{
+	void __iomem *r;
+
+	r = am->mdio_base + reg;
+	__raw_writel(value, r);
+
+	/* flush write */
+	(void) __raw_readl(r);
+}
+
+static inline u32 ag71xx_mdio_rr(struct ag71xx_mdio *am, unsigned reg)
+{
+	return __raw_readl(am->mdio_base + reg);
+}
+
+static void ag71xx_mdio_dump_regs(struct ag71xx_mdio *am)
+{
+	DBG("%s: mii_cfg=%08x, mii_cmd=%08x, mii_addr=%08x\n",
+		am->mii_bus->name,
+		ag71xx_mdio_rr(am, AG71XX_REG_MII_CFG),
+		ag71xx_mdio_rr(am, AG71XX_REG_MII_CMD),
+		ag71xx_mdio_rr(am, AG71XX_REG_MII_ADDR));
+	DBG("%s: mii_ctrl=%08x, mii_status=%08x, mii_ind=%08x\n",
+		am->mii_bus->name,
+		ag71xx_mdio_rr(am, AG71XX_REG_MII_CTRL),
+		ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS),
+		ag71xx_mdio_rr(am, AG71XX_REG_MII_IND));
+}
+
+static int ag71xx_mdio_wait_busy(struct ag71xx_mdio *am)
+{
+	int i;
+
+	for (i = 0; i < AG71XX_MDIO_RETRY; i++) {
+		u32 busy;
+
+		udelay(AG71XX_MDIO_DELAY);
+
+		busy = ag71xx_mdio_rr(am, AG71XX_REG_MII_IND);
+		if (!busy)
+			return 0;
+
+		udelay(AG71XX_MDIO_DELAY);
+	}
+
+	pr_err("%s: MDIO operation timed out\n", am->mii_bus->name);
+
+	return -ETIMEDOUT;
+}
+
+int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg)
+{
+	int err;
+	int ret;
+
+	err = ag71xx_mdio_wait_busy(am);
+	if (err)
+		return 0xffff;
+
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
+			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_READ);
+
+	err = ag71xx_mdio_wait_busy(am);
+	if (err)
+		return 0xffff;
+
+	ret = ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS) & 0xffff;
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+
+	DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
+
+	return ret;
+}
+
+void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val)
+{
+	DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
+
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
+			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_CTRL, val);
+
+	ag71xx_mdio_wait_busy(am);
+}
+
+static const u32 ar71xx_mdio_div_table[] = {
+	4, 4, 6, 8, 10, 14, 20, 28,
+};
+
+static const u32 ar7240_mdio_div_table[] = {
+	2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
+};
+
+static const u32 ar933x_mdio_div_table[] = {
+	4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
+};
+
+static int ag71xx_mdio_get_divider(struct ag71xx_mdio *am, u32 *div)
+{
+	unsigned long ref_clock, mdio_clock;
+	const u32 *table;
+	int ndivs;
+	int i;
+
+	ref_clock = am->pdata->ref_clock;
+	mdio_clock = am->pdata->mdio_clock;
+
+	if (!ref_clock || !mdio_clock)
+		return -EINVAL;
+
+	if (am->pdata->is_ar9330 || am->pdata->is_ar934x) {
+		table = ar933x_mdio_div_table;
+		ndivs = ARRAY_SIZE(ar933x_mdio_div_table);
+	} else if (am->pdata->is_ar7240) {
+		table = ar7240_mdio_div_table;
+		ndivs = ARRAY_SIZE(ar7240_mdio_div_table);
+	} else {
+		table = ar71xx_mdio_div_table;
+		ndivs = ARRAY_SIZE(ar71xx_mdio_div_table);
+	}
+
+	for (i = 0; i < ndivs; i++) {
+		unsigned long t;
+
+		t = ref_clock / table[i];
+		if (t <= mdio_clock) {
+			*div = i;
+			return 0;
+		}
+	}
+
+	dev_err(&am->mii_bus->dev, "no divider found for %lu/%lu\n",
+		ref_clock, mdio_clock);
+	return -ENOENT;
+}
+
+static int ag71xx_mdio_reset(struct mii_bus *bus)
+{
+	struct ag71xx_mdio *am = bus->priv;
+	u32 t;
+	int err;
+
+	err = ag71xx_mdio_get_divider(am, &t);
+	if (err) {
+		/* fallback */
+		if (am->pdata->is_ar7240)
+			t = MII_CFG_CLK_DIV_6;
+		else if (am->pdata->builtin_switch && !am->pdata->is_ar934x)
+			t = MII_CFG_CLK_DIV_10;
+		else if (!am->pdata->builtin_switch && am->pdata->is_ar934x)
+			t = MII_CFG_CLK_DIV_58;
+		else
+			t = MII_CFG_CLK_DIV_28;
+	}
+
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
+	udelay(100);
+
+	ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t);
+	udelay(100);
+
+	if (am->pdata->reset)
+		am->pdata->reset(bus);
+
+	return 0;
+}
+
+static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct ag71xx_mdio *am = bus->priv;
+
+	if (am->pdata->builtin_switch)
+		return ar7240sw_phy_read(bus, addr, reg);
+	else
+		return ag71xx_mdio_mii_read(am, addr, reg);
+}
+
+static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct ag71xx_mdio *am = bus->priv;
+
+	if (am->pdata->builtin_switch)
+		ar7240sw_phy_write(bus, addr, reg, val);
+	else
+		ag71xx_mdio_mii_write(am, addr, reg, val);
+	return 0;
+}
+
+static int ag71xx_mdio_probe(struct platform_device *pdev)
+{
+	struct ag71xx_mdio_platform_data *pdata;
+	struct ag71xx_mdio *am;
+	struct resource *res;
+	int i;
+	int err;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data specified\n");
+		return -EINVAL;
+	}
+
+	am = kzalloc(sizeof(*am), GFP_KERNEL);
+	if (!am) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	am->pdata = pdata;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no iomem resource found\n");
+		err = -ENXIO;
+		goto err_out;
+	}
+
+	am->mdio_base = ioremap_nocache(res->start, res->end - res->start + 1);
+	if (!am->mdio_base) {
+		dev_err(&pdev->dev, "unable to ioremap registers\n");
+		err = -ENOMEM;
+		goto err_free_mdio;
+	}
+
+	am->mii_bus = mdiobus_alloc();
+	if (am->mii_bus == NULL) {
+		err = -ENOMEM;
+		goto err_iounmap;
+	}
+
+	am->mii_bus->name = "ag71xx_mdio";
+	am->mii_bus->read = ag71xx_mdio_read;
+	am->mii_bus->write = ag71xx_mdio_write;
+	am->mii_bus->reset = ag71xx_mdio_reset;
+	am->mii_bus->irq = am->mii_irq;
+	am->mii_bus->priv = am;
+	am->mii_bus->parent = &pdev->dev;
+	snprintf(am->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&pdev->dev));
+	am->mii_bus->phy_mask = pdata->phy_mask;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		am->mii_irq[i] = PHY_POLL;
+
+	ag71xx_mdio_wr(am, AG71XX_REG_MAC_CFG1, 0);
+
+	err = mdiobus_register(am->mii_bus);
+	if (err)
+		goto err_free_bus;
+
+	ag71xx_mdio_dump_regs(am);
+
+	platform_set_drvdata(pdev, am);
+	return 0;
+
+err_free_bus:
+	mdiobus_free(am->mii_bus);
+err_iounmap:
+	iounmap(am->mdio_base);
+err_free_mdio:
+	kfree(am);
+err_out:
+	return err;
+}
+
+static int ag71xx_mdio_remove(struct platform_device *pdev)
+{
+	struct ag71xx_mdio *am = platform_get_drvdata(pdev);
+
+	if (am) {
+		mdiobus_unregister(am->mii_bus);
+		mdiobus_free(am->mii_bus);
+		iounmap(am->mdio_base);
+		kfree(am);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return 0;
+}
+
+static struct platform_driver ag71xx_mdio_driver = {
+	.probe		= ag71xx_mdio_probe,
+	.remove		= ag71xx_mdio_remove,
+	.driver = {
+		.name	= "ag71xx-mdio",
+	}
+};
+
+int __init ag71xx_mdio_driver_init(void)
+{
+	return platform_driver_register(&ag71xx_mdio_driver);
+}
+
+void ag71xx_mdio_driver_exit(void)
+{
+	platform_driver_unregister(&ag71xx_mdio_driver);
+}
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c
new file mode 100644
index 0000000000..9de77e924b
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c
@@ -0,0 +1,235 @@
+/*
+ *  Atheros AR71xx built-in ethernet mac driver
+ *
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Based on Atheros' AG7100 driver
+ *
+ *  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 "ag71xx.h"
+
+static void ag71xx_phy_link_adjust(struct net_device *dev)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	struct phy_device *phydev = ag->phy_dev;
+	unsigned long flags;
+	int status_change = 0;
+
+	spin_lock_irqsave(&ag->lock, flags);
+
+	if (phydev->link) {
+		if (ag->duplex != phydev->duplex
+		    || ag->speed != phydev->speed) {
+			status_change = 1;
+		}
+	}
+
+	if (phydev->link != ag->link)
+		status_change = 1;
+
+	ag->link = phydev->link;
+	ag->duplex = phydev->duplex;
+	ag->speed = phydev->speed;
+
+	if (status_change)
+		ag71xx_link_adjust(ag);
+
+	spin_unlock_irqrestore(&ag->lock, flags);
+}
+
+void ag71xx_phy_start(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+
+	if (ag->phy_dev) {
+		phy_start(ag->phy_dev);
+	} else if (pdata->mii_bus_dev && pdata->switch_data) {
+		ag71xx_ar7240_start(ag);
+	} else {
+		ag->link = 1;
+		ag71xx_link_adjust(ag);
+	}
+}
+
+void ag71xx_phy_stop(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	unsigned long flags;
+
+	if (ag->phy_dev)
+		phy_stop(ag->phy_dev);
+	else if (pdata->mii_bus_dev && pdata->switch_data)
+		ag71xx_ar7240_stop(ag);
+
+	spin_lock_irqsave(&ag->lock, flags);
+	if (ag->link) {
+		ag->link = 0;
+		ag71xx_link_adjust(ag);
+	}
+	spin_unlock_irqrestore(&ag->lock, flags);
+}
+
+static int ag71xx_phy_connect_fixed(struct ag71xx *ag)
+{
+	struct device *dev = &ag->pdev->dev;
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	int ret = 0;
+
+	/* use fixed settings */
+	switch (pdata->speed) {
+	case SPEED_10:
+	case SPEED_100:
+	case SPEED_1000:
+		break;
+	default:
+		dev_err(dev, "invalid speed specified\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	dev_dbg(dev, "using fixed link parameters\n");
+
+	ag->duplex = pdata->duplex;
+	ag->speed = pdata->speed;
+
+	return ret;
+}
+
+static int ag71xx_phy_connect_multi(struct ag71xx *ag)
+{
+	struct device *dev = &ag->pdev->dev;
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+	struct phy_device *phydev = NULL;
+	int phy_addr;
+	int ret = 0;
+
+	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+		if (!(pdata->phy_mask & (1 << phy_addr)))
+			continue;
+
+		if (ag->mii_bus->phy_map[phy_addr] == NULL)
+			continue;
+
+		DBG("%s: PHY found at %s, uid=%08x\n",
+			dev_name(dev),
+			dev_name(&ag->mii_bus->phy_map[phy_addr]->dev),
+			ag->mii_bus->phy_map[phy_addr]->phy_id);
+
+		if (phydev == NULL)
+			phydev = ag->mii_bus->phy_map[phy_addr];
+	}
+
+	if (!phydev) {
+		dev_err(dev, "no PHY found with phy_mask=%08x\n",
+			   pdata->phy_mask);
+		return -ENODEV;
+	}
+
+	ag->phy_dev = phy_connect(ag->dev, dev_name(&phydev->dev),
+				  &ag71xx_phy_link_adjust,
+				  pdata->phy_if_mode);
+
+	if (IS_ERR(ag->phy_dev)) {
+		dev_err(dev, "could not connect to PHY at %s\n",
+			   dev_name(&phydev->dev));
+		return PTR_ERR(ag->phy_dev);
+	}
+
+	/* mask with MAC supported features */
+	if (pdata->has_gbit)
+		phydev->supported &= PHY_GBIT_FEATURES;
+	else
+		phydev->supported &= PHY_BASIC_FEATURES;
+
+	phydev->advertising = phydev->supported;
+
+	dev_info(dev, "connected to PHY at %s [uid=%08x, driver=%s]\n",
+		    dev_name(&phydev->dev), phydev->phy_id, phydev->drv->name);
+
+	ag->link = 0;
+	ag->speed = 0;
+	ag->duplex = -1;
+
+	return ret;
+}
+
+static int dev_is_class(struct device *dev, void *class)
+{
+	if (dev->class != NULL && !strcmp(dev->class->name, class))
+		return 1;
+
+	return 0;
+}
+
+static struct device *dev_find_class(struct device *parent, char *class)
+{
+	if (dev_is_class(parent, class)) {
+		get_device(parent);
+		return parent;
+	}
+
+	return device_find_child(parent, class, dev_is_class);
+}
+
+static struct mii_bus *dev_to_mii_bus(struct device *dev)
+{
+	struct device *d;
+
+	d = dev_find_class(dev, "mdio_bus");
+	if (d != NULL) {
+		struct mii_bus *bus;
+
+		bus = to_mii_bus(d);
+		put_device(d);
+
+		return bus;
+	}
+
+	return NULL;
+}
+
+int ag71xx_phy_connect(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+
+	if (pdata->mii_bus_dev == NULL ||
+	    pdata->mii_bus_dev->bus == NULL )
+		return ag71xx_phy_connect_fixed(ag);
+
+	ag->mii_bus = dev_to_mii_bus(pdata->mii_bus_dev);
+	if (ag->mii_bus == NULL) {
+		dev_err(&ag->pdev->dev, "unable to find MII bus on device '%s'\n",
+			   dev_name(pdata->mii_bus_dev));
+		return -ENODEV;
+	}
+
+	/* Reset the mdio bus explicitly */
+	if (ag->mii_bus->reset) {
+		mutex_lock(&ag->mii_bus->mdio_lock);
+		ag->mii_bus->reset(ag->mii_bus);
+		mutex_unlock(&ag->mii_bus->mdio_lock);
+	}
+
+	if (pdata->switch_data)
+		return ag71xx_ar7240_init(ag);
+
+	if (pdata->phy_mask)
+		return ag71xx_phy_connect_multi(ag);
+
+	return ag71xx_phy_connect_fixed(ag);
+}
+
+void ag71xx_phy_disconnect(struct ag71xx *ag)
+{
+	struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+
+	if (pdata->switch_data)
+		ag71xx_ar7240_cleanup(ag);
+	else if (ag->phy_dev)
+		phy_disconnect(ag->phy_dev);
+}
diff --git a/target/linux/ar71xx/files/drivers/spi/spi-ap83.c b/target/linux/ar71xx/files/drivers/spi/spi-ap83.c
new file mode 100644
index 0000000000..33843a6daa
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/spi/spi-ap83.c
@@ -0,0 +1,283 @@
+/*
+ * Atheros AP83 board specific SPI Controller driver
+ *
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#define DRV_DESC	"Atheros AP83 board SPI Controller driver"
+#define DRV_VERSION	"0.1.0"
+#define DRV_NAME	"ap83-spi"
+
+#define AP83_SPI_CLK_HIGH	(1 << 23)
+#define AP83_SPI_CLK_LOW	0
+#define AP83_SPI_MOSI_HIGH	(1 << 22)
+#define AP83_SPI_MOSI_LOW	0
+
+#define AP83_SPI_GPIO_CS	1
+#define AP83_SPI_GPIO_MISO	3
+
+struct ap83_spi {
+	struct	spi_bitbang	bitbang;
+	void __iomem		*base;
+	u32			addr;
+
+	struct platform_device	*pdev;
+};
+
+static inline u32 ap83_spi_rr(struct ap83_spi *sp, u32 reg)
+{
+	return __raw_readl(sp->base + reg);
+}
+
+static inline struct ap83_spi *spidev_to_sp(struct spi_device *spi)
+{
+	return spi_master_get_devdata(spi->master);
+}
+
+static inline void setsck(struct spi_device *spi, int val)
+{
+	struct ap83_spi *sp = spidev_to_sp(spi);
+
+	if (val)
+		sp->addr |= AP83_SPI_CLK_HIGH;
+	else
+		sp->addr &= ~AP83_SPI_CLK_HIGH;
+
+	dev_dbg(&spi->dev, "addr=%08x,  SCK set to %s\n",
+		sp->addr, (val) ? "HIGH" : "LOW");
+
+	ap83_spi_rr(sp, sp->addr);
+}
+
+static inline void setmosi(struct spi_device *spi, int val)
+{
+	struct ap83_spi *sp = spidev_to_sp(spi);
+
+	if (val)
+		sp->addr |= AP83_SPI_MOSI_HIGH;
+	else
+		sp->addr &= ~AP83_SPI_MOSI_HIGH;
+
+	dev_dbg(&spi->dev, "addr=%08x, MOSI set to %s\n",
+		sp->addr, (val) ? "HIGH" : "LOW");
+
+	ap83_spi_rr(sp, sp->addr);
+}
+
+static inline u32 getmiso(struct spi_device *spi)
+{
+	u32 ret;
+
+	ret = gpio_get_value(AP83_SPI_GPIO_MISO) ? 1 : 0;
+	dev_dbg(&spi->dev, "get MISO: %d\n", ret);
+
+	return ret;
+}
+
+static inline void do_spidelay(struct spi_device *spi, unsigned nsecs)
+{
+	ndelay(nsecs);
+}
+
+static void ap83_spi_chipselect(struct spi_device *spi, int on)
+{
+	struct ap83_spi *sp = spidev_to_sp(spi);
+
+	dev_dbg(&spi->dev, "set CS to %d\n", (on) ? 0 : 1);
+
+	if (on) {
+		ath79_flash_acquire();
+
+		sp->addr = 0;
+		ap83_spi_rr(sp, sp->addr);
+
+		gpio_set_value(AP83_SPI_GPIO_CS, 0);
+	} else {
+		gpio_set_value(AP83_SPI_GPIO_CS, 1);
+		ath79_flash_release();
+	}
+}
+
+#define spidelay(nsecs)							\
+	do {								\
+		/* Steal the spi_device pointer from our caller.	\
+		 * The bitbang-API should probably get fixed here... */	\
+		do_spidelay(spi, nsecs);				\
+	} while (0)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+#include "spi-bitbang-txrx.h"
+
+static u32 ap83_spi_txrx_mode0(struct spi_device *spi,
+			       unsigned nsecs, u32 word, u8 bits)
+{
+	dev_dbg(&spi->dev, "TXRX0 word=%08x, bits=%u\n", word, bits);
+	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+}
+
+static u32 ap83_spi_txrx_mode1(struct spi_device *spi,
+			       unsigned nsecs, u32 word, u8 bits)
+{
+	dev_dbg(&spi->dev, "TXRX1 word=%08x, bits=%u\n", word, bits);
+	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+}
+
+static u32 ap83_spi_txrx_mode2(struct spi_device *spi,
+			       unsigned nsecs, u32 word, u8 bits)
+{
+	dev_dbg(&spi->dev, "TXRX2 word=%08x, bits=%u\n", word, bits);
+	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+}
+
+static u32 ap83_spi_txrx_mode3(struct spi_device *spi,
+			       unsigned nsecs, u32 word, u8 bits)
+{
+	dev_dbg(&spi->dev, "TXRX3 word=%08x, bits=%u\n", word, bits);
+	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+}
+
+static int ap83_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct ap83_spi *sp;
+	struct ap83_spi_platform_data *pdata;
+	struct resource	*r;
+	int ret;
+
+	ret = gpio_request(AP83_SPI_GPIO_MISO, "spi-miso");
+	if (ret) {
+		dev_err(&pdev->dev, "gpio request failed for MISO\n");
+		return ret;
+	}
+
+	ret = gpio_request(AP83_SPI_GPIO_CS, "spi-cs");
+	if (ret) {
+		dev_err(&pdev->dev, "gpio request failed for CS\n");
+		goto err_free_miso;
+	}
+
+	ret = gpio_direction_input(AP83_SPI_GPIO_MISO);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to set direction of MISO\n");
+		goto err_free_cs;
+	}
+
+	ret = gpio_direction_output(AP83_SPI_GPIO_CS, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to set direction of CS\n");
+		goto err_free_cs;
+	}
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
+	if (master == NULL) {
+		dev_err(&pdev->dev, "failed to allocate spi master\n");
+		return -ENOMEM;
+	}
+
+	sp = spi_master_get_devdata(master);
+	platform_set_drvdata(pdev, sp);
+
+	pdata = pdev->dev.platform_data;
+
+	sp->bitbang.master = spi_master_get(master);
+	sp->bitbang.chipselect = ap83_spi_chipselect;
+	sp->bitbang.txrx_word[SPI_MODE_0] = ap83_spi_txrx_mode0;
+	sp->bitbang.txrx_word[SPI_MODE_1] = ap83_spi_txrx_mode1;
+	sp->bitbang.txrx_word[SPI_MODE_2] = ap83_spi_txrx_mode2;
+	sp->bitbang.txrx_word[SPI_MODE_3] = ap83_spi_txrx_mode3;
+
+	sp->bitbang.master->bus_num = pdev->id;
+	sp->bitbang.master->num_chipselect = 1;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		ret = -ENOENT;
+		goto err_spi_put;
+	}
+
+	sp->base = ioremap_nocache(r->start, r->end - r->start + 1);
+	if (!sp->base) {
+		ret = -ENXIO;
+		goto err_spi_put;
+	}
+
+	ret = spi_bitbang_start(&sp->bitbang);
+	if (!ret)
+		goto err_unmap;
+
+	dev_info(&pdev->dev, "AP83 SPI adapter at %08x\n", r->start);
+
+	return 0;
+
+err_unmap:
+	iounmap(sp->base);
+err_spi_put:
+	platform_set_drvdata(pdev, NULL);
+	spi_master_put(sp->bitbang.master);
+
+err_free_cs:
+	gpio_free(AP83_SPI_GPIO_CS);
+err_free_miso:
+	gpio_free(AP83_SPI_GPIO_MISO);
+	return ret;
+}
+
+static int ap83_spi_remove(struct platform_device *pdev)
+{
+	struct ap83_spi *sp = platform_get_drvdata(pdev);
+
+	spi_bitbang_stop(&sp->bitbang);
+	iounmap(sp->base);
+	platform_set_drvdata(pdev, NULL);
+	spi_master_put(sp->bitbang.master);
+
+	return 0;
+}
+
+static struct platform_driver ap83_spi_drv = {
+	.probe		= ap83_spi_probe,
+	.remove		= ap83_spi_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ap83_spi_init(void)
+{
+	return platform_driver_register(&ap83_spi_drv);
+}
+module_init(ap83_spi_init);
+
+static void __exit ap83_spi_exit(void)
+{
+	platform_driver_unregister(&ap83_spi_drv);
+}
+module_exit(ap83_spi_exit);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/spi/spi-rb4xx-cpld.c b/target/linux/ar71xx/files/drivers/spi/spi-rb4xx-cpld.c
new file mode 100644
index 0000000000..a8d52825eb
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/spi/spi-rb4xx-cpld.c
@@ -0,0 +1,441 @@
+/*
+ * SPI driver for the CPLD chip on the Mikrotik RB4xx boards
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file was based on the patches for Linux 2.6.27.39 published by
+ * MikroTik for their RouterBoard 4xx series devices.
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <asm/mach-ath79/rb4xx_cpld.h>
+
+#define DRV_NAME	"spi-rb4xx-cpld"
+#define DRV_DESC	"RB4xx CPLD driver"
+#define DRV_VERSION	"0.1.0"
+
+#define CPLD_CMD_WRITE_NAND	0x08 /* send cmd, n x send data, send indle */
+#define CPLD_CMD_WRITE_CFG	0x09 /* send cmd, n x send cfg */
+#define CPLD_CMD_READ_NAND	0x0a /* send cmd, send idle, n x read data */
+#define CPLD_CMD_READ_FAST	0x0b /* send cmd, 4 x idle, n x read data */
+#define CPLD_CMD_LED5_ON	0x0c /* send cmd */
+#define CPLD_CMD_LED5_OFF	0x0d /* send cmd */
+
+struct rb4xx_cpld {
+	struct spi_device	*spi;
+	struct mutex		lock;
+	struct gpio_chip	chip;
+	unsigned int		config;
+};
+
+static struct rb4xx_cpld *rb4xx_cpld;
+
+static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip)
+{
+	return container_of(chip, struct rb4xx_cpld, chip);
+}
+
+static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd)
+{
+	struct spi_transfer t[1];
+	struct spi_message m;
+	unsigned char tx_buf[1];
+	int err;
+
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = tx_buf;
+	t[0].len = sizeof(tx_buf);
+	spi_message_add_tail(&t[0], &m);
+
+	tx_buf[0] = cmd;
+
+	err = spi_sync(cpld->spi, &m);
+	return err;
+}
+
+static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config)
+{
+	struct spi_transfer t[1];
+	struct spi_message m;
+	unsigned char cmd[2];
+	int err;
+
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	cmd[0] = CPLD_CMD_WRITE_CFG;
+	cmd[1] = config;
+
+	err = spi_sync(cpld->spi, &m);
+	return err;
+}
+
+static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask,
+				   unsigned value)
+{
+	unsigned int config;
+	int err;
+
+	config = cpld->config & ~mask;
+	config |= value;
+
+	if ((cpld->config ^ config) & 0xff) {
+		err = rb4xx_cpld_write_cfg(cpld, config);
+		if (err)
+			return err;
+	}
+
+	if ((cpld->config ^ config) & CPLD_CFG_nLED5) {
+		err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON :
+							   CPLD_CMD_LED5_OFF);
+		if (err)
+			return err;
+	}
+
+	cpld->config = config;
+	return 0;
+}
+
+int rb4xx_cpld_change_cfg(unsigned mask, unsigned value)
+{
+	int ret;
+
+	if (rb4xx_cpld == NULL)
+		return -ENODEV;
+
+	mutex_lock(&rb4xx_cpld->lock);
+	ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value);
+	mutex_unlock(&rb4xx_cpld->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg);
+
+int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf,
+			 const unsigned char *verify_buf, unsigned count)
+{
+	const unsigned char cmd[5] = {
+		CPLD_CMD_READ_FAST,
+		(addr >> 16) & 0xff,
+		(addr >> 8) & 0xff,
+		 addr & 0xff,
+		 0
+	};
+	struct spi_transfer t[2] = {
+		{
+			.tx_buf = &cmd,
+			.len = 5,
+		},
+		{
+			.tx_buf = verify_buf,
+			.rx_buf = rx_buf,
+			.len = count,
+			.verify = (verify_buf != NULL),
+		},
+	};
+	struct spi_message m;
+
+	if (rb4xx_cpld == NULL)
+		return -ENODEV;
+
+	spi_message_init(&m);
+	m.fast_read = 1;
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+	return spi_sync(rb4xx_cpld->spi, &m);
+}
+EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from);
+
+#if 0
+int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf,
+		    unsigned count)
+{
+	struct spi_transfer t[2];
+	struct spi_message m;
+	unsigned char cmd[2];
+
+	if (rb4xx_cpld == NULL)
+		return -ENODEV;
+
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(t));
+
+	/* send command */
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	cmd[0] = CPLD_CMD_READ_NAND;
+	cmd[1] = 0;
+
+	/* read data */
+	t[1].rx_buf = buf;
+	t[1].len = count;
+	spi_message_add_tail(&t[1], &m);
+
+	return spi_sync(rb4xx_cpld->spi, &m);
+}
+#else
+int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf,
+		    unsigned count)
+{
+	static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 };
+	struct spi_transfer t[2] = {
+		{
+			.tx_buf = &cmd,
+			.len = 2,
+		}, {
+			.tx_buf = verify_buf,
+			.rx_buf = rx_buf,
+			.len = count,
+			.verify = (verify_buf != NULL),
+		},
+	};
+	struct spi_message m;
+
+	if (rb4xx_cpld == NULL)
+		return -ENODEV;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+	return spi_sync(rb4xx_cpld->spi, &m);
+}
+#endif
+EXPORT_SYMBOL_GPL(rb4xx_cpld_read);
+
+int rb4xx_cpld_write(const unsigned char *buf, unsigned count)
+{
+#if 0
+	struct spi_transfer t[3];
+	struct spi_message m;
+	unsigned char cmd[1];
+
+	if (rb4xx_cpld == NULL)
+		return -ENODEV;
+
+	memset(&t, 0, sizeof(t));
+	spi_message_init(&m);
+
+	/* send command */
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	cmd[0] = CPLD_CMD_WRITE_NAND;
+
+	/* write data */
+	t[1].tx_buf = buf;
+	t[1].len = count;
+	spi_message_add_tail(&t[1], &m);
+
+	/* send idle */
+	t[2].len = 1;
+	spi_message_add_tail(&t[2], &m);
+
+	return spi_sync(rb4xx_cpld->spi, &m);
+#else
+	static const unsigned char cmd = CPLD_CMD_WRITE_NAND;
+	struct spi_transfer t[3] = {
+		{
+			.tx_buf = &cmd,
+			.len = 1,
+		}, {
+			.tx_buf = buf,
+			.len = count,
+			.fast_write = 1,
+		}, {
+			.len = 1,
+			.fast_write = 1,
+		},
+	};
+	struct spi_message m;
+
+	if (rb4xx_cpld == NULL)
+		return -ENODEV;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+	spi_message_add_tail(&t[2], &m);
+	return spi_sync(rb4xx_cpld->spi, &m);
+#endif
+}
+EXPORT_SYMBOL_GPL(rb4xx_cpld_write);
+
+static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
+	int ret;
+
+	mutex_lock(&cpld->lock);
+	ret = (cpld->config >> offset) & 1;
+	mutex_unlock(&cpld->lock);
+
+	return ret;
+}
+
+static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset,
+				int value)
+{
+	struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
+
+	mutex_lock(&cpld->lock);
+	__rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
+	mutex_unlock(&cpld->lock);
+}
+
+static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip,
+					   unsigned offset)
+{
+	return -EOPNOTSUPP;
+}
+
+static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip,
+					    unsigned offset,
+					    int value)
+{
+	struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
+	int ret;
+
+	mutex_lock(&cpld->lock);
+	ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
+	mutex_unlock(&cpld->lock);
+
+	return ret;
+}
+
+static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base)
+{
+	int err;
+
+	/* init config */
+	cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 |
+		       CPLD_CFG_nLED4 | CPLD_CFG_nCE;
+	rb4xx_cpld_write_cfg(cpld, cpld->config);
+
+	/* setup GPIO chip */
+	cpld->chip.label = DRV_NAME;
+
+	cpld->chip.get = rb4xx_cpld_gpio_get;
+	cpld->chip.set = rb4xx_cpld_gpio_set;
+	cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input;
+	cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output;
+
+	cpld->chip.base = base;
+	cpld->chip.ngpio = CPLD_NUM_GPIOS;
+	cpld->chip.can_sleep = 1;
+	cpld->chip.dev = &cpld->spi->dev;
+	cpld->chip.owner = THIS_MODULE;
+
+	err = gpiochip_add(&cpld->chip);
+	if (err)
+		dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n",
+			err);
+
+	return err;
+}
+
+static int rb4xx_cpld_probe(struct spi_device *spi)
+{
+	struct rb4xx_cpld *cpld;
+	struct rb4xx_cpld_platform_data *pdata;
+	int err;
+
+	pdata = spi->dev.platform_data;
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	cpld = kzalloc(sizeof(*cpld), GFP_KERNEL);
+	if (!cpld) {
+		dev_err(&spi->dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&cpld->lock);
+	cpld->spi = spi_dev_get(spi);
+	dev_set_drvdata(&spi->dev, cpld);
+
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+	err = spi_setup(spi);
+	if (err) {
+		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
+		goto err_drvdata;
+	}
+
+	err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base);
+	if (err)
+		goto err_drvdata;
+
+	rb4xx_cpld = cpld;
+
+	return 0;
+
+err_drvdata:
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(cpld);
+
+	return err;
+}
+
+static int rb4xx_cpld_remove(struct spi_device *spi)
+{
+	struct rb4xx_cpld *cpld;
+
+	rb4xx_cpld = NULL;
+	cpld = dev_get_drvdata(&spi->dev);
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(cpld);
+
+	return 0;
+}
+
+static struct spi_driver rb4xx_cpld_driver = {
+	.driver = {
+		.name		= DRV_NAME,
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= rb4xx_cpld_probe,
+	.remove		= rb4xx_cpld_remove,
+};
+
+static int __init rb4xx_cpld_init(void)
+{
+	return spi_register_driver(&rb4xx_cpld_driver);
+}
+module_init(rb4xx_cpld_init);
+
+static void __exit rb4xx_cpld_exit(void)
+{
+	spi_unregister_driver(&rb4xx_cpld_driver);
+}
+module_exit(rb4xx_cpld_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/spi/spi-rb4xx.c b/target/linux/ar71xx/files/drivers/spi/spi-rb4xx.c
new file mode 100644
index 0000000000..357fd41708
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/spi/spi-rb4xx.c
@@ -0,0 +1,507 @@
+/*
+ * SPI controller driver for the Mikrotik RB4xx boards
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file was based on the patches for Linux 2.6.27.39 published by
+ * MikroTik for their RouterBoard 4xx series devices.
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+
+#define DRV_NAME	"rb4xx-spi"
+#define DRV_DESC	"Mikrotik RB4xx SPI controller driver"
+#define DRV_VERSION	"0.1.0"
+
+#define SPI_CTRL_FASTEST	0x40
+#define SPI_FLASH_HZ		33333334
+#define SPI_CPLD_HZ		33333334
+
+#define CPLD_CMD_READ_FAST	0x0b
+
+#undef RB4XX_SPI_DEBUG
+
+struct rb4xx_spi {
+	void __iomem		*base;
+	struct spi_master	*master;
+
+	unsigned		spi_ctrl_flash;
+	unsigned		spi_ctrl_fread;
+
+	struct clk		*ahb_clk;
+	unsigned long		ahb_freq;
+
+	spinlock_t		lock;
+	struct list_head	queue;
+	int			busy:1;
+	int			cs_wait;
+};
+
+static unsigned spi_clk_low = AR71XX_SPI_IOC_CS1;
+
+#ifdef RB4XX_SPI_DEBUG
+static inline void do_spi_delay(void)
+{
+	ndelay(20000);
+}
+#else
+static inline void do_spi_delay(void) { }
+#endif
+
+static inline void do_spi_init(struct spi_device *spi)
+{
+	unsigned cs = AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1;
+
+	if (!(spi->mode & SPI_CS_HIGH))
+		cs ^= (spi->chip_select == 2) ? AR71XX_SPI_IOC_CS1 :
+						AR71XX_SPI_IOC_CS0;
+
+	spi_clk_low = cs;
+}
+
+static inline void do_spi_finish(void __iomem *base)
+{
+	do_spi_delay();
+	__raw_writel(AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1,
+		     base + AR71XX_SPI_REG_IOC);
+}
+
+static inline void do_spi_clk(void __iomem *base, int bit)
+{
+	unsigned bval = spi_clk_low | ((bit & 1) ? AR71XX_SPI_IOC_DO : 0);
+
+	do_spi_delay();
+	__raw_writel(bval, base + AR71XX_SPI_REG_IOC);
+	do_spi_delay();
+	__raw_writel(bval | AR71XX_SPI_IOC_CLK, base + AR71XX_SPI_REG_IOC);
+}
+
+static void do_spi_byte(void __iomem *base, unsigned char byte)
+{
+	do_spi_clk(base, byte >> 7);
+	do_spi_clk(base, byte >> 6);
+	do_spi_clk(base, byte >> 5);
+	do_spi_clk(base, byte >> 4);
+	do_spi_clk(base, byte >> 3);
+	do_spi_clk(base, byte >> 2);
+	do_spi_clk(base, byte >> 1);
+	do_spi_clk(base, byte);
+
+	pr_debug("spi_byte sent 0x%02x got 0x%02x\n",
+	       (unsigned)byte,
+	       (unsigned char)__raw_readl(base + AR71XX_SPI_REG_RDS));
+}
+
+static inline void do_spi_clk_fast(void __iomem *base, unsigned bit1,
+				   unsigned bit2)
+{
+	unsigned bval = (spi_clk_low |
+			 ((bit1 & 1) ? AR71XX_SPI_IOC_DO : 0) |
+			 ((bit2 & 1) ? AR71XX_SPI_IOC_CS2 : 0));
+	do_spi_delay();
+	__raw_writel(bval, base + AR71XX_SPI_REG_IOC);
+	do_spi_delay();
+	__raw_writel(bval | AR71XX_SPI_IOC_CLK, base + AR71XX_SPI_REG_IOC);
+}
+
+static void do_spi_byte_fast(void __iomem *base, unsigned char byte)
+{
+	do_spi_clk_fast(base, byte >> 7, byte >> 6);
+	do_spi_clk_fast(base, byte >> 5, byte >> 4);
+	do_spi_clk_fast(base, byte >> 3, byte >> 2);
+	do_spi_clk_fast(base, byte >> 1, byte >> 0);
+
+	pr_debug("spi_byte_fast sent 0x%02x got 0x%02x\n",
+	       (unsigned)byte,
+	       (unsigned char) __raw_readl(base + AR71XX_SPI_REG_RDS));
+}
+
+static int rb4xx_spi_txrx(void __iomem *base, struct spi_transfer *t)
+{
+	const unsigned char *rxv_ptr = NULL;
+	const unsigned char *tx_ptr = t->tx_buf;
+	unsigned char *rx_ptr = t->rx_buf;
+	unsigned i;
+
+	pr_debug("spi_txrx len %u tx %u rx %u\n",
+	       t->len,
+	       (t->tx_buf ? 1 : 0),
+	       (t->rx_buf ? 1 : 0));
+
+	if (t->verify) {
+		rxv_ptr = tx_ptr;
+		tx_ptr = NULL;
+	}
+
+	for (i = 0; i < t->len; ++i) {
+		unsigned char sdata = tx_ptr ? tx_ptr[i] : 0;
+
+		if (t->fast_write)
+			do_spi_byte_fast(base, sdata);
+		else
+			do_spi_byte(base, sdata);
+
+		if (rx_ptr) {
+			rx_ptr[i] = __raw_readl(base + AR71XX_SPI_REG_RDS) & 0xff;
+		} else if (rxv_ptr) {
+			unsigned char c = __raw_readl(base + AR71XX_SPI_REG_RDS);
+			if (rxv_ptr[i] != c)
+				return i;
+		}
+	}
+
+	return i;
+}
+
+static int rb4xx_spi_read_fast(struct rb4xx_spi *rbspi,
+			       struct spi_message *m)
+{
+	struct spi_transfer *t;
+	const unsigned char *tx_ptr;
+	unsigned addr;
+	void __iomem *base = rbspi->base;
+
+	/* check for exactly two transfers */
+	if (list_empty(&m->transfers) ||
+	    list_is_last(m->transfers.next, &m->transfers) ||
+	    !list_is_last(m->transfers.next->next, &m->transfers)) {
+		return -1;
+	}
+
+	/* first transfer contains command and address  */
+	t = list_entry(m->transfers.next,
+		       struct spi_transfer, transfer_list);
+
+	if (t->len != 5 || t->tx_buf == NULL)
+		return -1;
+
+	tx_ptr = t->tx_buf;
+	if (tx_ptr[0] != CPLD_CMD_READ_FAST)
+		return -1;
+
+	addr = tx_ptr[1];
+	addr = tx_ptr[2] | (addr << 8);
+	addr = tx_ptr[3] | (addr << 8);
+	addr += (unsigned) base;
+
+	m->actual_length += t->len;
+
+	/* second transfer contains data itself */
+	t = list_entry(m->transfers.next->next,
+		       struct spi_transfer, transfer_list);
+
+	if (t->tx_buf && !t->verify)
+		return -1;
+
+	__raw_writel(AR71XX_SPI_FS_GPIO, base + AR71XX_SPI_REG_FS);
+	__raw_writel(rbspi->spi_ctrl_fread, base + AR71XX_SPI_REG_CTRL);
+	__raw_writel(0, base + AR71XX_SPI_REG_FS);
+
+	if (t->rx_buf) {
+		memcpy(t->rx_buf, (const void *)addr, t->len);
+	} else if (t->tx_buf) {
+		unsigned char buf[t->len];
+		memcpy(buf, (const void *)addr, t->len);
+		if (memcmp(t->tx_buf, buf, t->len) != 0)
+			m->status = -EMSGSIZE;
+	}
+	m->actual_length += t->len;
+
+	if (rbspi->spi_ctrl_flash != rbspi->spi_ctrl_fread) {
+		__raw_writel(AR71XX_SPI_FS_GPIO, base + AR71XX_SPI_REG_FS);
+		__raw_writel(rbspi->spi_ctrl_flash, base + AR71XX_SPI_REG_CTRL);
+		__raw_writel(0, base + AR71XX_SPI_REG_FS);
+	}
+
+	return 0;
+}
+
+static int rb4xx_spi_msg(struct rb4xx_spi *rbspi, struct spi_message *m)
+{
+	struct spi_transfer *t = NULL;
+	void __iomem *base = rbspi->base;
+
+	m->status = 0;
+	if (list_empty(&m->transfers))
+		return -1;
+
+	if (m->fast_read)
+		if (rb4xx_spi_read_fast(rbspi, m) == 0)
+			return -1;
+
+	__raw_writel(AR71XX_SPI_FS_GPIO, base + AR71XX_SPI_REG_FS);
+	__raw_writel(SPI_CTRL_FASTEST, base + AR71XX_SPI_REG_CTRL);
+	do_spi_init(m->spi);
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		int len;
+
+		len = rb4xx_spi_txrx(base, t);
+		if (len != t->len) {
+			m->status = -EMSGSIZE;
+			break;
+		}
+		m->actual_length += len;
+
+		if (t->cs_change) {
+			if (list_is_last(&t->transfer_list, &m->transfers)) {
+				/* wait for continuation */
+				return m->spi->chip_select;
+			}
+			do_spi_finish(base);
+			ndelay(100);
+		}
+	}
+
+	do_spi_finish(base);
+	__raw_writel(rbspi->spi_ctrl_flash, base + AR71XX_SPI_REG_CTRL);
+	__raw_writel(0, base + AR71XX_SPI_REG_FS);
+	return -1;
+}
+
+static void rb4xx_spi_process_queue_locked(struct rb4xx_spi *rbspi,
+					   unsigned long *flags)
+{
+	int cs = rbspi->cs_wait;
+
+	rbspi->busy = 1;
+	while (!list_empty(&rbspi->queue)) {
+		struct spi_message *m;
+
+		list_for_each_entry(m, &rbspi->queue, queue)
+			if (cs < 0 || cs == m->spi->chip_select)
+				break;
+
+		if (&m->queue == &rbspi->queue)
+			break;
+
+		list_del_init(&m->queue);
+		spin_unlock_irqrestore(&rbspi->lock, *flags);
+
+		cs = rb4xx_spi_msg(rbspi, m);
+		m->complete(m->context);
+
+		spin_lock_irqsave(&rbspi->lock, *flags);
+	}
+
+	rbspi->cs_wait = cs;
+	rbspi->busy = 0;
+
+	if (cs >= 0) {
+		/* TODO: add timer to unlock cs after 1s inactivity */
+	}
+}
+
+static int rb4xx_spi_transfer(struct spi_device *spi,
+			      struct spi_message *m)
+{
+	struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&rbspi->lock, flags);
+	list_add_tail(&m->queue, &rbspi->queue);
+	if (rbspi->busy ||
+	    (rbspi->cs_wait >= 0 && rbspi->cs_wait != m->spi->chip_select)) {
+		/* job will be done later */
+		spin_unlock_irqrestore(&rbspi->lock, flags);
+		return 0;
+	}
+
+	/* process job in current context */
+	rb4xx_spi_process_queue_locked(rbspi, &flags);
+	spin_unlock_irqrestore(&rbspi->lock, flags);
+
+	return 0;
+}
+
+static int rb4xx_spi_setup(struct spi_device *spi)
+{
+	struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	if (spi->mode & ~(SPI_CS_HIGH)) {
+		dev_err(&spi->dev, "mode %x not supported\n",
+			(unsigned) spi->mode);
+		return -EINVAL;
+	}
+
+	if (spi->bits_per_word != 8 && spi->bits_per_word != 0) {
+		dev_err(&spi->dev, "bits_per_word %u not supported\n",
+			(unsigned) spi->bits_per_word);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&rbspi->lock, flags);
+	if (rbspi->cs_wait == spi->chip_select && !rbspi->busy) {
+		rbspi->cs_wait = -1;
+		rb4xx_spi_process_queue_locked(rbspi, &flags);
+	}
+	spin_unlock_irqrestore(&rbspi->lock, flags);
+
+	return 0;
+}
+
+static unsigned get_spi_ctrl(struct rb4xx_spi *rbspi, unsigned hz_max,
+			     const char *name)
+{
+	unsigned div;
+
+	div = (rbspi->ahb_freq - 1) / (2 * hz_max);
+
+	/*
+	 * CPU has a bug at (div == 0) - first bit read is random
+	 */
+	if (div == 0)
+		++div;
+
+	if (name) {
+		unsigned ahb_khz = (rbspi->ahb_freq + 500) / 1000;
+		unsigned div_real = 2 * (div + 1);
+		pr_debug("rb4xx: %s SPI clock %u kHz (AHB %u kHz / %u)\n",
+		       name,
+		       ahb_khz / div_real,
+		       ahb_khz, div_real);
+	}
+
+	return SPI_CTRL_FASTEST + div;
+}
+
+static int rb4xx_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct rb4xx_spi *rbspi;
+	struct resource *r;
+	int err = 0;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
+	if (master == NULL) {
+		dev_err(&pdev->dev, "no memory for spi_master\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	master->bus_num = 0;
+	master->num_chipselect = 3;
+	master->setup = rb4xx_spi_setup;
+	master->transfer = rb4xx_spi_transfer;
+
+	rbspi = spi_master_get_devdata(master);
+
+	rbspi->ahb_clk = clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(rbspi->ahb_clk)) {
+		err = PTR_ERR(rbspi->ahb_clk);
+		goto err_put_master;
+	}
+
+	err = clk_prepare_enable(rbspi->ahb_clk);
+	if (err)
+		goto err_clk_put;
+
+	rbspi->ahb_freq = clk_get_rate(rbspi->ahb_clk);
+	if (!rbspi->ahb_freq) {
+		err = -EINVAL;
+		goto err_clk_disable;
+	}
+
+	platform_set_drvdata(pdev, rbspi);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		err = -ENOENT;
+		goto err_clk_disable;
+	}
+
+	rbspi->base = ioremap(r->start, r->end - r->start + 1);
+	if (!rbspi->base) {
+		err = -ENXIO;
+		goto err_clk_disable;
+	}
+
+	rbspi->master = master;
+	rbspi->spi_ctrl_flash = get_spi_ctrl(rbspi, SPI_FLASH_HZ, "FLASH");
+	rbspi->spi_ctrl_fread = get_spi_ctrl(rbspi, SPI_CPLD_HZ, "CPLD");
+	rbspi->cs_wait = -1;
+
+	spin_lock_init(&rbspi->lock);
+	INIT_LIST_HEAD(&rbspi->queue);
+
+	err = spi_register_master(master);
+	if (err) {
+		dev_err(&pdev->dev, "failed to register SPI master\n");
+		goto err_iounmap;
+	}
+
+	return 0;
+
+err_iounmap:
+	iounmap(rbspi->base);
+err_clk_disable:
+	clk_disable(rbspi->ahb_clk);
+err_clk_put:
+	clk_put(rbspi->ahb_clk);
+err_put_master:
+	platform_set_drvdata(pdev, NULL);
+	spi_master_put(master);
+err_out:
+	return err;
+}
+
+static int rb4xx_spi_remove(struct platform_device *pdev)
+{
+	struct rb4xx_spi *rbspi = platform_get_drvdata(pdev);
+
+	iounmap(rbspi->base);
+	clk_disable(rbspi->ahb_clk);
+	clk_put(rbspi->ahb_clk);
+	platform_set_drvdata(pdev, NULL);
+	spi_master_put(rbspi->master);
+
+	return 0;
+}
+
+static struct platform_driver rb4xx_spi_drv = {
+	.probe		= rb4xx_spi_probe,
+	.remove		= rb4xx_spi_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rb4xx_spi_init(void)
+{
+	return platform_driver_register(&rb4xx_spi_drv);
+}
+subsys_initcall(rb4xx_spi_init);
+
+static void __exit rb4xx_spi_exit(void)
+{
+	platform_driver_unregister(&rb4xx_spi_drv);
+}
+
+module_exit(rb4xx_spi_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ar71xx/files/drivers/spi/spi-vsc7385.c b/target/linux/ar71xx/files/drivers/spi/spi-vsc7385.c
new file mode 100644
index 0000000000..b712e71875
--- /dev/null
+++ b/target/linux/ar71xx/files/drivers/spi/spi-vsc7385.c
@@ -0,0 +1,621 @@
+/*
+ * SPI driver for the Vitesse VSC7385 ethernet switch
+ *
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/firmware.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/vsc7385.h>
+
+#define DRV_NAME	"spi-vsc7385"
+#define DRV_DESC	"Vitesse VSC7385 Gbit ethernet switch driver"
+#define DRV_VERSION	"0.1.0"
+
+#define VSC73XX_BLOCK_MAC	0x1
+#define VSC73XX_BLOCK_2		0x2
+#define VSC73XX_BLOCK_MII	0x3
+#define VSC73XX_BLOCK_4		0x4
+#define VSC73XX_BLOCK_5		0x5
+#define VSC73XX_BLOCK_SYSTEM	0x7
+
+#define VSC73XX_SUBBLOCK_PORT_0		0
+#define VSC73XX_SUBBLOCK_PORT_1		1
+#define VSC73XX_SUBBLOCK_PORT_2		2
+#define VSC73XX_SUBBLOCK_PORT_3		3
+#define VSC73XX_SUBBLOCK_PORT_4		4
+#define VSC73XX_SUBBLOCK_PORT_MAC	6
+
+/* MAC Block registers */
+#define VSC73XX_MAC_CFG		0x0
+#define VSC73XX_ADVPORTM	0x19
+#define VSC73XX_RXOCT		0x50
+#define VSC73XX_TXOCT		0x51
+#define VSC73XX_C_RX0		0x52
+#define VSC73XX_C_RX1		0x53
+#define VSC73XX_C_RX2		0x54
+#define VSC73XX_C_TX0		0x55
+#define VSC73XX_C_TX1		0x56
+#define VSC73XX_C_TX2		0x57
+#define VSC73XX_C_CFG		0x58
+
+/* MAC_CFG register bits */
+#define VSC73XX_MAC_CFG_WEXC_DIS	(1 << 31)
+#define VSC73XX_MAC_CFG_PORT_RST	(1 << 29)
+#define VSC73XX_MAC_CFG_TX_EN		(1 << 28)
+#define VSC73XX_MAC_CFG_SEED_LOAD	(1 << 27)
+#define VSC73XX_MAC_CFG_FDX		(1 << 18)
+#define VSC73XX_MAC_CFG_GIGE		(1 << 17)
+#define VSC73XX_MAC_CFG_RX_EN		(1 << 16)
+#define VSC73XX_MAC_CFG_VLAN_DBLAWR	(1 << 15)
+#define VSC73XX_MAC_CFG_VLAN_AWR	(1 << 14)
+#define VSC73XX_MAC_CFG_100_BASE_T	(1 << 13)
+#define VSC73XX_MAC_CFG_TX_IPG(x)	(((x) & 0x1f) << 6)
+#define VSC73XX_MAC_CFG_MAC_RX_RST	(1 << 5)
+#define VSC73XX_MAC_CFG_MAC_TX_RST	(1 << 4)
+#define VSC73XX_MAC_CFG_BIT2		(1 << 2)
+#define VSC73XX_MAC_CFG_CLK_SEL(x)	((x) & 0x3)
+
+/* ADVPORTM register bits */
+#define VSC73XX_ADVPORTM_IFG_PPM	(1 << 7)
+#define VSC73XX_ADVPORTM_EXC_COL_CONT	(1 << 6)
+#define VSC73XX_ADVPORTM_EXT_PORT	(1 << 5)
+#define VSC73XX_ADVPORTM_INV_GTX	(1 << 4)
+#define VSC73XX_ADVPORTM_ENA_GTX	(1 << 3)
+#define VSC73XX_ADVPORTM_DDR_MODE	(1 << 2)
+#define VSC73XX_ADVPORTM_IO_LOOPBACK	(1 << 1)
+#define VSC73XX_ADVPORTM_HOST_LOOPBACK	(1 << 0)
+
+/* MII Block registers */
+#define VSC73XX_MII_STAT	0x0
+#define VSC73XX_MII_CMD		0x1
+#define VSC73XX_MII_DATA	0x2
+
+/* System Block registers */
+#define VSC73XX_ICPU_SIPAD		0x01
+#define VSC73XX_ICPU_CLOCK_DELAY	0x05
+#define VSC73XX_ICPU_CTRL		0x10
+#define VSC73XX_ICPU_ADDR		0x11
+#define VSC73XX_ICPU_SRAM		0x12
+#define VSC73XX_ICPU_MBOX_VAL		0x15
+#define VSC73XX_ICPU_MBOX_SET		0x16
+#define VSC73XX_ICPU_MBOX_CLR		0x17
+#define VSC73XX_ICPU_CHIPID		0x18
+#define VSC73XX_ICPU_GPIO		0x34
+
+#define VSC73XX_ICPU_CTRL_CLK_DIV	(1 << 8)
+#define VSC73XX_ICPU_CTRL_SRST_HOLD	(1 << 7)
+#define VSC73XX_ICPU_CTRL_BOOT_EN	(1 << 3)
+#define VSC73XX_ICPU_CTRL_EXT_ACC_EN	(1 << 2)
+#define VSC73XX_ICPU_CTRL_CLK_EN	(1 << 1)
+#define VSC73XX_ICPU_CTRL_SRST		(1 << 0)
+
+#define VSC73XX_ICPU_CHIPID_ID_SHIFT	12
+#define VSC73XX_ICPU_CHIPID_ID_MASK	0xffff
+#define VSC73XX_ICPU_CHIPID_REV_SHIFT	28
+#define VSC73XX_ICPU_CHIPID_REV_MASK	0xf
+#define VSC73XX_ICPU_CHIPID_ID_7385	0x7385
+#define VSC73XX_ICPU_CHIPID_ID_7395	0x7395
+
+#define VSC73XX_CMD_MODE_READ		0
+#define VSC73XX_CMD_MODE_WRITE		1
+#define VSC73XX_CMD_MODE_SHIFT		4
+#define VSC73XX_CMD_BLOCK_SHIFT		5
+#define VSC73XX_CMD_BLOCK_MASK		0x7
+#define VSC73XX_CMD_SUBBLOCK_MASK	0xf
+
+#define VSC7385_CLOCK_DELAY		((3 << 4) | 3)
+#define VSC7385_CLOCK_DELAY_MASK	((3 << 4) | 3)
+
+#define VSC73XX_ICPU_CTRL_STOP	(VSC73XX_ICPU_CTRL_SRST_HOLD | \
+				 VSC73XX_ICPU_CTRL_BOOT_EN | \
+				 VSC73XX_ICPU_CTRL_EXT_ACC_EN)
+
+#define VSC73XX_ICPU_CTRL_START	(VSC73XX_ICPU_CTRL_CLK_DIV | \
+				 VSC73XX_ICPU_CTRL_BOOT_EN | \
+				 VSC73XX_ICPU_CTRL_CLK_EN | \
+				 VSC73XX_ICPU_CTRL_SRST)
+
+#define VSC7385_ADVPORTM_MASK	(VSC73XX_ADVPORTM_IFG_PPM | \
+				 VSC73XX_ADVPORTM_EXC_COL_CONT | \
+				 VSC73XX_ADVPORTM_EXT_PORT | \
+				 VSC73XX_ADVPORTM_INV_GTX | \
+				 VSC73XX_ADVPORTM_ENA_GTX | \
+				 VSC73XX_ADVPORTM_DDR_MODE | \
+				 VSC73XX_ADVPORTM_IO_LOOPBACK | \
+				 VSC73XX_ADVPORTM_HOST_LOOPBACK)
+
+#define VSC7385_ADVPORTM_INIT	(VSC73XX_ADVPORTM_EXT_PORT | \
+				 VSC73XX_ADVPORTM_ENA_GTX | \
+				 VSC73XX_ADVPORTM_DDR_MODE)
+
+#define VSC7385_MAC_CFG_RESET	(VSC73XX_MAC_CFG_PORT_RST | \
+				 VSC73XX_MAC_CFG_MAC_RX_RST | \
+				 VSC73XX_MAC_CFG_MAC_TX_RST)
+
+#define VSC73XX_MAC_CFG_INIT	(VSC73XX_MAC_CFG_TX_EN | \
+				 VSC73XX_MAC_CFG_FDX | \
+				 VSC73XX_MAC_CFG_GIGE | \
+				 VSC73XX_MAC_CFG_RX_EN)
+
+#define VSC73XX_RESET_DELAY	100
+
+struct vsc7385 {
+	struct spi_device		*spi;
+	struct mutex			lock;
+	struct vsc7385_platform_data	*pdata;
+};
+
+static int vsc7385_is_addr_valid(u8 block, u8 subblock)
+{
+	switch (block) {
+	case VSC73XX_BLOCK_MAC:
+		switch (subblock) {
+		case 0 ... 4:
+		case 6:
+			return 1;
+		}
+		break;
+
+	case VSC73XX_BLOCK_2:
+	case VSC73XX_BLOCK_SYSTEM:
+		switch (subblock) {
+		case 0:
+			return 1;
+		}
+		break;
+
+	case VSC73XX_BLOCK_MII:
+	case VSC73XX_BLOCK_4:
+	case VSC73XX_BLOCK_5:
+		switch (subblock) {
+		case 0 ... 1:
+			return 1;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static inline u8 vsc7385_make_addr(u8 mode, u8 block, u8 subblock)
+{
+	u8 ret;
+
+	ret = (block & VSC73XX_CMD_BLOCK_MASK) << VSC73XX_CMD_BLOCK_SHIFT;
+	ret |= (mode & 1) << VSC73XX_CMD_MODE_SHIFT;
+	ret |= subblock & VSC73XX_CMD_SUBBLOCK_MASK;
+
+	return ret;
+}
+
+static int vsc7385_read(struct vsc7385 *vsc, u8 block, u8 subblock, u8 reg,
+			u32 *value)
+{
+	u8 cmd[4];
+	u8 buf[4];
+	struct spi_transfer t[2];
+	struct spi_message m;
+	int err;
+
+	if (!vsc7385_is_addr_valid(block, subblock))
+		return -EINVAL;
+
+	spi_message_init(&m);
+
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = buf;
+	t[1].len = sizeof(buf);
+	spi_message_add_tail(&t[1], &m);
+
+	cmd[0] = vsc7385_make_addr(VSC73XX_CMD_MODE_READ, block, subblock);
+	cmd[1] = reg;
+	cmd[2] = 0;
+	cmd[3] = 0;
+
+	mutex_lock(&vsc->lock);
+	err = spi_sync(vsc->spi, &m);
+	mutex_unlock(&vsc->lock);
+
+	if (err)
+		return err;
+
+	*value = (((u32) buf[0]) << 24) | (((u32) buf[1]) << 16) |
+		 (((u32) buf[2]) << 8) | ((u32) buf[3]);
+
+	return 0;
+}
+
+
+static int vsc7385_write(struct vsc7385 *vsc, u8 block, u8 subblock, u8 reg,
+			 u32 value)
+{
+	u8 cmd[2];
+	u8 buf[4];
+	struct spi_transfer t[2];
+	struct spi_message m;
+	int err;
+
+	if (!vsc7385_is_addr_valid(block, subblock))
+		return -EINVAL;
+
+	spi_message_init(&m);
+
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = cmd;
+	t[0].len = sizeof(cmd);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = buf;
+	t[1].len = sizeof(buf);
+	spi_message_add_tail(&t[1], &m);
+
+	cmd[0] = vsc7385_make_addr(VSC73XX_CMD_MODE_WRITE, block, subblock);
+	cmd[1] = reg;
+
+	buf[0] = (value >> 24) & 0xff;
+	buf[1] = (value >> 16) & 0xff;
+	buf[2] = (value >> 8) & 0xff;
+	buf[3] = value & 0xff;
+
+	mutex_lock(&vsc->lock);
+	err = spi_sync(vsc->spi, &m);
+	mutex_unlock(&vsc->lock);
+
+	return err;
+}
+
+static inline int vsc7385_write_verify(struct vsc7385 *vsc, u8 block,
+				       u8 subblock, u8 reg, u32 value,
+				       u32 read_mask, u32 read_val)
+{
+	struct spi_device *spi = vsc->spi;
+	u32 t;
+	int err;
+
+	err = vsc7385_write(vsc, block, subblock, reg, value);
+	if (err)
+		return err;
+
+	err = vsc7385_read(vsc, block, subblock, reg, &t);
+	if (err)
+		return err;
+
+	if ((t & read_mask) != read_val) {
+		dev_err(&spi->dev, "register write error\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline int vsc7385_set_clock_delay(struct vsc7385 *vsc, u32 val)
+{
+	return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+			     VSC73XX_ICPU_CLOCK_DELAY, val);
+}
+
+static inline int vsc7385_get_clock_delay(struct vsc7385 *vsc, u32 *val)
+{
+	return vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+			    VSC73XX_ICPU_CLOCK_DELAY, val);
+}
+
+static inline int vsc7385_icpu_stop(struct vsc7385 *vsc)
+{
+	return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_CTRL,
+			     VSC73XX_ICPU_CTRL_STOP);
+}
+
+static inline int vsc7385_icpu_start(struct vsc7385 *vsc)
+{
+	return vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_CTRL,
+			     VSC73XX_ICPU_CTRL_START);
+}
+
+static inline int vsc7385_icpu_reset(struct vsc7385 *vsc)
+{
+	int rc;
+
+	rc = vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_ICPU_ADDR,
+			   0x0000);
+	if (rc)
+		dev_err(&vsc->spi->dev,
+			"could not reset microcode, err=%d\n", rc);
+
+	return rc;
+}
+
+static int vsc7385_upload_ucode(struct vsc7385 *vsc)
+{
+	struct spi_device *spi = vsc->spi;
+	const struct firmware *firmware;
+	char *ucode_name;
+	unsigned char *dp;
+	unsigned int curVal;
+	int i;
+	int diffs;
+	int rc;
+
+	ucode_name = (vsc->pdata->ucode_name) ? vsc->pdata->ucode_name
+					      : "vsc7385_ucode.bin";
+	rc = request_firmware(&firmware, ucode_name, &spi->dev);
+	if (rc) {
+		dev_err(&spi->dev, "request_firmware failed, err=%d\n",
+			rc);
+		return rc;
+	}
+
+	rc = vsc7385_icpu_stop(vsc);
+	if (rc)
+		goto out;
+
+	rc = vsc7385_icpu_reset(vsc);
+	if (rc)
+		goto out;
+
+	dev_info(&spi->dev, "uploading microcode...\n");
+
+	dp = (unsigned char *) firmware->data;
+	for (i = 0; i < firmware->size; i++) {
+		rc = vsc7385_write(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+				   VSC73XX_ICPU_SRAM, *dp++);
+		if (rc) {
+			dev_err(&spi->dev, "could not load microcode, err=%d\n",
+				rc);
+			goto out;
+		}
+	}
+
+	rc = vsc7385_icpu_reset(vsc);
+	if (rc)
+		goto out;
+
+	dev_info(&spi->dev, "verifying microcode...\n");
+
+	dp = (unsigned char *) firmware->data;
+	diffs = 0;
+	for (i = 0; i < firmware->size; i++) {
+		rc = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+				  VSC73XX_ICPU_SRAM, &curVal);
+		if (rc) {
+			dev_err(&spi->dev, "could not read microcode %d\n",
+				rc);
+			goto out;
+		}
+
+		if (curVal > 0xff) {
+			dev_err(&spi->dev, "bad val read: %04x : %02x  %02x\n",
+				i, *dp, curVal);
+			rc = -EIO;
+			goto out;
+		}
+
+		if ((curVal & 0xff) != *dp) {
+			diffs++;
+			dev_err(&spi->dev, "verify error: %04x : %02x  %02x\n",
+				i, *dp, curVal);
+
+			if (diffs > 4)
+				break;
+			}
+		dp++;
+	}
+
+	if (diffs) {
+		dev_err(&spi->dev, "microcode verification failed\n");
+		rc = -EIO;
+		goto out;
+	}
+
+	dev_info(&spi->dev, "microcode uploaded\n");
+
+	rc = vsc7385_icpu_start(vsc);
+
+out:
+	release_firmware(firmware);
+	return rc;
+}
+
+static int vsc7385_setup(struct vsc7385 *vsc)
+{
+	struct vsc7385_platform_data *pdata = vsc->pdata;
+	u32 t;
+	int err;
+
+	err = vsc7385_write_verify(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+				   VSC73XX_ICPU_CLOCK_DELAY,
+				   VSC7385_CLOCK_DELAY,
+				   VSC7385_CLOCK_DELAY_MASK,
+				   VSC7385_CLOCK_DELAY);
+	if (err)
+		goto err;
+
+	err = vsc7385_write_verify(vsc, VSC73XX_BLOCK_MAC,
+				   VSC73XX_SUBBLOCK_PORT_MAC, VSC73XX_ADVPORTM,
+				   VSC7385_ADVPORTM_INIT,
+				   VSC7385_ADVPORTM_MASK,
+				   VSC7385_ADVPORTM_INIT);
+	if (err)
+		goto err;
+
+	err = vsc7385_write(vsc, VSC73XX_BLOCK_MAC, VSC73XX_SUBBLOCK_PORT_MAC,
+			    VSC73XX_MAC_CFG, VSC7385_MAC_CFG_RESET);
+	if (err)
+		goto err;
+
+	t = VSC73XX_MAC_CFG_INIT;
+	t |= VSC73XX_MAC_CFG_TX_IPG(pdata->mac_cfg.tx_ipg);
+	t |= VSC73XX_MAC_CFG_CLK_SEL(pdata->mac_cfg.clk_sel);
+	if (pdata->mac_cfg.bit2)
+		t |= VSC73XX_MAC_CFG_BIT2;
+
+	err = vsc7385_write(vsc, VSC73XX_BLOCK_MAC, VSC73XX_SUBBLOCK_PORT_MAC,
+			    VSC73XX_MAC_CFG, t);
+	if (err)
+		goto err;
+
+	return 0;
+
+err:
+	return err;
+}
+
+static int vsc7385_detect(struct vsc7385 *vsc)
+{
+	struct spi_device *spi = vsc->spi;
+	u32 t;
+	u32 id;
+	u32 rev;
+	int err;
+
+	err = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+				VSC73XX_ICPU_MBOX_VAL, &t);
+	if (err) {
+		dev_err(&spi->dev, "unable to read mailbox, err=%d\n", err);
+		return err;
+	}
+
+	if (t == 0xffffffff) {
+		dev_dbg(&spi->dev, "assert chip reset\n");
+		if (vsc->pdata->reset)
+			vsc->pdata->reset();
+
+	}
+
+	err = vsc7385_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
+				VSC73XX_ICPU_CHIPID, &t);
+	if (err) {
+		dev_err(&spi->dev, "unable to read chip id, err=%d\n", err);
+		return err;
+	}
+
+	id = (t >> VSC73XX_ICPU_CHIPID_ID_SHIFT) & VSC73XX_ICPU_CHIPID_ID_MASK;
+	switch (id) {
+	case VSC73XX_ICPU_CHIPID_ID_7385:
+	case VSC73XX_ICPU_CHIPID_ID_7395:
+		break;
+	default:
+		dev_err(&spi->dev, "unsupported chip, id=%04x\n", id);
+		return -ENODEV;
+	}
+
+	rev = (t >> VSC73XX_ICPU_CHIPID_REV_SHIFT) &
+	      VSC73XX_ICPU_CHIPID_REV_MASK;
+	dev_info(&spi->dev, "VSC%04X (rev. %d) switch found\n", id, rev);
+
+	return 0;
+}
+
+static int vsc7385_probe(struct spi_device *spi)
+{
+	struct vsc7385 *vsc;
+	struct vsc7385_platform_data *pdata;
+	int	err;
+
+	printk(KERN_INFO DRV_DESC " version " DRV_VERSION"\n");
+
+	pdata = spi->dev.platform_data;
+	if (!pdata) {
+		dev_err(&spi->dev, "no platform data specified\n");
+		return -ENODEV;
+	}
+
+	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
+	if (!vsc) {
+		dev_err(&spi->dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&vsc->lock);
+	vsc->pdata = pdata;
+	vsc->spi = spi_dev_get(spi);
+	dev_set_drvdata(&spi->dev, vsc);
+
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+	err = spi_setup(spi);
+	if (err) {
+		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
+		goto err_drvdata;
+	}
+
+	err = vsc7385_detect(vsc);
+	if (err) {
+		dev_err(&spi->dev, "no chip found, err=%d\n", err);
+		goto err_drvdata;
+	}
+
+	err = vsc7385_upload_ucode(vsc);
+	if (err)
+		goto err_drvdata;
+
+	err = vsc7385_setup(vsc);
+	if (err)
+		goto err_drvdata;
+
+	return 0;
+
+err_drvdata:
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(vsc);
+	return err;
+}
+
+static int vsc7385_remove(struct spi_device *spi)
+{
+	struct vsc7385_data	*vsc;
+
+	vsc = dev_get_drvdata(&spi->dev);
+	dev_set_drvdata(&spi->dev, NULL);
+	kfree(vsc);
+
+	return 0;
+}
+
+static struct spi_driver vsc7385_driver = {
+	.driver = {
+		.name		= DRV_NAME,
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= vsc7385_probe,
+	.remove		= vsc7385_remove,
+};
+
+static int __init vsc7385_init(void)
+{
+	return spi_register_driver(&vsc7385_driver);
+}
+module_init(vsc7385_init);
+
+static void __exit vsc7385_exit(void)
+{
+	spi_unregister_driver(&vsc7385_driver);
+}
+module_exit(vsc7385_exit);
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/target/linux/ar71xx/files/include/linux/leds-nu801.h b/target/linux/ar71xx/files/include/linux/leds-nu801.h
new file mode 100644
index 0000000000..0fc310d277
--- /dev/null
+++ b/target/linux/ar71xx/files/include/linux/leds-nu801.h
@@ -0,0 +1,38 @@
+#ifndef __LEDS_NU801_H__
+#define __LEDS_NU801_H__
+
+/*
+ * Definitions for LED driver for NU801
+ *
+ * Kevin Paul Herbert
+ * Copyright (c) 2012, Meraki, Inc.
+ *
+ * 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/leds.h>
+
+struct led_nu801_template {
+	const char *device_name;	/* Name of the platform device */
+	const char *name;	/* Name of this LED chain */
+	int num_leds;		/* Number of LEDs in the chain */
+	unsigned cki;		/* GPIO pin for CKI */
+	unsigned sdi;		/* GPIO pin for SDI */
+	int lei;		/* GPIO pin for LEI; < 0 if none */
+	u32 ndelay;		/* Delay in nanoseconds */
+	enum led_brightness init_brightness[3]; /* Default rgb state */
+#ifdef CONFIG_LEDS_TRIGGERS
+	const char *default_trigger; /* default trigger */
+#endif
+	const char *led_colors[3];  /* rgb color order */
+};
+
+struct led_nu801_platform_data {
+	int num_controllers;	/* Numnber of controllers */
+	struct led_nu801_template *template; /* Template per controller */
+};
+
+#endif /* __LEDS_NU801_H__ */
diff --git a/target/linux/ar71xx/files/include/linux/nxp_74hc153.h b/target/linux/ar71xx/files/include/linux/nxp_74hc153.h
new file mode 100644
index 0000000000..20b8845e53
--- /dev/null
+++ b/target/linux/ar71xx/files/include/linux/nxp_74hc153.h
@@ -0,0 +1,24 @@
+/*
+ *  NXP 74HC153 - Dual 4-input multiplexer defines
+ *
+ *  Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef _NXP_74HC153_H
+#define _NXP_74HC153_H
+
+#define NXP_74HC153_DRIVER_NAME "nxp-74hc153"
+
+struct nxp_74hc153_platform_data {
+	unsigned	gpio_base;
+	unsigned	gpio_pin_s0;
+	unsigned	gpio_pin_s1;
+	unsigned	gpio_pin_1y;
+	unsigned	gpio_pin_2y;
+};
+
+#endif /* _NXP_74HC153_H */
diff --git a/target/linux/ar71xx/files/include/linux/platform/ar934x_nfc.h b/target/linux/ar71xx/files/include/linux/platform/ar934x_nfc.h
new file mode 100644
index 0000000000..371aaee7f8
--- /dev/null
+++ b/target/linux/ar71xx/files/include/linux/platform/ar934x_nfc.h
@@ -0,0 +1,39 @@
+/*
+ * Platform data definition for the built-in NAND controller of the
+ * Atheros AR934x SoCs
+ *
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ */
+
+#ifndef _AR934X_NFC_PLATFORM_H
+#define _AR934X_NFC_PLATFORM_H
+
+#define AR934X_NFC_DRIVER_NAME		"ar934x-nfc"
+
+struct mtd_info;
+struct mtd_partition;
+
+enum ar934x_nfc_ecc_mode {
+	AR934X_NFC_ECC_SOFT = 0,
+	AR934X_NFC_ECC_HW,
+	AR934X_NFC_ECC_SOFT_BCH,
+};
+
+struct ar934x_nfc_platform_data {
+	const char *name;
+	struct mtd_partition *parts;
+	int nr_parts;
+
+	bool swap_dma;
+	enum ar934x_nfc_ecc_mode ecc_mode;
+
+	void (*hw_reset)(bool active);
+	void (*select_chip)(int chip_no);
+	int (*scan_fixup)(struct mtd_info *mtd);
+};
+
+#endif /* _AR934X_NFC_PLATFORM_H */
diff --git a/target/linux/ar71xx/files/include/linux/platform_data/gpio-latch.h b/target/linux/ar71xx/files/include/linux/platform_data/gpio-latch.h
new file mode 100644
index 0000000000..0450e679ec
--- /dev/null
+++ b/target/linux/ar71xx/files/include/linux/platform_data/gpio-latch.h
@@ -0,0 +1,14 @@
+#ifndef _GPIO_LATCH_H_
+#define _GPIO_LATCH_H_
+
+#define GPIO_LATCH_DRIVER_NAME	"gpio-latch"
+
+struct gpio_latch_platform_data {
+	int base;
+	int num_gpios;
+	int *gpios;
+	int le_gpio_index;
+	bool le_active_low;
+};
+
+#endif /* _GPIO_LATCH_H_ */
diff --git a/target/linux/ar71xx/files/include/linux/platform_data/rb91x_nand.h b/target/linux/ar71xx/files/include/linux/platform_data/rb91x_nand.h
new file mode 100644
index 0000000000..5f17fb8148
--- /dev/null
+++ b/target/linux/ar71xx/files/include/linux/platform_data/rb91x_nand.h
@@ -0,0 +1,16 @@
+#ifndef _RB91X_NAND_H_
+#define _RB91X_NAND_H_
+
+#define RB91X_NAND_DRIVER_NAME	"rb91x-nand"
+
+struct rb91x_nand_platform_data {
+	int gpio_nce;	/* chip enable, active low */
+	int gpio_ale;	/* address latch enable */
+	int gpio_cle;   /* command latch enable */
+	int gpio_rdy;
+	int gpio_read;
+	int gpio_nrw;	/* read/write enable, active low */
+	int gpio_nle;	/* latch enable, active low */
+};
+
+#endif /* _RB91X_NAND_H_ */
\ No newline at end of file
diff --git a/target/linux/ar71xx/files/include/linux/spi/vsc7385.h b/target/linux/ar71xx/files/include/linux/spi/vsc7385.h
new file mode 100644
index 0000000000..1072ad7941
--- /dev/null
+++ b/target/linux/ar71xx/files/include/linux/spi/vsc7385.h
@@ -0,0 +1,19 @@
+/*
+ * Platform data definition for the Vitesse VSC7385 ethernet switch driver
+ *
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ */
+
+struct vsc7385_platform_data {
+	void		(*reset)(void);
+	char		*ucode_name;
+	struct {
+		u32	tx_ipg:5;
+		u32	bit2:1;
+		u32	clk_sel:3;
+	} mac_cfg;
+};
diff --git a/target/linux/ar71xx/files/net/dsa/mv88e6063.c b/target/linux/ar71xx/files/net/dsa/mv88e6063.c
new file mode 100644
index 0000000000..5638a9fe94
--- /dev/null
+++ b/target/linux/ar71xx/files/net/dsa/mv88e6063.c
@@ -0,0 +1,294 @@
+/*
+ * net/dsa/mv88e6063.c - Driver for Marvell 88e6063 switch chips
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This driver was base on: net/dsa/mv88e6060.c
+ *   net/dsa/mv88e6063.c - Driver for Marvell 88e6060 switch chips
+ *   Copyright (c) 2008-2009 Marvell Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "dsa_priv.h"
+
+#define REG_BASE		0x10
+#define REG_PHY(p)		(REG_BASE + (p))
+#define REG_PORT(p)		(REG_BASE + 8 + (p))
+#define REG_GLOBAL		(REG_BASE + 0x0f)
+#define NUM_PORTS		7
+
+static int reg_read(struct dsa_switch *ds, int addr, int reg)
+{
+	return mdiobus_read(ds->master_mii_bus, addr, reg);
+}
+
+#define REG_READ(addr, reg)					\
+	({							\
+		int __ret;					\
+								\
+		__ret = reg_read(ds, addr, reg);		\
+		if (__ret < 0)					\
+			return __ret;				\
+		__ret;						\
+	})
+
+
+static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
+{
+	return mdiobus_write(ds->master_mii_bus, addr, reg, val);
+}
+
+#define REG_WRITE(addr, reg, val)				\
+	({							\
+		int __ret;					\
+								\
+		__ret = reg_write(ds, addr, reg, val);		\
+		if (__ret < 0)					\
+			return __ret;				\
+	})
+
+static char *mv88e6063_probe(struct mii_bus *bus, int sw_addr)
+{
+	int ret;
+
+	ret = mdiobus_read(bus, REG_PORT(0), 0x03);
+	if (ret >= 0) {
+		ret &= 0xfff0;
+		if (ret == 0x1530)
+			return "Marvell 88E6063";
+	}
+
+	return NULL;
+}
+
+static int mv88e6063_switch_reset(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	/*
+	 * Set all ports to the disabled state.
+	 */
+	for (i = 0; i < NUM_PORTS; i++) {
+		ret = REG_READ(REG_PORT(i), 0x04);
+		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+	}
+
+	/*
+	 * Wait for transmit queues to drain.
+	 */
+	msleep(2);
+
+	/*
+	 * Reset the switch.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
+
+	/*
+	 * Wait up to one second for reset to complete.
+	 */
+	for (i = 0; i < 1000; i++) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		if ((ret & 0x8000) == 0x0000)
+			break;
+
+		msleep(1);
+	}
+	if (i == 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mv88e6063_setup_global(struct dsa_switch *ds)
+{
+	/*
+	 * Disable discarding of frames with excessive collisions,
+	 * set the maximum frame size to 1536 bytes, and mask all
+	 * interrupt sources.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
+
+	/*
+	 * Enable automatic address learning, set the address
+	 * database size to 1024 entries, and set the default aging
+	 * time to 5 minutes.
+	 */
+	REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
+
+	return 0;
+}
+
+static int mv88e6063_setup_port(struct dsa_switch *ds, int p)
+{
+	int addr = REG_PORT(p);
+
+	/*
+	 * Do not force flow control, disable Ingress and Egress
+	 * Header tagging, disable VLAN tunneling, and set the port
+	 * state to Forwarding.  Additionally, if this is the CPU
+	 * port, enable Ingress and Egress Trailer tagging mode.
+	 */
+	REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
+
+	/*
+	 * Port based VLAN map: give each port its own address
+	 * database, allow the CPU port to talk to each of the 'real'
+	 * ports, and allow each of the 'real' ports to only talk to
+	 * the CPU port.
+	 */
+	REG_WRITE(addr, 0x06,
+			((p & 0xf) << 12) |
+			 (dsa_is_cpu_port(ds, p) ?
+				ds->phys_port_mask :
+				(1 << ds->dst->cpu_port)));
+
+	/*
+	 * Port Association Vector: when learning source addresses
+	 * of packets, add the address to the address database using
+	 * a port bitmap that has only the bit for this port set and
+	 * the other bits clear.
+	 */
+	REG_WRITE(addr, 0x0b, 1 << p);
+
+	return 0;
+}
+
+static int mv88e6063_setup(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	ret = mv88e6063_switch_reset(ds);
+	if (ret < 0)
+		return ret;
+
+	/* @@@ initialise atu */
+
+	ret = mv88e6063_setup_global(ds);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < NUM_PORTS; i++) {
+		ret = mv88e6063_setup_port(ds, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mv88e6063_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+	REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
+	REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
+	REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
+
+	return 0;
+}
+
+static int mv88e6063_port_to_phy_addr(int port)
+{
+	if (port >= 0 && port <= NUM_PORTS)
+		return REG_PHY(port);
+	return -1;
+}
+
+static int mv88e6063_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	int addr;
+
+	addr = mv88e6063_port_to_phy_addr(port);
+	if (addr == -1)
+		return 0xffff;
+
+	return reg_read(ds, addr, regnum);
+}
+
+static int
+mv88e6063_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
+{
+	int addr;
+
+	addr = mv88e6063_port_to_phy_addr(port);
+	if (addr == -1)
+		return 0xffff;
+
+	return reg_write(ds, addr, regnum, val);
+}
+
+static void mv88e6063_poll_link(struct dsa_switch *ds)
+{
+	int i;
+
+	for (i = 0; i < DSA_MAX_PORTS; i++) {
+		struct net_device *dev;
+		int uninitialized_var(port_status);
+		int link;
+		int speed;
+		int duplex;
+		int fc;
+
+		dev = ds->ports[i];
+		if (dev == NULL)
+			continue;
+
+		link = 0;
+		if (dev->flags & IFF_UP) {
+			port_status = reg_read(ds, REG_PORT(i), 0x00);
+			if (port_status < 0)
+				continue;
+
+			link = !!(port_status & 0x1000);
+		}
+
+		if (!link) {
+			if (netif_carrier_ok(dev)) {
+				printk(KERN_INFO "%s: link down\n", dev->name);
+				netif_carrier_off(dev);
+			}
+			continue;
+		}
+
+		speed = (port_status & 0x0100) ? 100 : 10;
+		duplex = (port_status & 0x0200) ? 1 : 0;
+		fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
+
+		if (!netif_carrier_ok(dev)) {
+			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
+					 "flow control %sabled\n", dev->name,
+					 speed, duplex ? "full" : "half",
+					 fc ? "en" : "dis");
+			netif_carrier_on(dev);
+		}
+	}
+}
+
+static struct dsa_switch_driver mv88e6063_switch_driver = {
+	.tag_protocol	= htons(ETH_P_TRAILER),
+	.probe		= mv88e6063_probe,
+	.setup		= mv88e6063_setup,
+	.set_addr	= mv88e6063_set_addr,
+	.phy_read	= mv88e6063_phy_read,
+	.phy_write	= mv88e6063_phy_write,
+	.poll_link	= mv88e6063_poll_link,
+};
+
+static int __init mv88e6063_init(void)
+{
+	register_switch_driver(&mv88e6063_switch_driver);
+	return 0;
+}
+module_init(mv88e6063_init);
+
+static void __exit mv88e6063_cleanup(void)
+{
+	unregister_switch_driver(&mv88e6063_switch_driver);
+}
+module_exit(mv88e6063_cleanup);
diff --git a/target/linux/ar71xx/generic/config-default b/target/linux/ar71xx/generic/config-default
new file mode 100644
index 0000000000..45169689e0
--- /dev/null
+++ b/target/linux/ar71xx/generic/config-default
@@ -0,0 +1 @@
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2 noinitrd"
diff --git a/target/linux/ar71xx/generic/profiles/00-default.mk b/target/linux/ar71xx/generic/profiles/00-default.mk
new file mode 100644
index 0000000000..f5ebdd2dd8
--- /dev/null
+++ b/target/linux/ar71xx/generic/profiles/00-default.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Default
+	NAME:=Default Profile (all drivers)
+	PACKAGES:= \
+		kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+	PRIORITY := 1
+endef
+
+define Profile/Default/Description
+	Default package set compatible with most boards.
+endef
+$(eval $(call Profile,Default))
diff --git a/target/linux/ar71xx/generic/target.mk b/target/linux/ar71xx/generic/target.mk
new file mode 100644
index 0000000000..64eb205e4d
--- /dev/null
+++ b/target/linux/ar71xx/generic/target.mk
@@ -0,0 +1,8 @@
+BOARDNAME:=Generic
+FEATURES += squashfs
+
+define Target/Description
+	Build firmware images for generic Atheros AR71xx/AR913x/AR934x based boards.
+endef
+
+
diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile
new file mode 100644
index 0000000000..a87811362b
--- /dev/null
+++ b/target/linux/ar71xx/image/Makefile
@@ -0,0 +1,109 @@
+#
+# Copyright (C) 2008-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+KERNEL_LOADADDR = 0x80060000
+
+DEVICE_VARS += NETGEAR_KERNEL_MAGIC NETGEAR_BOARD_ID NETGEAR_HW_ID CMDLINE CONSOLE IMAGE_SIZE BOARDNAME LOADER_FLASH_OFFS LOADER_TYPE
+
+ifeq ($(SUBTARGET),generic)
+include ./tp-link.mk
+include ./generic.mk
+include ./legacy-devices.mk
+endif
+ifeq ($(SUBTARGET),nand)
+include ./nand.mk
+endif
+include ./legacy.mk
+
+define Build/netgear-squashfs
+	rm -rf $@.fs $@.squashfs
+	mkdir -p $@.fs/image
+	cp $@ $@.fs/image/uImage
+	$(STAGING_DIR_HOST)/bin/mksquashfs-lzma \
+		$@.fs $@.squashfs \
+		-noappend -root-owned -be -b 65536 \
+		$(if $(SOURCE_DATE_EPOCH),-fixed-time $(SOURCE_DATE_EPOCH))
+
+	dd if=/dev/zero bs=1k count=1 >> $@.squashfs
+	mkimage \
+		-A mips -O linux -T filesystem -C none \
+		-M $(NETGEAR_KERNEL_MAGIC) \
+		-a 0xbf070000 -e 0xbf070000 \
+		-n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+		-d $@.squashfs $@
+	rm -rf $@.squashfs $@.fs
+endef
+
+define Build/netgear-uImage
+	$(call Build/uImage,$(1) -M $(NETGEAR_KERNEL_MAGIC))
+endef
+
+define Build/loader-common
+	rm -rf $@.src
+	$(MAKE) -C lzma-loader \
+		PKG_BUILD_DIR="$@.src" \
+		TARGET_DIR="$(dir $@)" LOADER_NAME="$(notdir $@)" \
+		BOARD="$(BOARDNAME)" \
+		LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
+		$(1) compile loader.$(LOADER_TYPE)
+	mv "$@.$(LOADER_TYPE)" "$@"
+	rm -rf $@.src
+endef
+
+define Build/loader-okli-compile
+	$(call Build/loader-common,FLASH_OFFS=$(LOADER_FLASH_OFFS) FLASH_MAX=0 KERNEL_CMDLINE="$(CMDLINE)")
+endef
+
+define Build/loader-kernel
+	$(call Build/loader-common,LOADER_DATA="$@")
+endef
+
+define Build/loader-kernel-cmdline
+	$(call Build/loader-common,LOADER_DATA="$@" KERNEL_CMDLINE="$(CMDLINE)")
+endef
+
+define Build/loader-okli
+	dd if=$(KDIR)/loader-$(1).gz bs=7680 conv=sync of="$@.new"
+	cat "$@" >> "$@.new"
+	mv "$@.new" "$@"
+endef
+
+define Build/relocate-kernel
+	rm -rf $@.relocate
+	$(CP) ../../generic/image/relocate $@.relocate
+	$(MAKE) -j1 -C $@.relocate KERNEL_ADDR=$(KERNEL_LOADADDR) CROSS_COMPILE=$(TARGET_CROSS)
+	( \
+		dd if=$@.relocate/loader.bin bs=32 conv=sync && \
+		perl -e '@s = stat("$@"); print pack("N", @s[7])' && \
+		cat "$@" \
+	) > "$@.new"
+	mv "$@.new" "$@"
+	rm -rf $@.relocate
+endef
+
+define Build/copy-file
+	cat "$(1)" > "$@"
+endef
+
+define Device/Default
+  BOARDNAME :=
+  DEVICE_PROFILE = $$(BOARDNAME)
+  PROFILES = Default Minimal $$(DEVICE_PROFILE)
+  MTDPARTS :=
+  BLOCKSIZE := 64k
+  CONSOLE = ttyS0,115200
+  CMDLINE = $$(if $$(BOARDNAME),board=$$(BOARDNAME)) $$(if $$(MTDPARTS),mtdparts=$$(MTDPARTS)) $$(if $$(CONSOLE),console=$$(CONSOLE))
+  KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma
+  COMPILE :=
+  IMAGES := sysupgrade.bin
+  IMAGE/sysupgrade.bin = append-kernel | pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/ar71xx/image/generic.mk b/target/linux/ar71xx/image/generic.mk
new file mode 100644
index 0000000000..16a4001a29
--- /dev/null
+++ b/target/linux/ar71xx/image/generic.mk
@@ -0,0 +1,612 @@
+define Device/ap90q
+  DEVICE_TITLE := YunCore AP90Q
+  BOARDNAME = AP90Q
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env),16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += ap90q
+
+define Device/bsb
+  DEVICE_TITLE := Smart Electronics Black Swift board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = BSB
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyATH0,115200
+  MTDPARTS = spi0.0:128k(u-boot)ro,64k(u-boot-env)ro,16128k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += bsb
+
+define Device/carambola2
+  DEVICE_TITLE := Carambola2 board from 8Devices
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = CARAMBOLA2
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyATH0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += carambola2
+
+define Device/cf-e316n-v2
+  DEVICE_TITLE := COMFAST CF-E316N v2
+  BOARDNAME = CF-E316N-V2
+  IMAGE_SIZE = 16192k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = spi0.0:64k(u-boot)ro,64k(art)ro,16192k(firmware),64k(art-backup)ro
+endef
+TARGET_DEVICES += cf-e316n-v2
+
+define Device/cf-e320n-v2
+  $(Device/cf-e316n-v2)
+  DEVICE_TITLE := COMFAST CF-E320N v2
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = CF-E320N-V2
+endef
+TARGET_DEVICES += cf-e320n-v2
+
+define Device/cf-e380ac-v2
+  $(Device/cf-e380ac-v1)
+  DEVICE_TITLE := COMFAST CF-E380AC v2
+  BOARDNAME = CF-E380AC-V2
+  IMAGE_SIZE = 16000k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(art)ro,16000k(firmware),64k(art-backup)ro
+endef
+TARGET_DEVICES += cf-e380ac-v2
+
+define Device/cf-e520n
+  DEVICE_TITLE := COMFAST CF-E520N
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = CF-E520N
+  IMAGE_SIZE = 8000k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = spi0.0:64k(u-boot)ro,64k(art)ro,8000k(firmware),64k(art-backup)ro
+endef
+TARGET_DEVICES += cf-e520n
+
+define Device/cf-e530n
+  $(Device/cf-e520n)
+  DEVICE_TITLE := COMFAST CF-E530N
+  BOARDNAME = CF-E530N
+endef
+TARGET_DEVICES += cf-e530n
+
+define Device/cpe830
+  $(Device/ap90q)
+  DEVICE_TITLE := YunCore CPE830
+  DEVICE_PACKAGES := rssileds
+  BOARDNAME = CPE830
+endef
+TARGET_DEVICES += cpe830
+
+define Device/cpe870
+  DEVICE_TITLE := YunCore CPE870
+  DEVICE_PACKAGES := rssileds
+  BOARDNAME = CPE870
+  IMAGE_SIZE = 7936k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = spi0.0:64k(u-boot)ro,64k(u-boot-env),7936k(firmware),64k(config)ro,64k(art)ro
+endef
+TARGET_DEVICES += cpe870
+
+define Device/dragino2
+  BOARDNAME := DRAGINO2
+  CONSOLE := ttyATH0,115200
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+  DEVICE_TITLE := Dragino 2 (MS14)
+  IMAGE_SIZE := 16000k
+  MTDPARTS := spi0.0:256k(u-boot)ro,16000k(firmware),64k(config)ro,64k(art)ro
+endef
+TARGET_DEVICES += dragino2
+
+define Device/weio
+  DEVICE_TITLE := WeIO
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = WEIO
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyATH0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += weio
+
+define Device/gl-ar150
+  DEVICE_TITLE := GL AR150
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = GL-AR150
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyATH0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-ar150
+
+define Device/gl-ar300
+  DEVICE_TITLE := GL AR300
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = GL-AR300
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-ar300
+
+define Device/gl-ar300m
+  DEVICE_TITLE := GL AR300M
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 uboot-envtools
+  BOARDNAME = GL-AR300M
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env),16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-ar300m
+
+define Device/gl-domino
+  DEVICE_TITLE := GL Domino Pi
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = DOMINO
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyATH0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-domino
+
+define Device/gl-mifi
+  DEVICE_TITLE := GL MIFI
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = GL-MIFI
+  IMAGE_SIZE = 16000k
+  CONSOLE = ttyATH0,115200
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += gl-mifi
+
+define Device/mr12
+  DEVICE_TITLE := Meraki MR12
+  DEVICE_PACKAGES := kmod-spi-gpio
+  BOARDNAME = MR12
+  IMAGE_SIZE = 15680k
+  MTDPARTS = spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13440k(rootfs),2240k(kernel),64k(mac),128k(art)ro,15680k@0x80000(firmware)
+  IMAGE/kernel.bin = append-kernel
+  IMAGE/rootfs.bin = append-rootfs | pad-rootfs
+  IMAGE/sysupgrade.bin = append-rootfs | pad-rootfs | pad-to 13440k | append-kernel | check-size $$$$(IMAGE_SIZE)
+  IMAGES := kernel.bin rootfs.bin sysupgrade.bin
+endef
+TARGET_DEVICES += mr12
+
+define Device/mr16
+  DEVICE_TITLE := Meraki MR16
+  DEVICE_PACKAGES := kmod-spi-gpio
+  BOARDNAME = MR16
+  IMAGE_SIZE = 15680k
+  MTDPARTS = spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13440k(rootfs),2240k(kernel),64k(mac),128k(art)ro,15680k@0x80000(firmware)
+  IMAGE/kernel.bin = append-kernel
+  IMAGE/rootfs.bin = append-rootfs | pad-rootfs
+  IMAGE/sysupgrade.bin = append-rootfs | pad-rootfs | pad-to 13440k | append-kernel | check-size $$$$(IMAGE_SIZE)
+  IMAGES := kernel.bin rootfs.bin sysupgrade.bin
+endef
+TARGET_DEVICES += mr16
+
+define Device/dr531
+  DEVICE_TITLE := Wallys DR531
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = DR531
+  IMAGE_SIZE = 7808k
+  MTDPARTS = spi0.0:192k(u-boot)ro,64k(u-boot-env),64k(partition-table)ro,7808k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += dr531
+
+define Device/wndr3700
+  DEVICE_TITLE := NETGEAR WNDR3700
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport kmod-leds-wndr3700-usb
+  BOARDNAME = WNDR3700
+  NETGEAR_KERNEL_MAGIC = 0x33373030
+  NETGEAR_BOARD_ID = WNDR3700
+  IMAGE_SIZE = 7680k
+  MTDPARTS = spi0.0:320k(u-boot)ro,128k(u-boot-env)ro,7680k(firmware),64k(art)ro
+  IMAGES := sysupgrade.bin factory.img factory-NA.img
+  KERNEL := kernel-bin | patch-cmdline | lzma -d20 | netgear-uImage lzma
+  IMAGE/default = append-kernel | pad-to $$$$(BLOCKSIZE) | netgear-squashfs | append-rootfs | pad-rootfs
+  IMAGE/sysupgrade.bin = $$(IMAGE/default) | check-size $$$$(IMAGE_SIZE)
+  IMAGE/factory.img = $$(IMAGE/default) | netgear-dni | check-size $$$$(IMAGE_SIZE)
+  IMAGE/factory-NA.img = $$(IMAGE/default) | netgear-dni NA | check-size $$$$(IMAGE_SIZE)
+endef
+
+define Device/wndr3700v2
+$(Device/wndr3700)
+  DEVICE_TITLE := NETGEAR WNDR3700 v2
+  NETGEAR_BOARD_ID = WNDR3700v2
+  NETGEAR_KERNEL_MAGIC = 0x33373031
+  NETGEAR_HW_ID = 29763654+16+64
+  IMAGE_SIZE = 15872k
+  MTDPARTS = spi0.0:320k(u-boot)ro,128k(u-boot-env)ro,15872k(firmware),64k(art)ro
+  IMAGES := sysupgrade.bin factory.img
+endef
+
+define Device/wndr3800
+$(Device/wndr3700v2)
+  DEVICE_TITLE := NETGEAR WNDR3800
+  NETGEAR_BOARD_ID = WNDR3800
+  NETGEAR_HW_ID = 29763654+16+128
+endef
+
+define Device/wndr3800ch
+$(Device/wndr3800)
+  DEVICE_TITLE := NETGEAR WNDR3800 (Ch)
+  NETGEAR_BOARD_ID = WNDR3800CH
+endef
+
+define Device/wndrmac
+$(Device/wndr3700v2)
+  DEVICE_TITLE := NETGEAR WNDRMAC
+  NETGEAR_BOARD_ID = WNDRMAC
+endef
+
+define Device/wndrmacv2
+$(Device/wndr3800)
+  DEVICE_TITLE := NETGEAR WNDRMAC v2
+  NETGEAR_BOARD_ID = WNDRMACv2
+endef
+
+TARGET_DEVICES += wndr3700 wndr3700v2 wndr3800 wndr3800ch wndrmac wndrmacv2
+
+define Device/cap324
+  DEVICE_TITLE := PowerCloud CAP324 Cloud AP
+  DEVICE_PACKAGES := uboot-envtools
+  BOARDNAME := CAP324
+  DEVICE_PROFILE := CAP324
+  IMAGE_SIZE = 15296k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,15296k(firmware),640k(certs),64k(nvram),64k(art)ro
+endef
+
+TARGET_DEVICES += cap324
+
+define Device/cap324-nocloud
+  DEVICE_TITLE := PowerCloud CAP324 Cloud AP (No-Cloud)
+  DEVICE_PACKAGES := uboot-envtools
+  BOARDNAME := CAP324
+  DEVICE_PROFILE := CAP324
+  IMAGE_SIZE = 16000k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,16000k(firmware),64k(art)ro
+endef
+
+TARGET_DEVICES += cap324-nocloud
+
+define Device/cr3000
+  DEVICE_TITLE := PowerCloud CR3000 Cloud Router
+  DEVICE_PACKAGES := uboot-envtools
+  BOARDNAME := CR3000
+  DEVICE_PROFILE := CR3000
+  IMAGE_SIZE = 7104k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7104k(firmware),640k(certs),64k(nvram),64k(art)ro
+endef
+
+TARGET_DEVICES += cr3000
+
+define Device/cr3000-nocloud
+  DEVICE_TITLE := PowerCloud CR3000 (No-Cloud)
+  DEVICE_PACKAGES := uboot-envtools
+  BOARDNAME := CR3000
+  DEVICE_PROFILE := CR3000
+  IMAGE_SIZE = 7808k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7808k(firmware),64k(art)ro
+endef
+
+TARGET_DEVICES += cr3000-nocloud
+
+define Device/cr5000
+  DEVICE_TITLE := PowerCloud CR5000 Cloud Router
+  DEVICE_PACKAGES := uboot-envtools kmod-usb2 kmod-usb-ohci kmod-usb-ledtrig-usbport kmod-usb-core
+  BOARDNAME := CR5000
+  DEVICE_PROFILE := CR5000
+  IMAGE_SIZE = 7104k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7104k(firmware),640k(certs),64k(nvram),64k(art)ro
+endef
+
+TARGET_DEVICES += cr5000
+
+define Device/cr5000-nocloud
+  DEVICE_TITLE := PowerCloud CR5000 (No-Cloud)
+  DEVICE_PACKAGES := uboot-envtools kmod-usb2 kmod-usb-ohci kmod-usb-ledtrig-usbport kmod-usb-core
+  BOARDNAME := CR5000
+  DEVICE_PROFILE := CR5000
+  IMAGE_SIZE = 7808k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7808k(firmware),64k(art)ro
+endef
+
+TARGET_DEVICES += cr5000-nocloud
+
+define Device/antminer-s1
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := Antminer-S1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-crypto-manager kmod-i2c-gpio-custom kmod-usb-hid
+  BOARDNAME := ANTMINER-S1
+  DEVICE_PROFILE := ANTMINERS1
+  TPLINK_HWID := 0x04440101
+  CONSOLE := ttyATH0,115200
+endef
+
+define Device/antminer-s3
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := Antminer-S3
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-crypto-manager kmod-i2c-gpio-custom kmod-usb-hid
+  BOARDNAME := ANTMINER-S3
+  DEVICE_PROFILE := ANTMINERS3
+  TPLINK_HWID := 0x04440301
+  CONSOLE := ttyATH0,115200
+endef
+
+define Device/antrouter-r1
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := Antrouter-R1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME := ANTROUTER-R1
+  DEVICE_PROFILE := ANTROUTERR1
+  TPLINK_HWID := 0x44440101
+  CONSOLE := ttyATH0,115200
+endef
+
+define Device/el-m150
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := EasyLink EL-M150
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME := EL-M150
+  DEVICE_PROFILE := ELM150
+  TPLINK_HWID := 0x01500101
+  CONSOLE := ttyATH0,115200
+endef
+
+define Device/el-mini
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := EasyLink EL-MINI
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME := EL-MINI
+  DEVICE_PROFILE := ELMINI
+  TPLINK_HWID := 0x01530001
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += antminer-s1 antminer-s3 antrouter-r1 el-m150 el-mini
+
+define Device/gl-inet-6408A-v1
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := GL.iNet 6408
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME := GL-INET
+  DEVICE_PROFILE := GLINET
+  TPLINK_HWID := 0x08000001
+  CONSOLE := ttyATH0,115200
+endef
+
+define Device/gl-inet-6416A-v1
+  $(Device/tplink-16mlzma)
+  DEVICE_TITLE := GL.iNet 6416
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME := GL-INET
+  DEVICE_PROFILE := GLINET
+  TPLINK_HWID := 0x08000001
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += gl-inet-6408A-v1 gl-inet-6416A-v1
+
+define Device/jwap230
+  DEVICE_TITLE := jjPlus JWAP230
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = JWAP230
+  IMAGE_SIZE = 16000k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env),16000k(firmware),64k(art)ro
+endef
+TARGET_DEVICES += jwap230
+
+define Device/rnx-n360rt
+  $(Device/tplink-4m)
+  DEVICE_TITLE := Rosewill RNX-N360RT
+  BOARDNAME := TL-WR941ND
+  DEVICE_PROFILE := RNXN360RT
+  TPLINK_HWID := 0x09410002
+  TPLINK_HWREV := 0x00420001
+endef
+TARGET_DEVICES += rnx-n360rt
+
+define Device/minibox-v1
+  $(Device/tplink-16mlzma)
+  DEVICE_TITLE := Gainstrong MiniBox V1.0
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2  kmod-usb-ledtrig-usbport
+  BOARDNAME := MINIBOX-V1
+  DEVICE_PROFILE := MINIBOXV1
+  TPLINK_HWID := 0x3C000201
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += minibox-v1
+
+define Device/omy-g1
+  $(Device/tplink-16mlzma)
+  DEVICE_TITLE := OMYlink OMY-G1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME := OMY-G1
+  DEVICE_PROFILE := OMYG1
+  TPLINK_HWID := 0x06660101
+endef
+
+define Device/omy-x1
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := OMYlink OMY-X1
+  BOARDNAME := OMY-X1
+  DEVICE_PROFILE := OMYX1
+  TPLINK_HWID := 0x06660201
+endef
+TARGET_DEVICES += omy-g1 omy-x1
+
+define Device/onion-omega
+  $(Device/tplink-16mlzma)
+  DEVICE_TITLE := Onion Omega
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage kmod-i2c-core kmod-i2c-gpio-custom kmod-spi-bitbang kmod-spi-dev kmod-spi-gpio kmod-spi-gpio-custom kmod-usb-serial
+  BOARDNAME := ONION-OMEGA
+  DEVICE_PROFILE := OMEGA
+  TPLINK_HWID := 0x04700001
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += onion-omega
+
+define Device/smart-300
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := NC-LINK SMART-300
+  BOARDNAME := SMART-300
+  DEVICE_PROFILE := SMART-300
+  TPLINK_HWID := 0x93410001
+endef
+TARGET_DEVICES += smart-300
+
+define Device/som9331
+  $(Device/tplink-8mlzma)
+  DEVICE_TITLE := OpenEmbed SOM9331
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage kmod-i2c-core kmod-i2c-gpio-custom kmod-spi-bitbang kmod-spi-dev kmod-spi-gpio kmod-spi-gpio-custom kmod-usb-serial
+  BOARDNAME := SOM9331
+  DEVICE_PROFILE := SOM9331
+  TPLINK_HWID := 0x04800054
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += som9331
+
+define Device/tellstick-znet-lite
+  $(Device/tplink-16mlzma)
+  DEVICE_TITLE := TellStick ZNet Lite
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-acm kmod-usb-serial kmod-usb-serial-pl2303
+  BOARDNAME := TELLSTICK-ZNET-LITE
+  DEVICE_PROFILE := TELLSTICKZNETLITE
+  TPLINK_HWID := 0x00726001
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tellstick-znet-lite
+
+define Device/oolite
+  $(Device/tplink-16mlzma)
+  DEVICE_TITLE := Gainstrong OOLITE
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME := GS-OOLITE
+  DEVICE_PROFILE := OOLITE
+  TPLINK_HWID := 0x3C000101
+  CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += oolite
+
+
+define Device/c-55
+  DEVICE_TITLE := AirTight Networks C-55
+  DEVICE_PACKAGES := kmod-ath9k
+  BOARDNAME = C-55
+  KERNEL_SIZE = 2048k
+  IMAGE_SIZE = 15872k
+  MTDPARTS = spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,2048k(kernel),13824k(rootfs),13824k(opt)ro,2624k(failsafe)ro,64k(art)ro,15872k@0x60000(firmware)
+  IMAGE/sysupgrade.bin = append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE)
+endef
+
+TARGET_DEVICES += c-55
+
+
+define Build/uImageHiWiFi
+	# Field ih_name needs to start with "tw150v1"
+	mkimage -A $(LINUX_KARCH) \
+		-O linux -T kernel \
+		-C $(1) -a $(KERNEL_LOADADDR) -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
+		-n 'tw150v1 $(call toupper,$(LINUX_KARCH)) LEDE Linux-$(LINUX_VERSION)' -d $@ $@.new
+	@mv $@.new $@
+endef
+
+define Device/hiwifi-hc6361
+  DEVICE_TITLE := HiWiFi HC6361
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage \
+	kmod-fs-ext4 kmod-nls-iso8859-1 e2fsprogs
+  BOARDNAME := HiWiFi-HC6361
+  DEVICE_PROFILE := HIWIFI_HC6361
+  IMAGE_SIZE := 16128k
+  KERNEL := kernel-bin | patch-cmdline | lzma | uImageHiWiFi lzma
+  CONSOLE := ttyATH0,115200
+  MTDPARTS := spi0.0:64k(u-boot)ro,64k(bdinfo)ro,16128k(firmware),64k(backup)ro,64k(art)ro
+endef
+TARGET_DEVICES += hiwifi-hc6361
+
+
+define Build/seama
+	$(STAGING_DIR_HOST)/bin/seama -i $@ $(if $(1),$(1),-m "dev=/dev/mtdblock/1" -m "type=firmware")
+	mv $@.seama $@
+endef
+
+define Build/seama-seal
+	$(call Build/seama,-s $@.seama $(1))
+endef
+
+define Device/seama
+  CONSOLE := ttyS0,115200
+  LOADER_TYPE := bin
+  BLOCKSIZE := 64k
+  KERNEL := kernel-bin | patch-cmdline | relocate-kernel | lzma
+  KERNEL_INITRAMFS := kernel-bin | patch-cmdline | lzma | seama
+  KERNEL_INITRAMFS_SUFFIX = $$(KERNEL_SUFFIX).seama
+  IMAGES := sysupgrade.bin factory.bin
+
+  # 64 bytes offset:
+  # - 28 bytes seama_header
+  # - 36 bytes of META data (4-bytes aligned)
+  IMAGE/default := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-rootfs
+  IMAGE/sysupgrade.bin := \
+	$$(IMAGE/default) | seama | pad-rootfs | \
+	check-size $$$$(IMAGE_SIZE)
+  IMAGE/factory.bin := \
+	$$(IMAGE/default) | seama | pad-rootfs | \
+	seama-seal -m "signature=$$$$(SEAMA_SIGNATURE)" | \
+	check-size $$$$(IMAGE_SIZE)
+  SEAMA_SIGNATURE :=
+  DEVICE_VARS += SEAMA_SIGNATURE
+endef
+
+define Device/mynet-n600
+$(Device/seama)
+  DEVICE_TITLE := Western Digital My Net N600
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = MYNET-N600
+  IMAGE_SIZE = 15808k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(devdata)ro,64k(devconf)ro,15872k(firmware),64k(radiocfg)ro
+  SEAMA_SIGNATURE := wrgnd16_wd_db600
+endef
+
+define Device/mynet-n750
+$(Device/seama)
+  DEVICE_TITLE := Western Digital My Net N750
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+  BOARDNAME = MYNET-N750
+  IMAGE_SIZE = 15808k
+  MTDPARTS = spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(devdata)ro,64k(devconf)ro,15872k(firmware),64k(radiocfg)ro
+  SEAMA_SIGNATURE := wrgnd13_wd_av
+endef
+
+TARGET_DEVICES += dir-869-a1 mynet-n600 mynet-n750
+
+define Build/mkwrggimg
+	$(STAGING_DIR_HOST)/bin/mkwrggimg -b \
+		-i $@ -o $@.imghdr -d /dev/mtdblock/1 \
+		-m $(BOARDNAME) -s $(DAP_SIGNATURE) \
+		-v LEDE -B $(REVISION)
+	mv $@.imghdr $@
+endef
+
+define Build/wrgg-pad-rootfs
+	$(STAGING_DIR_HOST)/bin/padjffs2 $(IMAGE_ROOTFS) -c 64 >>$@
+endef
+
+define Build/mkbuffaloimg
+	$(STAGING_DIR_HOST)/bin/mkbuffaloimg -B $(BOARDNAME) \
+		-R $$(($(subst k, * 1024,$(ROOTFS_SIZE)))) \
+		-K $$(($(subst k, * 1024,$(KERNEL_SIZE)))) \
+		-i $@ -o $@.new
+	mv $@.new $@
+endef
+
+define Device/bhr-4grv2
+  DEVICE_TITLE := Buffalo BHR-4GRV2
+  BOARDNAME := BHR-4GRV2
+  ROOTFS_SIZE := 14528k
+  KERNEL_SIZE := 1472k
+  IMAGE_SIZE := 16000k
+  MTDPARTS := spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+  IMAGES := sysupgrade.bin factory.bin
+  IMAGE/sysupgrade.bin = append-rootfs | pad-rootfs | pad-to $$$$(ROOTFS_SIZE) | append-kernel | check-size $$$$(IMAGE_SIZE)
+  IMAGE/factory.bin = append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | mkbuffaloimg
+endef
+TARGET_DEVICES += bhr-4grv2
diff --git a/target/linux/ar71xx/image/legacy-devices.mk b/target/linux/ar71xx/image/legacy-devices.mk
new file mode 100644
index 0000000000..36a6d8d2c8
--- /dev/null
+++ b/target/linux/ar71xx/image/legacy-devices.mk
@@ -0,0 +1,611 @@
+define LegacyDevice/ALFANX
+  DEVICE_TITLE := ALFA Network N2/N5 board
+endef
+LEGACY_DEVICES += ALFANX
+
+define LegacyDevice/HORNETUB
+  DEVICE_TITLE := ALFA Network Hornet-UB board (8MB flash, 32MB ram)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += HORNETUB
+
+define LegacyDevice/TUBE2H8M
+  DEVICE_TITLE := ALFA Network Tube2H board (8MB flash)
+endef
+LEGACY_DEVICES += TUBE2H8M
+
+define LegacyDevice/AP81
+  DEVICE_TITLE := Atheros AP81 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += AP81
+
+define LegacyDevice/AP83
+  DEVICE_TITLE := Atheros AP83 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 \
+	  vsc7385-ucode-ap83 vsc7395-ucode-ap83
+endef
+LEGACY_DEVICES += AP83
+
+define LegacyDevice/AP96
+  DEVICE_TITLE := Atheros AP96 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += AP96
+
+define LegacyDevice/WNDAP360
+  DEVICE_TITLE := NETGEAR WNDAP360
+endef
+LEGACY_DEVICES += WNDAP360
+
+define LegacyDevice/ALFAAP120C
+  DEVICE_TITLE := ALFA Network AP120C board
+endef
+LEGACY_DEVICES += ALFAAP120C
+
+define LegacyDevice/ALFAAP96
+  DEVICE_TITLE := ALFA Network AP96 board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-rtc-pcf2123
+endef
+LEGACY_DEVICES += ALFAAP96
+
+define LegacyDevice/ALL0258N
+  DEVICE_TITLE := Allnet ALL0258N
+  DEVICE_PACKAGES := rssileds
+endef
+LEGACY_DEVICES += ALL0258N
+
+define LegacyDevice/ALL0315N
+  DEVICE_TITLE := Allnet ALL0315N
+  DEVICE_PACKAGES := rssileds
+endef
+LEGACY_DEVICES += ALL0315N
+
+define LegacyDevice/AP121_8M
+  DEVICE_TITLE := Atheros AP121 reference board (8MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += AP121_8M
+
+define LegacyDevice/AP121_16M
+  DEVICE_TITLE := Atheros AP121 reference board (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += AP121_16M
+
+define LegacyDevice/AP132
+  DEVICE_TITLE := Atheros AP132 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP132
+
+define LegacyDevice/AP135
+  DEVICE_TITLE := Atheros AP135 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP135
+
+define LegacyDevice/AP136_010
+  DEVICE_TITLE := Atheros AP136-010 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP136_010
+
+define LegacyDevice/AP136_020
+  DEVICE_TITLE := Atheros AP136-020 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP136_020
+
+define LegacyDevice/AP143_8M
+  DEVICE_TITLE := Qualcomm Atheros AP143 reference board (8MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP143_8M
+
+define LegacyDevice/AP143_16M
+  DEVICE_TITLE := Qualcomm Atheros AP143 reference board (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP143_16M
+
+define LegacyDevice/AP147_010
+  DEVICE_TITLE := Qualcomm Atheros AP147-010 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP147_010
+
+define LegacyDevice/AP152_16M
+  DEVICE_TITLE := Qualcomm Atheros AP152 reference board (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += AP152_16M
+
+define LegacyDevice/BXU2000N2
+  DEVICE_TITLE := BHU BXU2000n-2
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += BXU2000N2
+
+define LegacyDevice/CAP4200AG
+  DEVICE_TITLE := Senao CAP4200AG
+endef
+LEGACY_DEVICES += CAP4200AG
+
+define LegacyDevice/DB120
+  DEVICE_TITLE := Atheros DB120 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += DB120
+
+define LegacyDevice/EWDORINAP
+  DEVICE_TITLE := Embedded Wireless Dorin Platform (4MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport kmod-usb-storage
+endef
+LEGACY_DEVICES += EWDORINAP
+
+define LegacyDevice/EWDORINRT
+  DEVICE_TITLE := Embedded Wireless Dorin Router
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport kmod-usb-storage
+endef
+LEGACY_DEVICES += EWDORINRT
+
+define LegacyDevice/EWDORIN16M
+  DEVICE_TITLE := Embedded Wireless Dorin Platform (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport kmod-usb-storage
+endef
+LEGACY_DEVICES += EWDORIN16M
+
+define LegacyDevice/HORNETUBx2
+  DEVICE_TITLE := ALFA Network Hornet-UB-x2 board (16MB flash, 64MB ram)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += HORNETUBx2
+
+define LegacyDevice/TUBE2H16M
+  DEVICE_TITLE := ALFA Network Tube2H board (16MB flash)
+endef
+LEGACY_DEVICES += TUBE2H16M
+
+define LegacyDevice/WLR8100
+  DEVICE_TITLE := Sitecom WLR-8100
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport kmod-usb3
+endef
+LEGACY_DEVICES += WLR8100
+
+define LegacyDevice/WPJ342_16M
+  DEVICE_TITLE := Compex WPJ342 (16MB flash)
+endef
+LEGACY_DEVICES += WPJ342_16M
+
+define LegacyDevice/WPJ344_16M
+  DEVICE_TITLE := Compex WPJ344 (16MB flash)
+endef
+LEGACY_DEVICES += WPJ344_16M
+
+define LegacyDevice/DR344
+  DEVICE_TITLE := Wallys DR344
+endef
+LEGACY_DEVICES += DR344
+
+define LegacyDevice/WPJ531_16M
+  DEVICE_TITLE := Compex WPJ531 (16MB flash)
+endef
+LEGACY_DEVICES += WPJ531_16M
+
+define LegacyDevice/WPJ558_16M
+  DEVICE_TITLE := Compex WPJ558 (16MB flash)
+endef
+LEGACY_DEVICES += WPJ558_16M
+
+define LegacyDevice/WRTNODE2Q
+  DEVICE_TITLE := WRTnode2Q board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-storage
+endef
+LEGACY_DEVICES += WRTNODE2Q
+
+define LegacyDevice/YUN_8M
+  DEVICE_TITLE := Arduino Yun based on Atheros AR9331 (8MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += YUN_8M
+
+define LegacyDevice/YUN_16M
+  DEVICE_TITLE := Arduino Yun based on Atheros AR9331 (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += YUN_16M
+
+define LegacyDevice/DIR600A1
+  DEVICE_TITLE := D-Link DIR-600 rev. A1
+endef
+LEGACY_DEVICES += DIR600A1
+
+define LegacyDevice/DIR601A1
+  DEVICE_TITLE := D-Link DIR-601 rev. A1
+endef
+LEGACY_DEVICES += DIR601A1
+
+define LegacyDevice/FR54RTR
+  DEVICE_TITLE := Frys FR-54RTR
+endef
+LEGACY_DEVICES += FR54RTR
+
+define LegacyDevice/DIR615E1
+  DEVICE_TITLE := D-Link DIR-615 rev. E1
+endef
+LEGACY_DEVICES += DIR615E1
+
+define LegacyDevice/DIR615E4
+  DEVICE_TITLE := D-Link DIR-615 rev. E4
+endef
+LEGACY_DEVICES += DIR615E4
+
+define LegacyDevice/DIR615I1
+  DEVICE_TITLE := D-Link DIR-615 rev. I1
+endef
+LEGACY_DEVICES += DIR615I1
+
+define LegacyDevice/DIR615I3
+  DEVICE_TITLE := D-Link DIR-615 rev. I3
+endef
+LEGACY_DEVICES += DIR615I3
+
+define LegacyDevice/A02RBW300N
+  DEVICE_TITLE := Atlantis-Land A02-RB-W300N
+endef
+LEGACY_DEVICES += A02RBW300N
+
+define LegacyDevice/DIR615C1
+  DEVICE_TITLE := D-Link DIR-615 rev. C1
+endef
+LEGACY_DEVICES += DIR615C1
+
+define LegacyDevice/TEW632BRP
+  DEVICE_TITLE := TRENDNet TEW-632BRP
+endef
+LEGACY_DEVICES += TEW632BRP
+
+define LegacyDevice/TEW652BRP_FW
+  DEVICE_TITLE := TRENDNet TEW-652BRP
+endef
+LEGACY_DEVICES += TEW652BRP_FW
+
+define LegacyDevice/TEW652BRP_RECOVERY
+  DEVICE_TITLE := TRENDNet TEW-652BRP (recovery)
+endef
+LEGACY_DEVICES += TEW652BRP_RECOVERY
+
+define LegacyDevice/TEW712BR
+  DEVICE_TITLE := TRENDNet TEW-712BR
+endef
+LEGACY_DEVICES += TEW712BR
+
+define LegacyDevice/DIR601B1
+  DEVICE_TITLE := D-Link DIR-601 rev. B1
+endef
+LEGACY_DEVICES += DIR601B1
+
+define LegacyDevice/DIR505A1
+  DEVICE_TITLE := D-Link DIR-505 rev. A1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += DIR505A1
+
+define LegacyDevice/DGL5500A1
+  DEVICE_TITLE := D-Link DGL-5500 rev. A1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += DGL5500A1
+
+define LegacyDevice/DHP1565A1
+  DEVICE_TITLE := D-Link DHP-1565 rev. A1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += DHP1565A1
+
+define LegacyDevice/DIR825C1
+  DEVICE_TITLE := D-Link DIR-825 rev. C1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += DIR825C1
+
+define LegacyDevice/DIR835A1
+  DEVICE_TITLE := D-Link DIR-835 rev. A1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += DIR835A1
+
+define LegacyDevice/TEW732BR
+  DEVICE_TITLE := TRENDNet TEW-732BR
+endef
+LEGACY_DEVICES += TEW732BR
+
+define LegacyDevice/WRT160NL
+  DEVICE_TITLE := Linksys WRT160NL
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += WRT160NL
+
+define LegacyDevice/MYNETREXT
+  DEVICE_TITLE := WD My Net Wi-Fi Range Extender
+  DEVICE_PACKAGES := rssileds
+endef
+LEGACY_DEVICES += MYNETREXT
+
+define LegacyDevice/DIR825B1
+  DEVICE_TITLE := D-Link DIR-825 rev. B1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += DIR825B1
+
+define LegacyDevice/TEW673GRU
+  DEVICE_TITLE := TRENDNet TEW-673GRU
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += TEW673GRU
+
+define LegacyDevice/DLRTDEV01
+  DEVICE_TITLE := PowerCloud Systems dlrtdev01 model
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += DLRTDEV01
+
+define LegacyDevice/dLAN_Hotspot
+  DEVICE_TITLE := devolo dLAN Hotspot
+endef
+LEGACY_DEVICES += dLAN_Hotspot
+
+define LegacyDevice/dLAN_pro_500_wp
+  DEVICE_TITLE := devolo dLAN pro 500 Wireless+
+endef
+LEGACY_DEVICES += dLAN_pro_500_wp
+
+define LegacyDevice/ESR900
+  DEVICE_TITLE := EnGenius ESR900
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += ESR900
+
+define LegacyDevice/WP543_4M
+  DEVICE_TITLE := Compex WP543/WPJ543 (4MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += WP543_4M
+
+define LegacyDevice/WP543_8M
+  DEVICE_TITLE := Compex WP543/WPJ543 (8MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += WP543_8M
+
+define LegacyDevice/WP543_16M
+  DEVICE_TITLE := Compex WP543/WPJ543 (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += WP543_16M
+
+define LegacyDevice/WPE72_4M
+  DEVICE_TITLE := Compex WPE72/WPE72NX (4MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += WPE72_4M
+
+define LegacyDevice/WPE72_8M
+  DEVICE_TITLE := Compex WPE72/WPE72NX (8MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += WPE72_8M
+
+define LegacyDevice/WPE72_16M
+  DEVICE_TITLE := Compex WPE72/WPE72NX (16MB flash)
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += WPE72_16M
+
+define LegacyDevice/WNR2000V3
+  DEVICE_TITLE := NETGEAR WNR2000V3
+endef
+LEGACY_DEVICES += WNR2000V3
+
+define LegacyDevice/WNR2000V4
+  DEVICE_TITLE := NETGEAR WNR2000V4
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WNR2000V4
+
+define LegacyDevice/WNR2200
+  DEVICE_TITLE := NETGEAR WNR2200
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WNR2200
+
+define LegacyDevice/REALWNR612V2
+  DEVICE_TITLE := NETGEAR WNR612V2
+endef
+LEGACY_DEVICES += REALWNR612V2
+
+define LegacyDevice/N150R
+  DEVICE_TITLE := On Networks N150
+endef
+LEGACY_DEVICES += N150R
+
+define LegacyDevice/REALWNR1000V2
+  DEVICE_TITLE := NETGEAR WNR1000V2
+endef
+LEGACY_DEVICES += REALWNR1000V2
+
+define LegacyDevice/WNR1000V2_VC
+  DEVICE_TITLE := NETGEAR WNR1000V2-VC
+endef
+LEGACY_DEVICES += WNR1000V2_VC
+
+define LegacyDevice/WPN824N
+  DEVICE_TITLE := NETGEAR WPN824N
+endef
+LEGACY_DEVICES += WPN824N
+
+define LegacyDevice/OM2P
+  DEVICE_TITLE := OpenMesh OM2P/OM2Pv2/OM2P-HS/OM2P-HSv2/OM2P-HSv3/OM2P-LC
+  DEVICE_PACKAGES := om-watchdog
+endef
+LEGACY_DEVICES += OM2P
+
+define LegacyDevice/OM5P
+  DEVICE_TITLE := OpenMesh OM5P/OM5P-AN
+  DEVICE_PACKAGES := om-watchdog
+endef
+LEGACY_DEVICES += OM5P
+
+define LegacyDevice/MR600
+  DEVICE_TITLE := OpenMesh MR600
+  DEVICE_PACKAGES := om-watchdog
+endef
+LEGACY_DEVICES += MR600
+
+define LegacyDevice/MR900
+  DEVICE_TITLE := OpenMesh MR900/MR900v2
+  DEVICE_PACKAGES := om-watchdog
+endef
+LEGACY_DEVICES += MR900
+
+define LegacyDevice/ALL0305
+  DEVICE_TITLE := Allnet ALL0305
+  DEVICE_PACKAGES := fconfig kmod-ath5k -kmod-ath9k
+endef
+LEGACY_DEVICES += ALL0305
+
+define LegacyDevice/EAP7660D
+  DEVICE_TITLE := Senao EAP7660D
+endef
+LEGACY_DEVICES += EAP7660D
+
+define LegacyDevice/JA76PF
+  DEVICE_TITLE := jjPlus JA76PF
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-hwmon-core kmod-i2c-core kmod-hwmon-lm75
+endef
+LEGACY_DEVICES += JA76PF
+
+define LegacyDevice/JA76PF2
+  DEVICE_TITLE := jjPlus JA76PF2
+endef
+LEGACY_DEVICES += JA76PF2
+
+define LegacyDevice/JWAP003
+  DEVICE_TITLE := jjPlus JWAP003
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += JWAP003
+
+define LegacyDevice/PB42
+  DEVICE_TITLE := Atheros PB42 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2
+endef
+LEGACY_DEVICES += PB42
+
+define LegacyDevice/PB44
+  DEVICE_TITLE := Atheros PB44 reference board
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 \
+	  vsc7385-ucode-pb44 vsc7395-ucode-pb44
+endef
+LEGACY_DEVICES += PB44
+
+define LegacyDevice/MZKW04NU
+  DEVICE_TITLE := Planex MZK-W04NU
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += MZKW04NU
+
+define LegacyDevice/MZKW300NH
+  DEVICE_TITLE := Planex MZK-W300NH
+endef
+LEGACY_DEVICES += MZKW300NH
+
+define LegacyDevice/EAP300V2
+  DEVICE_TITLE := EnGenius EAP300V2
+endef
+LEGACY_DEVICES += EAP300V2
+
+define LegacyDevice/WHRG301N
+  DEVICE_TITLE := Buffalo WHR-G301N
+endef
+LEGACY_DEVICES += WHRG301N
+
+define LegacyDevice/WHRHPG300N
+  DEVICE_TITLE := Buffalo WHR-HP-G300N
+endef
+LEGACY_DEVICES += WHRHPG300N
+
+define LegacyDevice/WHRHPGN
+  DEVICE_TITLE := Buffalo WHR-HP-GN
+endef
+LEGACY_DEVICES += WHRHPGN
+
+define LegacyDevice/WLAEAG300N
+  DEVICE_TITLE := Buffalo WLAE-AG300N
+  DEVICE_PACKAGES := kmod-ledtrig-netdev
+endef
+LEGACY_DEVICES += WLAEAG300N
+
+define LegacyDevice/WRT400N
+  DEVICE_TITLE := Linksys WRT400N
+endef
+LEGACY_DEVICES += WRT400N
+
+define LegacyDevice/WZRHPG300NH
+  DEVICE_TITLE := Buffalo WZR-HP-G300NH
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WZRHPG300NH
+
+define LegacyDevice/WZRHPG300NH2
+  DEVICE_TITLE := Buffalo WZR-HP-G300NH2
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WZRHPG300NH2
+
+define LegacyDevice/WZRHPAG300H
+  DEVICE_TITLE := Buffalo WZR-HP-AG300H
+  DEVICE_PACKAGES := kmod-usb-ohci kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WZRHPAG300H
+
+define LegacyDevice/WZRHPG450H
+  DEVICE_TITLE := Buffalo WZR-HP-G450H
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WZRHPG450H
+
+define LegacyDevice/WZR600DHP
+  DEVICE_TITLE := Buffalo WZR-600DHP
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WZR600DHP
+
+define LegacyDevice/WZR450HP2
+  DEVICE_TITLE := Buffalo WZR-450HP2
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WZR450HP2
+
+define LegacyDevice/ZBTWE1526
+  DEVICE_TITLE := Zbtlink ZBT-WE1526
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+endef
+LEGACY_DEVICES += ZBTWE1526
+
+define LegacyDevice/ZCN1523H28
+  DEVICE_TITLE := Zcomax ZCN-1523H-2-8
+endef
+LEGACY_DEVICES += ZCN1523H28
+
+define LegacyDevice/ZCN1523H516
+  DEVICE_TITLE := Zcomax ZCN-1523H-5-16
+endef
+LEGACY_DEVICES += ZCN1523H516
+
+define LegacyDevice/NBG_460N_550N_550NH
+  DEVICE_TITLE := Zyxel NBG 460N/550N/550NH
+  DEVICE_PACKAGES := kmod-rtc-pcf8563
+endef
+LEGACY_DEVICES += NBG_460N_550N_550NH
diff --git a/target/linux/ar71xx/image/legacy.mk b/target/linux/ar71xx/image/legacy.mk
new file mode 100644
index 0000000000..e0e7be1a88
--- /dev/null
+++ b/target/linux/ar71xx/image/legacy.mk
@@ -0,0 +1,1065 @@
+rootfs_type=$(patsubst squashfs-%,squashfs,$(1))
+
+# $(1): rootfs type.
+# $(2): board name.
+define imgname
+$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(call rootfs_type,$(1))
+endef
+
+define rootfs_align
+$(patsubst %-256k,0x40000,$(patsubst %-128k,0x20000,$(patsubst %-64k,0x10000,$(patsubst squashfs%,0x4,$(patsubst root.%,%,$(1))))))
+endef
+
+define sysupname
+$(call imgname,$(1),$(2))-sysupgrade.bin
+endef
+
+define factoryname
+$(call imgname,$(1),$(2))-factory.bin
+endef
+
+COMMA:=,
+
+define mkcmdline
+$(if $(1),board=$(1) )$(if $(2),console=$(2)$(COMMA)$(3))
+endef
+
+define mtdpartsize
+$(shell sz=`echo '$(2)' | sed -ne 's/.*[:$(COMMA)]\([0-9]*\)k[@]*[0-9a-zx]*($(1)).*/\1/p'`; [ -n "$$sz" ] && echo $$(($$sz * 1024)))
+endef
+
+# $(1)      : name of image build method to be used, e.g., AthLzma.
+# $(2)      : name of the build template to be used, e.g. 64k, 64kraw, 128k, etc.
+# $(3)      : name of the profile to be defined.
+# $(4)      : board name.
+# $(5)~$(7) : arguments for $(mkcmdline)
+#		board=$(1) console=$(2),$(3)
+# $(8)~$(14): extra arguments.
+define SingleProfile
+  # $(1): action name, e.g. loader, buildkernel, squashfs, etc.
+  define Image/Build/Profile/$(3)
+	$$(call Image/Build/Template/$(2)/$$(1),$(1),$(4),$$(call mkcmdline,$(5),$(6),$(7)),$(8),$(9),$(10),$(11),$(12),$(13),$(14))
+  endef
+endef
+
+LOADER_MAKE := $(NO_TRACE_MAKE) -C lzma-loader KDIR=$(KDIR)
+
+VMLINUX:=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux
+UIMAGE:=$(BIN_DIR)/$(IMG_PREFIX)-uImage
+
+# $(1): input file.
+# $(2): output file.
+# $(3): extra arguments for lzma.
+define CompressLzma
+  $(STAGING_DIR_HOST)/bin/lzma e $(1) -lc1 -lp2 -pb2 $(3) $(2)
+endef
+
+define PatchKernel
+	cp $(KDIR)/vmlinux$(3) $(KDIR_TMP)/vmlinux$(3)-$(1)
+	$(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(3)-$(1) "$(strip $(2))"
+endef
+
+define PatchKernel/initramfs
+	$(call PatchKernel,$(1),$(2),-initramfs)
+	cp $(KDIR_TMP)/vmlinux-initramfs-$(1) $(call imgname,initramfs,$(1)).bin
+endef
+
+# $(1): board name.
+# $(2): kernel command line.
+# $(3): extra argumetns for lzma.
+# $(4): name suffix, e.g. "-initramfs".
+define PatchKernelLzma
+	cp $(KDIR)/vmlinux$(4) $(KDIR_TMP)/vmlinux$(4)-$(1)
+	$(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(4)-$(1) "$(strip $(2))"
+	$(call CompressLzma,$(KDIR_TMP)/vmlinux$(4)-$(1),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(3))
+endef
+
+define PatchKernelGzip
+	cp $(KDIR)/vmlinux$(3) $(KDIR_TMP)/vmlinux$(3)-$(1)
+	$(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR_TMP)/vmlinux$(3)-$(1) "$(strip $(2))"
+	gzip -9n -c $(KDIR_TMP)/vmlinux$(3)-$(1) > $(KDIR_TMP)/vmlinux$(3)-$(1).bin.gz
+endef
+
+ifneq ($(SUBTARGET),mikrotik)
+# $(1): compression method of the data.
+# $(2): extra arguments.
+# $(3): input data file.
+# $(4): output file.
+define MkuImage
+	mkimage -A mips -O linux -T kernel -a 0x80060000 -C $(1) $(2) \
+		-e 0x80060000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+		-d $(3) $(4)
+endef
+
+# $(1): board name.
+# $(2): kernel command line.
+# $(3): extra arguments for lzma.
+# $(4): name suffix, e.g. "-initramfs".
+# $(5): extra arguments for mkimage.
+define MkuImageLzma
+	$(call PatchKernelLzma,$(1),$(2),$(3),$(4))
+	$(call MkuImage,lzma,$(5),$(KDIR_TMP)/vmlinux$(4)-$(1).bin.lzma,$(KDIR_TMP)/vmlinux$(4)-$(1).uImage)
+endef
+
+define MkuImageLzma/initramfs
+	$(call PatchKernelLzma,$(1),$(2),$(3),-initramfs)
+	$(call MkuImage,lzma,$(4),$(KDIR_TMP)/vmlinux-initramfs-$(1).bin.lzma,$(call imgname,initramfs,$(1))-uImage.bin)
+endef
+
+define MkuImageGzip
+	$(call PatchKernelGzip,$(1),$(2))
+	$(call MkuImage,gzip,,$(KDIR_TMP)/vmlinux-$(1).bin.gz,$(KDIR_TMP)/vmlinux-$(1).uImage)
+endef
+
+define MkuImageGzip/initramfs
+	$(call PatchKernelGzip,$(1),$(2),-initramfs)
+	$(call MkuImage,gzip,,$(KDIR_TMP)/vmlinux-initramfs-$(1).bin.gz,$(call imgname,initramfs,$(1))-uImage.bin)
+endef
+
+define MkuImageOKLI
+	$(call MkuImage,lzma,-M 0x4f4b4c49,$(KDIR)/vmlinux.bin.lzma,$(KDIR_TMP)/vmlinux-$(1).okli)
+endef
+endif
+
+# $(1): name of the 1st file.
+# $(2): size limit of the 1st file if it is greater than 262144, or
+#       the erase size of the flash if it is greater than zero and less
+#       than 262144
+# $(3): name of the 2nd file.
+# $(4): size limit of the 2nd file if $(2) is greater than 262144, otherwise
+#       it is the size limit of the output file
+# $(5): name of the output file.
+# $(6): padding size.
+define CatFiles
+	if [ $(2) -eq 0 ]; then \
+		filename="$(3)"; fstype=$${filename##*\.}; \
+		case "$${fstype}" in \
+		*) bs=`stat -c%s $(1)`;; \
+		esac; \
+		( dd if=$(1) bs=$${bs} conv=sync;  cat $(3) ) > $(5); \
+		if [ -n "$(6)" ]; then \
+			case "$${fstype}" in \
+			squashfs*) \
+				padjffs2 $(5) $(6); \
+				;; \
+			esac; \
+		fi; \
+		if [ `stat -c%s $(5)` -gt $(4) ]; then \
+			echo "Warning: $(5) is too big (> $(4) bytes)" >&2; \
+			rm -f $(5); \
+		fi; \
+	else if [ $(2) -gt 262144 ]; then \
+		if [ `stat -c%s "$(1)"` -gt $(2) ]; then \
+			echo "Warning: $(1) is too big (> $(2) bytes)" >&2; \
+		else if [ `stat -c%s $(3)` -gt $(4) ]; then \
+			echo "Warning: $(3) is too big (> $(4) bytes)" >&2; \
+		else \
+			( dd if=$(1) bs=$(2) conv=sync; dd if=$(3) ) > $(5); \
+		fi; fi; \
+	else \
+		( dd if=$(1) bs=$(2) conv=sync; dd if=$(3) ) > $(5); \
+		if [ `stat -c%s $(5)` -gt $(4) ]; then \
+			echo "Warning: $(5) is too big (> $(4) bytes)" >&2; \
+			rm -f $(5); \
+		fi; \
+	fi; fi
+endef
+
+# $(1): rootfs type.
+# $(2): board name.
+# $(3): kernel image size limit.
+# $(4): rootfs image size limit.
+# $(5): padding argument for padjffs2.
+Sysupgrade/KR=$(call CatFiles,$(2),$(3),$(KDIR)/root.$(1),$(4),$(call sysupname,$(1),$(5)))
+Sysupgrade/KRuImage=$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage,$(3),$(KDIR)/root.$(1),$(4),$(call sysupname,$(1),$(2)),$(5))
+Sysupgrade/RKuImage=$(call CatFiles,$(KDIR)/root.$(1),$(4),$(KDIR_TMP)/vmlinux-$(2).uImage,$(3),$(call sysupname,$(1),$(2)))
+
+# $(1): ubinize ini file
+# $(2): working directory
+# $(3): output file
+# $(4): physical erase block size
+# $(5): minimum I/O unit size
+# $(6): custom options
+define ubinize
+	$(CP) $(1) $(2)
+	( cd $(2); $(STAGING_DIR_HOST)/bin/ubinize -o $(3) -p $(4) -m $(5) $(6) $(1))
+endef
+
+#
+# Embed lzma-compressed kernel inside lzma-loader.
+#
+# $(1), suffix of output filename, e.g. generic, lowercase board name, etc.
+# $(2), suffix of target file to build, e.g. bin, gz, elf
+# $(3), kernel command line to pass from lzma-loader to kernel
+# $(4), unused here
+# $(5), suffix of kernel filename, e.g. -initramfs, or empty
+define Image/BuildLoader
+	-rm -rf $(KDIR)/lzma-loader
+	$(LOADER_MAKE) LOADER=loader-$(1).$(2) KERNEL_CMDLINE="$(3)"\
+		LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
+		LOADER_DATA="$(KDIR)/vmlinux$(5).bin.lzma" BOARD="$(1)" \
+		compile loader.$(2)
+	-$(CP) $(KDIR)/loader-$(1).$(2) $(KDIR)/loader-$(1)$(5).$(2)
+endef
+
+#
+# Build lzma-loader alone which will search for lzma-compressed kernel identified by
+# uImage header with magic "OKLI" at boot time.
+#
+# $(4), offset into the flash space to start searching uImage magic "OKLI".
+# $(5), size of search range starting at $(4).  With 0 as the value, uImage
+#	header is expected to be at precisely $(4)
+define Image/BuildLoaderAlone
+	-rm -rf $(KDIR)/lzma-loader
+	$(LOADER_MAKE) LOADER=loader-$(1).$(2) KERNEL_CMDLINE="$(3)" \
+		LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
+		BOARD="$(1)" FLASH_OFFS=$(4) FLASH_MAX=$(5) \
+		compile loader.$(2)
+endef
+
+define Build/Clean
+	$(LOADER_MAKE) clean
+endef
+
+alfa_ap120c_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,13312k(rootfs),1536k(kernel),1152k(unknown)ro,64k(art)ro;spi0.1:-(unknown)
+alfa_ap96_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env)ro,13312k(rootfs),2048k(kernel),512k(caldata)ro,15360k@0x80000(firmware)
+alfa_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1600k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+alfa_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,15936k(firmware),64k(nvram),64k(art)ro
+all0258n_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),6272k(firmware),1536k(failsafe),64k(art)ro
+all0315n_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,256k(u-boot-env),13568k(firmware),2048k(failsafe),256k(art)ro
+ap81_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,5120k(rootfs),2688k(kernel),64k(art)ro,7808k@0x50000(firmware)
+ap83_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,4096k(rootfs),3648k(kernel),64k(art)ro,7744k@0x60000(firmware)
+ap96_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1728k(kernel),64k(art)ro,7872k@0x40000(firmware)
+ap121_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6144k(rootfs),1600k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+ap121_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,10944k(rootfs),4992k(kernel),64k(nvram),64k(art)ro,15936k@0x50000(firmware)
+ap132_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),6400k(rootfs),64k(art)ro,7808k@0x50000(firmware)
+ap135_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+ap136_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(mib0),64k(art)ro,7744k@0x50000(firmware)
+ap143_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1472k(kernel),64k(art)ro,7744k@0x50000(firmware)
+ap143_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+ap147_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+ap152_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14528k(rootfs),1472k(kernel),64k(art)ro,16000k@0x50000(firmware)
+bxu2000n2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),8448k(rootfs),6016k(user),64k(cfg),64k(oem),64k(art)ro
+cameo_ap81_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(config)ro,3840k(firmware),64k(art)ro
+cameo_ap91_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,3712k(firmware),64k(mac)ro,64k(art)ro
+cameo_ap99_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,3520k(firmware),64k(mac)ro,192k(lp)ro,64k(art)ro
+cameo_ap121_mtdlayout=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k(nvram)ro,192k(language)ro,3648k(firmware)
+cameo_ap121_mtdlayout_8M=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k(nvram)ro,256k(language)ro,7680k@0x80000(firmware)
+cameo_ap123_mtdlayout_4M=mtdparts=spi0.0:64k(u-boot)ro,64k(nvram)ro,3712k(firmware),192k(lang)ro,64k(art)ro
+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)ro,64k(u-boot-env),320k(custom)ro,1536k(kernel),12096k(rootfs),2048k(failsafe),64k(art)ro,13632k@0xa0000(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)
+dgl_5500_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,15296k(firmware),192k(lang)ro,512k(my-dlink)ro,64k(mac)ro,64k(art)ro
+dlan_hotspot_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(Config1)ro,64k(Config2)ro,7872k@0x40000(firmware),64k(art)ro
+dlan_pro_500_wp_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(Config1)ro,64k(Config2)ro,7680k@0x70000(firmware),64k(art)ro
+dlan_pro_1200_ac_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,64k(Config1)ro,64k(Config2)ro,15872k@0x70000(firmware),64k(art)ro
+cameo_ap94_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,1600k(unknown)ro,64k@0x7f0000(caldata_copy)
+cameo_ap94_mtdlayout_fat=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,7808k(firmware),64k(caldata)ro,64k@0x660000(caldata_orig),6208k@0x50000(firmware_orig)
+esr900_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
+esr1750_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
+epg5000_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),13248k(rootfs),1024k(manufacture)ro,64k(backup)ro,320k(storage)ro,64k(caldata)ro,14656k@0x40000(firmware)
+ew-dorin_mtdlayout_4M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),3712k(firmware),64k(art)ro
+ew-dorin_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),16000k(firmware),64k(art)ro
+f9k1115v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),14464k(rootfs),1408k(kernel),64k(nvram)ro,64k(envram)ro,64k(art)ro,15872k@0x50000(firmware)
+dlrtdev_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,640k(certs),960k(unknown)ro,64k@0x7f0000(caldata_copy)
+dlrtdev_mtdlayout_fat=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,7168k(firmware),640k(certs),64k(caldata)ro,64k@0x660000(caldata_orig),6208k@0x50000(firmware_orig)
+planex_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7744k(firmware),128k(art)ro
+ubntxm_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro
+uap_pro_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1536k(kernel),14208k(rootfs),256k(cfg)ro,64k(EEPROM)ro,15744k@0x50000(firmware)
+ubdev_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7488k(firmware),64k(certs),256k(cfg)ro,64k(EEPROM)ro
+whrhpg300n_mtdlayout=mtdparts=spi0.0:248k(u-boot)ro,8k(u-boot-env)ro,3712k(firmware),64k(art)ro
+wlr8100_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,1408k(kernel),14080k(rootfs),192k(unknown)ro,64k(art)ro,384k(unknown2)ro,15488k@0x40000(firmware)
+wpj342_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+wpj344_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+dr344_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)
+wpj531_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+wpj558_mtdlayout_16M=mtdparts=spi0.0:192k(u-boot)ro,16128k(firmware),64k(art)ro
+wndap360_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,1728k(kernel),6016k(rootfs),64k(nvram)ro,64k(art)ro,7744k@0x50000(firmware)
+wnr2200_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7808k(firmware),64k(art)ro
+wnr2000v3_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,3712k(firmware),64k(art)ro
+wnr2000v4_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env)ro,3776k(firmware),64k(art)ro
+r6100_mtdlayout=mtdparts=ar934x-nfc:128k(u-boot)ro,256k(caldata)ro,256k(caldata-backup),512k(config),512k(pot),2048k(kernel),122240k(ubi),25600k@0x1a0000(firmware),2048k(language),3072k(traffic_meter)
+tew823dru_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(nvram)ro,15296k(firmware),192k(lang)ro,512k(my-dlink)ro,64k(mac)ro,64k(art)ro
+wndr4300_mtdlayout=mtdparts=ar934x-nfc:256k(u-boot)ro,256k(u-boot-env)ro,256k(caldata)ro,512k(pot),2048k(language),512k(config),3072k(traffic_meter),2048k(kernel),23552k(ubi),25600k@0x6c0000(firmware),256k(caldata_backup),-(reserved)
+zcn1523h_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6208k(rootfs),1472k(kernel),64k(configure)ro,64k(mfg)ro,64k(art)ro,7680k@0x50000(firmware)
+mynet_rext_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,7808k(firmware),64k(nvram)ro,64k(ART)ro
+zyx_nbg6716_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(env)ro,64k(RFdata)ro,-(nbu);ar934x-nfc:2048k(zyxel_rfsd),2048k(romd),1024k(header),2048k(kernel),-(ubi)
+yun_mtdlayout_8M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6464k(rootfs),1280k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+yun_mtdlayout_16M=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14656k(rootfs),1280k(kernel),64k(nvram),64k(art)ro,15936k@0x50000(firmware)
+wrtnode2q_mtdlayout=mtdparts=spi0.0:192k(u-boot)ro,64k(u-boot-env),64k(art)ro,1472k(kernel),14592k(rootfs),16064k@0x50000(firmware),16384k@0x0(fullflash)
+
+define Image/BuildKernel
+	cp $(KDIR)/vmlinux.elf $(VMLINUX).elf
+	cp $(KDIR)/vmlinux $(VMLINUX).bin
+	dd if=$(KDIR)/vmlinux.bin.lzma of=$(VMLINUX).lzma bs=65536 conv=sync
+	$(call MkuImage,lzma,,$(KDIR)/vmlinux.bin.lzma,$(UIMAGE)-lzma.bin)
+	cp $(KDIR)/loader-generic.elf $(VMLINUX)-lzma.elf
+	-mkdir -p $(KDIR_TMP)
+endef
+
+define Image/BuildKernel/Initramfs
+	cp $(KDIR)/vmlinux-initramfs.elf $(VMLINUX)-initramfs.elf
+	cp $(KDIR)/vmlinux-initramfs $(VMLINUX)-initramfs.bin
+	dd if=$(KDIR)/vmlinux-initramfs.bin.lzma of=$(VMLINUX)-initramfs.lzma bs=65536 conv=sync
+	$(call MkuImage,lzma,,$(KDIR)/vmlinux-initramfs.bin.lzma,$(UIMAGE)-initramfs-lzma.bin)
+	cp $(KDIR)/loader-generic-initramfs.elf $(VMLINUX)-initramfs-lzma.elf
+	$(call Image/Build/Initramfs)
+endef
+
+Image/Build/WRT400N/buildkernel=$(call MkuImageLzma,$(2),$(3))
+
+define Image/Build/WRT400N
+	$(call Sysupgrade/KRuImage,$(1),$(2),1310720,6488064)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		wrt400n $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR)/root.$(1) $(call factoryname,$(1),$(2)); \
+	fi
+endef
+
+
+define Image/Build/CameoAP94/buildkernel
+	$(call MkuImageLzma,$(2),$(3) $(4))
+	$(call MkuImageLzma,$(2)-fat,$(3) $(5))
+endef
+
+define Image/Build/CameoAP94
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(eval fwsize_fat=$(call mtdpartsize,firmware,$(5)))
+	$(call Sysupgrade/KRuImage,$(1),$(2),0,$$(($(fwsize)-4*64*1024)),64)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		( \
+			dd if=$(call sysupname,$(1),$(2)); \
+			echo -n "$(6)"; \
+		) > $(call imgname,$(1),$(2))-backup-loader.bin; \
+		if [ `stat -c%s $(call sysupname,$(1),$(2))` -gt 4194304 ]; then \
+			echo "Warning: $(call sysupname,$(1),$(2)) is too big" >&2; \
+		else \
+			( \
+				dd if=$(call sysupname,$(1),$(2)) bs=4096k conv=sync; \
+				echo -n "$(7)"; \
+			) > $(call factoryname,$(1),$(2)); \
+		fi; \
+	fi
+	$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2)-fat.uImage,0,$(KDIR)/root.$(1),$$(($(fwsize_fat)-4*64*1024)),$(KDIR_TMP)/$(2)-fat.bin,64)
+	if [ -e "$(KDIR_TMP)/$(2)-fat.bin" ]; then \
+		echo -n "" > $(KDIR_TMP)/$(2)-fat.dummy; \
+		sh $(TOPDIR)/scripts/combined-image.sh \
+			"$(KDIR_TMP)/$(2)-fat.bin" \
+			"$(KDIR_TMP)/$(2)-fat.dummy" \
+			$(call sysupname,$(1),$(2)-fat); \
+	fi
+endef
+
+define Image/Build/WZRHP
+	$(call Sysupgrade/KRuImage,$(1),$(2),0,$$(($(3)-4*$(4)*1024)),$(4))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		( \
+			echo -n -e "# Airstation Public Fmt1\x00\x00\x00\x00\x00\x00\x00\x00"; \
+			dd if=$(call sysupname,$(1),$(2)); \
+		) > $(call imgname,$(1),$(2))-tftp.bin; \
+		buffalo-enc -p $(5) -v 1.99 \
+			-i $(call sysupname,$(1),$(2)) \
+			-o $(KDIR_TMP)/$(2).enc; \
+		buffalo-tag -b $(5) -p $(5) -a ath -v 1.99 -m 1.01 -l mlang8 \
+			-w 3 -c 0x80041000 -d 0x801e8000 -f 1 -r M_ \
+			-i $(KDIR_TMP)/$(2).enc \
+			-o $(call factoryname,$(1),$(2)); \
+	fi
+endef
+
+Image/Build/WZRHP64K/buildkernel=$(call MkuImageLzma,$(2),$(3))
+Image/Build/WZRHP64K/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+Image/Build/WZRHP64K=$(call Image/Build/WZRHP,$(1),$(2),33095680,64,$(4))
+
+Image/Build/WZRHP128K/buildkernel=$(call MkuImageLzma,$(2),$(3))
+Image/Build/WZRHP128K/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+Image/Build/WZRHP128K=$(call Image/Build/WZRHP,$(1),$(2),33030144,128,$(4))
+
+
+Image/Build/WHRHPG300N/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/WHRHPG300N/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/WHRHPG300N
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(call Sysupgrade/KRuImage,$(1),$(2),0,$$(($(fwsize)-4*64*1024)),64)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		( \
+			echo -n -e "# Airstation Public Fmt1\x00\x00\x00\x00\x00\x00\x00\x00"; \
+			dd if=$(call sysupname,$(1),$(2)); \
+		) > $(call imgname,$(1),$(2))-tftp.bin; \
+		buffalo-enc -p $(5) -v 1.99 \
+			-i $(call sysupname,$(1),$(2)) \
+			-o $(KDIR_TMP)/$(2).enc; \
+		buffalo-tag -b $(5) -p $(5) -a ath -v 1.99 -m 1.01 -l mlang8 \
+			-w 3 -c 0x80041000 -d 0x801e8000 -f 1 -r M_ \
+			-i $(KDIR_TMP)/$(2).enc \
+			-o $(call factoryname,$(1),$(2)); \
+	fi
+endef
+
+
+define Image/Build/Cameo
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(call Sysupgrade/KRuImage,$(1),$(2),0,$$(($(fwsize)-4*64*1024)),64)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		factory_size=$$(($(fwsize) - $(6))); \
+		( \
+			dd if=$(call sysupname,$(1),$(2)) bs=$${factory_size} conv=sync; \
+			echo -n $(5); \
+		) > $(call factoryname,$(1),$(2)); \
+	fi
+endef
+
+Image/Build/CameoAP81/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap81_mtdlayout))
+Image/Build/CameoAP81=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap81_mtdlayout),$(4),65536)
+Image/Build/CameoAP81/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap81_mtdlayout))
+
+Image/Build/CameoAP91/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap91_mtdlayout))
+Image/Build/CameoAP91=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap91_mtdlayout),$(4),65536)
+Image/Build/CameoAP91/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap91_mtdlayout))
+
+Image/Build/CameoAP99/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap99_mtdlayout))
+Image/Build/CameoAP99=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap99_mtdlayout),$(4),65536)
+Image/Build/CameoAP99/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap99_mtdlayout))
+
+Image/Build/CameoAP123_4M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap123_mtdlayout_4M))
+Image/Build/CameoAP123_4M=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_ap123_mtdlayout_4M),$(4),26)
+Image/Build/CameoAP123_4M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap123_mtdlayout_4M))
+
+Image/Build/CameoAP135/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/CameoAP135=$(call Image/Build/Cameo,$(1),$(2),$(3),$(4),$(5),26)
+Image/Build/CameoAP135/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+Image/Build/CameoDB120/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_db120_mtdlayout))
+Image/Build/CameoDB120=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_db120_mtdlayout),$(4),26)
+Image/Build/CameoDB120/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_db120_mtdlayout))
+
+Image/Build/CameoDB120_8M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_db120_mtdlayout_8M))
+Image/Build/CameoDB120_8M=$(call Image/Build/Cameo,$(1),$(2),$(3),$(cameo_db120_mtdlayout_8M),$(4),26)
+Image/Build/CameoDB120_8M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_db120_mtdlayout_8M))
+
+define Image/Build/CameoHornet
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(call Sysupgrade/KRuImage,$(1),$(2),0,$$(($(fwsize)-4*64*1024)),64)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		for r in $(7); do \
+			[ -n "$$r" ] && dashr="-$$r" || dashr=; \
+			[ -z "$$r" ] && r="DEF"; \
+			mkcameofw -M HORNET -R "$$r" -S $(5) -V $(6) -c \
+				-K $(8) -I $(fwsize) \
+				-k "$(call sysupname,$(1),$(2))" \
+				-o $(call imgname,$(1),$(2))-factory$$dashr.bin; \
+			true; \
+		done; \
+	fi
+endef
+
+Image/Build/CameoAP121/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap121_mtdlayout))
+Image/Build/CameoAP121=$(call Image/Build/CameoHornet,$(1),$(2),$(3),$(cameo_ap121_mtdlayout),$(4),$(5),$(6),0xe0000)
+Image/Build/CameoAP121/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap121_mtdlayout))
+
+Image/Build/CameoAP121_8M/buildkernel=$(call MkuImageLzma,$(2),$(3) $(cameo_ap121_mtdlayout_8M))
+Image/Build/CameoAP121_8M=$(call Image/Build/CameoHornet,$(1),$(2),$(3),$(cameo_ap121_mtdlayout_8M),$(4),$(5),$(6),0x100000)
+Image/Build/CameoAP121_8M/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(cameo_ap121_mtdlayout_8M))
+
+define Image/Build/dLAN
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+	$(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+	$(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
+endef
+
+Image/Build/dLANLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/dLANLzma=$(call Image/Build/dLAN,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/dLANLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Ath
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+	$(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+	$(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
+endef
+
+Image/Build/AthGzip/buildkernel=$(call MkuImageGzip,$(2),$(3) $(4))
+Image/Build/AthGzip=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/AthGzip/initramfs=$(call MkuImageGzip/initramfs,$(2),$(3) $(4))
+
+Image/Build/AthLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/AthLzma=$(call Image/Build/Ath,$(1),$(2),$(3),$(4),$(5),$(6),$(7))
+Image/Build/AthLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+
+Image/Build/Belkin/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/Belkin/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Belkin
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+	$(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+	$(call Sysupgrade/RKuImage,$(1),$(2),$(kernsize),$(rootsize))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		edimax_fw_header -m $(5) -v "$(shell echo -n LEDE$(REVISION) | cut -c -13)" \
+			-n "uImage" \
+			-i $(KDIR_TMP)/vmlinux-$(2).uImage \
+			-o $(KDIR_TMP)/$(2)-uImage; \
+		edimax_fw_header -m $(5) -v "$(shell echo -n LEDE$(REVISION) | cut -c -13)" \
+			-n "rootfs" \
+			-i $(KDIR)/root.$(1) \
+			-o $(KDIR_TMP)/$(2)-rootfs; \
+		( \
+			dd if=$(KDIR_TMP)/$(2)-rootfs; \
+			dd if=$(KDIR_TMP)/$(2)-uImage; \
+		) > "$(call factoryname,$(1),$(2))"; \
+	fi
+endef
+
+define Image/Build/EnGenius
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(eval rootsize=$(call mtdpartsize,rootfs,$(4)))
+	$(eval kernsize=$(call mtdpartsize,kernel,$(4)))
+	$(call Sysupgrade/$(5),$(1),$(2),$(if $(6),$(6),$(kernsize)),$(if $(rootsize),$(rootsize),$(fwsize)))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		mksenaofw -e $(call sysupname,$(1),$(2)) \
+			-o $(call imgname,$(1),$(2))-factory.dlf \
+			-r 0x101 -p $(7) -t 2; \
+	fi
+endef
+
+Image/Build/EnGenius/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/EnGenius/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+
+Image/Build/PB4X/buildkernel=$(call PatchKernelLzma,$(2),$(3))
+
+define Image/Build/PB4X
+	dd if=$(KDIR_TMP)/vmlinux-$(2).bin.lzma \
+	   of=$(call imgname,kernel,$(2)).bin bs=64k conv=sync
+	dd if=$(KDIR)/root.$(1) \
+	   of=$(call imgname,$(1),$(2)-rootfs).bin bs=128k conv=sync
+	-sh $(TOPDIR)/scripts/combined-image.sh \
+		"$(call imgname,kernel,$(2)).bin" \
+		"$(call imgname,$(1),$(2)-rootfs).bin" \
+		$(call sysupname,$(1),$(2))
+endef
+
+
+Image/Build/MyLoader/buildkernel=$(call PatchKernelLzma,$(2),$(3))
+Image/Build/MyLoader/initramfs=$(call PatchKernel/initramfs,$(2),$(3))
+
+define Image/Build/MyLoader
+	$(eval fwsize=$(shell echo $$(($(4)-0x30000-4*64*1024))))
+	$(eval fwimage=$(KDIR_TMP)/$(2)-$(5)-firmware.bin)
+	$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).bin.lzma,65536,$(KDIR)/root.$(1),$(fwsize),$(fwimage))
+	if [ -e "$(fwimage)" ]; then \
+		$(STAGING_DIR_HOST)/bin/mkmylofw -B $(2) -s $(4) -v \
+			-p0x00030000:0:al:0x80060000:firmware:$(fwimage) \
+			$(call imgname,$(1),$(2))-$(5)-factory.img; \
+		echo -n "" > $(KDIR_TMP)/empty.bin; \
+		sh $(TOPDIR)/scripts/combined-image.sh \
+			$(fwimage) $(KDIR_TMP)/empty.bin \
+			$(call imgname,$(1),$(2))-$(5)-sysupgrade.bin; \
+	fi
+endef
+
+Image/Build/Planex/initramfs=$(call MkuImageGzip/initramfs,$(2),$(3) $(planex_mtdlayout))
+Image/Build/Planex/loader=$(call Image/BuildLoaderAlone,$(1),gz,$(2) $(planex_mtdlayout),0x52000,0)
+
+define Image/Build/Planex/buildkernel
+	[ -e "$(KDIR)/loader-$(2).gz" ]
+	$(call MkuImageOKLI,$(2))
+	( \
+		dd if=$(KDIR)/loader-$(2).gz bs=8128 count=1 conv=sync; \
+		dd if=$(KDIR_TMP)/vmlinux-$(2).okli; \
+	) > $(KDIR_TMP)/kernel-$(2).bin
+	$(call MkuImage,gzip,,$(KDIR_TMP)/kernel-$(2).bin,$(KDIR_TMP)/vmlinux-$(2).uImage)
+endef
+
+define Image/Build/Planex
+	$(eval fwsize=$(call mtdpartsize,firmware,$(planex_mtdlayout)))
+	$(call Sysupgrade/KRuImage,$(1),$(2),0,$$(($(fwsize)-4*64*1024)),64)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		$(STAGING_DIR_HOST)/bin/mkplanexfw \
+			-B $(2) \
+			-v 2.00.00 \
+			-i $(call sysupname,$(1),$(2)) \
+			-o $(call factoryname,$(1),$(2)); \
+	fi
+endef
+
+
+Image/Build/ALFA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/ALFA/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/ALFA
+	$(call Sysupgrade/RKuImage,$(1),$(2),$(5),$(6))
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		rm -rf $(KDIR)/$(1); \
+		mkdir -p $(KDIR)/$(1); \
+		cd $(KDIR)/$(1); \
+		cp $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR)/$(1)/$(7); \
+		cp $(KDIR)/root.$(1) $(KDIR)/$(1)/$(8); \
+		$(TAR) zcf $(call factoryname,$(1),$(2)) -C $(KDIR)/$(1) $(7) $(8); \
+		( \
+			echo WRM7222C | dd bs=32 count=1 conv=sync; \
+			echo -ne '\xfe'; \
+		) >> $(call factoryname,$(1),$(2)); \
+	fi
+endef
+
+
+Image/Build/Senao/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/Senao/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Senao
+	mkdir -p $(KDIR_TMP)/$(2)/
+	touch $(KDIR_TMP)/$(2)/FWINFO-OpenWrt-$(REVISION)-$(2)
+	-$(CP) ./$(2)/* $(KDIR_TMP)/$(2)/
+	dd if=$(KDIR_TMP)/vmlinux-$(2).uImage \
+		of=$(KDIR_TMP)/$(2)/openwrt-senao-$(2)-uImage-lzma.bin bs=64k conv=sync
+	dd if=$(KDIR)/root.$(1) \
+		of=$(KDIR_TMP)/$(2)/openwrt-senao-$(2)-root.$(1) bs=64k conv=sync
+	( \
+		cd $(KDIR_TMP)/$(2)/;  \
+		$(TAR) -cz -f $(call factoryname,$(1),$(2)) * \
+	)
+	-rm -rf $(KDIR_TMP)/$(2)/
+	-sh $(TOPDIR)/scripts/combined-image.sh \
+		$(KDIR_TMP)/vmlinux-$(2).uImage \
+		$(KDIR)/root.$(1) \
+		$(call sysupname,$(1),$(2))
+endef
+
+define Image/Build/CyberTAN
+	echo -n '' > $(KDIR_TMP)/empty.bin
+	-$(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp \
+		-f $(KDIR_TMP)/vmlinux-$(2).uImage -F $(KDIR_TMP)/empty.bin \
+		-x 32 -a 0x10000 -x -32 -f $(KDIR)/root.$(1) && \
+	$(STAGING_DIR_HOST)/bin/addpattern -B $(2) -v v$(5) \
+		-i $(KDIR)/image.tmp \
+		-o $(call sysupname,$(1),$(2))
+	-$(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp -f $(KDIR_TMP)/vmlinux-$(2).uImage \
+		-x 32 -a 0x10000 -x -32 -f $(KDIR)/root.$(1) && \
+	$(STAGING_DIR_HOST)/bin/addpattern -B $(2) -v v$(5) -g \
+		-i $(KDIR)/image.tmp \
+		-o $(call factoryname,$(1),$(2))
+	-rm $(KDIR)/image.tmp
+endef
+
+Image/Build/CyberTANGZIP/loader=$(call Image/BuildLoader,$(1),gz,$(2),0x80060000)
+Image/Build/CyberTANGZIP/buildkernel=$(call MkuImage,gzip,,$(KDIR)/loader-$(2).gz,$(KDIR_TMP)/vmlinux-$(2).uImage)
+Image/Build/CyberTANGZIP=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
+
+Image/Build/CyberTANLZMA/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/CyberTANLZMA=$(call Image/Build/CyberTAN,$(1),$(2),$(3),$(4),$(5))
+
+
+Image/Build/Netgear/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
+
+define Image/Build/Netgear/buildkernel
+	$(call MkuImageLzma,$(2),$(3) $(4),-d20,,-M $(5))
+	-rm -rf $(KDIR_TMP)/$(2)
+	mkdir -p $(KDIR_TMP)/$(2)/image
+	cat $(KDIR_TMP)/vmlinux-$(2).uImage > $(KDIR_TMP)/$(2)/image/uImage
+	$(STAGING_DIR_HOST)/bin/mksquashfs-lzma \
+		$(KDIR_TMP)/$(2) $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp1 \
+		-noappend -root-owned -be -b 65536 \
+		$(if $(SOURCE_DATE_EPOCH),-fixed-time $(SOURCE_DATE_EPOCH))
+	( \
+		cat $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp1; \
+		dd if=/dev/zero bs=1k count=1 \
+	) > $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp2
+	mkimage -A mips -O linux -T filesystem -C none -M $(5) \
+		-a 0xbf070000 -e 0xbf070000 \
+		-n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+		-d $(KDIR_TMP)/vmlinux-$(2).uImage.squashfs.tmp2 \
+		$(KDIR_TMP)/vmlinux-$(2).uImage.squashfs
+endef
+
+define Image/Build/Netgear
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage.squashfs,0,$(KDIR)/root.$(1),$(fwsize),$(call sysupname,$(1),$(2)),64)
+	if [ -e $(call sysupname,$(1),$(2)) ]; then \
+		for r in $(7) ; do \
+			[ -n "$$r" ] && dashr="-$$r" || dashr= ; \
+			$(STAGING_DIR_HOST)/bin/mkdniimg \
+				-B $(6) -v OpenWrt.$(REVISION) -r "$$r" $(8) \
+				-i $(call sysupname,$(1),$(2)) \
+				-o $(call imgname,$(1),$(2))-factory$$dashr.img; \
+		done; \
+	fi
+endef
+
+
+Image/Build/NetgearLzma/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
+Image/Build/NetgearLzma/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4),-d20,,-M $(5))
+
+define Image/Build/NetgearLzma
+	$(eval fwsize=$(call mtdpartsize,firmware,$(4)))
+	$(call CatFiles,$(KDIR_TMP)/vmlinux-$(2).uImage,0,$(KDIR)/root.$(1),$(fwsize),$(call sysupname,$(1),$(2)),64)
+endef
+
+
+Image/Build/NetgearNAND/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4),,-M $(5))
+
+# $(1): (empty)
+# $(2): Board name (small caps)
+# $(3): Kernel board specific cmdline
+# $(4): Kernel mtdparts definition
+# $(5): U-Boot magic
+define Image/Build/NetgearNAND/buildkernel
+	$(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
+	$(call PatchKernelLzma,$(2),$(3) $(4),-d20)
+	dd if=$(KDIR_TMP)/vmlinux-$(2).bin.lzma \
+		of=$(KDIR_TMP)/vmlinux-$(2).bin.tmp \
+		bs=$$(($(kernelsize)-131072-2*64-1)) \
+		count=1 conv=sync
+	$(call MkuImage,lzma,-M $(5),$(KDIR_TMP)/vmlinux-$(2).bin.tmp,$(KDIR_TMP)/vmlinux-$(2).uImage)
+	echo -ne '\xff' >> $(KDIR_TMP)/vmlinux-$(2).uImage
+	# create a fake rootfs image
+	dd if=/dev/zero of=$(KDIR_TMP)/fakeroot-$(2) bs=131072 count=1
+	mkimage -A mips -O linux -T filesystem -C none \
+		-a 0xbf070000 -e 0xbf070000 \
+		-n 'MIPS OpenWrt fakeroot' \
+		-d $(KDIR_TMP)/fakeroot-$(2) \
+		-M $(5) \
+		$(KDIR_TMP)/fakeroot-$(2).uImage
+	# append the fake rootfs image to the kernel, it will reside in the last
+	# erase block of the kernel partition
+	cat $(KDIR_TMP)/fakeroot-$(2).uImage >> $(KDIR_TMP)/vmlinux-$(2).uImage
+endef
+
+
+# $(1): rootfs image suffix
+# $(2): Board name (small caps)
+# $(3): Kernel board specific cmdline
+# $(4): Kernel mtdparts definition
+# $(5): U-Boot magic
+# $(6): Board name (upper caps)
+# $(7): firmware region code (not used yet)
+# $(8): DNI Hardware version
+# $(9): suffix of the configuration file for ubinize
+define Image/Build/NetgearNAND
+	$(eval firmwaresize=$(call mtdpartsize,firmware,$(4)))
+	$(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
+	$(eval imageraw=$(KDIR_TMP)/$(2)-raw.img)
+	$(CP) $(KDIR)/root.squashfs-raw $(KDIR_TMP)/root.squashfs
+	echo -ne '\xde\xad\xc0\xde' > $(KDIR_TMP)/jffs2.eof
+	$(call ubinize,ubinize-$(9).ini,$(KDIR_TMP),$(KDIR_TMP)/$(2)-root.ubi,128KiB,2048,-E 5)
+	( \
+		dd if=$(KDIR_TMP)/vmlinux-$(2).uImage; \
+		dd if=$(KDIR_TMP)/$(2)-root.ubi \
+	) > $(imageraw)
+	$(STAGING_DIR_HOST)/bin/mkdniimg \
+		-B $(6) -v OpenWrt.$(REVISION) -r "$$r" $(8) \
+		-i $(imageraw) \
+		-o $(call imgname,ubi,$(2))-factory.img
+
+	$(call Image/Build/SysupgradeNAND,$(2),squashfs,$(KDIR_TMP)/vmlinux-$(2).uImage)
+endef
+
+
+ifdef CONFIG_PACKAGE_uboot-ar71xx-nbg460n_550n_550nh
+  Image/Build/ZyXEL/buildkernel=$(call MkuImageLzma,$(2),$(3))
+
+  define Image/Build/ZyXEL
+	$(call Sysupgrade/KRuImage,$(1),$(2),917504,2752512)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		if [ ! -f $(BIN_DIR)/$(IMG_PREFIX)-$(2)-u-boot.bin ]; then \
+			echo "Warning: $(IMG_PREFIX)-$(2)-u-boot.bin not found" >&2; \
+		else \
+			$(STAGING_DIR_HOST)/bin/mkzynfw \
+				-B $(4) \
+				-b $(BIN_DIR)/$(IMG_PREFIX)-$(2)-u-boot.bin \
+				-r $(call sysupname,$(1),$(2)):0x10000 \
+				-o $(call factoryname,$(1),$(2)); \
+	fi; fi
+  endef
+endif
+
+define	Image/Build/ZyXELNAND/buildkernel
+	$(eval kernelsize=$(call mtdpartsize,kernel,$(5)))
+	$(call MkuImageLzma,$(2),$(3) $(5) $(6))
+	mkdir -p $(KDIR_TMP)/$(2)/image/boot
+	cp $(KDIR_TMP)/vmlinux-$(2).uImage $(KDIR_TMP)/$(2)/image/boot/vmlinux.lzma.uImage
+	$(STAGING_DIR_HOST)/bin/mkfs.jffs2 \
+		--pad=$(kernelsize) --big-endian --squash-uids -v -e 128KiB \
+		-o $(KDIR_TMP)/$(2)-kernel.jffs2 \
+		-d $(KDIR_TMP)/$(2)/image \
+		2>&1 1>/dev/null | awk '/^.+$$/'
+	-rm -rf $(KDIR_TMP)/$(2)
+endef
+
+define Image/Build/ZyXELNAND
+	if [ "$(1)" != "squashfs" ]; then \
+		echo Only squashfs is supported; \
+		return 0; \
+	fi
+	$(eval firmwaresize=$(call mtdpartsize,firmware,$(4)))
+	$(eval kernelsize=$(call mtdpartsize,kernel,$(4)))
+	$(eval imageraw=$(KDIR_TMP)/$(2)-raw.img)
+	$(CP) $(KDIR)/root.$(1) $(KDIR_TMP)/ubi_root.img
+	$(call ubinize,ubinize-$(2).ini,$(KDIR_TMP),$(KDIR_TMP)/$(2)-root.ubi,128KiB,2048,-E 5)
+	( \
+		dd if=$(KDIR_TMP)/$(2)-kernel.jffs2; \
+		dd if=$(KDIR_TMP)/$(2)-root.ubi \
+	) > $(imageraw)
+	dd if=$(imageraw) of=$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1)-factory.bin \
+		bs=128k conv=sync
+	$(call Image/Build/SysupgradeNAND,$(2),squashfs,$(KDIR_TMP)/$(2)-kernel.jffs2)
+endef
+
+
+Image/Build/OpenMesh/buildkernel=$(call MkuImageLzma,$(2))
+Image/Build/OpenMesh/initramfs=$(call MkuImageLzma/initramfs,$(2),)
+
+define Image/Build/OpenMesh
+	-sh $(TOPDIR)/scripts/om-fwupgradecfg-gen.sh \
+		"$(4)" \
+		"$(BUILD_DIR)/fwupgrade.cfg-$(4)" \
+		"$(KDIR_TMP)/vmlinux-$(2).uImage" \
+		"$(KDIR)/root.$(1)"
+	-sh $(TOPDIR)/scripts/combined-ext-image.sh \
+		"$(4)" "$(call factoryname,$(1),$(2))" \
+		"$(BUILD_DIR)/fwupgrade.cfg-$(4)" "fwupgrade.cfg" \
+		"$(KDIR_TMP)/vmlinux-$(2).uImage" "kernel" \
+		"$(KDIR)/root.$(1)" "rootfs"
+	if [ -e "$(call factoryname,$(1),$(2))" ]; then \
+		cp "$(call factoryname,$(1),$(2))" "$(call sysupname,$(1),$(2))"; \
+	fi
+endef
+
+
+Image/Build/Zcomax/buildkernel=$(call MkuImageLzma,$(2),$(3) $(4))
+Image/Build/Zcomax/initramfs=$(call MkuImageLzma/initramfs,$(2),$(3) $(4))
+
+define Image/Build/Zcomax
+	$(call Sysupgrade/RKuImage,$(1),$(2),1507328,6356992)
+	if [ -e "$(call sysupname,$(1),$(2))" ]; then \
+		$(STAGING_DIR_HOST)/bin/mkzcfw \
+			-B $(2) \
+			-k $(KDIR_TMP)/vmlinux-$(2).uImage \
+			-r $(KDIR)/root.$(1) \
+			-o $(call imgname,$(1),$(2))-factory.img; \
+	fi
+endef
+
+
+# $(1): template name to be defined.
+# $(2): squashfs suffix to be used.
+define BuildTemplate
+  # $(1)     : name of build method.
+  # $(2)     : board name.
+  # $(3)     : kernel command line.
+  # $(4)~$(8): extra arguments.
+  define Image/Build/Template/$(1)/initramfs
+    $$(call Image/Build/$$(1)/initramfs,initramfs,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+  endef
+  define Image/Build/Template/$(1)/loader
+    $$(call Image/Build/$$(1)/loader,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+  endef
+  define Image/Build/Template/$(1)/buildkernel
+    $$(call Image/Build/$$(1)/buildkernel,,$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+  endef
+  define Image/Build/Template/$(1)/squashfs
+    $$(call Image/Build/$$(1),squashfs$(2),$$(2),$$(3),$$(4),$$(5),$$(6),$$(7),$$(8),$$(9),$$(10))
+  endef
+endef
+
+$(eval $(call BuildTemplate,squashfs-only))
+$(eval $(call BuildTemplate,64k,-64k))
+$(eval $(call BuildTemplate,64kraw,-raw))
+$(eval $(call BuildTemplate,64kraw-nojffs,-raw))
+$(eval $(call BuildTemplate,128k))
+$(eval $(call BuildTemplate,128kraw,-raw))
+$(eval $(call BuildTemplate,256k))
+$(eval $(call BuildTemplate,all))
+
+ifeq ($(SUBTARGET),generic)
+$(eval $(call SingleProfile,ALFA,64k,ALFANX,alfa-nx,ALFA-NX,ttyS0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,vmlinux.gz.uImage,pb9x-2.6.31-jffs2))
+$(eval $(call SingleProfile,ALFA,64k,HORNETUB,hornet-ub,HORNET-UB,ttyATH0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,kernel_image,rootfs_image))
+$(eval $(call SingleProfile,ALFA,64k,TUBE2H8M,tube2h-8M,TUBE2H,ttyATH0,115200,$$(alfa_mtdlayout_8M),1638400,6291456,kernel.image,rootfs.image))
+
+$(eval $(call SingleProfile,AthGzip,64k,AP81,ap81,AP81,ttyS0,115200,$$(ap81_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthGzip,64k,AP83,ap83,AP83,ttyS0,115200,$$(ap83_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthGzip,64k,AP96,ap96,AP96,ttyS0,115200,$$(ap96_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthGzip,64k,WNDAP360,wndap360,WNDAP360,ttyS0,9600,$$(wndap360_mtdlayout),KRuImage))
+
+$(eval $(call SingleProfile,AthLzma,64k,ALFAAP120C,alfa-ap120c,ALFA-AP120C,ttyS0,115200,$$(alfa_ap120c_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,ALFAAP96,alfa-ap96,ALFA-AP96,ttyS0,115200,$$(alfa_ap96_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,ALL0258N,all0258n,ALL0258N,ttyS0,115200,$$(all0258n_mtdlayout),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,256k,ALL0315N,all0315n,ALL0315N,ttyS0,115200,$$(all0315n_mtdlayout),KRuImage,262144))
+$(eval $(call SingleProfile,AthLzma,64k,AP121_8M,ap121-8M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_8M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP121_16M,ap121-16M,AP121,ttyATH0,115200,$$(ap121_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP132,ap132,AP132,ttyS0,115200,$$(ap132_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP135,ap135-020,AP135-020,ttyS0,115200,$$(ap135_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP136_010,ap136-010,AP136-010,ttyS0,115200,$$(ap136_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP136_020,ap136-020,AP136-020,ttyS0,115200,$$(ap136_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP143_8M,ap143-8M,AP143,ttyS0,115200,$$(ap143_mtdlayout_8M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP143_16M,ap143-16M,AP143,ttyS0,115200,$$(ap143_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP147_010,ap147-010,AP147-010,ttyS0,115200,$$(ap147_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,AP152_16M,ap152-16M,AP152,ttyS0,115200,$$(ap152_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,BXU2000N2,bxu2000n-2-a1,BXU2000n-2-A1,ttyS0,115200,$$(bxu2000n2_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,CAP4200AG,cap4200ag,CAP4200AG,ttyS0,115200,$$(cap4200ag_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,DB120,db120,DB120,ttyS0,115200,$$(db120_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,EWDORINAP,ew-dorin,EW-DORIN,ttyATH0,115200,$$(ew-dorin_mtdlayout_4M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,EWDORINRT,ew-dorin-router,EW-DORIN-ROUTER,ttyATH0,115200,$$(ew-dorin_mtdlayout_4M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,EWDORIN16M,ew-dorin-16M,EW-DORIN,ttyATH0,115200,$$(ew-dorin_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,HORNETUBx2,hornet-ub-x2,HORNET-UB,ttyATH0,115200,$$(alfa_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,TUBE2H16M,tube2h-16M,TUBE2H,ttyATH0,115200,$$(alfa_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WLR8100,wlr8100,WLR8100,ttyS0,115200,$$(wlr8100_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ342_16M,wpj342-16M,WPJ342,ttyS0,115200,$$(wpj342_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ344_16M,wpj344-16M,WPJ344,ttyS0,115200,$$(wpj344_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,DR344,dr344,DR344,ttyS0,115200,$$(dr344_mtdlayout),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ531_16M,wpj531-16M,WPJ531,ttyS0,115200,$$(wpj531_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WPJ558_16M,wpj558-16M,WPJ558,ttyS0,115200,$$(wpj558_mtdlayout_16M),KRuImage,65536))
+$(eval $(call SingleProfile,AthLzma,64k,WRTNODE2Q,wrtnode2q,WRTNODE2Q,ttyS0,115200,$$(wrtnode2q_mtdlayout),KRuImage))
+$(eval $(call SingleProfile,AthLzma,64k,YUN_8M,yun-8M,Yun,ttyATH0,250000,$$(yun_mtdlayout_8M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,YUN_16M,yun-16M,Yun,ttyATH0,250000,$$(yun_mtdlayout_16M),RKuImage))
+$(eval $(call SingleProfile,AthLzma,64k,ZBTWE1526,zbt-we1526,ZBT-WE1526,ttyS0,115200,$$(ap147_mtdlayout),RKuImage))
+
+$(eval $(call SingleProfile,Belkin,64k,F9K1115V2,f9k1115v2,F9K1115V2,ttyS0,115200,$$(f9k1115v2_mtdlayout),BR-6679BAC))
+
+$(eval $(call SingleProfile,CameoAP91,64kraw,DIR600A1,dir-600-a1,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-00"))
+$(eval $(call SingleProfile,CameoAP91,64kraw,DIR601A1,dir-601-a1,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-02"))
+$(eval $(call SingleProfile,CameoAP91,64kraw,FR54RTR,fr-54rtr,DIR-600-A1,ttyS0,115200,"AP91-AR7240-RT-090223-01"))
+
+$(eval $(call SingleProfile,CameoAP99,64kraw,DIR615E1,dir-615-e1,DIR-615-E1,ttyS0,115200,"AP93-AR7240-RT-081028-00"))
+$(eval $(call SingleProfile,CameoAP99,64kraw,DIR615E4,dir-615-e4,DIR-615-E4,ttyS0,115200,"AP99-AR7240-RT-091105-05"))
+
+$(eval $(call SingleProfile,CameoAP123_4M,64kraw,DIR615I1,dir-615-i1,DIR-615-I1,ttyS0,115200,"00DB120AR9341-RT-1012I1-00"))
+$(eval $(call SingleProfile,CameoAP123_4M,64kraw,DIR615I3,dir-615-i3,DIR-615-I1,ttyS0,115200,"00DB120AR9341-RT-101214-00"))
+
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,A02RBW300N,a02-rb-w300n,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-03"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,DIR615C1,dir-615-c1,DIR-615-C1,ttyS0,115200,"AP81-AR9130-RT-070614-02"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW632BRP,tew-632brp,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-00"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW652BRP_FW,tew-652brp,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-080609-05"))
+$(eval $(call SingleProfile,CameoAP81,64kraw-nojffs,TEW652BRP_RECOVERY,tew-652brp-recovery,TEW-632BRP,ttyS0,115200,"AP81-AR9130-RT-070614-02"))
+
+$(eval $(call SingleProfile,CameoAP121,64kraw-nojffs,TEW712BR,tew-712br,TEW-712BR,ttyATH0,115200,"HORNET-RT-TEW712BR-3",1.99,""))
+$(eval $(call SingleProfile,CameoAP121,64kraw-nojffs,DIR601B1,dir-601-b1,TEW-712BR,ttyATH0,115200,"HORNET-RT-DIR601B1-3",2.99.99,"" "NA"))
+$(eval $(call SingleProfile,CameoAP121_8M,64kraw-nojffs,DIR505A1,dir-505-a1,DIR-505-A1,ttyATH0,115200,"HORNET-PACKET-DIR505A1-3",1.99.99,""))
+
+$(eval $(call SingleProfile,CameoAP135,64kraw,DGL5500A1,dgl-5500-a1,DGL-5500-A1,ttyS0,115200,$$(dgl_5500_mtdlayout),"00AP135AR9558-RT-130508-00"))
+$(eval $(call SingleProfile,CameoAP135,64kraw,TEW823DRU,tew-823dru,TEW-823DRU,ttyS0,115200,$$(tew823dru_mtdlayout) mem=256M,"00AP135AR9558-RT-131129-00"))
+
+$(eval $(call SingleProfile,CameoDB120,64kraw,DHP1565A1,dhp-1565-a1,DHP-1565-A1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
+$(eval $(call SingleProfile,CameoDB120,64kraw,DIR825C1,dir-825-c1,DIR-825-C1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
+$(eval $(call SingleProfile,CameoDB120,64kraw,DIR835A1,dir-835-a1,DIR-835-A1,ttyS0,115200,"00DB120AR9344-RT-101214-00"))
+
+$(eval $(call SingleProfile,CameoDB120_8M,64kraw,TEW732BR,tew-732br,TEW-732BR,ttyS0,115200,"00DB120AR9341-RT-120906-NA"))
+
+$(eval $(call SingleProfile,CyberTANGZIP,64k,WRT160NL,wrt160nl,WRT160NL,ttyS0,115200,,1.00.01))
+
+$(eval $(call SingleProfile,CyberTANLZMA,64k,MYNETREXT,mynet-rext,MYNET-REXT,ttyS0,115200,$$(mynet_rext_mtdlayout) root=31:2,1.00.01))
+
+$(eval $(call SingleProfile,CameoAP94,64kraw,DIR825B1,dir-825-b1,DIR-825-B1,ttyS0,115200,$$(cameo_ap94_mtdlayout),$$(cameo_ap94_mtdlayout_fat),01AP94-AR7161-RT-080619-00,00AP94-AR7161-RT-080619-00))
+$(eval $(call SingleProfile,CameoAP94,64kraw,TEW673GRU,tew-673gru,TEW-673GRU,ttyS0,115200,$$(cameo_ap94_mtdlayout),$$(cameo_ap94_mtdlayout_fat),01AP94-AR7161-RT-080619-01,00AP94-AR7161-RT-080619-01))
+$(eval $(call SingleProfile,CameoAP94,64kraw,DLRTDEV01,dlrtdev01,DIR-825-B1,ttyS0,115200,$$(dlrtdev_mtdlayout),$$(dlrtdev_mtdlayout_fat),01AP94-AR7161-RT-080619-00,00AP94-AR7161-RT-080619-00))
+
+$(eval $(call SingleProfile,dLANLzma,64k,dLAN_Hotspot,dlan-hotspot,dLAN-Hotspot,ttyATH0,115200,$$(dlan_hotspot_mtdlayout) mem=64M,KRuImage,65536))
+$(eval $(call SingleProfile,dLANLzma,64k,dLAN_pro_500_wp,dlan-pro-500-wp,dLAN-pro-500-wp,ttyS0,115200,$$(dlan_pro_500_wp_mtdlayout) mem=128M,KRuImage,65536))
+$(eval $(call SingleProfile,dLANLzma,64k,dLAN_pro_1200_ac,dlan-pro-1200-ac,dLAN-pro-1200-ac,ttyS0,115200,$$(dlan_pro_1200_ac_mtdlayout) mem=128M,KRuImage,65536))
+
+$(eval $(call SingleProfile,EnGenius,64k,ESR900,esr900,ESR900,ttyS0,115200,$$(esr900_mtdlayout),KRuImage,,0x4e))
+$(eval $(call SingleProfile,EnGenius,64k,ESR1750,esr1750,ESR1750,ttyS0,115200,$$(esr1750_mtdlayout),KRuImage,,0x61))
+$(eval $(call SingleProfile,EnGenius,64k,EPG5000,epg5000,EPG5000,ttyS0,115200,$$(epg5000_mtdlayout),KRuImage,,0x71))
+
+$(eval $(call SingleProfile,MyLoader,64k,WP543_4M,wp543,,ttyS0,115200,0x400000,4M))
+$(eval $(call SingleProfile,MyLoader,64k,WP543_8M,wp543,,ttyS0,115200,0x800000,8M))
+$(eval $(call SingleProfile,MyLoader,64k,WP543_16M,wp543,,ttyS0,115200,0x1000000,16M))
+$(eval $(call SingleProfile,MyLoader,64k,WPE72_4M,wpe72,,ttyS0,115200,0x400000,4M))
+$(eval $(call SingleProfile,MyLoader,64k,WPE72_8M,wpe72,,ttyS0,115200,0x800000,8M))
+$(eval $(call SingleProfile,MyLoader,64k,WPE72_16M,wpe72,,ttyS0,115200,0x1000000,16M))
+
+$(eval $(call SingleProfile,Netgear,64kraw,WNR2000V3,wnr2000v3,WNR2000V3,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303033,WNR2000V3,"" NA,-H 29763551+04+32))
+$(eval $(call SingleProfile,NetgearLzma,64kraw,WNR2000V4,wnr2000v4,WNR2000V4,ttyS0,115200,$$(wnr2000v4_mtdlayout),0x32303034,WNR2000V4,"" NA,))
+$(eval $(call SingleProfile,Netgear,64kraw,WNR2200,wnr2200,WNR2200,ttyS0,115200,$$(wnr2200_mtdlayout),0x32323030,wnr2200,"" NA,))
+$(eval $(call SingleProfile,Netgear,64kraw,REALWNR612V2,wnr612v2,WNR612V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303631,WNR612V2,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,N150R,n150r,WNR612V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x32303631,N150R,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,REALWNR1000V2,wnr1000v2,WNR1000V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31303031,WNR1000V2,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,WNR1000V2_VC,wnr1000v2-vc,WNR1000V2,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31303030,WNR1000V2-VC,"",))
+$(eval $(call SingleProfile,Netgear,64kraw,WPN824N,wpn824n,WPN824N,ttyS0,115200,$$(wnr2000v3_mtdlayout),0x31313030,WPN824N,"" NA,))
+
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM2P,om2p,,,,OM2P))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM5P,om5p,,,,OM5P))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,OM5PAC,om5pac,,,,OM5PAC))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR600,mr600,,,,MR600))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR900,mr900,,,,MR900))
+$(eval $(call SingleProfile,OpenMesh,squashfs-only,MR1750,mr1750,,,,MR1750))
+
+$(eval $(call SingleProfile,PB4X,128k,ALL0305,all0305,ALL0305,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,128k,EAP7660D,eap7660d,EAP7660D,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,JA76PF,ja76pf,JA76PF,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,JA76PF2,ja76pf2,JA76PF2,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,JWAP003,jwap003,JWAP003,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,PB42,pb42,PB42,ttyS0,115200))
+$(eval $(call SingleProfile,PB4X,64k,PB44,pb44,PB44,ttyS0,115200))
+
+$(eval $(call SingleProfile,Planex,64kraw,MZKW04NU,mzk-w04nu,MZK-W04NU,ttyS0,115200))
+$(eval $(call SingleProfile,Planex,64kraw,MZKW300NH,mzk-w300nh,MZK-W300NH,ttyS0,115200))
+
+$(eval $(call SingleProfile,Senao,squashfs-only,EAP300V2,eap300v2,EAP300V2,ttyS0,115200,$$(eap300v2_mtdlayout)))
+
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRG301N,whr-g301n,WHR-G301N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-G301N))
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPG300N,whr-hp-g300n,WHR-HP-G300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-HP-G300N))
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPGN,whr-hp-gn,WHR-HP-GN,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-HP-GN))
+$(eval $(call SingleProfile,WHRHPG300N,64kraw,WLAEAG300N,wlae-ag300n,WLAE-AG300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WLAE-AG300N))
+
+$(eval $(call SingleProfile,WRT400N,64k,WRT400N,wrt400n,WRT400N,ttyS0,115200))
+
+$(eval $(call SingleProfile,WZRHP128K,128kraw,WZRHPG300NH,wzr-hp-g300nh,WZR-HP-G300NH,ttyS0,115200,WZR-HP-G300NH))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG300NH2,wzr-hp-g300nh2,WZR-HP-G300NH2,ttyS0,115200,WZR-HP-G300NH2))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPAG300H,wzr-hp-ag300h,WZR-HP-AG300H,ttyS0,115200,WZR-HP-AG300H))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG450H,wzr-hp-g450h,WZR-HP-G450H,ttyS0,115200,WZR-HP-AG450H))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZR600DHP,wzr-600dhp,WZR-HP-AG300H,ttyS0,115200,WZR-600DHP))
+$(eval $(call SingleProfile,WZRHP64K,64kraw,WZR450HP2,wzr-450hp2,WZR-450HP2,ttyS0,115200,WZR-450HP2))
+
+$(eval $(call SingleProfile,Zcomax,64k,ZCN1523H28,zcn-1523h-2-8,ZCN-1523H-2,ttyS0,115200,$$(zcn1523h_mtdlayout)))
+$(eval $(call SingleProfile,Zcomax,64k,ZCN1523H516,zcn-1523h-5-16,ZCN-1523H-5,ttyS0,115200,$$(zcn1523h_mtdlayout)))
+
+$(eval $(call SingleProfile,ZyXEL,64k,NBG_460N_550N_550NH,nbg460n_550n_550nh,NBG460N,ttyS0,115200,NBG-460N))
+
+endif # ifeq ($(SUBTARGET),generic)
+
+ifeq ($(SUBTARGET),nand)
+
+$(eval $(call SingleProfile,NetgearNAND,64k,WNDR3700V4,wndr3700v4,WNDR3700_V4,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR3700v4,"",-H 29763948+128+128,wndr4300))
+$(eval $(call SingleProfile,NetgearNAND,64k,WNDR4300V1,wndr4300,WNDR4300,ttyS0,115200,$$(wndr4300_mtdlayout),0x33373033,WNDR4300,"",-H 29763948+0+128+128+2x2+3x3,wndr4300))
+$(eval $(call SingleProfile,NetgearNAND,64k,R6100,r6100,R6100,ttyS0,115200,$$(r6100_mtdlayout),0x36303030,R6100,"",-H 29764434+0+128+128+2x2+2x2,wndr4300))
+
+$(eval $(call SingleProfile,ZyXELNAND,128k,NBG6716,nbg6716,NBG6716,ttyS0,115200,NBG6716,$$(zyx_nbg6716_mtdlayout),mem=256M))
+
+endif # ifeq ($(SUBTARGET),nand)
+
+define Image/Build/squashfs
+	cp $(KDIR)/root.squashfs $(KDIR)/root.squashfs-raw
+	cp $(KDIR)/root.squashfs $(KDIR)/root.squashfs-64k
+	$(STAGING_DIR_HOST)/bin/padjffs2 $(KDIR)/root.squashfs-64k 64
+	$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
+	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
+endef
+
+define Image/Prepare
+	$(call CompressLzma,$(KDIR)/vmlinux,$(KDIR)/vmlinux.bin.lzma)
+ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+	$(call CompressLzma,$(KDIR)/vmlinux-initramfs,$(KDIR)/vmlinux-initramfs.bin.lzma)
+	$(call Image/BuildLoader,generic,elf,,,-initramfs)
+endif
+	$(call Image/BuildLoader,generic,elf)
+endef
+
+define Image/Prepare/Profile
+	$(call Image/Build/Profile/$(1),loader)
+endef
+
+define Image/Build/Profile
+	$(call Image/Build/Profile/$(1),buildkernel)
+	$(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(call Image/Build/Profile/$(1),initramfs))
+	$(call Image/Build/Profile/$(1),$(2))
+endef
+
+# $(1): filesystem type.
+define Image/Build
+	$(call Image/Build/$(call rootfs_type,$(1)),$(1))
+endef
diff --git a/target/linux/ar71xx/image/lzma-loader/Makefile b/target/linux/ar71xx/image/lzma-loader/Makefile
new file mode 100644
index 0000000000..9b81e87306
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/Makefile
@@ -0,0 +1,66 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+# Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+LZMA_TEXT_START	:= 0x80a00000
+LOADADDR	:= 0x80060000
+LOADER		:= loader.bin
+LOADER_NAME	:= $(basename $(notdir $(LOADER)))
+LOADER_DATA 	:=
+TARGET_DIR	:=
+FLASH_OFFS	:=
+FLASH_MAX	:=
+BOARD		:=
+
+ifeq ($(TARGET_DIR),)
+TARGET_DIR	:= $(KDIR)
+endif
+
+LOADER_BIN	:= $(TARGET_DIR)/$(LOADER_NAME).bin
+LOADER_GZ	:= $(TARGET_DIR)/$(LOADER_NAME).gz
+LOADER_ELF	:= $(TARGET_DIR)/$(LOADER_NAME).elf
+
+PKG_NAME := lzma-loader
+PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)
+
+.PHONY : loader-compile loader.bin loader.elf loader.gz
+
+$(PKG_BUILD_DIR)/.prepared:
+	mkdir $(PKG_BUILD_DIR)
+	$(CP) ./src/* $(PKG_BUILD_DIR)/
+	touch $@
+
+loader-compile: $(PKG_BUILD_DIR)/.prepared
+	$(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \
+		LZMA_TEXT_START=$(LZMA_TEXT_START) \
+		LOADADDR=$(LOADADDR) \
+		LOADER_DATA=$(LOADER_DATA) \
+		FLASH_OFFS=$(FLASH_OFFS) \
+		FLASH_MAX=$(FLASH_MAX) \
+		BOARD="$(BOARD)" \
+		clean all
+
+loader.gz: $(PKG_BUILD_DIR)/loader.bin
+	gzip -nc9 $< > $(LOADER_GZ)
+
+loader.elf: $(PKG_BUILD_DIR)/loader.elf
+	$(CP) $< $(LOADER_ELF)
+
+loader.bin: $(PKG_BUILD_DIR)/loader.bin
+	$(CP) $< $(LOADER_BIN)
+
+download:
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: loader-compile
+
+install:
+
+clean:
+	rm -rf $(PKG_BUILD_DIR)
+
diff --git a/target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.c b/target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.c
new file mode 100644
index 0000000000..cb8345377e
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.c
@@ -0,0 +1,584 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+ 
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.h b/target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.h
new file mode 100644
index 0000000000..2870eeb9c9
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/LzmaDecode.h
@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/target/linux/ar71xx/image/lzma-loader/src/LzmaTypes.h b/target/linux/ar71xx/image/lzma-loader/src/LzmaTypes.h
new file mode 100644
index 0000000000..9c27290757
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/LzmaTypes.h
@@ -0,0 +1,45 @@
+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif
diff --git a/target/linux/ar71xx/image/lzma-loader/src/Makefile b/target/linux/ar71xx/image/lzma-loader/src/Makefile
new file mode 100644
index 0000000000..5f10bdb8f1
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/Makefile
@@ -0,0 +1,106 @@
+#
+# Makefile for the LZMA compressed kernel loader for
+# Atheros AR7XXX/AR9XXX based boards
+#
+# Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+#
+# Some parts of this file was based on the OpenWrt specific lzma-loader
+# for the BCM47xx and ADM5120 based boards:
+#	Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
+#	Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
+#	Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+#
+# 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.
+#
+
+LOADADDR	:=
+LZMA_TEXT_START	:= 0x80a00000
+LOADER_DATA	:=
+BOARD		:=
+FLASH_OFFS	:=
+FLASH_MAX	:=
+
+CC		:= $(CROSS_COMPILE)gcc
+LD		:= $(CROSS_COMPILE)ld
+OBJCOPY		:= $(CROSS_COMPILE)objcopy
+OBJDUMP		:= $(CROSS_COMPILE)objdump
+
+BIN_FLAGS	:= -O binary -R .reginfo -R .note -R .comment -R .mdebug \
+		   -R .MIPS.abiflags -S
+
+CFLAGS		= -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
+		  -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \
+		  -mno-abicalls -fno-pic -ffunction-sections -pipe -mlong-calls \
+		  -fno-common -ffreestanding -fhonour-copts \
+		  -mabi=32 -march=mips32r2 \
+		  -Wa,-32 -Wa,-march=mips32r2 -Wa,-mips32r2 -Wa,--trap
+CFLAGS		+= -D_LZMA_PROB32
+
+ASFLAGS		= $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS		= -static --gc-sections -no-warn-mismatch
+LDFLAGS		+= -e startup -T loader.lds -Ttext $(LZMA_TEXT_START)
+
+O_FORMAT 	= $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+
+OBJECTS		:= head.o loader.o cache.o board.o printf.o LzmaDecode.o
+
+ifneq ($(strip $(LOADER_DATA)),)
+OBJECTS		+= data.o
+CFLAGS		+= -DLZMA_WRAPPER=1 -DLOADADDR=$(LOADADDR)
+endif
+
+ifneq ($(strip $(KERNEL_CMDLINE)),)
+CFLAGS		+= -DCONFIG_KERNEL_CMDLINE='"$(KERNEL_CMDLINE)"'
+endif
+
+ifneq ($(strip $(FLASH_OFFS)),)
+CFLAGS		+= -DCONFIG_FLASH_OFFS=$(FLASH_OFFS)
+endif
+
+ifneq ($(strip $(FLASH_MAX)),)
+CFLAGS		+= -DCONFIG_FLASH_MAX=$(FLASH_MAX)
+endif
+
+BOARD_DEF := $(shell echo $(strip $(BOARD)) | tr a-z A-Z | tr - _)
+ifneq ($(BOARD_DEF),)
+CFLAGS		+= -DCONFIG_BOARD_$(BOARD_DEF)
+endif
+
+all: loader.elf
+
+# Don't build dependencies, this may die if $(CC) isn't gcc
+dep:
+
+install:
+
+%.o : %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.o : %.S
+	$(CC) $(ASFLAGS) -c -o $@ $<
+
+data.o: $(LOADER_DATA)
+	$(LD) -r -b binary --oformat $(O_FORMAT) -T lzma-data.lds -o $@ $<
+
+loader: $(OBJECTS)
+	$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
+
+loader.bin: loader
+	$(OBJCOPY) $(BIN_FLAGS) $< $@
+
+loader2.o: loader.bin
+	$(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $<
+
+loader.elf: loader2.o
+	$(LD) -e startup -T loader2.lds -Ttext $(LOADADDR) -o $@ $<
+
+mrproper: clean
+
+clean:
+	rm -f loader *.elf *.bin *.o
+
+
+
diff --git a/target/linux/ar71xx/image/lzma-loader/src/ar71xx_regs.h b/target/linux/ar71xx/image/lzma-loader/src/ar71xx_regs.h
new file mode 100644
index 0000000000..19a4785bb4
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/ar71xx_regs.h
@@ -0,0 +1,725 @@
+/*
+ *  Atheros AR71XX/AR724X/AR913X SoC register definitions
+ *
+ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
+ *
+ *  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.
+ */
+
+#ifndef __ASM_MACH_AR71XX_REGS_H
+#define __ASM_MACH_AR71XX_REGS_H
+
+#define BIT(_x)			(1UL << (_x))
+
+#define AR71XX_APB_BASE		0x18000000
+#define AR71XX_GE0_BASE		0x19000000
+#define AR71XX_GE0_SIZE		0x10000
+#define AR71XX_GE1_BASE		0x1a000000
+#define AR71XX_GE1_SIZE		0x10000
+#define AR71XX_EHCI_BASE	0x1b000000
+#define AR71XX_EHCI_SIZE	0x1000
+#define AR71XX_OHCI_BASE	0x1c000000
+#define AR71XX_OHCI_SIZE	0x1000
+#define AR71XX_SPI_BASE		0x1f000000
+#define AR71XX_SPI_SIZE		0x01000000
+
+#define AR71XX_DDR_CTRL_BASE	(AR71XX_APB_BASE + 0x00000000)
+#define AR71XX_DDR_CTRL_SIZE	0x100
+#define AR71XX_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
+#define AR71XX_UART_SIZE	0x100
+#define AR71XX_USB_CTRL_BASE	(AR71XX_APB_BASE + 0x00030000)
+#define AR71XX_USB_CTRL_SIZE	0x100
+#define AR71XX_GPIO_BASE        (AR71XX_APB_BASE + 0x00040000)
+#define AR71XX_GPIO_SIZE        0x100
+#define AR71XX_PLL_BASE		(AR71XX_APB_BASE + 0x00050000)
+#define AR71XX_PLL_SIZE		0x100
+#define AR71XX_RESET_BASE	(AR71XX_APB_BASE + 0x00060000)
+#define AR71XX_RESET_SIZE	0x100
+#define AR71XX_MII_BASE		(AR71XX_APB_BASE + 0x00070000)
+#define AR71XX_MII_SIZE		0x100
+
+#define AR71XX_PCI_MEM_BASE	0x10000000
+#define AR71XX_PCI_MEM_SIZE	0x07000000
+
+#define AR71XX_PCI_WIN0_OFFS	0x10000000
+#define AR71XX_PCI_WIN1_OFFS	0x11000000
+#define AR71XX_PCI_WIN2_OFFS	0x12000000
+#define AR71XX_PCI_WIN3_OFFS	0x13000000
+#define AR71XX_PCI_WIN4_OFFS	0x14000000
+#define AR71XX_PCI_WIN5_OFFS	0x15000000
+#define AR71XX_PCI_WIN6_OFFS	0x16000000
+#define AR71XX_PCI_WIN7_OFFS	0x07000000
+
+#define AR71XX_PCI_CFG_BASE	\
+	(AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000)
+#define AR71XX_PCI_CFG_SIZE	0x100
+
+#define AR7240_USB_CTRL_BASE	(AR71XX_APB_BASE + 0x00030000)
+#define AR7240_USB_CTRL_SIZE	0x100
+#define AR7240_OHCI_BASE	0x1b000000
+#define AR7240_OHCI_SIZE	0x1000
+
+#define AR724X_PCI_MEM_BASE	0x10000000
+#define AR724X_PCI_MEM_SIZE	0x04000000
+
+#define AR724X_PCI_CFG_BASE	0x14000000
+#define AR724X_PCI_CFG_SIZE	0x1000
+#define AR724X_PCI_CRP_BASE	(AR71XX_APB_BASE + 0x000c0000)
+#define AR724X_PCI_CRP_SIZE	0x1000
+#define AR724X_PCI_CTRL_BASE	(AR71XX_APB_BASE + 0x000f0000)
+#define AR724X_PCI_CTRL_SIZE	0x100
+
+#define AR724X_EHCI_BASE	0x1b000000
+#define AR724X_EHCI_SIZE	0x1000
+
+#define AR913X_EHCI_BASE	0x1b000000
+#define AR913X_EHCI_SIZE	0x1000
+#define AR913X_WMAC_BASE	(AR71XX_APB_BASE + 0x000C0000)
+#define AR913X_WMAC_SIZE	0x30000
+
+#define AR933X_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
+#define AR933X_UART_SIZE	0x14
+#define AR933X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
+#define AR933X_GMAC_SIZE	0x04
+#define AR933X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+#define AR933X_WMAC_SIZE	0x20000
+#define AR933X_EHCI_BASE	0x1b000000
+#define AR933X_EHCI_SIZE	0x1000
+
+#define AR934X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
+#define AR934X_GMAC_SIZE	0x14
+#define AR934X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+#define AR934X_WMAC_SIZE	0x20000
+#define AR934X_EHCI_BASE	0x1b000000
+#define AR934X_EHCI_SIZE	0x200
+
+#define QCA955X_PCI_MEM_BASE0	0x10000000
+#define QCA955X_PCI_MEM_BASE1	0x12000000
+#define QCA955X_PCI_MEM_SIZE	0x02000000
+#define QCA955X_PCI_CFG_BASE0	0x14000000
+#define QCA955X_PCI_CFG_BASE1	0x16000000
+#define QCA955X_PCI_CFG_SIZE	0x1000
+#define QCA955X_PCI_CRP_BASE0	(AR71XX_APB_BASE + 0x000c0000)
+#define QCA955X_PCI_CRP_BASE1	(AR71XX_APB_BASE + 0x00250000)
+#define QCA955X_PCI_CRP_SIZE	0x1000
+#define QCA955X_PCI_CTRL_BASE0	(AR71XX_APB_BASE + 0x000f0000)
+#define QCA955X_PCI_CTRL_BASE1	(AR71XX_APB_BASE + 0x00280000)
+#define QCA955X_PCI_CTRL_SIZE	0x100
+
+#define QCA955X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+#define QCA955X_WMAC_SIZE	0x20000
+#define QCA955X_EHCI0_BASE	0x1b000000
+#define QCA955X_EHCI1_BASE	0x1b400000
+#define QCA955X_EHCI_SIZE	0x1000
+#define QCA955X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
+#define QCA955X_GMAC_SIZE	0x40
+
+#define AR9300_OTP_BASE		0x14000
+#define AR9300_OTP_STATUS	0x15f18
+#define AR9300_OTP_STATUS_TYPE		0x7
+#define AR9300_OTP_STATUS_VALID		0x4
+#define AR9300_OTP_STATUS_ACCESS_BUSY	0x2
+#define AR9300_OTP_STATUS_SM_BUSY	0x1
+#define AR9300_OTP_READ_DATA	0x15f1c
+
+/*
+ * DDR_CTRL block
+ */
+#define AR71XX_DDR_REG_PCI_WIN0		0x7c
+#define AR71XX_DDR_REG_PCI_WIN1		0x80
+#define AR71XX_DDR_REG_PCI_WIN2		0x84
+#define AR71XX_DDR_REG_PCI_WIN3		0x88
+#define AR71XX_DDR_REG_PCI_WIN4		0x8c
+#define AR71XX_DDR_REG_PCI_WIN5		0x90
+#define AR71XX_DDR_REG_PCI_WIN6		0x94
+#define AR71XX_DDR_REG_PCI_WIN7		0x98
+#define AR71XX_DDR_REG_FLUSH_GE0	0x9c
+#define AR71XX_DDR_REG_FLUSH_GE1	0xa0
+#define AR71XX_DDR_REG_FLUSH_USB	0xa4
+#define AR71XX_DDR_REG_FLUSH_PCI	0xa8
+
+#define AR724X_DDR_REG_FLUSH_GE0	0x7c
+#define AR724X_DDR_REG_FLUSH_GE1	0x80
+#define AR724X_DDR_REG_FLUSH_USB	0x84
+#define AR724X_DDR_REG_FLUSH_PCIE	0x88
+
+#define AR913X_DDR_REG_FLUSH_GE0	0x7c
+#define AR913X_DDR_REG_FLUSH_GE1	0x80
+#define AR913X_DDR_REG_FLUSH_USB	0x84
+#define AR913X_DDR_REG_FLUSH_WMAC	0x88
+
+#define AR933X_DDR_REG_FLUSH_GE0	0x7c
+#define AR933X_DDR_REG_FLUSH_GE1	0x80
+#define AR933X_DDR_REG_FLUSH_USB	0x84
+#define AR933X_DDR_REG_FLUSH_WMAC	0x88
+
+#define AR934X_DDR_REG_FLUSH_GE0	0x9c
+#define AR934X_DDR_REG_FLUSH_GE1	0xa0
+#define AR934X_DDR_REG_FLUSH_USB	0xa4
+#define AR934X_DDR_REG_FLUSH_PCIE	0xa8
+#define AR934X_DDR_REG_FLUSH_WMAC	0xac
+
+/*
+ * PLL block
+ */
+#define AR71XX_PLL_REG_CPU_CONFIG	0x00
+#define AR71XX_PLL_REG_SEC_CONFIG	0x04
+#define AR71XX_PLL_REG_ETH0_INT_CLOCK	0x10
+#define AR71XX_PLL_REG_ETH1_INT_CLOCK	0x14
+
+#define AR71XX_PLL_DIV_SHIFT		3
+#define AR71XX_PLL_DIV_MASK		0x1f
+#define AR71XX_CPU_DIV_SHIFT		16
+#define AR71XX_CPU_DIV_MASK		0x3
+#define AR71XX_DDR_DIV_SHIFT		18
+#define AR71XX_DDR_DIV_MASK		0x3
+#define AR71XX_AHB_DIV_SHIFT		20
+#define AR71XX_AHB_DIV_MASK		0x7
+
+#define AR71XX_ETH0_PLL_SHIFT		17
+#define AR71XX_ETH1_PLL_SHIFT		19
+
+#define AR724X_PLL_REG_CPU_CONFIG	0x00
+#define AR724X_PLL_REG_PCIE_CONFIG	0x18
+
+#define AR724X_PLL_DIV_SHIFT		0
+#define AR724X_PLL_DIV_MASK		0x3ff
+#define AR724X_PLL_REF_DIV_SHIFT	10
+#define AR724X_PLL_REF_DIV_MASK		0xf
+#define AR724X_AHB_DIV_SHIFT		19
+#define AR724X_AHB_DIV_MASK		0x1
+#define AR724X_DDR_DIV_SHIFT		22
+#define AR724X_DDR_DIV_MASK		0x3
+
+#define AR7242_PLL_REG_ETH0_INT_CLOCK	0x2c
+
+#define AR913X_PLL_REG_CPU_CONFIG	0x00
+#define AR913X_PLL_REG_ETH_CONFIG	0x04
+#define AR913X_PLL_REG_ETH0_INT_CLOCK	0x14
+#define AR913X_PLL_REG_ETH1_INT_CLOCK	0x18
+
+#define AR913X_PLL_DIV_SHIFT		0
+#define AR913X_PLL_DIV_MASK		0x3ff
+#define AR913X_DDR_DIV_SHIFT		22
+#define AR913X_DDR_DIV_MASK		0x3
+#define AR913X_AHB_DIV_SHIFT		19
+#define AR913X_AHB_DIV_MASK		0x1
+
+#define AR913X_ETH0_PLL_SHIFT		20
+#define AR913X_ETH1_PLL_SHIFT		22
+
+#define AR933X_PLL_CPU_CONFIG_REG	0x00
+#define AR933X_PLL_CLOCK_CTRL_REG	0x08
+
+#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT	10
+#define AR933X_PLL_CPU_CONFIG_NINT_MASK		0x3f
+#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT	16
+#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK	0x1f
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT	23
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK	0x7
+
+#define AR933X_PLL_CLOCK_CTRL_BYPASS		BIT(2)
+#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT	5
+#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK	0x3
+#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT	10
+#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK	0x3
+#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT	15
+#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK	0x7
+
+#define AR934X_PLL_CPU_CONFIG_REG		0x00
+#define AR934X_PLL_DDR_CONFIG_REG		0x04
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_REG		0x08
+#define AR934X_PLL_ETH_XMII_CONTROL_REG		0x2c
+
+#define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT	0
+#define AR934X_PLL_CPU_CONFIG_NFRAC_MASK	0x3f
+#define AR934X_PLL_CPU_CONFIG_NINT_SHIFT	6
+#define AR934X_PLL_CPU_CONFIG_NINT_MASK		0x3f
+#define AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT	12
+#define AR934X_PLL_CPU_CONFIG_REFDIV_MASK	0x1f
+#define AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT	19
+#define AR934X_PLL_CPU_CONFIG_OUTDIV_MASK	0x3
+
+#define AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT	0
+#define AR934X_PLL_DDR_CONFIG_NFRAC_MASK	0x3ff
+#define AR934X_PLL_DDR_CONFIG_NINT_SHIFT	10
+#define AR934X_PLL_DDR_CONFIG_NINT_MASK		0x3f
+#define AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT	16
+#define AR934X_PLL_DDR_CONFIG_REFDIV_MASK	0x1f
+#define AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT	23
+#define AR934X_PLL_DDR_CONFIG_OUTDIV_MASK	0x7
+
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS	BIT(2)
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS	BIT(3)
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS	BIT(4)
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT	5
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK	0x1f
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT	10
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK	0x1f
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT	15
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK	0x1f
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL	BIT(20)
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL	BIT(21)
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL	BIT(24)
+
+#define QCA955X_PLL_CPU_CONFIG_REG		0x00
+#define QCA955X_PLL_DDR_CONFIG_REG		0x04
+#define QCA955X_PLL_CLK_CTRL_REG		0x08
+
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT	0
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK	0x3f
+#define QCA955X_PLL_CPU_CONFIG_NINT_SHIFT	6
+#define QCA955X_PLL_CPU_CONFIG_NINT_MASK	0x3f
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT	12
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_MASK	0x1f
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT	19
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK	0x3
+
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT	0
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_MASK	0x3ff
+#define QCA955X_PLL_DDR_CONFIG_NINT_SHIFT	10
+#define QCA955X_PLL_DDR_CONFIG_NINT_MASK	0x3f
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT	16
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_MASK	0x1f
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT	23
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK	0x7
+
+#define QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+/*
+ * USB_CONFIG block
+ */
+#define AR71XX_USB_CTRL_REG_FLADJ	0x00
+#define AR71XX_USB_CTRL_REG_CONFIG	0x04
+
+/*
+ * RESET block
+ */
+#define AR71XX_RESET_REG_TIMER			0x00
+#define AR71XX_RESET_REG_TIMER_RELOAD		0x04
+#define AR71XX_RESET_REG_WDOG_CTRL		0x08
+#define AR71XX_RESET_REG_WDOG			0x0c
+#define AR71XX_RESET_REG_MISC_INT_STATUS	0x10
+#define AR71XX_RESET_REG_MISC_INT_ENABLE	0x14
+#define AR71XX_RESET_REG_PCI_INT_STATUS		0x18
+#define AR71XX_RESET_REG_PCI_INT_ENABLE		0x1c
+#define AR71XX_RESET_REG_GLOBAL_INT_STATUS	0x20
+#define AR71XX_RESET_REG_RESET_MODULE		0x24
+#define AR71XX_RESET_REG_PERFC_CTRL		0x2c
+#define AR71XX_RESET_REG_PERFC0			0x30
+#define AR71XX_RESET_REG_PERFC1			0x34
+#define AR71XX_RESET_REG_REV_ID			0x90
+
+#define AR913X_RESET_REG_GLOBAL_INT_STATUS	0x18
+#define AR913X_RESET_REG_RESET_MODULE		0x1c
+#define AR913X_RESET_REG_PERF_CTRL		0x20
+#define AR913X_RESET_REG_PERFC0			0x24
+#define AR913X_RESET_REG_PERFC1			0x28
+
+#define AR724X_RESET_REG_RESET_MODULE		0x1c
+
+#define AR933X_RESET_REG_RESET_MODULE		0x1c
+#define AR933X_RESET_REG_BOOTSTRAP		0xac
+
+#define AR934X_RESET_REG_RESET_MODULE		0x1c
+#define AR934X_RESET_REG_BOOTSTRAP		0xb0
+#define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS	0xac
+
+#define QCA955X_RESET_REG_BOOTSTRAP		0xb0
+#define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
+
+#define MISC_INT_ETHSW			BIT(12)
+#define MISC_INT_TIMER4			BIT(10)
+#define MISC_INT_TIMER3			BIT(9)
+#define MISC_INT_TIMER2			BIT(8)
+#define MISC_INT_DMA			BIT(7)
+#define MISC_INT_OHCI			BIT(6)
+#define MISC_INT_PERFC			BIT(5)
+#define MISC_INT_WDOG			BIT(4)
+#define MISC_INT_UART			BIT(3)
+#define MISC_INT_GPIO			BIT(2)
+#define MISC_INT_ERROR			BIT(1)
+#define MISC_INT_TIMER			BIT(0)
+
+#define AR71XX_RESET_EXTERNAL		BIT(28)
+#define AR71XX_RESET_FULL_CHIP		BIT(24)
+#define AR71XX_RESET_CPU_NMI		BIT(21)
+#define AR71XX_RESET_CPU_COLD		BIT(20)
+#define AR71XX_RESET_DMA		BIT(19)
+#define AR71XX_RESET_SLIC		BIT(18)
+#define AR71XX_RESET_STEREO		BIT(17)
+#define AR71XX_RESET_DDR		BIT(16)
+#define AR71XX_RESET_GE1_MAC		BIT(13)
+#define AR71XX_RESET_GE1_PHY		BIT(12)
+#define AR71XX_RESET_USBSUS_OVERRIDE	BIT(10)
+#define AR71XX_RESET_GE0_MAC		BIT(9)
+#define AR71XX_RESET_GE0_PHY		BIT(8)
+#define AR71XX_RESET_USB_OHCI_DLL	BIT(6)
+#define AR71XX_RESET_USB_HOST		BIT(5)
+#define AR71XX_RESET_USB_PHY		BIT(4)
+#define AR71XX_RESET_PCI_BUS		BIT(1)
+#define AR71XX_RESET_PCI_CORE		BIT(0)
+
+#define AR7240_RESET_USB_HOST		BIT(5)
+#define AR7240_RESET_OHCI_DLL		BIT(3)
+
+#define AR724X_RESET_GE1_MDIO		BIT(23)
+#define AR724X_RESET_GE0_MDIO		BIT(22)
+#define AR724X_RESET_PCIE_PHY_SERIAL	BIT(10)
+#define AR724X_RESET_PCIE_PHY		BIT(7)
+#define AR724X_RESET_PCIE		BIT(6)
+#define AR724X_RESET_USB_HOST		BIT(5)
+#define AR724X_RESET_USB_PHY		BIT(4)
+#define AR724X_RESET_USBSUS_OVERRIDE	BIT(3)
+
+#define AR913X_RESET_AMBA2WMAC		BIT(22)
+#define AR913X_RESET_USBSUS_OVERRIDE	BIT(10)
+#define AR913X_RESET_USB_HOST		BIT(5)
+#define AR913X_RESET_USB_PHY		BIT(4)
+
+#define AR933X_RESET_GE1_MDIO		BIT(23)
+#define AR933X_RESET_GE0_MDIO		BIT(22)
+#define AR933X_RESET_GE1_MAC		BIT(13)
+#define AR933X_RESET_WMAC		BIT(11)
+#define AR933X_RESET_GE0_MAC		BIT(9)
+#define AR933X_RESET_USB_HOST		BIT(5)
+#define AR933X_RESET_USB_PHY		BIT(4)
+#define AR933X_RESET_USBSUS_OVERRIDE	BIT(3)
+
+#define AR934X_RESET_HOST		BIT(31)
+#define AR934X_RESET_SLIC		BIT(30)
+#define AR934X_RESET_HDMA		BIT(29)
+#define AR934X_RESET_EXTERNAL		BIT(28)
+#define AR934X_RESET_RTC		BIT(27)
+#define AR934X_RESET_PCIE_EP_INT	BIT(26)
+#define AR934X_RESET_CHKSUM_ACC		BIT(25)
+#define AR934X_RESET_FULL_CHIP		BIT(24)
+#define AR934X_RESET_GE1_MDIO		BIT(23)
+#define AR934X_RESET_GE0_MDIO		BIT(22)
+#define AR934X_RESET_CPU_NMI		BIT(21)
+#define AR934X_RESET_CPU_COLD		BIT(20)
+#define AR934X_RESET_HOST_RESET_INT	BIT(19)
+#define AR934X_RESET_PCIE_EP		BIT(18)
+#define AR934X_RESET_UART1		BIT(17)
+#define AR934X_RESET_DDR		BIT(16)
+#define AR934X_RESET_USB_PHY_PLL_PWD_EXT BIT(15)
+#define AR934X_RESET_NANDF		BIT(14)
+#define AR934X_RESET_GE1_MAC		BIT(13)
+#define AR934X_RESET_ETH_SWITCH_ANALOG	BIT(12)
+#define AR934X_RESET_USB_PHY_ANALOG	BIT(11)
+#define AR934X_RESET_HOST_DMA_INT	BIT(10)
+#define AR934X_RESET_GE0_MAC		BIT(9)
+#define AR934X_RESET_ETH_SWITCH		BIT(8)
+#define AR934X_RESET_PCIE_PHY		BIT(7)
+#define AR934X_RESET_PCIE		BIT(6)
+#define AR934X_RESET_USB_HOST		BIT(5)
+#define AR934X_RESET_USB_PHY		BIT(4)
+#define AR934X_RESET_USBSUS_OVERRIDE	BIT(3)
+#define AR934X_RESET_LUT		BIT(2)
+#define AR934X_RESET_MBOX		BIT(1)
+#define AR934X_RESET_I2S		BIT(0)
+
+#define AR933X_BOOTSTRAP_MDIO_GPIO_EN	BIT(18)
+#define AR933X_BOOTSTRAP_EEPBUSY	BIT(4)
+#define AR933X_BOOTSTRAP_REF_CLK_40	BIT(0)
+
+#define AR934X_BOOTSTRAP_SW_OPTION8	BIT(23)
+#define AR934X_BOOTSTRAP_SW_OPTION7	BIT(22)
+#define AR934X_BOOTSTRAP_SW_OPTION6	BIT(21)
+#define AR934X_BOOTSTRAP_SW_OPTION5	BIT(20)
+#define AR934X_BOOTSTRAP_SW_OPTION4	BIT(19)
+#define AR934X_BOOTSTRAP_SW_OPTION3	BIT(18)
+#define AR934X_BOOTSTRAP_SW_OPTION2	BIT(17)
+#define AR934X_BOOTSTRAP_SW_OPTION1	BIT(16)
+#define AR934X_BOOTSTRAP_USB_MODE_DEVICE BIT(7)
+#define AR934X_BOOTSTRAP_PCIE_RC	BIT(6)
+#define AR934X_BOOTSTRAP_EJTAG_MODE	BIT(5)
+#define AR934X_BOOTSTRAP_REF_CLK_40	BIT(4)
+#define AR934X_BOOTSTRAP_BOOT_FROM_SPI	BIT(2)
+#define AR934X_BOOTSTRAP_SDRAM_DISABLED	BIT(1)
+#define AR934X_BOOTSTRAP_DDR1		BIT(0)
+
+#define QCA955X_BOOTSTRAP_REF_CLK_40	BIT(4)
+
+#define AR934X_PCIE_WMAC_INT_WMAC_MISC		BIT(0)
+#define AR934X_PCIE_WMAC_INT_WMAC_TX		BIT(1)
+#define AR934X_PCIE_WMAC_INT_WMAC_RXLP		BIT(2)
+#define AR934X_PCIE_WMAC_INT_WMAC_RXHP		BIT(3)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC		BIT(4)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC0		BIT(5)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC1		BIT(6)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC2		BIT(7)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC3		BIT(8)
+#define AR934X_PCIE_WMAC_INT_WMAC_ALL \
+	(AR934X_PCIE_WMAC_INT_WMAC_MISC | AR934X_PCIE_WMAC_INT_WMAC_TX | \
+	 AR934X_PCIE_WMAC_INT_WMAC_RXLP | AR934X_PCIE_WMAC_INT_WMAC_RXHP)
+
+#define AR934X_PCIE_WMAC_INT_PCIE_ALL \
+	(AR934X_PCIE_WMAC_INT_PCIE_RC | AR934X_PCIE_WMAC_INT_PCIE_RC0 | \
+	 AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \
+	 AR934X_PCIE_WMAC_INT_PCIE_RC3)
+
+#define QCA955X_EXT_INT_WMAC_MISC		BIT(0)
+#define QCA955X_EXT_INT_WMAC_TX			BIT(1)
+#define QCA955X_EXT_INT_WMAC_RXLP		BIT(2)
+#define QCA955X_EXT_INT_WMAC_RXHP		BIT(3)
+#define QCA955X_EXT_INT_PCIE_RC1		BIT(4)
+#define QCA955X_EXT_INT_PCIE_RC1_INT0		BIT(5)
+#define QCA955X_EXT_INT_PCIE_RC1_INT1		BIT(6)
+#define QCA955X_EXT_INT_PCIE_RC1_INT2		BIT(7)
+#define QCA955X_EXT_INT_PCIE_RC1_INT3		BIT(8)
+#define QCA955X_EXT_INT_PCIE_RC2		BIT(12)
+#define QCA955X_EXT_INT_PCIE_RC2_INT0		BIT(13)
+#define QCA955X_EXT_INT_PCIE_RC2_INT1		BIT(14)
+#define QCA955X_EXT_INT_PCIE_RC2_INT2		BIT(15)
+#define QCA955X_EXT_INT_PCIE_RC2_INT3		BIT(16)
+#define QCA955X_EXT_INT_USB1			BIT(24)
+#define QCA955X_EXT_INT_USB2			BIT(28)
+
+#define QCA955X_EXT_INT_WMAC_ALL \
+	(QCA955X_EXT_INT_WMAC_MISC | QCA955X_EXT_INT_WMAC_TX | \
+	 QCA955X_EXT_INT_WMAC_RXLP | QCA955X_EXT_INT_WMAC_RXHP)
+
+#define QCA955X_EXT_INT_PCIE_RC1_ALL \
+	(QCA955X_EXT_INT_PCIE_RC1 | QCA955X_EXT_INT_PCIE_RC1_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT1 | QCA955X_EXT_INT_PCIE_RC1_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT3)
+
+#define QCA955X_EXT_INT_PCIE_RC2_ALL \
+	(QCA955X_EXT_INT_PCIE_RC2 | QCA955X_EXT_INT_PCIE_RC2_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT3)
+
+#define REV_ID_MAJOR_MASK		0xfff0
+#define REV_ID_MAJOR_AR71XX		0x00a0
+#define REV_ID_MAJOR_AR913X		0x00b0
+#define REV_ID_MAJOR_AR7240		0x00c0
+#define REV_ID_MAJOR_AR7241		0x0100
+#define REV_ID_MAJOR_AR7242		0x1100
+#define REV_ID_MAJOR_AR9330		0x0110
+#define REV_ID_MAJOR_AR9331		0x1110
+#define REV_ID_MAJOR_AR9341		0x0120
+#define REV_ID_MAJOR_AR9342		0x1120
+#define REV_ID_MAJOR_AR9344		0x2120
+#define REV_ID_MAJOR_QCA9558		0x1130
+
+#define AR71XX_REV_ID_MINOR_MASK	0x3
+#define AR71XX_REV_ID_MINOR_AR7130	0x0
+#define AR71XX_REV_ID_MINOR_AR7141	0x1
+#define AR71XX_REV_ID_MINOR_AR7161	0x2
+#define AR71XX_REV_ID_REVISION_MASK	0x3
+#define AR71XX_REV_ID_REVISION_SHIFT	2
+
+#define AR913X_REV_ID_MINOR_MASK	0x3
+#define AR913X_REV_ID_MINOR_AR9130	0x0
+#define AR913X_REV_ID_MINOR_AR9132	0x1
+#define AR913X_REV_ID_REVISION_MASK	0x3
+#define AR913X_REV_ID_REVISION_SHIFT	2
+
+#define AR933X_REV_ID_REVISION_MASK	0x3
+
+#define AR724X_REV_ID_REVISION_MASK	0x3
+
+#define AR934X_REV_ID_REVISION_MASK     0xf
+
+#define AR944X_REV_ID_REVISION_MASK	0xf
+
+/*
+ * SPI block
+ */
+#define AR71XX_SPI_REG_FS	0x00	/* Function Select */
+#define AR71XX_SPI_REG_CTRL	0x04	/* SPI Control */
+#define AR71XX_SPI_REG_IOC	0x08	/* SPI I/O Control */
+#define AR71XX_SPI_REG_RDS	0x0c	/* Read Data Shift */
+
+#define AR71XX_SPI_FS_GPIO	BIT(0)	/* Enable GPIO mode */
+
+#define AR71XX_SPI_CTRL_RD	BIT(6)	/* Remap Disable */
+#define AR71XX_SPI_CTRL_DIV_MASK 0x3f
+
+#define AR71XX_SPI_IOC_DO	BIT(0)	/* Data Out pin */
+#define AR71XX_SPI_IOC_CLK	BIT(8)	/* CLK pin */
+#define AR71XX_SPI_IOC_CS(n)	BIT(16 + (n))
+#define AR71XX_SPI_IOC_CS0	AR71XX_SPI_IOC_CS(0)
+#define AR71XX_SPI_IOC_CS1	AR71XX_SPI_IOC_CS(1)
+#define AR71XX_SPI_IOC_CS2	AR71XX_SPI_IOC_CS(2)
+#define AR71XX_SPI_IOC_CS_ALL	(AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | \
+				 AR71XX_SPI_IOC_CS2)
+
+/*
+ * GPIO block
+ */
+#define AR71XX_GPIO_REG_OE		0x00
+#define AR71XX_GPIO_REG_IN		0x04
+#define AR71XX_GPIO_REG_OUT		0x08
+#define AR71XX_GPIO_REG_SET		0x0c
+#define AR71XX_GPIO_REG_CLEAR		0x10
+#define AR71XX_GPIO_REG_INT_MODE	0x14
+#define AR71XX_GPIO_REG_INT_TYPE	0x18
+#define AR71XX_GPIO_REG_INT_POLARITY	0x1c
+#define AR71XX_GPIO_REG_INT_PENDING	0x20
+#define AR71XX_GPIO_REG_INT_ENABLE	0x24
+#define AR71XX_GPIO_REG_FUNC		0x28
+
+#define AR934X_GPIO_REG_OUT_FUNC0	0x2c
+#define AR934X_GPIO_REG_OUT_FUNC1	0x30
+#define AR934X_GPIO_REG_OUT_FUNC2	0x34
+#define AR934X_GPIO_REG_OUT_FUNC3	0x38
+#define AR934X_GPIO_REG_OUT_FUNC4	0x3c
+#define AR934X_GPIO_REG_OUT_FUNC5	0x40
+#define AR934X_GPIO_REG_FUNC		0x6c
+
+#define AR71XX_GPIO_COUNT		16
+#define AR724X_GPIO_COUNT		18
+#define AR913X_GPIO_COUNT		22
+#define AR933X_GPIO_COUNT		30
+#define AR934X_GPIO_COUNT		23
+#define QCA955X_GPIO_COUNT		24
+
+#define AR71XX_GPIO_FUNC_STEREO_EN		BIT(17)
+#define AR71XX_GPIO_FUNC_SLIC_EN		BIT(16)
+#define AR71XX_GPIO_FUNC_SPI_CS2_EN		BIT(13)
+#define AR71XX_GPIO_FUNC_SPI_CS1_EN		BIT(12)
+#define AR71XX_GPIO_FUNC_UART_EN		BIT(8)
+#define AR71XX_GPIO_FUNC_USB_OC_EN		BIT(4)
+#define AR71XX_GPIO_FUNC_USB_CLK_EN		BIT(0)
+
+#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN		BIT(19)
+#define AR724X_GPIO_FUNC_SPI_EN			BIT(18)
+#define AR724X_GPIO_FUNC_SPI_CS_EN2		BIT(14)
+#define AR724X_GPIO_FUNC_SPI_CS_EN1		BIT(13)
+#define AR724X_GPIO_FUNC_CLK_OBS5_EN		BIT(12)
+#define AR724X_GPIO_FUNC_CLK_OBS4_EN		BIT(11)
+#define AR724X_GPIO_FUNC_CLK_OBS3_EN		BIT(10)
+#define AR724X_GPIO_FUNC_CLK_OBS2_EN		BIT(9)
+#define AR724X_GPIO_FUNC_CLK_OBS1_EN		BIT(8)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN	BIT(7)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN	BIT(6)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN	BIT(5)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN	BIT(4)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN	BIT(3)
+#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN	BIT(2)
+#define AR724X_GPIO_FUNC_UART_EN		BIT(1)
+#define AR724X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
+
+#define AR913X_GPIO_FUNC_WMAC_LED_EN		BIT(22)
+#define AR913X_GPIO_FUNC_EXP_PORT_CS_EN		BIT(21)
+#define AR913X_GPIO_FUNC_I2S_REFCLKEN		BIT(20)
+#define AR913X_GPIO_FUNC_I2S_MCKEN		BIT(19)
+#define AR913X_GPIO_FUNC_I2S1_EN		BIT(18)
+#define AR913X_GPIO_FUNC_I2S0_EN		BIT(17)
+#define AR913X_GPIO_FUNC_SLIC_EN		BIT(16)
+#define AR913X_GPIO_FUNC_UART_RTSCTS_EN		BIT(9)
+#define AR913X_GPIO_FUNC_UART_EN		BIT(8)
+#define AR913X_GPIO_FUNC_USB_CLK_EN		BIT(4)
+
+#define AR933X_GPIO_FUNC_SPDIF2TCK		BIT(31)
+#define AR933X_GPIO_FUNC_SPDIF_EN		BIT(30)
+#define AR933X_GPIO_FUNC_I2SO_22_18_EN		BIT(29)
+#define AR933X_GPIO_FUNC_I2S_MCK_EN		BIT(27)
+#define AR933X_GPIO_FUNC_I2SO_EN		BIT(26)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_DUPL	BIT(25)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_COLL	BIT(24)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_ACT	BIT(23)
+#define AR933X_GPIO_FUNC_SPI_EN			BIT(18)
+#define AR933X_GPIO_FUNC_SPI_CS_EN2		BIT(14)
+#define AR933X_GPIO_FUNC_SPI_CS_EN1		BIT(13)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN	BIT(7)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN	BIT(6)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN	BIT(5)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN	BIT(4)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN	BIT(3)
+#define AR933X_GPIO_FUNC_UART_RTS_CTS_EN	BIT(2)
+#define AR933X_GPIO_FUNC_UART_EN		BIT(1)
+#define AR933X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
+
+#define AR934X_GPIO_FUNC_DDR_DQOE_EN	BIT(17)
+#define AR934X_GPIO_FUNC_SPI_CS_1_EN	BIT(14)
+#define AR934X_GPIO_FUNC_SPI_CS_0_EN	BIT(13)
+
+#define AR934X_GPIO_OUT_GPIO		0x00
+
+/*
+ * MII_CTRL block
+ */
+#define AR71XX_MII_REG_MII0_CTRL	0x00
+#define AR71XX_MII_REG_MII1_CTRL	0x04
+
+#define AR71XX_MII_CTRL_IF_MASK		3
+#define AR71XX_MII_CTRL_SPEED_SHIFT	4
+#define AR71XX_MII_CTRL_SPEED_MASK	3
+#define AR71XX_MII_CTRL_SPEED_10	0
+#define AR71XX_MII_CTRL_SPEED_100	1
+#define AR71XX_MII_CTRL_SPEED_1000	2
+
+#define AR71XX_MII0_CTRL_IF_GMII	0
+#define AR71XX_MII0_CTRL_IF_MII		1
+#define AR71XX_MII0_CTRL_IF_RGMII	2
+#define AR71XX_MII0_CTRL_IF_RMII	3
+
+#define AR71XX_MII1_CTRL_IF_RGMII	0
+#define AR71XX_MII1_CTRL_IF_RMII	1
+
+/*
+ * AR933X GMAC interface
+ */
+#define AR933X_GMAC_REG_ETH_CFG		0x00
+
+#define AR933X_ETH_CFG_RGMII_GE0	BIT(0)
+#define AR933X_ETH_CFG_MII_GE0		BIT(1)
+#define AR933X_ETH_CFG_GMII_GE0		BIT(2)
+#define AR933X_ETH_CFG_MII_GE0_MASTER	BIT(3)
+#define AR933X_ETH_CFG_MII_GE0_SLAVE	BIT(4)
+#define AR933X_ETH_CFG_MII_GE0_ERR_EN	BIT(5)
+#define AR933X_ETH_CFG_SW_PHY_SWAP	BIT(7)
+#define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP	BIT(8)
+#define AR933X_ETH_CFG_RMII_GE0		BIT(9)
+#define AR933X_ETH_CFG_RMII_GE0_SPD_10	0
+#define AR933X_ETH_CFG_RMII_GE0_SPD_100	BIT(10)
+
+/*
+ * AR934X GMAC Interface
+ */
+#define AR934X_GMAC_REG_ETH_CFG		0x00
+
+#define AR934X_ETH_CFG_RGMII_GMAC0	BIT(0)
+#define AR934X_ETH_CFG_MII_GMAC0	BIT(1)
+#define AR934X_ETH_CFG_GMII_GMAC0	BIT(2)
+#define AR934X_ETH_CFG_MII_GMAC0_MASTER	BIT(3)
+#define AR934X_ETH_CFG_MII_GMAC0_SLAVE	BIT(4)
+#define AR934X_ETH_CFG_MII_GMAC0_ERR_EN	BIT(5)
+#define AR934X_ETH_CFG_SW_ONLY_MODE	BIT(6)
+#define AR934X_ETH_CFG_SW_PHY_SWAP	BIT(7)
+#define AR934X_ETH_CFG_SW_APB_ACCESS	BIT(9)
+#define AR934X_ETH_CFG_RMII_GMAC0	BIT(10)
+#define AR933X_ETH_CFG_MII_CNTL_SPEED	BIT(11)
+#define AR934X_ETH_CFG_RMII_GMAC0_MASTER BIT(12)
+#define AR933X_ETH_CFG_SW_ACC_MSB_FIRST	BIT(13)
+
+/*
+ * QCA955X GMAC Interface
+ */
+
+#define QCA955X_GMAC_REG_ETH_CFG	0x00
+
+#define QCA955X_ETH_CFG_RGMII_GMAC0	BIT(0)
+#define QCA955X_ETH_CFG_SGMII_GMAC0	BIT(6)
+
+#endif /* __ASM_MACH_AR71XX_REGS_H */
diff --git a/target/linux/ar71xx/image/lzma-loader/src/board.c b/target/linux/ar71xx/image/lzma-loader/src/board.c
new file mode 100644
index 0000000000..2f4dd6b1f6
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/board.c
@@ -0,0 +1,56 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stddef.h>
+#include "config.h"
+#include "ar71xx_regs.h"
+
+#define READREG(r)	*(volatile unsigned int *)(r)
+#define WRITEREG(r,v)	*(volatile unsigned int *)(r) = v
+
+#define KSEG1ADDR(_x)	(((_x) & 0x1fffffff) | 0xa0000000)
+
+#define UART_BASE	0xb8020000
+
+#define UART_TX		0
+#define UART_LSR	5
+
+#define UART_LSR_THRE   0x20
+
+#define UART_READ(r)		READREG(UART_BASE + 4 * (r))
+#define UART_WRITE(r,v)		WRITEREG(UART_BASE + 4 * (r), (v))
+
+void board_putc(int ch)
+{
+	while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
+	UART_WRITE(UART_TX, ch);
+	while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
+}
+
+#ifdef CONFIG_BOARD_TL_WR1043ND_V1
+static void tlwr1043nd_init(void)
+{
+	unsigned int reg = KSEG1ADDR(AR71XX_RESET_BASE);
+	unsigned int t;
+
+	t = READREG(reg + AR913X_RESET_REG_RESET_MODULE);
+	t |= AR71XX_RESET_GE0_PHY;
+	WRITEREG(reg + AR913X_RESET_REG_RESET_MODULE, t);
+	/* flush write */
+	t = READREG(reg + AR913X_RESET_REG_RESET_MODULE);
+}
+#else
+static inline void tlwr1043nd_init(void) {}
+#endif
+
+void board_init(void)
+{
+	tlwr1043nd_init();
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/cache.c b/target/linux/ar71xx/image/lzma-loader/src/cache.c
new file mode 100644
index 0000000000..28cc848333
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/cache.c
@@ -0,0 +1,43 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * The cache manipulation routine has been taken from the U-Boot project.
+ *	(C) Copyright 2003
+ *	Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * 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 "cache.h"
+#include "cacheops.h"
+#include "config.h"
+
+#define cache_op(op,addr)						\
+	__asm__ __volatile__(						\
+	"	.set	push					\n"	\
+	"	.set	noreorder				\n"	\
+	"	.set	mips3\n\t				\n"	\
+	"	cache	%0, %1					\n"	\
+	"	.set	pop					\n"	\
+	:								\
+	: "i" (op), "R" (*(unsigned char *)(addr)))
+
+void flush_cache(unsigned long start_addr, unsigned long size)
+{
+	unsigned long lsize = CONFIG_CACHELINE_SIZE;
+	unsigned long addr = start_addr & ~(lsize - 1);
+	unsigned long aend = (start_addr + size - 1) & ~(lsize - 1);
+
+	while (1) {
+		cache_op(Hit_Writeback_Inv_D, addr);
+		cache_op(Hit_Invalidate_I, addr);
+		if (addr == aend)
+			break;
+		addr += lsize;
+	}
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/cache.h b/target/linux/ar71xx/image/lzma-loader/src/cache.h
new file mode 100644
index 0000000000..506a235884
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/cache.h
@@ -0,0 +1,17 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CACHE_H
+#define __CACHE_H
+
+void flush_cache(unsigned long start_addr, unsigned long size);
+
+#endif /* __CACHE_H */
diff --git a/target/linux/ar71xx/image/lzma-loader/src/cacheops.h b/target/linux/ar71xx/image/lzma-loader/src/cacheops.h
new file mode 100644
index 0000000000..70bcad7694
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/cacheops.h
@@ -0,0 +1,85 @@
+/*
+ * Cache operations for the cache instruction.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) Copyright 1996, 97, 99, 2002, 03 Ralf Baechle
+ * (C) Copyright 1999 Silicon Graphics, Inc.
+ */
+#ifndef	__ASM_CACHEOPS_H
+#define	__ASM_CACHEOPS_H
+
+/*
+ * Cache Operations available on all MIPS processors with R4000-style caches
+ */
+#define Index_Invalidate_I      0x00
+#define Index_Writeback_Inv_D   0x01
+#define Index_Load_Tag_I	0x04
+#define Index_Load_Tag_D	0x05
+#define Index_Store_Tag_I	0x08
+#define Index_Store_Tag_D	0x09
+#if defined(CONFIG_CPU_LOONGSON2)
+#define Hit_Invalidate_I	0x00
+#else
+#define Hit_Invalidate_I	0x10
+#endif
+#define Hit_Invalidate_D	0x11
+#define Hit_Writeback_Inv_D	0x15
+
+/*
+ * R4000-specific cacheops
+ */
+#define Create_Dirty_Excl_D	0x0d
+#define Fill			0x14
+#define Hit_Writeback_I		0x18
+#define Hit_Writeback_D		0x19
+
+/*
+ * R4000SC and R4400SC-specific cacheops
+ */
+#define Index_Invalidate_SI     0x02
+#define Index_Writeback_Inv_SD  0x03
+#define Index_Load_Tag_SI	0x06
+#define Index_Load_Tag_SD	0x07
+#define Index_Store_Tag_SI	0x0A
+#define Index_Store_Tag_SD	0x0B
+#define Create_Dirty_Excl_SD	0x0f
+#define Hit_Invalidate_SI	0x12
+#define Hit_Invalidate_SD	0x13
+#define Hit_Writeback_Inv_SD	0x17
+#define Hit_Writeback_SD	0x1b
+#define Hit_Set_Virtual_SI	0x1e
+#define Hit_Set_Virtual_SD	0x1f
+
+/*
+ * R5000-specific cacheops
+ */
+#define R5K_Page_Invalidate_S	0x17
+
+/*
+ * RM7000-specific cacheops
+ */
+#define Page_Invalidate_T	0x16
+
+/*
+ * R10000-specific cacheops
+ *
+ * Cacheops 0x02, 0x06, 0x0a, 0x0c-0x0e, 0x16, 0x1a and 0x1e are unused.
+ * Most of the _S cacheops are identical to the R4000SC _SD cacheops.
+ */
+#define Index_Writeback_Inv_S	0x03
+#define Index_Load_Tag_S	0x07
+#define Index_Store_Tag_S	0x0B
+#define Hit_Invalidate_S	0x13
+#define Cache_Barrier		0x14
+#define Hit_Writeback_Inv_S	0x17
+#define Index_Load_Data_I	0x18
+#define Index_Load_Data_D	0x19
+#define Index_Load_Data_S	0x1b
+#define Index_Store_Data_I	0x1c
+#define Index_Store_Data_D	0x1d
+#define Index_Store_Data_S	0x1f
+
+#endif	/* __ASM_CACHEOPS_H */
diff --git a/target/linux/ar71xx/image/lzma-loader/src/config.h b/target/linux/ar71xx/image/lzma-loader/src/config.h
new file mode 100644
index 0000000000..287392b340
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/config.h
@@ -0,0 +1,31 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#define CONFIG_ICACHE_SIZE	(32 * 1024)
+#define CONFIG_DCACHE_SIZE	(64 * 1024)
+#define CONFIG_CACHELINE_SIZE	32
+
+#ifndef CONFIG_FLASH_OFFS
+#define CONFIG_FLASH_OFFS	0
+#endif
+
+#ifndef CONFIG_FLASH_MAX
+#define CONFIG_FLASH_MAX	0
+#endif
+
+#ifndef CONFIG_FLASH_STEP
+#define CONFIG_FLASH_STEP	0x1000
+#endif
+
+#endif /* _CONFIG_H_ */
diff --git a/target/linux/ar71xx/image/lzma-loader/src/cp0regdef.h b/target/linux/ar71xx/image/lzma-loader/src/cp0regdef.h
new file mode 100644
index 0000000000..c1188ad8c8
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/cp0regdef.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
+ *
+ * Copyright (C) 2001, Monta Vista Software
+ * Author: jsun@mvista.com or jsun@junsun.net
+ */
+#ifndef _cp0regdef_h_
+#define _cp0regdef_h_
+
+#define CP0_INDEX $0
+#define CP0_RANDOM $1
+#define CP0_ENTRYLO0 $2
+#define CP0_ENTRYLO1 $3
+#define CP0_CONTEXT $4
+#define CP0_PAGEMASK $5
+#define CP0_WIRED $6
+#define CP0_BADVADDR $8
+#define CP0_COUNT $9
+#define CP0_ENTRYHI $10
+#define CP0_COMPARE $11
+#define CP0_STATUS $12
+#define CP0_CAUSE $13
+#define CP0_EPC $14
+#define CP0_PRID $15
+#define CP0_CONFIG $16
+#define CP0_LLADDR $17
+#define CP0_WATCHLO $18
+#define CP0_WATCHHI $19
+#define CP0_XCONTEXT $20
+#define CP0_FRAMEMASK $21
+#define CP0_DIAGNOSTIC $22
+#define CP0_PERFORMANCE $25
+#define CP0_ECC $26
+#define CP0_CACHEERR $27
+#define CP0_TAGLO $28
+#define CP0_TAGHI $29
+#define CP0_ERROREPC $30
+
+#endif
diff --git a/target/linux/ar71xx/image/lzma-loader/src/head.S b/target/linux/ar71xx/image/lzma-loader/src/head.S
new file mode 100644
index 0000000000..47a7c9bd63
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/head.S
@@ -0,0 +1,121 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the BCM47xx and ADM5120 based boards:
+ *	Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
+ *	Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * 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 <asm/asm.h>
+#include <asm/regdef.h>
+#include "cp0regdef.h"
+#include "cacheops.h"
+#include "config.h"
+
+#define KSEG0		0x80000000
+
+	.macro	ehb
+	sll     zero, 3
+	.endm
+
+	.text
+
+LEAF(startup)
+	.set noreorder
+	.set mips32
+
+	mtc0	zero, CP0_WATCHLO	# clear watch registers
+	mtc0	zero, CP0_WATCHHI
+	mtc0	zero, CP0_CAUSE		# clear before writing status register
+
+	mfc0	t0, CP0_STATUS
+	li	t1, 0x1000001f
+	or	t0, t1
+	xori	t0, 0x1f
+	mtc0	t0, CP0_STATUS
+	ehb
+
+	mtc0	zero, CP0_COUNT
+	mtc0	zero, CP0_COMPARE
+	ehb
+
+	la	t0, __reloc_label	# get linked address of label
+	bal	__reloc_label		# branch and link to label to
+	nop				# get actual address
+__reloc_label:
+	subu	t0, ra, t0		# get reloc_delta
+
+	beqz	t0, __reloc_done         # if delta is 0 we are in the right place
+	nop
+
+	/* Copy our code to the right place */
+	la	t1, _code_start		# get linked address of _code_start
+	la	t2, _code_end		# get linked address of _code_end
+	addu	t0, t0, t1		# calculate actual address of _code_start
+
+__reloc_copy:
+	lw	t3, 0(t0)
+	sw	t3, 0(t1)
+	add	t1, 4
+	blt	t1, t2, __reloc_copy
+	add	t0, 4
+
+	/* flush cache */
+	la	t0, _code_start
+	la	t1, _code_end
+
+	li	t2, ~(CONFIG_CACHELINE_SIZE - 1)
+	and	t0, t2
+	and	t1, t2
+	li	t2, CONFIG_CACHELINE_SIZE
+
+	b	__flush_check
+	nop
+
+__flush_line:
+	cache	Hit_Writeback_Inv_D, 0(t0)
+	cache	Hit_Invalidate_I, 0(t0)
+	add	t0, t2
+
+__flush_check:
+	bne	t0, t1, __flush_line
+	nop
+
+	sync
+
+__reloc_done:
+
+	/* clear bss */
+	la	t0, _bss_start
+	la	t1, _bss_end
+	b	__bss_check
+	nop
+
+__bss_fill:
+	sw	zero, 0(t0)
+	addi	t0, 4
+
+__bss_check:
+	bne	t0, t1, __bss_fill
+	nop
+
+	/* Setup new "C" stack */
+	la	sp, _stack
+
+	/* reserve stack space for a0-a3 registers */
+	subu	sp, 16
+
+	/* jump to the decompressor routine */
+	la	t0, loader_main
+	jr	t0
+	nop
+
+	.set reorder
+END(startup)
diff --git a/target/linux/ar71xx/image/lzma-loader/src/loader.c b/target/linux/ar71xx/image/lzma-loader/src/loader.c
new file mode 100644
index 0000000000..cc73eb1721
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/loader.c
@@ -0,0 +1,264 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the BCM47xx and ADM5120 based boards:
+ *	Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
+ *	Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
+ *	Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * The image_header structure has been taken from the U-Boot project.
+ *	(C) Copyright 2008 Semihalf
+ *	(C) Copyright 2000-2005
+ *	Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 <stddef.h>
+#include <stdint.h>
+
+#include "config.h"
+#include "cache.h"
+#include "printf.h"
+#include "LzmaDecode.h"
+
+#define AR71XX_FLASH_START	0x1f000000
+#define AR71XX_FLASH_END	0x1fe00000
+
+#define KSEG0			0x80000000
+#define KSEG1			0xa0000000
+
+#define KSEG1ADDR(a)		((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
+
+#undef LZMA_DEBUG
+
+#ifdef LZMA_DEBUG
+#  define DBG(f, a...)	printf(f, ## a)
+#else
+#  define DBG(f, a...)	do {} while (0)
+#endif
+
+#define IH_MAGIC_OKLI		0x4f4b4c49	/* 'OKLI' */
+
+#define IH_NMLEN		32	/* Image Name Length		*/
+
+typedef struct image_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+} image_header_t;
+
+/* beyond the image end, size not known in advance */
+extern unsigned char workspace[];
+extern void board_init(void);
+
+static CLzmaDecoderState lzma_state;
+static unsigned char *lzma_data;
+static unsigned long lzma_datasize;
+static unsigned long lzma_outsize;
+static unsigned long kernel_la;
+
+#ifdef CONFIG_KERNEL_CMDLINE
+#define kernel_argc	2
+static const char kernel_cmdline[] = CONFIG_KERNEL_CMDLINE;
+static const char *kernel_argv[] = {
+	NULL,
+	kernel_cmdline,
+	NULL,
+};
+#endif /* CONFIG_KERNEL_CMDLINE */
+
+static void halt(void)
+{
+	printf("\nSystem halted!\n");
+	for(;;);
+}
+
+static __inline__ unsigned long get_be32(void *buf)
+{
+	unsigned char *p = buf;
+
+	return (((unsigned long) p[0] << 24) +
+	        ((unsigned long) p[1] << 16) +
+	        ((unsigned long) p[2] << 8) +
+	        (unsigned long) p[3]);
+}
+
+static __inline__ unsigned char lzma_get_byte(void)
+{
+	unsigned char c;
+
+	lzma_datasize--;
+	c = *lzma_data++;
+
+	return c;
+}
+
+static int lzma_init_props(void)
+{
+	unsigned char props[LZMA_PROPERTIES_SIZE];
+	int res;
+	int i;
+
+	/* read lzma properties */
+	for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
+		props[i] = lzma_get_byte();
+
+	/* read the lower half of uncompressed size in the header */
+	lzma_outsize = ((SizeT) lzma_get_byte()) +
+		       ((SizeT) lzma_get_byte() << 8) +
+		       ((SizeT) lzma_get_byte() << 16) +
+		       ((SizeT) lzma_get_byte() << 24);
+
+	/* skip rest of the header (upper half of uncompressed size) */
+	for (i = 0; i < 4; i++)
+		lzma_get_byte();
+
+	res = LzmaDecodeProperties(&lzma_state.Properties, props,
+					LZMA_PROPERTIES_SIZE);
+	return res;
+}
+
+static int lzma_decompress(unsigned char *outStream)
+{
+	SizeT ip, op;
+	int ret;
+
+	lzma_state.Probs = (CProb *) workspace;
+
+	ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
+			 lzma_outsize, &op);
+
+	if (ret != LZMA_RESULT_OK) {
+		int i;
+
+		DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
+		    ret, lzma_data + ip, lzma_outsize, ip, op);
+
+		for (i = 0; i < 16; i++)
+			DBG("%02x ", lzma_data[ip + i]);
+
+		DBG("\n");
+	}
+
+	return ret;
+}
+
+#if (LZMA_WRAPPER)
+static void lzma_init_data(void)
+{
+	extern unsigned char _lzma_data_start[];
+	extern unsigned char _lzma_data_end[];
+
+	kernel_la = LOADADDR;
+	lzma_data = _lzma_data_start;
+	lzma_datasize = _lzma_data_end - _lzma_data_start;
+}
+#else
+static void lzma_init_data(void)
+{
+	struct image_header *hdr = NULL;
+	unsigned char *flash_base;
+	unsigned long flash_ofs;
+	unsigned long kernel_ofs;
+	unsigned long kernel_size;
+
+	flash_base = (unsigned char *) KSEG1ADDR(AR71XX_FLASH_START);
+
+	printf("Looking for OpenWrt image... ");
+
+	for (flash_ofs = CONFIG_FLASH_OFFS;
+	     flash_ofs <= (CONFIG_FLASH_OFFS + CONFIG_FLASH_MAX);
+	     flash_ofs += CONFIG_FLASH_STEP) {
+		unsigned long magic;
+		unsigned char *p;
+
+		p = flash_base + flash_ofs;
+		magic = get_be32(p);
+		if (magic == IH_MAGIC_OKLI) {
+			hdr = (struct image_header *) p;
+			break;
+		}
+	}
+
+	if (hdr == NULL) {
+		printf("not found!\n");
+		halt();
+	}
+
+	printf("found at 0x%08x\n", flash_base + flash_ofs);
+
+	kernel_ofs = sizeof(struct image_header);
+	kernel_size = get_be32(&hdr->ih_size);
+	kernel_la = get_be32(&hdr->ih_load);
+
+	lzma_data = flash_base + flash_ofs + kernel_ofs;
+	lzma_datasize = kernel_size;
+}
+#endif /* (LZMA_WRAPPER) */
+
+void loader_main(unsigned long reg_a0, unsigned long reg_a1,
+		 unsigned long reg_a2, unsigned long reg_a3)
+{
+	void (*kernel_entry) (unsigned long, unsigned long, unsigned long,
+			      unsigned long);
+	int res;
+
+	board_init();
+
+	printf("\n\nOpenWrt kernel loader for AR7XXX/AR9XXX\n");
+	printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n");
+
+	lzma_init_data();
+
+	res = lzma_init_props();
+	if (res != LZMA_RESULT_OK) {
+		printf("Incorrect LZMA stream properties!\n");
+		halt();
+	}
+
+	printf("Decompressing kernel... ");
+
+	res = lzma_decompress((unsigned char *) kernel_la);
+	if (res != LZMA_RESULT_OK) {
+		printf("failed, ");
+		switch (res) {
+		case LZMA_RESULT_DATA_ERROR:
+			printf("data error!\n");
+			break;
+		default:
+			printf("unknown error %d!\n", res);
+		}
+		halt();
+	} else {
+		printf("done!\n");
+	}
+
+	flush_cache(kernel_la, lzma_outsize);
+
+	printf("Starting kernel at %08x...\n\n", kernel_la);
+
+#ifdef CONFIG_KERNEL_CMDLINE
+	reg_a0 = kernel_argc;
+	reg_a1 = (unsigned long) kernel_argv;
+	reg_a2 = 0;
+	reg_a3 = 0;
+#endif
+
+	kernel_entry = (void *) kernel_la;
+	kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3);
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/loader.lds b/target/linux/ar71xx/image/lzma-loader/src/loader.lds
new file mode 100644
index 0000000000..80cc7ca3ec
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/loader.lds
@@ -0,0 +1,35 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+	.text : {
+		_code_start = .;
+		*(.text)
+		*(.text.*)
+		*(.rodata)
+		*(.rodata.*)
+		*(.data.lzma)
+	}
+
+	. = ALIGN(32);
+	.data : {
+		*(.data)
+		*(.data.*)
+		. = . + 524288;		/* workaround for buggy bootloaders */
+	}
+
+	. = ALIGN(32);
+	_code_end = .;
+
+	_bss_start = .;
+	.bss : {
+		*(.bss)
+		*(.bss.*)
+	}
+
+	. = ALIGN(32);
+	_bss_end = .;
+
+	. = . + 8192;
+	_stack = .;
+
+	workspace = .;
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/loader2.lds b/target/linux/ar71xx/image/lzma-loader/src/loader2.lds
new file mode 100644
index 0000000000..db0bb46424
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/loader2.lds
@@ -0,0 +1,10 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+	.text : {
+		startup = .;
+		*(.text)
+		*(.text.*)
+		*(.data)
+		*(.data.*)
+	}
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/lzma-data.lds b/target/linux/ar71xx/image/lzma-loader/src/lzma-data.lds
new file mode 100644
index 0000000000..abf756ba13
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/lzma-data.lds
@@ -0,0 +1,8 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+	.data.lzma : {
+		_lzma_data_start = .;
+		*(.data)
+		_lzma_data_end = .;
+	}
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/printf.c b/target/linux/ar71xx/image/lzma-loader/src/printf.c
new file mode 100644
index 0000000000..7bb5a86e18
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/printf.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include	"printf.h"
+
+extern void board_putc(int ch);
+
+/* this is the maximum width for a variable */
+#define		LP_MAX_BUF	256
+
+/* macros */
+#define		IsDigit(x)	( ((x) >= '0') && ((x) <= '9') )
+#define		Ctod(x)		( (x) - '0')
+
+/* forward declaration */
+static int PrintChar(char *, char, int, int);
+static int PrintString(char *, char *, int, int);
+static int PrintNum(char *, unsigned long, int, int, int, int, char, int);
+
+/* private variable */
+static const char theFatalMsg[] = "fatal error in lp_Print!";
+
+/* -*-
+ * A low level printf() function.
+ */
+static void
+lp_Print(void (*output)(void *, char *, int),
+	 void * arg,
+	 char *fmt,
+	 va_list ap)
+{
+
+#define 	OUTPUT(arg, s, l)  \
+  { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
+       (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
+    } else { \
+      (*output)(arg, s, l); \
+    } \
+  }
+
+    char buf[LP_MAX_BUF];
+
+    char c;
+    char *s;
+    long int num;
+
+    int longFlag;
+    int negFlag;
+    int width;
+    int prec;
+    int ladjust;
+    char padc;
+
+    int length;
+
+    for(;;) {
+	{
+	    /* scan for the next '%' */
+	    char *fmtStart = fmt;
+	    while ( (*fmt != '\0') && (*fmt != '%')) {
+		fmt ++;
+	    }
+
+	    /* flush the string found so far */
+	    OUTPUT(arg, fmtStart, fmt-fmtStart);
+
+	    /* are we hitting the end? */
+	    if (*fmt == '\0') break;
+	}
+
+	/* we found a '%' */
+	fmt ++;
+
+	/* check for long */
+	if (*fmt == 'l') {
+	    longFlag = 1;
+	    fmt ++;
+	} else {
+	    longFlag = 0;
+	}
+
+	/* check for other prefixes */
+	width = 0;
+	prec = -1;
+	ladjust = 0;
+	padc = ' ';
+
+	if (*fmt == '-') {
+	    ladjust = 1;
+	    fmt ++;
+	}
+
+	if (*fmt == '0') {
+	    padc = '0';
+	    fmt++;
+	}
+
+	if (IsDigit(*fmt)) {
+	    while (IsDigit(*fmt)) {
+		width = 10 * width + Ctod(*fmt++);
+	    }
+	}
+
+	if (*fmt == '.') {
+	    fmt ++;
+	    if (IsDigit(*fmt)) {
+		prec = 0;
+		while (IsDigit(*fmt)) {
+		    prec = prec*10 + Ctod(*fmt++);
+		}
+	    }
+	}
+
+
+	/* check format flag */
+	negFlag = 0;
+	switch (*fmt) {
+	 case 'b':
+	    if (longFlag) {
+		num = va_arg(ap, long int);
+	    } else {
+		num = va_arg(ap, int);
+	    }
+	    length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'd':
+	 case 'D':
+	    if (longFlag) {
+		num = va_arg(ap, long int);
+	    } else {
+		num = va_arg(ap, int);
+	    }
+	    if (num < 0) {
+		num = - num;
+		negFlag = 1;
+	    }
+	    length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'o':
+	 case 'O':
+	    if (longFlag) {
+		num = va_arg(ap, long int);
+	    } else {
+		num = va_arg(ap, int);
+	    }
+	    length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'u':
+	 case 'U':
+	    if (longFlag) {
+		num = va_arg(ap, long int);
+	    } else {
+		num = va_arg(ap, int);
+	    }
+	    length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'x':
+	    if (longFlag) {
+		num = va_arg(ap, long int);
+	    } else {
+		num = va_arg(ap, int);
+	    }
+	    length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'X':
+	    if (longFlag) {
+		num = va_arg(ap, long int);
+	    } else {
+		num = va_arg(ap, int);
+	    }
+	    length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'c':
+	    c = (char)va_arg(ap, int);
+	    length = PrintChar(buf, c, width, ladjust);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 's':
+	    s = (char*)va_arg(ap, char *);
+	    length = PrintString(buf, s, width, ladjust);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case '\0':
+	    fmt --;
+	    break;
+
+	 default:
+	    /* output this char as it is */
+	    OUTPUT(arg, fmt, 1);
+	}	/* switch (*fmt) */
+
+	fmt ++;
+    }		/* for(;;) */
+
+    /* special termination call */
+    OUTPUT(arg, "\0", 1);
+}
+
+
+/* --------------- local help functions --------------------- */
+static int
+PrintChar(char * buf, char c, int length, int ladjust)
+{
+    int i;
+
+    if (length < 1) length = 1;
+    if (ladjust) {
+	*buf = c;
+	for (i=1; i< length; i++) buf[i] = ' ';
+    } else {
+	for (i=0; i< length-1; i++) buf[i] = ' ';
+	buf[length - 1] = c;
+    }
+    return length;
+}
+
+static int
+PrintString(char * buf, char* s, int length, int ladjust)
+{
+    int i;
+    int len=0;
+    char* s1 = s;
+    while (*s1++) len++;
+    if (length < len) length = len;
+
+    if (ladjust) {
+	for (i=0; i< len; i++) buf[i] = s[i];
+	for (i=len; i< length; i++) buf[i] = ' ';
+    } else {
+	for (i=0; i< length-len; i++) buf[i] = ' ';
+	for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
+    }
+    return length;
+}
+
+static int
+PrintNum(char * buf, unsigned long u, int base, int negFlag,
+	 int length, int ladjust, char padc, int upcase)
+{
+    /* algorithm :
+     *  1. prints the number from left to right in reverse form.
+     *  2. fill the remaining spaces with padc if length is longer than
+     *     the actual length
+     *     TRICKY : if left adjusted, no "0" padding.
+     *		    if negtive, insert  "0" padding between "0" and number.
+     *  3. if (!ladjust) we reverse the whole string including paddings
+     *  4. otherwise we only reverse the actual string representing the num.
+     */
+
+    int actualLength =0;
+    char *p = buf;
+    int i;
+
+    do {
+	int tmp = u %base;
+	if (tmp <= 9) {
+	    *p++ = '0' + tmp;
+	} else if (upcase) {
+	    *p++ = 'A' + tmp - 10;
+	} else {
+	    *p++ = 'a' + tmp - 10;
+	}
+	u /= base;
+    } while (u != 0);
+
+    if (negFlag) {
+	*p++ = '-';
+    }
+
+    /* figure out actual length and adjust the maximum length */
+    actualLength = p - buf;
+    if (length < actualLength) length = actualLength;
+
+    /* add padding */
+    if (ladjust) {
+	padc = ' ';
+    }
+    if (negFlag && !ladjust && (padc == '0')) {
+	for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
+	buf[length -1] = '-';
+    } else {
+	for (i = actualLength; i< length; i++) buf[i] = padc;
+    }
+
+
+    /* prepare to reverse the string */
+    {
+	int begin = 0;
+	int end;
+	if (ladjust) {
+	    end = actualLength - 1;
+	} else {
+	    end = length -1;
+	}
+
+	while (end > begin) {
+	    char tmp = buf[begin];
+	    buf[begin] = buf[end];
+	    buf[end] = tmp;
+	    begin ++;
+	    end --;
+	}
+    }
+
+    /* adjust the string pointer */
+    return length;
+}
+
+static void printf_output(void *arg, char *s, int l)
+{
+    int i;
+
+    // special termination call
+    if ((l==1) && (s[0] == '\0')) return;
+
+    for (i=0; i< l; i++) {
+	board_putc(s[i]);
+	if (s[i] == '\n') board_putc('\r');
+    }
+}
+
+void printf(char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    lp_Print(printf_output, 0, fmt, ap);
+    va_end(ap);
+}
diff --git a/target/linux/ar71xx/image/lzma-loader/src/printf.h b/target/linux/ar71xx/image/lzma-loader/src/printf.h
new file mode 100644
index 0000000000..9b1c1df232
--- /dev/null
+++ b/target/linux/ar71xx/image/lzma-loader/src/printf.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _printf_h_
+#define _printf_h_
+
+#include <stdarg.h>
+void printf(char *fmt, ...);
+
+#endif /* _printf_h_ */
diff --git a/target/linux/ar71xx/image/nand.mk b/target/linux/ar71xx/image/nand.mk
new file mode 100644
index 0000000000..b02b896435
--- /dev/null
+++ b/target/linux/ar71xx/image/nand.mk
@@ -0,0 +1,78 @@
+define Device/c-60
+  DEVICE_TITLE := AirTight C-60
+  DEVICE_PACKAGES := kmod-spi-gpio kmod-usb-core kmod-usb2 kmod-ath9k
+  BOARDNAME = C-60
+  BLOCKSIZE := 64k
+  KERNEL_SIZE = 3648k
+  IMAGE_SIZE = 32m
+  IMAGES := sysupgrade.tar
+  MTDPARTS = spi0.0:256k(u-boot)ro,128k(u-boot-env)ro,3648k(kernel),64k(art)ro;ar934x-nfc:32m(ubi)
+  KERNEL := kernel-bin | patch-cmdline | lzma | uImage lzma
+  IMAGE/sysupgrade.tar := sysupgrade-tar
+endef
+
+TARGET_DEVICES += c-60
+
+define Build/MerakiNAND
+	-$(STAGING_DIR_HOST)/bin/mkmerakifw \
+		-B $(BOARDNAME) -s \
+		-i $@ \
+		-o $@.new
+	@mv $@.new $@
+endef
+
+define Device/mr18
+  DEVICE_TITLE := Meraki MR18
+  DEVICE_PACKAGES := kmod-spi-gpio kmod-ath9k
+  BOARDNAME = MR18
+  BLOCKSIZE := 64k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = ar934x-nfc:512k(nandloader)ro,8M(kernel),8M(recovery),113664k(ubi),128k@130944k(odm-caldata)ro
+  IMAGES := sysupgrade.tar
+  KERNEL := kernel-bin | patch-cmdline | MerakiNAND
+  KERNEL_INITRAMFS := kernel-bin | patch-cmdline | MerakiNAND
+  IMAGE/sysupgrade.tar := sysupgrade-tar
+endef
+TARGET_DEVICES += mr18
+
+define Build/MerakiNAND-old
+	-$(STAGING_DIR_HOST)/bin/mkmerakifw-old \
+		-B $(BOARDNAME) -s \
+		-i $@ \
+		-o $@.new
+	@mv $@.new $@
+endef
+
+define Device/z1
+  DEVICE_TITLE := Meraki Z1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport kmod-spi-gpio kmod-ath9k kmod-owl-loader
+  BOARDNAME = Z1
+  BLOCKSIZE := 64k
+  CONSOLE = ttyS0,115200
+  MTDPARTS = ar934x-nfc:128K(loader1)ro,8064K(kernel),128K(loader2)ro,8064K(recovery),114560K(ubi),128K(origcaldata)ro
+  IMAGES := sysupgrade.tar
+  KERNEL := kernel-bin | patch-cmdline | MerakiNAND-old
+  KERNEL_INITRAMFS := kernel-bin | patch-cmdline | MerakiNAND-old
+  IMAGE/sysupgrade.tar := sysupgrade-tar
+endef
+
+TARGET_DEVICES += z1
+
+define LegacyDevice/R6100
+  DEVICE_TITLE := NETGEAR R6100
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += R6100
+
+define LegacyDevice/WNDR3700V4
+  DEVICE_TITLE := NETGEAR WNDR3700v4
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WNDR3700V4
+
+define LegacyDevice/WNDR4300V1
+  DEVICE_TITLE := NETGEAR WNDR4300v1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+endef
+LEGACY_DEVICES += WNDR4300V1
+
diff --git a/target/linux/ar71xx/image/tp-link.mk b/target/linux/ar71xx/image/tp-link.mk
new file mode 100644
index 0000000000..c96ffd58ad
--- /dev/null
+++ b/target/linux/ar71xx/image/tp-link.mk
@@ -0,0 +1,855 @@
+DEVICE_VARS += TPLINK_HWID TPLINK_HWREV TPLINK_FLASHLAYOUT TPLINK_HEADER_VERSION TPLINK_BOARD_NAME
+
+# combine kernel and rootfs into one image
+# mktplinkfw <type> <optional extra arguments to mktplinkfw binary>
+# <type> is "sysupgrade" or "factory"
+#
+# -a align the rootfs start on an <align> bytes boundary
+# -j add jffs2 end-of-filesystem markers
+# -s strip padding from end of the image
+# -X reserve <size> bytes in the firmware image (hexval prefixed with 0x)
+define Build/mktplinkfw
+	-$(STAGING_DIR_HOST)/bin/mktplinkfw \
+		-H $(TPLINK_HWID) -W $(TPLINK_HWREV) -F $(TPLINK_FLASHLAYOUT) -N OpenWrt -V $(REVISION) \
+		-m $(TPLINK_HEADER_VERSION) \
+		-k $(IMAGE_KERNEL) \
+		-r $@ \
+		-o $@.new \
+		-j -X 0x40000 \
+		-a $(call rootfs_align,$(FILESYSTEM)) \
+		$(wordlist 2,$(words $(1)),$(1)) \
+		$(if $(findstring sysupgrade,$(word 1,$(1))),-s) && mv $@.new $@ || rm -f $@
+endef
+
+# mktplinkfw-initramfs <optional extra arguments to mktplinkfw binary>
+#
+# -c combined image
+define Build/mktplinkfw-initramfs
+	$(STAGING_DIR_HOST)/bin/mktplinkfw \
+		-H $(TPLINK_HWID) -W $(TPLINK_HWREV) -F $(TPLINK_FLASHLAYOUT) -N OpenWrt -V $(REVISION) $(1) \
+		-m $(TPLINK_HEADER_VERSION) \
+		-k $@ \
+		-o $@.new \
+		-s -S \
+		-c
+	@mv $@.new $@
+endef
+
+define Device/tplink
+  TPLINK_HWREV := 0x1
+  TPLINK_HEADER_VERSION := 1
+  LOADER_TYPE := gz
+  KERNEL := kernel-bin | patch-cmdline | lzma
+  KERNEL_INITRAMFS := kernel-bin | patch-cmdline | lzma | mktplinkfw-initramfs
+  IMAGES := sysupgrade.bin factory.bin
+  IMAGE/sysupgrade.bin := append-rootfs | mktplinkfw sysupgrade
+  IMAGE/factory.bin := append-rootfs | mktplinkfw factory
+endef
+
+define Device/tplink-nolzma
+$(Device/tplink)
+  LOADER_FLASH_OFFS := 0x22000
+  COMPILE := loader-$(1).gz
+  COMPILE/loader-$(1).gz := loader-okli-compile
+  KERNEL := copy-file $(KDIR)/vmlinux.bin.lzma | uImage lzma -M 0x4f4b4c49 | loader-okli $(1)
+  KERNEL_INITRAMFS := copy-file $(KDIR)/vmlinux-initramfs.bin.lzma | loader-kernel-cmdline | mktplinkfw-initramfs
+endef
+
+define Device/tplink-4m
+$(Device/tplink-nolzma)
+  TPLINK_FLASHLAYOUT := 4M
+  IMAGE_SIZE := 3904k
+endef
+
+define Device/tplink-8m
+$(Device/tplink-nolzma)
+  TPLINK_FLASHLAYOUT := 8M
+  IMAGE_SIZE := 7936k
+endef
+
+define Device/tplink-4mlzma
+$(Device/tplink)
+  TPLINK_FLASHLAYOUT := 4Mlzma
+  IMAGE_SIZE := 3904k
+endef
+
+define Device/tplink-8mlzma
+$(Device/tplink)
+  TPLINK_FLASHLAYOUT := 8Mlzma
+  IMAGE_SIZE := 7936k
+endef
+
+define Device/tplink-16mlzma
+$(Device/tplink)
+  TPLINK_FLASHLAYOUT := 16Mlzma
+  IMAGE_SIZE := 15872k
+endef
+
+define Device/cpe510-520
+  DEVICE_TITLE := TP-LINK CPE510/520
+  DEVICE_PACKAGES := rssileds
+  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)
+  IMAGE_SIZE := 7680k
+  BOARDNAME := CPE510
+  TPLINK_BOARD_NAME := CPE510
+  DEVICE_PROFILE := CPE510
+  LOADER_TYPE := elf
+  KERNEL := kernel-bin | patch-cmdline | lzma | loader-kernel
+  IMAGES := sysupgrade.bin factory.bin
+  IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade
+  IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
+endef
+
+define Device/cpe210-220
+$(Device/cpe510-520)
+  DEVICE_TITLE := TP-LINK CPE210/220
+  DEVICE_PACKAGES := rssileds
+  BOARDNAME := CPE210
+  TPLINK_BOARD_NAME := CPE210
+endef
+TARGET_DEVICES += cpe210-220 cpe510-520
+
+define Device/eap120
+  DEVICE_TITLE := TP-LINK EAP120
+  MTDPARTS := spi0.0:128k(u-boot)ro,64k(pation-table)ro,64k(product-info)ro,1536k(kernel),14336k(rootfs),192k(config)ro,64k(ART)ro,15872k@0x40000(firmware)
+  IMAGE_SIZE := 15872k
+  BOARDNAME := EAP120
+  TPLINK_BOARD_NAME := EAP120
+  DEVICE_PROFILE := EAP120
+  LOADER_TYPE := elf
+  KERNEL := kernel-bin | patch-cmdline | lzma | loader-kernel
+  IMAGES := sysupgrade.bin factory.bin
+  IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade
+  IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
+endef
+TARGET_DEVICES += eap120
+
+define Device/tl-wdr4300-v1
+$(Device/tplink-8mlzma)
+  DEVICE_TITLE := TP-LINK TL-WDR4300 v1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME := TL-WDR4300
+  DEVICE_PROFILE := TLWDR4300
+  TPLINK_HWID := 0x43000001
+  IMAGE/factory.bin := append-rootfs | mktplinkfw factory -C US
+endef
+
+define Device/tl-wdr3500-v1
+$(Device/tplink-8mlzma)
+  DEVICE_TITLE := TP-LINK TL-WDR3500 v1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME := TL-WDR3500
+  DEVICE_PROFILE := TLWDR4300
+  TPLINK_HWID := 0x35000001
+endef
+
+define Device/tl-wdr3600-v1
+$(Device/tplink-8mlzma)
+  DEVICE_TITLE := TP-LINK TL-WDR3600 v1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME := TL-WDR4300
+  DEVICE_PROFILE := TLWDR4300
+  TPLINK_HWID := 0x36000001
+  IMAGE/factory.bin := append-rootfs | mktplinkfw factory -C US
+endef
+
+define Device/tl-wdr4300-v1-il
+$(Device/tplink-8mlzma)
+  DEVICE_TITLE := TP-LINK TL-WDR4300 v1 IL
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME := TL-WDR4300
+  DEVICE_PROFILE := TLWDR4300
+  TPLINK_HWID := 0x43008001
+endef
+
+define Device/tl-wdr4310-v1
+$(Device/tplink-8mlzma)
+  DEVICE_TITLE := TP-LINK TL-WDR4310 v1
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME := TL-WDR4300
+  DEVICE_PROFILE = TLWDR4300
+  TPLINK_HWID := 0x43100001
+endef
+
+define Device/mw4530r-v1
+$(Device/tl-wdr4300-v1)
+  DEVICE_TITLE := Mercury MW4530R v1
+  TPLINK_HWID := 0x45300001
+endef
+TARGET_DEVICES += tl-wdr3500-v1 tl-wdr3600-v1 tl-wdr4300-v1 tl-wdr4300-v1-il tl-wdr4310-v1 mw4530r-v1
+
+define Device/tl-wdr3320-v2
+$(Device/tplink-4mlzma)
+  DEVICE_TITLE := TP-LINK TL-WDR3320v2
+  DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+  BOARDNAME = TL-WDR3320-v2
+  DEVICE_PROFILE = TLWDR3320V2
+  TPLINK_HWID := 0x33200002
+  TPLINK_HEADER_VERSION := 2
+endef
+TARGET_DEVICES += tl-wdr3320-v2
+
+define Device/tl-mr10u-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR10U
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-MR10U
+    DEVICE_PROFILE := TLMR10U
+    TPLINK_HWID := 0x00100101
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr11u-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR11U
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR11U
+    DEVICE_PROFILE := TLMR11U
+    TPLINK_HWID := 0x00110101
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr11u-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR11U v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR11U
+    DEVICE_PROFILE := TLMR11U
+    TPLINK_HWID := 0x00110102
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr12u-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR12U
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR13U
+    DEVICE_PROFILE := TLMR12U
+    TPLINK_HWID := 0x00120101
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr13u-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR13U
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR13U
+    DEVICE_PROFILE := TLMR13U
+    TPLINK_HWID := 0x00130101
+    CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-mr10u-v1 tl-mr11u-v1 tl-mr11u-v2 tl-mr12u-v1 tl-mr13u-v1
+
+define Device/tl-mr3020-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR3020
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3020
+    DEVICE_PROFILE := TLMR3020
+    TPLINK_HWID := 0x30200001
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3040-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR3040
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3040
+    DEVICE_PROFILE := TLMR3040
+    TPLINK_HWID := 0x30400001
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3040-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR3040
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3040-v2
+    DEVICE_PROFILE := TLMR3040
+    TPLINK_HWID := 0x30400002
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3220-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-MR3220
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3220
+    DEVICE_PROFILE := TLMR3220
+    TPLINK_HWID := 0x32200001
+endef
+
+define Device/tl-mr3220-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR3220 v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3220-v2
+    DEVICE_PROFILE := TLMR3220
+    TPLINK_HWID := 0x32200002
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-mr3420-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-MR3420
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3420
+    DEVICE_PROFILE := TLMR3420
+    TPLINK_HWID := 0x34200001
+endef
+
+define Device/tl-mr3420-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-MR3420 v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3420-v2
+    DEVICE_PROFILE := TLMR3420
+    TPLINK_HWID := 0x34200002
+endef
+TARGET_DEVICES += tl-mr3020-v1 tl-mr3040-v1 tl-mr3040-v2 tl-mr3220-v1 tl-mr3220-v2 tl-mr3420-v1 tl-mr3420-v2
+
+define Device/tl-wr703n-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR703N
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR703N
+    DEVICE_PROFILE := TLWR703
+    TPLINK_HWID := 0x07030101
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr710n-v1
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR710N
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR710N
+    DEVICE_PROFILE := TLWR710
+    TPLINK_HWID := 0x07100001
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr710n-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR710N v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR710N v2
+    DEVICE_PROFILE := TLWR710
+    TPLINK_HWID := 0x07100002
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr710n-v2.1
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR710N v2.1
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR710N v2.1
+    DEVICE_PROFILE := TLWR710
+    TPLINK_HWID := 0x07100002
+    TPLINK_HWREV := 0x00000002
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr720n-v3
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR720N v3
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR720N-v3
+    DEVICE_PROFILE := TLWR720
+    TPLINK_HWID := 0x07200103
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr720n-v4
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR720N v4
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR720N-v3
+    DEVICE_PROFILE := TLWR720
+    TPLINK_HWID := 0x07200104
+    CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-wr703n-v1 tl-wr710n-v1 tl-wr710n-v2 tl-wr710n-v2.1 tl-wr720n-v3 tl-wr720n-v4
+
+define Device/tl-wr740n-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR740N/ND v1
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR740
+    TPLINK_HWID := 0x07400001
+endef
+
+define Device/tl-wr740n-v3
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR740N/ND v3
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR740
+    TPLINK_HWID := 0x07400003
+endef
+
+define Device/tl-wr740n-v4
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR740N/ND v4
+    BOARDNAME := TL-WR741ND-v4
+    DEVICE_PROFILE := TLWR740
+    TPLINK_HWID := 0x07400004
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr740n-v5
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR740N/ND v5
+    BOARDNAME := TL-WR741ND-v4
+    DEVICE_PROFILE := TLWR740
+    TPLINK_HWID := 0x07400005
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr740n-v6
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR740N/ND v6
+    BOARDNAME := TL-WR841N-v9
+    DEVICE_PROFILE := TLWR740
+    TPLINK_HWID := 0x07400006
+endef
+
+define Device/tl-wr741nd-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR741N/ND v1
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR741
+    TPLINK_HWID := 0x07410001
+endef
+
+define Device/tl-wr741nd-v2
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR741N/ND v2
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR741
+    TPLINK_HWID := 0x07410001
+endef
+
+define Device/tl-wr741nd-v4
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR741N/ND v4
+    BOARDNAME := TL-WR741ND-v4
+    DEVICE_PROFILE := TLWR741
+    TPLINK_HWID := 0x07410004
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr741nd-v5
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR741N/ND v5
+    BOARDNAME := TL-WR741ND-v4
+    DEVICE_PROFILE := TLWR741
+    TPLINK_HWID := 0x07400005
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wr810n
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-Link TL-WR810N
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2
+    BOARDNAME := TL-WR810N
+    DEVICE_PROFILE := TLWR810
+    TPLINK_HWID := 0x08100001
+endef
+TARGET_DEVICES += tl-wr810n
+
+define Device/tl-wr743nd-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR743N/ND v1
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR743
+    TPLINK_HWID := 0x07430001
+endef
+
+define Device/tl-wr743nd-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR743N/ND v2
+    BOARDNAME := TL-WR741ND-v4
+    DEVICE_PROFILE := TLWR743
+    TPLINK_HWID := 0x07430002
+    CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-wr740n-v1 tl-wr740n-v3 tl-wr740n-v4 tl-wr740n-v5 tl-wr740n-v6 tl-wr741nd-v1 tl-wr741nd-v2 tl-wr741nd-v4 tl-wr741nd-v5 tl-wr743nd-v1 tl-wr743nd-v2
+
+define Device/tl-wr802n-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR802N v1
+	BOARDNAME := TL-WR802N-v1
+    DEVICE_PROFILE := TLWR802
+    TPLINK_HWID := 0x08020001
+    TPLINK_HWREV := 1
+endef
+TARGET_DEVICES += tl-wr802n-v1
+
+define Device/tl-wr841-v1.5
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v1.5
+    BOARDNAME := TL-WR841N-v1.5
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410002
+    TPLINK_HWREV := 2
+endef
+
+define Device/tl-wr841-v3
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v3
+    BOARDNAME := TL-WR941ND
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410003
+    TPLINK_HWREV := 3
+endef
+
+define Device/tl-wr841-v5
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v5
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410005
+endef
+
+define Device/tl-wr841-v7
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v7
+    BOARDNAME := TL-WR841N-v7
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410007
+endef
+
+define Device/tl-wr841-v8
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v8
+    BOARDNAME := TL-WR841N-v8
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410008
+endef
+
+define Device/tl-wr841-v9
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v9
+    BOARDNAME := TL-WR841N-v9
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410009
+endef
+
+define Device/tl-wr841-v10
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR841N/ND v10
+    BOARDNAME := TL-WR841N-v9
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08410010
+endef
+
+define Device/tl-wr841-v11
+   $(Device/tplink-4mlzma)
+   DEVICE_TITLE := TP-LINK TL-WR841N/ND v11
+   BOARDNAME := TL-WR841N-v11
+   DEVICE_PROFILE := TLWR841
+   TPLINK_HWID := 0x08410011
+   IMAGES += factory-us.bin factory-eu.bin
+   IMAGE/factory-us.bin := append-rootfs | mktplinkfw factory -C US
+   IMAGE/factory-eu.bin := append-rootfs | mktplinkfw factory -C EU
+endef
+
+define Device/tl-wr842n-v1
+    $(Device/tplink-8m)
+    DEVICE_TITLE := TP-LINK TL-WR842N/ND v1
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-MR3420
+    DEVICE_PROFILE := TLWR842
+    TPLINK_HWID := 0x08420001
+endef
+
+define Device/tl-wr842n-v2
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR842N/ND v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WR842N-v2
+    DEVICE_PROFILE := TLWR842
+    TPLINK_HWID := 0x8420002
+endef
+
+define Device/tl-wr842n-v3
+    $(Device/tplink-16mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR842N/ND v3
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WR842N-v3
+    DEVICE_PROFILE := TLWR842
+    TPLINK_HWID := 0x08420003
+endef
+
+define Device/tl-wr843nd-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR843N/ND
+    BOARDNAME := TL-WR841N-v8
+    DEVICE_PROFILE := TLWR843
+    TPLINK_HWID := 0x08430001
+endef
+
+define Device/tl-wr847n-v8
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR847N/ND v8
+    BOARDNAME := TL-WR841N-v8
+    DEVICE_PROFILE := TLWR841
+    TPLINK_HWID := 0x08470008
+endef
+TARGET_DEVICES += tl-wr841-v1.5 tl-wr841-v3 tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 tl-wr842n-v1 tl-wr842n-v2 tl-wr842n-v3 tl-wr843nd-v1 tl-wr847n-v8
+
+define Device/tl-wr941nd-v2
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR941N/ND v2
+    BOARDNAME := TL-WR941ND
+    DEVICE_PROFILE := TLWR941
+    TPLINK_HWID := 0x09410002
+    TPLINK_HWREV := 2
+endef
+
+define Device/tl-wr941nd-v3
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR941N/ND v3
+    BOARDNAME := TL-WR941ND
+    DEVICE_PROFILE := TLWR941
+    TPLINK_HWID := 0x09410002
+    TPLINK_HWREV := 2
+endef
+
+define Device/tl-wr941nd-v4
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WR941N/ND v4
+    BOARDNAME := TL-WR741ND
+    DEVICE_PROFILE := TLWR941
+    TPLINK_HWID := 0x09410004
+endef
+
+define Device/tl-wr941nd-v5
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR941N/ND v5
+    BOARDNAME := TL-WR941ND-v5
+    DEVICE_PROFILE := TLWR941
+    TPLINK_HWID := 0x09410005
+endef
+
+define Device/tl-wr941nd-v6
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR941N/ND v6
+    BOARDNAME := TL-WR941ND-v6
+    DEVICE_PROFILE := TLWR941
+    TPLINK_HWID := 0x09410006
+endef
+
+# Chinese version (unlike European) is similar to the TL-WDR3500
+define Device/tl-wr941nd-v6-cn
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR941N/ND v6 (CN)
+    BOARDNAME := TL-WDR3500
+    DEVICE_PROFILE := TLWR941
+    TPLINK_HWID := 0x09410006
+endef
+TARGET_DEVICES += tl-wr941nd-v2 tl-wr941nd-v3 tl-wr941nd-v4 tl-wr941nd-v5 tl-wr941nd-v6 tl-wr941nd-v6-cn
+
+define Device/tl-wr1041n-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR1041N
+    BOARDNAME := TL-WR1041N-v2
+    DEVICE_PROFILE := TLWR1041
+    TPLINK_HWID := 0x10410002
+endef
+TARGET_DEVICES += tl-wr1041n-v2
+
+define Device/tl-wr1043nd-v1
+    $(Device/tplink-8m)
+    DEVICE_TITLE := TP-LINK TL-WR1043N/ND v1
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WR1043ND
+    DEVICE_PROFILE := TLWR1043
+    TPLINK_HWID := 0x10430001
+endef
+
+define Device/tl-wr1043nd-v2
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR1043N/ND v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WR1043ND-v2
+    DEVICE_PROFILE := TLWR1043
+    TPLINK_HWID := 0x10430002
+endef
+
+define Device/tl-wr1043nd-v3
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR1043N/ND v3
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WR1043ND-v2
+    DEVICE_PROFILE := TLWR1043
+    TPLINK_HWID := 0x10430003
+endef
+TARGET_DEVICES += tl-wr1043nd-v1 tl-wr1043nd-v2 tl-wr1043nd-v3
+
+define Device/tl-wr2543-v1
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WR2543N/ND
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WR2543N
+    DEVICE_PROFILE := TLWR2543
+    TPLINK_HWID := 0x25430001
+    IMAGE/sysupgrade.bin := append-rootfs | mktplinkfw sysupgrade -v 3.13.99
+    IMAGE/factory.bin := append-rootfs | mktplinkfw factory -v 3.13.99
+endef
+TARGET_DEVICES += tl-wr2543-v1
+
+define Device/tl-wdr4900-v2
+    $(Device/tplink-8mlzma)
+    DEVICE_TITLE := TP-LINK TL-WDR4900v2
+    DEVICE_PACKAGES := kmod-usb-core kmod-usb2 kmod-usb-ledtrig-usbport
+    BOARDNAME := TL-WDR4900-v2
+    DEVICE_PROFILE := TLWDR4900V2
+    TPLINK_HWID := 0x49000002
+endef
+TARGET_DEVICES += tl-wdr4900-v2
+
+define Device/tl-wa701nd-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA701N/ND v1
+    BOARDNAME := TL-WA901ND
+    DEVICE_PROFILE := TLWA701
+    TPLINK_HWID := 0x07010001
+endef
+
+define Device/tl-wa701nd-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA701N/ND v2
+    BOARDNAME := TL-WA701ND-v2
+    DEVICE_PROFILE := TLWA701
+    TPLINK_HWID := 0x07010002
+    CONSOLE := ttyATH0,115200
+endef
+
+define Device/tl-wa730re-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA730RE
+    BOARDNAME := TL-WA901ND
+    DEVICE_PROFILE := TLWA730RE
+    TPLINK_HWID := 0x07300001
+endef
+
+define Device/tl-wa750re-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA750RE
+    DEVICE_PACKAGES := rssileds
+    BOARDNAME := TL-WA750RE
+    DEVICE_PROFILE := TLWA750
+    TPLINK_HWID := 0x07500001
+endef
+
+define Device/tl-wa7510n
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA7510N
+    BOARDNAME := TL-WA7510N
+    DEVICE_PROFILE := TLWA7510
+    TPLINK_HWID := 0x75100001
+endef
+TARGET_DEVICES += tl-wa701nd-v1 tl-wa701nd-v2 tl-wa730re-v1 tl-wa750re-v1 tl-wa7510n
+
+define Device/tl-wa801nd-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA801N/ND v1
+    BOARDNAME := TL-WA901ND
+    DEVICE_PROFILE := TLWA801
+    TPLINK_HWID := 0x08010001
+endef
+
+define Device/tl-wa801nd-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA801N/ND v2
+    BOARDNAME := TL-WA801ND-v2
+    DEVICE_PROFILE := TLWA801
+    TPLINK_HWID := 0x08010002
+endef
+
+define Device/tl-wa801nd-v3
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA801N/ND v3
+    BOARDNAME := TL-WA801ND-v3
+    DEVICE_PROFILE := TLWA801
+    TPLINK_HWID := 0x08010003
+endef
+
+define Device/tl-wa830re-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA830RE
+    BOARDNAME := TL-WA901ND
+    DEVICE_PROFILE := TLWA830
+    TPLINK_HWID := 0x08300010
+endef
+
+define Device/tl-wa830re-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA830RE
+    BOARDNAME := TL-WA830RE-v2
+    DEVICE_PROFILE := TLWA830
+    TPLINK_HWID := 0x08300002
+endef
+
+define Device/tl-wa850re-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA850RE
+    BOARDNAME := TL-WA850RE
+    DEVICE_PROFILE := TLWA850
+    TPLINK_HWID := 0x08500001
+endef
+
+define Device/tl-wa860re-v1
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA860RE
+    BOARDNAME := TL-WA860RE
+    DEVICE_PROFILE := TLWA860
+    TPLINK_HWID := 0x08600001
+endef
+TARGET_DEVICES += tl-wa801nd-v1 tl-wa801nd-v2 tl-wa801nd-v3 tl-wa830re-v1 tl-wa830re-v2 tl-wa850re-v1 tl-wa860re-v1
+
+define Device/tl-wa901nd-v1
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA901N/ND v1
+    BOARDNAME := TL-WA901ND
+    DEVICE_PROFILE := TLWA901
+    TPLINK_HWID := 0x09010001
+endef
+
+define Device/tl-wa901nd-v2
+    $(Device/tplink-4m)
+    DEVICE_TITLE := TP-LINK TL-WA901N/ND v2
+    BOARDNAME := TL-WA901ND-v2
+    DEVICE_PROFILE := TLWA901
+    TPLINK_HWID := 0x09010002
+endef
+
+define Device/tl-wa901nd-v3
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA901N/ND v3
+    BOARDNAME := TL-WA901ND-v3
+    DEVICE_PROFILE := TLWA901
+    TPLINK_HWID := 0x09010003
+endef
+
+define Device/tl-wa901nd-v4
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA901N/ND v4
+    BOARDNAME := TL-WA901ND-v4
+    DEVICE_PROFILE := TLWA901
+    TPLINK_HWID := 0x09010004
+    IMAGE/factory.bin := append-rootfs | mktplinkfw factory -C EU
+endef
+
+TARGET_DEVICES += tl-wa901nd-v1 tl-wa901nd-v2 tl-wa901nd-v3 tl-wa901nd-v4
+
+define Device/tl-wa7210n-v2
+    $(Device/tplink-4mlzma)
+    DEVICE_TITLE := TP-LINK TL-WA7210N
+    DEVICE_PACKAGES := rssileds kmod-ledtrig-netdev
+    BOARDNAME := TL-WA7210N-v2
+    DEVICE_PROFILE := TLWA7210
+    TPLINK_HWID := 0x72100002
+    CONSOLE := ttyATH0,115200
+endef
+TARGET_DEVICES += tl-wa7210n-v2
diff --git a/target/linux/ar71xx/image/ubinize-nbg6716.ini b/target/linux/ar71xx/image/ubinize-nbg6716.ini
new file mode 100644
index 0000000000..814b0fbcc8
--- /dev/null
+++ b/target/linux/ar71xx/image/ubinize-nbg6716.ini
@@ -0,0 +1,24 @@
+[rootfs]
+# Volume mode (other option is static)
+mode=ubi
+# Source image
+image=ubi_root.img
+# Volume ID in UBI image
+vol_id=0
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs
+
+[rootfs_data]
+# Volume mode (other option is static)
+mode=ubi
+# Volume ID in UBI image
+vol_id=1
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs_data
+# Autoresize volume at first mount
+vol_size=1MiB
+vol_flags=autoresize
diff --git a/target/linux/ar71xx/image/ubinize-wndr4300.ini b/target/linux/ar71xx/image/ubinize-wndr4300.ini
new file mode 100644
index 0000000000..5bff906ae8
--- /dev/null
+++ b/target/linux/ar71xx/image/ubinize-wndr4300.ini
@@ -0,0 +1,26 @@
+[rootfs]
+# Volume mode (other option is static)
+mode=ubi
+# Source image
+image=root.squashfs
+# Volume ID in UBI image
+vol_id=0
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs
+# Autoresize volume at first mount
+# vol_flags=autoresize
+
+[rootfs_data]
+# Volume mode (other option is static)
+mode=ubi
+# Volume ID in UBI image
+vol_id=1
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs_data
+# Autoresize volume at first mount
+vol_flags=autoresize
+vol_size=1MiB
diff --git a/target/linux/ar71xx/mikrotik/config-default b/target/linux/ar71xx/mikrotik/config-default
new file mode 100644
index 0000000000..e17b16635e
--- /dev/null
+++ b/target/linux/ar71xx/mikrotik/config-default
@@ -0,0 +1,176 @@
+# CONFIG_ATH79_DEV_DSA is not set
+# CONFIG_ATH79_MACH_ALFA_AP96 is not set
+# CONFIG_ATH79_MACH_ALFA_NX is not set
+# CONFIG_ATH79_MACH_ALL0258N is not set
+# CONFIG_ATH79_MACH_ALL0315N is not set
+# CONFIG_ATH79_MACH_ANTMINER_S1 is not set
+# CONFIG_ATH79_MACH_AP113 is not set
+# CONFIG_ATH79_MACH_AP121 is not set
+# CONFIG_ATH79_MACH_AP132 is not set
+# CONFIG_ATH79_MACH_AP136 is not set
+# CONFIG_ATH79_MACH_AP147 is not set
+# CONFIG_ATH79_MACH_AP81 is not set
+# CONFIG_ATH79_MACH_AP83 is not set
+# CONFIG_ATH79_MACH_AP96 is not set
+# CONFIG_ATH79_MACH_ARCHER_C7 is not set
+# CONFIG_ATH79_MACH_AW_NR580 is not set
+# CONFIG_ATH79_MACH_BHU_BXU2000N2_A is not set
+# CONFIG_ATH79_MACH_CAP324 is not set
+# CONFIG_ATH79_MACH_CAP4200AG is not set
+# CONFIG_ATH79_MACH_CARAMBOLA2 is not set
+# CONFIG_ATH79_MACH_CPE510 is not set
+# CONFIG_ATH79_MACH_CR3000 is not set
+# CONFIG_ATH79_MACH_CR5000 is not set
+# CONFIG_ATH79_MACH_DB120 is not set
+# CONFIG_ATH79_MACH_DGL_5500_A1 is not set
+# CONFIG_ATH79_MACH_DHP_1565_A1 is not set
+# CONFIG_ATH79_MACH_DIR_505_A1 is not set
+# CONFIG_ATH79_MACH_DIR_600_A1 is not set
+# CONFIG_ATH79_MACH_DIR_615_C1 is not set
+# CONFIG_ATH79_MACH_DIR_825_B1 is not set
+# CONFIG_ATH79_MACH_DIR_825_C1 is not set
+# CONFIG_ATH79_MACH_DIR_869_A1 is not set
+# CONFIG_ATH79_MACH_DRAGINO2 is not set
+# CONFIG_ATH79_MACH_EAP300V2 is not set
+# CONFIG_ATH79_MACH_EAP7660D is not set
+# CONFIG_ATH79_MACH_EL_M150 is not set
+# CONFIG_ATH79_MACH_EL_MINI is not set
+# CONFIG_ATH79_MACH_EPG5000 is not set
+# CONFIG_ATH79_MACH_ESR1750 is not set
+# CONFIG_ATH79_MACH_ESR900 is not set
+# CONFIG_ATH79_MACH_EW_DORIN is not set
+# CONFIG_ATH79_MACH_F9K1115V2 is not set
+# CONFIG_ATH79_MACH_GL_INET is not set
+# CONFIG_ATH79_MACH_GS_OOLITE is not set
+# CONFIG_ATH79_MACH_HIWIFI_HC6361 is not set
+# CONFIG_ATH79_MACH_HORNET_UB is not set
+# CONFIG_ATH79_MACH_JA76PF is not set
+# CONFIG_ATH79_MACH_JWAP003 is not set
+# CONFIG_ATH79_MACH_MC_MAC1200R is not set
+# CONFIG_ATH79_MACH_MR12 is not set
+# CONFIG_ATH79_MACH_MR16 is not set
+# CONFIG_ATH79_MACH_MR600 is not set
+# CONFIG_ATH79_MACH_MR900 is not set
+# CONFIG_ATH79_MACH_MYNET_N600 is not set
+# CONFIG_ATH79_MACH_MYNET_N750 is not set
+# CONFIG_ATH79_MACH_MYNET_REXT is not set
+# CONFIG_ATH79_MACH_MZK_W04NU is not set
+# CONFIG_ATH79_MACH_MZK_W300NH is not set
+# CONFIG_ATH79_MACH_NBG460N is not set
+# CONFIG_ATH79_MACH_NBG6716 is not set
+# CONFIG_ATH79_MACH_OM2P is not set
+# CONFIG_ATH79_MACH_OM5P is not set
+# CONFIG_ATH79_MACH_PB42 is not set
+# CONFIG_ATH79_MACH_PB44 is not set
+# CONFIG_ATH79_MACH_PB92 is not set
+# CONFIG_ATH79_MACH_QIHOO_C301 is not set
+# CONFIG_ATH79_MACH_R6100 is not set
+CONFIG_ATH79_MACH_RB2011=y
+CONFIG_ATH79_MACH_RB4XX=y
+CONFIG_ATH79_MACH_RB750=y
+CONFIG_ATH79_MACH_RB91X=y
+CONFIG_ATH79_MACH_RB922=y
+CONFIG_ATH79_MACH_RB95X=y
+CONFIG_ATH79_MACH_RBSXTLITE=y
+# CONFIG_ATH79_MACH_RW2458N is not set
+# CONFIG_ATH79_MACH_SMART_300 is not set
+# CONFIG_ATH79_MACH_TEW_632BRP is not set
+# CONFIG_ATH79_MACH_TEW_673GRU is not set
+# CONFIG_ATH79_MACH_TEW_712BR is not set
+# CONFIG_ATH79_MACH_TEW_732BR is not set
+# CONFIG_ATH79_MACH_TL_MR11U is not set
+# CONFIG_ATH79_MACH_TL_MR13U is not set
+# CONFIG_ATH79_MACH_TL_MR3020 is not set
+# CONFIG_ATH79_MACH_TL_MR3X20 is not set
+# CONFIG_ATH79_MACH_TL_WA701ND_V2 is not set
+# CONFIG_ATH79_MACH_TL_WA7210N_V2 is not set
+# CONFIG_ATH79_MACH_TL_WA830RE_V2 is not set
+# CONFIG_ATH79_MACH_TL_WA901ND is not set
+# CONFIG_ATH79_MACH_TL_WA901ND_V2 is not set
+# CONFIG_ATH79_MACH_TL_WAX50RE is not set
+# CONFIG_ATH79_MACH_TL_WDR3500 is not set
+# CONFIG_ATH79_MACH_TL_WDR4300 is not set
+# CONFIG_ATH79_MACH_TL_WR1041N_V2 is not set
+# CONFIG_ATH79_MACH_TL_WR1043ND is not set
+# CONFIG_ATH79_MACH_TL_WR1043ND_V2 is not set
+# CONFIG_ATH79_MACH_TL_WR2543N is not set
+# CONFIG_ATH79_MACH_TL_WR703N is not set
+# CONFIG_ATH79_MACH_TL_WR720N_V3 is not set
+# CONFIG_ATH79_MACH_TL_WR741ND is not set
+# CONFIG_ATH79_MACH_TL_WR741ND_V4 is not set
+# CONFIG_ATH79_MACH_TL_WR802N_V1 is not set
+# CONFIG_ATH79_MACH_TL_WR841N_V1 is not set
+# CONFIG_ATH79_MACH_TL_WR841N_V8 is not set
+# CONFIG_ATH79_MACH_TL_WR841N_V9 is not set
+# CONFIG_ATH79_MACH_TL_WR941ND is not set
+# CONFIG_ATH79_MACH_TUBE2H is not set
+# CONFIG_ATH79_MACH_UBNT is not set
+# CONFIG_ATH79_MACH_UBNT_UNIFIAC is not set
+# CONFIG_ATH79_MACH_UBNT_XM is not set
+# CONFIG_ATH79_MACH_WHR_HP_G300N is not set
+# CONFIG_ATH79_MACH_WLAE_AG300N is not set
+# CONFIG_ATH79_MACH_WLR8100 is not set
+# CONFIG_ATH79_MACH_WNDAP360 is not set
+# CONFIG_ATH79_MACH_WNDR3700 is not set
+# CONFIG_ATH79_MACH_WNDR4300 is not set
+# CONFIG_ATH79_MACH_WNR2000 is not set
+# CONFIG_ATH79_MACH_WNR2000_V3 is not set
+# CONFIG_ATH79_MACH_WNR2000_V4 is not set
+# CONFIG_ATH79_MACH_WNR2200 is not set
+# CONFIG_ATH79_MACH_WP543 is not set
+# CONFIG_ATH79_MACH_WPE72 is not set
+# CONFIG_ATH79_MACH_WPJ342 is not set
+# CONFIG_ATH79_MACH_WPJ344 is not set
+# CONFIG_ATH79_MACH_WPJ531 is not set
+# CONFIG_ATH79_MACH_WPJ558 is not set
+# CONFIG_ATH79_MACH_WRT160NL is not set
+# CONFIG_ATH79_MACH_WRT400N is not set
+# CONFIG_ATH79_MACH_WZR_450HP2 is not set
+# CONFIG_ATH79_MACH_WZR_HP_AG300H is not set
+# CONFIG_ATH79_MACH_WZR_HP_G300NH is not set
+# CONFIG_ATH79_MACH_WZR_HP_G300NH2 is not set
+# CONFIG_ATH79_MACH_WZR_HP_G450H is not set
+# CONFIG_ATH79_MACH_ZCN_1523H is not set
+# CONFIG_ATH79_NVRAM is not set
+CONFIG_ATH79_ROUTERBOOT=y
+CONFIG_CMDLINE="rootfstype=yaffs noinitrd"
+CONFIG_GPIO_74X164=y
+CONFIG_GPIO_LATCH=y
+# CONFIG_JFFS2_FS is not set
+CONFIG_LEDS_RB750=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_GPIO=y
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MYLOADER_PARTS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_AR934X=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_RB4XX=y
+CONFIG_MTD_NAND_RB750=y
+CONFIG_MTD_NAND_RB91X=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+# CONFIG_MTD_TPLINK_PARTS is not set
+# CONFIG_OVERLAY_FS is not set
+CONFIG_RLE_DECOMPRESS=y
+# CONFIG_SOC_AR913X is not set
+# CONFIG_SOC_AR933X is not set
+# CONFIG_SOC_QCA953X is not set
+CONFIG_SPI_RB4XX=y
+CONFIG_SPI_RB4XX_CPLD=y
+# CONFIG_SQUASHFS is not set
+CONFIG_YAFFS_9BYTE_TAGS=y
+CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_BACKGROUND is not set
+# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set
+# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_XATTR=y
+CONFIG_YAFFS_YAFFS1=y
+CONFIG_YAFFS_YAFFS2=y
diff --git a/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk b/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk
new file mode 100644
index 0000000000..a334977d48
--- /dev/null
+++ b/target/linux/ar71xx/mikrotik/profiles/01-minimal.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/DefaultNoWifi
+	NAME:=Default Profile (no WiFi)
+	PACKAGES:=
+	PRIORITY := 2
+endef
+
+define Profile/DefaultNoWifi/Description
+	Default package set compatible with most boards.
+endef
+$(eval $(call Profile,DefaultNoWifi))
diff --git a/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk b/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk
new file mode 100644
index 0000000000..fa304b7d4c
--- /dev/null
+++ b/target/linux/ar71xx/mikrotik/profiles/02-ath5k.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2009-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Ath5k
+	NAME:=Atheros WiFi (ath5k)
+	PACKAGES:=kmod-ath5k -kmod-ath9k
+	PRIORITY := 3
+endef
+
+define Profile/Ath5k/Description
+	Package set compatible with hardware using Atheros WiFi cards.
+endef
+$(eval $(call Profile,Ath5k))
diff --git a/target/linux/ar71xx/mikrotik/target.mk b/target/linux/ar71xx/mikrotik/target.mk
new file mode 100644
index 0000000000..cb2447aee8
--- /dev/null
+++ b/target/linux/ar71xx/mikrotik/target.mk
@@ -0,0 +1,9 @@
+BOARDNAME:=Mikrotik devices with NAND/NOR flash
+FEATURES += targz ramdisk minor
+
+define Target/Description
+	Build firmware images for Atheros AR71xx/AR913x based Mikrotik boards.
+	e.g. MikroTik RB-4xx or RB-750
+endef
+
+
diff --git a/target/linux/ar71xx/modules.mk b/target/linux/ar71xx/modules.mk
new file mode 100644
index 0000000000..9ead8b451c
--- /dev/null
+++ b/target/linux/ar71xx/modules.mk
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define KernelPackage/leds-nu801
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=Meraki MR18 LED support
+  DEPENDS:=@TARGET_ar71xx
+  KCONFIG:=CONFIG_LEDS_NU801
+  FILES:=$(LINUX_DIR)/drivers/leds/leds-nu801.ko
+  AUTOLOAD:=$(call AutoLoad,60,leds-nu801)
+endef
+
+define KernelPackage/leds-nu801/description
+ Kernel module for the nu801 LED driver used on the Meraki MR18.
+endef
+
+$(eval $(call KernelPackage,leds-nu801))
+
+
+define KernelPackage/leds-rb750
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=RouterBOARD 750 LED support
+  DEPENDS:=@TARGET_ar71xx
+  KCONFIG:=CONFIG_LEDS_RB750
+  FILES:=$(LINUX_DIR)/drivers/leds/leds-rb750.ko
+  AUTOLOAD:=$(call AutoLoad,60,leds-rb750)
+endef
+
+define KernelPackage/leds-rb750/description
+ Kernel module for the LEDs on the MikroTik RouterBOARD 750.
+endef
+
+$(eval $(call KernelPackage,leds-rb750))
+
+
+define KernelPackage/leds-wndr3700-usb
+  SUBMENU:=$(LEDS_MENU)
+  TITLE:=WNDR3700 USB LED support
+  DEPENDS:=@TARGET_ar71xx
+  KCONFIG:=CONFIG_LEDS_WNDR3700_USB
+  FILES:=$(LINUX_DIR)/drivers/leds/leds-wndr3700-usb.ko
+  AUTOLOAD:=$(call AutoLoad,60,leds-wndr3700-usb)
+endef
+
+define KernelPackage/leds-wndr3700-usb/description
+ Kernel module for the USB LED on the NETGEAR WNDR3700 board.
+endef
+
+$(eval $(call KernelPackage,leds-wndr3700-usb))
+
+
+define KernelPackage/spi-vsc7385
+  SUBMENU:=$(SPI_MENU)
+  TITLE:=Vitesse VSC7385 ethernet switch driver
+  DEPENDS:=@TARGET_ar71xx
+  KCONFIG:=CONFIG_SPI_VSC7385
+  FILES:=$(LINUX_DIR)/drivers/spi/spi-vsc7385.ko
+  AUTOLOAD:=$(call AutoLoad,93,spi-vsc7385)
+endef
+
+define KernelPackage/spi-vsc7385/description
+  This package contains the SPI driver for the Vitesse VSC7385 ethernet switch.
+endef
+
+$(eval $(call KernelPackage,spi-vsc7385))
diff --git a/target/linux/ar71xx/nand/config-default b/target/linux/ar71xx/nand/config-default
new file mode 100644
index 0000000000..7f94781b8c
--- /dev/null
+++ b/target/linux/ar71xx/nand/config-default
@@ -0,0 +1,118 @@
+# CONFIG_ATH79_DEV_DSA is not set
+# CONFIG_ATH79_MACH_ALFA_AP96 is not set
+# CONFIG_ATH79_MACH_ALFA_NX is not set
+# CONFIG_ATH79_MACH_ALL0258N is not set
+# CONFIG_ATH79_MACH_ALL0315N is not set
+# CONFIG_ATH79_MACH_AP113 is not set
+# CONFIG_ATH79_MACH_AP121 is not set
+# CONFIG_ATH79_MACH_AP132 is not set
+# CONFIG_ATH79_MACH_AP136 is not set
+# CONFIG_ATH79_MACH_AP147 is not set
+# CONFIG_ATH79_MACH_AP81 is not set
+# CONFIG_ATH79_MACH_AP83 is not set
+# CONFIG_ATH79_MACH_AP96 is not set
+# CONFIG_ATH79_MACH_ARCHER_C7 is not set
+# CONFIG_ATH79_MACH_AW_NR580 is not set
+# CONFIG_ATH79_MACH_CAP324 is not set
+# CONFIG_ATH79_MACH_CAP4200AG is not set
+# CONFIG_ATH79_MACH_CARAMBOLA2 is not set
+# CONFIG_ATH79_MACH_CR3000 is not set
+# CONFIG_ATH79_MACH_CR5000 is not set
+# CONFIG_ATH79_MACH_DB120 is not set
+# CONFIG_ATH79_MACH_DIR_505_A1 is not set
+# CONFIG_ATH79_MACH_DIR_600_A1 is not set
+# CONFIG_ATH79_MACH_DIR_615_C1 is not set
+# CONFIG_ATH79_MACH_DIR_825_B1 is not set
+# CONFIG_ATH79_MACH_DIR_825_C1 is not set
+# CONFIG_ATH79_MACH_DIR_869_A1 is not set
+# CONFIG_ATH79_MACH_EAP7660D is not set
+# CONFIG_ATH79_MACH_EW_DORIN is not set
+# CONFIG_ATH79_MACH_HORNET_UB is not set
+# CONFIG_ATH79_MACH_JA76PF is not set
+# CONFIG_ATH79_MACH_JWAP003 is not set
+# CONFIG_ATH79_MACH_MR600 is not set
+# CONFIG_ATH79_MACH_MYNET_N600 is not set
+# CONFIG_ATH79_MACH_MZK_W04NU is not set
+# CONFIG_ATH79_MACH_MZK_W300NH is not set
+# CONFIG_ATH79_MACH_NBG460N is not set
+# CONFIG_ATH79_MACH_OM2P is not set
+# CONFIG_ATH79_MACH_PB42 is not set
+# CONFIG_ATH79_MACH_PB44 is not set
+# CONFIG_ATH79_MACH_PB92 is not set
+# CONFIG_ATH79_MACH_RW2458N is not set
+# CONFIG_ATH79_MACH_TEW_632BRP is not set
+# CONFIG_ATH79_MACH_TEW_673GRU is not set
+# CONFIG_ATH79_MACH_TEW_712BR is not set
+# CONFIG_ATH79_MACH_TEW_732BR is not set
+# CONFIG_ATH79_MACH_TL_MR11U is not set
+# CONFIG_ATH79_MACH_TL_MR13U is not set
+# CONFIG_ATH79_MACH_TL_MR3020 is not set
+# CONFIG_ATH79_MACH_TL_MR3X20 is not set
+# CONFIG_ATH79_MACH_TL_WA901ND is not set
+# CONFIG_ATH79_MACH_TL_WA901ND_V2 is not set
+# CONFIG_ATH79_MACH_TL_WDR3500 is not set
+# CONFIG_ATH79_MACH_TL_WDR4300 is not set
+# CONFIG_ATH79_MACH_TL_WR1041N_V2 is not set
+# CONFIG_ATH79_MACH_TL_WR1043ND is not set
+# CONFIG_ATH79_MACH_TL_WR2543N is not set
+# CONFIG_ATH79_MACH_TL_WR703N is not set
+# CONFIG_ATH79_MACH_TL_WR720N_V3 is not set
+# CONFIG_ATH79_MACH_TL_WR741ND is not set
+# CONFIG_ATH79_MACH_TL_WR741ND_V4 is not set
+# CONFIG_ATH79_MACH_TL_WR841N_V1 is not set
+# CONFIG_ATH79_MACH_TL_WR841N_V8 is not set
+# CONFIG_ATH79_MACH_TL_WR941ND is not set
+# CONFIG_ATH79_MACH_UBNT is not set
+# CONFIG_ATH79_MACH_UBNT_UNIFIAC is not set
+# CONFIG_ATH79_MACH_UBNT_XM is not set
+# CONFIG_ATH79_MACH_WHR_HP_G300N is not set
+# CONFIG_ATH79_MACH_WLAE_AG300N is not set
+# CONFIG_ATH79_MACH_WNDAP360 is not set
+# CONFIG_ATH79_MACH_WNDR3700 is not set
+# CONFIG_ATH79_MACH_WNR2000 is not set
+# CONFIG_ATH79_MACH_WNR2000_V3 is not set
+# CONFIG_ATH79_MACH_WNR2200 is not set
+# CONFIG_ATH79_MACH_WP543 is not set
+# CONFIG_ATH79_MACH_WPE72 is not set
+# CONFIG_ATH79_MACH_WRT160NL is not set
+# CONFIG_ATH79_MACH_WRT400N is not set
+# CONFIG_ATH79_MACH_WZR_HP_AG300H is not set
+# CONFIG_ATH79_MACH_WZR_HP_G300NH is not set
+# CONFIG_ATH79_MACH_WZR_HP_G300NH2 is not set
+# CONFIG_ATH79_MACH_WZR_HP_G450H is not set
+# CONFIG_ATH79_MACH_ZCN_1523H is not set
+# CONFIG_ATH79_NVRAM is not set
+CONFIG_CMDLINE="rootfstype=squashfs noinitrd"
+# CONFIG_IP17XX_PHY is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MYLOADER_PARTS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_AR934X=y
+CONFIG_MTD_NAND_AR934X_HW_ECC=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_ECC_BCH=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_SPLIT_SEAMA_FW is not set
+# CONFIG_MTD_TPLINK_PARTS is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+# CONFIG_RTL8306_PHY is not set
+# CONFIG_RTL8366_SMI is not set
+# CONFIG_SOC_AR71XX is not set
+# CONFIG_SOC_AR724X is not set
+# CONFIG_SOC_AR913X is not set
+CONFIG_SPI_ATH79=y
+# CONFIG_SPI_BITBANG is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
diff --git a/target/linux/ar71xx/nand/profiles/00-default.mk b/target/linux/ar71xx/nand/profiles/00-default.mk
new file mode 100644
index 0000000000..06ab790389
--- /dev/null
+++ b/target/linux/ar71xx/nand/profiles/00-default.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Default
+	NAME:=Default Profile
+	PACKAGES:= \
+		kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport
+	PRIORITY := 1
+endef
+
+define Profile/Default/Description
+	Default package set compatible with most boards.
+endef
+$(eval $(call Profile,Default))
diff --git a/target/linux/ar71xx/nand/target.mk b/target/linux/ar71xx/nand/target.mk
new file mode 100644
index 0000000000..7532ec6958
--- /dev/null
+++ b/target/linux/ar71xx/nand/target.mk
@@ -0,0 +1,7 @@
+BOARDNAME := Generic devices with NAND flash
+FEATURES += squashfs nand rtc
+
+define Target/Description
+	Build firmware images for Atheros AR71xx/AR913x based boards with
+	NAND flash, e.g. Netgear WNDR4300.
+endef
diff --git a/target/linux/ar71xx/patches-4.4/001-revert_spi_device_tree_support.patch b/target/linux/ar71xx/patches-4.4/001-revert_spi_device_tree_support.patch
new file mode 100644
index 0000000000..9821eb7a85
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/001-revert_spi_device_tree_support.patch
@@ -0,0 +1,83 @@
+--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
++++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+@@ -16,4 +16,8 @@ struct ath79_spi_platform_data {
+ 	unsigned	num_chipselect;
+ };
+ 
++struct ath79_spi_controller_data {
++	unsigned	gpio;
++};
++
+ #endif /* _ATH79_SPI_PLATFORM_H */
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -79,8 +79,10 @@ static void ath79_spi_chipselect(struct
+ 	}
+ 
+ 	if (spi->chip_select) {
++		struct ath79_spi_controller_data *cdata = spi->controller_data;
++
+ 		/* SPI is normally active-low */
+-		gpio_set_value(spi->cs_gpio, cs_high);
++		gpio_set_value(cdata->gpio, cs_high);
+ 	} else {
+ 		if (cs_high)
+ 			sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+@@ -116,9 +118,10 @@ static void ath79_spi_disable(struct ath
+ static int ath79_spi_setup_cs(struct spi_device *spi)
+ {
+ 	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++	struct ath79_spi_controller_data *cdata = spi->controller_data;
+ 	int status;
+ 
+-	if (spi->chip_select && !gpio_is_valid(spi->cs_gpio))
++	if (spi->chip_select && (!cdata || !gpio_is_valid(cdata->gpio)))
+ 		return -EINVAL;
+ 
+ 	status = 0;
+@@ -131,7 +134,7 @@ static int ath79_spi_setup_cs(struct spi
+ 		else
+ 			flags |= GPIOF_INIT_HIGH;
+ 
+-		status = gpio_request_one(spi->cs_gpio, flags,
++		status = gpio_request_one(cdata->gpio, flags,
+ 					  dev_name(&spi->dev));
+ 	} else {
+ 		if (spi->mode & SPI_CS_HIGH)
+@@ -148,7 +151,8 @@ static int ath79_spi_setup_cs(struct spi
+ static void ath79_spi_cleanup_cs(struct spi_device *spi)
+ {
+ 	if (spi->chip_select) {
+-		gpio_free(spi->cs_gpio);
++		struct ath79_spi_controller_data *cdata = spi->controller_data;
++		gpio_free(cdata->gpio);
+ 	}
+ }
+ 
+@@ -220,7 +224,6 @@ static int ath79_spi_probe(struct platfo
+ 	}
+ 
+ 	sp = spi_master_get_devdata(master);
+-	master->dev.of_node = pdev->dev.of_node;
+ 	platform_set_drvdata(pdev, sp);
+ 
+ 	pdata = dev_get_platdata(&pdev->dev);
+@@ -300,18 +303,12 @@ static void ath79_spi_shutdown(struct pl
+ 	ath79_spi_remove(pdev);
+ }
+ 
+-static const struct of_device_id ath79_spi_of_match[] = {
+-	{ .compatible = "qca,ar7100-spi", },
+-	{ },
+-};
+-
+ static struct platform_driver ath79_spi_driver = {
+ 	.probe		= ath79_spi_probe,
+ 	.remove		= ath79_spi_remove,
+ 	.shutdown	= ath79_spi_shutdown,
+ 	.driver		= {
+ 		.name	= DRV_NAME,
+-		.of_match_table = ath79_spi_of_match,
+ 	},
+ };
+ module_platform_driver(ath79_spi_driver);
diff --git a/target/linux/ar71xx/patches-4.4/002-add_back_gpio_function_select.patch b/target/linux/ar71xx/patches-4.4/002-add_back_gpio_function_select.patch
new file mode 100644
index 0000000000..73cfeb5506
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/002-add_back_gpio_function_select.patch
@@ -0,0 +1,92 @@
+--- /dev/null
++++ b/arch/mips/ath79/gpio.c
+@@ -0,0 +1,59 @@
++/*
++ *  Atheros AR71XX/AR724X/AR913X GPIO API support
++ *
++ *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
++ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
++ *
++ *  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/kernel.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <asm/mach-ath79/ath79.h>
++#include "common.h"
++
++void __iomem *ath79_gpio_base;
++EXPORT_SYMBOL_GPL(ath79_gpio_base);
++
++static void __iomem *ath79_gpio_get_function_reg(void)
++{
++	u32 reg = 0;
++
++	if (soc_is_ar71xx() ||
++	    soc_is_ar724x() ||
++	    soc_is_ar913x() ||
++	    soc_is_ar933x())
++		reg = AR71XX_GPIO_REG_FUNC;
++	else if (soc_is_ar934x())
++		reg = AR934X_GPIO_REG_FUNC;
++	else
++		BUG();
++
++	return ath79_gpio_base + reg;
++}
++
++void ath79_gpio_function_setup(u32 set, u32 clear)
++{
++	void __iomem *reg = ath79_gpio_get_function_reg();
++
++	__raw_writel((__raw_readl(reg) & ~clear) | set, reg);
++	/* flush write */
++	__raw_readl(reg);
++}
++
++void ath79_gpio_function_enable(u32 mask)
++{
++	ath79_gpio_function_setup(mask, 0);
++}
++
++void ath79_gpio_function_disable(u32 mask)
++{
++	ath79_gpio_function_setup(0, mask);
++}
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -117,6 +117,7 @@ static inline int soc_is_qca955x(void)
+ 
+ void ath79_ddr_set_pci_windows(void);
+ 
++extern void __iomem *ath79_gpio_base;
+ extern void __iomem *ath79_pll_base;
+ extern void __iomem *ath79_reset_base;
+ 
+--- a/arch/mips/ath79/dev-common.c
++++ b/arch/mips/ath79/dev-common.c
+@@ -156,4 +156,5 @@ void __init ath79_gpio_init(void)
+ 	}
+ 
+ 	platform_device_register(&ath79_gpio_device);
++	ath79_gpio_base = ioremap(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
+ }
+--- a/arch/mips/ath79/common.h
++++ b/arch/mips/ath79/common.h
+@@ -25,6 +25,9 @@ unsigned long ath79_get_sys_clk_rate(con
+ void ath79_ddr_ctrl_init(void);
+ void ath79_ddr_wb_flush(unsigned int reg);
+ 
++void ath79_gpio_function_enable(u32 mask);
++void ath79_gpio_function_disable(u32 mask);
++void ath79_gpio_function_setup(u32 set, u32 clear);
+ void ath79_gpio_init(void);
+ 
+ #endif /* __ATH79_COMMON_H */
diff --git a/target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch b/target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch
new file mode 100644
index 0000000000..0c07cb18c7
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/004-register_gpio_driver_earlier.patch
@@ -0,0 +1,15 @@
+HACK: register the GPIO driver earlier to ensure that gpio_request calls
+from mach files succeed.
+
+--- a/drivers/gpio/gpio-ath79.c
++++ b/drivers/gpio/gpio-ath79.c
+@@ -202,4 +202,8 @@ static struct platform_driver ath79_gpio
+ 	.probe = ath79_gpio_probe,
+ };
+ 
+-module_platform_driver(ath79_gpio_driver);
++static int __init ath79_gpio_init(void)
++{
++	return platform_driver_register(&ath79_gpio_driver);
++}
++postcore_initcall(ath79_gpio_init);
diff --git a/target/linux/ar71xx/patches-4.4/100-MIPS-ath79-Avoid-using-unitialized-reg-variable.patch b/target/linux/ar71xx/patches-4.4/100-MIPS-ath79-Avoid-using-unitialized-reg-variable.patch
new file mode 100644
index 0000000000..8d5b089986
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/100-MIPS-ath79-Avoid-using-unitialized-reg-variable.patch
@@ -0,0 +1,42 @@
+From 8b7a76e72fc819753878cd5684e243f33f847c79 Mon Sep 17 00:00:00 2001
+From: Markos Chandras <markos.chandras@imgtec.com>
+Date: Wed, 21 Aug 2013 11:47:22 +0100
+Subject: [PATCH] MIPS: ath79: Avoid using unitialized 'reg' variable
+
+Fixes the following build error:
+arch/mips/include/asm/mach-ath79/ath79.h:139:20: error: 'reg' may be used
+uninitialized in this function [-Werror=maybe-uninitialized]
+arch/mips/ath79/common.c:62:6: note: 'reg' was declared here
+In file included from arch/mips/ath79/common.c:20:0:
+arch/mips/ath79/common.c: In function 'ath79_device_reset_clear':
+arch/mips/include/asm/mach-ath79/ath79.h:139:20:
+error: 'reg' may be used uninitialized in this function
+[-Werror=maybe-uninitialized]
+arch/mips/ath79/common.c:90:6: note: 'reg' was declared here
+
+Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
+Acked-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ arch/mips/ath79/common.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -106,7 +106,7 @@ void ath79_device_reset_set(u32 mask)
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
+ 	else
+-		BUG();
++		panic("Reset register not defined for this SOC");
+ 
+ 	spin_lock_irqsave(&ath79_device_reset_lock, flags);
+ 	t = ath79_reset_rr(reg);
+@@ -134,7 +134,7 @@ void ath79_device_reset_clear(u32 mask)
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
+ 	else
+-		BUG();
++		panic("Reset register not defined for this SOC");
+ 
+ 	spin_lock_irqsave(&ath79_device_reset_lock, flags);
+ 	t = ath79_reset_rr(reg);
diff --git a/target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch b/target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch
new file mode 100644
index 0000000000..09e6617b90
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/101-MIPS-ath79-make-ath79_ddr_ctrl_init-compatible-for-n.patch
@@ -0,0 +1,31 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 14 May 2016 20:20:04 +0200
+Subject: [PATCH] MIPS: ath79: make ath79_ddr_ctrl_init() compatible for newer
+ SoCs
+
+AR913x, AR724x and AR933x are the only SoCs where the
+ath79_ddr_wb_flush_base starts at 0x7c, all newer SoCs use 0x9c
+Invert the logic to make the code compatible with AR95xx
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -46,12 +46,12 @@ void ath79_ddr_ctrl_init(void)
+ {
+ 	ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
+ 					 AR71XX_DDR_CTRL_SIZE);
+-	if (soc_is_ar71xx() || soc_is_ar934x()) {
+-		ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c;
+-		ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c;
+-	} else {
++	if (soc_is_ar913x() || soc_is_ar724x() || soc_is_ar933x()) {
+ 		ath79_ddr_wb_flush_base = ath79_ddr_base + 0x7c;
+ 		ath79_ddr_pci_win_base = 0;
++	} else {
++		ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c;
++		ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c;
+ 	}
+ }
+ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init);
diff --git a/target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch b/target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch
new file mode 100644
index 0000000000..e5226a5dc3
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/102-MIPS-ath79-fix-regression-in-PCI-window-initializati.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 15 May 2016 13:09:20 +0200
+Subject: [PATCH] MIPS: ath79: fix regression in PCI window initialization
+
+ath79_ddr_pci_win_base has the type void __iomem *, so register offsets
+need to be a multiple of 4.
+
+Cc: Alban Bedel <albeu@free.fr>
+Fixes: 24b0e3e84fbf ("MIPS: ath79: Improve the DDR controller interface")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -76,14 +76,14 @@ void ath79_ddr_set_pci_windows(void)
+ {
+ 	BUG_ON(!ath79_ddr_pci_win_base);
+ 
+-	__raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0);
+-	__raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1);
+-	__raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2);
+-	__raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3);
+-	__raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4);
+-	__raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5);
+-	__raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6);
+-	__raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7);
++	__raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0x0);
++	__raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 0x4);
++	__raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 0x8);
++	__raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 0xc);
++	__raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 0x10);
++	__raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 0x14);
++	__raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 0x18);
++	__raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 0x1c);
+ }
+ EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows);
+ 
diff --git a/target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch b/target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch
new file mode 100644
index 0000000000..64fb545b24
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/103-MIPS-ath79-fix-register-address-in-ath79_ddr_wb_flus.patch
@@ -0,0 +1,23 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 18 May 2016 18:03:31 +0200
+Subject: [PATCH] MIPS: ath79: fix register address in ath79_ddr_wb_flush()
+
+ath79_ddr_wb_flush_base has the type void __iomem *, so register offsets
+need to be a multiple of 4.
+
+Cc: Alban Bedel <albeu@free.fr>
+Fixes: 24b0e3e84fbf ("MIPS: ath79: Improve the DDR controller interface")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init);
+ 
+ void ath79_ddr_wb_flush(u32 reg)
+ {
+-	void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg;
++	void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg * 4;
+ 
+ 	/* Flush the DDR write buffer. */
+ 	__raw_writel(0x1, flush_reg);
diff --git a/target/linux/ar71xx/patches-4.4/200-MIPS-ath79-fix-ar933x-wmac-reset.patch b/target/linux/ar71xx/patches-4.4/200-MIPS-ath79-fix-ar933x-wmac-reset.patch
new file mode 100644
index 0000000000..e0821a7776
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/200-MIPS-ath79-fix-ar933x-wmac-reset.patch
@@ -0,0 +1,31 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -62,10 +62,27 @@ static void __init ar913x_wmac_setup(voi
+ 
+ static int ar933x_wmac_reset(void)
+ {
++	int retries = 20;
++
+ 	ath79_device_reset_set(AR933X_RESET_WMAC);
+ 	ath79_device_reset_clear(AR933X_RESET_WMAC);
+ 
+-	return 0;
++	while (1) {
++		u32 bootstrap;
++
++		bootstrap = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
++		if ((bootstrap & AR933X_BOOTSTRAP_EEPBUSY) == 0)
++			return 0;
++
++		if (retries-- == 0)
++			break;
++
++		udelay(10000);
++		retries++;
++	}
++
++	pr_err("ar933x: WMAC reset timed out");
++	return -ETIMEDOUT;
+ }
+ 
+ static int ar933x_r1_get_wmac_revision(void)
diff --git a/target/linux/ar71xx/patches-4.4/201-ar913x_wmac_external_reset.patch b/target/linux/ar71xx/patches-4.4/201-ar913x_wmac_external_reset.patch
new file mode 100644
index 0000000000..9b704a3c47
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/201-ar913x_wmac_external_reset.patch
@@ -0,0 +1,31 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -44,7 +44,7 @@ static struct platform_device ath79_wmac
+ 	},
+ };
+ 
+-static void __init ar913x_wmac_setup(void)
++static int ar913x_wmac_reset(void)
+ {
+ 	/* reset the WMAC */
+ 	ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
+@@ -53,10 +53,19 @@ static void __init ar913x_wmac_setup(voi
+ 	ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
+ 	mdelay(10);
+ 
++	return 0;
++}
++
++static void __init ar913x_wmac_setup(void)
++{
++	ar913x_wmac_reset();
++
+ 	ath79_wmac_resources[0].start = AR913X_WMAC_BASE;
+ 	ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1;
+ 	ath79_wmac_resources[1].start = ATH79_CPU_IRQ(2);
+ 	ath79_wmac_resources[1].end = ATH79_CPU_IRQ(2);
++
++	ath79_wmac_data.external_reset = ar913x_wmac_reset;
+ }
+ 
+ 
diff --git a/target/linux/ar71xx/patches-4.4/202-MIPS-ath79-ar934x-wmac-revision.patch b/target/linux/ar71xx/patches-4.4/202-MIPS-ath79-ar934x-wmac-revision.patch
new file mode 100644
index 0000000000..c91ecdf439
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/202-MIPS-ath79-ar934x-wmac-revision.patch
@@ -0,0 +1,11 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -140,6 +140,8 @@ static void ar934x_wmac_setup(void)
+ 		ath79_wmac_data.is_clk_25mhz = false;
+ 	else
+ 		ath79_wmac_data.is_clk_25mhz = true;
++
++	ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision;
+ }
+ 
+ static void qca955x_wmac_setup(void)
diff --git a/target/linux/ar71xx/patches-4.4/203-MIPS-ath79-fix-restart.patch b/target/linux/ar71xx/patches-4.4/203-MIPS-ath79-fix-restart.patch
new file mode 100644
index 0000000000..77773ea920
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/203-MIPS-ath79-fix-restart.patch
@@ -0,0 +1,20 @@
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -44,6 +44,7 @@ static char ath79_sys_type[ATH79_SYS_TYP
+ 
+ static void ath79_restart(char *command)
+ {
++	local_irq_disable();
+ 	ath79_device_reset_set(AR71XX_RESET_FULL_CHIP);
+ 	for (;;)
+ 		if (cpu_wait)
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -134,6 +134,7 @@ static inline u32 ath79_pll_rr(unsigned
+ static inline void ath79_reset_wr(unsigned reg, u32 val)
+ {
+ 	__raw_writel(val, ath79_reset_base + reg);
++	(void) __raw_readl(ath79_reset_base + reg); /* flush */
+ }
+ 
+ static inline u32 ath79_reset_rr(unsigned reg)
diff --git a/target/linux/ar71xx/patches-4.4/206-spi-ath79-make-chipselect-logic-more-flexible.patch b/target/linux/ar71xx/patches-4.4/206-spi-ath79-make-chipselect-logic-more-flexible.patch
new file mode 100644
index 0000000000..e0863a4a02
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/206-spi-ath79-make-chipselect-logic-more-flexible.patch
@@ -0,0 +1,199 @@
+From 7008284716403237f6bc7d7590b3ed073555bd56 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Wed, 11 Jan 2012 22:25:11 +0100
+Subject: [PATCH 34/34] spi/ath79: make chipselect logic more flexible
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ arch/mips/ath79/mach-pb44.c                        |    6 ++
+ .../include/asm/mach-ath79/ath79_spi_platform.h    |    8 ++-
+ drivers/spi/spi-ath79.c                            |   67 +++++++++++++-------
+ 8 files changed, 88 insertions(+), 23 deletions(-)
+
+--- a/arch/mips/ath79/mach-pb44.c
++++ b/arch/mips/ath79/mach-pb44.c
+@@ -87,12 +87,18 @@ static struct gpio_keys_button pb44_gpio
+ 	}
+ };
+ 
++static struct ath79_spi_controller_data pb44_spi0_data = {
++	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
++	.cs_line = 0,
++};
++
+ static struct spi_board_info pb44_spi_info[] = {
+ 	{
+ 		.bus_num	= 0,
+ 		.chip_select	= 0,
+ 		.max_speed_hz	= 25000000,
+ 		.modalias	= "m25p64",
++		.controller_data = &pb44_spi0_data,
+ 	},
+ };
+ 
+--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
++++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+@@ -16,8 +16,14 @@ struct ath79_spi_platform_data {
+ 	unsigned	num_chipselect;
+ };
+ 
++enum ath79_spi_cs_type {
++	ATH79_SPI_CS_TYPE_INTERNAL,
++	ATH79_SPI_CS_TYPE_GPIO,
++};
++
+ struct ath79_spi_controller_data {
+-	unsigned	gpio;
++	enum ath79_spi_cs_type cs_type;
++	unsigned cs_line;
+ };
+ 
+ #endif /* _ATH79_SPI_PLATFORM_H */
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -33,6 +33,8 @@
+ #define ATH79_SPI_RRW_DELAY_FACTOR	12000
+ #define MHZ				(1000 * 1000)
+ 
++#define ATH79_SPI_CS_LINE_MAX		2
++
+ struct ath79_spi {
+ 	struct spi_bitbang	bitbang;
+ 	u32			ioc_base;
+@@ -67,6 +69,7 @@ static void ath79_spi_chipselect(struct
+ {
+ 	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
+ 	int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active;
++	struct ath79_spi_controller_data *cdata = spi->controller_data;
+ 
+ 	if (is_active) {
+ 		/* set initial clock polarity */
+@@ -78,20 +81,24 @@ static void ath79_spi_chipselect(struct
+ 		ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
+ 	}
+ 
+-	if (spi->chip_select) {
+-		struct ath79_spi_controller_data *cdata = spi->controller_data;
+-
+-		/* SPI is normally active-low */
+-		gpio_set_value(cdata->gpio, cs_high);
+-	} else {
++	switch (cdata->cs_type) {
++	case ATH79_SPI_CS_TYPE_INTERNAL:
+ 		if (cs_high)
+-			sp->ioc_base |= AR71XX_SPI_IOC_CS0;
++			sp->ioc_base |= AR71XX_SPI_IOC_CS(cdata->cs_line);
+ 		else
+-			sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
++			sp->ioc_base &= ~AR71XX_SPI_IOC_CS(cdata->cs_line);
+ 
+ 		ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
+-	}
++		break;
+ 
++	case ATH79_SPI_CS_TYPE_GPIO:
++		/* SPI is normally active-low */
++		if (gpio_cansleep(cdata->cs_line))
++			gpio_set_value_cansleep(cdata->cs_line, cs_high);
++		else
++			gpio_set_value(cdata->cs_line, cs_high);
++		break;
++	}
+ }
+ 
+ static void ath79_spi_enable(struct ath79_spi *sp)
+@@ -119,14 +126,15 @@ static int ath79_spi_setup_cs(struct spi
+ {
+ 	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
+ 	struct ath79_spi_controller_data *cdata = spi->controller_data;
++	unsigned long flags;
+ 	int status;
+ 
+-	if (spi->chip_select && (!cdata || !gpio_is_valid(cdata->gpio)))
++	if (!cdata)
+ 		return -EINVAL;
+ 
+ 	status = 0;
+-	if (spi->chip_select) {
+-		unsigned long flags;
++	switch (cdata->cs_type) {
++	case ATH79_SPI_CS_TYPE_GPIO:
+ 
+ 		flags = GPIOF_DIR_OUT;
+ 		if (spi->mode & SPI_CS_HIGH)
+@@ -134,15 +142,21 @@ static int ath79_spi_setup_cs(struct spi
+ 		else
+ 			flags |= GPIOF_INIT_HIGH;
+ 
+-		status = gpio_request_one(cdata->gpio, flags,
++		status = gpio_request_one(cdata->cs_line, flags,
+ 					  dev_name(&spi->dev));
+-	} else {
++		break;
++	case ATH79_SPI_CS_TYPE_INTERNAL:
++		if (cdata->cs_line > ATH79_SPI_CS_LINE_MAX)
++			status = -EINVAL;
++		break;
++
+ 		if (spi->mode & SPI_CS_HIGH)
+ 			sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
+ 		else
+ 			sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+ 
+ 		ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
++		break;
+ 	}
+ 
+ 	return status;
+@@ -150,9 +164,19 @@ static int ath79_spi_setup_cs(struct spi
+ 
+ static void ath79_spi_cleanup_cs(struct spi_device *spi)
+ {
+-	if (spi->chip_select) {
+-		struct ath79_spi_controller_data *cdata = spi->controller_data;
+-		gpio_free(cdata->gpio);
++	struct ath79_spi_controller_data *cdata;
++
++	cdata = spi->controller_data;
++	if (!cdata)
++		return;
++
++	switch (cdata->cs_type) {
++	case ATH79_SPI_CS_TYPE_INTERNAL:
++		/* nothing to do */
++		break;
++	case ATH79_SPI_CS_TYPE_GPIO:
++		gpio_free(cdata->cs_line);
++		break;
+ 	}
+ }
+ 
+@@ -217,6 +241,10 @@ static int ath79_spi_probe(struct platfo
+ 	unsigned long rate;
+ 	int ret;
+ 
++	pdata = pdev->dev.platform_data;
++	if (!pdata)
++		return -EINVAL;
++
+ 	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
+ 	if (master == NULL) {
+ 		dev_err(&pdev->dev, "failed to allocate spi master\n");
+@@ -226,15 +254,11 @@ static int ath79_spi_probe(struct platfo
+ 	sp = spi_master_get_devdata(master);
+ 	platform_set_drvdata(pdev, sp);
+ 
+-	pdata = dev_get_platdata(&pdev->dev);
+-
+ 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ 	master->setup = ath79_spi_setup;
+ 	master->cleanup = ath79_spi_cleanup;
+-	if (pdata) {
+-		master->bus_num = pdata->bus_num;
+-		master->num_chipselect = pdata->num_chipselect;
+-	}
++	master->bus_num = pdata->bus_num;
++	master->num_chipselect = pdata->num_chipselect;
+ 
+ 	sp->bitbang.master = master;
+ 	sp->bitbang.chipselect = ath79_spi_chipselect;
diff --git a/target/linux/ar71xx/patches-4.4/220-add_cpu_feature_overrides.patch b/target/linux/ar71xx/patches-4.4/220-add_cpu_feature_overrides.patch
new file mode 100644
index 0000000000..d925f92624
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/220-add_cpu_feature_overrides.patch
@@ -0,0 +1,28 @@
+--- a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
++++ b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
+@@ -36,6 +36,7 @@
+ #define cpu_has_mdmx		0
+ #define cpu_has_mips3d		0
+ #define cpu_has_smartmips	0
++#define cpu_has_rixi		0
+ 
+ #define cpu_has_mips32r1	1
+ #define cpu_has_mips32r2	1
+@@ -43,6 +44,7 @@
+ #define cpu_has_mips64r2	0
+ 
+ #define cpu_has_mipsmt		0
++#define cpu_has_userlocal	0
+ 
+ #define cpu_has_64bits		0
+ #define cpu_has_64bit_zero_reg	0
+@@ -51,5 +53,9 @@
+ 
+ #define cpu_dcache_line_size()	32
+ #define cpu_icache_line_size()	32
++#define cpu_has_vtag_icache	0
++#define cpu_has_dc_aliases	1
++#define cpu_has_ic_fills_f_dc	0
++#define cpu_has_pindexed_dcache	0
+ 
+ #endif /* __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H */
diff --git a/target/linux/ar71xx/patches-4.4/300-MIPS-add-MIPS_MACHINE_NONAME-macro.patch b/target/linux/ar71xx/patches-4.4/300-MIPS-add-MIPS_MACHINE_NONAME-macro.patch
new file mode 100644
index 0000000000..0bc64b7a17
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/300-MIPS-add-MIPS_MACHINE_NONAME-macro.patch
@@ -0,0 +1,21 @@
+--- a/arch/mips/include/asm/mips_machine.h
++++ b/arch/mips/include/asm/mips_machine.h
+@@ -36,6 +36,18 @@ static struct mips_machine machine_##_ty
+ 	.mach_setup	= _setup,				\
+ };
+ 
++#define MIPS_MACHINE_NONAME(_type, _id, _setup)		\
++static const char machine_id_##_type[] __initconst		\
++			__aligned(1) = _id;			\
++static struct mips_machine machine_##_type			\
++		__used __section(.mips.machines.init) =		\
++{								\
++	.mach_type	= _type,				\
++	.mach_id	= machine_id_##_type,			\
++	.mach_name	= NULL,					\
++	.mach_setup	= _setup,				\
++};
++
+ extern long __mips_machines_start;
+ extern long __mips_machines_end;
+ 
diff --git a/target/linux/ar71xx/patches-4.4/310-lib-add-rle-decompression.patch b/target/linux/ar71xx/patches-4.4/310-lib-add-rle-decompression.patch
new file mode 100644
index 0000000000..f5466db176
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/310-lib-add-rle-decompression.patch
@@ -0,0 +1,124 @@
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -247,6 +247,9 @@ config LZMA_COMPRESS
+ config LZMA_DECOMPRESS
+     tristate
+ 
++config RLE_DECOMPRESS
++	tristate
++
+ #
+ # These all provide a common interface (hence the apparent duplication with
+ # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.)
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -110,6 +110,7 @@ obj-$(CONFIG_XZ_DEC) += xz/
+ obj-$(CONFIG_RAID6_PQ) += raid6/
+ obj-$(CONFIG_LZMA_COMPRESS) += lzma/
+ obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/
++obj-$(CONFIG_RLE_DECOMPRESS) += rle.o
+ 
+ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
+ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+--- /dev/null
++++ b/include/linux/rle.h
+@@ -0,0 +1,18 @@
++#ifndef _RLE_H_
++#define _RLE_H_
++
++#ifdef CONFIG_RLE_DECOMPRESS
++int rle_decode(const unsigned char *src, size_t srclen,
++	       unsigned char *dst, size_t dstlen,
++	       size_t *src_done, size_t *dst_done);
++#else
++static inline int
++rle_decode(const unsigned char *src, size_t srclen,
++	   unsigned char *dst, size_t dstlen,
++	   size_t *src_done, size_t *dst_done)
++{
++	return -ENOTSUPP;
++}
++#endif /* CONFIG_RLE_DECOMPRESS */
++
++#endif /* _RLE_H_ */
+--- /dev/null
++++ b/lib/rle.c
+@@ -0,0 +1,78 @@
++/*
++ *  RLE decoding routine
++ *
++ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  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/kernel.h>
++#include <linux/module.h>
++#include <linux/rle.h>
++
++int rle_decode(const unsigned char *src, size_t srclen,
++	       unsigned char *dst, size_t dstlen,
++	       size_t *src_done, size_t *dst_done)
++{
++	size_t srcpos, dstpos;
++	int ret;
++
++	srcpos = 0;
++	dstpos = 0;
++	ret = -EINVAL;
++
++	/* sanity checks */
++	if (!src || !srclen || !dst || !dstlen)
++		goto out;
++
++	while (1) {
++		char count;
++
++		if (srcpos >= srclen)
++			break;
++
++		count = (char) src[srcpos++];
++		if (count == 0) {
++			ret = 0;
++			break;
++		}
++
++		if (count > 0) {
++			unsigned char c;
++
++			if (srcpos >= srclen)
++				break;
++
++			c = src[srcpos++];
++
++			while (count--) {
++				if (dstpos >= dstlen)
++					break;
++
++				dst[dstpos++] = c;
++			}
++		} else {
++			count *= -1;
++
++			while (count--) {
++				if (srcpos >= srclen)
++					break;
++				if (dstpos >= dstlen)
++					break;
++				dst[dstpos++] = src[srcpos++];
++			}
++		}
++	}
++
++out:
++	if (src_done)
++		*src_done = srcpos;
++	if (dst_done)
++		*dst_done = dstpos;
++
++	return ret;
++}
++
++EXPORT_SYMBOL_GPL(rle_decode);
diff --git a/target/linux/ar71xx/patches-4.4/401-mtd-physmap-add-lock-unlock.patch b/target/linux/ar71xx/patches-4.4/401-mtd-physmap-add-lock-unlock.patch
new file mode 100644
index 0000000000..db7b3ca83d
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/401-mtd-physmap-add-lock-unlock.patch
@@ -0,0 +1,94 @@
+--- a/drivers/mtd/maps/physmap.c
++++ b/drivers/mtd/maps/physmap.c
+@@ -31,6 +31,66 @@ struct physmap_flash_info {
+ 	int			vpp_refcnt;
+ };
+ 
++static struct platform_device *physmap_map2pdev(struct map_info *map)
++{
++	return (struct platform_device *) map->map_priv_1;
++}
++
++static void physmap_lock(struct map_info *map)
++{
++	struct platform_device *pdev;
++	struct physmap_flash_data *physmap_data;
++
++	pdev = physmap_map2pdev(map);
++	physmap_data = pdev->dev.platform_data;
++	physmap_data->lock(pdev);
++}
++
++static void physmap_unlock(struct map_info *map)
++{
++	struct platform_device *pdev;
++	struct physmap_flash_data *physmap_data;
++
++	pdev = physmap_map2pdev(map);
++	physmap_data = pdev->dev.platform_data;
++	physmap_data->unlock(pdev);
++}
++
++static map_word physmap_flash_read_lock(struct map_info *map, unsigned long ofs)
++{
++	map_word ret;
++
++	physmap_lock(map);
++	ret = inline_map_read(map, ofs);
++	physmap_unlock(map);
++
++	return ret;
++}
++
++static void physmap_flash_write_lock(struct map_info *map, map_word d,
++				     unsigned long ofs)
++{
++	physmap_lock(map);
++	inline_map_write(map, d, ofs);
++	physmap_unlock(map);
++}
++
++static void physmap_flash_copy_from_lock(struct map_info *map, void *to,
++					 unsigned long from, ssize_t len)
++{
++	physmap_lock(map);
++	inline_map_copy_from(map, to, from, len);
++	physmap_unlock(map);
++}
++
++static void physmap_flash_copy_to_lock(struct map_info *map, unsigned long to,
++				       const void *from, ssize_t len)
++{
++	physmap_lock(map);
++	inline_map_copy_to(map, to, from, len);
++	physmap_unlock(map);
++}
++
+ static int physmap_flash_remove(struct platform_device *dev)
+ {
+ 	struct physmap_flash_info *info;
+@@ -153,6 +213,13 @@ static int physmap_flash_probe(struct pl
+ 
+ 		simple_map_init(&info->map[i]);
+ 
++		if (physmap_data->lock && physmap_data->unlock) {
++			info->map[i].read = physmap_flash_read_lock;
++			info->map[i].write = physmap_flash_write_lock;
++			info->map[i].copy_from = physmap_flash_copy_from_lock;
++			info->map[i].copy_to = physmap_flash_copy_to_lock;
++		}
++
+ 		probe_type = rom_probe_types;
+ 		if (physmap_data->probe_type == NULL) {
+ 			for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
+--- a/include/linux/mtd/physmap.h
++++ b/include/linux/mtd/physmap.h
+@@ -25,6 +25,8 @@ struct physmap_flash_data {
+ 	unsigned int		width;
+ 	int			(*init)(struct platform_device *);
+ 	void			(*exit)(struct platform_device *);
++	void			(*lock)(struct platform_device *);
++	void			(*unlock)(struct platform_device *);
+ 	void			(*set_vpp)(struct platform_device *, int);
+ 	unsigned int		nr_parts;
+ 	unsigned int		pfow_base;
diff --git a/target/linux/ar71xx/patches-4.4/402-mtd-SST39VF6401B-support.patch b/target/linux/ar71xx/patches-4.4/402-mtd-SST39VF6401B-support.patch
new file mode 100644
index 0000000000..0d483ab1a4
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/402-mtd-SST39VF6401B-support.patch
@@ -0,0 +1,29 @@
+--- a/drivers/mtd/chips/jedec_probe.c
++++ b/drivers/mtd/chips/jedec_probe.c
+@@ -148,6 +148,7 @@
+ #define SST39LF160	0x2782
+ #define SST39VF1601	0x234b
+ #define SST39VF3201	0x235b
++#define SST39VF6401B	0x236d
+ #define SST39WF1601	0x274b
+ #define SST39WF1602	0x274a
+ #define SST39LF512	0x00D4
+@@ -1569,6 +1570,18 @@ static const struct amd_flash_info jedec
+ 			ERASEINFO(0x10000,64),
+ 		}
+ 	}, {
++		.mfr_id         = CFI_MFR_SST,
++		.dev_id         = SST39VF6401B,
++		.name           = "SST 39VF6401B",
++		.devtypes       = CFI_DEVICETYPE_X16,
++		.uaddr          = MTD_UADDR_0xAAAA_0x5555,
++		.dev_size       = SIZE_8MiB,
++		.cmd_set        = P_ID_AMD_STD,
++		.nr_regions     = 1,
++		.regions        = {
++			ERASEINFO(0x10000,128)
++		}
++	}, {
+ 		.mfr_id		= CFI_MFR_ST,
+ 		.dev_id		= M29F800AB,
+ 		.name		= "ST M29F800AB",
diff --git a/target/linux/ar71xx/patches-4.4/403-mtd_fix_cfi_cmdset_0002_status_check.patch b/target/linux/ar71xx/patches-4.4/403-mtd_fix_cfi_cmdset_0002_status_check.patch
new file mode 100644
index 0000000000..1ccce4ecec
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/403-mtd_fix_cfi_cmdset_0002_status_check.patch
@@ -0,0 +1,69 @@
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -1632,8 +1632,8 @@ static int __xipram do_write_oneword(str
+ 			break;
+ 		}
+ 
+-		if (chip_ready(map, adr))
+-			break;
++		if (chip_good(map, adr, datum))
++			goto enable_xip;
+ 
+ 		/* Latency issues. Drop the lock, wait a while and retry */
+ 		UDELAY(map, chip, adr, 1);
+@@ -1649,6 +1649,8 @@ static int __xipram do_write_oneword(str
+ 
+ 		ret = -EIO;
+ 	}
++
++ enable_xip:
+ 	xip_enable(map, chip, adr);
+  op_done:
+ 	if (mode == FL_OTP_WRITE)
+@@ -2227,7 +2229,6 @@ static int cfi_amdstd_panic_write(struct
+ 	return 0;
+ }
+ 
+-
+ /*
+  * Handle devices with one erase region, that only implement
+  * the chip erase command.
+@@ -2291,8 +2292,8 @@ static int __xipram do_erase_chip(struct
+ 			chip->erase_suspended = 0;
+ 		}
+ 
+-		if (chip_ready(map, adr))
+-			break;
++		if (chip_good(map, adr, map_word_ff(map)))
++			goto op_done;
+ 
+ 		if (time_after(jiffies, timeo)) {
+ 			printk(KERN_WARNING "MTD %s(): software timeout\n",
+@@ -2312,6 +2313,7 @@ static int __xipram do_erase_chip(struct
+ 		ret = -EIO;
+ 	}
+ 
++ op_done:
+ 	chip->state = FL_READY;
+ 	xip_enable(map, chip, adr);
+ 	DISABLE_VPP(map);
+@@ -2380,9 +2382,9 @@ static int __xipram do_erase_oneblock(st
+ 			chip->erase_suspended = 0;
+ 		}
+ 
+-		if (chip_ready(map, adr)) {
++		if (chip_good(map, adr, map_word_ff(map))) {
+ 			xip_enable(map, chip, adr);
+-			break;
++			goto op_done;
+ 		}
+ 
+ 		if (time_after(jiffies, timeo)) {
+@@ -2404,6 +2406,7 @@ static int __xipram do_erase_oneblock(st
+ 		ret = -EIO;
+ 	}
+ 
++ op_done:
+ 	chip->state = FL_READY;
+ 	DISABLE_VPP(map);
+ 	put_chip(map, chip, adr);
diff --git a/target/linux/ar71xx/patches-4.4/404-mtd-cybertan-trx-parser.patch b/target/linux/ar71xx/patches-4.4/404-mtd-cybertan-trx-parser.patch
new file mode 100644
index 0000000000..3f67c4c5da
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/404-mtd-cybertan-trx-parser.patch
@@ -0,0 +1,25 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -174,6 +174,12 @@ config MTD_BCM47XX_PARTS
+ 	  This provides partitions parser for devices based on BCM47xx
+ 	  boards.
+ 
++config MTD_CYBERTAN_PARTS
++	tristate "Cybertan partitioning support"
++	depends on ATH79
++	---help---
++	   Cybertan partitioning support
++
+ config MTD_MYLOADER_PARTS
+ 	tristate "MyLoader partition parsing"
+ 	depends on ADM5120 || ATH25 || ATH79
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)	+= bcm47xxpart.o
+ obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
++obj-$(CONFIG_MTD_CYBERTAN_PARTS) += cybertan_part.o
+ 
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS)	+= mtd_blkdevs.o
diff --git a/target/linux/ar71xx/patches-4.4/405-mtd-tp-link-partition-parser.patch b/target/linux/ar71xx/patches-4.4/405-mtd-tp-link-partition-parser.patch
new file mode 100644
index 0000000000..9d0d1db168
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/405-mtd-tp-link-partition-parser.patch
@@ -0,0 +1,25 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -196,6 +196,12 @@ config MTD_MYLOADER_PARTS
+ 	  You will still need the parsing functions to be called by the driver
+ 	  for your particular device. It won't happen automatically.
+ 
++config MTD_TPLINK_PARTS
++	tristate "TP-Link AR7XXX/AR9XXX partitioning support"
++	depends on ATH79
++	---help---
++	  TBD.
++
+ comment "User Modules And Translation Layers"
+ 
+ #
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)	+= bcm47xxpart.o
+ obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
++obj-$(CONFIG_MTD_TPLINK_PARTS)	+= tplinkpart.o
+ obj-$(CONFIG_MTD_CYBERTAN_PARTS) += cybertan_part.o
+ 
+ # 'Users' - code which presents functionality to userspace.
diff --git a/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch b/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch
new file mode 100644
index 0000000000..04acdb6d9e
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/407-mtd-m25p80-allow-to-pass-probe-types-via-platform-data.patch
@@ -0,0 +1,23 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -251,7 +251,9 @@ static int m25p_probe(struct spi_device
+ 
+ 	ppdata.of_node = spi->dev.of_node;
+ 
+-	return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
++	return mtd_device_parse_register(&nor->mtd,
++			data ? data->part_probes : NULL,
++			&ppdata,
+ 			data ? data->parts : NULL,
+ 			data ? data->nr_parts : 0);
+ }
+--- a/include/linux/spi/flash.h
++++ b/include/linux/spi/flash.h
+@@ -24,6 +24,7 @@ struct flash_platform_data {
+ 	unsigned int	nr_parts;
+ 
+ 	char		*type;
++	const char	**part_probes;
+ 
+ 	/* we'll likely add more ... use JEDEC IDs, etc */
+ };
diff --git a/target/linux/ar71xx/patches-4.4/408-mtd-redboot_partition_scan.patch b/target/linux/ar71xx/patches-4.4/408-mtd-redboot_partition_scan.patch
new file mode 100644
index 0000000000..cd41e7ceb2
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/408-mtd-redboot_partition_scan.patch
@@ -0,0 +1,44 @@
+--- a/drivers/mtd/redboot.c
++++ b/drivers/mtd/redboot.c
+@@ -76,12 +76,18 @@ static int parse_redboot_partitions(stru
+ 	static char nullstring[] = "unallocated";
+ #endif
+ 
++	buf = vmalloc(master->erasesize);
++	if (!buf)
++		return -ENOMEM;
++
++ restart:
+ 	if ( directory < 0 ) {
+ 		offset = master->size + directory * master->erasesize;
+ 		while (mtd_block_isbad(master, offset)) {
+ 			if (!offset) {
+ 			nogood:
+ 				printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
++				vfree(buf);
+ 				return -EIO;
+ 			}
+ 			offset -= master->erasesize;
+@@ -94,10 +100,6 @@ static int parse_redboot_partitions(stru
+ 				goto nogood;
+ 		}
+ 	}
+-	buf = vmalloc(master->erasesize);
+-
+-	if (!buf)
+-		return -ENOMEM;
+ 
+ 	printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
+ 	       master->name, offset);
+@@ -170,6 +172,11 @@ static int parse_redboot_partitions(stru
+ 	}
+ 	if (i == numslots) {
+ 		/* Didn't find it */
++		if (offset + master->erasesize < master->size) {
++			/* not at the end of the flash yet, maybe next block :) */
++			directory++;
++			goto restart;
++		}
+ 		printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
+ 		       master->name);
+ 		ret = 0;
diff --git a/target/linux/ar71xx/patches-4.4/409-mtd-rb4xx_nand_driver.patch b/target/linux/ar71xx/patches-4.4/409-mtd-rb4xx_nand_driver.patch
new file mode 100644
index 0000000000..4039aa185a
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/409-mtd-rb4xx_nand_driver.patch
@@ -0,0 +1,21 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -546,4 +546,8 @@ config MTD_NAND_HISI504
+ 	help
+ 	  Enables support for NAND controller on Hisilicon SoC Hip04.
+ 
++config MTD_NAND_RB4XX
++	tristate "NAND flash driver for RouterBoard 4xx series"
++	depends on MTD_NAND && ATH79_MACH_RB4XX
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -33,6 +33,7 @@ obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx27
+ obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx_nand.o
+ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
++obj-$(CONFIG_MTD_NAND_RB4XX)		+= rb4xx_nand.o
+ obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+ obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
diff --git a/target/linux/ar71xx/patches-4.4/410-mtd-rb750-nand-driver.patch b/target/linux/ar71xx/patches-4.4/410-mtd-rb750-nand-driver.patch
new file mode 100644
index 0000000000..c67d1776f1
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/410-mtd-rb750-nand-driver.patch
@@ -0,0 +1,21 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -550,4 +550,8 @@ config MTD_NAND_RB4XX
+ 	tristate "NAND flash driver for RouterBoard 4xx series"
+ 	depends on MTD_NAND && ATH79_MACH_RB4XX
+ 
++config MTD_NAND_RB750
++	tristate "NAND flash driver for the RouterBoard 750"
++	depends on MTD_NAND && ATH79_MACH_RB750
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_MTD_NAND_PXA3xx)		+= pxa3xx
+ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
+ obj-$(CONFIG_MTD_NAND_RB4XX)		+= rb4xx_nand.o
++obj-$(CONFIG_MTD_NAND_RB750)		+= rb750_nand.o
+ obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+ obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
diff --git a/target/linux/ar71xx/patches-4.4/411-mtd-cfi_cmdset_0002-force-word-write.patch b/target/linux/ar71xx/patches-4.4/411-mtd-cfi_cmdset_0002-force-word-write.patch
new file mode 100644
index 0000000000..39c5478182
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/411-mtd-cfi_cmdset_0002-force-word-write.patch
@@ -0,0 +1,61 @@
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -40,7 +40,7 @@
+ #include <linux/mtd/xip.h>
+ 
+ #define AMD_BOOTLOC_BUG
+-#define FORCE_WORD_WRITE 0
++#define FORCE_WORD_WRITE 1
+ 
+ #define MAX_WORD_RETRIES 3
+ 
+@@ -51,7 +51,9 @@
+ 
+ static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+ static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
++#if !FORCE_WORD_WRITE
+ static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
++#endif
+ static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
+ static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
+ static void cfi_amdstd_sync (struct mtd_info *);
+@@ -202,6 +204,7 @@ static void fixup_amd_bootblock(struct m
+ }
+ #endif
+ 
++#if !FORCE_WORD_WRITE
+ static void fixup_use_write_buffers(struct mtd_info *mtd)
+ {
+ 	struct map_info *map = mtd->priv;
+@@ -211,6 +214,7 @@ static void fixup_use_write_buffers(stru
+ 		mtd->_write = cfi_amdstd_write_buffers;
+ 	}
+ }
++#endif /* !FORCE_WORD_WRITE */
+ 
+ /* Atmel chips don't use the same PRI format as AMD chips */
+ static void fixup_convert_atmel_pri(struct mtd_info *mtd)
+@@ -1791,6 +1795,7 @@ static int cfi_amdstd_write_words(struct
+ /*
+  * FIXME: interleaved mode not tested, and probably not supported!
+  */
++#if !FORCE_WORD_WRITE
+ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
+ 				    unsigned long adr, const u_char *buf,
+ 				    int len)
+@@ -1919,7 +1924,6 @@ static int __xipram do_write_buffer(stru
+ 	return ret;
+ }
+ 
+-
+ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
+ 				    size_t *retlen, const u_char *buf)
+ {
+@@ -1994,6 +1998,7 @@ static int cfi_amdstd_write_buffers(stru
+ 
+ 	return 0;
+ }
++#endif /* !FORCE_WORD_WRITE */
+ 
+ /*
+  * Wait for the flash chip to become ready to write data
diff --git a/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch b/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch
new file mode 100644
index 0000000000..866920a249
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/412-mtd-m25p80-zero-partition-parser-data.patch
@@ -0,0 +1,10 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -249,6 +249,7 @@ static int m25p_probe(struct spi_device
+ 	if (ret)
+ 		return ret;
+ 
++	memset(&ppdata, '\0', sizeof(ppdata));
+ 	ppdata.of_node = spi->dev.of_node;
+ 
+ 	return mtd_device_parse_register(&nor->mtd,
diff --git a/target/linux/ar71xx/patches-4.4/413-mtd-ar934x-nand-driver.patch b/target/linux/ar71xx/patches-4.4/413-mtd-ar934x-nand-driver.patch
new file mode 100644
index 0000000000..cfcd07a193
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/413-mtd-ar934x-nand-driver.patch
@@ -0,0 +1,25 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -554,4 +554,12 @@ config MTD_NAND_RB750
+ 	tristate "NAND flash driver for the RouterBoard 750"
+ 	depends on MTD_NAND && ATH79_MACH_RB750
+ 
++config MTD_NAND_AR934X
++	tristate "NAND flash driver for the Qualcomm Atheros AR934x/QCA955x SoCs"
++	depends on (SOC_AR934X || SOC_QCA955X)
++
++config MTD_NAND_AR934X_HW_ECC
++	bool "Hardware ECC support for the AR934X NAND Controller (EXPERIMENTAL)"
++	depends on MTD_NAND_AR934X
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-
+ obj-$(CONFIG_MTD_NAND_DENALI)		+= denali.o
+ obj-$(CONFIG_MTD_NAND_DENALI_PCI)	+= denali_pci.o
+ obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= denali_dt.o
++obj-$(CONFIG_MTD_NAND_AR934X)		+= ar934x_nfc.o
+ obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
+ obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
+ obj-$(CONFIG_MTD_NAND_S3C2410)		+= s3c2410.o
diff --git a/target/linux/ar71xx/patches-4.4/414-mtd-rb91x-nand-driver.patch b/target/linux/ar71xx/patches-4.4/414-mtd-rb91x-nand-driver.patch
new file mode 100644
index 0000000000..8b7582dce1
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/414-mtd-rb91x-nand-driver.patch
@@ -0,0 +1,23 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -554,6 +554,10 @@ config MTD_NAND_RB750
+ 	tristate "NAND flash driver for the RouterBoard 750"
+ 	depends on MTD_NAND && ATH79_MACH_RB750
+ 
++config MTD_NAND_RB91X
++	tristate "NAND flash driver for the RouterBOARD 91x series"
++	depends on MTD_NAND && ATH79_MACH_RB91X
++
+ config MTD_NAND_AR934X
+ 	tristate "NAND flash driver for the Qualcomm Atheros AR934x/QCA955x SoCs"
+ 	depends on (SOC_AR934X || SOC_QCA955X)
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -36,6 +36,7 @@ obj-$(CONFIG_MTD_NAND_TMIO)		+= tmio_nan
+ obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
+ obj-$(CONFIG_MTD_NAND_RB4XX)		+= rb4xx_nand.o
+ obj-$(CONFIG_MTD_NAND_RB750)		+= rb750_nand.o
++obj-$(CONFIG_MTD_NAND_RB91X)		+= rb91x_nand.o
+ obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
+ obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
diff --git a/target/linux/ar71xx/patches-4.4/420-net-ar71xx_mac_driver.patch b/target/linux/ar71xx/patches-4.4/420-net-ar71xx_mac_driver.patch
new file mode 100644
index 0000000000..feb2e6a393
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/420-net-ar71xx_mac_driver.patch
@@ -0,0 +1,28 @@
+--- a/drivers/net/ethernet/atheros/Kconfig
++++ b/drivers/net/ethernet/atheros/Kconfig
+@@ -5,7 +5,7 @@
+ config NET_VENDOR_ATHEROS
+ 	bool "Atheros devices"
+ 	default y
+-	depends on PCI
++	depends on (PCI || ATH79)
+ 	---help---
+ 	  If you have a network (Ethernet) card belonging to this class, say Y.
+ 
+@@ -78,4 +78,6 @@ config ALX
+ 	  To compile this driver as a module, choose M here.  The module
+ 	  will be called alx.
+ 
++source drivers/net/ethernet/atheros/ag71xx/Kconfig
++
+ endif # NET_VENDOR_ATHEROS
+--- a/drivers/net/ethernet/atheros/Makefile
++++ b/drivers/net/ethernet/atheros/Makefile
+@@ -2,6 +2,7 @@
+ # Makefile for the Atheros network device drivers.
+ #
+ 
++obj-$(CONFIG_AG71XX) += ag71xx/
+ obj-$(CONFIG_ATL1) += atlx/
+ obj-$(CONFIG_ATL2) += atlx/
+ obj-$(CONFIG_ATL1E) += atl1e/
diff --git a/target/linux/ar71xx/patches-4.4/423-dsa-add-88e6063-driver.patch b/target/linux/ar71xx/patches-4.4/423-dsa-add-88e6063-driver.patch
new file mode 100644
index 0000000000..1348cd9b04
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/423-dsa-add-88e6063-driver.patch
@@ -0,0 +1,24 @@
+--- a/drivers/net/dsa/Kconfig
++++ b/drivers/net/dsa/Kconfig
+@@ -13,6 +13,13 @@ config NET_DSA_MV88E6060
+ 	  This enables support for the Marvell 88E6060 ethernet switch
+ 	  chip.
+ 
++config NET_DSA_MV88E6063
++	bool "Marvell 88E6063 ethernet switch chip support"
++	select NET_DSA_TAG_TRAILER
++	---help---
++	  This enables support for the Marvell 88E6063 ethernet switch
++	  chip
++
+ config NET_DSA_MV88E6XXX_NEED_PPU
+ 	bool
+ 	default n
+--- a/drivers/net/dsa/Makefile
++++ b/drivers/net/dsa/Makefile
+@@ -1,4 +1,5 @@
+ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
++obj-$(CONFIG_NET_DSA_MV88E6063) += mv88e6063.o
+ obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx_drv.o
+ mv88e6xxx_drv-y += mv88e6xxx.o
+ ifdef CONFIG_NET_DSA_MV88E6123_61_65
diff --git a/target/linux/ar71xx/patches-4.4/430-drivers-link-spi-before-mtd.patch b/target/linux/ar71xx/patches-4.4/430-drivers-link-spi-before-mtd.patch
new file mode 100644
index 0000000000..e1adfb0183
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/430-drivers-link-spi-before-mtd.patch
@@ -0,0 +1,12 @@
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -74,8 +74,8 @@ obj-$(CONFIG_SCSI)		+= scsi/
+ obj-y				+= nvme/
+ obj-$(CONFIG_ATA)		+= ata/
+ obj-$(CONFIG_TARGET_CORE)	+= target/
+-obj-$(CONFIG_MTD)		+= mtd/
+ obj-$(CONFIG_SPI)		+= spi/
++obj-$(CONFIG_MTD)		+= mtd/
+ obj-$(CONFIG_SPMI)		+= spmi/
+ obj-y				+= hsi/
+ obj-y				+= net/
diff --git a/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch b/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch
new file mode 100644
index 0000000000..bf5aff5c7e
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/431-spi-add-various-flags.patch
@@ -0,0 +1,19 @@
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -695,6 +695,8 @@ struct spi_transfer {
+ 	unsigned	cs_change:1;
+ 	unsigned	tx_nbits:3;
+ 	unsigned	rx_nbits:3;
++	unsigned	verify:1;
++	unsigned	fast_write:1;
+ #define	SPI_NBITS_SINGLE	0x01 /* 1bit transfer */
+ #define	SPI_NBITS_DUAL		0x02 /* 2bits transfer */
+ #define	SPI_NBITS_QUAD		0x04 /* 4bits transfer */
+@@ -740,6 +742,7 @@ struct spi_message {
+ 	struct spi_device	*spi;
+ 
+ 	unsigned		is_dma_mapped:1;
++	unsigned		fast_read:1;
+ 
+ 	/* REVISIT:  we might want a flag affecting the behavior of the
+ 	 * last transfer ... allowing things like "read 16 bit length L"
diff --git a/target/linux/ar71xx/patches-4.4/432-spi-rb4xx-spi-driver.patch b/target/linux/ar71xx/patches-4.4/432-spi-rb4xx-spi-driver.patch
new file mode 100644
index 0000000000..7d99c43b95
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/432-spi-rb4xx-spi-driver.patch
@@ -0,0 +1,25 @@
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -477,6 +477,12 @@ config SPI_QUP
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called spi_qup.
+ 
++config SPI_RB4XX
++	tristate "Mikrotik RB4XX SPI master"
++	depends on SPI_MASTER && ATH79_MACH_RB4XX
++	help
++	  SPI controller driver for the Mikrotik RB4xx series boards.
++
+ config SPI_S3C24XX
+ 	tristate "Samsung S3C24XX series SPI"
+ 	depends on ARCH_S3C24XX
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -66,6 +66,7 @@ spi-pxa2xx-platform-objs		:= spi-pxa2xx.
+ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)	+= spi-pxa2xx-dma.o
+ obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
+ obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
++obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
+ obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
+ obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
+ obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
diff --git a/target/linux/ar71xx/patches-4.4/433-spi-rb4xx-cpld-driver.patch b/target/linux/ar71xx/patches-4.4/433-spi-rb4xx-cpld-driver.patch
new file mode 100644
index 0000000000..0932c729f9
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/433-spi-rb4xx-cpld-driver.patch
@@ -0,0 +1,26 @@
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -713,6 +713,13 @@ config SPI_TLE62X0
+ 	  sysfs interface, with each line presented as a kind of GPIO
+ 	  exposing both switch control and diagnostic feedback.
+ 
++config SPI_RB4XX_CPLD
++	tristate "MikroTik RB4XX CPLD driver"
++	depends on ATH79_MACH_RB4XX
++	help
++	  SPI driver for the Xilinx CPLD chip present on the
++	  MikroTik RB4xx boards.
++
+ #
+ # Add new SPI protocol masters in alphabetical order above this line
+ #
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -67,6 +67,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_
+ obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
+ obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
+ obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
++obj-$(CONFIG_SPI_RB4XX_CPLD)		+= spi-rb4xx-cpld.o
+ obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
+ obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
+ obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
diff --git a/target/linux/ar71xx/patches-4.4/434-spi-ap83_spi_controller.patch b/target/linux/ar71xx/patches-4.4/434-spi-ap83_spi_controller.patch
new file mode 100644
index 0000000000..a67e8084a2
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/434-spi-ap83_spi_controller.patch
@@ -0,0 +1,27 @@
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_SPI_SPIDEV)		+= spidev.o
+ # SPI master controller drivers (bus)
+ obj-$(CONFIG_SPI_ALTERA)		+= spi-altera.o
+ obj-$(CONFIG_SPI_ATMEL)			+= spi-atmel.o
++obj-$(CONFIG_SPI_AP83)			+= spi-ap83.o
+ obj-$(CONFIG_SPI_ATH79)			+= spi-ath79.o
+ obj-$(CONFIG_SPI_AU1550)		+= spi-au1550.o
+ obj-$(CONFIG_SPI_BCM2835)		+= spi-bcm2835.o
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -59,6 +59,14 @@ config SPI_ALTERA
+ 	help
+ 	  This is the driver for the Altera SPI Controller.
+ 
++config SPI_AP83
++	tristate "Atheros AP83 specific SPI Controller"
++	depends on SPI_MASTER && ATH79_MACH_AP83
++	select SPI_BITBANG
++	help
++	  This is a specific SPI controller driver for the Atheros AP83
++	  reference board.
++
+ config SPI_ATH79
+ 	tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver"
+ 	depends on ATH79 && GPIOLIB
diff --git a/target/linux/ar71xx/patches-4.4/435-spi-vsc7385_driver.patch b/target/linux/ar71xx/patches-4.4/435-spi-vsc7385_driver.patch
new file mode 100644
index 0000000000..78318f8e25
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/435-spi-vsc7385_driver.patch
@@ -0,0 +1,24 @@
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -728,6 +728,11 @@ config SPI_RB4XX_CPLD
+ 	  SPI driver for the Xilinx CPLD chip present on the
+ 	  MikroTik RB4xx boards.
+ 
++config SPI_VSC7385
++	tristate "Vitesse VSC7385 ethernet switch driver"
++	help
++	  SPI driver for the Vitesse VSC7385 ethernet switch.
++
+ #
+ # Add new SPI protocol masters in alphabetical order above this line
+ #
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -92,6 +92,7 @@ obj-$(CONFIG_SPI_TEGRA20_SLINK)		+= spi-
+ obj-$(CONFIG_SPI_TLE62X0)		+= spi-tle62x0.o
+ obj-$(CONFIG_SPI_TOPCLIFF_PCH)		+= spi-topcliff-pch.o
+ obj-$(CONFIG_SPI_TXX9)			+= spi-txx9.o
++obj-$(CONFIG_SPI_VSC7385)		+= spi-vsc7385.o
+ obj-$(CONFIG_SPI_XCOMM)		+= spi-xcomm.o
+ obj-$(CONFIG_SPI_XILINX)		+= spi-xilinx.o
+ obj-$(CONFIG_SPI_XLP)			+= spi-xlp.o
diff --git a/target/linux/ar71xx/patches-4.4/440-leds-wndr3700-usb-led-driver.patch b/target/linux/ar71xx/patches-4.4/440-leds-wndr3700-usb-led-driver.patch
new file mode 100644
index 0000000000..3ef0d1b0d4
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/440-leds-wndr3700-usb-led-driver.patch
@@ -0,0 +1,26 @@
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -605,6 +605,13 @@ config LEDS_VERSATILE
+ 	  This option enabled support for the LEDs on the ARM Versatile
+ 	  and RealView boards. Say Y to enabled these.
+ 
++config LEDS_WNDR3700_USB
++	tristate "NETGEAR WNDR3700 USB LED driver"
++	depends on LEDS_CLASS && ATH79_MACH_WNDR3700
++	help
++	  This option enables support for the USB LED found on the
++	  NETGEAR WNDR3700 board.
++
+ comment "LED Triggers"
+ source "drivers/leds/trigger/Kconfig"
+ 
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -47,6 +47,7 @@ obj-$(CONFIG_LEDS_DA9052)		+= leds-da905
+ obj-$(CONFIG_LEDS_WM831X_STATUS)	+= leds-wm831x-status.o
+ obj-$(CONFIG_LEDS_WM8350)		+= leds-wm8350.o
+ obj-$(CONFIG_LEDS_PWM)			+= leds-pwm.o
++obj-${CONFIG_LEDS_WNDR3700_USB}		+= leds-wndr3700-usb.o
+ obj-$(CONFIG_LEDS_REGULATOR)		+= leds-regulator.o
+ obj-$(CONFIG_LEDS_INTEL_SS4200)		+= leds-ss4200.o
+ obj-$(CONFIG_LEDS_LT3593)		+= leds-lt3593.o
diff --git a/target/linux/ar71xx/patches-4.4/441-leds-rb750-led-driver.patch b/target/linux/ar71xx/patches-4.4/441-leds-rb750-led-driver.patch
new file mode 100644
index 0000000000..fc2d02b8ff
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/441-leds-rb750-led-driver.patch
@@ -0,0 +1,23 @@
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -612,6 +612,10 @@ config LEDS_WNDR3700_USB
+ 	  This option enables support for the USB LED found on the
+ 	  NETGEAR WNDR3700 board.
+ 
++config LEDS_RB750
++	tristate "LED driver for the Mikrotik RouterBOARD 750"
++	depends on LEDS_CLASS && ATH79_MACH_RB750
++
+ comment "LED Triggers"
+ source "drivers/leds/trigger/Kconfig"
+ 
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -54,6 +54,7 @@ obj-$(CONFIG_LEDS_LT3593)		+= leds-lt359
+ obj-$(CONFIG_LEDS_ADP5520)		+= leds-adp5520.o
+ obj-$(CONFIG_LEDS_DELL_NETBOOKS)	+= dell-led.o
+ obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
++obj-$(CONFIG_LEDS_RB750)		+= leds-rb750.o
+ obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
+ obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
+ obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
diff --git a/target/linux/ar71xx/patches-4.4/450-gpio-nxp-74hc153-gpio-chip-driver.patch b/target/linux/ar71xx/patches-4.4/450-gpio-nxp-74hc153-gpio-chip-driver.patch
new file mode 100644
index 0000000000..8bccd12fac
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/450-gpio-nxp-74hc153-gpio-chip-driver.patch
@@ -0,0 +1,25 @@
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -1040,4 +1040,12 @@ config GPIO_VIPERBOARD
+ 
+ endmenu
+ 
++comment "Other GPIO expanders"
++
++config GPIO_NXP_74HC153
++	tristate "NXP 74HC153 Dual 4-input multiplexer"
++	help
++	  Platform driver for NXP 74HC153 Dual 4-input Multiplexer. This
++	  provides a GPIO interface supporting input mode only.
++
+ endif
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -69,6 +69,7 @@ obj-$(CONFIG_GPIO_MSIC)		+= gpio-msic.o
+ obj-$(CONFIG_GPIO_MVEBU)        += gpio-mvebu.o
+ obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
+ obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
++obj-$(CONFIG_GPIO_NXP_74HC153)	+= gpio-nxp-74hc153.o
+ obj-$(CONFIG_GPIO_OCTEON)	+= gpio-octeon.o
+ obj-$(CONFIG_GPIO_OMAP)		+= gpio-omap.o
+ obj-$(CONFIG_GPIO_PCA953X)	+= gpio-pca953x.o
diff --git a/target/linux/ar71xx/patches-4.4/451-gpio-74x164-improve-platform-device-support.patch b/target/linux/ar71xx/patches-4.4/451-gpio-74x164-improve-platform-device-support.patch
new file mode 100644
index 0000000000..0f7faf280f
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/451-gpio-74x164-improve-platform-device-support.patch
@@ -0,0 +1,109 @@
+--- a/drivers/gpio/gpio-74x164.c
++++ b/drivers/gpio/gpio-74x164.c
+@@ -12,6 +12,7 @@
+ #include <linux/init.h>
+ #include <linux/mutex.h>
+ #include <linux/spi/spi.h>
++#include <linux/spi/74x164.h>
+ #include <linux/gpio.h>
+ #include <linux/of_gpio.h>
+ #include <linux/slab.h>
+@@ -107,8 +108,18 @@ static int gen_74x164_direction_output(s
+ static int gen_74x164_probe(struct spi_device *spi)
+ {
+ 	struct gen_74x164_chip *chip;
++	struct gen_74x164_chip_platform_data *pdata;
++	struct device_node *np;
+ 	int ret;
+ 
++	pdata = spi->dev.platform_data;
++	np = spi->dev.of_node;
++
++	if (!np && !pdata) {
++		dev_err(&spi->dev, "No configuration data available.\n");
++		return -EINVAL;
++	}
++
+ 	/*
+ 	 * bits_per_word cannot be configured in platform data
+ 	 */
+@@ -130,18 +141,28 @@ static int gen_74x164_probe(struct spi_d
+ 	chip->gpio_chip.set = gen_74x164_set_value;
+ 	chip->gpio_chip.base = -1;
+ 
+-	if (of_property_read_u32(spi->dev.of_node, "registers-number",
+-				 &chip->registers)) {
+-		dev_err(&spi->dev,
+-			"Missing registers-number property in the DT.\n");
+-		return -EINVAL;
++	if (np) {
++		if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) {
++			dev_err(&spi->dev, "Missing registers-number property in the DT.\n");
++			ret = -EINVAL;
++			goto exit_destroy;
++		}
++	} else if (pdata) {
++		chip->gpio_chip.base = pdata->base;
++		chip->registers = pdata->num_registers;
+ 	}
+ 
++	if (!chip->registers)
++		chip->registers = 1;
++
+ 	chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
+ 	chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
+ 	if (!chip->buffer)
+ 		return -ENOMEM;
+ 
++	if (pdata && pdata->init_data)
++		memcpy(chip->buffer, pdata->init_data, chip->registers);
++
+ 	chip->gpio_chip.can_sleep = true;
+ 	chip->gpio_chip.dev = &spi->dev;
+ 	chip->gpio_chip.owner = THIS_MODULE;
+@@ -174,16 +195,18 @@ static int gen_74x164_remove(struct spi_
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_OF
+ static const struct of_device_id gen_74x164_dt_ids[] = {
+ 	{ .compatible = "fairchild,74hc595" },
+ 	{},
+ };
+ MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids);
++#endif
+ 
+ static struct spi_driver gen_74x164_driver = {
+ 	.driver = {
+ 		.name		= "74x164",
+-		.of_match_table	= gen_74x164_dt_ids,
++		.of_match_table	= of_match_ptr(gen_74x164_dt_ids),
+ 	},
+ 	.probe		= gen_74x164_probe,
+ 	.remove		= gen_74x164_remove,
+--- /dev/null
++++ b/include/linux/spi/74x164.h
+@@ -0,0 +1,13 @@
++#ifndef LINUX_SPI_74X164_H
++#define LINUX_SPI_74X164_H
++
++struct gen_74x164_chip_platform_data {
++	/* number assigned to the first GPIO */
++	unsigned        base;
++	/* number of chained registers */
++	unsigned	num_registers;
++	/* address of a buffer containing initial data */
++	u8		*init_data;
++};
++
++#endif
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -991,7 +991,6 @@ menu "SPI GPIO expanders"
+ 
+ config GPIO_74X164
+ 	tristate "74x164 serial-in/parallel-out 8-bits shift register"
+-	depends on OF
+ 	help
+ 	  Driver for 74x164 compatible serial-in/parallel-out 8-outputs
+ 	  shift registers. This driver can be used to provide access
diff --git a/target/linux/ar71xx/patches-4.4/452-gpio-add-gpio-latch-driver.patch b/target/linux/ar71xx/patches-4.4/452-gpio-add-gpio-latch-driver.patch
new file mode 100644
index 0000000000..c545252b38
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/452-gpio-add-gpio-latch-driver.patch
@@ -0,0 +1,22 @@
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -1047,4 +1047,9 @@ config GPIO_NXP_74HC153
+ 	  Platform driver for NXP 74HC153 Dual 4-input Multiplexer. This
+ 	  provides a GPIO interface supporting input mode only.
+ 
++config GPIO_LATCH
++	tristate "GPIO latch driver"
++	help
++	  Say yes here to enable a GPIO latch driver.
++
+ endif
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -47,6 +47,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz
+ obj-$(CONFIG_GPIO_KEMPLD)	+= gpio-kempld.o
+ obj-$(CONFIG_ARCH_KS8695)	+= gpio-ks8695.o
+ obj-$(CONFIG_GPIO_INTEL_MID)	+= gpio-intel-mid.o
++obj-$(CONFIG_GPIO_LATCH)	+= gpio-latch.o
+ obj-$(CONFIG_GPIO_LOONGSON)	+= gpio-loongson.o
+ obj-$(CONFIG_GPIO_LP3943)	+= gpio-lp3943.o
+ obj-$(CONFIG_GPIO_LPC18XX)	+= gpio-lpc18xx.o
diff --git a/target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch b/target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch
new file mode 100644
index 0000000000..2a8d7af1bb
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch
@@ -0,0 +1,28 @@
+--- a/drivers/spi/spi-bitbang.c
++++ b/drivers/spi/spi-bitbang.c
+@@ -231,13 +231,14 @@ void spi_bitbang_cleanup(struct spi_devi
+ }
+ EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
+ 
+-static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
++int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
+ {
+ 	struct spi_bitbang_cs	*cs = spi->controller_state;
+ 	unsigned		nsecs = cs->nsecs;
+ 
+ 	return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
+ }
++EXPORT_SYMBOL_GPL(spi_bitbang_bufs);
+ 
+ /*----------------------------------------------------------------------*/
+ 
+--- a/include/linux/spi/spi_bitbang.h
++++ b/include/linux/spi/spi_bitbang.h
+@@ -39,6 +39,7 @@ extern int spi_bitbang_setup(struct spi_
+ extern void spi_bitbang_cleanup(struct spi_device *spi);
+ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
+ 				      struct spi_transfer *t);
++extern int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t);
+ 
+ /* start or stop queue processing */
+ extern int spi_bitbang_start(struct spi_bitbang *spi);
diff --git a/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch b/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
new file mode 100644
index 0000000000..6ccb632ecc
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
@@ -0,0 +1,23 @@
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -583,6 +583,12 @@ extern struct spi_master *spi_busnum_to_
+ 
+ /*---------------------------------------------------------------------------*/
+ 
++enum spi_transfer_type {
++	SPI_TRANSFER_GENERIC = 0,
++	SPI_TRANSFER_FLASH_READ_CMD,
++	SPI_TRANSFER_FLASH_READ_DATA,
++};
++
+ /*
+  * I/O INTERFACE between SPI controller and protocol drivers
+  *
+@@ -703,6 +709,7 @@ struct spi_transfer {
+ 	u8		bits_per_word;
+ 	u16		delay_usecs;
+ 	u32		speed_hz;
++	enum spi_transfer_type type;
+ 
+ 	struct list_head transfer_list;
+ };
diff --git a/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch b/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
new file mode 100644
index 0000000000..f949235966
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
@@ -0,0 +1,15 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -159,10 +159,12 @@ static int m25p80_read(struct spi_nor *n
+ 	flash->command[0] = nor->read_opcode;
+ 	m25p_addr2cmd(nor, from, flash->command);
+ 
++	t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
+ 	t[0].tx_buf = flash->command;
+ 	t[0].len = m25p_cmdsz(nor) + dummy;
+ 	spi_message_add_tail(&t[0], &m);
+ 
++	t[1].type = SPI_TRANSFER_FLASH_READ_DATA;
+ 	t[1].rx_buf = buf;
+ 	t[1].rx_nbits = m25p80_rx_nbits(nor);
+ 	t[1].len = len;
diff --git a/target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch b/target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch
new file mode 100644
index 0000000000..408ce653e9
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch
@@ -0,0 +1,185 @@
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -35,6 +35,11 @@
+ 
+ #define ATH79_SPI_CS_LINE_MAX		2
+ 
++enum ath79_spi_state {
++	ATH79_SPI_STATE_WAIT_CMD = 0,
++	ATH79_SPI_STATE_WAIT_READ,
++};
++
+ struct ath79_spi {
+ 	struct spi_bitbang	bitbang;
+ 	u32			ioc_base;
+@@ -42,6 +47,11 @@ struct ath79_spi {
+ 	void __iomem		*base;
+ 	struct clk		*clk;
+ 	unsigned		rrw_delay;
++
++	enum ath79_spi_state	state;
++	u32			clk_div;
++	unsigned long 		read_addr;
++	unsigned long		ahb_rate;
+ };
+ 
+ static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
+@@ -109,9 +119,6 @@ static void ath79_spi_enable(struct ath7
+ 	/* save CTRL register */
+ 	sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
+ 	sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
+-
+-	/* TODO: setup speed? */
+-	ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
+ }
+ 
+ static void ath79_spi_disable(struct ath79_spi *sp)
+@@ -232,6 +239,110 @@ static u32 ath79_spi_txrx_mode0(struct s
+ 	return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
+ }
+ 
++static int ath79_spi_do_read_flash_data(struct spi_device *spi,
++					struct spi_transfer *t)
++{
++	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++
++	/* disable GPIO mode */
++	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
++
++	memcpy_fromio(t->rx_buf, sp->base + sp->read_addr, t->len);
++
++	/* enable GPIO mode */
++	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
++
++	/* restore IOC register */
++	ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
++
++	return t->len;
++}
++
++static int ath79_spi_do_read_flash_cmd(struct spi_device *spi,
++				       struct spi_transfer *t)
++{
++	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++	int len;
++	const u8 *p;
++
++	sp->read_addr = 0;
++
++	len = t->len - 1;
++	p = t->tx_buf;
++
++	while (len--) {
++		p++;
++		sp->read_addr <<= 8;
++		sp->read_addr |= *p;
++	}
++
++	return t->len;
++}
++
++static bool ath79_spi_is_read_cmd(struct spi_device *spi,
++				 struct spi_transfer *t)
++{
++	return t->type == SPI_TRANSFER_FLASH_READ_CMD;
++}
++
++static bool ath79_spi_is_data_read(struct spi_device *spi,
++				  struct spi_transfer *t)
++{
++	return t->type == SPI_TRANSFER_FLASH_READ_DATA;
++}
++
++static int ath79_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
++{
++	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++	int ret;
++
++	switch (sp->state) {
++	case ATH79_SPI_STATE_WAIT_CMD:
++		if (ath79_spi_is_read_cmd(spi, t)) {
++			ret = ath79_spi_do_read_flash_cmd(spi, t);
++			sp->state = ATH79_SPI_STATE_WAIT_READ;
++		} else {
++			ret = spi_bitbang_bufs(spi, t);
++		}
++		break;
++
++	case ATH79_SPI_STATE_WAIT_READ:
++		if (ath79_spi_is_data_read(spi, t)) {
++			ret = ath79_spi_do_read_flash_data(spi, t);
++		} else {
++			dev_warn(&spi->dev, "flash data read expected\n");
++			ret = -EIO;
++		}
++		sp->state = ATH79_SPI_STATE_WAIT_CMD;
++		break;
++
++	default:
++		BUG();
++	}
++
++	return ret;
++}
++
++static int ath79_spi_setup_transfer(struct spi_device *spi,
++				    struct spi_transfer *t)
++{
++	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++	struct ath79_spi_controller_data *cdata;
++	int ret;
++
++	ret = spi_bitbang_setup_transfer(spi, t);
++	if (ret)
++		return ret;
++
++	cdata = spi->controller_data;
++	if (cdata->is_flash)
++		sp->bitbang.txrx_bufs = ath79_spi_txrx_bufs;
++	else
++		sp->bitbang.txrx_bufs = spi_bitbang_bufs;
++
++	return ret;
++}
++
+ static int ath79_spi_probe(struct platform_device *pdev)
+ {
+ 	struct spi_master *master;
+@@ -254,6 +365,8 @@ static int ath79_spi_probe(struct platfo
+ 	sp = spi_master_get_devdata(master);
+ 	platform_set_drvdata(pdev, sp);
+ 
++	sp->state = ATH79_SPI_STATE_WAIT_CMD;
++
+ 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ 	master->setup = ath79_spi_setup;
+ 	master->cleanup = ath79_spi_cleanup;
+@@ -263,7 +376,7 @@ static int ath79_spi_probe(struct platfo
+ 	sp->bitbang.master = master;
+ 	sp->bitbang.chipselect = ath79_spi_chipselect;
+ 	sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
+-	sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
++	sp->bitbang.setup_transfer = ath79_spi_setup_transfer;
+ 	sp->bitbang.flags = SPI_CS_HIGH;
+ 
+ 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -283,7 +396,8 @@ static int ath79_spi_probe(struct platfo
+ 	if (ret)
+ 		goto err_put_master;
+ 
+-	rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
++	sp->ahb_rate = clk_get_rate(sp->clk);
++	rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
+ 	if (!rate) {
+ 		ret = -EINVAL;
+ 		goto err_clk_disable;
+--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
++++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+@@ -24,6 +24,7 @@ enum ath79_spi_cs_type {
+ struct ath79_spi_controller_data {
+ 	enum ath79_spi_cs_type cs_type;
+ 	unsigned cs_line;
++	bool is_flash;
+ };
+ 
+ #endif /* _ATH79_SPI_PLATFORM_H */
diff --git a/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch b/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
new file mode 100644
index 0000000000..03483e82a6
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
@@ -0,0 +1,35 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -159,6 +159,9 @@ static int m25p80_read(struct spi_nor *n
+ 	flash->command[0] = nor->read_opcode;
+ 	m25p_addr2cmd(nor, from, flash->command);
+ 
++	if (dummy == 1)
++		t[0].dummy = true;
++
+ 	t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
+ 	t[0].tx_buf = flash->command;
+ 	t[0].len = m25p_cmdsz(nor) + dummy;
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -268,6 +268,10 @@ static int ath79_spi_do_read_flash_cmd(s
+ 	sp->read_addr = 0;
+ 
+ 	len = t->len - 1;
++
++	if (t->dummy)
++		len -= 1;
++
+ 	p = t->tx_buf;
+ 
+ 	while (len--) {
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -710,6 +710,7 @@ struct spi_transfer {
+ 	u16		delay_usecs;
+ 	u32		speed_hz;
+ 	enum spi_transfer_type type;
++	bool dummy;
+ 
+ 	struct list_head transfer_list;
+ };
diff --git a/target/linux/ar71xx/patches-4.4/470-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch b/target/linux/ar71xx/patches-4.4/470-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch
new file mode 100644
index 0000000000..520c652059
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/470-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch
@@ -0,0 +1,111 @@
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ath79/mangle-port.h
+@@ -0,0 +1,37 @@
++/*
++ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file was derived from: inlude/asm-mips/mach-generic/mangle-port.h
++ *      Copyright (C) 2003, 2004 Ralf Baechle
++ *
++ *  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.
++ */
++
++#ifndef __ASM_MACH_ATH79_MANGLE_PORT_H
++#define __ASM_MACH_ATH79_MANGLE_PORT_H
++
++#ifdef CONFIG_PCI
++extern unsigned long (ath79_pci_swizzle_b)(unsigned long port);
++extern unsigned long (ath79_pci_swizzle_w)(unsigned long port);
++#else
++#define ath79_pci_swizzle_b(port) (port)
++#define ath79_pci_swizzle_w(port) (port)
++#endif
++
++#define __swizzle_addr_b(port)	ath79_pci_swizzle_b(port)
++#define __swizzle_addr_w(port)	ath79_pci_swizzle_w(port)
++#define __swizzle_addr_l(port)	(port)
++#define __swizzle_addr_q(port)	(port)
++
++# define ioswabb(a, x)           (x)
++# define __mem_ioswabb(a, x)     (x)
++# define ioswabw(a, x)           (x)
++# define __mem_ioswabw(a, x)     cpu_to_le16(x)
++# define ioswabl(a, x)           (x)
++# define __mem_ioswabl(a, x)     cpu_to_le32(x)
++# define ioswabq(a, x)           (x)
++# define __mem_ioswabq(a, x)     cpu_to_le64(x)
++
++#endif /* __ASM_MACH_ATH79_MANGLE_PORT_H */
+--- a/arch/mips/ath79/pci.c
++++ b/arch/mips/ath79/pci.c
+@@ -13,6 +13,7 @@
+  */
+ 
+ #include <linux/init.h>
++#include <linux/export.h>
+ #include <linux/pci.h>
+ #include <linux/resource.h>
+ #include <linux/platform_device.h>
+@@ -25,6 +26,9 @@ static int (*ath79_pci_plat_dev_init)(st
+ static const struct ath79_pci_irq *ath79_pci_irq_map __initdata;
+ static unsigned ath79_pci_nr_irqs __initdata;
+ 
++static unsigned long (*__ath79_pci_swizzle_b)(unsigned long port);
++static unsigned long (*__ath79_pci_swizzle_w)(unsigned long port);
++
+ static const struct ath79_pci_irq ar71xx_pci_irq_map[] __initconst = {
+ 	{
+ 		.slot	= 17,
+@@ -212,12 +216,50 @@ ath79_register_pci_ar724x(int id,
+ 	return pdev;
+ }
+ 
++static inline bool ar71xx_is_pci_addr(unsigned long port)
++{
++	unsigned long phys = CPHYSADDR(port);
++
++	return (phys >= AR71XX_PCI_MEM_BASE &&
++		phys < AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE);
++}
++
++static unsigned long ar71xx_pci_swizzle_b(unsigned long port)
++{
++	return ar71xx_is_pci_addr(port) ? port ^ 3 : port;
++}
++
++static unsigned long ar71xx_pci_swizzle_w(unsigned long port)
++{
++	return ar71xx_is_pci_addr(port) ? port ^ 2 : port;
++}
++
++unsigned long ath79_pci_swizzle_b(unsigned long port)
++{
++	if (__ath79_pci_swizzle_b)
++		return __ath79_pci_swizzle_b(port);
++
++	return port;
++}
++EXPORT_SYMBOL(ath79_pci_swizzle_b);
++
++unsigned long ath79_pci_swizzle_w(unsigned long port)
++{
++	if (__ath79_pci_swizzle_w)
++		return __ath79_pci_swizzle_w(port);
++
++	return port;
++}
++EXPORT_SYMBOL(ath79_pci_swizzle_w);
++
+ int __init ath79_register_pci(void)
+ {
+ 	struct platform_device *pdev = NULL;
+ 
+ 	if (soc_is_ar71xx()) {
+ 		pdev = ath79_register_pci_ar71xx();
++		__ath79_pci_swizzle_b = ar71xx_pci_swizzle_b;
++		__ath79_pci_swizzle_w = ar71xx_pci_swizzle_w;
+ 	} else if (soc_is_ar724x()) {
+ 		pdev = ath79_register_pci_ar724x(-1,
+ 						 AR724X_PCI_CFG_BASE,
diff --git a/target/linux/ar71xx/patches-4.4/490-usb-ehci-add-quirks-for-qca-socs.patch b/target/linux/ar71xx/patches-4.4/490-usb-ehci-add-quirks-for-qca-socs.patch
new file mode 100644
index 0000000000..d74ef1c83d
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/490-usb-ehci-add-quirks-for-qca-socs.patch
@@ -0,0 +1,103 @@
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -252,6 +252,37 @@ int ehci_reset(struct ehci_hcd *ehci)
+ 	command |= CMD_RESET;
+ 	dbg_cmd (ehci, "reset", command);
+ 	ehci_writel(ehci, command, &ehci->regs->command);
++
++	if (ehci->qca_force_host_mode) {
++		u32 usbmode;
++
++		udelay(1000);
++
++		usbmode = ehci_readl(ehci, &ehci->regs->usbmode);
++		usbmode |= USBMODE_CM_HC | (1 << 4);
++		ehci_writel(ehci, usbmode, &ehci->regs->usbmode);
++
++		ehci_dbg(ehci, "forced host mode, usbmode: %08x\n",
++			 ehci_readl(ehci, &ehci->regs->usbmode));
++	}
++
++	if (ehci->qca_force_16bit_ptw) {
++		u32 port_status;
++
++		udelay(1000);
++
++		/* enable 16-bit UTMI interface */
++		port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
++		port_status |= BIT(28);
++		ehci_writel(ehci, port_status, &ehci->regs->port_status[0]);
++
++		ehci_dbg(ehci, "16-bit UTMI interface enabled, status: %08x\n",
++			 ehci_readl(ehci, &ehci->regs->port_status[0]));
++	}
++
++	if (ehci->reset_notifier)
++		ehci->reset_notifier(ehci_to_hcd(ehci));
++
+ 	ehci->rh_state = EHCI_RH_HALTED;
+ 	ehci->next_statechange = jiffies;
+ 	retval = ehci_handshake(ehci, &ehci->regs->command,
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -228,6 +228,10 @@ struct ehci_hcd {			/* one per controlle
+ 	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
+ 	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
+ 	unsigned		ignore_oc:1;
++	unsigned		qca_force_host_mode:1;
++	unsigned		qca_force_16bit_ptw:1; /* force 16 bit UTMI */
++
++	void (*reset_notifier)(struct usb_hcd *hcd);
+ 
+ 	/* required for usb32 quirk */
+ 	#define OHCI_CTRL_HCFS          (3 << 6)
+--- a/include/linux/usb/ehci_pdriver.h
++++ b/include/linux/usb/ehci_pdriver.h
+@@ -50,6 +50,8 @@ struct usb_ehci_pdata {
+ 	unsigned	reset_on_resume:1;
+ 	unsigned	dma_mask_64:1;
+ 	unsigned	ignore_oc:1;
++	unsigned	qca_force_host_mode:1;
++	unsigned	qca_force_16bit_ptw:1;
+ 
+ 	/* Turn on all power and clocks */
+ 	int (*power_on)(struct platform_device *pdev);
+@@ -59,6 +61,7 @@ struct usb_ehci_pdata {
+ 	 * turn off everything else */
+ 	void (*power_suspend)(struct platform_device *pdev);
+ 	int (*pre_setup)(struct usb_hcd *hcd);
++	void (*reset_notifier)(struct platform_device *pdev);
+ };
+ 
+ #endif /* __USB_CORE_EHCI_PDRIVER_H */
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -51,6 +51,14 @@ struct ehci_platform_priv {
+ 
+ static const char hcd_name[] = "ehci-platform";
+ 
++static void ehci_platform_reset_notifier(struct usb_hcd *hcd)
++{
++	struct platform_device *pdev = to_platform_device(hcd->self.controller);
++	struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
++
++	pdata->reset_notifier(pdev);
++}
++
+ static int ehci_platform_reset(struct usb_hcd *hcd)
+ {
+ 	struct platform_device *pdev = to_platform_device(hcd->self.controller);
+@@ -256,6 +264,13 @@ static int ehci_platform_probe(struct pl
+ 		priv->reset_on_resume = true;
+ 	if (pdata->ignore_oc)
+ 		ehci->ignore_oc = 1;
++	if (pdata->qca_force_host_mode)
++		ehci->qca_force_host_mode = 1;
++	if (pdata->qca_force_16bit_ptw)
++		ehci->qca_force_16bit_ptw = 1;
++
++	if (pdata->reset_notifier)
++		ehci->reset_notifier = ehci_platform_reset_notifier;
+ 
+ #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ 	if (ehci->big_endian_mmio) {
diff --git a/target/linux/ar71xx/patches-4.4/500-MIPS-fw-myloader.patch b/target/linux/ar71xx/patches-4.4/500-MIPS-fw-myloader.patch
new file mode 100644
index 0000000000..e877b0c947
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/500-MIPS-fw-myloader.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -218,6 +218,7 @@ endif
+ #
+ libs-$(CONFIG_FW_ARC)		+= arch/mips/fw/arc/
+ libs-$(CONFIG_FW_CFE)		+= arch/mips/fw/cfe/
++libs-$(CONFIG_MYLOADER)		+= arch/mips/fw/myloader/
+ libs-$(CONFIG_FW_SNIPROM)	+= arch/mips/fw/sni/
+ libs-y				+= arch/mips/fw/lib/
+ 
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1117,6 +1117,9 @@ config MIPS_MSC
+ config MIPS_NILE4
+ 	bool
+ 
++config MYLOADER
++	bool
++
+ config SYNC_R4K
+ 	bool
+ 
diff --git a/target/linux/ar71xx/patches-4.4/501-MIPS-ath79-add-mac-argument-to-ath79_register_wmac.patch b/target/linux/ar71xx/patches-4.4/501-MIPS-ath79-add-mac-argument-to-ath79_register_wmac.patch
new file mode 100644
index 0000000000..fdf353c2e6
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/501-MIPS-ath79-add-mac-argument-to-ath79_register_wmac.patch
@@ -0,0 +1,81 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -15,6 +15,7 @@
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/irq.h>
++#include <linux/etherdevice.h>
+ #include <linux/platform_device.h>
+ #include <linux/ath9k_platform.h>
+ 
+@@ -22,6 +23,7 @@
+ #include <asm/mach-ath79/ar71xx_regs.h>
+ #include "dev-wmac.h"
+ 
++static u8 ath79_wmac_mac[ETH_ALEN];
+ static struct ath9k_platform_data ath79_wmac_data;
+ 
+ static struct resource ath79_wmac_resources[] = {
+@@ -162,7 +164,7 @@ static void qca955x_wmac_setup(void)
+ 		ath79_wmac_data.is_clk_25mhz = true;
+ }
+ 
+-void __init ath79_register_wmac(u8 *cal_data)
++void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+ 	if (soc_is_ar913x())
+ 		ar913x_wmac_setup();
+@@ -179,5 +181,10 @@ void __init ath79_register_wmac(u8 *cal_
+ 		memcpy(ath79_wmac_data.eeprom_data, cal_data,
+ 		       sizeof(ath79_wmac_data.eeprom_data));
+ 
++	if (mac_addr) {
++		memcpy(ath79_wmac_mac, mac_addr, sizeof(ath79_wmac_mac));
++		ath79_wmac_data.macaddr = ath79_wmac_mac;
++	}
++
+ 	platform_device_register(&ath79_wmac_device);
+ }
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -12,6 +12,6 @@
+ #ifndef _ATH79_DEV_WMAC_H
+ #define _ATH79_DEV_WMAC_H
+ 
+-void ath79_register_wmac(u8 *cal_data);
++void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
+ 
+ #endif /* _ATH79_DEV_WMAC_H */
+--- a/arch/mips/ath79/mach-ap81.c
++++ b/arch/mips/ath79/mach-ap81.c
+@@ -92,7 +92,7 @@ static void __init ap81_setup(void)
+ 					ap81_gpio_keys);
+ 	ath79_register_spi(&ap81_spi_data, ap81_spi_info,
+ 			   ARRAY_SIZE(ap81_spi_info));
+-	ath79_register_wmac(cal_data);
++	ath79_register_wmac(cal_data, NULL);
+ 	ath79_register_usb();
+ }
+ 
+--- a/arch/mips/ath79/mach-db120.c
++++ b/arch/mips/ath79/mach-db120.c
+@@ -128,7 +128,7 @@ static void __init db120_setup(void)
+ 	ath79_register_spi(&db120_spi_data, db120_spi_info,
+ 			   ARRAY_SIZE(db120_spi_info));
+ 	ath79_register_usb();
+-	ath79_register_wmac(art + DB120_WMAC_CALDATA_OFFSET);
++	ath79_register_wmac(art + DB120_WMAC_CALDATA_OFFSET, NULL);
+ 	db120_pci_init(art + DB120_PCIE_CALDATA_OFFSET);
+ }
+ 
+--- a/arch/mips/ath79/mach-ap121.c
++++ b/arch/mips/ath79/mach-ap121.c
+@@ -85,7 +85,7 @@ static void __init ap121_setup(void)
+ 	ath79_register_spi(&ap121_spi_data, ap121_spi_info,
+ 			   ARRAY_SIZE(ap121_spi_info));
+ 	ath79_register_usb();
+-	ath79_register_wmac(cal_data);
++	ath79_register_wmac(cal_data, NULL);
+ }
+ 
+ MIPS_MACHINE(ATH79_MACH_AP121, "AP121", "Atheros AP121 reference board",
diff --git a/target/linux/ar71xx/patches-4.4/503-MIPS-ath79-add-flash-acquire-release.patch b/target/linux/ar71xx/patches-4.4/503-MIPS-ath79-add-flash-acquire-release.patch
new file mode 100644
index 0000000000..82235ce22c
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/503-MIPS-ath79-add-flash-acquire-release.patch
@@ -0,0 +1,37 @@
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -22,6 +22,7 @@
+ #include "common.h"
+ 
+ static DEFINE_SPINLOCK(ath79_device_reset_lock);
++static DEFINE_MUTEX(ath79_flash_mutex);
+ 
+ u32 ath79_cpu_freq;
+ EXPORT_SYMBOL_GPL(ath79_cpu_freq);
+@@ -142,3 +143,16 @@ void ath79_device_reset_clear(u32 mask)
+ 	spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
+ }
+ EXPORT_SYMBOL_GPL(ath79_device_reset_clear);
++
++void ath79_flash_acquire(void)
++{
++	mutex_lock(&ath79_flash_mutex);
++}
++EXPORT_SYMBOL_GPL(ath79_flash_acquire);
++
++void ath79_flash_release(void)
++{
++	mutex_unlock(&ath79_flash_mutex);
++}
++EXPORT_SYMBOL_GPL(ath79_flash_release);
++
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -145,4 +145,7 @@ static inline u32 ath79_reset_rr(unsigne
+ void ath79_device_reset_set(u32 mask);
+ void ath79_device_reset_clear(u32 mask);
+ 
++void ath79_flash_acquire(void);
++void ath79_flash_release(void);
++
+ #endif /* __ASM_MACH_ATH79_H */
diff --git a/target/linux/ar71xx/patches-4.4/504-MIPS-ath79-add-ath79_device_reset_get.patch b/target/linux/ar71xx/patches-4.4/504-MIPS-ath79-add-ath79_device_reset_get.patch
new file mode 100644
index 0000000000..38d426e014
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/504-MIPS-ath79-add-ath79_device_reset_get.patch
@@ -0,0 +1,45 @@
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -144,6 +144,7 @@ static inline u32 ath79_reset_rr(unsigne
+ 
+ void ath79_device_reset_set(u32 mask);
+ void ath79_device_reset_clear(u32 mask);
++u32 ath79_device_reset_get(u32 mask);
+ 
+ void ath79_flash_acquire(void);
+ void ath79_flash_release(void);
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -144,6 +144,32 @@ void ath79_device_reset_clear(u32 mask)
+ }
+ EXPORT_SYMBOL_GPL(ath79_device_reset_clear);
+ 
++u32 ath79_device_reset_get(u32 mask)
++{
++	unsigned long flags;
++	u32 reg;
++	u32 ret;
++
++	if (soc_is_ar71xx())
++		reg = AR71XX_RESET_REG_RESET_MODULE;
++	else if (soc_is_ar724x())
++		reg = AR724X_RESET_REG_RESET_MODULE;
++	else if (soc_is_ar913x())
++		reg = AR913X_RESET_REG_RESET_MODULE;
++	else if (soc_is_ar933x())
++		reg = AR933X_RESET_REG_RESET_MODULE;
++	else if (soc_is_ar934x())
++		reg = AR934X_RESET_REG_RESET_MODULE;
++	else
++		BUG();
++
++	spin_lock_irqsave(&ath79_device_reset_lock, flags);
++	ret = ath79_reset_rr(reg);
++	spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(ath79_device_reset_get);
++
+ void ath79_flash_acquire(void)
+ {
+ 	mutex_lock(&ath79_flash_mutex);
diff --git a/target/linux/ar71xx/patches-4.4/505-MIPS-ath79-add-ath79_gpio_function_select.patch b/target/linux/ar71xx/patches-4.4/505-MIPS-ath79-add-ath79_gpio_function_select.patch
new file mode 100644
index 0000000000..3adb088d52
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/505-MIPS-ath79-add-ath79_gpio_function_select.patch
@@ -0,0 +1,39 @@
+--- a/arch/mips/ath79/common.h
++++ b/arch/mips/ath79/common.h
+@@ -28,6 +28,7 @@ void ath79_ddr_wb_flush(unsigned int reg
+ void ath79_gpio_function_enable(u32 mask);
+ void ath79_gpio_function_disable(u32 mask);
+ void ath79_gpio_function_setup(u32 set, u32 clear);
++void ath79_gpio_output_select(unsigned gpio, u8 val);
+ void ath79_gpio_init(void);
+ 
+ #endif /* __ATH79_COMMON_H */
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -57,3 +57,26 @@ void ath79_gpio_function_disable(u32 mas
+ {
+ 	ath79_gpio_function_setup(0, mask);
+ }
++
++void __init ath79_gpio_output_select(unsigned gpio, u8 val)
++{
++	void __iomem *base = ath79_gpio_base;
++	unsigned int reg;
++	u32 t, s;
++
++	BUG_ON(!soc_is_ar934x());
++
++	if (gpio >= AR934X_GPIO_COUNT)
++		return;
++
++	reg = AR934X_GPIO_REG_OUT_FUNC0 + 4 * (gpio / 4);
++	s = 8 * (gpio % 4);
++
++	t = __raw_readl(base + reg);
++	t &= ~(0xff << s);
++	t |= val << s;
++	__raw_writel(t, base + reg);
++
++	/* flush write */
++	(void) __raw_readl(base + reg);
++}
diff --git a/target/linux/ar71xx/patches-4.4/506-MIPS-ath79-prom-parse-redboot-args.patch b/target/linux/ar71xx/patches-4.4/506-MIPS-ath79-prom-parse-redboot-args.patch
new file mode 100644
index 0000000000..46beeffeea
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/506-MIPS-ath79-prom-parse-redboot-args.patch
@@ -0,0 +1,42 @@
+--- a/arch/mips/ath79/prom.c
++++ b/arch/mips/ath79/prom.c
+@@ -22,10 +22,39 @@
+ 
+ #include "common.h"
+ 
++static char ath79_cmdline_buf[COMMAND_LINE_SIZE] __initdata;
++
++static void __init ath79_prom_append_cmdline(const char *name,
++					      const char *value)
++{
++	snprintf(ath79_cmdline_buf, sizeof(ath79_cmdline_buf),
++		 " %s=%s", name, value);
++	strlcat(arcs_cmdline, ath79_cmdline_buf, sizeof(arcs_cmdline));
++}
++
+ void __init prom_init(void)
+ {
++	const char *env;
++
+ 	fw_init_cmdline();
+ 
++	env = fw_getenv("ethaddr");
++	if (env)
++		ath79_prom_append_cmdline("ethaddr", env);
++
++	env = fw_getenv("board");
++	if (env) {
++		/* Workaround for buggy bootloaders */
++		if (strcmp(env, "RouterStation") == 0 ||
++		    strcmp(env, "Ubiquiti AR71xx-based board") == 0)
++			env = "UBNT-RS";
++
++		if (strcmp(env, "RouterStation PRO") == 0)
++			env = "UBNT-RSPRO";
++
++		ath79_prom_append_cmdline("board", env);
++	}
++
+ #ifdef CONFIG_BLK_DEV_INITRD
+ 	/* Read the initrd address from the firmware environment */
+ 	initrd_start = fw_getenvl("initrd_start");
diff --git a/target/linux/ar71xx/patches-4.4/507-MIPS-ath79-prom-add-myloader-support.patch b/target/linux/ar71xx/patches-4.4/507-MIPS-ath79-prom-add-myloader-support.patch
new file mode 100644
index 0000000000..17a97335d2
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/507-MIPS-ath79-prom-add-myloader-support.patch
@@ -0,0 +1,55 @@
+--- a/arch/mips/ath79/prom.c
++++ b/arch/mips/ath79/prom.c
+@@ -19,6 +19,7 @@
+ #include <asm/bootinfo.h>
+ #include <asm/addrspace.h>
+ #include <asm/fw/fw.h>
++#include <asm/fw/myloader/myloader.h>
+ 
+ #include "common.h"
+ 
+@@ -32,10 +33,44 @@ static void __init ath79_prom_append_cmd
+ 	strlcat(arcs_cmdline, ath79_cmdline_buf, sizeof(arcs_cmdline));
+ }
+ 
++static int __init ath79_prom_init_myloader(void)
++{
++	struct myloader_info *mylo;
++	char mac_buf[32];
++	unsigned char *mac;
++
++	mylo = myloader_get_info();
++	if (!mylo)
++		return 0;
++
++	switch (mylo->did) {
++	case DEVID_COMPEX_WP543:
++		ath79_prom_append_cmdline("board", "WP543");
++		break;
++	case DEVID_COMPEX_WPE72:
++		ath79_prom_append_cmdline("board", "WPE72");
++		break;
++	default:
++		pr_warn("prom: unknown device id: %x\n", mylo->did);
++		return 0;
++	}
++
++	mac = mylo->macs[0];
++	snprintf(mac_buf, sizeof(mac_buf), "%02x:%02x:%02x:%02x:%02x:%02x",
++		 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++
++	ath79_prom_append_cmdline("ethaddr", mac_buf);
++
++	return 1;
++}
++
+ void __init prom_init(void)
+ {
+ 	const char *env;
+ 
++	if (ath79_prom_init_myloader())
++		return;
++
+ 	fw_init_cmdline();
+ 
+ 	env = fw_getenv("ethaddr");
diff --git a/target/linux/ar71xx/patches-4.4/508-MIPS-ath79-prom-image-command-line-hack.patch b/target/linux/ar71xx/patches-4.4/508-MIPS-ath79-prom-image-command-line-hack.patch
new file mode 100644
index 0000000000..cfa5e72eec
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/508-MIPS-ath79-prom-image-command-line-hack.patch
@@ -0,0 +1,73 @@
+--- a/arch/mips/ath79/prom.c
++++ b/arch/mips/ath79/prom.c
+@@ -33,6 +33,41 @@ static void __init ath79_prom_append_cmd
+ 	strlcat(arcs_cmdline, ath79_cmdline_buf, sizeof(arcs_cmdline));
+ }
+ 
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++extern char __image_cmdline[];
++
++static int __init ath79_use_image_cmdline(void)
++{
++	char *p = __image_cmdline;
++	int replace = 0;
++
++	if (*p == '-') {
++		replace = 1;
++		p++;
++	}
++
++	if (*p == '\0')
++		return 0;
++
++	if (replace) {
++		strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
++	} else {
++		strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
++		strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
++	}
++
++	/* Validate and setup environment pointer */
++	if (fw_arg2 < CKSEG0)
++		_fw_envp = NULL;
++	else
++		_fw_envp = (int *)fw_arg2;
++
++	return 1;
++}
++#else
++static inline int ath79_use_image_cmdline(void) { return 0; }
++#endif
++
+ static int __init ath79_prom_init_myloader(void)
+ {
+ 	struct myloader_info *mylo;
+@@ -61,6 +96,8 @@ static int __init ath79_prom_init_myload
+ 
+ 	ath79_prom_append_cmdline("ethaddr", mac_buf);
+ 
++	ath79_use_image_cmdline();
++
+ 	return 1;
+ }
+ 
+@@ -71,7 +108,8 @@ void __init prom_init(void)
+ 	if (ath79_prom_init_myloader())
+ 		return;
+ 
+-	fw_init_cmdline();
++	if (!ath79_use_image_cmdline())
++		fw_init_cmdline();
+ 
+ 	env = fw_getenv("ethaddr");
+ 	if (env)
+--- a/arch/mips/fw/lib/cmdline.c
++++ b/arch/mips/fw/lib/cmdline.c
+@@ -35,6 +35,7 @@ void __init fw_init_cmdline(void)
+ 	else
+ 		_fw_envp = (int *)fw_arg2;
+ 
++	arcs_cmdline[0] = '\0';
+ 	for (i = 1; i < fw_argc; i++) {
+ 		strlcat(arcs_cmdline, fw_argv(i), COMMAND_LINE_SIZE);
+ 		if (i < (fw_argc - 1))
diff --git a/target/linux/ar71xx/patches-4.4/509-MIPS-ath79-process-board-kernel-option.patch b/target/linux/ar71xx/patches-4.4/509-MIPS-ath79-process-board-kernel-option.patch
new file mode 100644
index 0000000000..40bd8522ab
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/509-MIPS-ath79-process-board-kernel-option.patch
@@ -0,0 +1,11 @@
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -253,6 +253,8 @@ void __init plat_time_init(void)
+ 	mips_hpt_frequency = cpu_clk_rate / 2;
+ }
+ 
++__setup("board=", mips_machtype_setup);
++
+ static int __init ath79_setup(void)
+ {
+ 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
diff --git a/target/linux/ar71xx/patches-4.4/510-MIPS-ath79-init-gpio-pin-of-wmac-device.patch b/target/linux/ar71xx/patches-4.4/510-MIPS-ath79-init-gpio-pin-of-wmac-device.patch
new file mode 100644
index 0000000000..2d2235e292
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/510-MIPS-ath79-init-gpio-pin-of-wmac-device.patch
@@ -0,0 +1,14 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -24,7 +24,10 @@
+ #include "dev-wmac.h"
+ 
+ static u8 ath79_wmac_mac[ETH_ALEN];
+-static struct ath9k_platform_data ath79_wmac_data;
++
++static struct ath9k_platform_data ath79_wmac_data = {
++	.led_pin = -1,
++};
+ 
+ static struct resource ath79_wmac_resources[] = {
+ 	{
diff --git a/target/linux/ar71xx/patches-4.4/520-MIPS-ath79-enable-UART-function.patch b/target/linux/ar71xx/patches-4.4/520-MIPS-ath79-enable-UART-function.patch
new file mode 100644
index 0000000000..c8649b7494
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/520-MIPS-ath79-enable-UART-function.patch
@@ -0,0 +1,18 @@
+--- a/arch/mips/ath79/dev-common.c
++++ b/arch/mips/ath79/dev-common.c
+@@ -81,6 +81,15 @@ void __init ath79_register_uart(void)
+ 
+ 	uart_clk_rate = ath79_get_sys_clk_rate("uart");
+ 
++	if (soc_is_ar71xx())
++		ath79_gpio_function_enable(AR71XX_GPIO_FUNC_UART_EN);
++	else if (soc_is_ar724x())
++		ath79_gpio_function_enable(AR724X_GPIO_FUNC_UART_EN);
++	else if (soc_is_ar913x())
++		ath79_gpio_function_enable(AR913X_GPIO_FUNC_UART_EN);
++	else if (soc_is_ar933x())
++		ath79_gpio_function_enable(AR933X_GPIO_FUNC_UART_EN);
++
+ 	if (soc_is_ar71xx() ||
+ 	    soc_is_ar724x() ||
+ 	    soc_is_ar913x() ||
diff --git a/target/linux/ar71xx/patches-4.4/521-MIPS-ath79-enable-UART-for-early_serial.patch b/target/linux/ar71xx/patches-4.4/521-MIPS-ath79-enable-UART-for-early_serial.patch
new file mode 100644
index 0000000000..e546ff26fe
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/521-MIPS-ath79-enable-UART-for-early_serial.patch
@@ -0,0 +1,61 @@
+--- a/arch/mips/ath79/early_printk.c
++++ b/arch/mips/ath79/early_printk.c
+@@ -58,6 +58,46 @@ static void prom_putchar_dummy(unsigned
+ 	/* nothing to do */
+ }
+ 
++static void prom_enable_uart(u32 id)
++{
++	void __iomem *gpio_base;
++	u32 uart_en;
++	u32 t;
++
++	switch (id) {
++	case REV_ID_MAJOR_AR71XX:
++		uart_en = AR71XX_GPIO_FUNC_UART_EN;
++		break;
++
++	case REV_ID_MAJOR_AR7240:
++	case REV_ID_MAJOR_AR7241:
++	case REV_ID_MAJOR_AR7242:
++		uart_en = AR724X_GPIO_FUNC_UART_EN;
++		break;
++
++	case REV_ID_MAJOR_AR913X:
++		uart_en = AR913X_GPIO_FUNC_UART_EN;
++		break;
++
++	case REV_ID_MAJOR_AR9330:
++	case REV_ID_MAJOR_AR9331:
++		uart_en = AR933X_GPIO_FUNC_UART_EN;
++		break;
++
++	case REV_ID_MAJOR_AR9341:
++	case REV_ID_MAJOR_AR9342:
++	case REV_ID_MAJOR_AR9344:
++		/* TODO */
++	default:
++		return;
++	}
++
++	gpio_base = (void __iomem *)(KSEG1ADDR(AR71XX_GPIO_BASE));
++	t = __raw_readl(gpio_base + AR71XX_GPIO_REG_FUNC);
++	t |= uart_en;
++	__raw_writel(t, gpio_base + AR71XX_GPIO_REG_FUNC);
++}
++
+ static void prom_putchar_init(void)
+ {
+ 	void __iomem *base;
+@@ -88,8 +128,10 @@ static void prom_putchar_init(void)
+ 
+ 	default:
+ 		_prom_putchar = prom_putchar_dummy;
+-		break;
++		return;
+ 	}
++
++	prom_enable_uart(id);
+ }
+ 
+ void prom_putchar(unsigned char ch)
diff --git a/target/linux/ar71xx/patches-4.4/522-MIPS-ath79-add-ath79_wmac_register_simple-helper.patch b/target/linux/ar71xx/patches-4.4/522-MIPS-ath79-add-ath79_wmac_register_simple-helper.patch
new file mode 100644
index 0000000000..a29c7be8ec
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/522-MIPS-ath79-add-ath79_wmac_register_simple-helper.patch
@@ -0,0 +1,21 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -191,3 +191,9 @@ void __init ath79_register_wmac(u8 *cal_
+ 
+ 	platform_device_register(&ath79_wmac_device);
+ }
++
++void __init ath79_register_wmac_simple(void)
++{
++	ath79_register_wmac(NULL, NULL);
++	ath79_wmac_data.eeprom_name = "soc_wmac.eeprom";
++}
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -13,5 +13,6 @@
+ #define _ATH79_DEV_WMAC_H
+ 
+ void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
++void ath79_register_wmac_simple(void);
+ 
+ #endif /* _ATH79_DEV_WMAC_H */
diff --git a/target/linux/ar71xx/patches-4.4/523-MIPS-ath79-OTP-support.patch b/target/linux/ar71xx/patches-4.4/523-MIPS-ath79-OTP-support.patch
new file mode 100644
index 0000000000..e030d7cec3
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/523-MIPS-ath79-OTP-support.patch
@@ -0,0 +1,166 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -167,6 +167,137 @@ static void qca955x_wmac_setup(void)
+ 		ath79_wmac_data.is_clk_25mhz = true;
+ }
+ 
++static bool __init
++ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data)
++{
++	int timeout = 1000;
++	u32 val;
++
++	__raw_readl(base + AR9300_OTP_BASE + (4 * addr));
++	while (timeout--) {
++		val = __raw_readl(base + AR9300_OTP_STATUS);
++		if ((val & AR9300_OTP_STATUS_TYPE) == AR9300_OTP_STATUS_VALID)
++			break;
++
++		udelay(10);
++	}
++
++	if (!timeout)
++		return false;
++
++	*data = __raw_readl(base + AR9300_OTP_READ_DATA);
++	return true;
++}
++
++static bool __init
++ar93xx_wmac_otp_read(void __iomem *base, int addr, u8 *dest, int len)
++{
++	u32 data;
++	int i;
++
++	for (i = 0; i < len; i++) {
++		int offset = 8 * ((addr - i) % 4);
++
++		if (!ar93xx_wmac_otp_read_word(base, (addr - i) / 4, &data))
++			return false;
++
++		dest[i] = (data >> offset) & 0xff;
++	}
++
++	return true;
++}
++
++static bool __init
++ar93xx_wmac_otp_uncompress(void __iomem *base, int addr, int len, u8 *dest,
++			   int dest_start, int dest_len)
++{
++	int dest_bytes = 0;
++	int offset = 0;
++	int end = addr - len;
++	u8 hdr[2];
++
++	while (addr > end) {
++		if (!ar93xx_wmac_otp_read(base, addr, hdr, 2))
++			return false;
++
++		addr -= 2;
++		offset += hdr[0];
++
++		if (offset <= dest_start + dest_len &&
++		    offset + len >= dest_start) {
++			int data_offset = 0;
++			int dest_offset = 0;
++			int copy_len;
++
++			if (offset < dest_start)
++				data_offset = dest_start - offset;
++			else
++				dest_offset = offset - dest_start;
++
++			copy_len = len - data_offset;
++			if (copy_len > dest_len - dest_offset)
++				copy_len = dest_len - dest_offset;
++
++			ar93xx_wmac_otp_read(base, addr - data_offset,
++					     dest + dest_offset,
++					     copy_len);
++
++			dest_bytes += copy_len;
++		}
++		addr -= hdr[1];
++	}
++	return !!dest_bytes;
++}
++
++bool __init ar93xx_wmac_read_mac_address(u8 *dest)
++{
++	void __iomem *base;
++	bool ret = false;
++	int addr = 0x1ff;
++	unsigned int len;
++	u32 hdr_u32;
++	u8 *hdr = (u8 *) &hdr_u32;
++	u8 mac[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x06 };
++	int mac_start = 2, mac_end = 8;
++
++	BUG_ON(!soc_is_ar933x() && !soc_is_ar934x());
++	base = ioremap_nocache(AR933X_WMAC_BASE, AR933X_WMAC_SIZE);
++	while (addr > sizeof(hdr)) {
++		if (!ar93xx_wmac_otp_read(base, addr, hdr, sizeof(hdr)))
++			break;
++
++		if (hdr_u32 == 0 || hdr_u32 == ~0)
++			break;
++
++		len = (hdr[1] << 4) | (hdr[2] >> 4);
++		addr -= 4;
++
++		switch (hdr[0] >> 5) {
++		case 0:
++			if (len < mac_end)
++				break;
++
++			ar93xx_wmac_otp_read(base, addr - mac_start, mac, 6);
++			ret = true;
++			break;
++		case 3:
++			ret |= ar93xx_wmac_otp_uncompress(base, addr, len, mac,
++							  mac_start, 6);
++			break;
++		default:
++			break;
++		}
++
++		addr -= len + 2;
++	}
++
++	iounmap(base);
++	if (ret)
++		memcpy(dest, mac, 6);
++
++	return ret;
++}
++
+ void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+ 	if (soc_is_ar913x())
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -14,5 +14,6 @@
+ 
+ void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
+ void ath79_register_wmac_simple(void);
++bool ar93xx_wmac_read_mac_address(u8 *dest);
+ 
+ #endif /* _ATH79_DEV_WMAC_H */
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -112,6 +112,14 @@
+ #define QCA955X_EHCI1_BASE	0x1b400000
+ #define QCA955X_EHCI_SIZE	0x1000
+ 
++#define AR9300_OTP_BASE		0x14000
++#define AR9300_OTP_STATUS	0x15f18
++#define AR9300_OTP_STATUS_TYPE		0x7
++#define AR9300_OTP_STATUS_VALID		0x4
++#define AR9300_OTP_STATUS_ACCESS_BUSY	0x2
++#define AR9300_OTP_STATUS_SM_BUSY	0x1
++#define AR9300_OTP_READ_DATA	0x15f1c
++
+ /*
+  * DDR_CTRL block
+  */
diff --git a/target/linux/ar71xx/patches-4.4/524-MIPS-ath79-add-ath79_wmac_disable_25ghz-helpers.patch b/target/linux/ar71xx/patches-4.4/524-MIPS-ath79-add-ath79_wmac_disable_25ghz-helpers.patch
new file mode 100644
index 0000000000..31f885f2c8
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/524-MIPS-ath79-add-ath79_wmac_disable_25ghz-helpers.patch
@@ -0,0 +1,31 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -298,6 +298,16 @@ bool __init ar93xx_wmac_read_mac_address
+ 	return ret;
+ }
+ 
++void __init ath79_wmac_disable_2ghz(void)
++{
++	ath79_wmac_data.disable_2ghz = true;
++}
++
++void __init ath79_wmac_disable_5ghz(void)
++{
++	ath79_wmac_data.disable_5ghz = true;
++}
++
+ void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+ 	if (soc_is_ar913x())
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -14,6 +14,9 @@
+ 
+ void ath79_register_wmac(u8 *cal_data, u8 *mac_addr);
+ void ath79_register_wmac_simple(void);
++void ath79_wmac_disable_2ghz(void);
++void ath79_wmac_disable_5ghz(void);
++
+ bool ar93xx_wmac_read_mac_address(u8 *dest);
+ 
+ #endif /* _ATH79_DEV_WMAC_H */
diff --git a/target/linux/ar71xx/patches-4.4/525-MIPS-ath79-enable-qca-usb-quirks.patch b/target/linux/ar71xx/patches-4.4/525-MIPS-ath79-enable-qca-usb-quirks.patch
new file mode 100644
index 0000000000..0e33674adf
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/525-MIPS-ath79-enable-qca-usb-quirks.patch
@@ -0,0 +1,101 @@
+--- a/arch/mips/ath79/dev-usb.c
++++ b/arch/mips/ath79/dev-usb.c
+@@ -37,6 +37,8 @@ static struct usb_ehci_pdata ath79_ehci_
+ static struct usb_ehci_pdata ath79_ehci_pdata_v2 = {
+ 	.caps_offset		= 0x100,
+ 	.has_tt			= 1,
++	.qca_force_host_mode	= 1,
++	.qca_force_16bit_ptw	= 1,
+ };
+ 
+ static void __init ath79_usb_register(const char *name, int id,
+@@ -159,6 +161,9 @@ static void __init ar913x_usb_setup(void
+ 	ath79_device_reset_clear(AR913X_RESET_USB_PHY);
+ 	mdelay(10);
+ 
++	ath79_ehci_pdata_v2.qca_force_host_mode	= 0;
++	ath79_ehci_pdata_v2.qca_force_16bit_ptw	= 0;
++
+ 	ath79_usb_register("ehci-platform", -1,
+ 			   AR913X_EHCI_BASE, AR913X_EHCI_SIZE,
+ 			   ATH79_CPU_IRQ(3),
+@@ -182,14 +187,34 @@ static void __init ar933x_usb_setup(void
+ 			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+ }
+ 
+-static void __init ar934x_usb_setup(void)
++static void enable_tx_tx_idp_violation_fix(unsigned base)
+ {
+-	u32 bootstrap;
++	void __iomem *phy_reg;
++	u32 t;
++
++	phy_reg = ioremap(base, 4);
++	if (!phy_reg)
++		return;
++
++	t = ioread32(phy_reg);
++	t &= ~0xff;
++	t |= 0x58;
++	iowrite32(t, phy_reg);
++
++	iounmap(phy_reg);
++}
+ 
+-	bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
+-	if (bootstrap & AR934X_BOOTSTRAP_USB_MODE_DEVICE)
++static void ar934x_usb_reset_notifier(struct platform_device *pdev)
++{
++	if (pdev->id != -1)
+ 		return;
+ 
++	enable_tx_tx_idp_violation_fix(0x18116c94);
++	dev_info(&pdev->dev, "TX-TX IDP fix enabled\n");
++}
++
++static void __init ar934x_usb_setup(void)
++{
+ 	ath79_device_reset_set(AR934X_RESET_USBSUS_OVERRIDE);
+ 	udelay(1000);
+ 
+@@ -202,14 +227,40 @@ static void __init ar934x_usb_setup(void
+ 	ath79_device_reset_clear(AR934X_RESET_USB_HOST);
+ 	udelay(1000);
+ 
++	if (ath79_soc_rev >= 3)
++		ath79_ehci_pdata_v2.reset_notifier = ar934x_usb_reset_notifier;
++
+ 	ath79_usb_register("ehci-platform", -1,
+ 			   AR934X_EHCI_BASE, AR934X_EHCI_SIZE,
+ 			   ATH79_CPU_IRQ(3),
+ 			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+ }
+ 
++static void qca955x_usb_reset_notifier(struct platform_device *pdev)
++{
++	u32 base;
++
++	switch (pdev->id) {
++	case 0:
++		base = 0x18116c94;
++		break;
++
++	case 1:
++		base = 0x18116e54;
++		break;
++
++	default:
++		return;
++	}
++
++	enable_tx_tx_idp_violation_fix(base);
++	dev_info(&pdev->dev, "TX-TX IDP fix enabled\n");
++}
++
+ static void __init qca955x_usb_setup(void)
+ {
++	ath79_ehci_pdata_v2.reset_notifier = qca955x_usb_reset_notifier;
++
+ 	ath79_usb_register("ehci-platform", 0,
+ 			   QCA955X_EHCI0_BASE, QCA955X_EHCI_SIZE,
+ 			   ATH79_IP3_IRQ(0),
diff --git a/target/linux/ar71xx/patches-4.4/601-MIPS-ath79-add-more-register-defines.patch b/target/linux/ar71xx/patches-4.4/601-MIPS-ath79-add-more-register-defines.patch
new file mode 100644
index 0000000000..0126f6a3b9
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/601-MIPS-ath79-add-more-register-defines.patch
@@ -0,0 +1,455 @@
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -20,6 +20,10 @@
+ #include <linux/bitops.h>
+ 
+ #define AR71XX_APB_BASE		0x18000000
++#define AR71XX_GE0_BASE		0x19000000
++#define AR71XX_GE0_SIZE		0x10000
++#define AR71XX_GE1_BASE		0x1a000000
++#define AR71XX_GE1_SIZE		0x10000
+ #define AR71XX_EHCI_BASE	0x1b000000
+ #define AR71XX_EHCI_SIZE	0x1000
+ #define AR71XX_OHCI_BASE	0x1c000000
+@@ -39,6 +43,8 @@
+ #define AR71XX_PLL_SIZE		0x100
+ #define AR71XX_RESET_BASE	(AR71XX_APB_BASE + 0x00060000)
+ #define AR71XX_RESET_SIZE	0x100
++#define AR71XX_MII_BASE		(AR71XX_APB_BASE + 0x00070000)
++#define AR71XX_MII_SIZE		0x100
+ 
+ #define AR71XX_PCI_MEM_BASE	0x10000000
+ #define AR71XX_PCI_MEM_SIZE	0x07000000
+@@ -81,15 +87,21 @@
+ 
+ #define AR933X_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
+ #define AR933X_UART_SIZE	0x14
++#define AR933X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
++#define AR933X_GMAC_SIZE	0x04
+ #define AR933X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+ #define AR933X_WMAC_SIZE	0x20000
+ #define AR933X_EHCI_BASE	0x1b000000
+ #define AR933X_EHCI_SIZE	0x1000
+ 
++#define AR934X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
++#define AR934X_GMAC_SIZE	0x14
+ #define AR934X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+ #define AR934X_WMAC_SIZE	0x20000
+ #define AR934X_EHCI_BASE	0x1b000000
+ #define AR934X_EHCI_SIZE	0x200
++#define AR934X_NFC_BASE		0x1b000200
++#define AR934X_NFC_SIZE		0xb8
+ #define AR934X_SRIF_BASE	(AR71XX_APB_BASE + 0x00116000)
+ #define AR934X_SRIF_SIZE	0x1000
+ 
+@@ -106,11 +118,15 @@
+ #define QCA955X_PCI_CTRL_BASE1	(AR71XX_APB_BASE + 0x00280000)
+ #define QCA955X_PCI_CTRL_SIZE	0x100
+ 
++#define QCA955X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
++#define QCA955X_GMAC_SIZE	0x40
+ #define QCA955X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+ #define QCA955X_WMAC_SIZE	0x20000
+ #define QCA955X_EHCI0_BASE	0x1b000000
+ #define QCA955X_EHCI1_BASE	0x1b400000
+ #define QCA955X_EHCI_SIZE	0x1000
++#define QCA955X_NFC_BASE	0x1b800200
++#define QCA955X_NFC_SIZE	0xb8
+ 
+ #define AR9300_OTP_BASE		0x14000
+ #define AR9300_OTP_STATUS	0x15f18
+@@ -174,6 +190,9 @@
+ #define AR71XX_AHB_DIV_SHIFT		20
+ #define AR71XX_AHB_DIV_MASK		0x7
+ 
++#define AR71XX_ETH0_PLL_SHIFT		17
++#define AR71XX_ETH1_PLL_SHIFT		19
++
+ #define AR724X_PLL_REG_CPU_CONFIG	0x00
+ #define AR724X_PLL_REG_PCIE_CONFIG	0x18
+ 
+@@ -186,6 +205,8 @@
+ #define AR724X_DDR_DIV_SHIFT		22
+ #define AR724X_DDR_DIV_MASK		0x3
+ 
++#define AR7242_PLL_REG_ETH0_INT_CLOCK	0x2c
++
+ #define AR913X_PLL_REG_CPU_CONFIG	0x00
+ #define AR913X_PLL_REG_ETH_CONFIG	0x04
+ #define AR913X_PLL_REG_ETH0_INT_CLOCK	0x14
+@@ -198,6 +219,9 @@
+ #define AR913X_AHB_DIV_SHIFT		19
+ #define AR913X_AHB_DIV_MASK		0x1
+ 
++#define AR913X_ETH0_PLL_SHIFT		20
++#define AR913X_ETH1_PLL_SHIFT		22
++
+ #define AR933X_PLL_CPU_CONFIG_REG	0x00
+ #define AR933X_PLL_CLOCK_CTRL_REG	0x08
+ 
+@@ -219,6 +243,8 @@
+ #define AR934X_PLL_CPU_CONFIG_REG		0x00
+ #define AR934X_PLL_DDR_CONFIG_REG		0x04
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_REG		0x08
++#define AR934X_PLL_SWITCH_CLOCK_CONTROL_REG	0x24
++#define AR934X_PLL_ETH_XMII_CONTROL_REG		0x2c
+ 
+ #define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT	0
+ #define AR934X_PLL_CPU_CONFIG_NFRAC_MASK	0x3f
+@@ -251,9 +277,13 @@
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL	BIT(21)
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL	BIT(24)
+ 
++#define AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL	BIT(6)
++
+ #define QCA955X_PLL_CPU_CONFIG_REG		0x00
+ #define QCA955X_PLL_DDR_CONFIG_REG		0x04
+ #define QCA955X_PLL_CLK_CTRL_REG		0x08
++#define QCA955X_PLL_ETH_XMII_CONTROL_REG	0x28
++#define QCA955X_PLL_ETH_SGMII_CONTROL_REG	0x48
+ 
+ #define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT	0
+ #define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK	0x3f
+@@ -378,16 +408,83 @@
+ #define AR913X_RESET_USB_HOST		BIT(5)
+ #define AR913X_RESET_USB_PHY		BIT(4)
+ 
++#define AR933X_RESET_GE1_MDIO		BIT(23)
++#define AR933X_RESET_GE0_MDIO		BIT(22)
++#define AR933X_RESET_GE1_MAC		BIT(13)
+ #define AR933X_RESET_WMAC		BIT(11)
++#define AR933X_RESET_GE0_MAC		BIT(9)
+ #define AR933X_RESET_USB_HOST		BIT(5)
+ #define AR933X_RESET_USB_PHY		BIT(4)
+ #define AR933X_RESET_USBSUS_OVERRIDE	BIT(3)
+ 
++#define AR934X_RESET_HOST		BIT(31)
++#define AR934X_RESET_SLIC		BIT(30)
++#define AR934X_RESET_HDMA		BIT(29)
++#define AR934X_RESET_EXTERNAL		BIT(28)
++#define AR934X_RESET_RTC		BIT(27)
++#define AR934X_RESET_PCIE_EP_INT	BIT(26)
++#define AR934X_RESET_CHKSUM_ACC		BIT(25)
++#define AR934X_RESET_FULL_CHIP		BIT(24)
++#define AR934X_RESET_GE1_MDIO		BIT(23)
++#define AR934X_RESET_GE0_MDIO		BIT(22)
++#define AR934X_RESET_CPU_NMI		BIT(21)
++#define AR934X_RESET_CPU_COLD		BIT(20)
++#define AR934X_RESET_HOST_RESET_INT	BIT(19)
++#define AR934X_RESET_PCIE_EP		BIT(18)
++#define AR934X_RESET_UART1		BIT(17)
++#define AR934X_RESET_DDR		BIT(16)
++#define AR934X_RESET_USB_PHY_PLL_PWD_EXT BIT(15)
++#define AR934X_RESET_NANDF		BIT(14)
++#define AR934X_RESET_GE1_MAC		BIT(13)
++#define AR934X_RESET_ETH_SWITCH_ANALOG	BIT(12)
+ #define AR934X_RESET_USB_PHY_ANALOG	BIT(11)
++#define AR934X_RESET_HOST_DMA_INT	BIT(10)
++#define AR934X_RESET_GE0_MAC		BIT(9)
++#define AR934X_RESET_ETH_SWITCH		BIT(8)
++#define AR934X_RESET_PCIE_PHY		BIT(7)
++#define AR934X_RESET_PCIE		BIT(6)
+ #define AR934X_RESET_USB_HOST		BIT(5)
+ #define AR934X_RESET_USB_PHY		BIT(4)
+ #define AR934X_RESET_USBSUS_OVERRIDE	BIT(3)
++#define AR934X_RESET_LUT		BIT(2)
++#define AR934X_RESET_MBOX		BIT(1)
++#define AR934X_RESET_I2S		BIT(0)
++
++#define QCA955X_RESET_HOST		BIT(31)
++#define QCA955X_RESET_SLIC		BIT(30)
++#define QCA955X_RESET_HDMA		BIT(29)
++#define QCA955X_RESET_EXTERNAL		BIT(28)
++#define QCA955X_RESET_RTC		BIT(27)
++#define QCA955X_RESET_PCIE_EP_INT	BIT(26)
++#define QCA955X_RESET_CHKSUM_ACC	BIT(25)
++#define QCA955X_RESET_FULL_CHIP		BIT(24)
++#define QCA955X_RESET_GE1_MDIO		BIT(23)
++#define QCA955X_RESET_GE0_MDIO		BIT(22)
++#define QCA955X_RESET_CPU_NMI		BIT(21)
++#define QCA955X_RESET_CPU_COLD		BIT(20)
++#define QCA955X_RESET_HOST_RESET_INT	BIT(19)
++#define QCA955X_RESET_PCIE_EP		BIT(18)
++#define QCA955X_RESET_UART1		BIT(17)
++#define QCA955X_RESET_DDR		BIT(16)
++#define QCA955X_RESET_USB_PHY_PLL_PWD_EXT BIT(15)
++#define QCA955X_RESET_NANDF		BIT(14)
++#define QCA955X_RESET_GE1_MAC		BIT(13)
++#define QCA955X_RESET_SGMII_ANALOG	BIT(12)
++#define QCA955X_RESET_USB_PHY_ANALOG	BIT(11)
++#define QCA955X_RESET_HOST_DMA_INT	BIT(10)
++#define QCA955X_RESET_GE0_MAC		BIT(9)
++#define QCA955X_RESET_SGMII		BIT(8)
++#define QCA955X_RESET_PCIE_PHY		BIT(7)
++#define QCA955X_RESET_PCIE		BIT(6)
++#define QCA955X_RESET_USB_HOST		BIT(5)
++#define QCA955X_RESET_USB_PHY		BIT(4)
++#define QCA955X_RESET_USBSUS_OVERRIDE	BIT(3)
++#define QCA955X_RESET_LUT		BIT(2)
++#define QCA955X_RESET_MBOX		BIT(1)
++#define QCA955X_RESET_I2S		BIT(0)
+ 
++#define AR933X_BOOTSTRAP_MDIO_GPIO_EN	BIT(18)
++#define AR933X_BOOTSTRAP_EEPBUSY	BIT(4)
+ #define AR933X_BOOTSTRAP_REF_CLK_40	BIT(0)
+ 
+ #define AR934X_BOOTSTRAP_SW_OPTION8	BIT(23)
+@@ -529,8 +626,22 @@
+ #define AR71XX_GPIO_REG_INT_ENABLE	0x24
+ #define AR71XX_GPIO_REG_FUNC		0x28
+ 
++#define AR934X_GPIO_REG_OUT_FUNC0	0x2c
++#define AR934X_GPIO_REG_OUT_FUNC1	0x30
++#define AR934X_GPIO_REG_OUT_FUNC2	0x34
++#define AR934X_GPIO_REG_OUT_FUNC3	0x38
++#define AR934X_GPIO_REG_OUT_FUNC4	0x3c
++#define AR934X_GPIO_REG_OUT_FUNC5	0x40
+ #define AR934X_GPIO_REG_FUNC		0x6c
+ 
++#define QCA955X_GPIO_REG_OUT_FUNC0	0x2c
++#define QCA955X_GPIO_REG_OUT_FUNC1	0x30
++#define QCA955X_GPIO_REG_OUT_FUNC2	0x34
++#define QCA955X_GPIO_REG_OUT_FUNC3	0x38
++#define QCA955X_GPIO_REG_OUT_FUNC4	0x3c
++#define QCA955X_GPIO_REG_OUT_FUNC5	0x40
++#define QCA955X_GPIO_REG_FUNC		0x6c
++
+ #define AR71XX_GPIO_COUNT		16
+ #define AR7240_GPIO_COUNT		18
+ #define AR7241_GPIO_COUNT		20
+@@ -560,4 +671,235 @@
+ #define AR934X_SRIF_DPLL2_OUTDIV_SHIFT	13
+ #define AR934X_SRIF_DPLL2_OUTDIV_MASK	0x7
+ 
++#define AR71XX_GPIO_FUNC_STEREO_EN		BIT(17)
++#define AR71XX_GPIO_FUNC_SLIC_EN		BIT(16)
++#define AR71XX_GPIO_FUNC_SPI_CS2_EN		BIT(13)
++#define AR71XX_GPIO_FUNC_SPI_CS1_EN		BIT(12)
++#define AR71XX_GPIO_FUNC_UART_EN		BIT(8)
++#define AR71XX_GPIO_FUNC_USB_OC_EN		BIT(4)
++#define AR71XX_GPIO_FUNC_USB_CLK_EN		BIT(0)
++
++#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN		BIT(19)
++#define AR724X_GPIO_FUNC_SPI_EN			BIT(18)
++#define AR724X_GPIO_FUNC_SPI_CS_EN2		BIT(14)
++#define AR724X_GPIO_FUNC_SPI_CS_EN1		BIT(13)
++#define AR724X_GPIO_FUNC_CLK_OBS5_EN		BIT(12)
++#define AR724X_GPIO_FUNC_CLK_OBS4_EN		BIT(11)
++#define AR724X_GPIO_FUNC_CLK_OBS3_EN		BIT(10)
++#define AR724X_GPIO_FUNC_CLK_OBS2_EN		BIT(9)
++#define AR724X_GPIO_FUNC_CLK_OBS1_EN		BIT(8)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN	BIT(7)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN	BIT(6)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN	BIT(5)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN	BIT(4)
++#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN	BIT(3)
++#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN	BIT(2)
++#define AR724X_GPIO_FUNC_UART_EN		BIT(1)
++#define AR724X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
++
++#define AR913X_GPIO_FUNC_WMAC_LED_EN		BIT(22)
++#define AR913X_GPIO_FUNC_EXP_PORT_CS_EN		BIT(21)
++#define AR913X_GPIO_FUNC_I2S_REFCLKEN		BIT(20)
++#define AR913X_GPIO_FUNC_I2S_MCKEN		BIT(19)
++#define AR913X_GPIO_FUNC_I2S1_EN		BIT(18)
++#define AR913X_GPIO_FUNC_I2S0_EN		BIT(17)
++#define AR913X_GPIO_FUNC_SLIC_EN		BIT(16)
++#define AR913X_GPIO_FUNC_UART_RTSCTS_EN		BIT(9)
++#define AR913X_GPIO_FUNC_UART_EN		BIT(8)
++#define AR913X_GPIO_FUNC_USB_CLK_EN		BIT(4)
++
++#define AR933X_GPIO_FUNC_SPDIF2TCK		BIT(31)
++#define AR933X_GPIO_FUNC_SPDIF_EN		BIT(30)
++#define AR933X_GPIO_FUNC_I2SO_22_18_EN		BIT(29)
++#define AR933X_GPIO_FUNC_I2S_MCK_EN		BIT(27)
++#define AR933X_GPIO_FUNC_I2SO_EN		BIT(26)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_DUPL	BIT(25)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_COLL	BIT(24)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_ACT	BIT(23)
++#define AR933X_GPIO_FUNC_SPI_EN			BIT(18)
++#define AR933X_GPIO_FUNC_SPI_CS_EN2		BIT(14)
++#define AR933X_GPIO_FUNC_SPI_CS_EN1		BIT(13)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN	BIT(7)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN	BIT(6)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN	BIT(5)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN	BIT(4)
++#define AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN	BIT(3)
++#define AR933X_GPIO_FUNC_UART_RTS_CTS_EN	BIT(2)
++#define AR933X_GPIO_FUNC_UART_EN		BIT(1)
++#define AR933X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
++
++#define AR934X_GPIO_FUNC_CLK_OBS7_EN		BIT(9)
++#define AR934X_GPIO_FUNC_CLK_OBS6_EN		BIT(8)
++#define AR934X_GPIO_FUNC_CLK_OBS5_EN		BIT(7)
++#define AR934X_GPIO_FUNC_CLK_OBS4_EN		BIT(6)
++#define AR934X_GPIO_FUNC_CLK_OBS3_EN		BIT(5)
++#define AR934X_GPIO_FUNC_CLK_OBS2_EN		BIT(4)
++#define AR934X_GPIO_FUNC_CLK_OBS1_EN		BIT(3)
++#define AR934X_GPIO_FUNC_CLK_OBS0_EN		BIT(2)
++#define AR934X_GPIO_FUNC_JTAG_DISABLE		BIT(1)
++
++#define AR934X_GPIO_OUT_GPIO		0
++#define AR934X_GPIO_OUT_SPI_CS1	7
++#define AR934X_GPIO_OUT_LED_LINK0	41
++#define AR934X_GPIO_OUT_LED_LINK1	42
++#define AR934X_GPIO_OUT_LED_LINK2	43
++#define AR934X_GPIO_OUT_LED_LINK3	44
++#define AR934X_GPIO_OUT_LED_LINK4	45
++#define AR934X_GPIO_OUT_EXT_LNA0	46
++#define AR934X_GPIO_OUT_EXT_LNA1	47
++
++#define QCA955X_GPIO_FUNC_CLK_OBS7_EN		BIT(9)
++#define QCA955X_GPIO_FUNC_CLK_OBS6_EN		BIT(8)
++#define QCA955X_GPIO_FUNC_CLK_OBS5_EN		BIT(7)
++#define QCA955X_GPIO_FUNC_CLK_OBS4_EN		BIT(6)
++#define QCA955X_GPIO_FUNC_CLK_OBS3_EN		BIT(5)
++#define QCA955X_GPIO_FUNC_CLK_OBS2_EN		BIT(4)
++#define QCA955X_GPIO_FUNC_CLK_OBS1_EN		BIT(3)
++#define QCA955X_GPIO_FUNC_JTAG_DISABLE		BIT(1)
++
++#define QCA955X_GPIO_OUT_GPIO		0
++#define QCA955X_MII_EXT_MDI		1
++#define QCA955X_SLIC_DATA_OUT		3
++#define QCA955X_SLIC_PCM_FS		4
++#define QCA955X_SLIC_PCM_CLK		5
++#define QCA955X_SPI_CLK			8
++#define QCA955X_SPI_CS_0		9
++#define QCA955X_SPI_CS_1		10
++#define QCA955X_SPI_CS_2		11
++#define QCA955X_SPI_MISO		12
++#define QCA955X_I2S_CLK			13
++#define QCA955X_I2S_WS			14
++#define QCA955X_I2S_SD			15
++#define QCA955X_I2S_MCK			16
++#define QCA955X_SPDIF_OUT		17
++#define QCA955X_UART1_TD		18
++#define QCA955X_UART1_RTS		19
++#define QCA955X_UART1_RD		20
++#define QCA955X_UART1_CTS		21
++#define QCA955X_UART0_SOUT		22
++#define QCA955X_SPDIF2_OUT		23
++#define QCA955X_LED_SGMII_SPEED0	24
++#define QCA955X_LED_SGMII_SPEED1	25
++#define QCA955X_LED_SGMII_DUPLEX	26
++#define QCA955X_LED_SGMII_LINK_UP	27
++#define QCA955X_SGMII_SPEED0_INVERT	28
++#define QCA955X_SGMII_SPEED1_INVERT	29
++#define QCA955X_SGMII_DUPLEX_INVERT	30
++#define QCA955X_SGMII_LINK_UP_INVERT	31
++#define QCA955X_GE1_MII_MDO		32
++#define QCA955X_GE1_MII_MDC		33
++#define QCA955X_SWCOM2			38
++#define QCA955X_SWCOM3			39
++#define QCA955X_MAC2_GPIO		40
++#define QCA955X_MAC3_GPIO		41
++#define QCA955X_ATT_LED			42
++#define QCA955X_PWR_LED			43
++#define QCA955X_TX_FRAME		44
++#define QCA955X_RX_CLEAR_EXTERNAL	45
++#define QCA955X_LED_NETWORK_EN		46
++#define QCA955X_LED_POWER_EN		47
++#define QCA955X_WMAC_GLUE_WOW		68
++#define QCA955X_RX_CLEAR_EXTENSION	70
++#define QCA955X_CP_NAND_CS1		73
++#define QCA955X_USB_SUSPEND		74
++#define QCA955X_ETH_TX_ERR		75
++#define QCA955X_DDR_DQ_OE		76
++#define QCA955X_CLKREQ_N_EP		77
++#define QCA955X_CLKREQ_N_RC		78
++#define QCA955X_CLK_OBS0		79
++#define QCA955X_CLK_OBS1		80
++#define QCA955X_CLK_OBS2		81
++#define QCA955X_CLK_OBS3		82
++#define QCA955X_CLK_OBS4		83
++#define QCA955X_CLK_OBS5		84
++
++/*
++ * MII_CTRL block
++ */
++#define AR71XX_MII_REG_MII0_CTRL	0x00
++#define AR71XX_MII_REG_MII1_CTRL	0x04
++
++#define AR71XX_MII_CTRL_IF_MASK		3
++#define AR71XX_MII_CTRL_SPEED_SHIFT	4
++#define AR71XX_MII_CTRL_SPEED_MASK	3
++#define AR71XX_MII_CTRL_SPEED_10	0
++#define AR71XX_MII_CTRL_SPEED_100	1
++#define AR71XX_MII_CTRL_SPEED_1000	2
++
++#define AR71XX_MII0_CTRL_IF_GMII	0
++#define AR71XX_MII0_CTRL_IF_MII		1
++#define AR71XX_MII0_CTRL_IF_RGMII	2
++#define AR71XX_MII0_CTRL_IF_RMII	3
++
++#define AR71XX_MII1_CTRL_IF_RGMII	0
++#define AR71XX_MII1_CTRL_IF_RMII	1
++
++/*
++ * AR933X GMAC interface
++ */
++#define AR933X_GMAC_REG_ETH_CFG		0x00
++
++#define AR933X_ETH_CFG_RGMII_GE0	BIT(0)
++#define AR933X_ETH_CFG_MII_GE0		BIT(1)
++#define AR933X_ETH_CFG_GMII_GE0		BIT(2)
++#define AR933X_ETH_CFG_MII_GE0_MASTER	BIT(3)
++#define AR933X_ETH_CFG_MII_GE0_SLAVE	BIT(4)
++#define AR933X_ETH_CFG_MII_GE0_ERR_EN	BIT(5)
++#define AR933X_ETH_CFG_SW_PHY_SWAP	BIT(7)
++#define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP	BIT(8)
++#define AR933X_ETH_CFG_RMII_GE0		BIT(9)
++#define AR933X_ETH_CFG_RMII_GE0_SPD_10	0
++#define AR933X_ETH_CFG_RMII_GE0_SPD_100	BIT(10)
++
++/*
++ * AR934X GMAC Interface
++ */
++#define AR934X_GMAC_REG_ETH_CFG		0x00
++
++#define AR934X_ETH_CFG_RGMII_GMAC0	BIT(0)
++#define AR934X_ETH_CFG_MII_GMAC0	BIT(1)
++#define AR934X_ETH_CFG_GMII_GMAC0	BIT(2)
++#define AR934X_ETH_CFG_MII_GMAC0_MASTER	BIT(3)
++#define AR934X_ETH_CFG_MII_GMAC0_SLAVE	BIT(4)
++#define AR934X_ETH_CFG_MII_GMAC0_ERR_EN	BIT(5)
++#define AR934X_ETH_CFG_SW_ONLY_MODE	BIT(6)
++#define AR934X_ETH_CFG_SW_PHY_SWAP	BIT(7)
++#define AR934X_ETH_CFG_SW_APB_ACCESS	BIT(9)
++#define AR934X_ETH_CFG_RMII_GMAC0	BIT(10)
++#define AR933X_ETH_CFG_MII_CNTL_SPEED	BIT(11)
++#define AR934X_ETH_CFG_RMII_GMAC0_MASTER BIT(12)
++#define AR933X_ETH_CFG_SW_ACC_MSB_FIRST	BIT(13)
++#define AR934X_ETH_CFG_RXD_DELAY        BIT(14)
++#define AR934X_ETH_CFG_RXD_DELAY_MASK   0x3
++#define AR934X_ETH_CFG_RXD_DELAY_SHIFT  14
++#define AR934X_ETH_CFG_RDV_DELAY        BIT(16)
++#define AR934X_ETH_CFG_RDV_DELAY_MASK   0x3
++#define AR934X_ETH_CFG_RDV_DELAY_SHIFT  16
++
++/*
++ * QCA955X GMAC Interface
++ */
++
++#define QCA955X_GMAC_REG_ETH_CFG	0x00
++
++#define QCA955X_ETH_CFG_RGMII_EN	BIT(0)
++#define QCA955X_ETH_CFG_MII_GE0		BIT(1)
++#define QCA955X_ETH_CFG_GMII_GE0	BIT(2)
++#define QCA955X_ETH_CFG_MII_GE0_MASTER	BIT(3)
++#define QCA955X_ETH_CFG_MII_GE0_SLAVE	BIT(4)
++#define QCA955X_ETH_CFG_GE0_ERR_EN	BIT(5)
++#define QCA955X_ETH_CFG_GE0_SGMII	BIT(6)
++#define QCA955X_ETH_CFG_RMII_GE0	BIT(10)
++#define QCA955X_ETH_CFG_MII_CNTL_SPEED	BIT(11)
++#define QCA955X_ETH_CFG_RMII_GE0_MASTER	BIT(12)
++#define QCA955X_ETH_CFG_RXD_DELAY_MASK	0x3
++#define QCA955X_ETH_CFG_RXD_DELAY_SHIFT	14
++#define QCA955X_ETH_CFG_RDV_DELAY	BIT(16)
++#define QCA955X_ETH_CFG_RDV_DELAY_MASK	0x3
++#define QCA955X_ETH_CFG_RDV_DELAY_SHIFT	16
++#define QCA955X_ETH_CFG_TXD_DELAY_MASK	0x3
++#define QCA955X_ETH_CFG_TXD_DELAY_SHIFT	18
++#define QCA955X_ETH_CFG_TXE_DELAY_MASK	0x3
++#define QCA955X_ETH_CFG_TXE_DELAY_SHIFT	20
++
+ #endif /* __ASM_MACH_AR71XX_REGS_H */
diff --git a/target/linux/ar71xx/patches-4.4/602-MIPS-ath79-add-openwrt-stuff.patch b/target/linux/ar71xx/patches-4.4/602-MIPS-ath79-add-openwrt-stuff.patch
new file mode 100644
index 0000000000..9959a39651
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/602-MIPS-ath79-add-openwrt-stuff.patch
@@ -0,0 +1,49 @@
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -110,6 +110,20 @@ config SOC_QCA955X
+ 	select PCI_AR724X if PCI
+ 	def_bool n
+ 
++config ATH79_DEV_M25P80
++	select ATH79_DEV_SPI
++	def_bool n
++
++config ATH79_DEV_AP9X_PCI
++	select ATH79_PCI_ATH9K_FIXUP
++	def_bool n
++
++config ATH79_DEV_DSA
++	def_bool n
++
++config ATH79_DEV_ETH
++	def_bool n
++
+ config PCI_AR724X
+ 	def_bool n
+ 
+@@ -119,6 +133,10 @@ config ATH79_DEV_GPIO_BUTTONS
+ config ATH79_DEV_LEDS_GPIO
+ 	def_bool n
+ 
++config ATH79_DEV_NFC
++	depends on (SOC_AR934X || SOC_QCA955X)
++	def_bool n
++
+ config ATH79_DEV_SPI
+ 	def_bool n
+ 
+@@ -129,4 +147,14 @@ config ATH79_DEV_WMAC
+ 	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X)
+ 	def_bool n
+ 
++config ATH79_NVRAM
++	def_bool n
++
++config ATH79_PCI_ATH9K_FIXUP
++	def_bool n
++
++config ATH79_ROUTERBOOT
++	select LZO_DECOMPRESS
++	def_bool n
++
+ endif
diff --git a/target/linux/ar71xx/patches-4.4/603-MIPS-ath79-ap121-fixes.patch b/target/linux/ar71xx/patches-4.4/603-MIPS-ath79-ap121-fixes.patch
new file mode 100644
index 0000000000..773a858ae1
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/603-MIPS-ath79-ap121-fixes.patch
@@ -0,0 +1,149 @@
+--- a/arch/mips/ath79/mach-ap121.c
++++ b/arch/mips/ath79/mach-ap121.c
+@@ -1,19 +1,21 @@
+ /*
+  *  Atheros AP121 board support
+  *
+- *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+  *
+  *  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 "machtypes.h"
++#include "dev-eth.h"
+ #include "dev-gpio-buttons.h"
+ #include "dev-leds-gpio.h"
++#include "dev-m25p80.h"
+ #include "dev-spi.h"
+ #include "dev-usb.h"
+ #include "dev-wmac.h"
++#include "machtypes.h"
+ 
+ #define AP121_GPIO_LED_WLAN		0
+ #define AP121_GPIO_LED_USB		1
+@@ -24,7 +26,14 @@
+ #define AP121_KEYS_POLL_INTERVAL	20	/* msecs */
+ #define AP121_KEYS_DEBOUNCE_INTERVAL	(3 * AP121_KEYS_POLL_INTERVAL)
+ 
+-#define AP121_CAL_DATA_ADDR	0x1fff1000
++#define AP121_MAC0_OFFSET		0x0000
++#define AP121_MAC1_OFFSET		0x0006
++#define AP121_CALDATA_OFFSET		0x1000
++#define AP121_WMAC_MAC_OFFSET		0x1002
++
++#define AP121_MINI_GPIO_LED_WLAN	0
++#define AP121_MINI_GPIO_BTN_JUMPSTART	12
++#define AP121_MINI_GPIO_BTN_RESET	11
+ 
+ static struct gpio_led ap121_leds_gpio[] __initdata = {
+ 	{
+@@ -58,35 +67,78 @@ static struct gpio_keys_button ap121_gpi
+ 	}
+ };
+ 
+-static struct spi_board_info ap121_spi_info[] = {
++static struct gpio_led ap121_mini_leds_gpio[] __initdata = {
+ 	{
+-		.bus_num	= 0,
+-		.chip_select	= 0,
+-		.max_speed_hz	= 25000000,
+-		.modalias	= "mx25l1606e",
+-	}
++		.name		= "ap121:green:wlan",
++		.gpio		= AP121_MINI_GPIO_LED_WLAN,
++		.active_low	= 0,
++	},
+ };
+ 
+-static struct ath79_spi_platform_data ap121_spi_data = {
+-	.bus_num	= 0,
+-	.num_chipselect = 1,
++static struct gpio_keys_button ap121_mini_gpio_keys[] __initdata = {
++	{
++		.desc		= "jumpstart button",
++		.type		= EV_KEY,
++		.code		= KEY_WPS_BUTTON,
++		.debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL,
++		.gpio		= AP121_MINI_GPIO_BTN_JUMPSTART,
++		.active_low	= 1,
++	},
++	{
++		.desc		= "reset button",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL,
++		.gpio		= AP121_MINI_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}
+ };
+ 
++static void __init ap121_common_setup(void)
++{
++	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
++
++	ath79_register_m25p80(NULL);
++	ath79_register_wmac(art + AP121_CALDATA_OFFSET,
++			    art + AP121_WMAC_MAC_OFFSET);
++
++	ath79_init_mac(ath79_eth0_data.mac_addr, art + AP121_MAC0_OFFSET, 0);
++	ath79_init_mac(ath79_eth1_data.mac_addr, art + AP121_MAC1_OFFSET, 0);
++
++	ath79_register_mdio(0, 0x0);
++
++	/* LAN ports */
++	ath79_register_eth(1);
++
++	/* WAN port */
++	ath79_register_eth(0);
++}
++
+ static void __init ap121_setup(void)
+ {
+-	u8 *cal_data = (u8 *) KSEG1ADDR(AP121_CAL_DATA_ADDR);
++	ap121_common_setup();
+ 
+ 	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap121_leds_gpio),
+ 				 ap121_leds_gpio);
+ 	ath79_register_gpio_keys_polled(-1, AP121_KEYS_POLL_INTERVAL,
+ 					ARRAY_SIZE(ap121_gpio_keys),
+ 					ap121_gpio_keys);
+-
+-	ath79_register_spi(&ap121_spi_data, ap121_spi_info,
+-			   ARRAY_SIZE(ap121_spi_info));
+ 	ath79_register_usb();
+-	ath79_register_wmac(cal_data, NULL);
+ }
+ 
+ MIPS_MACHINE(ATH79_MACH_AP121, "AP121", "Atheros AP121 reference board",
+ 	     ap121_setup);
++
++static void __init ap121_mini_setup(void)
++{
++	ap121_common_setup();
++
++	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap121_mini_leds_gpio),
++				 ap121_mini_leds_gpio);
++	ath79_register_gpio_keys_polled(-1, AP121_KEYS_POLL_INTERVAL,
++					ARRAY_SIZE(ap121_mini_gpio_keys),
++					ap121_mini_gpio_keys);
++}
++
++MIPS_MACHINE(ATH79_MACH_AP121_MINI, "AP121-MINI", "Atheros AP121-MINI",
++	     ap121_mini_setup);
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -5,9 +5,10 @@ menu "Atheros AR71XX/AR724X/AR913X machi
+ config ATH79_MACH_AP121
+ 	bool "Atheros AP121 reference board"
+ 	select SOC_AR933X
++	select ATH79_DEV_ETH
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
+-	select ATH79_DEV_SPI
++	select ATH79_DEV_M25P80
+ 	select ATH79_DEV_USB
+ 	select ATH79_DEV_WMAC
+ 	help
diff --git a/target/linux/ar71xx/patches-4.4/604-MIPS-ath79-ap81-fixes.patch b/target/linux/ar71xx/patches-4.4/604-MIPS-ath79-ap81-fixes.patch
new file mode 100644
index 0000000000..3112eab6bb
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/604-MIPS-ath79-ap81-fixes.patch
@@ -0,0 +1,84 @@
+--- a/arch/mips/ath79/mach-ap81.c
++++ b/arch/mips/ath79/mach-ap81.c
+@@ -9,12 +9,16 @@
+  *  by the Free Software Foundation.
+  */
+ 
+-#include "machtypes.h"
+-#include "dev-wmac.h"
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include "dev-eth.h"
+ #include "dev-gpio-buttons.h"
+ #include "dev-leds-gpio.h"
+-#include "dev-spi.h"
++#include "dev-m25p80.h"
+ #include "dev-usb.h"
++#include "dev-wmac.h"
++#include "machtypes.h"
+ 
+ #define AP81_GPIO_LED_STATUS	1
+ #define AP81_GPIO_LED_AOSS	3
+@@ -67,20 +71,6 @@ static struct gpio_keys_button ap81_gpio
+ 	}
+ };
+ 
+-static struct spi_board_info ap81_spi_info[] = {
+-	{
+-		.bus_num	= 0,
+-		.chip_select	= 0,
+-		.max_speed_hz	= 25000000,
+-		.modalias	= "m25p64",
+-	}
+-};
+-
+-static struct ath79_spi_platform_data ap81_spi_data = {
+-	.bus_num	= 0,
+-	.num_chipselect = 1,
+-};
+-
+ static void __init ap81_setup(void)
+ {
+ 	u8 *cal_data = (u8 *) KSEG1ADDR(AP81_CAL_DATA_ADDR);
+@@ -90,10 +80,24 @@ static void __init ap81_setup(void)
+ 	ath79_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL,
+ 					ARRAY_SIZE(ap81_gpio_keys),
+ 					ap81_gpio_keys);
+-	ath79_register_spi(&ap81_spi_data, ap81_spi_info,
+-			   ARRAY_SIZE(ap81_spi_info));
++	ath79_register_m25p80(NULL);
+ 	ath79_register_wmac(cal_data, NULL);
+ 	ath79_register_usb();
++
++	ath79_register_mdio(0, 0x0);
++
++	ath79_init_mac(ath79_eth0_data.mac_addr, cal_data, 0);
++	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ath79_eth0_data.speed = SPEED_100;
++	ath79_eth0_data.duplex = DUPLEX_FULL;
++	ath79_eth0_data.has_ar8216 = 1;
++
++	ath79_init_mac(ath79_eth1_data.mac_addr, cal_data, 1);
++	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++	ath79_eth1_data.phy_mask = 0x10;
++
++	ath79_register_eth(0);
++	ath79_register_eth(1);
+ }
+ 
+ MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board",
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -30,9 +30,10 @@ config ATH79_MACH_AP136
+ config ATH79_MACH_AP81
+ 	bool "Atheros AP81 reference board"
+ 	select SOC_AR913X
++	select ATH79_DEV_ETH
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
+-	select ATH79_DEV_SPI
++	select ATH79_DEV_M25P80
+ 	select ATH79_DEV_USB
+ 	select ATH79_DEV_WMAC
+ 	help
diff --git a/target/linux/ar71xx/patches-4.4/605-MIPS-ath79-db120-fixes.patch b/target/linux/ar71xx/patches-4.4/605-MIPS-ath79-db120-fixes.patch
new file mode 100644
index 0000000000..080165a802
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/605-MIPS-ath79-db120-fixes.patch
@@ -0,0 +1,204 @@
+--- a/arch/mips/ath79/mach-db120.c
++++ b/arch/mips/ath79/mach-db120.c
+@@ -2,7 +2,7 @@
+  * Atheros DB120 reference board support
+  *
+  * Copyright (c) 2011 Qualcomm Atheros
+- * Copyright (c) 2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (c) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+  *
+  * Permission to use, copy, modify, and/or distribute this software for any
+  * purpose with or without fee is hereby granted, provided that the above
+@@ -19,16 +19,26 @@
+  */
+ 
+ #include <linux/pci.h>
++#include <linux/phy.h>
++#include <linux/platform_device.h>
+ #include <linux/ath9k_platform.h>
++#include <linux/ar8216_platform.h>
+ 
+-#include "machtypes.h"
++#include <asm/mach-ath79/ar71xx_regs.h>
++
++#include "common.h"
++#include "dev-ap9x-pci.h"
++#include "dev-eth.h"
+ #include "dev-gpio-buttons.h"
+ #include "dev-leds-gpio.h"
++#include "dev-m25p80.h"
++#include "dev-nfc.h"
+ #include "dev-spi.h"
+ #include "dev-usb.h"
+ #include "dev-wmac.h"
+-#include "pci.h"
++#include "machtypes.h"
+ 
++#define DB120_GPIO_LED_USB		11
+ #define DB120_GPIO_LED_WLAN_5G		12
+ #define DB120_GPIO_LED_WLAN_2G		13
+ #define DB120_GPIO_LED_STATUS		14
+@@ -39,8 +49,10 @@
+ #define DB120_KEYS_POLL_INTERVAL	20	/* msecs */
+ #define DB120_KEYS_DEBOUNCE_INTERVAL	(3 * DB120_KEYS_POLL_INTERVAL)
+ 
+-#define DB120_WMAC_CALDATA_OFFSET 0x1000
+-#define DB120_PCIE_CALDATA_OFFSET 0x5000
++#define DB120_MAC0_OFFSET		0
++#define DB120_MAC1_OFFSET		6
++#define DB120_WMAC_CALDATA_OFFSET	0x1000
++#define DB120_PCIE_CALDATA_OFFSET	0x5000
+ 
+ static struct gpio_led db120_leds_gpio[] __initdata = {
+ 	{
+@@ -63,6 +75,11 @@ static struct gpio_led db120_leds_gpio[]
+ 		.gpio		= DB120_GPIO_LED_WLAN_2G,
+ 		.active_low	= 1,
+ 	},
++	{
++		.name		= "db120:green:usb",
++		.gpio		= DB120_GPIO_LED_USB,
++		.active_low	= 1,
++	}
+ };
+ 
+ static struct gpio_keys_button db120_gpio_keys[] __initdata = {
+@@ -76,60 +93,85 @@ static struct gpio_keys_button db120_gpi
+ 	},
+ };
+ 
+-static struct spi_board_info db120_spi_info[] = {
+-	{
+-		.bus_num	= 0,
+-		.chip_select	= 0,
+-		.max_speed_hz	= 25000000,
+-		.modalias	= "s25sl064a",
+-	}
++static struct ar8327_pad_cfg db120_ar8327_pad0_cfg = {
++	.mode = AR8327_PAD_MAC_RGMII,
++	.txclk_delay_en = true,
++	.rxclk_delay_en = true,
++	.txclk_delay_sel = AR8327_CLK_DELAY_SEL1,
++	.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2,
+ };
+ 
+-static struct ath79_spi_platform_data db120_spi_data = {
+-	.bus_num	= 0,
+-	.num_chipselect = 1,
++static struct ar8327_led_cfg db120_ar8327_led_cfg = {
++	.led_ctrl0 = 0x00000000,
++	.led_ctrl1 = 0xc737c737,
++	.led_ctrl2 = 0x00000000,
++	.led_ctrl3 = 0x00c30c00,
++	.open_drain = true,
+ };
+ 
+-#ifdef CONFIG_PCI
+-static struct ath9k_platform_data db120_ath9k_data;
+-
+-static int db120_pci_plat_dev_init(struct pci_dev *dev)
+-{
+-	switch (PCI_SLOT(dev->devfn)) {
+-	case 0:
+-		dev->dev.platform_data = &db120_ath9k_data;
+-		break;
+-	}
+-
+-	return 0;
+-}
+-
+-static void __init db120_pci_init(u8 *eeprom)
+-{
+-	memcpy(db120_ath9k_data.eeprom_data, eeprom,
+-	       sizeof(db120_ath9k_data.eeprom_data));
++static struct ar8327_platform_data db120_ar8327_data = {
++	.pad0_cfg = &db120_ar8327_pad0_cfg,
++	.port0_cfg = {
++		.force_link = 1,
++		.speed = AR8327_PORT_SPEED_1000,
++		.duplex = 1,
++		.txpause = 1,
++		.rxpause = 1,
++	},
++	.led_cfg = &db120_ar8327_led_cfg,
++};
+ 
+-	ath79_pci_set_plat_dev_init(db120_pci_plat_dev_init);
+-	ath79_register_pci();
+-}
+-#else
+-static inline void db120_pci_init(u8 *eeprom) {}
+-#endif /* CONFIG_PCI */
++static struct mdio_board_info db120_mdio0_info[] = {
++	{
++		.bus_id = "ag71xx-mdio.0",
++		.phy_addr = 0,
++		.platform_data = &db120_ar8327_data,
++	},
++};
+ 
+ static void __init db120_setup(void)
+ {
+ 	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+ 
++	ath79_gpio_output_select(DB120_GPIO_LED_USB, AR934X_GPIO_OUT_GPIO);
++	ath79_register_m25p80(NULL);
++
+ 	ath79_register_leds_gpio(-1, ARRAY_SIZE(db120_leds_gpio),
+ 				 db120_leds_gpio);
+ 	ath79_register_gpio_keys_polled(-1, DB120_KEYS_POLL_INTERVAL,
+ 					ARRAY_SIZE(db120_gpio_keys),
+ 					db120_gpio_keys);
+-	ath79_register_spi(&db120_spi_data, db120_spi_info,
+-			   ARRAY_SIZE(db120_spi_info));
+ 	ath79_register_usb();
+ 	ath79_register_wmac(art + DB120_WMAC_CALDATA_OFFSET, NULL);
+-	db120_pci_init(art + DB120_PCIE_CALDATA_OFFSET);
++	ap91_pci_init(art + DB120_PCIE_CALDATA_OFFSET, NULL);
++
++	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_RGMII_GMAC0 |
++				   AR934X_ETH_CFG_SW_ONLY_MODE);
++
++	ath79_register_mdio(1, 0x0);
++	ath79_register_mdio(0, 0x0);
++
++	ath79_init_mac(ath79_eth0_data.mac_addr, art + DB120_MAC0_OFFSET, 0);
++
++	mdiobus_register_board_info(db120_mdio0_info,
++				    ARRAY_SIZE(db120_mdio0_info));
++
++	/* GMAC0 is connected to an AR8327 switch */
++	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ath79_eth0_data.phy_mask = BIT(0);
++	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
++	ath79_eth0_pll_data.pll_1000 = 0x06000000;
++	ath79_register_eth(0);
++
++	/* GMAC1 is connected to the internal switch */
++	ath79_init_mac(ath79_eth1_data.mac_addr, art + DB120_MAC1_OFFSET, 0);
++	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
++	ath79_eth1_data.speed = SPEED_1000;
++	ath79_eth1_data.duplex = DUPLEX_FULL;
++
++	ath79_register_eth(1);
++
++	ath79_register_nfc();
+ }
+ 
+ MIPS_MACHINE(ATH79_MACH_DB120, "DB120", "Atheros DB120 reference board",
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -43,9 +43,12 @@ config ATH79_MACH_AP81
+ config ATH79_MACH_DB120
+ 	bool "Atheros DB120 reference board"
+ 	select SOC_AR934X
++	select ATH79_DEV_AP9X_PCI if PCI
++	select ATH79_DEV_ETH
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
+-	select ATH79_DEV_SPI
++	select ATH79_DEV_M25P80
++	select ATH79_DEV_NFC
+ 	select ATH79_DEV_USB
+ 	select ATH79_DEV_WMAC
+ 	help
diff --git a/target/linux/ar71xx/patches-4.4/606-MIPS-ath79-pb44-fixes.patch b/target/linux/ar71xx/patches-4.4/606-MIPS-ath79-pb44-fixes.patch
new file mode 100644
index 0000000000..f9ec7753f1
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/606-MIPS-ath79-pb44-fixes.patch
@@ -0,0 +1,153 @@
+--- a/arch/mips/ath79/mach-pb44.c
++++ b/arch/mips/ath79/mach-pb44.c
+@@ -8,23 +8,48 @@
+  *  by the Free Software Foundation.
+  */
+ 
++#include <linux/delay.h>
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-gpio.h>
+ #include <linux/i2c/pcf857x.h>
++#include <linux/i2c/pcf857x.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/vsc7385.h>
+ 
+-#include "machtypes.h"
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <asm/mach-ath79/ath79.h>
++
++#include "dev-eth.h"
+ #include "dev-gpio-buttons.h"
+ #include "dev-leds-gpio.h"
+ #include "dev-spi.h"
+ #include "dev-usb.h"
++#include "machtypes.h"
+ #include "pci.h"
+ 
+ #define PB44_GPIO_I2C_SCL	0
+ #define PB44_GPIO_I2C_SDA	1
+ 
++#define PB44_PCF8757_VSC7395_CS	0
++#define PB44_PCF8757_STEREO_CS	1
++#define PB44_PCF8757_SLIC_CS0	2
++#define PB44_PCF8757_SLIC_TEST	3
++#define PB44_PCF8757_SLIC_INT0	4
++#define PB44_PCF8757_SLIC_INT1	5
++#define PB44_PCF8757_SW_RESET	6
++#define PB44_PCF8757_SW_JUMP	8
++#define PB44_PCF8757_LED_JUMP1	9
++#define PB44_PCF8757_LED_JUMP2	10
++#define PB44_PCF8757_TP24	11
++#define PB44_PCF8757_TP25	12
++#define PB44_PCF8757_TP26	13
++#define PB44_PCF8757_TP27	14
++#define PB44_PCF8757_TP28	15
++
+ #define PB44_GPIO_EXP_BASE	16
++#define PB44_GPIO_VSC7395_CS	(PB44_GPIO_EXP_BASE + PB44_PCF8757_VSC7395_CS)
+ #define PB44_GPIO_SW_RESET	(PB44_GPIO_EXP_BASE + 6)
+ #define PB44_GPIO_SW_JUMP	(PB44_GPIO_EXP_BASE + 8)
+ #define PB44_GPIO_LED_JUMP1	(PB44_GPIO_EXP_BASE + 9)
+@@ -92,21 +117,66 @@ static struct ath79_spi_controller_data
+ 	.cs_line = 0,
+ };
+ 
++static struct ath79_spi_controller_data pb44_spi1_data = {
++	.cs_type = ATH79_SPI_CS_TYPE_GPIO,
++	.cs_line = PB44_GPIO_VSC7395_CS,
++};
++
++static void pb44_vsc7395_reset(void)
++{
++	ath79_device_reset_set(AR71XX_RESET_GE1_PHY);
++	udelay(10);
++	ath79_device_reset_clear(AR71XX_RESET_GE1_PHY);
++	mdelay(50);
++}
++
++static struct vsc7385_platform_data pb44_vsc7395_data = {
++	.reset		= pb44_vsc7395_reset,
++	.ucode_name	= "vsc7395_ucode_pb44.bin",
++	.mac_cfg = {
++		.tx_ipg		= 6,
++		.bit2		= 1,
++		.clk_sel	= 0,
++	},
++};
++
++static const char *pb44_part_probes[] = {
++	"RedBoot",
++	NULL,
++};
++
++static struct flash_platform_data pb44_flash_data = {
++	.part_probes	= pb44_part_probes,
++};
++
+ static struct spi_board_info pb44_spi_info[] = {
+ 	{
+ 		.bus_num	= 0,
+ 		.chip_select	= 0,
+ 		.max_speed_hz	= 25000000,
+ 		.modalias	= "m25p64",
++		.platform_data	= &pb44_flash_data,
+ 		.controller_data = &pb44_spi0_data,
+ 	},
++	{
++		.bus_num	= 0,
++		.chip_select	= 1,
++		.max_speed_hz	= 25000000,
++		.modalias	= "spi-vsc7385",
++		.platform_data	= &pb44_vsc7395_data,
++		.controller_data = &pb44_spi1_data,
++	}
+ };
+ 
+ static struct ath79_spi_platform_data pb44_spi_data = {
+ 	.bus_num		= 0,
+-	.num_chipselect		= 1,
++	.num_chipselect		= 2,
+ };
+ 
++#define PB44_WAN_PHYMASK	BIT(0)
++#define PB44_LAN_PHYMASK	0
++#define PB44_MDIO_PHYMASK	(PB44_LAN_PHYMASK | PB44_WAN_PHYMASK)
++
+ static void __init pb44_init(void)
+ {
+ 	i2c_register_board_info(0, pb44_i2c_board_info,
+@@ -122,6 +192,22 @@ static void __init pb44_init(void)
+ 			   ARRAY_SIZE(pb44_spi_info));
+ 	ath79_register_usb();
+ 	ath79_register_pci();
++
++	ath79_register_mdio(0, ~PB44_MDIO_PHYMASK);
++
++	ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
++	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ath79_eth0_data.phy_mask = PB44_WAN_PHYMASK;
++
++	ath79_register_eth(0);
++
++	ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
++	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ath79_eth1_data.speed = SPEED_1000;
++	ath79_eth1_data.duplex = DUPLEX_FULL;
++	ath79_eth1_pll_data.pll_1000 = 0x110000;
++
++	ath79_register_eth(1);
+ }
+ 
+ MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board",
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -58,6 +58,7 @@ config ATH79_MACH_DB120
+ config ATH79_MACH_PB44
+ 	bool "Atheros PB44 reference board"
+ 	select SOC_AR71XX
++	select ATH79_DEV_ETH
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
+ 	select ATH79_DEV_SPI
diff --git a/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch b/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch
new file mode 100644
index 0000000000..4699c82746
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/607-MIPS-ath79-ubnt-xm-fixes.patch
@@ -0,0 +1,14 @@
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -70,9 +70,10 @@ config ATH79_MACH_PB44
+ config ATH79_MACH_UBNT_XM
+ 	bool "Ubiquiti Networks XM (rev 1.0) board"
+ 	select SOC_AR724X
++	select ATH79_DEV_AP9X_PCI if PCI
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
+-	select ATH79_DEV_SPI
++	select ATH79_DEV_M25P80
+ 	help
+ 	  Say 'Y' here if you want your kernel to support the
+ 	  Ubiquiti Networks XM (rev 1.0) board.
diff --git a/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch b/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch
new file mode 100644
index 0000000000..b33db4dd0d
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/608-MIPS-ath79-ubnt-xm-add-more-boards.patch
@@ -0,0 +1,20 @@
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -68,12 +68,16 @@ config ATH79_MACH_PB44
+ 	  Atheros PB44 reference board.
+ 
+ config ATH79_MACH_UBNT_XM
+-	bool "Ubiquiti Networks XM (rev 1.0) board"
++	bool "Ubiquiti Networks XM/UniFi boards"
+ 	select SOC_AR724X
++	select SOC_AR934X
+ 	select ATH79_DEV_AP9X_PCI if PCI
++	select ATH79_DEV_ETH
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
+ 	select ATH79_DEV_M25P80
++	select ATH79_DEV_USB
++	select ATH79_DEV_WMAC
+ 	help
+ 	  Say 'Y' here if you want your kernel to support the
+ 	  Ubiquiti Networks XM (rev 1.0) board.
diff --git a/target/linux/ar71xx/patches-4.4/609-MIPS-ath79-ap136-fixes.patch b/target/linux/ar71xx/patches-4.4/609-MIPS-ath79-ap136-fixes.patch
new file mode 100644
index 0000000000..4d7902e166
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/609-MIPS-ath79-ap136-fixes.patch
@@ -0,0 +1,300 @@
+--- a/arch/mips/ath79/mach-ap136.c
++++ b/arch/mips/ath79/mach-ap136.c
+@@ -18,23 +18,29 @@
+  *
+  */
+ 
+-#include <linux/pci.h>
+-#include <linux/ath9k_platform.h>
++#include <linux/platform_device.h>
++#include <linux/ar8216_platform.h>
+ 
+-#include "machtypes.h"
++#include <asm/mach-ath79/ar71xx_regs.h>
++
++#include "common.h"
++#include "pci.h"
++#include "dev-ap9x-pci.h"
+ #include "dev-gpio-buttons.h"
++#include "dev-eth.h"
+ #include "dev-leds-gpio.h"
+-#include "dev-spi.h"
++#include "dev-m25p80.h"
++#include "dev-nfc.h"
+ #include "dev-usb.h"
+ #include "dev-wmac.h"
+-#include "pci.h"
++#include "machtypes.h"
+ 
+-#define AP136_GPIO_LED_STATUS_RED	14
+-#define AP136_GPIO_LED_STATUS_GREEN	19
+ #define AP136_GPIO_LED_USB		4
+-#define AP136_GPIO_LED_WLAN_2G		13
+ #define AP136_GPIO_LED_WLAN_5G		12
++#define AP136_GPIO_LED_WLAN_2G		13
++#define AP136_GPIO_LED_STATUS_RED	14
+ #define AP136_GPIO_LED_WPS_RED		15
++#define AP136_GPIO_LED_STATUS_GREEN	19
+ #define AP136_GPIO_LED_WPS_GREEN	20
+ 
+ #define AP136_GPIO_BTN_WPS		16
+@@ -43,37 +49,39 @@
+ #define AP136_KEYS_POLL_INTERVAL	20	/* msecs */
+ #define AP136_KEYS_DEBOUNCE_INTERVAL	(3 * AP136_KEYS_POLL_INTERVAL)
+ 
+-#define AP136_WMAC_CALDATA_OFFSET 0x1000
+-#define AP136_PCIE_CALDATA_OFFSET 0x5000
++#define AP136_MAC0_OFFSET		0
++#define AP136_MAC1_OFFSET		6
++#define AP136_WMAC_CALDATA_OFFSET	0x1000
++#define AP136_PCIE_CALDATA_OFFSET	0x5000
+ 
+ static struct gpio_led ap136_leds_gpio[] __initdata = {
+ 	{
+-		.name		= "qca:green:status",
++		.name		= "ap136:green:status",
+ 		.gpio		= AP136_GPIO_LED_STATUS_GREEN,
+ 		.active_low	= 1,
+ 	},
+ 	{
+-		.name		= "qca:red:status",
++		.name		= "ap136:red:status",
+ 		.gpio		= AP136_GPIO_LED_STATUS_RED,
+ 		.active_low	= 1,
+ 	},
+ 	{
+-		.name		= "qca:green:wps",
++		.name		= "ap136:green:wps",
+ 		.gpio		= AP136_GPIO_LED_WPS_GREEN,
+ 		.active_low	= 1,
+ 	},
+ 	{
+-		.name		= "qca:red:wps",
++		.name		= "ap136:red:wps",
+ 		.gpio		= AP136_GPIO_LED_WPS_RED,
+ 		.active_low	= 1,
+ 	},
+ 	{
+-		.name		= "qca:red:wlan-2g",
++		.name		= "ap136:red:wlan-2g",
+ 		.gpio		= AP136_GPIO_LED_WLAN_2G,
+ 		.active_low	= 1,
+ 	},
+ 	{
+-		.name		= "qca:red:usb",
++		.name		= "ap136:red:usb",
+ 		.gpio		= AP136_GPIO_LED_USB,
+ 		.active_low	= 1,
+ 	}
+@@ -98,59 +106,151 @@ static struct gpio_keys_button ap136_gpi
+ 	},
+ };
+ 
+-static struct spi_board_info ap136_spi_info[] = {
+-	{
+-		.bus_num	= 0,
+-		.chip_select	= 0,
+-		.max_speed_hz	= 25000000,
+-		.modalias	= "mx25l6405d",
+-	}
++static struct ar8327_pad_cfg ap136_ar8327_pad0_cfg;
++static struct ar8327_pad_cfg ap136_ar8327_pad6_cfg;
++
++static struct ar8327_platform_data ap136_ar8327_data = {
++	.pad0_cfg = &ap136_ar8327_pad0_cfg,
++	.pad6_cfg = &ap136_ar8327_pad6_cfg,
++	.port0_cfg = {
++		.force_link = 1,
++		.speed = AR8327_PORT_SPEED_1000,
++		.duplex = 1,
++		.txpause = 1,
++		.rxpause = 1,
++	},
++	.port6_cfg = {
++		.force_link = 1,
++		.speed = AR8327_PORT_SPEED_1000,
++		.duplex = 1,
++		.txpause = 1,
++		.rxpause = 1,
++	},
+ };
+ 
+-static struct ath79_spi_platform_data ap136_spi_data = {
+-	.bus_num	= 0,
+-	.num_chipselect	= 1,
++static struct mdio_board_info ap136_mdio0_info[] = {
++	{
++		.bus_id = "ag71xx-mdio.0",
++		.phy_addr = 0,
++		.platform_data = &ap136_ar8327_data,
++	},
+ };
+ 
+-#ifdef CONFIG_PCI
+-static struct ath9k_platform_data ap136_ath9k_data;
++static void __init ap136_common_setup(void)
++{
++	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
++
++	ath79_register_m25p80(NULL);
++
++	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap136_leds_gpio),
++				 ap136_leds_gpio);
++	ath79_register_gpio_keys_polled(-1, AP136_KEYS_POLL_INTERVAL,
++					ARRAY_SIZE(ap136_gpio_keys),
++					ap136_gpio_keys);
++
++	ath79_register_usb();
++	ath79_register_nfc();
++
++	ath79_register_wmac(art + AP136_WMAC_CALDATA_OFFSET, NULL);
++
++	ath79_setup_qca955x_eth_cfg(QCA955X_ETH_CFG_RGMII_EN);
+ 
+-static int ap136_pci_plat_dev_init(struct pci_dev *dev)
++	ath79_register_mdio(0, 0x0);
++	ath79_init_mac(ath79_eth0_data.mac_addr, art + AP136_MAC0_OFFSET, 0);
++
++	mdiobus_register_board_info(ap136_mdio0_info,
++				    ARRAY_SIZE(ap136_mdio0_info));
++
++	/* GMAC0 is connected to the RMGII interface */
++	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++	ath79_eth0_data.phy_mask = BIT(0);
++	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
++
++	ath79_register_eth(0);
++
++	/* GMAC1 is connected tot eh SGMII interface */
++	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_SGMII;
++	ath79_eth1_data.speed = SPEED_1000;
++	ath79_eth1_data.duplex = DUPLEX_FULL;
++
++	ath79_register_eth(1);
++}
++
++static void __init ap136_010_setup(void)
+ {
+-	if (dev->bus->number == 1 && (PCI_SLOT(dev->devfn)) == 0)
+-		dev->dev.platform_data = &ap136_ath9k_data;
++	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+ 
+-	return 0;
++	/* GMAC0 of the AR8327 switch is connected to GMAC0 via RGMII */
++	ap136_ar8327_pad0_cfg.mode = AR8327_PAD_MAC_RGMII;
++	ap136_ar8327_pad0_cfg.txclk_delay_en = true;
++	ap136_ar8327_pad0_cfg.rxclk_delay_en = true;
++	ap136_ar8327_pad0_cfg.txclk_delay_sel = AR8327_CLK_DELAY_SEL1;
++	ap136_ar8327_pad0_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2;
++
++	/* GMAC6 of the AR8327 switch is connected to GMAC1 via SGMII */
++	ap136_ar8327_pad6_cfg.mode = AR8327_PAD_MAC_SGMII;
++	ap136_ar8327_pad6_cfg.rxclk_delay_en = true;
++	ap136_ar8327_pad6_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL0;
++
++	ath79_eth0_pll_data.pll_1000 = 0xa6000000;
++	ath79_eth1_pll_data.pll_1000 = 0x03000101;
++
++	ap136_common_setup();
++	ap91_pci_init(art + AP136_PCIE_CALDATA_OFFSET, NULL);
+ }
+ 
+-static void __init ap136_pci_init(u8 *eeprom)
++MIPS_MACHINE(ATH79_MACH_AP136_010, "AP136-010",
++	     "Atheros AP136-010 reference board",
++	     ap136_010_setup);
++
++static void __init ap136_020_common_setup(void)
+ {
+-	memcpy(ap136_ath9k_data.eeprom_data, eeprom,
+-	       sizeof(ap136_ath9k_data.eeprom_data));
++	/* GMAC0 of the AR8327 switch is connected to GMAC1 via SGMII */
++	ap136_ar8327_pad0_cfg.mode = AR8327_PAD_MAC_SGMII;
++	ap136_ar8327_pad0_cfg.sgmii_delay_en = true;
++
++	/* GMAC6 of the AR8327 switch is connected to GMAC0 via RGMII */
++	ap136_ar8327_pad6_cfg.mode = AR8327_PAD_MAC_RGMII;
++	ap136_ar8327_pad6_cfg.txclk_delay_en = true;
++	ap136_ar8327_pad6_cfg.rxclk_delay_en = true;
++	ap136_ar8327_pad6_cfg.txclk_delay_sel = AR8327_CLK_DELAY_SEL1;
++	ap136_ar8327_pad6_cfg.rxclk_delay_sel = AR8327_CLK_DELAY_SEL2;
+ 
+-	ath79_pci_set_plat_dev_init(ap136_pci_plat_dev_init);
+-	ath79_register_pci();
++	ath79_eth0_pll_data.pll_1000 = 0x56000000;
++	ath79_eth1_pll_data.pll_1000 = 0x03000101;
++
++	ap136_common_setup();
+ }
+-#else
+-static inline void ap136_pci_init(u8 *eeprom) {}
+-#endif /* CONFIG_PCI */
+ 
+-static void __init ap136_setup(void)
++static void __init ap136_020_setup(void)
+ {
+ 	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+ 
+-	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap136_leds_gpio),
+-				 ap136_leds_gpio);
+-	ath79_register_gpio_keys_polled(-1, AP136_KEYS_POLL_INTERVAL,
+-					ARRAY_SIZE(ap136_gpio_keys),
+-					ap136_gpio_keys);
+-	ath79_register_spi(&ap136_spi_data, ap136_spi_info,
+-			   ARRAY_SIZE(ap136_spi_info));
+-	ath79_register_usb();
+-	ath79_register_wmac(art + AP136_WMAC_CALDATA_OFFSET);
+-	ap136_pci_init(art + AP136_PCIE_CALDATA_OFFSET);
++	ap136_020_common_setup();
++	ap91_pci_init(art + AP136_PCIE_CALDATA_OFFSET, NULL);
+ }
+ 
+-MIPS_MACHINE(ATH79_MACH_AP136_010, "AP136-010",
+-	     "Atheros AP136-010 reference board",
+-	     ap136_setup);
++MIPS_MACHINE(ATH79_MACH_AP136_020, "AP136-020",
++	     "Atheros AP136-020 reference board",
++	     ap136_020_setup);
++
++/*
++ * AP135-020 is similar to AP136-020, any future AP135 specific init
++ * code can be added here.
++ */
++static void __init ap135_020_setup(void)
++{
++	ap136_leds_gpio[0].name = "ap135:green:status";
++	ap136_leds_gpio[1].name = "ap135:red:status";
++	ap136_leds_gpio[2].name = "ap135:green:wps";
++	ap136_leds_gpio[3].name = "ap135:red:wps";
++	ap136_leds_gpio[4].name = "ap135:red:wlan-2g";
++	ap136_leds_gpio[5].name = "ap135:red:usb";
++
++	ap136_020_common_setup();
++	ath79_register_pci();
++}
++
++MIPS_MACHINE(ATH79_MACH_AP135_020, "AP135-020",
++	     "Atheros AP135-020 reference board",
++	     ap135_020_setup);
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -16,16 +16,17 @@ config ATH79_MACH_AP121
+ 	  Atheros AP121 reference board.
+ 
+ config ATH79_MACH_AP136
+-	bool "Atheros AP136 reference board"
++	bool "Atheros AP136/AP135 reference board"
+ 	select SOC_QCA955X
+ 	select ATH79_DEV_GPIO_BUTTONS
+ 	select ATH79_DEV_LEDS_GPIO
++	select ATH79_DEV_NFC
+ 	select ATH79_DEV_SPI
+ 	select ATH79_DEV_USB
+ 	select ATH79_DEV_WMAC
+ 	help
+ 	  Say 'Y' here if you want your kernel to support the
+-	  Atheros AP136 reference board.
++	  Atheros AP136 or AP135 reference boards.
+ 
+ config ATH79_MACH_AP81
+ 	bool "Atheros AP81 reference board"
diff --git a/target/linux/ar71xx/patches-4.4/611-MIPS-ath79-wdt-timeout.patch b/target/linux/ar71xx/patches-4.4/611-MIPS-ath79-wdt-timeout.patch
new file mode 100644
index 0000000000..7a70ac3f87
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/611-MIPS-ath79-wdt-timeout.patch
@@ -0,0 +1,25 @@
+MIPS: ath79: fix maximum timeout
+
+If the userland tries to set a timeout higher than the max_timeout, then we should fallback to max_timeout.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+
+--- a/drivers/watchdog/ath79_wdt.c
++++ b/drivers/watchdog/ath79_wdt.c
+@@ -114,10 +114,14 @@ static inline void ath79_wdt_disable(voi
+ 
+ static int ath79_wdt_set_timeout(int val)
+ {
+-	if (val < 1 || val > max_timeout)
++	if (val < 1)
+ 		return -EINVAL;
+ 
+-	timeout = val;
++	if (val > max_timeout)
++		timeout = max_timeout;
++	else
++		timeout = val;
++
+ 	ath79_wdt_keepalive();
+ 
+ 	return 0;
diff --git a/target/linux/ar71xx/patches-4.4/612-MIPS-ath79-set-buffalo-txgain.patch b/target/linux/ar71xx/patches-4.4/612-MIPS-ath79-set-buffalo-txgain.patch
new file mode 100644
index 0000000000..4e3ac70f59
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/612-MIPS-ath79-set-buffalo-txgain.patch
@@ -0,0 +1,24 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -308,6 +308,11 @@ void __init ath79_wmac_disable_5ghz(void
+ 	ath79_wmac_data.disable_5ghz = true;
+ }
+ 
++void __init ath79_wmac_set_tx_gain_buffalo(void)
++{
++	ath79_wmac_data.tx_gain_buffalo = true;
++}
++
+ void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+ 	if (soc_is_ar913x())
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -16,6 +16,7 @@ void ath79_register_wmac(u8 *cal_data, u
+ void ath79_register_wmac_simple(void);
+ void ath79_wmac_disable_2ghz(void);
+ void ath79_wmac_disable_5ghz(void);
++void ath79_wmac_set_tx_gain_buffalo(void);
+ 
+ bool ar93xx_wmac_read_mac_address(u8 *dest);
+ 
diff --git a/target/linux/ar71xx/patches-4.4/613-MIPS-ath79-add-ath79_wmac_setup_ext_lna_gpio-helper.patch b/target/linux/ar71xx/patches-4.4/613-MIPS-ath79-add-ath79_wmac_setup_ext_lna_gpio-helper.patch
new file mode 100644
index 0000000000..e8bbe44002
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/613-MIPS-ath79-add-ath79_wmac_setup_ext_lna_gpio-helper.patch
@@ -0,0 +1,76 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -18,9 +18,11 @@
+ #include <linux/etherdevice.h>
+ #include <linux/platform_device.h>
+ #include <linux/ath9k_platform.h>
++#include <linux/gpio.h>
+ 
+ #include <asm/mach-ath79/ath79.h>
+ #include <asm/mach-ath79/ar71xx_regs.h>
++#include "common.h"
+ #include "dev-wmac.h"
+ 
+ static u8 ath79_wmac_mac[ETH_ALEN];
+@@ -313,6 +315,51 @@ void __init ath79_wmac_set_tx_gain_buffa
+ 	ath79_wmac_data.tx_gain_buffalo = true;
+ }
+ 
++static int ath79_request_ext_lna_gpio(unsigned chain, int gpio)
++{
++	char *label;
++	int err;
++
++	label = kasprintf(GFP_KERNEL, "external LNA%u", chain);
++	if (!label)
++		return -ENOMEM;
++
++	err = gpio_request_one(gpio, GPIOF_DIR_OUT | GPIOF_INIT_LOW, label);
++	if (err) {
++		pr_err("unable to request GPIO%d for external LNA%u\n",
++			gpio, chain);
++		kfree(label);
++	}
++
++	return err;
++}
++
++static void ar934x_set_ext_lna_gpio(unsigned chain, int gpio)
++{
++	unsigned int sel;
++	int err;
++
++	if (WARN_ON(chain > 1))
++		return;
++
++	err = ath79_request_ext_lna_gpio(chain, gpio);
++	if (err)
++		return;
++
++	if (chain == 0)
++		sel = AR934X_GPIO_OUT_EXT_LNA0;
++	else
++		sel = AR934X_GPIO_OUT_EXT_LNA1;
++
++	ath79_gpio_output_select(gpio, sel);
++}
++
++void __init ath79_wmac_set_ext_lna_gpio(unsigned chain, int gpio)
++{
++	if (soc_is_ar934x())
++		ar934x_set_ext_lna_gpio(chain, gpio);
++}
++
+ void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+ 	if (soc_is_ar913x())
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -17,6 +17,7 @@ void ath79_register_wmac_simple(void);
+ void ath79_wmac_disable_2ghz(void);
+ void ath79_wmac_disable_5ghz(void);
+ void ath79_wmac_set_tx_gain_buffalo(void);
++void ath79_wmac_set_ext_lna_gpio(unsigned chain, int gpio);
+ 
+ bool ar93xx_wmac_read_mac_address(u8 *dest);
+ 
diff --git a/target/linux/ar71xx/patches-4.4/615-MIPS-ath79-ap83-remove-mtd-partitions.patch b/target/linux/ar71xx/patches-4.4/615-MIPS-ath79-ap83-remove-mtd-partitions.patch
new file mode 100644
index 0000000000..60872ae0a6
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/615-MIPS-ath79-ap83-remove-mtd-partitions.patch
@@ -0,0 +1,44 @@
+--- a/arch/mips/ath79/mach-ap83.c
++++ b/arch/mips/ath79/mach-ap83.c
+@@ -42,41 +42,8 @@
+ #define AP83_KEYS_POLL_INTERVAL		20	/* msecs */
+ #define AP83_KEYS_DEBOUNCE_INTERVAL	(3 * AP83_KEYS_POLL_INTERVAL)
+ 
+-static struct mtd_partition ap83_flash_partitions[] = {
+-	{
+-		.name		= "u-boot",
+-		.offset		= 0,
+-		.size		= 0x040000,
+-		.mask_flags	= MTD_WRITEABLE,
+-	}, {
+-		.name		= "u-boot-env",
+-		.offset		= 0x040000,
+-		.size		= 0x020000,
+-		.mask_flags	= MTD_WRITEABLE,
+-	}, {
+-		.name		= "kernel",
+-		.offset		= 0x060000,
+-		.size		= 0x140000,
+-	}, {
+-		.name		= "rootfs",
+-		.offset		= 0x1a0000,
+-		.size		= 0x650000,
+-	}, {
+-		.name		= "art",
+-		.offset		= 0x7f0000,
+-		.size		= 0x010000,
+-		.mask_flags	= MTD_WRITEABLE,
+-	}, {
+-		.name		= "firmware",
+-		.offset		= 0x060000,
+-		.size		= 0x790000,
+-	}
+-};
+-
+ static struct physmap_flash_data ap83_flash_data = {
+ 	.width		= 2,
+-	.parts		= ap83_flash_partitions,
+-	.nr_parts	= ARRAY_SIZE(ap83_flash_partitions),
+ };
+ 
+ static struct resource ap83_flash_resources[] = {
diff --git a/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch b/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch
new file mode 100644
index 0000000000..08a684becd
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/620-MIPS-ath79-add-support-for-QCA953x-SoC.patch
@@ -0,0 +1,705 @@
+From 5300a7cd7ed2f88488ddba62947b9c6bb9663777 Mon Sep 17 00:00:00 2001
+Message-Id: <5300a7cd7ed2f88488ddba62947b9c6bb9663777.1396122227.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 29 Mar 2014 20:26:08 +0100
+Subject: [PATCH 1/2] MIPS: ath79: add support for QCA953x SoC
+
+Note that the clock calculation looks very similar to the QCA955x, but the
+meaning of the bits CPUCLK_FROM_CPUPLL and DDRCLK_FROM_DDRPLL is reversed.
+---
+ arch/mips/ath79/Kconfig                        |  6 +-
+ arch/mips/ath79/clock.c                        | 78 ++++++++++++++++++++++++++
+ arch/mips/ath79/common.c                       |  4 ++
+ arch/mips/ath79/dev-common.c                   |  1 +
+ arch/mips/ath79/dev-wmac.c                     | 20 +++++++
+ arch/mips/ath79/early_printk.c                 |  1 +
+ arch/mips/ath79/gpio.c                         |  4 +-
+ arch/mips/ath79/irq.c                          |  4 ++
+ arch/mips/ath79/setup.c                        |  8 ++-
+ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 48 ++++++++++++++++
+ arch/mips/include/asm/mach-ath79/ath79.h       | 11 ++++
+ 11 files changed, 182 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -117,6 +117,10 @@ config SOC_AR934X
+ 	select PCI_AR724X if PCI
+ 	def_bool n
+ 
++config SOC_QCA953X
++	select USB_ARCH_HAS_EHCI
++	def_bool n
++
+ config SOC_QCA955X
+ 	select HW_HAS_PCI
+ 	select PCI_AR724X if PCI
+@@ -156,7 +160,7 @@ config ATH79_DEV_USB
+ 	def_bool n
+ 
+ config ATH79_DEV_WMAC
+-	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X)
++	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA953X || SOC_QCA955X)
+ 	def_bool n
+ 
+ config ATH79_NVRAM
+--- a/arch/mips/ath79/clock.c
++++ b/arch/mips/ath79/clock.c
+@@ -354,6 +354,91 @@ static void __init ar934x_clocks_init(vo
+ 	iounmap(dpll_base);
+ }
+ 
++static void __init qca953x_clocks_init(void)
++{
++	unsigned long ref_rate;
++	unsigned long cpu_rate;
++	unsigned long ddr_rate;
++	unsigned long ahb_rate;
++	u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
++	u32 cpu_pll, ddr_pll;
++	u32 bootstrap;
++
++	bootstrap = ath79_reset_rr(QCA953X_RESET_REG_BOOTSTRAP);
++	if (bootstrap &	QCA953X_BOOTSTRAP_REF_CLK_40)
++		ref_rate = 40 * 1000 * 1000;
++	else
++		ref_rate = 25 * 1000 * 1000;
++
++	pll = ath79_pll_rr(QCA953X_PLL_CPU_CONFIG_REG);
++	out_div = (pll >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
++		  QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK;
++	ref_div = (pll >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
++		  QCA953X_PLL_CPU_CONFIG_REFDIV_MASK;
++	nint = (pll >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT) &
++	       QCA953X_PLL_CPU_CONFIG_NINT_MASK;
++	frac = (pll >> QCA953X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
++	       QCA953X_PLL_CPU_CONFIG_NFRAC_MASK;
++
++	cpu_pll = nint * ref_rate / ref_div;
++	cpu_pll += frac * (ref_rate >> 6) / ref_div;
++	cpu_pll /= (1 << out_div);
++
++	pll = ath79_pll_rr(QCA953X_PLL_DDR_CONFIG_REG);
++	out_div = (pll >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
++		  QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK;
++	ref_div = (pll >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
++		  QCA953X_PLL_DDR_CONFIG_REFDIV_MASK;
++	nint = (pll >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT) &
++	       QCA953X_PLL_DDR_CONFIG_NINT_MASK;
++	frac = (pll >> QCA953X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
++	       QCA953X_PLL_DDR_CONFIG_NFRAC_MASK;
++
++	ddr_pll = nint * ref_rate / ref_div;
++	ddr_pll += frac * (ref_rate >> 6) / (ref_div << 4);
++	ddr_pll /= (1 << out_div);
++
++	clk_ctrl = ath79_pll_rr(QCA953X_PLL_CLK_CTRL_REG);
++
++	postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
++		  QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
++		cpu_rate = ref_rate;
++	else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
++		cpu_rate = cpu_pll / (postdiv + 1);
++	else
++		cpu_rate = ddr_pll / (postdiv + 1);
++
++	postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
++		  QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
++		ddr_rate = ref_rate;
++	else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
++		ddr_rate = ddr_pll / (postdiv + 1);
++	else
++		ddr_rate = cpu_pll / (postdiv + 1);
++
++	postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
++		  QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
++		ahb_rate = ref_rate;
++	else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
++		ahb_rate = ddr_pll / (postdiv + 1);
++	else
++		ahb_rate = cpu_pll / (postdiv + 1);
++
++	ath79_add_sys_clkdev("ref", ref_rate);
++	ath79_add_sys_clkdev("cpu", cpu_rate);
++	ath79_add_sys_clkdev("ddr", ddr_rate);
++	ath79_add_sys_clkdev("ahb", ahb_rate);
++
++	clk_add_alias("wdt", NULL, "ref", NULL);
++	clk_add_alias("uart", NULL, "ref", NULL);
++}
++
+ static void __init qca955x_clocks_init(void)
+ {
+ 	unsigned long ref_rate;
+@@ -451,6 +536,8 @@ void __init ath79_clocks_init(void)
+ 		ar933x_clocks_init();
+ 	else if (soc_is_ar934x())
+ 		ar934x_clocks_init();
++	else if (soc_is_qca953x())
++		qca953x_clocks_init();
+ 	else if (soc_is_qca955x())
+ 		qca955x_clocks_init();
+ 	else
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -104,6 +104,8 @@ void ath79_device_reset_set(u32 mask)
+ 		reg = AR933X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_ar934x())
+ 		reg = AR934X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca953x())
++		reg = QCA953X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
+ 	else
+@@ -132,6 +134,8 @@ void ath79_device_reset_clear(u32 mask)
+ 		reg = AR933X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_ar934x())
+ 		reg = AR934X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca953x())
++		reg = QCA953X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
+ 	else
+--- a/arch/mips/ath79/dev-common.c
++++ b/arch/mips/ath79/dev-common.c
+@@ -94,6 +94,7 @@ void __init ath79_register_uart(void)
+ 	    soc_is_ar724x() ||
+ 	    soc_is_ar913x() ||
+ 	    soc_is_ar934x() ||
++	    soc_is_qca953x() ||
+ 	    soc_is_qca955x()) {
+ 		ath79_uart_data[0].uartclk = uart_clk_rate;
+ 		platform_device_register(&ath79_uart_device);
+@@ -157,6 +158,9 @@ void __init ath79_gpio_init(void)
+ 	} else if (soc_is_ar934x()) {
+ 		ath79_gpio_pdata.ngpios = AR934X_GPIO_COUNT;
+ 		ath79_gpio_pdata.oe_inverted = 1;
++	} else if (soc_is_qca953x()) {
++		ath79_gpio_pdata.ngpios = QCA953X_GPIO_COUNT;
++		ath79_gpio_pdata.oe_inverted = 1;
+ 	} else if (soc_is_qca955x()) {
+ 		ath79_gpio_pdata.ngpios = QCA955X_GPIO_COUNT;
+ 		ath79_gpio_pdata.oe_inverted = 1;
+--- a/arch/mips/ath79/dev-usb.c
++++ b/arch/mips/ath79/dev-usb.c
+@@ -236,6 +236,30 @@ static void __init ar934x_usb_setup(void
+ 			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+ }
+ 
++static void __init qca953x_usb_setup(void)
++{
++	u32 bootstrap;
++
++	bootstrap = ath79_reset_rr(QCA953X_RESET_REG_BOOTSTRAP);
++
++	ath79_device_reset_set(QCA953X_RESET_USBSUS_OVERRIDE);
++	udelay(1000);
++
++	ath79_device_reset_clear(QCA953X_RESET_USB_PHY);
++	udelay(1000);
++
++	ath79_device_reset_clear(QCA953X_RESET_USB_PHY_ANALOG);
++	udelay(1000);
++
++	ath79_device_reset_clear(QCA953X_RESET_USB_HOST);
++	udelay(1000);
++
++	ath79_usb_register("ehci-platform", -1,
++			   QCA953X_EHCI_BASE, QCA953X_EHCI_SIZE,
++			   ATH79_CPU_IRQ(3),
++			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
++}
++
+ static void qca955x_usb_reset_notifier(struct platform_device *pdev)
+ {
+ 	u32 base;
+@@ -286,6 +310,8 @@ void __init ath79_register_usb(void)
+ 		ar933x_usb_setup();
+ 	else if (soc_is_ar934x())
+ 		ar934x_usb_setup();
++	else if (soc_is_qca953x())
++		qca953x_usb_setup();
+ 	else if (soc_is_qca955x())
+ 		qca955x_usb_setup();
+ 	else
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -101,7 +101,7 @@ static int ar933x_wmac_reset(void)
+ 	return -ETIMEDOUT;
+ }
+ 
+-static int ar933x_r1_get_wmac_revision(void)
++static int ar93xx_get_soc_revision(void)
+ {
+ 	return ath79_soc_rev;
+ }
+@@ -126,7 +126,7 @@ static void __init ar933x_wmac_setup(voi
+ 		ath79_wmac_data.is_clk_25mhz = true;
+ 
+ 	if (ath79_soc_rev == 1)
+-		ath79_wmac_data.get_mac_revision = ar933x_r1_get_wmac_revision;
++		ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision;
+ 
+ 	ath79_wmac_data.external_reset = ar933x_wmac_reset;
+ }
+@@ -151,6 +151,26 @@ static void ar934x_wmac_setup(void)
+ 	ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision;
+ }
+ 
++static void qca953x_wmac_setup(void)
++{
++	u32 t;
++
++	ath79_wmac_device.name = "qca953x_wmac";
++
++	ath79_wmac_resources[0].start = QCA953X_WMAC_BASE;
++	ath79_wmac_resources[0].end = QCA953X_WMAC_BASE + QCA953X_WMAC_SIZE - 1;
++	ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1);
++	ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1);
++
++	t = ath79_reset_rr(QCA953X_RESET_REG_BOOTSTRAP);
++	if (t & QCA953X_BOOTSTRAP_REF_CLK_40)
++		ath79_wmac_data.is_clk_25mhz = false;
++	else
++		ath79_wmac_data.is_clk_25mhz = true;
++
++	ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision;
++}
++
+ static void qca955x_wmac_setup(void)
+ {
+ 	u32 t;
+@@ -368,6 +388,8 @@ void __init ath79_register_wmac(u8 *cal_
+ 		ar933x_wmac_setup();
+ 	else if (soc_is_ar934x())
+ 		ar934x_wmac_setup();
++	else if (soc_is_qca953x())
++		qca953x_wmac_setup();
+ 	else if (soc_is_qca955x())
+ 		qca955x_wmac_setup();
+ 	else
+--- a/arch/mips/ath79/early_printk.c
++++ b/arch/mips/ath79/early_printk.c
+@@ -116,6 +116,8 @@ static void prom_putchar_init(void)
+ 	case REV_ID_MAJOR_AR9341:
+ 	case REV_ID_MAJOR_AR9342:
+ 	case REV_ID_MAJOR_AR9344:
++	case REV_ID_MAJOR_QCA9533:
++	case REV_ID_MAJOR_QCA9533_V2:
+ 	case REV_ID_MAJOR_QCA9556:
+ 	case REV_ID_MAJOR_QCA9558:
+ 		_prom_putchar = prom_putchar_ar71xx;
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -31,7 +31,7 @@ static void __iomem *ath79_gpio_get_func
+ 	    soc_is_ar913x() ||
+ 	    soc_is_ar933x())
+ 		reg = AR71XX_GPIO_REG_FUNC;
+-	else if (soc_is_ar934x())
++	else if (soc_is_ar934x() || soc_is_qca953x())
+ 		reg = AR934X_GPIO_REG_FUNC;
+ 	else
+ 		BUG();
+@@ -64,7 +64,7 @@ void __init ath79_gpio_output_select(uns
+ 	unsigned int reg;
+ 	u32 t, s;
+ 
+-	BUG_ON(!soc_is_ar934x());
++	BUG_ON(!soc_is_ar934x() && !soc_is_qca953x());
+ 
+ 	if (gpio >= AR934X_GPIO_COUNT)
+ 		return;
+--- a/arch/mips/ath79/irq.c
++++ b/arch/mips/ath79/irq.c
+@@ -105,6 +105,7 @@ static void __init ath79_misc_irq_init(v
+ 	else if (soc_is_ar724x() ||
+ 		 soc_is_ar933x() ||
+ 		 soc_is_ar934x() ||
++		 soc_is_qca953x() ||
+ 		 soc_is_qca955x())
+ 		ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
+ 	else
+@@ -148,6 +149,34 @@ static void ar934x_ip2_irq_init(void)
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch);
+ }
+ 
++static void qca953x_ip2_irq_dispatch(struct irq_desc *desc)
++{
++	u32 status;
++
++	status = ath79_reset_rr(QCA953X_RESET_REG_PCIE_WMAC_INT_STATUS);
++
++	if (status & QCA953X_PCIE_WMAC_INT_PCIE_ALL) {
++		ath79_ddr_wb_flush(3);
++		generic_handle_irq(ATH79_IP2_IRQ(0));
++	} else if (status & QCA953X_PCIE_WMAC_INT_WMAC_ALL) {
++		ath79_ddr_wb_flush(4);
++		generic_handle_irq(ATH79_IP2_IRQ(1));
++	} else {
++		spurious_interrupt();
++	}
++}
++
++static void qca953x_irq_init(void)
++{
++	int i;
++
++	for (i = ATH79_IP2_IRQ_BASE;
++	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
++		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq);
++
++	irq_set_chained_handler(ATH79_CPU_IRQ(2), qca953x_ip2_irq_dispatch);
++}
++
+ static void qca955x_ip2_irq_dispatch(struct irq_desc *desc)
+ {
+ 	u32 status;
+@@ -362,7 +391,7 @@ void __init arch_init_irq(void)
+ 	    soc_is_ar913x() || soc_is_ar933x()) {
+ 		irq_wb_chan[2] = 3;
+ 		irq_wb_chan[3] = 2;
+-	} else if (soc_is_ar934x()) {
++	} else if (soc_is_ar934x() || soc_is_qca953x()) {
+ 		irq_wb_chan[3] = 2;
+ 	}
+ 
+@@ -371,6 +400,8 @@ void __init arch_init_irq(void)
+ 
+ 	if (soc_is_ar934x())
+ 		ar934x_ip2_irq_init();
++	else if (soc_is_qca953x())
++		qca953x_irq_init();
+ 	else if (soc_is_qca955x())
+ 		qca955x_irq_init();
+ }
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -64,6 +64,7 @@ static void __init ath79_detect_sys_type
+ 	u32 major;
+ 	u32 minor;
+ 	u32 rev = 0;
++	u32 ver = 1;
+ 
+ 	id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID);
+ 	major = id & REV_ID_MAJOR_MASK;
+@@ -156,6 +157,17 @@ static void __init ath79_detect_sys_type
+ 		rev = id & AR934X_REV_ID_REVISION_MASK;
+ 		break;
+ 
++	case REV_ID_MAJOR_QCA9533_V2:
++		ver = 2;
++		ath79_soc_rev = 2;
++		/* drop through */
++
++	case REV_ID_MAJOR_QCA9533:
++		ath79_soc = ATH79_SOC_QCA9533;
++		chip = "9533";
++		rev = id & QCA953X_REV_ID_REVISION_MASK;
++		break;
++
+ 	case REV_ID_MAJOR_QCA9556:
+ 		ath79_soc = ATH79_SOC_QCA9556;
+ 		chip = "9556";
+@@ -172,11 +184,12 @@ static void __init ath79_detect_sys_type
+ 		panic("ath79: unknown SoC, id:0x%08x", id);
+ 	}
+ 
+-	ath79_soc_rev = rev;
++	if (ver == 1)
++		ath79_soc_rev = rev;
+ 
+-	if (soc_is_qca955x())
+-		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s rev %u",
+-			chip, rev);
++	if (soc_is_qca953x() || soc_is_qca955x())
++		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s ver %u rev %u",
++			chip, ver, rev);
+ 	else
+ 		sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
+ 	pr_info("SoC: %s\n", ath79_sys_type);
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -105,6 +105,21 @@
+ #define AR934X_SRIF_BASE	(AR71XX_APB_BASE + 0x00116000)
+ #define AR934X_SRIF_SIZE	0x1000
+ 
++#define QCA953X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
++#define QCA953X_GMAC_SIZE	0x14
++#define QCA953X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
++#define QCA953X_WMAC_SIZE	0x20000
++#define QCA953X_EHCI_BASE	0x1b000000
++#define QCA953X_EHCI_SIZE	0x200
++#define QCA953X_SRIF_BASE	(AR71XX_APB_BASE + 0x00116000)
++#define QCA953X_SRIF_SIZE	0x1000
++
++#define QCA953X_PCI_CFG_BASE0	0x14000000
++#define QCA953X_PCI_CTRL_BASE0	(AR71XX_APB_BASE + 0x000f0000)
++#define QCA953X_PCI_CRP_BASE0	(AR71XX_APB_BASE + 0x000c0000)
++#define QCA953X_PCI_MEM_BASE0	0x10000000
++#define QCA953X_PCI_MEM_SIZE	0x02000000
++
+ #define QCA955X_PCI_MEM_BASE0	0x10000000
+ #define QCA955X_PCI_MEM_BASE1	0x12000000
+ #define QCA955X_PCI_MEM_SIZE	0x02000000
+@@ -173,6 +188,12 @@
+ #define AR934X_DDR_REG_FLUSH_PCIE	0xa8
+ #define AR934X_DDR_REG_FLUSH_WMAC	0xac
+ 
++#define QCA953X_DDR_REG_FLUSH_GE0	0x9c
++#define QCA953X_DDR_REG_FLUSH_GE1	0xa0
++#define QCA953X_DDR_REG_FLUSH_USB	0xa4
++#define QCA953X_DDR_REG_FLUSH_PCIE	0xa8
++#define QCA953X_DDR_REG_FLUSH_WMAC	0xac
++
+ /*
+  * PLL block
+  */
+@@ -279,6 +300,44 @@
+ 
+ #define AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL	BIT(6)
+ 
++#define QCA953X_PLL_CPU_CONFIG_REG		0x00
++#define QCA953X_PLL_DDR_CONFIG_REG		0x04
++#define QCA953X_PLL_CLK_CTRL_REG		0x08
++#define QCA953X_PLL_SWITCH_CLOCK_CONTROL_REG	0x24
++#define QCA953X_PLL_ETH_XMII_CONTROL_REG	0x2c
++#define QCA953X_PLL_ETH_SGMII_CONTROL_REG	0x48
++
++#define QCA953X_PLL_CPU_CONFIG_NFRAC_SHIFT	0
++#define QCA953X_PLL_CPU_CONFIG_NFRAC_MASK	0x3f
++#define QCA953X_PLL_CPU_CONFIG_NINT_SHIFT	6
++#define QCA953X_PLL_CPU_CONFIG_NINT_MASK	0x3f
++#define QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT	12
++#define QCA953X_PLL_CPU_CONFIG_REFDIV_MASK	0x1f
++#define QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT	19
++#define QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK	0x7
++
++#define QCA953X_PLL_DDR_CONFIG_NFRAC_SHIFT	0
++#define QCA953X_PLL_DDR_CONFIG_NFRAC_MASK	0x3ff
++#define QCA953X_PLL_DDR_CONFIG_NINT_SHIFT	10
++#define QCA953X_PLL_DDR_CONFIG_NINT_MASK	0x3f
++#define QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT	16
++#define QCA953X_PLL_DDR_CONFIG_REFDIV_MASK	0x1f
++#define QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT	23
++#define QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK	0x7
++
++#define QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
++#define QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
++#define QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
++#define QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
++#define QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
++#define QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
++#define QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
++#define QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
++#define QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
++#define QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
++#define QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
++#define QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
++
+ #define QCA955X_PLL_CPU_CONFIG_REG		0x00
+ #define QCA955X_PLL_DDR_CONFIG_REG		0x04
+ #define QCA955X_PLL_CLK_CTRL_REG		0x08
+@@ -355,6 +414,10 @@
+ #define AR934X_RESET_REG_BOOTSTRAP		0xb0
+ #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS	0xac
+ 
++#define QCA953X_RESET_REG_RESET_MODULE		0x1c
++#define QCA953X_RESET_REG_BOOTSTRAP		0xb0
++#define QCA953X_RESET_REG_PCIE_WMAC_INT_STATUS	0xac
++
+ #define QCA955X_RESET_REG_RESET_MODULE		0x1c
+ #define QCA955X_RESET_REG_BOOTSTRAP		0xb0
+ #define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
+@@ -450,6 +513,27 @@
+ #define AR934X_RESET_MBOX		BIT(1)
+ #define AR934X_RESET_I2S		BIT(0)
+ 
++#define QCA953X_RESET_USB_EXT_PWR	BIT(29)
++#define QCA953X_RESET_EXTERNAL		BIT(28)
++#define QCA953X_RESET_RTC		BIT(27)
++#define QCA953X_RESET_FULL_CHIP		BIT(24)
++#define QCA953X_RESET_GE1_MDIO		BIT(23)
++#define QCA953X_RESET_GE0_MDIO		BIT(22)
++#define QCA953X_RESET_CPU_NMI		BIT(21)
++#define QCA953X_RESET_CPU_COLD		BIT(20)
++#define QCA953X_RESET_DDR		BIT(16)
++#define QCA953X_RESET_USB_PHY_PLL_PWD_EXT BIT(15)
++#define QCA953X_RESET_GE1_MAC		BIT(13)
++#define QCA953X_RESET_ETH_SWITCH_ANALOG	BIT(12)
++#define QCA953X_RESET_USB_PHY_ANALOG	BIT(11)
++#define QCA953X_RESET_GE0_MAC		BIT(9)
++#define QCA953X_RESET_ETH_SWITCH	BIT(8)
++#define QCA953X_RESET_PCIE_PHY		BIT(7)
++#define QCA953X_RESET_PCIE		BIT(6)
++#define QCA953X_RESET_USB_HOST		BIT(5)
++#define QCA953X_RESET_USB_PHY		BIT(4)
++#define QCA953X_RESET_USBSUS_OVERRIDE	BIT(3)
++
+ #define QCA955X_RESET_HOST		BIT(31)
+ #define QCA955X_RESET_SLIC		BIT(30)
+ #define QCA955X_RESET_HDMA		BIT(29)
+@@ -503,6 +587,13 @@
+ #define AR934X_BOOTSTRAP_SDRAM_DISABLED BIT(1)
+ #define AR934X_BOOTSTRAP_DDR1		BIT(0)
+ 
++#define QCA953X_BOOTSTRAP_SW_OPTION2	BIT(12)
++#define QCA953X_BOOTSTRAP_SW_OPTION1	BIT(11)
++#define QCA953X_BOOTSTRAP_EJTAG_MODE	BIT(5)
++#define QCA953X_BOOTSTRAP_REF_CLK_40	BIT(4)
++#define QCA953X_BOOTSTRAP_SDRAM_DISABLED BIT(1)
++#define QCA953X_BOOTSTRAP_DDR1		BIT(0)
++
+ #define QCA955X_BOOTSTRAP_REF_CLK_40	BIT(4)
+ 
+ #define AR934X_PCIE_WMAC_INT_WMAC_MISC		BIT(0)
+@@ -523,6 +614,24 @@
+ 	 AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \
+ 	 AR934X_PCIE_WMAC_INT_PCIE_RC3)
+ 
++#define QCA953X_PCIE_WMAC_INT_WMAC_MISC		BIT(0)
++#define QCA953X_PCIE_WMAC_INT_WMAC_TX		BIT(1)
++#define QCA953X_PCIE_WMAC_INT_WMAC_RXLP		BIT(2)
++#define QCA953X_PCIE_WMAC_INT_WMAC_RXHP		BIT(3)
++#define QCA953X_PCIE_WMAC_INT_PCIE_RC		BIT(4)
++#define QCA953X_PCIE_WMAC_INT_PCIE_RC0		BIT(5)
++#define QCA953X_PCIE_WMAC_INT_PCIE_RC1		BIT(6)
++#define QCA953X_PCIE_WMAC_INT_PCIE_RC2		BIT(7)
++#define QCA953X_PCIE_WMAC_INT_PCIE_RC3		BIT(8)
++#define QCA953X_PCIE_WMAC_INT_WMAC_ALL \
++	(QCA953X_PCIE_WMAC_INT_WMAC_MISC | QCA953X_PCIE_WMAC_INT_WMAC_TX | \
++	 QCA953X_PCIE_WMAC_INT_WMAC_RXLP | QCA953X_PCIE_WMAC_INT_WMAC_RXHP)
++
++#define QCA953X_PCIE_WMAC_INT_PCIE_ALL \
++	(QCA953X_PCIE_WMAC_INT_PCIE_RC | QCA953X_PCIE_WMAC_INT_PCIE_RC0 | \
++	 QCA953X_PCIE_WMAC_INT_PCIE_RC1 | QCA953X_PCIE_WMAC_INT_PCIE_RC2 | \
++	 QCA953X_PCIE_WMAC_INT_PCIE_RC3)
++
+ #define QCA955X_EXT_INT_WMAC_MISC		BIT(0)
+ #define QCA955X_EXT_INT_WMAC_TX			BIT(1)
+ #define QCA955X_EXT_INT_WMAC_RXLP		BIT(2)
+@@ -565,6 +674,8 @@
+ #define REV_ID_MAJOR_AR9341		0x0120
+ #define REV_ID_MAJOR_AR9342		0x1120
+ #define REV_ID_MAJOR_AR9344		0x2120
++#define REV_ID_MAJOR_QCA9533		0x0140
++#define REV_ID_MAJOR_QCA9533_V2		0x0160
+ #define REV_ID_MAJOR_QCA9556		0x0130
+ #define REV_ID_MAJOR_QCA9558		0x1130
+ 
+@@ -587,6 +698,8 @@
+ 
+ #define AR934X_REV_ID_REVISION_MASK	0xf
+ 
++#define QCA953X_REV_ID_REVISION_MASK	0xf
++
+ #define QCA955X_REV_ID_REVISION_MASK	0xf
+ 
+ /*
+@@ -634,6 +747,25 @@
+ #define AR934X_GPIO_REG_OUT_FUNC5	0x40
+ #define AR934X_GPIO_REG_FUNC		0x6c
+ 
++#define QCA953X_GPIO_REG_OUT_FUNC0	0x2c
++#define QCA953X_GPIO_REG_OUT_FUNC1	0x30
++#define QCA953X_GPIO_REG_OUT_FUNC2	0x34
++#define QCA953X_GPIO_REG_OUT_FUNC3	0x38
++#define QCA953X_GPIO_REG_OUT_FUNC4	0x3c
++#define QCA953X_GPIO_REG_IN_ENABLE0	0x44
++#define QCA953X_GPIO_REG_FUNC		0x6c
++
++#define QCA953X_GPIO_OUT_MUX_SPI_CS1		10
++#define QCA953X_GPIO_OUT_MUX_SPI_CS2		11
++#define QCA953X_GPIO_OUT_MUX_SPI_CS0		9
++#define QCA953X_GPIO_OUT_MUX_SPI_CLK		8
++#define QCA953X_GPIO_OUT_MUX_SPI_MOSI		12
++#define QCA953X_GPIO_OUT_MUX_LED_LINK1		41
++#define QCA953X_GPIO_OUT_MUX_LED_LINK2		42
++#define QCA953X_GPIO_OUT_MUX_LED_LINK3		43
++#define QCA953X_GPIO_OUT_MUX_LED_LINK4		44
++#define QCA953X_GPIO_OUT_MUX_LED_LINK5		45
++
+ #define QCA955X_GPIO_REG_OUT_FUNC0	0x2c
+ #define QCA955X_GPIO_REG_OUT_FUNC1	0x30
+ #define QCA955X_GPIO_REG_OUT_FUNC2	0x34
+@@ -648,6 +780,7 @@
+ #define AR913X_GPIO_COUNT		22
+ #define AR933X_GPIO_COUNT		30
+ #define AR934X_GPIO_COUNT		23
++#define QCA953X_GPIO_COUNT		18
+ #define QCA955X_GPIO_COUNT		24
+ 
+ /*
+@@ -671,6 +804,24 @@
+ #define AR934X_SRIF_DPLL2_OUTDIV_SHIFT	13
+ #define AR934X_SRIF_DPLL2_OUTDIV_MASK	0x7
+ 
++#define QCA953X_SRIF_CPU_DPLL1_REG	0x1c0
++#define QCA953X_SRIF_CPU_DPLL2_REG	0x1c4
++#define QCA953X_SRIF_CPU_DPLL3_REG	0x1c8
++
++#define QCA953X_SRIF_DDR_DPLL1_REG	0x240
++#define QCA953X_SRIF_DDR_DPLL2_REG	0x244
++#define QCA953X_SRIF_DDR_DPLL3_REG	0x248
++
++#define QCA953X_SRIF_DPLL1_REFDIV_SHIFT	27
++#define QCA953X_SRIF_DPLL1_REFDIV_MASK	0x1f
++#define QCA953X_SRIF_DPLL1_NINT_SHIFT	18
++#define QCA953X_SRIF_DPLL1_NINT_MASK	0x1ff
++#define QCA953X_SRIF_DPLL1_NFRAC_MASK	0x0003ffff
++
++#define QCA953X_SRIF_DPLL2_LOCAL_PLL	BIT(30)
++#define QCA953X_SRIF_DPLL2_OUTDIV_SHIFT	13
++#define QCA953X_SRIF_DPLL2_OUTDIV_MASK	0x7
++
+ #define AR71XX_GPIO_FUNC_STEREO_EN		BIT(17)
+ #define AR71XX_GPIO_FUNC_SLIC_EN		BIT(16)
+ #define AR71XX_GPIO_FUNC_SPI_CS2_EN		BIT(13)
+@@ -877,6 +1028,16 @@
+ #define AR934X_ETH_CFG_RDV_DELAY_SHIFT  16
+ 
+ /*
++ * QCA953X GMAC Interface
++ */
++#define QCA953X_GMAC_REG_ETH_CFG		0x00
++
++#define QCA953X_ETH_CFG_SW_ONLY_MODE		BIT(6)
++#define QCA953X_ETH_CFG_SW_PHY_SWAP		BIT(7)
++#define QCA953X_ETH_CFG_SW_APB_ACCESS		BIT(9)
++#define QCA953X_ETH_CFG_SW_ACC_MSB_FIRST	BIT(13)
++
++/*
+  * QCA955X GMAC Interface
+  */
+ 
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -32,6 +32,7 @@ enum ath79_soc_type {
+ 	ATH79_SOC_AR9341,
+ 	ATH79_SOC_AR9342,
+ 	ATH79_SOC_AR9344,
++	ATH79_SOC_QCA9533,
+ 	ATH79_SOC_QCA9556,
+ 	ATH79_SOC_QCA9558,
+ };
+@@ -100,6 +101,16 @@ static inline int soc_is_ar934x(void)
+ 	return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344();
+ }
+ 
++static inline int soc_is_qca9533(void)
++{
++	return ath79_soc == ATH79_SOC_QCA9533;
++}
++
++static inline int soc_is_qca953x(void)
++{
++	return soc_is_qca9533();
++}
++
+ static inline int soc_is_qca9556(void)
+ {
+ 	return ath79_soc == ATH79_SOC_QCA9556;
diff --git a/target/linux/ar71xx/patches-4.4/621-MIPS-ath79-add-support-for-QCA956x-SoC.patch b/target/linux/ar71xx/patches-4.4/621-MIPS-ath79-add-support-for-QCA956x-SoC.patch
new file mode 100644
index 0000000000..116c2b675f
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/621-MIPS-ath79-add-support-for-QCA956x-SoC.patch
@@ -0,0 +1,717 @@
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -126,6 +126,12 @@ config SOC_QCA955X
+ 	select PCI_AR724X if PCI
+ 	def_bool n
+ 
++config SOC_QCA956X
++	select USB_ARCH_HAS_EHCI
++	select HW_HAS_PCI
++	select PCI_AR724X if PCI
++	def_bool n
++
+ config ATH79_DEV_M25P80
+ 	select ATH79_DEV_SPI
+ 	def_bool n
+@@ -160,7 +166,7 @@ config ATH79_DEV_USB
+ 	def_bool n
+ 
+ config ATH79_DEV_WMAC
+-	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA953X || SOC_QCA955X)
++	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA953X || SOC_QCA955X || SOC_QCA956X)
+ 	def_bool n
+ 
+ config ATH79_NVRAM
+--- a/arch/mips/ath79/clock.c
++++ b/arch/mips/ath79/clock.c
+@@ -524,6 +524,100 @@ static void __init qca955x_clocks_init(v
+ 	clk_add_alias("uart", NULL, "ref", NULL);
+ }
+ 
++static void __init qca956x_clocks_init(void)
++{
++	unsigned long ref_rate;
++	unsigned long cpu_rate;
++	unsigned long ddr_rate;
++	unsigned long ahb_rate;
++	u32 pll, out_div, ref_div, nint, hfrac, lfrac, clk_ctrl, postdiv;
++	u32 cpu_pll, ddr_pll;
++	u32 bootstrap;
++
++	bootstrap = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
++	if (bootstrap &	QCA956X_BOOTSTRAP_REF_CLK_40)
++		ref_rate = 40 * 1000 * 1000;
++	else
++		ref_rate = 25 * 1000 * 1000;
++
++	pll = ath79_pll_rr(QCA956X_PLL_CPU_CONFIG_REG);
++	out_div = (pll >> QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
++		  QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK;
++	ref_div = (pll >> QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
++		  QCA956X_PLL_CPU_CONFIG_REFDIV_MASK;
++
++	pll = ath79_pll_rr(QCA956X_PLL_CPU_CONFIG1_REG);
++	nint = (pll >> QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT) &
++	       QCA956X_PLL_CPU_CONFIG1_NINT_MASK;
++	hfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT) &
++	       QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK;
++	lfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT) &
++	       QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK;
++
++	cpu_pll = nint * ref_rate / ref_div;
++	cpu_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
++	cpu_pll += (hfrac >> 13) * ref_rate / ref_div;
++	cpu_pll /= (1 << out_div);
++
++	pll = ath79_pll_rr(QCA956X_PLL_DDR_CONFIG_REG);
++	out_div = (pll >> QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
++		  QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK;
++	ref_div = (pll >> QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
++		  QCA956X_PLL_DDR_CONFIG_REFDIV_MASK;
++	pll = ath79_pll_rr(QCA956X_PLL_DDR_CONFIG1_REG);
++	nint = (pll >> QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT) &
++	       QCA956X_PLL_DDR_CONFIG1_NINT_MASK;
++	hfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT) &
++	       QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK;
++	lfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT) &
++	       QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK;
++
++	ddr_pll = nint * ref_rate / ref_div;
++	ddr_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
++	ddr_pll += (hfrac >> 13) * ref_rate / ref_div;
++	ddr_pll /= (1 << out_div);
++
++	clk_ctrl = ath79_pll_rr(QCA956X_PLL_CLK_CTRL_REG);
++
++	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
++		  QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
++		cpu_rate = ref_rate;
++	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL)
++		cpu_rate = ddr_pll / (postdiv + 1);
++	else
++		cpu_rate = cpu_pll / (postdiv + 1);
++
++	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
++		  QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
++		ddr_rate = ref_rate;
++	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL)
++		ddr_rate = cpu_pll / (postdiv + 1);
++	else
++		ddr_rate = ddr_pll / (postdiv + 1);
++
++	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
++		  QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
++		ahb_rate = ref_rate;
++	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
++		ahb_rate = ddr_pll / (postdiv + 1);
++	else
++		ahb_rate = cpu_pll / (postdiv + 1);
++
++	ath79_add_sys_clkdev("ref", ref_rate);
++	ath79_add_sys_clkdev("cpu", cpu_rate);
++	ath79_add_sys_clkdev("ddr", ddr_rate);
++	ath79_add_sys_clkdev("ahb", ahb_rate);
++
++	clk_add_alias("wdt", NULL, "ref", NULL);
++	clk_add_alias("uart", NULL, "ref", NULL);
++}
++
+ void __init ath79_clocks_init(void)
+ {
+ 	if (soc_is_ar71xx())
+@@ -540,6 +634,8 @@ void __init ath79_clocks_init(void)
+ 		qca953x_clocks_init();
+ 	else if (soc_is_qca955x())
+ 		qca955x_clocks_init();
++	else if (soc_is_qca956x() || soc_is_tp9343())
++		qca956x_clocks_init();
+ 	else
+ 		BUG();
+ 
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -108,6 +108,8 @@ void ath79_device_reset_set(u32 mask)
+ 		reg = QCA953X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca956x() || soc_is_tp9343())
++		reg = QCA956X_RESET_REG_RESET_MODULE;
+ 	else
+ 		panic("Reset register not defined for this SOC");
+ 
+@@ -138,6 +140,8 @@ void ath79_device_reset_clear(u32 mask)
+ 		reg = QCA953X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca956x() || soc_is_tp9343())
++		reg = QCA956X_RESET_REG_RESET_MODULE;
+ 	else
+ 		panic("Reset register not defined for this SOC");
+ 
+@@ -164,6 +168,8 @@ u32 ath79_device_reset_get(u32 mask)
+ 		reg = AR933X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_ar934x())
+ 		reg = AR934X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca956x() || soc_is_tp9343())
++		reg = QCA956X_RESET_REG_RESET_MODULE;
+ 	else
+ 		BUG();
+ 
+--- a/arch/mips/ath79/dev-common.c
++++ b/arch/mips/ath79/dev-common.c
+@@ -95,7 +95,9 @@ void __init ath79_register_uart(void)
+ 	    soc_is_ar913x() ||
+ 	    soc_is_ar934x() ||
+ 	    soc_is_qca953x() ||
+-	    soc_is_qca955x()) {
++	    soc_is_qca955x() ||
++	    soc_is_qca956x() ||
++	    soc_is_tp9343()) {
+ 		ath79_uart_data[0].uartclk = uart_clk_rate;
+ 		platform_device_register(&ath79_uart_device);
+ 	} else if (soc_is_ar933x()) {
+@@ -164,6 +166,9 @@ void __init ath79_gpio_init(void)
+ 	} else if (soc_is_qca955x()) {
+ 		ath79_gpio_pdata.ngpios = QCA955X_GPIO_COUNT;
+ 		ath79_gpio_pdata.oe_inverted = 1;
++	} else if (soc_is_qca956x() || soc_is_tp9343()) {
++		ath79_gpio_pdata.ngpios = QCA956X_GPIO_COUNT;
++		ath79_gpio_pdata.oe_inverted = 1;
+ 	} else {
+ 		BUG();
+ 	}
+--- a/arch/mips/ath79/dev-usb.c
++++ b/arch/mips/ath79/dev-usb.c
+@@ -296,6 +296,19 @@ static void __init qca955x_usb_setup(voi
+ 			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+ }
+ 
++static void __init qca956x_usb_setup(void)
++{
++	ath79_usb_register("ehci-platform", 0,
++			   QCA956X_EHCI0_BASE, QCA956X_EHCI_SIZE,
++			   ATH79_IP3_IRQ(0),
++			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
++
++	ath79_usb_register("ehci-platform", 1,
++			   QCA956X_EHCI1_BASE, QCA956X_EHCI_SIZE,
++			   ATH79_IP3_IRQ(1),
++			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
++}
++
+ void __init ath79_register_usb(void)
+ {
+ 	if (soc_is_ar71xx())
+@@ -314,6 +327,8 @@ void __init ath79_register_usb(void)
+ 		qca953x_usb_setup();
+ 	else if (soc_is_qca955x())
+ 		qca955x_usb_setup();
++	else if (soc_is_qca956x())
++		qca956x_usb_setup();
+ 	else
+ 		BUG();
+ }
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -189,6 +189,26 @@ static void qca955x_wmac_setup(void)
+ 		ath79_wmac_data.is_clk_25mhz = true;
+ }
+ 
++static void qca956x_wmac_setup(void)
++{
++	u32 t;
++
++	ath79_wmac_device.name = "qca956x_wmac";
++
++	ath79_wmac_resources[0].start = QCA956X_WMAC_BASE;
++	ath79_wmac_resources[0].end = QCA956X_WMAC_BASE + QCA956X_WMAC_SIZE - 1;
++	ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1);
++	ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1);
++
++	t = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
++	if (t & QCA956X_BOOTSTRAP_REF_CLK_40)
++		ath79_wmac_data.is_clk_25mhz = false;
++	else
++		ath79_wmac_data.is_clk_25mhz = true;
++
++	ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision;
++}
++
+ static bool __init
+ ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data)
+ {
+@@ -392,6 +412,8 @@ void __init ath79_register_wmac(u8 *cal_
+ 		qca953x_wmac_setup();
+ 	else if (soc_is_qca955x())
+ 		qca955x_wmac_setup();
++	else if (soc_is_qca956x() || soc_is_tp9343())
++		qca956x_wmac_setup();
+ 	else
+ 		BUG();
+ 
+--- a/arch/mips/ath79/early_printk.c
++++ b/arch/mips/ath79/early_printk.c
+@@ -120,6 +120,8 @@ static void prom_putchar_init(void)
+ 	case REV_ID_MAJOR_QCA9533_V2:
+ 	case REV_ID_MAJOR_QCA9556:
+ 	case REV_ID_MAJOR_QCA9558:
++	case REV_ID_MAJOR_TP9343:
++	case REV_ID_MAJOR_QCA956X:
+ 		_prom_putchar = prom_putchar_ar71xx;
+ 		break;
+ 
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -31,7 +31,10 @@ static void __iomem *ath79_gpio_get_func
+ 	    soc_is_ar913x() ||
+ 	    soc_is_ar933x())
+ 		reg = AR71XX_GPIO_REG_FUNC;
+-	else if (soc_is_ar934x() || soc_is_qca953x())
++	else if (soc_is_ar934x() ||
++		 soc_is_qca953x() ||
++		 soc_is_qca956x() ||
++		 soc_is_tp9343())
+ 		reg = AR934X_GPIO_REG_FUNC;
+ 	else
+ 		BUG();
+@@ -64,7 +67,7 @@ void __init ath79_gpio_output_select(uns
+ 	unsigned int reg;
+ 	u32 t, s;
+ 
+-	BUG_ON(!soc_is_ar934x() && !soc_is_qca953x());
++	BUG_ON(!soc_is_ar934x() && !soc_is_qca953x() && !soc_is_qca956x());
+ 
+ 	if (gpio >= AR934X_GPIO_COUNT)
+ 		return;
+--- a/arch/mips/ath79/irq.c
++++ b/arch/mips/ath79/irq.c
+@@ -106,7 +106,9 @@ static void __init ath79_misc_irq_init(v
+ 		 soc_is_ar933x() ||
+ 		 soc_is_ar934x() ||
+ 		 soc_is_qca953x() ||
+-		 soc_is_qca955x())
++		 soc_is_qca955x() ||
++		 soc_is_qca956x() ||
++		 soc_is_tp9343())
+ 		ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
+ 	else
+ 		BUG();
+@@ -263,6 +265,87 @@ static unsigned irq_wb_chan[8] = {
+ 	-1, -1, -1, -1, -1, -1, -1, -1,
+ };
+ 
++static void qca956x_ip2_irq_dispatch(struct irq_desc *desc)
++{
++	u32 status;
++
++	status = ath79_reset_rr(QCA956X_RESET_REG_EXT_INT_STATUS);
++	status &= QCA956X_EXT_INT_PCIE_RC1_ALL | QCA956X_EXT_INT_WMAC_ALL;
++
++	if (status == 0) {
++		spurious_interrupt();
++		return;
++	}
++
++	if (status & QCA956X_EXT_INT_PCIE_RC1_ALL) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP2_IRQ(0));
++	}
++
++	if (status & QCA956X_EXT_INT_WMAC_ALL) {
++		/* TODO: flsuh DDR? */
++		generic_handle_irq(ATH79_IP2_IRQ(1));
++	}
++}
++
++static void qca956x_ip3_irq_dispatch(struct irq_desc *desc)
++{
++	u32 status;
++
++	status = ath79_reset_rr(QCA956X_RESET_REG_EXT_INT_STATUS);
++	status &= QCA956X_EXT_INT_PCIE_RC2_ALL |
++		  QCA956X_EXT_INT_USB1 | QCA956X_EXT_INT_USB2;
++
++	if (status == 0) {
++		spurious_interrupt();
++		return;
++	}
++
++	if (status & QCA956X_EXT_INT_USB1) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP3_IRQ(0));
++	}
++
++	if (status & QCA956X_EXT_INT_USB2) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP3_IRQ(1));
++	}
++
++	if (status & QCA956X_EXT_INT_PCIE_RC2_ALL) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP3_IRQ(2));
++	}
++}
++
++static void qca956x_enable_timer_cb(void) {
++	u32 misc;
++
++	misc = ath79_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE);
++	misc |= MISC_INT_MIPS_SI_TIMERINT_MASK;
++	ath79_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, misc);
++}
++
++static void qca956x_irq_init(void)
++{
++	int i;
++
++	for (i = ATH79_IP2_IRQ_BASE;
++	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
++		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq);
++
++	irq_set_chained_handler(ATH79_CPU_IRQ(2), qca956x_ip2_irq_dispatch);
++
++	for (i = ATH79_IP3_IRQ_BASE;
++	     i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++)
++		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq);
++
++	irq_set_chained_handler(ATH79_CPU_IRQ(3), qca956x_ip3_irq_dispatch);
++
++	/* QCA956x timer init workaround has to be applied right before setting
++	 * up the clock. Else, there will be no jiffies */
++	late_time_init = &qca956x_enable_timer_cb;
++}
++
+ asmlinkage void plat_irq_dispatch(void)
+ {
+ 	unsigned long pending;
+@@ -404,4 +487,6 @@ void __init arch_init_irq(void)
+ 		qca953x_irq_init();
+ 	else if (soc_is_qca955x())
+ 		qca955x_irq_init();
++	else if (soc_is_qca956x() || soc_is_tp9343())
++		qca956x_irq_init();
+ }
+--- a/arch/mips/ath79/pci.c
++++ b/arch/mips/ath79/pci.c
+@@ -68,6 +68,21 @@ static const struct ath79_pci_irq qca955
+ 	},
+ };
+ 
++static const struct ath79_pci_irq qca956x_pci_irq_map[] __initconst = {
++	{
++		.bus    = 0,
++		.slot   = 0,
++		.pin    = 1,
++		.irq    = ATH79_PCI_IRQ(0),
++	},
++	{
++		.bus    = 1,
++		.slot   = 0,
++		.pin    = 1,
++		.irq    = ATH79_PCI_IRQ(1),
++	},
++};
++
+ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
+ {
+ 	int irq = -1;
+@@ -86,6 +101,9 @@ int __init pcibios_map_irq(const struct
+ 		} else if (soc_is_qca955x()) {
+ 			ath79_pci_irq_map = qca955x_pci_irq_map;
+ 			ath79_pci_nr_irqs = ARRAY_SIZE(qca955x_pci_irq_map);
++		} else if (soc_is_qca956x()) {
++			ath79_pci_irq_map = qca956x_pci_irq_map;
++			ath79_pci_nr_irqs = ARRAY_SIZE(qca956x_pci_irq_map);
+ 		} else {
+ 			pr_crit("pci %s: invalid irq map\n",
+ 				pci_name((struct pci_dev *) dev));
+@@ -303,6 +321,15 @@ int __init ath79_register_pci(void)
+ 						 QCA955X_PCI_MEM_SIZE,
+ 						 1,
+ 						 ATH79_IP3_IRQ(2));
++	} else if (soc_is_qca956x()) {
++		pdev = ath79_register_pci_ar724x(0,
++						 QCA956X_PCI_CFG_BASE1,
++						 QCA956X_PCI_CTRL_BASE1,
++						 QCA956X_PCI_CRP_BASE1,
++						 QCA956X_PCI_MEM_BASE1,
++						 QCA956X_PCI_MEM_SIZE,
++						 1,
++						 ATH79_IP3_IRQ(2));
+ 	} else {
+ 		/* No PCI support */
+ 		return -ENODEV;
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -180,6 +180,18 @@ static void __init ath79_detect_sys_type
+ 		rev = id & QCA955X_REV_ID_REVISION_MASK;
+ 		break;
+ 
++	case REV_ID_MAJOR_QCA956X:
++		ath79_soc = ATH79_SOC_QCA956X;
++		chip = "956X";
++		rev = id & QCA956X_REV_ID_REVISION_MASK;
++		break;
++
++	case REV_ID_MAJOR_TP9343:
++		ath79_soc = ATH79_SOC_TP9343;
++		chip = "9343";
++		rev = id & QCA956X_REV_ID_REVISION_MASK;
++		break;
++
+ 	default:
+ 		panic("ath79: unknown SoC, id:0x%08x", id);
+ 	}
+@@ -187,9 +199,12 @@ static void __init ath79_detect_sys_type
+ 	if (ver == 1)
+ 		ath79_soc_rev = rev;
+ 
+-	if (soc_is_qca953x() || soc_is_qca955x())
++	if (soc_is_qca953x() || soc_is_qca955x() || soc_is_qca956x())
+ 		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s ver %u rev %u",
+ 			chip, ver, rev);
++	else if (soc_is_tp9343())
++		sprintf(ath79_sys_type, "Qualcomm Atheros TP%s rev %u",
++			chip, rev);
+ 	else
+ 		sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
+ 	pr_info("SoC: %s\n", ath79_sys_type);
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -143,6 +143,23 @@
+ #define QCA955X_NFC_BASE	0x1b800200
+ #define QCA955X_NFC_SIZE	0xb8
+ 
++#define QCA956X_PCI_MEM_BASE1	0x12000000
++#define QCA956X_PCI_MEM_SIZE	0x02000000
++#define QCA956X_PCI_CFG_BASE1	0x16000000
++#define QCA956X_PCI_CFG_SIZE	0x1000
++#define QCA956X_PCI_CRP_BASE1	(AR71XX_APB_BASE + 0x00250000)
++#define QCA956X_PCI_CRP_SIZE	0x1000
++#define QCA956X_PCI_CTRL_BASE1	(AR71XX_APB_BASE + 0x00280000)
++#define QCA956X_PCI_CTRL_SIZE	0x100
++
++#define QCA956X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
++#define QCA956X_WMAC_SIZE	0x20000
++#define QCA956X_EHCI0_BASE	0x1b000000
++#define QCA956X_EHCI1_BASE	0x1b400000
++#define QCA956X_EHCI_SIZE	0x200
++#define QCA956X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
++#define QCA956X_GMAC_SIZE	0x64
++
+ #define AR9300_OTP_BASE		0x14000
+ #define AR9300_OTP_STATUS	0x15f18
+ #define AR9300_OTP_STATUS_TYPE		0x7
+@@ -152,6 +169,13 @@
+ #define AR9300_OTP_READ_DATA	0x15f1c
+ 
+ /*
++ * Hidden Registers
++ */
++#define QCA956X_DAM_RESET_OFFSET	0xb90001bc
++#define QCA956X_DAM_RESET_SIZE		0x4
++#define QCA956X_INLINE_CHKSUM_ENG	BIT(27)
++
++/*
+  * DDR_CTRL block
+  */
+ #define AR71XX_DDR_REG_PCI_WIN0		0x7c
+@@ -375,6 +399,49 @@
+ #define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+ #define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+ 
++#define QCA956X_PLL_CPU_CONFIG_REG			0x00
++#define QCA956X_PLL_CPU_CONFIG1_REG			0x04
++#define QCA956X_PLL_DDR_CONFIG_REG			0x08
++#define QCA956X_PLL_DDR_CONFIG1_REG			0x0c
++#define QCA956X_PLL_CLK_CTRL_REG			0x10
++
++#define QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
++#define QCA956X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
++#define QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
++#define QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
++
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT		0
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK		0x1f
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT		5
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK		0x1fff
++#define QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT		18
++#define QCA956X_PLL_CPU_CONFIG1_NINT_MASK		0x1ff
++
++#define QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
++#define QCA956X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
++#define QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
++#define QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
++
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT		0
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK		0x1f
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT		5
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK		0x1fff
++#define QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT		18
++#define QCA956X_PLL_DDR_CONFIG1_NINT_MASK		0x1ff
++
++#define QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
++#define QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
++#define QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
++#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
++#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
++#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
++#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
++#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
++#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
++#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL	BIT(20)
++#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL	BIT(21)
++#define QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
++
+ /*
+  * USB_CONFIG block
+  */
+@@ -422,6 +489,11 @@
+ #define QCA955X_RESET_REG_BOOTSTRAP		0xb0
+ #define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
+ 
++#define QCA956X_RESET_REG_RESET_MODULE		0x1c
++#define QCA956X_RESET_REG_BOOTSTRAP		0xb0
++#define QCA956X_RESET_REG_EXT_INT_STATUS	0xac
++
++#define MISC_INT_MIPS_SI_TIMERINT_MASK	BIT(28)
+ #define MISC_INT_ETHSW			BIT(12)
+ #define MISC_INT_TIMER4			BIT(10)
+ #define MISC_INT_TIMER3			BIT(9)
+@@ -596,6 +668,8 @@
+ 
+ #define QCA955X_BOOTSTRAP_REF_CLK_40	BIT(4)
+ 
++#define QCA956X_BOOTSTRAP_REF_CLK_40	BIT(2)
++
+ #define AR934X_PCIE_WMAC_INT_WMAC_MISC		BIT(0)
+ #define AR934X_PCIE_WMAC_INT_WMAC_TX		BIT(1)
+ #define AR934X_PCIE_WMAC_INT_WMAC_RXLP		BIT(2)
+@@ -663,6 +737,37 @@
+ 	 QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \
+ 	 QCA955X_EXT_INT_PCIE_RC2_INT3)
+ 
++#define QCA956X_EXT_INT_WMAC_MISC		BIT(0)
++#define QCA956X_EXT_INT_WMAC_TX			BIT(1)
++#define QCA956X_EXT_INT_WMAC_RXLP		BIT(2)
++#define QCA956X_EXT_INT_WMAC_RXHP		BIT(3)
++#define QCA956X_EXT_INT_PCIE_RC1		BIT(4)
++#define QCA956X_EXT_INT_PCIE_RC1_INT0		BIT(5)
++#define QCA956X_EXT_INT_PCIE_RC1_INT1		BIT(6)
++#define QCA956X_EXT_INT_PCIE_RC1_INT2		BIT(7)
++#define QCA956X_EXT_INT_PCIE_RC1_INT3		BIT(8)
++#define QCA956X_EXT_INT_PCIE_RC2		BIT(12)
++#define QCA956X_EXT_INT_PCIE_RC2_INT0		BIT(13)
++#define QCA956X_EXT_INT_PCIE_RC2_INT1		BIT(14)
++#define QCA956X_EXT_INT_PCIE_RC2_INT2		BIT(15)
++#define QCA956X_EXT_INT_PCIE_RC2_INT3		BIT(16)
++#define QCA956X_EXT_INT_USB1			BIT(24)
++#define QCA956X_EXT_INT_USB2			BIT(28)
++
++#define QCA956X_EXT_INT_WMAC_ALL \
++	(QCA956X_EXT_INT_WMAC_MISC | QCA956X_EXT_INT_WMAC_TX | \
++	 QCA956X_EXT_INT_WMAC_RXLP | QCA956X_EXT_INT_WMAC_RXHP)
++
++#define QCA956X_EXT_INT_PCIE_RC1_ALL \
++	(QCA956X_EXT_INT_PCIE_RC1 | QCA956X_EXT_INT_PCIE_RC1_INT0 | \
++	 QCA956X_EXT_INT_PCIE_RC1_INT1 | QCA956X_EXT_INT_PCIE_RC1_INT2 | \
++	 QCA956X_EXT_INT_PCIE_RC1_INT3)
++
++#define QCA956X_EXT_INT_PCIE_RC2_ALL \
++	(QCA956X_EXT_INT_PCIE_RC2 | QCA956X_EXT_INT_PCIE_RC2_INT0 | \
++	 QCA956X_EXT_INT_PCIE_RC2_INT1 | QCA956X_EXT_INT_PCIE_RC2_INT2 | \
++	 QCA956X_EXT_INT_PCIE_RC2_INT3)
++
+ #define REV_ID_MAJOR_MASK		0xfff0
+ #define REV_ID_MAJOR_AR71XX		0x00a0
+ #define REV_ID_MAJOR_AR913X		0x00b0
+@@ -678,6 +783,8 @@
+ #define REV_ID_MAJOR_QCA9533_V2		0x0160
+ #define REV_ID_MAJOR_QCA9556		0x0130
+ #define REV_ID_MAJOR_QCA9558		0x1130
++#define REV_ID_MAJOR_TP9343		0x0150
++#define REV_ID_MAJOR_QCA956X		0x1150
+ 
+ #define AR71XX_REV_ID_MINOR_MASK	0x3
+ #define AR71XX_REV_ID_MINOR_AR7130	0x0
+@@ -702,6 +809,8 @@
+ 
+ #define QCA955X_REV_ID_REVISION_MASK	0xf
+ 
++#define QCA956X_REV_ID_REVISION_MASK	0xf
++
+ /*
+  * SPI block
+  */
+@@ -774,6 +883,19 @@
+ #define QCA955X_GPIO_REG_OUT_FUNC5	0x40
+ #define QCA955X_GPIO_REG_FUNC		0x6c
+ 
++#define QCA956X_GPIO_REG_OUT_FUNC0	0x2c
++#define QCA956X_GPIO_REG_OUT_FUNC1	0x30
++#define QCA956X_GPIO_REG_OUT_FUNC2	0x34
++#define QCA956X_GPIO_REG_OUT_FUNC3	0x38
++#define QCA956X_GPIO_REG_OUT_FUNC4	0x3c
++#define QCA956X_GPIO_REG_OUT_FUNC5	0x40
++#define QCA956X_GPIO_REG_IN_ENABLE0	0x44
++#define QCA956X_GPIO_REG_IN_ENABLE3	0x50
++#define QCA956X_GPIO_REG_FUNC		0x6c
++
++#define QCA956X_GPIO_OUT_MUX_GE0_MDO	32
++#define QCA956X_GPIO_OUT_MUX_GE0_MDC	33
++
+ #define AR71XX_GPIO_COUNT		16
+ #define AR7240_GPIO_COUNT		18
+ #define AR7241_GPIO_COUNT		20
+@@ -782,6 +904,7 @@
+ #define AR934X_GPIO_COUNT		23
+ #define QCA953X_GPIO_COUNT		18
+ #define QCA955X_GPIO_COUNT		24
++#define QCA956X_GPIO_COUNT		23
+ 
+ /*
+  * SRIF block
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -35,6 +35,8 @@ enum ath79_soc_type {
+ 	ATH79_SOC_QCA9533,
+ 	ATH79_SOC_QCA9556,
+ 	ATH79_SOC_QCA9558,
++	ATH79_SOC_TP9343,
++	ATH79_SOC_QCA956X,
+ };
+ 
+ extern enum ath79_soc_type ath79_soc;
+@@ -126,6 +128,26 @@ static inline int soc_is_qca955x(void)
+ 	return soc_is_qca9556() || soc_is_qca9558();
+ }
+ 
++static inline int soc_is_tp9343(void)
++{
++	return ath79_soc == ATH79_SOC_TP9343;
++}
++
++static inline int soc_is_qca9561(void)
++{
++	return ath79_soc == ATH79_SOC_QCA956X;
++}
++
++static inline int soc_is_qca9563(void)
++{
++	return ath79_soc == ATH79_SOC_QCA956X;
++}
++
++static inline int soc_is_qca956x(void)
++{
++	return soc_is_qca9561() || soc_is_qca9563();
++}
++
+ void ath79_ddr_set_pci_windows(void);
+ 
+ extern void __iomem *ath79_gpio_base;
diff --git a/target/linux/ar71xx/patches-4.4/630-MIPS-ath79-fix-chained-irq-disable.patch b/target/linux/ar71xx/patches-4.4/630-MIPS-ath79-fix-chained-irq-disable.patch
new file mode 100644
index 0000000000..63b91ddc0e
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/630-MIPS-ath79-fix-chained-irq-disable.patch
@@ -0,0 +1,102 @@
+--- a/arch/mips/ath79/irq.c
++++ b/arch/mips/ath79/irq.c
+@@ -26,6 +26,9 @@
+ #include "common.h"
+ #include "machtypes.h"
+ 
++static struct irq_chip ip2_chip;
++static struct irq_chip ip3_chip;
++
+ static void ath79_misc_irq_handler(struct irq_desc *desc)
+ {
+ 	void __iomem *base = ath79_reset_base;
+@@ -145,8 +148,7 @@ static void ar934x_ip2_irq_init(void)
+ 
+ 	for (i = ATH79_IP2_IRQ_BASE;
+ 	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
+-		irq_set_chip_and_handler(i, &dummy_irq_chip,
+-					 handle_level_irq);
++		irq_set_chip_and_handler(i, &ip2_chip, handle_level_irq);
+ 
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch);
+ }
+@@ -174,7 +176,7 @@ static void qca953x_irq_init(void)
+ 
+ 	for (i = ATH79_IP2_IRQ_BASE;
+ 	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
+-		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq);
++		irq_set_chip_and_handler(i, &ip2_chip, handle_level_irq);
+ 
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(2), qca953x_ip2_irq_dispatch);
+ }
+@@ -238,15 +240,13 @@ static void qca955x_irq_init(void)
+ 
+ 	for (i = ATH79_IP2_IRQ_BASE;
+ 	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
+-		irq_set_chip_and_handler(i, &dummy_irq_chip,
+-					 handle_level_irq);
++		irq_set_chip_and_handler(i, &ip2_chip, handle_level_irq);
+ 
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(2), qca955x_ip2_irq_dispatch);
+ 
+ 	for (i = ATH79_IP3_IRQ_BASE;
+ 	     i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++)
+-		irq_set_chip_and_handler(i, &dummy_irq_chip,
+-					 handle_level_irq);
++		irq_set_chip_and_handler(i, &ip3_chip, handle_level_irq);
+ 
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
+ }
+@@ -331,13 +331,13 @@ static void qca956x_irq_init(void)
+ 
+ 	for (i = ATH79_IP2_IRQ_BASE;
+ 	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
+-		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq);
++		irq_set_chip_and_handler(i, &ip2_chip, handle_level_irq);
+ 
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(2), qca956x_ip2_irq_dispatch);
+ 
+ 	for (i = ATH79_IP3_IRQ_BASE;
+ 	     i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++)
+-		irq_set_chip_and_handler(i, &dummy_irq_chip, handle_level_irq);
++		irq_set_chip_and_handler(i, &ip3_chip, handle_level_irq);
+ 
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(3), qca956x_ip3_irq_dispatch);
+ 
+@@ -463,8 +463,36 @@ IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar71
+ 
+ #endif
+ 
++static void ath79_ip2_disable(struct irq_data *data)
++{
++	disable_irq(ATH79_CPU_IRQ(2));
++}
++
++static void ath79_ip2_enable(struct irq_data *data)
++{
++	enable_irq(ATH79_CPU_IRQ(2));
++}
++
++static void ath79_ip3_disable(struct irq_data *data)
++{
++	disable_irq(ATH79_CPU_IRQ(3));
++}
++
++static void ath79_ip3_enable(struct irq_data *data)
++{
++	enable_irq(ATH79_CPU_IRQ(3));
++}
++
+ void __init arch_init_irq(void)
+ {
++	ip2_chip = dummy_irq_chip;
++	ip2_chip.irq_disable = ath79_ip2_disable;
++	ip2_chip.irq_enable = ath79_ip2_enable;
++
++	ip3_chip = dummy_irq_chip;
++	ip3_chip.irq_disable = ath79_ip3_disable;
++	ip3_chip.irq_enable = ath79_ip3_enable;
++
+ 	if (mips_machtype == ATH79_MACH_GENERIC_OF) {
+ 		irqchip_init();
+ 		return;
diff --git a/target/linux/ar71xx/patches-4.4/631-MIPS-ath79-wmac-enable-set-led-pin.patch b/target/linux/ar71xx/patches-4.4/631-MIPS-ath79-wmac-enable-set-led-pin.patch
new file mode 100644
index 0000000000..16a0b909c5
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/631-MIPS-ath79-wmac-enable-set-led-pin.patch
@@ -0,0 +1,24 @@
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -400,6 +400,11 @@ void __init ath79_wmac_set_ext_lna_gpio(
+ 		ar934x_set_ext_lna_gpio(chain, gpio);
+ }
+ 
++void __init ath79_wmac_set_led_pin(int gpio)
++{
++	ath79_wmac_data.led_pin = gpio;
++}
++
+ void __init ath79_register_wmac(u8 *cal_data, u8 *mac_addr)
+ {
+ 	if (soc_is_ar913x())
+--- a/arch/mips/ath79/dev-wmac.h
++++ b/arch/mips/ath79/dev-wmac.h
+@@ -18,6 +18,7 @@ void ath79_wmac_disable_2ghz(void);
+ void ath79_wmac_disable_5ghz(void);
+ void ath79_wmac_set_tx_gain_buffalo(void);
+ void ath79_wmac_set_ext_lna_gpio(unsigned chain, int gpio);
++void ath79_wmac_set_led_pin(int gpio);
+ 
+ bool ar93xx_wmac_read_mac_address(u8 *dest);
+ 
diff --git a/target/linux/ar71xx/patches-4.4/632-MIPS-ath79-gpio-enable-set-direction.patch b/target/linux/ar71xx/patches-4.4/632-MIPS-ath79-gpio-enable-set-direction.patch
new file mode 100644
index 0000000000..0a6be75088
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/632-MIPS-ath79-gpio-enable-set-direction.patch
@@ -0,0 +1,32 @@
+--- a/arch/mips/ath79/common.h
++++ b/arch/mips/ath79/common.h
+@@ -29,6 +29,7 @@ void ath79_gpio_function_enable(u32 mask
+ void ath79_gpio_function_disable(u32 mask);
+ void ath79_gpio_function_setup(u32 set, u32 clear);
+ void ath79_gpio_output_select(unsigned gpio, u8 val);
++int ath79_gpio_direction_select(unsigned gpio, bool oe);
+ void ath79_gpio_init(void);
+ 
+ #endif /* __ATH79_COMMON_H */
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -83,3 +83,19 @@ void __init ath79_gpio_output_select(uns
+ 	/* flush write */
+ 	(void) __raw_readl(base + reg);
+ }
++
++int ath79_gpio_direction_select(unsigned gpio, bool oe)
++{
++	void __iomem *base = ath79_gpio_base;
++	bool ieq_1 = (soc_is_ar934x() ||
++			soc_is_qca953x());
++
++	if ((ieq_1 && oe) || (!ieq_1 && !oe))
++		__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << gpio),
++				base + AR71XX_GPIO_REG_OE);
++	else
++		__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << gpio),
++				base + AR71XX_GPIO_REG_OE);
++
++	return 0;
++}
diff --git a/target/linux/ar71xx/patches-4.4/634-MIPS-ath79-ar724x-clock-calculation-fixes.patch b/target/linux/ar71xx/patches-4.4/634-MIPS-ath79-ar724x-clock-calculation-fixes.patch
new file mode 100644
index 0000000000..90149ef187
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/634-MIPS-ath79-ar724x-clock-calculation-fixes.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/ath79/clock.c
++++ b/arch/mips/ath79/clock.c
+@@ -26,7 +26,7 @@
+ #include "common.h"
+ 
+ #define AR71XX_BASE_FREQ	40000000
+-#define AR724X_BASE_FREQ	5000000
++#define AR724X_BASE_FREQ	40000000
+ #define AR913X_BASE_FREQ	5000000
+ 
+ static struct clk *clks[3];
+@@ -103,8 +103,8 @@ static void __init ar724x_clocks_init(vo
+ 	div = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK);
+ 	freq = div * ref_rate;
+ 
+-	div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
+-	freq *= div;
++	div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK) * 2;
++	freq /= div;
+ 
+ 	cpu_rate = freq;
+ 
diff --git a/target/linux/ar71xx/patches-4.4/640-MIPS-ath79-add-QCA955x-wmac-reset.patch b/target/linux/ar71xx/patches-4.4/640-MIPS-ath79-add-QCA955x-wmac-reset.patch
new file mode 100644
index 0000000000..8c2e6051cb
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/640-MIPS-ath79-add-QCA955x-wmac-reset.patch
@@ -0,0 +1,82 @@
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -39,7 +39,7 @@ unsigned int ath79_soc_rev;
+ void __iomem *ath79_pll_base;
+ void __iomem *ath79_reset_base;
+ EXPORT_SYMBOL_GPL(ath79_reset_base);
+-static void __iomem *ath79_ddr_base;
++void __iomem *ath79_ddr_base;
+ static void __iomem *ath79_ddr_wb_flush_base;
+ static void __iomem *ath79_ddr_pci_win_base;
+ 
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -32,7 +32,7 @@
+ #define AR71XX_SPI_SIZE		0x01000000
+ 
+ #define AR71XX_DDR_CTRL_BASE	(AR71XX_APB_BASE + 0x00000000)
+-#define AR71XX_DDR_CTRL_SIZE	0x100
++#define AR71XX_DDR_CTRL_SIZE	0x200
+ #define AR71XX_UART_BASE	(AR71XX_APB_BASE + 0x00020000)
+ #define AR71XX_UART_SIZE	0x100
+ #define AR71XX_USB_CTRL_BASE	(AR71XX_APB_BASE + 0x00030000)
+@@ -218,6 +218,9 @@
+ #define QCA953X_DDR_REG_FLUSH_PCIE	0xa8
+ #define QCA953X_DDR_REG_FLUSH_WMAC	0xac
+ 
++#define QCA955X_DDR_CTL_CONFIG		0x108
++#define QCA955X_DDR_CTL_CONFIG_ACT_WMAC	BIT(23)
++
+ /*
+  * PLL block
+  */
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -171,6 +171,27 @@ static void qca953x_wmac_setup(void)
+ 	ath79_wmac_data.get_mac_revision = ar93xx_get_soc_revision;
+ }
+ 
++static int ar955x_wmac_reset(void)
++{
++	int i;
++
++	/* Try to wait for WMAC DDR activity to stop */
++	for (i = 0; i < 10; i++) {
++		if (!(__raw_readl(ath79_ddr_base + QCA955X_DDR_CTL_CONFIG) &
++		      QCA955X_DDR_CTL_CONFIG_ACT_WMAC))
++			break;
++
++		udelay(10);
++	}
++
++	ath79_device_reset_set(QCA955X_RESET_RTC);
++	udelay(10);
++	ath79_device_reset_clear(QCA955X_RESET_RTC);
++	udelay(10);
++
++	return 0;
++}
++
+ static void qca955x_wmac_setup(void)
+ {
+ 	u32 t;
+@@ -187,6 +208,8 @@ static void qca955x_wmac_setup(void)
+ 		ath79_wmac_data.is_clk_25mhz = false;
+ 	else
+ 		ath79_wmac_data.is_clk_25mhz = true;
++
++	ath79_wmac_data.external_reset = ar955x_wmac_reset;
+ }
+ 
+ static void qca956x_wmac_setup(void)
+--- a/arch/mips/ath79/common.h
++++ b/arch/mips/ath79/common.h
+@@ -19,6 +19,8 @@
+ #define ATH79_MEM_SIZE_MIN	(2 * 1024 * 1024)
+ #define ATH79_MEM_SIZE_MAX	(256 * 1024 * 1024)
+ 
++extern void __iomem *ath79_ddr_base;
++
+ void ath79_clocks_init(void);
+ unsigned long ath79_get_sys_clk_rate(const char *id);
+ 
diff --git a/target/linux/ar71xx/patches-4.4/700-MIPS-ath79-add-openwrt-Kconfig.patch b/target/linux/ar71xx/patches-4.4/700-MIPS-ath79-add-openwrt-Kconfig.patch
new file mode 100644
index 0000000000..c2bd2ea2b7
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/700-MIPS-ath79-add-openwrt-Kconfig.patch
@@ -0,0 +1,11 @@
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -95,6 +95,8 @@ choice
+ 		select SOC_AR913X
+ endchoice
+ 
++source "arch/mips/ath79/Kconfig.openwrt"
++
+ endmenu
+ 
+ config SOC_AR71XX
diff --git a/target/linux/ar71xx/patches-4.4/701-MIPS-ath79-add-routerboard-detection.patch b/target/linux/ar71xx/patches-4.4/701-MIPS-ath79-add-routerboard-detection.patch
new file mode 100644
index 0000000000..77bf38cc00
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/701-MIPS-ath79-add-routerboard-detection.patch
@@ -0,0 +1,19 @@
+--- a/arch/mips/ath79/prom.c
++++ b/arch/mips/ath79/prom.c
+@@ -136,6 +136,16 @@ void __init prom_init(void)
+ 		initrd_end = initrd_start + fw_getenvl("initrd_size");
+ 	}
+ #endif
++
++	if (strstr(arcs_cmdline, "board=750Gr3") ||
++	    strstr(arcs_cmdline, "board=750i") ||
++	    strstr(arcs_cmdline, "board=450") ||
++	    strstr(arcs_cmdline, "board=493") ||
++	    strstr(arcs_cmdline, "board=951G") ||
++	    strstr(arcs_cmdline, "board=2011L") ||
++	    strstr(arcs_cmdline, "board=711Gr100") ||
++	    strstr(arcs_cmdline, "board=922gs"))
++		ath79_prom_append_cmdline("console", "ttyS0,115200");
+ }
+ 
+ void __init prom_free_prom_memory(void)
diff --git a/target/linux/ar71xx/patches-4.4/739-MIPS-ath79-add-gpio-func-register-for-QCA955x-SoC.patch b/target/linux/ar71xx/patches-4.4/739-MIPS-ath79-add-gpio-func-register-for-QCA955x-SoC.patch
new file mode 100644
index 0000000000..a65f7d993f
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/739-MIPS-ath79-add-gpio-func-register-for-QCA955x-SoC.patch
@@ -0,0 +1,38 @@
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -33,6 +33,7 @@ static void __iomem *ath79_gpio_get_func
+ 		reg = AR71XX_GPIO_REG_FUNC;
+ 	else if (soc_is_ar934x() ||
+ 		 soc_is_qca953x() ||
++		 soc_is_qca955x() ||
+ 		 soc_is_qca956x() ||
+ 		 soc_is_tp9343())
+ 		reg = AR934X_GPIO_REG_FUNC;
+@@ -64,15 +65,21 @@ void ath79_gpio_function_disable(u32 mas
+ void __init ath79_gpio_output_select(unsigned gpio, u8 val)
+ {
+ 	void __iomem *base = ath79_gpio_base;
+-	unsigned int reg;
++	unsigned int reg, reg_base;
+ 	u32 t, s;
+ 
+-	BUG_ON(!soc_is_ar934x() && !soc_is_qca953x() && !soc_is_qca956x());
+-
+-	if (gpio >= AR934X_GPIO_COUNT)
+-		return;
++	if (soc_is_ar934x())
++		reg_base = AR934X_GPIO_REG_OUT_FUNC0;
++	else if (soc_is_qca953x())
++		reg_base = QCA953X_GPIO_REG_OUT_FUNC0;
++	else if (soc_is_qca955x())
++		reg_base = QCA955X_GPIO_REG_OUT_FUNC0;
++	else if (soc_is_qca956x())
++		reg_base = QCA956X_GPIO_REG_OUT_FUNC0;
++	else
++		BUG();
+ 
+-	reg = AR934X_GPIO_REG_OUT_FUNC0 + 4 * (gpio / 4);
++	reg = reg_base + 4 * (gpio / 4);
+ 	s = 8 * (gpio % 4);
+ 
+ 	t = __raw_readl(base + reg);
diff --git a/target/linux/ar71xx/patches-4.4/740-MIPS-ath79-add-PCI-for-QCA953x-SoC.patch b/target/linux/ar71xx/patches-4.4/740-MIPS-ath79-add-PCI-for-QCA953x-SoC.patch
new file mode 100644
index 0000000000..a57351efde
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/740-MIPS-ath79-add-PCI-for-QCA953x-SoC.patch
@@ -0,0 +1,44 @@
+--- a/arch/mips/ath79/pci.c
++++ b/arch/mips/ath79/pci.c
+@@ -53,6 +53,15 @@ static const struct ath79_pci_irq ar724x
+ 	}
+ };
+ 
++static const struct ath79_pci_irq qca953x_pci_irq_map[] __initconst = {
++	{
++		.bus	= 0,
++		.slot	= 0,
++		.pin	= 1,
++		.irq	= ATH79_PCI_IRQ(0),
++	},
++};
++
+ static const struct ath79_pci_irq qca955x_pci_irq_map[] __initconst = {
+ 	{
+ 		.bus	= 0,
+@@ -98,6 +107,9 @@ int __init pcibios_map_irq(const struct
+ 			   soc_is_ar9344()) {
+ 			ath79_pci_irq_map = ar724x_pci_irq_map;
+ 			ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map);
++		} else if (soc_is_qca953x()) {
++			ath79_pci_irq_map = qca953x_pci_irq_map;
++			ath79_pci_nr_irqs = ARRAY_SIZE(qca953x_pci_irq_map);
+ 		} else if (soc_is_qca955x()) {
+ 			ath79_pci_irq_map = qca955x_pci_irq_map;
+ 			ath79_pci_nr_irqs = ARRAY_SIZE(qca955x_pci_irq_map);
+@@ -303,6 +315,15 @@ int __init ath79_register_pci(void)
+ 						 AR724X_PCI_MEM_SIZE,
+ 						 0,
+ 						 ATH79_IP2_IRQ(0));
++	} else if (soc_is_qca9533()) {
++		pdev = ath79_register_pci_ar724x(0,
++						 QCA953X_PCI_CFG_BASE0,
++						 QCA953X_PCI_CTRL_BASE0,
++						 QCA953X_PCI_CRP_BASE0,
++						 QCA953X_PCI_MEM_BASE0,
++						 QCA953X_PCI_MEM_SIZE,
++						 0,
++						 ATH79_IP2_IRQ(0));
+ 	} else if (soc_is_qca9558()) {
+ 		pdev = ath79_register_pci_ar724x(0,
+ 						 QCA955X_PCI_CFG_BASE0,
diff --git a/target/linux/ar71xx/patches-4.4/818-MIPS-ath79-add-nu801-led-driver.patch b/target/linux/ar71xx/patches-4.4/818-MIPS-ath79-add-nu801-led-driver.patch
new file mode 100644
index 0000000000..420bbff185
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/818-MIPS-ath79-add-nu801-led-driver.patch
@@ -0,0 +1,26 @@
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -568,6 +568,13 @@ config LEDS_SEAD3
+ 
+ comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
+ 
++config LEDS_NU801
++	tristate "LED driver for NU801 RGB LED"
++	depends on LEDS_CLASS && (ATH79_MACH_MR18 || ATH79_MACH_Z1)
++	help
++	  This option enables support for NU801 RGB LED driver chips
++	  accessed via GPIO.
++
+ config LEDS_BLINKM
+ 	tristate "LED support for the BlinkM I2C RGB LED"
+ 	depends on LEDS_CLASS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -55,6 +55,7 @@ obj-$(CONFIG_LEDS_ADP5520)		+= leds-adp5
+ obj-$(CONFIG_LEDS_DELL_NETBOOKS)	+= dell-led.o
+ obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
+ obj-$(CONFIG_LEDS_RB750)		+= leds-rb750.o
++obj-$(CONFIG_LEDS_NU801)		+= leds-nu801.o
+ obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
+ obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
+ obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
diff --git a/target/linux/ar71xx/patches-4.4/820-MIPS-ath79-add_gpio_function2_setup.patch b/target/linux/ar71xx/patches-4.4/820-MIPS-ath79-add_gpio_function2_setup.patch
new file mode 100644
index 0000000000..7db6ad361f
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/820-MIPS-ath79-add_gpio_function2_setup.patch
@@ -0,0 +1,67 @@
+Add access to the function2 gpio register. This probably has to be
+converted into a pimux driver later on. This is needed for some setup
+functions on the Arduino Yun.
+
+--- a/arch/mips/ath79/common.h
++++ b/arch/mips/ath79/common.h
+@@ -30,6 +30,7 @@ void ath79_ddr_wb_flush(unsigned int reg
+ void ath79_gpio_function_enable(u32 mask);
+ void ath79_gpio_function_disable(u32 mask);
+ void ath79_gpio_function_setup(u32 set, u32 clear);
++void ath79_gpio_function2_setup(u32 set, u32 clear);
+ void ath79_gpio_output_select(unsigned gpio, u8 val);
+ int ath79_gpio_direction_select(unsigned gpio, bool oe);
+ void ath79_gpio_init(void);
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -43,6 +43,31 @@ static void __iomem *ath79_gpio_get_func
+ 	return ath79_gpio_base + reg;
+ }
+ 
++static void __iomem *ath79_gpio_get_function2_reg(void)
++{
++	u32 reg = 0;
++
++	if (soc_is_ar71xx() ||
++	    soc_is_ar724x() ||
++	    soc_is_ar913x() ||
++	    soc_is_ar933x())
++		reg = AR71XX_GPIO_REG_FUNC_2;
++	else
++		BUG();
++
++	return ath79_gpio_base + reg;
++}
++
++
++void ath79_gpio_function2_setup(u32 set, u32 clear)
++{
++	void __iomem *reg = ath79_gpio_get_function2_reg();
++
++	__raw_writel((__raw_readl(reg) & ~clear) | set, reg);
++	/* flush write */
++	__raw_readl(reg);
++}
++
+ void ath79_gpio_function_setup(u32 set, u32 clear)
+ {
+ 	void __iomem *reg = ath79_gpio_get_function_reg();
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -850,6 +850,7 @@
+ #define AR71XX_GPIO_REG_INT_PENDING	0x20
+ #define AR71XX_GPIO_REG_INT_ENABLE	0x24
+ #define AR71XX_GPIO_REG_FUNC		0x28
++#define AR71XX_GPIO_REG_FUNC_2		0x30
+ 
+ #define AR934X_GPIO_REG_OUT_FUNC0	0x2c
+ #define AR934X_GPIO_REG_OUT_FUNC1	0x30
+@@ -974,6 +975,8 @@
+ #define AR724X_GPIO_FUNC_UART_EN		BIT(1)
+ #define AR724X_GPIO_FUNC_JTAG_DISABLE		BIT(0)
+ 
++#define AR933X_GPIO_FUNC2_JUMPSTART_DISABLE 	BIT(9)
++
+ #define AR913X_GPIO_FUNC_WMAC_LED_EN		BIT(22)
+ #define AR913X_GPIO_FUNC_EXP_PORT_CS_EN		BIT(21)
+ #define AR913X_GPIO_FUNC_I2S_REFCLKEN		BIT(20)
diff --git a/target/linux/ar71xx/patches-4.4/821-serial-core-add-support-for-boot-console-with-arbitr.patch b/target/linux/ar71xx/patches-4.4/821-serial-core-add-support-for-boot-console-with-arbitr.patch
new file mode 100644
index 0000000000..9d6e7bca05
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/821-serial-core-add-support-for-boot-console-with-arbitr.patch
@@ -0,0 +1,76 @@
+From 4d3c17975c7814884a721fe693b3adf5c426d759 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Tue, 10 Nov 2015 22:18:39 +0100
+Subject: [RFC] serial: core: add support for boot console with arbitrary
+ baud rates
+
+The Arduino Yun uses a baud rate of 250000 by default. The serial is
+going over the Atmel ATmega and is used to connect to this chip.
+Without this patch Linux wants to switch the console to 230400 Baud.
+
+With this patch Linux will use the configured baud rate and not some
+standard one which is near by.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/tty/serial/serial_core.c | 13 ++++++++++---
+ include/linux/console.h          |  1 +
+ 2 files changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -164,6 +164,8 @@ static int uart_port_startup(struct tty_
+ 	if (retval == 0) {
+ 		if (uart_console(uport) && uport->cons->cflag) {
+ 			tty->termios.c_cflag = uport->cons->cflag;
++			tty->termios.c_ospeed = uport->cons->baud;
++			tty->termios.c_ispeed = uport->cons->baud;
+ 			uport->cons->cflag = 0;
+ 		}
+ 		/*
+@@ -1909,7 +1911,7 @@ static const struct baud_rates baud_rate
+ 	{   4800, B4800   },
+ 	{   2400, B2400   },
+ 	{   1200, B1200   },
+-	{      0, B38400  }
++	{      0, BOTHER  }
+ };
+ 
+ /**
+@@ -1948,10 +1950,13 @@ uart_set_options(struct uart_port *port,
+ 	 * Construct a cflag setting.
+ 	 */
+ 	for (i = 0; baud_rates[i].rate; i++)
+-		if (baud_rates[i].rate <= baud)
++		if (baud_rates[i].rate == baud)
+ 			break;
+ 
+ 	termios.c_cflag |= baud_rates[i].cflag;
++	if (!baud_rates[i].rate) {
++		termios.c_ospeed = baud;
++	}
+ 
+ 	if (bits == 7)
+ 		termios.c_cflag |= CS7;
+@@ -1981,8 +1986,10 @@ uart_set_options(struct uart_port *port,
+ 	 * Allow the setting of the UART parameters with a NULL console
+ 	 * too:
+ 	 */
+-	if (co)
++	if (co) {
+ 		co->cflag = termios.c_cflag;
++		co->baud = baud;
++	}
+ 
+ 	return 0;
+ }
+--- a/include/linux/console.h
++++ b/include/linux/console.h
+@@ -128,6 +128,7 @@ struct console {
+ 	short	flags;
+ 	short	index;
+ 	int	cflag;
++	int	baud;
+ 	void	*data;
+ 	struct	 console *next;
+ };
diff --git a/target/linux/ar71xx/patches-4.4/900-mdio_bitbang_ignore_ta_value.patch b/target/linux/ar71xx/patches-4.4/900-mdio_bitbang_ignore_ta_value.patch
new file mode 100644
index 0000000000..4536d519f8
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/900-mdio_bitbang_ignore_ta_value.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/mdio-bitbang.c
++++ b/drivers/net/phy/mdio-bitbang.c
+@@ -165,19 +165,7 @@ static int mdiobb_read(struct mii_bus *b
+ 
+ 	ctrl->ops->set_mdio_dir(ctrl, 0);
+ 
+-	/* check the turnaround bit: the PHY should be driving it to zero, if this
+-	 * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that
+-	 */
+-	if (mdiobb_get_bit(ctrl) != 0 &&
+-	    !(bus->phy_ignore_ta_mask & (1 << phy))) {
+-		/* PHY didn't drive TA low -- flush any bits it
+-		 * may be trying to send.
+-		 */
+-		for (i = 0; i < 32; i++)
+-			mdiobb_get_bit(ctrl);
+-
+-		return 0xffff;
+-	}
++	mdiobb_get_bit(ctrl);
+ 
+ 	ret = mdiobb_get_num(ctrl, 16);
+ 	mdiobb_get_bit(ctrl);
diff --git a/target/linux/ar71xx/patches-4.4/901-phy-mdio-bitbang-prevent-rescheduling-during-command.patch b/target/linux/ar71xx/patches-4.4/901-phy-mdio-bitbang-prevent-rescheduling-during-command.patch
new file mode 100644
index 0000000000..68f86e0e09
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/901-phy-mdio-bitbang-prevent-rescheduling-during-command.patch
@@ -0,0 +1,61 @@
+From 66e584435ac0de6e0abeb6d7166fe4fe25d6bb73 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Tue, 16 Jun 2015 13:15:08 +0200
+Subject: [PATCH] phy/mdio-bitbang: prevent rescheduling during command
+
+It seems some phys have some maximum timings for accessing the MDIO line,
+resulting in bit errors under cpu stress. Prevent this from happening by
+disabling interrupts when sending commands.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ drivers/net/phy/mdio-bitbang.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/phy/mdio-bitbang.c
++++ b/drivers/net/phy/mdio-bitbang.c
+@@ -17,6 +17,7 @@
+  * kind, whether express or implied.
+  */
+ 
++#include <linux/irqflags.h>
+ #include <linux/module.h>
+ #include <linux/mdio-bitbang.h>
+ #include <linux/types.h>
+@@ -156,7 +157,9 @@ static int mdiobb_read(struct mii_bus *b
+ {
+ 	struct mdiobb_ctrl *ctrl = bus->priv;
+ 	int ret, i;
++	long flags;
+ 
++	local_irq_save(flags);
+ 	if (reg & MII_ADDR_C45) {
+ 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+ 		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+@@ -169,13 +172,17 @@ static int mdiobb_read(struct mii_bus *b
+ 
+ 	ret = mdiobb_get_num(ctrl, 16);
+ 	mdiobb_get_bit(ctrl);
++	local_irq_restore(flags);
++
+ 	return ret;
+ }
+ 
+ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+ {
+ 	struct mdiobb_ctrl *ctrl = bus->priv;
++	long flags;
+ 
++	local_irq_save(flags);
+ 	if (reg & MII_ADDR_C45) {
+ 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+ 		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+@@ -190,6 +197,8 @@ static int mdiobb_write(struct mii_bus *
+ 
+ 	ctrl->ops->set_mdio_dir(ctrl, 0);
+ 	mdiobb_get_bit(ctrl);
++	local_irq_restore(flags);
++
+ 	return 0;
+ }
+ 
diff --git a/target/linux/ar71xx/patches-4.4/902-at803x-add-reset-gpio-pdata.patch b/target/linux/ar71xx/patches-4.4/902-at803x-add-reset-gpio-pdata.patch
new file mode 100644
index 0000000000..2244f882e7
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/902-at803x-add-reset-gpio-pdata.patch
@@ -0,0 +1,68 @@
+Add support for configuring AT803x GPIO reset via platform data.
+This is necessary, because ath79 is not converted to device tree yet.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/include/linux/platform_data/phy-at803x.h
++++ b/include/linux/platform_data/phy-at803x.h
+@@ -6,6 +6,8 @@ struct at803x_platform_data {
+ 	int enable_rgmii_tx_delay:1;
+ 	int enable_rgmii_rx_delay:1;
+ 	int fixup_rgmii_tx_delay:1;
++	int has_reset_gpio:1;
++	int reset_gpio;
+ };
+ 
+ #endif /* _PHY_AT803X_PDATA_H */
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -243,6 +243,7 @@ static int at803x_resume(struct phy_devi
+ 
+ static int at803x_probe(struct phy_device *phydev)
+ {
++	struct at803x_platform_data *pdata;
+ 	struct device *dev = &phydev->dev;
+ 	struct at803x_priv *priv;
+ 	struct gpio_desc *gpiod_reset;
+@@ -255,6 +256,12 @@ static int at803x_probe(struct phy_devic
+ 	    phydev->drv->phy_id != ATH8032_PHY_ID)
+ 		goto does_not_require_reset_workaround;
+ 
++	pdata = dev_get_platdata(&phydev->dev);
++	if (pdata && pdata->has_reset_gpio) {
++		devm_gpio_request(dev, pdata->reset_gpio, "reset");
++		gpio_direction_output(pdata->reset_gpio, 1);
++	}
++
+ 	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ 	if (IS_ERR(gpiod_reset))
+ 		return PTR_ERR(gpiod_reset);
+@@ -377,15 +384,23 @@ static void at803x_link_change_notify(st
+ 	 * cannot recover from by software.
+ 	 */
+ 	if (phydev->state == PHY_NOLINK) {
+-		if (priv->gpiod_reset && !priv->phy_reset) {
++		if ((priv->gpiod_reset || pdata->has_reset_gpio) &&
++		    !priv->phy_reset) {
+ 			struct at803x_context context;
+ 
+ 			at803x_context_save(phydev, &context);
+ 
+-			gpiod_set_value(priv->gpiod_reset, 1);
+-			msleep(1);
+-			gpiod_set_value(priv->gpiod_reset, 0);
+-			msleep(1);
++			if (pdata->has_reset_gpio) {
++				gpio_set_value_cansleep(pdata->reset_gpio, 0);
++				msleep(1);
++				gpio_set_value_cansleep(pdata->reset_gpio, 1);
++				msleep(1);
++			} else {
++				gpiod_set_value(priv->gpiod_reset, 1);
++				msleep(1);
++				gpiod_set_value(priv->gpiod_reset, 0);
++				msleep(1);
++			}
+ 
+ 			at803x_context_restore(phydev, &context);
+ 
diff --git a/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch b/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch
new file mode 100644
index 0000000000..fc006f0f4d
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/910-unaligned_access_hacks.patch
@@ -0,0 +1,931 @@
+--- a/arch/mips/include/asm/checksum.h
++++ b/arch/mips/include/asm/checksum.h
+@@ -134,26 +134,30 @@ static inline __sum16 ip_fast_csum(const
+ 	const unsigned int *stop = word + ihl;
+ 	unsigned int csum;
+ 	int carry;
++	unsigned int w;
+ 
+-	csum = word[0];
+-	csum += word[1];
+-	carry = (csum < word[1]);
++	csum = net_hdr_word(word++);
++
++	w = net_hdr_word(word++);
++	csum += w;
++	carry = (csum < w);
+ 	csum += carry;
+ 
+-	csum += word[2];
+-	carry = (csum < word[2]);
++	w = net_hdr_word(word++);
++	csum += w;
++	carry = (csum < w);
+ 	csum += carry;
+ 
+-	csum += word[3];
+-	carry = (csum < word[3]);
++	w = net_hdr_word(word++);
++	csum += w;
++	carry = (csum < w);
+ 	csum += carry;
+ 
+-	word += 4;
+ 	do {
+-		csum += *word;
+-		carry = (csum < *word);
++		w = net_hdr_word(word++);
++		csum += w;
++		carry = (csum < w);
+ 		csum += carry;
+-		word++;
+ 	} while (word != stop);
+ 
+ 	return csum_fold(csum);
+@@ -212,73 +216,6 @@ static inline __sum16 ip_compute_csum(co
+ 	return csum_fold(csum_partial(buff, len, 0));
+ }
+ 
+-#define _HAVE_ARCH_IPV6_CSUM
+-static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+-					  const struct in6_addr *daddr,
+-					  __u32 len, unsigned short proto,
+-					  __wsum sum)
+-{
+-	__wsum tmp;
+-
+-	__asm__(
+-	"	.set	push		# csum_ipv6_magic\n"
+-	"	.set	noreorder	\n"
+-	"	.set	noat		\n"
+-	"	addu	%0, %5		# proto (long in network byte order)\n"
+-	"	sltu	$1, %0, %5	\n"
+-	"	addu	%0, $1		\n"
+-
+-	"	addu	%0, %6		# csum\n"
+-	"	sltu	$1, %0, %6	\n"
+-	"	lw	%1, 0(%2)	# four words source address\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 4(%2)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 8(%2)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 12(%2)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 0(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 4(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 8(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 12(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	addu	%0, $1		# Add final carry\n"
+-	"	.set	pop"
+-	: "=&r" (sum), "=&r" (tmp)
+-	: "r" (saddr), "r" (daddr),
+-	  "0" (htonl(len)), "r" (htonl(proto)), "r" (sum));
+-
+-	return csum_fold(sum);
+-}
+-
+ #include <asm-generic/checksum.h>
+ #endif /* CONFIG_GENERIC_CSUM */
+ 
+--- a/include/uapi/linux/ip.h
++++ b/include/uapi/linux/ip.h
+@@ -102,7 +102,7 @@ struct iphdr {
+ 	__be32	saddr;
+ 	__be32	daddr;
+ 	/*The options start here. */
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ struct ip_auth_hdr {
+--- a/include/uapi/linux/ipv6.h
++++ b/include/uapi/linux/ipv6.h
+@@ -129,7 +129,7 @@ struct ipv6hdr {
+ 
+ 	struct	in6_addr	saddr;
+ 	struct	in6_addr	daddr;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ /* index values for the variables in ipv6_devconf */
+--- a/include/uapi/linux/tcp.h
++++ b/include/uapi/linux/tcp.h
+@@ -54,7 +54,7 @@ struct tcphdr {
+ 	__be16	window;
+ 	__sum16	check;
+ 	__be16	urg_ptr;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /*
+  *	The union cast uses a gcc extension to avoid aliasing problems
+@@ -64,7 +64,7 @@ struct tcphdr {
+ union tcp_word_hdr { 
+ 	struct tcphdr hdr;
+ 	__be32 		  words[5];
+-}; 
++} __attribute__((packed, aligned(2)));
+ 
+ #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) 
+ 
+--- a/include/uapi/linux/udp.h
++++ b/include/uapi/linux/udp.h
+@@ -24,7 +24,7 @@ struct udphdr {
+ 	__be16	dest;
+ 	__be16	len;
+ 	__sum16	check;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /* UDP socket options */
+ #define UDP_CORK	1	/* Never send partially complete segments */
+--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
++++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+@@ -41,8 +41,8 @@ static bool ipv4_pkt_to_tuple(const stru
+ 	if (ap == NULL)
+ 		return false;
+ 
+-	tuple->src.u3.ip = ap[0];
+-	tuple->dst.u3.ip = ap[1];
++	tuple->src.u3.ip = net_hdr_word(ap++);
++	tuple->dst.u3.ip = net_hdr_word(ap);
+ 
+ 	return true;
+ }
+--- a/include/uapi/linux/icmp.h
++++ b/include/uapi/linux/icmp.h
+@@ -80,7 +80,7 @@ struct icmphdr {
+ 		__be16	mtu;
+ 	} frag;
+   } un;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ /*
+--- a/include/uapi/linux/in6.h
++++ b/include/uapi/linux/in6.h
+@@ -42,7 +42,7 @@ struct in6_addr {
+ #define s6_addr16		in6_u.u6_addr16
+ #define s6_addr32		in6_u.u6_addr32
+ #endif
+-};
++} __attribute__((packed, aligned(2)));
+ #endif /* __UAPI_DEF_IN6_ADDR */
+ 
+ #if __UAPI_DEF_SOCKADDR_IN6
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -39,6 +39,7 @@
+ #include <linux/ipsec.h>
+ #include <linux/times.h>
+ #include <linux/slab.h>
++#include <asm/unaligned.h>
+ #include <linux/uaccess.h>
+ #include <linux/ipv6.h>
+ #include <linux/icmpv6.h>
+@@ -779,10 +780,10 @@ static void tcp_v6_send_response(const s
+ 	topt = (__be32 *)(t1 + 1);
+ 
+ 	if (tsecr) {
+-		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+-				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+-		*topt++ = htonl(tsval);
+-		*topt++ = htonl(tsecr);
++		put_unaligned_be32((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
++				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP, topt++);
++		put_unaligned_be32(tsval, topt++);
++		put_unaligned_be32(tsecr, topt++);
+ 	}
+ 
+ #ifdef CONFIG_TCP_MD5SIG
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -5,6 +5,7 @@
+ 
+ #define ipv6_optlen(p)  (((p)->hdrlen+1) << 3)
+ #define ipv6_authlen(p) (((p)->hdrlen+2) << 2)
++
+ /*
+  * This structure contains configuration options per IPv6 link.
+  */
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -429,7 +429,7 @@ int ipv6_recv_error(struct sock *sk, str
+ 				ipv6_iface_scope_id(&sin->sin6_addr,
+ 						    IP6CB(skb)->iif);
+ 		} else {
+-			ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
++			ipv6_addr_set_v4mapped(net_hdr_word(nh + serr->addr_offset),
+ 					       &sin->sin6_addr);
+ 			sin->sin6_scope_id = 0;
+ 		}
+@@ -766,12 +766,12 @@ int ip6_datagram_send_ctl(struct net *ne
+ 			}
+ 
+ 			if (fl6->flowlabel&IPV6_FLOWINFO_MASK) {
+-				if ((fl6->flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
++				if ((fl6->flowlabel^net_hdr_word(CMSG_DATA(cmsg)))&~IPV6_FLOWINFO_MASK) {
+ 					err = -EINVAL;
+ 					goto exit_f;
+ 				}
+ 			}
+-			fl6->flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg);
++			fl6->flowlabel = IPV6_FLOWINFO_MASK & net_hdr_word(CMSG_DATA(cmsg));
+ 			break;
+ 
+ 		case IPV6_2292HOPOPTS:
+--- a/net/ipv6/ip6_gre.c
++++ b/net/ipv6/ip6_gre.c
+@@ -394,7 +394,7 @@ static void ip6gre_err(struct sk_buff *s
+ 
+ 	t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
+ 				flags & GRE_KEY ?
+-				*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
++				net_hdr_word(((__be32 *)p) + (grehlen / 4) - 1) : 0,
+ 				p[1]);
+ 	if (!t)
+ 		return;
+@@ -476,11 +476,11 @@ static int ip6gre_rcv(struct sk_buff *sk
+ 			offset += 4;
+ 		}
+ 		if (flags&GRE_KEY) {
+-			key = *(__be32 *)(h + offset);
++			key = net_hdr_word(h + offset);
+ 			offset += 4;
+ 		}
+ 		if (flags&GRE_SEQ) {
+-			seqno = ntohl(*(__be32 *)(h + offset));
++			seqno = ntohl(net_hdr_word(h + offset));
+ 			offset += 4;
+ 		}
+ 	}
+@@ -742,7 +742,7 @@ static netdev_tx_t ip6gre_xmit2(struct s
+ 
+ 		if (tunnel->parms.o_flags&GRE_SEQ) {
+ 			++tunnel->o_seqno;
+-			*ptr = htonl(tunnel->o_seqno);
++			net_hdr_word(ptr) = htonl(tunnel->o_seqno);
+ 			ptr--;
+ 		}
+ 		if (tunnel->parms.o_flags&GRE_KEY) {
+@@ -838,7 +838,7 @@ static inline int ip6gre_xmit_ipv6(struc
+ 
+ 	dsfield = ipv6_get_dsfield(ipv6h);
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
+-		fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
++		fl6.flowlabel |= net_hdr_word(ipv6h) & IPV6_TCLASS_MASK;
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+ 		fl6.flowlabel |= ip6_flowlabel(ipv6h);
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -1388,7 +1388,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ 
+ 	dsfield = ipv6_get_dsfield(ipv6h);
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
+-		fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
++		fl6.flowlabel |= net_hdr_word(ipv6h) & IPV6_TCLASS_MASK;
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+ 		fl6.flowlabel |= ip6_flowlabel(ipv6h);
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -573,7 +573,7 @@ static bool ipv6_hop_jumbo(struct sk_buf
+ 		goto drop;
+ 	}
+ 
+-	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
++	pkt_len = ntohl(net_hdr_word(nh + optoff + 2));
+ 	if (pkt_len <= IPV6_MAXPLEN) {
+ 		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
+ 				 IPSTATS_MIB_INHDRERRORS);
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -232,5 +232,11 @@ typedef void (*call_rcu_func_t)(struct r
+ /* clocksource cycle base type */
+ typedef u64 cycle_t;
+ 
++struct net_hdr_word {
++       u32 words[1];
++} __attribute__((packed, aligned(2)));
++
++#define net_hdr_word(_p) (((struct net_hdr_word *) (_p))->words[0])
++
+ #endif /*  __ASSEMBLY__ */
+ #endif /* _LINUX_TYPES_H */
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -1321,8 +1321,8 @@ static struct sk_buff **inet_gro_receive
+ 	if (unlikely(ip_fast_csum((u8 *)iph, 5)))
+ 		goto out_unlock;
+ 
+-	id = ntohl(*(__be32 *)&iph->id);
+-	flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));
++	id = ntohl(net_hdr_word(&iph->id));
++	flush = (u16)((ntohl(net_hdr_word(iph)) ^ skb_gro_len(skb)) | (id & ~IP_DF));
+ 	id >>= 16;
+ 
+ 	for (p = *head; p; p = p->next) {
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -458,7 +458,7 @@ static struct neighbour *ipv4_neigh_look
+ 	else if (skb)
+ 		pkey = &ip_hdr(skb)->daddr;
+ 
+-	n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey);
++	n = __ipv4_neigh_lookup(dev, net_hdr_word(pkey));
+ 	if (n)
+ 		return n;
+ 	return neigh_create(&arp_tbl, pkey, dev);
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -451,48 +451,53 @@ static void tcp_options_write(__be32 *pt
+ 	u16 options = opts->options;	/* mungable copy */
+ 
+ 	if (unlikely(OPTION_MD5 & options)) {
+-		*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+-			       (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
++			      (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
+ 		/* overload cookie hash location */
+ 		opts->hash_location = (__u8 *)ptr;
+ 		ptr += 4;
+ 	}
+ 
+ 	if (unlikely(opts->mss)) {
+-		*ptr++ = htonl((TCPOPT_MSS << 24) |
+-			       (TCPOLEN_MSS << 16) |
+-			       opts->mss);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) |
++			      opts->mss);
+ 	}
+ 
+ 	if (likely(OPTION_TS & options)) {
+ 		if (unlikely(OPTION_SACK_ADVERTISE & options)) {
+-			*ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
+-				       (TCPOLEN_SACK_PERM << 16) |
+-				       (TCPOPT_TIMESTAMP << 8) |
+-				       TCPOLEN_TIMESTAMP);
++			net_hdr_word(ptr++) =
++				htonl((TCPOPT_SACK_PERM << 24) |
++				      (TCPOLEN_SACK_PERM << 16) |
++				      (TCPOPT_TIMESTAMP << 8) |
++				      TCPOLEN_TIMESTAMP);
+ 			options &= ~OPTION_SACK_ADVERTISE;
+ 		} else {
+-			*ptr++ = htonl((TCPOPT_NOP << 24) |
+-				       (TCPOPT_NOP << 16) |
+-				       (TCPOPT_TIMESTAMP << 8) |
+-				       TCPOLEN_TIMESTAMP);
++			net_hdr_word(ptr++) =
++				htonl((TCPOPT_NOP << 24) |
++				      (TCPOPT_NOP << 16) |
++				      (TCPOPT_TIMESTAMP << 8) |
++				      TCPOLEN_TIMESTAMP);
+ 		}
+-		*ptr++ = htonl(opts->tsval);
+-		*ptr++ = htonl(opts->tsecr);
++		net_hdr_word(ptr++) = htonl(opts->tsval);
++		net_hdr_word(ptr++) = htonl(opts->tsecr);
+ 	}
+ 
+ 	if (unlikely(OPTION_SACK_ADVERTISE & options)) {
+-		*ptr++ = htonl((TCPOPT_NOP << 24) |
+-			       (TCPOPT_NOP << 16) |
+-			       (TCPOPT_SACK_PERM << 8) |
+-			       TCPOLEN_SACK_PERM);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) |
++			      (TCPOPT_NOP << 16) |
++			      (TCPOPT_SACK_PERM << 8) |
++			      TCPOLEN_SACK_PERM);
+ 	}
+ 
+ 	if (unlikely(OPTION_WSCALE & options)) {
+-		*ptr++ = htonl((TCPOPT_NOP << 24) |
+-			       (TCPOPT_WINDOW << 16) |
+-			       (TCPOLEN_WINDOW << 8) |
+-			       opts->ws);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) |
++			      (TCPOPT_WINDOW << 16) |
++			      (TCPOLEN_WINDOW << 8) |
++			      opts->ws);
+ 	}
+ 
+ 	if (unlikely(opts->num_sack_blocks)) {
+@@ -500,16 +505,17 @@ static void tcp_options_write(__be32 *pt
+ 			tp->duplicate_sack : tp->selective_acks;
+ 		int this_sack;
+ 
+-		*ptr++ = htonl((TCPOPT_NOP  << 24) |
+-			       (TCPOPT_NOP  << 16) |
+-			       (TCPOPT_SACK <<  8) |
+-			       (TCPOLEN_SACK_BASE + (opts->num_sack_blocks *
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) |
++			      (TCPOPT_NOP << 16) |
++			      (TCPOPT_SACK << 8) |
++			      (TCPOLEN_SACK_BASE + (opts->num_sack_blocks *
+ 						     TCPOLEN_SACK_PERBLOCK)));
+ 
+ 		for (this_sack = 0; this_sack < opts->num_sack_blocks;
+ 		     ++this_sack) {
+-			*ptr++ = htonl(sp[this_sack].start_seq);
+-			*ptr++ = htonl(sp[this_sack].end_seq);
++			net_hdr_word(ptr++) = htonl(sp[this_sack].start_seq);
++			net_hdr_word(ptr++) = htonl(sp[this_sack].end_seq);
+ 		}
+ 
+ 		tp->rx_opt.dsack = 0;
+@@ -522,13 +528,14 @@ static void tcp_options_write(__be32 *pt
+ 
+ 		if (foc->exp) {
+ 			len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len;
+-			*ptr = htonl((TCPOPT_EXP << 24) | (len << 16) |
++			net_hdr_word(ptr) =
++				htonl((TCPOPT_EXP << 24) | (len << 16) |
+ 				     TCPOPT_FASTOPEN_MAGIC);
+ 			p += TCPOLEN_EXP_FASTOPEN_BASE;
+ 		} else {
+ 			len = TCPOLEN_FASTOPEN_BASE + foc->len;
+-			*p++ = TCPOPT_FASTOPEN;
+-			*p++ = len;
++			net_hdr_word(p++) = TCPOPT_FASTOPEN;
++			net_hdr_word(p++) = len;
+ 		}
+ 
+ 		memcpy(p, foc->val, foc->len);
+--- a/net/ipv4/igmp.c
++++ b/net/ipv4/igmp.c
+@@ -500,7 +500,7 @@ static struct sk_buff *add_grec(struct s
+ 		if (!skb)
+ 			return NULL;
+ 		psrc = (__be32 *)skb_put(skb, sizeof(__be32));
+-		*psrc = psf->sf_inaddr;
++		net_hdr_word(psrc) = psf->sf_inaddr;
+ 		scount++; stotal++;
+ 		if ((type == IGMPV3_ALLOW_NEW_SOURCES ||
+ 		     type == IGMPV3_BLOCK_OLD_SOURCES) && psf->sf_crcount) {
+--- a/include/uapi/linux/igmp.h
++++ b/include/uapi/linux/igmp.h
+@@ -32,7 +32,7 @@ struct igmphdr {
+ 	__u8 code;		/* For newer IGMP */
+ 	__sum16 csum;
+ 	__be32 group;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /* V3 group record types [grec_type] */
+ #define IGMPV3_MODE_IS_INCLUDE		1
+@@ -48,7 +48,7 @@ struct igmpv3_grec {
+ 	__be16	grec_nsrcs;
+ 	__be32	grec_mca;
+ 	__be32	grec_src[0];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ struct igmpv3_report {
+ 	__u8 type;
+@@ -57,7 +57,7 @@ struct igmpv3_report {
+ 	__be16 resv2;
+ 	__be16 ngrec;
+ 	struct igmpv3_grec grec[0];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ struct igmpv3_query {
+ 	__u8 type;
+@@ -78,7 +78,7 @@ struct igmpv3_query {
+ 	__u8 qqic;
+ 	__be16 nsrcs;
+ 	__be32 srcs[0];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ #define IGMP_HOST_MEMBERSHIP_QUERY	0x11	/* From RFC1112 */
+ #define IGMP_HOST_MEMBERSHIP_REPORT	0x12	/* Ditto */
+--- a/net/core/flow_dissector.c
++++ b/net/core/flow_dissector.c
+@@ -95,7 +95,7 @@ __be32 __skb_flow_get_ports(const struct
+ 		ports = __skb_header_pointer(skb, thoff + poff,
+ 					     sizeof(_ports), data, hlen, &_ports);
+ 		if (ports)
+-			return *ports;
++			return (__be32)net_hdr_word(ports);
+ 	}
+ 
+ 	return 0;
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -76,7 +76,7 @@ struct icmp6hdr {
+ #define icmp6_addrconf_other	icmp6_dataun.u_nd_ra.other
+ #define icmp6_rt_lifetime	icmp6_dataun.u_nd_ra.rt_lifetime
+ #define icmp6_router_pref	icmp6_dataun.u_nd_ra.router_pref
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ #define ICMPV6_ROUTER_PREF_LOW		0x3
+--- a/include/net/ndisc.h
++++ b/include/net/ndisc.h
+@@ -76,7 +76,7 @@ struct ra_msg {
+         struct icmp6hdr		icmph;
+ 	__be32			reachable_time;
+ 	__be32			retrans_timer;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ struct rd_msg {
+ 	struct icmp6hdr icmph;
+@@ -148,10 +148,10 @@ static inline u32 ndisc_hashfn(const voi
+ {
+ 	const u32 *p32 = pkey;
+ 
+-	return (((p32[0] ^ hash32_ptr(dev)) * hash_rnd[0]) +
+-		(p32[1] * hash_rnd[1]) +
+-		(p32[2] * hash_rnd[2]) +
+-		(p32[3] * hash_rnd[3]));
++	return (((net_hdr_word(&p32[0]) ^ hash32_ptr(dev)) * hash_rnd[0]) +
++		(net_hdr_word(&p32[1]) * hash_rnd[1]) +
++		(net_hdr_word(&p32[2]) * hash_rnd[2]) +
++		(net_hdr_word(&p32[3]) * hash_rnd[3]));
+ }
+ 
+ static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
+--- a/net/sched/cls_u32.c
++++ b/net/sched/cls_u32.c
+@@ -151,7 +151,7 @@ next_knode:
+ 			data = skb_header_pointer(skb, toff, 4, &hdata);
+ 			if (!data)
+ 				goto out;
+-			if ((*data ^ key->val) & key->mask) {
++			if ((net_hdr_word(data) ^ key->val) & key->mask) {
+ 				n = rcu_dereference_bh(n->next);
+ 				goto next_knode;
+ 			}
+@@ -204,8 +204,8 @@ check_terminal:
+ 						  &hdata);
+ 			if (!data)
+ 				goto out;
+-			sel = ht->divisor & u32_hash_fold(*data, &n->sel,
+-							  n->fshift);
++			sel = ht->divisor & u32_hash_fold(net_hdr_word(data),
++							  &n->sel, n->fshift);
+ 		}
+ 		if (!(n->sel.flags & (TC_U32_VAROFFSET | TC_U32_OFFSET | TC_U32_EAT)))
+ 			goto next_ht;
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -221,7 +221,7 @@ static struct sk_buff **ipv6_gro_receive
+ 			continue;
+ 
+ 		iph2 = (struct ipv6hdr *)(p->data + off);
+-		first_word = *(__be32 *)iph ^ *(__be32 *)iph2;
++		first_word = net_hdr_word(iph) ^ net_hdr_word(iph2);
+ 
+ 		/* All fields must match except length and Traffic Class.
+ 		 * XXX skbs on the gro_list have all been parsed and pulled
+--- a/include/net/addrconf.h
++++ b/include/net/addrconf.h
+@@ -43,7 +43,7 @@ struct prefix_info {
+ 	__be32			reserved2;
+ 
+ 	struct in6_addr		prefix;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ #include <linux/netdevice.h>
+--- a/include/net/inet_ecn.h
++++ b/include/net/inet_ecn.h
+@@ -124,9 +124,9 @@ static inline int IP6_ECN_set_ce(struct
+ 	if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
+ 		return 0;
+ 
+-	from = *(__be32 *)iph;
++	from = net_hdr_word(iph);
+ 	to = from | htonl(INET_ECN_CE << 20);
+-	*(__be32 *)iph = to;
++	net_hdr_word(iph) = to;
+ 	if (skb->ip_summed == CHECKSUM_COMPLETE)
+ 		skb->csum = csum_add(csum_sub(skb->csum, from), to);
+ 	return 1;
+@@ -134,7 +134,7 @@ static inline int IP6_ECN_set_ce(struct
+ 
+ static inline void IP6_ECN_clear(struct ipv6hdr *iph)
+ {
+-	*(__be32*)iph &= ~htonl(INET_ECN_MASK << 20);
++	net_hdr_word(iph) &= ~htonl(INET_ECN_MASK << 20);
+ }
+ 
+ static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner)
+--- a/include/net/ipv6.h
++++ b/include/net/ipv6.h
+@@ -107,7 +107,7 @@ struct frag_hdr {
+ 	__u8	reserved;
+ 	__be16	frag_off;
+ 	__be32	identification;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ #define	IP6_MF		0x0001
+ #define	IP6_OFFSET	0xFFF8
+@@ -417,8 +417,8 @@ static inline void __ipv6_addr_set_half(
+ 	}
+ #endif
+ #endif
+-	addr[0] = wh;
+-	addr[1] = wl;
++	net_hdr_word(&addr[0]) = wh;
++	net_hdr_word(&addr[1]) = wl;
+ }
+ 
+ static inline void ipv6_addr_set(struct in6_addr *addr, 
+@@ -477,6 +477,8 @@ static inline bool ipv6_prefix_equal(con
+ 	const __be32 *a1 = addr1->s6_addr32;
+ 	const __be32 *a2 = addr2->s6_addr32;
+ 	unsigned int pdw, pbi;
++	/* Used for last <32-bit fraction of prefix */
++	u32 pbia1, pbia2;
+ 
+ 	/* check complete u32 in prefix */
+ 	pdw = prefixlen >> 5;
+@@ -485,7 +487,9 @@ static inline bool ipv6_prefix_equal(con
+ 
+ 	/* check incomplete u32 in prefix */
+ 	pbi = prefixlen & 0x1f;
+-	if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi))))
++	pbia1 = net_hdr_word(&a1[pdw]);
++	pbia2 = net_hdr_word(&a2[pdw]);
++	if (pbi && ((pbia1 ^ pbia2) & htonl((0xffffffff) << (32 - pbi))))
+ 		return false;
+ 
+ 	return true;
+@@ -629,13 +633,13 @@ static inline void ipv6_addr_set_v4mappe
+  */
+ static inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen)
+ {
+-	const __be32 *a1 = token1, *a2 = token2;
++	const struct in6_addr *a1 = token1, *a2 = token2;
+ 	int i;
+ 
+ 	addrlen >>= 2;
+ 
+ 	for (i = 0; i < addrlen; i++) {
+-		__be32 xb = a1[i] ^ a2[i];
++		__be32 xb = a1->s6_addr32[i] ^ a2->s6_addr32[i];
+ 		if (xb)
+ 			return i * 32 + 31 - __fls(ntohl(xb));
+ 	}
+@@ -799,17 +803,18 @@ static inline int ip6_default_np_autolab
+ static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass,
+ 				__be32 flowlabel)
+ {
+-	*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel;
++	net_hdr_word((__be32 *)hdr) =
++		htonl(0x60000000 | (tclass << 20)) | flowlabel;
+ }
+ 
+ static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr)
+ {
+-	return *(__be32 *)hdr & IPV6_FLOWINFO_MASK;
++	return net_hdr_word((__be32 *)hdr) & IPV6_FLOWINFO_MASK;
+ }
+ 
+ static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
+ {
+-	return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
++	return net_hdr_word((__be32 *)hdr) & IPV6_FLOWLABEL_MASK;
+ }
+ 
+ static inline u8 ip6_tclass(__be32 flowinfo)
+--- a/include/net/secure_seq.h
++++ b/include/net/secure_seq.h
+@@ -2,6 +2,7 @@
+ #define _NET_SECURE_SEQ
+ 
+ #include <linux/types.h>
++#include <linux/in6.h>
+ 
+ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
+ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+--- a/include/uapi/linux/in.h
++++ b/include/uapi/linux/in.h
+@@ -83,7 +83,7 @@ enum {
+ /* Internet address. */
+ struct in_addr {
+ 	__be32	s_addr;
+-};
++} __attribute__((packed, aligned(2)));
+ #endif
+ 
+ #define IP_TOS		1
+--- a/net/core/secure_seq.c
++++ b/net/core/secure_seq.c
+@@ -46,11 +46,12 @@ __u32 secure_tcpv6_sequence_number(const
+ 	u32 secret[MD5_MESSAGE_BYTES / 4];
+ 	u32 hash[MD5_DIGEST_WORDS];
+ 	u32 i;
++	const struct in6_addr *daddr6 = (struct in6_addr *) daddr;
+ 
+ 	net_secret_init();
+ 	memcpy(hash, saddr, 16);
+ 	for (i = 0; i < 4; i++)
+-		secret[i] = net_secret[i] + (__force u32)daddr[i];
++		secret[i] = net_secret[i] + (__force u32)daddr6->s6_addr32[i];
+ 	secret[4] = net_secret[4] +
+ 		(((__force u16)sport << 16) + (__force u16)dport);
+ 	for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+@@ -68,11 +69,12 @@ u32 secure_ipv6_port_ephemeral(const __b
+ 	u32 secret[MD5_MESSAGE_BYTES / 4];
+ 	u32 hash[MD5_DIGEST_WORDS];
+ 	u32 i;
++	const struct in6_addr *daddr6 = (struct in6_addr *) daddr;
+ 
+ 	net_secret_init();
+ 	memcpy(hash, saddr, 16);
+ 	for (i = 0; i < 4; i++)
+-		secret[i] = net_secret[i] + (__force u32) daddr[i];
++		secret[i] = net_secret[i] + (__force u32) daddr6->s6_addr32[i];
+ 	secret[4] = net_secret[4] + (__force u32)dport;
+ 	for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+ 		secret[i] = net_secret[i];
+@@ -146,6 +148,7 @@ EXPORT_SYMBOL(secure_dccp_sequence_numbe
+ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+ 				  __be16 sport, __be16 dport)
+ {
++	const struct in6_addr *daddr6 = (struct in6_addr *) daddr;
+ 	u32 secret[MD5_MESSAGE_BYTES / 4];
+ 	u32 hash[MD5_DIGEST_WORDS];
+ 	u64 seq;
+@@ -154,7 +157,7 @@ u64 secure_dccpv6_sequence_number(__be32
+ 	net_secret_init();
+ 	memcpy(hash, saddr, 16);
+ 	for (i = 0; i < 4; i++)
+-		secret[i] = net_secret[i] + (__force u32)daddr[i];
++		secret[i] = net_secret[i] + (__force u32)daddr6->s6_addr32[i];
+ 	secret[4] = net_secret[4] +
+ 		(((__force u16)sport << 16) + (__force u16)dport);
+ 	for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -138,7 +138,7 @@ static __be32 addr_bit_set(const void *t
+ 	 * See include/asm-generic/bitops/le.h.
+ 	 */
+ 	return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) &
+-	       addr[fn_bit >> 5];
++	       net_hdr_word(&addr[fn_bit >> 5]);
+ }
+ 
+ static struct fib6_node *node_alloc(void)
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -456,7 +456,7 @@ static void tcp_sack(const struct sk_buf
+ 
+ 	/* Fast path for timestamp-only option */
+ 	if (length == TCPOLEN_TSTAMP_ALIGNED
+-	    && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24)
++	    && net_hdr_word(ptr) == htonl((TCPOPT_NOP << 24)
+ 				       | (TCPOPT_NOP << 16)
+ 				       | (TCPOPT_TIMESTAMP << 8)
+ 				       | TCPOLEN_TIMESTAMP))
+--- a/net/xfrm/xfrm_input.c
++++ b/net/xfrm/xfrm_input.c
+@@ -154,8 +154,8 @@ int xfrm_parse_spi(struct sk_buff *skb,
+ 	if (!pskb_may_pull(skb, hlen))
+ 		return -EINVAL;
+ 
+-	*spi = *(__be32 *)(skb_transport_header(skb) + offset);
+-	*seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
++	*spi = net_hdr_word(skb_transport_header(skb) + offset);
++	*seq = net_hdr_word(skb_transport_header(skb) + offset_seq);
+ 	return 0;
+ }
+ 
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -3818,14 +3818,16 @@ static bool tcp_parse_aligned_timestamp(
+ {
+ 	const __be32 *ptr = (const __be32 *)(th + 1);
+ 
+-	if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+-			  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
++	if (net_hdr_word(ptr) ==
++	    htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
++		  (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+ 		tp->rx_opt.saw_tstamp = 1;
+ 		++ptr;
+-		tp->rx_opt.rcv_tsval = ntohl(*ptr);
++		tp->rx_opt.rcv_tsval = get_unaligned_be32(ptr);
+ 		++ptr;
+-		if (*ptr)
+-			tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset;
++		if (net_hdr_word(ptr))
++			tp->rx_opt.rcv_tsecr = get_unaligned_be32(ptr) -
++					       tp->tsoffset;
+ 		else
+ 			tp->rx_opt.rcv_tsecr = 0;
+ 		return true;
+--- a/include/uapi/linux/if_pppox.h
++++ b/include/uapi/linux/if_pppox.h
+@@ -47,6 +47,7 @@ struct pppoe_addr {
+  */
+ struct pptp_addr {
+ 	__u16		call_id;
++	__u16		pad;
+ 	struct in_addr	sin_addr;
+ };
+ 
+--- a/net/ipv6/netfilter/nf_log_ipv6.c
++++ b/net/ipv6/netfilter/nf_log_ipv6.c
+@@ -66,9 +66,9 @@ static void dump_ipv6_packet(struct nf_l
+ 	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
+ 	nf_log_buf_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
+ 	       ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
+-	       (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
++	       (ntohl(net_hdr_word(ih)) & 0x0ff00000) >> 20,
+ 	       ih->hop_limit,
+-	       (ntohl(*(__be32 *)ih) & 0x000fffff));
++	       (ntohl(net_hdr_word(ih)) & 0x000fffff));
+ 
+ 	fragment = 0;
+ 	ptr = ip6hoff + sizeof(struct ipv6hdr);
+--- a/include/net/neighbour.h
++++ b/include/net/neighbour.h
+@@ -263,8 +263,10 @@ static inline bool neigh_key_eq128(const
+ 	const u32 *n32 = (const u32 *)n->primary_key;
+ 	const u32 *p32 = pkey;
+ 
+-	return ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
+-		(n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0;
++	return ((n32[0] ^ net_hdr_word(&p32[0])) |
++		(n32[1] ^ net_hdr_word(&p32[1])) |
++		(n32[2] ^ net_hdr_word(&p32[2])) |
++		(n32[3] ^ net_hdr_word(&p32[3]))) == 0;
+ }
+ 
+ static inline struct neighbour *___neigh_lookup_noref(
+--- a/include/uapi/linux/netfilter_arp/arp_tables.h
++++ b/include/uapi/linux/netfilter_arp/arp_tables.h
+@@ -68,7 +68,7 @@ struct arpt_arp {
+ 	__u8 flags;
+ 	/* Inverse flags */
+ 	__u16 invflags;
+-};
++} __attribute__((aligned(4)));
+ 
+ /* Values for "flag" field in struct arpt_ip (general arp structure).
+  * No flags defined yet.
+--- a/net/core/utils.c
++++ b/net/core/utils.c
+@@ -321,8 +321,14 @@ void inet_proto_csum_replace16(__sum16 *
+ 			       bool pseudohdr)
+ {
+ 	__be32 diff[] = {
+-		~from[0], ~from[1], ~from[2], ~from[3],
+-		to[0], to[1], to[2], to[3],
++		~net_hdr_word(&from[0]),
++		~net_hdr_word(&from[1]),
++		~net_hdr_word(&from[2]),
++		~net_hdr_word(&from[3]),
++		net_hdr_word(&to[0]),
++		net_hdr_word(&to[1]),
++		net_hdr_word(&to[2]),
++		net_hdr_word(&to[3]),
+ 	};
+ 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ 		*sum = csum_fold(csum_partial(diff, sizeof(diff),
diff --git a/target/linux/generic/PATCHES b/target/linux/generic/PATCHES
new file mode 100644
index 0000000000..86ced46804
--- /dev/null
+++ b/target/linux/generic/PATCHES
@@ -0,0 +1,20 @@
+The patches-* subdirectories contain the kernel patches applied for every
+OpenWrt target. All patches should be named 'NNN-lowercase_shortname.patch'
+and sorted into the following categories:
+
+0xx - upstream backports
+1xx - code awaiting upstream merge
+2xx - kernel build / config / header patches
+3xx - architecture specific patches
+4xx - mtd related patches (subsystem and drivers)
+5xx - filesystem related patches
+6xx - generic network patches
+7xx - network / phy driver patches
+8xx - other drivers
+9xx - uncategorized other patches
+
+ALL patches must be in a way that they are potentially upstreamable, meaning:
+
+- they must contain a proper subject
+- they must contain a proper commit message explaining what they change
+- they must contain a valid Signed-off-by line
diff --git a/target/linux/generic/base-files/init b/target/linux/generic/base-files/init
new file mode 100755
index 0000000000..514be57e66
--- /dev/null
+++ b/target/linux/generic/base-files/init
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+export INITRAMFS=1
+exec /sbin/init
diff --git a/target/linux/generic/config-3.18 b/target/linux/generic/config-3.18
new file mode 100644
index 0000000000..c61a4b35b4
--- /dev/null
+++ b/target/linux/generic/config-3.18
@@ -0,0 +1,4646 @@
+CONFIG_32BIT=y
+# CONFIG_6LOWPAN is not set
+# CONFIG_6PACK is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_9P_FS is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_AB8500_CORE is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_ACENIC is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_ACPI_APEI is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_EXTLOG is not set
+# CONFIG_ACPI_HED is not set
+# CONFIG_ACPI_INT3403_THERMAL is not set
+# CONFIG_ACPI_POWER_METER is not set
+# CONFIG_ACPI_QUICKSTART is not set
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+# CONFIG_AD2S90 is not set
+# CONFIG_AD5064 is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5686 is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5930 is not set
+# CONFIG_AD5933 is not set
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_AD7266 is not set
+# CONFIG_AD7280 is not set
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7303 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD7746 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD7923 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD8366 is not set
+# CONFIG_AD9523 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_AD9850 is not set
+# CONFIG_AD9852 is not set
+# CONFIG_AD9910 is not set
+# CONFIG_AD9951 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+# CONFIG_ADF4350 is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16136 is not set
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_ADIS16255 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADIS16480 is not set
+# CONFIG_ADJD_S311 is not set
+# CONFIG_ADM6996_PHY is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_ADT7316 is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_ADXRS450 is not set
+CONFIG_AEABI=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AGP is not set
+# CONFIG_AHCI_MVEBU is not set
+CONFIG_AIO=y
+# CONFIG_AIRO is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_AK09911 is not set
+# CONFIG_AK8975 is not set
+# CONFIG_AL3320A is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_ALTERA_STAPL is not set
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_ALX is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_AMD_XGBE is not set
+# CONFIG_AMD_XGBE_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_ANDROID is not set
+CONFIG_ANON_INODES=y
+# CONFIG_APDS9300 is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_APM8018X is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AR5523 is not set
+# CONFIG_AR7 is not set
+# CONFIG_AR8216_PHY is not set
+# CONFIG_AR8216_PHY_LEDS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BCM2835 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_EXYNOS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ARCH_HI3xxx is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_HISI is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_MSM_DT is not set
+# CONFIG_ARCH_MSM_NODT is not set
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_NSPIRE is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2PLUS is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_S3C24XX is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_SHMOBILE_LEGACY is not set
+# CONFIG_ARCH_SHMOBILE_MULTI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_WM8505 is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCNET is not set
+# CONFIG_ARC_EMAC is not set
+# CONFIG_ARM_APPENDED_DTB is not set
+# CONFIG_ARM_ARCH_TIMER is not set
+# CONFIG_ARM_AT91_ETHER is not set
+# CONFIG_ARM_CCI is not set
+# CONFIG_ARM_CCN is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+# CONFIG_ARM_ERRATA_326103 is not set
+# CONFIG_ARM_ERRATA_364296 is not set
+# CONFIG_ARM_ERRATA_411920 is not set
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_643719 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+# CONFIG_ARM_ERRATA_742230 is not set
+# CONFIG_ARM_ERRATA_742231 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_751472 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+# CONFIG_ARM_ERRATA_754327 is not set
+# CONFIG_ARM_ERRATA_764369 is not set
+# CONFIG_ARM_ERRATA_773022 is not set
+# CONFIG_ARM_ERRATA_775420 is not set
+# CONFIG_ARM_ERRATA_798181 is not set
+# CONFIG_ARM_KPROBES_TEST is not set
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+# CONFIG_ARM_PSCI is not set
+# CONFIG_ARM_PTDUMP is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_ARM_VIRT_EXT is not set
+CONFIG_ARPD=y
+# CONFIG_ARTHUR is not set
+# CONFIG_AS3935 is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_AT803X_PHY is not set
+# CONFIG_ATA is not set
+# CONFIG_ATAGS is not set
+CONFIG_ATAGS_PROC=y
+# CONFIG_ATALK is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_ATA_ACPI is not set
+CONFIG_ATA_BMDMA=y
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_ATA_PIIX is not set
+CONFIG_ATA_SFF=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATH10K is not set
+# CONFIG_ATH5K is not set
+# CONFIG_ATH6KL is not set
+# CONFIG_ATH6K_LEGACY is not set
+# CONFIG_ATH79 is not set
+# CONFIG_ATH9K is not set
+# CONFIG_ATH9K_HTC is not set
+# CONFIG_ATH_CARDS is not set
+# CONFIG_ATH_DEBUG is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_ATMEL_PWM is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_BR2684 is not set
+CONFIG_ATM_BR2684_IPFILTER=y
+# CONFIG_ATM_CLIP is not set
+CONFIG_ATM_CLIP_NO_ICMP=y
+# CONFIG_ATM_DRIVERS is not set
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_FORE200E is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_LANE is not set
+# CONFIG_ATM_MPOA is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_SOLOS is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ATP is not set
+# CONFIG_AUDIT is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_AUTO_ZRELADDR is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_AVERAGE is not set
+# CONFIG_AX25 is not set
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_AX88796 is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_B44 is not set
+# CONFIG_SWCONFIG_B53 is not set
+# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set
+# CONFIG_BACKLIGHT_BD6107 is not set
+# CONFIG_BACKLIGHT_GPIO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_BACKLIGHT_LM3630 is not set
+# CONFIG_BACKLIGHT_LM3630A is not set
+# CONFIG_BACKLIGHT_LM3639 is not set
+# CONFIG_BACKLIGHT_LP855X is not set
+# CONFIG_BACKLIGHT_LV5207LP is not set
+# CONFIG_BACKLIGHT_PANDORA is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BCACHE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_BCM7XXX_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_BCMA is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
+CONFIG_BCMA_POSSIBLE=y
+# CONFIG_BCMGENET is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BE2NET is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_BGMAC is not set
+# CONFIG_BIG_KEYS is not set
+# CONFIG_BIG_LITTLE is not set
+# CONFIG_BINARY_PRINTF is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BITREVERSE=y
+# CONFIG_BLK_CMDLINE_PARSER is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
+# CONFIG_BLK_DEV_CS5536 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDE_AU1XXX is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_QD65XX is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_THROTTLING is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_UMC8672 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_BLOCK=y
+# CONFIG_BMA180 is not set
+# CONFIG_BMC150_ACCEL is not set
+# CONFIG_BMG160 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_BNA is not set
+# CONFIG_BNX2 is not set
+# CONFIG_BNX2X is not set
+# CONFIG_BONDING is not set
+# CONFIG_BOOKE_WDT is not set
+CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3
+# CONFIG_BOOT_PRINTK_DELAY is not set
+CONFIG_BOOT_RAW=y
+# CONFIG_BPCTL is not set
+CONFIG_BPF=y
+# CONFIG_BPF_JIT is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_BPQETHER is not set
+CONFIG_BQL=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_BRCMFMAC is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMSTB_GISB_ARB is not set
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_EBT_802_3 is not set
+# CONFIG_BRIDGE_EBT_AMONG is not set
+# CONFIG_BRIDGE_EBT_ARP is not set
+# CONFIG_BRIDGE_EBT_ARPREPLY is not set
+# CONFIG_BRIDGE_EBT_BROUTE is not set
+# CONFIG_BRIDGE_EBT_DNAT is not set
+# CONFIG_BRIDGE_EBT_IP is not set
+# CONFIG_BRIDGE_EBT_IP6 is not set
+# CONFIG_BRIDGE_EBT_LIMIT is not set
+# CONFIG_BRIDGE_EBT_LOG is not set
+# CONFIG_BRIDGE_EBT_MARK is not set
+# CONFIG_BRIDGE_EBT_MARK_T is not set
+# CONFIG_BRIDGE_EBT_NFLOG is not set
+# CONFIG_BRIDGE_EBT_PKTTYPE is not set
+# CONFIG_BRIDGE_EBT_REDIRECT is not set
+# CONFIG_BRIDGE_EBT_SNAT is not set
+# CONFIG_BRIDGE_EBT_STP is not set
+# CONFIG_BRIDGE_EBT_T_FILTER is not set
+# CONFIG_BRIDGE_EBT_T_NAT is not set
+# CONFIG_BRIDGE_EBT_ULOG is not set
+# CONFIG_BRIDGE_EBT_VLAN is not set
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_NETFILTER is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_BT is not set
+# CONFIG_BTRFS_ASSERT is not set
+# CONFIG_BTRFS_DEBUG is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_CMTP is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_3WIRE is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_HIDP is not set
+CONFIG_BT_L2CAP=y
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BUILD_BIN2C is not set
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_SCO=y
+CONFIG_BUG=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+# CONFIG_C2PORT is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CAN is not set
+# CONFIG_CAN_GS_USB is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_RCAR is not set
+# CONFIG_CAPI_AVM is not set
+# CONFIG_CAPI_EICON is not set
+# CONFIG_CAPI_TRACE is not set
+CONFIG_CARDBUS=y
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_CARL9170 is not set
+# CONFIG_CARMA_FPGA is not set
+# CONFIG_CARMA_FPGA_PROGRAM is not set
+# CONFIG_CASSINI is not set
+CONFIG_CAVIUM_OCTEON_HELPER=y
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_SOC is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_CED1401 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_CFG80211 is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_DEFAULT_PS is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_WEXT is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24190 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_ISP1704 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_CHARGER_TWL4030 is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_CHELSIO_T4 is not set
+# CONFIG_CHELSIO_T4VF is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_CIFS is not set
+# CONFIG_CIFS_ACL is not set
+# CONFIG_CIFS_DEBUG is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_FSCACHE is not set
+# CONFIG_CIFS_NFSD_EXPORT is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_SMB2 is not set
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CLKSRC_VERSATILE is not set
+CONFIG_CLS_U32_MARK=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CM32181 is not set
+# CONFIG_CM36651 is not set
+# CONFIG_CMA is not set
+CONFIG_CMDLINE=""
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_CMDLINE_EXTEND is not set
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
+# CONFIG_CMDLINE_PARTITION is not set
+# CONFIG_CNIC is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_COMEDI is not set
+# CONFIG_COMMON_CLK_DEBUG is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_QCOM is not set
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMPACTION is not set
+# CONFIG_COMPAL_LAPTOP is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_COMPILE_TEST is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_CONSTRUCTORS=y
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_COPS is not set
+# CONFIG_CORDIC is not set
+# CONFIG_COREDUMP is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+# CONFIG_CPU_IDLE_GOV_MENU is not set
+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_CRASHLOG=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC32_SARWATE=y
+# CONFIG_CRC32_SELFTEST is not set
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SLICEBY8 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_CRC8 is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CROSS_COMPILE=""
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_AEAD is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_AES_ARM is not set
+# CONFIG_CRYPTO_AES_ARM_BS is not set
+# CONFIG_CRYPTO_AES_NI_INTEL is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CMAC is not set
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+# CONFIG_CRYPTO_CRCT10DIF is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_AES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set
+# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set
+# CONFIG_CRYPTO_DEV_CCP is not set
+# CONFIG_CRYPTO_DEV_FSL_CAAM is not set
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_MV_CESA is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QCE is not set
+# CONFIG_CRYPTO_DEV_SAHARA is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
+# CONFIG_CRYPTO_HASH is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_MCRYPTD is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_PCOMP is not set
+# CONFIG_CRYPTO_PCOMP2 is not set
+CONFIG_CRYPTO_PCRYPT=y
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_RNG is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA1_ARM is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+# CONFIG_CRYPTO_TWOFISH_COMMON is not set
+# CONFIG_CRYPTO_USER is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+# CONFIG_CRYPTO_VMAC is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_XZ is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYSTALHD is not set
+# CONFIG_CS5535_MFGPT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_CUSE is not set
+# CONFIG_CW1200 is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXT1E1 is not set
+# CONFIG_CYPRESS_FIRMWARE is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_DCB is not set
+# CONFIG_DDR is not set
+# CONFIG_DE600 is not set
+# CONFIG_DE620 is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+CONFIG_DEBUG_INFO_REDUCED=y
+# CONFIG_DEBUG_INFO_SPLIT is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_KOBJECT_RELEASE is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_LL_UART_8250 is not set
+# CONFIG_DEBUG_LL_UART_PL01X is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_NX_TEST is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_PINCTRL is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RODATA is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_SEMIHOSTING is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_UART_BCM63XX is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_ZBOOT is not set
+# CONFIG_DECNET is not set
+CONFIG_DEFAULT_CUBIC=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_DELL_SMO8800 is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_DEVPORT=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_DEVTMPFS is not set
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_DGAP is not set
+# CONFIG_DGNC is not set
+# CONFIG_DGRP is not set
+# CONFIG_DHT11 is not set
+# CONFIG_DIRECT_IO is not set
+CONFIG_DISABLE_DEV_COREDUMP=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set
+# CONFIG_DISPLAY_CONNECTOR_DVI is not set
+# CONFIG_DISPLAY_CONNECTOR_HDMI is not set
+# CONFIG_DISPLAY_ENCODER_TFP410 is not set
+# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set
+# CONFIG_DISPLAY_PANEL_DPI is not set
+# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_DL2K is not set
+# CONFIG_DLM is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_DMADEVICES_DEBUG is not set
+# CONFIG_DMASCC is not set
+# CONFIG_DMATEST is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_ENGINE is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_LOG_USERSPACE is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_RAID is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DNET is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+CONFIG_DOUBLEFAULT=y
+CONFIG_DQL=y
+# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_DRM is not set
+# CONFIG_DS1682 is not set
+# CONFIG_DTLK is not set
+# CONFIG_DUMMY is not set
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_DVB_AU8522_V4L is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_DWC3_HOST_USB3_LPM_ENABLE is not set
+# CONFIG_DX_SEP is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_E100 is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_E2100 is not set
+# CONFIG_EARLY_PRINTK_8250 is not set
+# CONFIG_EASYCAP is not set
+# CONFIG_ECHO is not set
+# CONFIG_ECONET is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_EDAC is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_DIGSY_MTC_CFG is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_EFS_FS is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_EMAC_ROCKCHIP is not set
+CONFIG_EMBEDDED=y
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_ENIC is not set
+# CONFIG_EPAPR_PARAVIRT is not set
+# CONFIG_EPIC100 is not set
+CONFIG_EPOLL=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_ET131X is not set
+# CONFIG_GATEWORKS_GW16083 is not set
+# CONFIG_GLOB_SELFTEST is not set
+# CONFIG_GS_FPGABOOT is not set
+# CONFIG_ETH16I is not set
+CONFIG_ETHERNET=y
+# CONFIG_ETHOC is not set
+CONFIG_EVENTFD=y
+# CONFIG_EVENT_POWER_TRACING_DEPRECATED is not set
+# CONFIG_EWRK3 is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXPERT=y
+# CONFIG_EXPORTFS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXTCON is not set
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_EXYNOS_ADC is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_F2FS_FS_POSIX_ACL is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_FANOTIFY is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_FAT_FS is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_FB is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_DA8XX is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_IMX is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_MXS is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_PS3 is not set
+# CONFIG_FB_PXA is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_FCOE is not set
+# CONFIG_FCOE_FNIC is not set
+# CONFIG_FDDI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_FENCE_TRACE is not set
+# CONFIG_FHANDLE is not set
+CONFIG_FIB_RULES=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_FIREWIRE_SERIAL is not set
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_FIXED_PHY is not set
+CONFIG_FLATMEM=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FM10K is not set
+# CONFIG_FMC is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_FREEZER is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_FSCACHE is not set
+# CONFIG_FSL_EDMA is not set
+# CONFIG_FSL_XGMAC_MDIO is not set
+CONFIG_FSNOTIFY=y
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_FT1000 is not set
+# CONFIG_FTGMAC100 is not set
+# CONFIG_FTL is not set
+# CONFIG_FTMAC100 is not set
+# CONFIG_FTRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_FUSE_FS is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+# CONFIG_FUSION_SPI is not set
+CONFIG_FUTEX=y
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_GACT_PROB=y
+# CONFIG_GADGET_UAC1 is not set
+# CONFIG_GAMEPORT is not set
+# CONFIG_GCOV is not set
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_GENEVE is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_NET_UTILS=y
+# CONFIG_GENERIC_PHY is not set
+CONFIG_GENERIC_TIME=y
+# CONFIG_GENWQE is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_GIGASET_CAPI is not set
+# CONFIG_GIGASET_DEBUG is not set
+# CONFIG_GP2AP020A00F is not set
+# CONFIG_GPIOLIB is not set
+# CONFIG_GPIO_74X164 is not set
+# CONFIG_GPIO_ADNP is not set
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_BCM_KONA is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_CS5535 is not set
+# CONFIG_GPIO_DWAPB is not set
+# CONFIG_GPIO_EM is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_GRGPIO is not set
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_LANGWELL is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_PL061 is not set
+# CONFIG_GPIO_RCAR is not set
+# CONFIG_GPIO_RDC321X is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_GPIO_SCH311X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_SYSCON is not set
+# CONFIG_GPIO_SYSFS is not set
+# CONFIG_GPIO_TS5500 is not set
+# CONFIG_GPIO_VX855 is not set
+# CONFIG_GPIO_WATCHDOG is not set
+# CONFIG_GPIO_WDT is not set
+# CONFIG_GPIO_XILINX is not set
+# CONFIG_GPIO_ZEVIO is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_HAVE_ARM_ARCH_TIMER is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HCALL_STATS is not set
+# CONFIG_HDLC is not set
+# CONFIG_HDLC_CISCO is not set
+# CONFIG_HDLC_FR is not set
+# CONFIG_HDLC_PPP is not set
+# CONFIG_HDLC_RAW is not set
+# CONFIG_HDLC_RAW_ETH is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_HERMES is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_HFSPLUS_FS_POSIX_ACL is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFS_FS_POSIX_ACL is not set
+# CONFIG_HIBERNATION is not set
+# CONFIG_HID is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GENERIC is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_HUION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LENOVO_TPKBD is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PID is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_PS3REMOTE is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_ARVO is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_KONEPLUS is not set
+# CONFIG_HID_ROCCAT_KOVAPLUS is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_HIPPI is not set
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+# CONFIG_HOSTAP_PCI is not set
+# CONFIG_HOSTAP_PLX is not set
+CONFIG_HOTPLUG=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HP100 is not set
+CONFIG_HPET_MMAP_DEFAULT=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_HP_WIRELESS is not set
+# CONFIG_HSI is not set
+# CONFIG_HSR is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWSPINLOCK_OMAP is not set
+CONFIG_HW_PERF_EVENTS=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_ATMEL is not set
+# CONFIG_HW_RANDOM_EXYNOS is not set
+# CONFIG_HW_RANDOM_GEODE is not set
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_OMAP3_ROM is not set
+# CONFIG_HW_RANDOM_PPC4XX is not set
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM_VIA is not set
+# CONFIG_HYPERV is not set
+# CONFIG_HYSDN is not set
+CONFIG_HZ=100
+CONFIG_HZ_100=y
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_PERIODIC is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCA is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
+# CONFIG_I2C_AU1550 is not set
+# CONFIG_I2C_BCM2835 is not set
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_DESIGNWARE_PCI is not set
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_EG20T is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_HID is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_IBM_IIC is not set
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_ISMT is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+# CONFIG_I2C_MV64XXX is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OCTEON is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_RCAR is not set
+# CONFIG_I2C_RK3X is not set
+# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_SCMI is not set
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_SMBUS is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VERSATILE is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2O is not set
+# CONFIG_I40E is not set
+# CONFIG_I40EVF is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_IBM_EMAC_DEBUG is not set
+# CONFIG_IBM_EMAC_EMAC4 is not set
+# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_EMAC_RGMII is not set
+# CONFIG_IBM_EMAC_TAH is not set
+# CONFIG_IBM_EMAC_ZMII is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_IDE is not set
+# CONFIG_IDEAPAD_LAPTOP is not set
+# CONFIG_IDE_GD is not set
+# CONFIG_IDE_PHISON is not set
+# CONFIG_IDE_PROC_FS is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_IEEE802154_FAKEHARD is not set
+# CONFIG_IFB is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_IIO is not set
+# CONFIG_IIO_BUFFER_CB is not set
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+# CONFIG_IIO_GPIO_TRIGGER is not set
+# CONFIG_IIO_INTERRUPT_TRIGGER is not set
+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_IIO_ST_ACCEL_3AXIS is not set
+# CONFIG_IIO_ST_GYRO_3AXIS is not set
+# CONFIG_IIO_ST_MAGN_3AXIS is not set
+# CONFIG_IIO_ST_PRESS is not set
+# CONFIG_IIO_SYSFS_TRIGGER is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_IMAGE_CMDLINE_HACK is not set
+# CONFIG_IMX_IPUV3_CORE is not set
+CONFIG_INET=y
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_TCP_DIAG is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_INFTL is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_GP2A is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_WISTRON_BTNS is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INT340X_THERMAL is not set
+# CONFIG_INTEL_IDLE is not set
+# CONFIG_INTEL_MEI is not set
+# CONFIG_INTEL_MEI_ME is not set
+# CONFIG_INTEL_MEI_TXE is not set
+# CONFIG_INTEL_MIC_CARD is not set
+# CONFIG_INTEL_MIC_HOST is not set
+# CONFIG_INTEL_MID_PTI is not set
+# CONFIG_INTEL_OAKTRAIL is not set
+# CONFIG_INTEL_RST is not set
+# CONFIG_INTEL_SMARTCONNECT is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_INV_MPU6050_IIO is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IP1000 is not set
+# CONFIG_IP17XX_PHY is not set
+# CONFIG_IP6_NF_FILTER is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_NAT is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_RAW is not set
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_TARGET_LOG is not set
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
+# CONFIG_IPACK_BUS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPV6 is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_SIT_6RD is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_VTI is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2200 is not set
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW2200_PROMISCUOUS is not set
+# CONFIG_IPW2200_QOS is not set
+# CONFIG_IPW2200_RADIOTAP is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_IPX is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_NF_ARPFILTER is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_ARP_MANGLE is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_SECURITY is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IRDA is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_IR_GPIO_CIR is not set
+# CONFIG_IR_HIX5HD2 is not set
+# CONFIG_IR_IGUANA is not set
+# CONFIG_IR_IMG is not set
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_LIRC_CODEC is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_NEC_DECODER is not set
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC5_SZ_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_REDRAT3 is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_IR_TTUSBIR is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_ISCSI_TCP is not set
+CONFIG_ISDN=y
+# CONFIG_ISDN_AUDIO is not set
+# CONFIG_ISDN_CAPI is not set
+# CONFIG_ISDN_CAPI_CAPIDRV is not set
+# CONFIG_ISDN_DIVERSION is not set
+# CONFIG_ISDN_DRV_ACT2000 is not set
+# CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON is not set
+# CONFIG_ISDN_DRV_GIGASET is not set
+# CONFIG_ISDN_DRV_HISAX is not set
+# CONFIG_ISDN_DRV_ICN is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_ISDN_DRV_PCBIT is not set
+# CONFIG_ISDN_DRV_SC is not set
+# CONFIG_ISDN_I4L is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_ISL29125 is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_ISS4xx is not set
+# CONFIG_ITG3200 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_IWLAGN is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWMC3200TOP is not set
+# CONFIG_IXGB is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD2_DEBUG is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_POSIX_ACL is not set
+# CONFIG_JFFS2_FS_SECURITY is not set
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_LZMA=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_ZLIB is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_JME is not set
+CONFIG_JOLIET=y
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_UNCOMPRESSED is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_KERNEL_XZ=y
+CONFIG_KERNFS=y
+# CONFIG_KEXEC is not set
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_CAP1106 is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OMAP4 is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PXA27x is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_SH_KEYSC is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYS is not set
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_KPROBES is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_KSM is not set
+# CONFIG_KSZ884X_PCI is not set
+CONFIG_KUSER_HELPERS=y
+# CONFIG_KVM_GUEST is not set
+# CONFIG_KXCJK1013 is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_L2TP is not set
+# CONFIG_L2TP_ETH is not set
+# CONFIG_L2TP_IP is not set
+# CONFIG_L2TP_V3 is not set
+# CONFIG_LANMEDIA is not set
+# CONFIG_LANTIQ is not set
+# CONFIG_LAPB is not set
+# CONFIG_LASAT is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+CONFIG_LBDAF=y
+# CONFIG_LCD_HX8357 is not set
+# CONFIG_LCD_ILI922X is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_LMS501KF03 is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_LEDS_ATMEL_PWM is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_BLINKM is not set
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_GPIO is not set
+CONFIG_LEDS_GPIO_OF=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_INTEL_SS4200 is not set
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM3556 is not set
+# CONFIG_LEDS_LM355x is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LP5562 is not set
+# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_NET5501 is not set
+# CONFIG_LEDS_OT200 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA9633 is not set
+# CONFIG_LEDS_PCA963X is not set
+# CONFIG_LEDS_PCA9685 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_RENESAS_TPU is not set
+# CONFIG_LEDS_SYSCON is not set
+# CONFIG_LEDS_TCA6507 is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
+CONFIG_LEDS_TRIGGER_NETDEV=y
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+CONFIG_LEDS_TRIGGER_TIMER=y
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_LIB80211_CRYPT_CCMP is not set
+# CONFIG_LIB80211_CRYPT_TKIP is not set
+# CONFIG_LIB80211_CRYPT_WEP is not set
+# CONFIG_LIB80211_DEBUG is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_LIBERTAS_USB is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_LIBIPW_DEBUG is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_LIRC_STAGING is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_LKDTM is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_LOCKD is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKD_V4=y
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_LOGFS is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_LOGO is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+# CONFIG_LOONGSON_MC146818 is not set
+# CONFIG_LP486E is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_LTR501 is not set
+# CONFIG_LTPC is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_LXT_PHY is not set
+CONFIG_LZMA_COMPRESS=y
+CONFIG_LZMA_DECOMPRESS=y
+# CONFIG_LZO_COMPRESS is not set
+# CONFIG_LZO_DECOMPRESS is not set
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+# CONFIG_LZ4HC_COMPRESS is not set
+# CONFIG_M25PXX_PREFER_SMALL_SECTOR_ERASE is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MACB is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MACH_LOONGSON1 is not set
+# CONFIG_MACH_NO_WESTBRIDGE is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_MACVTAP is not set
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MAG3110 is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+# CONFIG_MAILBOX is not set
+# CONFIG_MANGLE_BOOTARGS is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_MAX1027 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MAX5821 is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_MCB is not set
+# CONFIG_MCP320X is not set
+# CONFIG_MCP3422 is not set
+# CONFIG_MCP4725 is not set
+# CONFIG_MCP4922 is not set
+# CONFIG_MCPM is not set
+# CONFIG_MD is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_ATTACH is not set
+# CONFIG_MEDIA_CAMERA_SUPPORT is not set
+# CONFIG_MEDIA_CONTROLLER is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_PARPORT_SUPPORT is not set
+# CONFIG_MEDIA_PCI_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_RC_SUPPORT is not set
+# CONFIG_MEDIA_SDR_SUPPORT is not set
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+# CONFIG_MEDIA_SUPPORT is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_USB_SUPPORT is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_MEMORY is not set
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_MEN_A21_WDT is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MENF21BMC is not set
+# CONFIG_MFD_OMAP_USB_HOST is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_PM8921_CORE is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_RK808 is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_S5M_CORE is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_MFD_STMPE is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_MIGRATION is not set
+CONFIG_MII=y
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MIPS_FPU_EMULATOR is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_O32_FP64_SUPPORT is not set
+# CONFIG_MIPS_PARAVIRT is not set
+# CONFIG_MIPS_SEAD3 is not set
+# CONFIG_MIPS_SIM is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_MISDN is not set
+# CONFIG_MISDN_AVMFRITZ is not set
+# CONFIG_MISDN_HFCPCI is not set
+# CONFIG_MISDN_HFCUSB is not set
+# CONFIG_MISDN_INFINEON is not set
+# CONFIG_MISDN_NETJET is not set
+# CONFIG_MISDN_SPEEDFAX is not set
+# CONFIG_MISDN_W6692 is not set
+# CONFIG_MKISS is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX5_CORE is not set
+# CONFIG_MLX90614 is not set
+# CONFIG_MMA8452 is not set
+# CONFIG_MMC is not set
+# CONFIG_MMC_ARMMMCI is not set
+# CONFIG_MMC_AU1X is not set
+# CONFIG_MMC_BLOCK is not set
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_MMC_BLOCK_MINORS=8
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_CLKGATE is not set
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_MVSDIO is not set
+# CONFIG_MMC_S3C is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SDHCI_ACPI is not set
+# CONFIG_MMC_SDHCI_BCM_KONA is not set
+# CONFIG_MMC_SDHCI_MSM is not set
+# CONFIG_MMC_SDHCI_OF_ARASAN is not set
+# CONFIG_MMC_SDHCI_OF_ESDHC is not set
+# CONFIG_MMC_SDHCI_OF_HLWD is not set
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+# CONFIG_MMC_SDRICOH_CS is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_TEST is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_USDHI6ROL0 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMIOTRACE is not set
+CONFIG_MMU=y
+CONFIG_MODULES=y
+# CONFIG_MODULE_COMPRESS is not set
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_MODULE_STRIPPED=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_MPL115 is not set
+# CONFIG_MPL3115 is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_MSI_LAPTOP is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_AR7_PARTS is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_LATCH_ADDR is not set
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_LPDDR2_NVM is not set
+# CONFIG_MTD_M25P80 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_MYLOADER_PARTS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_AMS_DELTA is not set
+# CONFIG_MTD_NAND_AR934X is not set
+# CONFIG_MTD_NAND_AR934X_HW_ECC is not set
+# CONFIG_MTD_NAND_ATMEL is not set
+# CONFIG_MTD_NAND_AU1550 is not set
+# CONFIG_MTD_NAND_AUTCPU12 is not set
+# CONFIG_MTD_NAND_BCH is not set
+# CONFIG_MTD_NAND_BCM_UMI is not set
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_CM_X270 is not set
+# CONFIG_MTD_NAND_CS553X is not set
+# CONFIG_MTD_NAND_DAVINCI is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_DOCG4 is not set
+# CONFIG_MTD_NAND_ECC is not set
+# CONFIG_MTD_NAND_ECC_BCH is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_NAND_FSL_IFC is not set
+# CONFIG_MTD_NAND_FSL_UPM is not set
+# CONFIG_MTD_NAND_FSMC is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_GPMI_NAND is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_JZ4740 is not set
+# CONFIG_MTD_NAND_MPC5121_NFC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_MXC is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_NDFC is not set
+# CONFIG_MTD_NAND_NOMADIK is not set
+# CONFIG_MTD_NAND_NUC900 is not set
+# CONFIG_MTD_NAND_OMAP2 is not set
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+# CONFIG_MTD_NAND_ORION is not set
+# CONFIG_MTD_NAND_PASEMI is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_PPCHAMELEONEVB is not set
+# CONFIG_MTD_NAND_PXA3xx is not set
+# CONFIG_MTD_NAND_RB4XX is not set
+# CONFIG_MTD_NAND_RB750 is not set
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_RTC_FROM4 is not set
+# CONFIG_MTD_NAND_S3C2410 is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_SH_FLCTL is not set
+# CONFIG_MTD_NAND_SOCRATES is not set
+# CONFIG_MTD_NAND_SPIA is not set
+# CONFIG_MTD_NAND_TMIO is not set
+# CONFIG_MTD_NAND_TXX9NDFMC is not set
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OOPS is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_ROM is not set
+CONFIG_MTD_ROOTFS_ROOT_DEV=y
+CONFIG_MTD_ROOTFS_SPLIT=y
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+# CONFIG_MTD_SPI_NOR is not set
+# CONFIG_MTD_SPINAND_MT29F is not set
+CONFIG_MTD_SPLIT=y
+# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_EVA_FW is not set
+# CONFIG_MTD_SPLIT_FIRMWARE is not set
+CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
+# CONFIG_MTD_SPLIT_FIT_FW is not set
+# CONFIG_MTD_SPLIT_LZMA_FW is not set
+# CONFIG_MTD_SPLIT_SEAMA_FW is not set
+CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y
+CONFIG_MTD_SPLIT_SUPPORT=y
+# CONFIG_MTD_SPLIT_TRX_FW is not set
+# CONFIG_MTD_SPLIT_TPLINK_FW is not set
+# CONFIG_MTD_SPLIT_UIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_WRGG_FW is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SWAP is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UIMAGE_SPLIT is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_MVMDIO is not set
+# CONFIG_MVSW61XX_PHY is not set
+# CONFIG_MVSW6171_PHY is not set
+# CONFIG_MVSWITCH_PHY is not set
+# CONFIG_MWAVE is not set
+# CONFIG_MWIFIEX is not set
+# CONFIG_MWL8K is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NAU7802 is not set
+# CONFIG_NBPFAXI_DMA is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NEC_MARKEINS is not set
+CONFIG_NET=y
+# CONFIG_NETCONSOLE is not set
+CONFIG_NETDEVICES=y
+CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set
+# CONFIG_NETFILTER_TPROXY is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_NETFILTER_XT_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+# CONFIG_NETFILTER_XT_MATCH_LAYER7 is not set
+# CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_CT is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETROM is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NET_9P is not set
+# CONFIG_NET_ACT_CSUM is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_POLICE is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+CONFIG_NET_CADENCE=y
+# CONFIG_NET_CALXEDA_XGMAC is not set
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_BPF is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_IND=y
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_U32 is not set
+CONFIG_NET_CORE=y
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_NET_DSA_BCM_SF2 is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6171 is not set
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_TAG_DSA is not set
+# CONFIG_NET_DSA_TAG_EDSA is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_TEXT is not set
+# CONFIG_NET_EMATCH_U32 is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_FC is not set
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPVTI is not set
+# CONFIG_NET_IP_TUNNEL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_KEY is not set
+# CONFIG_NET_KEY_MIGRATE is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+CONFIG_NET_PCI=y
+# CONFIG_NET_PCMCIA is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+CONFIG_NET_RX_BUSY_POLL=y
+# CONFIG_NET_SB1000 is not set
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_ATM is not set
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_CHOKE is not set
+# CONFIG_NET_SCH_CODEL is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_DSMARK is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_SCH_FQ is not set
+CONFIG_NET_SCH_FQ_CODEL=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_HHF is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_PIE is not set
+# CONFIG_NET_SCH_PLUG is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_QFQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFB is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCTPPROBE is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_NET_UDP_TUNNEL is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_8390=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CIRRUS=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_FARADAY=y
+CONFIG_NET_VENDOR_FREESCALE=y
+CONFIG_NET_VENDOR_FUJITSU=y
+CONFIG_NET_VENDOR_HISILICON=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MICROCHIP=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SILICOM=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_TOSHIBA=y
+CONFIG_NET_VENDOR_VIA=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_NET_VENDOR_XILINX=y
+CONFIG_NET_VENDOR_XIRCOM=y
+# CONFIG_NET_XGENE is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_NFC is not set
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_DEPRECATED is not set
+# CONFIG_NFSD_V2_ACL is not set
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFS_ACL_SUPPORT is not set
+CONFIG_NFS_COMMON=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_FSCACHE is not set
+# CONFIG_NFS_SWAP is not set
+# CONFIG_NFS_V2 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_V4_1 is not set
+# CONFIG_NFTL is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IPV4 is not set
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+# CONFIG_NF_CONNTRACK_RTSP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CONNTRACK_ZONES is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_GRE is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_NF_LOG_ARP is not set
+# CONFIG_NF_LOG_IPV4 is not set
+# CONFIG_NF_NAT is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set
+# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set
+# CONFIG_NF_NAT_NEEDED is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_PROTO_GRE is not set
+# CONFIG_NF_NAT_RTSP is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NF_TABLES is not set
+# CONFIG_NI52 is not set
+# CONFIG_NI65 is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_NIU is not set
+# CONFIG_NL80211_TESTMODE is not set
+CONFIG_NLATTR=y
+# CONFIG_NLMON is not set
+# CONFIG_NLM_XLP_BOARD is not set
+# CONFIG_NLM_XLR_BOARD is not set
+# CONFIG_NLS is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_NO_BOOTMEM is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_NO_HZ_FULL is not set
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_NTP_PPS is not set
+# CONFIG_NVRAM is not set
+# CONFIG_NV_TCO is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_N_GSM is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_OBS600 is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_OC_ETM is not set
+# CONFIG_OF_SELFTEST is not set
+# CONFIG_OMAP2_DSS_DEBUG is not set
+# CONFIG_OMAP2_DSS_DEBUGFS is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP_CONTROL_USB is not set
+# CONFIG_OMAP_OCP2SCP is not set
+# CONFIG_OMAP_USB2 is not set
+# CONFIG_OMAP_USB3 is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_OPROFILE is not set
+# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
+# CONFIG_ORION_WATCHDOG is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_OVERLAY_FS=y
+# CONFIG_P54_COMMON is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PANEL is not set
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PANIC_ON_OOPS_VALUE=1
+CONFIG_PANIC_TIMEOUT=1
+# CONFIG_PANTHERLORD_FF is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PARPORT_1284 is not set
+# CONFIG_PARPORT_AX88796 is not set
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_ISAPNP is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OCTEON_CF is not set
+# CONFIG_PATA_OF_PLATFORM is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+# CONFIG_PC300TOO is not set
+# CONFIG_PCCARD is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_PCI200SYN is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PCI_ATMEL is not set
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_PCI_HOST_GENERIC is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_PASID is not set
+# CONFIG_PCI_PRI is not set
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCMCIA is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_XIRCOM is not set
+# CONFIG_PCNET32 is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PD6729 is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_PHONE is not set
+# CONFIG_PHONET is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+# CONFIG_PHY_EXYNOS_DP_VIDEO is not set
+# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
+# CONFIG_PHY_QCOM_DWC3 is not set
+# CONFIG_PHY_SAMSUNG_USB2 is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_PID_NS is not set
+CONFIG_PINCONF=y
+# CONFIG_PINCTRL is not set
+# CONFIG_PINCTRL_CAPRI is not set
+# CONFIG_PINCTRL_EXYNOS is not set
+# CONFIG_PINCTRL_EXYNOS5440 is not set
+# CONFIG_PINCTRL_MSM8X74 is not set
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINMUX=y
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_PLIP is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PM is not set
+# CONFIG_PMBUS is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_PM_RUNTIME is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_POWERTV is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_VERSATILE is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PPC4xx_GPIO is not set
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+# CONFIG_PPC_EMULATED_STATS is not set
+# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
+# CONFIG_PPP is not set
+# CONFIG_PPPOATM is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+CONFIG_PPP_FILTER=y
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPS is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_PARPORT is not set
+# CONFIG_PPS_DEBUG is not set
+# CONFIG_PPTP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTK=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_PRISM2_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_PROBE_INITRD_HEADER is not set
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_PROC_STRIPPED=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILING is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_PROVE_RCU is not set
+# CONFIG_PROVE_RCU_DELAY is not set
+# CONFIG_PSB6970_PHY is not set
+# CONFIG_PSTORE is not set
+# CONFIG_PTP_1588_CLOCK is not set
+# CONFIG_PTP_1588_CLOCK_IXP46X is not set
+# CONFIG_PTP_1588_CLOCK_PCH is not set
+# CONFIG_PWM is not set
+# CONFIG_PWM_PCA9685 is not set
+# CONFIG_QCA7000 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_QLCNIC is not set
+# CONFIG_QLGE is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_R3964 is not set
+# CONFIG_R6040 is not set
+# CONFIG_R8169 is not set
+# CONFIG_R8187SE is not set
+# CONFIG_R8188EU is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8723AU is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_RALINK is not set
+# CONFIG_RAMOOPS is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+# CONFIG_RAPIDIO is not set
+# CONFIG_RAR_REGISTER is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_RCU_CPU_STALL_INFO is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_USER_QS is not set
+# CONFIG_RC_ATI_REMOTE is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_RC_DECODERS is not set
+# CONFIG_RC_LOOPBACK is not set
+# CONFIG_RC_MAP is not set
+# CONFIG_RDS is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_LZ4 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_REDWOOD is not set
+# CONFIG_REGMAP is not set
+# CONFIG_REGMAP_I2C is not set
+# CONFIG_REGMAP_MMIO is not set
+# CONFIG_REGMAP_SPI is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_GPIO is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+# CONFIG_REGULATOR_TI_ABB is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+# CONFIG_REISERFS_FS_XATTR
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_RELAY is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_RFKILL is not set
+# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_ROSE is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DEBUG is not set
+# CONFIG_RTC_DRV_AU1XXX is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_EP93XX is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_RTC_DRV_HYM8563 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL12057 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+# CONFIG_RTC_DRV_MOXART is not set
+# CONFIG_RTC_DRV_MPC5121 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_OMAP is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_PS3 is not set
+# CONFIG_RTC_DRV_PT7C4338 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_RTC7301 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_SUN6I is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_XGENE is not set
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_SYSTOHC=y
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_RTL8192E is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTL8306_PHY is not set
+# CONFIG_RTL8366RB_PHY is not set
+# CONFIG_RTL8366S_PHY is not set
+# CONFIG_RTL8366_SMI is not set
+# CONFIG_RTL8366_SMI_DEBUG_FS is not set
+# CONFIG_RTL8367B_PHY is not set
+# CONFIG_RTL8367_PHY is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_RTL_CARDS is not set
+# CONFIG_RTS5139 is not set
+# CONFIG_RTS5208 is not set
+# CONFIG_RTS_PSTOR is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_RUNTIME_DEBUG is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_S2IO is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_SAMSUNG_LAPTOP is not set
+# CONFIG_SAMSUNG_USB2PHY is not set
+# CONFIG_SAMSUNG_USB3PHY is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_DWC is not set
+# CONFIG_SATA_FSL is not set
+# CONFIG_SATA_HIGHBANK is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_RCAR is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SBC_FITPC2_WATCHDOG is not set
+# CONFIG_SBE_2T3E3 is not set
+# CONFIG_SBYPASS is not set
+# CONFIG_SC92031 is not set
+# CONFIG_SCA3000 is not set
+# CONFIG_SCC is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHED_MC is not set
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+# CONFIG_SCHED_SMT is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CHELSIO_FCOE is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_ESAS2R is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ISCI is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_LPFC is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MPT3SAS is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVUMI is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_PMCRAID is not set
+CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_VIRTIO is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SEEQ8005 is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADC128D818 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_ADT7310 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATK0110 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_G762 is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_GSC is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_SENSORS_HIH6130 is not set
+# CONFIG_SENSORS_HMC5843 is not set
+# CONFIG_SENSORS_HMC5843_I2C is not set
+# CONFIG_SENSORS_HMC5843_SPI is not set
+# CONFIG_SENSORS_HTU21 is not set
+# CONFIG_SENSORS_I5500 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_IIO_HWMON is not set
+# CONFIG_SENSORS_INA209 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LM95234 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_LTC2945 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4222 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4260 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MAX6697 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_POWR1220 is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SHTC1 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP103 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_SENSORS_VEXPRESS is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_ACCENT is not set
+# CONFIG_SERIAL_8250_BOCA is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_DMA=y
+# CONFIG_SERIAL_8250_DW is not set
+# CONFIG_SERIAL_8250_EM is not set
+# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_FOURPORT is not set
+# CONFIG_SERIAL_8250_FINTEK is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_RSA is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_SYSRQ is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_EARLYCON=y
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MAX310X is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_UARTLITE is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SFC is not set
+# CONFIG_SFI is not set
+# CONFIG_SGETMASK_SYSCALL is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SGI_PARTITION is not set
+CONFIG_SHMEM=y
+# CONFIG_SH_ETH is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SI7005 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIGMA is not set
+CONFIG_SIGNALFD=y
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SKY2_DEBUG is not set
+CONFIG_SLAB=y
+CONFIG_SLABINFO=y
+# CONFIG_SLHC is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_SLIP is not set
+# CONFIG_SLOB is not set
+# CONFIG_SLUB is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SMARTJOYPLUS_FF is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMC9194 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_SMP is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_SND is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_AD1816A is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ADLIB is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_ALS100 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_ATMEL_AC97C is not set
+# CONFIG_SND_ATMEL_SOC is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT2320 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BCD2000 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DESIGNWARE_I2S is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FIREWIRE is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_HDA_INPUT_JACK is not set
+# CONFIG_SND_HDA_INTEL is not set
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_HWDEP is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_ISA is not set
+# CONFIG_SND_KIRKWOOD_SOC is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_MIPS is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MPC52xx_SOC_EFIKA is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
+# CONFIG_SND_MXS_SOC is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_SND_OXYGEN is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_PCM is not set
+# CONFIG_SND_PCMCIA is not set
+# CONFIG_SND_PCM_OSS is not set
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_PORTMAN2X4 is not set
+# CONFIG_SND_POWERPC_SOC is not set
+# CONFIG_SND_PPC is not set
+# CONFIG_SND_RAWMIDI is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_SIMPLE_CARD is not set
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SND_SOC_ADAU1701 is not set
+# CONFIG_SND_SOC_AK4104 is not set
+# CONFIG_SND_SOC_AK4554 is not set
+# CONFIG_SND_SOC_AK4642 is not set
+# CONFIG_SND_SOC_AK5386 is not set
+# CONFIG_SND_SOC_ALC5623 is not set
+# CONFIG_SND_SOC_AU1XAUDIO is not set
+# CONFIG_SND_SOC_AU1XPSC is not set
+# CONFIG_SND_SOC_CACHE_LZO is not set
+# CONFIG_SND_SOC_CS35L32 is not set
+# CONFIG_SND_SOC_CS4265 is not set
+# CONFIG_SND_SOC_CS4270 is not set
+# CONFIG_SND_SOC_CS4271 is not set
+# CONFIG_SND_SOC_CS42L52 is not set
+# CONFIG_SND_SOC_CS42L56 is not set
+# CONFIG_SND_SOC_CS42L73 is not set
+# CONFIG_SND_SOC_CS42XX8_I2C is not set
+# CONFIG_SND_SOC_ES8328 is not set
+# CONFIG_SND_SOC_EUKREA_TLV320 is not set
+# CONFIG_SND_SOC_FSL_ASOC_CARD is not set
+# CONFIG_SND_SOC_FSL_ASRC is not set
+# CONFIG_SND_SOC_FSL_ESAI is not set
+# CONFIG_SND_SOC_FSL_SAI is not set
+# CONFIG_SND_SOC_FSL_SPDIF is not set
+# CONFIG_SND_SOC_HDMI_CODEC is not set
+# CONFIG_SND_SOC_IMX_ES8328 is not set
+# CONFIG_SND_SOC_IMX_SPDIF is not set
+# CONFIG_SND_SOC_IMX_WM8962 is not set
+# CONFIG_SND_SOC_INTEL_SST is not set
+# CONFIG_SND_SOC_MPC5200_AC97 is not set
+# CONFIG_SND_SOC_MPC5200_I2S is not set
+# CONFIG_SND_SOC_PCM1681 is not set
+# CONFIG_SND_SOC_PCM1792A is not set
+# CONFIG_SND_SOC_PCM512x_I2C is not set
+# CONFIG_SND_SOC_PCM512x_SPI is not set
+# CONFIG_SND_SOC_SGTL5000 is not set
+# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
+# CONFIG_SND_SOC_SPDIF is not set
+# CONFIG_SND_SOC_SSM2602_I2C is not set
+# CONFIG_SND_SOC_SSM2602_SPI is not set
+# CONFIG_SND_SOC_SSM4567 is not set
+# CONFIG_SND_SOC_STA350 is not set
+# CONFIG_SND_SOC_TAS2552 is not set
+# CONFIG_SND_SOC_TAS5086 is not set
+# CONFIG_SND_SOC_TLV320AIC31XX is not set
+# CONFIG_SND_SOC_TLV320AIC3X is not set
+# CONFIG_SND_SOC_TPA6130A2 is not set
+# CONFIG_SND_SOC_WM8510 is not set
+# CONFIG_SND_SOC_WM8523 is not set
+# CONFIG_SND_SOC_WM8580 is not set
+# CONFIG_SND_SOC_WM8711 is not set
+# CONFIG_SND_SOC_WM8728 is not set
+# CONFIG_SND_SOC_WM8731 is not set
+# CONFIG_SND_SOC_WM8737 is not set
+# CONFIG_SND_SOC_WM8741 is not set
+# CONFIG_SND_SOC_WM8750 is not set
+# CONFIG_SND_SOC_WM8753 is not set
+# CONFIG_SND_SOC_WM8770 is not set
+# CONFIG_SND_SOC_WM8776 is not set
+# CONFIG_SND_SOC_WM8804 is not set
+# CONFIG_SND_SOC_WM8903 is not set
+# CONFIG_SND_SOC_WM8962 is not set
+# CONFIG_SND_SOC_WM8978 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_SSCAPE is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_TIMER is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_6FIRE is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_HIFACE is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_WAVEFRONT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_SOC_HAS_OMAP2_SDRC is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SOLO6X10 is not set
+# CONFIG_SONYPI is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_SOUND is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_SP5100_TCO is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+# CONFIG_SPARSE_IRQ is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_SPEAKUP is not set
+# CONFIG_SPI is not set
+# CONFIG_SPINLOCK_TEST is not set
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_AU1550 is not set
+# CONFIG_SPI_BCM2835 is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_BUTTERFLY is not set
+# CONFIG_SPI_CADENCE is not set
+# CONFIG_SPI_DEBUG is not set
+# CONFIG_SPI_DESIGNWARE is not set
+# CONFIG_SPI_FSL_DSPI is not set
+# CONFIG_SPI_FSL_ESPI is not set
+# CONFIG_SPI_FSL_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_GPIO_OLD is not set
+# CONFIG_SPI_LM70_LLP is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_SPI_MPC52xx is not set
+# CONFIG_SPI_MPC52xx_PSC is not set
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_OCTEON is not set
+# CONFIG_SPI_ORION is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_PPC4xx is not set
+# CONFIG_SPI_PXA2XX is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_RAMIPS is not set
+# CONFIG_SPI_ROCKCHIP is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TI_QSPI is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_XWAY is not set
+# CONFIG_SPMI is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+# CONFIG_SQUASHFS_DECOMP_SINGLE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+# CONFIG_SQUASHFS_FILE_CACHE is not set
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_ZLIB is not set
+# CONFIG_SRAM is not set
+# CONFIG_SSB is not set
+# CONFIG_SSBI is not set
+# CONFIG_SSB_DEBUG is not set
+# CONFIG_SSB_DRIVER_GPIO is not set
+# CONFIG_SSB_PCMCIAHOST is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSFDC is not set
+CONFIG_STACKTRACE_SUPPORT=y
+# CONFIG_STACKTRACE is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_MEDIA is not set
+CONFIG_STANDALONE=y
+CONFIG_STDBINUTILS=y
+# CONFIG_STE10XP is not set
+# CONFIG_STE_MODEM_RPROC is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_STMMAC_PLATFORM is not set
+# CONFIG_STMMAC_PCI is not set
+CONFIG_STP=y
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SUSPEND is not set
+CONFIG_SWAP=y
+# CONFIG_SWCONFIG is not set
+# CONFIG_SWCONFIG_LEDS is not set
+# CONFIG_SXGBE_ETH is not set
+# CONFIG_SYNCLINK_CS is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_SYSFS=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_SYSTEMPORT is not set
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_T5403 is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_TASKS_RCU is not set
+# CONFIG_TC35815 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TCIC is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_DCTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_TCS3414 is not set
+# CONFIG_TCS3472 is not set
+# CONFIG_TEGRA_HOST1X is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_MODULE is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_USER_COPY is not set
+CONFIG_TEXTSEARCH=y
+# CONFIG_TEXTSEARCH_BM is not set
+# CONFIG_TEXTSEARCH_FSM is not set
+# CONFIG_TEXTSEARCH_KMP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_THUNDERBOLT is not set
+# CONFIG_TICK_CPU_ACCOUNTING is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_TIFM_CORE is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_TIMB_DMA is not set
+CONFIG_TIMERFD=y
+# CONFIG_TIMER_STATS is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TIPC is not set
+# CONFIG_TI_ADC081C is not set
+# CONFIG_TI_ADC128S052 is not set
+# CONFIG_TI_AM335X_ADC is not set
+# CONFIG_TI_CPSW is not set
+# CONFIG_TI_CPTS is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_TI_DAVINCI_CPDMA is not set
+# CONFIG_TI_DAVINCI_MDIO is not set
+# CONFIG_TI_ST is not set
+# CONFIG_TLAN is not set
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_TMP006 is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_TOSHIBA_HAPS is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_EGALAX is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_ILI210X is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_MMS114 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_S3C2410 is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_SUR40 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_ZFORCE is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TR is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_TRACE_SINK is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TSL2x7x is not set
+# CONFIG_TSL4531 is not set
+CONFIG_TTY=y
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_TUN is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6030_GPADC is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_TYPHOON is not set
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_UDF_FS is not set
+CONFIG_UDF_NLS=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_UFS_FS is not set
+# CONFIG_UHID is not set
+CONFIG_UIDGID_STRICT_TYPE_CHECKS=y
+# CONFIG_UIO is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_UNIX_DIAG is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_UPROBE_EVENT is not set
+# CONFIG_UPROBES is not set
+# CONFIG_USB is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_ADUTUX is not set
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AMD5536UDC is not set
+CONFIG_USB_AN2720=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_ATM is not set
+CONFIG_USB_BELKIN=y
+# CONFIG_USB_BTMTK is not set
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_CONFIGFS is not set
+# CONFIG_USB_CXACRU is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEFAULT_PERSIST=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DUMMY_HCD is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_DWC2_DUAL_ROLE is not set
+# CONFIG_USB_DWC2_HOST is not set
+# CONFIG_USB_DWC2_PERIPHERAL is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC3_EXYNOS is not set
+# CONFIG_USB_DWC3_QCOM is not set
+# CONFIG_USB_DWC3_PCI is not set
+# CONFIG_USB_DWC3_KEYSTONE is not set
+# CONFIG_USB_DWC_OTG_LPM is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_EG20T is not set
+# CONFIG_USB_EHCI_HCD_AT91 is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_EHCI_MSM is not set
+# CONFIG_USB_EHCI_MV is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_ET61X251 is not set
+CONFIG_USB_EZUSB=y
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_FOTG210_UDC is not set
+# CONFIG_USB_FSL_USB2 is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FUSB300 is not set
+# CONFIG_USB_FUSBH200_HCD is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+CONFIG_USB_GADGET_VBUS_DRAW=2
+# CONFIG_USB_GADGET_XILINX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GOKU is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_GR_UDC is not set
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_DTCS033 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_JL2005BCD is not set
+# CONFIG_USB_GSPCA_KINECT is not set
+# CONFIG_USB_GSPCA_KONICA is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_NW80X is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SE401 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA1528 is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_SQ930X is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STK1135 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TOPRO is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_VICAM is not set
+# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_G_WEBCAM is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_INPUT_IMS_PCU is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_IP_COMMON is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LIBUSUAL is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_MAX3421_HCD is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_MSM_OTG is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MV_U3D is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_NET2280 is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_CDC_MBIM is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_DRIVERS is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_QMI_WWAN is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD_PCI is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+# CONFIG_USB_OHCI_HCD_PPC_SOC is not set
+# CONFIG_USB_OHCI_HCD_SSB is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_PWC_INPUT_EVDEV is not set
+# CONFIG_USB_PXA27X is not set
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_RCAR_PHY is not set
+# CONFIG_USB_RENESAS_USBHS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_USB_S3C_HSOTG is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_MXUPORT is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SIMPLE is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_ZTE is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_SPEEDTOUCH is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_TMC is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_UEAGLEATM is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_XUSBATM is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USELIB is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+# CONFIG_USE_OF is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_UWB is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_VCNL4000 is not set
+# CONFIG_VETH is not set
+# CONFIG_VEXPRESS_CONFIG is not set
+# CONFIG_VF610_ADC is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VGA_ARB is not set
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_AK881X is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_CX2341X is not set
+# CONFIG_VIDEO_CX25840 is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_DM6446_CCDC is not set
+# CONFIG_VIDEO_DT3155 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_GO7007 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_IR_I2C is not set
+# CONFIG_VIDEO_IVTV is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_MEDIA is not set
+# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set
+# CONFIG_VIDEO_ML86V7667 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_OMAP2_VOUT is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_SAA6588 is not set
+# CONFIG_VIDEO_SAA6752HS is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+# CONFIG_VIDEO_SONY_BTF_MPX is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_THS8200 is not set
+# CONFIG_VIDEO_TIMBERDALE is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_TW2804 is not set
+# CONFIG_VIDEO_TW9903 is not set
+# CONFIG_VIDEO_TW9906 is not set
+# CONFIG_VIDEO_UDA1342 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_USBTV is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_VIDEO_V4L2 is not set
+# CONFIG_VIDEO_V4L2_COMMON is not set
+# CONFIG_VIDEO_V4L2_INT_DEVICE is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_VPX3220 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTUALIZATION is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_VITESSE_PHY is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_VLAN_8021Q_MVRP is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_VMSPLIT_1G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_2G_OPT is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMWARE_PVSCSI is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_VORTEX is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_VT is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_VXGE is not set
+# CONFIG_VXLAN is not set
+# CONFIG_W1 is not set
+# CONFIG_W1_CON is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_W1_MASTER_MATROX is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+# CONFIG_W1_SLAVE_DS2406 is not set
+# CONFIG_W1_SLAVE_DS2408 is not set
+# CONFIG_W1_SLAVE_DS2413 is not set
+# CONFIG_W1_SLAVE_DS2423 is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_DS2780 is not set
+# CONFIG_W1_SLAVE_DS2781 is not set
+# CONFIG_W1_SLAVE_DS28E04 is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W35UND is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83697HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_WAN is not set
+# CONFIG_WANXL is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WD80x3 is not set
+# CONFIG_WDTPCI is not set
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WILINK_PLATFORM_DATA=y
+# CONFIG_WIMAX is not set
+# CONFIG_WIMAX_GDM72XX is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+# CONFIG_WIRELESS_EXT_SYSFS is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_WL18XX is not set
+# CONFIG_WLAGS49_H2 is not set
+# CONFIG_WLAGS49_H25 is not set
+CONFIG_WLAN=y
+# CONFIG_WLCORE is not set
+CONFIG_WL_TI=y
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+# CONFIG_WR_PPMC is not set
+# CONFIG_X25 is not set
+# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set
+# CONFIG_X86_PKG_TEMP_THERMAL is not set
+CONFIG_X86_SYSFB=y
+# CONFIG_XEN is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_IPCOMP is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_WARN is not set
+# CONFIG_XILINX_AXI_EMAC is not set
+# CONFIG_XILINX_EMACLITE is not set
+# CONFIG_XILINX_LL_TEMAC is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_XMON is not set
+# CONFIG_XVMALLOC is not set
+CONFIG_XZ_DEC=y
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_BCJ is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_TEST is not set
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
+# CONFIG_YAFFS_FS is not set
+# CONFIG_YAM is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_YENTA is not set
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_ZD1211RW_DEBUG is not set
+# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_ZLIB_DEFLATE is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZNET is not set
+# CONFIG_ZPOOL is not set
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_ZRAM is not set
+# CONFIG_ZRAM_LZ4_COMPRESS is not set
+# CONFIG_ZSMALLOC is not set
diff --git a/target/linux/generic/config-4.1 b/target/linux/generic/config-4.1
new file mode 100644
index 0000000000..4fae342366
--- /dev/null
+++ b/target/linux/generic/config-4.1
@@ -0,0 +1,4821 @@
+CONFIG_32BIT=y
+# CONFIG_6LOWPAN is not set
+# CONFIG_6PACK is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_9P_FS is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_AB8500_CORE is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_ACENIC is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_ACPI_APEI is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_EXTLOG is not set
+# CONFIG_ACPI_HED is not set
+# CONFIG_ACPI_INT3403_THERMAL is not set
+# CONFIG_ACPI_POWER_METER is not set
+# CONFIG_ACPI_QUICKSTART is not set
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+# CONFIG_AD2S90 is not set
+# CONFIG_AD5064 is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5686 is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5930 is not set
+# CONFIG_AD5933 is not set
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_AD7266 is not set
+# CONFIG_AD7280 is not set
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7303 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD7746 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD7923 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD8366 is not set
+# CONFIG_AD9523 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_AD9850 is not set
+# CONFIG_AD9852 is not set
+# CONFIG_AD9910 is not set
+# CONFIG_AD9951 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+# CONFIG_ADF4350 is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16136 is not set
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_ADIS16255 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADIS16480 is not set
+# CONFIG_ADJD_S311 is not set
+# CONFIG_ADM6996_PHY is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_ADT7316 is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_ADXRS450 is not set
+CONFIG_AEABI=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AGP is not set
+# CONFIG_AHCI_MVEBU is not set
+CONFIG_AIO=y
+# CONFIG_AIRO is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_AK09911 is not set
+# CONFIG_AK8975 is not set
+# CONFIG_AL3320A is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_ALTERA_MBOX is not set
+# CONFIG_ALTERA_STAPL is not set
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_ALX is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_AMD_XGBE is not set
+# CONFIG_AMD_XGBE_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_ANDROID is not set
+CONFIG_ANON_INODES=y
+# CONFIG_APDS9300 is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_APM8018X is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AR5523 is not set
+# CONFIG_AR7 is not set
+# CONFIG_AR8216_PHY is not set
+# CONFIG_AR8216_PHY_LEDS is not set
+# CONFIG_ARCH_ALPINE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BCM2835 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_DIGICOLOR is not set
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_EXYNOS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ARCH_HI3xxx is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_HISI is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_MSM_DT is not set
+# CONFIG_ARCH_MSM_NODT is not set
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_NSPIRE is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2PLUS is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_S3C24XX is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_SHMOBILE_LEGACY is not set
+# CONFIG_ARCH_SHMOBILE_MULTI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_WM8505 is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCNET is not set
+# CONFIG_ARC_EMAC is not set
+# CONFIG_ARM_APPENDED_DTB is not set
+# CONFIG_ARM_ARCH_TIMER is not set
+# CONFIG_ARM_AT91_ETHER is not set
+# CONFIG_ARM_CCI is not set
+# CONFIG_ARM_CCI400_PMU is not set
+# CONFIG_ARM_CCN is not set
+# CONFIG_ARM_CRYPTO is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_ARM_CPUIDLE is not set
+# CONFIG_ARM_CRYPTO is not set
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+# CONFIG_ARM_ERRATA_326103 is not set
+# CONFIG_ARM_ERRATA_364296 is not set
+# CONFIG_ARM_ERRATA_411920 is not set
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_643719 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+# CONFIG_ARM_ERRATA_742230 is not set
+# CONFIG_ARM_ERRATA_742231 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_751472 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+# CONFIG_ARM_ERRATA_754327 is not set
+# CONFIG_ARM_ERRATA_764369 is not set
+# CONFIG_ARM_ERRATA_773022 is not set
+# CONFIG_ARM_ERRATA_775420 is not set
+# CONFIG_ARM_ERRATA_798181 is not set
+# CONFIG_ARM_KERNMEM_PERMS is not set
+# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
+# CONFIG_ARM_KPROBES_TEST is not set
+# CONFIG_ARM_MHU is not set
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+# CONFIG_ARM_PSCI is not set
+# CONFIG_ARM_PTDUMP is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_ARM_VIRT_EXT is not set
+CONFIG_ARPD=y
+# CONFIG_ARTHUR is not set
+# CONFIG_AS3935 is not set
+# CONFIG_ASM9260_TIMER is not set
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_AT803X_PHY is not set
+# CONFIG_ATA is not set
+# CONFIG_ATAGS is not set
+CONFIG_ATAGS_PROC=y
+# CONFIG_ATALK is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_ATA_ACPI is not set
+CONFIG_ATA_BMDMA=y
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_ATA_PIIX is not set
+CONFIG_ATA_SFF=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATH10K is not set
+# CONFIG_ATH25 is not set
+# CONFIG_ATH5K is not set
+# CONFIG_ATH6KL is not set
+# CONFIG_ATH6K_LEGACY is not set
+# CONFIG_ATH79 is not set
+# CONFIG_ATH9K is not set
+# CONFIG_ATH9K_HTC is not set
+# CONFIG_ATH_DEBUG is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_ATMEL_PWM is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_BR2684 is not set
+CONFIG_ATM_BR2684_IPFILTER=y
+# CONFIG_ATM_CLIP is not set
+CONFIG_ATM_CLIP_NO_ICMP=y
+# CONFIG_ATM_DRIVERS is not set
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_FORE200E is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_LANE is not set
+# CONFIG_ATM_MPOA is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_SOLOS is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ATP is not set
+# CONFIG_AUDIT is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_AUTO_ZRELADDR is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_AVERAGE is not set
+# CONFIG_AX25 is not set
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_AX88796 is not set
+# CONFIG_AXP288_ADC is not set
+# CONFIG_AXP288_FUEL_GAUGE is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_B44 is not set
+# CONFIG_SWCONFIG_B53 is not set
+# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set 
+# CONFIG_BACKLIGHT_ADP8870 is not set
+# CONFIG_BACKLIGHT_BD6107 is not set
+# CONFIG_BACKLIGHT_GPIO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_BACKLIGHT_LM3630 is not set
+# CONFIG_BACKLIGHT_LM3630A is not set
+# CONFIG_BACKLIGHT_LM3639 is not set
+# CONFIG_BACKLIGHT_LP855X is not set
+# CONFIG_BACKLIGHT_LV5207LP is not set
+# CONFIG_BACKLIGHT_PANDORA is not set
+# CONFIG_BACKLIGHT_RPI is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BCACHE is not set
+# CONFIG_BCM3384 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_BCM7XXX_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_BCMA is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
+CONFIG_BCMA_POSSIBLE=y
+# CONFIG_BCMGENET is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BE2NET is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_BGMAC is not set
+# CONFIG_BIG_KEYS is not set
+# CONFIG_BIG_LITTLE is not set
+# CONFIG_BINARY_PRINTF is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BITREVERSE=y
+# CONFIG_BLK_CMDLINE_PARSER is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
+# CONFIG_BLK_DEV_CS5536 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDE_AU1XXX is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_PMEM is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_QD65XX is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_THROTTLING is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_UMC8672 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_BLOCK=y
+# CONFIG_BMA180 is not set
+# CONFIG_BMC150_ACCEL is not set
+# CONFIG_BMG160 is not set
+# CONFIG_BMIPS_GENERIC is not set
+# CONFIG_BMP085 is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_BMP280 is not set
+# CONFIG_BNA is not set
+# CONFIG_BNX2 is not set
+# CONFIG_BNX2X is not set
+# CONFIG_BONDING is not set
+# CONFIG_BOOKE_WDT is not set
+CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3
+# CONFIG_BOOT_PRINTK_DELAY is not set
+CONFIG_BOOT_RAW=y
+# CONFIG_BPCTL is not set
+CONFIG_BPF=y
+# CONFIG_BPF_JIT is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_BPQETHER is not set
+CONFIG_BQL=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_BRCMFMAC is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMSTB_GISB_ARB is not set
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_EBT_802_3 is not set
+# CONFIG_BRIDGE_EBT_AMONG is not set
+# CONFIG_BRIDGE_EBT_ARP is not set
+# CONFIG_BRIDGE_EBT_ARPREPLY is not set
+# CONFIG_BRIDGE_EBT_BROUTE is not set
+# CONFIG_BRIDGE_EBT_DNAT is not set
+# CONFIG_BRIDGE_EBT_IP is not set
+# CONFIG_BRIDGE_EBT_IP6 is not set
+# CONFIG_BRIDGE_EBT_LIMIT is not set
+# CONFIG_BRIDGE_EBT_LOG is not set
+# CONFIG_BRIDGE_EBT_MARK is not set
+# CONFIG_BRIDGE_EBT_MARK_T is not set
+# CONFIG_BRIDGE_EBT_NFLOG is not set
+# CONFIG_BRIDGE_EBT_PKTTYPE is not set
+# CONFIG_BRIDGE_EBT_REDIRECT is not set
+# CONFIG_BRIDGE_EBT_SNAT is not set
+# CONFIG_BRIDGE_EBT_STP is not set
+# CONFIG_BRIDGE_EBT_T_FILTER is not set
+# CONFIG_BRIDGE_EBT_T_NAT is not set
+# CONFIG_BRIDGE_EBT_ULOG is not set
+# CONFIG_BRIDGE_EBT_VLAN is not set
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_NETFILTER is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_BT is not set
+# CONFIG_BTRFS_ASSERT is not set
+# CONFIG_BTRFS_DEBUG is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_CMTP is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_3WIRE is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_HIDP is not set
+CONFIG_BT_L2CAP=y
+# CONFIG_BT_LE is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BUILD_BIN2C is not set
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_SCO=y
+# CONFIG_BT_SELFTEST is not set
+CONFIG_BUG=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+# CONFIG_C2PORT is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CAN is not set
+# CONFIG_CAN_GS_USB is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_RCAR is not set
+# CONFIG_CAPI_AVM is not set
+# CONFIG_CAPI_EICON is not set
+# CONFIG_CAPI_TRACE is not set
+CONFIG_CARDBUS=y
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_CARL9170 is not set
+# CONFIG_CARMA_FPGA is not set
+# CONFIG_CARMA_FPGA_PROGRAM is not set
+# CONFIG_CASSINI is not set
+CONFIG_CAVIUM_OCTEON_HELPER=y
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_SOC is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_CC10001_ADC is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_CED1401 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_CFG80211 is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24190 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_ISP1704 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_CHARGER_TWL4030 is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_CHELSIO_T4 is not set
+# CONFIG_CHELSIO_T4VF is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_CIFS is not set
+# CONFIG_CIFS_ACL is not set
+# CONFIG_CIFS_DEBUG is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_FSCACHE is not set
+# CONFIG_CIFS_NFSD_EXPORT is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_SMB2 is not set
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CLK_QORIQ is not set
+# CONFIG_CLKSRC_VERSATILE is not set
+# CONFIG_CLOCK_THERMAL is not set
+CONFIG_CLS_U32_MARK=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CM32181 is not set
+# CONFIG_CM3232 is not set
+# CONFIG_CM3323 is not set
+# CONFIG_CM36651 is not set
+# CONFIG_CMA is not set
+CONFIG_CMDLINE=""
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_CMDLINE_EXTEND is not set
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
+# CONFIG_CMDLINE_PARTITION is not set
+# CONFIG_CNIC is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_COMEDI is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_DEBUG is not set
+# CONFIG_COMMON_CLK_PWM is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_QCOM is not set
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
+# CONFIG_COMPACTION is not set
+# CONFIG_COMPAL_LAPTOP is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_COMPILE_TEST is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_CONSTRUCTORS=y
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_COPS is not set
+# CONFIG_CORDIC is not set
+# CONFIG_COREDUMP is not set
+# CONFIG_CORESIGHT is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+# CONFIG_CPU_IDLE_GOV_MENU is not set
+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_CRASHLOG=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC32_SARWATE=y
+# CONFIG_CRC32_SELFTEST is not set
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SLICEBY8 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_CRC8 is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CROSS_COMPILE=""
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_AEAD is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_AES_ARM is not set
+# CONFIG_CRYPTO_AES_ARM_BS is not set
+# CONFIG_CRYPTO_AES_NI_INTEL is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CMAC is not set
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+# CONFIG_CRYPTO_CRCT10DIF is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_AES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set
+# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set
+# CONFIG_CRYPTO_DEV_CCP is not set
+# CONFIG_CRYPTO_DEV_FSL_CAAM is not set
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set
+# CONFIG_CRYPTO_DEV_MV_CESA is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QCE is not set
+# CONFIG_CRYPTO_DEV_SAHARA is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+# CONFIG_CRYPTO_DRBG_HASH is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
+# CONFIG_CRYPTO_HASH is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_MCRYPTD is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_PCOMP is not set
+# CONFIG_CRYPTO_PCOMP2 is not set
+CONFIG_CRYPTO_PCRYPT=y
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_RNG is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA1_ARM is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+# CONFIG_CRYPTO_TWOFISH_COMMON is not set
+# CONFIG_CRYPTO_USER is not set
+# CONFIG_CRYPTO_USER_API_AEAD is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_RNG is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+# CONFIG_CRYPTO_VMAC is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_XZ is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYSTALHD is not set
+# CONFIG_CS5535_MFGPT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_CUSE is not set
+# CONFIG_CW1200 is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXT1E1 is not set
+# CONFIG_CYPRESS_FIRMWARE is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_DCB is not set
+# CONFIG_DDR is not set
+# CONFIG_DE600 is not set
+# CONFIG_DE620 is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+CONFIG_DEBUG_INFO_REDUCED=y
+# CONFIG_DEBUG_INFO_SPLIT is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_KOBJECT_RELEASE is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_LL_UART_8250 is not set
+# CONFIG_DEBUG_LL_UART_PL01X is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_NX_TEST is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_PINCTRL is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RODATA is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_SEMIHOSTING is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+# CONFIG_DEBUG_UART_BCM63XX is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_ZBOOT is not set
+# CONFIG_DECNET is not set
+CONFIG_DEFAULT_CUBIC=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_DELL_SMO8800 is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_DEVMEM is not set
+CONFIG_DEVPORT=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_DEVTMPFS is not set
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_DGAP is not set
+# CONFIG_DGNC is not set
+# CONFIG_DGRP is not set
+# CONFIG_DHT11 is not set
+# CONFIG_DIRECT_IO is not set
+CONFIG_DISABLE_DEV_COREDUMP=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set
+# CONFIG_DISPLAY_CONNECTOR_DVI is not set
+# CONFIG_DISPLAY_CONNECTOR_HDMI is not set
+# CONFIG_DISPLAY_ENCODER_TFP410 is not set
+# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set
+# CONFIG_DISPLAY_PANEL_DPI is not set
+# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_DL2K is not set
+# CONFIG_DLM is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_DMADEVICES_DEBUG is not set
+# CONFIG_DMASCC is not set
+# CONFIG_DMATEST is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_ENGINE is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_LOG_USERSPACE is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_RAID is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DNET is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+CONFIG_DOUBLEFAULT=y
+CONFIG_DQL=y
+# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_DRM is not set
+# CONFIG_DS1682 is not set
+# CONFIG_DTLK is not set
+# CONFIG_DUMMY is not set
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_DVB_AU8522_V4L is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_DWC3_HOST_USB3_LPM_ENABLE is not set
+# CONFIG_DX_SEP is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_E100 is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_E2100 is not set
+# CONFIG_EARLY_PRINTK_8250 is not set
+# CONFIG_EASYCAP is not set
+# CONFIG_ECHO is not set
+# CONFIG_ECONET is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_EDAC is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_DIGSY_MTC_CFG is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_EFS_FS is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_EMAC_ROCKCHIP is not set
+CONFIG_EMBEDDED=y
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_ENIC is not set
+# CONFIG_EPAPR_PARAVIRT is not set
+# CONFIG_EPIC100 is not set
+CONFIG_EPOLL=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_ET131X is not set
+# CONFIG_GATEWORKS_GW16083 is not set
+# CONFIG_GDB_SCRIPTS is not set
+# CONFIG_GLOB_SELFTEST is not set
+# CONFIG_GS_FPGABOOT is not set
+# CONFIG_ETH16I is not set
+CONFIG_ETHERNET=y
+# CONFIG_ETHOC is not set
+CONFIG_EVENTFD=y
+# CONFIG_EVENT_POWER_TRACING_DEPRECATED is not set
+# CONFIG_EWRK3 is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXPERT=y
+# CONFIG_EXPORTFS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+# CONFIG_EXT4_ENCRYPTION is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXTCON is not set
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_EXYNOS_ADC is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_F2FS_FS_POSIX_ACL is not set
+# CONFIG_F2FS_IO_TRACE is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_FANOTIFY is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_FAT_FS is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_FB is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_DA8XX is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_IMX is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_MXS is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_PS3 is not set
+# CONFIG_FB_PXA is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_SM750 is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_TFT is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_FCOE is not set
+# CONFIG_FCOE_FNIC is not set
+# CONFIG_FDDI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_FENCE_TRACE is not set
+# CONFIG_FHANDLE is not set
+CONFIG_FIB_RULES=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_FIREWIRE_SERIAL is not set
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_FIXED_PHY is not set
+CONFIG_FLATMEM=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FM10K is not set
+# CONFIG_FMC is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_FREEZER is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_FSCACHE is not set
+# CONFIG_FSL_EDMA is not set
+# CONFIG_FSL_XGMAC_MDIO is not set
+CONFIG_FSNOTIFY=y
+# CONFIG_FS_DAX is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_FT1000 is not set
+# CONFIG_FTGMAC100 is not set
+# CONFIG_FTL is not set
+# CONFIG_FTMAC100 is not set
+# CONFIG_FTRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_FUSE_FS is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+# CONFIG_FUSION_SPI is not set
+CONFIG_FUTEX=y
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_GACT_PROB=y
+# CONFIG_GADGET_UAC1 is not set
+# CONFIG_GAMEPORT is not set
+# CONFIG_GCOV is not set
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_GENEVE is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_NET_UTILS=y
+# CONFIG_GENERIC_PHY is not set
+CONFIG_GENERIC_TIME=y
+# CONFIG_GENWQE is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_GIGASET_CAPI is not set
+# CONFIG_GIGASET_DEBUG is not set
+# CONFIG_GP2AP020A00F is not set
+# CONFIG_GPIOLIB is not set
+# CONFIG_GPIO_74X164 is not set
+# CONFIG_GPIO_74XX_MMIO is not set
+# CONFIG_GPIO_ADNP is not set
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_ALTERA is not set
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_BCM_KONA is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_CS5535 is not set
+# CONFIG_GPIO_DWAPB is not set
+# CONFIG_GPIO_EM is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_GRGPIO is not set
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_LANGWELL is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_PL061 is not set
+# CONFIG_GPIO_RCAR is not set
+# CONFIG_GPIO_RDC321X is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_GPIO_SCH311X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_SYSCON is not set
+# CONFIG_GPIO_SYSFS is not set
+# CONFIG_GPIO_TS5500 is not set
+# CONFIG_GPIO_VX855 is not set
+# CONFIG_GPIO_WATCHDOG is not set
+# CONFIG_GPIO_XILINX is not set
+# CONFIG_GPIO_ZEVIO is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_HAVE_ARM_ARCH_TIMER is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HCALL_STATS is not set
+# CONFIG_HDLC is not set
+# CONFIG_HDLC_CISCO is not set
+# CONFIG_HDLC_FR is not set
+# CONFIG_HDLC_PPP is not set
+# CONFIG_HDLC_RAW is not set
+# CONFIG_HDLC_RAW_ETH is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_HERMES is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_HFSPLUS_FS_POSIX_ACL is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFS_FS_POSIX_ACL is not set
+# CONFIG_HIBERNATION is not set
+# CONFIG_HID is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BETOP_FF is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GENERIC is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_HUION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LENOVO_TPKBD is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PID is not set
+# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_PS3REMOTE is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_ARVO is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_KONEPLUS is not set
+# CONFIG_HID_ROCCAT_KOVAPLUS is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_HIP04_ETH is not set
+# CONFIG_HIPPI is not set
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+# CONFIG_HOSTAP_PCI is not set
+# CONFIG_HOSTAP_PLX is not set
+CONFIG_HOTPLUG=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HP100 is not set
+CONFIG_HPET_MMAP_DEFAULT=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_HP_WIRELESS is not set
+# CONFIG_HSI is not set
+# CONFIG_HSR is not set
+# CONFIG_HSU_DMA_PCI is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWSPINLOCK_OMAP is not set
+CONFIG_HW_PERF_EVENTS=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_ATMEL is not set
+# CONFIG_HW_RANDOM_EXYNOS is not set
+# CONFIG_HW_RANDOM_GEODE is not set
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_IPROC_RNG200 is not set
+# CONFIG_HW_RANDOM_OMAP3_ROM is not set
+# CONFIG_HW_RANDOM_PPC4XX is not set
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM_VIA is not set
+# CONFIG_HYPERV is not set
+# CONFIG_HYSDN is not set
+CONFIG_HZ=100
+CONFIG_HZ_100=y
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_PERIODIC is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCA is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
+# CONFIG_I2C_AU1550 is not set
+# CONFIG_I2C_BCM2835 is not set
+# CONFIG_I2C_BCM_IPROC is not set
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_DESIGNWARE_PCI is not set
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_EG20T is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_HID is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_IBM_IIC is not set
+# CONFIG_I2C_IMG is not set
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_ISMT is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+# CONFIG_I2C_MV64XXX is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OCTEON is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_RCAR is not set
+# CONFIG_I2C_RK3X is not set
+# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_SCMI is not set
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_SLAVE is not set
+# CONFIG_I2C_SMBUS is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VERSATILE is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2O is not set
+# CONFIG_I40E is not set
+# CONFIG_I40EVF is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_IBM_EMAC_DEBUG is not set
+# CONFIG_IBM_EMAC_EMAC4 is not set
+# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_EMAC_RGMII is not set
+# CONFIG_IBM_EMAC_TAH is not set
+# CONFIG_IBM_EMAC_ZMII is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_IDE is not set
+# CONFIG_IDEAPAD_LAPTOP is not set
+# CONFIG_IDE_GD is not set
+# CONFIG_IDE_PHISON is not set
+# CONFIG_IDE_PROC_FS is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_IFB is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_IIO is not set
+# CONFIG_IIO_BUFFER_CB is not set
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+# CONFIG_IIO_GPIO_TRIGGER is not set
+# CONFIG_IIO_INTERRUPT_TRIGGER is not set
+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_IIO_SSP_SENSORHUB is not set
+# CONFIG_IIO_ST_ACCEL_3AXIS is not set
+# CONFIG_IIO_ST_GYRO_3AXIS is not set
+# CONFIG_IIO_ST_MAGN_3AXIS is not set
+# CONFIG_IIO_ST_PRESS is not set
+# CONFIG_IIO_SYSFS_TRIGGER is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_IMAGE_CMDLINE_HACK is not set
+# CONFIG_IMGPDC_WDT is not set
+# CONFIG_IMX_IPUV3_CORE is not set
+CONFIG_INET=y
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_TCP_DIAG is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_INFTL is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_INIT_FALLBACK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_GP2A is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_REGULATOR_HAPTIC is not set
+# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_WISTRON_BTNS is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INT340X_THERMAL is not set
+# CONFIG_INTEL_IDLE is not set
+# CONFIG_INTEL_MEI is not set
+# CONFIG_INTEL_MEI_ME is not set
+# CONFIG_INTEL_MEI_TXE is not set
+# CONFIG_INTEL_MIC_CARD is not set
+# CONFIG_INTEL_MIC_HOST is not set
+# CONFIG_INTEL_MID_PTI is not set
+# CONFIG_INTEL_OAKTRAIL is not set
+# CONFIG_INTEL_RST is not set
+# CONFIG_INTEL_SMARTCONNECT is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_INV_MPU6050_IIO is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IP1000 is not set
+# CONFIG_IP17XX_PHY is not set
+# CONFIG_IP6_NF_FILTER is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_NAT is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_RAW is not set
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_TARGET_LOG is not set
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
+# CONFIG_IPACK_BUS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPV6 is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_SIT_6RD is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_VTI is not set
+# CONFIG_IPVLAN is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2200 is not set
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW2200_PROMISCUOUS is not set
+# CONFIG_IPW2200_QOS is not set
+# CONFIG_IPW2200_RADIOTAP is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_IPX is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_NF_ARPFILTER is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_ARP_MANGLE is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_SECURITY is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IRDA is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_IR_GPIO_CIR is not set
+# CONFIG_IR_HIX5HD2 is not set
+# CONFIG_IR_IGORPLUGUSB is not set
+# CONFIG_IR_IGUANA is not set
+# CONFIG_IR_IMG is not set
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_LIRC_CODEC is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_NEC_DECODER is not set
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC5_SZ_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_REDRAT3 is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_IR_TTUSBIR is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_ISCSI_TCP is not set
+CONFIG_ISDN=y
+# CONFIG_ISDN_AUDIO is not set
+# CONFIG_ISDN_CAPI is not set
+# CONFIG_ISDN_CAPI_CAPIDRV is not set
+# CONFIG_ISDN_DIVERSION is not set
+# CONFIG_ISDN_DRV_ACT2000 is not set
+# CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON is not set
+# CONFIG_ISDN_DRV_GIGASET is not set
+# CONFIG_ISDN_DRV_HISAX is not set
+# CONFIG_ISDN_DRV_ICN is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_ISDN_DRV_PCBIT is not set
+# CONFIG_ISDN_DRV_SC is not set
+# CONFIG_ISDN_I4L is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_ISL29125 is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_ISS4xx is not set
+# CONFIG_ITG3200 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_IWLAGN is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWMC3200TOP is not set
+# CONFIG_IXGB is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD2_DEBUG is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_POSIX_ACL is not set
+# CONFIG_JFFS2_FS_SECURITY is not set
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_LZMA=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_ZLIB is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_JME is not set
+CONFIG_JOLIET=y
+# CONFIG_JSA1212 is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_UNCOMPRESSED is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_KERNEL_XZ=y
+CONFIG_KERNFS=y
+# CONFIG_KEXEC is not set
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_BCM is not set
+# CONFIG_KEYBOARD_CAP1106 is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OMAP4 is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PXA27x is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_SH_KEYSC is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_CAP11XX is not set
+# CONFIG_KEYS is not set
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_KMX61 is not set
+# CONFIG_KPROBES is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_KSM is not set
+# CONFIG_KSZ884X_PCI is not set
+CONFIG_KUSER_HELPERS=y
+# CONFIG_KVM_GUEST is not set
+# CONFIG_KXCJK1013 is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_L2TP is not set
+# CONFIG_L2TP_ETH is not set
+# CONFIG_L2TP_IP is not set
+# CONFIG_L2TP_V3 is not set
+# CONFIG_LANMEDIA is not set
+# CONFIG_LANTIQ is not set
+# CONFIG_LAPB is not set
+# CONFIG_LASAT is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+CONFIG_LBDAF=y
+# CONFIG_LCD_AMS369FG06 is not set
+# CONFIG_LCD_HX8357 is not set
+# CONFIG_LCD_ILI922X is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LD9040 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LMS501KF03 is not set
+# CONFIG_LCD_LTV350QV is not set  
+# CONFIG_LCD_S6E63M0 is not set
+# CONFIG_LCD_TDO24M is not set    
+# CONFIG_LCD_VGG2432A4 is not set 
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_LEDS_ATMEL_PWM is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_BLINKM is not set
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_CLASS_FLASH is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_GPIO is not set
+CONFIG_LEDS_GPIO_OF=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_INTEL_SS4200 is not set
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM3556 is not set
+# CONFIG_LEDS_LM355x is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LP5562 is not set
+# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LP8860 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_NET5501 is not set
+# CONFIG_LEDS_OT200 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA9633 is not set
+# CONFIG_LEDS_PCA963X is not set
+# CONFIG_LEDS_PCA9685 is not set
+# CONFIG_LEDS_PM8941_WLED is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_RENESAS_TPU is not set
+# CONFIG_LEDS_SYSCON is not set
+# CONFIG_LEDS_TCA6507 is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
+CONFIG_LEDS_TRIGGER_NETDEV=y
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+CONFIG_LEDS_TRIGGER_TIMER=y
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_LIB80211_CRYPT_CCMP is not set
+# CONFIG_LIB80211_CRYPT_TKIP is not set
+# CONFIG_LIB80211_CRYPT_WEP is not set
+# CONFIG_LIB80211_DEBUG is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_LIBERTAS_USB is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_LIBIPW_DEBUG is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_LIRC_STAGING is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_LKDTM is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_LOCKD is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKD_V4=y
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_LOGFS is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_LOGO is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+# CONFIG_LOONGSON_MC146818 is not set
+# CONFIG_LP486E is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_LTR501 is not set
+# CONFIG_LTPC is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+# CONFIG_LZ4HC_COMPRESS is not set
+CONFIG_LZMA_COMPRESS=y
+CONFIG_LZMA_DECOMPRESS=y
+# CONFIG_LZO_COMPRESS is not set
+# CONFIG_LZO_DECOMPRESS is not set
+# CONFIG_M25PXX_PREFER_SMALL_SECTOR_ERASE is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MACB is not set
+# CONFIG_MACH_ASM9260 is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MACH_LOONGSON1 is not set
+# CONFIG_MACH_NO_WESTBRIDGE is not set
+# CONFIG_MACH_PISTACHIO is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_MACVTAP is not set
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MAG3110 is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+# CONFIG_MAILBOX is not set
+# CONFIG_MANGLE_BOOTARGS is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_MAX1027 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MAX5821 is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_MCB is not set
+# CONFIG_MCP320X is not set
+# CONFIG_MCP3422 is not set
+# CONFIG_MCP4725 is not set
+# CONFIG_MCP4922 is not set
+# CONFIG_MCPM is not set
+# CONFIG_MD is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_ATTACH is not set
+# CONFIG_MEDIA_CAMERA_SUPPORT is not set
+# CONFIG_MEDIA_CONTROLLER is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_PARPORT_SUPPORT is not set
+# CONFIG_MEDIA_PCI_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_RC_SUPPORT is not set
+# CONFIG_MEDIA_SDR_SUPPORT is not set
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+# CONFIG_MEDIA_SUPPORT is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_MEDIA_USB_SUPPORT is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_MEMORY is not set
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_MEMTEST is not set
+# CONFIG_MEN_A21_WDT is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_ATMEL_HLCDC is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MENF21BMC is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_OMAP_USB_HOST is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_PM8921_CORE is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_RK808 is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_S5M_CORE is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SKY81452 is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_MFD_STMPE is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_MIGRATION is not set
+CONFIG_MII=y
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_MIPS_CDMM is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MIPS_FPU_EMULATOR is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_O32_FP64_SUPPORT is not set
+# CONFIG_MIPS_PARAVIRT is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+# CONFIG_MIPS_SEAD3 is not set
+# CONFIG_MIPS_SIM is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_MISDN is not set
+# CONFIG_MISDN_AVMFRITZ is not set
+# CONFIG_MISDN_HFCPCI is not set
+# CONFIG_MISDN_HFCUSB is not set
+# CONFIG_MISDN_INFINEON is not set
+# CONFIG_MISDN_NETJET is not set
+# CONFIG_MISDN_SPEEDFAX is not set
+# CONFIG_MISDN_W6692 is not set
+# CONFIG_MKISS is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX5_CORE is not set
+# CONFIG_MLX90614 is not set
+# CONFIG_MMA8452 is not set
+# CONFIG_MMA9551 is not set
+# CONFIG_MMA9553 is not set
+# CONFIG_MMC is not set
+# CONFIG_MMC_ARMMMCI is not set
+# CONFIG_MMC_AU1X is not set
+# CONFIG_MMC_BLOCK is not set
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_MMC_BLOCK_MINORS=8
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_CLKGATE is not set
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_MVSDIO is not set
+# CONFIG_MMC_S3C is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SDHCI_ACPI is not set
+# CONFIG_MMC_SDHCI_BCM_KONA is not set
+# CONFIG_MMC_SDHCI_IPROC is not set
+# CONFIG_MMC_SDHCI_MSM is not set
+# CONFIG_MMC_SDHCI_OF_ARASAN is not set
+# CONFIG_MMC_SDHCI_OF_ESDHC is not set
+# CONFIG_MMC_SDHCI_OF_HLWD is not set
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+# CONFIG_MMC_SDHCI_F_SDH30 is not set
+# CONFIG_MMC_SDRICOH_CS is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_TEST is not set
+# CONFIG_MMC_TOSHIBA_PCI is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_USDHI6ROL0 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMIOTRACE is not set
+CONFIG_MMU=y
+CONFIG_MODULES=y
+# CONFIG_MODULE_COMPRESS is not set
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_MODULE_STRIPPED=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_MPL115 is not set
+# CONFIG_MPL3115 is not set
+# CONFIG_MPLS is not set
+# CONFIG_MS5611 is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_MSI_LAPTOP is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_AR7_PARTS is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_LATCH_ADDR is not set
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_LPDDR2_NVM is not set
+# CONFIG_MTD_M25P80 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_MYLOADER_PARTS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_AMS_DELTA is not set
+# CONFIG_MTD_NAND_AR934X is not set
+# CONFIG_MTD_NAND_AR934X_HW_ECC is not set
+# CONFIG_MTD_NAND_ATMEL is not set
+# CONFIG_MTD_NAND_AU1550 is not set
+# CONFIG_MTD_NAND_AUTCPU12 is not set
+# CONFIG_MTD_NAND_BCH is not set
+# CONFIG_MTD_NAND_BCM_UMI is not set
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_CM_X270 is not set
+# CONFIG_MTD_NAND_CS553X is not set
+# CONFIG_MTD_NAND_DAVINCI is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_DOCG4 is not set
+# CONFIG_MTD_NAND_ECC is not set
+# CONFIG_MTD_NAND_ECC_BCH is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_NAND_FSL_IFC is not set
+# CONFIG_MTD_NAND_FSL_UPM is not set
+# CONFIG_MTD_NAND_FSMC is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_GPMI_NAND is not set
+# CONFIG_MTD_NAND_H1900 is not set
+# CONFIG_MTD_NAND_HISI504 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_JZ4740 is not set
+# CONFIG_MTD_NAND_MPC5121_NFC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_MXC is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_NDFC is not set
+# CONFIG_MTD_NAND_NOMADIK is not set
+# CONFIG_MTD_NAND_NUC900 is not set
+# CONFIG_MTD_NAND_OMAP2 is not set
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+# CONFIG_MTD_NAND_ORION is not set
+# CONFIG_MTD_NAND_PASEMI is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_PPCHAMELEONEVB is not set
+# CONFIG_MTD_NAND_PXA3xx is not set
+# CONFIG_MTD_NAND_RB4XX is not set
+# CONFIG_MTD_NAND_RB750 is not set
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_RTC_FROM4 is not set
+# CONFIG_MTD_NAND_S3C2410 is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_SH_FLCTL is not set
+# CONFIG_MTD_NAND_SOCRATES is not set
+# CONFIG_MTD_NAND_SPIA is not set
+# CONFIG_MTD_NAND_TMIO is not set
+# CONFIG_MTD_NAND_TXX9NDFMC is not set
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OOPS is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_PARTITIONED_MASTER is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_ROM is not set
+CONFIG_MTD_ROOTFS_ROOT_DEV=y
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+# CONFIG_MTD_SPI_NOR is not set
+# CONFIG_MTD_SPINAND_MT29F is not set
+CONFIG_MTD_SPLIT=y
+# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_EVA_FW is not set
+# CONFIG_MTD_SPLIT_FIRMWARE is not set
+CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
+# CONFIG_MTD_SPLIT_FIT_FW is not set
+# CONFIG_MTD_SPLIT_LZMA_FW is not set
+# CONFIG_MTD_SPLIT_SEAMA_FW is not set
+CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y
+CONFIG_MTD_SPLIT_SUPPORT=y
+# CONFIG_MTD_SPLIT_TRX_FW is not set
+# CONFIG_MTD_SPLIT_TPLINK_FW is not set
+# CONFIG_MTD_SPLIT_UIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_WRGG_FW is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SWAP is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UIMAGE_SPLIT is not set
+CONFIG_MULTIUSER=y
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_MVMDIO is not set
+# CONFIG_MVSW61XX_PHY is not set
+# CONFIG_MVSW6171_PHY is not set
+# CONFIG_MVSWITCH_PHY is not set
+# CONFIG_MWAVE is not set
+# CONFIG_MWL8K is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NAU7802 is not set
+# CONFIG_NBPFAXI_DMA is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NEC_MARKEINS is not set
+CONFIG_NET=y
+# CONFIG_NETCONSOLE is not set
+CONFIG_NETDEVICES=y
+CONFIG_NETDEV_1000=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set
+# CONFIG_NETFILTER_TPROXY is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_NETFILTER_XT_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+# CONFIG_NETFILTER_XT_MATCH_LAYER7 is not set
+# CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_CT is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETROM is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NET_9P is not set
+# CONFIG_NET_ACT_BPF is not set
+# CONFIG_NET_ACT_CSUM is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_POLICE is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+# CONFIG_NET_ACT_VLAN is not set
+CONFIG_NET_CADENCE=y
+# CONFIG_NET_CALXEDA_XGMAC is not set
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_BPF is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_IND=y
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_U32 is not set
+CONFIG_NET_CORE=y
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_NET_DSA_BCM_SF2 is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6171 is not set
+# CONFIG_NET_DSA_MV88E6352 is not set
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_TAG_DSA is not set
+# CONFIG_NET_DSA_TAG_EDSA is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_TEXT is not set
+# CONFIG_NET_EMATCH_U32 is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_FC is not set
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPVTI is not set
+# CONFIG_NET_IP_TUNNEL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_KEY is not set
+# CONFIG_NET_KEY_MIGRATE is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+CONFIG_NET_PCI=y
+# CONFIG_NET_PCMCIA is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+CONFIG_NET_RX_BUSY_POLL=y
+# CONFIG_NET_SB1000 is not set
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_ATM is not set
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_CHOKE is not set
+# CONFIG_NET_SCH_CODEL is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_DSMARK is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_SCH_FQ is not set
+CONFIG_NET_SCH_FQ_CODEL=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_HHF is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_PIE is not set
+# CONFIG_NET_SCH_PLUG is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_QFQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFB is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCTPPROBE is not set
+# CONFIG_NET_SWITCHDEV is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_NET_UDP_TUNNEL is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_8390=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CIRRUS=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_FARADAY=y
+CONFIG_NET_VENDOR_FREESCALE=y
+CONFIG_NET_VENDOR_FUJITSU=y
+CONFIG_NET_VENDOR_HISILICON=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MICROCHIP=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SILICOM=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_TOSHIBA=y
+CONFIG_NET_VENDOR_VIA=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_NET_VENDOR_XILINX=y
+CONFIG_NET_VENDOR_XIRCOM=y
+# CONFIG_NET_XGENE is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_NFC is not set
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_DEPRECATED is not set
+# CONFIG_NFSD_V2_ACL is not set
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFS_ACL_SUPPORT is not set
+CONFIG_NFS_COMMON=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_FSCACHE is not set
+# CONFIG_NFS_SWAP is not set
+# CONFIG_NFS_V2 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_V4_1 is not set
+# CONFIG_NFTL is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IPV4 is not set
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+# CONFIG_NF_CONNTRACK_RTSP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CONNTRACK_ZONES is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_GRE is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_NF_LOG_ARP is not set
+# CONFIG_NF_LOG_IPV4 is not set
+# CONFIG_NF_NAT is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set
+# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set
+# CONFIG_NF_NAT_NEEDED is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_PROTO_GRE is not set
+# CONFIG_NF_NAT_RTSP is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NF_TABLES is not set
+# CONFIG_NI52 is not set
+# CONFIG_NI65 is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_NIU is not set
+CONFIG_NLATTR=y
+# CONFIG_NLMON is not set
+# CONFIG_NLM_XLP_BOARD is not set
+# CONFIG_NLM_XLR_BOARD is not set
+# CONFIG_NLS is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_NO_BOOTMEM is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_NO_HZ_FULL is not set
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_NTP_PPS is not set
+# CONFIG_NVRAM is not set
+# CONFIG_NV_TCO is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_N_GSM is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_OBS600 is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_OC_ETM is not set
+# CONFIG_OF_OVERLAY is not set
+# CONFIG_OF_SELFTEST is not set
+# CONFIG_OF_UNITTEST is not set
+# CONFIG_OMAP2_DSS_DEBUG is not set
+# CONFIG_OMAP2_DSS_DEBUGFS is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP_CONTROL_USB is not set
+# CONFIG_OMAP_OCP2SCP is not set
+# CONFIG_OMAP_USB2 is not set
+# CONFIG_OMAP_USB3 is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_OPROFILE is not set
+# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
+# CONFIG_ORION_WATCHDOG is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_OVERLAY_FS=y
+# CONFIG_P54_COMMON is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_PAGE_OWNER is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PANEL is not set
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PANIC_ON_OOPS_VALUE=1
+CONFIG_PANIC_TIMEOUT=1
+# CONFIG_PANTHERLORD_FF is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PARPORT_1284 is not set
+# CONFIG_PARPORT_AX88796 is not set
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_ISAPNP is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OCTEON_CF is not set
+# CONFIG_PATA_OF_PLATFORM is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+# CONFIG_PC300TOO is not set
+# CONFIG_PCCARD is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_PCI200SYN is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIE_IPROC is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PCI_ATMEL is not set
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_PCI_HOST_GENERIC is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_LAYERSCAPE is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_PASID is not set
+# CONFIG_PCI_PRI is not set
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCMCIA is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_XIRCOM is not set
+# CONFIG_PCNET32 is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PD6729 is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_PHONE is not set
+# CONFIG_PHONET is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+# CONFIG_PHY_EXYNOS_DP_VIDEO is not set
+# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
+# CONFIG_PHY_SAMSUNG_USB2 is not set
+# CONFIG_PHY_QCOM_DWC3 is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_PID_NS is not set
+CONFIG_PINCONF=y
+# CONFIG_PINCTRL is not set
+# CONFIG_PINCTRL_AMD is not set
+# CONFIG_PINCTRL_CAPRI is not set
+# CONFIG_PINCTRL_EXYNOS is not set
+# CONFIG_PINCTRL_EXYNOS5440 is not set
+# CONFIG_PINCTRL_MSM8X74 is not set
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINMUX=y
+# CONFIG_PL320_MBOX is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_PLIP is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PM is not set
+# CONFIG_PMBUS is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_PM_RUNTIME is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_POWERTV is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_RESET_GPIO is not set
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
+# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
+# CONFIG_POWER_RESET_VERSATILE is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PPC4xx_GPIO is not set
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+# CONFIG_PPC_EMULATED_STATS is not set
+# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
+# CONFIG_PPP is not set
+# CONFIG_PPPOATM is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+CONFIG_PPP_FILTER=y
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPS is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_PARPORT is not set
+# CONFIG_PPS_DEBUG is not set
+# CONFIG_PPTP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTK=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_PRISM2_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_PROBE_INITRD_HEADER is not set
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_PROC_STRIPPED=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILING is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_PROVE_RCU is not set
+# CONFIG_PROVE_RCU_DELAY is not set
+# CONFIG_PROVE_RCU_REPEATEDLY is not set
+# CONFIG_PSB6970_PHY is not set
+# CONFIG_PSTORE is not set
+# CONFIG_PTP_1588_CLOCK is not set
+# CONFIG_PTP_1588_CLOCK_IXP46X is not set
+# CONFIG_PTP_1588_CLOCK_PCH is not set
+# CONFIG_PWM is not set
+# CONFIG_PWM_FSL_FTM is not set
+# CONFIG_PWM_PCA9685 is not set
+# CONFIG_QCA7000 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_QLCNIC is not set
+# CONFIG_QLGE is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_QORIQ_CPUFREQ is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_R3964 is not set
+# CONFIG_R6040 is not set
+# CONFIG_R8169 is not set
+# CONFIG_R8187SE is not set
+# CONFIG_R8188EU is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8723AU is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_RALINK is not set
+# CONFIG_RAMOOPS is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+# CONFIG_RAPIDIO is not set
+# CONFIG_RAR_REGISTER is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_RCU_CPU_STALL_INFO is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FAST_NO_HZ is not set
+CONFIG_RCU_KTHREAD_PRIO=0
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_USER_QS is not set
+# CONFIG_RC_ATI_REMOTE is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_RC_DECODERS is not set
+# CONFIG_RC_LOOPBACK is not set
+# CONFIG_RC_MAP is not set
+# CONFIG_RDS is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_LZ4 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_REDWOOD is not set
+# CONFIG_REGMAP is not set
+# CONFIG_REGMAP_I2C is not set
+# CONFIG_REGMAP_MMIO is not set
+# CONFIG_REGMAP_SPI is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_GPIO is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+# CONFIG_REGULATOR_PWM is not set
+# CONFIG_REGULATOR_TI_ABB is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_RELAY is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_RFKILL is not set
+# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_ROCKER is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_ROSE is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DEBUG is not set
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_ARMADA38X is not set
+# CONFIG_RTC_DRV_AU1XXX is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_EP93XX is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_RTC_DRV_HYM8563 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL12057 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+# CONFIG_RTC_DRV_MOXART is not set
+# CONFIG_RTC_DRV_MPC5121 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_OMAP is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_PS3 is not set
+# CONFIG_RTC_DRV_PT7C4338 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_RTC7301 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_SUN6I is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_XGENE is not set
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_SYSTOHC=y
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_RTL8192E is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTL8306_PHY is not set
+# CONFIG_RTL8366RB_PHY is not set
+# CONFIG_RTL8366S_PHY is not set
+# CONFIG_RTL8366_SMI is not set
+# CONFIG_RTL8366_SMI_DEBUG_FS is not set
+# CONFIG_RTL8367B_PHY is not set
+# CONFIG_RTL8367_PHY is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_RTL_CARDS is not set
+# CONFIG_RTS5139 is not set
+# CONFIG_RTS5208 is not set
+# CONFIG_RTS_PSTOR is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_RUNTIME_DEBUG is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_S2IO is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_SAMSUNG_LAPTOP is not set
+# CONFIG_SAMSUNG_USB2PHY is not set
+# CONFIG_SAMSUNG_USB3PHY is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_DWC is not set
+# CONFIG_SATA_FSL is not set
+# CONFIG_SATA_HIGHBANK is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_RCAR is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SBC_FITPC2_WATCHDOG is not set
+# CONFIG_SBE_2T3E3 is not set
+# CONFIG_SBYPASS is not set
+# CONFIG_SC92031 is not set
+# CONFIG_SCA3000 is not set
+# CONFIG_SCC is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHED_MC is not set
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+# CONFIG_SCHED_SMT is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CHELSIO_FCOE is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_ESAS2R is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ISCI is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_LPFC is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MPT3SAS is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVUMI is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_PMCRAID is not set
+CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_VIRTIO is not set
+# CONFIG_SCSI_WD719X is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SEEQ8005 is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADC128D818 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_ADT7310 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATK0110 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_G762 is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_GSC is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_SENSORS_HIH6130 is not set
+# CONFIG_SENSORS_HMC5843 is not set
+# CONFIG_SENSORS_HMC5843_I2C is not set
+# CONFIG_SENSORS_HMC5843_SPI is not set
+# CONFIG_SENSORS_HTU21 is not set
+# CONFIG_SENSORS_I5500 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_IIO_HWMON is not set
+# CONFIG_SENSORS_INA209 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LM95234 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_LTC2945 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4222 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4260 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MAX6697 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_NCT7802 is not set
+# CONFIG_SENSORS_NCT7904 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_POWR1220 is not set
+# CONFIG_SENSORS_PWM_FAN is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SHTC1 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP103 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_SENSORS_VEXPRESS is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_ACCENT is not set
+# CONFIG_SERIAL_8250_BOCA is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_DMA=y
+# CONFIG_SERIAL_8250_DW is not set
+# CONFIG_SERIAL_8250_EM is not set
+# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_FINTEK is not set
+# CONFIG_SERIAL_8250_FOURPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_RSA is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_SYSRQ is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_BCM63XX is not set
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_EARLYCON=y
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MAX310X is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_UARTLITE is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_APBPS2 is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_SUN4I_PS2 is not set
+# CONFIG_SFC is not set
+# CONFIG_SFI is not set
+# CONFIG_SGETMASK_SYSCALL is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SGI_PARTITION is not set
+CONFIG_SHMEM=y
+# CONFIG_SH_ETH is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SI7005 is not set
+# CONFIG_SI7020 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIGMA is not set
+CONFIG_SIGNALFD=y
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SKY2_DEBUG is not set
+CONFIG_SLAB=y
+CONFIG_SLABINFO=y
+# CONFIG_SLHC is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_SLIP is not set
+# CONFIG_SLOB is not set
+# CONFIG_SLUB is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SMARTJOYPLUS_FF is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMC9194 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_SMP is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_SND is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_AD1816A is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ADLIB is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_ALS100 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_ATMEL_AC97C is not set
+# CONFIG_SND_ATMEL_SOC is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT2320 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BCD2000 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DESIGNWARE_I2S is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FIREWIRE is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_HDA_INPUT_JACK is not set
+# CONFIG_SND_HDA_INTEL is not set
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_HWDEP is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_ISA is not set
+# CONFIG_SND_KIRKWOOD_SOC is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_MIPS is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MPC52xx_SOC_EFIKA is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
+# CONFIG_SND_MXS_SOC is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_SND_OXYGEN is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_PCM is not set
+# CONFIG_SND_PCMCIA is not set
+# CONFIG_SND_PCM_OSS is not set
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_PORTMAN2X4 is not set
+# CONFIG_SND_POWERPC_SOC is not set
+# CONFIG_SND_PPC is not set
+# CONFIG_SND_RAWMIDI is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SE6X is not set
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_SIMPLE_CARD is not set
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SND_SOC_ADAU1701 is not set
+# CONFIG_SND_SOC_AK4104 is not set
+# CONFIG_SND_SOC_AK4554 is not set
+# CONFIG_SND_SOC_AK4642 is not set
+# CONFIG_SND_SOC_AK5386 is not set
+# CONFIG_SND_SOC_ALC5623 is not set
+# CONFIG_SND_SOC_AU1XAUDIO is not set
+# CONFIG_SND_SOC_AU1XPSC is not set
+# CONFIG_SND_SOC_CACHE_LZO is not set
+# CONFIG_SND_SOC_CS35L32 is not set
+# CONFIG_SND_SOC_CS4265 is not set
+# CONFIG_SND_SOC_CS4270 is not set
+# CONFIG_SND_SOC_CS4271 is not set
+# CONFIG_SND_SOC_CS4271_I2C is not set
+# CONFIG_SND_SOC_CS4271_SND is not set
+# CONFIG_SND_SOC_CS4271_SPI is not set
+# CONFIG_SND_SOC_CS42L51_I2C is not set
+# CONFIG_SND_SOC_CS42L52 is not set
+# CONFIG_SND_SOC_CS42L56 is not set
+# CONFIG_SND_SOC_CS42L73 is not set
+# CONFIG_SND_SOC_CS42L73 is not set
+# CONFIG_SND_SOC_CS42XX8_I2C is not set
+# CONFIG_SND_SOC_ES8328 is not set
+# CONFIG_SND_SOC_EUKREA_TLV320 is not set
+# CONFIG_SND_SOC_FSL_ASOC_CARD is not set
+# CONFIG_SND_SOC_FSL_ASRC is not set
+# CONFIG_SND_SOC_FSL_ESAI is not set
+# CONFIG_SND_SOC_FSL_SAI is not set
+# CONFIG_SND_SOC_FSL_SPDIF is not set
+# CONFIG_SND_SOC_HDMI_CODEC is not set
+# CONFIG_SND_SOC_IMX_ES8328 is not set
+# CONFIG_SND_SOC_IMX_SPDIF is not set
+# CONFIG_SND_SOC_IMX_WM8962 is not set
+# CONFIG_SND_SOC_INTEL_SST is not set
+# CONFIG_SND_SOC_MPC5200_AC97 is not set
+# CONFIG_SND_SOC_MPC5200_I2S is not set
+# CONFIG_SND_SOC_PCM1681 is not set
+# CONFIG_SND_SOC_PCM1792A is not set
+# CONFIG_SND_SOC_PCM512x_I2C is not set
+# CONFIG_SND_SOC_PCM512x_SPI is not set
+# CONFIG_SND_SOC_QCOM is not set
+# CONFIG_SND_SOC_RT5631 is not set
+# CONFIG_SND_SOC_SGTL5000 is not set
+# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
+# CONFIG_SND_SOC_SPDIF is not set
+# CONFIG_SND_SOC_SSM2602_I2C is not set
+# CONFIG_SND_SOC_SSM2602_SPI is not set
+# CONFIG_SND_SOC_SSM4567 is not set
+# CONFIG_SND_SOC_STA32X is not set
+# CONFIG_SND_SOC_STA350 is not set
+# CONFIG_SND_SOC_TAS2552 is not set
+# CONFIG_SND_SOC_TAS5086 is not set
+# CONFIG_SND_SOC_TFA9879 is not set
+# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
+# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
+# CONFIG_SND_SOC_TLV320AIC31XX is not set
+# CONFIG_SND_SOC_TLV320AIC3X is not set
+# CONFIG_SND_SOC_TPA6130A2 is not set
+# CONFIG_SND_SOC_TS3A227E is not set
+# CONFIG_SND_SOC_WM8510 is not set
+# CONFIG_SND_SOC_WM8523 is not set
+# CONFIG_SND_SOC_WM8580 is not set
+# CONFIG_SND_SOC_WM8711 is not set
+# CONFIG_SND_SOC_WM8728 is not set
+# CONFIG_SND_SOC_WM8731 is not set
+# CONFIG_SND_SOC_WM8737 is not set
+# CONFIG_SND_SOC_WM8741 is not set
+# CONFIG_SND_SOC_WM8750 is not set
+# CONFIG_SND_SOC_WM8753 is not set
+# CONFIG_SND_SOC_WM8770 is not set
+# CONFIG_SND_SOC_WM8776 is not set
+# CONFIG_SND_SOC_WM8804_I2C is not set
+# CONFIG_SND_SOC_WM8804_SPI is not set
+# CONFIG_SND_SOC_WM8903 is not set
+# CONFIG_SND_SOC_WM8962 is not set
+# CONFIG_SND_SOC_WM8978 is not set
+# CONFIG_SND_SOC_XTFPGA_I2S is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_SSCAPE is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_TIMER is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_6FIRE is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_HIFACE is not set
+# CONFIG_SND_USB_POD is not set
+# CONFIG_SND_USB_PODHD is not set
+# CONFIG_SND_USB_TONEPORT is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_VARIAX is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_WAVEFRONT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_SOC_HAS_OMAP2_SDRC is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SOLO6X10 is not set
+# CONFIG_SONYPI is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_SOUND is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_SP5100_TCO is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+# CONFIG_SPARSE_IRQ is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_SPEAKUP is not set
+# CONFIG_SPI is not set
+# CONFIG_SPINLOCK_TEST is not set
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_AU1550 is not set
+# CONFIG_SPI_BCM2835 is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_BUTTERFLY is not set
+# CONFIG_SPI_CADENCE is not set
+# CONFIG_SPI_DEBUG is not set
+# CONFIG_SPI_DESIGNWARE is not set
+# CONFIG_SPI_FSL_DSPI is not set
+# CONFIG_SPI_FSL_ESPI is not set
+# CONFIG_SPI_FSL_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_GPIO_OLD is not set
+# CONFIG_SPI_IMG_SPFI is not set
+# CONFIG_SPI_LM70_LLP is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_SPI_MPC52xx is not set
+# CONFIG_SPI_MPC52xx_PSC is not set
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_OCTEON is not set
+# CONFIG_SPI_ORION is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_PPC4xx is not set
+# CONFIG_SPI_PXA2XX is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_RAMIPS is not set
+# CONFIG_SPI_ROCKCHIP is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TI_QSPI is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_XWAY is not set
+# CONFIG_SPMI is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+# CONFIG_SQUASHFS_DECOMP_SINGLE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+# CONFIG_SQUASHFS_FILE_CACHE is not set
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_LZ4 is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_ZLIB is not set
+# CONFIG_SRAM is not set
+# CONFIG_SSB is not set
+# CONFIG_SSBI is not set
+# CONFIG_SSB_DEBUG is not set
+# CONFIG_SSB_DRIVER_GPIO is not set
+# CONFIG_SSB_PCMCIAHOST is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_HOST_SOC is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSFDC is not set
+CONFIG_STACKTRACE_SUPPORT=y
+# CONFIG_STACKTRACE is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_MEDIA is not set
+CONFIG_STANDALONE=y
+CONFIG_STDBINUTILS=y
+# CONFIG_STE10XP is not set
+# CONFIG_STE_MODEM_RPROC is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_STMMAC_PLATFORM is not set
+# CONFIG_STMMAC_PCI is not set
+CONFIG_STP=y
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SUSPEND is not set
+CONFIG_SWAP=y
+# CONFIG_SWCONFIG is not set
+# CONFIG_SWCONFIG_LEDS is not set
+# CONFIG_SX9500 is not set
+# CONFIG_SXGBE_ETH is not set
+# CONFIG_SYNCLINK_CS is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_SYSFS=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_SYSTEMPORT is not set
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_T5403 is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_TASKS_RCU is not set
+# CONFIG_TC35815 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TCIC is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_DCTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_TCS3414 is not set
+# CONFIG_TCS3472 is not set
+# CONFIG_TEGRA_AHB is not set
+# CONFIG_TEGRA_HOST1X is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_MODULE is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_USER_COPY is not set
+CONFIG_TEXTSEARCH=y
+# CONFIG_TEXTSEARCH_BM is not set
+# CONFIG_TEXTSEARCH_FSM is not set
+# CONFIG_TEXTSEARCH_KMP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_THINKPAD_ACPI is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_THUNDERBOLT is not set
+# CONFIG_TICK_CPU_ACCOUNTING is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_TIFM_CORE is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_TIMB_DMA is not set
+CONFIG_TIMERFD=y
+# CONFIG_TIMER_STATS is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TIPC is not set
+# CONFIG_TI_ADC081C is not set
+# CONFIG_TI_ADC128S052 is not set
+# CONFIG_TI_AM335X_ADC is not set
+# CONFIG_TI_CPSW is not set
+# CONFIG_TI_CPSW_ALE is not set
+# CONFIG_TI_CPTS is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_TI_DAVINCI_CPDMA is not set
+# CONFIG_TI_DAVINCI_MDIO is not set
+# CONFIG_TI_ST is not set
+# CONFIG_TLAN is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_TMP006 is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_TOSHIBA_HAPS is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_EGALAX is not set
+# CONFIG_TOUCHSCREEN_ELAN is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GOODIX is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_ILI210X is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_MMS114 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_S3C2410 is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_SUR40 is not set
+# CONFIG_TOUCHSCREEN_SX8654 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_ZFORCE is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TR is not set
+# CONFIG_TRACE_ENUM_MAP_FILE is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_TRACE_ENUM_MAP_FILE is not set
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_TRACE_SINK is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TSL2x7x is not set
+# CONFIG_TSL4531 is not set
+CONFIG_TTY=y
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_TUN is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6030_GPADC is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_TYPHOON is not set
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_UDF_FS is not set
+CONFIG_UDF_NLS=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_UFS_FS is not set
+# CONFIG_UHID is not set
+CONFIG_UIDGID_STRICT_TYPE_CHECKS=y
+# CONFIG_UIO is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_UNIX_DIAG is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_UPROBE_EVENT is not set
+# CONFIG_UPROBES is not set
+# CONFIG_USB is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_ADUTUX is not set
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AMD5536UDC is not set
+CONFIG_USB_AN2720=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_BDC_UDC is not set
+CONFIG_USB_BELKIN=y
+# CONFIG_USB_BTMTK is not set
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_CHAOSKEY is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_CONFIGFS is not set
+# CONFIG_USB_CXACRU is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEFAULT_PERSIST=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DUMMY_HCD is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_DWC2_DUAL_ROLE is not set
+# CONFIG_USB_DWC2_HOST is not set
+# CONFIG_USB_DWC2_PERIPHERAL is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC3_EXYNOS is not set
+# CONFIG_USB_DWC3_QCOM is not set
+# CONFIG_USB_DWC3_PCI is not set
+# CONFIG_USB_DWC3_KEYSTONE is not set
+# CONFIG_USB_DWC_OTG_LPM is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_EG20T is not set
+# CONFIG_USB_EHCI_HCD_AT91 is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_EHCI_MSM is not set
+# CONFIG_USB_EHCI_MV is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_ET61X251 is not set
+CONFIG_USB_EZUSB=y
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_FOTG210_UDC is not set
+# CONFIG_USB_FSL_USB2 is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FUSB300 is not set
+# CONFIG_USB_FUSBH200_HCD is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+CONFIG_USB_GADGET_VBUS_DRAW=2
+# CONFIG_USB_GADGET_XILINX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GOKU is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_GR_UDC is not set
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_DTCS033 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_JL2005BCD is not set
+# CONFIG_USB_GSPCA_KINECT is not set
+# CONFIG_USB_GSPCA_KONICA is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_NW80X is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SE401 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA1528 is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_SQ930X is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STK1135 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TOPRO is not set
+# CONFIG_USB_GSPCA_TOUPTEK is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_VICAM is not set
+# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_G_WEBCAM is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_INPUT_IMS_PCU is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_IP_COMMON is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_ISP1760 is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LIBUSUAL is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_MAX3421_HCD is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_MSM_OTG is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MV_U3D is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_NET2280 is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_CDC_MBIM is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_DRIVERS is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_QMI_WWAN is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD_PCI is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+# CONFIG_USB_OHCI_HCD_PPC_SOC is not set
+# CONFIG_USB_OHCI_HCD_SSB is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_PWC_INPUT_EVDEV is not set
+# CONFIG_USB_PXA27X is not set
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_RCAR_PHY is not set
+# CONFIG_USB_RENESAS_USBHS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_USB_S3C_HSOTG is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_MXUPORT is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SIMPLE is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_ZTE is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_SPEEDTOUCH is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_TMC is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_UEAGLEATM is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_XUSBATM is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USELIB is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+# CONFIG_USE_OF is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_UWB is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_VCNL4000 is not set
+# CONFIG_VDSO is not set
+# CONFIG_VETH is not set
+# CONFIG_VEXPRESS_CONFIG is not set
+# CONFIG_VF610_ADC is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VGA_ARB is not set
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_AK881X is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_CX2341X is not set
+# CONFIG_VIDEO_CX25840 is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_DM6446_CCDC is not set
+# CONFIG_VIDEO_DT3155 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_GO7007 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_IR_I2C is not set
+# CONFIG_VIDEO_IVTV is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_MEDIA is not set
+# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set
+# CONFIG_VIDEO_ML86V7667 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_OMAP2_VOUT is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_VIDEO_OV2659 is not set
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_SAA6588 is not set
+# CONFIG_VIDEO_SAA6752HS is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+# CONFIG_VIDEO_SONY_BTF_MPX is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_THS8200 is not set
+# CONFIG_VIDEO_TIMBERDALE is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_TW2804 is not set
+# CONFIG_VIDEO_TW9903 is not set
+# CONFIG_VIDEO_TW9906 is not set
+# CONFIG_VIDEO_UDA1342 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_USBTV is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_VIDEO_V4L2 is not set
+# CONFIG_VIDEO_V4L2_COMMON is not set
+# CONFIG_VIDEO_V4L2_INT_DEVICE is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_VPX3220 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_INPUT is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTUALIZATION is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_VITESSE_PHY is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_VLAN_8021Q_MVRP is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_VMSPLIT_1G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_2G_OPT is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMWARE_PVSCSI is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_VORTEX is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_VT is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_VXGE is not set
+# CONFIG_VXLAN is not set
+# CONFIG_W1 is not set
+# CONFIG_W1_CON is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_W1_MASTER_MATROX is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+# CONFIG_W1_SLAVE_DS2406 is not set
+# CONFIG_W1_SLAVE_DS2408 is not set
+# CONFIG_W1_SLAVE_DS2413 is not set
+# CONFIG_W1_SLAVE_DS2423 is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_DS2780 is not set
+# CONFIG_W1_SLAVE_DS2781 is not set
+# CONFIG_W1_SLAVE_DS28E04 is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W35UND is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83697HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_WAN is not set
+# CONFIG_WANXL is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WD80x3 is not set
+# CONFIG_WDTPCI is not set
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WILINK_PLATFORM_DATA=y
+# CONFIG_WIMAX is not set
+# CONFIG_WIMAX_GDM72XX is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+# CONFIG_WIRELESS_EXT_SYSFS is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_WL18XX is not set
+# CONFIG_WLAGS49_H2 is not set
+# CONFIG_WLAGS49_H25 is not set
+CONFIG_WLAN=y
+# CONFIG_WLCORE is not set
+CONFIG_WL_TI=y
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+# CONFIG_WR_PPMC is not set
+# CONFIG_X25 is not set
+# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set
+# CONFIG_X86_PKG_TEMP_THERMAL is not set
+CONFIG_X86_SYSFB=y
+# CONFIG_XEN is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_IPCOMP is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_WARN is not set
+# CONFIG_XILINX_AXI_EMAC is not set
+# CONFIG_XILINX_EMACLITE is not set
+# CONFIG_XILINX_LL_TEMAC is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_XMON is not set
+# CONFIG_XVMALLOC is not set
+CONFIG_XZ_DEC=y
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_BCJ is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_TEST is not set
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
+# CONFIG_YAFFS_FS is not set
+# CONFIG_YAM is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_YENTA is not set
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_ZD1211RW_DEBUG is not set
+# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_ZLIB_DEFLATE is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZNET is not set
+# CONFIG_ZPOOL is not set
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_ZRAM is not set
+# CONFIG_ZSMALLOC is not set
diff --git a/target/linux/generic/config-4.4 b/target/linux/generic/config-4.4
new file mode 100644
index 0000000000..8ce316b426
--- /dev/null
+++ b/target/linux/generic/config-4.4
@@ -0,0 +1,4825 @@
+CONFIG_32BIT=y
+# CONFIG_6LOWPAN is not set
+# CONFIG_6PACK is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_9P_FS is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_AB8500_CORE is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_ACENIC is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_ACPI_ALS is not set
+# CONFIG_ACPI_APEI is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_EXTLOG is not set
+# CONFIG_ACPI_HED is not set
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+# CONFIG_AD2S90 is not set
+# CONFIG_AD5064 is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5686 is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5933 is not set
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_AD7266 is not set
+# CONFIG_AD7280 is not set
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7303 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD7746 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD7923 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD8366 is not set
+# CONFIG_AD9523 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+# CONFIG_ADF4350 is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16136 is not set
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADIS16480 is not set
+# CONFIG_ADJD_S311 is not set
+# CONFIG_ADM6996_PHY is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_ADT7316 is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_ADXRS450 is not set
+CONFIG_AEABI=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AGP is not set
+# CONFIG_AHCI_CEVA is not set
+# CONFIG_AHCI_MVEBU is not set
+# CONFIG_AHCI_QORIQ is not set
+CONFIG_AIO=y
+# CONFIG_AIRO is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_AK09911 is not set
+# CONFIG_AK8975 is not set
+# CONFIG_AL3320A is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_ALTERA_MBOX is not set
+# CONFIG_ALTERA_STAPL is not set
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_ALX is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_AMD_XGBE is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_ANDROID is not set
+CONFIG_ANON_INODES=y
+# CONFIG_APDS9300 is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_APDS9960 is not set
+# CONFIG_APM8018X is not set
+# CONFIG_APPLE_GMUX is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AQUANTIA_PHY is not set
+# CONFIG_AR5523 is not set
+# CONFIG_AR7 is not set
+# CONFIG_AR8216_PHY is not set
+# CONFIG_AR8216_PHY_LEDS is not set
+# CONFIG_ARCH_ALPINE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BCM2835 is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_DIGICOLOR is not set
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_EXYNOS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ARCH_HI3xxx is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_HISI is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_NSPIRE is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2PLUS is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_S3C24XX is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_SHMOBILE_MULTI is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_UNIPHIER is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_WM8505 is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_ZX is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCNET is not set
+# CONFIG_ARC_EMAC is not set
+# CONFIG_ARM_APPENDED_DTB is not set
+# CONFIG_ARM_ARCH_TIMER is not set
+# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
+# CONFIG_ARM_CCI is not set
+# CONFIG_ARM_CCI400_PMU is not set
+# CONFIG_ARM_CCI500_PMU is not set
+# CONFIG_ARM_CCN is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_ARM_CPUIDLE is not set
+# CONFIG_ARM_CRYPTO is not set
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+# CONFIG_ARM_ERRATA_326103 is not set
+# CONFIG_ARM_ERRATA_364296 is not set
+# CONFIG_ARM_ERRATA_411920 is not set
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_643719 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+# CONFIG_ARM_ERRATA_742230 is not set
+# CONFIG_ARM_ERRATA_742231 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_751472 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+# CONFIG_ARM_ERRATA_754327 is not set
+# CONFIG_ARM_ERRATA_764369 is not set
+# CONFIG_ARM_ERRATA_773022 is not set
+# CONFIG_ARM_ERRATA_775420 is not set
+# CONFIG_ARM_ERRATA_798181 is not set
+# CONFIG_ARM_KERNMEM_PERMS is not set
+# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
+# CONFIG_ARM_KPROBES_TEST is not set
+# CONFIG_ARM_MHU is not set
+# CONFIG_ARM_MODULE_PLTS is not set
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+# CONFIG_ARM_PSCI is not set
+# CONFIG_ARM_PTDUMP is not set
+# CONFIG_ARM_TIMER_SP804 is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_ARM_VIRT_EXT is not set
+# CONFIG_AS3935 is not set
+# CONFIG_ASM9260_TIMER is not set
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_AT803X_PHY is not set
+# CONFIG_ATA is not set
+# CONFIG_ATAGS is not set
+CONFIG_ATAGS_PROC=y
+# CONFIG_ATALK is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_ATA_ACPI is not set
+CONFIG_ATA_BMDMA=y
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_ATA_PIIX is not set
+CONFIG_ATA_SFF=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATH10K is not set
+# CONFIG_ATH25 is not set
+# CONFIG_ATH5K is not set
+# CONFIG_ATH6KL is not set
+# CONFIG_ATH79 is not set
+# CONFIG_ATH9K is not set
+# CONFIG_ATH9K_HTC is not set
+# CONFIG_ATH_DEBUG is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_BR2684 is not set
+CONFIG_ATM_BR2684_IPFILTER=y
+# CONFIG_ATM_CLIP is not set
+CONFIG_ATM_CLIP_NO_ICMP=y
+# CONFIG_ATM_DRIVERS is not set
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_FORE200E is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_LANE is not set
+# CONFIG_ATM_MPOA is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_SOLOS is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ATP is not set
+# CONFIG_AUDIT is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_AURORA_NB8800 is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_AUTO_ZRELADDR is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_AX25 is not set
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_AX88796 is not set
+# CONFIG_AXP288_ADC is not set
+# CONFIG_AXP288_FUEL_GAUGE is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_B44 is not set
+# CONFIG_SWCONFIG_B53 is not set
+# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+# CONFIG_BACKLIGHT_BD6107 is not set
+# CONFIG_BACKLIGHT_GENERIC is not set
+# CONFIG_BACKLIGHT_GPIO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_BACKLIGHT_LM3630A is not set
+# CONFIG_BACKLIGHT_LM3639 is not set
+# CONFIG_BACKLIGHT_LP855X is not set
+# CONFIG_BACKLIGHT_LV5207LP is not set
+# CONFIG_BACKLIGHT_PANDORA is not set
+# CONFIG_BACKLIGHT_PM8941_WLED is not set
+# CONFIG_BACKLIGHT_RPI is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_BATTERY_BQ27XXX is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BCACHE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_BCM7038_WDT is not set
+# CONFIG_BCM7XXX_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_BCMA is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
+CONFIG_BCMA_POSSIBLE=y
+# CONFIG_BCMGENET is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BE2NET is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_BGMAC is not set
+# CONFIG_BH1750 is not set
+# CONFIG_BIG_KEYS is not set
+# CONFIG_BIG_LITTLE is not set
+# CONFIG_BINARY_PRINTF is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BITREVERSE=y
+# CONFIG_BLK_CMDLINE_PARSER is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_CPQ_DA is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
+# CONFIG_BLK_DEV_CS5536 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDE_AU1XXX is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_PMEM is not set
+# CONFIG_BLK_DEV_QD65XX is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_THROTTLING is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_UMC8672 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLOCK=y
+# CONFIG_BMA180 is not set
+# CONFIG_BMC150_ACCEL is not set
+# CONFIG_BMC150_MAGN is not set
+# CONFIG_BMG160 is not set
+# CONFIG_BMIPS_GENERIC is not set
+# CONFIG_BMP085 is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_BMP280 is not set
+# CONFIG_BNA is not set
+# CONFIG_BNX2 is not set
+# CONFIG_BNX2X is not set
+# CONFIG_BNXT is not set
+# CONFIG_BONDING is not set
+# CONFIG_BOOKE_WDT is not set
+CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3
+# CONFIG_BOOT_PRINTK_DELAY is not set
+CONFIG_BOOT_RAW=y
+CONFIG_BPF=y
+# CONFIG_BPF_JIT is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_BPQETHER is not set
+CONFIG_BQL=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_BRCMFMAC is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMSTB_GISB_ARB is not set
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_EBT_802_3 is not set
+# CONFIG_BRIDGE_EBT_AMONG is not set
+# CONFIG_BRIDGE_EBT_ARP is not set
+# CONFIG_BRIDGE_EBT_ARPREPLY is not set
+# CONFIG_BRIDGE_EBT_BROUTE is not set
+# CONFIG_BRIDGE_EBT_DNAT is not set
+# CONFIG_BRIDGE_EBT_IP is not set
+# CONFIG_BRIDGE_EBT_IP6 is not set
+# CONFIG_BRIDGE_EBT_LIMIT is not set
+# CONFIG_BRIDGE_EBT_LOG is not set
+# CONFIG_BRIDGE_EBT_MARK is not set
+# CONFIG_BRIDGE_EBT_MARK_T is not set
+# CONFIG_BRIDGE_EBT_NFLOG is not set
+# CONFIG_BRIDGE_EBT_PKTTYPE is not set
+# CONFIG_BRIDGE_EBT_REDIRECT is not set
+# CONFIG_BRIDGE_EBT_SNAT is not set
+# CONFIG_BRIDGE_EBT_STP is not set
+# CONFIG_BRIDGE_EBT_T_FILTER is not set
+# CONFIG_BRIDGE_EBT_T_NAT is not set
+# CONFIG_BRIDGE_EBT_VLAN is not set
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_NETFILTER is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_BT is not set
+# CONFIG_BTRFS_ASSERT is not set
+# CONFIG_BTRFS_DEBUG is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_CMTP is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTUSB_RTL is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_3WIRE is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIUART_QCA is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_HIDP is not set
+# CONFIG_BT_HS is not set
+# CONFIG_BT_LE is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_RFCOMM is not set
+CONFIG_BT_RFCOMM_TTY=y
+# CONFIG_BT_SELFTEST is not set
+CONFIG_BUG=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+# CONFIG_BUILD_BIN2C is not set
+# CONFIG_C2PORT is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CAN is not set
+# CONFIG_CAN_BCM is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+# CONFIG_CAN_DEV is not set
+# CONFIG_CAN_GS_USB is not set
+# CONFIG_CAN_GW is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_RAW is not set
+# CONFIG_CAN_RCAR is not set
+# CONFIG_CAN_SLCAN is not set
+# CONFIG_CAN_SUN4I is not set
+# CONFIG_CAN_VCAN is not set
+# CONFIG_CAPI_AVM is not set
+# CONFIG_CAPI_EICON is not set
+# CONFIG_CAPI_TRACE is not set
+CONFIG_CARDBUS=y
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_CARL9170 is not set
+# CONFIG_CASSINI is not set
+# CONFIG_CAVIUM_OCTEON_SOC is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_CC10001_ADC is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_CFG80211 is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24190 is not set
+# CONFIG_CHARGER_BQ24257 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_BQ25890 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_ISP1704 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_RT9455 is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_CHARGER_TWL4030 is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_CHELSIO_T4 is not set
+# CONFIG_CHELSIO_T4VF is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_CIFS is not set
+# CONFIG_CIFS_ACL is not set
+# CONFIG_CIFS_DEBUG is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_FSCACHE is not set
+# CONFIG_CIFS_NFSD_EXPORT is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_SMB2 is not set
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CLKSRC_VERSATILE is not set
+# CONFIG_CLK_QORIQ is not set
+# CONFIG_CLOCK_THERMAL is not set
+CONFIG_CLS_U32_MARK=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CM32181 is not set
+# CONFIG_CM3232 is not set
+# CONFIG_CM3323 is not set
+# CONFIG_CM36651 is not set
+# CONFIG_CMA is not set
+CONFIG_CMDLINE=""
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_CMDLINE_EXTEND is not set
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
+# CONFIG_CMDLINE_PARTITION is not set
+# CONFIG_CNIC is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_COMEDI is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_CDCE925 is not set
+# CONFIG_COMMON_CLK_IPROC is not set
+# CONFIG_COMMON_CLK_PWM is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_QCOM is not set
+# CONFIG_COMMON_CLK_SI514 is not set
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
+# CONFIG_COMPACTION is not set
+# CONFIG_COMPAL_LAPTOP is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_COMPILE_TEST is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_CONSTRUCTORS=y
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_COPS is not set
+# CONFIG_CORDIC is not set
+# CONFIG_COREDUMP is not set
+# CONFIG_CORESIGHT is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_IDLE is not set
+# CONFIG_CPU_IDLE_GOV_MENU is not set
+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
+CONFIG_CPU_SW_DOMAIN_PAN=y
+# CONFIG_CRAMFS is not set
+CONFIG_CRASHLOG=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC32_SARWATE=y
+# CONFIG_CRC32_SELFTEST is not set
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SLICEBY8 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_CRC8 is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CROSS_COMPILE=""
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_842 is not set
+# CONFIG_CRYPTO_AEAD is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_AES_ARM is not set
+# CONFIG_CRYPTO_AES_ARM_BS is not set
+# CONFIG_CRYPTO_AES_NI_INTEL is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CHACHA20 is not set
+# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
+# CONFIG_CRYPTO_CMAC is not set
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+# CONFIG_CRYPTO_CRCT10DIF is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_AES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set
+# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set
+# CONFIG_CRYPTO_DEV_CCP is not set
+# CONFIG_CRYPTO_DEV_FSL_CAAM is not set
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set
+# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set
+# CONFIG_CRYPTO_DEV_MV_CESA is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
+# CONFIG_CRYPTO_DEV_QCE is not set
+# CONFIG_CRYPTO_DEV_SAHARA is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+# CONFIG_CRYPTO_DRBG_HASH is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_ECHAINIV is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
+# CONFIG_CRYPTO_HASH is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_CRYPTO_JITTERENTROPY is not set
+# CONFIG_CRYPTO_KEYWRAP is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_MCRYPTD is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_PCOMP is not set
+# CONFIG_CRYPTO_PCOMP2 is not set
+CONFIG_CRYPTO_PCRYPT=y
+# CONFIG_CRYPTO_POLY1305 is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_RNG is not set
+# CONFIG_CRYPTO_RSA is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA1_ARM is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+# CONFIG_CRYPTO_TWOFISH_COMMON is not set
+# CONFIG_CRYPTO_USER is not set
+# CONFIG_CRYPTO_USER_API_AEAD is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_RNG is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+# CONFIG_CRYPTO_VMAC is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_XZ is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CS5535_MFGPT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_CUSE is not set
+# CONFIG_CW1200 is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+# CONFIG_CYPRESS_FIRMWARE is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_DCB is not set
+# CONFIG_DDR is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+CONFIG_DEBUG_INFO_REDUCED=y
+# CONFIG_DEBUG_INFO_SPLIT is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_KOBJECT_RELEASE is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_LL_UART_8250 is not set
+# CONFIG_DEBUG_LL_UART_PL01X is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_NX_TEST is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_PINCTRL is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RODATA is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_SEMIHOSTING is not set
+# CONFIG_DEBUG_SET_MODULE_RONX is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+# CONFIG_DEBUG_UART_BCM63XX is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_ZBOOT is not set
+# CONFIG_DECNET is not set
+CONFIG_DEFAULT_CUBIC=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_DELL_RBTN is not set
+# CONFIG_DELL_SMO8800 is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_DEVMEM is not set
+CONFIG_DEVPORT=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_DEVTMPFS is not set
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_DGAP is not set
+# CONFIG_DGNC is not set
+# CONFIG_DHT11 is not set
+# CONFIG_DIRECT_IO is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set
+# CONFIG_DISPLAY_CONNECTOR_DVI is not set
+# CONFIG_DISPLAY_CONNECTOR_HDMI is not set
+# CONFIG_DISPLAY_ENCODER_TFP410 is not set
+# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set
+# CONFIG_DISPLAY_PANEL_DPI is not set
+# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set
+# CONFIG_DL2K is not set
+# CONFIG_DLM is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_DMADEVICES_DEBUG is not set
+# CONFIG_DMASCC is not set
+# CONFIG_DMATEST is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_ENGINE is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_LOG_USERSPACE is not set
+# CONFIG_DM_LOG_WRITES is not set
+# CONFIG_DM_MQ_DEFAULT is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_RAID is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DNET is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+CONFIG_DOUBLEFAULT=y
+# CONFIG_DP83848_PHY is not set
+# CONFIG_DP83867_PHY is not set
+CONFIG_DQL=y
+# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_DRM is not set
+# CONFIG_DS1682 is not set
+# CONFIG_DTLK is not set
+# CONFIG_DUMMY is not set
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_DVB_AU8522_V4L is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+# CONFIG_DWMAC_IPQ806X is not set
+# CONFIG_DWMAC_LPC18XX is not set
+# CONFIG_DWMAC_MESON is not set
+# CONFIG_DWMAC_ROCKCHIP is not set
+# CONFIG_DWMAC_SOCFPGA is not set
+# CONFIG_DWMAC_STI is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_DW_DMAC_PCI is not set
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_E100 is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_EARLY_PRINTK_8250 is not set
+# CONFIG_ECHO is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_EDAC is not set
+# CONFIG_EEEPC_LAPTOP is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_DIGSY_MTC_CFG is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_EFS_FS is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_EMAC_ROCKCHIP is not set
+CONFIG_EMBEDDED=y
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_ENCX24J600 is not set
+# CONFIG_ENIC is not set
+# CONFIG_EPAPR_PARAVIRT is not set
+# CONFIG_EPIC100 is not set
+CONFIG_EPOLL=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_ET131X is not set
+CONFIG_ETHERNET=y
+# CONFIG_ETHOC is not set
+CONFIG_EVENTFD=y
+CONFIG_EXPERT=y
+# CONFIG_EXPORTFS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_DEBUG is not set
+# CONFIG_EXT4_ENCRYPTION is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_USE_FOR_EXT2=y
+# CONFIG_EXTCON is not set
+# CONFIG_EXTCON_ADC_JACK is not set
+# CONFIG_EXTCON_GPIO is not set
+# CONFIG_EXTCON_RT8973A is not set
+# CONFIG_EXTCON_SM5502 is not set
+# CONFIG_EXTCON_USB_GPIO is not set
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_EXYNOS_ADC is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_F2FS_FS_ENCRYPTION is not set
+# CONFIG_F2FS_FS_POSIX_ACL is not set
+# CONFIG_F2FS_IO_TRACE is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_FANOTIFY is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_FAT_FS is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_FB is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_BIG_ENDIAN is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_BOTH_ENDIAN is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_DA8XX is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_IMX is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_LITTLE_ENDIAN is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_MXS is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_PS3 is not set
+# CONFIG_FB_PXA is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_SM712 is not set
+# CONFIG_FB_SM750 is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_TFT is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_FCOE is not set
+# CONFIG_FCOE_FNIC is not set
+# CONFIG_FDDI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_FENCE_TRACE is not set
+# CONFIG_FHANDLE is not set
+CONFIG_FIB_RULES=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_FIREWIRE_SERIAL is not set
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_FIXED_PHY is not set
+CONFIG_FLATMEM=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FM10K is not set
+# CONFIG_FMC is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_FPGA is not set
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_FREEZER is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_FSCACHE is not set
+# CONFIG_FSL_EDMA is not set
+# CONFIG_FSL_PQ_MDIO is not set
+# CONFIG_FSL_XGMAC_MDIO is not set
+CONFIG_FSNOTIFY=y
+# CONFIG_FS_DAX is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_FTGMAC100 is not set
+# CONFIG_FTL is not set
+# CONFIG_FTMAC100 is not set
+# CONFIG_FTRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_FUJITSU_ES is not set
+# CONFIG_FUJITSU_LAPTOP is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_FUSE_FS is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+# CONFIG_FUSION_SPI is not set
+CONFIG_FUTEX=y
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_GACT_PROB=y
+# CONFIG_GADGET_UAC1 is not set
+# CONFIG_GAMEPORT is not set
+# CONFIG_GATEWORKS_GW16083 is not set
+# CONFIG_GCOV is not set
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_GDB_SCRIPTS is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_NET_UTILS=y
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_GENEVE is not set
+# CONFIG_GENWQE is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_GIGASET_CAPI is not set
+# CONFIG_GIGASET_DEBUG is not set
+# CONFIG_GLOB_SELFTEST is not set
+# CONFIG_GP2AP020A00F is not set
+# CONFIG_GPIOLIB is not set
+# CONFIG_GPIO_74X164 is not set
+# CONFIG_GPIO_74XX_MMIO is not set
+# CONFIG_GPIO_ADNP is not set
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_ALTERA is not set
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_BCM_KONA is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_CS5535 is not set
+# CONFIG_GPIO_DWAPB is not set
+# CONFIG_GPIO_EM is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_GRGPIO is not set
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_PL061 is not set
+# CONFIG_GPIO_RCAR is not set
+# CONFIG_GPIO_RDC321X is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_GPIO_SCH311X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_SYSCON is not set
+# CONFIG_GPIO_SYSFS is not set
+# CONFIG_GPIO_TS5500 is not set
+# CONFIG_GPIO_VX855 is not set
+# CONFIG_GPIO_WATCHDOG is not set
+# CONFIG_GPIO_XILINX is not set
+# CONFIG_GPIO_ZEVIO is not set
+# CONFIG_GPIO_ZX is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_GS_FPGABOOT is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_HAVE_ARM_ARCH_TIMER is not set
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_CAT=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HCALL_STATS is not set
+# CONFIG_HDC100X is not set
+# CONFIG_HDLC is not set
+# CONFIG_HDLC_CISCO is not set
+# CONFIG_HDLC_FR is not set
+# CONFIG_HDLC_PPP is not set
+# CONFIG_HDLC_RAW is not set
+# CONFIG_HDLC_RAW_ETH is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_HERMES is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_HFSPLUS_FS_POSIX_ACL is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFS_FS_POSIX_ACL is not set
+# CONFIG_HI8435 is not set
+# CONFIG_HIBERNATION is not set
+# CONFIG_HID is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BETOP_FF is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CORSAIR is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GEMBIRD is not set
+# CONFIG_HID_GENERIC is not set
+# CONFIG_HID_GFRM is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PID is not set
+# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_HIP04_ETH is not set
+# CONFIG_HIPPI is not set
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_HNS is not set
+# CONFIG_HNS_DSAF is not set
+# CONFIG_HNS_ENET is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+# CONFIG_HOSTAP_PCI is not set
+# CONFIG_HOSTAP_PLX is not set
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HP100 is not set
+CONFIG_HPET_MMAP_DEFAULT=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_HP_WIRELESS is not set
+# CONFIG_HSI is not set
+# CONFIG_HSR is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTU21 is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWSPINLOCK_OMAP is not set
+CONFIG_HW_PERF_EVENTS=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_ATMEL is not set
+# CONFIG_HW_RANDOM_EXYNOS is not set
+# CONFIG_HW_RANDOM_GEODE is not set
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_IPROC_RNG200 is not set
+# CONFIG_HW_RANDOM_OMAP3_ROM is not set
+# CONFIG_HW_RANDOM_PPC4XX is not set
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM_VIA is not set
+# CONFIG_HW_RANDOM_VIRTIO is not set
+# CONFIG_HYPERV is not set
+# CONFIG_HYSDN is not set
+CONFIG_HZ=100
+CONFIG_HZ_100=y
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_24 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_PERIODIC is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCA is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
+# CONFIG_I2C_AU1550 is not set
+# CONFIG_I2C_BCM2835 is not set
+# CONFIG_I2C_BCM_IPROC is not set
+# CONFIG_I2C_CADENCE is not set
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DESIGNWARE_PCI is not set
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_EG20T is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_EMEV2 is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_HID is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_IBM_IIC is not set
+# CONFIG_I2C_IMG is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_ISMT is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+# CONFIG_I2C_MUX_REG is not set
+# CONFIG_I2C_MV64XXX is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OCTEON is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_RCAR is not set
+# CONFIG_I2C_RK3X is not set
+# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_SCMI is not set
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_SLAVE is not set
+# CONFIG_I2C_SMBUS is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VERSATILE is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I40E is not set
+# CONFIG_I40EVF is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_IBM_EMAC_DEBUG is not set
+# CONFIG_IBM_EMAC_EMAC4 is not set
+# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_EMAC_RGMII is not set
+# CONFIG_IBM_EMAC_TAH is not set
+# CONFIG_IBM_EMAC_ZMII is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_IDE is not set
+# CONFIG_IDEAPAD_LAPTOP is not set
+# CONFIG_IDE_GD is not set
+# CONFIG_IDE_PROC_FS is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDLE_PAGE_TRACKING is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_IEEE802154_ATUSB is not set
+# CONFIG_IFB is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_IIO is not set
+# CONFIG_IIO_BUFFER_CB is not set
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+# CONFIG_IIO_INTERRUPT_TRIGGER is not set
+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_IIO_SSP_SENSORHUB is not set
+# CONFIG_IIO_ST_ACCEL_3AXIS is not set
+# CONFIG_IIO_ST_GYRO_3AXIS is not set
+# CONFIG_IIO_ST_MAGN_3AXIS is not set
+# CONFIG_IIO_ST_PRESS is not set
+# CONFIG_IIO_SYSFS_TRIGGER is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_IMAGE_CMDLINE_HACK is not set
+# CONFIG_IMGPDC_WDT is not set
+# CONFIG_IMX_IPUV3_CORE is not set
+# CONFIG_IMX_THERMAL is not set
+CONFIG_INET=y
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_TCP_DIAG is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_INFTL is not set
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2665_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_GP2A is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_LEDS is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_PALMAS_PWRBUTTON is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_REGULATOR_HAPTIC is not set
+# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_TPS65218_PWRBUTTON is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+# CONFIG_INPUT_TWL4030_VIBRA is not set
+# CONFIG_INPUT_TWL6040_VIBRA is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_WISTRON_BTNS is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INT340X_THERMAL is not set
+# CONFIG_INTEL_IDLE is not set
+# CONFIG_INTEL_IDMA64 is not set
+# CONFIG_INTEL_MEI is not set
+# CONFIG_INTEL_MEI_ME is not set
+# CONFIG_INTEL_MEI_TXE is not set
+# CONFIG_INTEL_MIC_CARD is not set
+# CONFIG_INTEL_MIC_HOST is not set
+# CONFIG_INTEL_MID_PTI is not set
+# CONFIG_INTEL_OAKTRAIL is not set
+# CONFIG_INTEL_RST is not set
+# CONFIG_INTEL_SMARTCONNECT is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_INTEL_TH is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_INV_MPU6050_IIO is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IP17XX_PHY is not set
+# CONFIG_IP6_NF_FILTER is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_NAT is not set
+# CONFIG_IP6_NF_RAW is not set
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
+# CONFIG_IPACK_BUS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPV6 is not set
+# CONFIG_IPV6_ILA is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_SIT_6RD is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_VTI is not set
+# CONFIG_IPVLAN is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2200 is not set
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW2200_PROMISCUOUS is not set
+# CONFIG_IPW2200_QOS is not set
+# CONFIG_IPW2200_RADIOTAP is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_IPX is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_NF_ARPFILTER is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_ARP_MANGLE is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_SECURITY is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IRDA is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_IR_GPIO_CIR is not set
+# CONFIG_IR_HIX5HD2 is not set
+# CONFIG_IR_IGORPLUGUSB is not set
+# CONFIG_IR_IGUANA is not set
+# CONFIG_IR_IMG is not set
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_LIRC_CODEC is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_NEC_DECODER is not set
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_REDRAT3 is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_IR_TTUSBIR is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_ISCSI_TCP is not set
+CONFIG_ISDN=y
+# CONFIG_ISDN_AUDIO is not set
+# CONFIG_ISDN_CAPI is not set
+# CONFIG_ISDN_CAPI_CAPIDRV is not set
+# CONFIG_ISDN_DIVERSION is not set
+# CONFIG_ISDN_DRV_ACT2000 is not set
+# CONFIG_ISDN_DRV_GIGASET is not set
+# CONFIG_ISDN_DRV_HISAX is not set
+# CONFIG_ISDN_DRV_ICN is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_ISDN_DRV_PCBIT is not set
+# CONFIG_ISDN_DRV_SC is not set
+# CONFIG_ISDN_I4L is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_ISL29125 is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_ISS4xx is not set
+# CONFIG_ITG3200 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IXGB is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+# CONFIG_JBD2_DEBUG is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_POSIX_ACL is not set
+# CONFIG_JFFS2_FS_SECURITY is not set
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_LZMA=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_ZLIB is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_JME is not set
+CONFIG_JOLIET=y
+# CONFIG_JSA1212 is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_UNCOMPRESSED is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_CAT is not set
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_KERNEL_XZ=y
+CONFIG_KERNFS=y
+# CONFIG_KEXEC is not set
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_BCM is not set
+# CONFIG_KEYBOARD_CAP11XX is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OMAP4 is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PXA27x is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_SH_KEYSC is not set
+# CONFIG_KEYBOARD_SNVS_PWRKEY is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_TWL4030 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYS is not set
+# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_KMX61 is not set
+# CONFIG_KPROBES is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_KSM is not set
+# CONFIG_KSZ884X_PCI is not set
+CONFIG_KUSER_HELPERS=y
+# CONFIG_KVM_AMD is not set
+# CONFIG_KVM_GUEST is not set
+# CONFIG_KVM_INTEL is not set
+# CONFIG_KXCJK1013 is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_L2TP is not set
+# CONFIG_L2TP_ETH is not set
+# CONFIG_L2TP_IP is not set
+# CONFIG_L2TP_V3 is not set
+# CONFIG_LANMEDIA is not set
+# CONFIG_LANTIQ is not set
+# CONFIG_LAPB is not set
+# CONFIG_LASAT is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+CONFIG_LBDAF=y
+# CONFIG_LCD_AMS369FG06 is not set
+# CONFIG_LCD_HX8357 is not set
+# CONFIG_LCD_ILI922X is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LD9040 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LMS501KF03 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_S6E63M0 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_LEDS_BCM6328 is not set
+# CONFIG_LEDS_BCM6358 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_BLINKM is not set
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_CLASS_FLASH is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_INTEL_SS4200 is not set
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM355x is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LP5562 is not set
+# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LP8860 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_NS2 is not set
+# CONFIG_LEDS_OT200 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA963X is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_SYSCON is not set
+# CONFIG_LEDS_TCA6507 is not set
+# CONFIG_LEDS_TLC591XX is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
+CONFIG_LEDS_TRIGGER_NETDEV=y
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+CONFIG_LEDS_TRIGGER_TIMER=y
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LGUEST is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_LIB80211_CRYPT_CCMP is not set
+# CONFIG_LIB80211_CRYPT_TKIP is not set
+# CONFIG_LIB80211_CRYPT_WEP is not set
+# CONFIG_LIB80211_DEBUG is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_LIBERTAS_USB is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_LIBIPW_DEBUG is not set
+# CONFIG_LIBNVDIMM is not set
+# CONFIG_LIDAR_LITE_V2 is not set
+# CONFIG_LIRC_STAGING is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_LKDTM is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_LOCKD is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKD_V4=y
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_LOGFS is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_LOGO is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+# CONFIG_LOONGSON_MC146818 is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_LTPC is not set
+# CONFIG_LTR501 is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_LWTUNNEL is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_LZ4HC_COMPRESS is not set
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+CONFIG_LZMA_COMPRESS=y
+CONFIG_LZMA_DECOMPRESS=y
+# CONFIG_LZO_COMPRESS is not set
+# CONFIG_LZO_DECOMPRESS is not set
+# CONFIG_M62332 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+# CONFIG_MACB is not set
+# CONFIG_MACH_ASM9260 is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_INGENIC is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_MACH_LOONGSON32 is not set
+# CONFIG_MACH_LOONGSON64 is not set
+# CONFIG_MACH_PISTACHIO is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_MACH_XILFPGA is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_MACVTAP is not set
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MAG3110 is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+# CONFIG_MAGIC_SYSRQ_SERIAL is not set
+# CONFIG_MAILBOX is not set
+# CONFIG_MANGLE_BOOTARGS is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_MAX1027 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MAX5821 is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_MCB is not set
+# CONFIG_MCP320X is not set
+# CONFIG_MCP3422 is not set
+# CONFIG_MCP4531 is not set
+# CONFIG_MCP4725 is not set
+# CONFIG_MCP4922 is not set
+# CONFIG_MCPM is not set
+# CONFIG_MD is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+# CONFIG_MDIO_OCTEON is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_ATTACH is not set
+# CONFIG_MEDIA_CAMERA_SUPPORT is not set
+# CONFIG_MEDIA_CONTROLLER is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_PCI_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_RC_SUPPORT is not set
+# CONFIG_MEDIA_SDR_SUPPORT is not set
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+# CONFIG_MEDIA_SUPPORT is not set
+# CONFIG_MEDIA_USB_SUPPORT is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_SAS is not set
+CONFIG_MEMBARRIER=y
+# CONFIG_MEMORY is not set
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_MEMTEST is not set
+# CONFIG_MEN_A21_WDT is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_ATMEL_FLEXCOM is not set
+# CONFIG_MFD_ATMEL_HLCDC is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9062 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MENF21BMC is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_OMAP_USB_HOST is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_PM8921_CORE is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_RK808 is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SKY81452 is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_MICROCHIP_PHY is not set
+# CONFIG_MIGRATION is not set
+CONFIG_MII=y
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_MIPS_CDMM is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MIPS_FPU_EMULATOR is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_O32_FP64_SUPPORT is not set
+# CONFIG_MIPS_PARAVIRT is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+# CONFIG_MIPS_SEAD3 is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_MISDN is not set
+# CONFIG_MISDN_AVMFRITZ is not set
+# CONFIG_MISDN_HFCPCI is not set
+# CONFIG_MISDN_HFCUSB is not set
+# CONFIG_MISDN_INFINEON is not set
+# CONFIG_MISDN_NETJET is not set
+# CONFIG_MISDN_SPEEDFAX is not set
+# CONFIG_MISDN_W6692 is not set
+# CONFIG_MKISS is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX5_CORE is not set
+# CONFIG_MLX90614 is not set
+# CONFIG_MLXSW_CORE is not set
+# CONFIG_MMA8452 is not set
+# CONFIG_MMA9551 is not set
+# CONFIG_MMA9553 is not set
+# CONFIG_MMC is not set
+# CONFIG_MMC35240 is not set
+# CONFIG_MMC_ARMMMCI is not set
+# CONFIG_MMC_AU1X is not set
+# CONFIG_MMC_BLOCK is not set
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_MMC_BLOCK_MINORS=8
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_MTK is not set
+# CONFIG_MMC_MVSDIO is not set
+# CONFIG_MMC_S3C is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SDHCI_ACPI is not set
+# CONFIG_MMC_SDHCI_BCM_KONA is not set
+# CONFIG_MMC_SDHCI_F_SDH30 is not set
+# CONFIG_MMC_SDHCI_IPROC is not set
+# CONFIG_MMC_SDHCI_MSM is not set
+# CONFIG_MMC_SDHCI_OF_ARASAN is not set
+# CONFIG_MMC_SDHCI_OF_AT91 is not set
+# CONFIG_MMC_SDHCI_OF_ESDHC is not set
+# CONFIG_MMC_SDHCI_OF_HLWD is not set
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+# CONFIG_MMC_SDRICOH_CS is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_TEST is not set
+# CONFIG_MMC_TOSHIBA_PCI is not set
+# CONFIG_MMC_USDHI6ROL0 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMIOTRACE is not set
+CONFIG_MMU=y
+CONFIG_MODULES=y
+# CONFIG_MODULE_COMPRESS is not set
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_MODULE_STRIPPED=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MOST is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_ELAN_I2C is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_PS2_FOCALTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_MPL115 is not set
+# CONFIG_MPL3115 is not set
+# CONFIG_MPLS is not set
+# CONFIG_MS5611 is not set
+# CONFIG_MS5637 is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_MSI_LAPTOP is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_LATCH_ADDR is not set
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_LPDDR2_NVM is not set
+# CONFIG_MTD_M25P80 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_MYLOADER_PARTS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_AMS_DELTA is not set
+# CONFIG_MTD_NAND_AR934X is not set
+# CONFIG_MTD_NAND_AR934X_HW_ECC is not set
+# CONFIG_MTD_NAND_ATMEL is not set
+# CONFIG_MTD_NAND_AU1550 is not set
+# CONFIG_MTD_NAND_BCH is not set
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_BRCMNAND is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_CM_X270 is not set
+# CONFIG_MTD_NAND_CS553X is not set
+# CONFIG_MTD_NAND_DAVINCI is not set
+# CONFIG_MTD_NAND_DENALI is not set
+# CONFIG_MTD_NAND_DENALI_DT is not set
+# CONFIG_MTD_NAND_DENALI_PCI is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_DOCG4 is not set
+# CONFIG_MTD_NAND_ECC is not set
+# CONFIG_MTD_NAND_ECC_BCH is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_NAND_FSL_IFC is not set
+# CONFIG_MTD_NAND_FSL_UPM is not set
+# CONFIG_MTD_NAND_FSMC is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_GPMI_NAND is not set
+# CONFIG_MTD_NAND_HISI504 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_JZ4740 is not set
+# CONFIG_MTD_NAND_MPC5121_NFC is not set
+# CONFIG_MTD_NAND_MXC is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_NDFC is not set
+# CONFIG_MTD_NAND_NUC900 is not set
+# CONFIG_MTD_NAND_OMAP2 is not set
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+# CONFIG_MTD_NAND_ORION is not set
+# CONFIG_MTD_NAND_PASEMI is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_PXA3xx is not set
+# CONFIG_MTD_NAND_RB4XX is not set
+# CONFIG_MTD_NAND_RB750 is not set
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_S3C2410 is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_SH_FLCTL is not set
+# CONFIG_MTD_NAND_SOCRATES is not set
+# CONFIG_MTD_NAND_TMIO is not set
+# CONFIG_MTD_NAND_TXX9NDFMC is not set
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OOPS is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_PARTITIONED_MASTER is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_ROM is not set
+CONFIG_MTD_ROOTFS_ROOT_DEV=y
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_SPINAND_MT29F is not set
+# CONFIG_MTD_SPI_NOR is not set
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_MTD_SPLIT=y
+# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_EVA_FW is not set
+# CONFIG_MTD_SPLIT_FIRMWARE is not set
+CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
+# CONFIG_MTD_SPLIT_FIT_FW is not set
+# CONFIG_MTD_SPLIT_LZMA_FW is not set
+# CONFIG_MTD_SPLIT_SEAMA_FW is not set
+CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y
+CONFIG_MTD_SPLIT_SUPPORT=y
+# CONFIG_MTD_SPLIT_TPLINK_FW is not set
+# CONFIG_MTD_SPLIT_TRX_FW is not set
+# CONFIG_MTD_SPLIT_UIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_WRGG_FW is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SWAP is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UIMAGE_SPLIT is not set
+CONFIG_MULTIUSER=y
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_MVMDIO is not set
+# CONFIG_MVSW61XX_PHY is not set
+# CONFIG_MVSWITCH_PHY is not set
+# CONFIG_MWAVE is not set
+# CONFIG_MWL8K is not set
+# CONFIG_MXC4005 is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NAU7802 is not set
+# CONFIG_NBPFAXI_DMA is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NEC_MARKEINS is not set
+CONFIG_NET=y
+# CONFIG_NETCONSOLE is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETFILTER is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_INGRESS is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_NETFILTER_XT_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_CT is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETROM is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NET_9P is not set
+# CONFIG_NET_ACT_BPF is not set
+# CONFIG_NET_ACT_CSUM is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_POLICE is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+# CONFIG_NET_ACT_VLAN is not set
+CONFIG_NET_CADENCE=y
+# CONFIG_NET_CALXEDA_XGMAC is not set
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_BPF is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_FLOWER is not set
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_IND=y
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_U32 is not set
+CONFIG_NET_CORE=y
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_NET_DSA_BCM_SF2 is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6171 is not set
+# CONFIG_NET_DSA_MV88E6352 is not set
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_TAG_DSA is not set
+# CONFIG_NET_DSA_TAG_EDSA is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_EMATCH_CANID is not set
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_TEXT is not set
+# CONFIG_NET_EMATCH_U32 is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPVTI is not set
+# CONFIG_NET_IP_TUNNEL is not set
+# CONFIG_NET_KEY is not set
+# CONFIG_NET_KEY_MIGRATE is not set
+# CONFIG_NET_L3_MASTER_DEV is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+CONFIG_NET_RX_BUSY_POLL=y
+# CONFIG_NET_SB1000 is not set
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_ATM is not set
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_CHOKE is not set
+# CONFIG_NET_SCH_CODEL is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_DSMARK is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_SCH_FQ is not set
+CONFIG_NET_SCH_FQ_CODEL=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_HHF is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_PIE is not set
+# CONFIG_NET_SCH_PLUG is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_QFQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFB is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCTPPROBE is not set
+# CONFIG_NET_SWITCHDEV is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_NET_UDP_TUNNEL is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_8390=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_AURORA=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CIRRUS=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_FARADAY=y
+CONFIG_NET_VENDOR_FREESCALE=y
+CONFIG_NET_VENDOR_FUJITSU=y
+CONFIG_NET_VENDOR_HISILICON=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MICROCHIP=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_TOSHIBA=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NET_VENDOR_XILINX=y
+CONFIG_NET_VENDOR_XIRCOM=y
+# CONFIG_NET_VRF is not set
+# CONFIG_NET_XGENE is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_NFC is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V2_ACL is not set
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFS_ACL_SUPPORT is not set
+CONFIG_NFS_COMMON=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_FSCACHE is not set
+# CONFIG_NFS_SWAP is not set
+# CONFIG_NFS_V2 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_V4_1 is not set
+# CONFIG_NFTL is not set
+# CONFIG_NFT_DUP_IPV4 is not set
+# CONFIG_NFT_DUP_IPV6 is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IPV4 is not set
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CONNTRACK_ZONES is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_GRE is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_NF_DUP_IPV4 is not set
+# CONFIG_NF_DUP_IPV6 is not set
+# CONFIG_NF_LOG_ARP is not set
+# CONFIG_NF_LOG_IPV4 is not set
+# CONFIG_NF_NAT is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_MASQUERADE_IPV4 is not set
+# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set
+# CONFIG_NF_NAT_NEEDED is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_PROTO_GRE is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NF_TABLES is not set
+# CONFIG_NF_TABLES_NETDEV is not set
+# CONFIG_NI65 is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_NIU is not set
+CONFIG_NLATTR=y
+# CONFIG_NLMON is not set
+# CONFIG_NLM_XLP_BOARD is not set
+# CONFIG_NLM_XLR_BOARD is not set
+# CONFIG_NLS is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_NO_BOOTMEM is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_NO_HZ_FULL is not set
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NS83820 is not set
+# CONFIG_NTB is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_NTP_PPS is not set
+# CONFIG_NVM is not set
+# CONFIG_NVMEM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_NV_TCO is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_N_GSM is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_OBS600 is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_OF_OVERLAY is not set
+# CONFIG_OF_UNITTEST is not set
+# CONFIG_OMAP2_DSS_DEBUG is not set
+# CONFIG_OMAP2_DSS_DEBUGFS is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP_OCP2SCP is not set
+# CONFIG_OMAP_USB2 is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_OPROFILE is not set
+# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
+# CONFIG_OPT3001 is not set
+# CONFIG_ORION_WATCHDOG is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_OVERLAY_FS=y
+# CONFIG_OWL_LOADER is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_PA12203001 is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_PAGE_OWNER is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PANASONIC_LAPTOP is not set
+# CONFIG_PANEL is not set
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PANIC_ON_OOPS_VALUE=1
+CONFIG_PANIC_TIMEOUT=1
+# CONFIG_PANTHERLORD_FF is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PARPORT_1284 is not set
+# CONFIG_PARPORT_AX88796 is not set
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_ISAPNP is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OCTEON_CF is not set
+# CONFIG_PATA_OF_PLATFORM is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+# CONFIG_PC300TOO is not set
+# CONFIG_PCCARD is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_PCI200SYN is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCIE_ALTERA is not set
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIE_IPROC is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PCI_ATMEL is not set
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_PCI_HOST_GENERIC is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_LAYERSCAPE is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_PASID is not set
+# CONFIG_PCI_PRI is not set
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCMCIA is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_XIRCOM is not set
+# CONFIG_PCNET32 is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PD6729 is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_PHONET is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+# CONFIG_PHY_EXYNOS_DP_VIDEO is not set
+# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_PHY_QCOM_DWC3 is not set
+# CONFIG_PHY_SAMSUNG_USB2 is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_PID_NS is not set
+CONFIG_PINCONF=y
+# CONFIG_PINCTRL is not set
+# CONFIG_PINCTRL_AMD is not set
+# CONFIG_PINCTRL_EXYNOS is not set
+# CONFIG_PINCTRL_EXYNOS5440 is not set
+# CONFIG_PINCTRL_MSM8X74 is not set
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINMUX=y
+# CONFIG_PKCS7_MESSAGE_PARSER is not set
+# CONFIG_PKCS7_TEST_KEY it not set
+# CONFIG_PL320_MBOX is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_PLIP is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PM is not set
+# CONFIG_PMBUS is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_RESET_BRCMSTB is not set
+# CONFIG_POWER_RESET_GPIO is not set
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
+# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
+# CONFIG_POWER_RESET_VERSATILE is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PPC4xx_GPIO is not set
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+# CONFIG_PPC_EMULATED_STATS is not set
+# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
+# CONFIG_PPP is not set
+# CONFIG_PPPOATM is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+CONFIG_PPP_FILTER=y
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPS is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_PARPORT is not set
+# CONFIG_PPS_DEBUG is not set
+# CONFIG_PPTP is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTK=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_PRISM2_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_PROC_CHILDREN is not set
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_PROC_STRIPPED=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILING is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_PROVE_RCU is not set
+# CONFIG_PROVE_RCU_REPEATEDLY is not set
+# CONFIG_PSB6970_PHY is not set
+# CONFIG_PSTORE is not set
+# CONFIG_PTP_1588_CLOCK is not set
+# CONFIG_PTP_1588_CLOCK_IXP46X is not set
+# CONFIG_PTP_1588_CLOCK_PCH is not set
+# CONFIG_PUBLIC_KEY_ALGO_RSA is not set
+# CONFIG_PWM is not set
+# CONFIG_PWM_FSL_FTM is not set
+# CONFIG_PWM_PCA9685 is not set
+# CONFIG_QCA7000 is not set
+# CONFIG_QCOM_SPMI_IADC is not set
+# CONFIG_QCOM_SPMI_TEMP_ALARM is not set
+# CONFIG_QCOM_SPMI_VADC is not set
+# CONFIG_QED is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_QLCNIC is not set
+# CONFIG_QLGE is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_QORIQ_CPUFREQ is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_R3964 is not set
+# CONFIG_R6040 is not set
+# CONFIG_R8169 is not set
+# CONFIG_R8188EU is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8723AU is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_RALINK is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+# CONFIG_RAPIDIO is not set
+# CONFIG_RAS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_RBTREE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FAST_NO_HZ is not set
+CONFIG_RCU_KTHREAD_PRIO=0
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RC_ATI_REMOTE is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_RC_DECODERS is not set
+# CONFIG_RC_LOOPBACK is not set
+# CONFIG_RC_MAP is not set
+# CONFIG_RDS is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_LZ4 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_REDWOOD is not set
+# CONFIG_REGMAP is not set
+# CONFIG_REGMAP_I2C is not set
+# CONFIG_REGMAP_MMIO is not set
+# CONFIG_REGMAP_SPI is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_GPIO is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_MT6311 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+# CONFIG_REGULATOR_PWM is not set
+# CONFIG_REGULATOR_TI_ABB is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_RELAY is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_RFD_FTL is not set
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_FULL is not set
+# CONFIG_RFKILL_GPIO is not set
+# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL_LEDS is not set
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_ROCKER is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_ROSE is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPR0521 is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DEBUG is not set
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_ARMADA38X is not set
+# CONFIG_RTC_DRV_AU1XXX is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_EP93XX is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_RTC_DRV_HYM8563 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL12057 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+# CONFIG_RTC_DRV_MOXART is not set
+# CONFIG_RTC_DRV_MPC5121 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_OMAP is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_PS3 is not set
+# CONFIG_RTC_DRV_PT7C4338 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_RTC7301 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RV8803 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_SUN6I is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_XGENE is not set
+# CONFIG_RTC_DRV_ZYNQMP is not set
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_RTL8192E is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTL8306_PHY is not set
+# CONFIG_RTL8366RB_PHY is not set
+# CONFIG_RTL8366S_PHY is not set
+# CONFIG_RTL8366_SMI is not set
+# CONFIG_RTL8366_SMI_DEBUG_FS is not set
+# CONFIG_RTL8367B_PHY is not set
+# CONFIG_RTL8367_PHY is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_RTL_CARDS is not set
+# CONFIG_RTS5208 is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_RUNTIME_DEBUG is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_S2IO is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_SAMSUNG_LAPTOP is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_DWC is not set
+# CONFIG_SATA_FSL is not set
+# CONFIG_SATA_HIGHBANK is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_RCAR is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SBC_FITPC2_WATCHDOG is not set
+# CONFIG_SC92031 is not set
+# CONFIG_SCA3000 is not set
+# CONFIG_SCACHE_DEBUGFS is not set
+# CONFIG_SCC is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHED_MC is not set
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+# CONFIG_SCHED_SMT is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CHELSIO_FCOE is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_ESAS2R is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ISCI is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_LPFC is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MPT3SAS is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVUMI is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_PMCRAID is not set
+CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+# CONFIG_SCSI_SNIC is not set
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_VIRTIO is not set
+# CONFIG_SCSI_WD719X is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_SECCOMP is not set
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADC128D818 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_ADT7310 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATK0110 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_DELL_SMM is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_G762 is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_GSC is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_SENSORS_HIH6130 is not set
+# CONFIG_SENSORS_HMC5843 is not set
+# CONFIG_SENSORS_HMC5843_I2C is not set
+# CONFIG_SENSORS_HMC5843_SPI is not set
+# CONFIG_SENSORS_HTU21 is not set
+# CONFIG_SENSORS_I5500 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_IIO_HWMON is not set
+# CONFIG_SENSORS_INA209 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LM95234 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_LTC2945 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4222 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4260 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX31790 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MAX6697 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_NCT7802 is not set
+# CONFIG_SENSORS_NCT7904 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_POWR1220 is not set
+# CONFIG_SENSORS_PWM_FAN is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SHTC1 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_TC74 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP103 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_SENSORS_VEXPRESS is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_ACCENT is not set
+# CONFIG_SERIAL_8250_BOCA is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_DMA=y
+# CONFIG_SERIAL_8250_DW is not set
+# CONFIG_SERIAL_8250_EM is not set
+# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_FINTEK is not set
+# CONFIG_SERIAL_8250_FOURPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+# CONFIG_SERIAL_8250_INGENIC is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_MID is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_RSA is not set
+# CONFIG_SERIAL_8250_RT288X is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_BCM63XX is not set
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_EARLYCON=y
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX310X is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_STM32 is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_UARTLITE is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_APBPS2 is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_SUN4I_PS2 is not set
+# CONFIG_SFC is not set
+# CONFIG_SFI is not set
+# CONFIG_SGETMASK_SYSCALL is not set
+# CONFIG_SG_SPLIT is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SGI_PARTITION is not set
+CONFIG_SHMEM=y
+# CONFIG_SH_ETH is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SI7005 is not set
+# CONFIG_SI7020 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+CONFIG_SIGNALFD=y
+# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SKY2_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLABINFO=y
+# CONFIG_SLHC is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_SLIP is not set
+# CONFIG_SLOB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SMARTJOYPLUS_FF is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMC9194 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_SMP is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_SND is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_AD1816A is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ADLIB is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_ALS100 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_ATMEL_AC97C is not set
+# CONFIG_SND_ATMEL_SOC is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT2320 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BCD2000 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DESIGNWARE_I2S is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FIREWIRE is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_HDA_INTEL is not set
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_HWDEP is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_ISA is not set
+# CONFIG_SND_KIRKWOOD_SOC is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_MIPS is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MPC52xx_SOC_EFIKA is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
+# CONFIG_SND_MXS_SOC is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_SND_OXYGEN is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_PCM is not set
+# CONFIG_SND_PCMCIA is not set
+# CONFIG_SND_PCM_OSS is not set
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_PCM_TIMER is not set
+# CONFIG_SND_PCM_XRUN_DEBUG is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_PORTMAN2X4 is not set
+# CONFIG_SND_POWERPC_SOC is not set
+# CONFIG_SND_PPC is not set
+CONFIG_SND_PROC_FS=y
+# CONFIG_SND_RAWMIDI is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_SE6X is not set
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_SIMPLE_CARD is not set
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SND_SOC_AC97_CODEC is not set
+# CONFIG_SND_SOC_ADAU1701 is not set
+# CONFIG_SND_SOC_AK4104 is not set
+# CONFIG_SND_SOC_AK4554 is not set
+# CONFIG_SND_SOC_AK4613 is not set
+# CONFIG_SND_SOC_AK4642 is not set
+# CONFIG_SND_SOC_AK5386 is not set
+# CONFIG_SND_SOC_ALC5623 is not set
+# CONFIG_SND_SOC_AU1XAUDIO is not set
+# CONFIG_SND_SOC_AU1XPSC is not set
+# CONFIG_SND_SOC_CS35L32 is not set
+# CONFIG_SND_SOC_CS4265 is not set
+# CONFIG_SND_SOC_CS4270 is not set
+# CONFIG_SND_SOC_CS4271 is not set
+# CONFIG_SND_SOC_CS4271_I2C is not set
+# CONFIG_SND_SOC_CS4271_SPI is not set
+# CONFIG_SND_SOC_CS42L51_I2C is not set
+# CONFIG_SND_SOC_CS42L52 is not set
+# CONFIG_SND_SOC_CS42L56 is not set
+# CONFIG_SND_SOC_CS42L73 is not set
+# CONFIG_SND_SOC_CS42XX8_I2C is not set
+# CONFIG_SND_SOC_CS4349 is not set
+# CONFIG_SND_SOC_ES8328 is not set
+# CONFIG_SND_SOC_EUKREA_TLV320 is not set
+# CONFIG_SND_SOC_FSL_ASOC_CARD is not set
+# CONFIG_SND_SOC_FSL_ASRC is not set
+# CONFIG_SND_SOC_FSL_ESAI is not set
+# CONFIG_SND_SOC_FSL_SAI is not set
+# CONFIG_SND_SOC_FSL_SPDIF is not set
+# CONFIG_SND_SOC_FSL_SSI is not set
+# CONFIG_SND_SOC_GTM601 is not set
+# CONFIG_SND_SOC_IMX_AUDMUX is not set
+# CONFIG_SND_SOC_IMX_ES8328 is not set
+# CONFIG_SND_SOC_IMX_SPDIF is not set
+# CONFIG_SND_SOC_IMX_WM8962 is not set
+# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set
+# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set
+# CONFIG_SND_SOC_INTEL_SST is not set
+# CONFIG_SND_SOC_MEDIATEK is not set
+# CONFIG_SND_SOC_MPC5200_AC97 is not set
+# CONFIG_SND_SOC_MPC5200_I2S is not set
+# CONFIG_SND_SOC_PCM1681 is not set
+# CONFIG_SND_SOC_PCM1792A is not set
+# CONFIG_SND_SOC_PCM512x_I2C is not set
+# CONFIG_SND_SOC_PCM512x_SPI is not set
+# CONFIG_SND_SOC_QCOM is not set
+# CONFIG_SND_SOC_RT5631 is not set
+# CONFIG_SND_SOC_RT5677_SPI is not set
+# CONFIG_SND_SOC_SGTL5000 is not set
+# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
+# CONFIG_SND_SOC_SPDIF is not set
+# CONFIG_SND_SOC_SSM2602_I2C is not set
+# CONFIG_SND_SOC_SSM2602_SPI is not set
+# CONFIG_SND_SOC_SSM4567 is not set
+# CONFIG_SND_SOC_STA32X is not set
+# CONFIG_SND_SOC_STA350 is not set
+# CONFIG_SND_SOC_STI_SAS is not set
+# CONFIG_SND_SOC_TAS2552 is not set
+# CONFIG_SND_SOC_TAS5086 is not set
+# CONFIG_SND_SOC_TAS571X is not set
+# CONFIG_SND_SOC_TFA9879 is not set
+# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
+# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
+# CONFIG_SND_SOC_TLV320AIC31XX is not set
+# CONFIG_SND_SOC_TLV320AIC3X is not set
+# CONFIG_SND_SOC_TPA6130A2 is not set
+# CONFIG_SND_SOC_TS3A227E is not set
+# CONFIG_SND_SOC_WM8510 is not set
+# CONFIG_SND_SOC_WM8523 is not set
+# CONFIG_SND_SOC_WM8580 is not set
+# CONFIG_SND_SOC_WM8711 is not set
+# CONFIG_SND_SOC_WM8728 is not set
+# CONFIG_SND_SOC_WM8731 is not set
+# CONFIG_SND_SOC_WM8737 is not set
+# CONFIG_SND_SOC_WM8741 is not set
+# CONFIG_SND_SOC_WM8750 is not set
+# CONFIG_SND_SOC_WM8753 is not set
+# CONFIG_SND_SOC_WM8770 is not set
+# CONFIG_SND_SOC_WM8776 is not set
+# CONFIG_SND_SOC_WM8804_I2C is not set
+# CONFIG_SND_SOC_WM8804_SPI is not set
+# CONFIG_SND_SOC_WM8903 is not set
+# CONFIG_SND_SOC_WM8962 is not set
+# CONFIG_SND_SOC_WM8978 is not set
+# CONFIG_SND_SOC_XTFPGA_I2S is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_SSCAPE is not set
+# CONFIG_SND_SUN4I_CODEC is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_TIMER is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_6FIRE is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_HIFACE is not set
+# CONFIG_SND_USB_POD is not set
+# CONFIG_SND_USB_PODHD is not set
+# CONFIG_SND_USB_TONEPORT is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_VARIAX is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_WAVEFRONT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_BRCMSTB is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_SOC_HAS_OMAP2_SDRC is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SONYPI is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_SOUND is not set
+# CONFIG_SOUND_OSS_CORE is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_SP5100_TCO is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+# CONFIG_SPARSE_IRQ is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_SPEAKUP is not set
+# CONFIG_SPI is not set
+# CONFIG_SPINLOCK_TEST is not set
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_AU1550 is not set
+# CONFIG_SPI_BCM2835 is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_BUTTERFLY is not set
+# CONFIG_SPI_CADENCE is not set
+# CONFIG_SPI_DEBUG is not set
+# CONFIG_SPI_DESIGNWARE is not set
+# CONFIG_SPI_FSL_DSPI is not set
+# CONFIG_SPI_FSL_ESPI is not set
+# CONFIG_SPI_FSL_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_GPIO_OLD is not set
+# CONFIG_SPI_IMG_SPFI is not set
+# CONFIG_SPI_LM70_LLP is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_SPI_MPC52xx is not set
+# CONFIG_SPI_MPC52xx_PSC is not set
+# CONFIG_SPI_OCTEON is not set
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_ORION is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_PPC4xx is not set
+# CONFIG_SPI_PXA2XX is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_ROCKCHIP is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TI_QSPI is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_XWAY is not set
+# CONFIG_SPI_ZYNQMP_GQSPI is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_SPMI is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+# CONFIG_SQUASHFS_DECOMP_SINGLE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+# CONFIG_SQUASHFS_FILE_CACHE is not set
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_LZ4 is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_ZLIB is not set
+# CONFIG_SRAM is not set
+# CONFIG_SSB is not set
+# CONFIG_SSB_DEBUG is not set
+# CONFIG_SSB_DRIVER_GPIO is not set
+# CONFIG_SSB_HOST_SOC is not set
+# CONFIG_SSB_PCMCIAHOST is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSFDC is not set
+# CONFIG_STACKTRACE is not set
+CONFIG_STACKTRACE_SUPPORT=y
+# CONFIG_STACK_TRACER is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_BOARD is not set
+# CONFIG_STAGING_MEDIA is not set
+CONFIG_STANDALONE=y
+# CONFIG_STATIC_KEYS_SELFTEST is not set
+CONFIG_STDBINUTILS=y
+# CONFIG_STE10XP is not set
+# CONFIG_STE_MODEM_RPROC is not set
+# CONFIG_STK3310 is not set
+# CONFIG_STK8312 is not set
+# CONFIG_STK8BA50 is not set
+# CONFIG_STM is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_STMMAC_PCI is not set
+# CONFIG_STMMAC_PLATFORM is not set
+# CONFIG_STM_DUMMY is not set
+# CONFIG_STM_SOURCE_CONSOLE is not set
+CONFIG_STP=y
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SUNXI_SRAM is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_SUSPEND_SKIP_SYNC is not set
+CONFIG_SWAP=y
+# CONFIG_SWCONFIG is not set
+# CONFIG_SWCONFIG_LEDS is not set
+# CONFIG_SX9500 is not set
+# CONFIG_SXGBE_ETH is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSFS=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_SYSTEMPORT is not set
+# CONFIG_SYSTEM_DATA_VERIFICATION is not set
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+CONFIG_SYSTEM_TRUSTED_KEYS=""
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_T5403 is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_TASK_XACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_TASKS_RCU is not set
+# CONFIG_TC35815 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TCIC is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_CDG is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_DCTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_TCS3414 is not set
+# CONFIG_TCS3472 is not set
+# CONFIG_TEGRA_AHB is not set
+# CONFIG_TEGRA_HOST1X is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_TERANETICS_PHY is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_TEST_STATIC_KEYS is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_TEST_USER_COPY is not set
+CONFIG_TEXTSEARCH=y
+# CONFIG_TEXTSEARCH_BM is not set
+# CONFIG_TEXTSEARCH_FSM is not set
+# CONFIG_TEXTSEARCH_KMP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_THERMAL_WRITABLE_TRIPS is not set
+# CONFIG_THINKPAD_ACPI is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_THUNDERBOLT is not set
+# CONFIG_TICK_CPU_ACCOUNTING is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_TIFM_CORE is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_TIMB_DMA is not set
+CONFIG_TIMERFD=y
+# CONFIG_TIMER_STATS is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TIPC is not set
+# CONFIG_TI_ADC081C is not set
+# CONFIG_TI_ADC128S052 is not set
+# CONFIG_TI_AM335X_ADC is not set
+# CONFIG_TI_CPSW is not set
+# CONFIG_TI_CPSW_ALE is not set
+# CONFIG_TI_CPTS is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_TI_DAVINCI_CPDMA is not set
+# CONFIG_TI_DAVINCI_MDIO is not set
+# CONFIG_TI_ST is not set
+# CONFIG_TLAN is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_TMP006 is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_TOSHIBA_HAPS is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_EGALAX is not set
+# CONFIG_TOUCHSCREEN_ELAN is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_FT6236 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GOODIX is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_ILI210X is not set
+# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_MMS114 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
+# CONFIG_TOUCHSCREEN_S3C2410 is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_SUR40 is not set
+# CONFIG_TOUCHSCREEN_SX8654 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_TSC2004 is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_ZFORCE is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_TRACE_ENUM_MAP_FILE is not set
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_TRACE_SINK is not set
+# CONFIG_TRACING_EVENTS_GPIO is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TSL2x7x is not set
+# CONFIG_TSL4531 is not set
+# CONFIG_TSYS01 is not set
+# CONFIG_TSYS02D is not set
+# CONFIG_TTPCI_EEPROM is not set
+CONFIG_TTY=y
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_TUN is not set
+# CONFIG_TUN_VNET_CROSS_LE is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL6030_GPADC is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_TYPHOON is not set
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_UBIFS_ATIME_SUPPORT is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_UDF_FS is not set
+CONFIG_UDF_NLS=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_UFS_FS is not set
+# CONFIG_UHID is not set
+CONFIG_UID16=y
+# CONFIG_UIO is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_UNIX_DIAG is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_UPROBES is not set
+# CONFIG_UPROBE_EVENT is not set
+# CONFIG_US5182D is not set
+# CONFIG_USB is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_ADUTUX is not set
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AMD5536UDC is not set
+CONFIG_USB_AN2720=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_BDC_UDC is not set
+CONFIG_USB_BELKIN=y
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_CHAOSKEY is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_CONFIGFS is not set
+# CONFIG_USB_CXACRU is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DUMMY_HCD is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_DWC2_DEBUG is not set
+# CONFIG_USB_DWC2_DUAL_ROLE is not set
+# CONFIG_USB_DWC2_HOST is not set
+# CONFIG_USB_DWC2_PERIPHERAL is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC3_EXYNOS is not set
+# CONFIG_USB_DWC3_KEYSTONE is not set
+# CONFIG_USB_DWC3_PCI is not set
+# CONFIG_USB_DWC3_QCOM is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_EG20T is not set
+# CONFIG_USB_EHCI_HCD_AT91 is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_EHCI_MSM is not set
+# CONFIG_USB_EHCI_MV is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_FOTG210_UDC is not set
+# CONFIG_USB_FSL_USB2 is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FUSB300 is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+CONFIG_USB_GADGET_VBUS_DRAW=2
+# CONFIG_USB_GADGET_XILINX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GOKU is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_GR_UDC is not set
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_DTCS033 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_JL2005BCD is not set
+# CONFIG_USB_GSPCA_KINECT is not set
+# CONFIG_USB_GSPCA_KONICA is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_NW80X is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SE401 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA1528 is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_SQ930X is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STK1135 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TOPRO is not set
+# CONFIG_USB_GSPCA_TOUPTEK is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_VICAM is not set
+# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_G_WEBCAM is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_ISP1760 is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_LAN78XX is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_MAX3421_HCD is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_MSM_OTG is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MV_U3D is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_NET2280 is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_CDC_MBIM is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_CH9200 is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_DRIVERS is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_QMI_WWAN is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD_PCI is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+# CONFIG_USB_OHCI_HCD_SSB is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_PWC_INPUT_EVDEV is not set
+# CONFIG_USB_PXA27X is not set
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_RCAR_PHY is not set
+# CONFIG_USB_RENESAS_USBHS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MXUPORT is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SIMPLE is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_SPEEDTOUCH is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_TMC is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_UEAGLEATM is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_ULPI_BUS is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_XUSBATM is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USELIB is not set
+# CONFIG_USERFAULTFD is not set
+# CONFIG_USE_OF is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_UWB is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_VCNL4000 is not set
+# CONFIG_VDSO is not set
+# CONFIG_VETH is not set
+# CONFIG_VEXPRESS_CONFIG is not set
+# CONFIG_VF610_ADC is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VGA_ARB is not set
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+# CONFIG_VHOST_NET is not seta
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_AK881X is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_CX2341X is not set
+# CONFIG_VIDEO_CX25840 is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_DM6446_CCDC is not set
+# CONFIG_VIDEO_DT3155 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_GO7007 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_IR_I2C is not set
+# CONFIG_VIDEO_IVTV is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_ML86V7667 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_OMAP2_VOUT is not set
+# CONFIG_VIDEO_OV2659 is not set
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_SAA6588 is not set
+# CONFIG_VIDEO_SAA6752HS is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+# CONFIG_VIDEO_SONY_BTF_MPX is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_THS8200 is not set
+# CONFIG_VIDEO_TIMBERDALE is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_TW2804 is not set
+# CONFIG_VIDEO_TW9903 is not set
+# CONFIG_VIDEO_TW9906 is not set
+# CONFIG_VIDEO_UDA1342 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_USBTV is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_VIDEO_V4L2 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_VPX3220 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_INPUT is not set
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTUALIZATION is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_VITESSE_PHY is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_VLAN_8021Q_MVRP is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_VMSPLIT_1G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_2G_OPT is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMWARE_PVSCSI is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_VORTEX is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_VT is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_VXGE is not set
+# CONFIG_VXLAN is not set
+# CONFIG_VZ89X is not set
+# CONFIG_W1 is not set
+# CONFIG_W1_CON is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_W1_MASTER_MATROX is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+# CONFIG_W1_SLAVE_DS2406 is not set
+# CONFIG_W1_SLAVE_DS2408 is not set
+# CONFIG_W1_SLAVE_DS2413 is not set
+# CONFIG_W1_SLAVE_DS2423 is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_DS2780 is not set
+# CONFIG_W1_SLAVE_DS2781 is not set
+# CONFIG_W1_SLAVE_DS28E04 is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_WAN is not set
+# CONFIG_WANXL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WD80x3 is not set
+# CONFIG_WDTPCI is not set
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WILINK_PLATFORM_DATA=y
+# CONFIG_WIMAX is not set
+# CONFIG_WIMAX_GDM72XX is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+# CONFIG_WIZNET_W5100 is not set
+# CONFIG_WIZNET_W5300 is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_WL18XX is not set
+CONFIG_WLAN=y
+# CONFIG_WLCORE is not set
+# CONFIG_WL_MEDIATEK is not set
+CONFIG_WL_TI=y
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+# CONFIG_X25 is not set
+# CONFIG_X509_CERTIFICATE_PARSER is not set
+# CONFIG_X86_DEBUG_STATIC_CPU_HAS is not set
+# CONFIG_X86_PKG_TEMP_THERMAL is not set
+CONFIG_X86_SYSFB=y
+# CONFIG_XEN is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_IPCOMP is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_WARN is not set
+# CONFIG_XILINX_AXI_EMAC is not set
+# CONFIG_XILINX_EMACLITE is not set
+# CONFIG_XILINX_LL_TEMAC is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_XMON is not set
+CONFIG_XZ_DEC=y
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_BCJ is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_TEST is not set
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING is not set
+# CONFIG_YAFFS_FS is not set
+# CONFIG_YAM is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_YENTA is not set
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_ZD1211RW_DEBUG is not set
+# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_ZLIB_DEFLATE is not set
+# CONFIG_ZLIB_INFLATE is not set
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_ZPOOL is not set
+# CONFIG_ZRAM is not set
+# CONFIG_ZSMALLOC is not set
diff --git a/target/linux/generic/files/Documentation/networking/adm6996.txt b/target/linux/generic/files/Documentation/networking/adm6996.txt
new file mode 100644
index 0000000000..ab59f1df03
--- /dev/null
+++ b/target/linux/generic/files/Documentation/networking/adm6996.txt
@@ -0,0 +1,110 @@
+------- 
+
+ADM6996FC / ADM6996M switch chip driver
+
+
+1. General information
+
+  This driver supports the FC and M models only. The ADM6996F and L are
+  completely different chips.
+  
+  Support for the FC model is extremely limited at the moment. There is no VLAN
+  support as of yet. The driver will not offer an swconfig interface for the FC
+  chip.
+ 
+1.1 VLAN IDs
+
+  It is possible to define 16 different VLANs. Every VLAN has an identifier, its
+  VLAN ID. It is easiest if you use at most VLAN IDs 0-15. In that case, the
+  swconfig based configuration is very straightforward. To define two VLANs with
+  IDs 4 and 5, you can invoke, for example:
+  
+      # swconfig dev ethX vlan 4 set ports '0 1t 2 5t' 
+      # swconfig dev ethX vlan 5 set ports '0t 1t 5t'
+  
+  The swconfig framework will automatically invoke 'port Y set pvid Z' for every
+  port that is an untagged member of VLAN Y, setting its Primary VLAN ID. In
+  this example, ports 0 and 2 would get "pvid 4". The Primary VLAN ID of a port
+  is the VLAN ID associated with untagged packets coming in on that port.
+  
+  But if you wish to use VLAN IDs outside the range 0-15, this automatic
+  behaviour of the swconfig framework becomes a problem. The 16 VLANs that
+  swconfig can configure on the ADM6996 also have a "vid" setting. By default,
+  this is the same as the number of the VLAN entry, to make the simple behaviour
+  above possible. To still support a VLAN with a VLAN ID higher than 15
+  (presumably because you are in a network where such VLAN IDs are already in
+  use), you can change the "vid" setting of the VLAN to anything in the range
+  0-1023. But suppose you did the following:
+  
+      # swconfig dev ethX vlan 0 set vid 998 
+      # swconfig dev ethX vlan 0 set ports '0 2 5t'
+ 
+  Now the swconfig framework will issue 'port 0 set pvid 0' and 'port 2 set pvid
+  0'. But the "pvid" should be set to 998, so you are responsible for manually
+  fixing this!
+
+1.2 VLAN filtering
+
+  The switch is configured to apply source port filtering. This means that
+  packets are only accepted when the port the packets came in on is a member of
+  the VLAN the packet should go to.
+
+  Only membership of a VLAN is tested, it does not matter whether it is a tagged
+  or untagged membership.
+
+  For untagged packets, the destination VLAN is the Primary VLAN ID of the
+  incoming port. So if the PVID of a port is 0, but that port is not a member of
+  the VLAN with ID 0, this means that untagged packets on that port are dropped.
+  This can be used as a roundabout way of dropping untagged packets from a port,
+  a mode often referred to as "Admit only tagged packets".
+
+1.3 Reset
+
+  The two supported chip models do not have a sofware-initiated reset. When the
+  driver is initialised, as well as when the 'reset' swconfig option is invoked,
+  the driver will set those registers it knows about and supports to the correct
+  default value. But there are a lot of registers in the chip that the driver
+  does not support. If something changed those registers, invoking 'reset' or
+  performing a warm reboot might still leave the chip in a "broken" state. Only
+  a hardware reset will bring it back in the default state.
+
+2. Technical details on PHYs and the ADM6996
+
+  From the viewpoint of the Linux kernel, it is common that an Ethernet adapter
+  can be seen as a separate MAC entity and a separate PHY entity. The PHY entity
+  can be queried and set through registers accessible via an MDIO bus. A PHY
+  normally has a single address on that bus, in the range 0 through 31.
+
+  The ADM6996 has special-purpose registers in the range of PHYs 0 through 10.
+  Even though all these registers control a single ADM6996 chip, the Linux
+  kernel treats this as 11 separate PHYs.  The driver will bind to these
+  addresses to prevent a different PHY driver from binding and corrupting these
+  registers.
+
+  What Linux sees as the PHY on address 0 is meant for the Ethernet MAC
+  connected to the CPU port of the ADM6996 switch chip (port 5). This is the
+  Ethernet MAC you will use to send and receive data through the switch.
+
+  The PHYs at addresses 16 through 20 map to the PHYs on ports 0 through 4 of
+  the switch chip. These can be accessed with the Generic PHY driver, as the
+  registers have the common layout.
+
+  If a second Ethernet MAC on your board is wired to the port 4 PHY, that MAC
+  needs to bind to PHY address 20 for the port to work correctly.
+
+  The ADM6996 switch driver will reset the ports 0 through 3 on startup and when
+  'reset' is invoked. This could clash with a different PHY driver if the kernel
+  binds a PHY driver to address 16 through 19.
+
+  If Linux binds a PHY on addresses 1 through 10 to an Ethernet MAC, the ADM6996
+  driver will simply always report a connected 100 Mbit/s full-duplex link for
+  that PHY, and provide no other functionality. This is most likely not what you
+  want. So if you see a message in your log
+
+  	ethX: PHY overlaps ADM6996, providing fixed PHY yy.
+
+  This is most likely an indication that ethX will not work properly, and your
+  kernel needs to be configured to attach a different PHY to that Ethernet MAC.
+
+  Controlling the mapping between MACs and PHYs is usually done in platform- or
+  board-specific fixup code. The ADM6996 driver has no influence over this.
diff --git a/target/linux/generic/files/arch/mips/fw/myloader/Makefile b/target/linux/generic/files/arch/mips/fw/myloader/Makefile
new file mode 100644
index 0000000000..34acfd01cc
--- /dev/null
+++ b/target/linux/generic/files/arch/mips/fw/myloader/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Compex's MyLoader support on MIPS architecture
+#
+
+lib-y += myloader.o
diff --git a/target/linux/generic/files/arch/mips/fw/myloader/myloader.c b/target/linux/generic/files/arch/mips/fw/myloader/myloader.c
new file mode 100644
index 0000000000..a26f9ad3fd
--- /dev/null
+++ b/target/linux/generic/files/arch/mips/fw/myloader/myloader.c
@@ -0,0 +1,63 @@
+/*
+ *  Compex's MyLoader specific prom routines
+ *
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/addrspace.h>
+#include <asm/fw/myloader/myloader.h>
+
+#define SYS_PARAMS_ADDR		KSEG1ADDR(0x80000800)
+#define BOARD_PARAMS_ADDR	KSEG1ADDR(0x80000A00)
+#define PART_TABLE_ADDR		KSEG1ADDR(0x80000C00)
+#define BOOT_PARAMS_ADDR	KSEG1ADDR(0x80000E00)
+
+static struct myloader_info myloader_info __initdata;
+static int myloader_found __initdata;
+
+struct myloader_info * __init myloader_get_info(void)
+{
+	struct mylo_system_params *sysp;
+	struct mylo_board_params *boardp;
+	struct mylo_partition_table *parts;
+
+	if (myloader_found)
+		return &myloader_info;
+
+	sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR);
+	boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR);
+	parts = (struct mylo_partition_table *)(PART_TABLE_ADDR);
+
+	printk(KERN_DEBUG "MyLoader: sysp=%08x, boardp=%08x, parts=%08x\n",
+		sysp->magic, boardp->magic, parts->magic);
+
+	/* Check for some magic numbers */
+	if (sysp->magic != MYLO_MAGIC_SYS_PARAMS ||
+	    boardp->magic != MYLO_MAGIC_BOARD_PARAMS ||
+	    le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS)
+		return NULL;
+
+	printk(KERN_DEBUG "MyLoader: id=%04x:%04x, sub_id=%04x:%04x\n",
+		sysp->vid, sysp->did, sysp->svid, sysp->sdid);
+
+	myloader_info.vid = sysp->vid;
+	myloader_info.did = sysp->did;
+	myloader_info.svid = sysp->svid;
+	myloader_info.sdid = sysp->sdid;
+
+	memcpy(myloader_info.macs, boardp->addr, sizeof(myloader_info.macs));
+
+	myloader_found = 1;
+
+	return &myloader_info;
+}
diff --git a/target/linux/generic/files/drivers/leds/ledtrig-netdev.c b/target/linux/generic/files/drivers/leds/ledtrig-netdev.c
new file mode 100644
index 0000000000..cfa4dc0758
--- /dev/null
+++ b/target/linux/generic/files/drivers/leds/ledtrig-netdev.c
@@ -0,0 +1,444 @@
+/*
+ * LED Kernel Netdev Trigger
+ *
+ * Toggles the LED to reflect the link and traffic state of a named net device
+ *
+ * Copyright 2007 Oliver Jowett <oliver@opencloud.com>
+ *
+ * Derived from ledtrig-timer.c which is:
+ *  Copyright 2005-2006 Openedhand Ltd.
+ *  Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * 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/module.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+
+#include "leds.h"
+
+/*
+ * Configurable sysfs attributes:
+ *
+ * device_name - network device name to monitor
+ *
+ * interval - duration of LED blink, in milliseconds
+ *
+ * mode - either "none" (LED is off) or a space separated list of one or more of:
+ *   link: LED's normal state reflects whether the link is up (has carrier) or not
+ *   tx:   LED blinks on transmitted data
+ *   rx:   LED blinks on receive data
+ *
+ * Some suggestions:
+ *
+ *  Simple link status LED:
+ *  $ echo netdev >someled/trigger
+ *  $ echo eth0 >someled/device_name
+ *  $ echo link >someled/mode
+ *
+ *  Ethernet-style link/activity LED:
+ *  $ echo netdev >someled/trigger
+ *  $ echo eth0 >someled/device_name
+ *  $ echo "link tx rx" >someled/mode
+ *
+ *  Modem-style tx/rx LEDs:
+ *  $ echo netdev >led1/trigger
+ *  $ echo ppp0 >led1/device_name
+ *  $ echo tx >led1/mode
+ *  $ echo netdev >led2/trigger
+ *  $ echo ppp0 >led2/device_name
+ *  $ echo rx >led2/mode
+ *
+ */
+
+#define MODE_LINK 1
+#define MODE_TX   2
+#define MODE_RX   4
+
+struct led_netdev_data {
+	spinlock_t lock;
+
+	struct timer_list timer;
+	struct notifier_block notifier;
+
+	struct led_classdev *led_cdev;
+	struct net_device *net_dev;
+
+	char device_name[IFNAMSIZ];
+	unsigned interval;
+	unsigned mode;
+	unsigned link_up;
+	unsigned last_activity;
+};
+
+static void set_baseline_state(struct led_netdev_data *trigger_data)
+{
+	if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
+		led_set_brightness(trigger_data->led_cdev, LED_FULL);
+	else
+		led_set_brightness(trigger_data->led_cdev, LED_OFF);
+
+	if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
+		mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
+}
+
+static ssize_t led_device_name_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+
+	spin_lock_bh(&trigger_data->lock);
+	sprintf(buf, "%s\n", trigger_data->device_name);
+	spin_unlock_bh(&trigger_data->lock);
+
+	return strlen(buf) + 1;
+}
+
+static ssize_t led_device_name_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+
+	if (size < 0 || size >= IFNAMSIZ)
+		return -EINVAL;
+
+	spin_lock_bh(&trigger_data->lock);
+	del_timer_sync(&trigger_data->timer);
+
+	strcpy(trigger_data->device_name, buf);
+	if (size > 0 && trigger_data->device_name[size-1] == '\n')
+		trigger_data->device_name[size-1] = 0;
+	trigger_data->link_up = 0;
+	trigger_data->last_activity = 0;
+
+	if (trigger_data->device_name[0] != 0) {
+		/* check for existing device to update from */
+		trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name);
+		if (trigger_data->net_dev != NULL)
+			trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
+	}
+
+	set_baseline_state(trigger_data);
+	spin_unlock_bh(&trigger_data->lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
+
+static ssize_t led_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+
+	spin_lock_bh(&trigger_data->lock);
+
+	if (trigger_data->mode == 0) {
+		strcpy(buf, "none\n");
+	} else {
+		if (trigger_data->mode & MODE_LINK)
+			strcat(buf, "link ");
+		if (trigger_data->mode & MODE_TX)
+			strcat(buf, "tx ");
+		if (trigger_data->mode & MODE_RX)
+			strcat(buf, "rx ");
+		strcat(buf, "\n");
+	}
+
+	spin_unlock_bh(&trigger_data->lock);
+
+	return strlen(buf)+1;
+}
+
+static ssize_t led_mode_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+	char copybuf[128];
+	int new_mode = -1;
+	char *p, *token;
+
+	/* take a copy since we don't want to trash the inbound buffer when using strsep */
+	strncpy(copybuf, buf, sizeof(copybuf));
+	copybuf[sizeof(copybuf) - 1] = 0;
+	p = copybuf;
+
+	while ((token = strsep(&p, " \t\n")) != NULL) {
+		if (!*token)
+			continue;
+
+		if (new_mode == -1)
+			new_mode = 0;
+
+		if (!strcmp(token, "none"))
+			new_mode = 0;
+		else if (!strcmp(token, "tx"))
+			new_mode |= MODE_TX;
+		else if (!strcmp(token, "rx"))
+			new_mode |= MODE_RX;
+		else if (!strcmp(token, "link"))
+			new_mode |= MODE_LINK;
+		else
+			return -EINVAL;
+	}
+
+	if (new_mode == -1)
+		return -EINVAL;
+
+	spin_lock_bh(&trigger_data->lock);
+	del_timer_sync(&trigger_data->timer);
+
+	trigger_data->mode = new_mode;
+
+	set_baseline_state(trigger_data);
+	spin_unlock_bh(&trigger_data->lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
+
+static ssize_t led_interval_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+
+	spin_lock_bh(&trigger_data->lock);
+	sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
+	spin_unlock_bh(&trigger_data->lock);
+
+	return strlen(buf) + 1;
+}
+
+static ssize_t led_interval_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+	int ret = -EINVAL;
+	char *after;
+	unsigned long value = simple_strtoul(buf, &after, 10);
+	size_t count = after - buf;
+
+	if (isspace(*after))
+		count++;
+
+	/* impose some basic bounds on the timer interval */
+	if (count == size && value >= 5 && value <= 10000) {
+		spin_lock_bh(&trigger_data->lock);
+		del_timer_sync(&trigger_data->timer);
+
+		trigger_data->interval = msecs_to_jiffies(value);
+
+		set_baseline_state(trigger_data); /* resets timer */
+		spin_unlock_bh(&trigger_data->lock);
+
+		ret = count;
+	}
+
+	return ret;
+}
+
+static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
+
+static int netdev_trig_notify(struct notifier_block *nb,
+			      unsigned long evt,
+			      void *dv)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev((struct netdev_notifier_info *) dv);
+	struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
+
+	if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER && evt != NETDEV_CHANGENAME)
+		return NOTIFY_DONE;
+
+	spin_lock_bh(&trigger_data->lock);
+
+	if (strcmp(dev->name, trigger_data->device_name))
+		goto done;
+
+	del_timer_sync(&trigger_data->timer);
+
+	if (evt == NETDEV_REGISTER || evt == NETDEV_CHANGENAME) {
+		if (trigger_data->net_dev != NULL)
+			dev_put(trigger_data->net_dev);
+
+		dev_hold(dev);
+		trigger_data->net_dev = dev;
+		trigger_data->link_up = 0;
+		goto done;
+	}
+
+	if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
+		dev_put(trigger_data->net_dev);
+		trigger_data->net_dev = NULL;
+		goto done;
+	}
+
+	/* UP / DOWN / CHANGE */
+
+	trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
+	set_baseline_state(trigger_data);
+
+done:
+	spin_unlock_bh(&trigger_data->lock);
+	return NOTIFY_DONE;
+}
+
+/* here's the real work! */
+static void netdev_trig_timer(unsigned long arg)
+{
+	struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg;
+	struct rtnl_link_stats64 *dev_stats;
+	unsigned new_activity;
+	struct rtnl_link_stats64 temp;
+
+	if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
+		/* we don't need to do timer work, just reflect link state. */
+		led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
+		return;
+	}
+
+	dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
+	new_activity =
+		((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
+		((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
+
+	if (trigger_data->mode & MODE_LINK) {
+		/* base state is ON (link present) */
+		/* if there's no link, we don't get this far and the LED is off */
+
+		/* OFF -> ON always */
+		/* ON -> OFF on activity */
+		if (trigger_data->led_cdev->brightness == LED_OFF) {
+			led_set_brightness(trigger_data->led_cdev, LED_FULL);
+		} else if (trigger_data->last_activity != new_activity) {
+			led_set_brightness(trigger_data->led_cdev, LED_OFF);
+		}
+	} else {
+		/* base state is OFF */
+		/* ON -> OFF always */
+		/* OFF -> ON on activity */
+		if (trigger_data->led_cdev->brightness == LED_FULL) {
+			led_set_brightness(trigger_data->led_cdev, LED_OFF);
+		} else if (trigger_data->last_activity != new_activity) {
+			led_set_brightness(trigger_data->led_cdev, LED_FULL);
+		}
+	}
+
+	trigger_data->last_activity = new_activity;
+	mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
+}
+
+static void netdev_trig_activate(struct led_classdev *led_cdev)
+{
+	struct led_netdev_data *trigger_data;
+	int rc;
+
+	trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
+	if (!trigger_data)
+		return;
+
+	spin_lock_init(&trigger_data->lock);
+
+	trigger_data->notifier.notifier_call = netdev_trig_notify;
+	trigger_data->notifier.priority = 10;
+
+	setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data);
+
+	trigger_data->led_cdev = led_cdev;
+	trigger_data->net_dev = NULL;
+	trigger_data->device_name[0] = 0;
+
+	trigger_data->mode = 0;
+	trigger_data->interval = msecs_to_jiffies(50);
+	trigger_data->link_up = 0;
+	trigger_data->last_activity = 0;
+
+	led_cdev->trigger_data = trigger_data;
+
+	rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
+	if (rc)
+		goto err_out;
+	rc = device_create_file(led_cdev->dev, &dev_attr_mode);
+	if (rc)
+		goto err_out_device_name;
+	rc = device_create_file(led_cdev->dev, &dev_attr_interval);
+	if (rc)
+		goto err_out_mode;
+
+	register_netdevice_notifier(&trigger_data->notifier);
+	return;
+
+err_out_mode:
+	device_remove_file(led_cdev->dev, &dev_attr_mode);
+err_out_device_name:
+	device_remove_file(led_cdev->dev, &dev_attr_device_name);
+err_out:
+	led_cdev->trigger_data = NULL;
+	kfree(trigger_data);
+}
+
+static void netdev_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+
+	if (trigger_data) {
+		unregister_netdevice_notifier(&trigger_data->notifier);
+
+		device_remove_file(led_cdev->dev, &dev_attr_device_name);
+		device_remove_file(led_cdev->dev, &dev_attr_mode);
+		device_remove_file(led_cdev->dev, &dev_attr_interval);
+
+		spin_lock_bh(&trigger_data->lock);
+		del_timer_sync(&trigger_data->timer);
+
+		if (trigger_data->net_dev) {
+			dev_put(trigger_data->net_dev);
+			trigger_data->net_dev = NULL;
+		}
+
+		spin_unlock_bh(&trigger_data->lock);
+
+		kfree(trigger_data);
+	}
+}
+
+static struct led_trigger netdev_led_trigger = {
+	.name     = "netdev",
+	.activate = netdev_trig_activate,
+	.deactivate = netdev_trig_deactivate,
+};
+
+static int __init netdev_trig_init(void)
+{
+	return led_trigger_register(&netdev_led_trigger);
+}
+
+static void __exit netdev_trig_exit(void)
+{
+	led_trigger_unregister(&netdev_led_trigger);
+}
+
+module_init(netdev_trig_init);
+module_exit(netdev_trig_exit);
+
+MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
+MODULE_DESCRIPTION("Netdev LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/files/drivers/misc/owl-loader.c b/target/linux/generic/files/drivers/misc/owl-loader.c
new file mode 100644
index 0000000000..30340da486
--- /dev/null
+++ b/target/linux/generic/files/drivers/misc/owl-loader.c
@@ -0,0 +1,246 @@
+/*
+ * Initialize Owl Emulation Devices
+ *
+ * Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * 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.
+ *
+ * Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway)
+ * need to be able to initialize the PCIe wifi device. Normally, this is done
+ * during the early stages of booting linux, because the necessary init code
+ * is read from the memory mapped SPI and passed to pci_enable_ath9k_fixup.
+ * However,this isn't possible for devices which have the init code for the
+ * Atheros chip stored on NAND. Hence, this module can be used to initialze
+ * the chip when the user-space is ready to extract the init code.
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/completion.h>
+#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+struct owl_ctx {
+	struct completion eeprom_load;
+};
+
+#define EEPROM_FILENAME_LEN 100
+
+#define AR5416_EEPROM_MAGIC 0xa55a
+
+static int ath9k_pci_fixup(struct pci_dev *pdev, const u16 *cal_data,
+			   size_t cal_len)
+{
+	void __iomem *mem;
+	const void *cal_end = (void *)cal_data + cal_len;
+	const struct {
+		__be16 reg;
+		__be16 low_val;
+		__be16 high_val;
+	} __packed *data;
+	u16 cmd;
+	u32 bar0;
+	bool swap_needed = false;
+
+	if (*cal_data != AR5416_EEPROM_MAGIC) {
+		if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) {
+			dev_err(&pdev->dev, "invalid calibration data\n");
+			return -EINVAL;
+		}
+
+		dev_dbg(&pdev->dev, "calibration data needs swapping\n");
+		swap_needed = true;
+	}
+
+	dev_info(&pdev->dev, "fixup device configuration\n");
+
+	mem = pcim_iomap(pdev, 0, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "ioremap error\n");
+		return -EINVAL;
+	}
+
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0);
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0,
+			       pci_resource_start(pdev, 0));
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	/* set pointer to first reg address */
+	for (data = (const void *) (cal_data + 3);
+	     (const void *) data <= cal_end && data->reg != cpu_to_be16(~0);
+	     data++) {
+		u32 val;
+		u16 reg;
+
+		reg = data->reg;
+		val = data->low_val;
+		val |= data->high_val << 16;
+
+		if (swap_needed) {
+			reg = swab16(reg);
+			val = swahb32(val);
+		}
+
+#if CONFIG_LANTIQ
+		val = swab32(val);
+#endif
+
+		__raw_writel(val, mem + reg);
+		udelay(100);
+	}
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, bar0);
+	pcim_iounmap(pdev, mem);
+
+	pci_disable_device(pdev);
+
+	return 0;
+}
+
+static void owl_fw_cb(const struct firmware *fw, void *context)
+{
+	struct pci_dev *pdev = (struct pci_dev *) context;
+	struct owl_ctx *ctx = (struct owl_ctx *) pci_get_drvdata(pdev);
+	struct ath9k_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct pci_bus *bus;
+
+	complete(&ctx->eeprom_load);
+
+	if (!fw) {
+		dev_err(&pdev->dev, "no eeprom data received.\n");
+		goto release;
+	}
+
+	/* also note that we are doing *u16 operations on the file */
+	if (fw->size > sizeof(pdata->eeprom_data) || fw->size < 0x200 ||
+	    (fw->size & 1) == 1) {
+		dev_err(&pdev->dev, "eeprom file has an invalid size.\n");
+		goto release;
+	}
+
+	if (pdata) {
+		memcpy(pdata->eeprom_data, fw->data, fw->size);
+
+		/*
+		 * eeprom has been successfully loaded - pass the data to ath9k
+		 * but remove the eeprom_name, so it doesn't try to load it too.
+		 */
+		pdata->eeprom_name = NULL;
+	}
+
+	if (ath9k_pci_fixup(pdev, (const u16 *) fw->data, fw->size))
+		goto release;
+
+	pci_lock_rescan_remove();
+	bus = pdev->bus;
+	pci_stop_and_remove_bus_device(pdev);
+	/*
+	 * the device should come back with the proper
+	 * ProductId. But we have to initiate a rescan.
+	 */
+	pci_rescan_bus(bus);
+	pci_unlock_rescan_remove();
+
+release:
+	release_firmware(fw);
+}
+
+static const char *owl_get_eeprom_name(struct pci_dev *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ath9k_platform_data *pdata;
+	char *eeprom_name;
+
+	/* try the existing platform data first */
+	pdata = dev_get_platdata(dev);
+	if (pdata && pdata->eeprom_name)
+		return pdata->eeprom_name;
+
+	dev_dbg(dev, "using auto-generated eeprom filename\n");
+
+	eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL);
+	if (!eeprom_name)
+		return NULL;
+
+	/* this should match the pattern used in ath9k/init.c */
+	scnprintf(eeprom_name, EEPROM_FILENAME_LEN, "ath9k-eeprom-pci-%s.bin",
+		  dev_name(dev));
+
+	return eeprom_name;
+}
+
+static int owl_probe(struct pci_dev *pdev,
+		    const struct pci_device_id *id)
+{
+	struct owl_ctx *ctx;
+	const char *eeprom_name;
+	int err = 0;
+
+	if (pcim_enable_device(pdev))
+		return -EIO;
+
+	pcim_pin_device(pdev);
+
+	eeprom_name = owl_get_eeprom_name(pdev);
+	if (!eeprom_name) {
+		dev_err(&pdev->dev, "no eeprom filename found.\n");
+		return -ENODEV;
+	}
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		dev_err(&pdev->dev, "failed to alloc device context.\n");
+		return -ENOMEM;
+	}
+	init_completion(&ctx->eeprom_load);
+
+	pci_set_drvdata(pdev, ctx);
+	err = request_firmware_nowait(THIS_MODULE, true, eeprom_name,
+				      &pdev->dev, GFP_KERNEL, pdev, owl_fw_cb);
+	if (err) {
+		dev_err(&pdev->dev, "failed to request caldata (%d).\n", err);
+		kfree(ctx);
+	}
+	return err;
+}
+
+static void owl_remove(struct pci_dev *pdev)
+{
+	struct owl_ctx *ctx = pci_get_drvdata(pdev);
+
+	if (ctx) {
+		wait_for_completion(&ctx->eeprom_load);
+		pci_set_drvdata(pdev, NULL);
+		kfree(ctx);
+	}
+}
+
+static const struct pci_device_id owl_pci_table[] = {
+	{ PCI_VDEVICE(ATHEROS, 0xff1c) }, /* PCIe */
+	{ PCI_VDEVICE(ATHEROS, 0xff1d) }, /* PCI */
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, owl_pci_table);
+
+static struct pci_driver owl_driver = {
+	.name		= "owl-loader",
+	.id_table	= owl_pci_table,
+	.probe		= owl_probe,
+	.remove		= owl_remove,
+};
+module_pci_driver(owl_driver);
+MODULE_AUTHOR("Christian Lamparter <chunkeey@googlemail.com>");
+MODULE_DESCRIPTION("Initializes Atheros' Owl Emulation devices");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
new file mode 100644
index 0000000000..7e653e78a1
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig
@@ -0,0 +1,66 @@
+config MTD_SPLIT
+	def_bool n
+	help
+	  Generic MTD split support.
+
+config MTD_SPLIT_SUPPORT
+	def_bool MTD = y
+
+comment "Rootfs partition parsers"
+
+config MTD_SPLIT_SQUASHFS_ROOT
+	bool "Squashfs based root partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+	default n
+	help
+	  This provides a parsing function which allows to detect the
+	  offset and size of the unused portion of a rootfs partition
+	  containing a squashfs.
+
+comment "Firmware partition parsers"
+
+config MTD_SPLIT_SEAMA_FW
+	bool "Seama firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_WRGG_FW
+	bool "WRGG firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_UIMAGE_FW
+	bool "uImage based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_FIT_FW
+	bool "FIT based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_LZMA_FW
+	bool "LZMA compressed kernel based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_TPLINK_FW
+	bool "TP-Link firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_TRX_FW
+	bool "TRX image based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_BRNIMAGE_FW
+	bool "brnImage (brnboot image) firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_EVA_FW
+	bool "EVA image based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
new file mode 100644
index 0000000000..c843025ffb
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit.o
+obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o
+obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o
+obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o
+obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o
+obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o
+obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o
+obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o
+obj-$(CONFIG_MTD_SPLIT_BRNIMAGE_FW) += mtdsplit_brnimage.o
+obj-$(CONFIG_MTD_SPLIT_EVA_FW) += mtdsplit_eva.o
+obj-$(CONFIG_MTD_SPLIT_WRGG_FW) += mtdsplit_wrgg.o
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
new file mode 100644
index 0000000000..b2e51dcfc6
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009-2013 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2009-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jogo@openwrt.org>
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt)	"mtdsplit: " fmt
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/magic.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define UBI_EC_MAGIC			0x55424923	/* UBI# */
+
+struct squashfs_super_block {
+	__le32 s_magic;
+	__le32 pad0[9];
+	__le64 bytes_used;
+};
+
+int mtd_get_squashfs_len(struct mtd_info *master,
+			 size_t offset,
+			 size_t *squashfs_len)
+{
+	struct squashfs_super_block sb;
+	size_t retlen;
+	int err;
+
+	err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb);
+	if (err || (retlen != sizeof(sb))) {
+		pr_alert("error occured while reading from \"%s\"\n",
+			 master->name);
+		return -EIO;
+	}
+
+	if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) {
+		pr_alert("no squashfs found in \"%s\"\n", master->name);
+		return -EINVAL;
+	}
+
+	retlen = le64_to_cpu(sb.bytes_used);
+	if (retlen <= 0) {
+		pr_alert("squashfs is empty in \"%s\"\n", master->name);
+		return -ENODEV;
+	}
+
+	if (offset + retlen > master->size) {
+		pr_alert("squashfs has invalid size in \"%s\"\n",
+			 master->name);
+		return -EINVAL;
+	}
+
+	*squashfs_len = retlen;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_get_squashfs_len);
+
+static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset)
+{
+	return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize;
+}
+
+int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
+			   enum mtdsplit_part_type *type)
+{
+	u32 magic;
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, sizeof(magic), &retlen,
+		       (unsigned char *) &magic);
+	if (ret)
+		return ret;
+
+	if (retlen != sizeof(magic))
+		return -EIO;
+
+	if (le32_to_cpu(magic) == SQUASHFS_MAGIC) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_SQUASHFS;
+		return 0;
+	} else if (magic == 0x19852003) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_JFFS2;
+		return 0;
+	} else if (be32_to_cpu(magic) == UBI_EC_MAGIC) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_UBI;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic);
+
+int mtd_find_rootfs_from(struct mtd_info *mtd,
+			 size_t from,
+			 size_t limit,
+			 size_t *ret_offset,
+			 enum mtdsplit_part_type *type)
+{
+	size_t offset;
+	int err;
+
+	for (offset = from; offset < limit;
+	     offset = mtd_next_eb(mtd, offset)) {
+		err = mtd_check_rootfs_magic(mtd, offset, type);
+		if (err)
+			continue;
+
+		*ret_offset = offset;
+		return 0;
+	}
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(mtd_find_rootfs_from);
+
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
new file mode 100644
index 0000000000..71d62a8956
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009-2013 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2009-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jogo@openwrt.org>
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MTDSPLIT_H
+#define _MTDSPLIT_H
+
+#define KERNEL_PART_NAME	"kernel"
+#define ROOTFS_PART_NAME	"rootfs"
+#define UBI_PART_NAME		"ubi"
+
+#define ROOTFS_SPLIT_NAME	"rootfs_data"
+
+enum mtdsplit_part_type {
+	MTDSPLIT_PART_TYPE_UNK = 0,
+	MTDSPLIT_PART_TYPE_SQUASHFS,
+	MTDSPLIT_PART_TYPE_JFFS2,
+	MTDSPLIT_PART_TYPE_UBI,
+};
+
+#ifdef CONFIG_MTD_SPLIT
+int mtd_get_squashfs_len(struct mtd_info *master,
+			 size_t offset,
+			 size_t *squashfs_len);
+
+int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
+			   enum mtdsplit_part_type *type);
+
+int mtd_find_rootfs_from(struct mtd_info *mtd,
+			 size_t from,
+			 size_t limit,
+			 size_t *ret_offset,
+			 enum mtdsplit_part_type *type);
+
+#else
+static inline int mtd_get_squashfs_len(struct mtd_info *master,
+				       size_t offset,
+				       size_t *squashfs_len)
+{
+	return -ENODEV;
+}
+
+static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
+					 enum mtdsplit_part_type *type)
+{
+	return -EINVAL;
+}
+
+static inline int mtd_find_rootfs_from(struct mtd_info *mtd,
+				       size_t from,
+				       size_t limit,
+				       size_t *ret_offset,
+				       enum mtdsplit_part_type *type)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_MTD_SPLIT */
+
+#endif /* _MTDSPLIT_H */
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
new file mode 100644
index 0000000000..1f4325ac9a
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define BRNIMAGE_NR_PARTS	2
+
+#define BRNIMAGE_ALIGN_BYTES	0x400
+#define BRNIMAGE_FOOTER_SIZE	12
+
+#define BRNIMAGE_MIN_OVERHEAD	(BRNIMAGE_FOOTER_SIZE)
+#define BRNIMAGE_MAX_OVERHEAD	(BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE)
+
+static int mtdsplit_parse_brnimage(struct mtd_info *master,
+				struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	uint32_t buf;
+	unsigned long rootfs_offset, rootfs_size, kernel_size;
+	size_t len;
+	int ret = 0;
+
+	for (rootfs_offset = 0; rootfs_offset < master->size;
+	     rootfs_offset += BRNIMAGE_ALIGN_BYTES) {
+		ret = mtd_check_rootfs_magic(master, rootfs_offset, NULL);
+		if (!ret)
+			break;
+	}
+
+	if (ret)
+		return ret;
+
+	if (rootfs_offset >= master->size)
+		return -EINVAL;
+
+	ret = mtd_read(master, rootfs_offset - BRNIMAGE_FOOTER_SIZE, 4, &len,
+			(void *)&buf);
+	if (ret)
+		return ret;
+
+	if (len != 4)
+		return -EIO;
+
+	kernel_size = le32_to_cpu(buf);
+
+	if (kernel_size > (rootfs_offset - BRNIMAGE_MIN_OVERHEAD))
+		return -EINVAL;
+
+	if (kernel_size < (rootfs_offset - BRNIMAGE_MAX_OVERHEAD))
+		return -EINVAL;
+
+	/*
+	 * The footer must be untouched as it contains the checksum of the
+	 * original brnImage (kernel + squashfs)!
+	 */
+	rootfs_size = master->size - rootfs_offset - BRNIMAGE_FOOTER_SIZE;
+
+	parts = kzalloc(BRNIMAGE_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = kernel_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return BRNIMAGE_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_brnimage_parser = {
+	.owner = THIS_MODULE,
+	.name = "brnimage-fw",
+	.parse_fn = mtdsplit_parse_brnimage,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_brnimage_init(void)
+{
+	register_mtd_parser(&mtdsplit_brnimage_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_brnimage_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c
new file mode 100644
index 0000000000..3edc104f4e
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define EVA_NR_PARTS		2
+#define EVA_MAGIC		0xfeed1281
+#define EVA_FOOTER_SIZE		0x18
+#define EVA_DUMMY_SQUASHFS_SIZE	0x100
+
+struct eva_image_header {
+	uint32_t	magic;
+	uint32_t	size;
+};
+
+static int mtdsplit_parse_eva(struct mtd_info *master,
+				struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	struct eva_image_header hdr;
+	size_t retlen;
+	unsigned long kernel_size, rootfs_offset;
+	int err;
+
+	err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != sizeof(hdr))
+		return -EIO;
+
+	if (le32_to_cpu(hdr.magic) != EVA_MAGIC)
+		return -EINVAL;
+
+	kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE;
+
+	/* rootfs starts at the next 0x10000 boundary: */
+	rootfs_offset = round_up(kernel_size, 0x10000);
+
+	/* skip the dummy EVA squashfs partition (with wrong endianness): */
+	rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE;
+
+	if (rootfs_offset >= master->size)
+		return -EINVAL;
+
+	err = mtd_check_rootfs_magic(master, rootfs_offset, NULL);
+	if (err)
+		return err;
+
+	parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = kernel_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return EVA_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_eva_parser = {
+	.owner = THIS_MODULE,
+	.name = "eva-fw",
+	.parse_fn = mtdsplit_parse_eva,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_eva_init(void)
+{
+	register_mtd_parser(&mtdsplit_eva_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_eva_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
new file mode 100644
index 0000000000..57954061cd
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/types.h>
+#include <linux/byteorder/generic.h>
+#include <linux/slab.h>
+#include <linux/of_fdt.h>
+
+#include "mtdsplit.h"
+
+struct fdt_header {
+	uint32_t magic;			 /* magic word FDT_MAGIC */
+	uint32_t totalsize;		 /* total size of DT block */
+	uint32_t off_dt_struct;		 /* offset to structure */
+	uint32_t off_dt_strings;	 /* offset to strings */
+	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */
+	uint32_t version;		 /* format version */
+	uint32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	uint32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	uint32_t size_dt_struct;	 /* size of the structure block */
+};
+
+static int
+mtdsplit_fit_parse(struct mtd_info *mtd, struct mtd_partition **pparts,
+	           struct mtd_part_parser_data *data)
+{
+	struct fdt_header hdr;
+	size_t hdr_len, retlen;
+	size_t offset;
+	size_t fit_offset, fit_size;
+	size_t rootfs_offset, rootfs_size;
+	struct mtd_partition *parts;
+	int ret;
+
+	hdr_len = sizeof(struct fdt_header);
+
+	/* Parse the MTD device & search for the FIT image location */
+	for(offset = 0; offset < mtd->size; offset += mtd->erasesize) {
+		ret = mtd_read(mtd, 0, hdr_len, &retlen, (void*) &hdr);
+		if (ret) {
+			pr_err("read error in \"%s\" at offset 0x%llx\n",
+			       mtd->name, (unsigned long long) offset);
+			return ret;
+		}
+
+		if (retlen != hdr_len) {
+			pr_err("short read in \"%s\"\n", mtd->name);
+			return -EIO;
+		}
+
+		/* Check the magic - see if this is a FIT image */
+		if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) {
+			pr_debug("no valid FIT image found in \"%s\" at offset %llx\n",
+				 mtd->name, (unsigned long long) offset);
+			continue;
+		}
+
+		/* We found a FIT image. Let's keep going */
+		break;
+	}
+
+	fit_offset = offset;
+	fit_size = be32_to_cpu(hdr.totalsize);
+
+	if (fit_size == 0) {
+		pr_err("FIT image in \"%s\" at offset %llx has null size\n",
+		       mtd->name, (unsigned long long) fit_offset);
+		return -ENODEV;
+	}
+
+	/* Search for the rootfs partition after the FIT image */
+	ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size,
+				   &rootfs_offset, NULL);
+	if (ret) {
+		pr_info("no rootfs found after FIT image in \"%s\"\n",
+			mtd->name);
+		return ret;
+	}
+
+	rootfs_size = mtd->size - rootfs_offset;
+
+	parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = fit_offset;
+	parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return 2;
+}
+
+static struct mtd_part_parser uimage_parser = {
+	.owner = THIS_MODULE,
+	.name = "fit-fw",
+	.parse_fn = mtdsplit_fit_parse,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static int __init mtdsplit_fit_init(void)
+{
+	register_mtd_parser(&uimage_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_fit_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c
new file mode 100644
index 0000000000..f3d8c040c2
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/unaligned.h>
+
+#include "mtdsplit.h"
+
+#define LZMA_NR_PARTS		2
+#define LZMA_PROPERTIES_SIZE	5
+
+struct lzma_header {
+	u8 props[LZMA_PROPERTIES_SIZE];
+	u8 size_low[4];
+	u8 size_high[4];
+};
+
+static int mtdsplit_parse_lzma(struct mtd_info *master,
+			       struct mtd_partition **pparts,
+			       struct mtd_part_parser_data *data)
+{
+	struct lzma_header hdr;
+	size_t hdr_len, retlen;
+	size_t rootfs_offset;
+	u32 t;
+	struct mtd_partition *parts;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* verify LZMA properties */
+	if (hdr.props[0] >= (9 * 5 * 5))
+		return -EINVAL;
+
+	t = get_unaligned_le32(&hdr.props[1]);
+	if (!is_power_of_2(t))
+		return -EINVAL;
+
+	t = get_unaligned_le32(&hdr.size_high);
+	if (t)
+		return -EINVAL;
+
+	err = mtd_find_rootfs_from(master, master->erasesize, master->size,
+				   &rootfs_offset, NULL);
+	if (err)
+		return err;
+
+	parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return LZMA_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_lzma_parser = {
+	.owner = THIS_MODULE,
+	.name = "lzma-fw",
+	.parse_fn = mtdsplit_parse_lzma,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_lzma_init(void)
+{
+	register_mtd_parser(&mtdsplit_lzma_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_lzma_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c
new file mode 100644
index 0000000000..9fe1311018
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define SEAMA_MAGIC		0x5EA3A417
+#define SEAMA_NR_PARTS		2
+#define SEAMA_MIN_ROOTFS_OFFS	0x80000	/* 512KiB */
+
+struct seama_header {
+	__be32	magic;		/* should always be SEAMA_MAGIC. */
+	__be16	reserved;	/* reserved for  */
+	__be16	metasize;	/* size of the META data */
+	__be32	size;		/* size of the image */
+	u8	md5[16];	/* digest */
+};
+
+static int mtdsplit_parse_seama(struct mtd_info *master,
+				struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct seama_header hdr;
+	size_t hdr_len, retlen, kernel_ent_size;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	enum mtdsplit_part_type type;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* sanity checks */
+	if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC)
+		return -EINVAL;
+
+	kernel_ent_size = hdr_len + be32_to_cpu(hdr.size) +
+			  be16_to_cpu(hdr.metasize);
+	if (kernel_ent_size > master->size)
+		return -EINVAL;
+
+	/* Check for the rootfs right after Seama entity with a kernel. */
+	err = mtd_check_rootfs_magic(master, kernel_ent_size, &type);
+	if (!err) {
+		rootfs_offset = kernel_ent_size;
+	} else {
+		/*
+		 * On some devices firmware entity might contain both: kernel
+		 * and rootfs. We can't determine kernel size so we just have to
+		 * look for rootfs magic.
+		 * Start the search from an arbitrary offset.
+		 */
+		err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS,
+					   master->size, &rootfs_offset, &type);
+		if (err)
+			return err;
+	}
+
+	parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = sizeof hdr + be16_to_cpu(hdr.metasize);
+	parts[0].size = rootfs_offset - parts[0].offset;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[1].name = UBI_PART_NAME;
+	else
+		parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return SEAMA_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_seama_parser = {
+	.owner = THIS_MODULE,
+	.name = "seama-fw",
+	.parse_fn = mtdsplit_parse_seama,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_seama_init(void)
+{
+	register_mtd_parser(&mtdsplit_seama_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_seama_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
new file mode 100644
index 0000000000..43b44d5642
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 2013 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/magic.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+static int
+mtdsplit_parse_squashfs(struct mtd_info *master,
+			struct mtd_partition **pparts,
+			struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *part;
+	struct mtd_info *parent_mtd;
+	size_t part_offset;
+	size_t squashfs_len;
+	int err;
+
+	err = mtd_get_squashfs_len(master, 0, &squashfs_len);
+	if (err)
+		return err;
+
+	parent_mtd = mtdpart_get_master(master);
+	part_offset = mtdpart_get_offset(master);
+
+	part = kzalloc(sizeof(*part), GFP_KERNEL);
+	if (!part) {
+		pr_alert("unable to allocate memory for \"%s\" partition\n",
+			 ROOTFS_SPLIT_NAME);
+		return -ENOMEM;
+	}
+
+	part->name = ROOTFS_SPLIT_NAME;
+	part->offset = mtd_roundup_to_eb(part_offset + squashfs_len,
+					 parent_mtd) - part_offset;
+	part->size = mtd_rounddown_to_eb(master->size - part->offset, master);
+
+	*pparts = part;
+	return 1;
+}
+
+static struct mtd_part_parser mtdsplit_squashfs_parser = {
+	.owner = THIS_MODULE,
+	.name = "squashfs-split",
+	.parse_fn = mtdsplit_parse_squashfs,
+	.type = MTD_PARSER_TYPE_ROOTFS,
+};
+
+static int __init mtdsplit_squashfs_init(void)
+{
+	register_mtd_parser(&mtdsplit_squashfs_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_squashfs_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c
new file mode 100644
index 0000000000..d0cb381363
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c
@@ -0,0 +1,169 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define TPLINK_NR_PARTS		2
+#define TPLINK_MIN_ROOTFS_OFFS	0x80000	/* 512KiB */
+
+#define MD5SUM_LEN  16
+
+struct fw_v1 {
+	char		vendor_name[24];
+	char		fw_version[36];
+	uint32_t	hw_id;		/* hardware id */
+	uint32_t	hw_rev;		/* hardware revision */
+	uint32_t	unk1;
+	uint8_t		md5sum1[MD5SUM_LEN];
+	uint32_t	unk2;
+	uint8_t		md5sum2[MD5SUM_LEN];
+	uint32_t	unk3;
+	uint32_t	kernel_la;	/* kernel load address */
+	uint32_t	kernel_ep;	/* kernel entry point */
+	uint32_t	fw_length;	/* total length of the firmware */
+	uint32_t	kernel_ofs;	/* kernel data offset */
+	uint32_t	kernel_len;	/* kernel data length */
+	uint32_t	rootfs_ofs;	/* rootfs data offset */
+	uint32_t	rootfs_len;	/* rootfs data length */
+	uint32_t	boot_ofs;	/* bootloader data offset */
+	uint32_t	boot_len;	/* bootloader data length */
+	uint8_t		pad[360];
+} __attribute__ ((packed));
+
+struct fw_v2 {
+	char		fw_version[48]; /* 0x04: fw version string */
+	uint32_t	hw_id;		/* 0x34: hardware id */
+	uint32_t	hw_rev;		/* 0x38: FIXME: hardware revision? */
+	uint32_t	unk1;	        /* 0x3c: 0x00000000 */
+	uint8_t		md5sum1[MD5SUM_LEN]; /* 0x40 */
+	uint32_t	unk2;		/* 0x50: 0x00000000 */
+	uint8_t		md5sum2[MD5SUM_LEN]; /* 0x54 */
+	uint32_t	unk3;		/* 0x64: 0xffffffff */
+
+	uint32_t	kernel_la;	/* 0x68: kernel load address */
+	uint32_t	kernel_ep;	/* 0x6c: kernel entry point */
+	uint32_t	fw_length;	/* 0x70: total length of the image */
+	uint32_t	kernel_ofs;	/* 0x74: kernel data offset */
+	uint32_t	kernel_len;	/* 0x78: kernel data length */
+	uint32_t	rootfs_ofs;	/* 0x7c: rootfs data offset */
+	uint32_t	rootfs_len;	/* 0x80: rootfs data length */
+	uint32_t	boot_ofs;	/* 0x84: FIXME: seems to be unused */
+	uint32_t	boot_len;	/* 0x88: FIXME: seems to be unused */
+	uint16_t	unk4;		/* 0x8c: 0x55aa */
+	uint8_t		sver_hi;	/* 0x8e */
+	uint8_t		sver_lo;	/* 0x8f */
+	uint8_t		unk5;		/* 0x90: magic: 0xa5 */
+	uint8_t		ver_hi;         /* 0x91 */
+	uint8_t		ver_mid;        /* 0x92 */
+	uint8_t		ver_lo;         /* 0x93 */
+	uint8_t		pad[364];
+} __attribute__ ((packed));
+
+struct tplink_fw_header {
+	uint32_t version;
+	union {
+		struct fw_v1 v1;
+		struct fw_v2 v2;
+	};
+};
+
+static int mtdsplit_parse_tplink(struct mtd_info *master,
+				struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct tplink_fw_header hdr;
+	size_t hdr_len, retlen, kernel_size;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	switch (le32_to_cpu(hdr.version)) {
+	case 1:
+		if (be32_to_cpu(hdr.v1.kernel_ofs) != sizeof(hdr))
+			return -EINVAL;
+
+		kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v1.kernel_len);
+		break;
+	case 2:
+	case 3:
+		if (be32_to_cpu(hdr.v2.kernel_ofs) != sizeof(hdr))
+			return -EINVAL;
+
+		kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v2.kernel_len);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (kernel_size > master->size)
+		return -EINVAL;
+
+	/* Find the rootfs after the kernel. */
+	err = mtd_check_rootfs_magic(master, kernel_size, NULL);
+	if (!err) {
+		rootfs_offset = kernel_size;
+	} else {
+		/*
+		 * The size in the header might cover the rootfs as well.
+		 * Start the search from an arbitrary offset.
+		 */
+		err = mtd_find_rootfs_from(master, TPLINK_MIN_ROOTFS_OFFS,
+					   master->size, &rootfs_offset, NULL);
+		if (err)
+			return err;
+	}
+
+	parts = kzalloc(TPLINK_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return TPLINK_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_tplink_parser = {
+	.owner = THIS_MODULE,
+	.name = "tplink-fw",
+	.parse_fn = mtdsplit_parse_tplink,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_tplink_init(void)
+{
+	register_mtd_parser(&mtdsplit_tplink_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_tplink_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c
new file mode 100644
index 0000000000..29f47b283e
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c
@@ -0,0 +1,147 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *
+ *  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.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define TRX_MAGIC   0x30524448  /* "HDR0" */
+
+struct trx_header {
+	__le32 magic;
+	__le32 len;
+	__le32 crc32;
+	__le32 flag_version;
+	__le32 offset[4];
+};
+
+static int
+read_trx_header(struct mtd_info *mtd, size_t offset,
+		   struct trx_header *header)
+{
+	size_t header_len;
+	size_t retlen;
+	int ret;
+
+	header_len = sizeof(*header);
+	ret = mtd_read(mtd, offset, header_len, &retlen,
+		       (unsigned char *) header);
+	if (ret) {
+		pr_debug("read error in \"%s\"\n", mtd->name);
+		return ret;
+	}
+
+	if (retlen != header_len) {
+		pr_debug("short read in \"%s\"\n", mtd->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int
+mtdsplit_parse_trx(struct mtd_info *master,
+		   struct mtd_partition **pparts,
+		   struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	struct trx_header hdr;
+	int nr_parts;
+	size_t offset;
+	size_t trx_offset;
+	size_t trx_size = 0;
+	size_t rootfs_offset;
+	size_t rootfs_size = 0;
+	int ret;
+
+	nr_parts = 2;
+	parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	/* find trx image on erase block boundaries */
+	for (offset = 0; offset < master->size; offset += master->erasesize) {
+		trx_size = 0;
+
+		ret = read_trx_header(master, offset, &hdr);
+		if (ret)
+			continue;
+
+		if (hdr.magic != cpu_to_le32(TRX_MAGIC)) {
+			pr_debug("no valid trx header found in \"%s\" at offset %llx\n",
+				 master->name, (unsigned long long) offset);
+			continue;
+		}
+
+		trx_size = le32_to_cpu(hdr.len);
+		if ((offset + trx_size) > master->size) {
+			pr_debug("trx image exceeds MTD device \"%s\"\n",
+				 master->name);
+			continue;
+		}
+		break;
+	}
+
+	if (trx_size == 0) {
+		pr_debug("no trx header found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	trx_offset = offset + hdr.offset[0];
+	rootfs_offset = offset + hdr.offset[1];
+	rootfs_size = master->size - rootfs_offset;
+	trx_size = rootfs_offset - trx_offset;
+
+	if (rootfs_size == 0) {
+		pr_debug("no rootfs found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = trx_offset;
+	parts[0].size = trx_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return nr_parts;
+
+err:
+	kfree(parts);
+	return ret;
+}
+
+static struct mtd_part_parser trx_parser = {
+	.owner = THIS_MODULE,
+	.name = "trx-fw",
+	.parse_fn = mtdsplit_parse_trx,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_trx_init(void)
+{
+	register_mtd_parser(&trx_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_trx_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
new file mode 100644
index 0000000000..26cb66ac7f
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
@@ -0,0 +1,359 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+/*
+ * uimage_header itself is only 64B, but it may be prepended with another data.
+ * Currently the biggest size is for Edimax devices: 20B + 64B
+ */
+#define MAX_HEADER_LEN		84
+
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN		32	/* Image Name Length		*/
+
+#define IH_OS_LINUX		5	/* Linux	*/
+
+#define IH_TYPE_KERNEL		2	/* OS Kernel Image		*/
+#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image		*/
+
+/*
+ * Legacy format image header,
+ * all data in network byte order (aka natural aka bigendian).
+ */
+struct uimage_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+};
+
+static int
+read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf,
+		   size_t header_len)
+{
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, header_len, &retlen, buf);
+	if (ret) {
+		pr_debug("read error in \"%s\"\n", mtd->name);
+		return ret;
+	}
+
+	if (retlen != header_len) {
+		pr_debug("short read in \"%s\"\n", mtd->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts
+ *
+ * @find_header: function to call for a block of data that will return offset
+ *      of a valid uImage header if found
+ */
+static int __mtdsplit_parse_uimage(struct mtd_info *master,
+				   struct mtd_partition **pparts,
+				   struct mtd_part_parser_data *data,
+				   ssize_t (*find_header)(u_char *buf, size_t len))
+{
+	struct mtd_partition *parts;
+	u_char *buf;
+	int nr_parts;
+	size_t offset;
+	size_t uimage_offset;
+	size_t uimage_size = 0;
+	size_t rootfs_offset;
+	size_t rootfs_size = 0;
+	int uimage_part, rf_part;
+	int ret;
+	enum mtdsplit_part_type type;
+
+	nr_parts = 2;
+	parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	buf = vmalloc(MAX_HEADER_LEN);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_free_parts;
+	}
+
+	/* find uImage on erase block boundaries */
+	for (offset = 0; offset < master->size; offset += master->erasesize) {
+		struct uimage_header *header;
+
+		uimage_size = 0;
+
+		ret = read_uimage_header(master, offset, buf, MAX_HEADER_LEN);
+		if (ret)
+			continue;
+
+		ret = find_header(buf, MAX_HEADER_LEN);
+		if (ret < 0) {
+			pr_debug("no valid uImage found in \"%s\" at offset %llx\n",
+				 master->name, (unsigned long long) offset);
+			continue;
+		}
+		header = (struct uimage_header *)(buf + ret);
+
+		uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size) + ret;
+		if ((offset + uimage_size) > master->size) {
+			pr_debug("uImage exceeds MTD device \"%s\"\n",
+				 master->name);
+			continue;
+		}
+		break;
+	}
+
+	if (uimage_size == 0) {
+		pr_debug("no uImage found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err_free_buf;
+	}
+
+	uimage_offset = offset;
+
+	if (uimage_offset == 0) {
+		uimage_part = 0;
+		rf_part = 1;
+
+		/* find the roots after the uImage */
+		ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size,
+					   master->size, &rootfs_offset, &type);
+		if (ret) {
+			pr_debug("no rootfs after uImage in \"%s\"\n",
+				 master->name);
+			goto err_free_buf;
+		}
+
+		rootfs_size = master->size - rootfs_offset;
+		uimage_size = rootfs_offset - uimage_offset;
+	} else {
+		rf_part = 0;
+		uimage_part = 1;
+
+		/* check rootfs presence at offset 0 */
+		ret = mtd_check_rootfs_magic(master, 0, &type);
+		if (ret) {
+			pr_debug("no rootfs before uImage in \"%s\"\n",
+				 master->name);
+			goto err_free_buf;
+		}
+
+		rootfs_offset = 0;
+		rootfs_size = uimage_offset;
+	}
+
+	if (rootfs_size == 0) {
+		pr_debug("no rootfs found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err_free_buf;
+	}
+
+	parts[uimage_part].name = KERNEL_PART_NAME;
+	parts[uimage_part].offset = uimage_offset;
+	parts[uimage_part].size = uimage_size;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[rf_part].name = UBI_PART_NAME;
+	else
+		parts[rf_part].name = ROOTFS_PART_NAME;
+	parts[rf_part].offset = rootfs_offset;
+	parts[rf_part].size = rootfs_size;
+
+	vfree(buf);
+
+	*pparts = parts;
+	return nr_parts;
+
+err_free_buf:
+	vfree(buf);
+
+err_free_parts:
+	kfree(parts);
+	return ret;
+}
+
+static ssize_t uimage_verify_default(u_char *buf, size_t len)
+{
+	struct uimage_header *header = (struct uimage_header *)buf;
+
+	/* default sanity checks */
+	if (be32_to_cpu(header->ih_magic) != IH_MAGIC) {
+		pr_debug("invalid uImage magic: %08x\n",
+			 be32_to_cpu(header->ih_magic));
+		return -EINVAL;
+	}
+
+	if (header->ih_os != IH_OS_LINUX) {
+		pr_debug("invalid uImage OS: %08x\n",
+			 be32_to_cpu(header->ih_os));
+		return -EINVAL;
+	}
+
+	if (header->ih_type != IH_TYPE_KERNEL) {
+		pr_debug("invalid uImage type: %08x\n",
+			 be32_to_cpu(header->ih_type));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mtdsplit_uimage_parse_generic(struct mtd_info *master,
+			      struct mtd_partition **pparts,
+			      struct mtd_part_parser_data *data)
+{
+	return __mtdsplit_parse_uimage(master, pparts, data,
+				      uimage_verify_default);
+}
+
+static struct mtd_part_parser uimage_generic_parser = {
+	.owner = THIS_MODULE,
+	.name = "uimage-fw",
+	.parse_fn = mtdsplit_uimage_parse_generic,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+#define FW_MAGIC_WNR2000V3	0x32303033
+#define FW_MAGIC_WNR2000V4	0x32303034
+#define FW_MAGIC_WNR2200	0x32323030
+#define FW_MAGIC_WNR612V2	0x32303631
+#define FW_MAGIC_WNR1000V2	0x31303031
+#define FW_MAGIC_WNR1000V2_VC	0x31303030
+#define FW_MAGIC_WNDR3700	0x33373030
+#define FW_MAGIC_WNDR3700V2	0x33373031
+#define FW_MAGIC_WPN824N	0x31313030
+
+static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len)
+{
+	struct uimage_header *header = (struct uimage_header *)buf;
+	uint8_t expected_type = IH_TYPE_FILESYSTEM;
+
+	switch be32_to_cpu(header->ih_magic) {
+	case FW_MAGIC_WNR612V2:
+	case FW_MAGIC_WNR1000V2:
+	case FW_MAGIC_WNR1000V2_VC:
+	case FW_MAGIC_WNR2000V3:
+	case FW_MAGIC_WNR2200:
+	case FW_MAGIC_WNDR3700:
+	case FW_MAGIC_WNDR3700V2:
+	case FW_MAGIC_WPN824N:
+		break;
+	case FW_MAGIC_WNR2000V4:
+		expected_type = IH_TYPE_KERNEL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (header->ih_os != IH_OS_LINUX ||
+	    header->ih_type != expected_type)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+mtdsplit_uimage_parse_netgear(struct mtd_info *master,
+			      struct mtd_partition **pparts,
+			      struct mtd_part_parser_data *data)
+{
+	return __mtdsplit_parse_uimage(master, pparts, data,
+				      uimage_verify_wndr3700);
+}
+
+static struct mtd_part_parser uimage_netgear_parser = {
+	.owner = THIS_MODULE,
+	.name = "netgear-fw",
+	.parse_fn = mtdsplit_uimage_parse_netgear,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Edimax
+ **************************************************/
+
+#define FW_EDIMAX_OFFSET	20
+#define FW_MAGIC_EDIMAX		0x43535953
+
+static ssize_t uimage_find_edimax(u_char *buf, size_t len)
+{
+	u32 *magic;
+
+	if (len < FW_EDIMAX_OFFSET + sizeof(struct uimage_header)) {
+		pr_err("Buffer too small for checking Edimax header\n");
+		return -ENOSPC;
+	}
+
+	magic = (u32 *)buf;
+	if (be32_to_cpu(*magic) != FW_MAGIC_EDIMAX)
+		return -EINVAL;
+
+	if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len))
+		return FW_EDIMAX_OFFSET;
+
+	return -EINVAL;
+}
+
+static int
+mtdsplit_uimage_parse_edimax(struct mtd_info *master,
+			      struct mtd_partition **pparts,
+			      struct mtd_part_parser_data *data)
+{
+	return __mtdsplit_parse_uimage(master, pparts, data,
+				       uimage_find_edimax);
+}
+
+static struct mtd_part_parser uimage_edimax_parser = {
+	.owner = THIS_MODULE,
+	.name = "edimax-fw",
+	.parse_fn = mtdsplit_uimage_parse_edimax,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static int __init mtdsplit_uimage_init(void)
+{
+	register_mtd_parser(&uimage_generic_parser);
+	register_mtd_parser(&uimage_netgear_parser);
+	register_mtd_parser(&uimage_edimax_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_uimage_init);
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
new file mode 100644
index 0000000000..c1fbccbd25
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define WRGG_NR_PARTS		2
+#define WRGG_MIN_ROOTFS_OFFS	0x80000	/* 512KiB */
+#define WRGG03_MAGIC		0x20080321
+
+struct wrgg03_header {
+	char		signature[32];
+	uint32_t	magic1;
+	uint32_t	magic2;
+	char		version[16];
+	char		model[16];
+	uint32_t	flag[2];
+	uint32_t	reserve[2];
+	char		buildno[16];
+	uint32_t	size;
+	uint32_t	offset;
+	char		devname[32];
+	char		digest[16];
+} __attribute__ ((packed));
+
+
+static int mtdsplit_parse_wrgg(struct mtd_info *master,
+				struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct wrgg03_header hdr;
+	size_t hdr_len, retlen, kernel_ent_size;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	enum mtdsplit_part_type type;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* sanity checks */
+	if (le32_to_cpu(hdr.magic1) != WRGG03_MAGIC)
+		return -EINVAL;
+
+	kernel_ent_size = hdr_len + be32_to_cpu(hdr.size);
+
+	if (kernel_ent_size > master->size)
+		return -EINVAL;
+
+	/*
+	 * The size in the header covers the rootfs as well.
+	 * Start the search from an arbitrary offset.
+	 */
+	err = mtd_find_rootfs_from(master, WRGG_MIN_ROOTFS_OFFS,
+				   master->size, &rootfs_offset, &type);
+	if (err)
+		return err;
+
+	parts = kzalloc(WRGG_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return WRGG_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_wrgg_parser = {
+	.owner = THIS_MODULE,
+	.name = "wrgg-fw",
+	.parse_fn = mtdsplit_parse_wrgg,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_wrgg_init(void)
+{
+	register_mtd_parser(&mtdsplit_wrgg_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_wrgg_init);
diff --git a/target/linux/generic/files/drivers/mtd/myloader.c b/target/linux/generic/files/drivers/mtd/myloader.c
new file mode 100644
index 0000000000..cd573690a7
--- /dev/null
+++ b/target/linux/generic/files/drivers/mtd/myloader.c
@@ -0,0 +1,182 @@
+/*
+ *  Parse MyLoader-style flash partition tables and produce a Linux partition
+ *  array to match.
+ *
+ *  Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This file was based on drivers/mtd/redboot.c
+ *  Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/myloader.h>
+
+#define BLOCK_LEN_MIN		0x10000
+#define PART_NAME_LEN		32
+
+struct part_data {
+	struct mylo_partition_table	tab;
+	char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
+};
+
+static int myloader_parse_partitions(struct mtd_info *master,
+				     struct mtd_partition **pparts,
+				     struct mtd_part_parser_data *data)
+{
+	struct part_data *buf;
+	struct mylo_partition_table *tab;
+	struct mylo_partition *part;
+	struct mtd_partition *mtd_parts;
+	struct mtd_partition *mtd_part;
+	int num_parts;
+	int ret, i;
+	size_t retlen;
+	char *names;
+	unsigned long offset;
+	unsigned long blocklen;
+
+	buf = vmalloc(sizeof(*buf));
+	if (!buf) {
+		return -ENOMEM;
+		goto out;
+	}
+	tab = &buf->tab;
+
+	blocklen = master->erasesize;
+	if (blocklen < BLOCK_LEN_MIN)
+		blocklen = BLOCK_LEN_MIN;
+
+	offset = blocklen;
+
+	/* Find the partition table */
+	for (i = 0; i < 4; i++, offset += blocklen) {
+		printk(KERN_DEBUG "%s: searching for MyLoader partition table"
+				" at offset 0x%lx\n", master->name, offset);
+
+		ret = mtd_read(master, offset, sizeof(*buf), &retlen,
+			       (void *)buf);
+		if (ret)
+			goto out_free_buf;
+
+		if (retlen != sizeof(*buf)) {
+			ret = -EIO;
+			goto out_free_buf;
+		}
+
+		/* Check for Partition Table magic number */
+		if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
+			break;
+
+	}
+
+	if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
+		printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
+			master->name);
+		ret = 0;
+		goto out_free_buf;
+	}
+
+	/* The MyLoader and the Partition Table is always present */
+	num_parts = 2;
+
+	/* Detect number of used partitions */
+	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
+		part = &tab->partitions[i];
+
+		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
+			continue;
+
+		num_parts++;
+	}
+
+	mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
+				num_parts * PART_NAME_LEN), GFP_KERNEL);
+
+	if (!mtd_parts) {
+		ret = -ENOMEM;
+		goto out_free_buf;
+	}
+
+	mtd_part = mtd_parts;
+	names = (char *)&mtd_parts[num_parts];
+
+	strncpy(names, "myloader", PART_NAME_LEN);
+	mtd_part->name = names;
+	mtd_part->offset = 0;
+	mtd_part->size = offset;
+	mtd_part->mask_flags = MTD_WRITEABLE;
+	mtd_part++;
+	names += PART_NAME_LEN;
+
+	strncpy(names, "partition_table", PART_NAME_LEN);
+	mtd_part->name = names;
+	mtd_part->offset = offset;
+	mtd_part->size = blocklen;
+	mtd_part->mask_flags = MTD_WRITEABLE;
+	mtd_part++;
+	names += PART_NAME_LEN;
+
+	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
+		part = &tab->partitions[i];
+
+		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
+			continue;
+
+		if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
+			strncpy(names, buf->names[i], PART_NAME_LEN);
+		else
+			snprintf(names, PART_NAME_LEN, "partition%d", i);
+
+		mtd_part->offset = le32_to_cpu(part->addr);
+		mtd_part->size = le32_to_cpu(part->size);
+		mtd_part->name = names;
+		mtd_part++;
+		names += PART_NAME_LEN;
+	}
+
+	*pparts = mtd_parts;
+	ret = num_parts;
+
+ out_free_buf:
+	vfree(buf);
+ out:
+	return ret;
+}
+
+static struct mtd_part_parser myloader_mtd_parser = {
+	.owner		= THIS_MODULE,
+	.parse_fn	= myloader_parse_partitions,
+	.name		= "MyLoader",
+};
+
+static int __init myloader_mtd_parser_init(void)
+{
+	register_mtd_parser(&myloader_mtd_parser);
+
+	return 0;
+}
+
+static void __exit myloader_mtd_parser_exit(void)
+{
+	deregister_mtd_parser(&myloader_mtd_parser);
+}
+
+module_init(myloader_mtd_parser_init);
+module_exit(myloader_mtd_parser_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/generic/files/drivers/net/phy/adm6996.c b/target/linux/generic/files/drivers/net/phy/adm6996.c
new file mode 100644
index 0000000000..2fe2ee71bc
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/adm6996.c
@@ -0,0 +1,1215 @@
+/*
+ * ADM6996 switch driver
+ *
+ * swconfig interface based on ar8216.c
+ *
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ * VLAN support Copyright (c) 2010, 2011 Peter Lebbing <peter@digitalbrains.com>
+ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright (c) 2014 Matti Laakso <malaakso@elisanet.fi>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/*#define DEBUG 1*/
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/adm6996-gpio.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/switch.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "adm6996.h"
+
+MODULE_DESCRIPTION("Infineon ADM6996 Switch");
+MODULE_AUTHOR("Felix Fietkau, Peter Lebbing <peter@digitalbrains.com>");
+MODULE_LICENSE("GPL");
+
+static const char * const adm6996_model_name[] =
+{
+	NULL,
+	"ADM6996FC",
+	"ADM6996M",
+	"ADM6996L"
+};
+
+struct adm6996_mib_desc {
+	unsigned int offset;
+	const char *name;
+};
+
+struct adm6996_priv {
+	struct switch_dev dev;
+	void *priv;
+
+	u8 eecs;
+	u8 eesk;
+	u8 eedi;
+	u8 eerc;
+
+	enum adm6996_model model;
+
+	bool enable_vlan;
+	bool vlan_enabled;	/* Current hardware state */
+
+#ifdef DEBUG
+	u16 addr;		/* Debugging: register address to operate on */
+#endif
+
+	u16 pvid[ADM_NUM_PORTS];	/* Primary VLAN ID */
+	u8 tagged_ports;
+
+	u16 vlan_id[ADM_NUM_VLANS];
+	u8 vlan_table[ADM_NUM_VLANS];	/* bitmap, 1 = port is member */
+	u8 vlan_tagged[ADM_NUM_VLANS];	/* bitmap, 1 = tagged member */
+	
+	struct mutex mib_lock;
+	char buf[2048];
+
+	struct mutex reg_mutex;
+
+	/* use abstraction for regops, we want to add gpio support in the future */
+	u16 (*read)(struct adm6996_priv *priv, enum admreg reg);
+	void (*write)(struct adm6996_priv *priv, enum admreg reg, u16 val);
+};
+
+#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev)
+#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv)
+
+#define MIB_DESC(_o, _n)	\
+	{			\
+		.offset = (_o),	\
+		.name = (_n),	\
+	}
+
+static const struct adm6996_mib_desc adm6996_mibs[] = {
+	MIB_DESC(ADM_CL0, "RxPacket"),
+	MIB_DESC(ADM_CL6, "RxByte"),
+	MIB_DESC(ADM_CL12, "TxPacket"),
+	MIB_DESC(ADM_CL18, "TxByte"),
+	MIB_DESC(ADM_CL24, "Collision"),
+	MIB_DESC(ADM_CL30, "Error"),
+};
+
+static inline u16
+r16(struct adm6996_priv *priv, enum admreg reg)
+{
+	return priv->read(priv, reg);
+}
+
+static inline void
+w16(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+	priv->write(priv, reg, val);
+}
+
+/* Minimum timing constants */
+#define EECK_EDGE_TIME  3   /* 3us - max(adm 2.5us, 93c 1us) */
+#define EEDI_SETUP_TIME 1   /* 1us - max(adm 10ns, 93c 400ns) */
+#define EECS_SETUP_TIME 1   /* 1us - max(adm no, 93c 200ns) */
+
+static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits)
+{
+	int i, len = (bits + 7) / 8;
+	u8 mask;
+
+	gpio_set_value(priv->eecs, cs);
+	udelay(EECK_EDGE_TIME);
+
+	/* Byte assemble from MSB to LSB */
+	for (i = 0; i < len; i++) {
+		/* Bit bang from MSB to LSB */
+		for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) {
+			/* Clock low */
+			gpio_set_value(priv->eesk, 0);
+			udelay(EECK_EDGE_TIME);
+
+			/* Output on rising edge */
+			gpio_set_value(priv->eedi, (mask & buf[i]));
+			udelay(EEDI_SETUP_TIME);
+
+			/* Clock high */
+			gpio_set_value(priv->eesk, 1);
+			udelay(EECK_EDGE_TIME);
+		}
+	}
+
+	/* Clock low */
+	gpio_set_value(priv->eesk, 0);
+	udelay(EECK_EDGE_TIME);
+
+	if (cs)
+		gpio_set_value(priv->eecs, 0);
+}
+
+static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits)
+{
+	int i, len = (bits + 7) / 8;
+	u8 mask;
+
+	gpio_set_value(priv->eecs, cs);
+	udelay(EECK_EDGE_TIME);
+
+	/* Byte assemble from MSB to LSB */
+	for (i = 0; i < len; i++) {
+		u8 byte;
+
+		/* Bit bang from MSB to LSB */
+		for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) {
+			u8 gp;
+
+			/* Clock low */
+			gpio_set_value(priv->eesk, 0);
+			udelay(EECK_EDGE_TIME);
+
+			/* Input on rising edge */
+			gp = gpio_get_value(priv->eedi);
+			if (gp)
+				byte |= mask;
+
+			/* Clock high */
+			gpio_set_value(priv->eesk, 1);
+			udelay(EECK_EDGE_TIME);
+		}
+
+		*buf++ = byte;
+	}
+
+	/* Clock low */
+	gpio_set_value(priv->eesk, 0);
+	udelay(EECK_EDGE_TIME);
+
+	if (cs)
+		gpio_set_value(priv->eecs, 0);
+}
+
+/* Advance clock(s) */
+static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks)
+{
+	int i;
+	for (i = 0; i < clocks; i++) {
+		/* Clock high */
+		gpio_set_value(priv->eesk, 1);
+		udelay(EECK_EDGE_TIME);
+
+		/* Clock low */
+		gpio_set_value(priv->eesk, 0);
+		udelay(EECK_EDGE_TIME);
+	}
+}
+
+static u16
+adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg)
+{
+	/* cmd: 01 10 T DD R RRRRRR */
+	u8 bits[6] = {
+		0xFF, 0xFF, 0xFF, 0xFF,
+		(0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6),
+		((reg&63)<<2)
+	};
+
+	u8 rbits[4];
+
+	/* Enable GPIO outputs with all pins to 0 */
+	gpio_direction_output(priv->eecs, 0);
+	gpio_direction_output(priv->eesk, 0);
+	gpio_direction_output(priv->eedi, 0);
+
+	adm6996_gpio_write(priv, 0, bits, 46);
+	gpio_direction_input(priv->eedi);
+	adm6996_gpio_adclk(priv, 2);
+	adm6996_gpio_read(priv, 0, rbits, 32);
+
+	/* Extra clock(s) required per datasheet */
+	adm6996_gpio_adclk(priv, 2);
+
+	/* Disable GPIO outputs */
+	gpio_direction_input(priv->eecs);
+	gpio_direction_input(priv->eesk);
+
+	 /* EEPROM has 16-bit registers, but pumps out two registers in one request */
+	return (reg & 0x01 ?  (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3]));
+}
+
+/* Write chip configuration register */
+/* Follow 93c66 timing and chip's min EEPROM timing requirement */
+static void
+adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+	/* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */
+	u8 bits[4] = {
+		(0x05 << 5) | (reg >> 3),
+		(reg << 5) | (u8)(val >> 11),
+		(u8)(val >> 3),
+		(u8)(val << 5)
+	};
+
+	/* Enable GPIO outputs with all pins to 0 */
+	gpio_direction_output(priv->eecs, 0);
+	gpio_direction_output(priv->eesk, 0);
+	gpio_direction_output(priv->eedi, 0);
+
+	/* Write cmd. Total 27 bits */
+	adm6996_gpio_write(priv, 1, bits, 27);
+
+	/* Extra clock(s) required per datasheet */
+	adm6996_gpio_adclk(priv, 2);
+
+	/* Disable GPIO outputs */
+	gpio_direction_input(priv->eecs);
+	gpio_direction_input(priv->eesk);
+	gpio_direction_input(priv->eedi);
+}
+
+static u16
+adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg)
+{
+	struct phy_device *phydev = priv->priv;
+	struct mii_bus *bus = phydev->bus;
+
+	return bus->read(bus, PHYADDR(reg));
+}
+
+static void
+adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+	struct phy_device *phydev = priv->priv;
+	struct mii_bus *bus = phydev->bus;
+
+	bus->write(bus, PHYADDR(reg), val);
+}
+
+static int
+adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	if (val->value.i > 1)
+		return -EINVAL;
+
+	priv->enable_vlan = val->value.i;
+
+	return 0;
+};
+
+static int
+adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	val->value.i = priv->enable_vlan;
+
+	return 0;
+};
+
+#ifdef DEBUG
+
+static int
+adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	if (val->value.i > 1023)
+		return -EINVAL;
+
+	priv->addr = val->value.i;
+
+	return 0;
+};
+
+static int
+adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	val->value.i = priv->addr;
+
+	return 0;
+};
+
+static int
+adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	if (val->value.i > 65535)
+		return -EINVAL;
+
+	w16(priv, priv->addr, val->value.i);
+
+	return 0;
+};
+
+static int
+adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	val->value.i = r16(priv, priv->addr);
+
+	return 0;
+};
+
+#endif /* def DEBUG */
+
+static int
+adm6996_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("set_pvid port %d vlan %d\n", port, vlan);
+
+	if (vlan > ADM_VLAN_MAX_ID)
+		return -EINVAL;
+
+	priv->pvid[port] = vlan;
+
+	return 0;
+}
+
+static int
+adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("get_pvid port %d\n", port);
+	*vlan = priv->pvid[port];
+
+	return 0;
+}
+
+static int
+adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("set_vid port %d vid %d\n", val->port_vlan, val->value.i);
+
+	if (val->value.i > ADM_VLAN_MAX_ID)
+		return -EINVAL;
+
+	priv->vlan_id[val->port_vlan] = val->value.i;
+
+	return 0;
+};
+
+static int
+adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("get_vid port %d\n", val->port_vlan);
+
+	val->value.i = priv->vlan_id[val->port_vlan];
+
+	return 0;
+};
+
+static int
+adm6996_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	u8 ports = priv->vlan_table[val->port_vlan];
+	u8 tagged = priv->vlan_tagged[val->port_vlan];
+	int i;
+
+	pr_devel("get_ports port_vlan %d\n", val->port_vlan);
+
+	val->len = 0;
+
+	for (i = 0; i < ADM_NUM_PORTS; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+
+	return 0;
+};
+
+static int
+adm6996_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	u8 *ports = &priv->vlan_table[val->port_vlan];
+	u8 *tagged = &priv->vlan_tagged[val->port_vlan];
+	int i;
+
+	pr_devel("set_ports port_vlan %d ports", val->port_vlan);
+
+	*ports = 0;
+	*tagged = 0;
+
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+#ifdef DEBUG
+		pr_cont(" %d%s", p->id,
+		       ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" :
+			""));
+#endif
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+			*tagged |= (1 << p->id);
+			priv->tagged_ports |= (1 << p->id);
+		}
+
+		*ports |= (1 << p->id);
+	}
+
+#ifdef DEBUG
+	pr_cont("\n");
+#endif
+
+	return 0;
+};
+
+/*
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_enable_vlan(struct adm6996_priv *priv)
+{
+	u16 reg;
+
+	reg = r16(priv, ADM_OTBE_P2_PVID);
+	reg &= ~(ADM_OTBE_MASK);
+	w16(priv, ADM_OTBE_P2_PVID, reg);
+	reg = r16(priv, ADM_IFNTE);
+	reg &= ~(ADM_IFNTE_MASK);
+	w16(priv, ADM_IFNTE, reg);
+	reg = r16(priv, ADM_VID_CHECK);
+	reg |= ADM_VID_CHECK_MASK;
+	w16(priv, ADM_VID_CHECK, reg);
+	reg = r16(priv, ADM_SYSC0);
+	reg |= ADM_NTTE;
+	reg &= ~(ADM_RVID1);
+	w16(priv, ADM_SYSC0, reg);
+	reg = r16(priv, ADM_SYSC3);
+	reg |= ADM_TBV;
+	w16(priv, ADM_SYSC3, reg);
+}
+
+static void
+adm6996_enable_vlan_6996l(struct adm6996_priv *priv)
+{
+	u16 reg;
+
+	reg = r16(priv, ADM_SYSC3);
+	reg |= ADM_TBV;
+	reg |= ADM_MAC_CLONE;
+	w16(priv, ADM_SYSC3, reg);
+}
+
+/*
+ * Disable VLANs
+ *
+ * Sets VLAN mapping for port-based VLAN with all ports connected to
+ * eachother (this is also the power-on default).
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_disable_vlan(struct adm6996_priv *priv)
+{
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		reg = ADM_VLAN_FILT_MEMBER_MASK;
+		w16(priv, ADM_VLAN_FILT_L(i), reg);
+		reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1);
+		w16(priv, ADM_VLAN_FILT_H(i), reg);
+	}
+
+	reg = r16(priv, ADM_OTBE_P2_PVID);
+	reg |= ADM_OTBE_MASK;
+	w16(priv, ADM_OTBE_P2_PVID, reg);
+	reg = r16(priv, ADM_IFNTE);
+	reg |= ADM_IFNTE_MASK;
+	w16(priv, ADM_IFNTE, reg);
+	reg = r16(priv, ADM_VID_CHECK);
+	reg &= ~(ADM_VID_CHECK_MASK);
+	w16(priv, ADM_VID_CHECK, reg);
+	reg = r16(priv, ADM_SYSC0);
+	reg &= ~(ADM_NTTE);
+	reg |= ADM_RVID1;
+	w16(priv, ADM_SYSC0, reg);
+	reg = r16(priv, ADM_SYSC3);
+	reg &= ~(ADM_TBV);
+	w16(priv, ADM_SYSC3, reg);
+}
+
+/*
+ * Disable VLANs
+ *
+ * Sets VLAN mapping for port-based VLAN with all ports connected to
+ * eachother (this is also the power-on default).
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_disable_vlan_6996l(struct adm6996_priv *priv)
+{
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		w16(priv, ADM_VLAN_MAP(i), 0);
+	}
+
+	reg = r16(priv, ADM_SYSC3);
+	reg &= ~(ADM_TBV);
+	reg &= ~(ADM_MAC_CLONE);
+	w16(priv, ADM_SYSC3, reg);
+}
+
+/*
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_apply_port_pvids(struct adm6996_priv *priv)
+{
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_PORTS; i++) {
+		reg = r16(priv, adm_portcfg[i]);
+		reg &= ~(ADM_PORTCFG_PVID_MASK);
+		reg |= ADM_PORTCFG_PVID(priv->pvid[i]);
+		if (priv->model == ADM6996L) {
+			if (priv->tagged_ports & (1 << i))
+				reg |= (1 << 4);
+			else
+				reg &= ~(1 << 4);
+		}
+		w16(priv, adm_portcfg[i], reg);
+	}
+
+	w16(priv, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0]));
+	w16(priv, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1]));
+	reg = r16(priv, ADM_OTBE_P2_PVID);
+	reg &= ~(ADM_P2_PVID_MASK);
+	reg |= ADM_P2_PVID_VAL(priv->pvid[2]);
+	w16(priv, ADM_OTBE_P2_PVID, reg);
+	reg = ADM_P3_PVID_VAL(priv->pvid[3]);
+	reg |= ADM_P4_PVID_VAL(priv->pvid[4]);
+	w16(priv, ADM_P3_P4_PVID, reg);
+	reg = r16(priv, ADM_P5_PVID);
+	reg &= ~(ADM_P2_PVID_MASK);
+	reg |= ADM_P5_PVID_VAL(priv->pvid[5]);
+	w16(priv, ADM_P5_PVID, reg);
+}
+
+/*
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_apply_vlan_filters(struct adm6996_priv *priv)
+{
+	u8 ports, tagged;
+	u16 vid, reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		vid = priv->vlan_id[i];
+		ports = priv->vlan_table[i];
+		tagged = priv->vlan_tagged[i];
+
+		if (ports == 0) {
+			/* Disable VLAN entry */
+			w16(priv, ADM_VLAN_FILT_H(i), 0);
+			w16(priv, ADM_VLAN_FILT_L(i), 0);
+			continue;
+		}
+
+		reg = ADM_VLAN_FILT_MEMBER(ports);
+		reg |= ADM_VLAN_FILT_TAGGED(tagged);
+		w16(priv, ADM_VLAN_FILT_L(i), reg);
+		reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid);
+		w16(priv, ADM_VLAN_FILT_H(i), reg);
+	}
+}
+
+static void
+adm6996_apply_vlan_filters_6996l(struct adm6996_priv *priv)
+{
+	u8 ports;
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		ports = priv->vlan_table[i];
+
+		if (ports == 0) {
+			/* Disable VLAN entry */
+			w16(priv, ADM_VLAN_MAP(i), 0);
+			continue;
+		} else {
+			reg = ADM_VLAN_FILT(ports);
+			w16(priv, ADM_VLAN_MAP(i), reg);
+		}
+	}
+}
+
+static int
+adm6996_hw_apply(struct switch_dev *dev)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("hw_apply\n");
+
+	mutex_lock(&priv->reg_mutex);
+
+	if (!priv->enable_vlan) {
+		if (priv->vlan_enabled) {
+			if (priv->model == ADM6996L)
+				adm6996_disable_vlan_6996l(priv);
+			else
+				adm6996_disable_vlan(priv);
+			priv->vlan_enabled = 0;
+		}
+		goto out;
+	}
+
+	if (!priv->vlan_enabled) {
+		if (priv->model == ADM6996L)
+			adm6996_enable_vlan_6996l(priv);
+		else
+			adm6996_enable_vlan(priv);
+		priv->vlan_enabled = 1;
+	}
+
+	adm6996_apply_port_pvids(priv);
+	if (priv->model == ADM6996L)
+		adm6996_apply_vlan_filters_6996l(priv);
+	else
+		adm6996_apply_vlan_filters(priv);
+
+out:
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+/*
+ * Reset the switch
+ *
+ * The ADM6996 can't do a software-initiated reset, so we just initialise the
+ * registers we support in this driver.
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_perform_reset (struct adm6996_priv *priv)
+{
+	int i;
+
+	/* initialize port and vlan settings */
+	for (i = 0; i < ADM_NUM_PORTS - 1; i++) {
+		w16(priv, adm_portcfg[i], ADM_PORTCFG_INIT |
+			ADM_PORTCFG_PVID(0));
+	}
+	w16(priv, adm_portcfg[5], ADM_PORTCFG_CPU);
+
+	if (priv->model == ADM6996M || priv->model == ADM6996FC) {
+		/* reset all PHY ports */
+		for (i = 0; i < ADM_PHY_PORTS; i++) {
+			w16(priv, ADM_PHY_PORT(i), ADM_PHYCFG_INIT);
+		}
+	}
+
+	priv->enable_vlan = 0;
+	priv->vlan_enabled = 0;
+
+	for (i = 0; i < ADM_NUM_PORTS; i++) {
+		priv->pvid[i] = 0;
+	}
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		priv->vlan_id[i] = i;
+		priv->vlan_table[i] = 0;
+		priv->vlan_tagged[i] = 0;
+	}
+
+	if (priv->model == ADM6996M) {
+		/* Clear VLAN priority map so prio's are unused */
+		w16 (priv, ADM_VLAN_PRIOMAP, 0);
+
+		adm6996_disable_vlan(priv);
+		adm6996_apply_port_pvids(priv);
+	} else if (priv->model == ADM6996L) {
+		/* Clear VLAN priority map so prio's are unused */
+		w16 (priv, ADM_VLAN_PRIOMAP, 0);
+
+		adm6996_disable_vlan_6996l(priv);
+		adm6996_apply_port_pvids(priv);
+	}
+}
+
+static int
+adm6996_reset_switch(struct switch_dev *dev)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("reset\n");
+
+	mutex_lock(&priv->reg_mutex);
+	adm6996_perform_reset (priv);
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+static int
+adm6996_get_port_link(struct switch_dev *dev, int port,
+		struct switch_port_link *link)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	
+	u16 reg = 0;
+	
+	if (port >= ADM_NUM_PORTS)
+		return -EINVAL;
+	
+	switch (port) {
+	case 0:
+		reg = r16(priv, ADM_PS0);
+		break;
+	case 1:
+		reg = r16(priv, ADM_PS0);
+		reg = reg >> 8;
+		break;
+	case 2:
+		reg = r16(priv, ADM_PS1);
+		break;
+	case 3:
+		reg = r16(priv, ADM_PS1);
+		reg = reg >> 8;
+		break;
+	case 4:
+		reg = r16(priv, ADM_PS1);
+		reg = reg >> 12;
+		break;
+	case 5:
+		reg = r16(priv, ADM_PS2);
+		/* Bits 0, 1, 3 and 4. */
+		reg = (reg & 3) | ((reg & 24) >> 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	link->link = reg & ADM_PS_LS;
+	if (!link->link)
+		return 0;
+	link->aneg = true;
+	link->duplex = reg & ADM_PS_DS;
+	link->tx_flow = reg & ADM_PS_FCS;
+	link->rx_flow = reg & ADM_PS_FCS;
+	if (reg & ADM_PS_SS)
+		link->speed = SWITCH_PORT_SPEED_100;
+	else
+		link->speed = SWITCH_PORT_SPEED_10;
+
+	return 0;
+}
+
+static int
+adm6996_sw_get_port_mib(struct switch_dev *dev,
+		       const struct switch_attr *attr,
+		       struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	int port;
+	char *buf = priv->buf;
+	int i, len = 0;
+	u32 reg = 0;
+
+	port = val->port_vlan;
+	if (port >= ADM_NUM_PORTS)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+
+	len += snprintf(buf + len, sizeof(priv->buf) - len,
+			"Port %d MIB counters\n",
+			port);
+
+	for (i = 0; i < ARRAY_SIZE(adm6996_mibs); i++) {
+		reg = r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port));
+		reg += r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port) + 1) << 16;
+		len += snprintf(buf + len, sizeof(priv->buf) - len,
+				"%-12s: %u\n",
+				adm6996_mibs[i].name,
+				reg);
+	}
+
+	mutex_unlock(&priv->mib_lock);
+
+	val->value.s = buf;
+	val->len = len;
+
+	return 0;
+}
+
+static struct switch_attr adm6996_globals[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "enable_vlan",
+	 .description = "Enable VLANs",
+	 .set = adm6996_set_enable_vlan,
+	 .get = adm6996_get_enable_vlan,
+	},
+#ifdef DEBUG
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "addr",
+	 .description =
+	 "Direct register access: set register address (0 - 1023)",
+	 .set = adm6996_set_addr,
+	 .get = adm6996_get_addr,
+	 },
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "data",
+	 .description =
+	 "Direct register access: read/write to register (0 - 65535)",
+	 .set = adm6996_set_data,
+	 .get = adm6996_get_data,
+	 },
+#endif /* def DEBUG */
+};
+
+static struct switch_attr adm6996_port[] = {
+	{
+	 .type = SWITCH_TYPE_STRING,
+	 .name = "mib",
+	 .description = "Get port's MIB counters",
+	 .set = NULL,
+	 .get = adm6996_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr adm6996_vlan[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "vid",
+	 .description = "VLAN ID",
+	 .set = adm6996_set_vid,
+	 .get = adm6996_get_vid,
+	 },
+};
+
+static struct switch_dev_ops adm6996_ops = {
+	.attr_global = {
+			.attr = adm6996_globals,
+			.n_attr = ARRAY_SIZE(adm6996_globals),
+			},
+	.attr_port = {
+		      .attr = adm6996_port,
+		      .n_attr = ARRAY_SIZE(adm6996_port),
+		      },
+	.attr_vlan = {
+		      .attr = adm6996_vlan,
+		      .n_attr = ARRAY_SIZE(adm6996_vlan),
+		      },
+	.get_port_pvid = adm6996_get_pvid,
+	.set_port_pvid = adm6996_set_pvid,
+	.get_vlan_ports = adm6996_get_ports,
+	.set_vlan_ports = adm6996_set_ports,
+	.apply_config = adm6996_hw_apply,
+	.reset_switch = adm6996_reset_switch,
+	.get_port_link = adm6996_get_port_link,
+};
+
+static int adm6996_switch_init(struct adm6996_priv *priv, const char *alias, struct net_device *netdev)
+{
+	struct switch_dev *swdev;
+	u16 test, old;
+
+	if (!priv->model) {
+		/* Detect type of chip */
+		old = r16(priv, ADM_VID_CHECK);
+		test = old ^ (1 << 12);
+		w16(priv, ADM_VID_CHECK, test);
+		test ^= r16(priv, ADM_VID_CHECK);
+		if (test & (1 << 12)) {
+			/* 
+			 * Bit 12 of this register is read-only. 
+			 * This is the FC model. 
+			 */
+			priv->model = ADM6996FC;
+		} else {
+			/* Bit 12 is read-write. This is the M model. */
+			priv->model = ADM6996M;
+			w16(priv, ADM_VID_CHECK, old);
+		}
+	}
+
+	swdev = &priv->dev;
+	swdev->name = (adm6996_model_name[priv->model]);
+	swdev->cpu_port = ADM_CPU_PORT;
+	swdev->ports = ADM_NUM_PORTS;
+	swdev->vlans = ADM_NUM_VLANS;
+	swdev->ops = &adm6996_ops;
+	swdev->alias = alias;
+
+	/* The ADM6996L connected through GPIOs does not support any switch
+	   status calls */
+	if (priv->model == ADM6996L) {
+		adm6996_ops.attr_port.n_attr = 0;
+		adm6996_ops.get_port_link = NULL;
+	}
+
+	pr_info ("%s: %s model PHY found.\n", alias, swdev->name);
+
+	mutex_lock(&priv->reg_mutex);
+	adm6996_perform_reset (priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	if (priv->model == ADM6996M || priv->model == ADM6996L) {
+		return register_switch(swdev, netdev);
+	}
+
+	return -ENODEV;
+}
+
+static int adm6996_config_init(struct phy_device *pdev)
+{
+	struct adm6996_priv *priv;
+	int ret;
+
+	pdev->supported = ADVERTISED_100baseT_Full;
+	pdev->advertising = ADVERTISED_100baseT_Full;
+
+	if (pdev->addr != 0) {
+		pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n"
+				, pdev->attached_dev->name, pdev->addr);
+		return 0;
+	}
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->reg_mutex);
+	mutex_init(&priv->mib_lock);
+	priv->priv = pdev;
+	priv->read = adm6996_read_mii_reg;
+	priv->write = adm6996_write_mii_reg;
+
+	ret = adm6996_switch_init(priv, pdev->attached_dev->name, pdev->attached_dev);
+	if (ret < 0)
+		return ret;
+
+	pdev->priv = priv;
+
+	return 0;
+}
+
+/*
+ * Warning: phydev->priv is NULL if phydev->addr != 0
+ */
+static int adm6996_read_status(struct phy_device *phydev)
+{
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+
+	phydev->state = PHY_RUNNING;
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+/*
+ * Warning: phydev->priv is NULL if phydev->addr != 0
+ */
+static int adm6996_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int adm6996_fixup(struct phy_device *dev)
+{
+	struct mii_bus *bus = dev->bus;
+	u16 reg;
+
+	/* Our custom registers are at PHY addresses 0-10. Claim those. */
+	if (dev->addr > 10)
+		return 0;
+
+	/* look for the switch on the bus */
+	reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK;
+	if (reg != ADM_SIG0_VAL)
+		return 0;
+
+	reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK;
+	if (reg != ADM_SIG1_VAL)
+		return 0;
+
+	dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL;
+
+	return 0;
+}
+
+static int adm6996_probe(struct phy_device *pdev)
+{
+	return 0;
+}
+
+static void adm6996_remove(struct phy_device *pdev)
+{
+	struct adm6996_priv *priv = phy_to_adm(pdev);
+
+	if (priv && (priv->model == ADM6996M || priv->model == ADM6996L))
+		unregister_switch(&priv->dev);
+}
+
+static int adm6996_soft_reset(struct phy_device *phydev)
+{
+	/* we don't need an extra reset */
+	return 0;
+}
+
+static struct phy_driver adm6996_phy_driver = {
+	.name		= "Infineon ADM6996",
+	.phy_id		= (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL,
+	.phy_id_mask	= 0xffffffff,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= adm6996_probe,
+	.remove		= adm6996_remove,
+	.config_init	= &adm6996_config_init,
+	.config_aneg	= &adm6996_config_aneg,
+	.read_status	= &adm6996_read_status,
+	.soft_reset	= adm6996_soft_reset,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int adm6996_gpio_probe(struct platform_device *pdev)
+{
+	struct adm6996_gpio_platform_data *pdata = pdev->dev.platform_data;
+	struct adm6996_priv *priv;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+				  
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->reg_mutex);
+	mutex_init(&priv->mib_lock);
+
+	priv->eecs = pdata->eecs;
+	priv->eedi = pdata->eedi;
+	priv->eerc = pdata->eerc;
+	priv->eesk = pdata->eesk;
+
+	priv->model = pdata->model;
+	priv->read = adm6996_read_gpio_reg;
+	priv->write = adm6996_write_gpio_reg;
+
+	ret = devm_gpio_request(&pdev->dev, priv->eecs, "adm_eecs");
+	if (ret)
+		return ret;
+	ret = devm_gpio_request(&pdev->dev, priv->eedi, "adm_eedi");
+	if (ret)
+		return ret;
+	ret = devm_gpio_request(&pdev->dev, priv->eerc, "adm_eerc");
+	if (ret)
+		return ret;
+	ret = devm_gpio_request(&pdev->dev, priv->eesk, "adm_eesk");
+	if (ret)
+		return ret;
+
+	ret = adm6996_switch_init(priv, dev_name(&pdev->dev), NULL);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+}
+
+static int adm6996_gpio_remove(struct platform_device *pdev)
+{
+	struct adm6996_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv && (priv->model == ADM6996M || priv->model == ADM6996L))
+		unregister_switch(&priv->dev);
+
+	return 0;
+}
+
+static struct platform_driver adm6996_gpio_driver = {
+	.probe = adm6996_gpio_probe,
+	.remove = adm6996_gpio_remove,
+	.driver = {
+		.name = "adm6996_gpio",
+	},
+};
+
+static int __init adm6996_init(void)
+{
+	int err;
+
+	phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup);
+	err =  phy_driver_register(&adm6996_phy_driver);
+	if (err)
+		return err;
+
+	err = platform_driver_register(&adm6996_gpio_driver);
+	if (err)
+		phy_driver_unregister(&adm6996_phy_driver);
+
+	return err;
+}
+
+static void __exit adm6996_exit(void)
+{
+	platform_driver_unregister(&adm6996_gpio_driver);
+	phy_driver_unregister(&adm6996_phy_driver);
+}
+
+module_init(adm6996_init);
+module_exit(adm6996_exit);
diff --git a/target/linux/generic/files/drivers/net/phy/adm6996.h b/target/linux/generic/files/drivers/net/phy/adm6996.h
new file mode 100644
index 0000000000..6fd460a465
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/adm6996.h
@@ -0,0 +1,186 @@
+/*
+ * ADM6996 switch driver
+ *
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ * Copyright (c) 2010,2011 Peter Lebbing <peter@digitalbrains.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __ADM6996_H
+#define __ADM6996_H
+
+/*
+ * ADM_PHY_PORTS: Number of ports with a PHY.
+ * We only control ports 0 to 3, because if 4 is connected, it is most likely
+ * not connected to the switch but to a separate MII and MAC for the WAN port.
+ */
+#define ADM_PHY_PORTS	4
+#define ADM_NUM_PORTS	6
+#define ADM_CPU_PORT	5
+
+#define ADM_NUM_VLANS 16
+#define ADM_VLAN_MAX_ID 4094
+
+enum admreg {
+	ADM_EEPROM_BASE		= 0x0,
+		ADM_P0_CFG		= ADM_EEPROM_BASE + 1,
+		ADM_P1_CFG		= ADM_EEPROM_BASE + 3,
+		ADM_P2_CFG		= ADM_EEPROM_BASE + 5,
+		ADM_P3_CFG		= ADM_EEPROM_BASE + 7,
+		ADM_P4_CFG		= ADM_EEPROM_BASE + 8,
+		ADM_P5_CFG		= ADM_EEPROM_BASE + 9,
+		ADM_SYSC0		= ADM_EEPROM_BASE + 0xa,
+		ADM_VLAN_PRIOMAP	= ADM_EEPROM_BASE + 0xe,
+		ADM_SYSC3		= ADM_EEPROM_BASE + 0x11,
+		/* Input Force No Tag Enable */
+		ADM_IFNTE		= ADM_EEPROM_BASE + 0x20,
+		ADM_VID_CHECK		= ADM_EEPROM_BASE + 0x26,
+		ADM_P0_PVID		= ADM_EEPROM_BASE + 0x28,
+		ADM_P1_PVID		= ADM_EEPROM_BASE + 0x29,
+		/* Output Tag Bypass Enable and P2 PVID */
+		ADM_OTBE_P2_PVID	= ADM_EEPROM_BASE + 0x2a,
+		ADM_P3_P4_PVID		= ADM_EEPROM_BASE + 0x2b,
+		ADM_P5_PVID		= ADM_EEPROM_BASE + 0x2c,
+	ADM_EEPROM_EXT_BASE	= 0x40,
+#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n))
+#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n))
+#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n)
+	ADM_COUNTER_BASE	= 0xa0,
+		ADM_SIG0		= ADM_COUNTER_BASE + 0,
+		ADM_SIG1		= ADM_COUNTER_BASE + 1,
+		ADM_PS0		= ADM_COUNTER_BASE + 2,
+		ADM_PS1		= ADM_COUNTER_BASE + 3,
+		ADM_PS2		= ADM_COUNTER_BASE + 4,
+		ADM_CL0		= ADM_COUNTER_BASE + 8, /* RxPacket */
+		ADM_CL6		= ADM_COUNTER_BASE + 0x1a, /* RxByte */
+		ADM_CL12		= ADM_COUNTER_BASE + 0x2c, /* TxPacket */
+		ADM_CL18		= ADM_COUNTER_BASE + 0x3e, /* TxByte */
+		ADM_CL24		= ADM_COUNTER_BASE + 0x50, /* Coll */
+		ADM_CL30		= ADM_COUNTER_BASE + 0x62, /* Err */
+#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2)
+	ADM_PHY_BASE		= 0x200,
+#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n))
+};
+
+/* Chip identification patterns */
+#define	ADM_SIG0_MASK	0xffff
+#define ADM_SIG0_VAL	0x1023
+#define ADM_SIG1_MASK	0xffff
+#define ADM_SIG1_VAL	0x0007
+
+enum {
+	ADM_PHYCFG_COLTST     = (1 << 7),	/* Enable collision test */
+	ADM_PHYCFG_DPLX       = (1 << 8),	/* Enable full duplex */
+	ADM_PHYCFG_ANEN_RST   = (1 << 9),	/* Restart auto negotiation (self clear) */
+	ADM_PHYCFG_ISO        = (1 << 10),	/* Isolate PHY */
+	ADM_PHYCFG_PDN        = (1 << 11),	/* Power down PHY */
+	ADM_PHYCFG_ANEN       = (1 << 12),	/* Enable auto negotiation */
+	ADM_PHYCFG_SPEED_100  = (1 << 13),	/* Enable 100 Mbit/s */
+	ADM_PHYCFG_LPBK       = (1 << 14),	/* Enable loopback operation */
+	ADM_PHYCFG_RST        = (1 << 15),	/* Reset the port (self clear) */
+	ADM_PHYCFG_INIT = (
+		ADM_PHYCFG_RST |
+		ADM_PHYCFG_SPEED_100 |
+		ADM_PHYCFG_ANEN |
+		ADM_PHYCFG_ANEN_RST
+	)
+};
+
+enum {
+	ADM_PORTCFG_FC        = (1 << 0),	/* Enable 802.x flow control */
+	ADM_PORTCFG_AN        = (1 << 1),	/* Enable auto-negotiation */
+	ADM_PORTCFG_SPEED_100 = (1 << 2),	/* Enable 100 Mbit/s */
+	ADM_PORTCFG_DPLX      = (1 << 3),	/* Enable full duplex */
+	ADM_PORTCFG_OT        = (1 << 4),	/* Output tagged packets */
+	ADM_PORTCFG_PD        = (1 << 5),	/* Port disable */
+	ADM_PORTCFG_TV_PRIO   = (1 << 6),	/* 0 = VLAN based priority
+	                                 	 * 1 = TOS based priority */
+	ADM_PORTCFG_PPE       = (1 << 7),	/* Port based priority enable */
+	ADM_PORTCFG_PP_S      = (1 << 8),	/* Port based priority, 2 bits */
+	ADM_PORTCFG_PVID_BASE = (1 << 10),	/* Primary VLAN id, 4 bits */
+	ADM_PORTCFG_FSE	      = (1 << 14),	/* Fx select enable */
+	ADM_PORTCFG_CAM       = (1 << 15),	/* Crossover Auto MDIX */
+
+	ADM_PORTCFG_INIT = (
+		ADM_PORTCFG_FC |
+		ADM_PORTCFG_AN |
+		ADM_PORTCFG_SPEED_100 |
+		ADM_PORTCFG_DPLX |
+		ADM_PORTCFG_CAM
+	),
+	ADM_PORTCFG_CPU = (
+		ADM_PORTCFG_FC |
+		ADM_PORTCFG_SPEED_100 |
+		ADM_PORTCFG_OT |
+		ADM_PORTCFG_DPLX
+	),
+};
+
+#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8)
+#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10)
+#define ADM_PORTCFG_PVID_MASK (0xf << 10)
+
+#define ADM_IFNTE_MASK (0x3f << 9)
+#define ADM_VID_CHECK_MASK (0x3f << 6)
+
+#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8)
+#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P2_PVID_MASK 0xff
+
+#define ADM_OTBE(n) (((n) & 0x3f) << 8)
+#define ADM_OTBE_MASK (0x3f << 8)
+
+/* ADM_SYSC0 */
+enum {
+	ADM_NTTE	= (1 << 2),	/* New Tag Transmit Enable */
+	ADM_RVID1	= (1 << 8)	/* Replace VLAN ID 1 */
+};
+
+/* Tag Based VLAN in ADM_SYSC3 */
+#define ADM_MAC_CLONE	BIT(4)
+#define ADM_TBV		BIT(5)
+
+static const u8 adm_portcfg[] = {
+	[0] = ADM_P0_CFG,
+	[1] = ADM_P1_CFG,
+	[2] = ADM_P2_CFG,
+	[3] = ADM_P3_CFG,
+	[4] = ADM_P4_CFG,
+	[5] = ADM_P5_CFG,
+};
+
+/* Fields in ADM_VLAN_FILT_L(x) */
+#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12)
+#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6)
+#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0)
+#define ADM_VLAN_FILT_MEMBER_MASK 0x3f
+/* Fields in ADM_VLAN_FILT_H(x) */
+#define ADM_VLAN_FILT_VALID (1 << 15)
+#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0)
+
+/* Convert ports to a form for ADM6996L VLAN map */
+#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \
+			((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \
+			((ports & 0x10) << 3) | ((ports & 0x20) << 3))
+
+/* Port status register */
+enum {
+	ADM_PS_LS = (1 << 0),	/* Link status */
+	ADM_PS_SS = (1 << 1),	/* Speed status */
+	ADM_PS_DS = (1 << 2),	/* Duplex status */
+	ADM_PS_FCS = (1 << 3)	/* Flow control status */
+};
+
+/*
+ * Split the register address in phy id and register
+ * it will get combined again by the mdio bus op
+ */
+#define PHYADDR(_reg)	((_reg >> 5) & 0xff), (_reg & 0x1f)
+
+#endif
diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c
new file mode 100644
index 0000000000..746d8e6c3d
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
@@ -0,0 +1,2313 @@
+/*
+ * ar8216.c: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/bitops.h>
+#include <net/genetlink.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/lockdep.h>
+#include <linux/ar8216_platform.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
+
+#include "ar8216.h"
+
+extern const struct ar8xxx_chip ar8327_chip;
+extern const struct ar8xxx_chip ar8337_chip;
+
+#define AR8XXX_MIB_WORK_DELAY	2000 /* msecs */
+
+#define MIB_DESC(_s , _o, _n)	\
+	{			\
+		.size = (_s),	\
+		.offset = (_o),	\
+		.name = (_n),	\
+	}
+
+static const struct ar8xxx_mib_desc ar8216_mibs[] = {
+	MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"),
+	MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"),
+	MIB_DESC(1, AR8216_STATS_RXMULTI, "RxMulti"),
+	MIB_DESC(1, AR8216_STATS_RXFCSERR, "RxFcsErr"),
+	MIB_DESC(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"),
+	MIB_DESC(1, AR8216_STATS_RXRUNT, "RxRunt"),
+	MIB_DESC(1, AR8216_STATS_RXFRAGMENT, "RxFragment"),
+	MIB_DESC(1, AR8216_STATS_RX64BYTE, "Rx64Byte"),
+	MIB_DESC(1, AR8216_STATS_RX128BYTE, "Rx128Byte"),
+	MIB_DESC(1, AR8216_STATS_RX256BYTE, "Rx256Byte"),
+	MIB_DESC(1, AR8216_STATS_RX512BYTE, "Rx512Byte"),
+	MIB_DESC(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"),
+	MIB_DESC(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"),
+	MIB_DESC(1, AR8216_STATS_RXTOOLONG, "RxTooLong"),
+	MIB_DESC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"),
+	MIB_DESC(2, AR8216_STATS_RXBADBYTE, "RxBadByte"),
+	MIB_DESC(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"),
+	MIB_DESC(1, AR8216_STATS_FILTERED, "Filtered"),
+	MIB_DESC(1, AR8216_STATS_TXBROAD, "TxBroad"),
+	MIB_DESC(1, AR8216_STATS_TXPAUSE, "TxPause"),
+	MIB_DESC(1, AR8216_STATS_TXMULTI, "TxMulti"),
+	MIB_DESC(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"),
+	MIB_DESC(1, AR8216_STATS_TX64BYTE, "Tx64Byte"),
+	MIB_DESC(1, AR8216_STATS_TX128BYTE, "Tx128Byte"),
+	MIB_DESC(1, AR8216_STATS_TX256BYTE, "Tx256Byte"),
+	MIB_DESC(1, AR8216_STATS_TX512BYTE, "Tx512Byte"),
+	MIB_DESC(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"),
+	MIB_DESC(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"),
+	MIB_DESC(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"),
+	MIB_DESC(2, AR8216_STATS_TXBYTE, "TxByte"),
+	MIB_DESC(1, AR8216_STATS_TXCOLLISION, "TxCollision"),
+	MIB_DESC(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"),
+	MIB_DESC(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"),
+	MIB_DESC(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"),
+	MIB_DESC(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"),
+	MIB_DESC(1, AR8216_STATS_TXDEFER, "TxDefer"),
+	MIB_DESC(1, AR8216_STATS_TXLATECOL, "TxLateCol"),
+};
+
+const struct ar8xxx_mib_desc ar8236_mibs[39] = {
+	MIB_DESC(1, AR8236_STATS_RXBROAD, "RxBroad"),
+	MIB_DESC(1, AR8236_STATS_RXPAUSE, "RxPause"),
+	MIB_DESC(1, AR8236_STATS_RXMULTI, "RxMulti"),
+	MIB_DESC(1, AR8236_STATS_RXFCSERR, "RxFcsErr"),
+	MIB_DESC(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"),
+	MIB_DESC(1, AR8236_STATS_RXRUNT, "RxRunt"),
+	MIB_DESC(1, AR8236_STATS_RXFRAGMENT, "RxFragment"),
+	MIB_DESC(1, AR8236_STATS_RX64BYTE, "Rx64Byte"),
+	MIB_DESC(1, AR8236_STATS_RX128BYTE, "Rx128Byte"),
+	MIB_DESC(1, AR8236_STATS_RX256BYTE, "Rx256Byte"),
+	MIB_DESC(1, AR8236_STATS_RX512BYTE, "Rx512Byte"),
+	MIB_DESC(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"),
+	MIB_DESC(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"),
+	MIB_DESC(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"),
+	MIB_DESC(1, AR8236_STATS_RXTOOLONG, "RxTooLong"),
+	MIB_DESC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"),
+	MIB_DESC(2, AR8236_STATS_RXBADBYTE, "RxBadByte"),
+	MIB_DESC(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"),
+	MIB_DESC(1, AR8236_STATS_FILTERED, "Filtered"),
+	MIB_DESC(1, AR8236_STATS_TXBROAD, "TxBroad"),
+	MIB_DESC(1, AR8236_STATS_TXPAUSE, "TxPause"),
+	MIB_DESC(1, AR8236_STATS_TXMULTI, "TxMulti"),
+	MIB_DESC(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"),
+	MIB_DESC(1, AR8236_STATS_TX64BYTE, "Tx64Byte"),
+	MIB_DESC(1, AR8236_STATS_TX128BYTE, "Tx128Byte"),
+	MIB_DESC(1, AR8236_STATS_TX256BYTE, "Tx256Byte"),
+	MIB_DESC(1, AR8236_STATS_TX512BYTE, "Tx512Byte"),
+	MIB_DESC(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"),
+	MIB_DESC(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"),
+	MIB_DESC(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"),
+	MIB_DESC(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"),
+	MIB_DESC(2, AR8236_STATS_TXBYTE, "TxByte"),
+	MIB_DESC(1, AR8236_STATS_TXCOLLISION, "TxCollision"),
+	MIB_DESC(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"),
+	MIB_DESC(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"),
+	MIB_DESC(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"),
+	MIB_DESC(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"),
+	MIB_DESC(1, AR8236_STATS_TXDEFER, "TxDefer"),
+	MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"),
+};
+
+static DEFINE_MUTEX(ar8xxx_dev_list_lock);
+static LIST_HEAD(ar8xxx_dev_list);
+
+/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */
+static int
+ar8xxx_phy_poll_reset(struct mii_bus *bus)
+{
+        unsigned int sleep_msecs = 20;
+        int ret, elapsed, i;
+
+        for (elapsed = sleep_msecs; elapsed <= 600;
+	     elapsed += sleep_msecs) {
+                msleep(sleep_msecs);
+                for (i = 0; i < AR8XXX_NUM_PHYS; i++) {
+                        ret = mdiobus_read(bus, i, MII_BMCR);
+                        if (ret < 0)
+				return ret;
+                        if (ret & BMCR_RESET)
+				break;
+                        if (i == AR8XXX_NUM_PHYS - 1) {
+                                usleep_range(1000, 2000);
+                                return 0;
+                        }
+                }
+        }
+        return -ETIMEDOUT;
+}
+
+static int
+ar8xxx_phy_check_aneg(struct phy_device *phydev)
+{
+	int ret;
+
+	if (phydev->autoneg != AUTONEG_ENABLE)
+		return 0;
+	/*
+	 * BMCR_ANENABLE might have been cleared
+	 * by phy_init_hw in certain kernel versions
+	 * therefore check for it
+	 */
+	ret = phy_read(phydev, MII_BMCR);
+	if (ret < 0)
+		return ret;
+	if (ret & BMCR_ANENABLE)
+		return 0;
+
+	dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n");
+	ret |= BMCR_ANENABLE | BMCR_ANRESTART;
+	return phy_write(phydev, MII_BMCR, ret);
+}
+
+void
+ar8xxx_phy_init(struct ar8xxx_priv *priv)
+{
+	int i;
+	struct mii_bus *bus;
+
+	bus = priv->mii_bus;
+	for (i = 0; i < AR8XXX_NUM_PHYS; i++) {
+		if (priv->chip->phy_fixup)
+			priv->chip->phy_fixup(priv, i);
+
+		/* initialize the port itself */
+		mdiobus_write(bus, i, MII_ADVERTISE,
+			ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+		if (ar8xxx_has_gige(priv))
+			mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
+		mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
+	}
+
+	ar8xxx_phy_poll_reset(bus);
+}
+
+u32
+ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 lo, hi;
+
+	lo = bus->read(bus, phy_id, regnum);
+	hi = bus->read(bus, phy_id, regnum + 1);
+
+	return (hi << 16) | lo;
+}
+
+void
+ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 lo, hi;
+
+	lo = val & 0xffff;
+	hi = (u16) (val >> 16);
+
+	if (priv->chip->mii_lo_first)
+	{
+		bus->write(bus, phy_id, regnum, lo);
+		bus->write(bus, phy_id, regnum + 1, hi);
+	} else {
+		bus->write(bus, phy_id, regnum + 1, hi);
+		bus->write(bus, phy_id, regnum, lo);
+	}
+}
+
+u32
+ar8xxx_read(struct ar8xxx_priv *priv, int reg)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r1, r2, page;
+	u32 val;
+
+	split_addr((u32) reg, &r1, &r2, &page);
+
+	mutex_lock(&bus->mdio_lock);
+
+	bus->write(bus, 0x18, 0, page);
+	wait_for_page_switch();
+	val = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
+
+	mutex_unlock(&bus->mdio_lock);
+
+	return val;
+}
+
+void
+ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r1, r2, page;
+
+	split_addr((u32) reg, &r1, &r2, &page);
+
+	mutex_lock(&bus->mdio_lock);
+
+	bus->write(bus, 0x18, 0, page);
+	wait_for_page_switch();
+	ar8xxx_mii_write32(priv, 0x10 | r2, r1, val);
+
+	mutex_unlock(&bus->mdio_lock);
+}
+
+u32
+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r1, r2, page;
+	u32 ret;
+
+	split_addr((u32) reg, &r1, &r2, &page);
+
+	mutex_lock(&bus->mdio_lock);
+
+	bus->write(bus, 0x18, 0, page);
+	wait_for_page_switch();
+
+	ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
+	ret &= ~mask;
+	ret |= val;
+	ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret);
+
+	mutex_unlock(&bus->mdio_lock);
+
+	return ret;
+}
+
+void
+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
+		     u16 dbg_addr, u16 dbg_data)
+{
+	struct mii_bus *bus = priv->mii_bus;
+
+	mutex_lock(&bus->mdio_lock);
+	bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
+	bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data);
+	mutex_unlock(&bus->mdio_lock);
+}
+
+static inline void
+ar8xxx_phy_mmd_prep(struct mii_bus *bus, int phy_addr, u16 addr, u16 reg)
+{
+	bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr);
+	bus->write(bus, phy_addr, MII_ATH_MMD_DATA, reg);
+	bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr | 0x4000);
+}
+
+void
+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data)
+{
+	struct mii_bus *bus = priv->mii_bus;
+
+	mutex_lock(&bus->mdio_lock);
+	ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg);
+	bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data);
+	mutex_unlock(&bus->mdio_lock);
+}
+
+u16
+ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 data;
+
+	mutex_lock(&bus->mdio_lock);
+	ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg);
+	data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA);
+	mutex_unlock(&bus->mdio_lock);
+
+	return data;
+}
+
+static int
+ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val,
+		unsigned timeout)
+{
+	int i;
+
+	for (i = 0; i < timeout; i++) {
+		u32 t;
+
+		t = ar8xxx_read(priv, reg);
+		if ((t & mask) == val)
+			return 0;
+
+		usleep_range(1000, 2000);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int
+ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op)
+{
+	unsigned mib_func = priv->chip->mib_func;
+	int ret;
+
+	lockdep_assert_held(&priv->mib_lock);
+
+	/* Capture the hardware statistics for all ports */
+	ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
+
+	/* Wait for the capturing to complete. */
+	ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+static int
+ar8xxx_mib_capture(struct ar8xxx_priv *priv)
+{
+	return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
+}
+
+static int
+ar8xxx_mib_flush(struct ar8xxx_priv *priv)
+{
+	return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
+}
+
+static void
+ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush)
+{
+	unsigned int base;
+	u64 *mib_stats;
+	int i;
+
+	WARN_ON(port >= priv->dev.ports);
+
+	lockdep_assert_held(&priv->mib_lock);
+
+	base = priv->chip->reg_port_stats_start +
+	       priv->chip->reg_port_stats_length * port;
+
+	mib_stats = &priv->mib_stats[port * priv->chip->num_mibs];
+	for (i = 0; i < priv->chip->num_mibs; i++) {
+		const struct ar8xxx_mib_desc *mib;
+		u64 t;
+
+		mib = &priv->chip->mib_decs[i];
+		t = ar8xxx_read(priv, base + mib->offset);
+		if (mib->size == 2) {
+			u64 hi;
+
+			hi = ar8xxx_read(priv, base + mib->offset + 4);
+			t |= hi << 32;
+		}
+
+		if (flush)
+			mib_stats[i] = 0;
+		else
+			mib_stats[i] += t;
+	}
+}
+
+static void
+ar8216_read_port_link(struct ar8xxx_priv *priv, int port,
+		      struct switch_port_link *link)
+{
+	u32 status;
+	u32 speed;
+
+	memset(link, '\0', sizeof(*link));
+
+	status = priv->chip->read_port_status(priv, port);
+
+	link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO);
+	if (link->aneg) {
+		link->link = !!(status & AR8216_PORT_STATUS_LINK_UP);
+	} else {
+		link->link = true;
+
+		if (priv->get_port_link) {
+			int err;
+
+			err = priv->get_port_link(port);
+			if (err >= 0)
+				link->link = !!err;
+		}
+	}
+
+	if (!link->link)
+		return;
+
+	link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX);
+	link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW);
+	link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW);
+
+	if (link->aneg && link->duplex && priv->chip->read_port_eee_status)
+		link->eee = priv->chip->read_port_eee_status(priv, port);
+
+	speed = (status & AR8216_PORT_STATUS_SPEED) >>
+		 AR8216_PORT_STATUS_SPEED_S;
+
+	switch (speed) {
+	case AR8216_PORT_SPEED_10M:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case AR8216_PORT_SPEED_100M:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case AR8216_PORT_SPEED_1000M:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+}
+
+static struct sk_buff *
+ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct ar8xxx_priv *priv = dev->phy_ptr;
+	unsigned char *buf;
+
+	if (unlikely(!priv))
+		goto error;
+
+	if (!priv->vlan)
+		goto send;
+
+	if (unlikely(skb_headroom(skb) < 2)) {
+		if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0)
+			goto error;
+	}
+
+	buf = skb_push(skb, 2);
+	buf[0] = 0x10;
+	buf[1] = 0x80;
+
+send:
+	return skb;
+
+error:
+	dev_kfree_skb_any(skb);
+	return NULL;
+}
+
+static void
+ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct ar8xxx_priv *priv;
+	unsigned char *buf;
+	int port, vlan;
+
+	priv = dev->phy_ptr;
+	if (!priv)
+		return;
+
+	/* don't strip the header if vlan mode is disabled */
+	if (!priv->vlan)
+		return;
+
+	/* strip header, get vlan id */
+	buf = skb->data;
+	skb_pull(skb, 2);
+
+	/* check for vlan header presence */
+	if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00))
+		return;
+
+	port = buf[0] & 0x7;
+
+	/* no need to fix up packets coming from a tagged source */
+	if (priv->vlan_tagged & (1 << port))
+		return;
+
+	/* lookup port vid from local table, the switch passes an invalid vlan id */
+	vlan = priv->vlan_id[priv->pvid[port]];
+
+	buf[14 + 2] &= 0xf0;
+	buf[14 + 2] |= vlan >> 8;
+	buf[15 + 2] = vlan & 0xff;
+}
+
+int
+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
+{
+	int timeout = 20;
+	u32 t = 0;
+
+	while (1) {
+		t = ar8xxx_read(priv, reg);
+		if ((t & mask) == val)
+			return 0;
+
+		if (timeout-- <= 0)
+			break;
+
+		udelay(10);
+	}
+
+	pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n",
+	       (unsigned int) reg, t, mask, val);
+	return -ETIMEDOUT;
+}
+
+static void
+ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
+{
+	if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0))
+		return;
+	if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) {
+		val &= AR8216_VTUDATA_MEMBER;
+		val |= AR8216_VTUDATA_VALID;
+		ar8xxx_write(priv, AR8216_REG_VTU_DATA, val);
+	}
+	op |= AR8216_VTU_ACTIVE;
+	ar8xxx_write(priv, AR8216_REG_VTU, op);
+}
+
+static void
+ar8216_vtu_flush(struct ar8xxx_priv *priv)
+{
+	ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
+}
+
+static void
+ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
+{
+	u32 op;
+
+	op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S);
+	ar8216_vtu_op(priv, op, port_mask);
+}
+
+static int
+ar8216_atu_flush(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0);
+	if (!ret)
+		ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH |
+							 AR8216_ATU_ACTIVE);
+
+	return ret;
+}
+
+static int
+ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port)
+{
+	u32 t;
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0);
+	if (!ret) {
+		t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT;
+		t |= AR8216_ATU_ACTIVE;
+		ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t);
+	}
+
+	return ret;
+}
+
+static u32
+ar8216_read_port_status(struct ar8xxx_priv *priv, int port)
+{
+	return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port));
+}
+
+static void
+ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	u32 header;
+	u32 egress, ingress;
+	u32 pvid;
+
+	if (priv->vlan) {
+		pvid = priv->vlan_id[priv->pvid[port]];
+		if (priv->vlan_tagged & (1 << port))
+			egress = AR8216_OUT_ADD_VLAN;
+		else
+			egress = AR8216_OUT_STRIP_VLAN;
+		ingress = AR8216_IN_SECURE;
+	} else {
+		pvid = port;
+		egress = AR8216_OUT_KEEP;
+		ingress = AR8216_IN_PORT_ONLY;
+	}
+
+	if (chip_is_ar8216(priv) && priv->vlan && port == AR8216_PORT_CPU)
+		header = AR8216_PORT_CTRL_HEADER;
+	else
+		header = 0;
+
+	ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
+		   AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
+		   AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
+		   AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
+		   AR8216_PORT_CTRL_LEARN | header |
+		   (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
+		   (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
+
+	ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port),
+		   AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE |
+		   AR8216_PORT_VLAN_DEFAULT_ID,
+		   (members << AR8216_PORT_VLAN_DEST_PORTS_S) |
+		   (ingress << AR8216_PORT_VLAN_MODE_S) |
+		   (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S));
+}
+
+static int
+ar8216_hw_init(struct ar8xxx_priv *priv)
+{
+	if (priv->initialized)
+		return 0;
+
+	ar8xxx_phy_init(priv);
+
+	priv->initialized = true;
+	return 0;
+}
+
+static void
+ar8216_init_globals(struct ar8xxx_priv *priv)
+{
+	/* standard atheros magic */
+	ar8xxx_write(priv, 0x38, 0xc000050e);
+
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8216_GCTRL_MTU, 1518 + 8 + 2);
+}
+
+static void
+ar8216_init_port(struct ar8xxx_priv *priv, int port)
+{
+	/* Enable port learning and tx */
+	ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port),
+		AR8216_PORT_CTRL_LEARN |
+		(4 << AR8216_PORT_CTRL_STATE_S));
+
+	ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0);
+
+	if (port == AR8216_PORT_CPU) {
+		ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port),
+			AR8216_PORT_STATUS_LINK_UP |
+			(ar8xxx_has_gige(priv) ?
+                                AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
+			AR8216_PORT_STATUS_TXMAC |
+			AR8216_PORT_STATUS_RXMAC |
+			(chip_is_ar8316(priv) ? AR8216_PORT_STATUS_RXFLOW : 0) |
+			(chip_is_ar8316(priv) ? AR8216_PORT_STATUS_TXFLOW : 0) |
+			AR8216_PORT_STATUS_DUPLEX);
+	} else {
+		ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port),
+			AR8216_PORT_STATUS_LINK_AUTO);
+	}
+}
+
+static void
+ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
+{
+	int timeout = 20;
+
+	while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout)
+                udelay(10);
+
+	if (!timeout)
+		pr_err("ar8216: timeout waiting for atu to become ready\n");
+}
+
+static void ar8216_get_arl_entry(struct ar8xxx_priv *priv,
+				 struct arl_entry *a, u32 *status, enum arl_op op)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r2, page;
+	u16 r1_func0, r1_func1, r1_func2;
+	u32 t, val0, val1, val2;
+	int i;
+
+	split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page);
+	r2 |= 0x10;
+
+	r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e;
+	r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e;
+
+	switch (op) {
+	case AR8XXX_ARL_INITIALIZE:
+		/* all ATU registers are on the same page
+		* therefore set page only once
+		*/
+		bus->write(bus, 0x18, 0, page);
+		wait_for_page_switch();
+
+		ar8216_wait_atu_ready(priv, r2, r1_func0);
+
+		ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT);
+		ar8xxx_mii_write32(priv, r2, r1_func1, 0);
+		ar8xxx_mii_write32(priv, r2, r1_func2, 0);
+		break;
+	case AR8XXX_ARL_GET_NEXT:
+		t = ar8xxx_mii_read32(priv, r2, r1_func0);
+		t |= AR8216_ATU_ACTIVE;
+		ar8xxx_mii_write32(priv, r2, r1_func0, t);
+		ar8216_wait_atu_ready(priv, r2, r1_func0);
+
+		val0 = ar8xxx_mii_read32(priv, r2, r1_func0);
+		val1 = ar8xxx_mii_read32(priv, r2, r1_func1);
+		val2 = ar8xxx_mii_read32(priv, r2, r1_func2);
+
+		*status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S;
+		if (!*status)
+			break;
+
+		i = 0;
+		t = AR8216_ATU_PORT0;
+		while (!(val2 & t) && ++i < priv->dev.ports)
+			t <<= 1;
+
+		a->port = i;
+		a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S;
+		a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S;
+		a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S;
+		a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S;
+		a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S;
+		a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S;
+		break;
+	}
+}
+
+static void
+ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	u32 egress, ingress;
+	u32 pvid;
+
+	if (priv->vlan) {
+		pvid = priv->vlan_id[priv->pvid[port]];
+		if (priv->vlan_tagged & (1 << port))
+			egress = AR8216_OUT_ADD_VLAN;
+		else
+			egress = AR8216_OUT_STRIP_VLAN;
+		ingress = AR8216_IN_SECURE;
+	} else {
+		pvid = port;
+		egress = AR8216_OUT_KEEP;
+		ingress = AR8216_IN_PORT_ONLY;
+	}
+
+	ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
+		   AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
+		   AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
+		   AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
+		   AR8216_PORT_CTRL_LEARN |
+		   (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
+		   (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
+
+	ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port),
+		   AR8236_PORT_VLAN_DEFAULT_ID,
+		   (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S));
+
+	ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port),
+		   AR8236_PORT_VLAN2_VLAN_MODE |
+		   AR8236_PORT_VLAN2_MEMBER,
+		   (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) |
+		   (members << AR8236_PORT_VLAN2_MEMBER_S));
+}
+
+static void
+ar8236_init_globals(struct ar8xxx_priv *priv)
+{
+	/* enable jumbo frames */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8316_GCTRL_MTU, 9018 + 8 + 2);
+
+	/* enable cpu port to receive arp frames */
+	ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL,
+		   AR8236_ATU_CTRL_RES);
+
+	/* enable cpu port to receive multicast and broadcast frames */
+	ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK,
+		   AR8236_FM_CPU_BROADCAST_EN | AR8236_FM_CPU_BCAST_FWD_EN);
+
+	/* Enable MIB counters */
+	ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
+		   (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
+		   AR8236_MIB_EN);
+}
+
+static int
+ar8316_hw_init(struct ar8xxx_priv *priv)
+{
+	u32 val, newval;
+
+	val = ar8xxx_read(priv, AR8316_REG_POSTRIP);
+
+	if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
+		if (priv->port4_phy) {
+			/* value taken from Ubiquiti RouterStation Pro */
+			newval = 0x81461bea;
+			pr_info("ar8316: Using port 4 as PHY\n");
+		} else {
+			newval = 0x01261be2;
+			pr_info("ar8316: Using port 4 as switch port\n");
+		}
+	} else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) {
+		/* value taken from AVM Fritz!Box 7390 sources */
+		newval = 0x010e5b71;
+	} else {
+		/* no known value for phy interface */
+		pr_err("ar8316: unsupported mii mode: %d.\n",
+		       priv->phy->interface);
+		return -EINVAL;
+	}
+
+	if (val == newval)
+		goto out;
+
+	ar8xxx_write(priv, AR8316_REG_POSTRIP, newval);
+
+	if (priv->port4_phy &&
+	    priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
+		/* work around for phy4 rgmii mode */
+		ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c);
+		/* rx delay */
+		ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e);
+		/* tx delay */
+		ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47);
+		msleep(1000);
+	}
+
+	ar8xxx_phy_init(priv);
+
+out:
+	priv->initialized = true;
+	return 0;
+}
+
+static void
+ar8316_init_globals(struct ar8xxx_priv *priv)
+{
+	/* standard atheros magic */
+	ar8xxx_write(priv, 0x38, 0xc000050e);
+
+	/* enable cpu port to receive multicast and broadcast frames */
+	ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
+
+	/* enable jumbo frames */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8316_GCTRL_MTU, 9018 + 8 + 2);
+
+	/* Enable MIB counters */
+	ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
+		   (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
+		   AR8236_MIB_EN);
+}
+
+int
+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	priv->vlan = !!val->value.i;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->vlan;
+	return 0;
+}
+
+
+int
+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	/* make sure no invalid PVIDs get set */
+
+	if (vlan < 0 || vlan >= dev->vlans ||
+	    port < 0 || port >= AR8X16_MAX_PORTS)
+		return -EINVAL;
+
+	priv->pvid[port] = vlan;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (port < 0 || port >= AR8X16_MAX_PORTS)
+		return -EINVAL;
+
+	*vlan = priv->pvid[port];
+	return 0;
+}
+
+static int
+ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (val->port_vlan >= AR8X16_MAX_PORTS)
+		return -EINVAL;
+
+	priv->vlan_id[val->port_vlan] = val->value.i;
+	return 0;
+}
+
+static int
+ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->vlan_id[val->port_vlan];
+	return 0;
+}
+
+int
+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
+			struct switch_port_link *link)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	ar8216_read_port_link(priv, port, link);
+	return 0;
+}
+
+static int
+ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 ports;
+	int i;
+
+	if (val->port_vlan >= AR8X16_MAX_VLANS)
+		return -EINVAL;
+
+	ports = priv->vlan_table[val->port_vlan];
+	val->len = 0;
+	for (i = 0; i < dev->ports; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (priv->vlan_tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int
+ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 *vt = &priv->vlan_table[val->port_vlan];
+	int i, j;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+			priv->vlan_tagged |= (1 << p->id);
+		} else {
+			priv->vlan_tagged &= ~(1 << p->id);
+			priv->pvid[p->id] = val->port_vlan;
+
+			/* make sure that an untagged port does not
+			 * appear in other vlans */
+			for (j = 0; j < AR8X16_MAX_VLANS; j++) {
+				if (j == val->port_vlan)
+					continue;
+				priv->vlan_table[j] &= ~(1 << p->id);
+			}
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static void
+ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+	int port;
+
+	/* reset all mirror registers */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
+		   AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
+		   (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+	for (port = 0; port < AR8216_NUM_PORTS; port++) {
+		ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port),
+			   AR8216_PORT_CTRL_MIRROR_RX);
+
+		ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port),
+			   AR8216_PORT_CTRL_MIRROR_TX);
+	}
+
+	/* now enable mirroring if necessary */
+	if (priv->source_port >= AR8216_NUM_PORTS ||
+	    priv->monitor_port >= AR8216_NUM_PORTS ||
+	    priv->source_port == priv->monitor_port) {
+		return;
+	}
+
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
+		   AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
+		   (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+
+	if (priv->mirror_rx)
+		ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port),
+			   AR8216_PORT_CTRL_MIRROR_RX);
+
+	if (priv->mirror_tx)
+		ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port),
+			   AR8216_PORT_CTRL_MIRROR_TX);
+}
+
+static inline u32
+ar8xxx_age_time_val(int age_time)
+{
+	return (age_time + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS / 2) /
+	       AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS;
+}
+
+static inline void
+ar8xxx_set_age_time(struct ar8xxx_priv *priv, int reg)
+{
+	u32 age_time = ar8xxx_age_time_val(priv->arl_age_time);
+	ar8xxx_rmw(priv, reg, AR8216_ATU_CTRL_AGE_TIME, age_time << AR8216_ATU_CTRL_AGE_TIME_S);
+}
+
+int
+ar8xxx_sw_hw_apply(struct switch_dev *dev)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8xxx_chip *chip = priv->chip;
+	u8 portmask[AR8X16_MAX_PORTS];
+	int i, j;
+
+	mutex_lock(&priv->reg_mutex);
+	/* flush all vlan translation unit entries */
+	priv->chip->vtu_flush(priv);
+
+	memset(portmask, 0, sizeof(portmask));
+	if (!priv->init) {
+		/* calculate the port destination masks and load vlans
+		 * into the vlan translation unit */
+		for (j = 0; j < AR8X16_MAX_VLANS; j++) {
+			u8 vp = priv->vlan_table[j];
+
+			if (!vp)
+				continue;
+
+			for (i = 0; i < dev->ports; i++) {
+				u8 mask = (1 << i);
+				if (vp & mask)
+					portmask[i] |= vp & ~mask;
+			}
+
+			chip->vtu_load_vlan(priv, priv->vlan_id[j],
+					    priv->vlan_table[j]);
+		}
+	} else {
+		/* vlan disabled:
+		 * isolate all ports, but connect them to the cpu port */
+		for (i = 0; i < dev->ports; i++) {
+			if (i == AR8216_PORT_CPU)
+				continue;
+
+			portmask[i] = 1 << AR8216_PORT_CPU;
+			portmask[AR8216_PORT_CPU] |= (1 << i);
+		}
+	}
+
+	/* update the port destination mask registers and tag settings */
+	for (i = 0; i < dev->ports; i++) {
+		chip->setup_port(priv, i, portmask[i]);
+	}
+
+	chip->set_mirror_regs(priv);
+
+	/* set age time */
+	if (chip->reg_arl_ctrl)
+		ar8xxx_set_age_time(priv, chip->reg_arl_ctrl);
+
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+int
+ar8xxx_sw_reset_switch(struct switch_dev *dev)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8xxx_chip *chip = priv->chip;
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+	memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) -
+		offsetof(struct ar8xxx_priv, vlan));
+
+	for (i = 0; i < AR8X16_MAX_VLANS; i++)
+		priv->vlan_id[i] = i;
+
+	/* Configure all ports */
+	for (i = 0; i < dev->ports; i++)
+		chip->init_port(priv, i);
+
+	priv->mirror_rx = false;
+	priv->mirror_tx = false;
+	priv->source_port = 0;
+	priv->monitor_port = 0;
+	priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME;
+
+	chip->init_globals(priv);
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return chip->sw_hw_apply(dev);
+}
+
+int
+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
+			 const struct switch_attr *attr,
+			 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	unsigned int len;
+	int ret;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&priv->mib_lock);
+
+	len = priv->dev.ports * priv->chip->num_mibs *
+	      sizeof(*priv->mib_stats);
+	memset(priv->mib_stats, '\0', len);
+	ret = ar8xxx_mib_flush(priv);
+	if (ret)
+		goto unlock;
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&priv->mib_lock);
+	return ret;
+}
+
+int
+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->mirror_rx = !!val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->mirror_rx;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->mirror_tx = !!val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->mirror_tx;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->monitor_port = val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->monitor_port;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->source_port = val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->source_port;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+	int ret;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+
+	port = val->port_vlan;
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+	ret = ar8xxx_mib_capture(priv);
+	if (ret)
+		goto unlock;
+
+	ar8xxx_mib_fetch_port_stat(priv, port, true);
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&priv->mib_lock);
+	return ret;
+}
+
+static void
+ar8xxx_byte_to_str(char *buf, int len, u64 byte)
+{
+	unsigned long b;
+	const char *unit;
+
+	if (byte >= 0x40000000) { /* 1 GiB */
+		b = byte * 10 / 0x40000000;
+		unit = "GiB";
+	} else if (byte >= 0x100000) { /* 1 MiB */
+		b = byte * 10 / 0x100000;
+		unit = "MiB";
+	} else if (byte >= 0x400) { /* 1 KiB */
+		b = byte * 10 / 0x400;
+		unit = "KiB";
+	} else {
+		b = byte;
+		unit = "Byte";
+	}
+	if (strcmp(unit, "Byte"))
+		snprintf(buf, len, "%lu.%lu %s", b / 10, b % 10, unit);
+	else
+		snprintf(buf, len, "%lu %s", b, unit);
+}
+
+int
+ar8xxx_sw_get_port_mib(struct switch_dev *dev,
+		       const struct switch_attr *attr,
+		       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8xxx_chip *chip = priv->chip;
+	u64 *mib_stats, mib_data;
+	unsigned int port;
+	int ret;
+	char *buf = priv->buf;
+	char buf1[64];
+	const char *mib_name;
+	int i, len = 0;
+	bool mib_stats_empty = true;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+
+	port = val->port_vlan;
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+	ret = ar8xxx_mib_capture(priv);
+	if (ret)
+		goto unlock;
+
+	ar8xxx_mib_fetch_port_stat(priv, port, false);
+
+	len += snprintf(buf + len, sizeof(priv->buf) - len,
+			"MIB counters\n");
+
+	mib_stats = &priv->mib_stats[port * chip->num_mibs];
+	for (i = 0; i < chip->num_mibs; i++) {
+		mib_name = chip->mib_decs[i].name;
+		mib_data = mib_stats[i];
+		len += snprintf(buf + len, sizeof(priv->buf) - len,
+				"%-12s: %llu\n", mib_name, mib_data);
+		if ((!strcmp(mib_name, "TxByte") ||
+		    !strcmp(mib_name, "RxGoodByte")) &&
+		    mib_data >= 1024) {
+			ar8xxx_byte_to_str(buf1, sizeof(buf1), mib_data);
+			--len; /* discard newline at the end of buf */
+			len += snprintf(buf + len, sizeof(priv->buf) - len,
+					" (%s)\n", buf1);
+		}
+		if (mib_stats_empty && mib_data)
+			mib_stats_empty = false;
+	}
+
+	if (mib_stats_empty)
+		len = snprintf(buf, sizeof(priv->buf), "No MIB data");
+
+	val->value.s = buf;
+	val->len = len;
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&priv->mib_lock);
+	return ret;
+}
+
+int
+ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr,
+			   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int age_time = val->value.i;
+	u32 age_time_val;
+
+	if (age_time < 0)
+		return -EINVAL;
+
+	age_time_val = ar8xxx_age_time_val(age_time);
+	if (age_time_val == 0 || age_time_val > 0xffff)
+		return -EINVAL;
+
+	priv->arl_age_time = age_time;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr,
+                   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->arl_age_time;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_arl_table(struct switch_dev *dev,
+			const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	struct mii_bus *bus = priv->mii_bus;
+	const struct ar8xxx_chip *chip = priv->chip;
+	char *buf = priv->arl_buf;
+	int i, j, k, len = 0;
+	struct arl_entry *a, *a1;
+	u32 status;
+
+	if (!chip->get_arl_entry)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&priv->reg_mutex);
+	mutex_lock(&bus->mdio_lock);
+
+	chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE);
+
+	for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) {
+		a = &priv->arl_table[i];
+		duplicate:
+		chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT);
+
+		if (!status)
+			break;
+
+		/* avoid duplicates
+		 * ARL table can include multiple valid entries
+		 * per MAC, just with differing status codes
+		 */
+		for (j = 0; j < i; ++j) {
+			a1 = &priv->arl_table[j];
+			if (a->port == a1->port && !memcmp(a->mac, a1->mac, sizeof(a->mac)))
+				goto duplicate;
+		}
+	}
+
+	mutex_unlock(&bus->mdio_lock);
+
+	len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
+                        "address resolution table\n");
+
+	if (i == AR8XXX_NUM_ARL_RECORDS)
+		len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
+				"Too many entries found, displaying the first %d only!\n",
+				AR8XXX_NUM_ARL_RECORDS);
+
+	for (j = 0; j < priv->dev.ports; ++j) {
+		for (k = 0; k < i; ++k) {
+			a = &priv->arl_table[k];
+			if (a->port != j)
+				continue;
+			len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
+					"Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					j,
+					a->mac[5], a->mac[4], a->mac[3],
+					a->mac[2], a->mac[1], a->mac[0]);
+		}
+	}
+
+	val->value.s = buf;
+	val->len = len;
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
+			      const struct switch_attr *attr,
+			      struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int ret;
+
+	mutex_lock(&priv->reg_mutex);
+	ret = priv->chip->atu_flush(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return ret;
+}
+
+int
+ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
+				   const struct switch_attr *attr,
+				   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port, ret;
+
+	port = val->port_vlan;
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	ret = priv->chip->atu_flush_port(priv, port);
+	mutex_unlock(&priv->reg_mutex);
+
+	return ret;
+}
+
+static const struct switch_attr ar8xxx_sw_attr_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = ar8xxx_sw_set_vlan,
+		.get = ar8xxx_sw_get_vlan,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = ar8xxx_sw_set_reset_mibs,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_rx",
+		.description = "Enable mirroring of RX packets",
+		.set = ar8xxx_sw_set_mirror_rx_enable,
+		.get = ar8xxx_sw_get_mirror_rx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_tx",
+		.description = "Enable mirroring of TX packets",
+		.set = ar8xxx_sw_set_mirror_tx_enable,
+		.get = ar8xxx_sw_get_mirror_tx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_monitor_port",
+		.description = "Mirror monitor port",
+		.set = ar8xxx_sw_set_mirror_monitor_port,
+		.get = ar8xxx_sw_get_mirror_monitor_port,
+		.max = AR8216_NUM_PORTS - 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_source_port",
+		.description = "Mirror source port",
+		.set = ar8xxx_sw_set_mirror_source_port,
+		.get = ar8xxx_sw_get_mirror_source_port,
+		.max = AR8216_NUM_PORTS - 1
+ 	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "arl_table",
+		.description = "Get ARL table",
+		.set = NULL,
+		.get = ar8xxx_sw_get_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush ARL table",
+		.set = ar8xxx_sw_set_flush_arl_table,
+	},
+};
+
+const struct switch_attr ar8xxx_sw_attr_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = ar8xxx_sw_set_port_reset_mib,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get port's MIB counters",
+		.set = NULL,
+		.get = ar8xxx_sw_get_port_mib,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush port's ARL table entries",
+		.set = ar8xxx_sw_set_flush_port_arl_table,
+	},
+};
+
+const struct switch_attr ar8xxx_sw_attr_vlan[1] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "vid",
+		.description = "VLAN ID (0-4094)",
+		.set = ar8xxx_sw_set_vid,
+		.get = ar8xxx_sw_get_vid,
+		.max = 4094,
+	},
+};
+
+static const struct switch_dev_ops ar8xxx_sw_ops = {
+	.attr_global = {
+		.attr = ar8xxx_sw_attr_globals,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals),
+	},
+	.attr_port = {
+		.attr = ar8xxx_sw_attr_port,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
+	},
+	.attr_vlan = {
+		.attr = ar8xxx_sw_attr_vlan,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
+	},
+	.get_port_pvid = ar8xxx_sw_get_pvid,
+	.set_port_pvid = ar8xxx_sw_set_pvid,
+	.get_vlan_ports = ar8xxx_sw_get_ports,
+	.set_vlan_ports = ar8xxx_sw_set_ports,
+	.apply_config = ar8xxx_sw_hw_apply,
+	.reset_switch = ar8xxx_sw_reset_switch,
+	.get_port_link = ar8xxx_sw_get_port_link,
+};
+
+static const struct ar8xxx_chip ar8216_chip = {
+	.caps = AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x19000,
+	.reg_port_stats_length = 0xa0,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8216",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8216_NUM_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8216_hw_init,
+	.init_globals = ar8216_init_globals,
+	.init_port = ar8216_init_port,
+	.setup_port = ar8216_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8216_mibs),
+	.mib_decs = ar8216_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC
+};
+
+static const struct ar8xxx_chip ar8236_chip = {
+	.caps = AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x20000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8236",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8216_NUM_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8216_hw_init,
+	.init_globals = ar8236_init_globals,
+	.init_port = ar8216_init_port,
+	.setup_port = ar8236_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC
+};
+
+static const struct ar8xxx_chip ar8316_chip = {
+	.caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x20000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8316",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8X16_MAX_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8316_hw_init,
+	.init_globals = ar8316_init_globals,
+	.init_port = ar8216_init_port,
+	.setup_port = ar8216_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC
+};
+
+static int
+ar8xxx_id_chip(struct ar8xxx_priv *priv)
+{
+	u32 val;
+	u16 id;
+	int i;
+
+	val = ar8xxx_read(priv, AR8216_REG_CTRL);
+	if (val == ~0)
+		return -ENODEV;
+
+	id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
+	for (i = 0; i < AR8X16_PROBE_RETRIES; i++) {
+		u16 t;
+
+		val = ar8xxx_read(priv, AR8216_REG_CTRL);
+		if (val == ~0)
+			return -ENODEV;
+
+		t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
+		if (t != id)
+			return -ENODEV;
+	}
+
+	priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S;
+	priv->chip_rev = (id & AR8216_CTRL_REVISION);
+
+	switch (priv->chip_ver) {
+	case AR8XXX_VER_AR8216:
+		priv->chip = &ar8216_chip;
+		break;
+	case AR8XXX_VER_AR8236:
+		priv->chip = &ar8236_chip;
+		break;
+	case AR8XXX_VER_AR8316:
+		priv->chip = &ar8316_chip;
+		break;
+	case AR8XXX_VER_AR8327:
+		priv->chip = &ar8327_chip;
+		break;
+	case AR8XXX_VER_AR8337:
+		priv->chip = &ar8337_chip;
+		break;
+	default:
+		pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n",
+		       priv->chip_ver, priv->chip_rev);
+
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void
+ar8xxx_mib_work_func(struct work_struct *work)
+{
+	struct ar8xxx_priv *priv;
+	int err;
+
+	priv = container_of(work, struct ar8xxx_priv, mib_work.work);
+
+	mutex_lock(&priv->mib_lock);
+
+	err = ar8xxx_mib_capture(priv);
+	if (err)
+		goto next_port;
+
+	ar8xxx_mib_fetch_port_stat(priv, priv->mib_next_port, false);
+
+next_port:
+	priv->mib_next_port++;
+	if (priv->mib_next_port >= priv->dev.ports)
+		priv->mib_next_port = 0;
+
+	mutex_unlock(&priv->mib_lock);
+	schedule_delayed_work(&priv->mib_work,
+			      msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY));
+}
+
+static int
+ar8xxx_mib_init(struct ar8xxx_priv *priv)
+{
+	unsigned int len;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return 0;
+
+	BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs);
+
+	len = priv->dev.ports * priv->chip->num_mibs *
+	      sizeof(*priv->mib_stats);
+	priv->mib_stats = kzalloc(len, GFP_KERNEL);
+
+	if (!priv->mib_stats)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void
+ar8xxx_mib_start(struct ar8xxx_priv *priv)
+{
+	if (!ar8xxx_has_mib_counters(priv))
+		return;
+
+	schedule_delayed_work(&priv->mib_work,
+			      msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY));
+}
+
+static void
+ar8xxx_mib_stop(struct ar8xxx_priv *priv)
+{
+	if (!ar8xxx_has_mib_counters(priv))
+		return;
+
+	cancel_delayed_work_sync(&priv->mib_work);
+}
+
+static struct ar8xxx_priv *
+ar8xxx_create(void)
+{
+	struct ar8xxx_priv *priv;
+
+	priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	mutex_init(&priv->reg_mutex);
+	mutex_init(&priv->mib_lock);
+	INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func);
+
+	return priv;
+}
+
+static void
+ar8xxx_free(struct ar8xxx_priv *priv)
+{
+	if (priv->chip && priv->chip->cleanup)
+		priv->chip->cleanup(priv);
+
+	kfree(priv->chip_data);
+	kfree(priv->mib_stats);
+	kfree(priv);
+}
+
+static int
+ar8xxx_probe_switch(struct ar8xxx_priv *priv)
+{
+	const struct ar8xxx_chip *chip;
+	struct switch_dev *swdev;
+	int ret;
+
+	ret = ar8xxx_id_chip(priv);
+	if (ret)
+		return ret;
+
+	chip = priv->chip;
+
+	swdev = &priv->dev;
+	swdev->cpu_port = AR8216_PORT_CPU;
+	swdev->name = chip->name;
+	swdev->vlans = chip->vlans;
+	swdev->ports = chip->ports;
+	swdev->ops = chip->swops;
+
+	ret = ar8xxx_mib_init(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+ar8xxx_start(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	priv->init = true;
+
+	ret = priv->chip->hw_init(priv);
+	if (ret)
+		return ret;
+
+	ret = ar8xxx_sw_reset_switch(&priv->dev);
+	if (ret)
+		return ret;
+
+	priv->init = false;
+
+	ar8xxx_mib_start(priv);
+
+	return 0;
+}
+
+static int
+ar8xxx_phy_config_init(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+	struct net_device *dev = phydev->attached_dev;
+	int ret;
+
+	if (WARN_ON(!priv))
+		return -ENODEV;
+
+	if (priv->chip->config_at_probe)
+		return ar8xxx_phy_check_aneg(phydev);
+
+	priv->phy = phydev;
+
+	if (phydev->addr != 0) {
+		if (chip_is_ar8316(priv)) {
+			/* switch device has been initialized, reinit */
+			priv->dev.ports = (AR8216_NUM_PORTS - 1);
+			priv->initialized = false;
+			priv->port4_phy = true;
+			ar8316_hw_init(priv);
+			return 0;
+		}
+
+		return 0;
+	}
+
+	ret = ar8xxx_start(priv);
+	if (ret)
+		return ret;
+
+	/* VID fixup only needed on ar8216 */
+	if (chip_is_ar8216(priv)) {
+		dev->phy_ptr = priv;
+		dev->priv_flags |= IFF_NO_IP_ALIGN;
+		dev->eth_mangle_rx = ar8216_mangle_rx;
+		dev->eth_mangle_tx = ar8216_mangle_tx;
+	}
+
+	return 0;
+}
+
+static bool
+ar8xxx_check_link_states(struct ar8xxx_priv *priv)
+{
+	bool link_new, changed = false;
+	u32 status;
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+
+	for (i = 0; i < priv->dev.ports; i++) {
+		status = priv->chip->read_port_status(priv, i);
+		link_new = !!(status & AR8216_PORT_STATUS_LINK_UP);
+		if (link_new == priv->link_up[i])
+			continue;
+
+		priv->link_up[i] = link_new;
+		changed = true;
+		/* flush ARL entries for this port if it went down*/
+		if (!link_new)
+			priv->chip->atu_flush_port(priv, i);
+		dev_info(&priv->phy->dev, "Port %d is %s\n",
+			 i, link_new ? "up" : "down");
+	}
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return changed;
+}
+
+static int
+ar8xxx_phy_read_status(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+	struct switch_port_link link;
+
+	/* check for switch port link changes */
+	if (phydev->state == PHY_CHANGELINK)
+		ar8xxx_check_link_states(priv);
+
+	if (phydev->addr != 0)
+		return genphy_read_status(phydev);
+
+	ar8216_read_port_link(priv, phydev->addr, &link);
+	phydev->link = !!link.link;
+	if (!phydev->link)
+		return 0;
+
+	switch (link.speed) {
+	case SWITCH_PORT_SPEED_10:
+		phydev->speed = SPEED_10;
+		break;
+	case SWITCH_PORT_SPEED_100:
+		phydev->speed = SPEED_100;
+		break;
+	case SWITCH_PORT_SPEED_1000:
+		phydev->speed = SPEED_1000;
+		break;
+	default:
+		phydev->speed = 0;
+	}
+	phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF;
+
+	phydev->state = PHY_RUNNING;
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+static int
+ar8xxx_phy_config_aneg(struct phy_device *phydev)
+{
+	if (phydev->addr == 0)
+		return 0;
+
+	return genphy_config_aneg(phydev);
+}
+
+static const u32 ar8xxx_phy_ids[] = {
+	0x004dd033,
+	0x004dd034, /* AR8327 */
+	0x004dd036, /* AR8337 */
+	0x004dd041,
+	0x004dd042,
+	0x004dd043, /* AR8236 */
+};
+
+static bool
+ar8xxx_phy_match(u32 phy_id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++)
+		if (phy_id == ar8xxx_phy_ids[i])
+			return true;
+
+	return false;
+}
+
+static bool
+ar8xxx_is_possible(struct mii_bus *bus)
+{
+	unsigned int i, found_phys = 0;
+
+	for (i = 0; i < 5; i++) {
+		u32 phy_id;
+
+		phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16;
+		phy_id |= mdiobus_read(bus, i, MII_PHYSID2);
+		if (ar8xxx_phy_match(phy_id)) {
+			found_phys++;
+		} else if (phy_id) {
+			pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n",
+				 dev_name(&bus->dev), i, phy_id);
+		}
+	}
+	return !!found_phys;
+}
+
+static int
+ar8xxx_phy_probe(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv;
+	struct switch_dev *swdev;
+	int ret;
+
+	/* skip PHYs at unused adresses */
+	if (phydev->addr != 0 && phydev->addr != 4)
+		return -ENODEV;
+
+	if (!ar8xxx_is_possible(phydev->bus))
+		return -ENODEV;
+
+	mutex_lock(&ar8xxx_dev_list_lock);
+	list_for_each_entry(priv, &ar8xxx_dev_list, list)
+		if (priv->mii_bus == phydev->bus)
+			goto found;
+
+	priv = ar8xxx_create();
+	if (priv == NULL) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	priv->mii_bus = phydev->bus;
+
+	ret = ar8xxx_probe_switch(priv);
+	if (ret)
+		goto free_priv;
+
+	swdev = &priv->dev;
+	swdev->alias = dev_name(&priv->mii_bus->dev);
+	ret = register_switch(swdev, NULL);
+	if (ret)
+		goto free_priv;
+
+	pr_info("%s: %s rev. %u switch registered on %s\n",
+		swdev->devname, swdev->name, priv->chip_rev,
+		dev_name(&priv->mii_bus->dev));
+
+	list_add(&priv->list, &ar8xxx_dev_list);
+
+found:
+	priv->use_count++;
+
+	if (phydev->addr == 0) {
+		if (ar8xxx_has_gige(priv)) {
+			phydev->supported = SUPPORTED_1000baseT_Full;
+			phydev->advertising = ADVERTISED_1000baseT_Full;
+		} else {
+			phydev->supported = SUPPORTED_100baseT_Full;
+			phydev->advertising = ADVERTISED_100baseT_Full;
+		}
+
+		if (priv->chip->config_at_probe) {
+			priv->phy = phydev;
+
+			ret = ar8xxx_start(priv);
+			if (ret)
+				goto err_unregister_switch;
+		}
+	} else {
+		if (ar8xxx_has_gige(priv)) {
+			phydev->supported |= SUPPORTED_1000baseT_Full;
+			phydev->advertising |= ADVERTISED_1000baseT_Full;
+		}
+	}
+
+	phydev->priv = priv;
+
+	mutex_unlock(&ar8xxx_dev_list_lock);
+
+	return 0;
+
+err_unregister_switch:
+	if (--priv->use_count)
+		goto unlock;
+
+	unregister_switch(&priv->dev);
+
+free_priv:
+	ar8xxx_free(priv);
+unlock:
+	mutex_unlock(&ar8xxx_dev_list_lock);
+	return ret;
+}
+
+static void
+ar8xxx_phy_detach(struct phy_device *phydev)
+{
+	struct net_device *dev = phydev->attached_dev;
+
+	if (!dev)
+		return;
+
+	dev->phy_ptr = NULL;
+	dev->priv_flags &= ~IFF_NO_IP_ALIGN;
+	dev->eth_mangle_rx = NULL;
+	dev->eth_mangle_tx = NULL;
+}
+
+static void
+ar8xxx_phy_remove(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+
+	if (WARN_ON(!priv))
+		return;
+
+	phydev->priv = NULL;
+
+	mutex_lock(&ar8xxx_dev_list_lock);
+
+	if (--priv->use_count > 0) {
+		mutex_unlock(&ar8xxx_dev_list_lock);
+		return;
+	}
+
+	list_del(&priv->list);
+	mutex_unlock(&ar8xxx_dev_list_lock);
+
+	unregister_switch(&priv->dev);
+	ar8xxx_mib_stop(priv);
+	ar8xxx_free(priv);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
+static int
+ar8xxx_phy_soft_reset(struct phy_device *phydev)
+{
+	/* we don't need an extra reset */
+	return 0;
+}
+#endif
+
+static struct phy_driver ar8xxx_phy_driver = {
+	.phy_id		= 0x004d0000,
+	.name		= "Atheros AR8216/AR8236/AR8316",
+	.phy_id_mask	= 0xffff0000,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= ar8xxx_phy_probe,
+	.remove		= ar8xxx_phy_remove,
+	.detach		= ar8xxx_phy_detach,
+	.config_init	= ar8xxx_phy_config_init,
+	.config_aneg	= ar8xxx_phy_config_aneg,
+	.read_status	= ar8xxx_phy_read_status,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
+	.soft_reset	= ar8xxx_phy_soft_reset,
+#endif
+	.driver		= { .owner = THIS_MODULE },
+};
+
+int __init
+ar8xxx_init(void)
+{
+	return phy_driver_register(&ar8xxx_phy_driver);
+}
+
+void __exit
+ar8xxx_exit(void)
+{
+	phy_driver_unregister(&ar8xxx_phy_driver);
+}
+
+module_init(ar8xxx_init);
+module_exit(ar8xxx_exit);
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h
new file mode 100644
index 0000000000..d9508b9ff8
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.h
@@ -0,0 +1,643 @@
+/*
+ * ar8216.h: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AR8216_H
+#define __AR8216_H
+
+#define BITS(_s, _n)	(((1UL << (_n)) - 1) << _s)
+
+#define AR8XXX_CAP_GIGE			BIT(0)
+#define AR8XXX_CAP_MIB_COUNTERS		BIT(1)
+
+#define AR8XXX_NUM_PHYS 	5
+#define AR8216_PORT_CPU	0
+#define AR8216_NUM_PORTS	6
+#define AR8216_NUM_VLANS	16
+#define AR8316_NUM_VLANS	4096
+
+/* size of the vlan table */
+#define AR8X16_MAX_VLANS	128
+#define AR8X16_PROBE_RETRIES	10
+#define AR8X16_MAX_PORTS	8
+
+#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS	7
+#define AR8XXX_DEFAULT_ARL_AGE_TIME		300
+
+/* Atheros specific MII registers */
+#define MII_ATH_MMD_ADDR		0x0d
+#define MII_ATH_MMD_DATA		0x0e
+#define MII_ATH_DBG_ADDR		0x1d
+#define MII_ATH_DBG_DATA		0x1e
+
+#define AR8216_REG_CTRL			0x0000
+#define   AR8216_CTRL_REVISION		BITS(0, 8)
+#define   AR8216_CTRL_REVISION_S	0
+#define   AR8216_CTRL_VERSION		BITS(8, 8)
+#define   AR8216_CTRL_VERSION_S		8
+#define   AR8216_CTRL_RESET		BIT(31)
+
+#define AR8216_REG_FLOOD_MASK		0x002C
+#define   AR8216_FM_UNI_DEST_PORTS	BITS(0, 6)
+#define   AR8216_FM_MULTI_DEST_PORTS	BITS(16, 6)
+#define   AR8236_FM_CPU_BROADCAST_EN	BIT(26)
+#define   AR8236_FM_CPU_BCAST_FWD_EN	BIT(25)
+
+#define AR8216_REG_GLOBAL_CTRL		0x0030
+#define   AR8216_GCTRL_MTU		BITS(0, 11)
+#define   AR8236_GCTRL_MTU		BITS(0, 14)
+#define   AR8316_GCTRL_MTU		BITS(0, 14)
+
+#define AR8216_REG_VTU			0x0040
+#define   AR8216_VTU_OP			BITS(0, 3)
+#define   AR8216_VTU_OP_NOOP		0x0
+#define   AR8216_VTU_OP_FLUSH		0x1
+#define   AR8216_VTU_OP_LOAD		0x2
+#define   AR8216_VTU_OP_PURGE		0x3
+#define   AR8216_VTU_OP_REMOVE_PORT	0x4
+#define   AR8216_VTU_ACTIVE		BIT(3)
+#define   AR8216_VTU_FULL		BIT(4)
+#define   AR8216_VTU_PORT		BITS(8, 4)
+#define   AR8216_VTU_PORT_S		8
+#define   AR8216_VTU_VID		BITS(16, 12)
+#define   AR8216_VTU_VID_S		16
+#define   AR8216_VTU_PRIO		BITS(28, 3)
+#define   AR8216_VTU_PRIO_S		28
+#define   AR8216_VTU_PRIO_EN		BIT(31)
+
+#define AR8216_REG_VTU_DATA		0x0044
+#define   AR8216_VTUDATA_MEMBER		BITS(0, 10)
+#define   AR8236_VTUDATA_MEMBER		BITS(0, 7)
+#define   AR8216_VTUDATA_VALID		BIT(11)
+
+#define AR8216_REG_ATU_FUNC0		0x0050
+#define   AR8216_ATU_OP			BITS(0, 3)
+#define   AR8216_ATU_OP_NOOP		0x0
+#define   AR8216_ATU_OP_FLUSH		0x1
+#define   AR8216_ATU_OP_LOAD		0x2
+#define   AR8216_ATU_OP_PURGE		0x3
+#define   AR8216_ATU_OP_FLUSH_UNLOCKED	0x4
+#define   AR8216_ATU_OP_FLUSH_PORT	0x5
+#define   AR8216_ATU_OP_GET_NEXT	0x6
+#define   AR8216_ATU_ACTIVE		BIT(3)
+#define   AR8216_ATU_PORT_NUM		BITS(8, 4)
+#define   AR8216_ATU_PORT_NUM_S		8
+#define   AR8216_ATU_FULL_VIO		BIT(12)
+#define   AR8216_ATU_ADDR5		BITS(16, 8)
+#define   AR8216_ATU_ADDR5_S		16
+#define   AR8216_ATU_ADDR4		BITS(24, 8)
+#define   AR8216_ATU_ADDR4_S		24
+
+#define AR8216_REG_ATU_FUNC1		0x0054
+#define   AR8216_ATU_ADDR3		BITS(0, 8)
+#define   AR8216_ATU_ADDR3_S		0
+#define   AR8216_ATU_ADDR2		BITS(8, 8)
+#define   AR8216_ATU_ADDR2_S		8
+#define   AR8216_ATU_ADDR1		BITS(16, 8)
+#define   AR8216_ATU_ADDR1_S		16
+#define   AR8216_ATU_ADDR0		BITS(24, 8)
+#define   AR8216_ATU_ADDR0_S		24
+
+#define AR8216_REG_ATU_FUNC2		0x0058
+#define   AR8216_ATU_PORTS		BITS(0, 6)
+#define   AR8216_ATU_PORT0		BIT(0)
+#define   AR8216_ATU_PORT1		BIT(1)
+#define   AR8216_ATU_PORT2		BIT(2)
+#define   AR8216_ATU_PORT3		BIT(3)
+#define   AR8216_ATU_PORT4		BIT(4)
+#define   AR8216_ATU_PORT5		BIT(5)
+#define   AR8216_ATU_STATUS		BITS(16, 4)
+#define   AR8216_ATU_STATUS_S		16
+
+#define AR8216_REG_ATU_CTRL		0x005C
+#define   AR8216_ATU_CTRL_AGE_EN	BIT(17)
+#define   AR8216_ATU_CTRL_AGE_TIME	BITS(0, 16)
+#define   AR8216_ATU_CTRL_AGE_TIME_S	0
+#define   AR8236_ATU_CTRL_RES		BIT(20)
+
+#define AR8216_REG_MIB_FUNC		0x0080
+#define   AR8216_MIB_TIMER		BITS(0, 16)
+#define   AR8216_MIB_AT_HALF_EN		BIT(16)
+#define   AR8216_MIB_BUSY		BIT(17)
+#define   AR8216_MIB_FUNC		BITS(24, 3)
+#define   AR8216_MIB_FUNC_S		24
+#define   AR8216_MIB_FUNC_NO_OP		0x0
+#define   AR8216_MIB_FUNC_FLUSH		0x1
+#define   AR8216_MIB_FUNC_CAPTURE	0x3
+#define   AR8236_MIB_EN			BIT(30)
+
+#define AR8216_REG_GLOBAL_CPUPORT		0x0078
+#define   AR8216_GLOBAL_CPUPORT_MIRROR_PORT	BITS(4, 4)
+#define   AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S	4
+
+#define AR8216_PORT_OFFSET(_i)		(0x0100 * (_i + 1))
+#define AR8216_REG_PORT_STATUS(_i)	(AR8216_PORT_OFFSET(_i) + 0x0000)
+#define   AR8216_PORT_STATUS_SPEED	BITS(0,2)
+#define   AR8216_PORT_STATUS_SPEED_S	0
+#define   AR8216_PORT_STATUS_TXMAC	BIT(2)
+#define   AR8216_PORT_STATUS_RXMAC	BIT(3)
+#define   AR8216_PORT_STATUS_TXFLOW	BIT(4)
+#define   AR8216_PORT_STATUS_RXFLOW	BIT(5)
+#define   AR8216_PORT_STATUS_DUPLEX	BIT(6)
+#define   AR8216_PORT_STATUS_LINK_UP	BIT(8)
+#define   AR8216_PORT_STATUS_LINK_AUTO	BIT(9)
+#define   AR8216_PORT_STATUS_LINK_PAUSE	BIT(10)
+#define   AR8216_PORT_STATUS_FLOW_CONTROL  BIT(12)
+
+#define AR8216_REG_PORT_CTRL(_i)	(AR8216_PORT_OFFSET(_i) + 0x0004)
+
+/* port forwarding state */
+#define   AR8216_PORT_CTRL_STATE	BITS(0, 3)
+#define   AR8216_PORT_CTRL_STATE_S	0
+
+#define   AR8216_PORT_CTRL_LEARN_LOCK	BIT(7)
+
+/* egress 802.1q mode */
+#define   AR8216_PORT_CTRL_VLAN_MODE	BITS(8, 2)
+#define   AR8216_PORT_CTRL_VLAN_MODE_S	8
+
+#define   AR8216_PORT_CTRL_IGMP_SNOOP	BIT(10)
+#define   AR8216_PORT_CTRL_HEADER	BIT(11)
+#define   AR8216_PORT_CTRL_MAC_LOOP	BIT(12)
+#define   AR8216_PORT_CTRL_SINGLE_VLAN	BIT(13)
+#define   AR8216_PORT_CTRL_LEARN	BIT(14)
+#define   AR8216_PORT_CTRL_MIRROR_TX	BIT(16)
+#define   AR8216_PORT_CTRL_MIRROR_RX	BIT(17)
+
+#define AR8216_REG_PORT_VLAN(_i)	(AR8216_PORT_OFFSET(_i) + 0x0008)
+
+#define   AR8216_PORT_VLAN_DEFAULT_ID	BITS(0, 12)
+#define   AR8216_PORT_VLAN_DEFAULT_ID_S	0
+
+#define   AR8216_PORT_VLAN_DEST_PORTS	BITS(16, 9)
+#define   AR8216_PORT_VLAN_DEST_PORTS_S	16
+
+/* bit0 added to the priority field of egress frames */
+#define   AR8216_PORT_VLAN_TX_PRIO	BIT(27)
+
+/* port default priority */
+#define   AR8216_PORT_VLAN_PRIORITY	BITS(28, 2)
+#define   AR8216_PORT_VLAN_PRIORITY_S	28
+
+/* ingress 802.1q mode */
+#define   AR8216_PORT_VLAN_MODE		BITS(30, 2)
+#define   AR8216_PORT_VLAN_MODE_S	30
+
+#define AR8216_REG_PORT_RATE(_i)	(AR8216_PORT_OFFSET(_i) + 0x000c)
+#define AR8216_REG_PORT_PRIO(_i)	(AR8216_PORT_OFFSET(_i) + 0x0010)
+
+#define AR8216_STATS_RXBROAD		0x00
+#define AR8216_STATS_RXPAUSE		0x04
+#define AR8216_STATS_RXMULTI		0x08
+#define AR8216_STATS_RXFCSERR		0x0c
+#define AR8216_STATS_RXALIGNERR		0x10
+#define AR8216_STATS_RXRUNT		0x14
+#define AR8216_STATS_RXFRAGMENT		0x18
+#define AR8216_STATS_RX64BYTE		0x1c
+#define AR8216_STATS_RX128BYTE		0x20
+#define AR8216_STATS_RX256BYTE		0x24
+#define AR8216_STATS_RX512BYTE		0x28
+#define AR8216_STATS_RX1024BYTE		0x2c
+#define AR8216_STATS_RXMAXBYTE		0x30
+#define AR8216_STATS_RXTOOLONG		0x34
+#define AR8216_STATS_RXGOODBYTE		0x38
+#define AR8216_STATS_RXBADBYTE		0x40
+#define AR8216_STATS_RXOVERFLOW		0x48
+#define AR8216_STATS_FILTERED		0x4c
+#define AR8216_STATS_TXBROAD		0x50
+#define AR8216_STATS_TXPAUSE		0x54
+#define AR8216_STATS_TXMULTI		0x58
+#define AR8216_STATS_TXUNDERRUN		0x5c
+#define AR8216_STATS_TX64BYTE		0x60
+#define AR8216_STATS_TX128BYTE		0x64
+#define AR8216_STATS_TX256BYTE		0x68
+#define AR8216_STATS_TX512BYTE		0x6c
+#define AR8216_STATS_TX1024BYTE		0x70
+#define AR8216_STATS_TXMAXBYTE		0x74
+#define AR8216_STATS_TXOVERSIZE		0x78
+#define AR8216_STATS_TXBYTE		0x7c
+#define AR8216_STATS_TXCOLLISION	0x84
+#define AR8216_STATS_TXABORTCOL		0x88
+#define AR8216_STATS_TXMULTICOL		0x8c
+#define AR8216_STATS_TXSINGLECOL	0x90
+#define AR8216_STATS_TXEXCDEFER		0x94
+#define AR8216_STATS_TXDEFER		0x98
+#define AR8216_STATS_TXLATECOL		0x9c
+
+#define AR8236_REG_PORT_VLAN(_i)	(AR8216_PORT_OFFSET((_i)) + 0x0008)
+#define   AR8236_PORT_VLAN_DEFAULT_ID	BITS(16, 12)
+#define   AR8236_PORT_VLAN_DEFAULT_ID_S	16
+#define   AR8236_PORT_VLAN_PRIORITY	BITS(29, 3)
+#define   AR8236_PORT_VLAN_PRIORITY_S	28
+
+#define AR8236_REG_PORT_VLAN2(_i)	(AR8216_PORT_OFFSET((_i)) + 0x000c)
+#define   AR8236_PORT_VLAN2_MEMBER	BITS(16, 7)
+#define   AR8236_PORT_VLAN2_MEMBER_S	16
+#define   AR8236_PORT_VLAN2_TX_PRIO	BIT(23)
+#define   AR8236_PORT_VLAN2_VLAN_MODE	BITS(30, 2)
+#define   AR8236_PORT_VLAN2_VLAN_MODE_S	30
+
+#define AR8236_STATS_RXBROAD		0x00
+#define AR8236_STATS_RXPAUSE		0x04
+#define AR8236_STATS_RXMULTI		0x08
+#define AR8236_STATS_RXFCSERR		0x0c
+#define AR8236_STATS_RXALIGNERR		0x10
+#define AR8236_STATS_RXRUNT		0x14
+#define AR8236_STATS_RXFRAGMENT		0x18
+#define AR8236_STATS_RX64BYTE		0x1c
+#define AR8236_STATS_RX128BYTE		0x20
+#define AR8236_STATS_RX256BYTE		0x24
+#define AR8236_STATS_RX512BYTE		0x28
+#define AR8236_STATS_RX1024BYTE		0x2c
+#define AR8236_STATS_RX1518BYTE		0x30
+#define AR8236_STATS_RXMAXBYTE		0x34
+#define AR8236_STATS_RXTOOLONG		0x38
+#define AR8236_STATS_RXGOODBYTE		0x3c
+#define AR8236_STATS_RXBADBYTE		0x44
+#define AR8236_STATS_RXOVERFLOW		0x4c
+#define AR8236_STATS_FILTERED		0x50
+#define AR8236_STATS_TXBROAD		0x54
+#define AR8236_STATS_TXPAUSE		0x58
+#define AR8236_STATS_TXMULTI		0x5c
+#define AR8236_STATS_TXUNDERRUN		0x60
+#define AR8236_STATS_TX64BYTE		0x64
+#define AR8236_STATS_TX128BYTE		0x68
+#define AR8236_STATS_TX256BYTE		0x6c
+#define AR8236_STATS_TX512BYTE		0x70
+#define AR8236_STATS_TX1024BYTE		0x74
+#define AR8236_STATS_TX1518BYTE		0x78
+#define AR8236_STATS_TXMAXBYTE		0x7c
+#define AR8236_STATS_TXOVERSIZE		0x80
+#define AR8236_STATS_TXBYTE		0x84
+#define AR8236_STATS_TXCOLLISION	0x8c
+#define AR8236_STATS_TXABORTCOL		0x90
+#define AR8236_STATS_TXMULTICOL		0x94
+#define AR8236_STATS_TXSINGLECOL	0x98
+#define AR8236_STATS_TXEXCDEFER		0x9c
+#define AR8236_STATS_TXDEFER		0xa0
+#define AR8236_STATS_TXLATECOL		0xa4
+
+#define AR8316_REG_POSTRIP			0x0008
+#define   AR8316_POSTRIP_MAC0_GMII_EN		BIT(0)
+#define   AR8316_POSTRIP_MAC0_RGMII_EN		BIT(1)
+#define   AR8316_POSTRIP_PHY4_GMII_EN		BIT(2)
+#define   AR8316_POSTRIP_PHY4_RGMII_EN		BIT(3)
+#define   AR8316_POSTRIP_MAC0_MAC_MODE		BIT(4)
+#define   AR8316_POSTRIP_RTL_MODE		BIT(5)
+#define   AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN	BIT(6)
+#define   AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN	BIT(7)
+#define   AR8316_POSTRIP_SERDES_EN		BIT(8)
+#define   AR8316_POSTRIP_SEL_ANA_RST		BIT(9)
+#define   AR8316_POSTRIP_GATE_25M_EN		BIT(10)
+#define   AR8316_POSTRIP_SEL_CLK25M		BIT(11)
+#define   AR8316_POSTRIP_HIB_PULSE_HW		BIT(12)
+#define   AR8316_POSTRIP_DBG_MODE_I		BIT(13)
+#define   AR8316_POSTRIP_MAC5_MAC_MODE		BIT(14)
+#define   AR8316_POSTRIP_MAC5_PHY_MODE		BIT(15)
+#define   AR8316_POSTRIP_POWER_DOWN_HW		BIT(16)
+#define   AR8316_POSTRIP_LPW_STATE_EN		BIT(17)
+#define   AR8316_POSTRIP_MAN_EN			BIT(18)
+#define   AR8316_POSTRIP_PHY_PLL_ON		BIT(19)
+#define   AR8316_POSTRIP_LPW_EXIT		BIT(20)
+#define   AR8316_POSTRIP_TXDELAY_S0		BIT(21)
+#define   AR8316_POSTRIP_TXDELAY_S1		BIT(22)
+#define   AR8316_POSTRIP_RXDELAY_S0		BIT(23)
+#define   AR8316_POSTRIP_LED_OPEN_EN		BIT(24)
+#define   AR8316_POSTRIP_SPI_EN			BIT(25)
+#define   AR8316_POSTRIP_RXDELAY_S1		BIT(26)
+#define   AR8316_POSTRIP_POWER_ON_SEL		BIT(31)
+
+/* port speed */
+enum {
+        AR8216_PORT_SPEED_10M = 0,
+        AR8216_PORT_SPEED_100M = 1,
+        AR8216_PORT_SPEED_1000M = 2,
+        AR8216_PORT_SPEED_ERR = 3,
+};
+
+/* ingress 802.1q mode */
+enum {
+	AR8216_IN_PORT_ONLY = 0,
+	AR8216_IN_PORT_FALLBACK = 1,
+	AR8216_IN_VLAN_ONLY = 2,
+	AR8216_IN_SECURE = 3
+};
+
+/* egress 802.1q mode */
+enum {
+	AR8216_OUT_KEEP = 0,
+	AR8216_OUT_STRIP_VLAN = 1,
+	AR8216_OUT_ADD_VLAN = 2
+};
+
+/* port forwarding state */
+enum {
+	AR8216_PORT_STATE_DISABLED = 0,
+	AR8216_PORT_STATE_BLOCK = 1,
+	AR8216_PORT_STATE_LISTEN = 2,
+	AR8216_PORT_STATE_LEARN = 3,
+	AR8216_PORT_STATE_FORWARD = 4
+};
+
+enum {
+	AR8XXX_VER_AR8216 = 0x01,
+	AR8XXX_VER_AR8236 = 0x03,
+	AR8XXX_VER_AR8316 = 0x10,
+	AR8XXX_VER_AR8327 = 0x12,
+	AR8XXX_VER_AR8337 = 0x13,
+};
+
+#define AR8XXX_NUM_ARL_RECORDS	100
+
+enum arl_op {
+	AR8XXX_ARL_INITIALIZE,
+	AR8XXX_ARL_GET_NEXT
+};
+
+struct arl_entry {
+	u8 port;
+	u8 mac[6];
+};
+
+struct ar8xxx_priv;
+
+struct ar8xxx_mib_desc {
+	unsigned int size;
+	unsigned int offset;
+	const char *name;
+};
+
+struct ar8xxx_chip {
+	unsigned long caps;
+	bool config_at_probe;
+	bool mii_lo_first;
+
+	/* parameters to calculate REG_PORT_STATS_BASE */
+	unsigned reg_port_stats_start;
+	unsigned reg_port_stats_length;
+
+	unsigned reg_arl_ctrl;
+
+	int (*hw_init)(struct ar8xxx_priv *priv);
+	void (*cleanup)(struct ar8xxx_priv *priv);
+
+	const char *name;
+	int vlans;
+	int ports;
+	const struct switch_dev_ops *swops;
+
+	void (*init_globals)(struct ar8xxx_priv *priv);
+	void (*init_port)(struct ar8xxx_priv *priv, int port);
+	void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members);
+	u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
+	u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port);
+	int (*atu_flush)(struct ar8xxx_priv *priv);
+	int (*atu_flush_port)(struct ar8xxx_priv *priv, int port);
+	void (*vtu_flush)(struct ar8xxx_priv *priv);
+	void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
+	void (*phy_fixup)(struct ar8xxx_priv *priv, int phy);
+	void (*set_mirror_regs)(struct ar8xxx_priv *priv);
+	void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
+			      u32 *status, enum arl_op op);
+	int (*sw_hw_apply)(struct switch_dev *dev);
+
+	const struct ar8xxx_mib_desc *mib_decs;
+	unsigned num_mibs;
+	unsigned mib_func;
+};
+
+struct ar8xxx_priv {
+	struct switch_dev dev;
+	struct mii_bus *mii_bus;
+	struct phy_device *phy;
+
+	int (*get_port_link)(unsigned port);
+
+	const struct net_device_ops *ndo_old;
+	struct net_device_ops ndo;
+	struct mutex reg_mutex;
+	u8 chip_ver;
+	u8 chip_rev;
+	const struct ar8xxx_chip *chip;
+	void *chip_data;
+	bool initialized;
+	bool port4_phy;
+	char buf[2048];
+	struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS];
+	char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256];
+	bool link_up[AR8X16_MAX_PORTS];
+
+	bool init;
+
+	struct mutex mib_lock;
+	struct delayed_work mib_work;
+	int mib_next_port;
+	u64 *mib_stats;
+
+	struct list_head list;
+	unsigned int use_count;
+
+	/* all fields below are cleared on reset */
+	bool vlan;
+	u16 vlan_id[AR8X16_MAX_VLANS];
+	u8 vlan_table[AR8X16_MAX_VLANS];
+	u8 vlan_tagged;
+	u16 pvid[AR8X16_MAX_PORTS];
+	int arl_age_time;
+
+	/* mirroring */
+	bool mirror_rx;
+	bool mirror_tx;
+	int source_port;
+	int monitor_port;
+};
+
+u32
+ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum);
+void
+ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val);
+u32
+ar8xxx_read(struct ar8xxx_priv *priv, int reg);
+void
+ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val);
+u32
+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
+
+void
+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
+		     u16 dbg_addr, u16 dbg_data);
+void
+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data);
+u16
+ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg);
+void
+ar8xxx_phy_init(struct ar8xxx_priv *priv);
+int
+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val);
+int
+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val);
+int
+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
+			 const struct switch_attr *attr,
+			 struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val);
+int
+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan);
+int
+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan);
+int
+ar8xxx_sw_hw_apply(struct switch_dev *dev);
+int
+ar8xxx_sw_reset_switch(struct switch_dev *dev);
+int
+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
+			struct switch_port_link *link);
+int
+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
+                             const struct switch_attr *attr,
+                             struct switch_val *val);
+int
+ar8xxx_sw_get_port_mib(struct switch_dev *dev,
+                       const struct switch_attr *attr,
+                       struct switch_val *val);
+int
+ar8xxx_sw_get_arl_age_time(struct switch_dev *dev,
+			   const struct switch_attr *attr,
+			   struct switch_val *val);
+int
+ar8xxx_sw_set_arl_age_time(struct switch_dev *dev,
+			   const struct switch_attr *attr,
+			   struct switch_val *val);
+int
+ar8xxx_sw_get_arl_table(struct switch_dev *dev,
+			const struct switch_attr *attr,
+			struct switch_val *val);
+int
+ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
+			      const struct switch_attr *attr,
+			      struct switch_val *val);
+int
+ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
+				   const struct switch_attr *attr,
+				   struct switch_val *val);
+int
+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
+
+static inline struct ar8xxx_priv *
+swdev_to_ar8xxx(struct switch_dev *swdev)
+{
+	return container_of(swdev, struct ar8xxx_priv, dev);
+}
+
+static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv)
+{
+	return priv->chip->caps & AR8XXX_CAP_GIGE;
+}
+
+static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv)
+{
+	return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS;
+}
+
+static inline bool chip_is_ar8216(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8216;
+}
+
+static inline bool chip_is_ar8236(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8236;
+}
+
+static inline bool chip_is_ar8316(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8316;
+}
+
+static inline bool chip_is_ar8327(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8327;
+}
+
+static inline bool chip_is_ar8337(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8337;
+}
+
+static inline void
+ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+	ar8xxx_rmw(priv, reg, 0, val);
+}
+
+static inline void
+ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+	ar8xxx_rmw(priv, reg, val, 0);
+}
+
+static inline void
+split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
+{
+	regaddr >>= 1;
+	*r1 = regaddr & 0x1e;
+
+	regaddr >>= 5;
+	*r2 = regaddr & 0x7;
+
+	regaddr >>= 3;
+	*page = regaddr & 0x1ff;
+}
+
+static inline void
+wait_for_page_switch(void)
+{
+	udelay(5);
+}
+
+#endif
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c
new file mode 100644
index 0000000000..74c80d4452
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
@@ -0,0 +1,1443 @@
+/*
+ * ar8327.c: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/lockdep.h>
+#include <linux/ar8216_platform.h>
+#include <linux/workqueue.h>
+#include <linux/of_device.h>
+#include <linux/leds.h>
+#include <linux/mdio.h>
+
+#include "ar8216.h"
+#include "ar8327.h"
+
+extern const struct ar8xxx_mib_desc ar8236_mibs[39];
+extern const struct switch_attr ar8xxx_sw_attr_vlan[1];
+
+static u32
+ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
+{
+	u32 t;
+
+	if (!cfg)
+		return 0;
+
+	t = 0;
+	switch (cfg->mode) {
+	case AR8327_PAD_NC:
+		break;
+
+	case AR8327_PAD_MAC2MAC_MII:
+		t = AR8327_PAD_MAC_MII_EN;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_MAC_MII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_MAC_MII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC2MAC_GMII:
+		t = AR8327_PAD_MAC_GMII_EN;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_MAC_GMII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_MAC_GMII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC_SGMII:
+		t = AR8327_PAD_SGMII_EN;
+
+		/*
+		 * WAR for the QUalcomm Atheros AP136 board.
+		 * It seems that RGMII TX/RX delay settings needs to be
+		 * applied for SGMII mode as well, The ethernet is not
+		 * reliable without this.
+		 */
+		t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
+		t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
+		if (cfg->rxclk_delay_en)
+			t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+		if (cfg->txclk_delay_en)
+			t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
+
+		if (cfg->sgmii_delay_en)
+			t |= AR8327_PAD_SGMII_DELAY_EN;
+
+		break;
+
+	case AR8327_PAD_MAC2PHY_MII:
+		t = AR8327_PAD_PHY_MII_EN;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_PHY_MII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_PHY_MII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC2PHY_GMII:
+		t = AR8327_PAD_PHY_GMII_EN;
+		if (cfg->pipe_rxclk_sel)
+			t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_PHY_GMII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_PHY_GMII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC_RGMII:
+		t = AR8327_PAD_RGMII_EN;
+		t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
+		t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
+		if (cfg->rxclk_delay_en)
+			t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+		if (cfg->txclk_delay_en)
+			t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
+		break;
+
+	case AR8327_PAD_PHY_GMII:
+		t = AR8327_PAD_PHYX_GMII_EN;
+		break;
+
+	case AR8327_PAD_PHY_RGMII:
+		t = AR8327_PAD_PHYX_RGMII_EN;
+		break;
+
+	case AR8327_PAD_PHY_MII:
+		t = AR8327_PAD_PHYX_MII_EN;
+		break;
+	}
+
+	return t;
+}
+
+static void
+ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
+{
+	switch (priv->chip_rev) {
+	case 1:
+		/* For 100M waveform */
+		ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea);
+		/* Turn on Gigabit clock */
+		ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0);
+		break;
+
+	case 2:
+		ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0);
+		/* fallthrough */
+	case 4:
+		ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f);
+		ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860);
+		ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46);
+		ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000);
+		break;
+	}
+}
+
+static u32
+ar8327_get_port_init_status(struct ar8327_port_cfg *cfg)
+{
+	u32 t;
+
+	if (!cfg->force_link)
+		return AR8216_PORT_STATUS_LINK_AUTO;
+
+	t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC;
+	t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
+	t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
+	t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
+
+	switch (cfg->speed) {
+	case AR8327_PORT_SPEED_10:
+		t |= AR8216_PORT_SPEED_10M;
+		break;
+	case AR8327_PORT_SPEED_100:
+		t |= AR8216_PORT_SPEED_100M;
+		break;
+	case AR8327_PORT_SPEED_1000:
+		t |= AR8216_PORT_SPEED_1000M;
+		break;
+	}
+
+	return t;
+}
+
+#define AR8327_LED_ENTRY(_num, _reg, _shift) \
+	[_num] = { .reg = (_reg), .shift = (_shift) }
+
+static const struct ar8327_led_entry
+ar8327_led_map[AR8327_NUM_LEDS] = {
+	AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14),
+	AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14),
+	AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8),
+	AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10),
+	AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14),
+	AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16),
+	AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20),
+	AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22),
+	AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30),
+	AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30),
+	AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30),
+};
+
+static void
+ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num,
+		       enum ar8327_led_pattern pattern)
+{
+	const struct ar8327_led_entry *entry;
+
+	entry = &ar8327_led_map[led_num];
+	ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg),
+		   (3 << entry->shift), pattern << entry->shift);
+}
+
+static void
+ar8327_led_work_func(struct work_struct *work)
+{
+	struct ar8327_led *aled;
+	u8 pattern;
+
+	aled = container_of(work, struct ar8327_led, led_work);
+
+	pattern = aled->pattern;
+
+	ar8327_set_led_pattern(aled->sw_priv, aled->led_num,
+			       pattern);
+}
+
+static void
+ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern)
+{
+	if (aled->pattern == pattern)
+		return;
+
+	aled->pattern = pattern;
+	schedule_work(&aled->led_work);
+}
+
+static inline struct ar8327_led *
+led_cdev_to_ar8327_led(struct led_classdev *led_cdev)
+{
+	return container_of(led_cdev, struct ar8327_led, cdev);
+}
+
+static int
+ar8327_led_blink_set(struct led_classdev *led_cdev,
+		     unsigned long *delay_on,
+		     unsigned long *delay_off)
+{
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+
+	if (*delay_on == 0 && *delay_off == 0) {
+		*delay_on = 125;
+		*delay_off = 125;
+	}
+
+	if (*delay_on != 125 || *delay_off != 125) {
+		/*
+		 * The hardware only supports blinking at 4Hz. Fall back
+		 * to software implementation in other cases.
+		 */
+		return -EINVAL;
+	}
+
+	spin_lock(&aled->lock);
+
+	aled->enable_hw_mode = false;
+	ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK);
+
+	spin_unlock(&aled->lock);
+
+	return 0;
+}
+
+static void
+ar8327_led_set_brightness(struct led_classdev *led_cdev,
+			  enum led_brightness brightness)
+{
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+	u8 pattern;
+	bool active;
+
+	active = (brightness != LED_OFF);
+	active ^= aled->active_low;
+
+	pattern = (active) ? AR8327_LED_PATTERN_ON :
+			     AR8327_LED_PATTERN_OFF;
+
+	spin_lock(&aled->lock);
+
+	aled->enable_hw_mode = false;
+	ar8327_led_schedule_change(aled, pattern);
+
+	spin_unlock(&aled->lock);
+}
+
+static ssize_t
+ar8327_led_enable_hw_mode_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+	ssize_t ret = 0;
+
+	ret += scnprintf(buf, PAGE_SIZE, "%d\n", aled->enable_hw_mode);
+
+	return ret;
+}
+
+static ssize_t
+ar8327_led_enable_hw_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+        struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+	u8 pattern;
+	u8 value;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &value);
+	if (ret < 0)
+		return -EINVAL;
+
+	spin_lock(&aled->lock);
+
+	aled->enable_hw_mode = !!value;
+	if (aled->enable_hw_mode)
+		pattern = AR8327_LED_PATTERN_RULE;
+	else
+		pattern = AR8327_LED_PATTERN_OFF;
+
+	ar8327_led_schedule_change(aled, pattern);
+
+	spin_unlock(&aled->lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(enable_hw_mode,  S_IRUGO | S_IWUSR,
+		   ar8327_led_enable_hw_mode_show,
+		   ar8327_led_enable_hw_mode_store);
+
+static int
+ar8327_led_register(struct ar8327_led *aled)
+{
+	int ret;
+
+	ret = led_classdev_register(NULL, &aled->cdev);
+	if (ret < 0)
+		return ret;
+
+	if (aled->mode == AR8327_LED_MODE_HW) {
+		ret = device_create_file(aled->cdev.dev,
+					 &dev_attr_enable_hw_mode);
+		if (ret)
+			goto err_unregister;
+	}
+
+	return 0;
+
+err_unregister:
+	led_classdev_unregister(&aled->cdev);
+	return ret;
+}
+
+static void
+ar8327_led_unregister(struct ar8327_led *aled)
+{
+	if (aled->mode == AR8327_LED_MODE_HW)
+		device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode);
+
+	led_classdev_unregister(&aled->cdev);
+	cancel_work_sync(&aled->led_work);
+}
+
+static int
+ar8327_led_create(struct ar8xxx_priv *priv,
+		  const struct ar8327_led_info *led_info)
+{
+	struct ar8327_data *data = priv->chip_data;
+	struct ar8327_led *aled;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
+		return 0;
+
+	if (!led_info->name)
+		return -EINVAL;
+
+	if (led_info->led_num >= AR8327_NUM_LEDS)
+		return -EINVAL;
+
+	aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1,
+		       GFP_KERNEL);
+	if (!aled)
+		return -ENOMEM;
+
+	aled->sw_priv = priv;
+	aled->led_num = led_info->led_num;
+	aled->active_low = led_info->active_low;
+	aled->mode = led_info->mode;
+
+	if (aled->mode == AR8327_LED_MODE_HW)
+		aled->enable_hw_mode = true;
+
+	aled->name = (char *)(aled + 1);
+	strcpy(aled->name, led_info->name);
+
+	aled->cdev.name = aled->name;
+	aled->cdev.brightness_set = ar8327_led_set_brightness;
+	aled->cdev.blink_set = ar8327_led_blink_set;
+	aled->cdev.default_trigger = led_info->default_trigger;
+
+	spin_lock_init(&aled->lock);
+	mutex_init(&aled->mutex);
+	INIT_WORK(&aled->led_work, ar8327_led_work_func);
+
+	ret = ar8327_led_register(aled);
+	if (ret)
+		goto err_free;
+
+	data->leds[data->num_leds++] = aled;
+
+	return 0;
+
+err_free:
+	kfree(aled);
+	return ret;
+}
+
+static void
+ar8327_led_destroy(struct ar8327_led *aled)
+{
+	ar8327_led_unregister(aled);
+	kfree(aled);
+}
+
+static void
+ar8327_leds_init(struct ar8xxx_priv *priv)
+{
+	struct ar8327_data *data = priv->chip_data;
+	unsigned i;
+
+	if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
+		return;
+
+	for (i = 0; i < data->num_leds; i++) {
+		struct ar8327_led *aled;
+
+		aled = data->leds[i];
+
+		if (aled->enable_hw_mode)
+			aled->pattern = AR8327_LED_PATTERN_RULE;
+		else
+			aled->pattern = AR8327_LED_PATTERN_OFF;
+
+		ar8327_set_led_pattern(priv, aled->led_num, aled->pattern);
+	}
+}
+
+static void
+ar8327_leds_cleanup(struct ar8xxx_priv *priv)
+{
+	struct ar8327_data *data = priv->chip_data;
+	unsigned i;
+
+	if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
+		return;
+
+	for (i = 0; i < data->num_leds; i++) {
+		struct ar8327_led *aled;
+
+		aled = data->leds[i];
+		ar8327_led_destroy(aled);
+	}
+
+	kfree(data->leds);
+}
+
+static int
+ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
+		       struct ar8327_platform_data *pdata)
+{
+	struct ar8327_led_cfg *led_cfg;
+	struct ar8327_data *data = priv->chip_data;
+	u32 pos, new_pos;
+	u32 t;
+
+	if (!pdata)
+		return -EINVAL;
+
+	priv->get_port_link = pdata->get_port_link;
+
+	data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg);
+	data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg);
+
+	t = ar8327_get_pad_cfg(pdata->pad0_cfg);
+	if (chip_is_ar8337(priv) && !pdata->pad0_cfg->mac06_exchange_dis)
+	    t |= AR8337_PAD_MAC06_EXCHANGE_EN;
+	ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t);
+
+	t = ar8327_get_pad_cfg(pdata->pad5_cfg);
+	ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t);
+	t = ar8327_get_pad_cfg(pdata->pad6_cfg);
+	ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t);
+
+	pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRIP);
+	new_pos = pos;
+
+	led_cfg = pdata->led_cfg;
+	if (led_cfg) {
+		if (led_cfg->open_drain)
+			new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN;
+		else
+			new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN;
+
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0);
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1);
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2);
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3);
+
+		if (new_pos != pos)
+			new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL;
+	}
+
+	if (pdata->sgmii_cfg) {
+		t = pdata->sgmii_cfg->sgmii_ctrl;
+		if (priv->chip_rev == 1)
+			t |= AR8327_SGMII_CTRL_EN_PLL |
+			     AR8327_SGMII_CTRL_EN_RX |
+			     AR8327_SGMII_CTRL_EN_TX;
+		else
+			t &= ~(AR8327_SGMII_CTRL_EN_PLL |
+			       AR8327_SGMII_CTRL_EN_RX |
+			       AR8327_SGMII_CTRL_EN_TX);
+
+		ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t);
+
+		if (pdata->sgmii_cfg->serdes_aen)
+			new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN;
+		else
+			new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN;
+	}
+
+	ar8xxx_write(priv, AR8327_REG_POWER_ON_STRIP, new_pos);
+
+	if (pdata->leds && pdata->num_leds) {
+		int i;
+
+		data->leds = kzalloc(pdata->num_leds * sizeof(void *),
+				     GFP_KERNEL);
+		if (!data->leds)
+			return -ENOMEM;
+
+		for (i = 0; i < pdata->num_leds; i++)
+			ar8327_led_create(priv, &pdata->leds[i]);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int
+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
+{
+	struct ar8327_data *data = priv->chip_data;
+	const __be32 *paddr;
+	int len;
+	int i;
+
+	paddr = of_get_property(np, "qca,ar8327-initvals", &len);
+	if (!paddr || len < (2 * sizeof(*paddr)))
+		return -EINVAL;
+
+	len /= sizeof(*paddr);
+
+	for (i = 0; i < len - 1; i += 2) {
+		u32 reg;
+		u32 val;
+
+		reg = be32_to_cpup(paddr + i);
+		val = be32_to_cpup(paddr + i + 1);
+
+		switch (reg) {
+		case AR8327_REG_PORT_STATUS(0):
+			data->port0_status = val;
+			break;
+		case AR8327_REG_PORT_STATUS(6):
+			data->port6_status = val;
+			break;
+		default:
+			ar8xxx_write(priv, reg, val);
+			break;
+		}
+	}
+
+	return 0;
+}
+#else
+static inline int
+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
+{
+	return -EINVAL;
+}
+#endif
+
+static int
+ar8327_hw_init(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL);
+	if (!priv->chip_data)
+		return -ENOMEM;
+
+	if (priv->phy->dev.of_node)
+		ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node);
+	else
+		ret = ar8327_hw_config_pdata(priv,
+					     priv->phy->dev.platform_data);
+
+	if (ret)
+		return ret;
+
+	ar8327_leds_init(priv);
+
+	ar8xxx_phy_init(priv);
+
+	return 0;
+}
+
+static void
+ar8327_cleanup(struct ar8xxx_priv *priv)
+{
+	ar8327_leds_cleanup(priv);
+}
+
+static void
+ar8327_init_globals(struct ar8xxx_priv *priv)
+{
+	struct ar8327_data *data = priv->chip_data;
+	u32 t;
+	int i;
+
+	/* enable CPU port and disable mirror port */
+	t = AR8327_FWD_CTRL0_CPU_PORT_EN |
+	    AR8327_FWD_CTRL0_MIRROR_PORT;
+	ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t);
+
+	/* forward multicast and broadcast frames to CPU */
+	t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) |
+	    (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) |
+	    (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S);
+	ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t);
+
+	/* enable jumbo frames */
+	ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE,
+		   AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2);
+
+	/* Enable MIB counters */
+	ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
+		       AR8327_MODULE_EN_MIB);
+
+	/* Disable EEE on all phy's due to stability issues */
+	for (i = 0; i < AR8XXX_NUM_PHYS; i++)
+		data->eee[i] = false;
+}
+
+static void
+ar8327_init_port(struct ar8xxx_priv *priv, int port)
+{
+	struct ar8327_data *data = priv->chip_data;
+	u32 t;
+
+	if (port == AR8216_PORT_CPU)
+		t = data->port0_status;
+	else if (port == 6)
+		t = data->port6_status;
+	else
+		t = AR8216_PORT_STATUS_LINK_AUTO;
+
+	if (port != AR8216_PORT_CPU && port != 6) {
+		/*hw limitation:if configure mac when there is traffic,
+		port MAC may work abnormal. Need disable lan&wan mac at fisrt*/
+		ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), 0);
+		msleep(100);
+		t |= AR8216_PORT_STATUS_FLOW_CONTROL;
+		ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t);
+	} else {
+		ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t);
+	}
+
+	ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0);
+
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), 0);
+
+	t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t);
+
+	t = AR8327_PORT_LOOKUP_LEARN;
+	t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t);
+}
+
+static u32
+ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
+{
+	u32 t;
+
+	t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port));
+	/* map the flow control autoneg result bits to the flow control bits
+	 * used in forced mode to allow ar8216_read_port_link detect
+	 * flow control properly if autoneg is used
+	 */
+	if (t & AR8216_PORT_STATUS_LINK_UP &&
+	    t & AR8216_PORT_STATUS_LINK_AUTO) {
+		t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW);
+		if (t & AR8327_PORT_STATUS_TXFLOW_AUTO)
+			t |= AR8216_PORT_STATUS_TXFLOW;
+		if (t & AR8327_PORT_STATUS_RXFLOW_AUTO)
+			t |= AR8216_PORT_STATUS_RXFLOW;
+	}
+
+	return t;
+}
+
+static u32
+ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port)
+{
+	int phy;
+	u16 t;
+
+	if (port >= priv->dev.ports)
+		return 0;
+
+	if (port == 0 || port == 6)
+		return 0;
+
+	phy = port - 1;
+
+	/* EEE Ability Auto-negotiation Result */
+	t = ar8xxx_phy_mmd_read(priv, phy, 0x7, 0x8000);
+
+	return mmd_eee_adv_to_ethtool_adv_t(t);
+}
+
+static int
+ar8327_atu_flush(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
+			      AR8327_ATU_FUNC_BUSY, 0);
+	if (!ret)
+		ar8xxx_write(priv, AR8327_REG_ATU_FUNC,
+			     AR8327_ATU_FUNC_OP_FLUSH |
+			     AR8327_ATU_FUNC_BUSY);
+
+	return ret;
+}
+
+static int
+ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port)
+{
+	u32 t;
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
+			      AR8327_ATU_FUNC_BUSY, 0);
+	if (!ret) {
+		t = (port << AR8327_ATU_PORT_NUM_S);
+		t |= AR8327_ATU_FUNC_OP_FLUSH_PORT;
+		t |= AR8327_ATU_FUNC_BUSY;
+		ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t);
+	}
+
+	return ret;
+}
+
+static int
+ar8327_get_port_igmp(struct ar8xxx_priv *priv, int port)
+{
+	u32 fwd_ctrl, frame_ack;
+
+	fwd_ctrl = (BIT(port) << AR8327_FWD_CTRL1_IGMP_S);
+	frame_ack = ((AR8327_FRAME_ACK_CTRL_IGMP_MLD |
+		      AR8327_FRAME_ACK_CTRL_IGMP_JOIN |
+		      AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) <<
+		     AR8327_FRAME_ACK_CTRL_S(port));
+
+	return (ar8xxx_read(priv, AR8327_REG_FWD_CTRL1) &
+			fwd_ctrl) == fwd_ctrl &&
+		(ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL(port)) &
+			frame_ack) == frame_ack;
+}
+
+static void
+ar8327_set_port_igmp(struct ar8xxx_priv *priv, int port, int enable)
+{
+	int reg_frame_ack = AR8327_REG_FRAME_ACK_CTRL(port);
+	u32 val_frame_ack = (AR8327_FRAME_ACK_CTRL_IGMP_MLD |
+			  AR8327_FRAME_ACK_CTRL_IGMP_JOIN |
+			  AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) <<
+			 AR8327_FRAME_ACK_CTRL_S(port);
+
+	if (enable) {
+		ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1,
+			   BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S,
+			   BIT(port) << AR8327_FWD_CTRL1_IGMP_S);
+		ar8xxx_reg_set(priv, reg_frame_ack, val_frame_ack);
+	} else {
+		ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1,
+			   BIT(port) << AR8327_FWD_CTRL1_IGMP_S,
+			   BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S);
+		ar8xxx_reg_clear(priv, reg_frame_ack, val_frame_ack);
+	}
+}
+
+static void
+ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
+{
+	if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1,
+			    AR8327_VTU_FUNC1_BUSY, 0))
+		return;
+
+	if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD)
+		ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val);
+
+	op |= AR8327_VTU_FUNC1_BUSY;
+	ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op);
+}
+
+static void
+ar8327_vtu_flush(struct ar8xxx_priv *priv)
+{
+	ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0);
+}
+
+static void
+ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
+{
+	u32 op;
+	u32 val;
+	int i;
+
+	op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S);
+	val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL;
+	for (i = 0; i < AR8327_NUM_PORTS; i++) {
+		u32 mode;
+
+		if ((port_mask & BIT(i)) == 0)
+			mode = AR8327_VTU_FUNC0_EG_MODE_NOT;
+		else if (priv->vlan == 0)
+			mode = AR8327_VTU_FUNC0_EG_MODE_KEEP;
+		else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid))
+			mode = AR8327_VTU_FUNC0_EG_MODE_TAG;
+		else
+			mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG;
+
+		val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i);
+	}
+	ar8327_vtu_op(priv, op, val);
+}
+
+static void
+ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	u32 t;
+	u32 egress, ingress;
+	u32 pvid = priv->vlan_id[priv->pvid[port]];
+
+	if (priv->vlan) {
+		egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD;
+		ingress = AR8216_IN_SECURE;
+	} else {
+		egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
+		ingress = AR8216_IN_PORT_ONLY;
+	}
+
+	t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
+	t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t);
+
+	t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
+	t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t);
+
+	t = members;
+	t |= AR8327_PORT_LOOKUP_LEARN;
+	t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S;
+	t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t);
+}
+
+static int
+ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 ports = priv->vlan_table[val->port_vlan];
+	int i;
+
+	val->len = 0;
+	for (i = 0; i < dev->ports; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int
+ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 *vt = &priv->vlan_table[val->port_vlan];
+	int i;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+			if (val->port_vlan == priv->pvid[p->id]) {
+				priv->vlan_tagged |= (1 << p->id);
+			}
+		} else {
+			priv->vlan_tagged &= ~(1 << p->id);
+			priv->pvid[p->id] = val->port_vlan;
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static void
+ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+	int port;
+
+	/* reset all mirror registers */
+	ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
+		   AR8327_FWD_CTRL0_MIRROR_PORT,
+		   (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));
+	for (port = 0; port < AR8327_NUM_PORTS; port++) {
+		ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port),
+			   AR8327_PORT_LOOKUP_ING_MIRROR_EN);
+
+		ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port),
+			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
+	}
+
+	/* now enable mirroring if necessary */
+	if (priv->source_port >= AR8327_NUM_PORTS ||
+	    priv->monitor_port >= AR8327_NUM_PORTS ||
+	    priv->source_port == priv->monitor_port) {
+		return;
+	}
+
+	ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
+		   AR8327_FWD_CTRL0_MIRROR_PORT,
+		   (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S));
+
+	if (priv->mirror_rx)
+		ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
+			   AR8327_PORT_LOOKUP_ING_MIRROR_EN);
+
+	if (priv->mirror_tx)
+		ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port),
+			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
+}
+
+static int
+ar8327_sw_set_eee(struct switch_dev *dev,
+		  const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	struct ar8327_data *data = priv->chip_data;
+	int port = val->port_vlan;
+	int phy;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+	if (port == 0 || port == 6)
+		return -EOPNOTSUPP;
+
+	phy = port - 1;
+
+	data->eee[phy] = !!(val->value.i);
+
+	return 0;
+}
+
+static int
+ar8327_sw_get_eee(struct switch_dev *dev,
+		  const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8327_data *data = priv->chip_data;
+	int port = val->port_vlan;
+	int phy;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+	if (port == 0 || port == 6)
+		return -EOPNOTSUPP;
+
+	phy = port - 1;
+
+	val->value.i = data->eee[phy];
+
+	return 0;
+}
+
+static void
+ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
+{
+	int timeout = 20;
+
+	while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout)
+                udelay(10);
+
+	if (!timeout)
+		pr_err("ar8327: timeout waiting for atu to become ready\n");
+}
+
+static void ar8327_get_arl_entry(struct ar8xxx_priv *priv,
+				 struct arl_entry *a, u32 *status, enum arl_op op)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r2, page;
+	u16 r1_data0, r1_data1, r1_data2, r1_func;
+	u32 t, val0, val1, val2;
+	int i;
+
+	split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page);
+	r2 |= 0x10;
+
+	r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e;
+	r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e;
+	r1_func  = (AR8327_REG_ATU_FUNC >> 1) & 0x1e;
+
+	switch (op) {
+	case AR8XXX_ARL_INITIALIZE:
+		/* all ATU registers are on the same page
+		* therefore set page only once
+		*/
+		bus->write(bus, 0x18, 0, page);
+		wait_for_page_switch();
+
+		ar8327_wait_atu_ready(priv, r2, r1_func);
+
+		ar8xxx_mii_write32(priv, r2, r1_data0, 0);
+		ar8xxx_mii_write32(priv, r2, r1_data1, 0);
+		ar8xxx_mii_write32(priv, r2, r1_data2, 0);
+		break;
+	case AR8XXX_ARL_GET_NEXT:
+		ar8xxx_mii_write32(priv, r2, r1_func,
+				   AR8327_ATU_FUNC_OP_GET_NEXT |
+				   AR8327_ATU_FUNC_BUSY);
+		ar8327_wait_atu_ready(priv, r2, r1_func);
+
+		val0 = ar8xxx_mii_read32(priv, r2, r1_data0);
+		val1 = ar8xxx_mii_read32(priv, r2, r1_data1);
+		val2 = ar8xxx_mii_read32(priv, r2, r1_data2);
+
+		*status = val2 & AR8327_ATU_STATUS;
+		if (!*status)
+			break;
+
+		i = 0;
+		t = AR8327_ATU_PORT0;
+		while (!(val1 & t) && ++i < AR8327_NUM_PORTS)
+			t <<= 1;
+
+		a->port = i;
+		a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S;
+		a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S;
+		a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S;
+		a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S;
+		a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S;
+		a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S;
+		break;
+	}
+}
+
+static int
+ar8327_sw_hw_apply(struct switch_dev *dev)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8327_data *data = priv->chip_data;
+	int ret, i;
+
+	ret = ar8xxx_sw_hw_apply(dev);
+	if (ret)
+		return ret;
+
+	for (i=0; i < AR8XXX_NUM_PHYS; i++) {
+		if (data->eee[i])
+			ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL,
+			       AR8327_EEE_CTRL_DISABLE_PHY(i));
+		else
+			ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL,
+			       AR8327_EEE_CTRL_DISABLE_PHY(i));
+	}
+
+	return 0;
+}
+
+int
+ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = ar8327_get_port_igmp(priv, port);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	ar8327_set_port_igmp(priv, port, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	int port;
+
+	for (port = 0; port < dev->ports; port++) {
+		val->port_vlan = port;
+		if (ar8327_sw_get_port_igmp_snooping(dev, attr, val) ||
+		    !val->value.i)
+			break;
+	}
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	int port;
+
+	for (port = 0; port < dev->ports; port++) {
+		val->port_vlan = port;
+		if (ar8327_sw_set_port_igmp_snooping(dev, attr, val))
+			break;
+	}
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_v3(struct switch_dev *dev,
+		      const struct switch_attr *attr,
+		      struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u32 val_reg;
+
+	mutex_lock(&priv->reg_mutex);
+	val_reg = ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL1);
+	val->value.i = ((val_reg & AR8327_FRAME_ACK_CTRL_IGMP_V3_EN) != 0);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_v3(struct switch_dev *dev,
+		      const struct switch_attr *attr,
+		      struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	if (val->value.i)
+		ar8xxx_reg_set(priv, AR8327_REG_FRAME_ACK_CTRL1,
+			       AR8327_FRAME_ACK_CTRL_IGMP_V3_EN);
+	else
+		ar8xxx_reg_clear(priv, AR8327_REG_FRAME_ACK_CTRL1,
+				 AR8327_FRAME_ACK_CTRL_IGMP_V3_EN);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+static const struct switch_attr ar8327_sw_attr_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = ar8xxx_sw_set_vlan,
+		.get = ar8xxx_sw_get_vlan,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = ar8xxx_sw_set_reset_mibs,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_rx",
+		.description = "Enable mirroring of RX packets",
+		.set = ar8xxx_sw_set_mirror_rx_enable,
+		.get = ar8xxx_sw_get_mirror_rx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_tx",
+		.description = "Enable mirroring of TX packets",
+		.set = ar8xxx_sw_set_mirror_tx_enable,
+		.get = ar8xxx_sw_get_mirror_tx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_monitor_port",
+		.description = "Mirror monitor port",
+		.set = ar8xxx_sw_set_mirror_monitor_port,
+		.get = ar8xxx_sw_get_mirror_monitor_port,
+		.max = AR8327_NUM_PORTS - 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_source_port",
+		.description = "Mirror source port",
+		.set = ar8xxx_sw_set_mirror_source_port,
+		.get = ar8xxx_sw_get_mirror_source_port,
+		.max = AR8327_NUM_PORTS - 1
+ 	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "arl_age_time",
+		.description = "ARL age time (secs)",
+		.set = ar8xxx_sw_set_arl_age_time,
+		.get = ar8xxx_sw_get_arl_age_time,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "arl_table",
+		.description = "Get ARL table",
+		.set = NULL,
+		.get = ar8xxx_sw_get_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush ARL table",
+		.set = ar8xxx_sw_set_flush_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_snooping",
+		.description = "Enable IGMP Snooping",
+		.set = ar8327_sw_set_igmp_snooping,
+		.get = ar8327_sw_get_igmp_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_v3",
+		.description = "Enable IGMPv3 support",
+		.set = ar8327_sw_set_igmp_v3,
+		.get = ar8327_sw_get_igmp_v3,
+		.max = 1
+	},
+};
+
+static const struct switch_attr ar8327_sw_attr_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = ar8xxx_sw_set_port_reset_mib,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get port's MIB counters",
+		.set = NULL,
+		.get = ar8xxx_sw_get_port_mib,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_eee",
+		.description = "Enable EEE PHY sleep mode",
+		.set = ar8327_sw_set_eee,
+		.get = ar8327_sw_get_eee,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush port's ARL table entries",
+		.set = ar8xxx_sw_set_flush_port_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_snooping",
+		.description = "Enable port's IGMP Snooping",
+		.set = ar8327_sw_set_port_igmp_snooping,
+		.get = ar8327_sw_get_port_igmp_snooping,
+		.max = 1
+	},
+};
+
+static const struct switch_dev_ops ar8327_sw_ops = {
+	.attr_global = {
+		.attr = ar8327_sw_attr_globals,
+		.n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
+	},
+	.attr_port = {
+		.attr = ar8327_sw_attr_port,
+		.n_attr = ARRAY_SIZE(ar8327_sw_attr_port),
+	},
+	.attr_vlan = {
+		.attr = ar8xxx_sw_attr_vlan,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
+	},
+	.get_port_pvid = ar8xxx_sw_get_pvid,
+	.set_port_pvid = ar8xxx_sw_set_pvid,
+	.get_vlan_ports = ar8327_sw_get_ports,
+	.set_vlan_ports = ar8327_sw_set_ports,
+	.apply_config = ar8327_sw_hw_apply,
+	.reset_switch = ar8xxx_sw_reset_switch,
+	.get_port_link = ar8xxx_sw_get_port_link,
+};
+
+const struct ar8xxx_chip ar8327_chip = {
+	.caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
+	.config_at_probe = true,
+	.mii_lo_first = true,
+
+	.name = "Atheros AR8327",
+	.ports = AR8327_NUM_PORTS,
+	.vlans = AR8X16_MAX_VLANS,
+	.swops = &ar8327_sw_ops,
+
+	.reg_port_stats_start = 0x1000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8327_REG_ARL_CTRL,
+
+	.hw_init = ar8327_hw_init,
+	.cleanup = ar8327_cleanup,
+	.init_globals = ar8327_init_globals,
+	.init_port = ar8327_init_port,
+	.setup_port = ar8327_setup_port,
+	.read_port_status = ar8327_read_port_status,
+	.read_port_eee_status = ar8327_read_port_eee_status,
+	.atu_flush = ar8327_atu_flush,
+	.atu_flush_port = ar8327_atu_flush_port,
+	.vtu_flush = ar8327_vtu_flush,
+	.vtu_load_vlan = ar8327_vtu_load_vlan,
+	.phy_fixup = ar8327_phy_fixup,
+	.set_mirror_regs = ar8327_set_mirror_regs,
+	.get_arl_entry = ar8327_get_arl_entry,
+	.sw_hw_apply = ar8327_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8327_REG_MIB_FUNC
+};
+
+const struct ar8xxx_chip ar8337_chip = {
+	.caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
+	.config_at_probe = true,
+	.mii_lo_first = true,
+
+	.name = "Atheros AR8337",
+	.ports = AR8327_NUM_PORTS,
+	.vlans = AR8X16_MAX_VLANS,
+	.swops = &ar8327_sw_ops,
+
+	.reg_port_stats_start = 0x1000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8327_REG_ARL_CTRL,
+
+	.hw_init = ar8327_hw_init,
+	.cleanup = ar8327_cleanup,
+	.init_globals = ar8327_init_globals,
+	.init_port = ar8327_init_port,
+	.setup_port = ar8327_setup_port,
+	.read_port_status = ar8327_read_port_status,
+	.read_port_eee_status = ar8327_read_port_eee_status,
+	.atu_flush = ar8327_atu_flush,
+	.atu_flush_port = ar8327_atu_flush_port,
+	.vtu_flush = ar8327_vtu_flush,
+	.vtu_load_vlan = ar8327_vtu_load_vlan,
+	.phy_fixup = ar8327_phy_fixup,
+	.set_mirror_regs = ar8327_set_mirror_regs,
+	.get_arl_entry = ar8327_get_arl_entry,
+	.sw_hw_apply = ar8327_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8327_REG_MIB_FUNC
+};
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h b/target/linux/generic/files/drivers/net/phy/ar8327.h
new file mode 100644
index 0000000000..7bce18bfb8
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
@@ -0,0 +1,319 @@
+/*
+ * ar8327.h: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AR8327_H
+#define __AR8327_H
+
+#define AR8327_NUM_PORTS	7
+#define AR8327_NUM_LEDS		15
+#define AR8327_PORTS_ALL	0x7f
+#define AR8327_NUM_LED_CTRL_REGS	4
+
+#define AR8327_REG_MASK				0x000
+
+#define AR8327_REG_PAD0_MODE			0x004
+#define AR8327_REG_PAD5_MODE			0x008
+#define AR8327_REG_PAD6_MODE			0x00c
+#define   AR8327_PAD_MAC_MII_RXCLK_SEL		BIT(0)
+#define   AR8327_PAD_MAC_MII_TXCLK_SEL		BIT(1)
+#define   AR8327_PAD_MAC_MII_EN			BIT(2)
+#define   AR8327_PAD_MAC_GMII_RXCLK_SEL		BIT(4)
+#define   AR8327_PAD_MAC_GMII_TXCLK_SEL		BIT(5)
+#define   AR8327_PAD_MAC_GMII_EN		BIT(6)
+#define   AR8327_PAD_SGMII_EN			BIT(7)
+#define   AR8327_PAD_PHY_MII_RXCLK_SEL		BIT(8)
+#define   AR8327_PAD_PHY_MII_TXCLK_SEL		BIT(9)
+#define   AR8327_PAD_PHY_MII_EN			BIT(10)
+#define   AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL	BIT(11)
+#define   AR8327_PAD_PHY_GMII_RXCLK_SEL		BIT(12)
+#define   AR8327_PAD_PHY_GMII_TXCLK_SEL		BIT(13)
+#define   AR8327_PAD_PHY_GMII_EN		BIT(14)
+#define   AR8327_PAD_PHYX_GMII_EN		BIT(16)
+#define   AR8327_PAD_PHYX_RGMII_EN		BIT(17)
+#define   AR8327_PAD_PHYX_MII_EN		BIT(18)
+#define   AR8327_PAD_SGMII_DELAY_EN		BIT(19)
+#define   AR8327_PAD_RGMII_RXCLK_DELAY_SEL	BITS(20, 2)
+#define   AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S	20
+#define   AR8327_PAD_RGMII_TXCLK_DELAY_SEL	BITS(22, 2)
+#define   AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S	22
+#define   AR8327_PAD_RGMII_RXCLK_DELAY_EN	BIT(24)
+#define   AR8327_PAD_RGMII_TXCLK_DELAY_EN	BIT(25)
+#define   AR8327_PAD_RGMII_EN			BIT(26)
+
+#define AR8327_REG_POWER_ON_STRIP		0x010
+#define   AR8327_POWER_ON_STRIP_POWER_ON_SEL	BIT(31)
+#define   AR8327_POWER_ON_STRIP_LED_OPEN_EN	BIT(24)
+#define   AR8327_POWER_ON_STRIP_SERDES_AEN	BIT(7)
+
+#define AR8327_REG_INT_STATUS0			0x020
+#define   AR8327_INT0_VT_DONE			BIT(20)
+
+#define AR8327_REG_INT_STATUS1			0x024
+#define AR8327_REG_INT_MASK0			0x028
+#define AR8327_REG_INT_MASK1			0x02c
+
+#define AR8327_REG_MODULE_EN			0x030
+#define   AR8327_MODULE_EN_MIB			BIT(0)
+
+#define AR8327_REG_MIB_FUNC			0x034
+#define   AR8327_MIB_CPU_KEEP			BIT(20)
+
+#define AR8327_REG_SERVICE_TAG			0x048
+#define AR8327_REG_LED_CTRL(_i)			(0x050 + (_i) * 4)
+#define AR8327_REG_LED_CTRL0			0x050
+#define AR8327_REG_LED_CTRL1			0x054
+#define AR8327_REG_LED_CTRL2			0x058
+#define AR8327_REG_LED_CTRL3			0x05c
+#define AR8327_REG_MAC_ADDR0			0x060
+#define AR8327_REG_MAC_ADDR1			0x064
+
+#define AR8327_REG_MAX_FRAME_SIZE		0x078
+#define   AR8327_MAX_FRAME_SIZE_MTU		BITS(0, 14)
+
+#define AR8327_REG_PORT_STATUS(_i)		(0x07c + (_i) * 4)
+#define   AR8327_PORT_STATUS_TXFLOW_AUTO	BIT(10)
+#define   AR8327_PORT_STATUS_RXFLOW_AUTO	BIT(11)
+
+#define AR8327_REG_HEADER_CTRL			0x098
+#define AR8327_REG_PORT_HEADER(_i)		(0x09c + (_i) * 4)
+
+#define AR8327_REG_SGMII_CTRL			0x0e0
+#define   AR8327_SGMII_CTRL_EN_PLL		BIT(1)
+#define   AR8327_SGMII_CTRL_EN_RX		BIT(2)
+#define   AR8327_SGMII_CTRL_EN_TX		BIT(3)
+
+#define AR8327_REG_EEE_CTRL			0x100
+#define   AR8327_EEE_CTRL_DISABLE_PHY(_i)	BIT(4 + (_i) * 2)
+
+#define AR8327_REG_FRAME_ACK_CTRL0		0x210
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN0	BIT(0)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN0	BIT(1)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN0	BIT(2)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN0	BIT(3)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN0	BIT(4)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN0	BIT(5)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN0	BIT(6)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN1	BIT(8)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN1	BIT(9)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN1	BIT(10)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN1	BIT(11)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN1	BIT(12)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN1	BIT(13)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN1	BIT(14)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN2	BIT(16)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN2	BIT(17)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN2	BIT(18)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN2	BIT(19)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN2	BIT(20)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN2	BIT(21)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN2	BIT(22)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN3	BIT(24)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN3	BIT(25)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN3	BIT(26)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN3	BIT(27)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN3	BIT(28)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN3	BIT(29)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN3	BIT(30)
+
+#define AR8327_REG_FRAME_ACK_CTRL1		0x214
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN4	BIT(0)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN4	BIT(1)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN4	BIT(2)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN4	BIT(3)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN4	BIT(4)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN4	BIT(5)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN4	BIT(6)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN5	BIT(8)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN5	BIT(9)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN5	BIT(10)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN5	BIT(11)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN5	BIT(12)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN5	BIT(13)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN5	BIT(14)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN6	BIT(16)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN6	BIT(17)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN6	BIT(18)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN6	BIT(19)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN6	BIT(20)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN6	BIT(21)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN6	BIT(22)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_V3_EN	BIT(24)
+#define   AR8327_FRAME_ACK_CTRL_PPPOE_EN	BIT(25)
+
+#define AR8327_REG_FRAME_ACK_CTRL(_i)		(0x210 + ((_i) / 4) * 0x4)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD	BIT(0)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN	BIT(1)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE	BIT(2)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL		BIT(3)
+#define   AR8327_FRAME_ACK_CTRL_DHCP		BIT(4)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK		BIT(5)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ		BIT(6)
+#define   AR8327_FRAME_ACK_CTRL_S(_i)		(((_i) % 4) * 8)
+
+#define AR8327_REG_PORT_VLAN0(_i)		(0x420 + (_i) * 0x8)
+#define   AR8327_PORT_VLAN0_DEF_SVID		BITS(0, 12)
+#define   AR8327_PORT_VLAN0_DEF_SVID_S		0
+#define   AR8327_PORT_VLAN0_DEF_CVID		BITS(16, 12)
+#define   AR8327_PORT_VLAN0_DEF_CVID_S		16
+
+#define AR8327_REG_PORT_VLAN1(_i)		(0x424 + (_i) * 0x8)
+#define   AR8327_PORT_VLAN1_PORT_VLAN_PROP	BIT(6)
+#define   AR8327_PORT_VLAN1_OUT_MODE		BITS(12, 2)
+#define   AR8327_PORT_VLAN1_OUT_MODE_S		12
+#define   AR8327_PORT_VLAN1_OUT_MODE_UNMOD	0
+#define   AR8327_PORT_VLAN1_OUT_MODE_UNTAG	1
+#define   AR8327_PORT_VLAN1_OUT_MODE_TAG	2
+#define   AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH	3
+
+#define AR8327_REG_ATU_DATA0			0x600
+#define   AR8327_ATU_ADDR0			BITS(0, 8)
+#define   AR8327_ATU_ADDR0_S			0
+#define   AR8327_ATU_ADDR1			BITS(8, 8)
+#define   AR8327_ATU_ADDR1_S			8
+#define   AR8327_ATU_ADDR2			BITS(16, 8)
+#define   AR8327_ATU_ADDR2_S			16
+#define   AR8327_ATU_ADDR3			BITS(24, 8)
+#define   AR8327_ATU_ADDR3_S			24
+#define AR8327_REG_ATU_DATA1			0x604
+#define   AR8327_ATU_ADDR4			BITS(0, 8)
+#define   AR8327_ATU_ADDR4_S			0
+#define   AR8327_ATU_ADDR5			BITS(8, 8)
+#define   AR8327_ATU_ADDR5_S			8
+#define   AR8327_ATU_PORTS			BITS(16, 7)
+#define   AR8327_ATU_PORT0			BIT(16)
+#define   AR8327_ATU_PORT1			BIT(17)
+#define   AR8327_ATU_PORT2			BIT(18)
+#define   AR8327_ATU_PORT3			BIT(19)
+#define   AR8327_ATU_PORT4			BIT(20)
+#define   AR8327_ATU_PORT5			BIT(21)
+#define   AR8327_ATU_PORT6			BIT(22)
+#define AR8327_REG_ATU_DATA2			0x608
+#define   AR8327_ATU_STATUS			BITS(0, 4)
+
+#define AR8327_REG_ATU_FUNC			0x60c
+#define   AR8327_ATU_FUNC_OP			BITS(0, 4)
+#define   AR8327_ATU_FUNC_OP_NOOP		0x0
+#define   AR8327_ATU_FUNC_OP_FLUSH		0x1
+#define   AR8327_ATU_FUNC_OP_LOAD		0x2
+#define   AR8327_ATU_FUNC_OP_PURGE		0x3
+#define   AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED	0x4
+#define   AR8327_ATU_FUNC_OP_FLUSH_PORT		0x5
+#define   AR8327_ATU_FUNC_OP_GET_NEXT		0x6
+#define   AR8327_ATU_FUNC_OP_SEARCH_MAC		0x7
+#define   AR8327_ATU_FUNC_OP_CHANGE_TRUNK	0x8
+#define   AR8327_ATU_PORT_NUM			BITS(8, 4)
+#define   AR8327_ATU_PORT_NUM_S			8
+#define   AR8327_ATU_FUNC_BUSY			BIT(31)
+
+#define AR8327_REG_VTU_FUNC0			0x0610
+#define   AR8327_VTU_FUNC0_EG_MODE		BITS(4, 14)
+#define   AR8327_VTU_FUNC0_EG_MODE_S(_i)	(4 + (_i) * 2)
+#define   AR8327_VTU_FUNC0_EG_MODE_KEEP		0
+#define   AR8327_VTU_FUNC0_EG_MODE_UNTAG	1
+#define   AR8327_VTU_FUNC0_EG_MODE_TAG		2
+#define   AR8327_VTU_FUNC0_EG_MODE_NOT		3
+#define   AR8327_VTU_FUNC0_IVL			BIT(19)
+#define   AR8327_VTU_FUNC0_VALID		BIT(20)
+
+#define AR8327_REG_VTU_FUNC1			0x0614
+#define   AR8327_VTU_FUNC1_OP			BITS(0, 3)
+#define   AR8327_VTU_FUNC1_OP_NOOP		0
+#define   AR8327_VTU_FUNC1_OP_FLUSH		1
+#define   AR8327_VTU_FUNC1_OP_LOAD		2
+#define   AR8327_VTU_FUNC1_OP_PURGE		3
+#define   AR8327_VTU_FUNC1_OP_REMOVE_PORT	4
+#define   AR8327_VTU_FUNC1_OP_GET_NEXT		5
+#define   AR8327_VTU_FUNC1_OP_GET_ONE		6
+#define   AR8327_VTU_FUNC1_FULL			BIT(4)
+#define   AR8327_VTU_FUNC1_PORT			BIT(8, 4)
+#define   AR8327_VTU_FUNC1_PORT_S		8
+#define   AR8327_VTU_FUNC1_VID			BIT(16, 12)
+#define   AR8327_VTU_FUNC1_VID_S		16
+#define   AR8327_VTU_FUNC1_BUSY			BIT(31)
+
+#define AR8327_REG_ARL_CTRL			0x0618
+
+#define AR8327_REG_FWD_CTRL0			0x620
+#define   AR8327_FWD_CTRL0_CPU_PORT_EN		BIT(10)
+#define   AR8327_FWD_CTRL0_MIRROR_PORT		BITS(4, 4)
+#define   AR8327_FWD_CTRL0_MIRROR_PORT_S	4
+
+#define AR8327_REG_FWD_CTRL1			0x624
+#define   AR8327_FWD_CTRL1_UC_FLOOD		BITS(0, 7)
+#define   AR8327_FWD_CTRL1_UC_FLOOD_S		0
+#define   AR8327_FWD_CTRL1_MC_FLOOD		BITS(8, 7)
+#define   AR8327_FWD_CTRL1_MC_FLOOD_S		8
+#define   AR8327_FWD_CTRL1_BC_FLOOD		BITS(16, 7)
+#define   AR8327_FWD_CTRL1_BC_FLOOD_S		16
+#define   AR8327_FWD_CTRL1_IGMP			BITS(24, 7)
+#define   AR8327_FWD_CTRL1_IGMP_S		24
+
+#define AR8327_REG_PORT_LOOKUP(_i)		(0x660 + (_i) * 0xc)
+#define   AR8327_PORT_LOOKUP_MEMBER		BITS(0, 7)
+#define   AR8327_PORT_LOOKUP_IN_MODE		BITS(8, 2)
+#define   AR8327_PORT_LOOKUP_IN_MODE_S		8
+#define   AR8327_PORT_LOOKUP_STATE		BITS(16, 3)
+#define   AR8327_PORT_LOOKUP_STATE_S		16
+#define   AR8327_PORT_LOOKUP_LEARN		BIT(20)
+#define   AR8327_PORT_LOOKUP_ING_MIRROR_EN	BIT(25)
+
+#define AR8327_REG_PORT_PRIO(_i)		(0x664 + (_i) * 0xc)
+
+#define AR8327_REG_PORT_HOL_CTRL1(_i)		(0x974 + (_i) * 0x8)
+#define   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN	BIT(16)
+
+#define AR8337_PAD_MAC06_EXCHANGE_EN		BIT(31)
+
+enum ar8327_led_pattern {
+	AR8327_LED_PATTERN_OFF = 0,
+	AR8327_LED_PATTERN_BLINK,
+	AR8327_LED_PATTERN_ON,
+	AR8327_LED_PATTERN_RULE,
+};
+
+struct ar8327_led_entry {
+	unsigned reg;
+	unsigned shift;
+};
+
+struct ar8327_led {
+	struct led_classdev cdev;
+	struct ar8xxx_priv *sw_priv;
+
+	char *name;
+	bool active_low;
+	u8 led_num;
+	enum ar8327_led_mode mode;
+
+	struct mutex mutex;
+	spinlock_t lock;
+	struct work_struct led_work;
+	bool enable_hw_mode;
+	enum ar8327_led_pattern pattern;
+};
+
+struct ar8327_data {
+	u32 port0_status;
+	u32 port6_status;
+
+	struct ar8327_led **leds;
+	unsigned int num_leds;
+
+	/* all fields below are cleared on reset */
+	bool eee[AR8XXX_NUM_PHYS];
+};
+
+#endif
diff --git a/target/linux/generic/files/drivers/net/phy/b53/Kconfig b/target/linux/generic/files/drivers/net/phy/b53/Kconfig
new file mode 100644
index 0000000000..08287e7adf
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/Kconfig
@@ -0,0 +1,37 @@
+menuconfig SWCONFIG_B53
+	tristate "Broadcom bcm53xx managed switch support"
+	depends on SWCONFIG
+	help
+	  This driver adds support for Broadcom managed switch chips. It supports
+	  BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
+	  integrated switches.
+
+config SWCONFIG_B53_SPI_DRIVER
+	tristate "B53 SPI connected switch driver"
+	depends on SWCONFIG_B53 && SPI
+	help
+	  Select to enable support for registering switches configured through SPI.
+
+config SWCONFIG_B53_PHY_DRIVER
+	tristate "B53 MDIO connected switch driver"
+	depends on SWCONFIG_B53
+	select SWCONFIG_B53_PHY_FIXUP
+	help
+	  Select to enable support for registering switches configured through MDIO.
+
+config SWCONFIG_B53_MMAP_DRIVER
+	tristate "B53 MMAP connected switch driver"
+	depends on SWCONFIG_B53
+	help
+	  Select to enable support for memory-mapped switches like the BCM63XX
+	  integrated switches.
+
+config SWCONFIG_B53_SRAB_DRIVER
+	tristate "B53 SRAB connected switch driver"
+	depends on SWCONFIG_B53
+	help
+	  Select to enable support for memory-mapped Switch Register Access
+	  Bridge Registers (SRAB) like it is found on the BCM53010
+
+config SWCONFIG_B53_PHY_FIXUP
+	bool
diff --git a/target/linux/generic/files/drivers/net/phy/b53/Makefile b/target/linux/generic/files/drivers/net/phy/b53/Makefile
new file mode 100644
index 0000000000..13ff366448
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_SWCONFIG_B53)		+= b53_common.o
+
+obj-$(CONFIG_SWCONFIG_B53_PHY_FIXUP)	+= b53_phy_fixup.o
+
+obj-$(CONFIG_SWCONFIG_B53_MMAP_DRIVER)	+= b53_mmap.o
+obj-$(CONFIG_SWCONFIG_B53_SRAB_DRIVER)	+= b53_srab.o
+obj-$(CONFIG_SWCONFIG_B53_PHY_DRIVER)	+= b53_mdio.o
+obj-$(CONFIG_SWCONFIG_B53_SPI_DRIVER)	+= b53_spi.o
+
+ccflags-y				+= -Werror
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
new file mode 100644
index 0000000000..b884010d28
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
@@ -0,0 +1,1526 @@
+/*
+ * B53 switch driver main logic
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/switch.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_regs.h"
+#include "b53_priv.h"
+
+/* buffer size needed for displaying all MIBs with max'd values */
+#define B53_BUF_SIZE	1188
+
+struct b53_mib_desc {
+	u8 size;
+	u8 offset;
+	const char *name;
+};
+
+
+/* BCM5365 MIB counters */
+static const struct b53_mib_desc b53_mibs_65[] = {
+	{ 8, 0x00, "TxOctets" },
+	{ 4, 0x08, "TxDropPkts" },
+	{ 4, 0x10, "TxBroadcastPkts" },
+	{ 4, 0x14, "TxMulticastPkts" },
+	{ 4, 0x18, "TxUnicastPkts" },
+	{ 4, 0x1c, "TxCollisions" },
+	{ 4, 0x20, "TxSingleCollision" },
+	{ 4, 0x24, "TxMultipleCollision" },
+	{ 4, 0x28, "TxDeferredTransmit" },
+	{ 4, 0x2c, "TxLateCollision" },
+	{ 4, 0x30, "TxExcessiveCollision" },
+	{ 4, 0x38, "TxPausePkts" },
+	{ 8, 0x44, "RxOctets" },
+	{ 4, 0x4c, "RxUndersizePkts" },
+	{ 4, 0x50, "RxPausePkts" },
+	{ 4, 0x54, "Pkts64Octets" },
+	{ 4, 0x58, "Pkts65to127Octets" },
+	{ 4, 0x5c, "Pkts128to255Octets" },
+	{ 4, 0x60, "Pkts256to511Octets" },
+	{ 4, 0x64, "Pkts512to1023Octets" },
+	{ 4, 0x68, "Pkts1024to1522Octets" },
+	{ 4, 0x6c, "RxOversizePkts" },
+	{ 4, 0x70, "RxJabbers" },
+	{ 4, 0x74, "RxAlignmentErrors" },
+	{ 4, 0x78, "RxFCSErrors" },
+	{ 8, 0x7c, "RxGoodOctets" },
+	{ 4, 0x84, "RxDropPkts" },
+	{ 4, 0x88, "RxUnicastPkts" },
+	{ 4, 0x8c, "RxMulticastPkts" },
+	{ 4, 0x90, "RxBroadcastPkts" },
+	{ 4, 0x94, "RxSAChanges" },
+	{ 4, 0x98, "RxFragments" },
+	{ },
+};
+
+/* BCM63xx MIB counters */
+static const struct b53_mib_desc b53_mibs_63xx[] = {
+	{ 8, 0x00, "TxOctets" },
+	{ 4, 0x08, "TxDropPkts" },
+	{ 4, 0x0c, "TxQoSPkts" },
+	{ 4, 0x10, "TxBroadcastPkts" },
+	{ 4, 0x14, "TxMulticastPkts" },
+	{ 4, 0x18, "TxUnicastPkts" },
+	{ 4, 0x1c, "TxCollisions" },
+	{ 4, 0x20, "TxSingleCollision" },
+	{ 4, 0x24, "TxMultipleCollision" },
+	{ 4, 0x28, "TxDeferredTransmit" },
+	{ 4, 0x2c, "TxLateCollision" },
+	{ 4, 0x30, "TxExcessiveCollision" },
+	{ 4, 0x38, "TxPausePkts" },
+	{ 8, 0x3c, "TxQoSOctets" },
+	{ 8, 0x44, "RxOctets" },
+	{ 4, 0x4c, "RxUndersizePkts" },
+	{ 4, 0x50, "RxPausePkts" },
+	{ 4, 0x54, "Pkts64Octets" },
+	{ 4, 0x58, "Pkts65to127Octets" },
+	{ 4, 0x5c, "Pkts128to255Octets" },
+	{ 4, 0x60, "Pkts256to511Octets" },
+	{ 4, 0x64, "Pkts512to1023Octets" },
+	{ 4, 0x68, "Pkts1024to1522Octets" },
+	{ 4, 0x6c, "RxOversizePkts" },
+	{ 4, 0x70, "RxJabbers" },
+	{ 4, 0x74, "RxAlignmentErrors" },
+	{ 4, 0x78, "RxFCSErrors" },
+	{ 8, 0x7c, "RxGoodOctets" },
+	{ 4, 0x84, "RxDropPkts" },
+	{ 4, 0x88, "RxUnicastPkts" },
+	{ 4, 0x8c, "RxMulticastPkts" },
+	{ 4, 0x90, "RxBroadcastPkts" },
+	{ 4, 0x94, "RxSAChanges" },
+	{ 4, 0x98, "RxFragments" },
+	{ 4, 0xa0, "RxSymbolErrors" },
+	{ 4, 0xa4, "RxQoSPkts" },
+	{ 8, 0xa8, "RxQoSOctets" },
+	{ 4, 0xb0, "Pkts1523to2047Octets" },
+	{ 4, 0xb4, "Pkts2048to4095Octets" },
+	{ 4, 0xb8, "Pkts4096to8191Octets" },
+	{ 4, 0xbc, "Pkts8192to9728Octets" },
+	{ 4, 0xc0, "RxDiscarded" },
+	{ }
+};
+
+/* MIB counters */
+static const struct b53_mib_desc b53_mibs[] = {
+	{ 8, 0x00, "TxOctets" },
+	{ 4, 0x08, "TxDropPkts" },
+	{ 4, 0x10, "TxBroadcastPkts" },
+	{ 4, 0x14, "TxMulticastPkts" },
+	{ 4, 0x18, "TxUnicastPkts" },
+	{ 4, 0x1c, "TxCollisions" },
+	{ 4, 0x20, "TxSingleCollision" },
+	{ 4, 0x24, "TxMultipleCollision" },
+	{ 4, 0x28, "TxDeferredTransmit" },
+	{ 4, 0x2c, "TxLateCollision" },
+	{ 4, 0x30, "TxExcessiveCollision" },
+	{ 4, 0x38, "TxPausePkts" },
+	{ 8, 0x50, "RxOctets" },
+	{ 4, 0x58, "RxUndersizePkts" },
+	{ 4, 0x5c, "RxPausePkts" },
+	{ 4, 0x60, "Pkts64Octets" },
+	{ 4, 0x64, "Pkts65to127Octets" },
+	{ 4, 0x68, "Pkts128to255Octets" },
+	{ 4, 0x6c, "Pkts256to511Octets" },
+	{ 4, 0x70, "Pkts512to1023Octets" },
+	{ 4, 0x74, "Pkts1024to1522Octets" },
+	{ 4, 0x78, "RxOversizePkts" },
+	{ 4, 0x7c, "RxJabbers" },
+	{ 4, 0x80, "RxAlignmentErrors" },
+	{ 4, 0x84, "RxFCSErrors" },
+	{ 8, 0x88, "RxGoodOctets" },
+	{ 4, 0x90, "RxDropPkts" },
+	{ 4, 0x94, "RxUnicastPkts" },
+	{ 4, 0x98, "RxMulticastPkts" },
+	{ 4, 0x9c, "RxBroadcastPkts" },
+	{ 4, 0xa0, "RxSAChanges" },
+	{ 4, 0xa4, "RxFragments" },
+	{ 4, 0xa8, "RxJumboPkts" },
+	{ 4, 0xac, "RxSymbolErrors" },
+	{ 4, 0xc0, "RxDiscarded" },
+	{ }
+};
+
+static int b53_do_vlan_op(struct b53_device *dev, u8 op)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op);
+
+	for (i = 0; i < 10; i++) {
+		u8 vta;
+
+		b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta);
+		if (!(vta & VTA_START_CMD))
+			return 0;
+
+		usleep_range(100, 200);
+	}
+
+	return -EIO;
+}
+
+static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members,
+			       u16 untag)
+{
+	if (is5325(dev)) {
+		u32 entry = 0;
+
+		if (members) {
+			entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) |
+				members;
+			if (dev->core_rev >= 3)
+				entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S;
+			else
+				entry |= VA_VALID_25;
+		}
+
+		b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry);
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid |
+			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
+	} else if (is5365(dev)) {
+		u16 entry = 0;
+
+		if (members)
+			entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) |
+				members | VA_VALID_65;
+
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry);
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid |
+			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
+	} else {
+		b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid);
+		b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2],
+			    (untag << VTE_UNTAG_S) | members);
+
+		b53_do_vlan_op(dev, VTA_CMD_WRITE);
+	}
+}
+
+void b53_set_forwarding(struct b53_device *dev, int enable)
+{
+	u8 mgmt;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (enable)
+		mgmt |= SM_SW_FWD_EN;
+	else
+		mgmt &= ~SM_SW_FWD_EN;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+}
+
+static void b53_enable_vlan(struct b53_device *dev, int enable)
+{
+	u8 mgmt, vc0, vc1, vc4 = 0, vc5;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0);
+	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1);
+
+	if (is5325(dev) || is5365(dev)) {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5);
+	} else if (is63xx(dev)) {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5);
+	} else {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
+	}
+
+	mgmt &= ~SM_SW_FWD_MODE;
+
+	if (enable) {
+		vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
+		vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
+		vc4 &= ~VC4_ING_VID_CHECK_MASK;
+		vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
+		vc5 |= VC5_DROP_VTABLE_MISS;
+
+		if (is5325(dev))
+			vc0 &= ~VC0_RESERVED_1;
+
+		if (is5325(dev) || is5365(dev))
+			vc1 |= VC1_RX_MCST_TAG_EN;
+
+		if (!is5325(dev) && !is5365(dev)) {
+			if (dev->allow_vid_4095)
+				vc5 |= VC5_VID_FFF_EN;
+			else
+				vc5 &= ~VC5_VID_FFF_EN;
+		}
+	} else {
+		vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID);
+		vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN);
+		vc4 &= ~VC4_ING_VID_CHECK_MASK;
+		vc5 &= ~VC5_DROP_VTABLE_MISS;
+
+		if (is5325(dev) || is5365(dev))
+			vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
+		else
+			vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S;
+
+		if (is5325(dev) || is5365(dev))
+			vc1 &= ~VC1_RX_MCST_TAG_EN;
+
+		if (!is5325(dev) && !is5365(dev))
+			vc5 &= ~VC5_VID_FFF_EN;
+	}
+
+	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0);
+	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1);
+
+	if (is5325(dev) || is5365(dev)) {
+		/* enable the high 8 bit vid check on 5325 */
+		if (is5325(dev) && enable)
+			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3,
+				   VC3_HIGH_8BIT_EN);
+		else
+			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
+
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5);
+	} else if (is63xx(dev)) {
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5);
+	} else {
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5);
+	}
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+}
+
+static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100)
+{
+	u32 port_mask = 0;
+	u16 max_size = JMS_MIN_SIZE;
+
+	if (is5325(dev) || is5365(dev))
+		return -EINVAL;
+
+	if (enable) {
+		port_mask = dev->enabled_ports;
+		max_size = JMS_MAX_SIZE;
+		if (allow_10_100)
+			port_mask |= JPM_10_100_JUMBO_EN;
+	}
+
+	b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask);
+	return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size);
+}
+
+static int b53_flush_arl(struct b53_device *dev)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+		   FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC);
+
+	for (i = 0; i < 10; i++) {
+		u8 fast_age_ctrl;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+			  &fast_age_ctrl);
+
+		if (!(fast_age_ctrl & FAST_AGE_DONE))
+			return 0;
+
+		mdelay(1);
+	}
+
+	pr_warn("time out while flushing ARL\n");
+
+	return -EINVAL;
+}
+
+static void b53_enable_ports(struct b53_device *dev)
+{
+	unsigned i;
+
+	b53_for_each_port(dev, i) {
+		u8 port_ctrl;
+		u16 pvlan_mask;
+
+		/*
+		 * prevent leaking packets between wan and lan in unmanaged
+		 * mode through port vlans.
+		 */
+		if (dev->enable_vlan || is_cpu_port(dev, i))
+			pvlan_mask = 0x1ff;
+		else if (is531x5(dev) || is5301x(dev))
+			/* BCM53115 may use a different port as cpu port */
+			pvlan_mask = BIT(dev->sw_dev.cpu_port);
+		else
+			pvlan_mask = BIT(B53_CPU_PORT);
+
+		/* BCM5325 CPU port is at 8 */
+		if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25)
+			i = B53_CPU_PORT;
+
+		if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7))
+			/* disable unused ports 6 & 7 */
+			port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
+		else if (i == B53_CPU_PORT)
+			port_ctrl = PORT_CTRL_RX_BCST_EN |
+				    PORT_CTRL_RX_MCST_EN |
+				    PORT_CTRL_RX_UCST_EN;
+		else
+			port_ctrl = 0;
+
+		b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i),
+			    pvlan_mask);
+
+		/* port state is handled by bcm63xx_enet driver */
+		if (!is63xx(dev) && !(is5301x(dev) && i == 6))
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i),
+				   port_ctrl);
+	}
+}
+
+static void b53_enable_mib(struct b53_device *dev)
+{
+	u8 gc;
+
+	b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc);
+
+	gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN);
+
+	b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc);
+}
+
+static int b53_apply(struct b53_device *dev)
+{
+	int i;
+
+	/* clear all vlan entries */
+	if (is5325(dev) || is5365(dev)) {
+		for (i = 1; i < dev->sw_dev.vlans; i++)
+			b53_set_vlan_entry(dev, i, 0, 0);
+	} else {
+		b53_do_vlan_op(dev, VTA_CMD_CLEAR);
+	}
+
+	b53_enable_vlan(dev, dev->enable_vlan);
+
+	/* fill VLAN table */
+	if (dev->enable_vlan) {
+		for (i = 0; i < dev->sw_dev.vlans; i++) {
+			struct b53_vlan *vlan = &dev->vlans[i];
+
+			if (!vlan->members)
+				continue;
+
+			b53_set_vlan_entry(dev, i, vlan->members, vlan->untag);
+		}
+
+		b53_for_each_port(dev, i)
+			b53_write16(dev, B53_VLAN_PAGE,
+				    B53_VLAN_PORT_DEF_TAG(i),
+				    dev->ports[i].pvid);
+	} else {
+		b53_for_each_port(dev, i)
+			b53_write16(dev, B53_VLAN_PAGE,
+				    B53_VLAN_PORT_DEF_TAG(i), 1);
+
+	}
+
+	b53_enable_ports(dev);
+
+	if (!is5325(dev) && !is5365(dev))
+		b53_set_jumbo(dev, dev->enable_jumbo, 1);
+
+	return 0;
+}
+
+static void b53_switch_reset_gpio(struct b53_device *dev)
+{
+	int gpio = dev->reset_gpio;
+
+	if (gpio < 0)
+		return;
+
+	/*
+	 * Reset sequence: RESET low(50ms)->high(20ms)
+	 */
+	gpio_set_value(gpio, 0);
+	mdelay(50);
+
+	gpio_set_value(gpio, 1);
+	mdelay(20);
+
+	dev->current_page = 0xff;
+}
+
+static int b53_switch_reset(struct b53_device *dev)
+{
+	u8 cpu_port = dev->sw_dev.cpu_port;
+	u8 mgmt;
+
+	b53_switch_reset_gpio(dev);
+
+	if (is539x(dev)) {
+		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
+		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
+	}
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (!(mgmt & SM_SW_FWD_EN)) {
+		mgmt &= ~SM_SW_FWD_MODE;
+		mgmt |= SM_SW_FWD_EN;
+
+		b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+		b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+		if (!(mgmt & SM_SW_FWD_EN)) {
+			pr_err("Failed to enable switch!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* enable all ports */
+	b53_enable_ports(dev);
+
+	/* configure MII port if necessary */
+	if (is5325(dev)) {
+		u8 mii_port_override;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			  &mii_port_override);
+		/* reverse mii needs to be enabled */
+		if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				   mii_port_override | PORT_OVERRIDE_RV_MII_25);
+			b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				  &mii_port_override);
+
+			if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
+				pr_err("Failed to enable reverse MII mode\n");
+				return -EINVAL;
+			}
+		}
+	} else if (is531x5(dev) && cpu_port == B53_CPU_PORT) {
+		u8 mii_port_override;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			  &mii_port_override);
+		b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			   mii_port_override | PORT_OVERRIDE_EN |
+			   PORT_OVERRIDE_LINK);
+
+		/* BCM47189 has another interface connected to the port 5 */
+		if (dev->enabled_ports & BIT(5)) {
+			u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(5);
+			u8 gmii_po;
+
+			b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po);
+			gmii_po |= GMII_PO_LINK |
+				   GMII_PO_RX_FLOW |
+				   GMII_PO_TX_FLOW |
+				   GMII_PO_EN;
+			b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po);
+		}
+	} else if (is5301x(dev)) {
+		if (cpu_port == 8) {
+			u8 mii_port_override;
+
+			b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				  &mii_port_override);
+			mii_port_override |= PORT_OVERRIDE_LINK |
+					     PORT_OVERRIDE_RX_FLOW |
+					     PORT_OVERRIDE_TX_FLOW |
+					     PORT_OVERRIDE_SPEED_2000M |
+					     PORT_OVERRIDE_EN;
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				   mii_port_override);
+
+			/* TODO: Ports 5 & 7 require some extra handling */
+		} else {
+			u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(cpu_port);
+			u8 gmii_po;
+
+			b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po);
+			gmii_po |= GMII_PO_LINK |
+				   GMII_PO_RX_FLOW |
+				   GMII_PO_TX_FLOW |
+				   GMII_PO_EN |
+				   GMII_PO_SPEED_2000M;
+			b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po);
+		}
+	}
+
+	b53_enable_mib(dev);
+
+	return b53_flush_arl(dev);
+}
+
+/*
+ * Swconfig glue functions
+ */
+
+static int b53_global_get_vlan_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->value.i = priv->enable_vlan;
+
+	return 0;
+}
+
+static int b53_global_set_vlan_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	priv->enable_vlan = val->value.i;
+
+	return 0;
+}
+
+static int b53_global_get_jumbo_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->value.i = priv->enable_jumbo;
+
+	return 0;
+}
+
+static int b53_global_set_jumbo_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	priv->enable_jumbo = val->value.i;
+
+	return 0;
+}
+
+static int b53_global_get_4095_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->value.i = priv->allow_vid_4095;
+
+	return 0;
+}
+
+static int b53_global_set_4095_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	priv->allow_vid_4095 = val->value.i;
+
+	return 0;
+}
+
+static int b53_global_get_ports(struct switch_dev *dev,
+				const struct switch_attr *attr,
+				struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x",
+			    priv->enabled_ports);
+	val->value.s = priv->buf;
+
+	return 0;
+}
+
+static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	*val = priv->ports[port].pvid;
+
+	return 0;
+}
+
+static int b53_port_set_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (val > 15 && is5325(priv))
+		return -EINVAL;
+	if (val == 4095 && !priv->allow_vid_4095)
+		return -EINVAL;
+
+	priv->ports[port].pvid = val;
+
+	return 0;
+}
+
+static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+	struct switch_port *port = &val->value.ports[0];
+	struct b53_vlan *vlan = &priv->vlans[val->port_vlan];
+	int i;
+
+	val->len = 0;
+
+	if (!vlan->members)
+		return 0;
+
+	for (i = 0; i < dev->ports; i++) {
+		if (!(vlan->members & BIT(i)))
+			continue;
+
+
+		if (!(vlan->untag & BIT(i)))
+			port->flags = BIT(SWITCH_PORT_FLAG_TAGGED);
+		else
+			port->flags = 0;
+
+		port->id = i;
+		val->len++;
+		port++;
+	}
+
+	return 0;
+}
+
+static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+	struct switch_port *port;
+	struct b53_vlan *vlan = &priv->vlans[val->port_vlan];
+	int i;
+
+	/* only BCM5325 and BCM5365 supports VID 0 */
+	if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv))
+		return -EINVAL;
+
+	/* VLAN 4095 needs special handling */
+	if (val->port_vlan == 4095 && !priv->allow_vid_4095)
+		return -EINVAL;
+
+	port = &val->value.ports[0];
+	vlan->members = 0;
+	vlan->untag = 0;
+	for (i = 0; i < val->len; i++, port++) {
+		vlan->members |= BIT(port->id);
+
+		if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) {
+			vlan->untag |= BIT(port->id);
+			priv->ports[port->id].pvid = val->port_vlan;
+		};
+	}
+
+	/* ignore disabled ports */
+	vlan->members &= priv->enabled_ports;
+	vlan->untag &= priv->enabled_ports;
+
+	return 0;
+}
+
+static int b53_port_get_link(struct switch_dev *dev, int port,
+			     struct switch_port_link *link)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (is_cpu_port(priv, port)) {
+		link->link = 1;
+		link->duplex = 1;
+		link->speed = is5325(priv) || is5365(priv) ?
+				SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000;
+		link->aneg = 0;
+	} else if (priv->enabled_ports & BIT(port)) {
+		u32 speed;
+		u16 lnk, duplex;
+
+		b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk);
+		b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex);
+
+		lnk = (lnk >> port) & 1;
+		duplex = (duplex >> port) & 1;
+
+		if (is5325(priv) || is5365(priv)) {
+			u16 tmp;
+
+			b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp);
+			speed = SPEED_PORT_FE(tmp, port);
+		} else {
+			b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed);
+			speed = SPEED_PORT_GE(speed, port);
+		}
+
+		link->link = lnk;
+		if (lnk) {
+			link->duplex = duplex;
+			switch (speed) {
+			case SPEED_STAT_10M:
+				link->speed = SWITCH_PORT_SPEED_10;
+				break;
+			case SPEED_STAT_100M:
+				link->speed = SWITCH_PORT_SPEED_100;
+				break;
+			case SPEED_STAT_1000M:
+				link->speed = SWITCH_PORT_SPEED_1000;
+				break;
+			}
+		}
+
+		link->aneg = 1;
+	} else {
+		link->link = 0;
+	}
+
+	return 0;
+
+}
+
+static int b53_port_set_link(struct switch_dev *sw_dev, int port,
+			     struct switch_port_link *link)
+{
+	struct b53_device *dev = sw_to_b53(sw_dev);
+
+	/*
+	 * TODO: BCM63XX requires special handling as it can have external phys
+	 * and ports might be GE or only FE
+	 */
+	if (is63xx(dev))
+		return -ENOTSUPP;
+
+	if (port == sw_dev->cpu_port)
+		return -EINVAL;
+
+	if (!(BIT(port) & dev->enabled_ports))
+		return -EINVAL;
+
+	if (link->speed == SWITCH_PORT_SPEED_1000 &&
+	    (is5325(dev) || is5365(dev)))
+		return -EINVAL;
+
+	if (link->speed == SWITCH_PORT_SPEED_1000 && !link->duplex)
+		return -EINVAL;
+
+	return switch_generic_set_link(sw_dev, port, link);
+}
+
+static int b53_phy_read16(struct switch_dev *dev, int addr, u8 reg, u16 *value)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (priv->ops->phy_read16)
+		return priv->ops->phy_read16(priv, addr, reg, value);
+
+	return b53_read16(priv, B53_PORT_MII_PAGE(addr), reg, value);
+}
+
+static int b53_phy_write16(struct switch_dev *dev, int addr, u8 reg, u16 value)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (priv->ops->phy_write16)
+		return priv->ops->phy_write16(priv, addr, reg, value);
+
+	return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg, value);
+}
+
+static int b53_global_reset_switch(struct switch_dev *dev)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	/* reset vlans */
+	priv->enable_vlan = 0;
+	priv->enable_jumbo = 0;
+	priv->allow_vid_4095 = 0;
+
+	memset(priv->vlans, 0, sizeof(*priv->vlans) * dev->vlans);
+	memset(priv->ports, 0, sizeof(*priv->ports) * dev->ports);
+
+	return b53_switch_reset(priv);
+}
+
+static int b53_global_apply_config(struct switch_dev *dev)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	/* disable switching */
+	b53_set_forwarding(priv, 0);
+
+	b53_apply(priv);
+
+	/* enable switching */
+	b53_set_forwarding(priv, 1);
+
+	return 0;
+}
+
+
+static int b53_global_reset_mib(struct switch_dev *dev,
+				const struct switch_attr *attr,
+				struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+	u8 gc;
+
+	b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc);
+
+	b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB);
+	mdelay(1);
+	b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB);
+	mdelay(1);
+
+	return 0;
+}
+
+static int b53_port_get_mib(struct switch_dev *sw_dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct b53_device *dev = sw_to_b53(sw_dev);
+	const struct b53_mib_desc *mibs;
+	int port = val->port_vlan;
+	int len = 0;
+
+	if (!(BIT(port) & dev->enabled_ports))
+		return -1;
+
+	if (is5365(dev)) {
+		if (port == 5)
+			port = 8;
+
+		mibs = b53_mibs_65;
+	} else if (is63xx(dev)) {
+		mibs = b53_mibs_63xx;
+	} else {
+		mibs = b53_mibs;
+	}
+
+	dev->buf[0] = 0;
+
+	for (; mibs->size > 0; mibs++) {
+		u64 val;
+
+		if (mibs->size == 8) {
+			b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val);
+		} else {
+			u32 val32;
+
+			b53_read32(dev, B53_MIB_PAGE(port), mibs->offset,
+				   &val32);
+			val = val32;
+		}
+
+		len += snprintf(dev->buf + len, B53_BUF_SIZE - len,
+				"%-20s: %llu\n", mibs->name, val);
+	}
+
+	val->len = len;
+	val->value.s = dev->buf;
+
+	return 0;
+}
+
+static struct switch_attr b53_global_ops_25[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = b53_global_set_vlan_enable,
+		.get = b53_global_get_vlan_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "ports",
+		.description = "Available ports (as bitmask)",
+		.get = b53_global_get_ports,
+	},
+};
+
+static struct switch_attr b53_global_ops_65[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = b53_global_set_vlan_enable,
+		.get = b53_global_get_vlan_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "ports",
+		.description = "Available ports (as bitmask)",
+		.get = b53_global_get_ports,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "reset_mib",
+		.description = "Reset MIB counters",
+		.set = b53_global_reset_mib,
+	},
+};
+
+static struct switch_attr b53_global_ops[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = b53_global_set_vlan_enable,
+		.get = b53_global_get_vlan_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "ports",
+		.description = "Available Ports (as bitmask)",
+		.get = b53_global_get_ports,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "reset_mib",
+		.description = "Reset MIB counters",
+		.set = b53_global_reset_mib,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_jumbo",
+		.description = "Enable Jumbo Frames",
+		.set = b53_global_set_jumbo_enable,
+		.get = b53_global_get_jumbo_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "allow_vid_4095",
+		.description = "Allow VID 4095",
+		.set = b53_global_set_4095_enable,
+		.get = b53_global_get_4095_enable,
+		.max = 1,
+	},
+};
+
+static struct switch_attr b53_port_ops[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get port's MIB counters",
+		.get = b53_port_get_mib,
+	},
+};
+
+static struct switch_attr b53_no_ops[] = {
+};
+
+static const struct switch_dev_ops b53_switch_ops_25 = {
+	.attr_global = {
+		.attr = b53_global_ops_25,
+		.n_attr = ARRAY_SIZE(b53_global_ops_25),
+	},
+	.attr_port = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+	.attr_vlan = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+
+	.get_vlan_ports = b53_vlan_get_ports,
+	.set_vlan_ports = b53_vlan_set_ports,
+	.get_port_pvid = b53_port_get_pvid,
+	.set_port_pvid = b53_port_set_pvid,
+	.apply_config = b53_global_apply_config,
+	.reset_switch = b53_global_reset_switch,
+	.get_port_link = b53_port_get_link,
+	.set_port_link = b53_port_set_link,
+	.phy_read16 = b53_phy_read16,
+	.phy_write16 = b53_phy_write16,
+};
+
+static const struct switch_dev_ops b53_switch_ops_65 = {
+	.attr_global = {
+		.attr = b53_global_ops_65,
+		.n_attr = ARRAY_SIZE(b53_global_ops_65),
+	},
+	.attr_port = {
+		.attr = b53_port_ops,
+		.n_attr = ARRAY_SIZE(b53_port_ops),
+	},
+	.attr_vlan = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+
+	.get_vlan_ports = b53_vlan_get_ports,
+	.set_vlan_ports = b53_vlan_set_ports,
+	.get_port_pvid = b53_port_get_pvid,
+	.set_port_pvid = b53_port_set_pvid,
+	.apply_config = b53_global_apply_config,
+	.reset_switch = b53_global_reset_switch,
+	.get_port_link = b53_port_get_link,
+	.set_port_link = b53_port_set_link,
+	.phy_read16 = b53_phy_read16,
+	.phy_write16 = b53_phy_write16,
+};
+
+static const struct switch_dev_ops b53_switch_ops = {
+	.attr_global = {
+		.attr = b53_global_ops,
+		.n_attr = ARRAY_SIZE(b53_global_ops),
+	},
+	.attr_port = {
+		.attr = b53_port_ops,
+		.n_attr = ARRAY_SIZE(b53_port_ops),
+	},
+	.attr_vlan = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+
+	.get_vlan_ports = b53_vlan_get_ports,
+	.set_vlan_ports = b53_vlan_set_ports,
+	.get_port_pvid = b53_port_get_pvid,
+	.set_port_pvid = b53_port_set_pvid,
+	.apply_config = b53_global_apply_config,
+	.reset_switch = b53_global_reset_switch,
+	.get_port_link = b53_port_get_link,
+	.set_port_link = b53_port_set_link,
+	.phy_read16 = b53_phy_read16,
+	.phy_write16 = b53_phy_write16,
+};
+
+struct b53_chip_data {
+	u32 chip_id;
+	const char *dev_name;
+	const char *alias;
+	u16 vlans;
+	u16 enabled_ports;
+	u8 cpu_port;
+	u8 vta_regs[3];
+	u8 duplex_reg;
+	u8 jumbo_pm_reg;
+	u8 jumbo_size_reg;
+	const struct switch_dev_ops *sw_ops;
+};
+
+#define B53_VTA_REGS	\
+	{ B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY }
+#define B53_VTA_REGS_9798 \
+	{ B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 }
+#define B53_VTA_REGS_63XX \
+	{ B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX }
+
+static const struct b53_chip_data b53_switch_chips[] = {
+	{
+		.chip_id = BCM5325_DEVICE_ID,
+		.dev_name = "BCM5325",
+		.alias = "bcm5325",
+		.vlans = 16,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25,
+		.duplex_reg = B53_DUPLEX_STAT_FE,
+		.sw_ops = &b53_switch_ops_25,
+	},
+	{
+		.chip_id = BCM5365_DEVICE_ID,
+		.dev_name = "BCM5365",
+		.alias = "bcm5365",
+		.vlans = 256,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25,
+		.duplex_reg = B53_DUPLEX_STAT_FE,
+		.sw_ops = &b53_switch_ops_65,
+	},
+	{
+		.chip_id = BCM5395_DEVICE_ID,
+		.dev_name = "BCM5395",
+		.alias = "bcm5395",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM5397_DEVICE_ID,
+		.dev_name = "BCM5397",
+		.alias = "bcm5397",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_9798,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM5398_DEVICE_ID,
+		.dev_name = "BCM5398",
+		.alias = "bcm5398",
+		.vlans = 4096,
+		.enabled_ports = 0x7f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_9798,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53115_DEVICE_ID,
+		.dev_name = "BCM53115",
+		.alias = "bcm53115",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.vta_regs = B53_VTA_REGS,
+		.cpu_port = B53_CPU_PORT,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53125_DEVICE_ID,
+		.dev_name = "BCM53125",
+		.alias = "bcm53125",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53128_DEVICE_ID,
+		.dev_name = "BCM53128",
+		.alias = "bcm53128",
+		.vlans = 4096,
+		.enabled_ports = 0x1ff,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM63XX_DEVICE_ID,
+		.dev_name = "BCM63xx",
+		.alias = "bcm63xx",
+		.vlans = 4096,
+		.enabled_ports = 0, /* pdata must provide them */
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_63XX,
+		.duplex_reg = B53_DUPLEX_STAT_63XX,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53010_DEVICE_ID,
+		.dev_name = "BCM53010",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53011_DEVICE_ID,
+		.dev_name = "BCM53011",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1bf,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53012_DEVICE_ID,
+		.dev_name = "BCM53012",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1bf,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53018_DEVICE_ID,
+		.dev_name = "BCM53018",
+		.alias = "bcm53018",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53019_DEVICE_ID,
+		.dev_name = "BCM53019",
+		.alias = "bcm53019",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+};
+
+static int b53_switch_init(struct b53_device *dev)
+{
+	struct switch_dev *sw_dev = &dev->sw_dev;
+	unsigned i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
+		const struct b53_chip_data *chip = &b53_switch_chips[i];
+
+		if (chip->chip_id == dev->chip_id) {
+			sw_dev->name = chip->dev_name;
+			if (!sw_dev->alias)
+				sw_dev->alias = chip->alias;
+			if (!dev->enabled_ports)
+				dev->enabled_ports = chip->enabled_ports;
+			dev->duplex_reg = chip->duplex_reg;
+			dev->vta_regs[0] = chip->vta_regs[0];
+			dev->vta_regs[1] = chip->vta_regs[1];
+			dev->vta_regs[2] = chip->vta_regs[2];
+			dev->jumbo_pm_reg = chip->jumbo_pm_reg;
+			sw_dev->ops = chip->sw_ops;
+			sw_dev->cpu_port = chip->cpu_port;
+			sw_dev->vlans = chip->vlans;
+			break;
+		}
+	}
+
+	if (!sw_dev->name)
+		return -EINVAL;
+
+	/* check which BCM5325x version we have */
+	if (is5325(dev)) {
+		u8 vc4;
+
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
+
+		/* check reserved bits */
+		switch (vc4 & 3) {
+		case 1:
+			/* BCM5325E */
+			break;
+		case 3:
+			/* BCM5325F - do not use port 4 */
+			dev->enabled_ports &= ~BIT(4);
+			break;
+		default:
+/* On the BCM47XX SoCs this is the supported internal switch.*/
+#ifndef CONFIG_BCM47XX
+			/* BCM5325M */
+			return -EINVAL;
+#else
+			break;
+#endif
+		}
+	} else if (dev->chip_id == BCM53115_DEVICE_ID) {
+		u64 strap_value;
+
+		b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value);
+		/* use second IMP port if GMII is enabled */
+		if (strap_value & SV_GMII_CTRL_115)
+			sw_dev->cpu_port = 5;
+	}
+
+	dev->enabled_ports |= BIT(sw_dev->cpu_port);
+	sw_dev->ports = fls(dev->enabled_ports);
+
+	dev->ports = devm_kzalloc(dev->dev,
+				  sizeof(struct b53_port) * sw_dev->ports,
+				  GFP_KERNEL);
+	if (!dev->ports)
+		return -ENOMEM;
+
+	dev->vlans = devm_kzalloc(dev->dev,
+				  sizeof(struct b53_vlan) * sw_dev->vlans,
+				  GFP_KERNEL);
+	if (!dev->vlans)
+		return -ENOMEM;
+
+	dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL);
+	if (!dev->buf)
+		return -ENOMEM;
+
+	dev->reset_gpio = b53_switch_get_reset_gpio(dev);
+	if (dev->reset_gpio >= 0) {
+		ret = devm_gpio_request_one(dev->dev, dev->reset_gpio,
+					    GPIOF_OUT_INIT_HIGH, "robo_reset");
+		if (ret)
+			return ret;
+	}
+
+	return b53_switch_reset(dev);
+}
+
+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
+				    void *priv)
+{
+	struct b53_device *dev;
+
+	dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	dev->dev = base;
+	dev->ops = ops;
+	dev->priv = priv;
+	mutex_init(&dev->reg_mutex);
+
+	return dev;
+}
+EXPORT_SYMBOL(b53_switch_alloc);
+
+int b53_switch_detect(struct b53_device *dev)
+{
+	u32 id32;
+	u16 tmp;
+	u8 id8;
+	int ret;
+
+	ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8);
+	if (ret)
+		return ret;
+
+	switch (id8) {
+	case 0:
+		/*
+		 * BCM5325 and BCM5365 do not have this register so reads
+		 * return 0. But the read operation did succeed, so assume
+		 * this is one of them.
+		 *
+		 * Next check if we can write to the 5325's VTA register; for
+		 * 5365 it is read only.
+		 */
+
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf);
+		b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp);
+
+		if (tmp == 0xf)
+			dev->chip_id = BCM5325_DEVICE_ID;
+		else
+			dev->chip_id = BCM5365_DEVICE_ID;
+		break;
+	case BCM5395_DEVICE_ID:
+	case BCM5397_DEVICE_ID:
+	case BCM5398_DEVICE_ID:
+		dev->chip_id = id8;
+		break;
+	default:
+		ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32);
+		if (ret)
+			return ret;
+
+		switch (id32) {
+		case BCM53115_DEVICE_ID:
+		case BCM53125_DEVICE_ID:
+		case BCM53128_DEVICE_ID:
+		case BCM53010_DEVICE_ID:
+		case BCM53011_DEVICE_ID:
+		case BCM53012_DEVICE_ID:
+		case BCM53018_DEVICE_ID:
+		case BCM53019_DEVICE_ID:
+			dev->chip_id = id32;
+			break;
+		default:
+			pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n",
+			       id8, id32);
+			return -ENODEV;
+		}
+	}
+
+	if (dev->chip_id == BCM5325_DEVICE_ID)
+		return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25,
+				 &dev->core_rev);
+	else
+		return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID,
+				 &dev->core_rev);
+}
+EXPORT_SYMBOL(b53_switch_detect);
+
+int b53_switch_register(struct b53_device *dev)
+{
+	int ret;
+
+	if (dev->pdata) {
+		dev->chip_id = dev->pdata->chip_id;
+		dev->enabled_ports = dev->pdata->enabled_ports;
+		dev->sw_dev.alias = dev->pdata->alias;
+	}
+
+	if (!dev->chip_id && b53_switch_detect(dev))
+		return -EINVAL;
+
+	ret = b53_switch_init(dev);
+	if (ret)
+		return ret;
+
+	pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev);
+
+	return register_switch(&dev->sw_dev, NULL);
+}
+EXPORT_SYMBOL(b53_switch_register);
+
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 switch library");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
new file mode 100644
index 0000000000..185c95ffa7
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
@@ -0,0 +1,445 @@
+/*
+ * B53 register access through MII registers
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#include "b53_priv.h"
+
+#define B53_PSEUDO_PHY	0x1e /* Register Access Pseudo PHY */
+
+/* MII registers */
+#define REG_MII_PAGE    0x10    /* MII Page register */
+#define REG_MII_ADDR    0x11    /* MII Address register */
+#define REG_MII_DATA0   0x18    /* MII Data register 0 */
+#define REG_MII_DATA1   0x19    /* MII Data register 1 */
+#define REG_MII_DATA2   0x1a    /* MII Data register 2 */
+#define REG_MII_DATA3   0x1b    /* MII Data register 3 */
+
+#define REG_MII_PAGE_ENABLE     BIT(0)
+#define REG_MII_ADDR_WRITE      BIT(0)
+#define REG_MII_ADDR_READ       BIT(1)
+
+static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
+{
+	int i;
+	u16 v;
+	int ret;
+	struct mii_bus *bus = dev->priv;
+
+	if (dev->current_page != page) {
+		/* set page number */
+		v = (page << 8) | REG_MII_PAGE_ENABLE;
+		ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v);
+		if (ret)
+			return ret;
+		dev->current_page = page;
+	}
+
+	/* set register address */
+	v = (reg << 8) | op;
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v);
+	if (ret)
+		return ret;
+
+	/* check if operation completed */
+	for (i = 0; i < 5; ++i) {
+		v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR);
+		if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
+			break;
+		usleep_range(10, 100);
+	}
+
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff;
+
+	return 0;
+}
+
+static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
+
+	return 0;
+}
+
+static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
+	*val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16;
+
+	return 0;
+}
+
+static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 2; i >= 0; i--) {
+		temp <<= 16;
+		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 3; i >= 0; i--) {
+		temp <<= 16;
+		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
+			     u16 value)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
+				    u32 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned int i;
+	u32 temp = value;
+
+	for (i = 0; i < 2; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+
+}
+
+static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
+				    u64 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned i;
+	u64 temp = value;
+
+	for (i = 0; i < 3; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+
+}
+
+static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
+			     u64 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned i;
+	u64 temp = value;
+
+	for (i = 0; i < 4; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_phy_read16(struct b53_device *dev, int addr, u8 reg,
+			       u16 *value)
+{
+	struct mii_bus *bus = dev->priv;
+
+	*value = mdiobus_read(bus, addr, reg);
+
+	return 0;
+}
+
+static int b53_mdio_phy_write16(struct b53_device *dev, int addr, u8 reg,
+				u16 value)
+{
+	struct mii_bus *bus = dev->priv;
+
+	return mdiobus_write(bus, addr, reg, value);
+}
+
+static struct b53_io_ops b53_mdio_ops = {
+	.read8 = b53_mdio_read8,
+	.read16 = b53_mdio_read16,
+	.read32 = b53_mdio_read32,
+	.read48 = b53_mdio_read48,
+	.read64 = b53_mdio_read64,
+	.write8 = b53_mdio_write8,
+	.write16 = b53_mdio_write16,
+	.write32 = b53_mdio_write32,
+	.write48 = b53_mdio_write48,
+	.write64 = b53_mdio_write64,
+	.phy_read16 = b53_mdio_phy_read16,
+	.phy_write16 = b53_mdio_phy_write16,
+};
+
+static int b53_phy_probe(struct phy_device *phydev)
+{
+	struct b53_device dev;
+	int ret;
+
+	/* allow the generic phy driver to take over */
+	if (phydev->addr != B53_PSEUDO_PHY && phydev->addr != 0)
+		return -ENODEV;
+
+	dev.current_page = 0xff;
+	dev.priv = phydev->bus;
+	dev.ops = &b53_mdio_ops;
+	dev.pdata = NULL;
+	mutex_init(&dev.reg_mutex);
+
+	ret = b53_switch_detect(&dev);
+	if (ret)
+		return ret;
+
+	if (is5325(&dev) || is5365(&dev))
+		phydev->supported = SUPPORTED_100baseT_Full;
+	else
+		phydev->supported = SUPPORTED_1000baseT_Full;
+
+	phydev->advertising = phydev->supported;
+
+	return 0;
+}
+
+static int b53_phy_config_init(struct phy_device *phydev)
+{
+	struct b53_device *dev;
+	int ret;
+
+	dev = b53_switch_alloc(&phydev->dev, &b53_mdio_ops, phydev->bus);
+	if (!dev)
+		return -ENOMEM;
+
+	/* we don't use page 0xff, so force a page set */
+	dev->current_page = 0xff;
+	/* force the ethX as alias */
+	dev->sw_dev.alias = phydev->attached_dev->name;
+
+	ret = b53_switch_register(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to register switch: %i\n", ret);
+		return ret;
+	}
+
+	phydev->priv = dev;
+
+	return 0;
+}
+
+static void b53_phy_remove(struct phy_device *phydev)
+{
+	struct b53_device *priv = phydev->priv;
+
+	if (!priv)
+		return;
+
+	b53_switch_remove(priv);
+
+	phydev->priv = NULL;
+}
+
+static int b53_phy_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int b53_phy_read_status(struct phy_device *phydev)
+{
+	struct b53_device *priv = phydev->priv;
+
+	if (is5325(priv) || is5365(priv))
+		phydev->speed = 100;
+	else
+		phydev->speed = 1000;
+
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+	phydev->state = PHY_RUNNING;
+
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+/* BCM5325, BCM539x */
+static struct phy_driver b53_phy_driver_id1 = {
+	.phy_id		= 0x0143bc00,
+	.name		= "Broadcom B53 (1)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+/* BCM53125, BCM53128 */
+static struct phy_driver b53_phy_driver_id2 = {
+	.phy_id		= 0x03625c00,
+	.name		= "Broadcom B53 (2)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+/* BCM5365 */
+static struct phy_driver b53_phy_driver_id3 = {
+	.phy_id		= 0x00406000,
+	.name		= "Broadcom B53 (3)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.driver = {
+		.owner = THIS_MODULE,
+	},
+};
+
+int __init b53_phy_driver_register(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&b53_phy_driver_id1);
+	if (ret)
+		return ret;
+
+	ret = phy_driver_register(&b53_phy_driver_id2);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&b53_phy_driver_id3);
+	if (!ret)
+		return 0;
+
+	phy_driver_unregister(&b53_phy_driver_id2);
+err1:
+	phy_driver_unregister(&b53_phy_driver_id1);
+	return ret;
+}
+
+void __exit b53_phy_driver_unregister(void)
+{
+	phy_driver_unregister(&b53_phy_driver_id3);
+	phy_driver_unregister(&b53_phy_driver_id2);
+	phy_driver_unregister(&b53_phy_driver_id1);
+}
+
+module_init(b53_phy_driver_register);
+module_exit(b53_phy_driver_unregister);
+
+MODULE_DESCRIPTION("B53 MDIO access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c b/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c
new file mode 100644
index 0000000000..ab1895e9b5
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c
@@ -0,0 +1,241 @@
+/*
+ * B53 register access through memory mapped registers
+ *
+ * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	u8 __iomem *regs = dev->priv;
+
+	*val = readb(regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		*val = readw_be(regs + (page << 8) + reg);
+	else
+		*val = readw(regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		*val = readl_be(regs + (page << 8) + reg);
+	else
+		*val = readl(regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (reg % 4) {
+		u16 lo;
+		u32 hi;
+
+		b53_mmap_read16(dev, page, reg, &lo);
+		b53_mmap_read32(dev, page, reg + 2, &hi);
+
+		*val = ((u64)hi << 16) | lo;
+	} else {
+		u32 lo;
+		u16 hi;
+
+		b53_mmap_read32(dev, page, reg, &lo);
+		b53_mmap_read16(dev, page, reg + 4, &hi);
+
+		*val = ((u64)hi << 32) | lo;
+	}
+
+	return 0;
+}
+
+static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	u32 hi, lo;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	b53_mmap_read32(dev, page, reg, &lo);
+	b53_mmap_read32(dev, page, reg + 4, &hi);
+
+	*val = ((u64)hi << 32) | lo;
+
+	return 0;
+}
+
+static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	u8 __iomem *regs = dev->priv;
+
+	writeb(value, regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
+			     u16 value)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		writew_be(value, regs + (page << 8) + reg);
+	else
+		writew(value, regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
+				    u32 value)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		writel_be(value, regs + (page << 8) + reg);
+	else
+		writel(value, regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
+				    u64 value)
+{
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (reg % 4) {
+		u32 hi = (u32)(value >> 16);
+		u16 lo = (u16)value;
+
+		b53_mmap_write16(dev, page, reg, lo);
+		b53_mmap_write32(dev, page, reg + 2, hi);
+	} else {
+		u16 hi = (u16)(value >> 32);
+		u32 lo = (u32)value;
+
+		b53_mmap_write32(dev, page, reg, lo);
+		b53_mmap_write16(dev, page, reg + 4, hi);
+	}
+
+	return 0;
+}
+
+static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
+			     u64 value)
+{
+	u32 hi, lo;
+
+	hi = (u32)(value >> 32);
+	lo = (u32)value;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	b53_mmap_write32(dev, page, reg, lo);
+	b53_mmap_write32(dev, page, reg + 4, hi);
+
+	return 0;
+}
+
+static struct b53_io_ops b53_mmap_ops = {
+	.read8 = b53_mmap_read8,
+	.read16 = b53_mmap_read16,
+	.read32 = b53_mmap_read32,
+	.read48 = b53_mmap_read48,
+	.read64 = b53_mmap_read64,
+	.write8 = b53_mmap_write8,
+	.write16 = b53_mmap_write16,
+	.write32 = b53_mmap_write32,
+	.write48 = b53_mmap_write48,
+	.write64 = b53_mmap_write64,
+};
+
+static int b53_mmap_probe(struct platform_device *pdev)
+{
+	struct b53_platform_data *pdata = pdev->dev.platform_data;
+	struct b53_device *dev;
+
+	if (!pdata)
+		return -EINVAL;
+
+	dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
+	if (!dev)
+		return -ENOMEM;
+
+	if (pdata)
+		dev->pdata = pdata;
+
+	platform_set_drvdata(pdev, dev);
+
+	return b53_switch_register(dev);
+}
+
+static int b53_mmap_remove(struct platform_device *pdev)
+{
+	struct b53_device *dev = platform_get_drvdata(pdev);
+
+	if (dev)
+		b53_switch_remove(dev);
+
+	return 0;
+}
+
+static struct platform_driver b53_mmap_driver = {
+	.probe = b53_mmap_probe,
+	.remove = b53_mmap_remove,
+	.driver = {
+		.name = "b53-switch",
+	},
+};
+
+module_platform_driver(b53_mmap_driver);
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 MMAP access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c b/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c
new file mode 100644
index 0000000000..72d1373d7f
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_phy_fixup.c
@@ -0,0 +1,55 @@
+/*
+ * B53 PHY Fixup call
+ *
+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/phy.h>
+
+#define B53_PSEUDO_PHY	0x1e /* Register Access Pseudo PHY */
+
+#define B53_BRCM_OUI_1	0x0143bc00
+#define B53_BRCM_OUI_2	0x03625c00
+#define B53_BRCM_OUI_3	0x00406000
+
+static int b53_phy_fixup(struct phy_device *dev)
+{
+	u32 phy_id;
+	struct mii_bus *bus = dev->bus;
+
+	if (dev->addr != B53_PSEUDO_PHY)
+		return 0;
+
+	/* read the first port's id */
+	phy_id = mdiobus_read(bus, 0, 2) << 16;
+	phy_id |= mdiobus_read(bus, 0, 3);
+
+	if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 ||
+	    (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 ||
+	    (phy_id & 0xfffffc00) == B53_BRCM_OUI_3) {
+		dev->phy_id = phy_id;
+	}
+
+	return 0;
+}
+
+int __init b53_phy_fixup_register(void)
+{
+	return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup);
+}
+
+subsys_initcall(b53_phy_fixup_register);
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
new file mode 100644
index 0000000000..53da97ebba
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
@@ -0,0 +1,331 @@
+/*
+ * B53 common definitions
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __B53_PRIV_H
+#define __B53_PRIV_H
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/switch.h>
+
+struct b53_device;
+
+struct b53_io_ops {
+	int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
+	int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
+	int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
+	int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
+	int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
+	int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
+	int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
+	int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
+	int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
+	int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
+	int (*phy_read16)(struct b53_device *dev, int addr, u8 reg, u16 *value);
+	int (*phy_write16)(struct b53_device *dev, int addr, u8 reg, u16 value);
+};
+
+enum {
+	BCM5325_DEVICE_ID = 0x25,
+	BCM5365_DEVICE_ID = 0x65,
+	BCM5395_DEVICE_ID = 0x95,
+	BCM5397_DEVICE_ID = 0x97,
+	BCM5398_DEVICE_ID = 0x98,
+	BCM53115_DEVICE_ID = 0x53115,
+	BCM53125_DEVICE_ID = 0x53125,
+	BCM53128_DEVICE_ID = 0x53128,
+	BCM63XX_DEVICE_ID = 0x6300,
+	BCM53010_DEVICE_ID = 0x53010,
+	BCM53011_DEVICE_ID = 0x53011,
+	BCM53012_DEVICE_ID = 0x53012,
+	BCM53018_DEVICE_ID = 0x53018,
+	BCM53019_DEVICE_ID = 0x53019,
+};
+
+#define B53_N_PORTS	9
+#define B53_N_PORTS_25	6
+
+struct b53_vlan {
+	unsigned int	members:B53_N_PORTS;
+	unsigned int	untag:B53_N_PORTS;
+};
+
+struct b53_port {
+	unsigned int	pvid:12;
+};
+
+struct b53_device {
+	struct switch_dev sw_dev;
+	struct b53_platform_data *pdata;
+
+	struct mutex reg_mutex;
+	const struct b53_io_ops *ops;
+
+	/* chip specific data */
+	u32 chip_id;
+	u8 core_rev;
+	u8 vta_regs[3];
+	u8 duplex_reg;
+	u8 jumbo_pm_reg;
+	u8 jumbo_size_reg;
+	int reset_gpio;
+
+	/* used ports mask */
+	u16 enabled_ports;
+
+	/* connect specific data */
+	u8 current_page;
+	struct device *dev;
+	void *priv;
+
+	/* run time configuration */
+	unsigned enable_vlan:1;
+	unsigned enable_jumbo:1;
+	unsigned allow_vid_4095:1;
+
+	struct b53_port *ports;
+	struct b53_vlan *vlans;
+
+	char *buf;
+};
+
+#define b53_for_each_port(dev, i) \
+	for (i = 0; i < B53_N_PORTS; i++) \
+		if (dev->enabled_ports & BIT(i))
+
+
+
+static inline int is5325(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5325_DEVICE_ID;
+}
+
+static inline int is5365(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM47XX
+	return dev->chip_id == BCM5365_DEVICE_ID;
+#else
+	return 0;
+#endif
+}
+
+static inline int is5397_98(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5397_DEVICE_ID ||
+		dev->chip_id == BCM5398_DEVICE_ID;
+}
+
+static inline int is539x(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5395_DEVICE_ID ||
+		dev->chip_id == BCM5397_DEVICE_ID ||
+		dev->chip_id == BCM5398_DEVICE_ID;
+}
+
+static inline int is531x5(struct b53_device *dev)
+{
+	return dev->chip_id == BCM53115_DEVICE_ID ||
+		dev->chip_id == BCM53125_DEVICE_ID ||
+		dev->chip_id == BCM53128_DEVICE_ID;
+}
+
+static inline int is63xx(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM63XX
+	return dev->chip_id == BCM63XX_DEVICE_ID;
+#else
+	return 0;
+#endif
+}
+
+static inline int is5301x(struct b53_device *dev)
+{
+	return dev->chip_id == BCM53010_DEVICE_ID ||
+		dev->chip_id == BCM53011_DEVICE_ID ||
+		dev->chip_id == BCM53012_DEVICE_ID ||
+		dev->chip_id == BCM53018_DEVICE_ID ||
+		dev->chip_id == BCM53019_DEVICE_ID;
+}
+
+#define B53_CPU_PORT_25	5
+#define B53_CPU_PORT	8
+
+static inline int is_cpu_port(struct b53_device *dev, int port)
+{
+	return dev->sw_dev.cpu_port == port;
+}
+
+static inline struct b53_device *sw_to_b53(struct switch_dev *sw)
+{
+	return container_of(sw, struct b53_device, sw_dev);
+}
+
+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
+				    void *priv);
+
+int b53_switch_detect(struct b53_device *dev);
+
+int b53_switch_register(struct b53_device *dev);
+
+static inline void b53_switch_remove(struct b53_device *dev)
+{
+	unregister_switch(&dev->sw_dev);
+}
+
+static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read8(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read16(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read32(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read48(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read64(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write8(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
+			      u16 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write16(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
+			      u32 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write32(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
+			      u64 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write48(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
+			       u64 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write64(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+#ifdef CONFIG_BCM47XX
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+#include <linux/bcm47xx_nvram.h>
+#else
+#include <bcm47xx_nvram.h>
+#endif
+#include <bcm47xx_board.h>
+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
+{
+	enum bcm47xx_board board = bcm47xx_board_get();
+
+	switch (board) {
+	case BCM47XX_BOARD_LINKSYS_WRT300NV11:
+	case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+		return 8;
+	default:
+		return bcm47xx_nvram_gpio_pin("robo_reset");
+	}
+}
+#else
+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
+{
+	return -ENOENT;
+}
+#endif
+#endif
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h b/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h
new file mode 100644
index 0000000000..f0bf6744a7
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h
@@ -0,0 +1,348 @@
+/*
+ * B53 register definitions
+ *
+ * Copyright (C) 2004 Broadcom Corporation
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __B53_REGS_H
+#define __B53_REGS_H
+
+/* Management Port (SMP) Page offsets */
+#define B53_CTRL_PAGE			0x00 /* Control */
+#define B53_STAT_PAGE			0x01 /* Status */
+#define B53_MGMT_PAGE			0x02 /* Management Mode */
+#define B53_MIB_AC_PAGE			0x03 /* MIB Autocast */
+#define B53_ARLCTRL_PAGE		0x04 /* ARL Control */
+#define B53_ARLIO_PAGE			0x05 /* ARL Access */
+#define B53_FRAMEBUF_PAGE		0x06 /* Management frame access */
+#define B53_MEM_ACCESS_PAGE		0x08 /* Memory access */
+
+/* PHY Registers */
+#define B53_PORT_MII_PAGE(i)		(0x10 + (i)) /* Port i MII Registers */
+#define B53_IM_PORT_PAGE		0x18 /* Inverse MII Port (to EMAC) */
+#define B53_ALL_PORT_PAGE		0x19 /* All ports MII (broadcast) */
+
+/* MIB registers */
+#define B53_MIB_PAGE(i)			(0x20 + (i))
+
+/* Quality of Service (QoS) Registers */
+#define B53_QOS_PAGE			0x30
+
+/* Port VLAN Page */
+#define B53_PVLAN_PAGE			0x31
+
+/* VLAN Registers */
+#define B53_VLAN_PAGE			0x34
+
+/* Jumbo Frame Registers */
+#define B53_JUMBO_PAGE			0x40
+
+/* CFP Configuration Registers Page */
+#define B53_CFP_PAGE			0xa1
+
+/*************************************************************************
+ * Control Page registers
+ *************************************************************************/
+
+/* Port Control Register (8 bit) */
+#define B53_PORT_CTRL(i)		(0x00 + (i))
+#define   PORT_CTRL_RX_DISABLE		BIT(0)
+#define   PORT_CTRL_TX_DISABLE		BIT(1)
+#define   PORT_CTRL_RX_BCST_EN		BIT(2) /* Broadcast RX (P8 only) */
+#define   PORT_CTRL_RX_MCST_EN		BIT(3) /* Multicast RX (P8 only) */
+#define   PORT_CTRL_RX_UCST_EN		BIT(4) /* Unicast RX (P8 only) */
+#define	  PORT_CTRL_STP_STATE_S		5
+#define   PORT_CTRL_STP_STATE_MASK	(0x7 << PORT_CTRL_STP_STATE_S)
+
+/* SMP Control Register (8 bit) */
+#define B53_SMP_CTRL			0x0a
+
+/* Switch Mode Control Register (8 bit) */
+#define B53_SWITCH_MODE			0x0b
+#define   SM_SW_FWD_MODE		BIT(0)	/* 1 = Managed Mode */
+#define   SM_SW_FWD_EN			BIT(1)	/* Forwarding Enable */
+
+/* IMP Port state override register (8 bit) */
+#define B53_PORT_OVERRIDE_CTRL		0x0e
+#define   PORT_OVERRIDE_LINK		BIT(0)
+#define   PORT_OVERRIDE_FULL_DUPLEX	BIT(1) /* 0 = Half Duplex */
+#define   PORT_OVERRIDE_SPEED_S		2
+#define   PORT_OVERRIDE_SPEED_10M	(0 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_100M	(1 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_1000M	(2 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_RV_MII_25	BIT(4) /* BCM5325 only */
+#define   PORT_OVERRIDE_RX_FLOW		BIT(4)
+#define   PORT_OVERRIDE_TX_FLOW		BIT(5)
+#define   PORT_OVERRIDE_SPEED_2000M	BIT(6) /* BCM5301X only, requires setting 1000M */
+#define   PORT_OVERRIDE_EN		BIT(7) /* Use the register contents */
+
+/* Power-down mode control */
+#define B53_PD_MODE_CTRL_25		0x0f
+
+/* IP Multicast control (8 bit) */
+#define B53_IP_MULTICAST_CTRL		0x21
+#define  B53_IPMC_FWD_EN		BIT(1)
+#define  B53_UC_FWD_EN			BIT(6)
+#define  B53_MC_FWD_EN			BIT(7)
+
+/* (16 bit) */
+#define B53_UC_FLOOD_MASK		0x32
+#define B53_MC_FLOOD_MASK		0x34
+#define B53_IPMC_FLOOD_MASK		0x36
+
+/*
+ * Override Ports 0-7 State on devices with xMII interfaces (8 bit)
+ *
+ * For port 8 still use B53_PORT_OVERRIDE_CTRL
+ * Please note that not all ports are available on every hardware, e.g. BCM5301X
+ * don't include overriding port 6, BCM63xx also have some limitations.
+ */
+#define B53_GMII_PORT_OVERRIDE_CTRL(i)	(0x58 + (i))
+#define   GMII_PO_LINK			BIT(0)
+#define   GMII_PO_FULL_DUPLEX		BIT(1) /* 0 = Half Duplex */
+#define   GMII_PO_SPEED_S		2
+#define   GMII_PO_SPEED_10M		(0 << GMII_PO_SPEED_S)
+#define   GMII_PO_SPEED_100M		(1 << GMII_PO_SPEED_S)
+#define   GMII_PO_SPEED_1000M		(2 << GMII_PO_SPEED_S)
+#define   GMII_PO_RX_FLOW		BIT(4)
+#define   GMII_PO_TX_FLOW		BIT(5)
+#define   GMII_PO_EN			BIT(6) /* Use the register contents */
+#define   GMII_PO_SPEED_2000M		BIT(7) /* BCM5301X only, requires setting 1000M */
+
+/* Software reset register (8 bit) */
+#define B53_SOFTRESET			0x79
+
+/* Fast Aging Control register (8 bit) */
+#define B53_FAST_AGE_CTRL		0x88
+#define   FAST_AGE_STATIC		BIT(0)
+#define   FAST_AGE_DYNAMIC		BIT(1)
+#define   FAST_AGE_PORT			BIT(2)
+#define   FAST_AGE_VLAN			BIT(3)
+#define   FAST_AGE_STP			BIT(4)
+#define   FAST_AGE_MC			BIT(5)
+#define   FAST_AGE_DONE			BIT(7)
+
+/*************************************************************************
+ * Status Page registers
+ *************************************************************************/
+
+/* Link Status Summary Register (16bit) */
+#define B53_LINK_STAT			0x00
+
+/* Link Status Change Register (16 bit) */
+#define B53_LINK_STAT_CHANGE		0x02
+
+/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
+#define B53_SPEED_STAT			0x04
+#define  SPEED_PORT_FE(reg, port)	(((reg) >> (port)) & 1)
+#define  SPEED_PORT_GE(reg, port)	(((reg) >> 2 * (port)) & 3)
+#define  SPEED_STAT_10M			0
+#define  SPEED_STAT_100M		1
+#define  SPEED_STAT_1000M		2
+
+/* Duplex Status Summary (16 bit) */
+#define B53_DUPLEX_STAT_FE		0x06
+#define B53_DUPLEX_STAT_GE		0x08
+#define B53_DUPLEX_STAT_63XX		0x0c
+
+/* Revision ID register for BCM5325 */
+#define B53_REV_ID_25			0x50
+
+/* Strap Value (48 bit) */
+#define B53_STRAP_VALUE			0x70
+#define   SV_GMII_CTRL_115		BIT(27)
+
+/*************************************************************************
+ * Management Mode Page Registers
+ *************************************************************************/
+
+/* Global Management Config Register (8 bit) */
+#define B53_GLOBAL_CONFIG		0x00
+#define   GC_RESET_MIB			0x01
+#define   GC_RX_BPDU_EN			0x02
+#define   GC_MIB_AC_HDR_EN		0x10
+#define   GC_MIB_AC_EN			0x20
+#define   GC_FRM_MGMT_PORT_M		0xC0
+#define   GC_FRM_MGMT_PORT_04		0x00
+#define   GC_FRM_MGMT_PORT_MII		0x80
+
+/* Broadcom Header control register (8 bit) */
+#define B53_BRCM_HDR			0x03
+#define   BRCM_HDR_P8_EN		BIT(0) /* Enable tagging on port 8 */
+#define   BRCM_HDR_P5_EN		BIT(1) /* Enable tagging on port 5 */
+
+/* Device ID register (8 or 32 bit) */
+#define B53_DEVICE_ID			0x30
+
+/* Revision ID register (8 bit) */
+#define B53_REV_ID			0x40
+
+/*************************************************************************
+ * ARL Access Page Registers
+ *************************************************************************/
+
+/* VLAN Table Access Register (8 bit) */
+#define B53_VT_ACCESS			0x80
+#define B53_VT_ACCESS_9798		0x60 /* for BCM5397/BCM5398 */
+#define B53_VT_ACCESS_63XX		0x60 /* for BCM6328/62/68 */
+#define   VTA_CMD_WRITE			0
+#define   VTA_CMD_READ			1
+#define   VTA_CMD_CLEAR			2
+#define   VTA_START_CMD			BIT(7)
+
+/* VLAN Table Index Register (16 bit) */
+#define B53_VT_INDEX			0x81
+#define B53_VT_INDEX_9798		0x61
+#define B53_VT_INDEX_63XX		0x62
+
+/* VLAN Table Entry Register (32 bit) */
+#define B53_VT_ENTRY			0x83
+#define B53_VT_ENTRY_9798		0x63
+#define B53_VT_ENTRY_63XX		0x64
+#define   VTE_MEMBERS			0x1ff
+#define   VTE_UNTAG_S			9
+#define   VTE_UNTAG			(0x1ff << 9)
+
+/*************************************************************************
+ * Port VLAN Registers
+ *************************************************************************/
+
+/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
+#define B53_PVLAN_PORT_MASK(i)		((i) * 2)
+
+/*************************************************************************
+ * 802.1Q Page Registers
+ *************************************************************************/
+
+/* Global QoS Control (8 bit) */
+#define B53_QOS_GLOBAL_CTL		0x00
+
+/* Enable 802.1Q for individual Ports (16 bit) */
+#define B53_802_1P_EN			0x04
+
+/*************************************************************************
+ * VLAN Page Registers
+ *************************************************************************/
+
+/* VLAN Control 0 (8 bit) */
+#define B53_VLAN_CTRL0			0x00
+#define   VC0_8021PF_CTRL_MASK		0x3
+#define   VC0_8021PF_CTRL_NONE		0x0
+#define   VC0_8021PF_CTRL_CHANGE_PRI	0x1
+#define   VC0_8021PF_CTRL_CHANGE_VID	0x2
+#define   VC0_8021PF_CTRL_CHANGE_BOTH	0x3
+#define   VC0_8021QF_CTRL_MASK		0xc
+#define   VC0_8021QF_CTRL_CHANGE_PRI	0x1
+#define   VC0_8021QF_CTRL_CHANGE_VID	0x2
+#define   VC0_8021QF_CTRL_CHANGE_BOTH	0x3
+#define   VC0_RESERVED_1		BIT(1)
+#define   VC0_DROP_VID_MISS		BIT(4)
+#define   VC0_VID_HASH_VID		BIT(5)
+#define   VC0_VID_CHK_EN		BIT(6)	/* Use VID,DA or VID,SA */
+#define   VC0_VLAN_EN			BIT(7)	/* 802.1Q VLAN Enabled */
+
+/* VLAN Control 1 (8 bit) */
+#define B53_VLAN_CTRL1			0x01
+#define   VC1_RX_MCST_TAG_EN		BIT(1)
+#define   VC1_RX_MCST_FWD_EN		BIT(2)
+#define   VC1_RX_MCST_UNTAG_EN		BIT(3)
+
+/* VLAN Control 2 (8 bit) */
+#define B53_VLAN_CTRL2			0x02
+
+/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
+#define B53_VLAN_CTRL3			0x03
+#define B53_VLAN_CTRL3_63XX		0x04
+#define   VC3_MAXSIZE_1532		BIT(6) /* 5325 only */
+#define   VC3_HIGH_8BIT_EN		BIT(7) /* 5325 only */
+
+/* VLAN Control 4 (8 bit) */
+#define B53_VLAN_CTRL4			0x05
+#define B53_VLAN_CTRL4_25		0x04
+#define B53_VLAN_CTRL4_63XX		0x06
+#define   VC4_ING_VID_CHECK_S		6
+#define   VC4_ING_VID_CHECK_MASK	(0x3 << VC4_ING_VID_CHECK_S)
+#define   VC4_ING_VID_VIO_FWD		0 /* forward, but do not learn */
+#define   VC4_ING_VID_VIO_DROP		1 /* drop VID violations */
+#define   VC4_NO_ING_VID_CHK		2 /* do not check */
+#define   VC4_ING_VID_VIO_TO_IMP	3 /* redirect to MII port */
+
+/* VLAN Control 5 (8 bit) */
+#define B53_VLAN_CTRL5			0x06
+#define B53_VLAN_CTRL5_25		0x05
+#define B53_VLAN_CTRL5_63XX		0x07
+#define   VC5_VID_FFF_EN		BIT(2)
+#define   VC5_DROP_VTABLE_MISS		BIT(3)
+
+/* VLAN Control 6 (8 bit) */
+#define B53_VLAN_CTRL6			0x07
+#define B53_VLAN_CTRL6_63XX		0x08
+
+/* VLAN Table Access Register (16 bit) */
+#define B53_VLAN_TABLE_ACCESS_25	0x06	/* BCM5325E/5350 */
+#define B53_VLAN_TABLE_ACCESS_65	0x08	/* BCM5365 */
+#define   VTA_VID_LOW_MASK_25		0xf
+#define   VTA_VID_LOW_MASK_65		0xff
+#define   VTA_VID_HIGH_S_25		4
+#define   VTA_VID_HIGH_S_65		8
+#define   VTA_VID_HIGH_MASK_25		(0xff << VTA_VID_HIGH_S_25E)
+#define   VTA_VID_HIGH_MASK_65		(0xf << VTA_VID_HIGH_S_65)
+#define   VTA_RW_STATE			BIT(12)
+#define   VTA_RW_STATE_RD		0
+#define   VTA_RW_STATE_WR		BIT(12)
+#define   VTA_RW_OP_EN			BIT(13)
+
+/* VLAN Read/Write Registers for (16/32 bit) */
+#define B53_VLAN_WRITE_25		0x08
+#define B53_VLAN_WRITE_65		0x0a
+#define B53_VLAN_READ			0x0c
+#define   VA_MEMBER_MASK		0x3f
+#define   VA_UNTAG_S_25			6
+#define   VA_UNTAG_MASK_25		0x3f
+#define   VA_UNTAG_S_65			7
+#define   VA_UNTAG_MASK_65		0x1f
+#define   VA_VID_HIGH_S			12
+#define   VA_VID_HIGH_MASK		(0xffff << VA_VID_HIGH_S)
+#define   VA_VALID_25			BIT(20)
+#define   VA_VALID_25_R4		BIT(24)
+#define   VA_VALID_65			BIT(14)
+
+/* VLAN Port Default Tag (16 bit) */
+#define B53_VLAN_PORT_DEF_TAG(i)	(0x10 + 2 * (i))
+
+/*************************************************************************
+ * Jumbo Frame Page Registers
+ *************************************************************************/
+
+/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
+#define B53_JUMBO_PORT_MASK		0x01
+#define B53_JUMBO_PORT_MASK_63XX	0x04
+#define   JPM_10_100_JUMBO_EN		BIT(24) /* GigE always enabled */
+
+/* Good Frame Max Size without 802.1Q TAG (16 bit) */
+#define B53_JUMBO_MAX_SIZE		0x05
+#define B53_JUMBO_MAX_SIZE_63XX		0x08
+#define   JMS_MIN_SIZE			1518
+#define   JMS_MAX_SIZE			9724
+
+/*************************************************************************
+ * CFP Configuration Page Registers
+ *************************************************************************/
+
+/* CFP Control Register with ports map (8 bit) */
+#define B53_CFP_CTRL			0x00
+
+#endif /* !__B53_REGS_H */
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c b/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c
new file mode 100644
index 0000000000..469a8ddde3
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c
@@ -0,0 +1,330 @@
+/*
+ * B53 register access through SPI
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <asm/unaligned.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+#define B53_SPI_DATA		0xf0
+
+#define B53_SPI_STATUS		0xfe
+#define B53_SPI_CMD_SPIF	BIT(7)
+#define B53_SPI_CMD_RACK	BIT(5)
+
+#define B53_SPI_CMD_READ	0x00
+#define B53_SPI_CMD_WRITE	0x01
+#define B53_SPI_CMD_NORMAL	0x60
+#define B53_SPI_CMD_FAST	0x10
+
+#define B53_SPI_PAGE_SELECT	0xff
+
+static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
+				     unsigned len)
+{
+	u8 txbuf[2];
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
+	txbuf[1] = reg;
+
+	return spi_write_then_read(spi, txbuf, 2, val, len);
+}
+
+static inline int b53_spi_clear_status(struct spi_device *spi)
+{
+	unsigned int i;
+	u8 rxbuf;
+	int ret;
+
+	for (i = 0; i < 10; i++) {
+		ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
+		if (ret)
+			return ret;
+
+		if (!(rxbuf & B53_SPI_CMD_SPIF))
+			break;
+
+		mdelay(1);
+	}
+
+	if (i == 10)
+		return -EIO;
+
+	return 0;
+}
+
+static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
+{
+	u8 txbuf[3];
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = B53_SPI_PAGE_SELECT;
+	txbuf[2] = page;
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
+{
+	int ret = b53_spi_clear_status(spi);
+
+	if (ret)
+		return ret;
+
+	return b53_spi_set_page(spi, page);
+}
+
+static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
+{
+	u8 rxbuf;
+	int retry_count;
+	int ret;
+
+	ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
+	if (ret)
+		return ret;
+
+	for (retry_count = 0; retry_count < 10; retry_count++) {
+		ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
+		if (ret)
+			return ret;
+
+		if (rxbuf & B53_SPI_CMD_RACK)
+			break;
+
+		mdelay(1);
+	}
+
+	if (retry_count == 10)
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
+			unsigned len)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	ret = b53_spi_prepare_reg_read(spi, reg);
+	if (ret)
+		return ret;
+
+	return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
+}
+
+static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	return b53_spi_read(dev, page, reg, val, 1);
+}
+
+static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
+
+	if (!ret)
+		*val = le16_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
+
+	if (!ret)
+		*val = le32_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	*val = 0;
+	ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
+	if (!ret)
+		*val = le64_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
+
+	if (!ret)
+		*val = le64_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[3];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	txbuf[2] = value;
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[4];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le16(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[6];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le32(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[10];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le64(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf) - 2);
+}
+
+static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[10];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le64(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static struct b53_io_ops b53_spi_ops = {
+	.read8 = b53_spi_read8,
+	.read16 = b53_spi_read16,
+	.read32 = b53_spi_read32,
+	.read48 = b53_spi_read48,
+	.read64 = b53_spi_read64,
+	.write8 = b53_spi_write8,
+	.write16 = b53_spi_write16,
+	.write32 = b53_spi_write32,
+	.write48 = b53_spi_write48,
+	.write64 = b53_spi_write64,
+};
+
+static int b53_spi_probe(struct spi_device *spi)
+{
+	struct b53_device *dev;
+	int ret;
+
+	dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
+	if (!dev)
+		return -ENOMEM;
+
+	if (spi->dev.platform_data)
+		dev->pdata = spi->dev.platform_data;
+
+	ret = b53_switch_register(dev);
+	if (ret)
+		return ret;
+
+	spi_set_drvdata(spi, dev);
+
+	return 0;
+}
+
+static int b53_spi_remove(struct spi_device *spi)
+{
+	struct b53_device *dev = spi_get_drvdata(spi);
+
+	if (dev)
+		b53_switch_remove(dev);
+
+	return 0;
+}
+
+static struct spi_driver b53_spi_driver = {
+	.driver = {
+		.name	= "b53-switch",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= b53_spi_probe,
+	.remove	= b53_spi_remove,
+};
+
+module_spi_driver(b53_spi_driver);
+
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 SPI access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c
new file mode 100644
index 0000000000..012daa3a51
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c
@@ -0,0 +1,378 @@
+/*
+ * B53 register access through Switch Register Access Bridge Registers
+ *
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+/* command and status register of the SRAB */
+#define B53_SRAB_CMDSTAT		0x2c
+#define  B53_SRAB_CMDSTAT_RST		BIT(2)
+#define  B53_SRAB_CMDSTAT_WRITE		BIT(1)
+#define  B53_SRAB_CMDSTAT_GORDYN	BIT(0)
+#define  B53_SRAB_CMDSTAT_PAGE		24
+#define  B53_SRAB_CMDSTAT_REG		16
+
+/* high order word of write data to switch registe */
+#define B53_SRAB_WD_H			0x30
+
+/* low order word of write data to switch registe */
+#define B53_SRAB_WD_L			0x34
+
+/* high order word of read data from switch register */
+#define B53_SRAB_RD_H			0x38
+
+/* low order word of read data from switch register */
+#define B53_SRAB_RD_L			0x3c
+
+/* command and status register of the SRAB */
+#define B53_SRAB_CTRLS			0x40
+#define  B53_SRAB_CTRLS_RCAREQ		BIT(3)
+#define  B53_SRAB_CTRLS_RCAGNT		BIT(4)
+#define  B53_SRAB_CTRLS_SW_INIT_DONE	BIT(6)
+
+/* the register captures interrupt pulses from the switch */
+#define B53_SRAB_INTR			0x44
+
+static int b53_srab_request_grant(struct b53_device *dev)
+{
+	u8 __iomem *regs = dev->priv;
+	u32 ctrls;
+	int i;
+
+	ctrls = readl(regs + B53_SRAB_CTRLS);
+	ctrls |= B53_SRAB_CTRLS_RCAREQ;
+	writel(ctrls, regs + B53_SRAB_CTRLS);
+
+	for (i = 0; i < 20; i++) {
+		ctrls = readl(regs + B53_SRAB_CTRLS);
+		if (ctrls & B53_SRAB_CTRLS_RCAGNT)
+			break;
+		usleep_range(10, 100);
+	}
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static void b53_srab_release_grant(struct b53_device *dev)
+{
+	u8 __iomem *regs = dev->priv;
+	u32 ctrls;
+
+	ctrls = readl(regs + B53_SRAB_CTRLS);
+	ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
+	writel(ctrls, regs + B53_SRAB_CTRLS);
+}
+
+static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
+{
+	int i;
+	u32 cmdstat;
+	u8 __iomem *regs = dev->priv;
+
+	/* set register address */
+	cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
+		  (reg << B53_SRAB_CMDSTAT_REG) |
+		  B53_SRAB_CMDSTAT_GORDYN |
+		  op;
+	writel(cmdstat, regs + B53_SRAB_CMDSTAT);
+
+	/* check if operation completed */
+	for (i = 0; i < 5; ++i) {
+		cmdstat = readl(regs + B53_SRAB_CMDSTAT);
+		if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
+			break;
+		usleep_range(10, 100);
+	}
+
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L) & 0xff;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L);
+	*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L);
+	*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel(value, regs + B53_SRAB_WD_L);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
+			     u16 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel(value, regs + B53_SRAB_WD_L);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
+				    u32 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel(value, regs + B53_SRAB_WD_L);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+
+}
+
+static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
+				    u64 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel((u32)value, regs + B53_SRAB_WD_L);
+	writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+
+}
+
+static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
+			     u64 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel((u32)value, regs + B53_SRAB_WD_L);
+	writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static struct b53_io_ops b53_srab_ops = {
+	.read8 = b53_srab_read8,
+	.read16 = b53_srab_read16,
+	.read32 = b53_srab_read32,
+	.read48 = b53_srab_read48,
+	.read64 = b53_srab_read64,
+	.write8 = b53_srab_write8,
+	.write16 = b53_srab_write16,
+	.write32 = b53_srab_write32,
+	.write48 = b53_srab_write48,
+	.write64 = b53_srab_write64,
+};
+
+static int b53_srab_probe(struct platform_device *pdev)
+{
+	struct b53_platform_data *pdata = pdev->dev.platform_data;
+	struct b53_device *dev;
+
+	if (!pdata)
+		return -EINVAL;
+
+	dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs);
+	if (!dev)
+		return -ENOMEM;
+
+	if (pdata)
+		dev->pdata = pdata;
+
+	platform_set_drvdata(pdev, dev);
+
+	return b53_switch_register(dev);
+}
+
+static int b53_srab_remove(struct platform_device *pdev)
+{
+	struct b53_device *dev = platform_get_drvdata(pdev);
+
+	if (dev)
+		b53_switch_remove(dev);
+
+	return 0;
+}
+
+static struct platform_driver b53_srab_driver = {
+	.probe = b53_srab_probe,
+	.remove = b53_srab_remove,
+	.driver = {
+		.name = "b53-srab-switch",
+	},
+};
+
+module_platform_driver(b53_srab_driver);
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/ip17xx.c b/target/linux/generic/files/drivers/net/phy/ip17xx.c
new file mode 100644
index 0000000000..a4fe53dc5b
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/ip17xx.c
@@ -0,0 +1,1410 @@
+/*
+ * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family
+ *
+ * Copyright (C) 2008 Patrick Horn <patrick.horn@gmail.com>
+ * Copyright (C) 2008, 2010 Martin Mares <mj@ucw.cz>
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/switch.h>
+#include <linux/device.h>
+
+#define MAX_VLANS 16
+#define MAX_PORTS 9
+#undef DUMP_MII_IO
+
+typedef struct ip17xx_reg {
+	u16 p;			// phy
+	u16 m;			// mii
+} reg;
+typedef char bitnum;
+
+#define NOTSUPPORTED {-1,-1}
+
+#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1))
+
+struct ip17xx_state;
+
+/*********** CONSTANTS ***********/
+struct register_mappings {
+	char *NAME;
+	u16 MODEL_NO;			// Compare to bits 4-9 of MII register 0,3.
+	bitnum NUM_PORTS;
+	bitnum CPU_PORT;
+
+/* The default VLAN for each port.
+	 Default: 0x0001 for Ports 0,1,2,3
+		  0x0002 for Ports 4,5 */
+	reg VLAN_DEFAULT_TAG_REG[MAX_PORTS];
+
+/* These ports are tagged.
+	 Default: 0x00 */
+	reg ADD_TAG_REG;
+	reg REMOVE_TAG_REG;
+	bitnum ADD_TAG_BIT[MAX_PORTS];
+/* These ports are untagged.
+	 Default: 0x00 (i.e. do not alter any VLAN tags...)
+	 Maybe set to 0 if user disables VLANs. */
+	bitnum REMOVE_TAG_BIT[MAX_PORTS];
+
+/* Port M and Port N are on the same VLAN.
+	 Default: All ports on all VLANs. */
+// Use register {29, 19+N/2}
+	reg VLAN_LOOKUP_REG;
+// Port 5 uses register {30, 18} but same as odd bits.
+	reg VLAN_LOOKUP_REG_5;		// in a different register on IP175C.
+	bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS];
+	bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS];
+
+/* This VLAN corresponds to which ports.
+	 Default: 0x2f,0x30,0x3f,0x3f... */
+	reg TAG_VLAN_MASK_REG;
+	bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS];
+	bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS];
+
+	int RESET_VAL;
+	reg RESET_REG;
+
+	reg MODE_REG;
+	int MODE_VAL;
+
+/* General flags */
+	reg ROUTER_CONTROL_REG;
+	reg VLAN_CONTROL_REG;
+	bitnum TAG_VLAN_BIT;
+	bitnum ROUTER_EN_BIT;
+	bitnum NUMLAN_GROUPS_MAX;
+	bitnum NUMLAN_GROUPS_BIT;
+
+	reg MII_REGISTER_EN;
+	bitnum MII_REGISTER_EN_BIT;
+
+	// set to 1 for 178C, 0 for 175C.
+	bitnum SIMPLE_VLAN_REGISTERS;	// 175C has two vlans per register but 178C has only one.
+
+	// Pointers to functions which manipulate hardware state
+	int (*update_state)(struct ip17xx_state *state);
+	int (*set_vlan_mode)(struct ip17xx_state *state);
+	int (*reset)(struct ip17xx_state *state);
+};
+
+static int ip175c_update_state(struct ip17xx_state *state);
+static int ip175c_set_vlan_mode(struct ip17xx_state *state);
+static int ip175c_reset(struct ip17xx_state *state);
+
+static const struct register_mappings IP178C = {
+	.NAME = "IP178C",
+	.MODEL_NO = 0x18,
+	.VLAN_DEFAULT_TAG_REG = {
+		{30,3},{30,4},{30,5},{30,6},{30,7},{30,8},
+		{30,9},{30,10},{30,11},
+	},
+
+	.ADD_TAG_REG = {30,12},
+	.ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8},
+	.REMOVE_TAG_REG = {30,13},
+	.REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12},
+
+	.SIMPLE_VLAN_REGISTERS = 1,
+
+	.VLAN_LOOKUP_REG = {31,0},// +N
+	.VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS
+	.VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8},
+	.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8},
+
+	.TAG_VLAN_MASK_REG = {30,14}, // +N
+	.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8},
+	.TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8},
+
+	.RESET_VAL = 0x55AA,
+	.RESET_REG = {30,0},
+	.MODE_VAL = 0,
+	.MODE_REG = NOTSUPPORTED,
+
+	.ROUTER_CONTROL_REG = {30,30},
+	.ROUTER_EN_BIT = 11,
+	.NUMLAN_GROUPS_MAX = 8,
+	.NUMLAN_GROUPS_BIT = 8, // {0-2}
+
+	.VLAN_CONTROL_REG = {30,13},
+	.TAG_VLAN_BIT = 3,
+
+	.CPU_PORT = 8,
+	.NUM_PORTS = 9,
+
+	.MII_REGISTER_EN = NOTSUPPORTED,
+
+	.update_state = ip175c_update_state,
+	.set_vlan_mode = ip175c_set_vlan_mode,
+	.reset = ip175c_reset,
+};
+
+static const struct register_mappings IP175C = {
+	.NAME = "IP175C",
+	.MODEL_NO = 0x18,
+	.VLAN_DEFAULT_TAG_REG = {
+		{29,24},{29,25},{29,26},{29,27},{29,28},{29,30},
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED
+	},
+
+	.ADD_TAG_REG = {29,23},
+	.REMOVE_TAG_REG = {29,23},
+	.ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1},
+	.REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1},
+
+	.SIMPLE_VLAN_REGISTERS = 0,
+
+	.VLAN_LOOKUP_REG = {29,19},// +N/2
+	.VLAN_LOOKUP_REG_5 = {30,18},
+	.VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1},
+	.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1},
+
+	.TAG_VLAN_MASK_REG = {30,1}, // +N/2
+	.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1},
+	.TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1},
+
+	.RESET_VAL = 0x175C,
+	.RESET_REG = {30,0},
+	.MODE_VAL = 0x175C,
+	.MODE_REG = {29,31},
+
+	.ROUTER_CONTROL_REG = {30,9},
+	.ROUTER_EN_BIT = 3,
+	.NUMLAN_GROUPS_MAX = 8,
+	.NUMLAN_GROUPS_BIT = 0, // {0-2}
+
+	.VLAN_CONTROL_REG = {30,9},
+	.TAG_VLAN_BIT = 7,
+
+	.NUM_PORTS = 6,
+	.CPU_PORT = 5,
+
+	.MII_REGISTER_EN = NOTSUPPORTED,
+
+	.update_state = ip175c_update_state,
+	.set_vlan_mode = ip175c_set_vlan_mode,
+	.reset = ip175c_reset,
+};
+
+static const struct register_mappings IP175A = {
+	.NAME = "IP175A",
+	.MODEL_NO = 0x05,
+	.VLAN_DEFAULT_TAG_REG = {
+		{0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED,
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED
+	},
+
+	.ADD_TAG_REG = {0,23},
+	.REMOVE_TAG_REG = {0,23},
+	.ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1},
+	.REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1},
+
+	.SIMPLE_VLAN_REGISTERS = 0,
+
+	// Only programmable via EEPROM
+	.VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2
+	.VLAN_LOOKUP_REG_5 = NOTSUPPORTED,
+	.VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1},
+	.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1},
+
+	.TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2,
+	.TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1},
+	.TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1},
+
+	.RESET_VAL = -1,
+	.RESET_REG = NOTSUPPORTED,
+	.MODE_VAL = 0,
+	.MODE_REG = NOTSUPPORTED,
+
+	.ROUTER_CONTROL_REG = NOTSUPPORTED,
+	.VLAN_CONTROL_REG = NOTSUPPORTED,
+	.TAG_VLAN_BIT = -1,
+	.ROUTER_EN_BIT = -1,
+	.NUMLAN_GROUPS_MAX = -1,
+	.NUMLAN_GROUPS_BIT = -1, // {0-2}
+
+	.NUM_PORTS = 5,
+	.CPU_PORT = 4,
+
+	.MII_REGISTER_EN = {0, 18},
+	.MII_REGISTER_EN_BIT = 7,
+
+	.update_state = ip175c_update_state,
+	.set_vlan_mode = ip175c_set_vlan_mode,
+	.reset = ip175c_reset,
+};
+
+
+static int ip175d_update_state(struct ip17xx_state *state);
+static int ip175d_set_vlan_mode(struct ip17xx_state *state);
+static int ip175d_reset(struct ip17xx_state *state);
+
+static const struct register_mappings IP175D = {
+	.NAME = "IP175D",
+	.MODEL_NO = 0x18,
+
+	// The IP175D has a completely different interface, so we leave most
+	// of the registers undefined and switch to different code paths.
+
+	.VLAN_DEFAULT_TAG_REG = {
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
+	},
+
+	.ADD_TAG_REG = NOTSUPPORTED,
+	.REMOVE_TAG_REG = NOTSUPPORTED,
+
+	.SIMPLE_VLAN_REGISTERS = 0,
+
+	.VLAN_LOOKUP_REG = NOTSUPPORTED,
+	.VLAN_LOOKUP_REG_5 = NOTSUPPORTED,
+	.TAG_VLAN_MASK_REG = NOTSUPPORTED,
+
+	.RESET_VAL = 0x175D,
+	.RESET_REG = {20,2},
+	.MODE_REG = NOTSUPPORTED,
+
+	.ROUTER_CONTROL_REG = NOTSUPPORTED,
+	.ROUTER_EN_BIT = -1,
+	.NUMLAN_GROUPS_BIT = -1,
+
+	.VLAN_CONTROL_REG = NOTSUPPORTED,
+	.TAG_VLAN_BIT = -1,
+
+	.NUM_PORTS = 6,
+	.CPU_PORT = 5,
+
+	.MII_REGISTER_EN = NOTSUPPORTED,
+
+	.update_state = ip175d_update_state,
+	.set_vlan_mode = ip175d_set_vlan_mode,
+	.reset = ip175d_reset,
+};
+
+struct ip17xx_state {
+	struct switch_dev dev;
+	struct mii_bus *mii_bus;
+	bool registered;
+
+	int router_mode;		// ROUTER_EN
+	int vlan_enabled;		// TAG_VLAN_EN
+	struct port_state {
+		u16 pvid;
+		unsigned int shareports;
+	} ports[MAX_PORTS];
+	unsigned int add_tag;
+	unsigned int remove_tag;
+	int num_vlans;
+	struct vlan_state {
+		unsigned int ports;
+		unsigned int tag;	// VLAN tag (IP175D only)
+	} vlans[MAX_VLANS];
+	const struct register_mappings *regs;
+	reg proc_mii; 	// phy/reg for the low level register access via swconfig
+
+	char buf[80];
+};
+
+#define get_state(_dev) container_of((_dev), struct ip17xx_state, dev)
+
+static int ip_phy_read(struct ip17xx_state *state, int port, int reg)
+{
+	int val = mdiobus_read(state->mii_bus, port, reg);
+	if (val < 0)
+		pr_warning("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val);
+#ifdef DUMP_MII_IO
+	else
+		pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val);
+#endif
+	return val;
+}
+
+static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val)
+{
+	int err;
+
+#ifdef DUMP_MII_IO
+	pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val);
+#endif
+	err = mdiobus_write(state->mii_bus, port, reg, val);
+	if (err < 0)
+		pr_warning("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err);
+	return err;
+}
+
+static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data)
+{
+	int val = ip_phy_read(state, port, reg);
+	if (val < 0)
+		return 0;
+	return ip_phy_write(state, port, reg, (val & ~mask) | data);
+}
+
+static int getPhy(struct ip17xx_state *state, reg mii)
+{
+	if (!REG_SUPP(mii))
+		return -EFAULT;
+	return ip_phy_read(state, mii.p, mii.m);
+}
+
+static int setPhy(struct ip17xx_state *state, reg mii, u16 value)
+{
+	int err;
+
+	if (!REG_SUPP(mii))
+		return -EFAULT;
+	err = ip_phy_write(state, mii.p, mii.m, value);
+	if (err < 0)
+		return err;
+	mdelay(2);
+	getPhy(state, mii);
+	return 0;
+}
+
+
+/**
+ * These two macros are to simplify the mapping of logical bits to the bits in hardware.
+ * NOTE: these macros will return if there is an error!
+ */
+
+#define GET_PORT_BITS(state, bits, addr, bit_lookup)		\
+	do {							\
+		int i, val = getPhy((state), (addr));		\
+		if (val < 0)					\
+			return val;				\
+		(bits) = 0;					\
+		for (i = 0; i < MAX_PORTS; i++) {		\
+			if ((bit_lookup)[i] == -1) continue;	\
+			if (val & (1<<(bit_lookup)[i]))		\
+				(bits) |= (1<<i);		\
+		}						\
+	} while (0)
+
+#define SET_PORT_BITS(state, bits, addr, bit_lookup)		\
+	do {							\
+		int i, val = getPhy((state), (addr));		\
+		if (val < 0)					\
+			return val;				\
+		for (i = 0; i < MAX_PORTS; i++) {		\
+			unsigned int newmask = ((bits)&(1<<i));	\
+			if ((bit_lookup)[i] == -1) continue;	\
+			val &= ~(1<<(bit_lookup)[i]);		\
+			val |= ((newmask>>i)<<(bit_lookup)[i]);	\
+		}						\
+		val = setPhy((state), (addr), val);		\
+		if (val < 0)					\
+			return val;				\
+	} while (0)
+
+
+static int get_model(struct ip17xx_state *state)
+{
+	int id1, id2;
+	int oui_id, model_no, rev_no, chip_no;
+
+	id1 = ip_phy_read(state, 0, 2);
+	id2 = ip_phy_read(state, 0, 3);
+	oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f);
+	model_no = (id2 >> 4) & 0x3f;
+	rev_no = id2 & 0xf;
+	pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no);
+
+	if (oui_id != 0x0090c3)  // No other oui_id should have reached us anyway
+		return -ENODEV;
+
+	if (model_no == IP175A.MODEL_NO) {
+		state->regs = &IP175A;
+	} else if (model_no == IP175C.MODEL_NO) {
+		/*
+		 *  Several models share the same model_no:
+		 *  178C has more PHYs, so we try whether the device responds to a read from PHY5
+		 *  175D has a new chip ID register
+		 *  175C has neither
+		 */
+		if (ip_phy_read(state, 5, 2) == 0x0243) {
+			state->regs = &IP178C;
+		} else {
+			chip_no = ip_phy_read(state, 20, 0);
+			pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no);
+			if (chip_no == 0x175d) {
+				state->regs = &IP175D;
+			} else {
+				state->regs = &IP175C;
+			}
+		}
+	} else {
+		pr_warning("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no);
+		return -EPERM;
+	}
+	return 0;
+}
+
+/*** Low-level functions for the older models ***/
+
+/** Only set vlan and router flags in the switch **/
+static int ip175c_set_flags(struct ip17xx_state *state)
+{
+	int val;
+
+	if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) {
+		return 0;
+	}
+
+	val = getPhy(state, state->regs->ROUTER_CONTROL_REG);
+	if (val < 0) {
+		return val;
+	}
+	if (state->regs->ROUTER_EN_BIT >= 0) {
+		if (state->router_mode) {
+			val |= (1<<state->regs->ROUTER_EN_BIT);
+		} else {
+			val &= (~(1<<state->regs->ROUTER_EN_BIT));
+		}
+	}
+	if (state->regs->TAG_VLAN_BIT >= 0) {
+		if (state->vlan_enabled) {
+			val |= (1<<state->regs->TAG_VLAN_BIT);
+		} else {
+			val &= (~(1<<state->regs->TAG_VLAN_BIT));
+		}
+	}
+	if (state->regs->NUMLAN_GROUPS_BIT >= 0) {
+		val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<<state->regs->NUMLAN_GROUPS_BIT));
+		if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) {
+			val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT;
+		} else if (state->num_vlans >= 1) {
+			val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT;
+		}
+	}
+	return setPhy(state, state->regs->ROUTER_CONTROL_REG, val);
+}
+
+/** Set all VLAN and port state.  Usually you should call "correct_vlan_state" first. **/
+static int ip175c_set_state(struct ip17xx_state *state)
+{
+	int j;
+	int i;
+	SET_PORT_BITS(state, state->add_tag,
+				  state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT);
+	SET_PORT_BITS(state, state->remove_tag,
+				  state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
+
+	if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) {
+		for (j=0; j<state->regs->NUM_PORTS; j++) {
+			reg addr;
+			const bitnum *bit_lookup = (j%2==0)?
+				state->regs->VLAN_LOOKUP_EVEN_BIT:
+				state->regs->VLAN_LOOKUP_ODD_BIT;
+
+			addr = state->regs->VLAN_LOOKUP_REG;
+			if (state->regs->SIMPLE_VLAN_REGISTERS) {
+				addr.m += j;
+			} else {
+				switch (j) {
+				case 0:
+				case 1:
+					break;
+				case 2:
+				case 3:
+					addr.m+=1;
+					break;
+				case 4:
+					addr.m+=2;
+					break;
+				case 5:
+					addr = state->regs->VLAN_LOOKUP_REG_5;
+					break;
+				default:
+					addr.m = -1; // shouldn't get here, but...
+					break;
+				}
+			}
+			//printf("shareports for %d is %02X\n",j,state->ports[j].shareports);
+			if (REG_SUPP(addr)) {
+				SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup);
+			}
+		}
+	}
+	if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) {
+		for (j=0; j<MAX_VLANS; j++) {
+			reg addr = state->regs->TAG_VLAN_MASK_REG;
+			const bitnum *bit_lookup = (j%2==0)?
+				state->regs->TAG_VLAN_MASK_EVEN_BIT:
+				state->regs->TAG_VLAN_MASK_ODD_BIT;
+			unsigned int vlan_mask;
+			if (state->regs->SIMPLE_VLAN_REGISTERS) {
+				addr.m += j;
+			} else {
+				addr.m += j/2;
+			}
+			vlan_mask = state->vlans[j].ports;
+			SET_PORT_BITS(state, vlan_mask, addr, bit_lookup);
+		}
+	}
+
+	for (i=0; i<MAX_PORTS; i++) {
+		if (REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[i])) {
+			int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i],
+					state->ports[i].pvid);
+			if (err < 0) {
+				return err;
+			}
+		}
+	}
+
+	return ip175c_set_flags(state);
+}
+
+/**
+ *  Uses only the VLAN port mask and the add tag mask to generate the other fields:
+ *  which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids.
+ */
+static void ip175c_correct_vlan_state(struct ip17xx_state *state)
+{
+	int i, j;
+	state->num_vlans = 0;
+	for (i=0; i<MAX_VLANS; i++) {
+		if (state->vlans[i].ports != 0) {
+			state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere...
+		}
+	}
+
+	for (i=0; i<state->regs->NUM_PORTS; i++) {
+		unsigned int portmask = (1<<i);
+		if (!state->vlan_enabled) {
+			// Share with everybody!
+			state->ports[i].shareports = (1<<state->regs->NUM_PORTS)-1;
+			continue;
+		}
+		state->ports[i].shareports = portmask;
+		for (j=0; j<MAX_VLANS; j++) {
+			if (state->vlans[j].ports & portmask)
+				state->ports[i].shareports |= state->vlans[j].ports;
+		}
+	}
+}
+
+static int ip175c_update_state(struct ip17xx_state *state)
+{
+	ip175c_correct_vlan_state(state);
+	return ip175c_set_state(state);
+}
+
+static int ip175c_set_vlan_mode(struct ip17xx_state *state)
+{
+	return ip175c_update_state(state);
+}
+
+static int ip175c_reset(struct ip17xx_state *state)
+{
+	int err;
+
+	if (REG_SUPP(state->regs->MODE_REG)) {
+		err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL);
+		if (err < 0)
+			return err;
+		err = getPhy(state, state->regs->MODE_REG);
+		if (err < 0)
+			return err;
+	}
+
+	return ip175c_update_state(state);
+}
+
+/*** Low-level functions for IP175D ***/
+
+static int ip175d_update_state(struct ip17xx_state *state)
+{
+	unsigned int filter_mask = 0;
+	unsigned int ports[16], add[16], rem[16];
+	int i, j;
+	int err = 0;
+
+	for (i = 0; i < 16; i++) {
+		ports[i] = 0;
+		add[i] = 0;
+		rem[i] = 0;
+		if (!state->vlan_enabled) {
+			err |= ip_phy_write(state, 22, 14+i, i+1);	// default tags
+			ports[i] = 0x3f;
+			continue;
+		}
+		if (!state->vlans[i].tag) {
+			// Reset the filter
+			err |= ip_phy_write(state, 22, 14+i, 0);	// tag
+			continue;
+		}
+		filter_mask |= 1 << i;
+		err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag);
+		ports[i] = state->vlans[i].ports;
+		for (j = 0; j < 6; j++) {
+			if (ports[i] & (1 << j)) {
+				if (state->add_tag & (1 << j))
+					add[i] |= 1 << j;
+				if (state->remove_tag & (1 << j))
+					rem[i] |= 1 << j;
+			}
+		}
+	}
+
+	// Port masks, tag adds and removals
+	for (i = 0; i < 8; i++) {
+		err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8));
+		err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8));
+		err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8));
+	}
+	err |= ip_phy_write(state, 22, 10, filter_mask);
+
+	// Default VLAN tag for each port
+	for (i = 0; i < 6; i++)
+		err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag);
+
+	return (err ? -EIO : 0);
+}
+
+static int ip175d_set_vlan_mode(struct ip17xx_state *state)
+{
+	int i;
+	int err = 0;
+
+	if (state->vlan_enabled) {
+		// VLAN classification rules: tag-based VLANs, use VID to classify,
+		// drop packets that cannot be classified.
+		err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f);
+
+		// Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed,
+		// VID=0xfff discarded, admin both tagged and untagged, ingress
+		// filters enabled.
+		err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
+
+		// Egress rules: IGMP processing off, keep VLAN header off
+		err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
+	} else {
+		// VLAN classification rules: everything off & clear table
+		err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000);
+
+		// Ingress and egress rules: set to defaults
+		err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
+		err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
+	}
+
+	// Reset default VLAN for each port to 0
+	for (i = 0; i < 6; i++)
+		state->ports[i].pvid = 0;
+
+	err |= ip175d_update_state(state);
+
+	return (err ? -EIO : 0);
+}
+
+static int ip175d_reset(struct ip17xx_state *state)
+{
+	int err = 0;
+
+	// Disable the special tagging mode
+	err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000);
+
+	// Set 802.1q protocol type
+	err |= ip_phy_write(state, 22, 3, 0x8100);
+
+	state->vlan_enabled = 0;
+	err |= ip175d_set_vlan_mode(state);
+
+	return (err ? -EIO : 0);
+}
+
+/*** High-level functions ***/
+
+static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	val->value.i = state->vlan_enabled;
+	return 0;
+}
+
+static void ip17xx_reset_vlan_config(struct ip17xx_state *state)
+{
+	int i;
+
+	state->remove_tag = (state->vlan_enabled ? ((1<<state->regs->NUM_PORTS)-1) : 0x0000);
+	state->add_tag = 0x0000;
+	for (i = 0; i < MAX_VLANS; i++) {
+		state->vlans[i].ports = 0x0000;
+		state->vlans[i].tag = (i ? i : 16);
+	}
+	for (i = 0; i < MAX_PORTS; i++)
+		state->ports[i].pvid = 0;
+}
+
+static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int enable;
+
+	enable = val->value.i;
+	if (state->vlan_enabled == enable) {
+		// Do not change any state.
+		return 0;
+	}
+	state->vlan_enabled = enable;
+
+	// Otherwise, if we are switching state, set fields to a known default.
+	ip17xx_reset_vlan_config(state);
+
+	return state->regs->set_vlan_mode(state);
+}
+
+static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int b;
+	int ind;
+	unsigned int ports;
+
+	if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
+		return -EINVAL;
+
+	ports = state->vlans[val->port_vlan].ports;
+	b = 0;
+	ind = 0;
+	while (b < MAX_PORTS) {
+		if (ports&1) {
+			int istagged = ((state->add_tag >> b) & 1);
+			val->value.ports[ind].id = b;
+			val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED);
+			ind++;
+		}
+		b++;
+		ports >>= 1;
+	}
+	val->len = ind;
+
+	return 0;
+}
+
+static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int i;
+
+	if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
+		return -EINVAL;
+
+	state->vlans[val->port_vlan].ports = 0;
+	for (i = 0; i < val->len; i++) {
+		unsigned int bitmask = (1<<val->value.ports[i].id);
+		state->vlans[val->port_vlan].ports |= bitmask;
+		if (val->value.ports[i].flags & (1<<SWITCH_PORT_FLAG_TAGGED)) {
+			state->add_tag |= bitmask;
+			state->remove_tag &= (~bitmask);
+		} else {
+			state->add_tag &= (~bitmask);
+			state->remove_tag |= bitmask;
+		}
+	}
+
+	return state->regs->update_state(state);
+}
+
+static int ip17xx_apply(struct switch_dev *dev)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	if (REG_SUPP(state->regs->MII_REGISTER_EN)) {
+		int val = getPhy(state, state->regs->MII_REGISTER_EN);
+		if (val < 0) {
+			return val;
+		}
+		val |= (1<<state->regs->MII_REGISTER_EN_BIT);
+		return setPhy(state, state->regs->MII_REGISTER_EN, val);
+	}
+	return 0;
+}
+
+static int ip17xx_reset(struct switch_dev *dev)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int i, err;
+
+	if (REG_SUPP(state->regs->RESET_REG)) {
+		err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL);
+		if (err < 0)
+			return err;
+		err = getPhy(state, state->regs->RESET_REG);
+
+		/*
+		 *  Data sheet specifies reset period to be 2 msec.
+		 *  (I don't see any mention of the 2ms delay in the IP178C spec, only
+		 *  in IP175C, but it can't hurt.)
+		 */
+		mdelay(2);
+	}
+
+	/* reset switch ports */
+	for (i = 0; i < state->regs->NUM_PORTS-1; i++) {
+		err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET);
+		if (err < 0)
+			return err;
+	}
+
+	state->router_mode = 0;
+	state->vlan_enabled = 0;
+	ip17xx_reset_vlan_config(state);
+
+	return state->regs->reset(state);
+}
+
+static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	if (state->add_tag & (1<<val->port_vlan)) {
+		if (state->remove_tag & (1<<val->port_vlan))
+			val->value.i = 3; // shouldn't ever happen.
+		else
+			val->value.i = 1;
+	} else {
+		if (state->remove_tag & (1<<val->port_vlan))
+			val->value.i = 0;
+		else
+			val->value.i = 2;
+	}
+	return 0;
+}
+
+static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	state->add_tag &= ~(1<<val->port_vlan);
+	state->remove_tag &= ~(1<<val->port_vlan);
+
+	if (val->value.i == 0)
+		state->remove_tag |= (1<<val->port_vlan);
+	if (val->value.i == 1)
+		state->add_tag |= (1<<val->port_vlan);
+
+	return state->regs->update_state(state);
+}
+
+/** Get the current phy address */
+static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	val->value.i = state->proc_mii.p;
+	return 0;
+}
+
+/** Set a new phy address for low level access to registers */
+static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int new_reg = val->value.i;
+
+	if (new_reg < 0 || new_reg > 31)
+		state->proc_mii.p = (u16)-1;
+	else
+		state->proc_mii.p = (u16)new_reg;
+	return 0;
+}
+
+/** Get the current register number */
+static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	val->value.i = state->proc_mii.m;
+	return 0;
+}
+
+/** Set a new register address for low level access to registers */
+static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int new_reg = val->value.i;
+
+	if (new_reg < 0 || new_reg > 31)
+		state->proc_mii.m = (u16)-1;
+	else
+		state->proc_mii.m = (u16)new_reg;
+	return 0;
+}
+
+/** Get the register content of state->proc_mii */
+static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int retval = -EINVAL;
+	if (REG_SUPP(state->proc_mii))
+		retval = getPhy(state, state->proc_mii);
+
+	if (retval < 0) {
+		return retval;
+	} else {
+		val->value.i = retval;
+		return 0;
+	}
+}
+
+/** Write a value to the register defined by phy/reg above */
+static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int myval, err = -EINVAL;
+
+	myval = val->value.i;
+	if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) {
+		err = setPhy(state, state->proc_mii, (u16)myval);
+	}
+	return err;
+}
+
+static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig.
+	return 0;
+}
+
+static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int vlan = val->port_vlan;
+
+	if (vlan < 0 || vlan >= MAX_VLANS)
+		return -EINVAL;
+
+	val->value.i = state->vlans[vlan].tag;
+	return 0;
+}
+
+static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int vlan = val->port_vlan;
+	int tag = val->value.i;
+
+	if (vlan < 0 || vlan >= MAX_VLANS)
+		return -EINVAL;
+
+	if (tag < 0 || tag > 4095)
+		return -EINVAL;
+
+	state->vlans[vlan].tag = tag;
+	return state->regs->update_state(state);
+}
+
+static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int nr = val->port_vlan;
+	int ctrl;
+	int autoneg;
+	int speed;
+	if (val->value.i == 100) {
+		speed = 1;
+		autoneg = 0;
+	} else if (val->value.i == 10) {
+		speed = 0;
+		autoneg = 0;
+	} else {
+		autoneg = 1;
+		speed = 1;
+	}
+
+	/* Can't set speed for cpu port */
+	if (nr == state->regs->CPU_PORT)
+		return -EINVAL;
+
+	if (nr >= dev->ports || nr < 0)
+		return -EINVAL;
+
+	ctrl = ip_phy_read(state, nr, 0);
+	if (ctrl < 0)
+		return -EIO;
+
+	ctrl &= (~(1<<12));
+	ctrl &= (~(1<<13));
+	ctrl |= (autoneg<<12);
+	ctrl |= (speed<<13);
+
+	return ip_phy_write(state, nr, 0, ctrl);
+}
+
+static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int nr = val->port_vlan;
+	int speed, status;
+
+	if (nr == state->regs->CPU_PORT) {
+		val->value.i = 100;
+		return 0;
+	}
+
+	if (nr >= dev->ports || nr < 0)
+		return -EINVAL;
+
+	status = ip_phy_read(state, nr, 1);
+	speed = ip_phy_read(state, nr, 18);
+	if (status < 0 || speed < 0)
+		return -EIO;
+
+	if (status & 4)
+		val->value.i = ((speed & (1<<11)) ? 100 : 10);
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int ctrl, speed, status;
+	int nr = val->port_vlan;
+	int len;
+	char *buf = state->buf; // fixed-length at 80.
+
+	if (nr == state->regs->CPU_PORT) {
+		sprintf(buf, "up, 100 Mbps, cpu port");
+		val->value.s = buf;
+		return 0;
+	}
+
+	if (nr >= dev->ports || nr < 0)
+		return -EINVAL;
+
+	ctrl = ip_phy_read(state, nr, 0);
+	status = ip_phy_read(state, nr, 1);
+	speed = ip_phy_read(state, nr, 18);
+	if (ctrl < 0 || status < 0 || speed < 0)
+		return -EIO;
+
+	if (status & 4)
+		len = sprintf(buf, "up, %d Mbps, %s duplex",
+			((speed & (1<<11)) ? 100 : 10),
+			((speed & (1<<10)) ? "full" : "half"));
+	else
+		len = sprintf(buf, "down");
+
+	if (ctrl & (1<<12)) {
+		len += sprintf(buf+len, ", auto-negotiate");
+		if (!(status & (1<<5)))
+			len += sprintf(buf+len, " (in progress)");
+	} else {
+		len += sprintf(buf+len, ", fixed speed (%d)",
+			((ctrl & (1<<13)) ? 100 : 10));
+	}
+
+	buf[len] = '\0';
+	val->value.s = buf;
+	return 0;
+}
+
+static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	*val = state->ports[port].pvid;
+	return 0;
+}
+
+static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	if (val < 0 || val >= MAX_VLANS)
+		return -EINVAL;
+
+	state->ports[port].pvid = val;
+	return state->regs->update_state(state);
+}
+
+
+enum Ports {
+	IP17XX_PORT_STATUS,
+	IP17XX_PORT_LINK,
+	IP17XX_PORT_TAGGED,
+	IP17XX_PORT_PVID,
+};
+
+enum Globals {
+	IP17XX_ENABLE_VLAN,
+	IP17XX_GET_NAME,
+	IP17XX_REGISTER_PHY,
+	IP17XX_REGISTER_MII,
+	IP17XX_REGISTER_VALUE,
+	IP17XX_REGISTER_ERRNO,
+};
+
+enum Vlans {
+	IP17XX_VLAN_TAG,
+};
+
+static const struct switch_attr ip17xx_global[] = {
+	[IP17XX_ENABLE_VLAN] = {
+		.id = IP17XX_ENABLE_VLAN,
+		.type = SWITCH_TYPE_INT,
+		.name  = "enable_vlan",
+		.description = "Flag to enable or disable VLANs and tagging",
+		.get  = ip17xx_get_enable_vlan,
+		.set = ip17xx_set_enable_vlan,
+	},
+	[IP17XX_GET_NAME] = {
+		.id = IP17XX_GET_NAME,
+		.type = SWITCH_TYPE_STRING,
+		.description = "Returns the type of IC+ chip.",
+		.name  = "name",
+		.get  = ip17xx_read_name,
+		.set = NULL,
+	},
+	/* jal: added for low level debugging etc. */
+	[IP17XX_REGISTER_PHY] = {
+		.id = IP17XX_REGISTER_PHY,
+		.type = SWITCH_TYPE_INT,
+		.description = "Direct register access: set PHY (0-4, or 29,30,31)",
+		.name  = "phy",
+		.get  = ip17xx_get_phy,
+		.set = ip17xx_set_phy,
+	},
+	[IP17XX_REGISTER_MII] = {
+		.id = IP17XX_REGISTER_MII,
+		.type = SWITCH_TYPE_INT,
+		.description = "Direct register access: set MII register number (0-31)",
+		.name  = "reg",
+		.get  = ip17xx_get_reg,
+		.set = ip17xx_set_reg,
+	},
+	[IP17XX_REGISTER_VALUE] = {
+		.id = IP17XX_REGISTER_VALUE,
+		.type = SWITCH_TYPE_INT,
+		.description = "Direct register access: read/write to register (0-65535)",
+		.name  = "val",
+		.get  = ip17xx_get_val,
+		.set = ip17xx_set_val,
+	},
+};
+
+static const struct switch_attr ip17xx_vlan[] = {
+	[IP17XX_VLAN_TAG] = {
+		.id = IP17XX_VLAN_TAG,
+		.type = SWITCH_TYPE_INT,
+		.description = "VLAN ID (0-4095) [IP175D only]",
+		.name = "vid",
+		.get = ip17xx_get_tag,
+		.set = ip17xx_set_tag,
+	}
+};
+
+static const struct switch_attr ip17xx_port[] = {
+	[IP17XX_PORT_STATUS] = {
+		.id = IP17XX_PORT_STATUS,
+		.type = SWITCH_TYPE_STRING,
+		.description = "Returns Detailed port status",
+		.name  = "status",
+		.get  = ip17xx_get_port_status,
+		.set = NULL,
+	},
+	[IP17XX_PORT_LINK] = {
+		.id = IP17XX_PORT_LINK,
+		.type = SWITCH_TYPE_INT,
+		.description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100",
+		.name  = "link",
+		.get  = ip17xx_get_port_speed,
+		.set = ip17xx_set_port_speed,
+	},
+	[IP17XX_PORT_TAGGED] = {
+		.id = IP17XX_PORT_LINK,
+		.type = SWITCH_TYPE_INT,
+		.description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)",
+		.name  = "tagged",
+		.get  = ip17xx_get_tagged,
+		.set = ip17xx_set_tagged,
+	},
+};
+
+static const struct switch_dev_ops ip17xx_ops = {
+	.attr_global = {
+		.attr = ip17xx_global,
+		.n_attr = ARRAY_SIZE(ip17xx_global),
+	},
+	.attr_port = {
+		.attr = ip17xx_port,
+		.n_attr = ARRAY_SIZE(ip17xx_port),
+	},
+	.attr_vlan = {
+		.attr = ip17xx_vlan,
+		.n_attr = ARRAY_SIZE(ip17xx_vlan),
+	},
+
+	.get_port_pvid = ip17xx_get_pvid,
+	.set_port_pvid = ip17xx_set_pvid,
+	.get_vlan_ports = ip17xx_get_ports,
+	.set_vlan_ports = ip17xx_set_ports,
+	.apply_config = ip17xx_apply,
+	.reset_switch = ip17xx_reset,
+};
+
+static int ip17xx_probe(struct phy_device *pdev)
+{
+	struct ip17xx_state *state;
+	struct switch_dev *dev;
+	int err;
+
+	/* We only attach to PHY 0, but use all available PHYs */
+	if (pdev->addr != 0)
+		return -ENODEV;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	dev = &state->dev;
+
+	pdev->priv = state;
+	state->mii_bus = pdev->bus;
+
+	err = get_model(state);
+	if (err < 0)
+		goto error;
+
+	dev->vlans = MAX_VLANS;
+	dev->cpu_port = state->regs->CPU_PORT;
+	dev->ports = state->regs->NUM_PORTS;
+	dev->name = state->regs->NAME;
+	dev->ops = &ip17xx_ops;
+
+	pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->dev));
+	return 0;
+
+error:
+	kfree(state);
+	return err;
+}
+
+static int ip17xx_config_init(struct phy_device *pdev)
+{
+	struct ip17xx_state *state = pdev->priv;
+	struct net_device *dev = pdev->attached_dev;
+	int err;
+
+	err = register_switch(&state->dev, dev);
+	if (err < 0)
+		return err;
+
+	state->registered = true;
+	ip17xx_reset(&state->dev);
+	return 0;
+}
+
+static void ip17xx_remove(struct phy_device *pdev)
+{
+	struct ip17xx_state *state = pdev->priv;
+
+	if (state->registered)
+		unregister_switch(&state->dev);
+	kfree(state);
+}
+
+static int ip17xx_config_aneg(struct phy_device *pdev)
+{
+	return 0;
+}
+
+static int ip17xx_aneg_done(struct phy_device *pdev)
+{
+	return BMSR_ANEGCOMPLETE;
+}
+
+static int ip17xx_update_link(struct phy_device *pdev)
+{
+	pdev->link = 1;
+	return 0;
+}
+
+static int ip17xx_read_status(struct phy_device *pdev)
+{
+	pdev->speed = SPEED_100;
+	pdev->duplex = DUPLEX_FULL;
+	pdev->pause = pdev->asym_pause = 0;
+	pdev->link = 1;
+
+	return 0;
+}
+
+static struct phy_driver ip17xx_driver = {
+	.name		= "IC+ IP17xx",
+	.phy_id		= 0x02430c00,
+	.phy_id_mask	= 0x0ffffc00,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= ip17xx_probe,
+	.remove		= ip17xx_remove,
+	.config_init	= ip17xx_config_init,
+	.config_aneg	= ip17xx_config_aneg,
+	.aneg_done	= ip17xx_aneg_done,
+	.update_link	= ip17xx_update_link,
+	.read_status	= ip17xx_read_status,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+static struct phy_driver ip175a_driver = {
+	.name		= "IC+ IP175A",
+	.phy_id		= 0x02430c50,
+	.phy_id_mask	= 0x0ffffff0,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= ip17xx_probe,
+	.remove		= ip17xx_remove,
+	.config_init	= ip17xx_config_init,
+	.config_aneg	= ip17xx_config_aneg,
+	.aneg_done	= ip17xx_aneg_done,
+	.update_link	= ip17xx_update_link,
+	.read_status	= ip17xx_read_status,
+	.driver		= { .owner = THIS_MODULE },
+};
+
+
+int __init ip17xx_init(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&ip175a_driver);
+	if (ret < 0)
+		return ret;
+
+	return phy_driver_register(&ip17xx_driver);
+}
+
+void __exit ip17xx_exit(void)
+{
+	phy_driver_unregister(&ip17xx_driver);
+	phy_driver_unregister(&ip175a_driver);
+}
+
+MODULE_AUTHOR("Patrick Horn <patrick.horn@gmail.com>");
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_AUTHOR("Martin Mares <mj@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+module_init(ip17xx_init);
+module_exit(ip17xx_exit);
diff --git a/target/linux/generic/files/drivers/net/phy/mvsw61xx.c b/target/linux/generic/files/drivers/net/phy/mvsw61xx.c
new file mode 100644
index 0000000000..6bd112b00d
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/mvsw61xx.c
@@ -0,0 +1,943 @@
+/*
+ * Marvell 88E61xx switch driver
+ *
+ * Copyright (c) 2014 Claudio Leite <leitec@staticky.com>
+ * Copyright (c) 2014 Nikita Nazarenko <nnazarenko@radiofid.com>
+ *
+ * Based on code (c) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/delay.h>
+#include <linux/switch.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "mvsw61xx.h"
+
+MODULE_DESCRIPTION("Marvell 88E61xx Switch driver");
+MODULE_AUTHOR("Claudio Leite <leitec@staticky.com>");
+MODULE_AUTHOR("Nikita Nazarenko <nnazarenko@radiofid.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mvsw61xx");
+
+/*
+ * Register access is done through direct or indirect addressing,
+ * depending on how the switch is physically connected.
+ *
+ * Direct addressing: all port and global registers directly
+ *   accessible via an address/register pair
+ *
+ * Indirect addressing: switch is mapped at a single address,
+ *   port and global registers accessible via a single command/data
+ *   register pair
+ */
+
+static int
+mvsw61xx_wait_mask_raw(struct mii_bus *bus, int addr,
+		int reg, u16 mask, u16 val)
+{
+	int i = 100;
+	u16 r;
+
+	do {
+		r = bus->read(bus, addr, reg);
+		if ((r & mask) == val)
+			return 0;
+	} while (--i > 0);
+
+	return -ETIMEDOUT;
+}
+
+static u16
+r16(struct mii_bus *bus, bool indirect, int base_addr, int addr, int reg)
+{
+	u16 ind_addr;
+
+	if (!indirect)
+		return bus->read(bus, addr, reg);
+
+	/* Indirect read: First, make sure switch is free */
+	mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD,
+			MV_INDIRECT_INPROGRESS, 0);
+
+	/* Load address and request read */
+	ind_addr = MV_INDIRECT_READ | (addr << MV_INDIRECT_ADDR_S) | reg;
+	bus->write(bus, base_addr, MV_INDIRECT_REG_CMD,
+			ind_addr);
+
+	/* Wait until it's ready */
+	mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD,
+			MV_INDIRECT_INPROGRESS, 0);
+
+	/* Read the requested data */
+	return bus->read(bus, base_addr, MV_INDIRECT_REG_DATA);
+}
+
+static void
+w16(struct mii_bus *bus, bool indirect, int base_addr, int addr,
+		int reg, u16 val)
+{
+	u16 ind_addr;
+
+	if (!indirect) {
+		bus->write(bus, addr, reg, val);
+		return;
+	}
+
+	/* Indirect write: First, make sure switch is free */
+	mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD,
+			MV_INDIRECT_INPROGRESS, 0);
+
+	/* Load the data to be written */
+	bus->write(bus, base_addr, MV_INDIRECT_REG_DATA, val);
+
+	/* Wait again for switch to be free */
+	mvsw61xx_wait_mask_raw(bus, base_addr, MV_INDIRECT_REG_CMD,
+			MV_INDIRECT_INPROGRESS, 0);
+
+	/* Load address, and issue write command */
+	ind_addr = MV_INDIRECT_WRITE | (addr << MV_INDIRECT_ADDR_S) | reg;
+	bus->write(bus, base_addr, MV_INDIRECT_REG_CMD,
+			ind_addr);
+}
+
+/* swconfig support */
+
+static inline u16
+sr16(struct switch_dev *dev, int addr, int reg)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	return r16(state->bus, state->is_indirect, state->base_addr, addr, reg);
+}
+
+static inline void
+sw16(struct switch_dev *dev, int addr, int reg, u16 val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	w16(state->bus, state->is_indirect, state->base_addr, addr, reg, val);
+}
+
+static int
+mvsw61xx_wait_mask_s(struct switch_dev *dev, int addr,
+		int reg, u16 mask, u16 val)
+{
+	int i = 100;
+	u16 r;
+
+	do {
+		r = sr16(dev, addr, reg) & mask;
+		if (r == val)
+			return 0;
+	} while (--i > 0);
+
+	return -ETIMEDOUT;
+}
+
+static int
+mvsw61xx_mdio_read(struct switch_dev *dev, int addr, int reg)
+{
+	sw16(dev, MV_GLOBAL2REG(SMI_OP),
+	     MV_INDIRECT_READ | (addr << MV_INDIRECT_ADDR_S) | reg);
+
+	if (mvsw61xx_wait_mask_s(dev,  MV_GLOBAL2REG(SMI_OP),
+				 MV_INDIRECT_INPROGRESS, 0) < 0)
+		return -ETIMEDOUT;
+
+	return sr16(dev, MV_GLOBAL2REG(SMI_DATA));
+}
+
+static int
+mvsw61xx_mdio_write(struct switch_dev *dev, int addr, int reg, u16 val)
+{
+	sw16(dev, MV_GLOBAL2REG(SMI_DATA), val);
+
+	sw16(dev, MV_GLOBAL2REG(SMI_OP),
+	     MV_INDIRECT_WRITE | (addr << MV_INDIRECT_ADDR_S) | reg);
+
+	return mvsw61xx_wait_mask_s(dev,  MV_GLOBAL2REG(SMI_OP),
+				    MV_INDIRECT_INPROGRESS, 0) < 0;
+}
+
+static int
+mvsw61xx_mdio_page_read(struct switch_dev *dev, int port, int page, int reg)
+{
+	int ret;
+
+	mvsw61xx_mdio_write(dev, port, MII_MV_PAGE, page);
+	ret = mvsw61xx_mdio_read(dev, port, reg);
+	mvsw61xx_mdio_write(dev, port, MII_MV_PAGE, 0);
+
+	return ret;
+}
+
+static void
+mvsw61xx_mdio_page_write(struct switch_dev *dev, int port, int page, int reg,
+			 u16 val)
+{
+	mvsw61xx_mdio_write(dev, port, MII_MV_PAGE, page);
+	mvsw61xx_mdio_write(dev, port, reg, val);
+	mvsw61xx_mdio_write(dev, port, MII_MV_PAGE, 0);
+}
+
+static int
+mvsw61xx_get_port_mask(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	char *buf = state->buf;
+	int port, len, i;
+	u16 reg;
+
+	port = val->port_vlan;
+	reg = sr16(dev, MV_PORTREG(VLANMAP, port)) & MV_PORTS_MASK;
+
+	len = sprintf(buf, "0x%04x: ", reg);
+
+	for (i = 0; i < MV_PORTS; i++) {
+		if (reg & (1 << i))
+			len += sprintf(buf + len, "%d ", i);
+		else if (i == port)
+			len += sprintf(buf + len, "(%d) ", i);
+	}
+
+	val->value.s = buf;
+
+	return 0;
+}
+
+static int
+mvsw61xx_get_port_qmode(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	val->value.i = state->ports[val->port_vlan].qmode;
+
+	return 0;
+}
+
+static int
+mvsw61xx_set_port_qmode(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	state->ports[val->port_vlan].qmode = val->value.i;
+
+	return 0;
+}
+
+static int
+mvsw61xx_get_port_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	*val = state->ports[port].pvid;
+
+	return 0;
+}
+
+static int
+mvsw61xx_set_port_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	if (val < 0 || val >= MV_VLANS)
+		return -EINVAL;
+
+	state->ports[port].pvid = (u16)val;
+
+	return 0;
+}
+
+static int
+mvsw61xx_get_port_link(struct switch_dev *dev, int port,
+		struct switch_port_link *link)
+{
+	u16 status, speed;
+
+	status = sr16(dev, MV_PORTREG(STATUS, port));
+
+	link->link = status & MV_PORT_STATUS_LINK;
+	if (!link->link)
+		return 0;
+
+	link->duplex = status & MV_PORT_STATUS_FDX;
+
+	speed = (status & MV_PORT_STATUS_SPEED_MASK) >>
+			MV_PORT_STATUS_SPEED_SHIFT;
+
+	switch (speed) {
+	case MV_PORT_STATUS_SPEED_10:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case MV_PORT_STATUS_SPEED_100:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case MV_PORT_STATUS_SPEED_1000:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	}
+
+	return 0;
+}
+
+static int mvsw61xx_get_vlan_ports(struct switch_dev *dev,
+		struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int i, j, mode, vno;
+
+	vno = val->port_vlan;
+
+	if (vno <= 0 || vno >= dev->vlans)
+		return -EINVAL;
+
+	for (i = 0, j = 0; i < dev->ports; i++) {
+		if (state->vlans[vno].mask & (1 << i)) {
+			val->value.ports[j].id = i;
+
+			mode = (state->vlans[vno].port_mode >> (i * 4)) & 0xf;
+			if (mode == MV_VTUCTL_EGRESS_TAGGED)
+				val->value.ports[j].flags =
+					(1 << SWITCH_PORT_FLAG_TAGGED);
+			else
+				val->value.ports[j].flags = 0;
+
+			j++;
+		}
+	}
+
+	val->len = j;
+
+	return 0;
+}
+
+static int mvsw61xx_set_vlan_ports(struct switch_dev *dev,
+		struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int i, mode, pno, vno;
+
+	vno = val->port_vlan;
+
+	if (vno <= 0 || vno >= dev->vlans)
+		return -EINVAL;
+
+	state->vlans[vno].mask = 0;
+	state->vlans[vno].port_mode = 0;
+	state->vlans[vno].port_sstate = 0;
+
+	if(state->vlans[vno].vid == 0)
+		state->vlans[vno].vid = vno;
+
+	for (i = 0; i < val->len; i++) {
+		pno = val->value.ports[i].id;
+
+		state->vlans[vno].mask |= (1 << pno);
+		if (val->value.ports[i].flags &
+				(1 << SWITCH_PORT_FLAG_TAGGED))
+			mode = MV_VTUCTL_EGRESS_TAGGED;
+		else
+			mode = MV_VTUCTL_EGRESS_UNTAGGED;
+
+		state->vlans[vno].port_mode |= mode << (pno * 4);
+		state->vlans[vno].port_sstate |=
+			MV_STUCTL_STATE_FORWARDING << (pno * 4 + 2);
+	}
+
+	/*
+	 * DISCARD is nonzero, so it must be explicitly
+	 * set on ports not in the VLAN.
+	 */
+	for (i = 0; i < dev->ports; i++)
+		if (!(state->vlans[vno].mask & (1 << i)))
+			state->vlans[vno].port_mode |=
+				MV_VTUCTL_DISCARD << (i * 4);
+
+	return 0;
+}
+
+static int mvsw61xx_get_vlan_port_based(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int vno = val->port_vlan;
+
+	if (vno <= 0 || vno >= dev->vlans)
+		return -EINVAL;
+
+	if (state->vlans[vno].port_based)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int mvsw61xx_set_vlan_port_based(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int vno = val->port_vlan;
+
+	if (vno <= 0 || vno >= dev->vlans)
+		return -EINVAL;
+
+	if (val->value.i == 1)
+		state->vlans[vno].port_based = true;
+	else
+		state->vlans[vno].port_based = false;
+
+	return 0;
+}
+
+static int mvsw61xx_get_vid(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int vno = val->port_vlan;
+
+	if (vno <= 0 || vno >= dev->vlans)
+		return -EINVAL;
+
+	val->value.i = state->vlans[vno].vid;
+
+	return 0;
+}
+
+static int mvsw61xx_set_vid(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int vno = val->port_vlan;
+
+	if (vno <= 0 || vno >= dev->vlans)
+		return -EINVAL;
+
+	state->vlans[vno].vid = val->value.i;
+
+	return 0;
+}
+
+static int mvsw61xx_get_enable_vlan(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	val->value.i = state->vlan_enabled;
+
+	return 0;
+}
+
+static int mvsw61xx_set_enable_vlan(struct switch_dev *dev,
+		const struct switch_attr *attr, struct switch_val *val)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+
+	state->vlan_enabled = val->value.i;
+
+	return 0;
+}
+
+static int mvsw61xx_vtu_program(struct switch_dev *dev)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	u16 v1, v2, s1, s2;
+	int i;
+
+	/* Flush */
+	mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP),
+			MV_VTUOP_INPROGRESS, 0);
+	sw16(dev, MV_GLOBALREG(VTU_OP),
+			MV_VTUOP_INPROGRESS | MV_VTUOP_PURGE);
+
+	/* Write VLAN table */
+	for (i = 1; i < dev->vlans; i++) {
+		if (state->vlans[i].mask == 0 ||
+				state->vlans[i].vid == 0 ||
+				state->vlans[i].port_based == true)
+			continue;
+
+		mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP),
+				MV_VTUOP_INPROGRESS, 0);
+
+		/* Write per-VLAN port state into STU */
+		s1 = (u16) (state->vlans[i].port_sstate & 0xffff);
+		s2 = (u16) ((state->vlans[i].port_sstate >> 16) & 0xffff);
+
+		sw16(dev, MV_GLOBALREG(VTU_VID), MV_VTU_VID_VALID);
+		sw16(dev, MV_GLOBALREG(VTU_SID), i);
+		sw16(dev, MV_GLOBALREG(VTU_DATA1), s1);
+		sw16(dev, MV_GLOBALREG(VTU_DATA2), s2);
+		sw16(dev, MV_GLOBALREG(VTU_DATA3), 0);
+
+		sw16(dev, MV_GLOBALREG(VTU_OP),
+				MV_VTUOP_INPROGRESS | MV_VTUOP_STULOAD);
+		mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP),
+				MV_VTUOP_INPROGRESS, 0);
+
+		/* Write VLAN information into VTU */
+		v1 = (u16) (state->vlans[i].port_mode & 0xffff);
+		v2 = (u16) ((state->vlans[i].port_mode >> 16) & 0xffff);
+
+		sw16(dev, MV_GLOBALREG(VTU_VID),
+				MV_VTU_VID_VALID | state->vlans[i].vid);
+		sw16(dev, MV_GLOBALREG(VTU_SID), i);
+		sw16(dev, MV_GLOBALREG(VTU_FID), i);
+		sw16(dev, MV_GLOBALREG(VTU_DATA1), v1);
+		sw16(dev, MV_GLOBALREG(VTU_DATA2), v2);
+		sw16(dev, MV_GLOBALREG(VTU_DATA3), 0);
+
+		sw16(dev, MV_GLOBALREG(VTU_OP),
+				MV_VTUOP_INPROGRESS | MV_VTUOP_LOAD);
+		mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP),
+				MV_VTUOP_INPROGRESS, 0);
+	}
+
+	return 0;
+}
+
+static void mvsw61xx_vlan_port_config(struct switch_dev *dev, int vno)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int i, mode;
+
+	for (i = 0; i < dev->ports; i++) {
+		if (!(state->vlans[vno].mask & (1 << i)))
+			continue;
+
+		mode = (state->vlans[vno].port_mode >> (i * 4)) & 0xf;
+
+		if(mode != MV_VTUCTL_EGRESS_TAGGED)
+			state->ports[i].pvid = state->vlans[vno].vid;
+
+		if (state->vlans[vno].port_based) {
+			state->ports[i].mask |= state->vlans[vno].mask;
+			state->ports[i].fdb = vno;
+		}
+		else
+			state->ports[i].qmode = MV_8021Q_MODE_SECURE;
+	}
+}
+
+static int mvsw61xx_update_state(struct switch_dev *dev)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int i;
+	u16 reg;
+
+	if (!state->registered)
+		return -EINVAL;
+
+	/*
+	 * Set 802.1q-only mode if vlan_enabled is true.
+	 *
+	 * Without this, even if 802.1q is enabled for
+	 * a port/VLAN, it still depends on the port-based
+	 * VLAN mask being set.
+	 *
+	 * With this setting, port-based VLANs are still
+	 * functional, provided the VID is not in the VTU.
+	 */
+	reg = sr16(dev, MV_GLOBAL2REG(SDET_POLARITY));
+
+	if (state->vlan_enabled)
+		reg |= MV_8021Q_VLAN_ONLY;
+	else
+		reg &= ~MV_8021Q_VLAN_ONLY;
+
+	sw16(dev, MV_GLOBAL2REG(SDET_POLARITY), reg);
+
+	/*
+	 * Set port-based VLAN masks on each port
+	 * based only on VLAN definitions known to
+	 * the driver (i.e. in state).
+	 *
+	 * This means any pre-existing port mapping is
+	 * wiped out once our driver is initialized.
+	 */
+	for (i = 0; i < dev->ports; i++) {
+		state->ports[i].mask = 0;
+		state->ports[i].qmode = MV_8021Q_MODE_DISABLE;
+	}
+
+	for (i = 0; i < dev->vlans; i++)
+		mvsw61xx_vlan_port_config(dev, i);
+
+	for (i = 0; i < dev->ports; i++) {
+		reg = sr16(dev, MV_PORTREG(VLANID, i)) & ~MV_PVID_MASK;
+		reg |= state->ports[i].pvid;
+		sw16(dev, MV_PORTREG(VLANID, i), reg);
+
+		state->ports[i].mask &= ~(1 << i);
+
+		/* set default forwarding DB number and port mask */
+		reg = sr16(dev, MV_PORTREG(CONTROL1, i)) & ~MV_FDB_HI_MASK;
+		reg |= (state->ports[i].fdb >> MV_FDB_HI_SHIFT) &
+			MV_FDB_HI_MASK;
+		sw16(dev, MV_PORTREG(CONTROL1, i), reg);
+
+		reg = ((state->ports[i].fdb & 0xf) << MV_FDB_LO_SHIFT) |
+			state->ports[i].mask;
+		sw16(dev, MV_PORTREG(VLANMAP, i), reg);
+
+		reg = sr16(dev, MV_PORTREG(CONTROL2, i)) &
+			~MV_8021Q_MODE_MASK;
+		reg |= state->ports[i].qmode << MV_8021Q_MODE_SHIFT;
+		sw16(dev, MV_PORTREG(CONTROL2, i), reg);
+	}
+
+	mvsw61xx_vtu_program(dev);
+
+	return 0;
+}
+
+static int mvsw61xx_apply(struct switch_dev *dev)
+{
+	return mvsw61xx_update_state(dev);
+}
+
+static void mvsw61xx_enable_serdes(struct switch_dev *dev)
+{
+	int bmcr = mvsw61xx_mdio_page_read(dev, MV_REG_FIBER_SERDES,
+					   MV_PAGE_FIBER_SERDES, MII_BMCR);
+	if (bmcr < 0)
+		return;
+
+	if (bmcr & BMCR_PDOWN)
+		mvsw61xx_mdio_page_write(dev, MV_REG_FIBER_SERDES,
+					 MV_PAGE_FIBER_SERDES, MII_BMCR,
+					 bmcr & ~BMCR_PDOWN);
+}
+
+static int _mvsw61xx_reset(struct switch_dev *dev, bool full)
+{
+	struct mvsw61xx_state *state = get_state(dev);
+	int i;
+	u16 reg;
+
+	/* Disable all ports before reset */
+	for (i = 0; i < dev->ports; i++) {
+		reg = sr16(dev, MV_PORTREG(CONTROL, i)) &
+			~MV_PORTCTRL_FORWARDING;
+		sw16(dev, MV_PORTREG(CONTROL, i), reg);
+	}
+
+	reg = sr16(dev, MV_GLOBALREG(CONTROL)) | MV_CONTROL_RESET;
+
+	sw16(dev, MV_GLOBALREG(CONTROL), reg);
+	if (mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(CONTROL),
+				MV_CONTROL_RESET, 0) < 0)
+		return -ETIMEDOUT;
+
+	for (i = 0; i < dev->ports; i++) {
+		state->ports[i].fdb = 0;
+		state->ports[i].qmode = 0;
+		state->ports[i].mask = 0;
+		state->ports[i].pvid = 0;
+
+		/* Force flow control off */
+		reg = sr16(dev, MV_PORTREG(PHYCTL, i)) & ~MV_PHYCTL_FC_MASK;
+		reg |= MV_PHYCTL_FC_DISABLE;
+		sw16(dev, MV_PORTREG(PHYCTL, i), reg);
+
+		/* Set port association vector */
+		sw16(dev, MV_PORTREG(ASSOC, i), (1 << i));
+
+		/* power up phys */
+		if (full && i < 5) {
+			mvsw61xx_mdio_write(dev, i, MII_MV_SPEC_CTRL,
+					    MV_SPEC_MDI_CROSS_AUTO |
+					    MV_SPEC_ENERGY_DETECT |
+					    MV_SPEC_DOWNSHIFT_COUNTER);
+			mvsw61xx_mdio_write(dev, i, MII_BMCR, BMCR_RESET |
+					    BMCR_ANENABLE | BMCR_FULLDPLX |
+					    BMCR_SPEED1000);
+		}
+
+		/* enable SerDes if necessary */
+		if (full && i >= 5 && state->model == MV_IDENT_VALUE_6176) {
+			u16 sts = sr16(dev, MV_PORTREG(STATUS, i));
+			u16 mode = sts & MV_PORT_STATUS_CMODE_MASK;
+
+			if (mode == MV_PORT_STATUS_CMODE_100BASE_X ||
+			    mode == MV_PORT_STATUS_CMODE_1000BASE_X ||
+			    mode == MV_PORT_STATUS_CMODE_SGMII) {
+				mvsw61xx_enable_serdes(dev);
+			}
+		}
+	}
+
+	for (i = 0; i < dev->vlans; i++) {
+		state->vlans[i].port_based = false;
+		state->vlans[i].mask = 0;
+		state->vlans[i].vid = 0;
+		state->vlans[i].port_mode = 0;
+		state->vlans[i].port_sstate = 0;
+	}
+
+	state->vlan_enabled = 0;
+
+	mvsw61xx_update_state(dev);
+
+	/* Re-enable ports */
+	for (i = 0; i < dev->ports; i++) {
+		reg = sr16(dev, MV_PORTREG(CONTROL, i)) |
+			MV_PORTCTRL_FORWARDING;
+		sw16(dev, MV_PORTREG(CONTROL, i), reg);
+	}
+
+	return 0;
+}
+
+static int mvsw61xx_reset(struct switch_dev *dev)
+{
+	return _mvsw61xx_reset(dev, false);
+}
+
+enum {
+	MVSW61XX_ENABLE_VLAN,
+};
+
+enum {
+	MVSW61XX_VLAN_PORT_BASED,
+	MVSW61XX_VLAN_ID,
+};
+
+enum {
+	MVSW61XX_PORT_MASK,
+	MVSW61XX_PORT_QMODE,
+};
+
+static const struct switch_attr mvsw61xx_global[] = {
+	[MVSW61XX_ENABLE_VLAN] = {
+		.id = MVSW61XX_ENABLE_VLAN,
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable 802.1q VLAN support",
+		.get = mvsw61xx_get_enable_vlan,
+		.set = mvsw61xx_set_enable_vlan,
+	},
+};
+
+static const struct switch_attr mvsw61xx_vlan[] = {
+	[MVSW61XX_VLAN_PORT_BASED] = {
+		.id = MVSW61XX_VLAN_PORT_BASED,
+		.type = SWITCH_TYPE_INT,
+		.name = "port_based",
+		.description = "Use port-based (non-802.1q) VLAN only",
+		.get = mvsw61xx_get_vlan_port_based,
+		.set = mvsw61xx_set_vlan_port_based,
+	},
+	[MVSW61XX_VLAN_ID] = {
+		.id = MVSW61XX_VLAN_ID,
+		.type = SWITCH_TYPE_INT,
+		.name = "vid",
+		.description = "Get/set VLAN ID",
+		.get = mvsw61xx_get_vid,
+		.set = mvsw61xx_set_vid,
+	},
+};
+
+static const struct switch_attr mvsw61xx_port[] = {
+	[MVSW61XX_PORT_MASK] = {
+		.id = MVSW61XX_PORT_MASK,
+		.type = SWITCH_TYPE_STRING,
+		.description = "Port-based VLAN mask",
+		.name = "mask",
+		.get = mvsw61xx_get_port_mask,
+		.set = NULL,
+	},
+	[MVSW61XX_PORT_QMODE] = {
+		.id = MVSW61XX_PORT_QMODE,
+		.type = SWITCH_TYPE_INT,
+		.description = "802.1q mode: 0=off/1=fallback/2=check/3=secure",
+		.name = "qmode",
+		.get = mvsw61xx_get_port_qmode,
+		.set = mvsw61xx_set_port_qmode,
+	},
+};
+
+static const struct switch_dev_ops mvsw61xx_ops = {
+	.attr_global = {
+		.attr = mvsw61xx_global,
+		.n_attr = ARRAY_SIZE(mvsw61xx_global),
+	},
+	.attr_vlan = {
+		.attr = mvsw61xx_vlan,
+		.n_attr = ARRAY_SIZE(mvsw61xx_vlan),
+	},
+	.attr_port = {
+		.attr = mvsw61xx_port,
+		.n_attr = ARRAY_SIZE(mvsw61xx_port),
+	},
+	.get_port_link = mvsw61xx_get_port_link,
+	.get_port_pvid = mvsw61xx_get_port_pvid,
+	.set_port_pvid = mvsw61xx_set_port_pvid,
+	.get_vlan_ports = mvsw61xx_get_vlan_ports,
+	.set_vlan_ports = mvsw61xx_set_vlan_ports,
+	.apply_config = mvsw61xx_apply,
+	.reset_switch = mvsw61xx_reset,
+};
+
+/* end swconfig stuff */
+
+static int mvsw61xx_probe(struct platform_device *pdev)
+{
+	struct mvsw61xx_state *state;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *mdio;
+	char *model_str;
+	u32 val;
+	int err;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	mdio = of_parse_phandle(np, "mii-bus", 0);
+	if (!mdio) {
+		dev_err(&pdev->dev, "Couldn't get MII bus handle\n");
+		err = -ENODEV;
+		goto out_err;
+	}
+
+	state->bus = of_mdio_find_bus(mdio);
+	if (!state->bus) {
+		dev_err(&pdev->dev, "Couldn't find MII bus from handle\n");
+		err = -ENODEV;
+		goto out_err;
+	}
+
+	state->is_indirect = of_property_read_bool(np, "is-indirect");
+
+	if (state->is_indirect) {
+		if (of_property_read_u32(np, "reg", &val)) {
+			dev_err(&pdev->dev, "Switch address not specified\n");
+			err = -ENODEV;
+			goto out_err;
+		}
+
+		state->base_addr = val;
+	} else {
+		state->base_addr = MV_BASE;
+	}
+
+	state->model = r16(state->bus, state->is_indirect, state->base_addr,
+				MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
+
+	switch(state->model) {
+	case MV_IDENT_VALUE_6171:
+		model_str = MV_IDENT_STR_6171;
+		break;
+	case MV_IDENT_VALUE_6172:
+		model_str = MV_IDENT_STR_6172;
+		break;
+	case MV_IDENT_VALUE_6176:
+		model_str = MV_IDENT_STR_6176;
+		break;
+	default:
+		dev_err(&pdev->dev, "No compatible switch found at 0x%02x\n",
+				state->base_addr);
+		err = -ENODEV;
+		goto out_err;
+	}
+
+	platform_set_drvdata(pdev, state);
+	dev_info(&pdev->dev, "Found %s at %s:%02x\n", model_str,
+			state->bus->id, state->base_addr);
+
+	dev_info(&pdev->dev, "Using %sdirect addressing\n",
+			(state->is_indirect ? "in" : ""));
+
+	if (of_property_read_u32(np, "cpu-port-0", &val)) {
+		dev_err(&pdev->dev, "CPU port not set\n");
+		err = -ENODEV;
+		goto out_err;
+	}
+
+	state->cpu_port0 = val;
+
+	if (!of_property_read_u32(np, "cpu-port-1", &val))
+		state->cpu_port1 = val;
+	else
+		state->cpu_port1 = -1;
+
+	state->dev.vlans = MV_VLANS;
+	state->dev.cpu_port = state->cpu_port0;
+	state->dev.ports = MV_PORTS;
+	state->dev.name = model_str;
+	state->dev.ops = &mvsw61xx_ops;
+	state->dev.alias = dev_name(&pdev->dev);
+
+	_mvsw61xx_reset(&state->dev, true);
+
+	err = register_switch(&state->dev, NULL);
+	if (err < 0)
+		goto out_err;
+
+	state->registered = true;
+
+	return 0;
+out_err:
+	kfree(state);
+	return err;
+}
+
+static int
+mvsw61xx_remove(struct platform_device *pdev)
+{
+	struct mvsw61xx_state *state = platform_get_drvdata(pdev);
+
+	if (state->registered)
+		unregister_switch(&state->dev);
+
+	kfree(state);
+
+	return 0;
+}
+
+static const struct of_device_id mvsw61xx_match[] = {
+	{ .compatible = "marvell,88e6171" },
+	{ .compatible = "marvell,88e6172" },
+	{ .compatible = "marvell,88e6176" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mvsw61xx_match);
+
+static struct platform_driver mvsw61xx_driver = {
+	.probe = mvsw61xx_probe,
+	.remove = mvsw61xx_remove,
+	.driver = {
+		.name = "mvsw61xx",
+		.of_match_table = of_match_ptr(mvsw61xx_match),
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mvsw61xx_module_init(void)
+{
+	return platform_driver_register(&mvsw61xx_driver);
+}
+late_initcall(mvsw61xx_module_init);
+
+static void __exit mvsw61xx_module_exit(void)
+{
+	platform_driver_unregister(&mvsw61xx_driver);
+}
+module_exit(mvsw61xx_module_exit);
diff --git a/target/linux/generic/files/drivers/net/phy/mvsw61xx.h b/target/linux/generic/files/drivers/net/phy/mvsw61xx.h
new file mode 100644
index 0000000000..1c45189689
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/mvsw61xx.h
@@ -0,0 +1,289 @@
+/*
+ * Marvell 88E61xx switch driver
+ *
+ * Copyright (c) 2014 Claudio Leite <leitec@staticky.com>
+ * Copyright (c) 2014 Nikita Nazarenko <nnazarenko@radiofid.com>
+ *
+ * Based on code (c) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+
+#ifndef __MVSW61XX_H
+#define __MVSW61XX_H
+
+#define MV_PORTS			7
+#define MV_PORTS_MASK			((1 << MV_PORTS) - 1)
+
+#define MV_BASE				0x10
+
+#define MV_SWITCHPORT_BASE		0x10
+#define MV_SWITCHPORT(_n)		(MV_SWITCHPORT_BASE + (_n))
+#define MV_SWITCHREGS			(MV_BASE + 0xb)
+
+#define MV_VLANS			64
+
+enum {
+	MV_PORT_STATUS			= 0x00,
+	MV_PORT_PHYCTL			= 0x01,
+	MV_PORT_JAMCTL			= 0x02,
+	MV_PORT_IDENT			= 0x03,
+	MV_PORT_CONTROL			= 0x04,
+	MV_PORT_CONTROL1		= 0x05,
+	MV_PORT_VLANMAP			= 0x06,
+	MV_PORT_VLANID			= 0x07,
+	MV_PORT_CONTROL2		= 0x08,
+	MV_PORT_ASSOC			= 0x0b,
+	MV_PORT_RX_DISCARD_LOW		= 0x10,
+	MV_PORT_RX_DISCARD_HIGH		= 0x11,
+	MV_PORT_IN_FILTERED		= 0x12,
+	MV_PORT_OUT_ACCEPTED		= 0x13,
+};
+#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
+
+enum {
+	MV_PORT_STATUS_FDX		= (1 << 10),
+	MV_PORT_STATUS_LINK		= (1 << 11),
+};
+
+enum {
+	MV_PORT_STATUS_CMODE_100BASE_X	= 0x8,
+	MV_PORT_STATUS_CMODE_1000BASE_X	= 0x9,
+	MV_PORT_STATUS_CMODE_SGMII	= 0xa,
+};
+
+#define MV_PORT_STATUS_CMODE_MASK	0xf
+
+enum {
+	MV_PORT_STATUS_SPEED_10		= 0x00,
+	MV_PORT_STATUS_SPEED_100	= 0x01,
+	MV_PORT_STATUS_SPEED_1000	= 0x02,
+};
+#define MV_PORT_STATUS_SPEED_SHIFT	8
+#define MV_PORT_STATUS_SPEED_MASK	(3 << 8)
+
+enum {
+	MV_PORTCTRL_DISABLED		= (0 << 0),
+	MV_PORTCTRL_BLOCKING		= (1 << 0),
+	MV_PORTCTRL_LEARNING		= (2 << 0),
+	MV_PORTCTRL_FORWARDING		= (3 << 0),
+	MV_PORTCTRL_VLANTUN		= (1 << 7),
+	MV_PORTCTRL_EGRESS		= (1 << 12),
+};
+
+#define MV_PHYCTL_FC_MASK		(3 << 6)
+
+enum {
+	MV_PHYCTL_FC_ENABLE		= (3 << 6),
+	MV_PHYCTL_FC_DISABLE		= (1 << 6),
+};
+
+enum {
+	MV_8021Q_EGRESS_UNMODIFIED	= 0x00,
+	MV_8021Q_EGRESS_UNTAGGED	= 0x01,
+	MV_8021Q_EGRESS_TAGGED		= 0x02,
+	MV_8021Q_EGRESS_ADDTAG		= 0x03,
+};
+
+#define MV_8021Q_MODE_SHIFT		10
+#define MV_8021Q_MODE_MASK		(0x3 << MV_8021Q_MODE_SHIFT)
+
+enum {
+	MV_8021Q_MODE_DISABLE		= 0x00,
+	MV_8021Q_MODE_FALLBACK		= 0x01,
+	MV_8021Q_MODE_CHECK		= 0x02,
+	MV_8021Q_MODE_SECURE		= 0x03,
+};
+
+enum {
+	MV_8021Q_VLAN_ONLY		= (1 << 15),
+};
+
+#define MV_PORTASSOC_MONITOR		(1 << 15)
+
+enum {
+	MV_SWITCH_ATU_FID0		= 0x01,
+	MV_SWITCH_ATU_FID1		= 0x02,
+	MV_SWITCH_ATU_SID		= 0x03,
+	MV_SWITCH_CTRL			= 0x04,
+	MV_SWITCH_ATU_CTRL		= 0x0a,
+	MV_SWITCH_ATU_OP		= 0x0b,
+	MV_SWITCH_ATU_DATA		= 0x0c,
+	MV_SWITCH_ATU_MAC0		= 0x0d,
+	MV_SWITCH_ATU_MAC1		= 0x0e,
+	MV_SWITCH_ATU_MAC2		= 0x0f,
+	MV_SWITCH_GLOBAL		= 0x1b,
+	MV_SWITCH_GLOBAL2		= 0x1c,
+};
+#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
+
+enum {
+	MV_SWITCHCTL_EEIE		= (1 << 0),
+	MV_SWITCHCTL_PHYIE		= (1 << 1),
+	MV_SWITCHCTL_ATUDONE		= (1 << 2),
+	MV_SWITCHCTL_ATUIE		= (1 << 3),
+	MV_SWITCHCTL_CTRMODE		= (1 << 8),
+	MV_SWITCHCTL_RELOAD		= (1 << 9),
+	MV_SWITCHCTL_MSIZE		= (1 << 10),
+	MV_SWITCHCTL_DROP		= (1 << 13),
+};
+
+enum {
+#define MV_ATUCTL_AGETIME_MIN		16
+#define MV_ATUCTL_AGETIME_MAX		4080
+#define MV_ATUCTL_AGETIME(_n)		((((_n) / 16) & 0xff) << 4)
+	MV_ATUCTL_ATU_256		= (0 << 12),
+	MV_ATUCTL_ATU_512		= (1 << 12),
+	MV_ATUCTL_ATU_1K		= (2 << 12),
+	MV_ATUCTL_ATUMASK		= (3 << 12),
+	MV_ATUCTL_NO_LEARN		= (1 << 14),
+	MV_ATUCTL_RESET			= (1 << 15),
+};
+
+enum {
+#define MV_ATUOP_DBNUM(_n)		((_n) & 0x0f)
+	MV_ATUOP_NOOP			= (0 << 12),
+	MV_ATUOP_FLUSH_ALL		= (1 << 12),
+	MV_ATUOP_FLUSH_U		= (2 << 12),
+	MV_ATUOP_LOAD_DB		= (3 << 12),
+	MV_ATUOP_GET_NEXT		= (4 << 12),
+	MV_ATUOP_FLUSH_DB		= (5 << 12),
+	MV_ATUOP_FLUSH_DB_UU		= (6 << 12),
+	MV_ATUOP_INPROGRESS		= (1 << 15),
+};
+
+enum {
+	MV_GLOBAL_STATUS		= 0x00,
+	MV_GLOBAL_ATU_FID		= 0x01,
+	MV_GLOBAL_VTU_FID		= 0x02,
+	MV_GLOBAL_VTU_SID		= 0x03,
+	MV_GLOBAL_CONTROL		= 0x04,
+	MV_GLOBAL_VTU_OP		= 0x05,
+	MV_GLOBAL_VTU_VID		= 0x06,
+	MV_GLOBAL_VTU_DATA1		= 0x07,
+	MV_GLOBAL_VTU_DATA2		= 0x08,
+	MV_GLOBAL_VTU_DATA3		= 0x09,
+	MV_GLOBAL_CONTROL2		= 0x1c,
+};
+#define MV_GLOBALREG(_type) MV_SWITCH_GLOBAL, MV_GLOBAL_##_type
+
+enum {
+	MV_GLOBAL2_SMI_OP		= 0x18,
+	MV_GLOBAL2_SMI_DATA		= 0x19,
+	MV_GLOBAL2_SDET_POLARITY	= 0x1d,
+};
+#define MV_GLOBAL2REG(_type) MV_SWITCH_GLOBAL2, MV_GLOBAL2_##_type
+
+enum {
+	MV_VTU_VID_VALID		= (1 << 12),
+};
+
+enum {
+	MV_VTUOP_PURGE			= (1 << 12),
+	MV_VTUOP_LOAD			= (3 << 12),
+	MV_VTUOP_INPROGRESS		= (1 << 15),
+	MV_VTUOP_STULOAD		= (5 << 12),
+	MV_VTUOP_VTU_GET_NEXT		= (4 << 12),
+	MV_VTUOP_STU_GET_NEXT		= (6 << 12),
+	MV_VTUOP_GET_VIOLATION		= (7 << 12),
+};
+
+enum {
+	MV_CONTROL_RESET		= (1 << 15),
+	MV_CONTROL_PPU_ENABLE		= (1 << 14),
+};
+
+enum {
+	MV_VTUCTL_EGRESS_UNMODIFIED	= (0 << 0),
+	MV_VTUCTL_EGRESS_UNTAGGED	= (1 << 0),
+	MV_VTUCTL_EGRESS_TAGGED		= (2 << 0),
+	MV_VTUCTL_DISCARD		= (3 << 0),
+};
+
+enum {
+	MV_STUCTL_STATE_DISABLED	= (0 << 0),
+	MV_STUCTL_STATE_BLOCKING	= (1 << 0),
+	MV_STUCTL_STATE_LEARNING	= (2 << 0),
+	MV_STUCTL_STATE_FORWARDING	= (3 << 0),
+};
+
+enum {
+	MV_INDIRECT_REG_CMD		= 0,
+	MV_INDIRECT_REG_DATA		= 1,
+};
+
+enum {
+	MV_INDIRECT_INPROGRESS		= 0x8000,
+	MV_INDIRECT_WRITE		= 0x9400,
+	MV_INDIRECT_READ		= 0x9800,
+};
+#define MV_INDIRECT_ADDR_S		5
+
+#define MV_IDENT_MASK			0xfff0
+
+#define MV_IDENT_VALUE_6171		0x1710
+#define MV_IDENT_STR_6171		"MV88E6171"
+
+#define MV_IDENT_VALUE_6172		0x1720
+#define MV_IDENT_STR_6172		"MV88E6172"
+
+#define MV_IDENT_VALUE_6176		0x1760
+#define MV_IDENT_STR_6176		"MV88E6176"
+
+#define MV_PVID_MASK			0x0fff
+
+#define MV_FDB_HI_MASK			0x00ff
+#define MV_FDB_LO_MASK			0xf000
+#define MV_FDB_HI_SHIFT			4
+#define MV_FDB_LO_SHIFT			12
+
+/* Marvell Specific PHY register */
+#define MII_MV_SPEC_CTRL		16
+enum {
+	MV_SPEC_MDI_CROSS_AUTO		= (0x6 << 4),
+	MV_SPEC_ENERGY_DETECT		= (0x3 << 8),
+	MV_SPEC_DOWNSHIFT_COUNTER	= (0x3 << 12),
+};
+
+#define MII_MV_PAGE			22
+
+#define MV_REG_FIBER_SERDES		0xf
+#define MV_PAGE_FIBER_SERDES		0x1
+
+struct mvsw61xx_state {
+	struct switch_dev dev;
+	struct mii_bus *bus;
+	int base_addr;
+	u16 model;
+
+	bool registered;
+	bool is_indirect;
+
+	int cpu_port0;
+	int cpu_port1;
+
+	int vlan_enabled;
+	struct port_state {
+		u16 fdb;
+		u16 pvid;
+		u16 mask;
+		u8 qmode;
+	} ports[MV_PORTS];
+
+	struct vlan_state {
+		bool port_based;
+
+		u16 mask;
+		u16 vid;
+		u32 port_mode;
+		u32 port_sstate;
+	} vlans[MV_VLANS];
+
+	char buf[128];
+};
+
+#define get_state(_dev) container_of((_dev), struct mvsw61xx_state, dev)
+
+#endif
diff --git a/target/linux/generic/files/drivers/net/phy/mvswitch.c b/target/linux/generic/files/drivers/net/phy/mvswitch.c
new file mode 100644
index 0000000000..af31d0b5ac
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/mvswitch.c
@@ -0,0 +1,433 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/if_vlan.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "mvswitch.h"
+
+/* Undefine this to use trailer mode instead.
+ * I don't know if header mode works with all chips */
+#define HEADER_MODE	1
+
+MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
+MODULE_AUTHOR("Felix Fietkau");
+MODULE_LICENSE("GPL");
+
+#define MVSWITCH_MAGIC 0x88E6060
+
+struct mvswitch_priv {
+	netdev_features_t orig_features;
+	u8 vlans[16];
+};
+
+#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
+
+static inline u16
+r16(struct phy_device *phydev, int addr, int reg)
+{
+	return phydev->bus->read(phydev->bus, addr, reg);
+}
+
+static inline void
+w16(struct phy_device *phydev, int addr, int reg, u16 val)
+{
+	phydev->bus->write(phydev->bus, addr, reg, val);
+}
+
+
+static struct sk_buff *
+mvswitch_mangle_tx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct mvswitch_priv *priv;
+	char *buf = NULL;
+	u16 vid;
+
+	priv = dev->phy_ptr;
+	if (unlikely(!priv))
+		goto error;
+
+	if (unlikely(skb->len < 16))
+		goto error;
+
+#ifdef HEADER_MODE
+	if (__vlan_hwaccel_get_tag(skb, &vid))
+		goto error;
+
+	if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
+		if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC))
+			goto error_expand;
+		if (skb->len < 62)
+			skb->len = 62;
+	}
+	buf = skb_push(skb, MV_HEADER_SIZE);
+#else
+	if (__vlan_get_tag(skb, &vid))
+		goto error;
+
+	if (unlikely((vid > 15 || !priv->vlans[vid])))
+		goto error;
+
+	if (skb->len <= 64) {
+		if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC))
+			goto error_expand;
+
+		buf = skb->data + 64;
+		skb->len = 64 + MV_TRAILER_SIZE;
+	} else {
+		if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
+			if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC))
+				goto error_expand;
+		}
+		buf = skb_put(skb, 4);
+	}
+
+	/* move the ethernet header 4 bytes forward, overwriting the vlan tag */
+	memmove(skb->data + 4, skb->data, 12);
+	skb->data += 4;
+	skb->len -= 4;
+	skb->mac_header += 4;
+#endif
+
+	if (!buf)
+		goto error;
+
+
+#ifdef HEADER_MODE
+	/* prepend the tag */
+	*((__be16 *) buf) = cpu_to_be16(
+		((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) |
+		((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M)
+	);
+#else
+	/* append the tag */
+	*((__be32 *) buf) = cpu_to_be32((
+		(MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) |
+		((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S)
+	));
+#endif
+
+	return skb;
+
+error_expand:
+	if (net_ratelimit())
+		printk("%s: failed to expand/update skb for the switch\n", dev->name);
+
+error:
+	/* any errors? drop the packet! */
+	dev_kfree_skb_any(skb);
+	return NULL;
+}
+
+static void
+mvswitch_mangle_rx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct mvswitch_priv *priv;
+	unsigned char *buf;
+	int vlan = -1;
+	int i;
+
+	priv = dev->phy_ptr;
+	if (WARN_ON_ONCE(!priv))
+		return;
+
+#ifdef HEADER_MODE
+	buf = skb->data;
+	skb_pull(skb, MV_HEADER_SIZE);
+#else
+	buf = skb->data + skb->len - MV_TRAILER_SIZE;
+	if (buf[0] != 0x80)
+		return;
+#endif
+
+	/* look for the vlan matching the incoming port */
+	for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
+		if ((1 << buf[1]) & priv->vlans[i])
+			vlan = i;
+	}
+
+	if (vlan == -1)
+		return;
+
+	__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
+}
+
+
+static int
+mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val)
+{
+	int i = 100;
+	u16 r;
+
+	do {
+		r = r16(pdev, addr, reg) & mask;
+		if (r == val)
+			return 0;
+	} while(--i > 0);
+	return -ETIMEDOUT;
+}
+
+static int
+mvswitch_config_init(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+	struct net_device *dev = pdev->attached_dev;
+	u8 vlmap = 0;
+	int i;
+
+	if (!dev)
+		return -EINVAL;
+
+	printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
+	pdev->supported = ADVERTISED_100baseT_Full;
+	pdev->advertising = ADVERTISED_100baseT_Full;
+	dev->phy_ptr = priv;
+	pdev->irq = PHY_POLL;
+#ifdef HEADER_MODE
+	dev->flags |= IFF_PROMISC;
+#endif
+
+	/* initialize default vlans */
+	for (i = 0; i < MV_PORTS; i++)
+		priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i);
+
+	/* before entering reset, disable all ports */
+	for (i = 0; i < MV_PORTS; i++)
+		w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
+
+	msleep(2); /* wait for the status change to settle in */
+
+	/* put the ATU in reset */
+	w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET);
+
+	i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0);
+	if (i < 0) {
+		printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
+		return i;
+	}
+
+	/* set the ATU flags */
+	w16(pdev, MV_SWITCHREG(ATU_CTRL),
+		MV_ATUCTL_NO_LEARN |
+		MV_ATUCTL_ATU_1K |
+		MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */
+	);
+
+	/* initialize the cpu port */
+	w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
+#ifdef HEADER_MODE
+		MV_PORTCTRL_HEADER |
+#else
+		MV_PORTCTRL_RXTR |
+		MV_PORTCTRL_TXTR |
+#endif
+		MV_PORTCTRL_ENABLED
+	);
+	/* wait for the phy change to settle in */
+	msleep(2);
+	for (i = 0; i < MV_PORTS; i++) {
+		u8 pvid = 0;
+		int j;
+
+		vlmap = 0;
+
+		/* look for the matching vlan */
+		for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
+			if (priv->vlans[j] & (1 << i)) {
+				vlmap = priv->vlans[j];
+				pvid = j;
+			}
+		}
+		/* leave port unconfigured if it's not part of a vlan */
+		if (!vlmap)
+			continue;
+
+		/* add the cpu port to the allowed destinations list */
+		vlmap |= (1 << MV_CPUPORT);
+
+		/* take port out of its own vlan destination map */
+		vlmap &= ~(1 << i);
+
+		/* apply vlan settings */
+		w16(pdev, MV_PORTREG(VLANMAP, i),
+			MV_PORTVLAN_PORTS(vlmap) |
+			MV_PORTVLAN_ID(i)
+		);
+
+		/* re-enable port */
+		w16(pdev, MV_PORTREG(CONTROL, i),
+			MV_PORTCTRL_ENABLED
+		);
+	}
+
+	w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
+		MV_PORTVLAN_ID(MV_CPUPORT)
+	);
+
+	/* set the port association vector */
+	for (i = 0; i <= MV_PORTS; i++) {
+		w16(pdev, MV_PORTREG(ASSOC, i),
+			MV_PORTASSOC_PORTS(1 << i)
+		);
+	}
+
+	/* init switch control */
+	w16(pdev, MV_SWITCHREG(CTRL),
+		MV_SWITCHCTL_MSIZE |
+		MV_SWITCHCTL_DROP
+	);
+
+	dev->eth_mangle_rx = mvswitch_mangle_rx;
+	dev->eth_mangle_tx = mvswitch_mangle_tx;
+	priv->orig_features = dev->features;
+
+#ifdef HEADER_MODE
+	dev->priv_flags |= IFF_NO_IP_ALIGN;
+	dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
+#else
+	dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+#endif
+
+	return 0;
+}
+
+static int
+mvswitch_read_status(struct phy_device *pdev)
+{
+	pdev->speed = SPEED_100;
+	pdev->duplex = DUPLEX_FULL;
+	pdev->link = 1;
+
+	/* XXX ugly workaround: we can't force the switch
+	 * to gracefully handle hosts moving from one port to another,
+	 * so we have to regularly clear the ATU database */
+
+	/* wait for the ATU to become available */
+	mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
+	/* flush the ATU */
+	w16(pdev, MV_SWITCHREG(ATU_OP),
+		MV_ATUOP_INPROGRESS |
+		MV_ATUOP_FLUSH_ALL
+	);
+
+	/* wait for operation to complete */
+	mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
+	return 0;
+}
+
+static int
+mvswitch_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static void
+mvswitch_detach(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+	struct net_device *dev = pdev->attached_dev;
+
+	if (!dev)
+		return;
+
+	dev->phy_ptr = NULL;
+	dev->eth_mangle_rx = NULL;
+	dev->eth_mangle_tx = NULL;
+	dev->features = priv->orig_features;
+	dev->priv_flags &= ~IFF_NO_IP_ALIGN;
+}
+
+static void
+mvswitch_remove(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+
+	kfree(priv);
+}
+
+static int
+mvswitch_probe(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv;
+
+	priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	pdev->priv = priv;
+
+	return 0;
+}
+
+static int
+mvswitch_fixup(struct phy_device *dev)
+{
+	u16 reg;
+
+	if (dev->addr != 0x10)
+		return 0;
+
+	reg = dev->bus->read(dev->bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
+	if (reg != MV_IDENT_VALUE)
+		return 0;
+
+	dev->phy_id = MVSWITCH_MAGIC;
+	return 0;
+}
+
+
+static struct phy_driver mvswitch_driver = {
+	.name		= "Marvell 88E6060",
+	.phy_id		= MVSWITCH_MAGIC,
+	.phy_id_mask	= 0xffffffff,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= &mvswitch_probe,
+	.remove		= &mvswitch_remove,
+	.detach		= &mvswitch_detach,
+	.config_init	= &mvswitch_config_init,
+	.config_aneg	= &mvswitch_config_aneg,
+	.read_status	= &mvswitch_read_status,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init
+mvswitch_init(void)
+{
+	phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup);
+	return phy_driver_register(&mvswitch_driver);
+}
+
+static void __exit
+mvswitch_exit(void)
+{
+	phy_driver_unregister(&mvswitch_driver);
+}
+
+module_init(mvswitch_init);
+module_exit(mvswitch_exit);
diff --git a/target/linux/generic/files/drivers/net/phy/mvswitch.h b/target/linux/generic/files/drivers/net/phy/mvswitch.h
new file mode 100644
index 0000000000..ab2a1a126e
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/mvswitch.h
@@ -0,0 +1,145 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __MVSWITCH_H
+#define __MVSWITCH_H
+
+#define MV_HEADER_SIZE	2
+#define MV_HEADER_PORTS_M	0x001f
+#define MV_HEADER_PORTS_S	0
+#define MV_HEADER_VLAN_M	0xf000
+#define MV_HEADER_VLAN_S	12
+
+#define MV_TRAILER_SIZE	4
+#define MV_TRAILER_PORTS_M	0x1f
+#define MV_TRAILER_PORTS_S	16
+#define MV_TRAILER_FLAGS_S	24
+#define MV_TRAILER_OVERRIDE	0x80
+
+
+#define MV_PORTS	5
+#define MV_WANPORT	4
+#define MV_CPUPORT	5
+
+#define MV_BASE		0x10
+
+#define MV_PHYPORT_BASE		(MV_BASE + 0x0)
+#define MV_PHYPORT(_n)		(MV_PHYPORT_BASE + (_n))
+#define MV_SWITCHPORT_BASE	(MV_BASE + 0x8)
+#define MV_SWITCHPORT(_n)	(MV_SWITCHPORT_BASE + (_n))
+#define MV_SWITCHREGS		(MV_BASE + 0xf)
+
+enum {
+	MV_PHY_CONTROL      = 0x00,
+	MV_PHY_STATUS       = 0x01,
+	MV_PHY_IDENT0       = 0x02,
+	MV_PHY_IDENT1       = 0x03,
+	MV_PHY_ANEG         = 0x04,
+	MV_PHY_LINK_ABILITY = 0x05,
+	MV_PHY_ANEG_EXPAND  = 0x06,
+	MV_PHY_XMIT_NEXTP   = 0x07,
+	MV_PHY_LINK_NEXTP   = 0x08,
+	MV_PHY_CONTROL1     = 0x10,
+	MV_PHY_STATUS1      = 0x11,
+	MV_PHY_INTR_EN      = 0x12,
+	MV_PHY_INTR_STATUS  = 0x13,
+	MV_PHY_INTR_PORT    = 0x14,
+	MV_PHY_RECV_COUNTER = 0x16,
+	MV_PHY_LED_PARALLEL = 0x16,
+	MV_PHY_LED_STREAM   = 0x17,
+	MV_PHY_LED_CTRL     = 0x18,
+	MV_PHY_LED_OVERRIDE = 0x19,
+	MV_PHY_VCT_CTRL     = 0x1a,
+	MV_PHY_VCT_STATUS   = 0x1b,
+	MV_PHY_CONTROL2     = 0x1e
+};
+#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type
+
+enum {
+	MV_PORT_STATUS      = 0x00,
+	MV_PORT_IDENT       = 0x03,
+	MV_PORT_CONTROL     = 0x04,
+	MV_PORT_VLANMAP     = 0x06,
+	MV_PORT_ASSOC       = 0x0b,
+	MV_PORT_RXCOUNT     = 0x10,
+	MV_PORT_TXCOUNT     = 0x11,
+};
+#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
+
+enum {
+	MV_PORTCTRL_BLOCK   =  (1 << 0),
+	MV_PORTCTRL_LEARN   =  (2 << 0),
+	MV_PORTCTRL_ENABLED =  (3 << 0),
+	MV_PORTCTRL_VLANTUN =  (1 << 7),	/* Enforce VLANs on packets */
+	MV_PORTCTRL_RXTR    =  (1 << 8),	/* Enable Marvell packet trailer for ingress */
+	MV_PORTCTRL_HEADER	= (1 << 11),	/* Enable Marvell packet header mode for port */
+	MV_PORTCTRL_TXTR    = (1 << 14),	/* Enable Marvell packet trailer for egress */
+	MV_PORTCTRL_FORCEFL = (1 << 15),	/* force flow control */
+};
+
+#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12)
+#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f)
+
+#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f)
+#define MV_PORTASSOC_MONITOR	(1 << 15)
+
+enum {
+	MV_SWITCH_MAC0      = 0x01,
+	MV_SWITCH_MAC1      = 0x02,
+	MV_SWITCH_MAC2      = 0x03,
+	MV_SWITCH_CTRL      = 0x04,
+	MV_SWITCH_ATU_CTRL  = 0x0a,
+	MV_SWITCH_ATU_OP    = 0x0b,
+	MV_SWITCH_ATU_DATA  = 0x0c,
+	MV_SWITCH_ATU_MAC0  = 0x0d,
+	MV_SWITCH_ATU_MAC1  = 0x0e,
+	MV_SWITCH_ATU_MAC2  = 0x0f,
+};
+#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
+
+enum {
+	MV_SWITCHCTL_EEIE   =  (1 << 0),	/* EEPROM interrupt enable */
+	MV_SWITCHCTL_PHYIE  =  (1 << 1),	/* PHY interrupt enable */
+	MV_SWITCHCTL_ATUDONE=  (1 << 2),	/* ATU done interrupt enable */
+	MV_SWITCHCTL_ATUIE  =  (1 << 3),	/* ATU interrupt enable */
+	MV_SWITCHCTL_CTRMODE=  (1 << 8),	/* statistics for rx and tx errors */
+	MV_SWITCHCTL_RELOAD =  (1 << 9),	/* reload registers from eeprom */
+	MV_SWITCHCTL_MSIZE  = (1 << 10),	/* increase maximum frame size */
+	MV_SWITCHCTL_DROP   = (1 << 13),	/* discard frames with excessive collisions */
+};
+
+enum {
+#define MV_ATUCTL_AGETIME_MIN	16
+#define MV_ATUCTL_AGETIME_MAX	4080
+#define MV_ATUCTL_AGETIME(_n)	((((_n) / 16) & 0xff) << 4)
+	MV_ATUCTL_ATU_256   = (0 << 12),
+	MV_ATUCTL_ATU_512   = (1 << 12),
+	MV_ATUCTL_ATU_1K	= (2 << 12),
+	MV_ATUCTL_ATUMASK   = (3 << 12),
+	MV_ATUCTL_NO_LEARN  = (1 << 14),
+	MV_ATUCTL_RESET     = (1 << 15),
+};
+
+enum {
+#define MV_ATUOP_DBNUM(_n)	((_n) & 0x0f)
+
+	MV_ATUOP_NOOP       = (0 << 12),
+	MV_ATUOP_FLUSH_ALL  = (1 << 12),
+	MV_ATUOP_FLUSH_U    = (2 << 12),
+	MV_ATUOP_LOAD_DB    = (3 << 12),
+	MV_ATUOP_GET_NEXT   = (4 << 12),
+	MV_ATUOP_FLUSH_DB   = (5 << 12),
+	MV_ATUOP_FLUSH_DB_UU= (6 << 12),
+
+	MV_ATUOP_INPROGRESS = (1 << 15),
+};
+
+#define MV_IDENT_MASK		0xfff0
+#define MV_IDENT_VALUE		0x0600
+
+#endif
diff --git a/target/linux/generic/files/drivers/net/phy/psb6970.c b/target/linux/generic/files/drivers/net/phy/psb6970.c
new file mode 100644
index 0000000000..2fcd299013
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/psb6970.c
@@ -0,0 +1,438 @@
+/*
+ * Lantiq PSB6970 (Tantos) Switch driver
+ *
+ * Copyright (c) 2009,2010 Team Embedded.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * The switch programming done in this driver follows the 
+ * "Ethernet Traffic Separation using VLAN" Application Note as
+ * published by Lantiq.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/switch.h>
+#include <linux/phy.h>
+
+#define PSB6970_MAX_VLANS		16
+#define PSB6970_NUM_PORTS		7
+#define PSB6970_DEFAULT_PORT_CPU	6
+#define PSB6970_IS_CPU_PORT(x)		((x) > 4)
+
+#define PHYADDR(_reg)		((_reg >> 5) & 0xff), (_reg & 0x1f)
+
+/* --- Identification --- */
+#define PSB6970_CI0		0x0100
+#define PSB6970_CI0_MASK	0x000f
+#define PSB6970_CI1		0x0101
+#define PSB6970_CI1_VAL		0x2599
+#define PSB6970_CI1_MASK	0xffff
+
+/* --- VLAN filter table --- */
+#define PSB6970_VFxL(i)		((i)*2+0x10)	/* VLAN Filter Low */
+#define PSB6970_VFxL_VV		(1 << 15)	/* VLAN_Valid */
+
+#define PSB6970_VFxH(i)		((i)*2+0x11)	/* VLAN Filter High */
+#define PSB6970_VFxH_TM_SHIFT	7		/* Tagged Member */
+
+/* --- Port registers --- */
+#define PSB6970_EC(p)		((p)*0x20+2)	/* Extended Control */
+#define PSB6970_EC_IFNTE	(1 << 1)	/* Input Force No Tag Enable */
+
+#define PSB6970_PBVM(p)		((p)*0x20+3)	/* Port Base VLAN Map */
+#define PSB6970_PBVM_VMCE	(1 << 8)
+#define PSB6970_PBVM_AOVTP	(1 << 9)
+#define PSB6970_PBVM_VSD	(1 << 10)
+#define PSB6970_PBVM_VC		(1 << 11)	/* VID Check with VID table */
+#define PSB6970_PBVM_TBVE	(1 << 13)	/* Tag-Based VLAN enable */
+
+#define PSB6970_DVID(p)		((p)*0x20+4)	/* Default VLAN ID & Priority */
+
+struct psb6970_priv {
+	struct switch_dev dev;
+	struct phy_device *phy;
+	u16 (*read) (struct phy_device* phydev, int reg);
+	void (*write) (struct phy_device* phydev, int reg, u16 val);
+	struct mutex reg_mutex;
+
+	/* all fields below are cleared on reset */
+	bool vlan;
+	u16 vlan_id[PSB6970_MAX_VLANS];
+	u8 vlan_table[PSB6970_MAX_VLANS];
+	u8 vlan_tagged;
+	u16 pvid[PSB6970_NUM_PORTS];
+};
+
+#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev)
+
+static u16 psb6970_mii_read(struct phy_device *phydev, int reg)
+{
+	return phydev->bus->read(phydev->bus, PHYADDR(reg));
+}
+
+static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val)
+{
+	phydev->bus->write(phydev->bus, PHYADDR(reg), val);
+}
+
+static int
+psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	priv->vlan = !!val->value.i;
+	return 0;
+}
+
+static int
+psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	val->value.i = priv->vlan;
+	return 0;
+}
+
+static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+
+	/* make sure no invalid PVIDs get set */
+	if (vlan >= dev->vlans)
+		return -EINVAL;
+
+	priv->pvid[port] = vlan;
+	return 0;
+}
+
+static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	*vlan = priv->pvid[port];
+	return 0;
+}
+
+static int
+psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	priv->vlan_id[val->port_vlan] = val->value.i;
+	return 0;
+}
+
+static int
+psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	val->value.i = priv->vlan_id[val->port_vlan];
+	return 0;
+}
+
+static struct switch_attr psb6970_globals[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "enable_vlan",
+	 .description = "Enable VLAN mode",
+	 .set = psb6970_set_vlan,
+	 .get = psb6970_get_vlan,
+	 .max = 1},
+};
+
+static struct switch_attr psb6970_port[] = {
+};
+
+static struct switch_attr psb6970_vlan[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "vid",
+	 .description = "VLAN ID (0-4094)",
+	 .set = psb6970_set_vid,
+	 .get = psb6970_get_vid,
+	 .max = 4094,
+	 },
+};
+
+static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	u8 ports = priv->vlan_table[val->port_vlan];
+	int i;
+
+	val->len = 0;
+	for (i = 0; i < PSB6970_NUM_PORTS; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (priv->vlan_tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	u8 *vt = &priv->vlan_table[val->port_vlan];
+	int i, j;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
+			priv->vlan_tagged |= (1 << p->id);
+		else {
+			priv->vlan_tagged &= ~(1 << p->id);
+			priv->pvid[p->id] = val->port_vlan;
+
+			/* make sure that an untagged port does not
+			 * appear in other vlans */
+			for (j = 0; j < PSB6970_MAX_VLANS; j++) {
+				if (j == val->port_vlan)
+					continue;
+				priv->vlan_table[j] &= ~(1 << p->id);
+			}
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static int psb6970_hw_apply(struct switch_dev *dev)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	int i, j;
+
+	mutex_lock(&priv->reg_mutex);
+
+	if (priv->vlan) {
+		/* into the vlan translation unit */
+		for (j = 0; j < PSB6970_MAX_VLANS; j++) {
+			u8 vp = priv->vlan_table[j];
+
+			if (vp) {
+				priv->write(priv->phy, PSB6970_VFxL(j),
+					    PSB6970_VFxL_VV | priv->vlan_id[j]);
+				priv->write(priv->phy, PSB6970_VFxH(j),
+					    ((vp & priv->
+					      vlan_tagged) <<
+					     PSB6970_VFxH_TM_SHIFT) | vp);
+			} else	/* clear VLAN Valid flag for unused vlans */
+				priv->write(priv->phy, PSB6970_VFxL(j), 0);
+
+		}
+	}
+
+	/* update the port destination mask registers and tag settings */
+	for (i = 0; i < PSB6970_NUM_PORTS; i++) {
+		int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0;
+
+		if (priv->vlan) {
+			ec = PSB6970_EC_IFNTE;
+			dvid = priv->vlan_id[priv->pvid[i]];
+			pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE;
+
+			if ((i << 1) & priv->vlan_tagged)
+				pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC;
+		}
+
+		priv->write(priv->phy, PSB6970_PBVM(i), pbvm);
+
+		if (!PSB6970_IS_CPU_PORT(i)) {
+			priv->write(priv->phy, PSB6970_EC(i), ec);
+			priv->write(priv->phy, PSB6970_DVID(i), dvid);
+		}
+	}
+
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+static int psb6970_reset_switch(struct switch_dev *dev)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+
+	memset(&priv->vlan, 0, sizeof(struct psb6970_priv) -
+	       offsetof(struct psb6970_priv, vlan));
+
+	for (i = 0; i < PSB6970_MAX_VLANS; i++)
+		priv->vlan_id[i] = i;
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return psb6970_hw_apply(dev);
+}
+
+static const struct switch_dev_ops psb6970_ops = {
+	.attr_global = {
+			.attr = psb6970_globals,
+			.n_attr = ARRAY_SIZE(psb6970_globals),
+			},
+	.attr_port = {
+		      .attr = psb6970_port,
+		      .n_attr = ARRAY_SIZE(psb6970_port),
+		      },
+	.attr_vlan = {
+		      .attr = psb6970_vlan,
+		      .n_attr = ARRAY_SIZE(psb6970_vlan),
+		      },
+	.get_port_pvid = psb6970_get_pvid,
+	.set_port_pvid = psb6970_set_pvid,
+	.get_vlan_ports = psb6970_get_ports,
+	.set_vlan_ports = psb6970_set_ports,
+	.apply_config = psb6970_hw_apply,
+	.reset_switch = psb6970_reset_switch,
+};
+
+static int psb6970_config_init(struct phy_device *pdev)
+{
+	struct psb6970_priv *priv;
+	struct net_device *dev = pdev->attached_dev;
+	struct switch_dev *swdev;
+	int ret;
+
+	priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->phy = pdev;
+
+	if (pdev->addr == 0)
+		printk(KERN_INFO "%s: psb6970 switch driver attached.\n",
+		       pdev->attached_dev->name);
+
+	if (pdev->addr != 0) {
+		kfree(priv);
+		return 0;
+	}
+
+	pdev->supported = pdev->advertising = SUPPORTED_100baseT_Full;
+
+	mutex_init(&priv->reg_mutex);
+	priv->read = psb6970_mii_read;
+	priv->write = psb6970_mii_write;
+
+	pdev->priv = priv;
+
+	swdev = &priv->dev;
+	swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU;
+	swdev->ops = &psb6970_ops;
+
+	swdev->name = "Lantiq PSB6970";
+	swdev->vlans = PSB6970_MAX_VLANS;
+	swdev->ports = PSB6970_NUM_PORTS;
+
+	if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) {
+		kfree(priv);
+		goto done;
+	}
+
+	ret = psb6970_reset_switch(&priv->dev);
+	if (ret) {
+		kfree(priv);
+		goto done;
+	}
+
+	dev->phy_ptr = priv;
+
+done:
+	return ret;
+}
+
+static int psb6970_read_status(struct phy_device *phydev)
+{
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+
+	phydev->state = PHY_RUNNING;
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+static int psb6970_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int psb6970_probe(struct phy_device *pdev)
+{
+	return 0;
+}
+
+static void psb6970_remove(struct phy_device *pdev)
+{
+	struct psb6970_priv *priv = pdev->priv;
+
+	if (!priv)
+		return;
+
+	if (pdev->addr == 0)
+		unregister_switch(&priv->dev);
+	kfree(priv);
+}
+
+static int psb6970_fixup(struct phy_device *dev)
+{
+	struct mii_bus *bus = dev->bus;
+	u16 reg;
+
+	/* look for the switch on the bus */
+	reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK;
+	if (reg != PSB6970_CI1_VAL)
+		return 0;
+
+	dev->phy_id = (reg << 16);
+	dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK;
+
+	return 0;
+}
+
+static struct phy_driver psb6970_driver = {
+	.name = "Lantiq PSB6970",
+	.phy_id = PSB6970_CI1_VAL << 16,
+	.phy_id_mask = 0xffff0000,
+	.features = PHY_BASIC_FEATURES,
+	.probe = psb6970_probe,
+	.remove = psb6970_remove,
+	.config_init = &psb6970_config_init,
+	.config_aneg = &psb6970_config_aneg,
+	.read_status = &psb6970_read_status,
+	.driver = {.owner = THIS_MODULE},
+};
+
+int __init psb6970_init(void)
+{
+	phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup);
+	return phy_driver_register(&psb6970_driver);
+}
+
+module_init(psb6970_init);
+
+void __exit psb6970_exit(void)
+{
+	phy_driver_unregister(&psb6970_driver);
+}
+
+module_exit(psb6970_exit);
+
+MODULE_DESCRIPTION("Lantiq PSB6970 Switch");
+MODULE_AUTHOR("Ithamar R. Adema <ithamar.adema@team-embedded.nl>");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8306.c b/target/linux/generic/files/drivers/net/phy/rtl8306.c
new file mode 100644
index 0000000000..5206509c42
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8306.c
@@ -0,0 +1,1060 @@
+/*
+ * rtl8306.c: RTL8306S switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <net/genetlink.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+
+//#define DEBUG 1
+
+/* Global (PHY0) */
+#define RTL8306_REG_PAGE		16
+#define RTL8306_REG_PAGE_LO		(1 << 15)
+#define RTL8306_REG_PAGE_HI		(1 << 1) /* inverted */
+
+#define RTL8306_NUM_VLANS		16
+#define RTL8306_NUM_PORTS		6
+#define RTL8306_PORT_CPU		5
+#define RTL8306_NUM_PAGES		4
+#define RTL8306_NUM_REGS		32
+
+#define RTL_NAME_S          "RTL8306S"
+#define RTL_NAME_SD         "RTL8306SD"
+#define RTL_NAME_SDM        "RTL8306SDM"
+#define RTL_NAME_UNKNOWN    "RTL8306(unknown)"
+
+#define RTL8306_MAGIC	0x8306
+
+static LIST_HEAD(phydevs);
+
+struct rtl_priv {
+	struct list_head list;
+	struct switch_dev dev;
+	int page;
+	int type;
+	int do_cpu;
+	struct mii_bus *bus;
+	char hwname[sizeof(RTL_NAME_UNKNOWN)];
+	bool fixup;
+};
+
+struct rtl_phyregs {
+	int nway;
+	int speed;
+	int duplex;
+};
+
+#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev)
+
+enum {
+	RTL_TYPE_S,
+	RTL_TYPE_SD,
+	RTL_TYPE_SDM,
+};
+
+struct rtl_reg {
+	int page;
+	int phy;
+	int reg;
+	int bits;
+	int shift;
+	int inverted;
+};
+
+#define RTL_VLAN_REGOFS(name) \
+	(RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name)
+
+#define RTL_PORT_REGOFS(name) \
+	(RTL_REG_PORT1_##name - RTL_REG_PORT0_##name)
+
+#define RTL_PORT_REG(id, reg) \
+	(RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg)))
+
+#define RTL_VLAN_REG(id, reg) \
+	(RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg)))
+
+#define RTL_GLOBAL_REGATTR(reg) \
+	.id = RTL_REG_##reg, \
+	.type = SWITCH_TYPE_INT, \
+	.ofs = 0, \
+	.set = rtl_attr_set_int, \
+	.get = rtl_attr_get_int
+
+#define RTL_PORT_REGATTR(reg) \
+	.id = RTL_REG_PORT0_##reg, \
+	.type = SWITCH_TYPE_INT, \
+	.ofs = RTL_PORT_REGOFS(reg), \
+	.set = rtl_attr_set_port_int, \
+	.get = rtl_attr_get_port_int
+
+#define RTL_VLAN_REGATTR(reg) \
+	.id = RTL_REG_VLAN0_##reg, \
+	.type = SWITCH_TYPE_INT, \
+	.ofs = RTL_VLAN_REGOFS(reg), \
+	.set = rtl_attr_set_vlan_int, \
+	.get = rtl_attr_get_vlan_int
+
+enum rtl_regidx {
+	RTL_REG_CHIPID,
+	RTL_REG_CHIPVER,
+	RTL_REG_CHIPTYPE,
+	RTL_REG_CPUPORT,
+
+	RTL_REG_EN_CPUPORT,
+	RTL_REG_EN_TAG_OUT,
+	RTL_REG_EN_TAG_CLR,
+	RTL_REG_EN_TAG_IN,
+	RTL_REG_TRAP_CPU,
+	RTL_REG_CPU_LINKUP,
+	RTL_REG_TRUNK_PORTSEL,
+	RTL_REG_EN_TRUNK,
+	RTL_REG_RESET,
+
+	RTL_REG_VLAN_ENABLE,
+	RTL_REG_VLAN_FILTER,
+	RTL_REG_VLAN_TAG_ONLY,
+	RTL_REG_VLAN_TAG_AWARE,
+#define RTL_VLAN_ENUM(id) \
+	RTL_REG_VLAN##id##_VID, \
+	RTL_REG_VLAN##id##_PORTMASK
+	RTL_VLAN_ENUM(0),
+	RTL_VLAN_ENUM(1),
+	RTL_VLAN_ENUM(2),
+	RTL_VLAN_ENUM(3),
+	RTL_VLAN_ENUM(4),
+	RTL_VLAN_ENUM(5),
+	RTL_VLAN_ENUM(6),
+	RTL_VLAN_ENUM(7),
+	RTL_VLAN_ENUM(8),
+	RTL_VLAN_ENUM(9),
+	RTL_VLAN_ENUM(10),
+	RTL_VLAN_ENUM(11),
+	RTL_VLAN_ENUM(12),
+	RTL_VLAN_ENUM(13),
+	RTL_VLAN_ENUM(14),
+	RTL_VLAN_ENUM(15),
+#define RTL_PORT_ENUM(id) \
+	RTL_REG_PORT##id##_PVID, \
+	RTL_REG_PORT##id##_NULL_VID_REPLACE, \
+	RTL_REG_PORT##id##_NON_PVID_DISCARD, \
+	RTL_REG_PORT##id##_VID_INSERT, \
+	RTL_REG_PORT##id##_TAG_INSERT, \
+	RTL_REG_PORT##id##_LINK, \
+	RTL_REG_PORT##id##_SPEED, \
+	RTL_REG_PORT##id##_NWAY, \
+	RTL_REG_PORT##id##_NRESTART, \
+	RTL_REG_PORT##id##_DUPLEX, \
+	RTL_REG_PORT##id##_RXEN, \
+	RTL_REG_PORT##id##_TXEN
+	RTL_PORT_ENUM(0),
+	RTL_PORT_ENUM(1),
+	RTL_PORT_ENUM(2),
+	RTL_PORT_ENUM(3),
+	RTL_PORT_ENUM(4),
+	RTL_PORT_ENUM(5),
+};
+
+static const struct rtl_reg rtl_regs[] = {
+	[RTL_REG_CHIPID]         = { 0, 4, 30, 16,  0, 0 },
+	[RTL_REG_CHIPVER]        = { 0, 4, 31,  8,  0, 0 },
+	[RTL_REG_CHIPTYPE]       = { 0, 4, 31,  2,  8, 0 },
+
+	/* CPU port number */
+	[RTL_REG_CPUPORT]        = { 2, 4, 21,  3,  0, 0 },
+	/* Enable CPU port function */
+	[RTL_REG_EN_CPUPORT]     = { 3, 2, 21,  1, 15, 1 },
+	/* Enable CPU port tag insertion */
+	[RTL_REG_EN_TAG_OUT]     = { 3, 2, 21,  1, 12, 0 },
+	/* Enable CPU port tag removal */
+	[RTL_REG_EN_TAG_CLR]     = { 3, 2, 21,  1, 11, 0 },
+	/* Enable CPU port tag checking */
+	[RTL_REG_EN_TAG_IN]      = { 0, 4, 21,  1,  7, 0 },
+	[RTL_REG_EN_TRUNK]       = { 0, 0, 19,  1, 11, 1 },
+	[RTL_REG_TRUNK_PORTSEL]  = { 0, 0, 16,  1,  6, 1 },
+	[RTL_REG_RESET]          = { 0, 0, 16,  1, 12, 0 },
+
+	[RTL_REG_TRAP_CPU]       = { 3, 2, 22,  1,  6, 0 },
+	[RTL_REG_CPU_LINKUP]     = { 0, 6, 22,  1, 15, 0 },
+
+	[RTL_REG_VLAN_TAG_ONLY]  = { 0, 0, 16,  1,  8, 1 },
+	[RTL_REG_VLAN_FILTER]    = { 0, 0, 16,  1,  9, 1 },
+	[RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16,  1, 10, 1 },
+	[RTL_REG_VLAN_ENABLE]    = { 0, 0, 18,  1,  8, 1 },
+
+#define RTL_VLAN_REGS(id, phy, page, regofs) \
+	[RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \
+	[RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 }
+	RTL_VLAN_REGS( 0, 0, 0, 0),
+	RTL_VLAN_REGS( 1, 1, 0, 0),
+	RTL_VLAN_REGS( 2, 2, 0, 0),
+	RTL_VLAN_REGS( 3, 3, 0, 0),
+	RTL_VLAN_REGS( 4, 4, 0, 0),
+	RTL_VLAN_REGS( 5, 0, 1, 2),
+	RTL_VLAN_REGS( 6, 1, 1, 2),
+	RTL_VLAN_REGS( 7, 2, 1, 2),
+	RTL_VLAN_REGS( 8, 3, 1, 2),
+	RTL_VLAN_REGS( 9, 4, 1, 2),
+	RTL_VLAN_REGS(10, 0, 1, 4),
+	RTL_VLAN_REGS(11, 1, 1, 4),
+	RTL_VLAN_REGS(12, 2, 1, 4),
+	RTL_VLAN_REGS(13, 3, 1, 4),
+	RTL_VLAN_REGS(14, 4, 1, 4),
+	RTL_VLAN_REGS(15, 0, 1, 6),
+
+#define REG_PORT_SETTING(port, phy) \
+	[RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \
+	[RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \
+	[RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \
+	[RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \
+	[RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \
+	[RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \
+	[RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \
+	[RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \
+	[RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \
+	[RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \
+	[RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 }
+
+	REG_PORT_SETTING(0, 0),
+	REG_PORT_SETTING(1, 1),
+	REG_PORT_SETTING(2, 2),
+	REG_PORT_SETTING(3, 3),
+	REG_PORT_SETTING(4, 4),
+	REG_PORT_SETTING(5, 6),
+
+#define REG_PORT_PVID(phy, page, regofs) \
+	{ page, phy, 24 + regofs, 4, 12, 0 }
+	[RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0),
+	[RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0),
+	[RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0),
+	[RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0),
+	[RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0),
+	[RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2),
+};
+
+
+static inline void
+rtl_set_page(struct rtl_priv *priv, unsigned int page)
+{
+	struct mii_bus *bus = priv->bus;
+	u16 pgsel;
+
+	if (priv->fixup)
+		return;
+
+	if (priv->page == page)
+		return;
+
+	BUG_ON(page > RTL8306_NUM_PAGES);
+	pgsel = bus->read(bus, 0, RTL8306_REG_PAGE);
+	pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI);
+	if (page & (1 << 0))
+		pgsel |= RTL8306_REG_PAGE_LO;
+	if (!(page & (1 << 1))) /* bit is inverted */
+		pgsel |= RTL8306_REG_PAGE_HI;
+	bus->write(bus, 0, RTL8306_REG_PAGE, pgsel);
+}
+
+static inline int
+rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct mii_bus *bus = priv->bus;
+
+	rtl_set_page(priv, page);
+	bus->write(bus, phy, reg, val);
+	bus->read(bus, phy, reg); /* flush */
+	return 0;
+}
+
+static inline int
+rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct mii_bus *bus = priv->bus;
+
+	rtl_set_page(priv, page);
+	return bus->read(bus, phy, reg);
+}
+
+static inline u16
+rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct mii_bus *bus = priv->bus;
+	u16 r;
+
+	rtl_set_page(priv, page);
+	r = bus->read(bus, phy, reg);
+	r &= ~mask;
+	r |= val;
+	bus->write(bus, phy, reg, r);
+	return bus->read(bus, phy, reg); /* flush */
+}
+
+
+static inline int
+rtl_get(struct switch_dev *dev, enum rtl_regidx s)
+{
+	const struct rtl_reg *r = &rtl_regs[s];
+	u16 val;
+
+	BUG_ON(s >= ARRAY_SIZE(rtl_regs));
+	if (r->bits == 0) /* unimplemented */
+		return 0;
+
+	val = rtl_r16(dev, r->page, r->phy, r->reg);
+
+	if (r->shift > 0)
+		val >>= r->shift;
+
+	if (r->inverted)
+		val = ~val;
+
+	val &= (1 << r->bits) - 1;
+
+	return val;
+}
+
+static int
+rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val)
+{
+	const struct rtl_reg *r = &rtl_regs[s];
+	u16 mask = 0xffff;
+
+	BUG_ON(s >= ARRAY_SIZE(rtl_regs));
+
+	if (r->bits == 0) /* unimplemented */
+		return 0;
+
+	if (r->shift > 0)
+		val <<= r->shift;
+
+	if (r->inverted)
+		val = ~val;
+
+	if (r->bits != 16) {
+		mask = (1 << r->bits) - 1;
+		mask <<= r->shift;
+	}
+	val &= mask;
+	return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val);
+}
+
+static void
+rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs)
+{
+	regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY));
+	regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED));
+	regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX));
+}
+
+static void
+rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs)
+{
+	rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway);
+	rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed);
+	rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex);
+}
+
+static void
+rtl_port_set_enable(struct switch_dev *dev, int port, int enabled)
+{
+	rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled);
+	rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled);
+
+	if ((port >= 5) || !enabled)
+		return;
+
+	/* restart autonegotiation if enabled */
+	rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1);
+}
+
+static int
+rtl_hw_apply(struct switch_dev *dev)
+{
+	int i;
+	int trunk_en, trunk_psel;
+	struct rtl_phyregs port5;
+
+	rtl_phy_save(dev, 5, &port5);
+
+	/* disable rx/tx from PHYs */
+	for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) {
+		rtl_port_set_enable(dev, i, 0);
+	}
+
+	/* save trunking status */
+	trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK);
+	trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL);
+
+	/* trunk port 3 and 4
+	 * XXX: Big WTF, but RealTek seems to do it */
+	rtl_set(dev, RTL_REG_EN_TRUNK, 1);
+	rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1);
+
+	/* execute the software reset */
+	rtl_set(dev, RTL_REG_RESET, 1);
+
+	/* wait for the reset to complete,
+	 * but don't wait for too long */
+	for (i = 0; i < 10; i++) {
+		if (rtl_get(dev, RTL_REG_RESET) == 0)
+			break;
+
+		msleep(1);
+	}
+
+	/* enable rx/tx from PHYs */
+	for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) {
+		rtl_port_set_enable(dev, i, 1);
+	}
+
+	/* restore trunking settings */
+	rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en);
+	rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel);
+	rtl_phy_restore(dev, 5, &port5);
+
+	rtl_set(dev, RTL_REG_CPU_LINKUP, 1);
+
+	return 0;
+}
+
+static void
+rtl_hw_init(struct switch_dev *dev)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	int cpu_mask = 1 << dev->cpu_port;
+	int i;
+
+	rtl_set(dev, RTL_REG_VLAN_ENABLE, 0);
+	rtl_set(dev, RTL_REG_VLAN_FILTER, 0);
+	rtl_set(dev, RTL_REG_EN_TRUNK, 0);
+	rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0);
+
+	/* initialize cpu port settings */
+	if (priv->do_cpu) {
+		rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port);
+		rtl_set(dev, RTL_REG_EN_CPUPORT, 1);
+	} else {
+		rtl_set(dev, RTL_REG_CPUPORT, 7);
+		rtl_set(dev, RTL_REG_EN_CPUPORT, 0);
+	}
+	rtl_set(dev, RTL_REG_EN_TAG_OUT, 0);
+	rtl_set(dev, RTL_REG_EN_TAG_IN, 0);
+	rtl_set(dev, RTL_REG_EN_TAG_CLR, 0);
+
+	/* reset all vlans */
+	for (i = 0; i < RTL8306_NUM_VLANS; i++) {
+		rtl_set(dev, RTL_VLAN_REG(i, VID), i);
+		rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0);
+	}
+
+	/* default to port isolation */
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		unsigned long mask;
+
+		if ((1 << i) == cpu_mask)
+			mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */
+		else
+			mask = cpu_mask | (1 << i);
+
+		rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask);
+		rtl_set(dev, RTL_PORT_REG(i, PVID), i);
+		rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1);
+		rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1);
+		rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3);
+	}
+	rtl_hw_apply(dev);
+}
+
+#ifdef DEBUG
+static int
+rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	priv->do_cpu = val->value.i;
+	rtl_hw_init(dev);
+	return 0;
+}
+
+static int
+rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	val->value.i = priv->do_cpu;
+	return 0;
+}
+
+static int
+rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	dev->cpu_port = val->value.i;
+	rtl_hw_init(dev);
+	return 0;
+}
+
+static int
+rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	val->value.i = dev->cpu_port;
+	return 0;
+}
+#endif
+
+static int
+rtl_reset(struct switch_dev *dev)
+{
+	rtl_hw_init(dev);
+	return 0;
+}
+
+static int
+rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	int idx = attr->id + (val->port_vlan * attr->ofs);
+	struct rtl_phyregs port;
+
+	if (attr->id >= ARRAY_SIZE(rtl_regs))
+		return -EINVAL;
+
+	if ((attr->max > 0) && (val->value.i > attr->max))
+		return -EINVAL;
+
+	/* access to phy register 22 on port 4/5
+	 * needs phy status save/restore */
+	if ((val->port_vlan > 3) &&
+		(rtl_regs[idx].reg == 22) &&
+		(rtl_regs[idx].page == 0)) {
+
+		rtl_phy_save(dev, val->port_vlan, &port);
+		rtl_set(dev, idx, val->value.i);
+		rtl_phy_restore(dev, val->port_vlan, &port);
+	} else {
+		rtl_set(dev, idx, val->value.i);
+	}
+
+	return 0;
+}
+
+static int
+rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	int idx = attr->id + (val->port_vlan * attr->ofs);
+
+	if (idx >= ARRAY_SIZE(rtl_regs))
+		return -EINVAL;
+
+	val->value.i = rtl_get(dev, idx);
+	return 0;
+}
+
+static int
+rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= RTL8306_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl_attr_set_int(dev, attr, val);
+}
+
+static int
+rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= RTL8306_NUM_PORTS)
+		return -EINVAL;
+	return rtl_attr_get_int(dev, attr, val);
+}
+
+static int 
+rtl_get_port_link(struct switch_dev *dev, int port, struct switch_port_link *link)
+{
+	if (port >= RTL8306_NUM_PORTS)
+		return -EINVAL;
+
+	link->link = rtl_get(dev, RTL_PORT_REG(port, LINK));
+	if (!link->link)
+		return 0;
+
+	link->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX));
+	link->aneg = rtl_get(dev, RTL_PORT_REG(port, NWAY));
+
+	if (rtl_get(dev, RTL_PORT_REG(port, SPEED)))
+		link->speed = SWITCH_PORT_SPEED_100;
+	else
+		link->speed = SWITCH_PORT_SPEED_10;
+
+	return 0;
+}
+
+static int
+rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	return rtl_attr_set_int(dev, attr, val);
+}
+
+static int
+rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	return rtl_attr_get_int(dev, attr, val);
+}
+
+static int
+rtl_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	unsigned int i, mask;
+
+	mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK));
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		struct switch_port *port;
+
+		if (!(mask & (1 << i)))
+			continue;
+
+		port = &val->value.ports[val->len];
+		port->id = i;
+		if (rtl_get(dev, RTL_PORT_REG(i, TAG_INSERT)) == 2 || i == dev->cpu_port)
+			port->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+	}
+
+	return 0;
+}
+
+static int
+rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct rtl_phyregs port;
+	int en = val->value.i;
+	int i;
+
+	rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu);
+	rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu);
+	rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu);
+	rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en);
+	if (en)
+		rtl_set(dev, RTL_REG_VLAN_FILTER, en);
+
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		if (i > 3)
+			rtl_phy_save(dev, val->port_vlan, &port);
+		rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1);
+		rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1));
+		rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3));
+		if (i > 3)
+			rtl_phy_restore(dev, val->port_vlan, &port);
+	}
+	rtl_set(dev, RTL_REG_VLAN_ENABLE, en);
+
+	return 0;
+}
+
+static int
+rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	val->value.i = rtl_get(dev, RTL_REG_VLAN_ENABLE);
+	return 0;
+}
+
+static int
+rtl_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	unsigned int mask = 0;
+	unsigned int oldmask;
+	int i;
+
+	for(i = 0; i < val->len; i++)
+	{
+		struct switch_port *port = &val->value.ports[i];
+		bool tagged = false;
+
+		mask |= (1 << port->id);
+
+		if (port->id == dev->cpu_port)
+			continue;
+
+		if ((i == dev->cpu_port) ||
+			(port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
+			tagged = true;
+
+		/* fix up PVIDs for added ports */
+		if (!tagged)
+			rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan);
+
+		rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1));
+		rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1));
+		rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1));
+	}
+
+	oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK));
+	rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask);
+
+	/* fix up PVIDs for removed ports, default to last vlan */
+	oldmask &= ~mask;
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		if (!(oldmask & (1 << i)))
+			continue;
+
+		if (i == dev->cpu_port)
+			continue;
+
+		if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan)
+			rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1);
+	}
+
+	return 0;
+}
+
+static struct switch_attr rtl_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.max = 1,
+		.set = rtl_set_vlan,
+		.get = rtl_get_vlan,
+	},
+	{
+		RTL_GLOBAL_REGATTR(EN_TRUNK),
+		.name = "trunk",
+		.description = "Enable port trunking",
+		.max = 1,
+	},
+	{
+		RTL_GLOBAL_REGATTR(TRUNK_PORTSEL),
+		.name = "trunk_sel",
+		.description = "Select ports for trunking (0: 0,1 - 1: 3,4)",
+		.max = 1,
+	},
+#ifdef DEBUG
+	{
+		RTL_GLOBAL_REGATTR(VLAN_FILTER),
+		.name = "vlan_filter",
+		.description = "Filter incoming packets for allowed VLANS",
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "cpuport",
+		.description = "CPU Port",
+		.set = rtl_set_cpuport,
+		.get = rtl_get_cpuport,
+		.max = RTL8306_NUM_PORTS,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "use_cpuport",
+		.description = "CPU Port handling flag",
+		.set = rtl_set_use_cpuport,
+		.get = rtl_get_use_cpuport,
+		.max = RTL8306_NUM_PORTS,
+	},
+	{
+		RTL_GLOBAL_REGATTR(TRAP_CPU),
+		.name = "trap_cpu",
+		.description = "VLAN trap to CPU",
+		.max = 1,
+	},
+	{
+		RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE),
+		.name = "vlan_tag_aware",
+		.description = "Enable VLAN tag awareness",
+		.max = 1,
+	},
+	{
+		RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY),
+		.name = "tag_only",
+		.description = "Only accept tagged packets",
+		.max = 1,
+	},
+#endif
+};
+static struct switch_attr rtl_port[] = {
+	{
+		RTL_PORT_REGATTR(PVID),
+		.name = "pvid",
+		.description = "Port VLAN ID",
+		.max = RTL8306_NUM_VLANS - 1,
+	},
+#ifdef DEBUG
+	{
+		RTL_PORT_REGATTR(NULL_VID_REPLACE),
+		.name = "null_vid",
+		.description = "NULL VID gets replaced by port default vid",
+		.max = 1,
+	},
+	{
+		RTL_PORT_REGATTR(NON_PVID_DISCARD),
+		.name = "non_pvid_discard",
+		.description = "discard packets with VID != PVID",
+		.max = 1,
+	},
+	{
+		RTL_PORT_REGATTR(VID_INSERT),
+		.name = "vid_insert_remove",
+		.description = "how should the switch insert and remove vids ?",
+		.max = 3,
+	},
+	{
+		RTL_PORT_REGATTR(TAG_INSERT),
+		.name = "tag_insert",
+		.description = "tag insertion handling",
+		.max = 3,
+	},
+#endif
+};
+
+static struct switch_attr rtl_vlan[] = {
+	{
+		RTL_VLAN_REGATTR(VID),
+		.name = "vid",
+		.description = "VLAN ID (1-4095)",
+		.max = 4095,
+	},
+};
+
+static const struct switch_dev_ops rtl8306_ops = {
+	.attr_global = {
+		.attr = rtl_globals,
+		.n_attr = ARRAY_SIZE(rtl_globals),
+	},
+	.attr_port = {
+		.attr = rtl_port,
+		.n_attr = ARRAY_SIZE(rtl_port),
+	},
+	.attr_vlan = {
+		.attr = rtl_vlan,
+		.n_attr = ARRAY_SIZE(rtl_vlan),
+	},
+
+	.get_vlan_ports = rtl_get_ports,
+	.set_vlan_ports = rtl_set_ports,
+	.apply_config = rtl_hw_apply,
+	.reset_switch = rtl_reset,
+	.get_port_link = rtl_get_port_link,
+};
+
+static int
+rtl8306_config_init(struct phy_device *pdev)
+{
+	struct net_device *netdev = pdev->attached_dev;
+	struct rtl_priv *priv = pdev->priv;
+	struct switch_dev *dev = &priv->dev;
+	struct switch_val val;
+	unsigned int chipid, chipver, chiptype;
+	int err;
+
+	/* Only init the switch for the primary PHY */
+	if (pdev->addr != 0)
+		return 0;
+
+	val.value.i = 1;
+	priv->dev.cpu_port = RTL8306_PORT_CPU;
+	priv->dev.ports = RTL8306_NUM_PORTS;
+	priv->dev.vlans = RTL8306_NUM_VLANS;
+	priv->dev.ops = &rtl8306_ops;
+	priv->do_cpu = 0;
+	priv->page = -1;
+	priv->bus = pdev->bus;
+
+	chipid = rtl_get(dev, RTL_REG_CHIPID);
+	chipver = rtl_get(dev, RTL_REG_CHIPVER);
+	chiptype = rtl_get(dev, RTL_REG_CHIPTYPE);
+	switch(chiptype) {
+	case 0:
+	case 2:
+		strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname));
+		priv->type = RTL_TYPE_S;
+		break;
+	case 1:
+		strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname));
+		priv->type = RTL_TYPE_SD;
+		break;
+	case 3:
+		strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname));
+		priv->type = RTL_TYPE_SDM;
+		break;
+	default:
+		strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname));
+		break;
+	}
+
+	dev->name = priv->hwname;
+	rtl_hw_init(dev);
+
+	printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver);
+
+	err = register_switch(dev, netdev);
+	if (err < 0) {
+		kfree(priv);
+		return err;
+	}
+
+	return 0;
+}
+
+
+static int
+rtl8306_fixup(struct phy_device *pdev)
+{
+	struct rtl_priv priv;
+	u16 chipid;
+
+	/* Attach to primary LAN port and WAN port */
+	if (pdev->addr != 0 && pdev->addr != 4)
+		return 0;
+
+	memset(&priv, 0, sizeof(priv));
+	priv.fixup = true;
+	priv.page = -1;
+	priv.bus = pdev->bus;
+	chipid = rtl_get(&priv.dev, RTL_REG_CHIPID);
+	if (chipid == 0x5988)
+		pdev->phy_id = RTL8306_MAGIC;
+
+	return 0;
+}
+
+static int
+rtl8306_probe(struct phy_device *pdev)
+{
+	struct rtl_priv *priv;
+
+	list_for_each_entry(priv, &phydevs, list) {
+		/*
+		 * share one rtl_priv instance between virtual phy
+		 * devices on the same bus
+		 */
+		if (priv->bus == pdev->bus)
+			goto found;
+	}
+	priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->bus = pdev->bus;
+
+found:
+	pdev->priv = priv;
+	return 0;
+}
+
+static void
+rtl8306_remove(struct phy_device *pdev)
+{
+	struct rtl_priv *priv = pdev->priv;
+	unregister_switch(&priv->dev);
+	kfree(priv);
+}
+
+static int
+rtl8306_config_aneg(struct phy_device *pdev)
+{
+	struct rtl_priv *priv = pdev->priv;
+
+	/* Only for WAN */
+	if (pdev->addr == 0)
+		return 0;
+
+	/* Restart autonegotiation */
+	rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1);
+	rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1);
+
+	return 0;
+}
+
+static int
+rtl8306_read_status(struct phy_device *pdev)
+{
+	struct rtl_priv *priv = pdev->priv;
+	struct switch_dev *dev = &priv->dev;
+
+	if (pdev->addr == 4) {
+		/* WAN */
+		pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10;
+		pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF;
+		pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK));
+	} else {
+		/* LAN */
+		pdev->speed = SPEED_100;
+		pdev->duplex = DUPLEX_FULL;
+		pdev->link = 1;
+	}
+
+	/*
+	 * Bypass generic PHY status read,
+	 * it doesn't work with this switch
+	 */
+	if (pdev->link) {
+		pdev->state = PHY_RUNNING;
+		netif_carrier_on(pdev->attached_dev);
+		pdev->adjust_link(pdev->attached_dev);
+	} else {
+		pdev->state = PHY_NOLINK;
+		netif_carrier_off(pdev->attached_dev);
+		pdev->adjust_link(pdev->attached_dev);
+	}
+
+	return 0;
+}
+
+
+static struct phy_driver rtl8306_driver = {
+	.name		= "Realtek RTL8306S",
+	.flags		= PHY_HAS_MAGICANEG,
+	.phy_id		= RTL8306_MAGIC,
+	.phy_id_mask	= 0xffffffff,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= &rtl8306_probe,
+	.remove		= &rtl8306_remove,
+	.config_init	= &rtl8306_config_init,
+	.config_aneg	= &rtl8306_config_aneg,
+	.read_status	= &rtl8306_read_status,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+
+static int __init
+rtl_init(void)
+{
+	phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup);
+	return phy_driver_register(&rtl8306_driver);
+}
+
+static void __exit
+rtl_exit(void)
+{
+	phy_driver_unregister(&rtl8306_driver);
+}
+
+module_init(rtl_init);
+module_exit(rtl_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
new file mode 100644
index 0000000000..699234d22d
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
@@ -0,0 +1,1449 @@
+/*
+ * Realtek RTL8366 SMI interface driver
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/rtl8366.h>
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#include "rtl8366_smi.h"
+
+#define RTL8366_SMI_ACK_RETRY_COUNT         5
+
+#define RTL8366_SMI_HW_STOP_DELAY		25	/* msecs */
+#define RTL8366_SMI_HW_START_DELAY		100	/* msecs */
+
+static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi)
+{
+	ndelay(smi->clk_delay);
+}
+
+static void rtl8366_smi_start(struct rtl8366_smi *smi)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	/*
+	 * Set GPIO pins to output mode, with initial state:
+	 * SCK = 0, SDA = 1
+	 */
+	gpio_direction_output(sck, 0);
+	gpio_direction_output(sda, 1);
+	rtl8366_smi_clk_delay(smi);
+
+	/* CLK 1: 0 -> 1, 1 -> 0 */
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+
+	/* CLK 2: */
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 1);
+}
+
+static void rtl8366_smi_stop(struct rtl8366_smi *smi)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 0);
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 1);
+
+	/* add a click */
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 1);
+
+	/* set GPIO pins to input mode */
+	gpio_direction_input(sda);
+	gpio_direction_input(sck);
+}
+
+static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	for (; len > 0; len--) {
+		rtl8366_smi_clk_delay(smi);
+
+		/* prepare data */
+		gpio_set_value(sda, !!(data & ( 1 << (len - 1))));
+		rtl8366_smi_clk_delay(smi);
+
+		/* clocking */
+		gpio_set_value(sck, 1);
+		rtl8366_smi_clk_delay(smi);
+		gpio_set_value(sck, 0);
+	}
+}
+
+static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	gpio_direction_input(sda);
+
+	for (*data = 0; len > 0; len--) {
+		u32 u;
+
+		rtl8366_smi_clk_delay(smi);
+
+		/* clocking */
+		gpio_set_value(sck, 1);
+		rtl8366_smi_clk_delay(smi);
+		u = !!gpio_get_value(sda);
+		gpio_set_value(sck, 0);
+
+		*data |= (u << (len - 1));
+	}
+
+	gpio_direction_output(sda, 0);
+}
+
+static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi)
+{
+	int retry_cnt;
+
+	retry_cnt = 0;
+	do {
+		u32 ack;
+
+		rtl8366_smi_read_bits(smi, 1, &ack);
+		if (ack == 0)
+			break;
+
+		if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) {
+			dev_err(smi->parent, "ACK timeout\n");
+			return -ETIMEDOUT;
+		}
+	} while (1);
+
+	return 0;
+}
+
+static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data)
+{
+	rtl8366_smi_write_bits(smi, data, 8);
+	return rtl8366_smi_wait_for_ack(smi);
+}
+
+static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data)
+{
+	rtl8366_smi_write_bits(smi, data, 8);
+	return 0;
+}
+
+static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data)
+{
+	u32 t;
+
+	/* read data */
+	rtl8366_smi_read_bits(smi, 8, &t);
+	*data = (t & 0xff);
+
+	/* send an ACK */
+	rtl8366_smi_write_bits(smi, 0x00, 1);
+
+	return 0;
+}
+
+static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data)
+{
+	u32 t;
+
+	/* read data */
+	rtl8366_smi_read_bits(smi, 8, &t);
+	*data = (t & 0xff);
+
+	/* send an ACK */
+	rtl8366_smi_write_bits(smi, 0x01, 1);
+
+	return 0;
+}
+
+int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+{
+	unsigned long flags;
+	u8 lo = 0;
+	u8 hi = 0;
+	int ret;
+
+	spin_lock_irqsave(&smi->lock, flags);
+
+	rtl8366_smi_start(smi);
+
+	/* send READ command */
+	ret = rtl8366_smi_write_byte(smi, smi->cmd_read);
+	if (ret)
+		goto out;
+
+	/* set ADDR[7:0] */
+	ret = rtl8366_smi_write_byte(smi, addr & 0xff);
+	if (ret)
+		goto out;
+
+	/* set ADDR[15:8] */
+	ret = rtl8366_smi_write_byte(smi, addr >> 8);
+	if (ret)
+		goto out;
+
+	/* read DATA[7:0] */
+	rtl8366_smi_read_byte0(smi, &lo);
+	/* read DATA[15:8] */
+	rtl8366_smi_read_byte1(smi, &hi);
+
+	*data = ((u32) lo) | (((u32) hi) << 8);
+
+	ret = 0;
+
+ out:
+	rtl8366_smi_stop(smi);
+	spin_unlock_irqrestore(&smi->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg);
+
+static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi,
+				   u32 addr, u32 data, bool ack)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&smi->lock, flags);
+
+	rtl8366_smi_start(smi);
+
+	/* send WRITE command */
+	ret = rtl8366_smi_write_byte(smi, smi->cmd_write);
+	if (ret)
+		goto out;
+
+	/* set ADDR[7:0] */
+	ret = rtl8366_smi_write_byte(smi, addr & 0xff);
+	if (ret)
+		goto out;
+
+	/* set ADDR[15:8] */
+	ret = rtl8366_smi_write_byte(smi, addr >> 8);
+	if (ret)
+		goto out;
+
+	/* write DATA[7:0] */
+	ret = rtl8366_smi_write_byte(smi, data & 0xff);
+	if (ret)
+		goto out;
+
+	/* write DATA[15:8] */
+	if (ack)
+		ret = rtl8366_smi_write_byte(smi, data >> 8);
+	else
+		ret = rtl8366_smi_write_byte_noack(smi, data >> 8);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+ out:
+	rtl8366_smi_stop(smi);
+	spin_unlock_irqrestore(&smi->lock, flags);
+
+	return ret;
+}
+
+int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data)
+{
+	return __rtl8366_smi_write_reg(smi, addr, data, true);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg);
+
+int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data)
+{
+	return __rtl8366_smi_write_reg(smi, addr, data, false);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack);
+
+int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data)
+{
+	u32 t;
+	int err;
+
+	err = rtl8366_smi_read_reg(smi, addr, &t);
+	if (err)
+		return err;
+
+	err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data);
+	return err;
+
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr);
+
+static int rtl8366_reset(struct rtl8366_smi *smi)
+{
+	if (smi->hw_reset) {
+		smi->hw_reset(true);
+		msleep(RTL8366_SMI_HW_STOP_DELAY);
+		smi->hw_reset(false);
+		msleep(RTL8366_SMI_HW_START_DELAY);
+		return 0;
+	}
+
+	return smi->ops->reset_chip(smi);
+}
+
+static int rtl8366_mc_is_used(struct rtl8366_smi *smi, int mc_index, int *used)
+{
+	int err;
+	int i;
+
+	*used = 0;
+	for (i = 0; i < smi->num_ports; i++) {
+		int index = 0;
+
+		err = smi->ops->get_mc_index(smi, i, &index);
+		if (err)
+			return err;
+
+		if (mc_index == index) {
+			*used = 1;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rtl8366_set_vlan(struct rtl8366_smi *smi, int vid, u32 member,
+			    u32 untag, u32 fid)
+{
+	struct rtl8366_vlan_4k vlan4k;
+	int err;
+	int i;
+
+	/* Update the 4K table */
+	err = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+	if (err)
+		return err;
+
+	vlan4k.member = member;
+	vlan4k.untag = untag;
+	vlan4k.fid = fid;
+	err = smi->ops->set_vlan_4k(smi, &vlan4k);
+	if (err)
+		return err;
+
+	/* Try to find an existing MC entry for this VID */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		struct rtl8366_vlan_mc vlanmc;
+
+		err = smi->ops->get_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+
+		if (vid == vlanmc.vid) {
+			/* update the MC entry */
+			vlanmc.member = member;
+			vlanmc.untag = untag;
+			vlanmc.fid = fid;
+
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			break;
+		}
+	}
+
+	return err;
+}
+
+static int rtl8366_get_pvid(struct rtl8366_smi *smi, int port, int *val)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	int err;
+	int index;
+
+	err = smi->ops->get_mc_index(smi, port, &index);
+	if (err)
+		return err;
+
+	err = smi->ops->get_vlan_mc(smi, index, &vlanmc);
+	if (err)
+		return err;
+
+	*val = vlanmc.vid;
+	return 0;
+}
+
+static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port,
+			    unsigned vid)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	struct rtl8366_vlan_4k vlan4k;
+	int err;
+	int i;
+
+	/* Try to find an existing MC entry for this VID */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		err = smi->ops->get_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+
+		if (vid == vlanmc.vid) {
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			if (err)
+				return err;
+
+			err = smi->ops->set_mc_index(smi, port, i);
+			return err;
+		}
+	}
+
+	/* We have no MC entry for this VID, try to find an empty one */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		err = smi->ops->get_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+
+		if (vlanmc.vid == 0 && vlanmc.member == 0) {
+			/* Update the entry from the 4K table */
+			err = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+			if (err)
+				return err;
+
+			vlanmc.vid = vid;
+			vlanmc.member = vlan4k.member;
+			vlanmc.untag = vlan4k.untag;
+			vlanmc.fid = vlan4k.fid;
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			if (err)
+				return err;
+
+			err = smi->ops->set_mc_index(smi, port, i);
+			return err;
+		}
+	}
+
+	/* MC table is full, try to find an unused entry and replace it */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		int used;
+
+		err = rtl8366_mc_is_used(smi, i, &used);
+		if (err)
+			return err;
+
+		if (!used) {
+			/* Update the entry from the 4K table */
+			err = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+			if (err)
+				return err;
+
+			vlanmc.vid = vid;
+			vlanmc.member = vlan4k.member;
+			vlanmc.untag = vlan4k.untag;
+			vlanmc.fid = vlan4k.fid;
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			if (err)
+				return err;
+
+			err = smi->ops->set_mc_index(smi, port, i);
+			return err;
+		}
+	}
+
+	dev_err(smi->parent,
+		"all VLAN member configurations are in use\n");
+
+	return -ENOSPC;
+}
+
+int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	int err;
+
+	err = smi->ops->enable_vlan(smi, enable);
+	if (err)
+		return err;
+
+	smi->vlan_enabled = enable;
+
+	if (!enable) {
+		smi->vlan4k_enabled = 0;
+		err = smi->ops->enable_vlan4k(smi, enable);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtl8366_enable_vlan);
+
+static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	int err;
+
+	if (enable) {
+		err = smi->ops->enable_vlan(smi, enable);
+		if (err)
+			return err;
+
+		smi->vlan_enabled = enable;
+	}
+
+	err = smi->ops->enable_vlan4k(smi, enable);
+	if (err)
+		return err;
+
+	smi->vlan4k_enabled = enable;
+	return 0;
+}
+
+int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable)
+{
+	int port;
+	int err;
+
+	for (port = 0; port < smi->num_ports; port++) {
+		err = smi->ops->enable_port(smi, port, enable);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports);
+
+int rtl8366_reset_vlan(struct rtl8366_smi *smi)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	int err;
+	int i;
+
+	rtl8366_enable_vlan(smi, 0);
+	rtl8366_enable_vlan4k(smi, 0);
+
+	/* clear VLAN member configurations */
+	vlanmc.vid = 0;
+	vlanmc.priority = 0;
+	vlanmc.member = 0;
+	vlanmc.untag = 0;
+	vlanmc.fid = 0;
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
+
+static int rtl8366_init_vlan(struct rtl8366_smi *smi)
+{
+	int port;
+	int err;
+
+	err = rtl8366_reset_vlan(smi);
+	if (err)
+		return err;
+
+	for (port = 0; port < smi->num_ports; port++) {
+		u32 mask;
+
+		if (port == smi->cpu_port)
+			mask = (1 << smi->num_ports) - 1;
+		else
+			mask = (1 << port) | (1 << smi->cpu_port);
+
+		err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0);
+		if (err)
+			return err;
+
+		err = rtl8366_set_pvid(smi, port, (port + 1));
+		if (err)
+			return err;
+	}
+
+	return rtl8366_enable_vlan(smi, 1);
+}
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+int rtl8366_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_debugfs_open);
+
+static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file,
+					      char __user *user_buf,
+					      size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	int i, len = 0;
+	char *buf = smi->buf;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"%2s %6s %4s %6s %6s %3s\n",
+			"id", "vid","prio", "member", "untag", "fid");
+
+	for (i = 0; i < smi->num_vlan_mc; ++i) {
+		struct rtl8366_vlan_mc vlanmc;
+
+		smi->ops->get_vlan_mc(smi, i, &vlanmc);
+
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%2d %6d %4d 0x%04x 0x%04x %3d\n",
+				i, vlanmc.vid, vlanmc.priority,
+				vlanmc.member, vlanmc.untag, vlanmc.fid);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+#define RTL8366_VLAN4K_PAGE_SIZE	64
+#define RTL8366_VLAN4K_NUM_PAGES	(4096 / RTL8366_VLAN4K_PAGE_SIZE)
+
+static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file,
+					    char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	int i, len = 0;
+	int offset;
+	char *buf = smi->buf;
+
+	if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) {
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"invalid page: %u\n", smi->dbg_vlan_4k_page);
+		return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	}
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"%4s %6s %6s %3s\n",
+			"vid", "member", "untag", "fid");
+
+	offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page;
+	for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) {
+		struct rtl8366_vlan_4k vlan4k;
+
+		smi->ops->get_vlan_4k(smi, offset + i, &vlan4k);
+
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%4d 0x%04x 0x%04x %3d\n",
+				vlan4k.vid, vlan4k.member,
+				vlan4k.untag, vlan4k.fid);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t rtl8366_read_debugfs_pvid(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	char *buf = smi->buf;
+	int len = 0;
+	int i;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len, "%4s %4s\n",
+			"port", "pvid");
+
+	for (i = 0; i < smi->num_ports; i++) {
+		int pvid;
+		int err;
+
+		err = rtl8366_get_pvid(smi, i, &pvid);
+		if (err)
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%4d error\n", i);
+		else
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%4d %4d\n", i, pvid);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t rtl8366_read_debugfs_reg(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	u32 t, reg = smi->dbg_reg;
+	int err, len = 0;
+	char *buf = smi->buf;
+
+	memset(buf, '\0', sizeof(smi->buf));
+
+	err = rtl8366_smi_read_reg(smi, reg, &t);
+	if (err) {
+		len += snprintf(buf, sizeof(smi->buf),
+				"Read failed (reg: 0x%04x)\n", reg);
+		return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	}
+
+	len += snprintf(buf, sizeof(smi->buf), "reg = 0x%04x, val = 0x%04x\n",
+			reg, t);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t rtl8366_write_debugfs_reg(struct file *file,
+					  const char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	unsigned long data;
+	u32 reg = smi->dbg_reg;
+	int err;
+	size_t len;
+	char *buf = smi->buf;
+
+	len = min(count, sizeof(smi->buf) - 1);
+	if (copy_from_user(buf, user_buf, len)) {
+		dev_err(smi->parent, "copy from user failed\n");
+		return -EFAULT;
+	}
+
+	buf[len] = '\0';
+	if (len > 0 && buf[len - 1] == '\n')
+		buf[len - 1] = '\0';
+
+
+	if (kstrtoul(buf, 16, &data)) {
+		dev_err(smi->parent, "Invalid reg value %s\n", buf);
+	} else {
+		err = rtl8366_smi_write_reg(smi, reg, data);
+		if (err) {
+			dev_err(smi->parent,
+				"writing reg 0x%04x val 0x%04lx failed\n",
+				reg, data);
+		}
+	}
+
+	return count;
+}
+
+static ssize_t rtl8366_read_debugfs_mibs(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = file->private_data;
+	int i, j, len = 0;
+	char *buf = smi->buf;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s",
+			"Counter");
+
+	for (i = 0; i < smi->num_ports; i++) {
+		char port_buf[10];
+
+		snprintf(port_buf, sizeof(port_buf), "Port %d", i);
+		len += snprintf(buf + len, sizeof(smi->buf) - len, " %12s",
+				port_buf);
+	}
+	len += snprintf(buf + len, sizeof(smi->buf) - len, "\n");
+
+	for (i = 0; i < smi->num_mib_counters; i++) {
+		len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s ",
+				smi->mib_counters[i].name);
+		for (j = 0; j < smi->num_ports; j++) {
+			unsigned long long counter = 0;
+
+			if (!smi->ops->get_mib_counter(smi, i, j, &counter))
+				len += snprintf(buf + len,
+						sizeof(smi->buf) - len,
+						"%12llu ", counter);
+			else
+				len += snprintf(buf + len,
+						sizeof(smi->buf) - len,
+						"%12s ", "error");
+		}
+		len += snprintf(buf + len, sizeof(smi->buf) - len, "\n");
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_rtl8366_regs = {
+	.read	= rtl8366_read_debugfs_reg,
+	.write	= rtl8366_write_debugfs_reg,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_vlan_mc = {
+	.read	= rtl8366_read_debugfs_vlan_mc,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_vlan_4k = {
+	.read	= rtl8366_read_debugfs_vlan_4k,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_pvid = {
+	.read	= rtl8366_read_debugfs_pvid,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_mibs = {
+	.read = rtl8366_read_debugfs_mibs,
+	.open = rtl8366_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+static void rtl8366_debugfs_init(struct rtl8366_smi *smi)
+{
+	struct dentry *node;
+	struct dentry *root;
+
+	if (!smi->debugfs_root)
+		smi->debugfs_root = debugfs_create_dir(dev_name(smi->parent),
+						       NULL);
+
+	if (!smi->debugfs_root) {
+		dev_err(smi->parent, "Unable to create debugfs dir\n");
+		return;
+	}
+	root = smi->debugfs_root;
+
+	node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root,
+				  &smi->dbg_reg);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"reg");
+		return;
+	}
+
+	node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, smi,
+				   &fops_rtl8366_regs);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"val");
+		return;
+	}
+
+	node = debugfs_create_file("vlan_mc", S_IRUSR, root, smi,
+				   &fops_rtl8366_vlan_mc);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"vlan_mc");
+		return;
+	}
+
+	node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root,
+				  &smi->dbg_vlan_4k_page);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"vlan_4k_page");
+		return;
+	}
+
+	node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi,
+				   &fops_rtl8366_vlan_4k);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"vlan_4k");
+		return;
+	}
+
+	node = debugfs_create_file("pvid", S_IRUSR, root, smi,
+				   &fops_rtl8366_pvid);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"pvid");
+		return;
+	}
+
+	node = debugfs_create_file("mibs", S_IRUSR, smi->debugfs_root, smi,
+				   &fops_rtl8366_mibs);
+	if (!node)
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"mibs");
+}
+
+static void rtl8366_debugfs_remove(struct rtl8366_smi *smi)
+{
+	if (smi->debugfs_root) {
+		debugfs_remove_recursive(smi->debugfs_root);
+		smi->debugfs_root = NULL;
+	}
+}
+#else
+static inline void rtl8366_debugfs_init(struct rtl8366_smi *smi) {}
+static inline void rtl8366_debugfs_remove(struct rtl8366_smi *smi) {}
+#endif /* CONFIG_RTL8366_SMI_DEBUG_FS */
+
+static int rtl8366_smi_mii_init(struct rtl8366_smi *smi)
+{
+	int ret;
+	int i;
+
+	smi->mii_bus = mdiobus_alloc();
+	if (smi->mii_bus == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	smi->mii_bus->priv = (void *) smi;
+	smi->mii_bus->name = dev_name(smi->parent);
+	smi->mii_bus->read = smi->ops->mii_read;
+	smi->mii_bus->write = smi->ops->mii_write;
+	snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s",
+		 dev_name(smi->parent));
+	smi->mii_bus->parent = smi->parent;
+	smi->mii_bus->phy_mask = ~(0x1f);
+	smi->mii_bus->irq = smi->mii_irq;
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		smi->mii_irq[i] = PHY_POLL;
+
+	ret = mdiobus_register(smi->mii_bus);
+	if (ret)
+		goto err_free;
+
+	return 0;
+
+ err_free:
+	mdiobus_free(smi->mii_bus);
+ err:
+	return ret;
+}
+
+static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi)
+{
+	mdiobus_unregister(smi->mii_bus);
+	mdiobus_free(smi->mii_bus);
+}
+
+int rtl8366_sw_reset_switch(struct switch_dev *dev)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	err = rtl8366_reset(smi);
+	if (err)
+		return err;
+
+	err = smi->ops->setup(smi);
+	if (err)
+		return err;
+
+	err = rtl8366_reset_vlan(smi);
+	if (err)
+		return err;
+
+	err = rtl8366_enable_vlan(smi, 1);
+	if (err)
+		return err;
+
+	return rtl8366_enable_all_ports(smi, 1);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch);
+
+int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	return rtl8366_get_pvid(smi, port, val);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_pvid);
+
+int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	return rtl8366_set_pvid(smi, port, val);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_port_pvid);
+
+int rtl8366_sw_get_port_mib(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int i, len = 0;
+	unsigned long long counter = 0;
+	char *buf = smi->buf;
+
+	if (val->port_vlan >= smi->num_ports)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"Port %d MIB counters\n",
+			val->port_vlan);
+
+	for (i = 0; i < smi->num_mib_counters; ++i) {
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%-36s: ", smi->mib_counters[i].name);
+		if (!smi->ops->get_mib_counter(smi, i, val->port_vlan,
+					       &counter))
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+					"%llu\n", counter);
+		else
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+					"%s\n", "error");
+	}
+
+	val->value.s = buf;
+	val->len = len;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_mib);
+
+int rtl8366_sw_get_vlan_info(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val)
+{
+	int i;
+	u32 len = 0;
+	struct rtl8366_vlan_4k vlan4k;
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	char *buf = smi->buf;
+	int err;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	memset(buf, '\0', sizeof(smi->buf));
+
+	err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+	if (err)
+		return err;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"VLAN %d: Ports: '", vlan4k.vid);
+
+	for (i = 0; i < smi->num_ports; i++) {
+		if (!(vlan4k.member & (1 << i)))
+			continue;
+
+		len += snprintf(buf + len, sizeof(smi->buf) - len, "%d%s", i,
+				(vlan4k.untag & (1 << i)) ? "" : "t");
+	}
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"', members=%04x, untag=%04x, fid=%u",
+			vlan4k.member, vlan4k.untag, vlan4k.fid);
+
+	val->value.s = buf;
+	val->len = len;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_info);
+
+int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	struct switch_port *port;
+	struct rtl8366_vlan_4k vlan4k;
+	int i;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+
+	port = &val->value.ports[0];
+	val->len = 0;
+	for (i = 0; i < smi->num_ports; i++) {
+		if (!(vlan4k.member & BIT(i)))
+			continue;
+
+		port->id = i;
+		port->flags = (vlan4k.untag & BIT(i)) ?
+					0 : BIT(SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+		port++;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_ports);
+
+int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	struct switch_port *port;
+	u32 member = 0;
+	u32 untag = 0;
+	int err;
+	int i;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	port = &val->value.ports[0];
+	for (i = 0; i < val->len; i++, port++) {
+		int pvid = 0;
+		member |= BIT(port->id);
+
+		if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED)))
+			untag |= BIT(port->id);
+
+		/*
+		 * To ensure that we have a valid MC entry for this VLAN,
+		 * initialize the port VLAN ID here.
+		 */
+		err = rtl8366_get_pvid(smi, port->id, &pvid);
+		if (err < 0)
+			return err;
+		if (pvid == 0) {
+			err = rtl8366_set_pvid(smi, port->id, val->port_vlan);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports);
+
+int rtl8366_sw_get_vlan_fid(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct rtl8366_vlan_4k vlan4k;
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+	if (err)
+		return err;
+
+	val->value.i = vlan4k.fid;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid);
+
+int rtl8366_sw_set_vlan_fid(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct rtl8366_vlan_4k vlan4k;
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	if (val->value.i < 0 || val->value.i > attr->max)
+		return -EINVAL;
+
+	err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+	if (err)
+		return err;
+
+	return rtl8366_set_vlan(smi, val->port_vlan,
+				vlan4k.member,
+				vlan4k.untag,
+				val->value.i);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid);
+
+int rtl8366_sw_get_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (attr->ofs > 2)
+		return -EINVAL;
+
+	if (attr->ofs == 1)
+		val->value.i = smi->vlan_enabled;
+	else
+		val->value.i = smi->vlan4k_enabled;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_enable);
+
+int rtl8366_sw_set_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	if (attr->ofs > 2)
+		return -EINVAL;
+
+	if (attr->ofs == 1)
+		err = rtl8366_enable_vlan(smi, val->value.i);
+	else
+		err = rtl8366_enable_vlan4k(smi, val->value.i);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_enable);
+
+struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent)
+{
+	struct rtl8366_smi *smi;
+
+	BUG_ON(!parent);
+
+	smi = kzalloc(sizeof(*smi), GFP_KERNEL);
+	if (!smi) {
+		dev_err(parent, "no memory for private data\n");
+		return NULL;
+	}
+
+	smi->parent = parent;
+	return smi;
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_alloc);
+
+static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name)
+{
+	int err;
+
+	err = gpio_request(smi->gpio_sda, name);
+	if (err) {
+		printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
+			smi->gpio_sda, err);
+		goto err_out;
+	}
+
+	err = gpio_request(smi->gpio_sck, name);
+	if (err) {
+		printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
+			smi->gpio_sck, err);
+		goto err_free_sda;
+	}
+
+	spin_lock_init(&smi->lock);
+
+	/* start the switch */
+	if (smi->hw_reset) {
+		smi->hw_reset(false);
+		msleep(RTL8366_SMI_HW_START_DELAY);
+	}
+
+	return 0;
+
+ err_free_sda:
+	gpio_free(smi->gpio_sda);
+ err_out:
+	return err;
+}
+
+static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi)
+{
+	if (smi->hw_reset)
+		smi->hw_reset(true);
+
+	gpio_free(smi->gpio_sck);
+	gpio_free(smi->gpio_sda);
+}
+
+enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata)
+{
+	static struct rtl8366_smi smi;
+	enum rtl8366_type type = RTL8366_TYPE_UNKNOWN;
+	u32 reg = 0;
+
+	memset(&smi, 0, sizeof(smi));
+	smi.gpio_sda = pdata->gpio_sda;
+	smi.gpio_sck = pdata->gpio_sck;
+	smi.clk_delay = 10;
+	smi.cmd_read  = 0xa9;
+	smi.cmd_write = 0xa8;
+
+	if (__rtl8366_smi_init(&smi, "rtl8366"))
+		goto out;
+
+	if (rtl8366_smi_read_reg(&smi, 0x5c, &reg))
+		goto cleanup;
+
+	switch(reg) {
+	case 0x6027:
+		printk("Found an RTL8366S switch\n");
+		type = RTL8366_TYPE_S;
+		break;
+	case 0x5937:
+		printk("Found an RTL8366RB switch\n");
+		type = RTL8366_TYPE_RB;
+		break;
+	default:
+		printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg);
+		break;
+	}
+
+cleanup:
+	__rtl8366_smi_cleanup(&smi);
+out:
+	return type;
+}
+
+int rtl8366_smi_init(struct rtl8366_smi *smi)
+{
+	int err;
+
+	if (!smi->ops)
+		return -EINVAL;
+
+	err = __rtl8366_smi_init(smi, dev_name(smi->parent));
+	if (err)
+		goto err_out;
+
+	dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n",
+		 smi->gpio_sda, smi->gpio_sck);
+
+	err = smi->ops->detect(smi);
+	if (err) {
+		dev_err(smi->parent, "chip detection failed, err=%d\n", err);
+		goto err_free_sck;
+	}
+
+	err = rtl8366_reset(smi);
+	if (err)
+		goto err_free_sck;
+
+	err = smi->ops->setup(smi);
+	if (err) {
+		dev_err(smi->parent, "chip setup failed, err=%d\n", err);
+		goto err_free_sck;
+	}
+
+	err = rtl8366_init_vlan(smi);
+	if (err) {
+		dev_err(smi->parent, "VLAN initialization failed, err=%d\n",
+			err);
+		goto err_free_sck;
+	}
+
+	err = rtl8366_enable_all_ports(smi, 1);
+	if (err)
+		goto err_free_sck;
+
+	err = rtl8366_smi_mii_init(smi);
+	if (err)
+		goto err_free_sck;
+
+	rtl8366_debugfs_init(smi);
+
+	return 0;
+
+ err_free_sck:
+	__rtl8366_smi_cleanup(smi);
+ err_out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_init);
+
+void rtl8366_smi_cleanup(struct rtl8366_smi *smi)
+{
+	rtl8366_debugfs_remove(smi);
+	rtl8366_smi_mii_cleanup(smi);
+	__rtl8366_smi_cleanup(smi);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup);
+
+#ifdef CONFIG_OF
+int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
+{
+	int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0);
+	int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0);
+
+	if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) {
+		dev_err(&pdev->dev, "gpios missing in devictree\n");
+		return -EINVAL;
+	}
+
+	smi->gpio_sda = sda;
+	smi->gpio_sck = sck;
+
+	return 0;
+}
+#else
+static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
+{
+	return -ENODEV;
+}
+#endif
+
+int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi)
+{
+	struct rtl8366_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "no platform data specified\n");
+		return -EINVAL;
+	}
+
+	smi->gpio_sda = pdata->gpio_sda;
+	smi->gpio_sck = pdata->gpio_sck;
+	smi->hw_reset = pdata->hw_reset;
+
+	return 0;
+}
+
+
+struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi;
+	int err;
+
+	smi = rtl8366_smi_alloc(&pdev->dev);
+	if (!smi)
+		return NULL;
+
+	if (pdev->dev.of_node)
+		err = rtl8366_smi_probe_of(pdev, smi);
+	else
+		err = rtl8366_smi_probe_plat(pdev, smi);
+
+	if (err)
+		goto free_smi;
+
+	return smi;
+
+free_smi:
+	kfree(smi);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_probe);
+
+MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
new file mode 100644
index 0000000000..bd41385bed
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
@@ -0,0 +1,152 @@
+/*
+ * Realtek RTL8366 SMI interface driver defines
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ */
+
+#ifndef _RTL8366_SMI_H
+#define _RTL8366_SMI_H
+
+#include <linux/phy.h>
+#include <linux/switch.h>
+#include <linux/platform_device.h>
+
+struct rtl8366_smi_ops;
+struct rtl8366_vlan_ops;
+struct mii_bus;
+struct dentry;
+struct inode;
+struct file;
+
+struct rtl8366_mib_counter {
+	unsigned	base;
+	unsigned	offset;
+	unsigned	length;
+	const char	*name;
+};
+
+struct rtl8366_smi {
+	struct device		*parent;
+	unsigned int		gpio_sda;
+	unsigned int		gpio_sck;
+	void			(*hw_reset)(bool active);
+	unsigned int		clk_delay;	/* ns */
+	u8			cmd_read;
+	u8			cmd_write;
+	spinlock_t		lock;
+	struct mii_bus		*mii_bus;
+	int			mii_irq[PHY_MAX_ADDR];
+	struct switch_dev	sw_dev;
+
+	unsigned int		cpu_port;
+	unsigned int		num_ports;
+	unsigned int		num_vlan_mc;
+	unsigned int		num_mib_counters;
+	struct rtl8366_mib_counter *mib_counters;
+
+	struct rtl8366_smi_ops	*ops;
+
+	int			vlan_enabled;
+	int			vlan4k_enabled;
+
+	char			buf[4096];
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+	struct dentry           *debugfs_root;
+	u16			dbg_reg;
+	u8			dbg_vlan_4k_page;
+#endif
+};
+
+struct rtl8366_vlan_mc {
+	u16	vid;
+	u16	untag;
+	u16	member;
+	u8	fid;
+	u8	priority;
+};
+
+struct rtl8366_vlan_4k {
+	u16	vid;
+	u16	untag;
+	u16	member;
+	u8	fid;
+};
+
+struct rtl8366_smi_ops {
+	int	(*detect)(struct rtl8366_smi *smi);
+	int	(*reset_chip)(struct rtl8366_smi *smi);
+	int	(*setup)(struct rtl8366_smi *smi);
+
+	int	(*mii_read)(struct mii_bus *bus, int addr, int reg);
+	int	(*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val);
+
+	int	(*get_vlan_mc)(struct rtl8366_smi *smi, u32 index,
+			       struct rtl8366_vlan_mc *vlanmc);
+	int	(*set_vlan_mc)(struct rtl8366_smi *smi, u32 index,
+			       const struct rtl8366_vlan_mc *vlanmc);
+	int	(*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid,
+			       struct rtl8366_vlan_4k *vlan4k);
+	int	(*set_vlan_4k)(struct rtl8366_smi *smi,
+			       const struct rtl8366_vlan_4k *vlan4k);
+	int	(*get_mc_index)(struct rtl8366_smi *smi, int port, int *val);
+	int	(*set_mc_index)(struct rtl8366_smi *smi, int port, int index);
+	int	(*get_mib_counter)(struct rtl8366_smi *smi, int counter,
+				   int port, unsigned long long *val);
+	int	(*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan);
+	int	(*enable_vlan)(struct rtl8366_smi *smi, int enable);
+	int	(*enable_vlan4k)(struct rtl8366_smi *smi, int enable);
+	int	(*enable_port)(struct rtl8366_smi *smi, int port, int enable);
+};
+
+struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent);
+int rtl8366_smi_init(struct rtl8366_smi *smi);
+void rtl8366_smi_cleanup(struct rtl8366_smi *smi);
+int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data);
+int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data);
+int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data);
+int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data);
+
+int rtl8366_reset_vlan(struct rtl8366_smi *smi);
+int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable);
+int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable);
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+int rtl8366_debugfs_open(struct inode *inode, struct file *file);
+#endif
+
+static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw)
+{
+	return container_of(sw, struct rtl8366_smi, sw_dev);
+}
+
+int rtl8366_sw_reset_switch(struct switch_dev *dev);
+int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val);
+int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val);
+int rtl8366_sw_get_port_mib(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val);
+int rtl8366_sw_get_vlan_info(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val);
+int rtl8366_sw_get_vlan_fid(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val);
+int rtl8366_sw_set_vlan_fid(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val);
+int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val);
+int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val);
+int rtl8366_sw_get_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int rtl8366_sw_set_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+
+struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev);
+
+#endif /*  _RTL8366_SMI_H */
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c
new file mode 100644
index 0000000000..f4ec7483d6
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c
@@ -0,0 +1,1496 @@
+/*
+ * Platform driver for the Realtek RTL8366RB ethernet switch
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
+ * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
+ * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8366.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8366RB_DRIVER_DESC	"Realtek RTL8366RB ethernet switch driver"
+#define RTL8366RB_DRIVER_VER	"0.2.4"
+
+#define RTL8366RB_PHY_NO_MAX	4
+#define RTL8366RB_PHY_PAGE_MAX	7
+#define RTL8366RB_PHY_ADDR_MAX	31
+
+/* Switch Global Configuration register */
+#define RTL8366RB_SGCR				0x0000
+#define RTL8366RB_SGCR_EN_BC_STORM_CTRL		BIT(0)
+#define RTL8366RB_SGCR_MAX_LENGTH(_x)		(_x << 4)
+#define RTL8366RB_SGCR_MAX_LENGTH_MASK		RTL8366RB_SGCR_MAX_LENGTH(0x3)
+#define RTL8366RB_SGCR_MAX_LENGTH_1522		RTL8366RB_SGCR_MAX_LENGTH(0x0)
+#define RTL8366RB_SGCR_MAX_LENGTH_1536		RTL8366RB_SGCR_MAX_LENGTH(0x1)
+#define RTL8366RB_SGCR_MAX_LENGTH_1552		RTL8366RB_SGCR_MAX_LENGTH(0x2)
+#define RTL8366RB_SGCR_MAX_LENGTH_9216		RTL8366RB_SGCR_MAX_LENGTH(0x3)
+#define RTL8366RB_SGCR_EN_VLAN			BIT(13)
+#define RTL8366RB_SGCR_EN_VLAN_4KTB		BIT(14)
+
+/* Port Enable Control register */
+#define RTL8366RB_PECR				0x0001
+
+/* Port Mirror Control Register */
+#define RTL8366RB_PMCR				0x0007
+#define RTL8366RB_PMCR_SOURCE_PORT(_x)		(_x)
+#define RTL8366RB_PMCR_SOURCE_PORT_MASK		0x000f
+#define RTL8366RB_PMCR_MONITOR_PORT(_x)		((_x) << 4)
+#define RTL8366RB_PMCR_MONITOR_PORT_MASK	0x00f0
+#define RTL8366RB_PMCR_MIRROR_RX		BIT(8)
+#define RTL8366RB_PMCR_MIRROR_TX		BIT(9)
+#define RTL8366RB_PMCR_MIRROR_SPC		BIT(10)
+#define RTL8366RB_PMCR_MIRROR_ISO		BIT(11)
+
+/* Switch Security Control registers */
+#define RTL8366RB_SSCR0				0x0002
+#define RTL8366RB_SSCR1				0x0003
+#define RTL8366RB_SSCR2				0x0004
+#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA		BIT(0)
+
+#define RTL8366RB_RESET_CTRL_REG		0x0100
+#define RTL8366RB_CHIP_CTRL_RESET_HW		1
+#define RTL8366RB_CHIP_CTRL_RESET_SW		(1 << 1)
+
+#define RTL8366RB_CHIP_VERSION_CTRL_REG		0x050A
+#define RTL8366RB_CHIP_VERSION_MASK		0xf
+#define RTL8366RB_CHIP_ID_REG			0x0509
+#define RTL8366RB_CHIP_ID_8366			0x5937
+
+/* PHY registers control */
+#define RTL8366RB_PHY_ACCESS_CTRL_REG		0x8000
+#define RTL8366RB_PHY_ACCESS_DATA_REG		0x8002
+
+#define RTL8366RB_PHY_CTRL_READ			1
+#define RTL8366RB_PHY_CTRL_WRITE		0
+
+#define RTL8366RB_PHY_REG_MASK			0x1f
+#define RTL8366RB_PHY_PAGE_OFFSET		5
+#define RTL8366RB_PHY_PAGE_MASK			(0xf << 5)
+#define RTL8366RB_PHY_NO_OFFSET			9
+#define RTL8366RB_PHY_NO_MASK			(0x1f << 9)
+
+#define RTL8366RB_VLAN_INGRESS_CTRL2_REG	0x037f
+
+/* LED control registers */
+#define RTL8366RB_LED_BLINKRATE_REG		0x0430
+#define RTL8366RB_LED_BLINKRATE_BIT		0
+#define RTL8366RB_LED_BLINKRATE_MASK		0x0007
+
+#define RTL8366RB_LED_CTRL_REG			0x0431
+#define RTL8366RB_LED_0_1_CTRL_REG		0x0432
+#define RTL8366RB_LED_2_3_CTRL_REG		0x0433
+
+#define RTL8366RB_MIB_COUNT			33
+#define RTL8366RB_GLOBAL_MIB_COUNT		1
+#define RTL8366RB_MIB_COUNTER_PORT_OFFSET	0x0050
+#define RTL8366RB_MIB_COUNTER_BASE		0x1000
+#define RTL8366RB_MIB_CTRL_REG			0x13F0
+#define RTL8366RB_MIB_CTRL_USER_MASK		0x0FFC
+#define RTL8366RB_MIB_CTRL_BUSY_MASK		BIT(0)
+#define RTL8366RB_MIB_CTRL_RESET_MASK		BIT(1)
+#define RTL8366RB_MIB_CTRL_PORT_RESET(_p)	BIT(2 + (_p))
+#define RTL8366RB_MIB_CTRL_GLOBAL_RESET		BIT(11)
+
+#define RTL8366RB_PORT_VLAN_CTRL_BASE		0x0063
+#define RTL8366RB_PORT_VLAN_CTRL_REG(_p)  \
+		(RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4)
+#define RTL8366RB_PORT_VLAN_CTRL_MASK		0xf
+#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p)	(4 * ((_p) % 4))
+
+
+#define RTL8366RB_VLAN_TABLE_READ_BASE		0x018C
+#define RTL8366RB_VLAN_TABLE_WRITE_BASE		0x0185
+
+
+#define RTL8366RB_TABLE_ACCESS_CTRL_REG		0x0180
+#define RTL8366RB_TABLE_VLAN_READ_CTRL		0x0E01
+#define RTL8366RB_TABLE_VLAN_WRITE_CTRL		0x0F01
+
+#define RTL8366RB_VLAN_MC_BASE(_x)		(0x0020 + (_x) * 3)
+
+
+#define RTL8366RB_PORT_LINK_STATUS_BASE		0x0014
+#define RTL8366RB_PORT_STATUS_SPEED_MASK	0x0003
+#define RTL8366RB_PORT_STATUS_DUPLEX_MASK	0x0004
+#define RTL8366RB_PORT_STATUS_LINK_MASK		0x0010
+#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK	0x0020
+#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK	0x0040
+#define RTL8366RB_PORT_STATUS_AN_MASK		0x0080
+
+
+#define RTL8366RB_PORT_NUM_CPU		5
+#define RTL8366RB_NUM_PORTS		6
+#define RTL8366RB_NUM_VLANS		16
+#define RTL8366RB_NUM_LEDGROUPS		4
+#define RTL8366RB_NUM_VIDS		4096
+#define RTL8366RB_PRIORITYMAX		7
+#define RTL8366RB_FIDMAX		7
+
+
+#define RTL8366RB_PORT_1		(1 << 0) /* In userspace port 0 */
+#define RTL8366RB_PORT_2		(1 << 1) /* In userspace port 1 */
+#define RTL8366RB_PORT_3		(1 << 2) /* In userspace port 2 */
+#define RTL8366RB_PORT_4		(1 << 3) /* In userspace port 3 */
+#define RTL8366RB_PORT_5		(1 << 4) /* In userspace port 4 */
+
+#define RTL8366RB_PORT_CPU		(1 << 5) /* CPU port */
+
+#define RTL8366RB_PORT_ALL		(RTL8366RB_PORT_1 |	\
+					 RTL8366RB_PORT_2 |	\
+					 RTL8366RB_PORT_3 |	\
+					 RTL8366RB_PORT_4 |	\
+					 RTL8366RB_PORT_5 |	\
+					 RTL8366RB_PORT_CPU)
+
+#define RTL8366RB_PORT_ALL_BUT_CPU	(RTL8366RB_PORT_1 |	\
+					 RTL8366RB_PORT_2 |	\
+					 RTL8366RB_PORT_3 |	\
+					 RTL8366RB_PORT_4 |	\
+					 RTL8366RB_PORT_5)
+
+#define RTL8366RB_PORT_ALL_EXTERNAL	(RTL8366RB_PORT_1 |	\
+					 RTL8366RB_PORT_2 |	\
+					 RTL8366RB_PORT_3 |	\
+					 RTL8366RB_PORT_4)
+
+#define RTL8366RB_PORT_ALL_INTERNAL	 RTL8366RB_PORT_CPU
+
+#define RTL8366RB_VLAN_VID_MASK		0xfff
+#define RTL8366RB_VLAN_PRIORITY_SHIFT	12
+#define RTL8366RB_VLAN_PRIORITY_MASK	0x7
+#define RTL8366RB_VLAN_UNTAG_SHIFT	8
+#define RTL8366RB_VLAN_UNTAG_MASK	0xff
+#define RTL8366RB_VLAN_MEMBER_MASK	0xff
+#define RTL8366RB_VLAN_FID_MASK		0x7
+
+
+/* Port ingress bandwidth control */
+#define RTL8366RB_IB_BASE		0x0200
+#define RTL8366RB_IB_REG(pnum)		(RTL8366RB_IB_BASE + pnum)
+#define RTL8366RB_IB_BDTH_MASK		0x3fff
+#define RTL8366RB_IB_PREIFG_OFFSET	14
+#define RTL8366RB_IB_PREIFG_MASK	(1 << RTL8366RB_IB_PREIFG_OFFSET)
+
+/* Port egress bandwidth control */
+#define RTL8366RB_EB_BASE		0x02d1
+#define RTL8366RB_EB_REG(pnum)		(RTL8366RB_EB_BASE + pnum)
+#define RTL8366RB_EB_BDTH_MASK		0x3fff
+#define RTL8366RB_EB_PREIFG_REG	0x02f8
+#define RTL8366RB_EB_PREIFG_OFFSET	9
+#define RTL8366RB_EB_PREIFG_MASK	(1 << RTL8366RB_EB_PREIFG_OFFSET)
+
+#define RTL8366RB_BDTH_SW_MAX		1048512
+#define RTL8366RB_BDTH_UNIT		64
+#define RTL8366RB_BDTH_REG_DEFAULT	16383
+
+/* QOS */
+#define RTL8366RB_QOS_BIT		15
+#define RTL8366RB_QOS_MASK		(1 << RTL8366RB_QOS_BIT)
+/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */
+#define RTL8366RB_QOS_DEFAULT_PREIFG	1
+
+
+static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
+	{ 0,  0, 4, "IfInOctets"				},
+	{ 0,  4, 4, "EtherStatsOctets"				},
+	{ 0,  8, 2, "EtherStatsUnderSizePkts"			},
+	{ 0, 10, 2, "EtherFragments"				},
+	{ 0, 12, 2, "EtherStatsPkts64Octets"			},
+	{ 0, 14, 2, "EtherStatsPkts65to127Octets"		},
+	{ 0, 16, 2, "EtherStatsPkts128to255Octets"		},
+	{ 0, 18, 2, "EtherStatsPkts256to511Octets"		},
+	{ 0, 20, 2, "EtherStatsPkts512to1023Octets"		},
+	{ 0, 22, 2, "EtherStatsPkts1024to1518Octets"		},
+	{ 0, 24, 2, "EtherOversizeStats"			},
+	{ 0, 26, 2, "EtherStatsJabbers"				},
+	{ 0, 28, 2, "IfInUcastPkts"				},
+	{ 0, 30, 2, "EtherStatsMulticastPkts"			},
+	{ 0, 32, 2, "EtherStatsBroadcastPkts"			},
+	{ 0, 34, 2, "EtherStatsDropEvents"			},
+	{ 0, 36, 2, "Dot3StatsFCSErrors"			},
+	{ 0, 38, 2, "Dot3StatsSymbolErrors"			},
+	{ 0, 40, 2, "Dot3InPauseFrames"				},
+	{ 0, 42, 2, "Dot3ControlInUnknownOpcodes"		},
+	{ 0, 44, 4, "IfOutOctets"				},
+	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
+	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
+	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
+	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
+	{ 0, 56, 2, "EtherStatsCollisions"			},
+	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
+	{ 0, 60, 2, "Dot3OutPauseFrames"			},
+	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
+	{ 0, 64, 2, "Dot1dTpPortInDiscards"			},
+	{ 0, 66, 2, "IfOutUcastPkts"				},
+	{ 0, 68, 2, "IfOutMulticastPkts"			},
+	{ 0, 70, 2, "IfOutBroadcastPkts"			},
+};
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static int rtl8366rb_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	u32 data;
+
+	rtl8366_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG,
+			 	    RTL8366RB_CHIP_CTRL_RESET_HW);
+	do {
+		msleep(1);
+		if (rtl8366_smi_read_reg(smi, RTL8366RB_RESET_CTRL_REG, &data))
+			return -EIO;
+
+		if (!(data & RTL8366RB_CHIP_CTRL_RESET_HW))
+			break;
+	} while (--timeout);
+
+	if (!timeout) {
+		printk("Timeout waiting for the switch to reset\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int rtl8366rb_setup(struct rtl8366_smi *smi)
+{
+	int err;
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_MAX_LENGTH_MASK,
+		RTL8366RB_SGCR_MAX_LENGTH_1536);
+
+	/* enable learning for all ports */
+	REG_WR(smi, RTL8366RB_SSCR0, 0);
+
+	/* enable auto ageing for all ports */
+	REG_WR(smi, RTL8366RB_SSCR1, 0);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8366RB_VLAN_INGRESS_CTRL2_REG, RTL8366RB_PORT_ALL);
+
+	/* don't drop packets whose DA has not been learned */
+	REG_RMW(smi, RTL8366RB_SSCR2, RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0);
+
+	return 0;
+}
+
+static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_no, u32 page, u32 addr, u32 *data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366RB_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366RB_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366RB_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG,
+				    RTL8366RB_PHY_CTRL_READ);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) |
+	      ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) |
+	      (addr & RTL8366RB_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, 0);
+	if (ret)
+		return ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366RB_PHY_ACCESS_DATA_REG, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi,
+				  u32 phy_no, u32 page, u32 addr, u32 data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366RB_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366RB_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366RB_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG,
+				    RTL8366RB_PHY_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) |
+	      ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) |
+	      (addr & RTL8366RB_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366rb_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				     int port, unsigned long long *val)
+{
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8366RB_NUM_PORTS || counter >= RTL8366RB_MIB_COUNT)
+		return -EINVAL;
+
+	addr = RTL8366RB_MIB_COUNTER_BASE +
+	       RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) +
+	       rtl8366rb_mib_counters[counter].offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	data = 0; /* writing data will be discard by ASIC */
+	err = rtl8366_smi_write_reg(smi, addr, data);
+	if (err)
+		return err;
+
+	/* read MIB control register */
+	err =  rtl8366_smi_read_reg(smi, RTL8366RB_MIB_CTRL_REG, &data);
+	if (err)
+		return err;
+
+	if (data & RTL8366RB_MIB_CTRL_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8366RB_MIB_CTRL_RESET_MASK)
+		return -EIO;
+
+	mibvalue = 0;
+	for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) {
+		err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data);
+		if (err)
+			return err;
+
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				 struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8366RB_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	err = rtl8366_smi_write_reg(smi, RTL8366RB_VLAN_TABLE_WRITE_BASE,
+				    vid & RTL8366RB_VLAN_VID_MASK);
+	if (err)
+		return err;
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG,
+				    RTL8366RB_TABLE_VLAN_READ_CTRL);
+	if (err)
+		return err;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366RB_VLAN_TABLE_READ_BASE + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlan4k->vid = vid;
+	vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) &
+			RTL8366RB_VLAN_UNTAG_MASK;
+	vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK;
+	vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi,
+				 const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8366RB_NUM_VIDS ||
+	    vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK ||
+	    vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK ||
+	    vlan4k->fid > RTL8366RB_FIDMAX)
+		return -EINVAL;
+
+	data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK;
+	data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) |
+		  ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) <<
+			RTL8366RB_VLAN_UNTAG_SHIFT);
+	data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366RB_VLAN_TABLE_WRITE_BASE + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG,
+				    RTL8366RB_TABLE_VLAN_WRITE_CTRL);
+
+	return err;
+}
+
+static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				 struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8366RB_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366RB_VLAN_MC_BASE(index) + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK;
+	vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) &
+			   RTL8366RB_VLAN_PRIORITY_MASK;
+	vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) &
+			RTL8366RB_VLAN_UNTAG_MASK;
+	vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK;
+	vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				 const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	if (index >= RTL8366RB_NUM_VLANS ||
+	    vlanmc->vid >= RTL8366RB_NUM_VIDS ||
+	    vlanmc->priority > RTL8366RB_PRIORITYMAX ||
+	    vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK ||
+	    vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK ||
+	    vlanmc->fid > RTL8366RB_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) |
+		  ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) <<
+			RTL8366RB_VLAN_PRIORITY_SHIFT);
+	data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) |
+		  ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) <<
+			RTL8366RB_VLAN_UNTAG_SHIFT);
+	data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366RB_VLAN_MC_BASE(index) + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	err = rtl8366_smi_read_reg(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port),
+				   &data);
+	if (err)
+		return err;
+
+	*val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) &
+	       RTL8366RB_PORT_VLAN_CTRL_MASK;
+
+	return 0;
+
+}
+
+static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8366RB_NUM_PORTS || index >= RTL8366RB_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port),
+				RTL8366RB_PORT_VLAN_CTRL_MASK <<
+					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port),
+				(index & RTL8366RB_PORT_VLAN_CTRL_MASK) <<
+					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port));
+}
+
+static int rtl8366rb_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8366RB_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8366RB_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8366rb_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN,
+				(enable) ? RTL8366RB_SGCR_EN_VLAN : 0);
+}
+
+static int rtl8366rb_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR,
+				RTL8366RB_SGCR_EN_VLAN_4KTB,
+				(enable) ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0);
+}
+
+static int rtl8366rb_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, (1 << port),
+				(enable) ? 0 : (1 << port));
+}
+
+static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0,
+			        RTL8366RB_MIB_CTRL_GLOBAL_RESET);
+}
+
+static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_LED_BLINKRATE_REG, &data);
+
+	val->value.i = (data & (RTL8366RB_LED_BLINKRATE_MASK));
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->value.i >= 6)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_LED_BLINKRATE_REG,
+				RTL8366RB_LED_BLINKRATE_MASK,
+				val->value.i);
+}
+
+static int rtl8366rb_sw_get_learning_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_SSCR0, &data);
+	val->value.i = !data;
+
+	return 0;
+}
+
+
+static int rtl8366rb_sw_set_learning_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 portmask = 0;
+	int err = 0;
+
+	if (!val->value.i)
+		portmask = RTL8366RB_PORT_ALL;
+
+	/* set learning for all ports */
+	REG_WR(smi, RTL8366RB_SSCR0, portmask);
+
+	/* set auto ageing for all ports */
+	REG_WR(smi, RTL8366RB_SSCR1, portmask);
+
+	return 0;
+}
+
+static int rtl8366rb_sw_get_port_link(struct switch_dev *dev,
+				     int port,
+				     struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PORT_LINK_STATUS_BASE + (port / 2),
+			     &data);
+
+	if (port % 2)
+		data = data >> 8;
+
+	link->link = !!(data & RTL8366RB_PORT_STATUS_LINK_MASK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8366RB_PORT_STATUS_DUPLEX_MASK);
+	link->rx_flow = !!(data & RTL8366RB_PORT_STATUS_RXPAUSE_MASK);
+	link->tx_flow = !!(data & RTL8366RB_PORT_STATUS_TXPAUSE_MASK);
+	link->aneg = !!(data & RTL8366RB_PORT_STATUS_AN_MASK);
+
+	speed = (data & RTL8366RB_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+	u32 mask;
+	u32 reg;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	if (val->port_vlan == RTL8366RB_PORT_NUM_CPU) {
+		reg = RTL8366RB_LED_BLINKRATE_REG;
+		mask = 0xF << 4;
+		data = val->value.i << 4;
+	} else {
+		reg = RTL8366RB_LED_CTRL_REG;
+		mask = 0xF << (val->port_vlan * 4),
+		data = val->value.i << (val->port_vlan * 4);
+	}
+
+	return rtl8366_smi_rmwr(smi, reg, mask, data);
+}
+
+static int rtl8366rb_sw_get_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+
+	if (val->port_vlan >= RTL8366RB_NUM_LEDGROUPS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_LED_CTRL_REG, &data);
+	val->value.i = (data >> (val->port_vlan * 4)) & 0x000F;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 mask, data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	mask = 1 << val->port_vlan ;
+	if (val->value.i)
+		data = mask;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, mask, data);
+}
+
+static int rtl8366rb_sw_get_port_disable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PECR, &data);
+	if (data & (1 << val->port_vlan))
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_rate_in(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX)
+		val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT;
+	else
+		val->value.i = RTL8366RB_BDTH_REG_DEFAULT;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan),
+		RTL8366RB_IB_BDTH_MASK | RTL8366RB_IB_PREIFG_MASK,
+		val->value.i |
+		(RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_IB_PREIFG_OFFSET));
+
+}
+
+static int rtl8366rb_sw_get_port_rate_in(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data);
+	data &= RTL8366RB_IB_BDTH_MASK;
+	if (data < RTL8366RB_IB_BDTH_MASK)
+		data += 1;
+
+	val->value.i = (int)data * RTL8366RB_BDTH_UNIT;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_rate_out(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG,
+		RTL8366RB_EB_PREIFG_MASK,
+		(RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET));
+
+	if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX)
+		val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT;
+	else
+		val->value.i = RTL8366RB_BDTH_REG_DEFAULT;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan),
+			RTL8366RB_EB_BDTH_MASK, val->value.i );
+
+}
+
+static int rtl8366rb_sw_get_port_rate_out(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data);
+	data &= RTL8366RB_EB_BDTH_MASK;
+	if (data < RTL8366RB_EB_BDTH_MASK)
+		data += 1;
+
+	val->value.i = (int)data * RTL8366RB_BDTH_UNIT;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_QOS_MASK;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_QOS_MASK, data);
+}
+
+static int rtl8366rb_sw_get_qos_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data);
+	if (data & RTL8366RB_QOS_MASK)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_rx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_RX;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_RX, data);
+}
+
+static int rtl8366rb_sw_get_mirror_rx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_RX)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_tx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_TX;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_TX, data);
+}
+
+static int rtl8366rb_sw_get_mirror_tx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_TX)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_monitor_isolation_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_ISO;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_ISO, data);
+}
+
+static int rtl8366rb_sw_get_monitor_isolation_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_ISO)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_pause_frames_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_SPC;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_SPC, data);
+}
+
+static int rtl8366rb_sw_get_mirror_pause_frames_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_SPC)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_monitor_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	data = RTL8366RB_PMCR_MONITOR_PORT(val->value.i);
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MONITOR_PORT_MASK, data);
+}
+
+static int rtl8366rb_sw_get_mirror_monitor_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	val->value.i = (data & RTL8366RB_PMCR_MONITOR_PORT_MASK) >> 4;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_source_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	data = RTL8366RB_PMCR_SOURCE_PORT(val->value.i);
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_SOURCE_PORT_MASK, data);
+}
+
+static int rtl8366rb_sw_get_mirror_source_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	val->value.i = data & RTL8366RB_PMCR_SOURCE_PORT_MASK;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0,
+				RTL8366RB_MIB_CTRL_PORT_RESET(val->port_vlan));
+}
+
+static struct switch_attr rtl8366rb_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_learning",
+		.description = "Enable learning, enable aging",
+		.set = rtl8366rb_sw_set_learning_enable,
+		.get = rtl8366rb_sw_get_learning_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8366rb_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "blinkrate",
+		.description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms,"
+		" 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)",
+		.set = rtl8366rb_sw_set_blinkrate,
+		.get = rtl8366rb_sw_get_blinkrate,
+		.max = 5
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_qos",
+		.description = "Enable QOS",
+		.set = rtl8366rb_sw_set_qos_enable,
+		.get = rtl8366rb_sw_get_qos_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_rx",
+		.description = "Enable mirroring of RX packets",
+		.set = rtl8366rb_sw_set_mirror_rx_enable,
+		.get = rtl8366rb_sw_get_mirror_rx_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_tx",
+		.description = "Enable mirroring of TX packets",
+		.set = rtl8366rb_sw_set_mirror_tx_enable,
+		.get = rtl8366rb_sw_get_mirror_tx_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_monitor_isolation",
+		.description = "Enable isolation of monitor port (TX packets will be dropped)",
+		.set = rtl8366rb_sw_set_monitor_isolation_enable,
+		.get = rtl8366rb_sw_get_monitor_isolation_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_pause_frames",
+		.description = "Enable mirroring of RX pause frames",
+		.set = rtl8366rb_sw_set_mirror_pause_frames_enable,
+		.get = rtl8366rb_sw_get_mirror_pause_frames_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_monitor_port",
+		.description = "Mirror monitor port",
+		.set = rtl8366rb_sw_set_mirror_monitor_port,
+		.get = rtl8366rb_sw_get_mirror_monitor_port,
+		.max = 5
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_source_port",
+		.description = "Mirror source port",
+		.set = rtl8366rb_sw_set_mirror_source_port,
+		.get = rtl8366rb_sw_get_mirror_source_port,
+		.max = 5
+	},
+};
+
+static struct switch_attr rtl8366rb_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8366rb_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "led",
+		.description = "Get/Set port group (0 - 3) led mode (0 - 15)",
+		.max = 15,
+		.set = rtl8366rb_sw_set_port_led,
+		.get = rtl8366rb_sw_get_port_led,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "disable",
+		.description = "Get/Set port state (enabled or disabled)",
+		.max = 1,
+		.set = rtl8366rb_sw_set_port_disable,
+		.get = rtl8366rb_sw_get_port_disable,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "rate_in",
+		.description = "Get/Set port ingress (incoming) bandwidth limit in kbps",
+		.max = RTL8366RB_BDTH_SW_MAX,
+		.set = rtl8366rb_sw_set_port_rate_in,
+		.get = rtl8366rb_sw_get_port_rate_in,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "rate_out",
+		.description = "Get/Set port egress (outgoing) bandwidth limit in kbps",
+		.max = RTL8366RB_BDTH_SW_MAX,
+		.set = rtl8366rb_sw_set_port_rate_out,
+		.get = rtl8366rb_sw_get_port_rate_out,
+	},
+};
+
+static struct switch_attr rtl8366rb_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "fid",
+		.description = "Get/Set vlan FID",
+		.max = RTL8366RB_FIDMAX,
+		.set = rtl8366_sw_set_vlan_fid,
+		.get = rtl8366_sw_get_vlan_fid,
+	},
+};
+
+static const struct switch_dev_ops rtl8366_ops = {
+	.attr_global = {
+		.attr = rtl8366rb_globals,
+		.n_attr = ARRAY_SIZE(rtl8366rb_globals),
+	},
+	.attr_port = {
+		.attr = rtl8366rb_port,
+		.n_attr = ARRAY_SIZE(rtl8366rb_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8366rb_vlan,
+		.n_attr = ARRAY_SIZE(rtl8366rb_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8366rb_sw_get_port_link,
+};
+
+static int rtl8366rb_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8366RB";
+	dev->cpu_port = RTL8366RB_PORT_NUM_CPU;
+	dev->ports = RTL8366RB_NUM_PORTS;
+	dev->vlans = RTL8366RB_NUM_VIDS;
+	dev->ops = &rtl8366_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8366rb_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val);
+	/* flush write */
+	(void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t);
+
+	return err;
+}
+
+static int rtl8366rb_detect(struct rtl8366_smi *smi)
+{
+	u32 chip_id = 0;
+	u32 chip_ver = 0;
+	int ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_ID_REG, &chip_id);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip id\n");
+		return ret;
+	}
+
+	switch (chip_id) {
+	case RTL8366RB_CHIP_ID_8366:
+		break;
+	default:
+		dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id);
+		return -ENODEV;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_VERSION_CTRL_REG,
+				   &chip_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip version\n");
+		return ret;
+	}
+
+	dev_info(smi->parent, "RTL%04x ver. %u chip found\n",
+		 chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8366rb_smi_ops = {
+	.detect		= rtl8366rb_detect,
+	.reset_chip	= rtl8366rb_reset_chip,
+	.setup		= rtl8366rb_setup,
+
+	.mii_read	= rtl8366rb_mii_read,
+	.mii_write	= rtl8366rb_mii_write,
+
+	.get_vlan_mc	= rtl8366rb_get_vlan_mc,
+	.set_vlan_mc	= rtl8366rb_set_vlan_mc,
+	.get_vlan_4k	= rtl8366rb_get_vlan_4k,
+	.set_vlan_4k	= rtl8366rb_set_vlan_4k,
+	.get_mc_index	= rtl8366rb_get_mc_index,
+	.set_mc_index	= rtl8366rb_set_mc_index,
+	.get_mib_counter = rtl8366rb_get_mib_counter,
+	.is_vlan_valid	= rtl8366rb_is_vlan_valid,
+	.enable_vlan	= rtl8366rb_enable_vlan,
+	.enable_vlan4k	= rtl8366rb_enable_vlan4k,
+	.enable_port	= rtl8366rb_enable_port,
+};
+
+static int rtl8366rb_probe(struct platform_device *pdev)
+{
+	static int rtl8366_smi_version_printed;
+	struct rtl8366_smi *smi;
+	int err;
+
+	if (!rtl8366_smi_version_printed++)
+		printk(KERN_NOTICE RTL8366RB_DRIVER_DESC
+		       " version " RTL8366RB_DRIVER_VER"\n");
+
+	smi = rtl8366_smi_probe(pdev);
+	if (!smi)
+		return -ENODEV;
+
+	smi->clk_delay = 10;
+	smi->cmd_read = 0xa9;
+	smi->cmd_write = 0xa8;
+	smi->ops = &rtl8366rb_smi_ops;
+	smi->cpu_port = RTL8366RB_PORT_NUM_CPU;
+	smi->num_ports = RTL8366RB_NUM_PORTS;
+	smi->num_vlan_mc = RTL8366RB_NUM_VLANS;
+	smi->mib_counters = rtl8366rb_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8366rb_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8366rb_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8366rb_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8366rb_match[] = {
+	{ .compatible = "rtl8366rb" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtl8366rb_match);
+#endif
+
+static struct platform_driver rtl8366rb_driver = {
+	.driver = {
+		.name		= RTL8366RB_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table = of_match_ptr(rtl8366rb_match),
+	},
+	.probe		= rtl8366rb_probe,
+	.remove		= rtl8366rb_remove,
+};
+
+static int __init rtl8366rb_module_init(void)
+{
+	return platform_driver_register(&rtl8366rb_driver);
+}
+module_init(rtl8366rb_module_init);
+
+static void __exit rtl8366rb_module_exit(void)
+{
+	platform_driver_unregister(&rtl8366rb_driver);
+}
+module_exit(rtl8366rb_module_exit);
+
+MODULE_DESCRIPTION(RTL8366RB_DRIVER_DESC);
+MODULE_VERSION(RTL8366RB_DRIVER_VER);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Antti Seppälä <a.seppala@gmail.com>");
+MODULE_AUTHOR("Roman Yeryomin <roman@advem.lv>");
+MODULE_AUTHOR("Colin Leitner <colin.leitner@googlemail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME);
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c
new file mode 100644
index 0000000000..3dc2a87aed
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c
@@ -0,0 +1,1148 @@
+/*
+ * Platform driver for the Realtek RTL8366S ethernet switch
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8366.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8366S_DRIVER_DESC	"Realtek RTL8366S ethernet switch driver"
+#define RTL8366S_DRIVER_VER	"0.2.2"
+
+#define RTL8366S_PHY_NO_MAX	4
+#define RTL8366S_PHY_PAGE_MAX	7
+#define RTL8366S_PHY_ADDR_MAX	31
+
+/* Switch Global Configuration register */
+#define RTL8366S_SGCR				0x0000
+#define RTL8366S_SGCR_EN_BC_STORM_CTRL		BIT(0)
+#define RTL8366S_SGCR_MAX_LENGTH(_x)		(_x << 4)
+#define RTL8366S_SGCR_MAX_LENGTH_MASK		RTL8366S_SGCR_MAX_LENGTH(0x3)
+#define RTL8366S_SGCR_MAX_LENGTH_1522		RTL8366S_SGCR_MAX_LENGTH(0x0)
+#define RTL8366S_SGCR_MAX_LENGTH_1536		RTL8366S_SGCR_MAX_LENGTH(0x1)
+#define RTL8366S_SGCR_MAX_LENGTH_1552		RTL8366S_SGCR_MAX_LENGTH(0x2)
+#define RTL8366S_SGCR_MAX_LENGTH_16000		RTL8366S_SGCR_MAX_LENGTH(0x3)
+#define RTL8366S_SGCR_EN_VLAN			BIT(13)
+
+/* Port Enable Control register */
+#define RTL8366S_PECR				0x0001
+
+/* Switch Security Control registers */
+#define RTL8366S_SSCR0				0x0002
+#define RTL8366S_SSCR1				0x0003
+#define RTL8366S_SSCR2				0x0004
+#define RTL8366S_SSCR2_DROP_UNKNOWN_DA		BIT(0)
+
+#define RTL8366S_RESET_CTRL_REG			0x0100
+#define RTL8366S_CHIP_CTRL_RESET_HW		1
+#define RTL8366S_CHIP_CTRL_RESET_SW		(1 << 1)
+
+#define RTL8366S_CHIP_VERSION_CTRL_REG		0x0104
+#define RTL8366S_CHIP_VERSION_MASK		0xf
+#define RTL8366S_CHIP_ID_REG			0x0105
+#define RTL8366S_CHIP_ID_8366			0x8366
+
+/* PHY registers control */
+#define RTL8366S_PHY_ACCESS_CTRL_REG		0x8028
+#define RTL8366S_PHY_ACCESS_DATA_REG		0x8029
+
+#define RTL8366S_PHY_CTRL_READ			1
+#define RTL8366S_PHY_CTRL_WRITE			0
+
+#define RTL8366S_PHY_REG_MASK			0x1f
+#define RTL8366S_PHY_PAGE_OFFSET		5
+#define RTL8366S_PHY_PAGE_MASK			(0x7 << 5)
+#define RTL8366S_PHY_NO_OFFSET			9
+#define RTL8366S_PHY_NO_MASK			(0x1f << 9)
+
+/* LED control registers */
+#define RTL8366S_LED_BLINKRATE_REG		0x0420
+#define RTL8366S_LED_BLINKRATE_BIT		0
+#define RTL8366S_LED_BLINKRATE_MASK		0x0007
+
+#define RTL8366S_LED_CTRL_REG			0x0421
+#define RTL8366S_LED_0_1_CTRL_REG		0x0422
+#define RTL8366S_LED_2_3_CTRL_REG		0x0423
+
+#define RTL8366S_MIB_COUNT			33
+#define RTL8366S_GLOBAL_MIB_COUNT		1
+#define RTL8366S_MIB_COUNTER_PORT_OFFSET	0x0040
+#define RTL8366S_MIB_COUNTER_BASE		0x1000
+#define RTL8366S_MIB_COUNTER_PORT_OFFSET2	0x0008
+#define RTL8366S_MIB_COUNTER_BASE2		0x1180
+#define RTL8366S_MIB_CTRL_REG			0x11F0
+#define RTL8366S_MIB_CTRL_USER_MASK		0x01FF
+#define RTL8366S_MIB_CTRL_BUSY_MASK		0x0001
+#define RTL8366S_MIB_CTRL_RESET_MASK		0x0002
+
+#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK	0x0004
+#define RTL8366S_MIB_CTRL_PORT_RESET_BIT	0x0003
+#define RTL8366S_MIB_CTRL_PORT_RESET_MASK	0x01FC
+
+
+#define RTL8366S_PORT_VLAN_CTRL_BASE		0x0058
+#define RTL8366S_PORT_VLAN_CTRL_REG(_p)  \
+		(RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4)
+#define RTL8366S_PORT_VLAN_CTRL_MASK		0xf
+#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p)	(4 * ((_p) % 4))
+
+
+#define RTL8366S_VLAN_TABLE_READ_BASE		0x018B
+#define RTL8366S_VLAN_TABLE_WRITE_BASE		0x0185
+
+#define RTL8366S_VLAN_TB_CTRL_REG		0x010F
+
+#define RTL8366S_TABLE_ACCESS_CTRL_REG		0x0180
+#define RTL8366S_TABLE_VLAN_READ_CTRL		0x0E01
+#define RTL8366S_TABLE_VLAN_WRITE_CTRL		0x0F01
+
+#define RTL8366S_VLAN_MC_BASE(_x)		(0x0016 + (_x) * 2)
+
+#define RTL8366S_VLAN_MEMBERINGRESS_REG		0x0379
+
+#define RTL8366S_PORT_LINK_STATUS_BASE		0x0060
+#define RTL8366S_PORT_STATUS_SPEED_MASK		0x0003
+#define RTL8366S_PORT_STATUS_DUPLEX_MASK	0x0004
+#define RTL8366S_PORT_STATUS_LINK_MASK		0x0010
+#define RTL8366S_PORT_STATUS_TXPAUSE_MASK	0x0020
+#define RTL8366S_PORT_STATUS_RXPAUSE_MASK	0x0040
+#define RTL8366S_PORT_STATUS_AN_MASK		0x0080
+
+
+#define RTL8366S_PORT_NUM_CPU		5
+#define RTL8366S_NUM_PORTS		6
+#define RTL8366S_NUM_VLANS		16
+#define RTL8366S_NUM_LEDGROUPS		4
+#define RTL8366S_NUM_VIDS		4096
+#define RTL8366S_PRIORITYMAX		7
+#define RTL8366S_FIDMAX			7
+
+
+#define RTL8366S_PORT_1			(1 << 0) /* In userspace port 0 */
+#define RTL8366S_PORT_2			(1 << 1) /* In userspace port 1 */
+#define RTL8366S_PORT_3			(1 << 2) /* In userspace port 2 */
+#define RTL8366S_PORT_4			(1 << 3) /* In userspace port 3 */
+
+#define RTL8366S_PORT_UNKNOWN		(1 << 4) /* No known connection */
+#define RTL8366S_PORT_CPU		(1 << 5) /* CPU port */
+
+#define RTL8366S_PORT_ALL		(RTL8366S_PORT_1 |	\
+					 RTL8366S_PORT_2 |	\
+					 RTL8366S_PORT_3 |	\
+					 RTL8366S_PORT_4 |	\
+					 RTL8366S_PORT_UNKNOWN | \
+					 RTL8366S_PORT_CPU)
+
+#define RTL8366S_PORT_ALL_BUT_CPU	(RTL8366S_PORT_1 |	\
+					 RTL8366S_PORT_2 |	\
+					 RTL8366S_PORT_3 |	\
+					 RTL8366S_PORT_4 |	\
+					 RTL8366S_PORT_UNKNOWN)
+
+#define RTL8366S_PORT_ALL_EXTERNAL	(RTL8366S_PORT_1 |	\
+					 RTL8366S_PORT_2 |	\
+					 RTL8366S_PORT_3 |	\
+					 RTL8366S_PORT_4)
+
+#define RTL8366S_PORT_ALL_INTERNAL	(RTL8366S_PORT_UNKNOWN | \
+					 RTL8366S_PORT_CPU)
+
+#define RTL8366S_VLAN_VID_MASK		0xfff
+#define RTL8366S_VLAN_PRIORITY_SHIFT	12
+#define RTL8366S_VLAN_PRIORITY_MASK	0x7
+#define RTL8366S_VLAN_MEMBER_MASK	0x3f
+#define RTL8366S_VLAN_UNTAG_SHIFT	6
+#define RTL8366S_VLAN_UNTAG_MASK	0x3f
+#define RTL8366S_VLAN_FID_SHIFT		12
+#define RTL8366S_VLAN_FID_MASK		0x7
+
+static struct rtl8366_mib_counter rtl8366s_mib_counters[] = {
+	{ 0,  0, 4, "IfInOctets"				},
+	{ 0,  4, 4, "EtherStatsOctets"				},
+	{ 0,  8, 2, "EtherStatsUnderSizePkts"			},
+	{ 0, 10, 2, "EtherFragments"				},
+	{ 0, 12, 2, "EtherStatsPkts64Octets"			},
+	{ 0, 14, 2, "EtherStatsPkts65to127Octets"		},
+	{ 0, 16, 2, "EtherStatsPkts128to255Octets"		},
+	{ 0, 18, 2, "EtherStatsPkts256to511Octets"		},
+	{ 0, 20, 2, "EtherStatsPkts512to1023Octets"		},
+	{ 0, 22, 2, "EtherStatsPkts1024to1518Octets"		},
+	{ 0, 24, 2, "EtherOversizeStats"			},
+	{ 0, 26, 2, "EtherStatsJabbers"				},
+	{ 0, 28, 2, "IfInUcastPkts"				},
+	{ 0, 30, 2, "EtherStatsMulticastPkts"			},
+	{ 0, 32, 2, "EtherStatsBroadcastPkts"			},
+	{ 0, 34, 2, "EtherStatsDropEvents"			},
+	{ 0, 36, 2, "Dot3StatsFCSErrors"			},
+	{ 0, 38, 2, "Dot3StatsSymbolErrors"			},
+	{ 0, 40, 2, "Dot3InPauseFrames"				},
+	{ 0, 42, 2, "Dot3ControlInUnknownOpcodes"		},
+	{ 0, 44, 4, "IfOutOctets"				},
+	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
+	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
+	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
+	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
+	{ 0, 56, 2, "EtherStatsCollisions"			},
+	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
+	{ 0, 60, 2, "Dot3OutPauseFrames"			},
+	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
+
+	/*
+	 * The following counters are accessible at a different
+	 * base address.
+	 */
+	{ 1,  0, 2, "Dot1dTpPortInDiscards"			},
+	{ 1,  2, 2, "IfOutUcastPkts"				},
+	{ 1,  4, 2, "IfOutMulticastPkts"			},
+	{ 1,  6, 2, "IfOutBroadcastPkts"			},
+};
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static int rtl8366s_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	u32 data;
+
+	rtl8366_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG,
+				    RTL8366S_CHIP_CTRL_RESET_HW);
+	do {
+		msleep(1);
+		if (rtl8366_smi_read_reg(smi, RTL8366S_RESET_CTRL_REG, &data))
+			return -EIO;
+
+		if (!(data & RTL8366S_CHIP_CTRL_RESET_HW))
+			break;
+	} while (--timeout);
+
+	if (!timeout) {
+		printk("Timeout waiting for the switch to reset\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int rtl8366s_setup(struct rtl8366_smi *smi)
+{
+	struct rtl8366_platform_data *pdata;
+	int err;
+
+	pdata = smi->parent->platform_data;
+	if (pdata && pdata->num_initvals && pdata->initvals) {
+		unsigned i;
+
+		dev_info(smi->parent, "applying initvals\n");
+		for (i = 0; i < pdata->num_initvals; i++)
+			REG_WR(smi, pdata->initvals[i].reg,
+			       pdata->initvals[i].val);
+	}
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8366S_SGCR, RTL8366S_SGCR_MAX_LENGTH_MASK,
+		RTL8366S_SGCR_MAX_LENGTH_1536);
+
+	/* enable learning for all ports */
+	REG_WR(smi, RTL8366S_SSCR0, 0);
+
+	/* enable auto ageing for all ports */
+	REG_WR(smi, RTL8366S_SSCR1, 0);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8366S_VLAN_MEMBERINGRESS_REG, RTL8366S_PORT_ALL);
+
+	/* don't drop packets whose DA has not been learned */
+	REG_RMW(smi, RTL8366S_SSCR2, RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0);
+
+	return 0;
+}
+
+static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_no, u32 page, u32 addr, u32 *data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366S_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366S_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366S_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG,
+				    RTL8366S_PHY_CTRL_READ);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) |
+	      ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) |
+	      (addr & RTL8366S_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, 0);
+	if (ret)
+		return ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi,
+				  u32 phy_no, u32 page, u32 addr, u32 data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366S_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366S_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366S_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG,
+				    RTL8366S_PHY_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) |
+	      ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) |
+	      (addr & RTL8366S_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				   int port, unsigned long long *val)
+{
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8366S_NUM_PORTS || counter >= RTL8366S_MIB_COUNT)
+		return -EINVAL;
+
+	switch (rtl8366s_mib_counters[counter].base) {
+	case 0:
+		addr = RTL8366S_MIB_COUNTER_BASE +
+		       RTL8366S_MIB_COUNTER_PORT_OFFSET * port;
+		break;
+
+	case 1:
+		addr = RTL8366S_MIB_COUNTER_BASE2 +
+			RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	addr += rtl8366s_mib_counters[counter].offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	data = 0; /* writing data will be discard by ASIC */
+	err = rtl8366_smi_write_reg(smi, addr, data);
+	if (err)
+		return err;
+
+	/* read MIB control register */
+	err =  rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data);
+	if (err)
+		return err;
+
+	if (data & RTL8366S_MIB_CTRL_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8366S_MIB_CTRL_RESET_MASK)
+		return -EIO;
+
+	mibvalue = 0;
+	for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) {
+		err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data);
+		if (err)
+			return err;
+
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8366S_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE,
+				    vid & RTL8366S_VLAN_VID_MASK);
+	if (err)
+		return err;
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG,
+				    RTL8366S_TABLE_VLAN_READ_CTRL);
+	if (err)
+		return err;
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366S_VLAN_TABLE_READ_BASE + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlan4k->vid = vid;
+	vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) &
+			RTL8366S_VLAN_UNTAG_MASK;
+	vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK;
+	vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) &
+			RTL8366S_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi,
+				const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8366S_NUM_VIDS ||
+	    vlan4k->member > RTL8366S_VLAN_MEMBER_MASK ||
+	    vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK ||
+	    vlan4k->fid > RTL8366S_FIDMAX)
+		return -EINVAL;
+
+	data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK;
+	data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) |
+		  ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) <<
+			RTL8366S_VLAN_UNTAG_SHIFT) |
+		  ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) <<
+			RTL8366S_VLAN_FID_SHIFT);
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366S_VLAN_TABLE_WRITE_BASE + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG,
+				    RTL8366S_TABLE_VLAN_WRITE_CTRL);
+
+	return err;
+}
+
+static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8366S_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366S_VLAN_MC_BASE(index) + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK;
+	vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) &
+			   RTL8366S_VLAN_PRIORITY_MASK;
+	vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) &
+			RTL8366S_VLAN_UNTAG_MASK;
+	vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK;
+	vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) &
+		      RTL8366S_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	if (index >= RTL8366S_NUM_VLANS ||
+	    vlanmc->vid >= RTL8366S_NUM_VIDS ||
+	    vlanmc->priority > RTL8366S_PRIORITYMAX ||
+	    vlanmc->member > RTL8366S_VLAN_MEMBER_MASK ||
+	    vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK ||
+	    vlanmc->fid > RTL8366S_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) |
+		  ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) <<
+			RTL8366S_VLAN_PRIORITY_SHIFT);
+	data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) |
+		  ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) <<
+			RTL8366S_VLAN_UNTAG_SHIFT) |
+		  ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) <<
+			RTL8366S_VLAN_FID_SHIFT);
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366S_VLAN_MC_BASE(index) + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+	err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port),
+				   &data);
+	if (err)
+		return err;
+
+	*val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) &
+	       RTL8366S_PORT_VLAN_CTRL_MASK;
+
+	return 0;
+}
+
+static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port),
+				RTL8366S_PORT_VLAN_CTRL_MASK <<
+					RTL8366S_PORT_VLAN_CTRL_SHIFT(port),
+				(index & RTL8366S_PORT_VLAN_CTRL_MASK) <<
+					RTL8366S_PORT_VLAN_CTRL_SHIFT(port));
+}
+
+static int rtl8366s_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN,
+				(enable) ? RTL8366S_SGCR_EN_VLAN : 0);
+}
+
+static int rtl8366s_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG,
+				1, (enable) ? 1 : 0);
+}
+
+static int rtl8366s_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8366S_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8366S_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8366s_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366S_PECR, (1 << port),
+				(enable) ? 0 : (1 << port));
+}
+
+static int rtl8366s_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2));
+}
+
+static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_LED_BLINKRATE_REG, &data);
+
+	val->value.i = (data & (RTL8366S_LED_BLINKRATE_MASK));
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->value.i >= 6)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_LED_BLINKRATE_REG,
+				RTL8366S_LED_BLINKRATE_MASK,
+				val->value.i);
+}
+
+static int rtl8366s_sw_get_max_length(struct switch_dev *dev,
+					const struct switch_attr *attr,
+					struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_SGCR, &data);
+
+	val->value.i = ((data & (RTL8366S_SGCR_MAX_LENGTH_MASK)) >> 4);
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_max_length(struct switch_dev *dev,
+					const struct switch_attr *attr,
+					struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	char length_code;
+
+	switch (val->value.i) {
+		case 0:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_1522;
+			break;
+		case 1:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_1536;
+			break;
+		case 2:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_1552;
+			break;
+		case 3:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_16000;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_SGCR,
+			RTL8366S_SGCR_MAX_LENGTH_MASK,
+			length_code);
+}
+
+static int rtl8366s_sw_get_learning_enable(struct switch_dev *dev,
+					   const struct switch_attr *attr,
+					   struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi,RTL8366S_SSCR0, &data);
+	val->value.i = !data;
+
+	return 0;
+}
+
+
+static int rtl8366s_sw_set_learning_enable(struct switch_dev *dev,
+					   const struct switch_attr *attr,
+					   struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 portmask = 0;
+	int err = 0;
+
+	if (!val->value.i)
+		portmask = RTL8366S_PORT_ALL;
+
+	/* set learning for all ports */
+	REG_WR(smi, RTL8366S_SSCR0, portmask);
+
+	/* set auto ageing for all ports */
+	REG_WR(smi, RTL8366S_SSCR1, portmask);
+
+	return 0;
+}
+
+static int rtl8366s_sw_get_port_link(struct switch_dev *dev,
+				     int port,
+				     struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + (port / 2),
+			     &data);
+
+	if (port % 2)
+		data = data >> 8;
+
+	link->link = !!(data & RTL8366S_PORT_STATUS_LINK_MASK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8366S_PORT_STATUS_DUPLEX_MASK);
+	link->rx_flow = !!(data & RTL8366S_PORT_STATUS_RXPAUSE_MASK);
+	link->tx_flow = !!(data & RTL8366S_PORT_STATUS_TXPAUSE_MASK);
+	link->aneg = !!(data & RTL8366S_PORT_STATUS_AN_MASK);
+
+	speed = (data & RTL8366S_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+	u32 mask;
+	u32 reg;
+
+	if (val->port_vlan >= RTL8366S_NUM_PORTS ||
+	    (1 << val->port_vlan) == RTL8366S_PORT_UNKNOWN)
+		return -EINVAL;
+
+	if (val->port_vlan == RTL8366S_PORT_NUM_CPU) {
+		reg = RTL8366S_LED_BLINKRATE_REG;
+		mask = 0xF << 4;
+		data = val->value.i << 4;
+	} else {
+		reg = RTL8366S_LED_CTRL_REG;
+		mask = 0xF << (val->port_vlan * 4),
+		data = val->value.i << (val->port_vlan * 4);
+	}
+
+	return rtl8366_smi_rmwr(smi, reg, mask, data);
+}
+
+static int rtl8366s_sw_get_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+
+	if (val->port_vlan >= RTL8366S_NUM_LEDGROUPS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_LED_CTRL_REG, &data);
+	val->value.i = (data >> (val->port_vlan * 4)) & 0x000F;
+
+	return 0;
+}
+
+static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG,
+				0, (1 << (val->port_vlan + 3)));
+}
+
+static struct switch_attr rtl8366s_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_learning",
+		.description = "Enable learning, enable aging",
+		.set = rtl8366s_sw_set_learning_enable,
+		.get = rtl8366s_sw_get_learning_enable,
+		.max = 1,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8366s_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "blinkrate",
+		.description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms,"
+		" 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)",
+		.set = rtl8366s_sw_set_blinkrate,
+		.get = rtl8366s_sw_get_blinkrate,
+		.max = 5
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "max_length",
+		.description = "Get/Set the maximum length of valid packets"
+		" (0 = 1522, 1 = 1536, 2 = 1552, 3 = 16000 (9216?))",
+		.set = rtl8366s_sw_set_max_length,
+		.get = rtl8366s_sw_get_max_length,
+		.max = 3,
+	},
+};
+
+static struct switch_attr rtl8366s_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8366s_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "led",
+		.description = "Get/Set port group (0 - 3) led mode (0 - 15)",
+		.max = 15,
+		.set = rtl8366s_sw_set_port_led,
+		.get = rtl8366s_sw_get_port_led,
+	},
+};
+
+static struct switch_attr rtl8366s_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "fid",
+		.description = "Get/Set vlan FID",
+		.max = RTL8366S_FIDMAX,
+		.set = rtl8366_sw_set_vlan_fid,
+		.get = rtl8366_sw_get_vlan_fid,
+	},
+};
+
+static const struct switch_dev_ops rtl8366_ops = {
+	.attr_global = {
+		.attr = rtl8366s_globals,
+		.n_attr = ARRAY_SIZE(rtl8366s_globals),
+	},
+	.attr_port = {
+		.attr = rtl8366s_port,
+		.n_attr = ARRAY_SIZE(rtl8366s_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8366s_vlan,
+		.n_attr = ARRAY_SIZE(rtl8366s_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8366s_sw_get_port_link,
+};
+
+static int rtl8366s_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8366S";
+	dev->cpu_port = RTL8366S_PORT_NUM_CPU;
+	dev->ports = RTL8366S_NUM_PORTS;
+	dev->vlans = RTL8366S_NUM_VIDS;
+	dev->ops = &rtl8366_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8366s_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val);
+	/* flush write */
+	(void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t);
+
+	return err;
+}
+
+static int rtl8366s_detect(struct rtl8366_smi *smi)
+{
+	u32 chip_id = 0;
+	u32 chip_ver = 0;
+	int ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip id\n");
+		return ret;
+	}
+
+	switch (chip_id) {
+	case RTL8366S_CHIP_ID_8366:
+		break;
+	default:
+		dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id);
+		return -ENODEV;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG,
+				   &chip_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip version\n");
+		return ret;
+	}
+
+	dev_info(smi->parent, "RTL%04x ver. %u chip found\n",
+		 chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8366s_smi_ops = {
+	.detect		= rtl8366s_detect,
+	.reset_chip	= rtl8366s_reset_chip,
+	.setup		= rtl8366s_setup,
+
+	.mii_read	= rtl8366s_mii_read,
+	.mii_write	= rtl8366s_mii_write,
+
+	.get_vlan_mc	= rtl8366s_get_vlan_mc,
+	.set_vlan_mc	= rtl8366s_set_vlan_mc,
+	.get_vlan_4k	= rtl8366s_get_vlan_4k,
+	.set_vlan_4k	= rtl8366s_set_vlan_4k,
+	.get_mc_index	= rtl8366s_get_mc_index,
+	.set_mc_index	= rtl8366s_set_mc_index,
+	.get_mib_counter = rtl8366_get_mib_counter,
+	.is_vlan_valid	= rtl8366s_is_vlan_valid,
+	.enable_vlan	= rtl8366s_enable_vlan,
+	.enable_vlan4k	= rtl8366s_enable_vlan4k,
+	.enable_port	= rtl8366s_enable_port,
+};
+
+static int rtl8366s_probe(struct platform_device *pdev)
+{
+	static int rtl8366_smi_version_printed;
+	struct rtl8366_smi *smi;
+	int err;
+
+	if (!rtl8366_smi_version_printed++)
+		printk(KERN_NOTICE RTL8366S_DRIVER_DESC
+		       " version " RTL8366S_DRIVER_VER"\n");
+
+	smi = rtl8366_smi_probe(pdev);
+	if (!smi)
+		return -ENODEV;
+
+	smi->clk_delay = 10;
+	smi->cmd_read = 0xa9;
+	smi->cmd_write = 0xa8;
+	smi->ops = &rtl8366s_smi_ops;
+	smi->cpu_port = RTL8366S_PORT_NUM_CPU;
+	smi->num_ports = RTL8366S_NUM_PORTS;
+	smi->num_vlan_mc = RTL8366S_NUM_VLANS;
+	smi->mib_counters = rtl8366s_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8366s_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8366s_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8366s_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8366s_match[] = {
+	{ .compatible = "realtek,rtl8366s" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtl8366s_match);
+#endif
+
+static struct platform_driver rtl8366s_driver = {
+	.driver = {
+		.name		= RTL8366S_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(rtl8366s_match),
+#endif
+	},
+	.probe		= rtl8366s_probe,
+	.remove		= rtl8366s_remove,
+};
+
+static int __init rtl8366s_module_init(void)
+{
+	return platform_driver_register(&rtl8366s_driver);
+}
+module_init(rtl8366s_module_init);
+
+static void __exit rtl8366s_module_exit(void)
+{
+	platform_driver_unregister(&rtl8366s_driver);
+}
+module_exit(rtl8366s_module_exit);
+
+MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC);
+MODULE_VERSION(RTL8366S_DRIVER_VER);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Antti Seppälä <a.seppala@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME);
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c
new file mode 100644
index 0000000000..97cd1acfb5
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c
@@ -0,0 +1,1835 @@
+/*
+ * Platform driver for the Realtek RTL8367R/M ethernet switches
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8367.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8367_RESET_DELAY	1000	/* msecs*/
+
+#define RTL8367_PHY_ADDR_MAX	8
+#define RTL8367_PHY_REG_MAX	31
+
+#define RTL8367_VID_MASK	0xffff
+#define RTL8367_FID_MASK	0xfff
+#define RTL8367_UNTAG_MASK	0xffff
+#define RTL8367_MEMBER_MASK	0xffff
+
+#define RTL8367_PORT_CFG_REG(_p)		(0x000e + 0x20 * (_p))
+#define   RTL8367_PORT_CFG_EGRESS_MODE_SHIFT	4
+#define   RTL8367_PORT_CFG_EGRESS_MODE_MASK	0x3
+#define   RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL	0
+#define   RTL8367_PORT_CFG_EGRESS_MODE_KEEP	1
+#define   RTL8367_PORT_CFG_EGRESS_MODE_PRI	2
+#define   RTL8367_PORT_CFG_EGRESS_MODE_REAL	3
+
+#define RTL8367_BYPASS_LINE_RATE_REG		0x03f7
+
+#define RTL8367_TA_CTRL_REG			0x0500
+#define   RTL8367_TA_CTRL_STATUS		BIT(12)
+#define   RTL8367_TA_CTRL_METHOD		BIT(5)
+#define   RTL8367_TA_CTRL_CMD_SHIFT		4
+#define   RTL8367_TA_CTRL_CMD_READ		0
+#define   RTL8367_TA_CTRL_CMD_WRITE		1
+#define   RTL8367_TA_CTRL_TABLE_SHIFT		0
+#define   RTL8367_TA_CTRL_TABLE_ACLRULE		1
+#define   RTL8367_TA_CTRL_TABLE_ACLACT		2
+#define   RTL8367_TA_CTRL_TABLE_CVLAN		3
+#define   RTL8367_TA_CTRL_TABLE_L2		4
+#define   RTL8367_TA_CTRL_CVLAN_READ \
+		((RTL8367_TA_CTRL_CMD_READ << RTL8367_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367_TA_CTRL_TABLE_CVLAN)
+#define   RTL8367_TA_CTRL_CVLAN_WRITE \
+		((RTL8367_TA_CTRL_CMD_WRITE << RTL8367_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367_TA_CTRL_TABLE_CVLAN)
+
+#define RTL8367_TA_ADDR_REG			0x0501
+#define   RTL8367_TA_ADDR_MASK			0x3fff
+
+#define RTL8367_TA_DATA_REG(_x)			(0x0503 + (_x))
+#define   RTL8367_TA_VLAN_DATA_SIZE		4
+#define   RTL8367_TA_VLAN_VID_MASK		RTL8367_VID_MASK
+#define   RTL8367_TA_VLAN_MEMBER_SHIFT		0
+#define   RTL8367_TA_VLAN_MEMBER_MASK		RTL8367_MEMBER_MASK
+#define   RTL8367_TA_VLAN_FID_SHIFT		0
+#define   RTL8367_TA_VLAN_FID_MASK		RTL8367_FID_MASK
+#define   RTL8367_TA_VLAN_UNTAG1_SHIFT		14
+#define   RTL8367_TA_VLAN_UNTAG1_MASK		0x3
+#define   RTL8367_TA_VLAN_UNTAG2_SHIFT		0
+#define   RTL8367_TA_VLAN_UNTAG2_MASK		0x3fff
+
+#define RTL8367_VLAN_PVID_CTRL_REG(_p)		(0x0700 + (_p) / 2)
+#define RTL8367_VLAN_PVID_CTRL_MASK		0x1f
+#define RTL8367_VLAN_PVID_CTRL_SHIFT(_p)	(8 * ((_p) % 2))
+
+#define RTL8367_VLAN_MC_BASE(_x)		(0x0728 + (_x) * 4)
+#define   RTL8367_VLAN_MC_DATA_SIZE		4
+#define   RTL8367_VLAN_MC_MEMBER_SHIFT		0
+#define   RTL8367_VLAN_MC_MEMBER_MASK		RTL8367_MEMBER_MASK
+#define   RTL8367_VLAN_MC_FID_SHIFT		0
+#define   RTL8367_VLAN_MC_FID_MASK		RTL8367_FID_MASK
+#define   RTL8367_VLAN_MC_EVID_SHIFT		0
+#define   RTL8367_VLAN_MC_EVID_MASK		RTL8367_VID_MASK
+
+#define RTL8367_VLAN_CTRL_REG			0x07a8
+#define   RTL8367_VLAN_CTRL_ENABLE		BIT(0)
+
+#define RTL8367_VLAN_INGRESS_REG		0x07a9
+
+#define RTL8367_PORT_ISOLATION_REG(_p)		(0x08a2 + (_p))
+
+#define RTL8367_MIB_COUNTER_REG(_x)		(0x1000 + (_x))
+
+#define RTL8367_MIB_ADDRESS_REG			0x1004
+
+#define RTL8367_MIB_CTRL_REG(_x)		(0x1005 + (_x))
+#define   RTL8367_MIB_CTRL_GLOBAL_RESET_MASK	BIT(11)
+#define   RTL8367_MIB_CTRL_QM_RESET_MASK	BIT(10)
+#define   RTL8367_MIB_CTRL_PORT_RESET_MASK(_p)	BIT(2 + (_p))
+#define   RTL8367_MIB_CTRL_RESET_MASK		BIT(1)
+#define   RTL8367_MIB_CTRL_BUSY_MASK		BIT(0)
+
+#define RTL8367_MIB_COUNT			36
+#define RTL8367_MIB_COUNTER_PORT_OFFSET		0x0050
+
+#define RTL8367_SWC0_REG			0x1200
+#define   RTL8367_SWC0_MAX_LENGTH_SHIFT		13
+#define   RTL8367_SWC0_MAX_LENGTH(_x)		((_x) << 13)
+#define   RTL8367_SWC0_MAX_LENGTH_MASK		RTL8367_SWC0_MAX_LENGTH(0x3)
+#define   RTL8367_SWC0_MAX_LENGTH_1522		RTL8367_SWC0_MAX_LENGTH(0)
+#define   RTL8367_SWC0_MAX_LENGTH_1536		RTL8367_SWC0_MAX_LENGTH(1)
+#define   RTL8367_SWC0_MAX_LENGTH_1552		RTL8367_SWC0_MAX_LENGTH(2)
+#define   RTL8367_SWC0_MAX_LENGTH_16000		RTL8367_SWC0_MAX_LENGTH(3)
+
+#define RTL8367_CHIP_NUMBER_REG			0x1300
+
+#define RTL8367_CHIP_VER_REG			0x1301
+#define   RTL8367_CHIP_VER_RLVID_SHIFT		12
+#define   RTL8367_CHIP_VER_RLVID_MASK		0xf
+#define   RTL8367_CHIP_VER_MCID_SHIFT		8
+#define   RTL8367_CHIP_VER_MCID_MASK		0xf
+#define   RTL8367_CHIP_VER_BOID_SHIFT		4
+#define   RTL8367_CHIP_VER_BOID_MASK		0xf
+
+#define RTL8367_CHIP_MODE_REG			0x1302
+#define   RTL8367_CHIP_MODE_MASK		0x7
+
+#define RTL8367_CHIP_DEBUG0_REG			0x1303
+#define   RTL8367_CHIP_DEBUG0_DUMMY0(_x)	BIT(8 + (_x))
+
+#define RTL8367_CHIP_DEBUG1_REG			0x1304
+
+#define RTL8367_DIS_REG				0x1305
+#define   RTL8367_DIS_SKIP_MII_RXER(_x)		BIT(12 + (_x))
+#define   RTL8367_DIS_RGMII_SHIFT(_x)		(4 * (_x))
+#define   RTL8367_DIS_RGMII_MASK		0x7
+
+#define RTL8367_EXT_RGMXF_REG(_x)		(0x1306 + (_x))
+#define   RTL8367_EXT_RGMXF_DUMMY0_SHIFT	5
+#define   RTL8367_EXT_RGMXF_DUMMY0_MASK	0x7ff
+#define   RTL8367_EXT_RGMXF_TXDELAY_SHIFT	3
+#define   RTL8367_EXT_RGMXF_TXDELAY_MASK	1
+#define   RTL8367_EXT_RGMXF_RXDELAY_MASK	0x7
+
+#define RTL8367_DI_FORCE_REG(_x)		(0x1310 + (_x))
+#define   RTL8367_DI_FORCE_MODE			BIT(12)
+#define   RTL8367_DI_FORCE_NWAY			BIT(7)
+#define   RTL8367_DI_FORCE_TXPAUSE		BIT(6)
+#define   RTL8367_DI_FORCE_RXPAUSE		BIT(5)
+#define   RTL8367_DI_FORCE_LINK			BIT(4)
+#define   RTL8367_DI_FORCE_DUPLEX		BIT(2)
+#define   RTL8367_DI_FORCE_SPEED_MASK		3
+#define   RTL8367_DI_FORCE_SPEED_10		0
+#define   RTL8367_DI_FORCE_SPEED_100		1
+#define   RTL8367_DI_FORCE_SPEED_1000		2
+
+#define RTL8367_MAC_FORCE_REG(_x)		(0x1312 + (_x))
+
+#define RTL8367_CHIP_RESET_REG			0x1322
+#define   RTL8367_CHIP_RESET_SW			BIT(1)
+#define   RTL8367_CHIP_RESET_HW			BIT(0)
+
+#define RTL8367_PORT_STATUS_REG(_p)		(0x1352 + (_p))
+#define   RTL8367_PORT_STATUS_NWAY		BIT(7)
+#define   RTL8367_PORT_STATUS_TXPAUSE		BIT(6)
+#define   RTL8367_PORT_STATUS_RXPAUSE		BIT(5)
+#define   RTL8367_PORT_STATUS_LINK		BIT(4)
+#define   RTL8367_PORT_STATUS_DUPLEX		BIT(2)
+#define   RTL8367_PORT_STATUS_SPEED_MASK	0x0003
+#define   RTL8367_PORT_STATUS_SPEED_10		0
+#define   RTL8367_PORT_STATUS_SPEED_100		1
+#define   RTL8367_PORT_STATUS_SPEED_1000	2
+
+#define RTL8367_RTL_NO_REG			0x13c0
+#define   RTL8367_RTL_NO_8367R			0x3670
+#define   RTL8367_RTL_NO_8367M			0x3671
+
+#define RTL8367_RTL_VER_REG			0x13c1
+#define   RTL8367_RTL_VER_MASK			0xf
+
+#define RTL8367_RTL_MAGIC_ID_REG		0x13c2
+#define   RTL8367_RTL_MAGIC_ID_VAL		0x0249
+
+#define RTL8367_LED_SYS_CONFIG_REG		0x1b00
+#define RTL8367_LED_MODE_REG			0x1b02
+#define   RTL8367_LED_MODE_RATE_M		0x7
+#define   RTL8367_LED_MODE_RATE_S		1
+
+#define RTL8367_LED_CONFIG_REG			0x1b03
+#define   RTL8367_LED_CONFIG_DATA_S		12
+#define   RTL8367_LED_CONFIG_DATA_M		0x3
+#define   RTL8367_LED_CONFIG_SEL		BIT(14)
+#define   RTL8367_LED_CONFIG_LED_CFG_M		0xf
+
+#define RTL8367_PARA_LED_IO_EN1_REG		0x1b24
+#define RTL8367_PARA_LED_IO_EN2_REG		0x1b25
+#define   RTL8367_PARA_LED_IO_EN_PMASK		0xff
+
+#define RTL8367_IA_CTRL_REG			0x1f00
+#define   RTL8367_IA_CTRL_RW(_x)		((_x) << 1)
+#define   RTL8367_IA_CTRL_RW_READ		RTL8367_IA_CTRL_RW(0)
+#define   RTL8367_IA_CTRL_RW_WRITE		RTL8367_IA_CTRL_RW(1)
+#define   RTL8367_IA_CTRL_CMD_MASK		BIT(0)
+
+#define RTL8367_IA_STATUS_REG			0x1f01
+#define   RTL8367_IA_STATUS_PHY_BUSY		BIT(2)
+#define   RTL8367_IA_STATUS_SDS_BUSY		BIT(1)
+#define   RTL8367_IA_STATUS_MDX_BUSY		BIT(0)
+
+#define RTL8367_IA_ADDRESS_REG			0x1f02
+
+#define RTL8367_IA_WRITE_DATA_REG		0x1f03
+#define RTL8367_IA_READ_DATA_REG		0x1f04
+
+#define RTL8367_INTERNAL_PHY_REG(_a, _r)	(0x2000 + 32 * (_a) + (_r))
+
+#define RTL8367_CPU_PORT_NUM		9
+#define RTL8367_NUM_PORTS		10
+#define RTL8367_NUM_VLANS		32
+#define RTL8367_NUM_LEDGROUPS		4
+#define RTL8367_NUM_VIDS		4096
+#define RTL8367_PRIORITYMAX		7
+#define RTL8367_FIDMAX			7
+
+#define RTL8367_PORT_0			BIT(0)
+#define RTL8367_PORT_1			BIT(1)
+#define RTL8367_PORT_2			BIT(2)
+#define RTL8367_PORT_3			BIT(3)
+#define RTL8367_PORT_4			BIT(4)
+#define RTL8367_PORT_5			BIT(5)
+#define RTL8367_PORT_6			BIT(6)
+#define RTL8367_PORT_7			BIT(7)
+#define RTL8367_PORT_E1			BIT(8)	/* external port 1 */
+#define RTL8367_PORT_E0			BIT(9)	/* external port 0 */
+
+#define RTL8367_PORTS_ALL					\
+	(RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 |	\
+	 RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 |	\
+	 RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1 |	\
+	 RTL8367_PORT_E0)
+
+#define RTL8367_PORTS_ALL_BUT_CPU				\
+	(RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 |	\
+	 RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 |	\
+	 RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1)
+
+struct rtl8367_initval {
+	u16 reg;
+	u16 val;
+};
+
+static struct rtl8366_mib_counter rtl8367_mib_counters[] = {
+	{ 0,  0, 4, "IfInOctets"				},
+	{ 0,  4, 2, "Dot3StatsFCSErrors"			},
+	{ 0,  6, 2, "Dot3StatsSymbolErrors"			},
+	{ 0,  8, 2, "Dot3InPauseFrames"				},
+	{ 0, 10, 2, "Dot3ControlInUnknownOpcodes"		},
+	{ 0, 12, 2, "EtherStatsFragments"			},
+	{ 0, 14, 2, "EtherStatsJabbers"				},
+	{ 0, 16, 2, "IfInUcastPkts"				},
+	{ 0, 18, 2, "EtherStatsDropEvents"			},
+	{ 0, 20, 4, "EtherStatsOctets"				},
+
+	{ 0, 24, 2, "EtherStatsUnderSizePkts"			},
+	{ 0, 26, 2, "EtherOversizeStats"			},
+	{ 0, 28, 2, "EtherStatsPkts64Octets"			},
+	{ 0, 30, 2, "EtherStatsPkts65to127Octets"		},
+	{ 0, 32, 2, "EtherStatsPkts128to255Octets"		},
+	{ 0, 34, 2, "EtherStatsPkts256to511Octets"		},
+	{ 0, 36, 2, "EtherStatsPkts512to1023Octets"		},
+	{ 0, 38, 2, "EtherStatsPkts1024to1518Octets"		},
+	{ 0, 40, 2, "EtherStatsMulticastPkts"			},
+	{ 0, 42, 2, "EtherStatsBroadcastPkts"			},
+
+	{ 0, 44, 4, "IfOutOctets"				},
+
+	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
+	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
+	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
+	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
+	{ 0, 56, 2, "EtherStatsCollisions"			},
+	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
+	{ 0, 60, 2, "Dot3OutPauseFrames"			},
+	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
+	{ 0, 64, 2, "Dot1dTpPortInDiscards"			},
+	{ 0, 66, 2, "IfOutUcastPkts"				},
+	{ 0, 68, 2, "IfOutMulticastPkts"			},
+	{ 0, 70, 2, "IfOutBroadcastPkts"			},
+	{ 0, 72, 2, "OutOampduPkts"				},
+	{ 0, 74, 2, "InOampduPkts"				},
+	{ 0, 76, 2, "PktgenPkts"				},
+};
+
+#define REG_RD(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_read_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static const struct rtl8367_initval rtl8367_initvals_0_0[] = {
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006},
+	{0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412},
+	{0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0},
+	{0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4},
+	{0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7},
+	{0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003},
+	{0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2},
+	{0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207},
+	{0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620},
+	{0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede},
+	{0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1},
+	{0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00},
+	{0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002},
+	{0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000},
+	{0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f},
+	{0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A},
+	{0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005},
+	{0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA},
+	{0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055},
+	{0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354},
+	{0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB},
+	{0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1006}, {0x121e, 0x03e8},
+	{0x121f, 0x02b3}, {0x1220, 0x028f}, {0x1221, 0x029b}, {0x1222, 0x0277},
+	{0x1223, 0x02b3}, {0x1224, 0x028f}, {0x1225, 0x029b}, {0x1226, 0x0277},
+	{0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, {0x1230, 0x00b4},
+	{0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024},
+	{0x0219, 0x0032}, {0x0200, 0x03e8}, {0x0201, 0x03e8}, {0x0202, 0x03e8},
+	{0x0203, 0x03e8}, {0x0204, 0x03e8}, {0x0205, 0x03e8}, {0x0206, 0x03e8},
+	{0x0207, 0x03e8}, {0x0218, 0x0032}, {0x0208, 0x029b}, {0x0209, 0x029b},
+	{0x020a, 0x029b}, {0x020b, 0x029b}, {0x020c, 0x029b}, {0x020d, 0x029b},
+	{0x020e, 0x029b}, {0x020f, 0x029b}, {0x0210, 0x029b}, {0x0211, 0x029b},
+	{0x0212, 0x029b}, {0x0213, 0x029b}, {0x0214, 0x029b}, {0x0215, 0x029b},
+	{0x0216, 0x029b}, {0x0217, 0x029b}, {0x0900, 0x0000}, {0x0901, 0x0000},
+	{0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000},
+	{0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100},
+	{0x0802, 0x0100}, {0x1700, 0x014C}, {0x0301, 0x00FF}, {0x12AA, 0x0096},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4},
+	{0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340},
+	{0x133f, 0x0010}, {0x20A0, 0x1940}, {0x20C0, 0x1940}, {0x20E0, 0x1940},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_0_1[] = {
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006},
+	{0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412},
+	{0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0},
+	{0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4},
+	{0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7},
+	{0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003},
+	{0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2},
+	{0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207},
+	{0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620},
+	{0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede},
+	{0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1},
+	{0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00},
+	{0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002},
+	{0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000},
+	{0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f},
+	{0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A},
+	{0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005},
+	{0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA},
+	{0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055},
+	{0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354},
+	{0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB},
+	{0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1b06}, {0x121e, 0x07f0},
+	{0x121f, 0x0438}, {0x1220, 0x040f}, {0x1221, 0x040f}, {0x1222, 0x03eb},
+	{0x1223, 0x0438}, {0x1224, 0x040f}, {0x1225, 0x040f}, {0x1226, 0x03eb},
+	{0x1227, 0x0144}, {0x1228, 0x0138}, {0x122f, 0x0144}, {0x1230, 0x0138},
+	{0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024},
+	{0x0219, 0x0032}, {0x0200, 0x07d0}, {0x0201, 0x07d0}, {0x0202, 0x07d0},
+	{0x0203, 0x07d0}, {0x0204, 0x07d0}, {0x0205, 0x07d0}, {0x0206, 0x07d0},
+	{0x0207, 0x07d0}, {0x0218, 0x0032}, {0x0208, 0x0190}, {0x0209, 0x0190},
+	{0x020a, 0x0190}, {0x020b, 0x0190}, {0x020c, 0x0190}, {0x020d, 0x0190},
+	{0x020e, 0x0190}, {0x020f, 0x0190}, {0x0210, 0x0190}, {0x0211, 0x0190},
+	{0x0212, 0x0190}, {0x0213, 0x0190}, {0x0214, 0x0190}, {0x0215, 0x0190},
+	{0x0216, 0x0190}, {0x0217, 0x0190}, {0x0900, 0x0000}, {0x0901, 0x0000},
+	{0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000},
+	{0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100},
+	{0x0802, 0x0100}, {0x1700, 0x0125}, {0x0301, 0x00FF}, {0x12AA, 0x0096},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4},
+	{0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340},
+	{0x133f, 0x0010},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_1_0[] = {
+	{0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000},
+	{0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030},
+	{0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82},
+	{0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938},
+	{0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001},
+	{0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007},
+	{0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C},
+	{0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080},
+	{0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0},
+	{0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7},
+	{0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A},
+	{0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D},
+	{0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806},
+	{0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5},
+	{0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB},
+	{0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0},
+	{0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89},
+	{0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF},
+	{0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640},
+	{0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729},
+	{0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00},
+	{0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B},
+	{0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32},
+	{0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52},
+	{0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C},
+	{0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D},
+	{0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053},
+	{0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B},
+	{0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771},
+	{0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7},
+	{0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A},
+	{0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600},
+	{0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000},
+	{0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65},
+	{0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007},
+	{0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010},
+	{0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115},
+	{0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C},
+	{0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4},
+	{0x121D, 0x7D16}, {0x121E, 0x03E8}, {0x121F, 0x024E}, {0x1220, 0x0230},
+	{0x1221, 0x0244}, {0x1222, 0x0226}, {0x1223, 0x024E}, {0x1224, 0x0230},
+	{0x1225, 0x0244}, {0x1226, 0x0226}, {0x1227, 0x00C0}, {0x1228, 0x00B4},
+	{0x122F, 0x00C0}, {0x1230, 0x00B4}, {0x0208, 0x03E8}, {0x0209, 0x03E8},
+	{0x020A, 0x03E8}, {0x020B, 0x03E8}, {0x020C, 0x03E8}, {0x020D, 0x03E8},
+	{0x020E, 0x03E8}, {0x020F, 0x03E8}, {0x0210, 0x03E8}, {0x0211, 0x03E8},
+	{0x0212, 0x03E8}, {0x0213, 0x03E8}, {0x0214, 0x03E8}, {0x0215, 0x03E8},
+	{0x0216, 0x03E8}, {0x0217, 0x03E8}, {0x0900, 0x0000}, {0x0901, 0x0000},
+	{0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087B, 0x0000},
+	{0x087C, 0xFF00}, {0x087D, 0x0000}, {0x087E, 0x0000}, {0x0801, 0x0100},
+	{0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040},
+	{0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040},
+	{0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, {0x2200, 0x1340},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x20A0, 0x1940},
+	{0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_1_1[] = {
+	{0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000},
+	{0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030},
+	{0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82},
+	{0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938},
+	{0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001},
+	{0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007},
+	{0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C},
+	{0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080},
+	{0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0},
+	{0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7},
+	{0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A},
+	{0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D},
+	{0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806},
+	{0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5},
+	{0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB},
+	{0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0},
+	{0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89},
+	{0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF},
+	{0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640},
+	{0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729},
+	{0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00},
+	{0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B},
+	{0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32},
+	{0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52},
+	{0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C},
+	{0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D},
+	{0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053},
+	{0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B},
+	{0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771},
+	{0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7},
+	{0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A},
+	{0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600},
+	{0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000},
+	{0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65},
+	{0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007},
+	{0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010},
+	{0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115},
+	{0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C},
+	{0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4},
+	{0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000},
+	{0x0865, 0x3210}, {0x087B, 0x0000}, {0x087C, 0xFF00}, {0x087D, 0x0000},
+	{0x087E, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040},
+	{0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040},
+	{0x0A25, 0x2040}, {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040},
+	{0x0A29, 0x2040}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000},
+	{0x2200, 0x1340}, {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE},
+	{0x1B03, 0x0876},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_2_0[] = {
+	{0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8},
+	{0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207},
+	{0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000},
+	{0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005},
+	{0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000},
+	{0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7},
+	{0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e},
+	{0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201},
+	{0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e},
+	{0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000},
+	{0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00},
+	{0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6},
+	{0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140},
+	{0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4},
+	{0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa},
+	{0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a},
+	{0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978},
+	{0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806},
+	{0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5},
+	{0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425},
+	{0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e},
+	{0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68},
+	{0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d},
+	{0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365},
+	{0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d},
+	{0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036},
+	{0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce},
+	{0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530},
+	{0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a},
+	{0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100},
+	{0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306},
+	{0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77},
+	{0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f},
+	{0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405},
+	{0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010},
+	{0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x7D16},
+	{0x121e, 0x03e8}, {0x121f, 0x024e}, {0x1220, 0x0230}, {0x1221, 0x0244},
+	{0x1222, 0x0226}, {0x1223, 0x024e}, {0x1224, 0x0230}, {0x1225, 0x0244},
+	{0x1226, 0x0226}, {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0},
+	{0x1230, 0x00b4}, {0x0208, 0x03e8}, {0x0209, 0x03e8}, {0x020a, 0x03e8},
+	{0x020b, 0x03e8}, {0x020c, 0x03e8}, {0x020d, 0x03e8}, {0x020e, 0x03e8},
+	{0x020f, 0x03e8}, {0x0210, 0x03e8}, {0x0211, 0x03e8}, {0x0212, 0x03e8},
+	{0x0213, 0x03e8}, {0x0214, 0x03e8}, {0x0215, 0x03e8}, {0x0216, 0x03e8},
+	{0x0217, 0x03e8}, {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000},
+	{0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, {0x087c, 0xff00},
+	{0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100},
+	{0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040},
+	{0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, {0x20A0, 0x1940},
+	{0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_2_1[] = {
+	{0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8},
+	{0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207},
+	{0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000},
+	{0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005},
+	{0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000},
+	{0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7},
+	{0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e},
+	{0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201},
+	{0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e},
+	{0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000},
+	{0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00},
+	{0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6},
+	{0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140},
+	{0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4},
+	{0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa},
+	{0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a},
+	{0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978},
+	{0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806},
+	{0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5},
+	{0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425},
+	{0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e},
+	{0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68},
+	{0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d},
+	{0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365},
+	{0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d},
+	{0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036},
+	{0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce},
+	{0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530},
+	{0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a},
+	{0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100},
+	{0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306},
+	{0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77},
+	{0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f},
+	{0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405},
+	{0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010},
+	{0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x0900, 0x0000},
+	{0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210},
+	{0x087b, 0x0000}, {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000},
+	{0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040},
+	{0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A25, 0x2040},
+	{0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040},
+	{0x130c, 0x0050},
+};
+
+static int rtl8367_write_initvals(struct rtl8366_smi *smi,
+				  const struct rtl8367_initval *initvals,
+				  int count)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < count; i++)
+		REG_WR(smi, initvals[i].reg, initvals[i].val);
+
+	return 0;
+}
+
+static int rtl8367_read_phy_reg(struct rtl8366_smi *smi,
+				u32 phy_addr, u32 phy_reg, u32 *val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	if (phy_addr > RTL8367_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+	if (data & RTL8367_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* prepare address */
+	REG_WR(smi, RTL8367_IA_ADDRESS_REG,
+	       RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send read command */
+	REG_WR(smi, RTL8367_IA_CTRL_REG,
+	       RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_READ);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+		if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy read timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	/* read data */
+	REG_RD(smi, RTL8367_IA_READ_DATA_REG, val);
+
+	dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, *val);
+	return 0;
+}
+
+static int rtl8367_write_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_addr, u32 phy_reg, u32 val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, val);
+
+	if (phy_addr > RTL8367_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+	if (data & RTL8367_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* preapre data */
+	REG_WR(smi, RTL8367_IA_WRITE_DATA_REG, val);
+
+	/* prepare address */
+	REG_WR(smi, RTL8367_IA_ADDRESS_REG,
+	       RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send write command */
+	REG_WR(smi, RTL8367_IA_CTRL_REG,
+	       RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_WRITE);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+		if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy write timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	return 0;
+}
+
+static int rtl8367_init_regs0(struct rtl8366_smi *smi, unsigned mode)
+{
+	const struct rtl8367_initval *initvals;
+	int count;
+	int err;
+
+	switch (mode) {
+	case 0:
+		initvals = rtl8367_initvals_0_0;
+		count = ARRAY_SIZE(rtl8367_initvals_0_0);
+		break;
+
+	case 1:
+	case 2:
+		initvals = rtl8367_initvals_0_1;
+		count = ARRAY_SIZE(rtl8367_initvals_0_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode);
+		return -ENODEV;
+	}
+
+	err = rtl8367_write_initvals(smi, initvals, count);
+	if (err)
+		return err;
+
+	/* TODO: complete this */
+
+	return 0;
+}
+
+static int rtl8367_init_regs1(struct rtl8366_smi *smi, unsigned mode)
+{
+	const struct rtl8367_initval *initvals;
+	int count;
+
+	switch (mode) {
+	case 0:
+		initvals = rtl8367_initvals_1_0;
+		count = ARRAY_SIZE(rtl8367_initvals_1_0);
+		break;
+
+	case 1:
+	case 2:
+		initvals = rtl8367_initvals_1_1;
+		count = ARRAY_SIZE(rtl8367_initvals_1_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode);
+		return -ENODEV;
+	}
+
+	return rtl8367_write_initvals(smi, initvals, count);
+}
+
+static int rtl8367_init_regs2(struct rtl8366_smi *smi, unsigned mode)
+{
+	const struct rtl8367_initval *initvals;
+	int count;
+
+	switch (mode) {
+	case 0:
+		initvals = rtl8367_initvals_2_0;
+		count = ARRAY_SIZE(rtl8367_initvals_2_0);
+		break;
+
+	case 1:
+	case 2:
+		initvals = rtl8367_initvals_2_1;
+		count = ARRAY_SIZE(rtl8367_initvals_2_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode);
+		return -ENODEV;
+	}
+
+	return rtl8367_write_initvals(smi, initvals, count);
+}
+
+static int rtl8367_init_regs(struct rtl8366_smi *smi)
+{
+	u32 data;
+	u32 rlvid;
+	u32 mode;
+	int err;
+
+	REG_WR(smi, RTL8367_RTL_MAGIC_ID_REG, RTL8367_RTL_MAGIC_ID_VAL);
+
+	REG_RD(smi, RTL8367_CHIP_VER_REG, &data);
+	rlvid = (data >> RTL8367_CHIP_VER_RLVID_SHIFT) &
+		RTL8367_CHIP_VER_RLVID_MASK;
+
+	REG_RD(smi, RTL8367_CHIP_MODE_REG, &data);
+	mode = data & RTL8367_CHIP_MODE_MASK;
+
+	switch (rlvid) {
+	case 0:
+		err = rtl8367_init_regs0(smi, mode);
+		break;
+
+	case 1:
+		err = rtl8367_write_phy_reg(smi, 0, 31, 5);
+		if (err)
+			break;
+
+		err = rtl8367_write_phy_reg(smi, 0, 5, 0x3ffe);
+		if (err)
+			break;
+
+		err = rtl8367_read_phy_reg(smi, 0, 6, &data);
+		if (err)
+			break;
+
+		if (data == 0x94eb) {
+			err = rtl8367_init_regs1(smi, mode);
+		} else if (data == 0x2104) {
+			err = rtl8367_init_regs2(smi, mode);
+		} else {
+			dev_err(smi->parent, "unknow phy data %04x\n", data);
+			return -ENODEV;
+		}
+
+		break;
+
+	default:
+		dev_err(smi->parent, "unknow rlvid %u\n", rlvid);
+		err = -ENODEV;
+		break;
+	}
+
+	return err;
+}
+
+static int rtl8367_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	int err;
+	u32 data;
+
+	REG_WR(smi, RTL8367_CHIP_RESET_REG, RTL8367_CHIP_RESET_HW);
+	msleep(RTL8367_RESET_DELAY);
+
+	do {
+		REG_RD(smi, RTL8367_CHIP_RESET_REG, &data);
+		if (!(data & RTL8367_CHIP_RESET_HW))
+			break;
+
+		msleep(1);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_err(smi->parent, "chip reset timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rtl8367_extif_set_mode(struct rtl8366_smi *smi, int id,
+				  enum rtl8367_extif_mode mode)
+{
+	int err;
+
+	/* set port mode */
+	switch (mode) {
+	case RTL8367_EXTIF_MODE_RGMII:
+	case RTL8367_EXTIF_MODE_RGMII_33V:
+		REG_WR(smi, RTL8367_CHIP_DEBUG0_REG, 0x0367);
+		REG_WR(smi, RTL8367_CHIP_DEBUG1_REG, 0x7777);
+		break;
+
+	case RTL8367_EXTIF_MODE_TMII_MAC:
+	case RTL8367_EXTIF_MODE_TMII_PHY:
+		REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG,
+			BIT((id + 1) % 2), BIT((id + 1) % 2));
+		break;
+
+	case RTL8367_EXTIF_MODE_GMII:
+		REG_RMW(smi, RTL8367_CHIP_DEBUG0_REG,
+		        RTL8367_CHIP_DEBUG0_DUMMY0(id),
+			RTL8367_CHIP_DEBUG0_DUMMY0(id));
+		REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), BIT(6));
+		break;
+
+	case RTL8367_EXTIF_MODE_MII_MAC:
+	case RTL8367_EXTIF_MODE_MII_PHY:
+	case RTL8367_EXTIF_MODE_DISABLED:
+		REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG,
+			BIT((id + 1) % 2), 0);
+		REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), 0);
+		break;
+
+	default:
+		dev_err(smi->parent,
+			"invalid mode for external interface %d\n", id);
+		return -EINVAL;
+	}
+
+	REG_RMW(smi, RTL8367_DIS_REG,
+		RTL8367_DIS_RGMII_MASK << RTL8367_DIS_RGMII_SHIFT(id),
+		mode << RTL8367_DIS_RGMII_SHIFT(id));
+
+	return 0;
+}
+
+static int rtl8367_extif_set_force(struct rtl8366_smi *smi, int id,
+				   struct rtl8367_port_ability *pa)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367_DI_FORCE_MODE |
+		RTL8367_DI_FORCE_NWAY |
+		RTL8367_DI_FORCE_TXPAUSE |
+		RTL8367_DI_FORCE_RXPAUSE |
+		RTL8367_DI_FORCE_LINK |
+		RTL8367_DI_FORCE_DUPLEX |
+		RTL8367_DI_FORCE_SPEED_MASK);
+
+	val = pa->speed;
+	val |= pa->force_mode ? RTL8367_DI_FORCE_MODE : 0;
+	val |= pa->nway ? RTL8367_DI_FORCE_NWAY : 0;
+	val |= pa->txpause ? RTL8367_DI_FORCE_TXPAUSE : 0;
+	val |= pa->rxpause ? RTL8367_DI_FORCE_RXPAUSE : 0;
+	val |= pa->link ? RTL8367_DI_FORCE_LINK : 0;
+	val |= pa->duplex ? RTL8367_DI_FORCE_DUPLEX : 0;
+
+	REG_RMW(smi, RTL8367_DI_FORCE_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id,
+					 unsigned txdelay, unsigned rxdelay)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367_EXT_RGMXF_RXDELAY_MASK |
+		(RTL8367_EXT_RGMXF_TXDELAY_MASK <<
+			RTL8367_EXT_RGMXF_TXDELAY_SHIFT));
+
+	val = rxdelay;
+	val |= txdelay << RTL8367_EXT_RGMXF_TXDELAY_SHIFT;
+
+	REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367_extif_init(struct rtl8366_smi *smi, int id,
+			      struct rtl8367_extif_config *cfg)
+{
+	enum rtl8367_extif_mode mode;
+	int err;
+
+	mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED;
+
+	err = rtl8367_extif_set_mode(smi, id, mode);
+	if (err)
+		return err;
+
+	if (mode != RTL8367_EXTIF_MODE_DISABLED) {
+		err = rtl8367_extif_set_force(smi, id, &cfg->ability);
+		if (err)
+			return err;
+
+		err = rtl8367_extif_set_rgmii_delay(smi, id, cfg->txdelay,
+						     cfg->rxdelay);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rtl8367_led_group_set_ports(struct rtl8366_smi *smi,
+				       unsigned int group, u16 port_mask)
+{
+	u32 reg;
+	u32 s;
+	int err;
+
+	port_mask &= RTL8367_PARA_LED_IO_EN_PMASK;
+	s = (group % 2) * 8;
+	reg = RTL8367_PARA_LED_IO_EN1_REG + (group / 2);
+
+	REG_RMW(smi, reg, (RTL8367_PARA_LED_IO_EN_PMASK << s), port_mask << s);
+
+	return 0;
+}
+
+static int rtl8367_led_group_set_mode(struct rtl8366_smi *smi,
+				      unsigned int mode)
+{
+	u16 mask;
+	u16 set;
+	int err;
+
+	mode &= RTL8367_LED_CONFIG_DATA_M;
+
+	mask = (RTL8367_LED_CONFIG_DATA_M << RTL8367_LED_CONFIG_DATA_S) |
+		RTL8367_LED_CONFIG_SEL;
+	set = (mode << RTL8367_LED_CONFIG_DATA_S) | RTL8367_LED_CONFIG_SEL;
+
+	REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set);
+
+	return 0;
+}
+
+static int rtl8367_led_group_set_config(struct rtl8366_smi *smi,
+				        unsigned int led, unsigned int cfg)
+{
+	u16 mask;
+	u16 set;
+	int err;
+
+	mask = (RTL8367_LED_CONFIG_LED_CFG_M << (led * 4)) |
+		RTL8367_LED_CONFIG_SEL;
+	set = (cfg & RTL8367_LED_CONFIG_LED_CFG_M) << (led * 4);
+
+	REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set);
+	return 0;
+}
+
+static int rtl8367_led_op_select_parallel(struct rtl8366_smi *smi)
+{
+	int err;
+
+	REG_WR(smi, RTL8367_LED_SYS_CONFIG_REG, 0x1472);
+	return 0;
+}
+
+static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate)
+{
+	u16 mask;
+	u16 set;
+	int err;
+
+	mask = RTL8367_LED_MODE_RATE_M << RTL8367_LED_MODE_RATE_S;
+	set = (rate & RTL8367_LED_MODE_RATE_M) << RTL8367_LED_MODE_RATE_S;
+	REG_RMW(smi, RTL8367_LED_MODE_REG, mask, set);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id,
+				 const char *name)
+{
+	struct rtl8367_extif_config *cfg;
+	const __be32 *prop;
+	int size;
+	int err;
+
+	prop = of_get_property(smi->parent->of_node, name, &size);
+	if (!prop)
+		return rtl8367_extif_init(smi, id, NULL);
+
+	if (size != (9 * sizeof(*prop))) {
+		dev_err(smi->parent, "%s property is invalid\n", name);
+		return -EINVAL;
+	}
+
+	cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	cfg->txdelay = be32_to_cpup(prop++);
+	cfg->rxdelay = be32_to_cpup(prop++);
+	cfg->mode = be32_to_cpup(prop++);
+	cfg->ability.force_mode = be32_to_cpup(prop++);
+	cfg->ability.txpause = be32_to_cpup(prop++);
+	cfg->ability.rxpause = be32_to_cpup(prop++);
+	cfg->ability.link = be32_to_cpup(prop++);
+	cfg->ability.duplex = be32_to_cpup(prop++);
+	cfg->ability.speed = be32_to_cpup(prop++);
+
+	err = rtl8367_extif_init(smi, id, cfg);
+	kfree(cfg);
+
+	return err;
+}
+#else
+static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id,
+				 const char *name)
+{
+	return -EINVAL;
+}
+#endif
+
+static int rtl8367_setup(struct rtl8366_smi *smi)
+{
+	struct rtl8367_platform_data *pdata;
+	int err;
+	int i;
+
+	pdata = smi->parent->platform_data;
+
+	err = rtl8367_init_regs(smi);
+	if (err)
+		return err;
+
+	/* initialize external interfaces */
+	if (smi->parent->of_node) {
+		err = rtl8367_extif_init_of(smi, 0, "realtek,extif0");
+		if (err)
+			return err;
+
+		err = rtl8367_extif_init_of(smi, 1, "realtek,extif1");
+		if (err)
+			return err;
+	} else {
+		err = rtl8367_extif_init(smi, 0, pdata->extif0_cfg);
+		if (err)
+			return err;
+
+		err = rtl8367_extif_init(smi, 1, pdata->extif1_cfg);
+		if (err)
+			return err;
+	}
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8367_SWC0_REG, RTL8367_SWC0_MAX_LENGTH_MASK,
+		RTL8367_SWC0_MAX_LENGTH_1536);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8367_VLAN_INGRESS_REG, RTL8367_PORTS_ALL);
+
+	/*
+	 * Setup egress tag mode for each port.
+	 */
+	for (i = 0; i < RTL8367_NUM_PORTS; i++)
+		REG_RMW(smi,
+			RTL8367_PORT_CFG_REG(i),
+			RTL8367_PORT_CFG_EGRESS_MODE_MASK <<
+				RTL8367_PORT_CFG_EGRESS_MODE_SHIFT,
+			RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL <<
+				RTL8367_PORT_CFG_EGRESS_MODE_SHIFT);
+
+	/* setup LEDs */
+	err = rtl8367_led_group_set_ports(smi, 0, RTL8367_PORTS_ALL);
+	if (err)
+		return err;
+
+	err = rtl8367_led_group_set_mode(smi, 0);
+	if (err)
+		return err;
+
+	err = rtl8367_led_op_select_parallel(smi);
+	if (err)
+		return err;
+
+	err = rtl8367_led_blinkrate_set(smi, 1);
+	if (err)
+		return err;
+
+	err = rtl8367_led_group_set_config(smi, 0, 2);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int rtl8367_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				   int port, unsigned long long *val)
+{
+	struct rtl8366_mib_counter *mib;
+	int offset;
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8367_NUM_PORTS || counter >= RTL8367_MIB_COUNT)
+		return -EINVAL;
+
+	mib = &rtl8367_mib_counters[counter];
+	addr = RTL8367_MIB_COUNTER_PORT_OFFSET * port + mib->offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	REG_WR(smi, RTL8367_MIB_ADDRESS_REG, addr >> 2);
+
+	/* read MIB control register */
+	REG_RD(smi, RTL8367_MIB_CTRL_REG(0), &data);
+
+	if (data & RTL8367_MIB_CTRL_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8367_MIB_CTRL_RESET_MASK)
+		return -EIO;
+
+	if (mib->length == 4)
+		offset = 3;
+	else
+		offset = (mib->offset + 1) % 4;
+
+	mibvalue = 0;
+	for (i = 0; i < mib->length; i++) {
+		REG_RD(smi, RTL8367_MIB_COUNTER_REG(offset - i), &data);
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8367_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367_TA_VLAN_DATA_SIZE];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8367_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	REG_WR(smi, RTL8367_TA_ADDR_REG, vid);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_READ);
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367_TA_DATA_REG(i), &data[i]);
+
+	vlan4k->vid = vid;
+	vlan4k->member = (data[0] >> RTL8367_TA_VLAN_MEMBER_SHIFT) &
+			 RTL8367_TA_VLAN_MEMBER_MASK;
+	vlan4k->fid = (data[1] >> RTL8367_TA_VLAN_FID_SHIFT) &
+		      RTL8367_TA_VLAN_FID_MASK;
+	vlan4k->untag = (data[2] >> RTL8367_TA_VLAN_UNTAG1_SHIFT) &
+			RTL8367_TA_VLAN_UNTAG1_MASK;
+	vlan4k->untag |= ((data[3] >> RTL8367_TA_VLAN_UNTAG2_SHIFT) &
+			  RTL8367_TA_VLAN_UNTAG2_MASK) << 2;
+
+	return 0;
+}
+
+static int rtl8367_set_vlan_4k(struct rtl8366_smi *smi,
+				const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367_TA_VLAN_DATA_SIZE];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8367_NUM_VIDS ||
+	    vlan4k->member > RTL8367_TA_VLAN_MEMBER_MASK ||
+	    vlan4k->untag > RTL8367_UNTAG_MASK ||
+	    vlan4k->fid > RTL8367_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlan4k->member & RTL8367_TA_VLAN_MEMBER_MASK) <<
+		  RTL8367_TA_VLAN_MEMBER_SHIFT;
+	data[1] = (vlan4k->fid & RTL8367_TA_VLAN_FID_MASK) <<
+		  RTL8367_TA_VLAN_FID_SHIFT;
+	data[2] = (vlan4k->untag & RTL8367_TA_VLAN_UNTAG1_MASK) <<
+		  RTL8367_TA_VLAN_UNTAG1_SHIFT;
+	data[3] = ((vlan4k->untag >> 2) & RTL8367_TA_VLAN_UNTAG2_MASK) <<
+		  RTL8367_TA_VLAN_UNTAG2_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367_TA_DATA_REG(i), data[i]);
+
+	/* write VID */
+	REG_WR(smi, RTL8367_TA_ADDR_REG,
+	       vlan4k->vid & RTL8367_TA_VLAN_VID_MASK);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_WRITE);
+
+	return 0;
+}
+
+static int rtl8367_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367_VLAN_MC_DATA_SIZE];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8367_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367_VLAN_MC_BASE(index) + i, &data[i]);
+
+	vlanmc->member = (data[0] >> RTL8367_VLAN_MC_MEMBER_SHIFT) &
+			 RTL8367_VLAN_MC_MEMBER_MASK;
+	vlanmc->fid = (data[1] >> RTL8367_VLAN_MC_FID_SHIFT) &
+		      RTL8367_VLAN_MC_FID_MASK;
+	vlanmc->vid = (data[3] >> RTL8367_VLAN_MC_EVID_SHIFT) &
+		      RTL8367_VLAN_MC_EVID_MASK;
+
+	return 0;
+}
+
+static int rtl8367_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367_VLAN_MC_DATA_SIZE];
+	int err;
+	int i;
+
+	if (index >= RTL8367_NUM_VLANS ||
+	    vlanmc->vid >= RTL8367_NUM_VIDS ||
+	    vlanmc->priority > RTL8367_PRIORITYMAX ||
+	    vlanmc->member > RTL8367_VLAN_MC_MEMBER_MASK ||
+	    vlanmc->untag > RTL8367_UNTAG_MASK ||
+	    vlanmc->fid > RTL8367_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->member & RTL8367_VLAN_MC_MEMBER_MASK) <<
+		  RTL8367_VLAN_MC_MEMBER_SHIFT;
+	data[1] = (vlanmc->fid & RTL8367_VLAN_MC_FID_MASK) <<
+		  RTL8367_VLAN_MC_FID_SHIFT;
+	data[2] = 0;
+	data[3] = (vlanmc->vid & RTL8367_VLAN_MC_EVID_MASK) <<
+		   RTL8367_VLAN_MC_EVID_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367_VLAN_MC_BASE(index) + i, data[i]);
+
+	return 0;
+}
+
+static int rtl8367_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8367_NUM_PORTS)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367_VLAN_PVID_CTRL_REG(port), &data);
+
+	*val = (data >> RTL8367_VLAN_PVID_CTRL_SHIFT(port)) &
+	       RTL8367_VLAN_PVID_CTRL_MASK;
+
+	return 0;
+}
+
+static int rtl8367_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8367_NUM_PORTS || index >= RTL8367_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367_VLAN_PVID_CTRL_REG(port),
+				RTL8367_VLAN_PVID_CTRL_MASK <<
+					RTL8367_VLAN_PVID_CTRL_SHIFT(port),
+				(index & RTL8367_VLAN_PVID_CTRL_MASK) <<
+					RTL8367_VLAN_PVID_CTRL_SHIFT(port));
+}
+
+static int rtl8367_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8367_VLAN_CTRL_REG,
+				RTL8367_VLAN_CTRL_ENABLE,
+				(enable) ? RTL8367_VLAN_CTRL_ENABLE : 0);
+}
+
+static int rtl8367_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return 0;
+}
+
+static int rtl8367_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8367_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8367_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8367_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	int err;
+
+	REG_WR(smi, RTL8367_PORT_ISOLATION_REG(port),
+	       (enable) ? RTL8367_PORTS_ALL : 0);
+
+	return 0;
+}
+
+static int rtl8367_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(0), 0,
+				RTL8367_MIB_CTRL_GLOBAL_RESET_MASK);
+}
+
+static int rtl8367_sw_get_port_link(struct switch_dev *dev,
+				    int port,
+				    struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8367_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8367_PORT_STATUS_REG(port), &data);
+
+	link->link = !!(data & RTL8367_PORT_STATUS_LINK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8367_PORT_STATUS_DUPLEX);
+	link->rx_flow = !!(data & RTL8367_PORT_STATUS_RXPAUSE);
+	link->tx_flow = !!(data & RTL8367_PORT_STATUS_TXPAUSE);
+	link->aneg = !!(data & RTL8367_PORT_STATUS_NWAY);
+
+	speed = (data & RTL8367_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8367_sw_get_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8367_SWC0_REG, &data);
+	val->value.i = (data & RTL8367_SWC0_MAX_LENGTH_MASK) >>
+			RTL8367_SWC0_MAX_LENGTH_SHIFT;
+
+	return 0;
+}
+
+static int rtl8367_sw_set_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 max_len;
+
+	switch (val->value.i) {
+	case 0:
+		max_len = RTL8367_SWC0_MAX_LENGTH_1522;
+		break;
+	case 1:
+		max_len = RTL8367_SWC0_MAX_LENGTH_1536;
+		break;
+	case 2:
+		max_len = RTL8367_SWC0_MAX_LENGTH_1552;
+		break;
+	case 3:
+		max_len = RTL8367_SWC0_MAX_LENGTH_16000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rtl8366_smi_rmwr(smi, RTL8367_SWC0_REG,
+			        RTL8367_SWC0_MAX_LENGTH_MASK, max_len);
+}
+
+
+static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int port;
+
+	port = val->port_vlan;
+	if (port >= RTL8367_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(port / 8), 0,
+				RTL8367_MIB_CTRL_PORT_RESET_MASK(port % 8));
+}
+
+static struct switch_attr rtl8367_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8367_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "max_length",
+		.description = "Get/Set the maximum length of valid packets"
+			       "(0:1522, 1:1536, 2:1552, 3:16000)",
+		.set = rtl8367_sw_set_max_length,
+		.get = rtl8367_sw_get_max_length,
+		.max = 3,
+	}
+};
+
+static struct switch_attr rtl8367_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8367_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr rtl8367_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "fid",
+		.description = "Get/Set vlan FID",
+		.max = RTL8367_FIDMAX,
+		.set = rtl8366_sw_set_vlan_fid,
+		.get = rtl8366_sw_get_vlan_fid,
+	},
+};
+
+static const struct switch_dev_ops rtl8367_sw_ops = {
+	.attr_global = {
+		.attr = rtl8367_globals,
+		.n_attr = ARRAY_SIZE(rtl8367_globals),
+	},
+	.attr_port = {
+		.attr = rtl8367_port,
+		.n_attr = ARRAY_SIZE(rtl8367_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8367_vlan,
+		.n_attr = ARRAY_SIZE(rtl8367_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8367_sw_get_port_link,
+};
+
+static int rtl8367_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8367";
+	dev->cpu_port = RTL8367_CPU_PORT_NUM;
+	dev->ports = RTL8367_NUM_PORTS;
+	dev->vlans = RTL8367_NUM_VIDS;
+	dev->ops = &rtl8367_sw_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8367_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8367_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8367_read_phy_reg(smi, addr, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8367_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8367_write_phy_reg(smi, addr, reg, val);
+	if (err)
+		return err;
+
+	/* flush write */
+	(void) rtl8367_read_phy_reg(smi, addr, reg, &t);
+
+	return err;
+}
+
+static int rtl8367_detect(struct rtl8366_smi *smi)
+{
+	u32 rtl_no = 0;
+	u32 rtl_ver = 0;
+	char *chip_name;
+	int ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_NO_REG, &rtl_no);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip number\n");
+		return ret;
+	}
+
+	switch (rtl_no) {
+	case RTL8367_RTL_NO_8367R:
+		chip_name = "8367R";
+		break;
+	case RTL8367_RTL_NO_8367M:
+		chip_name = "8367M";
+		break;
+	default:
+		dev_err(smi->parent, "unknown chip number (%04x)\n", rtl_no);
+		return -ENODEV;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_VER_REG, &rtl_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip version\n");
+		return ret;
+	}
+
+	dev_info(smi->parent, "RTL%s ver. %u chip found\n",
+		 chip_name, rtl_ver & RTL8367_RTL_VER_MASK);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8367_smi_ops = {
+	.detect		= rtl8367_detect,
+	.reset_chip	= rtl8367_reset_chip,
+	.setup		= rtl8367_setup,
+
+	.mii_read	= rtl8367_mii_read,
+	.mii_write	= rtl8367_mii_write,
+
+	.get_vlan_mc	= rtl8367_get_vlan_mc,
+	.set_vlan_mc	= rtl8367_set_vlan_mc,
+	.get_vlan_4k	= rtl8367_get_vlan_4k,
+	.set_vlan_4k	= rtl8367_set_vlan_4k,
+	.get_mc_index	= rtl8367_get_mc_index,
+	.set_mc_index	= rtl8367_set_mc_index,
+	.get_mib_counter = rtl8367_get_mib_counter,
+	.is_vlan_valid	= rtl8367_is_vlan_valid,
+	.enable_vlan	= rtl8367_enable_vlan,
+	.enable_vlan4k	= rtl8367_enable_vlan4k,
+	.enable_port	= rtl8367_enable_port,
+};
+
+static int rtl8367_probe(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi;
+	int err;
+
+	smi = rtl8366_smi_probe(pdev);
+	if (!smi)
+		return -ENODEV;
+
+	smi->clk_delay = 1500;
+	smi->cmd_read = 0xb9;
+	smi->cmd_write = 0xb8;
+	smi->ops = &rtl8367_smi_ops;
+	smi->cpu_port = RTL8367_CPU_PORT_NUM;
+	smi->num_ports = RTL8367_NUM_PORTS;
+	smi->num_vlan_mc = RTL8367_NUM_VLANS;
+	smi->mib_counters = rtl8367_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8367_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8367_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8367_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8367_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+static void rtl8367_shutdown(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi)
+		rtl8367_reset_chip(smi);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8367_match[] = {
+       { .compatible = "realtek,rtl8367" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rtl8367_match);
+#endif
+
+static struct platform_driver rtl8367_driver = {
+	.driver = {
+		.name		= RTL8367_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(rtl8367_match),
+#endif
+	},
+	.probe		= rtl8367_probe,
+	.remove		= rtl8367_remove,
+	.shutdown	= rtl8367_shutdown,
+};
+
+static int __init rtl8367_module_init(void)
+{
+	return platform_driver_register(&rtl8367_driver);
+}
+module_init(rtl8367_module_init);
+
+static void __exit rtl8367_module_exit(void)
+{
+	platform_driver_unregister(&rtl8367_driver);
+}
+module_exit(rtl8367_module_exit);
+
+MODULE_DESCRIPTION("Realtek RTL8367 ethernet switch driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8367_DRIVER_NAME);
diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c
new file mode 100644
index 0000000000..a73e35ed2d
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c
@@ -0,0 +1,1602 @@
+/*
+ * Platform driver for the Realtek RTL8367R-VB ethernet switches
+ *
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8367.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8367B_RESET_DELAY	1000	/* msecs*/
+
+#define RTL8367B_PHY_ADDR_MAX	8
+#define RTL8367B_PHY_REG_MAX	31
+
+#define RTL8367B_VID_MASK	0x3fff
+#define RTL8367B_FID_MASK	0xf
+#define RTL8367B_UNTAG_MASK	0xff
+#define RTL8367B_MEMBER_MASK	0xff
+
+#define RTL8367B_PORT_MISC_CFG_REG(_p)		(0x000e + 0x20 * (_p))
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT	4
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK	0x3
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL	0
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_KEEP	1
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_PRI	2
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_REAL	3
+
+#define RTL8367B_BYPASS_LINE_RATE_REG		0x03f7
+
+#define RTL8367B_TA_CTRL_REG			0x0500 /*GOOD*/
+#define   RTL8367B_TA_CTRL_SPA_SHIFT		8
+#define   RTL8367B_TA_CTRL_SPA_MASK		0x7
+#define   RTL8367B_TA_CTRL_METHOD		BIT(4)/*GOOD*/
+#define   RTL8367B_TA_CTRL_CMD_SHIFT		3
+#define   RTL8367B_TA_CTRL_CMD_READ		0
+#define   RTL8367B_TA_CTRL_CMD_WRITE		1
+#define   RTL8367B_TA_CTRL_TABLE_SHIFT		0 /*GOOD*/
+#define   RTL8367B_TA_CTRL_TABLE_ACLRULE	1
+#define   RTL8367B_TA_CTRL_TABLE_ACLACT		2
+#define   RTL8367B_TA_CTRL_TABLE_CVLAN		3
+#define   RTL8367B_TA_CTRL_TABLE_L2		4
+#define   RTL8367B_TA_CTRL_CVLAN_READ \
+		((RTL8367B_TA_CTRL_CMD_READ << RTL8367B_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367B_TA_CTRL_TABLE_CVLAN)
+#define   RTL8367B_TA_CTRL_CVLAN_WRITE \
+		((RTL8367B_TA_CTRL_CMD_WRITE << RTL8367B_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367B_TA_CTRL_TABLE_CVLAN)
+
+#define RTL8367B_TA_ADDR_REG			0x0501/*GOOD*/
+#define   RTL8367B_TA_ADDR_MASK			0x3fff/*GOOD*/
+
+#define RTL8367B_TA_LUT_REG			0x0502/*GOOD*/
+
+#define RTL8367B_TA_WRDATA_REG(_x)		(0x0510 + (_x))/*GOOD*/
+#define   RTL8367B_TA_VLAN_NUM_WORDS		2
+#define   RTL8367B_TA_VLAN_VID_MASK		RTL8367B_VID_MASK
+#define   RTL8367B_TA_VLAN0_MEMBER_SHIFT	0
+#define   RTL8367B_TA_VLAN0_MEMBER_MASK		RTL8367B_MEMBER_MASK
+#define   RTL8367B_TA_VLAN0_UNTAG_SHIFT		8
+#define   RTL8367B_TA_VLAN0_UNTAG_MASK		RTL8367B_MEMBER_MASK
+#define   RTL8367B_TA_VLAN1_FID_SHIFT		0
+#define   RTL8367B_TA_VLAN1_FID_MASK		RTL8367B_FID_MASK
+
+#define RTL8367B_TA_RDDATA_REG(_x)		(0x0520 + (_x))/*GOOD*/
+
+#define RTL8367B_VLAN_PVID_CTRL_REG(_p)		(0x0700 + (_p) / 2) /*GOOD*/
+#define RTL8367B_VLAN_PVID_CTRL_MASK		0x1f /*GOOD*/
+#define RTL8367B_VLAN_PVID_CTRL_SHIFT(_p)	(8 * ((_p) % 2)) /*GOOD*/
+
+#define RTL8367B_VLAN_MC_BASE(_x)		(0x0728 + (_x) * 4) /*GOOD*/
+#define   RTL8367B_VLAN_MC_NUM_WORDS		4 /*GOOD*/
+#define   RTL8367B_VLAN_MC0_MEMBER_SHIFT	0/*GOOD*/
+#define   RTL8367B_VLAN_MC0_MEMBER_MASK		RTL8367B_MEMBER_MASK/*GOOD*/
+#define   RTL8367B_VLAN_MC1_FID_SHIFT		0/*GOOD*/
+#define   RTL8367B_VLAN_MC1_FID_MASK		RTL8367B_FID_MASK/*GOOD*/
+#define   RTL8367B_VLAN_MC3_EVID_SHIFT		0/*GOOD*/
+#define   RTL8367B_VLAN_MC3_EVID_MASK		RTL8367B_VID_MASK/*GOOD*/
+
+#define RTL8367B_VLAN_CTRL_REG			0x07a8 /*GOOD*/
+#define   RTL8367B_VLAN_CTRL_ENABLE		BIT(0)
+
+#define RTL8367B_VLAN_INGRESS_REG		0x07a9 /*GOOD*/
+
+#define RTL8367B_PORT_ISOLATION_REG(_p)		(0x08a2 + (_p)) /*GOOD*/
+
+#define RTL8367B_MIB_COUNTER_REG(_x)		(0x1000 + (_x))	/*GOOD*/
+#define RTL8367B_MIB_COUNTER_PORT_OFFSET	0x007c /*GOOD*/
+
+#define RTL8367B_MIB_ADDRESS_REG		0x1004 /*GOOD*/
+
+#define RTL8367B_MIB_CTRL0_REG(_x)		(0x1005 + (_x)) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK	BIT(11)	/*GOOD*/
+#define   RTL8367B_MIB_CTRL0_QM_RESET_MASK	BIT(10) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_PORT_RESET_MASK(_p) BIT(2 + (_p)) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_RESET_MASK		BIT(1) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_BUSY_MASK		BIT(0) /*GOOD*/
+
+#define RTL8367B_SWC0_REG			0x1200/*GOOD*/
+#define   RTL8367B_SWC0_MAX_LENGTH_SHIFT	13/*GOOD*/
+#define   RTL8367B_SWC0_MAX_LENGTH(_x)		((_x) << 13) /*GOOD*/
+#define   RTL8367B_SWC0_MAX_LENGTH_MASK		RTL8367B_SWC0_MAX_LENGTH(0x3)
+#define   RTL8367B_SWC0_MAX_LENGTH_1522		RTL8367B_SWC0_MAX_LENGTH(0)
+#define   RTL8367B_SWC0_MAX_LENGTH_1536		RTL8367B_SWC0_MAX_LENGTH(1)
+#define   RTL8367B_SWC0_MAX_LENGTH_1552		RTL8367B_SWC0_MAX_LENGTH(2)
+#define   RTL8367B_SWC0_MAX_LENGTH_16000	RTL8367B_SWC0_MAX_LENGTH(3)
+
+#define RTL8367B_CHIP_NUMBER_REG		0x1300/*GOOD*/
+
+#define RTL8367B_CHIP_VER_REG			0x1301/*GOOD*/
+#define   RTL8367B_CHIP_VER_RLVID_SHIFT		12/*GOOD*/
+#define   RTL8367B_CHIP_VER_RLVID_MASK		0xf/*GOOD*/
+#define   RTL8367B_CHIP_VER_MCID_SHIFT		8/*GOOD*/
+#define   RTL8367B_CHIP_VER_MCID_MASK		0xf/*GOOD*/
+#define   RTL8367B_CHIP_VER_BOID_SHIFT		4/*GOOD*/
+#define   RTL8367B_CHIP_VER_BOID_MASK		0xf/*GOOD*/
+#define   RTL8367B_CHIP_VER_AFE_SHIFT		0/*GOOD*/
+#define   RTL8367B_CHIP_VER_AFE_MASK		0x1/*GOOD*/
+
+#define RTL8367B_CHIP_MODE_REG			0x1302
+#define   RTL8367B_CHIP_MODE_MASK		0x7
+
+#define RTL8367B_CHIP_DEBUG0_REG		0x1303
+#define   RTL8367B_CHIP_DEBUG0_DUMMY0(_x)	BIT(8 + (_x))
+
+#define RTL8367B_CHIP_DEBUG1_REG		0x1304
+
+#define RTL8367B_DIS_REG			0x1305
+#define   RTL8367B_DIS_SKIP_MII_RXER(_x)	BIT(12 + (_x))
+#define   RTL8367B_DIS_RGMII_SHIFT(_x)		(4 * (_x))
+#define   RTL8367B_DIS_RGMII_MASK		0x7
+
+#define RTL8367B_EXT_RGMXF_REG(_x)		(0x1306 + (_x))
+#define   RTL8367B_EXT_RGMXF_DUMMY0_SHIFT	5
+#define   RTL8367B_EXT_RGMXF_DUMMY0_MASK	0x7ff
+#define   RTL8367B_EXT_RGMXF_TXDELAY_SHIFT	3
+#define   RTL8367B_EXT_RGMXF_TXDELAY_MASK	1
+#define   RTL8367B_EXT_RGMXF_RXDELAY_MASK	0x7
+
+#define RTL8367B_DI_FORCE_REG(_x)		(0x1310 + (_x))
+#define   RTL8367B_DI_FORCE_MODE		BIT(12)
+#define   RTL8367B_DI_FORCE_NWAY		BIT(7)
+#define   RTL8367B_DI_FORCE_TXPAUSE		BIT(6)
+#define   RTL8367B_DI_FORCE_RXPAUSE		BIT(5)
+#define   RTL8367B_DI_FORCE_LINK		BIT(4)
+#define   RTL8367B_DI_FORCE_DUPLEX		BIT(2)
+#define   RTL8367B_DI_FORCE_SPEED_MASK		3
+#define   RTL8367B_DI_FORCE_SPEED_10		0
+#define   RTL8367B_DI_FORCE_SPEED_100		1
+#define   RTL8367B_DI_FORCE_SPEED_1000		2
+
+#define RTL8367B_MAC_FORCE_REG(_x)		(0x1312 + (_x))
+
+#define RTL8367B_CHIP_RESET_REG			0x1322 /*GOOD*/
+#define   RTL8367B_CHIP_RESET_SW		BIT(1) /*GOOD*/
+#define   RTL8367B_CHIP_RESET_HW		BIT(0) /*GOOD*/
+
+#define RTL8367B_PORT_STATUS_REG(_p)		(0x1352 + (_p)) /*GOOD*/
+#define   RTL8367B_PORT_STATUS_EN_1000_SPI	BIT(11) /*GOOD*/
+#define   RTL8367B_PORT_STATUS_EN_100_SPI	BIT(10)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_NWAY_FAULT	BIT(9)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_LINK_MASTER	BIT(8)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_NWAY		BIT(7)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_TXPAUSE		BIT(6)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_RXPAUSE		BIT(5)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_LINK		BIT(4)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_DUPLEX		BIT(2)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_MASK	0x0003/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_10		0/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_100	1/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_1000	2/*GOOD*/
+
+#define RTL8367B_RTL_MAGIC_ID_REG		0x13c2
+#define   RTL8367B_RTL_MAGIC_ID_VAL		0x0249
+
+#define RTL8367B_IA_CTRL_REG			0x1f00
+#define   RTL8367B_IA_CTRL_RW(_x)		((_x) << 1)
+#define   RTL8367B_IA_CTRL_RW_READ		RTL8367B_IA_CTRL_RW(0)
+#define   RTL8367B_IA_CTRL_RW_WRITE		RTL8367B_IA_CTRL_RW(1)
+#define   RTL8367B_IA_CTRL_CMD_MASK		BIT(0)
+
+#define RTL8367B_IA_STATUS_REG			0x1f01
+#define   RTL8367B_IA_STATUS_PHY_BUSY		BIT(2)
+#define   RTL8367B_IA_STATUS_SDS_BUSY		BIT(1)
+#define   RTL8367B_IA_STATUS_MDX_BUSY		BIT(0)
+
+#define RTL8367B_IA_ADDRESS_REG			0x1f02
+#define RTL8367B_IA_WRITE_DATA_REG		0x1f03
+#define RTL8367B_IA_READ_DATA_REG		0x1f04
+
+#define RTL8367B_INTERNAL_PHY_REG(_a, _r)	(0x2000 + 32 * (_a) + (_r))
+
+#define RTL8367B_NUM_MIB_COUNTERS	58
+
+#define RTL8367B_CPU_PORT_NUM		5
+#define RTL8367B_NUM_PORTS		8
+#define RTL8367B_NUM_VLANS		32
+#define RTL8367B_NUM_VIDS		4096
+#define RTL8367B_PRIORITYMAX		7
+#define RTL8367B_FIDMAX			7
+
+#define RTL8367B_PORT_0			BIT(0)
+#define RTL8367B_PORT_1			BIT(1)
+#define RTL8367B_PORT_2			BIT(2)
+#define RTL8367B_PORT_3			BIT(3)
+#define RTL8367B_PORT_4			BIT(4)
+#define RTL8367B_PORT_E0		BIT(5)	/* External port 0 */
+#define RTL8367B_PORT_E1		BIT(6)	/* External port 1 */
+#define RTL8367B_PORT_E2		BIT(7)	/* External port 2 */
+
+#define RTL8367B_PORTS_ALL					\
+	(RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 |	\
+	 RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E0 | \
+	 RTL8367B_PORT_E1 | RTL8367B_PORT_E2)
+
+#define RTL8367B_PORTS_ALL_BUT_CPU				\
+	(RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 |	\
+	 RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E1 |	\
+	 RTL8367B_PORT_E2)
+
+struct rtl8367b_initval {
+	u16 reg;
+	u16 val;
+};
+
+static struct rtl8366_mib_counter
+rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = {
+	{0,   0, 4, "ifInOctets"			},
+	{0,   4, 2, "dot3StatsFCSErrors"		},
+	{0,   6, 2, "dot3StatsSymbolErrors"		},
+	{0,   8, 2, "dot3InPauseFrames"			},
+	{0,  10, 2, "dot3ControlInUnknownOpcodes"	},
+	{0,  12, 2, "etherStatsFragments"		},
+	{0,  14, 2, "etherStatsJabbers"			},
+	{0,  16, 2, "ifInUcastPkts"			},
+	{0,  18, 2, "etherStatsDropEvents"		},
+	{0,  20, 2, "ifInMulticastPkts"			},
+	{0,  22, 2, "ifInBroadcastPkts"			},
+	{0,  24, 2, "inMldChecksumError"		},
+	{0,  26, 2, "inIgmpChecksumError"		},
+	{0,  28, 2, "inMldSpecificQuery"		},
+	{0,  30, 2, "inMldGeneralQuery"			},
+	{0,  32, 2, "inIgmpSpecificQuery"		},
+	{0,  34, 2, "inIgmpGeneralQuery"		},
+	{0,  36, 2, "inMldLeaves"			},
+	{0,  38, 2, "inIgmpLeaves"			},
+
+	{0,  40, 4, "etherStatsOctets"			},
+	{0,  44, 2, "etherStatsUnderSizePkts"		},
+	{0,  46, 2, "etherOversizeStats"		},
+	{0,  48, 2, "etherStatsPkts64Octets"		},
+	{0,  50, 2, "etherStatsPkts65to127Octets"	},
+	{0,  52, 2, "etherStatsPkts128to255Octets"	},
+	{0,  54, 2, "etherStatsPkts256to511Octets"	},
+	{0,  56, 2, "etherStatsPkts512to1023Octets"	},
+	{0,  58, 2, "etherStatsPkts1024to1518Octets"	},
+
+	{0,  60, 4, "ifOutOctets"			},
+	{0,  64, 2, "dot3StatsSingleCollisionFrames"	},
+	{0,  66, 2, "dot3StatMultipleCollisionFrames"	},
+	{0,  68, 2, "dot3sDeferredTransmissions"	},
+	{0,  70, 2, "dot3StatsLateCollisions"		},
+	{0,  72, 2, "etherStatsCollisions"		},
+	{0,  74, 2, "dot3StatsExcessiveCollisions"	},
+	{0,  76, 2, "dot3OutPauseFrames"		},
+	{0,  78, 2, "ifOutDiscards"			},
+	{0,  80, 2, "dot1dTpPortInDiscards"		},
+	{0,  82, 2, "ifOutUcastPkts"			},
+	{0,  84, 2, "ifOutMulticastPkts"		},
+	{0,  86, 2, "ifOutBroadcastPkts"		},
+	{0,  88, 2, "outOampduPkts"			},
+	{0,  90, 2, "inOampduPkts"			},
+	{0,  92, 2, "inIgmpJoinsSuccess"		},
+	{0,  94, 2, "inIgmpJoinsFail"			},
+	{0,  96, 2, "inMldJoinsSuccess"			},
+	{0,  98, 2, "inMldJoinsFail"			},
+	{0, 100, 2, "inReportSuppressionDrop"		},
+	{0, 102, 2, "inLeaveSuppressionDrop"		},
+	{0, 104, 2, "outIgmpReports"			},
+	{0, 106, 2, "outIgmpLeaves"			},
+	{0, 108, 2, "outIgmpGeneralQuery"		},
+	{0, 110, 2, "outIgmpSpecificQuery"		},
+	{0, 112, 2, "outMldReports"			},
+	{0, 114, 2, "outMldLeaves"			},
+	{0, 116, 2, "outMldGeneralQuery"		},
+	{0, 118, 2, "outMldSpecificQuery"		},
+	{0, 120, 2, "inKnownMulticastPkts"		},
+};
+
+#define REG_RD(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_read_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static const struct rtl8367b_initval rtl8367r_vb_initvals_0[] = {
+	{0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x0301, 0x0026}, {0x1722, 0x0E14},
+	{0x205F, 0x0002}, {0x2059, 0x1A00}, {0x205F, 0x0000}, {0x207F, 0x0002},
+	{0x2077, 0x0000}, {0x2078, 0x0000}, {0x2079, 0x0000}, {0x207A, 0x0000},
+	{0x207B, 0x0000}, {0x207F, 0x0000}, {0x205F, 0x0002}, {0x2053, 0x0000},
+	{0x2054, 0x0000}, {0x2055, 0x0000}, {0x2056, 0x0000}, {0x2057, 0x0000},
+	{0x205F, 0x0000}, {0x12A4, 0x110A}, {0x12A6, 0x150A}, {0x13F1, 0x0013},
+	{0x13F4, 0x0010}, {0x13F5, 0x0000}, {0x0018, 0x0F00}, {0x0038, 0x0F00},
+	{0x0058, 0x0F00}, {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x12B6, 0x0C02},
+	{0x12B7, 0x030F}, {0x12B8, 0x11FF}, {0x12BC, 0x0004}, {0x1362, 0x0115},
+	{0x1363, 0x0002}, {0x1363, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E},
+	{0x221F, 0x0007}, {0x221E, 0x002D}, {0x2218, 0xF030}, {0x221F, 0x0007},
+	{0x221E, 0x0023}, {0x2216, 0x0005}, {0x2215, 0x00B9}, {0x2219, 0x0044},
+	{0x2215, 0x00BA}, {0x2219, 0x0020}, {0x2215, 0x00BB}, {0x2219, 0x00C1},
+	{0x2215, 0x0148}, {0x2219, 0x0096}, {0x2215, 0x016E}, {0x2219, 0x0026},
+	{0x2216, 0x0000}, {0x2216, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010},
+	{0x221F, 0x0007}, {0x221E, 0x0020}, {0x2215, 0x0D00}, {0x221F, 0x0000},
+	{0x221F, 0x0000}, {0x2217, 0x2160}, {0x221F, 0x0001}, {0x2210, 0xF25E},
+	{0x221F, 0x0007}, {0x221E, 0x0042}, {0x2215, 0x0F00}, {0x2215, 0x0F00},
+	{0x2216, 0x7408}, {0x2215, 0x0E00}, {0x2215, 0x0F00}, {0x2215, 0x0F01},
+	{0x2216, 0x4000}, {0x2215, 0x0E01}, {0x2215, 0x0F01}, {0x2215, 0x0F02},
+	{0x2216, 0x9400}, {0x2215, 0x0E02}, {0x2215, 0x0F02}, {0x2215, 0x0F03},
+	{0x2216, 0x7408}, {0x2215, 0x0E03}, {0x2215, 0x0F03}, {0x2215, 0x0F04},
+	{0x2216, 0x4008}, {0x2215, 0x0E04}, {0x2215, 0x0F04}, {0x2215, 0x0F05},
+	{0x2216, 0x9400}, {0x2215, 0x0E05}, {0x2215, 0x0F05}, {0x2215, 0x0F06},
+	{0x2216, 0x0803}, {0x2215, 0x0E06}, {0x2215, 0x0F06}, {0x2215, 0x0D00},
+	{0x2215, 0x0100}, {0x221F, 0x0001}, {0x2210, 0xF05E}, {0x221F, 0x0000},
+	{0x2217, 0x2100}, {0x221F, 0x0000}, {0x220D, 0x0003}, {0x220E, 0x0015},
+	{0x220D, 0x4003}, {0x220E, 0x0006}, {0x221F, 0x0000}, {0x2200, 0x1340},
+	{0x133F, 0x0010}, {0x12A0, 0x0058}, {0x12A1, 0x0058}, {0x133E, 0x000E},
+	{0x133F, 0x0030}, {0x221F, 0x0000}, {0x2210, 0x0166}, {0x221F, 0x0000},
+	{0x133E, 0x000E}, {0x133F, 0x0010}, {0x133F, 0x0030}, {0x133E, 0x000E},
+	{0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8B6E},
+	{0x2206, 0x0000}, {0x220F, 0x0100}, {0x2205, 0x8000}, {0x2206, 0x0280},
+	{0x2206, 0x28F7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080},
+	{0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201},
+	{0x2206, 0x6602}, {0x2206, 0x80B9}, {0x2206, 0xE08B}, {0x2206, 0x8CE1},
+	{0x2206, 0x8B8D}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x8E1E},
+	{0x2206, 0x01A0}, {0x2206, 0x00E7}, {0x2206, 0xAEDB}, {0x2206, 0xEEE0},
+	{0x2206, 0x120E}, {0x2206, 0xEEE0}, {0x2206, 0x1300}, {0x2206, 0xEEE0},
+	{0x2206, 0x2001}, {0x2206, 0xEEE0}, {0x2206, 0x2166}, {0x2206, 0xEEE0},
+	{0x2206, 0xC463}, {0x2206, 0xEEE0}, {0x2206, 0xC5E8}, {0x2206, 0xEEE0},
+	{0x2206, 0xC699}, {0x2206, 0xEEE0}, {0x2206, 0xC7C2}, {0x2206, 0xEEE0},
+	{0x2206, 0xC801}, {0x2206, 0xEEE0}, {0x2206, 0xC913}, {0x2206, 0xEEE0},
+	{0x2206, 0xCA30}, {0x2206, 0xEEE0}, {0x2206, 0xCB3E}, {0x2206, 0xEEE0},
+	{0x2206, 0xDCE1}, {0x2206, 0xEEE0}, {0x2206, 0xDD00}, {0x2206, 0xEEE2},
+	{0x2206, 0x0001}, {0x2206, 0xEEE2}, {0x2206, 0x0100}, {0x2206, 0xEEE4},
+	{0x2206, 0x8860}, {0x2206, 0xEEE4}, {0x2206, 0x8902}, {0x2206, 0xEEE4},
+	{0x2206, 0x8C00}, {0x2206, 0xEEE4}, {0x2206, 0x8D30}, {0x2206, 0xEEEA},
+	{0x2206, 0x1480}, {0x2206, 0xEEEA}, {0x2206, 0x1503}, {0x2206, 0xEEEA},
+	{0x2206, 0xC600}, {0x2206, 0xEEEA}, {0x2206, 0xC706}, {0x2206, 0xEE85},
+	{0x2206, 0xEE00}, {0x2206, 0xEE85}, {0x2206, 0xEF00}, {0x2206, 0xEE8B},
+	{0x2206, 0x6750}, {0x2206, 0xEE8B}, {0x2206, 0x6632}, {0x2206, 0xEE8A},
+	{0x2206, 0xD448}, {0x2206, 0xEE8A}, {0x2206, 0xD548}, {0x2206, 0xEE8A},
+	{0x2206, 0xD649}, {0x2206, 0xEE8A}, {0x2206, 0xD7F8}, {0x2206, 0xEE8B},
+	{0x2206, 0x85E2}, {0x2206, 0xEE8B}, {0x2206, 0x8700}, {0x2206, 0xEEFF},
+	{0x2206, 0xF600}, {0x2206, 0xEEFF}, {0x2206, 0xF7FC}, {0x2206, 0x04F8},
+	{0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2023}, {0x2206, 0xF620},
+	{0x2206, 0xE48B}, {0x2206, 0x8E02}, {0x2206, 0x2877}, {0x2206, 0x0225},
+	{0x2206, 0xC702}, {0x2206, 0x26A1}, {0x2206, 0x0281}, {0x2206, 0xB302},
+	{0x2206, 0x8496}, {0x2206, 0x0202}, {0x2206, 0xA102}, {0x2206, 0x27F1},
+	{0x2206, 0x0228}, {0x2206, 0xF902}, {0x2206, 0x2AA0}, {0x2206, 0x0282},
+	{0x2206, 0xB8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD21}, {0x2206, 0x08F6},
+	{0x2206, 0x21E4}, {0x2206, 0x8B8E}, {0x2206, 0x0202}, {0x2206, 0x80E0},
+	{0x2206, 0x8B8E}, {0x2206, 0xAD22}, {0x2206, 0x05F6}, {0x2206, 0x22E4},
+	{0x2206, 0x8B8E}, {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2305},
+	{0x2206, 0xF623}, {0x2206, 0xE48B}, {0x2206, 0x8EE0}, {0x2206, 0x8B8E},
+	{0x2206, 0xAD24}, {0x2206, 0x08F6}, {0x2206, 0x24E4}, {0x2206, 0x8B8E},
+	{0x2206, 0x0227}, {0x2206, 0x6AE0}, {0x2206, 0x8B8E}, {0x2206, 0xAD25},
+	{0x2206, 0x05F6}, {0x2206, 0x25E4}, {0x2206, 0x8B8E}, {0x2206, 0xE08B},
+	{0x2206, 0x8EAD}, {0x2206, 0x260B}, {0x2206, 0xF626}, {0x2206, 0xE48B},
+	{0x2206, 0x8E02}, {0x2206, 0x830D}, {0x2206, 0x021D}, {0x2206, 0x6BE0},
+	{0x2206, 0x8B8E}, {0x2206, 0xAD27}, {0x2206, 0x05F6}, {0x2206, 0x27E4},
+	{0x2206, 0x8B8E}, {0x2206, 0x0281}, {0x2206, 0x4402}, {0x2206, 0x045C},
+	{0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B83}, {0x2206, 0xAD23},
+	{0x2206, 0x30E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x2359},
+	{0x2206, 0x02E0}, {0x2206, 0x85EF}, {0x2206, 0xE585}, {0x2206, 0xEFAC},
+	{0x2206, 0x2907}, {0x2206, 0x1F01}, {0x2206, 0x9E51}, {0x2206, 0xAD29},
+	{0x2206, 0x20E0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x06E1},
+	{0x2206, 0x8B84}, {0x2206, 0xAD28}, {0x2206, 0x42E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD21}, {0x2206, 0x06E1}, {0x2206, 0x8B84}, {0x2206, 0xAD29},
+	{0x2206, 0x36BF}, {0x2206, 0x34BF}, {0x2206, 0x022C}, {0x2206, 0x31AE},
+	{0x2206, 0x2EE0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x10E0},
+	{0x2206, 0x8B84}, {0x2206, 0xF620}, {0x2206, 0xE48B}, {0x2206, 0x84EE},
+	{0x2206, 0x8ADA}, {0x2206, 0x00EE}, {0x2206, 0x8ADB}, {0x2206, 0x00E0},
+	{0x2206, 0x8B85}, {0x2206, 0xAD21}, {0x2206, 0x0CE0}, {0x2206, 0x8B84},
+	{0x2206, 0xF621}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, {0x2206, 0x8B72},
+	{0x2206, 0xFFBF}, {0x2206, 0x34C2}, {0x2206, 0x022C}, {0x2206, 0x31FC},
+	{0x2206, 0x04F8}, {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD21}, {0x2206, 0x42E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0},
+	{0x2206, 0x2358}, {0x2206, 0xC059}, {0x2206, 0x021E}, {0x2206, 0x01E1},
+	{0x2206, 0x8B72}, {0x2206, 0x1F10}, {0x2206, 0x9E2F}, {0x2206, 0xE48B},
+	{0x2206, 0x72AD}, {0x2206, 0x2123}, {0x2206, 0xE18B}, {0x2206, 0x84F7},
+	{0x2206, 0x29E5}, {0x2206, 0x8B84}, {0x2206, 0xAC27}, {0x2206, 0x10AC},
+	{0x2206, 0x2605}, {0x2206, 0x0205}, {0x2206, 0x23AE}, {0x2206, 0x1602},
+	{0x2206, 0x0535}, {0x2206, 0x0282}, {0x2206, 0x30AE}, {0x2206, 0x0E02},
+	{0x2206, 0x056A}, {0x2206, 0x0282}, {0x2206, 0x75AE}, {0x2206, 0x0602},
+	{0x2206, 0x04DC}, {0x2206, 0x0282}, {0x2206, 0x04EF}, {0x2206, 0x96FE},
+	{0x2206, 0xFC04}, {0x2206, 0xF8F9}, {0x2206, 0xE08B}, {0x2206, 0x87AD},
+	{0x2206, 0x2321}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15},
+	{0x2206, 0xAD26}, {0x2206, 0x18F6}, {0x2206, 0x27E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15F6}, {0x2206, 0x26E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8F9},
+	{0x2206, 0xE08B}, {0x2206, 0x87AD}, {0x2206, 0x233A}, {0x2206, 0xAD22},
+	{0x2206, 0x37E0}, {0x2206, 0xE020}, {0x2206, 0xE1E0}, {0x2206, 0x21AC},
+	{0x2206, 0x212E}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15},
+	{0x2206, 0xF627}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15},
+	{0x2206, 0xE2EA}, {0x2206, 0x12E3}, {0x2206, 0xEA13}, {0x2206, 0x5A8F},
+	{0x2206, 0x6A20}, {0x2206, 0xE6EA}, {0x2206, 0x12E7}, {0x2206, 0xEA13},
+	{0x2206, 0xF726}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15},
+	{0x2206, 0xF727}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15},
+	{0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B87},
+	{0x2206, 0xAD23}, {0x2206, 0x38AD}, {0x2206, 0x2135}, {0x2206, 0xE0E0},
+	{0x2206, 0x20E1}, {0x2206, 0xE021}, {0x2206, 0xAC21}, {0x2206, 0x2CE0},
+	{0x2206, 0xEA14}, {0x2206, 0xE1EA}, {0x2206, 0x15F6}, {0x2206, 0x27E4},
+	{0x2206, 0xEA14}, {0x2206, 0xE5EA}, {0x2206, 0x15E2}, {0x2206, 0xEA12},
+	{0x2206, 0xE3EA}, {0x2206, 0x135A}, {0x2206, 0x8FE6}, {0x2206, 0xEA12},
+	{0x2206, 0xE7EA}, {0x2206, 0x13F7}, {0x2206, 0x26E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2146},
+	{0x2206, 0xE0E0}, {0x2206, 0x22E1}, {0x2206, 0xE023}, {0x2206, 0x58C0},
+	{0x2206, 0x5902}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x651F},
+	{0x2206, 0x109E}, {0x2206, 0x33E4}, {0x2206, 0x8B65}, {0x2206, 0xAD21},
+	{0x2206, 0x22AD}, {0x2206, 0x272A}, {0x2206, 0xD400}, {0x2206, 0x01BF},
+	{0x2206, 0x34F2}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, {0x2206, 0x34F5},
+	{0x2206, 0x022C}, {0x2206, 0xE0E0}, {0x2206, 0x8B67}, {0x2206, 0x1B10},
+	{0x2206, 0xAA14}, {0x2206, 0xE18B}, {0x2206, 0x660D}, {0x2206, 0x1459},
+	{0x2206, 0x0FAE}, {0x2206, 0x05E1}, {0x2206, 0x8B66}, {0x2206, 0x590F},
+	{0x2206, 0xBF85}, {0x2206, 0x6102}, {0x2206, 0x2CA2}, {0x2206, 0xEF96},
+	{0x2206, 0xFEFC}, {0x2206, 0x04F8}, {0x2206, 0xF9FA}, {0x2206, 0xFBEF},
+	{0x2206, 0x79E2}, {0x2206, 0x8AD2}, {0x2206, 0xAC19}, {0x2206, 0x2DE0},
+	{0x2206, 0xE036}, {0x2206, 0xE1E0}, {0x2206, 0x37EF}, {0x2206, 0x311F},
+	{0x2206, 0x325B}, {0x2206, 0x019E}, {0x2206, 0x1F7A}, {0x2206, 0x0159},
+	{0x2206, 0x019F}, {0x2206, 0x0ABF}, {0x2206, 0x348E}, {0x2206, 0x022C},
+	{0x2206, 0x31F6}, {0x2206, 0x06AE}, {0x2206, 0x0FF6}, {0x2206, 0x0302},
+	{0x2206, 0x0470}, {0x2206, 0xF703}, {0x2206, 0xF706}, {0x2206, 0xBF34},
+	{0x2206, 0x9302}, {0x2206, 0x2C31}, {0x2206, 0xAC1A}, {0x2206, 0x25E0},
+	{0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x23EF}, {0x2206, 0x300D},
+	{0x2206, 0x311F}, {0x2206, 0x325B}, {0x2206, 0x029E}, {0x2206, 0x157A},
+	{0x2206, 0x0258}, {0x2206, 0xC4A0}, {0x2206, 0x0408}, {0x2206, 0xBF34},
+	{0x2206, 0x9E02}, {0x2206, 0x2C31}, {0x2206, 0xAE06}, {0x2206, 0xBF34},
+	{0x2206, 0x9C02}, {0x2206, 0x2C31}, {0x2206, 0xAC1B}, {0x2206, 0x4AE0},
+	{0x2206, 0xE012}, {0x2206, 0xE1E0}, {0x2206, 0x13EF}, {0x2206, 0x300D},
+	{0x2206, 0x331F}, {0x2206, 0x325B}, {0x2206, 0x1C9E}, {0x2206, 0x3AEF},
+	{0x2206, 0x325B}, {0x2206, 0x1C9F}, {0x2206, 0x09BF}, {0x2206, 0x3498},
+	{0x2206, 0x022C}, {0x2206, 0x3102}, {0x2206, 0x83C5}, {0x2206, 0x5A03},
+	{0x2206, 0x0D03}, {0x2206, 0x581C}, {0x2206, 0x1E20}, {0x2206, 0x0207},
+	{0x2206, 0xA0A0}, {0x2206, 0x000E}, {0x2206, 0x0284}, {0x2206, 0x17AD},
+	{0x2206, 0x1817}, {0x2206, 0xBF34}, {0x2206, 0x9A02}, {0x2206, 0x2C31},
+	{0x2206, 0xAE0F}, {0x2206, 0xBF34}, {0x2206, 0xC802}, {0x2206, 0x2C31},
+	{0x2206, 0xBF34}, {0x2206, 0xC502}, {0x2206, 0x2C31}, {0x2206, 0x0284},
+	{0x2206, 0x52E6}, {0x2206, 0x8AD2}, {0x2206, 0xEF97}, {0x2206, 0xFFFE},
+	{0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xBF34}, {0x2206, 0xDA02},
+	{0x2206, 0x2CE0}, {0x2206, 0xE58A}, {0x2206, 0xD3BF}, {0x2206, 0x34D4},
+	{0x2206, 0x022C}, {0x2206, 0xE00C}, {0x2206, 0x1159}, {0x2206, 0x02E0},
+	{0x2206, 0x8AD3}, {0x2206, 0x1E01}, {0x2206, 0xE48A}, {0x2206, 0xD3D1},
+	{0x2206, 0x00BF}, {0x2206, 0x34DA}, {0x2206, 0x022C}, {0x2206, 0xA2D1},
+	{0x2206, 0x01BF}, {0x2206, 0x34D4}, {0x2206, 0x022C}, {0x2206, 0xA2BF},
+	{0x2206, 0x34CB}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, {0x2206, 0x8ACE},
+	{0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CE0}, {0x2206, 0xE58A},
+	{0x2206, 0xCFBF}, {0x2206, 0x8564}, {0x2206, 0x022C}, {0x2206, 0xE0E5},
+	{0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, {0x2206, 0x2CE0},
+	{0x2206, 0xE58A}, {0x2206, 0xD1FC}, {0x2206, 0x04F8}, {0x2206, 0xE18A},
+	{0x2206, 0xD1BF}, {0x2206, 0x856A}, {0x2206, 0x022C}, {0x2206, 0xA2E1},
+	{0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2},
+	{0x2206, 0xE18A}, {0x2206, 0xCFBF}, {0x2206, 0x8567}, {0x2206, 0x022C},
+	{0x2206, 0xA2E1}, {0x2206, 0x8ACE}, {0x2206, 0xBF34}, {0x2206, 0xCB02},
+	{0x2206, 0x2CA2}, {0x2206, 0xE18A}, {0x2206, 0xD3BF}, {0x2206, 0x34DA},
+	{0x2206, 0x022C}, {0x2206, 0xA2E1}, {0x2206, 0x8AD3}, {0x2206, 0x0D11},
+	{0x2206, 0xBF34}, {0x2206, 0xD402}, {0x2206, 0x2CA2}, {0x2206, 0xFC04},
+	{0x2206, 0xF9A0}, {0x2206, 0x0405}, {0x2206, 0xE38A}, {0x2206, 0xD4AE},
+	{0x2206, 0x13A0}, {0x2206, 0x0805}, {0x2206, 0xE38A}, {0x2206, 0xD5AE},
+	{0x2206, 0x0BA0}, {0x2206, 0x0C05}, {0x2206, 0xE38A}, {0x2206, 0xD6AE},
+	{0x2206, 0x03E3}, {0x2206, 0x8AD7}, {0x2206, 0xEF13}, {0x2206, 0xBF34},
+	{0x2206, 0xCB02}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, {0x2206, 0x0D11},
+	{0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CA2}, {0x2206, 0xEF13},
+	{0x2206, 0x0D14}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2},
+	{0x2206, 0xEF13}, {0x2206, 0x0D17}, {0x2206, 0xBF85}, {0x2206, 0x6A02},
+	{0x2206, 0x2CA2}, {0x2206, 0xFD04}, {0x2206, 0xF8E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD27}, {0x2206, 0x2DE0}, {0x2206, 0xE036}, {0x2206, 0xE1E0},
+	{0x2206, 0x37E1}, {0x2206, 0x8B73}, {0x2206, 0x1F10}, {0x2206, 0x9E20},
+	{0x2206, 0xE48B}, {0x2206, 0x73AC}, {0x2206, 0x200B}, {0x2206, 0xAC21},
+	{0x2206, 0x0DAC}, {0x2206, 0x250F}, {0x2206, 0xAC27}, {0x2206, 0x0EAE},
+	{0x2206, 0x0F02}, {0x2206, 0x84CC}, {0x2206, 0xAE0A}, {0x2206, 0x0284},
+	{0x2206, 0xD1AE}, {0x2206, 0x05AE}, {0x2206, 0x0302}, {0x2206, 0x84D8},
+	{0x2206, 0xFC04}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0x0402},
+	{0x2206, 0x84E5}, {0x2206, 0x0285}, {0x2206, 0x2804}, {0x2206, 0x0285},
+	{0x2206, 0x4904}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0xEE8B},
+	{0x2206, 0x6902}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD26}, {0x2206, 0x38D0}, {0x2206, 0x0B02}, {0x2206, 0x2B4D},
+	{0x2206, 0x5882}, {0x2206, 0x7882}, {0x2206, 0x9F2D}, {0x2206, 0xE08B},
+	{0x2206, 0x68E1}, {0x2206, 0x8B69}, {0x2206, 0x1F10}, {0x2206, 0x9EC8},
+	{0x2206, 0x10E4}, {0x2206, 0x8B68}, {0x2206, 0xE0E0}, {0x2206, 0x00E1},
+	{0x2206, 0xE001}, {0x2206, 0xF727}, {0x2206, 0xE4E0}, {0x2206, 0x00E5},
+	{0x2206, 0xE001}, {0x2206, 0xE2E0}, {0x2206, 0x20E3}, {0x2206, 0xE021},
+	{0x2206, 0xAD30}, {0x2206, 0xF7F6}, {0x2206, 0x27E4}, {0x2206, 0xE000},
+	{0x2206, 0xE5E0}, {0x2206, 0x01FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2212},
+	{0x2206, 0xE0E0}, {0x2206, 0x14E1}, {0x2206, 0xE015}, {0x2206, 0xAD26},
+	{0x2206, 0x9CE1}, {0x2206, 0x85E0}, {0x2206, 0xBF85}, {0x2206, 0x6D02},
+	{0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x04F8},
+	{0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B86}, {0x2206, 0xAD22},
+	{0x2206, 0x09E1}, {0x2206, 0x85E1}, {0x2206, 0xBF85}, {0x2206, 0x6D02},
+	{0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x0464},
+	{0x2206, 0xE48C}, {0x2206, 0xFDE4}, {0x2206, 0x80CA}, {0x2206, 0xE480},
+	{0x2206, 0x66E0}, {0x2206, 0x8E70}, {0x2206, 0xE076}, {0x2205, 0xE142},
+	{0x2206, 0x0701}, {0x2205, 0xE140}, {0x2206, 0x0405}, {0x220F, 0x0000},
+	{0x221F, 0x0000}, {0x2200, 0x1340}, {0x133E, 0x000E}, {0x133F, 0x0010},
+	{0x13EB, 0x11BB}
+};
+
+static const struct rtl8367b_initval rtl8367r_vb_initvals_1[] = {
+	{0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA},
+	{0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078},
+	{0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00},
+	{0x205F, 0x0000}, {0x207F, 0x0002}, {0x2077, 0x0000}, {0x2078, 0x0000},
+	{0x2079, 0x0000}, {0x207A, 0x0000}, {0x207B, 0x0000}, {0x207F, 0x0000},
+	{0x205F, 0x0002}, {0x2053, 0x0000}, {0x2054, 0x0000}, {0x2055, 0x0000},
+	{0x2056, 0x0000}, {0x2057, 0x0000}, {0x205F, 0x0000}, {0x133F, 0x0030},
+	{0x133E, 0x000E}, {0x221F, 0x0005}, {0x2205, 0x8B86}, {0x2206, 0x800E},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x12A3, 0x2200}, {0x6107, 0xE58B},
+	{0x6103, 0xA970}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, {0x0058, 0x0F00},
+	{0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x133F, 0x0030}, {0x133E, 0x000E},
+	{0x221F, 0x0005}, {0x2205, 0x8B6E}, {0x2206, 0x0000}, {0x220F, 0x0100},
+	{0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8000}, {0x2206, 0x0280},
+	{0x2206, 0x2BF7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080},
+	{0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201},
+	{0x2206, 0x6602}, {0x2206, 0x8044}, {0x2206, 0x0201}, {0x2206, 0x7CE0},
+	{0x2206, 0x8B8C}, {0x2206, 0xE18B}, {0x2206, 0x8D1E}, {0x2206, 0x01E1},
+	{0x2206, 0x8B8E}, {0x2206, 0x1E01}, {0x2206, 0xA000}, {0x2206, 0xE4AE},
+	{0x2206, 0xD8EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, {0x2206, 0x85C1},
+	{0x2206, 0x00EE}, {0x2206, 0x8AFC}, {0x2206, 0x07EE}, {0x2206, 0x8AFD},
+	{0x2206, 0x73EE}, {0x2206, 0xFFF6}, {0x2206, 0x00EE}, {0x2206, 0xFFF7},
+	{0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD20},
+	{0x2206, 0x0302}, {0x2206, 0x8050}, {0x2206, 0xFC04}, {0x2206, 0xF8F9},
+	{0x2206, 0xE08B}, {0x2206, 0x85AD}, {0x2206, 0x2548}, {0x2206, 0xE08A},
+	{0x2206, 0xE4E1}, {0x2206, 0x8AE5}, {0x2206, 0x7C00}, {0x2206, 0x009E},
+	{0x2206, 0x35EE}, {0x2206, 0x8AE4}, {0x2206, 0x00EE}, {0x2206, 0x8AE5},
+	{0x2206, 0x00E0}, {0x2206, 0x8AFC}, {0x2206, 0xE18A}, {0x2206, 0xFDE2},
+	{0x2206, 0x85C0}, {0x2206, 0xE385}, {0x2206, 0xC102}, {0x2206, 0x2DAC},
+	{0x2206, 0xAD20}, {0x2206, 0x12EE}, {0x2206, 0x8AE4}, {0x2206, 0x03EE},
+	{0x2206, 0x8AE5}, {0x2206, 0xB7EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE},
+	{0x2206, 0x85C1}, {0x2206, 0x00AE}, {0x2206, 0x1115}, {0x2206, 0xE685},
+	{0x2206, 0xC0E7}, {0x2206, 0x85C1}, {0x2206, 0xAE08}, {0x2206, 0xEE85},
+	{0x2206, 0xC000}, {0x2206, 0xEE85}, {0x2206, 0xC100}, {0x2206, 0xFDFC},
+	{0x2206, 0x0400}, {0x2205, 0xE142}, {0x2206, 0x0701}, {0x2205, 0xE140},
+	{0x2206, 0x0405}, {0x220F, 0x0000}, {0x221F, 0x0000}, {0x133E, 0x000E},
+	{0x133F, 0x0010}, {0x13EB, 0x11BB}, {0x207F, 0x0002}, {0x2073, 0x1D22},
+	{0x207F, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x2200, 0x1340},
+	{0x133E, 0x000E}, {0x133F, 0x0010},
+};
+
+static int rtl8367b_write_initvals(struct rtl8366_smi *smi,
+				  const struct rtl8367b_initval *initvals,
+				  int count)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < count; i++)
+		REG_WR(smi, initvals[i].reg, initvals[i].val);
+
+	return 0;
+}
+
+static int rtl8367b_read_phy_reg(struct rtl8366_smi *smi,
+				u32 phy_addr, u32 phy_reg, u32 *val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	if (phy_addr > RTL8367B_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367B_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+	if (data & RTL8367B_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* prepare address */
+	REG_WR(smi, RTL8367B_IA_ADDRESS_REG,
+	       RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send read command */
+	REG_WR(smi, RTL8367B_IA_CTRL_REG,
+	       RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_READ);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+		if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy read timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	/* read data */
+	REG_RD(smi, RTL8367B_IA_READ_DATA_REG, val);
+
+	dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, *val);
+	return 0;
+}
+
+static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_addr, u32 phy_reg, u32 val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, val);
+
+	if (phy_addr > RTL8367B_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367B_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+	if (data & RTL8367B_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* preapre data */
+	REG_WR(smi, RTL8367B_IA_WRITE_DATA_REG, val);
+
+	/* prepare address */
+	REG_WR(smi, RTL8367B_IA_ADDRESS_REG,
+	       RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send write command */
+	REG_WR(smi, RTL8367B_IA_CTRL_REG,
+	       RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_WRITE);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+		if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy write timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	return 0;
+}
+
+static int rtl8367b_init_regs(struct rtl8366_smi *smi)
+{
+	const struct rtl8367b_initval *initvals;
+	u32 chip_ver;
+	u32 rlvid;
+	int count;
+	int err;
+
+	REG_WR(smi, RTL8367B_RTL_MAGIC_ID_REG, RTL8367B_RTL_MAGIC_ID_VAL);
+	REG_RD(smi, RTL8367B_CHIP_VER_REG, &chip_ver);
+
+	rlvid = (chip_ver >> RTL8367B_CHIP_VER_RLVID_SHIFT) &
+		RTL8367B_CHIP_VER_RLVID_MASK;
+
+	switch (rlvid) {
+	case 0:
+		initvals = rtl8367r_vb_initvals_0;
+		count = ARRAY_SIZE(rtl8367r_vb_initvals_0);
+		break;
+
+	case 1:
+		initvals = rtl8367r_vb_initvals_1;
+		count = ARRAY_SIZE(rtl8367r_vb_initvals_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "unknow rlvid %u\n", rlvid);
+		return -ENODEV;
+	}
+
+	/* TODO: disable RLTP */
+
+	return rtl8367b_write_initvals(smi, initvals, count);
+}
+
+static int rtl8367b_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	int err;
+	u32 data;
+
+	REG_WR(smi, RTL8367B_CHIP_RESET_REG, RTL8367B_CHIP_RESET_HW);
+	msleep(RTL8367B_RESET_DELAY);
+
+	do {
+		REG_RD(smi, RTL8367B_CHIP_RESET_REG, &data);
+		if (!(data & RTL8367B_CHIP_RESET_HW))
+			break;
+
+		msleep(1);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_err(smi->parent, "chip reset timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id,
+				   enum rtl8367_extif_mode mode)
+{
+	int err;
+
+	/* set port mode */
+	switch (mode) {
+	case RTL8367_EXTIF_MODE_RGMII:
+	case RTL8367_EXTIF_MODE_RGMII_33V:
+		REG_WR(smi, RTL8367B_CHIP_DEBUG0_REG, 0x0367);
+		REG_WR(smi, RTL8367B_CHIP_DEBUG1_REG, 0x7777);
+		break;
+
+	case RTL8367_EXTIF_MODE_TMII_MAC:
+	case RTL8367_EXTIF_MODE_TMII_PHY:
+		REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG,
+			BIT((id + 1) % 2), BIT((id + 1) % 2));
+		break;
+
+	case RTL8367_EXTIF_MODE_GMII:
+		REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG,
+		        RTL8367B_CHIP_DEBUG0_DUMMY0(id),
+			RTL8367B_CHIP_DEBUG0_DUMMY0(id));
+		REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), BIT(6));
+		break;
+
+	case RTL8367_EXTIF_MODE_MII_MAC:
+	case RTL8367_EXTIF_MODE_MII_PHY:
+	case RTL8367_EXTIF_MODE_DISABLED:
+		REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG,
+			BIT((id + 1) % 2), 0);
+		REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), 0);
+		break;
+
+	default:
+		dev_err(smi->parent,
+			"invalid mode for external interface %d\n", id);
+		return -EINVAL;
+	}
+
+	REG_RMW(smi, RTL8367B_DIS_REG,
+		RTL8367B_DIS_RGMII_MASK << RTL8367B_DIS_RGMII_SHIFT(id),
+		mode << RTL8367B_DIS_RGMII_SHIFT(id));
+
+	return 0;
+}
+
+static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id,
+				    struct rtl8367_port_ability *pa)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367B_DI_FORCE_MODE |
+		RTL8367B_DI_FORCE_NWAY |
+		RTL8367B_DI_FORCE_TXPAUSE |
+		RTL8367B_DI_FORCE_RXPAUSE |
+		RTL8367B_DI_FORCE_LINK |
+		RTL8367B_DI_FORCE_DUPLEX |
+		RTL8367B_DI_FORCE_SPEED_MASK);
+
+	val = pa->speed;
+	val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0;
+	val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0;
+	val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0;
+	val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0;
+	val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0;
+	val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0;
+
+	REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367b_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id,
+					 unsigned txdelay, unsigned rxdelay)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367B_EXT_RGMXF_RXDELAY_MASK |
+		(RTL8367B_EXT_RGMXF_TXDELAY_MASK <<
+			RTL8367B_EXT_RGMXF_TXDELAY_SHIFT));
+
+	val = rxdelay;
+	val |= txdelay << RTL8367B_EXT_RGMXF_TXDELAY_SHIFT;
+
+	REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id,
+			       struct rtl8367_extif_config *cfg)
+{
+	enum rtl8367_extif_mode mode;
+	int err;
+
+	mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED;
+
+	err = rtl8367b_extif_set_mode(smi, id, mode);
+	if (err)
+		return err;
+
+	if (mode != RTL8367_EXTIF_MODE_DISABLED) {
+		err = rtl8367b_extif_set_force(smi, id, &cfg->ability);
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_set_rgmii_delay(smi, id, cfg->txdelay,
+						     cfg->rxdelay);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id,
+				  const char *name)
+{
+	struct rtl8367_extif_config *cfg;
+	const __be32 *prop;
+	int size;
+	int err;
+
+	prop = of_get_property(smi->parent->of_node, name, &size);
+	if (!prop)
+		return rtl8367b_extif_init(smi, id, NULL);
+
+	if (size != (9 * sizeof(*prop))) {
+		dev_err(smi->parent, "%s property is invalid\n", name);
+		return -EINVAL;
+	}
+
+	cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	cfg->txdelay = be32_to_cpup(prop++);
+	cfg->rxdelay = be32_to_cpup(prop++);
+	cfg->mode = be32_to_cpup(prop++);
+	cfg->ability.force_mode = be32_to_cpup(prop++);
+	cfg->ability.txpause = be32_to_cpup(prop++);
+	cfg->ability.rxpause = be32_to_cpup(prop++);
+	cfg->ability.link = be32_to_cpup(prop++);
+	cfg->ability.duplex = be32_to_cpup(prop++);
+	cfg->ability.speed = be32_to_cpup(prop++);
+
+	err = rtl8367b_extif_init(smi, id, cfg);
+	kfree(cfg);
+
+	return err;
+}
+#else
+static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id,
+				  const char *name)
+{
+	return -EINVAL;
+}
+#endif
+
+static int rtl8367b_setup(struct rtl8366_smi *smi)
+{
+	struct rtl8367_platform_data *pdata;
+	int err;
+	int i;
+
+	pdata = smi->parent->platform_data;
+
+	err = rtl8367b_init_regs(smi);
+	if (err)
+		return err;
+
+	/* initialize external interfaces */
+	if (smi->parent->of_node) {
+		err = rtl8367b_extif_init_of(smi, 0, "realtek,extif0");
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_init_of(smi, 1, "realtek,extif1");
+		if (err)
+			return err;
+	} else {
+		err = rtl8367b_extif_init(smi, 0, pdata->extif0_cfg);
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_init(smi, 1, pdata->extif1_cfg);
+		if (err)
+			return err;
+	}
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8367B_SWC0_REG, RTL8367B_SWC0_MAX_LENGTH_MASK,
+		RTL8367B_SWC0_MAX_LENGTH_1536);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8367B_VLAN_INGRESS_REG, RTL8367B_PORTS_ALL);
+
+	/*
+	 * Setup egress tag mode for each port.
+	 */
+	for (i = 0; i < RTL8367B_NUM_PORTS; i++)
+		REG_RMW(smi,
+			RTL8367B_PORT_MISC_CFG_REG(i),
+			RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK <<
+				RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT,
+			RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL <<
+				RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT);
+
+	return 0;
+}
+
+static int rtl8367b_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				    int port, unsigned long long *val)
+{
+	struct rtl8366_mib_counter *mib;
+	int offset;
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8367B_NUM_PORTS ||
+	    counter >= RTL8367B_NUM_MIB_COUNTERS)
+		return -EINVAL;
+
+	mib = &rtl8367b_mib_counters[counter];
+	addr = RTL8367B_MIB_COUNTER_PORT_OFFSET * port + mib->offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	REG_WR(smi, RTL8367B_MIB_ADDRESS_REG, addr >> 2);
+
+	/* read MIB control register */
+	REG_RD(smi, RTL8367B_MIB_CTRL0_REG(0), &data);
+
+	if (data & RTL8367B_MIB_CTRL0_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8367B_MIB_CTRL0_RESET_MASK)
+		return -EIO;
+
+	if (mib->length == 4)
+		offset = 3;
+	else
+		offset = (mib->offset + 1) % 4;
+
+	mibvalue = 0;
+	for (i = 0; i < mib->length; i++) {
+		REG_RD(smi, RTL8367B_MIB_COUNTER_REG(offset - i), &data);
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367B_TA_VLAN_NUM_WORDS];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8367B_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	REG_WR(smi, RTL8367B_TA_ADDR_REG, vid);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_READ);
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367B_TA_RDDATA_REG(i), &data[i]);
+
+	vlan4k->vid = vid;
+	vlan4k->member = (data[0] >> RTL8367B_TA_VLAN0_MEMBER_SHIFT) &
+			 RTL8367B_TA_VLAN0_MEMBER_MASK;
+	vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) &
+			RTL8367B_TA_VLAN0_UNTAG_MASK;
+	vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) &
+		      RTL8367B_TA_VLAN1_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi,
+				const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367B_TA_VLAN_NUM_WORDS];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8367B_NUM_VIDS ||
+	    vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK ||
+	    vlan4k->untag > RTL8367B_UNTAG_MASK ||
+	    vlan4k->fid > RTL8367B_FIDMAX)
+		return -EINVAL;
+
+	memset(data, 0, sizeof(data));
+
+	data[0] = (vlan4k->member & RTL8367B_TA_VLAN0_MEMBER_MASK) <<
+		  RTL8367B_TA_VLAN0_MEMBER_SHIFT;
+	data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) <<
+		   RTL8367B_TA_VLAN0_UNTAG_SHIFT;
+	data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) <<
+		  RTL8367B_TA_VLAN1_FID_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]);
+
+	/* write VID */
+	REG_WR(smi, RTL8367B_TA_ADDR_REG,
+	       vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE);
+
+	return 0;
+}
+
+static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367B_VLAN_MC_NUM_WORDS];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8367B_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]);
+
+	vlanmc->member = (data[0] >> RTL8367B_VLAN_MC0_MEMBER_SHIFT) &
+			 RTL8367B_VLAN_MC0_MEMBER_MASK;
+	vlanmc->fid = (data[1] >> RTL8367B_VLAN_MC1_FID_SHIFT) &
+		      RTL8367B_VLAN_MC1_FID_MASK;
+	vlanmc->vid = (data[3] >> RTL8367B_VLAN_MC3_EVID_SHIFT) &
+		      RTL8367B_VLAN_MC3_EVID_MASK;
+
+	return 0;
+}
+
+static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367B_VLAN_MC_NUM_WORDS];
+	int err;
+	int i;
+
+	if (index >= RTL8367B_NUM_VLANS ||
+	    vlanmc->vid >= RTL8367B_NUM_VIDS ||
+	    vlanmc->priority > RTL8367B_PRIORITYMAX ||
+	    vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK ||
+	    vlanmc->untag > RTL8367B_UNTAG_MASK ||
+	    vlanmc->fid > RTL8367B_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) <<
+		  RTL8367B_VLAN_MC0_MEMBER_SHIFT;
+	data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) <<
+		  RTL8367B_VLAN_MC1_FID_SHIFT;
+	data[2] = 0;
+	data[3] = (vlanmc->vid & RTL8367B_VLAN_MC3_EVID_MASK) <<
+		   RTL8367B_VLAN_MC3_EVID_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367B_VLAN_MC_BASE(index) + i, data[i]);
+
+	return 0;
+}
+
+static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8367B_NUM_PORTS)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data);
+
+	*val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) &
+	       RTL8367B_VLAN_PVID_CTRL_MASK;
+
+	return 0;
+}
+
+static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port),
+				RTL8367B_VLAN_PVID_CTRL_MASK <<
+					RTL8367B_VLAN_PVID_CTRL_SHIFT(port),
+				(index & RTL8367B_VLAN_PVID_CTRL_MASK) <<
+					RTL8367B_VLAN_PVID_CTRL_SHIFT(port));
+}
+
+static int rtl8367b_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_CTRL_REG,
+				RTL8367B_VLAN_CTRL_ENABLE,
+				(enable) ? RTL8367B_VLAN_CTRL_ENABLE : 0);
+}
+
+static int rtl8367b_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return 0;
+}
+
+static int rtl8367b_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8367B_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8367B_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8367b_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	int err;
+
+	REG_WR(smi, RTL8367B_PORT_ISOLATION_REG(port),
+	       (enable) ? RTL8367B_PORTS_ALL : 0);
+
+	return 0;
+}
+
+static int rtl8367b_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(0), 0,
+				RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK);
+}
+
+static int rtl8367b_sw_get_port_link(struct switch_dev *dev,
+				    int port,
+				    struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8367B_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data);
+
+	link->link = !!(data & RTL8367B_PORT_STATUS_LINK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8367B_PORT_STATUS_DUPLEX);
+	link->rx_flow = !!(data & RTL8367B_PORT_STATUS_RXPAUSE);
+	link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE);
+	link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY);
+
+	speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8367b_sw_get_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8367B_SWC0_REG, &data);
+	val->value.i = (data & RTL8367B_SWC0_MAX_LENGTH_MASK) >>
+			RTL8367B_SWC0_MAX_LENGTH_SHIFT;
+
+	return 0;
+}
+
+static int rtl8367b_sw_set_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 max_len;
+
+	switch (val->value.i) {
+	case 0:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_1522;
+		break;
+	case 1:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_1536;
+		break;
+	case 2:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_1552;
+		break;
+	case 3:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_16000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_SWC0_REG,
+			        RTL8367B_SWC0_MAX_LENGTH_MASK, max_len);
+}
+
+
+static int rtl8367b_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int port;
+
+	port = val->port_vlan;
+	if (port >= RTL8367B_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(port / 8), 0,
+				RTL8367B_MIB_CTRL0_PORT_RESET_MASK(port % 8));
+}
+
+static struct switch_attr rtl8367b_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8367b_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "max_length",
+		.description = "Get/Set the maximum length of valid packets"
+			       "(0:1522, 1:1536, 2:1552, 3:16000)",
+		.set = rtl8367b_sw_set_max_length,
+		.get = rtl8367b_sw_get_max_length,
+		.max = 3,
+	}
+};
+
+static struct switch_attr rtl8367b_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8367b_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr rtl8367b_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	},
+};
+
+static const struct switch_dev_ops rtl8367b_sw_ops = {
+	.attr_global = {
+		.attr = rtl8367b_globals,
+		.n_attr = ARRAY_SIZE(rtl8367b_globals),
+	},
+	.attr_port = {
+		.attr = rtl8367b_port,
+		.n_attr = ARRAY_SIZE(rtl8367b_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8367b_vlan,
+		.n_attr = ARRAY_SIZE(rtl8367b_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8367b_sw_get_port_link,
+};
+
+static int rtl8367b_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8367B";
+	dev->cpu_port = RTL8367B_CPU_PORT_NUM;
+	dev->ports = RTL8367B_NUM_PORTS;
+	dev->vlans = RTL8367B_NUM_VIDS;
+	dev->ops = &rtl8367b_sw_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8367b_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8367b_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8367b_read_phy_reg(smi, addr, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8367b_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8367b_write_phy_reg(smi, addr, reg, val);
+	if (err)
+		return err;
+
+	/* flush write */
+	(void) rtl8367b_read_phy_reg(smi, addr, reg, &t);
+
+	return err;
+}
+
+static int rtl8367b_detect(struct rtl8366_smi *smi)
+{
+	const char *chip_name;
+	u32 chip_num;
+	u32 chip_ver;
+	u32 chip_mode;
+	int ret;
+
+	/* TODO: improve chip detection */
+	rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG,
+			      RTL8367B_RTL_MAGIC_ID_VAL);
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num);
+	if (ret) {
+		dev_err(smi->parent, "unable to read %s register\n",
+			"chip number");
+		return ret;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_VER_REG, &chip_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read %s register\n",
+			"chip version");
+		return ret;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_MODE_REG, &chip_mode);
+	if (ret) {
+		dev_err(smi->parent, "unable to read %s register\n",
+			"chip mode");
+		return ret;
+	}
+
+	switch (chip_ver) {
+	case 0x1000:
+		chip_name = "8367RB";
+		break;
+	case 0x1010:
+		chip_name = "8367R-VB";
+		break;
+	default:
+		dev_err(smi->parent,
+			"unknown chip num:%04x ver:%04x, mode:%04x\n",
+			chip_num, chip_ver, chip_mode);
+		return -ENODEV;
+	}
+
+	dev_info(smi->parent, "RTL%s chip found\n", chip_name);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8367b_smi_ops = {
+	.detect		= rtl8367b_detect,
+	.reset_chip	= rtl8367b_reset_chip,
+	.setup		= rtl8367b_setup,
+
+	.mii_read	= rtl8367b_mii_read,
+	.mii_write	= rtl8367b_mii_write,
+
+	.get_vlan_mc	= rtl8367b_get_vlan_mc,
+	.set_vlan_mc	= rtl8367b_set_vlan_mc,
+	.get_vlan_4k	= rtl8367b_get_vlan_4k,
+	.set_vlan_4k	= rtl8367b_set_vlan_4k,
+	.get_mc_index	= rtl8367b_get_mc_index,
+	.set_mc_index	= rtl8367b_set_mc_index,
+	.get_mib_counter = rtl8367b_get_mib_counter,
+	.is_vlan_valid	= rtl8367b_is_vlan_valid,
+	.enable_vlan	= rtl8367b_enable_vlan,
+	.enable_vlan4k	= rtl8367b_enable_vlan4k,
+	.enable_port	= rtl8367b_enable_port,
+};
+
+static int  rtl8367b_probe(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi;
+	int err;
+
+	smi = rtl8366_smi_probe(pdev);
+	if (!smi)
+		return -ENODEV;
+
+	smi->clk_delay = 1500;
+	smi->cmd_read = 0xb9;
+	smi->cmd_write = 0xb8;
+	smi->ops = &rtl8367b_smi_ops;
+	smi->cpu_port = RTL8367B_CPU_PORT_NUM;
+	smi->num_ports = RTL8367B_NUM_PORTS;
+	smi->num_vlan_mc = RTL8367B_NUM_VLANS;
+	smi->mib_counters = rtl8367b_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8367b_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8367b_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8367b_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+static void rtl8367b_shutdown(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi)
+		rtl8367b_reset_chip(smi);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8367b_match[] = {
+	{ .compatible = "realtek,rtl8367b" },
+	{ .compatible = "rtl8367b" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtl8367b_match);
+#endif
+
+static struct platform_driver rtl8367b_driver = {
+	.driver = {
+		.name		= RTL8367B_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(rtl8367b_match),
+#endif
+	},
+	.probe		= rtl8367b_probe,
+	.remove		= rtl8367b_remove,
+	.shutdown	= rtl8367b_shutdown,
+};
+
+module_platform_driver(rtl8367b_driver);
+
+MODULE_DESCRIPTION("Realtek RTL8367B ethernet switch driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8367B_DRIVER_NAME);
+
diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c
new file mode 100644
index 0000000000..63a9588136
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/swconfig.c
@@ -0,0 +1,1236 @@
+/*
+ * swconfig.c: Switch configuration API
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/capability.h>
+#include <linux/skbuff.h>
+#include <linux/switch.h>
+#include <linux/of.h>
+#include <linux/version.h>
+#include <uapi/linux/mii.h>
+
+#define SWCONFIG_DEVNAME	"switch%d"
+
+#include "swconfig_leds.c"
+
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_LICENSE("GPL");
+
+static int swdev_id;
+static struct list_head swdevs;
+static DEFINE_SPINLOCK(swdevs_lock);
+struct swconfig_callback;
+
+struct swconfig_callback {
+	struct sk_buff *msg;
+	struct genlmsghdr *hdr;
+	struct genl_info *info;
+	int cmd;
+
+	/* callback for filling in the message data */
+	int (*fill)(struct swconfig_callback *cb, void *arg);
+
+	/* callback for closing the message before sending it */
+	int (*close)(struct swconfig_callback *cb, void *arg);
+
+	struct nlattr *nest[4];
+	int args[4];
+};
+
+/* defaults */
+
+static int
+swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	int ret;
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	if (!dev->ops->get_vlan_ports)
+		return -EOPNOTSUPP;
+
+	ret = dev->ops->get_vlan_ports(dev, val);
+	return ret;
+}
+
+static int
+swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct switch_port *ports = val->value.ports;
+	const struct switch_dev_ops *ops = dev->ops;
+	int i;
+
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	/* validate ports */
+	if (val->len > dev->ports)
+		return -EINVAL;
+
+	if (!ops->set_vlan_ports)
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < val->len; i++) {
+		if (ports[i].id >= dev->ports)
+			return -EINVAL;
+
+		if (ops->set_port_pvid &&
+		    !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
+			ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
+	}
+
+	return ops->set_vlan_ports(dev, val);
+}
+
+static int
+swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->ops->set_port_pvid)
+		return -EOPNOTSUPP;
+
+	return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
+}
+
+static int
+swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->ops->get_port_pvid)
+		return -EOPNOTSUPP;
+
+	return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
+}
+
+static int
+swconfig_set_link(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	if (!dev->ops->set_port_link)
+		return -EOPNOTSUPP;
+
+	return dev->ops->set_port_link(dev, val->port_vlan, val->value.link);
+}
+
+static int
+swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct switch_port_link *link = val->value.link;
+
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->ops->get_port_link)
+		return -EOPNOTSUPP;
+
+	memset(link, 0, sizeof(*link));
+	return dev->ops->get_port_link(dev, val->port_vlan, link);
+}
+
+static int
+swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	/* don't complain if not supported by the switch driver */
+	if (!dev->ops->apply_config)
+		return 0;
+
+	return dev->ops->apply_config(dev);
+}
+
+static int
+swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	/* don't complain if not supported by the switch driver */
+	if (!dev->ops->reset_switch)
+		return 0;
+
+	return dev->ops->reset_switch(dev);
+}
+
+enum global_defaults {
+	GLOBAL_APPLY,
+	GLOBAL_RESET,
+};
+
+enum vlan_defaults {
+	VLAN_PORTS,
+};
+
+enum port_defaults {
+	PORT_PVID,
+	PORT_LINK,
+};
+
+static struct switch_attr default_global[] = {
+	[GLOBAL_APPLY] = {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "apply",
+		.description = "Activate changes in the hardware",
+		.set = swconfig_apply_config,
+	},
+	[GLOBAL_RESET] = {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset",
+		.description = "Reset the switch",
+		.set = swconfig_reset_switch,
+	}
+};
+
+static struct switch_attr default_port[] = {
+	[PORT_PVID] = {
+		.type = SWITCH_TYPE_INT,
+		.name = "pvid",
+		.description = "Primary VLAN ID",
+		.set = swconfig_set_pvid,
+		.get = swconfig_get_pvid,
+	},
+	[PORT_LINK] = {
+		.type = SWITCH_TYPE_LINK,
+		.name = "link",
+		.description = "Get port link information",
+		.set = swconfig_set_link,
+		.get = swconfig_get_link,
+	}
+};
+
+static struct switch_attr default_vlan[] = {
+	[VLAN_PORTS] = {
+		.type = SWITCH_TYPE_PORTS,
+		.name = "ports",
+		.description = "VLAN port mapping",
+		.set = swconfig_set_vlan_ports,
+		.get = swconfig_get_vlan_ports,
+	},
+};
+
+static const struct switch_attr *
+swconfig_find_attr_by_name(const struct switch_attrlist *alist,
+				const char *name)
+{
+	int i;
+
+	for (i = 0; i < alist->n_attr; i++)
+		if (strcmp(name, alist->attr[i].name) == 0)
+			return &alist->attr[i];
+
+	return NULL;
+}
+
+static void swconfig_defaults_init(struct switch_dev *dev)
+{
+	const struct switch_dev_ops *ops = dev->ops;
+
+	dev->def_global = 0;
+	dev->def_vlan = 0;
+	dev->def_port = 0;
+
+	if (ops->get_vlan_ports || ops->set_vlan_ports)
+		set_bit(VLAN_PORTS, &dev->def_vlan);
+
+	if (ops->get_port_pvid || ops->set_port_pvid)
+		set_bit(PORT_PVID, &dev->def_port);
+
+	if (ops->get_port_link &&
+	    !swconfig_find_attr_by_name(&ops->attr_port, "link"))
+		set_bit(PORT_LINK, &dev->def_port);
+
+	/* always present, can be no-op */
+	set_bit(GLOBAL_APPLY, &dev->def_global);
+	set_bit(GLOBAL_RESET, &dev->def_global);
+}
+
+
+static struct genl_family switch_fam = {
+	.id = GENL_ID_GENERATE,
+	.name = "switch",
+	.hdrsize = 0,
+	.version = 1,
+	.maxattr = SWITCH_ATTR_MAX,
+};
+
+static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
+	[SWITCH_ATTR_ID] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
+	[SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
+	[SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
+};
+
+static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
+	[SWITCH_PORT_ID] = { .type = NLA_U32 },
+	[SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
+};
+
+static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = {
+	[SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG },
+	[SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG },
+	[SWITCH_LINK_SPEED] = { .type = NLA_U32 },
+};
+
+static inline void
+swconfig_lock(void)
+{
+	spin_lock(&swdevs_lock);
+}
+
+static inline void
+swconfig_unlock(void)
+{
+	spin_unlock(&swdevs_lock);
+}
+
+static struct switch_dev *
+swconfig_get_dev(struct genl_info *info)
+{
+	struct switch_dev *dev = NULL;
+	struct switch_dev *p;
+	int id;
+
+	if (!info->attrs[SWITCH_ATTR_ID])
+		goto done;
+
+	id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
+	swconfig_lock();
+	list_for_each_entry(p, &swdevs, dev_list) {
+		if (id != p->id)
+			continue;
+
+		dev = p;
+		break;
+	}
+	if (dev)
+		mutex_lock(&dev->sw_mutex);
+	else
+		pr_debug("device %d not found\n", id);
+	swconfig_unlock();
+done:
+	return dev;
+}
+
+static inline void
+swconfig_put_dev(struct switch_dev *dev)
+{
+	mutex_unlock(&dev->sw_mutex);
+}
+
+static int
+swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
+{
+	struct switch_attr *op = arg;
+	struct genl_info *info = cb->info;
+	struct sk_buff *msg = cb->msg;
+	int id = cb->args[0];
+	void *hdr;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
+			NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
+	if (IS_ERR(hdr))
+		return -1;
+
+	if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name))
+		goto nla_put_failure;
+	if (op->description)
+		if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION,
+			op->description))
+			goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+	return msg->len;
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+/* spread multipart messages across multiple message buffers */
+static int
+swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
+{
+	struct genl_info *info = cb->info;
+	int restart = 0;
+	int err;
+
+	do {
+		if (!cb->msg) {
+			cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+			if (cb->msg == NULL)
+				goto error;
+		}
+
+		if (!(cb->fill(cb, arg) < 0))
+			break;
+
+		/* fill failed, check if this was already the second attempt */
+		if (restart)
+			goto error;
+
+		/* try again in a new message, send the current one */
+		restart = 1;
+		if (cb->close) {
+			if (cb->close(cb, arg) < 0)
+				goto error;
+		}
+		err = genlmsg_reply(cb->msg, info);
+		cb->msg = NULL;
+		if (err < 0)
+			goto error;
+
+	} while (restart);
+
+	return 0;
+
+error:
+	if (cb->msg)
+		nlmsg_free(cb->msg);
+	return -1;
+}
+
+static int
+swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct switch_attrlist *alist;
+	struct switch_dev *dev;
+	struct swconfig_callback cb;
+	int err = -EINVAL;
+	int i;
+
+	/* defaults */
+	struct switch_attr *def_list;
+	unsigned long *def_active;
+	int n_def;
+
+	dev = swconfig_get_dev(info);
+	if (!dev)
+		return -EINVAL;
+
+	switch (hdr->cmd) {
+	case SWITCH_CMD_LIST_GLOBAL:
+		alist = &dev->ops->attr_global;
+		def_list = default_global;
+		def_active = &dev->def_global;
+		n_def = ARRAY_SIZE(default_global);
+		break;
+	case SWITCH_CMD_LIST_VLAN:
+		alist = &dev->ops->attr_vlan;
+		def_list = default_vlan;
+		def_active = &dev->def_vlan;
+		n_def = ARRAY_SIZE(default_vlan);
+		break;
+	case SWITCH_CMD_LIST_PORT:
+		alist = &dev->ops->attr_port;
+		def_list = default_port;
+		def_active = &dev->def_port;
+		n_def = ARRAY_SIZE(default_port);
+		break;
+	default:
+		WARN_ON(1);
+		goto out;
+	}
+
+	memset(&cb, 0, sizeof(cb));
+	cb.info = info;
+	cb.fill = swconfig_dump_attr;
+	for (i = 0; i < alist->n_attr; i++) {
+		if (alist->attr[i].disabled)
+			continue;
+		cb.args[0] = i;
+		err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
+		if (err < 0)
+			goto error;
+	}
+
+	/* defaults */
+	for (i = 0; i < n_def; i++) {
+		if (!test_bit(i, def_active))
+			continue;
+		cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
+		err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
+		if (err < 0)
+			goto error;
+	}
+	swconfig_put_dev(dev);
+
+	if (!cb.msg)
+		return 0;
+
+	return genlmsg_reply(cb.msg, info);
+
+error:
+	if (cb.msg)
+		nlmsg_free(cb.msg);
+out:
+	swconfig_put_dev(dev);
+	return err;
+}
+
+static const struct switch_attr *
+swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
+		struct switch_val *val)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct switch_attrlist *alist;
+	const struct switch_attr *attr = NULL;
+	unsigned int attr_id;
+
+	/* defaults */
+	struct switch_attr *def_list;
+	unsigned long *def_active;
+	int n_def;
+
+	if (!info->attrs[SWITCH_ATTR_OP_ID])
+		goto done;
+
+	switch (hdr->cmd) {
+	case SWITCH_CMD_SET_GLOBAL:
+	case SWITCH_CMD_GET_GLOBAL:
+		alist = &dev->ops->attr_global;
+		def_list = default_global;
+		def_active = &dev->def_global;
+		n_def = ARRAY_SIZE(default_global);
+		break;
+	case SWITCH_CMD_SET_VLAN:
+	case SWITCH_CMD_GET_VLAN:
+		alist = &dev->ops->attr_vlan;
+		def_list = default_vlan;
+		def_active = &dev->def_vlan;
+		n_def = ARRAY_SIZE(default_vlan);
+		if (!info->attrs[SWITCH_ATTR_OP_VLAN])
+			goto done;
+		val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
+		if (val->port_vlan >= dev->vlans)
+			goto done;
+		break;
+	case SWITCH_CMD_SET_PORT:
+	case SWITCH_CMD_GET_PORT:
+		alist = &dev->ops->attr_port;
+		def_list = default_port;
+		def_active = &dev->def_port;
+		n_def = ARRAY_SIZE(default_port);
+		if (!info->attrs[SWITCH_ATTR_OP_PORT])
+			goto done;
+		val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
+		if (val->port_vlan >= dev->ports)
+			goto done;
+		break;
+	default:
+		WARN_ON(1);
+		goto done;
+	}
+
+	if (!alist)
+		goto done;
+
+	attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
+	if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
+		attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
+		if (attr_id >= n_def)
+			goto done;
+		if (!test_bit(attr_id, def_active))
+			goto done;
+		attr = &def_list[attr_id];
+	} else {
+		if (attr_id >= alist->n_attr)
+			goto done;
+		attr = &alist->attr[attr_id];
+	}
+
+	if (attr->disabled)
+		attr = NULL;
+
+done:
+	if (!attr)
+		pr_debug("attribute lookup failed\n");
+	val->attr = attr;
+	return attr;
+}
+
+static int
+swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
+		struct switch_val *val, int max)
+{
+	struct nlattr *nla;
+	int rem;
+
+	val->len = 0;
+	nla_for_each_nested(nla, head, rem) {
+		struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
+		struct switch_port *port;
+
+		if (val->len >= max)
+			return -EINVAL;
+
+		port = &val->value.ports[val->len];
+
+		if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
+				port_policy))
+			return -EINVAL;
+
+		if (!tb[SWITCH_PORT_ID])
+			return -EINVAL;
+
+		port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
+		if (tb[SWITCH_PORT_FLAG_TAGGED])
+			port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+	}
+
+	return 0;
+}
+
+static int
+swconfig_parse_link(struct sk_buff *msg, struct nlattr *nla,
+		    struct switch_port_link *link)
+{
+	struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1];
+
+	if (nla_parse_nested(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy))
+		return -EINVAL;
+
+	link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX];
+	link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG];
+	link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]);
+
+	return 0;
+}
+
+static int
+swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
+{
+	const struct switch_attr *attr;
+	struct switch_dev *dev;
+	struct switch_val val;
+	int err = -EINVAL;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	dev = swconfig_get_dev(info);
+	if (!dev)
+		return -EINVAL;
+
+	memset(&val, 0, sizeof(val));
+	attr = swconfig_lookup_attr(dev, info, &val);
+	if (!attr || !attr->set)
+		goto error;
+
+	val.attr = attr;
+	switch (attr->type) {
+	case SWITCH_TYPE_NOVAL:
+		break;
+	case SWITCH_TYPE_INT:
+		if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
+			goto error;
+		val.value.i =
+			nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
+		break;
+	case SWITCH_TYPE_STRING:
+		if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
+			goto error;
+		val.value.s =
+			nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
+		break;
+	case SWITCH_TYPE_PORTS:
+		val.value.ports = dev->portbuf;
+		memset(dev->portbuf, 0,
+			sizeof(struct switch_port) * dev->ports);
+
+		/* TODO: implement multipart? */
+		if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
+			err = swconfig_parse_ports(skb,
+				info->attrs[SWITCH_ATTR_OP_VALUE_PORTS],
+				&val, dev->ports);
+			if (err < 0)
+				goto error;
+		} else {
+			val.len = 0;
+			err = 0;
+		}
+		break;
+	case SWITCH_TYPE_LINK:
+		val.value.link = &dev->linkbuf;
+		memset(&dev->linkbuf, 0, sizeof(struct switch_port_link));
+
+		if (info->attrs[SWITCH_ATTR_OP_VALUE_LINK]) {
+			err = swconfig_parse_link(skb,
+						  info->attrs[SWITCH_ATTR_OP_VALUE_LINK],
+						  val.value.link);
+			if (err < 0)
+				goto error;
+		} else {
+			val.len = 0;
+			err = 0;
+		}
+		break;
+	default:
+		goto error;
+	}
+
+	err = attr->set(dev, attr, &val);
+error:
+	swconfig_put_dev(dev);
+	return err;
+}
+
+static int
+swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
+{
+	if (cb->nest[0])
+		nla_nest_end(cb->msg, cb->nest[0]);
+	return 0;
+}
+
+static int
+swconfig_send_port(struct swconfig_callback *cb, void *arg)
+{
+	const struct switch_port *port = arg;
+	struct nlattr *p = NULL;
+
+	if (!cb->nest[0]) {
+		cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
+		if (!cb->nest[0])
+			return -1;
+	}
+
+	p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
+	if (!p)
+		goto error;
+
+	if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id))
+		goto nla_put_failure;
+	if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+		if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED))
+			goto nla_put_failure;
+	}
+
+	nla_nest_end(cb->msg, p);
+	return 0;
+
+nla_put_failure:
+		nla_nest_cancel(cb->msg, p);
+error:
+	nla_nest_cancel(cb->msg, cb->nest[0]);
+	return -1;
+}
+
+static int
+swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
+		const struct switch_val *val)
+{
+	struct swconfig_callback cb;
+	int err = 0;
+	int i;
+
+	if (!val->value.ports)
+		return -EINVAL;
+
+	memset(&cb, 0, sizeof(cb));
+	cb.cmd = attr;
+	cb.msg = *msg;
+	cb.info = info;
+	cb.fill = swconfig_send_port;
+	cb.close = swconfig_close_portlist;
+
+	cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
+	for (i = 0; i < val->len; i++) {
+		err = swconfig_send_multipart(&cb, &val->value.ports[i]);
+		if (err)
+			goto done;
+	}
+	err = val->len;
+	swconfig_close_portlist(&cb, NULL);
+	*msg = cb.msg;
+
+done:
+	return err;
+}
+
+static int
+swconfig_send_link(struct sk_buff *msg, struct genl_info *info, int attr,
+		   const struct switch_port_link *link)
+{
+	struct nlattr *p = NULL;
+	int err = 0;
+
+	p = nla_nest_start(msg, attr);
+	if (link->link) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_LINK))
+			goto nla_put_failure;
+	}
+	if (link->duplex) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_DUPLEX))
+			goto nla_put_failure;
+	}
+	if (link->aneg) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_ANEG))
+			goto nla_put_failure;
+	}
+	if (link->tx_flow) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_TX_FLOW))
+			goto nla_put_failure;
+	}
+	if (link->rx_flow) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_RX_FLOW))
+			goto nla_put_failure;
+	}
+	if (nla_put_u32(msg, SWITCH_LINK_SPEED, link->speed))
+		goto nla_put_failure;
+	if (link->eee & ADVERTISED_100baseT_Full) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_100BASET))
+			goto nla_put_failure;
+	}
+	if (link->eee & ADVERTISED_1000baseT_Full) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_1000BASET))
+			goto nla_put_failure;
+	}
+	nla_nest_end(msg, p);
+
+	return err;
+
+nla_put_failure:
+	nla_nest_cancel(msg, p);
+	return -1;
+}
+
+static int
+swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct switch_attr *attr;
+	struct switch_dev *dev;
+	struct sk_buff *msg = NULL;
+	struct switch_val val;
+	int err = -EINVAL;
+	int cmd = hdr->cmd;
+
+	dev = swconfig_get_dev(info);
+	if (!dev)
+		return -EINVAL;
+
+	memset(&val, 0, sizeof(val));
+	attr = swconfig_lookup_attr(dev, info, &val);
+	if (!attr || !attr->get)
+		goto error;
+
+	if (attr->type == SWITCH_TYPE_PORTS) {
+		val.value.ports = dev->portbuf;
+		memset(dev->portbuf, 0,
+			sizeof(struct switch_port) * dev->ports);
+	} else if (attr->type == SWITCH_TYPE_LINK) {
+		val.value.link = &dev->linkbuf;
+		memset(&dev->linkbuf, 0, sizeof(struct switch_port_link));
+	}
+
+	err = attr->get(dev, attr, &val);
+	if (err)
+		goto error;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		goto error;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
+			0, cmd);
+	if (IS_ERR(hdr))
+		goto nla_put_failure;
+
+	switch (attr->type) {
+	case SWITCH_TYPE_INT:
+		if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i))
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_STRING:
+		if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s))
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_PORTS:
+		err = swconfig_send_ports(&msg, info,
+				SWITCH_ATTR_OP_VALUE_PORTS, &val);
+		if (err < 0)
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_LINK:
+		err = swconfig_send_link(msg, info,
+					 SWITCH_ATTR_OP_VALUE_LINK, val.value.link);
+		if (err < 0)
+			goto nla_put_failure;
+		break;
+	default:
+		pr_debug("invalid type in attribute\n");
+		err = -EINVAL;
+		goto error;
+	}
+	genlmsg_end(msg, hdr);
+	err = msg->len;
+	if (err < 0)
+		goto nla_put_failure;
+
+	swconfig_put_dev(dev);
+	return genlmsg_reply(msg, info);
+
+nla_put_failure:
+	if (msg)
+		nlmsg_free(msg);
+error:
+	swconfig_put_dev(dev);
+	if (!err)
+		err = -ENOMEM;
+	return err;
+}
+
+static int
+swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+		const struct switch_dev *dev)
+{
+	struct nlattr *p = NULL, *m = NULL;
+	void *hdr;
+	int i;
+
+	hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
+			SWITCH_CMD_NEW_ATTR);
+	if (IS_ERR(hdr))
+		return -1;
+
+	if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port))
+		goto nla_put_failure;
+
+	m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP);
+	if (!m)
+		goto nla_put_failure;
+	for (i = 0; i < dev->ports; i++) {
+		p = nla_nest_start(msg, SWITCH_ATTR_PORTS);
+		if (!p)
+			continue;
+		if (dev->portmap[i].s) {
+			if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT,
+						dev->portmap[i].s))
+				goto nla_put_failure;
+			if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT,
+						dev->portmap[i].virt))
+				goto nla_put_failure;
+		}
+		nla_nest_end(msg, p);
+	}
+	nla_nest_end(msg, m);
+	genlmsg_end(msg, hdr);
+	return msg->len;
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+static int swconfig_dump_switches(struct sk_buff *skb,
+		struct netlink_callback *cb)
+{
+	struct switch_dev *dev;
+	int start = cb->args[0];
+	int idx = 0;
+
+	swconfig_lock();
+	list_for_each_entry(dev, &swdevs, dev_list) {
+		if (++idx <= start)
+			continue;
+		if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid,
+				cb->nlh->nlmsg_seq, NLM_F_MULTI,
+				dev) < 0)
+			break;
+	}
+	swconfig_unlock();
+	cb->args[0] = idx;
+
+	return skb->len;
+}
+
+static int
+swconfig_done(struct netlink_callback *cb)
+{
+	return 0;
+}
+
+static struct genl_ops swconfig_ops[] = {
+	{
+		.cmd = SWITCH_CMD_LIST_GLOBAL,
+		.doit = swconfig_list_attrs,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_LIST_VLAN,
+		.doit = swconfig_list_attrs,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_LIST_PORT,
+		.doit = swconfig_list_attrs,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_GLOBAL,
+		.doit = swconfig_get_attr,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_VLAN,
+		.doit = swconfig_get_attr,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_PORT,
+		.doit = swconfig_get_attr,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_SET_GLOBAL,
+		.flags = GENL_ADMIN_PERM,
+		.doit = swconfig_set_attr,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_SET_VLAN,
+		.flags = GENL_ADMIN_PERM,
+		.doit = swconfig_set_attr,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_SET_PORT,
+		.flags = GENL_ADMIN_PERM,
+		.doit = swconfig_set_attr,
+		.policy = switch_policy,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_SWITCH,
+		.dumpit = swconfig_dump_switches,
+		.policy = switch_policy,
+		.done = swconfig_done,
+	}
+};
+
+#ifdef CONFIG_OF
+void
+of_switch_load_portmap(struct switch_dev *dev)
+{
+	struct device_node *port;
+
+	if (!dev->of_node)
+		return;
+
+	for_each_child_of_node(dev->of_node, port) {
+		const __be32 *prop;
+		const char *segment;
+		int size, phys;
+
+		if (!of_device_is_compatible(port, "swconfig,port"))
+			continue;
+
+		if (of_property_read_string(port, "swconfig,segment", &segment))
+			continue;
+
+		prop = of_get_property(port, "swconfig,portmap", &size);
+		if (!prop)
+			continue;
+
+		if (size != (2 * sizeof(*prop))) {
+			pr_err("%s: failed to parse port mapping\n",
+					port->name);
+			continue;
+		}
+
+		phys = be32_to_cpup(prop++);
+		if ((phys < 0) | (phys >= dev->ports)) {
+			pr_err("%s: physical port index out of range\n",
+					port->name);
+			continue;
+		}
+
+		dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL);
+		dev->portmap[phys].virt = be32_to_cpup(prop);
+		pr_debug("Found port: %s, physical: %d, virtual: %d\n",
+			segment, phys, dev->portmap[phys].virt);
+	}
+}
+#endif
+
+int
+register_switch(struct switch_dev *dev, struct net_device *netdev)
+{
+	struct switch_dev *sdev;
+	const int max_switches = 8 * sizeof(unsigned long);
+	unsigned long in_use = 0;
+	int err;
+	int i;
+
+	INIT_LIST_HEAD(&dev->dev_list);
+	if (netdev) {
+		dev->netdev = netdev;
+		if (!dev->alias)
+			dev->alias = netdev->name;
+	}
+	BUG_ON(!dev->alias);
+
+	/* Make sure swdev_id doesn't overflow */
+	if (swdev_id == INT_MAX) {
+		return -ENOMEM;
+	}
+
+	if (dev->ports > 0) {
+		dev->portbuf = kzalloc(sizeof(struct switch_port) *
+				dev->ports, GFP_KERNEL);
+		if (!dev->portbuf)
+			return -ENOMEM;
+		dev->portmap = kzalloc(sizeof(struct switch_portmap) *
+				dev->ports, GFP_KERNEL);
+		if (!dev->portmap) {
+			kfree(dev->portbuf);
+			return -ENOMEM;
+		}
+	}
+	swconfig_defaults_init(dev);
+	mutex_init(&dev->sw_mutex);
+	swconfig_lock();
+	dev->id = ++swdev_id;
+
+	list_for_each_entry(sdev, &swdevs, dev_list) {
+		if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i))
+			continue;
+		if (i < 0 || i > max_switches)
+			continue;
+
+		set_bit(i, &in_use);
+	}
+	i = find_first_zero_bit(&in_use, max_switches);
+
+	if (i == max_switches) {
+		swconfig_unlock();
+		return -ENFILE;
+	}
+
+#ifdef CONFIG_OF
+	if (dev->ports)
+		of_switch_load_portmap(dev);
+#endif
+
+	/* fill device name */
+	snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i);
+
+	list_add_tail(&dev->dev_list, &swdevs);
+	swconfig_unlock();
+
+	err = swconfig_create_led_trigger(dev);
+	if (err)
+		return err;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(register_switch);
+
+void
+unregister_switch(struct switch_dev *dev)
+{
+	swconfig_destroy_led_trigger(dev);
+	kfree(dev->portbuf);
+	mutex_lock(&dev->sw_mutex);
+	swconfig_lock();
+	list_del(&dev->dev_list);
+	swconfig_unlock();
+	mutex_unlock(&dev->sw_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_switch);
+
+int
+switch_generic_set_link(struct switch_dev *dev, int port,
+			struct switch_port_link *link)
+{
+	if (WARN_ON(!dev->ops->phy_write16))
+		return -ENOTSUPP;
+
+	/* Generic implementation */
+	if (link->aneg) {
+		dev->ops->phy_write16(dev, port, MII_BMCR, 0x0000);
+		dev->ops->phy_write16(dev, port, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+	} else {
+		u16 bmcr = 0;
+
+		if (link->duplex)
+			bmcr |= BMCR_FULLDPLX;
+
+		switch (link->speed) {
+		case SWITCH_PORT_SPEED_10:
+			break;
+		case SWITCH_PORT_SPEED_100:
+			bmcr |= BMCR_SPEED100;
+			break;
+		case SWITCH_PORT_SPEED_1000:
+			bmcr |= BMCR_SPEED1000;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+
+		dev->ops->phy_write16(dev, port, MII_BMCR, bmcr);
+	}
+
+	return 0;
+}
+
+static int __init
+swconfig_init(void)
+{
+	INIT_LIST_HEAD(&swdevs);
+	
+	return genl_register_family_with_ops(&switch_fam, swconfig_ops);
+}
+
+static void __exit
+swconfig_exit(void)
+{
+	genl_unregister_family(&switch_fam);
+}
+
+module_init(swconfig_init);
+module_exit(swconfig_exit);
diff --git a/target/linux/generic/files/drivers/net/phy/swconfig_leds.c b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c
new file mode 100644
index 0000000000..dad3c393a0
--- /dev/null
+++ b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c
@@ -0,0 +1,439 @@
+/*
+ * swconfig_led.c: LED trigger support for the switch configuration API
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifdef CONFIG_SWCONFIG_LEDS
+
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+
+#define SWCONFIG_LED_TIMER_INTERVAL	(HZ / 10)
+#define SWCONFIG_LED_NUM_PORTS		32
+
+#define SWCONFIG_LED_PORT_SPEED_NA	0x01	/* unknown speed */
+#define SWCONFIG_LED_PORT_SPEED_10	0x02	/* 10 Mbps */
+#define SWCONFIG_LED_PORT_SPEED_100	0x04	/* 100 Mbps */
+#define SWCONFIG_LED_PORT_SPEED_1000	0x08	/* 1000 Mbps */
+#define SWCONFIG_LED_PORT_SPEED_ALL	(SWCONFIG_LED_PORT_SPEED_NA | \
+					 SWCONFIG_LED_PORT_SPEED_10 | \
+					 SWCONFIG_LED_PORT_SPEED_100 | \
+					 SWCONFIG_LED_PORT_SPEED_1000)
+
+struct switch_led_trigger {
+	struct led_trigger trig;
+	struct switch_dev *swdev;
+
+	struct delayed_work sw_led_work;
+	u32 port_mask;
+	u32 port_link;
+	unsigned long port_traffic[SWCONFIG_LED_NUM_PORTS];
+	u8 link_speed[SWCONFIG_LED_NUM_PORTS];
+};
+
+struct swconfig_trig_data {
+	struct led_classdev *led_cdev;
+	struct switch_dev *swdev;
+
+	rwlock_t lock;
+	u32 port_mask;
+
+	bool prev_link;
+	unsigned long prev_traffic;
+	enum led_brightness prev_brightness;
+	u8 speed_mask;
+};
+
+static void
+swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data,
+			     enum led_brightness brightness)
+{
+	led_set_brightness(trig_data->led_cdev, brightness);
+	trig_data->prev_brightness = brightness;
+}
+
+static void
+swconfig_trig_update_port_mask(struct led_trigger *trigger)
+{
+	struct list_head *entry;
+	struct switch_led_trigger *sw_trig;
+	u32 port_mask;
+
+	if (!trigger)
+		return;
+
+	sw_trig = (void *) trigger;
+
+	port_mask = 0;
+	read_lock(&trigger->leddev_list_lock);
+	list_for_each(entry, &trigger->led_cdevs) {
+		struct led_classdev *led_cdev;
+		struct swconfig_trig_data *trig_data;
+
+		led_cdev = list_entry(entry, struct led_classdev, trig_list);
+		trig_data = led_cdev->trigger_data;
+		if (trig_data) {
+			read_lock(&trig_data->lock);
+			port_mask |= trig_data->port_mask;
+			read_unlock(&trig_data->lock);
+		}
+	}
+	read_unlock(&trigger->leddev_list_lock);
+
+	sw_trig->port_mask = port_mask;
+
+	if (port_mask)
+		schedule_delayed_work(&sw_trig->sw_led_work,
+				      SWCONFIG_LED_TIMER_INTERVAL);
+	else
+		cancel_delayed_work_sync(&sw_trig->sw_led_work);
+}
+
+static ssize_t
+swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	unsigned long port_mask;
+	int ret;
+	bool changed;
+
+	ret = kstrtoul(buf, 0, &port_mask);
+	if (ret)
+		return ret;
+
+	write_lock(&trig_data->lock);
+
+	changed = (trig_data->port_mask != port_mask);
+	if (changed) {
+		trig_data->port_mask = port_mask;
+		if (port_mask == 0)
+			swconfig_trig_set_brightness(trig_data, LED_OFF);
+	}
+
+	write_unlock(&trig_data->lock);
+
+	if (changed)
+		swconfig_trig_update_port_mask(led_cdev->trigger);
+
+	return size;
+}
+
+static ssize_t
+swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+
+	read_lock(&trig_data->lock);
+	sprintf(buf, "%#x\n", trig_data->port_mask);
+	read_unlock(&trig_data->lock);
+
+	return strlen(buf) + 1;
+}
+
+static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show,
+		   swconfig_trig_port_mask_store);
+
+/* speed_mask file handler - display value */
+static ssize_t swconfig_trig_speed_mask_show(struct device *dev,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+
+	read_lock(&trig_data->lock);
+	sprintf(buf, "%#x\n", trig_data->speed_mask);
+	read_unlock(&trig_data->lock);
+
+	return strlen(buf) + 1;
+}
+
+/* speed_mask file handler - store value */
+static ssize_t swconfig_trig_speed_mask_store(struct device *dev,
+					      struct device_attribute *attr,
+					      const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	u8 speed_mask;
+	int ret;
+
+	ret = kstrtou8(buf, 0, &speed_mask);
+	if (ret)
+		return ret;
+
+	write_lock(&trig_data->lock);
+	trig_data->speed_mask = speed_mask & SWCONFIG_LED_PORT_SPEED_ALL;
+	write_unlock(&trig_data->lock);
+
+	return size;
+}
+
+/* speed_mask special file */
+static DEVICE_ATTR(speed_mask, 0644, swconfig_trig_speed_mask_show,
+		   swconfig_trig_speed_mask_store);
+
+static void
+swconfig_trig_activate(struct led_classdev *led_cdev)
+{
+	struct switch_led_trigger *sw_trig;
+	struct swconfig_trig_data *trig_data;
+	int err;
+
+	if (led_cdev->trigger->activate != swconfig_trig_activate)
+		return;
+
+	trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
+	if (!trig_data)
+		return;
+
+	sw_trig = (void *) led_cdev->trigger;
+
+	rwlock_init(&trig_data->lock);
+	trig_data->led_cdev = led_cdev;
+	trig_data->swdev = sw_trig->swdev;
+	trig_data->speed_mask = SWCONFIG_LED_PORT_SPEED_ALL;
+	led_cdev->trigger_data = trig_data;
+
+	err = device_create_file(led_cdev->dev, &dev_attr_port_mask);
+	if (err)
+		goto err_free;
+
+	err = device_create_file(led_cdev->dev, &dev_attr_speed_mask);
+	if (err)
+		goto err_dev_free;
+
+	return;
+
+err_dev_free:
+	device_remove_file(led_cdev->dev, &dev_attr_port_mask);
+
+err_free:
+	led_cdev->trigger_data = NULL;
+	kfree(trig_data);
+}
+
+static void
+swconfig_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct swconfig_trig_data *trig_data;
+
+	swconfig_trig_update_port_mask(led_cdev->trigger);
+
+	trig_data = (void *) led_cdev->trigger_data;
+	if (trig_data) {
+		device_remove_file(led_cdev->dev, &dev_attr_port_mask);
+		device_remove_file(led_cdev->dev, &dev_attr_speed_mask);
+		kfree(trig_data);
+	}
+}
+
+static void
+swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
+			struct led_classdev *led_cdev)
+{
+	struct swconfig_trig_data *trig_data;
+	u32 port_mask;
+	bool link;
+	u8 speed_mask;
+
+	trig_data = led_cdev->trigger_data;
+	if (!trig_data)
+		return;
+
+	read_lock(&trig_data->lock);
+	port_mask = trig_data->port_mask;
+	speed_mask = trig_data->speed_mask;
+	read_unlock(&trig_data->lock);
+
+	link = !!(sw_trig->port_link & port_mask);
+	if (!link) {
+		if (link != trig_data->prev_link)
+			swconfig_trig_set_brightness(trig_data, LED_OFF);
+	} else {
+		unsigned long traffic;
+		int speedok;	/* link speed flag */
+		int i;
+
+		traffic = 0;
+		speedok = 0;
+		for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
+			if (port_mask & (1 << i))
+				if (sw_trig->link_speed[i] & speed_mask) {
+					traffic += sw_trig->port_traffic[i];
+					speedok = 1;
+				}
+		}
+
+		if (speedok) {
+			/* At least one port speed matches speed_mask */
+			if (trig_data->prev_brightness != LED_FULL)
+				swconfig_trig_set_brightness(trig_data,
+							     LED_FULL);
+			else if (traffic != trig_data->prev_traffic)
+				swconfig_trig_set_brightness(trig_data,
+							     LED_OFF);
+		} else if (trig_data->prev_brightness != LED_OFF)
+			swconfig_trig_set_brightness(trig_data, LED_OFF);
+
+		trig_data->prev_traffic = traffic;
+	}
+
+	trig_data->prev_link = link;
+}
+
+static void
+swconfig_trig_update_leds(struct switch_led_trigger *sw_trig)
+{
+	struct list_head *entry;
+	struct led_trigger *trigger;
+
+	trigger = &sw_trig->trig;
+	read_lock(&trigger->leddev_list_lock);
+	list_for_each(entry, &trigger->led_cdevs) {
+		struct led_classdev *led_cdev;
+
+		led_cdev = list_entry(entry, struct led_classdev, trig_list);
+		swconfig_trig_led_event(sw_trig, led_cdev);
+	}
+	read_unlock(&trigger->leddev_list_lock);
+}
+
+static void
+swconfig_led_work_func(struct work_struct *work)
+{
+	struct switch_led_trigger *sw_trig;
+	struct switch_dev *swdev;
+	u32 port_mask;
+	u32 link;
+	int i;
+
+	sw_trig = container_of(work, struct switch_led_trigger,
+			       sw_led_work.work);
+
+	port_mask = sw_trig->port_mask;
+	swdev = sw_trig->swdev;
+
+	link = 0;
+	for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
+		u32 port_bit;
+
+		sw_trig->link_speed[i] = 0;
+
+		port_bit = BIT(i);
+		if ((port_mask & port_bit) == 0)
+			continue;
+
+		if (swdev->ops->get_port_link) {
+			struct switch_port_link port_link;
+
+			memset(&port_link, '\0', sizeof(port_link));
+			swdev->ops->get_port_link(swdev, i, &port_link);
+
+			if (port_link.link) {
+				link |= port_bit;
+				switch (port_link.speed) {
+				case SWITCH_PORT_SPEED_UNKNOWN:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_NA;
+					break;
+				case SWITCH_PORT_SPEED_10:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_10;
+					break;
+				case SWITCH_PORT_SPEED_100:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_100;
+					break;
+				case SWITCH_PORT_SPEED_1000:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_1000;
+					break;
+				}
+			}
+		}
+
+		if (swdev->ops->get_port_stats) {
+			struct switch_port_stats port_stats;
+
+			memset(&port_stats, '\0', sizeof(port_stats));
+			swdev->ops->get_port_stats(swdev, i, &port_stats);
+			sw_trig->port_traffic[i] = port_stats.tx_bytes +
+						   port_stats.rx_bytes;
+		}
+	}
+
+	sw_trig->port_link = link;
+
+	swconfig_trig_update_leds(sw_trig);
+
+	schedule_delayed_work(&sw_trig->sw_led_work,
+			      SWCONFIG_LED_TIMER_INTERVAL);
+}
+
+static int
+swconfig_create_led_trigger(struct switch_dev *swdev)
+{
+	struct switch_led_trigger *sw_trig;
+	int err;
+
+	if (!swdev->ops->get_port_link)
+		return 0;
+
+	sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL);
+	if (!sw_trig)
+		return -ENOMEM;
+
+	sw_trig->swdev = swdev;
+	sw_trig->trig.name = swdev->devname;
+	sw_trig->trig.activate = swconfig_trig_activate;
+	sw_trig->trig.deactivate = swconfig_trig_deactivate;
+
+	INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
+
+	err = led_trigger_register(&sw_trig->trig);
+	if (err)
+		goto err_free;
+
+	swdev->led_trigger = sw_trig;
+
+	return 0;
+
+err_free:
+	kfree(sw_trig);
+	return err;
+}
+
+static void
+swconfig_destroy_led_trigger(struct switch_dev *swdev)
+{
+	struct switch_led_trigger *sw_trig;
+
+	sw_trig = swdev->led_trigger;
+	if (sw_trig) {
+		cancel_delayed_work_sync(&sw_trig->sw_led_work);
+		led_trigger_unregister(&sw_trig->trig);
+		kfree(sw_trig);
+	}
+}
+
+#else /* SWCONFIG_LEDS */
+static inline int
+swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; }
+
+static inline void
+swconfig_destroy_led_trigger(struct switch_dev *swdev) { }
+#endif /* CONFIG_SWCONFIG_LEDS */
diff --git a/target/linux/generic/files/fs/yaffs2/Kconfig b/target/linux/generic/files/fs/yaffs2/Kconfig
new file mode 100644
index 0000000000..408570fc7a
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/Kconfig
@@ -0,0 +1,171 @@
+#
+# yaffs file system configurations
+#
+
+config YAFFS_FS
+	tristate "yaffs2 file system support"
+	default n
+	depends on MTD_BLOCK
+	select YAFFS_YAFFS1
+	select YAFFS_YAFFS2
+	help
+	  yaffs2, or Yet Another Flash File System, is a file system
+	  optimised for NAND Flash chips.
+
+	  To compile the yaffs2 file system support as a module, choose M
+	  here: the module will be called yaffs2.
+
+	  If unsure, say N.
+
+	  Further information on yaffs2 is available at
+	  <http://www.aleph1.co.uk/yaffs/>.
+
+config YAFFS_YAFFS1
+	bool "512 byte / page devices"
+	depends on YAFFS_FS
+	default y
+	help
+	  Enable yaffs1 support -- yaffs for 512 byte / page devices
+
+	  Not needed for 2K-page devices.
+
+	  If unsure, say Y.
+
+config YAFFS_9BYTE_TAGS
+	bool "Use older-style on-NAND data format with pageStatus byte"
+	depends on YAFFS_YAFFS1
+	default n
+	help
+
+	  Older-style on-NAND data format has a "pageStatus" byte to record
+	  chunk/page state.  This byte is zero when the page is discarded.
+	  Choose this option if you have existing on-NAND data using this
+	  format that you need to continue to support.  New data written
+	  also uses the older-style format.  Note: Use of this option
+	  generally requires that MTD's oob layout be adjusted to use the
+	  older-style format.  See notes on tags formats and MTD versions
+	  in yaffs_mtdif1.c.
+
+	  If unsure, say N.
+
+config YAFFS_DOES_ECC
+	bool "Lets yaffs do its own ECC"
+	depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
+	default n
+	help
+	  This enables yaffs to use its own ECC functions instead of using
+	  the ones from the generic MTD-NAND driver.
+
+	  If unsure, say N.
+
+config YAFFS_ECC_WRONG_ORDER
+	bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
+	depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
+	default n
+	help
+	  This makes yaffs_ecc.c use the same ecc byte order as Steven
+	  Hill's nand_ecc.c. If not set, then you get the same ecc byte
+	  order as SmartMedia.
+
+	  If unsure, say N.
+
+config YAFFS_YAFFS2
+	bool "2048 byte (or larger) / page devices"
+	depends on YAFFS_FS
+	default y
+	help
+	  Enable yaffs2 support -- yaffs for >= 2K bytes per page devices
+
+	  If unsure, say Y.
+
+config YAFFS_AUTO_YAFFS2
+	bool "Autoselect yaffs2 format"
+	depends on YAFFS_YAFFS2
+	default y
+	help
+	  Without this, you need to explicitely use yaffs2 as the file
+	  system type. With this, you can say "yaffs" and yaffs or yaffs2
+	  will be used depending on the device page size (yaffs on
+	  512-byte page devices, yaffs2 on 2K page devices).
+
+	  If unsure, say Y.
+
+config YAFFS_DISABLE_TAGS_ECC
+	bool "Disable yaffs from doing ECC on tags by default"
+	depends on YAFFS_FS && YAFFS_YAFFS2
+	default n
+	help
+	  This defaults yaffs to using its own ECC calculations on tags instead of
+	  just relying on the MTD.
+	  This behavior can also be overridden with tags_ecc_on and
+	  tags_ecc_off mount options.
+
+	  If unsure, say N.
+
+config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+	bool "Force chunk erase check"
+	depends on YAFFS_FS
+	default n
+	help
+          Normally yaffs only checks chunks before writing until an erased
+	  chunk is found. This helps to detect any partially written
+	  chunks that might have happened due to power loss.
+
+	  Enabling this forces on the test that chunks are erased in flash
+	  before writing to them. This takes more time but is potentially
+	  a bit more secure.
+
+	  Suggest setting Y during development and ironing out driver
+	  issues etc. Suggest setting to N if you want faster writing.
+
+	  If unsure, say Y.
+
+config YAFFS_EMPTY_LOST_AND_FOUND
+	bool "Empty lost and found on boot"
+	depends on YAFFS_FS
+	default n
+	help
+	  If this is enabled then the contents of lost and found is
+	  automatically dumped at mount.
+
+	  If unsure, say N.
+
+config YAFFS_DISABLE_BLOCK_REFRESHING
+	bool "Disable yaffs2 block refreshing"
+	depends on YAFFS_FS
+	default n
+	help
+	 If this is set, then block refreshing is disabled.
+	 Block refreshing infrequently refreshes the oldest block in
+	 a yaffs2 file system. This mechanism helps to refresh flash to
+	 mitigate against data loss. This is particularly useful for MLC.
+
+	  If unsure, say N.
+
+config YAFFS_DISABLE_BACKGROUND
+	bool "Disable yaffs2 background processing"
+	depends on YAFFS_FS
+	default n
+	help
+	 If this is set, then background processing is disabled.
+	 Background processing makes many foreground activities faster.
+
+	 If unsure, say N.
+
+config YAFFS_DISABLE_BAD_BLOCK_MARKING
+	bool "Disable yaffs2 bad block marking"
+	depends on YAFFS_FS
+	default n
+	help
+	 Useful during early flash bring up to prevent problems causing
+	 lots of bad block marking.
+
+	 If unsure, say N.
+
+config YAFFS_XATTR
+	bool "Enable yaffs2 xattr support"
+	depends on YAFFS_FS
+	default y
+	help
+	 If this is set then yaffs2 will provide xattr support.
+	 If unsure, say Y.
diff --git a/target/linux/generic/files/fs/yaffs2/Makefile b/target/linux/generic/files/fs/yaffs2/Makefile
new file mode 100644
index 0000000000..f9a9fb1bfd
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the linux YAFFS filesystem routines.
+#
+
+obj-$(CONFIG_YAFFS_FS) += yaffs.o
+
+yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
+yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
+yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
+yaffs-y += yaffs_mtdif.o
+yaffs-y += yaffs_nameval.o yaffs_attribs.o
+yaffs-y += yaffs_allocator.o
+yaffs-y += yaffs_yaffs1.o
+yaffs-y += yaffs_yaffs2.o
+yaffs-y += yaffs_bitmap.o
+yaffs-y += yaffs_summary.o
+yaffs-y += yaffs_verify.o
+
diff --git a/target/linux/generic/files/fs/yaffs2/NOTE.openwrt b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt
new file mode 100644
index 0000000000..e84fbe6fc6
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt
@@ -0,0 +1,4 @@
+The yaffs2 source has been fetched from the yaffs2 GIT tree.
+
+URL: git://www.aleph1.co.uk/yaffs2
+Version: 583dbd9cc2668870cb013f051ba59f7d3e513dae (2015-06-02)
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_allocator.c b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.c
new file mode 100644
index 0000000000..c8f2861c53
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.c
@@ -0,0 +1,357 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_allocator.h"
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yportenv.h"
+
+/*
+ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
+ * of approx 100 objects that are themn allocated singly.
+ * This is basically a simplified slab allocator.
+ *
+ * We don't use the Linux slab allocator because slab does not allow
+ * us to dump all the objects in one hit when we do a umount and tear
+ * down  all the tnodes and objects. slab requires that we first free
+ * the individual objects.
+ *
+ * Once yaffs has been mainlined I shall try to motivate for a change
+ * to slab to provide the extra features we need here.
+ */
+
+struct yaffs_tnode_list {
+	struct yaffs_tnode_list *next;
+	struct yaffs_tnode *tnodes;
+};
+
+struct yaffs_obj_list {
+	struct yaffs_obj_list *next;
+	struct yaffs_obj *objects;
+};
+
+struct yaffs_allocator {
+	int n_tnodes_created;
+	struct yaffs_tnode *free_tnodes;
+	int n_free_tnodes;
+	struct yaffs_tnode_list *alloc_tnode_list;
+
+	int n_obj_created;
+	struct list_head free_objs;
+	int n_free_objects;
+
+	struct yaffs_obj_list *allocated_obj_list;
+};
+
+static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator =
+	    (struct yaffs_allocator *)dev->allocator;
+	struct yaffs_tnode_list *tmp;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	while (allocator->alloc_tnode_list) {
+		tmp = allocator->alloc_tnode_list->next;
+
+		kfree(allocator->alloc_tnode_list->tnodes);
+		kfree(allocator->alloc_tnode_list);
+		allocator->alloc_tnode_list = tmp;
+	}
+
+	allocator->free_tnodes = NULL;
+	allocator->n_free_tnodes = 0;
+	allocator->n_tnodes_created = 0;
+}
+
+static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	allocator->alloc_tnode_list = NULL;
+	allocator->free_tnodes = NULL;
+	allocator->n_free_tnodes = 0;
+	allocator->n_tnodes_created = 0;
+}
+
+static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
+{
+	struct yaffs_allocator *allocator =
+	    (struct yaffs_allocator *)dev->allocator;
+	int i;
+	struct yaffs_tnode *new_tnodes;
+	u8 *mem;
+	struct yaffs_tnode *curr;
+	struct yaffs_tnode *next;
+	struct yaffs_tnode_list *tnl;
+
+	if (!allocator) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	if (n_tnodes < 1)
+		return YAFFS_OK;
+
+	/* make these things */
+	new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
+	mem = (u8 *) new_tnodes;
+
+	if (!new_tnodes) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"yaffs: Could not allocate Tnodes");
+		return YAFFS_FAIL;
+	}
+
+	/* New hookup for wide tnodes */
+	for (i = 0; i < n_tnodes - 1; i++) {
+		curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
+		next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
+		curr->internal[0] = next;
+	}
+
+	curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
+	curr->internal[0] = allocator->free_tnodes;
+	allocator->free_tnodes = (struct yaffs_tnode *)mem;
+
+	allocator->n_free_tnodes += n_tnodes;
+	allocator->n_tnodes_created += n_tnodes;
+
+	/* Now add this bunch of tnodes to a list for freeing up.
+	 * NB If we can't add this to the management list it isn't fatal
+	 * but it just means we can't free this bunch of tnodes later.
+	 */
+	tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
+	if (!tnl) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Could not add tnodes to management list");
+		return YAFFS_FAIL;
+	} else {
+		tnl->tnodes = new_tnodes;
+		tnl->next = allocator->alloc_tnode_list;
+		allocator->alloc_tnode_list = tnl;
+	}
+
+	yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
+
+	return YAFFS_OK;
+}
+
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator =
+	    (struct yaffs_allocator *)dev->allocator;
+	struct yaffs_tnode *tn = NULL;
+
+	if (!allocator) {
+		BUG();
+		return NULL;
+	}
+
+	/* If there are none left make more */
+	if (!allocator->free_tnodes)
+		yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
+
+	if (allocator->free_tnodes) {
+		tn = allocator->free_tnodes;
+		allocator->free_tnodes = allocator->free_tnodes->internal[0];
+		allocator->n_free_tnodes--;
+	}
+
+	return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	if (tn) {
+		tn->internal[0] = allocator->free_tnodes;
+		allocator->free_tnodes = tn;
+		allocator->n_free_tnodes++;
+	}
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+}
+
+/*--------------- yaffs_obj alloaction ------------------------
+ *
+ * Free yaffs_objs are stored in a list using obj->siblings.
+ * The blocks of allocated objects are stored in a linked list.
+ */
+
+static void yaffs_init_raw_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	allocator->allocated_obj_list = NULL;
+	INIT_LIST_HEAD(&allocator->free_objs);
+	allocator->n_free_objects = 0;
+}
+
+static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+	struct yaffs_obj_list *tmp;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	while (allocator->allocated_obj_list) {
+		tmp = allocator->allocated_obj_list->next;
+		kfree(allocator->allocated_obj_list->objects);
+		kfree(allocator->allocated_obj_list);
+		allocator->allocated_obj_list = tmp;
+	}
+
+	INIT_LIST_HEAD(&allocator->free_objs);
+	allocator->n_free_objects = 0;
+	allocator->n_obj_created = 0;
+}
+
+static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+	int i;
+	struct yaffs_obj *new_objs;
+	struct yaffs_obj_list *list;
+
+	if (!allocator) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	if (n_obj < 1)
+		return YAFFS_OK;
+
+	/* make these things */
+	new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
+	list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
+
+	if (!new_objs || !list) {
+		kfree(new_objs);
+		new_objs = NULL;
+		kfree(list);
+		list = NULL;
+		yaffs_trace(YAFFS_TRACE_ALLOCATE,
+			"Could not allocate more objects");
+		return YAFFS_FAIL;
+	}
+
+	/* Hook them into the free list */
+	for (i = 0; i < n_obj; i++)
+		list_add(&new_objs[i].siblings, &allocator->free_objs);
+
+	allocator->n_free_objects += n_obj;
+	allocator->n_obj_created += n_obj;
+
+	/* Now add this bunch of Objects to a list for freeing up. */
+
+	list->objects = new_objs;
+	list->next = allocator->allocated_obj_list;
+	allocator->allocated_obj_list = list;
+
+	return YAFFS_OK;
+}
+
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj = NULL;
+	struct list_head *lh;
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return obj;
+	}
+
+	/* If there are none left make more */
+	if (list_empty(&allocator->free_objs))
+		yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
+
+	if (!list_empty(&allocator->free_objs)) {
+		lh = allocator->free_objs.next;
+		obj = list_entry(lh, struct yaffs_obj, siblings);
+		list_del_init(lh);
+		allocator->n_free_objects--;
+	}
+
+	return obj;
+}
+
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
+{
+
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	/* Link into the free list. */
+	list_add(&obj->siblings, &allocator->free_objs);
+	allocator->n_free_objects++;
+}
+
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
+{
+
+	if (!dev->allocator) {
+		BUG();
+		return;
+	}
+
+	yaffs_deinit_raw_tnodes(dev);
+	yaffs_deinit_raw_objs(dev);
+	kfree(dev->allocator);
+	dev->allocator = NULL;
+}
+
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator;
+
+	if (dev->allocator) {
+		BUG();
+		return;
+	}
+
+	allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
+	if (allocator) {
+		dev->allocator = allocator;
+		yaffs_init_raw_tnodes(dev);
+		yaffs_init_raw_objs(dev);
+	}
+}
+
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_allocator.h b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.h
new file mode 100644
index 0000000000..a8cc322642
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_allocator.h
@@ -0,0 +1,30 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ALLOCATOR_H__
+#define __YAFFS_ALLOCATOR_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
+
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
new file mode 100644
index 0000000000..711941f137
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
@@ -0,0 +1,132 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_guts.h"
+#include "yaffs_attribs.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+#define IATTR_UID ia_uid
+#define IATTR_GID ia_gid
+#else
+#define IATTR_UID ia_uid.val
+#define IATTR_GID ia_gid.val
+#endif
+
+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
+{
+	obj->yst_uid = oh->yst_uid;
+	obj->yst_gid = oh->yst_gid;
+	obj->yst_atime = oh->yst_atime;
+	obj->yst_mtime = oh->yst_mtime;
+	obj->yst_ctime = oh->yst_ctime;
+	obj->yst_rdev = oh->yst_rdev;
+}
+
+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
+{
+	oh->yst_uid = obj->yst_uid;
+	oh->yst_gid = obj->yst_gid;
+	oh->yst_atime = obj->yst_atime;
+	oh->yst_mtime = obj->yst_mtime;
+	oh->yst_ctime = obj->yst_ctime;
+	oh->yst_rdev = obj->yst_rdev;
+
+}
+
+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
+{
+	obj->yst_mtime = Y_CURRENT_TIME;
+	if (do_a)
+		obj->yst_atime = obj->yst_mtime;
+	if (do_c)
+		obj->yst_ctime = obj->yst_mtime;
+}
+
+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
+{
+	yaffs_load_current_time(obj, 1, 1);
+	obj->yst_rdev = rdev;
+	obj->yst_uid = uid;
+	obj->yst_gid = gid;
+}
+
+static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
+{
+	YCHAR *alias = NULL;
+	obj = yaffs_get_equivalent_obj(obj);
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		return obj->variant.file_variant.file_size;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		alias = obj->variant.symlink_variant.alias;
+		if (!alias)
+			return 0;
+		return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
+	default:
+		return 0;
+	}
+}
+
+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
+{
+	unsigned int valid = attr->ia_valid;
+
+	if (valid & ATTR_MODE)
+		obj->yst_mode = attr->ia_mode;
+	if (valid & ATTR_UID)
+		obj->yst_uid = attr->IATTR_UID;
+	if (valid & ATTR_GID)
+		obj->yst_gid = attr->IATTR_GID;
+
+	if (valid & ATTR_ATIME)
+		obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+	if (valid & ATTR_CTIME)
+		obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+	if (valid & ATTR_MTIME)
+		obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+
+	if (valid & ATTR_SIZE)
+		yaffs_resize_file(obj, attr->ia_size);
+
+	yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
+
+	return YAFFS_OK;
+
+}
+
+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
+{
+	unsigned int valid = 0;
+
+	attr->ia_mode = obj->yst_mode;
+	valid |= ATTR_MODE;
+	attr->IATTR_UID = obj->yst_uid;
+	valid |= ATTR_UID;
+	attr->IATTR_GID = obj->yst_gid;
+	valid |= ATTR_GID;
+
+	Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
+	valid |= ATTR_ATIME;
+	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
+	valid |= ATTR_CTIME;
+	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
+	valid |= ATTR_MTIME;
+
+	attr->ia_size = yaffs_get_file_size(obj);
+	valid |= ATTR_SIZE;
+
+	attr->ia_valid = valid;
+
+	return YAFFS_OK;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_attribs.h b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.h
new file mode 100644
index 0000000000..5b21b085b7
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.h
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ATTRIBS_H__
+#define __YAFFS_ATTRIBS_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c
new file mode 100644
index 0000000000..4440e930d6
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.c
@@ -0,0 +1,97 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_bitmap.h"
+#include "yaffs_trace.h"
+/*
+ * Chunk bitmap manipulations
+ */
+
+static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
+{
+	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"BlockBits block %d is not valid",
+			blk);
+		BUG();
+	}
+	return dev->chunk_bits +
+	    (dev->chunk_bit_stride * (blk - dev->internal_start_block));
+}
+
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
+{
+	if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
+	    chunk < 0 || chunk >= dev->param.chunks_per_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Chunk Id (%d:%d) invalid",
+			blk, chunk);
+		BUG();
+	}
+}
+
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	memset(blk_bits, 0, dev->chunk_bit_stride);
+}
+
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	yaffs_verify_chunk_bit_id(dev, blk, chunk);
+	blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	yaffs_verify_chunk_bit_id(dev, blk, chunk);
+	blk_bits[chunk / 8] |= (1 << (chunk & 7));
+}
+
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	yaffs_verify_chunk_bit_id(dev, blk, chunk);
+	return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+}
+
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+	int i;
+
+	for (i = 0; i < dev->chunk_bit_stride; i++) {
+		if (*blk_bits)
+			return 1;
+		blk_bits++;
+	}
+	return 0;
+}
+
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+	int i;
+	int n = 0;
+
+	for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
+		n += hweight8(*blk_bits);
+
+	return n;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h
new file mode 100644
index 0000000000..e26b37d89a
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_bitmap.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+#ifndef __YAFFS_BITMAP_H__
+#define __YAFFS_BITMAP_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c
new file mode 100644
index 0000000000..16ee1e0695
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.c
@@ -0,0 +1,466 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_checkptrw.h"
+#include "yaffs_getblockinfo.h"
+
+struct yaffs_checkpt_chunk_hdr {
+	int version;
+	int seq;
+	u32 sum;
+	u32 xor;
+} ;
+
+
+static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
+{
+	return chunk - dev->chunk_offset;
+}
+
+static int apply_block_offset(struct yaffs_dev *dev, int block)
+{
+	return block - dev->block_offset;
+}
+
+static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_chunk_hdr hdr;
+
+	hdr.version = YAFFS_CHECKPOINT_VERSION;
+	hdr.seq = dev->checkpt_page_seq;
+	hdr.sum = dev->checkpt_sum;
+	hdr.xor = dev->checkpt_xor;
+
+	dev->checkpt_byte_offs = sizeof(hdr);
+
+	memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
+}
+
+static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_chunk_hdr hdr;
+
+	memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
+
+	dev->checkpt_byte_offs = sizeof(hdr);
+
+	return hdr.version == YAFFS_CHECKPOINT_VERSION &&
+		hdr.seq == dev->checkpt_page_seq &&
+		hdr.sum == dev->checkpt_sum &&
+		hdr.xor == dev->checkpt_xor;
+}
+
+static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
+{
+	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checkpt blocks_avail = %d", blocks_avail);
+
+	return (blocks_avail <= 0) ? 0 : 1;
+}
+
+static int yaffs_checkpt_erase(struct yaffs_dev *dev)
+{
+	int i;
+
+	if (!dev->drv.drv_erase_fn)
+		return 0;
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checking blocks %d to %d",
+		dev->internal_start_block, dev->internal_end_block);
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
+		int offset_i = apply_block_offset(dev, i);
+		int result;
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"erasing checkpt block %d", i);
+
+			dev->n_erasures++;
+
+			result = dev->drv.drv_erase_fn(dev, offset_i);
+			if(result) {
+				bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+				dev->n_erased_blocks++;
+				dev->n_free_chunks +=
+				    dev->param.chunks_per_block;
+			} else {
+				dev->drv.drv_mark_bad_fn(dev, offset_i);
+				bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+			}
+		}
+	}
+
+	dev->blocks_in_checkpt = 0;
+
+	return 1;
+}
+
+static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
+{
+	int i;
+	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"allocating checkpt block: erased %d reserved %d avail %d next %d ",
+		dev->n_erased_blocks, dev->param.n_reserved_blocks,
+		blocks_avail, dev->checkpt_next_block);
+
+	if (dev->checkpt_next_block >= 0 &&
+	    dev->checkpt_next_block <= dev->internal_end_block &&
+	    blocks_avail > 0) {
+
+		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+		     i++) {
+			struct yaffs_block_info *bi;
+
+			bi = yaffs_get_block_info(dev, i);
+			if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+				dev->checkpt_next_block = i + 1;
+				dev->checkpt_cur_block = i;
+				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+					"allocating checkpt block %d", i);
+				return;
+			}
+		}
+	}
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
+
+	dev->checkpt_next_block = -1;
+	dev->checkpt_cur_block = -1;
+}
+
+static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
+{
+	int i;
+	struct yaffs_ext_tags tags;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"find next checkpt block: start:  blocks %d next %d",
+		dev->blocks_in_checkpt, dev->checkpt_next_block);
+
+	if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
+		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+		     i++) {
+			int chunk = i * dev->param.chunks_per_block;
+			enum yaffs_block_state state;
+			u32 seq;
+
+			dev->tagger.read_chunk_tags_fn(dev,
+					apply_chunk_offset(dev, chunk),
+					NULL, &tags);
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+				"find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
+				i, (int) state,
+				tags.obj_id, tags.seq_number,
+				tags.ecc_result);
+
+			if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
+				continue;
+
+			dev->tagger.query_block_fn(dev,
+						apply_block_offset(dev, i),
+						&state, &seq);
+			if (state == YAFFS_BLOCK_STATE_DEAD)
+				continue;
+
+			/* Right kind of block */
+			dev->checkpt_next_block = tags.obj_id;
+			dev->checkpt_cur_block = i;
+			dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
+			dev->blocks_in_checkpt++;
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+				"found checkpt block %d", i);
+			return;
+		}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
+
+	dev->checkpt_next_block = -1;
+	dev->checkpt_cur_block = -1;
+}
+
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
+{
+	int i;
+
+	dev->checkpt_open_write = writing;
+
+	/* Got the functions we need? */
+	if (!dev->tagger.write_chunk_tags_fn ||
+	    !dev->tagger.read_chunk_tags_fn ||
+	    !dev->drv.drv_erase_fn ||
+	    !dev->drv.drv_mark_bad_fn)
+		return 0;
+
+	if (writing && !yaffs2_checkpt_space_ok(dev))
+		return 0;
+
+	if (!dev->checkpt_buffer)
+		dev->checkpt_buffer =
+		    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+	if (!dev->checkpt_buffer)
+		return 0;
+
+	dev->checkpt_page_seq = 0;
+	dev->checkpt_byte_count = 0;
+	dev->checkpt_sum = 0;
+	dev->checkpt_xor = 0;
+	dev->checkpt_cur_block = -1;
+	dev->checkpt_cur_chunk = -1;
+	dev->checkpt_next_block = dev->internal_start_block;
+
+	if (writing) {
+		memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+		yaffs2_checkpt_init_chunk_hdr(dev);
+		return yaffs_checkpt_erase(dev);
+	}
+
+	/* Opening for a read */
+	/* Set to a value that will kick off a read */
+	dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
+	/* A checkpoint block list of 1 checkpoint block per 16 block is
+	 * (hopefully) going to be way more than we need */
+	dev->blocks_in_checkpt = 0;
+	dev->checkpt_max_blocks =
+	    (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
+	if (!dev->checkpt_block_list)
+		dev->checkpt_block_list =
+		      kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
+
+	if (!dev->checkpt_block_list)
+		return 0;
+
+	for (i = 0; i < dev->checkpt_max_blocks; i++)
+		dev->checkpt_block_list[i] = -1;
+
+	return 1;
+}
+
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
+{
+	u32 composite_sum;
+
+	composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
+	*sum = composite_sum;
+	return 1;
+}
+
+static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
+{
+	int chunk;
+	int offset_chunk;
+	struct yaffs_ext_tags tags;
+
+	if (dev->checkpt_cur_block < 0) {
+		yaffs2_checkpt_find_erased_block(dev);
+		dev->checkpt_cur_chunk = 0;
+	}
+
+	if (dev->checkpt_cur_block < 0)
+		return 0;
+
+	tags.is_deleted = 0;
+	tags.obj_id = dev->checkpt_next_block;	/* Hint to next place to look */
+	tags.chunk_id = dev->checkpt_page_seq + 1;
+	tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
+	tags.n_bytes = dev->data_bytes_per_chunk;
+	if (dev->checkpt_cur_chunk == 0) {
+		/* First chunk we write for the block? Set block state to
+		   checkpoint */
+		struct yaffs_block_info *bi =
+		    yaffs_get_block_info(dev, dev->checkpt_cur_block);
+		bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		dev->blocks_in_checkpt++;
+	}
+
+	chunk =
+	    dev->checkpt_cur_block * dev->param.chunks_per_block +
+	    dev->checkpt_cur_chunk;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
+		chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
+		tags.obj_id, tags.chunk_id);
+
+	offset_chunk = apply_chunk_offset(dev, chunk);
+
+	dev->n_page_writes++;
+
+	dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
+				       dev->checkpt_buffer, &tags);
+	dev->checkpt_page_seq++;
+	dev->checkpt_cur_chunk++;
+	if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
+		dev->checkpt_cur_chunk = 0;
+		dev->checkpt_cur_block = -1;
+	}
+	memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+
+	yaffs2_checkpt_init_chunk_hdr(dev);
+
+
+	return 1;
+}
+
+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
+{
+	int i = 0;
+	int ok = 1;
+	u8 *data_bytes = (u8 *) data;
+
+	if (!dev->checkpt_buffer)
+		return 0;
+
+	if (!dev->checkpt_open_write)
+		return -1;
+
+	while (i < n_bytes && ok) {
+		dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
+		dev->checkpt_sum += *data_bytes;
+		dev->checkpt_xor ^= *data_bytes;
+
+		dev->checkpt_byte_offs++;
+		i++;
+		data_bytes++;
+		dev->checkpt_byte_count++;
+
+		if (dev->checkpt_byte_offs < 0 ||
+		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
+			ok = yaffs2_checkpt_flush_buffer(dev);
+	}
+
+	return i;
+}
+
+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
+{
+	int i = 0;
+	struct yaffs_ext_tags tags;
+	int chunk;
+	int offset_chunk;
+	u8 *data_bytes = (u8 *) data;
+
+	if (!dev->checkpt_buffer)
+		return 0;
+
+	if (dev->checkpt_open_write)
+		return -1;
+
+	while (i < n_bytes) {
+
+		if (dev->checkpt_byte_offs < 0 ||
+		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
+
+			if (dev->checkpt_cur_block < 0) {
+				yaffs2_checkpt_find_block(dev);
+				dev->checkpt_cur_chunk = 0;
+			}
+
+			/* Bail out if we can't find a checpoint block */
+			if (dev->checkpt_cur_block < 0)
+				break;
+
+			chunk = dev->checkpt_cur_block *
+			    dev->param.chunks_per_block +
+			    dev->checkpt_cur_chunk;
+
+			offset_chunk = apply_chunk_offset(dev, chunk);
+			dev->n_page_reads++;
+
+			/* Read in the next chunk */
+			dev->tagger.read_chunk_tags_fn(dev,
+						offset_chunk,
+						dev->checkpt_buffer,
+						&tags);
+
+			/* Bail out if the chunk is corrupted. */
+			if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
+			    tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+			    tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
+				break;
+
+			/* Bail out if it is not a checkpoint chunk. */
+			if(!yaffs2_checkpt_check_chunk_hdr(dev))
+				break;
+
+			dev->checkpt_page_seq++;
+			dev->checkpt_cur_chunk++;
+
+			if (dev->checkpt_cur_chunk >=
+					dev->param.chunks_per_block)
+				dev->checkpt_cur_block = -1;
+
+		}
+
+		*data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
+		dev->checkpt_sum += *data_bytes;
+		dev->checkpt_xor ^= *data_bytes;
+		dev->checkpt_byte_offs++;
+		i++;
+		data_bytes++;
+		dev->checkpt_byte_count++;
+	}
+
+	return i; /* Number of bytes read */
+}
+
+int yaffs_checkpt_close(struct yaffs_dev *dev)
+{
+	int i;
+
+	if (dev->checkpt_open_write) {
+		if (dev->checkpt_byte_offs !=
+			sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
+			yaffs2_checkpt_flush_buffer(dev);
+	} else if (dev->checkpt_block_list) {
+		for (i = 0;
+		     i < dev->blocks_in_checkpt &&
+		     dev->checkpt_block_list[i] >= 0; i++) {
+			int blk = dev->checkpt_block_list[i];
+			struct yaffs_block_info *bi = NULL;
+
+			if (dev->internal_start_block <= blk &&
+			    blk <= dev->internal_end_block)
+				bi = yaffs_get_block_info(dev, blk);
+			if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
+				bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		}
+	}
+
+	dev->n_free_chunks -=
+		dev->blocks_in_checkpt * dev->param.chunks_per_block;
+	dev->n_erased_blocks -= dev->blocks_in_checkpt;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
+		dev->checkpt_byte_count);
+
+	if (dev->checkpt_buffer)
+		return 1;
+	else
+		return 0;
+}
+
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
+{
+	/* Erase the checkpoint data */
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checkpoint invalidate of %d blocks",
+		dev->blocks_in_checkpt);
+
+	return yaffs_checkpt_erase(dev);
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h
new file mode 100644
index 0000000000..cdbaba7153
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_checkptrw.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CHECKPTRW_H__
+#define __YAFFS_CHECKPTRW_H__
+
+#include "yaffs_guts.h"
+
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
+
+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
+
+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
+
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
+
+int yaffs_checkpt_close(struct yaffs_dev *dev);
+
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_ecc.c b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.c
new file mode 100644
index 0000000000..9294107c15
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.c
@@ -0,0 +1,281 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
+ * such ECC blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#include "yportenv.h"
+
+#include "yaffs_ecc.h"
+
+/* Table generated by gen-ecc.c
+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
+ * for each byte of data. These are instead provided in a table in bits7..2.
+ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
+ * and therefore this bytes influence on the line parity.
+ */
+
+static const unsigned char column_parity_table[] = {
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+
+/* Calculate the ECC for a 256-byte block of data */
+void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
+{
+	unsigned int i;
+	unsigned char col_parity = 0;
+	unsigned char line_parity = 0;
+	unsigned char line_parity_prime = 0;
+	unsigned char t;
+	unsigned char b;
+
+	for (i = 0; i < 256; i++) {
+		b = column_parity_table[*data++];
+		col_parity ^= b;
+
+		if (b & 0x01) {	/* odd number of bits in the byte */
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+	}
+
+	ecc[2] = (~col_parity) | 0x03;
+
+	t = 0;
+	if (line_parity & 0x80)
+		t |= 0x80;
+	if (line_parity_prime & 0x80)
+		t |= 0x40;
+	if (line_parity & 0x40)
+		t |= 0x20;
+	if (line_parity_prime & 0x40)
+		t |= 0x10;
+	if (line_parity & 0x20)
+		t |= 0x08;
+	if (line_parity_prime & 0x20)
+		t |= 0x04;
+	if (line_parity & 0x10)
+		t |= 0x02;
+	if (line_parity_prime & 0x10)
+		t |= 0x01;
+	ecc[1] = ~t;
+
+	t = 0;
+	if (line_parity & 0x08)
+		t |= 0x80;
+	if (line_parity_prime & 0x08)
+		t |= 0x40;
+	if (line_parity & 0x04)
+		t |= 0x20;
+	if (line_parity_prime & 0x04)
+		t |= 0x10;
+	if (line_parity & 0x02)
+		t |= 0x08;
+	if (line_parity_prime & 0x02)
+		t |= 0x04;
+	if (line_parity & 0x01)
+		t |= 0x02;
+	if (line_parity_prime & 0x01)
+		t |= 0x01;
+	ecc[0] = ~t;
+
+}
+
+/* Correct the ECC on a 256 byte block of data */
+
+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
+		      const unsigned char *test_ecc)
+{
+	unsigned char d0, d1, d2;	/* deltas */
+
+	d0 = read_ecc[0] ^ test_ecc[0];
+	d1 = read_ecc[1] ^ test_ecc[1];
+	d2 = read_ecc[2] ^ test_ecc[2];
+
+	if ((d0 | d1 | d2) == 0)
+		return 0;	/* no error */
+
+	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
+		/* Single bit (recoverable) error in data */
+
+		unsigned byte;
+		unsigned bit;
+
+		bit = byte = 0;
+
+		if (d1 & 0x80)
+			byte |= 0x80;
+		if (d1 & 0x20)
+			byte |= 0x40;
+		if (d1 & 0x08)
+			byte |= 0x20;
+		if (d1 & 0x02)
+			byte |= 0x10;
+		if (d0 & 0x80)
+			byte |= 0x08;
+		if (d0 & 0x20)
+			byte |= 0x04;
+		if (d0 & 0x08)
+			byte |= 0x02;
+		if (d0 & 0x02)
+			byte |= 0x01;
+
+		if (d2 & 0x80)
+			bit |= 0x04;
+		if (d2 & 0x20)
+			bit |= 0x02;
+		if (d2 & 0x08)
+			bit |= 0x01;
+
+		data[byte] ^= (1 << bit);
+
+		return 1;	/* Corrected the error */
+	}
+
+	if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
+		/* Reccoverable error in ecc */
+
+		read_ecc[0] = test_ecc[0];
+		read_ecc[1] = test_ecc[1];
+		read_ecc[2] = test_ecc[2];
+
+		return 1;	/* Corrected the error */
+	}
+
+	/* Unrecoverable error */
+
+	return -1;
+
+}
+
+/*
+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
+ */
+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
+			  struct yaffs_ecc_other *ecc_other)
+{
+	unsigned int i;
+	unsigned char col_parity = 0;
+	unsigned line_parity = 0;
+	unsigned line_parity_prime = 0;
+	unsigned char b;
+
+	for (i = 0; i < n_bytes; i++) {
+		b = column_parity_table[*data++];
+		col_parity ^= b;
+
+		if (b & 0x01) {
+			/* odd number of bits in the byte */
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+
+	}
+
+	ecc_other->col_parity = (col_parity >> 2) & 0x3f;
+	ecc_other->line_parity = line_parity;
+	ecc_other->line_parity_prime = line_parity_prime;
+}
+
+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
+			    struct yaffs_ecc_other *read_ecc,
+			    const struct yaffs_ecc_other *test_ecc)
+{
+	unsigned char delta_col;	/* column parity delta */
+	unsigned delta_line;	/* line parity delta */
+	unsigned delta_line_prime;	/* line parity delta */
+	unsigned bit;
+
+	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
+	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
+	delta_line_prime =
+	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
+
+	if ((delta_col | delta_line | delta_line_prime) == 0)
+		return 0;	/* no error */
+
+	if (delta_line == ~delta_line_prime &&
+	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
+		/* Single bit (recoverable) error in data */
+
+		bit = 0;
+
+		if (delta_col & 0x20)
+			bit |= 0x04;
+		if (delta_col & 0x08)
+			bit |= 0x02;
+		if (delta_col & 0x02)
+			bit |= 0x01;
+
+		if (delta_line >= n_bytes)
+			return -1;
+
+		data[delta_line] ^= (1 << bit);
+
+		return 1;	/* corrected */
+	}
+
+	if ((hweight32(delta_line) +
+	     hweight32(delta_line_prime) +
+	     hweight8(delta_col)) == 1) {
+		/* Reccoverable error in ecc */
+
+		*read_ecc = *test_ecc;
+		return 1;	/* corrected */
+	}
+
+	/* Unrecoverable error */
+
+	return -1;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_ecc.h b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.h
new file mode 100644
index 0000000000..17d47bd80f
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_ecc.h
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data.
+ * Thus, two such ECC blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#ifndef __YAFFS_ECC_H__
+#define __YAFFS_ECC_H__
+
+struct yaffs_ecc_other {
+	unsigned char col_parity;
+	unsigned line_parity;
+	unsigned line_parity_prime;
+};
+
+void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
+		      const unsigned char *test_ecc);
+
+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
+			  struct yaffs_ecc_other *ecc);
+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
+			    struct yaffs_ecc_other *read_ecc,
+			    const struct yaffs_ecc_other *test_ecc);
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h b/target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h
new file mode 100644
index 0000000000..8fd0802bdd
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_getblockinfo.h
@@ -0,0 +1,35 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GETBLOCKINFO_H__
+#define __YAFFS_GETBLOCKINFO_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+
+/* Function to manipulate block info */
+static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
+							      *dev, int blk)
+{
+	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>> yaffs: get_block_info block %d is not valid",
+			blk);
+		BUG();
+	}
+	return &dev->block_info[blk - dev->internal_start_block];
+}
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.c b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
new file mode 100644
index 0000000000..89fb2a9bba
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
@@ -0,0 +1,5140 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yportenv.h"
+#include "yaffs_trace.h"
+
+#include "yaffs_guts.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_tagsmarshall.h"
+#include "yaffs_nand.h"
+#include "yaffs_yaffs1.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_verify.h"
+#include "yaffs_nand.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_nameval.h"
+#include "yaffs_allocator.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
+
+/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
+#define YAFFS_GC_GOOD_ENOUGH 2
+#define YAFFS_GC_PASSIVE_THRESHOLD 4
+
+#include "yaffs_ecc.h"
+
+/* Forward declarations */
+
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+			     const u8 *buffer, int n_bytes, int use_reserve);
+
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+				int buffer_size);
+
+/* Function to calculate chunk and offset */
+
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+				int *chunk_out, u32 *offset_out)
+{
+	int chunk;
+	u32 offset;
+
+	chunk = (u32) (addr >> dev->chunk_shift);
+
+	if (dev->chunk_div == 1) {
+		/* easy power of 2 case */
+		offset = (u32) (addr & dev->chunk_mask);
+	} else {
+		/* Non power-of-2 case */
+
+		loff_t chunk_base;
+
+		chunk /= dev->chunk_div;
+
+		chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
+		offset = (u32) (addr - chunk_base);
+	}
+
+	*chunk_out = chunk;
+	*offset_out = offset;
+}
+
+/* Function to return the number of shifts for a power of 2 greater than or
+ * equal to the given number
+ * Note we don't try to cater for all possible numbers and this does not have to
+ * be hellishly efficient.
+ */
+
+static inline u32 calc_shifts_ceiling(u32 x)
+{
+	int extra_bits;
+	int shifts;
+
+	shifts = extra_bits = 0;
+
+	while (x > 1) {
+		if (x & 1)
+			extra_bits++;
+		x >>= 1;
+		shifts++;
+	}
+
+	if (extra_bits)
+		shifts++;
+
+	return shifts;
+}
+
+/* Function to return the number of shifts to get a 1 in bit 0
+ */
+
+static inline u32 calc_shifts(u32 x)
+{
+	u32 shifts;
+
+	shifts = 0;
+
+	if (!x)
+		return 0;
+
+	while (!(x & 1)) {
+		x >>= 1;
+		shifts++;
+	}
+
+	return shifts;
+}
+
+/*
+ * Temporary buffer manipulations.
+ */
+
+static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
+{
+	int i;
+	u8 *buf = (u8 *) 1;
+
+	memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
+
+	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
+		dev->temp_buffer[i].in_use = 0;
+		buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+		dev->temp_buffer[i].buffer = buf;
+	}
+
+	return buf ? YAFFS_OK : YAFFS_FAIL;
+}
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
+{
+	int i;
+
+	dev->temp_in_use++;
+	if (dev->temp_in_use > dev->max_temp)
+		dev->max_temp = dev->temp_in_use;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->temp_buffer[i].in_use == 0) {
+			dev->temp_buffer[i].in_use = 1;
+			return dev->temp_buffer[i].buffer;
+		}
+	}
+
+	yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
+	/*
+	 * If we got here then we have to allocate an unmanaged one
+	 * This is not good.
+	 */
+
+	dev->unmanaged_buffer_allocs++;
+	return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
+
+}
+
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
+{
+	int i;
+
+	dev->temp_in_use--;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->temp_buffer[i].buffer == buffer) {
+			dev->temp_buffer[i].in_use = 0;
+			return;
+		}
+	}
+
+	if (buffer) {
+		/* assume it is an unmanaged one. */
+		yaffs_trace(YAFFS_TRACE_BUFFERS,
+			"Releasing unmanaged temp buffer");
+		kfree(buffer);
+		dev->unmanaged_buffer_deallocs++;
+	}
+
+}
+
+/*
+ * Functions for robustisizing TODO
+ *
+ */
+
+static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
+				     const u8 *data,
+				     const struct yaffs_ext_tags *tags)
+{
+	(void) dev;
+	(void) nand_chunk;
+	(void) data;
+	(void) tags;
+}
+
+static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
+				      const struct yaffs_ext_tags *tags)
+{
+	(void) dev;
+	(void) nand_chunk;
+	(void) tags;
+}
+
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+			      struct yaffs_block_info *bi)
+{
+	if (!bi->gc_prioritise) {
+		bi->gc_prioritise = 1;
+		dev->has_pending_prioritised_gc = 1;
+		bi->chunk_error_strikes++;
+
+		if (bi->chunk_error_strikes > 3) {
+			bi->needs_retiring = 1;	/* Too many stikes, so retire */
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"yaffs: Block struck out");
+
+		}
+	}
+}
+
+static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
+					int erased_ok)
+{
+	int flash_block = nand_chunk / dev->param.chunks_per_block;
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
+
+	yaffs_handle_chunk_error(dev, bi);
+
+	if (erased_ok) {
+		/* Was an actual write failure,
+		 * so mark the block for retirement.*/
+		bi->needs_retiring = 1;
+		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+		  "**>> Block %d needs retiring", flash_block);
+	}
+
+	/* Delete the chunk */
+	yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+	yaffs_skip_rest_of_block(dev);
+}
+
+/*
+ * Verification code
+ */
+
+/*
+ *  Simple hash function. Needs to have a reasonable spread
+ */
+
+static inline int yaffs_hash_fn(int n)
+{
+	if (n < 0)
+		n = -n;
+	return n % YAFFS_NOBJECT_BUCKETS;
+}
+
+/*
+ * Access functions to useful fake objects.
+ * Note that root might have a presence in NAND if permissions are set.
+ */
+
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
+{
+	return dev->root_dir;
+}
+
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
+{
+	return dev->lost_n_found;
+}
+
+/*
+ *  Erased NAND checking functions
+ */
+
+int yaffs_check_ff(u8 *buffer, int n_bytes)
+{
+	/* Horrible, slow implementation */
+	while (n_bytes--) {
+		if (*buffer != 0xff)
+			return 0;
+		buffer++;
+	}
+	return 1;
+}
+
+static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
+{
+	int retval = YAFFS_OK;
+	u8 *data = yaffs_get_temp_buffer(dev);
+	struct yaffs_ext_tags tags;
+	int result;
+
+	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
+
+	if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
+		retval = YAFFS_FAIL;
+
+	if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
+		tags.chunk_used) {
+		yaffs_trace(YAFFS_TRACE_NANDACCESS,
+			"Chunk %d not erased", nand_chunk);
+		retval = YAFFS_FAIL;
+	}
+
+	yaffs_release_temp_buffer(dev, data);
+
+	return retval;
+
+}
+
+static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
+				      int nand_chunk,
+				      const u8 *data,
+				      struct yaffs_ext_tags *tags)
+{
+	int retval = YAFFS_OK;
+	struct yaffs_ext_tags temp_tags;
+	u8 *buffer = yaffs_get_temp_buffer(dev);
+	int result;
+
+	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
+	if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
+	    temp_tags.obj_id != tags->obj_id ||
+	    temp_tags.chunk_id != tags->chunk_id ||
+	    temp_tags.n_bytes != tags->n_bytes)
+		retval = YAFFS_FAIL;
+
+	yaffs_release_temp_buffer(dev, buffer);
+
+	return retval;
+}
+
+
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
+{
+	int reserved_chunks;
+	int reserved_blocks = dev->param.n_reserved_blocks;
+	int checkpt_blocks;
+
+	checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
+
+	reserved_chunks =
+	    (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
+
+	return (dev->n_free_chunks > (reserved_chunks + n_chunks));
+}
+
+static int yaffs_find_alloc_block(struct yaffs_dev *dev)
+{
+	int i;
+	struct yaffs_block_info *bi;
+
+	if (dev->n_erased_blocks < 1) {
+		/* Hoosterman we've got a problem.
+		 * Can't get space to gc
+		 */
+		yaffs_trace(YAFFS_TRACE_ERROR,
+		  "yaffs tragedy: no more erased blocks");
+
+		return -1;
+	}
+
+	/* Find an empty block. */
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		dev->alloc_block_finder++;
+		if (dev->alloc_block_finder < dev->internal_start_block
+		    || dev->alloc_block_finder > dev->internal_end_block) {
+			dev->alloc_block_finder = dev->internal_start_block;
+		}
+
+		bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+			bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
+			dev->seq_number++;
+			bi->seq_number = dev->seq_number;
+			dev->n_erased_blocks--;
+			yaffs_trace(YAFFS_TRACE_ALLOCATE,
+			  "Allocated block %d, seq  %d, %d left" ,
+			   dev->alloc_block_finder, dev->seq_number,
+			   dev->n_erased_blocks);
+			return dev->alloc_block_finder;
+		}
+	}
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS,
+		"yaffs tragedy: no more erased blocks, but there should have been %d",
+		dev->n_erased_blocks);
+
+	return -1;
+}
+
+static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
+			     struct yaffs_block_info **block_ptr)
+{
+	int ret_val;
+	struct yaffs_block_info *bi;
+
+	if (dev->alloc_block < 0) {
+		/* Get next block to allocate off */
+		dev->alloc_block = yaffs_find_alloc_block(dev);
+		dev->alloc_page = 0;
+	}
+
+	if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
+		/* No space unless we're allowed to use the reserve. */
+		return -1;
+	}
+
+	if (dev->n_erased_blocks < dev->param.n_reserved_blocks
+	    && dev->alloc_page == 0)
+		yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
+
+	/* Next page please.... */
+	if (dev->alloc_block >= 0) {
+		bi = yaffs_get_block_info(dev, dev->alloc_block);
+
+		ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
+		    dev->alloc_page;
+		bi->pages_in_use++;
+		yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
+
+		dev->alloc_page++;
+
+		dev->n_free_chunks--;
+
+		/* If the block is full set the state to full */
+		if (dev->alloc_page >= dev->param.chunks_per_block) {
+			bi->block_state = YAFFS_BLOCK_STATE_FULL;
+			dev->alloc_block = -1;
+		}
+
+		if (block_ptr)
+			*block_ptr = bi;
+
+		return ret_val;
+	}
+
+	yaffs_trace(YAFFS_TRACE_ERROR,
+		"!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
+
+	return -1;
+}
+
+static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
+{
+	int n;
+
+	n = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+	if (dev->alloc_block > 0)
+		n += (dev->param.chunks_per_block - dev->alloc_page);
+
+	return n;
+
+}
+
+/*
+ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
+ * if we don't want to write to it.
+ */
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
+{
+	struct yaffs_block_info *bi;
+
+	if (dev->alloc_block > 0) {
+		bi = yaffs_get_block_info(dev, dev->alloc_block);
+		if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+			bi->block_state = YAFFS_BLOCK_STATE_FULL;
+			dev->alloc_block = -1;
+		}
+	}
+}
+
+static int yaffs_write_new_chunk(struct yaffs_dev *dev,
+				 const u8 *data,
+				 struct yaffs_ext_tags *tags, int use_reserver)
+{
+	int attempts = 0;
+	int write_ok = 0;
+	int chunk;
+
+	yaffs2_checkpt_invalidate(dev);
+
+	do {
+		struct yaffs_block_info *bi = 0;
+		int erased_ok = 0;
+
+		chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
+		if (chunk < 0) {
+			/* no space */
+			break;
+		}
+
+		/* First check this chunk is erased, if it needs
+		 * checking.  The checking policy (unless forced
+		 * always on) is as follows:
+		 *
+		 * Check the first page we try to write in a block.
+		 * If the check passes then we don't need to check any
+		 * more.        If the check fails, we check again...
+		 * If the block has been erased, we don't need to check.
+		 *
+		 * However, if the block has been prioritised for gc,
+		 * then we think there might be something odd about
+		 * this block and stop using it.
+		 *
+		 * Rationale: We should only ever see chunks that have
+		 * not been erased if there was a partially written
+		 * chunk due to power loss.  This checking policy should
+		 * catch that case with very few checks and thus save a
+		 * lot of checks that are most likely not needed.
+		 *
+		 * Mods to the above
+		 * If an erase check fails or the write fails we skip the
+		 * rest of the block.
+		 */
+
+		/* let's give it a try */
+		attempts++;
+
+		if (dev->param.always_check_erased)
+			bi->skip_erased_check = 0;
+
+		if (!bi->skip_erased_check) {
+			erased_ok = yaffs_check_chunk_erased(dev, chunk);
+			if (erased_ok != YAFFS_OK) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+				  "**>> yaffs chunk %d was not erased",
+				  chunk);
+
+				/* If not erased, delete this one,
+				 * skip rest of block and
+				 * try another chunk */
+				yaffs_chunk_del(dev, chunk, 1, __LINE__);
+				yaffs_skip_rest_of_block(dev);
+				continue;
+			}
+		}
+
+		write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
+
+		if (!bi->skip_erased_check)
+			write_ok =
+			    yaffs_verify_chunk_written(dev, chunk, data, tags);
+
+		if (write_ok != YAFFS_OK) {
+			/* Clean up aborted write, skip to next block and
+			 * try another chunk */
+			yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
+			continue;
+		}
+
+		bi->skip_erased_check = 1;
+
+		/* Copy the data into the robustification buffer */
+		yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
+
+	} while (write_ok != YAFFS_OK &&
+		 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
+
+	if (!write_ok)
+		chunk = -1;
+
+	if (attempts > 1) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>> yaffs write required %d attempts",
+			attempts);
+		dev->n_retried_writes += (attempts - 1);
+	}
+
+	return chunk;
+}
+
+/*
+ * Block retiring for handling a broken block.
+ */
+
+static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
+{
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
+
+	yaffs2_checkpt_invalidate(dev);
+
+	yaffs2_clear_oldest_dirty_seq(dev, bi);
+
+	if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
+		if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"yaffs: Failed to mark bad and erase block %d",
+				flash_block);
+		} else {
+			struct yaffs_ext_tags tags;
+			int chunk_id =
+			    flash_block * dev->param.chunks_per_block;
+
+			u8 *buffer = yaffs_get_temp_buffer(dev);
+
+			memset(buffer, 0xff, dev->data_bytes_per_chunk);
+			memset(&tags, 0, sizeof(tags));
+			tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
+			if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
+							dev->chunk_offset,
+							buffer,
+							&tags) != YAFFS_OK)
+				yaffs_trace(YAFFS_TRACE_ALWAYS,
+					"yaffs: Failed to write bad block marker to block %d",
+					flash_block);
+
+			yaffs_release_temp_buffer(dev, buffer);
+		}
+	}
+
+	bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+	bi->gc_prioritise = 0;
+	bi->needs_retiring = 0;
+
+	dev->n_retired_blocks++;
+}
+
+/*---------------- Name handling functions ------------*/
+
+static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
+				    const YCHAR *oh_name, int buff_size)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+	if (dev->param.auto_unicode) {
+		if (*oh_name) {
+			/* It is an ASCII name, do an ASCII to
+			 * unicode conversion */
+			const char *ascii_oh_name = (const char *)oh_name;
+			int n = buff_size - 1;
+			while (n > 0 && *ascii_oh_name) {
+				*name = *ascii_oh_name;
+				name++;
+				ascii_oh_name++;
+				n--;
+			}
+		} else {
+			strncpy(name, oh_name + 1, buff_size - 1);
+		}
+	} else {
+#else
+	(void) dev;
+	{
+#endif
+		strncpy(name, oh_name, buff_size - 1);
+	}
+}
+
+static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
+				    const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+
+	int is_ascii;
+	const YCHAR *w;
+
+	if (dev->param.auto_unicode) {
+
+		is_ascii = 1;
+		w = name;
+
+		/* Figure out if the name will fit in ascii character set */
+		while (is_ascii && *w) {
+			if ((*w) & 0xff00)
+				is_ascii = 0;
+			w++;
+		}
+
+		if (is_ascii) {
+			/* It is an ASCII name, so convert unicode to ascii */
+			char *ascii_oh_name = (char *)oh_name;
+			int n = YAFFS_MAX_NAME_LENGTH - 1;
+			while (n > 0 && *name) {
+				*ascii_oh_name = *name;
+				name++;
+				ascii_oh_name++;
+				n--;
+			}
+		} else {
+			/* Unicode name, so save starting at the second YCHAR */
+			*oh_name = 0;
+			strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
+		}
+	} else {
+#else
+	dev = dev;
+	{
+#endif
+		strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
+	}
+}
+
+static u16 yaffs_calc_name_sum(const YCHAR *name)
+{
+	u16 sum = 0;
+	u16 i = 1;
+
+	if (!name)
+		return 0;
+
+	while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
+
+		/* 0x1f mask is case insensitive */
+		sum += ((*name) & 0x1f) * i;
+		i++;
+		name++;
+	}
+	return sum;
+}
+
+
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
+{
+	memset(obj->short_name, 0, sizeof(obj->short_name));
+
+	if (name && !name[0]) {
+		yaffs_fix_null_name(obj, obj->short_name,
+				YAFFS_SHORT_NAME_LENGTH);
+		name = obj->short_name;
+	} else if (name &&
+		strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
+		YAFFS_SHORT_NAME_LENGTH)  {
+		strcpy(obj->short_name, name);
+	}
+
+	obj->sum = yaffs_calc_name_sum(name);
+}
+
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+				const struct yaffs_obj_hdr *oh)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+	YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
+	memset(tmp_name, 0, sizeof(tmp_name));
+	yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
+				YAFFS_MAX_NAME_LENGTH + 1);
+	yaffs_set_obj_name(obj, tmp_name);
+#else
+	yaffs_set_obj_name(obj, oh->name);
+#endif
+}
+
+loff_t yaffs_max_file_size(struct yaffs_dev *dev)
+{
+	if(sizeof(loff_t) < 8)
+		return YAFFS_MAX_FILE_SIZE_32;
+	else
+		return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
+}
+
+/*-------------------- TNODES -------------------
+
+ * List of spare tnodes
+ * The list is hooked together using the first pointer
+ * in the tnode.
+ */
+
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
+{
+	struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
+
+	if (tn) {
+		memset(tn, 0, dev->tnode_size);
+		dev->n_tnodes++;
+	}
+
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+
+	return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+	yaffs_free_raw_tnode(dev, tn);
+	dev->n_tnodes--;
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+}
+
+static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
+{
+	yaffs_deinit_raw_tnodes_and_objs(dev);
+	dev->n_obj = 0;
+	dev->n_tnodes = 0;
+}
+
+static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+			unsigned pos, unsigned val)
+{
+	u32 *map = (u32 *) tn;
+	u32 bit_in_map;
+	u32 bit_in_word;
+	u32 word_in_map;
+	u32 mask;
+
+	pos &= YAFFS_TNODES_LEVEL0_MASK;
+	val >>= dev->chunk_grp_bits;
+
+	bit_in_map = pos * dev->tnode_width;
+	word_in_map = bit_in_map / 32;
+	bit_in_word = bit_in_map & (32 - 1);
+
+	mask = dev->tnode_mask << bit_in_word;
+
+	map[word_in_map] &= ~mask;
+	map[word_in_map] |= (mask & (val << bit_in_word));
+
+	if (dev->tnode_width > (32 - bit_in_word)) {
+		bit_in_word = (32 - bit_in_word);
+		word_in_map++;
+		mask =
+		    dev->tnode_mask >> bit_in_word;
+		map[word_in_map] &= ~mask;
+		map[word_in_map] |= (mask & (val >> bit_in_word));
+	}
+}
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+			 unsigned pos)
+{
+	u32 *map = (u32 *) tn;
+	u32 bit_in_map;
+	u32 bit_in_word;
+	u32 word_in_map;
+	u32 val;
+
+	pos &= YAFFS_TNODES_LEVEL0_MASK;
+
+	bit_in_map = pos * dev->tnode_width;
+	word_in_map = bit_in_map / 32;
+	bit_in_word = bit_in_map & (32 - 1);
+
+	val = map[word_in_map] >> bit_in_word;
+
+	if (dev->tnode_width > (32 - bit_in_word)) {
+		bit_in_word = (32 - bit_in_word);
+		word_in_map++;
+		val |= (map[word_in_map] << bit_in_word);
+	}
+
+	val &= dev->tnode_mask;
+	val <<= dev->chunk_grp_bits;
+
+	return val;
+}
+
+/* ------------------- End of individual tnode manipulation -----------------*/
+
+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
+ * The look up tree is represented by the top tnode and the number of top_level
+ * in the tree. 0 means only the level 0 tnode is in the tree.
+ */
+
+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+				       struct yaffs_file_var *file_struct,
+				       u32 chunk_id)
+{
+	struct yaffs_tnode *tn = file_struct->top;
+	u32 i;
+	int required_depth;
+	int level = file_struct->top_level;
+
+	(void) dev;
+
+	/* Check sane level and chunk Id */
+	if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
+		return NULL;
+
+	if (chunk_id > YAFFS_MAX_CHUNK_ID)
+		return NULL;
+
+	/* First check we're tall enough (ie enough top_level) */
+
+	i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
+	required_depth = 0;
+	while (i) {
+		i >>= YAFFS_TNODES_INTERNAL_BITS;
+		required_depth++;
+	}
+
+	if (required_depth > file_struct->top_level)
+		return NULL;	/* Not tall enough, so we can't find it */
+
+	/* Traverse down to level 0 */
+	while (level > 0 && tn) {
+		tn = tn->internal[(chunk_id >>
+				   (YAFFS_TNODES_LEVEL0_BITS +
+				    (level - 1) *
+				    YAFFS_TNODES_INTERNAL_BITS)) &
+				  YAFFS_TNODES_INTERNAL_MASK];
+		level--;
+	}
+
+	return tn;
+}
+
+/* add_find_tnode_0 finds the level 0 tnode if it exists,
+ * otherwise first expands the tree.
+ * This happens in two steps:
+ *  1. If the tree isn't tall enough, then make it taller.
+ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
+ *
+ * Used when modifying the tree.
+ *
+ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the
+ *  specified tn will be plugged into the ttree.
+ */
+
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+					   struct yaffs_file_var *file_struct,
+					   u32 chunk_id,
+					   struct yaffs_tnode *passed_tn)
+{
+	int required_depth;
+	int i;
+	int l;
+	struct yaffs_tnode *tn;
+	u32 x;
+
+	/* Check sane level and page Id */
+	if (file_struct->top_level < 0 ||
+	    file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
+		return NULL;
+
+	if (chunk_id > YAFFS_MAX_CHUNK_ID)
+		return NULL;
+
+	/* First check we're tall enough (ie enough top_level) */
+
+	x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
+	required_depth = 0;
+	while (x) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		required_depth++;
+	}
+
+	if (required_depth > file_struct->top_level) {
+		/* Not tall enough, gotta make the tree taller */
+		for (i = file_struct->top_level; i < required_depth; i++) {
+
+			tn = yaffs_get_tnode(dev);
+
+			if (tn) {
+				tn->internal[0] = file_struct->top;
+				file_struct->top = tn;
+				file_struct->top_level++;
+			} else {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"yaffs: no more tnodes");
+				return NULL;
+			}
+		}
+	}
+
+	/* Traverse down to level 0, adding anything we need */
+
+	l = file_struct->top_level;
+	tn = file_struct->top;
+
+	if (l > 0) {
+		while (l > 0 && tn) {
+			x = (chunk_id >>
+			     (YAFFS_TNODES_LEVEL0_BITS +
+			      (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
+			    YAFFS_TNODES_INTERNAL_MASK;
+
+			if ((l > 1) && !tn->internal[x]) {
+				/* Add missing non-level-zero tnode */
+				tn->internal[x] = yaffs_get_tnode(dev);
+				if (!tn->internal[x])
+					return NULL;
+			} else if (l == 1) {
+				/* Looking from level 1 at level 0 */
+				if (passed_tn) {
+					/* If we already have one, release it */
+					if (tn->internal[x])
+						yaffs_free_tnode(dev,
+							tn->internal[x]);
+					tn->internal[x] = passed_tn;
+
+				} else if (!tn->internal[x]) {
+					/* Don't have one, none passed in */
+					tn->internal[x] = yaffs_get_tnode(dev);
+					if (!tn->internal[x])
+						return NULL;
+				}
+			}
+
+			tn = tn->internal[x];
+			l--;
+		}
+	} else {
+		/* top is level 0 */
+		if (passed_tn) {
+			memcpy(tn, passed_tn,
+			       (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
+			yaffs_free_tnode(dev, passed_tn);
+		}
+	}
+
+	return tn;
+}
+
+static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
+			    int chunk_obj)
+{
+	return (tags->chunk_id == chunk_obj &&
+		tags->obj_id == obj_id &&
+		!tags->is_deleted) ? 1 : 0;
+
+}
+
+static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
+					struct yaffs_ext_tags *tags, int obj_id,
+					int inode_chunk)
+{
+	int j;
+
+	for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
+		if (yaffs_check_chunk_bit
+		    (dev, the_chunk / dev->param.chunks_per_block,
+		     the_chunk % dev->param.chunks_per_block)) {
+
+			if (dev->chunk_grp_size == 1)
+				return the_chunk;
+			else {
+				yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+							 tags);
+				if (yaffs_tags_match(tags,
+							obj_id, inode_chunk)) {
+					/* found it; */
+					return the_chunk;
+				}
+			}
+		}
+		the_chunk++;
+	}
+	return -1;
+}
+
+int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+				    struct yaffs_ext_tags *tags)
+{
+	/*Get the Tnode, then get the level 0 offset chunk offset */
+	struct yaffs_tnode *tn;
+	int the_chunk = -1;
+	struct yaffs_ext_tags local_tags;
+	int ret_val = -1;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (!tags) {
+		/* Passed a NULL, so use our own tags space */
+		tags = &local_tags;
+	}
+
+	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+	if (!tn)
+		return ret_val;
+
+	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+					      inode_chunk);
+	return ret_val;
+}
+
+static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
+				     struct yaffs_ext_tags *tags)
+{
+	/* Get the Tnode, then get the level 0 offset chunk offset */
+	struct yaffs_tnode *tn;
+	int the_chunk = -1;
+	struct yaffs_ext_tags local_tags;
+	struct yaffs_dev *dev = in->my_dev;
+	int ret_val = -1;
+
+	if (!tags) {
+		/* Passed a NULL, so use our own tags space */
+		tags = &local_tags;
+	}
+
+	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+	if (!tn)
+		return ret_val;
+
+	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+					      inode_chunk);
+
+	/* Delete the entry in the filestructure (if found) */
+	if (ret_val != -1)
+		yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
+
+	return ret_val;
+}
+
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+			    int nand_chunk, int in_scan)
+{
+	/* NB in_scan is zero unless scanning.
+	 * For forward scanning, in_scan is > 0;
+	 * for backward scanning in_scan is < 0
+	 *
+	 * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
+	 */
+
+	struct yaffs_tnode *tn;
+	struct yaffs_dev *dev = in->my_dev;
+	int existing_cunk;
+	struct yaffs_ext_tags existing_tags;
+	struct yaffs_ext_tags new_tags;
+	unsigned existing_serial, new_serial;
+
+	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
+		/* Just ignore an attempt at putting a chunk into a non-file
+		 * during scanning.
+		 * If it is not during Scanning then something went wrong!
+		 */
+		if (!in_scan) {
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"yaffs tragedy:attempt to put data chunk into a non-file"
+				);
+			BUG();
+		}
+
+		yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+		return YAFFS_OK;
+	}
+
+	tn = yaffs_add_find_tnode_0(dev,
+				    &in->variant.file_variant,
+				    inode_chunk, NULL);
+	if (!tn)
+		return YAFFS_FAIL;
+
+	if (!nand_chunk)
+		/* Dummy insert, bail now */
+		return YAFFS_OK;
+
+	existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+	if (in_scan != 0) {
+		/* If we're scanning then we need to test for duplicates
+		 * NB This does not need to be efficient since it should only
+		 * happen when the power fails during a write, then only one
+		 * chunk should ever be affected.
+		 *
+		 * Correction for YAFFS2: This could happen quite a lot and we
+		 * need to think about efficiency! TODO
+		 * Update: For backward scanning we don't need to re-read tags
+		 * so this is quite cheap.
+		 */
+
+		if (existing_cunk > 0) {
+			/* NB Right now existing chunk will not be real
+			 * chunk_id if the chunk group size > 1
+			 * thus we have to do a FindChunkInFile to get the
+			 * real chunk id.
+			 *
+			 * We have a duplicate now we need to decide which
+			 * one to use:
+			 *
+			 * Backwards scanning YAFFS2: The old one is what
+			 * we use, dump the new one.
+			 * YAFFS1: Get both sets of tags and compare serial
+			 * numbers.
+			 */
+
+			if (in_scan > 0) {
+				/* Only do this for forward scanning */
+				yaffs_rd_chunk_tags_nand(dev,
+							 nand_chunk,
+							 NULL, &new_tags);
+
+				/* Do a proper find */
+				existing_cunk =
+				    yaffs_find_chunk_in_file(in, inode_chunk,
+							     &existing_tags);
+			}
+
+			if (existing_cunk <= 0) {
+				/*Hoosterman - how did this happen? */
+
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"yaffs tragedy: existing chunk < 0 in scan"
+					);
+
+			}
+
+			/* NB The deleted flags should be false, otherwise
+			 * the chunks will not be loaded during a scan
+			 */
+
+			if (in_scan > 0) {
+				new_serial = new_tags.serial_number;
+				existing_serial = existing_tags.serial_number;
+			}
+
+			if ((in_scan > 0) &&
+			    (existing_cunk <= 0 ||
+			     ((existing_serial + 1) & 3) == new_serial)) {
+				/* Forward scanning.
+				 * Use new
+				 * Delete the old one and drop through to
+				 * update the tnode
+				 */
+				yaffs_chunk_del(dev, existing_cunk, 1,
+						__LINE__);
+			} else {
+				/* Backward scanning or we want to use the
+				 * existing one
+				 * Delete the new one and return early so that
+				 * the tnode isn't changed
+				 */
+				yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+				return YAFFS_OK;
+			}
+		}
+
+	}
+
+	if (existing_cunk == 0)
+		in->n_data_chunks++;
+
+	yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
+
+	return YAFFS_OK;
+}
+
+static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
+{
+	struct yaffs_block_info *the_block;
+	unsigned block_no;
+
+	yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
+
+	block_no = chunk / dev->param.chunks_per_block;
+	the_block = yaffs_get_block_info(dev, block_no);
+	if (the_block) {
+		the_block->soft_del_pages++;
+		dev->n_free_chunks++;
+		yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
+	}
+}
+
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
+ * the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls
+ * the chunk out of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks
+ * are soft deleted.
+ */
+
+static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
+				 u32 level, int chunk_offset)
+{
+	int i;
+	int the_chunk;
+	int all_done = 1;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (!tn)
+		return 1;
+
+	if (level > 0) {
+		for (i = YAFFS_NTNODES_INTERNAL - 1;
+			all_done && i >= 0;
+			i--) {
+			if (tn->internal[i]) {
+				all_done =
+				    yaffs_soft_del_worker(in,
+					tn->internal[i],
+					level - 1,
+					(chunk_offset <<
+					YAFFS_TNODES_INTERNAL_BITS)
+					+ i);
+				if (all_done) {
+					yaffs_free_tnode(dev,
+						tn->internal[i]);
+					tn->internal[i] = NULL;
+				} else {
+					/* Can this happen? */
+				}
+			}
+		}
+		return (all_done) ? 1 : 0;
+	}
+
+	/* level 0 */
+	 for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+		the_chunk = yaffs_get_group_base(dev, tn, i);
+		if (the_chunk) {
+			yaffs_soft_del_chunk(dev, the_chunk);
+			yaffs_load_tnode_0(dev, tn, i, 0);
+		}
+	}
+	return 1;
+}
+
+static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	struct yaffs_obj *parent;
+
+	yaffs_verify_obj_in_dir(obj);
+	parent = obj->parent;
+
+	yaffs_verify_dir(parent);
+
+	if (dev && dev->param.remove_obj_fn)
+		dev->param.remove_obj_fn(obj);
+
+	list_del_init(&obj->siblings);
+	obj->parent = NULL;
+
+	yaffs_verify_dir(parent);
+}
+
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
+{
+	if (!directory) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: Trying to add an object to a null pointer directory"
+			);
+		BUG();
+		return;
+	}
+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: Trying to add an object to a non-directory"
+			);
+		BUG();
+	}
+
+	if (obj->siblings.prev == NULL) {
+		/* Not initialised */
+		BUG();
+	}
+
+	yaffs_verify_dir(directory);
+
+	yaffs_remove_obj_from_dir(obj);
+
+	/* Now add it */
+	list_add(&obj->siblings, &directory->variant.dir_variant.children);
+	obj->parent = directory;
+
+	if (directory == obj->my_dev->unlinked_dir
+	    || directory == obj->my_dev->del_dir) {
+		obj->unlinked = 1;
+		obj->my_dev->n_unlinked_files++;
+		obj->rename_allowed = 0;
+	}
+
+	yaffs_verify_dir(directory);
+	yaffs_verify_obj_in_dir(obj);
+}
+
+static int yaffs_change_obj_name(struct yaffs_obj *obj,
+				 struct yaffs_obj *new_dir,
+				 const YCHAR *new_name, int force, int shadows)
+{
+	int unlink_op;
+	int del_op;
+	struct yaffs_obj *existing_target;
+
+	if (new_dir == NULL)
+		new_dir = obj->parent;	/* use the old directory */
+
+	if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: yaffs_change_obj_name: new_dir is not a directory"
+			);
+		BUG();
+	}
+
+	unlink_op = (new_dir == obj->my_dev->unlinked_dir);
+	del_op = (new_dir == obj->my_dev->del_dir);
+
+	existing_target = yaffs_find_by_name(new_dir, new_name);
+
+	/* If the object is a file going into the unlinked directory,
+	 *   then it is OK to just stuff it in since duplicate names are OK.
+	 *   else only proceed if the new name does not exist and we're putting
+	 *   it into a directory.
+	 */
+	if (!(unlink_op || del_op || force ||
+	      shadows > 0 || !existing_target) ||
+	      new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+		return YAFFS_FAIL;
+
+	yaffs_set_obj_name(obj, new_name);
+	obj->dirty = 1;
+	yaffs_add_obj_to_dir(new_dir, obj);
+
+	if (unlink_op)
+		obj->unlinked = 1;
+
+	/* If it is a deletion then we mark it as a shrink for gc  */
+	if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
+		return YAFFS_OK;
+
+	return YAFFS_FAIL;
+}
+
+/*------------------------ Short Operations Cache ------------------------------
+ *   In many situations where there is no high level buffering  a lot of
+ *   reads might be short sequential reads, and a lot of writes may be short
+ *   sequential writes. eg. scanning/writing a jpeg file.
+ *   In these cases, a short read/write cache can provide a huge perfomance
+ *   benefit with dumb-as-a-rock code.
+ *   In Linux, the page cache provides read buffering and the short op cache
+ *   provides write buffering.
+ *
+ *   There are a small number (~10) of cache chunks per device so that we don't
+ *   need a very intelligent search.
+ */
+
+static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	int i;
+	struct yaffs_cache *cache;
+	int n_caches = obj->my_dev->param.n_caches;
+
+	for (i = 0; i < n_caches; i++) {
+		cache = &dev->cache[i];
+		if (cache->object == obj && cache->dirty)
+			return 1;
+	}
+
+	return 0;
+}
+
+static void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
+{
+
+	if (!cache || cache->locked)
+		return;
+
+	/* Write it out and free it up  if need be.*/
+	if (cache->dirty) {
+		yaffs_wr_data_obj(cache->object,
+				  cache->chunk_id,
+				  cache->data,
+				  cache->n_bytes,
+				  1);
+
+		cache->dirty = 0;
+	}
+
+	if (discard)
+		cache->object = NULL;
+}
+
+static void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	int i;
+	struct yaffs_cache *cache;
+	int n_caches = obj->my_dev->param.n_caches;
+
+	if (n_caches < 1)
+		return;
+
+
+	/* Find the chunks for this object and flush them. */
+	for (i = 0; i < n_caches; i++) {
+		cache = &dev->cache[i];
+		if (cache->object == obj)
+			yaffs_flush_single_cache(cache, discard);
+	}
+
+}
+
+
+void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
+{
+	struct yaffs_obj *obj;
+	int n_caches = dev->param.n_caches;
+	int i;
+
+	/* Find a dirty object in the cache and flush it...
+	 * until there are no further dirty objects.
+	 */
+	do {
+		obj = NULL;
+		for (i = 0; i < n_caches && !obj; i++) {
+			if (dev->cache[i].object && dev->cache[i].dirty)
+				obj = dev->cache[i].object;
+		}
+		if (obj)
+			yaffs_flush_file_cache(obj, discard);
+	} while (obj);
+
+}
+
+/* Grab us an unused cache chunk for use.
+ * First look for an empty one.
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
+{
+	int i;
+
+	if (dev->param.n_caches > 0) {
+		for (i = 0; i < dev->param.n_caches; i++) {
+			if (!dev->cache[i].object)
+				return &dev->cache[i];
+		}
+	}
+
+	return NULL;
+}
+
+static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
+{
+	struct yaffs_cache *cache;
+	int usage;
+	int i;
+
+	if (dev->param.n_caches < 1)
+		return NULL;
+
+	/* First look for an unused cache */
+
+	cache = yaffs_grab_chunk_worker(dev);
+
+	if (cache)
+		return cache;
+
+	/*
+	 * Thery were all in use.
+	 * Find the LRU cache and flush it if it is dirty.
+	 */
+
+	usage = -1;
+	cache = NULL;
+
+	for (i = 0; i < dev->param.n_caches; i++) {
+		if (dev->cache[i].object &&
+		    !dev->cache[i].locked &&
+		    (dev->cache[i].last_use < usage || !cache)) {
+				usage = dev->cache[i].last_use;
+				cache = &dev->cache[i];
+		}
+	}
+
+#if 1
+	yaffs_flush_single_cache(cache, 1);
+#else
+	yaffs_flush_file_cache(cache->object, 1);
+	cache = yaffs_grab_chunk_worker(dev);
+#endif
+
+	return cache;
+}
+
+/* Find a cached chunk */
+static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
+						  int chunk_id)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	int i;
+
+	if (dev->param.n_caches < 1)
+		return NULL;
+
+	for (i = 0; i < dev->param.n_caches; i++) {
+		if (dev->cache[i].object == obj &&
+		    dev->cache[i].chunk_id == chunk_id) {
+			dev->cache_hits++;
+
+			return &dev->cache[i];
+		}
+	}
+	return NULL;
+}
+
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
+			    int is_write)
+{
+	int i;
+
+	if (dev->param.n_caches < 1)
+		return;
+
+	if (dev->cache_last_use < 0 ||
+		dev->cache_last_use > 100000000) {
+		/* Reset the cache usages */
+		for (i = 1; i < dev->param.n_caches; i++)
+			dev->cache[i].last_use = 0;
+
+		dev->cache_last_use = 0;
+	}
+	dev->cache_last_use++;
+	cache->last_use = dev->cache_last_use;
+
+	if (is_write)
+		cache->dirty = 1;
+}
+
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
+{
+	struct yaffs_cache *cache;
+
+	if (object->my_dev->param.n_caches > 0) {
+		cache = yaffs_find_chunk_cache(object, chunk_id);
+
+		if (cache)
+			cache->object = NULL;
+	}
+}
+
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
+{
+	int i;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (dev->param.n_caches > 0) {
+		/* Invalidate it. */
+		for (i = 0; i < dev->param.n_caches; i++) {
+			if (dev->cache[i].object == in)
+				dev->cache[i].object = NULL;
+		}
+	}
+}
+
+static void yaffs_unhash_obj(struct yaffs_obj *obj)
+{
+	int bucket;
+	struct yaffs_dev *dev = obj->my_dev;
+
+	/* If it is still linked into the bucket list, free from the list */
+	if (!list_empty(&obj->hash_link)) {
+		list_del_init(&obj->hash_link);
+		bucket = yaffs_hash_fn(obj->obj_id);
+		dev->obj_bucket[bucket].count--;
+	}
+}
+
+/*  FreeObject frees up a Object and puts it back on the free list */
+static void yaffs_free_obj(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev;
+
+	if (!obj) {
+		BUG();
+		return;
+	}
+	dev = obj->my_dev;
+	yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
+		obj, obj->my_inode);
+	if (obj->parent)
+		BUG();
+	if (!list_empty(&obj->siblings))
+		BUG();
+
+	if (obj->my_inode) {
+		/* We're still hooked up to a cached inode.
+		 * Don't delete now, but mark for later deletion
+		 */
+		obj->defered_free = 1;
+		return;
+	}
+
+	yaffs_unhash_obj(obj);
+
+	yaffs_free_raw_obj(dev, obj);
+	dev->n_obj--;
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+}
+
+void yaffs_handle_defered_free(struct yaffs_obj *obj)
+{
+	if (obj->defered_free)
+		yaffs_free_obj(obj);
+}
+
+static int yaffs_generic_obj_del(struct yaffs_obj *in)
+{
+	/* Iinvalidate the file's data in the cache, without flushing. */
+	yaffs_invalidate_whole_cache(in);
+
+	if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
+		/* Move to unlinked directory so we have a deletion record */
+		yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
+				      0);
+	}
+
+	yaffs_remove_obj_from_dir(in);
+	yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
+	in->hdr_chunk = 0;
+
+	yaffs_free_obj(in);
+	return YAFFS_OK;
+
+}
+
+static void yaffs_soft_del_file(struct yaffs_obj *obj)
+{
+	if (!obj->deleted ||
+	    obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
+	    obj->soft_del)
+		return;
+
+	if (obj->n_data_chunks <= 0) {
+		/* Empty file with no duplicate object headers,
+		 * just delete it immediately */
+		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+		obj->variant.file_variant.top = NULL;
+		yaffs_trace(YAFFS_TRACE_TRACING,
+			"yaffs: Deleting empty file %d",
+			obj->obj_id);
+		yaffs_generic_obj_del(obj);
+	} else {
+		yaffs_soft_del_worker(obj,
+				      obj->variant.file_variant.top,
+				      obj->variant.
+				      file_variant.top_level, 0);
+		obj->soft_del = 1;
+	}
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ *
+ * This function is recursive. For levels > 0 the function is called again on
+ * any sub-tree. For level == 0 we just check if the sub-tree has data.
+ * If there is no data in a subtree then it is pruned.
+ */
+
+static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
+					      struct yaffs_tnode *tn, u32 level,
+					      int del0)
+{
+	int i;
+	int has_data;
+
+	if (!tn)
+		return tn;
+
+	has_data = 0;
+
+	if (level > 0) {
+		for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+			if (tn->internal[i]) {
+				tn->internal[i] =
+				    yaffs_prune_worker(dev,
+						tn->internal[i],
+						level - 1,
+						(i == 0) ? del0 : 1);
+			}
+
+			if (tn->internal[i])
+				has_data++;
+		}
+	} else {
+		int tnode_size_u32 = dev->tnode_size / sizeof(u32);
+		u32 *map = (u32 *) tn;
+
+		for (i = 0; !has_data && i < tnode_size_u32; i++) {
+			if (map[i])
+				has_data++;
+		}
+	}
+
+	if (has_data == 0 && del0) {
+		/* Free and return NULL */
+		yaffs_free_tnode(dev, tn);
+		tn = NULL;
+	}
+	return tn;
+}
+
+static int yaffs_prune_tree(struct yaffs_dev *dev,
+			    struct yaffs_file_var *file_struct)
+{
+	int i;
+	int has_data;
+	int done = 0;
+	struct yaffs_tnode *tn;
+
+	if (file_struct->top_level < 1)
+		return YAFFS_OK;
+
+	file_struct->top =
+	   yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
+
+	/* Now we have a tree with all the non-zero branches NULL but
+	 * the height is the same as it was.
+	 * Let's see if we can trim internal tnodes to shorten the tree.
+	 * We can do this if only the 0th element in the tnode is in use
+	 * (ie all the non-zero are NULL)
+	 */
+
+	while (file_struct->top_level && !done) {
+		tn = file_struct->top;
+
+		has_data = 0;
+		for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+			if (tn->internal[i])
+				has_data++;
+		}
+
+		if (!has_data) {
+			file_struct->top = tn->internal[0];
+			file_struct->top_level--;
+			yaffs_free_tnode(dev, tn);
+		} else {
+			done = 1;
+		}
+	}
+
+	return YAFFS_OK;
+}
+
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* alloc_empty_obj gets us a clean Object.*/
+static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
+
+	if (!obj)
+		return obj;
+
+	dev->n_obj++;
+
+	/* Now sweeten it up... */
+
+	memset(obj, 0, sizeof(struct yaffs_obj));
+	obj->being_created = 1;
+
+	obj->my_dev = dev;
+	obj->hdr_chunk = 0;
+	obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
+	INIT_LIST_HEAD(&(obj->hard_links));
+	INIT_LIST_HEAD(&(obj->hash_link));
+	INIT_LIST_HEAD(&obj->siblings);
+
+	/* Now make the directory sane */
+	if (dev->root_dir) {
+		obj->parent = dev->root_dir;
+		list_add(&(obj->siblings),
+			 &dev->root_dir->variant.dir_variant.children);
+	}
+
+	/* Add it to the lost and found directory.
+	 * NB Can't put root or lost-n-found in lost-n-found so
+	 * check if lost-n-found exists first
+	 */
+	if (dev->lost_n_found)
+		yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+
+	obj->being_created = 0;
+
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+
+	return obj;
+}
+
+static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
+{
+	int i;
+	int l = 999;
+	int lowest = 999999;
+
+	/* Search for the shortest list or one that
+	 * isn't too long.
+	 */
+
+	for (i = 0; i < 10 && lowest > 4; i++) {
+		dev->bucket_finder++;
+		dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
+		if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
+			lowest = dev->obj_bucket[dev->bucket_finder].count;
+			l = dev->bucket_finder;
+		}
+	}
+
+	return l;
+}
+
+static int yaffs_new_obj_id(struct yaffs_dev *dev)
+{
+	int bucket = yaffs_find_nice_bucket(dev);
+	int found = 0;
+	struct list_head *i;
+	u32 n = (u32) bucket;
+
+	/*
+	 * Now find an object value that has not already been taken
+	 * by scanning the list, incrementing each time by number of buckets.
+	 */
+	while (!found) {
+		found = 1;
+		n += YAFFS_NOBJECT_BUCKETS;
+		list_for_each(i, &dev->obj_bucket[bucket].list) {
+			/* Check if this value is already taken. */
+			if (i && list_entry(i, struct yaffs_obj,
+					    hash_link)->obj_id == n)
+				found = 0;
+		}
+	}
+	return n;
+}
+
+static void yaffs_hash_obj(struct yaffs_obj *in)
+{
+	int bucket = yaffs_hash_fn(in->obj_id);
+	struct yaffs_dev *dev = in->my_dev;
+
+	list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
+	dev->obj_bucket[bucket].count++;
+}
+
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
+{
+	int bucket = yaffs_hash_fn(number);
+	struct list_head *i;
+	struct yaffs_obj *in;
+
+	list_for_each(i, &dev->obj_bucket[bucket].list) {
+		/* Look if it is in the list */
+		in = list_entry(i, struct yaffs_obj, hash_link);
+		if (in->obj_id == number) {
+			/* Don't show if it is defered free */
+			if (in->defered_free)
+				return NULL;
+			return in;
+		}
+	}
+
+	return NULL;
+}
+
+static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
+				enum yaffs_obj_type type)
+{
+	struct yaffs_obj *the_obj = NULL;
+	struct yaffs_tnode *tn = NULL;
+
+	if (number < 0)
+		number = yaffs_new_obj_id(dev);
+
+	if (type == YAFFS_OBJECT_TYPE_FILE) {
+		tn = yaffs_get_tnode(dev);
+		if (!tn)
+			return NULL;
+	}
+
+	the_obj = yaffs_alloc_empty_obj(dev);
+	if (!the_obj) {
+		if (tn)
+			yaffs_free_tnode(dev, tn);
+		return NULL;
+	}
+
+	the_obj->fake = 0;
+	the_obj->rename_allowed = 1;
+	the_obj->unlink_allowed = 1;
+	the_obj->obj_id = number;
+	yaffs_hash_obj(the_obj);
+	the_obj->variant_type = type;
+	yaffs_load_current_time(the_obj, 1, 1);
+
+	switch (type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		the_obj->variant.file_variant.file_size = 0;
+		the_obj->variant.file_variant.scanned_size = 0;
+		the_obj->variant.file_variant.shrink_size =
+						yaffs_max_file_size(dev);
+		the_obj->variant.file_variant.top_level = 0;
+		the_obj->variant.file_variant.top = tn;
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
+		INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		/* No action required */
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		/* todo this should not happen */
+		break;
+	}
+	return the_obj;
+}
+
+static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
+					       int number, u32 mode)
+{
+
+	struct yaffs_obj *obj =
+	    yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+
+	if (!obj)
+		return NULL;
+
+	obj->fake = 1;	/* it is fake so it might not use NAND */
+	obj->rename_allowed = 0;
+	obj->unlink_allowed = 0;
+	obj->deleted = 0;
+	obj->unlinked = 0;
+	obj->yst_mode = mode;
+	obj->my_dev = dev;
+	obj->hdr_chunk = 0;	/* Not a valid chunk. */
+	return obj;
+
+}
+
+
+static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
+{
+	int i;
+
+	dev->n_obj = 0;
+	dev->n_tnodes = 0;
+	yaffs_init_raw_tnodes_and_objs(dev);
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		INIT_LIST_HEAD(&dev->obj_bucket[i].list);
+		dev->obj_bucket[i].count = 0;
+	}
+}
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+						 int number,
+						 enum yaffs_obj_type type)
+{
+	struct yaffs_obj *the_obj = NULL;
+
+	if (number > 0)
+		the_obj = yaffs_find_by_number(dev, number);
+
+	if (!the_obj)
+		the_obj = yaffs_new_obj(dev, number, type);
+
+	return the_obj;
+
+}
+
+YCHAR *yaffs_clone_str(const YCHAR *str)
+{
+	YCHAR *new_str = NULL;
+	int len;
+
+	if (!str)
+		str = _Y("");
+
+	len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
+	new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
+	if (new_str) {
+		strncpy(new_str, str, len);
+		new_str[len] = 0;
+	}
+	return new_str;
+
+}
+/*
+ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ *   create dir/a : update dir's mtime/ctime
+ *   rm dir/a:   update dir's mtime/ctime
+ *   modify dir/a: don't update dir's mtimme/ctime
+ *
+ * This can be handled immediately or defered. Defering helps reduce the number
+ * of updates when many files in a directory are changed within a brief period.
+ *
+ * If the directory updating is defered then yaffs_update_dirty_dirs must be
+ * called periodically.
+ */
+
+static void yaffs_update_parent(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev;
+
+	if (!obj)
+		return;
+	dev = obj->my_dev;
+	obj->dirty = 1;
+	yaffs_load_current_time(obj, 0, 1);
+	if (dev->param.defered_dir_update) {
+		struct list_head *link = &obj->variant.dir_variant.dirty;
+
+		if (list_empty(link)) {
+			list_add(link, &dev->dirty_dirs);
+			yaffs_trace(YAFFS_TRACE_BACKGROUND,
+			  "Added object %d to dirty directories",
+			   obj->obj_id);
+		}
+
+	} else {
+		yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+	}
+}
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
+{
+	struct list_head *link;
+	struct yaffs_obj *obj;
+	struct yaffs_dir_var *d_s;
+	union yaffs_obj_var *o_v;
+
+	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
+
+	while (!list_empty(&dev->dirty_dirs)) {
+		link = dev->dirty_dirs.next;
+		list_del_init(link);
+
+		d_s = list_entry(link, struct yaffs_dir_var, dirty);
+		o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
+		obj = list_entry(o_v, struct yaffs_obj, variant);
+
+		yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
+			obj->obj_id);
+
+		if (obj->dirty)
+			yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+	}
+}
+
+/*
+ * Mknod (create) a new object.
+ * equiv_obj only has meaning for a hard link;
+ * alias_str only has meaning for a symlink.
+ * rdev only has meaning for devices (a subset of special objects)
+ */
+
+static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
+					  struct yaffs_obj *parent,
+					  const YCHAR *name,
+					  u32 mode,
+					  u32 uid,
+					  u32 gid,
+					  struct yaffs_obj *equiv_obj,
+					  const YCHAR *alias_str, u32 rdev)
+{
+	struct yaffs_obj *in;
+	YCHAR *str = NULL;
+	struct yaffs_dev *dev = parent->my_dev;
+
+	/* Check if the entry exists.
+	 * If it does then fail the call since we don't want a dup. */
+	if (yaffs_find_by_name(parent, name))
+		return NULL;
+
+	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		str = yaffs_clone_str(alias_str);
+		if (!str)
+			return NULL;
+	}
+
+	in = yaffs_new_obj(dev, -1, type);
+
+	if (!in) {
+		kfree(str);
+		return NULL;
+	}
+
+	in->hdr_chunk = 0;
+	in->valid = 1;
+	in->variant_type = type;
+
+	in->yst_mode = mode;
+
+	yaffs_attribs_init(in, gid, uid, rdev);
+
+	in->n_data_chunks = 0;
+
+	yaffs_set_obj_name(in, name);
+	in->dirty = 1;
+
+	yaffs_add_obj_to_dir(parent, in);
+
+	in->my_dev = parent->my_dev;
+
+	switch (type) {
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		in->variant.symlink_variant.alias = str;
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		in->variant.hardlink_variant.equiv_obj = equiv_obj;
+		in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
+		list_add(&in->hard_links, &equiv_obj->hard_links);
+		break;
+	case YAFFS_OBJECT_TYPE_FILE:
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		/* do nothing */
+		break;
+	}
+
+	if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
+		/* Could not create the object header, fail */
+		yaffs_del_obj(in);
+		in = NULL;
+	}
+
+	if (in)
+		yaffs_update_parent(parent);
+
+	return in;
+}
+
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+				    const YCHAR *name, u32 mode, u32 uid,
+				    u32 gid)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
+				uid, gid, NULL, NULL, 0);
+}
+
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+				   u32 mode, u32 uid, u32 gid)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
+				mode, uid, gid, NULL, NULL, 0);
+}
+
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, u32 rdev)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
+				uid, gid, NULL, NULL, rdev);
+}
+
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, const YCHAR *alias)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
+				uid, gid, NULL, alias, 0);
+}
+
+/* yaffs_link_obj returns the object id of the equivalent object.*/
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
+				 struct yaffs_obj *equiv_obj)
+{
+	/* Get the real object in case we were fed a hard link obj */
+	equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
+
+	if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
+			parent, name, 0, 0, 0,
+			equiv_obj, NULL, 0))
+		return equiv_obj;
+
+	return NULL;
+
+}
+
+
+
+/*---------------------- Block Management and Page Allocation -------------*/
+
+static void yaffs_deinit_blocks(struct yaffs_dev *dev)
+{
+	if (dev->block_info_alt && dev->block_info)
+		vfree(dev->block_info);
+	else
+		kfree(dev->block_info);
+
+	dev->block_info_alt = 0;
+
+	dev->block_info = NULL;
+
+	if (dev->chunk_bits_alt && dev->chunk_bits)
+		vfree(dev->chunk_bits);
+	else
+		kfree(dev->chunk_bits);
+	dev->chunk_bits_alt = 0;
+	dev->chunk_bits = NULL;
+}
+
+static int yaffs_init_blocks(struct yaffs_dev *dev)
+{
+	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+	dev->block_info = NULL;
+	dev->chunk_bits = NULL;
+	dev->alloc_block = -1;	/* force it to get a new one */
+
+	/* If the first allocation strategy fails, thry the alternate one */
+	dev->block_info =
+		kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
+	if (!dev->block_info) {
+		dev->block_info =
+		    vmalloc(n_blocks * sizeof(struct yaffs_block_info));
+		dev->block_info_alt = 1;
+	} else {
+		dev->block_info_alt = 0;
+	}
+
+	if (!dev->block_info)
+		goto alloc_error;
+
+	/* Set up dynamic blockinfo stuff. Round up bytes. */
+	dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
+	dev->chunk_bits =
+		kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
+	if (!dev->chunk_bits) {
+		dev->chunk_bits =
+		    vmalloc(dev->chunk_bit_stride * n_blocks);
+		dev->chunk_bits_alt = 1;
+	} else {
+		dev->chunk_bits_alt = 0;
+	}
+	if (!dev->chunk_bits)
+		goto alloc_error;
+
+
+	memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
+	memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
+	return YAFFS_OK;
+
+alloc_error:
+	yaffs_deinit_blocks(dev);
+	return YAFFS_FAIL;
+}
+
+
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
+{
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
+	int erased_ok = 0;
+	int i;
+
+	/* If the block is still healthy erase it and mark as clean.
+	 * If the block has had a data failure, then retire it.
+	 */
+
+	yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+		"yaffs_block_became_dirty block %d state %d %s",
+		block_no, bi->block_state,
+		(bi->needs_retiring) ? "needs retiring" : "");
+
+	yaffs2_clear_oldest_dirty_seq(dev, bi);
+
+	bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
+
+	/* If this is the block being garbage collected then stop gc'ing */
+	if (block_no == dev->gc_block)
+		dev->gc_block = 0;
+
+	/* If this block is currently the best candidate for gc
+	 * then drop as a candidate */
+	if (block_no == dev->gc_dirtiest) {
+		dev->gc_dirtiest = 0;
+		dev->gc_pages_in_use = 0;
+	}
+
+	if (!bi->needs_retiring) {
+		yaffs2_checkpt_invalidate(dev);
+		erased_ok = yaffs_erase_block(dev, block_no);
+		if (!erased_ok) {
+			dev->n_erase_failures++;
+			yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+			  "**>> Erasure failed %d", block_no);
+		}
+	}
+
+	/* Verify erasure if needed */
+	if (erased_ok &&
+	    ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
+	     !yaffs_skip_verification(dev))) {
+		for (i = 0; i < dev->param.chunks_per_block; i++) {
+			if (!yaffs_check_chunk_erased(dev,
+				block_no * dev->param.chunks_per_block + i)) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					">>Block %d erasure supposedly OK, but chunk %d not erased",
+					block_no, i);
+			}
+		}
+	}
+
+	if (!erased_ok) {
+		/* We lost a block of free space */
+		dev->n_free_chunks -= dev->param.chunks_per_block;
+		yaffs_retire_block(dev, block_no);
+		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+			"**>> Block %d retired", block_no);
+		return;
+	}
+
+	/* Clean it up... */
+	bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+	bi->seq_number = 0;
+	dev->n_erased_blocks++;
+	bi->pages_in_use = 0;
+	bi->soft_del_pages = 0;
+	bi->has_shrink_hdr = 0;
+	bi->skip_erased_check = 1;	/* Clean, so no need to check */
+	bi->gc_prioritise = 0;
+	bi->has_summary = 0;
+
+	yaffs_clear_chunk_bits(dev, block_no);
+
+	yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
+}
+
+static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
+					struct yaffs_block_info *bi,
+					int old_chunk, u8 *buffer)
+{
+	int new_chunk;
+	int mark_flash = 1;
+	struct yaffs_ext_tags tags;
+	struct yaffs_obj *object;
+	int matching_chunk;
+	int ret_val = YAFFS_OK;
+
+	memset(&tags, 0, sizeof(tags));
+	yaffs_rd_chunk_tags_nand(dev, old_chunk,
+				 buffer, &tags);
+	object = yaffs_find_by_number(dev, tags.obj_id);
+
+	yaffs_trace(YAFFS_TRACE_GC_DETAIL,
+		"Collecting chunk in block %d, %d %d %d ",
+		dev->gc_chunk, tags.obj_id,
+		tags.chunk_id, tags.n_bytes);
+
+	if (object && !yaffs_skip_verification(dev)) {
+		if (tags.chunk_id == 0)
+			matching_chunk =
+			    object->hdr_chunk;
+		else if (object->soft_del)
+			/* Defeat the test */
+			matching_chunk = old_chunk;
+		else
+			matching_chunk =
+			    yaffs_find_chunk_in_file
+			    (object, tags.chunk_id,
+			     NULL);
+
+		if (old_chunk != matching_chunk)
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"gc: page in gc mismatch: %d %d %d %d",
+				old_chunk,
+				matching_chunk,
+				tags.obj_id,
+				tags.chunk_id);
+	}
+
+	if (!object) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"page %d in gc has no object: %d %d %d ",
+			old_chunk,
+			tags.obj_id, tags.chunk_id,
+			tags.n_bytes);
+	}
+
+	if (object &&
+	    object->deleted &&
+	    object->soft_del && tags.chunk_id != 0) {
+		/* Data chunk in a soft deleted file,
+		 * throw it away.
+		 * It's a soft deleted data chunk,
+		 * No need to copy this, just forget
+		 * about it and fix up the object.
+		 */
+
+		/* Free chunks already includes
+		 * softdeleted chunks, how ever this
+		 * chunk is going to soon be really
+		 * deleted which will increment free
+		 * chunks. We have to decrement free
+		 * chunks so this works out properly.
+		 */
+		dev->n_free_chunks--;
+		bi->soft_del_pages--;
+
+		object->n_data_chunks--;
+		if (object->n_data_chunks <= 0) {
+			/* remeber to clean up obj */
+			dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
+			dev->n_clean_ups++;
+		}
+		mark_flash = 0;
+	} else if (object) {
+		/* It's either a data chunk in a live
+		 * file or an ObjectHeader, so we're
+		 * interested in it.
+		 * NB Need to keep the ObjectHeaders of
+		 * deleted files until the whole file
+		 * has been deleted off
+		 */
+		tags.serial_number++;
+		dev->n_gc_copies++;
+
+		if (tags.chunk_id == 0) {
+			/* It is an object Id,
+			 * We need to nuke the
+			 * shrinkheader flags since its
+			 * work is done.
+			 * Also need to clean up
+			 * shadowing.
+			 */
+			struct yaffs_obj_hdr *oh;
+			oh = (struct yaffs_obj_hdr *) buffer;
+
+			oh->is_shrink = 0;
+			tags.extra_is_shrink = 0;
+			oh->shadows_obj = 0;
+			oh->inband_shadowed_obj_id = 0;
+			tags.extra_shadows = 0;
+
+			/* Update file size */
+			if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
+				yaffs_oh_size_load(oh,
+				    object->variant.file_variant.file_size);
+				tags.extra_file_size =
+				    object->variant.file_variant.file_size;
+			}
+
+			yaffs_verify_oh(object, oh, &tags, 1);
+			new_chunk =
+			    yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
+		} else {
+			new_chunk =
+			    yaffs_write_new_chunk(dev, buffer, &tags, 1);
+		}
+
+		if (new_chunk < 0) {
+			ret_val = YAFFS_FAIL;
+		} else {
+
+			/* Now fix up the Tnodes etc. */
+
+			if (tags.chunk_id == 0) {
+				/* It's a header */
+				object->hdr_chunk = new_chunk;
+				object->serial = tags.serial_number;
+			} else {
+				/* It's a data chunk */
+				yaffs_put_chunk_in_file(object, tags.chunk_id,
+							new_chunk, 0);
+			}
+		}
+	}
+	if (ret_val == YAFFS_OK)
+		yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
+	return ret_val;
+}
+
+static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
+{
+	int old_chunk;
+	int ret_val = YAFFS_OK;
+	int i;
+	int is_checkpt_block;
+	int max_copies;
+	int chunks_before = yaffs_get_erased_chunks(dev);
+	int chunks_after;
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
+
+	is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
+
+	yaffs_trace(YAFFS_TRACE_TRACING,
+		"Collecting block %d, in use %d, shrink %d, whole_block %d",
+		block, bi->pages_in_use, bi->has_shrink_hdr,
+		whole_block);
+
+	/*yaffs_verify_free_chunks(dev); */
+
+	if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
+		bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
+
+	bi->has_shrink_hdr = 0;	/* clear the flag so that the block can erase */
+
+	dev->gc_disable = 1;
+
+	yaffs_summary_gc(dev, block);
+
+	if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
+		yaffs_trace(YAFFS_TRACE_TRACING,
+			"Collecting block %d that has no chunks in use",
+			block);
+		yaffs_block_became_dirty(dev, block);
+	} else {
+
+		u8 *buffer = yaffs_get_temp_buffer(dev);
+
+		yaffs_verify_blk(dev, bi, block);
+
+		max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
+		old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
+
+		for (/* init already done */ ;
+		     ret_val == YAFFS_OK &&
+		     dev->gc_chunk < dev->param.chunks_per_block &&
+		     (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
+		     max_copies > 0;
+		     dev->gc_chunk++, old_chunk++) {
+			if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
+				/* Page is in use and might need to be copied */
+				max_copies--;
+				ret_val = yaffs_gc_process_chunk(dev, bi,
+							old_chunk, buffer);
+			}
+		}
+		yaffs_release_temp_buffer(dev, buffer);
+	}
+
+	yaffs_verify_collected_blk(dev, bi, block);
+
+	if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
+		/*
+		 * The gc did not complete. Set block state back to FULL
+		 * because checkpointing does not restore gc.
+		 */
+		bi->block_state = YAFFS_BLOCK_STATE_FULL;
+	} else {
+		/* The gc completed. */
+		/* Do any required cleanups */
+		for (i = 0; i < dev->n_clean_ups; i++) {
+			/* Time to delete the file too */
+			struct yaffs_obj *object =
+			    yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
+			if (object) {
+				yaffs_free_tnode(dev,
+					  object->variant.file_variant.top);
+				object->variant.file_variant.top = NULL;
+				yaffs_trace(YAFFS_TRACE_GC,
+					"yaffs: About to finally delete object %d",
+					object->obj_id);
+				yaffs_generic_obj_del(object);
+				object->my_dev->n_deleted_files--;
+			}
+
+		}
+		chunks_after = yaffs_get_erased_chunks(dev);
+		if (chunks_before >= chunks_after)
+			yaffs_trace(YAFFS_TRACE_GC,
+				"gc did not increase free chunks before %d after %d",
+				chunks_before, chunks_after);
+		dev->gc_block = 0;
+		dev->gc_chunk = 0;
+		dev->n_clean_ups = 0;
+	}
+
+	dev->gc_disable = 0;
+
+	return ret_val;
+}
+
+/*
+ * find_gc_block() selects the dirtiest block (or close enough)
+ * for garbage collection.
+ */
+
+static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
+				    int aggressive, int background)
+{
+	int i;
+	int iterations;
+	unsigned selected = 0;
+	int prioritised = 0;
+	int prioritised_exist = 0;
+	struct yaffs_block_info *bi;
+	int threshold;
+
+	/* First let's see if we need to grab a prioritised block */
+	if (dev->has_pending_prioritised_gc && !aggressive) {
+		dev->gc_dirtiest = 0;
+		bi = dev->block_info;
+		for (i = dev->internal_start_block;
+		     i <= dev->internal_end_block && !selected; i++) {
+
+			if (bi->gc_prioritise) {
+				prioritised_exist = 1;
+				if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+				    yaffs_block_ok_for_gc(dev, bi)) {
+					selected = i;
+					prioritised = 1;
+				}
+			}
+			bi++;
+		}
+
+		/*
+		 * If there is a prioritised block and none was selected then
+		 * this happened because there is at least one old dirty block
+		 * gumming up the works. Let's gc the oldest dirty block.
+		 */
+
+		if (prioritised_exist &&
+		    !selected && dev->oldest_dirty_block > 0)
+			selected = dev->oldest_dirty_block;
+
+		if (!prioritised_exist)	/* None found, so we can clear this */
+			dev->has_pending_prioritised_gc = 0;
+	}
+
+	/* If we're doing aggressive GC then we are happy to take a less-dirty
+	 * block, and search harder.
+	 * else (leasurely gc), then we only bother to do this if the
+	 * block has only a few pages in use.
+	 */
+
+	if (!selected) {
+		int pages_used;
+		int n_blocks =
+		    dev->internal_end_block - dev->internal_start_block + 1;
+		if (aggressive) {
+			threshold = dev->param.chunks_per_block;
+			iterations = n_blocks;
+		} else {
+			int max_threshold;
+
+			if (background)
+				max_threshold = dev->param.chunks_per_block / 2;
+			else
+				max_threshold = dev->param.chunks_per_block / 8;
+
+			if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+				max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+
+			threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
+			if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+				threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+			if (threshold > max_threshold)
+				threshold = max_threshold;
+
+			iterations = n_blocks / 16 + 1;
+			if (iterations > 100)
+				iterations = 100;
+		}
+
+		for (i = 0;
+		     i < iterations &&
+		     (dev->gc_dirtiest < 1 ||
+		      dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
+		     i++) {
+			dev->gc_block_finder++;
+			if (dev->gc_block_finder < dev->internal_start_block ||
+			    dev->gc_block_finder > dev->internal_end_block)
+				dev->gc_block_finder =
+				    dev->internal_start_block;
+
+			bi = yaffs_get_block_info(dev, dev->gc_block_finder);
+
+			pages_used = bi->pages_in_use - bi->soft_del_pages;
+
+			if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+			    pages_used < dev->param.chunks_per_block &&
+			    (dev->gc_dirtiest < 1 ||
+			     pages_used < dev->gc_pages_in_use) &&
+			    yaffs_block_ok_for_gc(dev, bi)) {
+				dev->gc_dirtiest = dev->gc_block_finder;
+				dev->gc_pages_in_use = pages_used;
+			}
+		}
+
+		if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
+			selected = dev->gc_dirtiest;
+	}
+
+	/*
+	 * If nothing has been selected for a while, try the oldest dirty
+	 * because that's gumming up the works.
+	 */
+
+	if (!selected && dev->param.is_yaffs2 &&
+	    dev->gc_not_done >= (background ? 10 : 20)) {
+		yaffs2_find_oldest_dirty_seq(dev);
+		if (dev->oldest_dirty_block > 0) {
+			selected = dev->oldest_dirty_block;
+			dev->gc_dirtiest = selected;
+			dev->oldest_dirty_gc_count++;
+			bi = yaffs_get_block_info(dev, selected);
+			dev->gc_pages_in_use =
+			    bi->pages_in_use - bi->soft_del_pages;
+		} else {
+			dev->gc_not_done = 0;
+		}
+	}
+
+	if (selected) {
+		yaffs_trace(YAFFS_TRACE_GC,
+			"GC Selected block %d with %d free, prioritised:%d",
+			selected,
+			dev->param.chunks_per_block - dev->gc_pages_in_use,
+			prioritised);
+
+		dev->n_gc_blocks++;
+		if (background)
+			dev->bg_gcs++;
+
+		dev->gc_dirtiest = 0;
+		dev->gc_pages_in_use = 0;
+		dev->gc_not_done = 0;
+		if (dev->refresh_skip > 0)
+			dev->refresh_skip--;
+	} else {
+		dev->gc_not_done++;
+		yaffs_trace(YAFFS_TRACE_GC,
+			"GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
+			dev->gc_block_finder, dev->gc_not_done, threshold,
+			dev->gc_dirtiest, dev->gc_pages_in_use,
+			dev->oldest_dirty_block, background ? " bg" : "");
+	}
+
+	return selected;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_check_gc(struct yaffs_dev *dev, int background)
+{
+	int aggressive = 0;
+	int gc_ok = YAFFS_OK;
+	int max_tries = 0;
+	int min_erased;
+	int erased_chunks;
+	int checkpt_block_adjust;
+
+	if (dev->param.gc_control_fn &&
+		(dev->param.gc_control_fn(dev) & 1) == 0)
+		return YAFFS_OK;
+
+	if (dev->gc_disable)
+		/* Bail out so we don't get recursive gc */
+		return YAFFS_OK;
+
+	/* This loop should pass the first time.
+	 * Only loops here if the collection does not increase space.
+	 */
+
+	do {
+		max_tries++;
+
+		checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
+
+		min_erased =
+		    dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
+		erased_chunks =
+		    dev->n_erased_blocks * dev->param.chunks_per_block;
+
+		/* If we need a block soon then do aggressive gc. */
+		if (dev->n_erased_blocks < min_erased)
+			aggressive = 1;
+		else {
+			if (!background
+			    && erased_chunks > (dev->n_free_chunks / 4))
+				break;
+
+			if (dev->gc_skip > 20)
+				dev->gc_skip = 20;
+			if (erased_chunks < dev->n_free_chunks / 2 ||
+			    dev->gc_skip < 1 || background)
+				aggressive = 0;
+			else {
+				dev->gc_skip--;
+				break;
+			}
+		}
+
+		dev->gc_skip = 5;
+
+		/* If we don't already have a block being gc'd then see if we
+		 * should start another */
+
+		if (dev->gc_block < 1 && !aggressive) {
+			dev->gc_block = yaffs2_find_refresh_block(dev);
+			dev->gc_chunk = 0;
+			dev->n_clean_ups = 0;
+		}
+		if (dev->gc_block < 1) {
+			dev->gc_block =
+			    yaffs_find_gc_block(dev, aggressive, background);
+			dev->gc_chunk = 0;
+			dev->n_clean_ups = 0;
+		}
+
+		if (dev->gc_block > 0) {
+			dev->all_gcs++;
+			if (!aggressive)
+				dev->passive_gc_count++;
+
+			yaffs_trace(YAFFS_TRACE_GC,
+				"yaffs: GC n_erased_blocks %d aggressive %d",
+				dev->n_erased_blocks, aggressive);
+
+			gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
+		}
+
+		if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
+		    dev->gc_block > 0) {
+			yaffs_trace(YAFFS_TRACE_GC,
+				"yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
+				dev->n_erased_blocks, max_tries,
+				dev->gc_block);
+		}
+	} while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
+		 (dev->gc_block > 0) && (max_tries < 2));
+
+	return aggressive ? gc_ok : YAFFS_OK;
+}
+
+/*
+ * yaffs_bg_gc()
+ * Garbage collects. Intended to be called from a background thread.
+ * Returns non-zero if at least half the free chunks are erased.
+ */
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
+{
+	int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
+
+	yaffs_check_gc(dev, 1);
+	return erased_chunks > dev->n_free_chunks / 2;
+}
+
+/*-------------------- Data file manipulation -----------------*/
+
+static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
+{
+	int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
+
+	if (nand_chunk >= 0)
+		return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
+						buffer, NULL);
+	else {
+		yaffs_trace(YAFFS_TRACE_NANDACCESS,
+			"Chunk %d not found zero instead",
+			nand_chunk);
+		/* get sane (zero) data if you read a hole */
+		memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
+		return 0;
+	}
+
+}
+
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+		     int lyn)
+{
+	int block;
+	int page;
+	struct yaffs_ext_tags tags;
+	struct yaffs_block_info *bi;
+
+	if (chunk_id <= 0)
+		return;
+
+	dev->n_deletions++;
+	block = chunk_id / dev->param.chunks_per_block;
+	page = chunk_id % dev->param.chunks_per_block;
+
+	if (!yaffs_check_chunk_bit(dev, block, page))
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Deleting invalid chunk %d", chunk_id);
+
+	bi = yaffs_get_block_info(dev, block);
+
+	yaffs2_update_oldest_dirty_seq(dev, block, bi);
+
+	yaffs_trace(YAFFS_TRACE_DELETION,
+		"line %d delete of chunk %d",
+		lyn, chunk_id);
+
+	if (!dev->param.is_yaffs2 && mark_flash &&
+	    bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
+
+		memset(&tags, 0, sizeof(tags));
+		tags.is_deleted = 1;
+		yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
+		yaffs_handle_chunk_update(dev, chunk_id, &tags);
+	} else {
+		dev->n_unmarked_deletions++;
+	}
+
+	/* Pull out of the management area.
+	 * If the whole block became dirty, this will kick off an erasure.
+	 */
+	if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
+	    bi->block_state == YAFFS_BLOCK_STATE_FULL ||
+	    bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+	    bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
+		dev->n_free_chunks++;
+		yaffs_clear_chunk_bit(dev, block, page);
+		bi->pages_in_use--;
+
+		if (bi->pages_in_use == 0 &&
+		    !bi->has_shrink_hdr &&
+		    bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
+		    bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			yaffs_block_became_dirty(dev, block);
+		}
+	}
+}
+
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+			     const u8 *buffer, int n_bytes, int use_reserve)
+{
+	/* Find old chunk Need to do this to get serial number
+	 * Write new one and patch into tree.
+	 * Invalidate old tags.
+	 */
+
+	int prev_chunk_id;
+	struct yaffs_ext_tags prev_tags;
+	int new_chunk_id;
+	struct yaffs_ext_tags new_tags;
+	struct yaffs_dev *dev = in->my_dev;
+
+	yaffs_check_gc(dev, 0);
+
+	/* Get the previous chunk at this location in the file if it exists.
+	 * If it does not exist then put a zero into the tree. This creates
+	 * the tnode now, rather than later when it is harder to clean up.
+	 */
+	prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
+	if (prev_chunk_id < 1 &&
+	    !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
+		return 0;
+
+	/* Set up new tags */
+	memset(&new_tags, 0, sizeof(new_tags));
+
+	new_tags.chunk_id = inode_chunk;
+	new_tags.obj_id = in->obj_id;
+	new_tags.serial_number =
+	    (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
+	new_tags.n_bytes = n_bytes;
+
+	if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+		  "Writing %d bytes to chunk!!!!!!!!!",
+		   n_bytes);
+		BUG();
+	}
+
+	new_chunk_id =
+	    yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
+
+	if (new_chunk_id > 0) {
+		yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
+
+		if (prev_chunk_id > 0)
+			yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
+
+		yaffs_verify_file_sane(in);
+	}
+	return new_chunk_id;
+
+}
+
+
+
+static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
+				const YCHAR *name, const void *value, int size,
+				int flags)
+{
+	struct yaffs_xattr_mod xmod;
+	int result;
+
+	xmod.set = set;
+	xmod.name = name;
+	xmod.data = value;
+	xmod.size = size;
+	xmod.flags = flags;
+	xmod.result = -ENOSPC;
+
+	result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
+
+	if (result > 0)
+		return xmod.result;
+	else
+		return -ENOSPC;
+}
+
+static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
+				   struct yaffs_xattr_mod *xmod)
+{
+	int retval = 0;
+	int x_offs = sizeof(struct yaffs_obj_hdr);
+	struct yaffs_dev *dev = obj->my_dev;
+	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+	char *x_buffer = buffer + x_offs;
+
+	if (xmod->set)
+		retval =
+		    nval_set(x_buffer, x_size, xmod->name, xmod->data,
+			     xmod->size, xmod->flags);
+	else
+		retval = nval_del(x_buffer, x_size, xmod->name);
+
+	obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+	obj->xattr_known = 1;
+	xmod->result = retval;
+
+	return retval;
+}
+
+static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
+				  void *value, int size)
+{
+	char *buffer = NULL;
+	int result;
+	struct yaffs_ext_tags tags;
+	struct yaffs_dev *dev = obj->my_dev;
+	int x_offs = sizeof(struct yaffs_obj_hdr);
+	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+	char *x_buffer;
+	int retval = 0;
+
+	if (obj->hdr_chunk < 1)
+		return -ENODATA;
+
+	/* If we know that the object has no xattribs then don't do all the
+	 * reading and parsing.
+	 */
+	if (obj->xattr_known && !obj->has_xattr) {
+		if (name)
+			return -ENODATA;
+		else
+			return 0;
+	}
+
+	buffer = (char *)yaffs_get_temp_buffer(dev);
+	if (!buffer)
+		return -ENOMEM;
+
+	result =
+	    yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
+
+	if (result != YAFFS_OK)
+		retval = -ENOENT;
+	else {
+		x_buffer = buffer + x_offs;
+
+		if (!obj->xattr_known) {
+			obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+			obj->xattr_known = 1;
+		}
+
+		if (name)
+			retval = nval_get(x_buffer, x_size, name, value, size);
+		else
+			retval = nval_list(x_buffer, x_size, value, size);
+	}
+	yaffs_release_temp_buffer(dev, (u8 *) buffer);
+	return retval;
+}
+
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
+		      const void *value, int size, int flags)
+{
+	return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
+}
+
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
+{
+	return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
+}
+
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
+		      int size)
+{
+	return yaffs_do_xattrib_fetch(obj, name, value, size);
+}
+
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
+{
+	return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
+}
+
+static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
+{
+	u8 *buf;
+	struct yaffs_obj_hdr *oh;
+	struct yaffs_dev *dev;
+	struct yaffs_ext_tags tags;
+	int result;
+	int alloc_failed = 0;
+
+	if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
+		return;
+
+	dev = in->my_dev;
+	in->lazy_loaded = 0;
+	buf = yaffs_get_temp_buffer(dev);
+
+	result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
+	oh = (struct yaffs_obj_hdr *)buf;
+
+	in->yst_mode = oh->yst_mode;
+	yaffs_load_attribs(in, oh);
+	yaffs_set_obj_name_from_oh(in, oh);
+
+	if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		in->variant.symlink_variant.alias =
+		    yaffs_clone_str(oh->alias);
+		if (!in->variant.symlink_variant.alias)
+			alloc_failed = 1;	/* Not returned */
+	}
+	yaffs_release_temp_buffer(dev, buf);
+}
+
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
+		    int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
+{
+
+	struct yaffs_block_info *bi;
+	struct yaffs_dev *dev = in->my_dev;
+	int prev_chunk_id;
+	int ret_val = 0;
+	int result = 0;
+	int new_chunk_id;
+	struct yaffs_ext_tags new_tags;
+	struct yaffs_ext_tags old_tags;
+	const YCHAR *alias = NULL;
+	u8 *buffer = NULL;
+	YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
+	struct yaffs_obj_hdr *oh = NULL;
+	loff_t file_size = 0;
+
+	strcpy(old_name, _Y("silly old name"));
+
+	if (in->fake && in != dev->root_dir && !force && !xmod)
+		return ret_val;
+
+	yaffs_check_gc(dev, 0);
+	yaffs_check_obj_details_loaded(in);
+
+	buffer = yaffs_get_temp_buffer(in->my_dev);
+	oh = (struct yaffs_obj_hdr *)buffer;
+
+	prev_chunk_id = in->hdr_chunk;
+
+	if (prev_chunk_id > 0) {
+		result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
+						  buffer, &old_tags);
+
+		yaffs_verify_oh(in, oh, &old_tags, 0);
+		memcpy(old_name, oh->name, sizeof(oh->name));
+		memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
+	} else {
+		memset(buffer, 0xff, dev->data_bytes_per_chunk);
+	}
+
+	oh->type = in->variant_type;
+	oh->yst_mode = in->yst_mode;
+	oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
+
+	yaffs_load_attribs_oh(oh, in);
+
+	if (in->parent)
+		oh->parent_obj_id = in->parent->obj_id;
+	else
+		oh->parent_obj_id = 0;
+
+	if (name && *name) {
+		memset(oh->name, 0, sizeof(oh->name));
+		yaffs_load_oh_from_name(dev, oh->name, name);
+	} else if (prev_chunk_id > 0) {
+		memcpy(oh->name, old_name, sizeof(oh->name));
+	} else {
+		memset(oh->name, 0, sizeof(oh->name));
+	}
+
+	oh->is_shrink = is_shrink;
+
+	switch (in->variant_type) {
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		/* Should not happen */
+		break;
+	case YAFFS_OBJECT_TYPE_FILE:
+		if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
+		    oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
+			file_size = in->variant.file_variant.file_size;
+		yaffs_oh_size_load(oh, file_size);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		oh->equiv_id = in->variant.hardlink_variant.equiv_id;
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		/* Do nothing */
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		/* Do nothing */
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		alias = in->variant.symlink_variant.alias;
+		if (!alias)
+			alias = _Y("no alias");
+		strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
+		oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+		break;
+	}
+
+	/* process any xattrib modifications */
+	if (xmod)
+		yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
+
+	/* Tags */
+	memset(&new_tags, 0, sizeof(new_tags));
+	in->serial++;
+	new_tags.chunk_id = 0;
+	new_tags.obj_id = in->obj_id;
+	new_tags.serial_number = in->serial;
+
+	/* Add extra info for file header */
+	new_tags.extra_available = 1;
+	new_tags.extra_parent_id = oh->parent_obj_id;
+	new_tags.extra_file_size = file_size;
+	new_tags.extra_is_shrink = oh->is_shrink;
+	new_tags.extra_equiv_id = oh->equiv_id;
+	new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
+	new_tags.extra_obj_type = in->variant_type;
+	yaffs_verify_oh(in, oh, &new_tags, 1);
+
+	/* Create new chunk in NAND */
+	new_chunk_id =
+	    yaffs_write_new_chunk(dev, buffer, &new_tags,
+				  (prev_chunk_id > 0) ? 1 : 0);
+
+	if (buffer)
+		yaffs_release_temp_buffer(dev, buffer);
+
+	if (new_chunk_id < 0)
+		return new_chunk_id;
+
+	in->hdr_chunk = new_chunk_id;
+
+	if (prev_chunk_id > 0)
+		yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
+
+	if (!yaffs_obj_cache_dirty(in))
+		in->dirty = 0;
+
+	/* If this was a shrink, then mark the block
+	 * that the chunk lives on */
+	if (is_shrink) {
+		bi = yaffs_get_block_info(in->my_dev,
+					  new_chunk_id /
+					  in->my_dev->param.chunks_per_block);
+		bi->has_shrink_hdr = 1;
+	}
+
+
+	return new_chunk_id;
+}
+
+/*--------------------- File read/write ------------------------
+ * Read and write have very similar structures.
+ * In general the read/write has three parts to it
+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
+ * Some complete chunks
+ * An incomplete chunk to end off with
+ *
+ * Curve-balls: the first chunk might also be the last chunk.
+ */
+
+int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
+{
+	int chunk;
+	u32 start;
+	int n_copy;
+	int n = n_bytes;
+	int n_done = 0;
+	struct yaffs_cache *cache;
+	struct yaffs_dev *dev;
+
+	dev = in->my_dev;
+
+	while (n > 0) {
+		yaffs_addr_to_chunk(dev, offset, &chunk, &start);
+		chunk++;
+
+		/* OK now check for the curveball where the start and end are in
+		 * the same chunk.
+		 */
+		if ((start + n) < dev->data_bytes_per_chunk)
+			n_copy = n;
+		else
+			n_copy = dev->data_bytes_per_chunk - start;
+
+		cache = yaffs_find_chunk_cache(in, chunk);
+
+		/* If the chunk is already in the cache or it is less than
+		 * a whole chunk or we're using inband tags then use the cache
+		 * (if there is caching) else bypass the cache.
+		 */
+		if (cache || n_copy != dev->data_bytes_per_chunk ||
+		    dev->param.inband_tags) {
+			if (dev->param.n_caches > 0) {
+
+				/* If we can't find the data in the cache,
+				 * then load it up. */
+
+				if (!cache) {
+					cache =
+					    yaffs_grab_chunk_cache(in->my_dev);
+					cache->object = in;
+					cache->chunk_id = chunk;
+					cache->dirty = 0;
+					cache->locked = 0;
+					yaffs_rd_data_obj(in, chunk,
+							  cache->data);
+					cache->n_bytes = 0;
+				}
+
+				yaffs_use_cache(dev, cache, 0);
+
+				cache->locked = 1;
+
+				memcpy(buffer, &cache->data[start], n_copy);
+
+				cache->locked = 0;
+			} else {
+				/* Read into the local buffer then copy.. */
+
+				u8 *local_buffer =
+				    yaffs_get_temp_buffer(dev);
+				yaffs_rd_data_obj(in, chunk, local_buffer);
+
+				memcpy(buffer, &local_buffer[start], n_copy);
+
+				yaffs_release_temp_buffer(dev, local_buffer);
+			}
+		} else {
+			/* A full chunk. Read directly into the buffer. */
+			yaffs_rd_data_obj(in, chunk, buffer);
+		}
+		n -= n_copy;
+		offset += n_copy;
+		buffer += n_copy;
+		n_done += n_copy;
+	}
+	return n_done;
+}
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+		     int n_bytes, int write_through)
+{
+
+	int chunk;
+	u32 start;
+	int n_copy;
+	int n = n_bytes;
+	int n_done = 0;
+	int n_writeback;
+	loff_t start_write = offset;
+	int chunk_written = 0;
+	u32 n_bytes_read;
+	loff_t chunk_start;
+	struct yaffs_dev *dev;
+
+	dev = in->my_dev;
+
+	while (n > 0 && chunk_written >= 0) {
+		yaffs_addr_to_chunk(dev, offset, &chunk, &start);
+
+		if (((loff_t)chunk) *
+		    dev->data_bytes_per_chunk + start != offset ||
+		    start >= dev->data_bytes_per_chunk) {
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"AddrToChunk of offset %lld gives chunk %d start %d",
+				offset, chunk, start);
+		}
+		chunk++;	/* File pos to chunk in file offset */
+
+		/* OK now check for the curveball where the start and end are in
+		 * the same chunk.
+		 */
+
+		if ((start + n) < dev->data_bytes_per_chunk) {
+			n_copy = n;
+
+			/* Now calculate how many bytes to write back....
+			 * If we're overwriting and not writing to then end of
+			 * file then we need to write back as much as was there
+			 * before.
+			 */
+
+			chunk_start = (((loff_t)(chunk - 1)) *
+					dev->data_bytes_per_chunk);
+
+			if (chunk_start > in->variant.file_variant.file_size)
+				n_bytes_read = 0;	/* Past end of file */
+			else
+				n_bytes_read =
+				    in->variant.file_variant.file_size -
+				    chunk_start;
+
+			if (n_bytes_read > dev->data_bytes_per_chunk)
+				n_bytes_read = dev->data_bytes_per_chunk;
+
+			n_writeback =
+			    (n_bytes_read >
+			     (start + n)) ? n_bytes_read : (start + n);
+
+			if (n_writeback < 0 ||
+			    n_writeback > dev->data_bytes_per_chunk)
+				BUG();
+
+		} else {
+			n_copy = dev->data_bytes_per_chunk - start;
+			n_writeback = dev->data_bytes_per_chunk;
+		}
+
+		if (n_copy != dev->data_bytes_per_chunk ||
+		    !dev->param.cache_bypass_aligned ||
+		    dev->param.inband_tags) {
+			/* An incomplete start or end chunk (or maybe both
+			 * start and end chunk), or we're using inband tags,
+			 * or we're forcing writes through the cache,
+			 * so we want to use the cache buffers.
+			 */
+			if (dev->param.n_caches > 0) {
+				struct yaffs_cache *cache;
+
+				/* If we can't find the data in the cache, then
+				 * load the cache */
+				cache = yaffs_find_chunk_cache(in, chunk);
+
+				if (!cache &&
+				    yaffs_check_alloc_available(dev, 1)) {
+					cache = yaffs_grab_chunk_cache(dev);
+					cache->object = in;
+					cache->chunk_id = chunk;
+					cache->dirty = 0;
+					cache->locked = 0;
+					yaffs_rd_data_obj(in, chunk,
+							  cache->data);
+				} else if (cache &&
+					   !cache->dirty &&
+					   !yaffs_check_alloc_available(dev,
+									1)) {
+					/* Drop the cache if it was a read cache
+					 * item and no space check has been made
+					 * for it.
+					 */
+					cache = NULL;
+				}
+
+				if (cache) {
+					yaffs_use_cache(dev, cache, 1);
+					cache->locked = 1;
+
+					memcpy(&cache->data[start], buffer,
+					       n_copy);
+
+					cache->locked = 0;
+					cache->n_bytes = n_writeback;
+
+					if (write_through) {
+						chunk_written =
+						    yaffs_wr_data_obj
+						    (cache->object,
+						     cache->chunk_id,
+						     cache->data,
+						     cache->n_bytes, 1);
+						cache->dirty = 0;
+					}
+				} else {
+					chunk_written = -1;	/* fail write */
+				}
+			} else {
+				/* An incomplete start or end chunk (or maybe
+				 * both start and end chunk). Read into the
+				 * local buffer then copy over and write back.
+				 */
+
+				u8 *local_buffer = yaffs_get_temp_buffer(dev);
+
+				yaffs_rd_data_obj(in, chunk, local_buffer);
+				memcpy(&local_buffer[start], buffer, n_copy);
+
+				chunk_written =
+				    yaffs_wr_data_obj(in, chunk,
+						      local_buffer,
+						      n_writeback, 0);
+
+				yaffs_release_temp_buffer(dev, local_buffer);
+			}
+		} else {
+			/* A full chunk. Write directly from the buffer. */
+
+			chunk_written =
+			    yaffs_wr_data_obj(in, chunk, buffer,
+					      dev->data_bytes_per_chunk, 0);
+
+			/* Since we've overwritten the cached data,
+			 * we better invalidate it. */
+			yaffs_invalidate_chunk_cache(in, chunk);
+		}
+
+		if (chunk_written >= 0) {
+			n -= n_copy;
+			offset += n_copy;
+			buffer += n_copy;
+			n_done += n_copy;
+		}
+	}
+
+	/* Update file object */
+
+	if ((start_write + n_done) > in->variant.file_variant.file_size)
+		in->variant.file_variant.file_size = (start_write + n_done);
+
+	in->dirty = 1;
+	return n_done;
+}
+
+int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+		  int n_bytes, int write_through)
+{
+	yaffs2_handle_hole(in, offset);
+	return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
+}
+
+/* ---------------------- File resizing stuff ------------------ */
+
+static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
+{
+
+	struct yaffs_dev *dev = in->my_dev;
+	loff_t old_size = in->variant.file_variant.file_size;
+	int i;
+	int chunk_id;
+	u32 dummy;
+	int last_del;
+	int start_del;
+
+	if (old_size > 0)
+		yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
+	else
+		last_del = 0;
+
+	yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
+				&start_del, &dummy);
+	last_del++;
+	start_del++;
+
+	/* Delete backwards so that we don't end up with holes if
+	 * power is lost part-way through the operation.
+	 */
+	for (i = last_del; i >= start_del; i--) {
+		/* NB this could be optimised somewhat,
+		 * eg. could retrieve the tags and write them without
+		 * using yaffs_chunk_del
+		 */
+
+		chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
+
+		if (chunk_id < 1)
+			continue;
+
+		if (chunk_id <
+		    (dev->internal_start_block * dev->param.chunks_per_block) ||
+		    chunk_id >=
+		    ((dev->internal_end_block + 1) *
+		      dev->param.chunks_per_block)) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"Found daft chunk_id %d for %d",
+				chunk_id, i);
+		} else {
+			in->n_data_chunks--;
+			yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
+		}
+	}
+}
+
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
+{
+	int new_full;
+	u32 new_partial;
+	struct yaffs_dev *dev = obj->my_dev;
+
+	yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
+
+	yaffs_prune_chunks(obj, new_size);
+
+	if (new_partial != 0) {
+		int last_chunk = 1 + new_full;
+		u8 *local_buffer = yaffs_get_temp_buffer(dev);
+
+		/* Rewrite the last chunk with its new size and zero pad */
+		yaffs_rd_data_obj(obj, last_chunk, local_buffer);
+		memset(local_buffer + new_partial, 0,
+		       dev->data_bytes_per_chunk - new_partial);
+
+		yaffs_wr_data_obj(obj, last_chunk, local_buffer,
+				  new_partial, 1);
+
+		yaffs_release_temp_buffer(dev, local_buffer);
+	}
+
+	obj->variant.file_variant.file_size = new_size;
+
+	yaffs_prune_tree(dev, &obj->variant.file_variant);
+}
+
+int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
+{
+	struct yaffs_dev *dev = in->my_dev;
+	loff_t old_size = in->variant.file_variant.file_size;
+
+	yaffs_flush_file_cache(in, 1);
+	yaffs_invalidate_whole_cache(in);
+
+	yaffs_check_gc(dev, 0);
+
+	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		return YAFFS_FAIL;
+
+	if (new_size == old_size)
+		return YAFFS_OK;
+
+	if (new_size > old_size) {
+		yaffs2_handle_hole(in, new_size);
+		in->variant.file_variant.file_size = new_size;
+	} else {
+		/* new_size < old_size */
+		yaffs_resize_file_down(in, new_size);
+	}
+
+	/* Write a new object header to reflect the resize.
+	 * show we've shrunk the file, if need be
+	 * Do this only if the file is not in the deleted directories
+	 * and is not shadowed.
+	 */
+	if (in->parent &&
+	    !in->is_shadowed &&
+	    in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+	    in->parent->obj_id != YAFFS_OBJECTID_DELETED)
+		yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
+
+	return YAFFS_OK;
+}
+
+int yaffs_flush_file(struct yaffs_obj *in,
+		     int update_time,
+		     int data_sync,
+		     int discard_cache)
+{
+	if (!in->dirty)
+		return YAFFS_OK;
+
+	yaffs_flush_file_cache(in, discard_cache);
+
+	if (data_sync)
+		return YAFFS_OK;
+
+	if (update_time)
+		yaffs_load_current_time(in, 0, 0);
+
+	return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
+				YAFFS_OK : YAFFS_FAIL;
+}
+
+
+/* yaffs_del_file deletes the whole file data
+ * and the inode associated with the file.
+ * It does not delete the links associated with the file.
+ */
+static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
+{
+	int ret_val;
+	int del_now = 0;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (!in->my_inode)
+		del_now = 1;
+
+	if (del_now) {
+		ret_val =
+		    yaffs_change_obj_name(in, in->my_dev->del_dir,
+					  _Y("deleted"), 0, 0);
+		yaffs_trace(YAFFS_TRACE_TRACING,
+			"yaffs: immediate deletion of file %d",
+			in->obj_id);
+		in->deleted = 1;
+		in->my_dev->n_deleted_files++;
+		if (dev->param.disable_soft_del || dev->param.is_yaffs2)
+			yaffs_resize_file(in, 0);
+		yaffs_soft_del_file(in);
+	} else {
+		ret_val =
+		    yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
+					  _Y("unlinked"), 0, 0);
+	}
+	return ret_val;
+}
+
+static int yaffs_del_file(struct yaffs_obj *in)
+{
+	int ret_val = YAFFS_OK;
+	int deleted;	/* Need to cache value on stack if in is freed */
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (dev->param.disable_soft_del || dev->param.is_yaffs2)
+		yaffs_resize_file(in, 0);
+
+	if (in->n_data_chunks > 0) {
+		/* Use soft deletion if there is data in the file.
+		 * That won't be the case if it has been resized to zero.
+		 */
+		if (!in->unlinked)
+			ret_val = yaffs_unlink_file_if_needed(in);
+
+		deleted = in->deleted;
+
+		if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
+			in->deleted = 1;
+			deleted = 1;
+			in->my_dev->n_deleted_files++;
+			yaffs_soft_del_file(in);
+		}
+		return deleted ? YAFFS_OK : YAFFS_FAIL;
+	} else {
+		/* The file has no data chunks so we toss it immediately */
+		yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
+		in->variant.file_variant.top = NULL;
+		yaffs_generic_obj_del(in);
+
+		return YAFFS_OK;
+	}
+}
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
+{
+	return (obj &&
+		obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+		!(list_empty(&obj->variant.dir_variant.children));
+}
+
+static int yaffs_del_dir(struct yaffs_obj *obj)
+{
+	/* First check that the directory is empty. */
+	if (yaffs_is_non_empty_dir(obj))
+		return YAFFS_FAIL;
+
+	return yaffs_generic_obj_del(obj);
+}
+
+static int yaffs_del_symlink(struct yaffs_obj *in)
+{
+	kfree(in->variant.symlink_variant.alias);
+	in->variant.symlink_variant.alias = NULL;
+
+	return yaffs_generic_obj_del(in);
+}
+
+static int yaffs_del_link(struct yaffs_obj *in)
+{
+	/* remove this hardlink from the list associated with the equivalent
+	 * object
+	 */
+	list_del_init(&in->hard_links);
+	return yaffs_generic_obj_del(in);
+}
+
+int yaffs_del_obj(struct yaffs_obj *obj)
+{
+	int ret_val = -1;
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		ret_val = yaffs_del_file(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		if (!list_empty(&obj->variant.dir_variant.dirty)) {
+			yaffs_trace(YAFFS_TRACE_BACKGROUND,
+				"Remove object %d from dirty directories",
+				obj->obj_id);
+			list_del_init(&obj->variant.dir_variant.dirty);
+		}
+		return yaffs_del_dir(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		ret_val = yaffs_del_symlink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		ret_val = yaffs_del_link(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		ret_val = yaffs_generic_obj_del(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		ret_val = 0;
+		break;		/* should not happen. */
+	}
+	return ret_val;
+}
+
+
+static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
+				   struct yaffs_obj *to_dir)
+{
+	struct yaffs_obj *obj;
+	struct list_head *lh;
+	struct list_head *n;
+
+	list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
+		obj = list_entry(lh, struct yaffs_obj, siblings);
+		yaffs_add_obj_to_dir(to_dir, obj);
+	}
+}
+
+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
+				   enum yaffs_obj_type type)
+{
+	/* Tear down the old variant */
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		/* Nuke file data */
+		yaffs_resize_file(obj, 0);
+		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+		obj->variant.file_variant.top = NULL;
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		/* Put the children in lost and found. */
+		yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
+		if (!list_empty(&obj->variant.dir_variant.dirty))
+			list_del_init(&obj->variant.dir_variant.dirty);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		/* Nuke symplink data */
+		kfree(obj->variant.symlink_variant.alias);
+		obj->variant.symlink_variant.alias = NULL;
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		list_del_init(&obj->hard_links);
+		break;
+	default:
+		break;
+	}
+
+	memset(&obj->variant, 0, sizeof(obj->variant));
+
+	/*Set up new variant if the memset is not enough. */
+	switch (type) {
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		INIT_LIST_HEAD(&obj->variant.dir_variant.children);
+		INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
+		break;
+	case YAFFS_OBJECT_TYPE_FILE:
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+	default:
+		break;
+	}
+
+	obj->variant_type = type;
+
+	return obj;
+
+}
+
+static int yaffs_unlink_worker(struct yaffs_obj *obj)
+{
+	int del_now = 0;
+
+	if (!obj)
+		return YAFFS_FAIL;
+
+	if (!obj->my_inode)
+		del_now = 1;
+
+	yaffs_update_parent(obj->parent);
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
+		return yaffs_del_link(obj);
+	} else if (!list_empty(&obj->hard_links)) {
+		/* Curve ball: We're unlinking an object that has a hardlink.
+		 *
+		 * This problem arises because we are not strictly following
+		 * The Linux link/inode model.
+		 *
+		 * We can't really delete the object.
+		 * Instead, we do the following:
+		 * - Select a hardlink.
+		 * - Unhook it from the hard links
+		 * - Move it from its parent directory so that the rename works.
+		 * - Rename the object to the hardlink's name.
+		 * - Delete the hardlink
+		 */
+
+		struct yaffs_obj *hl;
+		struct yaffs_obj *parent;
+		int ret_val;
+		YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+		hl = list_entry(obj->hard_links.next, struct yaffs_obj,
+				hard_links);
+
+		yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+		parent = hl->parent;
+
+		list_del_init(&hl->hard_links);
+
+		yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
+
+		ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
+
+		if (ret_val == YAFFS_OK)
+			ret_val = yaffs_generic_obj_del(hl);
+
+		return ret_val;
+
+	} else if (del_now) {
+		switch (obj->variant_type) {
+		case YAFFS_OBJECT_TYPE_FILE:
+			return yaffs_del_file(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			list_del_init(&obj->variant.dir_variant.dirty);
+			return yaffs_del_dir(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			return yaffs_del_symlink(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+			return yaffs_generic_obj_del(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+		default:
+			return YAFFS_FAIL;
+		}
+	} else if (yaffs_is_non_empty_dir(obj)) {
+		return YAFFS_FAIL;
+	} else {
+		return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
+						_Y("unlinked"), 0, 0);
+	}
+}
+
+static int yaffs_unlink_obj(struct yaffs_obj *obj)
+{
+	if (obj && obj->unlink_allowed)
+		return yaffs_unlink_worker(obj);
+
+	return YAFFS_FAIL;
+}
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
+{
+	struct yaffs_obj *obj;
+
+	obj = yaffs_find_by_name(dir, name);
+	return yaffs_unlink_obj(obj);
+}
+
+/* Note:
+ * If old_name is NULL then we take old_dir as the object to be renamed.
+ */
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
+		     struct yaffs_obj *new_dir, const YCHAR *new_name)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *existing_target = NULL;
+	int force = 0;
+	int result;
+	struct yaffs_dev *dev;
+
+	if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+	if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	dev = old_dir->my_dev;
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+	/* Special case for case insemsitive systems.
+	 * While look-up is case insensitive, the name isn't.
+	 * Therefore we might want to change x.txt to X.txt
+	 */
+	if (old_dir == new_dir &&
+		old_name && new_name &&
+		strcmp(old_name, new_name) == 0)
+		force = 1;
+#endif
+
+	if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
+	    YAFFS_MAX_NAME_LENGTH)
+		/* ENAMETOOLONG */
+		return YAFFS_FAIL;
+
+	if (old_name)
+		obj = yaffs_find_by_name(old_dir, old_name);
+	else{
+		obj = old_dir;
+		old_dir = obj->parent;
+	}
+
+	if (obj && obj->rename_allowed) {
+		/* Now handle an existing target, if there is one */
+		existing_target = yaffs_find_by_name(new_dir, new_name);
+		if (yaffs_is_non_empty_dir(existing_target)) {
+			return YAFFS_FAIL;	/* ENOTEMPTY */
+		} else if (existing_target && existing_target != obj) {
+			/* Nuke the target first, using shadowing,
+			 * but only if it isn't the same object.
+			 *
+			 * Note we must disable gc here otherwise it can mess
+			 * up the shadowing.
+			 *
+			 */
+			dev->gc_disable = 1;
+			yaffs_change_obj_name(obj, new_dir, new_name, force,
+					      existing_target->obj_id);
+			existing_target->is_shadowed = 1;
+			yaffs_unlink_obj(existing_target);
+			dev->gc_disable = 0;
+		}
+
+		result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
+
+		yaffs_update_parent(old_dir);
+		if (new_dir != old_dir)
+			yaffs_update_parent(new_dir);
+
+		return result;
+	}
+	return YAFFS_FAIL;
+}
+
+/*----------------------- Initialisation Scanning ---------------------- */
+
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+			       int backward_scanning)
+{
+	struct yaffs_obj *obj;
+
+	if (backward_scanning) {
+		/* Handle YAFFS2 case (backward scanning)
+		 * If the shadowed object exists then ignore.
+		 */
+		obj = yaffs_find_by_number(dev, obj_id);
+		if (obj)
+			return;
+	}
+
+	/* Let's create it (if it does not exist) assuming it is a file so that
+	 * it can do shrinking etc.
+	 * We put it in unlinked dir to be cleaned up after the scanning
+	 */
+	obj =
+	    yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
+	if (!obj)
+		return;
+	obj->is_shadowed = 1;
+	yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
+	obj->variant.file_variant.shrink_size = 0;
+	obj->valid = 1;		/* So that we don't read any other info. */
+}
+
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
+{
+	struct list_head *lh;
+	struct list_head *save;
+	struct yaffs_obj *hl;
+	struct yaffs_obj *in;
+
+	list_for_each_safe(lh, save, hard_list) {
+		hl = list_entry(lh, struct yaffs_obj, hard_links);
+		in = yaffs_find_by_number(dev,
+					hl->variant.hardlink_variant.equiv_id);
+
+		if (in) {
+			/* Add the hardlink pointers */
+			hl->variant.hardlink_variant.equiv_obj = in;
+			list_add(&hl->hard_links, &in->hard_links);
+		} else {
+			/* Todo Need to report/handle this better.
+			 * Got a problem... hardlink to a non-existant object
+			 */
+			hl->variant.hardlink_variant.equiv_obj = NULL;
+			INIT_LIST_HEAD(&hl->hard_links);
+		}
+	}
+}
+
+static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
+{
+	/*
+	 *  Sort out state of unlinked and deleted objects after scanning.
+	 */
+	struct list_head *i;
+	struct list_head *n;
+	struct yaffs_obj *l;
+
+	if (dev->read_only)
+		return;
+
+	/* Soft delete all the unlinked files */
+	list_for_each_safe(i, n,
+			   &dev->unlinked_dir->variant.dir_variant.children) {
+		l = list_entry(i, struct yaffs_obj, siblings);
+		yaffs_del_obj(l);
+	}
+
+	list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
+		l = list_entry(i, struct yaffs_obj, siblings);
+		yaffs_del_obj(l);
+	}
+}
+
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ *  This code assumes that we don't ever change the current relationships
+ *  between directories:
+ *   root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
+ *   lost-n-found->parent == root_dir
+ *
+ * This fixes the problem where directories might have inadvertently been
+ * deleted leaving the object "hanging" without being rooted in the
+ * directory tree.
+ */
+
+static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
+{
+	return (obj == dev->del_dir ||
+		obj == dev->unlinked_dir || obj == dev->root_dir);
+}
+
+static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_obj *parent;
+	int i;
+	struct list_head *lh;
+	struct list_head *n;
+	int depth_limit;
+	int hanging;
+
+	if (dev->read_only)
+		return;
+
+	/* Iterate through the objects in each hash entry,
+	 * looking at each object.
+	 * Make sure it is rooted.
+	 */
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
+			obj = list_entry(lh, struct yaffs_obj, hash_link);
+			parent = obj->parent;
+
+			if (yaffs_has_null_parent(dev, obj)) {
+				/* These directories are not hanging */
+				hanging = 0;
+			} else if (!parent ||
+				   parent->variant_type !=
+				   YAFFS_OBJECT_TYPE_DIRECTORY) {
+				hanging = 1;
+			} else if (yaffs_has_null_parent(dev, parent)) {
+				hanging = 0;
+			} else {
+				/*
+				 * Need to follow the parent chain to
+				 * see if it is hanging.
+				 */
+				hanging = 0;
+				depth_limit = 100;
+
+				while (parent != dev->root_dir &&
+				       parent->parent &&
+				       parent->parent->variant_type ==
+				       YAFFS_OBJECT_TYPE_DIRECTORY &&
+				       depth_limit > 0) {
+					parent = parent->parent;
+					depth_limit--;
+				}
+				if (parent != dev->root_dir)
+					hanging = 1;
+			}
+			if (hanging) {
+				yaffs_trace(YAFFS_TRACE_SCAN,
+					"Hanging object %d moved to lost and found",
+					obj->obj_id);
+				yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+			}
+		}
+	}
+}
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_del_dir_contents(struct yaffs_obj *dir)
+{
+	struct yaffs_obj *obj;
+	struct list_head *lh;
+	struct list_head *n;
+
+	if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+		BUG();
+
+	list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
+		obj = list_entry(lh, struct yaffs_obj, siblings);
+		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+			yaffs_del_dir_contents(obj);
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			"Deleting lost_found object %d",
+			obj->obj_id);
+		yaffs_unlink_obj(obj);
+	}
+}
+
+static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
+{
+	yaffs_del_dir_contents(dev->lost_n_found);
+}
+
+
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
+				     const YCHAR *name)
+{
+	int sum;
+	struct list_head *i;
+	YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
+	struct yaffs_obj *l;
+
+	if (!name)
+		return NULL;
+
+	if (!directory) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: yaffs_find_by_name: null pointer directory"
+			);
+		BUG();
+		return NULL;
+	}
+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: yaffs_find_by_name: non-directory"
+			);
+		BUG();
+	}
+
+	sum = yaffs_calc_name_sum(name);
+
+	list_for_each(i, &directory->variant.dir_variant.children) {
+		l = list_entry(i, struct yaffs_obj, siblings);
+
+		if (l->parent != directory)
+			BUG();
+
+		yaffs_check_obj_details_loaded(l);
+
+		/* Special case for lost-n-found */
+		if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+			if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
+				return l;
+		} else if (l->sum == sum || l->hdr_chunk <= 0) {
+			/* LostnFound chunk called Objxxx
+			 * Do a real check
+			 */
+			yaffs_get_obj_name(l, buffer,
+				YAFFS_MAX_NAME_LENGTH + 1);
+			if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
+				return l;
+		}
+	}
+	return NULL;
+}
+
+/* GetEquivalentObject dereferences any hard links to get to the
+ * actual object.
+ */
+
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
+{
+	if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
+		obj = obj->variant.hardlink_variant.equiv_obj;
+		yaffs_check_obj_details_loaded(obj);
+	}
+	return obj;
+}
+
+/*
+ *  A note or two on object names.
+ *  * If the object name is missing, we then make one up in the form objnnn
+ *
+ *  * ASCII names are stored in the object header's name field from byte zero
+ *  * Unicode names are historically stored starting from byte zero.
+ *
+ * Then there are automatic Unicode names...
+ * The purpose of these is to save names in a way that can be read as
+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
+ * system to share files.
+ *
+ * These automatic unicode are stored slightly differently...
+ *  - If the name can fit in the ASCII character space then they are saved as
+ *    ascii names as per above.
+ *  - If the name needs Unicode then the name is saved in Unicode
+ *    starting at oh->name[1].
+
+ */
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+				int buffer_size)
+{
+	/* Create an object name if we could not find one. */
+	if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
+		YCHAR local_name[20];
+		YCHAR num_string[20];
+		YCHAR *x = &num_string[19];
+		unsigned v = obj->obj_id;
+		num_string[19] = 0;
+		while (v > 0) {
+			x--;
+			*x = '0' + (v % 10);
+			v /= 10;
+		}
+		/* make up a name */
+		strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
+		strcat(local_name, x);
+		strncpy(name, local_name, buffer_size - 1);
+	}
+}
+
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
+{
+	memset(name, 0, buffer_size * sizeof(YCHAR));
+	yaffs_check_obj_details_loaded(obj);
+	if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+		strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
+	} else if (obj->short_name[0]) {
+		strcpy(name, obj->short_name);
+	} else if (obj->hdr_chunk > 0) {
+		int result;
+		u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
+
+		struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
+
+		memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
+
+		if (obj->hdr_chunk > 0) {
+			result = yaffs_rd_chunk_tags_nand(obj->my_dev,
+							  obj->hdr_chunk,
+							  buffer, NULL);
+		}
+		yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
+					buffer_size);
+
+		yaffs_release_temp_buffer(obj->my_dev, buffer);
+	}
+
+	yaffs_fix_null_name(obj, name, buffer_size);
+
+	return strnlen(name, YAFFS_MAX_NAME_LENGTH);
+}
+
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
+{
+	/* Dereference any hard linking */
+	obj = yaffs_get_equivalent_obj(obj);
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+		return obj->variant.file_variant.file_size;
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		if (!obj->variant.symlink_variant.alias)
+			return 0;
+		return strnlen(obj->variant.symlink_variant.alias,
+				     YAFFS_MAX_ALIAS_LENGTH);
+	} else {
+		/* Only a directory should drop through to here */
+		return obj->my_dev->data_bytes_per_chunk;
+	}
+}
+
+int yaffs_get_obj_link_count(struct yaffs_obj *obj)
+{
+	int count = 0;
+	struct list_head *i;
+
+	if (!obj->unlinked)
+		count++;	/* the object itself */
+
+	list_for_each(i, &obj->hard_links)
+	    count++;		/* add the hard links; */
+
+	return count;
+}
+
+int yaffs_get_obj_inode(struct yaffs_obj *obj)
+{
+	obj = yaffs_get_equivalent_obj(obj);
+
+	return obj->obj_id;
+}
+
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
+{
+	obj = yaffs_get_equivalent_obj(obj);
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		return DT_REG;
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		return DT_DIR;
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		return DT_LNK;
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		return DT_REG;
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		if (S_ISFIFO(obj->yst_mode))
+			return DT_FIFO;
+		if (S_ISCHR(obj->yst_mode))
+			return DT_CHR;
+		if (S_ISBLK(obj->yst_mode))
+			return DT_BLK;
+		if (S_ISSOCK(obj->yst_mode))
+			return DT_SOCK;
+		return DT_REG;
+		break;
+	default:
+		return DT_REG;
+		break;
+	}
+}
+
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
+{
+	obj = yaffs_get_equivalent_obj(obj);
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+		return yaffs_clone_str(obj->variant.symlink_variant.alias);
+	else
+		return yaffs_clone_str(_Y(""));
+}
+
+/*--------------------------- Initialisation code -------------------------- */
+
+static int yaffs_check_dev_fns(struct yaffs_dev *dev)
+{
+	struct yaffs_driver *drv = &dev->drv;
+	struct yaffs_tags_handler *tagger = &dev->tagger;
+
+	/* Common functions, gotta have */
+	if (!drv->drv_read_chunk_fn ||
+	    !drv->drv_write_chunk_fn ||
+	    !drv->drv_erase_fn)
+		return 0;
+
+	if (dev->param.is_yaffs2 &&
+	     (!drv->drv_mark_bad_fn  || !drv->drv_check_bad_fn))
+		return 0;
+
+	/* Install the default tags marshalling functions if needed. */
+	yaffs_tags_compat_install(dev);
+	yaffs_tags_marshall_install(dev);
+
+	/* Check we now have the marshalling functions required. */
+	if (!tagger->write_chunk_tags_fn ||
+	    !tagger->read_chunk_tags_fn ||
+	    !tagger->query_block_fn ||
+	    !tagger->mark_bad_fn)
+		return 0;
+
+	return 1;
+}
+
+static int yaffs_create_initial_dir(struct yaffs_dev *dev)
+{
+	/* Initialise the unlinked, deleted, root and lost+found directories */
+	dev->lost_n_found = dev->root_dir = NULL;
+	dev->unlinked_dir = dev->del_dir = NULL;
+	dev->unlinked_dir =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+	dev->del_dir =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
+	dev->root_dir =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
+				  YAFFS_ROOT_MODE | S_IFDIR);
+	dev->lost_n_found =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
+				  YAFFS_LOSTNFOUND_MODE | S_IFDIR);
+
+	if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
+	    && dev->del_dir) {
+		yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
+		return YAFFS_OK;
+	}
+	return YAFFS_FAIL;
+}
+
+/* Low level init.
+ * Typically only used by yaffs_guts_initialise, but also used by the
+ * Low level yaffs driver tests.
+ */
+
+int yaffs_guts_ll_init(struct yaffs_dev *dev)
+{
+
+
+	yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
+
+	if (!dev) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"yaffs: Need a device"
+			);
+		return YAFFS_FAIL;
+	}
+
+	if (dev->ll_init)
+		return YAFFS_OK;
+
+	dev->internal_start_block = dev->param.start_block;
+	dev->internal_end_block = dev->param.end_block;
+	dev->block_offset = 0;
+	dev->chunk_offset = 0;
+	dev->n_free_chunks = 0;
+
+	dev->gc_block = 0;
+
+	if (dev->param.start_block == 0) {
+		dev->internal_start_block = dev->param.start_block + 1;
+		dev->internal_end_block = dev->param.end_block + 1;
+		dev->block_offset = 1;
+		dev->chunk_offset = dev->param.chunks_per_block;
+	}
+
+	/* Check geometry parameters. */
+
+	if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
+		dev->param.total_bytes_per_chunk < 1024) ||
+		(!dev->param.is_yaffs2 &&
+			dev->param.total_bytes_per_chunk < 512) ||
+		(dev->param.inband_tags && !dev->param.is_yaffs2) ||
+		 dev->param.chunks_per_block < 2 ||
+		 dev->param.n_reserved_blocks < 2 ||
+		dev->internal_start_block <= 0 ||
+		dev->internal_end_block <= 0 ||
+		dev->internal_end_block <=
+		(dev->internal_start_block + dev->param.n_reserved_blocks + 2)
+		) {
+		/* otherwise it is too small */
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
+			dev->param.total_bytes_per_chunk,
+			dev->param.is_yaffs2 ? "2" : "",
+			dev->param.inband_tags);
+		return YAFFS_FAIL;
+	}
+
+	/* Sort out space for inband tags, if required */
+	if (dev->param.inband_tags)
+		dev->data_bytes_per_chunk =
+		    dev->param.total_bytes_per_chunk -
+		    sizeof(struct yaffs_packed_tags2_tags_only);
+	else
+		dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
+
+	/* Got the right mix of functions? */
+	if (!yaffs_check_dev_fns(dev)) {
+		/* Function missing */
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"device function(s) missing or wrong");
+
+		return YAFFS_FAIL;
+	}
+
+	if (yaffs_init_nand(dev) != YAFFS_OK) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
+		return YAFFS_FAIL;
+	}
+
+	return YAFFS_OK;
+}
+
+
+int yaffs_guts_format_dev(struct yaffs_dev *dev)
+{
+	int i;
+	enum yaffs_block_state state;
+	u32 dummy;
+
+	if(yaffs_guts_ll_init(dev) != YAFFS_OK)
+		return YAFFS_FAIL;
+
+	if(dev->is_mounted)
+		return YAFFS_FAIL;
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		yaffs_query_init_block_state(dev, i, &state, &dummy);
+		if (state != YAFFS_BLOCK_STATE_DEAD)
+			yaffs_erase_block(dev, i);
+	}
+
+	return YAFFS_OK;
+}
+
+
+int yaffs_guts_initialise(struct yaffs_dev *dev)
+{
+	int init_failed = 0;
+	unsigned x;
+	int bits;
+
+	if(yaffs_guts_ll_init(dev) != YAFFS_OK)
+		return YAFFS_FAIL;
+
+	if (dev->is_mounted) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
+		return YAFFS_FAIL;
+	}
+
+	dev->is_mounted = 1;
+
+	/* OK now calculate a few things for the device */
+
+	/*
+	 *  Calculate all the chunk size manipulation numbers:
+	 */
+	x = dev->data_bytes_per_chunk;
+	/* We always use dev->chunk_shift and dev->chunk_div */
+	dev->chunk_shift = calc_shifts(x);
+	x >>= dev->chunk_shift;
+	dev->chunk_div = x;
+	/* We only use chunk mask if chunk_div is 1 */
+	dev->chunk_mask = (1 << dev->chunk_shift) - 1;
+
+	/*
+	 * Calculate chunk_grp_bits.
+	 * We need to find the next power of 2 > than internal_end_block
+	 */
+
+	x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
+
+	bits = calc_shifts_ceiling(x);
+
+	/* Set up tnode width if wide tnodes are enabled. */
+	if (!dev->param.wide_tnodes_disabled) {
+		/* bits must be even so that we end up with 32-bit words */
+		if (bits & 1)
+			bits++;
+		if (bits < 16)
+			dev->tnode_width = 16;
+		else
+			dev->tnode_width = bits;
+	} else {
+		dev->tnode_width = 16;
+	}
+
+	dev->tnode_mask = (1 << dev->tnode_width) - 1;
+
+	/* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
+	 * so if the bitwidth of the
+	 * chunk range we're using is greater than 16 we need
+	 * to figure out chunk shift and chunk_grp_size
+	 */
+
+	if (bits <= dev->tnode_width)
+		dev->chunk_grp_bits = 0;
+	else
+		dev->chunk_grp_bits = bits - dev->tnode_width;
+
+	dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
+	if (dev->tnode_size < sizeof(struct yaffs_tnode))
+		dev->tnode_size = sizeof(struct yaffs_tnode);
+
+	dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
+
+	if (dev->param.chunks_per_block < dev->chunk_grp_size) {
+		/* We have a problem because the soft delete won't work if
+		 * the chunk group size > chunks per block.
+		 * This can be remedied by using larger "virtual blocks".
+		 */
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
+
+		return YAFFS_FAIL;
+	}
+
+	/* Finished verifying the device, continue with initialisation */
+
+	/* More device initialisation */
+	dev->all_gcs = 0;
+	dev->passive_gc_count = 0;
+	dev->oldest_dirty_gc_count = 0;
+	dev->bg_gcs = 0;
+	dev->gc_block_finder = 0;
+	dev->buffered_block = -1;
+	dev->doing_buffered_block_rewrite = 0;
+	dev->n_deleted_files = 0;
+	dev->n_bg_deletions = 0;
+	dev->n_unlinked_files = 0;
+	dev->n_ecc_fixed = 0;
+	dev->n_ecc_unfixed = 0;
+	dev->n_tags_ecc_fixed = 0;
+	dev->n_tags_ecc_unfixed = 0;
+	dev->n_erase_failures = 0;
+	dev->n_erased_blocks = 0;
+	dev->gc_disable = 0;
+	dev->has_pending_prioritised_gc = 1;
+		/* Assume the worst for now, will get fixed on first GC */
+	INIT_LIST_HEAD(&dev->dirty_dirs);
+	dev->oldest_dirty_seq = 0;
+	dev->oldest_dirty_block = 0;
+
+	/* Initialise temporary buffers and caches. */
+	if (!yaffs_init_tmp_buffers(dev))
+		init_failed = 1;
+
+	dev->cache = NULL;
+	dev->gc_cleanup_list = NULL;
+
+	if (!init_failed && dev->param.n_caches > 0) {
+		int i;
+		void *buf;
+		int cache_bytes =
+		    dev->param.n_caches * sizeof(struct yaffs_cache);
+
+		if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
+			dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
+
+		dev->cache = kmalloc(cache_bytes, GFP_NOFS);
+
+		buf = (u8 *) dev->cache;
+
+		if (dev->cache)
+			memset(dev->cache, 0, cache_bytes);
+
+		for (i = 0; i < dev->param.n_caches && buf; i++) {
+			dev->cache[i].object = NULL;
+			dev->cache[i].last_use = 0;
+			dev->cache[i].dirty = 0;
+			dev->cache[i].data = buf =
+			    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+		}
+		if (!buf)
+			init_failed = 1;
+
+		dev->cache_last_use = 0;
+	}
+
+	dev->cache_hits = 0;
+
+	if (!init_failed) {
+		dev->gc_cleanup_list =
+		    kmalloc(dev->param.chunks_per_block * sizeof(u32),
+					GFP_NOFS);
+		if (!dev->gc_cleanup_list)
+			init_failed = 1;
+	}
+
+	if (dev->param.is_yaffs2)
+		dev->param.use_header_file_size = 1;
+
+	if (!init_failed && !yaffs_init_blocks(dev))
+		init_failed = 1;
+
+	yaffs_init_tnodes_and_objs(dev);
+
+	if (!init_failed && !yaffs_create_initial_dir(dev))
+		init_failed = 1;
+
+	if (!init_failed && dev->param.is_yaffs2 &&
+		!dev->param.disable_summary &&
+		!yaffs_summary_init(dev))
+		init_failed = 1;
+
+	if (!init_failed) {
+		/* Now scan the flash. */
+		if (dev->param.is_yaffs2) {
+			if (yaffs2_checkpt_restore(dev)) {
+				yaffs_check_obj_details_loaded(dev->root_dir);
+				yaffs_trace(YAFFS_TRACE_CHECKPOINT |
+					YAFFS_TRACE_MOUNT,
+					"yaffs: restored from checkpoint"
+					);
+			} else {
+
+				/* Clean up the mess caused by an aborted
+				 * checkpoint load then scan backwards.
+				 */
+				yaffs_deinit_blocks(dev);
+
+				yaffs_deinit_tnodes_and_objs(dev);
+
+				dev->n_erased_blocks = 0;
+				dev->n_free_chunks = 0;
+				dev->alloc_block = -1;
+				dev->alloc_page = -1;
+				dev->n_deleted_files = 0;
+				dev->n_unlinked_files = 0;
+				dev->n_bg_deletions = 0;
+
+				if (!init_failed && !yaffs_init_blocks(dev))
+					init_failed = 1;
+
+				yaffs_init_tnodes_and_objs(dev);
+
+				if (!init_failed
+				    && !yaffs_create_initial_dir(dev))
+					init_failed = 1;
+
+				if (!init_failed && !yaffs2_scan_backwards(dev))
+					init_failed = 1;
+			}
+		} else if (!yaffs1_scan(dev)) {
+			init_failed = 1;
+		}
+
+		yaffs_strip_deleted_objs(dev);
+		yaffs_fix_hanging_objs(dev);
+		if (dev->param.empty_lost_n_found)
+			yaffs_empty_l_n_f(dev);
+	}
+
+	if (init_failed) {
+		/* Clean up the mess */
+		yaffs_trace(YAFFS_TRACE_TRACING,
+		  "yaffs: yaffs_guts_initialise() aborted.");
+
+		yaffs_deinitialise(dev);
+		return YAFFS_FAIL;
+	}
+
+	/* Zero out stats */
+	dev->n_page_reads = 0;
+	dev->n_page_writes = 0;
+	dev->n_erasures = 0;
+	dev->n_gc_copies = 0;
+	dev->n_retried_writes = 0;
+
+	dev->n_retired_blocks = 0;
+
+	yaffs_verify_free_chunks(dev);
+	yaffs_verify_blocks(dev);
+
+	/* Clean up any aborted checkpoint data */
+	if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
+		yaffs2_checkpt_invalidate(dev);
+
+	yaffs_trace(YAFFS_TRACE_TRACING,
+	  "yaffs: yaffs_guts_initialise() done.");
+	return YAFFS_OK;
+}
+
+void yaffs_deinitialise(struct yaffs_dev *dev)
+{
+	if (dev->is_mounted) {
+		int i;
+
+		yaffs_deinit_blocks(dev);
+		yaffs_deinit_tnodes_and_objs(dev);
+		yaffs_summary_deinit(dev);
+
+		if (dev->param.n_caches > 0 && dev->cache) {
+
+			for (i = 0; i < dev->param.n_caches; i++) {
+				kfree(dev->cache[i].data);
+				dev->cache[i].data = NULL;
+			}
+
+			kfree(dev->cache);
+			dev->cache = NULL;
+		}
+
+		kfree(dev->gc_cleanup_list);
+
+		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+			kfree(dev->temp_buffer[i].buffer);
+			dev->temp_buffer[i].buffer = NULL;
+		}
+
+		kfree(dev->checkpt_buffer);
+		dev->checkpt_buffer = NULL;
+		kfree(dev->checkpt_block_list);
+		dev->checkpt_block_list = NULL;
+
+		dev->is_mounted = 0;
+
+		yaffs_deinit_nand(dev);
+	}
+}
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev)
+{
+	int n_free = 0;
+	int b;
+	struct yaffs_block_info *blk;
+
+	blk = dev->block_info;
+	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
+		switch (blk->block_state) {
+		case YAFFS_BLOCK_STATE_EMPTY:
+		case YAFFS_BLOCK_STATE_ALLOCATING:
+		case YAFFS_BLOCK_STATE_COLLECTING:
+		case YAFFS_BLOCK_STATE_FULL:
+			n_free +=
+			    (dev->param.chunks_per_block - blk->pages_in_use +
+			     blk->soft_del_pages);
+			break;
+		default:
+			break;
+		}
+		blk++;
+	}
+	return n_free;
+}
+
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
+{
+	/* This is what we report to the outside world */
+	int n_free;
+	int n_dirty_caches;
+	int blocks_for_checkpt;
+	int i;
+
+	n_free = dev->n_free_chunks;
+	n_free += dev->n_deleted_files;
+
+	/* Now count and subtract the number of dirty chunks in the cache. */
+
+	for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
+		if (dev->cache[i].dirty)
+			n_dirty_caches++;
+	}
+
+	n_free -= n_dirty_caches;
+
+	n_free -=
+	    ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
+
+	/* Now figure checkpoint space and report that... */
+	blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
+
+	n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
+
+	if (n_free < 0)
+		n_free = 0;
+
+	return n_free;
+}
+
+
+
+/*
+ * Marshalling functions to get loff_t file sizes into and out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
+{
+	oh->file_size_low = (fsize & 0xFFFFFFFF);
+	oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
+}
+
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
+{
+	loff_t retval;
+
+	if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
+		retval = (((loff_t) oh->file_size_high) << 32) |
+			(((loff_t) oh->file_size_low) & 0xFFFFFFFF);
+	else
+		retval = (loff_t) oh->file_size_low;
+
+	return retval;
+}
+
+
+void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
+{
+	int i;
+	struct yaffs_block_info *bi;
+	int s;
+
+	for(i = 0; i < 10; i++)
+		bs[i] = 0;
+
+	for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		bi = yaffs_get_block_info(dev, i);
+		s = bi->block_state;
+		if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
+			bs[0]++;
+		else
+			bs[s]++;
+	}
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.h b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h
new file mode 100644
index 0000000000..231f8ac567
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h
@@ -0,0 +1,1010 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GUTS_H__
+#define __YAFFS_GUTS_H__
+
+#include "yportenv.h"
+
+#define YAFFS_OK	1
+#define YAFFS_FAIL  0
+
+/* Give us a  Y=0x59,
+ * Give us an A=0x41,
+ * Give us an FF=0xff
+ * Give us an S=0x53
+ * And what have we got...
+ */
+#define YAFFS_MAGIC			0x5941ff53
+
+/*
+ * Tnodes form a tree with the tnodes in "levels"
+ * Levels greater than 0 hold 8 slots which point to other tnodes.
+ * Those at level 0 hold 16 slots which point to chunks in NAND.
+ *
+ * A maximum level of 8 thust supports files of size up to:
+ *
+ * 2^(3*MAX_LEVEL+4)
+ *
+ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
+ * a maximum file size of around 512Gbytees with 2k chunks.
+ */
+#define YAFFS_NTNODES_LEVEL0		16
+#define YAFFS_TNODES_LEVEL0_BITS	4
+#define YAFFS_TNODES_LEVEL0_MASK	0xf
+
+#define YAFFS_NTNODES_INTERNAL		(YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS	(YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_TNODES_INTERNAL_MASK	0x7
+#define YAFFS_TNODES_MAX_LEVEL		8
+#define YAFFS_TNODES_MAX_BITS		(YAFFS_TNODES_LEVEL0_BITS + \
+					YAFFS_TNODES_INTERNAL_BITS * \
+					YAFFS_TNODES_MAX_LEVEL)
+#define YAFFS_MAX_CHUNK_ID		((1 << YAFFS_TNODES_MAX_BITS) - 1)
+
+#define YAFFS_MAX_FILE_SIZE_32		0x7fffffff
+
+/* Constants for YAFFS1 mode */
+#define YAFFS_BYTES_PER_SPARE		16
+#define YAFFS_BYTES_PER_CHUNK		512
+#define YAFFS_CHUNK_SIZE_SHIFT		9
+#define YAFFS_CHUNKS_PER_BLOCK		32
+#define YAFFS_BYTES_PER_BLOCK	(YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
+
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE	1024
+#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32
+
+
+
+#define YAFFS_ALLOCATION_NOBJECTS	100
+#define YAFFS_ALLOCATION_NTNODES	100
+#define YAFFS_ALLOCATION_NLINKS		100
+
+#define YAFFS_NOBJECT_BUCKETS		256
+
+#define YAFFS_OBJECT_SPACE		0x40000
+#define YAFFS_MAX_OBJECT_ID		(YAFFS_OBJECT_SPACE - 1)
+
+/* Binary data version stamps */
+#define YAFFS_SUMMARY_VERSION		1
+#define YAFFS_CHECKPOINT_VERSION	7
+
+#ifdef CONFIG_YAFFS_UNICODE
+#define YAFFS_MAX_NAME_LENGTH		127
+#define YAFFS_MAX_ALIAS_LENGTH		79
+#else
+#define YAFFS_MAX_NAME_LENGTH		255
+#define YAFFS_MAX_ALIAS_LENGTH		159
+#endif
+
+#define YAFFS_SHORT_NAME_LENGTH		15
+
+/* Some special object ids for pseudo objects */
+#define YAFFS_OBJECTID_ROOT		1
+#define YAFFS_OBJECTID_LOSTNFOUND	2
+#define YAFFS_OBJECTID_UNLINKED		3
+#define YAFFS_OBJECTID_DELETED		4
+
+/* Fake object Id for summary data */
+#define YAFFS_OBJECTID_SUMMARY		0x10
+
+/* Pseudo object ids for checkpointing */
+#define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA	0x21
+
+#define YAFFS_MAX_SHORT_OP_CACHES	20
+
+#define YAFFS_N_TEMP_BUFFERS		6
+
+/* We limit the number attempts at sucessfully saving a chunk of data.
+ * Small-page devices have 32 pages per block; large-page devices have 64.
+ * Default to something in the order of 5 to 10 blocks worth of chunks.
+ */
+#define YAFFS_WR_ATTEMPTS		(5*64)
+
+/* Sequence numbers are used in YAFFS2 to determine block allocation order.
+ * The range is limited slightly to help distinguish bad numbers from good.
+ * This also allows us to perhaps in the future use special numbers for
+ * special purposes.
+ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
+ * and is a larger number than the lifetime of a 2GB device.
+ */
+#define YAFFS_LOWEST_SEQUENCE_NUMBER	0x00001000
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER	0xefffff00
+
+/* Special sequence number for bad block that failed to be marked bad */
+#define YAFFS_SEQUENCE_BAD_BLOCK	0xffff0000
+
+/* ChunkCache is used for short read/write operations.*/
+struct yaffs_cache {
+	struct yaffs_obj *object;
+	int chunk_id;
+	int last_use;
+	int dirty;
+	int n_bytes;		/* Only valid if the cache is dirty */
+	int locked;		/* Can't push out or flush while locked. */
+	u8 *data;
+};
+
+/* yaffs1 tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
+ * otherwise the structure size will get blown out.
+ */
+
+struct yaffs_tags {
+	u32 chunk_id:20;
+	u32 serial_number:2;
+	u32 n_bytes_lsb:10;
+	u32 obj_id:18;
+	u32 ecc:12;
+	u32 n_bytes_msb:2;
+};
+
+union yaffs_tags_union {
+	struct yaffs_tags as_tags;
+	u8 as_bytes[8];
+};
+
+
+/* Stuff used for extended tags in YAFFS2 */
+
+enum yaffs_ecc_result {
+	YAFFS_ECC_RESULT_UNKNOWN,
+	YAFFS_ECC_RESULT_NO_ERROR,
+	YAFFS_ECC_RESULT_FIXED,
+	YAFFS_ECC_RESULT_UNFIXED
+};
+
+enum yaffs_obj_type {
+	YAFFS_OBJECT_TYPE_UNKNOWN,
+	YAFFS_OBJECT_TYPE_FILE,
+	YAFFS_OBJECT_TYPE_SYMLINK,
+	YAFFS_OBJECT_TYPE_DIRECTORY,
+	YAFFS_OBJECT_TYPE_HARDLINK,
+	YAFFS_OBJECT_TYPE_SPECIAL
+};
+
+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
+
+struct yaffs_ext_tags {
+	unsigned chunk_used;	/*  Status of the chunk: used or unused */
+	unsigned obj_id;	/* If 0 this is not used */
+	unsigned chunk_id;	/* If 0 this is a header, else a data chunk */
+	unsigned n_bytes;	/* Only valid for data chunks */
+
+	/* The following stuff only has meaning when we read */
+	enum yaffs_ecc_result ecc_result;
+	unsigned block_bad;
+
+	/* YAFFS 1 stuff */
+	unsigned is_deleted;	/* The chunk is marked deleted */
+	unsigned serial_number;	/* Yaffs1 2-bit serial number */
+
+	/* YAFFS2 stuff */
+	unsigned seq_number;	/* The sequence number of this block */
+
+	/* Extra info if this is an object header (YAFFS2 only) */
+
+	unsigned extra_available;	/* Extra info available if not zero */
+	unsigned extra_parent_id;	/* The parent object */
+	unsigned extra_is_shrink;	/* Is it a shrink header? */
+	unsigned extra_shadows;	/* Does this shadow another object? */
+
+	enum yaffs_obj_type extra_obj_type;	/* What object type? */
+
+	loff_t extra_file_size;		/* Length if it is a file */
+	unsigned extra_equiv_id;	/* Equivalent object for a hard link */
+};
+
+/* Spare structure for YAFFS1 */
+struct yaffs_spare {
+	u8 tb0;
+	u8 tb1;
+	u8 tb2;
+	u8 tb3;
+	u8 page_status;		/* set to 0 to delete the chunk */
+	u8 block_status;
+	u8 tb4;
+	u8 tb5;
+	u8 ecc1[3];
+	u8 tb6;
+	u8 tb7;
+	u8 ecc2[3];
+};
+
+/*Special structure for passing through to mtd */
+struct yaffs_nand_spare {
+	struct yaffs_spare spare;
+	int eccres1;
+	int eccres2;
+};
+
+/* Block data in RAM */
+
+enum yaffs_block_state {
+	YAFFS_BLOCK_STATE_UNKNOWN = 0,
+
+	YAFFS_BLOCK_STATE_SCANNING,
+	/* Being scanned */
+
+	YAFFS_BLOCK_STATE_NEEDS_SCAN,
+	/* The block might have something on it (ie it is allocating or full,
+	 * perhaps empty) but it needs to be scanned to determine its true
+	 * state.
+	 * This state is only valid during scanning.
+	 * NB We tolerate empty because the pre-scanner might be incapable of
+	 * deciding
+	 * However, if this state is returned on a YAFFS2 device,
+	 * then we expect a sequence number
+	 */
+
+	YAFFS_BLOCK_STATE_EMPTY,
+	/* This block is empty */
+
+	YAFFS_BLOCK_STATE_ALLOCATING,
+	/* This block is partially allocated.
+	 * At least one page holds valid data.
+	 * This is the one currently being used for page
+	 * allocation. Should never be more than one of these.
+	 * If a block is only partially allocated at mount it is treated as
+	 * full.
+	 */
+
+	YAFFS_BLOCK_STATE_FULL,
+	/* All the pages in this block have been allocated.
+	 * If a block was only partially allocated when mounted we treat
+	 * it as fully allocated.
+	 */
+
+	YAFFS_BLOCK_STATE_DIRTY,
+	/* The block was full and now all chunks have been deleted.
+	 * Erase me, reuse me.
+	 */
+
+	YAFFS_BLOCK_STATE_CHECKPOINT,
+	/* This block is assigned to holding checkpoint data. */
+
+	YAFFS_BLOCK_STATE_COLLECTING,
+	/* This block is being garbage collected */
+
+	YAFFS_BLOCK_STATE_DEAD
+	    /* This block has failed and is not in use */
+};
+
+#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
+
+struct yaffs_block_info {
+
+	s32 soft_del_pages:10;	/* number of soft deleted pages */
+	s32 pages_in_use:10;	/* number of pages in use */
+	u32 block_state:4;	/* One of the above block states. */
+				/* NB use unsigned because enum is sometimes
+				 * an int */
+	u32 needs_retiring:1;	/* Data has failed on this block, */
+				/*need to get valid data off and retire*/
+	u32 skip_erased_check:1;/* Skip the erased check on this block */
+	u32 gc_prioritise:1;	/* An ECC check or blank check has failed.
+				   Block should be prioritised for GC */
+	u32 chunk_error_strikes:3;	/* How many times we've had ecc etc
+				failures on this block and tried to reuse it */
+	u32 has_summary:1;	/* The block has a summary */
+
+	u32 has_shrink_hdr:1;	/* This block has at least one shrink header */
+	u32 seq_number;		/* block sequence number for yaffs2 */
+
+};
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+struct yaffs_obj_hdr {
+	enum yaffs_obj_type type;
+
+	/* Apply to everything  */
+	int parent_obj_id;
+	u16 sum_no_longer_used;	/* checksum of name. No longer used */
+	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+	/* The following apply to all object types except for hard links */
+	u32 yst_mode;		/* protection */
+
+	u32 yst_uid;
+	u32 yst_gid;
+	u32 yst_atime;
+	u32 yst_mtime;
+	u32 yst_ctime;
+
+	/* File size  applies to files only */
+	u32 file_size_low;
+
+	/* Equivalent object id applies to hard links only. */
+	int equiv_id;
+
+	/* Alias is for symlinks only. */
+	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+	u32 yst_rdev;	/* stuff for block and char devices (major/min) */
+
+	u32 win_ctime[2];
+	u32 win_atime[2];
+	u32 win_mtime[2];
+
+	u32 inband_shadowed_obj_id;
+	u32 inband_is_shrink;
+
+	u32 file_size_high;
+	u32 reserved[1];
+	int shadows_obj;	/* This object header shadows the
+				specified object if > 0 */
+
+	/* is_shrink applies to object headers written when wemake a hole. */
+	u32 is_shrink;
+
+};
+
+/*--------------------------- Tnode -------------------------- */
+
+struct yaffs_tnode {
+	struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
+};
+
+/*------------------------  Object -----------------------------*/
+/* An object can be one of:
+ * - a directory (no data, has children links
+ * - a regular file (data.... not prunes :->).
+ * - a symlink [symbolic link] (the alias).
+ * - a hard link
+ */
+
+struct yaffs_file_var {
+	loff_t file_size;
+	loff_t scanned_size;
+	loff_t shrink_size;
+	int top_level;
+	struct yaffs_tnode *top;
+};
+
+struct yaffs_dir_var {
+	struct list_head children;	/* list of child links */
+	struct list_head dirty;	/* Entry for list of dirty directories */
+};
+
+struct yaffs_symlink_var {
+	YCHAR *alias;
+};
+
+struct yaffs_hardlink_var {
+	struct yaffs_obj *equiv_obj;
+	u32 equiv_id;
+};
+
+union yaffs_obj_var {
+	struct yaffs_file_var file_variant;
+	struct yaffs_dir_var dir_variant;
+	struct yaffs_symlink_var symlink_variant;
+	struct yaffs_hardlink_var hardlink_variant;
+};
+
+struct yaffs_obj {
+	u8 deleted:1;		/* This should only apply to unlinked files. */
+	u8 soft_del:1;		/* it has also been soft deleted */
+	u8 unlinked:1;		/* An unlinked file.*/
+	u8 fake:1;		/* A fake object has no presence on NAND. */
+	u8 rename_allowed:1;	/* Some objects cannot be renamed. */
+	u8 unlink_allowed:1;
+	u8 dirty:1;		/* the object needs to be written to flash */
+	u8 valid:1;		/* When the file system is being loaded up, this
+				 * object might be created before the data
+				 * is available
+				 * ie. file data chunks encountered before
+				* the header.
+				 */
+	u8 lazy_loaded:1;	/* This object has been lazy loaded and
+				 * is missing some detail */
+
+	u8 defered_free:1;	/* Object is removed from NAND, but is
+				 * still in the inode cache.
+				 * Free of object is defered.
+				 * until the inode is released.
+				 */
+	u8 being_created:1;	/* This object is still being created
+				 * so skip some verification checks. */
+	u8 is_shadowed:1;	/* This object is shadowed on the way
+				 * to being renamed. */
+
+	u8 xattr_known:1;	/* We know if this has object has xattribs
+				 * or not. */
+	u8 has_xattr:1;		/* This object has xattribs.
+				 * Only valid if xattr_known. */
+
+	u8 serial;		/* serial number of chunk in NAND.*/
+	u16 sum;		/* sum of the name to speed searching */
+
+	struct yaffs_dev *my_dev;	/* The device I'm on */
+
+	struct list_head hash_link;	/* list of objects in hash bucket */
+
+	struct list_head hard_links;	/* hard linked object chain*/
+
+	/* directory structure stuff */
+	/* also used for linking up the free list */
+	struct yaffs_obj *parent;
+	struct list_head siblings;
+
+	/* Where's my object header in NAND? */
+	int hdr_chunk;
+
+	int n_data_chunks;	/* Number of data chunks for this file. */
+
+	u32 obj_id;		/* the object id value */
+
+	u32 yst_mode;
+
+	YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
+
+#ifdef CONFIG_YAFFS_WINCE
+	u32 win_ctime[2];
+	u32 win_mtime[2];
+	u32 win_atime[2];
+#else
+	u32 yst_uid;
+	u32 yst_gid;
+	u32 yst_atime;
+	u32 yst_mtime;
+	u32 yst_ctime;
+#endif
+
+	u32 yst_rdev;
+
+	void *my_inode;
+
+	enum yaffs_obj_type variant_type;
+
+	union yaffs_obj_var variant;
+
+};
+
+struct yaffs_obj_bucket {
+	struct list_head list;
+	int count;
+};
+
+/* yaffs_checkpt_obj holds the definition of an object as dumped
+ * by checkpointing.
+ */
+
+struct yaffs_checkpt_obj {
+	int struct_type;
+	u32 obj_id;
+	u32 parent_id;
+	int hdr_chunk;
+	enum yaffs_obj_type variant_type:3;
+	u8 deleted:1;
+	u8 soft_del:1;
+	u8 unlinked:1;
+	u8 fake:1;
+	u8 rename_allowed:1;
+	u8 unlink_allowed:1;
+	u8 serial;
+	int n_data_chunks;
+	loff_t size_or_equiv_obj;
+};
+
+/*--------------------- Temporary buffers ----------------
+ *
+ * These are chunk-sized working buffers. Each device has a few.
+ */
+
+struct yaffs_buffer {
+	u8 *buffer;
+	int in_use;
+};
+
+/*----------------- Device ---------------------------------*/
+
+struct yaffs_param {
+	const YCHAR *name;
+
+	/*
+	 * Entry parameters set up way early. Yaffs sets up the rest.
+	 * The structure should be zeroed out before use so that unused
+	 * and default values are zero.
+	 */
+
+	int inband_tags;	/* Use unband tags */
+	u32 total_bytes_per_chunk;	/* Should be >= 512, does not need to
+					 be a power of 2 */
+	int chunks_per_block;	/* does not need to be a power of 2 */
+	int spare_bytes_per_chunk;	/* spare area size */
+	int start_block;	/* Start block we're allowed to use */
+	int end_block;		/* End block we're allowed to use */
+	int n_reserved_blocks;	/* Tuneable so that we can reduce
+				 * reserved blocks on NOR and RAM. */
+
+	int n_caches;		/* If <= 0, then short op caching is disabled,
+				 * else the number of short op caches.
+				 */
+	int cache_bypass_aligned; /* If non-zero then bypass the cache for
+				   * aligned writes.
+				   */
+
+	int use_nand_ecc;	/* Flag to decide whether or not to use
+				 * NAND driver ECC on data (yaffs1) */
+	int tags_9bytes;	/* Use 9 byte tags */
+	int no_tags_ecc;	/* Flag to decide whether or not to do ECC
+				 * on packed tags (yaffs2) */
+
+	int is_yaffs2;		/* Use yaffs2 mode on this device */
+
+	int empty_lost_n_found;	/* Auto-empty lost+found directory on mount */
+
+	int refresh_period;	/* How often to check for a block refresh */
+
+	/* Checkpoint control. Can be set before or after initialisation */
+	u8 skip_checkpt_rd;
+	u8 skip_checkpt_wr;
+
+	int enable_xattr;	/* Enable xattribs */
+
+	int max_objects;	/*
+				 * Set to limit the number of objects created.
+				 * 0 = no limit.
+				*/
+
+	/* The remove_obj_fn function must be supplied by OS flavours that
+	 * need it.
+	 * yaffs direct uses it to implement the faster readdir.
+	 * Linux uses it to protect the directory during unlocking.
+	 */
+	void (*remove_obj_fn) (struct yaffs_obj *obj);
+
+	/* Callback to mark the superblock dirty */
+	void (*sb_dirty_fn) (struct yaffs_dev *dev);
+
+	/*  Callback to control garbage collection. */
+	unsigned (*gc_control_fn) (struct yaffs_dev *dev);
+
+	/* Debug control flags. Don't use unless you know what you're doing */
+	int use_header_file_size;	/* Flag to determine if we should use
+					 * file sizes from the header */
+	int disable_lazy_load;	/* Disable lazy loading on this device */
+	int wide_tnodes_disabled;	/* Set to disable wide tnodes */
+	int disable_soft_del;	/* yaffs 1 only: Set to disable the use of
+				 * softdeletion. */
+
+	int defered_dir_update;	/* Set to defer directory updates */
+
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+	int auto_unicode;
+#endif
+	int always_check_erased;	/* Force chunk erased check always on */
+
+	int disable_summary;
+	int disable_bad_block_marking;
+
+};
+
+struct yaffs_driver {
+	int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+				   const u8 *data, int data_len,
+				   const u8 *oob, int oob_len);
+	int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
+				   u8 *data, int data_len,
+				   u8 *oob, int oob_len,
+				   enum yaffs_ecc_result *ecc_result);
+	int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
+	int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+	int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
+	int (*drv_initialise_fn) (struct yaffs_dev *dev);
+	int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
+};
+
+struct yaffs_tags_handler {
+	int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
+				    int nand_chunk, const u8 *data,
+				    const struct yaffs_ext_tags *tags);
+	int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
+				   int nand_chunk, u8 *data,
+				   struct yaffs_ext_tags *tags);
+
+	int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
+			       enum yaffs_block_state *state,
+			       u32 *seq_number);
+	int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
+};
+
+struct yaffs_dev {
+	struct yaffs_param param;
+	struct yaffs_driver drv;
+	struct yaffs_tags_handler tagger;
+
+	/* Context storage. Holds extra OS specific data for this device */
+
+	void *os_context;
+	void *driver_context;
+
+	struct list_head dev_list;
+
+	int ll_init;
+	/* Runtime parameters. Set up by YAFFS. */
+	int data_bytes_per_chunk;
+
+	/* Non-wide tnode stuff */
+	u16 chunk_grp_bits;	/* Number of bits that need to be resolved if
+				 * the tnodes are not wide enough.
+				 */
+	u16 chunk_grp_size;	/* == 2^^chunk_grp_bits */
+
+	/* Stuff to support wide tnodes */
+	u32 tnode_width;
+	u32 tnode_mask;
+	u32 tnode_size;
+
+	/* Stuff for figuring out file offset to chunk conversions */
+	u32 chunk_shift;	/* Shift value */
+	u32 chunk_div;		/* Divisor after shifting: 1 for 2^n sizes */
+	u32 chunk_mask;		/* Mask to use for power-of-2 case */
+
+	int is_mounted;
+	int read_only;
+	int is_checkpointed;
+
+	/* Stuff to support block offsetting to support start block zero */
+	int internal_start_block;
+	int internal_end_block;
+	int block_offset;
+	int chunk_offset;
+
+	/* Runtime checkpointing stuff */
+	int checkpt_page_seq;	/* running sequence number of checkpt pages */
+	int checkpt_byte_count;
+	int checkpt_byte_offs;
+	u8 *checkpt_buffer;
+	int checkpt_open_write;
+	int blocks_in_checkpt;
+	int checkpt_cur_chunk;
+	int checkpt_cur_block;
+	int checkpt_next_block;
+	int *checkpt_block_list;
+	int checkpt_max_blocks;
+	u32 checkpt_sum;
+	u32 checkpt_xor;
+
+	int checkpoint_blocks_required;	/* Number of blocks needed to store
+					 * current checkpoint set */
+
+	/* Block Info */
+	struct yaffs_block_info *block_info;
+	u8 *chunk_bits;		/* bitmap of chunks in use */
+	u8 block_info_alt:1;	/* allocated using alternative alloc */
+	u8 chunk_bits_alt:1;	/* allocated using alternative alloc */
+	int chunk_bit_stride;	/* Number of bytes of chunk_bits per block.
+				 * Must be consistent with chunks_per_block.
+				 */
+
+	int n_erased_blocks;
+	int alloc_block;	/* Current block being allocated off */
+	u32 alloc_page;
+	int alloc_block_finder;	/* Used to search for next allocation block */
+
+	/* Object and Tnode memory management */
+	void *allocator;
+	int n_obj;
+	int n_tnodes;
+
+	int n_hardlinks;
+
+	struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
+	u32 bucket_finder;
+
+	int n_free_chunks;
+
+	/* Garbage collection control */
+	u32 *gc_cleanup_list;	/* objects to delete at the end of a GC. */
+	u32 n_clean_ups;
+
+	unsigned has_pending_prioritised_gc;	/* We think this device might
+						have pending prioritised gcs */
+	unsigned gc_disable;
+	unsigned gc_block_finder;
+	unsigned gc_dirtiest;
+	unsigned gc_pages_in_use;
+	unsigned gc_not_done;
+	unsigned gc_block;
+	unsigned gc_chunk;
+	unsigned gc_skip;
+	struct yaffs_summary_tags *gc_sum_tags;
+
+	/* Special directories */
+	struct yaffs_obj *root_dir;
+	struct yaffs_obj *lost_n_found;
+
+	int buffered_block;	/* Which block is buffered here? */
+	int doing_buffered_block_rewrite;
+
+	struct yaffs_cache *cache;
+	int cache_last_use;
+
+	/* Stuff for background deletion and unlinked files. */
+	struct yaffs_obj *unlinked_dir;	/* Directory where unlinked and deleted
+					 files live. */
+	struct yaffs_obj *del_dir;	/* Directory where deleted objects are
+					sent to disappear. */
+	struct yaffs_obj *unlinked_deletion;	/* Current file being
+							background deleted. */
+	int n_deleted_files;	/* Count of files awaiting deletion; */
+	int n_unlinked_files;	/* Count of unlinked files. */
+	int n_bg_deletions;	/* Count of background deletions. */
+
+	/* Temporary buffer management */
+	struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
+	int max_temp;
+	int temp_in_use;
+	int unmanaged_buffer_allocs;
+	int unmanaged_buffer_deallocs;
+
+	/* yaffs2 runtime stuff */
+	unsigned seq_number;	/* Sequence number of currently
+					allocating block */
+	unsigned oldest_dirty_seq;
+	unsigned oldest_dirty_block;
+
+	/* Block refreshing */
+	int refresh_skip;	/* A skip down counter.
+				 * Refresh happens when this gets to zero. */
+
+	/* Dirty directory handling */
+	struct list_head dirty_dirs;	/* List of dirty directories */
+
+	/* Summary */
+	int chunks_per_summary;
+	struct yaffs_summary_tags *sum_tags;
+
+	/* Statistics */
+	u32 n_page_writes;
+	u32 n_page_reads;
+	u32 n_erasures;
+	u32 n_bad_queries;
+	u32 n_bad_markings;
+	u32 n_erase_failures;
+	u32 n_gc_copies;
+	u32 all_gcs;
+	u32 passive_gc_count;
+	u32 oldest_dirty_gc_count;
+	u32 n_gc_blocks;
+	u32 bg_gcs;
+	u32 n_retried_writes;
+	u32 n_retired_blocks;
+	u32 n_ecc_fixed;
+	u32 n_ecc_unfixed;
+	u32 n_tags_ecc_fixed;
+	u32 n_tags_ecc_unfixed;
+	u32 n_deletions;
+	u32 n_unmarked_deletions;
+	u32 refresh_count;
+	u32 cache_hits;
+	u32 tags_used;
+	u32 summary_used;
+
+};
+
+/* The CheckpointDevice structure holds the device information that changes
+ *at runtime and must be preserved over unmount/mount cycles.
+ */
+struct yaffs_checkpt_dev {
+	int struct_type;
+	int n_erased_blocks;
+	int alloc_block;	/* Current block being allocated off */
+	u32 alloc_page;
+	int n_free_chunks;
+
+	int n_deleted_files;	/* Count of files awaiting deletion; */
+	int n_unlinked_files;	/* Count of unlinked files. */
+	int n_bg_deletions;	/* Count of background deletions. */
+
+	/* yaffs2 runtime stuff */
+	unsigned seq_number;	/* Sequence number of currently
+				 * allocating block */
+
+};
+
+struct yaffs_checkpt_validity {
+	int struct_type;
+	u32 magic;
+	u32 version;
+	u32 head;
+};
+
+struct yaffs_shadow_fixer {
+	int obj_id;
+	int shadowed_id;
+	struct yaffs_shadow_fixer *next;
+};
+
+/* Structure for doing xattr modifications */
+struct yaffs_xattr_mod {
+	int set;		/* If 0 then this is a deletion */
+	const YCHAR *name;
+	const void *data;
+	int size;
+	int flags;
+	int result;
+};
+
+/*----------------------- YAFFS Functions -----------------------*/
+
+int yaffs_guts_initialise(struct yaffs_dev *dev);
+void yaffs_deinitialise(struct yaffs_dev *dev);
+
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
+
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
+		     struct yaffs_obj *new_dir, const YCHAR * new_name);
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
+int yaffs_del_obj(struct yaffs_obj *obj);
+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
+				   enum yaffs_obj_type type);
+
+
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
+int yaffs_get_obj_inode(struct yaffs_obj *obj);
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
+int yaffs_get_obj_link_count(struct yaffs_obj *obj);
+
+/* File operations */
+int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
+		  int n_bytes);
+int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
+		  int n_bytes, int write_trhrough);
+int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
+
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+				    const YCHAR *name, u32 mode, u32 uid,
+				    u32 gid);
+
+int yaffs_flush_file(struct yaffs_obj *in,
+		     int update_time,
+		     int data_sync,
+		     int discard_cache);
+
+/* Flushing and checkpointing */
+void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard);
+
+int yaffs_checkpoint_save(struct yaffs_dev *dev);
+int yaffs_checkpoint_restore(struct yaffs_dev *dev);
+
+/* Directory operations */
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+				   u32 mode, u32 uid, u32 gid);
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
+				     const YCHAR *name);
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
+
+/* Link operations */
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
+				 struct yaffs_obj *equiv_obj);
+
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
+
+/* Symlink operations */
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, const YCHAR *alias);
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
+
+/* Special inodes (fifos, sockets and devices) */
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, u32 rdev);
+
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
+		      const void *value, int size, int flags);
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
+		      int size);
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
+
+/* Special directories */
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
+
+void yaffs_handle_defered_free(struct yaffs_obj *obj);
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
+
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
+
+/* Debug dump  */
+int yaffs_dump_obj(struct yaffs_obj *obj);
+
+void yaffs_guts_test(struct yaffs_dev *dev);
+int yaffs_guts_ll_init(struct yaffs_dev *dev);
+
+
+/* A few useful functions to be used within the core files*/
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+		     int lyn);
+int yaffs_check_ff(u8 *buffer, int n_bytes);
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+			      struct yaffs_block_info *bi);
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+						 int number,
+						 enum yaffs_obj_type type);
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+			    int nand_chunk, int in_scan);
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+				const struct yaffs_obj_hdr *oh);
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
+YCHAR *yaffs_clone_str(const YCHAR *str);
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
+		    int force, int is_shrink, int shadows,
+		    struct yaffs_xattr_mod *xop);
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+			       int backward_scanning);
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+					   struct yaffs_file_var *file_struct,
+					   u32 chunk_id,
+					   struct yaffs_tnode *passed_tn);
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+		     int n_bytes, int write_trhrough);
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+				       struct yaffs_file_var *file_struct,
+				       u32 chunk_id);
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+			 unsigned pos);
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
+
+int yaffs_guts_format_dev(struct yaffs_dev *dev);
+
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+				int *chunk_out, u32 *offset_out);
+/*
+ * Marshalling functions to get loff_t file sizes into aand out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
+loff_t yaffs_max_file_size(struct yaffs_dev *dev);
+
+/*
+ * Debug function to count number of blocks in each state
+ * NB Needs to be called with correct number of integers
+ */
+
+void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
+
+int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+				    struct yaffs_ext_tags *tags);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_linux.h b/target/linux/generic/files/fs/yaffs2/yaffs_linux.h
new file mode 100644
index 0000000000..c20ab14b7f
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_linux.h
@@ -0,0 +1,48 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_LINUX_H__
+#define __YAFFS_LINUX_H__
+
+#include "yportenv.h"
+
+struct yaffs_linux_context {
+	struct list_head context_list;	/* List of these we have mounted */
+	struct yaffs_dev *dev;
+	struct super_block *super;
+	struct task_struct *bg_thread;	/* Background thread for this device */
+	int bg_running;
+	struct mutex gross_lock;	/* Gross locking mutex*/
+	u8 *spare_buffer;	/* For mtdif2 use. Don't know the buffer size
+				 * at compile time so we have to allocate it.
+				 */
+	struct list_head search_contexts;
+	struct task_struct *readdir_process;
+	unsigned mount_id;
+	int dirty;
+};
+
+#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
+#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#define WRITE_SIZE_STR "writesize"
+#define WRITE_SIZE(mtd) ((mtd)->writesize)
+#else
+#define WRITE_SIZE_STR "oobblock"
+#define WRITE_SIZE(mtd) ((mtd)->oobblock)
+#endif
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c
new file mode 100644
index 0000000000..7c01461ab9
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c
@@ -0,0 +1,310 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yportenv.h"
+
+#include "yaffs_mtdif.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+#include "linux/kernel.h"
+#include "linux/version.h"
+#include "linux/types.h"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+#include "uapi/linux/major.h"
+#endif
+
+#include "yaffs_trace.h"
+#include "yaffs_guts.h"
+#include "yaffs_linux.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
+#endif
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
+#define mtd_erase(m, ei) (m)->erase(m, ei)
+#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
+#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
+#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
+#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
+#endif
+
+
+
+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
+{
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+	u32 addr =
+	    ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
+	    dev->param.chunks_per_block;
+	struct erase_info ei;
+	int retval = 0;
+
+	ei.mtd = mtd;
+	ei.addr = addr;
+	ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
+	ei.time = 1000;
+	ei.retries = 2;
+	ei.callback = NULL;
+	ei.priv = (u_long) dev;
+
+	retval = mtd_erase(mtd, &ei);
+
+	if (retval == 0)
+		return YAFFS_OK;
+
+	return YAFFS_FAIL;
+}
+
+
+static 	int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
+				   const u8 *data, int data_len,
+				   const u8 *oob, int oob_len)
+{
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+	loff_t addr;
+	struct mtd_oob_ops ops;
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_MTD,
+			"yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
+			dev, nand_chunk, data, data_len, oob, oob_len);
+
+	if (!data || !data_len) {
+		data = NULL;
+		data_len = 0;
+	}
+
+	if (!oob || !oob_len) {
+		oob = NULL;
+		oob_len = 0;
+	}
+
+	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
+	memset(&ops, 0, sizeof(ops));
+	ops.mode = MTD_OPS_AUTO_OOB;
+	ops.len = (data) ? data_len : 0;
+	ops.ooblen = oob_len;
+	ops.datbuf = (u8 *)data;
+	ops.oobbuf = (u8 *)oob;
+
+	retval = mtd_write_oob(mtd, addr, &ops);
+	if (retval) {
+		yaffs_trace(YAFFS_TRACE_MTD,
+			"write_oob failed, chunk %d, mtd error %d",
+			nand_chunk, retval);
+	}
+	return retval ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
+				   u8 *data, int data_len,
+				   u8 *oob, int oob_len,
+				   enum yaffs_ecc_result *ecc_result)
+{
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+	loff_t addr;
+	struct mtd_oob_ops ops;
+	int retval;
+
+	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
+	memset(&ops, 0, sizeof(ops));
+	ops.mode = MTD_OPS_AUTO_OOB;
+	ops.len = (data) ? data_len : 0;
+	ops.ooblen = oob_len;
+	ops.datbuf = data;
+	ops.oobbuf = oob;
+
+#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
+	/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
+	 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
+	 */
+	ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
+#endif
+	/* Read page and oob using MTD.
+	 * Check status and determine ECC result.
+	 */
+	retval = mtd_read_oob(mtd, addr, &ops);
+	if (retval)
+		yaffs_trace(YAFFS_TRACE_MTD,
+			"read_oob failed, chunk %d, mtd error %d",
+			nand_chunk, retval);
+
+	switch (retval) {
+	case 0:
+		/* no error */
+		if(ecc_result)
+			*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+		break;
+
+	case -EUCLEAN:
+		/* MTD's ECC fixed the data */
+		if(ecc_result)
+			*ecc_result = YAFFS_ECC_RESULT_FIXED;
+		dev->n_ecc_fixed++;
+		break;
+
+	case -EBADMSG:
+	default:
+		/* MTD's ECC could not fix the data */
+		dev->n_ecc_unfixed++;
+		if(ecc_result)
+			*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+		return YAFFS_FAIL;
+	}
+
+	return YAFFS_OK;
+}
+
+static 	int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
+{
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+
+	loff_t addr;
+	struct erase_info ei;
+	int retval = 0;
+	u32 block_size;
+
+	block_size = dev->param.total_bytes_per_chunk *
+		     dev->param.chunks_per_block;
+	addr = ((loff_t) block_no) * block_size;
+
+	ei.mtd = mtd;
+	ei.addr = addr;
+	ei.len = block_size;
+	ei.time = 1000;
+	ei.retries = 2;
+	ei.callback = NULL;
+	ei.priv = (u_long) dev;
+
+	retval = mtd_erase(mtd, &ei);
+
+	if (retval == 0)
+		return YAFFS_OK;
+
+	return YAFFS_FAIL;
+}
+
+static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
+
+	retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
+	return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
+{
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
+
+	retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
+	return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+static int yaffs_mtd_initialise(struct yaffs_dev *dev)
+{
+	return YAFFS_OK;
+}
+
+static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
+{
+	return YAFFS_OK;
+}
+
+
+void yaffs_mtd_drv_install(struct yaffs_dev *dev)
+{
+	struct yaffs_driver *drv = &dev->drv;
+
+	drv->drv_write_chunk_fn = yaffs_mtd_write;
+	drv->drv_read_chunk_fn = yaffs_mtd_read;
+	drv->drv_erase_fn = yaffs_mtd_erase;
+	drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
+	drv->drv_check_bad_fn = yaffs_mtd_check_bad;
+	drv->drv_initialise_fn = yaffs_mtd_initialise;
+	drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
+}
+
+
+struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
+{
+	struct mtd_info *mtd;
+
+	mtd = yaffs_get_mtd_device(sdev);
+
+	/* Check it's an mtd device..... */
+	if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
+		return NULL;	/* This isn't an mtd device */
+
+	/* Check it's NAND */
+	if (mtd->type != MTD_NANDFLASH) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"yaffs: MTD device is not NAND it's type %d",
+			mtd->type);
+		return NULL;
+	}
+
+	yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
+	yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
+	yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+	yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
+#else
+	yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
+#endif
+
+	return mtd;
+}
+
+int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
+{
+	if (yaffs_version == 2) {
+		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+		     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
+		    !inband_tags) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"MTD device does not have the right page sizes"
+			);
+			return -1;
+		}
+	} else {
+		if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
+		    mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"MTD device does not support have the right page sizes"
+			);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+void yaffs_put_mtd_device(struct mtd_info *mtd)
+{
+	if(mtd)
+		put_mtd_device(mtd);
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h
new file mode 100644
index 0000000000..9cff224c6d
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.h
@@ -0,0 +1,25 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF_H__
+#define __YAFFS_MTDIF_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
+void yaffs_put_mtd_device(struct mtd_info *mtd);
+int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nameval.c b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.c
new file mode 100644
index 0000000000..4bdf4ed743
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.c
@@ -0,0 +1,208 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * This simple implementation of a name-value store assumes a small number of
+* values and fits into a small finite buffer.
+ *
+ * Each attribute is stored as a record:
+ *  sizeof(int) bytes   record size.
+ *  strnlen+1 bytes name null terminated.
+ *  nbytes    value.
+ *  ----------
+ *  total size  stored in record size
+ *
+ * This code has not been tested with unicode yet.
+ */
+
+#include "yaffs_nameval.h"
+
+#include "yportenv.h"
+
+static int nval_find(const char *xb, int xb_size, const YCHAR *name,
+		     int *exist_size)
+{
+	int pos = 0;
+	int size;
+
+	memcpy(&size, xb, sizeof(int));
+	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+		if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
+				name, size)) {
+			if (exist_size)
+				*exist_size = size;
+			return pos;
+		}
+		pos += size;
+		if (pos < xb_size - sizeof(int))
+			memcpy(&size, xb + pos, sizeof(int));
+		else
+			size = 0;
+	}
+	if (exist_size)
+		*exist_size = 0;
+	return -ENODATA;
+}
+
+static int nval_used(const char *xb, int xb_size)
+{
+	int pos = 0;
+	int size;
+
+	memcpy(&size, xb + pos, sizeof(int));
+	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+		pos += size;
+		if (pos < xb_size - sizeof(int))
+			memcpy(&size, xb + pos, sizeof(int));
+		else
+			size = 0;
+	}
+	return pos;
+}
+
+int nval_del(char *xb, int xb_size, const YCHAR *name)
+{
+	int pos = nval_find(xb, xb_size, name, NULL);
+	int size;
+
+	if (pos < 0 || pos >= xb_size)
+		return -ENODATA;
+
+	/* Find size, shift rest over this record,
+	 * then zero out the rest of buffer */
+	memcpy(&size, xb + pos, sizeof(int));
+	memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
+	memset(xb + (xb_size - size), 0, size);
+	return 0;
+}
+
+int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
+		int bsize, int flags)
+{
+	int pos;
+	int namelen = strnlen(name, xb_size);
+	int reclen;
+	int size_exist = 0;
+	int space;
+	int start;
+
+	pos = nval_find(xb, xb_size, name, &size_exist);
+
+	if (flags & XATTR_CREATE && pos >= 0)
+		return -EEXIST;
+	if (flags & XATTR_REPLACE && pos < 0)
+		return -ENODATA;
+
+	start = nval_used(xb, xb_size);
+	space = xb_size - start + size_exist;
+
+	reclen = (sizeof(int) + namelen + 1 + bsize);
+
+	if (reclen > space)
+		return -ENOSPC;
+
+	if (pos >= 0) {
+		nval_del(xb, xb_size, name);
+		start = nval_used(xb, xb_size);
+	}
+
+	pos = start;
+
+	memcpy(xb + pos, &reclen, sizeof(int));
+	pos += sizeof(int);
+	strncpy((YCHAR *) (xb + pos), name, reclen);
+	pos += (namelen + 1);
+	memcpy(xb + pos, buf, bsize);
+	return 0;
+}
+
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+	     int bsize)
+{
+	int pos = nval_find(xb, xb_size, name, NULL);
+	int size;
+
+	if (pos >= 0 && pos < xb_size) {
+
+		memcpy(&size, xb + pos, sizeof(int));
+		pos += sizeof(int);	/* advance past record length */
+		size -= sizeof(int);
+
+		/* Advance over name string */
+		while (xb[pos] && size > 0 && pos < xb_size) {
+			pos++;
+			size--;
+		}
+		/*Advance over NUL */
+		pos++;
+		size--;
+
+		/* If bsize is zero then this is a size query.
+		 * Return the size, but don't copy.
+		 */
+		if (!bsize)
+			return size;
+
+		if (size <= bsize) {
+			memcpy(buf, xb + pos, size);
+			return size;
+		}
+	}
+	if (pos >= 0)
+		return -ERANGE;
+
+	return -ENODATA;
+}
+
+int nval_list(const char *xb, int xb_size, char *buf, int bsize)
+{
+	int pos = 0;
+	int size;
+	int name_len;
+	int ncopied = 0;
+	int filled = 0;
+
+	memcpy(&size, xb + pos, sizeof(int));
+	while (size > sizeof(int) &&
+		size <= xb_size &&
+		(pos + size) < xb_size &&
+		!filled) {
+		pos += sizeof(int);
+		size -= sizeof(int);
+		name_len = strnlen((YCHAR *) (xb + pos), size);
+		if (ncopied + name_len + 1 < bsize) {
+			memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
+			buf += name_len;
+			*buf = '\0';
+			buf++;
+			if (sizeof(YCHAR) > 1) {
+				*buf = '\0';
+				buf++;
+			}
+			ncopied += (name_len + 1);
+		} else {
+			filled = 1;
+		}
+		pos += size;
+		if (pos < xb_size - sizeof(int))
+			memcpy(&size, xb + pos, sizeof(int));
+		else
+			size = 0;
+	}
+	return ncopied;
+}
+
+int nval_hasvalues(const char *xb, int xb_size)
+{
+	return nval_used(xb, xb_size) > 0;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nameval.h b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.h
new file mode 100644
index 0000000000..951e64f872
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_nameval.h
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAMEVAL_H__
+#define __NAMEVAL_H__
+
+#include "yportenv.h"
+
+int nval_del(char *xb, int xb_size, const YCHAR * name);
+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
+	     int bsize, int flags);
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+	     int bsize);
+int nval_list(const char *xb, int xb_size, char *buf, int bsize);
+int nval_hasvalues(const char *xb, int xb_size);
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nand.c b/target/linux/generic/files/fs/yaffs2/yaffs_nand.c
new file mode 100644
index 0000000000..0d8499bdc6
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_nand.c
@@ -0,0 +1,122 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_nand.h"
+#include "yaffs_tagscompat.h"
+
+#include "yaffs_getblockinfo.h"
+#include "yaffs_summary.h"
+
+static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
+{
+	return chunk - dev->chunk_offset;
+}
+
+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
+			     u8 *buffer, struct yaffs_ext_tags *tags)
+{
+	int result;
+	struct yaffs_ext_tags local_tags;
+	int flash_chunk = apply_chunk_offset(dev, nand_chunk);
+
+	dev->n_page_reads++;
+
+	/* If there are no tags provided use local tags. */
+	if (!tags)
+		tags = &local_tags;
+
+	result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
+	if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
+
+		struct yaffs_block_info *bi;
+		bi = yaffs_get_block_info(dev,
+					  nand_chunk /
+					  dev->param.chunks_per_block);
+		yaffs_handle_chunk_error(dev, bi);
+	}
+	return result;
+}
+
+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
+				int nand_chunk,
+				const u8 *buffer, struct yaffs_ext_tags *tags)
+{
+	int result;
+	int flash_chunk = apply_chunk_offset(dev, nand_chunk);
+
+	dev->n_page_writes++;
+
+	if (!tags) {
+		yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	tags->seq_number = dev->seq_number;
+	tags->chunk_used = 1;
+	yaffs_trace(YAFFS_TRACE_WRITE,
+		"Writing chunk %d tags %d %d",
+		nand_chunk, tags->obj_id, tags->chunk_id);
+
+	result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
+							buffer, tags);
+
+	yaffs_summary_add(dev, tags, nand_chunk);
+
+	return result;
+}
+
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+	block_no -= dev->block_offset;
+	dev->n_bad_markings++;
+
+	if (dev->param.disable_bad_block_marking)
+		return YAFFS_OK;
+
+	return dev->tagger.mark_bad_fn(dev, block_no);
+}
+
+
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+				 int block_no,
+				 enum yaffs_block_state *state,
+				 u32 *seq_number)
+{
+	block_no -= dev->block_offset;
+	return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
+}
+
+int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
+{
+	int result;
+
+	block_no -= dev->block_offset;
+	dev->n_erasures++;
+	result = dev->drv.drv_erase_fn(dev, block_no);
+	return result;
+}
+
+int yaffs_init_nand(struct yaffs_dev *dev)
+{
+	if (dev->drv.drv_initialise_fn)
+		return dev->drv.drv_initialise_fn(dev);
+	return YAFFS_OK;
+}
+
+int yaffs_deinit_nand(struct yaffs_dev *dev)
+{
+	if (dev->drv.drv_deinitialise_fn)
+		return dev->drv.drv_deinitialise_fn(dev);
+	return YAFFS_OK;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_nand.h b/target/linux/generic/files/fs/yaffs2/yaffs_nand.h
new file mode 100644
index 0000000000..804e97ad66
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_nand.h
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_H__
+#define __YAFFS_NAND_H__
+#include "yaffs_guts.h"
+
+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
+			     u8 *buffer, struct yaffs_ext_tags *tags);
+
+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
+			     int nand_chunk,
+			     const u8 *buffer, struct yaffs_ext_tags *tags);
+
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
+
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+				 int block_no,
+				 enum yaffs_block_state *state,
+				 unsigned *seq_number);
+
+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
+
+int yaffs_init_nand(struct yaffs_dev *dev);
+int yaffs_deinit_nand(struct yaffs_dev *dev);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c
new file mode 100644
index 0000000000..dd9a331d8f
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.c
@@ -0,0 +1,56 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_packedtags1.h"
+#include "yportenv.h"
+
+static const u8 all_ff[20] = {
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff
+};
+
+void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
+		      const struct yaffs_ext_tags *t)
+{
+	pt->chunk_id = t->chunk_id;
+	pt->serial_number = t->serial_number;
+	pt->n_bytes = t->n_bytes;
+	pt->obj_id = t->obj_id;
+	pt->ecc = 0;
+	pt->deleted = (t->is_deleted) ? 0 : 1;
+	pt->unused_stuff = 0;
+	pt->should_be_ff = 0xffffffff;
+}
+
+void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
+			const struct yaffs_packed_tags1 *pt)
+{
+
+	if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
+		t->block_bad = 0;
+		if (pt->should_be_ff != 0xffffffff)
+			t->block_bad = 1;
+		t->chunk_used = 1;
+		t->obj_id = pt->obj_id;
+		t->chunk_id = pt->chunk_id;
+		t->n_bytes = pt->n_bytes;
+		t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+		t->is_deleted = (pt->deleted) ? 0 : 1;
+		t->serial_number = pt->serial_number;
+	} else {
+		memset(t, 0, sizeof(struct yaffs_ext_tags));
+	}
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h
new file mode 100644
index 0000000000..3015d58a07
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
+
+#ifndef __YAFFS_PACKEDTAGS1_H__
+#define __YAFFS_PACKEDTAGS1_H__
+
+#include "yaffs_guts.h"
+
+struct yaffs_packed_tags1 {
+	u32 chunk_id:20;
+	u32 serial_number:2;
+	u32 n_bytes:10;
+	u32 obj_id:18;
+	u32 ecc:12;
+	u32 deleted:1;
+	u32 unused_stuff:1;
+	unsigned should_be_ff;
+
+};
+
+void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
+		      const struct yaffs_ext_tags *t);
+void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
+			const struct yaffs_packed_tags1 *pt);
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c
new file mode 100644
index 0000000000..e1d18cc33c
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.c
@@ -0,0 +1,197 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_packedtags2.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+/* This code packs a set of extended tags into a binary structure for
+ * NAND storage
+ */
+
+/* Some of the information is "extra" struff which can be packed in to
+ * speed scanning
+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
+ */
+
+/* Extra flags applied to chunk_id */
+
+#define EXTRA_HEADER_INFO_FLAG	0x80000000
+#define EXTRA_SHRINK_FLAG	0x40000000
+#define EXTRA_SHADOWS_FLAG	0x20000000
+#define EXTRA_SPARE_FLAGS	0x10000000
+
+#define ALL_EXTRA_FLAGS		0xf0000000
+
+/* Also, the top 4 bits of the object Id are set to the object type. */
+#define EXTRA_OBJECT_TYPE_SHIFT (28)
+#define EXTRA_OBJECT_TYPE_MASK  ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
+
+static void yaffs_dump_packed_tags2_tags_only(
+				const struct yaffs_packed_tags2_tags_only *ptt)
+{
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"packed tags obj %d chunk %d byte %d seq %d",
+		ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
+}
+
+static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
+{
+	yaffs_dump_packed_tags2_tags_only(&pt->t);
+}
+
+static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
+{
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
+		t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
+		t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
+		t->seq_number);
+
+}
+
+static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
+{
+	if (t->chunk_id != 0 || !t->extra_available)
+		return 0;
+
+	/* Check if the file size is too long to store */
+	if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
+	    (t->extra_file_size >> 31) != 0)
+		return 0;
+	return 1;
+}
+
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
+				const struct yaffs_ext_tags *t)
+{
+	ptt->chunk_id = t->chunk_id;
+	ptt->seq_number = t->seq_number;
+	ptt->n_bytes = t->n_bytes;
+	ptt->obj_id = t->obj_id;
+
+	/* Only store extra tags for object headers.
+	 * If it is a file then only store  if the file size is short\
+	 * enough to fit.
+	 */
+	if (yaffs_check_tags_extra_packable(t)) {
+		/* Store the extra header info instead */
+		/* We save the parent object in the chunk_id */
+		ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
+		if (t->extra_is_shrink)
+			ptt->chunk_id |= EXTRA_SHRINK_FLAG;
+		if (t->extra_shadows)
+			ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
+
+		ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
+		ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
+
+		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+			ptt->n_bytes = t->extra_equiv_id;
+		else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+			ptt->n_bytes = (unsigned) t->extra_file_size;
+		else
+			ptt->n_bytes = 0;
+	}
+
+	yaffs_dump_packed_tags2_tags_only(ptt);
+	yaffs_dump_tags2(t);
+}
+
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+		      const struct yaffs_ext_tags *t, int tags_ecc)
+{
+	yaffs_pack_tags2_tags_only(&pt->t, t);
+
+	if (tags_ecc)
+		yaffs_ecc_calc_other((unsigned char *)&pt->t,
+				    sizeof(struct yaffs_packed_tags2_tags_only),
+				    &pt->ecc);
+}
+
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+				  struct yaffs_packed_tags2_tags_only *ptt)
+{
+	memset(t, 0, sizeof(struct yaffs_ext_tags));
+
+	if (ptt->seq_number == 0xffffffff)
+		return;
+
+	t->block_bad = 0;
+	t->chunk_used = 1;
+	t->obj_id = ptt->obj_id;
+	t->chunk_id = ptt->chunk_id;
+	t->n_bytes = ptt->n_bytes;
+	t->is_deleted = 0;
+	t->serial_number = 0;
+	t->seq_number = ptt->seq_number;
+
+	/* Do extra header info stuff */
+	if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
+		t->chunk_id = 0;
+		t->n_bytes = 0;
+
+		t->extra_available = 1;
+		t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
+		t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
+		t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
+		t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
+		t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
+
+		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+			t->extra_equiv_id = ptt->n_bytes;
+		else
+			t->extra_file_size = ptt->n_bytes;
+	}
+	yaffs_dump_packed_tags2_tags_only(ptt);
+	yaffs_dump_tags2(t);
+}
+
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+			int tags_ecc)
+{
+	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+	if (pt->t.seq_number != 0xffffffff && tags_ecc) {
+		/* Chunk is in use and we need to do ECC */
+
+		struct yaffs_ecc_other ecc;
+		int result;
+		yaffs_ecc_calc_other((unsigned char *)&pt->t,
+				sizeof(struct yaffs_packed_tags2_tags_only),
+				&ecc);
+		result =
+		    yaffs_ecc_correct_other((unsigned char *)&pt->t,
+				sizeof(struct yaffs_packed_tags2_tags_only),
+				&pt->ecc, &ecc);
+		switch (result) {
+		case 0:
+			ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+			break;
+		case 1:
+			ecc_result = YAFFS_ECC_RESULT_FIXED;
+			break;
+		case -1:
+			ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+			break;
+		default:
+			ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+		}
+	}
+	yaffs_unpack_tags2_tags_only(t, &pt->t);
+
+	t->ecc_result = ecc_result;
+
+	yaffs_dump_packed_tags2(pt);
+	yaffs_dump_tags2(t);
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h
new file mode 100644
index 0000000000..675e719460
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags2.h
@@ -0,0 +1,47 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
+
+#ifndef __YAFFS_PACKEDTAGS2_H__
+#define __YAFFS_PACKEDTAGS2_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_ecc.h"
+
+struct yaffs_packed_tags2_tags_only {
+	unsigned seq_number;
+	unsigned obj_id;
+	unsigned chunk_id;
+	unsigned n_bytes;
+};
+
+struct yaffs_packed_tags2 {
+	struct yaffs_packed_tags2_tags_only t;
+	struct yaffs_ecc_other ecc;
+};
+
+/* Full packed tags with ECC, used for oob tags */
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+		      const struct yaffs_ext_tags *t, int tags_ecc);
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+			int tags_ecc);
+
+/* Only the tags part (no ECC for use with inband tags */
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
+				const struct yaffs_ext_tags *t);
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+				  struct yaffs_packed_tags2_tags_only *pt);
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_summary.c b/target/linux/generic/files/fs/yaffs2/yaffs_summary.c
new file mode 100644
index 0000000000..3c9e72321e
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_summary.c
@@ -0,0 +1,312 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/* Summaries write the useful part of the tags for the chunks in a block into an
+ * an array which is written to the last n chunks of the block.
+ * Reading the summaries gives all the tags for the block in one read. Much
+ * faster.
+ *
+ * Chunks holding summaries are marked with tags making it look like
+ * they are part of a fake file.
+ *
+ * The summary could also be used during gc.
+ *
+ */
+
+#include "yaffs_summary.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_bitmap.h"
+
+/*
+ * The summary is built up in an array of summary tags.
+ * This gets written to the last one or two (maybe more) chunks in a block.
+ * A summary header is written as the first part of each chunk of summary data.
+ * The summary header must match or the summary is rejected.
+ */
+
+/* Summary tags don't need the sequence number because that is redundant. */
+struct yaffs_summary_tags {
+	unsigned obj_id;
+	unsigned chunk_id;
+	unsigned n_bytes;
+};
+
+/* Summary header */
+struct yaffs_summary_header {
+	unsigned version;	/* Must match current version */
+	unsigned block;		/* Must be this block */
+	unsigned seq;		/* Must be this sequence number */
+	unsigned sum;		/* Just add up all the bytes in the tags */
+};
+
+
+static void yaffs_summary_clear(struct yaffs_dev *dev)
+{
+	if (!dev->sum_tags)
+		return;
+	memset(dev->sum_tags, 0, dev->chunks_per_summary *
+		sizeof(struct yaffs_summary_tags));
+}
+
+
+void yaffs_summary_deinit(struct yaffs_dev *dev)
+{
+	kfree(dev->sum_tags);
+	dev->sum_tags = NULL;
+	kfree(dev->gc_sum_tags);
+	dev->gc_sum_tags = NULL;
+	dev->chunks_per_summary = 0;
+}
+
+int yaffs_summary_init(struct yaffs_dev *dev)
+{
+	int sum_bytes;
+	int chunks_used; /* Number of chunks used by summary */
+	int sum_tags_bytes;
+
+	sum_bytes = dev->param.chunks_per_block *
+			sizeof(struct yaffs_summary_tags);
+
+	chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
+			(dev->data_bytes_per_chunk -
+				sizeof(struct yaffs_summary_header));
+
+	dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
+	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
+	dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
+	if (!dev->sum_tags || !dev->gc_sum_tags) {
+		yaffs_summary_deinit(dev);
+		return YAFFS_FAIL;
+	}
+
+	yaffs_summary_clear(dev);
+
+	return YAFFS_OK;
+}
+
+static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
+{
+	u8 *sum_buffer = (u8 *)dev->sum_tags;
+	int i;
+	unsigned sum = 0;
+
+	i = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	while (i > 0) {
+		sum += *sum_buffer;
+		sum_buffer++;
+		i--;
+	}
+
+	return sum;
+}
+
+static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
+{
+	struct yaffs_ext_tags tags;
+	u8 *buffer;
+	u8 *sum_buffer = (u8 *)dev->sum_tags;
+	int n_bytes;
+	int chunk_in_nand;
+	int chunk_in_block;
+	int result;
+	int this_tx;
+	struct yaffs_summary_header hdr;
+	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+
+	buffer = yaffs_get_temp_buffer(dev);
+	n_bytes = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	memset(&tags, 0, sizeof(struct yaffs_ext_tags));
+	tags.obj_id = YAFFS_OBJECTID_SUMMARY;
+	tags.chunk_id = 1;
+	chunk_in_block = dev->chunks_per_summary;
+	chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
+						dev->chunks_per_summary;
+	hdr.version = YAFFS_SUMMARY_VERSION;
+	hdr.block = blk;
+	hdr.seq = bi->seq_number;
+	hdr.sum = yaffs_summary_sum(dev);
+
+	do {
+		this_tx = n_bytes;
+		if (this_tx > sum_bytes_per_chunk)
+			this_tx = sum_bytes_per_chunk;
+		memcpy(buffer, &hdr, sizeof(hdr));
+		memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
+		tags.n_bytes = this_tx + sizeof(hdr);
+		result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
+						buffer, &tags);
+
+		if (result != YAFFS_OK)
+			break;
+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+		bi->pages_in_use++;
+		dev->n_free_chunks--;
+
+		n_bytes -= this_tx;
+		sum_buffer += this_tx;
+		chunk_in_nand++;
+		chunk_in_block++;
+		tags.chunk_id++;
+	} while (result == YAFFS_OK && n_bytes > 0);
+	yaffs_release_temp_buffer(dev, buffer);
+
+
+	if (result == YAFFS_OK)
+		bi->has_summary = 1;
+
+
+	return result;
+}
+
+int yaffs_summary_read(struct yaffs_dev *dev,
+			struct yaffs_summary_tags *st,
+			int blk)
+{
+	struct yaffs_ext_tags tags;
+	u8 *buffer;
+	u8 *sum_buffer = (u8 *)st;
+	int n_bytes;
+	int chunk_id;
+	int chunk_in_nand;
+	int chunk_in_block;
+	int result;
+	int this_tx;
+	struct yaffs_summary_header hdr;
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
+	int sum_tags_bytes;
+
+	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	buffer = yaffs_get_temp_buffer(dev);
+	n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
+	chunk_in_block = dev->chunks_per_summary;
+	chunk_in_nand = blk * dev->param.chunks_per_block +
+							dev->chunks_per_summary;
+	chunk_id = 1;
+	do {
+		this_tx = n_bytes;
+		if (this_tx > sum_bytes_per_chunk)
+			this_tx = sum_bytes_per_chunk;
+		result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
+						buffer, &tags);
+
+		if (tags.chunk_id != chunk_id ||
+			tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
+			tags.chunk_used == 0 ||
+			tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+			tags.n_bytes != (this_tx + sizeof(hdr)))
+				result = YAFFS_FAIL;
+		if (result != YAFFS_OK)
+			break;
+
+		if (st == dev->sum_tags) {
+			/* If we're scanning then update the block info */
+			yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+			bi->pages_in_use++;
+		}
+		memcpy(&hdr, buffer, sizeof(hdr));
+		memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
+		n_bytes -= this_tx;
+		sum_buffer += this_tx;
+		chunk_in_nand++;
+		chunk_in_block++;
+		chunk_id++;
+	} while (result == YAFFS_OK && n_bytes > 0);
+	yaffs_release_temp_buffer(dev, buffer);
+
+	if (result == YAFFS_OK) {
+		/* Verify header */
+		if (hdr.version != YAFFS_SUMMARY_VERSION ||
+		    hdr.seq != bi->seq_number ||
+		    hdr.sum != yaffs_summary_sum(dev))
+			result = YAFFS_FAIL;
+	}
+
+	if (st == dev->sum_tags && result == YAFFS_OK)
+		bi->has_summary = 1;
+
+	return result;
+}
+
+int yaffs_summary_add(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_nand)
+{
+	struct yaffs_packed_tags2_tags_only tags_only;
+	struct yaffs_summary_tags *sum_tags;
+	int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
+	int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
+
+	if (!dev->sum_tags)
+		return YAFFS_OK;
+
+	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
+		yaffs_pack_tags2_tags_only(&tags_only, tags);
+		sum_tags = &dev->sum_tags[chunk_in_block];
+		sum_tags->chunk_id = tags_only.chunk_id;
+		sum_tags->n_bytes = tags_only.n_bytes;
+		sum_tags->obj_id = tags_only.obj_id;
+
+		if (chunk_in_block == dev->chunks_per_summary - 1) {
+			/* Time to write out the summary */
+			yaffs_summary_write(dev, block_in_nand);
+			yaffs_summary_clear(dev);
+			yaffs_skip_rest_of_block(dev);
+		}
+	}
+	return YAFFS_OK;
+}
+
+int yaffs_summary_fetch(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_block)
+{
+	struct yaffs_packed_tags2_tags_only tags_only;
+	struct yaffs_summary_tags *sum_tags;
+	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
+		sum_tags = &dev->sum_tags[chunk_in_block];
+		tags_only.chunk_id = sum_tags->chunk_id;
+		tags_only.n_bytes = sum_tags->n_bytes;
+		tags_only.obj_id = sum_tags->obj_id;
+		yaffs_unpack_tags2_tags_only(tags, &tags_only);
+		return YAFFS_OK;
+	}
+	return YAFFS_FAIL;
+}
+
+void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
+{
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+	int i;
+
+	if (!bi->has_summary)
+		return;
+
+	for (i = dev->chunks_per_summary;
+	     i < dev->param.chunks_per_block;
+	     i++) {
+		if (yaffs_check_chunk_bit(dev, blk, i)) {
+			yaffs_clear_chunk_bit(dev, blk, i);
+			bi->pages_in_use--;
+			dev->n_free_chunks++;
+		}
+	}
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_summary.h b/target/linux/generic/files/fs/yaffs2/yaffs_summary.h
new file mode 100644
index 0000000000..be141d0733
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_summary.h
@@ -0,0 +1,37 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_SUMMARY_H__
+#define __YAFFS_SUMMARY_H__
+
+#include "yaffs_packedtags2.h"
+
+
+int yaffs_summary_init(struct yaffs_dev *dev);
+void yaffs_summary_deinit(struct yaffs_dev *dev);
+
+int yaffs_summary_add(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_block);
+int yaffs_summary_fetch(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_block);
+int yaffs_summary_read(struct yaffs_dev *dev,
+			struct yaffs_summary_tags *st,
+			int blk);
+void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
+
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c
new file mode 100644
index 0000000000..092430becc
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.c
@@ -0,0 +1,381 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_guts.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_ecc.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_trace.h"
+
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
+
+
+/********** Tags ECC calculations  *********/
+
+
+void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
+{
+	/* Calculate an ecc */
+	unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
+	unsigned i, j;
+	unsigned ecc = 0;
+	unsigned bit = 0;
+
+	tags->ecc = 0;
+
+	for (i = 0; i < 8; i++) {
+		for (j = 1; j & 0xff; j <<= 1) {
+			bit++;
+			if (b[i] & j)
+				ecc ^= bit;
+		}
+	}
+	tags->ecc = ecc;
+}
+
+int yaffs_check_tags_ecc(struct yaffs_tags *tags)
+{
+	unsigned ecc = tags->ecc;
+
+	yaffs_calc_tags_ecc(tags);
+
+	ecc ^= tags->ecc;
+
+	if (ecc && ecc <= 64) {
+		/* TODO: Handle the failure better. Retire? */
+		unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
+
+		ecc--;
+
+		b[ecc / 8] ^= (1 << (ecc & 7));
+
+		/* Now recvalc the ecc */
+		yaffs_calc_tags_ecc(tags);
+
+		return 1;	/* recovered error */
+	} else if (ecc) {
+		/* Wierd ecc failure value */
+		/* TODO Need to do somethiong here */
+		return -1;	/* unrecovered error */
+	}
+	return 0;
+}
+
+/********** Tags **********/
+
+static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+				     struct yaffs_tags *tags_ptr)
+{
+	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+
+	yaffs_calc_tags_ecc(tags_ptr);
+
+	spare_ptr->tb0 = tu->as_bytes[0];
+	spare_ptr->tb1 = tu->as_bytes[1];
+	spare_ptr->tb2 = tu->as_bytes[2];
+	spare_ptr->tb3 = tu->as_bytes[3];
+	spare_ptr->tb4 = tu->as_bytes[4];
+	spare_ptr->tb5 = tu->as_bytes[5];
+	spare_ptr->tb6 = tu->as_bytes[6];
+	spare_ptr->tb7 = tu->as_bytes[7];
+}
+
+static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
+				      struct yaffs_spare *spare_ptr,
+				      struct yaffs_tags *tags_ptr)
+{
+	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+	int result;
+
+	tu->as_bytes[0] = spare_ptr->tb0;
+	tu->as_bytes[1] = spare_ptr->tb1;
+	tu->as_bytes[2] = spare_ptr->tb2;
+	tu->as_bytes[3] = spare_ptr->tb3;
+	tu->as_bytes[4] = spare_ptr->tb4;
+	tu->as_bytes[5] = spare_ptr->tb5;
+	tu->as_bytes[6] = spare_ptr->tb6;
+	tu->as_bytes[7] = spare_ptr->tb7;
+
+	result = yaffs_check_tags_ecc(tags_ptr);
+	if (result > 0)
+		dev->n_tags_ecc_fixed++;
+	else if (result < 0)
+		dev->n_tags_ecc_unfixed++;
+}
+
+static void yaffs_spare_init(struct yaffs_spare *spare)
+{
+	memset(spare, 0xff, sizeof(struct yaffs_spare));
+}
+
+static int yaffs_wr_nand(struct yaffs_dev *dev,
+			 int nand_chunk, const u8 *data,
+			 struct yaffs_spare *spare)
+{
+	int data_size = dev->data_bytes_per_chunk;
+
+	return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
+				data, data_size,
+				(u8 *) spare, sizeof(*spare));
+}
+
+static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
+			       int nand_chunk,
+			       u8 *data,
+			       struct yaffs_spare *spare,
+			       enum yaffs_ecc_result *ecc_result,
+			       int correct_errors)
+{
+	int ret_val;
+	struct yaffs_spare local_spare;
+	int data_size;
+	int spare_size;
+	int ecc_result1, ecc_result2;
+	u8 calc_ecc[3];
+
+	if (!spare) {
+		/* If we don't have a real spare, then we use a local one. */
+		/* Need this for the calculation of the ecc */
+		spare = &local_spare;
+	}
+	data_size = dev->data_bytes_per_chunk;
+	spare_size = sizeof(struct yaffs_spare);
+
+	if (dev->param.use_nand_ecc)
+		return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+						data, data_size,
+						(u8 *) spare, spare_size,
+						ecc_result);
+
+
+	/* Handle the ECC at this level. */
+
+	ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+						 data, data_size,
+						 (u8 *)spare, spare_size,
+						NULL);
+	if (!data || !correct_errors)
+		return ret_val;
+
+	/* Do ECC correction if needed. */
+	yaffs_ecc_calc(data, calc_ecc);
+	ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
+	yaffs_ecc_calc(&data[256], calc_ecc);
+	ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
+
+	if (ecc_result1 > 0) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>>yaffs ecc error fix performed on chunk %d:0",
+			nand_chunk);
+		dev->n_ecc_fixed++;
+	} else if (ecc_result1 < 0) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>>yaffs ecc error unfixed on chunk %d:0",
+			nand_chunk);
+		dev->n_ecc_unfixed++;
+	}
+
+	if (ecc_result2 > 0) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>>yaffs ecc error fix performed on chunk %d:1",
+			nand_chunk);
+		dev->n_ecc_fixed++;
+	} else if (ecc_result2 < 0) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>>yaffs ecc error unfixed on chunk %d:1",
+			nand_chunk);
+		dev->n_ecc_unfixed++;
+	}
+
+	if (ecc_result1 || ecc_result2) {
+		/* We had a data problem on this page */
+		yaffs_handle_rd_data_error(dev, nand_chunk);
+	}
+
+	if (ecc_result1 < 0 || ecc_result2 < 0)
+		*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+	else if (ecc_result1 > 0 || ecc_result2 > 0)
+		*ecc_result = YAFFS_ECC_RESULT_FIXED;
+	else
+		*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+	return ret_val;
+}
+
+/*
+ * Functions for robustisizing
+ */
+
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
+{
+	int flash_block = nand_chunk / dev->param.chunks_per_block;
+
+	/* Mark the block for retirement */
+	yaffs_get_block_info(dev, flash_block + dev->block_offset)->
+		needs_retiring = 1;
+	yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+		"**>>Block %d marked for retirement",
+		flash_block);
+
+	/* TODO:
+	 * Just do a garbage collection on the affected block
+	 * then retire the block
+	 * NB recursion
+	 */
+}
+
+static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 const u8 *data, const struct yaffs_ext_tags *ext_tags)
+{
+	struct yaffs_spare spare;
+	struct yaffs_tags tags;
+
+	yaffs_spare_init(&spare);
+
+	if (ext_tags->is_deleted)
+		spare.page_status = 0;
+	else {
+		tags.obj_id = ext_tags->obj_id;
+		tags.chunk_id = ext_tags->chunk_id;
+
+		tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
+
+		if (dev->data_bytes_per_chunk >= 1024)
+			tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
+		else
+			tags.n_bytes_msb = 3;
+
+		tags.serial_number = ext_tags->serial_number;
+
+		if (!dev->param.use_nand_ecc && data) {
+			yaffs_ecc_calc(data, spare.ecc1);
+			yaffs_ecc_calc(&data[256], spare.ecc2);
+		}
+
+		yaffs_load_tags_to_spare(&spare, &tags);
+	}
+	return yaffs_wr_nand(dev, nand_chunk, data, &spare);
+}
+
+static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 u8 *data, struct yaffs_ext_tags *ext_tags)
+{
+	struct yaffs_spare spare;
+	struct yaffs_tags tags;
+	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+	static struct yaffs_spare spare_ff;
+	static int init;
+	int deleted;
+
+	if (!init) {
+		memset(&spare_ff, 0xff, sizeof(spare_ff));
+		init = 1;
+	}
+
+	if (!yaffs_rd_chunk_nand(dev, nand_chunk,
+					data, &spare, &ecc_result, 1))
+		return YAFFS_FAIL;
+
+	/* ext_tags may be NULL */
+	if (!ext_tags)
+		return YAFFS_OK;
+
+	deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
+
+	ext_tags->is_deleted = deleted;
+	ext_tags->ecc_result = ecc_result;
+	ext_tags->block_bad = 0;	/* We're reading it */
+	/* therefore it is not a bad block */
+	ext_tags->chunk_used =
+		memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
+
+	if (ext_tags->chunk_used) {
+		yaffs_get_tags_from_spare(dev, &spare, &tags);
+		ext_tags->obj_id = tags.obj_id;
+		ext_tags->chunk_id = tags.chunk_id;
+		ext_tags->n_bytes = tags.n_bytes_lsb;
+
+		if (dev->data_bytes_per_chunk >= 1024)
+			ext_tags->n_bytes |=
+				(((unsigned)tags.n_bytes_msb) << 10);
+
+		ext_tags->serial_number = tags.serial_number;
+	}
+
+	return YAFFS_OK;
+}
+
+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
+{
+	struct yaffs_spare spare;
+
+	memset(&spare, 0xff, sizeof(struct yaffs_spare));
+
+	spare.block_status = 'Y';
+
+	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
+		      &spare);
+	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
+		      NULL, &spare);
+
+	return YAFFS_OK;
+}
+
+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+				  int block_no,
+				  enum yaffs_block_state *state,
+				  u32 *seq_number)
+{
+	struct yaffs_spare spare0, spare1;
+	static struct yaffs_spare spare_ff;
+	static int init;
+	enum yaffs_ecc_result dummy;
+
+	if (!init) {
+		memset(&spare_ff, 0xff, sizeof(spare_ff));
+		init = 1;
+	}
+
+	*seq_number = 0;
+
+	/* Look for bad block markers in the first two chunks */
+	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
+			    NULL, &spare0, &dummy, 0);
+	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
+			    NULL, &spare1, &dummy, 0);
+
+	if (hweight8(spare0.block_status & spare1.block_status) < 7)
+		*state = YAFFS_BLOCK_STATE_DEAD;
+	else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
+		*state = YAFFS_BLOCK_STATE_EMPTY;
+	else
+		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+
+	return YAFFS_OK;
+}
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev)
+{
+	if(dev->param.is_yaffs2)
+		return;
+	if(!dev->tagger.write_chunk_tags_fn)
+		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
+	if(!dev->tagger.read_chunk_tags_fn)
+		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
+	if(!dev->tagger.query_block_fn)
+		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
+	if(!dev->tagger.mark_bad_fn)
+		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h
new file mode 100644
index 0000000000..92d298a6f5
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagscompat.h
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSCOMPAT_H__
+#define __YAFFS_TAGSCOMPAT_H__
+
+
+#include "yaffs_guts.h"
+
+#if 0
+
+
+int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 const u8 *data, const struct yaffs_ext_tags *tags);
+int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 u8 *data, struct yaffs_ext_tags *tags);
+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
+int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+				  int block_no,
+				  enum yaffs_block_state *state,
+				  u32 *seq_number);
+
+#endif
+
+
+void yaffs_tags_compat_install(struct yaffs_dev *dev);
+void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
+int yaffs_check_tags_ecc(struct yaffs_tags *tags);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c
new file mode 100644
index 0000000000..44a83b12ca
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.c
@@ -0,0 +1,199 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_packedtags2.h"
+
+static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
+				    int nand_chunk, const u8 *data,
+				    const struct yaffs_ext_tags *tags)
+{
+	struct yaffs_packed_tags2 pt;
+	int retval;
+
+	int packed_tags_size =
+	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+	void *packed_tags_ptr =
+	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"yaffs_tags_marshall_write chunk %d data %p tags %p",
+		nand_chunk, data, tags);
+
+	/* For yaffs2 writing there must be both data and tags.
+	 * If we're using inband tags, then the tags are stuffed into
+	 * the end of the data buffer.
+	 */
+	if (!data || !tags)
+		BUG();
+	else if (dev->param.inband_tags) {
+		struct yaffs_packed_tags2_tags_only *pt2tp;
+		pt2tp =
+		    (struct yaffs_packed_tags2_tags_only *)(data +
+							dev->
+							data_bytes_per_chunk);
+		yaffs_pack_tags2_tags_only(pt2tp, tags);
+	} else {
+		yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
+	}
+
+	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
+			data, dev->param.total_bytes_per_chunk,
+			(dev->param.inband_tags) ? NULL : packed_tags_ptr,
+			(dev->param.inband_tags) ? 0 : packed_tags_size);
+
+	return retval;
+}
+
+static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
+				   int nand_chunk, u8 *data,
+				   struct yaffs_ext_tags *tags)
+{
+	int retval = 0;
+	int local_data = 0;
+	u8 spare_buffer[100];
+	enum yaffs_ecc_result ecc_result;
+
+	struct yaffs_packed_tags2 pt;
+
+	int packed_tags_size =
+	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+	void *packed_tags_ptr =
+	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"yaffs_tags_marshall_read chunk %d data %p tags %p",
+		nand_chunk, data, tags);
+
+	if (dev->param.inband_tags) {
+		if (!data) {
+			local_data = 1;
+			data = yaffs_get_temp_buffer(dev);
+		}
+	}
+
+	if (dev->param.inband_tags || (data && !tags))
+		retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+					data, dev->param.total_bytes_per_chunk,
+					NULL, 0,
+					&ecc_result);
+	else if (tags)
+		retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
+					data, dev->param.total_bytes_per_chunk,
+					spare_buffer, packed_tags_size,
+					&ecc_result);
+	else
+		BUG();
+
+
+	if (dev->param.inband_tags) {
+		if (tags) {
+			struct yaffs_packed_tags2_tags_only *pt2tp;
+			pt2tp =
+				(struct yaffs_packed_tags2_tags_only *)
+				&data[dev->data_bytes_per_chunk];
+			yaffs_unpack_tags2_tags_only(tags, pt2tp);
+		}
+	} else if (tags) {
+		memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
+		yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
+	}
+
+	if (local_data)
+		yaffs_release_temp_buffer(dev, data);
+
+	if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
+		tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+		dev->n_ecc_unfixed++;
+	}
+
+	if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
+		if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
+			tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
+		dev->n_ecc_fixed++;
+	}
+
+	if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
+			       enum yaffs_block_state *state,
+			       u32 *seq_number)
+{
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
+			block_no);
+
+	retval = dev->drv.drv_check_bad_fn(dev, block_no);
+
+	if (retval== YAFFS_FAIL) {
+		yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
+
+		*state = YAFFS_BLOCK_STATE_DEAD;
+		*seq_number = 0;
+	} else {
+		struct yaffs_ext_tags t;
+
+		yaffs_tags_marshall_read(dev,
+				    block_no * dev->param.chunks_per_block,
+				    NULL, &t);
+
+		if (t.chunk_used) {
+			*seq_number = t.seq_number;
+			*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+		} else {
+			*seq_number = 0;
+			*state = YAFFS_BLOCK_STATE_EMPTY;
+		}
+	}
+
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"block query returns  seq %d state %d",
+		*seq_number, *state);
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+	return dev->drv.drv_mark_bad_fn(dev, block_no);
+
+}
+
+
+void yaffs_tags_marshall_install(struct yaffs_dev *dev)
+{
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (!dev->tagger.write_chunk_tags_fn)
+		dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
+
+	if (!dev->tagger.read_chunk_tags_fn)
+		dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
+
+	if (!dev->tagger.query_block_fn)
+		dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
+
+	if (!dev->tagger.mark_bad_fn)
+		dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
+
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h
new file mode 100644
index 0000000000..bf3e68a1a5
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_tagsmarshall.h
@@ -0,0 +1,22 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSMARSHALL_H__
+#define __YAFFS_TAGSMARSHALL_H__
+
+#include "yaffs_guts.h"
+void yaffs_tags_marshall_install(struct yaffs_dev *dev);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_trace.h b/target/linux/generic/files/fs/yaffs2/yaffs_trace.h
new file mode 100644
index 0000000000..fd26054d39
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_trace.h
@@ -0,0 +1,57 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YTRACE_H__
+#define __YTRACE_H__
+
+extern unsigned int yaffs_trace_mask;
+extern unsigned int yaffs_wr_attempts;
+
+/*
+ * Tracing flags.
+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
+ */
+
+#define YAFFS_TRACE_OS			0x00000002
+#define YAFFS_TRACE_ALLOCATE		0x00000004
+#define YAFFS_TRACE_SCAN		0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS		0x00000010
+#define YAFFS_TRACE_ERASE		0x00000020
+#define YAFFS_TRACE_GC			0x00000040
+#define YAFFS_TRACE_WRITE		0x00000080
+#define YAFFS_TRACE_TRACING		0x00000100
+#define YAFFS_TRACE_DELETION		0x00000200
+#define YAFFS_TRACE_BUFFERS		0x00000400
+#define YAFFS_TRACE_NANDACCESS		0x00000800
+#define YAFFS_TRACE_GC_DETAIL		0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG		0x00002000
+#define YAFFS_TRACE_MTD			0x00004000
+#define YAFFS_TRACE_CHECKPOINT		0x00008000
+
+#define YAFFS_TRACE_VERIFY		0x00010000
+#define YAFFS_TRACE_VERIFY_NAND		0x00020000
+#define YAFFS_TRACE_VERIFY_FULL		0x00040000
+#define YAFFS_TRACE_VERIFY_ALL		0x000f0000
+
+#define YAFFS_TRACE_SYNC		0x00100000
+#define YAFFS_TRACE_BACKGROUND		0x00200000
+#define YAFFS_TRACE_LOCK		0x00400000
+#define YAFFS_TRACE_MOUNT		0x00800000
+
+#define YAFFS_TRACE_ERROR		0x40000000
+#define YAFFS_TRACE_BUG			0x80000000
+#define YAFFS_TRACE_ALWAYS		0xf0000000
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_verify.c b/target/linux/generic/files/fs/yaffs2/yaffs_verify.c
new file mode 100644
index 0000000000..e8f2f0a6c2
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_verify.c
@@ -0,0 +1,529 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_verify.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+
+int yaffs_skip_verification(struct yaffs_dev *dev)
+{
+	(void) dev;
+	return !(yaffs_trace_mask &
+		 (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_skip_full_verification(struct yaffs_dev *dev)
+{
+	(void) dev;
+	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
+{
+	(void) dev;
+	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
+}
+
+static const char * const block_state_name[] = {
+	"Unknown",
+	"Needs scan",
+	"Scanning",
+	"Empty",
+	"Allocating",
+	"Full",
+	"Dirty",
+	"Checkpoint",
+	"Collecting",
+	"Dead"
+};
+
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
+{
+	int actually_used;
+	int in_use;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	/* Report illegal runtime states */
+	if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has undefined state %d",
+			n, bi->block_state);
+
+	switch (bi->block_state) {
+	case YAFFS_BLOCK_STATE_UNKNOWN:
+	case YAFFS_BLOCK_STATE_SCANNING:
+	case YAFFS_BLOCK_STATE_NEEDS_SCAN:
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has bad run-state %s",
+			n, block_state_name[bi->block_state]);
+	}
+
+	/* Check pages in use and soft deletions are legal */
+
+	actually_used = bi->pages_in_use - bi->soft_del_pages;
+
+	if (bi->pages_in_use < 0 ||
+	    bi->pages_in_use > dev->param.chunks_per_block ||
+	    bi->soft_del_pages < 0 ||
+	    bi->soft_del_pages > dev->param.chunks_per_block ||
+	    actually_used < 0 || actually_used > dev->param.chunks_per_block)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has illegal values pages_in_used %d soft_del_pages %d",
+			n, bi->pages_in_use, bi->soft_del_pages);
+
+	/* Check chunk bitmap legal */
+	in_use = yaffs_count_chunk_bits(dev, n);
+	if (in_use != bi->pages_in_use)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
+			n, bi->pages_in_use, in_use);
+}
+
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+				struct yaffs_block_info *bi, int n)
+{
+	yaffs_verify_blk(dev, bi, n);
+
+	/* After collection the block should be in the erased state */
+
+	if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
+	    bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Block %d is in state %d after gc, should be erased",
+			n, bi->block_state);
+	}
+}
+
+void yaffs_verify_blocks(struct yaffs_dev *dev)
+{
+	int i;
+	int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
+	int illegal_states = 0;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	memset(state_count, 0, sizeof(state_count));
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
+		yaffs_verify_blk(dev, bi, i);
+
+		if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
+			state_count[bi->block_state]++;
+		else
+			illegal_states++;
+	}
+
+	yaffs_trace(YAFFS_TRACE_VERIFY,	"Block summary");
+
+	yaffs_trace(YAFFS_TRACE_VERIFY,
+		"%d blocks have illegal states",
+		illegal_states);
+	if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Too many allocating blocks");
+
+	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"%s %d blocks",
+			block_state_name[i], state_count[i]);
+
+	if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Checkpoint block count wrong dev %d count %d",
+			dev->blocks_in_checkpt,
+			state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
+
+	if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Erased block count wrong dev %d count %d",
+			dev->n_erased_blocks,
+			state_count[YAFFS_BLOCK_STATE_EMPTY]);
+
+	if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Too many collecting blocks %d (max is 1)",
+			state_count[YAFFS_BLOCK_STATE_COLLECTING]);
+}
+
+/*
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in
+ * which case those tests will not be performed.
+ */
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+		     struct yaffs_ext_tags *tags, int parent_check)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+
+	if (!(tags && obj && oh)) {
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Verifying object header tags %p obj %p oh %p",
+			tags, obj, oh);
+		return;
+	}
+
+	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
+	    oh->type > YAFFS_OBJECT_TYPE_MAX)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header type is illegal value 0x%x",
+			tags->obj_id, oh->type);
+
+	if (tags->obj_id != obj->obj_id)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header mismatch obj_id %d",
+			tags->obj_id, obj->obj_id);
+
+	/*
+	 * Check that the object's parent ids match if parent_check requested.
+	 *
+	 * Tests do not apply to the root object.
+	 */
+
+	if (parent_check && tags->obj_id > 1 && !obj->parent)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header mismatch parent_id %d obj->parent is NULL",
+			tags->obj_id, oh->parent_obj_id);
+
+	if (parent_check && obj->parent &&
+	    oh->parent_obj_id != obj->parent->obj_id &&
+	    (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
+	     obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header mismatch parent_id %d parent_obj_id %d",
+			tags->obj_id, oh->parent_obj_id,
+			obj->parent->obj_id);
+
+	if (tags->obj_id > 1 && oh->name[0] == 0)	/* Null name */
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header name is NULL",
+			obj->obj_id);
+
+	if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff)	/* Junk name */
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header name is 0xff",
+			obj->obj_id);
+}
+
+void yaffs_verify_file(struct yaffs_obj *obj)
+{
+	u32 x;
+	int required_depth;
+	int actual_depth;
+	int last_chunk;
+	u32 offset_in_chunk;
+	u32 the_chunk;
+
+	u32 i;
+	struct yaffs_dev *dev;
+	struct yaffs_ext_tags tags;
+	struct yaffs_tnode *tn;
+	u32 obj_id;
+
+	if (!obj)
+		return;
+
+	if (yaffs_skip_verification(obj->my_dev))
+		return;
+
+	dev = obj->my_dev;
+	obj_id = obj->obj_id;
+
+
+	/* Check file size is consistent with tnode depth */
+	yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
+				&last_chunk, &offset_in_chunk);
+	last_chunk++;
+	x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
+	required_depth = 0;
+	while (x > 0) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		required_depth++;
+	}
+
+	actual_depth = obj->variant.file_variant.top_level;
+
+	/* Check that the chunks in the tnode tree are all correct.
+	 * We do this by scanning through the tnode tree and
+	 * checking the tags for every chunk match.
+	 */
+
+	if (yaffs_skip_nand_verification(dev))
+		return;
+
+	for (i = 1; i <= last_chunk; i++) {
+		tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
+
+		if (!tn)
+			continue;
+
+		the_chunk = yaffs_get_group_base(dev, tn, i);
+		if (the_chunk > 0) {
+			yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+						 &tags);
+			if (tags.obj_id != obj_id || tags.chunk_id != i)
+				yaffs_trace(YAFFS_TRACE_VERIFY,
+					"Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
+					obj_id, i, the_chunk,
+					tags.obj_id, tags.chunk_id);
+		}
+	}
+}
+
+void yaffs_verify_link(struct yaffs_obj *obj)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+
+	/* Verify sane equivalent object */
+}
+
+void yaffs_verify_symlink(struct yaffs_obj *obj)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+
+	/* Verify symlink string */
+}
+
+void yaffs_verify_special(struct yaffs_obj *obj)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+}
+
+void yaffs_verify_obj(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev;
+	u32 chunk_min;
+	u32 chunk_max;
+	u32 chunk_id_ok;
+	u32 chunk_in_range;
+	u32 chunk_wrongly_deleted;
+	u32 chunk_valid;
+
+	if (!obj)
+		return;
+
+	if (obj->being_created)
+		return;
+
+	dev = obj->my_dev;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	/* Check sane object header chunk */
+
+	chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
+	chunk_max =
+	    (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
+
+	chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
+			  ((unsigned)(obj->hdr_chunk)) <= chunk_max);
+	chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
+	chunk_valid = chunk_in_range &&
+	    yaffs_check_chunk_bit(dev,
+				  obj->hdr_chunk / dev->param.chunks_per_block,
+				  obj->hdr_chunk % dev->param.chunks_per_block);
+	chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
+
+	if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d has chunk_id %d %s %s",
+			obj->obj_id, obj->hdr_chunk,
+			chunk_id_ok ? "" : ",out of range",
+			chunk_wrongly_deleted ? ",marked as deleted" : "");
+
+	if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
+		struct yaffs_ext_tags tags;
+		struct yaffs_obj_hdr *oh;
+		u8 *buffer = yaffs_get_temp_buffer(dev);
+
+		oh = (struct yaffs_obj_hdr *)buffer;
+
+		yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
+
+		yaffs_verify_oh(obj, oh, &tags, 1);
+
+		yaffs_release_temp_buffer(dev, buffer);
+	}
+
+	/* Verify it has a parent */
+	if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d has parent pointer %p which does not look like an object",
+			obj->obj_id, obj->parent);
+	}
+
+	/* Verify parent is a directory */
+	if (obj->parent &&
+	    obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d's parent is not a directory (type %d)",
+			obj->obj_id, obj->parent->variant_type);
+	}
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		yaffs_verify_file(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		yaffs_verify_symlink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		yaffs_verify_dir(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		yaffs_verify_link(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		yaffs_verify_special(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+	default:
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d has illegaltype %d",
+		   obj->obj_id, obj->variant_type);
+		break;
+	}
+}
+
+void yaffs_verify_objects(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	int i;
+	struct list_head *lh;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	/* Iterate through the objects in each hash entry */
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		list_for_each(lh, &dev->obj_bucket[i].list) {
+			obj = list_entry(lh, struct yaffs_obj, hash_link);
+			yaffs_verify_obj(obj);
+		}
+	}
+}
+
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
+{
+	struct list_head *lh;
+	struct yaffs_obj *list_obj;
+	int count = 0;
+
+	if (!obj) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
+		BUG();
+		return;
+	}
+
+	if (yaffs_skip_verification(obj->my_dev))
+		return;
+
+	if (!obj->parent) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
+		BUG();
+		return;
+	}
+
+	if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
+		BUG();
+	}
+
+	/* Iterate through the objects in each hash entry */
+
+	list_for_each(lh, &obj->parent->variant.dir_variant.children) {
+		list_obj = list_entry(lh, struct yaffs_obj, siblings);
+		yaffs_verify_obj(list_obj);
+		if (obj == list_obj)
+			count++;
+	}
+
+	if (count != 1) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"Object in directory %d times",
+			count);
+		BUG();
+	}
+}
+
+void yaffs_verify_dir(struct yaffs_obj *directory)
+{
+	struct list_head *lh;
+	struct yaffs_obj *list_obj;
+
+	if (!directory) {
+		BUG();
+		return;
+	}
+
+	if (yaffs_skip_full_verification(directory->my_dev))
+		return;
+
+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"Directory has wrong type: %d",
+			directory->variant_type);
+		BUG();
+	}
+
+	/* Iterate through the objects in each hash entry */
+
+	list_for_each(lh, &directory->variant.dir_variant.children) {
+		list_obj = list_entry(lh, struct yaffs_obj, siblings);
+		if (list_obj->parent != directory) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"Object in directory list has wrong parent %p",
+				list_obj->parent);
+			BUG();
+		}
+		yaffs_verify_obj_in_dir(list_obj);
+	}
+}
+
+static int yaffs_free_verification_failures;
+
+void yaffs_verify_free_chunks(struct yaffs_dev *dev)
+{
+	int counted;
+	int difference;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	counted = yaffs_count_free_chunks(dev);
+
+	difference = dev->n_free_chunks - counted;
+
+	if (difference) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"Freechunks verification failure %d %d %d",
+			dev->n_free_chunks, counted, difference);
+		yaffs_free_verification_failures++;
+	}
+}
+
+int yaffs_verify_file_sane(struct yaffs_obj *in)
+{
+	(void) in;
+	return YAFFS_OK;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_verify.h b/target/linux/generic/files/fs/yaffs2/yaffs_verify.h
new file mode 100644
index 0000000000..4f4af8d29a
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_verify.h
@@ -0,0 +1,43 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_VERIFY_H__
+#define __YAFFS_VERIFY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
+		      int n);
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+				struct yaffs_block_info *bi, int n);
+void yaffs_verify_blocks(struct yaffs_dev *dev);
+
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+		     struct yaffs_ext_tags *tags, int parent_check);
+void yaffs_verify_file(struct yaffs_obj *obj);
+void yaffs_verify_link(struct yaffs_obj *obj);
+void yaffs_verify_symlink(struct yaffs_obj *obj);
+void yaffs_verify_special(struct yaffs_obj *obj);
+void yaffs_verify_obj(struct yaffs_obj *obj);
+void yaffs_verify_objects(struct yaffs_dev *dev);
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
+void yaffs_verify_dir(struct yaffs_obj *directory);
+void yaffs_verify_free_chunks(struct yaffs_dev *dev);
+
+int yaffs_verify_file_sane(struct yaffs_obj *obj);
+
+int yaffs_skip_verification(struct yaffs_dev *dev);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c b/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c
new file mode 100644
index 0000000000..864a5dc185
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c
@@ -0,0 +1,3665 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ * Acknowledgements:
+ * Luc van OostenRyck for numerous patches.
+ * Nick Bane for numerous patches.
+ * Nick Bane for 2.5/2.6 integration.
+ * Andras Toth for mknod rdev issue.
+ * Michael Fischer for finding the problem with inode inconsistency.
+ * Some code bodily lifted from JFFS
+ *
+ * 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.
+ */
+
+/*
+ *
+ * This is the file system front-end to YAFFS that hooks it up to
+ * the VFS.
+ *
+ * Special notes:
+ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
+ *         this superblock
+ * >> 2.6: sb->s_fs_info  points to the struct yaffs_dev associated with this
+ *         superblock
+ * >> inode->u.generic_ip points to the associated struct yaffs_obj.
+ */
+
+/*
+ * There are two variants of the VFS glue code. This variant should compile
+ * for any version of Linux.
+ */
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
+#define YAFFS_COMPILE_BACKGROUND
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
+#define YAFFS_COMPILE_FREEZER
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
+#define YAFFS_COMPILE_EXPORTFS
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
+#define YAFFS_USE_SETATTR_COPY
+#define YAFFS_USE_TRUNCATE_SETSIZE
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
+#define YAFFS_HAS_EVICT_INODE
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+#define YAFFS_NEW_FOLLOW_LINK 1
+#else
+#define YAFFS_NEW_FOLLOW_LINK 0
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define YAFFS_HAS_WRITE_SUPER
+#endif
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+#include <linux/config.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
+#include <linux/smp_lock.h>
+#endif
+#include <linux/pagemap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+#include <linux/namei.h>
+#endif
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+#include <linux/exportfs.h>
+#endif
+
+#ifdef YAFFS_COMPILE_BACKGROUND
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#endif
+#ifdef YAFFS_COMPILE_FREEZER
+#include <linux/freezer.h>
+#endif
+
+#include <asm/div64.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+#include <linux/statfs.h>
+
+#define UnlockPage(p) unlock_page(p)
+#define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)
+
+/* FIXME: use sb->s_id instead ? */
+#define yaffs_devname(sb, buf)	bdevname(sb->s_bdev, buf)
+
+#else
+
+#include <linux/locks.h>
+#define	BDEVNAME_SIZE		0
+#define	yaffs_devname(sb, buf)	kdevname(sb->s_dev)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
+#define __user
+#endif
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define YPROC_ROOT  (&proc_root)
+#else
+#define YPROC_ROOT  NULL
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define Y_INIT_TIMER(a)	init_timer(a)
+#else
+#define Y_INIT_TIMER(a)	init_timer_on_stack(a)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
+#define YAFFS_USE_WRITE_BEGIN_END 1
+#else
+#define YAFFS_USE_WRITE_BEGIN_END 0
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define YAFFS_SUPER_HAS_DIRTY
+#endif
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+#define set_nlink(inode, count)  do { (inode)->i_nlink = (count); } while(0)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
+{
+	uint64_t result = partition_size;
+	do_div(result, block_size);
+	return (uint32_t) result;
+}
+#else
+#define YCALCBLOCKS(s, b) ((s)/(b))
+#endif
+
+#include <linux/uaccess.h>
+#include <linux/mtd/mtd.h>
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_guts.h"
+#include "yaffs_attribs.h"
+
+#include "yaffs_linux.h"
+
+#include "yaffs_mtdif.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_getblockinfo.h"
+
+unsigned int yaffs_trace_mask =
+		YAFFS_TRACE_BAD_BLOCKS |
+		YAFFS_TRACE_ALWAYS |
+		0;
+
+unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
+unsigned int yaffs_auto_checkpoint = 1;
+unsigned int yaffs_gc_control = 1;
+unsigned int yaffs_bg_enable = 1;
+unsigned int yaffs_auto_select = 1;
+/* Module Parameters */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+module_param(yaffs_trace_mask, uint, 0644);
+module_param(yaffs_wr_attempts, uint, 0644);
+module_param(yaffs_auto_checkpoint, uint, 0644);
+module_param(yaffs_gc_control, uint, 0644);
+module_param(yaffs_bg_enable, uint, 0644);
+#else
+MODULE_PARM(yaffs_trace_mask, "i");
+MODULE_PARM(yaffs_wr_attempts, "i");
+MODULE_PARM(yaffs_auto_checkpoint, "i");
+MODULE_PARM(yaffs_gc_control, "i");
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+/* use iget and read_inode */
+#define Y_IGET(sb, inum) iget((sb), (inum))
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
+
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
+#else
+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
+#endif
+
+#define yaffs_inode_to_obj(iptr) \
+	((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
+#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#define yaffs_super_to_dev(sb)	((struct yaffs_dev *)sb->s_fs_info)
+#else
+#define yaffs_super_to_dev(sb)	((struct yaffs_dev *)sb->u.generic_sbp)
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+#define Y_CLEAR_INODE(i) clear_inode(i)
+#else
+#define Y_CLEAR_INODE(i) end_writeback(i)
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+#define YAFFS_USE_DIR_ITERATE
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0))
+#define YAFFS_NEW_PROCFS
+#include <linux/seq_file.h>
+#endif
+
+
+#define update_dir_time(dir) do {\
+			(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+		} while (0)
+
+static void yaffs_fill_inode_from_obj(struct inode *inode,
+				      struct yaffs_obj *obj);
+
+
+static void yaffs_gross_lock(struct yaffs_dev *dev)
+{
+	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
+	mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
+	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
+}
+
+static void yaffs_gross_unlock(struct yaffs_dev *dev)
+{
+	yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
+	mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
+}
+
+
+static int yaffs_readpage_nolock(struct file *f, struct page *pg)
+{
+	/* Lifted from jffs2 */
+
+	struct yaffs_obj *obj;
+	unsigned char *pg_buf;
+	int ret;
+	loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
+	struct yaffs_dev *dev;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_readpage_nolock at %lld, size %08x",
+		(long long)pos,
+		(unsigned)PAGE_CACHE_SIZE);
+
+	obj = yaffs_dentry_to_obj(f->f_dentry);
+
+	dev = obj->my_dev;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+	BUG_ON(!PageLocked(pg));
+#else
+	if (!PageLocked(pg))
+		PAGE_BUG(pg);
+#endif
+
+	pg_buf = kmap(pg);
+	/* FIXME: Can kmap fail? */
+
+	yaffs_gross_lock(dev);
+
+	ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
+
+	yaffs_gross_unlock(dev);
+
+	if (ret >= 0)
+		ret = 0;
+
+	if (ret) {
+		ClearPageUptodate(pg);
+		SetPageError(pg);
+	} else {
+		SetPageUptodate(pg);
+		ClearPageError(pg);
+	}
+
+	flush_dcache_page(pg);
+	kunmap(pg);
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
+	return ret;
+}
+
+static int yaffs_readpage_unlock(struct file *f, struct page *pg)
+{
+	int ret = yaffs_readpage_nolock(f, pg);
+	UnlockPage(pg);
+	return ret;
+}
+
+static int yaffs_readpage(struct file *f, struct page *pg)
+{
+	int ret;
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
+	ret = yaffs_readpage_unlock(f, pg);
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
+	return ret;
+}
+
+
+static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
+{
+	struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
+
+	if (lc)
+		lc->dirty = val;
+
+# ifdef YAFFS_SUPER_HAS_DIRTY
+	{
+		struct super_block *sb = lc->super;
+
+		if (sb)
+			sb->s_dirt = val;
+	}
+#endif
+
+}
+
+static void yaffs_set_super_dirty(struct yaffs_dev *dev)
+{
+	yaffs_set_super_dirty_val(dev, 1);
+}
+
+static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
+{
+	yaffs_set_super_dirty_val(dev, 0);
+}
+
+static int yaffs_check_super_dirty(struct yaffs_dev *dev)
+{
+	struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
+
+	if (lc && lc->dirty)
+		return 1;
+
+# ifdef YAFFS_SUPER_HAS_DIRTY
+	{
+		struct super_block *sb = lc->super;
+
+		if (sb && sb->s_dirt)
+			return 1;
+	}
+#endif
+	return 0;
+
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
+#else
+static int yaffs_writepage(struct page *page)
+#endif
+{
+	struct yaffs_dev *dev;
+	struct address_space *mapping = page->mapping;
+	struct inode *inode;
+	unsigned long end_index;
+	char *buffer;
+	struct yaffs_obj *obj;
+	int n_written = 0;
+	unsigned n_bytes;
+	loff_t i_size;
+
+	if (!mapping)
+		BUG();
+	inode = mapping->host;
+	if (!inode)
+		BUG();
+	i_size = i_size_read(inode);
+
+	end_index = i_size >> PAGE_CACHE_SHIFT;
+
+	if (page->index < end_index)
+		n_bytes = PAGE_CACHE_SIZE;
+	else {
+		n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
+
+		if (page->index > end_index || !n_bytes) {
+			yaffs_trace(YAFFS_TRACE_OS,
+				"yaffs_writepage at %lld, inode size = %lld!!",
+				((loff_t)page->index) << PAGE_CACHE_SHIFT,
+				inode->i_size);
+			yaffs_trace(YAFFS_TRACE_OS,
+				"                -> don't care!!");
+
+			zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+			set_page_writeback(page);
+			unlock_page(page);
+			end_page_writeback(page);
+			return 0;
+		}
+	}
+
+	if (n_bytes != PAGE_CACHE_SIZE)
+		zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
+
+	get_page(page);
+
+	buffer = kmap(page);
+
+	obj = yaffs_inode_to_obj(inode);
+	dev = obj->my_dev;
+	yaffs_gross_lock(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_writepage at %lld, size %08x",
+		((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
+	yaffs_trace(YAFFS_TRACE_OS,
+		"writepag0: obj = %lld, ino = %lld",
+		obj->variant.file_variant.file_size, inode->i_size);
+
+	n_written = yaffs_wr_file(obj, buffer,
+				  ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
+
+	yaffs_set_super_dirty(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"writepag1: obj = %lld, ino = %lld",
+		obj->variant.file_variant.file_size, inode->i_size);
+
+	yaffs_gross_unlock(dev);
+
+	kunmap(page);
+	set_page_writeback(page);
+	unlock_page(page);
+	end_page_writeback(page);
+	put_page(page);
+
+	return (n_written == n_bytes) ? 0 : -ENOSPC;
+}
+
+/* Space holding and freeing is done to ensure we have space available for write_begin/end */
+/* For now we just assume few parallel writes and check against a small number. */
+/* Todo: need to do this with a counter to handle parallel reads better */
+
+static ssize_t yaffs_hold_space(struct file *f)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+
+	int n_free_chunks;
+
+	obj = yaffs_dentry_to_obj(f->f_dentry);
+
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	n_free_chunks = yaffs_get_n_free_chunks(dev);
+
+	yaffs_gross_unlock(dev);
+
+	return (n_free_chunks > 20) ? 1 : 0;
+}
+
+static void yaffs_release_space(struct file *f)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+
+	obj = yaffs_dentry_to_obj(f->f_dentry);
+
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	yaffs_gross_unlock(dev);
+}
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+			     loff_t pos, unsigned len, unsigned flags,
+			     struct page **pagep, void **fsdata)
+{
+	struct page *pg = NULL;
+	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+
+	int ret = 0;
+	int space_held = 0;
+
+	/* Get a page */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+	pg = grab_cache_page_write_begin(mapping, index, flags);
+#else
+	pg = __grab_cache_page(mapping, index);
+#endif
+
+	*pagep = pg;
+	if (!pg) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	yaffs_trace(YAFFS_TRACE_OS,
+		"start yaffs_write_begin index %d(%x) uptodate %d",
+		(int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
+
+	/* Get fs space */
+	space_held = yaffs_hold_space(filp);
+
+	if (!space_held) {
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	/* Update page if required */
+
+	if (!Page_Uptodate(pg))
+		ret = yaffs_readpage_nolock(filp, pg);
+
+	if (ret)
+		goto out;
+
+	/* Happy path return */
+	yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
+
+	return 0;
+
+out:
+	yaffs_trace(YAFFS_TRACE_OS,
+		"end yaffs_write_begin fail returning %d", ret);
+	if (space_held)
+		yaffs_release_space(filp);
+	if (pg) {
+		unlock_page(pg);
+		page_cache_release(pg);
+	}
+	return ret;
+}
+
+#else
+
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+			       unsigned offset, unsigned to)
+{
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
+
+	if (!Page_Uptodate(pg))
+		return yaffs_readpage_nolock(f, pg);
+	return 0;
+}
+#endif
+
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+				loff_t * pos)
+{
+	struct yaffs_obj *obj;
+	int n_written;
+	loff_t ipos;
+	struct inode *inode;
+	struct yaffs_dev *dev;
+
+	obj = yaffs_dentry_to_obj(f->f_dentry);
+
+	if (!obj) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_file_write: hey obj is null!");
+                return -EINVAL;
+        }
+
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	inode = f->f_dentry->d_inode;
+
+	if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
+		ipos = inode->i_size;
+	else
+		ipos = *pos;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
+		(unsigned)n, (unsigned)n, obj->obj_id, ipos);
+
+	n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
+
+	yaffs_set_super_dirty(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_file_write: %d(%x) bytes written",
+		(unsigned)n, (unsigned)n);
+
+	if (n_written > 0) {
+		ipos += n_written;
+		*pos = ipos;
+		if (ipos > inode->i_size) {
+			inode->i_size = ipos;
+			inode->i_blocks = (ipos + 511) >> 9;
+
+			yaffs_trace(YAFFS_TRACE_OS,
+				"yaffs_file_write size updated to %lld bytes, %d blocks",
+				ipos, (int)(inode->i_blocks));
+		}
+
+	}
+	yaffs_gross_unlock(dev);
+	return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
+}
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+			   loff_t pos, unsigned len, unsigned copied,
+			   struct page *pg, void *fsdadata)
+{
+	int ret = 0;
+	void *addr, *kva;
+	uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
+
+	kva = kmap(pg);
+	addr = kva + offset_into_page;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_write_end addr %p pos %lld n_bytes %d",
+		addr, pos, copied);
+
+	ret = yaffs_file_write(filp, addr, copied, &pos);
+
+	if (ret != copied) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_write_end not same size ret %d  copied %d",
+			ret, copied);
+		SetPageError(pg);
+	}
+
+	kunmap(pg);
+
+	yaffs_release_space(filp);
+	unlock_page(pg);
+	page_cache_release(pg);
+	return ret;
+}
+#else
+
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+			      unsigned to)
+{
+	void *addr, *kva;
+
+	loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
+	int n_bytes = to - offset;
+	int n_written;
+
+	kva = kmap(pg);
+	addr = kva + offset;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_commit_write addr %p pos %lld n_bytes %d",
+		addr, pos, n_bytes);
+
+	n_written = yaffs_file_write(f, addr, n_bytes, &pos);
+
+	if (n_written != n_bytes) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_commit_write not same size n_written %d  n_bytes %d",
+			n_written, n_bytes);
+		SetPageError(pg);
+	}
+	kunmap(pg);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_commit_write returning %d",
+		n_written == n_bytes ? 0 : n_written);
+
+	return n_written == n_bytes ? 0 : n_written;
+}
+#endif
+
+static struct address_space_operations yaffs_file_address_operations = {
+	.readpage = yaffs_readpage,
+	.writepage = yaffs_writepage,
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+	.write_begin = yaffs_write_begin,
+	.write_end = yaffs_write_end,
+#else
+	.prepare_write = yaffs_prepare_write,
+	.commit_write = yaffs_commit_write,
+#endif
+};
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
+static int yaffs_file_flush(struct file *file)
+#endif
+{
+	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
+
+	struct yaffs_dev *dev = obj->my_dev;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_file_flush object %d (%s)",
+		obj->obj_id,
+		obj->dirty ? "dirty" : "clean");
+
+	yaffs_gross_lock(dev);
+
+	yaffs_flush_file(obj, 1, 0, 0);
+
+	yaffs_gross_unlock(dev);
+
+	return 0;
+}
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+static int yaffs_sync_object(struct file *file, int datasync)
+#else
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+			     int datasync)
+#endif
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+	struct dentry *dentry = file->f_path.dentry;
+#endif
+
+	obj = yaffs_dentry_to_obj(dentry);
+
+	dev = obj->my_dev;
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+		"yaffs_sync_object");
+	yaffs_gross_lock(dev);
+	yaffs_flush_file(obj, 1, datasync, 0);
+	yaffs_gross_unlock(dev);
+	return 0;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+static const struct file_operations yaffs_file_operations = {
+	.read = do_sync_read,
+	.write = do_sync_write,
+	.aio_read = generic_file_aio_read,
+	.aio_write = generic_file_aio_write,
+	.mmap = generic_file_mmap,
+	.flush = yaffs_file_flush,
+	.fsync = yaffs_sync_object,
+	.splice_read = generic_file_splice_read,
+	.splice_write = generic_file_splice_write,
+	.llseek = generic_file_llseek,
+};
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+
+static const struct file_operations yaffs_file_operations = {
+	.read = do_sync_read,
+	.write = do_sync_write,
+	.aio_read = generic_file_aio_read,
+	.aio_write = generic_file_aio_write,
+	.mmap = generic_file_mmap,
+	.flush = yaffs_file_flush,
+	.fsync = yaffs_sync_object,
+	.sendfile = generic_file_sendfile,
+};
+
+#else
+
+static const struct file_operations yaffs_file_operations = {
+	.read = generic_file_read,
+	.write = generic_file_write,
+	.mmap = generic_file_mmap,
+	.flush = yaffs_file_flush,
+	.fsync = yaffs_sync_object,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+	.sendfile = generic_file_sendfile,
+#endif
+};
+#endif
+
+
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+static void zero_user_segment(struct page *page, unsigned start, unsigned end)
+{
+	void *kaddr = kmap_atomic(page, KM_USER0);
+	memset(kaddr + start, 0, end - start);
+	kunmap_atomic(kaddr, KM_USER0);
+	flush_dcache_page(page);
+}
+#endif
+
+
+static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
+{
+#ifdef YAFFS_USE_TRUNCATE_SETSIZE
+	truncate_setsize(inode, newsize);
+	return 0;
+#else
+	truncate_inode_pages(&inode->i_data, newsize);
+	return 0;
+#endif
+
+}
+
+
+static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
+{
+#ifdef YAFFS_USE_SETATTR_COPY
+	setattr_copy(inode, attr);
+	return 0;
+#else
+	return inode_setattr(inode, attr);
+#endif
+
+}
+
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = 0;
+	struct yaffs_dev *dev;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_setattr of object %d",
+		yaffs_inode_to_obj(inode)->obj_id);
+#if 0
+	/* Fail if a requested resize >= 2GB */
+	if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
+		error = -EINVAL;
+#endif
+
+	if (error == 0)
+		error = inode_change_ok(inode, attr);
+	if (error == 0) {
+		int result;
+		if (!error) {
+			error = yaffs_vfs_setattr(inode, attr);
+			yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
+			if (attr->ia_valid & ATTR_SIZE) {
+				yaffs_vfs_setsize(inode, attr->ia_size);
+				inode->i_blocks = (inode->i_size + 511) >> 9;
+			}
+		}
+		dev = yaffs_inode_to_obj(inode)->my_dev;
+		if (attr->ia_valid & ATTR_SIZE) {
+			yaffs_trace(YAFFS_TRACE_OS,
+				"resize to %d(%x)",
+				(int)(attr->ia_size),
+				(int)(attr->ia_size));
+		}
+		yaffs_gross_lock(dev);
+		result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
+		if (result == YAFFS_OK) {
+			error = 0;
+		} else {
+			error = -EPERM;
+		}
+		yaffs_gross_unlock(dev);
+
+	}
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
+
+	return error;
+}
+
+static int yaffs_setxattr(struct dentry *dentry, const char *name,
+		   const void *value, size_t size, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = 0;
+	struct yaffs_dev *dev;
+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
+
+	if (error == 0) {
+		int result;
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		result = yaffs_set_xattrib(obj, name, value, size, flags);
+		if (result == YAFFS_OK)
+			error = 0;
+		else if (result < 0)
+			error = result;
+		yaffs_gross_unlock(dev);
+
+	}
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
+
+	return error;
+}
+
+static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
+			void *buff, size_t size)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = 0;
+	struct yaffs_dev *dev;
+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_getxattr \"%s\" from object %d",
+		name, obj->obj_id);
+
+	if (error == 0) {
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		error = yaffs_get_xattrib(obj, name, buff, size);
+		yaffs_gross_unlock(dev);
+
+	}
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
+
+	return error;
+}
+
+static int yaffs_removexattr(struct dentry *dentry, const char *name)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = 0;
+	struct yaffs_dev *dev;
+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_removexattr of object %d", obj->obj_id);
+
+	if (error == 0) {
+		int result;
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		result = yaffs_remove_xattrib(obj, name);
+		if (result == YAFFS_OK)
+			error = 0;
+		else if (result < 0)
+			error = result;
+		yaffs_gross_unlock(dev);
+
+	}
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_removexattr done returning %d", error);
+
+	return error;
+}
+
+static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = 0;
+	struct yaffs_dev *dev;
+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_listxattr of object %d", obj->obj_id);
+
+	if (error == 0) {
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		error = yaffs_list_xattrib(obj, buff, size);
+		yaffs_gross_unlock(dev);
+
+	}
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_listxattr done returning %d", error);
+
+	return error;
+}
+
+
+static const struct inode_operations yaffs_file_inode_operations = {
+	.setattr = yaffs_setattr,
+	.setxattr = yaffs_setxattr,
+	.getxattr = yaffs_getxattr,
+	.listxattr = yaffs_listxattr,
+	.removexattr = yaffs_removexattr,
+};
+
+
+static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
+			  int buflen)
+{
+	unsigned char *alias;
+	int ret;
+
+	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
+
+	yaffs_gross_unlock(dev);
+
+	if (!alias)
+		return -ENOMEM;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
+	ret = vfs_readlink(dentry, buffer, buflen, alias);
+#else
+	ret = readlink_copy(buffer, buflen, alias);
+#endif
+	kfree(alias);
+	return ret;
+}
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	void *ret;
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	int ret
+#endif
+	unsigned char *alias;
+	int ret_int = 0;
+	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
+	yaffs_gross_unlock(dev);
+
+	if (!alias) {
+		ret_int = -ENOMEM;
+		goto out;
+	}
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+	nd_set_link(nd, alias);
+	ret = alias;
+out:
+	if (ret_int)
+		ret = ERR_PTR(ret_int);
+	return ret;
+#else
+	ret = vfs_follow_link(nd, alias);
+	kfree(alias);
+out:
+	if (ret_int)
+		ret = ret_int;
+	return ret;
+#endif
+}
+
+
+#ifdef YAFFS_HAS_PUT_INODE
+
+/* For now put inode is just for debugging
+ * Put inode is called when the inode **structure** is put.
+ */
+static void yaffs_put_inode(struct inode *inode)
+{
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_put_inode: ino %d, count %d"),
+		(int)inode->i_ino, atomic_read(&inode->i_count);
+
+}
+#endif
+
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
+{
+	kfree(alias);
+}
+#endif
+
+static const struct inode_operations yaffs_symlink_inode_operations = {
+	.readlink = yaffs_readlink,
+	.follow_link = yaffs_follow_link,
+#if (YAFFS_NEW_FOLLOW_LINK == 1)
+	.put_link = yaffs_put_link,
+#endif
+	.setattr = yaffs_setattr,
+	.setxattr = yaffs_setxattr,
+	.getxattr = yaffs_getxattr,
+	.listxattr = yaffs_listxattr,
+	.removexattr = yaffs_removexattr,
+};
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+	struct inode *inode;
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
+
+	inode = iget_locked(sb, ino);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	if (!(inode->i_state & I_NEW))
+		return inode;
+
+	/* NB This is called as a side effect of other functions, but
+	 * we had to release the lock to prevent deadlocks, so
+	 * need to lock again.
+	 */
+
+	yaffs_gross_lock(dev);
+
+	obj = yaffs_find_by_number(dev, inode->i_ino);
+
+	yaffs_fill_inode_from_obj(inode, obj);
+
+	yaffs_gross_unlock(dev);
+
+	unlock_new_inode(inode);
+	return inode;
+}
+
+#else
+
+static void yaffs_read_inode(struct inode *inode)
+{
+	/* NB This is called as a side effect of other functions, but
+	 * we had to release the lock to prevent deadlocks, so
+	 * need to lock again.
+	 */
+
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_read_inode for %d", (int)inode->i_ino);
+
+	if (current != yaffs_dev_to_lc(dev)->readdir_process)
+		yaffs_gross_lock(dev);
+
+	obj = yaffs_find_by_number(dev, inode->i_ino);
+
+	yaffs_fill_inode_from_obj(inode, obj);
+
+	if (current != yaffs_dev_to_lc(dev)->readdir_process)
+		yaffs_gross_unlock(dev);
+}
+
+#endif
+
+
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+			      struct yaffs_obj *obj)
+{
+	struct inode *inode;
+
+	if (!sb) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_get_inode for NULL super_block!!");
+		return NULL;
+
+	}
+
+	if (!obj) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_get_inode for NULL object!!");
+		return NULL;
+
+	}
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_get_inode for object %d", obj->obj_id);
+
+	inode = Y_IGET(sb, obj->obj_id);
+	if (IS_ERR(inode))
+		return NULL;
+
+	/* NB Side effect: iget calls back to yaffs_read_inode(). */
+	/* iget also increments the inode's i_count */
+	/* NB You can't be holding gross_lock or deadlock will happen! */
+
+	return inode;
+}
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#define YCRED(x) x
+#else
+#define YCRED(x) (x->cred)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#define YPROC_uid(p) (YCRED(p)->fsuid)
+#define YPROC_gid(p) (YCRED(p)->fsgid)
+#define EXTRACT_gid(x) x
+#define EXTRACT_uid(x) x
+#define MAKE_gid(x) x
+#define MAKE_uid(x) x
+#else
+#define YPROC_uid(p) from_kuid(&init_user_ns, YCRED(p)->fsuid)
+#define YPROC_gid(p) from_kgid(&init_user_ns, YCRED(p)->fsgid)
+#define EXTRACT_gid(x) from_kgid(&init_user_ns, x)
+#define EXTRACT_uid(x) from_kuid(&init_user_ns, x)
+#define MAKE_gid(x) make_kgid(&init_user_ns, x)
+#define MAKE_uid(x) make_kuid(&init_user_ns, x)
+#endif
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+		       dev_t rdev)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+		       dev_t rdev)
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+		       int rdev)
+#endif
+{
+	struct inode *inode;
+
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_dev *dev;
+
+	struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
+
+	int error = -ENOSPC;
+	uid_t uid = YPROC_uid(current);
+	gid_t gid =
+	    (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
+
+	if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
+		mode |= S_ISGID;
+
+	if (parent) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_mknod: parent object %d type %d",
+			parent->obj_id, parent->variant_type);
+	} else {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_mknod: could not get parent object");
+		return -EPERM;
+	}
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_mknod: making oject for %s, mode %x dev %x",
+		dentry->d_name.name, mode, rdev);
+
+	dev = parent->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	switch (mode & S_IFMT) {
+	default:
+		/* Special (socket, fifo, device...) */
+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+		obj =
+		    yaffs_create_special(parent, dentry->d_name.name, mode, uid,
+					 gid, old_encode_dev(rdev));
+#else
+		obj =
+		    yaffs_create_special(parent, dentry->d_name.name, mode, uid,
+					 gid, rdev);
+#endif
+		break;
+	case S_IFREG:		/* file          */
+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
+		obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
+					gid);
+		break;
+	case S_IFDIR:		/* directory */
+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
+		obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
+				       uid, gid);
+		break;
+	case S_IFLNK:		/* symlink */
+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
+		obj = NULL;	/* Do we ever get here? */
+		break;
+	}
+
+	/* Can not call yaffs_get_inode() with gross lock held */
+	yaffs_gross_unlock(dev);
+
+	if (obj) {
+		inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+		d_instantiate(dentry, inode);
+		update_dir_time(dir);
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_mknod created object %d count = %d",
+			obj->obj_id, atomic_read(&inode->i_count));
+		error = 0;
+		yaffs_fill_inode_from_obj(dir, parent);
+	} else {
+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
+		error = -ENOMEM;
+	}
+
+	return error;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+#else
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+	int ret_val;
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
+	ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+	return ret_val;
+}
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+			bool dummy)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+			struct nameidata *n)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+			struct nameidata *n)
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
+	return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+				   unsigned int dummy)
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+				   struct nameidata *n)
+#else
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
+#endif
+{
+	struct yaffs_obj *obj;
+	struct inode *inode = NULL;	/* NCB 2.5/2.6 needs NULL here */
+
+	struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
+
+	if (current != yaffs_dev_to_lc(dev)->readdir_process)
+		yaffs_gross_lock(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
+		yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
+
+	obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
+
+	obj = yaffs_get_equivalent_obj(obj);	/* in case it was a hardlink */
+
+	/* Can't hold gross lock when calling yaffs_get_inode() */
+	if (current != yaffs_dev_to_lc(dev)->readdir_process)
+		yaffs_gross_unlock(dev);
+
+	if (obj) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_lookup found %d", obj->obj_id);
+
+		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+	} else {
+		yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
+
+	}
+
+/* added NCB for 2.5/6 compatability - forces add even if inode is
+ * NULL which creates dentry hash */
+	d_add(dentry, inode);
+
+	return NULL;
+}
+
+/*
+ * Create a link...
+ */
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+		      struct dentry *dentry)
+{
+	struct inode *inode = old_dentry->d_inode;
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *link = NULL;
+	struct yaffs_dev *dev;
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
+
+	obj = yaffs_inode_to_obj(inode);
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	if (!S_ISDIR(inode->i_mode))	/* Don't link directories */
+		link =
+		    yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
+				   obj);
+
+	if (link) {
+		set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
+		d_instantiate(dentry, old_dentry->d_inode);
+		atomic_inc(&old_dentry->d_inode->i_count);
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_link link count %d i_count %d",
+			old_dentry->d_inode->i_nlink,
+			atomic_read(&old_dentry->d_inode->i_count));
+	}
+
+	yaffs_gross_unlock(dev);
+
+	if (link) {
+		update_dir_time(dir);
+		return 0;
+	}
+
+	return -EPERM;
+}
+
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+			 const char *symname)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+	uid_t uid = YPROC_uid(current);
+	gid_t gid =
+	    (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
+
+	if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
+				YAFFS_MAX_NAME_LENGTH)
+		return -ENAMETOOLONG;
+
+	if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
+				YAFFS_MAX_ALIAS_LENGTH)
+		return -ENAMETOOLONG;
+
+	dev = yaffs_inode_to_obj(dir)->my_dev;
+	yaffs_gross_lock(dev);
+	obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
+				   S_IFLNK | S_IRWXUGO, uid, gid, symname);
+	yaffs_gross_unlock(dev);
+
+	if (obj) {
+		struct inode *inode;
+
+		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+		d_instantiate(dentry, inode);
+		update_dir_time(dir);
+		yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
+		return 0;
+	} else {
+		yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
+	}
+
+	return -ENOMEM;
+}
+
+/*
+ * The VFS layer already does all the dentry stuff for rename.
+ *
+ * NB: POSIX says you can rename an object over an old object of the same name
+ */
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+			struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct yaffs_dev *dev;
+	int ret_val = YAFFS_FAIL;
+	struct yaffs_obj *target;
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
+	dev = yaffs_inode_to_obj(old_dir)->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	/* Check if the target is an existing directory that is not empty. */
+	target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
+				    new_dentry->d_name.name);
+
+	if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
+	    !list_empty(&target->variant.dir_variant.children)) {
+
+		yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
+
+		ret_val = YAFFS_FAIL;
+	} else {
+		/* Now does unlinking internally using shadowing mechanism */
+		yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
+
+		ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
+					   old_dentry->d_name.name,
+					   yaffs_inode_to_obj(new_dir),
+					   new_dentry->d_name.name);
+	}
+	yaffs_gross_unlock(dev);
+
+	if (ret_val == YAFFS_OK) {
+		if (target)
+			inode_dec_link_count(new_dentry->d_inode);
+
+		update_dir_time(old_dir);
+		if (old_dir != new_dir)
+			update_dir_time(new_dir);
+		return 0;
+	} else {
+		return -ENOTEMPTY;
+	}
+}
+
+
+
+
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	int ret_val;
+
+	struct yaffs_dev *dev;
+	struct yaffs_obj *obj;
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
+		(int)(dir->i_ino), dentry->d_name.name);
+	obj = yaffs_inode_to_obj(dir);
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	ret_val = yaffs_unlinker(obj, dentry->d_name.name);
+
+	if (ret_val == YAFFS_OK) {
+		inode_dec_link_count(dentry->d_inode);
+		dir->i_version++;
+		yaffs_gross_unlock(dev);
+		update_dir_time(dir);
+		return 0;
+	}
+	yaffs_gross_unlock(dev);
+	return -ENOTEMPTY;
+}
+
+
+
+static const struct inode_operations yaffs_dir_inode_operations = {
+	.create = yaffs_create,
+	.lookup = yaffs_lookup,
+	.link = yaffs_link,
+	.unlink = yaffs_unlink,
+	.symlink = yaffs_symlink,
+	.mkdir = yaffs_mkdir,
+	.rmdir = yaffs_unlink,
+	.mknod = yaffs_mknod,
+	.rename = yaffs_rename,
+	.setattr = yaffs_setattr,
+	.setxattr = yaffs_setxattr,
+	.getxattr = yaffs_getxattr,
+	.listxattr = yaffs_listxattr,
+	.removexattr = yaffs_removexattr,
+};
+
+/*-----------------------------------------------------------------*/
+/* Directory search context allows us to unlock access to yaffs during
+ * filldir without causing problems with the directory being modified.
+ * This is similar to the tried and tested mechanism used in yaffs direct.
+ *
+ * A search context iterates along a doubly linked list of siblings in the
+ * directory. If the iterating object is deleted then this would corrupt
+ * the list iteration, likely causing a crash. The search context avoids
+ * this by using the remove_obj_fn to move the search context to the
+ * next object before the object is deleted.
+ *
+ * Many readdirs (and thus seach conexts) may be alive simulateously so
+ * each struct yaffs_dev has a list of these.
+ *
+ * A seach context lives for the duration of a readdir.
+ *
+ * All these functions must be called while yaffs is locked.
+ */
+
+struct yaffs_search_context {
+	struct yaffs_dev *dev;
+	struct yaffs_obj *dir_obj;
+	struct yaffs_obj *next_return;
+	struct list_head others;
+};
+
+/*
+ * yaffs_new_search() creates a new search context, initialises it and
+ * adds it to the device's search context list.
+ *
+ * Called at start of readdir.
+ */
+static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
+{
+	struct yaffs_dev *dev = dir->my_dev;
+	struct yaffs_search_context *sc =
+	    kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
+	if (sc) {
+		sc->dir_obj = dir;
+		sc->dev = dev;
+		if (list_empty(&sc->dir_obj->variant.dir_variant.children))
+			sc->next_return = NULL;
+		else
+			sc->next_return =
+			    list_entry(dir->variant.dir_variant.children.next,
+				       struct yaffs_obj, siblings);
+		INIT_LIST_HEAD(&sc->others);
+		list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
+	}
+	return sc;
+}
+
+/*
+ * yaffs_search_end() disposes of a search context and cleans up.
+ */
+static void yaffs_search_end(struct yaffs_search_context *sc)
+{
+	if (sc) {
+		list_del(&sc->others);
+		kfree(sc);
+	}
+}
+
+/*
+ * yaffs_search_advance() moves a search context to the next object.
+ * Called when the search iterates or when an object removal causes
+ * the search context to be moved to the next object.
+ */
+static void yaffs_search_advance(struct yaffs_search_context *sc)
+{
+	if (!sc)
+		return;
+
+	if (sc->next_return == NULL ||
+	    list_empty(&sc->dir_obj->variant.dir_variant.children))
+		sc->next_return = NULL;
+	else {
+		struct list_head *next = sc->next_return->siblings.next;
+
+		if (next == &sc->dir_obj->variant.dir_variant.children)
+			sc->next_return = NULL;	/* end of list */
+		else
+			sc->next_return =
+			    list_entry(next, struct yaffs_obj, siblings);
+	}
+}
+
+/*
+ * yaffs_remove_obj_callback() is called when an object is unlinked.
+ * We check open search contexts and advance any which are currently
+ * on the object being iterated.
+ */
+static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
+{
+
+	struct list_head *i;
+	struct yaffs_search_context *sc;
+	struct list_head *search_contexts =
+	    &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
+
+	/* Iterate through the directory search contexts.
+	 * If any are currently on the object being removed, then advance
+	 * the search context to the next object to prevent a hanging pointer.
+	 */
+	list_for_each(i, search_contexts) {
+		sc = list_entry(i, struct yaffs_search_context, others);
+		if (sc->next_return == obj)
+			yaffs_search_advance(sc);
+	}
+
+}
+
+
+/*-----------------------------------------------------------------*/
+
+#ifdef YAFFS_USE_DIR_ITERATE
+static int yaffs_iterate(struct file *f, struct dir_context *dc)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+	struct yaffs_search_context *sc;
+	unsigned long curoffs;
+	struct yaffs_obj *l;
+	int ret_val = 0;
+
+	char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+	obj = yaffs_dentry_to_obj(f->f_dentry);
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	yaffs_dev_to_lc(dev)->readdir_process = current;
+
+	sc = yaffs_new_search(obj);
+	if (!sc) {
+		ret_val = -ENOMEM;
+		goto out;
+	}
+
+	if (!dir_emit_dots(f, dc))
+		return 0;
+
+	curoffs = 1;
+
+	while (sc->next_return) {
+		curoffs++;
+		l = sc->next_return;
+		if (curoffs >= dc->pos) {
+			int this_inode = yaffs_get_obj_inode(l);
+			int this_type = yaffs_get_obj_type(l);
+
+			yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
+			yaffs_trace(YAFFS_TRACE_OS,
+				"yaffs_readdir: %s inode %d",
+				name, yaffs_get_obj_inode(l));
+
+			yaffs_gross_unlock(dev);
+
+			if (!dir_emit(dc,
+				      name,
+				      strlen(name),
+				      this_inode,
+				      this_type)) {
+				yaffs_gross_lock(dev);
+				goto out;
+			}
+
+			yaffs_gross_lock(dev);
+
+			dc->pos++;
+			f->f_pos++;
+		}
+		yaffs_search_advance(sc);
+	}
+
+out:
+	yaffs_search_end(sc);
+	yaffs_dev_to_lc(dev)->readdir_process = NULL;
+	yaffs_gross_unlock(dev);
+
+	return ret_val;
+}
+
+#else
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+	struct yaffs_search_context *sc;
+	struct inode *inode = f->f_dentry->d_inode;
+	unsigned long offset, curoffs;
+	struct yaffs_obj *l;
+	int ret_val = 0;
+
+	char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+	obj = yaffs_dentry_to_obj(f->f_dentry);
+	dev = obj->my_dev;
+
+	yaffs_gross_lock(dev);
+
+	yaffs_dev_to_lc(dev)->readdir_process = current;
+
+	offset = f->f_pos;
+
+	sc = yaffs_new_search(obj);
+	if (!sc) {
+		ret_val = -ENOMEM;
+		goto out;
+	}
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_readdir: starting at %d", (int)offset);
+
+	if (offset == 0) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_readdir: entry . ino %d",
+			(int)inode->i_ino);
+		yaffs_gross_unlock(dev);
+		if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
+			yaffs_gross_lock(dev);
+			goto out;
+		}
+		yaffs_gross_lock(dev);
+		offset++;
+		f->f_pos++;
+	}
+	if (offset == 1) {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_readdir: entry .. ino %d",
+			(int)f->f_dentry->d_parent->d_inode->i_ino);
+		yaffs_gross_unlock(dev);
+		if (filldir(dirent, "..", 2, offset,
+			    f->f_dentry->d_parent->d_inode->i_ino,
+			    DT_DIR) < 0) {
+			yaffs_gross_lock(dev);
+			goto out;
+		}
+		yaffs_gross_lock(dev);
+		offset++;
+		f->f_pos++;
+	}
+
+	curoffs = 1;
+
+	/* If the directory has changed since the open or last call to
+	   readdir, rewind to after the 2 canned entries. */
+	if (f->f_version != inode->i_version) {
+		offset = 2;
+		f->f_pos = offset;
+		f->f_version = inode->i_version;
+	}
+
+	while (sc->next_return) {
+		curoffs++;
+		l = sc->next_return;
+		if (curoffs >= offset) {
+			int this_inode = yaffs_get_obj_inode(l);
+			int this_type = yaffs_get_obj_type(l);
+
+			yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
+			yaffs_trace(YAFFS_TRACE_OS,
+				"yaffs_readdir: %s inode %d",
+				name, yaffs_get_obj_inode(l));
+
+			yaffs_gross_unlock(dev);
+
+			if (filldir(dirent,
+				    name,
+				    strlen(name),
+				    offset, this_inode, this_type) < 0) {
+				yaffs_gross_lock(dev);
+				goto out;
+			}
+
+			yaffs_gross_lock(dev);
+
+			offset++;
+			f->f_pos++;
+		}
+		yaffs_search_advance(sc);
+	}
+
+out:
+	yaffs_search_end(sc);
+	yaffs_dev_to_lc(dev)->readdir_process = NULL;
+	yaffs_gross_unlock(dev);
+
+	return ret_val;
+}
+
+#endif
+
+static const struct file_operations yaffs_dir_operations = {
+	.read = generic_read_dir,
+#ifdef YAFFS_USE_DIR_ITERATE
+	.iterate = yaffs_iterate,
+#else
+	.readdir = yaffs_readdir,
+#endif
+	.fsync = yaffs_sync_object,
+	.llseek = generic_file_llseek,
+};
+
+static void yaffs_fill_inode_from_obj(struct inode *inode,
+				      struct yaffs_obj *obj)
+{
+	if (inode && obj) {
+
+		/* Check mode against the variant type and attempt to repair if broken. */
+		u32 mode = obj->yst_mode;
+		switch (obj->variant_type) {
+		case YAFFS_OBJECT_TYPE_FILE:
+			if (!S_ISREG(mode)) {
+				obj->yst_mode &= ~S_IFMT;
+				obj->yst_mode |= S_IFREG;
+			}
+
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			if (!S_ISLNK(mode)) {
+				obj->yst_mode &= ~S_IFMT;
+				obj->yst_mode |= S_IFLNK;
+			}
+
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			if (!S_ISDIR(mode)) {
+				obj->yst_mode &= ~S_IFMT;
+				obj->yst_mode |= S_IFDIR;
+			}
+
+			break;
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+		default:
+			/* TODO? */
+			break;
+		}
+
+		inode->i_flags |= S_NOATIME;
+
+		inode->i_ino = obj->obj_id;
+		inode->i_mode = obj->yst_mode;
+		inode->i_uid = MAKE_uid(obj->yst_uid);
+		inode->i_gid = MAKE_gid(obj->yst_gid);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+		inode->i_blksize = inode->i_sb->s_blocksize;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+		inode->i_rdev = old_decode_dev(obj->yst_rdev);
+		inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+		inode->i_atime.tv_nsec = 0;
+		inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+		inode->i_mtime.tv_nsec = 0;
+		inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+		inode->i_ctime.tv_nsec = 0;
+#else
+		inode->i_rdev = obj->yst_rdev;
+		inode->i_atime = obj->yst_atime;
+		inode->i_mtime = obj->yst_mtime;
+		inode->i_ctime = obj->yst_ctime;
+#endif
+		inode->i_size = yaffs_get_obj_length(obj);
+		inode->i_blocks = (inode->i_size + 511) >> 9;
+
+		set_nlink(inode, yaffs_get_obj_link_count(obj));
+
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
+			inode->i_mode, obj->yst_uid, obj->yst_gid,
+			inode->i_size, atomic_read(&inode->i_count));
+
+		switch (obj->yst_mode & S_IFMT) {
+		default:	/* fifo, device or socket */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+			init_special_inode(inode, obj->yst_mode,
+					   old_decode_dev(obj->yst_rdev));
+#else
+			init_special_inode(inode, obj->yst_mode,
+					   (dev_t) (obj->yst_rdev));
+#endif
+			break;
+		case S_IFREG:	/* file */
+			inode->i_op = &yaffs_file_inode_operations;
+			inode->i_fop = &yaffs_file_operations;
+			inode->i_mapping->a_ops =
+			    &yaffs_file_address_operations;
+			break;
+		case S_IFDIR:	/* directory */
+			inode->i_op = &yaffs_dir_inode_operations;
+			inode->i_fop = &yaffs_dir_operations;
+			break;
+		case S_IFLNK:	/* symlink */
+			inode->i_op = &yaffs_symlink_inode_operations;
+			break;
+		}
+
+		yaffs_inode_to_obj_lv(inode) = obj;
+
+		obj->my_inode = inode;
+
+	} else {
+		yaffs_trace(YAFFS_TRACE_OS,
+			"yaffs_fill_inode invalid parameters");
+	}
+
+}
+
+
+
+/*
+ * yaffs background thread functions .
+ * yaffs_bg_thread_fn() the thread function
+ * yaffs_bg_start() launches the background thread.
+ * yaffs_bg_stop() cleans up the background thread.
+ *
+ * NB:
+ * The thread should only run after the yaffs is initialised
+ * The thread should be stopped before yaffs is unmounted.
+ * The thread should not do any writing while the fs is in read only.
+ */
+
+static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
+{
+	unsigned erased_chunks =
+	    dev->n_erased_blocks * dev->param.chunks_per_block;
+	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
+	unsigned scattered = 0;	/* Free chunks not in an erased block */
+
+	if (erased_chunks < dev->n_free_chunks)
+		scattered = (dev->n_free_chunks - erased_chunks);
+
+	if (!context->bg_running)
+		return 0;
+	else if (scattered < (dev->param.chunks_per_block * 2))
+		return 0;
+	else if (erased_chunks > dev->n_free_chunks / 2)
+		return 0;
+	else if (erased_chunks > dev->n_free_chunks / 4)
+		return 1;
+	else
+		return 2;
+}
+
+#ifdef YAFFS_COMPILE_BACKGROUND
+
+void yaffs_background_waker(unsigned long data)
+{
+	wake_up_process((struct task_struct *)data);
+}
+
+static int yaffs_bg_thread_fn(void *data)
+{
+	struct yaffs_dev *dev = (struct yaffs_dev *)data;
+	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
+	unsigned long now = jiffies;
+	unsigned long next_dir_update = now;
+	unsigned long next_gc = now;
+	unsigned long expires;
+	unsigned int urgency;
+
+	int gc_result;
+	struct timer_list timer;
+
+	yaffs_trace(YAFFS_TRACE_BACKGROUND,
+		"yaffs_background starting for dev %p", (void *)dev);
+
+#ifdef YAFFS_COMPILE_FREEZER
+	set_freezable();
+#endif
+	while (context->bg_running) {
+		yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
+
+		if (kthread_should_stop())
+			break;
+
+#ifdef YAFFS_COMPILE_FREEZER
+		if (try_to_freeze())
+			continue;
+#endif
+		yaffs_gross_lock(dev);
+
+		now = jiffies;
+
+		if (time_after(now, next_dir_update) && yaffs_bg_enable) {
+			yaffs_update_dirty_dirs(dev);
+			next_dir_update = now + HZ;
+		}
+
+		if (time_after(now, next_gc) && yaffs_bg_enable) {
+			if (!dev->is_checkpointed) {
+				urgency = yaffs_bg_gc_urgency(dev);
+				gc_result = yaffs_bg_gc(dev, urgency);
+				if (urgency > 1)
+					next_gc = now + HZ / 20 + 1;
+				else if (urgency > 0)
+					next_gc = now + HZ / 10 + 1;
+				else
+					next_gc = now + HZ * 2;
+			} else	{
+			        /*
+				 * gc not running so set to next_dir_update
+				 * to cut down on wake ups
+				 */
+				next_gc = next_dir_update;
+                        }
+		}
+		yaffs_gross_unlock(dev);
+#if 1
+		expires = next_dir_update;
+		if (time_before(next_gc, expires))
+			expires = next_gc;
+		if (time_before(expires, now))
+			expires = now + HZ;
+
+		Y_INIT_TIMER(&timer);
+		timer.expires = expires + 1;
+		timer.data = (unsigned long)current;
+		timer.function = yaffs_background_waker;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_timer(&timer);
+		schedule();
+		del_timer_sync(&timer);
+#else
+		msleep(10);
+#endif
+	}
+
+	return 0;
+}
+
+static int yaffs_bg_start(struct yaffs_dev *dev)
+{
+	int retval = 0;
+	struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
+
+	if (dev->read_only)
+		return -1;
+
+	context->bg_running = 1;
+
+	context->bg_thread = kthread_run(yaffs_bg_thread_fn,
+					 (void *)dev, "yaffs-bg-%d",
+					 context->mount_id);
+
+	if (IS_ERR(context->bg_thread)) {
+		retval = PTR_ERR(context->bg_thread);
+		context->bg_thread = NULL;
+		context->bg_running = 0;
+	}
+	return retval;
+}
+
+static void yaffs_bg_stop(struct yaffs_dev *dev)
+{
+	struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
+
+	ctxt->bg_running = 0;
+
+	if (ctxt->bg_thread) {
+		kthread_stop(ctxt->bg_thread);
+		ctxt->bg_thread = NULL;
+	}
+}
+#else
+static int yaffs_bg_thread_fn(void *data)
+{
+	return 0;
+}
+
+static int yaffs_bg_start(struct yaffs_dev *dev)
+{
+	return 0;
+}
+
+static void yaffs_bg_stop(struct yaffs_dev *dev)
+{
+}
+#endif
+
+
+static void yaffs_flush_inodes(struct super_block *sb)
+{
+	struct inode *iptr;
+	struct yaffs_obj *obj;
+
+	list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
+		obj = yaffs_inode_to_obj(iptr);
+		if (obj) {
+			yaffs_trace(YAFFS_TRACE_OS,
+				"flushing obj %d",
+				obj->obj_id);
+			yaffs_flush_file(obj, 1, 0, 0);
+		}
+	}
+}
+
+static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
+{
+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+	if (!dev)
+		return;
+
+	yaffs_flush_inodes(sb);
+	yaffs_update_dirty_dirs(dev);
+	yaffs_flush_whole_cache(dev, 1);
+	if (do_checkpoint)
+		yaffs_checkpoint_save(dev);
+}
+
+static LIST_HEAD(yaffs_context_list);
+struct mutex yaffs_context_lock;
+
+static void yaffs_put_super(struct super_block *sb)
+{
+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
+			"yaffs_put_super");
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+		"Shutting down yaffs background thread");
+	yaffs_bg_stop(dev);
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+		"yaffs background thread shut down");
+
+	yaffs_gross_lock(dev);
+
+	yaffs_flush_super(sb, 1);
+
+	yaffs_deinitialise(dev);
+
+	yaffs_gross_unlock(dev);
+
+	mutex_lock(&yaffs_context_lock);
+	list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
+	mutex_unlock(&yaffs_context_lock);
+
+	if (yaffs_dev_to_lc(dev)->spare_buffer) {
+		kfree(yaffs_dev_to_lc(dev)->spare_buffer);
+		yaffs_dev_to_lc(dev)->spare_buffer = NULL;
+	}
+
+	kfree(dev);
+
+	yaffs_put_mtd_device(mtd);
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
+			"yaffs_put_super done");
+}
+
+
+static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
+{
+	return yaffs_gc_control;
+}
+
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+
+static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
+					  uint32_t generation)
+{
+	return Y_IGET(sb, ino);
+}
+
+static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
+					  struct fid *fid, int fh_len,
+					  int fh_type)
+{
+	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+				    yaffs2_nfs_get_inode);
+}
+
+static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
+					  struct fid *fid, int fh_len,
+					  int fh_type)
+{
+	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+				    yaffs2_nfs_get_inode);
+}
+
+struct dentry *yaffs2_get_parent(struct dentry *dentry)
+{
+
+	struct super_block *sb = dentry->d_inode->i_sb;
+	struct dentry *parent = ERR_PTR(-ENOENT);
+	struct inode *inode;
+	unsigned long parent_ino;
+	struct yaffs_obj *d_obj;
+	struct yaffs_obj *parent_obj;
+
+	d_obj = yaffs_inode_to_obj(dentry->d_inode);
+
+	if (d_obj) {
+		parent_obj = d_obj->parent;
+		if (parent_obj) {
+			parent_ino = yaffs_get_obj_inode(parent_obj);
+			inode = Y_IGET(sb, parent_ino);
+
+			if (IS_ERR(inode)) {
+				parent = ERR_CAST(inode);
+			} else {
+				parent = d_obtain_alias(inode);
+				if (!IS_ERR(parent)) {
+					parent = ERR_PTR(-ENOMEM);
+					iput(inode);
+				}
+			}
+		}
+	}
+
+	return parent;
+}
+
+/* Just declare a zero structure as a NULL value implies
+ * using the default functions of exportfs.
+ */
+
+static struct export_operations yaffs_export_ops = {
+	.fh_to_dentry = yaffs2_fh_to_dentry,
+	.fh_to_parent = yaffs2_fh_to_parent,
+	.get_parent = yaffs2_get_parent,
+};
+
+#endif
+
+static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
+{
+	/* Clear the association between the inode and
+	 * the struct yaffs_obj.
+	 */
+	obj->my_inode = NULL;
+	yaffs_inode_to_obj_lv(inode) = NULL;
+
+	/* If the object freeing was deferred, then the real
+	 * free happens now.
+	 * This should fix the inode inconsistency problem.
+	 */
+	yaffs_handle_defered_free(obj);
+}
+
+#ifdef YAFFS_HAS_EVICT_INODE
+/* yaffs_evict_inode combines into one operation what was previously done in
+ * yaffs_clear_inode() and yaffs_delete_inode()
+ *
+ */
+static void yaffs_evict_inode(struct inode *inode)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+	int deleteme = 0;
+
+	obj = yaffs_inode_to_obj(inode);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_evict_inode: ino %d, count %d %s",
+		(int)inode->i_ino, atomic_read(&inode->i_count),
+		obj ? "object exists" : "null object");
+
+	if (!inode->i_nlink && !is_bad_inode(inode))
+		deleteme = 1;
+	truncate_inode_pages(&inode->i_data, 0);
+	Y_CLEAR_INODE(inode);
+
+	if (deleteme && obj) {
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		yaffs_del_obj(obj);
+		yaffs_gross_unlock(dev);
+	}
+	if (obj) {
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		yaffs_unstitch_obj(inode, obj);
+		yaffs_gross_unlock(dev);
+	}
+}
+#else
+
+/* clear is called to tell the fs to release any per-inode data it holds.
+ * The object might still exist on disk and is just being thrown out of the cache
+ * or else the object has actually been deleted and we're being called via
+ * the chain
+ *   yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
+ */
+
+static void yaffs_clear_inode(struct inode *inode)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_dev *dev;
+
+	obj = yaffs_inode_to_obj(inode);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_clear_inode: ino %d, count %d %s",
+		(int)inode->i_ino, atomic_read(&inode->i_count),
+		obj ? "object exists" : "null object");
+
+	if (obj) {
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		yaffs_unstitch_obj(inode, obj);
+		yaffs_gross_unlock(dev);
+	}
+
+}
+
+/* delete is called when the link count is zero and the inode
+ * is put (ie. nobody wants to know about it anymore, time to
+ * delete the file).
+ * NB Must call clear_inode()
+ */
+static void yaffs_delete_inode(struct inode *inode)
+{
+	struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+	struct yaffs_dev *dev;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_delete_inode: ino %d, count %d %s",
+		(int)inode->i_ino, atomic_read(&inode->i_count),
+		obj ? "object exists" : "null object");
+
+	if (obj) {
+		dev = obj->my_dev;
+		yaffs_gross_lock(dev);
+		yaffs_del_obj(obj);
+		yaffs_gross_unlock(dev);
+	}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+	truncate_inode_pages(&inode->i_data, 0);
+#endif
+	clear_inode(inode);
+}
+#endif
+
+
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+	struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+#endif
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
+
+	yaffs_gross_lock(dev);
+
+	buf->f_type = YAFFS_MAGIC;
+	buf->f_bsize = sb->s_blocksize;
+	buf->f_namelen = 255;
+
+	if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
+		/* Do this if chunk size is not a power of 2 */
+
+		uint64_t bytes_in_dev;
+		uint64_t bytes_free;
+
+		bytes_in_dev =
+		    ((uint64_t)
+		     ((dev->param.end_block - dev->param.start_block +
+		       1))) * ((uint64_t) (dev->param.chunks_per_block *
+					   dev->data_bytes_per_chunk));
+
+		do_div(bytes_in_dev, sb->s_blocksize);	/* bytes_in_dev becomes the number of blocks */
+		buf->f_blocks = bytes_in_dev;
+
+		bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
+		    ((uint64_t) (dev->data_bytes_per_chunk));
+
+		do_div(bytes_free, sb->s_blocksize);
+
+		buf->f_bfree = bytes_free;
+
+	} else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
+
+		buf->f_blocks =
+		    (dev->param.end_block - dev->param.start_block + 1) *
+		    dev->param.chunks_per_block /
+		    (sb->s_blocksize / dev->data_bytes_per_chunk);
+		buf->f_bfree =
+		    yaffs_get_n_free_chunks(dev) /
+		    (sb->s_blocksize / dev->data_bytes_per_chunk);
+	} else {
+		buf->f_blocks =
+		    (dev->param.end_block - dev->param.start_block + 1) *
+		    dev->param.chunks_per_block *
+		    (dev->data_bytes_per_chunk / sb->s_blocksize);
+
+		buf->f_bfree =
+		    yaffs_get_n_free_chunks(dev) *
+		    (dev->data_bytes_per_chunk / sb->s_blocksize);
+	}
+
+	buf->f_files = 0;
+	buf->f_ffree = 0;
+	buf->f_bavail = buf->f_bfree;
+
+	yaffs_gross_unlock(dev);
+	return 0;
+}
+
+
+
+static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
+{
+
+	struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+	unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
+	unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
+	int do_checkpoint;
+	int dirty = yaffs_check_super_dirty(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+		"yaffs_do_sync_fs: gc-urgency %d %s %s%s",
+		gc_urgent,
+		dirty ? "dirty" : "clean",
+		request_checkpoint ? "checkpoint requested" : "no checkpoint",
+		oneshot_checkpoint ? " one-shot" : "");
+
+	yaffs_gross_lock(dev);
+	do_checkpoint = ((request_checkpoint && !gc_urgent) ||
+			 oneshot_checkpoint) && !dev->is_checkpointed;
+
+	if (dirty || do_checkpoint) {
+		yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
+		yaffs_clear_super_dirty(dev);
+		if (oneshot_checkpoint)
+			yaffs_auto_checkpoint &= ~4;
+	}
+	yaffs_gross_unlock(dev);
+
+	return 0;
+}
+
+
+#ifdef YAFFS_HAS_WRITE_SUPER
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+	unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+		"yaffs_write_super %s",
+		request_checkpoint ? " checkpt" : "");
+
+	yaffs_do_sync_fs(sb, request_checkpoint);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+	return 0;
+#endif
+}
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+	unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
+
+	yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+		"yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
+
+	yaffs_do_sync_fs(sb, request_checkpoint);
+
+	return 0;
+}
+
+/* the function only is used to change dev->read_only when this file system
+ * is remounted.
+ */
+static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	int read_only = 0;
+	struct mtd_info *mtd;
+	struct yaffs_dev *dev = 0;
+
+	/* Get the device */
+	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+	if (!mtd) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"MTD device #%u doesn't appear to exist",
+			MINOR(sb->s_dev));
+		return 1;
+	}
+
+	/* Check it's NAND */
+	if (mtd->type != MTD_NANDFLASH) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"MTD device is not NAND it's type %d",
+			mtd->type);
+		return 1;
+	}
+
+	read_only = ((*flags & MS_RDONLY) != 0);
+	if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
+		read_only = 1;
+		printk(KERN_INFO
+			"yaffs: mtd is read only, setting superblock read only");
+		*flags |= MS_RDONLY;
+	}
+
+	dev = sb->s_fs_info;
+	dev->read_only = read_only;
+
+	return 0;
+}
+
+static const struct super_operations yaffs_super_ops = {
+	.statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
+	.read_inode = yaffs_read_inode,
+#endif
+#ifdef YAFFS_HAS_PUT_INODE
+	.put_inode = yaffs_put_inode,
+#endif
+	.put_super = yaffs_put_super,
+#ifdef YAFFS_HAS_EVICT_INODE
+	.evict_inode = yaffs_evict_inode,
+#else
+	.delete_inode = yaffs_delete_inode,
+	.clear_inode = yaffs_clear_inode,
+#endif
+	.sync_fs = yaffs_sync_fs,
+#ifdef YAFFS_HAS_WRITE_SUPER
+	.write_super = yaffs_write_super,
+#endif
+	.remount_fs = yaffs_remount_fs,
+};
+
+struct yaffs_options {
+	int inband_tags;
+	int skip_checkpoint_read;
+	int skip_checkpoint_write;
+	int no_cache;
+	int tags_ecc_on;
+	int tags_ecc_overridden;
+	int lazy_loading_enabled;
+	int lazy_loading_overridden;
+	int empty_lost_and_found;
+	int empty_lost_and_found_overridden;
+	int disable_summary;
+};
+
+#define MAX_OPT_LEN 30
+static int yaffs_parse_options(struct yaffs_options *options,
+			       const char *options_str)
+{
+	char cur_opt[MAX_OPT_LEN + 1];
+	int p;
+	int error = 0;
+
+	/* Parse through the options which is a comma seperated list */
+
+	while (options_str && *options_str && !error) {
+		memset(cur_opt, 0, MAX_OPT_LEN + 1);
+		p = 0;
+
+		while (*options_str == ',')
+			options_str++;
+
+		while (*options_str && *options_str != ',') {
+			if (p < MAX_OPT_LEN) {
+				cur_opt[p] = *options_str;
+				p++;
+			}
+			options_str++;
+		}
+
+		if (!strcmp(cur_opt, "inband-tags")) {
+			options->inband_tags = 1;
+		} else if (!strcmp(cur_opt, "tags-ecc-off")) {
+			options->tags_ecc_on = 0;
+			options->tags_ecc_overridden = 1;
+		} else if (!strcmp(cur_opt, "tags-ecc-on")) {
+			options->tags_ecc_on = 1;
+			options->tags_ecc_overridden = 1;
+		} else if (!strcmp(cur_opt, "lazy-loading-off")) {
+			options->lazy_loading_enabled = 0;
+			options->lazy_loading_overridden = 1;
+		} else if (!strcmp(cur_opt, "lazy-loading-on")) {
+			options->lazy_loading_enabled = 1;
+			options->lazy_loading_overridden = 1;
+		} else if (!strcmp(cur_opt, "disable-summary")) {
+			options->disable_summary = 1;
+		} else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
+			options->empty_lost_and_found = 0;
+			options->empty_lost_and_found_overridden = 1;
+		} else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
+			options->empty_lost_and_found = 1;
+			options->empty_lost_and_found_overridden = 1;
+		} else if (!strcmp(cur_opt, "no-cache")) {
+			options->no_cache = 1;
+		} else if (!strcmp(cur_opt, "no-checkpoint-read")) {
+			options->skip_checkpoint_read = 1;
+		} else if (!strcmp(cur_opt, "no-checkpoint-write")) {
+			options->skip_checkpoint_write = 1;
+		} else if (!strcmp(cur_opt, "no-checkpoint")) {
+			options->skip_checkpoint_read = 1;
+			options->skip_checkpoint_write = 1;
+		} else {
+			printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
+			       cur_opt);
+			error = 1;
+		}
+	}
+
+	return error;
+}
+
+
+static struct dentry *yaffs_make_root(struct inode *inode)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
+	struct dentry *root = d_alloc_root(inode);
+
+	if (!root)
+		iput(inode);
+
+        return root;
+#else
+        return d_make_root(inode);
+#endif
+}
+
+
+
+
+static struct super_block *yaffs_internal_read_super(int yaffs_version,
+						     struct super_block *sb,
+						     void *data, int silent)
+{
+	int n_blocks;
+	struct inode *inode = NULL;
+	struct dentry *root;
+	struct yaffs_dev *dev = 0;
+	char devname_buf[BDEVNAME_SIZE + 1];
+	struct mtd_info *mtd;
+	int err;
+	char *data_str = (char *)data;
+	struct yaffs_linux_context *context = NULL;
+	struct yaffs_param *param;
+
+	int read_only = 0;
+	int inband_tags = 0;
+
+	struct yaffs_options options;
+
+	unsigned mount_id;
+	int found;
+	struct yaffs_linux_context *context_iterator;
+	struct list_head *l;
+
+	if (!sb) {
+		printk(KERN_INFO "yaffs: sb is NULL\n");
+		return NULL;
+        }
+
+	sb->s_magic = YAFFS_MAGIC;
+	sb->s_op = &yaffs_super_ops;
+	sb->s_flags |= MS_NOATIME;
+
+	read_only = ((sb->s_flags & MS_RDONLY) != 0);
+
+#ifdef YAFFS_COMPILE_EXPORTFS
+	sb->s_export_op = &yaffs_export_ops;
+#endif
+
+	if (!sb->s_dev)
+		printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
+	else if (!yaffs_devname(sb, devname_buf))
+		printk(KERN_INFO "yaffs: devname is NULL\n");
+	else
+		printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
+		       sb->s_dev,
+		       yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
+
+	if (!data_str)
+		data_str = "";
+
+	printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
+
+	memset(&options, 0, sizeof(options));
+
+	if (yaffs_parse_options(&options, data_str)) {
+		/* Option parsing failed */
+		return NULL;
+	}
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_read_super: Using yaffs%d", yaffs_version);
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_read_super: block size %d", (int)(sb->s_blocksize));
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS,
+		"yaffs: Attempting MTD mount of %u.%u,\"%s\"",
+		MAJOR(sb->s_dev), MINOR(sb->s_dev),
+		yaffs_devname(sb, devname_buf));
+
+	/* Get the device */
+	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+	if (IS_ERR(mtd)) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"yaffs: MTD device %u either not valid or unavailable",
+			MINOR(sb->s_dev));
+		return NULL;
+	}
+
+	if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
+		yaffs_version = 2;
+	}
+
+	/* Added NCB 26/5/2006 for completeness */
+	if (yaffs_version == 2 && !options.inband_tags
+	    && WRITE_SIZE(mtd) == 512) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
+		yaffs_version = 1;
+	}
+
+	if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
+	    options.inband_tags)
+		inband_tags = 1;
+
+	if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
+		return NULL;
+
+	/* OK, so if we got here, we have an MTD that's NAND and looks
+	 * like it has the right capabilities
+	 * Set the struct yaffs_dev up for mtd
+	 */
+
+	if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
+		read_only = 1;
+		printk(KERN_INFO
+		       "yaffs: mtd is read only, setting superblock read only\n"
+		);
+		sb->s_flags |= MS_RDONLY;
+	}
+
+	dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
+	context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
+
+	if (!dev || !context) {
+		kfree(dev);
+		kfree(context);
+		dev = NULL;
+		context = NULL;
+
+		/* Deep shit could not allocate device structure */
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"yaffs_read_super: Failed trying to allocate struct yaffs_dev."
+		);
+		return NULL;
+	}
+	memset(dev, 0, sizeof(struct yaffs_dev));
+	param = &(dev->param);
+
+	memset(context, 0, sizeof(struct yaffs_linux_context));
+	dev->os_context = context;
+	INIT_LIST_HEAD(&(context->context_list));
+	context->dev = dev;
+	context->super = sb;
+
+	dev->read_only = read_only;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+	sb->s_fs_info = dev;
+#else
+	sb->u.generic_sbp = dev;
+#endif
+
+
+	dev->driver_context = mtd;
+	param->name = mtd->name;
+
+	/* Set up the memory size parameters.... */
+
+
+	param->n_reserved_blocks = 5;
+	param->n_caches = (options.no_cache) ? 0 : 10;
+	param->inband_tags = inband_tags;
+
+	param->enable_xattr = 1;
+	if (options.lazy_loading_overridden)
+		param->disable_lazy_load = !options.lazy_loading_enabled;
+
+	param->defered_dir_update = 1;
+
+	if (options.tags_ecc_overridden)
+		param->no_tags_ecc = !options.tags_ecc_on;
+
+	param->empty_lost_n_found = 1;
+	param->refresh_period = 500;
+	param->disable_summary = options.disable_summary;
+
+
+#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
+	param->disable_bad_block_marking  = 1;
+#endif
+	if (options.empty_lost_and_found_overridden)
+		param->empty_lost_n_found = options.empty_lost_and_found;
+
+	/* ... and the functions. */
+	if (yaffs_version == 2) {
+		param->is_yaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+		param->total_bytes_per_chunk = mtd->writesize;
+		param->chunks_per_block = mtd->erasesize / mtd->writesize;
+#else
+		param->total_bytes_per_chunk = mtd->oobblock;
+		param->chunks_per_block = mtd->erasesize / mtd->oobblock;
+#endif
+		n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
+
+		param->start_block = 0;
+		param->end_block = n_blocks - 1;
+	} else {
+		param->is_yaffs2 = 0;
+		n_blocks = YCALCBLOCKS(mtd->size,
+			     YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
+
+		param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
+		param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
+	}
+
+	param->start_block = 0;
+	param->end_block = n_blocks - 1;
+
+	yaffs_mtd_drv_install(dev);
+
+	param->sb_dirty_fn = yaffs_set_super_dirty;
+	param->gc_control_fn = yaffs_gc_control_callback;
+
+	yaffs_dev_to_lc(dev)->super = sb;
+
+	param->use_nand_ecc = 1;
+
+	param->skip_checkpt_rd = options.skip_checkpoint_read;
+	param->skip_checkpt_wr = options.skip_checkpoint_write;
+
+	mutex_lock(&yaffs_context_lock);
+	/* Get a mount id */
+	found = 0;
+	for (mount_id = 0; !found; mount_id++) {
+		found = 1;
+		list_for_each(l, &yaffs_context_list) {
+			context_iterator =
+			    list_entry(l, struct yaffs_linux_context,
+				       context_list);
+			if (context_iterator->mount_id == mount_id)
+				found = 0;
+		}
+	}
+	context->mount_id = mount_id;
+
+	list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
+		      &yaffs_context_list);
+	mutex_unlock(&yaffs_context_lock);
+
+	/* Directory search handling... */
+	INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
+	param->remove_obj_fn = yaffs_remove_obj_callback;
+
+	mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
+
+	yaffs_gross_lock(dev);
+
+	err = yaffs_guts_initialise(dev);
+
+	yaffs_trace(YAFFS_TRACE_OS,
+		"yaffs_read_super: guts initialised %s",
+		(err == YAFFS_OK) ? "OK" : "FAILED");
+
+	if (err == YAFFS_OK)
+		yaffs_bg_start(dev);
+
+	if (!context->bg_thread)
+		param->defered_dir_update = 0;
+
+	sb->s_maxbytes = yaffs_max_file_size(dev);
+
+	/* Release lock before yaffs_get_inode() */
+	yaffs_gross_unlock(dev);
+
+	/* Create root inode */
+	if (err == YAFFS_OK)
+		inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
+
+	if (!inode)
+		return NULL;
+
+	inode->i_op = &yaffs_dir_inode_operations;
+	inode->i_fop = &yaffs_dir_operations;
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
+
+	root = yaffs_make_root(inode);
+
+	if (!root)
+		return NULL;
+
+	sb->s_root = root;
+	if(!dev->is_checkpointed)
+		yaffs_set_super_dirty(dev);
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS,
+		"yaffs_read_super: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
+	return sb;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+					 int silent)
+{
+	return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
+        const char *dev_name, void *data)
+{
+    return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_read_super(struct file_system_type *fs,
+			    int flags, const char *dev_name,
+			    void *data, struct vfsmount *mnt)
+{
+
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs_read_super(struct file_system_type *fs,
+					    int flags, const char *dev_name,
+					    void *data)
+{
+
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "yaffs",
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+        .mount = yaffs_mount,
+#else
+        .get_sb = yaffs_read_super,
+#endif
+     	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
+					    int silent)
+{
+	return yaffs_internal_read_super(1, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
+		      FS_REQUIRES_DEV);
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
+					  int silent)
+{
+	return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
+        const char *dev_name, void *data)
+{
+        return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
+}
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs2_read_super(struct file_system_type *fs,
+			     int flags, const char *dev_name, void *data,
+			     struct vfsmount *mnt)
+{
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs2_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs2_read_super(struct file_system_type *fs,
+					     int flags, const char *dev_name,
+					     void *data)
+{
+
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs2_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs2_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "yaffs2",
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+        .mount = yaffs2_mount,
+#else
+        .get_sb = yaffs2_read_super,
+#endif
+     	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs2_read_super(struct super_block *sb,
+					     void *data, int silent)
+{
+	return yaffs_internal_read_super(2, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
+		      FS_REQUIRES_DEV);
+#endif
+
+
+static struct proc_dir_entry *my_proc_entry;
+
+static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
+{
+	struct yaffs_param *param = &dev->param;
+	int bs[10];
+
+	yaffs_count_blocks_by_state(dev,bs);
+
+	buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
+	buf += sprintf(buf, "end_block............ %d\n", param->end_block);
+	buf += sprintf(buf, "total_bytes_per_chunk %d\n",
+				param->total_bytes_per_chunk);
+	buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
+	buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
+	buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
+	buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
+	buf += sprintf(buf, "empty_lost_n_found... %d\n",
+				param->empty_lost_n_found);
+	buf += sprintf(buf, "disable_lazy_load.... %d\n",
+				param->disable_lazy_load);
+	buf += sprintf(buf, "disable_bad_block_mrk %d\n",
+				param->disable_bad_block_marking);
+	buf += sprintf(buf, "refresh_period....... %d\n",
+				param->refresh_period);
+	buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
+	buf += sprintf(buf, "n_reserved_blocks.... %d\n",
+				param->n_reserved_blocks);
+	buf += sprintf(buf, "always_check_erased.. %d\n",
+				param->always_check_erased);
+	buf += sprintf(buf, "\n");
+	buf += sprintf(buf, "block count by state\n");
+	buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
+				bs[0], bs[1], bs[2], bs[3], bs[4]);
+	buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
+				bs[5], bs[6], bs[7], bs[8], bs[9]);
+
+	return buf;
+}
+
+static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
+{
+	buf += sprintf(buf, "max file size....... %lld\n",
+				(long long) yaffs_max_file_size(dev));
+	buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
+				dev->data_bytes_per_chunk);
+	buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
+	buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
+	buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
+	buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
+				dev->blocks_in_checkpt);
+	buf += sprintf(buf, "\n");
+	buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
+	buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
+	buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
+	buf += sprintf(buf, "\n");
+	buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
+	buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
+	buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
+	buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
+	buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
+	buf += sprintf(buf, "passive_gc_count..... %u\n",
+				dev->passive_gc_count);
+	buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
+				dev->oldest_dirty_gc_count);
+	buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
+	buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
+	buf += sprintf(buf, "n_retried_writes..... %u\n",
+				dev->n_retried_writes);
+	buf += sprintf(buf, "n_retired_blocks..... %u\n",
+				dev->n_retired_blocks);
+	buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
+	buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
+	buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
+				dev->n_tags_ecc_fixed);
+	buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
+				dev->n_tags_ecc_unfixed);
+	buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
+	buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
+	buf += sprintf(buf, "n_unlinked_files..... %u\n",
+				dev->n_unlinked_files);
+	buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
+	buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
+	buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
+	buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
+
+	return buf;
+}
+
+static int yaffs_proc_read(char *page,
+			   char **start,
+			   off_t offset, int count, int *eof, void *data)
+{
+	struct list_head *item;
+	char *buf = page;
+	int step = offset;
+	int n = 0;
+
+	/* Get proc_file_read() to step 'offset' by one on each sucessive call.
+	 * We use 'offset' (*ppos) to indicate where we are in dev_list.
+	 * This also assumes the user has posted a read buffer large
+	 * enough to hold the complete output; but that's life in /proc.
+	 */
+
+	*(int *)start = 1;
+
+	/* Print header first */
+	if (step == 0)
+		buf +=
+		    sprintf(buf,
+			    "Multi-version YAFFS."
+			    "\n");
+	else if (step == 1)
+		buf += sprintf(buf, "\n");
+	else {
+		step -= 2;
+
+		mutex_lock(&yaffs_context_lock);
+
+		/* Locate and print the Nth entry.  Order N-squared but N is small. */
+		list_for_each(item, &yaffs_context_list) {
+			struct yaffs_linux_context *dc =
+			    list_entry(item, struct yaffs_linux_context,
+				       context_list);
+			struct yaffs_dev *dev = dc->dev;
+
+			if (n < (step & ~1)) {
+				n += 2;
+				continue;
+			}
+			if ((step & 1) == 0) {
+				buf +=
+				    sprintf(buf, "\nDevice %d \"%s\"\n", n,
+					    dev->param.name);
+				buf = yaffs_dump_dev_part0(buf, dev);
+			} else {
+				buf = yaffs_dump_dev_part1(buf, dev);
+                        }
+
+			break;
+		}
+		mutex_unlock(&yaffs_context_lock);
+	}
+
+	return buf - page < count ? buf - page : count;
+}
+
+/**
+ * Set the verbosity of the warnings and error messages.
+ *
+ * Note that the names can only be a..z or _ with the current code.
+ */
+
+static struct {
+	char *mask_name;
+	unsigned mask_bitfield;
+} mask_flags[] = {
+	{"allocate", YAFFS_TRACE_ALLOCATE},
+	{"always", YAFFS_TRACE_ALWAYS},
+	{"background", YAFFS_TRACE_BACKGROUND},
+	{"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
+	{"buffers", YAFFS_TRACE_BUFFERS},
+	{"bug", YAFFS_TRACE_BUG},
+	{"checkpt", YAFFS_TRACE_CHECKPOINT},
+	{"deletion", YAFFS_TRACE_DELETION},
+	{"erase", YAFFS_TRACE_ERASE},
+	{"error", YAFFS_TRACE_ERROR},
+	{"gc_detail", YAFFS_TRACE_GC_DETAIL},
+	{"gc", YAFFS_TRACE_GC},
+	{"lock", YAFFS_TRACE_LOCK},
+	{"mtd", YAFFS_TRACE_MTD},
+	{"nandaccess", YAFFS_TRACE_NANDACCESS},
+	{"os", YAFFS_TRACE_OS},
+	{"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
+	{"scan", YAFFS_TRACE_SCAN},
+	{"mount", YAFFS_TRACE_MOUNT},
+	{"tracing", YAFFS_TRACE_TRACING},
+	{"sync", YAFFS_TRACE_SYNC},
+	{"write", YAFFS_TRACE_WRITE},
+	{"verify", YAFFS_TRACE_VERIFY},
+	{"verify_nand", YAFFS_TRACE_VERIFY_NAND},
+	{"verify_full", YAFFS_TRACE_VERIFY_FULL},
+	{"verify_all", YAFFS_TRACE_VERIFY_ALL},
+	{"all", 0xffffffff},
+	{"none", 0},
+	{NULL, 0},
+};
+
+#define MAX_MASK_NAME_LENGTH 40
+static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
+					  unsigned long count)
+{
+	unsigned rg = 0, mask_bitfield;
+	char *end;
+	char *mask_name;
+	const char *x;
+	char substring[MAX_MASK_NAME_LENGTH + 1];
+	int i;
+	int done = 0;
+	int add, len = 0;
+	int pos = 0;
+
+	rg = yaffs_trace_mask;
+
+	while (!done && (pos < count)) {
+		done = 1;
+		while ((pos < count) && isspace(buf[pos]))
+			pos++;
+
+		switch (buf[pos]) {
+		case '+':
+		case '-':
+		case '=':
+			add = buf[pos];
+			pos++;
+			break;
+
+		default:
+			add = ' ';
+			break;
+		}
+		mask_name = NULL;
+
+		mask_bitfield = simple_strtoul(buf + pos, &end, 0);
+
+		if (end > buf + pos) {
+			mask_name = "numeral";
+			len = end - (buf + pos);
+			pos += len;
+			done = 0;
+		} else {
+			for (x = buf + pos, i = 0;
+			     (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
+			     i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
+				substring[i] = *x;
+			substring[i] = '\0';
+
+			for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+				if (strcmp(substring, mask_flags[i].mask_name)
+				    == 0) {
+					mask_name = mask_flags[i].mask_name;
+					mask_bitfield =
+					    mask_flags[i].mask_bitfield;
+					done = 0;
+					break;
+				}
+			}
+		}
+
+		if (mask_name != NULL) {
+			done = 0;
+			switch (add) {
+			case '-':
+				rg &= ~mask_bitfield;
+				break;
+			case '+':
+				rg |= mask_bitfield;
+				break;
+			case '=':
+				rg = mask_bitfield;
+				break;
+			default:
+				rg |= mask_bitfield;
+				break;
+			}
+		}
+	}
+
+	yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
+
+	printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
+
+	if (rg & YAFFS_TRACE_ALWAYS) {
+		for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+			char flag;
+			flag = ((rg & mask_flags[i].mask_bitfield) ==
+				mask_flags[i].mask_bitfield) ? '+' : '-';
+			printk(KERN_DEBUG "%c%s\n", flag,
+			       mask_flags[i].mask_name);
+		}
+	}
+
+	return count;
+}
+
+/* Debug strings are of the form:
+ * .bnnn         print info on block n
+ * .cobjn,chunkn print nand chunk id for objn:chunkn
+ */
+
+static int yaffs_proc_debug_write(struct file *file, const char *buf,
+					  unsigned long count)
+{
+
+	char str[100];
+	char *p0;
+	char *p1;
+	long p1_val;
+	long p0_val;
+	char cmd;
+	struct list_head *item;
+
+	memset(str, 0, sizeof(str));
+	memcpy(str, buf, min((size_t)count, sizeof(str) -1));
+
+	cmd = str[1];
+
+	p0 = str + 2;
+
+	p1 = p0;
+
+	while (*p1 && *p1 != ',') {
+		p1++;
+	}
+	*p1 = '\0';
+	p1++;
+
+	p0_val = simple_strtol(p0, NULL, 0);
+	p1_val = simple_strtol(p1, NULL, 0);
+
+
+	mutex_lock(&yaffs_context_lock);
+
+	/* Locate and print the Nth entry.  Order N-squared but N is small. */
+	list_for_each(item, &yaffs_context_list) {
+		struct yaffs_linux_context *dc =
+		    list_entry(item, struct yaffs_linux_context,
+			       context_list);
+		struct yaffs_dev *dev = dc->dev;
+
+		if (cmd == 'b') {
+			struct yaffs_block_info *bi;
+
+			bi = yaffs_get_block_info(dev,p0_val);
+
+			if(bi) {
+				printk("Block %d: state %d, retire %d, use %d, seq %d\n",
+					(int)p0_val, bi->block_state,
+					bi->needs_retiring, bi->pages_in_use,
+					bi->seq_number);
+			}
+		} else if (cmd == 'c') {
+			struct yaffs_obj *obj;
+			int nand_chunk;
+
+			obj = yaffs_find_by_number(dev, p0_val);
+			if (!obj)
+				printk("No obj %d\n", (int)p0_val);
+			else {
+				if(p1_val == 0)
+					nand_chunk = obj->hdr_chunk;
+				else
+					nand_chunk =
+						yaffs_find_chunk_in_file(obj,
+							p1_val, NULL);
+				printk("Nand chunk for %d:%d is %d\n",
+					(int)p0_val, (int)p1_val, nand_chunk);
+			}
+		}
+	}
+
+	mutex_unlock(&yaffs_context_lock);
+
+	return count;
+}
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+static int yaffs_proc_write(struct file *file, const char *buf,
+			    unsigned long count, void *ppos)
+#else
+static ssize_t yaffs_proc_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *ppos)
+#endif
+{
+	if (buf[0] == '.')
+		return yaffs_proc_debug_write(file, buf, count);
+	return yaffs_proc_write_trace_options(file, buf, count);
+}
+
+/* Stuff to handle installation of file systems */
+struct file_system_to_install {
+	struct file_system_type *fst;
+	int installed;
+};
+
+static struct file_system_to_install fs_to_install[] = {
+	{&yaffs_fs_type, 0},
+	{&yaffs2_fs_type, 0},
+	{NULL, 0}
+};
+
+
+#ifdef YAFFS_NEW_PROCFS
+static int yaffs_proc_show(struct seq_file *m, void *v)
+{
+	/* FIXME: Unify in a better way? */
+	char buffer[512];
+	char *start;
+	int len;
+
+	len = yaffs_proc_read(buffer, &start, 0, sizeof(buffer), NULL, NULL);
+	seq_puts(m, buffer);
+	return 0;
+}
+
+static int yaffs_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, yaffs_proc_show, NULL);
+}
+
+static struct file_operations procfs_ops = {
+	.owner = THIS_MODULE,
+	.open  = yaffs_proc_open,
+	.read  = seq_read,
+	.write = yaffs_proc_write,
+};
+
+static int yaffs_procfs_init(void)
+{
+	/* Install the proc_fs entries */
+	my_proc_entry = proc_create("yaffs",
+				    S_IRUGO | S_IFREG,
+				    YPROC_ROOT,
+				    &procfs_ops);
+
+	if (my_proc_entry) {
+		return 0;
+	} else {
+		return -ENOMEM;
+	}
+}
+
+#else
+
+
+static int yaffs_procfs_init(void)
+{
+	/* Install the proc_fs entries */
+	my_proc_entry = create_proc_entry("yaffs",
+					  S_IRUGO | S_IFREG, YPROC_ROOT);
+
+	if (my_proc_entry) {
+		my_proc_entry->write_proc = yaffs_proc_write;
+		my_proc_entry->read_proc = yaffs_proc_read;
+		my_proc_entry->data = NULL;
+		return 0;
+	} else {
+		return -ENOMEM;
+	}
+}
+
+#endif
+
+
+static int __init init_yaffs_fs(void)
+{
+	int error = 0;
+	struct file_system_to_install *fsinst;
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS,
+		"yaffs Installing.");
+
+	mutex_init(&yaffs_context_lock);
+
+	error = yaffs_procfs_init();
+	if (error)
+		return error;
+
+	/* Now add the file system entries */
+
+	fsinst = fs_to_install;
+
+	while (fsinst->fst && !error) {
+		error = register_filesystem(fsinst->fst);
+		if (!error)
+			fsinst->installed = 1;
+		fsinst++;
+	}
+
+	/* Any errors? uninstall  */
+	if (error) {
+		fsinst = fs_to_install;
+
+		while (fsinst->fst) {
+			if (fsinst->installed) {
+				unregister_filesystem(fsinst->fst);
+				fsinst->installed = 0;
+			}
+			fsinst++;
+		}
+	}
+
+	return error;
+}
+
+static void __exit exit_yaffs_fs(void)
+{
+
+	struct file_system_to_install *fsinst;
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS,
+		"yaffs removing.");
+
+	remove_proc_entry("yaffs", YPROC_ROOT);
+
+	fsinst = fs_to_install;
+
+	while (fsinst->fst) {
+		if (fsinst->installed) {
+			unregister_filesystem(fsinst->fst);
+			fsinst->installed = 0;
+		}
+		fsinst++;
+	}
+}
+
+module_init(init_yaffs_fs)
+    module_exit(exit_yaffs_fs)
+
+    MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c
new file mode 100644
index 0000000000..d277e20e2a
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.c
@@ -0,0 +1,422 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_yaffs1.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+#include "yaffs_attribs.h"
+
+int yaffs1_scan(struct yaffs_dev *dev)
+{
+	struct yaffs_ext_tags tags;
+	int blk;
+	int result;
+	int chunk;
+	int c;
+	int deleted;
+	enum yaffs_block_state state;
+	LIST_HEAD(hard_list);
+	struct yaffs_block_info *bi;
+	u32 seq_number;
+	struct yaffs_obj_hdr *oh;
+	struct yaffs_obj *in;
+	struct yaffs_obj *parent;
+	int alloc_failed = 0;
+	struct yaffs_shadow_fixer *shadow_fixers = NULL;
+	u8 *chunk_data;
+
+	yaffs_trace(YAFFS_TRACE_SCAN,
+		"yaffs1_scan starts  intstartblk %d intendblk %d...",
+		dev->internal_start_block, dev->internal_end_block);
+
+	chunk_data = yaffs_get_temp_buffer(dev);
+
+	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+	/* Scan all the blocks to determine their state */
+	bi = dev->block_info;
+	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+	     blk++) {
+		yaffs_clear_chunk_bits(dev, blk);
+		bi->pages_in_use = 0;
+		bi->soft_del_pages = 0;
+
+		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
+
+		bi->block_state = state;
+		bi->seq_number = seq_number;
+
+		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
+			bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
+
+		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+			"Block scanning block %d state %d seq %d",
+			blk, state, seq_number);
+
+		if (state == YAFFS_BLOCK_STATE_DEAD) {
+			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+				"block %d is bad", blk);
+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
+			dev->n_erased_blocks++;
+			dev->n_free_chunks += dev->param.chunks_per_block;
+		}
+		bi++;
+	}
+
+	/* For each block.... */
+	for (blk = dev->internal_start_block;
+	     !alloc_failed && blk <= dev->internal_end_block; blk++) {
+
+		cond_resched();
+
+		bi = yaffs_get_block_info(dev, blk);
+		state = bi->block_state;
+
+		deleted = 0;
+
+		/* For each chunk in each block that needs scanning.... */
+		for (c = 0;
+			!alloc_failed && c < dev->param.chunks_per_block &&
+			state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
+			/* Read the tags and decide what to do */
+			chunk = blk * dev->param.chunks_per_block + c;
+
+			result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
+							  &tags);
+
+			/* Let's have a good look at this chunk... */
+
+			if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
+			    tags.is_deleted) {
+				/* YAFFS1 only...
+				 * A deleted chunk
+				 */
+				deleted++;
+				dev->n_free_chunks++;
+			} else if (!tags.chunk_used) {
+				/* An unassigned chunk in the block
+				 * This means that either the block is empty or
+				 * this is the one being allocated from
+				 */
+
+				if (c == 0) {
+					/* We're looking at the first chunk in
+					 *the block so the block is unused */
+					state = YAFFS_BLOCK_STATE_EMPTY;
+					dev->n_erased_blocks++;
+				} else {
+					/* this is the block being allocated */
+					yaffs_trace(YAFFS_TRACE_SCAN,
+						" Allocating from %d %d",
+						blk, c);
+					state = YAFFS_BLOCK_STATE_ALLOCATING;
+					dev->alloc_block = blk;
+					dev->alloc_page = c;
+					dev->alloc_block_finder = blk;
+
+				}
+
+				dev->n_free_chunks +=
+				    (dev->param.chunks_per_block - c);
+			} else if (tags.chunk_id > 0) {
+				/* chunk_id > 0 so it is a data chunk... */
+				unsigned int endpos;
+
+				yaffs_set_chunk_bit(dev, blk, c);
+				bi->pages_in_use++;
+
+				in = yaffs_find_or_create_by_number(dev,
+							tags.obj_id,
+							YAFFS_OBJECT_TYPE_FILE);
+				/* PutChunkIntoFile checks for a clash
+				 * (two data chunks with the same chunk_id).
+				 */
+
+				if (!in)
+					alloc_failed = 1;
+
+				if (in) {
+					if (!yaffs_put_chunk_in_file
+					    (in, tags.chunk_id, chunk, 1))
+						alloc_failed = 1;
+				}
+
+				endpos =
+				    (tags.chunk_id - 1) *
+				    dev->data_bytes_per_chunk +
+				    tags.n_bytes;
+				if (in &&
+				    in->variant_type ==
+				     YAFFS_OBJECT_TYPE_FILE &&
+				    in->variant.file_variant.scanned_size <
+				      endpos) {
+					in->variant.file_variant.scanned_size =
+					    endpos;
+					if (!dev->param.use_header_file_size) {
+						in->variant.
+						    file_variant.file_size =
+						    in->variant.
+						    file_variant.scanned_size;
+					}
+
+				}
+			} else {
+				/* chunk_id == 0, so it is an ObjectHeader.
+				 * Make the object
+				 */
+				yaffs_set_chunk_bit(dev, blk, c);
+				bi->pages_in_use++;
+
+				result = yaffs_rd_chunk_tags_nand(dev, chunk,
+								  chunk_data,
+								  NULL);
+
+				oh = (struct yaffs_obj_hdr *)chunk_data;
+
+				in = yaffs_find_by_number(dev, tags.obj_id);
+				if (in && in->variant_type != oh->type) {
+					/* This should not happen, but somehow
+					 * Wev'e ended up with an obj_id that
+					 * has been reused but not yet deleted,
+					 * and worse still it has changed type.
+					 * Delete the old object.
+					 */
+
+					yaffs_del_obj(in);
+					in = NULL;
+				}
+
+				in = yaffs_find_or_create_by_number(dev,
+								tags.obj_id,
+								oh->type);
+
+				if (!in)
+					alloc_failed = 1;
+
+				if (in && oh->shadows_obj > 0) {
+
+					struct yaffs_shadow_fixer *fixer;
+					fixer =
+						kmalloc(sizeof
+						(struct yaffs_shadow_fixer),
+						GFP_NOFS);
+					if (fixer) {
+						fixer->next = shadow_fixers;
+						shadow_fixers = fixer;
+						fixer->obj_id = tags.obj_id;
+						fixer->shadowed_id =
+						    oh->shadows_obj;
+						yaffs_trace(YAFFS_TRACE_SCAN,
+							" Shadow fixer: %d shadows %d",
+							fixer->obj_id,
+							fixer->shadowed_id);
+
+					}
+
+				}
+
+				if (in && in->valid) {
+					/* We have already filled this one.
+					 * We have a duplicate and need to
+					 * resolve it. */
+
+					unsigned existing_serial = in->serial;
+					unsigned new_serial =
+					    tags.serial_number;
+
+					if (((existing_serial + 1) & 3) ==
+					    new_serial) {
+						/* Use new one - destroy the
+						 * exisiting one */
+						yaffs_chunk_del(dev,
+								in->hdr_chunk,
+								1, __LINE__);
+						in->valid = 0;
+					} else {
+						/* Use existing - destroy
+						 * this one. */
+						yaffs_chunk_del(dev, chunk, 1,
+								__LINE__);
+					}
+				}
+
+				if (in && !in->valid &&
+				    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+				     tags.obj_id ==
+				     YAFFS_OBJECTID_LOSTNFOUND)) {
+					/* We only load some info, don't fiddle
+					 * with directory structure */
+					in->valid = 1;
+					in->variant_type = oh->type;
+
+					in->yst_mode = oh->yst_mode;
+					yaffs_load_attribs(in, oh);
+					in->hdr_chunk = chunk;
+					in->serial = tags.serial_number;
+
+				} else if (in && !in->valid) {
+					/* we need to load this info */
+
+					in->valid = 1;
+					in->variant_type = oh->type;
+
+					in->yst_mode = oh->yst_mode;
+					yaffs_load_attribs(in, oh);
+					in->hdr_chunk = chunk;
+					in->serial = tags.serial_number;
+
+					yaffs_set_obj_name_from_oh(in, oh);
+					in->dirty = 0;
+
+					/* directory stuff...
+					 * hook up to parent
+					 */
+
+					parent =
+					    yaffs_find_or_create_by_number
+					    (dev, oh->parent_obj_id,
+					     YAFFS_OBJECT_TYPE_DIRECTORY);
+					if (!parent)
+						alloc_failed = 1;
+					if (parent && parent->variant_type ==
+					    YAFFS_OBJECT_TYPE_UNKNOWN) {
+						/* Set up as a directory */
+						parent->variant_type =
+						    YAFFS_OBJECT_TYPE_DIRECTORY;
+						INIT_LIST_HEAD(&parent->
+							variant.dir_variant.
+							children);
+					} else if (!parent ||
+						parent->variant_type !=
+						YAFFS_OBJECT_TYPE_DIRECTORY) {
+						/* Hoosterman, a problem....
+						 * We're trying to use a
+						 * non-directory as a directory
+						 */
+
+						yaffs_trace(YAFFS_TRACE_ERROR,
+							"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+							);
+						parent = dev->lost_n_found;
+					}
+
+					yaffs_add_obj_to_dir(parent, in);
+
+					switch (in->variant_type) {
+					case YAFFS_OBJECT_TYPE_UNKNOWN:
+						/* Todo got a problem */
+						break;
+					case YAFFS_OBJECT_TYPE_FILE:
+						if (dev->param.
+						    use_header_file_size)
+							in->variant.
+							file_variant.file_size
+							= yaffs_oh_to_size(oh);
+						break;
+					case YAFFS_OBJECT_TYPE_HARDLINK:
+						in->variant.
+						    hardlink_variant.equiv_id =
+						    oh->equiv_id;
+						list_add(&in->hard_links,
+								&hard_list);
+						break;
+					case YAFFS_OBJECT_TYPE_DIRECTORY:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SPECIAL:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SYMLINK:
+						in->variant.symlink_variant.
+						    alias =
+						    yaffs_clone_str(oh->alias);
+						if (!in->variant.
+						    symlink_variant.alias)
+							alloc_failed = 1;
+						break;
+					}
+				}
+			}
+		}
+
+		if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			/* If we got this far while scanning,
+			 * then the block is fully allocated. */
+			state = YAFFS_BLOCK_STATE_FULL;
+		}
+
+		if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
+			/* If the block was partially allocated then
+			 * treat it as fully allocated. */
+			state = YAFFS_BLOCK_STATE_FULL;
+			dev->alloc_block = -1;
+		}
+
+		bi->block_state = state;
+
+		/* Now let's see if it was dirty */
+		if (bi->pages_in_use == 0 &&
+		    !bi->has_shrink_hdr &&
+		    bi->block_state == YAFFS_BLOCK_STATE_FULL)
+			yaffs_block_became_dirty(dev, blk);
+	}
+
+	/* Ok, we've done all the scanning.
+	 * Fix up the hard link chains.
+	 * We should now have scanned all the objects, now it's time to add
+	 * these hardlinks.
+	 */
+
+	yaffs_link_fixup(dev, &hard_list);
+
+	/*
+	 * Fix up any shadowed objects.
+	 * There should not be more than one of these.
+	 */
+	{
+		struct yaffs_shadow_fixer *fixer;
+		struct yaffs_obj *obj;
+
+		while (shadow_fixers) {
+			fixer = shadow_fixers;
+			shadow_fixers = fixer->next;
+			/* Complete the rename transaction by deleting the
+			 * shadowed object then setting the object header
+			 to unshadowed.
+			 */
+			obj = yaffs_find_by_number(dev, fixer->shadowed_id);
+			if (obj)
+				yaffs_del_obj(obj);
+
+			obj = yaffs_find_by_number(dev, fixer->obj_id);
+
+			if (obj)
+				yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
+
+			kfree(fixer);
+		}
+	}
+
+	yaffs_release_temp_buffer(dev, chunk_data);
+
+	if (alloc_failed)
+		return YAFFS_FAIL;
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
+
+	return YAFFS_OK;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h
new file mode 100644
index 0000000000..97e2fdd08a
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs1.h
@@ -0,0 +1,22 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS1_H__
+#define __YAFFS_YAFFS1_H__
+
+#include "yaffs_guts.h"
+int yaffs1_scan(struct yaffs_dev *dev);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c
new file mode 100644
index 0000000000..9fb7c944ca
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c
@@ -0,0 +1,1532 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_checkptrw.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_verify.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
+
+/*
+ * Checkpoints are really no benefit on very small partitions.
+ *
+ * To save space on small partitions don't bother with checkpoints unless
+ * the partition is at least this big.
+ */
+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
+#define YAFFS_SMALL_HOLE_THRESHOLD 4
+
+/*
+ * Oldest Dirty Sequence Number handling.
+ */
+
+/* yaffs_calc_oldest_dirty_seq()
+ * yaffs2_find_oldest_dirty_seq()
+ * Calculate the oldest dirty sequence number if we don't know it.
+ */
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
+{
+	int i;
+	unsigned seq;
+	unsigned block_no = 0;
+	struct yaffs_block_info *b;
+
+	if (!dev->param.is_yaffs2)
+		return;
+
+	/* Find the oldest dirty sequence number. */
+	seq = dev->seq_number + 1;
+	b = dev->block_info;
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
+		    (b->pages_in_use - b->soft_del_pages) <
+		    dev->param.chunks_per_block &&
+		    b->seq_number < seq) {
+			seq = b->seq_number;
+			block_no = i;
+		}
+		b++;
+	}
+
+	if (block_no) {
+		dev->oldest_dirty_seq = seq;
+		dev->oldest_dirty_block = block_no;
+	}
+}
+
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
+{
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (!dev->oldest_dirty_seq)
+		yaffs_calc_oldest_dirty_seq(dev);
+}
+
+/*
+ * yaffs_clear_oldest_dirty_seq()
+ * Called when a block is erased or marked bad. (ie. when its seq_number
+ * becomes invalid). If the value matches the oldest then we clear
+ * dev->oldest_dirty_seq to force its recomputation.
+ */
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+				   struct yaffs_block_info *bi)
+{
+
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
+		dev->oldest_dirty_seq = 0;
+		dev->oldest_dirty_block = 0;
+	}
+}
+
+/*
+ * yaffs2_update_oldest_dirty_seq()
+ * Update the oldest dirty sequence number whenever we dirty a block.
+ * Only do this if the oldest_dirty_seq is actually being tracked.
+ */
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+				    struct yaffs_block_info *bi)
+{
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (dev->oldest_dirty_seq) {
+		if (dev->oldest_dirty_seq > bi->seq_number) {
+			dev->oldest_dirty_seq = bi->seq_number;
+			dev->oldest_dirty_block = block_no;
+		}
+	}
+}
+
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
+{
+
+	if (!dev->param.is_yaffs2)
+		return 1;	/* disqualification only applies to yaffs2. */
+
+	if (!bi->has_shrink_hdr)
+		return 1;	/* can gc */
+
+	yaffs2_find_oldest_dirty_seq(dev);
+
+	/* Can't do gc of this block if there are any blocks older than this
+	 * one that have discarded pages.
+	 */
+	return (bi->seq_number <= dev->oldest_dirty_seq);
+}
+
+/*
+ * yaffs2_find_refresh_block()
+ * periodically finds the oldest full block by sequence number for refreshing.
+ * Only for yaffs2.
+ */
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
+{
+	u32 b;
+	u32 oldest = 0;
+	u32 oldest_seq = 0;
+	struct yaffs_block_info *bi;
+
+	if (!dev->param.is_yaffs2)
+		return oldest;
+
+	/*
+	 * If refresh period < 10 then refreshing is disabled.
+	 */
+	if (dev->param.refresh_period < 10)
+		return oldest;
+
+	/*
+	 * Fix broken values.
+	 */
+	if (dev->refresh_skip > dev->param.refresh_period)
+		dev->refresh_skip = dev->param.refresh_period;
+
+	if (dev->refresh_skip > 0)
+		return oldest;
+
+	/*
+	 * Refresh skip is now zero.
+	 * We'll do a refresh this time around....
+	 * Update the refresh skip and find the oldest block.
+	 */
+	dev->refresh_skip = dev->param.refresh_period;
+	dev->refresh_count++;
+	bi = dev->block_info;
+	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+
+			if (oldest < 1 || bi->seq_number < oldest_seq) {
+				oldest = b;
+				oldest_seq = bi->seq_number;
+			}
+		}
+		bi++;
+	}
+
+	if (oldest > 0) {
+		yaffs_trace(YAFFS_TRACE_GC,
+			"GC refresh count %d selected block %d with seq_number %d",
+			dev->refresh_count, oldest, oldest_seq);
+	}
+
+	return oldest;
+}
+
+int yaffs2_checkpt_required(struct yaffs_dev *dev)
+{
+	int nblocks;
+
+	if (!dev->param.is_yaffs2)
+		return 0;
+
+	nblocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+	return !dev->param.skip_checkpt_wr &&
+	    !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
+}
+
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
+{
+	int retval;
+	int n_bytes = 0;
+	int n_blocks;
+	int dev_blocks;
+
+	if (!dev->param.is_yaffs2)
+		return 0;
+
+	if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
+		/* Not a valid value so recalculate */
+		dev_blocks = dev->param.end_block - dev->param.start_block + 1;
+		n_bytes += sizeof(struct yaffs_checkpt_validity);
+		n_bytes += sizeof(struct yaffs_checkpt_dev);
+		n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
+		n_bytes += dev_blocks * dev->chunk_bit_stride;
+		n_bytes +=
+		    (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
+		    dev->n_obj;
+		n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
+		n_bytes += sizeof(struct yaffs_checkpt_validity);
+		n_bytes += sizeof(u32);	/* checksum */
+
+		/* Round up and add 2 blocks to allow for some bad blocks,
+		 * so add 3 */
+
+		n_blocks =
+		    (n_bytes /
+		     (dev->data_bytes_per_chunk *
+		      dev->param.chunks_per_block)) + 3;
+
+		dev->checkpoint_blocks_required = n_blocks;
+	}
+
+	retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
+	if (retval < 0)
+		retval = 0;
+	return retval;
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
+{
+	struct yaffs_checkpt_validity cp;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.struct_type = sizeof(cp);
+	cp.magic = YAFFS_MAGIC;
+	cp.version = YAFFS_CHECKPOINT_VERSION;
+	cp.head = (head) ? 1 : 0;
+
+	return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
+{
+	struct yaffs_checkpt_validity cp;
+	int ok;
+
+	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	if (ok)
+		ok = (cp.struct_type == sizeof(cp)) &&
+		    (cp.magic == YAFFS_MAGIC) &&
+		    (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+		    (cp.head == ((head) ? 1 : 0));
+	return ok ? 1 : 0;
+}
+
+static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
+				      struct yaffs_dev *dev)
+{
+	cp->n_erased_blocks = dev->n_erased_blocks;
+	cp->alloc_block = dev->alloc_block;
+	cp->alloc_page = dev->alloc_page;
+	cp->n_free_chunks = dev->n_free_chunks;
+
+	cp->n_deleted_files = dev->n_deleted_files;
+	cp->n_unlinked_files = dev->n_unlinked_files;
+	cp->n_bg_deletions = dev->n_bg_deletions;
+	cp->seq_number = dev->seq_number;
+
+}
+
+static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
+				     struct yaffs_checkpt_dev *cp)
+{
+	dev->n_erased_blocks = cp->n_erased_blocks;
+	dev->alloc_block = cp->alloc_block;
+	dev->alloc_page = cp->alloc_page;
+	dev->n_free_chunks = cp->n_free_chunks;
+
+	dev->n_deleted_files = cp->n_deleted_files;
+	dev->n_unlinked_files = cp->n_unlinked_files;
+	dev->n_bg_deletions = cp->n_bg_deletions;
+	dev->seq_number = cp->seq_number;
+}
+
+static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_dev cp;
+	u32 n_bytes;
+	u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+	int ok;
+
+	/* Write device runtime values */
+	yaffs2_dev_to_checkpt_dev(&cp, dev);
+	cp.struct_type = sizeof(cp);
+
+	ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+	if (!ok)
+		return 0;
+
+	/* Write block info */
+	n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+	ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
+	if (!ok)
+		return 0;
+
+	/* Write chunk bits */
+	n_bytes = n_blocks * dev->chunk_bit_stride;
+	ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_dev cp;
+	u32 n_bytes;
+	u32 n_blocks =
+	    (dev->internal_end_block - dev->internal_start_block + 1);
+	int ok;
+
+	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+	if (!ok)
+		return 0;
+
+	if (cp.struct_type != sizeof(cp))
+		return 0;
+
+	yaffs_checkpt_dev_to_dev(dev, &cp);
+
+	n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+
+	ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
+
+	if (!ok)
+		return 0;
+
+	n_bytes = n_blocks * dev->chunk_bit_stride;
+
+	ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
+
+	return ok ? 1 : 0;
+}
+
+static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
+				   struct yaffs_obj *obj)
+{
+	cp->obj_id = obj->obj_id;
+	cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
+	cp->hdr_chunk = obj->hdr_chunk;
+	cp->variant_type = obj->variant_type;
+	cp->deleted = obj->deleted;
+	cp->soft_del = obj->soft_del;
+	cp->unlinked = obj->unlinked;
+	cp->fake = obj->fake;
+	cp->rename_allowed = obj->rename_allowed;
+	cp->unlink_allowed = obj->unlink_allowed;
+	cp->serial = obj->serial;
+	cp->n_data_chunks = obj->n_data_chunks;
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+		cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
+	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
+		cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
+}
+
+static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
+				     struct yaffs_checkpt_obj *cp)
+{
+	struct yaffs_obj *parent;
+
+	if (obj->variant_type != cp->variant_type) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Checkpoint read object %d type %d chunk %d does not match existing object type %d",
+			cp->obj_id, cp->variant_type, cp->hdr_chunk,
+			obj->variant_type);
+		return 0;
+	}
+
+	obj->obj_id = cp->obj_id;
+
+	if (cp->parent_id)
+		parent = yaffs_find_or_create_by_number(obj->my_dev,
+						cp->parent_id,
+						YAFFS_OBJECT_TYPE_DIRECTORY);
+	else
+		parent = NULL;
+
+	if (parent) {
+		if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
+				cp->obj_id, cp->parent_id,
+				cp->variant_type, cp->hdr_chunk,
+				parent->variant_type);
+			return 0;
+		}
+		yaffs_add_obj_to_dir(parent, obj);
+	}
+
+	obj->hdr_chunk = cp->hdr_chunk;
+	obj->variant_type = cp->variant_type;
+	obj->deleted = cp->deleted;
+	obj->soft_del = cp->soft_del;
+	obj->unlinked = cp->unlinked;
+	obj->fake = cp->fake;
+	obj->rename_allowed = cp->rename_allowed;
+	obj->unlink_allowed = cp->unlink_allowed;
+	obj->serial = cp->serial;
+	obj->n_data_chunks = cp->n_data_chunks;
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+		obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
+	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
+		obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
+
+	if (obj->hdr_chunk > 0)
+		obj->lazy_loaded = 1;
+	return 1;
+}
+
+static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
+				       struct yaffs_tnode *tn, u32 level,
+				       int chunk_offset)
+{
+	int i;
+	struct yaffs_dev *dev = in->my_dev;
+	int ok = 1;
+	u32 base_offset;
+
+	if (!tn)
+		return 1;
+
+	if (level > 0) {
+		for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+			if (!tn->internal[i])
+				continue;
+			ok = yaffs2_checkpt_tnode_worker(in,
+				 tn->internal[i],
+				 level - 1,
+				 (chunk_offset <<
+				  YAFFS_TNODES_INTERNAL_BITS) + i);
+		}
+		return ok;
+	}
+
+	/* Level 0 tnode */
+	base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
+	ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
+			sizeof(base_offset));
+	if (ok)
+		ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
+			dev->tnode_size);
+
+	return ok;
+}
+
+static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
+{
+	u32 end_marker = ~0;
+	int ok = 1;
+
+	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		return ok;
+
+	ok = yaffs2_checkpt_tnode_worker(obj,
+					 obj->variant.file_variant.top,
+					 obj->variant.file_variant.
+					 top_level, 0);
+	if (ok)
+		ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
+				sizeof(end_marker)) == sizeof(end_marker));
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
+{
+	u32 base_chunk;
+	int ok = 1;
+	struct yaffs_dev *dev = obj->my_dev;
+	struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
+	struct yaffs_tnode *tn;
+	int nread = 0;
+
+	ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
+	      sizeof(base_chunk));
+
+	while (ok && (~base_chunk)) {
+		nread++;
+		/* Read level 0 tnode */
+
+		tn = yaffs_get_tnode(dev);
+		if (tn)
+			ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
+				dev->tnode_size);
+		else
+			ok = 0;
+
+		if (tn && ok)
+			ok = yaffs_add_find_tnode_0(dev,
+						    file_stuct_ptr,
+						    base_chunk, tn) ? 1 : 0;
+
+		if (ok)
+			ok = (yaffs2_checkpt_rd
+			      (dev, &base_chunk,
+			       sizeof(base_chunk)) == sizeof(base_chunk));
+	}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"Checkpoint read tnodes %d records, last %d. ok %d",
+		nread, base_chunk, ok);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_checkpt_obj cp;
+	int i;
+	int ok = 1;
+	struct list_head *lh;
+
+	/* Iterate through the objects in each hash entry,
+	 * dumping them to the checkpointing stream.
+	 */
+
+	for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
+		list_for_each(lh, &dev->obj_bucket[i].list) {
+			obj = list_entry(lh, struct yaffs_obj, hash_link);
+			if (!obj->defered_free) {
+				yaffs2_obj_checkpt_obj(&cp, obj);
+				cp.struct_type = sizeof(cp);
+
+				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+					"Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
+					cp.obj_id, cp.parent_id,
+					cp.variant_type, cp.hdr_chunk, obj);
+
+				ok = (yaffs2_checkpt_wr(dev, &cp,
+						sizeof(cp)) == sizeof(cp));
+
+				if (ok &&
+					obj->variant_type ==
+					YAFFS_OBJECT_TYPE_FILE)
+					ok = yaffs2_wr_checkpt_tnodes(obj);
+			}
+		}
+	}
+
+	/* Dump end of list */
+	memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
+	cp.struct_type = sizeof(cp);
+
+	if (ok)
+		ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_checkpt_obj cp;
+	int ok = 1;
+	int done = 0;
+	LIST_HEAD(hard_list);
+
+
+	while (ok && !done) {
+		ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+		if (cp.struct_type != sizeof(cp)) {
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+				"struct size %d instead of %d ok %d",
+				cp.struct_type, (int)sizeof(cp), ok);
+			ok = 0;
+		}
+
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"Checkpoint read object %d parent %d type %d chunk %d ",
+			cp.obj_id, cp.parent_id, cp.variant_type,
+			cp.hdr_chunk);
+
+		if (ok && cp.obj_id == ~0) {
+			done = 1;
+		} else if (ok) {
+			obj =
+			    yaffs_find_or_create_by_number(dev, cp.obj_id,
+							   cp.variant_type);
+			if (obj) {
+				ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
+				if (!ok)
+					break;
+				if (obj->variant_type ==
+					YAFFS_OBJECT_TYPE_FILE) {
+					ok = yaffs2_rd_checkpt_tnodes(obj);
+				} else if (obj->variant_type ==
+					YAFFS_OBJECT_TYPE_HARDLINK) {
+					list_add(&obj->hard_links, &hard_list);
+				}
+			} else {
+				ok = 0;
+			}
+		}
+	}
+
+	if (ok)
+		yaffs_link_fixup(dev, &hard_list);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
+{
+	u32 checkpt_sum;
+	int ok;
+
+	yaffs2_get_checkpt_sum(dev, &checkpt_sum);
+
+	ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
+		sizeof(checkpt_sum));
+
+	if (!ok)
+		return 0;
+
+	return 1;
+}
+
+static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
+{
+	u32 checkpt_sum0;
+	u32 checkpt_sum1;
+	int ok;
+
+	yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
+
+	ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
+		sizeof(checkpt_sum1));
+
+	if (!ok)
+		return 0;
+
+	if (checkpt_sum0 != checkpt_sum1)
+		return 0;
+
+	return 1;
+}
+
+static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
+{
+	int ok = 1;
+
+	if (!yaffs2_checkpt_required(dev)) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"skipping checkpoint write");
+		ok = 0;
+	}
+
+	if (ok)
+		ok = yaffs2_checkpt_open(dev, 1);
+
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint validity");
+		ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint device");
+		ok = yaffs2_wr_checkpt_dev(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint objects");
+		ok = yaffs2_wr_checkpt_objs(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint validity");
+		ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
+	}
+
+	if (ok)
+		ok = yaffs2_wr_checkpt_sum(dev);
+
+	if (!yaffs_checkpt_close(dev))
+		ok = 0;
+
+	if (ok)
+		dev->is_checkpointed = 1;
+	else
+		dev->is_checkpointed = 0;
+
+	return dev->is_checkpointed;
+}
+
+static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
+{
+	int ok = 1;
+
+	if (!dev->param.is_yaffs2)
+		ok = 0;
+
+	if (ok && dev->param.skip_checkpt_rd) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"skipping checkpoint read");
+		ok = 0;
+	}
+
+	if (ok)
+		ok = yaffs2_checkpt_open(dev, 0); /* open for read */
+
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint validity");
+		ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint device");
+		ok = yaffs2_rd_checkpt_dev(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint objects");
+		ok = yaffs2_rd_checkpt_objs(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint validity");
+		ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
+	}
+
+	if (ok) {
+		ok = yaffs2_rd_checkpt_sum(dev);
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint checksum %d", ok);
+	}
+
+	if (!yaffs_checkpt_close(dev))
+		ok = 0;
+
+	if (ok)
+		dev->is_checkpointed = 1;
+	else
+		dev->is_checkpointed = 0;
+
+	return ok ? 1 : 0;
+}
+
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
+{
+	if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
+		dev->is_checkpointed = 0;
+		yaffs2_checkpt_invalidate_stream(dev);
+	}
+	if (dev->param.sb_dirty_fn)
+		dev->param.sb_dirty_fn(dev);
+}
+
+int yaffs_checkpoint_save(struct yaffs_dev *dev)
+{
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"save entry: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	yaffs_verify_objects(dev);
+	yaffs_verify_blocks(dev);
+	yaffs_verify_free_chunks(dev);
+
+	if (!dev->is_checkpointed) {
+		yaffs2_checkpt_invalidate(dev);
+		yaffs2_wr_checkpt_data(dev);
+	}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
+		"save exit: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	return dev->is_checkpointed;
+}
+
+int yaffs2_checkpt_restore(struct yaffs_dev *dev)
+{
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"restore entry: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	retval = yaffs2_rd_checkpt_data(dev);
+
+	if (dev->is_checkpointed) {
+		yaffs_verify_objects(dev);
+		yaffs_verify_blocks(dev);
+		yaffs_verify_free_chunks(dev);
+	}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"restore exit: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	return retval;
+}
+
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
+{
+	/* if new_size > old_file_size.
+	 * We're going to be writing a hole.
+	 * If the hole is small then write zeros otherwise write a start
+	 * of hole marker.
+	 */
+	loff_t old_file_size;
+	loff_t increase;
+	int small_hole;
+	int result = YAFFS_OK;
+	struct yaffs_dev *dev = NULL;
+	u8 *local_buffer = NULL;
+	int small_increase_ok = 0;
+
+	if (!obj)
+		return YAFFS_FAIL;
+
+	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		return YAFFS_FAIL;
+
+	dev = obj->my_dev;
+
+	/* Bail out if not yaffs2 mode */
+	if (!dev->param.is_yaffs2)
+		return YAFFS_OK;
+
+	old_file_size = obj->variant.file_variant.file_size;
+
+	if (new_size <= old_file_size)
+		return YAFFS_OK;
+
+	increase = new_size - old_file_size;
+
+	if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
+	    yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
+		small_hole = 1;
+	else
+		small_hole = 0;
+
+	if (small_hole)
+		local_buffer = yaffs_get_temp_buffer(dev);
+
+	if (local_buffer) {
+		/* fill hole with zero bytes */
+		loff_t pos = old_file_size;
+		int this_write;
+		int written;
+		memset(local_buffer, 0, dev->data_bytes_per_chunk);
+		small_increase_ok = 1;
+
+		while (increase > 0 && small_increase_ok) {
+			this_write = increase;
+			if (this_write > dev->data_bytes_per_chunk)
+				this_write = dev->data_bytes_per_chunk;
+			written =
+			    yaffs_do_file_wr(obj, local_buffer, pos, this_write,
+					     0);
+			if (written == this_write) {
+				pos += this_write;
+				increase -= this_write;
+			} else {
+				small_increase_ok = 0;
+			}
+		}
+
+		yaffs_release_temp_buffer(dev, local_buffer);
+
+		/* If out of space then reverse any chunks we've added */
+		if (!small_increase_ok)
+			yaffs_resize_file_down(obj, old_file_size);
+	}
+
+	if (!small_increase_ok &&
+	    obj->parent &&
+	    obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+	    obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
+		/* Write a hole start header with the old file size */
+		yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
+	}
+
+	return result;
+}
+
+struct yaffs_block_index {
+	int seq;
+	int block;
+};
+
+static int yaffs2_ybicmp(const void *a, const void *b)
+{
+	int aseq = ((struct yaffs_block_index *)a)->seq;
+	int bseq = ((struct yaffs_block_index *)b)->seq;
+	int ablock = ((struct yaffs_block_index *)a)->block;
+	int bblock = ((struct yaffs_block_index *)b)->block;
+
+	if (aseq == bseq)
+		return ablock - bblock;
+
+	return aseq - bseq;
+}
+
+static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
+		struct yaffs_block_info *bi,
+		int blk, int chunk_in_block,
+		int *found_chunks,
+		u8 *chunk_data,
+		struct list_head *hard_list,
+		int summary_available)
+{
+	struct yaffs_obj_hdr *oh;
+	struct yaffs_obj *in;
+	struct yaffs_obj *parent;
+	int equiv_id;
+	loff_t file_size;
+	int is_shrink;
+	int is_unlinked;
+	struct yaffs_ext_tags tags;
+	int result;
+	int alloc_failed = 0;
+	int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
+	struct yaffs_file_var *file_var;
+	struct yaffs_hardlink_var *hl_var;
+	struct yaffs_symlink_var *sl_var;
+
+	if (summary_available) {
+		result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
+		tags.seq_number = bi->seq_number;
+	}
+
+	if (!summary_available || tags.obj_id == 0) {
+		result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
+		dev->tags_used++;
+	} else {
+		dev->summary_used++;
+	}
+
+	/* Let's have a good look at this chunk... */
+
+	if (!tags.chunk_used) {
+		/* An unassigned chunk in the block.
+		 * If there are used chunks after this one, then
+		 * it is a chunk that was skipped due to failing
+		 * the erased check. Just skip it so that it can
+		 * be deleted.
+		 * But, more typically, We get here when this is
+		 * an unallocated chunk and his means that
+		 * either the block is empty or this is the one
+		 * being allocated from
+		 */
+
+		if (*found_chunks) {
+			/* This is a chunk that was skipped due
+			 * to failing the erased check */
+		} else if (chunk_in_block == 0) {
+			/* We're looking at the first chunk in
+			 * the block so the block is unused */
+			bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+			dev->n_erased_blocks++;
+		} else {
+			if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+			    bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+				if (dev->seq_number == bi->seq_number) {
+					/* Allocating from this block*/
+					yaffs_trace(YAFFS_TRACE_SCAN,
+					    " Allocating from %d %d",
+					    blk, chunk_in_block);
+
+					bi->block_state =
+						YAFFS_BLOCK_STATE_ALLOCATING;
+					dev->alloc_block = blk;
+					dev->alloc_page = chunk_in_block;
+					dev->alloc_block_finder = blk;
+				} else {
+					/* This is a partially written block
+					 * that is not the current
+					 * allocation block.
+					 */
+					yaffs_trace(YAFFS_TRACE_SCAN,
+						"Partially written block %d detected. gc will fix this.",
+						blk);
+				}
+			}
+		}
+
+		dev->n_free_chunks++;
+
+	} else if (tags.ecc_result ==
+		YAFFS_ECC_RESULT_UNFIXED) {
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			" Unfixed ECC in chunk(%d:%d), chunk ignored",
+			blk, chunk_in_block);
+			dev->n_free_chunks++;
+	} else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
+		   tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
+		   tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
+		   (tags.chunk_id > 0 &&
+		     tags.n_bytes > dev->data_bytes_per_chunk) ||
+		   tags.seq_number != bi->seq_number) {
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			"Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
+			blk, chunk_in_block, tags.obj_id,
+			tags.chunk_id, tags.n_bytes);
+		dev->n_free_chunks++;
+	} else if (tags.chunk_id > 0) {
+		/* chunk_id > 0 so it is a data chunk... */
+		loff_t endpos;
+		loff_t chunk_base = (tags.chunk_id - 1) *
+					dev->data_bytes_per_chunk;
+
+		*found_chunks = 1;
+
+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+		bi->pages_in_use++;
+
+		in = yaffs_find_or_create_by_number(dev,
+					tags.obj_id,
+					YAFFS_OBJECT_TYPE_FILE);
+		if (!in)
+			/* Out of memory */
+			alloc_failed = 1;
+
+		if (in &&
+		    in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
+		    chunk_base < in->variant.file_variant.shrink_size) {
+			/* This has not been invalidated by
+			 * a resize */
+			if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
+								chunk, -1))
+				alloc_failed = 1;
+
+			/* File size is calculated by looking at
+			 * the data chunks if we have not
+			 * seen an object header yet.
+			 * Stop this practice once we find an
+			 * object header.
+			 */
+			endpos = chunk_base + tags.n_bytes;
+
+			if (!in->valid &&
+			    in->variant.file_variant.scanned_size < endpos) {
+				in->variant.file_variant.
+				    scanned_size = endpos;
+				in->variant.file_variant.
+				    file_size = endpos;
+			}
+		} else if (in) {
+			/* This chunk has been invalidated by a
+			 * resize, or a past file deletion
+			 * so delete the chunk*/
+			yaffs_chunk_del(dev, chunk, 1, __LINE__);
+		}
+	} else {
+		/* chunk_id == 0, so it is an ObjectHeader.
+		 * Thus, we read in the object header and make
+		 * the object
+		 */
+		*found_chunks = 1;
+
+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+		bi->pages_in_use++;
+
+		oh = NULL;
+		in = NULL;
+
+		if (tags.extra_available) {
+			in = yaffs_find_or_create_by_number(dev,
+					tags.obj_id,
+					tags.extra_obj_type);
+			if (!in)
+				alloc_failed = 1;
+		}
+
+		if (!in ||
+		    (!in->valid && dev->param.disable_lazy_load) ||
+		    tags.extra_shadows ||
+		    (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+				 tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
+
+			/* If we don't have  valid info then we
+			 * need to read the chunk
+			 * TODO In future we can probably defer
+			 * reading the chunk and living with
+			 * invalid data until needed.
+			 */
+
+			result = yaffs_rd_chunk_tags_nand(dev,
+						  chunk,
+						  chunk_data,
+						  NULL);
+
+			oh = (struct yaffs_obj_hdr *)chunk_data;
+
+			if (dev->param.inband_tags) {
+				/* Fix up the header if they got
+				 * corrupted by inband tags */
+				oh->shadows_obj =
+				    oh->inband_shadowed_obj_id;
+				oh->is_shrink =
+				    oh->inband_is_shrink;
+			}
+
+			if (!in) {
+				in = yaffs_find_or_create_by_number(dev,
+							tags.obj_id, oh->type);
+				if (!in)
+					alloc_failed = 1;
+			}
+		}
+
+		if (!in) {
+			/* TODO Hoosterman we have a problem! */
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"yaffs tragedy: Could not make object for object  %d at chunk %d during scan",
+				tags.obj_id, chunk);
+			return YAFFS_FAIL;
+		}
+
+		if (in->valid) {
+			/* We have already filled this one.
+			 * We have a duplicate that will be
+			 * discarded, but we first have to suck
+			 * out resize info if it is a file.
+			 */
+			if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
+				((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+				 (tags.extra_available &&
+				  tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+				)) {
+				loff_t this_size = (oh) ?
+					yaffs_oh_to_size(oh) :
+					tags.extra_file_size;
+				u32 parent_obj_id = (oh) ?
+					oh->parent_obj_id :
+					tags.extra_parent_id;
+
+				is_shrink = (oh) ?
+					oh->is_shrink :
+					tags.extra_is_shrink;
+
+				/* If it is deleted (unlinked
+				 * at start also means deleted)
+				 * we treat the file size as
+				 * being zeroed at this point.
+				 */
+				if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
+				    parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
+					this_size = 0;
+					is_shrink = 1;
+				}
+
+				if (is_shrink &&
+				    in->variant.file_variant.shrink_size >
+				    this_size)
+					in->variant.file_variant.shrink_size =
+					this_size;
+
+				if (is_shrink)
+					bi->has_shrink_hdr = 1;
+			}
+			/* Use existing - destroy this one. */
+			yaffs_chunk_del(dev, chunk, 1, __LINE__);
+		}
+
+		if (!in->valid && in->variant_type !=
+		    (oh ? oh->type : tags.extra_obj_type)) {
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
+				oh ? oh->type : tags.extra_obj_type,
+				in->variant_type, tags.obj_id,
+				chunk);
+			in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
+		}
+
+		if (!in->valid &&
+		    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+		     tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
+			/* We only load some info, don't fiddle
+			 * with directory structure */
+			in->valid = 1;
+
+			if (oh) {
+				in->yst_mode = oh->yst_mode;
+				yaffs_load_attribs(in, oh);
+				in->lazy_loaded = 0;
+			} else {
+				in->lazy_loaded = 1;
+			}
+			in->hdr_chunk = chunk;
+
+		} else if (!in->valid) {
+			/* we need to load this info */
+			in->valid = 1;
+			in->hdr_chunk = chunk;
+			if (oh) {
+				in->variant_type = oh->type;
+				in->yst_mode = oh->yst_mode;
+				yaffs_load_attribs(in, oh);
+
+				if (oh->shadows_obj > 0)
+					yaffs_handle_shadowed_obj(dev,
+					     oh->shadows_obj, 1);
+
+				yaffs_set_obj_name_from_oh(in, oh);
+				parent = yaffs_find_or_create_by_number(dev,
+						oh->parent_obj_id,
+						YAFFS_OBJECT_TYPE_DIRECTORY);
+				file_size = yaffs_oh_to_size(oh);
+				is_shrink = oh->is_shrink;
+				equiv_id = oh->equiv_id;
+			} else {
+				in->variant_type = tags.extra_obj_type;
+				parent = yaffs_find_or_create_by_number(dev,
+						tags.extra_parent_id,
+						YAFFS_OBJECT_TYPE_DIRECTORY);
+				file_size = tags.extra_file_size;
+				is_shrink = tags.extra_is_shrink;
+				equiv_id = tags.extra_equiv_id;
+				in->lazy_loaded = 1;
+			}
+			in->dirty = 0;
+
+			if (!parent)
+				alloc_failed = 1;
+
+			/* directory stuff...
+			 * hook up to parent
+			 */
+
+			if (parent &&
+			    parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
+				/* Set up as a directory */
+				parent->variant_type =
+					YAFFS_OBJECT_TYPE_DIRECTORY;
+				INIT_LIST_HEAD(&parent->
+						variant.dir_variant.children);
+			} else if (!parent ||
+				   parent->variant_type !=
+					YAFFS_OBJECT_TYPE_DIRECTORY) {
+				/* Hoosterman, another problem....
+				 * Trying to use a non-directory as a directory
+				 */
+
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+					);
+				parent = dev->lost_n_found;
+			}
+			yaffs_add_obj_to_dir(parent, in);
+
+			is_unlinked = (parent == dev->del_dir) ||
+					(parent == dev->unlinked_dir);
+
+			if (is_shrink)
+				/* Mark the block */
+				bi->has_shrink_hdr = 1;
+
+			/* Note re hardlinks.
+			 * Since we might scan a hardlink before its equivalent
+			 * object is scanned we put them all in a list.
+			 * After scanning is complete, we should have all the
+			 * objects, so we run through this list and fix up all
+			 * the chains.
+			 */
+
+			switch (in->variant_type) {
+			case YAFFS_OBJECT_TYPE_UNKNOWN:
+				/* Todo got a problem */
+				break;
+			case YAFFS_OBJECT_TYPE_FILE:
+				file_var = &in->variant.file_variant;
+				if (file_var->scanned_size < file_size) {
+					/* This covers the case where the file
+					 * size is greater than the data held.
+					 * This will happen if the file is
+					 * resized to be larger than its
+					 * current data extents.
+					 */
+					file_var->file_size = file_size;
+					file_var->scanned_size = file_size;
+				}
+
+				if (file_var->shrink_size > file_size)
+					file_var->shrink_size = file_size;
+
+				break;
+			case YAFFS_OBJECT_TYPE_HARDLINK:
+				hl_var = &in->variant.hardlink_variant;
+				if (!is_unlinked) {
+					hl_var->equiv_id = equiv_id;
+					list_add(&in->hard_links, hard_list);
+				}
+				break;
+			case YAFFS_OBJECT_TYPE_DIRECTORY:
+				/* Do nothing */
+				break;
+			case YAFFS_OBJECT_TYPE_SPECIAL:
+				/* Do nothing */
+				break;
+			case YAFFS_OBJECT_TYPE_SYMLINK:
+				sl_var = &in->variant.symlink_variant;
+				if (oh) {
+					sl_var->alias =
+					    yaffs_clone_str(oh->alias);
+					if (!sl_var->alias)
+						alloc_failed = 1;
+				}
+				break;
+			}
+		}
+	}
+	return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
+}
+
+int yaffs2_scan_backwards(struct yaffs_dev *dev)
+{
+	int blk;
+	int block_iter;
+	int start_iter;
+	int end_iter;
+	int n_to_scan = 0;
+	enum yaffs_block_state state;
+	int c;
+	LIST_HEAD(hard_list);
+	struct yaffs_block_info *bi;
+	u32 seq_number;
+	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+	u8 *chunk_data;
+	int found_chunks;
+	int alloc_failed = 0;
+	struct yaffs_block_index *block_index = NULL;
+	int alt_block_index = 0;
+	int summary_available;
+
+	yaffs_trace(YAFFS_TRACE_SCAN,
+		"yaffs2_scan_backwards starts  intstartblk %d intendblk %d...",
+		dev->internal_start_block, dev->internal_end_block);
+
+	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+	block_index =
+		kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
+
+	if (!block_index) {
+		block_index =
+		    vmalloc(n_blocks * sizeof(struct yaffs_block_index));
+		alt_block_index = 1;
+	}
+
+	if (!block_index) {
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			"yaffs2_scan_backwards() could not allocate block index!"
+			);
+		return YAFFS_FAIL;
+	}
+
+	dev->blocks_in_checkpt = 0;
+
+	chunk_data = yaffs_get_temp_buffer(dev);
+
+	/* Scan all the blocks to determine their state */
+	bi = dev->block_info;
+	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+	     blk++) {
+		yaffs_clear_chunk_bits(dev, blk);
+		bi->pages_in_use = 0;
+		bi->soft_del_pages = 0;
+
+		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
+
+		bi->block_state = state;
+		bi->seq_number = seq_number;
+
+		if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
+			bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
+			bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+
+		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+			"Block scanning block %d state %d seq %d",
+			blk, bi->block_state, seq_number);
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+			dev->blocks_in_checkpt++;
+
+		} else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
+			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+				"block %d is bad", blk);
+		} else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
+			dev->n_erased_blocks++;
+			dev->n_free_chunks += dev->param.chunks_per_block;
+		} else if (bi->block_state ==
+				YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			/* Determine the highest sequence number */
+			if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+			    seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+				block_index[n_to_scan].seq = seq_number;
+				block_index[n_to_scan].block = blk;
+				n_to_scan++;
+				if (seq_number >= dev->seq_number)
+					dev->seq_number = seq_number;
+			} else {
+				/* TODO: Nasty sequence number! */
+				yaffs_trace(YAFFS_TRACE_SCAN,
+					"Block scanning block %d has bad sequence number %d",
+					blk, seq_number);
+			}
+		}
+		bi++;
+	}
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
+
+	cond_resched();
+
+	/* Sort the blocks by sequence number */
+	sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
+		   yaffs2_ybicmp, NULL);
+
+	cond_resched();
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "...done");
+
+	/* Now scan the blocks looking at the data. */
+	start_iter = 0;
+	end_iter = n_to_scan - 1;
+	yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
+
+	/* For each block.... backwards */
+	for (block_iter = end_iter;
+	     !alloc_failed && block_iter >= start_iter;
+	     block_iter--) {
+		/* Cooperative multitasking! This loop can run for so
+		   long that watchdog timers expire. */
+		cond_resched();
+
+		/* get the block to scan in the correct order */
+		blk = block_index[block_iter].block;
+		bi = yaffs_get_block_info(dev, blk);
+
+		summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
+
+		/* For each chunk in each block that needs scanning.... */
+		found_chunks = 0;
+		if (summary_available)
+			c = dev->chunks_per_summary - 1;
+		else
+			c = dev->param.chunks_per_block - 1;
+
+		for (/* c is already initialised */;
+		     !alloc_failed && c >= 0 &&
+		     (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+		      bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
+		      c--) {
+			/* Scan backwards...
+			 * Read the tags and decide what to do
+			 */
+			if (yaffs2_scan_chunk(dev, bi, blk, c,
+					&found_chunks, chunk_data,
+					&hard_list, summary_available) ==
+					YAFFS_FAIL)
+				alloc_failed = 1;
+		}
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			/* If we got this far while scanning, then the block
+			 * is fully allocated. */
+			bi->block_state = YAFFS_BLOCK_STATE_FULL;
+		}
+
+		/* Now let's see if it was dirty */
+		if (bi->pages_in_use == 0 &&
+		    !bi->has_shrink_hdr &&
+		    bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+			yaffs_block_became_dirty(dev, blk);
+		}
+	}
+
+	yaffs_skip_rest_of_block(dev);
+
+	if (alt_block_index)
+		vfree(block_index);
+	else
+		kfree(block_index);
+
+	/* Ok, we've done all the scanning.
+	 * Fix up the hard link chains.
+	 * We have scanned all the objects, now it's time to add these
+	 * hardlinks.
+	 */
+	yaffs_link_fixup(dev, &hard_list);
+
+	yaffs_release_temp_buffer(dev, chunk_data);
+
+	if (alloc_failed)
+		return YAFFS_FAIL;
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
+
+	return YAFFS_OK;
+}
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h
new file mode 100644
index 0000000000..2363bfd8bc
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.h
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS2_H__
+#define __YAFFS_YAFFS2_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+				   struct yaffs_block_info *bi);
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+				    struct yaffs_block_info *bi);
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
+int yaffs2_checkpt_required(struct yaffs_dev *dev);
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
+
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
+int yaffs2_checkpt_save(struct yaffs_dev *dev);
+int yaffs2_checkpt_restore(struct yaffs_dev *dev);
+
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
+int yaffs2_scan_backwards(struct yaffs_dev *dev);
+
+#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yportenv.h b/target/linux/generic/files/fs/yaffs2/yportenv.h
new file mode 100644
index 0000000000..8975af331e
--- /dev/null
+++ b/target/linux/generic/files/fs/yaffs2/yportenv.h
@@ -0,0 +1,85 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YPORTENV_H__
+#define __YPORTENV_H__
+
+/*
+ * Define the MTD version in terms of Linux Kernel versions
+ * This allows yaffs to be used independantly of the kernel
+ * as well as with it.
+ */
+
+#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
+
+#ifdef YAFFS_OUT_OF_TREE
+#include "moduleconfig.h"
+#endif
+
+#include <linux/version.h>
+#define MTD_VERSION_CODE LINUX_VERSION_CODE
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+#include <linux/config.h>
+#endif
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/xattr.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sort.h>
+#include <linux/bitops.h>
+
+/*  These type wrappings are used to support Unicode names in WinCE. */
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x)     x
+
+#define YAFFS_LOSTNFOUND_NAME		"lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX		"obj"
+
+
+#define YAFFS_ROOT_MODE			0755
+#define YAFFS_LOSTNFOUND_MODE		0700
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
+#define Y_TIME_CONVERT(x) (x).tv_sec
+#else
+#define Y_CURRENT_TIME CURRENT_TIME
+#define Y_TIME_CONVERT(x) (x)
+#endif
+
+#define compile_time_assertion(assertion) \
+	({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
+
+
+#define yaffs_printf(msk, fmt, ...) \
+	printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
+
+#define yaffs_trace(msk, fmt, ...) do { \
+	if (yaffs_trace_mask & (msk)) \
+		printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
+} while (0)
+
+
+#endif
diff --git a/target/linux/generic/files/include/linux/ar8216_platform.h b/target/linux/generic/files/include/linux/ar8216_platform.h
new file mode 100644
index 0000000000..24bc442a26
--- /dev/null
+++ b/target/linux/generic/files/include/linux/ar8216_platform.h
@@ -0,0 +1,133 @@
+/*
+ * AR8216 switch driver platform data
+ *
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef AR8216_PLATFORM_H
+#define AR8216_PLATFORM_H
+
+enum ar8327_pad_mode {
+	AR8327_PAD_NC = 0,
+	AR8327_PAD_MAC2MAC_MII,
+	AR8327_PAD_MAC2MAC_GMII,
+	AR8327_PAD_MAC_SGMII,
+	AR8327_PAD_MAC2PHY_MII,
+	AR8327_PAD_MAC2PHY_GMII,
+	AR8327_PAD_MAC_RGMII,
+	AR8327_PAD_PHY_GMII,
+	AR8327_PAD_PHY_RGMII,
+	AR8327_PAD_PHY_MII,
+};
+
+enum ar8327_clk_delay_sel {
+	AR8327_CLK_DELAY_SEL0 = 0,
+	AR8327_CLK_DELAY_SEL1,
+	AR8327_CLK_DELAY_SEL2,
+	AR8327_CLK_DELAY_SEL3,
+};
+
+struct ar8327_pad_cfg {
+	enum ar8327_pad_mode mode;
+	bool rxclk_sel;
+	bool txclk_sel;
+	bool pipe_rxclk_sel;
+	bool txclk_delay_en;
+	bool rxclk_delay_en;
+	bool sgmii_delay_en;
+	enum ar8327_clk_delay_sel txclk_delay_sel;
+	enum ar8327_clk_delay_sel rxclk_delay_sel;
+	bool mac06_exchange_dis;
+};
+
+enum ar8327_port_speed {
+	AR8327_PORT_SPEED_10 = 0,
+	AR8327_PORT_SPEED_100,
+	AR8327_PORT_SPEED_1000,
+};
+
+struct ar8327_port_cfg {
+	int force_link:1;
+	enum ar8327_port_speed speed;
+	int txpause:1;
+	int rxpause:1;
+	int duplex:1;
+};
+
+struct ar8327_sgmii_cfg {
+	u32 sgmii_ctrl;
+	bool serdes_aen;
+};
+
+struct ar8327_led_cfg {
+	u32 led_ctrl0;
+	u32 led_ctrl1;
+	u32 led_ctrl2;
+	u32 led_ctrl3;
+	bool open_drain;
+};
+
+enum ar8327_led_num {
+	AR8327_LED_PHY0_0 = 0,
+	AR8327_LED_PHY0_1,
+	AR8327_LED_PHY0_2,
+	AR8327_LED_PHY1_0,
+	AR8327_LED_PHY1_1,
+	AR8327_LED_PHY1_2,
+	AR8327_LED_PHY2_0,
+	AR8327_LED_PHY2_1,
+	AR8327_LED_PHY2_2,
+	AR8327_LED_PHY3_0,
+	AR8327_LED_PHY3_1,
+	AR8327_LED_PHY3_2,
+	AR8327_LED_PHY4_0,
+	AR8327_LED_PHY4_1,
+	AR8327_LED_PHY4_2,
+};
+
+enum ar8327_led_mode {
+	AR8327_LED_MODE_HW = 0,
+	AR8327_LED_MODE_SW,
+};
+
+struct ar8327_led_info {
+	const char *name;
+	const char *default_trigger;
+	bool active_low;
+	enum ar8327_led_num led_num;
+	enum ar8327_led_mode mode;
+};
+
+#define AR8327_LED_INFO(_led, _mode, _name) {	\
+	.name = (_name), 	   		\
+	.led_num = AR8327_LED_ ## _led,		\
+	.mode = AR8327_LED_MODE_ ## _mode 	\
+}
+
+struct ar8327_platform_data {
+	struct ar8327_pad_cfg *pad0_cfg;
+	struct ar8327_pad_cfg *pad5_cfg;
+	struct ar8327_pad_cfg *pad6_cfg;
+	struct ar8327_sgmii_cfg *sgmii_cfg;
+	struct ar8327_port_cfg port0_cfg;
+	struct ar8327_port_cfg port6_cfg;
+	struct ar8327_led_cfg *led_cfg;
+
+	int (*get_port_link)(unsigned port);
+
+	unsigned num_leds;
+	const struct ar8327_led_info *leds;
+};
+
+#endif /* AR8216_PLATFORM_H */
+
diff --git a/target/linux/generic/files/include/linux/ath5k_platform.h b/target/linux/generic/files/include/linux/ath5k_platform.h
new file mode 100644
index 0000000000..ec85224528
--- /dev/null
+++ b/target/linux/generic/files/include/linux/ath5k_platform.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (c) 2010 Daniel Golle <daniel.golle@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_ATH5K_PLATFORM_H
+#define _LINUX_ATH5K_PLATFORM_H
+
+#define ATH5K_PLAT_EEP_MAX_WORDS	2048
+
+struct ath5k_platform_data {
+	u16 *eeprom_data;
+	u8 *macaddr;
+};
+
+#endif /* _LINUX_ATH5K_PLATFORM_H */
diff --git a/target/linux/generic/files/include/linux/ath9k_platform.h b/target/linux/generic/files/include/linux/ath9k_platform.h
new file mode 100644
index 0000000000..558445ff63
--- /dev/null
+++ b/target/linux/generic/files/include/linux/ath9k_platform.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_ATH9K_PLATFORM_H
+#define _LINUX_ATH9K_PLATFORM_H
+
+#define ATH9K_PLAT_EEP_MAX_WORDS	2048
+
+struct ath9k_platform_data {
+	const char *eeprom_name;
+
+	u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
+	u8 *macaddr;
+
+	int led_pin;
+	u32 gpio_mask;
+	u32 gpio_val;
+
+	u32 bt_active_pin;
+	u32 bt_priority_pin;
+	u32 wlan_active_pin;
+
+	bool endian_check;
+	bool is_clk_25mhz;
+	bool tx_gain_buffalo;
+	bool disable_2ghz;
+	bool disable_5ghz;
+	bool led_active_high;
+
+	int (*get_mac_revision)(void);
+	int (*external_reset)(void);
+
+	bool use_eeprom;
+
+	int num_leds;
+	const struct gpio_led *leds;
+	const char *led_name;
+
+	unsigned num_btns;
+	const struct gpio_keys_button *btns;
+	unsigned btn_poll_interval;
+
+	bool ubnt_hsr;
+};
+
+#endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/target/linux/generic/files/include/linux/myloader.h b/target/linux/generic/files/include/linux/myloader.h
new file mode 100644
index 0000000000..d89e415fba
--- /dev/null
+++ b/target/linux/generic/files/include/linux/myloader.h
@@ -0,0 +1,121 @@
+/*
+ *  Compex's MyLoader specific definitions
+ *
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#ifndef _MYLOADER_H_
+#define _MYLOADER_H_
+
+/* Myloader specific magic numbers */
+#define MYLO_MAGIC_SYS_PARAMS	0x20021107
+#define MYLO_MAGIC_PARTITIONS	0x20021103
+#define MYLO_MAGIC_BOARD_PARAMS	0x20021103
+
+/* Vendor ID's (seems to be same as the PCI vendor ID's) */
+#define VENID_COMPEX		0x11F6
+
+/* Devices based on the ADM5120 */
+#define DEVID_COMPEX_NP27G	0x0078
+#define DEVID_COMPEX_NP28G	0x044C
+#define DEVID_COMPEX_NP28GHS	0x044E
+#define DEVID_COMPEX_WP54Gv1C	0x0514
+#define DEVID_COMPEX_WP54G	0x0515
+#define DEVID_COMPEX_WP54AG	0x0546
+#define DEVID_COMPEX_WPP54AG	0x0550
+#define DEVID_COMPEX_WPP54G	0x0555
+
+/* Devices based on the Atheros AR2317 */
+#define DEVID_COMPEX_NP25G	0x05E6
+#define DEVID_COMPEX_WPE53G	0x05DC
+
+/* Devices based on the Atheros AR71xx */
+#define DEVID_COMPEX_WP543	0x0640
+#define DEVID_COMPEX_WPE72	0x0672
+
+/* Devices based on the IXP422 */
+#define DEVID_COMPEX_WP18	0x047E
+#define DEVID_COMPEX_NP18A	0x0489
+
+/* Other devices */
+#define DEVID_COMPEX_NP26G8M	0x03E8
+#define DEVID_COMPEX_NP26G16M	0x03E9
+
+struct mylo_partition {
+	uint16_t	flags;	/* partition flags */
+	uint16_t	type;	/* type of the partition */
+	uint32_t	addr;	/* relative address of the partition from the
+				   flash start */
+	uint32_t	size;	/* size of the partition in bytes */
+	uint32_t	param;	/* if this is the active partition, the
+				   MyLoader load code to this address */
+};
+
+#define PARTITION_FLAG_ACTIVE	0x8000 /* this is the active partition,
+					* MyLoader loads firmware from here */
+#define PARTITION_FLAG_ISRAM	0x2000 /* FIXME: this is a RAM partition? */
+#define PARTIIION_FLAG_RAMLOAD	0x1000 /* FIXME: load this partition into the RAM? */
+#define PARTITION_FLAG_PRELOAD	0x0800 /* the partition data preloaded to RAM
+					* before decompression */
+#define PARTITION_FLAG_LZMA	0x0100 /* partition data compressed by LZMA */
+#define PARTITION_FLAG_HAVEHDR  0x0002 /* the partition data have a header */
+
+#define PARTITION_TYPE_FREE	0
+#define PARTITION_TYPE_USED	1
+
+#define MYLO_MAX_PARTITIONS	8	/* maximum number of partitions in the
+					   partition table */
+
+struct mylo_partition_table {
+	uint32_t	magic;		/* must be MYLO_MAGIC_PARTITIONS */
+	uint32_t	res0;		/* unknown/unused */
+	uint32_t	res1;		/* unknown/unused */
+	uint32_t 	res2;		/* unknown/unused */
+	struct mylo_partition partitions[MYLO_MAX_PARTITIONS];
+};
+
+struct mylo_partition_header {
+	uint32_t	len;		/* length of the partition data */
+	uint32_t	crc;		/* CRC value of the partition data */
+};
+
+struct mylo_system_params {
+	uint32_t	magic;		/* must be MYLO_MAGIC_SYS_PARAMS */
+	uint32_t	res0;
+	uint32_t	res1;
+	uint32_t	mylo_ver;
+	uint16_t	vid;		/* Vendor ID */
+	uint16_t	did;		/* Device ID */
+	uint16_t	svid;		/* Sub Vendor ID */
+	uint16_t	sdid;		/* Sub Device ID */
+	uint32_t	rev;		/* device revision */
+	uint32_t	fwhi;
+	uint32_t	fwlo;
+	uint32_t	tftp_addr;
+	uint32_t	prog_start;
+	uint32_t	flash_size;	/* size of boot FLASH in bytes */
+	uint32_t	dram_size;	/* size of onboard RAM in bytes */
+};
+
+struct mylo_eth_addr {
+	uint8_t	mac[6];
+	uint8_t	csum[2];
+};
+
+#define MYLO_ETHADDR_COUNT	8	/* maximum number of ethernet address
+					   in the board parameters */
+
+struct mylo_board_params {
+	uint32_t	magic;	/* must be MYLO_MAGIC_BOARD_PARAMS */
+	uint32_t	res0;
+	uint32_t	res1;
+	uint32_t	res2;
+	struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT];
+};
+
+#endif /* _MYLOADER_H_*/
diff --git a/target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h b/target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h
new file mode 100644
index 0000000000..e4fcfafa74
--- /dev/null
+++ b/target/linux/generic/files/include/linux/platform_data/adm6996-gpio.h
@@ -0,0 +1,30 @@
+/*
+ * ADM6996 GPIO platform data
+ *
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+
+#ifndef __PLATFORM_ADM6996_GPIO_H
+#define __PLATFORM_ADM6996_GPIO_H
+
+#include <linux/kernel.h>
+
+enum adm6996_model {
+	ADM6996FC = 1,
+	ADM6996M = 2,
+	ADM6996L = 3,
+};
+
+struct adm6996_gpio_platform_data {
+	u8 eecs;
+	u8 eesk;
+	u8 eedi;
+	u8 eerc;
+	enum adm6996_model model;
+};
+
+#endif
diff --git a/target/linux/generic/files/include/linux/platform_data/b53.h b/target/linux/generic/files/include/linux/platform_data/b53.h
new file mode 100644
index 0000000000..78427417a1
--- /dev/null
+++ b/target/linux/generic/files/include/linux/platform_data/b53.h
@@ -0,0 +1,36 @@
+/*
+ * B53 platform data
+ *
+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __B53_H
+#define __B53_H
+
+#include <linux/kernel.h>
+
+struct b53_platform_data {
+	u32 chip_id;
+	u16 enabled_ports;
+
+	/* allow to specify an ethX alias */
+	const char *alias;
+
+	/* only used by MMAP'd driver */
+	unsigned big_endian:1;
+	void __iomem *regs;
+};
+
+#endif
diff --git a/target/linux/generic/files/include/linux/routerboot.h b/target/linux/generic/files/include/linux/routerboot.h
new file mode 100644
index 0000000000..3cda858cf9
--- /dev/null
+++ b/target/linux/generic/files/include/linux/routerboot.h
@@ -0,0 +1,106 @@
+/*
+ *  Mikrotik's RouterBOOT definitions
+ *
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#ifndef _ROUTERBOOT_H
+#define _ROUTERBOOT_H
+
+#define RB_MAC_SIZE		6
+
+/*
+ * Magic numbers
+ */
+#define RB_MAGIC_HARD	0x64726148 /* "Hard" */
+#define RB_MAGIC_SOFT	0x74666F53 /* "Soft" */
+#define RB_MAGIC_DAWN	0x6E776144 /* "Dawn" */
+
+#define RB_ID_TERMINATOR	0
+
+/*
+ * ID values for Hardware settings
+ */
+#define RB_ID_HARD_01		1
+#define RB_ID_HARD_02		2
+#define RB_ID_FLASH_INFO	3
+#define RB_ID_MAC_ADDRESS_PACK	4
+#define RB_ID_BOARD_NAME	5
+#define RB_ID_BIOS_VERSION	6
+#define RB_ID_HARD_07		7
+#define RB_ID_SDRAM_TIMINGS	8
+#define RB_ID_DEVICE_TIMINGS	9
+#define RB_ID_SOFTWARE_ID	10
+#define RB_ID_SERIAL_NUMBER	11
+#define RB_ID_HARD_12		12
+#define RB_ID_MEMORY_SIZE	13
+#define RB_ID_MAC_ADDRESS_COUNT	14
+#define RB_ID_HW_OPTIONS	21
+#define RB_ID_WLAN_DATA		22
+
+/*
+ * ID values for Software settings
+ */
+#define RB_ID_UART_SPEED	1
+#define RB_ID_BOOT_DELAY	2
+#define RB_ID_BOOT_DEVICE	3
+#define RB_ID_BOOT_KEY		4
+#define RB_ID_CPU_MODE		5
+#define RB_ID_FW_VERSION	6
+#define RB_ID_SOFT_07		7
+#define RB_ID_SOFT_08		8
+#define RB_ID_BOOT_PROTOCOL	9
+#define RB_ID_SOFT_10		10
+#define RB_ID_SOFT_11		11
+
+/*
+ * UART_SPEED values
+ */
+#define RB_UART_SPEED_115200	0
+#define RB_UART_SPEED_57600	1
+#define RB_UART_SPEED_38400	2
+#define RB_UART_SPEED_19200	3
+#define RB_UART_SPEED_9600	4
+#define RB_UART_SPEED_4800	5
+#define RB_UART_SPEED_2400	6
+#define RB_UART_SPEED_1200	7
+
+/*
+ * BOOT_DELAY values
+ */
+#define RB_BOOT_DELAY_0SEC	0
+#define RB_BOOT_DELAY_1SEC	1
+#define RB_BOOT_DELAY_2SEC	2
+
+/*
+ * BOOT_DEVICE values
+ */
+#define RB_BOOT_DEVICE_ETHER	0
+#define RB_BOOT_DEVICE_NANDETH	1
+#define RB_BOOT_DEVICE_ETHONCE	2
+#define RB_BOOT_DEVICE_NANDONLY	3
+
+/*
+ * BOOT_KEY values
+ */
+#define RB_BOOT_KEY_ANY		0
+#define RB_BOOT_KEY_DEL		1
+
+/*
+ * CPU_MODE values
+ */
+#define RB_CPU_MODE_POWERSAVE	0
+#define RB_CPU_MODE_REGULAR	1
+
+/*
+ * BOOT_PROTOCOL values
+ */
+#define RB_BOOT_PROTOCOL_BOOTP	0
+#define RB_BOOT_PROTOCOL_DHCP	1
+
+#endif /* _ROUTERBOOT_H */
diff --git a/target/linux/generic/files/include/linux/rt2x00_platform.h b/target/linux/generic/files/include/linux/rt2x00_platform.h
new file mode 100644
index 0000000000..e10377e21b
--- /dev/null
+++ b/target/linux/generic/files/include/linux/rt2x00_platform.h
@@ -0,0 +1,23 @@
+/*
+ * Platform data definition for the rt2x00 driver
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _RT2X00_PLATFORM_H
+#define _RT2X00_PLATFORM_H
+
+struct rt2x00_platform_data {
+	char *eeprom_file_name;
+	const u8 *mac_address;
+
+	int disable_2ghz;
+	int disable_5ghz;
+};
+
+#endif /* _RT2X00_PLATFORM_H */
diff --git a/target/linux/generic/files/include/linux/rtl8366.h b/target/linux/generic/files/include/linux/rtl8366.h
new file mode 100644
index 0000000000..78daed2205
--- /dev/null
+++ b/target/linux/generic/files/include/linux/rtl8366.h
@@ -0,0 +1,40 @@
+/*
+ * Platform data definition for the Realtek RTL8366RB/S ethernet switch driver
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ */
+
+#ifndef _RTL8366_H
+#define _RTL8366_H
+
+#define RTL8366_DRIVER_NAME	"rtl8366"
+#define RTL8366S_DRIVER_NAME	"rtl8366s"
+#define RTL8366RB_DRIVER_NAME	"rtl8366rb"
+
+enum rtl8366_type {
+	RTL8366_TYPE_UNKNOWN,
+	RTL8366_TYPE_S,
+	RTL8366_TYPE_RB,
+};
+
+struct rtl8366_initval {
+	unsigned	reg;
+	u16		val;
+};
+
+struct rtl8366_platform_data {
+	unsigned	gpio_sda;
+	unsigned	gpio_sck;
+	void		(*hw_reset)(bool active);
+
+	unsigned	num_initvals;
+	struct rtl8366_initval *initvals;
+};
+
+enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata);
+
+#endif /*  _RTL8366_H */
diff --git a/target/linux/generic/files/include/linux/rtl8367.h b/target/linux/generic/files/include/linux/rtl8367.h
new file mode 100644
index 0000000000..855de6a5cc
--- /dev/null
+++ b/target/linux/generic/files/include/linux/rtl8367.h
@@ -0,0 +1,60 @@
+/*
+ * Platform data definition for the Realtek RTL8367 ethernet switch driver
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ */
+
+#ifndef _RTL8367_H
+#define _RTL8367_H
+
+#define RTL8367_DRIVER_NAME	"rtl8367"
+#define RTL8367B_DRIVER_NAME	"rtl8367b"
+
+enum rtl8367_port_speed {
+	RTL8367_PORT_SPEED_10 = 0,
+	RTL8367_PORT_SPEED_100,
+	RTL8367_PORT_SPEED_1000,
+};
+
+struct rtl8367_port_ability {
+	int force_mode;
+	int nway;
+	int txpause;
+	int rxpause;
+	int link;
+	int duplex;
+	enum rtl8367_port_speed speed;
+};
+
+enum rtl8367_extif_mode {
+	RTL8367_EXTIF_MODE_DISABLED = 0,
+	RTL8367_EXTIF_MODE_RGMII,
+	RTL8367_EXTIF_MODE_MII_MAC,
+	RTL8367_EXTIF_MODE_MII_PHY,
+	RTL8367_EXTIF_MODE_TMII_MAC,
+	RTL8367_EXTIF_MODE_TMII_PHY,
+	RTL8367_EXTIF_MODE_GMII,
+	RTL8367_EXTIF_MODE_RGMII_33V,
+};
+
+struct rtl8367_extif_config {
+	unsigned int txdelay;
+	unsigned int rxdelay;
+	enum rtl8367_extif_mode mode;
+	struct rtl8367_port_ability ability;
+};
+
+struct rtl8367_platform_data {
+	unsigned gpio_sda;
+	unsigned gpio_sck;
+	void (*hw_reset)(bool active);
+
+	struct rtl8367_extif_config *extif0_cfg;
+	struct rtl8367_extif_config *extif1_cfg;
+};
+
+#endif /*  _RTL8367_H */
diff --git a/target/linux/generic/files/include/linux/switch.h b/target/linux/generic/files/include/linux/switch.h
new file mode 100644
index 0000000000..f8380b98c5
--- /dev/null
+++ b/target/linux/generic/files/include/linux/switch.h
@@ -0,0 +1,179 @@
+/*
+ * switch.h: Switch configuration API
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _LINUX_SWITCH_H
+#define _LINUX_SWITCH_H
+
+#include <net/genetlink.h>
+#include <uapi/linux/switch.h>
+
+struct switch_dev;
+struct switch_op;
+struct switch_val;
+struct switch_attr;
+struct switch_attrlist;
+struct switch_led_trigger;
+
+int register_switch(struct switch_dev *dev, struct net_device *netdev);
+void unregister_switch(struct switch_dev *dev);
+
+/**
+ * struct switch_attrlist - attribute list
+ *
+ * @n_attr: number of attributes
+ * @attr: pointer to the attributes array
+ */
+struct switch_attrlist {
+	int n_attr;
+	const struct switch_attr *attr;
+};
+
+enum switch_port_speed {
+	SWITCH_PORT_SPEED_UNKNOWN = 0,
+	SWITCH_PORT_SPEED_10 = 10,
+	SWITCH_PORT_SPEED_100 = 100,
+	SWITCH_PORT_SPEED_1000 = 1000,
+};
+
+struct switch_port_link {
+	bool link;
+	bool duplex;
+	bool aneg;
+	bool tx_flow;
+	bool rx_flow;
+	enum switch_port_speed speed;
+	/* in ethtool adv_t format */
+	u32 eee;
+};
+
+struct switch_port_stats {
+	unsigned long tx_bytes;
+	unsigned long rx_bytes;
+};
+
+/**
+ * struct switch_dev_ops - switch driver operations
+ *
+ * @attr_global: global switch attribute list
+ * @attr_port: port attribute list
+ * @attr_vlan: vlan attribute list
+ *
+ * Callbacks:
+ *
+ * @get_vlan_ports: read the port list of a VLAN
+ * @set_vlan_ports: set the port list of a VLAN
+ *
+ * @get_port_pvid: get the primary VLAN ID of a port
+ * @set_port_pvid: set the primary VLAN ID of a port
+ *
+ * @apply_config: apply all changed settings to the switch
+ * @reset_switch: resetting the switch
+ */
+struct switch_dev_ops {
+	struct switch_attrlist attr_global, attr_port, attr_vlan;
+
+	int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
+	int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
+
+	int (*get_port_pvid)(struct switch_dev *dev, int port, int *val);
+	int (*set_port_pvid)(struct switch_dev *dev, int port, int val);
+
+	int (*apply_config)(struct switch_dev *dev);
+	int (*reset_switch)(struct switch_dev *dev);
+
+	int (*get_port_link)(struct switch_dev *dev, int port,
+			     struct switch_port_link *link);
+	int (*set_port_link)(struct switch_dev *dev, int port,
+			     struct switch_port_link *link);
+	int (*get_port_stats)(struct switch_dev *dev, int port,
+			      struct switch_port_stats *stats);
+
+	int (*phy_read16)(struct switch_dev *dev, int addr, u8 reg, u16 *value);
+	int (*phy_write16)(struct switch_dev *dev, int addr, u8 reg, u16 value);
+};
+
+struct switch_dev {
+	struct device_node *of_node;
+	const struct switch_dev_ops *ops;
+	/* will be automatically filled */
+	char devname[IFNAMSIZ];
+
+	const char *name;
+	/* NB: either alias or netdev must be set */
+	const char *alias;
+	struct net_device *netdev;
+
+	unsigned int ports;
+	unsigned int vlans;
+	unsigned int cpu_port;
+
+	/* the following fields are internal for swconfig */
+	unsigned int id;
+	struct list_head dev_list;
+	unsigned long def_global, def_port, def_vlan;
+
+	struct mutex sw_mutex;
+	struct switch_port *portbuf;
+	struct switch_portmap *portmap;
+	struct switch_port_link linkbuf;
+
+	char buf[128];
+
+#ifdef CONFIG_SWCONFIG_LEDS
+	struct switch_led_trigger *led_trigger;
+#endif
+};
+
+struct switch_port {
+	u32 id;
+	u32 flags;
+};
+
+struct switch_portmap {
+	u32 virt;
+	const char *s;
+};
+
+struct switch_val {
+	const struct switch_attr *attr;
+	unsigned int port_vlan;
+	unsigned int len;
+	union {
+		const char *s;
+		u32 i;
+		struct switch_port *ports;
+		struct switch_port_link *link;
+	} value;
+};
+
+struct switch_attr {
+	int disabled;
+	int type;
+	const char *name;
+	const char *description;
+
+	int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
+	int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
+
+	/* for driver internal use */
+	int id;
+	int ofs;
+	int max;
+};
+
+int switch_generic_set_link(struct switch_dev *dev, int port,
+			    struct switch_port_link *link);
+
+#endif /* _LINUX_SWITCH_H */
diff --git a/target/linux/generic/files/include/uapi/linux/switch.h b/target/linux/generic/files/include/uapi/linux/switch.h
new file mode 100644
index 0000000000..ea449653fa
--- /dev/null
+++ b/target/linux/generic/files/include/uapi/linux/switch.h
@@ -0,0 +1,119 @@
+/*
+ * switch.h: Switch configuration API
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _UAPI_LINUX_SWITCH_H
+#define _UAPI_LINUX_SWITCH_H
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#ifndef __KERNEL__
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#endif
+
+/* main attributes */
+enum {
+	SWITCH_ATTR_UNSPEC,
+	/* global */
+	SWITCH_ATTR_TYPE,
+	/* device */
+	SWITCH_ATTR_ID,
+	SWITCH_ATTR_DEV_NAME,
+	SWITCH_ATTR_ALIAS,
+	SWITCH_ATTR_NAME,
+	SWITCH_ATTR_VLANS,
+	SWITCH_ATTR_PORTS,
+	SWITCH_ATTR_PORTMAP,
+	SWITCH_ATTR_CPU_PORT,
+	/* attributes */
+	SWITCH_ATTR_OP_ID,
+	SWITCH_ATTR_OP_TYPE,
+	SWITCH_ATTR_OP_NAME,
+	SWITCH_ATTR_OP_PORT,
+	SWITCH_ATTR_OP_VLAN,
+	SWITCH_ATTR_OP_VALUE_INT,
+	SWITCH_ATTR_OP_VALUE_STR,
+	SWITCH_ATTR_OP_VALUE_PORTS,
+	SWITCH_ATTR_OP_VALUE_LINK,
+	SWITCH_ATTR_OP_DESCRIPTION,
+	/* port lists */
+	SWITCH_ATTR_PORT,
+	SWITCH_ATTR_MAX
+};
+
+enum {
+	/* port map */
+	SWITCH_PORTMAP_PORTS,
+	SWITCH_PORTMAP_SEGMENT,
+	SWITCH_PORTMAP_VIRT,
+	SWITCH_PORTMAP_MAX
+};
+
+/* commands */
+enum {
+	SWITCH_CMD_UNSPEC,
+	SWITCH_CMD_GET_SWITCH,
+	SWITCH_CMD_NEW_ATTR,
+	SWITCH_CMD_LIST_GLOBAL,
+	SWITCH_CMD_GET_GLOBAL,
+	SWITCH_CMD_SET_GLOBAL,
+	SWITCH_CMD_LIST_PORT,
+	SWITCH_CMD_GET_PORT,
+	SWITCH_CMD_SET_PORT,
+	SWITCH_CMD_LIST_VLAN,
+	SWITCH_CMD_GET_VLAN,
+	SWITCH_CMD_SET_VLAN
+};
+
+/* data types */
+enum switch_val_type {
+	SWITCH_TYPE_UNSPEC,
+	SWITCH_TYPE_INT,
+	SWITCH_TYPE_STRING,
+	SWITCH_TYPE_PORTS,
+	SWITCH_TYPE_LINK,
+	SWITCH_TYPE_NOVAL,
+};
+
+/* port nested attributes */
+enum {
+	SWITCH_PORT_UNSPEC,
+	SWITCH_PORT_ID,
+	SWITCH_PORT_FLAG_TAGGED,
+	SWITCH_PORT_ATTR_MAX
+};
+
+/* link nested attributes */
+enum {
+	SWITCH_LINK_UNSPEC,
+	SWITCH_LINK_FLAG_LINK,
+	SWITCH_LINK_FLAG_DUPLEX,
+	SWITCH_LINK_FLAG_ANEG,
+	SWITCH_LINK_FLAG_TX_FLOW,
+	SWITCH_LINK_FLAG_RX_FLOW,
+	SWITCH_LINK_SPEED,
+	SWITCH_LINK_FLAG_EEE_100BASET,
+	SWITCH_LINK_FLAG_EEE_1000BASET,
+	SWITCH_LINK_ATTR_MAX,
+};
+
+#define SWITCH_ATTR_DEFAULTS_OFFSET	0x1000
+
+
+#endif /* _UAPI_LINUX_SWITCH_H */
diff --git a/target/linux/generic/image/Makefile b/target/linux/generic/image/Makefile
new file mode 100644
index 0000000000..e733e0a37a
--- /dev/null
+++ b/target/linux/generic/image/Makefile
@@ -0,0 +1,12 @@
+# 
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+# use default targets for everything
+
+$(eval $(call BuildImage))
diff --git a/target/linux/generic/image/initramfs-base-files.txt b/target/linux/generic/image/initramfs-base-files.txt
new file mode 100644
index 0000000000..eda5d0d278
--- /dev/null
+++ b/target/linux/generic/image/initramfs-base-files.txt
@@ -0,0 +1,9 @@
+nod /dev/console 600 0 0 c 5 1
+nod /dev/null 666 0 0 c 1 3
+nod /dev/zero 666 0 0 c 1 5
+nod /dev/tty 666 0 0 c 5 0
+nod /dev/tty0 660 0 0 c 4 0
+nod /dev/tty1 660 0 0 c 4 1
+nod /dev/random 666 0 0 c 1 8
+nod /dev/urandom 666 0 0 c 1 9
+dir /dev/pts 755 0 0
diff --git a/target/linux/generic/image/lzma-loader/Makefile b/target/linux/generic/image/lzma-loader/Makefile
new file mode 100644
index 0000000000..d75a4468b0
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/Makefile
@@ -0,0 +1,46 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME := loader
+PKG_VERSION := 0.05
+
+PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)-$(PKG_VERSION)$(LOADER_TYPE)
+
+$(PKG_BUILD_DIR)/.prepared:
+	mkdir $(PKG_BUILD_DIR)
+	$(CP) ./src/* $(PKG_BUILD_DIR)/
+	touch $@
+
+$(PKG_BUILD_DIR)/lzma.elf: $(PKG_BUILD_DIR)/.prepared $(PKG_BUILD_DIR)/vmlinux.lzma
+	PATH="$(TARGET_PATH)" $(MAKE) -C $(PKG_BUILD_DIR) \
+		CC="$(TARGET_CC)" CROSS_COMPILE="$(TARGET_CROSS)" \
+		RAMSIZE=$(RAMSIZE) \
+		LOADADDR=$(LOADADDR) \
+		KERNEL_ENTRY=$(KERNEL_ENTRY) \
+		IMAGE_COPY=$(IMAGE_COPY)
+
+
+$(PKG_BUILD_DIR)/vmlinux.lzma: $(KDIR)/vmlinux.lzma
+	$(CP) $< $@
+
+$(KDIR)/loader$(LOADER_TYPE).elf: $(PKG_BUILD_DIR)/lzma.elf
+	$(CP) $< $@
+
+$(KDIR)/loader$(LOADER_TYPE).bin: $(PKG_BUILD_DIR)/lzma.bin
+	$(CP) $< $@
+
+download: 
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: $(KDIR)/loader$(LOADER_TYPE).elf $(KDIR)/loader$(LOADER_TYPE).bin
+install:
+
+clean:
+	rm -rf $(PKG_BUILD_DIR)
+	rm -f $(KDIR)/loader.elf
+	rm -f $(KDIR)/loader.bin
diff --git a/target/linux/generic/image/lzma-loader/src/LzmaDecode.c b/target/linux/generic/image/lzma-loader/src/LzmaDecode.c
new file mode 100644
index 0000000000..c90a0d3ef4
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/LzmaDecode.c
@@ -0,0 +1,590 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+ 
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#if 0
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+#endif
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/target/linux/generic/image/lzma-loader/src/LzmaDecode.h b/target/linux/generic/image/lzma-loader/src/LzmaDecode.h
new file mode 100644
index 0000000000..213062af12
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/LzmaDecode.h
@@ -0,0 +1,131 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifndef SizeT
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+#define SizeT size_t
+#else
+#define SizeT UInt32
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/target/linux/generic/image/lzma-loader/src/Makefile b/target/linux/generic/image/lzma-loader/src/Makefile
new file mode 100644
index 0000000000..910172c4f8
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/Makefile
@@ -0,0 +1,68 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+RAMSTART = 0x80000000
+RAMSIZE = 0x00100000		# 1MB
+LOADADDR = 0x80400000		# RAM start + 4M
+KERNEL_ENTRY = 0x80001000
+IMAGE_COPY:=0
+
+CROSS_COMPILE = mips-linux-
+
+OBJCOPY:= $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
+CFLAGS := -fno-builtin -Os -G 0 -ffunction-sections -mno-abicalls -fno-pic -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -Wall -DRAMSTART=${RAMSTART} -DRAMSIZE=${RAMSIZE} -DKERNEL_ENTRY=${KERNEL_ENTRY} -D_LZMA_IN_CB
+ifeq ($(IMAGE_COPY),1)
+CFLAGS += -DLOADADDR=${LOADADDR} -DIMAGE_COPY=1
+endif
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+CC =       $(CROSS_COMPILE)gcc
+LD =       $(CROSS_COMPILE)ld
+OBJDUMP =  $(CROSS_COMPILE)objdump
+
+O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+
+# Drop some uninteresting sections in the kernel.
+# This is only relevant for ELF kernels but doesn't hurt a.out
+drop-sections   = .reginfo .mdebug .comment
+strip-flags     = $(addprefix --remove-section=,$(drop-sections))
+
+all : lzma.elf lzma.bin
+
+lzma.lds: lzma.lds.in
+	sed -e 's,@LOADADDR@,$(LOADADDR),g' -e 's,@ENTRY@,_start,g' $< >$@
+
+kernel.o: vmlinux.lzma lzma.lds
+	$(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $<
+
+lzma.bin: lzma.elf
+	$(OBJCOPY) $< $@
+
+ifeq ($(IMAGE_COPY),1)
+LOADER_ENTRY ?= $(KERNEL_ENTRY)
+lzma.o: decompress.o LzmaDecode.o kernel.o
+	sed -e 's,@LOADADDR@,$(LOADADDR),g' -e 's,@ENTRY@,entry,g' lzma.lds.in >lzma-stage2.lds
+	$(LD) -static --no-warn-mismatch -e entry -Tlzma-stage2.lds -o temp-$@ $^
+	$(OBJCOPY) temp-$@ lzma.tmp
+	@echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > lzma-data.lds
+	$(LD) -no-warn-mismatch -T lzma-data.lds -r -o $@ -b binary lzma.tmp --oformat $(O_FORMAT)
+	
+lzma.elf: start.o lzma.o
+	sed -e 's,@LOADADDR@,$(LOADER_ENTRY),g' lzma-copy.lds.in >lzma-copy.lds
+	$(LD) -s -Tlzma-copy.lds -o $@ $^
+else
+lzma.elf: start.o decompress.o LzmaDecode.o kernel.o
+	$(LD) -s -Tlzma.lds -o $@ $^
+endif
+
+clean:
+	rm -f *.o lzma.elf lzma.bin *.tmp *.lds
diff --git a/target/linux/generic/image/lzma-loader/src/decompress.c b/target/linux/generic/image/lzma-loader/src/decompress.c
new file mode 100644
index 0000000000..45ac509cdc
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/decompress.c
@@ -0,0 +1,157 @@
+/*
+ * LZMA compressed kernel decompressor for bcm947xx boards
+ *
+ * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Please note, this was code based on the bunzip2 decompressor code
+ * by Manuel Novoa III  (mjn3@codepoet.org), although the only thing left
+ * is an idea and part of original vendor code
+ *
+ *
+ * 12-Mar-2005  Mineharu Takahara <mtakahar@yahoo.com>
+ *   pass actual output size to decoder (stream mode
+ *   compressed input is not a requirement anymore)
+ *
+ * 24-Apr-2005 Oleg I. Vdovikin
+ *   reordered functions using lds script, removed forward decl
+ *
+ * ??-Nov-2005 Mike Baker
+ *   reorder the script as an lzma wrapper; do not depend on flash access
+ */
+
+#include "LzmaDecode.h"
+
+#define KSEG0			0x80000000
+#define KSEG1			0xa0000000
+
+#define KSEG1ADDR(a)		((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
+
+#define Index_Invalidate_I	0x00
+#define Index_Writeback_Inv_D   0x01
+
+#define cache_unroll(base,op)	\
+	__asm__ __volatile__(		\
+		".set noreorder;\n"		\
+		".set mips3;\n"			\
+		"cache %1, (%0);\n"		\
+		".set mips0;\n"			\
+		".set reorder\n"		\
+		:						\
+		: "r" (base),			\
+		  "i" (op));
+
+
+static __inline__ void blast_icache(unsigned long size, unsigned long lsize)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + size);
+
+	while(start < end) {
+		cache_unroll(start,Index_Invalidate_I);
+		start += lsize;
+	}
+}
+
+static __inline__ void blast_dcache(unsigned long size, unsigned long lsize)
+{
+	unsigned long start = KSEG0;
+	unsigned long end = (start + size);
+
+	while(start < end) {
+		cache_unroll(start,Index_Writeback_Inv_D);
+		start += lsize;
+	}
+}
+
+unsigned char *data;
+
+static int read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize)
+{
+	*bufferSize = 1;
+	*buffer = data;
+	++data;
+	return LZMA_RESULT_OK;
+}
+
+static __inline__ unsigned char get_byte(void)
+{
+	unsigned char *buffer;
+	UInt32 fake;
+	
+	return read_byte(0, &buffer, &fake), *buffer;
+}
+
+/* This puts lzma workspace 128k below RAM end. 
+ * That should be enough for both lzma and stack
+ */
+static char *buffer = (char *)(RAMSTART + RAMSIZE - 0x00020000);
+extern char lzma_start[];
+extern char lzma_end[];
+
+/* should be the first function */
+void entry(unsigned long icache_size, unsigned long icache_lsize, 
+	unsigned long dcache_size, unsigned long dcache_lsize)
+{
+	unsigned int i;  /* temp value */
+	unsigned int osize; /* uncompressed size */
+	volatile unsigned int arg0, arg1, arg2, arg3;
+
+	/* restore argument registers */
+	__asm__ __volatile__ ("ori %0, $12, 0":"=r"(arg0));
+	__asm__ __volatile__ ("ori %0, $13, 0":"=r"(arg1));
+	__asm__ __volatile__ ("ori %0, $14, 0":"=r"(arg2));
+	__asm__ __volatile__ ("ori %0, $15, 0":"=r"(arg3));
+
+	ILzmaInCallback callback;
+	CLzmaDecoderState vs;
+	callback.Read = read_byte;
+
+	data = lzma_start;
+
+	/* lzma args */
+	i = get_byte();
+	vs.Properties.lc = i % 9, i = i / 9;
+	vs.Properties.lp = i % 5, vs.Properties.pb = i / 5;
+
+	vs.Probs = (CProb *)buffer;
+
+	/* skip rest of the LZMA coder property */
+	for (i = 0; i < 4; i++)
+		get_byte();
+
+	/* read the lower half of uncompressed size in the header */
+	osize = ((unsigned int)get_byte()) +
+		((unsigned int)get_byte() << 8) +
+		((unsigned int)get_byte() << 16) +
+		((unsigned int)get_byte() << 24);
+
+	/* skip rest of the header (upper half of uncompressed size) */
+	for (i = 0; i < 4; i++) 
+		get_byte();
+
+	/* decompress kernel */
+	if ((i = LzmaDecode(&vs, &callback,
+	(unsigned char*)KERNEL_ENTRY, osize, &osize)) == LZMA_RESULT_OK)
+	{
+		blast_dcache(dcache_size, dcache_lsize);
+		blast_icache(icache_size, icache_lsize);
+
+		/* Jump to load address */
+		((void (*)(int a0, int a1, int a2, int a3)) KERNEL_ENTRY)(arg0, arg1, arg2, arg3);
+	}
+}
diff --git a/target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in b/target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in
new file mode 100644
index 0000000000..fbc87ab8e2
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/lzma-copy.lds.in
@@ -0,0 +1,20 @@
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = @LOADADDR@;
+  .text      :
+  {
+    _ftext = . ;
+    *(.text)
+    *(.rodata)
+  } =0
+
+  .reginfo : { *(.reginfo) }
+
+  .bss       :
+  {
+   *(.bss)
+  }
+}
diff --git a/target/linux/generic/image/lzma-loader/src/lzma.lds.in b/target/linux/generic/image/lzma-loader/src/lzma.lds.in
new file mode 100644
index 0000000000..6021cec014
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/lzma.lds.in
@@ -0,0 +1,24 @@
+OUTPUT_ARCH(mips)
+ENTRY(@ENTRY@)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = @LOADADDR@;
+  .text      :
+  {
+    _ftext = . ;
+    *(.text.entry)
+    *(.text)
+    *(.rodata)
+    lzma_start = .;
+    kernel.o
+    lzma_end = .;
+  } =0
+
+  .reginfo : { *(.reginfo) }
+
+  .bss       :
+  {
+   *(.bss)
+  }
+}
diff --git a/target/linux/generic/image/lzma-loader/src/print.c b/target/linux/generic/image/lzma-loader/src/print.c
new file mode 100644
index 0000000000..950687beff
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/print.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include	"print.h"
+
+/* macros */
+#define		IsDigit(x)	( ((x) >= '0') && ((x) <= '9') )
+#define		Ctod(x)		( (x) - '0')
+
+/* forward declaration */
+extern int PrintChar(char *, char, int, int);
+extern int PrintString(char *, char *, int, int);
+extern int PrintNum(char *, unsigned long, int, int, int, int, char, int);
+
+/* private variable */
+static const char theFatalMsg[] = "fatal error in lp_Print!";
+
+/* -*-
+ * A low level printf() function.
+ */
+void
+lp_Print(void (*output)(void *, char *, int), 
+	 void * arg,
+	 char *fmt, 
+	 va_list ap)
+{
+
+#define 	OUTPUT(arg, s, l)  \
+  { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
+       (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
+    } else { \
+      (*output)(arg, s, l); \
+    } \
+  }
+    
+    char buf[LP_MAX_BUF];
+
+    char c;
+    char *s;
+    long int num;
+
+    int longFlag;
+    int negFlag;
+    int width;
+    int prec;
+    int ladjust;
+    char padc;
+
+    int length;
+
+    for(;;) {
+	{ 
+	    /* scan for the next '%' */
+	    char *fmtStart = fmt;
+	    while ( (*fmt != '\0') && (*fmt != '%')) {
+		fmt ++;
+	    }
+
+	    /* flush the string found so far */
+	    OUTPUT(arg, fmtStart, fmt-fmtStart);
+
+	    /* are we hitting the end? */
+	    if (*fmt == '\0') break;
+	}
+
+	/* we found a '%' */
+	fmt ++;
+	
+	/* check for long */
+	if (*fmt == 'l') {
+	    longFlag = 1;
+	    fmt ++;
+	} else {
+	    longFlag = 0;
+	}
+
+	/* check for other prefixes */
+	width = 0;
+	prec = -1;
+	ladjust = 0;
+	padc = ' ';
+
+	if (*fmt == '-') {
+	    ladjust = 1;
+	    fmt ++;
+	}
+
+	if (*fmt == '0') {
+	    padc = '0';
+	    fmt++;
+	}
+
+	if (IsDigit(*fmt)) {
+	    while (IsDigit(*fmt)) {
+		width = 10 * width + Ctod(*fmt++);
+	    }
+	}
+
+	if (*fmt == '.') {
+	    fmt ++;
+	    if (IsDigit(*fmt)) {
+		prec = 0;
+		while (IsDigit(*fmt)) {
+		    prec = prec*10 + Ctod(*fmt++);
+		}
+	    }
+	}
+
+
+	/* check format flag */
+	negFlag = 0;
+	switch (*fmt) {
+	 case 'b':
+	    if (longFlag) { 
+		num = va_arg(ap, long int); 
+	    } else { 
+		num = va_arg(ap, int);
+	    }
+	    length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'd':
+	 case 'D':
+	    if (longFlag) { 
+		num = va_arg(ap, long int);
+	    } else { 
+		num = va_arg(ap, int); 
+	    }
+	    if (num < 0) {
+		num = - num;
+		negFlag = 1;
+	    }
+	    length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'o':
+	 case 'O':
+	    if (longFlag) { 
+		num = va_arg(ap, long int);
+	    } else { 
+		num = va_arg(ap, int); 
+	    }
+	    length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'u':
+	 case 'U':
+	    if (longFlag) { 
+		num = va_arg(ap, long int);
+	    } else { 
+		num = va_arg(ap, int); 
+	    }
+	    length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+	    
+	 case 'x':
+	    if (longFlag) { 
+		num = va_arg(ap, long int);
+	    } else { 
+		num = va_arg(ap, int); 
+	    }
+	    length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'X':
+	    if (longFlag) { 
+		num = va_arg(ap, long int);
+	    } else { 
+		num = va_arg(ap, int); 
+	    }
+	    length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 'c':
+	    c = (char)va_arg(ap, int);
+	    length = PrintChar(buf, c, width, ladjust);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case 's':
+	    s = (char*)va_arg(ap, char *);
+	    length = PrintString(buf, s, width, ladjust);
+	    OUTPUT(arg, buf, length);
+	    break;
+
+	 case '\0':
+	    fmt --;
+	    break;
+
+	 default:
+	    /* output this char as it is */
+	    OUTPUT(arg, fmt, 1);
+	}	/* switch (*fmt) */
+
+	fmt ++;
+    }		/* for(;;) */
+
+    /* special termination call */
+    OUTPUT(arg, "\0", 1);
+}
+
+
+/* --------------- local help functions --------------------- */
+int
+PrintChar(char * buf, char c, int length, int ladjust)
+{
+    int i;
+    
+    if (length < 1) length = 1;
+    if (ladjust) {
+	*buf = c;
+	for (i=1; i< length; i++) buf[i] = ' ';
+    } else {
+	for (i=0; i< length-1; i++) buf[i] = ' ';
+	buf[length - 1] = c;
+    }
+    return length;
+}
+
+int
+PrintString(char * buf, char* s, int length, int ladjust)
+{
+    int i;
+    int len=0;
+    char* s1 = s;
+    while (*s1++) len++;
+    if (length < len) length = len;
+
+    if (ladjust) {
+	for (i=0; i< len; i++) buf[i] = s[i];
+	for (i=len; i< length; i++) buf[i] = ' ';
+    } else {
+	for (i=0; i< length-len; i++) buf[i] = ' ';
+	for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
+    }
+    return length;
+}
+
+int
+PrintNum(char * buf, unsigned long u, int base, int negFlag, 
+	 int length, int ladjust, char padc, int upcase)
+{
+    /* algorithm :
+     *  1. prints the number from left to right in reverse form.
+     *  2. fill the remaining spaces with padc if length is longer than
+     *     the actual length
+     *     TRICKY : if left adjusted, no "0" padding.
+     *		    if negtive, insert  "0" padding between "0" and number.
+     *  3. if (!ladjust) we reverse the whole string including paddings
+     *  4. otherwise we only reverse the actual string representing the num.
+     */
+
+    int actualLength =0;
+    char *p = buf;
+    int i;
+
+    do {
+	int tmp = u %base;
+	if (tmp <= 9) {
+	    *p++ = '0' + tmp;
+	} else if (upcase) {
+	    *p++ = 'A' + tmp - 10;
+	} else {
+	    *p++ = 'a' + tmp - 10;
+	}
+	u /= base;
+    } while (u != 0);
+
+    if (negFlag) {
+	*p++ = '-';
+    }
+
+    /* figure out actual length and adjust the maximum length */
+    actualLength = p - buf;
+    if (length < actualLength) length = actualLength;
+
+    /* add padding */
+    if (ladjust) {
+	padc = ' ';
+    }
+    if (negFlag && !ladjust && (padc == '0')) {
+	for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
+	buf[length -1] = '-';
+    } else {
+	for (i = actualLength; i< length; i++) buf[i] = padc;
+    }
+	    
+
+    /* prepare to reverse the string */
+    {
+	int begin = 0;
+	int end;
+	if (ladjust) {
+	    end = actualLength - 1;
+	} else {
+	    end = length -1;
+	}
+
+	while (end > begin) {
+	    char tmp = buf[begin];
+	    buf[begin] = buf[end];
+	    buf[end] = tmp;
+	    begin ++;
+	    end --;
+	}
+    }
+
+    /* adjust the string pointer */
+    return length;
+}
diff --git a/target/linux/generic/image/lzma-loader/src/print.h b/target/linux/generic/image/lzma-loader/src/print.h
new file mode 100644
index 0000000000..b051463909
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/print.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _print_h_
+#define _print_h_
+
+#include <stdarg.h>
+
+/* this is the maximum width for a variable */
+#define		LP_MAX_BUF	80
+
+/* -*-
+ * output function takes an void pointer which is passed in as the
+ * second argument in lp_Print().  This black-box argument gives output
+ * function a way to track state.
+ *
+ * The second argument in output function is a pointer to char buffer.
+ * The third argument specifies the number of chars to outputed.
+ *
+ * output function cannot assume the buffer is null-terminated after
+ * l number of chars.
+ */
+void lp_Print(void (*output)(void *, char *, int), 
+	      void * arg,
+	      char *fmt, 
+	      va_list ap);
+
+#endif
diff --git a/target/linux/generic/image/lzma-loader/src/printf.c b/target/linux/generic/image/lzma-loader/src/printf.c
new file mode 100644
index 0000000000..49bd50d7c7
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/printf.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include "printf.h"
+#include "print.h"
+#include "uart16550.h"
+
+static void myoutput(void *arg, char *s, int l)
+{
+    int i;
+
+    // special termination call
+    if ((l==1) && (s[0] == '\0')) return;
+    
+    for (i=0; i< l; i++) {
+	Uart16550Put(s[i]);
+	if (s[i] == '\n') Uart16550Put('\r');
+    }
+}
+
+void printf(char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    lp_Print(myoutput, 0, fmt, ap);
+    va_end(ap);
+}
diff --git a/target/linux/generic/image/lzma-loader/src/printf.h b/target/linux/generic/image/lzma-loader/src/printf.h
new file mode 100644
index 0000000000..9b1c1df232
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/printf.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _printf_h_
+#define _printf_h_
+
+#include <stdarg.h>
+void printf(char *fmt, ...);
+
+#endif /* _printf_h_ */
diff --git a/target/linux/generic/image/lzma-loader/src/start.S b/target/linux/generic/image/lzma-loader/src/start.S
new file mode 100644
index 0000000000..f025dabedd
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/start.S
@@ -0,0 +1,160 @@
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#define KSEG0		0x80000000
+
+#define C0_CONFIG	$16
+#define C0_TAGLO	$28
+#define C0_TAGHI	$29
+
+#define	CONF1_DA_SHIFT	7			/* D$ associativity */
+#define CONF1_DA_MASK	0x00000380
+#define CONF1_DA_BASE	1
+#define CONF1_DL_SHIFT	10			/* D$ line size */
+#define CONF1_DL_MASK	0x00001c00
+#define CONF1_DL_BASE	2
+#define CONF1_DS_SHIFT	13			/* D$ sets/way */
+#define CONF1_DS_MASK	0x0000e000
+#define CONF1_DS_BASE	64
+#define CONF1_IA_SHIFT	16			/* I$ associativity */
+#define CONF1_IA_MASK	0x00070000
+#define CONF1_IA_BASE	1
+#define CONF1_IL_SHIFT	19			/* I$ line size */
+#define CONF1_IL_MASK	0x00380000
+#define CONF1_IL_BASE	2
+#define CONF1_IS_SHIFT	22			/* Instruction cache sets/way */
+#define CONF1_IS_MASK	0x01c00000
+#define CONF1_IS_BASE	64
+
+#define Index_Invalidate_I	0x00
+#define Index_Writeback_Inv_D   0x01
+
+LEAF(_start)
+
+	.set	mips32
+	.set noreorder
+
+	/* save argument registers */
+	move t4, a0
+	move t5, a1
+	move t6, a2
+	move t7, a3
+
+	/* set up stack */
+	li	sp, RAMSTART + RAMSIZE - 16
+
+#ifdef IMAGE_COPY
+	/* Copy decompressor code to the right place */
+	li  t2, LOADADDR
+	add a0, t2, 0
+	la  a1, code_start
+	la  a2, code_stop
+$L1:
+	lw  t0, 0(a1)
+	sw  t0, 0(a0)
+	add a1, 4
+	add a0, 4
+	blt a1, a2, $L1
+	nop
+#endif
+
+	/* At this point we need to invalidate dcache and */
+	/* icache before jumping to new code */
+
+1:	/* Get cache sizes */
+	mfc0	s0,C0_CONFIG,1
+
+	li	s1,CONF1_DL_MASK
+	and	s1,s0
+	beq	s1,zero,nodc
+	nop
+
+	srl	s1,CONF1_DL_SHIFT
+	li	t0,CONF1_DL_BASE
+	sll	s1,t0,s1		/* s1 has D$ cache line size */
+
+	li	s2,CONF1_DA_MASK
+	and	s2,s0
+	srl	s2,CONF1_DA_SHIFT
+	addiu	s2,CONF1_DA_BASE	/* s2 now has D$ associativity */
+
+	li	t0,CONF1_DS_MASK
+	and	t0,s0
+	srl	t0,CONF1_DS_SHIFT
+	li	s3,CONF1_DS_BASE
+	sll	s3,s3,t0		/* s3 has D$ sets per way */
+
+	multu	s2,s3			/* sets/way * associativity */
+	mflo	t0			/* total cache lines */
+
+	multu	s1,t0			/* D$ linesize * lines */
+	mflo	s2			/* s2 is now D$ size in bytes */
+
+	/* Initilize the D$: */
+	mtc0	zero,C0_TAGLO
+	mtc0	zero,C0_TAGHI
+
+	li	t0,KSEG0		/* Just an address for the first $ line */
+	addu	t1,t0,s2		/*  + size of cache == end */
+
+1:	cache	Index_Writeback_Inv_D,0(t0)
+	bne	t0,t1,1b
+	addu	t0,s1
+
+nodc:
+	/* Now we get to do it all again for the I$ */
+
+	move	s3,zero			/* just in case there is no icache */
+	move	s4,zero
+
+	li	t0,CONF1_IL_MASK
+	and	t0,s0
+	beq	t0,zero,noic
+	nop
+
+	srl	t0,CONF1_IL_SHIFT
+	li	s3,CONF1_IL_BASE
+	sll	s3,t0			/* s3 has I$ cache line size */
+
+	li	t0,CONF1_IA_MASK
+	and	t0,s0
+	srl	t0,CONF1_IA_SHIFT
+	addiu	s4,t0,CONF1_IA_BASE	/* s4 now has I$ associativity */
+
+	li	t0,CONF1_IS_MASK
+	and	t0,s0
+	srl	t0,CONF1_IS_SHIFT
+	li	s5,CONF1_IS_BASE
+	sll	s5,t0			/* s5 has I$ sets per way */
+
+	multu	s4,s5			/* sets/way * associativity */
+	mflo	t0			/* s4 is now total cache lines */
+
+	multu	s3,t0			/* I$ linesize * lines */
+	mflo	s4			/* s4 is cache size in bytes */
+
+	/* Initilize the I$: */
+	mtc0	zero,C0_TAGLO
+	mtc0	zero,C0_TAGHI
+
+	li	t0,KSEG0		/* Just an address for the first $ line */
+	addu	t1,t0,s4		/*  + size of cache == end */
+
+1:	cache	Index_Invalidate_I,0(t0)
+	bne	t0,t1,1b
+	addu	t0,s3
+noic:
+	/* jump to main */
+	move    a0,s4			/* icache size */
+	move    a1,s3			/* icache line size */
+	move    a2,s2			/* dcache size */
+#ifdef IMAGE_COPY
+	jal		t2
+#else
+	jal     entry
+#endif
+	move    a3,s1			/* dcache line size */
+
+	.set reorder
+END(_start)
+
diff --git a/target/linux/generic/image/lzma-loader/src/uart16550.c b/target/linux/generic/image/lzma-loader/src/uart16550.c
new file mode 100644
index 0000000000..7df5727600
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/uart16550.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+
+#include "uart16550.h"
+
+/* === CONFIG === */
+
+#define         BASE                    0xb8058000
+#define         MAX_BAUD                1152000
+#define         REG_OFFSET              4
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define         OFS_RCV_BUFFER          (0*REG_OFFSET)
+#define         OFS_TRANS_HOLD          (0*REG_OFFSET)
+#define         OFS_SEND_BUFFER         (0*REG_OFFSET)
+#define         OFS_INTR_ENABLE         (1*REG_OFFSET)
+#define         OFS_INTR_ID             (2*REG_OFFSET)
+#define         OFS_DATA_FORMAT         (3*REG_OFFSET)
+#define         OFS_LINE_CONTROL        (3*REG_OFFSET)
+#define         OFS_MODEM_CONTROL       (4*REG_OFFSET)
+#define         OFS_RS232_OUTPUT        (4*REG_OFFSET)
+#define         OFS_LINE_STATUS         (5*REG_OFFSET)
+#define         OFS_MODEM_STATUS        (6*REG_OFFSET)
+#define         OFS_RS232_INPUT         (6*REG_OFFSET)
+#define         OFS_SCRATCH_PAD         (7*REG_OFFSET)
+
+#define         OFS_DIVISOR_LSB         (0*REG_OFFSET)
+#define         OFS_DIVISOR_MSB         (1*REG_OFFSET)
+
+
+/* memory-mapped read/write of the port */
+#define         UART16550_READ(y)    (*((volatile uint32*)(BASE + y)))
+#define         UART16550_WRITE(y, z)  ((*((volatile uint32*)(BASE + y))) = z)
+
+#define DEBUG_LED (*(unsigned short*)0xb7ffffc0)
+#define OutputLED(x)  (DEBUG_LED = x)
+
+void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+    /* disable interrupts */
+    UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+    /* set up buad rate */
+    { 
+        uint32 divisor;
+       
+        /* set DIAB bit */
+        UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+        
+        /* set divisor */
+        divisor = MAX_BAUD / baud;
+        UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+        UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8);
+
+        /* clear DIAB bit */
+        UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+    }
+
+    /* set data format */
+    UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+uint8 Uart16550GetPoll()
+{
+    while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+    return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+void Uart16550Put(uint8 byte)
+{
+    while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0);
+    UART16550_WRITE(OFS_SEND_BUFFER, byte);
+}
+
diff --git a/target/linux/generic/image/lzma-loader/src/uart16550.h b/target/linux/generic/image/lzma-loader/src/uart16550.h
new file mode 100644
index 0000000000..b3fd6fdd75
--- /dev/null
+++ b/target/linux/generic/image/lzma-loader/src/uart16550.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _uart16550_h_
+#define _uart16550_h_
+
+typedef         unsigned char uint8;
+typedef         unsigned int  uint32;
+
+#define         UART16550_BAUD_2400             2400
+#define         UART16550_BAUD_4800             4800
+#define         UART16550_BAUD_9600             9600
+#define         UART16550_BAUD_19200            19200
+#define         UART16550_BAUD_38400            38400
+#define         UART16550_BAUD_57600            57600
+#define         UART16550_BAUD_115200           115200
+
+#define         UART16550_PARITY_NONE           0
+#define         UART16550_PARITY_ODD            0x08
+#define         UART16550_PARITY_EVEN           0x18
+#define         UART16550_PARITY_MARK           0x28
+#define         UART16550_PARITY_SPACE          0x38
+
+#define         UART16550_DATA_5BIT             0x0
+#define         UART16550_DATA_6BIT             0x1
+#define         UART16550_DATA_7BIT             0x2
+#define         UART16550_DATA_8BIT             0x3
+
+#define         UART16550_STOP_1BIT             0x0
+#define         UART16550_STOP_2BIT             0x4
+
+void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop);
+
+/* blocking call */
+uint8 Uart16550GetPoll();
+
+void Uart16550Put(uint8 byte);
+
+#endif
diff --git a/target/linux/generic/image/relocate/Makefile b/target/linux/generic/image/relocate/Makefile
new file mode 100644
index 0000000000..62e3b32ee2
--- /dev/null
+++ b/target/linux/generic/image/relocate/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile for the kernel relocation stub for MIPS devices
+#
+# Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+# Copyright (C) 2015 Felix Fietkau <nbd@nbd.name>
+#
+# Some parts of this file was based on the OpenWrt specific lzma-loader
+# for the BCM47xx and ADM5120 based boards:
+#	Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
+#	Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
+#	Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+#
+# 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.
+#
+
+LOADADDR	:=
+LZMA_TEXT_START	:= 0x81000000
+LOADER_DATA	:=
+BOARD		:=
+FLASH_OFFS	:=
+FLASH_MAX	:=
+PLATFORM	:=
+CACHELINE_SIZE	:= 32
+
+CC		:= $(CROSS_COMPILE)gcc
+LD		:= $(CROSS_COMPILE)ld
+OBJCOPY		:= $(CROSS_COMPILE)objcopy
+OBJDUMP		:= $(CROSS_COMPILE)objdump
+
+BIN_FLAGS	:= -O binary -R .reginfo -R .note -R .comment -R .mdebug \
+		   -R .MIPS.abiflags -S
+
+CFLAGS		= -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
+		  -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \
+		  -mno-abicalls -fno-pic -ffunction-sections -pipe -mlong-calls \
+		  -fno-common -ffreestanding -fhonour-copts \
+		  -mabi=32 -march=mips32r2 \
+		  -Wa,-32 -Wa,-march=mips32r2 -Wa,-mips32r2 -Wa,--trap \
+		  -DCONFIG_CACHELINE_SIZE=$(CACHELINE_SIZE) \
+		  -DKERNEL_ADDR=$(KERNEL_ADDR)
+
+ASFLAGS		= $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS		= -static --gc-sections -no-warn-mismatch
+LDFLAGS		+= -e startup -T loader.lds -Ttext $(LZMA_TEXT_START)
+
+O_FORMAT 	= $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+
+OBJECTS		:= head.o
+
+all: head.o loader.bin
+
+# Don't build dependencies, this may die if $(CC) isn't gcc
+dep:
+
+install:
+
+%.o : %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.o : %.S
+	$(CC) $(ASFLAGS) -c -o $@ $<
+
+loader: $(OBJECTS)
+	$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
+
+loader.bin: loader
+	$(OBJCOPY) $(BIN_FLAGS) $< $@
+
+mrproper: clean
+
+clean:
+	rm -f loader *.elf *.bin *.o
diff --git a/target/linux/generic/image/relocate/cacheops.h b/target/linux/generic/image/relocate/cacheops.h
new file mode 100644
index 0000000000..70bcad7694
--- /dev/null
+++ b/target/linux/generic/image/relocate/cacheops.h
@@ -0,0 +1,85 @@
+/*
+ * Cache operations for the cache instruction.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) Copyright 1996, 97, 99, 2002, 03 Ralf Baechle
+ * (C) Copyright 1999 Silicon Graphics, Inc.
+ */
+#ifndef	__ASM_CACHEOPS_H
+#define	__ASM_CACHEOPS_H
+
+/*
+ * Cache Operations available on all MIPS processors with R4000-style caches
+ */
+#define Index_Invalidate_I      0x00
+#define Index_Writeback_Inv_D   0x01
+#define Index_Load_Tag_I	0x04
+#define Index_Load_Tag_D	0x05
+#define Index_Store_Tag_I	0x08
+#define Index_Store_Tag_D	0x09
+#if defined(CONFIG_CPU_LOONGSON2)
+#define Hit_Invalidate_I	0x00
+#else
+#define Hit_Invalidate_I	0x10
+#endif
+#define Hit_Invalidate_D	0x11
+#define Hit_Writeback_Inv_D	0x15
+
+/*
+ * R4000-specific cacheops
+ */
+#define Create_Dirty_Excl_D	0x0d
+#define Fill			0x14
+#define Hit_Writeback_I		0x18
+#define Hit_Writeback_D		0x19
+
+/*
+ * R4000SC and R4400SC-specific cacheops
+ */
+#define Index_Invalidate_SI     0x02
+#define Index_Writeback_Inv_SD  0x03
+#define Index_Load_Tag_SI	0x06
+#define Index_Load_Tag_SD	0x07
+#define Index_Store_Tag_SI	0x0A
+#define Index_Store_Tag_SD	0x0B
+#define Create_Dirty_Excl_SD	0x0f
+#define Hit_Invalidate_SI	0x12
+#define Hit_Invalidate_SD	0x13
+#define Hit_Writeback_Inv_SD	0x17
+#define Hit_Writeback_SD	0x1b
+#define Hit_Set_Virtual_SI	0x1e
+#define Hit_Set_Virtual_SD	0x1f
+
+/*
+ * R5000-specific cacheops
+ */
+#define R5K_Page_Invalidate_S	0x17
+
+/*
+ * RM7000-specific cacheops
+ */
+#define Page_Invalidate_T	0x16
+
+/*
+ * R10000-specific cacheops
+ *
+ * Cacheops 0x02, 0x06, 0x0a, 0x0c-0x0e, 0x16, 0x1a and 0x1e are unused.
+ * Most of the _S cacheops are identical to the R4000SC _SD cacheops.
+ */
+#define Index_Writeback_Inv_S	0x03
+#define Index_Load_Tag_S	0x07
+#define Index_Store_Tag_S	0x0B
+#define Hit_Invalidate_S	0x13
+#define Cache_Barrier		0x14
+#define Hit_Writeback_Inv_S	0x17
+#define Index_Load_Data_I	0x18
+#define Index_Load_Data_D	0x19
+#define Index_Load_Data_S	0x1b
+#define Index_Store_Data_I	0x1c
+#define Index_Store_Data_D	0x1d
+#define Index_Store_Data_S	0x1f
+
+#endif	/* __ASM_CACHEOPS_H */
diff --git a/target/linux/generic/image/relocate/cp0regdef.h b/target/linux/generic/image/relocate/cp0regdef.h
new file mode 100644
index 0000000000..c1188ad8c8
--- /dev/null
+++ b/target/linux/generic/image/relocate/cp0regdef.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
+ *
+ * Copyright (C) 2001, Monta Vista Software
+ * Author: jsun@mvista.com or jsun@junsun.net
+ */
+#ifndef _cp0regdef_h_
+#define _cp0regdef_h_
+
+#define CP0_INDEX $0
+#define CP0_RANDOM $1
+#define CP0_ENTRYLO0 $2
+#define CP0_ENTRYLO1 $3
+#define CP0_CONTEXT $4
+#define CP0_PAGEMASK $5
+#define CP0_WIRED $6
+#define CP0_BADVADDR $8
+#define CP0_COUNT $9
+#define CP0_ENTRYHI $10
+#define CP0_COMPARE $11
+#define CP0_STATUS $12
+#define CP0_CAUSE $13
+#define CP0_EPC $14
+#define CP0_PRID $15
+#define CP0_CONFIG $16
+#define CP0_LLADDR $17
+#define CP0_WATCHLO $18
+#define CP0_WATCHHI $19
+#define CP0_XCONTEXT $20
+#define CP0_FRAMEMASK $21
+#define CP0_DIAGNOSTIC $22
+#define CP0_PERFORMANCE $25
+#define CP0_ECC $26
+#define CP0_CACHEERR $27
+#define CP0_TAGLO $28
+#define CP0_TAGHI $29
+#define CP0_ERROREPC $30
+
+#endif
diff --git a/target/linux/generic/image/relocate/head.S b/target/linux/generic/image/relocate/head.S
new file mode 100644
index 0000000000..58c336d41c
--- /dev/null
+++ b/target/linux/generic/image/relocate/head.S
@@ -0,0 +1,159 @@
+/*
+ * Kernel relocation stub for MIPS devices
+ *
+ * Copyright (C) 2015 Felix Fietkau <nbd@nbd.name>
+ *
+ * Based on:
+ *
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the BCM47xx and ADM5120 based boards:
+ *	Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
+ *	Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * 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 <asm/asm.h>
+#include <asm/regdef.h>
+#include "cp0regdef.h"
+#include "cacheops.h"
+
+#define KSEG0		0x80000000
+
+	.macro	ehb
+	sll     zero, 3
+	.endm
+
+	.macro reset
+	li t0, 0xbe000034
+	lw t1, 0(t0)
+	ori t1, 1
+	sw t1, 0(t0)
+	.endm
+
+	.text
+
+LEAF(startup)
+	.set noreorder
+	.set mips32
+
+	.fill 0x10000
+
+	mtc0	zero, CP0_WATCHLO	# clear watch registers
+	mtc0	zero, CP0_WATCHHI
+	mtc0	zero, CP0_CAUSE		# clear before writing status register
+
+	mfc0	t0, CP0_STATUS
+	li	t1, 0x1000001f
+	or	t0, t1
+	xori	t0, 0x1f
+	mtc0	t0, CP0_STATUS
+	ehb
+
+	mtc0	zero, CP0_COUNT
+	mtc0	zero, CP0_COMPARE
+	ehb
+
+	la	t0, __reloc_label	# get linked address of label
+	bal	__reloc_label		# branch and link to label to
+	nop				# get actual address
+__reloc_label:
+	subu	t0, ra, t0		# get reloc_delta
+
+	/* Copy our code to the right place */
+	la	t1, _code_start		# get linked address of _code_start
+	la	t2, _code_end		# get linked address of _code_end
+
+	addu	t4, t2, t0		# calculate actual address of _code_end
+	lw	t5, 0(t4)		# get extra data size
+
+	add	t2, t5
+	add	t2, 4
+
+	add	t0, t1			# calculate actual address of _code_start
+
+__reloc_copy:
+	lw	t3, 0(t0)
+	sw	t3, 0(t1)
+	add	t1, 4
+	blt	t1, t2, __reloc_copy
+	add	t0, 4
+
+	/* flush cache */
+	la	t0, _code_start
+	la	t1, _code_end
+
+	li	t2, ~(CONFIG_CACHELINE_SIZE - 1)
+	and	t0, t2
+	and	t1, t2
+	li	t2, CONFIG_CACHELINE_SIZE
+
+	b	__flush_check
+	nop
+
+__flush_line:
+	cache	Hit_Writeback_Inv_D, 0(t0)
+	cache	Hit_Invalidate_I, 0(t0)
+	add	t0, t2
+
+__flush_check:
+	bne	t0, t1, __flush_line
+	nop
+
+	sync
+
+	la	t0, __reloc_back
+	j	t0
+	nop
+
+__reloc_back:
+	la	t0, _code_end
+	add	t0, 4
+
+	addu	t1, t0, t5
+
+	li	t2, KERNEL_ADDR
+
+__kernel_copy:
+	lw	t3, 0(t0)
+	sw	t3, 0(t2)
+	add	t0, 4
+	blt	t0, t1, __kernel_copy
+	add	t2, 4
+
+	/* flush cache */
+	li	t0, KERNEL_ADDR
+	addu	t1, t0, t5
+
+	add t1, CONFIG_CACHELINE_SIZE - 1
+	li	t2, ~(CONFIG_CACHELINE_SIZE - 1)
+	and	t0, t2
+	and	t1, t2
+	li	t2, CONFIG_CACHELINE_SIZE
+
+	b	__kernel_flush_check
+	nop
+
+__kernel_flush_line:
+	cache	Hit_Writeback_Inv_D, 0(t0)
+	cache	Hit_Invalidate_I, 0(t0)
+	add	t0, t2
+
+__kernel_flush_check:
+	bne	t0, t1, __kernel_flush_line
+	nop
+
+	sync
+
+	li	t0, KERNEL_ADDR
+	jr	t0
+	nop
+
+	.set reorder
+END(startup)
diff --git a/target/linux/generic/image/relocate/loader.lds b/target/linux/generic/image/relocate/loader.lds
new file mode 100644
index 0000000000..98ca209303
--- /dev/null
+++ b/target/linux/generic/image/relocate/loader.lds
@@ -0,0 +1,16 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+	.text : {
+		_code_start = .;
+		*(.text)
+		*(.text.*)
+		*(.rodata)
+		*(.rodata.*)
+		*(.data)
+		*(.data.*)
+	}
+
+	. = ALIGN(32);
+
+	_code_end = .;
+}
diff --git a/target/linux/generic/patches-3.18/020-ssb_update.patch b/target/linux/generic/patches-3.18/020-ssb_update.patch
new file mode 100644
index 0000000000..f94d160fc6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/020-ssb_update.patch
@@ -0,0 +1,134 @@
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -11,15 +11,17 @@
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ 
++#include <linux/pm.h>
+ #include <linux/pci.h>
+ #include <linux/export.h>
+ #include <linux/slab.h>
+ #include <linux/ssb/ssb.h>
+ 
+ 
+-#ifdef CONFIG_PM
+-static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
++#ifdef CONFIG_PM_SLEEP
++static int ssb_pcihost_suspend(struct device *d)
+ {
++	struct pci_dev *dev = to_pci_dev(d);
+ 	struct ssb_bus *ssb = pci_get_drvdata(dev);
+ 	int err;
+ 
+@@ -28,17 +30,23 @@ static int ssb_pcihost_suspend(struct pc
+ 		return err;
+ 	pci_save_state(dev);
+ 	pci_disable_device(dev);
+-	pci_set_power_state(dev, pci_choose_state(dev, state));
++
++	/* if there is a wakeup enabled child device on ssb bus,
++	   enable pci wakeup posibility. */
++	device_set_wakeup_enable(d, d->power.wakeup_path);
++
++	pci_prepare_to_sleep(dev);
+ 
+ 	return 0;
+ }
+ 
+-static int ssb_pcihost_resume(struct pci_dev *dev)
++static int ssb_pcihost_resume(struct device *d)
+ {
++	struct pci_dev *dev = to_pci_dev(d);
+ 	struct ssb_bus *ssb = pci_get_drvdata(dev);
+ 	int err;
+ 
+-	pci_set_power_state(dev, PCI_D0);
++	pci_back_from_sleep(dev);
+ 	err = pci_enable_device(dev);
+ 	if (err)
+ 		return err;
+@@ -49,10 +57,12 @@ static int ssb_pcihost_resume(struct pci
+ 
+ 	return 0;
+ }
+-#else /* CONFIG_PM */
+-# define ssb_pcihost_suspend	NULL
+-# define ssb_pcihost_resume	NULL
+-#endif /* CONFIG_PM */
++
++static const struct dev_pm_ops ssb_pcihost_pm_ops = {
++	SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume)
++};
++
++#endif /* CONFIG_PM_SLEEP */
+ 
+ static int ssb_pcihost_probe(struct pci_dev *dev,
+ 			     const struct pci_device_id *id)
+@@ -115,8 +125,9 @@ int ssb_pcihost_register(struct pci_driv
+ {
+ 	driver->probe = ssb_pcihost_probe;
+ 	driver->remove = ssb_pcihost_remove;
+-	driver->suspend = ssb_pcihost_suspend;
+-	driver->resume = ssb_pcihost_resume;
++#ifdef CONFIG_PM_SLEEP
++	driver->driver.pm = &ssb_pcihost_pm_ops;
++#endif
+ 
+ 	return pci_register_driver(driver);
+ }
+--- a/drivers/ssb/driver_pcicore.c
++++ b/drivers/ssb/driver_pcicore.c
+@@ -357,6 +357,16 @@ static void ssb_pcicore_init_hostmode(st
+ 	pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
+ 			SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
+ 
++	/*
++	 * Accessing PCI config without a proper delay after devices reset (not
++	 * GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704).
++	 * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it
++	 * completely. Flushing all writes was also tested but with no luck.
++	 * The same problem was reported for WRT350N v1 (BCM4705), so we just
++	 * sleep here unconditionally.
++	 */
++	usleep_range(1000, 2000);
++
+ 	/* Enable PCI bridge BAR0 prefetch and burst */
+ 	val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ 	ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -90,25 +90,6 @@ found:
+ }
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+ 
+-#ifdef CONFIG_SSB_SDIOHOST
+-struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func)
+-{
+-	struct ssb_bus *bus;
+-
+-	ssb_buses_lock();
+-	list_for_each_entry(bus, &buses, list) {
+-		if (bus->bustype == SSB_BUSTYPE_SDIO &&
+-		    bus->host_sdio == func)
+-			goto found;
+-	}
+-	bus = NULL;
+-found:
+-	ssb_buses_unlock();
+-
+-	return bus;
+-}
+-#endif /* CONFIG_SSB_SDIOHOST */
+-
+ int ssb_for_each_bus_call(unsigned long data,
+ 			  int (*func)(struct ssb_bus *bus, unsigned long data))
+ {
+@@ -1154,6 +1135,8 @@ static u32 ssb_tmslow_reject_bitmask(str
+ 	case SSB_IDLOW_SSBREV_25:     /* TODO - find the proper REJECT bit */
+ 	case SSB_IDLOW_SSBREV_27:     /* same here */
+ 		return SSB_TMSLOW_REJECT;	/* this is a guess */
++	case SSB_IDLOW_SSBREV:
++		break;
+ 	default:
+ 		WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
+ 	}
diff --git a/target/linux/generic/patches-3.18/021-ssb_sprom.patch b/target/linux/generic/patches-3.18/021-ssb_sprom.patch
new file mode 100644
index 0000000000..52d8080dfe
--- /dev/null
+++ b/target/linux/generic/patches-3.18/021-ssb_sprom.patch
@@ -0,0 +1,32 @@
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -29,10 +29,13 @@ struct ssb_sprom {
+ 	u8 il0mac[6] __aligned(sizeof(u16));	/* MAC address for 802.11b/g */
+ 	u8 et0mac[6] __aligned(sizeof(u16));	/* MAC address for Ethernet */
+ 	u8 et1mac[6] __aligned(sizeof(u16));	/* MAC address for 802.11a */
++	u8 et2mac[6] __aligned(sizeof(u16));	/* MAC address for extra Ethernet */
+ 	u8 et0phyaddr;		/* MII address for enet0 */
+ 	u8 et1phyaddr;		/* MII address for enet1 */
++	u8 et2phyaddr;		/* MII address for enet2 */
+ 	u8 et0mdcport;		/* MDIO for enet0 */
+ 	u8 et1mdcport;		/* MDIO for enet1 */
++	u8 et2mdcport;		/* MDIO for enet2 */
+ 	u16 dev_id;		/* Device ID overriding e.g. PCI ID */
+ 	u16 board_rev;		/* Board revision number from SPROM. */
+ 	u16 board_num;		/* Board number from SPROM. */
+@@ -88,11 +91,14 @@ struct ssb_sprom {
+ 	u32 ofdm5glpo;		/* 5.2GHz OFDM power offset */
+ 	u32 ofdm5gpo;		/* 5.3GHz OFDM power offset */
+ 	u32 ofdm5ghpo;		/* 5.8GHz OFDM power offset */
++	u32 boardflags;
++	u32 boardflags2;
++	u32 boardflags3;
++	/* TODO: Switch all drivers to new u32 fields and drop below ones */
+ 	u16 boardflags_lo;	/* Board flags (bits 0-15) */
+ 	u16 boardflags_hi;	/* Board flags (bits 16-31) */
+ 	u16 boardflags2_lo;	/* Board flags (bits 32-47) */
+ 	u16 boardflags2_hi;	/* Board flags (bits 48-63) */
+-	/* TODO store board flags in a single u64 */
+ 
+ 	struct ssb_sprom_core_pwr_info core_pwr_info[4];
+ 
diff --git a/target/linux/generic/patches-3.18/025-bcma_backport.patch b/target/linux/generic/patches-3.18/025-bcma_backport.patch
new file mode 100644
index 0000000000..ec1cb004b7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/025-bcma_backport.patch
@@ -0,0 +1,286 @@
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -22,6 +22,7 @@ struct bcma_bus;
+ /* main.c */
+ bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
+ 		     int timeout);
++void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
+ int bcma_bus_register(struct bcma_bus *bus);
+ void bcma_bus_unregister(struct bcma_bus *bus);
+ int __init bcma_bus_early_register(struct bcma_bus *bus,
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -339,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma
+ 		return;
+ 	}
+ 
+-	irq = bcma_core_irq(cc->core);
++	irq = bcma_core_irq(cc->core, 0);
+ 
+ 	/* Determine the registers of the UARTs */
+ 	cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -152,7 +152,7 @@ static int bcma_gpio_irq_domain_init(str
+ 					 handle_simple_irq);
+ 	}
+ 
+-	hwirq = bcma_core_irq(cc->core);
++	hwirq = bcma_core_irq(cc->core, 0);
+ 	err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio",
+ 			  cc);
+ 	if (err)
+@@ -183,7 +183,7 @@ static void bcma_gpio_irq_domain_exit(st
+ 		return;
+ 
+ 	bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO);
+-	free_irq(bcma_core_irq(cc->core), cc);
++	free_irq(bcma_core_irq(cc->core, 0), cc);
+ 	for (gpio = 0; gpio < chip->ngpio; gpio++) {
+ 		int irq = irq_find_mapping(cc->irq_domain, gpio);
+ 
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -115,7 +115,7 @@ static u32 bcma_core_mips_irqflag(struct
+  * If disabled, 5 is returned.
+  * If not supported, 6 is returned.
+  */
+-static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+ {
+ 	struct bcma_device *mdev = dev->bus->drv_mips.core;
+ 	u32 irqflag;
+@@ -133,13 +133,6 @@ static unsigned int bcma_core_mips_irq(s
+ 	return 5;
+ }
+ 
+-unsigned int bcma_core_irq(struct bcma_device *dev)
+-{
+-	unsigned int mips_irq = bcma_core_mips_irq(dev);
+-	return mips_irq <= 4 ? mips_irq + 2 : 0;
+-}
+-EXPORT_SYMBOL(bcma_core_irq);
+-
+ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+ {
+ 	unsigned int oldirq = bcma_core_mips_irq(dev);
+@@ -423,7 +416,7 @@ void bcma_core_mips_init(struct bcma_drv
+ 		break;
+ 	default:
+ 		list_for_each_entry(core, &bus->cores, list) {
+-			core->irq = bcma_core_irq(core);
++			core->irq = bcma_core_irq(core, 0);
+ 		}
+ 		bcma_err(bus,
+ 			 "Unknown device (0x%x) found, can not configure IRQs\n",
+--- a/drivers/bcma/driver_pci_host.c
++++ b/drivers/bcma/driver_pci_host.c
+@@ -593,7 +593,7 @@ int bcma_core_pci_plat_dev_init(struct p
+ 	pr_info("PCI: Fixing up device %s\n", pci_name(dev));
+ 
+ 	/* Fix up interrupt lines */
+-	dev->irq = bcma_core_irq(pc_host->pdev->core);
++	dev->irq = bcma_core_irq(pc_host->pdev->core, 0);
+ 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ 
+ 	readrq = pcie_get_readrq(dev);
+@@ -617,6 +617,6 @@ int bcma_core_pci_pcibios_map_irq(const
+ 
+ 	pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
+ 			       pci_ops);
+-	return bcma_core_irq(pc_host->pdev->core);
++	return bcma_core_irq(pc_host->pdev->core, 0);
+ }
+ EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -11,6 +11,7 @@
+ #include <linux/bcma/bcma.h>
+ #include <linux/slab.h>
+ #include <linux/of_address.h>
++#include <linux/of_irq.h>
+ 
+ MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
+ MODULE_LICENSE("GPL");
+@@ -153,6 +154,46 @@ static struct device_node *bcma_of_find_
+ 	return NULL;
+ }
+ 
++static int bcma_of_irq_parse(struct platform_device *parent,
++			     struct bcma_device *core,
++			     struct of_phandle_args *out_irq, int num)
++{
++	__be32 laddr[1];
++	int rc;
++
++	if (core->dev.of_node) {
++		rc = of_irq_parse_one(core->dev.of_node, num, out_irq);
++		if (!rc)
++			return rc;
++	}
++
++	out_irq->np = parent->dev.of_node;
++	out_irq->args_count = 1;
++	out_irq->args[0] = num;
++
++	laddr[0] = cpu_to_be32(core->addr);
++	return of_irq_parse_raw(laddr, out_irq);
++}
++
++static unsigned int bcma_of_get_irq(struct platform_device *parent,
++				    struct bcma_device *core, int num)
++{
++	struct of_phandle_args out_irq;
++	int ret;
++
++	if (!parent || !parent->dev.of_node)
++		return 0;
++
++	ret = bcma_of_irq_parse(parent, core, &out_irq, num);
++	if (ret) {
++		bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n",
++			   ret);
++		return 0;
++	}
++
++	return irq_create_of_mapping(&out_irq);
++}
++
+ static void bcma_of_fill_device(struct platform_device *parent,
+ 				struct bcma_device *core)
+ {
+@@ -161,18 +202,47 @@ static void bcma_of_fill_device(struct p
+ 	node = bcma_of_find_child_device(parent, core);
+ 	if (node)
+ 		core->dev.of_node = node;
++
++	core->irq = bcma_of_get_irq(parent, core, 0);
+ }
+ #else
+ static void bcma_of_fill_device(struct platform_device *parent,
+ 				struct bcma_device *core)
+ {
+ }
++static inline unsigned int bcma_of_get_irq(struct platform_device *parent,
++					   struct bcma_device *core, int num)
++{
++	return 0;
++}
+ #endif /* CONFIG_OF */
+ 
+-static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
++unsigned int bcma_core_irq(struct bcma_device *core, int num)
+ {
+-	int err;
++	struct bcma_bus *bus = core->bus;
++	unsigned int mips_irq;
++
++	switch (bus->hosttype) {
++	case BCMA_HOSTTYPE_PCI:
++		return bus->host_pci->irq;
++	case BCMA_HOSTTYPE_SOC:
++		if (bus->drv_mips.core && num == 0) {
++			mips_irq = bcma_core_mips_irq(core);
++			return mips_irq <= 4 ? mips_irq + 2 : 0;
++		}
++		if (bus->host_pdev)
++			return bcma_of_get_irq(bus->host_pdev, core, num);
++		return 0;
++	case BCMA_HOSTTYPE_SDIO:
++		return 0;
++	}
+ 
++	return 0;
++}
++EXPORT_SYMBOL(bcma_core_irq);
++
++void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
++{
+ 	core->dev.release = bcma_release_core_dev;
+ 	core->dev.bus = &bcma_bus_type;
+ 	dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
+@@ -196,6 +266,11 @@ static void bcma_register_core(struct bc
+ 	case BCMA_HOSTTYPE_SDIO:
+ 		break;
+ 	}
++}
++
++static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
++{
++	int err;
+ 
+ 	err = device_register(&core->dev);
+ 	if (err) {
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -505,6 +505,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
+ 		bus->nr_cores++;
+ 		other_core = bcma_find_core_reverse(bus, core->id.id);
+ 		core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
++		bcma_prepare_core(bus, core);
+ 
+ 		bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+ 			  core->core_index, bcma_device_name(&core->id),
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -448,4 +448,6 @@ extern u32 bcma_chipco_pll_read(struct b
+ #define  BCMA_DMA_TRANSLATION_DMA64_CMT	0x80000000 /* Client Mode Translation for 64-bit DMA */
+ extern u32 bcma_core_dma_translation(struct bcma_device *core);
+ 
++extern unsigned int bcma_core_irq(struct bcma_device *core, int num);
++
+ #endif /* LINUX_BCMA_H_ */
+--- a/include/linux/bcma/bcma_driver_mips.h
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -43,12 +43,12 @@ struct bcma_drv_mips {
+ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+ extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
+ 
+-extern unsigned int bcma_core_irq(struct bcma_device *core);
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+ #else
+ static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+ static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
+ 
+-static inline unsigned int bcma_core_irq(struct bcma_device *core)
++static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+ {
+ 	return 0;
+ }
+--- a/Documentation/devicetree/bindings/bus/bcma.txt
++++ b/Documentation/devicetree/bindings/bus/bcma.txt
+@@ -8,6 +8,11 @@ Required properties:
+ 
+ The cores on the AXI bus are automatically detected by bcma with the
+ memory ranges they are using and they get registered afterwards.
++Automatic detection of the IRQ number is not working on
++BCM47xx/BCM53xx ARM SoCs. To assign IRQ numbers to the cores, provide
++them manually through device tree. Use an interrupt-map to specify the
++IRQ used by the devices on the bus. The first address is just an index,
++because we do not have any special register.
+ 
+ The top-level axi bus may contain children representing attached cores
+ (devices). This is needed since some hardware details can't be auto
+@@ -22,6 +27,22 @@ Example:
+ 		ranges = <0x00000000 0x18000000 0x00100000>;
+ 		#address-cells = <1>;
+ 		#size-cells = <1>;
++		#interrupt-cells = <1>;
++		interrupt-map-mask = <0x000fffff 0xffff>;
++		interrupt-map =
++			/* Ethernet Controller 0 */
++			<0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
++
++			/* Ethernet Controller 1 */
++			<0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
++
++			/* PCIe Controller 0 */
++			<0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
++			<0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
++			<0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
++			<0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
++			<0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
++			<0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+ 
+ 		chipcommon {
+ 			reg = <0x00000000 0x1000>;
diff --git a/target/linux/generic/patches-3.18/026-bcma-from-3.20.patch b/target/linux/generic/patches-3.18/026-bcma-from-3.20.patch
new file mode 100644
index 0000000000..628b0bd389
--- /dev/null
+++ b/target/linux/generic/patches-3.18/026-bcma-from-3.20.patch
@@ -0,0 +1,527 @@
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -23,22 +23,18 @@ struct bcma_bus;
+ bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
+ 		     int timeout);
+ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
+ int bcma_bus_register(struct bcma_bus *bus);
+ void bcma_bus_unregister(struct bcma_bus *bus);
+-int __init bcma_bus_early_register(struct bcma_bus *bus,
+-				   struct bcma_device *core_cc,
+-				   struct bcma_device *core_mips);
++int __init bcma_bus_early_register(struct bcma_bus *bus);
+ #ifdef CONFIG_PM
+ int bcma_bus_suspend(struct bcma_bus *bus);
+ int bcma_bus_resume(struct bcma_bus *bus);
+ #endif
+ 
+ /* scan.c */
++void bcma_detect_chip(struct bcma_bus *bus);
+ int bcma_bus_scan(struct bcma_bus *bus);
+-int __init bcma_bus_scan_early(struct bcma_bus *bus,
+-			       struct bcma_device_id *match,
+-			       struct bcma_device *core);
+-void bcma_init_bus(struct bcma_bus *bus);
+ 
+ /* sprom.c */
+ int bcma_sprom_get(struct bcma_bus *bus);
+@@ -109,6 +105,14 @@ extern int bcma_chipco_watchdog_register
+ #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+ bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
+ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
++#else
++static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
++{
++	return false;
++}
++static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
++{
++}
+ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+ 
+ #ifdef CONFIG_BCMA_DRIVER_GPIO
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_pe
+ 
+ 	if (cc->capabilities & BCMA_CC_CAP_PMU) {
+ 		if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
+-			/* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
++			/* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP
++			 * clock
++			 */
+ 			return bcma_chipco_get_alp_clock(cc) / 4000;
+ 		else
+ 			/* based on 32KHz ILP clock */
+@@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct
+ 	wdt.driver_data = cc;
+ 	wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
+ 	wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
+-	wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
++	wdt.max_timer_ms =
++		bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+ 
+ 	pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
+ 					     cc->core->bus->num, &wdt,
+@@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bc
+ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
+ {
+ 	u32 maxt;
+-	enum bcma_clkmode clkmode;
+ 
+ 	maxt = bcma_chipco_watchdog_get_max_timer(cc);
+ 	if (cc->capabilities & BCMA_CC_CAP_PMU) {
+@@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struc
+ 			ticks = maxt;
+ 		bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+ 	} else {
+-		clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
+-		bcma_core_set_clockmode(cc->core, clkmode);
++		struct bcma_bus *bus = cc->core->bus;
++
++		if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
++		    bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
++			bcma_core_set_clockmode(cc->core,
++						ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
++
+ 		if (ticks > maxt)
+ 			ticks = maxt;
+ 		/* instant NMI */
+@@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma
+ 				       | BCMA_CC_CORECTL_UARTCLKEN);
+ 		}
+ 	} else {
+-		bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
++		bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n",
++			 ccrev);
+ 		return;
+ 	}
+ 
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -145,6 +145,47 @@ static u16 bcma_pcie_mdio_writeread(stru
+ }
+ 
+ /**************************************************
++ * Early init.
++ **************************************************/
++
++static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
++{
++	struct bcma_device *core = pc->core;
++	u16 val16, core_index;
++	uint regoff;
++
++	regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
++	core_index = (u16)core->core_index;
++
++	val16 = pcicore_read16(pc, regoff);
++	if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
++	     != core_index) {
++		val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
++			(val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
++		pcicore_write16(pc, regoff, val16);
++	}
++}
++
++/*
++ * Apply some early fixes required before accessing SPROM.
++ * See also si_pci_fixcfg.
++ */
++void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
++{
++	if (pc->early_setup_done)
++		return;
++
++	pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
++	if (pc->hostmode)
++		goto out;
++
++	bcma_core_pci_fixcfg(pc);
++
++out:
++	pc->early_setup_done = true;
++}
++
++/**************************************************
+  * Workarounds.
+  **************************************************/
+ 
+@@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workarou
+ 		                     tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
+ }
+ 
+-static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
+-{
+-	struct bcma_device *core = pc->core;
+-	u16 val16, core_index;
+-	uint regoff;
+-
+-	regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
+-	core_index = (u16)core->core_index;
+-
+-	val16 = pcicore_read16(pc, regoff);
+-	if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
+-	     != core_index) {
+-		val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
+-			(val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
+-		pcicore_write16(pc, regoff, val16);
+-	}
+-}
+-
+ /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
+ /* Needs to happen when coming out of 'standby'/'hibernate' */
+ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
+@@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(s
+ 
+ static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
+ {
+-	bcma_core_pci_fixcfg(pc);
+ 	bcma_pcicore_serdes_workaround(pc);
+ 	bcma_core_pci_config_fixup(pc);
+ }
+@@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_
+ 	if (pc->setup_done)
+ 		return;
+ 
+-#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+-	pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
++	bcma_core_pci_early_init(pc);
++
+ 	if (pc->hostmode)
+ 		bcma_core_pci_hostmode_init(pc);
+-#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+-
+-	if (!pc->hostmode)
++	else
+ 		bcma_core_pci_clientmode_init(pc);
+ }
+ 
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -13,10 +13,12 @@
+ 
+ static void bcma_host_pci_switch_core(struct bcma_device *core)
+ {
++	int win2 = core->bus->host_is_pcie2 ?
++		BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2;
++
+ 	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
+ 			       core->addr);
+-	pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
+-			       core->wrap);
++	pci_write_config_dword(core->bus->host_pci, win2, core->wrap);
+ 	core->bus->mapped_core = core;
+ 	bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
+ }
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcm
+ 	int err;
+ 
+ 	/* Scan bus and initialize it */
+-	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++	err = bcma_bus_early_register(bus);
+ 	if (err)
+ 		iounmap(bus->mmio);
+ 
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus *
+ 	}
+ }
+ 
++void bcma_init_bus(struct bcma_bus *bus)
++{
++	mutex_lock(&bcma_buses_mutex);
++	bus->num = bcma_bus_next_num++;
++	mutex_unlock(&bcma_buses_mutex);
++
++	INIT_LIST_HEAD(&bus->cores);
++	bus->nr_cores = 0;
++
++	bcma_detect_chip(bus);
++}
++
+ static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+ {
+ 	int err;
+@@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct
+ 	struct bcma_device *core, *tmp;
+ 
+ 	list_for_each_entry_safe(core, tmp, &bus->cores, list) {
++		if (!core->dev_registered)
++			continue;
+ 		list_del(&core->list);
+-		if (core->dev_registered)
+-			device_unregister(&core->dev);
++		device_unregister(&core->dev);
+ 	}
+ 	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ 		platform_device_unregister(bus->drv_cc.watchdog);
++
++	/* Now noone uses internally-handled cores, we can free them */
++	list_for_each_entry_safe(core, tmp, &bus->cores, list) {
++		list_del(&core->list);
++		kfree(core);
++	}
+ }
+ 
+ int bcma_bus_register(struct bcma_bus *bus)
+@@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *b
+ 	int err;
+ 	struct bcma_device *core;
+ 
+-	mutex_lock(&bcma_buses_mutex);
+-	bus->num = bcma_bus_next_num++;
+-	mutex_unlock(&bcma_buses_mutex);
+-
+ 	/* Scan for devices (cores) */
+ 	err = bcma_bus_scan(bus);
+ 	if (err) {
+@@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *b
+ 		bcma_core_chipcommon_early_init(&bus->drv_cc);
+ 	}
+ 
++	/* Early init PCIE core */
++	core = bcma_find_core(bus, BCMA_CORE_PCIE);
++	if (core) {
++		bus->drv_pci[0].core = core;
++		bcma_core_pci_early_init(&bus->drv_pci[0]);
++	}
++
+ 	/* Cores providing flash access go before SPROM init */
+ 	list_for_each_entry(core, &bus->cores, list) {
+ 		if (bcma_is_core_needed_early(core->id.id))
+@@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *b
+ 
+ void bcma_bus_unregister(struct bcma_bus *bus)
+ {
+-	struct bcma_device *cores[3];
+ 	int err;
+ 
+ 	err = bcma_gpio_unregister(&bus->drv_cc);
+@@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus
+ 
+ 	bcma_core_chipcommon_b_free(&bus->drv_cc_b);
+ 
+-	cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+-	cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
+-	cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
+-
+ 	bcma_unregister_cores(bus);
+-
+-	kfree(cores[2]);
+-	kfree(cores[1]);
+-	kfree(cores[0]);
+ }
+ 
+-int __init bcma_bus_early_register(struct bcma_bus *bus,
+-				   struct bcma_device *core_cc,
+-				   struct bcma_device *core_mips)
++/*
++ * This is a special version of bus registration function designed for SoCs.
++ * It scans bus and performs basic initialization of main cores only.
++ * Please note it requires memory allocation, however it won't try to sleep.
++ */
++int __init bcma_bus_early_register(struct bcma_bus *bus)
+ {
+ 	int err;
+ 	struct bcma_device *core;
+-	struct bcma_device_id match;
+-
+-	match.manuf = BCMA_MANUF_BCM;
+-	match.id = bcma_cc_core_id(bus);
+-	match.class = BCMA_CL_SIM;
+-	match.rev = BCMA_ANY_REV;
+ 
+-	/* Scan for chip common core */
+-	err = bcma_bus_scan_early(bus, &match, core_cc);
+-	if (err) {
+-		bcma_err(bus, "Failed to scan for common core: %d\n", err);
+-		return -1;
+-	}
+-
+-	match.manuf = BCMA_MANUF_MIPS;
+-	match.id = BCMA_CORE_MIPS_74K;
+-	match.class = BCMA_CL_SIM;
+-	match.rev = BCMA_ANY_REV;
+-
+-	/* Scan for mips core */
+-	err = bcma_bus_scan_early(bus, &match, core_mips);
++	/* Scan for devices (cores) */
++	err = bcma_bus_scan(bus);
+ 	if (err) {
+-		bcma_err(bus, "Failed to scan for mips core: %d\n", err);
++		bcma_err(bus, "Failed to scan bus: %d\n", err);
+ 		return -1;
+ 	}
+ 
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcm
+ 	return 0;
+ }
+ 
+-void bcma_init_bus(struct bcma_bus *bus)
++void bcma_detect_chip(struct bcma_bus *bus)
+ {
+ 	s32 tmp;
+ 	struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
+ 	char chip_id[8];
+ 
+-	INIT_LIST_HEAD(&bus->cores);
+-	bus->nr_cores = 0;
+-
+ 	bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
+ 
+ 	tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
+@@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
+ 
+ 	int err, core_num = 0;
+ 
++	/* Skip if bus was already scanned (e.g. during early register) */
++	if (bus->nr_cores)
++		return 0;
++
+ 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+ 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+ 		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+@@ -519,64 +520,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
+ out:
+ 	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ 		iounmap(eromptr);
+-
+-	return err;
+-}
+-
+-int __init bcma_bus_scan_early(struct bcma_bus *bus,
+-			       struct bcma_device_id *match,
+-			       struct bcma_device *core)
+-{
+-	u32 erombase;
+-	u32 __iomem *eromptr, *eromend;
+-
+-	int err = -ENODEV;
+-	int core_num = 0;
+-
+-	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+-	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
+-		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+-		if (!eromptr)
+-			return -ENOMEM;
+-	} else {
+-		eromptr = bus->mmio;
+-	}
+-
+-	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+-
+-	bcma_scan_switch_core(bus, erombase);
+-
+-	while (eromptr < eromend) {
+-		memset(core, 0, sizeof(*core));
+-		INIT_LIST_HEAD(&core->list);
+-		core->bus = bus;
+-
+-		err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
+-		if (err == -ENODEV) {
+-			core_num++;
+-			continue;
+-		} else if (err == -ENXIO)
+-			continue;
+-		else if (err == -ESPIPE)
+-			break;
+-		else if (err < 0)
+-			goto out;
+-
+-		core->core_index = core_num++;
+-		bus->nr_cores++;
+-		bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+-			  core->core_index, bcma_device_name(&core->id),
+-			  core->id.manuf, core->id.id, core->id.rev,
+-			  core->id.class);
+-
+-		list_add_tail(&core->list, &bus->cores);
+-		err = 0;
+-		break;
+-	}
+-
+-out:
+-	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+-		iounmap(eromptr);
+ 
+ 	return err;
+ }
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ 	u16 offset = BCMA_CC_SPROM;
+ 	u16 *sprom;
+ 	size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
+-				 SSB_SPROMSIZE_WORDS_R10, };
++				 SSB_SPROMSIZE_WORDS_R10,
++				 SSB_SPROMSIZE_WORDS_R11, };
+ 	int i, err = 0;
+ 
+ 	if (!bus->drv_cc.core)
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -319,6 +319,7 @@ struct bcma_bus {
+ 	const struct bcma_host_ops *ops;
+ 
+ 	enum bcma_hosttype hosttype;
++	bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */
+ 	union {
+ 		/* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
+ 		struct pci_dev *host_pci;
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -223,6 +223,7 @@ struct bcma_drv_pci_host {
+ 
+ struct bcma_drv_pci {
+ 	struct bcma_device *core;
++	u8 early_setup_done:1;
+ 	u8 setup_done:1;
+ 	u8 hostmode:1;
+ 
+@@ -237,6 +238,7 @@ struct bcma_drv_pci {
+ #define pcicore_write16(pc, offset, val)	bcma_write16((pc)->core, offset, val)
+ #define pcicore_write32(pc, offset, val)	bcma_write32((pc)->core, offset, val)
+ 
++extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
+ extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
+ extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
+ 				 struct bcma_device *core, bool enable);
+--- a/include/linux/bcma/bcma_regs.h
++++ b/include/linux/bcma/bcma_regs.h
+@@ -64,6 +64,8 @@
+ #define  BCMA_PCI_GPIO_XTAL		0x40	/* PCI config space GPIO 14 for Xtal powerup */
+ #define  BCMA_PCI_GPIO_PLL		0x80	/* PCI config space GPIO 15 for PLL powerdown */
+ 
++#define BCMA_PCIE2_BAR0_WIN2		0x70
++
+ /* SiliconBackplane Address Map.
+  * All regions may not exist on all chips.
+  */
+--- a/include/linux/bcma/bcma_soc.h
++++ b/include/linux/bcma/bcma_soc.h
+@@ -5,8 +5,6 @@
+ 
+ struct bcma_soc {
+ 	struct bcma_bus bus;
+-	struct bcma_device core_cc;
+-	struct bcma_device core_mips;
+ };
+ 
+ int __init bcma_host_soc_register(struct bcma_soc *soc);
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -173,6 +173,7 @@
+ #define SSB_SPROMSIZE_BYTES_R123	(SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
+ #define SSB_SPROMSIZE_BYTES_R4		(SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
+ #define SSB_SPROMSIZE_WORDS_R10		230
++#define SSB_SPROMSIZE_WORDS_R11		234
+ #define SSB_SPROM_BASE1			0x1000
+ #define SSB_SPROM_BASE31		0x0800
+ #define SSB_SPROM_REVISION		0x007E
diff --git a/target/linux/generic/patches-3.18/027-bcma-from-4.1.patch b/target/linux/generic/patches-3.18/027-bcma-from-4.1.patch
new file mode 100644
index 0000000000..c88a816fef
--- /dev/null
+++ b/target/linux/generic/patches-3.18/027-bcma-from-4.1.patch
@@ -0,0 +1,680 @@
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -24,6 +24,7 @@ bool bcma_wait_value(struct bcma_device
+ 		     int timeout);
+ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
+ void bcma_init_bus(struct bcma_bus *bus);
++void bcma_unregister_cores(struct bcma_bus *bus);
+ int bcma_bus_register(struct bcma_bus *bus);
+ void bcma_bus_unregister(struct bcma_bus *bus);
+ int __init bcma_bus_early_register(struct bcma_bus *bus);
+@@ -40,6 +41,9 @@ int bcma_bus_scan(struct bcma_bus *bus);
+ int bcma_sprom_get(struct bcma_bus *bus);
+ 
+ /* driver_chipcommon.c */
++void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
++void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+ extern struct platform_device bcma_pflash_dev;
+@@ -50,6 +54,8 @@ int bcma_core_chipcommon_b_init(struct b
+ void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
+ 
+ /* driver_chipcommon_pmu.c */
++void bcma_pmu_early_init(struct bcma_drv_cc *cc);
++void bcma_pmu_init(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
+ 
+@@ -98,7 +104,35 @@ static inline void __exit bcma_host_soc_
+ #endif /* CONFIG_BCMA_HOST_SOC && CONFIG_OF */
+ 
+ /* driver_pci.c */
++#ifdef CONFIG_BCMA_DRIVER_PCI
+ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
++void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
++void bcma_core_pci_init(struct bcma_drv_pci *pc);
++void bcma_core_pci_up(struct bcma_drv_pci *pc);
++void bcma_core_pci_down(struct bcma_drv_pci *pc);
++#else
++static inline void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
++{
++	WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
++}
++static inline void bcma_core_pci_init(struct bcma_drv_pci *pc)
++{
++	/* Initialization is required for PCI hosted bus */
++	WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
++}
++#endif
++
++/* driver_pcie2.c */
++#ifdef CONFIG_BCMA_DRIVER_PCI
++void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2);
++void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2);
++#else
++static inline void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
++{
++	/* Initialization is required for PCI hosted bus */
++	WARN_ON(pcie2->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
++}
++#endif
+ 
+ extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
+ 
+@@ -115,6 +149,39 @@ static inline void bcma_core_pci_hostmod
+ }
+ #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+ 
++/**************************************************
++ * driver_mips.c
++ **************************************************/
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
++void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++	return 0;
++}
++static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
++{
++}
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++}
++#endif
++
++/**************************************************
++ * driver_gmac_cmn.c
++ **************************************************/
++
++#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
++void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
++#else
++static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc)
++{
++}
++#endif
++
+ #ifdef CONFIG_BCMA_DRIVER_GPIO
+ /* driver_gpio.c */
+ int bcma_gpio_init(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -17,6 +17,8 @@
+ 
+ #include "bcma_private.h"
+ 
++#define BCMA_GPIO_MAX_PINS	32
++
+ static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
+ {
+ 	return container_of(chip, struct bcma_drv_cc, gpio);
+@@ -76,7 +78,7 @@ static void bcma_gpio_free(struct gpio_c
+ 	bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
+ }
+ 
+-#if IS_BUILTIN(CONFIG_BCM47XX)
++#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
+ static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+ {
+ 	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+@@ -204,6 +206,7 @@ static void bcma_gpio_irq_domain_exit(st
+ 
+ int bcma_gpio_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
+ 	struct gpio_chip *chip = &cc->gpio;
+ 	int err;
+ 
+@@ -215,14 +218,14 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 	chip->set		= bcma_gpio_set_value;
+ 	chip->direction_input	= bcma_gpio_direction_input;
+ 	chip->direction_output	= bcma_gpio_direction_output;
+-#if IS_BUILTIN(CONFIG_BCM47XX)
++#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
+ 	chip->to_irq		= bcma_gpio_to_irq;
+ #endif
+ #if IS_BUILTIN(CONFIG_OF)
+ 	if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+ 		chip->of_node	= cc->core->dev.of_node;
+ #endif
+-	switch (cc->core->bus->chipinfo.id) {
++	switch (bus->chipinfo.id) {
+ 	case BCMA_CHIP_ID_BCM5357:
+ 	case BCMA_CHIP_ID_BCM53572:
+ 		chip->ngpio	= 32;
+@@ -231,13 +234,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 		chip->ngpio	= 16;
+ 	}
+ 
+-	/* There is just one SoC in one device and its GPIO addresses should be
+-	 * deterministic to address them more easily. The other buses could get
+-	 * a random base number. */
+-	if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+-		chip->base		= 0;
+-	else
+-		chip->base		= -1;
++	/*
++	 * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
++	 * pin numbers. We don't have Device Tree there and we can't really use
++	 * relative (per chip) numbers.
++	 * So let's use predictable base for BCM47XX and "random" for all other.
++	 */
++#if IS_BUILTIN(CONFIG_BCM47XX)
++	chip->base		= bus->num * BCMA_GPIO_MAX_PINS;
++#else
++	chip->base		= -1;
++#endif
+ 
+ 	err = bcma_gpio_irq_domain_init(cc);
+ 	if (err)
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -282,39 +282,6 @@ void bcma_core_pci_power_save(struct bcm
+ }
+ EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
+ 
+-int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+-			  bool enable)
+-{
+-	struct pci_dev *pdev;
+-	u32 coremask, tmp;
+-	int err = 0;
+-
+-	if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
+-		/* This bcma device is not on a PCI host-bus. So the IRQs are
+-		 * not routed through the PCI core.
+-		 * So we must not enable routing through the PCI core. */
+-		goto out;
+-	}
+-
+-	pdev = pc->core->bus->host_pci;
+-
+-	err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
+-	if (err)
+-		goto out;
+-
+-	coremask = BIT(core->core_index) << 8;
+-	if (enable)
+-		tmp |= coremask;
+-	else
+-		tmp &= ~coremask;
+-
+-	err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
+-
+-out:
+-	return err;
+-}
+-EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
+-
+ static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
+ {
+ 	u32 w;
+@@ -328,28 +295,12 @@ static void bcma_core_pci_extend_L1timer
+ 	bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
+ }
+ 
+-void bcma_core_pci_up(struct bcma_bus *bus)
++void bcma_core_pci_up(struct bcma_drv_pci *pc)
+ {
+-	struct bcma_drv_pci *pc;
+-
+-	if (bus->hosttype != BCMA_HOSTTYPE_PCI)
+-		return;
+-
+-	pc = &bus->drv_pci[0];
+-
+ 	bcma_core_pci_extend_L1timer(pc, true);
+ }
+-EXPORT_SYMBOL_GPL(bcma_core_pci_up);
+ 
+-void bcma_core_pci_down(struct bcma_bus *bus)
++void bcma_core_pci_down(struct bcma_drv_pci *pc)
+ {
+-	struct bcma_drv_pci *pc;
+-
+-	if (bus->hosttype != BCMA_HOSTTYPE_PCI)
+-		return;
+-
+-	pc = &bus->drv_pci[0];
+-
+ 	bcma_core_pci_extend_L1timer(pc, false);
+ }
+-EXPORT_SYMBOL_GPL(bcma_core_pci_down);
+--- a/drivers/bcma/driver_pci_host.c
++++ b/drivers/bcma/driver_pci_host.c
+@@ -11,6 +11,7 @@
+ 
+ #include "bcma_private.h"
+ #include <linux/pci.h>
++#include <linux/slab.h>
+ #include <linux/export.h>
+ #include <linux/bcma/bcma.h>
+ #include <asm/paccess.h>
+--- a/drivers/bcma/driver_pcie2.c
++++ b/drivers/bcma/driver_pcie2.c
+@@ -10,6 +10,7 @@
+ 
+ #include "bcma_private.h"
+ #include <linux/bcma/bcma.h>
++#include <linux/pci.h>
+ 
+ /**************************************************
+  * R/W ops.
+@@ -156,14 +157,23 @@ static void pciedev_reg_pm_clk_period(st
+ 
+ void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
+ {
+-	struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo;
++	struct bcma_bus *bus = pcie2->core->bus;
++	struct bcma_chipinfo *ci = &bus->chipinfo;
+ 	u32 tmp;
+ 
+ 	tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54));
+ 	if ((tmp & 0xe) >> 1 == 2)
+ 		bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17);
+ 
+-	/* TODO: Do we need pcie_reqsize? */
++	switch (bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM4360:
++	case BCMA_CHIP_ID_BCM4352:
++		pcie2->reqsize = 1024;
++		break;
++	default:
++		pcie2->reqsize = 128;
++		break;
++	}
+ 
+ 	if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3)
+ 		bcma_core_pcie2_war_delay_perst_enab(pcie2, true);
+@@ -173,3 +183,18 @@ void bcma_core_pcie2_init(struct bcma_dr
+ 	pciedev_crwlpciegen2_180(pcie2);
+ 	pciedev_crwlpciegen2_182(pcie2);
+ }
++
++/**************************************************
++ * Runtime ops.
++ **************************************************/
++
++void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2)
++{
++	struct bcma_bus *bus = pcie2->core->bus;
++	struct pci_dev *dev = bus->host_pci;
++	int err;
++
++	err = pcie_set_readrq(dev, pcie2->reqsize);
++	if (err)
++		bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err);
++}
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -213,16 +213,26 @@ static int bcma_host_pci_probe(struct pc
+ 	/* Initialize struct, detect chip */
+ 	bcma_init_bus(bus);
+ 
++	/* Scan bus to find out generation of PCIe core */
++	err = bcma_bus_scan(bus);
++	if (err)
++		goto err_pci_unmap_mmio;
++
++	if (bcma_find_core(bus, BCMA_CORE_PCIE2))
++		bus->host_is_pcie2 = true;
++
+ 	/* Register */
+ 	err = bcma_bus_register(bus);
+ 	if (err)
+-		goto err_pci_unmap_mmio;
++		goto err_unregister_cores;
+ 
+ 	pci_set_drvdata(dev, bus);
+ 
+ out:
+ 	return err;
+ 
++err_unregister_cores:
++	bcma_unregister_cores(bus);
+ err_pci_unmap_mmio:
+ 	pci_iounmap(dev, bus->mmio);
+ err_pci_release_regions:
+@@ -283,9 +293,12 @@ static const struct pci_device_id bcma_p
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) },	/* 0xa8db, BCM43217 (sic!) */
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) },	/* 0xa8dc */
+@@ -310,3 +323,65 @@ void __exit bcma_host_pci_exit(void)
+ {
+ 	pci_unregister_driver(&bcma_pci_bridge_driver);
+ }
++
++/**************************************************
++ * Runtime ops for drivers.
++ **************************************************/
++
++/* See also pcicore_up */
++void bcma_host_pci_up(struct bcma_bus *bus)
++{
++	if (bus->hosttype != BCMA_HOSTTYPE_PCI)
++		return;
++
++	if (bus->host_is_pcie2)
++		bcma_core_pcie2_up(&bus->drv_pcie2);
++	else
++		bcma_core_pci_up(&bus->drv_pci[0]);
++}
++EXPORT_SYMBOL_GPL(bcma_host_pci_up);
++
++/* See also pcicore_down */
++void bcma_host_pci_down(struct bcma_bus *bus)
++{
++	if (bus->hosttype != BCMA_HOSTTYPE_PCI)
++		return;
++
++	if (!bus->host_is_pcie2)
++		bcma_core_pci_down(&bus->drv_pci[0]);
++}
++EXPORT_SYMBOL_GPL(bcma_host_pci_down);
++
++/* See also si_pci_setup */
++int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
++			  bool enable)
++{
++	struct pci_dev *pdev;
++	u32 coremask, tmp;
++	int err = 0;
++
++	if (bus->hosttype != BCMA_HOSTTYPE_PCI) {
++		/* This bcma device is not on a PCI host-bus. So the IRQs are
++		 * not routed through the PCI core.
++		 * So we must not enable routing through the PCI core. */
++		goto out;
++	}
++
++	pdev = bus->host_pci;
++
++	err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
++	if (err)
++		goto out;
++
++	coremask = BIT(core->core_index) << 8;
++	if (enable)
++		tmp |= coremask;
++	else
++		tmp &= ~coremask;
++
++	err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
++
++out:
++	return err;
++}
++EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl);
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -363,7 +363,7 @@ static int bcma_register_devices(struct
+ 	return 0;
+ }
+ 
+-static void bcma_unregister_cores(struct bcma_bus *bus)
++void bcma_unregister_cores(struct bcma_bus *bus)
+ {
+ 	struct bcma_device *core, *tmp;
+ 
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -4770,7 +4770,7 @@ static void b43_wireless_core_exit(struc
+ 	switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+ 	case B43_BUS_BCMA:
+-		bcma_core_pci_down(dev->dev->bdev->bus);
++		bcma_host_pci_down(dev->dev->bdev->bus);
+ 		break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+@@ -4817,9 +4817,9 @@ static int b43_wireless_core_init(struct
+ 	switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+ 	case B43_BUS_BCMA:
+-		bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
++		bcma_host_pci_irq_ctl(dev->dev->bdev->bus,
+ 				      dev->dev->bdev, true);
+-		bcma_core_pci_up(dev->dev->bdev->bus);
++		bcma_host_pci_up(dev->dev->bdev->bus);
+ 		break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -4669,7 +4669,7 @@ static int brcms_b_attach(struct brcms_c
+ 	brcms_c_coredisable(wlc_hw);
+ 
+ 	/* Match driver "down" state */
+-	bcma_core_pci_down(wlc_hw->d11core->bus);
++	bcma_host_pci_down(wlc_hw->d11core->bus);
+ 
+ 	/* turn off pll and xtal to match driver "down" state */
+ 	brcms_b_xtal(wlc_hw, OFF);
+@@ -4960,7 +4960,7 @@ static int brcms_b_up_prep(struct brcms_
+ 	 * Configure pci/pcmcia here instead of in brcms_c_attach()
+ 	 * to allow mfg hotswap:  down, hotswap (chip power cycle), up.
+ 	 */
+-	bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
++	bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
+ 			      true);
+ 
+ 	/*
+@@ -4970,12 +4970,12 @@ static int brcms_b_up_prep(struct brcms_
+ 	 */
+ 	if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
+ 		/* put SB PCI in down state again */
+-		bcma_core_pci_down(wlc_hw->d11core->bus);
++		bcma_host_pci_down(wlc_hw->d11core->bus);
+ 		brcms_b_xtal(wlc_hw, OFF);
+ 		return -ENOMEDIUM;
+ 	}
+ 
+-	bcma_core_pci_up(wlc_hw->d11core->bus);
++	bcma_host_pci_up(wlc_hw->d11core->bus);
+ 
+ 	/* reset the d11 core */
+ 	brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
+@@ -5172,7 +5172,7 @@ static int brcms_b_down_finish(struct br
+ 
+ 		/* turn off primary xtal and pll */
+ 		if (!wlc_hw->noreset) {
+-			bcma_core_pci_down(wlc_hw->d11core->bus);
++			bcma_host_pci_down(wlc_hw->d11core->bus);
+ 			brcms_b_xtal(wlc_hw, OFF);
+ 		}
+ 	}
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -435,6 +435,27 @@ static inline struct bcma_device *bcma_f
+ 	return bcma_find_core_unit(bus, coreid, 0);
+ }
+ 
++#ifdef CONFIG_BCMA_HOST_PCI
++extern void bcma_host_pci_up(struct bcma_bus *bus);
++extern void bcma_host_pci_down(struct bcma_bus *bus);
++extern int bcma_host_pci_irq_ctl(struct bcma_bus *bus,
++				 struct bcma_device *core, bool enable);
++#else
++static inline void bcma_host_pci_up(struct bcma_bus *bus)
++{
++}
++static inline void bcma_host_pci_down(struct bcma_bus *bus)
++{
++}
++static inline int bcma_host_pci_irq_ctl(struct bcma_bus *bus,
++					struct bcma_device *core, bool enable)
++{
++	if (bus->hosttype == BCMA_HOSTTYPE_PCI)
++		return -ENOTSUPP;
++	return 0;
++}
++#endif
++
+ extern bool bcma_core_is_enabled(struct bcma_device *core);
+ extern void bcma_core_disable(struct bcma_device *core, u32 flags);
+ extern int bcma_core_enable(struct bcma_device *core, u32 flags);
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -238,13 +238,13 @@ struct bcma_drv_pci {
+ #define pcicore_write16(pc, offset, val)	bcma_write16((pc)->core, offset, val)
+ #define pcicore_write32(pc, offset, val)	bcma_write32((pc)->core, offset, val)
+ 
+-extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
+-extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
+-extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
+-				 struct bcma_device *core, bool enable);
+-extern void bcma_core_pci_up(struct bcma_bus *bus);
+-extern void bcma_core_pci_down(struct bcma_bus *bus);
++#ifdef CONFIG_BCMA_DRIVER_PCI
+ extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
++#else
++static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
++{
++}
++#endif
+ 
+ extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
+ extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
+--- a/include/linux/bcma/bcma_driver_pcie2.h
++++ b/include/linux/bcma/bcma_driver_pcie2.h
+@@ -143,6 +143,8 @@
+ 
+ struct bcma_drv_pcie2 {
+ 	struct bcma_device *core;
++
++	u16 reqsize;
+ };
+ 
+ #define pcie2_read16(pcie2, offset)		bcma_read16((pcie2)->core, offset)
+@@ -153,6 +155,4 @@ struct bcma_drv_pcie2 {
+ #define pcie2_set32(pcie2, offset, set)		bcma_set32((pcie2)->core, offset, set)
+ #define pcie2_mask32(pcie2, offset, mask)	bcma_mask32((pcie2)->core, offset, mask)
+ 
+-void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2);
+-
+ #endif /* LINUX_BCMA_DRIVER_PCIE2_H_ */
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE
+ config BCMA_HOST_PCI
+ 	bool "Support for BCMA on PCI-host bus"
+ 	depends on BCMA_HOST_PCI_POSSIBLE
++	select BCMA_DRIVER_PCI
+ 	default y
+ 
+ config BCMA_DRIVER_PCI_HOSTMODE
+@@ -44,6 +45,22 @@ config BCMA_HOST_SOC
+ 
+ 	  If unsure, say N
+ 
++config BCMA_DRIVER_PCI
++	bool "BCMA Broadcom PCI core driver"
++	depends on BCMA && PCI
++	default y
++	help
++	  BCMA bus may have many versions of PCIe core. This driver
++	  supports:
++	  1) PCIe core working in clientmode
++	  2) PCIe Gen 2 clientmode core
++
++	  In general PCIe (Gen 2) clientmode core is required on PCIe
++	  hosted buses. It's responsible for initialization and basic
++	  hardware management.
++	  This driver is also prerequisite for a hostmode PCIe core
++	  support.
++
+ config BCMA_DRIVER_MIPS
+ 	bool "BCMA Broadcom MIPS core driver"
+ 	depends on BCMA && MIPS
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -3,8 +3,8 @@ bcma-y					+= driver_chipcommon.o driver
+ bcma-y					+= driver_chipcommon_b.o
+ bcma-$(CONFIG_BCMA_SFLASH)		+= driver_chipcommon_sflash.o
+ bcma-$(CONFIG_BCMA_NFLASH)		+= driver_chipcommon_nflash.o
+-bcma-y					+= driver_pci.o
+-bcma-y					+= driver_pcie2.o
++bcma-$(CONFIG_BCMA_DRIVER_PCI)		+= driver_pci.o
++bcma-$(CONFIG_BCMA_DRIVER_PCI)		+= driver_pcie2.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)	+= driver_pci_host.o
+ bcma-$(CONFIG_BCMA_DRIVER_MIPS)		+= driver_mips.o
+ bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN)	+= driver_gmac_cmn.o
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -663,14 +663,6 @@ struct bcma_drv_cc_b {
+ #define bcma_cc_maskset32(cc, offset, mask, set) \
+ 	bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+ 
+-extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
+-extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+-
+-extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+-extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
+-
+-void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+-
+ extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+ 
+ extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+@@ -690,9 +682,6 @@ u32 bcma_chipco_gpio_pullup(struct bcma_
+ u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value);
+ 
+ /* PMU support */
+-extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+-extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
+-
+ extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ 				  u32 value);
+ extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
+--- a/include/linux/bcma/bcma_driver_gmac_cmn.h
++++ b/include/linux/bcma/bcma_driver_gmac_cmn.h
+@@ -91,10 +91,4 @@ struct bcma_drv_gmac_cmn {
+ #define gmac_cmn_write16(gc, offset, val)	bcma_write16((gc)->core, offset, val)
+ #define gmac_cmn_write32(gc, offset, val)	bcma_write32((gc)->core, offset, val)
+ 
+-#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
+-extern void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
+-#else
+-static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { }
+-#endif
+-
+ #endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */
+--- a/include/linux/bcma/bcma_driver_mips.h
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -39,21 +39,6 @@ struct bcma_drv_mips {
+ 	u8 early_setup_done:1;
+ };
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+-extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
+-
+-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+-#else
+-static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
+-static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
+-
+-static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+-{
+-	return 0;
+-}
+-#endif
+-
+ extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+ 
+ #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
diff --git a/target/linux/generic/patches-3.18/028-bcma-from-4.2.patch b/target/linux/generic/patches-3.18/028-bcma-from-4.2.patch
new file mode 100644
index 0000000000..ba3df18bdd
--- /dev/null
+++ b/target/linux/generic/patches-3.18/028-bcma-from-4.2.patch
@@ -0,0 +1,86 @@
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 		chip->of_node	= cc->core->dev.of_node;
+ #endif
+ 	switch (bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM4707:
+ 	case BCMA_CHIP_ID_BCM5357:
+ 	case BCMA_CHIP_ID_BCM53572:
+ 		chip->ngpio	= 32;
+@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 	}
+ 
+ 	/*
+-	 * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
+-	 * pin numbers. We don't have Device Tree there and we can't really use
+-	 * relative (per chip) numbers.
+-	 * So let's use predictable base for BCM47XX and "random" for all other.
++	 * Register SoC GPIO devices with absolute GPIO pin base.
++	 * On MIPS, we don't have Device Tree and we can't use relative (per chip)
++	 * GPIO numbers.
++	 * On some ARM devices, user space may want to access some system GPIO
++	 * pins directly, which is easier to do with a predictable GPIO base.
+ 	 */
+-#if IS_BUILTIN(CONFIG_BCM47XX)
+-	chip->base		= bus->num * BCMA_GPIO_MAX_PINS;
+-#else
+-	chip->base		= -1;
+-#endif
++	if (IS_BUILTIN(CONFIG_BCM47XX) ||
++	    cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
++		chip->base		= bus->num * BCMA_GPIO_MAX_PINS;
++	else
++		chip->base		= -1;
+ 
+ 	err = bcma_gpio_irq_domain_init(cc);
+ 	if (err)
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -29,12 +29,6 @@ config BCMA_HOST_PCI
+ 	select BCMA_DRIVER_PCI
+ 	default y
+ 
+-config BCMA_DRIVER_PCI_HOSTMODE
+-	bool "Driver for PCI core working in hostmode"
+-	depends on BCMA && MIPS && BCMA_HOST_PCI
+-	help
+-	  PCI core hostmode operation (external PCI bus).
+-
+ config BCMA_HOST_SOC
+ 	bool "Support for BCMA in a SoC"
+ 	depends on BCMA
+@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI
+ 	  This driver is also prerequisite for a hostmode PCIe core
+ 	  support.
+ 
++config BCMA_DRIVER_PCI_HOSTMODE
++	bool "Driver for PCI core working in hostmode"
++	depends on BCMA && MIPS && BCMA_DRIVER_PCI
++	help
++	  PCI core hostmode operation (external PCI bus).
++
+ config BCMA_DRIVER_MIPS
+ 	bool "BCMA Broadcom MIPS core driver"
+ 	depends on BCMA && MIPS
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s
+ }
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+ extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
+ extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
++#else
++static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
++{
++	return -ENOTSUPP;
++}
++static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
++{
++	return -ENOTSUPP;
++}
++#endif
+ 
+ #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
diff --git a/target/linux/generic/patches-3.18/029-bcma-from-4.4.patch b/target/linux/generic/patches-3.18/029-bcma-from-4.4.patch
new file mode 100644
index 0000000000..5704081ee4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/029-bcma-from-4.4.patch
@@ -0,0 +1,26 @@
+commit 55acca90da52b85299c033354e51ddaa7b73e019
+Author: Hante Meuleman <meuleman@broadcom.com>
+Date:   Fri Sep 18 22:08:17 2015 +0200
+
+    brcmfmac: Add support for the BCM4365 and BCM4366 PCIE devices.
+    
+    This patch adds support for the BCM4365 and BCM4366 11ac Wave2
+    PCIE devices.
+    
+    Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+    Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+    Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+    Signed-off-by: Arend van Spriel <arend@broadcom.com>
+    Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -151,6 +151,8 @@ struct bcma_host_ops {
+ #define BCMA_CORE_PCIE2			0x83C	/* PCI Express Gen2 */
+ #define BCMA_CORE_USB30_DEV		0x83D
+ #define BCMA_CORE_ARM_CR4		0x83E
++#define BCMA_CORE_ARM_CA7		0x847
++#define BCMA_CORE_SYS_MEM		0x849
+ #define BCMA_CORE_DEFAULT		0xFFF
+ 
+ #define BCMA_MAX_NR_CORES		16
diff --git a/target/linux/generic/patches-3.18/030-backport_bcm47xx_nvram.patch b/target/linux/generic/patches-3.18/030-backport_bcm47xx_nvram.patch
new file mode 100644
index 0000000000..7ae8b1db6c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/030-backport_bcm47xx_nvram.patch
@@ -0,0 +1,52 @@
+--- /dev/null
++++ b/include/linux/bcm47xx_nvram.h
+@@ -0,0 +1,49 @@
++/*
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ */
++
++#ifndef __BCM47XX_NVRAM_H
++#define __BCM47XX_NVRAM_H
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/vmalloc.h>
++
++#ifdef CONFIG_BCM47XX_NVRAM
++int bcm47xx_nvram_init_from_mem(u32 base, u32 lim);
++int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
++int bcm47xx_nvram_gpio_pin(const char *name);
++char *bcm47xx_nvram_get_contents(size_t *val_len);
++static inline void bcm47xx_nvram_release_contents(char *nvram)
++{
++	vfree(nvram);
++};
++#else
++static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
++{
++	return -ENOTSUPP;
++};
++static inline int bcm47xx_nvram_getenv(const char *name, char *val,
++				       size_t val_len)
++{
++	return -ENOTSUPP;
++};
++static inline int bcm47xx_nvram_gpio_pin(const char *name)
++{
++	return -ENOTSUPP;
++};
++
++static inline char *bcm47xx_nvram_get_contents(size_t *val_len)
++{
++	return NULL;
++};
++
++static inline void bcm47xx_nvram_release_contents(char *nvram)
++{
++};
++#endif
++
++#endif /* __BCM47XX_NVRAM_H */
diff --git a/target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch b/target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch
new file mode 100644
index 0000000000..52a2391ccd
--- /dev/null
+++ b/target/linux/generic/patches-3.18/030-nl80211-Allow-set-network-namespace-by-fd.patch
@@ -0,0 +1,21 @@
+From: Vadim Kochan <vadim4j@gmail.com>
+Date: Mon, 12 Jan 2015 16:34:05 +0200
+Subject: [PATCH] nl80211: Allow set network namespace by fd
+
+Added new NL80211_ATTR_NETNS_FD which allows to
+set namespace via nl80211 by fd.
+
+Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/core/net_namespace.c
++++ b/net/core/net_namespace.c
+@@ -361,6 +361,7 @@ struct net *get_net_ns_by_fd(int fd)
+ 	return ERR_PTR(-EINVAL);
+ }
+ #endif
++EXPORT_SYMBOL_GPL(get_net_ns_by_fd);
+ 
+ struct net *get_net_ns_by_pid(pid_t pid)
+ {
diff --git a/target/linux/generic/patches-3.18/031-bcma-from-4.5.patch b/target/linux/generic/patches-3.18/031-bcma-from-4.5.patch
new file mode 100644
index 0000000000..171395dcec
--- /dev/null
+++ b/target/linux/generic/patches-3.18/031-bcma-from-4.5.patch
@@ -0,0 +1,49 @@
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -637,11 +637,36 @@ static int bcma_device_uevent(struct dev
+ 			      core->id.rev, core->id.class);
+ }
+ 
+-static int __init bcma_modinit(void)
++static unsigned int bcma_bus_registered;
++
++/*
++ * If built-in, bus has to be registered early, before any driver calls
++ * bcma_driver_register.
++ * Otherwise registering driver would trigger BUG in driver_register.
++ */
++static int __init bcma_init_bus_register(void)
+ {
+ 	int err;
+ 
++	if (bcma_bus_registered)
++		return 0;
++
+ 	err = bus_register(&bcma_bus_type);
++	if (!err)
++		bcma_bus_registered = 1;
++
++	return err;
++}
++#ifndef MODULE
++fs_initcall(bcma_init_bus_register);
++#endif
++
++/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */
++static int __init bcma_modinit(void)
++{
++	int err;
++
++	err = bcma_init_bus_register();
+ 	if (err)
+ 		return err;
+ 
+@@ -660,7 +685,7 @@ static int __init bcma_modinit(void)
+ 
+ 	return err;
+ }
+-fs_initcall(bcma_modinit);
++module_init(bcma_modinit);
+ 
+ static void __exit bcma_modexit(void)
+ {
diff --git a/target/linux/generic/patches-3.18/032-bcma-from-4.6.patch b/target/linux/generic/patches-3.18/032-bcma-from-4.6.patch
new file mode 100644
index 0000000000..85eeaad4d3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/032-bcma-from-4.6.patch
@@ -0,0 +1,716 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -15,6 +15,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ 
++static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++
+ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
+ 					 u32 mask, u32 value)
+ {
+@@ -113,8 +115,37 @@ int bcma_chipco_watchdog_register(struct
+ 	return 0;
+ }
+ 
++static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
++{
++	struct bcma_bus *bus = cc->core->bus;
++
++	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++	case BCMA_CC_FLASHT_STSER:
++	case BCMA_CC_FLASHT_ATSER:
++		bcma_debug(bus, "Found serial flash\n");
++		bcma_sflash_init(cc);
++		break;
++	case BCMA_CC_FLASHT_PARA:
++		bcma_debug(bus, "Found parallel flash\n");
++		bcma_pflash_init(cc);
++		break;
++	default:
++		bcma_err(bus, "Flash type not supported\n");
++	}
++
++	if (cc->core->id.rev == 38 ||
++	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
++		if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
++			bcma_debug(bus, "Found NAND flash\n");
++			bcma_nflash_init(cc);
++		}
++	}
++}
++
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
++
+ 	if (cc->early_setup_done)
+ 		return;
+ 
+@@ -129,6 +160,12 @@ void bcma_core_chipcommon_early_init(str
+ 	if (cc->capabilities & BCMA_CC_CAP_PMU)
+ 		bcma_pmu_early_init(cc);
+ 
++	if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
++		bcma_chipco_serial_init(cc);
++
++	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++		bcma_core_chipcommon_flash_detect(cc);
++
+ 	cc->early_setup_done = true;
+ }
+ 
+@@ -185,11 +222,12 @@ u32 bcma_chipco_watchdog_timer_set(struc
+ 			ticks = 2;
+ 		else if (ticks > maxt)
+ 			ticks = maxt;
+-		bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+ 	} else {
+ 		struct bcma_bus *bus = cc->core->bus;
+ 
+ 		if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
++		    bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
+ 		    bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
+ 			bcma_core_set_clockmode(cc->core,
+ 						ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
+@@ -314,9 +352,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
+ 	return res;
+ }
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+ {
++#if IS_BUILTIN(CONFIG_BCM47XX)
+ 	unsigned int irq;
+ 	u32 baud_base;
+ 	u32 i;
+@@ -358,5 +396,5 @@ void bcma_chipco_serial_init(struct bcma
+ 		ports[i].baud_base = baud_base;
+ 		ports[i].reg_shift = 0;
+ 	}
++#endif /* CONFIG_BCM47XX */
+ }
+-#endif /* CONFIG_BCMA_DRIVER_MIPS */
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -15,44 +15,44 @@
+ 
+ u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
+ 
+ void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
+ 
+ void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ 			     u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
+ 
+ void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ 				 u32 offset, u32 mask, u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
+ 
+ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ 				u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
+ 
+@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma
+ {
+ 	u32 ilp_ctl, alp_hz;
+ 
+-	if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
++	if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
+ 	      BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
+ 		return 0;
+ 
+-	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+-			BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
++	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
++			 BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+ 	usleep_range(1000, 2000);
+ 
+-	ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
++	ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+ 	ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
+ 
+-	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+ 
+ 	alp_hz = ilp_ctl * 32768 / 4;
+ 	return (alp_hz + 50000) / 100000 * 100;
+@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct b
+ 		mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
+ 			      BCMA_RES_4314_MACPHY_CLK_AVAIL);
+ 
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+ 		bcma_wait_value(cc->core, BCMA_CLKCTLST,
+ 				BCMA_CLKCTLST_HAVEHT, 0, 20000);
+ 		break;
+@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct b
+ 
+ 	/* Flush */
+ 	if (cc->pmu.rev >= 2)
+-		bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
++		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+ 
+ 	/* TODO: Do we need to update OTP? */
+ }
+@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(stru
+ 
+ 	/* Set the resource masks. */
+ 	if (min_msk)
+-		bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+ 	if (max_msk)
+-		bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+ 
+ 	/*
+ 	 * Add some delay; allow resources to come up and settle.
+@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct
+ 
+ void bcma_pmu_early_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
+ 	u32 pmucap;
+ 
+-	pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
++	if (cc->core->id.rev >= 35 &&
++	    cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
++		cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
++		if (!cc->pmu.core)
++			bcma_warn(bus, "Couldn't find expected PMU core");
++	}
++	if (!cc->pmu.core)
++		cc->pmu.core = cc->core;
++
++	pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
+ 	cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
+ 
+-	bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
+-		   cc->pmu.rev, pmucap);
++	bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
++		   pmucap);
+ }
+ 
+ void bcma_pmu_init(struct bcma_drv_cc *cc)
+ {
+ 	if (cc->pmu.rev == 1)
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
+-			      ~BCMA_CC_PMU_CTL_NOILPONW);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
++				~BCMA_CC_PMU_CTL_NOILPONW);
+ 	else
+-		bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+-			     BCMA_CC_PMU_CTL_NOILPONW);
++		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
++			       BCMA_CC_PMU_CTL_NOILPONW);
+ 
+ 	bcma_pmu_pll_init(cc);
+ 	bcma_pmu_resources_init(cc);
+@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
+ static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ 					 u32 value)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
+ }
+ 
+ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
+@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct
+ 		       bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
+ 
+ 		/* RMW only the P1 divider */
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
+ 				BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
+-		tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ 		tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
+ 		tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
+ 
+ 		/* RMW only the int feedback divider */
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
+ 				BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
+-		tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ 		tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
+ 		tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
+ 
+ 		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
+ 		break;
+@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+ 		break;
+ 	}
+ 
+-	tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
+-	bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
++	tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
+ }
+ EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bc
+ 	{ "M25P32", 0x15, 0x10000, 64, },
+ 	{ "M25P64", 0x16, 0x10000, 128, },
+ 	{ "M25FL128", 0x17, 0x10000, 256, },
++	{ "MX25L25635F", 0x18, 0x10000, 512, },
+ 	{ NULL },
+ };
+ 
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -98,6 +98,9 @@ static const struct bcma_device_id_name
+ 	{ BCMA_CORE_SHIM, "SHIM" },
+ 	{ BCMA_CORE_PCIE2, "PCIe Gen2" },
+ 	{ BCMA_CORE_ARM_CR4, "ARM CR4" },
++	{ BCMA_CORE_GCI, "GCI" },
++	{ BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
++	{ BCMA_CORE_ARM_CA7, "ARM CA7" },
+ 	{ BCMA_CORE_DEFAULT, "Default" },
+ };
+ 
+@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcm
+ 		switch (core->id.id) {
+ 		case BCMA_CORE_4706_MAC_GBIT_COMMON:
+ 		case BCMA_CORE_NS_CHIPCOMMON_B:
++		case BCMA_CORE_PMU:
++		case BCMA_CORE_GCI:
+ 		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
+ 			break;
+ 		default:
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(str
+ 	case B43_BUS_BCMA:
+ 		bcma_cc = &dev->dev->bdev->bus->drv_cc;
+ 
+-		bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
+-		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+-		bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
+-		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
++		bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
++		bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
++		bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
++		bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
+ 		break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -151,6 +151,8 @@ struct bcma_host_ops {
+ #define BCMA_CORE_PCIE2			0x83C	/* PCI Express Gen2 */
+ #define BCMA_CORE_USB30_DEV		0x83D
+ #define BCMA_CORE_ARM_CR4		0x83E
++#define BCMA_CORE_GCI			0x840
++#define BCMA_CORE_CMEM			0x846	/* CNDS DDR2/3 memory controller */
+ #define BCMA_CORE_ARM_CA7		0x847
+ #define BCMA_CORE_SYS_MEM		0x849
+ #define BCMA_CORE_DEFAULT		0xFFF
+@@ -200,6 +202,7 @@ struct bcma_host_ops {
+ #define  BCMA_PKG_ID_BCM4707	1
+ #define  BCMA_PKG_ID_BCM4708	2
+ #define  BCMA_PKG_ID_BCM4709	0
++#define BCMA_CHIP_ID_BCM47094	53030
+ #define BCMA_CHIP_ID_BCM53018	53018
+ 
+ /* Board types (on PCI usually equals to the subsystem dev id) */
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -217,6 +217,11 @@
+ #define	 BCMA_CC_CLKDIV_JTAG_SHIFT	8
+ #define	 BCMA_CC_CLKDIV_UART		0x000000FF
+ #define BCMA_CC_CAP_EXT			0x00AC		/* Capabilities */
++#define  BCMA_CC_CAP_EXT_SECI_PRESENT	0x00000001
++#define  BCMA_CC_CAP_EXT_GSIO_PRESENT	0x00000002
++#define  BCMA_CC_CAP_EXT_GCI_PRESENT	0x00000004
++#define  BCMA_CC_CAP_EXT_SECI_PUART_PRESENT		0x00000008    /* UART present */
++#define  BCMA_CC_CAP_EXT_AOB_PRESENT	0x00000040
+ #define BCMA_CC_PLLONDELAY		0x00B0		/* Rev >= 4 only */
+ #define BCMA_CC_FREFSELDELAY		0x00B4		/* Rev >= 4 only */
+ #define BCMA_CC_SLOWCLKCTL		0x00B8		/* 6 <= Rev <= 9 only */
+@@ -351,12 +356,12 @@
+ #define BCMA_CC_PMU_RES_REQTS		0x0640 /* PMU res req timer sel */
+ #define BCMA_CC_PMU_RES_REQT		0x0644 /* PMU res req timer */
+ #define BCMA_CC_PMU_RES_REQM		0x0648 /* PMU res req mask */
+-#define BCMA_CC_CHIPCTL_ADDR		0x0650
+-#define BCMA_CC_CHIPCTL_DATA		0x0654
+-#define BCMA_CC_REGCTL_ADDR		0x0658
+-#define BCMA_CC_REGCTL_DATA		0x065C
+-#define BCMA_CC_PLLCTL_ADDR		0x0660
+-#define BCMA_CC_PLLCTL_DATA		0x0664
++#define BCMA_CC_PMU_CHIPCTL_ADDR	0x0650
++#define BCMA_CC_PMU_CHIPCTL_DATA	0x0654
++#define BCMA_CC_PMU_REGCTL_ADDR		0x0658
++#define BCMA_CC_PMU_REGCTL_DATA		0x065C
++#define BCMA_CC_PMU_PLLCTL_ADDR		0x0660
++#define BCMA_CC_PMU_PLLCTL_DATA		0x0664
+ #define BCMA_CC_PMU_STRAPOPT		0x0668 /* (corerev >= 28) */
+ #define BCMA_CC_PMU_XTAL_FREQ		0x066C /* (pmurev >= 10) */
+ #define  BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK	0x00001FFF
+@@ -566,17 +571,16 @@
+  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+  */
+ struct bcma_chipcommon_pmu {
++	struct bcma_device *core;	/* Can be separated core or just ChipCommon one */
+ 	u8 rev;			/* PMU revision */
+ 	u32 crystalfreq;	/* The active crystal frequency (in kHz) */
+ };
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ struct bcma_pflash {
+ 	bool present;
+-	u8 buswidth;
+-	u32 window;
+-	u32 window_size;
+ };
++#endif
+ 
+ #ifdef CONFIG_BCMA_SFLASH
+ struct bcma_sflash {
+@@ -602,6 +606,7 @@ struct bcma_nflash {
+ };
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_serial_port {
+ 	void *regs;
+ 	unsigned long clockspeed;
+@@ -621,8 +626,9 @@ struct bcma_drv_cc {
+ 	/* Fast Powerup Delay constant */
+ 	u16 fast_pwrup_delay;
+ 	struct bcma_chipcommon_pmu pmu;
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ 	struct bcma_pflash pflash;
++#endif
+ #ifdef CONFIG_BCMA_SFLASH
+ 	struct bcma_sflash sflash;
+ #endif
+@@ -630,6 +636,7 @@ struct bcma_drv_cc {
+ 	struct bcma_nflash nflash;
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_MIPS
+ 	int nr_serial_ports;
+ 	struct bcma_serial_port serial_ports[4];
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+@@ -663,6 +670,19 @@ struct bcma_drv_cc_b {
+ #define bcma_cc_maskset32(cc, offset, mask, set) \
+ 	bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+ 
++/* PMU registers access */
++#define bcma_pmu_read32(cc, offset) \
++	bcma_read32((cc)->pmu.core, offset)
++#define bcma_pmu_write32(cc, offset, val) \
++	bcma_write32((cc)->pmu.core, offset, val)
++
++#define bcma_pmu_mask32(cc, offset, mask) \
++	bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
++#define bcma_pmu_set32(cc, offset, set) \
++	bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
++#define bcma_pmu_maskset32(cc, offset, mask, set) \
++	bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
++
+ extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+ 
+ extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -44,10 +44,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
+ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+-extern struct platform_device bcma_pflash_dev;
+-#endif /* CONFIG_BCMA_DRIVER_MIPS */
+ 
+ /* driver_chipcommon_b.c */
+ int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
+@@ -59,6 +55,21 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
+ 
++/**************************************************
++ * driver_chipcommon_sflash.c
++ **************************************************/
++
++#ifdef CONFIG_BCMA_PFLASH
++extern struct platform_device bcma_pflash_dev;
++int bcma_pflash_init(struct bcma_drv_cc *cc);
++#else
++static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
++{
++	bcma_err(cc->core->bus, "Parallel flash not supported\n");
++	return 0;
++}
++#endif /* CONFIG_BCMA_PFLASH */
++
+ #ifdef CONFIG_BCMA_SFLASH
+ /* driver_chipcommon_sflash.c */
+ int bcma_sflash_init(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -229,6 +229,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 	case BCMA_CHIP_ID_BCM4707:
+ 	case BCMA_CHIP_ID_BCM5357:
+ 	case BCMA_CHIP_ID_BCM53572:
++	case BCMA_CHIP_ID_BCM47094:
+ 		chip->ngpio	= 32;
+ 		break;
+ 	default:
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -14,8 +14,6 @@
+ 
+ #include <linux/bcma/bcma.h>
+ 
+-#include <linux/mtd/physmap.h>
+-#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+@@ -29,26 +27,6 @@ enum bcma_boot_dev {
+ 	BCMA_BOOT_DEV_NAND,
+ };
+ 
+-static const char * const part_probes[] = { "bcm47xxpart", NULL };
+-
+-static struct physmap_flash_data bcma_pflash_data = {
+-	.part_probe_types	= part_probes,
+-};
+-
+-static struct resource bcma_pflash_resource = {
+-	.name	= "bcma_pflash",
+-	.flags  = IORESOURCE_MEM,
+-};
+-
+-struct platform_device bcma_pflash_dev = {
+-	.name		= "physmap-flash",
+-	.dev		= {
+-		.platform_data  = &bcma_pflash_data,
+-	},
+-	.resource	= &bcma_pflash_resource,
+-	.num_resources	= 1,
+-};
+-
+ /* The 47162a0 hangs when reading MIPS DMP registers registers */
+ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+ {
+@@ -269,48 +247,11 @@ static enum bcma_boot_dev bcma_boot_dev(
+ 	return BCMA_BOOT_DEV_SERIAL;
+ }
+ 
+-static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
+ {
+ 	struct bcma_bus *bus = mcore->core->bus;
+-	struct bcma_drv_cc *cc = &bus->drv_cc;
+-	struct bcma_pflash *pflash = &cc->pflash;
+ 	enum bcma_boot_dev boot_dev;
+ 
+-	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+-	case BCMA_CC_FLASHT_STSER:
+-	case BCMA_CC_FLASHT_ATSER:
+-		bcma_debug(bus, "Found serial flash\n");
+-		bcma_sflash_init(cc);
+-		break;
+-	case BCMA_CC_FLASHT_PARA:
+-		bcma_debug(bus, "Found parallel flash\n");
+-		pflash->present = true;
+-		pflash->window = BCMA_SOC_FLASH2;
+-		pflash->window_size = BCMA_SOC_FLASH2_SZ;
+-
+-		if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
+-		     BCMA_CC_FLASH_CFG_DS) == 0)
+-			pflash->buswidth = 1;
+-		else
+-			pflash->buswidth = 2;
+-
+-		bcma_pflash_data.width = pflash->buswidth;
+-		bcma_pflash_resource.start = pflash->window;
+-		bcma_pflash_resource.end = pflash->window + pflash->window_size;
+-
+-		break;
+-	default:
+-		bcma_err(bus, "Flash type not supported\n");
+-	}
+-
+-	if (cc->core->id.rev == 38 ||
+-	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+-		if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
+-			bcma_debug(bus, "Found NAND flash\n");
+-			bcma_nflash_init(cc);
+-		}
+-	}
+-
+ 	/* Determine flash type this SoC boots from */
+ 	boot_dev = bcma_boot_dev(bus);
+ 	switch (boot_dev) {
+@@ -328,13 +269,10 @@ static void bcma_core_mips_flash_detect(
+ 
+ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
+ {
+-	struct bcma_bus *bus = mcore->core->bus;
+-
+ 	if (mcore->early_setup_done)
+ 		return;
+ 
+-	bcma_chipco_serial_init(&bus->drv_cc);
+-	bcma_core_mips_flash_detect(mcore);
++	bcma_core_mips_nvram_init(mcore);
+ 
+ 	mcore->early_setup_done = true;
+ }
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -294,7 +294,7 @@ static const struct pci_device_id bcma_p
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
+ 
+ 	  If unsure, say N
+ 
++config BCMA_PFLASH
++	bool
++	depends on BCMA_DRIVER_MIPS
++	default y
++
+ config BCMA_SFLASH
+ 	bool
+ 	depends on BCMA_DRIVER_MIPS
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -1,6 +1,7 @@
+ bcma-y					+= main.o scan.o core.o sprom.o
+ bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
+ bcma-y					+= driver_chipcommon_b.o
++bcma-$(CONFIG_BCMA_PFLASH)		+= driver_chipcommon_pflash.o
+ bcma-$(CONFIG_BCMA_SFLASH)		+= driver_chipcommon_sflash.o
+ bcma-$(CONFIG_BCMA_NFLASH)		+= driver_chipcommon_nflash.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI)		+= driver_pci.o
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_pflash.c
+@@ -0,0 +1,49 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon parallel flash
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data bcma_pflash_data = {
++	.part_probe_types	= part_probes,
++};
++
++static struct resource bcma_pflash_resource = {
++	.name	= "bcma_pflash",
++	.flags  = IORESOURCE_MEM,
++};
++
++struct platform_device bcma_pflash_dev = {
++	.name		= "physmap-flash",
++	.dev		= {
++		.platform_data  = &bcma_pflash_data,
++	},
++	.resource	= &bcma_pflash_resource,
++	.num_resources	= 1,
++};
++
++int bcma_pflash_init(struct bcma_drv_cc *cc)
++{
++	struct bcma_pflash *pflash = &cc->pflash;
++
++	pflash->present = true;
++
++	if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
++		bcma_pflash_data.width = 1;
++	else
++		bcma_pflash_data.width = 2;
++
++	bcma_pflash_resource.start = BCMA_SOC_FLASH2;
++	bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
++
++	return 0;
++}
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -325,7 +325,7 @@ static int bcma_register_devices(struct
+ 		bcma_register_core(bus, core);
+ 	}
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ 	if (bus->drv_cc.pflash.present) {
+ 		err = platform_device_register(&bcma_pflash_dev);
+ 		if (err)
diff --git a/target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch b/target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch
new file mode 100644
index 0000000000..b2d53f9f8a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/040-mtd-bcm47xxpart-backports-from-3.19.patch
@@ -0,0 +1,50 @@
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -15,8 +15,12 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ 
+-/* 10 parts were found on sflash on Netgear WNDR4500 */
+-#define BCM47XXPART_MAX_PARTS		12
++/*
++ * NAND flash on Netgear R6250 was verified to contain 15 partitions.
++ * This will result in allocating too big array for some old devices, but the
++ * memory will be freed soon anyway (see mtd_device_parse_register).
++ */
++#define BCM47XXPART_MAX_PARTS		20
+ 
+ /*
+  * Amount of bytes we read when analyzing each block of flash memory.
+@@ -168,18 +172,26 @@ static int bcm47xxpart_parse(struct mtd_
+ 				i++;
+ 			}
+ 
+-			bcm47xxpart_add_part(&parts[curr_part++], "linux",
+-					     offset + trx->offset[i], 0);
+-			i++;
++			if (trx->offset[i]) {
++				bcm47xxpart_add_part(&parts[curr_part++],
++						     "linux",
++						     offset + trx->offset[i],
++						     0);
++				i++;
++			}
+ 
+ 			/*
+ 			 * Pure rootfs size is known and can be calculated as:
+ 			 * trx->length - trx->offset[i]. We don't fill it as
+ 			 * we want to have jffs2 (overlay) in the same mtd.
+ 			 */
+-			bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
+-					     offset + trx->offset[i], 0);
+-			i++;
++			if (trx->offset[i]) {
++				bcm47xxpart_add_part(&parts[curr_part++],
++						     "rootfs",
++						     offset + trx->offset[i],
++						     0);
++				i++;
++			}
+ 
+ 			last_trx_part = curr_part - 1;
+ 
diff --git a/target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch b/target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch
new file mode 100644
index 0000000000..59180c2084
--- /dev/null
+++ b/target/linux/generic/patches-3.18/041-mtd-bcm47xxpart-backports-from-3.20.patch
@@ -0,0 +1,95 @@
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -15,6 +15,8 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ 
++#include <uapi/linux/magic.h>
++
+ /*
+  * NAND flash on Netgear R6250 was verified to contain 15 partitions.
+  * This will result in allocating too big array for some old devices, but the
+@@ -39,7 +41,8 @@
+ #define ML_MAGIC1			0x39685a42
+ #define ML_MAGIC2			0x26594131
+ #define TRX_MAGIC			0x30524448
+-#define SQSH_MAGIC			0x71736873	/* shsq */
++#define SHSQ_MAGIC			0x71736873	/* shsq (weird ZTE H218N endianness) */
++#define UBI_EC_MAGIC			0x23494255	/* UBI# */
+ 
+ struct trx_header {
+ 	uint32_t magic;
+@@ -50,7 +53,7 @@ struct trx_header {
+ 	uint32_t offset[3];
+ } __packed;
+ 
+-static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
++static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
+ 				 u64 offset, uint32_t mask_flags)
+ {
+ 	part->name = name;
+@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct
+ 	part->mask_flags = mask_flags;
+ }
+ 
++static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
++						  size_t offset)
++{
++	uint32_t buf;
++	size_t bytes_read;
++
++	if (mtd_read(master, offset, sizeof(buf), &bytes_read,
++		     (uint8_t *)&buf) < 0) {
++		pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
++			offset);
++		goto out_default;
++	}
++
++	if (buf == UBI_EC_MAGIC)
++		return "ubi";
++
++out_default:
++	return "rootfs";
++}
++
+ static int bcm47xxpart_parse(struct mtd_info *master,
+ 			     struct mtd_partition **pparts,
+ 			     struct mtd_part_parser_data *data)
+@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_
+ 	int last_trx_part = -1;
+ 	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
+ 
+-	if (blocksize <= 0x10000)
+-		blocksize = 0x10000;
++	/*
++	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
++	 * partitions were aligned to at least 0x1000 anyway.
++	 */
++	if (blocksize < 0x1000)
++		blocksize = 0x1000;
+ 
+ 	/* Alloc */
+ 	parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
+@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 			 * we want to have jffs2 (overlay) in the same mtd.
+ 			 */
+ 			if (trx->offset[i]) {
++				const char *name;
++
++				name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "rootfs",
++						     name,
+ 						     offset + trx->offset[i],
+ 						     0);
+ 				i++;
+@@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Squashfs on devices not using TRX */
+-		if (buf[0x000 / 4] == SQSH_MAGIC) {
++		if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
++		    buf[0x000 / 4] == SHSQ_MAGIC) {
+ 			bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
+ 					     offset, 0);
+ 			continue;
diff --git a/target/linux/generic/patches-3.18/043-mtd_GD25Q128B_support_backport_from_3.19.patch b/target/linux/generic/patches-3.18/043-mtd_GD25Q128B_support_backport_from_3.19.patch
new file mode 100644
index 0000000000..b7bae34aa7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/043-mtd_GD25Q128B_support_backport_from_3.19.patch
@@ -0,0 +1,15 @@
+mtd: spi-nor: support for (GigaDevice) GD25Q128B
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -510,6 +510,7 @@ static const struct spi_device_id spi_no
+ 	/* GigaDevice */
+ 	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
+ 	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
++	{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
+ 
+ 	/* Intel/Numonyx -- xxxs33b */
+ 	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
diff --git a/target/linux/generic/patches-3.18/044-backport-m25p80-jedec-probe.patch b/target/linux/generic/patches-3.18/044-backport-m25p80-jedec-probe.patch
new file mode 100644
index 0000000000..41b912d5d4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/044-backport-m25p80-jedec-probe.patch
@@ -0,0 +1,39 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -310,11 +310,21 @@ static const struct spi_device_id m25p_i
+ };
+ MODULE_DEVICE_TABLE(spi, m25p_ids);
+ 
++static const struct of_device_id m25p_of_table[] = {
++	/*
++	 * Generic compatibility for SPI NOR that can be identified by the
++	 * JEDEC READ ID opcode (0x9F). Use this, if possible.
++	 */
++	{ .compatible = "jedec,spi-nor" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, m25p_of_table);
+ 
+ static struct spi_driver m25p80_driver = {
+ 	.driver = {
+ 		.name	= "m25p80",
+ 		.owner	= THIS_MODULE,
++		.of_match_table = m25p_of_table,
+ 	},
+ 	.id_table	= m25p_ids,
+ 	.probe	= m25p_probe,
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -927,8 +927,11 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	if (ret)
+ 		return ret;
+ 
+-	id = spi_nor_match_id(name);
++	if (name)
++		id = spi_nor_match_id(name);
+ 	if (!id)
++		id = nor->read_id(nor);
++	if (IS_ERR_OR_NULL(id))
+ 		return -ENOENT;
+ 
+ 	info = (void *)id->driver_data;
diff --git a/target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch b/target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch
new file mode 100644
index 0000000000..9f23db6a79
--- /dev/null
+++ b/target/linux/generic/patches-3.18/050-backport_netfilter_rtcache.patch
@@ -0,0 +1,509 @@
+Subject: netfilter: conntrack: cache route for forwarded connections
+
+... to avoid per-packet FIB lookup if possible.
+
+The cached dst is re-used provided the input interface
+is the same as that of the previous packet in the same direction.
+
+If not, the cached dst is invalidated.
+
+For ipv6 we also need to store sernum, else dst_check doesn't work,
+pointed out by Eric Dumazet.
+
+This should speed up forwarding when conntrack is already in use
+anyway, especially when using reverse path filtering -- active RPF
+enforces two FIB lookups for each packet.
+
+Before the routing cache removal this didn't matter since RPF was performed
+only when route cache didn't yield a result; but without route cache it
+comes at higher price.
+
+Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
+avoid holding on to dsts of 'frozen' conntracks.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+
+--- a/include/net/netfilter/nf_conntrack_extend.h
++++ b/include/net/netfilter/nf_conntrack_extend.h
+@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
+ #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
+ 	NF_CT_EXT_SYNPROXY,
+ #endif
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++	NF_CT_EXT_RTCACHE,
++#endif
+ 	NF_CT_EXT_NUM,
+ };
+ 
+@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
+ #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+ #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
+ #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
+ 
+ /* Extensions: optional stuff which isn't permanently in struct. */
+ struct nf_ct_ext {
+--- /dev/null
++++ b/include/net/netfilter/nf_conntrack_rtcache.h
+@@ -0,0 +1,34 @@
++#include <linux/gfp.h>
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++
++struct dst_entry;
++
++struct nf_conn_dst_cache {
++	struct dst_entry *dst;
++	int iif;
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	u32 cookie;
++#endif
++
++};
++
++struct nf_conn_rtcache {
++	struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
++};
++
++static inline
++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++	return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
++#else
++	return NULL;
++#endif
++}
++
++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
++					  enum ip_conntrack_dir dir)
++{
++	return rtc->cached_dst[dir].iif;
++}
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS
+ 
+ 	  If unsure, say `N'.
+ 
++config NF_CONNTRACK_RTCACHE
++	tristate "Cache route entries in conntrack objects"
++	depends on NETFILTER_ADVANCED
++	depends on NF_CONNTRACK
++	help
++	  If this option is enabled, the connection tracking code will
++	  cache routing information for each connection that is being
++	  forwarded, at a cost of 32 bytes per conntrack object.
++
++	  To compile it as a module, choose M here.  If unsure, say N.
++	  The module will be called nf_conntrack_rtcache.
++
+ config NF_CONNTRACK_TIMEOUT
+ 	bool  'Connection tracking timeout'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
+ # connection tracking
+ obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
+ 
++# optional conntrack route cache extension
++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
++
+ # SCTP protocol connection tracking
+ obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
+ obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
+--- /dev/null
++++ b/net/netfilter/nf_conntrack_rtcache.c
+@@ -0,0 +1,391 @@
++/* route cache for netfilter.
++ *
++ * (C) 2014 Red Hat GmbH
++ *
++ * 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.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/types.h>
++#include <linux/netfilter.h>
++#include <linux/skbuff.h>
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/export.h>
++#include <linux/module.h>
++
++#include <net/dst.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++#include <net/netfilter/nf_conntrack_rtcache.h>
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++#include <net/ip6_fib.h>
++#endif
++
++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
++				      enum ip_conntrack_dir dir)
++{
++	struct dst_entry *dst = rtc->cached_dst[dir].dst;
++
++	dst_release(dst);
++}
++
++static void nf_conn_rtcache_destroy(struct nf_conn *ct)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++	if (!rtc)
++		return;
++
++	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
++	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
++}
++
++static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
++{
++	struct nf_conn_rtcache *rtc;
++
++	rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
++	if (rtc) {
++		rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
++		rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
++		rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
++		rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
++	}
++}
++
++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
++{
++	if (nf_ct_is_untracked(ct))
++		return NULL;
++	return nf_ct_rtcache_find(ct);
++}
++
++static struct dst_entry *
++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
++			enum ip_conntrack_dir dir)
++{
++	return rtc->cached_dst[dir].dst;
++}
++
++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	if (pf == NFPROTO_IPV6) {
++		const struct rt6_info *rt = (const struct rt6_info *)dst;
++
++		if (rt->rt6i_node)
++			return (u32)rt->rt6i_node->fn_sernum;
++	}
++#endif
++	return 0;
++}
++
++static void nf_conn_rtcache_dst_set(int pf,
++				    struct nf_conn_rtcache *rtc,
++				    struct dst_entry *dst,
++				    enum ip_conntrack_dir dir, int iif)
++{
++	if (rtc->cached_dst[dir].iif != iif)
++		rtc->cached_dst[dir].iif = iif;
++
++	if (rtc->cached_dst[dir].dst != dst) {
++		struct dst_entry *old;
++
++		dst_hold(dst);
++
++		old = xchg(&rtc->cached_dst[dir].dst, dst);
++		dst_release(old);
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++		if (pf == NFPROTO_IPV6)
++			rtc->cached_dst[dir].cookie =
++				nf_rtcache_get_cookie(pf, dst);
++#endif
++	}
++}
++
++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
++					 enum ip_conntrack_dir dir)
++{
++	struct dst_entry *old;
++
++	pr_debug("Invalidate iif %d for dir %d on cache %p\n",
++		 rtc->cached_dst[dir].iif, dir, rtc);
++
++	old = xchg(&rtc->cached_dst[dir].dst, NULL);
++	dst_release(old);
++	rtc->cached_dst[dir].iif = -1;
++}
++
++static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops,
++				  struct sk_buff *skb,
++				  const struct net_device *in,
++				  const struct net_device *out,
++				  int (*okfn)(struct sk_buff *))
++{
++	struct nf_conn_rtcache *rtc;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct dst_entry *dst;
++	struct nf_conn *ct;
++	int iif;
++	u32 cookie;
++
++	if (skb_dst(skb) || skb->sk)
++		return NF_ACCEPT;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return NF_ACCEPT;
++
++	rtc = nf_ct_rtcache_find_usable(ct);
++	if (!rtc)
++		return NF_ACCEPT;
++
++	/* if iif changes, don't use cache and let ip stack
++	 * do route lookup.
++	 *
++	 * If rp_filter is enabled it might toss skb, so
++	 * we don't want to avoid these checks.
++	 */
++	dir = CTINFO2DIR(ctinfo);
++	iif = nf_conn_rtcache_iif_get(rtc, dir);
++	if (in->ifindex != iif) {
++		pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
++			 ct, iif, in->ifindex);
++		return NF_ACCEPT;
++	}
++	dst = nf_conn_rtcache_dst_get(rtc, dir);
++	if (dst == NULL)
++		return NF_ACCEPT;
++
++	cookie = nf_rtcache_get_cookie(ops->pf, dst);
++
++	dst = dst_check(dst, cookie);
++	pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
++	if (likely(dst))
++		skb_dst_set_noref_force(skb, dst);
++	else
++		nf_conn_rtcache_dst_obsolete(rtc, dir);
++
++	return NF_ACCEPT;
++}
++
++static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops,
++				       struct sk_buff *skb,
++				       const struct net_device *in,
++				       const struct net_device *out,
++				       int (*okfn)(struct sk_buff *))
++{
++	struct nf_conn_rtcache *rtc;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct nf_conn *ct;
++	struct dst_entry *dst = skb_dst(skb);
++	int iif;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return NF_ACCEPT;
++
++	if (dst && dst_xfrm(dst))
++		return NF_ACCEPT;
++
++	if (!nf_ct_is_confirmed(ct)) {
++		if (WARN_ON(nf_ct_rtcache_find(ct)))
++			return NF_ACCEPT;
++		nf_ct_rtcache_ext_add(ct);
++		return NF_ACCEPT;
++	}
++
++	rtc = nf_ct_rtcache_find_usable(ct);
++	if (!rtc)
++		return NF_ACCEPT;
++
++	dir = CTINFO2DIR(ctinfo);
++	iif = nf_conn_rtcache_iif_get(rtc, dir);
++	pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
++		 ct, skb, dir, iif, in->ifindex);
++	if (likely(in->ifindex == iif))
++		return NF_ACCEPT;
++
++	nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, in->ifindex);
++	return NF_ACCEPT;
++}
++
++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++	struct net_device *dev = data;
++
++	if (!rtc)
++		return 0;
++
++	if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
++	    dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
++		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
++		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
++	}
++
++	return 0;
++}
++
++static int nf_rtcache_netdev_event(struct notifier_block *this,
++				   unsigned long event, void *ptr)
++{
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++	struct net *net = dev_net(dev);
++
++	if (event == NETDEV_DOWN)
++		nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
++
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block nf_rtcache_notifier = {
++	.notifier_call = nf_rtcache_netdev_event,
++};
++
++static struct nf_hook_ops rtcache_ops[] = {
++	{
++		.hook		= nf_rtcache_in,
++		.owner		= THIS_MODULE,
++		.pf		= NFPROTO_IPV4,
++		.hooknum	= NF_INET_PRE_ROUTING,
++		.priority       = NF_IP_PRI_LAST,
++	},
++	{
++		.hook           = nf_rtcache_forward,
++		.owner          = THIS_MODULE,
++		.pf             = NFPROTO_IPV4,
++		.hooknum        = NF_INET_FORWARD,
++		.priority       = NF_IP_PRI_LAST,
++	},
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	{
++		.hook		= nf_rtcache_in,
++		.owner		= THIS_MODULE,
++		.pf		= NFPROTO_IPV6,
++		.hooknum	= NF_INET_PRE_ROUTING,
++		.priority       = NF_IP_PRI_LAST,
++	},
++	{
++		.hook           = nf_rtcache_forward,
++		.owner          = THIS_MODULE,
++		.pf             = NFPROTO_IPV6,
++		.hooknum        = NF_INET_FORWARD,
++		.priority       = NF_IP_PRI_LAST,
++	},
++#endif
++};
++
++static struct nf_ct_ext_type rtcache_extend __read_mostly = {
++	.len	= sizeof(struct nf_conn_rtcache),
++	.align	= __alignof__(struct nf_conn_rtcache),
++	.id	= NF_CT_EXT_RTCACHE,
++	.destroy = nf_conn_rtcache_destroy,
++};
++
++static int __init nf_conntrack_rtcache_init(void)
++{
++	int ret = nf_ct_extend_register(&rtcache_extend);
++
++	if (ret < 0) {
++		pr_err("nf_conntrack_rtcache: Unable to register extension\n");
++		return ret;
++	}
++
++	ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++	if (ret < 0) {
++		nf_ct_extend_unregister(&rtcache_extend);
++		return ret;
++	}
++
++	ret = register_netdevice_notifier(&nf_rtcache_notifier);
++	if (ret) {
++		nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++		nf_ct_extend_unregister(&rtcache_extend);
++	}
++
++	return ret;
++}
++
++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++	return rtc != NULL;
++}
++
++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
++{
++	bool wait = false;
++	int cpu;
++
++	for_each_possible_cpu(cpu) {
++		struct nf_conntrack_tuple_hash *h;
++		struct hlist_nulls_node *n;
++		struct nf_conn *ct;
++		struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
++
++		rcu_read_lock();
++		spin_lock_bh(&pcpu->lock);
++
++		hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
++			ct = nf_ct_tuplehash_to_ctrack(h);
++			if (nf_ct_rtcache_find(ct) != NULL) {
++				wait = true;
++				break;
++			}
++		}
++		spin_unlock_bh(&pcpu->lock);
++		rcu_read_unlock();
++	}
++
++	return wait;
++}
++
++static void __exit nf_conntrack_rtcache_fini(void)
++{
++	struct net *net;
++	int count = 0;
++
++	/* remove hooks so no new connections get rtcache extension */
++	nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++
++	synchronize_net();
++
++	unregister_netdevice_notifier(&nf_rtcache_notifier);
++
++	rtnl_lock();
++
++	/* zap all conntracks with rtcache extension */
++	for_each_net(net)
++		nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
++
++	for_each_net(net) {
++		/* .. and make sure they're gone from dying list, too */
++		while (nf_conntrack_rtcache_wait_for_dying(net)) {
++			msleep(200);
++			WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
++		}
++	}
++
++	rtnl_unlock();
++	synchronize_net();
++	nf_ct_extend_unregister(&rtcache_extend);
++}
++module_init(nf_conntrack_rtcache_init);
++module_exit(nf_conntrack_rtcache_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
++MODULE_DESCRIPTION("Conntrack route cache extension");
diff --git a/target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch b/target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch
new file mode 100644
index 0000000000..f7f88f8134
--- /dev/null
+++ b/target/linux/generic/patches-3.18/051-02-bridge-allow-setting-hash_max-multicast_router-if-in.patch
@@ -0,0 +1,99 @@
+From 6ae4ae8e512bd229f806c22f8a2cd751e4f987c2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
+Date: Sat, 23 May 2015 03:12:34 +0200
+Subject: [PATCH] bridge: allow setting hash_max + multicast_router if
+ interface is down
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Network managers like netifd (used in OpenWRT for instance) try to
+configure interface options after creation but before setting the
+interface up.
+
+Unfortunately the sysfs / bridge currently only allows to configure the
+hash_max and multicast_router options when the bridge interface is up.
+But since br_multicast_init() doesn't start any timers and only sets
+default values and initializes timers it should be save to reconfigure
+the default values after that, before things actually get active after
+the bridge is set up.
+
+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/bridge/br_multicast.c |   24 +++---------------------
+ 1 file changed, 3 insertions(+), 21 deletions(-)
+
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -1948,11 +1948,9 @@ out:
+ 
+ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
+ {
+-	int err = -ENOENT;
++	int err = -EINVAL;
+ 
+ 	spin_lock_bh(&br->multicast_lock);
+-	if (!netif_running(br->dev))
+-		goto unlock;
+ 
+ 	switch (val) {
+ 	case 0:
+@@ -1963,13 +1961,8 @@ int br_multicast_set_router(struct net_b
+ 		br->multicast_router = val;
+ 		err = 0;
+ 		break;
+-
+-	default:
+-		err = -EINVAL;
+-		break;
+ 	}
+ 
+-unlock:
+ 	spin_unlock_bh(&br->multicast_lock);
+ 
+ 	return err;
+@@ -1978,11 +1971,9 @@ unlock:
+ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
+ {
+ 	struct net_bridge *br = p->br;
+-	int err = -ENOENT;
++	int err = -EINVAL;
+ 
+ 	spin_lock(&br->multicast_lock);
+-	if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
+-		goto unlock;
+ 
+ 	switch (val) {
+ 	case 0:
+@@ -2004,13 +1995,8 @@ int br_multicast_set_port_router(struct
+ 
+ 		br_multicast_add_router(br, p);
+ 		break;
+-
+-	default:
+-		err = -EINVAL;
+-		break;
+ 	}
+ 
+-unlock:
+ 	spin_unlock(&br->multicast_lock);
+ 
+ 	return err;
+@@ -2115,15 +2101,11 @@ unlock:
+ 
+ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
+ {
+-	int err = -ENOENT;
++	int err = -EINVAL;
+ 	u32 old;
+ 	struct net_bridge_mdb_htable *mdb;
+ 
+ 	spin_lock_bh(&br->multicast_lock);
+-	if (!netif_running(br->dev))
+-		goto unlock;
+-
+-	err = -EINVAL;
+ 	if (!is_power_of_2(val))
+ 		goto unlock;
+ 
diff --git a/target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch b/target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch
new file mode 100644
index 0000000000..d215b80ab2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/060-mips_decompressor_memmove.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/boot/compressed/string.c
++++ b/arch/mips/boot/compressed/string.c
+@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
+ 		ss[i] = c;
+ 	return s;
+ }
++
++void *memmove(void *__dest, __const void *__src, size_t count)
++{
++	unsigned char *d = __dest;
++	const unsigned char *s = __src;
++
++	if (__dest == __src)
++		return __dest;
++
++	if (__dest < __src)
++		return memcpy(__dest, __src, count);
++
++	while (count--)
++		d[count] = s[count];
++	return __dest;
++}
diff --git a/target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch b/target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch
new file mode 100644
index 0000000000..aa45860e93
--- /dev/null
+++ b/target/linux/generic/patches-3.18/070-bgmac-register-napi-before-the-device.patch
@@ -0,0 +1,44 @@
+From 6216642f200258708e47170ff14ba8ecb486f4f0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 Jan 2015 19:49:58 +0100
+Subject: [PATCH] bgmac: register napi before the device
+
+napi should get registered before the netdev and not after.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1515,6 +1515,8 @@ static int bgmac_probe(struct bcma_devic
+ 	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+ 		bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+ 
++	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
++
+ 	err = bgmac_mii_register(bgmac);
+ 	if (err) {
+ 		bgmac_err(bgmac, "Cannot register MDIO\n");
+@@ -1529,8 +1531,6 @@ static int bgmac_probe(struct bcma_devic
+ 
+ 	netif_carrier_off(net_dev);
+ 
+-	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+-
+ 	return 0;
+ 
+ err_mii_unregister:
+@@ -1549,9 +1549,9 @@ static void bgmac_remove(struct bcma_dev
+ {
+ 	struct bgmac *bgmac = bcma_get_drvdata(core);
+ 
+-	netif_napi_del(&bgmac->napi);
+ 	unregister_netdev(bgmac->net_dev);
+ 	bgmac_mii_unregister(bgmac);
++	netif_napi_del(&bgmac->napi);
+ 	bgmac_dma_free(bgmac);
+ 	bcma_set_drvdata(core, NULL);
+ 	free_netdev(bgmac->net_dev);
diff --git a/target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch b/target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch
new file mode 100644
index 0000000000..cc43d367cc
--- /dev/null
+++ b/target/linux/generic/patches-3.18/071-bgmac-activate-irqs-only-if-there-is-nothing-to-poll.patch
@@ -0,0 +1,30 @@
+From 43f159c60a99318b1ef7d1d7c16c4dfdd06bfd90 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 Jan 2015 19:49:59 +0100
+Subject: [PATCH] bgmac: activate irqs only if there is nothing to poll
+
+IRQs should only get activated when there is nothing to poll in the
+queue any more and to after every poll.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct
+ 		bgmac->int_status = 0;
+ 	}
+ 
+-	if (handled < weight)
++	if (handled < weight) {
+ 		napi_complete(napi);
+-
+-	bgmac_chip_intrs_on(bgmac);
++		bgmac_chip_intrs_on(bgmac);
++	}
+ 
+ 	return handled;
+ }
diff --git a/target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch b/target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch
new file mode 100644
index 0000000000..121d2f4122
--- /dev/null
+++ b/target/linux/generic/patches-3.18/072-bgmac-fix-device-initialization-on-Northstar-SoCs-co.patch
@@ -0,0 +1,40 @@
+From 21697336d46b71dd031f29e426dda0b1e7f06cc0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 11 Feb 2015 18:06:34 +0100
+Subject: [PATCH] bgmac: fix device initialization on Northstar SoCs (condition
+ typo)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On Northstar (Broadcom's ARM architecture) we need to manually enable
+all cores. Code for that is already in place, but the condition for it
+was wrong.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1412,6 +1412,7 @@ static void bgmac_mii_unregister(struct
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+ static int bgmac_probe(struct bcma_device *core)
+ {
++	struct bcma_chipinfo *ci = &core->bus->chipinfo;
+ 	struct net_device *net_dev;
+ 	struct bgmac *bgmac;
+ 	struct ssb_sprom *sprom = &core->bus->sprom;
+@@ -1474,8 +1475,8 @@ static int bgmac_probe(struct bcma_devic
+ 	bgmac_chip_reset(bgmac);
+ 
+ 	/* For Northstar, we have to take all GMAC core out of reset */
+-	if (core->id.id == BCMA_CHIP_ID_BCM4707 ||
+-	    core->id.id == BCMA_CHIP_ID_BCM53018) {
++	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
++	    ci->id == BCMA_CHIP_ID_BCM53018) {
+ 		struct bcma_device *ns_core;
+ 		int ns_gmac;
+ 
diff --git a/target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch b/target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch
new file mode 100644
index 0000000000..17fe5dff5e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/073-bgmac-Clean-warning-messages.patch
@@ -0,0 +1,50 @@
+From 8edfe3b6fad28da191c8fa15e4e0d8f7335a0091 Mon Sep 17 00:00:00 2001
+From: Peter Senna Tschudin <peter.senna@gmail.com>
+Date: Sat, 7 Mar 2015 12:10:26 +0100
+Subject: [PATCH] bgmac: Clean warning messages
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On my test environment the throughput of a file transfer drops
+from 4.4MBps to 116KBps due the number of repeated warning
+messages. This patch removes the warning messages as DMA works
+correctly with addresses using 0xC0000000 bits.
+
+Signed-off-by: Peter Senna Tschudin <peter.senna@gmail.com>
+Acked-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -302,9 +302,6 @@ static int bgmac_dma_rx_skb_for_slot(str
+ 	slot->skb = skb;
+ 	slot->dma_addr = dma_addr;
+ 
+-	if (slot->dma_addr & 0xC0000000)
+-		bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+-
+ 	return 0;
+ }
+ 
+@@ -505,8 +502,6 @@ static int bgmac_dma_alloc(struct bgmac
+ 				  ring->mmio_base);
+ 			goto err_dma_free;
+ 		}
+-		if (ring->dma_base & 0xC0000000)
+-			bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+ 
+ 		ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
+ 						      BGMAC_DMA_RING_TX);
+@@ -536,8 +531,6 @@ static int bgmac_dma_alloc(struct bgmac
+ 			err = -ENOMEM;
+ 			goto err_dma_free;
+ 		}
+-		if (ring->dma_base & 0xC0000000)
+-			bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+ 
+ 		ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
+ 						      BGMAC_DMA_RING_RX);
diff --git a/target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch b/target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch
new file mode 100644
index 0000000000..9f0baff0ee
--- /dev/null
+++ b/target/linux/generic/patches-3.18/074-bgmac-register-fixed-PHY-for-ARM-BCM470X-BCM5301X-ch.patch
@@ -0,0 +1,76 @@
+From c25b23b8a387e7d31f7a74af8e37b61e9e6ebb21 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 20 Mar 2015 23:14:31 +0100
+Subject: [PATCH] bgmac: register fixed PHY for ARM BCM470X / BCM5301X chipsets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On ARM SoCs with bgmac Ethernet hardware we don't have any normal PHY.
+There is always a switch attached but it's not even controlled over MDIO
+like in case of MIPS devices.
+We need a fixed PHY to be able to send/receive packets from the switch.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 34 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -14,6 +14,7 @@
+ #include <linux/etherdevice.h>
+ #include <linux/mii.h>
+ #include <linux/phy.h>
++#include <linux/phy_fixed.h>
+ #include <linux/interrupt.h>
+ #include <linux/dma-mapping.h>
+ #include <bcm47xx_nvram.h>
+@@ -1330,13 +1331,46 @@ static void bgmac_adjust_link(struct net
+ 	}
+ }
+ 
++static int bgmac_fixed_phy_register(struct bgmac *bgmac)
++{
++	struct fixed_phy_status fphy_status = {
++		.link = 1,
++		.speed = SPEED_1000,
++		.duplex = DUPLEX_FULL,
++	};
++	struct phy_device *phy_dev;
++	int err;
++
++	phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
++	if (!phy_dev || IS_ERR(phy_dev)) {
++		bgmac_err(bgmac, "Failed to register fixed PHY device\n");
++		return -ENODEV;
++	}
++
++	err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
++				 PHY_INTERFACE_MODE_MII);
++	if (err) {
++		bgmac_err(bgmac, "Connecting PHY failed\n");
++		return err;
++	}
++
++	bgmac->phy_dev = phy_dev;
++
++	return err;
++}
++
+ static int bgmac_mii_register(struct bgmac *bgmac)
+ {
++	struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+ 	struct mii_bus *mii_bus;
+ 	struct phy_device *phy_dev;
+ 	char bus_id[MII_BUS_ID_SIZE + 3];
+ 	int i, err = 0;
+ 
++	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
++	    ci->id == BCMA_CHIP_ID_BCM53018)
++		return bgmac_fixed_phy_register(bgmac);
++
+ 	mii_bus = mdiobus_alloc();
+ 	if (!mii_bus)
+ 		return -ENOMEM;
diff --git a/target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch b/target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch
new file mode 100644
index 0000000000..4513667e3a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/075-bgmac-allow-enabling-on-ARCH_BCM_5301X.patch
@@ -0,0 +1,28 @@
+From fc300dc3733fdc328e6e10c7b8379b60c26cd648 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 20 Mar 2015 23:14:32 +0100
+Subject: [PATCH] bgmac: allow enabling on ARCH_BCM_5301X
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Home routers based on ARM SoCs like BCM4708 also have bcma bus with core
+supported by bgmac.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/Kconfig
++++ b/drivers/net/ethernet/broadcom/Kconfig
+@@ -143,7 +143,7 @@ config BNX2X_SRIOV
+ 
+ config BGMAC
+ 	tristate "BCMA bus GBit core support"
+-	depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
++	depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X)
+ 	select PHYLIB
+ 	---help---
+ 	  This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
diff --git a/target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch b/target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch
new file mode 100644
index 0000000000..939016c2e8
--- /dev/null
+++ b/target/linux/generic/patches-3.18/076-net-phy-export-fixed_phy_register.patch
@@ -0,0 +1,30 @@
+From 37e9a6904520b525b542ecd67201164d06fdb95a Mon Sep 17 00:00:00 2001
+From: Mark Salter <msalter@redhat.com>
+Date: Thu, 11 Dec 2014 23:03:26 -0500
+Subject: [PATCH] net: phy: export fixed_phy_register()
+
+When building the bcmgenet driver as module, I get:
+
+ERROR: "fixed_phy_register" [drivers/net/ethernet/broadcom/genet/genet.ko] undefined!
+
+commit b0ba512e225d72 ("net: bcmgenet: enable driver to work without device
+tree") which added a call to fixed_phy_register. But fixed_phy_register
+needs to be exported if used from a module.
+
+Signed-off-by: Mark Salter <msalter@redhat.com>
+Acked-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/fixed.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/phy/fixed.c
++++ b/drivers/net/phy/fixed.c
+@@ -274,6 +274,7 @@ struct phy_device *fixed_phy_register(un
+ 
+ 	return phy;
+ }
++EXPORT_SYMBOL_GPL(fixed_phy_register);
+ 
+ static int __init fixed_mdio_bus_init(void)
+ {
diff --git a/target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch b/target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch
new file mode 100644
index 0000000000..fe8a602160
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-01-bgmac-fix-descriptor-frame-start-end-definitions.patch
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 23 Mar 2015 02:40:06 +0100
+Subject: [PATCH] bgmac: fix descriptor frame start/end definitions
+
+The start-of-frame and end-of-frame bits were accidentally swapped.
+In the current code it does not make any difference, since they are
+always used together.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -345,8 +345,8 @@
+ 
+ #define BGMAC_DESC_CTL0_EOT			0x10000000	/* End of ring */
+ #define BGMAC_DESC_CTL0_IOC			0x20000000	/* IRQ on complete */
+-#define BGMAC_DESC_CTL0_SOF			0x40000000	/* Start of frame */
+-#define BGMAC_DESC_CTL0_EOF			0x80000000	/* End of frame */
++#define BGMAC_DESC_CTL0_EOF			0x40000000	/* End of frame */
++#define BGMAC_DESC_CTL0_SOF			0x80000000	/* Start of frame */
+ #define BGMAC_DESC_CTL1_LEN			0x00001FFF
+ 
+ #define BGMAC_PHY_NOREGS			0x1E
diff --git a/target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch b/target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch
new file mode 100644
index 0000000000..8dc5242b5a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-02-bgmac-implement-GRO-and-use-build_skb.patch
@@ -0,0 +1,189 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 23 Mar 2015 02:41:25 +0100
+Subject: [PATCH] bgmac: implement GRO and use build_skb
+
+This improves performance for routing and local rx
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -276,31 +276,31 @@ static int bgmac_dma_rx_skb_for_slot(str
+ 				     struct bgmac_slot_info *slot)
+ {
+ 	struct device *dma_dev = bgmac->core->dma_dev;
+-	struct sk_buff *skb;
+ 	dma_addr_t dma_addr;
+ 	struct bgmac_rx_header *rx;
++	void *buf;
+ 
+ 	/* Alloc skb */
+-	skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
+-	if (!skb)
++	buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE);
++	if (!buf)
+ 		return -ENOMEM;
+ 
+ 	/* Poison - if everything goes fine, hardware will overwrite it */
+-	rx = (struct bgmac_rx_header *)skb->data;
++	rx = buf;
+ 	rx->len = cpu_to_le16(0xdead);
+ 	rx->flags = cpu_to_le16(0xbeef);
+ 
+ 	/* Map skb for the DMA */
+-	dma_addr = dma_map_single(dma_dev, skb->data,
+-				  BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
++	dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
++				  DMA_FROM_DEVICE);
+ 	if (dma_mapping_error(dma_dev, dma_addr)) {
+ 		bgmac_err(bgmac, "DMA mapping error\n");
+-		dev_kfree_skb(skb);
++		put_page(virt_to_head_page(buf));
+ 		return -ENOMEM;
+ 	}
+ 
+ 	/* Update the slot */
+-	slot->skb = skb;
++	slot->buf = buf;
+ 	slot->dma_addr = dma_addr;
+ 
+ 	return 0;
+@@ -343,8 +343,9 @@ static int bgmac_dma_rx_read(struct bgma
+ 	while (ring->start != ring->end) {
+ 		struct device *dma_dev = bgmac->core->dma_dev;
+ 		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+-		struct sk_buff *skb = slot->skb;
+-		struct bgmac_rx_header *rx;
++		struct bgmac_rx_header *rx = slot->buf;
++		struct sk_buff *skb;
++		void *buf = slot->buf;
+ 		u16 len, flags;
+ 
+ 		/* Unmap buffer to make it accessible to the CPU */
+@@ -352,7 +353,6 @@ static int bgmac_dma_rx_read(struct bgma
+ 					BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+ 
+ 		/* Get info from the header */
+-		rx = (struct bgmac_rx_header *)skb->data;
+ 		len = le16_to_cpu(rx->len);
+ 		flags = le16_to_cpu(rx->flags);
+ 
+@@ -393,12 +393,13 @@ static int bgmac_dma_rx_read(struct bgma
+ 			dma_unmap_single(dma_dev, old_dma_addr,
+ 					 BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+ 
++			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+ 			skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
+ 			skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
+ 
+ 			skb_checksum_none_assert(skb);
+ 			skb->protocol = eth_type_trans(skb, bgmac->net_dev);
+-			netif_receive_skb(skb);
++			napi_gro_receive(&bgmac->napi, skb);
+ 			handled++;
+ 		} while (0);
+ 
+@@ -434,12 +435,11 @@ static bool bgmac_dma_unaligned(struct b
+ 	return false;
+ }
+ 
+-static void bgmac_dma_ring_free(struct bgmac *bgmac,
+-				struct bgmac_dma_ring *ring)
++static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
++				   struct bgmac_dma_ring *ring)
+ {
+ 	struct device *dma_dev = bgmac->core->dma_dev;
+ 	struct bgmac_slot_info *slot;
+-	int size;
+ 	int i;
+ 
+ 	for (i = 0; i < ring->num_slots; i++) {
+@@ -451,23 +451,55 @@ static void bgmac_dma_ring_free(struct b
+ 			dev_kfree_skb(slot->skb);
+ 		}
+ 	}
++}
++
++static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
++				   struct bgmac_dma_ring *ring)
++{
++	struct device *dma_dev = bgmac->core->dma_dev;
++	struct bgmac_slot_info *slot;
++	int i;
++
++	for (i = 0; i < ring->num_slots; i++) {
++		slot = &ring->slots[i];
++		if (!slot->buf)
++			continue;
+ 
+-	if (ring->cpu_base) {
+-		/* Free ring of descriptors */
+-		size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+-		dma_free_coherent(dma_dev, size, ring->cpu_base,
+-				  ring->dma_base);
++		if (slot->dma_addr)
++			dma_unmap_single(dma_dev, slot->dma_addr,
++					 BGMAC_RX_BUF_SIZE,
++					 DMA_FROM_DEVICE);
++		put_page(virt_to_head_page(slot->buf));
+ 	}
+ }
+ 
++static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
++				     struct bgmac_dma_ring *ring)
++{
++	struct device *dma_dev = bgmac->core->dma_dev;
++	int size;
++
++	if (!ring->cpu_base)
++	    return;
++
++	/* Free ring of descriptors */
++	size = ring->num_slots * sizeof(struct bgmac_dma_desc);
++	dma_free_coherent(dma_dev, size, ring->cpu_base,
++			  ring->dma_base);
++}
++
+ static void bgmac_dma_free(struct bgmac *bgmac)
+ {
+ 	int i;
+ 
+-	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+-		bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
+-	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+-		bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
++	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
++		bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
++		bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
++	}
++	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
++		bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
++		bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
++	}
+ }
+ 
+ static int bgmac_dma_alloc(struct bgmac *bgmac)
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -362,6 +362,8 @@
+ #define BGMAC_RX_FRAME_OFFSET			30		/* There are 2 unused bytes between header and real data */
+ #define BGMAC_RX_MAX_FRAME_SIZE			1536		/* Copied from b44/tg3 */
+ #define BGMAC_RX_BUF_SIZE			(BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
++#define BGMAC_RX_ALLOC_SIZE			(SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
++						 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+ 
+ #define BGMAC_BFL_ENETROBO			0x0010		/* has ephy roboswitch spi */
+ #define BGMAC_BFL_ENETADM			0x0080		/* has ADMtek switch */
+@@ -383,7 +385,10 @@
+ #define ETHER_MAX_LEN   1518
+ 
+ struct bgmac_slot_info {
+-	struct sk_buff *skb;
++	union {
++		struct sk_buff *skb;
++		void *buf;
++	};
+ 	dma_addr_t dma_addr;
+ };
+ 
diff --git a/target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch b/target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch
new file mode 100644
index 0000000000..ceb25e85ad
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-03-bgmac-implement-scatter-gather-support.patch
@@ -0,0 +1,267 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 23 Mar 2015 02:42:26 +0100
+Subject: [PATCH] bgmac: implement scatter/gather support
+
+Always use software checksumming, since the hardware does not have any
+checksum offload support.
+This significantly improves local TCP tx performance.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -115,53 +115,91 @@ static void bgmac_dma_tx_enable(struct b
+ 	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
+ }
+ 
++static void
++bgmac_dma_tx_add_buf(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
++		     int i, int len, u32 ctl0)
++{
++	struct bgmac_slot_info *slot;
++	struct bgmac_dma_desc *dma_desc;
++	u32 ctl1;
++
++	if (i == ring->num_slots - 1)
++		ctl0 |= BGMAC_DESC_CTL0_EOT;
++
++	ctl1 = len & BGMAC_DESC_CTL1_LEN;
++
++	slot = &ring->slots[i];
++	dma_desc = &ring->cpu_base[i];
++	dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
++	dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
++	dma_desc->ctl0 = cpu_to_le32(ctl0);
++	dma_desc->ctl1 = cpu_to_le32(ctl1);
++}
++
+ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
+ 				    struct bgmac_dma_ring *ring,
+ 				    struct sk_buff *skb)
+ {
+ 	struct device *dma_dev = bgmac->core->dma_dev;
+ 	struct net_device *net_dev = bgmac->net_dev;
+-	struct bgmac_dma_desc *dma_desc;
+-	struct bgmac_slot_info *slot;
+-	u32 ctl0, ctl1;
++	struct bgmac_slot_info *slot = &ring->slots[ring->end];
+ 	int free_slots;
++	int nr_frags;
++	u32 flags;
++	int index = ring->end;
++	int i;
+ 
+ 	if (skb->len > BGMAC_DESC_CTL1_LEN) {
+ 		bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
+-		goto err_stop_drop;
++		goto err_drop;
+ 	}
+ 
++	if (skb->ip_summed == CHECKSUM_PARTIAL)
++		skb_checksum_help(skb);
++
++	nr_frags = skb_shinfo(skb)->nr_frags;
++
+ 	if (ring->start <= ring->end)
+ 		free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
+ 	else
+ 		free_slots = ring->start - ring->end;
+-	if (free_slots == 1) {
++
++	if (free_slots <= nr_frags + 1) {
+ 		bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
+ 		netif_stop_queue(net_dev);
+ 		return NETDEV_TX_BUSY;
+ 	}
+ 
+-	slot = &ring->slots[ring->end];
+-	slot->skb = skb;
+-	slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len,
++	slot->dma_addr = dma_map_single(dma_dev, skb->data, skb_headlen(skb),
+ 					DMA_TO_DEVICE);
+-	if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+-		bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
+-			  ring->mmio_base);
+-		goto err_stop_drop;
+-	}
++	if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
++		goto err_dma_head;
+ 
+-	ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF;
+-	if (ring->end == ring->num_slots - 1)
+-		ctl0 |= BGMAC_DESC_CTL0_EOT;
+-	ctl1 = skb->len & BGMAC_DESC_CTL1_LEN;
++	flags = BGMAC_DESC_CTL0_SOF;
++	if (!nr_frags)
++		flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
++
++	bgmac_dma_tx_add_buf(bgmac, ring, index, skb_headlen(skb), flags);
++	flags = 0;
++
++	for (i = 0; i < nr_frags; i++) {
++		struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
++		int len = skb_frag_size(frag);
++
++		index = (index + 1) % BGMAC_TX_RING_SLOTS;
++		slot = &ring->slots[index];
++		slot->dma_addr = skb_frag_dma_map(dma_dev, frag, 0,
++						  len, DMA_TO_DEVICE);
++		if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
++			goto err_dma;
+ 
+-	dma_desc = ring->cpu_base;
+-	dma_desc += ring->end;
+-	dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
+-	dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
+-	dma_desc->ctl0 = cpu_to_le32(ctl0);
+-	dma_desc->ctl1 = cpu_to_le32(ctl1);
++		if (i == nr_frags - 1)
++			flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
++
++		bgmac_dma_tx_add_buf(bgmac, ring, index, len, flags);
++	}
++
++	slot->skb = skb;
+ 
+ 	netdev_sent_queue(net_dev, skb->len);
+ 
+@@ -170,20 +208,35 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 	/* Increase ring->end to point empty slot. We tell hardware the first
+ 	 * slot it should *not* read.
+ 	 */
+-	if (++ring->end >= BGMAC_TX_RING_SLOTS)
+-		ring->end = 0;
++	ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
+ 	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
+ 		    ring->index_base +
+ 		    ring->end * sizeof(struct bgmac_dma_desc));
+ 
+-	/* Always keep one slot free to allow detecting bugged calls. */
+-	if (--free_slots == 1)
++	free_slots -= nr_frags + 1;
++	if (free_slots < 8)
+ 		netif_stop_queue(net_dev);
+ 
+ 	return NETDEV_TX_OK;
+ 
+-err_stop_drop:
+-	netif_stop_queue(net_dev);
++err_dma:
++	dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
++			 DMA_TO_DEVICE);
++
++	while (i > 0) {
++		int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
++		struct bgmac_slot_info *slot = &ring->slots[index];
++		u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
++		int len = ctl1 & BGMAC_DESC_CTL1_LEN;
++
++		dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE);
++	}
++
++err_dma_head:
++	bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
++		  ring->mmio_base);
++
++err_drop:
+ 	dev_kfree_skb(skb);
+ 	return NETDEV_TX_OK;
+ }
+@@ -205,32 +258,45 @@ static void bgmac_dma_tx_free(struct bgm
+ 
+ 	while (ring->start != empty_slot) {
+ 		struct bgmac_slot_info *slot = &ring->slots[ring->start];
++		u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
++		int len = ctl1 & BGMAC_DESC_CTL1_LEN;
+ 
+-		if (slot->skb) {
++		if (!slot->dma_addr) {
++			bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
++				  ring->start, ring->end);
++			goto next;
++		}
++
++		if (ctl1 & BGMAC_DESC_CTL0_SOF)
+ 			/* Unmap no longer used buffer */
+-			dma_unmap_single(dma_dev, slot->dma_addr,
+-					 slot->skb->len, DMA_TO_DEVICE);
+-			slot->dma_addr = 0;
++			dma_unmap_single(dma_dev, slot->dma_addr, len,
++					 DMA_TO_DEVICE);
++		else
++			dma_unmap_page(dma_dev, slot->dma_addr, len,
++				       DMA_TO_DEVICE);
+ 
++		if (slot->skb) {
+ 			bytes_compl += slot->skb->len;
+ 			pkts_compl++;
+ 
+ 			/* Free memory! :) */
+ 			dev_kfree_skb(slot->skb);
+ 			slot->skb = NULL;
+-		} else {
+-			bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
+-				  ring->start, ring->end);
+ 		}
+ 
++next:
++		slot->dma_addr = 0;
+ 		if (++ring->start >= BGMAC_TX_RING_SLOTS)
+ 			ring->start = 0;
+ 		freed = true;
+ 	}
+ 
++	if (!pkts_compl)
++		return;
++
+ 	netdev_completed_queue(bgmac->net_dev, pkts_compl, bytes_compl);
+ 
+-	if (freed && netif_queue_stopped(bgmac->net_dev))
++	if (netif_queue_stopped(bgmac->net_dev))
+ 		netif_wake_queue(bgmac->net_dev);
+ }
+ 
+@@ -439,17 +505,25 @@ static void bgmac_dma_tx_ring_free(struc
+ 				   struct bgmac_dma_ring *ring)
+ {
+ 	struct device *dma_dev = bgmac->core->dma_dev;
++	struct bgmac_dma_desc *dma_desc = ring->cpu_base;
+ 	struct bgmac_slot_info *slot;
+ 	int i;
+ 
+ 	for (i = 0; i < ring->num_slots; i++) {
++		int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
++
+ 		slot = &ring->slots[i];
+-		if (slot->skb) {
+-			if (slot->dma_addr)
+-				dma_unmap_single(dma_dev, slot->dma_addr,
+-						 slot->skb->len, DMA_TO_DEVICE);
+-			dev_kfree_skb(slot->skb);
+-		}
++		dev_kfree_skb(slot->skb);
++
++		if (!slot->dma_addr)
++			continue;
++
++		if (slot->skb)
++			dma_unmap_single(dma_dev, slot->dma_addr,
++					 len, DMA_TO_DEVICE);
++		else
++			dma_unmap_page(dma_dev, slot->dma_addr,
++				       len, DMA_TO_DEVICE);
+ 	}
+ }
+ 
+@@ -1583,6 +1657,10 @@ static int bgmac_probe(struct bcma_devic
+ 		goto err_dma_free;
+ 	}
+ 
++	net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++	net_dev->hw_features = net_dev->features;
++	net_dev->vlan_features = net_dev->features;
++
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+ 		bgmac_err(bgmac, "Cannot register net device\n");
diff --git a/target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch b/target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch
new file mode 100644
index 0000000000..bf4a22dbea
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-04-bgmac-simplify-tx-ring-index-handling.patch
@@ -0,0 +1,125 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 09:58:56 +0200
+Subject: [PATCH] bgmac: simplify tx ring index handling
+
+Keep incrementing ring->start and ring->end instead of pointing it to
+the actual ring slot entry. This simplifies the calculation of the
+number of free slots.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ {
+ 	struct device *dma_dev = bgmac->core->dma_dev;
+ 	struct net_device *net_dev = bgmac->net_dev;
+-	struct bgmac_slot_info *slot = &ring->slots[ring->end];
+-	int free_slots;
++	int index = ring->end % BGMAC_TX_RING_SLOTS;
++	struct bgmac_slot_info *slot = &ring->slots[index];
+ 	int nr_frags;
+ 	u32 flags;
+-	int index = ring->end;
+ 	int i;
+ 
+ 	if (skb->len > BGMAC_DESC_CTL1_LEN) {
+@@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 
+ 	nr_frags = skb_shinfo(skb)->nr_frags;
+ 
+-	if (ring->start <= ring->end)
+-		free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
+-	else
+-		free_slots = ring->start - ring->end;
+-
+-	if (free_slots <= nr_frags + 1) {
++	/* ring->end - ring->start will return the number of valid slots,
++	 * even when ring->end overflows
++	 */
++	if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
+ 		bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
+ 		netif_stop_queue(net_dev);
+ 		return NETDEV_TX_BUSY;
+@@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 	}
+ 
+ 	slot->skb = skb;
+-
++	ring->end += nr_frags + 1;
+ 	netdev_sent_queue(net_dev, skb->len);
+ 
+ 	wmb();
+@@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 	/* Increase ring->end to point empty slot. We tell hardware the first
+ 	 * slot it should *not* read.
+ 	 */
+-	ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
+ 	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
+ 		    ring->index_base +
+-		    ring->end * sizeof(struct bgmac_dma_desc));
++		    (ring->end % BGMAC_TX_RING_SLOTS) *
++		    sizeof(struct bgmac_dma_desc));
+ 
+-	free_slots -= nr_frags + 1;
+-	if (free_slots < 8)
++	if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8)
+ 		netif_stop_queue(net_dev);
+ 
+ 	return NETDEV_TX_OK;
+@@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgm
+ 	empty_slot &= BGMAC_DMA_TX_STATDPTR;
+ 	empty_slot /= sizeof(struct bgmac_dma_desc);
+ 
+-	while (ring->start != empty_slot) {
+-		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+-		u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
+-		int len = ctl1 & BGMAC_DESC_CTL1_LEN;
++	while (ring->start != ring->end) {
++		int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
++		struct bgmac_slot_info *slot = &ring->slots[slot_idx];
++		u32 ctl1;
++		int len;
+ 
+-		if (!slot->dma_addr) {
+-			bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
+-				  ring->start, ring->end);
+-			goto next;
+-		}
++		if (slot_idx == empty_slot)
++			break;
+ 
++		ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
++		len = ctl1 & BGMAC_DESC_CTL1_LEN;
+ 		if (ctl1 & BGMAC_DESC_CTL0_SOF)
+ 			/* Unmap no longer used buffer */
+ 			dma_unmap_single(dma_dev, slot->dma_addr, len,
+@@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgm
+ 			slot->skb = NULL;
+ 		}
+ 
+-next:
+ 		slot->dma_addr = 0;
+-		if (++ring->start >= BGMAC_TX_RING_SLOTS)
+-			ring->start = 0;
++		ring->start++;
+ 		freed = true;
+ 	}
+ 
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -414,10 +414,10 @@ enum bgmac_dma_ring_type {
+  * empty.
+  */
+ struct bgmac_dma_ring {
+-	u16 num_slots;
+-	u16 start;
+-	u16 end;
++	u32 start;
++	u32 end;
+ 
++	u16 num_slots;
+ 	u16 mmio_base;
+ 	struct bgmac_dma_desc *cpu_base;
+ 	dma_addr_t dma_base;
diff --git a/target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch b/target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch
new file mode 100644
index 0000000000..4e5e2e720a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-05-bgmac-leave-interrupts-disabled-as-long-as-there-is-.patch
@@ -0,0 +1,87 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 10:08:04 +0200
+Subject: [PATCH] bgmac: leave interrupts disabled as long as there is work
+ to do
+
+Always poll rx and tx during NAPI poll instead of relying on the status
+of the first interrupt. This prevents bgmac_poll from leaving unfinished
+work around until the next IRQ.
+In my tests this makes bridging/routing throughput under heavy load more
+stable and ensures that no new IRQs arrive as long as bgmac_poll uses up
+the entire budget.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1109,8 +1109,6 @@ static void bgmac_chip_reset(struct bgma
+ 	bgmac_phy_init(bgmac);
+ 
+ 	netdev_reset_queue(bgmac->net_dev);
+-
+-	bgmac->int_status = 0;
+ }
+ 
+ static void bgmac_chip_intrs_on(struct bgmac *bgmac)
+@@ -1225,14 +1223,13 @@ static irqreturn_t bgmac_interrupt(int i
+ 	if (!int_status)
+ 		return IRQ_NONE;
+ 
+-	/* Ack */
+-	bgmac_write(bgmac, BGMAC_INT_STATUS, int_status);
++	int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX);
++	if (int_status)
++		bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status);
+ 
+ 	/* Disable new interrupts until handling existing ones */
+ 	bgmac_chip_intrs_off(bgmac);
+ 
+-	bgmac->int_status = int_status;
+-
+ 	napi_schedule(&bgmac->napi);
+ 
+ 	return IRQ_HANDLED;
+@@ -1241,25 +1238,17 @@ static irqreturn_t bgmac_interrupt(int i
+ static int bgmac_poll(struct napi_struct *napi, int weight)
+ {
+ 	struct bgmac *bgmac = container_of(napi, struct bgmac, napi);
+-	struct bgmac_dma_ring *ring;
+ 	int handled = 0;
+ 
+-	if (bgmac->int_status & BGMAC_IS_TX0) {
+-		ring = &bgmac->tx_ring[0];
+-		bgmac_dma_tx_free(bgmac, ring);
+-		bgmac->int_status &= ~BGMAC_IS_TX0;
+-	}
++	/* Ack */
++	bgmac_write(bgmac, BGMAC_INT_STATUS, ~0);
+ 
+-	if (bgmac->int_status & BGMAC_IS_RX) {
+-		ring = &bgmac->rx_ring[0];
+-		handled += bgmac_dma_rx_read(bgmac, ring, weight);
+-		bgmac->int_status &= ~BGMAC_IS_RX;
+-	}
++	bgmac_dma_tx_free(bgmac, &bgmac->tx_ring[0]);
++	handled += bgmac_dma_rx_read(bgmac, &bgmac->rx_ring[0], weight);
+ 
+-	if (bgmac->int_status) {
+-		bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status);
+-		bgmac->int_status = 0;
+-	}
++	/* Poll again if more events arrived in the meantime */
++	if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX))
++		return handled;
+ 
+ 	if (handled < weight) {
+ 		napi_complete(napi);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -452,7 +452,6 @@ struct bgmac {
+ 
+ 	/* Int */
+ 	u32 int_mask;
+-	u32 int_status;
+ 
+ 	/* Current MAC state */
+ 	int mac_speed;
diff --git a/target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch b/target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch
new file mode 100644
index 0000000000..1b0742cd3a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-06-bgmac-set-received-skb-headroom-to-NET_SKB_PAD.patch
@@ -0,0 +1,66 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 10:13:28 +0200
+Subject: [PATCH] bgmac: set received skb headroom to NET_SKB_PAD
+
+A packet buffer offset of 30 bytes is inefficient, because the first 2
+bytes end up in a different cacheline.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -346,13 +346,13 @@ static int bgmac_dma_rx_skb_for_slot(str
+ 		return -ENOMEM;
+ 
+ 	/* Poison - if everything goes fine, hardware will overwrite it */
+-	rx = buf;
++	rx = buf + BGMAC_RX_BUF_OFFSET;
+ 	rx->len = cpu_to_le16(0xdead);
+ 	rx->flags = cpu_to_le16(0xbeef);
+ 
+ 	/* Map skb for the DMA */
+-	dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
+-				  DMA_FROM_DEVICE);
++	dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET,
++				  BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+ 	if (dma_mapping_error(dma_dev, dma_addr)) {
+ 		bgmac_err(bgmac, "DMA mapping error\n");
+ 		put_page(virt_to_head_page(buf));
+@@ -403,7 +403,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 	while (ring->start != ring->end) {
+ 		struct device *dma_dev = bgmac->core->dma_dev;
+ 		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+-		struct bgmac_rx_header *rx = slot->buf;
++		struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
+ 		struct sk_buff *skb;
+ 		void *buf = slot->buf;
+ 		u16 len, flags;
+@@ -454,8 +454,10 @@ static int bgmac_dma_rx_read(struct bgma
+ 					 BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+ 
+ 			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+-			skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
+-			skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
++			skb_put(skb, BGMAC_RX_FRAME_OFFSET +
++				BGMAC_RX_BUF_OFFSET + len);
++			skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
++				 BGMAC_RX_BUF_OFFSET);
+ 
+ 			skb_checksum_none_assert(skb);
+ 			skb->protocol = eth_type_trans(skb, bgmac->net_dev);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -360,9 +360,11 @@
+ 
+ #define BGMAC_RX_HEADER_LEN			28		/* Last 24 bytes are unused. Well... */
+ #define BGMAC_RX_FRAME_OFFSET			30		/* There are 2 unused bytes between header and real data */
++#define BGMAC_RX_BUF_OFFSET			(NET_SKB_PAD + NET_IP_ALIGN - \
++						 BGMAC_RX_FRAME_OFFSET)
+ #define BGMAC_RX_MAX_FRAME_SIZE			1536		/* Copied from b44/tg3 */
+ #define BGMAC_RX_BUF_SIZE			(BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
+-#define BGMAC_RX_ALLOC_SIZE			(SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
++#define BGMAC_RX_ALLOC_SIZE			(SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE + BGMAC_RX_BUF_OFFSET) + \
+ 						 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+ 
+ #define BGMAC_BFL_ENETROBO			0x0010		/* has ephy roboswitch spi */
diff --git a/target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch b/target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch
new file mode 100644
index 0000000000..2be65b4544
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-07-bgmac-simplify-rx-DMA-error-handling.patch
@@ -0,0 +1,130 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 22:23:07 +0200
+Subject: [PATCH] bgmac: simplify/optimize rx DMA error handling
+
+Allocate a new buffer before processing the completed one. If allocation
+fails, reuse the old buffer.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -386,6 +386,19 @@ static void bgmac_dma_rx_setup_desc(stru
+ 	dma_desc->ctl1 = cpu_to_le32(ctl1);
+ }
+ 
++static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
++				    struct bgmac_slot_info *slot)
++{
++	struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
++
++	dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
++				DMA_FROM_DEVICE);
++	rx->len = cpu_to_le16(0xdead);
++	rx->flags = cpu_to_le16(0xbeef);
++	dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
++				   DMA_FROM_DEVICE);
++}
++
+ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
+ 			     int weight)
+ {
+@@ -406,53 +419,35 @@ static int bgmac_dma_rx_read(struct bgma
+ 		struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
+ 		struct sk_buff *skb;
+ 		void *buf = slot->buf;
++		dma_addr_t dma_addr = slot->dma_addr;
+ 		u16 len, flags;
+ 
+-		/* Unmap buffer to make it accessible to the CPU */
+-		dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
+-					BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+-
+-		/* Get info from the header */
+-		len = le16_to_cpu(rx->len);
+-		flags = le16_to_cpu(rx->flags);
+-
+ 		do {
+-			dma_addr_t old_dma_addr = slot->dma_addr;
+-			int err;
++			/* Prepare new skb as replacement */
++			if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) {
++				bgmac_dma_rx_poison_buf(dma_dev, slot);
++				break;
++			}
++
++			/* Unmap buffer to make it accessible to the CPU */
++			dma_unmap_single(dma_dev, dma_addr,
++					 BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
++
++			/* Get info from the header */
++			len = le16_to_cpu(rx->len);
++			flags = le16_to_cpu(rx->flags);
+ 
+ 			/* Check for poison and drop or pass the packet */
+ 			if (len == 0xdead && flags == 0xbeef) {
+ 				bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+ 					  ring->start);
+-				dma_sync_single_for_device(dma_dev,
+-							   slot->dma_addr,
+-							   BGMAC_RX_BUF_SIZE,
+-							   DMA_FROM_DEVICE);
++				put_page(virt_to_head_page(buf));
+ 				break;
+ 			}
+ 
+ 			/* Omit CRC. */
+ 			len -= ETH_FCS_LEN;
+ 
+-			/* Prepare new skb as replacement */
+-			err = bgmac_dma_rx_skb_for_slot(bgmac, slot);
+-			if (err) {
+-				/* Poison the old skb */
+-				rx->len = cpu_to_le16(0xdead);
+-				rx->flags = cpu_to_le16(0xbeef);
+-
+-				dma_sync_single_for_device(dma_dev,
+-							   slot->dma_addr,
+-							   BGMAC_RX_BUF_SIZE,
+-							   DMA_FROM_DEVICE);
+-				break;
+-			}
+-			bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
+-
+-			/* Unmap old skb, we'll pass it to the netfif */
+-			dma_unmap_single(dma_dev, old_dma_addr,
+-					 BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+-
+ 			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+ 			skb_put(skb, BGMAC_RX_FRAME_OFFSET +
+ 				BGMAC_RX_BUF_OFFSET + len);
+@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma
+ 			handled++;
+ 		} while (0);
+ 
++		bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
++
+ 		if (++ring->start >= BGMAC_RX_RING_SLOTS)
+ 			ring->start = 0;
+ 
+@@ -532,14 +529,14 @@ static void bgmac_dma_rx_ring_free(struc
+ 
+ 	for (i = 0; i < ring->num_slots; i++) {
+ 		slot = &ring->slots[i];
+-		if (!slot->buf)
++		if (!slot->dma_addr)
+ 			continue;
+ 
+-		if (slot->dma_addr)
+-			dma_unmap_single(dma_dev, slot->dma_addr,
+-					 BGMAC_RX_BUF_SIZE,
+-					 DMA_FROM_DEVICE);
++		dma_unmap_single(dma_dev, slot->dma_addr,
++				 BGMAC_RX_BUF_SIZE,
++				 DMA_FROM_DEVICE);
+ 		put_page(virt_to_head_page(slot->buf));
++		slot->dma_addr = 0;
+ 	}
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch b/target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch
new file mode 100644
index 0000000000..6bb4747686
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-08-bgmac-add-check-for-oversized-packets.patch
@@ -0,0 +1,27 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 22:28:20 +0200
+Subject: [PATCH] bgmac: add check for oversized packets
+
+In very rare cases, the MAC can catch an internal buffer that is bigger
+than it's supposed to be. Instead of crashing the kernel, simply pass
+the buffer back to the hardware
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -445,6 +445,13 @@ static int bgmac_dma_rx_read(struct bgma
+ 				break;
+ 			}
+ 
++			if (len > BGMAC_RX_ALLOC_SIZE) {
++				bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
++					  ring->start);
++				put_page(virt_to_head_page(buf));
++				break;
++			}
++
+ 			/* Omit CRC. */
+ 			len -= ETH_FCS_LEN;
+ 
diff --git a/target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch b/target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch
new file mode 100644
index 0000000000..1fc4ed03f1
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-09-bgmac-increase-rx-ring-size-from-511-to-512.patch
@@ -0,0 +1,23 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 22:36:16 +0200
+Subject: [PATCH] bgmac: increase rx ring size from 511 to 512
+
+Limiting it to 511 looks like a failed attempt at leaving one descriptor
+empty to allow the hardware to stop processing a buffer that has not
+been prepared yet. However, this doesn't work because this affects the
+total ring size as well
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -356,7 +356,7 @@
+ #define BGMAC_MAX_RX_RINGS			1
+ 
+ #define BGMAC_TX_RING_SLOTS			128
+-#define BGMAC_RX_RING_SLOTS			512 - 1		/* Why -1? Well, Broadcom does that... */
++#define BGMAC_RX_RING_SLOTS			512
+ 
+ #define BGMAC_RX_HEADER_LEN			28		/* Last 24 bytes are unused. Well... */
+ #define BGMAC_RX_FRAME_OFFSET			30		/* There are 2 unused bytes between header and real data */
diff --git a/target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch b/target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch
new file mode 100644
index 0000000000..a49bd5f5e7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-10-bgmac-simplify-dma-init-cleanup.patch
@@ -0,0 +1,184 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 23:19:32 +0200
+Subject: [PATCH] bgmac: simplify dma init/cleanup
+
+Instead of allocating buffers at device init time and initializing
+descriptors at device open, do both at the same time (during open).
+Free all buffers when closing the device.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -562,18 +562,26 @@ static void bgmac_dma_ring_desc_free(str
+ 			  ring->dma_base);
+ }
+ 
+-static void bgmac_dma_free(struct bgmac *bgmac)
++static void bgmac_dma_cleanup(struct bgmac *bgmac)
+ {
+ 	int i;
+ 
+-	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
++	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+ 		bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
+-		bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
+-	}
+-	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
++
++	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+ 		bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
++}
++
++static void bgmac_dma_free(struct bgmac *bgmac)
++{
++	int i;
++
++	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
++		bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
++
++	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+ 		bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
+-	}
+ }
+ 
+ static int bgmac_dma_alloc(struct bgmac *bgmac)
+@@ -621,8 +629,6 @@ static int bgmac_dma_alloc(struct bgmac
+ 	}
+ 
+ 	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+-		int j;
+-
+ 		ring = &bgmac->rx_ring[i];
+ 		ring->num_slots = BGMAC_RX_RING_SLOTS;
+ 		ring->mmio_base = ring_base[i];
+@@ -645,15 +651,6 @@ static int bgmac_dma_alloc(struct bgmac
+ 			ring->index_base = lower_32_bits(ring->dma_base);
+ 		else
+ 			ring->index_base = 0;
+-
+-		/* Alloc RX slots */
+-		for (j = 0; j < ring->num_slots; j++) {
+-			err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
+-			if (err) {
+-				bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n");
+-				goto err_dma_free;
+-			}
+-		}
+ 	}
+ 
+ 	return 0;
+@@ -663,10 +660,10 @@ err_dma_free:
+ 	return -ENOMEM;
+ }
+ 
+-static void bgmac_dma_init(struct bgmac *bgmac)
++static int bgmac_dma_init(struct bgmac *bgmac)
+ {
+ 	struct bgmac_dma_ring *ring;
+-	int i;
++	int i, err;
+ 
+ 	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+ 		ring = &bgmac->tx_ring[i];
+@@ -698,8 +695,13 @@ static void bgmac_dma_init(struct bgmac
+ 		if (ring->unaligned)
+ 			bgmac_dma_rx_enable(bgmac, ring);
+ 
+-		for (j = 0; j < ring->num_slots; j++)
++		for (j = 0; j < ring->num_slots; j++) {
++			err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
++			if (err)
++				goto error;
++
+ 			bgmac_dma_rx_setup_desc(bgmac, ring, j);
++		}
+ 
+ 		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
+ 			    ring->index_base +
+@@ -708,6 +710,12 @@ static void bgmac_dma_init(struct bgmac
+ 		ring->start = 0;
+ 		ring->end = 0;
+ 	}
++
++	return 0;
++
++error:
++	bgmac_dma_cleanup(bgmac);
++	return err;
+ }
+ 
+ /**************************************************
+@@ -1183,11 +1191,8 @@ static void bgmac_enable(struct bgmac *b
+ }
+ 
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
+-static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
++static void bgmac_chip_init(struct bgmac *bgmac)
+ {
+-	struct bgmac_dma_ring *ring;
+-	int i;
+-
+ 	/* 1 interrupt per received frame */
+ 	bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
+ 
+@@ -1205,16 +1210,7 @@ static void bgmac_chip_init(struct bgmac
+ 
+ 	bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
+ 
+-	if (full_init) {
+-		bgmac_dma_init(bgmac);
+-		if (1) /* FIXME: is there any case we don't want IRQs? */
+-			bgmac_chip_intrs_on(bgmac);
+-	} else {
+-		for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+-			ring = &bgmac->rx_ring[i];
+-			bgmac_dma_rx_enable(bgmac, ring);
+-		}
+-	}
++	bgmac_chip_intrs_on(bgmac);
+ 
+ 	bgmac_enable(bgmac);
+ }
+@@ -1274,23 +1270,27 @@ static int bgmac_open(struct net_device
+ 	int err = 0;
+ 
+ 	bgmac_chip_reset(bgmac);
++
++	err = bgmac_dma_init(bgmac);
++	if (err)
++		return err;
++
+ 	/* Specs say about reclaiming rings here, but we do that in DMA init */
+-	bgmac_chip_init(bgmac, true);
++	bgmac_chip_init(bgmac);
+ 
+ 	err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
+ 			  KBUILD_MODNAME, net_dev);
+ 	if (err < 0) {
+ 		bgmac_err(bgmac, "IRQ request error: %d!\n", err);
+-		goto err_out;
++		bgmac_dma_cleanup(bgmac);
++		return err;
+ 	}
+ 	napi_enable(&bgmac->napi);
+ 
+ 	phy_start(bgmac->phy_dev);
+ 
+ 	netif_carrier_on(net_dev);
+-
+-err_out:
+-	return err;
++	return 0;
+ }
+ 
+ static int bgmac_stop(struct net_device *net_dev)
+@@ -1306,6 +1306,7 @@ static int bgmac_stop(struct net_device
+ 	free_irq(bgmac->core->irq, net_dev);
+ 
+ 	bgmac_chip_reset(bgmac);
++	bgmac_dma_cleanup(bgmac);
+ 
+ 	return 0;
+ }
diff --git a/target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch b/target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch
new file mode 100644
index 0000000000..e7a7987f43
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-11-bgmac-fix-DMA-rx-corruption.patch
@@ -0,0 +1,88 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 11:59:47 +0200
+Subject: [PATCH] bgmac: fix DMA rx corruption
+
+The driver needs to inform the hardware about the first invalid (not yet
+filled) rx slot, by writing its DMA descriptor pointer offset to the
+BGMAC_DMA_RX_INDEX register.
+
+This register was set to a value exceeding the rx ring size, effectively
+allowing the hardware constant access to the full ring, regardless of
+which slots are initialized.
+
+To fix this issue, always mark the last filled rx slot as invalid.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -366,6 +366,16 @@ static int bgmac_dma_rx_skb_for_slot(str
+ 	return 0;
+ }
+ 
++static void bgmac_dma_rx_update_index(struct bgmac *bgmac,
++				      struct bgmac_dma_ring *ring)
++{
++	wmb();
++
++	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
++		    ring->index_base +
++		    ring->end * sizeof(struct bgmac_dma_desc));
++}
++
+ static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac,
+ 				    struct bgmac_dma_ring *ring, int desc_idx)
+ {
+@@ -384,6 +394,8 @@ static void bgmac_dma_rx_setup_desc(stru
+ 	dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr));
+ 	dma_desc->ctl0 = cpu_to_le32(ctl0);
+ 	dma_desc->ctl1 = cpu_to_le32(ctl1);
++
++	ring->end = desc_idx;
+ }
+ 
+ static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
+@@ -411,9 +423,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 	end_slot &= BGMAC_DMA_RX_STATDPTR;
+ 	end_slot /= sizeof(struct bgmac_dma_desc);
+ 
+-	ring->end = end_slot;
+-
+-	while (ring->start != ring->end) {
++	while (ring->start != end_slot) {
+ 		struct device *dma_dev = bgmac->core->dma_dev;
+ 		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+ 		struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
+@@ -476,6 +486,8 @@ static int bgmac_dma_rx_read(struct bgma
+ 			break;
+ 	}
+ 
++	bgmac_dma_rx_update_index(bgmac, ring);
++
+ 	return handled;
+ }
+ 
+@@ -695,6 +707,8 @@ static int bgmac_dma_init(struct bgmac *
+ 		if (ring->unaligned)
+ 			bgmac_dma_rx_enable(bgmac, ring);
+ 
++		ring->start = 0;
++		ring->end = 0;
+ 		for (j = 0; j < ring->num_slots; j++) {
+ 			err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
+ 			if (err)
+@@ -703,12 +717,7 @@ static int bgmac_dma_init(struct bgmac *
+ 			bgmac_dma_rx_setup_desc(bgmac, ring, j);
+ 		}
+ 
+-		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
+-			    ring->index_base +
+-			    ring->num_slots * sizeof(struct bgmac_dma_desc));
+-
+-		ring->start = 0;
+-		ring->end = 0;
++		bgmac_dma_rx_update_index(bgmac, ring);
+ 	}
+ 
+ 	return 0;
diff --git a/target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch b/target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch
new file mode 100644
index 0000000000..4dbb6f48de
--- /dev/null
+++ b/target/linux/generic/patches-3.18/077-12-bgmac-drop-ring-num_slots.patch
@@ -0,0 +1,132 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 12 Apr 2015 23:28:38 +0200
+Subject: [PATCH] bgmac: drop ring->num_slots
+
+The ring size is always known at compile time, so make the code a bit
+more efficient
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -123,7 +123,7 @@ bgmac_dma_tx_add_buf(struct bgmac *bgmac
+ 	struct bgmac_dma_desc *dma_desc;
+ 	u32 ctl1;
+ 
+-	if (i == ring->num_slots - 1)
++	if (i == BGMAC_TX_RING_SLOTS - 1)
+ 		ctl0 |= BGMAC_DESC_CTL0_EOT;
+ 
+ 	ctl1 = len & BGMAC_DESC_CTL1_LEN;
+@@ -382,7 +382,7 @@ static void bgmac_dma_rx_setup_desc(stru
+ 	struct bgmac_dma_desc *dma_desc = ring->cpu_base + desc_idx;
+ 	u32 ctl0 = 0, ctl1 = 0;
+ 
+-	if (desc_idx == ring->num_slots - 1)
++	if (desc_idx == BGMAC_RX_RING_SLOTS - 1)
+ 		ctl0 |= BGMAC_DESC_CTL0_EOT;
+ 	ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
+ 	/* Is there any BGMAC device that requires extension? */
+@@ -521,7 +521,7 @@ static void bgmac_dma_tx_ring_free(struc
+ 	struct bgmac_slot_info *slot;
+ 	int i;
+ 
+-	for (i = 0; i < ring->num_slots; i++) {
++	for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) {
+ 		int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
+ 
+ 		slot = &ring->slots[i];
+@@ -546,7 +546,7 @@ static void bgmac_dma_rx_ring_free(struc
+ 	struct bgmac_slot_info *slot;
+ 	int i;
+ 
+-	for (i = 0; i < ring->num_slots; i++) {
++	for (i = 0; i < BGMAC_RX_RING_SLOTS; i++) {
+ 		slot = &ring->slots[i];
+ 		if (!slot->dma_addr)
+ 			continue;
+@@ -560,7 +560,8 @@ static void bgmac_dma_rx_ring_free(struc
+ }
+ 
+ static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
+-				     struct bgmac_dma_ring *ring)
++				     struct bgmac_dma_ring *ring,
++				     int num_slots)
+ {
+ 	struct device *dma_dev = bgmac->core->dma_dev;
+ 	int size;
+@@ -569,7 +570,7 @@ static void bgmac_dma_ring_desc_free(str
+ 	    return;
+ 
+ 	/* Free ring of descriptors */
+-	size = ring->num_slots * sizeof(struct bgmac_dma_desc);
++	size = num_slots * sizeof(struct bgmac_dma_desc);
+ 	dma_free_coherent(dma_dev, size, ring->cpu_base,
+ 			  ring->dma_base);
+ }
+@@ -590,10 +591,12 @@ static void bgmac_dma_free(struct bgmac
+ 	int i;
+ 
+ 	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+-		bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
++		bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i],
++					 BGMAC_TX_RING_SLOTS);
+ 
+ 	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+-		bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
++		bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i],
++					 BGMAC_RX_RING_SLOTS);
+ }
+ 
+ static int bgmac_dma_alloc(struct bgmac *bgmac)
+@@ -616,11 +619,10 @@ static int bgmac_dma_alloc(struct bgmac
+ 
+ 	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+ 		ring = &bgmac->tx_ring[i];
+-		ring->num_slots = BGMAC_TX_RING_SLOTS;
+ 		ring->mmio_base = ring_base[i];
+ 
+ 		/* Alloc ring of descriptors */
+-		size = ring->num_slots * sizeof(struct bgmac_dma_desc);
++		size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
+ 		ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+ 						     &ring->dma_base,
+ 						     GFP_KERNEL);
+@@ -642,11 +644,10 @@ static int bgmac_dma_alloc(struct bgmac
+ 
+ 	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+ 		ring = &bgmac->rx_ring[i];
+-		ring->num_slots = BGMAC_RX_RING_SLOTS;
+ 		ring->mmio_base = ring_base[i];
+ 
+ 		/* Alloc ring of descriptors */
+-		size = ring->num_slots * sizeof(struct bgmac_dma_desc);
++		size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
+ 		ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+ 						     &ring->dma_base,
+ 						     GFP_KERNEL);
+@@ -709,7 +710,7 @@ static int bgmac_dma_init(struct bgmac *
+ 
+ 		ring->start = 0;
+ 		ring->end = 0;
+-		for (j = 0; j < ring->num_slots; j++) {
++		for (j = 0; j < BGMAC_RX_RING_SLOTS; j++) {
+ 			err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
+ 			if (err)
+ 				goto error;
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -419,11 +419,10 @@ struct bgmac_dma_ring {
+ 	u32 start;
+ 	u32 end;
+ 
+-	u16 num_slots;
+-	u16 mmio_base;
+ 	struct bgmac_dma_desc *cpu_base;
+ 	dma_addr_t dma_base;
+ 	u32 index_base; /* Used for unaligned rings only, otherwise 0 */
++	u16 mmio_base;
+ 	bool unaligned;
+ 
+ 	struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
diff --git a/target/linux/generic/patches-3.18/078-bgmac-reset-enable-Ethernet-core-before-using-it.patch b/target/linux/generic/patches-3.18/078-bgmac-reset-enable-Ethernet-core-before-using-it.patch
new file mode 100644
index 0000000000..ca061a50d1
--- /dev/null
+++ b/target/linux/generic/patches-3.18/078-bgmac-reset-enable-Ethernet-core-before-using-it.patch
@@ -0,0 +1,31 @@
+From b4dfd8e92956b396d3438212bc9a0be6267b8b34 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 12 Apr 2016 13:30:45 +0200
+Subject: [PATCH] bgmac: reset & enable Ethernet core before using it
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes Ethernet on D-Link DIR-885L with BCM47094 SoC. Felix reported
+similar fix was needed for his BCM4709 device (Buffalo WXR-1900DHP?).
+I tested this for regressions on BCM4706, BCM4708A0 and BCM47081A0.
+
+Cc: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1564,6 +1564,11 @@ static int bgmac_probe(struct bcma_devic
+ 		dev_warn(&core->dev, "Using random MAC: %pM\n", mac);
+ 	}
+ 
++	/* This (reset &) enable is not preset in specs or reference driver but
++	 * Broadcom does it in arch PCI code when enabling fake PCI device.
++	 */
++	bcma_core_enable(core, 0);
++
+ 	/* Allocation and references */
+ 	net_dev = alloc_etherdev(sizeof(*bgmac));
+ 	if (!net_dev)
diff --git a/target/linux/generic/patches-3.18/079-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch b/target/linux/generic/patches-3.18/079-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
new file mode 100644
index 0000000000..f8d0a58769
--- /dev/null
+++ b/target/linux/generic/patches-3.18/079-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
@@ -0,0 +1,34 @@
+From c02bc350f9dbce7d637c394a6e1c4d29dc5b28b2 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 12 Apr 2016 18:27:29 +0200
+Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0. This mainly
+fixes support for BCM4708A0KF SoCs with Ethernet core rev 5 (it means
+only some devices as most of BCM4708A0KF-s got core rev 4).
+This was tested for regressions on BCM47094 which doesn't seem to care
+which bit gets used.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -198,9 +198,9 @@
+ #define  BGMAC_CMDCFG_TAI			0x00000200
+ #define  BGMAC_CMDCFG_HD			0x00000400	/* Set if in half duplex mode */
+ #define  BGMAC_CMDCFG_HD_SHIFT			10
+-#define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for other revs */
+-#define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, only for core rev 4 */
+-#define  BGMAC_CMDCFG_SR(rev)  ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
++#define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for core rev 0-3 */
++#define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, for core rev >= 4 */
++#define  BGMAC_CMDCFG_SR(rev)  ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
+ #define  BGMAC_CMDCFG_ML			0x00008000	/* Set to activate mac loopback mode */
+ #define  BGMAC_CMDCFG_AE			0x00400000
+ #define  BGMAC_CMDCFG_CFE			0x00800000
diff --git a/target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch b/target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch
new file mode 100644
index 0000000000..5d99367ad4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-00-fib_trie-Fix-proc-net-fib_trie-when-CONFIG_IP_MULTIP.patch
@@ -0,0 +1,46 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Tue, 2 Dec 2014 10:58:21 -0800
+Subject: [PATCH] fib_trie: Fix /proc/net/fib_trie when
+ CONFIG_IP_MULTIPLE_TABLES is not defined
+
+In recent testing I had disabled CONFIG_IP_MULTIPLE_TABLES and as a result
+when I ran "cat /proc/net/fib_trie" the main trie was displayed multiple
+times.  I found that the problem line of code was in the function
+fib_trie_seq_next.  Specifically the line below caused the indexes to go in
+the opposite direction of our traversal:
+
+	h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
+
+This issue was that the RT tables are defined such that RT_TABLE_LOCAL is ID
+255, while it is located at TABLE_LOCAL_INDEX of 0, and RT_TABLE_MAIN is 254
+with a TABLE_MAIN_INDEX of 1.  This means that the above line will return 1
+for the local table and 0 for main.  The result is that fib_trie_seq_next
+will return NULL at the end of the local table, fib_trie_seq_start will
+return the start of the main table, and then fib_trie_seq_next will loop on
+main forever as h will always return 0.
+
+The fix for this is to reverse the ordering of the two tables.  It has the
+advantage of making it so that the tables now print in the same order
+regardless of if multiple tables are enabled or not.  In order to make the
+definition consistent with the multiple tables case I simply masked the to
+RT_TABLE_XXX values by (FIB_TABLE_HASHSZ - 1).  This way the two table
+layouts should always stay consistent.
+
+Fixes: 93456b6 ("[IPV4]: Unify access to the routing tables")
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/include/net/ip_fib.h
++++ b/include/net/ip_fib.h
+@@ -201,8 +201,8 @@ void fib_free_table(struct fib_table *tb
+ 
+ #ifndef CONFIG_IP_MULTIPLE_TABLES
+ 
+-#define TABLE_LOCAL_INDEX	0
+-#define TABLE_MAIN_INDEX	1
++#define TABLE_LOCAL_INDEX	(RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1))
++#define TABLE_MAIN_INDEX	(RT_TABLE_MAIN  & (FIB_TABLE_HASHSZ - 1))
+ 
+ static inline struct fib_table *fib_get_table(struct net *net, u32 id)
+ {
diff --git a/target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch b/target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch
new file mode 100644
index 0000000000..4e09f8a189
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-01-fib_trie-Fix-trie-balancing-issue-if-new-node-pushes.patch
@@ -0,0 +1,72 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 10 Dec 2014 21:49:22 -0800
+Subject: [PATCH] fib_trie: Fix trie balancing issue if new node pushes down
+ existing node
+
+This patch addresses an issue with the level compression of the fib_trie.
+Specifically in the case of adding a new leaf that triggers a new node to
+be added that takes the place of the old node.  The result is a trie where
+the 1 child tnode is on one side and one leaf is on the other which gives
+you a very deep trie.  Below is the script I used to generate a trie on
+dummy0 with a 10.X.X.X family of addresses.
+
+  ip link add type dummy
+  ipval=184549374
+  bit=2
+  for i in `seq 1 23`
+  do
+    ifconfig dummy0:$bit $ipval/8
+    ipval=`expr $ipval - $bit`
+    bit=`expr $bit \* 2`
+  done
+  cat /proc/net/fib_triestat
+
+Running the script before the patch:
+
+	Local:
+		Aver depth:     10.82
+		Max depth:      23
+		Leaves:         29
+		Prefixes:       30
+		Internal nodes: 27
+		  1: 26  2: 1
+		Pointers: 56
+	Null ptrs: 1
+	Total size: 5  kB
+
+After applying the patch and repeating:
+
+	Local:
+		Aver depth:     4.72
+		Max depth:      9
+		Leaves:         29
+		Prefixes:       30
+		Internal nodes: 12
+		  1: 3  2: 2  3: 7
+		Pointers: 70
+	Null ptrs: 30
+	Total size: 4  kB
+
+What this fix does is start the rebalance at the newly created tnode
+instead of at the parent tnode.  This way if there is a gap between the
+parent and the new node it doesn't prevent the new tnode from being
+coalesced with any pre-existing nodes that may have been pushed into one
+of the new nodes child branches.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1143,8 +1143,9 @@ static struct list_head *fib_insert_node
+ 			put_child(tp, cindex, (struct rt_trie_node *)tn);
+ 		} else {
+ 			rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+-			tp = tn;
+ 		}
++
++		tp = tn;
+ 	}
+ 
+ 	if (tp && tp->pos + tp->bits > 32)
diff --git a/target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch b/target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch
new file mode 100644
index 0000000000..2e6deb5bbc
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch
@@ -0,0 +1,200 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:55:29 -0800
+Subject: [PATCH] fib_trie: Update usage stats to be percpu instead of
+ global variables
+
+The trie usage stats were currently being shared by all threads that were
+calling fib_table_lookup.  As a result when multiple threads were
+performing lookups simultaneously the trie would begin to cache bounce
+between those threads.
+
+In order to prevent this I have updated the usage stats to use a set of
+percpu variables.  By doing this we should be able to avoid the cache
+bouncing and still make use of these stats.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(st
+ 	return 0;
+ 
+ fail:
+-	kfree(local_table);
++	fib_free_table(local_table);
+ 	return -ENOMEM;
+ }
+ #else
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -153,7 +153,7 @@ struct trie_stat {
+ struct trie {
+ 	struct rt_trie_node __rcu *trie;
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-	struct trie_use_stats stats;
++	struct trie_use_stats __percpu *stats;
+ #endif
+ };
+ 
+@@ -631,7 +631,7 @@ static struct rt_trie_node *resize(struc
+ 		if (IS_ERR(tn)) {
+ 			tn = old_tn;
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-			t->stats.resize_node_skipped++;
++			this_cpu_inc(t->stats->resize_node_skipped);
+ #endif
+ 			break;
+ 		}
+@@ -658,7 +658,7 @@ static struct rt_trie_node *resize(struc
+ 		if (IS_ERR(tn)) {
+ 			tn = old_tn;
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-			t->stats.resize_node_skipped++;
++			this_cpu_inc(t->stats->resize_node_skipped);
+ #endif
+ 			break;
+ 		}
+@@ -1357,7 +1357,7 @@ static int check_leaf(struct fib_table *
+ 			err = fib_props[fa->fa_type].error;
+ 			if (err) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-				t->stats.semantic_match_passed++;
++				this_cpu_inc(t->stats->semantic_match_passed);
+ #endif
+ 				return err;
+ 			}
+@@ -1372,7 +1372,7 @@ static int check_leaf(struct fib_table *
+ 					continue;
+ 
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-				t->stats.semantic_match_passed++;
++				this_cpu_inc(t->stats->semantic_match_passed);
+ #endif
+ 				res->prefixlen = li->plen;
+ 				res->nh_sel = nhsel;
+@@ -1388,7 +1388,7 @@ static int check_leaf(struct fib_table *
+ 		}
+ 
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-		t->stats.semantic_match_miss++;
++		this_cpu_inc(t->stats->semantic_match_miss);
+ #endif
+ 	}
+ 
+@@ -1399,6 +1399,9 @@ int fib_table_lookup(struct fib_table *t
+ 		     struct fib_result *res, int fib_flags)
+ {
+ 	struct trie *t = (struct trie *) tb->tb_data;
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++	struct trie_use_stats __percpu *stats = t->stats;
++#endif
+ 	int ret;
+ 	struct rt_trie_node *n;
+ 	struct tnode *pn;
+@@ -1417,7 +1420,7 @@ int fib_table_lookup(struct fib_table *t
+ 		goto failed;
+ 
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-	t->stats.gets++;
++	this_cpu_inc(stats->gets);
+ #endif
+ 
+ 	/* Just a leaf? */
+@@ -1441,7 +1444,7 @@ int fib_table_lookup(struct fib_table *t
+ 
+ 		if (n == NULL) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-			t->stats.null_node_hit++;
++			this_cpu_inc(stats->null_node_hit);
+ #endif
+ 			goto backtrace;
+ 		}
+@@ -1576,7 +1579,7 @@ backtrace:
+ 			chopped_off = 0;
+ 
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-			t->stats.backtrack++;
++			this_cpu_inc(stats->backtrack);
+ #endif
+ 			goto backtrace;
+ 		}
+@@ -1830,6 +1833,11 @@ int fib_table_flush(struct fib_table *tb
+ 
+ void fib_free_table(struct fib_table *tb)
+ {
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++	struct trie *t = (struct trie *)tb->tb_data;
++
++	free_percpu(t->stats);
++#endif /* CONFIG_IP_FIB_TRIE_STATS */
+ 	kfree(tb);
+ }
+ 
+@@ -1973,7 +1981,14 @@ struct fib_table *fib_trie_table(u32 id)
+ 	tb->tb_num_default = 0;
+ 
+ 	t = (struct trie *) tb->tb_data;
+-	memset(t, 0, sizeof(*t));
++	RCU_INIT_POINTER(t->trie, NULL);
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++	t->stats = alloc_percpu(struct trie_use_stats);
++	if (!t->stats) {
++		kfree(tb);
++		tb = NULL;
++	}
++#endif
+ 
+ 	return tb;
+ }
+@@ -2139,18 +2154,31 @@ static void trie_show_stats(struct seq_f
+ 
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ static void trie_show_usage(struct seq_file *seq,
+-			    const struct trie_use_stats *stats)
++			    const struct trie_use_stats __percpu *stats)
+ {
++	struct trie_use_stats s = { 0 };
++	int cpu;
++
++	/* loop through all of the CPUs and gather up the stats */
++	for_each_possible_cpu(cpu) {
++		const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu);
++
++		s.gets += pcpu->gets;
++		s.backtrack += pcpu->backtrack;
++		s.semantic_match_passed += pcpu->semantic_match_passed;
++		s.semantic_match_miss += pcpu->semantic_match_miss;
++		s.null_node_hit += pcpu->null_node_hit;
++		s.resize_node_skipped += pcpu->resize_node_skipped;
++	}
++
+ 	seq_printf(seq, "\nCounters:\n---------\n");
+-	seq_printf(seq, "gets = %u\n", stats->gets);
+-	seq_printf(seq, "backtracks = %u\n", stats->backtrack);
++	seq_printf(seq, "gets = %u\n", s.gets);
++	seq_printf(seq, "backtracks = %u\n", s.backtrack);
+ 	seq_printf(seq, "semantic match passed = %u\n",
+-		   stats->semantic_match_passed);
+-	seq_printf(seq, "semantic match miss = %u\n",
+-		   stats->semantic_match_miss);
+-	seq_printf(seq, "null node hit= %u\n", stats->null_node_hit);
+-	seq_printf(seq, "skipped node resize = %u\n\n",
+-		   stats->resize_node_skipped);
++		   s.semantic_match_passed);
++	seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss);
++	seq_printf(seq, "null node hit= %u\n", s.null_node_hit);
++	seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped);
+ }
+ #endif /*  CONFIG_IP_FIB_TRIE_STATS */
+ 
+@@ -2191,7 +2219,7 @@ static int fib_triestat_seq_show(struct
+ 			trie_collect_stats(t, &stat);
+ 			trie_show_stats(seq, &stat);
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-			trie_show_usage(seq, &t->stats);
++			trie_show_usage(seq, t->stats);
+ #endif
+ 		}
+ 	}
diff --git a/target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch b/target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch
new file mode 100644
index 0000000000..4c727cdfce
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-03-fib_trie-Make-leaf-and-tnode-more-uniform.patch
@@ -0,0 +1,421 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:55:35 -0800
+Subject: [PATCH] fib_trie: Make leaf and tnode more uniform
+
+This change makes some fundamental changes to the way leaves and tnodes are
+constructed.  The big differences are:
+1.  Leaves now populate pos and bits indicating their full key size.
+2.  Trie nodes now mask out their lower bits to be consistent with the leaf
+3.  Both structures have been reordered so that rt_trie_node now consisists
+    of a much larger region including the pos, bits, and rcu portions of
+    the tnode structure.
+
+On 32b systems this will result in the leaf being 4B larger as the pos and
+bits values were added to a hole created by the key as it was only 4B in
+length.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -87,24 +87,38 @@
+ 
+ typedef unsigned int t_key;
+ 
+-#define T_TNODE 0
+-#define T_LEAF  1
+-#define NODE_TYPE_MASK	0x1UL
+-#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK)
++#define IS_TNODE(n) ((n)->bits)
++#define IS_LEAF(n) (!(n)->bits)
+ 
+-#define IS_TNODE(n) (!(n->parent & T_LEAF))
+-#define IS_LEAF(n) (n->parent & T_LEAF)
++struct tnode {
++	t_key key;
++	unsigned char bits;		/* 2log(KEYLENGTH) bits needed */
++	unsigned char pos;		/* 2log(KEYLENGTH) bits needed */
++	struct tnode __rcu *parent;
++	union {
++		struct rcu_head rcu;
++		struct tnode *tnode_free;
++	};
++	unsigned int full_children;	/* KEYLENGTH bits needed */
++	unsigned int empty_children;	/* KEYLENGTH bits needed */
++	struct rt_trie_node __rcu *child[0];
++};
+ 
+ struct rt_trie_node {
+-	unsigned long parent;
+ 	t_key key;
++	unsigned char bits;
++	unsigned char pos;
++	struct tnode __rcu *parent;
++	struct rcu_head rcu;
+ };
+ 
+ struct leaf {
+-	unsigned long parent;
+ 	t_key key;
+-	struct hlist_head list;
++	unsigned char bits;
++	unsigned char pos;
++	struct tnode __rcu *parent;
+ 	struct rcu_head rcu;
++	struct hlist_head list;
+ };
+ 
+ struct leaf_info {
+@@ -115,20 +129,6 @@ struct leaf_info {
+ 	struct rcu_head rcu;
+ };
+ 
+-struct tnode {
+-	unsigned long parent;
+-	t_key key;
+-	unsigned char pos;		/* 2log(KEYLENGTH) bits needed */
+-	unsigned char bits;		/* 2log(KEYLENGTH) bits needed */
+-	unsigned int full_children;	/* KEYLENGTH bits needed */
+-	unsigned int empty_children;	/* KEYLENGTH bits needed */
+-	union {
+-		struct rcu_head rcu;
+-		struct tnode *tnode_free;
+-	};
+-	struct rt_trie_node __rcu *child[0];
+-};
+-
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ struct trie_use_stats {
+ 	unsigned int gets;
+@@ -176,38 +176,27 @@ static const int sync_pages = 128;
+ static struct kmem_cache *fn_alias_kmem __read_mostly;
+ static struct kmem_cache *trie_leaf_kmem __read_mostly;
+ 
+-/*
+- * caller must hold RTNL
+- */
+-static inline struct tnode *node_parent(const struct rt_trie_node *node)
+-{
+-	unsigned long parent;
++/* caller must hold RTNL */
++#define node_parent(n) rtnl_dereference((n)->parent)
+ 
+-	parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
++/* caller must hold RCU read lock or RTNL */
++#define node_parent_rcu(n) rcu_dereference_rtnl((n)->parent)
+ 
+-	return (struct tnode *)(parent & ~NODE_TYPE_MASK);
+-}
+-
+-/*
+- * caller must hold RCU read lock or RTNL
+- */
+-static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
++/* wrapper for rcu_assign_pointer */
++static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
+ {
+-	unsigned long parent;
+-
+-	parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
+-							   lockdep_rtnl_is_held());
+-
+-	return (struct tnode *)(parent & ~NODE_TYPE_MASK);
++	if (node)
++		rcu_assign_pointer(node->parent, ptr);
+ }
+ 
+-/* Same as rcu_assign_pointer
+- * but that macro() assumes that value is a pointer.
++#define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER((n)->parent, p)
++
++/* This provides us with the number of children in this node, in the case of a
++ * leaf this will return 0 meaning none of the children are accessible.
+  */
+-static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
++static inline int tnode_child_length(const struct tnode *tn)
+ {
+-	smp_wmb();
+-	node->parent = (unsigned long)ptr | NODE_TYPE(node);
++	return (1ul << tn->bits) & ~(1ul);
+ }
+ 
+ /*
+@@ -215,7 +204,7 @@ static inline void node_set_parent(struc
+  */
+ static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
+ {
+-	BUG_ON(i >= 1U << tn->bits);
++	BUG_ON(i >= tnode_child_length(tn));
+ 
+ 	return rtnl_dereference(tn->child[i]);
+ }
+@@ -225,16 +214,11 @@ static inline struct rt_trie_node *tnode
+  */
+ static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
+ {
+-	BUG_ON(i >= 1U << tn->bits);
++	BUG_ON(i >= tnode_child_length(tn));
+ 
+ 	return rcu_dereference_rtnl(tn->child[i]);
+ }
+ 
+-static inline int tnode_child_length(const struct tnode *tn)
+-{
+-	return 1 << tn->bits;
+-}
+-
+ static inline t_key mask_pfx(t_key k, unsigned int l)
+ {
+ 	return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
+@@ -336,11 +320,6 @@ static inline int tkey_mismatch(t_key a,
+ 
+ */
+ 
+-static inline void check_tnode(const struct tnode *tn)
+-{
+-	WARN_ON(tn && tn->pos+tn->bits > 32);
+-}
+-
+ static const int halve_threshold = 25;
+ static const int inflate_threshold = 50;
+ static const int halve_threshold_root = 15;
+@@ -426,11 +405,20 @@ static void tnode_free_flush(void)
+ 	}
+ }
+ 
+-static struct leaf *leaf_new(void)
++static struct leaf *leaf_new(t_key key)
+ {
+ 	struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
+ 	if (l) {
+-		l->parent = T_LEAF;
++		l->parent = NULL;
++		/* set key and pos to reflect full key value
++		 * any trailing zeros in the key should be ignored
++		 * as the nodes are searched
++		 */
++		l->key = key;
++		l->pos = KEYLENGTH;
++		/* set bits to 0 indicating we are not a tnode */
++		l->bits = 0;
++
+ 		INIT_HLIST_HEAD(&l->list);
+ 	}
+ 	return l;
+@@ -451,12 +439,16 @@ static struct tnode *tnode_new(t_key key
+ {
+ 	size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits);
+ 	struct tnode *tn = tnode_alloc(sz);
++	unsigned int shift = pos + bits;
++
++	/* verify bits and pos their msb bits clear and values are valid */
++	BUG_ON(!bits || (shift > KEYLENGTH));
+ 
+ 	if (tn) {
+-		tn->parent = T_TNODE;
++		tn->parent = NULL;
+ 		tn->pos = pos;
+ 		tn->bits = bits;
+-		tn->key = key;
++		tn->key = mask_pfx(key, pos);
+ 		tn->full_children = 0;
+ 		tn->empty_children = 1<<bits;
+ 	}
+@@ -473,10 +465,7 @@ static struct tnode *tnode_new(t_key key
+ 
+ static inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n)
+ {
+-	if (n == NULL || IS_LEAF(n))
+-		return 0;
+-
+-	return ((struct tnode *) n)->pos == tn->pos + tn->bits;
++	return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits));
+ }
+ 
+ static inline void put_child(struct tnode *tn, int i,
+@@ -514,8 +503,7 @@ static void tnode_put_child_reorg(struct
+ 	else if (!wasfull && isfull)
+ 		tn->full_children++;
+ 
+-	if (n)
+-		node_set_parent(n, tn);
++	node_set_parent(n, tn);
+ 
+ 	rcu_assign_pointer(tn->child[i], n);
+ }
+@@ -523,7 +511,7 @@ static void tnode_put_child_reorg(struct
+ #define MAX_WORK 10
+ static struct rt_trie_node *resize(struct trie *t, struct tnode *tn)
+ {
+-	int i;
++	struct rt_trie_node *n = NULL;
+ 	struct tnode *old_tn;
+ 	int inflate_threshold_use;
+ 	int halve_threshold_use;
+@@ -536,12 +524,11 @@ static struct rt_trie_node *resize(struc
+ 		 tn, inflate_threshold, halve_threshold);
+ 
+ 	/* No children */
+-	if (tn->empty_children == tnode_child_length(tn)) {
+-		tnode_free_safe(tn);
+-		return NULL;
+-	}
++	if (tn->empty_children > (tnode_child_length(tn) - 1))
++		goto no_children;
++
+ 	/* One child */
+-	if (tn->empty_children == tnode_child_length(tn) - 1)
++	if (tn->empty_children == (tnode_child_length(tn) - 1))
+ 		goto one_child;
+ 	/*
+ 	 * Double as long as the resulting node has a number of
+@@ -607,11 +594,9 @@ static struct rt_trie_node *resize(struc
+ 	 *
+ 	 */
+ 
+-	check_tnode(tn);
+-
+ 	/* Keep root node larger  */
+ 
+-	if (!node_parent((struct rt_trie_node *)tn)) {
++	if (!node_parent(tn)) {
+ 		inflate_threshold_use = inflate_threshold_root;
+ 		halve_threshold_use = halve_threshold_root;
+ 	} else {
+@@ -637,8 +622,6 @@ static struct rt_trie_node *resize(struc
+ 		}
+ 	}
+ 
+-	check_tnode(tn);
+-
+ 	/* Return if at least one inflate is run */
+ 	if (max_work != MAX_WORK)
+ 		return (struct rt_trie_node *) tn;
+@@ -666,21 +649,16 @@ static struct rt_trie_node *resize(struc
+ 
+ 
+ 	/* Only one child remains */
+-	if (tn->empty_children == tnode_child_length(tn) - 1) {
++	if (tn->empty_children == (tnode_child_length(tn) - 1)) {
++		unsigned long i;
+ one_child:
+-		for (i = 0; i < tnode_child_length(tn); i++) {
+-			struct rt_trie_node *n;
+-
+-			n = rtnl_dereference(tn->child[i]);
+-			if (!n)
+-				continue;
+-
+-			/* compress one level */
+-
+-			node_set_parent(n, NULL);
+-			tnode_free_safe(tn);
+-			return n;
+-		}
++		for (i = tnode_child_length(tn); !n && i;)
++			n = tnode_get_child(tn, --i);
++no_children:
++		/* compress one level */
++		node_set_parent(n, NULL);
++		tnode_free_safe(tn);
++		return n;
+ 	}
+ 	return (struct rt_trie_node *) tn;
+ }
+@@ -760,8 +738,7 @@ static struct tnode *inflate(struct trie
+ 
+ 		/* A leaf or an internal node with skipped bits */
+ 
+-		if (IS_LEAF(node) || ((struct tnode *) node)->pos >
+-		   tn->pos + tn->bits - 1) {
++		if (IS_LEAF(node) || (node->pos > (tn->pos + tn->bits - 1))) {
+ 			put_child(tn,
+ 				tkey_extract_bits(node->key, oldtnode->pos, oldtnode->bits + 1),
+ 				node);
+@@ -958,11 +935,9 @@ fib_find_node(struct trie *t, u32 key)
+ 	pos = 0;
+ 	n = rcu_dereference_rtnl(t->trie);
+ 
+-	while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
++	while (n && IS_TNODE(n)) {
+ 		tn = (struct tnode *) n;
+ 
+-		check_tnode(tn);
+-
+ 		if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
+ 			pos = tn->pos + tn->bits;
+ 			n = tnode_get_child_rcu(tn,
+@@ -988,7 +963,7 @@ static void trie_rebalance(struct trie *
+ 
+ 	key = tn->key;
+ 
+-	while (tn != NULL && (tp = node_parent((struct rt_trie_node *)tn)) != NULL) {
++	while (tn != NULL && (tp = node_parent(tn)) != NULL) {
+ 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+ 		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
+ 		tn = (struct tnode *)resize(t, tn);
+@@ -996,7 +971,7 @@ static void trie_rebalance(struct trie *
+ 		tnode_put_child_reorg(tp, cindex,
+ 				      (struct rt_trie_node *)tn, wasfull);
+ 
+-		tp = node_parent((struct rt_trie_node *) tn);
++		tp = node_parent(tn);
+ 		if (!tp)
+ 			rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
+ 
+@@ -1048,11 +1023,9 @@ static struct list_head *fib_insert_node
+ 	 * If it doesn't, we need to replace it with a T_TNODE.
+ 	 */
+ 
+-	while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
++	while (n && IS_TNODE(n)) {
+ 		tn = (struct tnode *) n;
+ 
+-		check_tnode(tn);
+-
+ 		if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
+ 			tp = tn;
+ 			pos = tn->pos + tn->bits;
+@@ -1087,12 +1060,11 @@ static struct list_head *fib_insert_node
+ 		insert_leaf_info(&l->list, li);
+ 		goto done;
+ 	}
+-	l = leaf_new();
++	l = leaf_new(key);
+ 
+ 	if (!l)
+ 		return NULL;
+ 
+-	l->key = key;
+ 	li = leaf_info_new(plen);
+ 
+ 	if (!li) {
+@@ -1569,7 +1541,7 @@ backtrace:
+ 		if (chopped_off <= pn->bits) {
+ 			cindex &= ~(1 << (chopped_off-1));
+ 		} else {
+-			struct tnode *parent = node_parent_rcu((struct rt_trie_node *) pn);
++			struct tnode *parent = node_parent_rcu(pn);
+ 			if (!parent)
+ 				goto failed;
+ 
+@@ -1597,7 +1569,7 @@ EXPORT_SYMBOL_GPL(fib_table_lookup);
+  */
+ static void trie_leaf_remove(struct trie *t, struct leaf *l)
+ {
+-	struct tnode *tp = node_parent((struct rt_trie_node *) l);
++	struct tnode *tp = node_parent(l);
+ 
+ 	pr_debug("entering trie_leaf_remove(%p)\n", l);
+ 
+@@ -2374,7 +2346,7 @@ static int fib_trie_seq_show(struct seq_
+ 
+ 	if (IS_TNODE(n)) {
+ 		struct tnode *tn = (struct tnode *) n;
+-		__be32 prf = htonl(mask_pfx(tn->key, tn->pos));
++		__be32 prf = htonl(tn->key);
+ 
+ 		seq_indent(seq, iter->depth-1);
+ 		seq_printf(seq, "  +-- %pI4/%d %d %d %d\n",
diff --git a/target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch b/target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch
new file mode 100644
index 0000000000..3f8d03067d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-04-fib_trie-Merge-tnode_free-and-leaf_free-into-node_fr.patch
@@ -0,0 +1,209 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:55:41 -0800
+Subject: [PATCH] fib_trie: Merge tnode_free and leaf_free into node_free
+
+Both the leaf and the tnode had an rcu_head in them, but they had them in
+slightly different places.  Since we now have them in the same spot and
+know that any node with bits == 0 is a leaf and the rest are either vmalloc
+or kmalloc tnodes depending on the value of bits it makes it easy to combine
+the functions and reduce overhead.
+
+In addition I have taken advantage of the rcu_head pointer to go ahead and
+put together a simple linked list instead of using the tnode pointer as
+this way we can merge either type of structure for freeing.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -95,15 +95,17 @@ struct tnode {
+ 	unsigned char bits;		/* 2log(KEYLENGTH) bits needed */
+ 	unsigned char pos;		/* 2log(KEYLENGTH) bits needed */
+ 	struct tnode __rcu *parent;
+-	union {
+-		struct rcu_head rcu;
+-		struct tnode *tnode_free;
+-	};
++	struct rcu_head rcu;
++	/* everything above this comment must be the same as rt_trie_node */
+ 	unsigned int full_children;	/* KEYLENGTH bits needed */
+ 	unsigned int empty_children;	/* KEYLENGTH bits needed */
+ 	struct rt_trie_node __rcu *child[0];
+ };
+ 
++/* This struct represents the shared bits between tnode and leaf.  If any
++ * ordering is changed here is must also be updated in tnode and leaf as
++ * well.
++ */
+ struct rt_trie_node {
+ 	t_key key;
+ 	unsigned char bits;
+@@ -118,6 +120,7 @@ struct leaf {
+ 	unsigned char pos;
+ 	struct tnode __rcu *parent;
+ 	struct rcu_head rcu;
++	/* everything above this comment must be the same as rt_trie_node */
+ 	struct hlist_head list;
+ };
+ 
+@@ -163,7 +166,7 @@ static struct rt_trie_node *resize(struc
+ static struct tnode *inflate(struct trie *t, struct tnode *tn);
+ static struct tnode *halve(struct trie *t, struct tnode *tn);
+ /* tnodes to free after resize(); protected by RTNL */
+-static struct tnode *tnode_free_head;
++static struct callback_head *tnode_free_head;
+ static size_t tnode_free_size;
+ 
+ /*
+@@ -336,17 +339,23 @@ static inline void alias_free_mem_rcu(st
+ 	call_rcu(&fa->rcu, __alias_free_mem);
+ }
+ 
+-static void __leaf_free_rcu(struct rcu_head *head)
+-{
+-	struct leaf *l = container_of(head, struct leaf, rcu);
+-	kmem_cache_free(trie_leaf_kmem, l);
+-}
++#define TNODE_KMALLOC_MAX \
++	ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct rt_trie_node *))
+ 
+-static inline void free_leaf(struct leaf *l)
++static void __node_free_rcu(struct rcu_head *head)
+ {
+-	call_rcu(&l->rcu, __leaf_free_rcu);
++	struct rt_trie_node *n = container_of(head, struct rt_trie_node, rcu);
++
++	if (IS_LEAF(n))
++		kmem_cache_free(trie_leaf_kmem, n);
++	else if (n->bits <= TNODE_KMALLOC_MAX)
++		kfree(n);
++	else
++		vfree(n);
+ }
+ 
++#define node_free(n) call_rcu(&n->rcu, __node_free_rcu)
++
+ static inline void free_leaf_info(struct leaf_info *leaf)
+ {
+ 	kfree_rcu(leaf, rcu);
+@@ -360,43 +369,24 @@ static struct tnode *tnode_alloc(size_t
+ 		return vzalloc(size);
+ }
+ 
+-static void __tnode_free_rcu(struct rcu_head *head)
+-{
+-	struct tnode *tn = container_of(head, struct tnode, rcu);
+-	size_t size = sizeof(struct tnode) +
+-		      (sizeof(struct rt_trie_node *) << tn->bits);
+-
+-	if (size <= PAGE_SIZE)
+-		kfree(tn);
+-	else
+-		vfree(tn);
+-}
+-
+-static inline void tnode_free(struct tnode *tn)
+-{
+-	if (IS_LEAF(tn))
+-		free_leaf((struct leaf *) tn);
+-	else
+-		call_rcu(&tn->rcu, __tnode_free_rcu);
+-}
+-
+ static void tnode_free_safe(struct tnode *tn)
+ {
+ 	BUG_ON(IS_LEAF(tn));
+-	tn->tnode_free = tnode_free_head;
+-	tnode_free_head = tn;
+-	tnode_free_size += sizeof(struct tnode) +
+-			   (sizeof(struct rt_trie_node *) << tn->bits);
++	tn->rcu.next = tnode_free_head;
++	tnode_free_head = &tn->rcu;
+ }
+ 
+ static void tnode_free_flush(void)
+ {
+-	struct tnode *tn;
++	struct callback_head *head;
++
++	while ((head = tnode_free_head)) {
++		struct tnode *tn = container_of(head, struct tnode, rcu);
++
++		tnode_free_head = head->next;
++		tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
+ 
+-	while ((tn = tnode_free_head)) {
+-		tnode_free_head = tn->tnode_free;
+-		tn->tnode_free = NULL;
+-		tnode_free(tn);
++		node_free(tn);
+ 	}
+ 
+ 	if (tnode_free_size >= PAGE_SIZE * sync_pages) {
+@@ -437,7 +427,7 @@ static struct leaf_info *leaf_info_new(i
+ 
+ static struct tnode *tnode_new(t_key key, int pos, int bits)
+ {
+-	size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits);
++	size_t sz = offsetof(struct tnode, child[1 << bits]);
+ 	struct tnode *tn = tnode_alloc(sz);
+ 	unsigned int shift = pos + bits;
+ 
+@@ -666,15 +656,15 @@ no_children:
+ 
+ static void tnode_clean_free(struct tnode *tn)
+ {
++	struct rt_trie_node *tofree;
+ 	int i;
+-	struct tnode *tofree;
+ 
+ 	for (i = 0; i < tnode_child_length(tn); i++) {
+-		tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
++		tofree = rtnl_dereference(tn->child[i]);
+ 		if (tofree)
+-			tnode_free(tofree);
++			node_free(tofree);
+ 	}
+-	tnode_free(tn);
++	node_free(tn);
+ }
+ 
+ static struct tnode *inflate(struct trie *t, struct tnode *tn)
+@@ -717,7 +707,7 @@ static struct tnode *inflate(struct trie
+ 					  inode->bits - 1);
+ 
+ 			if (!right) {
+-				tnode_free(left);
++				node_free(left);
+ 				goto nomem;
+ 			}
+ 
+@@ -1068,7 +1058,7 @@ static struct list_head *fib_insert_node
+ 	li = leaf_info_new(plen);
+ 
+ 	if (!li) {
+-		free_leaf(l);
++		node_free(l);
+ 		return NULL;
+ 	}
+ 
+@@ -1100,7 +1090,7 @@ static struct list_head *fib_insert_node
+ 
+ 		if (!tn) {
+ 			free_leaf_info(li);
+-			free_leaf(l);
++			node_free(l);
+ 			return NULL;
+ 		}
+ 
+@@ -1580,7 +1570,7 @@ static void trie_leaf_remove(struct trie
+ 	} else
+ 		RCU_INIT_POINTER(t->trie, NULL);
+ 
+-	free_leaf(l);
++	node_free(l);
+ }
+ 
+ /*
diff --git a/target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch b/target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch
new file mode 100644
index 0000000000..a3393bf93f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-05-fib_trie-Merge-leaf-into-tnode.patch
@@ -0,0 +1,928 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:55:47 -0800
+Subject: [PATCH] fib_trie: Merge leaf into tnode
+
+This change makes it so that leaf and tnode are the same struct.  As a
+result there is no need for rt_trie_node anymore since everyting can be
+merged into tnode.
+
+On 32b systems this results in the leaf being 4 bytes larger, however I
+don't know if that is really an issue as this and an eariler patch that
+added bits & pos have increased the size from 20 to 28.  If I am not
+mistaken slub/slab allocate on power of 2 sizes so 20 was likely being
+rounded up to 32 anyway.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -96,32 +96,16 @@ struct tnode {
+ 	unsigned char pos;		/* 2log(KEYLENGTH) bits needed */
+ 	struct tnode __rcu *parent;
+ 	struct rcu_head rcu;
+-	/* everything above this comment must be the same as rt_trie_node */
+-	unsigned int full_children;	/* KEYLENGTH bits needed */
+-	unsigned int empty_children;	/* KEYLENGTH bits needed */
+-	struct rt_trie_node __rcu *child[0];
+-};
+-
+-/* This struct represents the shared bits between tnode and leaf.  If any
+- * ordering is changed here is must also be updated in tnode and leaf as
+- * well.
+- */
+-struct rt_trie_node {
+-	t_key key;
+-	unsigned char bits;
+-	unsigned char pos;
+-	struct tnode __rcu *parent;
+-	struct rcu_head rcu;
+-};
+-
+-struct leaf {
+-	t_key key;
+-	unsigned char bits;
+-	unsigned char pos;
+-	struct tnode __rcu *parent;
+-	struct rcu_head rcu;
+-	/* everything above this comment must be the same as rt_trie_node */
+-	struct hlist_head list;
++	union {
++		/* The fields in this struct are valid if bits > 0 (TNODE) */
++		struct {
++			unsigned int full_children;  /* KEYLENGTH bits needed */
++			unsigned int empty_children; /* KEYLENGTH bits needed */
++			struct tnode __rcu *child[0];
++		};
++		/* This list pointer if valid if bits == 0 (LEAF) */
++		struct hlist_head list;
++	};
+ };
+ 
+ struct leaf_info {
+@@ -154,15 +138,15 @@ struct trie_stat {
+ };
+ 
+ struct trie {
+-	struct rt_trie_node __rcu *trie;
++	struct tnode __rcu *trie;
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 	struct trie_use_stats __percpu *stats;
+ #endif
+ };
+ 
+-static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
++static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
+ 				  int wasfull);
+-static struct rt_trie_node *resize(struct trie *t, struct tnode *tn);
++static struct tnode *resize(struct trie *t, struct tnode *tn);
+ static struct tnode *inflate(struct trie *t, struct tnode *tn);
+ static struct tnode *halve(struct trie *t, struct tnode *tn);
+ /* tnodes to free after resize(); protected by RTNL */
+@@ -186,10 +170,10 @@ static struct kmem_cache *trie_leaf_kmem
+ #define node_parent_rcu(n) rcu_dereference_rtnl((n)->parent)
+ 
+ /* wrapper for rcu_assign_pointer */
+-static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
++static inline void node_set_parent(struct tnode *n, struct tnode *tp)
+ {
+-	if (node)
+-		rcu_assign_pointer(node->parent, ptr);
++	if (n)
++		rcu_assign_pointer(n->parent, tp);
+ }
+ 
+ #define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER((n)->parent, p)
+@@ -205,7 +189,7 @@ static inline int tnode_child_length(con
+ /*
+  * caller must hold RTNL
+  */
+-static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
++static inline struct tnode *tnode_get_child(const struct tnode *tn, unsigned int i)
+ {
+ 	BUG_ON(i >= tnode_child_length(tn));
+ 
+@@ -215,7 +199,7 @@ static inline struct rt_trie_node *tnode
+ /*
+  * caller must hold RCU read lock or RTNL
+  */
+-static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
++static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
+ {
+ 	BUG_ON(i >= tnode_child_length(tn));
+ 
+@@ -340,11 +324,11 @@ static inline void alias_free_mem_rcu(st
+ }
+ 
+ #define TNODE_KMALLOC_MAX \
+-	ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct rt_trie_node *))
++	ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct tnode *))
+ 
+ static void __node_free_rcu(struct rcu_head *head)
+ {
+-	struct rt_trie_node *n = container_of(head, struct rt_trie_node, rcu);
++	struct tnode *n = container_of(head, struct tnode, rcu);
+ 
+ 	if (IS_LEAF(n))
+ 		kmem_cache_free(trie_leaf_kmem, n);
+@@ -395,9 +379,9 @@ static void tnode_free_flush(void)
+ 	}
+ }
+ 
+-static struct leaf *leaf_new(t_key key)
++static struct tnode *leaf_new(t_key key)
+ {
+-	struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
++	struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
+ 	if (l) {
+ 		l->parent = NULL;
+ 		/* set key and pos to reflect full key value
+@@ -444,7 +428,7 @@ static struct tnode *tnode_new(t_key key
+ 	}
+ 
+ 	pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
+-		 sizeof(struct rt_trie_node *) << bits);
++		 sizeof(struct tnode *) << bits);
+ 	return tn;
+ }
+ 
+@@ -453,13 +437,13 @@ static struct tnode *tnode_new(t_key key
+  * and no bits are skipped. See discussion in dyntree paper p. 6
+  */
+ 
+-static inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n)
++static inline int tnode_full(const struct tnode *tn, const struct tnode *n)
+ {
+ 	return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits));
+ }
+ 
+ static inline void put_child(struct tnode *tn, int i,
+-			     struct rt_trie_node *n)
++			     struct tnode *n)
+ {
+ 	tnode_put_child_reorg(tn, i, n, -1);
+ }
+@@ -469,10 +453,10 @@ static inline void put_child(struct tnod
+   * Update the value of full_children and empty_children.
+   */
+ 
+-static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
++static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
+ 				  int wasfull)
+ {
+-	struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
++	struct tnode *chi = rtnl_dereference(tn->child[i]);
+ 	int isfull;
+ 
+ 	BUG_ON(i >= 1<<tn->bits);
+@@ -499,10 +483,9 @@ static void tnode_put_child_reorg(struct
+ }
+ 
+ #define MAX_WORK 10
+-static struct rt_trie_node *resize(struct trie *t, struct tnode *tn)
++static struct tnode *resize(struct trie *t, struct tnode *tn)
+ {
+-	struct rt_trie_node *n = NULL;
+-	struct tnode *old_tn;
++	struct tnode *old_tn, *n = NULL;
+ 	int inflate_threshold_use;
+ 	int halve_threshold_use;
+ 	int max_work;
+@@ -614,7 +597,7 @@ static struct rt_trie_node *resize(struc
+ 
+ 	/* Return if at least one inflate is run */
+ 	if (max_work != MAX_WORK)
+-		return (struct rt_trie_node *) tn;
++		return tn;
+ 
+ 	/*
+ 	 * Halve as long as the number of empty children in this
+@@ -650,13 +633,13 @@ no_children:
+ 		tnode_free_safe(tn);
+ 		return n;
+ 	}
+-	return (struct rt_trie_node *) tn;
++	return tn;
+ }
+ 
+ 
+ static void tnode_clean_free(struct tnode *tn)
+ {
+-	struct rt_trie_node *tofree;
++	struct tnode *tofree;
+ 	int i;
+ 
+ 	for (i = 0; i < tnode_child_length(tn); i++) {
+@@ -667,10 +650,10 @@ static void tnode_clean_free(struct tnod
+ 	node_free(tn);
+ }
+ 
+-static struct tnode *inflate(struct trie *t, struct tnode *tn)
++static struct tnode *inflate(struct trie *t, struct tnode *oldtnode)
+ {
+-	struct tnode *oldtnode = tn;
+-	int olen = tnode_child_length(tn);
++	int olen = tnode_child_length(oldtnode);
++	struct tnode *tn;
+ 	int i;
+ 
+ 	pr_debug("In inflate\n");
+@@ -690,11 +673,8 @@ static struct tnode *inflate(struct trie
+ 	for (i = 0; i < olen; i++) {
+ 		struct tnode *inode;
+ 
+-		inode = (struct tnode *) tnode_get_child(oldtnode, i);
+-		if (inode &&
+-		    IS_TNODE(inode) &&
+-		    inode->pos == oldtnode->pos + oldtnode->bits &&
+-		    inode->bits > 1) {
++		inode = tnode_get_child(oldtnode, i);
++		if (tnode_full(oldtnode, inode) && inode->bits > 1) {
+ 			struct tnode *left, *right;
+ 			t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;
+ 
+@@ -711,33 +691,29 @@ static struct tnode *inflate(struct trie
+ 				goto nomem;
+ 			}
+ 
+-			put_child(tn, 2*i, (struct rt_trie_node *) left);
+-			put_child(tn, 2*i+1, (struct rt_trie_node *) right);
++			put_child(tn, 2*i, left);
++			put_child(tn, 2*i+1, right);
+ 		}
+ 	}
+ 
+ 	for (i = 0; i < olen; i++) {
+-		struct tnode *inode;
+-		struct rt_trie_node *node = tnode_get_child(oldtnode, i);
++		struct tnode *inode = tnode_get_child(oldtnode, i);
+ 		struct tnode *left, *right;
+ 		int size, j;
+ 
+ 		/* An empty child */
+-		if (node == NULL)
++		if (inode == NULL)
+ 			continue;
+ 
+ 		/* A leaf or an internal node with skipped bits */
+-
+-		if (IS_LEAF(node) || (node->pos > (tn->pos + tn->bits - 1))) {
++		if (!tnode_full(oldtnode, inode)) {
+ 			put_child(tn,
+-				tkey_extract_bits(node->key, oldtnode->pos, oldtnode->bits + 1),
+-				node);
++				tkey_extract_bits(inode->key, tn->pos, tn->bits),
++				inode);
+ 			continue;
+ 		}
+ 
+ 		/* An internal node with two children */
+-		inode = (struct tnode *) node;
+-
+ 		if (inode->bits == 1) {
+ 			put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
+ 			put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
+@@ -769,12 +745,12 @@ static struct tnode *inflate(struct trie
+ 		 *   bit to zero.
+ 		 */
+ 
+-		left = (struct tnode *) tnode_get_child(tn, 2*i);
++		left = tnode_get_child(tn, 2*i);
+ 		put_child(tn, 2*i, NULL);
+ 
+ 		BUG_ON(!left);
+ 
+-		right = (struct tnode *) tnode_get_child(tn, 2*i+1);
++		right = tnode_get_child(tn, 2*i+1);
+ 		put_child(tn, 2*i+1, NULL);
+ 
+ 		BUG_ON(!right);
+@@ -796,12 +772,11 @@ nomem:
+ 	return ERR_PTR(-ENOMEM);
+ }
+ 
+-static struct tnode *halve(struct trie *t, struct tnode *tn)
++static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
+ {
+-	struct tnode *oldtnode = tn;
+-	struct rt_trie_node *left, *right;
++	int olen = tnode_child_length(oldtnode);
++	struct tnode *tn, *left, *right;
+ 	int i;
+-	int olen = tnode_child_length(tn);
+ 
+ 	pr_debug("In halve\n");
+ 
+@@ -830,7 +805,7 @@ static struct tnode *halve(struct trie *
+ 			if (!newn)
+ 				goto nomem;
+ 
+-			put_child(tn, i/2, (struct rt_trie_node *)newn);
++			put_child(tn, i/2, newn);
+ 		}
+ 
+ 	}
+@@ -855,7 +830,7 @@ static struct tnode *halve(struct trie *
+ 		}
+ 
+ 		/* Two nonempty children */
+-		newBinNode = (struct tnode *) tnode_get_child(tn, i/2);
++		newBinNode = tnode_get_child(tn, i/2);
+ 		put_child(tn, i/2, NULL);
+ 		put_child(newBinNode, 0, left);
+ 		put_child(newBinNode, 1, right);
+@@ -871,7 +846,7 @@ nomem:
+ /* readside must use rcu_read_lock currently dump routines
+  via get_fa_head and dump */
+ 
+-static struct leaf_info *find_leaf_info(struct leaf *l, int plen)
++static struct leaf_info *find_leaf_info(struct tnode *l, int plen)
+ {
+ 	struct hlist_head *head = &l->list;
+ 	struct leaf_info *li;
+@@ -883,7 +858,7 @@ static struct leaf_info *find_leaf_info(
+ 	return NULL;
+ }
+ 
+-static inline struct list_head *get_fa_head(struct leaf *l, int plen)
++static inline struct list_head *get_fa_head(struct tnode *l, int plen)
+ {
+ 	struct leaf_info *li = find_leaf_info(l, plen);
+ 
+@@ -915,32 +890,25 @@ static void insert_leaf_info(struct hlis
+ 
+ /* rcu_read_lock needs to be hold by caller from readside */
+ 
+-static struct leaf *
+-fib_find_node(struct trie *t, u32 key)
++static struct tnode *fib_find_node(struct trie *t, u32 key)
+ {
+-	int pos;
+-	struct tnode *tn;
+-	struct rt_trie_node *n;
+-
+-	pos = 0;
+-	n = rcu_dereference_rtnl(t->trie);
++	struct tnode *n = rcu_dereference_rtnl(t->trie);
++	int pos = 0;
+ 
+ 	while (n && IS_TNODE(n)) {
+-		tn = (struct tnode *) n;
+-
+-		if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
+-			pos = tn->pos + tn->bits;
+-			n = tnode_get_child_rcu(tn,
++		if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
++			pos = n->pos + n->bits;
++			n = tnode_get_child_rcu(n,
+ 						tkey_extract_bits(key,
+-								  tn->pos,
+-								  tn->bits));
++								  n->pos,
++								  n->bits));
+ 		} else
+ 			break;
+ 	}
+ 	/* Case we have found a leaf. Compare prefixes */
+ 
+ 	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
+-		return (struct leaf *)n;
++		return n;
+ 
+ 	return NULL;
+ }
+@@ -956,14 +924,13 @@ static void trie_rebalance(struct trie *
+ 	while (tn != NULL && (tp = node_parent(tn)) != NULL) {
+ 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+ 		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
+-		tn = (struct tnode *)resize(t, tn);
++		tn = resize(t, tn);
+ 
+-		tnode_put_child_reorg(tp, cindex,
+-				      (struct rt_trie_node *)tn, wasfull);
++		tnode_put_child_reorg(tp, cindex, tn, wasfull);
+ 
+ 		tp = node_parent(tn);
+ 		if (!tp)
+-			rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
++			rcu_assign_pointer(t->trie, tn);
+ 
+ 		tnode_free_flush();
+ 		if (!tp)
+@@ -973,9 +940,9 @@ static void trie_rebalance(struct trie *
+ 
+ 	/* Handle last (top) tnode */
+ 	if (IS_TNODE(tn))
+-		tn = (struct tnode *)resize(t, tn);
++		tn = resize(t, tn);
+ 
+-	rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
++	rcu_assign_pointer(t->trie, tn);
+ 	tnode_free_flush();
+ }
+ 
+@@ -985,8 +952,8 @@ static struct list_head *fib_insert_node
+ {
+ 	int pos, newpos;
+ 	struct tnode *tp = NULL, *tn = NULL;
+-	struct rt_trie_node *n;
+-	struct leaf *l;
++	struct tnode *n;
++	struct tnode *l;
+ 	int missbit;
+ 	struct list_head *fa_head = NULL;
+ 	struct leaf_info *li;
+@@ -1014,17 +981,15 @@ static struct list_head *fib_insert_node
+ 	 */
+ 
+ 	while (n && IS_TNODE(n)) {
+-		tn = (struct tnode *) n;
+-
+-		if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
+-			tp = tn;
+-			pos = tn->pos + tn->bits;
+-			n = tnode_get_child(tn,
++		if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
++			tp = n;
++			pos = n->pos + n->bits;
++			n = tnode_get_child(n,
+ 					    tkey_extract_bits(key,
+-							      tn->pos,
+-							      tn->bits));
++							      n->pos,
++							      n->bits));
+ 
+-			BUG_ON(n && node_parent(n) != tn);
++			BUG_ON(n && node_parent(n) != tp);
+ 		} else
+ 			break;
+ 	}
+@@ -1040,14 +1005,13 @@ static struct list_head *fib_insert_node
+ 	/* Case 1: n is a leaf. Compare prefixes */
+ 
+ 	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
+-		l = (struct leaf *) n;
+ 		li = leaf_info_new(plen);
+ 
+ 		if (!li)
+ 			return NULL;
+ 
+ 		fa_head = &li->falh;
+-		insert_leaf_info(&l->list, li);
++		insert_leaf_info(&n->list, li);
+ 		goto done;
+ 	}
+ 	l = leaf_new(key);
+@@ -1068,10 +1032,10 @@ static struct list_head *fib_insert_node
+ 	if (t->trie && n == NULL) {
+ 		/* Case 2: n is NULL, and will just insert a new leaf */
+ 
+-		node_set_parent((struct rt_trie_node *)l, tp);
++		node_set_parent(l, tp);
+ 
+ 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+-		put_child(tp, cindex, (struct rt_trie_node *)l);
++		put_child(tp, cindex, l);
+ 	} else {
+ 		/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
+ 		/*
+@@ -1094,17 +1058,17 @@ static struct list_head *fib_insert_node
+ 			return NULL;
+ 		}
+ 
+-		node_set_parent((struct rt_trie_node *)tn, tp);
++		node_set_parent(tn, tp);
+ 
+ 		missbit = tkey_extract_bits(key, newpos, 1);
+-		put_child(tn, missbit, (struct rt_trie_node *)l);
++		put_child(tn, missbit, l);
+ 		put_child(tn, 1-missbit, n);
+ 
+ 		if (tp) {
+ 			cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+-			put_child(tp, cindex, (struct rt_trie_node *)tn);
++			put_child(tp, cindex, tn);
+ 		} else {
+-			rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
++			rcu_assign_pointer(t->trie, tn);
+ 		}
+ 
+ 		tp = tn;
+@@ -1134,7 +1098,7 @@ int fib_table_insert(struct fib_table *t
+ 	u8 tos = cfg->fc_tos;
+ 	u32 key, mask;
+ 	int err;
+-	struct leaf *l;
++	struct tnode *l;
+ 
+ 	if (plen > 32)
+ 		return -EINVAL;
+@@ -1292,7 +1256,7 @@ err:
+ }
+ 
+ /* should be called with rcu_read_lock */
+-static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
++static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
+ 		      t_key key,  const struct flowi4 *flp,
+ 		      struct fib_result *res, int fib_flags)
+ {
+@@ -1365,7 +1329,7 @@ int fib_table_lookup(struct fib_table *t
+ 	struct trie_use_stats __percpu *stats = t->stats;
+ #endif
+ 	int ret;
+-	struct rt_trie_node *n;
++	struct tnode *n;
+ 	struct tnode *pn;
+ 	unsigned int pos, bits;
+ 	t_key key = ntohl(flp->daddr);
+@@ -1387,11 +1351,11 @@ int fib_table_lookup(struct fib_table *t
+ 
+ 	/* Just a leaf? */
+ 	if (IS_LEAF(n)) {
+-		ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
++		ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
+ 		goto found;
+ 	}
+ 
+-	pn = (struct tnode *) n;
++	pn = n;
+ 	chopped_off = 0;
+ 
+ 	while (pn) {
+@@ -1412,13 +1376,13 @@ int fib_table_lookup(struct fib_table *t
+ 		}
+ 
+ 		if (IS_LEAF(n)) {
+-			ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
++			ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
+ 			if (ret > 0)
+ 				goto backtrace;
+ 			goto found;
+ 		}
+ 
+-		cn = (struct tnode *)n;
++		cn = n;
+ 
+ 		/*
+ 		 * It's a tnode, and we can do some extra checks here if we
+@@ -1506,7 +1470,7 @@ int fib_table_lookup(struct fib_table *t
+ 				current_prefix_length = mp;
+ 		}
+ 
+-		pn = (struct tnode *)n; /* Descend */
++		pn = n; /* Descend */
+ 		chopped_off = 0;
+ 		continue;
+ 
+@@ -1557,7 +1521,7 @@ EXPORT_SYMBOL_GPL(fib_table_lookup);
+ /*
+  * Remove the leaf and return parent.
+  */
+-static void trie_leaf_remove(struct trie *t, struct leaf *l)
++static void trie_leaf_remove(struct trie *t, struct tnode *l)
+ {
+ 	struct tnode *tp = node_parent(l);
+ 
+@@ -1584,7 +1548,7 @@ int fib_table_delete(struct fib_table *t
+ 	u8 tos = cfg->fc_tos;
+ 	struct fib_alias *fa, *fa_to_delete;
+ 	struct list_head *fa_head;
+-	struct leaf *l;
++	struct tnode *l;
+ 	struct leaf_info *li;
+ 
+ 	if (plen > 32)
+@@ -1682,7 +1646,7 @@ static int trie_flush_list(struct list_h
+ 	return found;
+ }
+ 
+-static int trie_flush_leaf(struct leaf *l)
++static int trie_flush_leaf(struct tnode *l)
+ {
+ 	int found = 0;
+ 	struct hlist_head *lih = &l->list;
+@@ -1704,7 +1668,7 @@ static int trie_flush_leaf(struct leaf *
+  * Scan for the next right leaf starting at node p->child[idx]
+  * Since we have back pointer, no recursion necessary.
+  */
+-static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c)
++static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
+ {
+ 	do {
+ 		t_key idx;
+@@ -1720,47 +1684,46 @@ static struct leaf *leaf_walk_rcu(struct
+ 				continue;
+ 
+ 			if (IS_LEAF(c))
+-				return (struct leaf *) c;
++				return c;
+ 
+ 			/* Rescan start scanning in new node */
+-			p = (struct tnode *) c;
++			p = c;
+ 			idx = 0;
+ 		}
+ 
+ 		/* Node empty, walk back up to parent */
+-		c = (struct rt_trie_node *) p;
++		c = p;
+ 	} while ((p = node_parent_rcu(c)) != NULL);
+ 
+ 	return NULL; /* Root of trie */
+ }
+ 
+-static struct leaf *trie_firstleaf(struct trie *t)
++static struct tnode *trie_firstleaf(struct trie *t)
+ {
+-	struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie);
++	struct tnode *n = rcu_dereference_rtnl(t->trie);
+ 
+ 	if (!n)
+ 		return NULL;
+ 
+ 	if (IS_LEAF(n))          /* trie is just a leaf */
+-		return (struct leaf *) n;
++		return n;
+ 
+ 	return leaf_walk_rcu(n, NULL);
+ }
+ 
+-static struct leaf *trie_nextleaf(struct leaf *l)
++static struct tnode *trie_nextleaf(struct tnode *l)
+ {
+-	struct rt_trie_node *c = (struct rt_trie_node *) l;
+-	struct tnode *p = node_parent_rcu(c);
++	struct tnode *p = node_parent_rcu(l);
+ 
+ 	if (!p)
+ 		return NULL;	/* trie with just one leaf */
+ 
+-	return leaf_walk_rcu(p, c);
++	return leaf_walk_rcu(p, l);
+ }
+ 
+-static struct leaf *trie_leafindex(struct trie *t, int index)
++static struct tnode *trie_leafindex(struct trie *t, int index)
+ {
+-	struct leaf *l = trie_firstleaf(t);
++	struct tnode *l = trie_firstleaf(t);
+ 
+ 	while (l && index-- > 0)
+ 		l = trie_nextleaf(l);
+@@ -1775,7 +1738,7 @@ static struct leaf *trie_leafindex(struc
+ int fib_table_flush(struct fib_table *tb)
+ {
+ 	struct trie *t = (struct trie *) tb->tb_data;
+-	struct leaf *l, *ll = NULL;
++	struct tnode *l, *ll = NULL;
+ 	int found = 0;
+ 
+ 	for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
+@@ -1840,7 +1803,7 @@ static int fn_trie_dump_fa(t_key key, in
+ 	return skb->len;
+ }
+ 
+-static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
++static int fn_trie_dump_leaf(struct tnode *l, struct fib_table *tb,
+ 			struct sk_buff *skb, struct netlink_callback *cb)
+ {
+ 	struct leaf_info *li;
+@@ -1876,7 +1839,7 @@ static int fn_trie_dump_leaf(struct leaf
+ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
+ 		   struct netlink_callback *cb)
+ {
+-	struct leaf *l;
++	struct tnode *l;
+ 	struct trie *t = (struct trie *) tb->tb_data;
+ 	t_key key = cb->args[2];
+ 	int count = cb->args[3];
+@@ -1922,7 +1885,7 @@ void __init fib_trie_init(void)
+ 					  0, SLAB_PANIC, NULL);
+ 
+ 	trie_leaf_kmem = kmem_cache_create("ip_fib_trie",
+-					   max(sizeof(struct leaf),
++					   max(sizeof(struct tnode),
+ 					       sizeof(struct leaf_info)),
+ 					   0, SLAB_PANIC, NULL);
+ }
+@@ -1965,7 +1928,7 @@ struct fib_trie_iter {
+ 	unsigned int depth;
+ };
+ 
+-static struct rt_trie_node *fib_trie_get_next(struct fib_trie_iter *iter)
++static struct tnode *fib_trie_get_next(struct fib_trie_iter *iter)
+ {
+ 	struct tnode *tn = iter->tnode;
+ 	unsigned int cindex = iter->index;
+@@ -1979,7 +1942,7 @@ static struct rt_trie_node *fib_trie_get
+ 		 iter->tnode, iter->index, iter->depth);
+ rescan:
+ 	while (cindex < (1<<tn->bits)) {
+-		struct rt_trie_node *n = tnode_get_child_rcu(tn, cindex);
++		struct tnode *n = tnode_get_child_rcu(tn, cindex);
+ 
+ 		if (n) {
+ 			if (IS_LEAF(n)) {
+@@ -1987,7 +1950,7 @@ rescan:
+ 				iter->index = cindex + 1;
+ 			} else {
+ 				/* push down one level */
+-				iter->tnode = (struct tnode *) n;
++				iter->tnode = n;
+ 				iter->index = 0;
+ 				++iter->depth;
+ 			}
+@@ -1998,7 +1961,7 @@ rescan:
+ 	}
+ 
+ 	/* Current node exhausted, pop back up */
+-	p = node_parent_rcu((struct rt_trie_node *)tn);
++	p = node_parent_rcu(tn);
+ 	if (p) {
+ 		cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
+ 		tn = p;
+@@ -2010,10 +1973,10 @@ rescan:
+ 	return NULL;
+ }
+ 
+-static struct rt_trie_node *fib_trie_get_first(struct fib_trie_iter *iter,
++static struct tnode *fib_trie_get_first(struct fib_trie_iter *iter,
+ 				       struct trie *t)
+ {
+-	struct rt_trie_node *n;
++	struct tnode *n;
+ 
+ 	if (!t)
+ 		return NULL;
+@@ -2023,7 +1986,7 @@ static struct rt_trie_node *fib_trie_get
+ 		return NULL;
+ 
+ 	if (IS_TNODE(n)) {
+-		iter->tnode = (struct tnode *) n;
++		iter->tnode = n;
+ 		iter->index = 0;
+ 		iter->depth = 1;
+ 	} else {
+@@ -2037,7 +2000,7 @@ static struct rt_trie_node *fib_trie_get
+ 
+ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
+ {
+-	struct rt_trie_node *n;
++	struct tnode *n;
+ 	struct fib_trie_iter iter;
+ 
+ 	memset(s, 0, sizeof(*s));
+@@ -2045,7 +2008,6 @@ static void trie_collect_stats(struct tr
+ 	rcu_read_lock();
+ 	for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) {
+ 		if (IS_LEAF(n)) {
+-			struct leaf *l = (struct leaf *)n;
+ 			struct leaf_info *li;
+ 
+ 			s->leaves++;
+@@ -2053,18 +2015,17 @@ static void trie_collect_stats(struct tr
+ 			if (iter.depth > s->maxdepth)
+ 				s->maxdepth = iter.depth;
+ 
+-			hlist_for_each_entry_rcu(li, &l->list, hlist)
++			hlist_for_each_entry_rcu(li, &n->list, hlist)
+ 				++s->prefixes;
+ 		} else {
+-			const struct tnode *tn = (const struct tnode *) n;
+ 			int i;
+ 
+ 			s->tnodes++;
+-			if (tn->bits < MAX_STAT_DEPTH)
+-				s->nodesizes[tn->bits]++;
++			if (n->bits < MAX_STAT_DEPTH)
++				s->nodesizes[n->bits]++;
+ 
+-			for (i = 0; i < (1<<tn->bits); i++)
+-				if (!tn->child[i])
++			for (i = 0; i < tnode_child_length(n); i++)
++				if (!rcu_access_pointer(n->child[i]))
+ 					s->nullpointers++;
+ 		}
+ 	}
+@@ -2088,7 +2049,7 @@ static void trie_show_stats(struct seq_f
+ 	seq_printf(seq, "\tMax depth:      %u\n", stat->maxdepth);
+ 
+ 	seq_printf(seq, "\tLeaves:         %u\n", stat->leaves);
+-	bytes = sizeof(struct leaf) * stat->leaves;
++	bytes = sizeof(struct tnode) * stat->leaves;
+ 
+ 	seq_printf(seq, "\tPrefixes:       %u\n", stat->prefixes);
+ 	bytes += sizeof(struct leaf_info) * stat->prefixes;
+@@ -2109,7 +2070,7 @@ static void trie_show_stats(struct seq_f
+ 	seq_putc(seq, '\n');
+ 	seq_printf(seq, "\tPointers: %u\n", pointers);
+ 
+-	bytes += sizeof(struct rt_trie_node *) * pointers;
++	bytes += sizeof(struct tnode *) * pointers;
+ 	seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers);
+ 	seq_printf(seq, "Total size: %u  kB\n", (bytes + 1023) / 1024);
+ }
+@@ -2163,7 +2124,7 @@ static int fib_triestat_seq_show(struct
+ 	seq_printf(seq,
+ 		   "Basic info: size of leaf:"
+ 		   " %Zd bytes, size of tnode: %Zd bytes.\n",
+-		   sizeof(struct leaf), sizeof(struct tnode));
++		   sizeof(struct tnode), sizeof(struct tnode));
+ 
+ 	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+ 		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+@@ -2202,7 +2163,7 @@ static const struct file_operations fib_
+ 	.release = single_release_net,
+ };
+ 
+-static struct rt_trie_node *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
++static struct tnode *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
+ {
+ 	struct fib_trie_iter *iter = seq->private;
+ 	struct net *net = seq_file_net(seq);
+@@ -2214,7 +2175,7 @@ static struct rt_trie_node *fib_trie_get
+ 		struct fib_table *tb;
+ 
+ 		hlist_for_each_entry_rcu(tb, head, tb_hlist) {
+-			struct rt_trie_node *n;
++			struct tnode *n;
+ 
+ 			for (n = fib_trie_get_first(iter,
+ 						    (struct trie *) tb->tb_data);
+@@ -2243,7 +2204,7 @@ static void *fib_trie_seq_next(struct se
+ 	struct fib_table *tb = iter->tb;
+ 	struct hlist_node *tb_node;
+ 	unsigned int h;
+-	struct rt_trie_node *n;
++	struct tnode *n;
+ 
+ 	++*pos;
+ 	/* next node in same table */
+@@ -2329,29 +2290,26 @@ static inline const char *rtn_type(char
+ static int fib_trie_seq_show(struct seq_file *seq, void *v)
+ {
+ 	const struct fib_trie_iter *iter = seq->private;
+-	struct rt_trie_node *n = v;
++	struct tnode *n = v;
+ 
+ 	if (!node_parent_rcu(n))
+ 		fib_table_print(seq, iter->tb);
+ 
+ 	if (IS_TNODE(n)) {
+-		struct tnode *tn = (struct tnode *) n;
+-		__be32 prf = htonl(tn->key);
++		__be32 prf = htonl(n->key);
+ 
+-		seq_indent(seq, iter->depth-1);
++		seq_indent(seq, iter->depth - 1);
+ 		seq_printf(seq, "  +-- %pI4/%d %d %d %d\n",
+-			   &prf, tn->pos, tn->bits, tn->full_children,
+-			   tn->empty_children);
+-
++			   &prf, n->pos, n->bits, n->full_children,
++			   n->empty_children);
+ 	} else {
+-		struct leaf *l = (struct leaf *) n;
+ 		struct leaf_info *li;
+-		__be32 val = htonl(l->key);
++		__be32 val = htonl(n->key);
+ 
+ 		seq_indent(seq, iter->depth);
+ 		seq_printf(seq, "  |-- %pI4\n", &val);
+ 
+-		hlist_for_each_entry_rcu(li, &l->list, hlist) {
++		hlist_for_each_entry_rcu(li, &n->list, hlist) {
+ 			struct fib_alias *fa;
+ 
+ 			list_for_each_entry_rcu(fa, &li->falh, fa_list) {
+@@ -2401,9 +2359,9 @@ struct fib_route_iter {
+ 	t_key	key;
+ };
+ 
+-static struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos)
++static struct tnode *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos)
+ {
+-	struct leaf *l = NULL;
++	struct tnode *l = NULL;
+ 	struct trie *t = iter->main_trie;
+ 
+ 	/* use cache location of last found key */
+@@ -2448,7 +2406,7 @@ static void *fib_route_seq_start(struct
+ static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ {
+ 	struct fib_route_iter *iter = seq->private;
+-	struct leaf *l = v;
++	struct tnode *l = v;
+ 
+ 	++*pos;
+ 	if (v == SEQ_START_TOKEN) {
+@@ -2494,7 +2452,7 @@ static unsigned int fib_flag_trans(int t
+  */
+ static int fib_route_seq_show(struct seq_file *seq, void *v)
+ {
+-	struct leaf *l = v;
++	struct tnode *l = v;
+ 	struct leaf_info *li;
+ 
+ 	if (v == SEQ_START_TOKEN) {
diff --git a/target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch b/target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch
new file mode 100644
index 0000000000..e84412687d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-06-fib_trie-Optimize-fib_table_lookup-to-avoid-wasting-.patch
@@ -0,0 +1,343 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:55:54 -0800
+Subject: [PATCH] fib_trie: Optimize fib_table_lookup to avoid wasting
+ time on loops/variables
+
+This patch is meant to reduce the complexity of fib_table_lookup by reducing
+the number of variables to the bare minimum while still keeping the same if
+not improved functionality versus the original.
+
+Most of this change was started off by the desire to rid the function of
+chopped_off and current_prefix_length as they actually added very little to
+the function since they only applied when computing the cindex.  I was able
+to replace them mostly with just a check for the prefix match.  As long as
+the prefix between the key and the node being tested was the same we know
+we can search the tnode fully versus just testing cindex 0.
+
+The second portion of the change ended up being a massive reordering.
+Originally the calls to check_leaf were up near the start of the loop, and
+the backtracing and descending into lower levels of tnodes was later.  This
+didn't make much sense as the structure of the tree means the leaves are
+always the last thing to be tested.  As such I reordered things so that we
+instead have a loop that will delve into the tree and only exit when we
+have either found a leaf or we have exhausted the tree.  The advantage of
+rearranging things like this is that we can fully inline check_leaf since
+there is now only one reference to it in the function.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -90,6 +90,9 @@ typedef unsigned int t_key;
+ #define IS_TNODE(n) ((n)->bits)
+ #define IS_LEAF(n) (!(n)->bits)
+ 
++#define get_shift(_kv) (KEYLENGTH - (_kv)->pos - (_kv)->bits)
++#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> get_shift(_kv))
++
+ struct tnode {
+ 	t_key key;
+ 	unsigned char bits;		/* 2log(KEYLENGTH) bits needed */
+@@ -1281,7 +1284,7 @@ static int check_leaf(struct fib_table *
+ 				continue;
+ 			fib_alias_accessed(fa);
+ 			err = fib_props[fa->fa_type].error;
+-			if (err) {
++			if (unlikely(err < 0)) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 				this_cpu_inc(t->stats->semantic_match_passed);
+ #endif
+@@ -1303,7 +1306,7 @@ static int check_leaf(struct fib_table *
+ 				res->prefixlen = li->plen;
+ 				res->nh_sel = nhsel;
+ 				res->type = fa->fa_type;
+-				res->scope = fa->fa_info->fib_scope;
++				res->scope = fi->fib_scope;
+ 				res->fi = fi;
+ 				res->table = tb;
+ 				res->fa_head = &li->falh;
+@@ -1321,23 +1324,24 @@ static int check_leaf(struct fib_table *
+ 	return 1;
+ }
+ 
++static inline t_key prefix_mismatch(t_key key, struct tnode *n)
++{
++	t_key prefix = n->key;
++
++	return (key ^ prefix) & (prefix | -prefix);
++}
++
+ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
+ 		     struct fib_result *res, int fib_flags)
+ {
+-	struct trie *t = (struct trie *) tb->tb_data;
++	struct trie *t = (struct trie *)tb->tb_data;
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 	struct trie_use_stats __percpu *stats = t->stats;
+ #endif
+-	int ret;
+-	struct tnode *n;
+-	struct tnode *pn;
+-	unsigned int pos, bits;
+-	t_key key = ntohl(flp->daddr);
+-	unsigned int chopped_off;
+-	t_key cindex = 0;
+-	unsigned int current_prefix_length = KEYLENGTH;
+-	struct tnode *cn;
+-	t_key pref_mismatch;
++	const t_key key = ntohl(flp->daddr);
++	struct tnode *n, *pn;
++	t_key cindex;
++	int ret = 1;
+ 
+ 	rcu_read_lock();
+ 
+@@ -1349,170 +1353,102 @@ int fib_table_lookup(struct fib_table *t
+ 	this_cpu_inc(stats->gets);
+ #endif
+ 
+-	/* Just a leaf? */
+-	if (IS_LEAF(n)) {
+-		ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
+-		goto found;
+-	}
+-
+ 	pn = n;
+-	chopped_off = 0;
+-
+-	while (pn) {
+-		pos = pn->pos;
+-		bits = pn->bits;
++	cindex = 0;
+ 
+-		if (!chopped_off)
+-			cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
+-						   pos, bits);
+-
+-		n = tnode_get_child_rcu(pn, cindex);
+-
+-		if (n == NULL) {
+-#ifdef CONFIG_IP_FIB_TRIE_STATS
+-			this_cpu_inc(stats->null_node_hit);
+-#endif
+-			goto backtrace;
+-		}
++	/* Step 1: Travel to the longest prefix match in the trie */
++	for (;;) {
++		unsigned long index = get_index(key, n);
++
++		/* This bit of code is a bit tricky but it combines multiple
++		 * checks into a single check.  The prefix consists of the
++		 * prefix plus zeros for the "bits" in the prefix. The index
++		 * is the difference between the key and this value.  From
++		 * this we can actually derive several pieces of data.
++		 *   if !(index >> bits)
++		 *     we know the value is child index
++		 *   else
++		 *     we have a mismatch in skip bits and failed
++		 */
++		if (index >> n->bits)
++			break;
+ 
+-		if (IS_LEAF(n)) {
+-			ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
+-			if (ret > 0)
+-				goto backtrace;
++		/* we have found a leaf. Prefixes have already been compared */
++		if (IS_LEAF(n))
+ 			goto found;
+-		}
+-
+-		cn = n;
+ 
+-		/*
+-		 * It's a tnode, and we can do some extra checks here if we
+-		 * like, to avoid descending into a dead-end branch.
+-		 * This tnode is in the parent's child array at index
+-		 * key[p_pos..p_pos+p_bits] but potentially with some bits
+-		 * chopped off, so in reality the index may be just a
+-		 * subprefix, padded with zero at the end.
+-		 * We can also take a look at any skipped bits in this
+-		 * tnode - everything up to p_pos is supposed to be ok,
+-		 * and the non-chopped bits of the index (se previous
+-		 * paragraph) are also guaranteed ok, but the rest is
+-		 * considered unknown.
+-		 *
+-		 * The skipped bits are key[pos+bits..cn->pos].
+-		 */
+-
+-		/* If current_prefix_length < pos+bits, we are already doing
+-		 * actual prefix  matching, which means everything from
+-		 * pos+(bits-chopped_off) onward must be zero along some
+-		 * branch of this subtree - otherwise there is *no* valid
+-		 * prefix present. Here we can only check the skipped
+-		 * bits. Remember, since we have already indexed into the
+-		 * parent's child array, we know that the bits we chopped of
+-		 * *are* zero.
++		/* only record pn and cindex if we are going to be chopping
++		 * bits later.  Otherwise we are just wasting cycles.
+ 		 */
+-
+-		/* NOTA BENE: Checking only skipped bits
+-		   for the new node here */
+-
+-		if (current_prefix_length < pos+bits) {
+-			if (tkey_extract_bits(cn->key, current_prefix_length,
+-						cn->pos - current_prefix_length)
+-			    || !(cn->child[0]))
+-				goto backtrace;
++		if (index) {
++			pn = n;
++			cindex = index;
+ 		}
+ 
+-		/*
+-		 * If chopped_off=0, the index is fully validated and we
+-		 * only need to look at the skipped bits for this, the new,
+-		 * tnode. What we actually want to do is to find out if
+-		 * these skipped bits match our key perfectly, or if we will
+-		 * have to count on finding a matching prefix further down,
+-		 * because if we do, we would like to have some way of
+-		 * verifying the existence of such a prefix at this point.
+-		 */
+-
+-		/* The only thing we can do at this point is to verify that
+-		 * any such matching prefix can indeed be a prefix to our
+-		 * key, and if the bits in the node we are inspecting that
+-		 * do not match our key are not ZERO, this cannot be true.
+-		 * Thus, find out where there is a mismatch (before cn->pos)
+-		 * and verify that all the mismatching bits are zero in the
+-		 * new tnode's key.
+-		 */
++		n = rcu_dereference(n->child[index]);
++		if (unlikely(!n))
++			goto backtrace;
++	}
+ 
+-		/*
+-		 * Note: We aren't very concerned about the piece of
+-		 * the key that precede pn->pos+pn->bits, since these
+-		 * have already been checked. The bits after cn->pos
+-		 * aren't checked since these are by definition
+-		 * "unknown" at this point. Thus, what we want to see
+-		 * is if we are about to enter the "prefix matching"
+-		 * state, and in that case verify that the skipped
+-		 * bits that will prevail throughout this subtree are
+-		 * zero, as they have to be if we are to find a
+-		 * matching prefix.
++	/* Step 2: Sort out leaves and begin backtracing for longest prefix */
++	for (;;) {
++		/* record the pointer where our next node pointer is stored */
++		struct tnode __rcu **cptr = n->child;
++
++		/* This test verifies that none of the bits that differ
++		 * between the key and the prefix exist in the region of
++		 * the lsb and higher in the prefix.
+ 		 */
++		if (unlikely(prefix_mismatch(key, n)))
++			goto backtrace;
+ 
+-		pref_mismatch = mask_pfx(cn->key ^ key, cn->pos);
++		/* exit out and process leaf */
++		if (unlikely(IS_LEAF(n)))
++			break;
+ 
+-		/*
+-		 * In short: If skipped bits in this node do not match
+-		 * the search key, enter the "prefix matching"
+-		 * state.directly.
++		/* Don't bother recording parent info.  Since we are in
++		 * prefix match mode we will have to come back to wherever
++		 * we started this traversal anyway
+ 		 */
+-		if (pref_mismatch) {
+-			/* fls(x) = __fls(x) + 1 */
+-			int mp = KEYLENGTH - __fls(pref_mismatch) - 1;
+-
+-			if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
+-				goto backtrace;
+-
+-			if (current_prefix_length >= cn->pos)
+-				current_prefix_length = mp;
+-		}
+-
+-		pn = n; /* Descend */
+-		chopped_off = 0;
+-		continue;
+ 
++		while ((n = rcu_dereference(*cptr)) == NULL) {
+ backtrace:
+-		chopped_off++;
+-
+-		/* As zero don't change the child key (cindex) */
+-		while ((chopped_off <= pn->bits)
+-		       && !(cindex & (1<<(chopped_off-1))))
+-			chopped_off++;
+-
+-		/* Decrease current_... with bits chopped off */
+-		if (current_prefix_length > pn->pos + pn->bits - chopped_off)
+-			current_prefix_length = pn->pos + pn->bits
+-				- chopped_off;
+-
+-		/*
+-		 * Either we do the actual chop off according or if we have
+-		 * chopped off all bits in this tnode walk up to our parent.
+-		 */
+-
+-		if (chopped_off <= pn->bits) {
+-			cindex &= ~(1 << (chopped_off-1));
+-		} else {
+-			struct tnode *parent = node_parent_rcu(pn);
+-			if (!parent)
+-				goto failed;
+-
+-			/* Get Child's index */
+-			cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits);
+-			pn = parent;
+-			chopped_off = 0;
+-
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+-			this_cpu_inc(stats->backtrack);
++			if (!n)
++				this_cpu_inc(stats->null_node_hit);
+ #endif
+-			goto backtrace;
++			/* If we are at cindex 0 there are no more bits for
++			 * us to strip at this level so we must ascend back
++			 * up one level to see if there are any more bits to
++			 * be stripped there.
++			 */
++			while (!cindex) {
++				t_key pkey = pn->key;
++
++				pn = node_parent_rcu(pn);
++				if (unlikely(!pn))
++					goto failed;
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++				this_cpu_inc(stats->backtrack);
++#endif
++				/* Get Child's index */
++				cindex = get_index(pkey, pn);
++			}
++
++			/* strip the least significant bit from the cindex */
++			cindex &= cindex - 1;
++
++			/* grab pointer for next child node */
++			cptr = &pn->child[cindex];
+ 		}
+ 	}
+-failed:
+-	ret = 1;
++
+ found:
++	/* Step 3: Process the leaf, if that fails fall back to backtracing */
++	ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
++	if (unlikely(ret > 0))
++		goto backtrace;
++failed:
+ 	rcu_read_unlock();
+ 	return ret;
+ }
diff --git a/target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch b/target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch
new file mode 100644
index 0000000000..0193f758f6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-07-fib_trie-Optimize-fib_find_node.patch
@@ -0,0 +1,64 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:00 -0800
+Subject: [PATCH] fib_trie: Optimize fib_find_node
+
+This patch makes use of the same features I made use of for
+fib_table_lookup to streamline fib_find_node.  The resultant code should be
+smaller and run faster than the original.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -892,28 +892,34 @@ static void insert_leaf_info(struct hlis
+ }
+ 
+ /* rcu_read_lock needs to be hold by caller from readside */
+-
+ static struct tnode *fib_find_node(struct trie *t, u32 key)
+ {
+ 	struct tnode *n = rcu_dereference_rtnl(t->trie);
+-	int pos = 0;
+ 
+-	while (n && IS_TNODE(n)) {
+-		if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
+-			pos = n->pos + n->bits;
+-			n = tnode_get_child_rcu(n,
+-						tkey_extract_bits(key,
+-								  n->pos,
+-								  n->bits));
+-		} else
++	while (n) {
++		unsigned long index = get_index(key, n);
++
++		/* This bit of code is a bit tricky but it combines multiple
++		 * checks into a single check.  The prefix consists of the
++		 * prefix plus zeros for the bits in the cindex. The index
++		 * is the difference between the key and this value.  From
++		 * this we can actually derive several pieces of data.
++		 *   if !(index >> bits)
++		 *     we know the value is cindex
++		 *   else
++		 *     we have a mismatch in skip bits and failed
++		 */
++		if (index >> n->bits)
++			return NULL;
++
++		/* we have found a leaf. Prefixes have already been compared */
++		if (IS_LEAF(n))
+ 			break;
+-	}
+-	/* Case we have found a leaf. Compare prefixes */
+ 
+-	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
+-		return n;
++		n = rcu_dereference_rtnl(n->child[index]);
++	}
+ 
+-	return NULL;
++	return n;
+ }
+ 
+ static void trie_rebalance(struct trie *t, struct tnode *tn)
diff --git a/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch b/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch
new file mode 100644
index 0000000000..b328d2c5d2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-08-fib_trie-Optimize-fib_table_insert.patch
@@ -0,0 +1,276 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:06 -0800
+Subject: [PATCH] fib_trie: Optimize fib_table_insert
+
+This patch updates the fib_table_insert function to take advantage of the
+changes made to improve the performance of fib_table_lookup.  As a result
+the code should be smaller and run faster then the original.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -222,31 +222,6 @@ static inline t_key tkey_extract_bits(t_
+ 		return 0;
+ }
+ 
+-static inline int tkey_equals(t_key a, t_key b)
+-{
+-	return a == b;
+-}
+-
+-static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
+-{
+-	if (bits == 0 || offset >= KEYLENGTH)
+-		return 1;
+-	bits = bits > KEYLENGTH ? KEYLENGTH : bits;
+-	return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
+-}
+-
+-static inline int tkey_mismatch(t_key a, int offset, t_key b)
+-{
+-	t_key diff = a ^ b;
+-	int i = offset;
+-
+-	if (!diff)
+-		return 0;
+-	while ((diff << i) >> (KEYLENGTH-1) == 0)
+-		i++;
+-	return i;
+-}
+-
+ /*
+   To understand this stuff, an understanding of keys and all their bits is
+   necessary. Every node in the trie has a key associated with it, but not
+@@ -485,6 +460,15 @@ static void tnode_put_child_reorg(struct
+ 	rcu_assign_pointer(tn->child[i], n);
+ }
+ 
++static void put_child_root(struct tnode *tp, struct trie *t,
++			   t_key key, struct tnode *n)
++{
++	if (tp)
++		put_child(tp, get_index(key, tp), n);
++	else
++		rcu_assign_pointer(t->trie, n);
++}
++
+ #define MAX_WORK 10
+ static struct tnode *resize(struct trie *t, struct tnode *tn)
+ {
+@@ -959,138 +943,100 @@ static void trie_rebalance(struct trie *
+ 
+ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
+ {
+-	int pos, newpos;
+-	struct tnode *tp = NULL, *tn = NULL;
+-	struct tnode *n;
+-	struct tnode *l;
+-	int missbit;
+ 	struct list_head *fa_head = NULL;
++	struct tnode *l, *n, *tp = NULL;
+ 	struct leaf_info *li;
+-	t_key cindex;
+ 
+-	pos = 0;
++	li = leaf_info_new(plen);
++	if (!li)
++		return NULL;
++	fa_head = &li->falh;
++
+ 	n = rtnl_dereference(t->trie);
+ 
+ 	/* If we point to NULL, stop. Either the tree is empty and we should
+ 	 * just put a new leaf in if, or we have reached an empty child slot,
+ 	 * and we should just put our new leaf in that.
+-	 * If we point to a T_TNODE, check if it matches our key. Note that
+-	 * a T_TNODE might be skipping any number of bits - its 'pos' need
+-	 * not be the parent's 'pos'+'bits'!
+-	 *
+-	 * If it does match the current key, get pos/bits from it, extract
+-	 * the index from our key, push the T_TNODE and walk the tree.
+-	 *
+-	 * If it doesn't, we have to replace it with a new T_TNODE.
+ 	 *
+-	 * If we point to a T_LEAF, it might or might not have the same key
+-	 * as we do. If it does, just change the value, update the T_LEAF's
+-	 * value, and return it.
+-	 * If it doesn't, we need to replace it with a T_TNODE.
++	 * If we hit a node with a key that does't match then we should stop
++	 * and create a new tnode to replace that node and insert ourselves
++	 * and the other node into the new tnode.
+ 	 */
++	while (n) {
++		unsigned long index = get_index(key, n);
+ 
+-	while (n && IS_TNODE(n)) {
+-		if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
+-			tp = n;
+-			pos = n->pos + n->bits;
+-			n = tnode_get_child(n,
+-					    tkey_extract_bits(key,
+-							      n->pos,
+-							      n->bits));
+-
+-			BUG_ON(n && node_parent(n) != tp);
+-		} else
++		/* This bit of code is a bit tricky but it combines multiple
++		 * checks into a single check.  The prefix consists of the
++		 * prefix plus zeros for the "bits" in the prefix. The index
++		 * is the difference between the key and this value.  From
++		 * this we can actually derive several pieces of data.
++		 *   if !(index >> bits)
++		 *     we know the value is child index
++		 *   else
++		 *     we have a mismatch in skip bits and failed
++		 */
++		if (index >> n->bits)
+ 			break;
+-	}
+-
+-	/*
+-	 * n  ----> NULL, LEAF or TNODE
+-	 *
+-	 * tp is n's (parent) ----> NULL or TNODE
+-	 */
+ 
+-	BUG_ON(tp && IS_LEAF(tp));
+-
+-	/* Case 1: n is a leaf. Compare prefixes */
+-
+-	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
+-		li = leaf_info_new(plen);
+-
+-		if (!li)
+-			return NULL;
++		/* we have found a leaf. Prefixes have already been compared */
++		if (IS_LEAF(n)) {
++			/* Case 1: n is a leaf, and prefixes match*/
++			insert_leaf_info(&n->list, li);
++			return fa_head;
++		}
+ 
+-		fa_head = &li->falh;
+-		insert_leaf_info(&n->list, li);
+-		goto done;
++		tp = n;
++		n = rcu_dereference_rtnl(n->child[index]);
+ 	}
+-	l = leaf_new(key);
+-
+-	if (!l)
+-		return NULL;
+ 
+-	li = leaf_info_new(plen);
+-
+-	if (!li) {
+-		node_free(l);
++	l = leaf_new(key);
++	if (!l) {
++		free_leaf_info(li);
+ 		return NULL;
+ 	}
+ 
+-	fa_head = &li->falh;
+ 	insert_leaf_info(&l->list, li);
+ 
+-	if (t->trie && n == NULL) {
+-		/* Case 2: n is NULL, and will just insert a new leaf */
+-
+-		node_set_parent(l, tp);
+-
+-		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+-		put_child(tp, cindex, l);
+-	} else {
+-		/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
+-		/*
+-		 *  Add a new tnode here
+-		 *  first tnode need some special handling
+-		 */
++	/* Case 2: n is a LEAF or a TNODE and the key doesn't match.
++	 *
++	 *  Add a new tnode here
++	 *  first tnode need some special handling
++	 *  leaves us in position for handling as case 3
++	 */
++	if (n) {
++		struct tnode *tn;
++		int newpos;
+ 
+-		if (n) {
+-			pos = tp ? tp->pos+tp->bits : 0;
+-			newpos = tkey_mismatch(key, pos, n->key);
+-			tn = tnode_new(n->key, newpos, 1);
+-		} else {
+-			newpos = 0;
+-			tn = tnode_new(key, newpos, 1); /* First tnode */
+-		}
++		newpos = KEYLENGTH - __fls(n->key ^ key) - 1;
+ 
++		tn = tnode_new(key, newpos, 1);
+ 		if (!tn) {
+ 			free_leaf_info(li);
+ 			node_free(l);
+ 			return NULL;
+ 		}
+ 
+-		node_set_parent(tn, tp);
+-
+-		missbit = tkey_extract_bits(key, newpos, 1);
+-		put_child(tn, missbit, l);
+-		put_child(tn, 1-missbit, n);
+-
+-		if (tp) {
+-			cindex = tkey_extract_bits(key, tp->pos, tp->bits);
+-			put_child(tp, cindex, tn);
+-		} else {
+-			rcu_assign_pointer(t->trie, tn);
+-		}
++		/* initialize routes out of node */
++		NODE_INIT_PARENT(tn, tp);
++		put_child(tn, get_index(key, tn) ^ 1, n);
++
++		/* start adding routes into the node */
++		put_child_root(tp, t, key, tn);
++		node_set_parent(n, tn);
+ 
++		/* parent now has a NULL spot where the leaf can go */
+ 		tp = tn;
+ 	}
+ 
+-	if (tp && tp->pos + tp->bits > 32)
+-		pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
+-			tp, tp->pos, tp->bits, key, plen);
+-
+-	/* Rebalance the trie */
++	/* Case 3: n is NULL, and will just insert a new leaf */
++	if (tp) {
++		NODE_INIT_PARENT(l, tp);
++		put_child(tp, get_index(key, tp), l);
++		trie_rebalance(t, tp);
++	} else {
++		rcu_assign_pointer(t->trie, l);
++	}
+ 
+-	trie_rebalance(t, tp);
+-done:
+ 	return fa_head;
+ }
+ 
+@@ -1470,11 +1416,11 @@ static void trie_leaf_remove(struct trie
+ 	pr_debug("entering trie_leaf_remove(%p)\n", l);
+ 
+ 	if (tp) {
+-		t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
+-		put_child(tp, cindex, NULL);
++		put_child(tp, get_index(l->key, tp), NULL);
+ 		trie_rebalance(t, tp);
+-	} else
++	} else {
+ 		RCU_INIT_POINTER(t->trie, NULL);
++	}
+ 
+ 	node_free(l);
+ }
diff --git a/target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch b/target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch
new file mode 100644
index 0000000000..a0d34762b8
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-09-fib_trie-Update-meaning-of-pos-to-represent-unchecke.patch
@@ -0,0 +1,346 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:12 -0800
+Subject: [PATCH] fib_trie: Update meaning of pos to represent unchecked
+ bits
+
+This change moves the pos value to the other side of the "bits" field.  By
+doing this it actually simplifies a significant amount of code in the trie.
+
+For example when halving a tree we know that the bit lost exists at
+oldnode->pos, and if we inflate the tree the new bit being add is at
+tn->pos.  Previously to find those bits you would have to subtract pos and
+bits from the keylength or start with a value of (1 << 31) and then shift
+that.
+
+There are a number of spots throughout the code that benefit from this.  In
+the case of the hot-path searches the main advantage is that we can drop 2
+or more operations from the search path as we no longer need to compute the
+value for the index to be shifted by and can instead just use the raw pos
+value.
+
+In addition the tkey_extract_bits is now defunct and can be replaced by
+get_index since the two operations were doing the same thing, but now
+get_index does it much more quickly as it is only an xor and shift versus a
+pair of shifts and a subtraction.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -90,8 +90,7 @@ typedef unsigned int t_key;
+ #define IS_TNODE(n) ((n)->bits)
+ #define IS_LEAF(n) (!(n)->bits)
+ 
+-#define get_shift(_kv) (KEYLENGTH - (_kv)->pos - (_kv)->bits)
+-#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> get_shift(_kv))
++#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> (_kv)->pos)
+ 
+ struct tnode {
+ 	t_key key;
+@@ -209,81 +208,64 @@ static inline struct tnode *tnode_get_ch
+ 	return rcu_dereference_rtnl(tn->child[i]);
+ }
+ 
+-static inline t_key mask_pfx(t_key k, unsigned int l)
+-{
+-	return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
+-}
+-
+-static inline t_key tkey_extract_bits(t_key a, unsigned int offset, unsigned int bits)
+-{
+-	if (offset < KEYLENGTH)
+-		return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
+-	else
+-		return 0;
+-}
+-
+-/*
+-  To understand this stuff, an understanding of keys and all their bits is
+-  necessary. Every node in the trie has a key associated with it, but not
+-  all of the bits in that key are significant.
+-
+-  Consider a node 'n' and its parent 'tp'.
+-
+-  If n is a leaf, every bit in its key is significant. Its presence is
+-  necessitated by path compression, since during a tree traversal (when
+-  searching for a leaf - unless we are doing an insertion) we will completely
+-  ignore all skipped bits we encounter. Thus we need to verify, at the end of
+-  a potentially successful search, that we have indeed been walking the
+-  correct key path.
+-
+-  Note that we can never "miss" the correct key in the tree if present by
+-  following the wrong path. Path compression ensures that segments of the key
+-  that are the same for all keys with a given prefix are skipped, but the
+-  skipped part *is* identical for each node in the subtrie below the skipped
+-  bit! trie_insert() in this implementation takes care of that - note the
+-  call to tkey_sub_equals() in trie_insert().
+-
+-  if n is an internal node - a 'tnode' here, the various parts of its key
+-  have many different meanings.
+-
+-  Example:
+-  _________________________________________________________________
+-  | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
+-  -----------------------------------------------------------------
+-    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
+-
+-  _________________________________________________________________
+-  | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
+-  -----------------------------------------------------------------
+-   16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31
+-
+-  tp->pos = 7
+-  tp->bits = 3
+-  n->pos = 15
+-  n->bits = 4
+-
+-  First, let's just ignore the bits that come before the parent tp, that is
+-  the bits from 0 to (tp->pos-1). They are *known* but at this point we do
+-  not use them for anything.
+-
+-  The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
+-  index into the parent's child array. That is, they will be used to find
+-  'n' among tp's children.
+-
+-  The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits
+-  for the node n.
+-
+-  All the bits we have seen so far are significant to the node n. The rest
+-  of the bits are really not needed or indeed known in n->key.
+-
+-  The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
+-  n's child array, and will of course be different for each child.
+-
+-
+-  The rest of the bits, from (n->pos + n->bits) onward, are completely unknown
+-  at this point.
+-
+-*/
++/* To understand this stuff, an understanding of keys and all their bits is
++ * necessary. Every node in the trie has a key associated with it, but not
++ * all of the bits in that key are significant.
++ *
++ * Consider a node 'n' and its parent 'tp'.
++ *
++ * If n is a leaf, every bit in its key is significant. Its presence is
++ * necessitated by path compression, since during a tree traversal (when
++ * searching for a leaf - unless we are doing an insertion) we will completely
++ * ignore all skipped bits we encounter. Thus we need to verify, at the end of
++ * a potentially successful search, that we have indeed been walking the
++ * correct key path.
++ *
++ * Note that we can never "miss" the correct key in the tree if present by
++ * following the wrong path. Path compression ensures that segments of the key
++ * that are the same for all keys with a given prefix are skipped, but the
++ * skipped part *is* identical for each node in the subtrie below the skipped
++ * bit! trie_insert() in this implementation takes care of that.
++ *
++ * if n is an internal node - a 'tnode' here, the various parts of its key
++ * have many different meanings.
++ *
++ * Example:
++ * _________________________________________________________________
++ * | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
++ * -----------------------------------------------------------------
++ *  31  30  29  28  27  26  25  24  23  22  21  20  19  18  17  16
++ *
++ * _________________________________________________________________
++ * | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
++ * -----------------------------------------------------------------
++ *  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
++ *
++ * tp->pos = 22
++ * tp->bits = 3
++ * n->pos = 13
++ * n->bits = 4
++ *
++ * First, let's just ignore the bits that come before the parent tp, that is
++ * the bits from (tp->pos + tp->bits) to 31. They are *known* but at this
++ * point we do not use them for anything.
++ *
++ * The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
++ * index into the parent's child array. That is, they will be used to find
++ * 'n' among tp's children.
++ *
++ * The bits from (n->pos + n->bits) to (tn->pos - 1) - "S" - are skipped bits
++ * for the node n.
++ *
++ * All the bits we have seen so far are significant to the node n. The rest
++ * of the bits are really not needed or indeed known in n->key.
++ *
++ * The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
++ * n's child array, and will of course be different for each child.
++ *
++ * The rest of the bits, from 0 to (n->pos + n->bits), are completely unknown
++ * at this point.
++ */
+ 
+ static const int halve_threshold = 25;
+ static const int inflate_threshold = 50;
+@@ -367,7 +349,7 @@ static struct tnode *leaf_new(t_key key)
+ 		 * as the nodes are searched
+ 		 */
+ 		l->key = key;
+-		l->pos = KEYLENGTH;
++		l->pos = 0;
+ 		/* set bits to 0 indicating we are not a tnode */
+ 		l->bits = 0;
+ 
+@@ -400,7 +382,7 @@ static struct tnode *tnode_new(t_key key
+ 		tn->parent = NULL;
+ 		tn->pos = pos;
+ 		tn->bits = bits;
+-		tn->key = mask_pfx(key, pos);
++		tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
+ 		tn->full_children = 0;
+ 		tn->empty_children = 1<<bits;
+ 	}
+@@ -410,14 +392,12 @@ static struct tnode *tnode_new(t_key key
+ 	return tn;
+ }
+ 
+-/*
+- * Check whether a tnode 'n' is "full", i.e. it is an internal node
++/* Check whether a tnode 'n' is "full", i.e. it is an internal node
+  * and no bits are skipped. See discussion in dyntree paper p. 6
+  */
+-
+ static inline int tnode_full(const struct tnode *tn, const struct tnode *n)
+ {
+-	return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits));
++	return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
+ }
+ 
+ static inline void put_child(struct tnode *tn, int i,
+@@ -641,11 +621,12 @@ static struct tnode *inflate(struct trie
+ {
+ 	int olen = tnode_child_length(oldtnode);
+ 	struct tnode *tn;
++	t_key m;
+ 	int i;
+ 
+ 	pr_debug("In inflate\n");
+ 
+-	tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
++	tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1);
+ 
+ 	if (!tn)
+ 		return ERR_PTR(-ENOMEM);
+@@ -656,21 +637,18 @@ static struct tnode *inflate(struct trie
+ 	 * fails. In case of failure we return the oldnode and  inflate
+ 	 * of tnode is ignored.
+ 	 */
++	for (i = 0, m = 1u << tn->pos; i < olen; i++) {
++		struct tnode *inode = tnode_get_child(oldtnode, i);
+ 
+-	for (i = 0; i < olen; i++) {
+-		struct tnode *inode;
+-
+-		inode = tnode_get_child(oldtnode, i);
+-		if (tnode_full(oldtnode, inode) && inode->bits > 1) {
++		if (tnode_full(oldtnode, inode) && (inode->bits > 1)) {
+ 			struct tnode *left, *right;
+-			t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;
+ 
+-			left = tnode_new(inode->key&(~m), inode->pos + 1,
++			left = tnode_new(inode->key & ~m, inode->pos,
+ 					 inode->bits - 1);
+ 			if (!left)
+ 				goto nomem;
+ 
+-			right = tnode_new(inode->key|m, inode->pos + 1,
++			right = tnode_new(inode->key | m, inode->pos,
+ 					  inode->bits - 1);
+ 
+ 			if (!right) {
+@@ -694,9 +672,7 @@ static struct tnode *inflate(struct trie
+ 
+ 		/* A leaf or an internal node with skipped bits */
+ 		if (!tnode_full(oldtnode, inode)) {
+-			put_child(tn,
+-				tkey_extract_bits(inode->key, tn->pos, tn->bits),
+-				inode);
++			put_child(tn, get_index(inode->key, tn), inode);
+ 			continue;
+ 		}
+ 
+@@ -767,7 +743,7 @@ static struct tnode *halve(struct trie *
+ 
+ 	pr_debug("In halve\n");
+ 
+-	tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
++	tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1);
+ 
+ 	if (!tn)
+ 		return ERR_PTR(-ENOMEM);
+@@ -787,7 +763,7 @@ static struct tnode *halve(struct trie *
+ 		if (left && right) {
+ 			struct tnode *newn;
+ 
+-			newn = tnode_new(left->key, tn->pos + tn->bits, 1);
++			newn = tnode_new(left->key, oldtnode->pos, 1);
+ 
+ 			if (!newn)
+ 				goto nomem;
+@@ -915,7 +891,7 @@ static void trie_rebalance(struct trie *
+ 	key = tn->key;
+ 
+ 	while (tn != NULL && (tp = node_parent(tn)) != NULL) {
+-		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
++		cindex = get_index(key, tp);
+ 		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
+ 		tn = resize(t, tn);
+ 
+@@ -1005,11 +981,8 @@ static struct list_head *fib_insert_node
+ 	 */
+ 	if (n) {
+ 		struct tnode *tn;
+-		int newpos;
+-
+-		newpos = KEYLENGTH - __fls(n->key ^ key) - 1;
+ 
+-		tn = tnode_new(key, newpos, 1);
++		tn = tnode_new(key, __fls(key ^ n->key), 1);
+ 		if (!tn) {
+ 			free_leaf_info(li);
+ 			node_free(l);
+@@ -1559,12 +1532,7 @@ static int trie_flush_leaf(struct tnode
+ static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
+ {
+ 	do {
+-		t_key idx;
+-
+-		if (c)
+-			idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1;
+-		else
+-			idx = 0;
++		t_key idx = c ? idx = get_index(c->key, p) + 1 : 0;
+ 
+ 		while (idx < 1u << p->bits) {
+ 			c = tnode_get_child_rcu(p, idx++);
+@@ -1851,7 +1819,7 @@ rescan:
+ 	/* Current node exhausted, pop back up */
+ 	p = node_parent_rcu(tn);
+ 	if (p) {
+-		cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
++		cindex = get_index(tn->key, p) + 1;
+ 		tn = p;
+ 		--iter->depth;
+ 		goto rescan;
+@@ -2186,10 +2154,10 @@ static int fib_trie_seq_show(struct seq_
+ 	if (IS_TNODE(n)) {
+ 		__be32 prf = htonl(n->key);
+ 
+-		seq_indent(seq, iter->depth - 1);
+-		seq_printf(seq, "  +-- %pI4/%d %d %d %d\n",
+-			   &prf, n->pos, n->bits, n->full_children,
+-			   n->empty_children);
++		seq_indent(seq, iter->depth-1);
++		seq_printf(seq, "  +-- %pI4/%zu %u %u %u\n",
++			   &prf, KEYLENGTH - n->pos - n->bits, n->bits,
++			   n->full_children, n->empty_children);
+ 	} else {
+ 		struct leaf_info *li;
+ 		__be32 val = htonl(n->key);
diff --git a/target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch b/target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch
new file mode 100644
index 0000000000..487a25f0d9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-10-fib_trie-Use-unsigned-long-for-anything-dealing-with.patch
@@ -0,0 +1,186 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:18 -0800
+Subject: [PATCH] fib_trie: Use unsigned long for anything dealing with a
+ shift by bits
+
+This change makes it so that anything that can be shifted by, or compared
+to a value shifted by bits is updated to be an unsigned long.  This is
+mostly a precaution against an insanely huge address space that somehow
+starts coming close to the 2^32 root node size which would require
+something like 1.5 billion addresses.
+
+I chose unsigned long instead of unsigned long long since I do not believe
+it is possible to allocate a 32 bit tnode on a 32 bit system as the memory
+consumed would be 16GB + 28B which exceeds the addressible space for any
+one process.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -146,8 +146,8 @@ struct trie {
+ #endif
+ };
+ 
+-static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
+-				  int wasfull);
++static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
++				  struct tnode *n, int wasfull);
+ static struct tnode *resize(struct trie *t, struct tnode *tn);
+ static struct tnode *inflate(struct trie *t, struct tnode *tn);
+ static struct tnode *halve(struct trie *t, struct tnode *tn);
+@@ -183,25 +183,23 @@ static inline void node_set_parent(struc
+ /* This provides us with the number of children in this node, in the case of a
+  * leaf this will return 0 meaning none of the children are accessible.
+  */
+-static inline int tnode_child_length(const struct tnode *tn)
++static inline unsigned long tnode_child_length(const struct tnode *tn)
+ {
+ 	return (1ul << tn->bits) & ~(1ul);
+ }
+ 
+-/*
+- * caller must hold RTNL
+- */
+-static inline struct tnode *tnode_get_child(const struct tnode *tn, unsigned int i)
++/* caller must hold RTNL */
++static inline struct tnode *tnode_get_child(const struct tnode *tn,
++					    unsigned long i)
+ {
+ 	BUG_ON(i >= tnode_child_length(tn));
+ 
+ 	return rtnl_dereference(tn->child[i]);
+ }
+ 
+-/*
+- * caller must hold RCU read lock or RTNL
+- */
+-static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
++/* caller must hold RCU read lock or RTNL */
++static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn,
++						unsigned long i)
+ {
+ 	BUG_ON(i >= tnode_child_length(tn));
+ 
+@@ -400,7 +398,7 @@ static inline int tnode_full(const struc
+ 	return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
+ }
+ 
+-static inline void put_child(struct tnode *tn, int i,
++static inline void put_child(struct tnode *tn, unsigned long i,
+ 			     struct tnode *n)
+ {
+ 	tnode_put_child_reorg(tn, i, n, -1);
+@@ -411,13 +409,13 @@ static inline void put_child(struct tnod
+   * Update the value of full_children and empty_children.
+   */
+ 
+-static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
+-				  int wasfull)
++static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
++				  struct tnode *n, int wasfull)
+ {
+ 	struct tnode *chi = rtnl_dereference(tn->child[i]);
+ 	int isfull;
+ 
+-	BUG_ON(i >= 1<<tn->bits);
++	BUG_ON(i >= tnode_child_length(tn));
+ 
+ 	/* update emptyChildren */
+ 	if (n == NULL && chi != NULL)
+@@ -607,10 +605,10 @@ no_children:
+ static void tnode_clean_free(struct tnode *tn)
+ {
+ 	struct tnode *tofree;
+-	int i;
++	unsigned long i;
+ 
+ 	for (i = 0; i < tnode_child_length(tn); i++) {
+-		tofree = rtnl_dereference(tn->child[i]);
++		tofree = tnode_get_child(tn, i);
+ 		if (tofree)
+ 			node_free(tofree);
+ 	}
+@@ -619,10 +617,10 @@ static void tnode_clean_free(struct tnod
+ 
+ static struct tnode *inflate(struct trie *t, struct tnode *oldtnode)
+ {
+-	int olen = tnode_child_length(oldtnode);
++	unsigned long olen = tnode_child_length(oldtnode);
+ 	struct tnode *tn;
++	unsigned long i;
+ 	t_key m;
+-	int i;
+ 
+ 	pr_debug("In inflate\n");
+ 
+@@ -664,7 +662,7 @@ static struct tnode *inflate(struct trie
+ 	for (i = 0; i < olen; i++) {
+ 		struct tnode *inode = tnode_get_child(oldtnode, i);
+ 		struct tnode *left, *right;
+-		int size, j;
++		unsigned long size, j;
+ 
+ 		/* An empty child */
+ 		if (inode == NULL)
+@@ -737,7 +735,7 @@ nomem:
+ 
+ static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
+ {
+-	int olen = tnode_child_length(oldtnode);
++	unsigned long olen = tnode_child_length(oldtnode);
+ 	struct tnode *tn, *left, *right;
+ 	int i;
+ 
+@@ -1532,9 +1530,9 @@ static int trie_flush_leaf(struct tnode
+ static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
+ {
+ 	do {
+-		t_key idx = c ? idx = get_index(c->key, p) + 1 : 0;
++		unsigned long idx = c ? idx = get_index(c->key, p) + 1 : 0;
+ 
+-		while (idx < 1u << p->bits) {
++		while (idx < tnode_child_length(p)) {
+ 			c = tnode_get_child_rcu(p, idx++);
+ 			if (!c)
+ 				continue;
+@@ -1786,8 +1784,8 @@ struct fib_trie_iter {
+ 
+ static struct tnode *fib_trie_get_next(struct fib_trie_iter *iter)
+ {
++	unsigned long cindex = iter->index;
+ 	struct tnode *tn = iter->tnode;
+-	unsigned int cindex = iter->index;
+ 	struct tnode *p;
+ 
+ 	/* A single entry routing table */
+@@ -1797,7 +1795,7 @@ static struct tnode *fib_trie_get_next(s
+ 	pr_debug("get_next iter={node=%p index=%d depth=%d}\n",
+ 		 iter->tnode, iter->index, iter->depth);
+ rescan:
+-	while (cindex < (1<<tn->bits)) {
++	while (cindex < tnode_child_length(tn)) {
+ 		struct tnode *n = tnode_get_child_rcu(tn, cindex);
+ 
+ 		if (n) {
+@@ -1874,15 +1872,16 @@ static void trie_collect_stats(struct tr
+ 			hlist_for_each_entry_rcu(li, &n->list, hlist)
+ 				++s->prefixes;
+ 		} else {
+-			int i;
++			unsigned long i;
+ 
+ 			s->tnodes++;
+ 			if (n->bits < MAX_STAT_DEPTH)
+ 				s->nodesizes[n->bits]++;
+ 
+-			for (i = 0; i < tnode_child_length(n); i++)
++			for (i = 0; i < tnode_child_length(n); i++) {
+ 				if (!rcu_access_pointer(n->child[i]))
+ 					s->nullpointers++;
++			}
+ 		}
+ 	}
+ 	rcu_read_unlock();
diff --git a/target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch b/target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch
new file mode 100644
index 0000000000..fe55323a50
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch
@@ -0,0 +1,403 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:24 -0800
+Subject: [PATCH] fib_trie: Push rcu_read_lock/unlock to callers
+
+This change is to start cleaning up some of the rcu_read_lock/unlock
+handling.  I realized while reviewing the code there are several spots that
+I don't believe are being handled correctly or are masking warnings by
+locally calling rcu_read_lock/unlock instead of calling them at the correct
+level.
+
+A common example is a call to fib_get_table followed by fib_table_lookup.
+The rcu_read_lock/unlock ought to wrap both but there are several spots where
+they were not wrapped.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/include/net/ip_fib.h
++++ b/include/net/ip_fib.h
+@@ -222,16 +222,19 @@ static inline struct fib_table *fib_new_
+ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
+ 			     struct fib_result *res)
+ {
+-	struct fib_table *table;
++	int err = -ENETUNREACH;
+ 
+-	table = fib_get_table(net, RT_TABLE_LOCAL);
+-	if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
+-		return 0;
+-
+-	table = fib_get_table(net, RT_TABLE_MAIN);
+-	if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
+-		return 0;
+-	return -ENETUNREACH;
++	rcu_read_lock();
++
++	if (!fib_table_lookup(fib_get_table(net, RT_TABLE_LOCAL), flp, res,
++			      FIB_LOOKUP_NOREF) ||
++	    !fib_table_lookup(fib_get_table(net, RT_TABLE_MAIN), flp, res,
++			      FIB_LOOKUP_NOREF))
++		err = 0;
++
++	rcu_read_unlock();
++
++	return err;
+ }
+ 
+ #else /* CONFIG_IP_MULTIPLE_TABLES */
+@@ -247,20 +250,25 @@ static inline int fib_lookup(struct net
+ 			     struct fib_result *res)
+ {
+ 	if (!net->ipv4.fib_has_custom_rules) {
++		int err = -ENETUNREACH;
++
++		rcu_read_lock();
++
+ 		res->tclassid = 0;
+-		if (net->ipv4.fib_local &&
+-		    !fib_table_lookup(net->ipv4.fib_local, flp, res,
+-				      FIB_LOOKUP_NOREF))
+-			return 0;
+-		if (net->ipv4.fib_main &&
+-		    !fib_table_lookup(net->ipv4.fib_main, flp, res,
+-				      FIB_LOOKUP_NOREF))
+-			return 0;
+-		if (net->ipv4.fib_default &&
+-		    !fib_table_lookup(net->ipv4.fib_default, flp, res,
+-				      FIB_LOOKUP_NOREF))
+-			return 0;
+-		return -ENETUNREACH;
++		if ((net->ipv4.fib_local &&
++		     !fib_table_lookup(net->ipv4.fib_local, flp, res,
++				       FIB_LOOKUP_NOREF)) ||
++		    (net->ipv4.fib_main &&
++		     !fib_table_lookup(net->ipv4.fib_main, flp, res,
++				       FIB_LOOKUP_NOREF)) ||
++		    (net->ipv4.fib_default &&
++		     !fib_table_lookup(net->ipv4.fib_default, flp, res,
++				       FIB_LOOKUP_NOREF)))
++			err = 0;
++
++		rcu_read_unlock();
++
++		return err;
+ 	}
+ 	return __fib_lookup(net, flp, res);
+ }
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct n
+ 	return tb;
+ }
+ 
++/* caller must hold either rtnl or rcu read lock */
+ struct fib_table *fib_get_table(struct net *net, u32 id)
+ {
+ 	struct fib_table *tb;
+@@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct n
+ 		id = RT_TABLE_MAIN;
+ 	h = id & (FIB_TABLE_HASHSZ - 1);
+ 
+-	rcu_read_lock();
+ 	head = &net->ipv4.fib_table_hash[h];
+ 	hlist_for_each_entry_rcu(tb, head, tb_hlist) {
+-		if (tb->tb_id == id) {
+-			rcu_read_unlock();
++		if (tb->tb_id == id)
+ 			return tb;
+-		}
+ 	}
+-	rcu_read_unlock();
+ 	return NULL;
+ }
+ #endif /* CONFIG_IP_MULTIPLE_TABLES */
+@@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_ad
+ 	if (ipv4_is_multicast(addr))
+ 		return RTN_MULTICAST;
+ 
++	rcu_read_lock();
++
+ 	local_table = fib_get_table(net, RT_TABLE_LOCAL);
+ 	if (local_table) {
+ 		ret = RTN_UNICAST;
+-		rcu_read_lock();
+ 		if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
+ 			if (!dev || dev == res.fi->fib_dev)
+ 				ret = res.type;
+ 		}
+-		rcu_read_unlock();
+ 	}
++
++	rcu_read_unlock();
+ 	return ret;
+ }
+ 
+@@ -923,7 +922,7 @@ no_promotions:
+ #undef BRD1_OK
+ }
+ 
+-static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
++static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
+ {
+ 
+ 	struct fib_result       res;
+@@ -933,6 +932,11 @@ static void nl_fib_lookup(struct fib_res
+ 		.flowi4_tos = frn->fl_tos,
+ 		.flowi4_scope = frn->fl_scope,
+ 	};
++	struct fib_table *tb;
++
++	rcu_read_lock();
++
++	tb = fib_get_table(net, frn->tb_id_in);
+ 
+ 	frn->err = -ENOENT;
+ 	if (tb) {
+@@ -949,6 +953,8 @@ static void nl_fib_lookup(struct fib_res
+ 		}
+ 		local_bh_enable();
+ 	}
++
++	rcu_read_unlock();
+ }
+ 
+ static void nl_fib_input(struct sk_buff *skb)
+@@ -956,7 +962,6 @@ static void nl_fib_input(struct sk_buff
+ 	struct net *net;
+ 	struct fib_result_nl *frn;
+ 	struct nlmsghdr *nlh;
+-	struct fib_table *tb;
+ 	u32 portid;
+ 
+ 	net = sock_net(skb->sk);
+@@ -971,9 +976,7 @@ static void nl_fib_input(struct sk_buff
+ 	nlh = nlmsg_hdr(skb);
+ 
+ 	frn = (struct fib_result_nl *) nlmsg_data(nlh);
+-	tb = fib_get_table(net, frn->tb_id_in);
+-
+-	nl_fib_lookup(frn, tb);
++	nl_fib_lookup(net, frn);
+ 
+ 	portid = NETLINK_CB(skb).portid;      /* netlink portid */
+ 	NETLINK_CB(skb).portid = 0;        /* from kernel */
+--- a/net/ipv4/fib_rules.c
++++ b/net/ipv4/fib_rules.c
+@@ -81,27 +81,25 @@ static int fib4_rule_action(struct fib_r
+ 		break;
+ 
+ 	case FR_ACT_UNREACHABLE:
+-		err = -ENETUNREACH;
+-		goto errout;
++		return -ENETUNREACH;
+ 
+ 	case FR_ACT_PROHIBIT:
+-		err = -EACCES;
+-		goto errout;
++		return -EACCES;
+ 
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+-		err = -EINVAL;
+-		goto errout;
++		return -EINVAL;
+ 	}
+ 
++	rcu_read_lock();
++
+ 	tbl = fib_get_table(rule->fr_net, rule->table);
+-	if (!tbl)
+-		goto errout;
++	if (tbl)
++		err = fib_table_lookup(tbl, &flp->u.ip4,
++				       (struct fib_result *)arg->result,
++				       arg->flags);
+ 
+-	err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags);
+-	if (err > 0)
+-		err = -EAGAIN;
+-errout:
++	rcu_read_unlock();
+ 	return err;
+ }
+ 
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1181,72 +1181,6 @@ err:
+ 	return err;
+ }
+ 
+-/* should be called with rcu_read_lock */
+-static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
+-		      t_key key,  const struct flowi4 *flp,
+-		      struct fib_result *res, int fib_flags)
+-{
+-	struct leaf_info *li;
+-	struct hlist_head *hhead = &l->list;
+-
+-	hlist_for_each_entry_rcu(li, hhead, hlist) {
+-		struct fib_alias *fa;
+-
+-		if (l->key != (key & li->mask_plen))
+-			continue;
+-
+-		list_for_each_entry_rcu(fa, &li->falh, fa_list) {
+-			struct fib_info *fi = fa->fa_info;
+-			int nhsel, err;
+-
+-			if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
+-				continue;
+-			if (fi->fib_dead)
+-				continue;
+-			if (fa->fa_info->fib_scope < flp->flowi4_scope)
+-				continue;
+-			fib_alias_accessed(fa);
+-			err = fib_props[fa->fa_type].error;
+-			if (unlikely(err < 0)) {
+-#ifdef CONFIG_IP_FIB_TRIE_STATS
+-				this_cpu_inc(t->stats->semantic_match_passed);
+-#endif
+-				return err;
+-			}
+-			if (fi->fib_flags & RTNH_F_DEAD)
+-				continue;
+-			for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
+-				const struct fib_nh *nh = &fi->fib_nh[nhsel];
+-
+-				if (nh->nh_flags & RTNH_F_DEAD)
+-					continue;
+-				if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
+-					continue;
+-
+-#ifdef CONFIG_IP_FIB_TRIE_STATS
+-				this_cpu_inc(t->stats->semantic_match_passed);
+-#endif
+-				res->prefixlen = li->plen;
+-				res->nh_sel = nhsel;
+-				res->type = fa->fa_type;
+-				res->scope = fi->fib_scope;
+-				res->fi = fi;
+-				res->table = tb;
+-				res->fa_head = &li->falh;
+-				if (!(fib_flags & FIB_LOOKUP_NOREF))
+-					atomic_inc(&fi->fib_clntref);
+-				return 0;
+-			}
+-		}
+-
+-#ifdef CONFIG_IP_FIB_TRIE_STATS
+-		this_cpu_inc(t->stats->semantic_match_miss);
+-#endif
+-	}
+-
+-	return 1;
+-}
+-
+ static inline t_key prefix_mismatch(t_key key, struct tnode *n)
+ {
+ 	t_key prefix = n->key;
+@@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_ke
+ 	return (key ^ prefix) & (prefix | -prefix);
+ }
+ 
++/* should be called with rcu_read_lock */
+ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
+ 		     struct fib_result *res, int fib_flags)
+ {
+@@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *t
+ #endif
+ 	const t_key key = ntohl(flp->daddr);
+ 	struct tnode *n, *pn;
++	struct leaf_info *li;
+ 	t_key cindex;
+-	int ret = 1;
+-
+-	rcu_read_lock();
+ 
+ 	n = rcu_dereference(t->trie);
+ 	if (!n)
+-		goto failed;
++		return -EAGAIN;
+ 
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 	this_cpu_inc(stats->gets);
+@@ -1350,7 +1283,7 @@ backtrace:
+ 
+ 				pn = node_parent_rcu(pn);
+ 				if (unlikely(!pn))
+-					goto failed;
++					return -EAGAIN;
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 				this_cpu_inc(stats->backtrack);
+ #endif
+@@ -1368,12 +1301,62 @@ backtrace:
+ 
+ found:
+ 	/* Step 3: Process the leaf, if that fails fall back to backtracing */
+-	ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
+-	if (unlikely(ret > 0))
+-		goto backtrace;
+-failed:
+-	rcu_read_unlock();
+-	return ret;
++	hlist_for_each_entry_rcu(li, &n->list, hlist) {
++		struct fib_alias *fa;
++
++		if ((key ^ n->key) & li->mask_plen)
++			continue;
++
++		list_for_each_entry_rcu(fa, &li->falh, fa_list) {
++			struct fib_info *fi = fa->fa_info;
++			int nhsel, err;
++
++			if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
++				continue;
++			if (fi->fib_dead)
++				continue;
++			if (fa->fa_info->fib_scope < flp->flowi4_scope)
++				continue;
++			fib_alias_accessed(fa);
++			err = fib_props[fa->fa_type].error;
++			if (unlikely(err < 0)) {
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++				this_cpu_inc(stats->semantic_match_passed);
++#endif
++				return err;
++			}
++			if (fi->fib_flags & RTNH_F_DEAD)
++				continue;
++			for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
++				const struct fib_nh *nh = &fi->fib_nh[nhsel];
++
++				if (nh->nh_flags & RTNH_F_DEAD)
++					continue;
++				if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
++					continue;
++
++				if (!(fib_flags & FIB_LOOKUP_NOREF))
++					atomic_inc(&fi->fib_clntref);
++
++				res->prefixlen = li->plen;
++				res->nh_sel = nhsel;
++				res->type = fa->fa_type;
++				res->scope = fi->fib_scope;
++				res->fi = fi;
++				res->table = tb;
++				res->fa_head = &li->falh;
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++				this_cpu_inc(stats->semantic_match_passed);
++#endif
++				return err;
++			}
++		}
++
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++		this_cpu_inc(stats->semantic_match_miss);
++#endif
++	}
++	goto backtrace;
+ }
+ EXPORT_SYMBOL_GPL(fib_table_lookup);
+ 
diff --git a/target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch b/target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch
new file mode 100644
index 0000000000..a373add1d2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-12-fib_trie-Move-resize-to-after-inflate-halve.patch
@@ -0,0 +1,345 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:31 -0800
+Subject: [PATCH] fib_trie: Move resize to after inflate/halve
+
+This change consists of a cut/paste of resize to behind inflate and halve
+so that I could remove the two function prototypes.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -149,8 +149,6 @@ struct trie {
+ static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
+ 				  struct tnode *n, int wasfull);
+ static struct tnode *resize(struct trie *t, struct tnode *tn);
+-static struct tnode *inflate(struct trie *t, struct tnode *tn);
+-static struct tnode *halve(struct trie *t, struct tnode *tn);
+ /* tnodes to free after resize(); protected by RTNL */
+ static struct callback_head *tnode_free_head;
+ static size_t tnode_free_size;
+@@ -447,161 +445,6 @@ static void put_child_root(struct tnode
+ 		rcu_assign_pointer(t->trie, n);
+ }
+ 
+-#define MAX_WORK 10
+-static struct tnode *resize(struct trie *t, struct tnode *tn)
+-{
+-	struct tnode *old_tn, *n = NULL;
+-	int inflate_threshold_use;
+-	int halve_threshold_use;
+-	int max_work;
+-
+-	if (!tn)
+-		return NULL;
+-
+-	pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
+-		 tn, inflate_threshold, halve_threshold);
+-
+-	/* No children */
+-	if (tn->empty_children > (tnode_child_length(tn) - 1))
+-		goto no_children;
+-
+-	/* One child */
+-	if (tn->empty_children == (tnode_child_length(tn) - 1))
+-		goto one_child;
+-	/*
+-	 * Double as long as the resulting node has a number of
+-	 * nonempty nodes that are above the threshold.
+-	 */
+-
+-	/*
+-	 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
+-	 * the Helsinki University of Technology and Matti Tikkanen of Nokia
+-	 * Telecommunications, page 6:
+-	 * "A node is doubled if the ratio of non-empty children to all
+-	 * children in the *doubled* node is at least 'high'."
+-	 *
+-	 * 'high' in this instance is the variable 'inflate_threshold'. It
+-	 * is expressed as a percentage, so we multiply it with
+-	 * tnode_child_length() and instead of multiplying by 2 (since the
+-	 * child array will be doubled by inflate()) and multiplying
+-	 * the left-hand side by 100 (to handle the percentage thing) we
+-	 * multiply the left-hand side by 50.
+-	 *
+-	 * The left-hand side may look a bit weird: tnode_child_length(tn)
+-	 * - tn->empty_children is of course the number of non-null children
+-	 * in the current node. tn->full_children is the number of "full"
+-	 * children, that is non-null tnodes with a skip value of 0.
+-	 * All of those will be doubled in the resulting inflated tnode, so
+-	 * we just count them one extra time here.
+-	 *
+-	 * A clearer way to write this would be:
+-	 *
+-	 * to_be_doubled = tn->full_children;
+-	 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
+-	 *     tn->full_children;
+-	 *
+-	 * new_child_length = tnode_child_length(tn) * 2;
+-	 *
+-	 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
+-	 *      new_child_length;
+-	 * if (new_fill_factor >= inflate_threshold)
+-	 *
+-	 * ...and so on, tho it would mess up the while () loop.
+-	 *
+-	 * anyway,
+-	 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
+-	 *      inflate_threshold
+-	 *
+-	 * avoid a division:
+-	 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
+-	 *      inflate_threshold * new_child_length
+-	 *
+-	 * expand not_to_be_doubled and to_be_doubled, and shorten:
+-	 * 100 * (tnode_child_length(tn) - tn->empty_children +
+-	 *    tn->full_children) >= inflate_threshold * new_child_length
+-	 *
+-	 * expand new_child_length:
+-	 * 100 * (tnode_child_length(tn) - tn->empty_children +
+-	 *    tn->full_children) >=
+-	 *      inflate_threshold * tnode_child_length(tn) * 2
+-	 *
+-	 * shorten again:
+-	 * 50 * (tn->full_children + tnode_child_length(tn) -
+-	 *    tn->empty_children) >= inflate_threshold *
+-	 *    tnode_child_length(tn)
+-	 *
+-	 */
+-
+-	/* Keep root node larger  */
+-
+-	if (!node_parent(tn)) {
+-		inflate_threshold_use = inflate_threshold_root;
+-		halve_threshold_use = halve_threshold_root;
+-	} else {
+-		inflate_threshold_use = inflate_threshold;
+-		halve_threshold_use = halve_threshold;
+-	}
+-
+-	max_work = MAX_WORK;
+-	while ((tn->full_children > 0 &&  max_work-- &&
+-		50 * (tn->full_children + tnode_child_length(tn)
+-		      - tn->empty_children)
+-		>= inflate_threshold_use * tnode_child_length(tn))) {
+-
+-		old_tn = tn;
+-		tn = inflate(t, tn);
+-
+-		if (IS_ERR(tn)) {
+-			tn = old_tn;
+-#ifdef CONFIG_IP_FIB_TRIE_STATS
+-			this_cpu_inc(t->stats->resize_node_skipped);
+-#endif
+-			break;
+-		}
+-	}
+-
+-	/* Return if at least one inflate is run */
+-	if (max_work != MAX_WORK)
+-		return tn;
+-
+-	/*
+-	 * Halve as long as the number of empty children in this
+-	 * node is above threshold.
+-	 */
+-
+-	max_work = MAX_WORK;
+-	while (tn->bits > 1 &&  max_work-- &&
+-	       100 * (tnode_child_length(tn) - tn->empty_children) <
+-	       halve_threshold_use * tnode_child_length(tn)) {
+-
+-		old_tn = tn;
+-		tn = halve(t, tn);
+-		if (IS_ERR(tn)) {
+-			tn = old_tn;
+-#ifdef CONFIG_IP_FIB_TRIE_STATS
+-			this_cpu_inc(t->stats->resize_node_skipped);
+-#endif
+-			break;
+-		}
+-	}
+-
+-
+-	/* Only one child remains */
+-	if (tn->empty_children == (tnode_child_length(tn) - 1)) {
+-		unsigned long i;
+-one_child:
+-		for (i = tnode_child_length(tn); !n && i;)
+-			n = tnode_get_child(tn, --i);
+-no_children:
+-		/* compress one level */
+-		node_set_parent(n, NULL);
+-		tnode_free_safe(tn);
+-		return n;
+-	}
+-	return tn;
+-}
+-
+-
+ static void tnode_clean_free(struct tnode *tn)
+ {
+ 	struct tnode *tofree;
+@@ -804,6 +647,160 @@ nomem:
+ 	return ERR_PTR(-ENOMEM);
+ }
+ 
++#define MAX_WORK 10
++static struct tnode *resize(struct trie *t, struct tnode *tn)
++{
++	struct tnode *old_tn, *n = NULL;
++	int inflate_threshold_use;
++	int halve_threshold_use;
++	int max_work;
++
++	if (!tn)
++		return NULL;
++
++	pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
++		 tn, inflate_threshold, halve_threshold);
++
++	/* No children */
++	if (tn->empty_children > (tnode_child_length(tn) - 1))
++		goto no_children;
++
++	/* One child */
++	if (tn->empty_children == (tnode_child_length(tn) - 1))
++		goto one_child;
++	/*
++	 * Double as long as the resulting node has a number of
++	 * nonempty nodes that are above the threshold.
++	 */
++
++	/*
++	 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
++	 * the Helsinki University of Technology and Matti Tikkanen of Nokia
++	 * Telecommunications, page 6:
++	 * "A node is doubled if the ratio of non-empty children to all
++	 * children in the *doubled* node is at least 'high'."
++	 *
++	 * 'high' in this instance is the variable 'inflate_threshold'. It
++	 * is expressed as a percentage, so we multiply it with
++	 * tnode_child_length() and instead of multiplying by 2 (since the
++	 * child array will be doubled by inflate()) and multiplying
++	 * the left-hand side by 100 (to handle the percentage thing) we
++	 * multiply the left-hand side by 50.
++	 *
++	 * The left-hand side may look a bit weird: tnode_child_length(tn)
++	 * - tn->empty_children is of course the number of non-null children
++	 * in the current node. tn->full_children is the number of "full"
++	 * children, that is non-null tnodes with a skip value of 0.
++	 * All of those will be doubled in the resulting inflated tnode, so
++	 * we just count them one extra time here.
++	 *
++	 * A clearer way to write this would be:
++	 *
++	 * to_be_doubled = tn->full_children;
++	 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
++	 *     tn->full_children;
++	 *
++	 * new_child_length = tnode_child_length(tn) * 2;
++	 *
++	 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
++	 *      new_child_length;
++	 * if (new_fill_factor >= inflate_threshold)
++	 *
++	 * ...and so on, tho it would mess up the while () loop.
++	 *
++	 * anyway,
++	 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
++	 *      inflate_threshold
++	 *
++	 * avoid a division:
++	 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
++	 *      inflate_threshold * new_child_length
++	 *
++	 * expand not_to_be_doubled and to_be_doubled, and shorten:
++	 * 100 * (tnode_child_length(tn) - tn->empty_children +
++	 *    tn->full_children) >= inflate_threshold * new_child_length
++	 *
++	 * expand new_child_length:
++	 * 100 * (tnode_child_length(tn) - tn->empty_children +
++	 *    tn->full_children) >=
++	 *      inflate_threshold * tnode_child_length(tn) * 2
++	 *
++	 * shorten again:
++	 * 50 * (tn->full_children + tnode_child_length(tn) -
++	 *    tn->empty_children) >= inflate_threshold *
++	 *    tnode_child_length(tn)
++	 *
++	 */
++
++	/* Keep root node larger  */
++
++	if (!node_parent(tn)) {
++		inflate_threshold_use = inflate_threshold_root;
++		halve_threshold_use = halve_threshold_root;
++	} else {
++		inflate_threshold_use = inflate_threshold;
++		halve_threshold_use = halve_threshold;
++	}
++
++	max_work = MAX_WORK;
++	while ((tn->full_children > 0 &&  max_work-- &&
++		50 * (tn->full_children + tnode_child_length(tn)
++		      - tn->empty_children)
++		>= inflate_threshold_use * tnode_child_length(tn))) {
++
++		old_tn = tn;
++		tn = inflate(t, tn);
++
++		if (IS_ERR(tn)) {
++			tn = old_tn;
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++			this_cpu_inc(t->stats->resize_node_skipped);
++#endif
++			break;
++		}
++	}
++
++	/* Return if at least one inflate is run */
++	if (max_work != MAX_WORK)
++		return tn;
++
++	/*
++	 * Halve as long as the number of empty children in this
++	 * node is above threshold.
++	 */
++
++	max_work = MAX_WORK;
++	while (tn->bits > 1 &&  max_work-- &&
++	       100 * (tnode_child_length(tn) - tn->empty_children) <
++	       halve_threshold_use * tnode_child_length(tn)) {
++
++		old_tn = tn;
++		tn = halve(t, tn);
++		if (IS_ERR(tn)) {
++			tn = old_tn;
++#ifdef CONFIG_IP_FIB_TRIE_STATS
++			this_cpu_inc(t->stats->resize_node_skipped);
++#endif
++			break;
++		}
++	}
++
++
++	/* Only one child remains */
++	if (tn->empty_children == (tnode_child_length(tn) - 1)) {
++		unsigned long i;
++one_child:
++		for (i = tnode_child_length(tn); !n && i;)
++			n = tnode_get_child(tn, --i);
++no_children:
++		/* compress one level */
++		node_set_parent(n, NULL);
++		tnode_free_safe(tn);
++		return n;
++	}
++	return tn;
++}
++
+ /* readside must use rcu_read_lock currently dump routines
+  via get_fa_head and dump */
+ 
diff --git a/target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch b/target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch
new file mode 100644
index 0000000000..c01d57af0f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-13-fib_trie-Add-functions-should_inflate-and-should_hal.patch
@@ -0,0 +1,250 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:37 -0800
+Subject: [PATCH] fib_trie: Add functions should_inflate and should_halve
+
+This change pulls the logic for if we should inflate/halve the nodes out
+into separate functions.  It also addresses what I believe is a bug where 1
+full node is all that is needed to keep a node from ever being halved.
+
+Simple script to reproduce the issue:
+	modprobe dummy;	ifconfig dummy0 up
+	for i in `seq 0 255`; do ifconfig dummy0:$i 10.0.${i}.1/24 up; done
+	ifconfig dummy0:256 10.0.255.33/16 up
+	for i in `seq 0 254`; do ifconfig dummy0:$i down; done
+
+Results from /proc/net/fib_triestat
+Before:
+	Local:
+		Aver depth:     3.00
+		Max depth:      4
+		Leaves:         17
+		Prefixes:       18
+		Internal nodes: 11
+		  1: 8  2: 2  10: 1
+		Pointers: 1048
+	Null ptrs: 1021
+	Total size: 11  kB
+After:
+	Local:
+		Aver depth:     3.41
+		Max depth:      5
+		Leaves:         17
+		Prefixes:       18
+		Internal nodes: 12
+		  1: 8  2: 3  3: 1
+		Pointers: 36
+	Null ptrs: 8
+	Total size: 3  kB
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -647,12 +647,94 @@ nomem:
+ 	return ERR_PTR(-ENOMEM);
+ }
+ 
++/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
++ * the Helsinki University of Technology and Matti Tikkanen of Nokia
++ * Telecommunications, page 6:
++ * "A node is doubled if the ratio of non-empty children to all
++ * children in the *doubled* node is at least 'high'."
++ *
++ * 'high' in this instance is the variable 'inflate_threshold'. It
++ * is expressed as a percentage, so we multiply it with
++ * tnode_child_length() and instead of multiplying by 2 (since the
++ * child array will be doubled by inflate()) and multiplying
++ * the left-hand side by 100 (to handle the percentage thing) we
++ * multiply the left-hand side by 50.
++ *
++ * The left-hand side may look a bit weird: tnode_child_length(tn)
++ * - tn->empty_children is of course the number of non-null children
++ * in the current node. tn->full_children is the number of "full"
++ * children, that is non-null tnodes with a skip value of 0.
++ * All of those will be doubled in the resulting inflated tnode, so
++ * we just count them one extra time here.
++ *
++ * A clearer way to write this would be:
++ *
++ * to_be_doubled = tn->full_children;
++ * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
++ *     tn->full_children;
++ *
++ * new_child_length = tnode_child_length(tn) * 2;
++ *
++ * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
++ *      new_child_length;
++ * if (new_fill_factor >= inflate_threshold)
++ *
++ * ...and so on, tho it would mess up the while () loop.
++ *
++ * anyway,
++ * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
++ *      inflate_threshold
++ *
++ * avoid a division:
++ * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
++ *      inflate_threshold * new_child_length
++ *
++ * expand not_to_be_doubled and to_be_doubled, and shorten:
++ * 100 * (tnode_child_length(tn) - tn->empty_children +
++ *    tn->full_children) >= inflate_threshold * new_child_length
++ *
++ * expand new_child_length:
++ * 100 * (tnode_child_length(tn) - tn->empty_children +
++ *    tn->full_children) >=
++ *      inflate_threshold * tnode_child_length(tn) * 2
++ *
++ * shorten again:
++ * 50 * (tn->full_children + tnode_child_length(tn) -
++ *    tn->empty_children) >= inflate_threshold *
++ *    tnode_child_length(tn)
++ *
++ */
++static bool should_inflate(const struct tnode *tn)
++{
++	unsigned long used = tnode_child_length(tn);
++	unsigned long threshold = used;
++
++	/* Keep root node larger */
++	threshold *= node_parent(tn) ? inflate_threshold :
++				       inflate_threshold_root;
++	used += tn->full_children;
++	used -= tn->empty_children;
++
++	return tn->pos && ((50 * used) >= threshold);
++}
++
++static bool should_halve(const struct tnode *tn)
++{
++	unsigned long used = tnode_child_length(tn);
++	unsigned long threshold = used;
++
++	/* Keep root node larger */
++	threshold *= node_parent(tn) ? halve_threshold :
++				       halve_threshold_root;
++	used -= tn->empty_children;
++
++	return (tn->bits > 1) && ((100 * used) < threshold);
++}
++
+ #define MAX_WORK 10
+ static struct tnode *resize(struct trie *t, struct tnode *tn)
+ {
+ 	struct tnode *old_tn, *n = NULL;
+-	int inflate_threshold_use;
+-	int halve_threshold_use;
+ 	int max_work;
+ 
+ 	if (!tn)
+@@ -668,86 +750,12 @@ static struct tnode *resize(struct trie
+ 	/* One child */
+ 	if (tn->empty_children == (tnode_child_length(tn) - 1))
+ 		goto one_child;
+-	/*
+-	 * Double as long as the resulting node has a number of
+-	 * nonempty nodes that are above the threshold.
+-	 */
+ 
+-	/*
+-	 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
+-	 * the Helsinki University of Technology and Matti Tikkanen of Nokia
+-	 * Telecommunications, page 6:
+-	 * "A node is doubled if the ratio of non-empty children to all
+-	 * children in the *doubled* node is at least 'high'."
+-	 *
+-	 * 'high' in this instance is the variable 'inflate_threshold'. It
+-	 * is expressed as a percentage, so we multiply it with
+-	 * tnode_child_length() and instead of multiplying by 2 (since the
+-	 * child array will be doubled by inflate()) and multiplying
+-	 * the left-hand side by 100 (to handle the percentage thing) we
+-	 * multiply the left-hand side by 50.
+-	 *
+-	 * The left-hand side may look a bit weird: tnode_child_length(tn)
+-	 * - tn->empty_children is of course the number of non-null children
+-	 * in the current node. tn->full_children is the number of "full"
+-	 * children, that is non-null tnodes with a skip value of 0.
+-	 * All of those will be doubled in the resulting inflated tnode, so
+-	 * we just count them one extra time here.
+-	 *
+-	 * A clearer way to write this would be:
+-	 *
+-	 * to_be_doubled = tn->full_children;
+-	 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
+-	 *     tn->full_children;
+-	 *
+-	 * new_child_length = tnode_child_length(tn) * 2;
+-	 *
+-	 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
+-	 *      new_child_length;
+-	 * if (new_fill_factor >= inflate_threshold)
+-	 *
+-	 * ...and so on, tho it would mess up the while () loop.
+-	 *
+-	 * anyway,
+-	 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
+-	 *      inflate_threshold
+-	 *
+-	 * avoid a division:
+-	 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
+-	 *      inflate_threshold * new_child_length
+-	 *
+-	 * expand not_to_be_doubled and to_be_doubled, and shorten:
+-	 * 100 * (tnode_child_length(tn) - tn->empty_children +
+-	 *    tn->full_children) >= inflate_threshold * new_child_length
+-	 *
+-	 * expand new_child_length:
+-	 * 100 * (tnode_child_length(tn) - tn->empty_children +
+-	 *    tn->full_children) >=
+-	 *      inflate_threshold * tnode_child_length(tn) * 2
+-	 *
+-	 * shorten again:
+-	 * 50 * (tn->full_children + tnode_child_length(tn) -
+-	 *    tn->empty_children) >= inflate_threshold *
+-	 *    tnode_child_length(tn)
+-	 *
++	/* Double as long as the resulting node has a number of
++	 * nonempty nodes that are above the threshold.
+ 	 */
+-
+-	/* Keep root node larger  */
+-
+-	if (!node_parent(tn)) {
+-		inflate_threshold_use = inflate_threshold_root;
+-		halve_threshold_use = halve_threshold_root;
+-	} else {
+-		inflate_threshold_use = inflate_threshold;
+-		halve_threshold_use = halve_threshold;
+-	}
+-
+ 	max_work = MAX_WORK;
+-	while ((tn->full_children > 0 &&  max_work-- &&
+-		50 * (tn->full_children + tnode_child_length(tn)
+-		      - tn->empty_children)
+-		>= inflate_threshold_use * tnode_child_length(tn))) {
+-
++	while (should_inflate(tn) && max_work--) {
+ 		old_tn = tn;
+ 		tn = inflate(t, tn);
+ 
+@@ -764,16 +772,11 @@ static struct tnode *resize(struct trie
+ 	if (max_work != MAX_WORK)
+ 		return tn;
+ 
+-	/*
+-	 * Halve as long as the number of empty children in this
++	/* Halve as long as the number of empty children in this
+ 	 * node is above threshold.
+ 	 */
+-
+ 	max_work = MAX_WORK;
+-	while (tn->bits > 1 &&  max_work-- &&
+-	       100 * (tnode_child_length(tn) - tn->empty_children) <
+-	       halve_threshold_use * tnode_child_length(tn)) {
+-
++	while (should_halve(tn) && max_work--) {
+ 		old_tn = tn;
+ 		tn = halve(t, tn);
+ 		if (IS_ERR(tn)) {
diff --git a/target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch b/target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch
new file mode 100644
index 0000000000..8f26e32d3d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-14-fib_trie-Push-assignment-of-child-to-parent-down-int.patch
@@ -0,0 +1,336 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:43 -0800
+Subject: [PATCH] fib_trie: Push assignment of child to parent down into
+ inflate/halve
+
+This change makes it so that the assignment of the tnode to the parent is
+handled directly within whatever function is currently handling the node be
+it inflate, halve, or resize.  By doing this we can avoid some of the need
+to set NULL pointers in the tree while we are resizing the subnodes.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -146,9 +146,7 @@ struct trie {
+ #endif
+ };
+ 
+-static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
+-				  struct tnode *n, int wasfull);
+-static struct tnode *resize(struct trie *t, struct tnode *tn);
++static void resize(struct trie *t, struct tnode *tn);
+ /* tnodes to free after resize(); protected by RTNL */
+ static struct callback_head *tnode_free_head;
+ static size_t tnode_free_size;
+@@ -396,22 +394,13 @@ static inline int tnode_full(const struc
+ 	return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
+ }
+ 
+-static inline void put_child(struct tnode *tn, unsigned long i,
+-			     struct tnode *n)
+-{
+-	tnode_put_child_reorg(tn, i, n, -1);
+-}
+-
+- /*
+-  * Add a child at position i overwriting the old value.
+-  * Update the value of full_children and empty_children.
+-  */
+-
+-static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
+-				  struct tnode *n, int wasfull)
++/* Add a child at position i overwriting the old value.
++ * Update the value of full_children and empty_children.
++ */
++static void put_child(struct tnode *tn, unsigned long i, struct tnode *n)
+ {
+ 	struct tnode *chi = rtnl_dereference(tn->child[i]);
+-	int isfull;
++	int isfull, wasfull;
+ 
+ 	BUG_ON(i >= tnode_child_length(tn));
+ 
+@@ -422,10 +411,9 @@ static void tnode_put_child_reorg(struct
+ 		tn->empty_children--;
+ 
+ 	/* update fullChildren */
+-	if (wasfull == -1)
+-		wasfull = tnode_full(tn, chi);
+-
++	wasfull = tnode_full(tn, chi);
+ 	isfull = tnode_full(tn, n);
++
+ 	if (wasfull && !isfull)
+ 		tn->full_children--;
+ 	else if (!wasfull && isfull)
+@@ -458,9 +446,10 @@ static void tnode_clean_free(struct tnod
+ 	node_free(tn);
+ }
+ 
+-static struct tnode *inflate(struct trie *t, struct tnode *oldtnode)
++static int inflate(struct trie *t, struct tnode *oldtnode)
+ {
+ 	unsigned long olen = tnode_child_length(oldtnode);
++	struct tnode *tp = node_parent(oldtnode);
+ 	struct tnode *tn;
+ 	unsigned long i;
+ 	t_key m;
+@@ -468,9 +457,8 @@ static struct tnode *inflate(struct trie
+ 	pr_debug("In inflate\n");
+ 
+ 	tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1);
+-
+ 	if (!tn)
+-		return ERR_PTR(-ENOMEM);
++		return -ENOMEM;
+ 
+ 	/*
+ 	 * Preallocate and store tnodes before the actual work so we
+@@ -564,30 +552,36 @@ static struct tnode *inflate(struct trie
+ 			put_child(left, j, rtnl_dereference(inode->child[j]));
+ 			put_child(right, j, rtnl_dereference(inode->child[j + size]));
+ 		}
+-		put_child(tn, 2*i, resize(t, left));
+-		put_child(tn, 2*i+1, resize(t, right));
++
++		put_child(tn, 2 * i, left);
++		put_child(tn, 2 * i + 1, right);
+ 
+ 		tnode_free_safe(inode);
++
++		resize(t, left);
++		resize(t, right);
+ 	}
++
++	put_child_root(tp, t, tn->key, tn);
+ 	tnode_free_safe(oldtnode);
+-	return tn;
++	return 0;
+ nomem:
+ 	tnode_clean_free(tn);
+-	return ERR_PTR(-ENOMEM);
++	return -ENOMEM;
+ }
+ 
+-static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
++static int halve(struct trie *t, struct tnode *oldtnode)
+ {
+ 	unsigned long olen = tnode_child_length(oldtnode);
++	struct tnode *tp = node_parent(oldtnode);
+ 	struct tnode *tn, *left, *right;
+ 	int i;
+ 
+ 	pr_debug("In halve\n");
+ 
+ 	tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1);
+-
+ 	if (!tn)
+-		return ERR_PTR(-ENOMEM);
++		return -ENOMEM;
+ 
+ 	/*
+ 	 * Preallocate and store tnodes before the actual work so we
+@@ -606,8 +600,10 @@ static struct tnode *halve(struct trie *
+ 
+ 			newn = tnode_new(left->key, oldtnode->pos, 1);
+ 
+-			if (!newn)
+-				goto nomem;
++			if (!newn) {
++				tnode_clean_free(tn);
++				return -ENOMEM;
++			}
+ 
+ 			put_child(tn, i/2, newn);
+ 		}
+@@ -635,16 +631,18 @@ static struct tnode *halve(struct trie *
+ 
+ 		/* Two nonempty children */
+ 		newBinNode = tnode_get_child(tn, i/2);
+-		put_child(tn, i/2, NULL);
+ 		put_child(newBinNode, 0, left);
+ 		put_child(newBinNode, 1, right);
+-		put_child(tn, i/2, resize(t, newBinNode));
++
++		put_child(tn, i / 2, newBinNode);
++
++		resize(t, newBinNode);
+ 	}
++
++	put_child_root(tp, t, tn->key, tn);
+ 	tnode_free_safe(oldtnode);
+-	return tn;
+-nomem:
+-	tnode_clean_free(tn);
+-	return ERR_PTR(-ENOMEM);
++
++	return 0;
+ }
+ 
+ /* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
+@@ -704,45 +702,48 @@ nomem:
+  *    tnode_child_length(tn)
+  *
+  */
+-static bool should_inflate(const struct tnode *tn)
++static bool should_inflate(const struct tnode *tp, const struct tnode *tn)
+ {
+ 	unsigned long used = tnode_child_length(tn);
+ 	unsigned long threshold = used;
+ 
+ 	/* Keep root node larger */
+-	threshold *= node_parent(tn) ? inflate_threshold :
+-				       inflate_threshold_root;
++	threshold *= tp ? inflate_threshold : inflate_threshold_root;
+ 	used += tn->full_children;
+ 	used -= tn->empty_children;
+ 
+ 	return tn->pos && ((50 * used) >= threshold);
+ }
+ 
+-static bool should_halve(const struct tnode *tn)
++static bool should_halve(const struct tnode *tp, const struct tnode *tn)
+ {
+ 	unsigned long used = tnode_child_length(tn);
+ 	unsigned long threshold = used;
+ 
+ 	/* Keep root node larger */
+-	threshold *= node_parent(tn) ? halve_threshold :
+-				       halve_threshold_root;
++	threshold *= tp ? halve_threshold : halve_threshold_root;
+ 	used -= tn->empty_children;
+ 
+ 	return (tn->bits > 1) && ((100 * used) < threshold);
+ }
+ 
+ #define MAX_WORK 10
+-static struct tnode *resize(struct trie *t, struct tnode *tn)
++static void resize(struct trie *t, struct tnode *tn)
+ {
+-	struct tnode *old_tn, *n = NULL;
++	struct tnode *tp = node_parent(tn), *n = NULL;
++	struct tnode __rcu **cptr;
+ 	int max_work;
+ 
+-	if (!tn)
+-		return NULL;
+-
+ 	pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
+ 		 tn, inflate_threshold, halve_threshold);
+ 
++	/* track the tnode via the pointer from the parent instead of
++	 * doing it ourselves.  This way we can let RCU fully do its
++	 * thing without us interfering
++	 */
++	cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie;
++	BUG_ON(tn != rtnl_dereference(*cptr));
++
+ 	/* No children */
+ 	if (tn->empty_children > (tnode_child_length(tn) - 1))
+ 		goto no_children;
+@@ -755,39 +756,35 @@ static struct tnode *resize(struct trie
+ 	 * nonempty nodes that are above the threshold.
+ 	 */
+ 	max_work = MAX_WORK;
+-	while (should_inflate(tn) && max_work--) {
+-		old_tn = tn;
+-		tn = inflate(t, tn);
+-
+-		if (IS_ERR(tn)) {
+-			tn = old_tn;
++	while (should_inflate(tp, tn) && max_work--) {
++		if (inflate(t, tn)) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 			this_cpu_inc(t->stats->resize_node_skipped);
+ #endif
+ 			break;
+ 		}
++
++		tn = rtnl_dereference(*cptr);
+ 	}
+ 
+ 	/* Return if at least one inflate is run */
+ 	if (max_work != MAX_WORK)
+-		return tn;
++		return;
+ 
+ 	/* Halve as long as the number of empty children in this
+ 	 * node is above threshold.
+ 	 */
+ 	max_work = MAX_WORK;
+-	while (should_halve(tn) && max_work--) {
+-		old_tn = tn;
+-		tn = halve(t, tn);
+-		if (IS_ERR(tn)) {
+-			tn = old_tn;
++	while (should_halve(tp, tn) && max_work--) {
++		if (halve(t, tn)) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 			this_cpu_inc(t->stats->resize_node_skipped);
+ #endif
+ 			break;
+ 		}
+-	}
+ 
++		tn = rtnl_dereference(*cptr);
++	}
+ 
+ 	/* Only one child remains */
+ 	if (tn->empty_children == (tnode_child_length(tn) - 1)) {
+@@ -797,11 +794,12 @@ one_child:
+ 			n = tnode_get_child(tn, --i);
+ no_children:
+ 		/* compress one level */
+-		node_set_parent(n, NULL);
++		put_child_root(tp, t, tn->key, n);
++		node_set_parent(n, tp);
++
++		/* drop dead node */
+ 		tnode_free_safe(tn);
+-		return n;
+ 	}
+-	return tn;
+ }
+ 
+ /* readside must use rcu_read_lock currently dump routines
+@@ -882,34 +880,19 @@ static struct tnode *fib_find_node(struc
+ 
+ static void trie_rebalance(struct trie *t, struct tnode *tn)
+ {
+-	int wasfull;
+-	t_key cindex, key;
+ 	struct tnode *tp;
+ 
+-	key = tn->key;
+-
+-	while (tn != NULL && (tp = node_parent(tn)) != NULL) {
+-		cindex = get_index(key, tp);
+-		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
+-		tn = resize(t, tn);
+-
+-		tnode_put_child_reorg(tp, cindex, tn, wasfull);
+-
+-		tp = node_parent(tn);
+-		if (!tp)
+-			rcu_assign_pointer(t->trie, tn);
++	while ((tp = node_parent(tn)) != NULL) {
++		resize(t, tn);
+ 
+ 		tnode_free_flush();
+-		if (!tp)
+-			break;
+ 		tn = tp;
+ 	}
+ 
+ 	/* Handle last (top) tnode */
+ 	if (IS_TNODE(tn))
+-		tn = resize(t, tn);
++		resize(t, tn);
+ 
+-	rcu_assign_pointer(t->trie, tn);
+ 	tnode_free_flush();
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch b/target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch
new file mode 100644
index 0000000000..51178a0f14
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch
@@ -0,0 +1,237 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:49 -0800
+Subject: [PATCH] fib_trie: Push tnode flushing down to inflate/halve
+
+This change pushes the tnode freeing down into the inflate and halve
+functions.  It makes more sense here as we have a better grasp of what is
+going on and when a given cluster of nodes is ready to be freed.
+
+I believe this may address a bug in the freeing logic as well.  For some
+reason if the freelist got to a certain size we would call
+synchronize_rcu().  I'm assuming that what they meant to do is call
+synchronize_rcu() after they had handed off that much memory via
+call_rcu().  As such that is what I have updated the behavior to be.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -147,8 +147,6 @@ struct trie {
+ };
+ 
+ static void resize(struct trie *t, struct tnode *tn);
+-/* tnodes to free after resize(); protected by RTNL */
+-static struct callback_head *tnode_free_head;
+ static size_t tnode_free_size;
+ 
+ /*
+@@ -307,32 +305,6 @@ static struct tnode *tnode_alloc(size_t
+ 		return vzalloc(size);
+ }
+ 
+-static void tnode_free_safe(struct tnode *tn)
+-{
+-	BUG_ON(IS_LEAF(tn));
+-	tn->rcu.next = tnode_free_head;
+-	tnode_free_head = &tn->rcu;
+-}
+-
+-static void tnode_free_flush(void)
+-{
+-	struct callback_head *head;
+-
+-	while ((head = tnode_free_head)) {
+-		struct tnode *tn = container_of(head, struct tnode, rcu);
+-
+-		tnode_free_head = head->next;
+-		tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
+-
+-		node_free(tn);
+-	}
+-
+-	if (tnode_free_size >= PAGE_SIZE * sync_pages) {
+-		tnode_free_size = 0;
+-		synchronize_rcu();
+-	}
+-}
+-
+ static struct tnode *leaf_new(t_key key)
+ {
+ 	struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
+@@ -433,17 +405,33 @@ static void put_child_root(struct tnode
+ 		rcu_assign_pointer(t->trie, n);
+ }
+ 
+-static void tnode_clean_free(struct tnode *tn)
++static inline void tnode_free_init(struct tnode *tn)
+ {
+-	struct tnode *tofree;
+-	unsigned long i;
++	tn->rcu.next = NULL;
++}
++
++static inline void tnode_free_append(struct tnode *tn, struct tnode *n)
++{
++	n->rcu.next = tn->rcu.next;
++	tn->rcu.next = &n->rcu;
++}
+ 
+-	for (i = 0; i < tnode_child_length(tn); i++) {
+-		tofree = tnode_get_child(tn, i);
+-		if (tofree)
+-			node_free(tofree);
++static void tnode_free(struct tnode *tn)
++{
++	struct callback_head *head = &tn->rcu;
++
++	while (head) {
++		head = head->next;
++		tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
++		node_free(tn);
++
++		tn = container_of(head, struct tnode, rcu);
++	}
++
++	if (tnode_free_size >= PAGE_SIZE * sync_pages) {
++		tnode_free_size = 0;
++		synchronize_rcu();
+ 	}
+-	node_free(tn);
+ }
+ 
+ static int inflate(struct trie *t, struct tnode *oldtnode)
+@@ -476,20 +464,23 @@ static int inflate(struct trie *t, struc
+ 					 inode->bits - 1);
+ 			if (!left)
+ 				goto nomem;
++			tnode_free_append(tn, left);
+ 
+ 			right = tnode_new(inode->key | m, inode->pos,
+ 					  inode->bits - 1);
+ 
+-			if (!right) {
+-				node_free(left);
++			if (!right)
+ 				goto nomem;
+-			}
++			tnode_free_append(tn, right);
+ 
+ 			put_child(tn, 2*i, left);
+ 			put_child(tn, 2*i+1, right);
+ 		}
+ 	}
+ 
++	/* prepare oldtnode to be freed */
++	tnode_free_init(oldtnode);
++
+ 	for (i = 0; i < olen; i++) {
+ 		struct tnode *inode = tnode_get_child(oldtnode, i);
+ 		struct tnode *left, *right;
+@@ -505,12 +496,13 @@ static int inflate(struct trie *t, struc
+ 			continue;
+ 		}
+ 
++		/* drop the node in the old tnode free list */
++		tnode_free_append(oldtnode, inode);
++
+ 		/* An internal node with two children */
+ 		if (inode->bits == 1) {
+ 			put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
+ 			put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
+-
+-			tnode_free_safe(inode);
+ 			continue;
+ 		}
+ 
+@@ -556,17 +548,19 @@ static int inflate(struct trie *t, struc
+ 		put_child(tn, 2 * i, left);
+ 		put_child(tn, 2 * i + 1, right);
+ 
+-		tnode_free_safe(inode);
+-
++		/* resize child nodes */
+ 		resize(t, left);
+ 		resize(t, right);
+ 	}
+ 
+ 	put_child_root(tp, t, tn->key, tn);
+-	tnode_free_safe(oldtnode);
++
++	/* we completed without error, prepare to free old node */
++	tnode_free(oldtnode);
+ 	return 0;
+ nomem:
+-	tnode_clean_free(tn);
++	/* all pointers should be clean so we are done */
++	tnode_free(tn);
+ 	return -ENOMEM;
+ }
+ 
+@@ -599,17 +593,20 @@ static int halve(struct trie *t, struct
+ 			struct tnode *newn;
+ 
+ 			newn = tnode_new(left->key, oldtnode->pos, 1);
+-
+ 			if (!newn) {
+-				tnode_clean_free(tn);
++				tnode_free(tn);
+ 				return -ENOMEM;
+ 			}
++			tnode_free_append(tn, newn);
+ 
+ 			put_child(tn, i/2, newn);
+ 		}
+ 
+ 	}
+ 
++	/* prepare oldtnode to be freed */
++	tnode_free_init(oldtnode);
++
+ 	for (i = 0; i < olen; i += 2) {
+ 		struct tnode *newBinNode;
+ 
+@@ -636,11 +633,14 @@ static int halve(struct trie *t, struct
+ 
+ 		put_child(tn, i / 2, newBinNode);
+ 
++		/* resize child node */
+ 		resize(t, newBinNode);
+ 	}
+ 
+ 	put_child_root(tp, t, tn->key, tn);
+-	tnode_free_safe(oldtnode);
++
++	/* all pointers should be clean so we are done */
++	tnode_free(oldtnode);
+ 
+ 	return 0;
+ }
+@@ -798,7 +798,8 @@ no_children:
+ 		node_set_parent(n, tp);
+ 
+ 		/* drop dead node */
+-		tnode_free_safe(tn);
++		tnode_free_init(tn);
++		tnode_free(tn);
+ 	}
+ }
+ 
+@@ -884,16 +885,12 @@ static void trie_rebalance(struct trie *
+ 
+ 	while ((tp = node_parent(tn)) != NULL) {
+ 		resize(t, tn);
+-
+-		tnode_free_flush();
+ 		tn = tp;
+ 	}
+ 
+ 	/* Handle last (top) tnode */
+ 	if (IS_TNODE(tn))
+ 		resize(t, tn);
+-
+-	tnode_free_flush();
+ }
+ 
+ /* only used from updater-side */
diff --git a/target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch b/target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch
new file mode 100644
index 0000000000..d6b600c5dd
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-16-fib_trie-inflate-halve-nodes-in-a-more-RCU-friendly-.patch
@@ -0,0 +1,345 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:56:55 -0800
+Subject: [PATCH] fib_trie: inflate/halve nodes in a more RCU friendly
+ way
+
+This change pulls the node_set_parent functionality out of put_child_reorg
+and instead leaves that to the function to take care of as well.  By doing
+this we can fully construct the new cluster of tnodes and all of the
+pointers out of it before we start routing pointers into it.
+
+I am suspecting this will likely fix some concurency issues though I don't
+have a good test to show as such.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -391,8 +391,6 @@ static void put_child(struct tnode *tn,
+ 	else if (!wasfull && isfull)
+ 		tn->full_children++;
+ 
+-	node_set_parent(n, tn);
+-
+ 	rcu_assign_pointer(tn->child[i], n);
+ }
+ 
+@@ -436,10 +434,8 @@ static void tnode_free(struct tnode *tn)
+ 
+ static int inflate(struct trie *t, struct tnode *oldtnode)
+ {
+-	unsigned long olen = tnode_child_length(oldtnode);
+-	struct tnode *tp = node_parent(oldtnode);
+-	struct tnode *tn;
+-	unsigned long i;
++	struct tnode *inode, *node0, *node1, *tn, *tp;
++	unsigned long i, j, k;
+ 	t_key m;
+ 
+ 	pr_debug("In inflate\n");
+@@ -448,43 +444,13 @@ static int inflate(struct trie *t, struc
+ 	if (!tn)
+ 		return -ENOMEM;
+ 
+-	/*
+-	 * Preallocate and store tnodes before the actual work so we
+-	 * don't get into an inconsistent state if memory allocation
+-	 * fails. In case of failure we return the oldnode and  inflate
+-	 * of tnode is ignored.
++	/* Assemble all of the pointers in our cluster, in this case that
++	 * represents all of the pointers out of our allocated nodes that
++	 * point to existing tnodes and the links between our allocated
++	 * nodes.
+ 	 */
+-	for (i = 0, m = 1u << tn->pos; i < olen; i++) {
+-		struct tnode *inode = tnode_get_child(oldtnode, i);
+-
+-		if (tnode_full(oldtnode, inode) && (inode->bits > 1)) {
+-			struct tnode *left, *right;
+-
+-			left = tnode_new(inode->key & ~m, inode->pos,
+-					 inode->bits - 1);
+-			if (!left)
+-				goto nomem;
+-			tnode_free_append(tn, left);
+-
+-			right = tnode_new(inode->key | m, inode->pos,
+-					  inode->bits - 1);
+-
+-			if (!right)
+-				goto nomem;
+-			tnode_free_append(tn, right);
+-
+-			put_child(tn, 2*i, left);
+-			put_child(tn, 2*i+1, right);
+-		}
+-	}
+-
+-	/* prepare oldtnode to be freed */
+-	tnode_free_init(oldtnode);
+-
+-	for (i = 0; i < olen; i++) {
+-		struct tnode *inode = tnode_get_child(oldtnode, i);
+-		struct tnode *left, *right;
+-		unsigned long size, j;
++	for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) {
++		inode = tnode_get_child(oldtnode, --i);
+ 
+ 		/* An empty child */
+ 		if (inode == NULL)
+@@ -496,65 +462,99 @@ static int inflate(struct trie *t, struc
+ 			continue;
+ 		}
+ 
+-		/* drop the node in the old tnode free list */
+-		tnode_free_append(oldtnode, inode);
+-
+ 		/* An internal node with two children */
+ 		if (inode->bits == 1) {
+-			put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
+-			put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
++			put_child(tn, 2 * i + 1, tnode_get_child(inode, 1));
++			put_child(tn, 2 * i, tnode_get_child(inode, 0));
+ 			continue;
+ 		}
+ 
+-		/* An internal node with more than two children */
+-
+ 		/* We will replace this node 'inode' with two new
+-		 * ones, 'left' and 'right', each with half of the
++		 * ones, 'node0' and 'node1', each with half of the
+ 		 * original children. The two new nodes will have
+ 		 * a position one bit further down the key and this
+ 		 * means that the "significant" part of their keys
+ 		 * (see the discussion near the top of this file)
+ 		 * will differ by one bit, which will be "0" in
+-		 * left's key and "1" in right's key. Since we are
++		 * node0's key and "1" in node1's key. Since we are
+ 		 * moving the key position by one step, the bit that
+ 		 * we are moving away from - the bit at position
+-		 * (inode->pos) - is the one that will differ between
+-		 * left and right. So... we synthesize that bit in the
+-		 * two  new keys.
+-		 * The mask 'm' below will be a single "one" bit at
+-		 * the position (inode->pos)
++		 * (tn->pos) - is the one that will differ between
++		 * node0 and node1. So... we synthesize that bit in the
++		 * two new keys.
+ 		 */
++		node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1);
++		if (!node1)
++			goto nomem;
++		tnode_free_append(tn, node1);
++
++		node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1);
++		if (!node0)
++			goto nomem;
++		tnode_free_append(tn, node0);
++
++		/* populate child pointers in new nodes */
++		for (k = tnode_child_length(inode), j = k / 2; j;) {
++			put_child(node1, --j, tnode_get_child(inode, --k));
++			put_child(node0, j, tnode_get_child(inode, j));
++			put_child(node1, --j, tnode_get_child(inode, --k));
++			put_child(node0, j, tnode_get_child(inode, j));
++		}
++
++		/* link new nodes to parent */
++		NODE_INIT_PARENT(node1, tn);
++		NODE_INIT_PARENT(node0, tn);
++
++		/* link parent to nodes */
++		put_child(tn, 2 * i + 1, node1);
++		put_child(tn, 2 * i, node0);
++	}
++
++	/* setup the parent pointer into and out of this node */
++	tp = node_parent(oldtnode);
++	NODE_INIT_PARENT(tn, tp);
++	put_child_root(tp, t, tn->key, tn);
+ 
+-		/* Use the old key, but set the new significant
+-		 *   bit to zero.
+-		 */
++	/* prepare oldtnode to be freed */
++	tnode_free_init(oldtnode);
+ 
+-		left = tnode_get_child(tn, 2*i);
+-		put_child(tn, 2*i, NULL);
++	/* update all child nodes parent pointers to route to us */
++	for (i = tnode_child_length(oldtnode); i;) {
++		inode = tnode_get_child(oldtnode, --i);
+ 
+-		BUG_ON(!left);
++		/* A leaf or an internal node with skipped bits */
++		if (!tnode_full(oldtnode, inode)) {
++			node_set_parent(inode, tn);
++			continue;
++		}
+ 
+-		right = tnode_get_child(tn, 2*i+1);
+-		put_child(tn, 2*i+1, NULL);
++		/* drop the node in the old tnode free list */
++		tnode_free_append(oldtnode, inode);
+ 
+-		BUG_ON(!right);
++		/* fetch new nodes */
++		node1 = tnode_get_child(tn, 2 * i + 1);
++		node0 = tnode_get_child(tn, 2 * i);
+ 
+-		size = tnode_child_length(left);
+-		for (j = 0; j < size; j++) {
+-			put_child(left, j, rtnl_dereference(inode->child[j]));
+-			put_child(right, j, rtnl_dereference(inode->child[j + size]));
++		/* bits == 1 then node0 and node1 represent inode's children */
++		if (inode->bits == 1) {
++			node_set_parent(node1, tn);
++			node_set_parent(node0, tn);
++			continue;
+ 		}
+ 
+-		put_child(tn, 2 * i, left);
+-		put_child(tn, 2 * i + 1, right);
++		/* update parent pointers in child node's children */
++		for (k = tnode_child_length(inode), j = k / 2; j;) {
++			node_set_parent(tnode_get_child(inode, --k), node1);
++			node_set_parent(tnode_get_child(inode, --j), node0);
++			node_set_parent(tnode_get_child(inode, --k), node1);
++			node_set_parent(tnode_get_child(inode, --j), node0);
++		}
+ 
+ 		/* resize child nodes */
+-		resize(t, left);
+-		resize(t, right);
++		resize(t, node1);
++		resize(t, node0);
+ 	}
+ 
+-	put_child_root(tp, t, tn->key, tn);
+-
+ 	/* we completed without error, prepare to free old node */
+ 	tnode_free(oldtnode);
+ 	return 0;
+@@ -566,10 +566,8 @@ nomem:
+ 
+ static int halve(struct trie *t, struct tnode *oldtnode)
+ {
+-	unsigned long olen = tnode_child_length(oldtnode);
+-	struct tnode *tp = node_parent(oldtnode);
+-	struct tnode *tn, *left, *right;
+-	int i;
++	struct tnode *tn, *tp, *inode, *node0, *node1;
++	unsigned long i;
+ 
+ 	pr_debug("In halve\n");
+ 
+@@ -577,68 +575,64 @@ static int halve(struct trie *t, struct
+ 	if (!tn)
+ 		return -ENOMEM;
+ 
+-	/*
+-	 * Preallocate and store tnodes before the actual work so we
+-	 * don't get into an inconsistent state if memory allocation
+-	 * fails. In case of failure we return the oldnode and halve
+-	 * of tnode is ignored.
++	/* Assemble all of the pointers in our cluster, in this case that
++	 * represents all of the pointers out of our allocated nodes that
++	 * point to existing tnodes and the links between our allocated
++	 * nodes.
+ 	 */
++	for (i = tnode_child_length(oldtnode); i;) {
++		node1 = tnode_get_child(oldtnode, --i);
++		node0 = tnode_get_child(oldtnode, --i);
+ 
+-	for (i = 0; i < olen; i += 2) {
+-		left = tnode_get_child(oldtnode, i);
+-		right = tnode_get_child(oldtnode, i+1);
++		/* At least one of the children is empty */
++		if (!node1 || !node0) {
++			put_child(tn, i / 2, node1 ? : node0);
++			continue;
++		}
+ 
+ 		/* Two nonempty children */
+-		if (left && right) {
+-			struct tnode *newn;
+-
+-			newn = tnode_new(left->key, oldtnode->pos, 1);
+-			if (!newn) {
+-				tnode_free(tn);
+-				return -ENOMEM;
+-			}
+-			tnode_free_append(tn, newn);
+-
+-			put_child(tn, i/2, newn);
++		inode = tnode_new(node0->key, oldtnode->pos, 1);
++		if (!inode) {
++			tnode_free(tn);
++			return -ENOMEM;
+ 		}
++		tnode_free_append(tn, inode);
+ 
++		/* initialize pointers out of node */
++		put_child(inode, 1, node1);
++		put_child(inode, 0, node0);
++		NODE_INIT_PARENT(inode, tn);
++
++		/* link parent to node */
++		put_child(tn, i / 2, inode);
+ 	}
+ 
++	/* setup the parent pointer out of and back into this node */
++	tp = node_parent(oldtnode);
++	NODE_INIT_PARENT(tn, tp);
++	put_child_root(tp, t, tn->key, tn);
++
+ 	/* prepare oldtnode to be freed */
+ 	tnode_free_init(oldtnode);
+ 
+-	for (i = 0; i < olen; i += 2) {
+-		struct tnode *newBinNode;
+-
+-		left = tnode_get_child(oldtnode, i);
+-		right = tnode_get_child(oldtnode, i+1);
+-
+-		/* At least one of the children is empty */
+-		if (left == NULL) {
+-			if (right == NULL)    /* Both are empty */
+-				continue;
+-			put_child(tn, i/2, right);
+-			continue;
+-		}
+-
+-		if (right == NULL) {
+-			put_child(tn, i/2, left);
++	/* update all of the child parent pointers */
++	for (i = tnode_child_length(tn); i;) {
++		inode = tnode_get_child(tn, --i);
++
++		/* only new tnodes will be considered "full" nodes */
++		if (!tnode_full(tn, inode)) {
++			node_set_parent(inode, tn);
+ 			continue;
+ 		}
+ 
+ 		/* Two nonempty children */
+-		newBinNode = tnode_get_child(tn, i/2);
+-		put_child(newBinNode, 0, left);
+-		put_child(newBinNode, 1, right);
+-
+-		put_child(tn, i / 2, newBinNode);
++		node_set_parent(tnode_get_child(inode, 1), inode);
++		node_set_parent(tnode_get_child(inode, 0), inode);
+ 
+ 		/* resize child node */
+-		resize(t, newBinNode);
++		resize(t, inode);
+ 	}
+ 
+-	put_child_root(tp, t, tn->key, tn);
+-
+ 	/* all pointers should be clean so we are done */
+ 	tnode_free(oldtnode);
+ 
diff --git a/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch b/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch
new file mode 100644
index 0000000000..8f7c671ac6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-17-fib_trie-Remove-checks-for-index-tnode_child_length-.patch
@@ -0,0 +1,95 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:57:02 -0800
+Subject: [PATCH] fib_trie: Remove checks for index >= tnode_child_length
+ from tnode_get_child
+
+For some reason the compiler doesn't seem to understand that when we are in
+a loop that runs from tnode_child_length - 1 to 0 we don't expect the value
+of tn->bits to change.  As such every call to tnode_get_child was rerunning
+tnode_chile_length which ended up consuming quite a bit of space in the
+resultant assembly code.
+
+I have gone though and verified that in all cases where tnode_get_child
+is used we are either winding though a fixed loop from tnode_child_length -
+1 to 0, or are in a fastpath case where we are verifying the value by
+either checking for any remaining bits after shifting index by bits and
+testing for leaf, or by using tnode_child_length.
+
+size net/ipv4/fib_trie.o
+Before:
+   text	   data	    bss	    dec	    hex	filename
+  15506	    376	      8	  15890	   3e12	net/ipv4/fib_trie.o
+
+After:
+   text	   data	    bss	    dec	    hex	filename
+  14827	    376	      8	  15211	   3b6b	net/ipv4/fib_trie.o
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -186,8 +186,6 @@ static inline unsigned long tnode_child_
+ static inline struct tnode *tnode_get_child(const struct tnode *tn,
+ 					    unsigned long i)
+ {
+-	BUG_ON(i >= tnode_child_length(tn));
+-
+ 	return rtnl_dereference(tn->child[i]);
+ }
+ 
+@@ -195,8 +193,6 @@ static inline struct tnode *tnode_get_ch
+ static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn,
+ 						unsigned long i)
+ {
+-	BUG_ON(i >= tnode_child_length(tn));
+-
+ 	return rcu_dereference_rtnl(tn->child[i]);
+ }
+ 
+@@ -371,7 +367,7 @@ static inline int tnode_full(const struc
+  */
+ static void put_child(struct tnode *tn, unsigned long i, struct tnode *n)
+ {
+-	struct tnode *chi = rtnl_dereference(tn->child[i]);
++	struct tnode *chi = tnode_get_child(tn, i);
+ 	int isfull, wasfull;
+ 
+ 	BUG_ON(i >= tnode_child_length(tn));
+@@ -867,7 +863,7 @@ static struct tnode *fib_find_node(struc
+ 		if (IS_LEAF(n))
+ 			break;
+ 
+-		n = rcu_dereference_rtnl(n->child[index]);
++		n = tnode_get_child_rcu(n, index);
+ 	}
+ 
+ 	return n;
+@@ -934,7 +930,7 @@ static struct list_head *fib_insert_node
+ 		}
+ 
+ 		tp = n;
+-		n = rcu_dereference_rtnl(n->child[index]);
++		n = tnode_get_child_rcu(n, index);
+ 	}
+ 
+ 	l = leaf_new(key);
+@@ -1215,7 +1211,7 @@ int fib_table_lookup(struct fib_table *t
+ 			cindex = index;
+ 		}
+ 
+-		n = rcu_dereference(n->child[index]);
++		n = tnode_get_child_rcu(n, index);
+ 		if (unlikely(!n))
+ 			goto backtrace;
+ 	}
+@@ -1835,7 +1831,7 @@ static void trie_collect_stats(struct tr
+ 			if (n->bits < MAX_STAT_DEPTH)
+ 				s->nodesizes[n->bits]++;
+ 
+-			for (i = 0; i < tnode_child_length(n); i++) {
++			for (i = tnode_child_length(n); i--;) {
+ 				if (!rcu_access_pointer(n->child[i]))
+ 					s->nullpointers++;
+ 			}
diff --git a/target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch b/target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch
new file mode 100644
index 0000000000..6a4a45e952
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-18-fib_trie-Add-tracking-value-for-suffix-length.patch
@@ -0,0 +1,234 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Wed, 31 Dec 2014 10:57:08 -0800
+Subject: [PATCH] fib_trie: Add tracking value for suffix length
+
+This change adds a tracking value for the maximum suffix length of all
+prefixes stored in any given tnode.  With this value we can determine if we
+need to backtrace or not based on if the suffix is greater than the pos
+value.
+
+By doing this we can reduce the CPU overhead for lookups in the local table
+as many of the prefixes there are 32b long and have a suffix length of 0
+meaning we can immediately backtrace to the root node without needing to
+test any of the nodes between it and where we ended up.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -96,6 +96,7 @@ struct tnode {
+ 	t_key key;
+ 	unsigned char bits;		/* 2log(KEYLENGTH) bits needed */
+ 	unsigned char pos;		/* 2log(KEYLENGTH) bits needed */
++	unsigned char slen;
+ 	struct tnode __rcu *parent;
+ 	struct rcu_head rcu;
+ 	union {
+@@ -311,6 +312,7 @@ static struct tnode *leaf_new(t_key key)
+ 		 * as the nodes are searched
+ 		 */
+ 		l->key = key;
++		l->slen = 0;
+ 		l->pos = 0;
+ 		/* set bits to 0 indicating we are not a tnode */
+ 		l->bits = 0;
+@@ -342,6 +344,7 @@ static struct tnode *tnode_new(t_key key
+ 
+ 	if (tn) {
+ 		tn->parent = NULL;
++		tn->slen = pos;
+ 		tn->pos = pos;
+ 		tn->bits = bits;
+ 		tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
+@@ -387,6 +390,9 @@ static void put_child(struct tnode *tn,
+ 	else if (!wasfull && isfull)
+ 		tn->full_children++;
+ 
++	if (n && (tn->slen < n->slen))
++		tn->slen = n->slen;
++
+ 	rcu_assign_pointer(tn->child[i], n);
+ }
+ 
+@@ -635,6 +641,41 @@ static int halve(struct trie *t, struct
+ 	return 0;
+ }
+ 
++static unsigned char update_suffix(struct tnode *tn)
++{
++	unsigned char slen = tn->pos;
++	unsigned long stride, i;
++
++	/* search though the list of children looking for nodes that might
++	 * have a suffix greater than the one we currently have.  This is
++	 * why we start with a stride of 2 since a stride of 1 would
++	 * represent the nodes with suffix length equal to tn->pos
++	 */
++	for (i = 0, stride = 0x2ul ; i < tnode_child_length(tn); i += stride) {
++		struct tnode *n = tnode_get_child(tn, i);
++
++		if (!n || (n->slen <= slen))
++			continue;
++
++		/* update stride and slen based on new value */
++		stride <<= (n->slen - slen);
++		slen = n->slen;
++		i &= ~(stride - 1);
++
++		/* if slen covers all but the last bit we can stop here
++		 * there will be nothing longer than that since only node
++		 * 0 and 1 << (bits - 1) could have that as their suffix
++		 * length.
++		 */
++		if ((slen + 1) >= (tn->pos + tn->bits))
++			break;
++	}
++
++	tn->slen = slen;
++
++	return slen;
++}
++
+ /* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
+  * the Helsinki University of Technology and Matti Tikkanen of Nokia
+  * Telecommunications, page 6:
+@@ -790,6 +831,19 @@ no_children:
+ 		/* drop dead node */
+ 		tnode_free_init(tn);
+ 		tnode_free(tn);
++		return;
++	}
++
++	/* Return if at least one deflate was run */
++	if (max_work != MAX_WORK)
++		return;
++
++	/* push the suffix length to the parent node */
++	if (tn->slen > tn->pos) {
++		unsigned char slen = update_suffix(tn);
++
++		if (tp && (slen > tp->slen))
++			tp->slen = slen;
+ 	}
+ }
+ 
+@@ -818,8 +872,58 @@ static inline struct list_head *get_fa_h
+ 	return &li->falh;
+ }
+ 
+-static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
++static void leaf_pull_suffix(struct tnode *l)
++{
++	struct tnode *tp = node_parent(l);
++
++	while (tp && (tp->slen > tp->pos) && (tp->slen > l->slen)) {
++		if (update_suffix(tp) > l->slen)
++			break;
++		tp = node_parent(tp);
++	}
++}
++
++static void leaf_push_suffix(struct tnode *l)
++{
++	struct tnode *tn = node_parent(l);
++
++	/* if this is a new leaf then tn will be NULL and we can sort
++	 * out parent suffix lengths as a part of trie_rebalance
++	 */
++	while (tn && (tn->slen < l->slen)) {
++		tn->slen = l->slen;
++		tn = node_parent(tn);
++	}
++}
++
++static void remove_leaf_info(struct tnode *l, struct leaf_info *old)
++{
++	struct hlist_node *prev;
++
++	/* record the location of the pointer to this object */
++	prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist));
++
++	/* remove the leaf info from the list */
++	hlist_del_rcu(&old->hlist);
++
++	/* if we emptied the list this leaf will be freed and we can sort
++	 * out parent suffix lengths as a part of trie_rebalance
++	 */
++	if (hlist_empty(&l->list))
++		return;
++
++	/* if we removed the tail then we need to update slen */
++	if (!rcu_access_pointer(hlist_next_rcu(prev))) {
++		struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist);
++
++		l->slen = KEYLENGTH - li->plen;
++		leaf_pull_suffix(l);
++	}
++}
++
++static void insert_leaf_info(struct tnode *l, struct leaf_info *new)
+ {
++	struct hlist_head *head = &l->list;
+ 	struct leaf_info *li = NULL, *last = NULL;
+ 
+ 	if (hlist_empty(head)) {
+@@ -836,6 +940,12 @@ static void insert_leaf_info(struct hlis
+ 		else
+ 			hlist_add_before_rcu(&new->hlist, &li->hlist);
+ 	}
++
++	/* if we added to the tail node then we need to update slen */
++	if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) {
++		l->slen = KEYLENGTH - new->plen;
++		leaf_push_suffix(l);
++	}
+ }
+ 
+ /* rcu_read_lock needs to be hold by caller from readside */
+@@ -925,7 +1035,7 @@ static struct list_head *fib_insert_node
+ 		/* we have found a leaf. Prefixes have already been compared */
+ 		if (IS_LEAF(n)) {
+ 			/* Case 1: n is a leaf, and prefixes match*/
+-			insert_leaf_info(&n->list, li);
++			insert_leaf_info(n, li);
+ 			return fa_head;
+ 		}
+ 
+@@ -939,7 +1049,7 @@ static struct list_head *fib_insert_node
+ 		return NULL;
+ 	}
+ 
+-	insert_leaf_info(&l->list, li);
++	insert_leaf_info(l, li);
+ 
+ 	/* Case 2: n is a LEAF or a TNODE and the key doesn't match.
+ 	 *
+@@ -1206,7 +1316,7 @@ int fib_table_lookup(struct fib_table *t
+ 		/* only record pn and cindex if we are going to be chopping
+ 		 * bits later.  Otherwise we are just wasting cycles.
+ 		 */
+-		if (index) {
++		if (n->slen > n->pos) {
+ 			pn = n;
+ 			cindex = index;
+ 		}
+@@ -1225,7 +1335,7 @@ int fib_table_lookup(struct fib_table *t
+ 		 * between the key and the prefix exist in the region of
+ 		 * the lsb and higher in the prefix.
+ 		 */
+-		if (unlikely(prefix_mismatch(key, n)))
++		if (unlikely(prefix_mismatch(key, n)) || (n->slen == n->pos))
+ 			goto backtrace;
+ 
+ 		/* exit out and process leaf */
+@@ -1425,7 +1535,7 @@ int fib_table_delete(struct fib_table *t
+ 		tb->tb_num_default--;
+ 
+ 	if (list_empty(fa_head)) {
+-		hlist_del_rcu(&li->hlist);
++		remove_leaf_info(l, li);
+ 		free_leaf_info(li);
+ 	}
+ 
diff --git a/target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch b/target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch
new file mode 100644
index 0000000000..d5fc112563
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-19-fib_trie-Use-index-0ul-n-bits-instead-of-index-n-bit.patch
@@ -0,0 +1,52 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:08 -0800
+Subject: [PATCH] fib_trie: Use index & (~0ul << n->bits) instead of index >>
+ n->bits
+
+In doing performance testing and analysis of the changes I recently found
+that by shifting the index I had created an unnecessary dependency.
+
+I have updated the code so that we instead shift a mask by bits and then
+just test against that as that should save us about 2 CPU cycles since we
+can generate the mask while the key and pos are being processed.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -961,12 +961,12 @@ static struct tnode *fib_find_node(struc
+ 		 * prefix plus zeros for the bits in the cindex. The index
+ 		 * is the difference between the key and this value.  From
+ 		 * this we can actually derive several pieces of data.
+-		 *   if !(index >> bits)
+-		 *     we know the value is cindex
+-		 *   else
++		 *   if (index & (~0ul << bits))
+ 		 *     we have a mismatch in skip bits and failed
++		 *   else
++		 *     we know the value is cindex
+ 		 */
+-		if (index >> n->bits)
++		if (index & (~0ul << n->bits))
+ 			return NULL;
+ 
+ 		/* we have found a leaf. Prefixes have already been compared */
+@@ -1301,12 +1301,12 @@ int fib_table_lookup(struct fib_table *t
+ 		 * prefix plus zeros for the "bits" in the prefix. The index
+ 		 * is the difference between the key and this value.  From
+ 		 * this we can actually derive several pieces of data.
+-		 *   if !(index >> bits)
+-		 *     we know the value is child index
+-		 *   else
++		 *   if (index & (~0ul << bits))
+ 		 *     we have a mismatch in skip bits and failed
++		 *   else
++		 *     we know the value is cindex
+ 		 */
+-		if (index >> n->bits)
++		if (index & (~0ul << n->bits))
+ 			break;
+ 
+ 		/* we have found a leaf. Prefixes have already been compared */
diff --git a/target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch b/target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch
new file mode 100644
index 0000000000..7e26127084
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-20-fib_trie-Fix-RCU-bug-and-merge-similar-bits-of-infla.patch
@@ -0,0 +1,267 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:14 -0800
+Subject: [PATCH] fib_trie: Fix RCU bug and merge similar bits of inflate/halve
+
+This patch addresses two issues.
+
+The first issue is the fact that I believe I had the RCU freeing sequence
+slightly out of order.  As a result we could get into an issue if a caller
+went into a child of a child of the new node, then backtraced into the to be
+freed parent, and then attempted to access a child of a child that may have
+been consumed in a resize of one of the new nodes children.  To resolve this I
+have moved the resize after we have freed the oldtnode.  The only side effect
+of this is that we will now be calling resize on more nodes in the case of
+inflate due to the fact that we don't have a good way to test to see if a
+full_tnode on the new node was there before or after the allocation.  This
+should have minimal impact however since the node should already be
+correctly size so it is just the cost of calling should_inflate that we
+will be taking on the node which is only a couple of cycles.
+
+The second issue is the fact that inflate and halve were essentially doing
+the same thing after the new node was added to the trie replacing the old
+one.  As such it wasn't really necessary to keep the code in both functions
+so I have split it out into two other functions, called replace and
+update_children.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -396,8 +396,30 @@ static void put_child(struct tnode *tn,
+ 	rcu_assign_pointer(tn->child[i], n);
+ }
+ 
+-static void put_child_root(struct tnode *tp, struct trie *t,
+-			   t_key key, struct tnode *n)
++static void update_children(struct tnode *tn)
++{
++	unsigned long i;
++
++	/* update all of the child parent pointers */
++	for (i = tnode_child_length(tn); i;) {
++		struct tnode *inode = tnode_get_child(tn, --i);
++
++		if (!inode)
++			continue;
++
++		/* Either update the children of a tnode that
++		 * already belongs to us or update the child
++		 * to point to ourselves.
++		 */
++		if (node_parent(inode) == tn)
++			update_children(inode);
++		else
++			node_set_parent(inode, tn);
++	}
++}
++
++static inline void put_child_root(struct tnode *tp, struct trie *t,
++				  t_key key, struct tnode *n)
+ {
+ 	if (tp)
+ 		put_child(tp, get_index(key, tp), n);
+@@ -434,10 +456,35 @@ static void tnode_free(struct tnode *tn)
+ 	}
+ }
+ 
++static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn)
++{
++	struct tnode *tp = node_parent(oldtnode);
++	unsigned long i;
++
++	/* setup the parent pointer out of and back into this node */
++	NODE_INIT_PARENT(tn, tp);
++	put_child_root(tp, t, tn->key, tn);
++
++	/* update all of the child parent pointers */
++	update_children(tn);
++
++	/* all pointers should be clean so we are done */
++	tnode_free(oldtnode);
++
++	/* resize children now that oldtnode is freed */
++	for (i = tnode_child_length(tn); i;) {
++		struct tnode *inode = tnode_get_child(tn, --i);
++
++		/* resize child node */
++		if (tnode_full(tn, inode))
++			resize(t, inode);
++	}
++}
++
+ static int inflate(struct trie *t, struct tnode *oldtnode)
+ {
+-	struct tnode *inode, *node0, *node1, *tn, *tp;
+-	unsigned long i, j, k;
++	struct tnode *tn;
++	unsigned long i;
+ 	t_key m;
+ 
+ 	pr_debug("In inflate\n");
+@@ -446,13 +493,18 @@ static int inflate(struct trie *t, struc
+ 	if (!tn)
+ 		return -ENOMEM;
+ 
++	/* prepare oldtnode to be freed */
++	tnode_free_init(oldtnode);
++
+ 	/* Assemble all of the pointers in our cluster, in this case that
+ 	 * represents all of the pointers out of our allocated nodes that
+ 	 * point to existing tnodes and the links between our allocated
+ 	 * nodes.
+ 	 */
+ 	for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) {
+-		inode = tnode_get_child(oldtnode, --i);
++		struct tnode *inode = tnode_get_child(oldtnode, --i);
++		struct tnode *node0, *node1;
++		unsigned long j, k;
+ 
+ 		/* An empty child */
+ 		if (inode == NULL)
+@@ -464,6 +516,9 @@ static int inflate(struct trie *t, struc
+ 			continue;
+ 		}
+ 
++		/* drop the node in the old tnode free list */
++		tnode_free_append(oldtnode, inode);
++
+ 		/* An internal node with two children */
+ 		if (inode->bits == 1) {
+ 			put_child(tn, 2 * i + 1, tnode_get_child(inode, 1));
+@@ -488,9 +543,9 @@ static int inflate(struct trie *t, struc
+ 		node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1);
+ 		if (!node1)
+ 			goto nomem;
+-		tnode_free_append(tn, node1);
++		node0 = tnode_new(inode->key, inode->pos, inode->bits - 1);
+ 
+-		node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1);
++		tnode_free_append(tn, node1);
+ 		if (!node0)
+ 			goto nomem;
+ 		tnode_free_append(tn, node0);
+@@ -512,53 +567,9 @@ static int inflate(struct trie *t, struc
+ 		put_child(tn, 2 * i, node0);
+ 	}
+ 
+-	/* setup the parent pointer into and out of this node */
+-	tp = node_parent(oldtnode);
+-	NODE_INIT_PARENT(tn, tp);
+-	put_child_root(tp, t, tn->key, tn);
++	/* setup the parent pointers into and out of this node */
++	replace(t, oldtnode, tn);
+ 
+-	/* prepare oldtnode to be freed */
+-	tnode_free_init(oldtnode);
+-
+-	/* update all child nodes parent pointers to route to us */
+-	for (i = tnode_child_length(oldtnode); i;) {
+-		inode = tnode_get_child(oldtnode, --i);
+-
+-		/* A leaf or an internal node with skipped bits */
+-		if (!tnode_full(oldtnode, inode)) {
+-			node_set_parent(inode, tn);
+-			continue;
+-		}
+-
+-		/* drop the node in the old tnode free list */
+-		tnode_free_append(oldtnode, inode);
+-
+-		/* fetch new nodes */
+-		node1 = tnode_get_child(tn, 2 * i + 1);
+-		node0 = tnode_get_child(tn, 2 * i);
+-
+-		/* bits == 1 then node0 and node1 represent inode's children */
+-		if (inode->bits == 1) {
+-			node_set_parent(node1, tn);
+-			node_set_parent(node0, tn);
+-			continue;
+-		}
+-
+-		/* update parent pointers in child node's children */
+-		for (k = tnode_child_length(inode), j = k / 2; j;) {
+-			node_set_parent(tnode_get_child(inode, --k), node1);
+-			node_set_parent(tnode_get_child(inode, --j), node0);
+-			node_set_parent(tnode_get_child(inode, --k), node1);
+-			node_set_parent(tnode_get_child(inode, --j), node0);
+-		}
+-
+-		/* resize child nodes */
+-		resize(t, node1);
+-		resize(t, node0);
+-	}
+-
+-	/* we completed without error, prepare to free old node */
+-	tnode_free(oldtnode);
+ 	return 0;
+ nomem:
+ 	/* all pointers should be clean so we are done */
+@@ -568,7 +579,7 @@ nomem:
+ 
+ static int halve(struct trie *t, struct tnode *oldtnode)
+ {
+-	struct tnode *tn, *tp, *inode, *node0, *node1;
++	struct tnode *tn;
+ 	unsigned long i;
+ 
+ 	pr_debug("In halve\n");
+@@ -577,14 +588,18 @@ static int halve(struct trie *t, struct
+ 	if (!tn)
+ 		return -ENOMEM;
+ 
++	/* prepare oldtnode to be freed */
++	tnode_free_init(oldtnode);
++
+ 	/* Assemble all of the pointers in our cluster, in this case that
+ 	 * represents all of the pointers out of our allocated nodes that
+ 	 * point to existing tnodes and the links between our allocated
+ 	 * nodes.
+ 	 */
+ 	for (i = tnode_child_length(oldtnode); i;) {
+-		node1 = tnode_get_child(oldtnode, --i);
+-		node0 = tnode_get_child(oldtnode, --i);
++		struct tnode *node1 = tnode_get_child(oldtnode, --i);
++		struct tnode *node0 = tnode_get_child(oldtnode, --i);
++		struct tnode *inode;
+ 
+ 		/* At least one of the children is empty */
+ 		if (!node1 || !node0) {
+@@ -609,34 +624,8 @@ static int halve(struct trie *t, struct
+ 		put_child(tn, i / 2, inode);
+ 	}
+ 
+-	/* setup the parent pointer out of and back into this node */
+-	tp = node_parent(oldtnode);
+-	NODE_INIT_PARENT(tn, tp);
+-	put_child_root(tp, t, tn->key, tn);
+-
+-	/* prepare oldtnode to be freed */
+-	tnode_free_init(oldtnode);
+-
+-	/* update all of the child parent pointers */
+-	for (i = tnode_child_length(tn); i;) {
+-		inode = tnode_get_child(tn, --i);
+-
+-		/* only new tnodes will be considered "full" nodes */
+-		if (!tnode_full(tn, inode)) {
+-			node_set_parent(inode, tn);
+-			continue;
+-		}
+-
+-		/* Two nonempty children */
+-		node_set_parent(tnode_get_child(inode, 1), inode);
+-		node_set_parent(tnode_get_child(inode, 0), inode);
+-
+-		/* resize child node */
+-		resize(t, inode);
+-	}
+-
+-	/* all pointers should be clean so we are done */
+-	tnode_free(oldtnode);
++	/* setup the parent pointers into and out of this node */
++	replace(t, oldtnode, tn);
+ 
+ 	return 0;
+ }
diff --git a/target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch b/target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch
new file mode 100644
index 0000000000..058b33bf9d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-21-fib_trie-Fall-back-to-slen-update-on-inflate-halve-f.patch
@@ -0,0 +1,61 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:20 -0800
+Subject: [PATCH] fib_trie: Fall back to slen update on inflate/halve failure
+
+This change corrects an issue where if inflate or halve fails we were
+exiting the resize function without at least updating the slen for the
+node.  To correct this I have moved the update of max_size into the while
+loop so that it is only decremented on a successful call to either inflate
+or halve.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -752,7 +752,7 @@ static void resize(struct trie *t, struc
+ {
+ 	struct tnode *tp = node_parent(tn), *n = NULL;
+ 	struct tnode __rcu **cptr;
+-	int max_work;
++	int max_work = MAX_WORK;
+ 
+ 	pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
+ 		 tn, inflate_threshold, halve_threshold);
+@@ -775,8 +775,7 @@ static void resize(struct trie *t, struc
+ 	/* Double as long as the resulting node has a number of
+ 	 * nonempty nodes that are above the threshold.
+ 	 */
+-	max_work = MAX_WORK;
+-	while (should_inflate(tp, tn) && max_work--) {
++	while (should_inflate(tp, tn) && max_work) {
+ 		if (inflate(t, tn)) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 			this_cpu_inc(t->stats->resize_node_skipped);
+@@ -784,6 +783,7 @@ static void resize(struct trie *t, struc
+ 			break;
+ 		}
+ 
++		max_work--;
+ 		tn = rtnl_dereference(*cptr);
+ 	}
+ 
+@@ -794,8 +794,7 @@ static void resize(struct trie *t, struc
+ 	/* Halve as long as the number of empty children in this
+ 	 * node is above threshold.
+ 	 */
+-	max_work = MAX_WORK;
+-	while (should_halve(tp, tn) && max_work--) {
++	while (should_halve(tp, tn) && max_work) {
+ 		if (halve(t, tn)) {
+ #ifdef CONFIG_IP_FIB_TRIE_STATS
+ 			this_cpu_inc(t->stats->resize_node_skipped);
+@@ -803,6 +802,7 @@ static void resize(struct trie *t, struc
+ 			break;
+ 		}
+ 
++		max_work--;
+ 		tn = rtnl_dereference(*cptr);
+ 	}
+ 
diff --git a/target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch b/target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch
new file mode 100644
index 0000000000..19b7db7f94
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-22-fib_trie-Add-collapse-and-should_collapse-to-resize.patch
@@ -0,0 +1,206 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:26 -0800
+Subject: [PATCH] fib_trie: Add collapse() and should_collapse() to resize
+
+This patch really does two things.
+
+First it pulls the logic for determining if we should collapse one node out
+of the tree and the actual code doing the collapse into a separate pair of
+functions.  This helps to make the changes to these areas more readable.
+
+Second it encodes the upper 32b of the empty_children value onto the
+full_children value in the case of bits == KEYLENGTH.  By doing this we are
+able to handle the case of a 32b node where empty_children would appear to
+be 0 when it was actually 1ul << 32.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -83,7 +83,8 @@
+ 
+ #define MAX_STAT_DEPTH 32
+ 
+-#define KEYLENGTH (8*sizeof(t_key))
++#define KEYLENGTH	(8*sizeof(t_key))
++#define KEY_MAX		((t_key)~0)
+ 
+ typedef unsigned int t_key;
+ 
+@@ -102,8 +103,8 @@ struct tnode {
+ 	union {
+ 		/* The fields in this struct are valid if bits > 0 (TNODE) */
+ 		struct {
+-			unsigned int full_children;  /* KEYLENGTH bits needed */
+-			unsigned int empty_children; /* KEYLENGTH bits needed */
++			t_key empty_children; /* KEYLENGTH bits needed */
++			t_key full_children;  /* KEYLENGTH bits needed */
+ 			struct tnode __rcu *child[0];
+ 		};
+ 		/* This list pointer if valid if bits == 0 (LEAF) */
+@@ -302,6 +303,16 @@ static struct tnode *tnode_alloc(size_t
+ 		return vzalloc(size);
+ }
+ 
++static inline void empty_child_inc(struct tnode *n)
++{
++	++n->empty_children ? : ++n->full_children;
++}
++
++static inline void empty_child_dec(struct tnode *n)
++{
++	n->empty_children-- ? : n->full_children--;
++}
++
+ static struct tnode *leaf_new(t_key key)
+ {
+ 	struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
+@@ -335,7 +346,7 @@ static struct leaf_info *leaf_info_new(i
+ 
+ static struct tnode *tnode_new(t_key key, int pos, int bits)
+ {
+-	size_t sz = offsetof(struct tnode, child[1 << bits]);
++	size_t sz = offsetof(struct tnode, child[1ul << bits]);
+ 	struct tnode *tn = tnode_alloc(sz);
+ 	unsigned int shift = pos + bits;
+ 
+@@ -348,8 +359,10 @@ static struct tnode *tnode_new(t_key key
+ 		tn->pos = pos;
+ 		tn->bits = bits;
+ 		tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
+-		tn->full_children = 0;
+-		tn->empty_children = 1<<bits;
++		if (bits == KEYLENGTH)
++			tn->full_children = 1;
++		else
++			tn->empty_children = 1ul << bits;
+ 	}
+ 
+ 	pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
+@@ -375,11 +388,11 @@ static void put_child(struct tnode *tn,
+ 
+ 	BUG_ON(i >= tnode_child_length(tn));
+ 
+-	/* update emptyChildren */
++	/* update emptyChildren, overflow into fullChildren */
+ 	if (n == NULL && chi != NULL)
+-		tn->empty_children++;
+-	else if (n != NULL && chi == NULL)
+-		tn->empty_children--;
++		empty_child_inc(tn);
++	if (n != NULL && chi == NULL)
++		empty_child_dec(tn);
+ 
+ 	/* update fullChildren */
+ 	wasfull = tnode_full(tn, chi);
+@@ -630,6 +643,24 @@ static int halve(struct trie *t, struct
+ 	return 0;
+ }
+ 
++static void collapse(struct trie *t, struct tnode *oldtnode)
++{
++	struct tnode *n, *tp;
++	unsigned long i;
++
++	/* scan the tnode looking for that one child that might still exist */
++	for (n = NULL, i = tnode_child_length(oldtnode); !n && i;)
++		n = tnode_get_child(oldtnode, --i);
++
++	/* compress one level */
++	tp = node_parent(oldtnode);
++	put_child_root(tp, t, oldtnode->key, n);
++	node_set_parent(n, tp);
++
++	/* drop dead node */
++	node_free(oldtnode);
++}
++
+ static unsigned char update_suffix(struct tnode *tn)
+ {
+ 	unsigned char slen = tn->pos;
+@@ -729,10 +760,12 @@ static bool should_inflate(const struct
+ 
+ 	/* Keep root node larger */
+ 	threshold *= tp ? inflate_threshold : inflate_threshold_root;
+-	used += tn->full_children;
+ 	used -= tn->empty_children;
++	used += tn->full_children;
+ 
+-	return tn->pos && ((50 * used) >= threshold);
++	/* if bits == KEYLENGTH then pos = 0, and will fail below */
++
++	return (used > 1) && tn->pos && ((50 * used) >= threshold);
+ }
+ 
+ static bool should_halve(const struct tnode *tp, const struct tnode *tn)
+@@ -744,13 +777,29 @@ static bool should_halve(const struct tn
+ 	threshold *= tp ? halve_threshold : halve_threshold_root;
+ 	used -= tn->empty_children;
+ 
+-	return (tn->bits > 1) && ((100 * used) < threshold);
++	/* if bits == KEYLENGTH then used = 100% on wrap, and will fail below */
++
++	return (used > 1) && (tn->bits > 1) && ((100 * used) < threshold);
++}
++
++static bool should_collapse(const struct tnode *tn)
++{
++	unsigned long used = tnode_child_length(tn);
++
++	used -= tn->empty_children;
++
++	/* account for bits == KEYLENGTH case */
++	if ((tn->bits == KEYLENGTH) && tn->full_children)
++		used -= KEY_MAX;
++
++	/* One child or none, time to drop us from the trie */
++	return used < 2;
+ }
+ 
+ #define MAX_WORK 10
+ static void resize(struct trie *t, struct tnode *tn)
+ {
+-	struct tnode *tp = node_parent(tn), *n = NULL;
++	struct tnode *tp = node_parent(tn);
+ 	struct tnode __rcu **cptr;
+ 	int max_work = MAX_WORK;
+ 
+@@ -764,14 +813,6 @@ static void resize(struct trie *t, struc
+ 	cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie;
+ 	BUG_ON(tn != rtnl_dereference(*cptr));
+ 
+-	/* No children */
+-	if (tn->empty_children > (tnode_child_length(tn) - 1))
+-		goto no_children;
+-
+-	/* One child */
+-	if (tn->empty_children == (tnode_child_length(tn) - 1))
+-		goto one_child;
+-
+ 	/* Double as long as the resulting node has a number of
+ 	 * nonempty nodes that are above the threshold.
+ 	 */
+@@ -807,19 +848,8 @@ static void resize(struct trie *t, struc
+ 	}
+ 
+ 	/* Only one child remains */
+-	if (tn->empty_children == (tnode_child_length(tn) - 1)) {
+-		unsigned long i;
+-one_child:
+-		for (i = tnode_child_length(tn); !n && i;)
+-			n = tnode_get_child(tn, --i);
+-no_children:
+-		/* compress one level */
+-		put_child_root(tp, t, tn->key, n);
+-		node_set_parent(n, tp);
+-
+-		/* drop dead node */
+-		tnode_free_init(tn);
+-		tnode_free(tn);
++	if (should_collapse(tn)) {
++		collapse(t, tn);
+ 		return;
+ 	}
+ 
diff --git a/target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch b/target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch
new file mode 100644
index 0000000000..160fbe1f3e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-23-fib_trie-Use-empty_children-instead-of-counting-empt.patch
@@ -0,0 +1,34 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:33 -0800
+Subject: [PATCH] fib_trie: Use empty_children instead of counting empty nodes
+ in stats collection
+
+It doesn't make much sense to count the pointers ourselves when
+empty_children already has a count for the number of NULL pointers stored
+in the tnode.  As such save ourselves the cycles and just use
+empty_children.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1954,16 +1954,10 @@ static void trie_collect_stats(struct tr
+ 			hlist_for_each_entry_rcu(li, &n->list, hlist)
+ 				++s->prefixes;
+ 		} else {
+-			unsigned long i;
+-
+ 			s->tnodes++;
+ 			if (n->bits < MAX_STAT_DEPTH)
+ 				s->nodesizes[n->bits]++;
+-
+-			for (i = tnode_child_length(n); i--;) {
+-				if (!rcu_access_pointer(n->child[i]))
+-					s->nullpointers++;
+-			}
++			s->nullpointers += n->empty_children;
+ 		}
+ 	}
+ 	rcu_read_unlock();
diff --git a/target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch b/target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch
new file mode 100644
index 0000000000..5eba700caa
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-24-fib_trie-Move-fib_find_alias-to-file-where-it-is-use.patch
@@ -0,0 +1,79 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:39 -0800
+Subject: [PATCH] fib_trie: Move fib_find_alias to file where it is used
+
+The function fib_find_alias is only accessed by functions in fib_trie.c as
+such it makes sense to relocate it and cast it as static so that the
+compiler can take advantage of optimizations it can do to it as a local
+function.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_lookup.h
++++ b/net/ipv4/fib_lookup.h
+@@ -32,7 +32,6 @@ int fib_dump_info(struct sk_buff *skb, u
+ 		  unsigned int);
+ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len,
+ 	       u32 tb_id, const struct nl_info *info, unsigned int nlm_flags);
+-struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
+ 
+ static inline void fib_result_assign(struct fib_result *res,
+ 				     struct fib_info *fi)
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -410,24 +410,6 @@ errout:
+ 		rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
+ }
+ 
+-/* Return the first fib alias matching TOS with
+- * priority less than or equal to PRIO.
+- */
+-struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio)
+-{
+-	if (fah) {
+-		struct fib_alias *fa;
+-		list_for_each_entry(fa, fah, fa_list) {
+-			if (fa->fa_tos > tos)
+-				continue;
+-			if (fa->fa_info->fib_priority >= prio ||
+-			    fa->fa_tos < tos)
+-				return fa;
+-		}
+-	}
+-	return NULL;
+-}
+-
+ static int fib_detect_death(struct fib_info *fi, int order,
+ 			    struct fib_info **last_resort, int *last_idx,
+ 			    int dflt)
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -998,6 +998,26 @@ static struct tnode *fib_find_node(struc
+ 	return n;
+ }
+ 
++/* Return the first fib alias matching TOS with
++ * priority less than or equal to PRIO.
++ */
++static struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio)
++{
++	struct fib_alias *fa;
++
++	if (!fah)
++		return NULL;
++
++	list_for_each_entry(fa, fah, fa_list) {
++		if (fa->fa_tos > tos)
++			continue;
++		if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos)
++			return fa;
++	}
++
++	return NULL;
++}
++
+ static void trie_rebalance(struct trie *t, struct tnode *tn)
+ {
+ 	struct tnode *tp;
diff --git a/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch b/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch
new file mode 100644
index 0000000000..c7739d0323
--- /dev/null
+++ b/target/linux/generic/patches-3.18/080-25-fib_trie-Various-clean-ups-for-handling-slen.patch
@@ -0,0 +1,116 @@
+From: Alexander Duyck <alexander.h.duyck@redhat.com>
+Date: Thu, 22 Jan 2015 15:51:45 -0800
+Subject: [PATCH] fib_trie: Various clean-ups for handling slen
+
+While doing further work on the fib_trie I noted a few items.
+
+First I was using calls that were far more complicated than they needed to
+be for determining when to push/pull the suffix length.  I have updated the
+code to reflect the simplier logic.
+
+The second issue is that I realised we weren't necessarily handling the
+case of a leaf_info struct surviving a flush.  I have updated the logic so
+that now we will call pull_suffix in the event of having a leaf info value
+left in the leaf after flushing it.
+
+Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -917,27 +917,20 @@ static void leaf_push_suffix(struct tnod
+ 
+ static void remove_leaf_info(struct tnode *l, struct leaf_info *old)
+ {
+-	struct hlist_node *prev;
+-
+-	/* record the location of the pointer to this object */
+-	prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist));
++	/* record the location of the previous list_info entry */
++	struct hlist_node **pprev = old->hlist.pprev;
++	struct leaf_info *li = hlist_entry(pprev, typeof(*li), hlist.next);
+ 
+ 	/* remove the leaf info from the list */
+ 	hlist_del_rcu(&old->hlist);
+ 
+-	/* if we emptied the list this leaf will be freed and we can sort
+-	 * out parent suffix lengths as a part of trie_rebalance
+-	 */
+-	if (hlist_empty(&l->list))
++	/* only access li if it is pointing at the last valid hlist_node */
++	if (hlist_empty(&l->list) || (*pprev))
+ 		return;
+ 
+-	/* if we removed the tail then we need to update slen */
+-	if (!rcu_access_pointer(hlist_next_rcu(prev))) {
+-		struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist);
+-
+-		l->slen = KEYLENGTH - li->plen;
+-		leaf_pull_suffix(l);
+-	}
++	/* update the trie with the latest suffix length */
++	l->slen = KEYLENGTH - li->plen;
++	leaf_pull_suffix(l);
+ }
+ 
+ static void insert_leaf_info(struct tnode *l, struct leaf_info *new)
+@@ -961,7 +954,7 @@ static void insert_leaf_info(struct tnod
+ 	}
+ 
+ 	/* if we added to the tail node then we need to update slen */
+-	if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) {
++	if (l->slen < (KEYLENGTH - new->plen)) {
+ 		l->slen = KEYLENGTH - new->plen;
+ 		leaf_push_suffix(l);
+ 	}
+@@ -1613,6 +1606,7 @@ static int trie_flush_leaf(struct tnode
+ 	struct hlist_head *lih = &l->list;
+ 	struct hlist_node *tmp;
+ 	struct leaf_info *li = NULL;
++	unsigned char plen = KEYLENGTH;
+ 
+ 	hlist_for_each_entry_safe(li, tmp, lih, hlist) {
+ 		found += trie_flush_list(&li->falh);
+@@ -1620,8 +1614,14 @@ static int trie_flush_leaf(struct tnode
+ 		if (list_empty(&li->falh)) {
+ 			hlist_del_rcu(&li->hlist);
+ 			free_leaf_info(li);
++			continue;
+ 		}
++
++		plen = li->plen;
+ 	}
++
++	l->slen = KEYLENGTH - plen;
++
+ 	return found;
+ }
+ 
+@@ -1700,13 +1700,22 @@ int fib_table_flush(struct fib_table *tb
+ 	for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
+ 		found += trie_flush_leaf(l);
+ 
+-		if (ll && hlist_empty(&ll->list))
+-			trie_leaf_remove(t, ll);
++		if (ll) {
++			if (hlist_empty(&ll->list))
++				trie_leaf_remove(t, ll);
++			else
++				leaf_pull_suffix(ll);
++		}
++
+ 		ll = l;
+ 	}
+ 
+-	if (ll && hlist_empty(&ll->list))
+-		trie_leaf_remove(t, ll);
++	if (ll) {
++		if (hlist_empty(&ll->list))
++			trie_leaf_remove(t, ll);
++		else
++			leaf_pull_suffix(ll);
++	}
+ 
+ 	pr_debug("trie_flush found=%d\n", found);
+ 	return found;
diff --git a/target/linux/generic/patches-3.18/081-01-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch b/target/linux/generic/patches-3.18/081-01-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch
new file mode 100644
index 0000000000..347049a924
--- /dev/null
+++ b/target/linux/generic/patches-3.18/081-01-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch
@@ -0,0 +1,89 @@
+From: Simon Farnsworth <simon@farnz.org.uk>
+Date: Sun, 1 Mar 2015 10:54:39 +0000
+Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received
+
+When a PADT frame is received, the socket may not be in a good state to
+close down the PPP interface. The current implementation handles this by
+simply blocking all further PPP traffic, and hoping that the lack of traffic
+will trigger the user to investigate.
+
+Use schedule_work to get to a process context from which we clear down the
+PPP interface, in a fashion analogous to hangup on a TTY-based PPP
+interface. This causes pppd to disconnect immediately, and allows tools to
+take immediate corrective action.
+
+Note that pppd's rp_pppoe.so plugin has code in it to disable the session
+when it disconnects; however, as a consequence of this patch, the session is
+already disabled before rp_pppoe.so is asked to disable the session. The
+result is a harmless error message:
+
+Failed to disconnect PPPoE socket: 114 Operation already in progress
+
+This message is safe to ignore, as long as the error is 114 Operation
+already in progress; in that specific case, it means that the PPPoE session
+has already been disabled before pppd tried to disable it.
+
+Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
+Tested-by: Dan Williams <dcbw@redhat.com>
+Tested-by: Christoph Schulz <develop@kristov.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -454,6 +454,18 @@ out:
+ 	return NET_RX_DROP;
+ }
+ 
++static void pppoe_unbind_sock_work(struct work_struct *work)
++{
++	struct pppox_sock *po = container_of(work, struct pppox_sock,
++					     proto.pppoe.padt_work);
++	struct sock *sk = sk_pppox(po);
++
++	lock_sock(sk);
++	pppox_unbind_sock(sk);
++	release_sock(sk);
++	sock_put(sk);
++}
++
+ /************************************************************************
+  *
+  * Receive a PPPoE Discovery frame.
+@@ -499,7 +511,8 @@ static int pppoe_disc_rcv(struct sk_buff
+ 		}
+ 
+ 		bh_unlock_sock(sk);
+-		sock_put(sk);
++		if (!schedule_work(&po->proto.pppoe.padt_work))
++			sock_put(sk);
+ 	}
+ 
+ abort:
+@@ -612,6 +625,8 @@ static int pppoe_connect(struct socket *
+ 
+ 	lock_sock(sk);
+ 
++	INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
++
+ 	error = -EINVAL;
+ 	if (sp->sa_protocol != PX_PROTO_OE)
+ 		goto end;
+--- a/include/linux/if_pppox.h
++++ b/include/linux/if_pppox.h
+@@ -19,6 +19,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/ppp_channel.h>
+ #include <linux/skbuff.h>
++#include <linux/workqueue.h>
+ #include <uapi/linux/if_pppox.h>
+ 
+ static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
+@@ -32,6 +33,7 @@ struct pppoe_opt {
+ 	struct pppoe_addr	pa;	  /* what this socket is bound to*/
+ 	struct sockaddr_pppox	relay;	  /* what socket data will be
+ 					     relayed to (PPPoE relaying) */
++	struct work_struct      padt_work;/* Work item for handling PADT */
+ };
+ 
+ struct pptp_opt {
diff --git a/target/linux/generic/patches-3.18/081-02-pppoe-Lacks-DST-MAC-address-check.patch b/target/linux/generic/patches-3.18/081-02-pppoe-Lacks-DST-MAC-address-check.patch
new file mode 100644
index 0000000000..f592929b3e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/081-02-pppoe-Lacks-DST-MAC-address-check.patch
@@ -0,0 +1,25 @@
+From: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
+Date: Mon, 20 Apr 2015 21:07:48 +0200
+Subject: [PATCH] pppoe: Lacks DST MAC address check
+
+A pppoe session is identified by its session ID and MAC address.
+Currently pppoe does not check if the received pkg has the correct
+MAC address. This is a problem when the eth I/F is in promisc mode
+as then any DST MAC address is accepted.
+
+Signed-off-by: Joakim Tjernlund <joakim.tjernlund@transmode.se>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -379,6 +379,9 @@ static int pppoe_rcv_core(struct sock *s
+ 	 * can't change.
+ 	 */
+ 
++	if (skb->pkt_type == PACKET_OTHERHOST)
++		goto abort_kfree;
++
+ 	if (sk->sk_state & PPPOX_BOUND) {
+ 		ppp_input(&po->chan, skb);
+ 	} else if (sk->sk_state & PPPOX_RELAY) {
diff --git a/target/linux/generic/patches-3.18/081-03-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch b/target/linux/generic/patches-3.18/081-03-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch
new file mode 100644
index 0000000000..07d64359ce
--- /dev/null
+++ b/target/linux/generic/patches-3.18/081-03-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch
@@ -0,0 +1,28 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 9 May 2015 23:08:38 +0200
+Subject: [PATCH] pppoe: drop pppoe device in pppoe_unbind_sock_work
+
+After receiving a PADT and the socket is closed, user space will no
+longer drop the reference to the pppoe device.
+This leads to errors like this:
+
+[  488.570000] unregister_netdevice: waiting for eth0.2 to become free. Usage count = 2
+
+Fixes: 287f3a943fe ("pppoe: Use workqueue to die properly when a PADT is received")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -464,6 +464,10 @@ static void pppoe_unbind_sock_work(struc
+ 	struct sock *sk = sk_pppox(po);
+ 
+ 	lock_sock(sk);
++	if (po->pppoe_dev) {
++		dev_put(po->pppoe_dev);
++		po->pppoe_dev = NULL;
++	}
+ 	pppox_unbind_sock(sk);
+ 	release_sock(sk);
+ 	sock_put(sk);
diff --git a/target/linux/generic/patches-3.18/081-06-ppp-don-t-set-sk_state-to-PPPOX_ZOMBIE-in-pppoe_disc.patch b/target/linux/generic/patches-3.18/081-06-ppp-don-t-set-sk_state-to-PPPOX_ZOMBIE-in-pppoe_disc.patch
new file mode 100644
index 0000000000..8d155eba1d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/081-06-ppp-don-t-set-sk_state-to-PPPOX_ZOMBIE-in-pppoe_disc.patch
@@ -0,0 +1,45 @@
+From: Guillaume Nault <g.nault@alphalink.fr>
+Date: Thu, 19 Nov 2015 12:52:56 +0100
+Subject: [PATCH] ppp: don't set sk_state to PPPOX_ZOMBIE in pppoe_disc_rcv()
+
+Since 287f3a943fef ("pppoe: Use workqueue to die properly when a PADT
+is received"), pppoe_disc_rcv() disconnects the socket by scheduling
+pppoe_unbind_sock_work(). This is enough to stop socket transmission
+and makes the PPPOX_ZOMBIE state uncessary.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -500,27 +500,9 @@ static int pppoe_disc_rcv(struct sk_buff
+ 
+ 	pn = pppoe_pernet(dev_net(dev));
+ 	po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+-	if (po) {
+-		struct sock *sk = sk_pppox(po);
+-
+-		bh_lock_sock(sk);
+-
+-		/* If the user has locked the socket, just ignore
+-		 * the packet.  With the way two rcv protocols hook into
+-		 * one socket family type, we cannot (easily) distinguish
+-		 * what kind of SKB it is during backlog rcv.
+-		 */
+-		if (sock_owned_by_user(sk) == 0) {
+-			/* We're no longer connect at the PPPOE layer,
+-			 * and must wait for ppp channel to disconnect us.
+-			 */
+-			sk->sk_state = PPPOX_ZOMBIE;
+-		}
+-
+-		bh_unlock_sock(sk);
++	if (po)
+ 		if (!schedule_work(&po->proto.pppoe.padt_work))
+-			sock_put(sk);
+-	}
++			sock_put(sk_pppox(po));
+ 
+ abort:
+ 	kfree_skb(skb);
diff --git a/target/linux/generic/patches-3.18/081-07-ppp-remove-PPPOX_ZOMBIE-socket-state.patch b/target/linux/generic/patches-3.18/081-07-ppp-remove-PPPOX_ZOMBIE-socket-state.patch
new file mode 100644
index 0000000000..ffdba4d923
--- /dev/null
+++ b/target/linux/generic/patches-3.18/081-07-ppp-remove-PPPOX_ZOMBIE-socket-state.patch
@@ -0,0 +1,51 @@
+From: Guillaume Nault <g.nault@alphalink.fr>
+Date: Thu, 19 Nov 2015 12:53:21 +0100
+Subject: [PATCH] ppp: remove PPPOX_ZOMBIE socket state
+
+PPPOX_ZOMBIE is never set anymore.
+
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -311,7 +311,7 @@ static void pppoe_flush_dev(struct net_d
+ 			lock_sock(sk);
+ 
+ 			if (po->pppoe_dev == dev &&
+-			    sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) {
++			    sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+ 				pppox_unbind_sock(sk);
+ 				sk->sk_state_change(sk);
+ 				po->pppoe_dev = NULL;
+@@ -775,7 +775,7 @@ static int pppoe_ioctl(struct socket *so
+ 		struct pppox_sock *relay_po;
+ 
+ 		err = -EBUSY;
+-		if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE | PPPOX_DEAD))
++		if (sk->sk_state & (PPPOX_BOUND | PPPOX_DEAD))
+ 			break;
+ 
+ 		err = -ENOTCONN;
+--- a/drivers/net/ppp/pppox.c
++++ b/drivers/net/ppp/pppox.c
+@@ -58,7 +58,7 @@ void pppox_unbind_sock(struct sock *sk)
+ {
+ 	/* Clear connection to ppp device, if attached. */
+ 
+-	if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) {
++	if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED)) {
+ 		ppp_unregister_channel(&pppox_sk(sk)->chan);
+ 		sk->sk_state = PPPOX_DEAD;
+ 	}
+--- a/include/linux/if_pppox.h
++++ b/include/linux/if_pppox.h
+@@ -91,7 +91,6 @@ enum {
+     PPPOX_CONNECTED	= 1,  /* connection established ==TCP_ESTABLISHED */
+     PPPOX_BOUND		= 2,  /* bound to ppp device */
+     PPPOX_RELAY		= 4,  /* forwarding is enabled */
+-    PPPOX_ZOMBIE	= 8,  /* dead, but still bound to ppp device */
+     PPPOX_DEAD		= 16  /* dead, useless, please clean me up!*/
+ };
+ 
diff --git a/target/linux/generic/patches-3.18/081-08-pppoe-fix-memory-corruption-in-padt-work-structure.patch b/target/linux/generic/patches-3.18/081-08-pppoe-fix-memory-corruption-in-padt-work-structure.patch
new file mode 100644
index 0000000000..147e9712db
--- /dev/null
+++ b/target/linux/generic/patches-3.18/081-08-pppoe-fix-memory-corruption-in-padt-work-structure.patch
@@ -0,0 +1,82 @@
+From: Guillaume Nault <g.nault@alphalink.fr>
+Date: Thu, 3 Dec 2015 16:49:32 +0100
+Subject: [PATCH] pppoe: fix memory corruption in padt work structure
+
+pppoe_connect() mustn't touch the padt_work field of pppoe sockets
+because that work could be already pending.
+
+[   21.473147] BUG: unable to handle kernel NULL pointer dereference at 00000004
+[   21.474523] IP: [<c1043177>] process_one_work+0x29/0x31c
+[   21.475164] *pde = 00000000
+[   21.475513] Oops: 0000 [#1] SMP
+[   21.475910] Modules linked in: pppoe pppox ppp_generic slhc crc32c_intel aesni_intel virtio_net xts aes_i586 lrw gf128mul ablk_helper cryptd evdev acpi_cpufreq processor serio_raw button ext4 crc16 mbcache jbd2 virtio_blk virtio_pci virtio_ring virtio
+[   21.476168] CPU: 2 PID: 164 Comm: kworker/2:2 Not tainted 4.4.0-rc1 #1
+[   21.476168] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Debian-1.8.2-1 04/01/2014
+[   21.476168] task: f5f83c00 ti: f5e28000 task.ti: f5e28000
+[   21.476168] EIP: 0060:[<c1043177>] EFLAGS: 00010046 CPU: 2
+[   21.476168] EIP is at process_one_work+0x29/0x31c
+[   21.484082] EAX: 00000000 EBX: f678b2a0 ECX: 00000004 EDX: 00000000
+[   21.484082] ESI: f6c69940 EDI: f5e29ef0 EBP: f5e29f0c ESP: f5e29edc
+[   21.484082]  DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
+[   21.484082] CR0: 80050033 CR2: 000000a4 CR3: 317ad000 CR4: 00040690
+[   21.484082] Stack:
+[   21.484082]  00000000 f6c69950 00000000 f6c69940 c0042338 f5e29f0c c1327945 00000000
+[   21.484082]  00000008 f678b2a0 f6c69940 f678b2b8 f5e29f30 c1043984 f5f83c00 f6c69970
+[   21.484082]  f678b2a0 c10437d3 f6775e80 f678b2a0 c10437d3 f5e29fac c1047059 f5e29f74
+[   21.484082] Call Trace:
+[   21.484082]  [<c1327945>] ? _raw_spin_lock_irq+0x28/0x30
+[   21.484082]  [<c1043984>] worker_thread+0x1b1/0x244
+[   21.484082]  [<c10437d3>] ? rescuer_thread+0x229/0x229
+[   21.484082]  [<c10437d3>] ? rescuer_thread+0x229/0x229
+[   21.484082]  [<c1047059>] kthread+0x8f/0x94
+[   21.484082]  [<c1327a32>] ? _raw_spin_unlock_irq+0x22/0x26
+[   21.484082]  [<c1327ee9>] ret_from_kernel_thread+0x21/0x38
+[   21.484082]  [<c1046fca>] ? kthread_parkme+0x19/0x19
+[   21.496082] Code: 5d c3 55 89 e5 57 56 53 89 c3 83 ec 24 89 d0 89 55 e0 8d 7d e4 e8 6c d8 ff ff b9 04 00 00 00 89 45 d8 8b 43 24 89 45 dc 8b 45 d8 <8b> 40 04 8b 80 e0 00 00 00 c1 e8 05 24 01 88 45 d7 8b 45 e0 8d
+[   21.496082] EIP: [<c1043177>] process_one_work+0x29/0x31c SS:ESP 0068:f5e29edc
+[   21.496082] CR2: 0000000000000004
+[   21.496082] ---[ end trace e362cc9cf10dae89 ]---
+
+Reported-by: Andrew <nitr0@seti.kr.ua>
+Fixes: 287f3a943fef ("pppoe: Use workqueue to die properly when a PADT is received")
+Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -550,6 +550,9 @@ static int pppoe_create(struct net *net,
+ 	sk->sk_family		= PF_PPPOX;
+ 	sk->sk_protocol		= PX_PROTO_OE;
+ 
++	INIT_WORK(&pppox_sk(sk)->proto.pppoe.padt_work,
++		  pppoe_unbind_sock_work);
++
+ 	return 0;
+ }
+ 
+@@ -614,8 +617,6 @@ static int pppoe_connect(struct socket *
+ 
+ 	lock_sock(sk);
+ 
+-	INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
+-
+ 	error = -EINVAL;
+ 	if (sp->sa_protocol != PX_PROTO_OE)
+ 		goto end;
+@@ -645,8 +646,13 @@ static int pppoe_connect(struct socket *
+ 			po->pppoe_dev = NULL;
+ 		}
+ 
+-		memset(sk_pppox(po) + 1, 0,
+-		       sizeof(struct pppox_sock) - sizeof(struct sock));
++		po->pppoe_ifindex = 0;
++		memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa));
++		memset(&po->pppoe_relay, 0, sizeof(po->pppoe_relay));
++		memset(&po->chan, 0, sizeof(po->chan));
++		po->next = NULL;
++		po->num = 0;
++
+ 		sk->sk_state = PPPOX_NONE;
+ 	}
+ 
diff --git a/target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch b/target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
new file mode 100644
index 0000000000..d3da41e918
--- /dev/null
+++ b/target/linux/generic/patches-3.18/082-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
@@ -0,0 +1,101 @@
+From: Florian Westphal <fw@strlen.de>
+Date: Thu, 17 Sep 2015 11:24:48 +0100
+Subject: [PATCH] ipv6: ip6_fragment: fix headroom tests and skb leak
+
+David Woodhouse reports skb_under_panic when we try to push ethernet
+header to fragmented ipv6 skbs:
+
+ skbuff: skb_under_panic: text:c1277f1e len:1294 put:14 head:dec98000
+ data:dec97ffc tail:0xdec9850a end:0xdec98f40 dev:br-lan
+[..]
+ip6_finish_output2+0x196/0x4da
+
+David further debugged this:
+  [..] offending fragments were arriving here with skb_headroom(skb)==10.
+  Which is reasonable, being the Solos ADSL card's header of 8 bytes
+  followed by 2 bytes of PPP frame type.
+
+The problem is that if netfilter ipv6 defragmentation is used, skb_cow()
+in ip6_forward will only see reassembled skb.
+
+Therefore, headroom is overestimated by 8 bytes (we pulled fragment
+header) and we don't check the skbs in the frag_list either.
+
+We can't do these checks in netfilter defrag since outdev isn't known yet.
+
+Furthermore, existing tests in ip6_fragment did not consider the fragment
+or ipv6 header size when checking headroom of the fraglist skbs.
+
+While at it, also fix a skb leak on memory allocation -- ip6_fragment
+must consume the skb.
+
+I tested this e1000 driver hacked to not allocate additional headroom
+(we end up in slowpath, since LL_RESERVED_SPACE is 16).
+
+If 2 bytes of headroom are allocated, fastpath is taken (14 byte
+ethernet header was pulled, so 16 byte headroom available in all
+fragments).
+
+Reported-by: David Woodhouse <dwmw2@infradead.org>
+Diagnosed-by: David Woodhouse <dwmw2@infradead.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Closes 20532
+---
+
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -597,20 +597,22 @@ int ip6_fragment(struct sk_buff *skb, in
+ 	}
+ 	mtu -= hlen + sizeof(struct frag_hdr);
+ 
++	hroom = LL_RESERVED_SPACE(rt->dst.dev);
+ 	if (skb_has_frag_list(skb)) {
+ 		int first_len = skb_pagelen(skb);
+ 		struct sk_buff *frag2;
+ 
+ 		if (first_len - hlen > mtu ||
+ 		    ((first_len - hlen) & 7) ||
+-		    skb_cloned(skb))
++		    skb_cloned(skb) ||
++		    skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
+ 			goto slow_path;
+ 
+ 		skb_walk_frags(skb, frag) {
+ 			/* Correct geometry. */
+ 			if (frag->len > mtu ||
+ 			    ((frag->len & 7) && frag->next) ||
+-			    skb_headroom(frag) < hlen)
++			    skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
+ 				goto slow_path_clean;
+ 
+ 			/* Partially cloned skb? */
+@@ -627,8 +629,6 @@ int ip6_fragment(struct sk_buff *skb, in
+ 
+ 		err = 0;
+ 		offset = 0;
+-		frag = skb_shinfo(skb)->frag_list;
+-		skb_frag_list_init(skb);
+ 		/* BUILD HEADER */
+ 
+ 		*prevhdr = NEXTHDR_FRAGMENT;
+@@ -636,8 +636,11 @@ int ip6_fragment(struct sk_buff *skb, in
+ 		if (!tmp_hdr) {
+ 			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
+ 				      IPSTATS_MIB_FRAGFAILS);
+-			return -ENOMEM;
++			err = -ENOMEM;
++			goto fail;
+ 		}
++		frag = skb_shinfo(skb)->frag_list;
++		skb_frag_list_init(skb);
+ 
+ 		__skb_pull(skb, hlen);
+ 		fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
+@@ -735,7 +738,6 @@ slow_path:
+ 	 */
+ 
+ 	*prevhdr = NEXTHDR_FRAGMENT;
+-	hroom = LL_RESERVED_SPACE(rt->dst.dev);
+ 	troom = rt->dst.dev->needed_tailroom;
+ 
+ 	/*
diff --git a/target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch b/target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch
new file mode 100644
index 0000000000..7f9f9266c6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/083-solos-pci-Increase-headroom-on-received-packets.patch
@@ -0,0 +1,54 @@
+From: David Woodhouse <dwmw2@infradead.org>
+Date: Thu, 17 Sep 2015 11:19:53 +0100
+Subject: [PATCH] solos-pci: Increase headroom on received packets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A comment in include/linux/skbuff.h says that:
+
+ * Various parts of the networking layer expect at least 32 bytes of
+ * headroom, you should not reduce this.
+
+This was demonstrated by a panic when handling fragmented IPv6 packets:
+http://marc.info/?l=linux-netdev&m=144236093519172&w=2
+
+It's not entirely clear if that comment is still valid — and if it is,
+perhaps netif_rx() ought to be enforcing it with a warning.
+
+But either way, it is rather stupid from a performance point of view
+for us to be receiving packets into a buffer which doesn't have enough
+room to prepend an Ethernet header — it means that *every* incoming
+packet is going to be need to be reallocated. So let's fix that.
+
+Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+---
+
+--- a/drivers/atm/solos-pci.c
++++ b/drivers/atm/solos-pci.c
+@@ -805,7 +805,12 @@ static void solos_bh(unsigned long card_
+ 					continue;
+ 				}
+ 
+-				skb = alloc_skb(size + 1, GFP_ATOMIC);
++				/* Use netdev_alloc_skb() because it adds NET_SKB_PAD of
++				 * headroom, and ensures we can route packets back out an
++				 * Ethernet interface (for example) without having to
++				 * reallocate. Adding NET_IP_ALIGN also ensures that both
++				 * PPPoATM and PPPoEoBR2684 packets end up aligned. */
++				skb = netdev_alloc_skb_ip_align(NULL, size + 1);
+ 				if (!skb) {
+ 					if (net_ratelimit())
+ 						dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+@@ -869,7 +874,10 @@ static void solos_bh(unsigned long card_
+ 		/* Allocate RX skbs for any ports which need them */
+ 		if (card->using_dma && card->atmdev[port] &&
+ 		    !card->rx_skb[port]) {
+-			struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC);
++			/* Unlike the MMIO case (qv) we can't add NET_IP_ALIGN
++			 * here; the FPGA can only DMA to addresses which are
++			 * aligned to 4 bytes. */
++			struct sk_buff *skb = dev_alloc_skb(RX_DMA_SIZE);
+ 			if (skb) {
+ 				SKB_CB(skb)->dma_addr =
+ 					pci_map_single(card->dev, skb->data,
diff --git a/target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch b/target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch
new file mode 100644
index 0000000000..c75af99c60
--- /dev/null
+++ b/target/linux/generic/patches-3.18/090-overlayfs-fallback-to-readonly-when-full.patch
@@ -0,0 +1,109 @@
+[linux-unionfs added to Cc]
+
+On Tue, May 19, 2015 at 09:51:20AM +0200, Bastian Bittorf wrote:
+> Hi Miklos,
+>
+> sorry for writing directly to you, feel free to forward
+> this to the appropriate mailinglist.
+>
+> we have a problem with mainline overlay filesystem on kernel 3.18:
+> https://dev.openwrt.org/ticket/19564
+>
+> 2 things are odd:
+> when the working filesystem is full, overlays fails with:
+>
+> overlayfs: failed to create directory /overlay/work/work
+>
+> what is strange, that we call it with:
+>
+> mount(overlay, "/mnt", "overlay", MS_NOATIME, lowerdir)
+>
+> see here:
+> http://nbd.name/gitweb.cgi?p=fstools.git;a=blob;f=libfstools/mount.c;h=81176ce399b4cd8e2d347c0008c13dec92407f55;hb=e6004000ff15d7bd32cf5663e8690fc94d7ec747#l125
+>
+> do you have an idea whats wrong?
+> 1) is it really needed, that we need space for creating dir "/overlay/work"?
+> 2) why does overlay need "/overlay/work/work"?
+
+The work directory is needed for atomic copy-up and similar.  It is not actually
+necessary to mount a read-only overlay.  Post 4.0 it is possible to mount the
+overlay without workdir (but even then it won't happen automatically in case the
+upper fs is full, so this should be fixed in the latest kernel too).
+
+Could you please try the following patch?  If the workdir can't be created it
+will fall back to mounting the overlay read-only.
+
+Thanks,
+Miklos
+
+---
+ fs/overlayfs/copy_up.c |    3 +++
+ fs/overlayfs/dir.c     |    9 +++++++++
+ fs/overlayfs/super.c   |   12 +++++++++---
+ 3 files changed, 21 insertions(+), 3 deletions(-)
+
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -313,6 +313,9 @@ int ovl_copy_up_one(struct dentry *paren
+ 	struct cred *override_cred;
+ 	char *link = NULL;
+ 
++	if (WARN_ON(!workdir))
++		return -EROFS;
++
+ 	ovl_path_upper(parent, &parentpath);
+ 	upperdir = parentpath.dentry;
+ 
+--- a/fs/overlayfs/dir.c
++++ b/fs/overlayfs/dir.c
+@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(st
+ 	struct kstat stat;
+ 	int err;
+ 
++	if (WARN_ON(!workdir))
++		return ERR_PTR(-EROFS);
++
+ 	err = ovl_lock_rename_workdir(workdir, upperdir);
+ 	if (err)
+ 		goto out;
+@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(stru
+ 	struct dentry *newdentry;
+ 	int err;
+ 
++	if (WARN_ON(!workdir))
++		return -EROFS;
++
+ 	err = ovl_lock_rename_workdir(workdir, upperdir);
+ 	if (err)
+ 		goto out;
+@@ -507,6 +513,9 @@ static int ovl_remove_and_whiteout(struc
+ 	int err;
+ 	int flags = 0;
+ 
++	if (WARN_ON(!workdir))
++		return -EROFS;
++
+ 	if (is_dir) {
+ 		opaquedir = ovl_check_empty_and_clear(dentry);
+ 		err = PTR_ERR(opaquedir);
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -760,9 +760,15 @@ static int ovl_fill_super(struct super_b
+ 	ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
+ 	err = PTR_ERR(ufs->workdir);
+ 	if (IS_ERR(ufs->workdir)) {
+-		pr_err("overlayfs: failed to create directory %s/%s\n",
+-		       ufs->config.workdir, OVL_WORKDIR_NAME);
+-		goto out_put_lower_mnt;
++		if (err == -ENOSPC || err == -EROFS) {
++			pr_warning("overlayfs: failed to create work directory (%s), mounting read-only\n", err == ENOSPC ? "ENOSPC" : "EROFS");
++			sb->s_flags |= MS_RDONLY;
++			ufs->workdir = NULL;
++		} else {
++			pr_err("overlayfs: failed to create directory %s/%s\n",
++			       ufs->config.workdir, OVL_WORKDIR_NAME);
++			goto out_put_lower_mnt;
++		}
+ 	}
+ 
+ 	/*
diff --git a/target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K b/target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K
new file mode 100644
index 0000000000..24aa0752d8
--- /dev/null
+++ b/target/linux/generic/patches-3.18/091-mtd-spi-nor-add-support-Spansion_S25FL164K
@@ -0,0 +1,10 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -567,6 +567,7 @@ static const struct spi_device_id spi_no
+ 	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
+ 	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
+ 	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
++	{ "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
+ 
+ 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
+ 	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
diff --git a/target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch b/target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch
new file mode 100644
index 0000000000..fa3ab6a638
--- /dev/null
+++ b/target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch
@@ -0,0 +1,47 @@
+From: Mark Brown <broonie@kernel.org>
+Date: Tue, 9 Dec 2014 19:46:56 +0000
+Subject: [PATCH] spi: Check to see if the device is processing a message
+ before we idle
+
+cur_msg is updated under the queue lock and holds the message we are
+currently processing. Since currently we only ever do removals in the
+pump kthread it doesn't matter in what order we do things but we want
+to be able to push things out from the submitting thread so pull the
+check to see if we're currently handling a message before we check to
+see if the queue is idle.
+
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -891,8 +891,16 @@ static void spi_pump_messages(struct kth
+ 	bool was_busy = false;
+ 	int ret;
+ 
+-	/* Lock queue and check for queue work */
++	/* Lock queue */
+ 	spin_lock_irqsave(&master->queue_lock, flags);
++
++	/* Make sure we are not already running a message */
++	if (master->cur_msg) {
++		spin_unlock_irqrestore(&master->queue_lock, flags);
++		return;
++	}
++
++	/* Check if the queue is idle */
+ 	if (list_empty(&master->queue) || !master->running) {
+ 		if (!master->busy) {
+ 			spin_unlock_irqrestore(&master->queue_lock, flags);
+@@ -916,11 +924,6 @@ static void spi_pump_messages(struct kth
+ 		return;
+ 	}
+ 
+-	/* Make sure we are not already running a message */
+-	if (master->cur_msg) {
+-		spin_unlock_irqrestore(&master->queue_lock, flags);
+-		return;
+-	}
+ 	/* Extract head of queue */
+ 	master->cur_msg =
+ 		list_first_entry(&master->queue, struct spi_message, queue);
diff --git a/target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch b/target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
new file mode 100644
index 0000000000..b74b4cb93b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
@@ -0,0 +1,184 @@
+From: Mark Brown <broonie@kernel.org>
+Date: Tue, 9 Dec 2014 21:38:05 +0000
+Subject: [PATCH] spi: Pump transfers inside calling context for spi_sync()
+
+If we are using the standard SPI message pump (which all drivers should be
+transitioning over to) then special case the message enqueue and instead of
+starting the worker thread to push messages to the hardware do so in the
+context of the caller if the controller is idle. This avoids a context
+switch in the common case where the controller has a single user in a
+single thread, for short PIO transfers there may be no need to context
+switch away from the calling context to complete the transfer.
+
+The code is a bit more complex than is desirable in part due to the need
+to handle drivers not using the standard queue and in part due to handling
+the various combinations of bus locking and asynchronous submission in
+interrupt context.
+
+It is still suboptimal since it will still wake the message pump for each
+transfer in order to schedule idling of the hardware and if multiple
+contexts are using the controller simultaneously a caller may end up
+pumping a message for some random other thread rather than for itself,
+and if the thread ends up deferring due to another context idling the
+hardware then it will just busy wait.  It can, however, have the benefit
+of aggregating power up and down of the hardware when a caller performs
+a series of transfers back to back without any need for the use of
+spi_async().
+
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -882,6 +882,9 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_t
+  * needs processing and if so call out to the driver to initialize hardware
+  * and transfer each message.
+  *
++ * Note that it is called both from the kthread itself and also from
++ * inside spi_sync(); the queue extraction handling at the top of the
++ * function should deal with this safely.
+  */
+ static void spi_pump_messages(struct kthread_work *work)
+ {
+@@ -900,6 +903,13 @@ static void spi_pump_messages(struct kth
+ 		return;
+ 	}
+ 
++	/* If another context is idling the device then defer */
++	if (master->idling) {
++		queue_kthread_work(&master->kworker, &master->pump_messages);
++		spin_unlock_irqrestore(&master->queue_lock, flags);
++		return;
++	}
++
+ 	/* Check if the queue is idle */
+ 	if (list_empty(&master->queue) || !master->running) {
+ 		if (!master->busy) {
+@@ -907,7 +917,9 @@ static void spi_pump_messages(struct kth
+ 			return;
+ 		}
+ 		master->busy = false;
++		master->idling = true;
+ 		spin_unlock_irqrestore(&master->queue_lock, flags);
++
+ 		kfree(master->dummy_rx);
+ 		master->dummy_rx = NULL;
+ 		kfree(master->dummy_tx);
+@@ -921,6 +933,10 @@ static void spi_pump_messages(struct kth
+ 			pm_runtime_put_autosuspend(master->dev.parent);
+ 		}
+ 		trace_spi_master_idle(master);
++
++		spin_lock_irqsave(&master->queue_lock, flags);
++		master->idling = false;
++		spin_unlock_irqrestore(&master->queue_lock, flags);
+ 		return;
+ 	}
+ 
+@@ -1166,12 +1182,9 @@ static int spi_destroy_queue(struct spi_
+ 	return 0;
+ }
+ 
+-/**
+- * spi_queued_transfer - transfer function for queued transfers
+- * @spi: spi device which is requesting transfer
+- * @msg: spi message which is to handled is queued to driver queue
+- */
+-static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
++static int __spi_queued_transfer(struct spi_device *spi,
++				 struct spi_message *msg,
++				 bool need_pump)
+ {
+ 	struct spi_master *master = spi->master;
+ 	unsigned long flags;
+@@ -1186,13 +1199,23 @@ static int spi_queued_transfer(struct sp
+ 	msg->status = -EINPROGRESS;
+ 
+ 	list_add_tail(&msg->queue, &master->queue);
+-	if (!master->busy)
++	if (!master->busy && need_pump)
+ 		queue_kthread_work(&master->kworker, &master->pump_messages);
+ 
+ 	spin_unlock_irqrestore(&master->queue_lock, flags);
+ 	return 0;
+ }
+ 
++/**
++ * spi_queued_transfer - transfer function for queued transfers
++ * @spi: spi device which is requesting transfer
++ * @msg: spi message which is to handled is queued to driver queue
++ */
++static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
++{
++	return __spi_queued_transfer(spi, msg, true);
++}
++
+ static int spi_master_initialize_queue(struct spi_master *master)
+ {
+ 	int ret;
+@@ -2104,19 +2127,46 @@ static int __spi_sync(struct spi_device
+ 	DECLARE_COMPLETION_ONSTACK(done);
+ 	int status;
+ 	struct spi_master *master = spi->master;
++	unsigned long flags;
++
++	status = __spi_validate(spi, message);
++	if (status != 0)
++		return status;
+ 
+ 	message->complete = spi_complete;
+ 	message->context = &done;
++	message->spi = spi;
+ 
+ 	if (!bus_locked)
+ 		mutex_lock(&master->bus_lock_mutex);
+ 
+-	status = spi_async_locked(spi, message);
++	/* If we're not using the legacy transfer method then we will
++	 * try to transfer in the calling context so special case.
++	 * This code would be less tricky if we could remove the
++	 * support for driver implemented message queues.
++	 */
++	if (master->transfer == spi_queued_transfer) {
++		spin_lock_irqsave(&master->bus_lock_spinlock, flags);
++
++		trace_spi_message_submit(message);
++
++		status = __spi_queued_transfer(spi, message, false);
++
++		spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
++	} else {
++		status = spi_async_locked(spi, message);
++	}
+ 
+ 	if (!bus_locked)
+ 		mutex_unlock(&master->bus_lock_mutex);
+ 
+ 	if (status == 0) {
++		/* Push out the messages in the calling context if we
++		 * can.
++		 */
++		if (master->transfer == spi_queued_transfer)
++			spi_pump_messages(&master->pump_messages);
++
+ 		wait_for_completion(&done);
+ 		status = message->status;
+ 	}
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -260,6 +260,7 @@ static inline void spi_unregister_driver
+  * @pump_messages: work struct for scheduling work to the message pump
+  * @queue_lock: spinlock to syncronise access to message queue
+  * @queue: message queue
++ * @idling: the device is entering idle state
+  * @cur_msg: the currently in-flight message
+  * @cur_msg_prepared: spi_prepare_message was called for the currently
+  *                    in-flight message
+@@ -425,6 +426,7 @@ struct spi_master {
+ 	spinlock_t			queue_lock;
+ 	struct list_head		queue;
+ 	struct spi_message		*cur_msg;
++	bool				idling;
+ 	bool				busy;
+ 	bool				running;
+ 	bool				rt;
diff --git a/target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch b/target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch
new file mode 100644
index 0000000000..a5d85be2b4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch
@@ -0,0 +1,83 @@
+From: Mark Brown <broonie@kernel.org>
+Date: Wed, 10 Dec 2014 13:46:33 +0000
+Subject: [PATCH] spi: Only idle the message pump in the worker kthread
+
+In order to avoid the situation where the kthread is waiting for another
+context to make the hardware idle let the message pump know if it's being
+called from the worker thread context and if it isn't then defer to the
+worker thread instead of idling the hardware immediately. This will ensure
+that if this situation happens we block rather than busy waiting.
+
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -875,8 +875,9 @@ void spi_finalize_current_transfer(struc
+ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
+ 
+ /**
+- * spi_pump_messages - kthread work function which processes spi message queue
+- * @work: pointer to kthread work struct contained in the master struct
++ * __spi_pump_messages - function which processes spi message queue
++ * @master: master to process queue for
++ * @in_kthread: true if we are in the context of the message pump thread
+  *
+  * This function checks if there is any spi message in the queue that
+  * needs processing and if so call out to the driver to initialize hardware
+@@ -886,10 +887,8 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_t
+  * inside spi_sync(); the queue extraction handling at the top of the
+  * function should deal with this safely.
+  */
+-static void spi_pump_messages(struct kthread_work *work)
++static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+ {
+-	struct spi_master *master =
+-		container_of(work, struct spi_master, pump_messages);
+ 	unsigned long flags;
+ 	bool was_busy = false;
+ 	int ret;
+@@ -916,6 +915,15 @@ static void spi_pump_messages(struct kth
+ 			spin_unlock_irqrestore(&master->queue_lock, flags);
+ 			return;
+ 		}
++
++		/* Only do teardown in the thread */
++		if (!in_kthread) {
++			queue_kthread_work(&master->kworker,
++					   &master->pump_messages);
++			spin_unlock_irqrestore(&master->queue_lock, flags);
++			return;
++		}
++
+ 		master->busy = false;
+ 		master->idling = true;
+ 		spin_unlock_irqrestore(&master->queue_lock, flags);
+@@ -1004,6 +1012,18 @@ static void spi_pump_messages(struct kth
+ 	}
+ }
+ 
++/**
++ * spi_pump_messages - kthread work function which processes spi message queue
++ * @work: pointer to kthread work struct contained in the master struct
++ */
++static void spi_pump_messages(struct kthread_work *work)
++{
++	struct spi_master *master =
++		container_of(work, struct spi_master, pump_messages);
++
++	__spi_pump_messages(master, true);
++}
++
+ static int spi_init_queue(struct spi_master *master)
+ {
+ 	struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+@@ -2165,7 +2185,7 @@ static int __spi_sync(struct spi_device
+ 		 * can.
+ 		 */
+ 		if (master->transfer == spi_queued_transfer)
+-			spi_pump_messages(&master->pump_messages);
++			__spi_pump_messages(master, false);
+ 
+ 		wait_for_completion(&done);
+ 		status = message->status;
diff --git a/target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch b/target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch
new file mode 100644
index 0000000000..4c5cd596f7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch
@@ -0,0 +1,146 @@
+From 279c6c7fa64f5763e6b9f05e7ab3840092e702e7 Mon Sep 17 00:00:00 2001
+From: Stephen Hemminger <stephen@networkplumber.org>
+Date: Mon, 29 Jun 2015 14:57:48 -1000
+Subject: [PATCH] api: fix compatibility of linux/in.h with netinet/in.h
+
+u
+This fixes breakage to iproute2 build with recent kernel headers
+caused by:
+   commit a263653ed798216c0069922d7b5237ca49436007
+   Author: Pablo Neira Ayuso <pablo@netfilter.org>
+   Date:   Wed Jun 17 10:28:27 2015 -0500
+
+   netfilter: don't pull include/linux/netfilter.h from netns headers
+
+The issue is that definitions in linux/in.h overlap with those
+in netinet/in.h. This patch solves this by introducing the same
+mechanism as was used to solve the same problem with linux/in6.h
+
+Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/uapi/linux/in.h          | 16 +++++++++++++---
+ include/uapi/linux/libc-compat.h | 22 ++++++++++++++++++++++
+ 2 files changed, 35 insertions(+), 3 deletions(-)
+
+--- a/include/uapi/linux/in.h
++++ b/include/uapi/linux/in.h
+@@ -19,8 +19,10 @@
+ #define _UAPI_LINUX_IN_H
+ 
+ #include <linux/types.h>
++#include <linux/libc-compat.h>
+ #include <linux/socket.h>
+ 
++#if __UAPI_DEF_IN_IPPROTO
+ /* Standard well-defined IP protocols.  */
+ enum {
+   IPPROTO_IP = 0,		/* Dummy protocol for TCP		*/
+@@ -73,12 +75,14 @@ enum {
+ #define IPPROTO_RAW		IPPROTO_RAW
+   IPPROTO_MAX
+ };
++#endif
+ 
+-
++#if __UAPI_DEF_IN_ADDR
+ /* Internet address. */
+ struct in_addr {
+ 	__be32	s_addr;
+ };
++#endif
+ 
+ #define IP_TOS		1
+ #define IP_TTL		2
+@@ -154,6 +158,7 @@ struct in_addr {
+ 
+ /* Request struct for multicast socket ops */
+ 
++#if __UAPI_DEF_IP_MREQ
+ struct ip_mreq  {
+ 	struct in_addr imr_multiaddr;	/* IP multicast address of group */
+ 	struct in_addr imr_interface;	/* local IP address of interface */
+@@ -205,14 +210,18 @@ struct group_filter {
+ #define GROUP_FILTER_SIZE(numsrc) \
+ 	(sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
+ 	+ (numsrc) * sizeof(struct __kernel_sockaddr_storage))
++#endif
+ 
++#if __UAPI_DEF_IN_PKTINFO
+ struct in_pktinfo {
+ 	int		ipi_ifindex;
+ 	struct in_addr	ipi_spec_dst;
+ 	struct in_addr	ipi_addr;
+ };
++#endif
+ 
+ /* Structure describing an Internet (IP) socket address. */
++#if  __UAPI_DEF_SOCKADDR_IN
+ #define __SOCK_SIZE__	16		/* sizeof(struct sockaddr)	*/
+ struct sockaddr_in {
+   __kernel_sa_family_t	sin_family;	/* Address family		*/
+@@ -224,8 +233,9 @@ struct sockaddr_in {
+ 			sizeof(unsigned short int) - sizeof(struct in_addr)];
+ };
+ #define sin_zero	__pad		/* for BSD UNIX comp. -FvK	*/
++#endif
+ 
+-
++#if __UAPI_DEF_IN_CLASS
+ /*
+  * Definitions of the bits in an Internet address integer.
+  * On subnets, host and network parts are found according
+@@ -276,7 +286,7 @@ struct sockaddr_in {
+ #define INADDR_ALLHOSTS_GROUP 	0xe0000001U	/* 224.0.0.1   */
+ #define INADDR_ALLRTRS_GROUP    0xe0000002U	/* 224.0.0.2 */
+ #define INADDR_MAX_LOCAL_GROUP  0xe00000ffU	/* 224.0.0.255 */
+-
++#endif
+ 
+ /* <asm/byteorder.h> contains the htonl type stuff.. */
+ #include <asm/byteorder.h> 
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -56,6 +56,13 @@
+ 
+ /* GLIBC headers included first so don't define anything
+  * that would already be defined. */
++#define __UAPI_DEF_IN_ADDR		0
++#define __UAPI_DEF_IN_IPPROTO		0
++#define __UAPI_DEF_IN_PKTINFO		0
++#define __UAPI_DEF_IP_MREQ		0
++#define __UAPI_DEF_SOCKADDR_IN		0
++#define __UAPI_DEF_IN_CLASS		0
++
+ #define __UAPI_DEF_IN6_ADDR		0
+ /* The exception is the in6_addr macros which must be defined
+  * if the glibc code didn't define them. This guard matches
+@@ -76,6 +83,13 @@
+ /* Linux headers included first, and we must define everything
+  * we need. The expectation is that glibc will check the
+  * __UAPI_DEF_* defines and adjust appropriately. */
++#define __UAPI_DEF_IN_ADDR		1
++#define __UAPI_DEF_IN_IPPROTO		1
++#define __UAPI_DEF_IN_PKTINFO		1
++#define __UAPI_DEF_IP_MREQ		1
++#define __UAPI_DEF_SOCKADDR_IN		1
++#define __UAPI_DEF_IN_CLASS		1
++
+ #define __UAPI_DEF_IN6_ADDR		1
+ /* We unconditionally define the in6_addr macros and glibc must
+  * coordinate. */
+@@ -99,6 +113,14 @@
+  * that we need. */
+ #else /* !defined(__GLIBC__) */
+ 
++/* Definitions for in.h */
++#define __UAPI_DEF_IN_ADDR		1
++#define __UAPI_DEF_IN_IPPROTO		1
++#define __UAPI_DEF_IN_PKTINFO		1
++#define __UAPI_DEF_IP_MREQ		1
++#define __UAPI_DEF_SOCKADDR_IN		1
++#define __UAPI_DEF_IN_CLASS		1
++
+ /* Definitions for in6.h */
+ #define __UAPI_DEF_IN6_ADDR		1
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
diff --git a/target/linux/generic/patches-3.18/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch b/target/linux/generic/patches-3.18/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch
new file mode 100644
index 0000000000..213f85b0a9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch
@@ -0,0 +1,90 @@
+From e45a502bdeae5a075257c4f061d1ff4ff0821354 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 13 Oct 2016 13:07:36 -0700
+Subject: [PATCH] mm: remove gup_flags FOLL_WRITE games from __get_user_pages()
+
+[ Upstream commit 19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619 ]
+
+This is an ancient bug that was actually attempted to be fixed once
+(badly) by me eleven years ago in commit 4ceb5db9757a ("Fix
+get_user_pages() race for write access") but that was then undone due to
+problems on s390 by commit f33ea7f404e5 ("fix get_user_pages bug").
+
+In the meantime, the s390 situation has long been fixed, and we can now
+fix it by checking the pte_dirty() bit properly (and do it better).  The
+s390 dirty bit was implemented in abf09bed3cce ("s390/mm: implement
+software dirty bits") which made it into v3.9.  Earlier kernels will
+have to look at the page state itself.
+
+Also, the VM has become more scalable, and what used a purely
+theoretical race back then has become easier to trigger.
+
+To fix it, we introduce a new internal FOLL_COW flag to mark the "yes,
+we already did a COW" rather than play racy games with FOLL_WRITE that
+is very fundamental, and then use the pte dirty flag to validate that
+the FOLL_COW flag is still valid.
+
+Reported-and-tested-by: Phil "not Paul" Oester <kernel@linuxace.com>
+Acked-by: Hugh Dickins <hughd@google.com>
+Reviewed-by: Michal Hocko <mhocko@suse.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Willy Tarreau <w@1wt.eu>
+Cc: Nick Piggin <npiggin@gmail.com>
+Cc: Greg Thelen <gthelen@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+---
+ include/linux/mm.h |  1 +
+ mm/gup.c           | 14 ++++++++++++--
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -2029,6 +2029,7 @@ static inline struct page *follow_page(s
+ #define FOLL_NUMA	0x200	/* force NUMA hinting page fault */
+ #define FOLL_MIGRATION	0x400	/* wait for page to replace migration entry */
+ #define FOLL_TRIED	0x800	/* a retry, previous pass started an IO */
++#define FOLL_COW	0x4000	/* internal GUP flag */
+ 
+ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
+ 			void *data);
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -32,6 +32,16 @@ static struct page *no_page_table(struct
+ 	return NULL;
+ }
+ 
++/*
++ * FOLL_FORCE can write to even unwritable pte's, but only
++ * after we've gone through a COW cycle and they are dirty.
++ */
++static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
++{
++	return pte_write(pte) ||
++		((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
++}
++
+ static struct page *follow_page_pte(struct vm_area_struct *vma,
+ 		unsigned long address, pmd_t *pmd, unsigned int flags)
+ {
+@@ -66,7 +76,7 @@ retry:
+ 	}
+ 	if ((flags & FOLL_NUMA) && pte_numa(pte))
+ 		goto no_page;
+-	if ((flags & FOLL_WRITE) && !pte_write(pte)) {
++	if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
+ 		pte_unmap_unlock(ptep, ptl);
+ 		return NULL;
+ 	}
+@@ -315,7 +325,7 @@ static int faultin_page(struct task_stru
+ 	 * reCOWed by userspace write).
+ 	 */
+ 	if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
+-		*flags &= ~FOLL_WRITE;
++	        *flags |= FOLL_COW;
+ 	return 0;
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch b/target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch
new file mode 100644
index 0000000000..352bf6de15
--- /dev/null
+++ b/target/linux/generic/patches-3.18/099-module_arch_freeing_init-new-hook-for-archs-before-m.patch
@@ -0,0 +1,182 @@
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Tue, 20 Jan 2015 09:07:04 +1030
+Subject: [PATCH] module_arch_freeing_init(): new hook for archs before module->module_init freed.
+
+Archs have been abusing module_free() to clean up their arch-specific
+allocations.  Since module_free() is also (ab)used by BPF and trace code,
+let's keep it to simple allocations, and provide a hook called before
+that.
+
+This means that avr32, ia64, parisc and s390 no longer need to implement
+their own module_free() at all.  avr32 doesn't need module_finalize()
+either.
+
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Cc: Chris Metcalf <cmetcalf@ezchip.com>
+Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
+Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: Fenghua Yu <fenghua.yu@intel.com>
+Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
+Cc: Helge Deller <deller@gmx.de>
+Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
+Cc: linux-kernel@vger.kernel.org
+Cc: linux-ia64@vger.kernel.org
+Cc: linux-parisc@vger.kernel.org
+Cc: linux-s390@vger.kernel.org
+
+Origin: backport, https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=d453cded05ee219b77815ea194dc36efa5398bca
+---
+ arch/avr32/kernel/module.c   | 13 +------------
+ arch/ia64/kernel/module.c    |  6 ++----
+ arch/parisc/kernel/module.c  |  6 +-----
+ arch/s390/kernel/module.c    | 10 +++-------
+ arch/tile/kernel/module.c    |  2 +-
+ include/linux/moduleloader.h |  2 ++
+ kernel/module.c              |  7 +++++++
+ 7 files changed, 17 insertions(+), 29 deletions(-)
+
+--- a/arch/avr32/kernel/module.c
++++ b/arch/avr32/kernel/module.c
+@@ -19,12 +19,10 @@
+ #include <linux/moduleloader.h>
+ #include <linux/vmalloc.h>
+ 
+-void module_free(struct module *mod, void *module_region)
++void module_arch_freeing_init(struct module *mod)
+ {
+ 	vfree(mod->arch.syminfo);
+ 	mod->arch.syminfo = NULL;
+-
+-	vfree(module_region);
+ }
+ 
+ static inline int check_rela(Elf32_Rela *rela, struct module *module,
+@@ -291,12 +289,3 @@ int apply_relocate_add(Elf32_Shdr *sechd
+ 
+ 	return ret;
+ }
+-
+-int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+-		    struct module *module)
+-{
+-	vfree(module->arch.syminfo);
+-	module->arch.syminfo = NULL;
+-
+-	return 0;
+-}
+--- a/arch/ia64/kernel/module.c
++++ b/arch/ia64/kernel/module.c
+@@ -305,14 +305,12 @@ plt_target (struct plt_entry *plt)
+ #endif /* !USE_BRL */
+ 
+ void
+-module_free (struct module *mod, void *module_region)
++module_arch_freeing_init (struct module *mod)
+ {
+-	if (mod && mod->arch.init_unw_table &&
+-	    module_region == mod->module_init) {
++	if (mod->arch.init_unw_table) {
+ 		unw_remove_unwind_table(mod->arch.init_unw_table);
+ 		mod->arch.init_unw_table = NULL;
+ 	}
+-	vfree(module_region);
+ }
+ 
+ /* Have we already seen one of these relocations? */
+--- a/arch/parisc/kernel/module.c
++++ b/arch/parisc/kernel/module.c
+@@ -298,14 +298,10 @@ static inline unsigned long count_stubs(
+ }
+ #endif
+ 
+-
+-/* Free memory returned from module_alloc */
+-void module_free(struct module *mod, void *module_region)
++void module_arch_freeing_init(struct module *mod)
+ {
+ 	kfree(mod->arch.section);
+ 	mod->arch.section = NULL;
+-
+-	vfree(module_region);
+ }
+ 
+ /* Additional bytes needed in front of individual sections */
+--- a/arch/s390/kernel/module.c
++++ b/arch/s390/kernel/module.c
+@@ -55,14 +55,10 @@ void *module_alloc(unsigned long size)
+ }
+ #endif
+ 
+-/* Free memory returned from module_alloc */
+-void module_free(struct module *mod, void *module_region)
++void module_arch_freeing_init(struct module *mod)
+ {
+-	if (mod) {
+-		vfree(mod->arch.syminfo);
+-		mod->arch.syminfo = NULL;
+-	}
+-	vfree(module_region);
++	vfree(mod->arch.syminfo);
++	mod->arch.syminfo = NULL;
+ }
+ 
+ static void check_rela(Elf_Rela *rela, struct module *me)
+--- a/arch/tile/kernel/module.c
++++ b/arch/tile/kernel/module.c
+@@ -83,7 +83,7 @@ void module_free(struct module *mod, voi
+ 		     0, 0, 0, NULL, NULL, 0);
+ 
+ 	/*
+-	 * FIXME: If module_region == mod->module_init, trim exception
++	 * FIXME: Add module_arch_freeing_init to trim exception
+ 	 * table entries.
+ 	 */
+ }
+--- a/include/linux/moduleloader.h
++++ b/include/linux/moduleloader.h
+@@ -82,4 +82,6 @@ int module_finalize(const Elf_Ehdr *hdr,
+ /* Any cleanup needed when module leaves. */
+ void module_arch_cleanup(struct module *mod);
+ 
++/* Any cleanup before freeing mod->module_init */
++void module_arch_freeing_init(struct module *mod);
+ #endif
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -1840,6 +1840,10 @@ void __weak module_arch_cleanup(struct m
+ {
+ }
+ 
++void __weak module_arch_freeing_init(struct module *mod)
++{
++}
++
+ /* Free a module, remove from lists, etc. */
+ static void free_module(struct module *mod)
+ {
+@@ -1872,6 +1876,7 @@ static void free_module(struct module *m
+ 
+ 	/* This may be NULL, but that's OK */
+ 	unset_module_init_ro_nx(mod);
++	module_arch_freeing_init(mod);
+ 	module_free(mod, mod->module_init);
+ 	kfree(mod->args);
+ 	percpu_modfree(mod);
+@@ -2983,6 +2988,7 @@ static struct module *layout_and_allocat
+ static void module_deallocate(struct module *mod, struct load_info *info)
+ {
+ 	percpu_modfree(mod);
++	module_arch_freeing_init(mod);
+ 	module_free(mod, mod->module_init);
+ 	module_free(mod, mod->module_core);
+ }
+@@ -3105,6 +3111,7 @@ static int do_init_module(struct module
+ 	rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
+ #endif
+ 	unset_module_init_ro_nx(mod);
++	module_arch_freeing_init(mod);
+ 	module_free(mod, mod->module_init);
+ 	mod->module_init = NULL;
+ 	mod->init_size = 0;
diff --git a/target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch b/target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch
new file mode 100644
index 0000000000..a5645596f9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/102-ehci_hcd_ignore_oc.patch
@@ -0,0 +1,82 @@
+From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:29 +0100
+Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent
+ checking
+
+This patch adds an ignore_oc flag which can be set by EHCI controller
+not supporting or wanting to disable overcurrent checking. The EHCI
+platform data in include/linux/usb/ehci_pdriver.h is also augmented to
+take advantage of this new flag.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ drivers/usb/host/ehci-hcd.c      |    2 +-
+ drivers/usb/host/ehci-hub.c      |    4 ++--
+ drivers/usb/host/ehci-platform.c |    1 +
+ drivers/usb/host/ehci.h          |    1 +
+ include/linux/usb/ehci_pdriver.h |    1 +
+ 5 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -633,7 +633,7 @@ static int ehci_run (struct usb_hcd *hcd
+ 		"USB %x.%x started, EHCI %x.%02x%s\n",
+ 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
+ 		temp >> 8, temp & 0xff,
+-		ignore_oc ? ", overcurrent ignored" : "");
++		(ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
+ 
+ 	ehci_writel(ehci, INTR_MASK,
+ 		    &ehci->regs->intr_enable); /* Turn On Interrupts */
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -635,7 +635,7 @@ ehci_hub_status_data (struct usb_hcd *hc
+ 	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
+ 	 * PORT_POWER; that's surprising, but maybe within-spec.
+ 	 */
+-	if (!ignore_oc)
++	if (!ignore_oc && !ehci->ignore_oc)
+ 		mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ 	else
+ 		mask = PORT_CSC | PORT_PEC;
+@@ -995,7 +995,7 @@ int ehci_hub_control(
+ 		if (temp & PORT_PEC)
+ 			status |= USB_PORT_STAT_C_ENABLE << 16;
+ 
+-		if ((temp & PORT_OCC) && !ignore_oc){
++		if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
+ 			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ 
+ 			/*
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -226,6 +226,8 @@ static int ehci_platform_probe(struct pl
+ 		ehci->big_endian_desc = 1;
+ 	if (pdata->big_endian_mmio)
+ 		ehci->big_endian_mmio = 1;
++	if (pdata->ignore_oc)
++		ehci->ignore_oc = 1;
+ 
+ #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ 	if (ehci->big_endian_mmio) {
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -226,6 +226,7 @@ struct ehci_hcd {			/* one per controlle
+ 	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
+ 	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
+ 	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
++	unsigned		ignore_oc:1;
+ 
+ 	/* required for usb32 quirk */
+ 	#define OHCI_CTRL_HCFS          (3 << 6)
+--- a/include/linux/usb/ehci_pdriver.h
++++ b/include/linux/usb/ehci_pdriver.h
+@@ -45,6 +45,7 @@ struct usb_ehci_pdata {
+ 	unsigned	big_endian_desc:1;
+ 	unsigned	big_endian_mmio:1;
+ 	unsigned	no_io_watchdog:1;
++	unsigned	ignore_oc:1;
+ 
+ 	/* Turn on all power and clocks */
+ 	int (*power_on)(struct platform_device *pdev);
diff --git a/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
new file mode 100644
index 0000000000..f671db6e94
--- /dev/null
+++ b/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
@@ -0,0 +1,86 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 10 Apr 2015 13:35:29 +0200
+Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support
+
+It is required for renames on overlayfs
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s
+ static int jffs2_rmdir (struct inode *,struct dentry *);
+ static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
+ static int jffs2_rename (struct inode *, struct dentry *,
+-			 struct inode *, struct dentry *);
++			 struct inode *, struct dentry *, unsigned int);
+ 
+ const struct file_operations jffs2_dir_operations =
+ {
+@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_
+ 	.mkdir =	jffs2_mkdir,
+ 	.rmdir =	jffs2_rmdir,
+ 	.mknod =	jffs2_mknod,
+-	.rename =	jffs2_rename,
++	.rename2 =	jffs2_rename,
+ 	.get_acl =	jffs2_get_acl,
+ 	.set_acl =	jffs2_set_acl,
+ 	.setattr =	jffs2_setattr,
+@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di
+ 	return ret;
+ }
+ 
++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry)
++{
++	struct dentry *wh;
++	int err;
++
++	wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
++	if (!wh)
++		return -ENOMEM;
++
++	err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
++			  WHITEOUT_DEV);
++	if (err)
++		return err;
++
++	d_rehash(wh);
++	return 0;
++}
++
+ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
+-			 struct inode *new_dir_i, struct dentry *new_dentry)
++			 struct inode *new_dir_i, struct dentry *new_dentry,
++			 unsigned int flags)
+ {
+ 	int ret;
+ 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
+@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
++	if (flags & ~RENAME_WHITEOUT)
++		return -EINVAL;
++
+ 	/* The VFS will check for us and prevent trying to rename a
+ 	 * file over a directory and vice versa, but if it's a directory,
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o
+ 	if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
+ 		inc_nlink(new_dir_i);
+ 
+-	/* Unlink the original */
+-	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+-			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
++	if (flags & RENAME_WHITEOUT)
++		/* Replace with whiteout */
++		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else
++		/* Unlink the original */
++		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
++				      old_dentry->d_name.name,
++				      old_dentry->d_name.len, NULL, now);
+ 
+ 	/* We don't touch inode->i_nlink */
+ 
diff --git a/target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch
new file mode 100644
index 0000000000..be87c3507e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/111-jffs2-add-RENAME_EXCHANGE-support.patch
@@ -0,0 +1,58 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 25 Apr 2015 12:41:32 +0200
+Subject: [PATCH] jffs2: add RENAME_EXCHANGE support
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
+-	if (flags & ~RENAME_WHITEOUT)
++	if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE))
+ 		return -EINVAL;
+ 
+ 	/* The VFS will check for us and prevent trying to rename a
+@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+ 	 * needs to do that for itself.
+ 	 */
+-	if (new_dentry->d_inode) {
++	if (new_dentry->d_inode && !(flags & RENAME_EXCHANGE)) {
+ 		victim_f = JFFS2_INODE_INFO(new_dentry->d_inode);
+ 		if (S_ISDIR(new_dentry->d_inode->i_mode)) {
+ 			struct jffs2_full_dirent *fd;
+@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o
+ 	if (ret)
+ 		return ret;
+ 
+-	if (victim_f) {
++	if (victim_f && !(flags & RENAME_EXCHANGE)) {
+ 		/* There was a victim. Kill it off nicely */
+ 		if (S_ISDIR(new_dentry->d_inode->i_mode))
+ 			clear_nlink(new_dentry->d_inode);
+@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o
+ 	if (flags & RENAME_WHITEOUT)
+ 		/* Replace with whiteout */
+ 		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else if (flags & RENAME_EXCHANGE)
++		/* Replace the original */
++		ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
++				    new_dentry->d_inode->i_ino, type,
++				    old_dentry->d_name.name, old_dentry->d_name.len,
++				    now);
+ 	else
+ 		/* Unlink the original */
+ 		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+@@ -879,7 +885,7 @@ static int jffs2_rename (struct inode *o
+ 		return ret;
+ 	}
+ 
+-	if (S_ISDIR(old_dentry->d_inode->i_mode))
++	if (S_ISDIR(old_dentry->d_inode->i_mode) && !(flags & RENAME_EXCHANGE))
+ 		drop_nlink(old_dir_i);
+ 
+ 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
diff --git a/target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch
new file mode 100644
index 0000000000..909611403c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/120-bridge_allow_receiption_on_disabled_port.patch
@@ -0,0 +1,54 @@
+From: Stephen Hemminger <stephen@networkplumber.org>
+Subject: bridge: allow receiption on disabled port
+
+When an ethernet device is enslaved to a bridge, and the bridge STP
+detects loss of carrier (or operational state down), then normally
+packet receiption is blocked.
+
+This breaks control applications like WPA which maybe expecting to
+receive packets to negotiate to bring link up. The bridge needs to
+block forwarding packets from these disabled ports, but there is no
+hard requirement to not allow local packet delivery.
+
+Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -146,11 +146,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish
+ static int br_handle_local_finish(struct sk_buff *skb)
+ {
+ 	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
+-	u16 vid = 0;
++	if (p->state != BR_STATE_DISABLED) {
++		u16 vid = 0;
+ 
+-	/* check if vlan is allowed, to avoid spoofing */
+-	if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
+-		br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
++		/* check if vlan is allowed, to avoid spoofing */
++		if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
++			br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
++	}
+ 	return 0;	 /* process further */
+ }
+ 
+@@ -224,6 +226,18 @@ rx_handler_result_t br_handle_frame(stru
+ 
+ forward:
+ 	switch (p->state) {
++	case BR_STATE_DISABLED:
++		if (ether_addr_equal(p->br->dev->dev_addr, dest))
++			skb->pkt_type = PACKET_HOST;
++
++		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
++			br_handle_local_finish))
++			break;
++
++		BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
++		br_pass_frame_up(skb);
++		break;
++
+ 	case BR_STATE_FORWARDING:
+ 		rhook = rcu_dereference(br_should_route_hook);
+ 		if (rhook) {
diff --git a/target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch b/target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch
new file mode 100644
index 0000000000..c008aea41d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/132-mips_inline_dma_ops.patch
@@ -0,0 +1,688 @@
+From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 12 Aug 2013 12:50:22 +0200
+Subject: [PATCH] MIPS: partially inline dma ops
+
+Several DMA ops are no-op on many platforms, and the indirection through
+the mips_dma_map_ops function table is causing the compiler to emit
+unnecessary code.
+
+Inlining visibly improves network performance in my tests (on a 24Kc
+based system), and also slightly reduces code size of a few drivers.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/Kconfig                   |   4 +
+ arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++-
+ arch/mips/mm/dma-default.c          | 163 ++--------------
+ 3 files changed, 373 insertions(+), 154 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1450,6 +1450,7 @@ config CPU_CAVIUM_OCTEON
+ 	select CPU_SUPPORTS_HUGEPAGES
+ 	select USB_EHCI_BIG_ENDIAN_MMIO
+ 	select MIPS_L1_CACHE_SHIFT_7
++	select SYS_HAS_DMA_OPS
+ 	help
+ 	  The Cavium Octeon processor is a highly integrated chip containing
+ 	  many ethernet hardware widgets for networking tasks. The processor
+@@ -1705,6 +1706,9 @@ config MIPS_MALTA_PM
+ 	bool
+ 	default y
+ 
++config SYS_HAS_DMA_OPS
++	bool
++
+ #
+ # CPU may reorder R->R, R->W, W->R, W->W
+ # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+--- a/arch/mips/include/asm/dma-mapping.h
++++ b/arch/mips/include/asm/dma-mapping.h
+@@ -1,9 +1,16 @@
+ #ifndef _ASM_DMA_MAPPING_H
+ #define _ASM_DMA_MAPPING_H
+ 
++#include <linux/kmemcheck.h>
++#include <linux/bug.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-debug.h>
++#include <linux/dma-attrs.h>
++
+ #include <asm/scatterlist.h>
+ #include <asm/dma-coherence.h>
+ #include <asm/cache.h>
++#include <asm/cpu-type.h>
+ #include <asm-generic/dma-coherent.h>
+ 
+ #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
+@@ -12,12 +19,48 @@
+ 
+ extern struct dma_map_ops *mips_dma_map_ops;
+ 
++void __dma_sync(struct page *page, unsigned long offset, size_t size,
++		enum dma_data_direction direction);
++void *mips_dma_alloc_coherent(struct device *dev, size_t size,
++			      dma_addr_t *dma_handle, gfp_t gfp,
++			      struct dma_attrs *attrs);
++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++			    dma_addr_t dma_handle, struct dma_attrs *attrs);
++
+ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+ {
++#ifdef CONFIG_SYS_HAS_DMA_OPS
+ 	if (dev && dev->archdata.dma_ops)
+ 		return dev->archdata.dma_ops;
+ 	else
+ 		return mips_dma_map_ops;
++#else
++	return NULL;
++#endif
++}
++
++/*
++ * Warning on the terminology - Linux calls an uncached area coherent;
++ * MIPS terminology calls memory areas with hardware maintained coherency
++ * coherent.
++ */
++
++static inline int cpu_needs_post_dma_flush(struct device *dev)
++{
++#ifndef CONFIG_SYS_HAS_CPU_R10000
++	return 0;
++#endif
++	return !plat_device_is_coherent(dev) &&
++	       (boot_cpu_type() == CPU_R10000 ||
++		boot_cpu_type() == CPU_R12000 ||
++		boot_cpu_type() == CPU_BMIPS5000);
++}
++
++static inline struct page *dma_addr_to_page(struct device *dev,
++	dma_addr_t dma_addr)
++{
++	return pfn_to_page(
++		plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
+ }
+ 
+ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+@@ -30,12 +73,304 @@ static inline bool dma_capable(struct de
+ 
+ static inline void dma_mark_clean(void *addr, size_t size) {}
+ 
+-#include <asm-generic/dma-mapping-common.h>
++static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
++					      size_t size,
++					      enum dma_data_direction dir,
++					      struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	unsigned long offset = (unsigned long)ptr & ~PAGE_MASK;
++	struct page *page = virt_to_page(ptr);
++	dma_addr_t addr;
++
++	kmemcheck_mark_initialized(ptr, size);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		addr = ops->map_page(dev, page, offset, size, dir, attrs);
++	} else {
++		if (!plat_device_is_coherent(dev))
++			__dma_sync(page, offset, size, dir);
++
++		addr = plat_map_dma_mem_page(dev, page) + offset;
++	}
++	debug_dma_map_page(dev, page, offset, size, dir, addr, true);
++	return addr;
++}
++
++static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
++					  size_t size,
++					  enum dma_data_direction dir,
++					  struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->unmap_page(dev, addr, size, dir, attrs);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++
++		plat_unmap_dma_mem(dev, addr, size, dir);
++	}
++	debug_dma_unmap_page(dev, addr, size, dir, true);
++}
++
++static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
++				   int nents, enum dma_data_direction dir,
++				   struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	int i, ents;
++	struct scatterlist *s;
++
++	for_each_sg(sg, s, nents, i)
++		kmemcheck_mark_initialized(sg_virt(s), s->length);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ents = ops->map_sg(dev, sg, nents, dir, attrs);
++	} else {
++		for_each_sg(sg, s, nents, i) {
++			struct page *page = sg_page(s);
++
++			if (!plat_device_is_coherent(dev))
++				__dma_sync(page, s->offset, s->length, dir);
++#ifdef CONFIG_NEED_SG_DMA_LENGTH
++			s->dma_length = s->length;
++#endif
++			s->dma_address =
++				plat_map_dma_mem_page(dev, page) + s->offset;
++		}
++		ents = nents;
++	}
++	debug_dma_map_sg(dev, sg, nents, ents, dir);
++
++	return ents;
++}
++
++static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
++				      int nents, enum dma_data_direction dir,
++				      struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	debug_dma_unmap_sg(dev, sg, nents, dir);
++	if (ops) {
++		ops->unmap_sg(dev, sg, nents, dir, attrs);
++		return;
++	}
++
++	for_each_sg(sg, s, nents, i) {
++		if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++		plat_unmap_dma_mem(dev, s->dma_address, s->length, dir);
++	}
++}
++
++static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
++				      size_t offset, size_t size,
++				      enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	dma_addr_t addr;
++
++	kmemcheck_mark_initialized(page_address(page) + offset, size);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		addr = ops->map_page(dev, page, offset, size, dir, NULL);
++	} else {
++		if (!plat_device_is_coherent(dev))
++			__dma_sync(page, offset, size, dir);
++
++		addr = plat_map_dma_mem_page(dev, page) + offset;
++	}
++	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
++
++	return addr;
++}
++
++static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
++				  size_t size, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->unmap_page(dev, addr, size, dir, NULL);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++
++		plat_unmap_dma_mem(dev, addr, size, dir);
++	}
++	debug_dma_unmap_page(dev, addr, size, dir, false);
++}
++
++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
++					   size_t size,
++					   enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_cpu(dev, addr, size, dir);
++	else if (cpu_needs_post_dma_flush(dev))
++		__dma_sync(dma_addr_to_page(dev, addr),
++			   addr & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_for_cpu(dev, addr, size, dir);
++}
++
++static inline void dma_sync_single_for_device(struct device *dev,
++					      dma_addr_t addr, size_t size,
++					      enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_device(dev, addr, size, dir);
++	else if (!plat_device_is_coherent(dev))
++		__dma_sync(dma_addr_to_page(dev, addr),
++			   addr & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_for_device(dev, addr, size, dir);
++}
++
++static inline void dma_sync_single_range_for_cpu(struct device *dev,
++						 dma_addr_t addr,
++						 unsigned long offset,
++						 size_t size,
++						 enum dma_data_direction dir)
++{
++	const struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_cpu(dev, addr + offset, size, dir);
++	else if (cpu_needs_post_dma_flush(dev))
++		__dma_sync(dma_addr_to_page(dev, addr + offset),
++			   (addr + offset) & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
++}
++
++static inline void dma_sync_single_range_for_device(struct device *dev,
++						    dma_addr_t addr,
++						    unsigned long offset,
++						    size_t size,
++						    enum dma_data_direction dir)
++{
++	const struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_device(dev, addr + offset, size, dir);
++	else if (!plat_device_is_coherent(dev))
++		__dma_sync(dma_addr_to_page(dev, addr + offset),
++			   (addr + offset) & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
++}
++
++static inline void
++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
++		    int nelems, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_sg_for_cpu(dev, sg, nelems, dir);
++	else if (cpu_needs_post_dma_flush(dev)) {
++		for_each_sg(sg, s, nelems, i)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++	}
++	debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
++		       int nelems, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_sg_for_device(dev, sg, nelems, dir);
++	else if (!plat_device_is_coherent(dev)) {
++		for_each_sg(sg, s, nelems, i)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++	}
++	debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
++
++}
++
++#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
++#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
++#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
++#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
++
++extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
++			   void *cpu_addr, dma_addr_t dma_addr, size_t size);
++
++/**
++ * dma_mmap_attrs - map a coherent DMA allocation into user space
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @vma: vm_area_struct describing requested user mapping
++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
++ * @handle: device-view address returned from dma_alloc_attrs
++ * @size: size of memory originally requested in dma_alloc_attrs
++ * @attrs: attributes of mapping properties requested in dma_alloc_attrs
++ *
++ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs
++ * into user space.  The coherent DMA buffer must not be freed by the
++ * driver until the user space mapping has been released.
++ */
++static inline int
++dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
++	       dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	BUG_ON(!ops);
++	if (ops && ops->mmap)
++		return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
++	return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
++}
++
++#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
++
++int
++dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
++		       void *cpu_addr, dma_addr_t dma_addr, size_t size);
++
++static inline int
++dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
++		      dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	BUG_ON(!ops);
++	if (ops && ops->get_sgtable)
++		return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
++					attrs);
++	return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
++}
++
++#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
++
+ 
+ static inline int dma_supported(struct device *dev, u64 mask)
+ {
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+-	return ops->dma_supported(dev, mask);
++	if (ops)
++		return ops->dma_supported(dev, mask);
++	return plat_dma_supported(dev, mask);
+ }
+ 
+ static inline int dma_mapping_error(struct device *dev, u64 mask)
+@@ -43,7 +378,9 @@ static inline int dma_mapping_error(stru
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+ 
+ 	debug_dma_mapping_error(dev, mask);
+-	return ops->mapping_error(dev, mask);
++	if (ops)
++		return ops->mapping_error(dev, mask);
++	return 0;
+ }
+ 
+ static inline int
+@@ -54,7 +391,7 @@ dma_set_mask(struct device *dev, u64 mas
+ 	if(!dev->dma_mask || !dma_supported(dev, mask))
+ 		return -EIO;
+ 
+-	if (ops->set_dma_mask)
++	if (ops && ops->set_dma_mask)
+ 		return ops->set_dma_mask(dev, mask);
+ 
+ 	*dev->dma_mask = mask;
+@@ -74,7 +411,11 @@ static inline void *dma_alloc_attrs(stru
+ 	void *ret;
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+ 
+-	ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
++	if (ops)
++		ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
++	else
++		ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp,
++					      attrs);
+ 
+ 	debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
+ 
+@@ -89,7 +430,10 @@ static inline void dma_free_attrs(struct
+ {
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+ 
+-	ops->free(dev, size, vaddr, dma_handle, attrs);
++	if (ops)
++		ops->free(dev, size, vaddr, dma_handle, attrs);
++	else
++		mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs);
+ 
+ 	debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+ }
+--- a/arch/mips/mm/dma-default.c
++++ b/arch/mips/mm/dma-default.c
+@@ -26,7 +26,7 @@
+ 
+ #ifdef CONFIG_DMA_MAYBE_COHERENT
+ int coherentio = 0;	/* User defined DMA coherency from command line. */
+-EXPORT_SYMBOL_GPL(coherentio);
++EXPORT_SYMBOL(coherentio);
+ int hw_coherentio = 0;	/* Actual hardware supported DMA coherency setting. */
+ 
+ static int __init setcoherentio(char *str)
+@@ -46,30 +46,6 @@ static int __init setnocoherentio(char *
+ early_param("nocoherentio", setnocoherentio);
+ #endif
+ 
+-static inline struct page *dma_addr_to_page(struct device *dev,
+-	dma_addr_t dma_addr)
+-{
+-	return pfn_to_page(
+-		plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
+-}
+-
+-/*
+- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
+- * speculatively fill random cachelines with stale data at any time,
+- * requiring an extra flush post-DMA.
+- *
+- * Warning on the terminology - Linux calls an uncached area coherent;
+- * MIPS terminology calls memory areas with hardware maintained coherency
+- * coherent.
+- */
+-static inline int cpu_needs_post_dma_flush(struct device *dev)
+-{
+-	return !plat_device_is_coherent(dev) &&
+-	       (boot_cpu_type() == CPU_R10000 ||
+-		boot_cpu_type() == CPU_R12000 ||
+-		boot_cpu_type() == CPU_BMIPS5000);
+-}
+-
+ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
+ {
+ 	gfp_t dma_flag;
+@@ -125,8 +101,9 @@ void *dma_alloc_noncoherent(struct devic
+ }
+ EXPORT_SYMBOL(dma_alloc_noncoherent);
+ 
+-static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
+-	dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
++void *mips_dma_alloc_coherent(struct device *dev, size_t size,
++			      dma_addr_t *dma_handle, gfp_t gfp,
++			      struct dma_attrs *attrs)
+ {
+ 	void *ret;
+ 	struct page *page = NULL;
+@@ -157,6 +134,7 @@ static void *mips_dma_alloc_coherent(str
+ 
+ 	return ret;
+ }
++EXPORT_SYMBOL(mips_dma_alloc_coherent);
+ 
+ 
+ void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+@@ -167,8 +145,8 @@ void dma_free_noncoherent(struct device
+ }
+ EXPORT_SYMBOL(dma_free_noncoherent);
+ 
+-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+-	dma_addr_t dma_handle, struct dma_attrs *attrs)
++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++			    dma_addr_t dma_handle, struct dma_attrs *attrs)
+ {
+ 	unsigned long addr = (unsigned long) vaddr;
+ 	int order = get_order(size);
+@@ -188,6 +166,7 @@ static void mips_dma_free_coherent(struc
+ 	if (!dma_release_from_contiguous(dev, page, count))
+ 		__free_pages(page, get_order(size));
+ }
++EXPORT_SYMBOL(mips_dma_free_coherent);
+ 
+ static inline void __dma_sync_virtual(void *addr, size_t size,
+ 	enum dma_data_direction direction)
+@@ -216,8 +195,8 @@ static inline void __dma_sync_virtual(vo
+  * If highmem is not configured then the bulk of this loop gets
+  * optimized out.
+  */
+-static inline void __dma_sync(struct page *page,
+-	unsigned long offset, size_t size, enum dma_data_direction direction)
++void __dma_sync(struct page *page, unsigned long offset, size_t size,
++		enum dma_data_direction direction)
+ {
+ 	size_t left = size;
+ 
+@@ -246,108 +225,7 @@ static inline void __dma_sync(struct pag
+ 		left -= len;
+ 	} while (left);
+ }
+-
+-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+-	size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
+-{
+-	if (cpu_needs_post_dma_flush(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_addr),
+-			   dma_addr & ~PAGE_MASK, size, direction);
+-
+-	plat_unmap_dma_mem(dev, dma_addr, size, direction);
+-}
+-
+-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg,
+-	int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+-{
+-	int i;
+-
+-	for (i = 0; i < nents; i++, sg++) {
+-		if (!plat_device_is_coherent(dev))
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-#ifdef CONFIG_NEED_SG_DMA_LENGTH
+-		sg->dma_length = sg->length;
+-#endif
+-		sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) +
+-				  sg->offset;
+-	}
+-
+-	return nents;
+-}
+-
+-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
+-	unsigned long offset, size_t size, enum dma_data_direction direction,
+-	struct dma_attrs *attrs)
+-{
+-	if (!plat_device_is_coherent(dev))
+-		__dma_sync(page, offset, size, direction);
+-
+-	return plat_map_dma_mem_page(dev, page) + offset;
+-}
+-
+-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+-	int nhwentries, enum dma_data_direction direction,
+-	struct dma_attrs *attrs)
+-{
+-	int i;
+-
+-	for (i = 0; i < nhwentries; i++, sg++) {
+-		if (!plat_device_is_coherent(dev) &&
+-		    direction != DMA_TO_DEVICE)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-		plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction);
+-	}
+-}
+-
+-static void mips_dma_sync_single_for_cpu(struct device *dev,
+-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+-{
+-	if (cpu_needs_post_dma_flush(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_handle),
+-			   dma_handle & ~PAGE_MASK, size, direction);
+-}
+-
+-static void mips_dma_sync_single_for_device(struct device *dev,
+-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+-{
+-	if (!plat_device_is_coherent(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_handle),
+-			   dma_handle & ~PAGE_MASK, size, direction);
+-}
+-
+-static void mips_dma_sync_sg_for_cpu(struct device *dev,
+-	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
+-{
+-	int i;
+-
+-	if (cpu_needs_post_dma_flush(dev))
+-		for (i = 0; i < nelems; i++, sg++)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-}
+-
+-static void mips_dma_sync_sg_for_device(struct device *dev,
+-	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
+-{
+-	int i;
+-
+-	if (!plat_device_is_coherent(dev))
+-		for (i = 0; i < nelems; i++, sg++)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-}
+-
+-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+-{
+-	return 0;
+-}
+-
+-int mips_dma_supported(struct device *dev, u64 mask)
+-{
+-	return plat_dma_supported(dev, mask);
+-}
++EXPORT_SYMBOL(__dma_sync);
+ 
+ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ 			 enum dma_data_direction direction)
+@@ -360,23 +238,10 @@ void dma_cache_sync(struct device *dev,
+ 
+ EXPORT_SYMBOL(dma_cache_sync);
+ 
+-static struct dma_map_ops mips_default_dma_map_ops = {
+-	.alloc = mips_dma_alloc_coherent,
+-	.free = mips_dma_free_coherent,
+-	.map_page = mips_dma_map_page,
+-	.unmap_page = mips_dma_unmap_page,
+-	.map_sg = mips_dma_map_sg,
+-	.unmap_sg = mips_dma_unmap_sg,
+-	.sync_single_for_cpu = mips_dma_sync_single_for_cpu,
+-	.sync_single_for_device = mips_dma_sync_single_for_device,
+-	.sync_sg_for_cpu = mips_dma_sync_sg_for_cpu,
+-	.sync_sg_for_device = mips_dma_sync_sg_for_device,
+-	.mapping_error = mips_dma_mapping_error,
+-	.dma_supported = mips_dma_supported
+-};
+-
+-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops;
++#ifdef CONFIG_SYS_HAS_DMA_OPS
++struct dma_map_ops *mips_dma_map_ops = NULL;
+ EXPORT_SYMBOL(mips_dma_map_ops);
++#endif
+ 
+ #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+ 
diff --git a/target/linux/generic/patches-3.18/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch b/target/linux/generic/patches-3.18/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch
new file mode 100644
index 0000000000..ebbe1bbaee
--- /dev/null
+++ b/target/linux/generic/patches-3.18/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch
@@ -0,0 +1,53 @@
+From 71a0a72456b48de972d7ed613b06a22a3aa9057f Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Sat, 26 Sep 2015 13:41:43 +0800
+Subject: [PATCH] MIPS: UAPI: Ignore __arch_swab{16,32,64} when using MIPS16
+
+Some GCC versions (e.g. 4.8.3) can incorrectly inline a function with
+MIPS32 instructions into another function with MIPS16 code [1], causing
+the assembler to genereate incorrect binary code or fail right away
+complaining about unrecognized opcode.
+
+In the case of __arch_swab{16,32}, when inlined by the compiler with
+flags `-mips32r2 -mips16 -Os', the assembler can fail with the following
+error.
+
+    {standard input}:79: Error: unrecognized opcode `wsbh $2,$2'
+
+For performance concerns and to workaround the issue already existing in
+older compilers, just ignore these 2 functions when compiling with
+mips16 enabled.
+
+ [1] Inlining nomips16 function into mips16 function can result in
+     undefined builtins, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55777
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+Cc: Maciej W. Rozycki <macro@linux-mips.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/11241/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/include/uapi/asm/swab.h |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/include/uapi/asm/swab.h
++++ b/arch/mips/include/uapi/asm/swab.h
+@@ -13,8 +13,9 @@
+ 
+ #define __SWAB_64_THRU_32__
+ 
+-#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) ||		\
+-    defined(_MIPS_ARCH_LOONGSON3A)
++#if !defined(__mips16) &&					\
++	((defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) ||	\
++	 defined(_MIPS_ARCH_LOONGSON3A))
+ 
+ static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
+ {
+@@ -65,5 +66,5 @@ static inline __attribute_const__ __u64
+ }
+ #define __arch_swab64 __arch_swab64
+ #endif /* __mips64 */
+-#endif /* MIPS R2 or newer or Loongson 3A */
++#endif /* (not __mips16) and (MIPS R2 or newer or Loongson 3A) */
+ #endif /* _ASM_SWAB_H */
diff --git a/target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch b/target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
new file mode 100644
index 0000000000..bd34f9698a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
@@ -0,0 +1,175 @@
+From 173b0add0cff6558f950c0cb1eacfb729d482711 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 May 2015 18:48:38 +0200
+Subject: [PATCH 4/8] mtd: part: add generic parsing of linux,part-probe
+
+This moves the linux,part-probe device tree parsing code from
+physmap_of.c to mtdpart.c. Now all drivers can use this feature by just
+providing a reference to their device tree node in struct
+mtd_part_parser_data.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ Documentation/devicetree/bindings/mtd/nand.txt | 16 ++++++++++
+ drivers/mtd/maps/physmap_of.c                  | 40 +-----------------------
+ drivers/mtd/mtdpart.c                          | 43 ++++++++++++++++++++++++++
+ 3 files changed, 60 insertions(+), 39 deletions(-)
+
+--- a/Documentation/devicetree/bindings/mtd/nand.txt
++++ b/Documentation/devicetree/bindings/mtd/nand.txt
+@@ -12,6 +12,22 @@
+ - nand-ecc-step-size: integer representing the number of data bytes
+ 		      that are covered by a single ECC step.
+ 
++- linux,part-probe: list of name as strings of the partition parser
++		    which should be used to parse the partition table.
++		    They will be tried in the specified ordering and
++		    the next one will be used if the previous one
++		    failed.
++
++		    Example: linux,part-probe = "cmdlinepart", "ofpart";
++
++		    This is also the default value, which will be used
++		    if this attribute is not specified. It could be
++		    that the flash driver in use overwrote the default
++		    value and uses some other default.
++
++		    Possible values are: bcm47xxpart, afs, ar7part,
++		    ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart
++
+ The ECC strength and ECC step size properties define the correction capability
+ of a controller. Together, they say a controller can correct "{strength} bit
+ errors per {size} bytes".
+--- a/drivers/mtd/maps/physmap_of.c
++++ b/drivers/mtd/maps/physmap_of.c
+@@ -114,45 +114,9 @@ static struct mtd_info *obsolete_probe(s
+ static const char * const part_probe_types_def[] = {
+ 	"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
+ 
+-static const char * const *of_get_probes(struct device_node *dp)
+-{
+-	const char *cp;
+-	int cplen;
+-	unsigned int l;
+-	unsigned int count;
+-	const char **res;
+-
+-	cp = of_get_property(dp, "linux,part-probe", &cplen);
+-	if (cp == NULL)
+-		return part_probe_types_def;
+-
+-	count = 0;
+-	for (l = 0; l != cplen; l++)
+-		if (cp[l] == 0)
+-			count++;
+-
+-	res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
+-	count = 0;
+-	while (cplen > 0) {
+-		res[count] = cp;
+-		l = strlen(cp) + 1;
+-		cp += l;
+-		cplen -= l;
+-		count++;
+-	}
+-	return res;
+-}
+-
+-static void of_free_probes(const char * const *probes)
+-{
+-	if (probes != part_probe_types_def)
+-		kfree(probes);
+-}
+-
+ static struct of_device_id of_flash_match[];
+ static int of_flash_probe(struct platform_device *dev)
+ {
+-	const char * const *part_probe_types;
+ 	const struct of_device_id *match;
+ 	struct device_node *dp = dev->dev.of_node;
+ 	struct resource res;
+@@ -302,10 +266,8 @@ static int of_flash_probe(struct platfor
+ 		goto err_out;
+ 
+ 	ppdata.of_node = dp;
+-	part_probe_types = of_get_probes(dp);
+-	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
++	mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata,
+ 			NULL, 0);
+-	of_free_probes(part_probe_types);
+ 
+ 	kfree(mtd_list);
+ 
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -29,6 +29,7 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/of.h>
+ #include <linux/err.h>
+ 
+ #include "mtdcore.h"
+@@ -702,6 +703,40 @@ void deregister_mtd_parser(struct mtd_pa
+ EXPORT_SYMBOL_GPL(deregister_mtd_parser);
+ 
+ /*
++ * Parses the linux,part-probe device tree property.
++ * When a non null value is returned it has to be freed with kfree() by
++ * the caller.
++ */
++static const char * const *of_get_probes(struct device_node *dp)
++{
++	const char *cp;
++	int cplen;
++	unsigned int l;
++	unsigned int count;
++	const char **res;
++
++	cp = of_get_property(dp, "linux,part-probe", &cplen);
++	if (cp == NULL)
++		return NULL;
++
++	count = 0;
++	for (l = 0; l != cplen; l++)
++		if (cp[l] == 0)
++			count++;
++
++	res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
++	count = 0;
++	while (cplen > 0) {
++		res[count] = cp;
++		l = strlen(cp) + 1;
++		cp += l;
++		cplen -= l;
++		count++;
++	}
++	return res;
++}
++
++/*
+  * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
+  * are changing this array!
+  */
+@@ -737,6 +772,13 @@ int parse_mtd_partitions(struct mtd_info
+ {
+ 	struct mtd_part_parser *parser;
+ 	int ret = 0;
++	const char *const *types_of = NULL;
++
++	if (data && data->of_node) {
++		types_of = of_get_probes(data->of_node);
++		if (types_of != NULL)
++			types = types_of;
++	}
+ 
+ 	if (!types)
+ 		types = default_mtd_part_types;
+@@ -755,6 +797,7 @@ int parse_mtd_partitions(struct mtd_info
+ 			break;
+ 		}
+ 	}
++	kfree(types_of);
+ 	return ret;
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/141-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch b/target/linux/generic/patches-3.18/141-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
new file mode 100644
index 0000000000..761cff316d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/141-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
@@ -0,0 +1,33 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 5 Dec 2015 02:03:32 +0100
+Subject: [PATCH] mtd: bcm47xxpart: limit scanned flash area on BCM47XX (MIPS)
+ only
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We allowed using bcm47xxpart on BCM5301X arch with commit:
+9e3afa5f5c7 ("mtd: bcm47xxpart: allow enabling on ARCH_BCM_5301X")
+
+BCM5301X devices may contain some partitions in higher memory, e.g.
+Netgear R8000 has board_data at 0x2600000. To detect them we should
+use size limit on MIPS only.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -118,8 +118,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 	/* Parse block by block looking for magics */
+ 	for (offset = 0; offset <= master->size - blocksize;
+ 	     offset += blocksize) {
+-		/* Nothing more in higher memory */
+-		if (offset >= 0x2000000)
++		/* Nothing more in higher memory on BCM47XX (MIPS) */
++		if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
+ 			break;
+ 
+ 		if (curr_part >= BCM47XXPART_MAX_PARTS) {
diff --git a/target/linux/generic/patches-3.18/142-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch b/target/linux/generic/patches-3.18/142-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
new file mode 100644
index 0000000000..9073f795e2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/142-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
@@ -0,0 +1,92 @@
+From dfe4b4c732365fc1d83c2d2fd9cc18054ae850b7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 6 Dec 2015 11:24:05 +0100
+Subject: [PATCH] mtd: bcm47xxpart: don't fail because of bit-flips
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Bit-flip errors may occur on NAND flashes and are harmless. Handle them
+gracefully as read content is still reliable and can be parsed.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 38 ++++++++++++++++++++++----------------
+ 1 file changed, 22 insertions(+), 16 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_
+ {
+ 	uint32_t buf;
+ 	size_t bytes_read;
++	int err;
+ 
+-	if (mtd_read(master, offset, sizeof(buf), &bytes_read,
+-		     (uint8_t *)&buf) < 0) {
+-		pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			offset);
++	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
++			(uint8_t *)&buf);
++	if (err && !mtd_is_bitflip(err)) {
++		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			offset, err);
+ 		goto out_default;
+ 	}
+ 
+@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_
+ 	int trx_part = -1;
+ 	int last_trx_part = -1;
+ 	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
++	int err;
+ 
+ 	/*
+ 	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
+@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Read beginning of the block */
+-		if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+-			     &bytes_read, (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			       offset);
++		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
++			       &bytes_read, (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
+@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Read middle of the block */
+-		if (mtd_read(master, offset + 0x8000, 0x4,
+-			     &bytes_read, (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			       offset);
++		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
++			       (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
+@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		offset = master->size - possible_nvram_sizes[i];
+-		if (mtd_read(master, offset, 0x4, &bytes_read,
+-			     (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while reading at offset 0x%X!\n",
+-			       offset);
++		err = mtd_read(master, offset, 0x4, &bytes_read,
++			       (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
diff --git a/target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch b/target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch
new file mode 100644
index 0000000000..a17e39800c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch
@@ -0,0 +1,41 @@
+From 9612e686b235dc9e33c8dfb5e6d2ff2b2140fb9d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 16 Jun 2015 21:01:30 +0200
+Subject: [PATCH V2] usb: xhci: make USB_XHCI_PLATFORM selectable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Right now xhci-plat-hcd can be built when using one of platform specific
+drivers only (mvebu/rcar). There shouldn't be such limitation as some
+platforms may not require any quirks and may want to just use a generic
+driver ("generic-xhci" / "xhci-hcd").
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+Greg/Mathias: I'm not sure if it's more like USB subsystem stuff or xHCI
+Could you decide which one of you could pick that, please?
+
+V2: Drop useless "default n", thanks Sergei :)
+---
+ drivers/usb/host/Kconfig | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -32,7 +32,14 @@ config USB_XHCI_PCI
+        default y
+ 
+ config USB_XHCI_PLATFORM
+-	tristate
++	tristate "Generic xHCI driver for a platform device"
++	---help---
++	  Adds an xHCI host driver for a generic platform device, which
++	  provides a memory space and an irq.
++	  It is also a prerequisite for platform specific drivers that
++	  implement some extra quirks.
++
++	  If unsure, say N.
+ 
+ config USB_XHCI_MVEBU
+ 	tristate "xHCI support for Marvell Armada 375/38x"
diff --git a/target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch b/target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch
new file mode 100644
index 0000000000..0b03963f0a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch
@@ -0,0 +1,228 @@
+From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001
+From: Enrico Mioso <mrkiko.rs@gmail.com>
+Date: Wed, 8 Jul 2015 13:05:57 +0200
+Subject: [PATCH] cdc_ncm: Add support for moving NDP to end of NCM frame
+
+NCM specs are not actually mandating a specific position in the frame for
+the NDP (Network Datagram Pointer). However, some Huawei devices will
+ignore our aggregates if it is not placed after the datagrams it points
+to. Add support for doing just this, in a per-device configurable way.
+While at it, update NCM subdrivers, disabling this functionality in all of
+them, except in huawei_cdc_ncm where it is enabled instead.
+We aren't making any distinction between different Huawei NCM devices,
+based on what the vendor driver does. Standard NCM devices are left
+unaffected: if they are compliant, they should be always usable, still
+stay on the safe side.
+
+This change has been tested and working with a Huawei E3131 device (which
+works regardless of NDP position), a Huawei E3531 (also working both
+ways) and an E3372 (which mandates NDP to be after indexed datagrams).
+
+V1->V2:
+- corrected wrong NDP acronym definition
+- fixed possible NULL pointer dereference
+- patch cleanup
+V2->V3:
+- Properly account for the NDP size when writing new packets to SKB
+
+Signed-off-by: Enrico Mioso <mrkiko.rs@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/usb/cdc_mbim.c       |  2 +-
+ drivers/net/usb/cdc_ncm.c        | 61 ++++++++++++++++++++++++++++++++++++----
+ drivers/net/usb/huawei_cdc_ncm.c |  7 +++--
+ include/linux/usb/cdc_ncm.h      |  7 ++++-
+ 4 files changed, 67 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/usb/cdc_mbim.c
++++ b/drivers/net/usb/cdc_mbim.c
+@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *
+ 	if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
+ 		goto err;
+ 
+-	ret = cdc_ncm_bind_common(dev, intf, data_altsetting);
++	ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0);
+ 	if (ret)
+ 		goto err;
+ 
+--- a/drivers/net/usb/cdc_ncm.c
++++ b/drivers/net/usb/cdc_ncm.c
+@@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_
+ 		ctx->tx_curr_skb = NULL;
+ 	}
+ 
++	kfree(ctx->delayed_ndp16);
++
+ 	kfree(ctx);
+ }
+ 
+-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting)
++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
+ {
+ 	const struct usb_cdc_union_desc *union_desc = NULL;
+ 	struct cdc_ncm_ctx *ctx;
+@@ -859,6 +861,17 @@ advance:
+ 	/* finish setting up the device specific data */
+ 	cdc_ncm_setup(dev);
+ 
++	/* Device-specific flags */
++	ctx->drvflags = drvflags;
++
++	/* Allocate the delayed NDP if needed. */
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
++		ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
++		if (!ctx->delayed_ndp16)
++			goto error2;
++		dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
++	}
++
+ 	/* override ethtool_ops */
+ 	dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
+ 
+@@ -958,8 +971,11 @@ static int cdc_ncm_bind(struct usbnet *d
+ 	if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
+ 		return -ENODEV;
+ 
+-	/* The NCM data altsetting is fixed */
+-	ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM);
++	/* The NCM data altsetting is fixed, so we hard-coded it.
++	 * Additionally, generic NCM devices are assumed to accept arbitrarily
++	 * placed NDP.
++	 */
++	ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
+ 
+ 	/*
+ 	 * We should get an event when network connection is "connected" or
+@@ -990,6 +1006,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
+ 	struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
+ 	size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
+ 
++	/* If NDP should be moved to the end of the NCM package, we can't follow the
++	* NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
++	* the wNdpIndex field in the header is actually not consistent with reality. It will be later.
++	*/
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
++		if (ctx->delayed_ndp16->dwSignature == sign)
++			return ctx->delayed_ndp16;
++
+ 	/* follow the chain of NDPs, looking for a match */
+ 	while (ndpoffset) {
+ 		ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
+@@ -999,7 +1023,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
+ 	}
+ 
+ 	/* align new NDP */
+-	cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
++	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
++		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
+ 
+ 	/* verify that there is room for the NDP and the datagram (reserve) */
+ 	if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size)
+@@ -1012,7 +1037,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
+ 		nth16->wNdpIndex = cpu_to_le16(skb->len);
+ 
+ 	/* push a new empty NDP */
+-	ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
++	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
++		ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
++	else
++		ndp16 = ctx->delayed_ndp16;
++
+ 	ndp16->dwSignature = sign;
+ 	ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
+ 	return ndp16;
+@@ -1027,6 +1056,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 	struct sk_buff *skb_out;
+ 	u16 n = 0, index, ndplen;
+ 	u8 ready2send = 0;
++	u32 delayed_ndp_size;
++
++	/* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
++	 * accordingly. Otherwise, we should check here.
++	 */
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
++		delayed_ndp_size = ctx->max_ndp_size;
++	else
++		delayed_ndp_size = 0;
+ 
+ 	/* if there is a remaining skb, it gets priority */
+ 	if (skb != NULL) {
+@@ -1081,7 +1119,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 		cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max);
+ 
+ 		/* check if we had enough room left for both NDP and frame */
+-		if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) {
++		if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) {
+ 			if (n == 0) {
+ 				/* won't fit, MTU problem? */
+ 				dev_kfree_skb_any(skb);
+@@ -1154,6 +1192,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 		/* variables will be reset at next call */
+ 	}
+ 
++	/* If requested, put NDP at end of frame. */
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
++		nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
++		cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max);
++		nth16->wNdpIndex = cpu_to_le16(skb_out->len);
++		memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size);
++
++		/* Zero out delayed NDP - signature checking will naturally fail. */
++		ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
++	}
++
+ 	/* If collected data size is less or equal ctx->min_tx_pkt
+ 	 * bytes, we send buffers as it is. If we get more data, it
+ 	 * would be more efficient for USB HS mobile device with DMA
+--- a/drivers/net/usb/huawei_cdc_ncm.c
++++ b/drivers/net/usb/huawei_cdc_ncm.c
+@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct us
+ 	struct usb_driver *subdriver = ERR_PTR(-ENODEV);
+ 	int ret = -ENODEV;
+ 	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
++	int drvflags = 0;
+ 
+ 	/* altsetting should always be 1 for NCM devices - so we hard-coded
+-	 * it here
++	 * it here. Some huawei devices will need the NDP part of the NCM package to
++	 * be at the end of the frame.
+ 	 */
+-	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1);
++	drvflags |= CDC_NCM_FLAG_NDP_TO_END;
++	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
+ 	if (ret)
+ 		goto err;
+ 
+--- a/include/linux/usb/cdc_ncm.h
++++ b/include/linux/usb/cdc_ncm.h
+@@ -80,6 +80,9 @@
+ #define CDC_NCM_TIMER_INTERVAL_MIN		5UL
+ #define CDC_NCM_TIMER_INTERVAL_MAX		(U32_MAX / NSEC_PER_USEC)
+ 
++/* Driver flags */
++#define CDC_NCM_FLAG_NDP_TO_END	0x02		/* NDP is placed at end of frame */
++
+ #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
+ 				       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
+ #define cdc_ncm_data_intf_is_mbim(x)  ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
+@@ -103,9 +106,11 @@ struct cdc_ncm_ctx {
+ 
+ 	spinlock_t mtx;
+ 	atomic_t stop;
++	int drvflags;
+ 
+ 	u32 timer_interval;
+ 	u32 max_ndp_size;
++	struct usb_cdc_ncm_ndp16 *delayed_ndp16;
+ 
+ 	u32 tx_timer_pending;
+ 	u32 tx_curr_frame_num;
+@@ -133,7 +138,7 @@ struct cdc_ncm_ctx {
+ };
+ 
+ u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
+-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
+ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
+ struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
+ int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in);
diff --git a/target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch b/target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch
new file mode 100644
index 0000000000..5a3dc06c14
--- /dev/null
+++ b/target/linux/generic/patches-3.18/191-usb-ehci-orion-fix-probe-for-GENERIC_PHY.patch
@@ -0,0 +1,35 @@
+From a95f03e51471dbdbafd3391991d867ac2358ed02 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 23 Aug 2015 14:23:29 +0200
+Subject: [PATCH] usb: ehci-orion: fix probe for !GENERIC_PHY
+
+Commit d445913ce0ab7f ("usb: ehci-orion: add optional PHY support")
+added support for optional phys, but devm_phy_optional_get returns
+-ENOSYS if GENERIC_PHY is not enabled.
+
+This causes probe failures, even when there are no phys specified:
+
+[    1.443365] orion-ehci f1058000.usb: init f1058000.usb fail, -38
+[    1.449403] orion-ehci: probe of f1058000.usb failed with error -38
+
+Similar to dwc3, treat -ENOSYS as no phy.
+
+Fixes: d445913ce0ab7f ("usb: ehci-orion: add optional PHY support")
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ drivers/usb/host/ehci-orion.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/ehci-orion.c
++++ b/drivers/usb/host/ehci-orion.c
+@@ -226,7 +226,8 @@ static int ehci_orion_drv_probe(struct p
+ 	priv->phy = devm_phy_optional_get(&pdev->dev, "usb");
+ 	if (IS_ERR(priv->phy)) {
+ 		err = PTR_ERR(priv->phy);
+-		goto err_phy_get;
++		if (err != -ENOSYS)
++			goto err_phy_get;
+ 	} else {
+ 		err = phy_init(priv->phy);
+ 		if (err)
diff --git a/target/linux/generic/patches-3.18/192-USB-qcserial-Add-support-for-Quectel-EC20-Mini-PCIe-.patch b/target/linux/generic/patches-3.18/192-USB-qcserial-Add-support-for-Quectel-EC20-Mini-PCIe-.patch
new file mode 100644
index 0000000000..7c49a6f111
--- /dev/null
+++ b/target/linux/generic/patches-3.18/192-USB-qcserial-Add-support-for-Quectel-EC20-Mini-PCIe-.patch
@@ -0,0 +1,114 @@
+From 128524b9db3e4f4245226852bee771bd03db75be Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Tue, 3 Nov 2015 11:01:42 +0100
+Subject: [PATCH 1/2] USB: qcserial: Add support for Quectel EC20 Mini PCIe
+ module
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It seems like this device has same vendor and product IDs as G2K
+devices, but it has different number of interfaces(4 vs 5) and also
+different interface layout which makes it currently unusable:
+
+	usbcore: registered new interface driver qcserial
+	usbserial: USB Serial support registered for Qualcomm USB modem
+	usb 2-1.2: unknown number of interfaces: 5
+
+lsusb output:
+
+	Bus 002 Device 003: ID 05c6:9215 Qualcomm, Inc. Acer Gobi 2000 Wireless
+	Device Descriptor:
+	  bLength                18
+	  bDescriptorType         1
+	  bcdUSB               2.00
+	  bDeviceClass            0 (Defined at Interface level)
+	  bDeviceSubClass         0
+	  bDeviceProtocol         0
+	  bMaxPacketSize0        64
+	  idVendor           0x05c6 Qualcomm, Inc.
+	  idProduct          0x9215 Acer Gobi 2000 Wireless Modem
+	  bcdDevice            2.32
+	  iManufacturer           1 Quectel
+	  iProduct                2 Quectel LTE Module
+	  iSerial                 0
+	  bNumConfigurations      1
+	  Configuration Descriptor:
+	    bLength                 9
+	    bDescriptorType         2
+	    wTotalLength          209
+	    bNumInterfaces          5
+	    bConfigurationValue     1
+	    iConfiguration          0
+	    bmAttributes         0xa0
+	      (Bus Powered)
+	      Remote Wakeup
+	    MaxPower              500mA
+
+Signed-off-by: Petr Å tetiar <ynezz@true.cz>
+---
+ drivers/usb/serial/qcserial.c |   39 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+--- a/drivers/usb/serial/qcserial.c
++++ b/drivers/usb/serial/qcserial.c
+@@ -22,6 +22,8 @@
+ #define DRIVER_AUTHOR "Qualcomm Inc"
+ #define DRIVER_DESC "Qualcomm USB Serial driver"
+ 
++#define QUECTEL_EC20_IDPRODUCT 0x9215
++
+ /* standard device layouts supported by this driver */
+ enum qcserial_layouts {
+ 	QCSERIAL_G2K = 0,	/* Gobi 2000 */
+@@ -171,6 +173,38 @@ static const struct usb_device_id id_tab
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+ 
++static int handle_quectel_ec20(struct device *dev, int ifnum)
++{
++	int altsetting = 0;
++
++	/*
++	 * Quectel EC20 Mini PCIe LTE module layout:
++	 * 0: DM/DIAG (use libqcdm from ModemManager for communication)
++	 * 1: NMEA
++	 * 2: AT-capable modem port
++	 * 3: Modem interface
++	 * 4: NDIS
++	 */
++	switch (ifnum) {
++	case 0:
++		dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n");
++		break;
++	case 1:
++		dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n");
++		break;
++	case 2:
++	case 3:
++		dev_dbg(dev, "Quectel EC20 Modem port found\n");
++		break;
++	case 4:
++		/* Don't claim the QMI/net interface */
++		altsetting = -1;
++		break;
++	}
++
++	return altsetting;
++}
++
+ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
+ {
+ 	struct usb_host_interface *intf = serial->interface->cur_altsetting;
+@@ -239,6 +273,11 @@ static int qcprobe(struct usb_serial *se
+ 			altsetting = -1;
+ 		break;
+ 	case QCSERIAL_G2K:
++		if (nintf == 5 && id->idProduct == QUECTEL_EC20_IDPRODUCT) {
++			altsetting = handle_quectel_ec20(dev, ifnum);
++			goto done;
++		}
++
+ 		/*
+ 		 * Gobi 2K+ USB layout:
+ 		 * 0: QMI/net
diff --git a/target/linux/generic/patches-3.18/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch b/target/linux/generic/patches-3.18/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
new file mode 100644
index 0000000000..1b1afd5d31
--- /dev/null
+++ b/target/linux/generic/patches-3.18/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
@@ -0,0 +1,96 @@
+From fe29727caa7fe434fcb3166df2a62672bc516b54 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Wed, 4 Nov 2015 16:23:37 +0100
+Subject: [PATCH 2/2] USB: qmi_wwan: Add quirk for Quectel EC20 Mini PCIe
+ module
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This device has same vendor and product IDs as G2K devices, but it has
+different number of interfaces(4 vs 5) and also different interface
+layout where EC20 has QMI on interface 4 instead of 0.
+
+lsusb output:
+
+	Bus 002 Device 003: ID 05c6:9215 Qualcomm, Inc. Acer Gobi 2000
+	Device Descriptor:
+	  bLength                18
+	  bDescriptorType         1
+	  bcdUSB               2.00
+	  bDeviceClass            0 (Defined at Interface level)
+	  bDeviceSubClass         0
+	  bDeviceProtocol         0
+	  bMaxPacketSize0        64
+	  idVendor           0x05c6 Qualcomm, Inc.
+	  idProduct          0x9215 Acer Gobi 2000 Wireless Modem
+	  bcdDevice            2.32
+	  iManufacturer           1 Quectel
+	  iProduct                2 Quectel LTE Module
+	  iSerial                 0
+	  bNumConfigurations      1
+	  Configuration Descriptor:
+	    bLength                 9
+	    bDescriptorType         2
+	    wTotalLength          209
+	    bNumInterfaces          5
+	    bConfigurationValue     1
+	    iConfiguration          0
+	    bmAttributes         0xa0
+	      (Bus Powered)
+	      Remote Wakeup
+	    MaxPower              500mA
+
+Signed-off-by: Petr Å tetiar <ynezz@true.cz>
+---
+ drivers/net/usb/qmi_wwan.c |   21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+--- a/drivers/net/usb/qmi_wwan.c
++++ b/drivers/net/usb/qmi_wwan.c
+@@ -822,6 +822,7 @@ static const struct usb_device_id produc
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9245)},	/* Samsung Gobi 2000 Modem device (VL176) */
+ 	{QMI_GOBI_DEVICE(0x03f0, 0x251d)},	/* HP Gobi 2000 Modem device (VP412) */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9215)},	/* Acer Gobi 2000 Modem device (VP413) */
++	{QMI_FIXED_INTF(0x05c6, 0x9215, 4)},	/* Quectel EC20 Mini PCIe */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9265)},	/* Asus Gobi 2000 Modem device (VR305) */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9235)},	/* Top Global Gobi 2000 Modem device (VR306) */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9275)},	/* iRex Technologies Gobi 2000 Modem device (VR307) */
+@@ -853,10 +854,24 @@ static const struct usb_device_id produc
+ };
+ MODULE_DEVICE_TABLE(usb, products);
+ 
++static bool quectel_ec20_detected(struct usb_interface *intf)
++{
++	struct usb_device *dev = interface_to_usbdev(intf);
++
++	if (dev->actconfig &&
++	    le16_to_cpu(dev->descriptor.idVendor) == 0x05c6 &&
++	    le16_to_cpu(dev->descriptor.idProduct) == 0x9215 &&
++	    dev->actconfig->desc.bNumInterfaces == 5)
++		return true;
++
++	return false;
++}
++
+ static int qmi_wwan_probe(struct usb_interface *intf,
+ 			  const struct usb_device_id *prod)
+ {
+ 	struct usb_device_id *id = (struct usb_device_id *)prod;
++	struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
+ 
+ 	/* Workaround to enable dynamic IDs.  This disables usbnet
+ 	 * blacklisting functionality.  Which, if required, can be
+@@ -868,6 +883,12 @@ static int qmi_wwan_probe(struct usb_int
+ 		id->driver_info = (unsigned long)&qmi_wwan_info;
+ 	}
+ 
++	/* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
++	if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
++		dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
++		return -ENODEV;
++	}
++
+ 	return usbnet_probe(intf, id);
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/200-fix_localversion.patch b/target/linux/generic/patches-3.18/200-fix_localversion.patch
new file mode 100644
index 0000000000..70228bb5f4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/200-fix_localversion.patch
@@ -0,0 +1,11 @@
+--- a/scripts/setlocalversion
++++ b/scripts/setlocalversion
+@@ -165,7 +165,7 @@ else
+ 	# annotated or signed tagged state (as git describe only
+ 	# looks at signed or annotated tags - git tag -a/-s) and
+ 	# LOCALVERSION= is not specified
+-	if test "${LOCALVERSION+set}" != "set"; then
++	if test "${CONFIG_LOCALVERSION+set}" != "set"; then
+ 		scm=$(scm_version --short)
+ 		res="$res${scm:++}"
+ 	fi
diff --git a/target/linux/generic/patches-3.18/201-extra_optimization.patch b/target/linux/generic/patches-3.18/201-extra_optimization.patch
new file mode 100644
index 0000000000..7ec93a47f4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/201-extra_optimization.patch
@@ -0,0 +1,14 @@
+--- a/Makefile
++++ b/Makefile
+@@ -612,9 +612,9 @@ include $(srctree)/arch/$(SRCARCH)/Makef
+ KBUILD_CFLAGS	+= $(call cc-option,-fno-delete-null-pointer-checks,)
+ 
+ ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+-KBUILD_CFLAGS	+= -Os $(call cc-disable-warning,maybe-uninitialized,)
++KBUILD_CFLAGS	+= -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,)
+ else
+-KBUILD_CFLAGS	+= -O2
++KBUILD_CFLAGS	+= -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
+ endif
+ 
+ # Tell gcc to never replace conditional load with a non-conditional one
diff --git a/target/linux/generic/patches-3.18/202-reduce_module_size.patch b/target/linux/generic/patches-3.18/202-reduce_module_size.patch
new file mode 100644
index 0000000000..b98ea4e9d8
--- /dev/null
+++ b/target/linux/generic/patches-3.18/202-reduce_module_size.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -409,7 +409,7 @@ KBUILD_CFLAGS_KERNEL :=
+ KBUILD_AFLAGS   := -D__ASSEMBLY__
+ KBUILD_AFLAGS_MODULE  := -DMODULE
+ KBUILD_CFLAGS_MODULE  := -DMODULE
+-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
++KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
+ 
+ # Read KERNELRELEASE from include/config/kernel.release (if it exists)
+ KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
diff --git a/target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch b/target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch
new file mode 100644
index 0000000000..b9d82207a0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/203-kallsyms_uncompressed.patch
@@ -0,0 +1,108 @@
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -58,6 +58,7 @@ static struct addr_range percpu_range =
+ static struct sym_entry *table;
+ static unsigned int table_size, table_cnt;
+ static int all_symbols = 0;
++static int uncompressed = 0;
+ static int absolute_percpu = 0;
+ static char symbol_prefix_char = '\0';
+ static unsigned long long kernel_start_addr = 0;
+@@ -392,6 +393,9 @@ static void write_src(void)
+ 
+ 	free(markers);
+ 
++	if (uncompressed)
++		return;
++
+ 	output_label("kallsyms_token_table");
+ 	off = 0;
+ 	for (i = 0; i < 256; i++) {
+@@ -450,6 +454,9 @@ static void *find_token(unsigned char *s
+ {
+ 	int i;
+ 
++	if (uncompressed)
++		return NULL;
++
+ 	for (i = 0; i < len - 1; i++) {
+ 		if (str[i] == token[0] && str[i+1] == token[1])
+ 			return &str[i];
+@@ -522,6 +529,9 @@ static void optimize_result(void)
+ {
+ 	int i, best;
+ 
++	if (uncompressed)
++		return;
++
+ 	/* using the '\0' symbol last allows compress_symbols to use standard
+ 	 * fast string functions */
+ 	for (i = 255; i >= 0; i--) {
+@@ -692,7 +702,9 @@ int main(int argc, char **argv)
+ 			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+ 				const char *p = &argv[i][14];
+ 				kernel_start_addr = strtoull(p, NULL, 16);
+-			} else
++			} else if (strcmp(argv[i], "--uncompressed") == 0)
++				uncompressed = 1;
++			else
+ 				usage();
+ 		}
+ 	} else if (argc != 1)
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1338,6 +1338,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
+ 	  the unaligned access emulation.
+ 	  see arch/parisc/kernel/unaligned.c for reference
+ 
++config KALLSYMS_UNCOMPRESSED
++	bool "Keep kallsyms uncompressed"
++	depends on KALLSYMS
++	help
++		Normally kallsyms contains compressed symbols (using a token table),
++		reducing the uncompressed kernel image size. Keeping the symbol table
++		uncompressed significantly improves the size of this part in compressed
++		kernel images.
++
++		Say N unless you need compressed kernel images to be small.
++
+ config HAVE_PCSPKR_PLATFORM
+ 	bool
+ 
+--- a/scripts/link-vmlinux.sh
++++ b/scripts/link-vmlinux.sh
+@@ -90,6 +90,10 @@ kallsyms()
+ 		kallsymopt="${kallsymopt} --absolute-percpu"
+ 	fi
+ 
++	if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
++		kallsymopt="${kallsymopt} --uncompressed"
++	fi
++
+ 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
+ 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
+ 
+--- a/kernel/kallsyms.c
++++ b/kernel/kallsyms.c
+@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb
+ 	 * For every byte on the compressed symbol data, copy the table
+ 	 * entry for that byte.
+ 	 */
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	memcpy(result, data + 1, len - 1);
++	result += len - 1;
++	len = 0;
++#endif
+ 	while (len) {
+ 		tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
+ 		data++;
+@@ -141,6 +146,9 @@ tail:
+  */
+ static char kallsyms_get_symbol_type(unsigned int off)
+ {
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	return kallsyms_names[off + 1];
++#endif
+ 	/*
+ 	 * Get just the first code, look it up in the token table,
+ 	 * and return the first char from this token.
diff --git a/target/linux/generic/patches-3.18/204-module_strip.patch b/target/linux/generic/patches-3.18/204-module_strip.patch
new file mode 100644
index 0000000000..dab7799084
--- /dev/null
+++ b/target/linux/generic/patches-3.18/204-module_strip.patch
@@ -0,0 +1,194 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] build: add a hack for removing non-essential module info
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -84,9 +84,10 @@ void trim_init_extable(struct module *m)
+ 
+ /* Generic info of form tag = "info" */
+ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
+ 
+ /* For userspace: you can also call me... */
+-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
++#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias)
+ 
+ /* Soft module dependencies. See man modprobe.d for details.
+  * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
+@@ -127,12 +128,12 @@ void trim_init_extable(struct module *m)
+  * Author(s), use "Name <email>" or just "Name", for multiple
+  * authors use multiple MODULE_AUTHOR() statements/lines.
+  */
+-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
+ 
+ /* What your module does. */
+-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
+ 
+-#ifdef MODULE
++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
+ /* Creates an alias so file2alias.c can find device table. */
+ #define MODULE_DEVICE_TABLE(type, name)					\
+   extern const struct type##_device_id __mod_##type##__##name##_device_table \
+@@ -159,7 +160,9 @@ void trim_init_extable(struct module *m)
+  */
+ 
+ #if defined(MODULE) || !defined(CONFIG_SYSFS)
+-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
++#elif defined(CONFIG_MODULE_STRIPPED)
++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
+ #else
+ #define MODULE_VERSION(_version)					\
+ 	static struct module_version_attribute ___modver_attr = {	\
+@@ -181,7 +184,7 @@ void trim_init_extable(struct module *m)
+ /* Optional firmware file (or files) needed by the module
+  * format is simply firmware file name.  Multiple firmware
+  * files require multiple MODULE_FIRMWARE() specifiers */
+-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
+ 
+ /* Given an address, look for it in the exception tables */
+ const struct exception_table_entry *search_exception_tables(unsigned long add);
+--- a/include/linux/moduleparam.h
++++ b/include/linux/moduleparam.h
+@@ -16,6 +16,16 @@
+ /* Chosen so that structs with an unsigned long line up. */
+ #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
+ 
++/* This struct is here for syntactic coherency, it is not used */
++#define __MODULE_INFO_DISABLED(name)					  \
++  struct __UNIQUE_ID(name) {}
++
++#ifdef CONFIG_MODULE_STRIPPED
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
++#else
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
++#endif
++
+ #ifdef MODULE
+ #define __MODULE_INFO(tag, name, info)					  \
+ static const char __UNIQUE_ID(name)[]					  \
+@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[]
+   = __stringify(tag) "=" info
+ #else  /* !MODULE */
+ /* This struct is here for syntactic coherency, it is not used */
+-#define __MODULE_INFO(tag, name, info)					  \
+-  struct __UNIQUE_ID(name) {}
++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
+ #endif
+ #define __MODULE_PARM_TYPE(name, _type)					  \
+   __MODULE_INFO(parmtype, name##type, #name ":" _type)
+@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[]
+ /* One for each parameter, describing how to use it.  Some files do
+    multiple of these per line, so can't just use MODULE_INFO. */
+ #define MODULE_PARM_DESC(_parm, desc) \
+-	__MODULE_INFO(parm, _parm, #_parm ":" desc)
++	__MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
+ 
+ struct kernel_param;
+ 
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1987,6 +1987,13 @@ config MODULE_COMPRESS_XZ
+ 
+ endchoice
+ 
++config MODULE_STRIPPED
++	bool "Reduce module size"
++	depends on MODULES
++	help
++	  Remove module parameter descriptions, author info, version, aliases,
++	  device tables, etc.
++
+ endif # MODULES
+ 
+ config INIT_ALL_POSSIBLE
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2699,6 +2699,7 @@ static struct module *setup_load_info(st
+ 
+ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	const char *modmagic = get_modinfo(info, "vermagic");
+ 	int err;
+ 
+@@ -2724,6 +2725,7 @@ static int check_modinfo(struct module *
+ 		pr_warn("%s: module is from the staging directory, the quality "
+ 			"is unknown, you have been warned.\n", mod->name);
+ 	}
++#endif
+ 
+ 	/* Set up license info based on the info section */
+ 	set_license(mod, get_modinfo(info, "license"));
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -1726,7 +1726,9 @@ static void read_symbols(char *modname)
+ 		symname = remove_dot(info.strtab + sym->st_name);
+ 
+ 		handle_modversions(mod, &info, sym, symname);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		handle_moddevtable(mod, &info, sym, symname);
++#endif
+ 	}
+ 	if (!is_vmlinux(modname) ||
+ 	     (is_vmlinux(modname) && vmlinux_section_warnings))
+@@ -1870,7 +1872,9 @@ static void add_header(struct buffer *b,
+ 	buf_printf(b, "#include <linux/vermagic.h>\n");
+ 	buf_printf(b, "#include <linux/compiler.h>\n");
+ 	buf_printf(b, "\n");
++#ifndef CONFIG_MODULE_STRIPPED
+ 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
++#endif
+ 	buf_printf(b, "\n");
+ 	buf_printf(b, "__visible struct module __this_module\n");
+ 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
+@@ -1887,16 +1891,20 @@ static void add_header(struct buffer *b,
+ 
+ static void add_intree_flag(struct buffer *b, int is_intree)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (is_intree)
+ 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
++#endif
+ }
+ 
+ static void add_staging_flag(struct buffer *b, const char *name)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	static const char *staging_dir = "drivers/staging";
+ 
+ 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
+ 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
++#endif
+ }
+ 
+ /**
+@@ -1989,11 +1997,13 @@ static void add_depends(struct buffer *b
+ 
+ static void add_srcversion(struct buffer *b, struct module *mod)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (mod->srcversion[0]) {
+ 		buf_printf(b, "\n");
+ 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ 			   mod->srcversion);
+ 	}
++#endif
+ }
+ 
+ static void write_if_changed(struct buffer *b, const char *fname)
+@@ -2224,7 +2234,9 @@ int main(int argc, char **argv)
+ 		add_staging_flag(&buf, mod->name);
+ 		err |= add_versions(&buf, mod);
+ 		add_depends(&buf, mod, modules);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		add_moddevtable(&buf, mod);
++#endif
+ 		add_srcversion(&buf, mod);
+ 
+ 		sprintf(fname, "%s.mod.c", mod->name);
diff --git a/target/linux/generic/patches-3.18/205-backtrace_module_info.patch b/target/linux/generic/patches-3.18/205-backtrace_module_info.patch
new file mode 100644
index 0000000000..f83b21ebc8
--- /dev/null
+++ b/target/linux/generic/patches-3.18/205-backtrace_module_info.patch
@@ -0,0 +1,36 @@
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -614,8 +614,10 @@ char *symbol_string(char *buf, char *end
+ 		    struct printf_spec spec, const char *fmt)
+ {
+ 	unsigned long value;
+-#ifdef CONFIG_KALLSYMS
+ 	char sym[KSYM_SYMBOL_LEN];
++#ifndef CONFIG_KALLSYMS
++	struct module *mod;
++	int len;
+ #endif
+ 
+ 	if (fmt[1] == 'R')
+@@ -629,15 +631,15 @@ char *symbol_string(char *buf, char *end
+ 		sprint_symbol(sym, value);
+ 	else
+ 		sprint_symbol_no_offset(sym, value);
+-
+-	return string(buf, end, sym, spec);
+ #else
+-	spec.field_width = 2 * sizeof(void *);
+-	spec.flags |= SPECIAL | SMALL | ZEROPAD;
+-	spec.base = 16;
++	len = snprintf(sym, sizeof(sym), "0x%lx", value);
+ 
+-	return number(buf, end, value, spec);
++	mod = __module_address(value);
++	if (mod)
++		snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
++			 mod->name, mod->module_core, mod->core_size);
+ #endif
++	return string(buf, end, sym, spec);
+ }
+ 
+ static noinline_for_stack
diff --git a/target/linux/generic/patches-3.18/210-darwin_scripts_include.patch b/target/linux/generic/patches-3.18/210-darwin_scripts_include.patch
new file mode 100644
index 0000000000..dc554de247
--- /dev/null
+++ b/target/linux/generic/patches-3.18/210-darwin_scripts_include.patch
@@ -0,0 +1,3088 @@
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -22,6 +22,35 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
++#ifdef __APPLE__
++/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */
++void *memmem (const void *haystack, size_t haystack_len,
++                          const void *needle,  size_t needle_len)
++{
++  const char *begin;
++  const char *const last_possible
++    = (const char *) haystack + haystack_len - needle_len;
++
++  if (needle_len == 0)
++    /* The first occurrence of the empty string is deemed to occur at
++       the beginning of the string.  */
++    return (void *) haystack;
++
++  /* Sanity check, otherwise the loop might search through the whole
++     memory.  */
++  if (__builtin_expect (haystack_len < needle_len, 0))
++    return NULL;
++
++  for (begin = (const char *) haystack; begin <= last_possible; ++begin)
++    if (begin[0] == ((const char *) needle)[0] &&
++        !memcmp ((const void *) &begin[1],
++                 (const void *) ((const char *) needle + 1),
++                 needle_len - 1))
++      return (void *) begin;
++
++  return NULL;
++}
++#endif
+ 
+ #ifndef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+--- a/scripts/kconfig/Makefile
++++ b/scripts/kconfig/Makefile
+@@ -151,6 +151,9 @@ check-lxdialog  := $(srctree)/$(src)/lxd
+ # we really need to do so. (Do not call gcc as part of make mrproper)
+ HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+                     -DLOCALE
++ifeq ($(shell uname -s),Darwin)
++HOST_LOADLIBES  += -lncurses
++endif
+ 
+ # ===========================================================================
+ # Shared Makefile for the various kconfig executables:
+--- a/scripts/mod/mk_elfconfig.c
++++ b/scripts/mod/mk_elfconfig.c
+@@ -1,7 +1,11 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#ifndef __APPLE__
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ int
+ main(int argc, char **argv)
+--- a/scripts/mod/modpost.h
++++ b/scripts/mod/modpost.h
+@@ -7,7 +7,11 @@
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <unistd.h>
++#if !(defined(__APPLE__) || defined(__CYGWIN__))
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ #include "elfconfig.h"
+ 
+--- /dev/null
++++ b/scripts/mod/elf.h
+@@ -0,0 +1,3007 @@
++/* This file defines standard ELF types, structures, and macros.
++   Copyright (C) 1995-2012 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef _ELF_H
++#define	_ELF_H 1
++
++/* Standard ELF types.  */
++
++#include <stdint.h>
++
++/* Type for a 16-bit quantity.  */
++typedef uint16_t Elf32_Half;
++typedef uint16_t Elf64_Half;
++
++/* Types for signed and unsigned 32-bit quantities.  */
++typedef uint32_t Elf32_Word;
++typedef	int32_t  Elf32_Sword;
++typedef uint32_t Elf64_Word;
++typedef	int32_t  Elf64_Sword;
++
++/* Types for signed and unsigned 64-bit quantities.  */
++typedef uint64_t Elf32_Xword;
++typedef	int64_t  Elf32_Sxword;
++typedef uint64_t Elf64_Xword;
++typedef	int64_t  Elf64_Sxword;
++
++/* Type of addresses.  */
++typedef uint32_t Elf32_Addr;
++typedef uint64_t Elf64_Addr;
++
++/* Type of file offsets.  */
++typedef uint32_t Elf32_Off;
++typedef uint64_t Elf64_Off;
++
++/* Type for section indices, which are 16-bit quantities.  */
++typedef uint16_t Elf32_Section;
++typedef uint16_t Elf64_Section;
++
++/* Type for version symbol information.  */
++typedef Elf32_Half Elf32_Versym;
++typedef Elf64_Half Elf64_Versym;
++
++
++/* The ELF file header.  This appears at the start of every ELF file.  */
++
++#define EI_NIDENT (16)
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf32_Half	e_type;			/* Object file type */
++  Elf32_Half	e_machine;		/* Architecture */
++  Elf32_Word	e_version;		/* Object file version */
++  Elf32_Addr	e_entry;		/* Entry point virtual address */
++  Elf32_Off	e_phoff;		/* Program header table file offset */
++  Elf32_Off	e_shoff;		/* Section header table file offset */
++  Elf32_Word	e_flags;		/* Processor-specific flags */
++  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf32_Half	e_phentsize;		/* Program header table entry size */
++  Elf32_Half	e_phnum;		/* Program header table entry count */
++  Elf32_Half	e_shentsize;		/* Section header table entry size */
++  Elf32_Half	e_shnum;		/* Section header table entry count */
++  Elf32_Half	e_shstrndx;		/* Section header string table index */
++} Elf32_Ehdr;
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf64_Half	e_type;			/* Object file type */
++  Elf64_Half	e_machine;		/* Architecture */
++  Elf64_Word	e_version;		/* Object file version */
++  Elf64_Addr	e_entry;		/* Entry point virtual address */
++  Elf64_Off	e_phoff;		/* Program header table file offset */
++  Elf64_Off	e_shoff;		/* Section header table file offset */
++  Elf64_Word	e_flags;		/* Processor-specific flags */
++  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf64_Half	e_phentsize;		/* Program header table entry size */
++  Elf64_Half	e_phnum;		/* Program header table entry count */
++  Elf64_Half	e_shentsize;		/* Section header table entry size */
++  Elf64_Half	e_shnum;		/* Section header table entry count */
++  Elf64_Half	e_shstrndx;		/* Section header string table index */
++} Elf64_Ehdr;
++
++/* Fields in the e_ident array.  The EI_* macros are indices into the
++   array.  The macros under each EI_* macro are the values the byte
++   may have.  */
++
++#define EI_MAG0		0		/* File identification byte 0 index */
++#define ELFMAG0		0x7f		/* Magic number byte 0 */
++
++#define EI_MAG1		1		/* File identification byte 1 index */
++#define ELFMAG1		'E'		/* Magic number byte 1 */
++
++#define EI_MAG2		2		/* File identification byte 2 index */
++#define ELFMAG2		'L'		/* Magic number byte 2 */
++
++#define EI_MAG3		3		/* File identification byte 3 index */
++#define ELFMAG3		'F'		/* Magic number byte 3 */
++
++/* Conglomeration of the identification bytes, for easy testing as a word.  */
++#define	ELFMAG		"\177ELF"
++#define	SELFMAG		4
++
++#define EI_CLASS	4		/* File class byte index */
++#define ELFCLASSNONE	0		/* Invalid class */
++#define ELFCLASS32	1		/* 32-bit objects */
++#define ELFCLASS64	2		/* 64-bit objects */
++#define ELFCLASSNUM	3
++
++#define EI_DATA		5		/* Data encoding byte index */
++#define ELFDATANONE	0		/* Invalid data encoding */
++#define ELFDATA2LSB	1		/* 2's complement, little endian */
++#define ELFDATA2MSB	2		/* 2's complement, big endian */
++#define ELFDATANUM	3
++
++#define EI_VERSION	6		/* File version byte index */
++					/* Value must be EV_CURRENT */
++
++#define EI_OSABI	7		/* OS ABI identification */
++#define ELFOSABI_NONE		0	/* UNIX System V ABI */
++#define ELFOSABI_SYSV		0	/* Alias.  */
++#define ELFOSABI_HPUX		1	/* HP-UX */
++#define ELFOSABI_NETBSD		2	/* NetBSD.  */
++#define ELFOSABI_GNU		3	/* Object uses GNU ELF extensions.  */
++#define ELFOSABI_LINUX		ELFOSABI_GNU /* Compatibility alias.  */
++#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
++#define ELFOSABI_AIX		7	/* IBM AIX.  */
++#define ELFOSABI_IRIX		8	/* SGI Irix.  */
++#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
++#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
++#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
++#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
++#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
++#define ELFOSABI_ARM		97	/* ARM */
++#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
++
++#define EI_ABIVERSION	8		/* ABI version */
++
++#define EI_PAD		9		/* Byte index of padding bytes */
++
++/* Legal values for e_type (object file type).  */
++
++#define ET_NONE		0		/* No file type */
++#define ET_REL		1		/* Relocatable file */
++#define ET_EXEC		2		/* Executable file */
++#define ET_DYN		3		/* Shared object file */
++#define ET_CORE		4		/* Core file */
++#define	ET_NUM		5		/* Number of defined types */
++#define ET_LOOS		0xfe00		/* OS-specific range start */
++#define ET_HIOS		0xfeff		/* OS-specific range end */
++#define ET_LOPROC	0xff00		/* Processor-specific range start */
++#define ET_HIPROC	0xffff		/* Processor-specific range end */
++
++/* Legal values for e_machine (architecture).  */
++
++#define EM_NONE		 0		/* No machine */
++#define EM_M32		 1		/* AT&T WE 32100 */
++#define EM_SPARC	 2		/* SUN SPARC */
++#define EM_386		 3		/* Intel 80386 */
++#define EM_68K		 4		/* Motorola m68k family */
++#define EM_88K		 5		/* Motorola m88k family */
++#define EM_860		 7		/* Intel 80860 */
++#define EM_MIPS		 8		/* MIPS R3000 big-endian */
++#define EM_S370		 9		/* IBM System/370 */
++#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
++
++#define EM_PARISC	15		/* HPPA */
++#define EM_VPP500	17		/* Fujitsu VPP500 */
++#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
++#define EM_960		19		/* Intel 80960 */
++#define EM_PPC		20		/* PowerPC */
++#define EM_PPC64	21		/* PowerPC 64-bit */
++#define EM_S390		22		/* IBM S390 */
++
++#define EM_V800		36		/* NEC V800 series */
++#define EM_FR20		37		/* Fujitsu FR20 */
++#define EM_RH32		38		/* TRW RH-32 */
++#define EM_RCE		39		/* Motorola RCE */
++#define EM_ARM		40		/* ARM */
++#define EM_FAKE_ALPHA	41		/* Digital Alpha */
++#define EM_SH		42		/* Hitachi SH */
++#define EM_SPARCV9	43		/* SPARC v9 64-bit */
++#define EM_TRICORE	44		/* Siemens Tricore */
++#define EM_ARC		45		/* Argonaut RISC Core */
++#define EM_H8_300	46		/* Hitachi H8/300 */
++#define EM_H8_300H	47		/* Hitachi H8/300H */
++#define EM_H8S		48		/* Hitachi H8S */
++#define EM_H8_500	49		/* Hitachi H8/500 */
++#define EM_IA_64	50		/* Intel Merced */
++#define EM_MIPS_X	51		/* Stanford MIPS-X */
++#define EM_COLDFIRE	52		/* Motorola Coldfire */
++#define EM_68HC12	53		/* Motorola M68HC12 */
++#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
++#define EM_PCP		55		/* Siemens PCP */
++#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
++#define EM_NDR1		57		/* Denso NDR1 microprocessor */
++#define EM_STARCORE	58		/* Motorola Start*Core processor */
++#define EM_ME16		59		/* Toyota ME16 processor */
++#define EM_ST100	60		/* STMicroelectronic ST100 processor */
++#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
++#define EM_X86_64	62		/* AMD x86-64 architecture */
++#define EM_PDSP		63		/* Sony DSP Processor */
++
++#define EM_FX66		66		/* Siemens FX66 microcontroller */
++#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
++#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
++#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
++#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
++#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
++#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
++#define EM_SVX		73		/* Silicon Graphics SVx */
++#define EM_ST19		74		/* STMicroelectronics ST19 8 bit mc */
++#define EM_VAX		75		/* Digital VAX */
++#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
++#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
++#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
++#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
++#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
++#define EM_HUANY	81		/* Harvard University machine-independent object files */
++#define EM_PRISM	82		/* SiTera Prism */
++#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
++#define EM_FR30		84		/* Fujitsu FR30 */
++#define EM_D10V		85		/* Mitsubishi D10V */
++#define EM_D30V		86		/* Mitsubishi D30V */
++#define EM_V850		87		/* NEC v850 */
++#define EM_M32R		88		/* Mitsubishi M32R */
++#define EM_MN10300	89		/* Matsushita MN10300 */
++#define EM_MN10200	90		/* Matsushita MN10200 */
++#define EM_PJ		91		/* picoJava */
++#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
++#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
++#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
++#define EM_TILEPRO	188		/* Tilera TILEPro */
++#define EM_TILEGX	191		/* Tilera TILE-Gx */
++#define EM_NUM		192
++
++/* If it is necessary to assign new unofficial EM_* values, please
++   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
++   chances of collision with official or non-GNU unofficial values.  */
++
++#define EM_ALPHA	0x9026
++
++/* Legal values for e_version (version).  */
++
++#define EV_NONE		0		/* Invalid ELF version */
++#define EV_CURRENT	1		/* Current version */
++#define EV_NUM		2
++
++/* Section header.  */
++
++typedef struct
++{
++  Elf32_Word	sh_name;		/* Section name (string tbl index) */
++  Elf32_Word	sh_type;		/* Section type */
++  Elf32_Word	sh_flags;		/* Section flags */
++  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf32_Off	sh_offset;		/* Section file offset */
++  Elf32_Word	sh_size;		/* Section size in bytes */
++  Elf32_Word	sh_link;		/* Link to another section */
++  Elf32_Word	sh_info;		/* Additional section information */
++  Elf32_Word	sh_addralign;		/* Section alignment */
++  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
++} Elf32_Shdr;
++
++typedef struct
++{
++  Elf64_Word	sh_name;		/* Section name (string tbl index) */
++  Elf64_Word	sh_type;		/* Section type */
++  Elf64_Xword	sh_flags;		/* Section flags */
++  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf64_Off	sh_offset;		/* Section file offset */
++  Elf64_Xword	sh_size;		/* Section size in bytes */
++  Elf64_Word	sh_link;		/* Link to another section */
++  Elf64_Word	sh_info;		/* Additional section information */
++  Elf64_Xword	sh_addralign;		/* Section alignment */
++  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
++} Elf64_Shdr;
++
++/* Special section indices.  */
++
++#define SHN_UNDEF	0		/* Undefined section */
++#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
++#define SHN_LOPROC	0xff00		/* Start of processor-specific */
++#define SHN_BEFORE	0xff00		/* Order section before all others
++					   (Solaris).  */
++#define SHN_AFTER	0xff01		/* Order section after all others
++					   (Solaris).  */
++#define SHN_HIPROC	0xff1f		/* End of processor-specific */
++#define SHN_LOOS	0xff20		/* Start of OS-specific */
++#define SHN_HIOS	0xff3f		/* End of OS-specific */
++#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
++#define SHN_COMMON	0xfff2		/* Associated symbol is common */
++#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
++#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
++
++/* Legal values for sh_type (section type).  */
++
++#define SHT_NULL	  0		/* Section header table entry unused */
++#define SHT_PROGBITS	  1		/* Program data */
++#define SHT_SYMTAB	  2		/* Symbol table */
++#define SHT_STRTAB	  3		/* String table */
++#define SHT_RELA	  4		/* Relocation entries with addends */
++#define SHT_HASH	  5		/* Symbol hash table */
++#define SHT_DYNAMIC	  6		/* Dynamic linking information */
++#define SHT_NOTE	  7		/* Notes */
++#define SHT_NOBITS	  8		/* Program space with no data (bss) */
++#define SHT_REL		  9		/* Relocation entries, no addends */
++#define SHT_SHLIB	  10		/* Reserved */
++#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
++#define SHT_INIT_ARRAY	  14		/* Array of constructors */
++#define SHT_FINI_ARRAY	  15		/* Array of destructors */
++#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
++#define SHT_GROUP	  17		/* Section group */
++#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
++#define	SHT_NUM		  19		/* Number of defined types.  */
++#define SHT_LOOS	  0x60000000	/* Start OS-specific.  */
++#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes.  */
++#define SHT_GNU_HASH	  0x6ffffff6	/* GNU-style hash table.  */
++#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
++#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
++#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
++#define SHT_SUNW_move	  0x6ffffffa
++#define SHT_SUNW_COMDAT   0x6ffffffb
++#define SHT_SUNW_syminfo  0x6ffffffc
++#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
++#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
++#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
++#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
++#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
++#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
++#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
++#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
++#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
++
++/* Legal values for sh_flags (section flags).  */
++
++#define SHF_WRITE	     (1 << 0)	/* Writable */
++#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
++#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
++#define SHF_MERGE	     (1 << 4)	/* Might be merged */
++#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
++#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
++#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
++#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
++					   required */
++#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
++#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
++#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
++#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
++#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
++					   (Solaris).  */
++#define SHF_EXCLUDE	     (1 << 31)	/* Section is excluded unless
++					   referenced or allocated (Solaris).*/
++
++/* Section group handling.  */
++#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
++
++/* Symbol table entry.  */
++
++typedef struct
++{
++  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
++  Elf32_Addr	st_value;		/* Symbol value */
++  Elf32_Word	st_size;		/* Symbol size */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char	st_other;		/* Symbol visibility */
++  Elf32_Section	st_shndx;		/* Section index */
++} Elf32_Sym;
++
++typedef struct
++{
++  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char st_other;		/* Symbol visibility */
++  Elf64_Section	st_shndx;		/* Section index */
++  Elf64_Addr	st_value;		/* Symbol value */
++  Elf64_Xword	st_size;		/* Symbol size */
++} Elf64_Sym;
++
++/* The syminfo section if available contains additional information about
++   every dynamic symbol.  */
++
++typedef struct
++{
++  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf32_Half si_flags;			/* Per symbol flags */
++} Elf32_Syminfo;
++
++typedef struct
++{
++  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf64_Half si_flags;			/* Per symbol flags */
++} Elf64_Syminfo;
++
++/* Possible values for si_boundto.  */
++#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
++#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
++#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
++
++/* Possible bitmasks for si_flags.  */
++#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
++#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
++#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
++#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
++					   loaded */
++/* Syminfo version values.  */
++#define SYMINFO_NONE		0
++#define SYMINFO_CURRENT		1
++#define SYMINFO_NUM		2
++
++
++/* How to extract and insert information held in the st_info field.  */
++
++#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
++#define ELF32_ST_TYPE(val)		((val) & 0xf)
++#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
++
++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
++#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
++#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
++#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
++
++/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
++
++#define STB_LOCAL	0		/* Local symbol */
++#define STB_GLOBAL	1		/* Global symbol */
++#define STB_WEAK	2		/* Weak symbol */
++#define	STB_NUM		3		/* Number of defined types.  */
++#define STB_LOOS	10		/* Start of OS-specific */
++#define STB_GNU_UNIQUE	10		/* Unique symbol.  */
++#define STB_HIOS	12		/* End of OS-specific */
++#define STB_LOPROC	13		/* Start of processor-specific */
++#define STB_HIPROC	15		/* End of processor-specific */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_NOTYPE	0		/* Symbol type is unspecified */
++#define STT_OBJECT	1		/* Symbol is a data object */
++#define STT_FUNC	2		/* Symbol is a code object */
++#define STT_SECTION	3		/* Symbol associated with a section */
++#define STT_FILE	4		/* Symbol's name is file name */
++#define STT_COMMON	5		/* Symbol is a common data object */
++#define STT_TLS		6		/* Symbol is thread-local data object*/
++#define	STT_NUM		7		/* Number of defined types.  */
++#define STT_LOOS	10		/* Start of OS-specific */
++#define STT_GNU_IFUNC	10		/* Symbol is indirect code object */
++#define STT_HIOS	12		/* End of OS-specific */
++#define STT_LOPROC	13		/* Start of processor-specific */
++#define STT_HIPROC	15		/* End of processor-specific */
++
++
++/* Symbol table indices are found in the hash buckets and chain table
++   of a symbol hash table section.  This special index value indicates
++   the end of a chain, meaning no further symbols are found in that bucket.  */
++
++#define STN_UNDEF	0		/* End of a chain.  */
++
++
++/* How to extract and insert information held in the st_other field.  */
++
++#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
++
++/* For ELF64 the definitions are the same.  */
++#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
++
++/* Symbol visibility specification encoded in the st_other field.  */
++#define STV_DEFAULT	0		/* Default symbol visibility rules */
++#define STV_INTERNAL	1		/* Processor specific hidden class */
++#define STV_HIDDEN	2		/* Sym unavailable in other modules */
++#define STV_PROTECTED	3		/* Not preemptible, not exported */
++
++
++/* Relocation table entry without addend (in section of type SHT_REL).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++} Elf32_Rel;
++
++/* I have seen two different definitions of the Elf64_Rel and
++   Elf64_Rela structures, so we'll leave them out until Novell (or
++   whoever) gets their act together.  */
++/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++} Elf64_Rel;
++
++/* Relocation table entry with addend (in section of type SHT_RELA).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++  Elf32_Sword	r_addend;		/* Addend */
++} Elf32_Rela;
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++  Elf64_Sxword	r_addend;		/* Addend */
++} Elf64_Rela;
++
++/* How to extract and insert information held in the r_info field.  */
++
++#define ELF32_R_SYM(val)		((val) >> 8)
++#define ELF32_R_TYPE(val)		((val) & 0xff)
++#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
++
++#define ELF64_R_SYM(i)			((i) >> 32)
++#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
++#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
++
++/* Program segment header.  */
++
++typedef struct
++{
++  Elf32_Word	p_type;			/* Segment type */
++  Elf32_Off	p_offset;		/* Segment file offset */
++  Elf32_Addr	p_vaddr;		/* Segment virtual address */
++  Elf32_Addr	p_paddr;		/* Segment physical address */
++  Elf32_Word	p_filesz;		/* Segment size in file */
++  Elf32_Word	p_memsz;		/* Segment size in memory */
++  Elf32_Word	p_flags;		/* Segment flags */
++  Elf32_Word	p_align;		/* Segment alignment */
++} Elf32_Phdr;
++
++typedef struct
++{
++  Elf64_Word	p_type;			/* Segment type */
++  Elf64_Word	p_flags;		/* Segment flags */
++  Elf64_Off	p_offset;		/* Segment file offset */
++  Elf64_Addr	p_vaddr;		/* Segment virtual address */
++  Elf64_Addr	p_paddr;		/* Segment physical address */
++  Elf64_Xword	p_filesz;		/* Segment size in file */
++  Elf64_Xword	p_memsz;		/* Segment size in memory */
++  Elf64_Xword	p_align;		/* Segment alignment */
++} Elf64_Phdr;
++
++/* Special value for e_phnum.  This indicates that the real number of
++   program headers is too large to fit into e_phnum.  Instead the real
++   value is in the field sh_info of section 0.  */
++
++#define PN_XNUM		0xffff
++
++/* Legal values for p_type (segment type).  */
++
++#define	PT_NULL		0		/* Program header table entry unused */
++#define PT_LOAD		1		/* Loadable program segment */
++#define PT_DYNAMIC	2		/* Dynamic linking information */
++#define PT_INTERP	3		/* Program interpreter */
++#define PT_NOTE		4		/* Auxiliary information */
++#define PT_SHLIB	5		/* Reserved */
++#define PT_PHDR		6		/* Entry for header table itself */
++#define PT_TLS		7		/* Thread-local storage segment */
++#define	PT_NUM		8		/* Number of defined types */
++#define PT_LOOS		0x60000000	/* Start of OS-specific */
++#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
++#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
++#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
++#define PT_LOSUNW	0x6ffffffa
++#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
++#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
++#define PT_HISUNW	0x6fffffff
++#define PT_HIOS		0x6fffffff	/* End of OS-specific */
++#define PT_LOPROC	0x70000000	/* Start of processor-specific */
++#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
++
++/* Legal values for p_flags (segment flags).  */
++
++#define PF_X		(1 << 0)	/* Segment is executable */
++#define PF_W		(1 << 1)	/* Segment is writable */
++#define PF_R		(1 << 2)	/* Segment is readable */
++#define PF_MASKOS	0x0ff00000	/* OS-specific */
++#define PF_MASKPROC	0xf0000000	/* Processor-specific */
++
++/* Legal values for note segment descriptor types for core files. */
++
++#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
++#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
++#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
++#define NT_PRXREG	4		/* Contains copy of prxregset struct */
++#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
++#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
++#define NT_AUXV		6		/* Contains copy of auxv array */
++#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
++#define NT_ASRS		8		/* Contains copy of asrset struct */
++#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
++#define NT_PSINFO	13		/* Contains copy of psinfo struct */
++#define NT_PRCRED	14		/* Contains copy of prcred struct */
++#define NT_UTSNAME	15		/* Contains copy of utsname struct */
++#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
++#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
++#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct */
++#define NT_PRXFPREG	0x46e62b7f	/* Contains copy of user_fxsr_struct */
++#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
++#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
++#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
++#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
++#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
++#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
++
++/* Legal values for the note segment descriptor types for object files.  */
++
++#define NT_VERSION	1		/* Contains a version string.  */
++
++
++/* Dynamic section entry.  */
++
++typedef struct
++{
++  Elf32_Sword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf32_Word d_val;			/* Integer value */
++      Elf32_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf32_Dyn;
++
++typedef struct
++{
++  Elf64_Sxword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf64_Xword d_val;		/* Integer value */
++      Elf64_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf64_Dyn;
++
++/* Legal values for d_tag (dynamic entry type).  */
++
++#define DT_NULL		0		/* Marks end of dynamic section */
++#define DT_NEEDED	1		/* Name of needed library */
++#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
++#define DT_PLTGOT	3		/* Processor defined value */
++#define DT_HASH		4		/* Address of symbol hash table */
++#define DT_STRTAB	5		/* Address of string table */
++#define DT_SYMTAB	6		/* Address of symbol table */
++#define DT_RELA		7		/* Address of Rela relocs */
++#define DT_RELASZ	8		/* Total size of Rela relocs */
++#define DT_RELAENT	9		/* Size of one Rela reloc */
++#define DT_STRSZ	10		/* Size of string table */
++#define DT_SYMENT	11		/* Size of one symbol table entry */
++#define DT_INIT		12		/* Address of init function */
++#define DT_FINI		13		/* Address of termination function */
++#define DT_SONAME	14		/* Name of shared object */
++#define DT_RPATH	15		/* Library search path (deprecated) */
++#define DT_SYMBOLIC	16		/* Start symbol search here */
++#define DT_REL		17		/* Address of Rel relocs */
++#define DT_RELSZ	18		/* Total size of Rel relocs */
++#define DT_RELENT	19		/* Size of one Rel reloc */
++#define DT_PLTREL	20		/* Type of reloc in PLT */
++#define DT_DEBUG	21		/* For debugging; unspecified */
++#define DT_TEXTREL	22		/* Reloc might modify .text */
++#define DT_JMPREL	23		/* Address of PLT relocs */
++#define	DT_BIND_NOW	24		/* Process relocations of object */
++#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
++#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
++#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
++#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
++#define DT_RUNPATH	29		/* Library search path */
++#define DT_FLAGS	30		/* Flags for the object being loaded */
++#define DT_ENCODING	32		/* Start of encoded range */
++#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
++#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
++#define	DT_NUM		34		/* Number used */
++#define DT_LOOS		0x6000000d	/* Start of OS-specific */
++#define DT_HIOS		0x6ffff000	/* End of OS-specific */
++#define DT_LOPROC	0x70000000	/* Start of processor-specific */
++#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
++#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
++
++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
++   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
++   approach.  */
++#define DT_VALRNGLO	0x6ffffd00
++#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
++#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
++#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
++#define DT_CHECKSUM	0x6ffffdf8
++#define DT_PLTPADSZ	0x6ffffdf9
++#define DT_MOVEENT	0x6ffffdfa
++#define DT_MOVESZ	0x6ffffdfb
++#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
++#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
++					   the following DT_* entry.  */
++#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
++#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
++#define DT_VALRNGHI	0x6ffffdff
++#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
++#define DT_VALNUM 12
++
++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
++   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
++
++   If any adjustment is made to the ELF object after it has been
++   built these entries will need to be adjusted.  */
++#define DT_ADDRRNGLO	0x6ffffe00
++#define DT_GNU_HASH	0x6ffffef5	/* GNU-style hash table.  */
++#define DT_TLSDESC_PLT	0x6ffffef6
++#define DT_TLSDESC_GOT	0x6ffffef7
++#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
++#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
++#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
++#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
++#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
++#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
++#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
++#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
++#define DT_ADDRRNGHI	0x6ffffeff
++#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
++#define DT_ADDRNUM 11
++
++/* The versioning entry types.  The next are defined as part of the
++   GNU extension.  */
++#define DT_VERSYM	0x6ffffff0
++
++#define DT_RELACOUNT	0x6ffffff9
++#define DT_RELCOUNT	0x6ffffffa
++
++/* These were chosen by Sun.  */
++#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
++#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
++					   table */
++#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
++#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
++					   versions */
++#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
++#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
++#define DT_VERSIONTAGNUM 16
++
++/* Sun added these machine-independent extensions in the "processor-specific"
++   range.  Be compatible.  */
++#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
++#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
++#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
++#define DT_EXTRANUM	3
++
++/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
++#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
++#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
++#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
++#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
++#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
++
++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
++   entry in the dynamic section.  */
++#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
++#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
++#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
++#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
++#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
++#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
++#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
++#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
++#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
++#define DF_1_TRANS	0x00000200
++#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
++#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
++#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
++#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
++#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
++#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
++#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
++
++/* Flags for the feature selection in DT_FEATURE_1.  */
++#define DTF_1_PARINIT	0x00000001
++#define DTF_1_CONFEXP	0x00000002
++
++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
++#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
++#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
++					   generally available.  */
++
++/* Version definition sections.  */
++
++typedef struct
++{
++  Elf32_Half	vd_version;		/* Version revision */
++  Elf32_Half	vd_flags;		/* Version information */
++  Elf32_Half	vd_ndx;			/* Version Index */
++  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vd_hash;		/* Version name hash value */
++  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf32_Verdef;
++
++typedef struct
++{
++  Elf64_Half	vd_version;		/* Version revision */
++  Elf64_Half	vd_flags;		/* Version information */
++  Elf64_Half	vd_ndx;			/* Version Index */
++  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vd_hash;		/* Version name hash value */
++  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf64_Verdef;
++
++
++/* Legal values for vd_version (version revision).  */
++#define VER_DEF_NONE	0		/* No version */
++#define VER_DEF_CURRENT	1		/* Current version */
++#define VER_DEF_NUM	2		/* Given version number */
++
++/* Legal values for vd_flags (version information flags).  */
++#define VER_FLG_BASE	0x1		/* Version definition of file itself */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++/* Versym symbol index values.  */
++#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
++#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
++#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
++#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
++
++/* Auxialiary version information.  */
++
++typedef struct
++{
++  Elf32_Word	vda_name;		/* Version or dependency names */
++  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf32_Verdaux;
++
++typedef struct
++{
++  Elf64_Word	vda_name;		/* Version or dependency names */
++  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf64_Verdaux;
++
++
++/* Version dependency section.  */
++
++typedef struct
++{
++  Elf32_Half	vn_version;		/* Version of structure */
++  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf32_Verneed;
++
++typedef struct
++{
++  Elf64_Half	vn_version;		/* Version of structure */
++  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf64_Verneed;
++
++
++/* Legal values for vn_version (version revision).  */
++#define VER_NEED_NONE	 0		/* No version */
++#define VER_NEED_CURRENT 1		/* Current version */
++#define VER_NEED_NUM	 2		/* Given version number */
++
++/* Auxiliary needed version information.  */
++
++typedef struct
++{
++  Elf32_Word	vna_hash;		/* Hash value of dependency name */
++  Elf32_Half	vna_flags;		/* Dependency specific information */
++  Elf32_Half	vna_other;		/* Unused */
++  Elf32_Word	vna_name;		/* Dependency name string offset */
++  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf32_Vernaux;
++
++typedef struct
++{
++  Elf64_Word	vna_hash;		/* Hash value of dependency name */
++  Elf64_Half	vna_flags;		/* Dependency specific information */
++  Elf64_Half	vna_other;		/* Unused */
++  Elf64_Word	vna_name;		/* Dependency name string offset */
++  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf64_Vernaux;
++
++
++/* Legal values for vna_flags.  */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++
++/* Auxiliary vector.  */
++
++/* This vector is normally only used by the program interpreter.  The
++   usual definition in an ABI supplement uses the name auxv_t.  The
++   vector is not usually defined in a standard <elf.h> file, but it
++   can't hurt.  We rename it to avoid conflicts.  The sizes of these
++   types are an arrangement between the exec server and the program
++   interpreter, so we don't fully specify them here.  */
++
++typedef struct
++{
++  uint32_t a_type;		/* Entry type */
++  union
++    {
++      uint32_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf32_auxv_t;
++
++typedef struct
++{
++  uint64_t a_type;		/* Entry type */
++  union
++    {
++      uint64_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf64_auxv_t;
++
++/* Legal values for a_type (entry type).  */
++
++#define AT_NULL		0		/* End of vector */
++#define AT_IGNORE	1		/* Entry should be ignored */
++#define AT_EXECFD	2		/* File descriptor of program */
++#define AT_PHDR		3		/* Program headers for program */
++#define AT_PHENT	4		/* Size of program header entry */
++#define AT_PHNUM	5		/* Number of program headers */
++#define AT_PAGESZ	6		/* System page size */
++#define AT_BASE		7		/* Base address of interpreter */
++#define AT_FLAGS	8		/* Flags */
++#define AT_ENTRY	9		/* Entry point of program */
++#define AT_NOTELF	10		/* Program is not ELF */
++#define AT_UID		11		/* Real uid */
++#define AT_EUID		12		/* Effective uid */
++#define AT_GID		13		/* Real gid */
++#define AT_EGID		14		/* Effective gid */
++#define AT_CLKTCK	17		/* Frequency of times() */
++
++/* Some more special a_type values describing the hardware.  */
++#define AT_PLATFORM	15		/* String identifying platform.  */
++#define AT_HWCAP	16		/* Machine dependent hints about
++					   processor capabilities.  */
++
++/* This entry gives some information about the FPU initialization
++   performed by the kernel.  */
++#define AT_FPUCW	18		/* Used FPU control word.  */
++
++/* Cache block sizes.  */
++#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
++#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
++#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
++
++/* A special ignored value for PPC, used by the kernel to control the
++   interpretation of the AUXV. Must be > 16.  */
++#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
++
++#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
++
++#define AT_BASE_PLATFORM 24		/* String identifying real platforms.*/
++
++#define AT_RANDOM	25		/* Address of 16 random bytes.  */
++
++#define AT_EXECFN	31		/* Filename of executable.  */
++
++/* Pointer to the global system page used for system calls and other
++   nice things.  */
++#define AT_SYSINFO	32
++#define AT_SYSINFO_EHDR	33
++
++/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
++   log2 of line size; mask those to get cache size.  */
++#define AT_L1I_CACHESHAPE	34
++#define AT_L1D_CACHESHAPE	35
++#define AT_L2_CACHESHAPE	36
++#define AT_L3_CACHESHAPE	37
++
++/* Note section contents.  Each entry in the note section begins with
++   a header of a fixed form.  */
++
++typedef struct
++{
++  Elf32_Word n_namesz;			/* Length of the note's name.  */
++  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf32_Word n_type;			/* Type of the note.  */
++} Elf32_Nhdr;
++
++typedef struct
++{
++  Elf64_Word n_namesz;			/* Length of the note's name.  */
++  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf64_Word n_type;			/* Type of the note.  */
++} Elf64_Nhdr;
++
++/* Known names of notes.  */
++
++/* Solaris entries in the note section have this name.  */
++#define ELF_NOTE_SOLARIS	"SUNW Solaris"
++
++/* Note entries for GNU systems have this name.  */
++#define ELF_NOTE_GNU		"GNU"
++
++
++/* Defined types of notes for Solaris.  */
++
++/* Value of descriptor (one word) is desired pagesize for the binary.  */
++#define ELF_NOTE_PAGESIZE_HINT	1
++
++
++/* Defined note types for GNU systems.  */
++
++/* ABI information.  The descriptor consists of words:
++   word 0: OS descriptor
++   word 1: major version of the ABI
++   word 2: minor version of the ABI
++   word 3: subminor version of the ABI
++*/
++#define NT_GNU_ABI_TAG	1
++#define ELF_NOTE_ABI	NT_GNU_ABI_TAG /* Old name.  */
++
++/* Known OSes.  These values can appear in word 0 of an
++   NT_GNU_ABI_TAG note section entry.  */
++#define ELF_NOTE_OS_LINUX	0
++#define ELF_NOTE_OS_GNU		1
++#define ELF_NOTE_OS_SOLARIS2	2
++#define ELF_NOTE_OS_FREEBSD	3
++
++/* Synthetic hwcap information.  The descriptor begins with two words:
++   word 0: number of entries
++   word 1: bitmask of enabled entries
++   Then follow variable-length entries, one byte followed by a
++   '\0'-terminated hwcap name string.  The byte gives the bit
++   number to test if enabled, (1U << bit) & bitmask.  */
++#define NT_GNU_HWCAP	2
++
++/* Build ID bits as generated by ld --build-id.
++   The descriptor consists of any nonzero number of bytes.  */
++#define NT_GNU_BUILD_ID	3
++
++/* Version note generated by GNU gold containing a version string.  */
++#define NT_GNU_GOLD_VERSION	4
++
++
++/* Move records.  */
++typedef struct
++{
++  Elf32_Xword m_value;		/* Symbol value.  */
++  Elf32_Word m_info;		/* Size and index.  */
++  Elf32_Word m_poffset;		/* Symbol offset.  */
++  Elf32_Half m_repeat;		/* Repeat count.  */
++  Elf32_Half m_stride;		/* Stride info.  */
++} Elf32_Move;
++
++typedef struct
++{
++  Elf64_Xword m_value;		/* Symbol value.  */
++  Elf64_Xword m_info;		/* Size and index.  */
++  Elf64_Xword m_poffset;	/* Symbol offset.  */
++  Elf64_Half m_repeat;		/* Repeat count.  */
++  Elf64_Half m_stride;		/* Stride info.  */
++} Elf64_Move;
++
++/* Macro to construct move records.  */
++#define ELF32_M_SYM(info)	((info) >> 8)
++#define ELF32_M_SIZE(info)	((unsigned char) (info))
++#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
++
++#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
++#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
++#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
++
++
++/* Motorola 68k specific definitions.  */
++
++/* Values for Elf32_Ehdr.e_flags.  */
++#define EF_CPU32	0x00810000
++
++/* m68k relocs.  */
++
++#define R_68K_NONE	0		/* No reloc */
++#define R_68K_32	1		/* Direct 32 bit  */
++#define R_68K_16	2		/* Direct 16 bit  */
++#define R_68K_8		3		/* Direct 8 bit  */
++#define R_68K_PC32	4		/* PC relative 32 bit */
++#define R_68K_PC16	5		/* PC relative 16 bit */
++#define R_68K_PC8	6		/* PC relative 8 bit */
++#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
++#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
++#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
++#define R_68K_GOT32O	10		/* 32 bit GOT offset */
++#define R_68K_GOT16O	11		/* 16 bit GOT offset */
++#define R_68K_GOT8O	12		/* 8 bit GOT offset */
++#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
++#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
++#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
++#define R_68K_PLT32O	16		/* 32 bit PLT offset */
++#define R_68K_PLT16O	17		/* 16 bit PLT offset */
++#define R_68K_PLT8O	18		/* 8 bit PLT offset */
++#define R_68K_COPY	19		/* Copy symbol at runtime */
++#define R_68K_GLOB_DAT	20		/* Create GOT entry */
++#define R_68K_JMP_SLOT	21		/* Create PLT entry */
++#define R_68K_RELATIVE	22		/* Adjust by program base */
++#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
++#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
++#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
++#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
++#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
++#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
++#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
++#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
++#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
++#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
++#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
++#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
++#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
++#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
++#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
++/* Keep this the last entry.  */
++#define R_68K_NUM	43
++
++/* Intel 80386 specific definitions.  */
++
++/* i386 relocs.  */
++
++#define R_386_NONE	   0		/* No reloc */
++#define R_386_32	   1		/* Direct 32 bit  */
++#define R_386_PC32	   2		/* PC relative 32 bit */
++#define R_386_GOT32	   3		/* 32 bit GOT entry */
++#define R_386_PLT32	   4		/* 32 bit PLT address */
++#define R_386_COPY	   5		/* Copy symbol at runtime */
++#define R_386_GLOB_DAT	   6		/* Create GOT entry */
++#define R_386_JMP_SLOT	   7		/* Create PLT entry */
++#define R_386_RELATIVE	   8		/* Adjust by program base */
++#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
++#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
++#define R_386_32PLT	   11
++#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
++#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
++					   block offset */
++#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
++					   offset */
++#define R_386_TLS_LE	   17		/* Offset relative to static TLS
++					   block */
++#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
++					   general dynamic thread local data */
++#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
++					   local dynamic thread local data
++					   in LE code */
++#define R_386_16	   20
++#define R_386_PC16	   21
++#define R_386_8		   22
++#define R_386_PC8	   23
++#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
++					   thread local data */
++#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
++#define R_386_TLS_GD_CALL  26		/* Relocation for call to
++					   __tls_get_addr() */
++#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
++#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
++					   thread local data in LE code */
++#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
++#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
++					   __tls_get_addr() in LDM code */
++#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
++#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
++#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
++					   block offset */
++#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
++					   TLS block */
++#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
++#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
++#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
++/* 38? */
++#define R_386_TLS_GOTDESC  39		/* GOT offset for TLS descriptor.  */
++#define R_386_TLS_DESC_CALL 40		/* Marker of call through TLS
++					   descriptor for
++					   relaxation.  */
++#define R_386_TLS_DESC     41		/* TLS descriptor containing
++					   pointer to code and to
++					   argument, returning the TLS
++					   offset for the symbol.  */
++#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
++/* Keep this the last entry.  */
++#define R_386_NUM	   43
++
++/* SUN SPARC specific definitions.  */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
++
++/* Values for Elf64_Ehdr.e_flags.  */
++
++#define EF_SPARCV9_MM		3
++#define EF_SPARCV9_TSO		0
++#define EF_SPARCV9_PSO		1
++#define EF_SPARCV9_RMO		2
++#define EF_SPARC_LEDATA		0x800000 /* little endian data */
++#define EF_SPARC_EXT_MASK	0xFFFF00
++#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
++#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
++#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
++#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
++
++/* SPARC relocs.  */
++
++#define R_SPARC_NONE		0	/* No reloc */
++#define R_SPARC_8		1	/* Direct 8 bit */
++#define R_SPARC_16		2	/* Direct 16 bit */
++#define R_SPARC_32		3	/* Direct 32 bit */
++#define R_SPARC_DISP8		4	/* PC relative 8 bit */
++#define R_SPARC_DISP16		5	/* PC relative 16 bit */
++#define R_SPARC_DISP32		6	/* PC relative 32 bit */
++#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
++#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
++#define R_SPARC_HI22		9	/* High 22 bit */
++#define R_SPARC_22		10	/* Direct 22 bit */
++#define R_SPARC_13		11	/* Direct 13 bit */
++#define R_SPARC_LO10		12	/* Truncated 10 bit */
++#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
++#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
++#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
++#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
++#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
++#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
++#define R_SPARC_COPY		19	/* Copy symbol at runtime */
++#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
++#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
++#define R_SPARC_RELATIVE	22	/* Adjust by program base */
++#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
++
++/* Additional Sparc64 relocs.  */
++
++#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
++#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
++#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
++#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
++#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
++#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
++#define R_SPARC_10		30	/* Direct 10 bit */
++#define R_SPARC_11		31	/* Direct 11 bit */
++#define R_SPARC_64		32	/* Direct 64 bit */
++#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
++#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
++#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
++#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
++#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
++#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
++#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
++#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
++#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
++#define R_SPARC_GLOB_JMP	42	/* was part of v9 ABI but was removed */
++#define R_SPARC_7		43	/* Direct 7 bit */
++#define R_SPARC_5		44	/* Direct 5 bit */
++#define R_SPARC_6		45	/* Direct 6 bit */
++#define R_SPARC_DISP64		46	/* PC relative 64 bit */
++#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
++#define R_SPARC_HIX22		48	/* High 22 bit complemented */
++#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
++#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
++#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
++#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
++#define R_SPARC_REGISTER	53	/* Global register usage */
++#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
++#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
++#define R_SPARC_TLS_GD_HI22	56
++#define R_SPARC_TLS_GD_LO10	57
++#define R_SPARC_TLS_GD_ADD	58
++#define R_SPARC_TLS_GD_CALL	59
++#define R_SPARC_TLS_LDM_HI22	60
++#define R_SPARC_TLS_LDM_LO10	61
++#define R_SPARC_TLS_LDM_ADD	62
++#define R_SPARC_TLS_LDM_CALL	63
++#define R_SPARC_TLS_LDO_HIX22	64
++#define R_SPARC_TLS_LDO_LOX10	65
++#define R_SPARC_TLS_LDO_ADD	66
++#define R_SPARC_TLS_IE_HI22	67
++#define R_SPARC_TLS_IE_LO10	68
++#define R_SPARC_TLS_IE_LD	69
++#define R_SPARC_TLS_IE_LDX	70
++#define R_SPARC_TLS_IE_ADD	71
++#define R_SPARC_TLS_LE_HIX22	72
++#define R_SPARC_TLS_LE_LOX10	73
++#define R_SPARC_TLS_DTPMOD32	74
++#define R_SPARC_TLS_DTPMOD64	75
++#define R_SPARC_TLS_DTPOFF32	76
++#define R_SPARC_TLS_DTPOFF64	77
++#define R_SPARC_TLS_TPOFF32	78
++#define R_SPARC_TLS_TPOFF64	79
++#define R_SPARC_GOTDATA_HIX22	80
++#define R_SPARC_GOTDATA_LOX10	81
++#define R_SPARC_GOTDATA_OP_HIX22	82
++#define R_SPARC_GOTDATA_OP_LOX10	83
++#define R_SPARC_GOTDATA_OP	84
++#define R_SPARC_H34		85
++#define R_SPARC_SIZE32		86
++#define R_SPARC_SIZE64		87
++#define R_SPARC_WDISP10		88
++#define R_SPARC_JMP_IREL	248
++#define R_SPARC_IRELATIVE	249
++#define R_SPARC_GNU_VTINHERIT	250
++#define R_SPARC_GNU_VTENTRY	251
++#define R_SPARC_REV32		252
++/* Keep this the last entry.  */
++#define R_SPARC_NUM		253
++
++/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
++
++#define DT_SPARC_REGISTER 0x70000001
++#define DT_SPARC_NUM	2
++
++/* MIPS R3000 specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
++#define EF_MIPS_PIC	    2		/* Contains PIC code */
++#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
++#define EF_MIPS_XGOT	    8
++#define EF_MIPS_64BIT_WHIRL 16
++#define EF_MIPS_ABI2	    32
++#define EF_MIPS_ABI_ON32    64
++#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
++
++/* Legal values for MIPS architecture level.  */
++
++#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
++#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
++#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
++#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
++#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
++#define EF_MIPS_ARCH_32	    0x60000000	/* MIPS32 code.  */
++#define EF_MIPS_ARCH_64	    0x70000000	/* MIPS64 code.  */
++
++/* The following are non-official names and should not be used.  */
++
++#define E_MIPS_ARCH_1	  0x00000000	/* -mips1 code.  */
++#define E_MIPS_ARCH_2	  0x10000000	/* -mips2 code.  */
++#define E_MIPS_ARCH_3	  0x20000000	/* -mips3 code.  */
++#define E_MIPS_ARCH_4	  0x30000000	/* -mips4 code.  */
++#define E_MIPS_ARCH_5	  0x40000000	/* -mips5 code.  */
++#define E_MIPS_ARCH_32	  0x60000000	/* MIPS32 code.  */
++#define E_MIPS_ARCH_64	  0x70000000	/* MIPS64 code.  */
++
++/* Special section indices.  */
++
++#define SHN_MIPS_ACOMMON    0xff00	/* Allocated common symbols */
++#define SHN_MIPS_TEXT	    0xff01	/* Allocated test symbols.  */
++#define SHN_MIPS_DATA	    0xff02	/* Allocated data symbols.  */
++#define SHN_MIPS_SCOMMON    0xff03	/* Small common symbols */
++#define SHN_MIPS_SUNDEFINED 0xff04	/* Small undefined symbols */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
++#define SHT_MIPS_MSYM	       0x70000001
++#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
++#define SHT_MIPS_GPTAB	       0x70000003 /* Global data area sizes */
++#define SHT_MIPS_UCODE	       0x70000004 /* Reserved for SGI/MIPS compilers */
++#define SHT_MIPS_DEBUG	       0x70000005 /* MIPS ECOFF debugging information*/
++#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
++#define SHT_MIPS_PACKAGE       0x70000007
++#define SHT_MIPS_PACKSYM       0x70000008
++#define SHT_MIPS_RELD	       0x70000009
++#define SHT_MIPS_IFACE         0x7000000b
++#define SHT_MIPS_CONTENT       0x7000000c
++#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
++#define SHT_MIPS_SHDR	       0x70000010
++#define SHT_MIPS_FDESC	       0x70000011
++#define SHT_MIPS_EXTSYM	       0x70000012
++#define SHT_MIPS_DENSE	       0x70000013
++#define SHT_MIPS_PDESC	       0x70000014
++#define SHT_MIPS_LOCSYM	       0x70000015
++#define SHT_MIPS_AUXSYM	       0x70000016
++#define SHT_MIPS_OPTSYM	       0x70000017
++#define SHT_MIPS_LOCSTR	       0x70000018
++#define SHT_MIPS_LINE	       0x70000019
++#define SHT_MIPS_RFDESC	       0x7000001a
++#define SHT_MIPS_DELTASYM      0x7000001b
++#define SHT_MIPS_DELTAINST     0x7000001c
++#define SHT_MIPS_DELTACLASS    0x7000001d
++#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
++#define SHT_MIPS_DELTADECL     0x7000001f
++#define SHT_MIPS_SYMBOL_LIB    0x70000020
++#define SHT_MIPS_EVENTS	       0x70000021 /* Event section.  */
++#define SHT_MIPS_TRANSLATE     0x70000022
++#define SHT_MIPS_PIXIE	       0x70000023
++#define SHT_MIPS_XLATE	       0x70000024
++#define SHT_MIPS_XLATE_DEBUG   0x70000025
++#define SHT_MIPS_WHIRL	       0x70000026
++#define SHT_MIPS_EH_REGION     0x70000027
++#define SHT_MIPS_XLATE_OLD     0x70000028
++#define SHT_MIPS_PDR_EXCEPTION 0x70000029
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_MIPS_GPREL	 0x10000000	/* Must be part of global data area */
++#define SHF_MIPS_MERGE	 0x20000000
++#define SHF_MIPS_ADDR	 0x40000000
++#define SHF_MIPS_STRINGS 0x80000000
++#define SHF_MIPS_NOSTRIP 0x08000000
++#define SHF_MIPS_LOCAL	 0x04000000
++#define SHF_MIPS_NAMES	 0x02000000
++#define SHF_MIPS_NODUPE	 0x01000000
++
++
++/* Symbol tables.  */
++
++/* MIPS specific values for `st_other'.  */
++#define STO_MIPS_DEFAULT		0x0
++#define STO_MIPS_INTERNAL		0x1
++#define STO_MIPS_HIDDEN			0x2
++#define STO_MIPS_PROTECTED		0x3
++#define STO_MIPS_PLT			0x8
++#define STO_MIPS_SC_ALIGN_UNUSED	0xff
++
++/* MIPS specific values for `st_info'.  */
++#define STB_MIPS_SPLIT_COMMON		13
++
++/* Entries found in sections of type SHT_MIPS_GPTAB.  */
++
++typedef union
++{
++  struct
++    {
++      Elf32_Word gt_current_g_value;	/* -G value used for compilation */
++      Elf32_Word gt_unused;		/* Not used */
++    } gt_header;			/* First entry in section */
++  struct
++    {
++      Elf32_Word gt_g_value;		/* If this value were used for -G */
++      Elf32_Word gt_bytes;		/* This many bytes would be used */
++    } gt_entry;				/* Subsequent entries in section */
++} Elf32_gptab;
++
++/* Entry found in sections of type SHT_MIPS_REGINFO.  */
++
++typedef struct
++{
++  Elf32_Word	ri_gprmask;		/* General registers used */
++  Elf32_Word	ri_cprmask[4];		/* Coprocessor registers used */
++  Elf32_Sword	ri_gp_value;		/* $gp register value */
++} Elf32_RegInfo;
++
++/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
++
++typedef struct
++{
++  unsigned char kind;		/* Determines interpretation of the
++				   variable part of descriptor.  */
++  unsigned char size;		/* Size of descriptor, including header.  */
++  Elf32_Section section;	/* Section header index of section affected,
++				   0 for global options.  */
++  Elf32_Word info;		/* Kind-specific information.  */
++} Elf_Options;
++
++/* Values for `kind' field in Elf_Options.  */
++
++#define ODK_NULL	0	/* Undefined.  */
++#define ODK_REGINFO	1	/* Register usage information.  */
++#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
++#define ODK_PAD		3	/* Section padding options.  */
++#define ODK_HWPATCH	4	/* Hardware workarounds performed */
++#define ODK_FILL	5	/* record the fill value used by the linker. */
++#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
++#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
++#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
++
++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
++
++#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
++#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
++#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
++#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
++#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
++#define OEX_PRECISEFP	OEX_FPDBUG
++#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
++
++#define OEX_FPU_INVAL	0x10
++#define OEX_FPU_DIV0	0x08
++#define OEX_FPU_OFLO	0x04
++#define OEX_FPU_UFLO	0x02
++#define OEX_FPU_INEX	0x01
++
++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
++
++#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
++#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
++#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
++#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
++
++#define OPAD_PREFIX	0x1
++#define OPAD_POSTFIX	0x2
++#define OPAD_SYMBOL	0x4
++
++/* Entry found in `.options' section.  */
++
++typedef struct
++{
++  Elf32_Word hwp_flags1;	/* Extra flags.  */
++  Elf32_Word hwp_flags2;	/* Extra flags.  */
++} Elf_Options_Hw;
++
++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
++
++#define OHWA0_R4KEOP_CHECKED	0x00000001
++#define OHWA1_R4KEOP_CLEAN	0x00000002
++
++/* MIPS relocs.  */
++
++#define R_MIPS_NONE		0	/* No reloc */
++#define R_MIPS_16		1	/* Direct 16 bit */
++#define R_MIPS_32		2	/* Direct 32 bit */
++#define R_MIPS_REL32		3	/* PC relative 32 bit */
++#define R_MIPS_26		4	/* Direct 26 bit shifted */
++#define R_MIPS_HI16		5	/* High 16 bit */
++#define R_MIPS_LO16		6	/* Low 16 bit */
++#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
++#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
++#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
++#define R_MIPS_PC16		10	/* PC relative 16 bit */
++#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
++#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
++
++#define R_MIPS_SHIFT5		16
++#define R_MIPS_SHIFT6		17
++#define R_MIPS_64		18
++#define R_MIPS_GOT_DISP		19
++#define R_MIPS_GOT_PAGE		20
++#define R_MIPS_GOT_OFST		21
++#define R_MIPS_GOT_HI16		22
++#define R_MIPS_GOT_LO16		23
++#define R_MIPS_SUB		24
++#define R_MIPS_INSERT_A		25
++#define R_MIPS_INSERT_B		26
++#define R_MIPS_DELETE		27
++#define R_MIPS_HIGHER		28
++#define R_MIPS_HIGHEST		29
++#define R_MIPS_CALL_HI16	30
++#define R_MIPS_CALL_LO16	31
++#define R_MIPS_SCN_DISP		32
++#define R_MIPS_REL16		33
++#define R_MIPS_ADD_IMMEDIATE	34
++#define R_MIPS_PJUMP		35
++#define R_MIPS_RELGOT		36
++#define R_MIPS_JALR		37
++#define R_MIPS_TLS_DTPMOD32	38	/* Module number 32 bit */
++#define R_MIPS_TLS_DTPREL32	39	/* Module-relative offset 32 bit */
++#define R_MIPS_TLS_DTPMOD64	40	/* Module number 64 bit */
++#define R_MIPS_TLS_DTPREL64	41	/* Module-relative offset 64 bit */
++#define R_MIPS_TLS_GD		42	/* 16 bit GOT offset for GD */
++#define R_MIPS_TLS_LDM		43	/* 16 bit GOT offset for LDM */
++#define R_MIPS_TLS_DTPREL_HI16	44	/* Module-relative offset, high 16 bits */
++#define R_MIPS_TLS_DTPREL_LO16	45	/* Module-relative offset, low 16 bits */
++#define R_MIPS_TLS_GOTTPREL	46	/* 16 bit GOT offset for IE */
++#define R_MIPS_TLS_TPREL32	47	/* TP-relative offset, 32 bit */
++#define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
++#define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
++#define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
++#define R_MIPS_GLOB_DAT		51
++#define R_MIPS_COPY		126
++#define R_MIPS_JUMP_SLOT        127
++/* Keep this the last entry.  */
++#define R_MIPS_NUM		128
++
++/* Legal values for p_type field of Elf32_Phdr.  */
++
++#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
++#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
++#define PT_MIPS_OPTIONS 0x70000002
++
++/* Special program header types.  */
++
++#define PF_MIPS_LOCAL	0x10000000
++
++/* Legal values for d_tag field of Elf32_Dyn.  */
++
++#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
++#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
++#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
++#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
++#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
++#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
++#define DT_MIPS_MSYM	     0x70000007
++#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
++#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
++#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
++#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
++#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
++#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
++#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
++#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
++#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
++#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
++#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
++#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
++						DT_MIPS_DELTA_CLASS.  */
++#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
++						DT_MIPS_DELTA_INSTANCE.  */
++#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
++					     DT_MIPS_DELTA_RELOC.  */
++#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
++					   relocations refer to.  */
++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
++					   DT_MIPS_DELTA_SYM.  */
++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
++					     class declaration.  */
++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
++						DT_MIPS_DELTA_CLASSSYM.  */
++#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
++#define DT_MIPS_PIXIE_INIT   0x70000023
++#define DT_MIPS_SYMBOL_LIB   0x70000024
++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
++#define DT_MIPS_LOCAL_GOTIDX 0x70000026
++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
++#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
++#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
++						    function stored in GOT.  */
++#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
++					   by rld on dlopen() calls.  */
++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
++#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
++#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
++/* The address of .got.plt in an executable using the new non-PIC ABI.  */
++#define DT_MIPS_PLTGOT	     0x70000032
++/* The base of the PLT in an executable using the new non-PIC ABI if that
++   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
++   value.  */
++#define DT_MIPS_RWPLT        0x70000034
++#define DT_MIPS_NUM	     0x35
++
++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
++
++#define RHF_NONE		   0		/* No flags */
++#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
++#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
++#define RHF_NO_MOVE		   (1 << 3)
++#define RHF_SGI_ONLY		   (1 << 4)
++#define RHF_GUARANTEE_INIT	   (1 << 5)
++#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
++#define RHF_GUARANTEE_START_INIT   (1 << 7)
++#define RHF_PIXIE		   (1 << 8)
++#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
++#define RHF_REQUICKSTART	   (1 << 10)
++#define RHF_REQUICKSTARTED	   (1 << 11)
++#define RHF_CORD		   (1 << 12)
++#define RHF_NO_UNRES_UNDEF	   (1 << 13)
++#define RHF_RLD_ORDER_SAFE	   (1 << 14)
++
++/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
++
++typedef struct
++{
++  Elf32_Word l_name;		/* Name (string table index) */
++  Elf32_Word l_time_stamp;	/* Timestamp */
++  Elf32_Word l_checksum;	/* Checksum */
++  Elf32_Word l_version;		/* Interface version */
++  Elf32_Word l_flags;		/* Flags */
++} Elf32_Lib;
++
++typedef struct
++{
++  Elf64_Word l_name;		/* Name (string table index) */
++  Elf64_Word l_time_stamp;	/* Timestamp */
++  Elf64_Word l_checksum;	/* Checksum */
++  Elf64_Word l_version;		/* Interface version */
++  Elf64_Word l_flags;		/* Flags */
++} Elf64_Lib;
++
++
++/* Legal values for l_flags.  */
++
++#define LL_NONE		  0
++#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
++#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
++#define LL_REQUIRE_MINOR  (1 << 2)
++#define LL_EXPORTS	  (1 << 3)
++#define LL_DELAY_LOAD	  (1 << 4)
++#define LL_DELTA	  (1 << 5)
++
++/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
++
++typedef Elf32_Addr Elf32_Conflict;
++
++
++/* HPPA specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
++#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
++#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
++#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
++#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
++					      prediction.  */
++#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
++#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
++
++/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
++
++#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
++#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
++#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
++
++/* Additional section indeces.  */
++
++#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
++					      symbols in ANSI C.  */
++#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
++#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
++#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
++#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
++#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
++
++#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
++#define STT_HP_STUB		(STT_LOOS + 0x2)
++
++/* HPPA relocs.  */
++
++#define R_PARISC_NONE		0	/* No reloc.  */
++#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
++#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
++#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
++#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
++#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
++#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
++#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
++#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
++#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
++#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
++#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
++#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
++#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
++#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
++#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
++#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
++#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
++#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
++#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
++#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
++#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
++#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
++#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
++#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
++#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
++#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fdesc address.  */
++#define R_PARISC_PLABEL14R	70	/* Right 14 bits of fdesc address.  */
++#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
++#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
++#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
++#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
++#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
++#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
++#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
++#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
++#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
++#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
++#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
++#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
++#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
++#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
++#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LORESERVE	128
++#define R_PARISC_COPY		128	/* Copy relocation.  */
++#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
++#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
++#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
++#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
++#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
++#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
++#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
++#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
++#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_GNU_VTENTRY	232
++#define R_PARISC_GNU_VTINHERIT	233
++#define R_PARISC_TLS_GD21L	234	/* GD 21-bit left.  */
++#define R_PARISC_TLS_GD14R	235	/* GD 14-bit right.  */
++#define R_PARISC_TLS_GDCALL	236	/* GD call to __t_g_a.  */
++#define R_PARISC_TLS_LDM21L	237	/* LD module 21-bit left.  */
++#define R_PARISC_TLS_LDM14R	238	/* LD module 14-bit right.  */
++#define R_PARISC_TLS_LDMCALL	239	/* LD module call to __t_g_a.  */
++#define R_PARISC_TLS_LDO21L	240	/* LD offset 21-bit left.  */
++#define R_PARISC_TLS_LDO14R	241	/* LD offset 14-bit right.  */
++#define R_PARISC_TLS_DTPMOD32	242	/* DTP module 32-bit.  */
++#define R_PARISC_TLS_DTPMOD64	243	/* DTP module 64-bit.  */
++#define R_PARISC_TLS_DTPOFF32	244	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_DTPOFF64	245	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L
++#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R
++#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L
++#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R
++#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32
++#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64
++#define R_PARISC_HIRESERVE	255
++
++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PT_HP_TLS		(PT_LOOS + 0x0)
++#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
++#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
++#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
++#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
++#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
++#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
++#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
++#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
++#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
++#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
++#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
++#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
++#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
++#define PT_HP_STACK		(PT_LOOS + 0x14)
++
++#define PT_PARISC_ARCHEXT	0x70000000
++#define PT_PARISC_UNWIND	0x70000001
++
++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PF_PARISC_SBP		0x08000000
++
++#define PF_HP_PAGE_SIZE		0x00100000
++#define PF_HP_FAR_SHARED	0x00200000
++#define PF_HP_NEAR_SHARED	0x00400000
++#define PF_HP_CODE		0x01000000
++#define PF_HP_MODIFY		0x02000000
++#define PF_HP_LAZYSWAP		0x04000000
++#define PF_HP_SBP		0x08000000
++
++
++/* Alpha specific definitions.  */
++
++/* Legal values for e_flags field of Elf64_Ehdr.  */
++
++#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
++#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
++
++/* Legal values for sh_type field of Elf64_Shdr.  */
++
++/* These two are primerily concerned with ECOFF debugging info.  */
++#define SHT_ALPHA_DEBUG		0x70000001
++#define SHT_ALPHA_REGINFO	0x70000002
++
++/* Legal values for sh_flags field of Elf64_Shdr.  */
++
++#define SHF_ALPHA_GPREL		0x10000000
++
++/* Legal values for st_other field of Elf64_Sym.  */
++#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
++#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
++
++/* Alpha relocs.  */
++
++#define R_ALPHA_NONE		0	/* No reloc */
++#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
++#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
++#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
++#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
++#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
++#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
++#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
++#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
++#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
++#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
++#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
++#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
++#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
++#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
++#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
++#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
++#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
++#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
++#define R_ALPHA_TLS_GD_HI	28
++#define R_ALPHA_TLSGD		29
++#define R_ALPHA_TLS_LDM		30
++#define R_ALPHA_DTPMOD64	31
++#define R_ALPHA_GOTDTPREL	32
++#define R_ALPHA_DTPREL64	33
++#define R_ALPHA_DTPRELHI	34
++#define R_ALPHA_DTPRELLO	35
++#define R_ALPHA_DTPREL16	36
++#define R_ALPHA_GOTTPREL	37
++#define R_ALPHA_TPREL64		38
++#define R_ALPHA_TPRELHI		39
++#define R_ALPHA_TPRELLO		40
++#define R_ALPHA_TPREL16		41
++/* Keep this the last entry.  */
++#define R_ALPHA_NUM		46
++
++/* Magic values of the LITUSE relocation addend.  */
++#define LITUSE_ALPHA_ADDR	0
++#define LITUSE_ALPHA_BASE	1
++#define LITUSE_ALPHA_BYTOFF	2
++#define LITUSE_ALPHA_JSR	3
++#define LITUSE_ALPHA_TLS_GD	4
++#define LITUSE_ALPHA_TLS_LDM	5
++
++/* Legal values for d_tag of Elf64_Dyn.  */
++#define DT_ALPHA_PLTRO		(DT_LOPROC + 0)
++#define DT_ALPHA_NUM		1
++
++/* PowerPC specific declarations */
++
++/* Values for Elf32/64_Ehdr.e_flags.  */
++#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
++
++/* Cygnus local bits below */
++#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
++#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
++						   flag */
++
++/* PowerPC relocations defined by the ABIs */
++#define R_PPC_NONE		0
++#define R_PPC_ADDR32		1	/* 32bit absolute address */
++#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
++#define R_PPC_ADDR16		3	/* 16bit absolute address */
++#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
++#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
++#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
++#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
++#define R_PPC_ADDR14_BRTAKEN	8
++#define R_PPC_ADDR14_BRNTAKEN	9
++#define R_PPC_REL24		10	/* PC relative 26 bit */
++#define R_PPC_REL14		11	/* PC relative 16 bit */
++#define R_PPC_REL14_BRTAKEN	12
++#define R_PPC_REL14_BRNTAKEN	13
++#define R_PPC_GOT16		14
++#define R_PPC_GOT16_LO		15
++#define R_PPC_GOT16_HI		16
++#define R_PPC_GOT16_HA		17
++#define R_PPC_PLTREL24		18
++#define R_PPC_COPY		19
++#define R_PPC_GLOB_DAT		20
++#define R_PPC_JMP_SLOT		21
++#define R_PPC_RELATIVE		22
++#define R_PPC_LOCAL24PC		23
++#define R_PPC_UADDR32		24
++#define R_PPC_UADDR16		25
++#define R_PPC_REL32		26
++#define R_PPC_PLT32		27
++#define R_PPC_PLTREL32		28
++#define R_PPC_PLT16_LO		29
++#define R_PPC_PLT16_HI		30
++#define R_PPC_PLT16_HA		31
++#define R_PPC_SDAREL16		32
++#define R_PPC_SECTOFF		33
++#define R_PPC_SECTOFF_LO	34
++#define R_PPC_SECTOFF_HI	35
++#define R_PPC_SECTOFF_HA	36
++
++/* PowerPC relocations defined for the TLS access ABI.  */
++#define R_PPC_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
++#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
++#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
++#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
++#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
++#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
++#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
++#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
++#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
++#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
++
++/* The remaining relocs are from the Embedded ELF ABI, and are not
++   in the SVR4 ELF ABI.  */
++#define R_PPC_EMB_NADDR32	101
++#define R_PPC_EMB_NADDR16	102
++#define R_PPC_EMB_NADDR16_LO	103
++#define R_PPC_EMB_NADDR16_HI	104
++#define R_PPC_EMB_NADDR16_HA	105
++#define R_PPC_EMB_SDAI16	106
++#define R_PPC_EMB_SDA2I16	107
++#define R_PPC_EMB_SDA2REL	108
++#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
++#define R_PPC_EMB_MRKREF	110
++#define R_PPC_EMB_RELSEC16	111
++#define R_PPC_EMB_RELST_LO	112
++#define R_PPC_EMB_RELST_HI	113
++#define R_PPC_EMB_RELST_HA	114
++#define R_PPC_EMB_BIT_FLD	115
++#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
++
++/* Diab tool relocations.  */
++#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
++#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
++#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
++#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
++#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
++#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC_IRELATIVE		248
++
++/* GNU relocs used in PIC code sequences.  */
++#define R_PPC_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC_REL16_LO		250	/* half16   (sym+add-.)@l */
++#define R_PPC_REL16_HI		251	/* half16   (sym+add-.)@h */
++#define R_PPC_REL16_HA		252	/* half16   (sym+add-.)@ha */
++
++/* This is a phony reloc to handle any old fashioned TOC16 references
++   that may still be in object files.  */
++#define R_PPC_TOC16		255
++
++/* PowerPC specific values for the Dyn d_tag field.  */
++#define DT_PPC_GOT		(DT_LOPROC + 0)
++#define DT_PPC_NUM		1
++
++/* PowerPC64 relocations defined by the ABIs */
++#define R_PPC64_NONE		R_PPC_NONE
++#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
++#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
++#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
++#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
++#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
++#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
++#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
++#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
++#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
++#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
++#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
++#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
++#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
++#define R_PPC64_GOT16		R_PPC_GOT16
++#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
++#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
++#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
++
++#define R_PPC64_COPY		R_PPC_COPY
++#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
++#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
++#define R_PPC64_RELATIVE	R_PPC_RELATIVE
++
++#define R_PPC64_UADDR32		R_PPC_UADDR32
++#define R_PPC64_UADDR16		R_PPC_UADDR16
++#define R_PPC64_REL32		R_PPC_REL32
++#define R_PPC64_PLT32		R_PPC_PLT32
++#define R_PPC64_PLTREL32	R_PPC_PLTREL32
++#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
++#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
++#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
++
++#define R_PPC64_SECTOFF		R_PPC_SECTOFF
++#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
++#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
++#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
++#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
++#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
++#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
++#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
++#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
++#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
++#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
++#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
++#define R_PPC64_PLT64		45 /* doubleword64 L + A */
++#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
++#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
++#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
++#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
++#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
++#define R_PPC64_TOC		51 /* doubleword64 .TOC */
++#define R_PPC64_PLTGOT16	52 /* half16* M + A */
++#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
++#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
++#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
++
++#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
++#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
++#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
++#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
++#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
++#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
++#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
++#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
++#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
++#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
++#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
++
++/* PowerPC64 relocations defined for the TLS access ABI.  */
++#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
++#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
++#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
++#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
++#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
++#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
++#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
++#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
++#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
++#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
++#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC64_JMP_IREL	247
++#define R_PPC64_IRELATIVE	248
++#define R_PPC64_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC64_REL16_LO	250	/* half16   (sym+add-.)@l */
++#define R_PPC64_REL16_HI	251	/* half16   (sym+add-.)@h */
++#define R_PPC64_REL16_HA	252	/* half16   (sym+add-.)@ha */
++
++/* PowerPC64 specific values for the Dyn d_tag field.  */
++#define DT_PPC64_GLINK  (DT_LOPROC + 0)
++#define DT_PPC64_OPD	(DT_LOPROC + 1)
++#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
++#define DT_PPC64_NUM    3
++
++
++/* ARM specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_ARM_RELEXEC		0x01
++#define EF_ARM_HASENTRY		0x02
++#define EF_ARM_INTERWORK	0x04
++#define EF_ARM_APCS_26		0x08
++#define EF_ARM_APCS_FLOAT	0x10
++#define EF_ARM_PIC		0x20
++#define EF_ARM_ALIGN8		0x40 /* 8-bit structure alignment is in use */
++#define EF_ARM_NEW_ABI		0x80
++#define EF_ARM_OLD_ABI		0x100
++#define EF_ARM_SOFT_FLOAT	0x200
++#define EF_ARM_VFP_FLOAT	0x400
++#define EF_ARM_MAVERICK_FLOAT	0x800
++
++
++/* Other constants defined in the ARM ELF spec. version B-01.  */
++/* NB. These conflict with values defined above.  */
++#define EF_ARM_SYMSARESORTED	0x04
++#define EF_ARM_DYNSYMSUSESEGIDX	0x08
++#define EF_ARM_MAPSYMSFIRST	0x10
++#define EF_ARM_EABIMASK		0XFF000000
++
++/* Constants defined in AAELF.  */
++#define EF_ARM_BE8	    0x00800000
++#define EF_ARM_LE8	    0x00400000
++
++#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK)
++#define EF_ARM_EABI_UNKNOWN	0x00000000
++#define EF_ARM_EABI_VER1	0x01000000
++#define EF_ARM_EABI_VER2	0x02000000
++#define EF_ARM_EABI_VER3	0x03000000
++#define EF_ARM_EABI_VER4	0x04000000
++#define EF_ARM_EABI_VER5	0x05000000
++
++/* Additional symbol types for Thumb.  */
++#define STT_ARM_TFUNC		STT_LOPROC /* A Thumb function.  */
++#define STT_ARM_16BIT		STT_HIPROC /* A Thumb label.  */
++
++/* ARM-specific values for sh_flags */
++#define SHF_ARM_ENTRYSECT	0x10000000 /* Section contains an entry point */
++#define SHF_ARM_COMDEF		0x80000000 /* Section may be multiply defined
++					      in the input to a link step.  */
++
++/* ARM-specific program header flags */
++#define PF_ARM_SB		0x10000000 /* Segment contains the location
++					      addressed by the static base. */
++#define PF_ARM_PI		0x20000000 /* Position-independent segment.  */
++#define PF_ARM_ABS		0x40000000 /* Absolute segment.  */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
++#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
++#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
++
++
++/* ARM relocs.  */
++
++#define R_ARM_NONE		0	/* No reloc */
++#define R_ARM_PC24		1	/* PC relative 26 bit branch */
++#define R_ARM_ABS32		2	/* Direct 32 bit  */
++#define R_ARM_REL32		3	/* PC relative 32 bit */
++#define R_ARM_PC13		4
++#define R_ARM_ABS16		5	/* Direct 16 bit */
++#define R_ARM_ABS12		6	/* Direct 12 bit */
++#define R_ARM_THM_ABS5		7
++#define R_ARM_ABS8		8	/* Direct 8 bit */
++#define R_ARM_SBREL32		9
++#define R_ARM_THM_PC22		10
++#define R_ARM_THM_PC8		11
++#define R_ARM_AMP_VCALL9	12
++#define R_ARM_SWI24		13	/* Obsolete static relocation.  */
++#define R_ARM_TLS_DESC		13      /* Dynamic relocation.  */
++#define R_ARM_THM_SWI8		14
++#define R_ARM_XPC25		15
++#define R_ARM_THM_XPC22		16
++#define R_ARM_TLS_DTPMOD32	17	/* ID of module containing symbol */
++#define R_ARM_TLS_DTPOFF32	18	/* Offset in TLS block */
++#define R_ARM_TLS_TPOFF32	19	/* Offset in static TLS block */
++#define R_ARM_COPY		20	/* Copy symbol at runtime */
++#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
++#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
++#define R_ARM_RELATIVE		23	/* Adjust by program base */
++#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
++#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
++#define R_ARM_GOT32		26	/* 32 bit GOT entry */
++#define R_ARM_PLT32		27	/* 32 bit PLT address */
++#define R_ARM_ALU_PCREL_7_0	32
++#define R_ARM_ALU_PCREL_15_8	33
++#define R_ARM_ALU_PCREL_23_15	34
++#define R_ARM_LDR_SBREL_11_0	35
++#define R_ARM_ALU_SBREL_19_12	36
++#define R_ARM_ALU_SBREL_27_20	37
++#define R_ARM_TLS_GOTDESC	90
++#define R_ARM_TLS_CALL		91
++#define R_ARM_TLS_DESCSEQ	92
++#define R_ARM_THM_TLS_CALL	93
++#define R_ARM_GNU_VTENTRY	100
++#define R_ARM_GNU_VTINHERIT	101
++#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
++#define R_ARM_THM_PC9		103	/* thumb conditional branch */
++#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
++					   thread local data */
++#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
++					   thread local data */
++#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
++					   block */
++#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
++					   static TLS block offset */
++#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
++					   TLS block */
++#define	R_ARM_THM_TLS_DESCSEQ	129
++#define R_ARM_IRELATIVE		160
++#define R_ARM_RXPC25		249
++#define R_ARM_RSBREL32		250
++#define R_ARM_THM_RPC22		251
++#define R_ARM_RREL32		252
++#define R_ARM_RABS22		253
++#define R_ARM_RPC24		254
++#define R_ARM_RBASE		255
++/* Keep this the last entry.  */
++#define R_ARM_NUM		256
++
++/* IA-64 specific declarations.  */
++
++/* Processor specific flags for the Ehdr e_flags field.  */
++#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
++#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
++#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
++#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
++#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
++#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
++#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
++
++/* Processor specific flags for the Phdr p_flags field.  */
++#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
++#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
++
++/* Processor specific flags for the Shdr sh_flags field.  */
++#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
++#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Dyn d_tag field.  */
++#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
++#define DT_IA_64_NUM		1
++
++/* IA-64 relocations.  */
++#define R_IA64_NONE		0x00	/* none */
++#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
++#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
++#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
++#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
++#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
++#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
++#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
++#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
++#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
++#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
++#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
++#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
++#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
++#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
++#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
++#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
++#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
++#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
++#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
++#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
++#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
++#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
++#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
++#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
++#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
++#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
++#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
++#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
++#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
++#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
++#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
++#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
++#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
++#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
++#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
++#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
++#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
++#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
++#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
++#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
++#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
++#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
++#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
++#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
++#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
++#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
++#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
++#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
++#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
++#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
++#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
++#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
++#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
++#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
++#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
++#define R_IA64_COPY		0x84	/* copy relocation */
++#define R_IA64_SUB		0x85	/* Addend and symbol difference */
++#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
++#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
++#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
++#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
++#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
++#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
++#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
++#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
++#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
++#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
++#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
++#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
++#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
++#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
++#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
++#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
++
++/* SH specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_SH_MACH_MASK		0x1f
++#define EF_SH_UNKNOWN		0x0
++#define EF_SH1			0x1
++#define EF_SH2			0x2
++#define EF_SH3			0x3
++#define EF_SH_DSP		0x4
++#define EF_SH3_DSP		0x5
++#define EF_SH4AL_DSP		0x6
++#define EF_SH3E			0x8
++#define EF_SH4			0x9
++#define EF_SH2E			0xb
++#define EF_SH4A			0xc
++#define EF_SH2A			0xd
++#define EF_SH4_NOFPU		0x10
++#define EF_SH4A_NOFPU		0x11
++#define EF_SH4_NOMMU_NOFPU	0x12
++#define EF_SH2A_NOFPU		0x13
++#define EF_SH3_NOMMU		0x14
++#define EF_SH2A_SH4_NOFPU	0x15
++#define EF_SH2A_SH3_NOFPU	0x16
++#define EF_SH2A_SH4		0x17
++#define EF_SH2A_SH3E		0x18
++
++/* SH relocs.  */
++#define	R_SH_NONE		0
++#define	R_SH_DIR32		1
++#define	R_SH_REL32		2
++#define	R_SH_DIR8WPN		3
++#define	R_SH_IND12W		4
++#define	R_SH_DIR8WPL		5
++#define	R_SH_DIR8WPZ		6
++#define	R_SH_DIR8BP		7
++#define	R_SH_DIR8W		8
++#define	R_SH_DIR8L		9
++#define	R_SH_SWITCH16		25
++#define	R_SH_SWITCH32		26
++#define	R_SH_USES		27
++#define	R_SH_COUNT		28
++#define	R_SH_ALIGN		29
++#define	R_SH_CODE		30
++#define	R_SH_DATA		31
++#define	R_SH_LABEL		32
++#define	R_SH_SWITCH8		33
++#define	R_SH_GNU_VTINHERIT	34
++#define	R_SH_GNU_VTENTRY	35
++#define	R_SH_TLS_GD_32		144
++#define	R_SH_TLS_LD_32		145
++#define	R_SH_TLS_LDO_32		146
++#define	R_SH_TLS_IE_32		147
++#define	R_SH_TLS_LE_32		148
++#define	R_SH_TLS_DTPMOD32	149
++#define	R_SH_TLS_DTPOFF32	150
++#define	R_SH_TLS_TPOFF32	151
++#define	R_SH_GOT32		160
++#define	R_SH_PLT32		161
++#define	R_SH_COPY		162
++#define	R_SH_GLOB_DAT		163
++#define	R_SH_JMP_SLOT		164
++#define	R_SH_RELATIVE		165
++#define	R_SH_GOTOFF		166
++#define	R_SH_GOTPC		167
++/* Keep this the last entry.  */
++#define	R_SH_NUM		256
++
++/* S/390 specific definitions.  */
++
++/* Valid values for the e_flags field.  */
++
++#define EF_S390_HIGH_GPRS    0x00000001  /* High GPRs kernel facility needed.  */
++
++/* Additional s390 relocs */
++
++#define R_390_NONE		0	/* No reloc.  */
++#define R_390_8			1	/* Direct 8 bit.  */
++#define R_390_12		2	/* Direct 12 bit.  */
++#define R_390_16		3	/* Direct 16 bit.  */
++#define R_390_32		4	/* Direct 32 bit.  */
++#define R_390_PC32		5	/* PC relative 32 bit.	*/
++#define R_390_GOT12		6	/* 12 bit GOT offset.  */
++#define R_390_GOT32		7	/* 32 bit GOT offset.  */
++#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
++#define R_390_COPY		9	/* Copy symbol at runtime.  */
++#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
++#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
++#define R_390_RELATIVE		12	/* Adjust by program base.  */
++#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
++#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
++#define R_390_GOT16		15	/* 16 bit GOT offset.  */
++#define R_390_PC16		16	/* PC relative 16 bit.	*/
++#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
++#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
++#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
++#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
++#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
++#define R_390_64		22	/* Direct 64 bit.  */
++#define R_390_PC64		23	/* PC relative 64 bit.	*/
++#define R_390_GOT64		24	/* 64 bit GOT offset.  */
++#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
++#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
++#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
++#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
++#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
++#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
++#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
++#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
++#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
++#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
++#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
++#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
++#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
++#define R_390_TLS_GDCALL	38	/* Tag for function call in general
++					   dynamic TLS code. */
++#define R_390_TLS_LDCALL	39	/* Tag for function call in local
++					   dynamic TLS code. */
++#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
++					   thread local data.  */
++#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
++					  thread local data.  */
++#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
++					   block offset. */
++#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
++#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
++#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
++					   block.  */
++#define R_390_20		57	/* Direct 20 bit.  */
++#define R_390_GOT20		58	/* 20 bit GOT offset.  */
++#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
++#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
++/* Keep this the last entry.  */
++#define R_390_NUM		62
++
++
++/* CRIS relocations.  */
++#define R_CRIS_NONE		0
++#define R_CRIS_8		1
++#define R_CRIS_16		2
++#define R_CRIS_32		3
++#define R_CRIS_8_PCREL		4
++#define R_CRIS_16_PCREL		5
++#define R_CRIS_32_PCREL		6
++#define R_CRIS_GNU_VTINHERIT	7
++#define R_CRIS_GNU_VTENTRY	8
++#define R_CRIS_COPY		9
++#define R_CRIS_GLOB_DAT		10
++#define R_CRIS_JUMP_SLOT	11
++#define R_CRIS_RELATIVE		12
++#define R_CRIS_16_GOT		13
++#define R_CRIS_32_GOT		14
++#define R_CRIS_16_GOTPLT	15
++#define R_CRIS_32_GOTPLT	16
++#define R_CRIS_32_GOTREL	17
++#define R_CRIS_32_PLT_GOTREL	18
++#define R_CRIS_32_PLT_PCREL	19
++
++#define R_CRIS_NUM		20
++
++
++/* AMD x86-64 relocations.  */
++#define R_X86_64_NONE		0	/* No reloc */
++#define R_X86_64_64		1	/* Direct 64 bit  */
++#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
++#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
++#define R_X86_64_PLT32		4	/* 32 bit PLT address */
++#define R_X86_64_COPY		5	/* Copy symbol at runtime */
++#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
++#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
++#define R_X86_64_RELATIVE	8	/* Adjust by program base */
++#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
++					   offset to GOT */
++#define R_X86_64_32		10	/* Direct 32 bit zero extended */
++#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
++#define R_X86_64_16		12	/* Direct 16 bit zero extended */
++#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
++#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
++#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
++#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
++#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
++#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
++#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
++					   to two GOT entries for GD symbol */
++#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
++					   to two GOT entries for LD symbol */
++#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
++#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
++					   to GOT entry for IE symbol */
++#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
++#define R_X86_64_PC64		24	/* PC relative 64 bit */
++#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
++#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
++					   offset to GOT */
++#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
++#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
++					   to GOT entry */
++#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
++#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
++#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
++					   to PLT entry */
++#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
++#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
++#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
++#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
++					   descriptor.  */
++#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
++#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
++#define R_X86_64_RELATIVE64	38	/* 64-bit adjust by program base */
++
++#define R_X86_64_NUM		39
++
++
++/* AM33 relocations.  */
++#define R_MN10300_NONE		0	/* No reloc.  */
++#define R_MN10300_32		1	/* Direct 32 bit.  */
++#define R_MN10300_16		2	/* Direct 16 bit.  */
++#define R_MN10300_8		3	/* Direct 8 bit.  */
++#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
++#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
++#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
++#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
++#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
++#define R_MN10300_24		9	/* Direct 24 bit.  */
++#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
++#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
++#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
++#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
++#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
++#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
++#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
++#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
++#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
++#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
++#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
++#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
++
++#define R_MN10300_NUM		24
++
++
++/* M32R relocs.  */
++#define R_M32R_NONE		0	/* No reloc. */
++#define R_M32R_16		1	/* Direct 16 bit. */
++#define R_M32R_32		2	/* Direct 32 bit. */
++#define R_M32R_24		3	/* Direct 24 bit. */
++#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
++#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
++#define R_M32R_LO16		9	/* Low 16 bit. */
++#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
++#define R_M32R_GNU_VTINHERIT	11
++#define R_M32R_GNU_VTENTRY	12
++/* M32R relocs use SHT_RELA.  */
++#define R_M32R_16_RELA		33	/* Direct 16 bit. */
++#define R_M32R_32_RELA		34	/* Direct 32 bit. */
++#define R_M32R_24_RELA		35	/* Direct 24 bit. */
++#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
++#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
++#define R_M32R_LO16_RELA	41	/* Low 16 bit */
++#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
++#define R_M32R_RELA_GNU_VTINHERIT	43
++#define R_M32R_RELA_GNU_VTENTRY	44
++#define R_M32R_REL32		45	/* PC relative 32 bit.  */
++
++#define R_M32R_GOT24		48	/* 24 bit GOT entry */
++#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
++#define R_M32R_COPY		50	/* Copy symbol at runtime */
++#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
++#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
++#define R_M32R_RELATIVE		53	/* Adjust by program base */
++#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
++#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
++#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
++					   low */
++#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
++					   low */
++#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
++#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
++					   GOT with unsigned low */
++#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
++					   GOT with signed low */
++#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
++					   GOT */
++#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
++					   with unsigned low */
++#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
++					   with signed low */
++#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
++#define R_M32R_NUM		256	/* Keep this the last entry. */
++
++
++/* TILEPro relocations.  */
++#define R_TILEPRO_NONE		0	/* No reloc */
++#define R_TILEPRO_32		1	/* Direct 32 bit */
++#define R_TILEPRO_16		2	/* Direct 16 bit */
++#define R_TILEPRO_8		3	/* Direct 8 bit */
++#define R_TILEPRO_32_PCREL	4	/* PC relative 32 bit */
++#define R_TILEPRO_16_PCREL	5	/* PC relative 16 bit */
++#define R_TILEPRO_8_PCREL	6	/* PC relative 8 bit */
++#define R_TILEPRO_LO16		7	/* Low 16 bit */
++#define R_TILEPRO_HI16		8	/* High 16 bit */
++#define R_TILEPRO_HA16		9	/* High 16 bit, adjusted */
++#define R_TILEPRO_COPY		10	/* Copy relocation */
++#define R_TILEPRO_GLOB_DAT	11	/* Create GOT entry */
++#define R_TILEPRO_JMP_SLOT	12	/* Create PLT entry */
++#define R_TILEPRO_RELATIVE	13	/* Adjust by program base */
++#define R_TILEPRO_BROFF_X1	14	/* X1 pipe branch offset */
++#define R_TILEPRO_JOFFLONG_X1	15	/* X1 pipe jump offset */
++#define R_TILEPRO_JOFFLONG_X1_PLT 16	/* X1 pipe jump offset to PLT */
++#define R_TILEPRO_IMM8_X0	17	/* X0 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y0	18	/* Y0 pipe 8-bit */
++#define R_TILEPRO_IMM8_X1	19	/* X1 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y1	20	/* Y1 pipe 8-bit */
++#define R_TILEPRO_MT_IMM15_X1	21	/* X1 pipe mtspr */
++#define R_TILEPRO_MF_IMM15_X1	22	/* X1 pipe mfspr */
++#define R_TILEPRO_IMM16_X0	23	/* X0 pipe 16-bit */
++#define R_TILEPRO_IMM16_X1	24	/* X1 pipe 16-bit */
++#define R_TILEPRO_IMM16_X0_LO	25	/* X0 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X1_LO	26	/* X1 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X0_HI	27	/* X0 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X1_HI	28	/* X1 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X0_HA	29	/* X0 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X1_HA	30	/* X1 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X0_PCREL 31	/* X0 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X1_PCREL 32	/* X1 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X0_LO_PCREL 33	/* X0 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X1_LO_PCREL 34	/* X1 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X0_HI_PCREL 35	/* X0 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X1_HI_PCREL 36	/* X1 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X0_HA_PCREL 37	/* X0 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X1_HA_PCREL 38	/* X1 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X0_GOT	39	/* X0 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT	40	/* X1 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_LO 41	/* X0 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_LO 42	/* X1 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HI 43	/* X0 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HI 44	/* X1 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HA 45	/* X0 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HA 46	/* X1 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_MMSTART_X0	47	/* X0 pipe mm "start" */
++#define R_TILEPRO_MMEND_X0	48	/* X0 pipe mm "end" */
++#define R_TILEPRO_MMSTART_X1	49	/* X1 pipe mm "start" */
++#define R_TILEPRO_MMEND_X1	50	/* X1 pipe mm "end" */
++#define R_TILEPRO_SHAMT_X0	51	/* X0 pipe shift amount */
++#define R_TILEPRO_SHAMT_X1	52	/* X1 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y0	53	/* Y0 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y1	54	/* Y1 pipe shift amount */
++#define R_TILEPRO_DEST_IMM8_X1	55	/* X1 pipe destination 8-bit */
++/* Relocs 56-59 are currently not defined.  */
++#define R_TILEPRO_TLS_GD_CALL	60	/* "jal" for TLS GD */
++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61	/* X0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62	/* X1 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEPRO_TLS_IE_LOAD	65	/* "lw_tls" for TLS IE */
++#define R_TILEPRO_IMM16_X0_TLS_GD 66	/* X0 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD 67	/* X1 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68	/* X0 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69	/* X1 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70	/* X0 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71	/* X1 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72	/* X0 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73	/* X1 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE 74	/* X0 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE 75	/* X1 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76	/* X0 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77	/* X1 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78	/* X0 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79	/* X1 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80	/* X0 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81	/* X1 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_TLS_DTPMOD32	82	/* ID of module containing symbol */
++#define R_TILEPRO_TLS_DTPOFF32	83	/* Offset in TLS block */
++#define R_TILEPRO_TLS_TPOFF32	84	/* Offset in static TLS block */
++#define R_TILEPRO_IMM16_X0_TLS_LE 85	/* X0 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE 86	/* X1 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87	/* X0 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88	/* X1 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89	/* X0 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90	/* X1 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91	/* X0 pipe ha() 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92	/* X1 pipe ha() 16-bit TLS LE offset */
++
++#define R_TILEPRO_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEPRO_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEPRO_NUM		130
++
++
++/* TILE-Gx relocations.  */
++#define R_TILEGX_NONE		0	/* No reloc */
++#define R_TILEGX_64		1	/* Direct 64 bit */
++#define R_TILEGX_32		2	/* Direct 32 bit */
++#define R_TILEGX_16		3	/* Direct 16 bit */
++#define R_TILEGX_8		4	/* Direct 8 bit */
++#define R_TILEGX_64_PCREL	5	/* PC relative 64 bit */
++#define R_TILEGX_32_PCREL	6	/* PC relative 32 bit */
++#define R_TILEGX_16_PCREL	7	/* PC relative 16 bit */
++#define R_TILEGX_8_PCREL	8	/* PC relative 8 bit */
++#define R_TILEGX_HW0		9	/* hword 0 16-bit */
++#define R_TILEGX_HW1		10	/* hword 1 16-bit */
++#define R_TILEGX_HW2		11	/* hword 2 16-bit */
++#define R_TILEGX_HW3		12	/* hword 3 16-bit */
++#define R_TILEGX_HW0_LAST	13	/* last hword 0 16-bit */
++#define R_TILEGX_HW1_LAST	14	/* last hword 1 16-bit */
++#define R_TILEGX_HW2_LAST	15	/* last hword 2 16-bit */
++#define R_TILEGX_COPY		16	/* Copy relocation */
++#define R_TILEGX_GLOB_DAT	17	/* Create GOT entry */
++#define R_TILEGX_JMP_SLOT	18	/* Create PLT entry */
++#define R_TILEGX_RELATIVE	19	/* Adjust by program base */
++#define R_TILEGX_BROFF_X1	20	/* X1 pipe branch offset */
++#define R_TILEGX_JUMPOFF_X1	21	/* X1 pipe jump offset */
++#define R_TILEGX_JUMPOFF_X1_PLT	22	/* X1 pipe jump offset to PLT */
++#define R_TILEGX_IMM8_X0	23	/* X0 pipe 8-bit */
++#define R_TILEGX_IMM8_Y0	24	/* Y0 pipe 8-bit */
++#define R_TILEGX_IMM8_X1	25	/* X1 pipe 8-bit */
++#define R_TILEGX_IMM8_Y1	26	/* Y1 pipe 8-bit */
++#define R_TILEGX_DEST_IMM8_X1	27	/* X1 pipe destination 8-bit */
++#define R_TILEGX_MT_IMM14_X1	28	/* X1 pipe mtspr */
++#define R_TILEGX_MF_IMM14_X1	29	/* X1 pipe mfspr */
++#define R_TILEGX_MMSTART_X0	30	/* X0 pipe mm "start" */
++#define R_TILEGX_MMEND_X0	31	/* X0 pipe mm "end" */
++#define R_TILEGX_SHAMT_X0	32	/* X0 pipe shift amount */
++#define R_TILEGX_SHAMT_X1	33	/* X1 pipe shift amount */
++#define R_TILEGX_SHAMT_Y0	34	/* Y0 pipe shift amount */
++#define R_TILEGX_SHAMT_Y1	35	/* Y1 pipe shift amount */
++#define R_TILEGX_IMM16_X0_HW0	36	/* X0 pipe hword 0 */
++#define R_TILEGX_IMM16_X1_HW0	37	/* X1 pipe hword 0 */
++#define R_TILEGX_IMM16_X0_HW1	38	/* X0 pipe hword 1 */
++#define R_TILEGX_IMM16_X1_HW1	39	/* X1 pipe hword 1 */
++#define R_TILEGX_IMM16_X0_HW2	40	/* X0 pipe hword 2 */
++#define R_TILEGX_IMM16_X1_HW2	41	/* X1 pipe hword 2 */
++#define R_TILEGX_IMM16_X0_HW3	42	/* X0 pipe hword 3 */
++#define R_TILEGX_IMM16_X1_HW3	43	/* X1 pipe hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST 44	/* X0 pipe last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST 45	/* X1 pipe last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST 46	/* X0 pipe last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST 47	/* X1 pipe last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST 48	/* X0 pipe last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST 49	/* X1 pipe last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_PCREL 50	/* X0 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_PCREL 51	/* X1 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_PCREL 52	/* X0 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_PCREL 53	/* X1 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_PCREL 54	/* X0 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_PCREL 55	/* X1 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X0_HW3_PCREL 56	/* X0 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X1_HW3_PCREL 57	/* X1 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_GOT 64	/* X0 pipe hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_GOT 65	/* X1 pipe hword 0 GOT offset */
++/* Relocs 66-71 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
++/* Relocs 76-77 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78	/* X0 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79	/* X1 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80	/* X0 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81	/* X1 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
++/* Relocs 90-91 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92	/* X0 pipe hword 0 TLS IE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93	/* X1 pipe hword 0 TLS IE offset */
++/* Relocs 94-99 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
++/* Relocs 104-105 are currently not defined.  */
++#define R_TILEGX_TLS_DTPMOD64	106	/* 64-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF64	107	/* 64-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF64	108	/* 64-bit offset in static TLS block */
++#define R_TILEGX_TLS_DTPMOD32	109	/* 32-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF32	110	/* 32-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF32	111	/* 32-bit offset in static TLS block */
++#define R_TILEGX_TLS_GD_CALL	112	/* "jal" for TLS GD */
++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113	/* X0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114	/* X1 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEGX_TLS_IE_LOAD	117	/* "ld_tls" for TLS IE */
++#define R_TILEGX_IMM8_X0_TLS_ADD 118	/* X0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_X1_TLS_ADD 119	/* X1 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y0_TLS_ADD 120	/* Y0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y1_TLS_ADD 121	/* Y1 pipe "addi" for TLS GD/IE */
++
++#define R_TILEGX_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEGX_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEGX_NUM		130
++
++#endif	/* elf.h */
diff --git a/target/linux/generic/patches-3.18/212-byteshift_portability.patch b/target/linux/generic/patches-3.18/212-byteshift_portability.patch
new file mode 100644
index 0000000000..0f23ba9be9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/212-byteshift_portability.patch
@@ -0,0 +1,51 @@
+--- a/tools/include/tools/be_byteshift.h
++++ b/tools/include/tools/be_byteshift.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_BE_BYTESHIFT_H
+ #define _TOOLS_BE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_be16(const uint8_t *p)
+--- a/tools/include/tools/le_byteshift.h
++++ b/tools/include/tools/le_byteshift.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_LE_BYTESHIFT_H
+ #define _TOOLS_LE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_le16(const uint8_t *p)
+--- /dev/null
++++ b/tools/include/tools/linux_types.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_TYPES_H
++#define __LINUX_TYPES_H
++
++#include <stdint.h>
++
++typedef uint8_t __u8;
++typedef uint8_t __be8;
++typedef uint8_t __le8;
++
++typedef uint16_t __u16;
++typedef uint16_t __be16;
++typedef uint16_t __le16;
++
++typedef uint32_t __u32;
++typedef uint32_t __be32;
++typedef uint32_t __le32;
++
++typedef uint64_t __u64;
++typedef uint64_t __be64;
++typedef uint64_t __le64;
++
++#endif
diff --git a/target/linux/generic/patches-3.18/213-x86_vdso_portability.patch b/target/linux/generic/patches-3.18/213-x86_vdso_portability.patch
new file mode 100644
index 0000000000..937ab9054d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/213-x86_vdso_portability.patch
@@ -0,0 +1,13 @@
+--- a/arch/x86/vdso/vdso2c.c
++++ b/arch/x86/vdso/vdso2c.c
+@@ -63,8 +63,8 @@
+ 
+ #include <tools/le_byteshift.h>
+ 
+-#include <linux/elf.h>
+-#include <linux/types.h>
++#include <elf.h>
++#include <stdbool.h>
+ 
+ const char *outfilename;
+ 
diff --git a/target/linux/generic/patches-3.18/214-spidev_h_portability.patch b/target/linux/generic/patches-3.18/214-spidev_h_portability.patch
new file mode 100644
index 0000000000..dbee090547
--- /dev/null
+++ b/target/linux/generic/patches-3.18/214-spidev_h_portability.patch
@@ -0,0 +1,11 @@
+--- a/include/uapi/linux/spi/spidev.h
++++ b/include/uapi/linux/spi/spidev.h
+@@ -111,7 +111,7 @@ struct spi_ioc_transfer {
+ 
+ /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+ #define SPI_MSGSIZE(N) \
+-	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
++	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
+ 		? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+ #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+ 
diff --git a/target/linux/generic/patches-3.18/220-gc_sections.patch b/target/linux/generic/patches-3.18/220-gc_sections.patch
new file mode 100644
index 0000000000..d872949f8d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/220-gc_sections.patch
@@ -0,0 +1,531 @@
+From: Felix Fietkau <nbd@nbd.name>
+
+use -ffunction-sections, -fdata-sections and --gc-sections
+
+In combination with kernel symbol export stripping this significantly reduces
+the kernel image size. Used on both ARM and MIPS architectures.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ #
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
+ cflags-y			+= -msoft-float
+-LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
++LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
+ 
++ifndef CONFIG_FUNCTION_TRACER
++KBUILD_CFLAGS_KERNEL		+= -ffunction-sections -fdata-sections
++endif
++
+ #
+ # pass -msoft-float to GAS if it supports it.  However on newer binutils
+ # (specifically newer than 2.24.51.20140728) we then also need to explicitly
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -67,7 +67,7 @@ SECTIONS
+ 	/* Exception table for data bus errors */
+ 	__dbe_table : {
+ 		__start___dbe_table = .;
+-		*(__dbe_table)
++		KEEP(*(__dbe_table))
+ 		__stop___dbe_table = .;
+ 	}
+ 
+@@ -112,7 +112,7 @@ SECTIONS
+ 	. = ALIGN(4);
+ 	.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
+ 		__mips_machines_start = .;
+-		*(.mips.machines.init)
++		KEEP(*(.mips.machines.init))
+ 		__mips_machines_end = .;
+ 	}
+ 
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -89,7 +89,7 @@
+ #ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ #define MCOUNT_REC()	. = ALIGN(8);				\
+ 			VMLINUX_SYMBOL(__start_mcount_loc) = .; \
+-			*(__mcount_loc)				\
++			KEEP(*(__mcount_loc))			\
+ 			VMLINUX_SYMBOL(__stop_mcount_loc) = .;
+ #else
+ #define MCOUNT_REC()
+@@ -97,7 +97,7 @@
+ 
+ #ifdef CONFIG_TRACE_BRANCH_PROFILING
+ #define LIKELY_PROFILE()	VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
+-				*(_ftrace_annotated_branch)			      \
++				KEEP(*(_ftrace_annotated_branch))		      \
+ 				VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .;
+ #else
+ #define LIKELY_PROFILE()
+@@ -105,7 +105,7 @@
+ 
+ #ifdef CONFIG_PROFILE_ALL_BRANCHES
+ #define BRANCH_PROFILE()	VMLINUX_SYMBOL(__start_branch_profile) = .;   \
+-				*(_ftrace_branch)			      \
++				KEEP(*(_ftrace_branch))			      \
+ 				VMLINUX_SYMBOL(__stop_branch_profile) = .;
+ #else
+ #define BRANCH_PROFILE()
+@@ -114,7 +114,7 @@
+ #ifdef CONFIG_KPROBES
+ #define KPROBE_BLACKLIST()	. = ALIGN(8);				      \
+ 				VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
+-				*(_kprobe_blacklist)			      \
++				KEEP(*(_kprobe_blacklist))		      \
+ 				VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
+ #else
+ #define KPROBE_BLACKLIST()
+@@ -123,7 +123,7 @@
+ #ifdef CONFIG_EVENT_TRACING
+ #define FTRACE_EVENTS()	. = ALIGN(8);					\
+ 			VMLINUX_SYMBOL(__start_ftrace_events) = .;	\
+-			*(_ftrace_events)				\
++			KEEP(*(_ftrace_events))				\
+ 			VMLINUX_SYMBOL(__stop_ftrace_events) = .;
+ #else
+ #define FTRACE_EVENTS()
+@@ -131,7 +131,7 @@
+ 
+ #ifdef CONFIG_TRACING
+ #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .;      \
+-			 *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
++			 KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \
+ 			 VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
+ #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .;	\
+ 			 *(__tracepoint_str) /* Trace_printk fmt' pointer */ \
+@@ -144,7 +144,7 @@
+ #ifdef CONFIG_FTRACE_SYSCALLS
+ #define TRACE_SYSCALLS() . = ALIGN(8);					\
+ 			 VMLINUX_SYMBOL(__start_syscalls_metadata) = .;	\
+-			 *(__syscalls_metadata)				\
++			 KEEP(*(__syscalls_metadata))			\
+ 			 VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
+ #else
+ #define TRACE_SYSCALLS()
+@@ -158,8 +158,8 @@
+ #define _OF_TABLE_1(name)						\
+ 	. = ALIGN(8);							\
+ 	VMLINUX_SYMBOL(__##name##_of_table) = .;			\
+-	*(__##name##_of_table)						\
+-	*(__##name##_of_table_end)
++	KEEP(*(__##name##_of_table))					\
++	KEEP(*(__##name##_of_table_end))
+ 
+ #define CLKSRC_OF_TABLES()	OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
+ #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
+@@ -171,7 +171,7 @@
+ #define KERNEL_DTB()							\
+ 	STRUCT_ALIGN();							\
+ 	VMLINUX_SYMBOL(__dtb_start) = .;				\
+-	*(.dtb.init.rodata)						\
++	KEEP(*(.dtb.init.rodata))					\
+ 	VMLINUX_SYMBOL(__dtb_end) = .;
+ 
+ /* .data section */
+@@ -187,16 +187,17 @@
+ 	/* implement dynamic printk debug */				\
+ 	. = ALIGN(8);                                                   \
+ 	VMLINUX_SYMBOL(__start___jump_table) = .;                       \
+-	*(__jump_table)                                                 \
++	KEEP(*(__jump_table))                                           \
+ 	VMLINUX_SYMBOL(__stop___jump_table) = .;                        \
+ 	. = ALIGN(8);							\
+ 	VMLINUX_SYMBOL(__start___verbose) = .;                          \
+-	*(__verbose)                                                    \
++	KEEP(*(__verbose))                                              \
+ 	VMLINUX_SYMBOL(__stop___verbose) = .;				\
+ 	LIKELY_PROFILE()		       				\
+ 	BRANCH_PROFILE()						\
+ 	TRACE_PRINTKS()							\
+-	TRACEPOINT_STR()
++	TRACEPOINT_STR()                                                \
++	*(.data.[a-zA-Z_]*)
+ 
+ /*
+  * Data section helpers
+@@ -250,35 +251,35 @@
+ 	/* PCI quirks */						\
+ 	.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_early) = .;		\
+-		*(.pci_fixup_early)					\
++		KEEP(*(.pci_fixup_early))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_early) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_header) = .;		\
+-		*(.pci_fixup_header)					\
++		KEEP(*(.pci_fixup_header))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_header) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_final) = .;		\
+-		*(.pci_fixup_final)					\
++		KEEP(*(.pci_fixup_final))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_final) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_enable) = .;		\
+-		*(.pci_fixup_enable)					\
++		KEEP(*(.pci_fixup_enable))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_resume) = .;		\
+-		*(.pci_fixup_resume)					\
++		KEEP(*(.pci_fixup_resume))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_resume) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .;	\
+-		*(.pci_fixup_resume_early)				\
++		KEEP(*(.pci_fixup_resume_early))			\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .;	\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .;		\
+-		*(.pci_fixup_suspend)					\
++		KEEP(*(.pci_fixup_suspend))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .;	\
+-		*(.pci_fixup_suspend_late)				\
++		KEEP(*(.pci_fixup_suspend_late))			\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .;	\
+ 	}								\
+ 									\
+ 	/* Built-in firmware blobs */					\
+ 	.builtin_fw        : AT(ADDR(.builtin_fw) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start_builtin_fw) = .;			\
+-		*(.builtin_fw)						\
++		KEEP(*(.builtin_fw))					\
+ 		VMLINUX_SYMBOL(__end_builtin_fw) = .;			\
+ 	}								\
+ 									\
+@@ -287,49 +288,49 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
+-		*(SORT(___ksymtab+*))					\
++		KEEP(*(SORT(___ksymtab+*)))				\
+ 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
+-		*(SORT(___ksymtab_gpl+*))				\
++		KEEP(*(SORT(___ksymtab_gpl+*)))				\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: Normal unused symbols */		\
+ 	__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_unused) = .;		\
+-		*(SORT(___ksymtab_unused+*))				\
++		KEEP(*(SORT(___ksymtab_unused+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;		\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only unused symbols */		\
+ 	__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;	\
+-		*(SORT(___ksymtab_unused_gpl+*))			\
++		KEEP(*(SORT(___ksymtab_unused_gpl+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-future-only symbols */		\
+ 	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
+-		*(SORT(___ksymtab_gpl_future+*))			\
++		KEEP(*(SORT(___ksymtab_gpl_future+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
+-		*(SORT(___kcrctab+*))					\
++		KEEP(*(SORT(___kcrctab+*)))				\
+ 		VMLINUX_SYMBOL(__stop___kcrctab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___kcrctab_gpl) = .;		\
+-		*(SORT(___kcrctab_gpl+*))				\
++		KEEP(*(SORT(___kcrctab_gpl+*)))				\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
+ 	}								\
+ 									\
+@@ -343,14 +344,14 @@
+ 	/* Kernel symbol table: GPL-only unused symbols */		\
+ 	__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;	\
+-		*(SORT(___kcrctab_unused_gpl+*))			\
++		KEEP(*(SORT(___kcrctab_unused_gpl+*)))			\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-future-only symbols */		\
+ 	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
+-		*(SORT(___kcrctab_gpl_future+*))			\
++		KEEP(*(SORT(___kcrctab_gpl_future+*)))			\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
+ 	}								\
+ 									\
+@@ -369,14 +370,14 @@
+ 	/* Built-in module parameters. */				\
+ 	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
+ 		VMLINUX_SYMBOL(__start___param) = .;			\
+-		*(__param)						\
++		KEEP(*(__param))					\
+ 		VMLINUX_SYMBOL(__stop___param) = .;			\
+ 	}								\
+ 									\
+ 	/* Built-in module versions. */					\
+ 	__modver : AT(ADDR(__modver) - LOAD_OFFSET) {			\
+ 		VMLINUX_SYMBOL(__start___modver) = .;			\
+-		*(__modver)						\
++		KEEP(*(__modver))					\
+ 		VMLINUX_SYMBOL(__stop___modver) = .;			\
+ 		. = ALIGN((align));					\
+ 		VMLINUX_SYMBOL(__end_rodata) = .;			\
+@@ -432,7 +433,7 @@
+ #define ENTRY_TEXT							\
+ 		ALIGN_FUNCTION();					\
+ 		VMLINUX_SYMBOL(__entry_text_start) = .;			\
+-		*(.entry.text)						\
++		KEEP(*(.entry.text))					\
+ 		VMLINUX_SYMBOL(__entry_text_end) = .;
+ 
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+@@ -460,7 +461,7 @@
+ 	. = ALIGN(align);						\
+ 	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ex_table) = .;			\
+-		*(__ex_table)						\
++		KEEP(*(__ex_table))						\
+ 		VMLINUX_SYMBOL(__stop___ex_table) = .;			\
+ 	}
+ 
+@@ -476,8 +477,8 @@
+ #ifdef CONFIG_CONSTRUCTORS
+ #define KERNEL_CTORS()	. = ALIGN(8);			   \
+ 			VMLINUX_SYMBOL(__ctors_start) = .; \
+-			*(.ctors)			   \
+-			*(.init_array)			   \
++			KEEP(*(.ctors))			   \
++			KEEP(*(.init_array))		   \
+ 			VMLINUX_SYMBOL(__ctors_end) = .;
+ #else
+ #define KERNEL_CTORS()
+@@ -525,7 +526,7 @@
+ #define SBSS(sbss_align)						\
+ 	. = ALIGN(sbss_align);						\
+ 	.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {				\
+-		*(.sbss)						\
++		*(.sbss .sbss.*)					\
+ 		*(.scommon)						\
+ 	}
+ 
+@@ -543,7 +544,7 @@
+ 		BSS_FIRST_SECTIONS					\
+ 		*(.bss..page_aligned)					\
+ 		*(.dynbss)						\
+-		*(.bss)							\
++		*(.bss .bss.*)						\
+ 		*(COMMON)						\
+ 	}
+ 
+@@ -592,7 +593,7 @@
+ 	. = ALIGN(8);							\
+ 	__bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___bug_table) = .;		\
+-		*(__bug_table)						\
++		KEEP(*(__bug_table))					\
+ 		VMLINUX_SYMBOL(__stop___bug_table) = .;			\
+ 	}
+ #else
+@@ -604,7 +605,7 @@
+ 	. = ALIGN(4);							\
+ 	.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__tracedata_start) = .;			\
+-		*(.tracedata)						\
++		KEEP(*(.tracedata))					\
+ 		VMLINUX_SYMBOL(__tracedata_end) = .;			\
+ 	}
+ #else
+@@ -621,17 +622,17 @@
+ #define INIT_SETUP(initsetup_align)					\
+ 		. = ALIGN(initsetup_align);				\
+ 		VMLINUX_SYMBOL(__setup_start) = .;			\
+-		*(.init.setup)						\
++		KEEP(*(.init.setup))					\
+ 		VMLINUX_SYMBOL(__setup_end) = .;
+ 
+ #define INIT_CALLS_LEVEL(level)						\
+ 		VMLINUX_SYMBOL(__initcall##level##_start) = .;		\
+-		*(.initcall##level##.init)				\
+-		*(.initcall##level##s.init)				\
++		KEEP(*(.initcall##level##.init))			\
++		KEEP(*(.initcall##level##s.init))			\
+ 
+ #define INIT_CALLS							\
+ 		VMLINUX_SYMBOL(__initcall_start) = .;			\
+-		*(.initcallearly.init)					\
++		KEEP(*(.initcallearly.init))				\
+ 		INIT_CALLS_LEVEL(0)					\
+ 		INIT_CALLS_LEVEL(1)					\
+ 		INIT_CALLS_LEVEL(2)					\
+@@ -645,21 +646,21 @@
+ 
+ #define CON_INITCALL							\
+ 		VMLINUX_SYMBOL(__con_initcall_start) = .;		\
+-		*(.con_initcall.init)					\
++		KEEP(*(.con_initcall.init))				\
+ 		VMLINUX_SYMBOL(__con_initcall_end) = .;
+ 
+ #define SECURITY_INITCALL						\
+ 		VMLINUX_SYMBOL(__security_initcall_start) = .;		\
+-		*(.security_initcall.init)				\
++		KEEP(*(.security_initcall.init))			\
+ 		VMLINUX_SYMBOL(__security_initcall_end) = .;
+ 
+ #ifdef CONFIG_BLK_DEV_INITRD
+ #define INIT_RAM_FS							\
+ 	. = ALIGN(4);							\
+ 	VMLINUX_SYMBOL(__initramfs_start) = .;				\
+-	*(.init.ramfs)							\
++	KEEP(*(.init.ramfs))						\
+ 	. = ALIGN(8);							\
+-	*(.init.ramfs.info)
++	KEEP(*(.init.ramfs.info))
+ #else
+ #define INIT_RAM_FS
+ #endif
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -18,11 +18,16 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+ LDFLAGS_vmlinux	+= --be8
+ LDFLAGS_MODULE	+= --be8
+ endif
++LDFLAGS_vmlinux += --gc-sections
+ 
+ OBJCOPYFLAGS	:=-O binary -R .comment -S
+ GZFLAGS		:=-9
+ #KBUILD_CFLAGS	+=-pipe
+ 
++ifndef CONFIG_FUNCTION_TRACER
++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
++endif
++
+ # Never generate .eh_frame
+ KBUILD_CFLAGS	+= $(call cc-option,-fno-dwarf2-cfi-asm)
+ 
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -12,13 +12,13 @@
+ #define PROC_INFO							\
+ 	. = ALIGN(4);							\
+ 	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
+-	*(.proc.info.init)						\
++	KEEP(*(.proc.info.init))					\
+ 	VMLINUX_SYMBOL(__proc_info_end) = .;
+ 
+ #define IDMAP_TEXT							\
+ 	ALIGN_FUNCTION();						\
+ 	VMLINUX_SYMBOL(__idmap_text_start) = .;				\
+-	*(.idmap.text)							\
++	KEEP(*(.idmap.text))						\
+ 	VMLINUX_SYMBOL(__idmap_text_end) = .;				\
+ 	. = ALIGN(32);							\
+ 	VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;			\
+@@ -93,7 +93,7 @@ SECTIONS
+ 	.text : {			/* Real text segment		*/
+ 		_stext = .;		/* Text and read-only data	*/
+ 			__exception_text_start = .;
+-			*(.exception.text)
++			KEEP(*(.exception.text))
+ 			__exception_text_end = .;
+ 			IRQENTRY_TEXT
+ 			TEXT_TEXT
+@@ -118,7 +118,7 @@ SECTIONS
+ 	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+ 		__start___ex_table = .;
+ #ifdef CONFIG_MMU
+-		*(__ex_table)
++		KEEP(*(__ex_table))
+ #endif
+ 		__stop___ex_table = .;
+ 	}
+@@ -130,12 +130,12 @@ SECTIONS
+ 	. = ALIGN(8);
+ 	.ARM.unwind_idx : {
+ 		__start_unwind_idx = .;
+-		*(.ARM.exidx*)
++		KEEP(*(.ARM.exidx*))
+ 		__stop_unwind_idx = .;
+ 	}
+ 	.ARM.unwind_tab : {
+ 		__start_unwind_tab = .;
+-		*(.ARM.extab*)
++		KEEP(*(.ARM.extab*))
+ 		__stop_unwind_tab = .;
+ 	}
+ #endif
+@@ -154,14 +154,14 @@ SECTIONS
+ 	 */
+ 	__vectors_start = .;
+ 	.vectors 0 : AT(__vectors_start) {
+-		*(.vectors)
++		KEEP(*(.vectors))
+ 	}
+ 	. = __vectors_start + SIZEOF(.vectors);
+ 	__vectors_end = .;
+ 
+ 	__stubs_start = .;
+ 	.stubs 0x1000 : AT(__stubs_start) {
+-		*(.stubs)
++		KEEP(*(.stubs))
+ 	}
+ 	. = __stubs_start + SIZEOF(.stubs);
+ 	__stubs_end = .;
+@@ -175,24 +175,24 @@ SECTIONS
+ 	}
+ 	.init.arch.info : {
+ 		__arch_info_begin = .;
+-		*(.arch.info.init)
++		KEEP(*(.arch.info.init))
+ 		__arch_info_end = .;
+ 	}
+ 	.init.tagtable : {
+ 		__tagtable_begin = .;
+-		*(.taglist.init)
++		KEEP(*(.taglist.init))
+ 		__tagtable_end = .;
+ 	}
+ #ifdef CONFIG_SMP_ON_UP
+ 	.init.smpalt : {
+ 		__smpalt_begin = .;
+-		*(.alt.smp.init)
++		KEEP(*(.alt.smp.init))
+ 		__smpalt_end = .;
+ 	}
+ #endif
+ 	.init.pv_table : {
+ 		__pv_table_begin = .;
+-		*(.pv_table)
++		KEEP(*(.pv_table))
+ 		__pv_table_end = .;
+ 	}
+ 	.init.data : {
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -122,6 +122,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+ endif
++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
+ 
+ ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj)
+ asflags-y := -DZIMAGE
diff --git a/target/linux/generic/patches-3.18/221-module_exports.patch b/target/linux/generic/patches-3.18/221-module_exports.patch
new file mode 100644
index 0000000000..f2cad7a028
--- /dev/null
+++ b/target/linux/generic/patches-3.18/221-module_exports.patch
@@ -0,0 +1,88 @@
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -54,6 +54,16 @@
+ #define LOAD_OFFSET 0
+ #endif
+ 
++#ifndef SYMTAB_KEEP
++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
++#endif
++
++#ifndef SYMTAB_DISCARD
++#define SYMTAB_DISCARD
++#define SYMTAB_DISCARD_GPL
++#endif
++
+ #include <linux/export.h>
+ 
+ /* Align . to a 8 byte boundary equals to maximum function alignment. */
+@@ -288,14 +298,14 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
+-		KEEP(*(SORT(___ksymtab+*)))				\
++		SYMTAB_KEEP						\
+ 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
+-		KEEP(*(SORT(___ksymtab_gpl+*)))				\
++		SYMTAB_KEEP_GPL						\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
+ 	}								\
+ 									\
+@@ -357,7 +367,7 @@
+ 									\
+ 	/* Kernel symbol table: strings */				\
+         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
+-		*(__ksymtab_strings)					\
++		*(__ksymtab_strings+*)					\
+ 	}								\
+ 									\
+ 	/* __*init sections */						\
+@@ -679,6 +689,8 @@
+ 	EXIT_TEXT							\
+ 	EXIT_DATA							\
+ 	EXIT_CALL							\
++	SYMTAB_DISCARD							\
++	SYMTAB_DISCARD_GPL						\
+ 	*(.discard)							\
+ 	*(.discard.*)							\
+ 	}
+--- a/scripts/Makefile.build
++++ b/scripts/Makefile.build
+@@ -298,7 +298,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
+ # Linker scripts preprocessor (.lds.S -> .lds)
+ # ---------------------------------------------------------------------------
+ quiet_cmd_cpp_lds_S = LDS     $@
+-      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
++      cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \
+ 	                     -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+ 
+ $(obj)/%.lds: $(src)/%.lds.S FORCE
+--- a/include/linux/export.h
++++ b/include/linux/export.h
+@@ -52,12 +52,19 @@ extern struct module __this_module;
+ #define __CRC_SYMBOL(sym, sec)
+ #endif
+ 
++#ifdef MODULE
++#define __EXPORT_SUFFIX(sym)
++#else
++#define __EXPORT_SUFFIX(sym) "+" #sym
++#endif
++
+ /* For every exported symbol, place a struct in the __ksymtab section */
+ #define __EXPORT_SYMBOL(sym, sec)				\
+ 	extern typeof(sym) sym;					\
+ 	__CRC_SYMBOL(sym, sec)					\
+ 	static const char __kstrtab_##sym[]			\
+-	__attribute__((section("__ksymtab_strings"), aligned(1))) \
++	__attribute__((section("__ksymtab_strings"		\
++	  __EXPORT_SUFFIX(sym)), aligned(1)))			\
+ 	= VMLINUX_SYMBOL_STR(sym);				\
+ 	extern const struct kernel_symbol __ksymtab_##sym;	\
+ 	__visible const struct kernel_symbol __ksymtab_##sym	\
diff --git a/target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch b/target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch
new file mode 100644
index 0000000000..e59fdcd2e0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/230-openwrt_lzma_options.patch
@@ -0,0 +1,58 @@
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -325,7 +325,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
+ 
+ quiet_cmd_lzma = LZMA    $@
+ cmd_lzma = (cat $(filter-out FORCE,$^) | \
+-	lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
++	lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+ 	(rm -f $@ ; false)
+ 
+ quiet_cmd_lzo = LZO     $@
+--- a/scripts/gen_initramfs_list.sh
++++ b/scripts/gen_initramfs_list.sh
+@@ -226,7 +226,7 @@ cpio_list=
+ output="/dev/stdout"
+ output_file=""
+ is_cpio_compressed=
+-compr="gzip -n -9 -f"
++compr="gzip -n -9 -f -"
+ 
+ arg="$1"
+ case "$arg" in
+@@ -242,13 +242,13 @@ case "$arg" in
+ 		output=${cpio_list}
+ 		echo "$output_file" | grep -q "\.gz$" \
+                 && [ -x "`which gzip 2> /dev/null`" ] \
+-                && compr="gzip -n -9 -f"
++                && compr="gzip -n -9 -f -"
+ 		echo "$output_file" | grep -q "\.bz2$" \
+                 && [ -x "`which bzip2 2> /dev/null`" ] \
+-                && compr="bzip2 -9 -f"
++                && compr="bzip2 -9 -f -"
+ 		echo "$output_file" | grep -q "\.lzma$" \
+                 && [ -x "`which lzma 2> /dev/null`" ] \
+-                && compr="lzma -9 -f"
++                && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
+ 		echo "$output_file" | grep -q "\.xz$" \
+                 && [ -x "`which xz 2> /dev/null`" ] \
+                 && compr="xz --check=crc32 --lzma2=dict=1MiB"
+@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then
+ 	if [ "${is_cpio_compressed}" = "compressed" ]; then
+ 		cat ${cpio_tfile} > ${output_file}
+ 	else
+-		(cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
++		(cat ${cpio_tfile} | ${compr} > ${output_file}) \
+ 		|| (rm -f ${output_file} ; false)
+ 	fi
+ 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
+--- a/lib/decompress.c
++++ b/lib/decompress.c
+@@ -48,6 +48,7 @@ static const struct compress_format comp
+ 	{ {037, 0236}, "gzip", gunzip },
+ 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
+ 	{ {0x5d, 0x00}, "lzma", unlzma },
++	{ {0x6d, 0x00}, "lzma-openwrt", unlzma },
+ 	{ {0xfd, 0x37}, "xz", unxz },
+ 	{ {0x89, 0x4c}, "lzo", unlzo },
+ 	{ {0x02, 0x21}, "lz4", unlz4 },
diff --git a/target/linux/generic/patches-3.18/250-netfilter_depends.patch b/target/linux/generic/patches-3.18/250-netfilter_depends.patch
new file mode 100644
index 0000000000..47be4a0197
--- /dev/null
+++ b/target/linux/generic/patches-3.18/250-netfilter_depends.patch
@@ -0,0 +1,18 @@
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -210,7 +210,6 @@ config NF_CONNTRACK_FTP
+ 
+ config NF_CONNTRACK_H323
+ 	tristate "H.323 protocol support"
+-	depends on (IPV6 || IPV6=n)
+ 	depends on NETFILTER_ADVANCED
+ 	help
+ 	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
+@@ -907,7 +906,6 @@ config NETFILTER_XT_TARGET_SECMARK
+ 
+ config NETFILTER_XT_TARGET_TCPMSS
+ 	tristate '"TCPMSS" target support'
+-	depends on (IPV6 || IPV6=n)
+ 	default m if NETFILTER_ADVANCED=n
+ 	---help---
+ 	  This option adds a `TCPMSS' target, which allows you to alter the
diff --git a/target/linux/generic/patches-3.18/251-sound_kconfig.patch b/target/linux/generic/patches-3.18/251-sound_kconfig.patch
new file mode 100644
index 0000000000..c2ebacecd1
--- /dev/null
+++ b/target/linux/generic/patches-3.18/251-sound_kconfig.patch
@@ -0,0 +1,18 @@
+--- a/sound/core/Kconfig
++++ b/sound/core/Kconfig
+@@ -10,13 +10,13 @@ config SND_DMAENGINE_PCM
+ 	tristate
+ 
+ config SND_HWDEP
+-	tristate
++	tristate "Sound hardware support"
+ 
+ config SND_RAWMIDI
+ 	tristate
+ 
+ config SND_COMPRESS_OFFLOAD
+-	tristate
++	tristate "Compression offloading support"
+ 
+ # To be effective this also requires INPUT - users should say:
+ #    select SND_JACK if INPUT=y || INPUT=SND
diff --git a/target/linux/generic/patches-3.18/252-mv_cesa_depends.patch b/target/linux/generic/patches-3.18/252-mv_cesa_depends.patch
new file mode 100644
index 0000000000..fee28db120
--- /dev/null
+++ b/target/linux/generic/patches-3.18/252-mv_cesa_depends.patch
@@ -0,0 +1,10 @@
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -164,6 +164,7 @@ config CRYPTO_DEV_MV_CESA
+ 	depends on PLAT_ORION
+ 	select CRYPTO_ALGAPI
+ 	select CRYPTO_AES
++	select CRYPTO_HASH2
+ 	select CRYPTO_BLKCIPHER2
+ 	select CRYPTO_HASH
+ 	help
diff --git a/target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch b/target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch
new file mode 100644
index 0000000000..29d2a41a3b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/253-ssb_b43_default_on.patch
@@ -0,0 +1,29 @@
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -29,6 +29,7 @@ config SSB_SPROM
+ config SSB_BLOCKIO
+ 	bool
+ 	depends on SSB
++	default y
+ 
+ config SSB_PCIHOST_POSSIBLE
+ 	bool
+@@ -49,7 +50,7 @@ config SSB_PCIHOST
+ config SSB_B43_PCI_BRIDGE
+ 	bool
+ 	depends on SSB_PCIHOST
+-	default n
++	default y
+ 
+ config SSB_PCMCIAHOST_POSSIBLE
+ 	bool
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -17,6 +17,7 @@ config BCMA
+ config BCMA_BLOCKIO
+ 	bool
+ 	depends on BCMA
++	default y
+ 
+ config BCMA_HOST_PCI_POSSIBLE
+ 	bool
diff --git a/target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch b/target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch
new file mode 100644
index 0000000000..3c3b1e1b53
--- /dev/null
+++ b/target/linux/generic/patches-3.18/254-textsearch_kconfig_hacks.patch
@@ -0,0 +1,23 @@
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -320,16 +320,16 @@ config BCH_CONST_T
+ # Textsearch support is select'ed if needed
+ #
+ config TEXTSEARCH
+-	boolean
++	boolean	"Textsearch support"
+ 
+ config TEXTSEARCH_KMP
+-	tristate
++	tristate "Textsearch KMP"
+ 
+ config TEXTSEARCH_BM
+-	tristate
++	tristate "Textsearch BM"
+ 
+ config TEXTSEARCH_FSM
+-	tristate
++	tristate "Textsearch FSM"
+ 
+ config BTREE
+ 	boolean
diff --git a/target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch b/target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch
new file mode 100644
index 0000000000..d8752359c7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/255-lib80211_kconfig_hacks.patch
@@ -0,0 +1,31 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -183,7 +183,7 @@ config CFG80211_WEXT
+ 	  extensions with cfg80211-based drivers.
+ 
+ config LIB80211
+-	tristate
++	tristate "LIB80211"
+ 	default n
+ 	help
+ 	  This options enables a library of common routines used
+@@ -192,13 +192,16 @@ config LIB80211
+ 	  Drivers should select this themselves if needed.
+ 
+ config LIB80211_CRYPT_WEP
+-	tristate
++	tristate "LIB80211_CRYPT_WEP"
++	select LIB80211
+ 
+ config LIB80211_CRYPT_CCMP
+-	tristate
++	tristate "LIB80211_CRYPT_CCMP"
++	select LIB80211
+ 
+ config LIB80211_CRYPT_TKIP
+-	tristate
++	tristate "LIB80211_CRYPT_TKIP"
++	select LIB80211
+ 
+ config LIB80211_DEBUG
+ 	bool "lib80211 debugging messages"
diff --git a/target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch b/target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch
new file mode 100644
index 0000000000..f9f6c0ea7b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/256-crypto_add_kconfig_prompts.patch
@@ -0,0 +1,47 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -32,7 +32,7 @@ config CRYPTO_FIPS
+ 	  this is.
+ 
+ config CRYPTO_ALGAPI
+-	tristate
++	tristate "ALGAPI"
+ 	select CRYPTO_ALGAPI2
+ 	help
+ 	  This option provides the API for cryptographic algorithms.
+@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2
+ 	tristate
+ 
+ config CRYPTO_AEAD
+-	tristate
++	tristate "AEAD"
+ 	select CRYPTO_AEAD2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -50,7 +50,7 @@ config CRYPTO_AEAD2
+ 	select CRYPTO_ALGAPI2
+ 
+ config CRYPTO_BLKCIPHER
+-	tristate
++	tristate "BLKCIPHER"
+ 	select CRYPTO_BLKCIPHER2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -61,7 +61,7 @@ config CRYPTO_BLKCIPHER2
+ 	select CRYPTO_WORKQUEUE
+ 
+ config CRYPTO_HASH
+-	tristate
++	tristate "HASH"
+ 	select CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -70,7 +70,7 @@ config CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI2
+ 
+ config CRYPTO_RNG
+-	tristate
++	tristate "RNG"
+ 	select CRYPTO_RNG2
+ 	select CRYPTO_ALGAPI
+ 
diff --git a/target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch b/target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch
new file mode 100644
index 0000000000..daac5898ae
--- /dev/null
+++ b/target/linux/generic/patches-3.18/257-wireless_ext_kconfig_hack.patch
@@ -0,0 +1,22 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -1,5 +1,5 @@
+ config WIRELESS_EXT
+-	bool
++	bool "Wireless extensions"
+ 
+ config WEXT_CORE
+ 	def_bool y
+@@ -11,10 +11,10 @@ config WEXT_PROC
+ 	depends on WEXT_CORE
+ 
+ config WEXT_SPY
+-	bool
++	bool "WEXT_SPY"
+ 
+ config WEXT_PRIV
+-	bool
++	bool "WEXT_PRIV"
+ 
+ config CFG80211
+ 	tristate "cfg80211 - wireless configuration API"
diff --git a/target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch b/target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch
new file mode 100644
index 0000000000..9d827c253b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/258-netfilter_netlink_kconfig_hack.patch
@@ -0,0 +1,11 @@
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -2,7 +2,7 @@ menu "Core Netfilter Configuration"
+ 	depends on NET && INET && NETFILTER
+ 
+ config NETFILTER_NETLINK
+-	tristate
++	tristate "Netfilter NFNETLINK interface"
+ 
+ config NETFILTER_NETLINK_ACCT
+ tristate "Netfilter NFACCT over NFNETLINK interface"
diff --git a/target/linux/generic/patches-3.18/259-regmap_dynamic.patch b/target/linux/generic/patches-3.18/259-regmap_dynamic.patch
new file mode 100644
index 0000000000..b1d4ad2772
--- /dev/null
+++ b/target/linux/generic/patches-3.18/259-regmap_dynamic.patch
@@ -0,0 +1,80 @@
+--- a/drivers/base/regmap/Kconfig
++++ b/drivers/base/regmap/Kconfig
+@@ -3,26 +3,31 @@
+ # subsystems should select the appropriate symbols.
+ 
+ config REGMAP
+-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
+ 	select LZO_COMPRESS
+ 	select LZO_DECOMPRESS
+ 	select IRQ_DOMAIN if REGMAP_IRQ
+-	bool
++	tristate "Regmap"
+ 
+ config REGMAP_I2C
+-	tristate
++	tristate "Regmap I2C"
++	select REGMAP
+ 	depends on I2C
+ 
+ config REGMAP_SPI
+-	tristate
++	tristate "Regmap SPI"
++	select REGMAP
++	depends on SPI_MASTER
+ 	depends on SPI
+ 
+ config REGMAP_SPMI
++	select REGMAP
+ 	tristate
+ 	depends on SPMI
+ 
+ config REGMAP_MMIO
+-	tristate
++	tristate "Regmap MMIO"
++	select REGMAP
+ 
+ config REGMAP_IRQ
++	select REGMAP
+ 	bool
+--- a/include/linux/regmap.h
++++ b/include/linux/regmap.h
+@@ -49,7 +49,7 @@ struct reg_default {
+ 	unsigned int def;
+ };
+ 
+-#ifdef CONFIG_REGMAP
++#if IS_ENABLED(CONFIG_REGMAP)
+ 
+ enum regmap_endian {
+ 	/* Unspecified -> 0 -> Backwards compatible default */
+--- a/drivers/base/regmap/Makefile
++++ b/drivers/base/regmap/Makefile
+@@ -1,6 +1,8 @@
+-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
+-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
+-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o
++ifdef CONFIG_DEBUG_FS
++regmap-core-objs += regmap-debugfs.o
++endif
++obj-$(CONFIG_REGMAP) += regmap-core.o
+ obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
+ obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
+ obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
+--- a/drivers/base/regmap/regmap.c
++++ b/drivers/base/regmap/regmap.c
+@@ -13,6 +13,7 @@
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/export.h>
++#include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/err.h>
+ #include <linux/of.h>
+@@ -2630,3 +2631,5 @@ static int __init regmap_initcall(void)
+ 	return 0;
+ }
+ postcore_initcall(regmap_initcall);
++
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch b/target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch
new file mode 100644
index 0000000000..8a96fd9da7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/260-crypto_test_dependencies.patch
@@ -0,0 +1,37 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -96,10 +96,10 @@ config CRYPTO_MANAGER
+ 
+ config CRYPTO_MANAGER2
+ 	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
+-	select CRYPTO_AEAD2
+-	select CRYPTO_HASH2
+-	select CRYPTO_BLKCIPHER2
+-	select CRYPTO_PCOMP2
++	select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ 
+ config CRYPTO_USER
+ 	tristate "Userspace cryptographic algorithm configuration"
+--- a/crypto/algboss.c
++++ b/crypto/algboss.c
+@@ -248,6 +248,9 @@ static int cryptomgr_schedule_test(struc
+ 	type = alg->cra_flags;
+ 
+ 	/* This piece of crap needs to disappear into per-type test hooks. */
++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
++	type |= CRYPTO_ALG_TESTED;
++#else
+ 	if ((!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
+ 	       CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) &&
+ 	     ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+@@ -256,6 +259,7 @@ static int cryptomgr_schedule_test(struc
+ 	    (!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) &&
+ 	     alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize))
+ 		type |= CRYPTO_ALG_TESTED;
++#endif
+ 
+ 	param->type = type;
+ 
diff --git a/target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch b/target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
new file mode 100644
index 0000000000..762f4989b6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
@@ -0,0 +1,34 @@
+From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 14:37:54 +0200
+Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h
+
+including sysinfo.h from kernel.h makes no sense whatsoever,
+but removing it breaks glibc's userspace header,
+which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h.
+this seems to be a historical mistake.
+on musl, including any header that uses kernel.h directly or indirectly
+plus sys/sysinfo.h will produce a compile error due to redefinition of
+struct sysinfo from sys/sysinfo.h.
+so for now, only include it on glibc or when including from kernel
+in order not to break their headers.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Signed-off-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/kernel.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/uapi/linux/kernel.h
++++ b/include/uapi/linux/kernel.h
+@@ -1,7 +1,9 @@
+ #ifndef _UAPI_LINUX_KERNEL_H
+ #define _UAPI_LINUX_KERNEL_H
+ 
++#if defined(__KERNEL__) || defined( __GLIBC__)
+ #include <linux/sysinfo.h>
++#endif
+ 
+ /*
+  * 'kernel.h' contains some often-used function prototypes etc
diff --git a/target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
new file mode 100644
index 0000000000..891299ead1
--- /dev/null
+++ b/target/linux/generic/patches-3.18/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
@@ -0,0 +1,81 @@
+From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 16:50:40 +0200
+Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__
+
+Musl provides the same structs as glibc, but does not provide a define to
+allow its detection. Since the absence of __GLIBC__ also can mean that it
+is included from the kernel, change the __GLIBC__ detection to
+!__KERNEL__, which should always be true when included from userspace.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/libc-compat.h | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -48,13 +48,13 @@
+ #ifndef _UAPI_LIBC_COMPAT_H
+ #define _UAPI_LIBC_COMPAT_H
+ 
+-/* We have included glibc headers... */
+-#if defined(__GLIBC__)
++/* We have included libc headers... */
++#if !defined(__KERNEL__)
+ 
+-/* Coordinate with glibc netinet/in.h header. */
++/* Coordinate with libc netinet/in.h header. */
+ #if defined(_NETINET_IN_H)
+ 
+-/* GLIBC headers included first so don't define anything
++/* LIBC headers included first so don't define anything
+  * that would already be defined. */
+ #define __UAPI_DEF_IN_ADDR		0
+ #define __UAPI_DEF_IN_IPPROTO		0
+@@ -68,7 +68,7 @@
+  * if the glibc code didn't define them. This guard matches
+  * the guard in glibc/inet/netinet/in.h which defines the
+  * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
+-#if defined(__USE_MISC) || defined (__USE_GNU)
++#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU)
+ #define __UAPI_DEF_IN6_ADDR_ALT		0
+ #else
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
+@@ -81,7 +81,7 @@
+ #else
+ 
+ /* Linux headers included first, and we must define everything
+- * we need. The expectation is that glibc will check the
++ * we need. The expectation is that the libc will check the
+  * __UAPI_DEF_* defines and adjust appropriately. */
+ #define __UAPI_DEF_IN_ADDR		1
+ #define __UAPI_DEF_IN_IPPROTO		1
+@@ -91,7 +91,7 @@
+ #define __UAPI_DEF_IN_CLASS		1
+ 
+ #define __UAPI_DEF_IN6_ADDR		1
+-/* We unconditionally define the in6_addr macros and glibc must
++/* We unconditionally define the in6_addr macros and the libc must
+  * coordinate. */
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
+ #define __UAPI_DEF_SOCKADDR_IN6		1
+@@ -111,7 +111,7 @@
+ /* If we did not see any headers from any supported C libraries,
+  * or we are being included in the kernel, then define everything
+  * that we need. */
+-#else /* !defined(__GLIBC__) */
++#else /* defined(__KERNEL__) */
+ 
+ /* Definitions for in.h */
+ #define __UAPI_DEF_IN_ADDR		1
+@@ -132,6 +132,6 @@
+ /* Definitions for xattr.h */
+ #define __UAPI_DEF_XATTR		1
+ 
+-#endif /* __GLIBC__ */
++#endif /* __KERNEL__ */
+ 
+ #endif /* _UAPI_LIBC_COMPAT_H */
diff --git a/target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
new file mode 100644
index 0000000000..feea4c31c6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
@@ -0,0 +1,67 @@
+From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 16:53:03 +0200
+Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr
+
+Musl provides its own ethhdr struct definition. Add a guard to prevent
+its definition of the appropriate musl header has already been included.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/if_ether.h    |  3 +++
+ include/uapi/linux/libc-compat.h | 11 +++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/include/uapi/linux/if_ether.h
++++ b/include/uapi/linux/if_ether.h
+@@ -22,6 +22,7 @@
+ #define _UAPI_LINUX_IF_ETHER_H
+ 
+ #include <linux/types.h>
++#include <linux/libc-compat.h>
+ 
+ /*
+  *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+@@ -134,11 +135,13 @@
+  *	This is an Ethernet frame header.
+  */
+ 
++#if __UAPI_DEF_ETHHDR
+ struct ethhdr {
+ 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+ 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+ 	__be16		h_proto;		/* packet type ID field	*/
+ } __attribute__((packed));
++#endif
+ 
+ 
+ #endif /* _UAPI_LINUX_IF_ETHER_H */
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -51,6 +51,14 @@
+ /* We have included libc headers... */
+ #if !defined(__KERNEL__)
+ 
++/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
++ * Glibc just includes the kernel header and uses a different guard. */
++#if defined(_NETINET_IF_ETHER_H)
++#define __UAPI_DEF_ETHHDR		0
++#else
++#define __UAPI_DEF_ETHHDR		1
++#endif
++
+ /* Coordinate with libc netinet/in.h header. */
+ #if defined(_NETINET_IN_H)
+ 
+@@ -113,6 +121,9 @@
+  * that we need. */
+ #else /* defined(__KERNEL__) */
+ 
++/* Definitions for if_ether.h */
++#define __UAPI_DEF_ETHHDR 		1
++
+ /* Definitions for in.h */
+ #define __UAPI_DEF_IN_ADDR		1
+ #define __UAPI_DEF_IN_IPPROTO		1
diff --git a/target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch b/target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch
new file mode 100644
index 0000000000..69d61f20a9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/300-mips_expose_boot_raw.patch
@@ -0,0 +1,39 @@
+From: Mark Miller <mark@mirell.org>
+
+This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
+certain Broadcom chipsets running CFE in order to load the kernel.
+
+Signed-off-by: Mark Miller <mark@mirell.org>
+Acked-by: Rob Landley <rob@landley.net>
+---
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -892,9 +892,6 @@ config FW_ARC
+ config ARCH_MAY_HAVE_PC_FDC
+ 	bool
+ 
+-config BOOT_RAW
+-	bool
+-
+ config CEVT_BCM1480
+ 	bool
+ 
+@@ -2503,6 +2500,18 @@ config USE_OF
+ config BUILTIN_DTB
+ 	bool
+ 
++config BOOT_RAW
++	bool "Enable the kernel to be executed from the load address"
++	default n
++	help
++	 Allow the kernel to be executed from the load address for
++	 bootloaders which cannot read the ELF format. This places
++	 a jump to start_kernel at the load address.
++
++	 If unsure, say N.
++
++
++
+ endmenu
+ 
+ config LOCKDEP_SUPPORT
diff --git a/target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch b/target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch
new file mode 100644
index 0000000000..c87d4480ce
--- /dev/null
+++ b/target/linux/generic/patches-3.18/301-mips_image_cmdline_hack.patch
@@ -0,0 +1,28 @@
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -988,6 +988,10 @@ config SYNC_R4K
+ config MIPS_MACHINE
+ 	def_bool n
+ 
++config IMAGE_CMDLINE_HACK
++	bool "OpenWrt specific image command line hack"
++	default n
++
+ config NO_IOPORT_MAP
+ 	def_bool n
+ 
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry)
+ 	j	kernel_entry
+ #endif
+ 
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++	.ascii	"CMDLINE:"
++EXPORT(__image_cmdline)
++	.fill	0x400
++#endif /* CONFIG_IMAGE_CMDLINE_HACK */
++
+ 	__REF
+ 
+ NESTED(kernel_entry, 16, sp)			# kernel entry point
diff --git a/target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch b/target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch
new file mode 100644
index 0000000000..44c6b04fcf
--- /dev/null
+++ b/target/linux/generic/patches-3.18/302-mips_no_branch_likely.patch
@@ -0,0 +1,11 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ # machines may also.  Since BFD is incredibly buggy with respect to
+ # crossformat linking we rely on the elf2ecoff tool for format conversion.
+ #
+-cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
++cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
diff --git a/target/linux/generic/patches-3.18/304-mips_disable_fpu.patch b/target/linux/generic/patches-3.18/304-mips_disable_fpu.patch
new file mode 100644
index 0000000000..37ec9934ff
--- /dev/null
+++ b/target/linux/generic/patches-3.18/304-mips_disable_fpu.patch
@@ -0,0 +1,105 @@
+From:   Manuel Lauss <manuel.lauss@gmail.com>
+Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
+Date:   Mon,  7 Apr 2014 12:57:04 +0200
+Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com>
+
+This small patch makes the MIPS FPU emulator optional. The kernel
+kills float-users on systems without a hardware FPU by sending a SIGILL.
+
+Disabling the emulator shrinks vmlinux by about 54kBytes (32bit,
+optimizing for size).
+
+Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
+---
+v4: rediffed because of patch 1/2, should now work with micromips as well
+v3: updated patch description with size savings.
+v2: incorporated changes suggested by Jonas Gorski
+    force the fpu emulator on for micromips: relocating the parts
+    of the mmips code in the emulator to other areas would be a
+    much larger change; I went the cheap route instead with this.
+
+ arch/mips/Kbuild                     |  2 +-
+ arch/mips/Kconfig                    | 14 ++++++++++++++
+ arch/mips/include/asm/fpu.h          |  5 +++--
+ arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++
+ 4 files changed, 33 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -2495,6 +2495,20 @@ config MIPS_O32_FP64_SUPPORT
+ 
+ 	  If unsure, say N.
+ 
++config MIPS_FPU_EMULATOR
++	bool "MIPS FPU Emulator"
++	default y
++	help
++	  This option lets you disable the built-in MIPS FPU (Coprocessor 1)
++	  emulator, which handles floating-point instructions on processors
++	  without a hardware FPU.  It is generally a good idea to keep the
++	  emulator built-in, unless you are perfectly sure you have a
++	  complete soft-float environment.  With the emulator disabled, all
++	  users of float operations will be killed with an illegal instr-
++	  uction exception.
++
++	  Say Y, please.
++
+ config USE_OF
+ 	bool
+ 	select OF
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -275,7 +275,7 @@ OBJCOPYFLAGS		+= --remove-section=.regin
+ head-y := arch/mips/kernel/head.o
+ 
+ libs-y			+= arch/mips/lib/
+-libs-y			+= arch/mips/math-emu/
++libs-$(CONFIG_MIPS_FPU_EMULATOR)	+= arch/mips/math-emu/
+ 
+ # See arch/mips/Kbuild for content of core part of the kernel
+ core-y += arch/mips/
+--- a/arch/mips/include/asm/fpu.h
++++ b/arch/mips/include/asm/fpu.h
+@@ -169,8 +169,10 @@ static inline int init_fpu(void)
+ 		ret = __own_fpu();
+ 		if (!ret)
+ 			_init_fpu();
+-	} else
++	} else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR))
+ 		fpu_emulator_init_fpu();
++	else
++		ret = SIGILL;
+ 
+ 	return ret;
+ }
+--- a/arch/mips/include/asm/fpu_emulator.h
++++ b/arch/mips/include/asm/fpu_emulator.h
+@@ -30,6 +30,7 @@
+ #include <asm/local.h>
+ #include <asm/processor.h>
+ 
++#ifdef CONFIG_MIPS_FPU_EMULATOR
+ #ifdef CONFIG_DEBUG_FS
+ 
+ struct mips_fpu_emulator_stats {
+@@ -65,6 +66,20 @@ extern int do_dsemulret(struct pt_regs *
+ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
+ 				    struct mips_fpu_struct *ctx, int has_fpu,
+ 				    void *__user *fault_addr);
++#else	/* no CONFIG_MIPS_FPU_EMULATOR */
++static inline int do_dsemulret(struct pt_regs *xcp)
++{
++	return 0;	/* 0 means error, should never get here anyway */
++}
++
++static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
++				struct mips_fpu_struct *ctx, int has_fpu,
++				void *__user *fault_addr)
++{
++	return SIGILL;	/* we don't speak MIPS FPU */
++}
++#endif	/* CONFIG_MIPS_FPU_EMULATOR */
++
+ int process_fpemu_return(int sig, void __user *fault_addr);
+ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
+ 		     unsigned long *contpc);
diff --git a/target/linux/generic/patches-3.18/305-mips_module_reloc.patch b/target/linux/generic/patches-3.18/305-mips_module_reloc.patch
new file mode 100644
index 0000000000..f8ca91401a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/305-mips_module_reloc.patch
@@ -0,0 +1,353 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
++ifdef CONFIG_64BIT
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
++else
++KBUILD_AFLAGS_MODULE		+= -mno-long-calls
++KBUILD_CFLAGS_MODULE		+= -mno-long-calls
++endif
+ 
+ ifndef CONFIG_FUNCTION_TRACER
+ KBUILD_CFLAGS_KERNEL		+= -ffunction-sections -fdata-sections
+--- a/arch/mips/include/asm/module.h
++++ b/arch/mips/include/asm/module.h
+@@ -11,6 +11,11 @@ struct mod_arch_specific {
+ 	const struct exception_table_entry *dbe_start;
+ 	const struct exception_table_entry *dbe_end;
+ 	struct mips_hi16 *r_mips_hi16_list;
++
++	void *phys_plt_tbl;
++	void *virt_plt_tbl;
++	unsigned int phys_plt_offset;
++	unsigned int virt_plt_offset;
+ };
+ 
+ typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */
+--- a/arch/mips/kernel/module.c
++++ b/arch/mips/kernel/module.c
+@@ -43,14 +43,222 @@ struct mips_hi16 {
+ static LIST_HEAD(dbe_list);
+ static DEFINE_SPINLOCK(dbe_lock);
+ 
+-#ifdef MODULE_START
++/*
++ * Get the potential max trampolines size required of the init and
++ * non-init sections. Only used if we cannot find enough contiguous
++ * physically mapped memory to put the module into.
++ */
++static unsigned int
++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
++             const char *secstrings, unsigned int symindex, bool is_init)
++{
++	unsigned long ret = 0;
++	unsigned int i, j;
++	Elf_Sym *syms;
++
++	/* Everything marked ALLOC (this includes the exported symbols) */
++	for (i = 1; i < hdr->e_shnum; ++i) {
++		unsigned int info = sechdrs[i].sh_info;
++
++		if (sechdrs[i].sh_type != SHT_REL
++		    && sechdrs[i].sh_type != SHT_RELA)
++			continue;
++
++		/* Not a valid relocation section? */
++		if (info >= hdr->e_shnum)
++			continue;
++
++		/* Don't bother with non-allocated sections */
++		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
++			continue;
++
++		/* If it's called *.init*, and we're not init, we're
++                   not interested */
++		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
++		    != is_init)
++			continue;
++
++		syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
++		if (sechdrs[i].sh_type == SHT_REL) {
++			Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rel[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		} else {
++			Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rela[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		}
++	}
++
++	return ret;
++}
++
++#ifndef MODULE_START
++static void *alloc_phys(unsigned long size)
++{
++	unsigned order;
++	struct page *page;
++	struct page *p;
++
++	size = PAGE_ALIGN(size);
++	order = get_order(size);
++
++	page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
++			__GFP_THISNODE, order);
++	if (!page)
++		return NULL;
++
++	split_page(page, order);
++
++	for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
++		__free_page(p);
++
++	return page_address(page);
++}
++#endif
++
++static void free_phys(void *ptr, unsigned long size)
++{
++	struct page *page;
++	struct page *end;
++
++	page = virt_to_page(ptr);
++	end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT);
++
++	for (; page < end; ++page)
++		__free_page(page);
++}
++
++
+ void *module_alloc(unsigned long size)
+ {
++#ifdef MODULE_START
+ 	return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
+ 				GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE,
+ 				__builtin_return_address(0));
++#else
++	void *ptr;
++
++	if (size == 0)
++		return NULL;
++
++	ptr = alloc_phys(size);
++
++	/* If we failed to allocate physically contiguous memory,
++	 * fall back to regular vmalloc. The module loader code will
++	 * create jump tables to handle long jumps */
++	if (!ptr)
++		return vmalloc(size);
++
++	return ptr;
++#endif
+ }
++
++static inline bool is_phys_addr(void *ptr)
++{
++#ifdef CONFIG_64BIT
++	return (KSEGX((unsigned long)ptr) == CKSEG0);
++#else
++	return (KSEGX(ptr) == KSEG0);
+ #endif
++}
++
++/* Free memory returned from module_alloc */
++void module_free(struct module *mod, void *module_region)
++{
++	if (is_phys_addr(module_region)) {
++		if (mod->module_init == module_region)
++			free_phys(module_region, mod->init_size);
++		else if (mod->module_core == module_region)
++			free_phys(module_region, mod->core_size);
++		else
++			BUG();
++	} else {
++		vfree(module_region);
++	}
++}
++
++static void *__module_alloc(int size, bool phys)
++{
++	void *ptr;
++
++	if (phys)
++		ptr = kmalloc(size, GFP_KERNEL);
++	else
++		ptr = vmalloc(size);
++	return ptr;
++}
++
++static void __module_free(void *ptr)
++{
++	if (is_phys_addr(ptr))
++		kfree(ptr);
++	else
++		vfree(ptr);
++}
++
++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
++			      char *secstrings, struct module *mod)
++{
++	unsigned int symindex = 0;
++	unsigned int core_size, init_size;
++	int i;
++
++	mod->arch.phys_plt_offset = 0;
++	mod->arch.virt_plt_offset = 0;
++	mod->arch.phys_plt_tbl = NULL;
++	mod->arch.virt_plt_tbl = NULL;
++
++	if (IS_ENABLED(CONFIG_64BIT))
++		return 0;
++
++	for (i = 1; i < hdr->e_shnum; i++)
++		if (sechdrs[i].sh_type == SHT_SYMTAB)
++			symindex = i;
++
++	core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
++	init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
++
++	if ((core_size + init_size) == 0)
++		return 0;
++
++	mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
++	if (!mod->arch.phys_plt_tbl)
++		return -ENOMEM;
++
++	mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
++	if (!mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++		return -ENOMEM;
++	}
++
++	return 0;
++}
+ 
+ int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
+ {
+@@ -64,8 +272,39 @@ static int apply_r_mips_32_rel(struct mo
+ 	return 0;
+ }
+ 
++static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
++				 void *start, Elf_Addr v)
++{
++	unsigned *tramp = start + *plt_offset;
++	*plt_offset += 4 * sizeof(int);
++
++	/* adjust carry for addiu */
++	if (v & 0x00008000)
++		v += 0x10000;
++
++	tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
++	tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
++	tramp[2] = 0x03200008;                  /* jr t9 */
++	tramp[3] = 0x00000000;                  /* nop */
++
++	return (Elf_Addr) tramp;
++}
++
++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
++{
++	if (is_phys_addr(location))
++		return add_plt_entry_to(&me->arch.phys_plt_offset,
++				me->arch.phys_plt_tbl, v);
++	else
++		return add_plt_entry_to(&me->arch.virt_plt_offset,
++				me->arch.virt_plt_tbl, v);
++
++}
++
+ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
+ {
++	u32 ofs = *location & 0x03ffffff;
++
+ 	if (v % 4) {
+ 		pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
+ 		       me->name);
+@@ -73,14 +312,17 @@ static int apply_r_mips_26_rel(struct mo
+ 	}
+ 
+ 	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
+-		printk(KERN_ERR
+-		       "module %s: relocation overflow\n",
+-		       me->name);
+-		return -ENOEXEC;
++		v = add_plt_entry(me, location, v + (ofs << 2));
++		if (!v) {
++			printk(KERN_ERR
++				"module %s: relocation overflow\n", me->name);
++			return -ENOEXEC;
++		}
++		ofs = 0;
+ 	}
+ 
+ 	*location = (*location & ~0x03ffffff) |
+-		    ((*location + (v >> 2)) & 0x03ffffff);
++		    ((ofs + (v >> 2)) & 0x03ffffff);
+ 
+ 	return 0;
+ }
+@@ -287,9 +529,33 @@ int module_finalize(const Elf_Ehdr *hdr,
+ 		list_add(&me->arch.dbe_list, &dbe_list);
+ 		spin_unlock_irq(&dbe_lock);
+ 	}
++
++	/* Get rid of the fixup trampoline if we're running the module
++	 * from physically mapped address space */
++	if (me->arch.phys_plt_offset == 0) {
++		__module_free(me->arch.phys_plt_tbl);
++		me->arch.phys_plt_tbl = NULL;
++	}
++	if (me->arch.virt_plt_offset == 0) {
++		__module_free(me->arch.virt_plt_tbl);
++		me->arch.virt_plt_tbl = NULL;
++	}
++
+ 	return 0;
+ }
+ 
++void module_arch_freeing_init(struct module *mod)
++{
++	if (mod->arch.phys_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++	}
++	if (mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.virt_plt_tbl);
++		mod->arch.virt_plt_tbl = NULL;
++	}
++}
++
+ void module_arch_cleanup(struct module *mod)
+ {
+ 	spin_lock_irq(&dbe_lock);
diff --git a/target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch b/target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch
new file mode 100644
index 0000000000..9818677425
--- /dev/null
+++ b/target/linux/generic/patches-3.18/306-mips_mem_functions_performance.patch
@@ -0,0 +1,83 @@
+--- a/arch/mips/include/asm/string.h
++++ b/arch/mips/include/asm/string.h
+@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__
+ 
+ #define __HAVE_ARCH_MEMSET
+ extern void *memset(void *__s, int __c, size_t __count);
++#define memset(__s, __c, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memset((__s), (__c), __len);		\
++	else							\
++		__ret = __builtin_memset((__s), (__c), __len);	\
++	__ret;							\
++})
+ 
+ #define __HAVE_ARCH_MEMCPY
+ extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
++#define memcpy(dst, src, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memcpy((dst), (src), __len);		\
++	else							\
++		__ret = __builtin_memcpy((dst), (src), __len);	\
++	__ret;							\
++})
+ 
+ #define __HAVE_ARCH_MEMMOVE
+ extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
++#define memmove(dst, src, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memmove((dst), (src), __len);		\
++	else							\
++		__ret = __builtin_memmove((dst), (src), __len);	\
++	__ret;							\
++})
++
++#define __HAVE_ARCH_MEMCMP
++#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len))
+ 
+ #endif /* _ASM_STRING_H */
+--- a/arch/mips/lib/Makefile
++++ b/arch/mips/lib/Makefile
+@@ -4,7 +4,7 @@
+ 
+ lib-y	+= bitops.o csum_partial.o delay.o memcpy.o memset.o \
+ 	   mips-atomic.o strlen_user.o strncpy_user.o \
+-	   strnlen_user.o uncached.o
++	   strnlen_user.o uncached.o memcmp.o
+ 
+ obj-y			+= iomap.o
+ obj-$(CONFIG_PCI)	+= iomap-pci.o
+--- /dev/null
++++ b/arch/mips/lib/memcmp.c
+@@ -0,0 +1,22 @@
++/*
++ *  copied from linux/lib/string.c
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++
++#undef memcmp
++int memcmp(const void *cs, const void *ct, size_t count)
++{
++	const unsigned char *su1, *su2;
++	int res = 0;
++
++	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
++		if ((res = *su1 - *su2) != 0)
++			break;
++	return res;
++}
++EXPORT_SYMBOL(memcmp);
++
diff --git a/target/linux/generic/patches-3.18/307-mips_highmem_offset.patch b/target/linux/generic/patches-3.18/307-mips_highmem_offset.patch
new file mode 100644
index 0000000000..5a7dc9cee9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/307-mips_highmem_offset.patch
@@ -0,0 +1,17 @@
+Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations
+stay within the same 256M boundary. This ensures that -mlong-calls is not
+needed on systems with more than 256M RAM.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/arch/mips/include/asm/mach-generic/spaces.h
++++ b/arch/mips/include/asm/mach-generic/spaces.h
+@@ -44,7 +44,7 @@
+  * Memory above this physical address will be considered highmem.
+  */
+ #ifndef HIGHMEM_START
+-#define HIGHMEM_START		_AC(0x20000000, UL)
++#define HIGHMEM_START		_AC(0x10000000, UL)
+ #endif
+ 
+ #endif /* CONFIG_32BIT */
diff --git a/target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch
new file mode 100644
index 0000000000..9210c1d2d3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/310-arm_module_unresolved_weak_sym.patch
@@ -0,0 +1,13 @@
+--- a/arch/arm/kernel/module.c
++++ b/arch/arm/kernel/module.c
+@@ -83,6 +83,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
+ 			return -ENOEXEC;
+ 		}
+ 
++		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
++		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
++			continue;
++
+ 		loc = dstsec->sh_addr + rel->r_offset;
+ 
+ 		switch (ELF32_R_TYPE(rel->r_info)) {
diff --git a/target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch b/target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch
new file mode 100644
index 0000000000..8673de4df2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/320-ppc4xx_optimization.patch
@@ -0,0 +1,31 @@
+Upstream doesn't optimize the kernel and bootwrappers for ppc44x because
+they still want to support gcc 3.3 -- well, we don't.
+
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -203,7 +203,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ KBUILD_CFLAGS		+= -mno-sched-epilog
+ endif
+ 
+-cpu-as-$(CONFIG_4xx)		+= -Wa,-m405
++cpu-as-$(CONFIG_40x)		+= -Wa,-m405
++cpu-as-$(CONFIG_44x)		+= -Wa,-m440
+ cpu-as-$(CONFIG_ALTIVEC)	+= -Wa,-maltivec
+ cpu-as-$(CONFIG_E200)		+= -Wa,-me200
+ 
+--- a/arch/powerpc/boot/Makefile
++++ b/arch/powerpc/boot/Makefile
+@@ -45,10 +45,10 @@ BOOTCFLAGS	+= -I$(obj) -I$(srctree)/$(ob
+ DTC_FLAGS	?= -p 1024
+ 
+ $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
++$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
+ $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
++$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440
++$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440
+ $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
+ $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
+ $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405
diff --git a/target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch
new file mode 100644
index 0000000000..ab6ea7beb2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/321-powerpc_crtsavres_prereq.patch
@@ -0,0 +1,10 @@
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -165,7 +165,6 @@ CPP		= $(CC) -E $(KBUILD_CFLAGS)
+ 
+ CHECKFLAGS	+= -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
+ 
+-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+ 
+ ifeq ($(CONFIG_476FPE_ERR46),y)
+ 	KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
diff --git a/target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
new file mode 100644
index 0000000000..a69d197e62
--- /dev/null
+++ b/target/linux/generic/patches-3.18/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
@@ -0,0 +1,298 @@
+From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Sat, 31 Jan 2015 22:26:03 +0800
+Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from
+ userspace.
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ arch/mips/kernel/machine_kexec.c   |  153 +++++++++++++++++++++++++++++++-----
+ arch/mips/kernel/machine_kexec.h   |   20 +++++
+ arch/mips/kernel/relocate_kernel.S |   21 +++--
+ 3 files changed, 167 insertions(+), 27 deletions(-)
+ create mode 100644 arch/mips/kernel/machine_kexec.h
+
+--- a/arch/mips/kernel/machine_kexec.c
++++ b/arch/mips/kernel/machine_kexec.c
+@@ -10,45 +10,145 @@
+ #include <linux/mm.h>
+ #include <linux/delay.h>
+ 
++#include <asm/bootinfo.h>
+ #include <asm/cacheflush.h>
+ #include <asm/page.h>
+-
+-extern const unsigned char relocate_new_kernel[];
+-extern const size_t relocate_new_kernel_size;
+-
+-extern unsigned long kexec_start_address;
+-extern unsigned long kexec_indirection_page;
++#include <asm/uaccess.h>
++#include "machine_kexec.h"
+ 
+ int (*_machine_kexec_prepare)(struct kimage *) = NULL;
+ void (*_machine_kexec_shutdown)(void) = NULL;
+ void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
++
+ #ifdef CONFIG_SMP
+ void (*relocated_kexec_smp_wait) (void *);
+ atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
+ #endif
+ 
+-int
+-machine_kexec_prepare(struct kimage *kimage)
++static void machine_kexec_print_args(void)
+ {
++	unsigned long argc = (int)kexec_args[0];
++	int i;
++
++	pr_info("kexec_args[0] (argc): %lu\n", argc);
++	pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
++	pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
++	pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
++
++	for (i = 0; i < argc; i++) {
++		pr_info("kexec_argv[%d] = %p, %s\n",
++				i, kexec_argv[i], kexec_argv[i]);
++	}
++}
++
++static void machine_kexec_init_argv(struct kimage *image)
++{
++	void __user *buf = NULL;
++	size_t bufsz;
++	size_t size;
++	int i;
++
++	bufsz = 0;
++	for (i = 0; i < image->nr_segments; i++) {
++		struct kexec_segment *seg;
++
++		seg = &image->segment[i];
++		if (seg->bufsz < 6)
++			continue;
++
++		if (strncmp((char *) seg->buf, "kexec ", 6))
++			continue;
++
++		buf = seg->buf;
++		bufsz = seg->bufsz;
++		break;
++	}
++
++	if (!buf)
++		return;
++
++	size = KEXEC_COMMAND_LINE_SIZE;
++	size = min(size, bufsz);
++	if (size < bufsz)
++		pr_warn("kexec command line truncated to %zd bytes\n", size);
++
++	/* Copy to kernel space */
++	copy_from_user(kexec_argv_buf, buf, size);
++	kexec_argv_buf[size - 1] = 0;
++}
++
++static void machine_kexec_parse_argv(struct kimage *image)
++{
++	char *reboot_code_buffer;
++	int reloc_delta;
++	char *ptr;
++	int argc;
++	int i;
++
++	ptr = kexec_argv_buf;
++	argc = 0;
++
++	/*
++	 * convert command line string to array of parameters
++	 * (as bootloader does).
++	 */
++	while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
++		if (*ptr == ' ') {
++			*ptr++ = '\0';
++			continue;
++		}
++
++		kexec_argv[argc++] = ptr;
++		ptr = strchr(ptr, ' ');
++	}
++
++	if (!argc)
++		return;
++
++	kexec_args[0] = argc;
++	kexec_args[1] = (unsigned long)kexec_argv;
++	kexec_args[2] = 0;
++	kexec_args[3] = 0;
++
++	reboot_code_buffer = page_address(image->control_code_page);
++	reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
++
++	kexec_args[1] += reloc_delta;
++	for (i = 0; i < argc; i++)
++		kexec_argv[i] += reloc_delta;
++}
++
++int machine_kexec_prepare(struct kimage *kimage)
++{
++	/*
++	 * Whenever arguments passed from kexec-tools, Init the arguments as
++	 * the original ones to try avoiding booting failure.
++	 */
++
++	kexec_args[0] = fw_arg0;
++	kexec_args[1] = fw_arg1;
++	kexec_args[2] = fw_arg2;
++	kexec_args[3] = fw_arg3;
++
++	machine_kexec_init_argv(kimage);
++	machine_kexec_parse_argv(kimage);
++
+ 	if (_machine_kexec_prepare)
+ 		return _machine_kexec_prepare(kimage);
+ 	return 0;
+ }
+ 
+-void
+-machine_kexec_cleanup(struct kimage *kimage)
++void machine_kexec_cleanup(struct kimage *kimage)
+ {
+ }
+ 
+-void
+-machine_shutdown(void)
++void machine_shutdown(void)
+ {
+ 	if (_machine_kexec_shutdown)
+ 		_machine_kexec_shutdown();
+ }
+ 
+-void
+-machine_crash_shutdown(struct pt_regs *regs)
++void machine_crash_shutdown(struct pt_regs *regs)
+ {
+ 	if (_machine_crash_shutdown)
+ 		_machine_crash_shutdown(regs);
+@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image)
+ 	unsigned long *ptr;
+ 
+ 	reboot_code_buffer =
+-	  (unsigned long)page_address(image->control_code_page);
++		(unsigned long)page_address(image->control_code_page);
++	pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
+ 
+ 	kexec_start_address =
+ 		(unsigned long) phys_to_virt(image->start);
++	pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
+ 
+ 	if (image->type == KEXEC_TYPE_DEFAULT) {
+ 		kexec_indirection_page =
+@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image)
+ 	} else {
+ 		kexec_indirection_page = (unsigned long)&image->head;
+ 	}
++	pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
+ 
+-	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
+-	       relocate_new_kernel_size);
++	pr_info("Where is memcpy: %p\n", memcpy);
++	pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
++		(void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
++	pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
++		(void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
++	memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
++	       KEXEC_RELOCATE_NEW_KERNEL_SIZE);
++
++	pr_info("Before _print_args().\n");
++	machine_kexec_print_args();
++	pr_info("Before eval loop.\n");
+ 
+ 	/*
+ 	 * The generic kexec code builds a page list with physical
+@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image)
+ 	/*
+ 	 * we do not want to be bothered.
+ 	 */
++	pr_info("Before irq_disable.\n");
+ 	local_irq_disable();
+ 
+-	printk("Will call new kernel at %08lx\n", image->start);
+-	printk("Bye ...\n");
++	pr_info("Will call new kernel at %08lx\n", image->start);
++	pr_info("Bye ...\n");
+ 	__flush_cache_all();
+ #ifdef CONFIG_SMP
+ 	/* All secondary cpus now may jump to kexec_wait cycle */
+ 	relocated_kexec_smp_wait = reboot_code_buffer +
+-		(void *)(kexec_smp_wait - relocate_new_kernel);
++		(void *)(kexec_smp_wait - kexec_relocate_new_kernel);
+ 	smp_wmb();
+ 	atomic_set(&kexec_ready_to_reboot, 1);
+ #endif
+--- /dev/null
++++ b/arch/mips/kernel/machine_kexec.h
+@@ -0,0 +1,20 @@
++#ifndef _MACHINE_KEXEC_H
++#define _MACHINE_KEXEC_H
++
++#ifndef __ASSEMBLY__
++extern const unsigned char kexec_relocate_new_kernel[];
++extern unsigned long kexec_relocate_new_kernel_end;
++extern unsigned long kexec_start_address;
++extern unsigned long kexec_indirection_page;
++
++extern char kexec_argv_buf[];
++extern char *kexec_argv[];
++
++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE	((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
++#endif /* !__ASSEMBLY__ */
++
++#define KEXEC_COMMAND_LINE_SIZE		256
++#define KEXEC_ARGV_SIZE			(KEXEC_COMMAND_LINE_SIZE / 16)
++#define KEXEC_MAX_ARGC			(KEXEC_ARGV_SIZE / sizeof(long))
++
++#endif
+--- a/arch/mips/kernel/relocate_kernel.S
++++ b/arch/mips/kernel/relocate_kernel.S
+@@ -12,8 +12,9 @@
+ #include <asm/mipsregs.h>
+ #include <asm/stackframe.h>
+ #include <asm/addrspace.h>
++#include "machine_kexec.h"
+ 
+-LEAF(relocate_new_kernel)
++LEAF(kexec_relocate_new_kernel)
+ 	PTR_L a0,	arg0
+ 	PTR_L a1,	arg1
+ 	PTR_L a2,	arg2
+@@ -98,7 +99,7 @@ done:
+ #endif
+ 	/* jump to kexec_start_address */
+ 	j		s1
+-	END(relocate_new_kernel)
++	END(kexec_relocate_new_kernel)
+ 
+ #ifdef CONFIG_SMP
+ /*
+@@ -184,9 +185,15 @@ kexec_indirection_page:
+ 	PTR		0
+ 	.size		kexec_indirection_page, PTRSIZE
+ 
+-relocate_new_kernel_end:
++kexec_argv_buf:
++	EXPORT(kexec_argv_buf)
++	.skip		KEXEC_COMMAND_LINE_SIZE
++	.size		kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
++
++kexec_argv:
++	EXPORT(kexec_argv)
++	.skip		KEXEC_ARGV_SIZE
++	.size		kexec_argv, KEXEC_ARGV_SIZE
+ 
+-relocate_new_kernel_size:
+-	EXPORT(relocate_new_kernel_size)
+-	PTR		relocate_new_kernel_end - relocate_new_kernel
+-	.size		relocate_new_kernel_size, PTRSIZE
++kexec_relocate_new_kernel_end:
++	EXPORT(kexec_relocate_new_kernel_end)
diff --git a/target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch b/target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch
new file mode 100644
index 0000000000..0a6e134ed5
--- /dev/null
+++ b/target/linux/generic/patches-3.18/400-mtd-add-rootfs-split-support.patch
@@ -0,0 +1,171 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -12,6 +12,23 @@ menuconfig MTD
+ 
+ if MTD
+ 
++menu "OpenWrt specific MTD options"
++
++config MTD_ROOTFS_ROOT_DEV
++	bool "Automatically set 'rootfs' partition to be root filesystem"
++	default y
++
++config MTD_SPLIT_FIRMWARE
++	bool "Automatically split firmware partition for kernel+rootfs"
++	default y
++
++config MTD_SPLIT_FIRMWARE_NAME
++	string "Firmware partition name"
++	depends on MTD_SPLIT_FIRMWARE
++	default "firmware"
++
++endmenu
++
+ config MTD_TESTS
+ 	tristate "MTD tests support (DANGEROUS)"
+ 	depends on m
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -30,9 +30,11 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/of.h>
++#include <linux/magic.h>
+ #include <linux/err.h>
+ 
+ #include "mtdcore.h"
++#include "mtdsplit/mtdsplit.h"
+ 
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+@@ -46,13 +48,14 @@ struct mtd_part {
+ 	struct list_head list;
+ };
+ 
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
++
+ /*
+  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+  * the pointer to that structure with this macro.
+  */
+ #define PART(x)  ((struct mtd_part *)(x))
+ 
+-
+ /*
+  * MTD methods which simply translate the effective address and pass through
+  * to the _real_ device.
+@@ -548,8 +551,10 @@ out_register:
+ 	return slave;
+ }
+ 
+-int mtd_add_partition(struct mtd_info *master, const char *name,
+-		      long long offset, long long length)
++
++static int
++__mtd_add_partition(struct mtd_info *master, const char *name,
++		    long long offset, long long length, bool dup_check)
+ {
+ 	struct mtd_partition part;
+ 	struct mtd_part *p, *new;
+@@ -581,21 +586,24 @@ int mtd_add_partition(struct mtd_info *m
+ 	end = offset + length;
+ 
+ 	mutex_lock(&mtd_partitions_mutex);
+-	list_for_each_entry(p, &mtd_partitions, list)
+-		if (p->master == master) {
+-			if ((start >= p->offset) &&
+-			    (start < (p->offset + p->mtd.size)))
+-				goto err_inv;
+-
+-			if ((end >= p->offset) &&
+-			    (end < (p->offset + p->mtd.size)))
+-				goto err_inv;
+-		}
++	if (dup_check) {
++		list_for_each_entry(p, &mtd_partitions, list)
++			if (p->master == master) {
++				if ((start >= p->offset) &&
++				    (start < (p->offset + p->mtd.size)))
++					goto err_inv;
++
++				if ((end >= p->offset) &&
++				    (end < (p->offset + p->mtd.size)))
++					goto err_inv;
++			}
++	}
+ 
+ 	list_add(&new->list, &mtd_partitions);
+ 	mutex_unlock(&mtd_partitions_mutex);
+ 
+ 	add_mtd_device(&new->mtd);
++	mtd_partition_split(master, new);
+ 
+ 	return ret;
+ err_inv:
+@@ -605,6 +613,12 @@ err_inv:
+ }
+ EXPORT_SYMBOL_GPL(mtd_add_partition);
+ 
++int mtd_add_partition(struct mtd_info *master, const char *name,
++		      long long offset, long long length)
++{
++	return __mtd_add_partition(master, name, offset, length, true);
++}
++
+ int mtd_del_partition(struct mtd_info *master, int partno)
+ {
+ 	struct mtd_part *slave, *next;
+@@ -628,6 +642,35 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#else
++#define SPLIT_FIRMWARE_NAME	"unused"
++#endif
++
++static void split_firmware(struct mtd_info *master, struct mtd_part *part)
++{
++}
++
++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
++                                int offset, int size)
++{
++}
++
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
++{
++	static int rootfs_found = 0;
++
++	if (rootfs_found)
++		return;
++
++	if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
++	    config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
++		split_firmware(master, part);
++
++	arch_split_mtd_part(master, part->mtd.name, part->offset,
++			    part->mtd.size);
++}
+ /*
+  * This function, given a master MTD object and a partition table, creates
+  * and registers slave MTD objects which are bound to the master according to
+@@ -657,6 +700,7 @@ int add_mtd_partitions(struct mtd_info *
+ 		mutex_unlock(&mtd_partitions_mutex);
+ 
+ 		add_mtd_device(&slave->mtd);
++		mtd_partition_split(master, slave);
+ 
+ 		cur_offset = slave->offset + slave->mtd.size;
+ 	}
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
++extern void __weak arch_split_mtd_part(struct mtd_info *master,
++				       const char *name, int offset, int size);
+ 
+ #endif
diff --git a/target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch b/target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch
new file mode 100644
index 0000000000..684234161a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/401-mtd-add-support-for-different-partition-parser-types.patch
@@ -0,0 +1,113 @@
+From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Tue, 3 Sep 2013 18:11:50 +0200
+Subject: [PATCH] mtd: add support for different partition parser types
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdpart.c          |   56 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/partitions.h |   11 ++++++++
+ 2 files changed, 67 insertions(+)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -730,6 +730,30 @@ static struct mtd_part_parser *get_parti
+ 
+ #define put_partition_parser(p) do { module_put((p)->owner); } while (0)
+ 
++static struct mtd_part_parser *
++get_partition_parser_by_type(enum mtd_parser_type type,
++			     struct mtd_part_parser *start)
++{
++	struct mtd_part_parser *p, *ret = NULL;
++
++	spin_lock(&part_parser_lock);
++
++	p = list_prepare_entry(start, &part_parsers, list);
++	if (start)
++		put_partition_parser(start);
++
++	list_for_each_entry_continue(p, &part_parsers, list) {
++		if (p->type == type && try_module_get(p->owner)) {
++			ret = p;
++			break;
++		}
++	}
++
++	spin_unlock(&part_parser_lock);
++
++	return ret;
++}
++
+ void register_mtd_parser(struct mtd_part_parser *p)
+ {
+ 	spin_lock(&part_parser_lock);
+@@ -845,6 +869,38 @@ int parse_mtd_partitions(struct mtd_info
+ 	return ret;
+ }
+ 
++int parse_mtd_partitions_by_type(struct mtd_info *master,
++				 enum mtd_parser_type type,
++				 struct mtd_partition **pparts,
++				 struct mtd_part_parser_data *data)
++{
++	struct mtd_part_parser *prev = NULL;
++	int ret = 0;
++
++	while (1) {
++		struct mtd_part_parser *parser;
++
++		parser = get_partition_parser_by_type(type, prev);
++		if (!parser)
++			break;
++
++		ret = (*parser->parse_fn)(master, pparts, data);
++
++		if (ret > 0) {
++			put_partition_parser(parser);
++			printk(KERN_NOTICE
++			       "%d %s partitions found on MTD device %s\n",
++			       ret, parser->name, master->name);
++			break;
++		}
++
++		prev = parser;
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
++
+ int mtd_is_partition(const struct mtd_info *mtd)
+ {
+ 	struct mtd_part *part;
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -68,12 +68,17 @@ struct mtd_part_parser_data {
+  * Functions dealing with the various ways of partitioning the space
+  */
+ 
++enum mtd_parser_type {
++	MTD_PARSER_TYPE_DEVICE = 0,
++};
++
+ struct mtd_part_parser {
+ 	struct list_head list;
+ 	struct module *owner;
+ 	const char *name;
+ 	int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
+ 			struct mtd_part_parser_data *);
++	enum mtd_parser_type type;
+ };
+ 
+ extern void register_mtd_parser(struct mtd_part_parser *parser);
+@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc
+ extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ 				       const char *name, int offset, int size);
+ 
++int parse_mtd_partitions_by_type(struct mtd_info *master,
++				 enum mtd_parser_type type,
++				 struct mtd_partition **pparts,
++				 struct mtd_part_parser_data *data);
++
+ #endif
diff --git a/target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
new file mode 100644
index 0000000000..dead0fbf5f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
@@ -0,0 +1,72 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -642,6 +642,37 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++static int
++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
++{
++	struct mtd_partition *parts;
++	int nr_parts;
++	int i;
++
++	nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts,
++						NULL);
++	if (nr_parts <= 0)
++		return nr_parts;
++
++	if (WARN_ON(!parts))
++		return 0;
++
++	for (i = 0; i < nr_parts; i++) {
++		/* adjust partition offsets */
++		parts[i].offset += slave->offset;
++
++		__mtd_add_partition(slave->master,
++				    parts[i].name,
++				    parts[i].offset,
++				    parts[i].size,
++				    false);
++	}
++
++	kfree(parts);
++
++	return nr_parts;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -650,6 +681,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
+ static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+ {
++	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+ }
+ 
+ void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
+@@ -664,6 +696,12 @@ static void mtd_partition_split(struct m
+ 	if (rootfs_found)
+ 		return;
+ 
++	if (!strcmp(part->mtd.name, "rootfs")) {
++		run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++
++		rootfs_found = 1;
++	}
++
+ 	if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
+ 	    config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
+ 		split_firmware(master, part);
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -70,6 +70,8 @@ struct mtd_part_parser_data {
+ 
+ enum mtd_parser_type {
+ 	MTD_PARSER_TYPE_DEVICE = 0,
++	MTD_PARSER_TYPE_ROOTFS,
++	MTD_PARSER_TYPE_FIRMWARE,
+ };
+ 
+ struct mtd_part_parser {
diff --git a/target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch b/target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch
new file mode 100644
index 0000000000..0cf1c38555
--- /dev/null
+++ b/target/linux/generic/patches-3.18/403-mtd-hook-mtdsplit-to-Kbuild.patch
@@ -0,0 +1,22 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
+ 	depends on MTD_SPLIT_FIRMWARE
+ 	default "firmware"
+ 
++source "drivers/mtd/mtdsplit/Kconfig"
++
+ endmenu
+ 
+ config MTD_TESTS
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -6,6 +6,8 @@
+ obj-$(CONFIG_MTD)		+= mtd.o
+ mtd-y				:= mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
+ 
++obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit/
++
+ obj-$(CONFIG_MTD_OF_PARTS)	+= ofpart.o
+ obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
diff --git a/target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch b/target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch
new file mode 100644
index 0000000000..b2f62c115d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/404-mtd-add-more-helper-functions.patch
@@ -0,0 +1,101 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -446,14 +446,12 @@ static struct mtd_part *allocate_partiti
+ 	if (slave->offset == MTDPART_OFS_APPEND)
+ 		slave->offset = cur_offset;
+ 	if (slave->offset == MTDPART_OFS_NXTBLK) {
+-		slave->offset = cur_offset;
+-		if (mtd_mod_by_eb(cur_offset, master) != 0) {
+-			/* Round up to next erasesize */
+-			slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
++		/* Round up to next erasesize */
++		slave->offset = mtd_roundup_to_eb(cur_offset, master);
++		if (slave->offset != cur_offset)
+ 			printk(KERN_NOTICE "Moving partition %d: "
+ 			       "0x%012llx -> 0x%012llx\n", partno,
+ 			       (unsigned long long)cur_offset, (unsigned long long)slave->offset);
+-		}
+ 	}
+ 	if (slave->offset == MTDPART_OFS_RETAIN) {
+ 		slave->offset = cur_offset;
+@@ -673,6 +671,17 @@ run_parsers_by_type(struct mtd_part *sla
+ 	return nr_parts;
+ }
+ 
++static inline unsigned long
++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
++{
++	unsigned long mask = mtd->erasesize - 1;
++
++	len += offset & mask;
++	len = (len + mask) & ~mask;
++	len -= offset & mask;
++	return len;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -956,6 +965,24 @@ int mtd_is_partition(const struct mtd_in
+ }
+ EXPORT_SYMBOL_GPL(mtd_is_partition);
+ 
++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return (struct mtd_info *)mtd;
++
++	return PART(mtd)->master;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_master);
++
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return 0;
++
++	return PART(mtd)->offset;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_offset);
++
+ /* Returns the size of the entire flash chip */
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd)
+ {
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in
+ int mtd_add_partition(struct mtd_info *master, const char *name,
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
+ extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ 				       const char *name, int offset, int size);
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -333,6 +333,24 @@ static inline uint32_t mtd_mod_by_eb(uin
+ 	return do_div(sz, mtd->erasesize);
+ }
+ 
++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round up to next erase block */
++	return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
++}
++
++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round down to the start of the current erase block */
++	return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
++}
++
+ static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
+ {
+ 	if (mtd->writesize_shift)
diff --git a/target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch b/target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch
new file mode 100644
index 0000000000..7e74c4e538
--- /dev/null
+++ b/target/linux/generic/patches-3.18/405-mtd-old-firmware-uimage-splitter.patch
@@ -0,0 +1,70 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME
+ 	depends on MTD_SPLIT_FIRMWARE
+ 	default "firmware"
+ 
++config MTD_UIMAGE_SPLIT
++	bool "Enable split support for firmware partitions containing a uImage"
++	depends on MTD_SPLIT_FIRMWARE
++	default y
++
+ source "drivers/mtd/mtdsplit/Kconfig"
+ 
+ endmenu
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -682,6 +682,37 @@ mtd_pad_erasesize(struct mtd_info *mtd,
+ 	return len;
+ }
+ 
++#define UBOOT_MAGIC	0x27051956
++
++static void split_uimage(struct mtd_info *master, struct mtd_part *part)
++{
++	struct {
++		__be32 magic;
++		__be32 pad[2];
++		__be32 size;
++	} hdr;
++	size_t len;
++
++	if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr))
++		return;
++
++	if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC))
++		return;
++
++	len = be32_to_cpu(hdr.size) + 0x40;
++	len = mtd_pad_erasesize(master, part->offset, len);
++	if (len + master->erasesize > part->mtd.size)
++		return;
++
++	if (config_enabled(CONFIG_MTD_SPLIT_UIMAGE_FW))
++		pr_err("Dedicated partitioner didn't split firmware partition, please fill a bug report!\n");
++	else
++		pr_warn("Support for built-in firmware splitter will be removed, please use CONFIG_MTD_SPLIT_UIMAGE_FW\n");
++
++	__mtd_add_partition(master, "rootfs", part->offset + len,
++			    part->mtd.size - len, false);
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -690,7 +721,14 @@ mtd_pad_erasesize(struct mtd_info *mtd,
+ 
+ static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+ {
+-	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
++	int ret;
++
++	ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
++	if (ret > 0)
++		return;
++
++	if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT))
++		split_uimage(master, part);
+ }
+ 
+ void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
diff --git a/target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch b/target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch
new file mode 100644
index 0000000000..cc548efb60
--- /dev/null
+++ b/target/linux/generic/patches-3.18/406-mtd-old-rootfs-squashfs-splitter.patch
@@ -0,0 +1,76 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -18,6 +18,11 @@ config MTD_ROOTFS_ROOT_DEV
+ 	bool "Automatically set 'rootfs' partition to be root filesystem"
+ 	default y
+ 
++config MTD_ROOTFS_SPLIT
++	bool "Automatically split 'rootfs' partition for squashfs"
++	select MTD_SPLIT
++	default y
++
+ config MTD_SPLIT_FIRMWARE
+ 	bool "Automatically split firmware partition for kernel+rootfs"
+ 	default y
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -682,6 +682,47 @@ mtd_pad_erasesize(struct mtd_info *mtd,
+ 	return len;
+ }
+ 
++static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
++{
++	size_t squashfs_len;
++	int len, ret;
++
++	ret = mtd_get_squashfs_len(master, offset, &squashfs_len);
++	if (ret)
++		return ret;
++
++	len = mtd_pad_erasesize(master, offset, squashfs_len);
++	*split_offset = offset + len;
++
++	return 0;
++}
++
++static void split_rootfs_data(struct mtd_info *master, struct mtd_part *part)
++{
++	unsigned int split_offset = 0;
++	unsigned int split_size;
++	int ret;
++
++	ret = split_squashfs(master, part->offset, &split_offset);
++	if (ret)
++		return;
++
++	if (split_offset <= 0)
++		return;
++
++	if (config_enabled(CONFIG_MTD_SPLIT_SQUASHFS_ROOT))
++		pr_err("Dedicated partitioner didn't create \"rootfs_data\" partition, please fill a bug report!\n");
++	else
++		pr_warn("Support for built-in \"rootfs_data\" splitter will be removed, please use CONFIG_MTD_SPLIT_SQUASHFS_ROOT\n");
++
++	split_size = part->mtd.size - (split_offset - part->offset);
++	printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=0x%x, len=0x%x\n",
++		ROOTFS_SPLIT_NAME, split_offset, split_size);
++
++	__mtd_add_partition(master, ROOTFS_SPLIT_NAME, split_offset,
++			    split_size, false);
++}
++
+ #define UBOOT_MAGIC	0x27051956
+ 
+ static void split_uimage(struct mtd_info *master, struct mtd_part *part)
+@@ -744,7 +785,10 @@ static void mtd_partition_split(struct m
+ 		return;
+ 
+ 	if (!strcmp(part->mtd.name, "rootfs")) {
+-		run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++		int num = run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++
++		if (num <= 0 && config_enabled(CONFIG_MTD_ROOTFS_SPLIT))
++			split_rootfs_data(master, part);
+ 
+ 		rootfs_found = 1;
+ 	}
diff --git a/target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch b/target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
new file mode 100644
index 0000000000..78ebbf88ca
--- /dev/null
+++ b/target/linux/generic/patches-3.18/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
@@ -0,0 +1,18 @@
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -35,6 +35,7 @@
+  * Note: writeable partitions require their size and offset be
+  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
+  */
++struct mtd_info;
+ 
+ struct mtd_partition {
+ 	const char *name;		/* identifier string */
+@@ -50,7 +51,6 @@ struct mtd_partition {
+ #define MTDPART_SIZ_FULL	(0)
+ 
+ 
+-struct mtd_info;
+ struct device_node;
+ 
+ /**
diff --git a/target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch b/target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch
new file mode 100644
index 0000000000..5d5c6ed5d3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/411-mtd-partial_eraseblock_write.patch
@@ -0,0 +1,142 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -36,6 +36,8 @@
+ #include "mtdcore.h"
+ #include "mtdsplit/mtdsplit.h"
+ 
++#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
++
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+ static DEFINE_MUTEX(mtd_partitions_mutex);
+@@ -234,13 +236,61 @@ static int part_erase(struct mtd_info *m
+ 	struct mtd_part *part = PART(mtd);
+ 	int ret;
+ 
++
++	instr->partial_start = false;
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		size_t readlen = 0;
++		u64 mtd_ofs;
++
++		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
++		if (!instr->erase_buf)
++			return -ENOMEM;
++
++		mtd_ofs = part->offset + instr->addr;
++		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
++
++		if (instr->erase_buf_ofs > 0) {
++			instr->addr -= instr->erase_buf_ofs;
++			ret = mtd_read(part->master,
++				instr->addr + part->offset,
++				part->master->erasesize,
++				&readlen, instr->erase_buf);
++
++			instr->len += instr->erase_buf_ofs;
++			instr->partial_start = true;
++		} else {
++			mtd_ofs = part->offset + part->mtd.size;
++			instr->erase_buf_ofs = part->master->erasesize -
++				do_div(mtd_ofs, part->master->erasesize);
++
++			if (instr->erase_buf_ofs > 0) {
++				instr->len += instr->erase_buf_ofs;
++				ret = mtd_read(part->master,
++					part->offset + instr->addr +
++					instr->len - part->master->erasesize,
++					part->master->erasesize, &readlen,
++					instr->erase_buf);
++			} else {
++				ret = 0;
++			}
++		}
++		if (ret < 0) {
++			kfree(instr->erase_buf);
++			return ret;
++		}
++
++	}
++
+ 	instr->addr += part->offset;
+ 	ret = part->master->_erase(part->master, instr);
+ 	if (ret) {
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+ 		instr->addr -= part->offset;
++		if (mtd->flags & MTD_ERASE_PARTIAL)
++			kfree(instr->erase_buf);
+ 	}
++
+ 	return ret;
+ }
+ 
+@@ -248,7 +298,25 @@ void mtd_erase_callback(struct erase_inf
+ {
+ 	if (instr->mtd->_erase == part_erase) {
+ 		struct mtd_part *part = PART(instr->mtd);
++		size_t wrlen = 0;
+ 
++		if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
++			if (instr->partial_start) {
++				part->master->_write(part->master,
++					instr->addr, instr->erase_buf_ofs,
++					&wrlen, instr->erase_buf);
++				instr->addr += instr->erase_buf_ofs;
++			} else {
++				instr->len -= instr->erase_buf_ofs;
++				part->master->_write(part->master,
++					instr->addr + instr->len,
++					instr->erase_buf_ofs, &wrlen,
++					instr->erase_buf +
++					part->master->erasesize -
++					instr->erase_buf_ofs);
++			}
++			kfree(instr->erase_buf);
++		}
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+ 		instr->addr -= part->offset;
+@@ -515,17 +583,20 @@ static struct mtd_part *allocate_partiti
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
+ 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
+ 		/* Doesn't start on a boundary of major erase size */
+-		/* FIXME: Let it be writable if it is on a boundary of
+-		 * _minor_ erase size though */
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+-			part->name);
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++		if (((u32) slave->mtd.size) > master->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
+-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+-			part->name);
++	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++
++		if ((u32) slave->mtd.size > master->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 
+ 	slave->mtd.ecclayout = master->ecclayout;
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -55,6 +55,10 @@ struct erase_info {
+ 	u_long priv;
+ 	u_char state;
+ 	struct erase_info *next;
++
++	u8 *erase_buf;
++	u32 erase_buf_ofs;
++	bool partial_start;
+ };
+ 
+ struct mtd_erase_region_info {
diff --git a/target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch b/target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch
new file mode 100644
index 0000000000..62f9d5bad0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/412-mtd-partial_eraseblock_unlock.patch
@@ -0,0 +1,18 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -335,7 +335,14 @@ static int part_lock(struct mtd_info *mt
+ static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+ 	struct mtd_part *part = PART(mtd);
+-	return part->master->_unlock(part->master, ofs + part->offset, len);
++
++	ofs += part->offset;
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		/* round up len to next erasesize and round down offset to prev block */
++		len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
++		ofs &= ~(part->master->erasesize - 1);
++	}
++	return part->master->_unlock(part->master, ofs, len);
+ }
+ 
+ static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
diff --git a/target/linux/generic/patches-3.18/420-mtd-redboot_space.patch b/target/linux/generic/patches-3.18/420-mtd-redboot_space.patch
new file mode 100644
index 0000000000..f74affcef7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/420-mtd-redboot_space.patch
@@ -0,0 +1,30 @@
+--- a/drivers/mtd/redboot.c
++++ b/drivers/mtd/redboot.c
+@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru
+ #endif
+ 		names += strlen(names)+1;
+ 
+-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ 		if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+-			i++;
+-			parts[i].offset = parts[i-1].size + parts[i-1].offset;
+-			parts[i].size = fl->next->img->flash_base - parts[i].offset;
+-			parts[i].name = nullname;
+-		}
++			if (!strcmp(parts[i].name, "rootfs")) {
++				parts[i].size = fl->next->img->flash_base;
++				parts[i].size &= ~(master->erasesize - 1);
++				parts[i].size -= parts[i].offset;
++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
++				nrparts--;
++			} else {
++				i++;
++				parts[i].offset = parts[i-1].size + parts[i-1].offset;
++				parts[i].size = fl->next->img->flash_base - parts[i].offset;
++				parts[i].name = nullname;
+ #endif
++			}
++		}
+ 		tmp_fl = fl;
+ 		fl = fl->next;
+ 		kfree(tmp_fl);
diff --git a/target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch
new file mode 100644
index 0000000000..25e0ecd048
--- /dev/null
+++ b/target/linux/generic/patches-3.18/430-mtd-add-myloader-partition-parser.patch
@@ -0,0 +1,35 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -184,6 +184,22 @@ config MTD_BCM47XX_PARTS
+ 	  This provides partitions parser for devices based on BCM47xx
+ 	  boards.
+ 
++config MTD_MYLOADER_PARTS
++	tristate "MyLoader partition parsing"
++	depends on ADM5120 || ATH25 || ATH79
++	---help---
++	  MyLoader is a bootloader which allows the user to define partitions
++	  in flash devices, by putting a table in the second erase block
++	  on the device, similar to a partition table. This table gives the 
++	  offsets and lengths of the user defined partitions.
++
++	  If you need code which can detect and parse these tables, and
++	  register MTD 'partitions' corresponding to each image detected,
++	  enable this option.
++
++	  You will still need the parsing functions to be called by the driver
++	  for your particular device. It won't happen automatically.
++
+ comment "User Modules And Translation Layers"
+ 
+ #
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)	+= bcm47xxpart.o
++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
+ 
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS)	+= mtd_blkdevs.o
diff --git a/target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch b/target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
new file mode 100644
index 0000000000..5ad82f1f51
--- /dev/null
+++ b/target/linux/generic/patches-3.18/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
@@ -0,0 +1,100 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 2 Jan 2016 01:04:52 +0100
+Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating
+ offsets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 50 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 40 insertions(+), 10 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -61,6 +61,34 @@ static void bcm47xxpart_add_part(struct
+ 	part->mask_flags = mask_flags;
+ }
+ 
++/*
++ * Calculate real end offset (address) for a given amount of data. It checks
++ * all blocks skipping bad ones.
++ */
++static size_t bcm47xxpart_real_offset(struct mtd_info *master, size_t offset,
++				      size_t bytes)
++{
++	size_t real_offset = offset;
++
++	if (mtd_block_isbad(master, real_offset))
++		pr_warn("Base offset shouldn't be at bad block");
++
++	while (bytes >= master->erasesize) {
++		bytes -= master->erasesize;
++		real_offset += master->erasesize;
++		while (mtd_block_isbad(master, real_offset)) {
++			real_offset += master->erasesize;
++
++			if (real_offset >= master->size)
++				return real_offset - master->erasesize;
++		}
++	}
++
++	real_offset += bytes;
++
++	return real_offset;
++}
++
+ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
+ 						  size_t offset)
+ {
+@@ -182,6 +210,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
++			uint32_t tmp;
++
+ 			if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
+ 				pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
+ 				break;
+@@ -196,18 +226,18 @@ static int bcm47xxpart_parse(struct mtd_
+ 			i = 0;
+ 			/* We have LZMA loader if offset[2] points to sth */
+ 			if (trx->offset[2]) {
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "loader",
+-						     offset + trx->offset[i],
+-						     0);
++						     "loader", tmp, 0);
+ 				i++;
+ 			}
+ 
+ 			if (trx->offset[i]) {
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "linux",
+-						     offset + trx->offset[i],
+-						     0);
++						     "linux", tmp, 0);
+ 				i++;
+ 			}
+ 
+@@ -219,11 +249,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 			if (trx->offset[i]) {
+ 				const char *name;
+ 
+-				name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
++				name = bcm47xxpart_trx_data_part_name(master, tmp);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     name,
+-						     offset + trx->offset[i],
+-						     0);
++						     name, tmp, 0);
+ 				i++;
+ 			}
+ 
diff --git a/target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
new file mode 100644
index 0000000000..9e5ca91e55
--- /dev/null
+++ b/target/linux/generic/patches-3.18/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
@@ -0,0 +1,42 @@
+From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 28 Jan 2015 22:14:41 +0100
+Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It can be found on many Netgear devices. It consists of many 0x30 blocks
+starting with 4D 54.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -38,6 +38,7 @@
+ #define NVRAM_HEADER			0x48534C46	/* FLSH */
+ #define POT_MAGIC1			0x54544f50	/* POTT */
+ #define POT_MAGIC2			0x504f		/* OP */
++#define T_METER_MAGIC			0x4D540000	/* MT */
+ #define ML_MAGIC1			0x39685a42
+ #define ML_MAGIC2			0x26594131
+ #define TRX_MAGIC			0x30524448
+@@ -207,6 +208,15 @@ static int bcm47xxpart_parse(struct mtd_
+ 					     MTD_WRITEABLE);
+ 			continue;
+ 		}
++
++		/* T_Meter */
++		if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
++			bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
++					     MTD_WRITEABLE);
++			continue;
++		}
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
diff --git a/target/linux/generic/patches-3.18/440-block2mtd_init.patch b/target/linux/generic/patches-3.18/440-block2mtd_init.patch
new file mode 100644
index 0000000000..5ab60265a3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/440-block2mtd_init.patch
@@ -0,0 +1,107 @@
+--- a/drivers/mtd/devices/block2mtd.c
++++ b/drivers/mtd/devices/block2mtd.c
+@@ -17,6 +17,7 @@
+ #include <linux/list.h>
+ #include <linux/init.h>
+ #include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
+ #include <linux/mutex.h>
+ #include <linux/mount.h>
+ #include <linux/slab.h>
+@@ -209,11 +210,12 @@ static void block2mtd_free_device(struct
+ }
+ 
+ 
+-static struct block2mtd_dev *add_device(char *devname, int erase_size)
++static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
+ {
+ 	const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
+ 	struct block_device *bdev;
+ 	struct block2mtd_dev *dev;
++	struct mtd_partition *part;
+ 	char *name;
+ 
+ 	if (!devname)
+@@ -257,13 +259,16 @@ static struct block2mtd_dev *add_device(
+ 
+ 	/* Setup the MTD structure */
+ 	/* make the name contain the block device in */
+-	name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
++	if (!mtdname)
++		mtdname = devname;
++	name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
+ 	if (!name)
+ 		goto err_destroy_mutex;
+ 
++	strcpy(name, mtdname);
+ 	dev->mtd.name = name;
+ 
+-	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
++	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
+ 	dev->mtd.erasesize = erase_size;
+ 	dev->mtd.writesize = 1;
+ 	dev->mtd.writebufsize = PAGE_SIZE;
+@@ -276,15 +281,18 @@ static struct block2mtd_dev *add_device(
+ 	dev->mtd.priv = dev;
+ 	dev->mtd.owner = THIS_MODULE;
+ 
+-	if (mtd_device_register(&dev->mtd, NULL, 0)) {
++	part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
++	part->name = name;
++	part->offset = 0;
++	part->size = dev->mtd.size;
++	if (mtd_device_register(&dev->mtd, part, 1)) {
+ 		/* Device didn't get added, so free the entry */
+ 		goto err_destroy_mutex;
+ 	}
+ 	list_add(&dev->list, &blkmtd_device_list);
+ 	pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
+ 		dev->mtd.index,
+-		dev->mtd.name + strlen("block2mtd: "),
+-		dev->mtd.erasesize >> 10, dev->mtd.erasesize);
++		mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ 	return dev;
+ 
+ err_destroy_mutex:
+@@ -353,9 +361,9 @@ static char block2mtd_paramline[80 + 12]
+ 
+ static int block2mtd_setup2(const char *val)
+ {
+-	char buf[80 + 12]; /* 80 for device, 12 for erase size */
++	char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */
+ 	char *str = buf;
+-	char *token[2];
++	char *token[3];
+ 	char *name;
+ 	size_t erase_size = PAGE_SIZE;
+ 	int i, ret;
+@@ -368,7 +376,7 @@ static int block2mtd_setup2(const char *
+ 	strcpy(str, val);
+ 	kill_final_newline(str);
+ 
+-	for (i = 0; i < 2; i++)
++	for (i = 0; i < 3; i++)
+ 		token[i] = strsep(&str, ",");
+ 
+ 	if (str) {
+@@ -394,8 +402,10 @@ static int block2mtd_setup2(const char *
+ 			return 0;
+ 		}
+ 	}
++	if (token[2] && (strlen(token[2]) + 1 > 80))
++		pr_err("mtd device name too long\n");
+ 
+-	add_device(name, erase_size);
++	add_device(name, erase_size, token[2]);
+ 
+ 	return 0;
+ }
+@@ -429,7 +439,7 @@ static int block2mtd_setup(const char *v
+ 
+ 
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
+ 
+ static int __init block2mtd_init(void)
+ {
diff --git a/target/linux/generic/patches-3.18/441-block2mtd_probe.patch b/target/linux/generic/patches-3.18/441-block2mtd_probe.patch
new file mode 100644
index 0000000000..6836a48e39
--- /dev/null
+++ b/target/linux/generic/patches-3.18/441-block2mtd_probe.patch
@@ -0,0 +1,110 @@
+--- a/drivers/mtd/devices/block2mtd.c
++++ b/drivers/mtd/devices/block2mtd.c
+@@ -10,6 +10,7 @@
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ 
+ #include <linux/module.h>
++#include <linux/delay.h>
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+ #include <linux/bio.h>
+@@ -210,13 +211,16 @@ static void block2mtd_free_device(struct
+ }
+ 
+ 
+-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
++static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout)
+ {
+ 	const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
+-	struct block_device *bdev;
++	struct block_device *bdev = ERR_PTR(-ENODEV);
+ 	struct block2mtd_dev *dev;
+ 	struct mtd_partition *part;
+ 	char *name;
++#ifndef MODULE
++	int i;
++#endif
+ 
+ 	if (!devname)
+ 		return NULL;
+@@ -227,15 +231,20 @@ static struct block2mtd_dev *add_device(
+ 
+ 	/* Get a handle on the device */
+ 	bdev = blkdev_get_by_path(devname, mode, dev);
++
+ #ifndef MODULE
+-	if (IS_ERR(bdev)) {
++	for (i = 0; IS_ERR(bdev) && i <= timeout; i++) {
++		dev_t devt;
+ 
+-		/* We might not have rootfs mounted at this point. Try
+-		   to resolve the device name by other means. */
++		if (i)
++			msleep(1000);
++		wait_for_device_probe();
++
++		devt = name_to_dev_t(devname);
++		if (!devt)
++			continue;
+ 
+-		dev_t devt = name_to_dev_t(devname);
+-		if (devt)
+-			bdev = blkdev_get_by_dev(devt, mode, dev);
++		bdev = blkdev_get_by_dev(devt, mode, dev);
+ 	}
+ #endif
+ 
+@@ -361,11 +370,12 @@ static char block2mtd_paramline[80 + 12]
+ 
+ static int block2mtd_setup2(const char *val)
+ {
+-	char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */
++	char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
+ 	char *str = buf;
+-	char *token[3];
++	char *token[4];
+ 	char *name;
+ 	size_t erase_size = PAGE_SIZE;
++	unsigned long timeout = 0;
+ 	int i, ret;
+ 
+ 	if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
+@@ -376,7 +386,7 @@ static int block2mtd_setup2(const char *
+ 	strcpy(str, val);
+ 	kill_final_newline(str);
+ 
+-	for (i = 0; i < 3; i++)
++	for (i = 0; i < 4; i++)
+ 		token[i] = strsep(&str, ",");
+ 
+ 	if (str) {
+@@ -405,7 +415,10 @@ static int block2mtd_setup2(const char *
+ 	if (token[2] && (strlen(token[2]) + 1 > 80))
+ 		pr_err("mtd device name too long\n");
+ 
+-	add_device(name, erase_size, token[2]);
++	if (token[3] && kstrtoul(token[3], 0, &timeout))
++		pr_err("invalid timeout\n");
++
++	add_device(name, erase_size, token[2], timeout);
+ 
+ 	return 0;
+ }
+@@ -439,7 +452,7 @@ static int block2mtd_setup(const char *v
+ 
+ 
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>[,<timeout>]]]\"");
+ 
+ static int __init block2mtd_init(void)
+ {
+@@ -474,7 +487,7 @@ static void block2mtd_exit(void)
+ }
+ 
+ 
+-module_init(block2mtd_init);
++late_initcall(block2mtd_init);
+ module_exit(block2mtd_exit);
+ 
+ MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch b/target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
new file mode 100644
index 0000000000..0f5abaa723
--- /dev/null
+++ b/target/linux/generic/patches-3.18/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
@@ -0,0 +1,37 @@
+---
+ drivers/mtd/nand/plat_nand.c |   13 ++++++++++++-
+ include/linux/mtd/nand.h     |    1 +
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -851,6 +851,7 @@ struct platform_nand_chip {
+ 	unsigned int options;
+ 	unsigned int bbt_options;
+ 	const char **part_probe_types;
++	int (*chip_fixup)(struct mtd_info *mtd);
+ };
+ 
+ /* Keep gcc happy */
+--- a/drivers/mtd/nand/plat_nand.c
++++ b/drivers/mtd/nand/plat_nand.c
+@@ -90,7 +90,18 @@ static int plat_nand_probe(struct platfo
+ 	}
+ 
+ 	/* Scan to find existence of the device */
+-	if (nand_scan(&data->mtd, pdata->chip.nr_chips)) {
++	if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) {
++		err = -ENXIO;
++		goto out;
++	}
++
++	if (pdata->chip.chip_fixup) {
++		err = pdata->chip.chip_fixup(&data->mtd);
++		if (err)
++			goto out;
++	}
++
++	if (nand_scan_tail(&data->mtd)) {
+ 		err = -ENXIO;
+ 		goto out;
+ 	}
diff --git a/target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch b/target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
new file mode 100644
index 0000000000..6a2092ce20
--- /dev/null
+++ b/target/linux/generic/patches-3.18/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/nand/nand_ecc.c
++++ b/drivers/mtd/nand/nand_ecc.c
+@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b
+ 		return 1;	/* error in ECC data; no action needed */
+ 
+ 	pr_err("%s: uncorrectable ECC error\n", __func__);
+-	return -1;
++	return -EBADMSG;
+ }
+ EXPORT_SYMBOL(__nand_correct_data);
+ 
diff --git a/target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
new file mode 100644
index 0000000000..68fbd12466
--- /dev/null
+++ b/target/linux/generic/patches-3.18/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map
+ 		return 0;
+ 
+ 	case FL_ERASING:
+-		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
++		if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
+ 		    !(mode == FL_READY || mode == FL_POINT ||
+ 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
+ 			goto sleep;
diff --git a/target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
new file mode 100644
index 0000000000..c437a140f0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
@@ -0,0 +1,18 @@
+From: George Kashperko <george@znau.edu.ua>
+
+Issue map read after Write Buffer Load command to ensure chip is ready
+to receive data.
+Signed-off-by: George Kashperko <george@znau.edu.ua>
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    1 +
+ 1 file changed, 1 insertion(+)
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru
+ 
+ 	/* Write Buffer Load */
+ 	map_write(map, CMD(0x25), cmd_adr);
++	(void) map_read(map, cmd_adr);
+ 
+ 	chip->state = FL_WRITING_TO_BUFFER;
+ 
diff --git a/target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch b/target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch
new file mode 100644
index 0000000000..f059aa777e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/472-mtd-m25p80-add-support-for-Winbond-W25X05-flash.patch
@@ -0,0 +1,20 @@
+From eef9dfc4e821408af1af13aa0cc707fc496fb7c6 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Wed, 11 Dec 2013 19:05:59 +0100
+Subject: [PATCH] m25p80: add support for the Winbond W25X05 flash
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/devices/m25p80.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -618,6 +618,7 @@ static const struct spi_device_id spi_no
+ 	{ "m25px80",    INFO(0x207114,  0, 64 * 1024, 16, 0) },
+ 
+ 	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
++	{ "w25x05", INFO(0xef3010, 0, 64 * 1024,  1,  SECT_4K) },
+ 	{ "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
+ 	{ "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
+ 	{ "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
diff --git a/target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch b/target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch
new file mode 100644
index 0000000000..9ba7a4ab2f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/473-mtd-spi-nor-add-support-for-the-Macronix-MX25L512E-S.patch
@@ -0,0 +1,21 @@
+From 0d7388de0911c1a4fc4a8a3898ef9d0ab818ca08 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Tue, 7 Apr 2015 18:35:15 +0200
+Subject: [PATCH] mtd: spi-nor: add support for the Macronix MX25L512E SPI
+ flash chip
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/spi-nor/spi-nor.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -518,6 +518,7 @@ static const struct spi_device_id spi_no
+ 	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+ 
+ 	/* Macronix */
++	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
+ 	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
+ 	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
+ 	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
diff --git a/target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch b/target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch
new file mode 100644
index 0000000000..b06ac73fae
--- /dev/null
+++ b/target/linux/generic/patches-3.18/474-mtd-spi-nor-add-support-for-the-ISSI-SI25CD512-SPI-f.patch
@@ -0,0 +1,22 @@
+From 34e2b403040a2f9d3ba071d95a7f42457e2950f9 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Tue, 7 Apr 2015 18:35:15 +0200
+Subject: [PATCH] mtd: spi-nor: add support for the ISSI SI25CD512 SPI flash
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/spi-nor/spi-nor.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -517,6 +517,9 @@ static const struct spi_device_id spi_no
+ 	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
+ 	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+ 
++	/* ISSI */
++	{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024,   2, SECT_4K) },
++
+ 	/* Macronix */
+ 	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
+ 	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
diff --git a/target/linux/generic/patches-3.18/475-mtd-spi-nor-add-macronix-mx25u25635f.patch b/target/linux/generic/patches-3.18/475-mtd-spi-nor-add-macronix-mx25u25635f.patch
new file mode 100644
index 0000000000..72c083232e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/475-mtd-spi-nor-add-macronix-mx25u25635f.patch
@@ -0,0 +1,10 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -532,6 +532,7 @@ static const struct spi_device_id spi_no
+ 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ 	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+ 	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
++	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, 0) },
+ 	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+ 	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+ 	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
diff --git a/target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch
new file mode 100644
index 0000000000..8fc3578a66
--- /dev/null
+++ b/target/linux/generic/patches-3.18/480-mtd-set-rootfs-to-be-root-dev.patch
@@ -0,0 +1,26 @@
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -37,6 +37,7 @@
+ #include <linux/backing-dev.h>
+ #include <linux/gfp.h>
+ #include <linux/slab.h>
++#include <linux/root_dev.h>
+ 
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -456,6 +457,15 @@ int add_mtd_device(struct mtd_info *mtd)
+ 	   of this try_ nonsense, and no bitching about it
+ 	   either. :) */
+ 	__module_get(THIS_MODULE);
++
++	if (!strcmp(mtd->name, "rootfs") &&
++	    config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("mtd: device %d (%s) set to be root filesystem\n",
++			  mtd->index, mtd->name);
++		ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
++	}
++
+ 	return 0;
+ 
+ fail_added:
diff --git a/target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
new file mode 100644
index 0000000000..bca3487d18
--- /dev/null
+++ b/target/linux/generic/patches-3.18/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
@@ -0,0 +1,76 @@
+From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:36:18 +0200
+Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -1212,6 +1212,49 @@ static struct mtd_info * __init open_mtd
+ 	return mtd;
+ }
+ 
++/*
++ * This function tries attaching mtd partitions named either "ubi" or "data"
++ * during boot.
++ */
++static void __init ubi_auto_attach(void)
++{
++	int err;
++	struct mtd_info *mtd;
++
++	/* try attaching mtd device named "ubi" or "data" */
++	mtd = open_mtd_device("ubi");
++	if (IS_ERR(mtd))
++		mtd = open_mtd_device("data");
++
++	if (!IS_ERR(mtd)) {
++		size_t len;
++		char magic[4];
++
++		/* check for a valid ubi magic */
++		err = mtd_read(mtd, 0, 4, &len, (void *) magic);
++		if (!err && len == 4 && strncmp(magic, "UBI#", 4)) {
++			ubi_err("no valid UBI magic found inside mtd%d", mtd->index);
++			put_mtd_device(mtd);
++			return;
++		}
++
++		/* auto-add only media types where UBI makes sense */
++		if (mtd->type == MTD_NANDFLASH ||
++		    mtd->type == MTD_NORFLASH ||
++		    mtd->type == MTD_DATAFLASH ||
++		    mtd->type == MTD_MLCNANDFLASH) {
++			mutex_lock(&ubi_devices_mutex);
++			ubi_msg("auto-attach mtd%d", mtd->index);
++			err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
++			mutex_unlock(&ubi_devices_mutex);
++			if (err < 0) {
++				ubi_err("cannot attach mtd%d", mtd->index);
++				put_mtd_device(mtd);
++			}
++		}
++	}
++}
++
+ static int __init ubi_init(void)
+ {
+ 	int err, i, k;
+@@ -1301,6 +1344,12 @@ static int __init ubi_init(void)
+ 		}
+ 	}
+ 
++	/* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
++	 * parameter was given */
++	if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    !ubi_is_module() && !mtd_devs)
++		ubi_auto_attach();
++
+ 	err = ubiblock_init();
+ 	if (err) {
+ 		ubi_err("block: cannot initialize, error %d", err);
diff --git a/target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
new file mode 100644
index 0000000000..b152fba1b3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
@@ -0,0 +1,69 @@
+From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 21:06:33 +0200
+Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -615,6 +615,44 @@ static int __init ubiblock_create_from_p
+ 	return ret;
+ }
+ 
++#define UBIFS_NODE_MAGIC  0x06101831
++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
++{
++	int ret;
++	uint32_t magic_of, magic;
++	ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
++	if (ret)
++		return 0;
++	magic = le32_to_cpu(magic_of);
++	return magic == UBIFS_NODE_MAGIC;
++}
++
++static void __init ubiblock_create_auto_rootfs(void)
++{
++	int ubi_num, ret, is_ubifs;
++	struct ubi_volume_desc *desc;
++	struct ubi_volume_info vi;
++
++	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
++		desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
++		if (IS_ERR(desc))
++			continue;
++
++		ubi_get_volume_info(desc, &vi);
++		is_ubifs = ubi_vol_is_ubifs(desc);
++		ubi_close_volume(desc);
++		if (is_ubifs)
++			break;
++
++		ret = ubiblock_create(&vi);
++		if (ret)
++			ubi_err("block: can't add '%s' volume, err=%d\n",
++				vi.name, ret);
++		/* always break if we get here */
++		break;
++	}
++}
++
+ static void ubiblock_remove_all(void)
+ {
+ 	struct ubiblock *next;
+@@ -645,6 +683,10 @@ int __init ubiblock_init(void)
+ 	if (ret)
+ 		goto err_remove;
+ 
++	/* auto-attach "rootfs" volume if existing and non-ubifs */
++	if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV))
++		ubiblock_create_auto_rootfs();
++
+ 	/*
+ 	 * Block devices are only created upon user requests, so we ignore
+ 	 * existing volumes.
diff --git a/target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
new file mode 100644
index 0000000000..54a2f8259c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
@@ -0,0 +1,54 @@
+From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:35:02 +0200
+Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ init/do_mounts.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -433,7 +433,28 @@ retry:
+ out:
+ 	put_page(page);
+ }
+- 
++
++static int __init mount_ubi_rootfs(void)
++{
++	int flags = MS_SILENT;
++	int err, tried = 0;
++
++	while (tried < 2) {
++		err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
++					root_mount_data);
++		switch (err) {
++			case -EACCES:
++				flags |= MS_RDONLY;
++				tried++;
++				break;
++			default:
++				return err;
++		}
++	}
++
++	return -EINVAL;
++}
++
+ #ifdef CONFIG_ROOT_NFS
+ 
+ #define NFSROOT_TIMEOUT_MIN	5
+@@ -527,6 +548,10 @@ void __init mount_root(void)
+ 			change_floppy("root floppy");
+ 	}
+ #endif
++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
++	if (!mount_ubi_rootfs())
++		return;
++#endif
+ #ifdef CONFIG_BLOCK
+ 	create_dev("/dev/root", ROOT_DEV);
+ 	mount_block_root("/dev/root", root_mountflags);
diff --git a/target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
new file mode 100644
index 0000000000..46917d12d2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
@@ -0,0 +1,37 @@
+From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 20:55:42 +0200
+Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -48,6 +48,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/hdreg.h>
+ #include <asm/div64.h>
++#include <linux/root_dev.h>
+ 
+ #include "ubi-media.h"
+ #include "ubi.h"
+@@ -448,6 +449,15 @@ int ubiblock_create(struct ubi_volume_in
+ 	add_disk(dev->gd);
+ 	ubi_msg("%s created from ubi%d:%d(%s)",
+ 		dev->gd->disk_name, dev->ubi_num, dev->vol_id, vi->name);
++
++	if (!strcmp(vi->name, "rootfs") &&
++	    config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
++			  dev->ubi_num, dev->vol_id, vi->name);
++		ROOT_DEV = MKDEV(gd->major, gd->first_minor);
++	}
++
+ 	return 0;
+ 
+ out_free_queue:
diff --git a/target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch
new file mode 100644
index 0000000000..4b5eb4568d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/494-mtd-ubi-add-EOF-marker-support.patch
@@ -0,0 +1,51 @@
+--- a/drivers/mtd/ubi/attach.c
++++ b/drivers/mtd/ubi/attach.c
+@@ -800,6 +800,13 @@ out_unlock:
+ 	return err;
+ }
+ 
++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
++{
++	return ech->padding1[0] == 'E' &&
++	       ech->padding1[1] == 'O' &&
++	       ech->padding1[2] == 'F';
++}
++
+ /**
+  * scan_peb - scan and process UBI headers of a PEB.
+  * @ubi: UBI device description object
+@@ -830,9 +837,21 @@ static int scan_peb(struct ubi_device *u
+ 		return 0;
+ 	}
+ 
+-	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+-	if (err < 0)
+-		return err;
++	if (!ai->eof_found) {
++		err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
++		if (err < 0)
++			return err;
++
++		if (ec_hdr_has_eof(ech)) {
++			ubi_msg("EOF marker found, PEBs from %d will be erased",
++				pnum);
++			ai->eof_found = true;
++		}
++	}
++
++	if (ai->eof_found)
++		err = UBI_IO_FF_BITFLIPS;
++
+ 	switch (err) {
+ 	case 0:
+ 		break;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -705,6 +705,7 @@ struct ubi_attach_info {
+ 	int mean_ec;
+ 	uint64_t ec_sum;
+ 	int ec_count;
++	bool eof_found;
+ 	struct kmem_cache *aeb_slab_cache;
+ };
+ 
diff --git a/target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch b/target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch
new file mode 100644
index 0000000000..de6643a41e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/500-yaffs-Kbuild-integration.patch
@@ -0,0 +1,18 @@
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -39,6 +39,7 @@ source "fs/gfs2/Kconfig"
+ source "fs/ocfs2/Kconfig"
+ source "fs/btrfs/Kconfig"
+ source "fs/nilfs2/Kconfig"
++source "fs/yaffs2/Kconfig"
+ 
+ endif # BLOCK
+ 
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -126,3 +126,5 @@ obj-y				+= exofs/ # Multiple modules
+ obj-$(CONFIG_CEPH_FS)		+= ceph/
+ obj-$(CONFIG_PSTORE)		+= pstore/
+ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
++obj-$(CONFIG_YAFFS_FS)		+= yaffs2/
++
diff --git a/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch
new file mode 100644
index 0000000000..a18cf6fd7b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch
@@ -0,0 +1,239 @@
+Subject: yaffs: fix compat tags handling
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+--- a/fs/yaffs2/yaffs_tagscompat.c
++++ b/fs/yaffs2/yaffs_tagscompat.c
+@@ -17,7 +17,9 @@
+ #include "yaffs_getblockinfo.h"
+ #include "yaffs_trace.h"
+ 
++#if 0
+ static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++#endif
+ 
+ 
+ /********** Tags ECC calculations  *********/
+@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
+ 	return 0;
+ }
+ 
++#if 0
+ /********** Tags **********/
+ 
+ static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
+ 	if(!dev->tagger.mark_bad_fn)
+ 		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+ }
++#else
++
++#include "yaffs_packedtags1.h"
++
++static int yaffs_tags_compat_write(struct yaffs_dev *dev,
++				   int nand_chunk,
++				   const u8 *data,
++				   const struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags1 pt1;
++	u8 tag_buf[9];
++	int retval;
++
++	/* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
++	compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
++	compile_time_assertion(sizeof(struct yaffs_tags) == 8);
++
++	yaffs_pack_tags1(&pt1, tags);
++	yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
++
++	/* When deleting a chunk, the upper layer provides only skeletal
++	 * tags, one with is_deleted set.  However, we need to update the
++	 * tags, not erase them completely.  So we use the NAND write property
++	 * that only zeroed-bits stick and set tag bytes to all-ones and
++	 * zero just the (not) deleted bit.
++	 */
++	if (!dev->param.tags_9bytes) {
++		if (tags->is_deleted) {
++			memset(&pt1, 0xff, 8);
++			/* clear delete status bit to indicate deleted */
++			pt1.deleted = 0;
++		}
++		memcpy(tag_buf, &pt1, 8);
++	} else {
++		if (tags->is_deleted) {
++			memset(tag_buf, 0xff, 8);
++			tag_buf[8] = 0;
++		} else {
++			memcpy(tag_buf, &pt1, 8);
++			tag_buf[8] = 0xff;
++		}
++	}
++
++	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++			data,
++			(data) ? dev->data_bytes_per_chunk : 0,
++			tag_buf,
++			(dev->param.tags_9bytes) ? 9 : 8);
++
++	return retval;
++}
++
++/* Return with empty extended tags but add ecc_result.
++ */
++static int return_empty_tags(struct yaffs_ext_tags *tags,
++			     enum yaffs_ecc_result ecc_result,
++			     int retval)
++{
++	if (tags) {
++		memset(tags, 0, sizeof(*tags));
++		tags->ecc_result = ecc_result;
++	}
++
++	return retval;
++}
++
++static int yaffs_tags_compat_read(struct yaffs_dev *dev,
++				  int nand_chunk,
++				  u8 *data,
++				  struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags1 pt1;
++	enum yaffs_ecc_result ecc_result;
++	int retval;
++	int deleted;
++	u8 tag_buf[9];
++
++	retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++			data, dev->param.total_bytes_per_chunk,
++			tag_buf,
++			(dev->param.tags_9bytes) ? 9 : 8,
++			&ecc_result);
++
++	switch (ecc_result) {
++	case YAFFS_ECC_RESULT_NO_ERROR:
++	case YAFFS_ECC_RESULT_FIXED:
++		break;
++
++	case YAFFS_ECC_RESULT_UNFIXED:
++	default:
++		return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
++		tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
++		return YAFFS_FAIL;
++	}
++
++	/* Check for a blank/erased chunk. */
++	if (yaffs_check_ff(tag_buf, 8)) {
++		/* when blank, upper layers want ecc_result to be <= NO_ERROR */
++		return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
++					 YAFFS_OK);
++	}
++
++	memcpy(&pt1, tag_buf, 8);
++
++	if (!dev->param.tags_9bytes) {
++		/* Read deleted status (bit) then return it to it's non-deleted
++		 * state before performing tags mini-ECC check. pt1.deleted is
++		 * inverted.
++		 */
++		deleted = !pt1.deleted;
++		pt1.deleted = 1;
++	} else {
++		deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
++	}
++
++	/* Check the packed tags mini-ECC and correct if necessary/possible. */
++	retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
++	switch (retval) {
++	case 0:
++		/* no tags error, use MTD result */
++		break;
++	case 1:
++		/* recovered tags-ECC error */
++		dev->n_tags_ecc_fixed++;
++		if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
++			ecc_result = YAFFS_ECC_RESULT_FIXED;
++		break;
++	default:
++		/* unrecovered tags-ECC error */
++		dev->n_tags_ecc_unfixed++;
++		return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
++					 YAFFS_FAIL);
++	}
++
++	/* Unpack the tags to extended form and set ECC result.
++	 * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
++	 */
++	pt1.should_be_ff = 0xffffffff;
++	yaffs_unpack_tags1(tags, &pt1);
++	tags->ecc_result = ecc_result;
++
++	/* Set deleted state */
++	tags->is_deleted = deleted;
++	return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++	return dev->drv.drv_mark_bad_fn(dev, block_no);
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++					 int block_no,
++					 enum yaffs_block_state *state,
++					 u32 *seq_number)
++{
++	struct yaffs_ext_tags tags;
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
++
++	*seq_number = 0;
++
++	retval = dev->drv.drv_check_bad_fn(dev, block_no);
++	if (retval == YAFFS_FAIL) {
++		*state = YAFFS_BLOCK_STATE_DEAD;
++		goto out;
++	}
++
++	yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
++			       NULL, &tags);
++
++	if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
++		yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
++			    block_no);
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++	} else if (tags.chunk_used) {
++		*seq_number = tags.seq_number;
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++	} else {
++		*state = YAFFS_BLOCK_STATE_EMPTY;
++	}
++
++	retval = YAFFS_OK;
++
++out:
++	yaffs_trace(YAFFS_TRACE_MTD,
++		    "block query returns seq %u state %d",
++		    *seq_number, *state);
++
++	return retval;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++	if (dev->param.is_yaffs2)
++		return;
++
++	if (!dev->tagger.write_chunk_tags_fn)
++		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
++
++	if (!dev->tagger.read_chunk_tags_fn)
++		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
++
++	if (!dev->tagger.query_block_fn)
++		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++
++	if (!dev->tagger.mark_bad_fn)
++		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
++#endif
diff --git a/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch
new file mode 100644
index 0000000000..3f51bafc11
--- /dev/null
+++ b/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch
@@ -0,0 +1,115 @@
+Subject: yaffs: add support for tags-9bytes mount option
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -2644,6 +2644,7 @@ static const struct super_operations yaf
+ 
+ struct yaffs_options {
+ 	int inband_tags;
++	int tags_9bytes;
+ 	int skip_checkpoint_read;
+ 	int skip_checkpoint_write;
+ 	int no_cache;
+@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya
+ 
+ 		if (!strcmp(cur_opt, "inband-tags")) {
+ 			options->inband_tags = 1;
++		} else if (!strcmp(cur_opt, "tags-9bytes")) {
++			options->tags_9bytes = 1;
+ 		} else if (!strcmp(cur_opt, "tags-ecc-off")) {
+ 			options->tags_ecc_on = 0;
+ 			options->tags_ecc_overridden = 1;
+@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna
+ 	struct yaffs_param *param;
+ 
+ 	int read_only = 0;
+-	int inband_tags = 0;
+ 
+ 	struct yaffs_options options;
+ 
+@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna
+ 
+ 	memset(&options, 0, sizeof(options));
+ 
++	if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS))
++		options.tags_9bytes = 1;
++
+ 	if (yaffs_parse_options(&options, data_str)) {
+ 		/* Option parsing failed */
+ 		return NULL;
+@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna
+ 	}
+ 
+ 	/* Added NCB 26/5/2006 for completeness */
+-	if (yaffs_version == 2 && !options.inband_tags
+-	    && WRITE_SIZE(mtd) == 512) {
++	if (yaffs_version == 2 &&
++	    (!options.inband_tags || options.tags_9bytes) &&
++	    WRITE_SIZE(mtd) == 512) {
+ 		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
+ 		yaffs_version = 1;
+ 	}
+ 
+-	if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
+-	    options.inband_tags)
+-		inband_tags = 1;
++	if (yaffs_version == 2 &&
++	    mtd->oobavail < sizeof(struct yaffs_packed_tags2)) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags");
++		options.inband_tags = 1;
++	}
+ 
+-	if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++	err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags,
++			       options.tags_9bytes);
++	if (err < 0)
+ 		return NULL;
+ 
+ 	/* OK, so if we got here, we have an MTD that's NAND and looks
+@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna
+ 
+ 	param->n_reserved_blocks = 5;
+ 	param->n_caches = (options.no_cache) ? 0 : 10;
+-	param->inband_tags = inband_tags;
++	param->inband_tags = options.inband_tags;
++	param->tags_9bytes = options.tags_9bytes;
+ 
+ 	param->enable_xattr = 1;
+ 	if (options.lazy_loading_overridden)
+--- a/fs/yaffs2/yaffs_mtdif.c
++++ b/fs/yaffs2/yaffs_mtdif.c
+@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d
+ 	return mtd;
+ }
+ 
+-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
++		     int tags_9bytes)
+ {
+ 	if (yaffs_version == 2) {
+ 		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt
+ 			);
+ 			return -1;
+ 		}
++
++		if (tags_9bytes && mtd->oobavail < 9) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				    "MTD device does not support 9-byte tags");
++			return -1;
++		}
+ 	}
+ 
+ 	return 0;
+--- a/fs/yaffs2/yaffs_mtdif.h
++++ b/fs/yaffs2/yaffs_mtdif.h
+@@ -21,5 +21,6 @@
+ void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+ struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
+ void yaffs_put_mtd_device(struct mtd_info *mtd);
+-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
++		     int tags_9bytes);
+ #endif
diff --git a/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch
new file mode 100644
index 0000000000..11c6da0516
--- /dev/null
+++ b/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch
@@ -0,0 +1,25 @@
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -774,7 +774,21 @@ static int yaffs_sync_object(struct file
+ }
+ 
+ 
+-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
++static const struct file_operations yaffs_file_operations = {
++	.read = new_sync_read,
++	.read_iter = generic_file_read_iter,
++	.write = new_sync_write,
++	.write_iter = generic_file_write_iter,
++	.mmap = generic_file_mmap,
++	.flush = yaffs_file_flush,
++	.fsync = yaffs_sync_object,
++	.splice_read = generic_file_splice_read,
++	.splice_write = iter_file_splice_write,
++	.llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+ static const struct file_operations yaffs_file_operations = {
+ 	.read = do_sync_read,
+ 	.write = do_sync_write,
diff --git a/target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch
new file mode 100644
index 0000000000..c92209a72c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/530-jffs2_make_lzma_available.patch
@@ -0,0 +1,5142 @@
+--- a/fs/jffs2/Kconfig
++++ b/fs/jffs2/Kconfig
+@@ -139,6 +139,15 @@ config JFFS2_LZO
+ 	  This feature was added in July, 2007. Say 'N' if you need
+ 	  compatibility with older bootloaders or kernels.
+ 
++config JFFS2_LZMA
++	bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS
++	select LZMA_COMPRESS
++	select LZMA_DECOMPRESS
++	depends on JFFS2_FS
++	default n
++	help
++	  JFFS2 wrapper to the LZMA C SDK
++
+ config JFFS2_RTIME
+ 	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+ 	depends on JFFS2_FS
+--- a/fs/jffs2/Makefile
++++ b/fs/jffs2/Makefile
+@@ -18,4 +18,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rub
+ jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
+ jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
+ jffs2-$(CONFIG_JFFS2_LZO)	+= compr_lzo.o
++jffs2-$(CONFIG_JFFS2_LZMA)      += compr_lzma.o
+ jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
++
++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma
+--- a/fs/jffs2/compr.c
++++ b/fs/jffs2/compr.c
+@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_init();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_init();
++#endif
+ /* Setting default compression mode */
+ #ifdef CONFIG_JFFS2_CMODE_NONE
+ 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void)
+ int jffs2_compressors_exit(void)
+ {
+ /* Unregistering compressors */
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_exit();
++#endif
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_exit();
+ #endif
+--- a/fs/jffs2/compr.h
++++ b/fs/jffs2/compr.h
+@@ -29,9 +29,9 @@
+ #define JFFS2_DYNRUBIN_PRIORITY  20
+ #define JFFS2_LZARI_PRIORITY     30
+ #define JFFS2_RTIME_PRIORITY     50
+-#define JFFS2_ZLIB_PRIORITY      60
+-#define JFFS2_LZO_PRIORITY       80
+-
++#define JFFS2_LZMA_PRIORITY      70
++#define JFFS2_ZLIB_PRIORITY      80
++#define JFFS2_LZO_PRIORITY       90
+ 
+ #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
+ #define JFFS2_DYNRUBIN_DISABLED  /*	   for decompression */
+@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void);
+ int jffs2_lzo_init(void);
+ void jffs2_lzo_exit(void);
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++int jffs2_lzma_init(void);
++void jffs2_lzma_exit(void);
++#endif
+ 
+ #endif /* __JFFS2_COMPR_H__ */
+--- /dev/null
++++ b/fs/jffs2/compr_lzma.c
+@@ -0,0 +1,128 @@
++/*
++ * JFFS2 -- Journalling Flash File System, Version 2.
++ *
++ * For licensing information, see the file 'LICENCE' in this directory.
++ *
++ * JFFS2 wrapper to the LZMA C SDK
++ *
++ */
++
++#include <linux/lzma.h>
++#include "compr.h"
++
++#ifdef __KERNEL__
++	static DEFINE_MUTEX(deflate_mutex);
++#endif
++
++CLzmaEncHandle *p;
++Byte propsEncoded[LZMA_PROPS_SIZE];
++SizeT propsSize = sizeof(propsEncoded);
++
++STATIC void lzma_free_workspace(void)
++{
++	LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
++}
++
++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
++{
++	if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
++	{
++		PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
++		return -ENOMEM;
++	}
++
++	if (LzmaEnc_SetProps(p, props) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++	
++	if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++        return 0;
++}
++
++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
++			      uint32_t *sourcelen, uint32_t *dstlen)
++{
++	SizeT compress_size = (SizeT)(*dstlen);
++	int ret;
++
++	#ifdef __KERNEL__
++		mutex_lock(&deflate_mutex);
++	#endif
++
++	ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
++		0, NULL, &lzma_alloc, &lzma_alloc);
++
++	#ifdef __KERNEL__
++		mutex_unlock(&deflate_mutex);
++	#endif
++
++	if (ret != SZ_OK)
++		return -1;
++
++	*dstlen = (uint32_t)compress_size;
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
++				 uint32_t srclen, uint32_t destlen)
++{
++	int ret;
++	SizeT dl = (SizeT)destlen;
++	SizeT sl = (SizeT)srclen;
++	ELzmaStatus status;
++	
++	ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
++		propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
++
++	if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
++		return -1;
++
++	return 0;
++}
++
++static struct jffs2_compressor jffs2_lzma_comp = {
++	.priority = JFFS2_LZMA_PRIORITY,
++	.name = "lzma",
++	.compr = JFFS2_COMPR_LZMA,
++	.compress = &jffs2_lzma_compress,
++	.decompress = &jffs2_lzma_decompress,
++	.disabled = 0,
++};
++
++int INIT jffs2_lzma_init(void)
++{
++        int ret;
++	CLzmaEncProps props;
++	LzmaEncProps_Init(&props);
++
++        props.dictSize = LZMA_BEST_DICT(0x2000);
++        props.level = LZMA_BEST_LEVEL;
++        props.lc = LZMA_BEST_LC;
++        props.lp = LZMA_BEST_LP;
++        props.pb = LZMA_BEST_PB;
++        props.fb = LZMA_BEST_FB;
++
++	ret = lzma_alloc_workspace(&props);
++        if (ret < 0)
++                return ret;
++
++	ret = jffs2_register_compressor(&jffs2_lzma_comp);
++	if (ret)
++		lzma_free_workspace();
++	
++        return ret;
++}
++
++void jffs2_lzma_exit(void)
++{
++	jffs2_unregister_compressor(&jffs2_lzma_comp);
++	lzma_free_workspace();
++}
+--- a/fs/jffs2/super.c
++++ b/fs/jffs2/super.c
+@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void)
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
+ 
+-	pr_info("version 2.2."
++	pr_info("version 2.2"
+ #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ 	       " (NAND)"
+ #endif
+ #ifdef CONFIG_JFFS2_SUMMARY
+-	       " (SUMMARY) "
++	       " (SUMMARY)"
+ #endif
+-	       " © 2001-2006 Red Hat, Inc.\n");
++#ifdef CONFIG_JFFS2_ZLIB
++	       " (ZLIB)"
++#endif
++#ifdef CONFIG_JFFS2_LZO
++	       " (LZO)"
++#endif
++#ifdef CONFIG_JFFS2_LZMA
++	       " (LZMA)"
++#endif
++#ifdef CONFIG_JFFS2_RTIME
++	       " (RTIME)"
++#endif
++#ifdef CONFIG_JFFS2_RUBIN
++	       " (RUBIN)"
++#endif
++#ifdef  CONFIG_JFFS2_CMODE_NONE
++	       " (CMODE_NONE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_PRIORITY
++	       " (CMODE_PRIORITY)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_SIZE
++	       " (CMODE_SIZE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
++	       " (CMODE_FAVOURLZO)"
++#endif
++	       " (c) 2001-2006 Red Hat, Inc.\n");
+ 
+ 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
+ 					     sizeof(struct jffs2_inode_info),
+--- a/include/uapi/linux/jffs2.h
++++ b/include/uapi/linux/jffs2.h
+@@ -46,6 +46,7 @@
+ #define JFFS2_COMPR_DYNRUBIN	0x05
+ #define JFFS2_COMPR_ZLIB	0x06
+ #define JFFS2_COMPR_LZO		0x07
++#define JFFS2_COMPR_LZMA	0x08
+ /* Compatibility flags. */
+ #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+ #define JFFS2_NODE_ACCURATE 0x2000
+--- /dev/null
++++ b/include/linux/lzma.h
+@@ -0,0 +1,62 @@
++#ifndef __LZMA_H__
++#define __LZMA_H__
++
++#ifdef __KERNEL__
++	#include <linux/kernel.h>
++	#include <linux/sched.h>
++	#include <linux/slab.h>
++	#include <linux/vmalloc.h>
++	#include <linux/init.h>
++	#define LZMA_MALLOC vmalloc
++	#define LZMA_FREE vfree
++	#define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
++	#define INIT __init
++	#define STATIC static
++#else
++	#include <stdint.h>
++	#include <stdlib.h>
++	#include <stdio.h>
++	#include <unistd.h>
++	#include <string.h>
++	#include <asm/types.h>
++	#include <errno.h>
++	#include <linux/jffs2.h>
++	#ifndef PAGE_SIZE
++		extern int page_size;
++		#define PAGE_SIZE page_size
++	#endif
++	#define LZMA_MALLOC malloc
++	#define LZMA_FREE free
++	#define PRINT_ERROR(msg) fprintf(stderr, msg)
++	#define INIT
++	#define STATIC
++#endif
++
++#include "lzma/LzmaDec.h"
++#include "lzma/LzmaEnc.h"
++
++#define LZMA_BEST_LEVEL (9)
++#define LZMA_BEST_LC    (0)
++#define LZMA_BEST_LP    (0)
++#define LZMA_BEST_PB    (0)
++#define LZMA_BEST_FB  (273)
++
++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
++
++static void *p_lzma_malloc(void *p, size_t size)
++{
++        if (size == 0)
++                return NULL;
++
++        return LZMA_MALLOC(size);
++}
++
++static void p_lzma_free(void *p, void *address)
++{
++        if (address != NULL)
++                LZMA_FREE(address);
++}
++
++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free};
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzFind.h
+@@ -0,0 +1,115 @@
++/* LzFind.h -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_FIND_H
++#define __LZ_FIND_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef UInt32 CLzRef;
++
++typedef struct _CMatchFinder
++{
++  Byte *buffer;
++  UInt32 pos;
++  UInt32 posLimit;
++  UInt32 streamPos;
++  UInt32 lenLimit;
++
++  UInt32 cyclicBufferPos;
++  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
++
++  UInt32 matchMaxLen;
++  CLzRef *hash;
++  CLzRef *son;
++  UInt32 hashMask;
++  UInt32 cutValue;
++
++  Byte *bufferBase;
++  ISeqInStream *stream;
++  int streamEndWasReached;
++
++  UInt32 blockSize;
++  UInt32 keepSizeBefore;
++  UInt32 keepSizeAfter;
++
++  UInt32 numHashBytes;
++  int directInput;
++  size_t directInputRem;
++  int btMode;
++  int bigHash;
++  UInt32 historySize;
++  UInt32 fixedHashSize;
++  UInt32 hashSizeSum;
++  UInt32 numSons;
++  SRes result;
++  UInt32 crc[256];
++} CMatchFinder;
++
++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
++
++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
++
++int MatchFinder_NeedMove(CMatchFinder *p);
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
++void MatchFinder_MoveBlock(CMatchFinder *p);
++void MatchFinder_ReadIfRequired(CMatchFinder *p);
++
++void MatchFinder_Construct(CMatchFinder *p);
++
++/* Conditions:
++     historySize <= 3 GB
++     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
++*/
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc);
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
++    UInt32 *distances, UInt32 maxLen);
++
++/*
++Conditions:
++  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
++  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
++*/
++
++typedef void (*Mf_Init_Func)(void *object);
++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
++typedef void (*Mf_Skip_Func)(void *object, UInt32);
++
++typedef struct _IMatchFinder
++{
++  Mf_Init_Func Init;
++  Mf_GetIndexByte_Func GetIndexByte;
++  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
++  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
++  Mf_GetMatches_Func GetMatches;
++  Mf_Skip_Func Skip;
++} IMatchFinder;
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
++
++void MatchFinder_Init(CMatchFinder *p);
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzHash.h
+@@ -0,0 +1,54 @@
++/* LzHash.h -- HASH functions for LZ algorithms
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_HASH_H
++#define __LZ_HASH_H
++
++#define kHash2Size (1 << 10)
++#define kHash3Size (1 << 16)
++#define kHash4Size (1 << 20)
++
++#define kFix3HashSize (kHash2Size)
++#define kFix4HashSize (kHash2Size + kHash3Size)
++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
++
++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
++
++#define HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
++
++#define HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
++
++#define HASH5_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
++  hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
++  hash4Value &= (kHash4Size - 1); }
++
++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
++
++
++#define MT_HASH2_CALC \
++  hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
++
++#define MT_HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
++
++#define MT_HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaDec.h
+@@ -0,0 +1,231 @@
++/* LzmaDec.h -- LZMA Decoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_DEC_H
++#define __LZMA_DEC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* #define _LZMA_PROB32 */
++/* _LZMA_PROB32 can increase the speed on some CPUs,
++   but memory usage for CLzmaDec::probs will be doubled in that case */
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++
++/* ---------- LZMA Properties ---------- */
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaProps
++{
++  unsigned lc, lp, pb;
++  UInt32 dicSize;
++} CLzmaProps;
++
++/* LzmaProps_Decode - decodes properties
++Returns:
++  SZ_OK
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
++
++
++/* ---------- LZMA Decoder state ---------- */
++
++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
++   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
++
++#define LZMA_REQUIRED_INPUT_MAX 20
++
++typedef struct
++{
++  CLzmaProps prop;
++  CLzmaProb *probs;
++  Byte *dic;
++  const Byte *buf;
++  UInt32 range, code;
++  SizeT dicPos;
++  SizeT dicBufSize;
++  UInt32 processedPos;
++  UInt32 checkDicSize;
++  unsigned state;
++  UInt32 reps[4];
++  unsigned remainLen;
++  int needFlush;
++  int needInitState;
++  UInt32 numProbs;
++  unsigned tempBufSize;
++  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
++} CLzmaDec;
++
++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
++
++void LzmaDec_Init(CLzmaDec *p);
++
++/* There are two types of LZMA streams:
++     0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
++     1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
++
++typedef enum
++{
++  LZMA_FINISH_ANY,   /* finish at any point */
++  LZMA_FINISH_END    /* block must be finished at the end */
++} ELzmaFinishMode;
++
++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
++
++   You must use LZMA_FINISH_END, when you know that current output buffer
++   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
++
++   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
++   and output value of destLen will be less than output buffer size limit.
++   You can check status result also.
++
++   You can use multiple checks to test data integrity after full decompression:
++     1) Check Result and "status" variable.
++     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
++     3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
++        You must use correct finish mode in that case. */
++
++typedef enum
++{
++  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
++  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
++  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
++  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */
++  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
++} ELzmaStatus;
++
++/* ELzmaStatus is used only as output value for function call */
++
++
++/* ---------- Interfaces ---------- */
++
++/* There are 3 levels of interfaces:
++     1) Dictionary Interface
++     2) Buffer Interface
++     3) One Call Interface
++   You can select any of these interfaces, but don't mix functions from different
++   groups for same object. */
++
++
++/* There are two variants to allocate state for Dictionary Interface:
++     1) LzmaDec_Allocate / LzmaDec_Free
++     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
++   You can use variant 2, if you set dictionary buffer manually.
++   For Buffer Interface you must always use variant 1.
++
++LzmaDec_Allocate* can return:
++  SZ_OK
++  SZ_ERROR_MEM         - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++   
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
++
++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
++
++/* ---------- Dictionary Interface ---------- */
++
++/* You can use it, if you want to eliminate the overhead for data copying from
++   dictionary to some other external buffer.
++   You must work with CLzmaDec variables directly in this interface.
++
++   STEPS:
++     LzmaDec_Constr()
++     LzmaDec_Allocate()
++     for (each new stream)
++     {
++       LzmaDec_Init()
++       while (it needs more decompression)
++       {
++         LzmaDec_DecodeToDic()
++         use data from CLzmaDec::dic and update CLzmaDec::dicPos
++       }
++     }
++     LzmaDec_Free()
++*/
++
++/* LzmaDec_DecodeToDic
++   
++   The decoding to internal dictionary buffer (CLzmaDec::dic).
++   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (dicLimit).
++  LZMA_FINISH_ANY - Decode just dicLimit bytes.
++  LZMA_FINISH_END - Stream must be finished after dicLimit.
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_NEEDS_MORE_INPUT
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++*/
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- Buffer Interface ---------- */
++
++/* It's zlib-like interface.
++   See LzmaDec_DecodeToDic description for information about STEPS and return results,
++   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
++   to work with CLzmaDec variables manually.
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++*/
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaDecode
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++  SZ_ERROR_MEM  - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
++*/
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -0,0 +1,80 @@
++/*  LzmaEnc.h -- LZMA Encoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_ENC_H
++#define __LZMA_ENC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaEncProps
++{
++  int level;       /*  0 <= level <= 9 */
++  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
++                      (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
++                       default = (1 << 24) */
++  int lc;          /* 0 <= lc <= 8, default = 3 */
++  int lp;          /* 0 <= lp <= 4, default = 0 */
++  int pb;          /* 0 <= pb <= 4, default = 2 */
++  int algo;        /* 0 - fast, 1 - normal, default = 1 */
++  int fb;          /* 5 <= fb <= 273, default = 32 */
++  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
++  int numHashBytes; /* 2, 3 or 4, default = 4 */
++  UInt32 mc;        /* 1 <= mc <= (1 << 30), default = 32 */
++  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
++  int numThreads;  /* 1 or 2, default = 2 */
++} CLzmaEncProps;
++
++void LzmaEncProps_Init(CLzmaEncProps *p);
++void LzmaEncProps_Normalize(CLzmaEncProps *p);
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
++
++
++/* ---------- CLzmaEncHandle Interface ---------- */
++
++/* LzmaEnc_* functions can return the following exit codes:
++Returns:
++  SZ_OK           - OK
++  SZ_ERROR_MEM    - Memory allocation error
++  SZ_ERROR_PARAM  - Incorrect paramater in props
++  SZ_ERROR_WRITE  - Write callback error.
++  SZ_ERROR_PROGRESS - some break from progress callback
++  SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
++*/
++
++typedef void * CLzmaEncHandle;
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaEncode
++Return code:
++  SZ_OK               - OK
++  SZ_ERROR_MEM        - Memory allocation error
++  SZ_ERROR_PARAM      - Incorrect paramater
++  SZ_ERROR_OUTPUT_EOF - output buffer overflow
++  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
++*/
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/Types.h
+@@ -0,0 +1,226 @@
++/* Types.h -- Basic types
++2009-11-23 : Igor Pavlov : Public domain */
++
++#ifndef __7Z_TYPES_H
++#define __7Z_TYPES_H
++
++#include <stddef.h>
++
++#ifdef _WIN32
++#include <windows.h>
++#endif
++
++#ifndef EXTERN_C_BEGIN
++#ifdef __cplusplus
++#define EXTERN_C_BEGIN extern "C" {
++#define EXTERN_C_END }
++#else
++#define EXTERN_C_BEGIN
++#define EXTERN_C_END
++#endif
++#endif
++
++EXTERN_C_BEGIN
++
++#define SZ_OK 0
++
++#define SZ_ERROR_DATA 1
++#define SZ_ERROR_MEM 2
++#define SZ_ERROR_CRC 3
++#define SZ_ERROR_UNSUPPORTED 4
++#define SZ_ERROR_PARAM 5
++#define SZ_ERROR_INPUT_EOF 6
++#define SZ_ERROR_OUTPUT_EOF 7
++#define SZ_ERROR_READ 8
++#define SZ_ERROR_WRITE 9
++#define SZ_ERROR_PROGRESS 10
++#define SZ_ERROR_FAIL 11
++#define SZ_ERROR_THREAD 12
++
++#define SZ_ERROR_ARCHIVE 16
++#define SZ_ERROR_NO_ARCHIVE 17
++
++typedef int SRes;
++
++#ifdef _WIN32
++typedef DWORD WRes;
++#else
++typedef int WRes;
++#endif
++
++#ifndef RINOK
++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
++#endif
++
++typedef unsigned char Byte;
++typedef short Int16;
++typedef unsigned short UInt16;
++
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef long Int32;
++typedef unsigned long UInt32;
++#else
++typedef int Int32;
++typedef unsigned int UInt32;
++#endif
++
++#ifdef _SZ_NO_INT_64
++
++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
++   NOTES: Some code will work incorrectly in that case! */
++
++typedef long Int64;
++typedef unsigned long UInt64;
++
++#else
++
++#if defined(_MSC_VER) || defined(__BORLANDC__)
++typedef __int64 Int64;
++typedef unsigned __int64 UInt64;
++#else
++typedef long long int Int64;
++typedef unsigned long long int UInt64;
++#endif
++
++#endif
++
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++typedef size_t SizeT;
++#endif
++
++typedef int Bool;
++#define True 1
++#define False 0
++
++
++#ifdef _WIN32
++#define MY_STD_CALL __stdcall
++#else
++#define MY_STD_CALL
++#endif
++
++#ifdef _MSC_VER
++
++#if _MSC_VER >= 1300
++#define MY_NO_INLINE __declspec(noinline)
++#else
++#define MY_NO_INLINE
++#endif
++
++#define MY_CDECL __cdecl
++#define MY_FAST_CALL __fastcall
++
++#else
++
++#define MY_CDECL
++#define MY_FAST_CALL
++
++#endif
++
++
++/* The following interfaces use first parameter as pointer to structure */
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) < input(*size)) is allowed */
++} ISeqInStream;
++
++/* it can return SZ_ERROR_INPUT_EOF */
++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
++
++typedef struct
++{
++  size_t (*Write)(void *p, const void *buf, size_t size);
++    /* Returns: result - the number of actually written bytes.
++       (result < size) means error */
++} ISeqOutStream;
++
++typedef enum
++{
++  SZ_SEEK_SET = 0,
++  SZ_SEEK_CUR = 1,
++  SZ_SEEK_END = 2
++} ESzSeek;
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);  /* same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ISeekInStream;
++
++typedef struct
++{
++  SRes (*Look)(void *p, void **buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) > input(*size)) is not allowed
++       (output(*size) < input(*size)) is allowed */
++  SRes (*Skip)(void *p, size_t offset);
++    /* offset must be <= output(*size) of Look */
++
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* reads directly (without buffer). It's same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ILookInStream;
++
++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
++
++/* reads via ILookInStream::Read */
++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
++
++#define LookToRead_BUF_SIZE (1 << 14)
++
++typedef struct
++{
++  ILookInStream s;
++  ISeekInStream *realStream;
++  size_t pos;
++  size_t size;
++  Byte buf[LookToRead_BUF_SIZE];
++} CLookToRead;
++
++void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
++void LookToRead_Init(CLookToRead *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToLook;
++
++void SecToLook_CreateVTable(CSecToLook *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToRead;
++
++void SecToRead_CreateVTable(CSecToRead *p);
++
++typedef struct
++{
++  SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
++    /* Returns: result. (result != SZ_OK) means break.
++       Value (UInt64)(Int64)-1 for size means unknown value. */
++} ICompressProgress;
++
++typedef struct
++{
++  void *(*Alloc)(void *p, size_t size);
++  void (*Free)(void *p, void *address); /* address can be 0 */
++} ISzAlloc;
++
++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
++#define IAlloc_Free(p, a) (p)->Free((p), a)
++
++EXTERN_C_END
++
++#endif
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -227,6 +227,12 @@ config LZ4_DECOMPRESS
+ 
+ source "lib/xz/Kconfig"
+ 
++config LZMA_COMPRESS
++    tristate
++
++config LZMA_DECOMPRESS
++    tristate
++
+ #
+ # These all provide a common interface (hence the apparent duplication with
+ # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.)
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -2,6 +2,16 @@
+ # Makefile for some libs needed in the kernel.
+ #
+ 
++ifdef CONFIG_JFFS2_ZLIB
++	CONFIG_ZLIB_INFLATE:=y
++	CONFIG_ZLIB_DEFLATE:=y
++endif
++
++ifdef CONFIG_JFFS2_LZMA
++	CONFIG_LZMA_DECOMPRESS:=y
++	CONFIG_LZMA_COMPRESS:=y
++endif
++
+ ifdef CONFIG_FUNCTION_TRACER
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS))
+@@ -85,6 +95,8 @@ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
+ obj-$(CONFIG_XZ_DEC) += xz/
+ obj-$(CONFIG_RAID6_PQ) += raid6/
++obj-$(CONFIG_LZMA_COMPRESS) += lzma/
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/
+ 
+ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
+ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+--- /dev/null
++++ b/lib/lzma/LzFind.c
+@@ -0,0 +1,761 @@
++/* LzFind.c -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++#include "LzFind.h"
++#include "LzHash.h"
++
++#define kEmptyHashValue 0
++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
++#define kNormalizeMask (~(kNormalizeStepMin - 1))
++#define kMaxHistorySize ((UInt32)3 << 30)
++
++#define kStartMaxLen 3
++
++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  if (!p->directInput)
++  {
++    alloc->Free(alloc, p->bufferBase);
++    p->bufferBase = 0;
++  }
++}
++
++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
++
++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
++{
++  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
++  if (p->directInput)
++  {
++    p->blockSize = blockSize;
++    return 1;
++  }
++  if (p->bufferBase == 0 || p->blockSize != blockSize)
++  {
++    LzInWindow_Free(p, alloc);
++    p->blockSize = blockSize;
++    p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
++  }
++  return (p->bufferBase != 0);
++}
++
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++
++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++{
++  p->posLimit -= subValue;
++  p->pos -= subValue;
++  p->streamPos -= subValue;
++}
++
++static void MatchFinder_ReadBlock(CMatchFinder *p)
++{
++  if (p->streamEndWasReached || p->result != SZ_OK)
++    return;
++  if (p->directInput)
++  {
++    UInt32 curSize = 0xFFFFFFFF - p->streamPos;
++    if (curSize > p->directInputRem)
++      curSize = (UInt32)p->directInputRem;
++    p->directInputRem -= curSize;
++    p->streamPos += curSize;
++    if (p->directInputRem == 0)
++      p->streamEndWasReached = 1;
++    return;
++  }
++  for (;;)
++  {
++    Byte *dest = p->buffer + (p->streamPos - p->pos);
++    size_t size = (p->bufferBase + p->blockSize - dest);
++    if (size == 0)
++      return;
++    p->result = p->stream->Read(p->stream, dest, &size);
++    if (p->result != SZ_OK)
++      return;
++    if (size == 0)
++    {
++      p->streamEndWasReached = 1;
++      return;
++    }
++    p->streamPos += (UInt32)size;
++    if (p->streamPos - p->pos > p->keepSizeAfter)
++      return;
++  }
++}
++
++void MatchFinder_MoveBlock(CMatchFinder *p)
++{
++  memmove(p->bufferBase,
++    p->buffer - p->keepSizeBefore,
++    (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
++  p->buffer = p->bufferBase + p->keepSizeBefore;
++}
++
++int MatchFinder_NeedMove(CMatchFinder *p)
++{
++  if (p->directInput)
++    return 0;
++  /* if (p->streamEndWasReached) return 0; */
++  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
++}
++
++void MatchFinder_ReadIfRequired(CMatchFinder *p)
++{
++  if (p->streamEndWasReached)
++    return;
++  if (p->keepSizeAfter >= p->streamPos - p->pos)
++    MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
++{
++  if (MatchFinder_NeedMove(p))
++    MatchFinder_MoveBlock(p);
++  MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
++{
++  p->cutValue = 32;
++  p->btMode = 1;
++  p->numHashBytes = 4;
++  p->bigHash = 0;
++}
++
++#define kCrcPoly 0xEDB88320
++
++void MatchFinder_Construct(CMatchFinder *p)
++{
++  UInt32 i;
++  p->bufferBase = 0;
++  p->directInput = 0;
++  p->hash = 0;
++  MatchFinder_SetDefaultSettings(p);
++
++  for (i = 0; i < 256; i++)
++  {
++    UInt32 r = i;
++    int j;
++    for (j = 0; j < 8; j++)
++      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
++    p->crc[i] = r;
++  }
++}
++
++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->hash);
++  p->hash = 0;
++}
++
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  MatchFinder_FreeThisClassMemory(p, alloc);
++  LzInWindow_Free(p, alloc);
++}
++
++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
++{
++  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
++  if (sizeInBytes / sizeof(CLzRef) != num)
++    return 0;
++  return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
++}
++
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc)
++{
++  UInt32 sizeReserv;
++  if (historySize > kMaxHistorySize)
++  {
++    MatchFinder_Free(p, alloc);
++    return 0;
++  }
++  sizeReserv = historySize >> 1;
++  if (historySize > ((UInt32)2 << 30))
++    sizeReserv = historySize >> 2;
++  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
++
++  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
++  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
++  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
++  if (LzInWindow_Create(p, sizeReserv, alloc))
++  {
++    UInt32 newCyclicBufferSize = historySize + 1;
++    UInt32 hs;
++    p->matchMaxLen = matchMaxLen;
++    {
++      p->fixedHashSize = 0;
++      if (p->numHashBytes == 2)
++        hs = (1 << 16) - 1;
++      else
++      {
++        hs = historySize - 1;
++        hs |= (hs >> 1);
++        hs |= (hs >> 2);
++        hs |= (hs >> 4);
++        hs |= (hs >> 8);
++        hs >>= 1;
++        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
++        if (hs > (1 << 24))
++        {
++          if (p->numHashBytes == 3)
++            hs = (1 << 24) - 1;
++          else
++            hs >>= 1;
++        }
++      }
++      p->hashMask = hs;
++      hs++;
++      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
++      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
++      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
++      hs += p->fixedHashSize;
++    }
++
++    {
++      UInt32 prevSize = p->hashSizeSum + p->numSons;
++      UInt32 newSize;
++      p->historySize = historySize;
++      p->hashSizeSum = hs;
++      p->cyclicBufferSize = newCyclicBufferSize;
++      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
++      newSize = p->hashSizeSum + p->numSons;
++      if (p->hash != 0 && prevSize == newSize)
++        return 1;
++      MatchFinder_FreeThisClassMemory(p, alloc);
++      p->hash = AllocRefs(newSize, alloc);
++      if (p->hash != 0)
++      {
++        p->son = p->hash + p->hashSizeSum;
++        return 1;
++      }
++    }
++  }
++  MatchFinder_Free(p, alloc);
++  return 0;
++}
++
++static void MatchFinder_SetLimits(CMatchFinder *p)
++{
++  UInt32 limit = kMaxValForNormalize - p->pos;
++  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
++  if (limit2 < limit)
++    limit = limit2;
++  limit2 = p->streamPos - p->pos;
++  if (limit2 <= p->keepSizeAfter)
++  {
++    if (limit2 > 0)
++      limit2 = 1;
++  }
++  else
++    limit2 -= p->keepSizeAfter;
++  if (limit2 < limit)
++    limit = limit2;
++  {
++    UInt32 lenLimit = p->streamPos - p->pos;
++    if (lenLimit > p->matchMaxLen)
++      lenLimit = p->matchMaxLen;
++    p->lenLimit = lenLimit;
++  }
++  p->posLimit = p->pos + limit;
++}
++
++void MatchFinder_Init(CMatchFinder *p)
++{
++  UInt32 i;
++  for (i = 0; i < p->hashSizeSum; i++)
++    p->hash[i] = kEmptyHashValue;
++  p->cyclicBufferPos = 0;
++  p->buffer = p->bufferBase;
++  p->pos = p->streamPos = p->cyclicBufferSize;
++  p->result = SZ_OK;
++  p->streamEndWasReached = 0;
++  MatchFinder_ReadBlock(p);
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
++{
++  return (p->pos - p->historySize - 1) & kNormalizeMask;
++}
++
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++{
++  UInt32 i;
++  for (i = 0; i < numItems; i++)
++  {
++    UInt32 value = items[i];
++    if (value <= subValue)
++      value = kEmptyHashValue;
++    else
++      value -= subValue;
++    items[i] = value;
++  }
++}
++
++static void MatchFinder_Normalize(CMatchFinder *p)
++{
++  UInt32 subValue = MatchFinder_GetSubValue(p);
++  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
++  MatchFinder_ReduceOffsets(p, subValue);
++}
++
++static void MatchFinder_CheckLimits(CMatchFinder *p)
++{
++  if (p->pos == kMaxValForNormalize)
++    MatchFinder_Normalize(p);
++  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
++    MatchFinder_CheckAndMoveAndRead(p);
++  if (p->cyclicBufferPos == p->cyclicBufferSize)
++    p->cyclicBufferPos = 0;
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  son[_cyclicBufferPos] = curMatch;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++      return distances;
++    {
++      const Byte *pb = cur - delta;
++      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
++      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
++      {
++        UInt32 len = 0;
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++            return distances;
++        }
++      }
++    }
++  }
++}
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return distances;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        if (++len != lenLimit && pb[len] == cur[len])
++          while (++len != lenLimit)
++            if (pb[len] != cur[len])
++              break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return distances;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        {
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++#define MOVE_POS \
++  ++p->cyclicBufferPos; \
++  p->buffer++; \
++  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
++
++#define MOVE_POS_RET MOVE_POS return offset;
++
++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
++
++#define GET_MATCHES_HEADER2(minLen, ret_op) \
++  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
++  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
++  cur = p->buffer;
++
++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
++#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
++
++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
++
++#define GET_MATCHES_FOOTER(offset, maxLen) \
++  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
++  distances + offset, maxLen) - distances); MOVE_POS_RET;
++
++#define SKIP_FOOTER \
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
++
++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(2)
++  HASH2_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 1)
++}
++
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 2)
++}
++
++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, delta2, maxLen, offset;
++  GET_MATCHES_HEADER(3)
++
++  HASH3_CALC;
++
++  delta2 = p->pos - p->hash[hash2Value];
++  curMatch = p->hash[kFix3HashSize + hashValue];
++  
++  p->hash[hash2Value] =
++  p->hash[kFix3HashSize + hashValue] = p->pos;
++
++
++  maxLen = 2;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[0] = maxLen;
++    distances[1] = delta2 - 1;
++    offset = 2;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++  
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      p->son[p->cyclicBufferPos] = curMatch;
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances + offset, maxLen) - (distances));
++  MOVE_POS_RET
++}
++
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances, 2) - (distances));
++  MOVE_POS_RET
++}
++
++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(2)
++    HASH2_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value;
++    SKIP_HEADER(3)
++    HASH3_CALC;
++    curMatch = p->hash[kFix3HashSize + hashValue];
++    p->hash[hash2Value] =
++    p->hash[kFix3HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] = p->pos;
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] =
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
++{
++  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
++  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
++  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
++  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
++  if (!p->btMode)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 2)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 3)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
++  }
++  else
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
++  }
++}
+--- /dev/null
++++ b/lib/lzma/LzmaDec.c
+@@ -0,0 +1,999 @@
++/* LzmaDec.c -- LZMA Decoder
++2009-09-20 : Igor Pavlov : Public domain */
++
++#include "LzmaDec.h"
++
++#include <string.h>
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_INIT_SIZE 5
++
++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
++  { UPDATE_0(p); i = (i + i); A0; } else \
++  { UPDATE_1(p); i = (i + i) + 1; A1; }
++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
++
++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
++#define TREE_DECODE(probs, limit, i) \
++  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
++
++/* #define _LZMA_SIZE_OPT */
++
++#ifdef _LZMA_SIZE_OPT
++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
++#else
++#define TREE_6_DECODE(probs, i) \
++  { i = 1; \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  i -= 0x40; }
++#endif
++
++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0_CHECK range = bound;
++#define UPDATE_1_CHECK range -= bound; code -= bound;
++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
++  { UPDATE_0_CHECK; i = (i + i); A0; } else \
++  { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
++#define TREE_DECODE_CHECK(probs, limit, i) \
++  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#define LZMA_DIC_MIN (1 << 12)
++
++/* First LZMA-symbol is always decoded.
++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
++Out:
++  Result:
++    SZ_OK - OK
++    SZ_ERROR_DATA - Error
++  p->remainLen:
++    < kMatchSpecLenStart : normal remain
++    = kMatchSpecLenStart : finished
++    = kMatchSpecLenStart + 1 : Flush marker
++    = kMatchSpecLenStart + 2 : State Init Marker
++*/
++
++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  CLzmaProb *probs = p->probs;
++
++  unsigned state = p->state;
++  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
++  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
++  unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
++  unsigned lc = p->prop.lc;
++
++  Byte *dic = p->dic;
++  SizeT dicBufSize = p->dicBufSize;
++  SizeT dicPos = p->dicPos;
++  
++  UInt32 processedPos = p->processedPos;
++  UInt32 checkDicSize = p->checkDicSize;
++  unsigned len = 0;
++
++  const Byte *buf = p->buf;
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++
++  do
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = processedPos & pbMask;
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0(prob)
++    {
++      unsigned symbol;
++      UPDATE_0(prob);
++      prob = probs + Literal;
++      if (checkDicSize != 0 || processedPos != 0)
++        prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
++        (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
++
++      if (state < kNumLitStates)
++      {
++        state -= (state < 4) ? state : 3;
++        symbol = 1;
++        do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++        unsigned offs = 0x100;
++        state -= (state < 10) ? 3 : 6;
++        symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      dic[dicPos++] = (Byte)symbol;
++      processedPos++;
++      continue;
++    }
++    else
++    {
++      UPDATE_1(prob);
++      prob = probs + IsRep + state;
++      IF_BIT_0(prob)
++      {
++        UPDATE_0(prob);
++        state += kNumStates;
++        prob = probs + LenCoder;
++      }
++      else
++      {
++        UPDATE_1(prob);
++        if (checkDicSize == 0 && processedPos == 0)
++          return SZ_ERROR_DATA;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0(prob)
++        {
++          UPDATE_0(prob);
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++            dicPos++;
++            processedPos++;
++            state = state < kNumLitStates ? 9 : 11;
++            continue;
++          }
++          UPDATE_1(prob);
++        }
++        else
++        {
++          UInt32 distance;
++          UPDATE_1(prob);
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            distance = rep1;
++          }
++          else
++          {
++            UPDATE_1(prob);
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0(prob)
++            {
++              UPDATE_0(prob);
++              distance = rep2;
++            }
++            else
++            {
++              UPDATE_1(prob);
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        state = state < kNumLitStates ? 8 : 11;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0(probLen)
++        {
++          UPDATE_0(probLen);
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = (1 << kLenNumLowBits);
++        }
++        else
++        {
++          UPDATE_1(probLen);
++          probLen = prob + LenChoice2;
++          IF_BIT_0(probLen)
++          {
++            UPDATE_0(probLen);
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = (1 << kLenNumMidBits);
++          }
++          else
++          {
++            UPDATE_1(probLen);
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = (1 << kLenNumHighBits);
++          }
++        }
++        TREE_DECODE(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state >= kNumStates)
++      {
++        UInt32 distance;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
++        TREE_6_DECODE(prob, distance);
++        if (distance >= kStartPosModelIndex)
++        {
++          unsigned posSlot = (unsigned)distance;
++          int numDirectBits = (int)(((distance >> 1) - 1));
++          distance = (2 | (distance & 1));
++          if (posSlot < kEndPosModelIndex)
++          {
++            distance <<= numDirectBits;
++            prob = probs + SpecPos + distance - posSlot - 1;
++            {
++              UInt32 mask = 1;
++              unsigned i = 1;
++              do
++              {
++                GET_BIT2(prob + i, i, ; , distance |= mask);
++                mask <<= 1;
++              }
++              while (--numDirectBits != 0);
++            }
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE
++              range >>= 1;
++              
++              {
++                UInt32 t;
++                code -= range;
++                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
++                distance = (distance << 1) + (t + 1);
++                code += range & t;
++              }
++              /*
++              distance <<= 1;
++              if (code >= range)
++              {
++                code -= range;
++                distance |= 1;
++              }
++              */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            distance <<= kNumAlignBits;
++            {
++              unsigned i = 1;
++              GET_BIT2(prob + i, i, ; , distance |= 1);
++              GET_BIT2(prob + i, i, ; , distance |= 2);
++              GET_BIT2(prob + i, i, ; , distance |= 4);
++              GET_BIT2(prob + i, i, ; , distance |= 8);
++            }
++            if (distance == (UInt32)0xFFFFFFFF)
++            {
++              len += kMatchSpecLenStart;
++              state -= kNumStates;
++              break;
++            }
++          }
++        }
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        rep0 = distance + 1;
++        if (checkDicSize == 0)
++        {
++          if (distance >= processedPos)
++            return SZ_ERROR_DATA;
++        }
++        else if (distance >= checkDicSize)
++          return SZ_ERROR_DATA;
++        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
++      }
++
++      len += kMatchMinLen;
++
++      if (limit == dicPos)
++        return SZ_ERROR_DATA;
++      {
++        SizeT rem = limit - dicPos;
++        unsigned curLen = ((rem < len) ? (unsigned)rem : len);
++        SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
++
++        processedPos += curLen;
++
++        len -= curLen;
++        if (pos + curLen <= dicBufSize)
++        {
++          Byte *dest = dic + dicPos;
++          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
++          const Byte *lim = dest + curLen;
++          dicPos += curLen;
++          do
++            *(dest) = (Byte)*(dest + src);
++          while (++dest != lim);
++        }
++        else
++        {
++          do
++          {
++            dic[dicPos++] = dic[pos];
++            if (++pos == dicBufSize)
++              pos = 0;
++          }
++          while (--curLen != 0);
++        }
++      }
++    }
++  }
++  while (dicPos < limit && buf < bufLimit);
++  NORMALIZE;
++  p->buf = buf;
++  p->range = range;
++  p->code = code;
++  p->remainLen = len;
++  p->dicPos = dicPos;
++  p->processedPos = processedPos;
++  p->reps[0] = rep0;
++  p->reps[1] = rep1;
++  p->reps[2] = rep2;
++  p->reps[3] = rep3;
++  p->state = state;
++
++  return SZ_OK;
++}
++
++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
++{
++  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
++  {
++    Byte *dic = p->dic;
++    SizeT dicPos = p->dicPos;
++    SizeT dicBufSize = p->dicBufSize;
++    unsigned len = p->remainLen;
++    UInt32 rep0 = p->reps[0];
++    if (limit - dicPos < len)
++      len = (unsigned)(limit - dicPos);
++
++    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
++      p->checkDicSize = p->prop.dicSize;
++
++    p->processedPos += len;
++    p->remainLen -= len;
++    while (len-- != 0)
++    {
++      dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++      dicPos++;
++    }
++    p->dicPos = dicPos;
++  }
++}
++
++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  do
++  {
++    SizeT limit2 = limit;
++    if (p->checkDicSize == 0)
++    {
++      UInt32 rem = p->prop.dicSize - p->processedPos;
++      if (limit - p->dicPos > rem)
++        limit2 = p->dicPos + rem;
++    }
++    RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
++    if (p->processedPos >= p->prop.dicSize)
++      p->checkDicSize = p->prop.dicSize;
++    LzmaDec_WriteRem(p, limit);
++  }
++  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
++
++  if (p->remainLen > kMatchSpecLenStart)
++  {
++    p->remainLen = kMatchSpecLenStart;
++  }
++  return 0;
++}
++
++typedef enum
++{
++  DUMMY_ERROR, /* unexpected end of input stream */
++  DUMMY_LIT,
++  DUMMY_MATCH,
++  DUMMY_REP
++} ELzmaDummy;
++
++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
++{
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++  const Byte *bufLimit = buf + inSize;
++  CLzmaProb *probs = p->probs;
++  unsigned state = p->state;
++  ELzmaDummy res;
++
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0_CHECK(prob)
++    {
++      UPDATE_0_CHECK
++
++      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
++
++      prob = probs + Literal;
++      if (p->checkDicSize != 0 || p->processedPos != 0)
++        prob += (LZMA_LIT_SIZE *
++          ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
++          (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
++
++      if (state < kNumLitStates)
++      {
++        unsigned symbol = 1;
++        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
++            ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
++        unsigned offs = 0x100;
++        unsigned symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      res = DUMMY_LIT;
++    }
++    else
++    {
++      unsigned len;
++      UPDATE_1_CHECK;
++
++      prob = probs + IsRep + state;
++      IF_BIT_0_CHECK(prob)
++      {
++        UPDATE_0_CHECK;
++        state = 0;
++        prob = probs + LenCoder;
++        res = DUMMY_MATCH;
++      }
++      else
++      {
++        UPDATE_1_CHECK;
++        res = DUMMY_REP;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0_CHECK(prob)
++        {
++          UPDATE_0_CHECK;
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++            NORMALIZE_CHECK;
++            return DUMMY_REP;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++          }
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0_CHECK(prob)
++            {
++              UPDATE_0_CHECK;
++            }
++            else
++            {
++              UPDATE_1_CHECK;
++            }
++          }
++        }
++        state = kNumStates;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0_CHECK(probLen)
++        {
++          UPDATE_0_CHECK;
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = 1 << kLenNumLowBits;
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          probLen = prob + LenChoice2;
++          IF_BIT_0_CHECK(probLen)
++          {
++            UPDATE_0_CHECK;
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = 1 << kLenNumMidBits;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = 1 << kLenNumHighBits;
++          }
++        }
++        TREE_DECODE_CHECK(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state < 4)
++      {
++        unsigned posSlot;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++            kNumPosSlotBits);
++        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++
++          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
++
++          if (posSlot < kEndPosModelIndex)
++          {
++            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE_CHECK
++              range >>= 1;
++              code -= range & (((code - range) >> 31) - 1);
++              /* if (code >= range) code -= range; */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            numDirectBits = kNumAlignBits;
++          }
++          {
++            unsigned i = 1;
++            do
++            {
++              GET_BIT_CHECK(prob + i, i);
++            }
++            while (--numDirectBits != 0);
++          }
++        }
++      }
++    }
++  }
++  NORMALIZE_CHECK;
++  return res;
++}
++
++
++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
++{
++  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->range = 0xFFFFFFFF;
++  p->needFlush = 0;
++}
++
++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++{
++  p->needFlush = 1;
++  p->remainLen = 0;
++  p->tempBufSize = 0;
++
++  if (initDic)
++  {
++    p->processedPos = 0;
++    p->checkDicSize = 0;
++    p->needInitState = 1;
++  }
++  if (initState)
++    p->needInitState = 1;
++}
++
++void LzmaDec_Init(CLzmaDec *p)
++{
++  p->dicPos = 0;
++  LzmaDec_InitDicAndState(p, True, True);
++}
++
++static void LzmaDec_InitStateReal(CLzmaDec *p)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
++  UInt32 i;
++  CLzmaProb *probs = p->probs;
++  for (i = 0; i < numProbs; i++)
++    probs[i] = kBitModelTotal >> 1;
++  p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
++  p->state = 0;
++  p->needInitState = 0;
++}
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++    ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT inSize = *srcLen;
++  (*srcLen) = 0;
++  LzmaDec_WriteRem(p, dicLimit);
++  
++  *status = LZMA_STATUS_NOT_SPECIFIED;
++
++  while (p->remainLen != kMatchSpecLenStart)
++  {
++      int checkEndMarkNow;
++
++      if (p->needFlush != 0)
++      {
++        for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
++          p->tempBuf[p->tempBufSize++] = *src++;
++        if (p->tempBufSize < RC_INIT_SIZE)
++        {
++          *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++          return SZ_OK;
++        }
++        if (p->tempBuf[0] != 0)
++          return SZ_ERROR_DATA;
++
++        LzmaDec_InitRc(p, p->tempBuf);
++        p->tempBufSize = 0;
++      }
++
++      checkEndMarkNow = 0;
++      if (p->dicPos >= dicLimit)
++      {
++        if (p->remainLen == 0 && p->code == 0)
++        {
++          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
++          return SZ_OK;
++        }
++        if (finishMode == LZMA_FINISH_ANY)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_OK;
++        }
++        if (p->remainLen != 0)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_ERROR_DATA;
++        }
++        checkEndMarkNow = 1;
++      }
++
++      if (p->needInitState)
++        LzmaDec_InitStateReal(p);
++  
++      if (p->tempBufSize == 0)
++      {
++        SizeT processed;
++        const Byte *bufLimit;
++        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            memcpy(p->tempBuf, src, inSize);
++            p->tempBufSize = (unsigned)inSize;
++            (*srcLen) += inSize;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++          bufLimit = src;
++        }
++        else
++          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
++        p->buf = src;
++        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
++          return SZ_ERROR_DATA;
++        processed = (SizeT)(p->buf - src);
++        (*srcLen) += processed;
++        src += processed;
++        inSize -= processed;
++      }
++      else
++      {
++        unsigned rem = p->tempBufSize, lookAhead = 0;
++        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
++          p->tempBuf[rem++] = src[lookAhead++];
++        p->tempBufSize = rem;
++        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            (*srcLen) += lookAhead;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++        }
++        p->buf = p->tempBuf;
++        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
++          return SZ_ERROR_DATA;
++        lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
++        (*srcLen) += lookAhead;
++        src += lookAhead;
++        inSize -= lookAhead;
++        p->tempBufSize = 0;
++      }
++  }
++  if (p->code == 0)
++    *status = LZMA_STATUS_FINISHED_WITH_MARK;
++  return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
++}
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT outSize = *destLen;
++  SizeT inSize = *srcLen;
++  *srcLen = *destLen = 0;
++  for (;;)
++  {
++    SizeT inSizeCur = inSize, outSizeCur, dicPos;
++    ELzmaFinishMode curFinishMode;
++    SRes res;
++    if (p->dicPos == p->dicBufSize)
++      p->dicPos = 0;
++    dicPos = p->dicPos;
++    if (outSize > p->dicBufSize - dicPos)
++    {
++      outSizeCur = p->dicBufSize;
++      curFinishMode = LZMA_FINISH_ANY;
++    }
++    else
++    {
++      outSizeCur = dicPos + outSize;
++      curFinishMode = finishMode;
++    }
++
++    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
++    src += inSizeCur;
++    inSize -= inSizeCur;
++    *srcLen += inSizeCur;
++    outSizeCur = p->dicPos - dicPos;
++    memcpy(dest, p->dic + dicPos, outSizeCur);
++    dest += outSizeCur;
++    outSize -= outSizeCur;
++    *destLen += outSizeCur;
++    if (res != 0)
++      return res;
++    if (outSizeCur == 0 || outSize == 0)
++      return SZ_OK;
++  }
++}
++
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->probs);
++  p->probs = 0;
++}
++
++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->dic);
++  p->dic = 0;
++}
++
++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
++{
++  LzmaDec_FreeProbs(p, alloc);
++  LzmaDec_FreeDict(p, alloc);
++}
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++{
++  UInt32 dicSize;
++  Byte d;
++  
++  if (size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_UNSUPPORTED;
++  else
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++ 
++  if (dicSize < LZMA_DIC_MIN)
++    dicSize = LZMA_DIC_MIN;
++  p->dicSize = dicSize;
++
++  d = data[0];
++  if (d >= (9 * 5 * 5))
++    return SZ_ERROR_UNSUPPORTED;
++
++  p->lc = d % 9;
++  d /= 9;
++  p->pb = d / 5;
++  p->lp = d % 5;
++
++  return SZ_OK;
++}
++
++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
++{
++  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
++  if (p->probs == 0 || numProbs != p->numProbs)
++  {
++    LzmaDec_FreeProbs(p, alloc);
++    p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
++    p->numProbs = numProbs;
++    if (p->probs == 0)
++      return SZ_ERROR_MEM;
++  }
++  return SZ_OK;
++}
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  SizeT dicBufSize;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  dicBufSize = propNew.dicSize;
++  if (p->dic == 0 || dicBufSize != p->dicBufSize)
++  {
++    LzmaDec_FreeDict(p, alloc);
++    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
++    if (p->dic == 0)
++    {
++      LzmaDec_FreeProbs(p, alloc);
++      return SZ_ERROR_MEM;
++    }
++  }
++  p->dicBufSize = dicBufSize;
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc)
++{
++  CLzmaDec p;
++  SRes res;
++  SizeT inSize = *srcLen;
++  SizeT outSize = *destLen;
++  *srcLen = *destLen = 0;
++  if (inSize < RC_INIT_SIZE)
++    return SZ_ERROR_INPUT_EOF;
++
++  LzmaDec_Construct(&p);
++  res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
++  if (res != 0)
++    return res;
++  p.dic = dest;
++  p.dicBufSize = outSize;
++
++  LzmaDec_Init(&p);
++  
++  *srcLen = inSize;
++  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
++
++  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
++    res = SZ_ERROR_INPUT_EOF;
++
++  (*destLen) = p.dicPos;
++  LzmaDec_FreeProbs(&p, alloc);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/LzmaEnc.c
+@@ -0,0 +1,2271 @@
++/* LzmaEnc.c -- LZMA Encoder
++2009-11-24 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++/* #define SHOW_STAT */
++/* #define SHOW_STAT2 */
++
++#if defined(SHOW_STAT) || defined(SHOW_STAT2)
++#include <stdio.h>
++#endif
++
++#include "LzmaEnc.h"
++
++/* disable MT */
++#define _7ZIP_ST
++
++#include "LzFind.h"
++#ifndef _7ZIP_ST
++#include "LzFindMt.h"
++#endif
++
++#ifdef SHOW_STAT
++static int ttt = 0;
++#endif
++
++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
++
++#define kBlockSize (9 << 10)
++#define kUnpackBlockSize (1 << 18)
++#define kMatchArraySize (1 << 21)
++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
++
++#define kNumMaxDirectBits (31)
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++#define kProbInitValue (kBitModelTotal >> 1)
++
++#define kNumMoveReducingBits 4
++#define kNumBitPriceShiftBits 4
++#define kBitPrice (1 << kNumBitPriceShiftBits)
++
++void LzmaEncProps_Init(CLzmaEncProps *p)
++{
++  p->level = 5;
++  p->dictSize = p->mc = 0;
++  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
++  p->writeEndMark = 0;
++}
++
++void LzmaEncProps_Normalize(CLzmaEncProps *p)
++{
++  int level = p->level;
++  if (level < 0) level = 5;
++  p->level = level;
++  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
++  if (p->lc < 0) p->lc = 3;
++  if (p->lp < 0) p->lp = 0;
++  if (p->pb < 0) p->pb = 2;
++  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
++  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
++  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
++  if (p->numHashBytes < 0) p->numHashBytes = 4;
++  if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
++  if (p->numThreads < 0)
++    p->numThreads =
++      #ifndef _7ZIP_ST
++      ((p->btMode && p->algo) ? 2 : 1);
++      #else
++      1;
++      #endif
++}
++
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++{
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++  return props.dictSize;
++}
++
++/* #define LZMA_LOG_BSR */
++/* Define it for Intel's CPU */
++
++
++#ifdef LZMA_LOG_BSR
++
++#define kDicLogSizeMaxCompress 30
++
++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
++
++UInt32 GetPosSlot1(UInt32 pos)
++{
++  UInt32 res;
++  BSR2_RET(pos, res);
++  return res;
++}
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
++
++#else
++
++#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
++
++void LzmaEnc_FastPosInit(Byte *g_FastPos)
++{
++  int c = 2, slotFast;
++  g_FastPos[0] = 0;
++  g_FastPos[1] = 1;
++  
++  for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
++  {
++    UInt32 k = (1 << ((slotFast >> 1) - 1));
++    UInt32 j;
++    for (j = 0; j < k; j++, c++)
++      g_FastPos[c] = (Byte)slotFast;
++  }
++}
++
++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
++  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
++  res = p->g_FastPos[pos >> i] + (i * 2); }
++/*
++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
++  p->g_FastPos[pos >> 6] + 12 : \
++  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
++*/
++
++#define GetPosSlot1(pos) p->g_FastPos[pos]
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
++
++#endif
++
++
++#define LZMA_NUM_REPS 4
++
++typedef unsigned CState;
++
++typedef struct
++{
++  UInt32 price;
++
++  CState state;
++  int prev1IsChar;
++  int prev2;
++
++  UInt32 posPrev2;
++  UInt32 backPrev2;
++
++  UInt32 posPrev;
++  UInt32 backPrev;
++  UInt32 backs[LZMA_NUM_REPS];
++} COptimal;
++
++#define kNumOpts (1 << 12)
++
++#define kNumLenToPosStates 4
++#define kNumPosSlotBits 6
++#define kDicLogSizeMin 0
++#define kDicLogSizeMax 32
++#define kDistTableSizeMax (kDicLogSizeMax * 2)
++
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++#define kAlignMask (kAlignTableSize - 1)
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
++
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++#define LZMA_PB_MAX 4
++#define LZMA_LC_MAX 8
++#define LZMA_LP_MAX 4
++
++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
++
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define LZMA_MATCH_LEN_MIN 2
++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
++
++#define kNumStates 12
++
++typedef struct
++{
++  CLzmaProb choice;
++  CLzmaProb choice2;
++  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
++  CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
++  CLzmaProb high[kLenNumHighSymbols];
++} CLenEnc;
++
++typedef struct
++{
++  CLenEnc p;
++  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
++  UInt32 tableSize;
++  UInt32 counters[LZMA_NUM_PB_STATES_MAX];
++} CLenPriceEnc;
++
++typedef struct
++{
++  UInt32 range;
++  Byte cache;
++  UInt64 low;
++  UInt64 cacheSize;
++  Byte *buf;
++  Byte *bufLim;
++  Byte *bufBase;
++  ISeqOutStream *outStream;
++  UInt64 processed;
++  SRes res;
++} CRangeEnc;
++
++typedef struct
++{
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++} CSaveState;
++
++typedef struct
++{
++  IMatchFinder matchFinder;
++  void *matchFinderObj;
++
++  #ifndef _7ZIP_ST
++  Bool mtMode;
++  CMatchFinderMt matchFinderMt;
++  #endif
++
++  CMatchFinder matchFinderBase;
++
++  #ifndef _7ZIP_ST
++  Byte pad[128];
++  #endif
++  
++  UInt32 optimumEndIndex;
++  UInt32 optimumCurrentIndex;
++
++  UInt32 longestMatchLength;
++  UInt32 numPairs;
++  UInt32 numAvail;
++  COptimal opt[kNumOpts];
++  
++  #ifndef LZMA_LOG_BSR
++  Byte g_FastPos[1 << kNumLogBits];
++  #endif
++
++  UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
++  UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
++  UInt32 numFastBytes;
++  UInt32 additionalOffset;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++
++  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
++  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
++  UInt32 alignPrices[kAlignTableSize];
++  UInt32 alignPriceCount;
++
++  UInt32 distTableSize;
++
++  unsigned lc, lp, pb;
++  unsigned lpMask, pbMask;
++
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  unsigned lclp;
++
++  Bool fastMode;
++  
++  CRangeEnc rc;
++
++  Bool writeEndMark;
++  UInt64 nowPos64;
++  UInt32 matchPriceCount;
++  Bool finished;
++  Bool multiThread;
++
++  SRes result;
++  UInt32 dictSize;
++  UInt32 matchFinderCycles;
++
++  int needInit;
++
++  CSaveState saveState;
++} CLzmaEnc;
++
++void LzmaEnc_SaveState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CSaveState *dest = &p->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
++}
++
++void LzmaEnc_RestoreState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *dest = (CLzmaEnc *)pp;
++  const CSaveState *p = &dest->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
++}
++
++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++
++  if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
++      props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
++    return SZ_ERROR_PARAM;
++  p->dictSize = props.dictSize;
++  p->matchFinderCycles = props.mc;
++  {
++    unsigned fb = props.fb;
++    if (fb < 5)
++      fb = 5;
++    if (fb > LZMA_MATCH_LEN_MAX)
++      fb = LZMA_MATCH_LEN_MAX;
++    p->numFastBytes = fb;
++  }
++  p->lc = props.lc;
++  p->lp = props.lp;
++  p->pb = props.pb;
++  p->fastMode = (props.algo == 0);
++  p->matchFinderBase.btMode = props.btMode;
++  {
++    UInt32 numHashBytes = 4;
++    if (props.btMode)
++    {
++      if (props.numHashBytes < 2)
++        numHashBytes = 2;
++      else if (props.numHashBytes < 4)
++        numHashBytes = props.numHashBytes;
++    }
++    p->matchFinderBase.numHashBytes = numHashBytes;
++  }
++
++  p->matchFinderBase.cutValue = props.mc;
++
++  p->writeEndMark = props.writeEndMark;
++
++  #ifndef _7ZIP_ST
++  /*
++  if (newMultiThread != _multiThread)
++  {
++    ReleaseMatchFinder();
++    _multiThread = newMultiThread;
++  }
++  */
++  p->multiThread = (props.numThreads > 1);
++  #endif
++
++  return SZ_OK;
++}
++
++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
++static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
++static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
++
++#define IsCharState(s) ((s) < 7)
++
++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
++
++#define kInfinityPrice (1 << 30)
++
++static void RangeEnc_Construct(CRangeEnc *p)
++{
++  p->outStream = 0;
++  p->bufBase = 0;
++}
++
++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
++
++#define RC_BUF_SIZE (1 << 16)
++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
++{
++  if (p->bufBase == 0)
++  {
++    p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
++    if (p->bufBase == 0)
++      return 0;
++    p->bufLim = p->bufBase + RC_BUF_SIZE;
++  }
++  return 1;
++}
++
++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->bufBase);
++  p->bufBase = 0;
++}
++
++static void RangeEnc_Init(CRangeEnc *p)
++{
++  /* Stream.Init(); */
++  p->low = 0;
++  p->range = 0xFFFFFFFF;
++  p->cacheSize = 1;
++  p->cache = 0;
++
++  p->buf = p->bufBase;
++
++  p->processed = 0;
++  p->res = SZ_OK;
++}
++
++static void RangeEnc_FlushStream(CRangeEnc *p)
++{
++  size_t num;
++  if (p->res != SZ_OK)
++    return;
++  num = p->buf - p->bufBase;
++  if (num != p->outStream->Write(p->outStream, p->bufBase, num))
++    p->res = SZ_ERROR_WRITE;
++  p->processed += num;
++  p->buf = p->bufBase;
++}
++
++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
++{
++  if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
++  {
++    Byte temp = p->cache;
++    do
++    {
++      Byte *buf = p->buf;
++      *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
++      p->buf = buf;
++      if (buf == p->bufLim)
++        RangeEnc_FlushStream(p);
++      temp = 0xFF;
++    }
++    while (--p->cacheSize != 0);
++    p->cache = (Byte)((UInt32)p->low >> 24);
++  }
++  p->cacheSize++;
++  p->low = (UInt32)p->low << 8;
++}
++
++static void RangeEnc_FlushData(CRangeEnc *p)
++{
++  int i;
++  for (i = 0; i < 5; i++)
++    RangeEnc_ShiftLow(p);
++}
++
++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
++{
++  do
++  {
++    p->range >>= 1;
++    p->low += p->range & (0 - ((value >> --numBits) & 1));
++    if (p->range < kTopValue)
++    {
++      p->range <<= 8;
++      RangeEnc_ShiftLow(p);
++    }
++  }
++  while (numBits != 0);
++}
++
++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
++{
++  UInt32 ttt = *prob;
++  UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
++  if (symbol == 0)
++  {
++    p->range = newBound;
++    ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
++  }
++  else
++  {
++    p->low += newBound;
++    p->range -= newBound;
++    ttt -= ttt >> kNumMoveBits;
++  }
++  *prob = (CLzmaProb)ttt;
++  if (p->range < kTopValue)
++  {
++    p->range <<= 8;
++    RangeEnc_ShiftLow(p);
++  }
++}
++
++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
++{
++  symbol |= 0x100;
++  do
++  {
++    RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++}
++
++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
++{
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++}
++
++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++{
++  UInt32 i;
++  for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
++  {
++    const int kCyclesBits = kNumBitPriceShiftBits;
++    UInt32 w = i;
++    UInt32 bitCount = 0;
++    int j;
++    for (j = 0; j < kCyclesBits; j++)
++    {
++      w = w * w;
++      bitCount <<= 1;
++      while (w >= ((UInt32)1 << 16))
++      {
++        w >>= 1;
++        bitCount++;
++      }
++    }
++    ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
++  }
++}
++
++
++#define GET_PRICE(prob, symbol) \
++  p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICEa(prob, symbol) \
++  ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= 0x100;
++  do
++  {
++    price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++
++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0;)
++  {
++    UInt32 bit;
++    i--;
++    bit = (symbol >> i) & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++  }
++}
++
++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = 0; i < numBitLevels; i++)
++  {
++    UInt32 bit = symbol & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++    symbol >>= 1;
++  }
++}
++
++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= (1 << numBitLevels);
++  while (symbol != 1)
++  {
++    price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
++    symbol >>= 1;
++  }
++  return price;
++}
++
++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0; i--)
++  {
++    UInt32 bit = symbol & 1;
++    symbol >>= 1;
++    price += GET_PRICEa(probs[m], bit);
++    m = (m << 1) | bit;
++  }
++  return price;
++}
++
++
++static void LenEnc_Init(CLenEnc *p)
++{
++  unsigned i;
++  p->choice = p->choice2 = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
++    p->low[i] = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
++    p->mid[i] = kProbInitValue;
++  for (i = 0; i < kLenNumHighSymbols; i++)
++    p->high[i] = kProbInitValue;
++}
++
++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
++{
++  if (symbol < kLenNumLowSymbols)
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 0);
++    RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
++  }
++  else
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 1);
++    if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 0);
++      RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
++    }
++    else
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 1);
++      RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
++    }
++  }
++}
++
++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
++{
++  UInt32 a0 = GET_PRICE_0a(p->choice);
++  UInt32 a1 = GET_PRICE_1a(p->choice);
++  UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
++  UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
++  UInt32 i = 0;
++  for (i = 0; i < kLenNumLowSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
++  }
++  for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
++  }
++  for (; i < numSymbols; i++)
++    prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
++}
++
++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
++{
++  LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
++  p->counters[posState] = p->tableSize;
++}
++
++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
++{
++  UInt32 posState;
++  for (posState = 0; posState < numPosStates; posState++)
++    LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
++{
++  LenEnc_Encode(&p->p, rc, symbol, posState);
++  if (updatePrice)
++    if (--p->counters[posState] == 0)
++      LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++
++
++
++static void MovePos(CLzmaEnc *p, UInt32 num)
++{
++  #ifdef SHOW_STAT
++  ttt += num;
++  printf("\n MovePos %d", num);
++  #endif
++  if (num != 0)
++  {
++    p->additionalOffset += num;
++    p->matchFinder.Skip(p->matchFinderObj, num);
++  }
++}
++
++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
++{
++  UInt32 lenRes = 0, numPairs;
++  p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++  numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
++  #ifdef SHOW_STAT
++  printf("\n i = %d numPairs = %d    ", ttt, numPairs / 2);
++  ttt++;
++  {
++    UInt32 i;
++    for (i = 0; i < numPairs; i += 2)
++      printf("%2d %6d   | ", p->matches[i], p->matches[i + 1]);
++  }
++  #endif
++  if (numPairs > 0)
++  {
++    lenRes = p->matches[numPairs - 2];
++    if (lenRes == p->numFastBytes)
++    {
++      const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++      UInt32 distance = p->matches[numPairs - 1] + 1;
++      UInt32 numAvail = p->numAvail;
++      if (numAvail > LZMA_MATCH_LEN_MAX)
++        numAvail = LZMA_MATCH_LEN_MAX;
++      {
++        const Byte *pby2 = pby - distance;
++        for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
++      }
++    }
++  }
++  p->additionalOffset++;
++  *numDistancePairsRes = numPairs;
++  return lenRes;
++}
++
++
++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
++#define IsShortRep(p) ((p)->backPrev == 0)
++
++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
++{
++  return
++    GET_PRICE_0(p->isRepG0[state]) +
++    GET_PRICE_0(p->isRep0Long[state][posState]);
++}
++
++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
++{
++  UInt32 price;
++  if (repIndex == 0)
++  {
++    price = GET_PRICE_0(p->isRepG0[state]);
++    price += GET_PRICE_1(p->isRep0Long[state][posState]);
++  }
++  else
++  {
++    price = GET_PRICE_1(p->isRepG0[state]);
++    if (repIndex == 1)
++      price += GET_PRICE_0(p->isRepG1[state]);
++    else
++    {
++      price += GET_PRICE_1(p->isRepG1[state]);
++      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
++    }
++  }
++  return price;
++}
++
++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
++{
++  return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
++    GetPureRepPrice(p, repIndex, state, posState);
++}
++
++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
++{
++  UInt32 posMem = p->opt[cur].posPrev;
++  UInt32 backMem = p->opt[cur].backPrev;
++  p->optimumEndIndex = cur;
++  do
++  {
++    if (p->opt[cur].prev1IsChar)
++    {
++      MakeAsChar(&p->opt[posMem])
++      p->opt[posMem].posPrev = posMem - 1;
++      if (p->opt[cur].prev2)
++      {
++        p->opt[posMem - 1].prev1IsChar = False;
++        p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
++        p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
++      }
++    }
++    {
++      UInt32 posPrev = posMem;
++      UInt32 backCur = backMem;
++      
++      backMem = p->opt[posPrev].backPrev;
++      posMem = p->opt[posPrev].posPrev;
++      
++      p->opt[posPrev].backPrev = backCur;
++      p->opt[posPrev].posPrev = cur;
++      cur = posPrev;
++    }
++  }
++  while (cur != 0);
++  *backRes = p->opt[0].backPrev;
++  p->optimumCurrentIndex  = p->opt[0].posPrev;
++  return p->optimumCurrentIndex;
++}
++
++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
++
++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
++  UInt32 matchPrice, repMatchPrice, normalMatchPrice;
++  UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
++  UInt32 *matches;
++  const Byte *data;
++  Byte curByte, matchByte;
++  if (p->optimumEndIndex != p->optimumCurrentIndex)
++  {
++    const COptimal *opt = &p->opt[p->optimumCurrentIndex];
++    UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
++    *backRes = opt->backPrev;
++    p->optimumCurrentIndex = opt->posPrev;
++    return lenRes;
++  }
++  p->optimumCurrentIndex = p->optimumEndIndex = 0;
++  
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  if (numAvail < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  repMaxIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 lenTest;
++    const Byte *data2;
++    reps[i] = p->reps[i];
++    data2 = data - (reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++    repLens[i] = lenTest;
++    if (lenTest > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  if (repLens[repMaxIndex] >= p->numFastBytes)
++  {
++    UInt32 lenRes;
++    *backRes = repMaxIndex;
++    lenRes = repLens[repMaxIndex];
++    MovePos(p, lenRes - 1);
++    return lenRes;
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++  curByte = *data;
++  matchByte = *(data - (reps[0] + 1));
++
++  if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
++  {
++    *backRes = (UInt32)-1;
++    return 1;
++  }
++
++  p->opt[0].state = (CState)p->state;
++
++  posState = (position & p->pbMask);
++
++  {
++    const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++    p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
++        (!IsCharState(p->state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++  }
++
++  MakeAsChar(&p->opt[1]);
++
++  matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
++  repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
++
++  if (matchByte == curByte)
++  {
++    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
++    if (shortRepPrice < p->opt[1].price)
++    {
++      p->opt[1].price = shortRepPrice;
++      MakeAsShortRep(&p->opt[1]);
++    }
++  }
++  lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
++
++  if (lenEnd < 2)
++  {
++    *backRes = p->opt[1].backPrev;
++    return 1;
++  }
++
++  p->opt[1].posPrev = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++    p->opt[0].backs[i] = reps[i];
++
++  len = lenEnd;
++  do
++    p->opt[len--].price = kInfinityPrice;
++  while (len >= 2);
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 repLen = repLens[i];
++    UInt32 price;
++    if (repLen < 2)
++      continue;
++    price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
++    do
++    {
++      UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
++      COptimal *opt = &p->opt[repLen];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = i;
++        opt->prev1IsChar = False;
++      }
++    }
++    while (--repLen >= 2);
++  }
++
++  normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
++
++  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
++  if (len <= mainLen)
++  {
++    UInt32 offs = 0;
++    while (len > matches[offs])
++      offs += 2;
++    for (; ; len++)
++    {
++      COptimal *opt;
++      UInt32 distance = matches[offs + 1];
++
++      UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
++      UInt32 lenToPosState = GetLenToPosState(len);
++      if (distance < kNumFullDistances)
++        curAndLenPrice += p->distancesPrices[lenToPosState][distance];
++      else
++      {
++        UInt32 slot;
++        GetPosSlot2(distance, slot);
++        curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
++      }
++      opt = &p->opt[len];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = distance + LZMA_NUM_REPS;
++        opt->prev1IsChar = False;
++      }
++      if (len == matches[offs])
++      {
++        offs += 2;
++        if (offs == numPairs)
++          break;
++      }
++    }
++  }
++
++  cur = 0;
++
++    #ifdef SHOW_STAT2
++    if (position >= 0)
++    {
++      unsigned i;
++      printf("\n pos = %4X", position);
++      for (i = cur; i <= lenEnd; i++)
++      printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
++    }
++    #endif
++
++  for (;;)
++  {
++    UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
++    UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
++    Bool nextIsChar;
++    Byte curByte, matchByte;
++    const Byte *data;
++    COptimal *curOpt;
++    COptimal *nextOpt;
++
++    cur++;
++    if (cur == lenEnd)
++      return Backward(p, backRes, cur);
++
++    newLen = ReadMatchDistances(p, &numPairs);
++    if (newLen >= p->numFastBytes)
++    {
++      p->numPairs = numPairs;
++      p->longestMatchLength = newLen;
++      return Backward(p, backRes, cur);
++    }
++    position++;
++    curOpt = &p->opt[cur];
++    posPrev = curOpt->posPrev;
++    if (curOpt->prev1IsChar)
++    {
++      posPrev--;
++      if (curOpt->prev2)
++      {
++        state = p->opt[curOpt->posPrev2].state;
++        if (curOpt->backPrev2 < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      else
++        state = p->opt[posPrev].state;
++      state = kLiteralNextStates[state];
++    }
++    else
++      state = p->opt[posPrev].state;
++    if (posPrev == cur - 1)
++    {
++      if (IsShortRep(curOpt))
++        state = kShortRepNextStates[state];
++      else
++        state = kLiteralNextStates[state];
++    }
++    else
++    {
++      UInt32 pos;
++      const COptimal *prevOpt;
++      if (curOpt->prev1IsChar && curOpt->prev2)
++      {
++        posPrev = curOpt->posPrev2;
++        pos = curOpt->backPrev2;
++        state = kRepNextStates[state];
++      }
++      else
++      {
++        pos = curOpt->backPrev;
++        if (pos < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      prevOpt = &p->opt[posPrev];
++      if (pos < LZMA_NUM_REPS)
++      {
++        UInt32 i;
++        reps[0] = prevOpt->backs[pos];
++        for (i = 1; i <= pos; i++)
++          reps[i] = prevOpt->backs[i - 1];
++        for (; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i];
++      }
++      else
++      {
++        UInt32 i;
++        reps[0] = (pos - LZMA_NUM_REPS);
++        for (i = 1; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i - 1];
++      }
++    }
++    curOpt->state = (CState)state;
++
++    curOpt->backs[0] = reps[0];
++    curOpt->backs[1] = reps[1];
++    curOpt->backs[2] = reps[2];
++    curOpt->backs[3] = reps[3];
++
++    curPrice = curOpt->price;
++    nextIsChar = False;
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    curByte = *data;
++    matchByte = *(data - (reps[0] + 1));
++
++    posState = (position & p->pbMask);
++
++    curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
++    {
++      const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++      curAnd1Price +=
++        (!IsCharState(state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++    }
++
++    nextOpt = &p->opt[cur + 1];
++
++    if (curAnd1Price < nextOpt->price)
++    {
++      nextOpt->price = curAnd1Price;
++      nextOpt->posPrev = cur;
++      MakeAsChar(nextOpt);
++      nextIsChar = True;
++    }
++
++    matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
++    repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
++    
++    if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
++    {
++      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
++      if (shortRepPrice <= nextOpt->price)
++      {
++        nextOpt->price = shortRepPrice;
++        nextOpt->posPrev = cur;
++        MakeAsShortRep(nextOpt);
++        nextIsChar = True;
++      }
++    }
++    numAvailFull = p->numAvail;
++    {
++      UInt32 temp = kNumOpts - 1 - cur;
++      if (temp < numAvailFull)
++        numAvailFull = temp;
++    }
++
++    if (numAvailFull < 2)
++      continue;
++    numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
++
++    if (!nextIsChar && matchByte != curByte) /* speed optimization */
++    {
++      /* try Literal + rep0 */
++      UInt32 temp;
++      UInt32 lenTest2;
++      const Byte *data2 = data - (reps[0] + 1);
++      UInt32 limit = p->numFastBytes + 1;
++      if (limit > numAvailFull)
++        limit = numAvailFull;
++
++      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
++      lenTest2 = temp - 1;
++      if (lenTest2 >= 2)
++      {
++        UInt32 state2 = kLiteralNextStates[state];
++        UInt32 posStateNext = (position + 1) & p->pbMask;
++        UInt32 nextRepMatchPrice = curAnd1Price +
++            GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++            GET_PRICE_1(p->isRep[state2]);
++        /* for (; lenTest2 >= 2; lenTest2--) */
++        {
++          UInt32 curAndLenPrice;
++          COptimal *opt;
++          UInt32 offset = cur + 1 + lenTest2;
++          while (lenEnd < offset)
++            p->opt[++lenEnd].price = kInfinityPrice;
++          curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++          opt = &p->opt[offset];
++          if (curAndLenPrice < opt->price)
++          {
++            opt->price = curAndLenPrice;
++            opt->posPrev = cur + 1;
++            opt->backPrev = 0;
++            opt->prev1IsChar = True;
++            opt->prev2 = False;
++          }
++        }
++      }
++    }
++    
++    startLen = 2; /* speed optimization */
++    {
++    UInt32 repIndex;
++    for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
++    {
++      UInt32 lenTest;
++      UInt32 lenTestTemp;
++      UInt32 price;
++      const Byte *data2 = data - (reps[repIndex] + 1);
++      if (data[0] != data2[0] || data[1] != data2[1])
++        continue;
++      for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++      while (lenEnd < cur + lenTest)
++        p->opt[++lenEnd].price = kInfinityPrice;
++      lenTestTemp = lenTest;
++      price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
++      do
++      {
++        UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
++        COptimal *opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = repIndex;
++          opt->prev1IsChar = False;
++        }
++      }
++      while (--lenTest >= 2);
++      lenTest = lenTestTemp;
++      
++      if (repIndex == 0)
++        startLen = lenTest + 1;
++        
++      /* if (_maxMode) */
++        {
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kRepNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice =
++                price + p->repLenEnc.prices[posState][lenTest - 2] +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (position + lenTest + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = repIndex;
++              }
++            }
++          }
++        }
++    }
++    }
++    /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
++    if (newLen > numAvail)
++    {
++      newLen = numAvail;
++      for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
++      matches[numPairs] = newLen;
++      numPairs += 2;
++    }
++    if (newLen >= startLen)
++    {
++      UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
++      UInt32 offs, curBack, posSlot;
++      UInt32 lenTest;
++      while (lenEnd < cur + newLen)
++        p->opt[++lenEnd].price = kInfinityPrice;
++
++      offs = 0;
++      while (startLen > matches[offs])
++        offs += 2;
++      curBack = matches[offs + 1];
++      GetPosSlot2(curBack, posSlot);
++      for (lenTest = /*2*/ startLen; ; lenTest++)
++      {
++        UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
++        UInt32 lenToPosState = GetLenToPosState(lenTest);
++        COptimal *opt;
++        if (curBack < kNumFullDistances)
++          curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
++        else
++          curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
++        
++        opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = curBack + LZMA_NUM_REPS;
++          opt->prev1IsChar = False;
++        }
++
++        if (/*_maxMode && */lenTest == matches[offs])
++        {
++          /* Try Match + Literal + Rep0 */
++          const Byte *data2 = data - (curBack + 1);
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kMatchNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = curAndLenPrice +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (posStateNext + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = curBack + LZMA_NUM_REPS;
++              }
++            }
++          }
++          offs += 2;
++          if (offs == numPairs)
++            break;
++          curBack = matches[offs + 1];
++          if (curBack >= kNumFullDistances)
++            GetPosSlot2(curBack, posSlot);
++        }
++      }
++    }
++  }
++}
++
++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
++
++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
++  const Byte *data;
++  const UInt32 *matches;
++
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  *backRes = (UInt32)-1;
++  if (numAvail < 2)
++    return 1;
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++
++  repLen = repIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    for (len = 2; len < numAvail && data[len] == data2[len]; len++);
++    if (len >= p->numFastBytes)
++    {
++      *backRes = i;
++      MovePos(p, len - 1);
++      return len;
++    }
++    if (len > repLen)
++    {
++      repIndex = i;
++      repLen = len;
++    }
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++
++  mainDist = 0; /* for GCC */
++  if (mainLen >= 2)
++  {
++    mainDist = matches[numPairs - 1];
++    while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
++    {
++      if (!ChangePair(matches[numPairs - 3], mainDist))
++        break;
++      numPairs -= 2;
++      mainLen = matches[numPairs - 2];
++      mainDist = matches[numPairs - 1];
++    }
++    if (mainLen == 2 && mainDist >= 0x80)
++      mainLen = 1;
++  }
++
++  if (repLen >= 2 && (
++        (repLen + 1 >= mainLen) ||
++        (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
++        (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
++  {
++    *backRes = repIndex;
++    MovePos(p, repLen - 1);
++    return repLen;
++  }
++  
++  if (mainLen < 2 || numAvail <= 2)
++    return 1;
++
++  p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
++  if (p->longestMatchLength >= 2)
++  {
++    UInt32 newDistance = matches[p->numPairs - 1];
++    if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
++        (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
++        (p->longestMatchLength > mainLen + 1) ||
++        (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
++      return 1;
++  }
++  
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len, limit;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    limit = mainLen - 1;
++    for (len = 2; len < limit && data[len] == data2[len]; len++);
++    if (len >= limit)
++      return 1;
++  }
++  *backRes = mainDist + LZMA_NUM_REPS;
++  MovePos(p, mainLen - 2);
++  return mainLen;
++}
++
++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
++{
++  UInt32 len;
++  RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++  RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++  p->state = kMatchNextStates[p->state];
++  len = LZMA_MATCH_LEN_MIN;
++  LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++  RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
++  RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
++  RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
++}
++
++static SRes CheckErrors(CLzmaEnc *p)
++{
++  if (p->result != SZ_OK)
++    return p->result;
++  if (p->rc.res != SZ_OK)
++    p->result = SZ_ERROR_WRITE;
++  if (p->matchFinderBase.result != SZ_OK)
++    p->result = SZ_ERROR_READ;
++  if (p->result != SZ_OK)
++    p->finished = True;
++  return p->result;
++}
++
++static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
++{
++  /* ReleaseMFStream(); */
++  p->finished = True;
++  if (p->writeEndMark)
++    WriteEndMarker(p, nowPos & p->pbMask);
++  RangeEnc_FlushData(&p->rc);
++  RangeEnc_FlushStream(&p->rc);
++  return CheckErrors(p);
++}
++
++static void FillAlignPrices(CLzmaEnc *p)
++{
++  UInt32 i;
++  for (i = 0; i < kAlignTableSize; i++)
++    p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
++  p->alignPriceCount = 0;
++}
++
++static void FillDistancesPrices(CLzmaEnc *p)
++{
++  UInt32 tempPrices[kNumFullDistances];
++  UInt32 i, lenToPosState;
++  for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
++  {
++    UInt32 posSlot = GetPosSlot1(i);
++    UInt32 footerBits = ((posSlot >> 1) - 1);
++    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++    tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
++  }
++
++  for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
++  {
++    UInt32 posSlot;
++    const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
++    UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
++    for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
++    for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
++
++    {
++      UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
++      UInt32 i;
++      for (i = 0; i < kStartPosModelIndex; i++)
++        distancesPrices[i] = posSlotPrices[i];
++      for (; i < kNumFullDistances; i++)
++        distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
++    }
++  }
++  p->matchPriceCount = 0;
++}
++
++void LzmaEnc_Construct(CLzmaEnc *p)
++{
++  RangeEnc_Construct(&p->rc);
++  MatchFinder_Construct(&p->matchFinderBase);
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Construct(&p->matchFinderMt);
++  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
++  #endif
++
++  {
++    CLzmaEncProps props;
++    LzmaEncProps_Init(&props);
++    LzmaEnc_SetProps(p, &props);
++  }
++
++  #ifndef LZMA_LOG_BSR
++  LzmaEnc_FastPosInit(p->g_FastPos);
++  #endif
++
++  LzmaEnc_InitPriceTables(p->ProbPrices);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
++{
++  void *p;
++  p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
++  if (p != 0)
++    LzmaEnc_Construct((CLzmaEnc *)p);
++  return p;
++}
++
++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->litProbs);
++  alloc->Free(alloc, p->saveState.litProbs);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
++  #endif
++  MatchFinder_Free(&p->matchFinderBase, allocBig);
++  LzmaEnc_FreeLits(p, alloc);
++  RangeEnc_Free(&p->rc, alloc);
++}
++
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
++  alloc->Free(alloc, p);
++}
++
++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
++{
++  UInt32 nowPos32, startPos32;
++  if (p->needInit)
++  {
++    p->matchFinder.Init(p->matchFinderObj);
++    p->needInit = 0;
++  }
++
++  if (p->finished)
++    return p->result;
++  RINOK(CheckErrors(p));
++
++  nowPos32 = (UInt32)p->nowPos64;
++  startPos32 = nowPos32;
++
++  if (p->nowPos64 == 0)
++  {
++    UInt32 numPairs;
++    Byte curByte;
++    if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++      return Flush(p, nowPos32);
++    ReadMatchDistances(p, &numPairs);
++    RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
++    p->state = kLiteralNextStates[p->state];
++    curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
++    LitEnc_Encode(&p->rc, p->litProbs, curByte);
++    p->additionalOffset--;
++    nowPos32++;
++  }
++
++  if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
++  for (;;)
++  {
++    UInt32 pos, len, posState;
++
++    if (p->fastMode)
++      len = GetOptimumFast(p, &pos);
++    else
++      len = GetOptimum(p, nowPos32, &pos);
++
++    #ifdef SHOW_STAT2
++    printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
++    #endif
++
++    posState = nowPos32 & p->pbMask;
++    if (len == 1 && pos == (UInt32)-1)
++    {
++      Byte curByte;
++      CLzmaProb *probs;
++      const Byte *data;
++
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
++      data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++      curByte = *data;
++      probs = LIT_PROBS(nowPos32, *(data - 1));
++      if (IsCharState(p->state))
++        LitEnc_Encode(&p->rc, probs, curByte);
++      else
++        LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
++      p->state = kLiteralNextStates[p->state];
++    }
++    else
++    {
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++      if (pos < LZMA_NUM_REPS)
++      {
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
++        if (pos == 0)
++        {
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
++          RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
++        }
++        else
++        {
++          UInt32 distance = p->reps[pos];
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
++          if (pos == 1)
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
++          else
++          {
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
++            if (pos == 3)
++              p->reps[3] = p->reps[2];
++            p->reps[2] = p->reps[1];
++          }
++          p->reps[1] = p->reps[0];
++          p->reps[0] = distance;
++        }
++        if (len == 1)
++          p->state = kShortRepNextStates[p->state];
++        else
++        {
++          LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++          p->state = kRepNextStates[p->state];
++        }
++      }
++      else
++      {
++        UInt32 posSlot;
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++        p->state = kMatchNextStates[p->state];
++        LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++        pos -= LZMA_NUM_REPS;
++        GetPosSlot(pos, posSlot);
++        RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
++        
++        if (posSlot >= kStartPosModelIndex)
++        {
++          UInt32 footerBits = ((posSlot >> 1) - 1);
++          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++          UInt32 posReduced = pos - base;
++
++          if (posSlot < kEndPosModelIndex)
++            RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
++          else
++          {
++            RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
++            RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
++            p->alignPriceCount++;
++          }
++        }
++        p->reps[3] = p->reps[2];
++        p->reps[2] = p->reps[1];
++        p->reps[1] = p->reps[0];
++        p->reps[0] = pos;
++        p->matchPriceCount++;
++      }
++    }
++    p->additionalOffset -= len;
++    nowPos32 += len;
++    if (p->additionalOffset == 0)
++    {
++      UInt32 processed;
++      if (!p->fastMode)
++      {
++        if (p->matchPriceCount >= (1 << 7))
++          FillDistancesPrices(p);
++        if (p->alignPriceCount >= kAlignTableSize)
++          FillAlignPrices(p);
++      }
++      if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++        break;
++      processed = nowPos32 - startPos32;
++      if (useLimits)
++      {
++        if (processed + kNumOpts + 300 >= maxUnpackSize ||
++            RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
++          break;
++      }
++      else if (processed >= (1 << 15))
++      {
++        p->nowPos64 += nowPos32 - startPos32;
++        return CheckErrors(p);
++      }
++    }
++  }
++  p->nowPos64 += nowPos32 - startPos32;
++  return Flush(p, nowPos32);
++}
++
++#define kBigHashDicLimit ((UInt32)1 << 24)
++
++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 beforeSize = kNumOpts;
++  Bool btMode;
++  if (!RangeEnc_Alloc(&p->rc, alloc))
++    return SZ_ERROR_MEM;
++  btMode = (p->matchFinderBase.btMode != 0);
++  #ifndef _7ZIP_ST
++  p->mtMode = (p->multiThread && !p->fastMode && btMode);
++  #endif
++
++  {
++    unsigned lclp = p->lc + p->lp;
++    if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
++    {
++      LzmaEnc_FreeLits(p, alloc);
++      p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      if (p->litProbs == 0 || p->saveState.litProbs == 0)
++      {
++        LzmaEnc_FreeLits(p, alloc);
++        return SZ_ERROR_MEM;
++      }
++      p->lclp = lclp;
++    }
++  }
++
++  p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
++
++  if (beforeSize + p->dictSize < keepWindowSize)
++    beforeSize = keepWindowSize - p->dictSize;
++
++  #ifndef _7ZIP_ST
++  if (p->mtMode)
++  {
++    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
++    p->matchFinderObj = &p->matchFinderMt;
++    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
++  }
++  else
++  #endif
++  {
++    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
++      return SZ_ERROR_MEM;
++    p->matchFinderObj = &p->matchFinderBase;
++    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
++  }
++  return SZ_OK;
++}
++
++void LzmaEnc_Init(CLzmaEnc *p)
++{
++  UInt32 i;
++  p->state = 0;
++  for (i = 0 ; i < LZMA_NUM_REPS; i++)
++    p->reps[i] = 0;
++
++  RangeEnc_Init(&p->rc);
++
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    UInt32 j;
++    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
++    {
++      p->isMatch[i][j] = kProbInitValue;
++      p->isRep0Long[i][j] = kProbInitValue;
++    }
++    p->isRep[i] = kProbInitValue;
++    p->isRepG0[i] = kProbInitValue;
++    p->isRepG1[i] = kProbInitValue;
++    p->isRepG2[i] = kProbInitValue;
++  }
++
++  {
++    UInt32 num = 0x300 << (p->lp + p->lc);
++    for (i = 0; i < num; i++)
++      p->litProbs[i] = kProbInitValue;
++  }
++
++  {
++    for (i = 0; i < kNumLenToPosStates; i++)
++    {
++      CLzmaProb *probs = p->posSlotEncoder[i];
++      UInt32 j;
++      for (j = 0; j < (1 << kNumPosSlotBits); j++)
++        probs[j] = kProbInitValue;
++    }
++  }
++  {
++    for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
++      p->posEncoders[i] = kProbInitValue;
++  }
++
++  LenEnc_Init(&p->lenEnc.p);
++  LenEnc_Init(&p->repLenEnc.p);
++
++  for (i = 0; i < (1 << kNumAlignBits); i++)
++    p->posAlignEncoder[i] = kProbInitValue;
++
++  p->optimumEndIndex = 0;
++  p->optimumCurrentIndex = 0;
++  p->additionalOffset = 0;
++
++  p->pbMask = (1 << p->pb) - 1;
++  p->lpMask = (1 << p->lp) - 1;
++}
++
++void LzmaEnc_InitPrices(CLzmaEnc *p)
++{
++  if (!p->fastMode)
++  {
++    FillDistancesPrices(p);
++    FillAlignPrices(p);
++  }
++
++  p->lenEnc.tableSize =
++  p->repLenEnc.tableSize =
++      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
++  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
++  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
++}
++
++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 i;
++  for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
++    if (p->dictSize <= ((UInt32)1 << i))
++      break;
++  p->distTableSize = i * 2;
++
++  p->finished = False;
++  p->result = SZ_OK;
++  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
++  LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  p->nowPos64 = 0;
++  return SZ_OK;
++}
++
++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  p->rc.outStream = outStream;
++  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
++}
++
++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
++    ISeqInStream *inStream, UInt32 keepWindowSize,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
++{
++  p->matchFinderBase.directInput = 1;
++  p->matchFinderBase.bufferBase = (Byte *)src;
++  p->matchFinderBase.directInputRem = srcLen;
++}
++
++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++    UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++  p->needInit = 1;
++
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++void LzmaEnc_Finish(CLzmaEncHandle pp)
++{
++  #ifndef _7ZIP_ST
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  if (p->mtMode)
++    MatchFinderMt_ReleaseStream(&p->matchFinderMt);
++  #else
++  pp = pp;
++  #endif
++}
++
++typedef struct
++{
++  ISeqOutStream funcTable;
++  Byte *data;
++  SizeT rem;
++  Bool overflow;
++} CSeqOutStreamBuf;
++
++static size_t MyWrite(void *pp, const void *data, size_t size)
++{
++  CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
++  if (p->rem < size)
++  {
++    size = p->rem;
++    p->overflow = True;
++  }
++  memcpy(p->data, data, size);
++  p->rem -= size;
++  p->data += size;
++  return size;
++}
++
++
++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++}
++
++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++}
++
++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
++    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  UInt64 nowPos64;
++  SRes res;
++  CSeqOutStreamBuf outStream;
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = False;
++  p->finished = False;
++  p->result = SZ_OK;
++
++  if (reInit)
++    LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  nowPos64 = p->nowPos64;
++  RangeEnc_Init(&p->rc);
++  p->rc.outStream = &outStream.funcTable;
++
++  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
++  
++  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++
++  return res;
++}
++
++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
++{
++  SRes res = SZ_OK;
++
++  #ifndef _7ZIP_ST
++  Byte allocaDummy[0x300];
++  int i = 0;
++  for (i = 0; i < 16; i++)
++    allocaDummy[i] = (Byte)i;
++  #endif
++
++  for (;;)
++  {
++    res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
++    if (res != SZ_OK || p->finished != 0)
++      break;
++    if (progress != 0)
++    {
++      res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
++      if (res != SZ_OK)
++      {
++        res = SZ_ERROR_PROGRESS;
++        break;
++      }
++    }
++  }
++  LzmaEnc_Finish(p);
++  return res;
++}
++
++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
++  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
++}
++
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  int i;
++  UInt32 dictSize = p->dictSize;
++  if (*size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_PARAM;
++  *size = LZMA_PROPS_SIZE;
++  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
++
++  for (i = 11; i <= 30; i++)
++  {
++    if (dictSize <= ((UInt32)2 << i))
++    {
++      dictSize = (2 << i);
++      break;
++    }
++    if (dictSize <= ((UInt32)3 << i))
++    {
++      dictSize = (3 << i);
++      break;
++    }
++  }
++
++  for (i = 0; i < 4; i++)
++    props[1 + i] = (Byte)(dictSize >> (8 * i));
++  return SZ_OK;
++}
++
++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  SRes res;
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++
++  CSeqOutStreamBuf outStream;
++
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = writeEndMark;
++
++  p->rc.outStream = &outStream.funcTable;
++  res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
++  if (res == SZ_OK)
++    res = LzmaEnc_Encode2(p, progress);
++
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++  return res;
++}
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
++  SRes res;
++  if (p == 0)
++    return SZ_ERROR_MEM;
++
++  res = LzmaEnc_SetProps(p, props);
++  if (res == SZ_OK)
++  {
++    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
++    if (res == SZ_OK)
++      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
++          writeEndMark, progress, alloc, allocBig);
++  }
++
++  LzmaEnc_Destroy(p, alloc, allocBig);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/Makefile
+@@ -0,0 +1,7 @@
++lzma_compress-objs := LzFind.o LzmaEnc.o
++lzma_decompress-objs := LzmaDec.o
++
++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o
++
++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h
diff --git a/target/linux/generic/patches-3.18/531-debloat_lzma.patch b/target/linux/generic/patches-3.18/531-debloat_lzma.patch
new file mode 100644
index 0000000000..aa3c498016
--- /dev/null
+++ b/target/linux/generic/patches-3.18/531-debloat_lzma.patch
@@ -0,0 +1,1024 @@
+--- a/include/linux/lzma/LzmaDec.h
++++ b/include/linux/lzma/LzmaDec.h
+@@ -31,14 +31,6 @@ typedef struct _CLzmaProps
+   UInt32 dicSize;
+ } CLzmaProps;
+ 
+-/* LzmaProps_Decode - decodes properties
+-Returns:
+-  SZ_OK
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+-
+ 
+ /* ---------- LZMA Decoder state ---------- */
+ 
+@@ -70,8 +62,6 @@ typedef struct
+ 
+ #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+ 
+-void LzmaDec_Init(CLzmaDec *p);
+-
+ /* There are two types of LZMA streams:
+      0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+      1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+@@ -108,97 +98,6 @@ typedef enum
+ 
+ /* ELzmaStatus is used only as output value for function call */
+ 
+-
+-/* ---------- Interfaces ---------- */
+-
+-/* There are 3 levels of interfaces:
+-     1) Dictionary Interface
+-     2) Buffer Interface
+-     3) One Call Interface
+-   You can select any of these interfaces, but don't mix functions from different
+-   groups for same object. */
+-
+-
+-/* There are two variants to allocate state for Dictionary Interface:
+-     1) LzmaDec_Allocate / LzmaDec_Free
+-     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+-   You can use variant 2, if you set dictionary buffer manually.
+-   For Buffer Interface you must always use variant 1.
+-
+-LzmaDec_Allocate* can return:
+-  SZ_OK
+-  SZ_ERROR_MEM         - Memory allocation error
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-   
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+-
+-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+-
+-/* ---------- Dictionary Interface ---------- */
+-
+-/* You can use it, if you want to eliminate the overhead for data copying from
+-   dictionary to some other external buffer.
+-   You must work with CLzmaDec variables directly in this interface.
+-
+-   STEPS:
+-     LzmaDec_Constr()
+-     LzmaDec_Allocate()
+-     for (each new stream)
+-     {
+-       LzmaDec_Init()
+-       while (it needs more decompression)
+-       {
+-         LzmaDec_DecodeToDic()
+-         use data from CLzmaDec::dic and update CLzmaDec::dicPos
+-       }
+-     }
+-     LzmaDec_Free()
+-*/
+-
+-/* LzmaDec_DecodeToDic
+-   
+-   The decoding to internal dictionary buffer (CLzmaDec::dic).
+-   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (dicLimit).
+-  LZMA_FINISH_ANY - Decode just dicLimit bytes.
+-  LZMA_FINISH_END - Stream must be finished after dicLimit.
+-
+-Returns:
+-  SZ_OK
+-    status:
+-      LZMA_STATUS_FINISHED_WITH_MARK
+-      LZMA_STATUS_NOT_FINISHED
+-      LZMA_STATUS_NEEDS_MORE_INPUT
+-      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+-  SZ_ERROR_DATA - Data error
+-*/
+-
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+-/* ---------- Buffer Interface ---------- */
+-
+-/* It's zlib-like interface.
+-   See LzmaDec_DecodeToDic description for information about STEPS and return results,
+-   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+-   to work with CLzmaDec variables manually.
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (*destLen).
+-  LZMA_FINISH_ANY - Decode just destLen bytes.
+-  LZMA_FINISH_END - Stream must be finished after (*destLen).
+-*/
+-
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+ /* ---------- One Call Interface ---------- */
+ 
+ /* LzmaDecode
+--- a/lib/lzma/LzmaDec.c
++++ b/lib/lzma/LzmaDec.c
+@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p,
+   p->needFlush = 0;
+ }
+ 
+-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+ {
+   p->needFlush = 1;
+   p->remainLen = 0;
+@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p
+     p->needInitState = 1;
+ }
+ 
+-void LzmaDec_Init(CLzmaDec *p)
++static void LzmaDec_Init(CLzmaDec *p)
+ {
+   p->dicPos = 0;
+   LzmaDec_InitDicAndState(p, True, True);
+@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD
+   p->needInitState = 0;
+ }
+ 
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+     ELzmaFinishMode finishMode, ELzmaStatus *status)
+ {
+   SizeT inSize = *srcLen;
+@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si
+   return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+ }
+ 
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+-{
+-  SizeT outSize = *destLen;
+-  SizeT inSize = *srcLen;
+-  *srcLen = *destLen = 0;
+-  for (;;)
+-  {
+-    SizeT inSizeCur = inSize, outSizeCur, dicPos;
+-    ELzmaFinishMode curFinishMode;
+-    SRes res;
+-    if (p->dicPos == p->dicBufSize)
+-      p->dicPos = 0;
+-    dicPos = p->dicPos;
+-    if (outSize > p->dicBufSize - dicPos)
+-    {
+-      outSizeCur = p->dicBufSize;
+-      curFinishMode = LZMA_FINISH_ANY;
+-    }
+-    else
+-    {
+-      outSizeCur = dicPos + outSize;
+-      curFinishMode = finishMode;
+-    }
+-
+-    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+-    src += inSizeCur;
+-    inSize -= inSizeCur;
+-    *srcLen += inSizeCur;
+-    outSizeCur = p->dicPos - dicPos;
+-    memcpy(dest, p->dic + dicPos, outSizeCur);
+-    dest += outSizeCur;
+-    outSize -= outSizeCur;
+-    *destLen += outSizeCur;
+-    if (res != 0)
+-      return res;
+-    if (outSizeCur == 0 || outSize == 0)
+-      return SZ_OK;
+-  }
+-}
+-
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->probs);
+   p->probs = 0;
+ }
+ 
+-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  alloc->Free(alloc, p->dic);
+-  p->dic = 0;
+-}
+-
+-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  LzmaDec_FreeProbs(p, alloc);
+-  LzmaDec_FreeDict(p, alloc);
+-}
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+ {
+   UInt32 dicSize;
+   Byte d;
+@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma
+   return SZ_OK;
+ }
+ 
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+ {
+   CLzmaProps propNew;
+   RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p,
+   p->prop = propNew;
+   return SZ_OK;
+ }
+-
+-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+-{
+-  CLzmaProps propNew;
+-  SizeT dicBufSize;
+-  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+-  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+-  dicBufSize = propNew.dicSize;
+-  if (p->dic == 0 || dicBufSize != p->dicBufSize)
+-  {
+-    LzmaDec_FreeDict(p, alloc);
+-    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+-    if (p->dic == 0)
+-    {
+-      LzmaDec_FreeProbs(p, alloc);
+-      return SZ_ERROR_MEM;
+-    }
+-  }
+-  p->dicBufSize = dicBufSize;
+-  p->prop = propNew;
+-  return SZ_OK;
+-}
+ 
+ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+     const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+--- a/include/linux/lzma/LzmaEnc.h
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps
+ } CLzmaEncProps;
+ 
+ void LzmaEncProps_Init(CLzmaEncProps *p);
+-void LzmaEncProps_Normalize(CLzmaEncProps *p);
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+-
+ 
+ /* ---------- CLzmaEncHandle Interface ---------- */
+ 
+@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+ void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+     int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ 
+-/* ---------- One Call Interface ---------- */
+-
+-/* LzmaEncode
+-Return code:
+-  SZ_OK               - OK
+-  SZ_ERROR_MEM        - Memory allocation error
+-  SZ_ERROR_PARAM      - Incorrect paramater
+-  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+-  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+-*/
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzmaEnc.c
++++ b/lib/lzma/LzmaEnc.c
+@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p)
+   p->writeEndMark = 0;
+ }
+ 
+-void LzmaEncProps_Normalize(CLzmaEncProps *p)
++static void LzmaEncProps_Normalize(CLzmaEncProps *p)
+ {
+   int level = p->level;
+   if (level < 0) level = 5;
+@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp
+       #endif
+ }
+ 
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+ {
+   CLzmaEncProps props = *props2;
+   LzmaEncProps_Normalize(&props);
+@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL
+ 
+ #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+ 
+-UInt32 GetPosSlot1(UInt32 pos)
++static UInt32 GetPosSlot1(UInt32 pos)
+ {
+   UInt32 res;
+   BSR2_RET(pos, res);
+@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos)
+ #define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+ #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+ 
+-void LzmaEnc_FastPosInit(Byte *g_FastPos)
++static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+ {
+   int c = 2, slotFast;
+   g_FastPos[0] = 0;
+@@ -339,58 +339,6 @@ typedef struct
+   CSaveState saveState;
+ } CLzmaEnc;
+ 
+-void LzmaEnc_SaveState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  CSaveState *dest = &p->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+-}
+-
+-void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *dest = (CLzmaEnc *)pp;
+-  const CSaveState *p = &dest->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+-}
+-
+ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE
+   while (symbol < 0x10000);
+ }
+ 
+-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+ {
+   UInt32 i;
+   for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc
+   p->matchPriceCount = 0;
+ }
+ 
+-void LzmaEnc_Construct(CLzmaEnc *p)
++static void LzmaEnc_Construct(CLzmaEnc *p)
+ {
+   RangeEnc_Construct(&p->rc);
+   MatchFinder_Construct(&p->matchFinderBase);
+@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+   return p;
+ }
+ 
+-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->litProbs);
+   alloc->Free(alloc, p->saveState.litProbs);
+@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl
+   p->saveState.litProbs = 0;
+ }
+ 
+-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   #ifndef _7ZIP_ST
+   MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U
+   return SZ_OK;
+ }
+ 
+-void LzmaEnc_Init(CLzmaEnc *p)
++static void LzmaEnc_Init(CLzmaEnc *p)
+ {
+   UInt32 i;
+   p->state = 0;
+@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p)
+   p->lpMask = (1 << p->lp) - 1;
+ }
+ 
+-void LzmaEnc_InitPrices(CLzmaEnc *p)
++static void LzmaEnc_InitPrices(CLzmaEnc *p)
+ {
+   if (!p->fastMode)
+   {
+@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn
+   return SZ_OK;
+ }
+ 
+-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  p->rc.outStream = outStream;
+-  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+-}
+-
+-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+-    ISeqInStream *inStream, UInt32 keepWindowSize,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+-}
+-
+ static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+ {
+   p->matchFinderBase.directInput = 1;
+@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc
+   p->matchFinderBase.directInputRem = srcLen;
+ }
+ 
+-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+     UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p
+   return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+ }
+ 
+-void LzmaEnc_Finish(CLzmaEncHandle pp)
++static void LzmaEnc_Finish(CLzmaEncHandle pp)
+ {
+   #ifndef _7ZIP_ST
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo
+   return size;
+ }
+ 
+-
+-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+-}
+-
+-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+-}
+-
+-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+-    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  UInt64 nowPos64;
+-  SRes res;
+-  CSeqOutStreamBuf outStream;
+-
+-  outStream.funcTable.Write = MyWrite;
+-  outStream.data = dest;
+-  outStream.rem = *destLen;
+-  outStream.overflow = False;
+-
+-  p->writeEndMark = False;
+-  p->finished = False;
+-  p->result = SZ_OK;
+-
+-  if (reInit)
+-    LzmaEnc_Init(p);
+-  LzmaEnc_InitPrices(p);
+-  nowPos64 = p->nowPos64;
+-  RangeEnc_Init(&p->rc);
+-  p->rc.outStream = &outStream.funcTable;
+-
+-  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+-  
+-  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+-  *destLen -= outStream.rem;
+-  if (outStream.overflow)
+-    return SZ_ERROR_OUTPUT_EOF;
+-
+-  return res;
+-}
+-
+ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+ {
+   SRes res = SZ_OK;
+@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p,
+   return res;
+ }
+ 
+-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+-  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+-}
+-
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp
+     return SZ_ERROR_OUTPUT_EOF;
+   return res;
+ }
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+-  SRes res;
+-  if (p == 0)
+-    return SZ_ERROR_MEM;
+-
+-  res = LzmaEnc_SetProps(p, props);
+-  if (res == SZ_OK)
+-  {
+-    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+-    if (res == SZ_OK)
+-      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+-          writeEndMark, progress, alloc, allocBig);
+-  }
+-
+-  LzmaEnc_Destroy(p, alloc, allocBig);
+-  return res;
+-}
+--- a/include/linux/lzma/LzFind.h
++++ b/include/linux/lzma/LzFind.h
+@@ -55,11 +55,6 @@ typedef struct _CMatchFinder
+ 
+ #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p);
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+-void MatchFinder_MoveBlock(CMatchFinder *p);
+-void MatchFinder_ReadIfRequired(CMatchFinder *p);
+-
+ void MatchFinder_Construct(CMatchFinder *p);
+ 
+ /* Conditions:
+@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p,
+     UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+     ISzAlloc *alloc);
+ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+-    UInt32 *distances, UInt32 maxLen);
+ 
+ /*
+ Conditions:
+@@ -102,12 +91,6 @@ typedef struct _IMatchFinder
+ 
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+ 
+-void MatchFinder_Init(CMatchFinder *p);
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzFind.c
++++ b/lib/lzma/LzFind.c
+@@ -14,9 +14,15 @@
+ 
+ #define kStartMaxLen 3
+ 
++#if 0
++#define DIRECT_INPUT	p->directInput
++#else
++#define DIRECT_INPUT	1
++#endif
++
+ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+ {
+-  if (!p->directInput)
++  if (!DIRECT_INPUT)
+   {
+     alloc->Free(alloc, p->bufferBase);
+     p->bufferBase = 0;
+@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder
+ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+ {
+   UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     p->blockSize = blockSize;
+     return 1;
+@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde
+   return (p->bufferBase != 0);
+ }
+ 
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+ 
+-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+ 
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+ {
+   p->posLimit -= subValue;
+   p->pos -= subValue;
+@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch
+ {
+   if (p->streamEndWasReached || p->result != SZ_OK)
+     return;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+     if (curSize > p->directInputRem)
+@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch
+   }
+ }
+ 
+-void MatchFinder_MoveBlock(CMatchFinder *p)
++static void MatchFinder_MoveBlock(CMatchFinder *p)
+ {
+   memmove(p->bufferBase,
+     p->buffer - p->keepSizeBefore,
+@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder
+   p->buffer = p->bufferBase + p->keepSizeBefore;
+ }
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p)
++static int MatchFinder_NeedMove(CMatchFinder *p)
+ {
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+     return 0;
+   /* if (p->streamEndWasReached) return 0; */
+   return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+ }
+ 
+-void MatchFinder_ReadIfRequired(CMatchFinder *p)
+-{
+-  if (p->streamEndWasReached)
+-    return;
+-  if (p->keepSizeAfter >= p->streamPos - p->pos)
+-    MatchFinder_ReadBlock(p);
+-}
+-
+ static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+ {
+   if (MatchFinder_NeedMove(p))
+@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch
+   p->posLimit = p->pos + limit;
+ }
+ 
+-void MatchFinder_Init(CMatchFinder *p)
++static void MatchFinder_Init(CMatchFinder *p)
+ {
+   UInt32 i;
+   for (i = 0; i < p->hashSizeSum; i++)
+@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM
+   return (p->pos - p->historySize - 1) & kNormalizeMask;
+ }
+ 
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+ {
+   UInt32 i;
+   for (i = 0; i < numItems; i++)
+@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat
+   MatchFinder_SetLimits(p);
+ }
+ 
+-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+-    UInt32 *distances, UInt32 maxLen)
+-{
+-  son[_cyclicBufferPos] = curMatch;
+-  for (;;)
+-  {
+-    UInt32 delta = pos - curMatch;
+-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+-      return distances;
+-    {
+-      const Byte *pb = cur - delta;
+-      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+-      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+-      {
+-        UInt32 len = 0;
+-        while (++len != lenLimit)
+-          if (pb[len] != cur[len])
+-            break;
+-        if (maxLen < len)
+-        {
+-          *distances++ = maxLen = len;
+-          *distances++ = delta - 1;
+-          if (len == lenLimit)
+-            return distances;
+-        }
+-      }
+-    }
+-  }
+-}
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+     UInt32 *distances, UInt32 maxLen)
+ {
+@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi
+   p->buffer++; \
+   if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+ 
+-#define MOVE_POS_RET MOVE_POS return offset;
+-
+ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+ 
++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset;
++
+ #define GET_MATCHES_HEADER2(minLen, ret_op) \
+   UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+   lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi
+   distances + offset, maxLen) - distances); MOVE_POS_RET;
+ 
+ #define SKIP_FOOTER \
+-  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+-
+-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(2)
+-  HASH2_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 1)
+-}
+-
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 2)
+-}
+-
+-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, delta2, maxLen, offset;
+-  GET_MATCHES_HEADER(3)
+-
+-  HASH3_CALC;
+-
+-  delta2 = p->pos - p->hash[hash2Value];
+-  curMatch = p->hash[kFix3HashSize + hashValue];
+-  
+-  p->hash[hash2Value] =
+-  p->hash[kFix3HashSize + hashValue] = p->pos;
+-
+-
+-  maxLen = 2;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[0] = maxLen;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-    if (maxLen == lenLimit)
+-    {
+-      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+-      MOVE_POS_RET;
+-    }
+-  }
+-  GET_MATCHES_FOOTER(offset, maxLen)
+-}
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p);
+ 
+ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+ {
+@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches
+   GET_MATCHES_FOOTER(offset, maxLen)
+ }
+ 
+-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+-  GET_MATCHES_HEADER(4)
+-
+-  HASH4_CALC;
+-
+-  delta2 = p->pos - p->hash[                hash2Value];
+-  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+-  curMatch = p->hash[kFix4HashSize + hashValue];
+-
+-  p->hash[                hash2Value] =
+-  p->hash[kFix3HashSize + hash3Value] =
+-  p->hash[kFix4HashSize + hashValue] = p->pos;
+-
+-  maxLen = 1;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    distances[0] = maxLen = 2;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-  }
+-  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+-  {
+-    maxLen = 3;
+-    distances[offset + 1] = delta3 - 1;
+-    offset += 2;
+-    delta2 = delta3;
+-  }
+-  if (offset != 0)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[offset - 2] = maxLen;
+-    if (maxLen == lenLimit)
+-    {
+-      p->son[p->cyclicBufferPos] = curMatch;
+-      MOVE_POS_RET;
+-    }
+-  }
+-  if (maxLen < 3)
+-    maxLen = 3;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances + offset, maxLen) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances, 2) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(2)
+-    HASH2_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value;
+-    SKIP_HEADER(3)
+-    HASH3_CALC;
+-    curMatch = p->hash[kFix3HashSize + hashValue];
+-    p->hash[hash2Value] =
+-    p->hash[kFix3HashSize + hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+ {
+   do
+@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF
+   while (--num != 0);
+ }
+ 
+-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value, hash3Value;
+-    SKIP_HEADER(4)
+-    HASH4_CALC;
+-    curMatch = p->hash[kFix4HashSize + hashValue];
+-    p->hash[                hash2Value] =
+-    p->hash[kFix3HashSize + hash3Value] =
+-    p->hash[kFix4HashSize + hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+ {
+   vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+   vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+   vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+   vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+-  if (!p->btMode)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 2)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 3)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+-  }
+-  else
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+-  }
++  vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++  vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
diff --git a/target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch b/target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch
new file mode 100644
index 0000000000..8ce53d8bed
--- /dev/null
+++ b/target/linux/generic/patches-3.18/532-jffs2_eofdetect.patch
@@ -0,0 +1,56 @@
+--- a/fs/jffs2/build.c
++++ b/fs/jffs2/build.c
+@@ -116,6 +116,16 @@ static int jffs2_build_filesystem(struct
+ 	dbg_fsbuild("scanned flash completely\n");
+ 	jffs2_dbg_dump_block_lists_nolock(c);
+ 
++	if (c->flags & (1 << 7)) {
++		printk("%s(): unlocking the mtd device... ", __func__);
++		mtd_unlock(c->mtd, 0, c->mtd->size);
++		printk("done.\n");
++
++		printk("%s(): erasing all blocks after the end marker... ", __func__);
++		jffs2_erase_pending_blocks(c, -1);
++		printk("done.\n");
++	}
++
+ 	dbg_fsbuild("pass 1 starting\n");
+ 	c->flags |= JFFS2_SB_FLAG_BUILDING;
+ 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
+--- a/fs/jffs2/scan.c
++++ b/fs/jffs2/scan.c
+@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
+ 		/* reset summary info for next eraseblock scan */
+ 		jffs2_sum_reset_collected(s);
+ 
+-		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+-						buf_size, s);
++		if (c->flags & (1 << 7)) {
++			if (mtd_block_isbad(c->mtd, jeb->offset))
++				ret = BLK_STATE_BADBLOCK;
++			else
++				ret = BLK_STATE_ALLFF;
++		} else
++			ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
++							buf_size, s);
+ 
+ 		if (ret < 0)
+ 			goto out;
+@@ -561,6 +567,17 @@ full_scan:
+ 			return err;
+ 	}
+ 
++	if ((buf[0] == 0xde) &&
++		(buf[1] == 0xad) &&
++		(buf[2] == 0xc0) &&
++		(buf[3] == 0xde)) {
++		/* end of filesystem. erase everything after this point */
++		printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
++		c->flags |= (1 << 7);
++
++		return BLK_STATE_ALLFF;
++	}
++
+ 	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+ 	ofs = 0;
+ 	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
diff --git a/target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch b/target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch
new file mode 100644
index 0000000000..00b0b7cadd
--- /dev/null
+++ b/target/linux/generic/patches-3.18/540-crypto-xz-decompression-support.patch
@@ -0,0 +1,146 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1437,6 +1437,13 @@ config CRYPTO_LZ4HC
+ 	help
+ 	  This is the LZ4 high compression mode algorithm.
+ 
++config CRYPTO_XZ
++	tristate "XZ compression algorithm"
++	select CRYPTO_ALGAPI
++	select XZ_DEC
++	help
++	  This is the XZ algorithm. Only decompression is supported for now.
++
+ comment "Random Number Generation"
+ 
+ config CRYPTO_ANSI_CPRNG
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -89,6 +89,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.
+ obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+ obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
+ obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
++obj-$(CONFIG_CRYPTO_XZ) += xz.o
+ obj-$(CONFIG_CRYPTO_842) += 842.o
+ obj-$(CONFIG_CRYPTO_RNG2) += rng.o
+ obj-$(CONFIG_CRYPTO_RNG2) += krng.o
+--- /dev/null
++++ b/crypto/xz.c
+@@ -0,0 +1,117 @@
++/*
++ * Cryptographic API.
++ *
++ * XZ decompression support.
++ *
++ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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/init.h>
++#include <linux/module.h>
++#include <linux/crypto.h>
++#include <linux/xz.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/net.h>
++
++struct xz_comp_ctx {
++	struct xz_dec	*decomp_state;
++	struct xz_buf	decomp_buf;
++};
++
++static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx)
++{
++	ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0);
++	if (!ctx->decomp_state)
++		return -ENOMEM;
++
++	return 0;
++}
++
++static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx)
++{
++	xz_dec_end(ctx->decomp_state);
++}
++
++static int crypto_xz_init(struct crypto_tfm *tfm)
++{
++	struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	return crypto_xz_decomp_init(ctx);
++}
++
++static void crypto_xz_exit(struct crypto_tfm *tfm)
++{
++	struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_xz_decomp_exit(ctx);
++}
++
++static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src,
++			      unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++	return -EOPNOTSUPP;
++}
++
++static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src,
++				unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++	struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm);
++	struct xz_buf *xz_buf = &dctx->decomp_buf;
++	int ret;
++
++	memset(xz_buf, '\0', sizeof(struct xz_buf));
++
++	xz_buf->in = (u8 *) src;
++	xz_buf->in_pos = 0;
++	xz_buf->in_size = slen;
++	xz_buf->out = (u8 *) dst;
++	xz_buf->out_pos = 0;
++	xz_buf->out_size = *dlen;
++
++	ret = xz_dec_run(dctx->decomp_state, xz_buf);
++	if (ret != XZ_STREAM_END) {
++		ret = -EINVAL;
++		goto out;
++	}
++
++	*dlen = xz_buf->out_pos;
++	ret = 0;
++
++out:
++	return ret;
++}
++
++static struct crypto_alg crypto_xz_alg = {
++	.cra_name		= "xz",
++	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
++	.cra_ctxsize		= sizeof(struct xz_comp_ctx),
++	.cra_module		= THIS_MODULE,
++	.cra_list		= LIST_HEAD_INIT(crypto_xz_alg.cra_list),
++	.cra_init		= crypto_xz_init,
++	.cra_exit		= crypto_xz_exit,
++	.cra_u			= { .compress = {
++	.coa_compress 		= crypto_xz_compress,
++	.coa_decompress  	= crypto_xz_decompress } }
++};
++
++static int __init crypto_xz_mod_init(void)
++{
++	return crypto_register_alg(&crypto_xz_alg);
++}
++
++static void __exit crypto_xz_mod_exit(void)
++{
++	crypto_unregister_alg(&crypto_xz_alg);
++}
++
++module_init(crypto_xz_mod_init);
++module_exit(crypto_xz_mod_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Crypto XZ decompression support");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
diff --git a/target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch b/target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch
new file mode 100644
index 0000000000..f85689c586
--- /dev/null
+++ b/target/linux/generic/patches-3.18/541-ubifs-xz-decompression-support.patch
@@ -0,0 +1,92 @@
+--- a/fs/ubifs/Kconfig
++++ b/fs/ubifs/Kconfig
+@@ -5,8 +5,10 @@ config UBIFS_FS
+ 	select CRYPTO if UBIFS_FS_ADVANCED_COMPR
+ 	select CRYPTO if UBIFS_FS_LZO
+ 	select CRYPTO if UBIFS_FS_ZLIB
++	select CRYPTO if UBIFS_FS_XZ
+ 	select CRYPTO_LZO if UBIFS_FS_LZO
+ 	select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
++	select CRYPTO_XZ if UBIFS_FS_XZ
+ 	depends on MTD_UBI
+ 	help
+ 	  UBIFS is a file system for flash devices which works on top of UBI.
+@@ -35,3 +37,12 @@ config UBIFS_FS_ZLIB
+ 	default y
+ 	help
+ 	  Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
++
++config UBIFS_FS_XZ
++	bool "XZ decompression support" if UBIFS_FS_ADVANCED_COMPR
++	depends on UBIFS_FS
++	default y
++	help
++	  XZ compresses better the ZLIB but it is slower..
++	  Say 'Y' if unsure.
++
+--- a/fs/ubifs/compress.c
++++ b/fs/ubifs/compress.c
+@@ -71,6 +71,24 @@ static struct ubifs_compressor zlib_comp
+ };
+ #endif
+ 
++#ifdef CONFIG_UBIFS_FS_XZ
++static DEFINE_MUTEX(xz_enc_mutex);
++static DEFINE_MUTEX(xz_dec_mutex);
++
++static struct ubifs_compressor xz_compr = {
++	.compr_type = UBIFS_COMPR_XZ,
++	.comp_mutex = &xz_enc_mutex,
++	.decomp_mutex = &xz_dec_mutex,
++	.name = "xz",
++	.capi_name = "xz",
++};
++#else
++static struct ubifs_compressor xz_compr = {
++	.compr_type = UBIFS_COMPR_XZ,
++	.name = "xz",
++};
++#endif
++
+ /* All UBIFS compressors */
+ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+ 
+@@ -232,9 +250,15 @@ int __init ubifs_compressors_init(void)
+ 	if (err)
+ 		goto out_lzo;
+ 
++	err = compr_init(&xz_compr);
++	if (err)
++		goto out_zlib;
++
+ 	ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
+ 	return 0;
+ 
++out_zlib:
++	compr_exit(&zlib_compr);
+ out_lzo:
+ 	compr_exit(&lzo_compr);
+ 	return err;
+@@ -247,4 +271,5 @@ void ubifs_compressors_exit(void)
+ {
+ 	compr_exit(&lzo_compr);
+ 	compr_exit(&zlib_compr);
++	compr_exit(&xz_compr);
+ }
+--- a/fs/ubifs/ubifs-media.h
++++ b/fs/ubifs/ubifs-media.h
+@@ -332,12 +332,14 @@ enum {
+  * UBIFS_COMPR_NONE: no compression
+  * UBIFS_COMPR_LZO: LZO compression
+  * UBIFS_COMPR_ZLIB: ZLIB compression
++ * UBIFS_COMPR_XZ: XZ compression
+  * UBIFS_COMPR_TYPES_CNT: count of supported compression types
+  */
+ enum {
+ 	UBIFS_COMPR_NONE,
+ 	UBIFS_COMPR_LZO,
+ 	UBIFS_COMPR_ZLIB,
++	UBIFS_COMPR_XZ,
+ 	UBIFS_COMPR_TYPES_CNT,
+ };
+ 
diff --git a/target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch b/target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch
new file mode 100644
index 0000000000..42ae9cb84a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/550-ubifs-symlink-xattr-support.patch
@@ -0,0 +1,55 @@
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -1597,6 +1597,10 @@ const struct inode_operations ubifs_syml
+ 	.follow_link = ubifs_follow_link,
+ 	.setattr     = ubifs_setattr,
+ 	.getattr     = ubifs_getattr,
++	.setxattr    = ubifs_setxattr,
++	.getxattr    = ubifs_getxattr,
++	.listxattr   = ubifs_listxattr,
++	.removexattr = ubifs_removexattr,
+ };
+ 
+ const struct file_operations ubifs_file_operations = {
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -572,6 +572,13 @@ int ubifs_jnl_update(struct ubifs_info *
+ 	aligned_dlen = ALIGN(dlen, 8);
+ 	aligned_ilen = ALIGN(ilen, 8);
+ 	len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ;
++	if (xent) {
++		/*
++		 * Make sure to account for host_ui->data_len in
++		 * length calculation in case there is extended attribute.
++		 */
++		len += host_ui->data_len;
++	}
+ 	dent = kmalloc(len, GFP_NOFS);
+ 	if (!dent)
+ 		return -ENOMEM;
+@@ -648,7 +655,8 @@ int ubifs_jnl_update(struct ubifs_info *
+ 
+ 	ino_key_init(c, &ino_key, dir->i_ino);
+ 	ino_offs += aligned_ilen;
+-	err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ);
++	err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs,
++			    UBIFS_INO_NODE_SZ + host_ui->data_len);
+ 	if (err)
+ 		goto out_ro;
+ 
+--- a/fs/ubifs/xattr.c
++++ b/fs/ubifs/xattr.c
+@@ -209,12 +209,12 @@ static int change_xattr(struct ubifs_inf
+ 		goto out_free;
+ 	}
+ 	inode->i_size = ui->ui_size = size;
+-	ui->data_len = size;
+ 
+ 	mutex_lock(&host_ui->ui_mutex);
+ 	host->i_ctime = ubifs_current_time(host);
+ 	host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
+ 	host_ui->xattr_size += CALC_XATTR_BYTES(size);
++	ui->data_len = size;
+ 
+ 	/*
+ 	 * It is important to write the host inode after the xattr inode
diff --git a/target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch b/target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch
new file mode 100644
index 0000000000..1b0f30718c
--- /dev/null
+++ b/target/linux/generic/patches-3.18/551-ubifs-fix-default-compression-selection.patch
@@ -0,0 +1,29 @@
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -63,6 +63,17 @@
+ /* Default time granularity in nanoseconds */
+ #define DEFAULT_TIME_GRAN 1000000000
+ 
++static int get_default_compressor(void)
++{
++	if (ubifs_compr_present(UBIFS_COMPR_LZO))
++		return UBIFS_COMPR_LZO;
++
++	if (ubifs_compr_present(UBIFS_COMPR_ZLIB))
++		return UBIFS_COMPR_ZLIB;
++
++	return UBIFS_COMPR_NONE;
++}
++
+ /**
+  * create_default_filesystem - format empty UBI volume.
+  * @c: UBIFS file-system description object
+@@ -183,7 +194,7 @@ static int create_default_filesystem(str
+ 	if (c->mount_opts.override_compr)
+ 		sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
+ 	else
+-		sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
++		sup->default_compr = cpu_to_le16(get_default_compressor());
+ 
+ 	generate_random_uuid(sup->uuid);
+ 
diff --git a/target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch b/target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch
new file mode 100644
index 0000000000..bc6ed3e5d7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/600-netfilter_conntrack_flush.patch
@@ -0,0 +1,86 @@
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -17,6 +17,7 @@
+ #include <linux/percpu.h>
+ #include <linux/netdevice.h>
+ #include <linux/security.h>
++#include <linux/inet.h>
+ #include <net/net_namespace.h>
+ #ifdef CONFIG_SYSCTL
+ #include <linux/sysctl.h>
+@@ -262,10 +263,66 @@ static int ct_open(struct inode *inode,
+ 			sizeof(struct ct_iter_state));
+ }
+ 
++struct kill_request {
++	u16 family;
++	union nf_inet_addr addr;
++};
++
++static int kill_matching(struct nf_conn *i, void *data)
++{
++	struct kill_request *kr = data;
++	struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++	struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
++
++	if (!kr->family)
++		return 1;
++
++	if (t1->src.l3num != kr->family)
++		return 0;
++
++	return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
++}
++
++static ssize_t ct_file_write(struct file *file, const char __user *buf,
++			     size_t count, loff_t *ppos)
++{
++	struct seq_file *seq = file->private_data;
++	struct net *net = seq_file_net(seq);
++	struct kill_request kr = { };
++	char req[INET6_ADDRSTRLEN] = { };
++
++	if (count == 0)
++		return 0;
++
++	if (count >= INET6_ADDRSTRLEN)
++		count = INET6_ADDRSTRLEN - 1;
++
++	if (copy_from_user(req, buf, count))
++		return -EFAULT;
++
++	if (strnchr(req, count, ':')) {
++		kr.family = AF_INET6;
++		if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	} else if (strnchr(req, count, '.')) {
++		kr.family = AF_INET;
++		if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	}
++
++	nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0);
++
++	return count;
++}
++
+ static const struct file_operations ct_file_ops = {
+ 	.owner   = THIS_MODULE,
+ 	.open    = ct_open,
+ 	.read    = seq_read,
++	.write	 = ct_file_write,
+ 	.llseek  = seq_lseek,
+ 	.release = seq_release_net,
+ };
+@@ -367,7 +424,7 @@ static int nf_conntrack_standalone_init_
+ {
+ 	struct proc_dir_entry *pde;
+ 
+-	pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops);
++	pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops);
+ 	if (!pde)
+ 		goto out_nf_conntrack;
+ 
diff --git a/target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch
new file mode 100644
index 0000000000..74be425049
--- /dev/null
+++ b/target/linux/generic/patches-3.18/610-netfilter_match_bypass_default_checks.patch
@@ -0,0 +1,84 @@
+--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
+@@ -87,6 +87,7 @@ struct ipt_ip {
+ #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
+ #define IPT_F_GOTO		0x02	/* Set if jump is a goto */
+ #define IPT_F_MASK		0x03	/* All possible flag bits mask. */
++#define IPT_F_NO_DEF_MATCH	0x80	/* Internal: no default match rules present */
+ 
+ /* Values for "inv" field in struct ipt_ip. */
+ #define IPT_INV_VIA_IN		0x01	/* Invert the sense of IN IFACE. */
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -82,6 +82,9 @@ ip_packet_match(const struct iphdr *ip,
+ 
+ #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
+ 
++	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
++		return true;
++
+ 	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+ 		  IPT_INV_SRCIP) ||
+ 	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+@@ -135,6 +138,29 @@ ip_packet_match(const struct iphdr *ip,
+ 	return true;
+ }
+ 
++static void
++ip_checkdefault(struct ipt_ip *ip)
++{
++	static const char iface_mask[IFNAMSIZ] = {};
++
++	if (ip->invflags || ip->flags & IPT_F_FRAG)
++		return;
++
++	if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (ip->smsk.s_addr || ip->dmsk.s_addr)
++		return;
++
++	if (ip->proto)
++		return;
++
++	ip->flags |= IPT_F_NO_DEF_MATCH;
++}
++
+ static bool
+ ip_checkentry(const struct ipt_ip *ip)
+ {
+@@ -650,6 +676,8 @@ find_check_entry(struct ipt_entry *e, st
+ 	struct xt_mtchk_param mtpar;
+ 	struct xt_entry_match *ematch;
+ 
++	ip_checkdefault(&e->ip);
++
+ 	j = 0;
+ 	mtpar.net	= net;
+ 	mtpar.table     = name;
+@@ -942,6 +970,7 @@ copy_entries_to_user(unsigned int total_
+ 	const struct xt_table_info *private = table->private;
+ 	int ret = 0;
+ 	const void *loc_cpu_entry;
++	u8 flags;
+ 
+ 	counters = alloc_counters(table);
+ 	if (IS_ERR(counters))
+@@ -972,6 +1001,14 @@ copy_entries_to_user(unsigned int total_
+ 			ret = -EFAULT;
+ 			goto free_counters;
+ 		}
++
++		flags = e->ip.flags & IPT_F_MASK;
++		if (copy_to_user(userptr + off
++				 + offsetof(struct ipt_entry, ip.flags),
++				 &flags, sizeof(flags)) != 0) {
++			ret = -EFAULT;
++			goto free_counters;
++		}
+ 
+ 		for (i = sizeof(struct ipt_entry);
+ 		     i < e->target_offset;
diff --git a/target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch
new file mode 100644
index 0000000000..ef993c864b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/611-netfilter_match_bypass_default_table.patch
@@ -0,0 +1,94 @@
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -310,6 +310,33 @@ struct ipt_entry *ipt_next_entry(const s
+ 	return (void *)entry + entry->next_offset;
+ }
+ 
++static bool
++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
++{
++	struct xt_entry_target *t;
++	struct xt_standard_target *st;
++
++	if (e->target_offset != sizeof(struct ipt_entry))
++		return false;
++
++	if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
++		return false;
++
++	t = ipt_get_target(e);
++	if (t->u.kernel.target->target)
++		return false;
++
++	st = (struct xt_standard_target *) t;
++	if (st->verdict == XT_RETURN)
++		return false;
++
++	if (st->verdict >= 0)
++		return false;
++
++	*verdict = (unsigned)(-st->verdict) - 1;
++	return true;
++}
++
+ /* Returns one of the generic firewall policies, like NF_ACCEPT. */
+ unsigned int
+ ipt_do_table(struct sk_buff *skb,
+@@ -331,9 +358,33 @@ ipt_do_table(struct sk_buff *skb,
+ 	unsigned int addend;
+ 
+ 	/* Initialization */
++	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
++	local_bh_disable();
++	private = table->private;
++	cpu        = smp_processor_id();
++	/*
++	 * Ensure we load private-> members after we've fetched the base
++	 * pointer.
++	 */
++	smp_read_barrier_depends();
++	table_base = private->entries[cpu];
++
++	e = get_entry(table_base, private->hook_entry[hook]);
++	if (ipt_handle_default_rule(e, &verdict)) {
++		ADD_COUNTER(e->counters, skb->len, 1);
++		local_bh_enable();
++		return verdict;
++	}
++
+ 	ip = ip_hdr(skb);
+ 	indev = in ? in->name : nulldevname;
+ 	outdev = out ? out->name : nulldevname;
++
++	addend = xt_write_recseq_begin();
++	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
++	stackptr   = per_cpu_ptr(private->stackptr, cpu);
++	origptr    = *stackptr;
++
+ 	/* We handle fragments by dealing with the first fragment as
+ 	 * if it was a normal packet.  All other fragments are treated
+ 	 * normally, except that they will NEVER match rules that ask
+@@ -348,23 +399,6 @@ ipt_do_table(struct sk_buff *skb,
+ 	acpar.family  = NFPROTO_IPV4;
+ 	acpar.hooknum = hook;
+ 
+-	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
+-	local_bh_disable();
+-	addend = xt_write_recseq_begin();
+-	private = table->private;
+-	cpu        = smp_processor_id();
+-	/*
+-	 * Ensure we load private-> members after we've fetched the base
+-	 * pointer.
+-	 */
+-	smp_read_barrier_depends();
+-	table_base = private->entries[cpu];
+-	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
+-	stackptr   = per_cpu_ptr(private->stackptr, cpu);
+-	origptr    = *stackptr;
+-
+-	e = get_entry(table_base, private->hook_entry[hook]);
+-
+ 	pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n",
+ 		 table->name, hook, origptr,
+ 		 get_entry(table_base, private->underflow[hook]));
diff --git a/target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch
new file mode 100644
index 0000000000..72172d8bb4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/612-netfilter_match_reduce_memory_access.patch
@@ -0,0 +1,16 @@
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -85,9 +85,11 @@ ip_packet_match(const struct iphdr *ip,
+ 	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+ 		return true;
+ 
+-	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
++	if (FWINV(ipinfo->smsk.s_addr &&
++		  (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+ 		  IPT_INV_SRCIP) ||
+-	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
++	    FWINV(ipinfo->dmsk.s_addr &&
++		  (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+ 		  IPT_INV_DSTIP)) {
+ 		dprintf("Source or dest mismatch.\n");
+ 
diff --git a/target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch b/target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch
new file mode 100644
index 0000000000..1d3b37cc10
--- /dev/null
+++ b/target/linux/generic/patches-3.18/613-netfilter_optional_tcp_window_check.patch
@@ -0,0 +1,36 @@
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -33,6 +33,9 @@
+ #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+ #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+ 
++/* Do not check the TCP window for incoming packets  */
++static int nf_ct_tcp_no_window_check __read_mostly = 1;
++
+ /* "Be conservative in what you do,
+     be liberal in what you accept from others."
+     If it's non-zero, we mark only out of window RST segments as INVALID. */
+@@ -515,6 +518,9 @@ static bool tcp_in_window(const struct n
+ 	s32 receiver_offset;
+ 	bool res, in_recv_win;
+ 
++	if (nf_ct_tcp_no_window_check)
++		return true;
++
+ 	/*
+ 	 * Get the required data from the packet.
+ 	 */
+@@ -1452,6 +1458,13 @@ static struct ctl_table tcp_sysctl_table
+ 		.mode		= 0644,
+ 		.proc_handler	= proc_dointvec,
+ 	},
++	{
++		.procname       = "nf_conntrack_tcp_no_window_check",
++		.data           = &nf_ct_tcp_no_window_check,
++		.maxlen         = sizeof(unsigned int),
++		.mode           = 0644,
++		.proc_handler   = proc_dointvec,
++	},
+ 	{ }
+ };
+ 
diff --git a/target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch b/target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch
new file mode 100644
index 0000000000..e9dae74d8d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/615-netfilter_add_xt_id_match.patch
@@ -0,0 +1,95 @@
+--- a/include/uapi/linux/netfilter/Kbuild
++++ b/include/uapi/linux/netfilter/Kbuild
+@@ -55,6 +55,7 @@ header-y += xt_ecn.h
+ header-y += xt_esp.h
+ header-y += xt_hashlimit.h
+ header-y += xt_helper.h
++header-y += xt_id.h
+ header-y += xt_ipcomp.h
+ header-y += xt_iprange.h
+ header-y += xt_ipvs.h
+--- /dev/null
++++ b/include/uapi/linux/netfilter/xt_id.h
+@@ -0,0 +1,8 @@
++#ifndef _XT_ID_H
++#define _XT_ID_H
++
++struct xt_id_info {
++	u32 id;
++};
++
++#endif /* XT_ID_H */
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -1157,6 +1157,13 @@ config NETFILTER_XT_MATCH_IPCOMP
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config NETFILTER_XT_MATCH_ID
++	tristate '"id" match support'
++	depends on NETFILTER_ADVANCED
++	---help---
++	This option adds a `id' dummy-match, which allows you to put
++	numeric IDs into your iptables ruleset.
++
+ config NETFILTER_XT_MATCH_IPRANGE
+ 	tristate '"iprange" address range match support'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -143,6 +143,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) +=
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
++obj-$(CONFIG_NETFILTER_XT_MATCH_ID) += xt_id.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
+--- /dev/null
++++ b/net/netfilter/xt_id.c
+@@ -0,0 +1,45 @@
++/*
++ * Implements a dummy match to allow attaching IDs to rules
++ *
++ * 2014-08-01 Jo-Philipp Wich <jo@mein.io>
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_id.h>
++
++MODULE_AUTHOR("Jo-Philipp Wich <jo@mein.io>");
++MODULE_DESCRIPTION("Xtables: No-op match which can be tagged with a 32bit ID");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_id");
++MODULE_ALIAS("ip6t_id");
++
++static bool
++id_mt(const struct sk_buff *skb, struct xt_action_param *par)
++{
++	/* We always match */
++	return true;
++}
++
++static struct xt_match id_mt_reg __read_mostly = {
++	.name      = "id",
++	.revision  = 0,
++	.family    = NFPROTO_UNSPEC,
++	.match     = id_mt,
++	.matchsize = sizeof(struct xt_id_info),
++	.me        = THIS_MODULE,
++};
++
++static int __init id_mt_init(void)
++{
++	return xt_register_match(&id_mt_reg);
++}
++
++static void __exit id_mt_exit(void)
++{
++	xt_unregister_match(&id_mt_reg);
++}
++
++module_init(id_mt_init);
++module_exit(id_mt_exit);
diff --git a/target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch b/target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch
new file mode 100644
index 0000000000..2a64d5420a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/616-net_optimize_xfrm_calls.patch
@@ -0,0 +1,12 @@
+--- a/net/netfilter/nf_nat_core.c
++++ b/net/netfilter/nf_nat_core.c
+@@ -90,6 +90,9 @@ int nf_xfrm_me_harder(struct sk_buff *sk
+ 	struct dst_entry *dst;
+ 	int err;
+ 
++	if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT])
++		return 0;
++
+ 	err = xfrm_decode_session(skb, &fl, family);
+ 	if (err < 0)
+ 		return err;
diff --git a/target/linux/generic/patches-3.18/621-sched_act_connmark.patch b/target/linux/generic/patches-3.18/621-sched_act_connmark.patch
new file mode 100644
index 0000000000..72d8e53433
--- /dev/null
+++ b/target/linux/generic/patches-3.18/621-sched_act_connmark.patch
@@ -0,0 +1,161 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,126 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@nbd.name>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK	20
++
++#define CONNMARK_TAB_MASK     3
++
++static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a,
++		       struct tcf_result *res)
++{
++	struct nf_conn *c;
++	enum ip_conntrack_info ctinfo;
++	int proto;
++	int r;
++
++	if (skb->protocol == htons(ETH_P_IP)) {
++		if (skb->len < sizeof(struct iphdr))
++			goto out;
++		proto = PF_INET;
++	} else if (skb->protocol == htons(ETH_P_IPV6)) {
++		if (skb->len < sizeof(struct ipv6hdr))
++			goto out;
++		proto = PF_INET6;
++	} else
++		goto out;
++
++	r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++	if (r != NF_ACCEPT)
++		goto out;
++
++	c = nf_ct_get(skb, &ctinfo);
++	if (!c)
++		goto out;
++
++	skb->mark = c->mark;
++	nf_conntrack_put(skb->nfct);
++	skb->nfct = NULL;
++
++out:
++	return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct net *net, struct nlattr *nla,
++			     struct nlattr *est, struct tc_action *a,
++			     int ovr, int bind)
++{
++	int ret = 0;
++
++	if (!tcf_hash_check(0, a, bind)) {
++		ret = tcf_hash_create(0, est, a, sizeof(struct tcf_common), bind);
++		if (ret)
++		    return ret;
++
++		tcf_hash_insert(a);
++		ret = ACT_P_CREATED;
++	} else {
++		if (!ovr) {
++			tcf_hash_release(a, bind);
++			return -EEXIST;
++		}
++	}
++
++	return ret;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++				int bind, int ref)
++{
++	return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++	.kind		=	"connmark",
++	.type		=	TCA_ACT_CONNMARK,
++	.owner		=	THIS_MODULE,
++	.act		=	tcf_connmark,
++	.dump		=	tcf_connmark_dump,
++	.init		=	tcf_connmark_init,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++
++	return tcf_register_action(&act_connmark_ops, CONNMARK_TAB_MASK);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++	tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -686,6 +686,19 @@ config NET_ACT_CSUM
+ 	  To compile this code as a module, choose M here: the
+ 	  module will be called act_csum.
+ 
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++	 depends on NF_CONNTRACK_MARK
++        ---help---
++	  Say Y here to restore the connmark from a scheduler action
++
++	  If unsure, say N.
++
++	  To compile this code as a module, choose M here: the
++	  module will be called act_connmark.
++
+ config NET_CLS_IND
+ 	bool "Incoming device classification"
+ 	depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit
+ obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
+ obj-$(CONFIG_NET_ACT_CSUM)	+= act_csum.o
++obj-$(CONFIG_NET_ACT_CONNMARK)	+= act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
diff --git a/target/linux/generic/patches-3.18/630-packet_socket_type.patch b/target/linux/generic/patches-3.18/630-packet_socket_type.patch
new file mode 100644
index 0000000000..61ddea84c6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/630-packet_socket_type.patch
@@ -0,0 +1,134 @@
+This patch allows the user to specify desired packet types (outgoing,
+broadcast, unicast, etc.) on packet sockets via setsockopt.
+This can reduce the load in situations where only a limited number
+of packet types are necessary
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/include/uapi/linux/if_packet.h
++++ b/include/uapi/linux/if_packet.h
+@@ -31,6 +31,8 @@ struct sockaddr_ll {
+ #define PACKET_KERNEL		7		/* To kernel space	*/
+ /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
+ #define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
++#define PACKET_MASK_ANY		0xffffffff	/* mask for packet type bits */
++
+ 
+ /* Packet socket options */
+ 
+@@ -54,6 +56,7 @@ struct sockaddr_ll {
+ #define PACKET_FANOUT			18
+ #define PACKET_TX_HAS_OFF		19
+ #define PACKET_QDISC_BYPASS		20
++#define PACKET_RECV_TYPE		21
+ 
+ #define PACKET_FANOUT_HASH		0
+ #define PACKET_FANOUT_LB		1
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -1530,6 +1530,7 @@ static int packet_rcv_spkt(struct sk_buf
+ {
+ 	struct sock *sk;
+ 	struct sockaddr_pkt *spkt;
++	struct packet_sock *po;
+ 
+ 	/*
+ 	 *	When we registered the protocol we saved the socket in the data
+@@ -1537,6 +1538,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 */
+ 
+ 	sk = pt->af_packet_priv;
++	po = pkt_sk(sk);
+ 
+ 	/*
+ 	 *	Yank back the headers [hope the device set this
+@@ -1549,7 +1551,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 *	so that this procedure is noop.
+ 	 */
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
+ 		goto out;
+ 
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+@@ -1748,12 +1750,12 @@ static int packet_rcv(struct sk_buff *sk
+ 	int skb_len = skb->len;
+ 	unsigned int snaplen, res;
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -1873,12 +1875,12 @@ static int tpacket_rcv(struct sk_buff *s
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -2828,6 +2830,7 @@ static int packet_create(struct net *net
+ 	spin_lock_init(&po->bind_lock);
+ 	mutex_init(&po->pg_vec_lock);
+ 	po->prot_hook.func = packet_rcv;
++	po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
+ 
+ 	if (sock->type == SOCK_PACKET)
+ 		po->prot_hook.func = packet_rcv_spkt;
+@@ -3409,6 +3412,16 @@ packet_setsockopt(struct socket *sock, i
+ 		po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
+ 		return 0;
+ 	}
++        case PACKET_RECV_TYPE:
++        {
++                unsigned int val;
++                if (optlen != sizeof(val))
++                        return -EINVAL;
++                if (copy_from_user(&val, optval, sizeof(val)))
++                        return -EFAULT;
++                po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
++                return 0;
++        }
+ 	default:
+ 		return -ENOPROTOOPT;
+ 	}
+@@ -3460,6 +3473,13 @@ static int packet_getsockopt(struct sock
+ 	case PACKET_VNET_HDR:
+ 		val = po->has_vnet_hdr;
+ 		break;
++	case PACKET_RECV_TYPE:
++		if (len > sizeof(unsigned int))
++			len = sizeof(unsigned int);
++		val = po->pkt_type;
++
++		data = &val;
++		break;
+ 	case PACKET_VERSION:
+ 		val = po->tp_version;
+ 		break;
+--- a/net/packet/internal.h
++++ b/net/packet/internal.h
+@@ -117,6 +117,7 @@ struct packet_sock {
+ 	struct net_device __rcu	*cached_dev;
+ 	int			(*xmit)(struct sk_buff *skb);
+ 	struct packet_type	prot_hook ____cacheline_aligned_in_smp;
++	unsigned int		pkt_type;
+ };
+ 
+ static struct packet_sock *pkt_sk(struct sock *sk)
diff --git a/target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch b/target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch
new file mode 100644
index 0000000000..35802d63dc
--- /dev/null
+++ b/target/linux/generic/patches-3.18/640-bridge_no_eap_forward.patch
@@ -0,0 +1,23 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: no EAP forward
+
+When bridging, do not forward EAP frames to other ports, only deliver
+them locally.
+Fixes WPA authentication issues with multiples APs that are connected to
+each other via bridges.
+---
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -97,7 +97,11 @@ int br_handle_frame_finish(struct sk_buf
+ 
+ 	dst = NULL;
+ 
+-	if (is_broadcast_ether_addr(dest)) {
++	if (skb->protocol == htons(ETH_P_PAE)) {
++		skb2 = skb;
++		/* Do not forward 802.1x/EAP frames */
++		skb = NULL;
++	} else if (is_broadcast_ether_addr(dest)) {
+ 		skb2 = skb;
+ 		unicast = false;
+ 	} else if (is_multicast_ether_addr(dest)) {
diff --git a/target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch b/target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch
new file mode 100644
index 0000000000..a822fb0dc9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/641-bridge_always_accept_eap.patch
@@ -0,0 +1,17 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: always accept EAP
+
+Allow EAP frames to pass through bridges even in learning state. Fixes
+issues with WDS.
+---
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -84,7 +84,7 @@ int br_handle_frame_finish(struct sk_buf
+ 	    br_multicast_rcv(br, p, skb, vid))
+ 		goto drop;
+ 
+-	if (p->state == BR_STATE_LEARNING)
++	if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE))
+ 		goto drop;
+ 
+ 	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
diff --git a/target/linux/generic/patches-3.18/642-bridge_port_isolate.patch b/target/linux/generic/patches-3.18/642-bridge_port_isolate.patch
new file mode 100644
index 0000000000..d231f881b9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/642-bridge_port_isolate.patch
@@ -0,0 +1,107 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: port isolate
+
+Isolating individual bridge ports
+---
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -172,6 +172,7 @@ struct net_bridge_port
+ #define BR_FLOOD		0x00000040
+ #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
+ #define BR_PROMISC		0x00000080
++#define BR_ISOLATE_MODE		0x00000100
+ 
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ 	struct bridge_mcast_own_query	ip4_own_query;
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -171,6 +171,22 @@ BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLO
+ BRPORT_ATTR_FLAG(learning, BR_LEARNING);
+ BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
+ 
++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf)
++{
++	int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0;
++	return sprintf(buf, "%d\n", isolate_mode);
++}
++static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v)
++{
++	if (v)
++		p->flags |= BR_ISOLATE_MODE;
++	else
++		p->flags &= ~BR_ISOLATE_MODE;
++	return 0;
++}
++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR,
++		   show_isolate_mode, store_isolate_mode);
++
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
+ {
+@@ -213,6 +229,7 @@ static const struct brport_attribute *br
+ 	&brport_attr_multicast_router,
+ 	&brport_attr_multicast_fast_leave,
+ #endif
++	&brport_attr_isolate_mode,
+ 	NULL
+ };
+ 
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -120,8 +120,8 @@ int br_handle_frame_finish(struct sk_buf
+ 
+ 		unicast = false;
+ 		br->dev->stats.multicast++;
+-	} else if ((dst = __br_fdb_get(br, dest, vid)) &&
+-			dst->is_local) {
++	} else if ((p->flags & BR_ISOLATE_MODE) ||
++		   ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local)) {
+ 		skb2 = skb;
+ 		/* Do not forward the packet since it's local. */
+ 		skb = NULL;
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -117,7 +117,7 @@ EXPORT_SYMBOL_GPL(br_deliver);
+ /* called with rcu_read_lock */
+ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
+ {
+-	if (should_deliver(to, skb)) {
++	if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) {
+ 		if (skb0)
+ 			deliver_clone(to, skb, __br_forward);
+ 		else
+@@ -173,7 +173,7 @@ static void br_flood(struct net_bridge *
+ 		     struct sk_buff *skb0,
+ 		     void (*__packet_hook)(const struct net_bridge_port *p,
+ 					   struct sk_buff *skb),
+-		     bool unicast)
++		     				bool unicast, bool forward)
+ {
+ 	struct net_bridge_port *p;
+ 	struct net_bridge_port *prev;
+@@ -181,6 +181,8 @@ static void br_flood(struct net_bridge *
+ 	prev = NULL;
+ 
+ 	list_for_each_entry_rcu(p, &br->port_list, list) {
++		if (forward && (p->flags & BR_ISOLATE_MODE))
++			continue;
+ 		/* Do not flood unicast traffic to ports that turn it off */
+ 		if (unicast && !(p->flags & BR_FLOOD))
+ 			continue;
+@@ -207,14 +209,14 @@ out:
+ /* called with rcu_read_lock */
+ void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast)
+ {
+-	br_flood(br, skb, NULL, __br_deliver, unicast);
++	br_flood(br, skb, NULL, __br_deliver, unicast, false);
+ }
+ 
+ /* called under bridge lock */
+ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
+ 		      struct sk_buff *skb2, bool unicast)
+ {
+-	br_flood(br, skb, skb2, __br_forward, unicast);
++	br_flood(br, skb, skb2, __br_forward, unicast, true);
+ }
+ 
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
diff --git a/target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch
new file mode 100644
index 0000000000..1226770a3b
--- /dev/null
+++ b/target/linux/generic/patches-3.18/645-bridge_multicast_to_unicast.patch
@@ -0,0 +1,390 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: multicast to unicast
+
+Implement optinal multicast->unicast conversion for igmp snooping
+---
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -635,7 +635,8 @@ struct net_bridge_port_group *br_multica
+ 			struct net_bridge_port *port,
+ 			struct br_ip *group,
+ 			struct net_bridge_port_group __rcu *next,
+-			unsigned char state)
++			unsigned char state,
++			const unsigned char *src)
+ {
+ 	struct net_bridge_port_group *p;
+ 
+@@ -650,12 +651,33 @@ struct net_bridge_port_group *br_multica
+ 	hlist_add_head(&p->mglist, &port->mglist);
+ 	setup_timer(&p->timer, br_multicast_port_group_expired,
+ 		    (unsigned long)p);
++	if ((port->flags & BR_MULTICAST_TO_UCAST) && src) {
++		memcpy(p->eth_addr, src, ETH_ALEN);
++		p->unicast = true;
++	}
+ 	return p;
+ }
+ 
++static bool br_port_group_equal(struct net_bridge_port_group *p,
++				struct net_bridge_port *port,
++				const unsigned char *src)
++{
++	if (p->port != port)
++		return false;
++
++	if (!p->unicast)
++		return true;
++
++	if (!src)
++		return false;
++
++	return ether_addr_equal(src, p->eth_addr);
++}
++
+ static int br_multicast_add_group(struct net_bridge *br,
+ 				  struct net_bridge_port *port,
+-				  struct br_ip *group)
++				  struct br_ip *group,
++				  const unsigned char *src)
+ {
+ 	struct net_bridge_mdb_entry *mp;
+ 	struct net_bridge_port_group *p;
+@@ -682,13 +704,13 @@ static int br_multicast_add_group(struct
+ 	for (pp = &mp->ports;
+ 	     (p = mlock_dereference(*pp, br)) != NULL;
+ 	     pp = &p->next) {
+-		if (p->port == port)
++		if (br_port_group_equal(p, port, src))
+ 			goto found;
+ 		if ((unsigned long)p->port < (unsigned long)port)
+ 			break;
+ 	}
+ 
+-	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
++	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src);
+ 	if (unlikely(!p))
+ 		goto err;
+ 	rcu_assign_pointer(*pp, p);
+@@ -707,7 +729,7 @@ err:
+ static int br_ip4_multicast_add_group(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      __be32 group,
+-				      __u16 vid)
++				      __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 
+@@ -718,14 +740,14 @@ static int br_ip4_multicast_add_group(st
+ 	br_group.proto = htons(ETH_P_IP);
+ 	br_group.vid = vid;
+ 
+-	return br_multicast_add_group(br, port, &br_group);
++	return br_multicast_add_group(br, port, &br_group, src);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static int br_ip6_multicast_add_group(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      const struct in6_addr *group,
+-				      __u16 vid)
++				      __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 
+@@ -736,7 +758,7 @@ static int br_ip6_multicast_add_group(st
+ 	br_group.proto = htons(ETH_P_IPV6);
+ 	br_group.vid = vid;
+ 
+-	return br_multicast_add_group(br, port, &br_group);
++	return br_multicast_add_group(br, port, &br_group, src);
+ }
+ #endif
+ 
+@@ -965,6 +987,7 @@ static int br_ip4_multicast_igmp3_report
+ 					 struct sk_buff *skb,
+ 					 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct igmpv3_report *ih;
+ 	struct igmpv3_grec *grec;
+ 	int i;
+@@ -1008,7 +1031,8 @@ static int br_ip4_multicast_igmp3_report
+ 			continue;
+ 		}
+ 
+-		err = br_ip4_multicast_add_group(br, port, group, vid);
++		src = eth_hdr(skb)->h_source;
++		err = br_ip4_multicast_add_group(br, port, group, vid, src);
+ 		if (err)
+ 			break;
+ 	}
+@@ -1022,6 +1046,7 @@ static int br_ip6_multicast_mld2_report(
+ 					struct sk_buff *skb,
+ 					u16 vid)
+ {
++	const unsigned char *src;
+ 	struct icmp6hdr *icmp6h;
+ 	struct mld2_grec *grec;
+ 	int i;
+@@ -1069,8 +1094,9 @@ static int br_ip6_multicast_mld2_report(
+ 			continue;
+ 		}
+ 
++		src = eth_hdr(skb)->h_source;
+ 		err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
+-						 vid);
++						 vid, src);
+ 		if (err)
+ 			break;
+ 	}
+@@ -1406,7 +1432,8 @@ br_multicast_leave_group(struct net_brid
+ 			 struct net_bridge_port *port,
+ 			 struct br_ip *group,
+ 			 struct bridge_mcast_other_query *other_query,
+-			 struct bridge_mcast_own_query *own_query)
++			 struct bridge_mcast_own_query *own_query,
++			 const unsigned char *src)
+ {
+ 	struct net_bridge_mdb_htable *mdb;
+ 	struct net_bridge_mdb_entry *mp;
+@@ -1456,7 +1483,7 @@ br_multicast_leave_group(struct net_brid
+ 		for (pp = &mp->ports;
+ 		     (p = mlock_dereference(*pp, br)) != NULL;
+ 		     pp = &p->next) {
+-			if (p->port != port)
++			if (!br_port_group_equal(p, port, src))
+ 				continue;
+ 
+ 			rcu_assign_pointer(*pp, p->next);
+@@ -1490,7 +1517,7 @@ br_multicast_leave_group(struct net_brid
+ 	for (p = mlock_dereference(mp->ports, br);
+ 	     p != NULL;
+ 	     p = mlock_dereference(p->next, br)) {
+-		if (p->port != port)
++		if (!br_port_group_equal(p, port, src))
+ 			continue;
+ 
+ 		if (!hlist_unhashed(&p->mglist) &&
+@@ -1508,8 +1535,8 @@ out:
+ 
+ static void br_ip4_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+-					 __be32 group,
+-					 __u16 vid)
++					 __be32 group, __u16 vid,
++					 const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 	struct bridge_mcast_own_query *own_query;
+@@ -1524,14 +1551,14 @@ static void br_ip4_multicast_leave_group
+ 	br_group.vid = vid;
+ 
+ 	br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
+-				 own_query);
++				 own_query, src);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static void br_ip6_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+ 					 const struct in6_addr *group,
+-					 __u16 vid)
++					 __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 	struct bridge_mcast_own_query *own_query;
+@@ -1546,7 +1573,7 @@ static void br_ip6_multicast_leave_group
+ 	br_group.vid = vid;
+ 
+ 	br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
+-				 own_query);
++				 own_query, src);
+ }
+ #endif
+ 
+@@ -1555,6 +1582,7 @@ static int br_multicast_ipv4_rcv(struct
+ 				 struct sk_buff *skb,
+ 				 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct sk_buff *skb2 = skb;
+ 	const struct iphdr *iph;
+ 	struct igmphdr *ih;
+@@ -1628,7 +1656,8 @@ static int br_multicast_ipv4_rcv(struct
+ 	case IGMP_HOST_MEMBERSHIP_REPORT:
+ 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
+ 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
+-		err = br_ip4_multicast_add_group(br, port, ih->group, vid);
++		src = eth_hdr(skb)->h_source;
++		err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
+ 		break;
+ 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
+ 		err = br_ip4_multicast_igmp3_report(br, port, skb2, vid);
+@@ -1637,7 +1666,8 @@ static int br_multicast_ipv4_rcv(struct
+ 		err = br_ip4_multicast_query(br, port, skb2, vid);
+ 		break;
+ 	case IGMP_HOST_LEAVE_MESSAGE:
+-		br_ip4_multicast_leave_group(br, port, ih->group, vid);
++		src = eth_hdr(skb)->h_source;
++		br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
+ 		break;
+ 	}
+ 
+@@ -1655,6 +1685,7 @@ static int br_multicast_ipv6_rcv(struct
+ 				 struct sk_buff *skb,
+ 				 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct sk_buff *skb2;
+ 	const struct ipv6hdr *ip6h;
+ 	u8 icmp6_type;
+@@ -1764,7 +1795,9 @@ static int br_multicast_ipv6_rcv(struct
+ 		}
+ 		mld = (struct mld_msg *)skb_transport_header(skb2);
+ 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
+-		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
++		src = eth_hdr(skb)->h_source;
++		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid,
++						 src);
+ 		break;
+ 	    }
+ 	case ICMPV6_MLD2_REPORT:
+@@ -1781,7 +1814,8 @@ static int br_multicast_ipv6_rcv(struct
+ 			goto out;
+ 		}
+ 		mld = (struct mld_msg *)skb_transport_header(skb2);
+-		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
++		src = eth_hdr(skb)->h_source;
++		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
+ 	    }
+ 	}
+ 
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -112,6 +112,9 @@ struct net_bridge_port_group {
+ 	struct timer_list		timer;
+ 	struct br_ip			addr;
+ 	unsigned char			state;
++
++	unsigned char			eth_addr[ETH_ALEN];
++	bool				unicast;
+ };
+ 
+ struct net_bridge_mdb_entry
+@@ -173,6 +176,7 @@ struct net_bridge_port
+ #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
+ #define BR_PROMISC		0x00000080
+ #define BR_ISOLATE_MODE		0x00000100
++#define BR_MULTICAST_TO_UCAST	0x00000200
+ 
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ 	struct bridge_mcast_own_query	ip4_own_query;
+@@ -485,7 +489,8 @@ void br_multicast_free_pg(struct rcu_hea
+ struct net_bridge_port_group *
+ br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
+ 			    struct net_bridge_port_group __rcu *next,
+-			    unsigned char state);
++			    unsigned char state,
++		       const unsigned char *src);
+ void br_mdb_init(void);
+ void br_mdb_uninit(void);
+ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+--- a/net/bridge/br_mdb.c
++++ b/net/bridge/br_mdb.c
+@@ -342,7 +342,7 @@ static int br_mdb_add_group(struct net_b
+ 			break;
+ 	}
+ 
+-	p = br_multicast_new_port_group(port, group, *pp, state);
++	p = br_multicast_new_port_group(port, group, *pp, state, NULL);
+ 	if (unlikely(!p))
+ 		return -ENOMEM;
+ 	rcu_assign_pointer(*pp, p);
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -168,6 +168,34 @@ out:
+ 	return p;
+ }
+ 
++static struct net_bridge_port *maybe_deliver_addr(
++	struct net_bridge_port *prev, struct net_bridge_port *p,
++	struct sk_buff *skb, const unsigned char *addr,
++	void (*__packet_hook)(const struct net_bridge_port *p,
++			      struct sk_buff *skb))
++{
++	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
++	const unsigned char *src = eth_hdr(skb)->h_source;
++
++	if (!should_deliver(p, skb))
++		return prev;
++
++	/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
++	if (skb->dev == p->dev && ether_addr_equal(src, addr))
++		return prev;
++
++	skb = skb_copy(skb, GFP_ATOMIC);
++	if (!skb) {
++		dev->stats.tx_dropped++;
++		return prev;
++	}
++
++	memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
++	__packet_hook(p, skb);
++
++	return prev;
++}
++
+ /* called under bridge lock */
+ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
+ 		     struct sk_buff *skb0,
+@@ -232,6 +260,7 @@ static void br_multicast_flood(struct ne
+ 	struct net_bridge_port *prev = NULL;
+ 	struct net_bridge_port_group *p;
+ 	struct hlist_node *rp;
++	const unsigned char *addr;
+ 
+ 	rp = rcu_dereference(hlist_first_rcu(&br->router_list));
+ 	p = mdst ? rcu_dereference(mdst->ports) : NULL;
+@@ -242,10 +271,19 @@ static void br_multicast_flood(struct ne
+ 		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
+ 			     NULL;
+ 
+-		port = (unsigned long)lport > (unsigned long)rport ?
+-		       lport : rport;
+-
+-		prev = maybe_deliver(prev, port, skb, __packet_hook);
++		if ((unsigned long)lport > (unsigned long)rport) {
++			port = lport;
++			addr = p->unicast ? p->eth_addr : NULL;
++		} else {
++			port = rport;
++			addr = NULL;
++		}
++
++		if (addr)
++			prev = maybe_deliver_addr(prev, port, skb, addr,
++						  __packet_hook);
++		else
++			prev = maybe_deliver(prev, port, skb, __packet_hook);
+ 		if (IS_ERR(prev))
+ 			goto out;
+ 
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -202,6 +202,7 @@ static BRPORT_ATTR(multicast_router, S_I
+ 		   store_multicast_router);
+ 
+ BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
++BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST);
+ #endif
+ 
+ static const struct brport_attribute *brport_attrs[] = {
+@@ -228,6 +229,7 @@ static const struct brport_attribute *br
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ 	&brport_attr_multicast_router,
+ 	&brport_attr_multicast_fast_leave,
++	&brport_attr_multicast_to_unicast,
+ #endif
+ 	&brport_attr_isolate_mode,
+ 	NULL
diff --git a/target/linux/generic/patches-3.18/650-pppoe_header_pad.patch b/target/linux/generic/patches-3.18/650-pppoe_header_pad.patch
new file mode 100644
index 0000000000..eb9b4bfd15
--- /dev/null
+++ b/target/linux/generic/patches-3.18/650-pppoe_header_pad.patch
@@ -0,0 +1,20 @@
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -859,7 +859,7 @@ static int pppoe_sendmsg(struct kiocb *i
+ 		goto end;
+ 
+ 
+-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
++	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD,
+ 			   0, GFP_KERNEL);
+ 	if (!skb) {
+ 		error = -ENOMEM;
+@@ -867,7 +867,7 @@ static int pppoe_sendmsg(struct kiocb *i
+ 	}
+ 
+ 	/* Reserve space for headers. */
+-	skb_reserve(skb, dev->hard_header_len);
++	skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD);
+ 	skb_reset_network_header(skb);
+ 
+ 	skb->dev = dev;
diff --git a/target/linux/generic/patches-3.18/651-wireless_mesh_header.patch b/target/linux/generic/patches-3.18/651-wireless_mesh_header.patch
new file mode 100644
index 0000000000..16da5cd66f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/651-wireless_mesh_header.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -130,7 +130,7 @@ static inline bool dev_xmit_complete(int
+  */
+ 
+ #if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
+-# if defined(CONFIG_MAC80211_MESH)
++# if 1 || defined(CONFIG_MAC80211_MESH)
+ #  define LL_MAX_HEADER 128
+ # else
+ #  define LL_MAX_HEADER 96
diff --git a/target/linux/generic/patches-3.18/653-disable_netlink_trim.patch b/target/linux/generic/patches-3.18/653-disable_netlink_trim.patch
new file mode 100644
index 0000000000..b38b87b48f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/653-disable_netlink_trim.patch
@@ -0,0 +1,30 @@
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1721,27 +1721,7 @@ void netlink_detachskb(struct sock *sk,
+ 
+ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
+ {
+-	int delta;
+-
+ 	WARN_ON(skb->sk != NULL);
+-	if (netlink_skb_is_mmaped(skb))
+-		return skb;
+-
+-	delta = skb->end - skb->tail;
+-	if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize)
+-		return skb;
+-
+-	if (skb_shared(skb)) {
+-		struct sk_buff *nskb = skb_clone(skb, allocation);
+-		if (!nskb)
+-			return skb;
+-		consume_skb(skb);
+-		skb = nskb;
+-	}
+-
+-	if (!pskb_expand_head(skb, 0, -delta, allocation))
+-		skb->truesize -= delta;
+-
+ 	return skb;
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/655-increase_skb_pad.patch b/target/linux/generic/patches-3.18/655-increase_skb_pad.patch
new file mode 100644
index 0000000000..19344cca3f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/655-increase_skb_pad.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2023,7 +2023,7 @@ static inline int pskb_network_may_pull(
+  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
+  */
+ #ifndef NET_SKB_PAD
+-#define NET_SKB_PAD	max(32, L1_CACHE_BYTES)
++#define NET_SKB_PAD	max(64, L1_CACHE_BYTES)
+ #endif
+ 
+ int ___pskb_trim(struct sk_buff *skb, unsigned int len);
diff --git a/target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch b/target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch
new file mode 100644
index 0000000000..b326a8b727
--- /dev/null
+++ b/target/linux/generic/patches-3.18/656-skb_reduce_truesize-helper.patch
@@ -0,0 +1,41 @@
+From 4593a806e31119c5bd3faa00c7210ad862d515af Mon Sep 17 00:00:00 2001
+From: Dave Taht <dave.taht@bufferbloat.net>
+Date: Mon, 31 Dec 2012 10:02:21 -0800
+Subject: [PATCH 3/7] skb_reduce_truesize: helper function for shrinking skbs
+ whenever needed
+
+On embedded devices in particular, large queues of small packets from the rx
+path with a large truesize can exist. Reducing their size can reduce
+memory pressure. skb_reduce_truesize is a helper function for doing this,
+when needed.
+---
+ include/linux/skbuff.h |   18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2068,6 +2068,24 @@ static inline void pskb_trim_unique(stru
+ 	BUG_ON(err);
+ }
+ 
++/*
++ * Caller wants to reduce memory needs before queueing skb
++ * The (expensive) copy should not be be done in fast path.
++ */
++static inline struct sk_buff *skb_reduce_truesize(struct sk_buff *skb)
++{
++	if (skb->truesize > 2 * SKB_TRUESIZE(skb->len)) {
++		struct sk_buff *nskb;
++		nskb = skb_copy_expand(skb, skb_headroom(skb), 0,
++			GFP_ATOMIC | __GFP_NOWARN);
++		if (nskb) {
++			__kfree_skb(skb);
++			skb = nskb;
++		}
++	}
++	return skb;
++}
++
+ /**
+  *	skb_orphan - orphan a buffer
+  *	@skb: buffer to orphan
diff --git a/target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch b/target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch
new file mode 100644
index 0000000000..410e0b763d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/657-qdisc_reduce_truesize.patch
@@ -0,0 +1,63 @@
+From bc9fec2f87d57bdbff30d296605e24504513f65c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Dave=20T=C3=A4ht?= <dave.taht@bufferbloat.net>
+Date: Mon, 17 Sep 2012 19:20:22 -0700
+Subject: [PATCH 4/7] net: add skb_reduce_truesize support to common qdiscs
+
+Reduce skb size under load when queues begin to fill on the
+commont qdiscs.
+---
+ net/sched/sch_codel.c    |    2 ++
+ net/sched/sch_fifo.c     |   12 ++++++++----
+ net/sched/sch_fq_codel.c |    2 ++
+ 3 files changed, 12 insertions(+), 4 deletions(-)
+
+--- a/net/sched/sch_codel.c
++++ b/net/sched/sch_codel.c
+@@ -97,6 +97,8 @@ static int codel_qdisc_enqueue(struct sk
+ 	struct codel_sched_data *q;
+ 
+ 	if (likely(qdisc_qlen(sch) < sch->limit)) {
++		if(qdisc_qlen(sch) > 128)
++			skb = skb_reduce_truesize(skb);
+ 		codel_set_enqueue_time(skb);
+ 		return qdisc_enqueue_tail(skb, sch);
+ 	}
+--- a/net/sched/sch_fifo.c
++++ b/net/sched/sch_fifo.c
+@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff
+ 
+ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+-	if (likely(skb_queue_len(&sch->q) < sch->limit))
++	if (likely(skb_queue_len(&sch->q) < sch->limit)) {
++		if (skb_queue_len(&sch->q) > 128)
++			skb = skb_reduce_truesize(skb);
+ 		return qdisc_enqueue_tail(skb, sch);
+-
++	}
+ 	return qdisc_reshape_fail(skb, sch);
+ }
+ 
+ static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+-	if (likely(skb_queue_len(&sch->q) < sch->limit))
++	if (likely(skb_queue_len(&sch->q) < sch->limit)) {
++		if (skb_queue_len(&sch->q) > 128)
++			skb = skb_reduce_truesize(skb);
+ 		return qdisc_enqueue_tail(skb, sch);
+-
++	}
+ 	/* queue full, remove one skb to fulfill the limit */
+ 	__qdisc_queue_drop_head(sch, &sch->q);
+ 	qdisc_qstats_drop(sch);
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -185,6 +185,8 @@ static int fq_codel_enqueue(struct sk_bu
+ 		return ret;
+ 	}
+ 	idx--;
++	if (sch->q.qlen > 128)
++		skb = skb_reduce_truesize(skb);
+ 
+ 	codel_set_enqueue_time(skb);
+ 	flow = &q->flows[idx];
diff --git a/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch b/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch
new file mode 100644
index 0000000000..8a870cccc1
--- /dev/null
+++ b/target/linux/generic/patches-3.18/660-fq_codel_defaults.patch
@@ -0,0 +1,13 @@
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -394,8 +394,8 @@ static int fq_codel_init(struct Qdisc *s
+ 	struct fq_codel_sched_data *q = qdisc_priv(sch);
+ 	int i;
+ 
+-	sch->limit = 10*1024;
+-	q->flows_cnt = 1024;
++	sch->limit = 1024;
++	q->flows_cnt = 128;
+ 	q->quantum = psched_mtu(qdisc_dev(sch));
+ 	q->perturbation = prandom_u32();
+ 	INIT_LIST_HEAD(&q->new_flows);
diff --git a/target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch
new file mode 100644
index 0000000000..45a8d68367
--- /dev/null
+++ b/target/linux/generic/patches-3.18/661-fq_codel_keep_dropped_stats.patch
@@ -0,0 +1,10 @@
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -198,7 +198,6 @@ static int fq_codel_enqueue(struct sk_bu
+ 		list_add_tail(&flow->flowchain, &q->new_flows);
+ 		q->new_flow_count++;
+ 		flow->deficit = q->quantum;
+-		flow->dropped = 0;
+ 	}
+ 	if (++sch->q.qlen <= sch->limit)
+ 		return NET_XMIT_SUCCESS;
diff --git a/target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch
new file mode 100644
index 0000000000..39abfaabea
--- /dev/null
+++ b/target/linux/generic/patches-3.18/662-use_fq_codel_by_default.patch
@@ -0,0 +1,95 @@
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -3,8 +3,9 @@
+ # 
+ 
+ menuconfig NET_SCHED
+-	bool "QoS and/or fair queueing"
++	def_bool y
+ 	select NET_SCH_FIFO
++	select NET_SCH_FQ_CODEL
+ 	---help---
+ 	  When the kernel has several packets to send out over a network
+ 	  device, it has to decide which ones to send first, which ones to
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -599,7 +599,7 @@ static const struct Qdisc_class_ops fq_c
+ 	.walk		=	fq_codel_walk,
+ };
+ 
+-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
+ 	.cl_ops		=	&fq_codel_class_ops,
+ 	.id		=	"fq_codel",
+ 	.priv_size	=	sizeof(struct fq_codel_sched_data),
+@@ -615,6 +615,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
+ 	.dump_stats =	fq_codel_dump_stats,
+ 	.owner		=	THIS_MODULE,
+ };
++EXPORT_SYMBOL(fq_codel_qdisc_ops);
+ 
+ static int __init fq_codel_module_init(void)
+ {
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -341,6 +341,7 @@ extern struct Qdisc noop_qdisc;
+ extern struct Qdisc_ops noop_qdisc_ops;
+ extern struct Qdisc_ops pfifo_fast_ops;
+ extern struct Qdisc_ops mq_qdisc_ops;
++extern struct Qdisc_ops fq_codel_qdisc_ops;
+ extern const struct Qdisc_ops *default_qdisc_ops;
+ 
+ struct Qdisc_class_common {
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -31,7 +31,7 @@
+ #include <net/dst.h>
+ 
+ /* Qdisc to use by default */
+-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
+ EXPORT_SYMBOL(default_qdisc_ops);
+ 
+ /* Main transmission queue. */
+@@ -742,7 +742,7 @@ static void attach_one_default_qdisc(str
+ 
+ 	if (dev->tx_queue_len) {
+ 		qdisc = qdisc_create_dflt(dev_queue,
+-					  default_qdisc_ops, TC_H_ROOT);
++					  &fq_codel_qdisc_ops, TC_H_ROOT);
+ 		if (!qdisc) {
+ 			netdev_info(dev, "activation failed\n");
+ 			return;
+--- a/net/sched/sch_mq.c
++++ b/net/sched/sch_mq.c
+@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, st
+ 
+ 	for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+ 		dev_queue = netdev_get_tx_queue(dev, ntx);
+-		qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
++		qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops,
+ 					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+ 						    TC_H_MIN(ntx + 1)));
+ 		if (qdisc == NULL)
+--- a/net/sched/sch_mqprio.c
++++ b/net/sched/sch_mqprio.c
+@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch
+ 
+ 	for (i = 0; i < dev->num_tx_queues; i++) {
+ 		dev_queue = netdev_get_tx_queue(dev, i);
+-		qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
++		qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops,
+ 					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+ 						    TC_H_MIN(i + 1)));
+ 		if (qdisc == NULL) {
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -1949,7 +1949,7 @@ static int __init pktsched_init(void)
+ 		return err;
+ 	}
+ 
+-	register_qdisc(&pfifo_fast_ops);
++	register_qdisc(&fq_codel_qdisc_ops);
+ 	register_qdisc(&pfifo_qdisc_ops);
+ 	register_qdisc(&bfifo_qdisc_ops);
+ 	register_qdisc(&pfifo_head_drop_qdisc_ops);
diff --git a/target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch b/target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch
new file mode 100644
index 0000000000..50b90b375f
--- /dev/null
+++ b/target/linux/generic/patches-3.18/663-remove_pfifo_fast.patch
@@ -0,0 +1,143 @@
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -445,140 +445,6 @@ static struct Qdisc noqueue_qdisc = {
+ 	.busylock	=	__SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock),
+ };
+ 
+-
+-static const u8 prio2band[TC_PRIO_MAX + 1] = {
+-	1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
+-};
+-
+-/* 3-band FIFO queue: old style, but should be a bit faster than
+-   generic prio+fifo combination.
+- */
+-
+-#define PFIFO_FAST_BANDS 3
+-
+-/*
+- * Private data for a pfifo_fast scheduler containing:
+- * 	- queues for the three band
+- * 	- bitmap indicating which of the bands contain skbs
+- */
+-struct pfifo_fast_priv {
+-	u32 bitmap;
+-	struct sk_buff_head q[PFIFO_FAST_BANDS];
+-};
+-
+-/*
+- * Convert a bitmap to the first band number where an skb is queued, where:
+- * 	bitmap=0 means there are no skbs on any band.
+- * 	bitmap=1 means there is an skb on band 0.
+- *	bitmap=7 means there are skbs on all 3 bands, etc.
+- */
+-static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0};
+-
+-static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv,
+-					     int band)
+-{
+-	return priv->q + band;
+-}
+-
+-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc)
+-{
+-	if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) {
+-		int band = prio2band[skb->priority & TC_PRIO_MAX];
+-		struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-		struct sk_buff_head *list = band2list(priv, band);
+-
+-		priv->bitmap |= (1 << band);
+-		qdisc->q.qlen++;
+-		return __qdisc_enqueue_tail(skb, qdisc, list);
+-	}
+-
+-	return qdisc_drop(skb, qdisc);
+-}
+-
+-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int band = bitmap2band[priv->bitmap];
+-
+-	if (likely(band >= 0)) {
+-		struct sk_buff_head *list = band2list(priv, band);
+-		struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list);
+-
+-		qdisc->q.qlen--;
+-		if (skb_queue_empty(list))
+-			priv->bitmap &= ~(1 << band);
+-
+-		return skb;
+-	}
+-
+-	return NULL;
+-}
+-
+-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int band = bitmap2band[priv->bitmap];
+-
+-	if (band >= 0) {
+-		struct sk_buff_head *list = band2list(priv, band);
+-
+-		return skb_peek(list);
+-	}
+-
+-	return NULL;
+-}
+-
+-static void pfifo_fast_reset(struct Qdisc *qdisc)
+-{
+-	int prio;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+-		__qdisc_reset_queue(qdisc, band2list(priv, prio));
+-
+-	priv->bitmap = 0;
+-	qdisc->qstats.backlog = 0;
+-	qdisc->q.qlen = 0;
+-}
+-
+-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
+-{
+-	struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
+-
+-	memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1);
+-	if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+-		goto nla_put_failure;
+-	return skb->len;
+-
+-nla_put_failure:
+-	return -1;
+-}
+-
+-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
+-{
+-	int prio;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+-		__skb_queue_head_init(band2list(priv, prio));
+-
+-	/* Can by-pass the queue discipline */
+-	qdisc->flags |= TCQ_F_CAN_BYPASS;
+-	return 0;
+-}
+-
+-struct Qdisc_ops pfifo_fast_ops __read_mostly = {
+-	.id		=	"pfifo_fast",
+-	.priv_size	=	sizeof(struct pfifo_fast_priv),
+-	.enqueue	=	pfifo_fast_enqueue,
+-	.dequeue	=	pfifo_fast_dequeue,
+-	.peek		=	pfifo_fast_peek,
+-	.init		=	pfifo_fast_init,
+-	.reset		=	pfifo_fast_reset,
+-	.dump		=	pfifo_fast_dump,
+-	.owner		=	THIS_MODULE,
+-};
+-
+ static struct lock_class_key qdisc_tx_busylock;
+ 
+ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
diff --git a/target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
new file mode 100644
index 0000000000..000665f047
--- /dev/null
+++ b/target/linux/generic/patches-3.18/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
@@ -0,0 +1,481 @@
+From 775d6fe74d1eaec2ba387535b068dde2dc89de9e Mon Sep 17 00:00:00 2001
+From: Steven Barth <steven@midlink.org>
+Date: Thu, 22 May 2014 09:49:05 +0200
+Subject: [PATCH] Add support for MAP-E FMRs (mesh mode)
+
+MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
+between MAP CEs (mesh mode) without the need to forward such data to a
+border relay. This is similar to how 6rd works but for IPv4 over IPv6.
+
+Signed-off-by: Steven Barth <cyrus@openwrt.org>
+---
+ include/net/ip6_tunnel.h       |  13 ++
+ include/uapi/linux/if_tunnel.h |  13 ++
+ net/ipv6/ip6_tunnel.c          | 276 +++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 291 insertions(+), 11 deletions(-)
+
+--- a/include/net/ip6_tunnel.h
++++ b/include/net/ip6_tunnel.h
+@@ -15,6 +15,18 @@
+ /* determine capability on a per-packet basis */
+ #define IP6_TNL_F_CAP_PER_PACKET 0x40000
+ 
++/* IPv6 tunnel FMR */
++struct __ip6_tnl_fmr {
++	struct __ip6_tnl_fmr *next; /* next fmr in list */
++	struct in6_addr ip6_prefix;
++	struct in_addr ip4_prefix;
++
++	__u8 ip6_prefix_len;
++	__u8 ip4_prefix_len;
++	__u8 ea_len;
++	__u8 offset;
++};
++
+ struct __ip6_tnl_parm {
+ 	char name[IFNAMSIZ];	/* name of tunnel device */
+ 	int link;		/* ifindex of underlying L2 interface */
+@@ -25,6 +37,7 @@ struct __ip6_tnl_parm {
+ 	__u32 flags;		/* tunnel flags */
+ 	struct in6_addr laddr;	/* local tunnel end-point address */
+ 	struct in6_addr raddr;	/* remote tunnel end-point address */
++	struct __ip6_tnl_fmr *fmrs;	/* FMRs */
+ 
+ 	__be16			i_flags;
+ 	__be16			o_flags;
+--- a/include/uapi/linux/if_tunnel.h
++++ b/include/uapi/linux/if_tunnel.h
+@@ -57,10 +57,23 @@ enum {
+ 	IFLA_IPTUN_ENCAP_FLAGS,
+ 	IFLA_IPTUN_ENCAP_SPORT,
+ 	IFLA_IPTUN_ENCAP_DPORT,
++	IFLA_IPTUN_FMRS,
+ 	__IFLA_IPTUN_MAX,
+ };
+ #define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
+ 
++enum {
++	IFLA_IPTUN_FMR_UNSPEC,
++	IFLA_IPTUN_FMR_IP6_PREFIX,
++	IFLA_IPTUN_FMR_IP4_PREFIX,
++	IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
++	IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
++	IFLA_IPTUN_FMR_EA_LEN,
++	IFLA_IPTUN_FMR_OFFSET,
++	__IFLA_IPTUN_FMR_MAX,
++};
++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
++
+ enum tunnel_encap_types {
+ 	TUNNEL_ENCAP_NONE,
+ 	TUNNEL_ENCAP_FOU,
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -16,6 +16,8 @@
+  *      as published by the Free Software Foundation; either version
+  *      2 of the License, or (at your option) any later version.
+  *
++ *	Changes:
++ * Steven Barth <cyrus@openwrt.org>:		MAP-E FMR support
+  */
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+@@ -77,11 +79,9 @@ static bool log_ecn_error = true;
+ module_param(log_ecn_error, bool, 0644);
+ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
+ 
+-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
++static u32 HASH(const struct in6_addr *addr)
+ {
+-	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
+-
+-	return hash_32(hash, HASH_SIZE_SHIFT);
++	return hash_32(ipv6_addr_hash(addr), HASH_SIZE_SHIFT);
+ }
+ 
+ static int ip6_tnl_dev_init(struct net_device *dev);
+@@ -180,15 +180,24 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
+ static struct ip6_tnl *
+ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
+ {
+-	unsigned int hash = HASH(remote, local);
++	unsigned int hash = HASH(local);
+ 	struct ip6_tnl *t;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+-		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+-		    ipv6_addr_equal(remote, &t->parms.raddr) &&
+-		    (t->dev->flags & IFF_UP))
++		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
++				!(t->dev->flags & IFF_UP))
++			continue;
++
++		if (ipv6_addr_equal(remote, &t->parms.raddr))
+ 			return t;
++
++		for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++			if (ipv6_prefix_equal(remote, &fmr->ip6_prefix,
++					fmr->ip6_prefix_len))
++				return t;
++		}
+ 	}
+ 	t = rcu_dereference(ip6n->tnls_wc[0]);
+ 	if (t && (t->dev->flags & IFF_UP))
+@@ -218,7 +227,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
+ 
+ 	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ 		prio = 1;
+-		h = HASH(remote, local);
++		h = HASH(local);
+ 	}
+ 	return &ip6n->tnls[prio][h];
+ }
+@@ -388,6 +397,12 @@ ip6_tnl_dev_uninit(struct net_device *de
+ 	struct net *net = t->net;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++
+ 	if (dev == ip6n->fb_tnl_dev)
+ 		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
+ 	else
+@@ -771,6 +786,108 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
+ }
+ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
+ 
++
++/**
++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
++ *   @dest: destination IPv6 address buffer
++ *   @skb: received socket buffer
++ *   @fmr: MAP FMR
++ *   @xmit: Calculate for xmit or rcv
++ **/
++static void ip4ip6_fmr_calc(struct in6_addr *dest,
++		const struct iphdr *iph, const uint8_t *end,
++		const struct __ip6_tnl_fmr *fmr, bool xmit)
++{
++	int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
++	u8 *portp = NULL;
++	bool use_dest_addr;
++	const struct iphdr *dsth = iph;
++
++	if ((u8*)dsth >= end)
++		return;
++
++	/* find significant IP header */
++	if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++		if (ih && ((u8*)&ih[1]) <= end && (
++			ih->type == ICMP_DEST_UNREACH ||
++			ih->type == ICMP_SOURCE_QUENCH ||
++			ih->type == ICMP_TIME_EXCEEDED ||
++			ih->type == ICMP_PARAMETERPROB ||
++			ih->type == ICMP_REDIRECT))
++				dsth = (const struct iphdr*)&ih[1];
++	}
++
++	/* in xmit-path use dest port by default and source port only if
++		this is an ICMP reply to something else; vice versa in rcv-path */
++	use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
++
++	/* get dst port */
++	if (((u8*)&dsth[1]) <= end && (
++		dsth->protocol == IPPROTO_UDP ||
++		dsth->protocol == IPPROTO_TCP ||
++		dsth->protocol == IPPROTO_SCTP ||
++		dsth->protocol == IPPROTO_DCCP)) {
++			/* for UDP, TCP, SCTP and DCCP source and dest port
++			follow IPv4 header directly */
++			portp = ((u8*)dsth) + dsth->ihl * 4;
++
++			if (use_dest_addr)
++				portp += sizeof(u16);
++	} else if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++
++		/* use icmp identifier as port */
++		if (((u8*)&ih) <= end && (
++		    (use_dest_addr && (
++		    ih->type == ICMP_ECHOREPLY ||
++			ih->type == ICMP_TIMESTAMPREPLY ||
++			ih->type == ICMP_INFO_REPLY ||
++			ih->type == ICMP_ADDRESSREPLY)) ||
++			(!use_dest_addr && (
++			ih->type == ICMP_ECHO ||
++			ih->type == ICMP_TIMESTAMP ||
++			ih->type == ICMP_INFO_REQUEST ||
++			ih->type == ICMP_ADDRESS)
++			)))
++				portp = (u8*)&ih->un.echo.id;
++	}
++
++	if ((portp && &portp[2] <= end) || psidlen == 0) {
++		int frombyte = fmr->ip6_prefix_len / 8;
++		int fromrem = fmr->ip6_prefix_len % 8;
++		int bytes = sizeof(struct in6_addr) - frombyte;
++		const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
++		u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
++		u64 t = 0;
++
++		/* extract PSID from port and add it to eabits */
++		u16 psidbits = 0;
++		if (psidlen > 0) {
++			psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
++			psidbits >>= 16 - psidlen - fmr->offset;
++			psidbits = (u16)(psidbits << (16 - psidlen));
++			eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
++		}
++
++		/* rewrite destination address */
++		*dest = fmr->ip6_prefix;
++		memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
++		dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
++
++		if (bytes > sizeof(u64))
++			bytes = sizeof(u64);
++
++		/* insert eabits */
++		memcpy(&t, &dest->s6_addr[frombyte], bytes);
++		t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
++			<< (64 - fmr->ea_len - fromrem));
++		t = cpu_to_be64(t | (eabits >> fromrem));
++		memcpy(&dest->s6_addr[frombyte], &t, bytes);
++	}
++}
++
++
+ /**
+  * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
+  *   @skb: received socket buffer
+@@ -815,6 +932,26 @@ static int ip6_tnl_rcv(struct sk_buff *s
+ 		skb_reset_network_header(skb);
+ 		skb->protocol = htons(protocol);
+ 		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
++		if (protocol == ETH_P_IP &&
++			!ipv6_addr_equal(&ipv6h->saddr, &t->parms.raddr)) {
++				/* Packet didn't come from BR, so lookup FMR */
++				struct __ip6_tnl_fmr *fmr;
++				struct in6_addr expected = t->parms.raddr;
++				for (fmr = t->parms.fmrs; fmr; fmr = fmr->next)
++					if (ipv6_prefix_equal(&ipv6h->saddr,
++						&fmr->ip6_prefix, fmr->ip6_prefix_len))
++							break;
++
++				/* Check that IPv6 matches IPv4 source to prevent spoofing */
++				if (fmr)
++					ip4ip6_fmr_calc(&expected, ip_hdr(skb),
++							skb_tail_pointer(skb), fmr, false);
++
++				if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
++					rcu_read_unlock();
++					goto discard;
++				}
++		}
+ 
+ 		__skb_tunnel_rx(skb, t->dev, t->net);
+ 
+@@ -1076,6 +1213,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str
+ 	__u8 dsfield;
+ 	__u32 mtu;
+ 	int err;
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) ||
+ 	    !ip6_tnl_xmit_ctl(t))
+@@ -1095,6 +1233,18 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+ 		fl6.flowi6_mark = skb->mark;
+ 
++	/* try to find matching FMR */
++	for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++		unsigned mshift = 32 - fmr->ip4_prefix_len;
++		if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
++				ntohl(iph->daddr) >> mshift)
++			break;
++	}
++
++	/* change dstaddr according to FMR */
++	if (fmr)
++		ip4ip6_fmr_calc(&fl6.daddr, iph, skb_tail_pointer(skb), fmr, true);
++
+ 	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+ 	if (err != 0) {
+ 		/* XXX: send ICMP error even if DF is not set. */
+@@ -1263,6 +1413,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
+ 	t->parms.flowinfo = p->flowinfo;
+ 	t->parms.link = p->link;
+ 	t->parms.proto = p->proto;
++
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++	t->parms.fmrs = p->fmrs;
++
+ 	ip6_tnl_dst_reset(t);
+ 	ip6_tnl_link_config(t);
+ 	return 0;
+@@ -1293,6 +1451,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
+ 	p->flowinfo = u->flowinfo;
+ 	p->link = u->link;
+ 	p->proto = u->proto;
++	p->fmrs = NULL;
+ 	memcpy(p->name, u->name, sizeof(u->name));
+ }
+ 
+@@ -1568,6 +1727,15 @@ static int ip6_tnl_validate(struct nlatt
+ 	return 0;
+ }
+ 
++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
++	[IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
++	[IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
++	[IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
++};
++
+ static void ip6_tnl_netlink_parms(struct nlattr *data[],
+ 				  struct __ip6_tnl_parm *parms)
+ {
+@@ -1601,6 +1769,46 @@ static void ip6_tnl_netlink_parms(struct
+ 
+ 	if (data[IFLA_IPTUN_PROTO])
+ 		parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
++
++	if (data[IFLA_IPTUN_FMRS]) {
++		unsigned rem;
++		struct nlattr *fmr;
++		nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
++			struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
++			struct __ip6_tnl_fmr *nfmr;
++
++			nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
++				fmr, ip6_tnl_fmr_policy);
++
++			if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
++				continue;
++
++			nfmr->offset = 6;
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
++				nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
++					sizeof(nfmr->ip6_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
++				nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
++					sizeof(nfmr->ip4_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
++				nfmr->ip6_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
++				nfmr->ip4_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
++				nfmr->ea_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
++				nfmr->offset = nla_get_u8(c);
++
++			nfmr->next = parms->fmrs;
++			parms->fmrs = nfmr;
++		}
++	}
+ }
+ 
+ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
+@@ -1653,6 +1861,12 @@ static void ip6_tnl_dellink(struct net_d
+ 
+ static size_t ip6_tnl_get_size(const struct net_device *dev)
+ {
++	const struct ip6_tnl *t = netdev_priv(dev);
++	struct __ip6_tnl_fmr *c;
++	int fmrs = 0;
++	for (c = t->parms.fmrs; c; c = c->next)
++		++fmrs;
++
+ 	return
+ 		/* IFLA_IPTUN_LINK */
+ 		nla_total_size(4) +
+@@ -1670,6 +1884,24 @@ static size_t ip6_tnl_get_size(const str
+ 		nla_total_size(4) +
+ 		/* IFLA_IPTUN_PROTO */
+ 		nla_total_size(1) +
++		/* IFLA_IPTUN_FMRS */
++		nla_total_size(0) +
++		(
++			/* nest */
++			nla_total_size(0) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX */
++			nla_total_size(sizeof(struct in6_addr)) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX */
++			nla_total_size(sizeof(struct in_addr)) +
++			/* IFLA_IPTUN_FMR_EA_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_OFFSET */
++			nla_total_size(1)
++		) * fmrs +
+ 		0;
+ }
+ 
+@@ -1677,6 +1909,9 @@ static int ip6_tnl_fill_info(struct sk_b
+ {
+ 	struct ip6_tnl *tunnel = netdev_priv(dev);
+ 	struct __ip6_tnl_parm *parm = &tunnel->parms;
++	struct __ip6_tnl_fmr *c;
++	int fmrcnt = 0;
++	struct nlattr *fmrs;
+ 
+ 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
+ 	    nla_put(skb, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr),
+@@ -1687,8 +1922,27 @@ static int ip6_tnl_fill_info(struct sk_b
+ 	    nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
+ 	    nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
+ 	    nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
+-	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto))
++	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
++	    !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
+ 		goto nla_put_failure;
++
++	for (c = parm->fmrs; c; c = c->next) {
++		struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
++		if (!fmr ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
++				sizeof(c->ip6_prefix), &c->ip6_prefix) ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
++				sizeof(c->ip4_prefix), &c->ip4_prefix) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
++				goto nla_put_failure;
++
++		nla_nest_end(skb, fmr);
++	}
++	nla_nest_end(skb, fmrs);
++
+ 	return 0;
+ 
+ nla_put_failure:
+@@ -1704,6 +1958,7 @@ static const struct nla_policy ip6_tnl_p
+ 	[IFLA_IPTUN_FLOWINFO]		= { .type = NLA_U32 },
+ 	[IFLA_IPTUN_FLAGS]		= { .type = NLA_U32 },
+ 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
++	[IFLA_IPTUN_FMRS]		= { .type = NLA_NESTED },
+ };
+ 
+ static struct rtnl_link_ops ip6_link_ops __read_mostly = {
diff --git a/target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch b/target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch
new file mode 100644
index 0000000000..0c951069c2
--- /dev/null
+++ b/target/linux/generic/patches-3.18/667-ipv6-Fixed-source-specific-default-route-handling.patch
@@ -0,0 +1,96 @@
+From e16e888b525503be05b3aea64190e8b3bdef44d0 Mon Sep 17 00:00:00 2001
+From: Markus Stenberg <markus.stenberg@iki.fi>
+Date: Tue, 5 May 2015 13:36:59 +0300
+Subject: [PATCH] ipv6: Fixed source specific default route handling.
+
+If there are only IPv6 source specific default routes present, the
+host gets -ENETUNREACH on e.g. connect() because ip6_dst_lookup_tail
+calls ip6_route_output first, and given source address any, it fails,
+and ip6_route_get_saddr is never called.
+
+The change is to use the ip6_route_get_saddr, even if the initial
+ip6_route_output fails, and then doing ip6_route_output _again_ after
+we have appropriate source address available.
+
+Note that this is '99% fix' to the problem; a correct fix would be to
+do route lookups only within addrconf.c when picking a source address,
+and never call ip6_route_output before source address has been
+populated.
+
+Signed-off-by: Markus Stenberg <markus.stenberg@iki.fi>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/ipv6/ip6_output.c | 39 +++++++++++++++++++++++++++++++--------
+ net/ipv6/route.c      |  5 +++--
+ 2 files changed, 34 insertions(+), 10 deletions(-)
+
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -903,21 +903,45 @@ static int ip6_dst_lookup_tail(struct so
+ #endif
+ 	int err;
+ 
+-	if (*dst == NULL)
+-		*dst = ip6_route_output(net, sk, fl6);
+-
+-	if ((err = (*dst)->error))
+-		goto out_err_release;
++	/* The correct way to handle this would be to do
++	 * ip6_route_get_saddr, and then ip6_route_output; however,
++	 * the route-specific preferred source forces the
++	 * ip6_route_output call _before_ ip6_route_get_saddr.
++	 *
++	 * In source specific routing (no src=any default route),
++	 * ip6_route_output will fail given src=any saddr, though, so
++	 * that's why we try it again later.
++	 */
++	if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) {
++		struct rt6_info *rt;
++		bool had_dst = *dst != NULL;
+ 
+-	if (ipv6_addr_any(&fl6->saddr)) {
+-		struct rt6_info *rt = (struct rt6_info *) *dst;
++		if (!had_dst)
++			*dst = ip6_route_output(net, sk, fl6);
++		rt = (*dst)->error ? NULL : (struct rt6_info *)*dst;
+ 		err = ip6_route_get_saddr(net, rt, &fl6->daddr,
+ 					  sk ? inet6_sk(sk)->srcprefs : 0,
+ 					  &fl6->saddr);
+ 		if (err)
+ 			goto out_err_release;
++
++		/* If we had an erroneous initial result, pretend it
++		 * never existed and let the SA-enabled version take
++		 * over.
++		 */
++		if (!had_dst && (*dst)->error) {
++			dst_release(*dst);
++			*dst = NULL;
++		}
+ 	}
+ 
++	if (!*dst)
++		*dst = ip6_route_output(net, sk, fl6);
++
++	err = (*dst)->error;
++	if (err)
++		goto out_err_release;
++
+ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ 	/*
+ 	 * Here if the dst entry we've looked up
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -2182,9 +2182,10 @@ int ip6_route_get_saddr(struct net *net,
+ 			unsigned int prefs,
+ 			struct in6_addr *saddr)
+ {
+-	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
++	struct inet6_dev *idev =
++		rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL;
+ 	int err = 0;
+-	if (rt->rt6i_prefsrc.plen)
++	if (rt && rt->rt6i_prefsrc.plen)
+ 		*saddr = rt->rt6i_prefsrc.addr;
+ 	else
+ 		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
diff --git a/target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
new file mode 100644
index 0000000000..1bf9dc99dc
--- /dev/null
+++ b/target/linux/generic/patches-3.18/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
@@ -0,0 +1,249 @@
+From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Fri, 24 May 2013 14:40:54 +0200
+Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy"
+
+RFC6204 L-14 requires rejecting traffic from invalid addresses with
+ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
+egress policy) on the LAN side, so add an appropriate rule for that.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/net/netns/ipv6.h       |  1 +
+ include/uapi/linux/fib_rules.h |  4 +++
+ include/uapi/linux/rtnetlink.h |  1 +
+ net/ipv4/fib_semantics.c       |  4 +++
+ net/ipv4/fib_trie.c            |  1 +
+ net/ipv4/ipmr.c                |  1 +
+ net/ipv6/fib6_rules.c          |  4 +++
+ net/ipv6/ip6mr.c               |  2 ++
+ net/ipv6/route.c               | 58 +++++++++++++++++++++++++++++++++++++++++-
+ 9 files changed, 75 insertions(+), 1 deletion(-)
+
+--- a/include/net/netns/ipv6.h
++++ b/include/net/netns/ipv6.h
+@@ -59,6 +59,7 @@ struct netns_ipv6 {
+ 	unsigned long		 ip6_rt_last_gc;
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	struct rt6_info         *ip6_prohibit_entry;
++	struct rt6_info		*ip6_policy_failed_entry;
+ 	struct rt6_info         *ip6_blk_hole_entry;
+ 	struct fib6_table       *fib6_local_tbl;
+ 	struct fib_rules_ops    *fib6_rules_ops;
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -64,6 +64,10 @@ enum {
+ 	FR_ACT_BLACKHOLE,	/* Drop without notification */
+ 	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
+ 	FR_ACT_PROHIBIT,	/* Drop with EACCES */
++	FR_ACT_RES9,
++	FR_ACT_RES10,
++	FR_ACT_RES11,
++	FR_ACT_POLICY_FAILED,	/* Drop with EACCES */
+ 	__FR_ACT_MAX,
+ };
+ 
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -203,6 +203,7 @@ enum {
+ 	RTN_THROW,		/* Not in this table		*/
+ 	RTN_NAT,		/* Translate this address	*/
+ 	RTN_XRESOLVE,		/* Use external resolver	*/
++	RTN_POLICY_FAILED,	/* Failed ingress/egress policy */
+ 	__RTN_MAX
+ };
+ 
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
+ 		.error	= -EINVAL,
+ 		.scope	= RT_SCOPE_NOWHERE,
+ 	},
++	[RTN_POLICY_FAILED] = {
++		.error	= -EACCES,
++		.scope	= RT_SCOPE_UNIVERSE,
++	},
+ };
+ 
+ static void rt_fibinfo_free(struct rtable __rcu **rtp)
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2236,6 +2236,7 @@ static const char *const rtn_type_names[
+ 	[RTN_THROW] = "THROW",
+ 	[RTN_NAT] = "NAT",
+ 	[RTN_XRESOLVE] = "XRESOLVE",
++	[RTN_POLICY_FAILED] = "POLICY_FAILED",
+ };
+ 
+ static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
+--- a/net/ipv4/ipmr.c
++++ b/net/ipv4/ipmr.c
+@@ -184,6 +184,7 @@ static int ipmr_rule_action(struct fib_r
+ 	case FR_ACT_UNREACHABLE:
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
++	case FR_ACT_POLICY_FAILED:
+ 		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+--- a/net/ipv6/fib6_rules.c
++++ b/net/ipv6/fib6_rules.c
+@@ -73,6 +73,10 @@ static int fib6_rule_action(struct fib_r
+ 		err = -EACCES;
+ 		rt = net->ipv6.ip6_prohibit_entry;
+ 		goto discard_pkt;
++	case FR_ACT_POLICY_FAILED:
++		err = -EACCES;
++		rt = net->ipv6.ip6_policy_failed_entry;
++		goto discard_pkt;
+ 	}
+ 
+ 	table = fib6_get_table(net, rule->table);
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -169,6 +169,8 @@ static int ip6mr_rule_action(struct fib_
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
+ 		return -EACCES;
++	case FR_ACT_POLICY_FAILED:
++		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+ 		return -EINVAL;
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -87,6 +87,8 @@ static int		ip6_pkt_discard(struct sk_bu
+ static int		ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
+ static int		ip6_pkt_prohibit(struct sk_buff *skb);
+ static int		ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
++static int		ip6_pkt_policy_failed(struct sk_buff *skb);
++static int		ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb);
+ static void		ip6_link_failure(struct sk_buff *skb);
+ static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ 					   struct sk_buff *skb, u32 mtu);
+@@ -283,6 +285,21 @@ static const struct rt6_info ip6_prohibi
+ 	.rt6i_ref	= ATOMIC_INIT(1),
+ };
+ 
++static const struct rt6_info ip6_policy_failed_entry_template = {
++	.dst = {
++		.__refcnt	= ATOMIC_INIT(1),
++		.__use		= 1,
++		.obsolete	= DST_OBSOLETE_FORCE_CHK,
++		.error		= -EACCES,
++		.input		= ip6_pkt_policy_failed,
++		.output		= ip6_pkt_policy_failed_out,
++	},
++	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
++	.rt6i_protocol	= RTPROT_KERNEL,
++	.rt6i_metric	= ~(u32) 0,
++	.rt6i_ref	= ATOMIC_INIT(1),
++};
++
+ static const struct rt6_info ip6_blk_hole_entry_template = {
+ 	.dst = {
+ 		.__refcnt	= ATOMIC_INIT(1),
+@@ -1578,6 +1595,11 @@ int ip6_route_add(struct fib6_config *cf
+ 			rt->dst.output = ip6_pkt_prohibit_out;
+ 			rt->dst.input = ip6_pkt_prohibit;
+ 			break;
++		case RTN_POLICY_FAILED:
++			rt->dst.error = -EACCES;
++			rt->dst.output = ip6_pkt_policy_failed_out;
++			rt->dst.input = ip6_pkt_policy_failed;
++			break;
+ 		case RTN_THROW:
+ 		default:
+ 			rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
+@@ -2139,6 +2161,17 @@ static int ip6_pkt_prohibit_out(struct s
+ 	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
+ }
+ 
++static int ip6_pkt_policy_failed(struct sk_buff *skb)
++{
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
++}
++
++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb)
++{
++	skb->dev = skb_dst(skb)->dev;
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
++}
++
+ /*
+  *	Allocate a dst for local (unicast / anycast) address.
+  */
+@@ -2363,7 +2396,8 @@ static int rtm_to_fib6_config(struct sk_
+ 	if (rtm->rtm_type == RTN_UNREACHABLE ||
+ 	    rtm->rtm_type == RTN_BLACKHOLE ||
+ 	    rtm->rtm_type == RTN_PROHIBIT ||
+-	    rtm->rtm_type == RTN_THROW)
++	    rtm->rtm_type == RTN_THROW ||
++	    rtm->rtm_type == RTN_POLICY_FAILED)
+ 		cfg->fc_flags |= RTF_REJECT;
+ 
+ 	if (rtm->rtm_type == RTN_LOCAL)
+@@ -2565,6 +2599,9 @@ static int rt6_fill_node(struct net *net
+ 		case -EACCES:
+ 			rtm->rtm_type = RTN_PROHIBIT;
+ 			break;
++		case -EPERM:
++			rtm->rtm_type = RTN_POLICY_FAILED;
++			break;
+ 		case -EAGAIN:
+ 			rtm->rtm_type = RTN_THROW;
+ 			break;
+@@ -2818,6 +2855,8 @@ static int ip6_route_dev_notify(struct n
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
+ 		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
++		net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
++		net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
+ 		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
+ 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
+ #endif
+@@ -3034,6 +3073,17 @@ static int __net_init ip6_route_net_init
+ 	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+ 	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
+ 			 ip6_template_metrics, true);
++
++	net->ipv6.ip6_policy_failed_entry =
++		kmemdup(&ip6_policy_failed_entry_template,
++			sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
++	if (!net->ipv6.ip6_policy_failed_entry)
++		goto out_ip6_blk_hole_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.path =
++		(struct dst_entry *)net->ipv6.ip6_policy_failed_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
++	dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
++			 ip6_template_metrics, true);
+ #endif
+ 
+ 	net->ipv6.sysctl.flush_delay = 0;
+@@ -3052,6 +3102,8 @@ out:
+ 	return ret;
+ 
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
++out_ip6_blk_hole_entry:
++	kfree(net->ipv6.ip6_blk_hole_entry);
+ out_ip6_prohibit_entry:
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ out_ip6_null_entry:
+@@ -3069,6 +3121,7 @@ static void __net_exit ip6_route_net_exi
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ 	kfree(net->ipv6.ip6_blk_hole_entry);
++	kfree(net->ipv6.ip6_policy_failed_entry);
+ #endif
+ 	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
+ }
+@@ -3165,6 +3218,9 @@ int __init ip6_route_init(void)
+ 	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ 	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+ 	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
++	init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
++	init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
++		in6_dev_get(init_net.loopback_dev);
+   #endif
+ 	ret = fib6_init();
+ 	if (ret)
diff --git a/target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
new file mode 100644
index 0000000000..25a8639397
--- /dev/null
+++ b/target/linux/generic/patches-3.18/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
@@ -0,0 +1,53 @@
+From 7749b481ce5d7e232b1f7da5e6b2c44816f51681 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 19 Jan 2014 20:45:51 +0100
+Subject: [PATCH 2/2] net: provide defines for _POLICY_FAILED until all code is
+ updated
+
+Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination
+unreachable, conflicting with our name.
+
+Add appropriate defines to allow our code to build with the new
+name until we have updated our local patches for older kernels
+and userspace packages.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/fib_rules.h | 2 ++
+ include/uapi/linux/icmpv6.h    | 2 ++
+ include/uapi/linux/rtnetlink.h | 2 ++
+ 3 files changed, 6 insertions(+)
+
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -71,6 +71,8 @@ enum {
+ 	__FR_ACT_MAX,
+ };
+ 
++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED
++
+ #define FR_ACT_MAX (__FR_ACT_MAX - 1)
+ 
+ #endif
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -118,6 +118,8 @@ struct icmp6hdr {
+ #define ICMPV6_POLICY_FAIL		5
+ #define ICMPV6_REJECT_ROUTE		6
+ 
++#define ICMPV6_FAILED_POLICY		ICMPV6_POLICY_FAIL
++
+ /*
+  *	Codes for Time Exceeded
+  */
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -207,6 +207,8 @@ enum {
+ 	__RTN_MAX
+ };
+ 
++#define RTN_FAILED_POLICY RTN_POLICY_FAILED
++
+ #define RTN_MAX (__RTN_MAX - 1)
+ 
+ 
diff --git a/target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
new file mode 100644
index 0000000000..714097bca0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
@@ -0,0 +1,160 @@
+Subject: NET: skip GRO for foreign MAC addresses
+
+For network drivers using napi_gro_receive, packets are run through GRO,
+even when the destination MAC address does not match, and they're supposed
+to be delivered to another host behind a different bridge port.
+
+This can be very expensive, because for drivers without TSO or scatter-
+gather, this can only be undone by copying the skb and checksumming it
+again.
+
+To be able to track foreign MAC addresses in an inexpensive way, create
+a mask of changed bits in MAC addresses of upper devices. This allows
+handling VLANs and bridge devices with different addresses (as long as
+they are not too different).
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -4002,6 +4002,9 @@ static enum gro_result dev_gro_receive(s
+ 	enum gro_result ret;
+ 	int grow;
+ 
++	if (skb->gro_skip)
++		goto normal;
++
+ 	if (!(skb->dev->features & NETIF_F_GRO))
+ 		goto normal;
+ 
+@@ -5067,6 +5070,48 @@ static void __netdev_adjacent_dev_unlink
+ 					   &upper_dev->adj_list.lower);
+ }
+ 
++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
++			       struct net_device *dev)
++{
++	int i;
++
++	for (i = 0; i < dev->addr_len; i++)
++		mask[i] |= addr[i] ^ dev->dev_addr[i];
++}
++
++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
++				struct net_device *lower)
++{
++	struct net_device *cur;
++	struct list_head *iter;
++
++	netdev_for_each_upper_dev_rcu(dev, cur, iter) {
++		__netdev_addr_mask(mask, cur->dev_addr, lower);
++		__netdev_upper_mask(mask, cur, lower);
++	}
++}
++
++static void __netdev_update_addr_mask(struct net_device *dev)
++{
++	unsigned char mask[MAX_ADDR_LEN];
++	struct net_device *cur;
++	struct list_head *iter;
++
++	memset(mask, 0, sizeof(mask));
++	__netdev_upper_mask(mask, dev, dev);
++	memcpy(dev->local_addr_mask, mask, dev->addr_len);
++
++	netdev_for_each_lower_dev(dev, cur, iter)
++		__netdev_update_addr_mask(cur);
++}
++
++static void netdev_update_addr_mask(struct net_device *dev)
++{
++	rcu_read_lock();
++	__netdev_update_addr_mask(dev);
++	rcu_read_unlock();
++}
++
+ static int __netdev_upper_dev_link(struct net_device *dev,
+ 				   struct net_device *upper_dev, bool master,
+ 				   void *private)
+@@ -5127,6 +5172,7 @@ static int __netdev_upper_dev_link(struc
+ 			goto rollback_lower_mesh;
+ 	}
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
+ 	return 0;
+ 
+@@ -5244,6 +5290,7 @@ void netdev_upper_dev_unlink(struct net_
+ 	list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
+ 		__netdev_adjacent_dev_unlink(dev, i->dev);
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
+ }
+ EXPORT_SYMBOL(netdev_upper_dev_unlink);
+@@ -5763,6 +5810,7 @@ int dev_set_mac_address(struct net_devic
+ 	if (err)
+ 		return err;
+ 	dev->addr_assign_type = NET_ADDR_SET;
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ 	add_device_randomness(dev->dev_addr, dev->addr_len);
+ 	return 0;
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1556,6 +1556,8 @@ struct net_device {
+ 	struct netdev_hw_addr_list	mc;
+ 	struct netdev_hw_addr_list	dev_addrs;
+ 
++	unsigned char		local_addr_mask[MAX_ADDR_LEN];
++
+ #ifdef CONFIG_SYSFS
+ 	struct kset		*queues_kset;
+ #endif
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -597,7 +597,8 @@ struct sk_buff {
+ #endif
+ 	__u8			ipvs_property:1;
+ 	__u8			inner_protocol_type:1;
+-	/* 4 or 6 bit hole */
++	__u8			gro_skip:1;
++	/* 3 or 5 bit hole */
+ 
+ #ifdef CONFIG_NET_SCHED
+ 	__u16			tc_index;	/* traffic control index */
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -172,6 +172,18 @@ u32 eth_get_headlen(void *data, unsigned
+ }
+ EXPORT_SYMBOL(eth_get_headlen);
+ 
++static inline bool
++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
++{
++	const u16 *a1 = addr1;
++	const u16 *a2 = addr2;
++	const u16 *m = mask;
++
++	return (((a1[0] ^ a2[0]) & ~m[0]) |
++		((a1[1] ^ a2[1]) & ~m[1]) |
++		((a1[2] ^ a2[2]) & ~m[2]));
++}
++
+ /**
+  * eth_type_trans - determine the packet's protocol ID.
+  * @skb: received socket data
+@@ -199,8 +211,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 			skb->pkt_type = PACKET_MULTICAST;
+ 	}
+ 	else if (unlikely(!ether_addr_equal_64bits(eth->h_dest,
+-						   dev->dev_addr)))
++						   dev->dev_addr))) {
+ 		skb->pkt_type = PACKET_OTHERHOST;
++		if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
++					 dev->local_addr_mask))
++			skb->gro_skip = 1;
++	}
+ 
+ 	/*
+ 	 * Some variants of DSA tagging don't have an ethertype field
diff --git a/target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch b/target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch
new file mode 100644
index 0000000000..a836eed867
--- /dev/null
+++ b/target/linux/generic/patches-3.18/681-NET-add-of_get_mac_address_mtd.patch
@@ -0,0 +1,88 @@
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:40:01 +0100
+Subject: NET: add of_get_mac_address_mtd()
+
+Many embedded devices have information such as mac addresses stored inside mtd
+devices. This patch allows us to add a property inside a node describing a
+network interface. The new property points at a mtd partition with an offset
+where the mac address can be found.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/of/of_net.c    |   37 +++++++++++++++++++++++++++++++++++++
+ include/linux/of_net.h |    1 +
+ 2 files changed, 38 insertions(+)
+
+--- a/drivers/of/of_net.c
++++ b/drivers/of/of_net.c
+@@ -10,6 +10,7 @@
+ #include <linux/of_net.h>
+ #include <linux/phy.h>
+ #include <linux/export.h>
++#include <linux/mtd/mtd.h>
+ 
+ /**
+  * of_get_phy_mode - Get phy mode for given device_node
+@@ -75,3 +76,45 @@ const void *of_get_mac_address(struct de
+ 	return NULL;
+ }
+ EXPORT_SYMBOL(of_get_mac_address);
++
++#ifdef CONFIG_MTD
++int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac)
++{
++	struct device_node *mtd_np = NULL;
++	size_t retlen;
++	int size, ret;
++	struct mtd_info *mtd;
++	const char *part;
++	const __be32 *list;
++	phandle phandle;
++	u32 mac_inc = 0;
++
++	list = of_get_property(np, "mtd-mac-address", &size);
++	if (!list || (size != (2 * sizeof(*list))))
++		return -ENOENT;
++
++	phandle = be32_to_cpup(list++);
++	if (phandle)
++		mtd_np = of_find_node_by_phandle(phandle);
++
++	if (!mtd_np)
++		return -ENOENT;
++
++	part = of_get_property(mtd_np, "label", NULL);
++	if (!part)
++		part = mtd_np->name;
++
++	mtd = get_mtd_device_nm(part);
++	if (IS_ERR(mtd))
++		return PTR_ERR(mtd);
++
++	ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
++	put_mtd_device(mtd);
++
++	if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
++		mac[5] += mac_inc;
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(of_get_mac_address_mtd);
++#endif
+--- a/include/linux/of_net.h
++++ b/include/linux/of_net.h
+@@ -11,6 +11,14 @@
+ #include <linux/of.h>
+ extern int of_get_phy_mode(struct device_node *np);
+ extern const void *of_get_mac_address(struct device_node *np);
++#ifdef CONFIG_MTD
++extern int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac);
++#else
++static inline int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac)
++{
++	return -ENOENT;
++}
++#endif
+ #else
+ static inline int of_get_phy_mode(struct device_node *np)
+ {
diff --git a/target/linux/generic/patches-3.18/700-swconfig.patch b/target/linux/generic/patches-3.18/700-swconfig.patch
new file mode 100644
index 0000000000..7cf525a509
--- /dev/null
+++ b/target/linux/generic/patches-3.18/700-swconfig.patch
@@ -0,0 +1,39 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,16 @@ menuconfig PHYLIB
+ 
+ if PHYLIB
+ 
++config SWCONFIG
++	tristate "Switch configuration API"
++	---help---
++	  Switch configuration API using netlink. This allows
++	  you to configure the VLAN features of certain switches.
++
++config SWCONFIG_LEDS
++	bool "Switch LED trigger support"
++	depends on (SWCONFIG && LEDS_TRIGGERS)
++
+ comment "MII PHY device drivers"
+ 
+ config AT803X_PHY
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -3,6 +3,7 @@
+ libphy-objs			:= phy.o phy_device.o mdio_bus.o
+ 
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
++obj-$(CONFIG_SWCONFIG)		+= swconfig.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+ obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
+ obj-$(CONFIG_CICADA_PHY)	+= cicada.o
+--- a/include/uapi/linux/Kbuild
++++ b/include/uapi/linux/Kbuild
+@@ -374,6 +374,7 @@ header-y += stddef.h
+ header-y += string.h
+ header-y += suspend_ioctls.h
+ header-y += swab.h
++header-y += switch.h
+ header-y += synclink.h
+ header-y += sysctl.h
+ header-y += sysinfo.h
diff --git a/target/linux/generic/patches-3.18/701-phy_extension.patch b/target/linux/generic/patches-3.18/701-phy_extension.patch
new file mode 100644
index 0000000000..5c63dbec62
--- /dev/null
+++ b/target/linux/generic/patches-3.18/701-phy_extension.patch
@@ -0,0 +1,63 @@
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -357,6 +357,50 @@ int phy_ethtool_gset(struct phy_device *
+ }
+ EXPORT_SYMBOL(phy_ethtool_gset);
+ 
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
++{
++	u32 cmd;
++	int tmp;
++	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++	struct ethtool_value edata = { ETHTOOL_GLINK };
++
++	if (get_user(cmd, (u32 *) useraddr))
++		return -EFAULT;
++
++	switch (cmd) {
++	case ETHTOOL_GSET:
++		phy_ethtool_gset(phydev, &ecmd);
++		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++			return -EFAULT;
++		return 0;
++
++	case ETHTOOL_SSET:
++		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++			return -EFAULT;
++		return phy_ethtool_sset(phydev, &ecmd);
++
++	case ETHTOOL_NWAY_RST:
++		/* if autoneg is off, it's an error */
++		tmp = phy_read(phydev, MII_BMCR);
++		if (tmp & BMCR_ANENABLE) {
++			tmp |= (BMCR_ANRESTART);
++			phy_write(phydev, MII_BMCR, tmp);
++			return 0;
++		}
++		return -EINVAL;
++
++	case ETHTOOL_GLINK:
++		edata.data = (phy_read(phydev,
++				MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
++		if (copy_to_user(useraddr, &edata, sizeof(edata)))
++			return -EFAULT;
++		return 0;
++	}
++
++	return -EOPNOTSUPP;
++}
++EXPORT_SYMBOL(phy_ethtool_ioctl);
++
+ /**
+  * phy_mii_ioctl - generic PHY MII ioctl interface
+  * @phydev: the phy_device struct
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -748,6 +748,7 @@ void phy_start_machine(struct phy_device
+ void phy_stop_machine(struct phy_device *phydev);
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
+ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
+ int phy_start_interrupts(struct phy_device *phydev);
+ void phy_print_status(struct phy_device *phydev);
diff --git a/target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch b/target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch
new file mode 100644
index 0000000000..d20fc04cb0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/702-phy_add_aneg_done_function.patch
@@ -0,0 +1,27 @@
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -484,6 +484,12 @@ struct phy_driver {
+ 	/* Determines the negotiated speed and duplex */
+ 	int (*read_status)(struct phy_device *phydev);
+ 
++	/* 
++	 * Update the value in phydev->link to reflect the 
++	 * current link value
++	 */
++	int (*update_link)(struct phy_device *phydev);
++
+ 	/* Clears any pending interrupts */
+ 	int (*ack_interrupt)(struct phy_device *phydev);
+ 
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -915,6 +915,9 @@ int genphy_update_link(struct phy_device
+ {
+ 	int status;
+ 
++	if (phydev->drv->update_link)
++		return phydev->drv->update_link(phydev);
++
+ 	/* Do a fake read */
+ 	status = phy_read(phydev, MII_BMSR);
+ 	if (status < 0)
diff --git a/target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch
new file mode 100644
index 0000000000..061e40fb49
--- /dev/null
+++ b/target/linux/generic/patches-3.18/703-phy-add-detach-callback-to-struct-phy_driver.patch
@@ -0,0 +1,27 @@
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -674,6 +674,9 @@ void phy_detach(struct phy_device *phyde
+ {
+ 	int i;
+ 
++	if (phydev->drv && phydev->drv->detach)
++		phydev->drv->detach(phydev);
++
+ 	if (phydev->bus->dev.driver)
+ 		module_put(phydev->bus->dev.driver->owner);
+ 
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -502,6 +502,12 @@ struct phy_driver {
+ 	 */
+ 	int (*did_interrupt)(struct phy_device *phydev);
+ 
++	/*
++	 * Called before an ethernet device is detached
++	 * from the PHY.
++	 */
++	void (*detach)(struct phy_device *phydev);
++
+ 	/* Clears up any memory if needed */
+ 	void (*remove)(struct phy_device *phydev);
+ 
diff --git a/target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch b/target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch
new file mode 100644
index 0000000000..0350f9efe4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/704-phy-no-genphy-soft-reset.patch
@@ -0,0 +1,29 @@
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1133,7 +1133,7 @@ int genphy_config_init(struct phy_device
+ 	return 0;
+ }
+ 
+-static int gen10g_soft_reset(struct phy_device *phydev)
++static int no_soft_reset(struct phy_device *phydev)
+ {
+ 	/* Do nothing for now */
+ 	return 0;
+@@ -1347,7 +1347,7 @@ static struct phy_driver genphy_driver[]
+ 	.phy_id		= 0xffffffff,
+ 	.phy_id_mask	= 0xffffffff,
+ 	.name		= "Generic PHY",
+-	.soft_reset	= genphy_soft_reset,
++	.soft_reset	= no_soft_reset,
+ 	.config_init	= genphy_config_init,
+ 	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
+ 			  SUPPORTED_AUI | SUPPORTED_FIBRE |
+@@ -1362,7 +1362,7 @@ static struct phy_driver genphy_driver[]
+ 	.phy_id         = 0xffffffff,
+ 	.phy_id_mask    = 0xffffffff,
+ 	.name           = "Generic 10G PHY",
+-	.soft_reset	= gen10g_soft_reset,
++	.soft_reset	= no_soft_reset,
+ 	.config_init    = gen10g_config_init,
+ 	.features       = 0,
+ 	.config_aneg    = gen10g_config_aneg,
diff --git a/target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch b/target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch
new file mode 100644
index 0000000000..cc3cb2445d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/710-phy-add-mdio_register_board_info.patch
@@ -0,0 +1,192 @@
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -38,6 +38,8 @@
+ 
+ #include <asm/irq.h>
+ 
++#include "mdio-boardinfo.h"
++
+ /**
+  * mdiobus_alloc_size - allocate a mii_bus structure
+  * @size: extra amount of memory to allocate for private storage.
+@@ -335,9 +337,21 @@ void mdiobus_free(struct mii_bus *bus)
+ }
+ EXPORT_SYMBOL(mdiobus_free);
+ 
++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus,
++						struct phy_device *phydev,
++						struct mdio_board_info *bi)
++{
++	if (strcmp(bus->id, bi->bus_id) ||
++	    bi->phy_addr != phydev->addr)
++	    return;
++
++	phydev->dev.platform_data = (void *) bi->platform_data;
++}
++
+ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+ {
+ 	struct phy_device *phydev;
++	struct mdio_board_entry *be;
+ 	int err;
+ 
+ 	phydev = get_phy_device(bus, addr, false);
+@@ -350,6 +364,12 @@ struct phy_device *mdiobus_scan(struct m
+ 	 */
+ 	of_mdiobus_link_phydev(bus, phydev);
+ 
++	mutex_lock(&__mdio_board_lock);
++	list_for_each_entry(be, &__mdio_board_list, list)
++		mdiobus_setup_phydev_from_boardinfo(bus, phydev,
++						    &be->board_info);
++	mutex_unlock(&__mdio_board_lock);
++
+ 	err = phy_device_register(phydev);
+ 	if (err) {
+ 		phy_device_free(phydev);
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -785,4 +785,22 @@ int __init mdio_bus_init(void);
+ void mdio_bus_exit(void);
+ 
+ extern struct bus_type mdio_bus_type;
++
++struct mdio_board_info {
++	const char	*bus_id;
++	int		phy_addr;
++
++	const void	*platform_data;
++};
++
++#ifdef CONFIG_MDIO_BOARDINFO
++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n);
++#else
++static inline int
++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n)
++{
++	return 0;
++}
++#endif
++
+ #endif /* __PHY_H */
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,10 @@ menuconfig PHYLIB
+ 
+ if PHYLIB
+ 
++config MDIO_BOARDINFO
++	bool
++	default y
++
+ config SWCONFIG
+ 	tristate "Switch configuration API"
+ 	---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -2,6 +2,8 @@
+ 
+ libphy-objs			:= phy.o phy_device.o mdio_bus.o
+ 
++obj-$(CONFIG_MDIO_BOARDINFO)	+= mdio-boardinfo.o
++
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
+ obj-$(CONFIG_SWCONFIG)		+= swconfig.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.c
+@@ -0,0 +1,58 @@
++/*
++ * mdio-boardinfo.c - collect pre-declarations of PHY devices
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/phy.h>
++#include <linux/slab.h>
++#include <linux/export.h>
++#include <linux/mutex.h>
++#include <linux/phy.h>
++
++#include "mdio-boardinfo.h"
++
++/*
++ * These symbols are exported ONLY FOR the mdio_bus component.
++ * No other users will be supported.
++ */
++
++LIST_HEAD(__mdio_board_list);
++EXPORT_SYMBOL_GPL(__mdio_board_list);
++
++DEFINE_MUTEX(__mdio_board_lock);
++EXPORT_SYMBOL_GPL(__mdio_board_lock);
++
++/**
++ * mdio_register_board_info - register PHY devices for a given board
++ * @info: array of chip descriptors
++ * @n: how many descriptors are provided
++ * Context: can sleep
++ *
++ * The board info passed can safely be __initdata ... but be careful of
++ * any embedded pointers (platform_data, etc), they're copied as-is.
++ */
++int __init
++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n)
++{
++	struct mdio_board_entry *be;
++	int i;
++
++	be = kzalloc(n * sizeof(*be), GFP_KERNEL);
++	if (!be)
++		return -ENOMEM;
++
++	for (i = 0; i < n; i++, be++, info++) {
++		memcpy(&be->board_info, info, sizeof(*info));
++		mutex_lock(&__mdio_board_lock);
++		list_add_tail(&be->list, &__mdio_board_list);
++		mutex_unlock(&__mdio_board_lock);
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.h
+@@ -0,0 +1,22 @@
++/*
++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/mutex.h>
++
++struct mdio_board_entry {
++	struct list_head	list;
++	struct mdio_board_info	board_info;
++};
++
++/* __mdio_board_lock protects __mdio_board_list
++ * only mdio_bus components are allowed to use these symbols.
++ */
++extern struct mutex __mdio_board_lock;
++extern struct list_head __mdio_board_list;
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -15,7 +15,7 @@ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_MDIO) += mdio.o
+ obj-$(CONFIG_NET) += Space.o loopback.o
+ obj-$(CONFIG_NETCONSOLE) += netconsole.o
+-obj-$(CONFIG_PHYLIB) += phy/
++obj-y += phy/
+ obj-$(CONFIG_RIONET) += rionet.o
+ obj-$(CONFIG_NET_TEAM) += team/
+ obj-$(CONFIG_TUN) += tun.o
diff --git a/target/linux/generic/patches-3.18/720-phy_adm6996.patch b/target/linux/generic/patches-3.18/720-phy_adm6996.patch
new file mode 100644
index 0000000000..b0b8db4e5d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/720-phy_adm6996.patch
@@ -0,0 +1,26 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -132,6 +132,13 @@ config MICREL_PHY
+ 	---help---
+ 	  Supports the KSZ9021, VSC8201, KS8001 PHYs.
+ 
++config ADM6996_PHY
++	tristate "Driver for ADM6996 switches"
++	select SWCONFIG
++	---help---
++	  Currently supports the ADM6996FC and ADM6996M switches.
++	  Support for FC is very limited.
++
+ config FIXED_PHY
+ 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB=y
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
+ obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
+ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
++obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
diff --git a/target/linux/generic/patches-3.18/721-phy_packets.patch b/target/linux/generic/patches-3.18/721-phy_packets.patch
new file mode 100644
index 0000000000..99811c6242
--- /dev/null
+++ b/target/linux/generic/patches-3.18/721-phy_packets.patch
@@ -0,0 +1,161 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1228,6 +1228,7 @@ enum netdev_priv_flags {
+ 	IFF_LIVE_ADDR_CHANGE		= 1<<20,
+ 	IFF_MACVLAN			= 1<<21,
+ 	IFF_XMIT_DST_RELEASE_PERM	= 1<<22,
++	IFF_NO_IP_ALIGN			= 1<<23,
+ };
+ 
+ #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
+@@ -1253,6 +1254,7 @@ enum netdev_priv_flags {
+ #define IFF_LIVE_ADDR_CHANGE		IFF_LIVE_ADDR_CHANGE
+ #define IFF_MACVLAN			IFF_MACVLAN
+ #define IFF_XMIT_DST_RELEASE_PERM	IFF_XMIT_DST_RELEASE_PERM
++#define IFF_NO_IP_ALIGN		IFF_NO_IP_ALIGN
+ 
+ /**
+  *	struct net_device - The DEVICE structure.
+@@ -1523,6 +1525,11 @@ struct net_device {
+ 	const struct ethtool_ops *ethtool_ops;
+ 	const struct forwarding_accel_ops *fwd_ops;
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
++	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
++#endif
++
+ 	const struct header_ops *header_ops;
+ 
+ 	unsigned int		flags;
+@@ -1587,6 +1594,10 @@ struct net_device {
+ 	void			*ax25_ptr;
+ 	struct wireless_dev	*ieee80211_ptr;
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void			*phy_ptr; /* PHY device specific data */
++#endif
++
+ /*
+  * Cache lines mostly used on receive path (including eth_type_trans())
+  */
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2054,6 +2054,10 @@ static inline int pskb_trim(struct sk_bu
+ 	return (len < skb->len) ? __pskb_trim(skb, len) : 0;
+ }
+ 
++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp);
++
++
+ /**
+  *	pskb_trim_unique - remove end from a paged unique (not cloned) buffer
+  *	@skb: buffer to alter
+@@ -2180,16 +2184,6 @@ static inline struct sk_buff *dev_alloc_
+ }
+ 
+ 
+-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+-		unsigned int length, gfp_t gfp)
+-{
+-	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
+-
+-	if (NET_IP_ALIGN && skb)
+-		skb_reserve(skb, NET_IP_ALIGN);
+-	return skb;
+-}
+-
+ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
+ 		unsigned int length)
+ {
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -25,6 +25,12 @@ menuconfig NET
+ 
+ if NET
+ 
++config ETHERNET_PACKET_MANGLE
++	bool
++	help
++	  This option can be selected by phy drivers that need to mangle
++	  packets going in or out of an ethernet device.
++
+ config WANT_COMPAT_NETLINK_MESSAGES
+ 	bool
+ 	help
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2623,10 +2623,20 @@ static int xmit_one(struct sk_buff *skb,
+ 	if (!list_empty(&ptype_all))
+ 		dev_queue_xmit_nit(skb, dev);
+ 
+-	len = skb->len;
+-	trace_net_dev_start_xmit(skb, dev);
+-	rc = netdev_start_xmit(skb, dev, txq, more);
+-	trace_net_dev_xmit(skb, rc, dev, len);
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (!dev->eth_mangle_tx ||
++	    (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
++#else
++	if (1)
++#endif
++	{
++		len = skb->len;
++		trace_net_dev_start_xmit(skb, dev);
++		rc = netdev_start_xmit(skb, dev, txq, more);
++		trace_net_dev_xmit(skb, rc, dev, len);
++	} else {
++		rc = NETDEV_TX_OK;
++	}
+ 
+ 	return rc;
+ }
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -63,6 +63,7 @@
+ #include <linux/errqueue.h>
+ #include <linux/prefetch.h>
+ #include <linux/if_vlan.h>
++#include <linux/if.h>
+ 
+ #include <net/protocol.h>
+ #include <net/dst.h>
+@@ -469,6 +470,22 @@ struct sk_buff *__netdev_alloc_skb(struc
+ }
+ EXPORT_SYMBOL(__netdev_alloc_skb);
+ 
++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp)
++{
++	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
++		return skb;
++#endif
++
++	if (NET_IP_ALIGN && skb)
++		skb_reserve(skb, NET_IP_ALIGN);
++	return skb;
++}
++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
++
+ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+ 		     int size, unsigned int truesize)
+ {
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -200,6 +200,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 	const struct ethhdr *eth;
+ 
+ 	skb->dev = dev;
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev->eth_mangle_rx)
++		dev->eth_mangle_rx(dev, skb);
++#endif
++
+ 	skb_reset_mac_header(skb);
+ 	skb_pull_inline(skb, ETH_HLEN);
+ 	eth = eth_hdr(skb);
diff --git a/target/linux/generic/patches-3.18/722-phy_mvswitch.patch b/target/linux/generic/patches-3.18/722-phy_mvswitch.patch
new file mode 100644
index 0000000000..f577a9f684
--- /dev/null
+++ b/target/linux/generic/patches-3.18/722-phy_mvswitch.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -139,6 +139,10 @@ config ADM6996_PHY
+ 	  Currently supports the ADM6996FC and ADM6996M switches.
+ 	  Support for FC is very limited.
+ 
++config MVSWITCH_PHY
++	tristate "Driver for Marvell 88E6060 switches"
++	select ETHERNET_PACKET_MANGLE
++
+ config FIXED_PHY
+ 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB=y
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
+ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
++obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
diff --git a/target/linux/generic/patches-3.18/723-phy_ip175c.patch b/target/linux/generic/patches-3.18/723-phy_ip175c.patch
new file mode 100644
index 0000000000..c7c4f99eec
--- /dev/null
+++ b/target/linux/generic/patches-3.18/723-phy_ip175c.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -143,6 +143,10 @@ config MVSWITCH_PHY
+ 	tristate "Driver for Marvell 88E6060 switches"
+ 	select ETHERNET_PACKET_MANGLE
+ 
++config IP17XX_PHY
++	tristate "Driver for IC+ IP17xx switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB=y
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
diff --git a/target/linux/generic/patches-3.18/724-phy_ar8216.patch b/target/linux/generic/patches-3.18/724-phy_ar8216.patch
new file mode 100644
index 0000000000..acb2df8f83
--- /dev/null
+++ b/target/linux/generic/patches-3.18/724-phy_ar8216.patch
@@ -0,0 +1,24 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -147,6 +147,11 @@ config IP17XX_PHY
+ 	tristate "Driver for IC+ IP17xx switches"
+ 	select SWCONFIG
+ 
++config AR8216_PHY
++	tristate "Driver for Atheros AR8216 switches"
++	select ETHERNET_PACKET_MANGLE
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB=y
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
++obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-3.18/725-phy_rtl8306.patch b/target/linux/generic/patches-3.18/725-phy_rtl8306.patch
new file mode 100644
index 0000000000..78ac6ce98a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/725-phy_rtl8306.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -152,6 +152,10 @@ config AR8216_PHY
+ 	select ETHERNET_PACKET_MANGLE
+ 	select SWCONFIG
+ 
++config RTL8306_PHY
++	tristate "Driver for Realtek RTL8306S switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB=y
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
++obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-3.18/726-phy_rtl8366.patch b/target/linux/generic/patches-3.18/726-phy_rtl8366.patch
new file mode 100644
index 0000000000..4a4a4acee0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/726-phy_rtl8366.patch
@@ -0,0 +1,45 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -250,6 +250,30 @@ config MDIO_BCM_UNIMAC
+ 	  controllers as well as some Broadcom Ethernet switches such as the
+ 	  Starfighter 2 switches.
+ 
++config RTL8366_SMI
++	tristate "Driver for the RTL8366 SMI interface"
++	depends on GPIOLIB
++	---help---
++	  This module implements the SMI interface protocol which is used
++	  by some RTL8366 ethernet switch devices via the generic GPIO API.
++
++if RTL8366_SMI
++
++config RTL8366_SMI_DEBUG_FS
++	bool "RTL8366 SMI interface debugfs support"
++        depends on DEBUG_FS
++        default n
++
++config RTL8366S_PHY
++	tristate "Driver for the Realtek RTL8366S switch"
++	select SWCONFIG
++
++config RTL8366RB_PHY
++	tristate "Driver for the Realtek RTL8366RB switch"
++	select SWCONFIG
++
++endif # RTL8366_SMI
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -24,6 +24,9 @@ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
+ obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
++obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
++obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
++obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-3.18/727-phy-rtl8367.patch b/target/linux/generic/patches-3.18/727-phy-rtl8367.patch
new file mode 100644
index 0000000000..8481b589d9
--- /dev/null
+++ b/target/linux/generic/patches-3.18/727-phy-rtl8367.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -272,6 +272,10 @@ config RTL8366RB_PHY
+ 	tristate "Driver for the Realtek RTL8366RB switch"
+ 	select SWCONFIG
+ 
++config RTL8367_PHY
++	tristate "Driver for the Realtek RTL8367R/M switches"
++	select SWCONFIG
++
+ endif # RTL8366_SMI
+ 
+ endif # PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
+ obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
+ obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
+ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
++obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-3.18/728-phy-rtl8367b.patch b/target/linux/generic/patches-3.18/728-phy-rtl8367b.patch
new file mode 100644
index 0000000000..958ff58907
--- /dev/null
+++ b/target/linux/generic/patches-3.18/728-phy-rtl8367b.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -276,6 +276,10 @@ config RTL8367_PHY
+ 	tristate "Driver for the Realtek RTL8367R/M switches"
+ 	select SWCONFIG
+ 
++config RTL8367B_PHY
++	tristate "Driver fot the Realtek RTL8367R-VB switch"
++	select SWCONFIG
++
+ endif # RTL8366_SMI
+ 
+ endif # PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi
+ obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
+ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
+ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
++obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-3.18/729-phy-tantos.patch b/target/linux/generic/patches-3.18/729-phy-tantos.patch
new file mode 100644
index 0000000000..019f919492
--- /dev/null
+++ b/target/linux/generic/patches-3.18/729-phy-tantos.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -287,3 +287,8 @@ endif # PHYLIB
+ config MICREL_KS8995MA
+ 	tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch"
+ 	depends on SPI
++
++config PSB6970_PHY
++	tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
++	select SWCONFIG
++	select ETHERNET_PACKET_MANGLE
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb
+ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
++obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
diff --git a/target/linux/generic/patches-3.18/730-phy_b53.patch b/target/linux/generic/patches-3.18/730-phy_b53.patch
new file mode 100644
index 0000000000..03fc369c9d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/730-phy_b53.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -282,6 +282,8 @@ config RTL8367B_PHY
+ 
+ endif # RTL8366_SMI
+ 
++source "drivers/net/phy/b53/Kconfig"
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
++obj-$(CONFIG_SWCONFIG_B53)	+= b53/
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
diff --git a/target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch b/target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch
new file mode 100644
index 0000000000..c753967572
--- /dev/null
+++ b/target/linux/generic/patches-3.18/732-phy-ar8216-led-support.patch
@@ -0,0 +1,13 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -152,6 +152,10 @@ config AR8216_PHY
+ 	select ETHERNET_PACKET_MANGLE
+ 	select SWCONFIG
+ 
++config AR8216_PHY_LEDS
++	bool "Atheros AR8216 switch LED support"
++	depends on (AR8216_PHY && LEDS_CLASS)
++
+ config RTL8306_PHY
+ 	tristate "Driver for Realtek RTL8306S switches"
+ 	select SWCONFIG
diff --git a/target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch b/target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch
new file mode 100644
index 0000000000..041d168b65
--- /dev/null
+++ b/target/linux/generic/patches-3.18/733-phy_mvsw61xx.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -143,6 +143,10 @@ config MVSWITCH_PHY
+ 	tristate "Driver for Marvell 88E6060 switches"
+ 	select ETHERNET_PACKET_MANGLE
+ 
++config MVSW61XX_PHY
++	tristate "Driver for Marvell 88E6171/6172 switches"
++	select SWCONFIG
++
+ config IP17XX_PHY
+ 	tristate "Driver for IC+ IP17xx switches"
+ 	select SWCONFIG
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_MVSW61XX_PHY)	+= mvsw61xx.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
diff --git a/target/linux/generic/patches-3.18/734-net-phy-at803x-allow-to-configure-via-pdata.patch b/target/linux/generic/patches-3.18/734-net-phy-at803x-allow-to-configure-via-pdata.patch
new file mode 100644
index 0000000000..0d021ac7bd
--- /dev/null
+++ b/target/linux/generic/patches-3.18/734-net-phy-at803x-allow-to-configure-via-pdata.patch
@@ -0,0 +1,180 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -12,12 +12,14 @@
+  */
+ 
+ #include <linux/phy.h>
++#include <linux/mdio.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/of_gpio.h>
+ #include <linux/gpio/consumer.h>
++#include <linux/platform_data/phy-at803x.h>
+ 
+ #define AT803X_INTR_ENABLE			0x12
+ #define AT803X_INTR_STATUS			0x13
+@@ -34,8 +36,16 @@
+ #define AT803X_INER				0x0012
+ #define AT803X_INER_INIT			0xec00
+ #define AT803X_INSR				0x0013
++
++#define AT803X_PCS_SMART_EEE_CTRL3			0x805D
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK	0x3
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT	12
++#define AT803X_SMART_EEE_CTRL3_LPI_EN			BIT(8)
++
+ #define AT803X_DEBUG_ADDR			0x1D
+ #define AT803X_DEBUG_DATA			0x1E
++#define AT803X_DBG0_REG				0x00
++#define AT803X_DEBUG_RGMII_RX_CLK_DLY		BIT(8)
+ #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
+ #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
+ 
+@@ -50,6 +60,7 @@ MODULE_LICENSE("GPL");
+ struct at803x_priv {
+ 	bool phy_reset:1;
+ 	struct gpio_desc *gpiod_reset;
++	int prev_speed;
+ };
+ 
+ struct at803x_context {
+@@ -61,6 +72,43 @@ struct at803x_context {
+ 	u16 led_control;
+ };
+ 
++static u16
++at803x_dbg_reg_rmw(struct phy_device *phydev, u16 reg, u16 clear, u16 set)
++{
++	struct mii_bus *bus = phydev->bus;
++	int val;
++
++	mutex_lock(&bus->mdio_lock);
++
++	bus->write(bus, phydev->addr, AT803X_DEBUG_ADDR, reg);
++	val = bus->read(bus, phydev->addr, AT803X_DEBUG_DATA);
++	if (val < 0) {
++		val = 0xffff;
++		goto out;
++	}
++
++	val &= ~clear;
++	val |= set;
++	bus->write(bus, phydev->addr, AT803X_DEBUG_DATA, val);
++
++out:
++	mutex_unlock(&bus->mdio_lock);
++	return val;
++}
++
++static inline void
++at803x_dbg_reg_set(struct phy_device *phydev, u16 reg, u16 set)
++{
++	at803x_dbg_reg_rmw(phydev, reg, 0, set);
++}
++
++static inline void
++at803x_dbg_reg_clr(struct phy_device *phydev, u16 reg, u16 clear)
++{
++	at803x_dbg_reg_rmw(phydev, reg, clear, 0);
++}
++
++
+ /* save relevant PHY registers to private copy */
+ static void at803x_context_save(struct phy_device *phydev,
+ 				struct at803x_context *context)
+@@ -208,8 +256,16 @@ static int at803x_probe(struct phy_devic
+ 	return 0;
+ }
+ 
++static void at803x_disable_smarteee(struct phy_device *phydev)
++{
++	phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
++		1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
++	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
++}
++
+ static int at803x_config_init(struct phy_device *phydev)
+ {
++	struct at803x_platform_data *pdata;
+ 	int ret;
+ 
+ 	ret = genphy_config_init(phydev);
+@@ -227,6 +283,26 @@ static int at803x_config_init(struct phy
+ 			return ret;
+ 	}
+ 
++	pdata = dev_get_platdata(&phydev->dev);
++	if (pdata) {
++		if (pdata->disable_smarteee)
++			at803x_disable_smarteee(phydev);
++
++		if (pdata->enable_rgmii_rx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DBG0_REG,
++				AT803X_DEBUG_RGMII_RX_CLK_DLY);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DBG0_REG,
++				AT803X_DEBUG_RGMII_RX_CLK_DLY);
++
++		if (pdata->enable_rgmii_tx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++	}
++
+ 	return 0;
+ }
+ 
+@@ -258,6 +334,8 @@ static int at803x_config_intr(struct phy
+ static void at803x_link_change_notify(struct phy_device *phydev)
+ {
+ 	struct at803x_priv *priv = phydev->priv;
++	struct at803x_platform_data *pdata;
++	pdata = dev_get_platdata(&phydev->dev);
+ 
+ 	/*
+ 	 * Conduct a hardware reset for AT8030 every time a link loss is
+@@ -288,6 +366,26 @@ static void at803x_link_change_notify(st
+ 			priv->phy_reset = false;
+ 		}
+ 	}
++	if (pdata && pdata->fixup_rgmii_tx_delay &&
++	    phydev->speed != priv->prev_speed) {
++		switch (phydev->speed) {
++		case SPEED_10:
++		case SPEED_100:
++			at803x_dbg_reg_set(phydev,
++				AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++			break;
++		case SPEED_1000:
++			at803x_dbg_reg_clr(phydev,
++				AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++			break;
++		default:
++			break;
++		}
++
++		priv->prev_speed = phydev->speed;
++	}
+ }
+ 
+ static struct phy_driver at803x_driver[] = {
+--- /dev/null
++++ b/include/linux/platform_data/phy-at803x.h
+@@ -0,0 +1,11 @@
++#ifndef _PHY_AT803X_PDATA_H
++#define _PHY_AT803X_PDATA_H
++
++struct at803x_platform_data {
++	int disable_smarteee:1;
++	int enable_rgmii_tx_delay:1;
++	int enable_rgmii_rx_delay:1;
++	int fixup_rgmii_tx_delay:1;
++};
++
++#endif /* _PHY_AT803X_PDATA_H */
diff --git a/target/linux/generic/patches-3.18/735-net-phy-at803x-fix-at8033-sgmii-mode.patch b/target/linux/generic/patches-3.18/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
new file mode 100644
index 0000000000..4a8f532aa3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
@@ -0,0 +1,96 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -36,6 +36,9 @@
+ #define AT803X_INER				0x0012
+ #define AT803X_INER_INIT			0xec00
+ #define AT803X_INSR				0x0013
++#define AT803X_REG_CHIP_CONFIG			0x1f
++#define AT803X_BT_BX_REG_SEL			0x8000
++#define AT803X_SGMII_ANEG_EN			0x1000
+ 
+ #define AT803X_PCS_SMART_EEE_CTRL3			0x805D
+ #define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK	0x3
+@@ -49,9 +52,10 @@
+ #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
+ #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
+ 
+-#define ATH8030_PHY_ID 0x004dd076
+-#define ATH8031_PHY_ID 0x004dd074
+-#define ATH8035_PHY_ID 0x004dd072
++#define AT803X_PHY_ID_MASK			0xffffffef
++#define ATH8030_PHY_ID				0x004dd076
++#define ATH8031_PHY_ID				0x004dd074
++#define ATH8035_PHY_ID				0x004dd072
+ 
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi");
+@@ -267,6 +271,27 @@ static int at803x_config_init(struct phy
+ {
+ 	struct at803x_platform_data *pdata;
+ 	int ret;
++	u32 v;
++
++	if (phydev->drv->phy_id == ATH8031_PHY_ID &&
++		phydev->interface == PHY_INTERFACE_MODE_SGMII)
++	{
++		v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
++		/* select SGMII/fiber page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v & ~AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++		/* enable SGMII autonegotiation */
++		ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
++		if (ret)
++			return ret;
++		/* select copper page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v | AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++	}
+ 
+ 	ret = genphy_config_init(phydev);
+ 	if (ret < 0)
+@@ -393,7 +418,7 @@ static struct phy_driver at803x_driver[]
+ 	/* ATHEROS 8035 */
+ 	.phy_id			= ATH8035_PHY_ID,
+ 	.name			= "Atheros 8035 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -412,7 +437,7 @@ static struct phy_driver at803x_driver[]
+ 	/* ATHEROS 8030 */
+ 	.phy_id			= ATH8030_PHY_ID,
+ 	.name			= "Atheros 8030 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -430,8 +455,8 @@ static struct phy_driver at803x_driver[]
+ }, {
+ 	/* ATHEROS 8031 */
+ 	.phy_id			= ATH8031_PHY_ID,
+-	.name			= "Atheros 8031 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.name			= "Atheros 8031/8033 ethernet",
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -465,9 +490,9 @@ module_init(atheros_init);
+ module_exit(atheros_exit);
+ 
+ static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+-	{ ATH8030_PHY_ID, 0xffffffef },
+-	{ ATH8031_PHY_ID, 0xffffffef },
+-	{ ATH8035_PHY_ID, 0xffffffef },
++	{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ }
+ };
+ 
diff --git a/target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch b/target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch
new file mode 100644
index 0000000000..7051843b74
--- /dev/null
+++ b/target/linux/generic/patches-3.18/760-8139cp-fixes-from-4.3.patch
@@ -0,0 +1,365 @@
+commit 41b976414c88016e2c9d9b2f6667ee67a998d388
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:45:31 2015 +0100
+
+    8139cp: Dump contents of descriptor ring on TX timeout
+    
+    We are seeing unexplained TX timeouts under heavy load. Let's try to get
+    a better idea of what's going on.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 7f4c685633e2df9ba10d49a31dda13715745db37
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:45:16 2015 +0100
+
+    8139cp: Fix DMA unmapping of transmitted buffers
+    
+    The low 16 bits of the 'opts1' field in the TX descriptor are supposed
+    to still contain the buffer length when the descriptor is handed back to
+    us. In practice, at least on my hardware, they don't. So stash the
+    original value of the opts1 field and get the length to unmap from
+    there.
+    
+    There are other ways we could have worked out the length, but I actually
+    want a stash of the opts1 field anyway so that I can dump it alongside
+    the contents of the descriptor ring when we suffer a TX timeout.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 0a5aeee0b79fa99d8e04c98dd4e87d4f52aa497b
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:44:57 2015 +0100
+
+    8139cp: Reduce duplicate csum/tso code in cp_start_xmit()
+    
+    We calculate the value of the opts1 descriptor field in three different
+    places. With two different behaviours when given an invalid packet to
+    be checksummed — none of them correct. Sort that out.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit a3b804043f490aeec57d8ca5baccdd35e6250857
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:44:38 2015 +0100
+
+    8139cp: Fix TSO/scatter-gather descriptor setup
+    
+    When sending a TSO frame in multiple buffers, we were neglecting to set
+    the first descriptor up in TSO mode.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 26b0bad6ac3a0167792dc4ffb276c29bc597d239
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:44:06 2015 +0100
+
+    8139cp: Fix tx_queued debug message to print correct slot numbers
+    
+    After a certain amount of staring at the debug output of this driver, I
+    realised it was lying to me.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit aaa0062ecf4877a26dea66bee1039c6eaf906c94
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:43:41 2015 +0100
+
+    8139cp: Do not re-enable RX interrupts in cp_tx_timeout()
+    
+    If an RX interrupt was already received but NAPI has not yet run when
+    the RX timeout happens, we end up in cp_tx_timeout() with RX interrupts
+    already disabled. Blindly re-enabling them will cause an IRQ storm.
+    
+    (This is made particularly horrid by the fact that cp_interrupt() always
+    returns that it's handled the interrupt, even when it hasn't actually
+    done anything. If it didn't do that, the core IRQ code would have
+    detected the storm and handled it, I'd have had a clear smoking gun
+    backtrace instead of just a spontaneously resetting router, and I'd have
+    at *least* two days of my life back. Changing the return value of
+    cp_interrupt() will be argued about under separate cover.)
+    
+    Unconditionally leave RX interrupts disabled after the reset, and
+    schedule NAPI to check the receive ring and re-enable them.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 7a8a8e75d505147358b225173e890ada43a267e2
+Author: David Woodhouse <dwmw2@infradead.org>
+Date:   Fri Sep 18 00:21:54 2015 +0100
+
+    8139cp: Call __cp_set_rx_mode() from cp_tx_timeout()
+    
+    Unless we reset the RX config, on real hardware I don't seem to receive
+    any packets after a TX timeout.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit fc27bd115b334e3ebdc682a42a47c3aea2566dcc
+Author: David Woodhouse <dwmw2@infradead.org>
+Date:   Fri Sep 18 00:19:08 2015 +0100
+
+    8139cp: Use dev_kfree_skb_any() instead of dev_kfree_skb() in cp_clean_rings()
+    
+    This can be called from cp_tx_timeout() with interrupts disabled.
+    Spotted by Francois Romieu <romieu@fr.zoreil.com>
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+--- a/drivers/net/ethernet/realtek/8139cp.c
++++ b/drivers/net/ethernet/realtek/8139cp.c
+@@ -157,6 +157,7 @@ enum {
+ 	NWayAdvert	= 0x66, /* MII ADVERTISE */
+ 	NWayLPAR	= 0x68, /* MII LPA */
+ 	NWayExpansion	= 0x6A, /* MII Expansion */
++	TxDmaOkLowDesc  = 0x82, /* Low 16 bit address of a Tx descriptor. */
+ 	Config5		= 0xD8,	/* Config5 */
+ 	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */
+ 	RxMaxSize	= 0xDA, /* Max size of an Rx packet (8169 only) */
+@@ -341,6 +342,7 @@ struct cp_private {
+ 	unsigned		tx_tail;
+ 	struct cp_desc		*tx_ring;
+ 	struct sk_buff		*tx_skb[CP_TX_RING_SIZE];
++	u32			tx_opts[CP_TX_RING_SIZE];
+ 
+ 	unsigned		rx_buf_sz;
+ 	unsigned		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
+@@ -665,7 +667,7 @@ static void cp_tx (struct cp_private *cp
+ 		BUG_ON(!skb);
+ 
+ 		dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
+-				 le32_to_cpu(txd->opts1) & 0xffff,
++				 cp->tx_opts[tx_tail] & 0xffff,
+ 				 PCI_DMA_TODEVICE);
+ 
+ 		if (status & LastFrag) {
+@@ -733,7 +735,7 @@ static netdev_tx_t cp_start_xmit (struct
+ {
+ 	struct cp_private *cp = netdev_priv(dev);
+ 	unsigned entry;
+-	u32 eor, flags;
++	u32 eor, opts1;
+ 	unsigned long intr_flags;
+ 	__le32 opts2;
+ 	int mss = 0;
+@@ -753,6 +755,21 @@ static netdev_tx_t cp_start_xmit (struct
+ 	mss = skb_shinfo(skb)->gso_size;
+ 
+ 	opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
++	opts1 = DescOwn;
++	if (mss)
++		opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
++	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
++		const struct iphdr *ip = ip_hdr(skb);
++		if (ip->protocol == IPPROTO_TCP)
++			opts1 |= IPCS | TCPCS;
++		else if (ip->protocol == IPPROTO_UDP)
++			opts1 |= IPCS | UDPCS;
++		else {
++			WARN_ONCE(1,
++				  "Net bug: asked to checksum invalid Legacy IP packet\n");
++			goto out_dma_error;
++		}
++	}
+ 
+ 	if (skb_shinfo(skb)->nr_frags == 0) {
+ 		struct cp_desc *txd = &cp->tx_ring[entry];
+@@ -768,31 +785,20 @@ static netdev_tx_t cp_start_xmit (struct
+ 		txd->addr = cpu_to_le64(mapping);
+ 		wmb();
+ 
+-		flags = eor | len | DescOwn | FirstFrag | LastFrag;
+-
+-		if (mss)
+-			flags |= LargeSend | ((mss & MSSMask) << MSSShift);
+-		else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-			const struct iphdr *ip = ip_hdr(skb);
+-			if (ip->protocol == IPPROTO_TCP)
+-				flags |= IPCS | TCPCS;
+-			else if (ip->protocol == IPPROTO_UDP)
+-				flags |= IPCS | UDPCS;
+-			else
+-				WARN_ON(1);	/* we need a WARN() */
+-		}
++		opts1 |= eor | len | FirstFrag | LastFrag;
+ 
+-		txd->opts1 = cpu_to_le32(flags);
++		txd->opts1 = cpu_to_le32(opts1);
+ 		wmb();
+ 
+ 		cp->tx_skb[entry] = skb;
+-		entry = NEXT_TX(entry);
++		cp->tx_opts[entry] = opts1;
++		netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
++			  entry, skb->len);
+ 	} else {
+ 		struct cp_desc *txd;
+-		u32 first_len, first_eor;
++		u32 first_len, first_eor, ctrl;
+ 		dma_addr_t first_mapping;
+ 		int frag, first_entry = entry;
+-		const struct iphdr *ip = ip_hdr(skb);
+ 
+ 		/* We must give this initial chunk to the device last.
+ 		 * Otherwise we could race with the device.
+@@ -805,14 +811,14 @@ static netdev_tx_t cp_start_xmit (struct
+ 			goto out_dma_error;
+ 
+ 		cp->tx_skb[entry] = skb;
+-		entry = NEXT_TX(entry);
+ 
+ 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+ 			const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ 			u32 len;
+-			u32 ctrl;
+ 			dma_addr_t mapping;
+ 
++			entry = NEXT_TX(entry);
++
+ 			len = skb_frag_size(this_frag);
+ 			mapping = dma_map_single(&cp->pdev->dev,
+ 						 skb_frag_address(this_frag),
+@@ -824,19 +830,7 @@ static netdev_tx_t cp_start_xmit (struct
+ 
+ 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+ 
+-			ctrl = eor | len | DescOwn;
+-
+-			if (mss)
+-				ctrl |= LargeSend |
+-					((mss & MSSMask) << MSSShift);
+-			else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-				if (ip->protocol == IPPROTO_TCP)
+-					ctrl |= IPCS | TCPCS;
+-				else if (ip->protocol == IPPROTO_UDP)
+-					ctrl |= IPCS | UDPCS;
+-				else
+-					BUG();
+-			}
++			ctrl = opts1 | eor | len;
+ 
+ 			if (frag == skb_shinfo(skb)->nr_frags - 1)
+ 				ctrl |= LastFrag;
+@@ -849,8 +843,8 @@ static netdev_tx_t cp_start_xmit (struct
+ 			txd->opts1 = cpu_to_le32(ctrl);
+ 			wmb();
+ 
++			cp->tx_opts[entry] = ctrl;
+ 			cp->tx_skb[entry] = skb;
+-			entry = NEXT_TX(entry);
+ 		}
+ 
+ 		txd = &cp->tx_ring[first_entry];
+@@ -858,27 +852,17 @@ static netdev_tx_t cp_start_xmit (struct
+ 		txd->addr = cpu_to_le64(first_mapping);
+ 		wmb();
+ 
+-		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-			if (ip->protocol == IPPROTO_TCP)
+-				txd->opts1 = cpu_to_le32(first_eor | first_len |
+-							 FirstFrag | DescOwn |
+-							 IPCS | TCPCS);
+-			else if (ip->protocol == IPPROTO_UDP)
+-				txd->opts1 = cpu_to_le32(first_eor | first_len |
+-							 FirstFrag | DescOwn |
+-							 IPCS | UDPCS);
+-			else
+-				BUG();
+-		} else
+-			txd->opts1 = cpu_to_le32(first_eor | first_len |
+-						 FirstFrag | DescOwn);
++		ctrl = opts1 | first_eor | first_len | FirstFrag;
++		txd->opts1 = cpu_to_le32(ctrl);
+ 		wmb();
++
++		cp->tx_opts[first_entry] = ctrl;
++		netif_dbg(cp, tx_queued, cp->dev, "tx queued, slots %d-%d, skblen %d\n",
++			  first_entry, entry, skb->len);
+ 	}
+-	cp->tx_head = entry;
++	cp->tx_head = NEXT_TX(entry);
+ 
+ 	netdev_sent_queue(dev, skb->len);
+-	netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
+-		  entry, skb->len);
+ 	if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
+ 		netif_stop_queue(dev);
+ 
+@@ -1115,6 +1099,7 @@ static int cp_init_rings (struct cp_priv
+ {
+ 	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+ 	cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
++	memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
+ 
+ 	cp_init_rings_index(cp);
+ 
+@@ -1151,7 +1136,7 @@ static void cp_clean_rings (struct cp_pr
+ 			desc = cp->rx_ring + i;
+ 			dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
+ 					 cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+-			dev_kfree_skb(cp->rx_skb[i]);
++			dev_kfree_skb_any(cp->rx_skb[i]);
+ 		}
+ 	}
+ 
+@@ -1164,7 +1149,7 @@ static void cp_clean_rings (struct cp_pr
+ 					 le32_to_cpu(desc->opts1) & 0xffff,
+ 					 PCI_DMA_TODEVICE);
+ 			if (le32_to_cpu(desc->opts1) & LastFrag)
+-				dev_kfree_skb(skb);
++				dev_kfree_skb_any(skb);
+ 			cp->dev->stats.tx_dropped++;
+ 		}
+ 	}
+@@ -1172,6 +1157,7 @@ static void cp_clean_rings (struct cp_pr
+ 
+ 	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+ 	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
++	memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
+ 
+ 	memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
+ 	memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
+@@ -1249,7 +1235,7 @@ static void cp_tx_timeout(struct net_dev
+ {
+ 	struct cp_private *cp = netdev_priv(dev);
+ 	unsigned long flags;
+-	int rc;
++	int rc, i;
+ 
+ 	netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
+ 		    cpr8(Cmd), cpr16(CpCmd),
+@@ -1257,13 +1243,26 @@ static void cp_tx_timeout(struct net_dev
+ 
+ 	spin_lock_irqsave(&cp->lock, flags);
+ 
++	netif_dbg(cp, tx_err, cp->dev, "TX ring head %d tail %d desc %x\n",
++		  cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc));
++	for (i = 0; i < CP_TX_RING_SIZE; i++) {
++		netif_dbg(cp, tx_err, cp->dev,
++			  "TX slot %d @%p: %08x (%08x) %08x %llx %p\n",
++			  i, &cp->tx_ring[i], le32_to_cpu(cp->tx_ring[i].opts1),
++			  cp->tx_opts[i], le32_to_cpu(cp->tx_ring[i].opts2),
++			  le64_to_cpu(cp->tx_ring[i].addr),
++			  cp->tx_skb[i]);
++	}
++
+ 	cp_stop_hw(cp);
+ 	cp_clean_rings(cp);
+ 	rc = cp_init_rings(cp);
+ 	cp_start_hw(cp);
+-	cp_enable_irq(cp);
++	__cp_set_rx_mode(dev);
++	cpw16_f(IntrMask, cp_norx_intr_mask);
+ 
+ 	netif_wake_queue(dev);
++	napi_schedule(&cp->napi);
+ 
+ 	spin_unlock_irqrestore(&cp->lock, flags);
+ }
diff --git a/target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch b/target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch
new file mode 100644
index 0000000000..52fc252447
--- /dev/null
+++ b/target/linux/generic/patches-3.18/773-bgmac-add-srab-switch.patch
@@ -0,0 +1,72 @@
+Register switch connected to srab
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -17,6 +17,7 @@
+ #include <linux/phy_fixed.h>
+ #include <linux/interrupt.h>
+ #include <linux/dma-mapping.h>
++#include <linux/platform_data/b53.h>
+ #include <bcm47xx_nvram.h>
+ 
+ static const struct bcma_device_id bgmac_bcma_tbl[] = {
+@@ -1538,6 +1539,17 @@ static void bgmac_mii_unregister(struct
+ 	mdiobus_free(mii_bus);
+ }
+ 
++static struct b53_platform_data bgmac_b53_pdata = {
++};
++
++static struct platform_device bgmac_b53_dev = {
++	.name		= "b53-srab-switch",
++	.id		= -1,
++	.dev		= {
++		.platform_data = &bgmac_b53_pdata,
++	},
++};
++
+ /**************************************************
+  * BCMA bus ops
+  **************************************************/
+@@ -1666,6 +1678,16 @@ static int bgmac_probe(struct bcma_devic
+ 	net_dev->hw_features = net_dev->features;
+ 	net_dev->vlan_features = net_dev->features;
+ 
++	if ((ci->id == BCMA_CHIP_ID_BCM4707 ||
++	     ci->id == BCMA_CHIP_ID_BCM53018) &&
++	    !bgmac_b53_pdata.regs) {
++		bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000);
++
++		err = platform_device_register(&bgmac_b53_dev);
++		if (!err)
++			bgmac->b53_device = &bgmac_b53_dev;
++	}
++
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+ 		bgmac_err(bgmac, "Cannot register net device\n");
+@@ -1692,6 +1714,10 @@ static void bgmac_remove(struct bcma_dev
+ {
+ 	struct bgmac *bgmac = bcma_get_drvdata(core);
+ 
++	if (bgmac->b53_device)
++		platform_device_unregister(&bgmac_b53_dev);
++	bgmac->b53_device = NULL;
++
+ 	unregister_netdev(bgmac->net_dev);
+ 	bgmac_mii_unregister(bgmac);
+ 	netif_napi_del(&bgmac->napi);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -462,6 +462,9 @@ struct bgmac {
+ 	bool has_robosw;
+ 
+ 	bool loopback;
++
++	/* platform device for associated switch */
++	struct platform_device *b53_device;
+ };
+ 
+ static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
diff --git a/target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch b/target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch
new file mode 100644
index 0000000000..50bccc4df5
--- /dev/null
+++ b/target/linux/generic/patches-3.18/785-hso-support-0af0-9300.patch
@@ -0,0 +1,25 @@
+--- a/drivers/net/usb/hso.c
++++ b/drivers/net/usb/hso.c
+@@ -468,6 +468,7 @@ static const struct usb_device_id hso_id
+ 	{USB_DEVICE(0x0af0, 0x8900)},
+ 	{USB_DEVICE(0x0af0, 0x9000)},
+ 	{USB_DEVICE(0x0af0, 0x9200)},		/* Option GTM671WFS */
++	{USB_DEVICE(0x0af0, 0x9300)},		/* GTM 66xxWFS */
+ 	{USB_DEVICE(0x0af0, 0xd035)},
+ 	{USB_DEVICE(0x0af0, 0xd055)},
+ 	{USB_DEVICE(0x0af0, 0xd155)},
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -1330,6 +1330,12 @@ UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0
+ 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 		0 ),
+ 
++UNUSUAL_DEV( 0x0af0, 0x9300, 0x0000, 0x0000,
++		"Option",
++		"Globetrotter 66xxWFS SD-Card",
++		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++		0 ),
++
+ UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+ 		"Option",
+ 		"GI 070x SD-Card",
diff --git a/target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch b/target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch
new file mode 100644
index 0000000000..5155bcdadf
--- /dev/null
+++ b/target/linux/generic/patches-3.18/810-pci_disable_common_quirks.patch
@@ -0,0 +1,51 @@
+--- a/drivers/pci/Kconfig
++++ b/drivers/pci/Kconfig
+@@ -58,6 +58,12 @@ config XEN_PCIDEV_FRONTEND
+           The PCI device frontend driver allows the kernel to import arbitrary
+           PCI devices from a PCI backend to support PCI driver domains.
+ 
++config PCI_DISABLE_COMMON_QUIRKS
++	bool "PCI disable common quirks"
++	depends on PCI
++	help
++	  If you don't know what to do here, say N.
++
+ config HT_IRQ
+ 	bool "Interrupts on hypertransport devices"
+ 	default y
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct
+ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+ 				PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ /* The Mellanox Tavor device gives false positive parity errors
+  * Mark this device with a broken_parity_status, to allow
+  * PCI scanning code to "skip" this now blacklisted device.
+@@ -2929,6 +2930,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
+ 
+ /*
+  * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.  To
+@@ -2985,6 +2987,8 @@ static void fixup_debug_report(struct pc
+ 	}
+ }
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ /*
+  * Some BIOS implementations leave the Intel GPU interrupts enabled,
+  * even though no one is handling them (f.e. i915 driver is never loaded).
+@@ -3019,6 +3023,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
+ /*
+  * PCI devices which are on Intel chips can skip the 10ms delay
+  * before entering D3 mode.
diff --git a/target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch
new file mode 100644
index 0000000000..a7bf0bb9fa
--- /dev/null
+++ b/target/linux/generic/patches-3.18/811-pci_disable_usb_common_quirks.patch
@@ -0,0 +1,101 @@
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -97,6 +97,8 @@ struct amd_chipset_type {
+ 	u8 rev;
+ };
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static struct amd_chipset_info {
+ 	struct pci_dev	*nb_dev;
+ 	struct pci_dev	*smbus_dev;
+@@ -454,6 +456,10 @@ void usb_amd_dev_put(void)
+ }
+ EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+ 
++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
++#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
++
+ /*
+  * Make sure the controller is completely inactive, unable to
+  * generate interrupts or do DMA.
+@@ -533,8 +539,17 @@ reset_needed:
+ 	uhci_reset_hc(pdev, base);
+ 	return 1;
+ }
++#else
++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
++{
++	return 0;
++}
++
++#endif
+ EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
+ {
+ 	u16 cmd;
+@@ -1095,3 +1110,4 @@ static void quirk_usb_early_handoff(stru
+ }
+ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ 			PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
++#endif
+--- a/drivers/usb/host/pci-quirks.h
++++ b/drivers/usb/host/pci-quirks.h
+@@ -4,6 +4,9 @@
+ #ifdef CONFIG_PCI
+ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
+ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
++#endif  /* CONFIG_PCI */
++
++#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
+ int usb_amd_find_chipset_info(void);
+ int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
+ bool usb_amd_hang_symptom_quirk(void);
+@@ -16,11 +19,24 @@ void usb_disable_xhci_ports(struct pci_d
+ void sb800_prefetch(struct device *dev, int on);
+ #else
+ struct pci_dev;
++static inline int usb_amd_find_chipset_info(void)
++{
++	return 0;
++}
++static inline bool usb_amd_hang_symptom_quirk(void)
++{
++	return false;
++}
++static inline bool usb_amd_prefetch_quirk(void)
++{
++	return false;
++}
+ static inline void usb_amd_quirk_pll_disable(void) {}
+ static inline void usb_amd_quirk_pll_enable(void) {}
+ static inline void usb_amd_dev_put(void) {}
+ static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
+ static inline void sb800_prefetch(struct device *dev, int on) {}
+-#endif  /* CONFIG_PCI */
++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
++#endif
+ 
+ #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -445,7 +445,14 @@ extern int usb_hcd_pci_probe(struct pci_
+ extern void usb_hcd_pci_remove(struct pci_dev *dev);
+ extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
++#else
++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
++{
++	return 0;
++}
++#endif
+ 
+ #ifdef CONFIG_PM
+ extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
diff --git a/target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch b/target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch
new file mode 100644
index 0000000000..9e841cb642
--- /dev/null
+++ b/target/linux/generic/patches-3.18/821-usb-dwc2-dualrole.patch
@@ -0,0 +1,146 @@
+--- a/drivers/usb/dwc2/Kconfig
++++ b/drivers/usb/dwc2/Kconfig
+@@ -1,6 +1,6 @@
+ config USB_DWC2
+-	bool "DesignWare USB2 DRD Core Support"
+-	depends on USB
++	tristate "DesignWare USB2 DRD Core Support"
++	depends on USB || USB_GADGET
+ 	help
+ 	  Say Y here if your system has a Dual Role Hi-Speed USB
+ 	  controller based on the DesignWare HSOTG IP Core.
+@@ -10,49 +10,61 @@ config USB_DWC2
+ 	  bus interface module (if you have a PCI bus system) will be
+ 	  called dwc2_pci.ko, and the platform interface module (for
+ 	  controllers directly connected to the CPU) will be called
+-	  dwc2_platform.ko. For gadget mode, there will be a single
+-	  module called dwc2_gadget.ko.
+-
+-	  NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The
+-	  host and gadget drivers are still currently separate drivers.
+-	  There are plans to merge the dwc2_gadget driver with the dwc2
+-	  host driver in the near future to create a dual-role driver.
++	  dwc2_platform.ko. For all modes(host, gadget and dual-role), there
++	  will be an additional module named dwc2.ko.
+ 
+ if USB_DWC2
+ 
++choice
++	bool "DWC2 Mode Selection"
++	default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET)
++	default USB_DWC2_HOST if (USB && !USB_GADGET)
++	default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET)
++
+ config USB_DWC2_HOST
+-	tristate "Host only mode"
++	bool "Host only mode"
+ 	depends on USB
+ 	help
+ 	  The Designware USB2.0 high-speed host controller
+-	  integrated into many SoCs.
++	  integrated into many SoCs. Select this option if you want the
++	  driver to operate in Host-only mode.
+ 
+-config USB_DWC2_PLATFORM
+-	bool "DWC2 Platform"
+-	depends on USB_DWC2_HOST
+-	default USB_DWC2_HOST
++comment "Gadget/Dual-role mode requires USB Gadget support to be enabled"
++
++config USB_DWC2_PERIPHERAL
++	bool "Gadget only mode"
++	depends on USB_GADGET=y || USB_GADGET=USB_DWC2
++	help
++	  The Designware USB2.0 high-speed gadget controller
++	  integrated into many SoCs. Select this option if you want the
++	  driver to operate in Peripheral-only mode. This option requires
++	  USB_GADGET to be enabled.
++
++config USB_DWC2_DUAL_ROLE
++	bool "Dual Role mode"
++	depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
+ 	help
+-	  The Designware USB2.0 platform interface module for
+-	  controllers directly connected to the CPU. This is only
+-	  used for host mode.
++	  Select this option if you want the driver to work in a dual-role
++	  mode. In this mode both host and gadget features are enabled, and
++	  the role will be determined by the cable that gets plugged-in. This
++	  option requires USB_GADGET to be enabled.
++endchoice
++
++config USB_DWC2_PLATFORM
++	tristate "DWC2 Platform"
++	default USB_DWC2_HOST || USB_DWC2_PERIPHERAL
++        help
++          The Designware USB2.0 platform interface module for
++          controllers directly connected to the CPU.
+ 
+ config USB_DWC2_PCI
+-	bool "DWC2 PCI"
++	tristate "DWC2 PCI"
+ 	depends on USB_DWC2_HOST && PCI
+ 	default USB_DWC2_HOST
+ 	help
+ 	  The Designware USB2.0 PCI interface module for controllers
+ 	  connected to a PCI bus. This is only used for host mode.
+ 
+-comment "Gadget mode requires USB Gadget support to be enabled"
+-
+-config USB_DWC2_PERIPHERAL
+-	tristate "Gadget only mode"
+-	depends on USB_GADGET
+-	help
+-	  The Designware USB2.0 high-speed gadget controller
+-	  integrated into many SoCs.
+-
+ config USB_DWC2_DEBUG
+ 	bool "Enable Debugging Messages"
+ 	help
+--- a/drivers/usb/dwc2/Makefile
++++ b/drivers/usb/dwc2/Makefile
+@@ -1,28 +1,28 @@
+ ccflags-$(CONFIG_USB_DWC2_DEBUG)	+= -DDEBUG
+ ccflags-$(CONFIG_USB_DWC2_VERBOSE)	+= -DVERBOSE_DEBUG
+ 
+-obj-$(CONFIG_USB_DWC2_HOST)		+= dwc2.o
++obj-$(CONFIG_USB_DWC2)			+= dwc2.o
+ dwc2-y					:= core.o core_intr.o
+-dwc2-y					+= hcd.o hcd_intr.o
+-dwc2-y					+= hcd_queue.o hcd_ddma.o
++
++ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
++	dwc2-y				+= hcd.o hcd_intr.o
++	dwc2-y				+= hcd_queue.o hcd_ddma.o
++endif
++
++ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
++	dwc2-y       			+= gadget.o
++endif
+ 
+ # NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to
+ # this location and renamed gadget.c. When building for dynamically linked
+-# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode,
+-# the core module will be dwc2.ko, the PCI bus interface module will called
+-# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko.
+-# At present the host and gadget driver will be separate drivers, but there
+-# are plans in the near future to create a dual-role driver.
++# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role
++# mode. The PCI bus interface module will called dwc2_pci.ko and the platform
++# interface module will be called dwc2_platform.ko.
+ 
+ ifneq ($(CONFIG_USB_DWC2_PCI),)
+-	obj-$(CONFIG_USB_DWC2_HOST)	+= dwc2_pci.o
++	obj-$(CONFIG_USB_DWC2)		+= dwc2_pci.o
+ 	dwc2_pci-y			:= pci.o
+ endif
+ 
+-ifneq ($(CONFIG_USB_DWC2_PLATFORM),)
+-	obj-$(CONFIG_USB_DWC2_HOST)	+= dwc2_platform.o
+-	dwc2_platform-y			:= platform.o
+-endif
+-
+-obj-$(CONFIG_USB_DWC2_PERIPHERAL)	+= dwc2_gadget.o
+-dwc2_gadget-y				:= gadget.o
++obj-$(CONFIG_USB_DWC2_PLATFORM)		+= dwc2_platform.o
++dwc2_platform-y				:= platform.o
diff --git a/target/linux/generic/patches-3.18/831-ledtrig_netdev.patch b/target/linux/generic/patches-3.18/831-ledtrig_netdev.patch
new file mode 100644
index 0000000000..3b46b4a9f4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/831-ledtrig_netdev.patch
@@ -0,0 +1,21 @@
+--- a/drivers/leds/trigger/Kconfig
++++ b/drivers/leds/trigger/Kconfig
+@@ -108,4 +108,11 @@ config LEDS_TRIGGER_CAMERA
+ 	  This enables direct flash/torch on/off by the driver, kernel space.
+ 	  If unsure, say Y.
+ 
++config LEDS_TRIGGER_NETDEV
++	tristate "LED Netdev Trigger"
++	depends on NET && LEDS_TRIGGERS
++	help
++	  This allows LEDs to be controlled by network device activity.
++	  If unsure, say Y.
++
+ endif # LEDS_TRIGGERS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -62,3 +62,4 @@ obj-$(CONFIG_LEDS_DAC124S085)		+= leds-d
+ 
+ # LED Triggers
+ obj-$(CONFIG_LEDS_TRIGGERS)		+= trigger/
++obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
diff --git a/target/linux/generic/patches-3.18/834-ledtrig-libata.patch b/target/linux/generic/patches-3.18/834-ledtrig-libata.patch
new file mode 100644
index 0000000000..d0aee1c2d0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/834-ledtrig-libata.patch
@@ -0,0 +1,153 @@
+From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 12 Dec 2014 13:38:33 +0100
+Subject: [PATCH] libata: add ledtrig support
+To: linux-ide@vger.kernel.org,
+    Tejun Heo <tj@kernel.org>
+
+This adds a LED trigger for each ATA port indicating disk activity.
+
+As this is needed only on specific platforms (NAS SoCs and such),
+these platforms should define ARCH_WANTS_LIBATA_LEDS if there
+are boards with LED(s) intended to indicate ATA disk activity and
+need the OS to take care of that.
+In that way, if not selected, LED trigger support not will be
+included in libata-core and both, codepaths and structures remain
+untouched.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/ata/Kconfig       | 16 ++++++++++++++++
+ drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/libata.h    |  9 +++++++++
+ 3 files changed, 66 insertions(+)
+
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
+ 
+ 	  If unsure, say Y.
+ 
++config ARCH_WANT_LIBATA_LEDS
++	bool
++
++config ATA_LEDS
++	bool "support ATA port LED triggers"
++	depends on ARCH_WANT_LIBATA_LEDS
++	select NEW_LEDS
++	select LEDS_CLASS
++	select LEDS_TRIGGERS
++	default y
++	help
++	  This option adds a LED trigger for each registered ATA port.
++	  It is used to drive disk activity leds connected via GPIO.
++
++	  If unsure, say N.
++
+ config ATA_ACPI
+ 	bool "ATA ACPI Support"
+ 	depends on ACPI && PCI
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -725,6 +725,19 @@ u64 ata_tf_read_block(struct ata_taskfil
+ 	return block;
+ }
+ 
++#ifdef CONFIG_ATA_LEDS
++#define LIBATA_BLINK_DELAY 20 /* ms */
++static inline void ata_led_act(struct ata_port *ap)
++{
++	unsigned long led_delay = LIBATA_BLINK_DELAY;
++
++	if (unlikely(!ap->ledtrig))
++		return;
++
++	led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
++}
++#endif
++
+ /**
+  *	ata_build_rw_tf - Build ATA taskfile for given read/write request
+  *	@tf: Target ATA taskfile
+@@ -4800,6 +4813,9 @@ static struct ata_queued_cmd *ata_qc_new
+ 			break;
+ 		}
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	ata_led_act(ap);
++#endif
+ 
+ 	return qc;
+ }
+@@ -5710,6 +5726,9 @@ struct ata_port *ata_port_alloc(struct a
+ 	ap->stats.unhandled_irq = 1;
+ 	ap->stats.idle_irq = 1;
+ #endif
++#ifdef CONFIG_ATA_LEDS
++	ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
++#endif
+ 	ata_sff_port_init(ap);
+ 
+ 	return ap;
+@@ -5731,6 +5750,12 @@ static void ata_host_release(struct devi
+ 
+ 		kfree(ap->pmp_link);
+ 		kfree(ap->slave_link);
++#ifdef CONFIG_ATA_LEDS
++		if (ap->ledtrig) {
++			led_trigger_unregister(ap->ledtrig);
++			kfree(ap->ledtrig);
++		};
++#endif
+ 		kfree(ap);
+ 		host->ports[i] = NULL;
+ 	}
+@@ -6177,7 +6202,23 @@ int ata_host_register(struct ata_host *h
+ 		host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+ 		host->ports[i]->local_port_no = i + 1;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	for (i = 0; i < host->n_ports; i++) {
++		if (unlikely(!host->ports[i]->ledtrig))
++			continue;
+ 
++		snprintf(host->ports[i]->ledtrig_name,
++			sizeof(host->ports[i]->ledtrig_name), "ata%u",
++			host->ports[i]->print_id);
++
++		host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
++
++		if (led_trigger_register(host->ports[i]->ledtrig)) {
++			kfree(host->ports[i]->ledtrig);
++			host->ports[i]->ledtrig = NULL;
++		}
++	}
++#endif
+ 	/* Create associated sysfs transport objects  */
+ 	for (i = 0; i < host->n_ports; i++) {
+ 		rc = ata_tport_add(host->dev,host->ports[i]);
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -38,6 +38,9 @@
+ #include <linux/acpi.h>
+ #include <linux/cdrom.h>
+ #include <linux/sched.h>
++#ifdef CONFIG_ATA_LEDS
++#include <linux/leds.h>
++#endif
+ 
+ /*
+  * Define if arch has non-standard setup.  This is a _PCI_ standard
+@@ -874,6 +877,12 @@ struct ata_port {
+ #ifdef CONFIG_ATA_ACPI
+ 	struct ata_acpi_gtm	__acpi_init_gtm; /* use ata_acpi_init_gtm() */
+ #endif
++
++#ifdef CONFIG_ATA_LEDS
++	struct led_trigger	*ledtrig;
++	char			ledtrig_name[8];
++#endif
++
+ 	/* owned by EH */
+ 	u8			sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ };
diff --git a/target/linux/generic/patches-3.18/840-rtc7301.patch b/target/linux/generic/patches-3.18/840-rtc7301.patch
new file mode 100644
index 0000000000..2134d87476
--- /dev/null
+++ b/target/linux/generic/patches-3.18/840-rtc7301.patch
@@ -0,0 +1,250 @@
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -979,6 +979,15 @@ config RTC_DRV_NUC900
+ 	  If you say yes here you get support for the RTC subsystem of the
+ 	  NUC910/NUC920 used in embedded systems.
+ 
++config RTC_DRV_RTC7301
++	tristate "Epson RTC-7301 SF/DG"
++	help
++	  If you say Y here you will get support for the
++	  Epson RTC-7301 SF/DG RTC chips.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-7301.
++
+ comment "on-CPU RTC drivers"
+ 
+ config RTC_DRV_DAVINCI
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -115,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01)	+= rtc-rp5c
+ obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
+ obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o
+ obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
++obj-$(CONFIG_RTC_DRV_RTC7301)	+= rtc-rtc7301.o
+ obj-$(CONFIG_RTC_DRV_RV3029C2)	+= rtc-rv3029c2.o
+ obj-$(CONFIG_RTC_DRV_RX4581)	+= rtc-rx4581.o
+ obj-$(CONFIG_RTC_DRV_RX8025)	+= rtc-rx8025.o
+--- /dev/null
++++ b/drivers/rtc/rtc-rtc7301.c
+@@ -0,0 +1,219 @@
++/*
++ * Driver for Epson RTC-7301SF/DG
++ *
++ * Copyright (C) 2009 Jose Vasconcellos
++ *
++ * 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/module.h>
++#include <linux/rtc.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/bcd.h>
++
++#define RTC_NAME "rtc7301"
++#define RTC_VERSION "0.1"
++
++/* Epson RTC-7301 register addresses */
++#define RTC7301_SEC		0x00
++#define RTC7301_SEC10		0x01
++#define RTC7301_MIN		0x02
++#define RTC7301_MIN10		0x03
++#define RTC7301_HOUR		0x04
++#define RTC7301_HOUR10		0x05
++#define RTC7301_WEEKDAY		0x06
++#define RTC7301_DAY		0x07
++#define RTC7301_DAY10		0x08
++#define RTC7301_MON		0x09
++#define RTC7301_MON10		0x0A
++#define RTC7301_YEAR		0x0B
++#define RTC7301_YEAR10		0x0C
++#define RTC7301_YEAR100		0x0D
++#define RTC7301_YEAR1000	0x0E
++#define RTC7301_CTRLREG		0x0F
++
++static uint8_t __iomem *rtc7301_base;
++
++#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf)
++#define write_reg(offset, data) writeb(data, rtc7301_base + (offset))
++
++#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1)
++
++static void rtc7301_init_settings(void)
++{
++	int i;
++
++	write_reg(RTC7301_CTRLREG, 2);
++	write_reg(RTC7301_YEAR1000, 2);
++	udelay(122);
++
++	/* bank 1 */
++	write_reg(RTC7301_CTRLREG, 6);
++	for (i=0; i<15; i++)
++		write_reg(i, 0);
++
++	/* bank 2 */
++	write_reg(RTC7301_CTRLREG, 14);
++	for (i=0; i<15; i++)
++		write_reg(i, 0);
++	write_reg(RTC7301_CTRLREG, 0);
++}
++
++static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt)
++{
++	int cnt;
++	uint8_t buf[16];
++
++	cnt = 0;
++	while (rtc7301_isbusy()) {
++		udelay(244);
++		if (cnt++ > 100) {
++			dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]);
++			return -EIO;
++		}
++	}
++
++	for (cnt=0; cnt<16; cnt++)
++		buf[cnt] = read_reg(cnt);
++
++	if (buf[RTC7301_SEC10] & 8) {
++		dev_err(dev, "%s: RTC not set\n", __func__);
++		return -EINVAL;
++	}
++
++	memset(dt, 0, sizeof(*dt));
++
++	dt->tm_sec =  buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10;
++	dt->tm_min =  buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10;
++	dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10;
++
++	dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10;
++	dt->tm_mon =  buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1;
++	dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 +
++		      buf[RTC7301_YEAR100]*100 +
++		      ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900;
++
++	/* the rtc device may contain illegal values on power up
++	 * according to the data sheet. make sure they are valid.
++	 */
++
++	return rtc_valid_tm(dt);
++}
++
++static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt)
++{
++	int data;
++
++	data = dt->tm_year + 1900;
++	if (data >= 2100 || data < 1900)
++		return -EINVAL;
++
++	write_reg(RTC7301_CTRLREG, 2);
++       	udelay(122);
++
++	data = bin2bcd(dt->tm_sec);
++	write_reg(RTC7301_SEC, data);
++	write_reg(RTC7301_SEC10, (data >> 4));
++
++	data = bin2bcd(dt->tm_min);
++	write_reg(RTC7301_MIN, data );
++	write_reg(RTC7301_MIN10, (data >> 4));
++
++	data = bin2bcd(dt->tm_hour);
++	write_reg(RTC7301_HOUR, data);
++	write_reg(RTC7301_HOUR10, (data >> 4));
++
++	data = bin2bcd(dt->tm_mday);
++	write_reg(RTC7301_DAY, data);
++	write_reg(RTC7301_DAY10, (data>> 4));
++
++	data = bin2bcd(dt->tm_mon + 1);
++	write_reg(RTC7301_MON, data);
++	write_reg(RTC7301_MON10, (data >> 4));
++
++	data = bin2bcd(dt->tm_year % 100);
++	write_reg(RTC7301_YEAR, data);
++	write_reg(RTC7301_YEAR10, (data >> 4));
++	data = bin2bcd((1900 + dt->tm_year) / 100);
++	write_reg(RTC7301_YEAR100, data);
++
++	data = bin2bcd(dt->tm_wday);
++	write_reg(RTC7301_WEEKDAY, data);
++
++	write_reg(RTC7301_CTRLREG, 0);
++
++	return 0;
++}
++
++static const struct rtc_class_ops rtc7301_rtc_ops = {
++	.read_time	= rtc7301_get_datetime,
++	.set_time	= rtc7301_set_datetime,
++};
++
++static int rtc7301_probe(struct platform_device *pdev)
++{
++	struct rtc_device *rtc;
++	struct resource *res;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENOENT;
++
++	rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/);
++	if (!rtc7301_base)
++		return -EINVAL;
++
++	rtc = rtc_device_register(RTC_NAME, &pdev->dev,
++				&rtc7301_rtc_ops, THIS_MODULE);
++	if (IS_ERR(rtc)) {
++		iounmap(rtc7301_base);
++		return PTR_ERR(rtc);
++	}
++
++	platform_set_drvdata(pdev, rtc);
++
++	rtc7301_init_settings();
++	return 0;
++}
++
++static int rtc7301_remove(struct platform_device *pdev)
++{
++	struct rtc_device *rtc = platform_get_drvdata(pdev);
++
++	if (rtc)
++		rtc_device_unregister(rtc);
++	if (rtc7301_base)
++		iounmap(rtc7301_base);
++	return 0;
++}
++
++static struct platform_driver rtc7301_driver = {
++	.driver = {
++		.name	= RTC_NAME,
++		.owner	= THIS_MODULE,
++	},
++	.probe	= rtc7301_probe,
++	.remove = rtc7301_remove,
++};
++
++static __init int rtc7301_init(void)
++{
++	return platform_driver_register(&rtc7301_driver);
++}
++module_init(rtc7301_init);
++
++static __exit void rtc7301_exit(void)
++{
++	platform_driver_unregister(&rtc7301_driver);
++}
++module_exit(rtc7301_exit);
++
++MODULE_DESCRIPTION("Epson 7301 RTC driver");
++MODULE_AUTHOR("Jose Vasconcellos <jvasco@verizon.net>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" RTC_NAME);
++MODULE_VERSION(RTC_VERSION);
diff --git a/target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch b/target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch
new file mode 100644
index 0000000000..83b0232e13
--- /dev/null
+++ b/target/linux/generic/patches-3.18/841-rtc_pt7c4338.patch
@@ -0,0 +1,247 @@
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -567,6 +567,15 @@ config RTC_DRV_S5M
+ 	  This driver can also be built as a module. If so, the module
+ 	  will be called rtc-s5m.
+ 
++config RTC_DRV_PT7C4338
++	tristate "Pericom Technology Inc. PT7C4338 RTC"
++	help
++	  If you say yes here you get support for the Pericom Technology
++	  Inc. PT7C4338 RTC chip.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-pt7c4338.
++
+ endif # I2C
+ 
+ comment "SPI RTC drivers"
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_PL030)	+= rtc-pl030
+ obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
+ obj-$(CONFIG_RTC_DRV_PM8XXX)	+= rtc-pm8xxx.o
+ obj-$(CONFIG_RTC_DRV_PS3)	+= rtc-ps3.o
++obj-$(CONFIG_RTC_DRV_PT7C4338)	+= rtc-pt7c4338.o
+ obj-$(CONFIG_RTC_DRV_PUV3)	+= rtc-puv3.o
+ obj-$(CONFIG_RTC_DRV_PXA)	+= rtc-pxa.o
+ obj-$(CONFIG_RTC_DRV_R9701)	+= rtc-r9701.o
+--- /dev/null
++++ b/drivers/rtc/rtc-pt7c4338.c
+@@ -0,0 +1,216 @@
++/*
++ * Copyright 2010 Freescale Semiconductor, Inc.
++ *
++ * Author:	Priyanka Jain <Priyanka.Jain@freescale.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++/*
++ * This file provides Date & Time support (no alarms) for PT7C4338 chip.
++ *
++ * This file is based on drivers/rtc/rtc-ds1307.c
++ *
++ * PT7C4338 chip is manufactured by Pericom Technology Inc.
++ * It is a serial real-time clock which provides
++ * 1)Low-power clock/calendar.
++ * 2)Programmable square-wave output.
++ * It has 56 bytes of nonvolatile RAM.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/rtc.h>
++#include <linux/bcd.h>
++
++/* RTC register addresses */
++#define PT7C4338_REG_SECONDS          0x00
++#define PT7C4338_REG_MINUTES          0x01
++#define PT7C4338_REG_HOURS            0x02
++#define PT7C4338_REG_AMPM             0x02
++#define PT7C4338_REG_DAY              0x03
++#define PT7C4338_REG_DATE             0x04
++#define PT7C4338_REG_MONTH            0x05
++#define PT7C4338_REG_YEAR             0x06
++#define PT7C4338_REG_CTRL_STAT        0x07
++
++/* RTC second register address bit */
++#define PT7C4338_SEC_BIT_CH           0x80	/*Clock Halt (in Register 0)*/
++
++/* RTC control and status register bits */
++#define PT7C4338_CTRL_STAT_BIT_RS0    0x1	/*Rate select 0*/
++#define PT7C4338_CTRL_STAT_BIT_RS1    0x2	/*Rate select 1*/
++#define PT7C4338_CTRL_STAT_BIT_SQWE   0x10	/*Square Wave Enable*/
++#define PT7C4338_CTRL_STAT_BIT_OSF    0x20	/*Oscillator Stop Flag*/
++#define PT7C4338_CTRL_STAT_BIT_OUT    0x80	/*Output Level Control*/
++
++static const struct i2c_device_id pt7c4338_id[] = {
++	{ "pt7c4338", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, pt7c4338_id);
++
++struct pt7c4338{
++	struct i2c_client *client;
++	struct rtc_device *rtc;
++};
++
++static int pt7c4338_read_time(struct device *dev, struct rtc_time *time)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	int ret;
++	u8 buf[7];
++	u8 year, month, day, hour, minute, second;
++	u8 week, twelve_hr, am_pm;
++
++	ret = i2c_smbus_read_i2c_block_data(client,
++			PT7C4338_REG_SECONDS, 7, buf);
++	if (ret < 0)
++		return ret;
++	if (ret < 7)
++		return -EIO;
++
++	second = buf[0];
++	minute = buf[1];
++	hour = buf[2];
++	week = buf[3];
++	day = buf[4];
++	month = buf[5];
++	year = buf[6];
++
++	/* Extract additional information for AM/PM */
++	twelve_hr = hour & 0x40;
++	am_pm = hour & 0x20;
++
++	/* Write to rtc_time structure */
++	time->tm_sec = bcd2bin(second & 0x7f);
++	time->tm_min = bcd2bin(minute & 0x7f);
++	if (twelve_hr) {
++		/* Convert to 24 hr */
++		if (am_pm)
++			time->tm_hour = bcd2bin(hour & 0x10) + 12;
++		else
++			time->tm_hour = bcd2bin(hour & 0xBF);
++	} else {
++		time->tm_hour = bcd2bin(hour);
++	}
++
++	time->tm_wday = bcd2bin(week & 0x07) - 1;
++	time->tm_mday = bcd2bin(day & 0x3f);
++	time->tm_mon = bcd2bin(month & 0x1F) - 1;
++	/* assume 20YY not 19YY */
++	time->tm_year = bcd2bin(year) + 100;
++
++	return 0;
++}
++
++static int pt7c4338_set_time(struct device *dev, struct rtc_time *time)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	u8 buf[7];
++
++	/* Extract time from rtc_time and load into pt7c4338*/
++	buf[0] = bin2bcd(time->tm_sec);
++	buf[1] = bin2bcd(time->tm_min);
++	buf[2] = bin2bcd(time->tm_hour);
++	buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */
++	buf[4] = bin2bcd(time->tm_mday); /* Date */
++	buf[5] = bin2bcd(time->tm_mon + 1);
++
++	/* assume 20YY not 19YY */
++	if (time->tm_year >= 100)
++		buf[6] = bin2bcd(time->tm_year - 100);
++	else
++		buf[6] = bin2bcd(time->tm_year);
++
++	return i2c_smbus_write_i2c_block_data(client,
++					PT7C4338_REG_SECONDS, 7, buf);
++}
++
++static const struct rtc_class_ops pt7c4338_rtc_ops = {
++	.read_time = pt7c4338_read_time,
++	.set_time = pt7c4338_set_time,
++};
++
++static int pt7c4338_probe(struct i2c_client *client,
++		const struct i2c_device_id *id)
++{
++	struct pt7c4338 *pt7c4338;
++	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
++	int ret;
++
++	pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL);
++	if (!pt7c4338)
++		return -ENOMEM;
++
++	pt7c4338->client = client;
++	i2c_set_clientdata(client, pt7c4338);
++	pt7c4338->rtc = rtc_device_register(client->name, &client->dev,
++					&pt7c4338_rtc_ops, THIS_MODULE);
++	if (IS_ERR(pt7c4338->rtc)) {
++		ret = PTR_ERR(pt7c4338->rtc);
++		dev_err(&client->dev, "unable to register the class device\n");
++		goto out_free;
++	}
++
++	return 0;
++out_free:
++	i2c_set_clientdata(client, NULL);
++	kfree(pt7c4338);
++	return ret;
++}
++
++static int pt7c4338_remove(struct i2c_client *client)
++{
++	struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client);
++
++	rtc_device_unregister(pt7c4338->rtc);
++	i2c_set_clientdata(client, NULL);
++	kfree(pt7c4338);
++	return 0;
++}
++
++static struct i2c_driver pt7c4338_driver = {
++	.driver = {
++		.name = "rtc-pt7c4338",
++		.owner = THIS_MODULE,
++	},
++	.probe = pt7c4338_probe,
++	.remove = pt7c4338_remove,
++	.id_table = pt7c4338_id,
++};
++
++static int __init pt7c4338_init(void)
++{
++	return i2c_add_driver(&pt7c4338_driver);
++}
++
++static void __exit pt7c4338_exit(void)
++{
++	i2c_del_driver(&pt7c4338_driver);
++}
++
++module_init(pt7c4338_init);
++module_exit(pt7c4338_exit);
++
++MODULE_AUTHOR("Priyanka Jain <Priyanka.Jain@freescale.com>");
++MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch b/target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch
new file mode 100644
index 0000000000..e7b32a50bc
--- /dev/null
+++ b/target/linux/generic/patches-3.18/861-04_spi_gpio_implement_spi_delay.patch
@@ -0,0 +1,58 @@
+Implement the SPI-GPIO delay function for busses that need speed limitation.
+
+--mb
+
+
+
+--- a/drivers/spi/spi-gpio.c
++++ b/drivers/spi/spi-gpio.c
+@@ -21,6 +21,7 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/gpio.h>
++#include <linux/delay.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_gpio.h>
+@@ -73,6 +74,7 @@ struct spi_gpio {
+  *		#define	SPI_MOSI_GPIO	120
+  *		#define	SPI_SCK_GPIO	121
+  *		#define	SPI_N_CHIPSEL	4
++ *		#undef NEED_SPIDELAY
+  *		#include "spi-gpio.c"
+  */
+ 
+@@ -80,6 +82,7 @@ struct spi_gpio {
+ #define DRIVER_NAME	"spi_gpio"
+ 
+ #define GENERIC_BITBANG	/* vs tight inlines */
++#define NEED_SPIDELAY	1
+ 
+ /* all functions referencing these symbols must define pdata */
+ #define SPI_MISO_GPIO	((pdata)->miso)
+@@ -130,12 +133,20 @@ static inline int getmiso(const struct s
+ #undef pdata
+ 
+ /*
+- * NOTE:  this clocks "as fast as we can".  It "should" be a function of the
+- * requested device clock.  Software overhead means we usually have trouble
+- * reaching even one Mbit/sec (except when we can inline bitops), so for now
+- * we'll just assume we never need additional per-bit slowdowns.
++ * NOTE:  to clock "as fast as we can", set spi_device.max_speed_hz
++ * and spi_transfer.speed_hz to 0.
++ * Otherwise this is a function of the requested device clock.
++ * Software overhead means we usually have trouble
++ * reaching even one Mbit/sec (except when we can inline bitops). So on small
++ * embedded devices with fast SPI slaves you usually don't need a delay.
+  */
+-#define spidelay(nsecs)	do {} while (0)
++static inline void spidelay(unsigned nsecs)
++{
++#ifdef NEED_SPIDELAY
++	if (unlikely(nsecs))
++		ndelay(nsecs);
++#endif /* NEED_SPIDELAY */
++}
+ 
+ #include "spi-bitbang-txrx.h"
+ 
diff --git a/target/linux/generic/patches-3.18/862-gpio_spi_driver.patch b/target/linux/generic/patches-3.18/862-gpio_spi_driver.patch
new file mode 100644
index 0000000000..70bf11f8f5
--- /dev/null
+++ b/target/linux/generic/patches-3.18/862-gpio_spi_driver.patch
@@ -0,0 +1,373 @@
+THIS CODE IS DEPRECATED.
+
+Please use the new mainline SPI-GPIO driver, as of 2.6.29.
+
+--mb
+
+
+
+---
+ drivers/spi/Kconfig              |    9 +
+ drivers/spi/Makefile             |    1 
+ drivers/spi/spi_gpio_old.c       |  251 +++++++++++++++++++++++++++++++++++++++
+ include/linux/spi/spi_gpio_old.h |   73 +++++++++++
+ 4 files changed, 334 insertions(+)
+
+--- /dev/null
++++ b/include/linux/spi/spi_gpio_old.h
+@@ -0,0 +1,73 @@
++/*
++ * spi_gpio interface to platform code
++ *
++ * Copyright (c) 2008 Piotr Skamruk
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * 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.
++ */
++#ifndef _LINUX_SPI_SPI_GPIO
++#define _LINUX_SPI_SPI_GPIO
++
++#include <linux/types.h>
++#include <linux/spi/spi.h>
++
++
++/**
++ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
++ *
++ * This structure holds information about a GPIO-based SPI device.
++ *
++ * @pin_clk: The GPIO pin number of the CLOCK pin.
++ *
++ * @pin_miso: The GPIO pin number of the MISO pin.
++ *
++ * @pin_mosi: The GPIO pin number of the MOSI pin.
++ *
++ * @pin_cs: The GPIO pin number of the CHIPSELECT pin.
++ *
++ * @cs_activelow: If true, the chip is selected when the CS line is low.
++ *
++ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
++ *                Note that doing no delay is not standards compliant,
++ *                but it might be needed to speed up transfers on some
++ *                slow embedded machines.
++ *
++ * @boardinfo_setup: This callback is called after the
++ *                   SPI master device was registered, but before the
++ *                   device is registered.
++ * @boardinfo_setup_data: Data argument passed to boardinfo_setup().
++ */
++struct spi_gpio_platform_data {
++	unsigned int pin_clk;
++	unsigned int pin_miso;
++	unsigned int pin_mosi;
++	unsigned int pin_cs;
++	bool cs_activelow;
++	bool no_spi_delay;
++	int (*boardinfo_setup)(struct spi_board_info *bi,
++			       struct spi_master *master,
++			       void *data);
++	void *boardinfo_setup_data;
++};
++
++/**
++ * SPI_GPIO_PLATDEV_NAME - The platform device name string.
++ *
++ * The name string that has to be used for platform_device_alloc
++ * when allocating a spi-gpio device.
++ */
++#define SPI_GPIO_PLATDEV_NAME	"spi-gpio"
++
++/**
++ * spi_gpio_next_id - Get another platform device ID number.
++ *
++ * This returns the next platform device ID number that has to be used
++ * for platform_device_alloc. The ID is opaque and should not be used for
++ * anything else.
++ */
++int spi_gpio_next_id(void);
++
++#endif /* _LINUX_SPI_SPI_GPIO */
+--- /dev/null
++++ b/drivers/spi/spi_gpio_old.c
+@@ -0,0 +1,251 @@
++/*
++ * Bitbanging SPI bus driver using GPIO API
++ *
++ * Copyright (c) 2008 Piotr Skamruk
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * based on spi_s3c2410_gpio.c
++ *   Copyright (c) 2006 Ben Dooks
++ *   Copyright (c) 2006 Simtec Electronics
++ * and on i2c-gpio.c
++ *   Copyright (C) 2007 Atmel Corporation
++ *
++ * 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/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/gpio.h>
++#include <asm/atomic.h>
++
++
++struct spi_gpio {
++	struct spi_bitbang bitbang;
++	struct spi_gpio_platform_data *info;
++	struct platform_device *pdev;
++	struct spi_board_info bi;
++};
++
++
++static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
++{
++	return dev->controller_data;
++}
++
++static inline void setsck(struct spi_device *dev, int val)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
++}
++
++static inline void setmosi(struct spi_device *dev, int val)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
++}
++
++static inline u32 getmiso(struct spi_device *dev)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
++}
++
++static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++
++	if (!sp->info->no_spi_delay)
++		ndelay(nsecs);
++}
++
++#define spidelay(nsecs) do {					\
++	/* Steal the spi_device pointer from our caller.	\
++	 * The bitbang-API should probably get fixed here... */	\
++	do_spidelay(spi, nsecs);				\
++  } while (0)
++
++#define EXPAND_BITBANG_TXRX
++#include "spi-bitbang-txrx.h"
++
++static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
++}
++
++static void spi_gpio_chipselect(struct spi_device *dev, int on)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++
++	if (sp->info->cs_activelow)
++		on = !on;
++	gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
++}
++
++static int spi_gpio_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct spi_gpio_platform_data *pdata;
++	struct spi_gpio *sp;
++	struct spi_device *spidev;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata)
++		return -ENXIO;
++
++	err = -ENOMEM;
++	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
++	if (!master)
++		goto err_alloc_master;
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++	sp->info = pdata;
++
++	err = gpio_request(pdata->pin_clk, "spi_clock");
++	if (err)
++		goto err_request_clk;
++	err = gpio_request(pdata->pin_mosi, "spi_mosi");
++	if (err)
++		goto err_request_mosi;
++	err = gpio_request(pdata->pin_miso, "spi_miso");
++	if (err)
++		goto err_request_miso;
++	err = gpio_request(pdata->pin_cs, "spi_cs");
++	if (err)
++		goto err_request_cs;
++
++	sp->bitbang.master = spi_master_get(master);
++	sp->bitbang.master->bus_num = -1;
++	sp->bitbang.master->num_chipselect = 1;
++	sp->bitbang.chipselect = spi_gpio_chipselect;
++	sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
++	sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
++	sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
++	sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
++
++	gpio_direction_output(pdata->pin_clk, 0);
++	gpio_direction_output(pdata->pin_mosi, 0);
++	gpio_direction_output(pdata->pin_cs,
++			      pdata->cs_activelow ? 1 : 0);
++	gpio_direction_input(pdata->pin_miso);
++
++	err = spi_bitbang_start(&sp->bitbang);
++	if (err)
++		goto err_no_bitbang;
++	err = pdata->boardinfo_setup(&sp->bi, master,
++				     pdata->boardinfo_setup_data);
++	if (err)
++		goto err_bi_setup;
++	sp->bi.controller_data = sp;
++	spidev = spi_new_device(master, &sp->bi);
++	if (!spidev)
++		goto err_new_dev;
++
++	return 0;
++
++err_new_dev:
++err_bi_setup:
++	spi_bitbang_stop(&sp->bitbang);
++err_no_bitbang:
++	spi_master_put(sp->bitbang.master);
++	gpio_free(pdata->pin_cs);
++err_request_cs:
++	gpio_free(pdata->pin_miso);
++err_request_miso:
++	gpio_free(pdata->pin_mosi);
++err_request_mosi:
++	gpio_free(pdata->pin_clk);
++err_request_clk:
++	kfree(master);
++
++err_alloc_master:
++	return err;
++}
++
++static int spi_gpio_remove(struct platform_device *pdev)
++{
++	struct spi_gpio *sp;
++	struct spi_gpio_platform_data *pdata;
++
++	pdata = pdev->dev.platform_data;
++	sp = platform_get_drvdata(pdev);
++
++	gpio_free(pdata->pin_clk);
++	gpio_free(pdata->pin_mosi);
++	gpio_free(pdata->pin_miso);
++	gpio_free(pdata->pin_cs);
++	spi_bitbang_stop(&sp->bitbang);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++static struct platform_driver spi_gpio_driver = {
++	.driver		= {
++		.name	= SPI_GPIO_PLATDEV_NAME,
++		.owner	= THIS_MODULE,
++	},
++	.probe		= spi_gpio_probe,
++	.remove		= spi_gpio_remove,
++};
++
++int spi_gpio_next_id(void)
++{
++	static atomic_t counter = ATOMIC_INIT(-1);
++
++	return atomic_inc_return(&counter);
++}
++EXPORT_SYMBOL(spi_gpio_next_id);
++
++static int __init spi_gpio_init(void)
++{
++	int err;
++
++	err = platform_driver_register(&spi_gpio_driver);
++	if (err)
++		printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
++
++	return err;
++}
++module_init(spi_gpio_init);
++
++static void __exit spi_gpio_exit(void)
++{
++	platform_driver_unregister(&spi_gpio_driver);
++}
++module_exit(spi_gpio_exit);
++
++MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
++MODULE_AUTHOR("Michael Buesch");
++MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver");
++MODULE_LICENSE("GPL v2");
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -225,6 +225,15 @@ config SPI_GPIO
+ 	  GPIO operations, you should be able to leverage that for better
+ 	  speed with a custom version of this driver; see the source code.
+ 
++config SPI_GPIO_OLD
++	tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)"
++	depends on SPI_MASTER && GPIOLIB
++	select SPI_BITBANG
++	help
++	  This code is deprecated. Please use the new mainline SPI-GPIO driver.
++
++	  If unsure, say N.
++
+ config SPI_IMX
+ 	tristate "Freescale i.MX SPI controllers"
+ 	depends on ARCH_MXC || COMPILE_TEST
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-li
+ obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o
+ obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o
+ obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o
++obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o
+ obj-$(CONFIG_SPI_IMX)			+= spi-imx.o
+ obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
+ obj-$(CONFIG_SPI_MPC512x_PSC)		+= spi-mpc512x-psc.o
diff --git a/target/linux/generic/patches-3.18/863-gpiommc.patch b/target/linux/generic/patches-3.18/863-gpiommc.patch
new file mode 100644
index 0000000000..3ed4d34fc6
--- /dev/null
+++ b/target/linux/generic/patches-3.18/863-gpiommc.patch
@@ -0,0 +1,844 @@
+--- /dev/null
++++ b/drivers/mmc/host/gpiommc.c
+@@ -0,0 +1,609 @@
++/*
++ * Driver an MMC/SD card on a bitbanging GPIO SPI bus.
++ * This module hooks up the mmc_spi and spi_gpio modules and also
++ * provides a configfs interface.
++ *
++ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/module.h>
++#include <linux/mmc/gpiommc.h>
++#include <linux/platform_device.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/configfs.h>
++#include <linux/gpio.h>
++#include <asm/atomic.h>
++
++
++#define PFX				"gpio-mmc: "
++
++
++struct gpiommc_device {
++	struct platform_device *pdev;
++	struct platform_device *spi_pdev;
++	struct spi_board_info boardinfo;
++};
++
++
++MODULE_DESCRIPTION("GPIO based MMC driver");
++MODULE_AUTHOR("Michael Buesch");
++MODULE_LICENSE("GPL");
++
++
++static int gpiommc_boardinfo_setup(struct spi_board_info *bi,
++				   struct spi_master *master,
++				   void *data)
++{
++	struct gpiommc_device *d = data;
++	struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
++
++	/* Bind the SPI master to the MMC-SPI host driver. */
++	strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias));
++
++	bi->max_speed_hz = pdata->max_bus_speed;
++	bi->bus_num = master->bus_num;
++	bi->mode = pdata->mode;
++
++	return 0;
++}
++
++static int gpiommc_probe(struct platform_device *pdev)
++{
++	struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data;
++	struct spi_gpio_platform_data spi_pdata;
++	struct gpiommc_device *d;
++	int err;
++
++	err = -ENXIO;
++	if (!mmc_pdata)
++		goto error;
++
++#ifdef CONFIG_MMC_SPI_MODULE
++	err = request_module("mmc_spi");
++	if (err) {
++		printk(KERN_WARNING PFX
++		       "Failed to request mmc_spi module.\n");
++	}
++#endif /* CONFIG_MMC_SPI_MODULE */
++
++	/* Allocate the GPIO-MMC device */
++	err = -ENOMEM;
++	d = kzalloc(sizeof(*d), GFP_KERNEL);
++	if (!d)
++		goto error;
++	d->pdev = pdev;
++
++	/* Create the SPI-GPIO device */
++	d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME,
++					    spi_gpio_next_id());
++	if (!d->spi_pdev)
++		goto err_free_d;
++
++	memset(&spi_pdata, 0, sizeof(spi_pdata));
++	spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk;
++	spi_pdata.pin_miso = mmc_pdata->pins.gpio_do;
++	spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di;
++	spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs;
++	spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow;
++	spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay;
++	spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup;
++	spi_pdata.boardinfo_setup_data = d;
++
++	err = platform_device_add_data(d->spi_pdev, &spi_pdata,
++				       sizeof(spi_pdata));
++	if (err)
++		goto err_free_pdev;
++	err = platform_device_add(d->spi_pdev);
++	if (err)
++		goto err_free_pdata;
++	platform_set_drvdata(pdev, d);
++
++	printk(KERN_INFO PFX "MMC-Card \"%s\" "
++	       "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n",
++	       mmc_pdata->name, mmc_pdata->pins.gpio_di,
++	       mmc_pdata->pins.gpio_do,
++	       mmc_pdata->pins.gpio_clk,
++	       mmc_pdata->pins.gpio_cs);
++
++	return 0;
++
++err_free_pdata:
++	kfree(d->spi_pdev->dev.platform_data);
++	d->spi_pdev->dev.platform_data = NULL;
++err_free_pdev:
++	platform_device_put(d->spi_pdev);
++err_free_d:
++	kfree(d);
++error:
++	return err;
++}
++
++static int gpiommc_remove(struct platform_device *pdev)
++{
++	struct gpiommc_device *d = platform_get_drvdata(pdev);
++	struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
++
++	platform_device_unregister(d->spi_pdev);
++	printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n",
++	       pdata->name);
++	platform_device_put(d->spi_pdev);
++
++	return 0;
++}
++
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++
++/* A device that was created through configfs */
++struct gpiommc_configfs_device {
++	struct config_item item;
++	/* The platform device, after registration. */
++	struct platform_device *pdev;
++	/* The configuration */
++	struct gpiommc_platform_data pdata;
++};
++
++#define GPIO_INVALID	-1
++
++static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev)
++{
++	return (dev->pdev != NULL);
++}
++
++static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item)
++{
++	return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL;
++}
++
++static struct configfs_attribute gpiommc_attr_DI = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_data_in",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_DO = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_data_out",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CLK = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_clock",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CS = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_chipselect",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CS_activelow = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_chipselect_activelow",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_spimode = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "spi_mode",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_spidelay = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "spi_delay",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_max_bus_speed = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "max_bus_speed",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_register = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "register",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute *gpiommc_config_attrs[] = {
++	&gpiommc_attr_DI,
++	&gpiommc_attr_DO,
++	&gpiommc_attr_CLK,
++	&gpiommc_attr_CS,
++	&gpiommc_attr_CS_activelow,
++	&gpiommc_attr_spimode,
++	&gpiommc_attr_spidelay,
++	&gpiommc_attr_max_bus_speed,
++	&gpiommc_attr_register,
++	NULL,
++};
++
++static ssize_t gpiommc_config_attr_show(struct config_item *item,
++					struct configfs_attribute *attr,
++					char *page)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++	ssize_t count = 0;
++	unsigned int gpio;
++	int err = 0;
++
++	if (attr == &gpiommc_attr_DI) {
++		gpio = dev->pdata.pins.gpio_di;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_DO) {
++		gpio = dev->pdata.pins.gpio_do;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CLK) {
++		gpio = dev->pdata.pins.gpio_clk;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS) {
++		gpio = dev->pdata.pins.gpio_cs;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS_activelow) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.pins.cs_activelow);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spimode) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.mode);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spidelay) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 !dev->pdata.no_spi_delay);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_max_bus_speed) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.max_bus_speed);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_register) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 gpiommc_is_registered(dev));
++		goto out;
++	}
++	WARN_ON(1);
++	err = -ENOSYS;
++out:
++	return err ? err : count;
++}
++
++static int gpiommc_do_register(struct gpiommc_configfs_device *dev,
++			       const char *name)
++{
++	int err;
++
++	if (gpiommc_is_registered(dev))
++		return 0;
++
++	if (!gpio_is_valid(dev->pdata.pins.gpio_di) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_do) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_clk) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_cs)) {
++		printk(KERN_ERR PFX
++		       "configfs: Invalid GPIO pin number(s)\n");
++		return -EINVAL;
++	}
++
++	strlcpy(dev->pdata.name, name,
++		sizeof(dev->pdata.name));
++
++	dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME,
++					  gpiommc_next_id());
++	if (!dev->pdev)
++		return -ENOMEM;
++	err = platform_device_add_data(dev->pdev, &dev->pdata,
++				       sizeof(dev->pdata));
++	if (err) {
++		platform_device_put(dev->pdev);
++		return err;
++	}
++	err = platform_device_add(dev->pdev);
++	if (err) {
++		platform_device_put(dev->pdev);
++		return err;
++	}
++
++	return 0;
++}
++
++static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev)
++{
++	if (!gpiommc_is_registered(dev))
++		return;
++
++	platform_device_unregister(dev->pdev);
++	dev->pdev = NULL;
++}
++
++static ssize_t gpiommc_config_attr_store(struct config_item *item,
++					 struct configfs_attribute *attr,
++					 const char *page, size_t count)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++	int err = -EINVAL;
++	unsigned long data;
++
++	if (attr == &gpiommc_attr_register) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data == 1)
++			err = gpiommc_do_register(dev, item->ci_name);
++		if (data == 0) {
++			gpiommc_do_unregister(dev);
++			err = 0;
++		}
++		goto out;
++	}
++
++	if (gpiommc_is_registered(dev)) {
++		/* The rest of the config parameters can only be set
++		 * as long as the device is not registered, yet. */
++		err = -EBUSY;
++		goto out;
++	}
++
++	if (attr == &gpiommc_attr_DI) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_di = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_DO) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_do = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CLK) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_clk = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_cs = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS_activelow) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data != 0 && data != 1)
++			goto out;
++		dev->pdata.pins.cs_activelow = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spimode) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		switch (data) {
++		case 0:
++			dev->pdata.mode = SPI_MODE_0;
++			break;
++		case 1:
++			dev->pdata.mode = SPI_MODE_1;
++			break;
++		case 2:
++			dev->pdata.mode = SPI_MODE_2;
++			break;
++		case 3:
++			dev->pdata.mode = SPI_MODE_3;
++			break;
++		default:
++			goto out;
++		}
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spidelay) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data != 0 && data != 1)
++			goto out;
++		dev->pdata.no_spi_delay = !data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_max_bus_speed) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data > UINT_MAX)
++			goto out;
++		dev->pdata.max_bus_speed = data;
++		err = 0;
++		goto out;
++	}
++	WARN_ON(1);
++	err = -ENOSYS;
++out:
++	return err ? err : count;
++}
++
++static void gpiommc_config_item_release(struct config_item *item)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++
++	kfree(dev);
++}
++
++static struct configfs_item_operations gpiommc_config_item_ops = {
++	.release		= gpiommc_config_item_release,
++	.show_attribute		= gpiommc_config_attr_show,
++	.store_attribute	= gpiommc_config_attr_store,
++};
++
++static struct config_item_type gpiommc_dev_ci_type = {
++	.ct_item_ops	= &gpiommc_config_item_ops,
++	.ct_attrs	= gpiommc_config_attrs,
++	.ct_owner	= THIS_MODULE,
++};
++
++static struct config_item *gpiommc_make_item(struct config_group *group,
++					     const char *name)
++{
++	struct gpiommc_configfs_device *dev;
++
++	if (strlen(name) > GPIOMMC_MAX_NAMELEN) {
++		printk(KERN_ERR PFX "configfs: device name too long\n");
++		return NULL;
++	}
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++	if (!dev)
++		return NULL;
++
++	config_item_init_type_name(&dev->item, name,
++				   &gpiommc_dev_ci_type);
++
++	/* Assign default configuration */
++	dev->pdata.pins.gpio_di = GPIO_INVALID;
++	dev->pdata.pins.gpio_do = GPIO_INVALID;
++	dev->pdata.pins.gpio_clk = GPIO_INVALID;
++	dev->pdata.pins.gpio_cs = GPIO_INVALID;
++	dev->pdata.pins.cs_activelow = 1;
++	dev->pdata.mode = SPI_MODE_0;
++	dev->pdata.no_spi_delay = 0;
++	dev->pdata.max_bus_speed = 5000000; /* 5 MHz */
++
++	return &(dev->item);
++}
++
++static void gpiommc_drop_item(struct config_group *group,
++			      struct config_item *item)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++
++	gpiommc_do_unregister(dev);
++	kfree(dev);
++}
++
++static struct configfs_group_operations gpiommc_ct_group_ops = {
++	.make_item	= gpiommc_make_item,
++	.drop_item	= gpiommc_drop_item,
++};
++
++static struct config_item_type gpiommc_ci_type = {
++	.ct_group_ops	= &gpiommc_ct_group_ops,
++	.ct_owner	= THIS_MODULE,
++};
++
++static struct configfs_subsystem gpiommc_subsys = {
++	.su_group = {
++		.cg_item = {
++			.ci_namebuf = GPIOMMC_PLATDEV_NAME,
++			.ci_type = &gpiommc_ci_type,
++		},
++	},
++	.su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex),
++};
++
++#endif /* CONFIG_GPIOMMC_CONFIGFS */
++
++static struct platform_driver gpiommc_plat_driver = {
++	.probe	= gpiommc_probe,
++	.remove	= gpiommc_remove,
++	.driver	= {
++		.name	= GPIOMMC_PLATDEV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++int gpiommc_next_id(void)
++{
++	static atomic_t counter = ATOMIC_INIT(-1);
++
++	return atomic_inc_return(&counter);
++}
++EXPORT_SYMBOL(gpiommc_next_id);
++
++static int __init gpiommc_modinit(void)
++{
++	int err;
++
++	err = platform_driver_register(&gpiommc_plat_driver);
++	if (err)
++		return err;
++
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++	config_group_init(&gpiommc_subsys.su_group);
++	err = configfs_register_subsystem(&gpiommc_subsys);
++	if (err) {
++		platform_driver_unregister(&gpiommc_plat_driver);
++		return err;
++	}
++#endif /* CONFIG_GPIOMMC_CONFIGFS */
++
++	return 0;
++}
++module_init(gpiommc_modinit);
++
++static void __exit gpiommc_modexit(void)
++{
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++	configfs_unregister_subsystem(&gpiommc_subsys);
++#endif
++	platform_driver_unregister(&gpiommc_plat_driver);
++}
++module_exit(gpiommc_modexit);
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -534,6 +534,31 @@ config MMC_SDHI
+ 	  This provides support for the SDHI SD/SDIO controller found in
+ 	  SuperH and ARM SH-Mobile SoCs
+ 
++config GPIOMMC
++	tristate "MMC/SD over GPIO-based SPI"
++	depends on MMC && MMC_SPI && SPI_GPIO_OLD
++	help
++	  This driver hooks up the mmc_spi and spi_gpio modules so that
++	  MMC/SD cards can be used on a GPIO based bus by bitbanging
++	  the SPI protocol in software.
++
++	  This driver provides a configfs interface to dynamically create
++	  and destroy GPIO-based MMC/SD card devices. It also provides
++	  a platform device interface API.
++	  See Documentation/gpiommc.txt for details.
++
++	  The module will be called gpiommc.
++
++	  If unsure, say N.
++
++config GPIOMMC_CONFIGFS
++	bool
++	depends on GPIOMMC && CONFIGFS_FS
++	default y
++	help
++	  This option automatically enables configfs support for gpiommc
++	  if configfs is available.
++
+ config MMC_CB710
+ 	tristate "ENE CB710 MMC/SD Interface support"
+ 	depends on PCI
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -40,6 +40,7 @@ tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_S
+ obj-$(CONFIG_MMC_SDHI)		+= sh_mobile_sdhi.o
+ obj-$(CONFIG_MMC_CB710)		+= cb710-mmc.o
+ obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
++obj-$(CONFIG_GPIOMMC)		+= gpiommc.o
+ obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
+ obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
+ obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
+--- /dev/null
++++ b/include/linux/mmc/gpiommc.h
+@@ -0,0 +1,71 @@
++/*
++ * Device driver for MMC/SD cards driven over a GPIO bus.
++ *
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * Licensed under the GNU/GPL version 2.
++ */
++#ifndef LINUX_GPIOMMC_H_
++#define LINUX_GPIOMMC_H_
++
++#include <linux/types.h>
++
++
++#define GPIOMMC_MAX_NAMELEN		15
++#define GPIOMMC_MAX_NAMELEN_STR		__stringify(GPIOMMC_MAX_NAMELEN)
++
++/**
++ * struct gpiommc_pins - Hardware pin assignments
++ *
++ * @gpio_di: The GPIO number of the DATA IN pin
++ * @gpio_do: The GPIO number of the DATA OUT pin
++ * @gpio_clk: The GPIO number of the CLOCK pin
++ * @gpio_cs: The GPIO number of the CHIPSELECT pin
++ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low.
++ */
++struct gpiommc_pins {
++	unsigned int gpio_di;
++	unsigned int gpio_do;
++	unsigned int gpio_clk;
++	unsigned int gpio_cs;
++	bool cs_activelow;
++};
++
++/**
++ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device.
++ *
++ * @name: The unique name string of the device.
++ * @pins: The hardware pin assignments.
++ * @mode: The hardware mode. This is either SPI_MODE_0,
++ *        SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation.
++ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code.
++ *                This is not standards compliant, but may be required for some
++ *                embedded machines to gain reasonable speed.
++ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz.
++ */
++struct gpiommc_platform_data {
++	char name[GPIOMMC_MAX_NAMELEN + 1];
++	struct gpiommc_pins pins;
++	u8 mode;
++	bool no_spi_delay;
++	unsigned int max_bus_speed;
++};
++
++/**
++ * GPIOMMC_PLATDEV_NAME - The platform device name string.
++ *
++ * The name string that has to be used for platform_device_alloc
++ * when allocating a gpiommc device.
++ */
++#define GPIOMMC_PLATDEV_NAME	"gpiommc"
++
++/**
++ * gpiommc_next_id - Get another platform device ID number.
++ *
++ * This returns the next platform device ID number that has to be used
++ * for platform_device_alloc. The ID is opaque and should not be used for
++ * anything else.
++ */
++int gpiommc_next_id(void);
++
++#endif /* LINUX_GPIOMMC_H_ */
+--- /dev/null
++++ b/Documentation/gpiommc.txt
+@@ -0,0 +1,97 @@
++GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus
++================================================================
++
++The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an
++MMC or SD card on GPIO pins.
++
++Two interfaces for registering a new MMC/SD card device are provided:
++A static platform-device based mechanism and a dynamic configfs based interface.
++
++
++Registering devices via platform-device
++=======================================
++
++The platform-device interface is used for registering MMC/SD devices that are
++part of the hardware platform. This is most useful only for embedded machines
++with MMC/SD devices statically connected to the platform GPIO bus.
++
++The data structures are declared in <linux/mmc/gpiommc.h>.
++
++To register a new device, define an instance of struct gpiommc_platform_data.
++This structure holds any information about how the device is hooked up to the
++GPIO pins and what hardware modes the device supports. See the docbook-style
++documentation in the header file for more information on the struct fields.
++
++Then allocate a new instance of a platform device by doing:
++
++	pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id());
++
++This will allocate the platform device data structures and hook it up to the
++gpiommc driver.
++Then add the gpiommc_platform_data to the platform device.
++
++	err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data));
++
++You may free the local instance of struct gpiommc_platform_data now. (So the
++struct may be allocated on the stack, too).
++Now simply register the platform device.
++
++	err = platform_device_add(pdev);
++
++Done. The gpiommc probe routine will be invoked now and you should see a kernel
++log message for the added device.
++
++
++Registering devices via configfs
++================================
++
++MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example
++selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded
++hardware are a common situation.
++So we provide a dynamic interface to conveniently handle adding and removing
++devices from userspace, without the need to recompile the kernel.
++
++The "gpiommc" subdirectory at the configfs mountpoint is used for handling
++the dynamic configuration.
++
++To create a new device, it must first be allocated with mkdir.
++The following command will allocate a device named "my_mmc":
++	mkdir /config/gpiommc/my_mmc
++
++There are several configuration files available in the new
++/config/gpiommc/my_mmc/ directory:
++
++gpio_data_in			= The SPI data-IN GPIO pin number.
++gpio_data_out			= The SPI data-OUT GPIO pin number.
++gpio_clock			= The SPI Clock GPIO pin number.
++gpio_chipselect			= The SPI Chipselect GPIO pin number.
++gpio_chipselect_activelow	= Boolean. If 0, Chipselect is active-HIGH.
++				  If 1, Chipselect is active-LOW.
++spi_mode			= The SPI data mode. Can be 0-3.
++spi_delay			= Enable all delays in the lowlevel bitbanging.
++max_bus_speed			= The maximum SPI bus speed. In Hertz.
++
++register			= Not a configuration parameter.
++				  Used to register the configured card
++				  with the kernel.
++
++The device must first get configured and then registered by writing "1" to
++the "register" file.
++The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock"
++and "gpio_chipselect" are essential and _must_ be configured before writing
++"1" to the "register" file. The registration will fail, otherwise.
++
++The default values for the other parameters are:
++gpio_chipselect_activelow	= 1		(CS active-LOW)
++spi_mode			= 0		(SPI_MODE_0)
++spi_delay			= 1		(enabled)
++max_bus_speed			= 5000000	(5 Mhz)
++
++Configuration values can not be changed after registration. To unregister
++the device, write a "0" to the "register" file. The configuration can be
++changed again after unregistering.
++
++To completely remove the device, simply rmdir the directory
++(/config/gpiommc/my_mmc in this example).
++There's no need to first unregister the device before removing it. That will
++be done automatically.
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4289,6 +4289,11 @@ T:	git git://linuxtv.org/anttip/media_tr
+ S:	Maintained
+ F:	drivers/media/usb/hackrf/
+ 
++GPIOMMC DRIVER
++P:	Michael Buesch
++M:	mb@bu3sch.de
++S:	Maintained
++
+ HARDWARE MONITORING
+ M:	Jean Delvare <jdelvare@suse.de>
+ M:	Guenter Roeck <linux@roeck-us.net>
diff --git a/target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch b/target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch
new file mode 100644
index 0000000000..92815d91f4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/864-gpiommc_configfs_locking.patch
@@ -0,0 +1,58 @@
+The gpiommc configfs context structure needs locking, as configfs
+does not lock access between files.
+
+--- a/drivers/mmc/host/gpiommc.c
++++ b/drivers/mmc/host/gpiommc.c
+@@ -144,6 +144,8 @@ struct gpiommc_configfs_device {
+ 	struct platform_device *pdev;
+ 	/* The configuration */
+ 	struct gpiommc_platform_data pdata;
++	/* Mutex to protect this structure */
++	struct mutex mutex;
+ };
+ 
+ #define GPIO_INVALID	-1
+@@ -234,6 +236,8 @@ static ssize_t gpiommc_config_attr_show(
+ 	unsigned int gpio;
+ 	int err = 0;
+ 
++	mutex_lock(&dev->mutex);
++
+ 	if (attr == &gpiommc_attr_DI) {
+ 		gpio = dev->pdata.pins.gpio_di;
+ 		if (gpio == GPIO_INVALID)
+@@ -294,6 +298,8 @@ static ssize_t gpiommc_config_attr_show(
+ 	WARN_ON(1);
+ 	err = -ENOSYS;
+ out:
++	mutex_unlock(&dev->mutex);
++
+ 	return err ? err : count;
+ }
+ 
+@@ -353,6 +359,8 @@ static ssize_t gpiommc_config_attr_store
+ 	int err = -EINVAL;
+ 	unsigned long data;
+ 
++	mutex_lock(&dev->mutex);
++
+ 	if (attr == &gpiommc_attr_register) {
+ 		err = kstrtoul(page, 10, &data);
+ 		if (err)
+@@ -478,6 +486,8 @@ static ssize_t gpiommc_config_attr_store
+ 	WARN_ON(1);
+ 	err = -ENOSYS;
+ out:
++	mutex_unlock(&dev->mutex);
++
+ 	return err ? err : count;
+ }
+ 
+@@ -514,6 +524,7 @@ static struct config_item *gpiommc_make_
+ 	if (!dev)
+ 		return NULL;
+ 
++	mutex_init(&dev->mutex);
+ 	config_item_init_type_name(&dev->item, name,
+ 				   &gpiommc_dev_ci_type);
+ 
diff --git a/target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch b/target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch
new file mode 100644
index 0000000000..3a37c951ec
--- /dev/null
+++ b/target/linux/generic/patches-3.18/870-hifn795x_byteswap.patch
@@ -0,0 +1,17 @@
+--- a/drivers/crypto/hifn_795x.c
++++ b/drivers/crypto/hifn_795x.c
+@@ -682,12 +682,12 @@ static inline u32 hifn_read_1(struct hif
+ 
+ static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
+ {
+-	writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg);
++	writel(val, dev->bar[0] + reg);
+ }
+ 
+ static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
+ {
+-	writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg);
++	writel(val, dev->bar[1] + reg);
+ }
+ 
+ static void hifn_wait_puc(struct hifn_device *dev)
diff --git a/target/linux/generic/patches-3.18/880-gateworks_system_controller.patch b/target/linux/generic/patches-3.18/880-gateworks_system_controller.patch
new file mode 100644
index 0000000000..55e95be706
--- /dev/null
+++ b/target/linux/generic/patches-3.18/880-gateworks_system_controller.patch
@@ -0,0 +1,339 @@
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -507,6 +507,15 @@ config SENSORS_G762
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called g762.
+ 
++config SENSORS_GSC
++	tristate "Gateworks System Controller"
++	depends on I2C
++	help
++	  If you say yes here you get support for the Gateworks System Controller.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called gsc.
++
+ config SENSORS_GPIO_FAN
+ 	tristate "GPIO fan"
+ 	depends on GPIOLIB
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -153,6 +153,7 @@ obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l7
+ obj-$(CONFIG_SENSORS_W83L786NG)	+= w83l786ng.o
+ obj-$(CONFIG_SENSORS_WM831X)	+= wm831x-hwmon.o
+ obj-$(CONFIG_SENSORS_WM8350)	+= wm8350-hwmon.o
++obj-$(CONFIG_SENSORS_GSC)	+= gsc.o
+ 
+ obj-$(CONFIG_PMBUS)		+= pmbus/
+ 
+--- /dev/null
++++ b/drivers/hwmon/gsc.c
+@@ -0,0 +1,308 @@
++/*
++ * A hwmon driver for the Gateworks System Controller 
++ * Copyright (C) 2009 Gateworks Corporation
++ *
++ * Author: Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License,
++ * as published by the Free Software Foundation - version 2.
++ */
++
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++
++#define DRV_VERSION "0.2"
++
++enum chips { gsp };
++
++/* AD7418 registers */
++#define GSP_REG_TEMP_IN		0x00
++#define GSP_REG_VIN		0x02
++#define GSP_REG_3P3		0x05
++#define GSP_REG_BAT		0x08
++#define GSP_REG_5P0		0x0b
++#define GSP_REG_CORE		0x0e
++#define GSP_REG_CPU1		0x11
++#define GSP_REG_CPU2		0x14
++#define GSP_REG_DRAM		0x17
++#define GSP_REG_EXT_BAT		0x1a
++#define GSP_REG_IO1		0x1d
++#define GSP_REG_IO2 		0x20
++#define GSP_REG_PCIE		0x23
++#define GSP_REG_CURRENT		0x26
++#define GSP_FAN_0		0x2C
++#define GSP_FAN_1		0x2E
++#define GSP_FAN_2		0x30
++#define GSP_FAN_3		0x32
++#define GSP_FAN_4		0x34
++#define GSP_FAN_5		0x36
++
++struct gsp_sensor_info {
++	const char* name;
++	int reg;
++};
++
++static const struct gsp_sensor_info gsp_sensors[] = {
++	{"temp", GSP_REG_TEMP_IN},
++	{"vin", GSP_REG_VIN},
++	{"3p3", GSP_REG_3P3},
++	{"bat", GSP_REG_BAT},
++	{"5p0", GSP_REG_5P0},
++	{"core", GSP_REG_CORE},
++	{"cpu1", GSP_REG_CPU1},
++	{"cpu2", GSP_REG_CPU2},
++	{"dram", GSP_REG_DRAM},
++	{"ext_bat", GSP_REG_EXT_BAT},
++	{"io1", GSP_REG_IO1},
++	{"io2", GSP_REG_IO2},
++	{"pci2", GSP_REG_PCIE},
++	{"current", GSP_REG_CURRENT},
++	{"fan_point0", GSP_FAN_0},
++	{"fan_point1", GSP_FAN_1},
++	{"fan_point2", GSP_FAN_2},
++	{"fan_point3", GSP_FAN_3},
++	{"fan_point4", GSP_FAN_4},
++	{"fan_point5", GSP_FAN_5},
++};
++
++struct gsp_data {
++	struct device		*hwmon_dev;
++	struct attribute_group	attrs;
++	enum chips		type;
++};
++
++static int gsp_probe(struct i2c_client *client,
++			const struct i2c_device_id *id);
++static int gsp_remove(struct i2c_client *client);
++
++static const struct i2c_device_id gsp_id[] = {
++	{ "gsp", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, gsp_id);
++
++static struct i2c_driver gsp_driver = {
++	.driver = {
++		.name	= "gsp",
++	},
++	.probe		= gsp_probe,
++	.remove		= gsp_remove,
++	.id_table	= gsp_id,
++};
++
++/* All registers are word-sized, except for the configuration registers.
++ * AD7418 uses a high-byte first convention. Do NOT use those functions to
++ * access the configuration registers CONF and CONF2, as they are byte-sized.
++ */
++static inline int gsp_read(struct i2c_client *client, u8 reg)
++{
++	unsigned int adc = 0;
++	if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT)
++	{
++		adc |= i2c_smbus_read_byte_data(client, reg);
++		adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
++		return adc;
++	}
++	else
++	{
++		adc |= i2c_smbus_read_byte_data(client, reg);
++		adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
++		adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16;
++		return adc;
++	}
++}
++
++static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value)
++{
++	i2c_smbus_write_byte_data(client, reg, value & 0xff);
++	i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff));
++	return 1;
++}
++
++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
++			char *buf)
++{
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++	struct i2c_client *client = to_i2c_client(dev);
++	return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg));
++}
++
++static ssize_t show_label(struct device *dev,
++			struct device_attribute *devattr, char *buf)
++{
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++
++	return sprintf(buf, "%s\n", gsp_sensors[attr->index].name);
++}
++
++static ssize_t store_fan(struct device *dev,
++			struct device_attribute *devattr, const char *buf, size_t count)
++{
++	u16 val;
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++	struct i2c_client *client = to_i2c_client(dev);
++	val = simple_strtoul(buf, NULL, 10);
++	gsp_write(client, gsp_sensors[attr->index].reg, val);
++	return count;
++}
++
++static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0);
++
++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1);
++static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1);
++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2);
++static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2);
++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3);
++static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3);
++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4);
++static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4);
++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5);
++static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5);
++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6);
++static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6);
++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7);
++static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7);
++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8);
++static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8);
++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9);
++static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9);
++static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10);
++static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10);
++static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11);
++static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11);
++static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12);
++static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12);
++static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13);
++static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13);
++
++static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14);
++static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15);
++static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16);
++static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17);
++static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18);
++static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19);
++
++static struct attribute *gsp_attributes[] = {
++	&sensor_dev_attr_temp0_input.dev_attr.attr,
++	&sensor_dev_attr_in0_input.dev_attr.attr,
++	&sensor_dev_attr_in1_input.dev_attr.attr,
++	&sensor_dev_attr_in2_input.dev_attr.attr,
++	&sensor_dev_attr_in3_input.dev_attr.attr,
++	&sensor_dev_attr_in4_input.dev_attr.attr,
++	&sensor_dev_attr_in5_input.dev_attr.attr,
++	&sensor_dev_attr_in6_input.dev_attr.attr,
++	&sensor_dev_attr_in7_input.dev_attr.attr,
++	&sensor_dev_attr_in8_input.dev_attr.attr,
++	&sensor_dev_attr_in9_input.dev_attr.attr,
++	&sensor_dev_attr_in10_input.dev_attr.attr,
++	&sensor_dev_attr_in11_input.dev_attr.attr,
++	&sensor_dev_attr_in12_input.dev_attr.attr,
++
++	&sensor_dev_attr_temp0_label.dev_attr.attr,
++	&sensor_dev_attr_in0_label.dev_attr.attr,
++	&sensor_dev_attr_in1_label.dev_attr.attr,
++	&sensor_dev_attr_in2_label.dev_attr.attr,
++	&sensor_dev_attr_in3_label.dev_attr.attr,
++	&sensor_dev_attr_in4_label.dev_attr.attr,
++	&sensor_dev_attr_in5_label.dev_attr.attr,
++	&sensor_dev_attr_in6_label.dev_attr.attr,
++	&sensor_dev_attr_in7_label.dev_attr.attr,
++	&sensor_dev_attr_in8_label.dev_attr.attr,
++	&sensor_dev_attr_in9_label.dev_attr.attr,
++	&sensor_dev_attr_in10_label.dev_attr.attr,
++	&sensor_dev_attr_in11_label.dev_attr.attr,
++	&sensor_dev_attr_in12_label.dev_attr.attr,
++
++	&sensor_dev_attr_fan0_point0.dev_attr.attr,
++	&sensor_dev_attr_fan0_point1.dev_attr.attr,
++	&sensor_dev_attr_fan0_point2.dev_attr.attr,
++	&sensor_dev_attr_fan0_point3.dev_attr.attr,
++	&sensor_dev_attr_fan0_point4.dev_attr.attr,
++	&sensor_dev_attr_fan0_point5.dev_attr.attr,
++	NULL
++};
++
++
++static int gsp_probe(struct i2c_client *client,
++			 const struct i2c_device_id *id)
++{
++	struct i2c_adapter *adapter = client->adapter;
++	struct gsp_data *data;
++	int err;
++
++	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
++					I2C_FUNC_SMBUS_WORD_DATA)) {
++		err = -EOPNOTSUPP;
++		goto exit;
++	}
++
++	if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) {
++		err = -ENOMEM;
++		goto exit;
++	}
++
++	i2c_set_clientdata(client, data);
++
++	data->type = id->driver_data;
++
++	switch (data->type) {
++	case 0:
++		data->attrs.attrs = gsp_attributes;
++		break;
++	}
++
++	dev_info(&client->dev, "%s chip found\n", client->name);
++
++	/* Register sysfs hooks */
++	if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
++		goto exit_free;
++
++	data->hwmon_dev = hwmon_device_register(&client->dev);
++	if (IS_ERR(data->hwmon_dev)) {
++		err = PTR_ERR(data->hwmon_dev);
++		goto exit_remove;
++	}
++
++	return 0;
++
++exit_remove:
++	sysfs_remove_group(&client->dev.kobj, &data->attrs);
++exit_free:
++	kfree(data);
++exit:
++	return err;
++}
++
++static int gsp_remove(struct i2c_client *client)
++{
++	struct gsp_data *data = i2c_get_clientdata(client);
++	hwmon_device_unregister(data->hwmon_dev);
++	sysfs_remove_group(&client->dev.kobj, &data->attrs);
++	kfree(data);
++	return 0;
++}
++
++static int __init gsp_init(void)
++{
++	return i2c_add_driver(&gsp_driver);
++}
++
++static void __exit gsp_exit(void)
++{
++	i2c_del_driver(&gsp_driver);
++}
++
++module_init(gsp_init);
++module_exit(gsp_exit);
++
++MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
++MODULE_DESCRIPTION("GSC HWMON driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
diff --git a/target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch b/target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch
new file mode 100644
index 0000000000..8815e4c644
--- /dev/null
+++ b/target/linux/generic/patches-3.18/890-8250_optional_sysrq.patch
@@ -0,0 +1,24 @@
+--- a/drivers/tty/serial/8250/8250_core.c
++++ b/drivers/tty/serial/8250/8250_core.c
+@@ -16,7 +16,7 @@
+  *  membase is an 'ioremapped' cookie.
+  */
+ 
+-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#if defined(CONFIG_SERIAL_8250_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+ 
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -91,6 +91,10 @@ config SERIAL_8250_CONSOLE
+ 
+ 	  If unsure, say N.
+ 
++config SERIAL_8250_SYSRQ
++	bool "Magic sysrq support on 8250/16550 devices"
++	depends on SERIAL_8250_CONSOLE
++
+ config SERIAL_8250_GSC
+ 	tristate
+ 	depends on SERIAL_8250 && GSC
diff --git a/target/linux/generic/patches-3.18/901-debloat_sock_diag.patch b/target/linux/generic/patches-3.18/901-debloat_sock_diag.patch
new file mode 100644
index 0000000000..99f23a027e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/901-debloat_sock_diag.patch
@@ -0,0 +1,65 @@
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -89,6 +89,9 @@ source "net/netlabel/Kconfig"
+ 
+ endif # if INET
+ 
++config SOCK_DIAG
++	bool
++
+ config NETWORK_SECMARK
+ 	bool "Security Marking"
+ 	help
+--- a/net/core/Makefile
++++ b/net/core/Makefile
+@@ -9,8 +9,9 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
+ 
+ obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
+ 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
+-			sock_diag.o dev_ioctl.o tso.o
++			dev_ioctl.o tso.o
+ 
++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
+ obj-$(CONFIG_XFRM) += flow.o
+ obj-y += net-sysfs.o
+ obj-$(CONFIG_PROC_FS) += net-procfs.o
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -419,6 +419,7 @@ config INET_LRO
+ 
+ config INET_DIAG
+ 	tristate "INET: socket monitoring interface"
++	select SOCK_DIAG
+ 	default y
+ 	---help---
+ 	  Support for INET (TCP, DCCP, etc) socket monitoring interface used by
+--- a/net/unix/Kconfig
++++ b/net/unix/Kconfig
+@@ -22,6 +22,7 @@ config UNIX
+ config UNIX_DIAG
+ 	tristate "UNIX: socket monitoring interface"
+ 	depends on UNIX
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for UNIX socket monitoring interface used by the ss tool.
+--- a/net/netlink/Kconfig
++++ b/net/netlink/Kconfig
+@@ -13,6 +13,7 @@ config NETLINK_MMAP
+ 
+ config NETLINK_DIAG
+ 	tristate "NETLINK: socket monitoring interface"
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for NETLINK socket monitoring interface used by the ss tool.
+--- a/net/packet/Kconfig
++++ b/net/packet/Kconfig
+@@ -18,6 +18,7 @@ config PACKET
+ config PACKET_DIAG
+ 	tristate "Packet: sockets monitoring interface"
+ 	depends on PACKET
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for PF_PACKET sockets monitoring interface used by the ss tool.
diff --git a/target/linux/generic/patches-3.18/902-debloat_proc.patch b/target/linux/generic/patches-3.18/902-debloat_proc.patch
new file mode 100644
index 0000000000..79cecf90d4
--- /dev/null
+++ b/target/linux/generic/patches-3.18/902-debloat_proc.patch
@@ -0,0 +1,341 @@
+--- a/fs/locks.c
++++ b/fs/locks.c
+@@ -2620,6 +2620,8 @@ static const struct file_operations proc
+ 
+ static int __init proc_locks_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("locks", 0, NULL, &proc_locks_operations);
+ 	return 0;
+ }
+--- a/fs/proc/Kconfig
++++ b/fs/proc/Kconfig
+@@ -71,3 +71,8 @@ config PROC_PAGE_MONITOR
+ 	  /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+ 	  /proc/kpagecount, and /proc/kpageflags. Disabling these
+           interfaces will reduce the size of the kernel by approximately 4kb.
++
++config PROC_STRIPPED
++	default n
++	depends on EXPERT
++	bool "Strip non-essential /proc functionality to reduce code size"
+--- a/fs/proc/consoles.c
++++ b/fs/proc/consoles.c
+@@ -106,6 +106,9 @@ static const struct file_operations proc
+ 
+ static int __init proc_consoles_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	proc_create("consoles", 0, NULL, &proc_consoles_operations);
+ 	return 0;
+ }
+--- a/fs/proc/proc_tty.c
++++ b/fs/proc/proc_tty.c
+@@ -143,7 +143,10 @@ static const struct file_operations proc
+ void proc_tty_register_driver(struct tty_driver *driver)
+ {
+ 	struct proc_dir_entry *ent;
+-		
++
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!driver->driver_name || driver->proc_entry ||
+ 	    !driver->ops->proc_fops)
+ 		return;
+@@ -160,6 +163,9 @@ void proc_tty_unregister_driver(struct t
+ {
+ 	struct proc_dir_entry *ent;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ent = driver->proc_entry;
+ 	if (!ent)
+ 		return;
+@@ -174,6 +180,9 @@ void proc_tty_unregister_driver(struct t
+  */
+ void __init proc_tty_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!proc_mkdir("tty", NULL))
+ 		return;
+ 	proc_mkdir("tty/ldisc", NULL);	/* Preserved: it's userspace visible */
+--- a/kernel/exec_domain.c
++++ b/kernel/exec_domain.c
+@@ -176,6 +176,8 @@ static const struct file_operations exec
+ 
+ static int __init proc_execdomains_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
+ 	return 0;
+ }
+--- a/kernel/irq/proc.c
++++ b/kernel/irq/proc.c
+@@ -330,6 +330,9 @@ void register_irq_proc(unsigned int irq,
+ 	static DEFINE_MUTEX(register_lock);
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
+ 		return;
+ 
+@@ -379,6 +382,9 @@ void unregister_irq_proc(unsigned int ir
+ {
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || !desc->dir)
+ 		return;
+ #ifdef CONFIG_SMP
+@@ -414,6 +420,9 @@ void init_irq_proc(void)
+ 	unsigned int irq;
+ 	struct irq_desc *desc;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	/* create /proc/irq */
+ 	root_irq_dir = proc_mkdir("irq", NULL);
+ 	if (!root_irq_dir)
+--- a/kernel/time/timer_list.c
++++ b/kernel/time/timer_list.c
+@@ -362,6 +362,8 @@ static int __init init_timer_list_procfs
+ {
+ 	struct proc_dir_entry *pe;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	pe = proc_create("timer_list", 0444, NULL, &timer_list_fops);
+ 	if (!pe)
+ 		return -ENOMEM;
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -2662,6 +2662,8 @@ static const struct file_operations proc
+ 
+ static int __init proc_vmalloc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
+ 	return 0;
+ }
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -1424,10 +1424,12 @@ static int __init setup_vmstat(void)
+ 	cpu_notifier_register_done();
+ #endif
+ #ifdef CONFIG_PROC_FS
+-	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
+-	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
++		proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
++		proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
++	}
+ 	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
+-	proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
+ #endif
+ 	return 0;
+ }
+--- a/net/8021q/vlanproc.c
++++ b/net/8021q/vlanproc.c
+@@ -127,6 +127,9 @@ void vlan_proc_cleanup(struct net *net)
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (vn->proc_vlan_conf)
+ 		remove_proc_entry(name_conf, vn->proc_vlan_dir);
+ 
+@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
+ 	if (!vn->proc_vlan_dir)
+ 		goto err;
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -2933,6 +2933,8 @@ static __net_initdata struct pernet_oper
+ 
+ static int __init proto_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	return register_pernet_subsys(&proto_net_ops);
+ }
+ 
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2490,10 +2490,12 @@ static const struct file_operations fib_
+ 
+ int __net_init fib_proc_init(struct net *net)
+ {
+-	if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops))
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops))
+ 		goto out1;
+ 
+-	if (!proc_create("fib_triestat", S_IRUGO, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("fib_triestat", S_IRUGO, net->proc_net,
+ 			 &fib_triestat_fops))
+ 		goto out2;
+ 
+@@ -2503,17 +2505,21 @@ int __net_init fib_proc_init(struct net
+ 	return 0;
+ 
+ out3:
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_triestat", net->proc_net);
+ out2:
+-	remove_proc_entry("fib_trie", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_trie", net->proc_net);
+ out1:
+ 	return -ENOMEM;
+ }
+ 
+ void __net_exit fib_proc_exit(struct net *net)
+ {
+-	remove_proc_entry("fib_trie", net->proc_net);
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("fib_trie", net->proc_net);
++		remove_proc_entry("fib_triestat", net->proc_net);
++	}
+ 	remove_proc_entry("route", net->proc_net);
+ }
+ 
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -524,6 +524,9 @@ static __net_initdata struct pernet_oper
+ 
+ int __init ip_misc_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_proc_ops);
+ }
+ 
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -416,6 +416,9 @@ static struct pernet_operations ip_rt_pr
+ 
+ static int __init ip_rt_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_rt_proc_ops);
+ }
+ 
+--- a/ipc/msg.c
++++ b/ipc/msg.c
+@@ -1072,6 +1072,9 @@ void __init msg_init(void)
+ 	printk(KERN_INFO "msgmni has been set to %d\n",
+ 		init_ipc_ns.msg_ctlmni);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ipc_init_proc_interface("sysvipc/msg",
+ 				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
+ 				IPC_MSG_IDS, sysvipc_msg_proc_show);
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -191,6 +191,8 @@ void sem_exit_ns(struct ipc_namespace *n
+ void __init sem_init(void)
+ {
+ 	sem_init_ns(&init_ipc_ns);
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/sem",
+ 				"       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
+ 				IPC_SEM_IDS, sysvipc_sem_proc_show);
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -118,6 +118,8 @@ pure_initcall(ipc_ns_init);
+ 
+ void __init shm_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/shm",
+ #if BITS_PER_LONG <= 32
+ 				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n",
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -161,6 +161,9 @@ void __init ipc_init_proc_interface(cons
+ 	struct proc_dir_entry *pde;
+ 	struct ipc_proc_iface *iface;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ 	if (!iface)
+ 		return;
+--- a/net/core/net-procfs.c
++++ b/net/core/net-procfs.c
+@@ -318,10 +318,12 @@ static int __net_init dev_proc_net_init(
+ 
+ 	if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
+ 		goto out;
+-	if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("softnet_stat", S_IRUGO, net->proc_net,
+ 			 &softnet_seq_fops))
+ 		goto out_dev;
+-	if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
+ 		goto out_softnet;
+ 
+ 	if (wext_proc_init(net))
+@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init(
+ out:
+ 	return rc;
+ out_ptype:
+-	remove_proc_entry("ptype", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("ptype", net->proc_net);
+ out_softnet:
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("softnet_stat", net->proc_net);
+ out_dev:
+ 	remove_proc_entry("dev", net->proc_net);
+ 	goto out;
+@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit
+ {
+ 	wext_proc_exit(net);
+ 
+-	remove_proc_entry("ptype", net->proc_net);
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("ptype", net->proc_net);
++		remove_proc_entry("softnet_stat", net->proc_net);
++	}
+ 	remove_proc_entry("dev", net->proc_net);
+ }
+ 
diff --git a/target/linux/generic/patches-3.18/903-debloat_direct_io.patch b/target/linux/generic/patches-3.18/903-debloat_direct_io.patch
new file mode 100644
index 0000000000..dbb08ca4e7
--- /dev/null
+++ b/target/linux/generic/patches-3.18/903-debloat_direct_io.patch
@@ -0,0 +1,83 @@
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -62,6 +62,11 @@ config FILE_LOCKING
+           for filesystems like NFS and for the flock() system
+           call. Disabling this option saves about 11k.
+ 
++config DIRECT_IO
++	bool "Enable O_DIRECT support" if EXPERT
++	depends on BLOCK
++	default y
++
+ source "fs/notify/Kconfig"
+ 
+ source "fs/quota/Kconfig"
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -14,7 +14,8 @@ obj-y :=	open.o read_write.o file_table.
+ 		stack.o fs_struct.o statfs.o fs_pin.o
+ 
+ ifeq ($(CONFIG_BLOCK),y)
+-obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
++obj-y +=	buffer.o block_dev.o mpage.o
++obj-$(CONFIG_DIRECT_IO) += direct-io.o
+ else
+ obj-y +=	no-block.o
+ endif
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2529,12 +2529,25 @@ enum {
+ 	DIO_ASYNC_EXTEND = 0x04,
+ };
+ 
++#ifdef CONFIG_DIRECT_IO
+ void dio_end_io(struct bio *bio, int error);
+ 
+ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+ 	struct block_device *bdev, struct iov_iter *iter, loff_t offset,
+ 	get_block_t get_block, dio_iodone_t end_io,
+ 	dio_submit_t submit_io,	int flags);
++#else
++static inline void dio_end_io(struct bio *bio, int error)
++{
++}
++static inline ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
++	struct block_device *bdev, struct iov_iter *iter, loff_t offset,
++	get_block_t get_block, dio_iodone_t end_io,
++	dio_submit_t submit_io,	int flags)
++{
++	return -EOPNOTSUPP;
++}
++#endif
+ 
+ static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
+ 		struct inode *inode, struct iov_iter *iter, loff_t offset,
+--- a/fs/fcntl.c
++++ b/fs/fcntl.c
+@@ -52,8 +52,10 @@ static int setfl(int fd, struct file * f
+ 		   arg |= O_NONBLOCK;
+ 
+ 	if (arg & O_DIRECT) {
++#ifdef CONFIG_DIRECT_IO
+ 		if (!filp->f_mapping || !filp->f_mapping->a_ops ||
+ 			!filp->f_mapping->a_ops->direct_IO)
++#endif
+ 				return -EINVAL;
+ 	}
+ 
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -655,9 +655,12 @@ int open_check_o_direct(struct file *f)
+ {
+ 	/* NB: we're sure to have correct a_ops only after f_op->open */
+ 	if (f->f_flags & O_DIRECT) {
++#ifdef CONFIG_DIRECT_IO
+ 		if (!f->f_mapping->a_ops ||
+ 		    ((!f->f_mapping->a_ops->direct_IO) &&
+-		    (!f->f_mapping->a_ops->get_xip_mem))) {
++		    (!f->f_mapping->a_ops->get_xip_mem)))
++#endif
++		{
+ 			return -EINVAL;
+ 		}
+ 	}
diff --git a/target/linux/generic/patches-3.18/904-debloat_dma_buf.patch b/target/linux/generic/patches-3.18/904-debloat_dma_buf.patch
new file mode 100644
index 0000000000..a5e0be2496
--- /dev/null
+++ b/target/linux/generic/patches-3.18/904-debloat_dma_buf.patch
@@ -0,0 +1,44 @@
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -229,7 +229,7 @@ config SOC_BUS
+ source "drivers/base/regmap/Kconfig"
+ 
+ config DMA_SHARED_BUFFER
+-	bool
++	tristate
+ 	default n
+ 	select ANON_INODES
+ 	help
+--- a/drivers/dma-buf/Makefile
++++ b/drivers/dma-buf/Makefile
+@@ -1 +1,2 @@
+-obj-y := dma-buf.o fence.o reservation.o seqno-fence.o
++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
++dma-shared-buffer-objs := dma-buf.o fence.o reservation.o seqno-fence.o
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -32,6 +32,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/poll.h>
+ #include <linux/reservation.h>
++#include <linux/module.h>
+ 
+ static inline int is_dma_buf_file(struct file *);
+ 
+@@ -904,4 +905,5 @@ static void __exit dma_buf_deinit(void)
+ {
+ 	dma_buf_uninit_debugfs();
+ }
+-__exitcall(dma_buf_deinit);
++module_exit(dma_buf_deinit);
++MODULE_LICENSE("GPL");
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -1823,6 +1823,7 @@ int wake_up_state(struct task_struct *p,
+ {
+ 	return try_to_wake_up(p, state, 0);
+ }
++EXPORT_SYMBOL_GPL(wake_up_state);
+ 
+ /*
+  * This function clears the sched_dl_entity static params.
diff --git a/target/linux/generic/patches-3.18/910-kobject_uevent.patch b/target/linux/generic/patches-3.18/910-kobject_uevent.patch
new file mode 100644
index 0000000000..f69294b4fe
--- /dev/null
+++ b/target/linux/generic/patches-3.18/910-kobject_uevent.patch
@@ -0,0 +1,21 @@
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -53,6 +53,18 @@ static const char *kobject_actions[] = {
+ 	[KOBJ_OFFLINE] =	"offline",
+ };
+ 
++u64 uevent_next_seqnum(void)
++{
++	u64 seq;
++
++	mutex_lock(&uevent_sock_mutex);
++	seq = ++uevent_seqnum;
++	mutex_unlock(&uevent_sock_mutex);
++
++	return seq;
++}
++EXPORT_SYMBOL_GPL(uevent_next_seqnum);
++
+ /**
+  * kobject_action_type - translate action string to numeric type
+  *
diff --git a/target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch
new file mode 100644
index 0000000000..6e4c140291
--- /dev/null
+++ b/target/linux/generic/patches-3.18/911-kobject_add_broadcast_uevent.patch
@@ -0,0 +1,65 @@
+--- a/include/linux/kobject.h
++++ b/include/linux/kobject.h
+@@ -32,6 +32,8 @@
+ #define UEVENT_NUM_ENVP			32	/* number of env pointers */
+ #define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */
+ 
++struct sk_buff;
++
+ #ifdef CONFIG_UEVENT_HELPER
+ /* path to the userspace helper executed on an event */
+ extern char uevent_helper[];
+@@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_en
+ int kobject_action_type(const char *buf, size_t count,
+ 			enum kobject_action *type);
+ 
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation);
++
+ #endif /* _KOBJECT_H_ */
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -424,6 +424,43 @@ int add_uevent_var(struct kobj_uevent_en
+ EXPORT_SYMBOL_GPL(add_uevent_var);
+ 
+ #if defined(CONFIG_NET)
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	struct uevent_sock *ue_sk;
++	int err = 0;
++
++	/* send netlink message */
++	mutex_lock(&uevent_sock_mutex);
++	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
++		struct sock *uevent_sock = ue_sk->sk;
++		struct sk_buff *skb2;
++
++		skb2 = skb_clone(skb, allocation);
++		if (!skb2)
++			break;
++
++		err = netlink_broadcast(uevent_sock, skb2, pid, group,
++					allocation);
++		if (err)
++			break;
++	}
++	mutex_unlock(&uevent_sock_mutex);
++
++	kfree_skb(skb);
++	return err;
++}
++#else
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	kfree_skb(skb);
++	return 0;
++}
++#endif
++EXPORT_SYMBOL_GPL(broadcast_uevent);
++
++#if defined(CONFIG_NET)
+ static int uevent_net_init(struct net *net)
+ {
+ 	struct uevent_sock *ue_sk;
diff --git a/target/linux/generic/patches-3.18/921-use_preinit_as_init.patch b/target/linux/generic/patches-3.18/921-use_preinit_as_init.patch
new file mode 100644
index 0000000000..57c2fe27be
--- /dev/null
+++ b/target/linux/generic/patches-3.18/921-use_preinit_as_init.patch
@@ -0,0 +1,12 @@
+--- a/init/main.c
++++ b/init/main.c
+@@ -963,7 +963,8 @@ static int __ref kernel_init(void *unuse
+ 		pr_err("Failed to execute %s (error %d).  Attempting defaults...\n",
+ 			execute_command, ret);
+ 	}
+-	if (!try_to_run_init_process("/sbin/init") ||
++	if (!try_to_run_init_process("/etc/preinit") ||
++	    !try_to_run_init_process("/sbin/init") ||
+ 	    !try_to_run_init_process("/etc/init") ||
+ 	    !try_to_run_init_process("/bin/init") ||
+ 	    !try_to_run_init_process("/bin/sh"))
diff --git a/target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch b/target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch
new file mode 100644
index 0000000000..988de35ce0
--- /dev/null
+++ b/target/linux/generic/patches-3.18/922-always-create-console-node-in-initramfs.patch
@@ -0,0 +1,30 @@
+--- a/scripts/gen_initramfs_list.sh
++++ b/scripts/gen_initramfs_list.sh
+@@ -59,6 +59,18 @@ default_initramfs() {
+ 	EOF
+ }
+ 
++list_openwrt_initramfs() {
++	:
++}
++
++openwrt_initramfs() {
++	# make sure that /dev/console exists
++	cat <<-EOF >> ${output}
++		dir /dev 0755 0 0
++		nod /dev/console 0600 0 0 c 5 1
++	EOF
++}
++
+ filetype() {
+ 	local argv1="$1"
+ 
+@@ -177,6 +189,8 @@ dir_filelist() {
+ 	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+ 		${dep_list}print_mtime "$1"
+ 
++		${dep_list}openwrt_initramfs
++
+ 		echo "${dirlist}" | \
+ 		while read x; do
+ 			${dep_list}parse ${x}
diff --git a/target/linux/generic/patches-3.18/930-crashlog.patch b/target/linux/generic/patches-3.18/930-crashlog.patch
new file mode 100644
index 0000000000..9b0eb732df
--- /dev/null
+++ b/target/linux/generic/patches-3.18/930-crashlog.patch
@@ -0,0 +1,276 @@
+--- /dev/null
++++ b/include/linux/crashlog.h
+@@ -0,0 +1,17 @@
++#ifndef __CRASHLOG_H
++#define __CRASHLOG_H
++
++#ifdef CONFIG_CRASHLOG
++void crashlog_init_bootmem(struct bootmem_data *bdata);
++void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size);
++#else
++static inline void crashlog_init_bootmem(struct bootmem_data *bdata)
++{
++}
++
++static inline void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
++{
++}
++#endif
++
++#endif
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1279,6 +1279,10 @@ config RELAY
+ 
+ 	  If unsure, say N.
+ 
++config CRASHLOG
++	bool "Crash logging"
++	depends on (!NO_BOOTMEM || HAVE_MEMBLOCK) && !(ARM || SPARC || PPC)
++
+ config BLK_DEV_INITRD
+ 	bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
+ 	depends on BROKEN || !FRV
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -96,6 +96,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+ obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
+ obj-$(CONFIG_TORTURE_TEST) += torture.o
++obj-$(CONFIG_CRASHLOG) += crashlog.o
+ 
+ $(obj)/configs.o: $(obj)/config_data.h
+ 
+--- /dev/null
++++ b/kernel/crashlog.c
+@@ -0,0 +1,181 @@
++/*
++ * Crash information logger
++ * Copyright (C) 2010 Felix Fietkau <nbd@nbd.name>
++ *
++ * Based on ramoops.c
++ *   Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/bootmem.h>
++#include <linux/memblock.h>
++#include <linux/debugfs.h>
++#include <linux/crashlog.h>
++#include <linux/kmsg_dump.h>
++#include <linux/module.h>
++#include <linux/pfn.h>
++#include <asm/io.h>
++
++#define CRASHLOG_PAGES	4
++#define CRASHLOG_SIZE	(CRASHLOG_PAGES * PAGE_SIZE)
++#define CRASHLOG_MAGIC	0xa1eedead
++
++/*
++ * Start the log at 1M before the end of RAM, as some boot loaders like
++ * to use the end of the RAM for stack usage and other things
++ * If this fails, fall back to using the last part.
++ */
++#define CRASHLOG_OFFSET	(1024 * 1024)
++
++struct crashlog_data {
++	u32 magic;
++	u32 len;
++	u8 data[];
++};
++
++static struct debugfs_blob_wrapper crashlog_blob;
++static unsigned long crashlog_addr = 0;
++static struct crashlog_data *crashlog_buf;
++static struct kmsg_dumper dump;
++static bool first = true;
++
++extern struct list_head *crashlog_modules;
++
++#ifndef CONFIG_NO_BOOTMEM
++void __init crashlog_init_bootmem(bootmem_data_t *bdata)
++{
++	unsigned long addr;
++
++	if (crashlog_addr)
++		return;
++
++	addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET;
++	if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) {
++		printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr);
++		bdata->node_low_pfn -= CRASHLOG_PAGES;
++		addr = PFN_PHYS(bdata->node_low_pfn);
++	}
++	crashlog_addr = addr;
++}
++#endif
++
++#ifdef CONFIG_HAVE_MEMBLOCK
++void __init_memblock crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
++{
++	if (crashlog_addr)
++		return;
++
++	addr += size - CRASHLOG_OFFSET;
++	if (memblock_reserve(addr, CRASHLOG_SIZE)) {
++		printk("Crashlog failed to allocate RAM at address 0x%lx\n", (unsigned long) addr);
++		return;
++	}
++
++	crashlog_addr = addr;
++}
++#endif
++
++static void __init crashlog_copy(void)
++{
++	if (crashlog_buf->magic != CRASHLOG_MAGIC)
++		return;
++
++	if (!crashlog_buf->len || crashlog_buf->len >
++	    CRASHLOG_SIZE - sizeof(*crashlog_buf))
++		return;
++
++	crashlog_blob.size = crashlog_buf->len;
++	crashlog_blob.data = kmemdup(crashlog_buf->data,
++		crashlog_buf->len, GFP_KERNEL);
++
++	debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob);
++}
++
++static int get_maxlen(void)
++{
++	return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len;
++}
++
++static void crashlog_printf(const char *fmt, ...)
++{
++	va_list args;
++	int len = get_maxlen();
++
++	if (!len)
++		return;
++
++	va_start(args, fmt);
++	crashlog_buf->len += vscnprintf(
++		&crashlog_buf->data[crashlog_buf->len],
++		len, fmt, args);
++	va_end(args);
++}
++
++static void crashlog_do_dump(struct kmsg_dumper *dumper,
++		enum kmsg_dump_reason reason)
++{
++	struct timeval tv;
++	struct module *m;
++	char *buf;
++	size_t len;
++
++	if (!first)
++		crashlog_printf("\n===================================\n");
++
++	do_gettimeofday(&tv);
++	crashlog_printf("Time: %lu.%lu\n",
++		(long)tv.tv_sec, (long)tv.tv_usec);
++
++	if (first) {
++		crashlog_printf("Modules:");
++		list_for_each_entry(m, crashlog_modules, list) {
++			crashlog_printf("\t%s@%p+%x", m->name,
++			m->module_core, m->core_size,
++			m->module_init, m->init_size);
++		}
++		crashlog_printf("\n");
++		first = false;
++	}
++
++	buf = (char *)&crashlog_buf->data[crashlog_buf->len];
++
++	kmsg_dump_get_buffer(dumper, true, buf, get_maxlen(), &len);
++
++	crashlog_buf->len += len;
++}
++
++
++int __init crashlog_init_fs(void)
++{
++	if (!crashlog_addr)
++		return -ENOMEM;
++
++	crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE);
++
++	crashlog_copy();
++
++	crashlog_buf->magic = CRASHLOG_MAGIC;
++	crashlog_buf->len = 0;
++
++	dump.max_reason = KMSG_DUMP_OOPS;
++	dump.dump = crashlog_do_dump;
++	kmsg_dump_register(&dump);
++
++	return 0;
++}
++module_init(crashlog_init_fs);
+--- a/mm/bootmem.c
++++ b/mm/bootmem.c
+@@ -15,6 +15,7 @@
+ #include <linux/export.h>
+ #include <linux/kmemleak.h>
+ #include <linux/range.h>
++#include <linux/crashlog.h>
+ #include <linux/memblock.h>
+ #include <linux/bug.h>
+ #include <linux/io.h>
+@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo
+ 	if (!bdata->node_bootmem_map)
+ 		return 0;
+ 
++	crashlog_init_bootmem(bdata);
+ 	map = bdata->node_bootmem_map;
+ 	start = bdata->node_min_pfn;
+ 	end = bdata->node_low_pfn;
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -105,6 +105,9 @@ static LIST_HEAD(modules);
+ #ifdef CONFIG_KGDB_KDB
+ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+ #endif /* CONFIG_KGDB_KDB */
++#ifdef CONFIG_CRASHLOG
++struct list_head *crashlog_modules = &modules;
++#endif
+ 
+ #ifdef CONFIG_MODULE_SIG
+ #ifdef CONFIG_MODULE_SIG_FORCE
+--- a/mm/memblock.c
++++ b/mm/memblock.c
+@@ -19,6 +19,7 @@
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
+ #include <linux/memblock.h>
++#include <linux/crashlog.h>
+ 
+ #include <asm-generic/sections.h>
+ #include <linux/io.h>
+@@ -477,6 +478,8 @@ static void __init_memblock memblock_ins
+ 	memblock_set_region_node(rgn, nid);
+ 	type->cnt++;
+ 	type->total_size += size;
++	if (type == &memblock.memory && idx == 0)
++		crashlog_init_memblock(base, size);
+ }
+ 
+ /**
diff --git a/target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch
new file mode 100644
index 0000000000..ac13c9e673
--- /dev/null
+++ b/target/linux/generic/patches-3.18/970-remove-unsane-filenames-from-deps_initramfs-list.patch
@@ -0,0 +1,29 @@
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data
+ 	include $(obj)/.initramfs_data.cpio.d
+ endif
+ 
++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
++
+ quiet_cmd_initfs = GEN     $@
+       cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
+ 
+@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra
+ 	initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \
+ 	initramfs_data.cpio
+ # do not try to update files included in initramfs
+-$(deps_initramfs): ;
++$(deps_initramfs_sane): ;
+ 
+-$(deps_initramfs): klibcdirs
++$(deps_initramfs_sane): klibcdirs
+ # We rebuild initramfs_data.cpio if:
+ # 1) Any included file is newer then initramfs_data.cpio
+ # 2) There are changes in which files are included (added or deleted)
+ # 3) If gen_init_cpio are newer than initramfs_data.cpio
+ # 4) arguments to gen_initramfs.sh changes
+-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
++$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
+ 	$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d
+ 	$(call if_changed,initfs)
diff --git a/target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch b/target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch
new file mode 100644
index 0000000000..5e9718b61d
--- /dev/null
+++ b/target/linux/generic/patches-3.18/980-arm_openwrt_machtypes.patch
@@ -0,0 +1,32 @@
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -1007,3 +1007,29 @@ eco5_bx2		MACH_ECO5_BX2		ECO5_BX2		4572
+ eukrea_cpuimx28sd	MACH_EUKREA_CPUIMX28SD	EUKREA_CPUIMX28SD	4573
+ domotab			MACH_DOMOTAB		DOMOTAB			4574
+ pfla03			MACH_PFLA03		PFLA03			4575
++#
++# Additional mach-types supported by OpenWrt
++#
++wg302v1			MACH_WG302V1		WG302V1			889
++pronghorn		MACH_PRONGHORN		PRONGHORN		928
++pronghorn_metro		MACH_PRONGHORNMETRO	PRONGHORNMETRO		1040
++sidewinder		MACH_SIDEWINDER		SIDEWINDER		1041
++wrt300nv2		MACH_WRT300NV2		WRT300NV2		1077
++compex42x		MACH_COMPEXWP18		COMPEXWP18		1273
++goldfish		MACH_GOLDFISH		GOLDFISH		1441
++cambria			MACH_CAMBRIA		CAMBRIA			1468
++dt2			MACH_DT2		DT2			1514
++ap1000			MACH_AP1000		AP1000			1543
++tw2662			MACH_TW2662		TW2662			1658
++tw5334			MACH_TW5334		TW5334			1664
++usr8200			MACH_USR8200		USR8200			1762
++mi424wr			MACH_MI424WR		MI424WR			1778
++gw2388			MACH_GW2388		GW2388			2635
++iconnect		MACH_ICONNECT		ICONNECT		2870
++nsb3ast			MACH_NSB3AST		NSB3AST			2917
++goflexnet		MACH_GOFLEXNET		GOFLEXNET		3089
++nas6210			MACH_NAS6210		NAS6210			3104
++ns_k330			MACH_NS_K330		NS_K330			3108
++bcm2708			MACH_BCM2708		BCM2708			3138
++wn802t			MACH_WN802T		WN802T			3306
++nsa310			MACH_NSA310		NSA310			4022
diff --git a/target/linux/generic/patches-3.18/990-gpio_wdt.patch b/target/linux/generic/patches-3.18/990-gpio_wdt.patch
new file mode 100644
index 0000000000..47422734f3
--- /dev/null
+++ b/target/linux/generic/patches-3.18/990-gpio_wdt.patch
@@ -0,0 +1,360 @@
+This generic GPIO watchdog is used on Huawei E970 (brcm47xx)
+
+Signed-off-by: Mathias Adam <m.adam--openwrt@adamis.de>
+
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -1139,6 +1139,15 @@ config WDT_MTX1
+ 	  Hardware driver for the MTX-1 boards. This is a watchdog timer that
+ 	  will reboot the machine after a 100 seconds timer expired.
+ 
++config GPIO_WDT
++	tristate "GPIO Hardware Watchdog"
++ 	help
++	  Hardware driver for GPIO-controlled watchdogs. GPIO pin and
++	  toggle interval settings are platform-specific. The driver
++	  will stop toggling the GPIO (i.e. machine reboots) after a
++	  100 second timer expired and no process has written to
++	  /dev/watchdog during that time.
++
+ config PNX833X_WDT
+ 	tristate "PNX833x Hardware Watchdog"
+ 	depends on SOC_PNX8335
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -134,6 +134,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt
+ obj-$(CONFIG_INDYDOG) += indydog.o
+ obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o
+ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
++obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o
+ obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
+ obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
+ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+--- /dev/null
++++ b/drivers/watchdog/old_gpio_wdt.c
+@@ -0,0 +1,301 @@
++/*
++ *      Driver for GPIO-controlled Hardware Watchdogs.
++ *
++ *      Copyright (C) 2013 Mathias Adam <m.adam--linux@adamis.de>
++ *
++ *      Replaces mtx1_wdt (driver for the MTX-1 Watchdog):
++ *
++ *      (C) Copyright 2005 4G Systems <info@4g-systems.biz>,
++ *                              All Rights Reserved.
++ *                              http://www.4g-systems.biz
++ *
++ *      (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
++ *
++ *      This program is free software; you can redistribute it and/or
++ *      modify it under the terms of the GNU General Public License
++ *      as published by the Free Software Foundation; either version
++ *      2 of the License, or (at your option) any later version.
++ *
++ *      Neither Michael Stickel nor 4G Systems admit liability nor provide
++ *      warranty for any of this software. This material is provided
++ *      "AS-IS" and at no charge.
++ *
++ *      (c) Copyright 2005    4G Systems <info@4g-systems.biz>
++ *
++ *      Release 0.01.
++ *      Author: Michael Stickel  michael.stickel@4g-systems.biz
++ *
++ *      Release 0.02.
++ *      Author: Florian Fainelli florian@openwrt.org
++ *              use the Linux watchdog/timer APIs
++ *
++ *      Release 0.03.
++ *      Author: Mathias Adam <m.adam--linux@adamis.de>
++ *              make it a generic gpio watchdog driver
++ *
++ *      The Watchdog is configured to reset the MTX-1
++ *      if it is not triggered for 100 seconds.
++ *      It should not be triggered more often than 1.6 seconds.
++ *
++ *      A timer triggers the watchdog every 5 seconds, until
++ *      it is opened for the first time. After the first open
++ *      it MUST be triggered every 2..95 seconds.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/timer.h>
++#include <linux/completion.h>
++#include <linux/jiffies.h>
++#include <linux/watchdog.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/uaccess.h>
++#include <linux/gpio.h>
++#include <linux/old_gpio_wdt.h>
++
++static int ticks = 100 * HZ;
++
++static struct {
++	struct completion stop;
++	spinlock_t lock;
++	int running;
++	struct timer_list timer;
++	int queue;
++	int default_ticks;
++	unsigned long inuse;
++	unsigned gpio;
++	unsigned int gstate;
++	int interval;
++	int first_interval;
++} gpio_wdt_device;
++
++static void gpio_wdt_trigger(unsigned long unused)
++{
++	spin_lock(&gpio_wdt_device.lock);
++	if (gpio_wdt_device.running && ticks > 0)
++		ticks -= gpio_wdt_device.interval;
++
++	/* toggle wdt gpio */
++	gpio_wdt_device.gstate = !gpio_wdt_device.gstate;
++	gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate);
++
++	if (gpio_wdt_device.queue && ticks > 0)
++		mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval);
++	else
++		complete(&gpio_wdt_device.stop);
++	spin_unlock(&gpio_wdt_device.lock);
++}
++
++static void gpio_wdt_reset(void)
++{
++	ticks = gpio_wdt_device.default_ticks;
++}
++
++
++static void gpio_wdt_start(void)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&gpio_wdt_device.lock, flags);
++	if (!gpio_wdt_device.queue) {
++		gpio_wdt_device.queue = 1;
++		gpio_wdt_device.gstate = 1;
++		gpio_set_value(gpio_wdt_device.gpio, 1);
++		mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval);
++	}
++	gpio_wdt_device.running++;
++	spin_unlock_irqrestore(&gpio_wdt_device.lock, flags);
++}
++
++static int gpio_wdt_stop(void)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&gpio_wdt_device.lock, flags);
++	if (gpio_wdt_device.queue) {
++		gpio_wdt_device.queue = 0;
++		gpio_wdt_device.gstate = 0;
++		gpio_set_value(gpio_wdt_device.gpio, 0);
++	}
++	ticks = gpio_wdt_device.default_ticks;
++	spin_unlock_irqrestore(&gpio_wdt_device.lock, flags);
++	return 0;
++}
++
++/* Filesystem functions */
++
++static int gpio_wdt_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit(0, &gpio_wdt_device.inuse))
++		return -EBUSY;
++	return nonseekable_open(inode, file);
++}
++
++
++static int gpio_wdt_release(struct inode *inode, struct file *file)
++{
++	clear_bit(0, &gpio_wdt_device.inuse);
++	return 0;
++}
++
++static long gpio_wdt_ioctl(struct file *file, unsigned int cmd,
++							unsigned long arg)
++{
++	void __user *argp = (void __user *)arg;
++	int __user *p = (int __user *)argp;
++	unsigned int value;
++	static const struct watchdog_info ident = {
++		.options = WDIOF_CARDRESET,
++		.identity = "GPIO WDT",
++	};
++
++	switch (cmd) {
++	case WDIOC_GETSUPPORT:
++		if (copy_to_user(argp, &ident, sizeof(ident)))
++			return -EFAULT;
++		break;
++	case WDIOC_GETSTATUS:
++	case WDIOC_GETBOOTSTATUS:
++		put_user(0, p);
++		break;
++	case WDIOC_SETOPTIONS:
++		if (get_user(value, p))
++			return -EFAULT;
++		if (value & WDIOS_ENABLECARD)
++			gpio_wdt_start();
++		else if (value & WDIOS_DISABLECARD)
++			gpio_wdt_stop();
++		else
++			return -EINVAL;
++		return 0;
++	case WDIOC_KEEPALIVE:
++		gpio_wdt_reset();
++		break;
++	default:
++		return -ENOTTY;
++	}
++	return 0;
++}
++
++
++static ssize_t gpio_wdt_write(struct file *file, const char *buf,
++						size_t count, loff_t *ppos)
++{
++	if (!count)
++		return -EIO;
++	gpio_wdt_reset();
++	return count;
++}
++
++static const struct file_operations gpio_wdt_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= no_llseek,
++	.unlocked_ioctl	= gpio_wdt_ioctl,
++	.open		= gpio_wdt_open,
++	.write		= gpio_wdt_write,
++	.release	= gpio_wdt_release,
++};
++
++
++static struct miscdevice gpio_wdt_misc = {
++	.minor	= WATCHDOG_MINOR,
++	.name	= "watchdog",
++	.fops	= &gpio_wdt_fops,
++};
++
++
++static int gpio_wdt_probe(struct platform_device *pdev)
++{
++	int ret;
++	struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data;
++
++	gpio_wdt_device.gpio = gpio_wdt_data->gpio;
++	gpio_wdt_device.interval = gpio_wdt_data->interval;
++	gpio_wdt_device.first_interval = gpio_wdt_data->first_interval;
++	if (gpio_wdt_device.first_interval <= 0) {
++		gpio_wdt_device.first_interval = gpio_wdt_device.interval;
++	}
++
++	ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt");
++	if (ret < 0) {
++		dev_err(&pdev->dev, "failed to request gpio");
++		return ret;
++	}
++
++	spin_lock_init(&gpio_wdt_device.lock);
++	init_completion(&gpio_wdt_device.stop);
++	gpio_wdt_device.queue = 0;
++	clear_bit(0, &gpio_wdt_device.inuse);
++	setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L);
++	gpio_wdt_device.default_ticks = ticks;
++
++	gpio_wdt_start();
++	dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n",
++		gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval);
++	return 0;
++}
++
++static int gpio_wdt_remove(struct platform_device *pdev)
++{
++	/* FIXME: do we need to lock this test ? */
++	if (gpio_wdt_device.queue) {
++		gpio_wdt_device.queue = 0;
++		wait_for_completion(&gpio_wdt_device.stop);
++	}
++
++	gpio_free(gpio_wdt_device.gpio);
++	misc_deregister(&gpio_wdt_misc);
++	return 0;
++}
++
++static struct platform_driver gpio_wdt_driver = {
++	.probe = gpio_wdt_probe,
++	.remove = gpio_wdt_remove,
++	.driver.name = "gpio-wdt",
++	.driver.owner = THIS_MODULE,
++};
++
++static int __init gpio_wdt_init(void)
++{
++	return platform_driver_register(&gpio_wdt_driver);
++}
++arch_initcall(gpio_wdt_init);
++
++/*
++ * We do wdt initialization in two steps: arch_initcall probes the wdt
++ * very early to start pinging the watchdog (misc devices are not yet
++ * available), and later module_init() just registers the misc device.
++ */
++static int gpio_wdt_init_late(void)
++{
++	int ret;
++
++	ret = misc_register(&gpio_wdt_misc);
++	if (ret < 0) {
++		pr_err("GPIO_WDT: failed to register misc device\n");
++		return ret;
++	}
++	return 0;
++}
++#ifndef MODULE
++module_init(gpio_wdt_init_late);
++#endif
++
++static void __exit gpio_wdt_exit(void)
++{
++	platform_driver_unregister(&gpio_wdt_driver);
++}
++module_exit(gpio_wdt_exit);
++
++MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam");
++MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
++MODULE_ALIAS("platform:gpio-wdt");
+--- /dev/null
++++ b/include/linux/old_gpio_wdt.h
+@@ -0,0 +1,21 @@
++/*
++ *  Definitions for the GPIO watchdog driver
++ *
++ *  Copyright (C) 2013 Mathias Adam <m.adam--linux@adamis.de>
++ *
++ *  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.
++ *
++ */
++
++#ifndef _GPIO_WDT_H_
++#define _GPIO_WDT_H_
++
++struct gpio_wdt_platform_data {
++	int	gpio;		/* GPIO line number */
++	int	interval;	/* watchdog reset interval in system ticks */
++	int	first_interval;	/* first wd reset interval in system ticks */
++};
++
++#endif /* _GPIO_WDT_H_ */
diff --git a/target/linux/generic/patches-3.18/995-mangle_bootargs.patch b/target/linux/generic/patches-3.18/995-mangle_bootargs.patch
new file mode 100644
index 0000000000..0029e90822
--- /dev/null
+++ b/target/linux/generic/patches-3.18/995-mangle_bootargs.patch
@@ -0,0 +1,58 @@
+--- a/init/main.c
++++ b/init/main.c
+@@ -362,6 +362,29 @@ static inline void setup_nr_cpu_ids(void
+ static inline void smp_prepare_cpus(unsigned int maxcpus) { }
+ #endif
+ 
++#ifdef CONFIG_MANGLE_BOOTARGS
++static void __init mangle_bootargs(char *command_line)
++{
++	char *rootdev;
++	char *rootfs;
++
++	rootdev = strstr(command_line, "root=/dev/mtdblock");
++
++	if (rootdev)
++		strncpy(rootdev, "mangled_rootblock=", 18);
++
++	rootfs = strstr(command_line, "rootfstype");
++
++	if (rootfs)
++		strncpy(rootfs, "mangled_fs", 10);
++
++}
++#else
++static void __init mangle_bootargs(char *command_line)
++{
++}
++#endif
++
+ /*
+  * We need to store the untouched command line for future reference.
+  * We also need to store the touched command line since the parameter
+@@ -530,6 +553,7 @@ asmlinkage __visible void __init start_k
+ 	pr_notice("%s", linux_banner);
+ 	setup_arch(&command_line);
+ 	mm_init_cpumask(&init_mm);
++	mangle_bootargs(command_line);
+ 	setup_command_line(command_line);
+ 	setup_nr_cpu_ids();
+ 	setup_per_cpu_areas();
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1597,6 +1597,15 @@ config EMBEDDED
+ 	  an embedded system so certain expert options are available
+ 	  for configuration.
+ 
++config MANGLE_BOOTARGS
++	bool "Rename offending bootargs"
++	depends on EXPERT
++	help
++	  Sometimes the bootloader passed bogus root= and rootfstype=
++	  parameters to the kernel, and while you want to ignore them,
++	  you need to know the values f.e. to support dual firmware
++	  layouts on the flash.
++
+ config HAVE_PERF_EVENTS
+ 	bool
+ 	help
diff --git a/target/linux/generic/patches-3.18/997-device_tree_cmdline.patch b/target/linux/generic/patches-3.18/997-device_tree_cmdline.patch
new file mode 100644
index 0000000000..dd725b01b1
--- /dev/null
+++ b/target/linux/generic/patches-3.18/997-device_tree_cmdline.patch
@@ -0,0 +1,24 @@
+--- a/drivers/of/fdt.c
++++ b/drivers/of/fdt.c
+@@ -903,6 +903,9 @@ int __init early_init_dt_scan_chosen(uns
+ 	p = of_get_flat_dt_prop(node, "bootargs", &l);
+ 	if (p != NULL && l > 0)
+ 		strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
++	p = of_get_flat_dt_prop(node, "bootargs-append", &l);
++	if (p != NULL && l > 0)
++		strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
+ 
+ 	/*
+ 	 * CONFIG_CMDLINE is meant to be a default in case nothing else
+--- a/arch/mips/kernel/prom.c
++++ b/arch/mips/kernel/prom.c
+@@ -49,6 +49,9 @@ void * __init early_init_dt_alloc_memory
+ 
+ void __init __dt_setup_arch(void *bph)
+ {
++	if (boot_command_line[0] == '\0')
++		strcpy(boot_command_line, arcs_cmdline);
++
+ 	if (!early_init_dt_scan(bph))
+ 		return;
+ 
diff --git a/target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch b/target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch
new file mode 100644
index 0000000000..d317de1102
--- /dev/null
+++ b/target/linux/generic/patches-3.18/998-enable_wilink_platform_without_drivers.patch
@@ -0,0 +1,15 @@
+We use backports for driver updates - make sure we can compile in the glue code regardless
+
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+
+--- a/drivers/net/wireless/ti/Kconfig
++++ b/drivers/net/wireless/ti/Kconfig
+@@ -15,7 +15,7 @@ source "drivers/net/wireless/ti/wlcore/K
+ 
+ config WILINK_PLATFORM_DATA
+ 	bool "TI WiLink platform data"
+-	depends on WLCORE_SDIO || WL1251_SDIO
++	depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
+ 	default y
+ 	---help---
+ 	Small platform data bit needed to pass data to the sdio modules.
diff --git a/target/linux/generic/patches-3.18/999-seccomp_log.patch b/target/linux/generic/patches-3.18/999-seccomp_log.patch
new file mode 100644
index 0000000000..1db6b18d4e
--- /dev/null
+++ b/target/linux/generic/patches-3.18/999-seccomp_log.patch
@@ -0,0 +1,34 @@
+--- a/kernel/seccomp.c
++++ b/kernel/seccomp.c
+@@ -614,6 +614,7 @@ int __secure_computing(void)
+ #ifdef CONFIG_SECCOMP_FILTER
+ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
+ {
++	char name[sizeof(current->comm)];
+ 	u32 filter_ret, action;
+ 	int data;
+ 
+@@ -644,6 +645,13 @@ static u32 __seccomp_phase1_filter(int t
+ 	case SECCOMP_RET_TRACE:
+ 		return filter_ret;  /* Save the rest for phase 2. */
+ 
++	case SECCOMP_RET_LOG:
++		get_task_comm(name, current);
++		pr_err_ratelimited("seccomp: %s [%u] tried to call non-whitelisted syscall: %d\n", name, current->pid, this_syscall);
++		syscall_set_return_value(current, task_pt_regs(current),
++					 -data, 0);
++		goto skip;
++
+ 	case SECCOMP_RET_ALLOW:
+ 		return SECCOMP_PHASE1_OK;
+ 
+--- a/include/uapi/linux/seccomp.h
++++ b/include/uapi/linux/seccomp.h
+@@ -28,6 +28,7 @@
+ #define SECCOMP_RET_KILL	0x00000000U /* kill the task immediately */
+ #define SECCOMP_RET_TRAP	0x00030000U /* disallow and force a SIGSYS */
+ #define SECCOMP_RET_ERRNO	0x00050000U /* returns an errno */
++#define SECCOMP_RET_LOG		0x00070000U /* allow + logline */
+ #define SECCOMP_RET_TRACE	0x7ff00000U /* pass to a tracer or disallow */
+ #define SECCOMP_RET_ALLOW	0x7fff0000U /* allow */
+ 
diff --git a/target/linux/generic/patches-4.1/010-perf-tools-Create-config.detected-into-OUTPUT-direct.patch b/target/linux/generic/patches-4.1/010-perf-tools-Create-config.detected-into-OUTPUT-direct.patch
new file mode 100644
index 0000000000..f2c1cdd343
--- /dev/null
+++ b/target/linux/generic/patches-4.1/010-perf-tools-Create-config.detected-into-OUTPUT-direct.patch
@@ -0,0 +1,54 @@
+From: Aaro Koskinen <aaro.koskinen@nokia.com>
+Date: Wed, 1 Jul 2015 14:54:42 +0300
+Subject: [PATCH] perf tools: Create config.detected into OUTPUT directory
+
+Create config.detected into OUTPUT directory instead of source
+directory.
+
+This fixes parallel builds that share the same source directory.
+
+Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
+Acked-by: Jiri Olsa <jolsa@kernel.org>
+Cc: Paul Mackerras <paulus@samba.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Link: http://lkml.kernel.org/r/1435751683-18500-1-git-send-email-aaro.koskinen@nokia.com
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+---
+
+--- a/tools/build/Makefile.build
++++ b/tools/build/Makefile.build
+@@ -25,7 +25,7 @@ build-dir := $(srctree)/tools/build
+ include $(build-dir)/Build.include
+ 
+ # do not force detected configuration
+--include .config-detected
++-include $(OUTPUT).config-detected
+ 
+ # Init all relevant variables used in build files so
+ # 1) they have correct type
+--- a/tools/perf/Makefile.perf
++++ b/tools/perf/Makefile.perf
+@@ -528,7 +528,7 @@ config-clean:
+ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
+ 	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
+ 	$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+-	$(Q)$(RM) .config-detected
++	$(Q)$(RM) $(OUTPUT).config-detected
+ 	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
+ 	$(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
+ 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
+--- a/tools/perf/config/Makefile
++++ b/tools/perf/config/Makefile
+@@ -11,9 +11,9 @@ ifneq ($(obj-perf),)
+ obj-perf := $(abspath $(obj-perf))/
+ endif
+ 
+-$(shell echo -n > .config-detected)
+-detected     = $(shell echo "$(1)=y"       >> .config-detected)
+-detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected)
++$(shell echo -n > $(OUTPUT).config-detected)
++detected     = $(shell echo "$(1)=y"       >> $(OUTPUT).config-detected)
++detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
+ 
+ CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
+ 
diff --git a/target/linux/generic/patches-4.1/011-perf-tools-Fix-makefile-generation-under-dash.patch b/target/linux/generic/patches-4.1/011-perf-tools-Fix-makefile-generation-under-dash.patch
new file mode 100644
index 0000000000..45ea1a04f2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/011-perf-tools-Fix-makefile-generation-under-dash.patch
@@ -0,0 +1,27 @@
+From: Sergei Trofimovich <siarheit@google.com>
+Date: Sun, 19 Jul 2015 10:30:05 +0100
+Subject: [PATCH] perf tools: Fix makefile generation under dash
+
+Under dash 'echo -n' yields '-n' to stdout.  Use printf "" instead.
+
+Signed-off-by: Sergei Trofimovich <siarheit@google.com>
+Acked-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Jiri Olsa <jolsa@kernel.org>
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Link: http://lkml.kernel.org/r/1437298205-29305-1-git-send-email-siarheit@google.com
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+---
+
+--- a/tools/perf/config/Makefile
++++ b/tools/perf/config/Makefile
+@@ -11,7 +11,7 @@ ifneq ($(obj-perf),)
+ obj-perf := $(abspath $(obj-perf))/
+ endif
+ 
+-$(shell echo -n > $(OUTPUT).config-detected)
++$(shell printf "" > $(OUTPUT).config-detected)
+ detected     = $(shell echo "$(1)=y"       >> $(OUTPUT).config-detected)
+ detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
+ 
diff --git a/target/linux/generic/patches-4.1/020-ssb-backport.patch b/target/linux/generic/patches-4.1/020-ssb-backport.patch
new file mode 100644
index 0000000000..e96480b021
--- /dev/null
+++ b/target/linux/generic/patches-4.1/020-ssb-backport.patch
@@ -0,0 +1,686 @@
+--- a/arch/mips/bcm47xx/Kconfig
++++ b/arch/mips/bcm47xx/Kconfig
+@@ -4,6 +4,7 @@ config BCM47XX_SSB
+ 	bool "SSB Support for Broadcom BCM47XX"
+ 	select SYS_HAS_CPU_BMIPS32_3300
+ 	select SSB
++	select SSB_HOST_SOC
+ 	select SSB_DRIVER_MIPS
+ 	select SSB_DRIVER_EXTIF
+ 	select SSB_EMBEDDED
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -80,6 +80,15 @@ config SSB_SDIOHOST
+ 
+ 	  If unsure, say N
+ 
++config SSB_HOST_SOC
++	bool "Support for SSB bus on SoC"
++	depends on SSB
++	help
++	  Host interface for a SSB directly mapped into memory. This is
++	  for some Broadcom SoCs from the BCM47xx and BCM53xx lines.
++
++	  If unsure, say N
++
+ config SSB_SILENT
+ 	bool "No SSB kernel messages"
+ 	depends on SSB && EXPERT
+--- a/drivers/ssb/Makefile
++++ b/drivers/ssb/Makefile
+@@ -5,8 +5,9 @@ ssb-$(CONFIG_SSB_SPROM)			+= sprom.o
+ 
+ # host support
+ ssb-$(CONFIG_SSB_PCIHOST)		+= pci.o pcihost_wrapper.o
+-ssb-$(CONFIG_SSB_PCMCIAHOST)		+= pcmcia.o
++ssb-$(CONFIG_SSB_PCMCIAHOST)		+= pcmcia.o bridge_pcmcia_80211.o
+ ssb-$(CONFIG_SSB_SDIOHOST)		+= sdio.o
++ssb-$(CONFIG_SSB_HOST_SOC)		+= host_soc.o
+ 
+ # built-in drivers
+ ssb-y					+= driver_chipcommon.o
+--- /dev/null
++++ b/drivers/ssb/bridge_pcmcia_80211.c
+@@ -0,0 +1,128 @@
++/*
++ * Broadcom 43xx PCMCIA-SSB bridge module
++ *
++ * Copyright (c) 2007 Michael Buesch <m@bues.ch>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/ssb/ssb.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include "ssb_private.h"
++
++static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
++	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
++	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
++	PCMCIA_DEVICE_NULL,
++};
++
++MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
++
++static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
++{
++	struct ssb_bus *ssb;
++	int err = -ENOMEM;
++	int res = 0;
++
++	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
++	if (!ssb)
++		goto out_error;
++
++	err = -ENODEV;
++
++	dev->config_flags |= CONF_ENABLE_IRQ;
++
++	dev->resource[2]->flags |=  WIN_ENABLE | WIN_DATA_WIDTH_16 |
++			 WIN_USE_WAIT;
++	dev->resource[2]->start = 0;
++	dev->resource[2]->end = SSB_CORE_SIZE;
++	res = pcmcia_request_window(dev, dev->resource[2], 250);
++	if (res != 0)
++		goto err_kfree_ssb;
++
++	res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
++	if (res != 0)
++		goto err_disable;
++
++	if (!dev->irq)
++		goto err_disable;
++
++	res = pcmcia_enable_device(dev);
++	if (res != 0)
++		goto err_disable;
++
++	err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
++	if (err)
++		goto err_disable;
++	dev->priv = ssb;
++
++	return 0;
++
++err_disable:
++	pcmcia_disable_device(dev);
++err_kfree_ssb:
++	kfree(ssb);
++out_error:
++	ssb_err("Initialization failed (%d, %d)\n", res, err);
++	return err;
++}
++
++static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
++{
++	struct ssb_bus *ssb = dev->priv;
++
++	ssb_bus_unregister(ssb);
++	pcmcia_disable_device(dev);
++	kfree(ssb);
++	dev->priv = NULL;
++}
++
++#ifdef CONFIG_PM
++static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
++{
++	struct ssb_bus *ssb = dev->priv;
++
++	return ssb_bus_suspend(ssb);
++}
++
++static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
++{
++	struct ssb_bus *ssb = dev->priv;
++
++	return ssb_bus_resume(ssb);
++}
++#else /* CONFIG_PM */
++# define ssb_host_pcmcia_suspend		NULL
++# define ssb_host_pcmcia_resume		NULL
++#endif /* CONFIG_PM */
++
++static struct pcmcia_driver ssb_host_pcmcia_driver = {
++	.owner		= THIS_MODULE,
++	.name		= "ssb-pcmcia",
++	.id_table	= ssb_host_pcmcia_tbl,
++	.probe		= ssb_host_pcmcia_probe,
++	.remove		= ssb_host_pcmcia_remove,
++	.suspend	= ssb_host_pcmcia_suspend,
++	.resume		= ssb_host_pcmcia_resume,
++};
++
++/*
++ * These are not module init/exit functions!
++ * The module_pcmcia_driver() helper cannot be used here.
++ */
++int ssb_host_pcmcia_init(void)
++{
++	return pcmcia_register_driver(&ssb_host_pcmcia_driver);
++}
++
++void ssb_host_pcmcia_exit(void)
++{
++	pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
++}
+--- /dev/null
++++ b/drivers/ssb/host_soc.c
+@@ -0,0 +1,173 @@
++/*
++ * Sonics Silicon Backplane SoC host related functions.
++ * Subsystem core
++ *
++ * Copyright 2005, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/ssb/ssb.h>
++
++#include "ssb_private.h"
++
++static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset)
++{
++	struct ssb_bus *bus = dev->bus;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	return readb(bus->mmio + offset);
++}
++
++static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset)
++{
++	struct ssb_bus *bus = dev->bus;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	return readw(bus->mmio + offset);
++}
++
++static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset)
++{
++	struct ssb_bus *bus = dev->bus;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	return readl(bus->mmio + offset);
++}
++
++#ifdef CONFIG_SSB_BLOCKIO
++static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer,
++				    size_t count, u16 offset, u8 reg_width)
++{
++	struct ssb_bus *bus = dev->bus;
++	void __iomem *addr;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	addr = bus->mmio + offset;
++
++	switch (reg_width) {
++	case sizeof(u8): {
++		u8 *buf = buffer;
++
++		while (count) {
++			*buf = __raw_readb(addr);
++			buf++;
++			count--;
++		}
++		break;
++	}
++	case sizeof(u16): {
++		__le16 *buf = buffer;
++
++		SSB_WARN_ON(count & 1);
++		while (count) {
++			*buf = (__force __le16)__raw_readw(addr);
++			buf++;
++			count -= 2;
++		}
++		break;
++	}
++	case sizeof(u32): {
++		__le32 *buf = buffer;
++
++		SSB_WARN_ON(count & 3);
++		while (count) {
++			*buf = (__force __le32)__raw_readl(addr);
++			buf++;
++			count -= 4;
++		}
++		break;
++	}
++	default:
++		SSB_WARN_ON(1);
++	}
++}
++#endif /* CONFIG_SSB_BLOCKIO */
++
++static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value)
++{
++	struct ssb_bus *bus = dev->bus;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	writeb(value, bus->mmio + offset);
++}
++
++static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value)
++{
++	struct ssb_bus *bus = dev->bus;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	writew(value, bus->mmio + offset);
++}
++
++static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value)
++{
++	struct ssb_bus *bus = dev->bus;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	writel(value, bus->mmio + offset);
++}
++
++#ifdef CONFIG_SSB_BLOCKIO
++static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer,
++				     size_t count, u16 offset, u8 reg_width)
++{
++	struct ssb_bus *bus = dev->bus;
++	void __iomem *addr;
++
++	offset += dev->core_index * SSB_CORE_SIZE;
++	addr = bus->mmio + offset;
++
++	switch (reg_width) {
++	case sizeof(u8): {
++		const u8 *buf = buffer;
++
++		while (count) {
++			__raw_writeb(*buf, addr);
++			buf++;
++			count--;
++		}
++		break;
++	}
++	case sizeof(u16): {
++		const __le16 *buf = buffer;
++
++		SSB_WARN_ON(count & 1);
++		while (count) {
++			__raw_writew((__force u16)(*buf), addr);
++			buf++;
++			count -= 2;
++		}
++		break;
++	}
++	case sizeof(u32): {
++		const __le32 *buf = buffer;
++
++		SSB_WARN_ON(count & 3);
++		while (count) {
++			__raw_writel((__force u32)(*buf), addr);
++			buf++;
++			count -= 4;
++		}
++		break;
++	}
++	default:
++		SSB_WARN_ON(1);
++	}
++}
++#endif /* CONFIG_SSB_BLOCKIO */
++
++/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
++const struct ssb_bus_ops ssb_host_soc_ops = {
++	.read8		= ssb_host_soc_read8,
++	.read16		= ssb_host_soc_read16,
++	.read32		= ssb_host_soc_read32,
++	.write8		= ssb_host_soc_write8,
++	.write16	= ssb_host_soc_write16,
++	.write32	= ssb_host_soc_write32,
++#ifdef CONFIG_SSB_BLOCKIO
++	.block_read	= ssb_host_soc_block_read,
++	.block_write	= ssb_host_soc_block_write,
++#endif
++};
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -596,166 +596,6 @@ error:
+ 	return err;
+ }
+ 
+-static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	return readb(bus->mmio + offset);
+-}
+-
+-static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	return readw(bus->mmio + offset);
+-}
+-
+-static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	return readl(bus->mmio + offset);
+-}
+-
+-#ifdef CONFIG_SSB_BLOCKIO
+-static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer,
+-			       size_t count, u16 offset, u8 reg_width)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-	void __iomem *addr;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	addr = bus->mmio + offset;
+-
+-	switch (reg_width) {
+-	case sizeof(u8): {
+-		u8 *buf = buffer;
+-
+-		while (count) {
+-			*buf = __raw_readb(addr);
+-			buf++;
+-			count--;
+-		}
+-		break;
+-	}
+-	case sizeof(u16): {
+-		__le16 *buf = buffer;
+-
+-		SSB_WARN_ON(count & 1);
+-		while (count) {
+-			*buf = (__force __le16)__raw_readw(addr);
+-			buf++;
+-			count -= 2;
+-		}
+-		break;
+-	}
+-	case sizeof(u32): {
+-		__le32 *buf = buffer;
+-
+-		SSB_WARN_ON(count & 3);
+-		while (count) {
+-			*buf = (__force __le32)__raw_readl(addr);
+-			buf++;
+-			count -= 4;
+-		}
+-		break;
+-	}
+-	default:
+-		SSB_WARN_ON(1);
+-	}
+-}
+-#endif /* CONFIG_SSB_BLOCKIO */
+-
+-static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	writeb(value, bus->mmio + offset);
+-}
+-
+-static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	writew(value, bus->mmio + offset);
+-}
+-
+-static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	writel(value, bus->mmio + offset);
+-}
+-
+-#ifdef CONFIG_SSB_BLOCKIO
+-static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer,
+-				size_t count, u16 offset, u8 reg_width)
+-{
+-	struct ssb_bus *bus = dev->bus;
+-	void __iomem *addr;
+-
+-	offset += dev->core_index * SSB_CORE_SIZE;
+-	addr = bus->mmio + offset;
+-
+-	switch (reg_width) {
+-	case sizeof(u8): {
+-		const u8 *buf = buffer;
+-
+-		while (count) {
+-			__raw_writeb(*buf, addr);
+-			buf++;
+-			count--;
+-		}
+-		break;
+-	}
+-	case sizeof(u16): {
+-		const __le16 *buf = buffer;
+-
+-		SSB_WARN_ON(count & 1);
+-		while (count) {
+-			__raw_writew((__force u16)(*buf), addr);
+-			buf++;
+-			count -= 2;
+-		}
+-		break;
+-	}
+-	case sizeof(u32): {
+-		const __le32 *buf = buffer;
+-
+-		SSB_WARN_ON(count & 3);
+-		while (count) {
+-			__raw_writel((__force u32)(*buf), addr);
+-			buf++;
+-			count -= 4;
+-		}
+-		break;
+-	}
+-	default:
+-		SSB_WARN_ON(1);
+-	}
+-}
+-#endif /* CONFIG_SSB_BLOCKIO */
+-
+-/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
+-static const struct ssb_bus_ops ssb_ssb_ops = {
+-	.read8		= ssb_ssb_read8,
+-	.read16		= ssb_ssb_read16,
+-	.read32		= ssb_ssb_read32,
+-	.write8		= ssb_ssb_write8,
+-	.write16	= ssb_ssb_write16,
+-	.write32	= ssb_ssb_write32,
+-#ifdef CONFIG_SSB_BLOCKIO
+-	.block_read	= ssb_ssb_block_read,
+-	.block_write	= ssb_ssb_block_write,
+-#endif
+-};
+-
+ static int ssb_fetch_invariants(struct ssb_bus *bus,
+ 				ssb_invariants_func_t get_invariants)
+ {
+@@ -876,7 +716,6 @@ int ssb_bus_pcibus_register(struct ssb_b
+ 
+ 	return err;
+ }
+-EXPORT_SYMBOL(ssb_bus_pcibus_register);
+ #endif /* CONFIG_SSB_PCIHOST */
+ 
+ #ifdef CONFIG_SSB_PCMCIAHOST
+@@ -898,7 +737,6 @@ int ssb_bus_pcmciabus_register(struct ss
+ 
+ 	return err;
+ }
+-EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+ 
+ #ifdef CONFIG_SSB_SDIOHOST
+@@ -923,13 +761,14 @@ int ssb_bus_sdiobus_register(struct ssb_
+ EXPORT_SYMBOL(ssb_bus_sdiobus_register);
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+ 
++#ifdef CONFIG_SSB_HOST_SOC
+ int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
+ 			    ssb_invariants_func_t get_invariants)
+ {
+ 	int err;
+ 
+ 	bus->bustype = SSB_BUSTYPE_SSB;
+-	bus->ops = &ssb_ssb_ops;
++	bus->ops = &ssb_host_soc_ops;
+ 
+ 	err = ssb_bus_register(bus, get_invariants, baseaddr);
+ 	if (!err) {
+@@ -939,6 +778,7 @@ int ssb_bus_ssbbus_register(struct ssb_b
+ 
+ 	return err;
+ }
++#endif
+ 
+ int __ssb_driver_register(struct ssb_driver *drv, struct module *owner)
+ {
+@@ -1465,6 +1305,12 @@ static int __init ssb_modinit(void)
+ 		/* don't fail SSB init because of this */
+ 		err = 0;
+ 	}
++	err = ssb_host_pcmcia_init();
++	if (err) {
++		ssb_err("PCMCIA host initialization failed\n");
++		/* don't fail SSB init because of this */
++		err = 0;
++	}
+ 	err = ssb_gige_init();
+ 	if (err) {
+ 		ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");
+@@ -1482,6 +1328,7 @@ fs_initcall(ssb_modinit);
+ static void __exit ssb_modexit(void)
+ {
+ 	ssb_gige_exit();
++	ssb_host_pcmcia_exit();
+ 	b43_pci_ssb_bridge_exit();
+ 	bus_unregister(&ssb_bustype);
+ }
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -147,8 +147,7 @@ error:
+ 	return err;
+ }
+ 
+-int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+-			   struct ssb_device *dev)
++static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
+ {
+ 	int err;
+ 
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -200,7 +200,7 @@ out:
+ }
+ 
+ /* host must be already claimed */
+-int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
++static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
+ {
+ 	u8 coreidx = dev->core_index;
+ 	u32 sbaddr;
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -85,8 +85,6 @@ static inline int ssb_pci_init(struct ss
+ 
+ /* pcmcia.c */
+ #ifdef CONFIG_SSB_PCMCIAHOST
+-extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+-				  struct ssb_device *dev);
+ extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ 				     u8 coreidx);
+ extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+@@ -96,13 +94,10 @@ extern int ssb_pcmcia_get_invariants(str
+ extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus);
+ extern void ssb_pcmcia_exit(struct ssb_bus *bus);
+ extern int ssb_pcmcia_init(struct ssb_bus *bus);
++extern int ssb_host_pcmcia_init(void);
++extern void ssb_host_pcmcia_exit(void);
+ extern const struct ssb_bus_ops ssb_pcmcia_ops;
+ #else /* CONFIG_SSB_PCMCIAHOST */
+-static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+-					 struct ssb_device *dev)
+-{
+-	return 0;
+-}
+ static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ 					    u8 coreidx)
+ {
+@@ -124,6 +119,13 @@ static inline int ssb_pcmcia_init(struct
+ {
+ 	return 0;
+ }
++static inline int ssb_host_pcmcia_init(void)
++{
++	return 0;
++}
++static inline void ssb_host_pcmcia_exit(void)
++{
++}
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+ 
+ /* sdio.c */
+@@ -132,9 +134,7 @@ extern int ssb_sdio_get_invariants(struc
+ 				     struct ssb_init_invariants *iv);
+ 
+ extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset);
+-extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev);
+ extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx);
+-extern int ssb_sdio_hardware_setup(struct ssb_bus *bus);
+ extern void ssb_sdio_exit(struct ssb_bus *bus);
+ extern int ssb_sdio_init(struct ssb_bus *bus);
+ 
+@@ -144,19 +144,10 @@ static inline u32 ssb_sdio_scan_read32(s
+ {
+ 	return 0;
+ }
+-static inline int ssb_sdio_switch_core(struct ssb_bus *bus,
+-					 struct ssb_device *dev)
+-{
+-	return 0;
+-}
+ static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
+ {
+ 	return 0;
+ }
+-static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus)
+-{
+-	return 0;
+-}
+ static inline void ssb_sdio_exit(struct ssb_bus *bus)
+ {
+ }
+@@ -166,6 +157,13 @@ static inline int ssb_sdio_init(struct s
+ }
+ #endif /* CONFIG_SSB_SDIOHOST */
+ 
++/**************************************************
++ * host_soc.c
++ **************************************************/
++
++#ifdef CONFIG_SSB_HOST_SOC
++extern const struct ssb_bus_ops ssb_host_soc_ops;
++#endif
+ 
+ /* scan.c */
+ extern const char *ssb_core_name(u16 coreid);
diff --git a/target/linux/generic/patches-4.1/021-ssb_sprom.patch b/target/linux/generic/patches-4.1/021-ssb_sprom.patch
new file mode 100644
index 0000000000..52d8080dfe
--- /dev/null
+++ b/target/linux/generic/patches-4.1/021-ssb_sprom.patch
@@ -0,0 +1,32 @@
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -29,10 +29,13 @@ struct ssb_sprom {
+ 	u8 il0mac[6] __aligned(sizeof(u16));	/* MAC address for 802.11b/g */
+ 	u8 et0mac[6] __aligned(sizeof(u16));	/* MAC address for Ethernet */
+ 	u8 et1mac[6] __aligned(sizeof(u16));	/* MAC address for 802.11a */
++	u8 et2mac[6] __aligned(sizeof(u16));	/* MAC address for extra Ethernet */
+ 	u8 et0phyaddr;		/* MII address for enet0 */
+ 	u8 et1phyaddr;		/* MII address for enet1 */
++	u8 et2phyaddr;		/* MII address for enet2 */
+ 	u8 et0mdcport;		/* MDIO for enet0 */
+ 	u8 et1mdcport;		/* MDIO for enet1 */
++	u8 et2mdcport;		/* MDIO for enet2 */
+ 	u16 dev_id;		/* Device ID overriding e.g. PCI ID */
+ 	u16 board_rev;		/* Board revision number from SPROM. */
+ 	u16 board_num;		/* Board number from SPROM. */
+@@ -88,11 +91,14 @@ struct ssb_sprom {
+ 	u32 ofdm5glpo;		/* 5.2GHz OFDM power offset */
+ 	u32 ofdm5gpo;		/* 5.3GHz OFDM power offset */
+ 	u32 ofdm5ghpo;		/* 5.8GHz OFDM power offset */
++	u32 boardflags;
++	u32 boardflags2;
++	u32 boardflags3;
++	/* TODO: Switch all drivers to new u32 fields and drop below ones */
+ 	u16 boardflags_lo;	/* Board flags (bits 0-15) */
+ 	u16 boardflags_hi;	/* Board flags (bits 16-31) */
+ 	u16 boardflags2_lo;	/* Board flags (bits 32-47) */
+ 	u16 boardflags2_hi;	/* Board flags (bits 48-63) */
+-	/* TODO store board flags in a single u64 */
+ 
+ 	struct ssb_sprom_core_pwr_info core_pwr_info[4];
+ 
diff --git a/target/linux/generic/patches-4.1/022-bcma-from-4.2.patch b/target/linux/generic/patches-4.1/022-bcma-from-4.2.patch
new file mode 100644
index 0000000000..ba3df18bdd
--- /dev/null
+++ b/target/linux/generic/patches-4.1/022-bcma-from-4.2.patch
@@ -0,0 +1,86 @@
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 		chip->of_node	= cc->core->dev.of_node;
+ #endif
+ 	switch (bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM4707:
+ 	case BCMA_CHIP_ID_BCM5357:
+ 	case BCMA_CHIP_ID_BCM53572:
+ 		chip->ngpio	= 32;
+@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 	}
+ 
+ 	/*
+-	 * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
+-	 * pin numbers. We don't have Device Tree there and we can't really use
+-	 * relative (per chip) numbers.
+-	 * So let's use predictable base for BCM47XX and "random" for all other.
++	 * Register SoC GPIO devices with absolute GPIO pin base.
++	 * On MIPS, we don't have Device Tree and we can't use relative (per chip)
++	 * GPIO numbers.
++	 * On some ARM devices, user space may want to access some system GPIO
++	 * pins directly, which is easier to do with a predictable GPIO base.
+ 	 */
+-#if IS_BUILTIN(CONFIG_BCM47XX)
+-	chip->base		= bus->num * BCMA_GPIO_MAX_PINS;
+-#else
+-	chip->base		= -1;
+-#endif
++	if (IS_BUILTIN(CONFIG_BCM47XX) ||
++	    cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
++		chip->base		= bus->num * BCMA_GPIO_MAX_PINS;
++	else
++		chip->base		= -1;
+ 
+ 	err = bcma_gpio_irq_domain_init(cc);
+ 	if (err)
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -29,12 +29,6 @@ config BCMA_HOST_PCI
+ 	select BCMA_DRIVER_PCI
+ 	default y
+ 
+-config BCMA_DRIVER_PCI_HOSTMODE
+-	bool "Driver for PCI core working in hostmode"
+-	depends on BCMA && MIPS && BCMA_HOST_PCI
+-	help
+-	  PCI core hostmode operation (external PCI bus).
+-
+ config BCMA_HOST_SOC
+ 	bool "Support for BCMA in a SoC"
+ 	depends on BCMA
+@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI
+ 	  This driver is also prerequisite for a hostmode PCIe core
+ 	  support.
+ 
++config BCMA_DRIVER_PCI_HOSTMODE
++	bool "Driver for PCI core working in hostmode"
++	depends on BCMA && MIPS && BCMA_DRIVER_PCI
++	help
++	  PCI core hostmode operation (external PCI bus).
++
+ config BCMA_DRIVER_MIPS
+ 	bool "BCMA Broadcom MIPS core driver"
+ 	depends on BCMA && MIPS
+--- a/include/linux/bcma/bcma_driver_pci.h
++++ b/include/linux/bcma/bcma_driver_pci.h
+@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s
+ }
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+ extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
+ extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
++#else
++static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
++{
++	return -ENOTSUPP;
++}
++static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
++{
++	return -ENOTSUPP;
++}
++#endif
+ 
+ #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
diff --git a/target/linux/generic/patches-4.1/023-bcma-from-4.4.patch b/target/linux/generic/patches-4.1/023-bcma-from-4.4.patch
new file mode 100644
index 0000000000..5704081ee4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/023-bcma-from-4.4.patch
@@ -0,0 +1,26 @@
+commit 55acca90da52b85299c033354e51ddaa7b73e019
+Author: Hante Meuleman <meuleman@broadcom.com>
+Date:   Fri Sep 18 22:08:17 2015 +0200
+
+    brcmfmac: Add support for the BCM4365 and BCM4366 PCIE devices.
+    
+    This patch adds support for the BCM4365 and BCM4366 11ac Wave2
+    PCIE devices.
+    
+    Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+    Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+    Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+    Signed-off-by: Arend van Spriel <arend@broadcom.com>
+    Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -151,6 +151,8 @@ struct bcma_host_ops {
+ #define BCMA_CORE_PCIE2			0x83C	/* PCI Express Gen2 */
+ #define BCMA_CORE_USB30_DEV		0x83D
+ #define BCMA_CORE_ARM_CR4		0x83E
++#define BCMA_CORE_ARM_CA7		0x847
++#define BCMA_CORE_SYS_MEM		0x849
+ #define BCMA_CORE_DEFAULT		0xFFF
+ 
+ #define BCMA_MAX_NR_CORES		16
diff --git a/target/linux/generic/patches-4.1/024-bcma-from-4.5.patch b/target/linux/generic/patches-4.1/024-bcma-from-4.5.patch
new file mode 100644
index 0000000000..171395dcec
--- /dev/null
+++ b/target/linux/generic/patches-4.1/024-bcma-from-4.5.patch
@@ -0,0 +1,49 @@
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -637,11 +637,36 @@ static int bcma_device_uevent(struct dev
+ 			      core->id.rev, core->id.class);
+ }
+ 
+-static int __init bcma_modinit(void)
++static unsigned int bcma_bus_registered;
++
++/*
++ * If built-in, bus has to be registered early, before any driver calls
++ * bcma_driver_register.
++ * Otherwise registering driver would trigger BUG in driver_register.
++ */
++static int __init bcma_init_bus_register(void)
+ {
+ 	int err;
+ 
++	if (bcma_bus_registered)
++		return 0;
++
+ 	err = bus_register(&bcma_bus_type);
++	if (!err)
++		bcma_bus_registered = 1;
++
++	return err;
++}
++#ifndef MODULE
++fs_initcall(bcma_init_bus_register);
++#endif
++
++/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */
++static int __init bcma_modinit(void)
++{
++	int err;
++
++	err = bcma_init_bus_register();
+ 	if (err)
+ 		return err;
+ 
+@@ -660,7 +685,7 @@ static int __init bcma_modinit(void)
+ 
+ 	return err;
+ }
+-fs_initcall(bcma_modinit);
++module_init(bcma_modinit);
+ 
+ static void __exit bcma_modexit(void)
+ {
diff --git a/target/linux/generic/patches-4.1/025-bcma-from-4.6.patch b/target/linux/generic/patches-4.1/025-bcma-from-4.6.patch
new file mode 100644
index 0000000000..c0504ac55c
--- /dev/null
+++ b/target/linux/generic/patches-4.1/025-bcma-from-4.6.patch
@@ -0,0 +1,716 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -15,6 +15,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ 
++static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++
+ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
+ 					 u32 mask, u32 value)
+ {
+@@ -113,8 +115,37 @@ int bcma_chipco_watchdog_register(struct
+ 	return 0;
+ }
+ 
++static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
++{
++	struct bcma_bus *bus = cc->core->bus;
++
++	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++	case BCMA_CC_FLASHT_STSER:
++	case BCMA_CC_FLASHT_ATSER:
++		bcma_debug(bus, "Found serial flash\n");
++		bcma_sflash_init(cc);
++		break;
++	case BCMA_CC_FLASHT_PARA:
++		bcma_debug(bus, "Found parallel flash\n");
++		bcma_pflash_init(cc);
++		break;
++	default:
++		bcma_err(bus, "Flash type not supported\n");
++	}
++
++	if (cc->core->id.rev == 38 ||
++	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
++		if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
++			bcma_debug(bus, "Found NAND flash\n");
++			bcma_nflash_init(cc);
++		}
++	}
++}
++
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
++
+ 	if (cc->early_setup_done)
+ 		return;
+ 
+@@ -129,6 +160,12 @@ void bcma_core_chipcommon_early_init(str
+ 	if (cc->capabilities & BCMA_CC_CAP_PMU)
+ 		bcma_pmu_early_init(cc);
+ 
++	if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
++		bcma_chipco_serial_init(cc);
++
++	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++		bcma_core_chipcommon_flash_detect(cc);
++
+ 	cc->early_setup_done = true;
+ }
+ 
+@@ -185,11 +222,12 @@ u32 bcma_chipco_watchdog_timer_set(struc
+ 			ticks = 2;
+ 		else if (ticks > maxt)
+ 			ticks = maxt;
+-		bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+ 	} else {
+ 		struct bcma_bus *bus = cc->core->bus;
+ 
+ 		if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
++		    bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
+ 		    bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
+ 			bcma_core_set_clockmode(cc->core,
+ 						ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
+@@ -314,9 +352,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
+ 	return res;
+ }
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+ {
++#if IS_BUILTIN(CONFIG_BCM47XX)
+ 	unsigned int irq;
+ 	u32 baud_base;
+ 	u32 i;
+@@ -358,5 +396,5 @@ void bcma_chipco_serial_init(struct bcma
+ 		ports[i].baud_base = baud_base;
+ 		ports[i].reg_shift = 0;
+ 	}
++#endif /* CONFIG_BCM47XX */
+ }
+-#endif /* CONFIG_BCMA_DRIVER_MIPS */
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -15,44 +15,44 @@
+ 
+ u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
+ 
+ void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
+ 
+ void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ 			     u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
+ 
+ void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ 				 u32 offset, u32 mask, u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
+ 
+ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ 				u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
+ 
+@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma
+ {
+ 	u32 ilp_ctl, alp_hz;
+ 
+-	if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
++	if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
+ 	      BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
+ 		return 0;
+ 
+-	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+-			BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
++	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
++			 BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+ 	usleep_range(1000, 2000);
+ 
+-	ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
++	ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+ 	ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
+ 
+-	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+ 
+ 	alp_hz = ilp_ctl * 32768 / 4;
+ 	return (alp_hz + 50000) / 100000 * 100;
+@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct b
+ 		mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
+ 			      BCMA_RES_4314_MACPHY_CLK_AVAIL);
+ 
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+ 		bcma_wait_value(cc->core, BCMA_CLKCTLST,
+ 				BCMA_CLKCTLST_HAVEHT, 0, 20000);
+ 		break;
+@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct b
+ 
+ 	/* Flush */
+ 	if (cc->pmu.rev >= 2)
+-		bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
++		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+ 
+ 	/* TODO: Do we need to update OTP? */
+ }
+@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(stru
+ 
+ 	/* Set the resource masks. */
+ 	if (min_msk)
+-		bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+ 	if (max_msk)
+-		bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+ 
+ 	/*
+ 	 * Add some delay; allow resources to come up and settle.
+@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct
+ 
+ void bcma_pmu_early_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
+ 	u32 pmucap;
+ 
+-	pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
++	if (cc->core->id.rev >= 35 &&
++	    cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
++		cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
++		if (!cc->pmu.core)
++			bcma_warn(bus, "Couldn't find expected PMU core");
++	}
++	if (!cc->pmu.core)
++		cc->pmu.core = cc->core;
++
++	pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
+ 	cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
+ 
+-	bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
+-		   cc->pmu.rev, pmucap);
++	bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
++		   pmucap);
+ }
+ 
+ void bcma_pmu_init(struct bcma_drv_cc *cc)
+ {
+ 	if (cc->pmu.rev == 1)
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
+-			      ~BCMA_CC_PMU_CTL_NOILPONW);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
++				~BCMA_CC_PMU_CTL_NOILPONW);
+ 	else
+-		bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+-			     BCMA_CC_PMU_CTL_NOILPONW);
++		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
++			       BCMA_CC_PMU_CTL_NOILPONW);
+ 
+ 	bcma_pmu_pll_init(cc);
+ 	bcma_pmu_resources_init(cc);
+@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
+ static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ 					 u32 value)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
+ }
+ 
+ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
+@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct
+ 		       bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
+ 
+ 		/* RMW only the P1 divider */
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
+ 				BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
+-		tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ 		tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
+ 		tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
+ 
+ 		/* RMW only the int feedback divider */
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
+ 				BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
+-		tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ 		tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
+ 		tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
+ 
+ 		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
+ 		break;
+@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+ 		break;
+ 	}
+ 
+-	tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
+-	bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
++	tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
+ }
+ EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bc
+ 	{ "M25P32", 0x15, 0x10000, 64, },
+ 	{ "M25P64", 0x16, 0x10000, 128, },
+ 	{ "M25FL128", 0x17, 0x10000, 256, },
++	{ "MX25L25635F", 0x18, 0x10000, 512, },
+ 	{ NULL },
+ };
+ 
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -98,6 +98,9 @@ static const struct bcma_device_id_name
+ 	{ BCMA_CORE_SHIM, "SHIM" },
+ 	{ BCMA_CORE_PCIE2, "PCIe Gen2" },
+ 	{ BCMA_CORE_ARM_CR4, "ARM CR4" },
++	{ BCMA_CORE_GCI, "GCI" },
++	{ BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
++	{ BCMA_CORE_ARM_CA7, "ARM CA7" },
+ 	{ BCMA_CORE_DEFAULT, "Default" },
+ };
+ 
+@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcm
+ 		switch (core->id.id) {
+ 		case BCMA_CORE_4706_MAC_GBIT_COMMON:
+ 		case BCMA_CORE_NS_CHIPCOMMON_B:
++		case BCMA_CORE_PMU:
++		case BCMA_CORE_GCI:
+ 		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
+ 			break;
+ 		default:
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(str
+ 	case B43_BUS_BCMA:
+ 		bcma_cc = &dev->dev->bdev->bus->drv_cc;
+ 
+-		bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
+-		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+-		bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
+-		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
++		bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
++		bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
++		bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
++		bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
+ 		break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -151,6 +151,8 @@ struct bcma_host_ops {
+ #define BCMA_CORE_PCIE2			0x83C	/* PCI Express Gen2 */
+ #define BCMA_CORE_USB30_DEV		0x83D
+ #define BCMA_CORE_ARM_CR4		0x83E
++#define BCMA_CORE_GCI			0x840
++#define BCMA_CORE_CMEM			0x846	/* CNDS DDR2/3 memory controller */
+ #define BCMA_CORE_ARM_CA7		0x847
+ #define BCMA_CORE_SYS_MEM		0x849
+ #define BCMA_CORE_DEFAULT		0xFFF
+@@ -200,6 +202,7 @@ struct bcma_host_ops {
+ #define  BCMA_PKG_ID_BCM4707	1
+ #define  BCMA_PKG_ID_BCM4708	2
+ #define  BCMA_PKG_ID_BCM4709	0
++#define BCMA_CHIP_ID_BCM47094	53030
+ #define BCMA_CHIP_ID_BCM53018	53018
+ 
+ /* Board types (on PCI usually equals to the subsystem dev id) */
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -217,6 +217,11 @@
+ #define	 BCMA_CC_CLKDIV_JTAG_SHIFT	8
+ #define	 BCMA_CC_CLKDIV_UART		0x000000FF
+ #define BCMA_CC_CAP_EXT			0x00AC		/* Capabilities */
++#define  BCMA_CC_CAP_EXT_SECI_PRESENT	0x00000001
++#define  BCMA_CC_CAP_EXT_GSIO_PRESENT	0x00000002
++#define  BCMA_CC_CAP_EXT_GCI_PRESENT	0x00000004
++#define  BCMA_CC_CAP_EXT_SECI_PUART_PRESENT		0x00000008    /* UART present */
++#define  BCMA_CC_CAP_EXT_AOB_PRESENT	0x00000040
+ #define BCMA_CC_PLLONDELAY		0x00B0		/* Rev >= 4 only */
+ #define BCMA_CC_FREFSELDELAY		0x00B4		/* Rev >= 4 only */
+ #define BCMA_CC_SLOWCLKCTL		0x00B8		/* 6 <= Rev <= 9 only */
+@@ -351,12 +356,12 @@
+ #define BCMA_CC_PMU_RES_REQTS		0x0640 /* PMU res req timer sel */
+ #define BCMA_CC_PMU_RES_REQT		0x0644 /* PMU res req timer */
+ #define BCMA_CC_PMU_RES_REQM		0x0648 /* PMU res req mask */
+-#define BCMA_CC_CHIPCTL_ADDR		0x0650
+-#define BCMA_CC_CHIPCTL_DATA		0x0654
+-#define BCMA_CC_REGCTL_ADDR		0x0658
+-#define BCMA_CC_REGCTL_DATA		0x065C
+-#define BCMA_CC_PLLCTL_ADDR		0x0660
+-#define BCMA_CC_PLLCTL_DATA		0x0664
++#define BCMA_CC_PMU_CHIPCTL_ADDR	0x0650
++#define BCMA_CC_PMU_CHIPCTL_DATA	0x0654
++#define BCMA_CC_PMU_REGCTL_ADDR		0x0658
++#define BCMA_CC_PMU_REGCTL_DATA		0x065C
++#define BCMA_CC_PMU_PLLCTL_ADDR		0x0660
++#define BCMA_CC_PMU_PLLCTL_DATA		0x0664
+ #define BCMA_CC_PMU_STRAPOPT		0x0668 /* (corerev >= 28) */
+ #define BCMA_CC_PMU_XTAL_FREQ		0x066C /* (pmurev >= 10) */
+ #define  BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK	0x00001FFF
+@@ -566,17 +571,16 @@
+  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+  */
+ struct bcma_chipcommon_pmu {
++	struct bcma_device *core;	/* Can be separated core or just ChipCommon one */
+ 	u8 rev;			/* PMU revision */
+ 	u32 crystalfreq;	/* The active crystal frequency (in kHz) */
+ };
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ struct bcma_pflash {
+ 	bool present;
+-	u8 buswidth;
+-	u32 window;
+-	u32 window_size;
+ };
++#endif
+ 
+ #ifdef CONFIG_BCMA_SFLASH
+ struct bcma_sflash {
+@@ -602,6 +606,7 @@ struct bcma_nflash {
+ };
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_serial_port {
+ 	void *regs;
+ 	unsigned long clockspeed;
+@@ -621,8 +626,9 @@ struct bcma_drv_cc {
+ 	/* Fast Powerup Delay constant */
+ 	u16 fast_pwrup_delay;
+ 	struct bcma_chipcommon_pmu pmu;
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ 	struct bcma_pflash pflash;
++#endif
+ #ifdef CONFIG_BCMA_SFLASH
+ 	struct bcma_sflash sflash;
+ #endif
+@@ -630,6 +636,7 @@ struct bcma_drv_cc {
+ 	struct bcma_nflash nflash;
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_MIPS
+ 	int nr_serial_ports;
+ 	struct bcma_serial_port serial_ports[4];
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+@@ -663,6 +670,19 @@ struct bcma_drv_cc_b {
+ #define bcma_cc_maskset32(cc, offset, mask, set) \
+ 	bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+ 
++/* PMU registers access */
++#define bcma_pmu_read32(cc, offset) \
++	bcma_read32((cc)->pmu.core, offset)
++#define bcma_pmu_write32(cc, offset, val) \
++	bcma_write32((cc)->pmu.core, offset, val)
++
++#define bcma_pmu_mask32(cc, offset, mask) \
++	bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
++#define bcma_pmu_set32(cc, offset, set) \
++	bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
++#define bcma_pmu_maskset32(cc, offset, mask, set) \
++	bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
++
+ extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+ 
+ extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -44,10 +44,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
+ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+-extern struct platform_device bcma_pflash_dev;
+-#endif /* CONFIG_BCMA_DRIVER_MIPS */
+ 
+ /* driver_chipcommon_b.c */
+ int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
+@@ -59,6 +55,21 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
+ 
++/**************************************************
++ * driver_chipcommon_sflash.c
++ **************************************************/
++
++#ifdef CONFIG_BCMA_PFLASH
++extern struct platform_device bcma_pflash_dev;
++int bcma_pflash_init(struct bcma_drv_cc *cc);
++#else
++static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
++{
++	bcma_err(cc->core->bus, "Parallel flash not supported\n");
++	return 0;
++}
++#endif /* CONFIG_BCMA_PFLASH */
++
+ #ifdef CONFIG_BCMA_SFLASH
+ /* driver_chipcommon_sflash.c */
+ int bcma_sflash_init(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -229,6 +229,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 	case BCMA_CHIP_ID_BCM4707:
+ 	case BCMA_CHIP_ID_BCM5357:
+ 	case BCMA_CHIP_ID_BCM53572:
++	case BCMA_CHIP_ID_BCM47094:
+ 		chip->ngpio	= 32;
+ 		break;
+ 	default:
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -14,8 +14,6 @@
+ 
+ #include <linux/bcma/bcma.h>
+ 
+-#include <linux/mtd/physmap.h>
+-#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+@@ -32,26 +30,6 @@ enum bcma_boot_dev {
+ 	BCMA_BOOT_DEV_NAND,
+ };
+ 
+-static const char * const part_probes[] = { "bcm47xxpart", NULL };
+-
+-static struct physmap_flash_data bcma_pflash_data = {
+-	.part_probe_types	= part_probes,
+-};
+-
+-static struct resource bcma_pflash_resource = {
+-	.name	= "bcma_pflash",
+-	.flags  = IORESOURCE_MEM,
+-};
+-
+-struct platform_device bcma_pflash_dev = {
+-	.name		= "physmap-flash",
+-	.dev		= {
+-		.platform_data  = &bcma_pflash_data,
+-	},
+-	.resource	= &bcma_pflash_resource,
+-	.num_resources	= 1,
+-};
+-
+ /* The 47162a0 hangs when reading MIPS DMP registers registers */
+ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+ {
+@@ -272,48 +250,11 @@ static enum bcma_boot_dev bcma_boot_dev(
+ 	return BCMA_BOOT_DEV_SERIAL;
+ }
+ 
+-static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
+ {
+ 	struct bcma_bus *bus = mcore->core->bus;
+-	struct bcma_drv_cc *cc = &bus->drv_cc;
+-	struct bcma_pflash *pflash = &cc->pflash;
+ 	enum bcma_boot_dev boot_dev;
+ 
+-	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+-	case BCMA_CC_FLASHT_STSER:
+-	case BCMA_CC_FLASHT_ATSER:
+-		bcma_debug(bus, "Found serial flash\n");
+-		bcma_sflash_init(cc);
+-		break;
+-	case BCMA_CC_FLASHT_PARA:
+-		bcma_debug(bus, "Found parallel flash\n");
+-		pflash->present = true;
+-		pflash->window = BCMA_SOC_FLASH2;
+-		pflash->window_size = BCMA_SOC_FLASH2_SZ;
+-
+-		if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
+-		     BCMA_CC_FLASH_CFG_DS) == 0)
+-			pflash->buswidth = 1;
+-		else
+-			pflash->buswidth = 2;
+-
+-		bcma_pflash_data.width = pflash->buswidth;
+-		bcma_pflash_resource.start = pflash->window;
+-		bcma_pflash_resource.end = pflash->window + pflash->window_size;
+-
+-		break;
+-	default:
+-		bcma_err(bus, "Flash type not supported\n");
+-	}
+-
+-	if (cc->core->id.rev == 38 ||
+-	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+-		if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
+-			bcma_debug(bus, "Found NAND flash\n");
+-			bcma_nflash_init(cc);
+-		}
+-	}
+-
+ 	/* Determine flash type this SoC boots from */
+ 	boot_dev = bcma_boot_dev(bus);
+ 	switch (boot_dev) {
+@@ -337,13 +278,10 @@ static void bcma_core_mips_flash_detect(
+ 
+ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
+ {
+-	struct bcma_bus *bus = mcore->core->bus;
+-
+ 	if (mcore->early_setup_done)
+ 		return;
+ 
+-	bcma_chipco_serial_init(&bus->drv_cc);
+-	bcma_core_mips_flash_detect(mcore);
++	bcma_core_mips_nvram_init(mcore);
+ 
+ 	mcore->early_setup_done = true;
+ }
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -294,7 +294,7 @@ static const struct pci_device_id bcma_p
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
+ 
+ 	  If unsure, say N
+ 
++config BCMA_PFLASH
++	bool
++	depends on BCMA_DRIVER_MIPS
++	default y
++
+ config BCMA_SFLASH
+ 	bool
+ 	depends on BCMA_DRIVER_MIPS
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -1,6 +1,7 @@
+ bcma-y					+= main.o scan.o core.o sprom.o
+ bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
+ bcma-y					+= driver_chipcommon_b.o
++bcma-$(CONFIG_BCMA_PFLASH)		+= driver_chipcommon_pflash.o
+ bcma-$(CONFIG_BCMA_SFLASH)		+= driver_chipcommon_sflash.o
+ bcma-$(CONFIG_BCMA_NFLASH)		+= driver_chipcommon_nflash.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI)		+= driver_pci.o
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_pflash.c
+@@ -0,0 +1,49 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon parallel flash
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data bcma_pflash_data = {
++	.part_probe_types	= part_probes,
++};
++
++static struct resource bcma_pflash_resource = {
++	.name	= "bcma_pflash",
++	.flags  = IORESOURCE_MEM,
++};
++
++struct platform_device bcma_pflash_dev = {
++	.name		= "physmap-flash",
++	.dev		= {
++		.platform_data  = &bcma_pflash_data,
++	},
++	.resource	= &bcma_pflash_resource,
++	.num_resources	= 1,
++};
++
++int bcma_pflash_init(struct bcma_drv_cc *cc)
++{
++	struct bcma_pflash *pflash = &cc->pflash;
++
++	pflash->present = true;
++
++	if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
++		bcma_pflash_data.width = 1;
++	else
++		bcma_pflash_data.width = 2;
++
++	bcma_pflash_resource.start = BCMA_SOC_FLASH2;
++	bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
++
++	return 0;
++}
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -325,7 +325,7 @@ static int bcma_register_devices(struct
+ 		bcma_register_core(bus, core);
+ 	}
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ 	if (bus->drv_cc.pflash.present) {
+ 		err = platform_device_register(&bcma_pflash_dev);
+ 		if (err)
diff --git a/target/linux/generic/patches-4.1/030-backport_bcm47xx_nvram.patch b/target/linux/generic/patches-4.1/030-backport_bcm47xx_nvram.patch
new file mode 100644
index 0000000000..c20f05e079
--- /dev/null
+++ b/target/linux/generic/patches-4.1/030-backport_bcm47xx_nvram.patch
@@ -0,0 +1,37 @@
+--- a/include/linux/bcm47xx_nvram.h
++++ b/include/linux/bcm47xx_nvram.h
+@@ -10,11 +10,17 @@
+ 
+ #include <linux/types.h>
+ #include <linux/kernel.h>
++#include <linux/vmalloc.h>
+ 
+-#ifdef CONFIG_BCM47XX
++#ifdef CONFIG_BCM47XX_NVRAM
+ int bcm47xx_nvram_init_from_mem(u32 base, u32 lim);
+ int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+ int bcm47xx_nvram_gpio_pin(const char *name);
++char *bcm47xx_nvram_get_contents(size_t *val_len);
++static inline void bcm47xx_nvram_release_contents(char *nvram)
++{
++	vfree(nvram);
++};
+ #else
+ static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
+ {
+@@ -29,6 +35,15 @@ static inline int bcm47xx_nvram_gpio_pin
+ {
+ 	return -ENOTSUPP;
+ };
++
++static inline char *bcm47xx_nvram_get_contents(size_t *val_len)
++{
++	return NULL;
++};
++
++static inline void bcm47xx_nvram_release_contents(char *nvram)
++{
++};
+ #endif
+ 
+ #endif /* __BCM47XX_NVRAM_H */
diff --git a/target/linux/generic/patches-4.1/040-fs-overlay-fix-stacking.patch b/target/linux/generic/patches-4.1/040-fs-overlay-fix-stacking.patch
new file mode 100644
index 0000000000..6474da6ebf
--- /dev/null
+++ b/target/linux/generic/patches-4.1/040-fs-overlay-fix-stacking.patch
@@ -0,0 +1,33 @@
+From 1c8a47df36d72ace8cf78eb6c228aa0f8027d3c2 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <miklos@szeredi.hu>
+Date: Mon, 12 Oct 2015 15:56:20 +0200
+Subject: ovl: fix open in stacked overlay
+
+If two overlayfs filesystems are stacked on top of each other, then we need
+recursion in ovl_d_select_inode().
+
+I guess d_backing_inode() is supposed to do that.  But currently it doesn't
+and that functionality is open coded in vfs_open().  This is now copied
+into ovl_d_select_inode() to fix this regression.
+
+Reported-by: Alban Crequy <alban.crequy@gmail.com>
+Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
+Fixes: 4bacc9c9234c ("overlayfs: Make f_path always point to the overlay...")
+Cc: David Howells <dhowells@redhat.com>
+Cc: <stable@vger.kernel.org> # v4.2+
+---
+ fs/overlayfs/inode.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/overlayfs/inode.c
++++ b/fs/overlayfs/inode.c
+@@ -383,6 +383,9 @@ struct inode *ovl_d_select_inode(struct
+ 		ovl_path_upper(dentry, &realpath);
+ 	}
+ 
++	if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE)
++		return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags);
++
+ 	return d_backing_inode(realpath.dentry);
+ }
+ 
diff --git a/target/linux/generic/patches-4.1/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch b/target/linux/generic/patches-4.1/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch
new file mode 100644
index 0000000000..0b02fff39b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch
@@ -0,0 +1,32 @@
+From 1ae92642e5900316011736072b4fa91710840620 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 18 Jun 2016 17:53:45 +0200
+Subject: [PATCH] ubifs: Silence error output if MS_SILENT is set
+
+This change completes commit
+90bea5a3f0 ("UBIFS: respect MS_SILENT mount flag")
+which already implements support for MS_SILENT except for that one
+error message which is still being displayed despite MS_SILENT being
+set. Suppress that error message as well in case MS_SILENT is set.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+[rw: massaged commit message]
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ fs/ubifs/super.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -2104,8 +2104,9 @@ static struct dentry *ubifs_mount(struct
+ 	 */
+ 	ubi = open_ubi(name, UBI_READONLY);
+ 	if (IS_ERR(ubi)) {
+-		pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
+-		       current->pid, name, (int)PTR_ERR(ubi));
++		if (!(flags & MS_SILENT))
++			pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
++			       current->pid, name, (int)PTR_ERR(ubi));
+ 		return ERR_CAST(ubi);
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.1/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch b/target/linux/generic/patches-4.1/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch
new file mode 100644
index 0000000000..cbcacd43eb
--- /dev/null
+++ b/target/linux/generic/patches-4.1/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch
@@ -0,0 +1,54 @@
+From dccbc9197d2c3614f2fd6811874e1d982e4415f0 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 19 Jul 2016 00:26:55 +0200
+Subject: [PATCH] ubifs: Silence early error messages if MS_SILENT is set
+
+Probe-mounting a volume too small for UBIFS results in kernel log
+polution which might irritate users.
+Address this by silencing errors which may happen during boot if the
+rootfs is e.g. squashfs (and thus rather small) stored on a UBI volume.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ fs/ubifs/super.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -516,19 +516,19 @@ static int init_constants_early(struct u
+ 	c->max_write_shift = fls(c->max_write_size) - 1;
+ 
+ 	if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+-		ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
+-			  c->leb_size, UBIFS_MIN_LEB_SZ);
++		ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
++			   c->leb_size, UBIFS_MIN_LEB_SZ);
+ 		return -EINVAL;
+ 	}
+ 
+ 	if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+-		ubifs_err(c, "too few LEBs (%d), min. is %d",
+-			  c->leb_cnt, UBIFS_MIN_LEB_CNT);
++		ubifs_errc(c, "too few LEBs (%d), min. is %d",
++			   c->leb_cnt, UBIFS_MIN_LEB_CNT);
+ 		return -EINVAL;
+ 	}
+ 
+ 	if (!is_power_of_2(c->min_io_size)) {
+-		ubifs_err(c, "bad min. I/O size %d", c->min_io_size);
++		ubifs_errc(c, "bad min. I/O size %d", c->min_io_size);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -539,8 +539,8 @@ static int init_constants_early(struct u
+ 	if (c->max_write_size < c->min_io_size ||
+ 	    c->max_write_size % c->min_io_size ||
+ 	    !is_power_of_2(c->max_write_size)) {
+-		ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
+-			  c->max_write_size, c->min_io_size);
++		ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
++			   c->max_write_size, c->min_io_size);
+ 		return -EINVAL;
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch b/target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch
new file mode 100644
index 0000000000..9a6d837de8
--- /dev/null
+++ b/target/linux/generic/patches-4.1/050-backport_netfilter_rtcache.patch
@@ -0,0 +1,505 @@
+Subject: netfilter: conntrack: cache route for forwarded connections
+
+... to avoid per-packet FIB lookup if possible.
+
+The cached dst is re-used provided the input interface
+is the same as that of the previous packet in the same direction.
+
+If not, the cached dst is invalidated.
+
+For ipv6 we also need to store sernum, else dst_check doesn't work,
+pointed out by Eric Dumazet.
+
+This should speed up forwarding when conntrack is already in use
+anyway, especially when using reverse path filtering -- active RPF
+enforces two FIB lookups for each packet.
+
+Before the routing cache removal this didn't matter since RPF was performed
+only when route cache didn't yield a result; but without route cache it
+comes at higher price.
+
+Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
+avoid holding on to dsts of 'frozen' conntracks.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+
+--- a/include/net/netfilter/nf_conntrack_extend.h
++++ b/include/net/netfilter/nf_conntrack_extend.h
+@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
+ #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
+ 	NF_CT_EXT_SYNPROXY,
+ #endif
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++	NF_CT_EXT_RTCACHE,
++#endif
+ 	NF_CT_EXT_NUM,
+ };
+ 
+@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
+ #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+ #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
+ #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
+ 
+ /* Extensions: optional stuff which isn't permanently in struct. */
+ struct nf_ct_ext {
+--- /dev/null
++++ b/include/net/netfilter/nf_conntrack_rtcache.h
+@@ -0,0 +1,34 @@
++#include <linux/gfp.h>
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++
++struct dst_entry;
++
++struct nf_conn_dst_cache {
++	struct dst_entry *dst;
++	int iif;
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	u32 cookie;
++#endif
++
++};
++
++struct nf_conn_rtcache {
++	struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
++};
++
++static inline
++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++	return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
++#else
++	return NULL;
++#endif
++}
++
++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
++					  enum ip_conntrack_dir dir)
++{
++	return rtc->cached_dst[dir].iif;
++}
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS
+ 
+ 	  If unsure, say `N'.
+ 
++config NF_CONNTRACK_RTCACHE
++	tristate "Cache route entries in conntrack objects"
++	depends on NETFILTER_ADVANCED
++	depends on NF_CONNTRACK
++	help
++	  If this option is enabled, the connection tracking code will
++	  cache routing information for each connection that is being
++	  forwarded, at a cost of 32 bytes per conntrack object.
++
++	  To compile it as a module, choose M here.  If unsure, say N.
++	  The module will be called nf_conntrack_rtcache.
++
+ config NF_CONNTRACK_TIMEOUT
+ 	bool  'Connection tracking timeout'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
+ # connection tracking
+ obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
+ 
++# optional conntrack route cache extension
++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
++
+ # SCTP protocol connection tracking
+ obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
+ obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
+--- /dev/null
++++ b/net/netfilter/nf_conntrack_rtcache.c
+@@ -0,0 +1,387 @@
++/* route cache for netfilter.
++ *
++ * (C) 2014 Red Hat GmbH
++ *
++ * 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.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/types.h>
++#include <linux/netfilter.h>
++#include <linux/skbuff.h>
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/export.h>
++#include <linux/module.h>
++
++#include <net/dst.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++#include <net/netfilter/nf_conntrack_rtcache.h>
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++#include <net/ip6_fib.h>
++#endif
++
++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
++				      enum ip_conntrack_dir dir)
++{
++	struct dst_entry *dst = rtc->cached_dst[dir].dst;
++
++	dst_release(dst);
++}
++
++static void nf_conn_rtcache_destroy(struct nf_conn *ct)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++	if (!rtc)
++		return;
++
++	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
++	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
++}
++
++static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
++{
++	struct nf_conn_rtcache *rtc;
++
++	rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
++	if (rtc) {
++		rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
++		rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
++		rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
++		rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
++	}
++}
++
++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
++{
++	if (nf_ct_is_untracked(ct))
++		return NULL;
++	return nf_ct_rtcache_find(ct);
++}
++
++static struct dst_entry *
++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
++			enum ip_conntrack_dir dir)
++{
++	return rtc->cached_dst[dir].dst;
++}
++
++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	if (pf == NFPROTO_IPV6) {
++		const struct rt6_info *rt = (const struct rt6_info *)dst;
++
++		if (rt->rt6i_node)
++			return (u32)rt->rt6i_node->fn_sernum;
++	}
++#endif
++	return 0;
++}
++
++static void nf_conn_rtcache_dst_set(int pf,
++				    struct nf_conn_rtcache *rtc,
++				    struct dst_entry *dst,
++				    enum ip_conntrack_dir dir, int iif)
++{
++	if (rtc->cached_dst[dir].iif != iif)
++		rtc->cached_dst[dir].iif = iif;
++
++	if (rtc->cached_dst[dir].dst != dst) {
++		struct dst_entry *old;
++
++		dst_hold(dst);
++
++		old = xchg(&rtc->cached_dst[dir].dst, dst);
++		dst_release(old);
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++		if (pf == NFPROTO_IPV6)
++			rtc->cached_dst[dir].cookie =
++				nf_rtcache_get_cookie(pf, dst);
++#endif
++	}
++}
++
++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
++					 enum ip_conntrack_dir dir)
++{
++	struct dst_entry *old;
++
++	pr_debug("Invalidate iif %d for dir %d on cache %p\n",
++		 rtc->cached_dst[dir].iif, dir, rtc);
++
++	old = xchg(&rtc->cached_dst[dir].dst, NULL);
++	dst_release(old);
++	rtc->cached_dst[dir].iif = -1;
++}
++
++static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops,
++				  struct sk_buff *skb,
++				  const struct nf_hook_state *state)
++{
++	struct nf_conn_rtcache *rtc;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct dst_entry *dst;
++	struct nf_conn *ct;
++	int iif;
++	u32 cookie;
++
++	if (skb_dst(skb) || skb->sk)
++		return NF_ACCEPT;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return NF_ACCEPT;
++
++	rtc = nf_ct_rtcache_find_usable(ct);
++	if (!rtc)
++		return NF_ACCEPT;
++
++	/* if iif changes, don't use cache and let ip stack
++	 * do route lookup.
++	 *
++	 * If rp_filter is enabled it might toss skb, so
++	 * we don't want to avoid these checks.
++	 */
++	dir = CTINFO2DIR(ctinfo);
++	iif = nf_conn_rtcache_iif_get(rtc, dir);
++	if (state->in->ifindex != iif) {
++		pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
++			 ct, iif, state->in->ifindex);
++		return NF_ACCEPT;
++	}
++	dst = nf_conn_rtcache_dst_get(rtc, dir);
++	if (dst == NULL)
++		return NF_ACCEPT;
++
++	cookie = nf_rtcache_get_cookie(ops->pf, dst);
++
++	dst = dst_check(dst, cookie);
++	pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
++	if (likely(dst))
++		skb_dst_set_noref(skb, dst);
++	else
++		nf_conn_rtcache_dst_obsolete(rtc, dir);
++
++	return NF_ACCEPT;
++}
++
++static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops,
++				       struct sk_buff *skb,
++				       const struct nf_hook_state *state)
++{
++	struct nf_conn_rtcache *rtc;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct nf_conn *ct;
++	struct dst_entry *dst = skb_dst(skb);
++	int iif;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return NF_ACCEPT;
++
++	if (dst && dst_xfrm(dst))
++		return NF_ACCEPT;
++
++	if (!nf_ct_is_confirmed(ct)) {
++		if (WARN_ON(nf_ct_rtcache_find(ct)))
++			return NF_ACCEPT;
++		nf_ct_rtcache_ext_add(ct);
++		return NF_ACCEPT;
++	}
++
++	rtc = nf_ct_rtcache_find_usable(ct);
++	if (!rtc)
++		return NF_ACCEPT;
++
++	dir = CTINFO2DIR(ctinfo);
++	iif = nf_conn_rtcache_iif_get(rtc, dir);
++	pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
++		 ct, skb, dir, iif, state->in->ifindex);
++	if (likely(state->in->ifindex == iif))
++		return NF_ACCEPT;
++
++	nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, state->in->ifindex);
++	return NF_ACCEPT;
++}
++
++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++	struct net_device *dev = data;
++
++	if (!rtc)
++		return 0;
++
++	if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
++	    dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
++		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
++		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
++	}
++
++	return 0;
++}
++
++static int nf_rtcache_netdev_event(struct notifier_block *this,
++				   unsigned long event, void *ptr)
++{
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++	struct net *net = dev_net(dev);
++
++	if (event == NETDEV_DOWN)
++		nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
++
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block nf_rtcache_notifier = {
++	.notifier_call = nf_rtcache_netdev_event,
++};
++
++static struct nf_hook_ops rtcache_ops[] = {
++	{
++		.hook		= nf_rtcache_in,
++		.owner		= THIS_MODULE,
++		.pf		= NFPROTO_IPV4,
++		.hooknum	= NF_INET_PRE_ROUTING,
++		.priority       = NF_IP_PRI_LAST,
++	},
++	{
++		.hook           = nf_rtcache_forward,
++		.owner          = THIS_MODULE,
++		.pf             = NFPROTO_IPV4,
++		.hooknum        = NF_INET_FORWARD,
++		.priority       = NF_IP_PRI_LAST,
++	},
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	{
++		.hook		= nf_rtcache_in,
++		.owner		= THIS_MODULE,
++		.pf		= NFPROTO_IPV6,
++		.hooknum	= NF_INET_PRE_ROUTING,
++		.priority       = NF_IP_PRI_LAST,
++	},
++	{
++		.hook           = nf_rtcache_forward,
++		.owner          = THIS_MODULE,
++		.pf             = NFPROTO_IPV6,
++		.hooknum        = NF_INET_FORWARD,
++		.priority       = NF_IP_PRI_LAST,
++	},
++#endif
++};
++
++static struct nf_ct_ext_type rtcache_extend __read_mostly = {
++	.len	= sizeof(struct nf_conn_rtcache),
++	.align	= __alignof__(struct nf_conn_rtcache),
++	.id	= NF_CT_EXT_RTCACHE,
++	.destroy = nf_conn_rtcache_destroy,
++};
++
++static int __init nf_conntrack_rtcache_init(void)
++{
++	int ret = nf_ct_extend_register(&rtcache_extend);
++
++	if (ret < 0) {
++		pr_err("nf_conntrack_rtcache: Unable to register extension\n");
++		return ret;
++	}
++
++	ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++	if (ret < 0) {
++		nf_ct_extend_unregister(&rtcache_extend);
++		return ret;
++	}
++
++	ret = register_netdevice_notifier(&nf_rtcache_notifier);
++	if (ret) {
++		nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++		nf_ct_extend_unregister(&rtcache_extend);
++	}
++
++	return ret;
++}
++
++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++	return rtc != NULL;
++}
++
++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
++{
++	bool wait = false;
++	int cpu;
++
++	for_each_possible_cpu(cpu) {
++		struct nf_conntrack_tuple_hash *h;
++		struct hlist_nulls_node *n;
++		struct nf_conn *ct;
++		struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
++
++		rcu_read_lock();
++		spin_lock_bh(&pcpu->lock);
++
++		hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
++			ct = nf_ct_tuplehash_to_ctrack(h);
++			if (nf_ct_rtcache_find(ct) != NULL) {
++				wait = true;
++				break;
++			}
++		}
++		spin_unlock_bh(&pcpu->lock);
++		rcu_read_unlock();
++	}
++
++	return wait;
++}
++
++static void __exit nf_conntrack_rtcache_fini(void)
++{
++	struct net *net;
++	int count = 0;
++
++	/* remove hooks so no new connections get rtcache extension */
++	nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++
++	synchronize_net();
++
++	unregister_netdevice_notifier(&nf_rtcache_notifier);
++
++	rtnl_lock();
++
++	/* zap all conntracks with rtcache extension */
++	for_each_net(net)
++		nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
++
++	for_each_net(net) {
++		/* .. and make sure they're gone from dying list, too */
++		while (nf_conntrack_rtcache_wait_for_dying(net)) {
++			msleep(200);
++			WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
++		}
++	}
++
++	rtnl_unlock();
++	synchronize_net();
++	nf_ct_extend_unregister(&rtcache_extend);
++}
++module_init(nf_conntrack_rtcache_init);
++module_exit(nf_conntrack_rtcache_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
++MODULE_DESCRIPTION("Conntrack route cache extension");
diff --git a/target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch b/target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch
new file mode 100644
index 0000000000..d215b80ab2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/060-mips_decompressor_memmove.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/boot/compressed/string.c
++++ b/arch/mips/boot/compressed/string.c
+@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
+ 		ss[i] = c;
+ 	return s;
+ }
++
++void *memmove(void *__dest, __const void *__src, size_t count)
++{
++	unsigned char *d = __dest;
++	const unsigned char *s = __src;
++
++	if (__dest == __src)
++		return __dest;
++
++	if (__dest < __src)
++		return memcpy(__dest, __src, count);
++
++	while (count--)
++		d[count] = s[count];
++	return __dest;
++}
diff --git a/target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch b/target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
new file mode 100644
index 0000000000..512df943e9
--- /dev/null
+++ b/target/linux/generic/patches-4.1/072-13-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 13 Apr 2015 15:54:04 +0200
+Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
+
+Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -198,9 +198,9 @@
+ #define  BGMAC_CMDCFG_TAI			0x00000200
+ #define  BGMAC_CMDCFG_HD			0x00000400	/* Set if in half duplex mode */
+ #define  BGMAC_CMDCFG_HD_SHIFT			10
+-#define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for other revs */
+-#define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, only for core rev 4 */
+-#define  BGMAC_CMDCFG_SR(rev)  ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
++#define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for core rev 0-3 */
++#define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, for core rev >= 4 */
++#define  BGMAC_CMDCFG_SR(rev)  ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
+ #define  BGMAC_CMDCFG_ML			0x00008000	/* Set to activate mac loopback mode */
+ #define  BGMAC_CMDCFG_AE			0x00400000
+ #define  BGMAC_CMDCFG_CFE			0x00800000
diff --git a/target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch b/target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch
new file mode 100644
index 0000000000..ddba71d430
--- /dev/null
+++ b/target/linux/generic/patches-4.1/072-14-bgmac-reset-all-4-GMAC-cores-on-init.patch
@@ -0,0 +1,28 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 13 Apr 2015 15:56:26 +0200
+Subject: [PATCH] bgmac: reset all 4 GMAC cores on init
+
+On a BCM4709 based device, I found that GMAC cores may be enabled at
+probe time, but only become usable after a full reset.
+Disable cores before re-enabling them to ensure that they are properly
+reset.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1623,8 +1623,11 @@ static int bgmac_probe(struct bcma_devic
+ 			ns_core = bcma_find_core_unit(core->bus,
+ 						      BCMA_CORE_MAC_GBIT,
+ 						      ns_gmac);
+-			if (ns_core && !bcma_core_is_enabled(ns_core))
+-				bcma_core_enable(ns_core, 0);
++			if (!ns_core)
++				continue;
++
++			bcma_core_disable(ns_core, 0);
++			bcma_core_enable(ns_core, 0);
+ 		}
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch b/target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
new file mode 100644
index 0000000000..629731c2c2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
@@ -0,0 +1,101 @@
+From: Florian Westphal <fw@strlen.de>
+Date: Thu, 17 Sep 2015 11:24:48 +0100
+Subject: [PATCH] ipv6: ip6_fragment: fix headroom tests and skb leak
+
+David Woodhouse reports skb_under_panic when we try to push ethernet
+header to fragmented ipv6 skbs:
+
+ skbuff: skb_under_panic: text:c1277f1e len:1294 put:14 head:dec98000
+ data:dec97ffc tail:0xdec9850a end:0xdec98f40 dev:br-lan
+[..]
+ip6_finish_output2+0x196/0x4da
+
+David further debugged this:
+  [..] offending fragments were arriving here with skb_headroom(skb)==10.
+  Which is reasonable, being the Solos ADSL card's header of 8 bytes
+  followed by 2 bytes of PPP frame type.
+
+The problem is that if netfilter ipv6 defragmentation is used, skb_cow()
+in ip6_forward will only see reassembled skb.
+
+Therefore, headroom is overestimated by 8 bytes (we pulled fragment
+header) and we don't check the skbs in the frag_list either.
+
+We can't do these checks in netfilter defrag since outdev isn't known yet.
+
+Furthermore, existing tests in ip6_fragment did not consider the fragment
+or ipv6 header size when checking headroom of the fraglist skbs.
+
+While at it, also fix a skb leak on memory allocation -- ip6_fragment
+must consume the skb.
+
+I tested this e1000 driver hacked to not allocate additional headroom
+(we end up in slowpath, since LL_RESERVED_SPACE is 16).
+
+If 2 bytes of headroom are allocated, fastpath is taken (14 byte
+ethernet header was pulled, so 16 byte headroom available in all
+fragments).
+
+Reported-by: David Woodhouse <dwmw2@infradead.org>
+Diagnosed-by: David Woodhouse <dwmw2@infradead.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Closes 20532
+---
+
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -587,20 +587,22 @@ int ip6_fragment(struct sock *sk, struct
+ 	}
+ 	mtu -= hlen + sizeof(struct frag_hdr);
+ 
++	hroom = LL_RESERVED_SPACE(rt->dst.dev);
+ 	if (skb_has_frag_list(skb)) {
+ 		int first_len = skb_pagelen(skb);
+ 		struct sk_buff *frag2;
+ 
+ 		if (first_len - hlen > mtu ||
+ 		    ((first_len - hlen) & 7) ||
+-		    skb_cloned(skb))
++		    skb_cloned(skb) ||
++		    skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
+ 			goto slow_path;
+ 
+ 		skb_walk_frags(skb, frag) {
+ 			/* Correct geometry. */
+ 			if (frag->len > mtu ||
+ 			    ((frag->len & 7) && frag->next) ||
+-			    skb_headroom(frag) < hlen)
++			    skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
+ 				goto slow_path_clean;
+ 
+ 			/* Partially cloned skb? */
+@@ -617,8 +619,6 @@ int ip6_fragment(struct sock *sk, struct
+ 
+ 		err = 0;
+ 		offset = 0;
+-		frag = skb_shinfo(skb)->frag_list;
+-		skb_frag_list_init(skb);
+ 		/* BUILD HEADER */
+ 
+ 		*prevhdr = NEXTHDR_FRAGMENT;
+@@ -626,8 +626,11 @@ int ip6_fragment(struct sock *sk, struct
+ 		if (!tmp_hdr) {
+ 			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
+ 				      IPSTATS_MIB_FRAGFAILS);
+-			return -ENOMEM;
++			err = -ENOMEM;
++			goto fail;
+ 		}
++		frag = skb_shinfo(skb)->frag_list;
++		skb_frag_list_init(skb);
+ 
+ 		__skb_pull(skb, hlen);
+ 		fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
+@@ -725,7 +728,6 @@ slow_path:
+ 	 */
+ 
+ 	*prevhdr = NEXTHDR_FRAGMENT;
+-	hroom = LL_RESERVED_SPACE(rt->dst.dev);
+ 	troom = rt->dst.dev->needed_tailroom;
+ 
+ 	/*
diff --git a/target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch b/target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch
new file mode 100644
index 0000000000..605f57a6ce
--- /dev/null
+++ b/target/linux/generic/patches-4.1/081-solos-pci-Increase-headroom-on-received-packets.patch
@@ -0,0 +1,54 @@
+From: David Woodhouse <dwmw2@infradead.org>
+Date: Thu, 17 Sep 2015 11:19:53 +0100
+Subject: [PATCH] solos-pci: Increase headroom on received packets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A comment in include/linux/skbuff.h says that:
+
+ * Various parts of the networking layer expect at least 32 bytes of
+ * headroom, you should not reduce this.
+
+This was demonstrated by a panic when handling fragmented IPv6 packets:
+http://marc.info/?l=linux-netdev&m=144236093519172&w=2
+
+It's not entirely clear if that comment is still valid — and if it is,
+perhaps netif_rx() ought to be enforcing it with a warning.
+
+But either way, it is rather stupid from a performance point of view
+for us to be receiving packets into a buffer which doesn't have enough
+room to prepend an Ethernet header — it means that *every* incoming
+packet is going to be need to be reallocated. So let's fix that.
+
+Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+---
+
+--- a/drivers/atm/solos-pci.c
++++ b/drivers/atm/solos-pci.c
+@@ -805,7 +805,12 @@ static void solos_bh(unsigned long card_
+ 					continue;
+ 				}
+ 
+-				skb = alloc_skb(size + 1, GFP_ATOMIC);
++				/* Use netdev_alloc_skb() because it adds NET_SKB_PAD of
++				 * headroom, and ensures we can route packets back out an
++				 * Ethernet interface (for example) without having to
++				 * reallocate. Adding NET_IP_ALIGN also ensures that both
++				 * PPPoATM and PPPoEoBR2684 packets end up aligned. */
++				skb = netdev_alloc_skb_ip_align(NULL, size + 1);
+ 				if (!skb) {
+ 					if (net_ratelimit())
+ 						dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+@@ -869,7 +874,10 @@ static void solos_bh(unsigned long card_
+ 		/* Allocate RX skbs for any ports which need them */
+ 		if (card->using_dma && card->atmdev[port] &&
+ 		    !card->rx_skb[port]) {
+-			struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC);
++			/* Unlike the MMIO case (qv) we can't add NET_IP_ALIGN
++			 * here; the FPGA can only DMA to addresses which are
++			 * aligned to 4 bytes. */
++			struct sk_buff *skb = dev_alloc_skb(RX_DMA_SIZE);
+ 			if (skb) {
+ 				SKB_CB(skb)->dma_addr =
+ 					dma_map_single(&card->dev->dev, skb->data,
diff --git a/target/linux/generic/patches-4.1/082-usb-core-Introduce-a-USB-port-LED-trigger.patch b/target/linux/generic/patches-4.1/082-usb-core-Introduce-a-USB-port-LED-trigger.patch
new file mode 100644
index 0000000000..ade7f9c8bb
--- /dev/null
+++ b/target/linux/generic/patches-4.1/082-usb-core-Introduce-a-USB-port-LED-trigger.patch
@@ -0,0 +1,464 @@
+From 0f247626cbbfa2010d2b86fdee652605e084e248 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 16 Sep 2016 16:13:48 +0200
+Subject: [PATCH] usb: core: Introduce a USB port LED trigger
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This commit adds a new trigger responsible for turning on LED when USB
+device gets connected to the selected USB port. This can can useful for
+various home routers that have USB port(s) and a proper LED telling user
+a device is connected.
+
+The trigger gets its documentation file but basically it just requires
+enabling it and selecting USB ports (e.g. echo 1 > ports/usb1-1).
+
+There was a long discussion on design of this driver. Its current state
+is a result of picking them most adjustable solution as others couldn't
+handle all cases.
+
+1) It wasn't possible for the driver to register separated trigger for
+   each USB port. Some physical USB ports are handled by more than one
+   controller and so by more than one USB port. E.g. USB 2.0 physical
+   port may be handled by OHCI's port and EHCI's port.
+   It's also not possible to assign more than 1 trigger to a single LED
+   and implementing such feature would be tricky due to syncing triggers
+   and sysfs conflicts with old triggers.
+
+2) Another idea was to register trigger per USB hub. This wouldn't allow
+   handling devices with multiple USB LEDs and controllers (hubs)
+   controlling more than 1 physical port. It's common for hubs to have
+   few ports and each may have its own LED.
+
+This final trigger is highly flexible. It allows selecting any USB ports
+for any LED. It was also modified (comparing to the initial version) to
+allow choosing ports rather than having user /guess/ proper names. It
+was successfully tested on SmartRG SR400ac which has 3 USB LEDs,
+2 physical ports and 3 controllers.
+
+It was noted USB subsystem already has usb-gadget and usb-host triggers
+but they are pretty trivial ones. They indicate activity only and can't
+have ports specified.
+
+In future it may be good idea to consider adding activity support to
+usbport as well. This should allow switching to this more generic driver
+and maybe marking old ones as obsolete.
+This can be implemented with another sysfs file for setting mode. The
+default mode wouldn't change so there won't be ABI breakage and so such
+feature can be safely implemented later.
+
+There was also an idea of supporting other devices (PCI, SDIO, etc.) but
+as this driver already contains some USB specific code (and will get
+more) these should be probably separated drivers (triggers).
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ .../ABI/testing/sysfs-class-led-trigger-usbport    |  12 +
+ Documentation/leds/ledtrig-usbport.txt             |  41 +++
+ drivers/usb/core/Kconfig                           |   8 +
+ drivers/usb/core/Makefile                          |   2 +
+ drivers/usb/core/ledtrig-usbport.c                 | 314 +++++++++++++++++++++
+ 5 files changed, 377 insertions(+)
+ create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-usbport
+ create mode 100644 Documentation/leds/ledtrig-usbport.txt
+ create mode 100644 drivers/usb/core/ledtrig-usbport.c
+
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-led-trigger-usbport
+@@ -0,0 +1,12 @@
++What:		/sys/class/leds/<led>/ports/<port>
++Date:		September 2016
++KernelVersion:	4.9
++Contact:	linux-leds@vger.kernel.org
++		linux-usb@vger.kernel.org
++Description:
++		Every dir entry represents a single USB port that can be
++		selected for the USB port trigger. Selecting ports makes trigger
++		observing them for any connected devices and lighting on LED if
++		there are any.
++		Echoing "1" value selects USB port. Echoing "0" unselects it.
++		Current state can be also read.
+--- /dev/null
++++ b/Documentation/leds/ledtrig-usbport.txt
+@@ -0,0 +1,41 @@
++USB port LED trigger
++====================
++
++This LED trigger can be used for signalling to the user a presence of USB device
++in a given port. It simply turns on LED when device appears and turns it off
++when it disappears.
++
++It requires selecting USB ports that should be observed. All available ones are
++listed as separated entries in a "ports" subdirectory. Selecting is handled by
++echoing "1" to a chosen port.
++
++Please note that this trigger allows selecting multiple USB ports for a single
++LED. This can be useful in two cases:
++
++1) Device with single USB LED and few physical ports
++
++In such a case LED will be turned on as long as there is at least one connected
++USB device.
++
++2) Device with a physical port handled by few controllers
++
++Some devices may have one controller per PHY standard. E.g. USB 3.0 physical
++port may be handled by ohci-platform, ehci-platform and xhci-hcd. If there is
++only one LED user will most likely want to assign ports from all 3 hubs.
++
++
++This trigger can be activated from user space on led class devices as shown
++below:
++
++  echo usbport > trigger
++
++This adds sysfs attributes to the LED that are documented in:
++Documentation/ABI/testing/sysfs-class-led-trigger-usbport
++
++Example use-case:
++
++  echo usbport > trigger
++  echo 1 > ports/usb1-port1
++  echo 1 > ports/usb2-port1
++  cat ports/usb1-port1
++  echo 0 > ports/usb1-port1
+--- a/drivers/usb/core/Kconfig
++++ b/drivers/usb/core/Kconfig
+@@ -84,3 +84,10 @@ config USB_OTG_FSM
+ 	  Implements OTG Finite State Machine as specified in On-The-Go
+ 	  and Embedded Host Supplement to the USB Revision 2.0 Specification.
+ 
++config USB_LEDS_TRIGGER_USBPORT
++	tristate "USB port LED trigger"
++	depends on USB && LEDS_TRIGGERS
++	help
++	  This driver allows LEDs to be controlled by USB events. Enabling this
++	  trigger allows specifying list of USB ports that should turn on LED
++	  when some USB device gets connected.
+--- a/drivers/usb/core/Makefile
++++ b/drivers/usb/core/Makefile
+@@ -11,3 +11,5 @@ usbcore-$(CONFIG_PCI)		+= hcd-pci.o
+ usbcore-$(CONFIG_ACPI)		+= usb-acpi.o
+ 
+ obj-$(CONFIG_USB)		+= usbcore.o
++
++obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT)	+= ledtrig-usbport.o
+--- /dev/null
++++ b/drivers/usb/core/ledtrig-usbport.c
+@@ -0,0 +1,314 @@
++/*
++ * USB port LED trigger
++ *
++ * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
++ *
++ * 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/device.h>
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/usb.h>
++
++struct usbport_trig_data {
++	struct led_classdev *led_cdev;
++	struct list_head ports;
++	struct notifier_block nb;
++	int count; /* Amount of connected matching devices */
++};
++
++struct usbport_trig_port {
++	struct usbport_trig_data *data;
++	struct usb_device *hub;
++	int portnum;
++	char *port_name;
++	bool observed;
++	struct device_attribute attr;
++	struct list_head list;
++};
++
++/***************************************
++ * Helpers
++ ***************************************/
++
++/**
++ * usbport_trig_usb_dev_observed - Check if dev is connected to observed port
++ */
++static bool usbport_trig_usb_dev_observed(struct usbport_trig_data *usbport_data,
++					  struct usb_device *usb_dev)
++{
++	struct usbport_trig_port *port;
++
++	if (!usb_dev->parent)
++		return false;
++
++	list_for_each_entry(port, &usbport_data->ports, list) {
++		if (usb_dev->parent == port->hub &&
++		    usb_dev->portnum == port->portnum)
++			return port->observed;
++	}
++
++	return false;
++}
++
++static int usbport_trig_usb_dev_check(struct usb_device *usb_dev, void *data)
++{
++	struct usbport_trig_data *usbport_data = data;
++
++	if (usbport_trig_usb_dev_observed(usbport_data, usb_dev))
++		usbport_data->count++;
++
++	return 0;
++}
++
++/**
++ * usbport_trig_update_count - Recalculate amount of connected matching devices
++ */
++static void usbport_trig_update_count(struct usbport_trig_data *usbport_data)
++{
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++
++	usbport_data->count = 0;
++	usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
++	led_cdev->brightness_set(led_cdev,
++				 usbport_data->count ? LED_FULL : LED_OFF);
++}
++
++/***************************************
++ * Device attr
++ ***************************************/
++
++static ssize_t usbport_trig_port_show(struct device *dev,
++				      struct device_attribute *attr, char *buf)
++{
++	struct usbport_trig_port *port = container_of(attr,
++						      struct usbport_trig_port,
++						      attr);
++
++	return sprintf(buf, "%d\n", port->observed) + 1;
++}
++
++static ssize_t usbport_trig_port_store(struct device *dev,
++				       struct device_attribute *attr,
++				       const char *buf, size_t size)
++{
++	struct usbport_trig_port *port = container_of(attr,
++						      struct usbport_trig_port,
++						      attr);
++
++	if (!strcmp(buf, "0") || !strcmp(buf, "0\n"))
++		port->observed = 0;
++	else if (!strcmp(buf, "1") || !strcmp(buf, "1\n"))
++		port->observed = 1;
++	else
++		return -EINVAL;
++
++	usbport_trig_update_count(port->data);
++
++	return size;
++}
++
++static struct attribute *ports_attrs[] = {
++	NULL,
++};
++static const struct attribute_group ports_group = {
++	.name = "ports",
++	.attrs = ports_attrs,
++};
++
++/***************************************
++ * Adding & removing ports
++ ***************************************/
++
++static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
++				 struct usb_device *usb_dev,
++				 const char *hub_name, int portnum)
++{
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++	struct usbport_trig_port *port;
++	size_t len;
++	int err;
++
++	port = kzalloc(sizeof(*port), GFP_KERNEL);
++	if (!port) {
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	port->data = usbport_data;
++	port->hub = usb_dev;
++	port->portnum = portnum;
++
++	len = strlen(hub_name) + 8;
++	port->port_name = kzalloc(len, GFP_KERNEL);
++	if (!port->port_name) {
++		err = -ENOMEM;
++		goto err_free_port;
++	}
++	snprintf(port->port_name, len, "%s-port%d", hub_name, portnum);
++
++	port->attr.attr.name = port->port_name;
++	port->attr.attr.mode = S_IRUSR | S_IWUSR;
++	port->attr.show = usbport_trig_port_show;
++	port->attr.store = usbport_trig_port_store;
++
++	err = sysfs_add_file_to_group(&led_cdev->dev->kobj, &port->attr.attr,
++				      ports_group.name);
++	if (err)
++		goto err_free_port_name;
++
++	list_add_tail(&port->list, &usbport_data->ports);
++
++	return 0;
++
++err_free_port_name:
++	kfree(port->port_name);
++err_free_port:
++	kfree(port);
++err_out:
++	return err;
++}
++
++static int usbport_trig_add_usb_dev_ports(struct usb_device *usb_dev,
++					  void *data)
++{
++	struct usbport_trig_data *usbport_data = data;
++	int i;
++
++	for (i = 1; i <= usb_dev->maxchild; i++)
++		usbport_trig_add_port(usbport_data, usb_dev,
++				      dev_name(&usb_dev->dev), i);
++
++	return 0;
++}
++
++static void usbport_trig_remove_port(struct usbport_trig_data *usbport_data,
++				     struct usbport_trig_port *port)
++{
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++
++	list_del(&port->list);
++	sysfs_remove_file_from_group(&led_cdev->dev->kobj, &port->attr.attr,
++				     ports_group.name);
++	kfree(port->port_name);
++	kfree(port);
++}
++
++static void usbport_trig_remove_usb_dev_ports(struct usbport_trig_data *usbport_data,
++					      struct usb_device *usb_dev)
++{
++	struct usbport_trig_port *port, *tmp;
++
++	list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
++		if (port->hub == usb_dev)
++			usbport_trig_remove_port(usbport_data, port);
++	}
++}
++
++/***************************************
++ * Init, exit, etc.
++ ***************************************/
++
++static int usbport_trig_notify(struct notifier_block *nb, unsigned long action,
++			       void *data)
++{
++	struct usbport_trig_data *usbport_data =
++		container_of(nb, struct usbport_trig_data, nb);
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++	struct usb_device *usb_dev = data;
++	bool observed;
++
++	observed = usbport_trig_usb_dev_observed(usbport_data, usb_dev);
++
++	switch (action) {
++	case USB_DEVICE_ADD:
++		usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
++		if (observed && usbport_data->count++ == 0)
++			led_cdev->brightness_set(led_cdev, LED_FULL);
++		return NOTIFY_OK;
++	case USB_DEVICE_REMOVE:
++		usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
++		if (observed && --usbport_data->count == 0)
++			led_cdev->brightness_set(led_cdev, LED_OFF);
++		return NOTIFY_OK;
++	}
++
++	return NOTIFY_DONE;
++}
++
++static void usbport_trig_activate(struct led_classdev *led_cdev)
++{
++	struct usbport_trig_data *usbport_data;
++	int err;
++
++	usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL);
++	if (!usbport_data)
++		return;
++	usbport_data->led_cdev = led_cdev;
++
++	/* List of ports */
++	INIT_LIST_HEAD(&usbport_data->ports);
++	err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group);
++	if (err)
++		goto err_free;
++	usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
++
++	/* Notifications */
++	usbport_data->nb.notifier_call = usbport_trig_notify,
++	led_cdev->trigger_data = usbport_data;
++	usb_register_notify(&usbport_data->nb);
++
++	led_cdev->activated = true;
++	return;
++
++err_free:
++	kfree(usbport_data);
++}
++
++static void usbport_trig_deactivate(struct led_classdev *led_cdev)
++{
++	struct usbport_trig_data *usbport_data = led_cdev->trigger_data;
++	struct usbport_trig_port *port, *tmp;
++
++	if (!led_cdev->activated)
++		return;
++
++	list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
++		usbport_trig_remove_port(usbport_data, port);
++	}
++
++	usb_unregister_notify(&usbport_data->nb);
++
++	sysfs_remove_group(&led_cdev->dev->kobj, &ports_group);
++
++	kfree(usbport_data);
++
++	led_cdev->activated = false;
++}
++
++static struct led_trigger usbport_led_trigger = {
++	.name     = "usbport",
++	.activate = usbport_trig_activate,
++	.deactivate = usbport_trig_deactivate,
++};
++
++static int __init usbport_trig_init(void)
++{
++	return led_trigger_register(&usbport_led_trigger);
++}
++
++static void __exit usbport_trig_exit(void)
++{
++	led_trigger_unregister(&usbport_led_trigger);
++}
++
++module_init(usbport_trig_init);
++module_exit(usbport_trig_exit);
++
++MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>");
++MODULE_DESCRIPTION("USB port trigger");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/generic/patches-4.1/090-m25p80_spi-nor_update_to_4.4rc1.patch b/target/linux/generic/patches-4.1/090-m25p80_spi-nor_update_to_4.4rc1.patch
new file mode 100644
index 0000000000..b640706587
--- /dev/null
+++ b/target/linux/generic/patches-4.1/090-m25p80_spi-nor_update_to_4.4rc1.patch
@@ -0,0 +1,1129 @@
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -31,7 +31,6 @@
+ struct m25p {
+ 	struct spi_device	*spi;
+ 	struct spi_nor		spi_nor;
+-	struct mtd_info		mtd;
+ 	u8			command[MAX_CMD_SIZE];
+ };
+ 
+@@ -62,8 +61,7 @@ static int m25p_cmdsz(struct spi_nor *no
+ 	return 1 + nor->addr_width;
+ }
+ 
+-static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+-			int wr_en)
++static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+ {
+ 	struct m25p *flash = nor->priv;
+ 	struct spi_device *spi = flash->spi;
+@@ -159,7 +157,7 @@ static int m25p80_erase(struct spi_nor *
+ 	struct m25p *flash = nor->priv;
+ 
+ 	dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
+-		flash->mtd.erasesize / 1024, (u32)offset);
++		flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
+ 
+ 	/* Set up command buffer. */
+ 	flash->command[0] = nor->erase_opcode;
+@@ -201,11 +199,10 @@ static int m25p_probe(struct spi_device
+ 	nor->read_reg = m25p80_read_reg;
+ 
+ 	nor->dev = &spi->dev;
+-	nor->mtd = &flash->mtd;
++	nor->flash_node = spi->dev.of_node;
+ 	nor->priv = flash;
+ 
+ 	spi_set_drvdata(spi, flash);
+-	flash->mtd.priv = nor;
+ 	flash->spi = spi;
+ 
+ 	if (spi->mode & SPI_RX_QUAD)
+@@ -214,7 +211,7 @@ static int m25p_probe(struct spi_device
+ 		mode = SPI_NOR_DUAL;
+ 
+ 	if (data && data->name)
+-		flash->mtd.name = data->name;
++		nor->mtd.name = data->name;
+ 
+ 	/* For some (historical?) reason many platforms provide two different
+ 	 * names in flash_platform_data: "name" and "type". Quite often name is
+@@ -223,8 +220,6 @@ static int m25p_probe(struct spi_device
+ 	 */
+ 	if (data && data->type)
+ 		flash_name = data->type;
+-	else if (!strcmp(spi->modalias, "spi-nor"))
+-		flash_name = NULL; /* auto-detect */
+ 	else
+ 		flash_name = spi->modalias;
+ 
+@@ -234,7 +229,7 @@ static int m25p_probe(struct spi_device
+ 
+ 	ppdata.of_node = spi->dev.of_node;
+ 
+-	return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
++	return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
+ 			data ? data->parts : NULL,
+ 			data ? data->nr_parts : 0);
+ }
+@@ -245,7 +240,7 @@ static int m25p_remove(struct spi_device
+ 	struct m25p	*flash = spi_get_drvdata(spi);
+ 
+ 	/* Clean up MTD stuff. */
+-	return mtd_device_unregister(&flash->mtd);
++	return mtd_device_unregister(&flash->spi_nor.mtd);
+ }
+ 
+ /*
+@@ -261,59 +256,52 @@ static int m25p_remove(struct spi_device
+  * keep them available as module aliases for existing platforms.
+  */
+ static const struct spi_device_id m25p_ids[] = {
+-	{"at25fs010"},	{"at25fs040"},	{"at25df041a"},	{"at25df321a"},
+-	{"at25df641"},	{"at26f004"},	{"at26df081a"},	{"at26df161a"},
+-	{"at26df321"},	{"at45db081d"},
+-	{"en25f32"},	{"en25p32"},	{"en25q32b"},	{"en25p64"},
+-	{"en25q64"},	{"en25qh128"},	{"en25qh256"},
+-	{"f25l32pa"},
+-	{"mr25h256"},	{"mr25h10"},
+-	{"gd25q32"},	{"gd25q64"},
+-	{"160s33b"},	{"320s33b"},	{"640s33b"},
+-	{"mx25l2005a"},	{"mx25l4005a"},	{"mx25l8005"},	{"mx25l1606e"},
+-	{"mx25l3205d"},	{"mx25l3255e"},	{"mx25l6405d"},	{"mx25l12805d"},
+-	{"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"},
+-	{"mx66l1g55g"},
+-	{"n25q064"},	{"n25q128a11"},	{"n25q128a13"},	{"n25q256a"},
+-	{"n25q512a"},	{"n25q512ax3"},	{"n25q00"},
+-	{"pm25lv512"},	{"pm25lv010"},	{"pm25lq032"},
+-	{"s25sl032p"},	{"s25sl064p"},	{"s25fl256s0"},	{"s25fl256s1"},
+-	{"s25fl512s"},	{"s70fl01gs"},	{"s25sl12800"},	{"s25sl12801"},
+-	{"s25fl129p0"},	{"s25fl129p1"},	{"s25sl004a"},	{"s25sl008a"},
+-	{"s25sl016a"},	{"s25sl032a"},	{"s25sl064a"},	{"s25fl008k"},
+-	{"s25fl016k"},	{"s25fl064k"},	{"s25fl132k"},
+-	{"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"},
+-	{"sst25vf064c"},{"sst25wf512"},	{"sst25wf010"},	{"sst25wf020"},
+-	{"sst25wf040"},
+-	{"m25p05"},	{"m25p10"},	{"m25p20"},	{"m25p40"},
+-	{"m25p80"},	{"m25p16"},	{"m25p32"},	{"m25p64"},
+-	{"m25p128"},	{"n25q032"},
++	/*
++	 * Entries not used in DTs that should be safe to drop after replacing
++	 * them with "nor-jedec" in platform data.
++	 */
++	{"s25sl064a"},	{"w25x16"},	{"m25p10"},	{"m25px64"},
++
++	/*
++	 * Entries that were used in DTs without "nor-jedec" fallback and should
++	 * be kept for backward compatibility.
++	 */
++	{"at25df321a"},	{"at25df641"},	{"at26df081a"},
++	{"mr25h256"},
++	{"mx25l4005a"},	{"mx25l1606e"},	{"mx25l6405d"},	{"mx25l12805d"},
++	{"mx25l25635e"},{"mx66l51235l"},
++	{"n25q064"},	{"n25q128a11"},	{"n25q128a13"},	{"n25q512a"},
++	{"s25fl256s1"},	{"s25fl512s"},	{"s25sl12801"},	{"s25fl008k"},
++	{"s25fl064k"},
++	{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},
++	{"m25p40"},	{"m25p80"},	{"m25p16"},	{"m25p32"},
++	{"m25p64"},	{"m25p128"},
++	{"w25x80"},	{"w25x32"},	{"w25q32"},	{"w25q32dw"},
++	{"w25q80bl"},	{"w25q128"},	{"w25q256"},
++
++	/* Flashes that can't be detected using JEDEC */
+ 	{"m25p05-nonjedec"},	{"m25p10-nonjedec"},	{"m25p20-nonjedec"},
+ 	{"m25p40-nonjedec"},	{"m25p80-nonjedec"},	{"m25p16-nonjedec"},
+ 	{"m25p32-nonjedec"},	{"m25p64-nonjedec"},	{"m25p128-nonjedec"},
+-	{"m45pe10"},	{"m45pe80"},	{"m45pe16"},
+-	{"m25pe20"},	{"m25pe80"},	{"m25pe16"},
+-	{"m25px16"},	{"m25px32"},	{"m25px32-s0"},	{"m25px32-s1"},
+-	{"m25px64"},	{"m25px80"},
+-	{"w25x10"},	{"w25x20"},	{"w25x40"},	{"w25x80"},
+-	{"w25x16"},	{"w25x32"},	{"w25q32"},	{"w25q32dw"},
+-	{"w25x64"},	{"w25q64"},	{"w25q80"},	{"w25q80bl"},
+-	{"w25q128"},	{"w25q256"},	{"cat25c11"},
+-	{"cat25c03"},	{"cat25c09"},	{"cat25c17"},	{"cat25128"},
+ 
+-	/*
+-	 * Generic support for SPI NOR that can be identified by the JEDEC READ
+-	 * ID opcode (0x9F). Use this, if possible.
+-	 */
+-	{"spi-nor"},
+ 	{ },
+ };
+ MODULE_DEVICE_TABLE(spi, m25p_ids);
+ 
++static const struct of_device_id m25p_of_table[] = {
++	/*
++	 * Generic compatibility for SPI NOR that can be identified by the
++	 * JEDEC READ ID opcode (0x9F). Use this, if possible.
++	 */
++	{ .compatible = "jedec,spi-nor" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, m25p_of_table);
++
+ static struct spi_driver m25p80_driver = {
+ 	.driver = {
+ 		.name	= "m25p80",
+-		.owner	= THIS_MODULE,
++		.of_match_table = m25p_of_table,
+ 	},
+ 	.id_table	= m25p_ids,
+ 	.probe	= m25p_probe,
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -16,19 +16,32 @@
+ #include <linux/device.h>
+ #include <linux/mutex.h>
+ #include <linux/math64.h>
++#include <linux/sizes.h>
+ 
+-#include <linux/mtd/cfi.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/of_platform.h>
+ #include <linux/spi/flash.h>
+ #include <linux/mtd/spi-nor.h>
+ 
+ /* Define max times to check status register before we give up. */
+-#define	MAX_READY_WAIT_JIFFIES	(40 * HZ) /* M25P16 specs 40s max chip erase */
++
++/*
++ * For everything but full-chip erase; probably could be much smaller, but kept
++ * around for safety for now
++ */
++#define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ)
++
++/*
++ * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
++ * for larger flash
++ */
++#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES	(40UL * HZ)
+ 
+ #define SPI_NOR_MAX_ID_LEN	6
+ 
+ struct flash_info {
++	char		*name;
++
+ 	/*
+ 	 * This array stores the ID bytes.
+ 	 * The first three bytes are the JEDIC ID.
+@@ -59,7 +72,7 @@ struct flash_info {
+ 
+ #define JEDEC_MFR(info)	((info)->id[0])
+ 
+-static const struct spi_device_id *spi_nor_match_id(const char *name);
++static const struct flash_info *spi_nor_match_id(const char *name);
+ 
+ /*
+  * Read the status register, returning its value in the location
+@@ -143,7 +156,7 @@ static inline int spi_nor_read_dummy_cyc
+ static inline int write_sr(struct spi_nor *nor, u8 val)
+ {
+ 	nor->cmd_buf[0] = val;
+-	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
++	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1);
+ }
+ 
+ /*
+@@ -152,7 +165,7 @@ static inline int write_sr(struct spi_no
+  */
+ static inline int write_enable(struct spi_nor *nor)
+ {
+-	return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
++	return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
+ }
+ 
+ /*
+@@ -160,7 +173,7 @@ static inline int write_enable(struct sp
+  */
+ static inline int write_disable(struct spi_nor *nor)
+ {
+-	return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
++	return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0);
+ }
+ 
+ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+@@ -169,7 +182,7 @@ static inline struct spi_nor *mtd_to_spi
+ }
+ 
+ /* Enable/disable 4-byte addressing mode. */
+-static inline int set_4byte(struct spi_nor *nor, struct flash_info *info,
++static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
+ 			    int enable)
+ {
+ 	int status;
+@@ -177,16 +190,16 @@ static inline int set_4byte(struct spi_n
+ 	u8 cmd;
+ 
+ 	switch (JEDEC_MFR(info)) {
+-	case CFI_MFR_ST: /* Micron, actually */
++	case SNOR_MFR_MICRON:
+ 		/* Some Micron need WREN command; all will accept it */
+ 		need_wren = true;
+-	case CFI_MFR_MACRONIX:
+-	case 0xEF /* winbond */:
++	case SNOR_MFR_MACRONIX:
++	case SNOR_MFR_WINBOND:
+ 		if (need_wren)
+ 			write_enable(nor);
+ 
+ 		cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
+-		status = nor->write_reg(nor, cmd, NULL, 0, 0);
++		status = nor->write_reg(nor, cmd, NULL, 0);
+ 		if (need_wren)
+ 			write_disable(nor);
+ 
+@@ -194,7 +207,7 @@ static inline int set_4byte(struct spi_n
+ 	default:
+ 		/* Spansion style */
+ 		nor->cmd_buf[0] = enable << 7;
+-		return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0);
++		return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1);
+ 	}
+ }
+ static inline int spi_nor_sr_ready(struct spi_nor *nor)
+@@ -231,12 +244,13 @@ static int spi_nor_ready(struct spi_nor
+  * Service routine to read status register until ready, or timeout occurs.
+  * Returns non-zero if error.
+  */
+-static int spi_nor_wait_till_ready(struct spi_nor *nor)
++static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor,
++						unsigned long timeout_jiffies)
+ {
+ 	unsigned long deadline;
+ 	int timeout = 0, ret;
+ 
+-	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
++	deadline = jiffies + timeout_jiffies;
+ 
+ 	while (!timeout) {
+ 		if (time_after_eq(jiffies, deadline))
+@@ -256,6 +270,12 @@ static int spi_nor_wait_till_ready(struc
+ 	return -ETIMEDOUT;
+ }
+ 
++static int spi_nor_wait_till_ready(struct spi_nor *nor)
++{
++	return spi_nor_wait_till_ready_with_timeout(nor,
++						    DEFAULT_READY_WAIT_JIFFIES);
++}
++
+ /*
+  * Erase the whole flash memory
+  *
+@@ -263,9 +283,9 @@ static int spi_nor_wait_till_ready(struc
+  */
+ static int erase_chip(struct spi_nor *nor)
+ {
+-	dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd->size >> 10));
++	dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10));
+ 
+-	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
++	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
+ }
+ 
+ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+@@ -319,6 +339,8 @@ static int spi_nor_erase(struct mtd_info
+ 
+ 	/* whole-chip erase? */
+ 	if (len == mtd->size) {
++		unsigned long timeout;
++
+ 		write_enable(nor);
+ 
+ 		if (erase_chip(nor)) {
+@@ -326,7 +348,16 @@ static int spi_nor_erase(struct mtd_info
+ 			goto erase_err;
+ 		}
+ 
+-		ret = spi_nor_wait_till_ready(nor);
++		/*
++		 * Scale the timeout linearly with the size of the flash, with
++		 * a minimum calibrated to an old 2MB flash. We could try to
++		 * pull these from CFI/SFDP, but these values should be good
++		 * enough for now.
++		 */
++		timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
++			      CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
++			      (unsigned long)(mtd->size / SZ_2M));
++		ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
+ 		if (ret)
+ 			goto erase_err;
+ 
+@@ -369,72 +400,171 @@ erase_err:
+ 	return ret;
+ }
+ 
++static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
++				 uint64_t *len)
++{
++	struct mtd_info *mtd = &nor->mtd;
++	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++	int shift = ffs(mask) - 1;
++	int pow;
++
++	if (!(sr & mask)) {
++		/* No protection */
++		*ofs = 0;
++		*len = 0;
++	} else {
++		pow = ((sr & mask) ^ mask) >> shift;
++		*len = mtd->size >> pow;
++		*ofs = mtd->size - *len;
++	}
++}
++
++/*
++ * Return 1 if the entire region is locked, 0 otherwise
++ */
++static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++			    u8 sr)
++{
++	loff_t lock_offs;
++	uint64_t lock_len;
++
++	stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
++
++	return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
++}
++
++/*
++ * Lock a region of the flash. Compatible with ST Micro and similar flash.
++ * Supports only the block protection bits BP{0,1,2} in the status register
++ * (SR). Does not support these features found in newer SR bitfields:
++ *   - TB: top/bottom protect - only handle TB=0 (top protect)
++ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
++ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
++ *
++ * Sample table portion for 8MB flash (Winbond w25q64fw):
++ *
++ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
++ *  --------------------------------------------------------------------------
++ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
++ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
++ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
++ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
++ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
++ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
++ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
++ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
++ *
++ * Returns negative on errors, 0 on success.
++ */
+ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+-	struct mtd_info *mtd = nor->mtd;
+-	uint32_t offset = ofs;
+-	uint8_t status_old, status_new;
+-	int ret = 0;
++	struct mtd_info *mtd = &nor->mtd;
++	u8 status_old, status_new;
++	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++	u8 shift = ffs(mask) - 1, pow, val;
+ 
+ 	status_old = read_sr(nor);
+ 
+-	if (offset < mtd->size - (mtd->size / 2))
+-		status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
+-	else if (offset < mtd->size - (mtd->size / 4))
+-		status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+-	else if (offset < mtd->size - (mtd->size / 8))
+-		status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+-	else if (offset < mtd->size - (mtd->size / 16))
+-		status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
+-	else if (offset < mtd->size - (mtd->size / 32))
+-		status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+-	else if (offset < mtd->size - (mtd->size / 64))
+-		status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
+-	else
+-		status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
++	/* SPI NOR always locks to the end */
++	if (ofs + len != mtd->size) {
++		/* Does combined region extend to end? */
++		if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
++				      status_old))
++			return -EINVAL;
++		len = mtd->size - ofs;
++	}
++
++	/*
++	 * Need smallest pow such that:
++	 *
++	 *   1 / (2^pow) <= (len / size)
++	 *
++	 * so (assuming power-of-2 size) we do:
++	 *
++	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
++	 */
++	pow = ilog2(mtd->size) - ilog2(len);
++	val = mask - (pow << shift);
++	if (val & ~mask)
++		return -EINVAL;
++	/* Don't "lock" with no region! */
++	if (!(val & mask))
++		return -EINVAL;
++
++	status_new = (status_old & ~mask) | val;
+ 
+ 	/* Only modify protection if it will not unlock other areas */
+-	if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) >
+-				(status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
+-		write_enable(nor);
+-		ret = write_sr(nor, status_new);
+-	}
++	if ((status_new & mask) <= (status_old & mask))
++		return -EINVAL;
+ 
+-	return ret;
++	write_enable(nor);
++	return write_sr(nor, status_new);
+ }
+ 
++/*
++ * Unlock a region of the flash. See stm_lock() for more info
++ *
++ * Returns negative on errors, 0 on success.
++ */
+ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+-	struct mtd_info *mtd = nor->mtd;
+-	uint32_t offset = ofs;
++	struct mtd_info *mtd = &nor->mtd;
+ 	uint8_t status_old, status_new;
+-	int ret = 0;
++	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++	u8 shift = ffs(mask) - 1, pow, val;
+ 
+ 	status_old = read_sr(nor);
+ 
+-	if (offset+len > mtd->size - (mtd->size / 64))
+-		status_new = status_old & ~(SR_BP2 | SR_BP1 | SR_BP0);
+-	else if (offset+len > mtd->size - (mtd->size / 32))
+-		status_new = (status_old & ~(SR_BP2 | SR_BP1)) | SR_BP0;
+-	else if (offset+len > mtd->size - (mtd->size / 16))
+-		status_new = (status_old & ~(SR_BP2 | SR_BP0)) | SR_BP1;
+-	else if (offset+len > mtd->size - (mtd->size / 8))
+-		status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+-	else if (offset+len > mtd->size - (mtd->size / 4))
+-		status_new = (status_old & ~(SR_BP0 | SR_BP1)) | SR_BP2;
+-	else if (offset+len > mtd->size - (mtd->size / 2))
+-		status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+-	else
+-		status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
++	/* Cannot unlock; would unlock larger region than requested */
++	if (stm_is_locked_sr(nor, status_old, ofs - mtd->erasesize,
++			     mtd->erasesize))
++		return -EINVAL;
+ 
+-	/* Only modify protection if it will not lock other areas */
+-	if ((status_new & (SR_BP2 | SR_BP1 | SR_BP0)) <
+-				(status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
+-		write_enable(nor);
+-		ret = write_sr(nor, status_new);
++	/*
++	 * Need largest pow such that:
++	 *
++	 *   1 / (2^pow) >= (len / size)
++	 *
++	 * so (assuming power-of-2 size) we do:
++	 *
++	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
++	 */
++	pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
++	if (ofs + len == mtd->size) {
++		val = 0; /* fully unlocked */
++	} else {
++		val = mask - (pow << shift);
++		/* Some power-of-two sizes are not supported */
++		if (val & ~mask)
++			return -EINVAL;
+ 	}
+ 
+-	return ret;
++	status_new = (status_old & ~mask) | val;
++
++	/* Only modify protection if it will not lock other areas */
++	if ((status_new & mask) >= (status_old & mask))
++		return -EINVAL;
++
++	write_enable(nor);
++	return write_sr(nor, status_new);
++}
++
++/*
++ * Check if a region of the flash is (completely) locked. See stm_lock() for
++ * more info.
++ *
++ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
++ * negative on errors.
++ */
++static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
++{
++	int status;
++
++	status = read_sr(nor);
++	if (status < 0)
++		return status;
++
++	return stm_is_locked_sr(nor, ofs, len, status);
+ }
+ 
+ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+@@ -467,9 +597,23 @@ static int spi_nor_unlock(struct mtd_inf
+ 	return ret;
+ }
+ 
++static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
++{
++	struct spi_nor *nor = mtd_to_spi_nor(mtd);
++	int ret;
++
++	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
++	if (ret)
++		return ret;
++
++	ret = nor->flash_is_locked(nor, ofs, len);
++
++	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
++	return ret;
++}
++
+ /* Used when the "_ext_id" is two bytes at most */
+ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+-	((kernel_ulong_t)&(struct flash_info) {				\
+ 		.id = {							\
+ 			((_jedec_id) >> 16) & 0xff,			\
+ 			((_jedec_id) >> 8) & 0xff,			\
+@@ -481,11 +625,9 @@ static int spi_nor_unlock(struct mtd_inf
+ 		.sector_size = (_sector_size),				\
+ 		.n_sectors = (_n_sectors),				\
+ 		.page_size = 256,					\
+-		.flags = (_flags),					\
+-	})
++		.flags = (_flags),
+ 
+ #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+-	((kernel_ulong_t)&(struct flash_info) {				\
+ 		.id = {							\
+ 			((_jedec_id) >> 16) & 0xff,			\
+ 			((_jedec_id) >> 8) & 0xff,			\
+@@ -498,23 +640,27 @@ static int spi_nor_unlock(struct mtd_inf
+ 		.sector_size = (_sector_size),				\
+ 		.n_sectors = (_n_sectors),				\
+ 		.page_size = 256,					\
+-		.flags = (_flags),					\
+-	})
++		.flags = (_flags),
+ 
+ #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)	\
+-	((kernel_ulong_t)&(struct flash_info) {				\
+ 		.sector_size = (_sector_size),				\
+ 		.n_sectors = (_n_sectors),				\
+ 		.page_size = (_page_size),				\
+ 		.addr_width = (_addr_width),				\
+-		.flags = (_flags),					\
+-	})
++		.flags = (_flags),
+ 
+ /* NOTE: double check command sets and memory organization when you add
+  * more nor chips.  This current list focusses on newer chips, which
+  * have been converging on command sets which including JEDEC ID.
++ *
++ * All newly added entries should describe *hardware* and should use SECT_4K
++ * (or SECT_4K_PMC) if hardware supports erasing 4 KiB sectors. For usage
++ * scenarios excluding small sectors there is config option that can be
++ * disabled: CONFIG_MTD_SPI_NOR_USE_4K_SECTORS.
++ * For historical (and compatibility) reasons (before we got above config) some
++ * old entries may be missing 4K flag.
+  */
+-static const struct spi_device_id spi_nor_ids[] = {
++static const struct flash_info spi_nor_ids[] = {
+ 	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
+ 	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
+ 	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
+@@ -538,7 +684,7 @@ static const struct spi_device_id spi_no
+ 	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
+ 	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 0) },
+ 	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
+-	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, 0) },
++	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, SECT_4K) },
+ 
+ 	/* ESMT */
+ 	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
+@@ -560,7 +706,11 @@ static const struct spi_device_id spi_no
+ 	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
+ 	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+ 
++	/* ISSI */
++	{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024,   2, SECT_4K) },
++
+ 	/* Macronix */
++	{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
+ 	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
+ 	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
+ 	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
+@@ -578,7 +728,9 @@ static const struct spi_device_id spi_no
+ 
+ 	/* Micron */
+ 	{ "n25q032",	 INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
+-	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SPI_NOR_QUAD_READ) },
++	{ "n25q032a",	 INFO(0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
++	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
++	{ "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
+ 	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
+ 	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
+ 	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
+@@ -595,25 +747,28 @@ static const struct spi_device_id spi_no
+ 	 * for the chips listed here (without boot sectors).
+ 	 */
+ 	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+-	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
++	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
+ 	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
+ 	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
+ 	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
+-	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
+-	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
+-	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
++	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
++	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
+ 	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
+ 	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
+ 	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
+ 	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
+-	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
+-	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
++	{ "s25fl004k",  INFO(0xef4013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
+-	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, 0) },
++	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, SECT_4K) },
++	{ "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128, SECT_4K) },
++	{ "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K | SPI_NOR_DUAL_READ) },
+ 
+ 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
+ 	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
+@@ -624,6 +779,8 @@ static const struct spi_device_id spi_no
+ 	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
+ 	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
+ 	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
++	{ "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4, SECT_4K) },
++	{ "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K) },
+ 	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
+ 	{ "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
+ 
+@@ -672,10 +829,11 @@ static const struct spi_device_id spi_no
+ 	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
+ 	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
+ 	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
++	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
+ 	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
+-	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) },
++	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+@@ -690,11 +848,11 @@ static const struct spi_device_id spi_no
+ 	{ },
+ };
+ 
+-static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor)
++static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
+ {
+ 	int			tmp;
+ 	u8			id[SPI_NOR_MAX_ID_LEN];
+-	struct flash_info	*info;
++	const struct flash_info	*info;
+ 
+ 	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ 	if (tmp < 0) {
+@@ -703,7 +861,7 @@ static const struct spi_device_id *spi_n
+ 	}
+ 
+ 	for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) {
+-		info = (void *)spi_nor_ids[tmp].driver_data;
++		info = &spi_nor_ids[tmp];
+ 		if (info->id_len) {
+ 			if (!memcmp(info->id, id, info->id_len))
+ 				return &spi_nor_ids[tmp];
+@@ -857,8 +1015,7 @@ static int macronix_quad_enable(struct s
+ 	val = read_sr(nor);
+ 	write_enable(nor);
+ 
+-	nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
+-	nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
++	write_sr(nor, val | SR_QUAD_EN_MX);
+ 
+ 	if (spi_nor_wait_till_ready(nor))
+ 		return 1;
+@@ -883,7 +1040,7 @@ static int write_sr_cr(struct spi_nor *n
+ 	nor->cmd_buf[0] = val & 0xff;
+ 	nor->cmd_buf[1] = (val >> 8);
+ 
+-	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
++	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
+ }
+ 
+ static int spansion_quad_enable(struct spi_nor *nor)
+@@ -925,7 +1082,7 @@ static int micron_quad_enable(struct spi
+ 
+ 	/* set EVCR, enable quad I/O */
+ 	nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
+-	ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0);
++	ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
+ 	if (ret < 0) {
+ 		dev_err(nor->dev, "error while writing EVCR register\n");
+ 		return ret;
+@@ -949,19 +1106,19 @@ static int micron_quad_enable(struct spi
+ 	return 0;
+ }
+ 
+-static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
++static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ {
+ 	int status;
+ 
+ 	switch (JEDEC_MFR(info)) {
+-	case CFI_MFR_MACRONIX:
++	case SNOR_MFR_MACRONIX:
+ 		status = macronix_quad_enable(nor);
+ 		if (status) {
+ 			dev_err(nor->dev, "Macronix quad-read not enabled\n");
+ 			return -EINVAL;
+ 		}
+ 		return status;
+-	case CFI_MFR_ST:
++	case SNOR_MFR_MICRON:
+ 		status = micron_quad_enable(nor);
+ 		if (status) {
+ 			dev_err(nor->dev, "Micron quad-read not enabled\n");
+@@ -991,11 +1148,10 @@ static int spi_nor_check(struct spi_nor
+ 
+ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
+ {
+-	const struct spi_device_id	*id = NULL;
+-	struct flash_info		*info;
++	const struct flash_info *info = NULL;
+ 	struct device *dev = nor->dev;
+-	struct mtd_info *mtd = nor->mtd;
+-	struct device_node *np = dev->of_node;
++	struct mtd_info *mtd = &nor->mtd;
++	struct device_node *np = nor->flash_node;
+ 	int ret;
+ 	int i;
+ 
+@@ -1003,27 +1159,25 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	if (ret)
+ 		return ret;
+ 
+-	/* Try to auto-detect if chip name wasn't specified */
+-	if (!name)
+-		id = spi_nor_read_id(nor);
+-	else
+-		id = spi_nor_match_id(name);
+-	if (IS_ERR_OR_NULL(id))
++	if (name)
++		info = spi_nor_match_id(name);
++	/* Try to auto-detect if chip name wasn't specified or not found */
++	if (!info)
++		info = spi_nor_read_id(nor);
++	if (IS_ERR_OR_NULL(info))
+ 		return -ENOENT;
+ 
+-	info = (void *)id->driver_data;
+-
+ 	/*
+ 	 * If caller has specified name of flash model that can normally be
+ 	 * detected using JEDEC, let's verify it.
+ 	 */
+ 	if (name && info->id_len) {
+-		const struct spi_device_id *jid;
++		const struct flash_info *jinfo;
+ 
+-		jid = spi_nor_read_id(nor);
+-		if (IS_ERR(jid)) {
+-			return PTR_ERR(jid);
+-		} else if (jid != id) {
++		jinfo = spi_nor_read_id(nor);
++		if (IS_ERR(jinfo)) {
++			return PTR_ERR(jinfo);
++		} else if (jinfo != info) {
+ 			/*
+ 			 * JEDEC knows better, so overwrite platform ID. We
+ 			 * can't trust partitions any longer, but we'll let
+@@ -1032,28 +1186,29 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 			 * information, even if it's not 100% accurate.
+ 			 */
+ 			dev_warn(dev, "found %s, expected %s\n",
+-				 jid->name, id->name);
+-			id = jid;
+-			info = (void *)jid->driver_data;
++				 jinfo->name, info->name);
++			info = jinfo;
+ 		}
+ 	}
+ 
+ 	mutex_init(&nor->lock);
+ 
+ 	/*
+-	 * Atmel, SST and Intel/Numonyx serial nor tend to power
+-	 * up with the software protection bits set
++	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
++	 * with the software protection bits set
+ 	 */
+ 
+-	if (JEDEC_MFR(info) == CFI_MFR_ATMEL ||
+-	    JEDEC_MFR(info) == CFI_MFR_INTEL ||
+-	    JEDEC_MFR(info) == CFI_MFR_SST) {
++	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
++	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
++	    JEDEC_MFR(info) == SNOR_MFR_SST ||
++	    JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+ 		write_enable(nor);
+ 		write_sr(nor, 0);
+ 	}
+ 
+ 	if (!mtd->name)
+ 		mtd->name = dev_name(dev);
++	mtd->priv = nor;
+ 	mtd->type = MTD_NORFLASH;
+ 	mtd->writesize = 1;
+ 	mtd->flags = MTD_CAP_NORFLASH;
+@@ -1061,15 +1216,18 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	mtd->_erase = spi_nor_erase;
+ 	mtd->_read = spi_nor_read;
+ 
+-	/* nor protection support for STmicro chips */
+-	if (JEDEC_MFR(info) == CFI_MFR_ST) {
++	/* NOR protection support for STmicro/Micron chips and similar */
++	if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
++	    JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+ 		nor->flash_lock = stm_lock;
+ 		nor->flash_unlock = stm_unlock;
++		nor->flash_is_locked = stm_is_locked;
+ 	}
+ 
+-	if (nor->flash_lock && nor->flash_unlock) {
++	if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
+ 		mtd->_lock = spi_nor_lock;
+ 		mtd->_unlock = spi_nor_unlock;
++		mtd->_is_locked = spi_nor_is_locked;
+ 	}
+ 
+ 	/* sst nor chips use AAI word program */
+@@ -1156,7 +1314,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	else if (mtd->size > 0x1000000) {
+ 		/* enable 4-byte addressing if the device exceeds 16MiB */
+ 		nor->addr_width = 4;
+-		if (JEDEC_MFR(info) == CFI_MFR_AMD) {
++		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
+ 			/* Dedicated 4-byte command set */
+ 			switch (nor->flash_read) {
+ 			case SPI_NOR_QUAD:
+@@ -1184,7 +1342,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 
+ 	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+ 
+-	dev_info(dev, "%s (%lld Kbytes)\n", id->name,
++	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+ 			(long long)mtd->size >> 10);
+ 
+ 	dev_dbg(dev,
+@@ -1207,11 +1365,11 @@ int spi_nor_scan(struct spi_nor *nor, co
+ }
+ EXPORT_SYMBOL_GPL(spi_nor_scan);
+ 
+-static const struct spi_device_id *spi_nor_match_id(const char *name)
++static const struct flash_info *spi_nor_match_id(const char *name)
+ {
+-	const struct spi_device_id *id = spi_nor_ids;
++	const struct flash_info *id = spi_nor_ids;
+ 
+-	while (id->name[0]) {
++	while (id->name) {
+ 		if (!strcmp(name, id->name))
+ 			return id;
+ 		id++;
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -10,6 +10,23 @@
+ #ifndef __LINUX_MTD_SPI_NOR_H
+ #define __LINUX_MTD_SPI_NOR_H
+ 
++#include <linux/bitops.h>
++#include <linux/mtd/cfi.h>
++
++/*
++ * Manufacturer IDs
++ *
++ * The first byte returned from the flash after sending opcode SPINOR_OP_RDID.
++ * Sometimes these are the same as CFI IDs, but sometimes they aren't.
++ */
++#define SNOR_MFR_ATMEL		CFI_MFR_ATMEL
++#define SNOR_MFR_INTEL		CFI_MFR_INTEL
++#define SNOR_MFR_MICRON		CFI_MFR_ST /* ST Micro <--> Micron */
++#define SNOR_MFR_MACRONIX	CFI_MFR_MACRONIX
++#define SNOR_MFR_SPANSION	CFI_MFR_AMD
++#define SNOR_MFR_SST		CFI_MFR_SST
++#define SNOR_MFR_WINBOND	0xef
++
+ /*
+  * Note on opcode nomenclature: some opcodes have a format like
+  * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
+@@ -61,24 +78,24 @@
+ #define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
+ 
+ /* Status Register bits. */
+-#define SR_WIP			1	/* Write in progress */
+-#define SR_WEL			2	/* Write enable latch */
++#define SR_WIP			BIT(0)	/* Write in progress */
++#define SR_WEL			BIT(1)	/* Write enable latch */
+ /* meaning of other SR_* bits may differ between vendors */
+-#define SR_BP0			4	/* Block protect 0 */
+-#define SR_BP1			8	/* Block protect 1 */
+-#define SR_BP2			0x10	/* Block protect 2 */
+-#define SR_SRWD			0x80	/* SR write protect */
++#define SR_BP0			BIT(2)	/* Block protect 0 */
++#define SR_BP1			BIT(3)	/* Block protect 1 */
++#define SR_BP2			BIT(4)	/* Block protect 2 */
++#define SR_SRWD			BIT(7)	/* SR write protect */
+ 
+-#define SR_QUAD_EN_MX		0x40	/* Macronix Quad I/O */
++#define SR_QUAD_EN_MX		BIT(6)	/* Macronix Quad I/O */
+ 
+ /* Enhanced Volatile Configuration Register bits */
+-#define EVCR_QUAD_EN_MICRON    0x80    /* Micron Quad I/O */
++#define EVCR_QUAD_EN_MICRON	BIT(7)	/* Micron Quad I/O */
+ 
+ /* Flag Status Register bits */
+-#define FSR_READY		0x80
++#define FSR_READY		BIT(7)
+ 
+ /* Configuration Register bits. */
+-#define CR_QUAD_EN_SPAN		0x2	/* Spansion Quad I/O */
++#define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
+ 
+ enum read_mode {
+ 	SPI_NOR_NORMAL = 0,
+@@ -87,33 +104,6 @@ enum read_mode {
+ 	SPI_NOR_QUAD,
+ };
+ 
+-/**
+- * struct spi_nor_xfer_cfg - Structure for defining a Serial Flash transfer
+- * @wren:		command for "Write Enable", or 0x00 for not required
+- * @cmd:		command for operation
+- * @cmd_pins:		number of pins to send @cmd (1, 2, 4)
+- * @addr:		address for operation
+- * @addr_pins:		number of pins to send @addr (1, 2, 4)
+- * @addr_width:		number of address bytes
+- *			(3,4, or 0 for address not required)
+- * @mode:		mode data
+- * @mode_pins:		number of pins to send @mode (1, 2, 4)
+- * @mode_cycles:	number of mode cycles (0 for mode not required)
+- * @dummy_cycles:	number of dummy cycles (0 for dummy not required)
+- */
+-struct spi_nor_xfer_cfg {
+-	u8		wren;
+-	u8		cmd;
+-	u8		cmd_pins;
+-	u32		addr;
+-	u8		addr_pins;
+-	u8		addr_width;
+-	u8		mode;
+-	u8		mode_pins;
+-	u8		mode_cycles;
+-	u8		dummy_cycles;
+-};
+-
+ #define SPI_NOR_MAX_CMD_SIZE	8
+ enum spi_nor_ops {
+ 	SPI_NOR_OPS_READ = 0,
+@@ -127,11 +117,14 @@ enum spi_nor_option_flags {
+ 	SNOR_F_USE_FSR		= BIT(0),
+ };
+ 
++struct mtd_info;
++
+ /**
+  * struct spi_nor - Structure for defining a the SPI NOR layer
+  * @mtd:		point to a mtd_info structure
+  * @lock:		the lock for the read/write/erase/lock/unlock operations
+  * @dev:		point to a spi device, or a spi nor controller device.
++ * @flash_node:		point to a device node describing this flash instance.
+  * @page_size:		the page size of the SPI NOR
+  * @addr_width:		number of address bytes
+  * @erase_opcode:	the opcode for erasing a sector
+@@ -141,28 +134,28 @@ enum spi_nor_option_flags {
+  * @flash_read:		the mode of the read
+  * @sst_write_second:	used by the SST write operation
+  * @flags:		flag options for the current SPI-NOR (SNOR_F_*)
+- * @cfg:		used by the read_xfer/write_xfer
+  * @cmd_buf:		used by the write_reg
+  * @prepare:		[OPTIONAL] do some preparations for the
+  *			read/write/erase/lock/unlock operations
+  * @unprepare:		[OPTIONAL] do some post work after the
+  *			read/write/erase/lock/unlock operations
+- * @read_xfer:		[OPTIONAL] the read fundamental primitive
+- * @write_xfer:		[OPTIONAL] the writefundamental primitive
+  * @read_reg:		[DRIVER-SPECIFIC] read out the register
+  * @write_reg:		[DRIVER-SPECIFIC] write data to the register
+  * @read:		[DRIVER-SPECIFIC] read data from the SPI NOR
+  * @write:		[DRIVER-SPECIFIC] write data to the SPI NOR
+  * @erase:		[DRIVER-SPECIFIC] erase a sector of the SPI NOR
+  *			at the offset @offs
+- * @lock:		[FLASH-SPECIFIC] lock a region of the SPI NOR
+- * @unlock:		[FLASH-SPECIFIC] unlock a region of the SPI NOR
++ * @flash_lock:		[FLASH-SPECIFIC] lock a region of the SPI NOR
++ * @flash_unlock:	[FLASH-SPECIFIC] unlock a region of the SPI NOR
++ * @flash_is_locked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
++ *			completely locked
+  * @priv:		the private data
+  */
+ struct spi_nor {
+-	struct mtd_info		*mtd;
++	struct mtd_info		mtd;
+ 	struct mutex		lock;
+ 	struct device		*dev;
++	struct device_node	*flash_node;
+ 	u32			page_size;
+ 	u8			addr_width;
+ 	u8			erase_opcode;
+@@ -172,18 +165,12 @@ struct spi_nor {
+ 	enum read_mode		flash_read;
+ 	bool			sst_write_second;
+ 	u32			flags;
+-	struct spi_nor_xfer_cfg	cfg;
+ 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+ 
+ 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+ 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
+-	int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+-			 u8 *buf, size_t len);
+-	int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+-			  u8 *buf, size_t len);
+ 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+-	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+-			int write_enable);
++	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+ 
+ 	int (*read)(struct spi_nor *nor, loff_t from,
+ 			size_t len, size_t *retlen, u_char *read_buf);
+@@ -193,6 +180,7 @@ struct spi_nor {
+ 
+ 	int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
+ 	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
++	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
+ 
+ 	void *priv;
+ };
diff --git a/target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch b/target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch
new file mode 100644
index 0000000000..d0bea944ac
--- /dev/null
+++ b/target/linux/generic/patches-4.1/095-api-fix-compatibility-of-linux-in.h-with-netinet-in..patch
@@ -0,0 +1,146 @@
+From 279c6c7fa64f5763e6b9f05e7ab3840092e702e7 Mon Sep 17 00:00:00 2001
+From: Stephen Hemminger <stephen@networkplumber.org>
+Date: Mon, 29 Jun 2015 14:57:48 -1000
+Subject: [PATCH] api: fix compatibility of linux/in.h with netinet/in.h
+
+u
+This fixes breakage to iproute2 build with recent kernel headers
+caused by:
+   commit a263653ed798216c0069922d7b5237ca49436007
+   Author: Pablo Neira Ayuso <pablo@netfilter.org>
+   Date:   Wed Jun 17 10:28:27 2015 -0500
+
+   netfilter: don't pull include/linux/netfilter.h from netns headers
+
+The issue is that definitions in linux/in.h overlap with those
+in netinet/in.h. This patch solves this by introducing the same
+mechanism as was used to solve the same problem with linux/in6.h
+
+Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/uapi/linux/in.h          | 16 +++++++++++++---
+ include/uapi/linux/libc-compat.h | 22 ++++++++++++++++++++++
+ 2 files changed, 35 insertions(+), 3 deletions(-)
+
+--- a/include/uapi/linux/in.h
++++ b/include/uapi/linux/in.h
+@@ -19,8 +19,10 @@
+ #define _UAPI_LINUX_IN_H
+ 
+ #include <linux/types.h>
++#include <linux/libc-compat.h>
+ #include <linux/socket.h>
+ 
++#if __UAPI_DEF_IN_IPPROTO
+ /* Standard well-defined IP protocols.  */
+ enum {
+   IPPROTO_IP = 0,		/* Dummy protocol for TCP		*/
+@@ -73,12 +75,14 @@ enum {
+ #define IPPROTO_RAW		IPPROTO_RAW
+   IPPROTO_MAX
+ };
++#endif
+ 
+-
++#if __UAPI_DEF_IN_ADDR
+ /* Internet address. */
+ struct in_addr {
+ 	__be32	s_addr;
+ };
++#endif
+ 
+ #define IP_TOS		1
+ #define IP_TTL		2
+@@ -155,6 +159,7 @@ struct in_addr {
+ 
+ /* Request struct for multicast socket ops */
+ 
++#if __UAPI_DEF_IP_MREQ
+ struct ip_mreq  {
+ 	struct in_addr imr_multiaddr;	/* IP multicast address of group */
+ 	struct in_addr imr_interface;	/* local IP address of interface */
+@@ -206,14 +211,18 @@ struct group_filter {
+ #define GROUP_FILTER_SIZE(numsrc) \
+ 	(sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
+ 	+ (numsrc) * sizeof(struct __kernel_sockaddr_storage))
++#endif
+ 
++#if __UAPI_DEF_IN_PKTINFO
+ struct in_pktinfo {
+ 	int		ipi_ifindex;
+ 	struct in_addr	ipi_spec_dst;
+ 	struct in_addr	ipi_addr;
+ };
++#endif
+ 
+ /* Structure describing an Internet (IP) socket address. */
++#if  __UAPI_DEF_SOCKADDR_IN
+ #define __SOCK_SIZE__	16		/* sizeof(struct sockaddr)	*/
+ struct sockaddr_in {
+   __kernel_sa_family_t	sin_family;	/* Address family		*/
+@@ -225,8 +234,9 @@ struct sockaddr_in {
+ 			sizeof(unsigned short int) - sizeof(struct in_addr)];
+ };
+ #define sin_zero	__pad		/* for BSD UNIX comp. -FvK	*/
++#endif
+ 
+-
++#if __UAPI_DEF_IN_CLASS
+ /*
+  * Definitions of the bits in an Internet address integer.
+  * On subnets, host and network parts are found according
+@@ -277,7 +287,7 @@ struct sockaddr_in {
+ #define INADDR_ALLHOSTS_GROUP 	0xe0000001U	/* 224.0.0.1   */
+ #define INADDR_ALLRTRS_GROUP    0xe0000002U	/* 224.0.0.2 */
+ #define INADDR_MAX_LOCAL_GROUP  0xe00000ffU	/* 224.0.0.255 */
+-
++#endif
+ 
+ /* <asm/byteorder.h> contains the htonl type stuff.. */
+ #include <asm/byteorder.h> 
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -56,6 +56,13 @@
+ 
+ /* GLIBC headers included first so don't define anything
+  * that would already be defined. */
++#define __UAPI_DEF_IN_ADDR		0
++#define __UAPI_DEF_IN_IPPROTO		0
++#define __UAPI_DEF_IN_PKTINFO		0
++#define __UAPI_DEF_IP_MREQ		0
++#define __UAPI_DEF_SOCKADDR_IN		0
++#define __UAPI_DEF_IN_CLASS		0
++
+ #define __UAPI_DEF_IN6_ADDR		0
+ /* The exception is the in6_addr macros which must be defined
+  * if the glibc code didn't define them. This guard matches
+@@ -78,6 +85,13 @@
+ /* Linux headers included first, and we must define everything
+  * we need. The expectation is that glibc will check the
+  * __UAPI_DEF_* defines and adjust appropriately. */
++#define __UAPI_DEF_IN_ADDR		1
++#define __UAPI_DEF_IN_IPPROTO		1
++#define __UAPI_DEF_IN_PKTINFO		1
++#define __UAPI_DEF_IP_MREQ		1
++#define __UAPI_DEF_SOCKADDR_IN		1
++#define __UAPI_DEF_IN_CLASS		1
++
+ #define __UAPI_DEF_IN6_ADDR		1
+ /* We unconditionally define the in6_addr macros and glibc must
+  * coordinate. */
+@@ -103,6 +117,14 @@
+  * that we need. */
+ #else /* !defined(__GLIBC__) */
+ 
++/* Definitions for in.h */
++#define __UAPI_DEF_IN_ADDR		1
++#define __UAPI_DEF_IN_IPPROTO		1
++#define __UAPI_DEF_IN_PKTINFO		1
++#define __UAPI_DEF_IP_MREQ		1
++#define __UAPI_DEF_SOCKADDR_IN		1
++#define __UAPI_DEF_IN_CLASS		1
++
+ /* Definitions for in6.h */
+ #define __UAPI_DEF_IN6_ADDR		1
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
diff --git a/target/linux/generic/patches-4.1/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch b/target/linux/generic/patches-4.1/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch
new file mode 100644
index 0000000000..4800ee2ea2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/097-mm-remove-gup_flags-FOLL_WRITE-games-from-__get_user.patch
@@ -0,0 +1,90 @@
+From c865f98df72112a3997b219bf711bc46c1e90706 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 13 Oct 2016 13:07:36 -0700
+Subject: [PATCH] mm: remove gup_flags FOLL_WRITE games from __get_user_pages()
+
+[ Upstream commit 19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619 ]
+
+This is an ancient bug that was actually attempted to be fixed once
+(badly) by me eleven years ago in commit 4ceb5db9757a ("Fix
+get_user_pages() race for write access") but that was then undone due to
+problems on s390 by commit f33ea7f404e5 ("fix get_user_pages bug").
+
+In the meantime, the s390 situation has long been fixed, and we can now
+fix it by checking the pte_dirty() bit properly (and do it better).  The
+s390 dirty bit was implemented in abf09bed3cce ("s390/mm: implement
+software dirty bits") which made it into v3.9.  Earlier kernels will
+have to look at the page state itself.
+
+Also, the VM has become more scalable, and what used a purely
+theoretical race back then has become easier to trigger.
+
+To fix it, we introduce a new internal FOLL_COW flag to mark the "yes,
+we already did a COW" rather than play racy games with FOLL_WRITE that
+is very fundamental, and then use the pte dirty flag to validate that
+the FOLL_COW flag is still valid.
+
+Reported-and-tested-by: Phil "not Paul" Oester <kernel@linuxace.com>
+Acked-by: Hugh Dickins <hughd@google.com>
+Reviewed-by: Michal Hocko <mhocko@suse.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: Willy Tarreau <w@1wt.eu>
+Cc: Nick Piggin <npiggin@gmail.com>
+Cc: Greg Thelen <gthelen@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
+---
+ include/linux/mm.h |  1 +
+ mm/gup.c           | 14 ++++++++++++--
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -2064,6 +2064,7 @@ static inline struct page *follow_page(s
+ #define FOLL_NUMA	0x200	/* force NUMA hinting page fault */
+ #define FOLL_MIGRATION	0x400	/* wait for page to replace migration entry */
+ #define FOLL_TRIED	0x800	/* a retry, previous pass started an IO */
++#define FOLL_COW	0x4000	/* internal GUP flag */
+ 
+ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
+ 			void *data);
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -32,6 +32,16 @@ static struct page *no_page_table(struct
+ 	return NULL;
+ }
+ 
++/*
++ * FOLL_FORCE can write to even unwritable pte's, but only
++ * after we've gone through a COW cycle and they are dirty.
++ */
++static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
++{
++	return pte_write(pte) ||
++		((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
++}
++
+ static struct page *follow_page_pte(struct vm_area_struct *vma,
+ 		unsigned long address, pmd_t *pmd, unsigned int flags)
+ {
+@@ -66,7 +76,7 @@ retry:
+ 	}
+ 	if ((flags & FOLL_NUMA) && pte_protnone(pte))
+ 		goto no_page;
+-	if ((flags & FOLL_WRITE) && !pte_write(pte)) {
++	if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
+ 		pte_unmap_unlock(ptep, ptl);
+ 		return NULL;
+ 	}
+@@ -315,7 +325,7 @@ static int faultin_page(struct task_stru
+ 	 * reCOWed by userspace write).
+ 	 */
+ 	if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
+-		*flags &= ~FOLL_WRITE;
++	        *flags |= FOLL_COW;
+ 	return 0;
+ }
+ 
diff --git a/target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch b/target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch
new file mode 100644
index 0000000000..4da579cedc
--- /dev/null
+++ b/target/linux/generic/patches-4.1/102-ehci_hcd_ignore_oc.patch
@@ -0,0 +1,82 @@
+From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:29 +0100
+Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent
+ checking
+
+This patch adds an ignore_oc flag which can be set by EHCI controller
+not supporting or wanting to disable overcurrent checking. The EHCI
+platform data in include/linux/usb/ehci_pdriver.h is also augmented to
+take advantage of this new flag.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ drivers/usb/host/ehci-hcd.c      |    2 +-
+ drivers/usb/host/ehci-hub.c      |    4 ++--
+ drivers/usb/host/ehci-platform.c |    1 +
+ drivers/usb/host/ehci.h          |    1 +
+ include/linux/usb/ehci_pdriver.h |    1 +
+ 5 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -638,7 +638,7 @@ static int ehci_run (struct usb_hcd *hcd
+ 		"USB %x.%x started, EHCI %x.%02x%s\n",
+ 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
+ 		temp >> 8, temp & 0xff,
+-		ignore_oc ? ", overcurrent ignored" : "");
++		(ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
+ 
+ 	ehci_writel(ehci, INTR_MASK,
+ 		    &ehci->regs->intr_enable); /* Turn On Interrupts */
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -633,7 +633,7 @@ ehci_hub_status_data (struct usb_hcd *hc
+ 	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
+ 	 * PORT_POWER; that's surprising, but maybe within-spec.
+ 	 */
+-	if (!ignore_oc)
++	if (!ignore_oc && !ehci->ignore_oc)
+ 		mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ 	else
+ 		mask = PORT_CSC | PORT_PEC;
+@@ -995,7 +995,7 @@ int ehci_hub_control(
+ 		if (temp & PORT_PEC)
+ 			status |= USB_PORT_STAT_C_ENABLE << 16;
+ 
+-		if ((temp & PORT_OCC) && !ignore_oc){
++		if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
+ 			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ 
+ 			/*
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -264,6 +264,8 @@ static int ehci_platform_probe(struct pl
+ 		ehci->big_endian_desc = 1;
+ 	if (pdata->big_endian_mmio)
+ 		ehci->big_endian_mmio = 1;
++	if (pdata->ignore_oc)
++		ehci->ignore_oc = 1;
+ 
+ #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ 	if (ehci->big_endian_mmio) {
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -226,6 +226,7 @@ struct ehci_hcd {			/* one per controlle
+ 	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
+ 	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
+ 	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
++	unsigned		ignore_oc:1;
+ 
+ 	/* required for usb32 quirk */
+ 	#define OHCI_CTRL_HCFS          (3 << 6)
+--- a/include/linux/usb/ehci_pdriver.h
++++ b/include/linux/usb/ehci_pdriver.h
+@@ -49,6 +49,7 @@ struct usb_ehci_pdata {
+ 	unsigned	no_io_watchdog:1;
+ 	unsigned	reset_on_resume:1;
+ 	unsigned	dma_mask_64:1;
++	unsigned	ignore_oc:1;
+ 
+ 	/* Turn on all power and clocks */
+ 	int (*power_on)(struct platform_device *pdev);
diff --git a/target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
new file mode 100644
index 0000000000..c5d8321b85
--- /dev/null
+++ b/target/linux/generic/patches-4.1/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
@@ -0,0 +1,86 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 10 Apr 2015 13:35:29 +0200
+Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support
+
+It is required for renames on overlayfs
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s
+ static int jffs2_rmdir (struct inode *,struct dentry *);
+ static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
+ static int jffs2_rename (struct inode *, struct dentry *,
+-			 struct inode *, struct dentry *);
++			 struct inode *, struct dentry *, unsigned int);
+ 
+ const struct file_operations jffs2_dir_operations =
+ {
+@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_
+ 	.mkdir =	jffs2_mkdir,
+ 	.rmdir =	jffs2_rmdir,
+ 	.mknod =	jffs2_mknod,
+-	.rename =	jffs2_rename,
++	.rename2 =	jffs2_rename,
+ 	.get_acl =	jffs2_get_acl,
+ 	.set_acl =	jffs2_set_acl,
+ 	.setattr =	jffs2_setattr,
+@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di
+ 	return ret;
+ }
+ 
++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry)
++{
++	struct dentry *wh;
++	int err;
++
++	wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
++	if (!wh)
++		return -ENOMEM;
++
++	err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
++			  WHITEOUT_DEV);
++	if (err)
++		return err;
++
++	d_rehash(wh);
++	return 0;
++}
++
+ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
+-			 struct inode *new_dir_i, struct dentry *new_dentry)
++			 struct inode *new_dir_i, struct dentry *new_dentry,
++			 unsigned int flags)
+ {
+ 	int ret;
+ 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
+@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
++	if (flags & ~RENAME_WHITEOUT)
++		return -EINVAL;
++
+ 	/* The VFS will check for us and prevent trying to rename a
+ 	 * file over a directory and vice versa, but if it's a directory,
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o
+ 	if (d_is_dir(old_dentry) && !victim_f)
+ 		inc_nlink(new_dir_i);
+ 
+-	/* Unlink the original */
+-	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+-			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
++	if (flags & RENAME_WHITEOUT)
++		/* Replace with whiteout */
++		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else
++		/* Unlink the original */
++		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
++				      old_dentry->d_name.name,
++				      old_dentry->d_name.len, NULL, now);
+ 
+ 	/* We don't touch inode->i_nlink */
+ 
diff --git a/target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch
new file mode 100644
index 0000000000..e1f1b29e1e
--- /dev/null
+++ b/target/linux/generic/patches-4.1/111-jffs2-add-RENAME_EXCHANGE-support.patch
@@ -0,0 +1,58 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 25 Apr 2015 12:41:32 +0200
+Subject: [PATCH] jffs2: add RENAME_EXCHANGE support
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
+-	if (flags & ~RENAME_WHITEOUT)
++	if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE))
+ 		return -EINVAL;
+ 
+ 	/* The VFS will check for us and prevent trying to rename a
+@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+ 	 * needs to do that for itself.
+ 	 */
+-	if (d_really_is_positive(new_dentry)) {
++	if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
+ 		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
+ 		if (d_is_dir(new_dentry)) {
+ 			struct jffs2_full_dirent *fd;
+@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o
+ 	if (ret)
+ 		return ret;
+ 
+-	if (victim_f) {
++	if (victim_f && !(flags & RENAME_EXCHANGE)) {
+ 		/* There was a victim. Kill it off nicely */
+ 		if (d_is_dir(new_dentry))
+ 			clear_nlink(d_inode(new_dentry));
+@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o
+ 	if (flags & RENAME_WHITEOUT)
+ 		/* Replace with whiteout */
+ 		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else if (flags & RENAME_EXCHANGE)
++		/* Replace the original */
++		ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
++				    d_inode(new_dentry)->i_ino, type,
++				    old_dentry->d_name.name, old_dentry->d_name.len,
++				    now);
+ 	else
+ 		/* Unlink the original */
+ 		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+@@ -884,7 +890,7 @@ static int jffs2_rename (struct inode *o
+ 		return ret;
+ 	}
+ 
+-	if (d_is_dir(old_dentry))
++	if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
+ 		drop_nlink(old_dir_i);
+ 
+ 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
diff --git a/target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch
new file mode 100644
index 0000000000..41e322850f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/120-bridge_allow_receiption_on_disabled_port.patch
@@ -0,0 +1,54 @@
+From: Stephen Hemminger <stephen@networkplumber.org>
+Subject: bridge: allow receiption on disabled port
+
+When an ethernet device is enslaved to a bridge, and the bridge STP
+detects loss of carrier (or operational state down), then normally
+packet receiption is blocked.
+
+This breaks control applications like WPA which maybe expecting to
+receive packets to negotiate to bring link up. The bridge needs to
+block forwarding packets from these disabled ports, but there is no
+hard requirement to not allow local packet delivery.
+
+Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -211,11 +211,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish
+ static int br_handle_local_finish(struct sock *sk, struct sk_buff *skb)
+ {
+ 	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
+-	u16 vid = 0;
++	if (p->state != BR_STATE_DISABLED) {
++		u16 vid = 0;
+ 
+-	/* check if vlan is allowed, to avoid spoofing */
+-	if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
+-		br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
++		/* check if vlan is allowed, to avoid spoofing */
++		if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
++			br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
++	}
+ 	return 0;	 /* process further */
+ }
+ 
+@@ -289,6 +291,18 @@ rx_handler_result_t br_handle_frame(stru
+ 
+ forward:
+ 	switch (p->state) {
++	case BR_STATE_DISABLED:
++		if (ether_addr_equal(p->br->dev->dev_addr, dest))
++			skb->pkt_type = PACKET_HOST;
++
++		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, skb->dev, NULL,
++			br_handle_local_finish))
++			break;
++
++		BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
++		br_pass_frame_up(skb);
++		break;
++
+ 	case BR_STATE_FORWARDING:
+ 		rhook = rcu_dereference(br_should_route_hook);
+ 		if (rhook) {
diff --git a/target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch b/target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch
new file mode 100644
index 0000000000..0b38d9c699
--- /dev/null
+++ b/target/linux/generic/patches-4.1/132-mips_inline_dma_ops.patch
@@ -0,0 +1,697 @@
+From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 12 Aug 2013 12:50:22 +0200
+Subject: [PATCH] MIPS: partially inline dma ops
+
+Several DMA ops are no-op on many platforms, and the indirection through
+the mips_dma_map_ops function table is causing the compiler to emit
+unnecessary code.
+
+Inlining visibly improves network performance in my tests (on a 24Kc
+based system), and also slightly reduces code size of a few drivers.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/Kconfig                   |   4 +
+ arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++-
+ arch/mips/mm/dma-default.c          | 163 ++--------------
+ 3 files changed, 373 insertions(+), 154 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1571,6 +1571,7 @@ config CPU_CAVIUM_OCTEON
+ 	select CPU_SUPPORTS_HUGEPAGES
+ 	select USB_EHCI_BIG_ENDIAN_MMIO
+ 	select MIPS_L1_CACHE_SHIFT_7
++	select SYS_HAS_DMA_OPS
+ 	help
+ 	  The Cavium Octeon processor is a highly integrated chip containing
+ 	  many ethernet hardware widgets for networking tasks. The processor
+@@ -1866,6 +1867,9 @@ config MIPS_MALTA_PM
+ 	bool
+ 	default y
+ 
++config SYS_HAS_DMA_OPS
++	bool
++
+ #
+ # CPU may reorder R->R, R->W, W->R, W->W
+ # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+--- a/arch/mips/include/asm/dma-mapping.h
++++ b/arch/mips/include/asm/dma-mapping.h
+@@ -1,9 +1,16 @@
+ #ifndef _ASM_DMA_MAPPING_H
+ #define _ASM_DMA_MAPPING_H
+ 
++#include <linux/kmemcheck.h>
++#include <linux/bug.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-debug.h>
++#include <linux/dma-attrs.h>
++
+ #include <asm/scatterlist.h>
+ #include <asm/dma-coherence.h>
+ #include <asm/cache.h>
++#include <asm/cpu-type.h>
+ #include <asm-generic/dma-coherent.h>
+ 
+ #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
+@@ -12,12 +19,48 @@
+ 
+ extern struct dma_map_ops *mips_dma_map_ops;
+ 
++void __dma_sync(struct page *page, unsigned long offset, size_t size,
++		enum dma_data_direction direction);
++void *mips_dma_alloc_coherent(struct device *dev, size_t size,
++			      dma_addr_t *dma_handle, gfp_t gfp,
++			      struct dma_attrs *attrs);
++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++			    dma_addr_t dma_handle, struct dma_attrs *attrs);
++
+ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+ {
++#ifdef CONFIG_SYS_HAS_DMA_OPS
+ 	if (dev && dev->archdata.dma_ops)
+ 		return dev->archdata.dma_ops;
+ 	else
+ 		return mips_dma_map_ops;
++#else
++	return NULL;
++#endif
++}
++
++/*
++ * Warning on the terminology - Linux calls an uncached area coherent;
++ * MIPS terminology calls memory areas with hardware maintained coherency
++ * coherent.
++ */
++
++static inline int cpu_needs_post_dma_flush(struct device *dev)
++{
++#ifndef CONFIG_SYS_HAS_CPU_R10000
++	return 0;
++#endif
++	return !plat_device_is_coherent(dev) &&
++	       (boot_cpu_type() == CPU_R10000 ||
++		boot_cpu_type() == CPU_R12000 ||
++		boot_cpu_type() == CPU_BMIPS5000);
++}
++
++static inline struct page *dma_addr_to_page(struct device *dev,
++	dma_addr_t dma_addr)
++{
++	return pfn_to_page(
++		plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
+ }
+ 
+ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+@@ -30,12 +73,306 @@ static inline bool dma_capable(struct de
+ 
+ static inline void dma_mark_clean(void *addr, size_t size) {}
+ 
+-#include <asm-generic/dma-mapping-common.h>
++static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
++					      size_t size,
++					      enum dma_data_direction dir,
++					      struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	unsigned long offset = (unsigned long)ptr & ~PAGE_MASK;
++	struct page *page = virt_to_page(ptr);
++	dma_addr_t addr;
++
++	kmemcheck_mark_initialized(ptr, size);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		addr = ops->map_page(dev, page, offset, size, dir, attrs);
++	} else {
++		if (!plat_device_is_coherent(dev))
++			__dma_sync(page, offset, size, dir);
++
++		addr = plat_map_dma_mem_page(dev, page) + offset;
++	}
++	debug_dma_map_page(dev, page, offset, size, dir, addr, true);
++	return addr;
++}
++
++static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
++					  size_t size,
++					  enum dma_data_direction dir,
++					  struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->unmap_page(dev, addr, size, dir, attrs);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++
++		plat_unmap_dma_mem(dev, addr, size, dir);
++	}
++	debug_dma_unmap_page(dev, addr, size, dir, true);
++}
++
++static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
++				   int nents, enum dma_data_direction dir,
++				   struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	int i, ents;
++	struct scatterlist *s;
++
++	for_each_sg(sg, s, nents, i)
++		kmemcheck_mark_initialized(sg_virt(s), s->length);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ents = ops->map_sg(dev, sg, nents, dir, attrs);
++	} else {
++		for_each_sg(sg, s, nents, i) {
++			struct page *page = sg_page(s);
++
++			if (!plat_device_is_coherent(dev))
++				__dma_sync(page, s->offset, s->length, dir);
++#ifdef CONFIG_NEED_SG_DMA_LENGTH
++			s->dma_length = s->length;
++#endif
++			s->dma_address =
++				plat_map_dma_mem_page(dev, page) + s->offset;
++		}
++		ents = nents;
++	}
++	debug_dma_map_sg(dev, sg, nents, ents, dir);
++
++	return ents;
++}
++
++static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
++				      int nents, enum dma_data_direction dir,
++				      struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	debug_dma_unmap_sg(dev, sg, nents, dir);
++	if (ops) {
++		ops->unmap_sg(dev, sg, nents, dir, attrs);
++		return;
++	}
++
++	for_each_sg(sg, s, nents, i) {
++		if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++		plat_unmap_dma_mem(dev, s->dma_address, s->length, dir);
++	}
++}
++
++static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
++				      size_t offset, size_t size,
++				      enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	dma_addr_t addr;
++
++	kmemcheck_mark_initialized(page_address(page) + offset, size);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		addr = ops->map_page(dev, page, offset, size, dir, NULL);
++	} else {
++		if (!plat_device_is_coherent(dev))
++			__dma_sync(page, offset, size, dir);
++
++		addr = plat_map_dma_mem_page(dev, page) + offset;
++	}
++	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
++
++	return addr;
++}
++
++static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
++				  size_t size, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->unmap_page(dev, addr, size, dir, NULL);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++		plat_post_dma_flush(dev);
++		plat_unmap_dma_mem(dev, addr, size, dir);
++	}
++	debug_dma_unmap_page(dev, addr, size, dir, false);
++}
++
++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
++					   size_t size,
++					   enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_cpu(dev, addr, size, dir);
++	else if (cpu_needs_post_dma_flush(dev))
++		__dma_sync(dma_addr_to_page(dev, addr),
++			   addr & ~PAGE_MASK, size, dir);
++	plat_post_dma_flush(dev);
++	debug_dma_sync_single_for_cpu(dev, addr, size, dir);
++}
++
++static inline void dma_sync_single_for_device(struct device *dev,
++					      dma_addr_t addr, size_t size,
++					      enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_device(dev, addr, size, dir);
++	else if (!plat_device_is_coherent(dev))
++		__dma_sync(dma_addr_to_page(dev, addr),
++			   addr & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_for_device(dev, addr, size, dir);
++}
++
++static inline void dma_sync_single_range_for_cpu(struct device *dev,
++						 dma_addr_t addr,
++						 unsigned long offset,
++						 size_t size,
++						 enum dma_data_direction dir)
++{
++	const struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_cpu(dev, addr + offset, size, dir);
++	else if (cpu_needs_post_dma_flush(dev))
++		__dma_sync(dma_addr_to_page(dev, addr + offset),
++			   (addr + offset) & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
++}
++
++static inline void dma_sync_single_range_for_device(struct device *dev,
++						    dma_addr_t addr,
++						    unsigned long offset,
++						    size_t size,
++						    enum dma_data_direction dir)
++{
++	const struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_device(dev, addr + offset, size, dir);
++	else if (!plat_device_is_coherent(dev))
++		__dma_sync(dma_addr_to_page(dev, addr + offset),
++			   (addr + offset) & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
++}
++
++static inline void
++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
++		    int nelems, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_sg_for_cpu(dev, sg, nelems, dir);
++	else if (cpu_needs_post_dma_flush(dev)) {
++		for_each_sg(sg, s, nelems, i)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++	}
++	plat_post_dma_flush(dev);
++	debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
++		       int nelems, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_sg_for_device(dev, sg, nelems, dir);
++	else if (!plat_device_is_coherent(dev)) {
++		for_each_sg(sg, s, nelems, i)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++	}
++	debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
++
++}
++
++#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
++#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
++#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
++#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
++
++extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
++			   void *cpu_addr, dma_addr_t dma_addr, size_t size);
++
++/**
++ * dma_mmap_attrs - map a coherent DMA allocation into user space
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @vma: vm_area_struct describing requested user mapping
++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
++ * @handle: device-view address returned from dma_alloc_attrs
++ * @size: size of memory originally requested in dma_alloc_attrs
++ * @attrs: attributes of mapping properties requested in dma_alloc_attrs
++ *
++ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs
++ * into user space.  The coherent DMA buffer must not be freed by the
++ * driver until the user space mapping has been released.
++ */
++static inline int
++dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
++	       dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	BUG_ON(!ops);
++	if (ops && ops->mmap)
++		return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
++	return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
++}
++
++#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
++
++int
++dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
++		       void *cpu_addr, dma_addr_t dma_addr, size_t size);
++
++static inline int
++dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
++		      dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	BUG_ON(!ops);
++	if (ops && ops->get_sgtable)
++		return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
++					attrs);
++	return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
++}
++
++#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
++
+ 
+ static inline int dma_supported(struct device *dev, u64 mask)
+ {
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+-	return ops->dma_supported(dev, mask);
++	if (ops)
++		return ops->dma_supported(dev, mask);
++	return plat_dma_supported(dev, mask);
+ }
+ 
+ static inline int dma_mapping_error(struct device *dev, u64 mask)
+@@ -43,7 +380,9 @@ static inline int dma_mapping_error(stru
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+ 
+ 	debug_dma_mapping_error(dev, mask);
+-	return ops->mapping_error(dev, mask);
++	if (ops)
++		return ops->mapping_error(dev, mask);
++	return 0;
+ }
+ 
+ static inline int
+@@ -54,7 +393,7 @@ dma_set_mask(struct device *dev, u64 mas
+ 	if(!dev->dma_mask || !dma_supported(dev, mask))
+ 		return -EIO;
+ 
+-	if (ops->set_dma_mask)
++	if (ops && ops->set_dma_mask)
+ 		return ops->set_dma_mask(dev, mask);
+ 
+ 	*dev->dma_mask = mask;
+@@ -74,7 +413,11 @@ static inline void *dma_alloc_attrs(stru
+ 	void *ret;
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+ 
+-	ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
++	if (ops)
++		ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
++	else
++		ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp,
++					      attrs);
+ 
+ 	debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
+ 
+@@ -89,7 +432,10 @@ static inline void dma_free_attrs(struct
+ {
+ 	struct dma_map_ops *ops = get_dma_ops(dev);
+ 
+-	ops->free(dev, size, vaddr, dma_handle, attrs);
++	if (ops)
++		ops->free(dev, size, vaddr, dma_handle, attrs);
++	else
++		mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs);
+ 
+ 	debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+ }
+--- a/arch/mips/mm/dma-default.c
++++ b/arch/mips/mm/dma-default.c
+@@ -26,7 +26,7 @@
+ 
+ #ifdef CONFIG_DMA_MAYBE_COHERENT
+ int coherentio = 0;	/* User defined DMA coherency from command line. */
+-EXPORT_SYMBOL_GPL(coherentio);
++EXPORT_SYMBOL(coherentio);
+ int hw_coherentio = 0;	/* Actual hardware supported DMA coherency setting. */
+ 
+ static int __init setcoherentio(char *str)
+@@ -46,35 +46,6 @@ static int __init setnocoherentio(char *
+ early_param("nocoherentio", setnocoherentio);
+ #endif
+ 
+-static inline struct page *dma_addr_to_page(struct device *dev,
+-	dma_addr_t dma_addr)
+-{
+-	return pfn_to_page(
+-		plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
+-}
+-
+-/*
+- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
+- * speculatively fill random cachelines with stale data at any time,
+- * requiring an extra flush post-DMA.
+- *
+- * Warning on the terminology - Linux calls an uncached area coherent;
+- * MIPS terminology calls memory areas with hardware maintained coherency
+- * coherent.
+- *
+- * Note that the R14000 and R16000 should also be checked for in this
+- * condition.  However this function is only called on non-I/O-coherent
+- * systems and only the R10000 and R12000 are used in such systems, the
+- * SGI IP28 Indigo² rsp. SGI IP32 aka O2.
+- */
+-static inline int cpu_needs_post_dma_flush(struct device *dev)
+-{
+-	return !plat_device_is_coherent(dev) &&
+-	       (boot_cpu_type() == CPU_R10000 ||
+-		boot_cpu_type() == CPU_R12000 ||
+-		boot_cpu_type() == CPU_BMIPS5000);
+-}
+-
+ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
+ {
+ 	gfp_t dma_flag;
+@@ -130,8 +101,9 @@ void *dma_alloc_noncoherent(struct devic
+ }
+ EXPORT_SYMBOL(dma_alloc_noncoherent);
+ 
+-static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
+-	dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
++void *mips_dma_alloc_coherent(struct device *dev, size_t size,
++			      dma_addr_t *dma_handle, gfp_t gfp,
++			      struct dma_attrs *attrs)
+ {
+ 	void *ret;
+ 	struct page *page = NULL;
+@@ -162,6 +134,7 @@ static void *mips_dma_alloc_coherent(str
+ 
+ 	return ret;
+ }
++EXPORT_SYMBOL(mips_dma_alloc_coherent);
+ 
+ 
+ void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+@@ -172,8 +145,8 @@ void dma_free_noncoherent(struct device
+ }
+ EXPORT_SYMBOL(dma_free_noncoherent);
+ 
+-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+-	dma_addr_t dma_handle, struct dma_attrs *attrs)
++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++			    dma_addr_t dma_handle, struct dma_attrs *attrs)
+ {
+ 	unsigned long addr = (unsigned long) vaddr;
+ 	int order = get_order(size);
+@@ -193,6 +166,7 @@ static void mips_dma_free_coherent(struc
+ 	if (!dma_release_from_contiguous(dev, page, count))
+ 		__free_pages(page, get_order(size));
+ }
++EXPORT_SYMBOL(mips_dma_free_coherent);
+ 
+ static inline void __dma_sync_virtual(void *addr, size_t size,
+ 	enum dma_data_direction direction)
+@@ -221,8 +195,8 @@ static inline void __dma_sync_virtual(vo
+  * If highmem is not configured then the bulk of this loop gets
+  * optimized out.
+  */
+-static inline void __dma_sync(struct page *page,
+-	unsigned long offset, size_t size, enum dma_data_direction direction)
++void __dma_sync(struct page *page, unsigned long offset, size_t size,
++		enum dma_data_direction direction)
+ {
+ 	size_t left = size;
+ 
+@@ -251,110 +225,7 @@ static inline void __dma_sync(struct pag
+ 		left -= len;
+ 	} while (left);
+ }
+-
+-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+-	size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
+-{
+-	if (cpu_needs_post_dma_flush(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_addr),
+-			   dma_addr & ~PAGE_MASK, size, direction);
+-	plat_post_dma_flush(dev);
+-	plat_unmap_dma_mem(dev, dma_addr, size, direction);
+-}
+-
+-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg,
+-	int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+-{
+-	int i;
+-
+-	for (i = 0; i < nents; i++, sg++) {
+-		if (!plat_device_is_coherent(dev))
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-#ifdef CONFIG_NEED_SG_DMA_LENGTH
+-		sg->dma_length = sg->length;
+-#endif
+-		sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) +
+-				  sg->offset;
+-	}
+-
+-	return nents;
+-}
+-
+-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
+-	unsigned long offset, size_t size, enum dma_data_direction direction,
+-	struct dma_attrs *attrs)
+-{
+-	if (!plat_device_is_coherent(dev))
+-		__dma_sync(page, offset, size, direction);
+-
+-	return plat_map_dma_mem_page(dev, page) + offset;
+-}
+-
+-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+-	int nhwentries, enum dma_data_direction direction,
+-	struct dma_attrs *attrs)
+-{
+-	int i;
+-
+-	for (i = 0; i < nhwentries; i++, sg++) {
+-		if (!plat_device_is_coherent(dev) &&
+-		    direction != DMA_TO_DEVICE)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-		plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction);
+-	}
+-}
+-
+-static void mips_dma_sync_single_for_cpu(struct device *dev,
+-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+-{
+-	if (cpu_needs_post_dma_flush(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_handle),
+-			   dma_handle & ~PAGE_MASK, size, direction);
+-	plat_post_dma_flush(dev);
+-}
+-
+-static void mips_dma_sync_single_for_device(struct device *dev,
+-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+-{
+-	if (!plat_device_is_coherent(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_handle),
+-			   dma_handle & ~PAGE_MASK, size, direction);
+-}
+-
+-static void mips_dma_sync_sg_for_cpu(struct device *dev,
+-	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
+-{
+-	int i;
+-
+-	if (cpu_needs_post_dma_flush(dev))
+-		for (i = 0; i < nelems; i++, sg++)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-	plat_post_dma_flush(dev);
+-}
+-
+-static void mips_dma_sync_sg_for_device(struct device *dev,
+-	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
+-{
+-	int i;
+-
+-	if (!plat_device_is_coherent(dev))
+-		for (i = 0; i < nelems; i++, sg++)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-}
+-
+-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+-{
+-	return 0;
+-}
+-
+-int mips_dma_supported(struct device *dev, u64 mask)
+-{
+-	return plat_dma_supported(dev, mask);
+-}
++EXPORT_SYMBOL(__dma_sync);
+ 
+ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ 			 enum dma_data_direction direction)
+@@ -367,23 +238,10 @@ void dma_cache_sync(struct device *dev,
+ 
+ EXPORT_SYMBOL(dma_cache_sync);
+ 
+-static struct dma_map_ops mips_default_dma_map_ops = {
+-	.alloc = mips_dma_alloc_coherent,
+-	.free = mips_dma_free_coherent,
+-	.map_page = mips_dma_map_page,
+-	.unmap_page = mips_dma_unmap_page,
+-	.map_sg = mips_dma_map_sg,
+-	.unmap_sg = mips_dma_unmap_sg,
+-	.sync_single_for_cpu = mips_dma_sync_single_for_cpu,
+-	.sync_single_for_device = mips_dma_sync_single_for_device,
+-	.sync_sg_for_cpu = mips_dma_sync_sg_for_cpu,
+-	.sync_sg_for_device = mips_dma_sync_sg_for_device,
+-	.mapping_error = mips_dma_mapping_error,
+-	.dma_supported = mips_dma_supported
+-};
+-
+-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops;
++#ifdef CONFIG_SYS_HAS_DMA_OPS
++struct dma_map_ops *mips_dma_map_ops = NULL;
+ EXPORT_SYMBOL(mips_dma_map_ops);
++#endif
+ 
+ #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+ 
diff --git a/target/linux/generic/patches-4.1/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch b/target/linux/generic/patches-4.1/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch
new file mode 100644
index 0000000000..ebbe1bbaee
--- /dev/null
+++ b/target/linux/generic/patches-4.1/133-MIPS-UAPI-Ignore-__arch_swab-16-32-64-when-using-MIP.patch
@@ -0,0 +1,53 @@
+From 71a0a72456b48de972d7ed613b06a22a3aa9057f Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Sat, 26 Sep 2015 13:41:43 +0800
+Subject: [PATCH] MIPS: UAPI: Ignore __arch_swab{16,32,64} when using MIPS16
+
+Some GCC versions (e.g. 4.8.3) can incorrectly inline a function with
+MIPS32 instructions into another function with MIPS16 code [1], causing
+the assembler to genereate incorrect binary code or fail right away
+complaining about unrecognized opcode.
+
+In the case of __arch_swab{16,32}, when inlined by the compiler with
+flags `-mips32r2 -mips16 -Os', the assembler can fail with the following
+error.
+
+    {standard input}:79: Error: unrecognized opcode `wsbh $2,$2'
+
+For performance concerns and to workaround the issue already existing in
+older compilers, just ignore these 2 functions when compiling with
+mips16 enabled.
+
+ [1] Inlining nomips16 function into mips16 function can result in
+     undefined builtins, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55777
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+Cc: Maciej W. Rozycki <macro@linux-mips.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/11241/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/include/uapi/asm/swab.h |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/include/uapi/asm/swab.h
++++ b/arch/mips/include/uapi/asm/swab.h
+@@ -13,8 +13,9 @@
+ 
+ #define __SWAB_64_THRU_32__
+ 
+-#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) ||		\
+-    defined(_MIPS_ARCH_LOONGSON3A)
++#if !defined(__mips16) &&					\
++	((defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) ||	\
++	 defined(_MIPS_ARCH_LOONGSON3A))
+ 
+ static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
+ {
+@@ -65,5 +66,5 @@ static inline __attribute_const__ __u64
+ }
+ #define __arch_swab64 __arch_swab64
+ #endif /* __mips64 */
+-#endif /* MIPS R2 or newer or Loongson 3A */
++#endif /* (not __mips16) and (MIPS R2 or newer or Loongson 3A) */
+ #endif /* _ASM_SWAB_H */
diff --git a/target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch b/target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
new file mode 100644
index 0000000000..18ec833f70
--- /dev/null
+++ b/target/linux/generic/patches-4.1/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
@@ -0,0 +1,175 @@
+From 173b0add0cff6558f950c0cb1eacfb729d482711 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 May 2015 18:48:38 +0200
+Subject: [PATCH 4/8] mtd: part: add generic parsing of linux,part-probe
+
+This moves the linux,part-probe device tree parsing code from
+physmap_of.c to mtdpart.c. Now all drivers can use this feature by just
+providing a reference to their device tree node in struct
+mtd_part_parser_data.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ Documentation/devicetree/bindings/mtd/nand.txt | 16 ++++++++++
+ drivers/mtd/maps/physmap_of.c                  | 40 +-----------------------
+ drivers/mtd/mtdpart.c                          | 43 ++++++++++++++++++++++++++
+ 3 files changed, 60 insertions(+), 39 deletions(-)
+
+--- a/Documentation/devicetree/bindings/mtd/nand.txt
++++ b/Documentation/devicetree/bindings/mtd/nand.txt
+@@ -12,6 +12,22 @@
+ - nand-ecc-step-size: integer representing the number of data bytes
+ 		      that are covered by a single ECC step.
+ 
++- linux,part-probe: list of name as strings of the partition parser
++		    which should be used to parse the partition table.
++		    They will be tried in the specified ordering and
++		    the next one will be used if the previous one
++		    failed.
++
++		    Example: linux,part-probe = "cmdlinepart", "ofpart";
++
++		    This is also the default value, which will be used
++		    if this attribute is not specified. It could be
++		    that the flash driver in use overwrote the default
++		    value and uses some other default.
++
++		    Possible values are: bcm47xxpart, afs, ar7part,
++		    ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart
++
+ The ECC strength and ECC step size properties define the correction capability
+ of a controller. Together, they say a controller can correct "{strength} bit
+ errors per {size} bytes".
+--- a/drivers/mtd/maps/physmap_of.c
++++ b/drivers/mtd/maps/physmap_of.c
+@@ -112,45 +112,9 @@ static struct mtd_info *obsolete_probe(s
+ static const char * const part_probe_types_def[] = {
+ 	"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
+ 
+-static const char * const *of_get_probes(struct device_node *dp)
+-{
+-	const char *cp;
+-	int cplen;
+-	unsigned int l;
+-	unsigned int count;
+-	const char **res;
+-
+-	cp = of_get_property(dp, "linux,part-probe", &cplen);
+-	if (cp == NULL)
+-		return part_probe_types_def;
+-
+-	count = 0;
+-	for (l = 0; l != cplen; l++)
+-		if (cp[l] == 0)
+-			count++;
+-
+-	res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
+-	count = 0;
+-	while (cplen > 0) {
+-		res[count] = cp;
+-		l = strlen(cp) + 1;
+-		cp += l;
+-		cplen -= l;
+-		count++;
+-	}
+-	return res;
+-}
+-
+-static void of_free_probes(const char * const *probes)
+-{
+-	if (probes != part_probe_types_def)
+-		kfree(probes);
+-}
+-
+ static struct of_device_id of_flash_match[];
+ static int of_flash_probe(struct platform_device *dev)
+ {
+-	const char * const *part_probe_types;
+ 	const struct of_device_id *match;
+ 	struct device_node *dp = dev->dev.of_node;
+ 	struct resource res;
+@@ -310,10 +274,8 @@ static int of_flash_probe(struct platfor
+ 		goto err_out;
+ 
+ 	ppdata.of_node = dp;
+-	part_probe_types = of_get_probes(dp);
+-	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
++	mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata,
+ 			NULL, 0);
+-	of_free_probes(part_probe_types);
+ 
+ 	kfree(mtd_list);
+ 
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -29,6 +29,7 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/of.h>
+ #include <linux/err.h>
+ #include <linux/kconfig.h>
+ 
+@@ -719,6 +720,40 @@ void deregister_mtd_parser(struct mtd_pa
+ EXPORT_SYMBOL_GPL(deregister_mtd_parser);
+ 
+ /*
++ * Parses the linux,part-probe device tree property.
++ * When a non null value is returned it has to be freed with kfree() by
++ * the caller.
++ */
++static const char * const *of_get_probes(struct device_node *dp)
++{
++	const char *cp;
++	int cplen;
++	unsigned int l;
++	unsigned int count;
++	const char **res;
++
++	cp = of_get_property(dp, "linux,part-probe", &cplen);
++	if (cp == NULL)
++		return NULL;
++
++	count = 0;
++	for (l = 0; l != cplen; l++)
++		if (cp[l] == 0)
++			count++;
++
++	res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
++	count = 0;
++	while (cplen > 0) {
++		res[count] = cp;
++		l = strlen(cp) + 1;
++		cp += l;
++		cplen -= l;
++		count++;
++	}
++	return res;
++}
++
++/*
+  * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
+  * are changing this array!
+  */
+@@ -754,6 +789,13 @@ int parse_mtd_partitions(struct mtd_info
+ {
+ 	struct mtd_part_parser *parser;
+ 	int ret = 0;
++	const char *const *types_of = NULL;
++
++	if (data && data->of_node) {
++		types_of = of_get_probes(data->of_node);
++		if (types_of != NULL)
++			types = types_of;
++	}
+ 
+ 	if (!types)
+ 		types = default_mtd_part_types;
+@@ -772,6 +814,7 @@ int parse_mtd_partitions(struct mtd_info
+ 			break;
+ 		}
+ 	}
++	kfree(types_of);
+ 	return ret;
+ }
+ 
diff --git a/target/linux/generic/patches-4.1/141-Revert-mtd-spi-nor-disable-protection-for-Winbond-fl.patch b/target/linux/generic/patches-4.1/141-Revert-mtd-spi-nor-disable-protection-for-Winbond-fl.patch
new file mode 100644
index 0000000000..3d4b64ea6f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/141-Revert-mtd-spi-nor-disable-protection-for-Winbond-fl.patch
@@ -0,0 +1,35 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 26 Nov 2015 17:03:46 +0100
+Subject: [PATCH] Revert "mtd: spi-nor: disable protection for Winbond flash at
+ startup"
+
+This reverts commit c6fc2171b249e73745c497b578b417a2946f1b2f.
+
+This commit is breaking read access on at least s25fl064k, but also
+possibly other Spansion flash chips.
+
+Any mtd read seems to succeed, but simply returns a zero-filled buffer.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1194,14 +1194,13 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	mutex_init(&nor->lock);
+ 
+ 	/*
+-	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
+-	 * with the software protection bits set
++	 * Atmel, SST and Intel/Numonyx serial nor tend to power
++	 * up with the software protection bits set
+ 	 */
+ 
+ 	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ 	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
+-	    JEDEC_MFR(info) == SNOR_MFR_SST ||
+-	    JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
++	    JEDEC_MFR(info) == SNOR_MFR_SST) {
+ 		write_enable(nor);
+ 		write_sr(nor, 0);
+ 	}
diff --git a/target/linux/generic/patches-4.1/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch b/target/linux/generic/patches-4.1/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
new file mode 100644
index 0000000000..b0a064fb4e
--- /dev/null
+++ b/target/linux/generic/patches-4.1/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
@@ -0,0 +1,38 @@
+From 72fc448c4c970bdbba604ab340f16080b4f3bb17 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Thu, 26 Nov 2015 08:52:09 +0100
+Subject: [PATCH] mtd: spi-nor: include mtd.h header for struct mtd_info
+ definition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So far struct spi_nor was using just a pointer to struct mtd_info so it
+wasn't needed to have it fully defined there. After recent change we
+embed whole struct so we need to include a proper header.
+
+Fixes: 1976367173a4 ("mtd: spi-nor: embed struct mtd_info within struct spi_nor")
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ include/linux/mtd/spi-nor.h | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -12,6 +12,7 @@
+ 
+ #include <linux/bitops.h>
+ #include <linux/mtd/cfi.h>
++#include <linux/mtd/mtd.h>
+ 
+ /*
+  * Manufacturer IDs
+@@ -117,8 +118,6 @@ enum spi_nor_option_flags {
+ 	SNOR_F_USE_FSR		= BIT(0),
+ };
+ 
+-struct mtd_info;
+-
+ /**
+  * struct spi_nor - Structure for defining a the SPI NOR layer
+  * @mtd:		point to a mtd_info structure
diff --git a/target/linux/generic/patches-4.1/143-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch b/target/linux/generic/patches-4.1/143-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
new file mode 100644
index 0000000000..761cff316d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/143-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
@@ -0,0 +1,33 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 5 Dec 2015 02:03:32 +0100
+Subject: [PATCH] mtd: bcm47xxpart: limit scanned flash area on BCM47XX (MIPS)
+ only
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We allowed using bcm47xxpart on BCM5301X arch with commit:
+9e3afa5f5c7 ("mtd: bcm47xxpart: allow enabling on ARCH_BCM_5301X")
+
+BCM5301X devices may contain some partitions in higher memory, e.g.
+Netgear R8000 has board_data at 0x2600000. To detect them we should
+use size limit on MIPS only.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -118,8 +118,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 	/* Parse block by block looking for magics */
+ 	for (offset = 0; offset <= master->size - blocksize;
+ 	     offset += blocksize) {
+-		/* Nothing more in higher memory */
+-		if (offset >= 0x2000000)
++		/* Nothing more in higher memory on BCM47XX (MIPS) */
++		if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
+ 			break;
+ 
+ 		if (curr_part >= BCM47XXPART_MAX_PARTS) {
diff --git a/target/linux/generic/patches-4.1/144-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch b/target/linux/generic/patches-4.1/144-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
new file mode 100644
index 0000000000..9073f795e2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/144-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
@@ -0,0 +1,92 @@
+From dfe4b4c732365fc1d83c2d2fd9cc18054ae850b7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 6 Dec 2015 11:24:05 +0100
+Subject: [PATCH] mtd: bcm47xxpart: don't fail because of bit-flips
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Bit-flip errors may occur on NAND flashes and are harmless. Handle them
+gracefully as read content is still reliable and can be parsed.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 38 ++++++++++++++++++++++----------------
+ 1 file changed, 22 insertions(+), 16 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_
+ {
+ 	uint32_t buf;
+ 	size_t bytes_read;
++	int err;
+ 
+-	if (mtd_read(master, offset, sizeof(buf), &bytes_read,
+-		     (uint8_t *)&buf) < 0) {
+-		pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			offset);
++	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
++			(uint8_t *)&buf);
++	if (err && !mtd_is_bitflip(err)) {
++		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			offset, err);
+ 		goto out_default;
+ 	}
+ 
+@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_
+ 	int trx_part = -1;
+ 	int last_trx_part = -1;
+ 	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
++	int err;
+ 
+ 	/*
+ 	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
+@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Read beginning of the block */
+-		if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+-			     &bytes_read, (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			       offset);
++		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
++			       &bytes_read, (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
+@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Read middle of the block */
+-		if (mtd_read(master, offset + 0x8000, 0x4,
+-			     &bytes_read, (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			       offset);
++		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
++			       (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
+@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		offset = master->size - possible_nvram_sizes[i];
+-		if (mtd_read(master, offset, 0x4, &bytes_read,
+-			     (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while reading at offset 0x%X!\n",
+-			       offset);
++		err = mtd_read(master, offset, 0x4, &bytes_read,
++			       (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
diff --git a/target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch b/target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch
new file mode 100644
index 0000000000..a17e39800c
--- /dev/null
+++ b/target/linux/generic/patches-4.1/180-usb-xhci-make-USB_XHCI_PLATFORM-selectable.patch
@@ -0,0 +1,41 @@
+From 9612e686b235dc9e33c8dfb5e6d2ff2b2140fb9d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 16 Jun 2015 21:01:30 +0200
+Subject: [PATCH V2] usb: xhci: make USB_XHCI_PLATFORM selectable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Right now xhci-plat-hcd can be built when using one of platform specific
+drivers only (mvebu/rcar). There shouldn't be such limitation as some
+platforms may not require any quirks and may want to just use a generic
+driver ("generic-xhci" / "xhci-hcd").
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+Greg/Mathias: I'm not sure if it's more like USB subsystem stuff or xHCI
+Could you decide which one of you could pick that, please?
+
+V2: Drop useless "default n", thanks Sergei :)
+---
+ drivers/usb/host/Kconfig | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -32,7 +32,14 @@ config USB_XHCI_PCI
+        default y
+ 
+ config USB_XHCI_PLATFORM
+-	tristate
++	tristate "Generic xHCI driver for a platform device"
++	---help---
++	  Adds an xHCI host driver for a generic platform device, which
++	  provides a memory space and an irq.
++	  It is also a prerequisite for platform specific drivers that
++	  implement some extra quirks.
++
++	  If unsure, say N.
+ 
+ config USB_XHCI_MVEBU
+ 	tristate "xHCI support for Marvell Armada 375/38x"
diff --git a/target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch b/target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch
new file mode 100644
index 0000000000..02644d0583
--- /dev/null
+++ b/target/linux/generic/patches-4.1/190-cdc_ncm_add_support_for_moving_ndp_to_end_of_ncm_frame.patch
@@ -0,0 +1,232 @@
+From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001
+From: Enrico Mioso <mrkiko.rs@gmail.com>
+Date: Wed, 8 Jul 2015 13:05:57 +0200
+Subject: [PATCH] cdc_ncm: Add support for moving NDP to end of NCM frame
+
+NCM specs are not actually mandating a specific position in the frame for
+the NDP (Network Datagram Pointer). However, some Huawei devices will
+ignore our aggregates if it is not placed after the datagrams it points
+to. Add support for doing just this, in a per-device configurable way.
+While at it, update NCM subdrivers, disabling this functionality in all of
+them, except in huawei_cdc_ncm where it is enabled instead.
+We aren't making any distinction between different Huawei NCM devices,
+based on what the vendor driver does. Standard NCM devices are left
+unaffected: if they are compliant, they should be always usable, still
+stay on the safe side.
+
+This change has been tested and working with a Huawei E3131 device (which
+works regardless of NDP position), a Huawei E3531 (also working both
+ways) and an E3372 (which mandates NDP to be after indexed datagrams).
+
+V1->V2:
+- corrected wrong NDP acronym definition
+- fixed possible NULL pointer dereference
+- patch cleanup
+V2->V3:
+- Properly account for the NDP size when writing new packets to SKB
+
+Signed-off-by: Enrico Mioso <mrkiko.rs@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/usb/cdc_mbim.c       |  2 +-
+ drivers/net/usb/cdc_ncm.c        | 61 ++++++++++++++++++++++++++++++++++++----
+ drivers/net/usb/huawei_cdc_ncm.c |  7 +++--
+ include/linux/usb/cdc_ncm.h      |  7 ++++-
+ 4 files changed, 67 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/usb/cdc_mbim.c
++++ b/drivers/net/usb/cdc_mbim.c
+@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *
+ 	if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
+ 		goto err;
+ 
+-	ret = cdc_ncm_bind_common(dev, intf, data_altsetting);
++	ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0);
+ 	if (ret)
+ 		goto err;
+ 
+--- a/drivers/net/usb/cdc_ncm.c
++++ b/drivers/net/usb/cdc_ncm.c
+@@ -685,6 +685,8 @@ static void cdc_ncm_free(struct cdc_ncm_
+ 		ctx->tx_curr_skb = NULL;
+ 	}
+ 
++	kfree(ctx->delayed_ndp16);
++
+ 	kfree(ctx);
+ }
+ 
+@@ -715,7 +717,7 @@ static const struct net_device_ops cdc_n
+ 	.ndo_validate_addr   = eth_validate_addr,
+ };
+ 
+-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting)
++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
+ {
+ 	const struct usb_cdc_union_desc *union_desc = NULL;
+ 	struct cdc_ncm_ctx *ctx;
+@@ -894,6 +896,17 @@ advance:
+ 	/* finish setting up the device specific data */
+ 	cdc_ncm_setup(dev);
+ 
++	/* Device-specific flags */
++	ctx->drvflags = drvflags;
++
++	/* Allocate the delayed NDP if needed. */
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
++		ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
++		if (!ctx->delayed_ndp16)
++			goto error2;
++		dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
++	}
++
+ 	/* override ethtool_ops */
+ 	dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
+ 
+@@ -996,8 +1009,11 @@ static int cdc_ncm_bind(struct usbnet *d
+ 	if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
+ 		return -ENODEV;
+ 
+-	/* The NCM data altsetting is fixed */
+-	ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM);
++	/* The NCM data altsetting is fixed, so we hard-coded it.
++	 * Additionally, generic NCM devices are assumed to accept arbitrarily
++	 * placed NDP.
++	 */
++	ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
+ 
+ 	/*
+ 	 * We should get an event when network connection is "connected" or
+@@ -1028,6 +1044,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
+ 	struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
+ 	size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
+ 
++	/* If NDP should be moved to the end of the NCM package, we can't follow the
++	* NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
++	* the wNdpIndex field in the header is actually not consistent with reality. It will be later.
++	*/
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
++		if (ctx->delayed_ndp16->dwSignature == sign)
++			return ctx->delayed_ndp16;
++
+ 	/* follow the chain of NDPs, looking for a match */
+ 	while (ndpoffset) {
+ 		ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
+@@ -1037,7 +1061,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
+ 	}
+ 
+ 	/* align new NDP */
+-	cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
++	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
++		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
+ 
+ 	/* verify that there is room for the NDP and the datagram (reserve) */
+ 	if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size)
+@@ -1050,7 +1075,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
+ 		nth16->wNdpIndex = cpu_to_le16(skb->len);
+ 
+ 	/* push a new empty NDP */
+-	ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
++	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
++		ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
++	else
++		ndp16 = ctx->delayed_ndp16;
++
+ 	ndp16->dwSignature = sign;
+ 	ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
+ 	return ndp16;
+@@ -1065,6 +1094,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 	struct sk_buff *skb_out;
+ 	u16 n = 0, index, ndplen;
+ 	u8 ready2send = 0;
++	u32 delayed_ndp_size;
++
++	/* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
++	 * accordingly. Otherwise, we should check here.
++	 */
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
++		delayed_ndp_size = ctx->max_ndp_size;
++	else
++		delayed_ndp_size = 0;
+ 
+ 	/* if there is a remaining skb, it gets priority */
+ 	if (skb != NULL) {
+@@ -1119,7 +1157,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 		cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max);
+ 
+ 		/* check if we had enough room left for both NDP and frame */
+-		if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) {
++		if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) {
+ 			if (n == 0) {
+ 				/* won't fit, MTU problem? */
+ 				dev_kfree_skb_any(skb);
+@@ -1192,6 +1230,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 		/* variables will be reset at next call */
+ 	}
+ 
++	/* If requested, put NDP at end of frame. */
++	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
++		nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
++		cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max);
++		nth16->wNdpIndex = cpu_to_le16(skb_out->len);
++		memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size);
++
++		/* Zero out delayed NDP - signature checking will naturally fail. */
++		ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
++	}
++
+ 	/* If collected data size is less or equal ctx->min_tx_pkt
+ 	 * bytes, we send buffers as it is. If we get more data, it
+ 	 * would be more efficient for USB HS mobile device with DMA
+--- a/drivers/net/usb/huawei_cdc_ncm.c
++++ b/drivers/net/usb/huawei_cdc_ncm.c
+@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct us
+ 	struct usb_driver *subdriver = ERR_PTR(-ENODEV);
+ 	int ret = -ENODEV;
+ 	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
++	int drvflags = 0;
+ 
+ 	/* altsetting should always be 1 for NCM devices - so we hard-coded
+-	 * it here
++	 * it here. Some huawei devices will need the NDP part of the NCM package to
++	 * be at the end of the frame.
+ 	 */
+-	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1);
++	drvflags |= CDC_NCM_FLAG_NDP_TO_END;
++	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
+ 	if (ret)
+ 		goto err;
+ 
+--- a/include/linux/usb/cdc_ncm.h
++++ b/include/linux/usb/cdc_ncm.h
+@@ -80,6 +80,9 @@
+ #define CDC_NCM_TIMER_INTERVAL_MIN		5UL
+ #define CDC_NCM_TIMER_INTERVAL_MAX		(U32_MAX / NSEC_PER_USEC)
+ 
++/* Driver flags */
++#define CDC_NCM_FLAG_NDP_TO_END	0x02		/* NDP is placed at end of frame */
++
+ #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
+ 				       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
+ #define cdc_ncm_data_intf_is_mbim(x)  ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
+@@ -103,9 +106,11 @@ struct cdc_ncm_ctx {
+ 
+ 	spinlock_t mtx;
+ 	atomic_t stop;
++	int drvflags;
+ 
+ 	u32 timer_interval;
+ 	u32 max_ndp_size;
++	struct usb_cdc_ncm_ndp16 *delayed_ndp16;
+ 
+ 	u32 tx_timer_pending;
+ 	u32 tx_curr_frame_num;
+@@ -134,7 +139,7 @@ struct cdc_ncm_ctx {
+ 
+ u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
+ int cdc_ncm_change_mtu(struct net_device *net, int new_mtu);
+-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
++int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
+ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
+ struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
+ int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in);
diff --git a/target/linux/generic/patches-4.1/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch b/target/linux/generic/patches-4.1/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
new file mode 100644
index 0000000000..c7bf45a2a8
--- /dev/null
+++ b/target/linux/generic/patches-4.1/193-USB-qmi_wwan-Add-quirk-for-Quectel-EC20-Mini-PCIe-mo.patch
@@ -0,0 +1,96 @@
+From fe29727caa7fe434fcb3166df2a62672bc516b54 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Wed, 4 Nov 2015 16:23:37 +0100
+Subject: [PATCH 2/2] USB: qmi_wwan: Add quirk for Quectel EC20 Mini PCIe
+ module
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This device has same vendor and product IDs as G2K devices, but it has
+different number of interfaces(4 vs 5) and also different interface
+layout where EC20 has QMI on interface 4 instead of 0.
+
+lsusb output:
+
+	Bus 002 Device 003: ID 05c6:9215 Qualcomm, Inc. Acer Gobi 2000
+	Device Descriptor:
+	  bLength                18
+	  bDescriptorType         1
+	  bcdUSB               2.00
+	  bDeviceClass            0 (Defined at Interface level)
+	  bDeviceSubClass         0
+	  bDeviceProtocol         0
+	  bMaxPacketSize0        64
+	  idVendor           0x05c6 Qualcomm, Inc.
+	  idProduct          0x9215 Acer Gobi 2000 Wireless Modem
+	  bcdDevice            2.32
+	  iManufacturer           1 Quectel
+	  iProduct                2 Quectel LTE Module
+	  iSerial                 0
+	  bNumConfigurations      1
+	  Configuration Descriptor:
+	    bLength                 9
+	    bDescriptorType         2
+	    wTotalLength          209
+	    bNumInterfaces          5
+	    bConfigurationValue     1
+	    iConfiguration          0
+	    bmAttributes         0xa0
+	      (Bus Powered)
+	      Remote Wakeup
+	    MaxPower              500mA
+
+Signed-off-by: Petr Å tetiar <ynezz@true.cz>
+---
+ drivers/net/usb/qmi_wwan.c |   21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+--- a/drivers/net/usb/qmi_wwan.c
++++ b/drivers/net/usb/qmi_wwan.c
+@@ -824,6 +824,7 @@ static const struct usb_device_id produc
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9245)},	/* Samsung Gobi 2000 Modem device (VL176) */
+ 	{QMI_GOBI_DEVICE(0x03f0, 0x251d)},	/* HP Gobi 2000 Modem device (VP412) */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9215)},	/* Acer Gobi 2000 Modem device (VP413) */
++	{QMI_FIXED_INTF(0x05c6, 0x9215, 4)},	/* Quectel EC20 Mini PCIe */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9265)},	/* Asus Gobi 2000 Modem device (VR305) */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9235)},	/* Top Global Gobi 2000 Modem device (VR306) */
+ 	{QMI_GOBI_DEVICE(0x05c6, 0x9275)},	/* iRex Technologies Gobi 2000 Modem device (VR307) */
+@@ -855,10 +856,24 @@ static const struct usb_device_id produc
+ };
+ MODULE_DEVICE_TABLE(usb, products);
+ 
++static bool quectel_ec20_detected(struct usb_interface *intf)
++{
++	struct usb_device *dev = interface_to_usbdev(intf);
++
++	if (dev->actconfig &&
++	    le16_to_cpu(dev->descriptor.idVendor) == 0x05c6 &&
++	    le16_to_cpu(dev->descriptor.idProduct) == 0x9215 &&
++	    dev->actconfig->desc.bNumInterfaces == 5)
++		return true;
++
++	return false;
++}
++
+ static int qmi_wwan_probe(struct usb_interface *intf,
+ 			  const struct usb_device_id *prod)
+ {
+ 	struct usb_device_id *id = (struct usb_device_id *)prod;
++	struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
+ 
+ 	/* Workaround to enable dynamic IDs.  This disables usbnet
+ 	 * blacklisting functionality.  Which, if required, can be
+@@ -870,6 +885,12 @@ static int qmi_wwan_probe(struct usb_int
+ 		id->driver_info = (unsigned long)&qmi_wwan_info;
+ 	}
+ 
++	/* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
++	if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
++		dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
++		return -ENODEV;
++	}
++
+ 	return usbnet_probe(intf, id);
+ }
+ 
diff --git a/target/linux/generic/patches-4.1/200-fix_localversion.patch b/target/linux/generic/patches-4.1/200-fix_localversion.patch
new file mode 100644
index 0000000000..70228bb5f4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/200-fix_localversion.patch
@@ -0,0 +1,11 @@
+--- a/scripts/setlocalversion
++++ b/scripts/setlocalversion
+@@ -165,7 +165,7 @@ else
+ 	# annotated or signed tagged state (as git describe only
+ 	# looks at signed or annotated tags - git tag -a/-s) and
+ 	# LOCALVERSION= is not specified
+-	if test "${LOCALVERSION+set}" != "set"; then
++	if test "${CONFIG_LOCALVERSION+set}" != "set"; then
+ 		scm=$(scm_version --short)
+ 		res="$res${scm:++}"
+ 	fi
diff --git a/target/linux/generic/patches-4.1/201-extra_optimization.patch b/target/linux/generic/patches-4.1/201-extra_optimization.patch
new file mode 100644
index 0000000000..34ded8c7eb
--- /dev/null
+++ b/target/linux/generic/patches-4.1/201-extra_optimization.patch
@@ -0,0 +1,14 @@
+--- a/Makefile
++++ b/Makefile
+@@ -612,9 +612,9 @@ include arch/$(SRCARCH)/Makefile
+ KBUILD_CFLAGS	+= $(call cc-option,-fno-delete-null-pointer-checks,)
+ 
+ ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+-KBUILD_CFLAGS	+= -Os $(call cc-disable-warning,maybe-uninitialized,)
++KBUILD_CFLAGS	+= -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,)
+ else
+-KBUILD_CFLAGS	+= -O2
++KBUILD_CFLAGS	+= -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
+ endif
+ 
+ # Tell gcc to never replace conditional load with a non-conditional one
diff --git a/target/linux/generic/patches-4.1/202-reduce_module_size.patch b/target/linux/generic/patches-4.1/202-reduce_module_size.patch
new file mode 100644
index 0000000000..60ea5c2085
--- /dev/null
+++ b/target/linux/generic/patches-4.1/202-reduce_module_size.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -408,7 +408,7 @@ KBUILD_CFLAGS_KERNEL :=
+ KBUILD_AFLAGS   := -D__ASSEMBLY__
+ KBUILD_AFLAGS_MODULE  := -DMODULE
+ KBUILD_CFLAGS_MODULE  := -DMODULE
+-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
++KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
+ 
+ # Read KERNELRELEASE from include/config/kernel.release (if it exists)
+ KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
diff --git a/target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch b/target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch
new file mode 100644
index 0000000000..10cfc83d78
--- /dev/null
+++ b/target/linux/generic/patches-4.1/203-kallsyms_uncompressed.patch
@@ -0,0 +1,108 @@
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -58,6 +58,7 @@ static struct addr_range percpu_range =
+ static struct sym_entry *table;
+ static unsigned int table_size, table_cnt;
+ static int all_symbols = 0;
++static int uncompressed = 0;
+ static int absolute_percpu = 0;
+ static char symbol_prefix_char = '\0';
+ static unsigned long long kernel_start_addr = 0;
+@@ -403,6 +404,9 @@ static void write_src(void)
+ 
+ 	free(markers);
+ 
++	if (uncompressed)
++		return;
++
+ 	output_label("kallsyms_token_table");
+ 	off = 0;
+ 	for (i = 0; i < 256; i++) {
+@@ -461,6 +465,9 @@ static void *find_token(unsigned char *s
+ {
+ 	int i;
+ 
++	if (uncompressed)
++		return NULL;
++
+ 	for (i = 0; i < len - 1; i++) {
+ 		if (str[i] == token[0] && str[i+1] == token[1])
+ 			return &str[i];
+@@ -533,6 +540,9 @@ static void optimize_result(void)
+ {
+ 	int i, best;
+ 
++	if (uncompressed)
++		return;
++
+ 	/* using the '\0' symbol last allows compress_symbols to use standard
+ 	 * fast string functions */
+ 	for (i = 255; i >= 0; i--) {
+@@ -703,7 +713,9 @@ int main(int argc, char **argv)
+ 			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+ 				const char *p = &argv[i][14];
+ 				kernel_start_addr = strtoull(p, NULL, 16);
+-			} else
++			} else if (strcmp(argv[i], "--uncompressed") == 0)
++				uncompressed = 1;
++			else
+ 				usage();
+ 		}
+ 	} else if (argc != 1)
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1334,6 +1334,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
+ 	  the unaligned access emulation.
+ 	  see arch/parisc/kernel/unaligned.c for reference
+ 
++config KALLSYMS_UNCOMPRESSED
++	bool "Keep kallsyms uncompressed"
++	depends on KALLSYMS
++	help
++		Normally kallsyms contains compressed symbols (using a token table),
++		reducing the uncompressed kernel image size. Keeping the symbol table
++		uncompressed significantly improves the size of this part in compressed
++		kernel images.
++
++		Say N unless you need compressed kernel images to be small.
++
+ config HAVE_PCSPKR_PLATFORM
+ 	bool
+ 
+--- a/scripts/link-vmlinux.sh
++++ b/scripts/link-vmlinux.sh
+@@ -90,6 +90,10 @@ kallsyms()
+ 		kallsymopt="${kallsymopt} --absolute-percpu"
+ 	fi
+ 
++	if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
++		kallsymopt="${kallsymopt} --uncompressed"
++	fi
++
+ 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
+ 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
+ 
+--- a/kernel/kallsyms.c
++++ b/kernel/kallsyms.c
+@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb
+ 	 * For every byte on the compressed symbol data, copy the table
+ 	 * entry for that byte.
+ 	 */
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	memcpy(result, data + 1, len - 1);
++	result += len - 1;
++	len = 0;
++#endif
+ 	while (len) {
+ 		tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
+ 		data++;
+@@ -141,6 +146,9 @@ tail:
+  */
+ static char kallsyms_get_symbol_type(unsigned int off)
+ {
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	return kallsyms_names[off + 1];
++#endif
+ 	/*
+ 	 * Get just the first code, look it up in the token table,
+ 	 * and return the first char from this token.
diff --git a/target/linux/generic/patches-4.1/204-module_strip.patch b/target/linux/generic/patches-4.1/204-module_strip.patch
new file mode 100644
index 0000000000..4f5f6474ee
--- /dev/null
+++ b/target/linux/generic/patches-4.1/204-module_strip.patch
@@ -0,0 +1,194 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] build: add a hack for removing non-essential module info
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -84,9 +84,10 @@ void trim_init_extable(struct module *m)
+ 
+ /* Generic info of form tag = "info" */
+ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
+ 
+ /* For userspace: you can also call me... */
+-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
++#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias)
+ 
+ /* Soft module dependencies. See man modprobe.d for details.
+  * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
+@@ -127,12 +128,12 @@ void trim_init_extable(struct module *m)
+  * Author(s), use "Name <email>" or just "Name", for multiple
+  * authors use multiple MODULE_AUTHOR() statements/lines.
+  */
+-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
+ 
+ /* What your module does. */
+-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
+ 
+-#ifdef MODULE
++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
+ /* Creates an alias so file2alias.c can find device table. */
+ #define MODULE_DEVICE_TABLE(type, name)					\
+ extern const typeof(name) __mod_##type##__##name##_device_table		\
+@@ -159,7 +160,9 @@ extern const typeof(name) __mod_##type##
+  */
+ 
+ #if defined(MODULE) || !defined(CONFIG_SYSFS)
+-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
++#elif defined(CONFIG_MODULE_STRIPPED)
++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
+ #else
+ #define MODULE_VERSION(_version)					\
+ 	static struct module_version_attribute ___modver_attr = {	\
+@@ -181,7 +184,7 @@ extern const typeof(name) __mod_##type##
+ /* Optional firmware file (or files) needed by the module
+  * format is simply firmware file name.  Multiple firmware
+  * files require multiple MODULE_FIRMWARE() specifiers */
+-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
+ 
+ /* Given an address, look for it in the exception tables */
+ const struct exception_table_entry *search_exception_tables(unsigned long add);
+--- a/include/linux/moduleparam.h
++++ b/include/linux/moduleparam.h
+@@ -16,6 +16,16 @@
+ /* Chosen so that structs with an unsigned long line up. */
+ #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
+ 
++/* This struct is here for syntactic coherency, it is not used */
++#define __MODULE_INFO_DISABLED(name)					  \
++  struct __UNIQUE_ID(name) {}
++
++#ifdef CONFIG_MODULE_STRIPPED
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
++#else
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
++#endif
++
+ #ifdef MODULE
+ #define __MODULE_INFO(tag, name, info)					  \
+ static const char __UNIQUE_ID(name)[]					  \
+@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[]
+   = __stringify(tag) "=" info
+ #else  /* !MODULE */
+ /* This struct is here for syntactic coherency, it is not used */
+-#define __MODULE_INFO(tag, name, info)					  \
+-  struct __UNIQUE_ID(name) {}
++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
+ #endif
+ #define __MODULE_PARM_TYPE(name, _type)					  \
+   __MODULE_INFO(parmtype, name##type, #name ":" _type)
+@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[]
+ /* One for each parameter, describing how to use it.  Some files do
+    multiple of these per line, so can't just use MODULE_INFO. */
+ #define MODULE_PARM_DESC(_parm, desc) \
+-	__MODULE_INFO(parm, _parm, #_parm ":" desc)
++	__MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
+ 
+ struct kernel_param;
+ 
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1998,6 +1998,13 @@ config MODULE_COMPRESS_XZ
+ 
+ endchoice
+ 
++config MODULE_STRIPPED
++	bool "Reduce module size"
++	depends on MODULES
++	help
++	  Remove module parameter descriptions, author info, version, aliases,
++	  device tables, etc.
++
+ endif # MODULES
+ 
+ config INIT_ALL_POSSIBLE
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2709,6 +2709,7 @@ static struct module *setup_load_info(st
+ 
+ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	const char *modmagic = get_modinfo(info, "vermagic");
+ 	int err;
+ 
+@@ -2734,6 +2735,7 @@ static int check_modinfo(struct module *
+ 		pr_warn("%s: module is from the staging directory, the quality "
+ 			"is unknown, you have been warned.\n", mod->name);
+ 	}
++#endif
+ 
+ 	/* Set up license info based on the info section */
+ 	set_license(mod, get_modinfo(info, "license"));
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -1959,7 +1959,9 @@ static void read_symbols(char *modname)
+ 		symname = remove_dot(info.strtab + sym->st_name);
+ 
+ 		handle_modversions(mod, &info, sym, symname);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		handle_moddevtable(mod, &info, sym, symname);
++#endif
+ 	}
+ 	if (!is_vmlinux(modname) ||
+ 	     (is_vmlinux(modname) && vmlinux_section_warnings))
+@@ -2103,7 +2105,9 @@ static void add_header(struct buffer *b,
+ 	buf_printf(b, "#include <linux/vermagic.h>\n");
+ 	buf_printf(b, "#include <linux/compiler.h>\n");
+ 	buf_printf(b, "\n");
++#ifndef CONFIG_MODULE_STRIPPED
+ 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
++#endif
+ 	buf_printf(b, "\n");
+ 	buf_printf(b, "__visible struct module __this_module\n");
+ 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
+@@ -2120,16 +2124,20 @@ static void add_header(struct buffer *b,
+ 
+ static void add_intree_flag(struct buffer *b, int is_intree)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (is_intree)
+ 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
++#endif
+ }
+ 
+ static void add_staging_flag(struct buffer *b, const char *name)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	static const char *staging_dir = "drivers/staging";
+ 
+ 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
+ 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
++#endif
+ }
+ 
+ /**
+@@ -2222,11 +2230,13 @@ static void add_depends(struct buffer *b
+ 
+ static void add_srcversion(struct buffer *b, struct module *mod)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (mod->srcversion[0]) {
+ 		buf_printf(b, "\n");
+ 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ 			   mod->srcversion);
+ 	}
++#endif
+ }
+ 
+ static void write_if_changed(struct buffer *b, const char *fname)
+@@ -2457,7 +2467,9 @@ int main(int argc, char **argv)
+ 		add_staging_flag(&buf, mod->name);
+ 		err |= add_versions(&buf, mod);
+ 		add_depends(&buf, mod, modules);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		add_moddevtable(&buf, mod);
++#endif
+ 		add_srcversion(&buf, mod);
+ 
+ 		sprintf(fname, "%s.mod.c", mod->name);
diff --git a/target/linux/generic/patches-4.1/205-backtrace_module_info.patch b/target/linux/generic/patches-4.1/205-backtrace_module_info.patch
new file mode 100644
index 0000000000..48b2204ab4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/205-backtrace_module_info.patch
@@ -0,0 +1,36 @@
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -617,8 +617,10 @@ char *symbol_string(char *buf, char *end
+ 		    struct printf_spec spec, const char *fmt)
+ {
+ 	unsigned long value;
+-#ifdef CONFIG_KALLSYMS
+ 	char sym[KSYM_SYMBOL_LEN];
++#ifndef CONFIG_KALLSYMS
++	struct module *mod;
++	int len;
+ #endif
+ 
+ 	if (fmt[1] == 'R')
+@@ -632,15 +634,15 @@ char *symbol_string(char *buf, char *end
+ 		sprint_symbol(sym, value);
+ 	else
+ 		sprint_symbol_no_offset(sym, value);
+-
+-	return string(buf, end, sym, spec);
+ #else
+-	spec.field_width = 2 * sizeof(void *);
+-	spec.flags |= SPECIAL | SMALL | ZEROPAD;
+-	spec.base = 16;
++	len = snprintf(sym, sizeof(sym), "0x%lx", value);
+ 
+-	return number(buf, end, value, spec);
++	mod = __module_address(value);
++	if (mod)
++		snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
++			 mod->name, mod->module_core, mod->core_size);
+ #endif
++	return string(buf, end, sym, spec);
+ }
+ 
+ static noinline_for_stack
diff --git a/target/linux/generic/patches-4.1/210-darwin_scripts_include.patch b/target/linux/generic/patches-4.1/210-darwin_scripts_include.patch
new file mode 100644
index 0000000000..ef548c730d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/210-darwin_scripts_include.patch
@@ -0,0 +1,3088 @@
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -22,6 +22,35 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
++#ifdef __APPLE__
++/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */
++void *memmem (const void *haystack, size_t haystack_len,
++                          const void *needle,  size_t needle_len)
++{
++  const char *begin;
++  const char *const last_possible
++    = (const char *) haystack + haystack_len - needle_len;
++
++  if (needle_len == 0)
++    /* The first occurrence of the empty string is deemed to occur at
++       the beginning of the string.  */
++    return (void *) haystack;
++
++  /* Sanity check, otherwise the loop might search through the whole
++     memory.  */
++  if (__builtin_expect (haystack_len < needle_len, 0))
++    return NULL;
++
++  for (begin = (const char *) haystack; begin <= last_possible; ++begin)
++    if (begin[0] == ((const char *) needle)[0] &&
++        !memcmp ((const void *) &begin[1],
++                 (const void *) ((const char *) needle + 1),
++                 needle_len - 1))
++      return (void *) begin;
++
++  return NULL;
++}
++#endif
+ 
+ #ifndef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+--- a/scripts/kconfig/Makefile
++++ b/scripts/kconfig/Makefile
+@@ -149,6 +149,9 @@ check-lxdialog  := $(srctree)/$(src)/lxd
+ # we really need to do so. (Do not call gcc as part of make mrproper)
+ HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+                     -DLOCALE
++ifeq ($(shell uname -s),Darwin)
++HOST_LOADLIBES  += -lncurses
++endif
+ 
+ # ===========================================================================
+ # Shared Makefile for the various kconfig executables:
+--- a/scripts/mod/mk_elfconfig.c
++++ b/scripts/mod/mk_elfconfig.c
+@@ -1,7 +1,11 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#ifndef __APPLE__
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ int
+ main(int argc, char **argv)
+--- a/scripts/mod/modpost.h
++++ b/scripts/mod/modpost.h
+@@ -7,7 +7,11 @@
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <unistd.h>
++#if !(defined(__APPLE__) || defined(__CYGWIN__))
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ #include "elfconfig.h"
+ 
+--- /dev/null
++++ b/scripts/mod/elf.h
+@@ -0,0 +1,3007 @@
++/* This file defines standard ELF types, structures, and macros.
++   Copyright (C) 1995-2012 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef _ELF_H
++#define	_ELF_H 1
++
++/* Standard ELF types.  */
++
++#include <stdint.h>
++
++/* Type for a 16-bit quantity.  */
++typedef uint16_t Elf32_Half;
++typedef uint16_t Elf64_Half;
++
++/* Types for signed and unsigned 32-bit quantities.  */
++typedef uint32_t Elf32_Word;
++typedef	int32_t  Elf32_Sword;
++typedef uint32_t Elf64_Word;
++typedef	int32_t  Elf64_Sword;
++
++/* Types for signed and unsigned 64-bit quantities.  */
++typedef uint64_t Elf32_Xword;
++typedef	int64_t  Elf32_Sxword;
++typedef uint64_t Elf64_Xword;
++typedef	int64_t  Elf64_Sxword;
++
++/* Type of addresses.  */
++typedef uint32_t Elf32_Addr;
++typedef uint64_t Elf64_Addr;
++
++/* Type of file offsets.  */
++typedef uint32_t Elf32_Off;
++typedef uint64_t Elf64_Off;
++
++/* Type for section indices, which are 16-bit quantities.  */
++typedef uint16_t Elf32_Section;
++typedef uint16_t Elf64_Section;
++
++/* Type for version symbol information.  */
++typedef Elf32_Half Elf32_Versym;
++typedef Elf64_Half Elf64_Versym;
++
++
++/* The ELF file header.  This appears at the start of every ELF file.  */
++
++#define EI_NIDENT (16)
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf32_Half	e_type;			/* Object file type */
++  Elf32_Half	e_machine;		/* Architecture */
++  Elf32_Word	e_version;		/* Object file version */
++  Elf32_Addr	e_entry;		/* Entry point virtual address */
++  Elf32_Off	e_phoff;		/* Program header table file offset */
++  Elf32_Off	e_shoff;		/* Section header table file offset */
++  Elf32_Word	e_flags;		/* Processor-specific flags */
++  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf32_Half	e_phentsize;		/* Program header table entry size */
++  Elf32_Half	e_phnum;		/* Program header table entry count */
++  Elf32_Half	e_shentsize;		/* Section header table entry size */
++  Elf32_Half	e_shnum;		/* Section header table entry count */
++  Elf32_Half	e_shstrndx;		/* Section header string table index */
++} Elf32_Ehdr;
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf64_Half	e_type;			/* Object file type */
++  Elf64_Half	e_machine;		/* Architecture */
++  Elf64_Word	e_version;		/* Object file version */
++  Elf64_Addr	e_entry;		/* Entry point virtual address */
++  Elf64_Off	e_phoff;		/* Program header table file offset */
++  Elf64_Off	e_shoff;		/* Section header table file offset */
++  Elf64_Word	e_flags;		/* Processor-specific flags */
++  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf64_Half	e_phentsize;		/* Program header table entry size */
++  Elf64_Half	e_phnum;		/* Program header table entry count */
++  Elf64_Half	e_shentsize;		/* Section header table entry size */
++  Elf64_Half	e_shnum;		/* Section header table entry count */
++  Elf64_Half	e_shstrndx;		/* Section header string table index */
++} Elf64_Ehdr;
++
++/* Fields in the e_ident array.  The EI_* macros are indices into the
++   array.  The macros under each EI_* macro are the values the byte
++   may have.  */
++
++#define EI_MAG0		0		/* File identification byte 0 index */
++#define ELFMAG0		0x7f		/* Magic number byte 0 */
++
++#define EI_MAG1		1		/* File identification byte 1 index */
++#define ELFMAG1		'E'		/* Magic number byte 1 */
++
++#define EI_MAG2		2		/* File identification byte 2 index */
++#define ELFMAG2		'L'		/* Magic number byte 2 */
++
++#define EI_MAG3		3		/* File identification byte 3 index */
++#define ELFMAG3		'F'		/* Magic number byte 3 */
++
++/* Conglomeration of the identification bytes, for easy testing as a word.  */
++#define	ELFMAG		"\177ELF"
++#define	SELFMAG		4
++
++#define EI_CLASS	4		/* File class byte index */
++#define ELFCLASSNONE	0		/* Invalid class */
++#define ELFCLASS32	1		/* 32-bit objects */
++#define ELFCLASS64	2		/* 64-bit objects */
++#define ELFCLASSNUM	3
++
++#define EI_DATA		5		/* Data encoding byte index */
++#define ELFDATANONE	0		/* Invalid data encoding */
++#define ELFDATA2LSB	1		/* 2's complement, little endian */
++#define ELFDATA2MSB	2		/* 2's complement, big endian */
++#define ELFDATANUM	3
++
++#define EI_VERSION	6		/* File version byte index */
++					/* Value must be EV_CURRENT */
++
++#define EI_OSABI	7		/* OS ABI identification */
++#define ELFOSABI_NONE		0	/* UNIX System V ABI */
++#define ELFOSABI_SYSV		0	/* Alias.  */
++#define ELFOSABI_HPUX		1	/* HP-UX */
++#define ELFOSABI_NETBSD		2	/* NetBSD.  */
++#define ELFOSABI_GNU		3	/* Object uses GNU ELF extensions.  */
++#define ELFOSABI_LINUX		ELFOSABI_GNU /* Compatibility alias.  */
++#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
++#define ELFOSABI_AIX		7	/* IBM AIX.  */
++#define ELFOSABI_IRIX		8	/* SGI Irix.  */
++#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
++#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
++#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
++#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
++#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
++#define ELFOSABI_ARM		97	/* ARM */
++#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
++
++#define EI_ABIVERSION	8		/* ABI version */
++
++#define EI_PAD		9		/* Byte index of padding bytes */
++
++/* Legal values for e_type (object file type).  */
++
++#define ET_NONE		0		/* No file type */
++#define ET_REL		1		/* Relocatable file */
++#define ET_EXEC		2		/* Executable file */
++#define ET_DYN		3		/* Shared object file */
++#define ET_CORE		4		/* Core file */
++#define	ET_NUM		5		/* Number of defined types */
++#define ET_LOOS		0xfe00		/* OS-specific range start */
++#define ET_HIOS		0xfeff		/* OS-specific range end */
++#define ET_LOPROC	0xff00		/* Processor-specific range start */
++#define ET_HIPROC	0xffff		/* Processor-specific range end */
++
++/* Legal values for e_machine (architecture).  */
++
++#define EM_NONE		 0		/* No machine */
++#define EM_M32		 1		/* AT&T WE 32100 */
++#define EM_SPARC	 2		/* SUN SPARC */
++#define EM_386		 3		/* Intel 80386 */
++#define EM_68K		 4		/* Motorola m68k family */
++#define EM_88K		 5		/* Motorola m88k family */
++#define EM_860		 7		/* Intel 80860 */
++#define EM_MIPS		 8		/* MIPS R3000 big-endian */
++#define EM_S370		 9		/* IBM System/370 */
++#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
++
++#define EM_PARISC	15		/* HPPA */
++#define EM_VPP500	17		/* Fujitsu VPP500 */
++#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
++#define EM_960		19		/* Intel 80960 */
++#define EM_PPC		20		/* PowerPC */
++#define EM_PPC64	21		/* PowerPC 64-bit */
++#define EM_S390		22		/* IBM S390 */
++
++#define EM_V800		36		/* NEC V800 series */
++#define EM_FR20		37		/* Fujitsu FR20 */
++#define EM_RH32		38		/* TRW RH-32 */
++#define EM_RCE		39		/* Motorola RCE */
++#define EM_ARM		40		/* ARM */
++#define EM_FAKE_ALPHA	41		/* Digital Alpha */
++#define EM_SH		42		/* Hitachi SH */
++#define EM_SPARCV9	43		/* SPARC v9 64-bit */
++#define EM_TRICORE	44		/* Siemens Tricore */
++#define EM_ARC		45		/* Argonaut RISC Core */
++#define EM_H8_300	46		/* Hitachi H8/300 */
++#define EM_H8_300H	47		/* Hitachi H8/300H */
++#define EM_H8S		48		/* Hitachi H8S */
++#define EM_H8_500	49		/* Hitachi H8/500 */
++#define EM_IA_64	50		/* Intel Merced */
++#define EM_MIPS_X	51		/* Stanford MIPS-X */
++#define EM_COLDFIRE	52		/* Motorola Coldfire */
++#define EM_68HC12	53		/* Motorola M68HC12 */
++#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
++#define EM_PCP		55		/* Siemens PCP */
++#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
++#define EM_NDR1		57		/* Denso NDR1 microprocessor */
++#define EM_STARCORE	58		/* Motorola Start*Core processor */
++#define EM_ME16		59		/* Toyota ME16 processor */
++#define EM_ST100	60		/* STMicroelectronic ST100 processor */
++#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
++#define EM_X86_64	62		/* AMD x86-64 architecture */
++#define EM_PDSP		63		/* Sony DSP Processor */
++
++#define EM_FX66		66		/* Siemens FX66 microcontroller */
++#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
++#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
++#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
++#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
++#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
++#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
++#define EM_SVX		73		/* Silicon Graphics SVx */
++#define EM_ST19		74		/* STMicroelectronics ST19 8 bit mc */
++#define EM_VAX		75		/* Digital VAX */
++#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
++#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
++#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
++#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
++#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
++#define EM_HUANY	81		/* Harvard University machine-independent object files */
++#define EM_PRISM	82		/* SiTera Prism */
++#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
++#define EM_FR30		84		/* Fujitsu FR30 */
++#define EM_D10V		85		/* Mitsubishi D10V */
++#define EM_D30V		86		/* Mitsubishi D30V */
++#define EM_V850		87		/* NEC v850 */
++#define EM_M32R		88		/* Mitsubishi M32R */
++#define EM_MN10300	89		/* Matsushita MN10300 */
++#define EM_MN10200	90		/* Matsushita MN10200 */
++#define EM_PJ		91		/* picoJava */
++#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
++#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
++#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
++#define EM_TILEPRO	188		/* Tilera TILEPro */
++#define EM_TILEGX	191		/* Tilera TILE-Gx */
++#define EM_NUM		192
++
++/* If it is necessary to assign new unofficial EM_* values, please
++   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
++   chances of collision with official or non-GNU unofficial values.  */
++
++#define EM_ALPHA	0x9026
++
++/* Legal values for e_version (version).  */
++
++#define EV_NONE		0		/* Invalid ELF version */
++#define EV_CURRENT	1		/* Current version */
++#define EV_NUM		2
++
++/* Section header.  */
++
++typedef struct
++{
++  Elf32_Word	sh_name;		/* Section name (string tbl index) */
++  Elf32_Word	sh_type;		/* Section type */
++  Elf32_Word	sh_flags;		/* Section flags */
++  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf32_Off	sh_offset;		/* Section file offset */
++  Elf32_Word	sh_size;		/* Section size in bytes */
++  Elf32_Word	sh_link;		/* Link to another section */
++  Elf32_Word	sh_info;		/* Additional section information */
++  Elf32_Word	sh_addralign;		/* Section alignment */
++  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
++} Elf32_Shdr;
++
++typedef struct
++{
++  Elf64_Word	sh_name;		/* Section name (string tbl index) */
++  Elf64_Word	sh_type;		/* Section type */
++  Elf64_Xword	sh_flags;		/* Section flags */
++  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf64_Off	sh_offset;		/* Section file offset */
++  Elf64_Xword	sh_size;		/* Section size in bytes */
++  Elf64_Word	sh_link;		/* Link to another section */
++  Elf64_Word	sh_info;		/* Additional section information */
++  Elf64_Xword	sh_addralign;		/* Section alignment */
++  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
++} Elf64_Shdr;
++
++/* Special section indices.  */
++
++#define SHN_UNDEF	0		/* Undefined section */
++#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
++#define SHN_LOPROC	0xff00		/* Start of processor-specific */
++#define SHN_BEFORE	0xff00		/* Order section before all others
++					   (Solaris).  */
++#define SHN_AFTER	0xff01		/* Order section after all others
++					   (Solaris).  */
++#define SHN_HIPROC	0xff1f		/* End of processor-specific */
++#define SHN_LOOS	0xff20		/* Start of OS-specific */
++#define SHN_HIOS	0xff3f		/* End of OS-specific */
++#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
++#define SHN_COMMON	0xfff2		/* Associated symbol is common */
++#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
++#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
++
++/* Legal values for sh_type (section type).  */
++
++#define SHT_NULL	  0		/* Section header table entry unused */
++#define SHT_PROGBITS	  1		/* Program data */
++#define SHT_SYMTAB	  2		/* Symbol table */
++#define SHT_STRTAB	  3		/* String table */
++#define SHT_RELA	  4		/* Relocation entries with addends */
++#define SHT_HASH	  5		/* Symbol hash table */
++#define SHT_DYNAMIC	  6		/* Dynamic linking information */
++#define SHT_NOTE	  7		/* Notes */
++#define SHT_NOBITS	  8		/* Program space with no data (bss) */
++#define SHT_REL		  9		/* Relocation entries, no addends */
++#define SHT_SHLIB	  10		/* Reserved */
++#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
++#define SHT_INIT_ARRAY	  14		/* Array of constructors */
++#define SHT_FINI_ARRAY	  15		/* Array of destructors */
++#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
++#define SHT_GROUP	  17		/* Section group */
++#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
++#define	SHT_NUM		  19		/* Number of defined types.  */
++#define SHT_LOOS	  0x60000000	/* Start OS-specific.  */
++#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes.  */
++#define SHT_GNU_HASH	  0x6ffffff6	/* GNU-style hash table.  */
++#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
++#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
++#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
++#define SHT_SUNW_move	  0x6ffffffa
++#define SHT_SUNW_COMDAT   0x6ffffffb
++#define SHT_SUNW_syminfo  0x6ffffffc
++#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
++#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
++#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
++#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
++#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
++#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
++#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
++#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
++#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
++
++/* Legal values for sh_flags (section flags).  */
++
++#define SHF_WRITE	     (1 << 0)	/* Writable */
++#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
++#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
++#define SHF_MERGE	     (1 << 4)	/* Might be merged */
++#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
++#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
++#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
++#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
++					   required */
++#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
++#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
++#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
++#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
++#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
++					   (Solaris).  */
++#define SHF_EXCLUDE	     (1 << 31)	/* Section is excluded unless
++					   referenced or allocated (Solaris).*/
++
++/* Section group handling.  */
++#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
++
++/* Symbol table entry.  */
++
++typedef struct
++{
++  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
++  Elf32_Addr	st_value;		/* Symbol value */
++  Elf32_Word	st_size;		/* Symbol size */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char	st_other;		/* Symbol visibility */
++  Elf32_Section	st_shndx;		/* Section index */
++} Elf32_Sym;
++
++typedef struct
++{
++  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char st_other;		/* Symbol visibility */
++  Elf64_Section	st_shndx;		/* Section index */
++  Elf64_Addr	st_value;		/* Symbol value */
++  Elf64_Xword	st_size;		/* Symbol size */
++} Elf64_Sym;
++
++/* The syminfo section if available contains additional information about
++   every dynamic symbol.  */
++
++typedef struct
++{
++  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf32_Half si_flags;			/* Per symbol flags */
++} Elf32_Syminfo;
++
++typedef struct
++{
++  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf64_Half si_flags;			/* Per symbol flags */
++} Elf64_Syminfo;
++
++/* Possible values for si_boundto.  */
++#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
++#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
++#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
++
++/* Possible bitmasks for si_flags.  */
++#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
++#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
++#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
++#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
++					   loaded */
++/* Syminfo version values.  */
++#define SYMINFO_NONE		0
++#define SYMINFO_CURRENT		1
++#define SYMINFO_NUM		2
++
++
++/* How to extract and insert information held in the st_info field.  */
++
++#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
++#define ELF32_ST_TYPE(val)		((val) & 0xf)
++#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
++
++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
++#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
++#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
++#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
++
++/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
++
++#define STB_LOCAL	0		/* Local symbol */
++#define STB_GLOBAL	1		/* Global symbol */
++#define STB_WEAK	2		/* Weak symbol */
++#define	STB_NUM		3		/* Number of defined types.  */
++#define STB_LOOS	10		/* Start of OS-specific */
++#define STB_GNU_UNIQUE	10		/* Unique symbol.  */
++#define STB_HIOS	12		/* End of OS-specific */
++#define STB_LOPROC	13		/* Start of processor-specific */
++#define STB_HIPROC	15		/* End of processor-specific */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_NOTYPE	0		/* Symbol type is unspecified */
++#define STT_OBJECT	1		/* Symbol is a data object */
++#define STT_FUNC	2		/* Symbol is a code object */
++#define STT_SECTION	3		/* Symbol associated with a section */
++#define STT_FILE	4		/* Symbol's name is file name */
++#define STT_COMMON	5		/* Symbol is a common data object */
++#define STT_TLS		6		/* Symbol is thread-local data object*/
++#define	STT_NUM		7		/* Number of defined types.  */
++#define STT_LOOS	10		/* Start of OS-specific */
++#define STT_GNU_IFUNC	10		/* Symbol is indirect code object */
++#define STT_HIOS	12		/* End of OS-specific */
++#define STT_LOPROC	13		/* Start of processor-specific */
++#define STT_HIPROC	15		/* End of processor-specific */
++
++
++/* Symbol table indices are found in the hash buckets and chain table
++   of a symbol hash table section.  This special index value indicates
++   the end of a chain, meaning no further symbols are found in that bucket.  */
++
++#define STN_UNDEF	0		/* End of a chain.  */
++
++
++/* How to extract and insert information held in the st_other field.  */
++
++#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
++
++/* For ELF64 the definitions are the same.  */
++#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
++
++/* Symbol visibility specification encoded in the st_other field.  */
++#define STV_DEFAULT	0		/* Default symbol visibility rules */
++#define STV_INTERNAL	1		/* Processor specific hidden class */
++#define STV_HIDDEN	2		/* Sym unavailable in other modules */
++#define STV_PROTECTED	3		/* Not preemptible, not exported */
++
++
++/* Relocation table entry without addend (in section of type SHT_REL).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++} Elf32_Rel;
++
++/* I have seen two different definitions of the Elf64_Rel and
++   Elf64_Rela structures, so we'll leave them out until Novell (or
++   whoever) gets their act together.  */
++/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++} Elf64_Rel;
++
++/* Relocation table entry with addend (in section of type SHT_RELA).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++  Elf32_Sword	r_addend;		/* Addend */
++} Elf32_Rela;
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++  Elf64_Sxword	r_addend;		/* Addend */
++} Elf64_Rela;
++
++/* How to extract and insert information held in the r_info field.  */
++
++#define ELF32_R_SYM(val)		((val) >> 8)
++#define ELF32_R_TYPE(val)		((val) & 0xff)
++#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
++
++#define ELF64_R_SYM(i)			((i) >> 32)
++#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
++#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
++
++/* Program segment header.  */
++
++typedef struct
++{
++  Elf32_Word	p_type;			/* Segment type */
++  Elf32_Off	p_offset;		/* Segment file offset */
++  Elf32_Addr	p_vaddr;		/* Segment virtual address */
++  Elf32_Addr	p_paddr;		/* Segment physical address */
++  Elf32_Word	p_filesz;		/* Segment size in file */
++  Elf32_Word	p_memsz;		/* Segment size in memory */
++  Elf32_Word	p_flags;		/* Segment flags */
++  Elf32_Word	p_align;		/* Segment alignment */
++} Elf32_Phdr;
++
++typedef struct
++{
++  Elf64_Word	p_type;			/* Segment type */
++  Elf64_Word	p_flags;		/* Segment flags */
++  Elf64_Off	p_offset;		/* Segment file offset */
++  Elf64_Addr	p_vaddr;		/* Segment virtual address */
++  Elf64_Addr	p_paddr;		/* Segment physical address */
++  Elf64_Xword	p_filesz;		/* Segment size in file */
++  Elf64_Xword	p_memsz;		/* Segment size in memory */
++  Elf64_Xword	p_align;		/* Segment alignment */
++} Elf64_Phdr;
++
++/* Special value for e_phnum.  This indicates that the real number of
++   program headers is too large to fit into e_phnum.  Instead the real
++   value is in the field sh_info of section 0.  */
++
++#define PN_XNUM		0xffff
++
++/* Legal values for p_type (segment type).  */
++
++#define	PT_NULL		0		/* Program header table entry unused */
++#define PT_LOAD		1		/* Loadable program segment */
++#define PT_DYNAMIC	2		/* Dynamic linking information */
++#define PT_INTERP	3		/* Program interpreter */
++#define PT_NOTE		4		/* Auxiliary information */
++#define PT_SHLIB	5		/* Reserved */
++#define PT_PHDR		6		/* Entry for header table itself */
++#define PT_TLS		7		/* Thread-local storage segment */
++#define	PT_NUM		8		/* Number of defined types */
++#define PT_LOOS		0x60000000	/* Start of OS-specific */
++#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
++#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
++#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
++#define PT_LOSUNW	0x6ffffffa
++#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
++#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
++#define PT_HISUNW	0x6fffffff
++#define PT_HIOS		0x6fffffff	/* End of OS-specific */
++#define PT_LOPROC	0x70000000	/* Start of processor-specific */
++#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
++
++/* Legal values for p_flags (segment flags).  */
++
++#define PF_X		(1 << 0)	/* Segment is executable */
++#define PF_W		(1 << 1)	/* Segment is writable */
++#define PF_R		(1 << 2)	/* Segment is readable */
++#define PF_MASKOS	0x0ff00000	/* OS-specific */
++#define PF_MASKPROC	0xf0000000	/* Processor-specific */
++
++/* Legal values for note segment descriptor types for core files. */
++
++#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
++#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
++#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
++#define NT_PRXREG	4		/* Contains copy of prxregset struct */
++#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
++#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
++#define NT_AUXV		6		/* Contains copy of auxv array */
++#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
++#define NT_ASRS		8		/* Contains copy of asrset struct */
++#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
++#define NT_PSINFO	13		/* Contains copy of psinfo struct */
++#define NT_PRCRED	14		/* Contains copy of prcred struct */
++#define NT_UTSNAME	15		/* Contains copy of utsname struct */
++#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
++#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
++#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct */
++#define NT_PRXFPREG	0x46e62b7f	/* Contains copy of user_fxsr_struct */
++#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
++#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
++#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
++#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
++#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
++#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
++
++/* Legal values for the note segment descriptor types for object files.  */
++
++#define NT_VERSION	1		/* Contains a version string.  */
++
++
++/* Dynamic section entry.  */
++
++typedef struct
++{
++  Elf32_Sword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf32_Word d_val;			/* Integer value */
++      Elf32_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf32_Dyn;
++
++typedef struct
++{
++  Elf64_Sxword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf64_Xword d_val;		/* Integer value */
++      Elf64_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf64_Dyn;
++
++/* Legal values for d_tag (dynamic entry type).  */
++
++#define DT_NULL		0		/* Marks end of dynamic section */
++#define DT_NEEDED	1		/* Name of needed library */
++#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
++#define DT_PLTGOT	3		/* Processor defined value */
++#define DT_HASH		4		/* Address of symbol hash table */
++#define DT_STRTAB	5		/* Address of string table */
++#define DT_SYMTAB	6		/* Address of symbol table */
++#define DT_RELA		7		/* Address of Rela relocs */
++#define DT_RELASZ	8		/* Total size of Rela relocs */
++#define DT_RELAENT	9		/* Size of one Rela reloc */
++#define DT_STRSZ	10		/* Size of string table */
++#define DT_SYMENT	11		/* Size of one symbol table entry */
++#define DT_INIT		12		/* Address of init function */
++#define DT_FINI		13		/* Address of termination function */
++#define DT_SONAME	14		/* Name of shared object */
++#define DT_RPATH	15		/* Library search path (deprecated) */
++#define DT_SYMBOLIC	16		/* Start symbol search here */
++#define DT_REL		17		/* Address of Rel relocs */
++#define DT_RELSZ	18		/* Total size of Rel relocs */
++#define DT_RELENT	19		/* Size of one Rel reloc */
++#define DT_PLTREL	20		/* Type of reloc in PLT */
++#define DT_DEBUG	21		/* For debugging; unspecified */
++#define DT_TEXTREL	22		/* Reloc might modify .text */
++#define DT_JMPREL	23		/* Address of PLT relocs */
++#define	DT_BIND_NOW	24		/* Process relocations of object */
++#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
++#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
++#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
++#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
++#define DT_RUNPATH	29		/* Library search path */
++#define DT_FLAGS	30		/* Flags for the object being loaded */
++#define DT_ENCODING	32		/* Start of encoded range */
++#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
++#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
++#define	DT_NUM		34		/* Number used */
++#define DT_LOOS		0x6000000d	/* Start of OS-specific */
++#define DT_HIOS		0x6ffff000	/* End of OS-specific */
++#define DT_LOPROC	0x70000000	/* Start of processor-specific */
++#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
++#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
++
++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
++   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
++   approach.  */
++#define DT_VALRNGLO	0x6ffffd00
++#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
++#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
++#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
++#define DT_CHECKSUM	0x6ffffdf8
++#define DT_PLTPADSZ	0x6ffffdf9
++#define DT_MOVEENT	0x6ffffdfa
++#define DT_MOVESZ	0x6ffffdfb
++#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
++#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
++					   the following DT_* entry.  */
++#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
++#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
++#define DT_VALRNGHI	0x6ffffdff
++#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
++#define DT_VALNUM 12
++
++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
++   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
++
++   If any adjustment is made to the ELF object after it has been
++   built these entries will need to be adjusted.  */
++#define DT_ADDRRNGLO	0x6ffffe00
++#define DT_GNU_HASH	0x6ffffef5	/* GNU-style hash table.  */
++#define DT_TLSDESC_PLT	0x6ffffef6
++#define DT_TLSDESC_GOT	0x6ffffef7
++#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
++#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
++#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
++#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
++#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
++#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
++#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
++#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
++#define DT_ADDRRNGHI	0x6ffffeff
++#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
++#define DT_ADDRNUM 11
++
++/* The versioning entry types.  The next are defined as part of the
++   GNU extension.  */
++#define DT_VERSYM	0x6ffffff0
++
++#define DT_RELACOUNT	0x6ffffff9
++#define DT_RELCOUNT	0x6ffffffa
++
++/* These were chosen by Sun.  */
++#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
++#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
++					   table */
++#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
++#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
++					   versions */
++#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
++#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
++#define DT_VERSIONTAGNUM 16
++
++/* Sun added these machine-independent extensions in the "processor-specific"
++   range.  Be compatible.  */
++#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
++#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
++#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
++#define DT_EXTRANUM	3
++
++/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
++#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
++#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
++#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
++#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
++#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
++
++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
++   entry in the dynamic section.  */
++#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
++#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
++#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
++#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
++#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
++#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
++#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
++#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
++#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
++#define DF_1_TRANS	0x00000200
++#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
++#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
++#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
++#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
++#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
++#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
++#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
++
++/* Flags for the feature selection in DT_FEATURE_1.  */
++#define DTF_1_PARINIT	0x00000001
++#define DTF_1_CONFEXP	0x00000002
++
++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
++#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
++#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
++					   generally available.  */
++
++/* Version definition sections.  */
++
++typedef struct
++{
++  Elf32_Half	vd_version;		/* Version revision */
++  Elf32_Half	vd_flags;		/* Version information */
++  Elf32_Half	vd_ndx;			/* Version Index */
++  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vd_hash;		/* Version name hash value */
++  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf32_Verdef;
++
++typedef struct
++{
++  Elf64_Half	vd_version;		/* Version revision */
++  Elf64_Half	vd_flags;		/* Version information */
++  Elf64_Half	vd_ndx;			/* Version Index */
++  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vd_hash;		/* Version name hash value */
++  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf64_Verdef;
++
++
++/* Legal values for vd_version (version revision).  */
++#define VER_DEF_NONE	0		/* No version */
++#define VER_DEF_CURRENT	1		/* Current version */
++#define VER_DEF_NUM	2		/* Given version number */
++
++/* Legal values for vd_flags (version information flags).  */
++#define VER_FLG_BASE	0x1		/* Version definition of file itself */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++/* Versym symbol index values.  */
++#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
++#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
++#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
++#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
++
++/* Auxialiary version information.  */
++
++typedef struct
++{
++  Elf32_Word	vda_name;		/* Version or dependency names */
++  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf32_Verdaux;
++
++typedef struct
++{
++  Elf64_Word	vda_name;		/* Version or dependency names */
++  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf64_Verdaux;
++
++
++/* Version dependency section.  */
++
++typedef struct
++{
++  Elf32_Half	vn_version;		/* Version of structure */
++  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf32_Verneed;
++
++typedef struct
++{
++  Elf64_Half	vn_version;		/* Version of structure */
++  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf64_Verneed;
++
++
++/* Legal values for vn_version (version revision).  */
++#define VER_NEED_NONE	 0		/* No version */
++#define VER_NEED_CURRENT 1		/* Current version */
++#define VER_NEED_NUM	 2		/* Given version number */
++
++/* Auxiliary needed version information.  */
++
++typedef struct
++{
++  Elf32_Word	vna_hash;		/* Hash value of dependency name */
++  Elf32_Half	vna_flags;		/* Dependency specific information */
++  Elf32_Half	vna_other;		/* Unused */
++  Elf32_Word	vna_name;		/* Dependency name string offset */
++  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf32_Vernaux;
++
++typedef struct
++{
++  Elf64_Word	vna_hash;		/* Hash value of dependency name */
++  Elf64_Half	vna_flags;		/* Dependency specific information */
++  Elf64_Half	vna_other;		/* Unused */
++  Elf64_Word	vna_name;		/* Dependency name string offset */
++  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf64_Vernaux;
++
++
++/* Legal values for vna_flags.  */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++
++/* Auxiliary vector.  */
++
++/* This vector is normally only used by the program interpreter.  The
++   usual definition in an ABI supplement uses the name auxv_t.  The
++   vector is not usually defined in a standard <elf.h> file, but it
++   can't hurt.  We rename it to avoid conflicts.  The sizes of these
++   types are an arrangement between the exec server and the program
++   interpreter, so we don't fully specify them here.  */
++
++typedef struct
++{
++  uint32_t a_type;		/* Entry type */
++  union
++    {
++      uint32_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf32_auxv_t;
++
++typedef struct
++{
++  uint64_t a_type;		/* Entry type */
++  union
++    {
++      uint64_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf64_auxv_t;
++
++/* Legal values for a_type (entry type).  */
++
++#define AT_NULL		0		/* End of vector */
++#define AT_IGNORE	1		/* Entry should be ignored */
++#define AT_EXECFD	2		/* File descriptor of program */
++#define AT_PHDR		3		/* Program headers for program */
++#define AT_PHENT	4		/* Size of program header entry */
++#define AT_PHNUM	5		/* Number of program headers */
++#define AT_PAGESZ	6		/* System page size */
++#define AT_BASE		7		/* Base address of interpreter */
++#define AT_FLAGS	8		/* Flags */
++#define AT_ENTRY	9		/* Entry point of program */
++#define AT_NOTELF	10		/* Program is not ELF */
++#define AT_UID		11		/* Real uid */
++#define AT_EUID		12		/* Effective uid */
++#define AT_GID		13		/* Real gid */
++#define AT_EGID		14		/* Effective gid */
++#define AT_CLKTCK	17		/* Frequency of times() */
++
++/* Some more special a_type values describing the hardware.  */
++#define AT_PLATFORM	15		/* String identifying platform.  */
++#define AT_HWCAP	16		/* Machine dependent hints about
++					   processor capabilities.  */
++
++/* This entry gives some information about the FPU initialization
++   performed by the kernel.  */
++#define AT_FPUCW	18		/* Used FPU control word.  */
++
++/* Cache block sizes.  */
++#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
++#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
++#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
++
++/* A special ignored value for PPC, used by the kernel to control the
++   interpretation of the AUXV. Must be > 16.  */
++#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
++
++#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
++
++#define AT_BASE_PLATFORM 24		/* String identifying real platforms.*/
++
++#define AT_RANDOM	25		/* Address of 16 random bytes.  */
++
++#define AT_EXECFN	31		/* Filename of executable.  */
++
++/* Pointer to the global system page used for system calls and other
++   nice things.  */
++#define AT_SYSINFO	32
++#define AT_SYSINFO_EHDR	33
++
++/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
++   log2 of line size; mask those to get cache size.  */
++#define AT_L1I_CACHESHAPE	34
++#define AT_L1D_CACHESHAPE	35
++#define AT_L2_CACHESHAPE	36
++#define AT_L3_CACHESHAPE	37
++
++/* Note section contents.  Each entry in the note section begins with
++   a header of a fixed form.  */
++
++typedef struct
++{
++  Elf32_Word n_namesz;			/* Length of the note's name.  */
++  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf32_Word n_type;			/* Type of the note.  */
++} Elf32_Nhdr;
++
++typedef struct
++{
++  Elf64_Word n_namesz;			/* Length of the note's name.  */
++  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf64_Word n_type;			/* Type of the note.  */
++} Elf64_Nhdr;
++
++/* Known names of notes.  */
++
++/* Solaris entries in the note section have this name.  */
++#define ELF_NOTE_SOLARIS	"SUNW Solaris"
++
++/* Note entries for GNU systems have this name.  */
++#define ELF_NOTE_GNU		"GNU"
++
++
++/* Defined types of notes for Solaris.  */
++
++/* Value of descriptor (one word) is desired pagesize for the binary.  */
++#define ELF_NOTE_PAGESIZE_HINT	1
++
++
++/* Defined note types for GNU systems.  */
++
++/* ABI information.  The descriptor consists of words:
++   word 0: OS descriptor
++   word 1: major version of the ABI
++   word 2: minor version of the ABI
++   word 3: subminor version of the ABI
++*/
++#define NT_GNU_ABI_TAG	1
++#define ELF_NOTE_ABI	NT_GNU_ABI_TAG /* Old name.  */
++
++/* Known OSes.  These values can appear in word 0 of an
++   NT_GNU_ABI_TAG note section entry.  */
++#define ELF_NOTE_OS_LINUX	0
++#define ELF_NOTE_OS_GNU		1
++#define ELF_NOTE_OS_SOLARIS2	2
++#define ELF_NOTE_OS_FREEBSD	3
++
++/* Synthetic hwcap information.  The descriptor begins with two words:
++   word 0: number of entries
++   word 1: bitmask of enabled entries
++   Then follow variable-length entries, one byte followed by a
++   '\0'-terminated hwcap name string.  The byte gives the bit
++   number to test if enabled, (1U << bit) & bitmask.  */
++#define NT_GNU_HWCAP	2
++
++/* Build ID bits as generated by ld --build-id.
++   The descriptor consists of any nonzero number of bytes.  */
++#define NT_GNU_BUILD_ID	3
++
++/* Version note generated by GNU gold containing a version string.  */
++#define NT_GNU_GOLD_VERSION	4
++
++
++/* Move records.  */
++typedef struct
++{
++  Elf32_Xword m_value;		/* Symbol value.  */
++  Elf32_Word m_info;		/* Size and index.  */
++  Elf32_Word m_poffset;		/* Symbol offset.  */
++  Elf32_Half m_repeat;		/* Repeat count.  */
++  Elf32_Half m_stride;		/* Stride info.  */
++} Elf32_Move;
++
++typedef struct
++{
++  Elf64_Xword m_value;		/* Symbol value.  */
++  Elf64_Xword m_info;		/* Size and index.  */
++  Elf64_Xword m_poffset;	/* Symbol offset.  */
++  Elf64_Half m_repeat;		/* Repeat count.  */
++  Elf64_Half m_stride;		/* Stride info.  */
++} Elf64_Move;
++
++/* Macro to construct move records.  */
++#define ELF32_M_SYM(info)	((info) >> 8)
++#define ELF32_M_SIZE(info)	((unsigned char) (info))
++#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
++
++#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
++#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
++#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
++
++
++/* Motorola 68k specific definitions.  */
++
++/* Values for Elf32_Ehdr.e_flags.  */
++#define EF_CPU32	0x00810000
++
++/* m68k relocs.  */
++
++#define R_68K_NONE	0		/* No reloc */
++#define R_68K_32	1		/* Direct 32 bit  */
++#define R_68K_16	2		/* Direct 16 bit  */
++#define R_68K_8		3		/* Direct 8 bit  */
++#define R_68K_PC32	4		/* PC relative 32 bit */
++#define R_68K_PC16	5		/* PC relative 16 bit */
++#define R_68K_PC8	6		/* PC relative 8 bit */
++#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
++#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
++#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
++#define R_68K_GOT32O	10		/* 32 bit GOT offset */
++#define R_68K_GOT16O	11		/* 16 bit GOT offset */
++#define R_68K_GOT8O	12		/* 8 bit GOT offset */
++#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
++#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
++#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
++#define R_68K_PLT32O	16		/* 32 bit PLT offset */
++#define R_68K_PLT16O	17		/* 16 bit PLT offset */
++#define R_68K_PLT8O	18		/* 8 bit PLT offset */
++#define R_68K_COPY	19		/* Copy symbol at runtime */
++#define R_68K_GLOB_DAT	20		/* Create GOT entry */
++#define R_68K_JMP_SLOT	21		/* Create PLT entry */
++#define R_68K_RELATIVE	22		/* Adjust by program base */
++#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
++#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
++#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
++#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
++#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
++#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
++#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
++#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
++#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
++#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
++#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
++#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
++#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
++#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
++#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
++/* Keep this the last entry.  */
++#define R_68K_NUM	43
++
++/* Intel 80386 specific definitions.  */
++
++/* i386 relocs.  */
++
++#define R_386_NONE	   0		/* No reloc */
++#define R_386_32	   1		/* Direct 32 bit  */
++#define R_386_PC32	   2		/* PC relative 32 bit */
++#define R_386_GOT32	   3		/* 32 bit GOT entry */
++#define R_386_PLT32	   4		/* 32 bit PLT address */
++#define R_386_COPY	   5		/* Copy symbol at runtime */
++#define R_386_GLOB_DAT	   6		/* Create GOT entry */
++#define R_386_JMP_SLOT	   7		/* Create PLT entry */
++#define R_386_RELATIVE	   8		/* Adjust by program base */
++#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
++#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
++#define R_386_32PLT	   11
++#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
++#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
++					   block offset */
++#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
++					   offset */
++#define R_386_TLS_LE	   17		/* Offset relative to static TLS
++					   block */
++#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
++					   general dynamic thread local data */
++#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
++					   local dynamic thread local data
++					   in LE code */
++#define R_386_16	   20
++#define R_386_PC16	   21
++#define R_386_8		   22
++#define R_386_PC8	   23
++#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
++					   thread local data */
++#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
++#define R_386_TLS_GD_CALL  26		/* Relocation for call to
++					   __tls_get_addr() */
++#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
++#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
++					   thread local data in LE code */
++#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
++#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
++					   __tls_get_addr() in LDM code */
++#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
++#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
++#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
++					   block offset */
++#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
++					   TLS block */
++#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
++#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
++#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
++/* 38? */
++#define R_386_TLS_GOTDESC  39		/* GOT offset for TLS descriptor.  */
++#define R_386_TLS_DESC_CALL 40		/* Marker of call through TLS
++					   descriptor for
++					   relaxation.  */
++#define R_386_TLS_DESC     41		/* TLS descriptor containing
++					   pointer to code and to
++					   argument, returning the TLS
++					   offset for the symbol.  */
++#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
++/* Keep this the last entry.  */
++#define R_386_NUM	   43
++
++/* SUN SPARC specific definitions.  */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
++
++/* Values for Elf64_Ehdr.e_flags.  */
++
++#define EF_SPARCV9_MM		3
++#define EF_SPARCV9_TSO		0
++#define EF_SPARCV9_PSO		1
++#define EF_SPARCV9_RMO		2
++#define EF_SPARC_LEDATA		0x800000 /* little endian data */
++#define EF_SPARC_EXT_MASK	0xFFFF00
++#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
++#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
++#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
++#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
++
++/* SPARC relocs.  */
++
++#define R_SPARC_NONE		0	/* No reloc */
++#define R_SPARC_8		1	/* Direct 8 bit */
++#define R_SPARC_16		2	/* Direct 16 bit */
++#define R_SPARC_32		3	/* Direct 32 bit */
++#define R_SPARC_DISP8		4	/* PC relative 8 bit */
++#define R_SPARC_DISP16		5	/* PC relative 16 bit */
++#define R_SPARC_DISP32		6	/* PC relative 32 bit */
++#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
++#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
++#define R_SPARC_HI22		9	/* High 22 bit */
++#define R_SPARC_22		10	/* Direct 22 bit */
++#define R_SPARC_13		11	/* Direct 13 bit */
++#define R_SPARC_LO10		12	/* Truncated 10 bit */
++#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
++#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
++#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
++#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
++#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
++#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
++#define R_SPARC_COPY		19	/* Copy symbol at runtime */
++#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
++#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
++#define R_SPARC_RELATIVE	22	/* Adjust by program base */
++#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
++
++/* Additional Sparc64 relocs.  */
++
++#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
++#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
++#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
++#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
++#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
++#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
++#define R_SPARC_10		30	/* Direct 10 bit */
++#define R_SPARC_11		31	/* Direct 11 bit */
++#define R_SPARC_64		32	/* Direct 64 bit */
++#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
++#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
++#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
++#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
++#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
++#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
++#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
++#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
++#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
++#define R_SPARC_GLOB_JMP	42	/* was part of v9 ABI but was removed */
++#define R_SPARC_7		43	/* Direct 7 bit */
++#define R_SPARC_5		44	/* Direct 5 bit */
++#define R_SPARC_6		45	/* Direct 6 bit */
++#define R_SPARC_DISP64		46	/* PC relative 64 bit */
++#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
++#define R_SPARC_HIX22		48	/* High 22 bit complemented */
++#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
++#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
++#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
++#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
++#define R_SPARC_REGISTER	53	/* Global register usage */
++#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
++#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
++#define R_SPARC_TLS_GD_HI22	56
++#define R_SPARC_TLS_GD_LO10	57
++#define R_SPARC_TLS_GD_ADD	58
++#define R_SPARC_TLS_GD_CALL	59
++#define R_SPARC_TLS_LDM_HI22	60
++#define R_SPARC_TLS_LDM_LO10	61
++#define R_SPARC_TLS_LDM_ADD	62
++#define R_SPARC_TLS_LDM_CALL	63
++#define R_SPARC_TLS_LDO_HIX22	64
++#define R_SPARC_TLS_LDO_LOX10	65
++#define R_SPARC_TLS_LDO_ADD	66
++#define R_SPARC_TLS_IE_HI22	67
++#define R_SPARC_TLS_IE_LO10	68
++#define R_SPARC_TLS_IE_LD	69
++#define R_SPARC_TLS_IE_LDX	70
++#define R_SPARC_TLS_IE_ADD	71
++#define R_SPARC_TLS_LE_HIX22	72
++#define R_SPARC_TLS_LE_LOX10	73
++#define R_SPARC_TLS_DTPMOD32	74
++#define R_SPARC_TLS_DTPMOD64	75
++#define R_SPARC_TLS_DTPOFF32	76
++#define R_SPARC_TLS_DTPOFF64	77
++#define R_SPARC_TLS_TPOFF32	78
++#define R_SPARC_TLS_TPOFF64	79
++#define R_SPARC_GOTDATA_HIX22	80
++#define R_SPARC_GOTDATA_LOX10	81
++#define R_SPARC_GOTDATA_OP_HIX22	82
++#define R_SPARC_GOTDATA_OP_LOX10	83
++#define R_SPARC_GOTDATA_OP	84
++#define R_SPARC_H34		85
++#define R_SPARC_SIZE32		86
++#define R_SPARC_SIZE64		87
++#define R_SPARC_WDISP10		88
++#define R_SPARC_JMP_IREL	248
++#define R_SPARC_IRELATIVE	249
++#define R_SPARC_GNU_VTINHERIT	250
++#define R_SPARC_GNU_VTENTRY	251
++#define R_SPARC_REV32		252
++/* Keep this the last entry.  */
++#define R_SPARC_NUM		253
++
++/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
++
++#define DT_SPARC_REGISTER 0x70000001
++#define DT_SPARC_NUM	2
++
++/* MIPS R3000 specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
++#define EF_MIPS_PIC	    2		/* Contains PIC code */
++#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
++#define EF_MIPS_XGOT	    8
++#define EF_MIPS_64BIT_WHIRL 16
++#define EF_MIPS_ABI2	    32
++#define EF_MIPS_ABI_ON32    64
++#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
++
++/* Legal values for MIPS architecture level.  */
++
++#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
++#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
++#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
++#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
++#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
++#define EF_MIPS_ARCH_32	    0x60000000	/* MIPS32 code.  */
++#define EF_MIPS_ARCH_64	    0x70000000	/* MIPS64 code.  */
++
++/* The following are non-official names and should not be used.  */
++
++#define E_MIPS_ARCH_1	  0x00000000	/* -mips1 code.  */
++#define E_MIPS_ARCH_2	  0x10000000	/* -mips2 code.  */
++#define E_MIPS_ARCH_3	  0x20000000	/* -mips3 code.  */
++#define E_MIPS_ARCH_4	  0x30000000	/* -mips4 code.  */
++#define E_MIPS_ARCH_5	  0x40000000	/* -mips5 code.  */
++#define E_MIPS_ARCH_32	  0x60000000	/* MIPS32 code.  */
++#define E_MIPS_ARCH_64	  0x70000000	/* MIPS64 code.  */
++
++/* Special section indices.  */
++
++#define SHN_MIPS_ACOMMON    0xff00	/* Allocated common symbols */
++#define SHN_MIPS_TEXT	    0xff01	/* Allocated test symbols.  */
++#define SHN_MIPS_DATA	    0xff02	/* Allocated data symbols.  */
++#define SHN_MIPS_SCOMMON    0xff03	/* Small common symbols */
++#define SHN_MIPS_SUNDEFINED 0xff04	/* Small undefined symbols */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
++#define SHT_MIPS_MSYM	       0x70000001
++#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
++#define SHT_MIPS_GPTAB	       0x70000003 /* Global data area sizes */
++#define SHT_MIPS_UCODE	       0x70000004 /* Reserved for SGI/MIPS compilers */
++#define SHT_MIPS_DEBUG	       0x70000005 /* MIPS ECOFF debugging information*/
++#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
++#define SHT_MIPS_PACKAGE       0x70000007
++#define SHT_MIPS_PACKSYM       0x70000008
++#define SHT_MIPS_RELD	       0x70000009
++#define SHT_MIPS_IFACE         0x7000000b
++#define SHT_MIPS_CONTENT       0x7000000c
++#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
++#define SHT_MIPS_SHDR	       0x70000010
++#define SHT_MIPS_FDESC	       0x70000011
++#define SHT_MIPS_EXTSYM	       0x70000012
++#define SHT_MIPS_DENSE	       0x70000013
++#define SHT_MIPS_PDESC	       0x70000014
++#define SHT_MIPS_LOCSYM	       0x70000015
++#define SHT_MIPS_AUXSYM	       0x70000016
++#define SHT_MIPS_OPTSYM	       0x70000017
++#define SHT_MIPS_LOCSTR	       0x70000018
++#define SHT_MIPS_LINE	       0x70000019
++#define SHT_MIPS_RFDESC	       0x7000001a
++#define SHT_MIPS_DELTASYM      0x7000001b
++#define SHT_MIPS_DELTAINST     0x7000001c
++#define SHT_MIPS_DELTACLASS    0x7000001d
++#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
++#define SHT_MIPS_DELTADECL     0x7000001f
++#define SHT_MIPS_SYMBOL_LIB    0x70000020
++#define SHT_MIPS_EVENTS	       0x70000021 /* Event section.  */
++#define SHT_MIPS_TRANSLATE     0x70000022
++#define SHT_MIPS_PIXIE	       0x70000023
++#define SHT_MIPS_XLATE	       0x70000024
++#define SHT_MIPS_XLATE_DEBUG   0x70000025
++#define SHT_MIPS_WHIRL	       0x70000026
++#define SHT_MIPS_EH_REGION     0x70000027
++#define SHT_MIPS_XLATE_OLD     0x70000028
++#define SHT_MIPS_PDR_EXCEPTION 0x70000029
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_MIPS_GPREL	 0x10000000	/* Must be part of global data area */
++#define SHF_MIPS_MERGE	 0x20000000
++#define SHF_MIPS_ADDR	 0x40000000
++#define SHF_MIPS_STRINGS 0x80000000
++#define SHF_MIPS_NOSTRIP 0x08000000
++#define SHF_MIPS_LOCAL	 0x04000000
++#define SHF_MIPS_NAMES	 0x02000000
++#define SHF_MIPS_NODUPE	 0x01000000
++
++
++/* Symbol tables.  */
++
++/* MIPS specific values for `st_other'.  */
++#define STO_MIPS_DEFAULT		0x0
++#define STO_MIPS_INTERNAL		0x1
++#define STO_MIPS_HIDDEN			0x2
++#define STO_MIPS_PROTECTED		0x3
++#define STO_MIPS_PLT			0x8
++#define STO_MIPS_SC_ALIGN_UNUSED	0xff
++
++/* MIPS specific values for `st_info'.  */
++#define STB_MIPS_SPLIT_COMMON		13
++
++/* Entries found in sections of type SHT_MIPS_GPTAB.  */
++
++typedef union
++{
++  struct
++    {
++      Elf32_Word gt_current_g_value;	/* -G value used for compilation */
++      Elf32_Word gt_unused;		/* Not used */
++    } gt_header;			/* First entry in section */
++  struct
++    {
++      Elf32_Word gt_g_value;		/* If this value were used for -G */
++      Elf32_Word gt_bytes;		/* This many bytes would be used */
++    } gt_entry;				/* Subsequent entries in section */
++} Elf32_gptab;
++
++/* Entry found in sections of type SHT_MIPS_REGINFO.  */
++
++typedef struct
++{
++  Elf32_Word	ri_gprmask;		/* General registers used */
++  Elf32_Word	ri_cprmask[4];		/* Coprocessor registers used */
++  Elf32_Sword	ri_gp_value;		/* $gp register value */
++} Elf32_RegInfo;
++
++/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
++
++typedef struct
++{
++  unsigned char kind;		/* Determines interpretation of the
++				   variable part of descriptor.  */
++  unsigned char size;		/* Size of descriptor, including header.  */
++  Elf32_Section section;	/* Section header index of section affected,
++				   0 for global options.  */
++  Elf32_Word info;		/* Kind-specific information.  */
++} Elf_Options;
++
++/* Values for `kind' field in Elf_Options.  */
++
++#define ODK_NULL	0	/* Undefined.  */
++#define ODK_REGINFO	1	/* Register usage information.  */
++#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
++#define ODK_PAD		3	/* Section padding options.  */
++#define ODK_HWPATCH	4	/* Hardware workarounds performed */
++#define ODK_FILL	5	/* record the fill value used by the linker. */
++#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
++#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
++#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
++
++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
++
++#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
++#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
++#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
++#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
++#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
++#define OEX_PRECISEFP	OEX_FPDBUG
++#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
++
++#define OEX_FPU_INVAL	0x10
++#define OEX_FPU_DIV0	0x08
++#define OEX_FPU_OFLO	0x04
++#define OEX_FPU_UFLO	0x02
++#define OEX_FPU_INEX	0x01
++
++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
++
++#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
++#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
++#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
++#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
++
++#define OPAD_PREFIX	0x1
++#define OPAD_POSTFIX	0x2
++#define OPAD_SYMBOL	0x4
++
++/* Entry found in `.options' section.  */
++
++typedef struct
++{
++  Elf32_Word hwp_flags1;	/* Extra flags.  */
++  Elf32_Word hwp_flags2;	/* Extra flags.  */
++} Elf_Options_Hw;
++
++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
++
++#define OHWA0_R4KEOP_CHECKED	0x00000001
++#define OHWA1_R4KEOP_CLEAN	0x00000002
++
++/* MIPS relocs.  */
++
++#define R_MIPS_NONE		0	/* No reloc */
++#define R_MIPS_16		1	/* Direct 16 bit */
++#define R_MIPS_32		2	/* Direct 32 bit */
++#define R_MIPS_REL32		3	/* PC relative 32 bit */
++#define R_MIPS_26		4	/* Direct 26 bit shifted */
++#define R_MIPS_HI16		5	/* High 16 bit */
++#define R_MIPS_LO16		6	/* Low 16 bit */
++#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
++#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
++#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
++#define R_MIPS_PC16		10	/* PC relative 16 bit */
++#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
++#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
++
++#define R_MIPS_SHIFT5		16
++#define R_MIPS_SHIFT6		17
++#define R_MIPS_64		18
++#define R_MIPS_GOT_DISP		19
++#define R_MIPS_GOT_PAGE		20
++#define R_MIPS_GOT_OFST		21
++#define R_MIPS_GOT_HI16		22
++#define R_MIPS_GOT_LO16		23
++#define R_MIPS_SUB		24
++#define R_MIPS_INSERT_A		25
++#define R_MIPS_INSERT_B		26
++#define R_MIPS_DELETE		27
++#define R_MIPS_HIGHER		28
++#define R_MIPS_HIGHEST		29
++#define R_MIPS_CALL_HI16	30
++#define R_MIPS_CALL_LO16	31
++#define R_MIPS_SCN_DISP		32
++#define R_MIPS_REL16		33
++#define R_MIPS_ADD_IMMEDIATE	34
++#define R_MIPS_PJUMP		35
++#define R_MIPS_RELGOT		36
++#define R_MIPS_JALR		37
++#define R_MIPS_TLS_DTPMOD32	38	/* Module number 32 bit */
++#define R_MIPS_TLS_DTPREL32	39	/* Module-relative offset 32 bit */
++#define R_MIPS_TLS_DTPMOD64	40	/* Module number 64 bit */
++#define R_MIPS_TLS_DTPREL64	41	/* Module-relative offset 64 bit */
++#define R_MIPS_TLS_GD		42	/* 16 bit GOT offset for GD */
++#define R_MIPS_TLS_LDM		43	/* 16 bit GOT offset for LDM */
++#define R_MIPS_TLS_DTPREL_HI16	44	/* Module-relative offset, high 16 bits */
++#define R_MIPS_TLS_DTPREL_LO16	45	/* Module-relative offset, low 16 bits */
++#define R_MIPS_TLS_GOTTPREL	46	/* 16 bit GOT offset for IE */
++#define R_MIPS_TLS_TPREL32	47	/* TP-relative offset, 32 bit */
++#define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
++#define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
++#define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
++#define R_MIPS_GLOB_DAT		51
++#define R_MIPS_COPY		126
++#define R_MIPS_JUMP_SLOT        127
++/* Keep this the last entry.  */
++#define R_MIPS_NUM		128
++
++/* Legal values for p_type field of Elf32_Phdr.  */
++
++#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
++#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
++#define PT_MIPS_OPTIONS 0x70000002
++
++/* Special program header types.  */
++
++#define PF_MIPS_LOCAL	0x10000000
++
++/* Legal values for d_tag field of Elf32_Dyn.  */
++
++#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
++#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
++#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
++#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
++#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
++#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
++#define DT_MIPS_MSYM	     0x70000007
++#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
++#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
++#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
++#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
++#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
++#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
++#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
++#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
++#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
++#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
++#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
++#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
++						DT_MIPS_DELTA_CLASS.  */
++#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
++						DT_MIPS_DELTA_INSTANCE.  */
++#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
++					     DT_MIPS_DELTA_RELOC.  */
++#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
++					   relocations refer to.  */
++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
++					   DT_MIPS_DELTA_SYM.  */
++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
++					     class declaration.  */
++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
++						DT_MIPS_DELTA_CLASSSYM.  */
++#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
++#define DT_MIPS_PIXIE_INIT   0x70000023
++#define DT_MIPS_SYMBOL_LIB   0x70000024
++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
++#define DT_MIPS_LOCAL_GOTIDX 0x70000026
++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
++#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
++#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
++						    function stored in GOT.  */
++#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
++					   by rld on dlopen() calls.  */
++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
++#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
++#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
++/* The address of .got.plt in an executable using the new non-PIC ABI.  */
++#define DT_MIPS_PLTGOT	     0x70000032
++/* The base of the PLT in an executable using the new non-PIC ABI if that
++   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
++   value.  */
++#define DT_MIPS_RWPLT        0x70000034
++#define DT_MIPS_NUM	     0x35
++
++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
++
++#define RHF_NONE		   0		/* No flags */
++#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
++#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
++#define RHF_NO_MOVE		   (1 << 3)
++#define RHF_SGI_ONLY		   (1 << 4)
++#define RHF_GUARANTEE_INIT	   (1 << 5)
++#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
++#define RHF_GUARANTEE_START_INIT   (1 << 7)
++#define RHF_PIXIE		   (1 << 8)
++#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
++#define RHF_REQUICKSTART	   (1 << 10)
++#define RHF_REQUICKSTARTED	   (1 << 11)
++#define RHF_CORD		   (1 << 12)
++#define RHF_NO_UNRES_UNDEF	   (1 << 13)
++#define RHF_RLD_ORDER_SAFE	   (1 << 14)
++
++/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
++
++typedef struct
++{
++  Elf32_Word l_name;		/* Name (string table index) */
++  Elf32_Word l_time_stamp;	/* Timestamp */
++  Elf32_Word l_checksum;	/* Checksum */
++  Elf32_Word l_version;		/* Interface version */
++  Elf32_Word l_flags;		/* Flags */
++} Elf32_Lib;
++
++typedef struct
++{
++  Elf64_Word l_name;		/* Name (string table index) */
++  Elf64_Word l_time_stamp;	/* Timestamp */
++  Elf64_Word l_checksum;	/* Checksum */
++  Elf64_Word l_version;		/* Interface version */
++  Elf64_Word l_flags;		/* Flags */
++} Elf64_Lib;
++
++
++/* Legal values for l_flags.  */
++
++#define LL_NONE		  0
++#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
++#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
++#define LL_REQUIRE_MINOR  (1 << 2)
++#define LL_EXPORTS	  (1 << 3)
++#define LL_DELAY_LOAD	  (1 << 4)
++#define LL_DELTA	  (1 << 5)
++
++/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
++
++typedef Elf32_Addr Elf32_Conflict;
++
++
++/* HPPA specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
++#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
++#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
++#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
++#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
++					      prediction.  */
++#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
++#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
++
++/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
++
++#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
++#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
++#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
++
++/* Additional section indeces.  */
++
++#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
++					      symbols in ANSI C.  */
++#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
++#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
++#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
++#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
++#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
++
++#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
++#define STT_HP_STUB		(STT_LOOS + 0x2)
++
++/* HPPA relocs.  */
++
++#define R_PARISC_NONE		0	/* No reloc.  */
++#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
++#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
++#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
++#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
++#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
++#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
++#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
++#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
++#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
++#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
++#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
++#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
++#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
++#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
++#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
++#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
++#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
++#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
++#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
++#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
++#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
++#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
++#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
++#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
++#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
++#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fdesc address.  */
++#define R_PARISC_PLABEL14R	70	/* Right 14 bits of fdesc address.  */
++#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
++#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
++#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
++#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
++#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
++#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
++#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
++#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
++#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
++#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
++#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
++#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
++#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
++#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
++#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LORESERVE	128
++#define R_PARISC_COPY		128	/* Copy relocation.  */
++#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
++#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
++#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
++#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
++#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
++#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
++#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
++#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
++#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_GNU_VTENTRY	232
++#define R_PARISC_GNU_VTINHERIT	233
++#define R_PARISC_TLS_GD21L	234	/* GD 21-bit left.  */
++#define R_PARISC_TLS_GD14R	235	/* GD 14-bit right.  */
++#define R_PARISC_TLS_GDCALL	236	/* GD call to __t_g_a.  */
++#define R_PARISC_TLS_LDM21L	237	/* LD module 21-bit left.  */
++#define R_PARISC_TLS_LDM14R	238	/* LD module 14-bit right.  */
++#define R_PARISC_TLS_LDMCALL	239	/* LD module call to __t_g_a.  */
++#define R_PARISC_TLS_LDO21L	240	/* LD offset 21-bit left.  */
++#define R_PARISC_TLS_LDO14R	241	/* LD offset 14-bit right.  */
++#define R_PARISC_TLS_DTPMOD32	242	/* DTP module 32-bit.  */
++#define R_PARISC_TLS_DTPMOD64	243	/* DTP module 64-bit.  */
++#define R_PARISC_TLS_DTPOFF32	244	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_DTPOFF64	245	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L
++#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R
++#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L
++#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R
++#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32
++#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64
++#define R_PARISC_HIRESERVE	255
++
++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PT_HP_TLS		(PT_LOOS + 0x0)
++#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
++#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
++#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
++#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
++#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
++#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
++#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
++#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
++#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
++#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
++#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
++#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
++#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
++#define PT_HP_STACK		(PT_LOOS + 0x14)
++
++#define PT_PARISC_ARCHEXT	0x70000000
++#define PT_PARISC_UNWIND	0x70000001
++
++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PF_PARISC_SBP		0x08000000
++
++#define PF_HP_PAGE_SIZE		0x00100000
++#define PF_HP_FAR_SHARED	0x00200000
++#define PF_HP_NEAR_SHARED	0x00400000
++#define PF_HP_CODE		0x01000000
++#define PF_HP_MODIFY		0x02000000
++#define PF_HP_LAZYSWAP		0x04000000
++#define PF_HP_SBP		0x08000000
++
++
++/* Alpha specific definitions.  */
++
++/* Legal values for e_flags field of Elf64_Ehdr.  */
++
++#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
++#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
++
++/* Legal values for sh_type field of Elf64_Shdr.  */
++
++/* These two are primerily concerned with ECOFF debugging info.  */
++#define SHT_ALPHA_DEBUG		0x70000001
++#define SHT_ALPHA_REGINFO	0x70000002
++
++/* Legal values for sh_flags field of Elf64_Shdr.  */
++
++#define SHF_ALPHA_GPREL		0x10000000
++
++/* Legal values for st_other field of Elf64_Sym.  */
++#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
++#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
++
++/* Alpha relocs.  */
++
++#define R_ALPHA_NONE		0	/* No reloc */
++#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
++#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
++#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
++#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
++#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
++#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
++#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
++#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
++#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
++#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
++#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
++#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
++#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
++#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
++#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
++#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
++#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
++#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
++#define R_ALPHA_TLS_GD_HI	28
++#define R_ALPHA_TLSGD		29
++#define R_ALPHA_TLS_LDM		30
++#define R_ALPHA_DTPMOD64	31
++#define R_ALPHA_GOTDTPREL	32
++#define R_ALPHA_DTPREL64	33
++#define R_ALPHA_DTPRELHI	34
++#define R_ALPHA_DTPRELLO	35
++#define R_ALPHA_DTPREL16	36
++#define R_ALPHA_GOTTPREL	37
++#define R_ALPHA_TPREL64		38
++#define R_ALPHA_TPRELHI		39
++#define R_ALPHA_TPRELLO		40
++#define R_ALPHA_TPREL16		41
++/* Keep this the last entry.  */
++#define R_ALPHA_NUM		46
++
++/* Magic values of the LITUSE relocation addend.  */
++#define LITUSE_ALPHA_ADDR	0
++#define LITUSE_ALPHA_BASE	1
++#define LITUSE_ALPHA_BYTOFF	2
++#define LITUSE_ALPHA_JSR	3
++#define LITUSE_ALPHA_TLS_GD	4
++#define LITUSE_ALPHA_TLS_LDM	5
++
++/* Legal values for d_tag of Elf64_Dyn.  */
++#define DT_ALPHA_PLTRO		(DT_LOPROC + 0)
++#define DT_ALPHA_NUM		1
++
++/* PowerPC specific declarations */
++
++/* Values for Elf32/64_Ehdr.e_flags.  */
++#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
++
++/* Cygnus local bits below */
++#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
++#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
++						   flag */
++
++/* PowerPC relocations defined by the ABIs */
++#define R_PPC_NONE		0
++#define R_PPC_ADDR32		1	/* 32bit absolute address */
++#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
++#define R_PPC_ADDR16		3	/* 16bit absolute address */
++#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
++#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
++#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
++#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
++#define R_PPC_ADDR14_BRTAKEN	8
++#define R_PPC_ADDR14_BRNTAKEN	9
++#define R_PPC_REL24		10	/* PC relative 26 bit */
++#define R_PPC_REL14		11	/* PC relative 16 bit */
++#define R_PPC_REL14_BRTAKEN	12
++#define R_PPC_REL14_BRNTAKEN	13
++#define R_PPC_GOT16		14
++#define R_PPC_GOT16_LO		15
++#define R_PPC_GOT16_HI		16
++#define R_PPC_GOT16_HA		17
++#define R_PPC_PLTREL24		18
++#define R_PPC_COPY		19
++#define R_PPC_GLOB_DAT		20
++#define R_PPC_JMP_SLOT		21
++#define R_PPC_RELATIVE		22
++#define R_PPC_LOCAL24PC		23
++#define R_PPC_UADDR32		24
++#define R_PPC_UADDR16		25
++#define R_PPC_REL32		26
++#define R_PPC_PLT32		27
++#define R_PPC_PLTREL32		28
++#define R_PPC_PLT16_LO		29
++#define R_PPC_PLT16_HI		30
++#define R_PPC_PLT16_HA		31
++#define R_PPC_SDAREL16		32
++#define R_PPC_SECTOFF		33
++#define R_PPC_SECTOFF_LO	34
++#define R_PPC_SECTOFF_HI	35
++#define R_PPC_SECTOFF_HA	36
++
++/* PowerPC relocations defined for the TLS access ABI.  */
++#define R_PPC_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
++#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
++#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
++#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
++#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
++#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
++#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
++#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
++#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
++#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
++
++/* The remaining relocs are from the Embedded ELF ABI, and are not
++   in the SVR4 ELF ABI.  */
++#define R_PPC_EMB_NADDR32	101
++#define R_PPC_EMB_NADDR16	102
++#define R_PPC_EMB_NADDR16_LO	103
++#define R_PPC_EMB_NADDR16_HI	104
++#define R_PPC_EMB_NADDR16_HA	105
++#define R_PPC_EMB_SDAI16	106
++#define R_PPC_EMB_SDA2I16	107
++#define R_PPC_EMB_SDA2REL	108
++#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
++#define R_PPC_EMB_MRKREF	110
++#define R_PPC_EMB_RELSEC16	111
++#define R_PPC_EMB_RELST_LO	112
++#define R_PPC_EMB_RELST_HI	113
++#define R_PPC_EMB_RELST_HA	114
++#define R_PPC_EMB_BIT_FLD	115
++#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
++
++/* Diab tool relocations.  */
++#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
++#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
++#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
++#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
++#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
++#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC_IRELATIVE		248
++
++/* GNU relocs used in PIC code sequences.  */
++#define R_PPC_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC_REL16_LO		250	/* half16   (sym+add-.)@l */
++#define R_PPC_REL16_HI		251	/* half16   (sym+add-.)@h */
++#define R_PPC_REL16_HA		252	/* half16   (sym+add-.)@ha */
++
++/* This is a phony reloc to handle any old fashioned TOC16 references
++   that may still be in object files.  */
++#define R_PPC_TOC16		255
++
++/* PowerPC specific values for the Dyn d_tag field.  */
++#define DT_PPC_GOT		(DT_LOPROC + 0)
++#define DT_PPC_NUM		1
++
++/* PowerPC64 relocations defined by the ABIs */
++#define R_PPC64_NONE		R_PPC_NONE
++#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
++#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
++#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
++#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
++#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
++#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
++#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
++#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
++#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
++#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
++#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
++#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
++#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
++#define R_PPC64_GOT16		R_PPC_GOT16
++#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
++#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
++#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
++
++#define R_PPC64_COPY		R_PPC_COPY
++#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
++#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
++#define R_PPC64_RELATIVE	R_PPC_RELATIVE
++
++#define R_PPC64_UADDR32		R_PPC_UADDR32
++#define R_PPC64_UADDR16		R_PPC_UADDR16
++#define R_PPC64_REL32		R_PPC_REL32
++#define R_PPC64_PLT32		R_PPC_PLT32
++#define R_PPC64_PLTREL32	R_PPC_PLTREL32
++#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
++#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
++#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
++
++#define R_PPC64_SECTOFF		R_PPC_SECTOFF
++#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
++#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
++#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
++#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
++#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
++#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
++#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
++#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
++#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
++#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
++#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
++#define R_PPC64_PLT64		45 /* doubleword64 L + A */
++#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
++#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
++#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
++#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
++#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
++#define R_PPC64_TOC		51 /* doubleword64 .TOC */
++#define R_PPC64_PLTGOT16	52 /* half16* M + A */
++#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
++#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
++#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
++
++#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
++#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
++#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
++#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
++#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
++#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
++#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
++#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
++#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
++#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
++#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
++
++/* PowerPC64 relocations defined for the TLS access ABI.  */
++#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
++#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
++#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
++#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
++#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
++#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
++#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
++#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
++#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
++#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
++#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC64_JMP_IREL	247
++#define R_PPC64_IRELATIVE	248
++#define R_PPC64_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC64_REL16_LO	250	/* half16   (sym+add-.)@l */
++#define R_PPC64_REL16_HI	251	/* half16   (sym+add-.)@h */
++#define R_PPC64_REL16_HA	252	/* half16   (sym+add-.)@ha */
++
++/* PowerPC64 specific values for the Dyn d_tag field.  */
++#define DT_PPC64_GLINK  (DT_LOPROC + 0)
++#define DT_PPC64_OPD	(DT_LOPROC + 1)
++#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
++#define DT_PPC64_NUM    3
++
++
++/* ARM specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_ARM_RELEXEC		0x01
++#define EF_ARM_HASENTRY		0x02
++#define EF_ARM_INTERWORK	0x04
++#define EF_ARM_APCS_26		0x08
++#define EF_ARM_APCS_FLOAT	0x10
++#define EF_ARM_PIC		0x20
++#define EF_ARM_ALIGN8		0x40 /* 8-bit structure alignment is in use */
++#define EF_ARM_NEW_ABI		0x80
++#define EF_ARM_OLD_ABI		0x100
++#define EF_ARM_SOFT_FLOAT	0x200
++#define EF_ARM_VFP_FLOAT	0x400
++#define EF_ARM_MAVERICK_FLOAT	0x800
++
++
++/* Other constants defined in the ARM ELF spec. version B-01.  */
++/* NB. These conflict with values defined above.  */
++#define EF_ARM_SYMSARESORTED	0x04
++#define EF_ARM_DYNSYMSUSESEGIDX	0x08
++#define EF_ARM_MAPSYMSFIRST	0x10
++#define EF_ARM_EABIMASK		0XFF000000
++
++/* Constants defined in AAELF.  */
++#define EF_ARM_BE8	    0x00800000
++#define EF_ARM_LE8	    0x00400000
++
++#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK)
++#define EF_ARM_EABI_UNKNOWN	0x00000000
++#define EF_ARM_EABI_VER1	0x01000000
++#define EF_ARM_EABI_VER2	0x02000000
++#define EF_ARM_EABI_VER3	0x03000000
++#define EF_ARM_EABI_VER4	0x04000000
++#define EF_ARM_EABI_VER5	0x05000000
++
++/* Additional symbol types for Thumb.  */
++#define STT_ARM_TFUNC		STT_LOPROC /* A Thumb function.  */
++#define STT_ARM_16BIT		STT_HIPROC /* A Thumb label.  */
++
++/* ARM-specific values for sh_flags */
++#define SHF_ARM_ENTRYSECT	0x10000000 /* Section contains an entry point */
++#define SHF_ARM_COMDEF		0x80000000 /* Section may be multiply defined
++					      in the input to a link step.  */
++
++/* ARM-specific program header flags */
++#define PF_ARM_SB		0x10000000 /* Segment contains the location
++					      addressed by the static base. */
++#define PF_ARM_PI		0x20000000 /* Position-independent segment.  */
++#define PF_ARM_ABS		0x40000000 /* Absolute segment.  */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
++#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
++#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
++
++
++/* ARM relocs.  */
++
++#define R_ARM_NONE		0	/* No reloc */
++#define R_ARM_PC24		1	/* PC relative 26 bit branch */
++#define R_ARM_ABS32		2	/* Direct 32 bit  */
++#define R_ARM_REL32		3	/* PC relative 32 bit */
++#define R_ARM_PC13		4
++#define R_ARM_ABS16		5	/* Direct 16 bit */
++#define R_ARM_ABS12		6	/* Direct 12 bit */
++#define R_ARM_THM_ABS5		7
++#define R_ARM_ABS8		8	/* Direct 8 bit */
++#define R_ARM_SBREL32		9
++#define R_ARM_THM_PC22		10
++#define R_ARM_THM_PC8		11
++#define R_ARM_AMP_VCALL9	12
++#define R_ARM_SWI24		13	/* Obsolete static relocation.  */
++#define R_ARM_TLS_DESC		13      /* Dynamic relocation.  */
++#define R_ARM_THM_SWI8		14
++#define R_ARM_XPC25		15
++#define R_ARM_THM_XPC22		16
++#define R_ARM_TLS_DTPMOD32	17	/* ID of module containing symbol */
++#define R_ARM_TLS_DTPOFF32	18	/* Offset in TLS block */
++#define R_ARM_TLS_TPOFF32	19	/* Offset in static TLS block */
++#define R_ARM_COPY		20	/* Copy symbol at runtime */
++#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
++#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
++#define R_ARM_RELATIVE		23	/* Adjust by program base */
++#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
++#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
++#define R_ARM_GOT32		26	/* 32 bit GOT entry */
++#define R_ARM_PLT32		27	/* 32 bit PLT address */
++#define R_ARM_ALU_PCREL_7_0	32
++#define R_ARM_ALU_PCREL_15_8	33
++#define R_ARM_ALU_PCREL_23_15	34
++#define R_ARM_LDR_SBREL_11_0	35
++#define R_ARM_ALU_SBREL_19_12	36
++#define R_ARM_ALU_SBREL_27_20	37
++#define R_ARM_TLS_GOTDESC	90
++#define R_ARM_TLS_CALL		91
++#define R_ARM_TLS_DESCSEQ	92
++#define R_ARM_THM_TLS_CALL	93
++#define R_ARM_GNU_VTENTRY	100
++#define R_ARM_GNU_VTINHERIT	101
++#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
++#define R_ARM_THM_PC9		103	/* thumb conditional branch */
++#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
++					   thread local data */
++#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
++					   thread local data */
++#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
++					   block */
++#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
++					   static TLS block offset */
++#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
++					   TLS block */
++#define	R_ARM_THM_TLS_DESCSEQ	129
++#define R_ARM_IRELATIVE		160
++#define R_ARM_RXPC25		249
++#define R_ARM_RSBREL32		250
++#define R_ARM_THM_RPC22		251
++#define R_ARM_RREL32		252
++#define R_ARM_RABS22		253
++#define R_ARM_RPC24		254
++#define R_ARM_RBASE		255
++/* Keep this the last entry.  */
++#define R_ARM_NUM		256
++
++/* IA-64 specific declarations.  */
++
++/* Processor specific flags for the Ehdr e_flags field.  */
++#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
++#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
++#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
++#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
++#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
++#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
++#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
++
++/* Processor specific flags for the Phdr p_flags field.  */
++#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
++#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
++
++/* Processor specific flags for the Shdr sh_flags field.  */
++#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
++#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Dyn d_tag field.  */
++#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
++#define DT_IA_64_NUM		1
++
++/* IA-64 relocations.  */
++#define R_IA64_NONE		0x00	/* none */
++#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
++#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
++#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
++#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
++#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
++#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
++#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
++#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
++#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
++#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
++#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
++#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
++#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
++#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
++#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
++#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
++#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
++#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
++#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
++#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
++#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
++#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
++#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
++#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
++#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
++#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
++#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
++#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
++#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
++#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
++#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
++#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
++#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
++#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
++#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
++#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
++#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
++#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
++#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
++#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
++#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
++#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
++#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
++#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
++#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
++#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
++#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
++#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
++#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
++#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
++#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
++#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
++#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
++#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
++#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
++#define R_IA64_COPY		0x84	/* copy relocation */
++#define R_IA64_SUB		0x85	/* Addend and symbol difference */
++#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
++#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
++#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
++#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
++#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
++#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
++#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
++#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
++#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
++#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
++#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
++#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
++#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
++#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
++#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
++#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
++
++/* SH specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_SH_MACH_MASK		0x1f
++#define EF_SH_UNKNOWN		0x0
++#define EF_SH1			0x1
++#define EF_SH2			0x2
++#define EF_SH3			0x3
++#define EF_SH_DSP		0x4
++#define EF_SH3_DSP		0x5
++#define EF_SH4AL_DSP		0x6
++#define EF_SH3E			0x8
++#define EF_SH4			0x9
++#define EF_SH2E			0xb
++#define EF_SH4A			0xc
++#define EF_SH2A			0xd
++#define EF_SH4_NOFPU		0x10
++#define EF_SH4A_NOFPU		0x11
++#define EF_SH4_NOMMU_NOFPU	0x12
++#define EF_SH2A_NOFPU		0x13
++#define EF_SH3_NOMMU		0x14
++#define EF_SH2A_SH4_NOFPU	0x15
++#define EF_SH2A_SH3_NOFPU	0x16
++#define EF_SH2A_SH4		0x17
++#define EF_SH2A_SH3E		0x18
++
++/* SH relocs.  */
++#define	R_SH_NONE		0
++#define	R_SH_DIR32		1
++#define	R_SH_REL32		2
++#define	R_SH_DIR8WPN		3
++#define	R_SH_IND12W		4
++#define	R_SH_DIR8WPL		5
++#define	R_SH_DIR8WPZ		6
++#define	R_SH_DIR8BP		7
++#define	R_SH_DIR8W		8
++#define	R_SH_DIR8L		9
++#define	R_SH_SWITCH16		25
++#define	R_SH_SWITCH32		26
++#define	R_SH_USES		27
++#define	R_SH_COUNT		28
++#define	R_SH_ALIGN		29
++#define	R_SH_CODE		30
++#define	R_SH_DATA		31
++#define	R_SH_LABEL		32
++#define	R_SH_SWITCH8		33
++#define	R_SH_GNU_VTINHERIT	34
++#define	R_SH_GNU_VTENTRY	35
++#define	R_SH_TLS_GD_32		144
++#define	R_SH_TLS_LD_32		145
++#define	R_SH_TLS_LDO_32		146
++#define	R_SH_TLS_IE_32		147
++#define	R_SH_TLS_LE_32		148
++#define	R_SH_TLS_DTPMOD32	149
++#define	R_SH_TLS_DTPOFF32	150
++#define	R_SH_TLS_TPOFF32	151
++#define	R_SH_GOT32		160
++#define	R_SH_PLT32		161
++#define	R_SH_COPY		162
++#define	R_SH_GLOB_DAT		163
++#define	R_SH_JMP_SLOT		164
++#define	R_SH_RELATIVE		165
++#define	R_SH_GOTOFF		166
++#define	R_SH_GOTPC		167
++/* Keep this the last entry.  */
++#define	R_SH_NUM		256
++
++/* S/390 specific definitions.  */
++
++/* Valid values for the e_flags field.  */
++
++#define EF_S390_HIGH_GPRS    0x00000001  /* High GPRs kernel facility needed.  */
++
++/* Additional s390 relocs */
++
++#define R_390_NONE		0	/* No reloc.  */
++#define R_390_8			1	/* Direct 8 bit.  */
++#define R_390_12		2	/* Direct 12 bit.  */
++#define R_390_16		3	/* Direct 16 bit.  */
++#define R_390_32		4	/* Direct 32 bit.  */
++#define R_390_PC32		5	/* PC relative 32 bit.	*/
++#define R_390_GOT12		6	/* 12 bit GOT offset.  */
++#define R_390_GOT32		7	/* 32 bit GOT offset.  */
++#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
++#define R_390_COPY		9	/* Copy symbol at runtime.  */
++#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
++#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
++#define R_390_RELATIVE		12	/* Adjust by program base.  */
++#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
++#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
++#define R_390_GOT16		15	/* 16 bit GOT offset.  */
++#define R_390_PC16		16	/* PC relative 16 bit.	*/
++#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
++#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
++#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
++#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
++#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
++#define R_390_64		22	/* Direct 64 bit.  */
++#define R_390_PC64		23	/* PC relative 64 bit.	*/
++#define R_390_GOT64		24	/* 64 bit GOT offset.  */
++#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
++#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
++#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
++#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
++#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
++#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
++#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
++#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
++#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
++#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
++#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
++#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
++#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
++#define R_390_TLS_GDCALL	38	/* Tag for function call in general
++					   dynamic TLS code. */
++#define R_390_TLS_LDCALL	39	/* Tag for function call in local
++					   dynamic TLS code. */
++#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
++					   thread local data.  */
++#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
++					  thread local data.  */
++#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
++					   block offset. */
++#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
++#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
++#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
++					   block.  */
++#define R_390_20		57	/* Direct 20 bit.  */
++#define R_390_GOT20		58	/* 20 bit GOT offset.  */
++#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
++#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
++/* Keep this the last entry.  */
++#define R_390_NUM		62
++
++
++/* CRIS relocations.  */
++#define R_CRIS_NONE		0
++#define R_CRIS_8		1
++#define R_CRIS_16		2
++#define R_CRIS_32		3
++#define R_CRIS_8_PCREL		4
++#define R_CRIS_16_PCREL		5
++#define R_CRIS_32_PCREL		6
++#define R_CRIS_GNU_VTINHERIT	7
++#define R_CRIS_GNU_VTENTRY	8
++#define R_CRIS_COPY		9
++#define R_CRIS_GLOB_DAT		10
++#define R_CRIS_JUMP_SLOT	11
++#define R_CRIS_RELATIVE		12
++#define R_CRIS_16_GOT		13
++#define R_CRIS_32_GOT		14
++#define R_CRIS_16_GOTPLT	15
++#define R_CRIS_32_GOTPLT	16
++#define R_CRIS_32_GOTREL	17
++#define R_CRIS_32_PLT_GOTREL	18
++#define R_CRIS_32_PLT_PCREL	19
++
++#define R_CRIS_NUM		20
++
++
++/* AMD x86-64 relocations.  */
++#define R_X86_64_NONE		0	/* No reloc */
++#define R_X86_64_64		1	/* Direct 64 bit  */
++#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
++#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
++#define R_X86_64_PLT32		4	/* 32 bit PLT address */
++#define R_X86_64_COPY		5	/* Copy symbol at runtime */
++#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
++#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
++#define R_X86_64_RELATIVE	8	/* Adjust by program base */
++#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
++					   offset to GOT */
++#define R_X86_64_32		10	/* Direct 32 bit zero extended */
++#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
++#define R_X86_64_16		12	/* Direct 16 bit zero extended */
++#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
++#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
++#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
++#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
++#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
++#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
++#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
++					   to two GOT entries for GD symbol */
++#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
++					   to two GOT entries for LD symbol */
++#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
++#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
++					   to GOT entry for IE symbol */
++#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
++#define R_X86_64_PC64		24	/* PC relative 64 bit */
++#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
++#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
++					   offset to GOT */
++#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
++#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
++					   to GOT entry */
++#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
++#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
++#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
++					   to PLT entry */
++#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
++#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
++#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
++#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
++					   descriptor.  */
++#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
++#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
++#define R_X86_64_RELATIVE64	38	/* 64-bit adjust by program base */
++
++#define R_X86_64_NUM		39
++
++
++/* AM33 relocations.  */
++#define R_MN10300_NONE		0	/* No reloc.  */
++#define R_MN10300_32		1	/* Direct 32 bit.  */
++#define R_MN10300_16		2	/* Direct 16 bit.  */
++#define R_MN10300_8		3	/* Direct 8 bit.  */
++#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
++#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
++#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
++#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
++#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
++#define R_MN10300_24		9	/* Direct 24 bit.  */
++#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
++#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
++#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
++#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
++#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
++#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
++#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
++#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
++#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
++#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
++#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
++#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
++
++#define R_MN10300_NUM		24
++
++
++/* M32R relocs.  */
++#define R_M32R_NONE		0	/* No reloc. */
++#define R_M32R_16		1	/* Direct 16 bit. */
++#define R_M32R_32		2	/* Direct 32 bit. */
++#define R_M32R_24		3	/* Direct 24 bit. */
++#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
++#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
++#define R_M32R_LO16		9	/* Low 16 bit. */
++#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
++#define R_M32R_GNU_VTINHERIT	11
++#define R_M32R_GNU_VTENTRY	12
++/* M32R relocs use SHT_RELA.  */
++#define R_M32R_16_RELA		33	/* Direct 16 bit. */
++#define R_M32R_32_RELA		34	/* Direct 32 bit. */
++#define R_M32R_24_RELA		35	/* Direct 24 bit. */
++#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
++#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
++#define R_M32R_LO16_RELA	41	/* Low 16 bit */
++#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
++#define R_M32R_RELA_GNU_VTINHERIT	43
++#define R_M32R_RELA_GNU_VTENTRY	44
++#define R_M32R_REL32		45	/* PC relative 32 bit.  */
++
++#define R_M32R_GOT24		48	/* 24 bit GOT entry */
++#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
++#define R_M32R_COPY		50	/* Copy symbol at runtime */
++#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
++#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
++#define R_M32R_RELATIVE		53	/* Adjust by program base */
++#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
++#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
++#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
++					   low */
++#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
++					   low */
++#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
++#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
++					   GOT with unsigned low */
++#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
++					   GOT with signed low */
++#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
++					   GOT */
++#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
++					   with unsigned low */
++#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
++					   with signed low */
++#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
++#define R_M32R_NUM		256	/* Keep this the last entry. */
++
++
++/* TILEPro relocations.  */
++#define R_TILEPRO_NONE		0	/* No reloc */
++#define R_TILEPRO_32		1	/* Direct 32 bit */
++#define R_TILEPRO_16		2	/* Direct 16 bit */
++#define R_TILEPRO_8		3	/* Direct 8 bit */
++#define R_TILEPRO_32_PCREL	4	/* PC relative 32 bit */
++#define R_TILEPRO_16_PCREL	5	/* PC relative 16 bit */
++#define R_TILEPRO_8_PCREL	6	/* PC relative 8 bit */
++#define R_TILEPRO_LO16		7	/* Low 16 bit */
++#define R_TILEPRO_HI16		8	/* High 16 bit */
++#define R_TILEPRO_HA16		9	/* High 16 bit, adjusted */
++#define R_TILEPRO_COPY		10	/* Copy relocation */
++#define R_TILEPRO_GLOB_DAT	11	/* Create GOT entry */
++#define R_TILEPRO_JMP_SLOT	12	/* Create PLT entry */
++#define R_TILEPRO_RELATIVE	13	/* Adjust by program base */
++#define R_TILEPRO_BROFF_X1	14	/* X1 pipe branch offset */
++#define R_TILEPRO_JOFFLONG_X1	15	/* X1 pipe jump offset */
++#define R_TILEPRO_JOFFLONG_X1_PLT 16	/* X1 pipe jump offset to PLT */
++#define R_TILEPRO_IMM8_X0	17	/* X0 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y0	18	/* Y0 pipe 8-bit */
++#define R_TILEPRO_IMM8_X1	19	/* X1 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y1	20	/* Y1 pipe 8-bit */
++#define R_TILEPRO_MT_IMM15_X1	21	/* X1 pipe mtspr */
++#define R_TILEPRO_MF_IMM15_X1	22	/* X1 pipe mfspr */
++#define R_TILEPRO_IMM16_X0	23	/* X0 pipe 16-bit */
++#define R_TILEPRO_IMM16_X1	24	/* X1 pipe 16-bit */
++#define R_TILEPRO_IMM16_X0_LO	25	/* X0 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X1_LO	26	/* X1 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X0_HI	27	/* X0 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X1_HI	28	/* X1 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X0_HA	29	/* X0 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X1_HA	30	/* X1 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X0_PCREL 31	/* X0 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X1_PCREL 32	/* X1 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X0_LO_PCREL 33	/* X0 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X1_LO_PCREL 34	/* X1 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X0_HI_PCREL 35	/* X0 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X1_HI_PCREL 36	/* X1 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X0_HA_PCREL 37	/* X0 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X1_HA_PCREL 38	/* X1 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X0_GOT	39	/* X0 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT	40	/* X1 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_LO 41	/* X0 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_LO 42	/* X1 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HI 43	/* X0 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HI 44	/* X1 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HA 45	/* X0 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HA 46	/* X1 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_MMSTART_X0	47	/* X0 pipe mm "start" */
++#define R_TILEPRO_MMEND_X0	48	/* X0 pipe mm "end" */
++#define R_TILEPRO_MMSTART_X1	49	/* X1 pipe mm "start" */
++#define R_TILEPRO_MMEND_X1	50	/* X1 pipe mm "end" */
++#define R_TILEPRO_SHAMT_X0	51	/* X0 pipe shift amount */
++#define R_TILEPRO_SHAMT_X1	52	/* X1 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y0	53	/* Y0 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y1	54	/* Y1 pipe shift amount */
++#define R_TILEPRO_DEST_IMM8_X1	55	/* X1 pipe destination 8-bit */
++/* Relocs 56-59 are currently not defined.  */
++#define R_TILEPRO_TLS_GD_CALL	60	/* "jal" for TLS GD */
++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61	/* X0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62	/* X1 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEPRO_TLS_IE_LOAD	65	/* "lw_tls" for TLS IE */
++#define R_TILEPRO_IMM16_X0_TLS_GD 66	/* X0 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD 67	/* X1 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68	/* X0 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69	/* X1 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70	/* X0 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71	/* X1 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72	/* X0 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73	/* X1 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE 74	/* X0 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE 75	/* X1 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76	/* X0 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77	/* X1 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78	/* X0 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79	/* X1 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80	/* X0 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81	/* X1 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_TLS_DTPMOD32	82	/* ID of module containing symbol */
++#define R_TILEPRO_TLS_DTPOFF32	83	/* Offset in TLS block */
++#define R_TILEPRO_TLS_TPOFF32	84	/* Offset in static TLS block */
++#define R_TILEPRO_IMM16_X0_TLS_LE 85	/* X0 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE 86	/* X1 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87	/* X0 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88	/* X1 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89	/* X0 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90	/* X1 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91	/* X0 pipe ha() 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92	/* X1 pipe ha() 16-bit TLS LE offset */
++
++#define R_TILEPRO_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEPRO_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEPRO_NUM		130
++
++
++/* TILE-Gx relocations.  */
++#define R_TILEGX_NONE		0	/* No reloc */
++#define R_TILEGX_64		1	/* Direct 64 bit */
++#define R_TILEGX_32		2	/* Direct 32 bit */
++#define R_TILEGX_16		3	/* Direct 16 bit */
++#define R_TILEGX_8		4	/* Direct 8 bit */
++#define R_TILEGX_64_PCREL	5	/* PC relative 64 bit */
++#define R_TILEGX_32_PCREL	6	/* PC relative 32 bit */
++#define R_TILEGX_16_PCREL	7	/* PC relative 16 bit */
++#define R_TILEGX_8_PCREL	8	/* PC relative 8 bit */
++#define R_TILEGX_HW0		9	/* hword 0 16-bit */
++#define R_TILEGX_HW1		10	/* hword 1 16-bit */
++#define R_TILEGX_HW2		11	/* hword 2 16-bit */
++#define R_TILEGX_HW3		12	/* hword 3 16-bit */
++#define R_TILEGX_HW0_LAST	13	/* last hword 0 16-bit */
++#define R_TILEGX_HW1_LAST	14	/* last hword 1 16-bit */
++#define R_TILEGX_HW2_LAST	15	/* last hword 2 16-bit */
++#define R_TILEGX_COPY		16	/* Copy relocation */
++#define R_TILEGX_GLOB_DAT	17	/* Create GOT entry */
++#define R_TILEGX_JMP_SLOT	18	/* Create PLT entry */
++#define R_TILEGX_RELATIVE	19	/* Adjust by program base */
++#define R_TILEGX_BROFF_X1	20	/* X1 pipe branch offset */
++#define R_TILEGX_JUMPOFF_X1	21	/* X1 pipe jump offset */
++#define R_TILEGX_JUMPOFF_X1_PLT	22	/* X1 pipe jump offset to PLT */
++#define R_TILEGX_IMM8_X0	23	/* X0 pipe 8-bit */
++#define R_TILEGX_IMM8_Y0	24	/* Y0 pipe 8-bit */
++#define R_TILEGX_IMM8_X1	25	/* X1 pipe 8-bit */
++#define R_TILEGX_IMM8_Y1	26	/* Y1 pipe 8-bit */
++#define R_TILEGX_DEST_IMM8_X1	27	/* X1 pipe destination 8-bit */
++#define R_TILEGX_MT_IMM14_X1	28	/* X1 pipe mtspr */
++#define R_TILEGX_MF_IMM14_X1	29	/* X1 pipe mfspr */
++#define R_TILEGX_MMSTART_X0	30	/* X0 pipe mm "start" */
++#define R_TILEGX_MMEND_X0	31	/* X0 pipe mm "end" */
++#define R_TILEGX_SHAMT_X0	32	/* X0 pipe shift amount */
++#define R_TILEGX_SHAMT_X1	33	/* X1 pipe shift amount */
++#define R_TILEGX_SHAMT_Y0	34	/* Y0 pipe shift amount */
++#define R_TILEGX_SHAMT_Y1	35	/* Y1 pipe shift amount */
++#define R_TILEGX_IMM16_X0_HW0	36	/* X0 pipe hword 0 */
++#define R_TILEGX_IMM16_X1_HW0	37	/* X1 pipe hword 0 */
++#define R_TILEGX_IMM16_X0_HW1	38	/* X0 pipe hword 1 */
++#define R_TILEGX_IMM16_X1_HW1	39	/* X1 pipe hword 1 */
++#define R_TILEGX_IMM16_X0_HW2	40	/* X0 pipe hword 2 */
++#define R_TILEGX_IMM16_X1_HW2	41	/* X1 pipe hword 2 */
++#define R_TILEGX_IMM16_X0_HW3	42	/* X0 pipe hword 3 */
++#define R_TILEGX_IMM16_X1_HW3	43	/* X1 pipe hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST 44	/* X0 pipe last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST 45	/* X1 pipe last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST 46	/* X0 pipe last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST 47	/* X1 pipe last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST 48	/* X0 pipe last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST 49	/* X1 pipe last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_PCREL 50	/* X0 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_PCREL 51	/* X1 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_PCREL 52	/* X0 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_PCREL 53	/* X1 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_PCREL 54	/* X0 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_PCREL 55	/* X1 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X0_HW3_PCREL 56	/* X0 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X1_HW3_PCREL 57	/* X1 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_GOT 64	/* X0 pipe hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_GOT 65	/* X1 pipe hword 0 GOT offset */
++/* Relocs 66-71 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
++/* Relocs 76-77 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78	/* X0 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79	/* X1 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80	/* X0 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81	/* X1 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
++/* Relocs 90-91 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92	/* X0 pipe hword 0 TLS IE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93	/* X1 pipe hword 0 TLS IE offset */
++/* Relocs 94-99 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
++/* Relocs 104-105 are currently not defined.  */
++#define R_TILEGX_TLS_DTPMOD64	106	/* 64-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF64	107	/* 64-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF64	108	/* 64-bit offset in static TLS block */
++#define R_TILEGX_TLS_DTPMOD32	109	/* 32-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF32	110	/* 32-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF32	111	/* 32-bit offset in static TLS block */
++#define R_TILEGX_TLS_GD_CALL	112	/* "jal" for TLS GD */
++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113	/* X0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114	/* X1 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEGX_TLS_IE_LOAD	117	/* "ld_tls" for TLS IE */
++#define R_TILEGX_IMM8_X0_TLS_ADD 118	/* X0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_X1_TLS_ADD 119	/* X1 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y0_TLS_ADD 120	/* Y0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y1_TLS_ADD 121	/* Y1 pipe "addi" for TLS GD/IE */
++
++#define R_TILEGX_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEGX_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEGX_NUM		130
++
++#endif	/* elf.h */
diff --git a/target/linux/generic/patches-4.1/212-byteshift_portability.patch b/target/linux/generic/patches-4.1/212-byteshift_portability.patch
new file mode 100644
index 0000000000..0f23ba9be9
--- /dev/null
+++ b/target/linux/generic/patches-4.1/212-byteshift_portability.patch
@@ -0,0 +1,51 @@
+--- a/tools/include/tools/be_byteshift.h
++++ b/tools/include/tools/be_byteshift.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_BE_BYTESHIFT_H
+ #define _TOOLS_BE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_be16(const uint8_t *p)
+--- a/tools/include/tools/le_byteshift.h
++++ b/tools/include/tools/le_byteshift.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_LE_BYTESHIFT_H
+ #define _TOOLS_LE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_le16(const uint8_t *p)
+--- /dev/null
++++ b/tools/include/tools/linux_types.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_TYPES_H
++#define __LINUX_TYPES_H
++
++#include <stdint.h>
++
++typedef uint8_t __u8;
++typedef uint8_t __be8;
++typedef uint8_t __le8;
++
++typedef uint16_t __u16;
++typedef uint16_t __be16;
++typedef uint16_t __le16;
++
++typedef uint32_t __u32;
++typedef uint32_t __be32;
++typedef uint32_t __le32;
++
++typedef uint64_t __u64;
++typedef uint64_t __be64;
++typedef uint64_t __le64;
++
++#endif
diff --git a/target/linux/generic/patches-4.1/214-spidev_h_portability.patch b/target/linux/generic/patches-4.1/214-spidev_h_portability.patch
new file mode 100644
index 0000000000..dbee090547
--- /dev/null
+++ b/target/linux/generic/patches-4.1/214-spidev_h_portability.patch
@@ -0,0 +1,11 @@
+--- a/include/uapi/linux/spi/spidev.h
++++ b/include/uapi/linux/spi/spidev.h
+@@ -111,7 +111,7 @@ struct spi_ioc_transfer {
+ 
+ /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+ #define SPI_MSGSIZE(N) \
+-	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
++	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
+ 		? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+ #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+ 
diff --git a/target/linux/generic/patches-4.1/220-gc_sections.patch b/target/linux/generic/patches-4.1/220-gc_sections.patch
new file mode 100644
index 0000000000..d18fabafbc
--- /dev/null
+++ b/target/linux/generic/patches-4.1/220-gc_sections.patch
@@ -0,0 +1,536 @@
+From: Felix Fietkau <nbd@nbd.name>
+
+use -ffunction-sections, -fdata-sections and --gc-sections
+
+In combination with kernel symbol export stripping this significantly reduces
+the kernel image size. Used on both ARM and MIPS architectures.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ #
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
+ cflags-y			+= -msoft-float
+-LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
++LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
+ 
++ifndef CONFIG_FUNCTION_TRACER
++KBUILD_CFLAGS_KERNEL		+= -ffunction-sections -fdata-sections
++endif
++
+ #
+ # pass -msoft-float to GAS if it supports it.  However on newer binutils
+ # (specifically newer than 2.24.51.20140728) we then also need to explicitly
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -67,7 +67,7 @@ SECTIONS
+ 	/* Exception table for data bus errors */
+ 	__dbe_table : {
+ 		__start___dbe_table = .;
+-		*(__dbe_table)
++		KEEP(*(__dbe_table))
+ 		__stop___dbe_table = .;
+ 	}
+ 
+@@ -112,7 +112,7 @@ SECTIONS
+ 	. = ALIGN(4);
+ 	.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
+ 		__mips_machines_start = .;
+-		*(.mips.machines.init)
++		KEEP(*(.mips.machines.init))
+ 		__mips_machines_end = .;
+ 	}
+ 
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -89,7 +89,7 @@
+ #ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ #define MCOUNT_REC()	. = ALIGN(8);				\
+ 			VMLINUX_SYMBOL(__start_mcount_loc) = .; \
+-			*(__mcount_loc)				\
++			KEEP(*(__mcount_loc))			\
+ 			VMLINUX_SYMBOL(__stop_mcount_loc) = .;
+ #else
+ #define MCOUNT_REC()
+@@ -97,7 +97,7 @@
+ 
+ #ifdef CONFIG_TRACE_BRANCH_PROFILING
+ #define LIKELY_PROFILE()	VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
+-				*(_ftrace_annotated_branch)			      \
++				KEEP(*(_ftrace_annotated_branch))		      \
+ 				VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .;
+ #else
+ #define LIKELY_PROFILE()
+@@ -105,7 +105,7 @@
+ 
+ #ifdef CONFIG_PROFILE_ALL_BRANCHES
+ #define BRANCH_PROFILE()	VMLINUX_SYMBOL(__start_branch_profile) = .;   \
+-				*(_ftrace_branch)			      \
++				KEEP(*(_ftrace_branch))			      \
+ 				VMLINUX_SYMBOL(__stop_branch_profile) = .;
+ #else
+ #define BRANCH_PROFILE()
+@@ -114,7 +114,7 @@
+ #ifdef CONFIG_KPROBES
+ #define KPROBE_BLACKLIST()	. = ALIGN(8);				      \
+ 				VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
+-				*(_kprobe_blacklist)			      \
++				KEEP(*(_kprobe_blacklist))		      \
+ 				VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
+ #else
+ #define KPROBE_BLACKLIST()
+@@ -123,10 +123,10 @@
+ #ifdef CONFIG_EVENT_TRACING
+ #define FTRACE_EVENTS()	. = ALIGN(8);					\
+ 			VMLINUX_SYMBOL(__start_ftrace_events) = .;	\
+-			*(_ftrace_events)				\
++			KEEP(*(_ftrace_events))				\
+ 			VMLINUX_SYMBOL(__stop_ftrace_events) = .;	\
+ 			VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .;	\
+-			*(_ftrace_enum_map)				\
++			KEEP(*(_ftrace_enum_map))			\
+ 			VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
+ #else
+ #define FTRACE_EVENTS()
+@@ -134,7 +134,7 @@
+ 
+ #ifdef CONFIG_TRACING
+ #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .;      \
+-			 *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
++			 KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \
+ 			 VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
+ #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .;	\
+ 			 *(__tracepoint_str) /* Trace_printk fmt' pointer */ \
+@@ -147,7 +147,7 @@
+ #ifdef CONFIG_FTRACE_SYSCALLS
+ #define TRACE_SYSCALLS() . = ALIGN(8);					\
+ 			 VMLINUX_SYMBOL(__start_syscalls_metadata) = .;	\
+-			 *(__syscalls_metadata)				\
++			 KEEP(*(__syscalls_metadata))			\
+ 			 VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
+ #else
+ #define TRACE_SYSCALLS()
+@@ -169,8 +169,8 @@
+ #define _OF_TABLE_1(name)						\
+ 	. = ALIGN(8);							\
+ 	VMLINUX_SYMBOL(__##name##_of_table) = .;			\
+-	*(__##name##_of_table)						\
+-	*(__##name##_of_table_end)
++	KEEP(*(__##name##_of_table))					\
++	KEEP(*(__##name##_of_table_end))
+ 
+ #define CLKSRC_OF_TABLES()	OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
+ #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
+@@ -184,7 +184,7 @@
+ #define KERNEL_DTB()							\
+ 	STRUCT_ALIGN();							\
+ 	VMLINUX_SYMBOL(__dtb_start) = .;				\
+-	*(.dtb.init.rodata)						\
++	KEEP(*(.dtb.init.rodata))					\
+ 	VMLINUX_SYMBOL(__dtb_end) = .;
+ 
+ /* .data section */
+@@ -200,16 +200,17 @@
+ 	/* implement dynamic printk debug */				\
+ 	. = ALIGN(8);                                                   \
+ 	VMLINUX_SYMBOL(__start___jump_table) = .;                       \
+-	*(__jump_table)                                                 \
++	KEEP(*(__jump_table))                                           \
+ 	VMLINUX_SYMBOL(__stop___jump_table) = .;                        \
+ 	. = ALIGN(8);							\
+ 	VMLINUX_SYMBOL(__start___verbose) = .;                          \
+-	*(__verbose)                                                    \
++	KEEP(*(__verbose))                                              \
+ 	VMLINUX_SYMBOL(__stop___verbose) = .;				\
+ 	LIKELY_PROFILE()		       				\
+ 	BRANCH_PROFILE()						\
+ 	TRACE_PRINTKS()							\
+-	TRACEPOINT_STR()
++	TRACEPOINT_STR()                                                \
++	*(.data.[a-zA-Z_]*)
+ 
+ /*
+  * Data section helpers
+@@ -263,35 +264,35 @@
+ 	/* PCI quirks */						\
+ 	.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_early) = .;		\
+-		*(.pci_fixup_early)					\
++		KEEP(*(.pci_fixup_early))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_early) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_header) = .;		\
+-		*(.pci_fixup_header)					\
++		KEEP(*(.pci_fixup_header))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_header) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_final) = .;		\
+-		*(.pci_fixup_final)					\
++		KEEP(*(.pci_fixup_final))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_final) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_enable) = .;		\
+-		*(.pci_fixup_enable)					\
++		KEEP(*(.pci_fixup_enable))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_resume) = .;		\
+-		*(.pci_fixup_resume)					\
++		KEEP(*(.pci_fixup_resume))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_resume) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .;	\
+-		*(.pci_fixup_resume_early)				\
++		KEEP(*(.pci_fixup_resume_early))			\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .;	\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .;		\
+-		*(.pci_fixup_suspend)					\
++		KEEP(*(.pci_fixup_suspend))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .;	\
+-		*(.pci_fixup_suspend_late)				\
++		KEEP(*(.pci_fixup_suspend_late))			\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .;	\
+ 	}								\
+ 									\
+ 	/* Built-in firmware blobs */					\
+ 	.builtin_fw        : AT(ADDR(.builtin_fw) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start_builtin_fw) = .;			\
+-		*(.builtin_fw)						\
++		KEEP(*(.builtin_fw))					\
+ 		VMLINUX_SYMBOL(__end_builtin_fw) = .;			\
+ 	}								\
+ 									\
+@@ -300,49 +301,49 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
+-		*(SORT(___ksymtab+*))					\
++		KEEP(*(SORT(___ksymtab+*)))				\
+ 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
+-		*(SORT(___ksymtab_gpl+*))				\
++		KEEP(*(SORT(___ksymtab_gpl+*)))				\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: Normal unused symbols */		\
+ 	__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_unused) = .;		\
+-		*(SORT(___ksymtab_unused+*))				\
++		KEEP(*(SORT(___ksymtab_unused+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;		\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only unused symbols */		\
+ 	__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;	\
+-		*(SORT(___ksymtab_unused_gpl+*))			\
++		KEEP(*(SORT(___ksymtab_unused_gpl+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-future-only symbols */		\
+ 	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
+-		*(SORT(___ksymtab_gpl_future+*))			\
++		KEEP(*(SORT(___ksymtab_gpl_future+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
+-		*(SORT(___kcrctab+*))					\
++		KEEP(*(SORT(___kcrctab+*)))				\
+ 		VMLINUX_SYMBOL(__stop___kcrctab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___kcrctab_gpl) = .;		\
+-		*(SORT(___kcrctab_gpl+*))				\
++		KEEP(*(SORT(___kcrctab_gpl+*)))				\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
+ 	}								\
+ 									\
+@@ -356,14 +357,14 @@
+ 	/* Kernel symbol table: GPL-only unused symbols */		\
+ 	__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;	\
+-		*(SORT(___kcrctab_unused_gpl+*))			\
++		KEEP(*(SORT(___kcrctab_unused_gpl+*)))			\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-future-only symbols */		\
+ 	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
+-		*(SORT(___kcrctab_gpl_future+*))			\
++		KEEP(*(SORT(___kcrctab_gpl_future+*)))			\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
+ 	}								\
+ 									\
+@@ -382,14 +383,14 @@
+ 	/* Built-in module parameters. */				\
+ 	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
+ 		VMLINUX_SYMBOL(__start___param) = .;			\
+-		*(__param)						\
++		KEEP(*(__param))					\
+ 		VMLINUX_SYMBOL(__stop___param) = .;			\
+ 	}								\
+ 									\
+ 	/* Built-in module versions. */					\
+ 	__modver : AT(ADDR(__modver) - LOAD_OFFSET) {			\
+ 		VMLINUX_SYMBOL(__start___modver) = .;			\
+-		*(__modver)						\
++		KEEP(*(__modver))					\
+ 		VMLINUX_SYMBOL(__stop___modver) = .;			\
+ 		. = ALIGN((align));					\
+ 		VMLINUX_SYMBOL(__end_rodata) = .;			\
+@@ -445,7 +446,7 @@
+ #define ENTRY_TEXT							\
+ 		ALIGN_FUNCTION();					\
+ 		VMLINUX_SYMBOL(__entry_text_start) = .;			\
+-		*(.entry.text)						\
++		KEEP(*(.entry.text))					\
+ 		VMLINUX_SYMBOL(__entry_text_end) = .;
+ 
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+@@ -473,7 +474,7 @@
+ 	. = ALIGN(align);						\
+ 	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ex_table) = .;			\
+-		*(__ex_table)						\
++		KEEP(*(__ex_table))						\
+ 		VMLINUX_SYMBOL(__stop___ex_table) = .;			\
+ 	}
+ 
+@@ -489,9 +490,9 @@
+ #ifdef CONFIG_CONSTRUCTORS
+ #define KERNEL_CTORS()	. = ALIGN(8);			   \
+ 			VMLINUX_SYMBOL(__ctors_start) = .; \
+-			*(.ctors)			   \
++			KEEP(*(.ctors))			   \
+ 			*(SORT(.init_array.*))		   \
+-			*(.init_array)			   \
++			KEEP(*(.init_array))		   \
+ 			VMLINUX_SYMBOL(__ctors_end) = .;
+ #else
+ #define KERNEL_CTORS()
+@@ -546,7 +547,7 @@
+ #define SBSS(sbss_align)						\
+ 	. = ALIGN(sbss_align);						\
+ 	.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {				\
+-		*(.sbss)						\
++		*(.sbss .sbss.*)					\
+ 		*(.scommon)						\
+ 	}
+ 
+@@ -564,7 +565,7 @@
+ 		BSS_FIRST_SECTIONS					\
+ 		*(.bss..page_aligned)					\
+ 		*(.dynbss)						\
+-		*(.bss)							\
++		*(.bss .bss.*)						\
+ 		*(COMMON)						\
+ 	}
+ 
+@@ -613,7 +614,7 @@
+ 	. = ALIGN(8);							\
+ 	__bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___bug_table) = .;		\
+-		*(__bug_table)						\
++		KEEP(*(__bug_table))					\
+ 		VMLINUX_SYMBOL(__stop___bug_table) = .;			\
+ 	}
+ #else
+@@ -625,7 +626,7 @@
+ 	. = ALIGN(4);							\
+ 	.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__tracedata_start) = .;			\
+-		*(.tracedata)						\
++		KEEP(*(.tracedata))					\
+ 		VMLINUX_SYMBOL(__tracedata_end) = .;			\
+ 	}
+ #else
+@@ -642,17 +643,17 @@
+ #define INIT_SETUP(initsetup_align)					\
+ 		. = ALIGN(initsetup_align);				\
+ 		VMLINUX_SYMBOL(__setup_start) = .;			\
+-		*(.init.setup)						\
++		KEEP(*(.init.setup))					\
+ 		VMLINUX_SYMBOL(__setup_end) = .;
+ 
+ #define INIT_CALLS_LEVEL(level)						\
+ 		VMLINUX_SYMBOL(__initcall##level##_start) = .;		\
+-		*(.initcall##level##.init)				\
+-		*(.initcall##level##s.init)				\
++		KEEP(*(.initcall##level##.init))			\
++		KEEP(*(.initcall##level##s.init))			\
+ 
+ #define INIT_CALLS							\
+ 		VMLINUX_SYMBOL(__initcall_start) = .;			\
+-		*(.initcallearly.init)					\
++		KEEP(*(.initcallearly.init))				\
+ 		INIT_CALLS_LEVEL(0)					\
+ 		INIT_CALLS_LEVEL(1)					\
+ 		INIT_CALLS_LEVEL(2)					\
+@@ -666,21 +667,21 @@
+ 
+ #define CON_INITCALL							\
+ 		VMLINUX_SYMBOL(__con_initcall_start) = .;		\
+-		*(.con_initcall.init)					\
++		KEEP(*(.con_initcall.init))				\
+ 		VMLINUX_SYMBOL(__con_initcall_end) = .;
+ 
+ #define SECURITY_INITCALL						\
+ 		VMLINUX_SYMBOL(__security_initcall_start) = .;		\
+-		*(.security_initcall.init)				\
++		KEEP(*(.security_initcall.init))			\
+ 		VMLINUX_SYMBOL(__security_initcall_end) = .;
+ 
+ #ifdef CONFIG_BLK_DEV_INITRD
+ #define INIT_RAM_FS							\
+ 	. = ALIGN(4);							\
+ 	VMLINUX_SYMBOL(__initramfs_start) = .;				\
+-	*(.init.ramfs)							\
++	KEEP(*(.init.ramfs))						\
+ 	. = ALIGN(8);							\
+-	*(.init.ramfs.info)
++	KEEP(*(.init.ramfs.info))
+ #else
+ #define INIT_RAM_FS
+ #endif
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -18,11 +18,16 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+ LDFLAGS_vmlinux	+= --be8
+ LDFLAGS_MODULE	+= --be8
+ endif
++LDFLAGS_vmlinux += --gc-sections
+ 
+ OBJCOPYFLAGS	:=-O binary -R .comment -S
+ GZFLAGS		:=-9
+ #KBUILD_CFLAGS	+=-pipe
+ 
++ifndef CONFIG_FUNCTION_TRACER
++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
++endif
++
+ # Never generate .eh_frame
+ KBUILD_CFLAGS	+= $(call cc-option,-fno-dwarf2-cfi-asm)
+ 
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -15,13 +15,13 @@
+ #define PROC_INFO							\
+ 	. = ALIGN(4);							\
+ 	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
+-	*(.proc.info.init)						\
++	KEEP(*(.proc.info.init))					\
+ 	VMLINUX_SYMBOL(__proc_info_end) = .;
+ 
+ #define IDMAP_TEXT							\
+ 	ALIGN_FUNCTION();						\
+ 	VMLINUX_SYMBOL(__idmap_text_start) = .;				\
+-	*(.idmap.text)							\
++	KEEP(*(.idmap.text))						\
+ 	VMLINUX_SYMBOL(__idmap_text_end) = .;				\
+ 	. = ALIGN(PAGE_SIZE);						\
+ 	VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;			\
+@@ -102,7 +102,7 @@ SECTIONS
+ 		_stext = .;		/* Text and read-only data	*/
+ 			IDMAP_TEXT
+ 			__exception_text_start = .;
+-			*(.exception.text)
++			KEEP(*(.exception.text))
+ 			__exception_text_end = .;
+ 			IRQENTRY_TEXT
+ 			TEXT_TEXT
+@@ -126,7 +126,7 @@ SECTIONS
+ 	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+ 		__start___ex_table = .;
+ #ifdef CONFIG_MMU
+-		*(__ex_table)
++		KEEP(*(__ex_table))
+ #endif
+ 		__stop___ex_table = .;
+ 	}
+@@ -138,12 +138,12 @@ SECTIONS
+ 	. = ALIGN(8);
+ 	.ARM.unwind_idx : {
+ 		__start_unwind_idx = .;
+-		*(.ARM.exidx*)
++		KEEP(*(.ARM.exidx*))
+ 		__stop_unwind_idx = .;
+ 	}
+ 	.ARM.unwind_tab : {
+ 		__start_unwind_tab = .;
+-		*(.ARM.extab*)
++		KEEP(*(.ARM.extab*))
+ 		__stop_unwind_tab = .;
+ 	}
+ #endif
+@@ -166,14 +166,14 @@ SECTIONS
+ 	 */
+ 	__vectors_start = .;
+ 	.vectors 0 : AT(__vectors_start) {
+-		*(.vectors)
++		KEEP(*(.vectors))
+ 	}
+ 	. = __vectors_start + SIZEOF(.vectors);
+ 	__vectors_end = .;
+ 
+ 	__stubs_start = .;
+ 	.stubs 0x1000 : AT(__stubs_start) {
+-		*(.stubs)
++		KEEP(*(.stubs))
+ 	}
+ 	. = __stubs_start + SIZEOF(.stubs);
+ 	__stubs_end = .;
+@@ -187,24 +187,24 @@ SECTIONS
+ 	}
+ 	.init.arch.info : {
+ 		__arch_info_begin = .;
+-		*(.arch.info.init)
++		KEEP(*(.arch.info.init))
+ 		__arch_info_end = .;
+ 	}
+ 	.init.tagtable : {
+ 		__tagtable_begin = .;
+-		*(.taglist.init)
++		KEEP(*(.taglist.init))
+ 		__tagtable_end = .;
+ 	}
+ #ifdef CONFIG_SMP_ON_UP
+ 	.init.smpalt : {
+ 		__smpalt_begin = .;
+-		*(.alt.smp.init)
++		KEEP(*(.alt.smp.init))
+ 		__smpalt_end = .;
+ 	}
+ #endif
+ 	.init.pv_table : {
+ 		__pv_table_begin = .;
+-		*(.pv_table)
++		KEEP(*(.pv_table))
+ 		__pv_table_end = .;
+ 	}
+ 	.init.data : {
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -107,6 +107,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+ endif
++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
+ 
+ ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj)
+ asflags-y := -DZIMAGE
diff --git a/target/linux/generic/patches-4.1/221-module_exports.patch b/target/linux/generic/patches-4.1/221-module_exports.patch
new file mode 100644
index 0000000000..38ea10a47f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/221-module_exports.patch
@@ -0,0 +1,88 @@
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -54,6 +54,16 @@
+ #define LOAD_OFFSET 0
+ #endif
+ 
++#ifndef SYMTAB_KEEP
++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
++#endif
++
++#ifndef SYMTAB_DISCARD
++#define SYMTAB_DISCARD
++#define SYMTAB_DISCARD_GPL
++#endif
++
+ #include <linux/export.h>
+ 
+ /* Align . to a 8 byte boundary equals to maximum function alignment. */
+@@ -301,14 +311,14 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
+-		KEEP(*(SORT(___ksymtab+*)))				\
++		SYMTAB_KEEP						\
+ 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
+-		KEEP(*(SORT(___ksymtab_gpl+*)))				\
++		SYMTAB_KEEP_GPL						\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
+ 	}								\
+ 									\
+@@ -370,7 +380,7 @@
+ 									\
+ 	/* Kernel symbol table: strings */				\
+         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
+-		*(__ksymtab_strings)					\
++		*(__ksymtab_strings+*)					\
+ 	}								\
+ 									\
+ 	/* __*init sections */						\
+@@ -700,6 +710,8 @@
+ 	EXIT_TEXT							\
+ 	EXIT_DATA							\
+ 	EXIT_CALL							\
++	SYMTAB_DISCARD							\
++	SYMTAB_DISCARD_GPL						\
+ 	*(.discard)							\
+ 	*(.discard.*)							\
+ 	}
+--- a/scripts/Makefile.build
++++ b/scripts/Makefile.build
+@@ -299,7 +299,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
+ # Linker scripts preprocessor (.lds.S -> .lds)
+ # ---------------------------------------------------------------------------
+ quiet_cmd_cpp_lds_S = LDS     $@
+-      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
++      cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \
+ 	                     -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+ 
+ $(obj)/%.lds: $(src)/%.lds.S FORCE
+--- a/include/linux/export.h
++++ b/include/linux/export.h
+@@ -52,12 +52,19 @@ extern struct module __this_module;
+ #define __CRC_SYMBOL(sym, sec)
+ #endif
+ 
++#ifdef MODULE
++#define __EXPORT_SUFFIX(sym)
++#else
++#define __EXPORT_SUFFIX(sym) "+" #sym
++#endif
++
+ /* For every exported symbol, place a struct in the __ksymtab section */
+ #define __EXPORT_SYMBOL(sym, sec)				\
+ 	extern typeof(sym) sym;					\
+ 	__CRC_SYMBOL(sym, sec)					\
+ 	static const char __kstrtab_##sym[]			\
+-	__attribute__((section("__ksymtab_strings"), aligned(1))) \
++	__attribute__((section("__ksymtab_strings"		\
++	  __EXPORT_SUFFIX(sym)), aligned(1)))			\
+ 	= VMLINUX_SYMBOL_STR(sym);				\
+ 	extern const struct kernel_symbol __ksymtab_##sym;	\
+ 	__visible const struct kernel_symbol __ksymtab_##sym	\
diff --git a/target/linux/generic/patches-4.1/222-perf-build-Do-not-fail-on-missing-Build-file.patch b/target/linux/generic/patches-4.1/222-perf-build-Do-not-fail-on-missing-Build-file.patch
new file mode 100644
index 0000000000..2026e4da8d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/222-perf-build-Do-not-fail-on-missing-Build-file.patch
@@ -0,0 +1,57 @@
+From d7a3d85e08477a979933a2bb3b525a8de99543c2 Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Fri, 29 May 2015 17:42:58 +0200
+Subject: [PATCH] perf build: Do not fail on missing Build file
+
+Allow nesting into directories without Build file. Currently we force
+include of the Build file, which fails the build when the Build file is
+missing.
+
+We already support empty *-in.o' objects if there's nothing in the
+directory to be compiled, so we can just use it for missing Build file
+cases.
+
+Also adding this case under tests.
+
+Reported-by: Rabin Vincent <rabin.vincent@axis.com>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Paul Mackerras <paulus@samba.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Cc: Rabin Vincent <rabin.vincent@axis.com>
+Link: http://lkml.kernel.org/r/1432914178-24086-1-git-send-email-jolsa@kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+---
+ tools/build/Makefile.build         | 2 +-
+ tools/build/tests/ex/Build         | 1 +
+ tools/build/tests/ex/empty2/README | 2 ++
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+ create mode 100644 tools/build/tests/ex/empty2/README
+
+--- a/tools/build/Makefile.build
++++ b/tools/build/Makefile.build
+@@ -37,7 +37,7 @@ subdir-obj-y :=
+ 
+ # Build definitions
+ build-file := $(dir)/Build
+-include $(build-file)
++-include $(build-file)
+ 
+ quiet_cmd_flex  = FLEX     $@
+ quiet_cmd_bison = BISON    $@
+--- a/tools/build/tests/ex/Build
++++ b/tools/build/tests/ex/Build
+@@ -2,6 +2,7 @@ ex-y += ex.o
+ ex-y += a.o
+ ex-y += b.o
+ ex-y += empty/
++ex-y += empty2/
+ 
+ libex-y += c.o
+ libex-y += d.o
+--- /dev/null
++++ b/tools/build/tests/ex/empty2/README
+@@ -0,0 +1,2 @@
++This directory is left intentionally without Build file
++to test proper nesting into Build-less directories.
diff --git a/target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch b/target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch
new file mode 100644
index 0000000000..d5bbb19cfe
--- /dev/null
+++ b/target/linux/generic/patches-4.1/230-openwrt_lzma_options.patch
@@ -0,0 +1,58 @@
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -324,7 +324,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
+ 
+ quiet_cmd_lzma = LZMA    $@
+ cmd_lzma = (cat $(filter-out FORCE,$^) | \
+-	lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
++	lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+ 	(rm -f $@ ; false)
+ 
+ quiet_cmd_lzo = LZO     $@
+--- a/scripts/gen_initramfs_list.sh
++++ b/scripts/gen_initramfs_list.sh
+@@ -226,7 +226,7 @@ cpio_list=
+ output="/dev/stdout"
+ output_file=""
+ is_cpio_compressed=
+-compr="gzip -n -9 -f"
++compr="gzip -n -9 -f -"
+ 
+ arg="$1"
+ case "$arg" in
+@@ -242,13 +242,13 @@ case "$arg" in
+ 		output=${cpio_list}
+ 		echo "$output_file" | grep -q "\.gz$" \
+                 && [ -x "`which gzip 2> /dev/null`" ] \
+-                && compr="gzip -n -9 -f"
++                && compr="gzip -n -9 -f -"
+ 		echo "$output_file" | grep -q "\.bz2$" \
+                 && [ -x "`which bzip2 2> /dev/null`" ] \
+-                && compr="bzip2 -9 -f"
++                && compr="bzip2 -9 -f -"
+ 		echo "$output_file" | grep -q "\.lzma$" \
+                 && [ -x "`which lzma 2> /dev/null`" ] \
+-                && compr="lzma -9 -f"
++                && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
+ 		echo "$output_file" | grep -q "\.xz$" \
+                 && [ -x "`which xz 2> /dev/null`" ] \
+                 && compr="xz --check=crc32 --lzma2=dict=1MiB"
+@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then
+ 	if [ "${is_cpio_compressed}" = "compressed" ]; then
+ 		cat ${cpio_tfile} > ${output_file}
+ 	else
+-		(cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
++		(cat ${cpio_tfile} | ${compr} > ${output_file}) \
+ 		|| (rm -f ${output_file} ; false)
+ 	fi
+ 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
+--- a/lib/decompress.c
++++ b/lib/decompress.c
+@@ -48,6 +48,7 @@ static const struct compress_format comp
+ 	{ {0x1f, 0x9e}, "gzip", gunzip },
+ 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
+ 	{ {0x5d, 0x00}, "lzma", unlzma },
++	{ {0x6d, 0x00}, "lzma-openwrt", unlzma },
+ 	{ {0xfd, 0x37}, "xz", unxz },
+ 	{ {0x89, 0x4c}, "lzo", unlzo },
+ 	{ {0x02, 0x21}, "lz4", unlz4 },
diff --git a/target/linux/generic/patches-4.1/250-netfilter_depends.patch b/target/linux/generic/patches-4.1/250-netfilter_depends.patch
new file mode 100644
index 0000000000..2b0815dbfb
--- /dev/null
+++ b/target/linux/generic/patches-4.1/250-netfilter_depends.patch
@@ -0,0 +1,18 @@
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -210,7 +210,6 @@ config NF_CONNTRACK_FTP
+ 
+ config NF_CONNTRACK_H323
+ 	tristate "H.323 protocol support"
+-	depends on (IPV6 || IPV6=n)
+ 	depends on NETFILTER_ADVANCED
+ 	help
+ 	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
+@@ -914,7 +913,6 @@ config NETFILTER_XT_TARGET_SECMARK
+ 
+ config NETFILTER_XT_TARGET_TCPMSS
+ 	tristate '"TCPMSS" target support'
+-	depends on (IPV6 || IPV6=n)
+ 	default m if NETFILTER_ADVANCED=n
+ 	---help---
+ 	  This option adds a `TCPMSS' target, which allows you to alter the
diff --git a/target/linux/generic/patches-4.1/251-sound_kconfig.patch b/target/linux/generic/patches-4.1/251-sound_kconfig.patch
new file mode 100644
index 0000000000..c2ebacecd1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/251-sound_kconfig.patch
@@ -0,0 +1,18 @@
+--- a/sound/core/Kconfig
++++ b/sound/core/Kconfig
+@@ -10,13 +10,13 @@ config SND_DMAENGINE_PCM
+ 	tristate
+ 
+ config SND_HWDEP
+-	tristate
++	tristate "Sound hardware support"
+ 
+ config SND_RAWMIDI
+ 	tristate
+ 
+ config SND_COMPRESS_OFFLOAD
+-	tristate
++	tristate "Compression offloading support"
+ 
+ # To be effective this also requires INPUT - users should say:
+ #    select SND_JACK if INPUT=y || INPUT=SND
diff --git a/target/linux/generic/patches-4.1/252-mv_cesa_depends.patch b/target/linux/generic/patches-4.1/252-mv_cesa_depends.patch
new file mode 100644
index 0000000000..fee28db120
--- /dev/null
+++ b/target/linux/generic/patches-4.1/252-mv_cesa_depends.patch
@@ -0,0 +1,10 @@
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -164,6 +164,7 @@ config CRYPTO_DEV_MV_CESA
+ 	depends on PLAT_ORION
+ 	select CRYPTO_ALGAPI
+ 	select CRYPTO_AES
++	select CRYPTO_HASH2
+ 	select CRYPTO_BLKCIPHER2
+ 	select CRYPTO_HASH
+ 	help
diff --git a/target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch b/target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch
new file mode 100644
index 0000000000..29d2a41a3b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/253-ssb_b43_default_on.patch
@@ -0,0 +1,29 @@
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -29,6 +29,7 @@ config SSB_SPROM
+ config SSB_BLOCKIO
+ 	bool
+ 	depends on SSB
++	default y
+ 
+ config SSB_PCIHOST_POSSIBLE
+ 	bool
+@@ -49,7 +50,7 @@ config SSB_PCIHOST
+ config SSB_B43_PCI_BRIDGE
+ 	bool
+ 	depends on SSB_PCIHOST
+-	default n
++	default y
+ 
+ config SSB_PCMCIAHOST_POSSIBLE
+ 	bool
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -17,6 +17,7 @@ config BCMA
+ config BCMA_BLOCKIO
+ 	bool
+ 	depends on BCMA
++	default y
+ 
+ config BCMA_HOST_PCI_POSSIBLE
+ 	bool
diff --git a/target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch b/target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch
new file mode 100644
index 0000000000..d682d4e65e
--- /dev/null
+++ b/target/linux/generic/patches-4.1/254-textsearch_kconfig_hacks.patch
@@ -0,0 +1,23 @@
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -328,16 +328,16 @@ config BCH_CONST_T
+ # Textsearch support is select'ed if needed
+ #
+ config TEXTSEARCH
+-	bool
++	boolean	"Textsearch support"
+ 
+ config TEXTSEARCH_KMP
+-	tristate
++	tristate "Textsearch KMP"
+ 
+ config TEXTSEARCH_BM
+-	tristate
++	tristate "Textsearch BM"
+ 
+ config TEXTSEARCH_FSM
+-	tristate
++	tristate "Textsearch FSM"
+ 
+ config BTREE
+ 	bool
diff --git a/target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch b/target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch
new file mode 100644
index 0000000000..8064b0212b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/255-lib80211_kconfig_hacks.patch
@@ -0,0 +1,31 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -191,7 +191,7 @@ config CFG80211_WEXT_EXPORT
+ 	  wext compatibility symbols to be exported.
+ 
+ config LIB80211
+-	tristate
++	tristate "LIB80211"
+ 	default n
+ 	help
+ 	  This options enables a library of common routines used
+@@ -200,13 +200,16 @@ config LIB80211
+ 	  Drivers should select this themselves if needed.
+ 
+ config LIB80211_CRYPT_WEP
+-	tristate
++	tristate "LIB80211_CRYPT_WEP"
++	select LIB80211
+ 
+ config LIB80211_CRYPT_CCMP
+-	tristate
++	tristate "LIB80211_CRYPT_CCMP"
++	select LIB80211
+ 
+ config LIB80211_CRYPT_TKIP
+-	tristate
++	tristate "LIB80211_CRYPT_TKIP"
++	select LIB80211
+ 
+ config LIB80211_DEBUG
+ 	bool "lib80211 debugging messages"
diff --git a/target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch b/target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch
new file mode 100644
index 0000000000..f9f6c0ea7b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/256-crypto_add_kconfig_prompts.patch
@@ -0,0 +1,47 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -32,7 +32,7 @@ config CRYPTO_FIPS
+ 	  this is.
+ 
+ config CRYPTO_ALGAPI
+-	tristate
++	tristate "ALGAPI"
+ 	select CRYPTO_ALGAPI2
+ 	help
+ 	  This option provides the API for cryptographic algorithms.
+@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2
+ 	tristate
+ 
+ config CRYPTO_AEAD
+-	tristate
++	tristate "AEAD"
+ 	select CRYPTO_AEAD2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -50,7 +50,7 @@ config CRYPTO_AEAD2
+ 	select CRYPTO_ALGAPI2
+ 
+ config CRYPTO_BLKCIPHER
+-	tristate
++	tristate "BLKCIPHER"
+ 	select CRYPTO_BLKCIPHER2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -61,7 +61,7 @@ config CRYPTO_BLKCIPHER2
+ 	select CRYPTO_WORKQUEUE
+ 
+ config CRYPTO_HASH
+-	tristate
++	tristate "HASH"
+ 	select CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -70,7 +70,7 @@ config CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI2
+ 
+ config CRYPTO_RNG
+-	tristate
++	tristate "RNG"
+ 	select CRYPTO_RNG2
+ 	select CRYPTO_ALGAPI
+ 
diff --git a/target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch b/target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch
new file mode 100644
index 0000000000..daac5898ae
--- /dev/null
+++ b/target/linux/generic/patches-4.1/257-wireless_ext_kconfig_hack.patch
@@ -0,0 +1,22 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -1,5 +1,5 @@
+ config WIRELESS_EXT
+-	bool
++	bool "Wireless extensions"
+ 
+ config WEXT_CORE
+ 	def_bool y
+@@ -11,10 +11,10 @@ config WEXT_PROC
+ 	depends on WEXT_CORE
+ 
+ config WEXT_SPY
+-	bool
++	bool "WEXT_SPY"
+ 
+ config WEXT_PRIV
+-	bool
++	bool "WEXT_PRIV"
+ 
+ config CFG80211
+ 	tristate "cfg80211 - wireless configuration API"
diff --git a/target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch b/target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch
new file mode 100644
index 0000000000..9d827c253b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/258-netfilter_netlink_kconfig_hack.patch
@@ -0,0 +1,11 @@
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -2,7 +2,7 @@ menu "Core Netfilter Configuration"
+ 	depends on NET && INET && NETFILTER
+ 
+ config NETFILTER_NETLINK
+-	tristate
++	tristate "Netfilter NFNETLINK interface"
+ 
+ config NETFILTER_NETLINK_ACCT
+ tristate "Netfilter NFACCT over NFNETLINK interface"
diff --git a/target/linux/generic/patches-4.1/259-regmap_dynamic.patch b/target/linux/generic/patches-4.1/259-regmap_dynamic.patch
new file mode 100644
index 0000000000..a4bdae6aec
--- /dev/null
+++ b/target/linux/generic/patches-4.1/259-regmap_dynamic.patch
@@ -0,0 +1,87 @@
+--- a/drivers/base/regmap/Kconfig
++++ b/drivers/base/regmap/Kconfig
+@@ -3,29 +3,35 @@
+ # subsystems should select the appropriate symbols.
+ 
+ config REGMAP
+-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+ 	select LZO_COMPRESS
+ 	select LZO_DECOMPRESS
+ 	select IRQ_DOMAIN if REGMAP_IRQ
+-	bool
++	tristate "Regmap"
+ 
+ config REGMAP_AC97
++	select REGMAP
+ 	tristate
+ 
+ config REGMAP_I2C
+-	tristate
++	tristate "Regmap I2C"
++	select REGMAP
+ 	depends on I2C
+ 
+ config REGMAP_SPI
+-	tristate
++	tristate "Regmap SPI"
++	select REGMAP
++	depends on SPI_MASTER
+ 	depends on SPI
+ 
+ config REGMAP_SPMI
++	select REGMAP
+ 	tristate
+ 	depends on SPMI
+ 
+ config REGMAP_MMIO
+-	tristate
++	tristate "Regmap MMIO"
++	select REGMAP
+ 
+ config REGMAP_IRQ
++	select REGMAP
+ 	bool
+--- a/include/linux/regmap.h
++++ b/include/linux/regmap.h
+@@ -50,7 +50,7 @@ struct reg_default {
+ 	unsigned int def;
+ };
+ 
+-#ifdef CONFIG_REGMAP
++#if IS_ENABLED(CONFIG_REGMAP)
+ 
+ enum regmap_endian {
+ 	/* Unspecified -> 0 -> Backwards compatible default */
+--- a/drivers/base/regmap/Makefile
++++ b/drivers/base/regmap/Makefile
+@@ -1,9 +1,11 @@
+ # For include/trace/define_trace.h to include trace.h
+ CFLAGS_regmap.o := -I$(src)
+ 
+-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
+-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
+-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o
++ifdef CONFIG_DEBUG_FS
++regmap-core-objs += regmap-debugfs.o
++endif
++obj-$(CONFIG_REGMAP) += regmap-core.o
+ obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
+ obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
+ obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
+--- a/drivers/base/regmap/regmap.c
++++ b/drivers/base/regmap/regmap.c
+@@ -13,6 +13,7 @@
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/export.h>
++#include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/err.h>
+ #include <linux/of.h>
+@@ -2631,3 +2632,5 @@ static int __init regmap_initcall(void)
+ 	return 0;
+ }
+ postcore_initcall(regmap_initcall);
++
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch b/target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch
new file mode 100644
index 0000000000..8a96fd9da7
--- /dev/null
+++ b/target/linux/generic/patches-4.1/260-crypto_test_dependencies.patch
@@ -0,0 +1,37 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -96,10 +96,10 @@ config CRYPTO_MANAGER
+ 
+ config CRYPTO_MANAGER2
+ 	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
+-	select CRYPTO_AEAD2
+-	select CRYPTO_HASH2
+-	select CRYPTO_BLKCIPHER2
+-	select CRYPTO_PCOMP2
++	select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ 
+ config CRYPTO_USER
+ 	tristate "Userspace cryptographic algorithm configuration"
+--- a/crypto/algboss.c
++++ b/crypto/algboss.c
+@@ -248,6 +248,9 @@ static int cryptomgr_schedule_test(struc
+ 	type = alg->cra_flags;
+ 
+ 	/* This piece of crap needs to disappear into per-type test hooks. */
++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
++	type |= CRYPTO_ALG_TESTED;
++#else
+ 	if ((!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
+ 	       CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) &&
+ 	     ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+@@ -256,6 +259,7 @@ static int cryptomgr_schedule_test(struc
+ 	    (!((type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) &&
+ 	     alg->cra_type == &crypto_nivaead_type && alg->cra_aead.ivsize))
+ 		type |= CRYPTO_ALG_TESTED;
++#endif
+ 
+ 	param->type = type;
+ 
diff --git a/target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch b/target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
new file mode 100644
index 0000000000..762f4989b6
--- /dev/null
+++ b/target/linux/generic/patches-4.1/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
@@ -0,0 +1,34 @@
+From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 14:37:54 +0200
+Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h
+
+including sysinfo.h from kernel.h makes no sense whatsoever,
+but removing it breaks glibc's userspace header,
+which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h.
+this seems to be a historical mistake.
+on musl, including any header that uses kernel.h directly or indirectly
+plus sys/sysinfo.h will produce a compile error due to redefinition of
+struct sysinfo from sys/sysinfo.h.
+so for now, only include it on glibc or when including from kernel
+in order not to break their headers.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Signed-off-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/kernel.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/uapi/linux/kernel.h
++++ b/include/uapi/linux/kernel.h
+@@ -1,7 +1,9 @@
+ #ifndef _UAPI_LINUX_KERNEL_H
+ #define _UAPI_LINUX_KERNEL_H
+ 
++#if defined(__KERNEL__) || defined( __GLIBC__)
+ #include <linux/sysinfo.h>
++#endif
+ 
+ /*
+  * 'kernel.h' contains some often-used function prototypes etc
diff --git a/target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
new file mode 100644
index 0000000000..61d3873c01
--- /dev/null
+++ b/target/linux/generic/patches-4.1/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
@@ -0,0 +1,81 @@
+From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 16:50:40 +0200
+Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__
+
+Musl provides the same structs as glibc, but does not provide a define to
+allow its detection. Since the absence of __GLIBC__ also can mean that it
+is included from the kernel, change the __GLIBC__ detection to
+!__KERNEL__, which should always be true when included from userspace.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/libc-compat.h | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -48,13 +48,13 @@
+ #ifndef _UAPI_LIBC_COMPAT_H
+ #define _UAPI_LIBC_COMPAT_H
+ 
+-/* We have included glibc headers... */
+-#if defined(__GLIBC__)
++/* We have included libc headers... */
++#if !defined(__KERNEL__)
+ 
+-/* Coordinate with glibc netinet/in.h header. */
++/* Coordinate with libc netinet/in.h header. */
+ #if defined(_NETINET_IN_H)
+ 
+-/* GLIBC headers included first so don't define anything
++/* LIBC headers included first so don't define anything
+  * that would already be defined. */
+ #define __UAPI_DEF_IN_ADDR		0
+ #define __UAPI_DEF_IN_IPPROTO		0
+@@ -68,7 +68,7 @@
+  * if the glibc code didn't define them. This guard matches
+  * the guard in glibc/inet/netinet/in.h which defines the
+  * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
+-#if defined(__USE_MISC) || defined (__USE_GNU)
++#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU)
+ #define __UAPI_DEF_IN6_ADDR_ALT		0
+ #else
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
+@@ -83,7 +83,7 @@
+ #else
+ 
+ /* Linux headers included first, and we must define everything
+- * we need. The expectation is that glibc will check the
++ * we need. The expectation is that the libc will check the
+  * __UAPI_DEF_* defines and adjust appropriately. */
+ #define __UAPI_DEF_IN_ADDR		1
+ #define __UAPI_DEF_IN_IPPROTO		1
+@@ -93,7 +93,7 @@
+ #define __UAPI_DEF_IN_CLASS		1
+ 
+ #define __UAPI_DEF_IN6_ADDR		1
+-/* We unconditionally define the in6_addr macros and glibc must
++/* We unconditionally define the in6_addr macros and the libc must
+  * coordinate. */
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
+ #define __UAPI_DEF_SOCKADDR_IN6		1
+@@ -115,7 +115,7 @@
+ /* If we did not see any headers from any supported C libraries,
+  * or we are being included in the kernel, then define everything
+  * that we need. */
+-#else /* !defined(__GLIBC__) */
++#else /* defined(__KERNEL__) */
+ 
+ /* Definitions for in.h */
+ #define __UAPI_DEF_IN_ADDR		1
+@@ -138,6 +138,6 @@
+ /* Definitions for xattr.h */
+ #define __UAPI_DEF_XATTR		1
+ 
+-#endif /* __GLIBC__ */
++#endif /* __KERNEL__ */
+ 
+ #endif /* _UAPI_LIBC_COMPAT_H */
diff --git a/target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
new file mode 100644
index 0000000000..257c9d7e99
--- /dev/null
+++ b/target/linux/generic/patches-4.1/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
@@ -0,0 +1,67 @@
+From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 16:53:03 +0200
+Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr
+
+Musl provides its own ethhdr struct definition. Add a guard to prevent
+its definition of the appropriate musl header has already been included.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/if_ether.h    |  3 +++
+ include/uapi/linux/libc-compat.h | 11 +++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/include/uapi/linux/if_ether.h
++++ b/include/uapi/linux/if_ether.h
+@@ -22,6 +22,7 @@
+ #define _UAPI_LINUX_IF_ETHER_H
+ 
+ #include <linux/types.h>
++#include <linux/libc-compat.h>
+ 
+ /*
+  *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+@@ -134,11 +135,13 @@
+  *	This is an Ethernet frame header.
+  */
+ 
++#if __UAPI_DEF_ETHHDR
+ struct ethhdr {
+ 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+ 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+ 	__be16		h_proto;		/* packet type ID field	*/
+ } __attribute__((packed));
++#endif
+ 
+ 
+ #endif /* _UAPI_LINUX_IF_ETHER_H */
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -51,6 +51,14 @@
+ /* We have included libc headers... */
+ #if !defined(__KERNEL__)
+ 
++/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
++ * Glibc just includes the kernel header and uses a different guard. */
++#if defined(_NETINET_IF_ETHER_H)
++#define __UAPI_DEF_ETHHDR		0
++#else
++#define __UAPI_DEF_ETHHDR		1
++#endif
++
+ /* Coordinate with libc netinet/in.h header. */
+ #if defined(_NETINET_IN_H)
+ 
+@@ -117,6 +125,9 @@
+  * that we need. */
+ #else /* defined(__KERNEL__) */
+ 
++/* Definitions for if_ether.h */
++#define __UAPI_DEF_ETHHDR 		1
++
+ /* Definitions for in.h */
+ #define __UAPI_DEF_IN_ADDR		1
+ #define __UAPI_DEF_IN_IPPROTO		1
diff --git a/target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch b/target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch
new file mode 100644
index 0000000000..b9cf5ba25a
--- /dev/null
+++ b/target/linux/generic/patches-4.1/300-mips_expose_boot_raw.patch
@@ -0,0 +1,39 @@
+From: Mark Miller <mark@mirell.org>
+
+This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
+certain Broadcom chipsets running CFE in order to load the kernel.
+
+Signed-off-by: Mark Miller <mark@mirell.org>
+Acked-by: Rob Landley <rob@landley.net>
+---
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -984,9 +984,6 @@ config FW_ARC
+ config ARCH_MAY_HAVE_PC_FDC
+ 	bool
+ 
+-config BOOT_RAW
+-	bool
+-
+ config CEVT_BCM1480
+ 	bool
+ 
+@@ -2677,6 +2674,18 @@ config USE_OF
+ config BUILTIN_DTB
+ 	bool
+ 
++config BOOT_RAW
++	bool "Enable the kernel to be executed from the load address"
++	default n
++	help
++	 Allow the kernel to be executed from the load address for
++	 bootloaders which cannot read the ELF format. This places
++	 a jump to start_kernel at the load address.
++
++	 If unsure, say N.
++
++
++
+ endmenu
+ 
+ config LOCKDEP_SUPPORT
diff --git a/target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch b/target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch
new file mode 100644
index 0000000000..f85310401d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/301-mips_image_cmdline_hack.patch
@@ -0,0 +1,28 @@
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1073,6 +1073,10 @@ config SYNC_R4K
+ config MIPS_MACHINE
+ 	def_bool n
+ 
++config IMAGE_CMDLINE_HACK
++	bool "OpenWrt specific image command line hack"
++	default n
++
+ config NO_IOPORT_MAP
+ 	def_bool n
+ 
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry)
+ 	j	kernel_entry
+ #endif
+ 
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++	.ascii	"CMDLINE:"
++EXPORT(__image_cmdline)
++	.fill	0x400
++#endif /* CONFIG_IMAGE_CMDLINE_HACK */
++
+ 	__REF
+ 
+ NESTED(kernel_entry, 16, sp)			# kernel entry point
diff --git a/target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch b/target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch
new file mode 100644
index 0000000000..44c6b04fcf
--- /dev/null
+++ b/target/linux/generic/patches-4.1/302-mips_no_branch_likely.patch
@@ -0,0 +1,11 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ # machines may also.  Since BFD is incredibly buggy with respect to
+ # crossformat linking we rely on the elf2ecoff tool for format conversion.
+ #
+-cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
++cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
diff --git a/target/linux/generic/patches-4.1/304-mips_disable_fpu.patch b/target/linux/generic/patches-4.1/304-mips_disable_fpu.patch
new file mode 100644
index 0000000000..646fe53ad1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/304-mips_disable_fpu.patch
@@ -0,0 +1,106 @@
+From:   Manuel Lauss <manuel.lauss@gmail.com>
+Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
+Date:   Mon,  7 Apr 2014 12:57:04 +0200
+Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com>
+
+This small patch makes the MIPS FPU emulator optional. The kernel
+kills float-users on systems without a hardware FPU by sending a SIGILL.
+
+Disabling the emulator shrinks vmlinux by about 54kBytes (32bit,
+optimizing for size).
+
+Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
+---
+v4: rediffed because of patch 1/2, should now work with micromips as well
+v3: updated patch description with size savings.
+v2: incorporated changes suggested by Jonas Gorski
+    force the fpu emulator on for micromips: relocating the parts
+    of the mmips code in the emulator to other areas would be a
+    much larger change; I went the cheap route instead with this.
+
+ arch/mips/Kbuild                     |  2 +-
+ arch/mips/Kconfig                    | 14 ++++++++++++++
+ arch/mips/include/asm/fpu.h          |  5 +++--
+ arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++
+ 4 files changed, 33 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -2669,6 +2669,20 @@ config MIPS_O32_FP64_SUPPORT
+ 
+ 	  If unsure, say N.
+ 
++config MIPS_FPU_EMULATOR
++	bool "MIPS FPU Emulator"
++	default y
++	help
++	  This option lets you disable the built-in MIPS FPU (Coprocessor 1)
++	  emulator, which handles floating-point instructions on processors
++	  without a hardware FPU.  It is generally a good idea to keep the
++	  emulator built-in, unless you are perfectly sure you have a
++	  complete soft-float environment.  With the emulator disabled, all
++	  users of float operations will be killed with an illegal instr-
++	  uction exception.
++
++	  Say Y, please.
++
+ config USE_OF
+ 	bool
+ 	select OF
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -292,7 +292,7 @@ OBJCOPYFLAGS		+= --remove-section=.regin
+ head-y := arch/mips/kernel/head.o
+ 
+ libs-y			+= arch/mips/lib/
+-libs-y			+= arch/mips/math-emu/
++libs-$(CONFIG_MIPS_FPU_EMULATOR)	+= arch/mips/math-emu/
+ 
+ # See arch/mips/Kbuild for content of core part of the kernel
+ core-y += arch/mips/
+--- a/arch/mips/include/asm/fpu.h
++++ b/arch/mips/include/asm/fpu.h
+@@ -218,8 +218,10 @@ static inline int init_fpu(void)
+ 		/* Restore FRE */
+ 		write_c0_config5(config5);
+ 		enable_fpu_hazard();
+-	} else
++	} else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR))
+ 		fpu_emulator_init_fpu();
++	else
++		ret = SIGILL;
+ 
+ 	return ret;
+ }
+--- a/arch/mips/include/asm/fpu_emulator.h
++++ b/arch/mips/include/asm/fpu_emulator.h
+@@ -30,6 +30,7 @@
+ #include <asm/local.h>
+ #include <asm/processor.h>
+ 
++#ifdef CONFIG_MIPS_FPU_EMULATOR
+ #ifdef CONFIG_DEBUG_FS
+ 
+ struct mips_fpu_emulator_stats {
+@@ -66,6 +67,21 @@ extern int do_dsemulret(struct pt_regs *
+ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
+ 				    struct mips_fpu_struct *ctx, int has_fpu,
+ 				    void *__user *fault_addr);
++#else	/* no CONFIG_MIPS_FPU_EMULATOR */
++static inline int do_dsemulret(struct pt_regs *xcp)
++{
++	return 0;	/* 0 means error, should never get here anyway */
++}
++
++static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
++				struct mips_fpu_struct *ctx, int has_fpu,
++				void *__user *fault_addr)
++{
++	*fault_addr = NULL;
++	return SIGILL;	/* we don't speak MIPS FPU */
++}
++#endif	/* CONFIG_MIPS_FPU_EMULATOR */
++
+ int process_fpemu_return(int sig, void __user *fault_addr,
+ 			 unsigned long fcr31);
+ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
diff --git a/target/linux/generic/patches-4.1/305-mips_module_reloc.patch b/target/linux/generic/patches-4.1/305-mips_module_reloc.patch
new file mode 100644
index 0000000000..8b3975fe09
--- /dev/null
+++ b/target/linux/generic/patches-4.1/305-mips_module_reloc.patch
@@ -0,0 +1,352 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
++ifdef CONFIG_64BIT
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
++else
++KBUILD_AFLAGS_MODULE		+= -mno-long-calls
++KBUILD_CFLAGS_MODULE		+= -mno-long-calls
++endif
+ 
+ ifndef CONFIG_FUNCTION_TRACER
+ KBUILD_CFLAGS_KERNEL		+= -ffunction-sections -fdata-sections
+--- a/arch/mips/include/asm/module.h
++++ b/arch/mips/include/asm/module.h
+@@ -11,6 +11,11 @@ struct mod_arch_specific {
+ 	const struct exception_table_entry *dbe_start;
+ 	const struct exception_table_entry *dbe_end;
+ 	struct mips_hi16 *r_mips_hi16_list;
++
++	void *phys_plt_tbl;
++	void *virt_plt_tbl;
++	unsigned int phys_plt_offset;
++	unsigned int virt_plt_offset;
+ };
+ 
+ typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */
+--- a/arch/mips/kernel/module.c
++++ b/arch/mips/kernel/module.c
+@@ -43,14 +43,221 @@ struct mips_hi16 {
+ static LIST_HEAD(dbe_list);
+ static DEFINE_SPINLOCK(dbe_lock);
+ 
+-#ifdef MODULE_START
++/*
++ * Get the potential max trampolines size required of the init and
++ * non-init sections. Only used if we cannot find enough contiguous
++ * physically mapped memory to put the module into.
++ */
++static unsigned int
++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
++             const char *secstrings, unsigned int symindex, bool is_init)
++{
++	unsigned long ret = 0;
++	unsigned int i, j;
++	Elf_Sym *syms;
++
++	/* Everything marked ALLOC (this includes the exported symbols) */
++	for (i = 1; i < hdr->e_shnum; ++i) {
++		unsigned int info = sechdrs[i].sh_info;
++
++		if (sechdrs[i].sh_type != SHT_REL
++		    && sechdrs[i].sh_type != SHT_RELA)
++			continue;
++
++		/* Not a valid relocation section? */
++		if (info >= hdr->e_shnum)
++			continue;
++
++		/* Don't bother with non-allocated sections */
++		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
++			continue;
++
++		/* If it's called *.init*, and we're not init, we're
++                   not interested */
++		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
++		    != is_init)
++			continue;
++
++		syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
++		if (sechdrs[i].sh_type == SHT_REL) {
++			Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rel[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		} else {
++			Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rela[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		}
++	}
++
++	return ret;
++}
++
++#ifndef MODULE_START
++static void *alloc_phys(unsigned long size)
++{
++	unsigned order;
++	struct page *page;
++	struct page *p;
++
++	size = PAGE_ALIGN(size);
++	order = get_order(size);
++
++	page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
++			__GFP_THISNODE, order);
++	if (!page)
++		return NULL;
++
++	split_page(page, order);
++
++	/* mark all pages except for the last one */
++	for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
++		set_bit(PG_owner_priv_1, &p->flags);
++
++	for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
++		__free_page(p);
++
++	return page_address(page);
++}
++#endif
++
++static void free_phys(void *ptr)
++{
++	struct page *page;
++	bool free;
++
++	page = virt_to_page(ptr);
++	do {
++		free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
++		__free_page(page);
++		page++;
++	} while (free);
++}
++
++
+ void *module_alloc(unsigned long size)
+ {
++#ifdef MODULE_START
+ 	return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
+ 				GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
+ 				__builtin_return_address(0));
++#else
++	void *ptr;
++
++	if (size == 0)
++		return NULL;
++
++	ptr = alloc_phys(size);
++
++	/* If we failed to allocate physically contiguous memory,
++	 * fall back to regular vmalloc. The module loader code will
++	 * create jump tables to handle long jumps */
++	if (!ptr)
++		return vmalloc(size);
++
++	return ptr;
++#endif
+ }
++
++static inline bool is_phys_addr(void *ptr)
++{
++#ifdef CONFIG_64BIT
++	return (KSEGX((unsigned long)ptr) == CKSEG0);
++#else
++	return (KSEGX(ptr) == KSEG0);
+ #endif
++}
++
++/* Free memory returned from module_alloc */
++void module_memfree(void *module_region)
++{
++	if (is_phys_addr(module_region))
++		free_phys(module_region);
++	else
++		vfree(module_region);
++}
++
++static void *__module_alloc(int size, bool phys)
++{
++	void *ptr;
++
++	if (phys)
++		ptr = kmalloc(size, GFP_KERNEL);
++	else
++		ptr = vmalloc(size);
++	return ptr;
++}
++
++static void __module_free(void *ptr)
++{
++	if (is_phys_addr(ptr))
++		kfree(ptr);
++	else
++		vfree(ptr);
++}
++
++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
++			      char *secstrings, struct module *mod)
++{
++	unsigned int symindex = 0;
++	unsigned int core_size, init_size;
++	int i;
++
++	mod->arch.phys_plt_offset = 0;
++	mod->arch.virt_plt_offset = 0;
++	mod->arch.phys_plt_tbl = NULL;
++	mod->arch.virt_plt_tbl = NULL;
++
++	if (IS_ENABLED(CONFIG_64BIT))
++		return 0;
++
++	for (i = 1; i < hdr->e_shnum; i++)
++		if (sechdrs[i].sh_type == SHT_SYMTAB)
++			symindex = i;
++
++	core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
++	init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
++
++	if ((core_size + init_size) == 0)
++		return 0;
++
++	mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
++	if (!mod->arch.phys_plt_tbl)
++		return -ENOMEM;
++
++	mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
++	if (!mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++		return -ENOMEM;
++	}
++
++	return 0;
++}
+ 
+ int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
+ {
+@@ -64,8 +271,39 @@ static int apply_r_mips_32_rel(struct mo
+ 	return 0;
+ }
+ 
++static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
++				 void *start, Elf_Addr v)
++{
++	unsigned *tramp = start + *plt_offset;
++	*plt_offset += 4 * sizeof(int);
++
++	/* adjust carry for addiu */
++	if (v & 0x00008000)
++		v += 0x10000;
++
++	tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
++	tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
++	tramp[2] = 0x03200008;                  /* jr t9 */
++	tramp[3] = 0x00000000;                  /* nop */
++
++	return (Elf_Addr) tramp;
++}
++
++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
++{
++	if (is_phys_addr(location))
++		return add_plt_entry_to(&me->arch.phys_plt_offset,
++				me->arch.phys_plt_tbl, v);
++	else
++		return add_plt_entry_to(&me->arch.virt_plt_offset,
++				me->arch.virt_plt_tbl, v);
++
++}
++
+ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
+ {
++	u32 ofs = *location & 0x03ffffff;
++
+ 	if (v % 4) {
+ 		pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
+ 		       me->name);
+@@ -73,14 +311,17 @@ static int apply_r_mips_26_rel(struct mo
+ 	}
+ 
+ 	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
+-		printk(KERN_ERR
+-		       "module %s: relocation overflow\n",
+-		       me->name);
+-		return -ENOEXEC;
++		v = add_plt_entry(me, location, v + (ofs << 2));
++		if (!v) {
++			printk(KERN_ERR
++				"module %s: relocation overflow\n", me->name);
++			return -ENOEXEC;
++		}
++		ofs = 0;
+ 	}
+ 
+ 	*location = (*location & ~0x03ffffff) |
+-		    ((*location + (v >> 2)) & 0x03ffffff);
++		    ((ofs + (v >> 2)) & 0x03ffffff);
+ 
+ 	return 0;
+ }
+@@ -287,9 +528,33 @@ int module_finalize(const Elf_Ehdr *hdr,
+ 		list_add(&me->arch.dbe_list, &dbe_list);
+ 		spin_unlock_irq(&dbe_lock);
+ 	}
++
++	/* Get rid of the fixup trampoline if we're running the module
++	 * from physically mapped address space */
++	if (me->arch.phys_plt_offset == 0) {
++		__module_free(me->arch.phys_plt_tbl);
++		me->arch.phys_plt_tbl = NULL;
++	}
++	if (me->arch.virt_plt_offset == 0) {
++		__module_free(me->arch.virt_plt_tbl);
++		me->arch.virt_plt_tbl = NULL;
++	}
++
+ 	return 0;
+ }
+ 
++void module_arch_freeing_init(struct module *mod)
++{
++	if (mod->arch.phys_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++	}
++	if (mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.virt_plt_tbl);
++		mod->arch.virt_plt_tbl = NULL;
++	}
++}
++
+ void module_arch_cleanup(struct module *mod)
+ {
+ 	spin_lock_irq(&dbe_lock);
diff --git a/target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch b/target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch
new file mode 100644
index 0000000000..9818677425
--- /dev/null
+++ b/target/linux/generic/patches-4.1/306-mips_mem_functions_performance.patch
@@ -0,0 +1,83 @@
+--- a/arch/mips/include/asm/string.h
++++ b/arch/mips/include/asm/string.h
+@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__
+ 
+ #define __HAVE_ARCH_MEMSET
+ extern void *memset(void *__s, int __c, size_t __count);
++#define memset(__s, __c, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memset((__s), (__c), __len);		\
++	else							\
++		__ret = __builtin_memset((__s), (__c), __len);	\
++	__ret;							\
++})
+ 
+ #define __HAVE_ARCH_MEMCPY
+ extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
++#define memcpy(dst, src, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memcpy((dst), (src), __len);		\
++	else							\
++		__ret = __builtin_memcpy((dst), (src), __len);	\
++	__ret;							\
++})
+ 
+ #define __HAVE_ARCH_MEMMOVE
+ extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
++#define memmove(dst, src, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memmove((dst), (src), __len);		\
++	else							\
++		__ret = __builtin_memmove((dst), (src), __len);	\
++	__ret;							\
++})
++
++#define __HAVE_ARCH_MEMCMP
++#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len))
+ 
+ #endif /* _ASM_STRING_H */
+--- a/arch/mips/lib/Makefile
++++ b/arch/mips/lib/Makefile
+@@ -4,7 +4,7 @@
+ 
+ lib-y	+= bitops.o csum_partial.o delay.o memcpy.o memset.o \
+ 	   mips-atomic.o strlen_user.o strncpy_user.o \
+-	   strnlen_user.o uncached.o
++	   strnlen_user.o uncached.o memcmp.o
+ 
+ obj-y			+= iomap.o
+ obj-$(CONFIG_PCI)	+= iomap-pci.o
+--- /dev/null
++++ b/arch/mips/lib/memcmp.c
+@@ -0,0 +1,22 @@
++/*
++ *  copied from linux/lib/string.c
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++
++#undef memcmp
++int memcmp(const void *cs, const void *ct, size_t count)
++{
++	const unsigned char *su1, *su2;
++	int res = 0;
++
++	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
++		if ((res = *su1 - *su2) != 0)
++			break;
++	return res;
++}
++EXPORT_SYMBOL(memcmp);
++
diff --git a/target/linux/generic/patches-4.1/307-mips_highmem_offset.patch b/target/linux/generic/patches-4.1/307-mips_highmem_offset.patch
new file mode 100644
index 0000000000..5a7dc9cee9
--- /dev/null
+++ b/target/linux/generic/patches-4.1/307-mips_highmem_offset.patch
@@ -0,0 +1,17 @@
+Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations
+stay within the same 256M boundary. This ensures that -mlong-calls is not
+needed on systems with more than 256M RAM.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/arch/mips/include/asm/mach-generic/spaces.h
++++ b/arch/mips/include/asm/mach-generic/spaces.h
+@@ -44,7 +44,7 @@
+  * Memory above this physical address will be considered highmem.
+  */
+ #ifndef HIGHMEM_START
+-#define HIGHMEM_START		_AC(0x20000000, UL)
++#define HIGHMEM_START		_AC(0x10000000, UL)
+ #endif
+ 
+ #endif /* CONFIG_32BIT */
diff --git a/target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch
new file mode 100644
index 0000000000..9210c1d2d3
--- /dev/null
+++ b/target/linux/generic/patches-4.1/310-arm_module_unresolved_weak_sym.patch
@@ -0,0 +1,13 @@
+--- a/arch/arm/kernel/module.c
++++ b/arch/arm/kernel/module.c
+@@ -83,6 +83,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
+ 			return -ENOEXEC;
+ 		}
+ 
++		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
++		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
++			continue;
++
+ 		loc = dstsec->sh_addr + rel->r_offset;
+ 
+ 		switch (ELF32_R_TYPE(rel->r_info)) {
diff --git a/target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch b/target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch
new file mode 100644
index 0000000000..7ea4479c20
--- /dev/null
+++ b/target/linux/generic/patches-4.1/320-ppc4xx_optimization.patch
@@ -0,0 +1,31 @@
+Upstream doesn't optimize the kernel and bootwrappers for ppc44x because
+they still want to support gcc 3.3 -- well, we don't.
+
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -203,7 +203,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ KBUILD_CFLAGS		+= -mno-sched-epilog
+ endif
+ 
+-cpu-as-$(CONFIG_4xx)		+= -Wa,-m405
++cpu-as-$(CONFIG_40x)		+= -Wa,-m405
++cpu-as-$(CONFIG_44x)		+= -Wa,-m440
+ cpu-as-$(CONFIG_ALTIVEC)	+= -Wa,-maltivec
+ cpu-as-$(CONFIG_E200)		+= -Wa,-me200
+ 
+--- a/arch/powerpc/boot/Makefile
++++ b/arch/powerpc/boot/Makefile
+@@ -48,10 +48,10 @@ BOOTCFLAGS	+= -I$(obj) -I$(srctree)/$(ob
+ DTC_FLAGS	?= -p 1024
+ 
+ $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
++$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
+ $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
++$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440
++$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440
+ $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
+ $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
+ $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405
diff --git a/target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch
new file mode 100644
index 0000000000..ab6ea7beb2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/321-powerpc_crtsavres_prereq.patch
@@ -0,0 +1,10 @@
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -165,7 +165,6 @@ CPP		= $(CC) -E $(KBUILD_CFLAGS)
+ 
+ CHECKFLAGS	+= -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
+ 
+-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+ 
+ ifeq ($(CONFIG_476FPE_ERR46),y)
+ 	KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
diff --git a/target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
new file mode 100644
index 0000000000..a69d197e62
--- /dev/null
+++ b/target/linux/generic/patches-4.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
@@ -0,0 +1,298 @@
+From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Sat, 31 Jan 2015 22:26:03 +0800
+Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from
+ userspace.
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ arch/mips/kernel/machine_kexec.c   |  153 +++++++++++++++++++++++++++++++-----
+ arch/mips/kernel/machine_kexec.h   |   20 +++++
+ arch/mips/kernel/relocate_kernel.S |   21 +++--
+ 3 files changed, 167 insertions(+), 27 deletions(-)
+ create mode 100644 arch/mips/kernel/machine_kexec.h
+
+--- a/arch/mips/kernel/machine_kexec.c
++++ b/arch/mips/kernel/machine_kexec.c
+@@ -10,45 +10,145 @@
+ #include <linux/mm.h>
+ #include <linux/delay.h>
+ 
++#include <asm/bootinfo.h>
+ #include <asm/cacheflush.h>
+ #include <asm/page.h>
+-
+-extern const unsigned char relocate_new_kernel[];
+-extern const size_t relocate_new_kernel_size;
+-
+-extern unsigned long kexec_start_address;
+-extern unsigned long kexec_indirection_page;
++#include <asm/uaccess.h>
++#include "machine_kexec.h"
+ 
+ int (*_machine_kexec_prepare)(struct kimage *) = NULL;
+ void (*_machine_kexec_shutdown)(void) = NULL;
+ void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
++
+ #ifdef CONFIG_SMP
+ void (*relocated_kexec_smp_wait) (void *);
+ atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
+ #endif
+ 
+-int
+-machine_kexec_prepare(struct kimage *kimage)
++static void machine_kexec_print_args(void)
+ {
++	unsigned long argc = (int)kexec_args[0];
++	int i;
++
++	pr_info("kexec_args[0] (argc): %lu\n", argc);
++	pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
++	pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
++	pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
++
++	for (i = 0; i < argc; i++) {
++		pr_info("kexec_argv[%d] = %p, %s\n",
++				i, kexec_argv[i], kexec_argv[i]);
++	}
++}
++
++static void machine_kexec_init_argv(struct kimage *image)
++{
++	void __user *buf = NULL;
++	size_t bufsz;
++	size_t size;
++	int i;
++
++	bufsz = 0;
++	for (i = 0; i < image->nr_segments; i++) {
++		struct kexec_segment *seg;
++
++		seg = &image->segment[i];
++		if (seg->bufsz < 6)
++			continue;
++
++		if (strncmp((char *) seg->buf, "kexec ", 6))
++			continue;
++
++		buf = seg->buf;
++		bufsz = seg->bufsz;
++		break;
++	}
++
++	if (!buf)
++		return;
++
++	size = KEXEC_COMMAND_LINE_SIZE;
++	size = min(size, bufsz);
++	if (size < bufsz)
++		pr_warn("kexec command line truncated to %zd bytes\n", size);
++
++	/* Copy to kernel space */
++	copy_from_user(kexec_argv_buf, buf, size);
++	kexec_argv_buf[size - 1] = 0;
++}
++
++static void machine_kexec_parse_argv(struct kimage *image)
++{
++	char *reboot_code_buffer;
++	int reloc_delta;
++	char *ptr;
++	int argc;
++	int i;
++
++	ptr = kexec_argv_buf;
++	argc = 0;
++
++	/*
++	 * convert command line string to array of parameters
++	 * (as bootloader does).
++	 */
++	while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
++		if (*ptr == ' ') {
++			*ptr++ = '\0';
++			continue;
++		}
++
++		kexec_argv[argc++] = ptr;
++		ptr = strchr(ptr, ' ');
++	}
++
++	if (!argc)
++		return;
++
++	kexec_args[0] = argc;
++	kexec_args[1] = (unsigned long)kexec_argv;
++	kexec_args[2] = 0;
++	kexec_args[3] = 0;
++
++	reboot_code_buffer = page_address(image->control_code_page);
++	reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
++
++	kexec_args[1] += reloc_delta;
++	for (i = 0; i < argc; i++)
++		kexec_argv[i] += reloc_delta;
++}
++
++int machine_kexec_prepare(struct kimage *kimage)
++{
++	/*
++	 * Whenever arguments passed from kexec-tools, Init the arguments as
++	 * the original ones to try avoiding booting failure.
++	 */
++
++	kexec_args[0] = fw_arg0;
++	kexec_args[1] = fw_arg1;
++	kexec_args[2] = fw_arg2;
++	kexec_args[3] = fw_arg3;
++
++	machine_kexec_init_argv(kimage);
++	machine_kexec_parse_argv(kimage);
++
+ 	if (_machine_kexec_prepare)
+ 		return _machine_kexec_prepare(kimage);
+ 	return 0;
+ }
+ 
+-void
+-machine_kexec_cleanup(struct kimage *kimage)
++void machine_kexec_cleanup(struct kimage *kimage)
+ {
+ }
+ 
+-void
+-machine_shutdown(void)
++void machine_shutdown(void)
+ {
+ 	if (_machine_kexec_shutdown)
+ 		_machine_kexec_shutdown();
+ }
+ 
+-void
+-machine_crash_shutdown(struct pt_regs *regs)
++void machine_crash_shutdown(struct pt_regs *regs)
+ {
+ 	if (_machine_crash_shutdown)
+ 		_machine_crash_shutdown(regs);
+@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image)
+ 	unsigned long *ptr;
+ 
+ 	reboot_code_buffer =
+-	  (unsigned long)page_address(image->control_code_page);
++		(unsigned long)page_address(image->control_code_page);
++	pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
+ 
+ 	kexec_start_address =
+ 		(unsigned long) phys_to_virt(image->start);
++	pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
+ 
+ 	if (image->type == KEXEC_TYPE_DEFAULT) {
+ 		kexec_indirection_page =
+@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image)
+ 	} else {
+ 		kexec_indirection_page = (unsigned long)&image->head;
+ 	}
++	pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
+ 
+-	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
+-	       relocate_new_kernel_size);
++	pr_info("Where is memcpy: %p\n", memcpy);
++	pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
++		(void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
++	pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
++		(void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
++	memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
++	       KEXEC_RELOCATE_NEW_KERNEL_SIZE);
++
++	pr_info("Before _print_args().\n");
++	machine_kexec_print_args();
++	pr_info("Before eval loop.\n");
+ 
+ 	/*
+ 	 * The generic kexec code builds a page list with physical
+@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image)
+ 	/*
+ 	 * we do not want to be bothered.
+ 	 */
++	pr_info("Before irq_disable.\n");
+ 	local_irq_disable();
+ 
+-	printk("Will call new kernel at %08lx\n", image->start);
+-	printk("Bye ...\n");
++	pr_info("Will call new kernel at %08lx\n", image->start);
++	pr_info("Bye ...\n");
+ 	__flush_cache_all();
+ #ifdef CONFIG_SMP
+ 	/* All secondary cpus now may jump to kexec_wait cycle */
+ 	relocated_kexec_smp_wait = reboot_code_buffer +
+-		(void *)(kexec_smp_wait - relocate_new_kernel);
++		(void *)(kexec_smp_wait - kexec_relocate_new_kernel);
+ 	smp_wmb();
+ 	atomic_set(&kexec_ready_to_reboot, 1);
+ #endif
+--- /dev/null
++++ b/arch/mips/kernel/machine_kexec.h
+@@ -0,0 +1,20 @@
++#ifndef _MACHINE_KEXEC_H
++#define _MACHINE_KEXEC_H
++
++#ifndef __ASSEMBLY__
++extern const unsigned char kexec_relocate_new_kernel[];
++extern unsigned long kexec_relocate_new_kernel_end;
++extern unsigned long kexec_start_address;
++extern unsigned long kexec_indirection_page;
++
++extern char kexec_argv_buf[];
++extern char *kexec_argv[];
++
++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE	((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
++#endif /* !__ASSEMBLY__ */
++
++#define KEXEC_COMMAND_LINE_SIZE		256
++#define KEXEC_ARGV_SIZE			(KEXEC_COMMAND_LINE_SIZE / 16)
++#define KEXEC_MAX_ARGC			(KEXEC_ARGV_SIZE / sizeof(long))
++
++#endif
+--- a/arch/mips/kernel/relocate_kernel.S
++++ b/arch/mips/kernel/relocate_kernel.S
+@@ -12,8 +12,9 @@
+ #include <asm/mipsregs.h>
+ #include <asm/stackframe.h>
+ #include <asm/addrspace.h>
++#include "machine_kexec.h"
+ 
+-LEAF(relocate_new_kernel)
++LEAF(kexec_relocate_new_kernel)
+ 	PTR_L a0,	arg0
+ 	PTR_L a1,	arg1
+ 	PTR_L a2,	arg2
+@@ -98,7 +99,7 @@ done:
+ #endif
+ 	/* jump to kexec_start_address */
+ 	j		s1
+-	END(relocate_new_kernel)
++	END(kexec_relocate_new_kernel)
+ 
+ #ifdef CONFIG_SMP
+ /*
+@@ -184,9 +185,15 @@ kexec_indirection_page:
+ 	PTR		0
+ 	.size		kexec_indirection_page, PTRSIZE
+ 
+-relocate_new_kernel_end:
++kexec_argv_buf:
++	EXPORT(kexec_argv_buf)
++	.skip		KEXEC_COMMAND_LINE_SIZE
++	.size		kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
++
++kexec_argv:
++	EXPORT(kexec_argv)
++	.skip		KEXEC_ARGV_SIZE
++	.size		kexec_argv, KEXEC_ARGV_SIZE
+ 
+-relocate_new_kernel_size:
+-	EXPORT(relocate_new_kernel_size)
+-	PTR		relocate_new_kernel_end - relocate_new_kernel
+-	.size		relocate_new_kernel_size, PTRSIZE
++kexec_relocate_new_kernel_end:
++	EXPORT(kexec_relocate_new_kernel_end)
diff --git a/target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch b/target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch
new file mode 100644
index 0000000000..ba64e093a9
--- /dev/null
+++ b/target/linux/generic/patches-4.1/400-mtd-add-rootfs-split-support.patch
@@ -0,0 +1,146 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -12,6 +12,23 @@ menuconfig MTD
+ 
+ if MTD
+ 
++menu "OpenWrt specific MTD options"
++
++config MTD_ROOTFS_ROOT_DEV
++	bool "Automatically set 'rootfs' partition to be root filesystem"
++	default y
++
++config MTD_SPLIT_FIRMWARE
++	bool "Automatically split firmware partition for kernel+rootfs"
++	default y
++
++config MTD_SPLIT_FIRMWARE_NAME
++	string "Firmware partition name"
++	depends on MTD_SPLIT_FIRMWARE
++	default "firmware"
++
++endmenu
++
+ config MTD_TESTS
+ 	tristate "MTD tests support (DANGEROUS)"
+ 	depends on m
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -29,11 +29,13 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/magic.h>
+ #include <linux/of.h>
+ #include <linux/err.h>
+ #include <linux/kconfig.h>
+ 
+ #include "mtdcore.h"
++#include "mtdsplit/mtdsplit.h"
+ 
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+@@ -47,13 +49,14 @@ struct mtd_part {
+ 	struct list_head list;
+ };
+ 
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
++
+ /*
+  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+  * the pointer to that structure with this macro.
+  */
+ #define PART(x)  ((struct mtd_part *)(x))
+ 
+-
+ /*
+  * MTD methods which simply translate the effective address and pass through
+  * to the _real_ device.
+@@ -579,8 +582,10 @@ static int mtd_add_partition_attrs(struc
+ 	return ret;
+ }
+ 
+-int mtd_add_partition(struct mtd_info *master, const char *name,
+-		      long long offset, long long length)
++
++static int
++__mtd_add_partition(struct mtd_info *master, const char *name,
++		    long long offset, long long length, bool dup_check)
+ {
+ 	struct mtd_partition part;
+ 	struct mtd_part *new;
+@@ -612,6 +617,7 @@ int mtd_add_partition(struct mtd_info *m
+ 	mutex_unlock(&mtd_partitions_mutex);
+ 
+ 	add_mtd_device(&new->mtd);
++	mtd_partition_split(master, new);
+ 
+ 	mtd_add_partition_attrs(new);
+ 
+@@ -619,6 +625,12 @@ int mtd_add_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_add_partition);
+ 
++int mtd_add_partition(struct mtd_info *master, const char *name,
++		      long long offset, long long length)
++{
++	return __mtd_add_partition(master, name, offset, length, true);
++}
++
+ int mtd_del_partition(struct mtd_info *master, int partno)
+ {
+ 	struct mtd_part *slave, *next;
+@@ -644,6 +656,35 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#else
++#define SPLIT_FIRMWARE_NAME	"unused"
++#endif
++
++static void split_firmware(struct mtd_info *master, struct mtd_part *part)
++{
++}
++
++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
++                                int offset, int size)
++{
++}
++
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
++{
++	static int rootfs_found = 0;
++
++	if (rootfs_found)
++		return;
++
++	if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
++	    config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
++		split_firmware(master, part);
++
++	arch_split_mtd_part(master, part->mtd.name, part->offset,
++			    part->mtd.size);
++}
+ /*
+  * This function, given a master MTD object and a partition table, creates
+  * and registers slave MTD objects which are bound to the master according to
+@@ -673,6 +714,7 @@ int add_mtd_partitions(struct mtd_info *
+ 		mutex_unlock(&mtd_partitions_mutex);
+ 
+ 		add_mtd_device(&slave->mtd);
++		mtd_partition_split(master, slave);
+ 		mtd_add_partition_attrs(slave);
+ 
+ 		cur_offset = slave->offset + slave->mtd.size;
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
++extern void __weak arch_split_mtd_part(struct mtd_info *master,
++				       const char *name, int offset, int size);
+ 
+ #endif
diff --git a/target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch b/target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch
new file mode 100644
index 0000000000..31dee98efd
--- /dev/null
+++ b/target/linux/generic/patches-4.1/401-mtd-add-support-for-different-partition-parser-types.patch
@@ -0,0 +1,113 @@
+From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Tue, 3 Sep 2013 18:11:50 +0200
+Subject: [PATCH] mtd: add support for different partition parser types
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdpart.c          |   56 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/partitions.h |   11 ++++++++
+ 2 files changed, 67 insertions(+)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -745,6 +745,30 @@ static struct mtd_part_parser *get_parti
+ 
+ #define put_partition_parser(p) do { module_put((p)->owner); } while (0)
+ 
++static struct mtd_part_parser *
++get_partition_parser_by_type(enum mtd_parser_type type,
++			     struct mtd_part_parser *start)
++{
++	struct mtd_part_parser *p, *ret = NULL;
++
++	spin_lock(&part_parser_lock);
++
++	p = list_prepare_entry(start, &part_parsers, list);
++	if (start)
++		put_partition_parser(start);
++
++	list_for_each_entry_continue(p, &part_parsers, list) {
++		if (p->type == type && try_module_get(p->owner)) {
++			ret = p;
++			break;
++		}
++	}
++
++	spin_unlock(&part_parser_lock);
++
++	return ret;
++}
++
+ void register_mtd_parser(struct mtd_part_parser *p)
+ {
+ 	spin_lock(&part_parser_lock);
+@@ -860,6 +884,38 @@ int parse_mtd_partitions(struct mtd_info
+ 	return ret;
+ }
+ 
++int parse_mtd_partitions_by_type(struct mtd_info *master,
++				 enum mtd_parser_type type,
++				 struct mtd_partition **pparts,
++				 struct mtd_part_parser_data *data)
++{
++	struct mtd_part_parser *prev = NULL;
++	int ret = 0;
++
++	while (1) {
++		struct mtd_part_parser *parser;
++
++		parser = get_partition_parser_by_type(type, prev);
++		if (!parser)
++			break;
++
++		ret = (*parser->parse_fn)(master, pparts, data);
++
++		if (ret > 0) {
++			put_partition_parser(parser);
++			printk(KERN_NOTICE
++			       "%d %s partitions found on MTD device %s\n",
++			       ret, parser->name, master->name);
++			break;
++		}
++
++		prev = parser;
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
++
+ int mtd_is_partition(const struct mtd_info *mtd)
+ {
+ 	struct mtd_part *part;
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -68,12 +68,17 @@ struct mtd_part_parser_data {
+  * Functions dealing with the various ways of partitioning the space
+  */
+ 
++enum mtd_parser_type {
++	MTD_PARSER_TYPE_DEVICE = 0,
++};
++
+ struct mtd_part_parser {
+ 	struct list_head list;
+ 	struct module *owner;
+ 	const char *name;
+ 	int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
+ 			struct mtd_part_parser_data *);
++	enum mtd_parser_type type;
+ };
+ 
+ extern void register_mtd_parser(struct mtd_part_parser *parser);
+@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc
+ extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ 				       const char *name, int offset, int size);
+ 
++int parse_mtd_partitions_by_type(struct mtd_info *master,
++				 enum mtd_parser_type type,
++				 struct mtd_partition **pparts,
++				 struct mtd_part_parser_data *data);
++
+ #endif
diff --git a/target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
new file mode 100644
index 0000000000..725dbe8b4d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
@@ -0,0 +1,72 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -656,6 +656,37 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++static int
++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
++{
++	struct mtd_partition *parts;
++	int nr_parts;
++	int i;
++
++	nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts,
++						NULL);
++	if (nr_parts <= 0)
++		return nr_parts;
++
++	if (WARN_ON(!parts))
++		return 0;
++
++	for (i = 0; i < nr_parts; i++) {
++		/* adjust partition offsets */
++		parts[i].offset += slave->offset;
++
++		__mtd_add_partition(slave->master,
++				    parts[i].name,
++				    parts[i].offset,
++				    parts[i].size,
++				    false);
++	}
++
++	kfree(parts);
++
++	return nr_parts;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -664,6 +695,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
+ static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+ {
++	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+ }
+ 
+ void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
+@@ -678,6 +710,12 @@ static void mtd_partition_split(struct m
+ 	if (rootfs_found)
+ 		return;
+ 
++	if (!strcmp(part->mtd.name, "rootfs")) {
++		run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++
++		rootfs_found = 1;
++	}
++
+ 	if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
+ 	    config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
+ 		split_firmware(master, part);
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -70,6 +70,8 @@ struct mtd_part_parser_data {
+ 
+ enum mtd_parser_type {
+ 	MTD_PARSER_TYPE_DEVICE = 0,
++	MTD_PARSER_TYPE_ROOTFS,
++	MTD_PARSER_TYPE_FIRMWARE,
+ };
+ 
+ struct mtd_part_parser {
diff --git a/target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch b/target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch
new file mode 100644
index 0000000000..0cf1c38555
--- /dev/null
+++ b/target/linux/generic/patches-4.1/403-mtd-hook-mtdsplit-to-Kbuild.patch
@@ -0,0 +1,22 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
+ 	depends on MTD_SPLIT_FIRMWARE
+ 	default "firmware"
+ 
++source "drivers/mtd/mtdsplit/Kconfig"
++
+ endmenu
+ 
+ config MTD_TESTS
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -6,6 +6,8 @@
+ obj-$(CONFIG_MTD)		+= mtd.o
+ mtd-y				:= mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
+ 
++obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit/
++
+ obj-$(CONFIG_MTD_OF_PARTS)	+= ofpart.o
+ obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
diff --git a/target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch b/target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch
new file mode 100644
index 0000000000..42e5cfdd45
--- /dev/null
+++ b/target/linux/generic/patches-4.1/404-mtd-add-more-helper-functions.patch
@@ -0,0 +1,101 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -453,14 +453,12 @@ static struct mtd_part *allocate_partiti
+ 	if (slave->offset == MTDPART_OFS_APPEND)
+ 		slave->offset = cur_offset;
+ 	if (slave->offset == MTDPART_OFS_NXTBLK) {
+-		slave->offset = cur_offset;
+-		if (mtd_mod_by_eb(cur_offset, master) != 0) {
+-			/* Round up to next erasesize */
+-			slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
++		/* Round up to next erasesize */
++		slave->offset = mtd_roundup_to_eb(cur_offset, master);
++		if (slave->offset != cur_offset)
+ 			printk(KERN_NOTICE "Moving partition %d: "
+ 			       "0x%012llx -> 0x%012llx\n", partno,
+ 			       (unsigned long long)cur_offset, (unsigned long long)slave->offset);
+-		}
+ 	}
+ 	if (slave->offset == MTDPART_OFS_RETAIN) {
+ 		slave->offset = cur_offset;
+@@ -687,6 +685,17 @@ run_parsers_by_type(struct mtd_part *sla
+ 	return nr_parts;
+ }
+ 
++static inline unsigned long
++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
++{
++	unsigned long mask = mtd->erasesize - 1;
++
++	len += offset & mask;
++	len = (len + mask) & ~mask;
++	len -= offset & mask;
++	return len;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -971,6 +980,24 @@ int mtd_is_partition(const struct mtd_in
+ }
+ EXPORT_SYMBOL_GPL(mtd_is_partition);
+ 
++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return (struct mtd_info *)mtd;
++
++	return PART(mtd)->master;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_master);
++
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return 0;
++
++	return PART(mtd)->offset;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_offset);
++
+ /* Returns the size of the entire flash chip */
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd)
+ {
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in
+ int mtd_add_partition(struct mtd_info *master, const char *name,
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
+ extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ 				       const char *name, int offset, int size);
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -334,6 +334,24 @@ static inline uint32_t mtd_mod_by_eb(uin
+ 	return do_div(sz, mtd->erasesize);
+ }
+ 
++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round up to next erase block */
++	return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
++}
++
++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round down to the start of the current erase block */
++	return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
++}
++
+ static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
+ {
+ 	if (mtd->writesize_shift)
diff --git a/target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch b/target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch
new file mode 100644
index 0000000000..430fd6f025
--- /dev/null
+++ b/target/linux/generic/patches-4.1/405-mtd-old-firmware-uimage-splitter.patch
@@ -0,0 +1,70 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME
+ 	depends on MTD_SPLIT_FIRMWARE
+ 	default "firmware"
+ 
++config MTD_UIMAGE_SPLIT
++	bool "Enable split support for firmware partitions containing a uImage"
++	depends on MTD_SPLIT_FIRMWARE
++	default y
++
+ source "drivers/mtd/mtdsplit/Kconfig"
+ 
+ endmenu
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -696,6 +696,37 @@ mtd_pad_erasesize(struct mtd_info *mtd,
+ 	return len;
+ }
+ 
++#define UBOOT_MAGIC	0x27051956
++
++static void split_uimage(struct mtd_info *master, struct mtd_part *part)
++{
++	struct {
++		__be32 magic;
++		__be32 pad[2];
++		__be32 size;
++	} hdr;
++	size_t len;
++
++	if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr))
++		return;
++
++	if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC))
++		return;
++
++	len = be32_to_cpu(hdr.size) + 0x40;
++	len = mtd_pad_erasesize(master, part->offset, len);
++	if (len + master->erasesize > part->mtd.size)
++		return;
++
++	if (config_enabled(CONFIG_MTD_SPLIT_UIMAGE_FW))
++		pr_err("Dedicated partitioner didn't split firmware partition, please fill a bug report!\n");
++	else
++		pr_warn("Support for built-in firmware splitter will be removed, please use CONFIG_MTD_SPLIT_UIMAGE_FW\n");
++
++	__mtd_add_partition(master, "rootfs", part->offset + len,
++			    part->mtd.size - len, false);
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -704,7 +735,14 @@ mtd_pad_erasesize(struct mtd_info *mtd,
+ 
+ static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+ {
+-	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
++	int ret;
++
++	ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
++	if (ret > 0)
++		return;
++
++	if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT))
++		split_uimage(master, part);
+ }
+ 
+ void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
diff --git a/target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch b/target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
new file mode 100644
index 0000000000..78ebbf88ca
--- /dev/null
+++ b/target/linux/generic/patches-4.1/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
@@ -0,0 +1,18 @@
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -35,6 +35,7 @@
+  * Note: writeable partitions require their size and offset be
+  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
+  */
++struct mtd_info;
+ 
+ struct mtd_partition {
+ 	const char *name;		/* identifier string */
+@@ -50,7 +51,6 @@ struct mtd_partition {
+ #define MTDPART_SIZ_FULL	(0)
+ 
+ 
+-struct mtd_info;
+ struct device_node;
+ 
+ /**
diff --git a/target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch b/target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch
new file mode 100644
index 0000000000..e6e809cf3c
--- /dev/null
+++ b/target/linux/generic/patches-4.1/411-mtd-partial_eraseblock_write.patch
@@ -0,0 +1,142 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -37,6 +37,8 @@
+ #include "mtdcore.h"
+ #include "mtdsplit/mtdsplit.h"
+ 
++#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
++
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+ static DEFINE_MUTEX(mtd_partitions_mutex);
+@@ -235,13 +237,61 @@ static int part_erase(struct mtd_info *m
+ 	struct mtd_part *part = PART(mtd);
+ 	int ret;
+ 
++
++	instr->partial_start = false;
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		size_t readlen = 0;
++		u64 mtd_ofs;
++
++		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
++		if (!instr->erase_buf)
++			return -ENOMEM;
++
++		mtd_ofs = part->offset + instr->addr;
++		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
++
++		if (instr->erase_buf_ofs > 0) {
++			instr->addr -= instr->erase_buf_ofs;
++			ret = mtd_read(part->master,
++				instr->addr + part->offset,
++				part->master->erasesize,
++				&readlen, instr->erase_buf);
++
++			instr->len += instr->erase_buf_ofs;
++			instr->partial_start = true;
++		} else {
++			mtd_ofs = part->offset + part->mtd.size;
++			instr->erase_buf_ofs = part->master->erasesize -
++				do_div(mtd_ofs, part->master->erasesize);
++
++			if (instr->erase_buf_ofs > 0) {
++				instr->len += instr->erase_buf_ofs;
++				ret = mtd_read(part->master,
++					part->offset + instr->addr +
++					instr->len - part->master->erasesize,
++					part->master->erasesize, &readlen,
++					instr->erase_buf);
++			} else {
++				ret = 0;
++			}
++		}
++		if (ret < 0) {
++			kfree(instr->erase_buf);
++			return ret;
++		}
++
++	}
++
+ 	instr->addr += part->offset;
+ 	ret = part->master->_erase(part->master, instr);
+ 	if (ret) {
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+ 		instr->addr -= part->offset;
++		if (mtd->flags & MTD_ERASE_PARTIAL)
++			kfree(instr->erase_buf);
+ 	}
++
+ 	return ret;
+ }
+ 
+@@ -249,7 +299,25 @@ void mtd_erase_callback(struct erase_inf
+ {
+ 	if (instr->mtd->_erase == part_erase) {
+ 		struct mtd_part *part = PART(instr->mtd);
++		size_t wrlen = 0;
+ 
++		if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
++			if (instr->partial_start) {
++				part->master->_write(part->master,
++					instr->addr, instr->erase_buf_ofs,
++					&wrlen, instr->erase_buf);
++				instr->addr += instr->erase_buf_ofs;
++			} else {
++				instr->len -= instr->erase_buf_ofs;
++				part->master->_write(part->master,
++					instr->addr + instr->len,
++					instr->erase_buf_ofs, &wrlen,
++					instr->erase_buf +
++					part->master->erasesize -
++					instr->erase_buf_ofs);
++			}
++			kfree(instr->erase_buf);
++		}
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+ 		instr->addr -= part->offset;
+@@ -522,17 +590,20 @@ static struct mtd_part *allocate_partiti
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
+ 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
+ 		/* Doesn't start on a boundary of major erase size */
+-		/* FIXME: Let it be writable if it is on a boundary of
+-		 * _minor_ erase size though */
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+-			part->name);
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++		if (((u32) slave->mtd.size) > master->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
+-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+-			part->name);
++	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++
++		if ((u32) slave->mtd.size > master->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 
+ 	slave->mtd.ecclayout = master->ecclayout;
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -55,6 +55,10 @@ struct erase_info {
+ 	u_long priv;
+ 	u_char state;
+ 	struct erase_info *next;
++
++	u8 *erase_buf;
++	u32 erase_buf_ofs;
++	bool partial_start;
+ };
+ 
+ struct mtd_erase_region_info {
diff --git a/target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch b/target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch
new file mode 100644
index 0000000000..b7964e25b8
--- /dev/null
+++ b/target/linux/generic/patches-4.1/412-mtd-partial_eraseblock_unlock.patch
@@ -0,0 +1,18 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -336,7 +336,14 @@ static int part_lock(struct mtd_info *mt
+ static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+ 	struct mtd_part *part = PART(mtd);
+-	return part->master->_unlock(part->master, ofs + part->offset, len);
++
++	ofs += part->offset;
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		/* round up len to next erasesize and round down offset to prev block */
++		len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
++		ofs &= ~(part->master->erasesize - 1);
++	}
++	return part->master->_unlock(part->master, ofs, len);
+ }
+ 
+ static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
diff --git a/target/linux/generic/patches-4.1/420-mtd-redboot_space.patch b/target/linux/generic/patches-4.1/420-mtd-redboot_space.patch
new file mode 100644
index 0000000000..f74affcef7
--- /dev/null
+++ b/target/linux/generic/patches-4.1/420-mtd-redboot_space.patch
@@ -0,0 +1,30 @@
+--- a/drivers/mtd/redboot.c
++++ b/drivers/mtd/redboot.c
+@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru
+ #endif
+ 		names += strlen(names)+1;
+ 
+-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ 		if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+-			i++;
+-			parts[i].offset = parts[i-1].size + parts[i-1].offset;
+-			parts[i].size = fl->next->img->flash_base - parts[i].offset;
+-			parts[i].name = nullname;
+-		}
++			if (!strcmp(parts[i].name, "rootfs")) {
++				parts[i].size = fl->next->img->flash_base;
++				parts[i].size &= ~(master->erasesize - 1);
++				parts[i].size -= parts[i].offset;
++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
++				nrparts--;
++			} else {
++				i++;
++				parts[i].offset = parts[i-1].size + parts[i-1].offset;
++				parts[i].size = fl->next->img->flash_base - parts[i].offset;
++				parts[i].name = nullname;
+ #endif
++			}
++		}
+ 		tmp_fl = fl;
+ 		fl = fl->next;
+ 		kfree(tmp_fl);
diff --git a/target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch
new file mode 100644
index 0000000000..fe74ad5927
--- /dev/null
+++ b/target/linux/generic/patches-4.1/430-mtd-add-myloader-partition-parser.patch
@@ -0,0 +1,35 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -179,6 +179,22 @@ config MTD_BCM47XX_PARTS
+ 	  This provides partitions parser for devices based on BCM47xx
+ 	  boards.
+ 
++config MTD_MYLOADER_PARTS
++	tristate "MyLoader partition parsing"
++	depends on ADM5120 || ATH25 || ATH79
++	---help---
++	  MyLoader is a bootloader which allows the user to define partitions
++	  in flash devices, by putting a table in the second erase block
++	  on the device, similar to a partition table. This table gives the 
++	  offsets and lengths of the user defined partitions.
++
++	  If you need code which can detect and parse these tables, and
++	  register MTD 'partitions' corresponding to each image detected,
++	  enable this option.
++
++	  You will still need the parsing functions to be called by the driver
++	  for your particular device. It won't happen automatically.
++
+ comment "User Modules And Translation Layers"
+ 
+ #
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)	+= bcm47xxpart.o
++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
+ 
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS)	+= mtd_blkdevs.o
diff --git a/target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch b/target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
new file mode 100644
index 0000000000..5ad82f1f51
--- /dev/null
+++ b/target/linux/generic/patches-4.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
@@ -0,0 +1,100 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 2 Jan 2016 01:04:52 +0100
+Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating
+ offsets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 50 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 40 insertions(+), 10 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -61,6 +61,34 @@ static void bcm47xxpart_add_part(struct
+ 	part->mask_flags = mask_flags;
+ }
+ 
++/*
++ * Calculate real end offset (address) for a given amount of data. It checks
++ * all blocks skipping bad ones.
++ */
++static size_t bcm47xxpart_real_offset(struct mtd_info *master, size_t offset,
++				      size_t bytes)
++{
++	size_t real_offset = offset;
++
++	if (mtd_block_isbad(master, real_offset))
++		pr_warn("Base offset shouldn't be at bad block");
++
++	while (bytes >= master->erasesize) {
++		bytes -= master->erasesize;
++		real_offset += master->erasesize;
++		while (mtd_block_isbad(master, real_offset)) {
++			real_offset += master->erasesize;
++
++			if (real_offset >= master->size)
++				return real_offset - master->erasesize;
++		}
++	}
++
++	real_offset += bytes;
++
++	return real_offset;
++}
++
+ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
+ 						  size_t offset)
+ {
+@@ -182,6 +210,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
++			uint32_t tmp;
++
+ 			if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
+ 				pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
+ 				break;
+@@ -196,18 +226,18 @@ static int bcm47xxpart_parse(struct mtd_
+ 			i = 0;
+ 			/* We have LZMA loader if offset[2] points to sth */
+ 			if (trx->offset[2]) {
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "loader",
+-						     offset + trx->offset[i],
+-						     0);
++						     "loader", tmp, 0);
+ 				i++;
+ 			}
+ 
+ 			if (trx->offset[i]) {
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "linux",
+-						     offset + trx->offset[i],
+-						     0);
++						     "linux", tmp, 0);
+ 				i++;
+ 			}
+ 
+@@ -219,11 +249,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 			if (trx->offset[i]) {
+ 				const char *name;
+ 
+-				name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
++				name = bcm47xxpart_trx_data_part_name(master, tmp);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     name,
+-						     offset + trx->offset[i],
+-						     0);
++						     name, tmp, 0);
+ 				i++;
+ 			}
+ 
diff --git a/target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
new file mode 100644
index 0000000000..9e5ca91e55
--- /dev/null
+++ b/target/linux/generic/patches-4.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
@@ -0,0 +1,42 @@
+From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 28 Jan 2015 22:14:41 +0100
+Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It can be found on many Netgear devices. It consists of many 0x30 blocks
+starting with 4D 54.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -38,6 +38,7 @@
+ #define NVRAM_HEADER			0x48534C46	/* FLSH */
+ #define POT_MAGIC1			0x54544f50	/* POTT */
+ #define POT_MAGIC2			0x504f		/* OP */
++#define T_METER_MAGIC			0x4D540000	/* MT */
+ #define ML_MAGIC1			0x39685a42
+ #define ML_MAGIC2			0x26594131
+ #define TRX_MAGIC			0x30524448
+@@ -207,6 +208,15 @@ static int bcm47xxpart_parse(struct mtd_
+ 					     MTD_WRITEABLE);
+ 			continue;
+ 		}
++
++		/* T_Meter */
++		if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
++			bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
++					     MTD_WRITEABLE);
++			continue;
++		}
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
diff --git a/target/linux/generic/patches-4.1/440-block2mtd_init.patch b/target/linux/generic/patches-4.1/440-block2mtd_init.patch
new file mode 100644
index 0000000000..eddb593c11
--- /dev/null
+++ b/target/linux/generic/patches-4.1/440-block2mtd_init.patch
@@ -0,0 +1,108 @@
+--- a/drivers/mtd/devices/block2mtd.c
++++ b/drivers/mtd/devices/block2mtd.c
+@@ -25,6 +25,7 @@
+ #include <linux/list.h>
+ #include <linux/init.h>
+ #include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
+ #include <linux/mutex.h>
+ #include <linux/mount.h>
+ #include <linux/slab.h>
+@@ -218,7 +219,7 @@ static void block2mtd_free_device(struct
+ 
+ 
+ static struct block2mtd_dev *add_device(char *devname, int erase_size,
+-		int timeout)
++		const char *mtdname, int timeout)
+ {
+ #ifndef MODULE
+ 	int i;
+@@ -226,6 +227,7 @@ static struct block2mtd_dev *add_device(
+ 	const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
+ 	struct block_device *bdev = ERR_PTR(-ENODEV);
+ 	struct block2mtd_dev *dev;
++	struct mtd_partition *part;
+ 	char *name;
+ 
+ 	if (!devname)
+@@ -282,13 +284,16 @@ static struct block2mtd_dev *add_device(
+ 
+ 	/* Setup the MTD structure */
+ 	/* make the name contain the block device in */
+-	name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
++	if (!mtdname)
++		mtdname = devname;
++	name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
+ 	if (!name)
+ 		goto err_destroy_mutex;
+ 
++	strcpy(name, mtdname);
+ 	dev->mtd.name = name;
+ 
+-	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
++	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
+ 	dev->mtd.erasesize = erase_size;
+ 	dev->mtd.writesize = 1;
+ 	dev->mtd.writebufsize = PAGE_SIZE;
+@@ -301,7 +306,11 @@ static struct block2mtd_dev *add_device(
+ 	dev->mtd.priv = dev;
+ 	dev->mtd.owner = THIS_MODULE;
+ 
+-	if (mtd_device_register(&dev->mtd, NULL, 0)) {
++	part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
++	part->name = name;
++	part->offset = 0;
++	part->size = dev->mtd.size;
++	if (mtd_device_register(&dev->mtd, part, 1)) {
+ 		/* Device didn't get added, so free the entry */
+ 		goto err_destroy_mutex;
+ 	}
+@@ -309,8 +318,7 @@ static struct block2mtd_dev *add_device(
+ 	list_add(&dev->list, &blkmtd_device_list);
+ 	pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
+ 		dev->mtd.index,
+-		dev->mtd.name + strlen("block2mtd: "),
+-		dev->mtd.erasesize >> 10, dev->mtd.erasesize);
++		mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ 	return dev;
+ 
+ err_destroy_mutex:
+@@ -383,7 +391,7 @@ static int block2mtd_setup2(const char *
+ 	/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
+ 	char buf[80 + 12 + 80 + 8];
+ 	char *str = buf;
+-	char *token[2];
++	char *token[3];
+ 	char *name;
+ 	size_t erase_size = PAGE_SIZE;
+ 	unsigned long timeout = MTD_DEFAULT_TIMEOUT;
+@@ -397,7 +405,7 @@ static int block2mtd_setup2(const char *
+ 	strcpy(str, val);
+ 	kill_final_newline(str);
+ 
+-	for (i = 0; i < 2; i++)
++	for (i = 0; i < 3; i++)
+ 		token[i] = strsep(&str, ",");
+ 
+ 	if (str) {
+@@ -423,8 +431,10 @@ static int block2mtd_setup2(const char *
+ 			return 0;
+ 		}
+ 	}
++	if (token[2] && (strlen(token[2]) + 1 > 80))
++		pr_err("mtd device name too long\n");
+ 
+-	add_device(name, erase_size, timeout);
++	add_device(name, erase_size, token[2], timeout);
+ 
+ 	return 0;
+ }
+@@ -458,7 +468,7 @@ static int block2mtd_setup(const char *v
+ 
+ 
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
+ 
+ static int __init block2mtd_init(void)
+ {
diff --git a/target/linux/generic/patches-4.1/441-block2mtd_probe.patch b/target/linux/generic/patches-4.1/441-block2mtd_probe.patch
new file mode 100644
index 0000000000..f78e80aefb
--- /dev/null
+++ b/target/linux/generic/patches-4.1/441-block2mtd_probe.patch
@@ -0,0 +1,39 @@
+--- a/drivers/mtd/devices/block2mtd.c
++++ b/drivers/mtd/devices/block2mtd.c
+@@ -391,7 +391,7 @@ static int block2mtd_setup2(const char *
+ 	/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
+ 	char buf[80 + 12 + 80 + 8];
+ 	char *str = buf;
+-	char *token[3];
++	char *token[4];
+ 	char *name;
+ 	size_t erase_size = PAGE_SIZE;
+ 	unsigned long timeout = MTD_DEFAULT_TIMEOUT;
+@@ -405,7 +405,7 @@ static int block2mtd_setup2(const char *
+ 	strcpy(str, val);
+ 	kill_final_newline(str);
+ 
+-	for (i = 0; i < 3; i++)
++	for (i = 0; i < 4; i++)
+ 		token[i] = strsep(&str, ",");
+ 
+ 	if (str) {
+@@ -434,6 +434,9 @@ static int block2mtd_setup2(const char *
+ 	if (token[2] && (strlen(token[2]) + 1 > 80))
+ 		pr_err("mtd device name too long\n");
+ 
++	if (token[3] && kstrtoul(token[3], 0, &timeout))
++		pr_err("invalid timeout\n");
++
+ 	add_device(name, erase_size, token[2], timeout);
+ 
+ 	return 0;
+@@ -468,7 +471,7 @@ static int block2mtd_setup(const char *v
+ 
+ 
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>[,<timeout>]]]\"");
+ 
+ static int __init block2mtd_init(void)
+ {
diff --git a/target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch b/target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
new file mode 100644
index 0000000000..ffaf70696e
--- /dev/null
+++ b/target/linux/generic/patches-4.1/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
@@ -0,0 +1,37 @@
+---
+ drivers/mtd/nand/plat_nand.c |   13 ++++++++++++-
+ include/linux/mtd/nand.h     |    1 +
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -865,6 +865,7 @@ struct platform_nand_chip {
+ 	unsigned int options;
+ 	unsigned int bbt_options;
+ 	const char **part_probe_types;
++	int (*chip_fixup)(struct mtd_info *mtd);
+ };
+ 
+ /* Keep gcc happy */
+--- a/drivers/mtd/nand/plat_nand.c
++++ b/drivers/mtd/nand/plat_nand.c
+@@ -90,7 +90,18 @@ static int plat_nand_probe(struct platfo
+ 	}
+ 
+ 	/* Scan to find existence of the device */
+-	if (nand_scan(&data->mtd, pdata->chip.nr_chips)) {
++	if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) {
++		err = -ENXIO;
++		goto out;
++	}
++
++	if (pdata->chip.chip_fixup) {
++		err = pdata->chip.chip_fixup(&data->mtd);
++		if (err)
++			goto out;
++	}
++
++	if (nand_scan_tail(&data->mtd)) {
+ 		err = -ENXIO;
+ 		goto out;
+ 	}
diff --git a/target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch b/target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
new file mode 100644
index 0000000000..6a2092ce20
--- /dev/null
+++ b/target/linux/generic/patches-4.1/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/nand/nand_ecc.c
++++ b/drivers/mtd/nand/nand_ecc.c
+@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b
+ 		return 1;	/* error in ECC data; no action needed */
+ 
+ 	pr_err("%s: uncorrectable ECC error\n", __func__);
+-	return -1;
++	return -EBADMSG;
+ }
+ EXPORT_SYMBOL(__nand_correct_data);
+ 
diff --git a/target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
new file mode 100644
index 0000000000..68fbd12466
--- /dev/null
+++ b/target/linux/generic/patches-4.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map
+ 		return 0;
+ 
+ 	case FL_ERASING:
+-		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
++		if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
+ 		    !(mode == FL_READY || mode == FL_POINT ||
+ 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
+ 			goto sleep;
diff --git a/target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
new file mode 100644
index 0000000000..c437a140f0
--- /dev/null
+++ b/target/linux/generic/patches-4.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
@@ -0,0 +1,18 @@
+From: George Kashperko <george@znau.edu.ua>
+
+Issue map read after Write Buffer Load command to ensure chip is ready
+to receive data.
+Signed-off-by: George Kashperko <george@znau.edu.ua>
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    1 +
+ 1 file changed, 1 insertion(+)
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru
+ 
+ 	/* Write Buffer Load */
+ 	map_write(map, CMD(0x25), cmd_adr);
++	(void) map_read(map, cmd_adr);
+ 
+ 	chip->state = FL_WRITING_TO_BUFFER;
+ 
diff --git a/target/linux/generic/patches-4.1/465-m25p80-mx-disable-software-protection.patch b/target/linux/generic/patches-4.1/465-m25p80-mx-disable-software-protection.patch
new file mode 100644
index 0000000000..1d62b4f718
--- /dev/null
+++ b/target/linux/generic/patches-4.1/465-m25p80-mx-disable-software-protection.patch
@@ -0,0 +1,14 @@
+Disable software protection bits for Macronix flashes.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1200,6 +1200,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 
+ 	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ 	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
++	    JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
+ 	    JEDEC_MFR(info) == SNOR_MFR_SST) {
+ 		write_enable(nor);
+ 		write_sr(nor, 0);
diff --git a/target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch
new file mode 100644
index 0000000000..8d3a1f4fff
--- /dev/null
+++ b/target/linux/generic/patches-4.1/480-mtd-set-rootfs-to-be-root-dev.patch
@@ -0,0 +1,26 @@
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -39,6 +39,7 @@
+ #include <linux/slab.h>
+ #include <linux/reboot.h>
+ #include <linux/kconfig.h>
++#include <linux/root_dev.h>
+ 
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -448,6 +449,15 @@ int add_mtd_device(struct mtd_info *mtd)
+ 	   of this try_ nonsense, and no bitching about it
+ 	   either. :) */
+ 	__module_get(THIS_MODULE);
++
++	if (!strcmp(mtd->name, "rootfs") &&
++	    config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("mtd: device %d (%s) set to be root filesystem\n",
++			  mtd->index, mtd->name);
++		ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
++	}
++
+ 	return 0;
+ 
+ fail_added:
diff --git a/target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
new file mode 100644
index 0000000000..7afc1386b1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
@@ -0,0 +1,76 @@
+From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:36:18 +0200
+Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -1221,6 +1221,49 @@ static struct mtd_info * __init open_mtd
+ 	return mtd;
+ }
+ 
++/*
++ * This function tries attaching mtd partitions named either "ubi" or "data"
++ * during boot.
++ */
++static void __init ubi_auto_attach(void)
++{
++	int err;
++	struct mtd_info *mtd;
++
++	/* try attaching mtd device named "ubi" or "data" */
++	mtd = open_mtd_device("ubi");
++	if (IS_ERR(mtd))
++		mtd = open_mtd_device("data");
++
++	if (!IS_ERR(mtd)) {
++		size_t len;
++		char magic[4];
++
++		/* check for a valid ubi magic */
++		err = mtd_read(mtd, 0, 4, &len, (void *) magic);
++		if (!err && len == 4 && strncmp(magic, "UBI#", 4)) {
++			pr_err("UBI error: no valid UBI magic found inside mtd%d", mtd->index);
++			put_mtd_device(mtd);
++			return;
++		}
++
++		/* auto-add only media types where UBI makes sense */
++		if (mtd->type == MTD_NANDFLASH ||
++		    mtd->type == MTD_NORFLASH ||
++		    mtd->type == MTD_DATAFLASH ||
++		    mtd->type == MTD_MLCNANDFLASH) {
++			mutex_lock(&ubi_devices_mutex);
++			pr_notice("UBI: auto-attach mtd%d", mtd->index);
++			err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
++			mutex_unlock(&ubi_devices_mutex);
++			if (err < 0) {
++				pr_err("UBI error: cannot attach mtd%d", mtd->index);
++				put_mtd_device(mtd);
++			}
++		}
++	}
++}
++
+ static int __init ubi_init(void)
+ {
+ 	int err, i, k;
+@@ -1313,6 +1356,12 @@ static int __init ubi_init(void)
+ 		}
+ 	}
+ 
++	/* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
++	 * parameter was given */
++	if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    !ubi_is_module() && !mtd_devs)
++		ubi_auto_attach();
++
+ 	err = ubiblock_init();
+ 	if (err) {
+ 		pr_err("UBI error: block: cannot initialize, error %d", err);
diff --git a/target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
new file mode 100644
index 0000000000..433d77b6c1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
@@ -0,0 +1,69 @@
+From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 21:06:33 +0200
+Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -616,6 +616,44 @@ static void __init ubiblock_create_from_
+ 	}
+ }
+ 
++#define UBIFS_NODE_MAGIC  0x06101831
++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
++{
++	int ret;
++	uint32_t magic_of, magic;
++	ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
++	if (ret)
++		return 0;
++	magic = le32_to_cpu(magic_of);
++	return magic == UBIFS_NODE_MAGIC;
++}
++
++static void __init ubiblock_create_auto_rootfs(void)
++{
++	int ubi_num, ret, is_ubifs;
++	struct ubi_volume_desc *desc;
++	struct ubi_volume_info vi;
++
++	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
++		desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
++		if (IS_ERR(desc))
++			continue;
++
++		ubi_get_volume_info(desc, &vi);
++		is_ubifs = ubi_vol_is_ubifs(desc);
++		ubi_close_volume(desc);
++		if (is_ubifs)
++			break;
++
++		ret = ubiblock_create(&vi);
++		if (ret)
++			pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
++				vi.name, ret);
++		/* always break if we get here */
++		break;
++	}
++}
++
+ static void ubiblock_remove_all(void)
+ {
+ 	struct ubiblock *next;
+@@ -646,6 +684,10 @@ int __init ubiblock_init(void)
+ 	 */
+ 	ubiblock_create_from_param();
+ 
++	/* auto-attach "rootfs" volume if existing and non-ubifs */
++	if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV))
++		ubiblock_create_auto_rootfs();
++
+ 	/*
+ 	 * Block devices are only created upon user requests, so we ignore
+ 	 * existing volumes.
diff --git a/target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
new file mode 100644
index 0000000000..c4a672c964
--- /dev/null
+++ b/target/linux/generic/patches-4.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
@@ -0,0 +1,54 @@
+From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:35:02 +0200
+Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ init/do_mounts.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -438,7 +438,28 @@ retry:
+ out:
+ 	put_page(page);
+ }
+- 
++
++static int __init mount_ubi_rootfs(void)
++{
++	int flags = MS_SILENT;
++	int err, tried = 0;
++
++	while (tried < 2) {
++		err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
++					root_mount_data);
++		switch (err) {
++			case -EACCES:
++				flags |= MS_RDONLY;
++				tried++;
++				break;
++			default:
++				return err;
++		}
++	}
++
++	return -EINVAL;
++}
++
+ #ifdef CONFIG_ROOT_NFS
+ 
+ #define NFSROOT_TIMEOUT_MIN	5
+@@ -532,6 +553,10 @@ void __init mount_root(void)
+ 			change_floppy("root floppy");
+ 	}
+ #endif
++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
++	if (!mount_ubi_rootfs())
++		return;
++#endif
+ #ifdef CONFIG_BLOCK
+ 	create_dev("/dev/root", ROOT_DEV);
+ 	mount_block_root("/dev/root", root_mountflags);
diff --git a/target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
new file mode 100644
index 0000000000..18737524e8
--- /dev/null
+++ b/target/linux/generic/patches-4.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
@@ -0,0 +1,37 @@
+From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 20:55:42 +0200
+Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -49,6 +49,7 @@
+ #include <linux/hdreg.h>
+ #include <linux/scatterlist.h>
+ #include <asm/div64.h>
++#include <linux/root_dev.h>
+ 
+ #include "ubi-media.h"
+ #include "ubi.h"
+@@ -439,6 +440,15 @@ int ubiblock_create(struct ubi_volume_in
+ 	add_disk(dev->gd);
+ 	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
+ 		 dev->ubi_num, dev->vol_id, vi->name);
++
++	if (!strcmp(vi->name, "rootfs") &&
++	    config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
++			  dev->ubi_num, dev->vol_id, vi->name);
++		ROOT_DEV = MKDEV(gd->major, gd->first_minor);
++	}
++
+ 	return 0;
+ 
+ out_free_queue:
diff --git a/target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch
new file mode 100644
index 0000000000..dd5ee306ef
--- /dev/null
+++ b/target/linux/generic/patches-4.1/494-mtd-ubi-add-EOF-marker-support.patch
@@ -0,0 +1,51 @@
+--- a/drivers/mtd/ubi/attach.c
++++ b/drivers/mtd/ubi/attach.c
+@@ -803,6 +803,13 @@ out_unlock:
+ 	return err;
+ }
+ 
++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
++{
++	return ech->padding1[0] == 'E' &&
++	       ech->padding1[1] == 'O' &&
++	       ech->padding1[2] == 'F';
++}
++
+ /**
+  * scan_peb - scan and process UBI headers of a PEB.
+  * @ubi: UBI device description object
+@@ -833,9 +840,21 @@ static int scan_peb(struct ubi_device *u
+ 		return 0;
+ 	}
+ 
+-	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+-	if (err < 0)
+-		return err;
++	if (!ai->eof_found) {
++		err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
++		if (err < 0)
++			return err;
++
++		if (ec_hdr_has_eof(ech)) {
++			pr_notice("UBI: EOF marker found, PEBs from %d will be erased",
++				pnum);
++			ai->eof_found = true;
++		}
++	}
++
++	if (ai->eof_found)
++		err = UBI_IO_FF_BITFLIPS;
++
+ 	switch (err) {
+ 	case 0:
+ 		break;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -741,6 +741,7 @@ struct ubi_attach_info {
+ 	int mean_ec;
+ 	uint64_t ec_sum;
+ 	int ec_count;
++	bool eof_found;
+ 	struct kmem_cache *aeb_slab_cache;
+ };
+ 
diff --git a/target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch b/target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch
new file mode 100644
index 0000000000..2754c1a13d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/500-yaffs-Kbuild-integration.patch
@@ -0,0 +1,18 @@
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -33,6 +33,7 @@ source "fs/ocfs2/Kconfig"
+ source "fs/btrfs/Kconfig"
+ source "fs/nilfs2/Kconfig"
+ source "fs/f2fs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ 
+ config FS_DAX
+ 	bool "Direct Access (DAX) support"
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -127,3 +127,5 @@ obj-y				+= exofs/ # Multiple modules
+ obj-$(CONFIG_CEPH_FS)		+= ceph/
+ obj-$(CONFIG_PSTORE)		+= pstore/
+ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
++obj-$(CONFIG_YAFFS_FS)		+= yaffs2/
++
diff --git a/target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch
new file mode 100644
index 0000000000..a18cf6fd7b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/502-yaffs-fix-compat-tags-handling.patch
@@ -0,0 +1,239 @@
+Subject: yaffs: fix compat tags handling
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+--- a/fs/yaffs2/yaffs_tagscompat.c
++++ b/fs/yaffs2/yaffs_tagscompat.c
+@@ -17,7 +17,9 @@
+ #include "yaffs_getblockinfo.h"
+ #include "yaffs_trace.h"
+ 
++#if 0
+ static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++#endif
+ 
+ 
+ /********** Tags ECC calculations  *********/
+@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
+ 	return 0;
+ }
+ 
++#if 0
+ /********** Tags **********/
+ 
+ static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
+ 	if(!dev->tagger.mark_bad_fn)
+ 		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+ }
++#else
++
++#include "yaffs_packedtags1.h"
++
++static int yaffs_tags_compat_write(struct yaffs_dev *dev,
++				   int nand_chunk,
++				   const u8 *data,
++				   const struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags1 pt1;
++	u8 tag_buf[9];
++	int retval;
++
++	/* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
++	compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
++	compile_time_assertion(sizeof(struct yaffs_tags) == 8);
++
++	yaffs_pack_tags1(&pt1, tags);
++	yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
++
++	/* When deleting a chunk, the upper layer provides only skeletal
++	 * tags, one with is_deleted set.  However, we need to update the
++	 * tags, not erase them completely.  So we use the NAND write property
++	 * that only zeroed-bits stick and set tag bytes to all-ones and
++	 * zero just the (not) deleted bit.
++	 */
++	if (!dev->param.tags_9bytes) {
++		if (tags->is_deleted) {
++			memset(&pt1, 0xff, 8);
++			/* clear delete status bit to indicate deleted */
++			pt1.deleted = 0;
++		}
++		memcpy(tag_buf, &pt1, 8);
++	} else {
++		if (tags->is_deleted) {
++			memset(tag_buf, 0xff, 8);
++			tag_buf[8] = 0;
++		} else {
++			memcpy(tag_buf, &pt1, 8);
++			tag_buf[8] = 0xff;
++		}
++	}
++
++	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++			data,
++			(data) ? dev->data_bytes_per_chunk : 0,
++			tag_buf,
++			(dev->param.tags_9bytes) ? 9 : 8);
++
++	return retval;
++}
++
++/* Return with empty extended tags but add ecc_result.
++ */
++static int return_empty_tags(struct yaffs_ext_tags *tags,
++			     enum yaffs_ecc_result ecc_result,
++			     int retval)
++{
++	if (tags) {
++		memset(tags, 0, sizeof(*tags));
++		tags->ecc_result = ecc_result;
++	}
++
++	return retval;
++}
++
++static int yaffs_tags_compat_read(struct yaffs_dev *dev,
++				  int nand_chunk,
++				  u8 *data,
++				  struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags1 pt1;
++	enum yaffs_ecc_result ecc_result;
++	int retval;
++	int deleted;
++	u8 tag_buf[9];
++
++	retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++			data, dev->param.total_bytes_per_chunk,
++			tag_buf,
++			(dev->param.tags_9bytes) ? 9 : 8,
++			&ecc_result);
++
++	switch (ecc_result) {
++	case YAFFS_ECC_RESULT_NO_ERROR:
++	case YAFFS_ECC_RESULT_FIXED:
++		break;
++
++	case YAFFS_ECC_RESULT_UNFIXED:
++	default:
++		return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
++		tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
++		return YAFFS_FAIL;
++	}
++
++	/* Check for a blank/erased chunk. */
++	if (yaffs_check_ff(tag_buf, 8)) {
++		/* when blank, upper layers want ecc_result to be <= NO_ERROR */
++		return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
++					 YAFFS_OK);
++	}
++
++	memcpy(&pt1, tag_buf, 8);
++
++	if (!dev->param.tags_9bytes) {
++		/* Read deleted status (bit) then return it to it's non-deleted
++		 * state before performing tags mini-ECC check. pt1.deleted is
++		 * inverted.
++		 */
++		deleted = !pt1.deleted;
++		pt1.deleted = 1;
++	} else {
++		deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
++	}
++
++	/* Check the packed tags mini-ECC and correct if necessary/possible. */
++	retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
++	switch (retval) {
++	case 0:
++		/* no tags error, use MTD result */
++		break;
++	case 1:
++		/* recovered tags-ECC error */
++		dev->n_tags_ecc_fixed++;
++		if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
++			ecc_result = YAFFS_ECC_RESULT_FIXED;
++		break;
++	default:
++		/* unrecovered tags-ECC error */
++		dev->n_tags_ecc_unfixed++;
++		return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
++					 YAFFS_FAIL);
++	}
++
++	/* Unpack the tags to extended form and set ECC result.
++	 * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
++	 */
++	pt1.should_be_ff = 0xffffffff;
++	yaffs_unpack_tags1(tags, &pt1);
++	tags->ecc_result = ecc_result;
++
++	/* Set deleted state */
++	tags->is_deleted = deleted;
++	return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++	return dev->drv.drv_mark_bad_fn(dev, block_no);
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++					 int block_no,
++					 enum yaffs_block_state *state,
++					 u32 *seq_number)
++{
++	struct yaffs_ext_tags tags;
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
++
++	*seq_number = 0;
++
++	retval = dev->drv.drv_check_bad_fn(dev, block_no);
++	if (retval == YAFFS_FAIL) {
++		*state = YAFFS_BLOCK_STATE_DEAD;
++		goto out;
++	}
++
++	yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
++			       NULL, &tags);
++
++	if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
++		yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
++			    block_no);
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++	} else if (tags.chunk_used) {
++		*seq_number = tags.seq_number;
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++	} else {
++		*state = YAFFS_BLOCK_STATE_EMPTY;
++	}
++
++	retval = YAFFS_OK;
++
++out:
++	yaffs_trace(YAFFS_TRACE_MTD,
++		    "block query returns seq %u state %d",
++		    *seq_number, *state);
++
++	return retval;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++	if (dev->param.is_yaffs2)
++		return;
++
++	if (!dev->tagger.write_chunk_tags_fn)
++		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
++
++	if (!dev->tagger.read_chunk_tags_fn)
++		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
++
++	if (!dev->tagger.query_block_fn)
++		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++
++	if (!dev->tagger.mark_bad_fn)
++		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
++#endif
diff --git a/target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch
new file mode 100644
index 0000000000..3f51bafc11
--- /dev/null
+++ b/target/linux/generic/patches-4.1/503-yaffs-add-tags-9bytes-mount-option.patch
@@ -0,0 +1,115 @@
+Subject: yaffs: add support for tags-9bytes mount option
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -2644,6 +2644,7 @@ static const struct super_operations yaf
+ 
+ struct yaffs_options {
+ 	int inband_tags;
++	int tags_9bytes;
+ 	int skip_checkpoint_read;
+ 	int skip_checkpoint_write;
+ 	int no_cache;
+@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya
+ 
+ 		if (!strcmp(cur_opt, "inband-tags")) {
+ 			options->inband_tags = 1;
++		} else if (!strcmp(cur_opt, "tags-9bytes")) {
++			options->tags_9bytes = 1;
+ 		} else if (!strcmp(cur_opt, "tags-ecc-off")) {
+ 			options->tags_ecc_on = 0;
+ 			options->tags_ecc_overridden = 1;
+@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna
+ 	struct yaffs_param *param;
+ 
+ 	int read_only = 0;
+-	int inband_tags = 0;
+ 
+ 	struct yaffs_options options;
+ 
+@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna
+ 
+ 	memset(&options, 0, sizeof(options));
+ 
++	if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS))
++		options.tags_9bytes = 1;
++
+ 	if (yaffs_parse_options(&options, data_str)) {
+ 		/* Option parsing failed */
+ 		return NULL;
+@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna
+ 	}
+ 
+ 	/* Added NCB 26/5/2006 for completeness */
+-	if (yaffs_version == 2 && !options.inband_tags
+-	    && WRITE_SIZE(mtd) == 512) {
++	if (yaffs_version == 2 &&
++	    (!options.inband_tags || options.tags_9bytes) &&
++	    WRITE_SIZE(mtd) == 512) {
+ 		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
+ 		yaffs_version = 1;
+ 	}
+ 
+-	if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
+-	    options.inband_tags)
+-		inband_tags = 1;
++	if (yaffs_version == 2 &&
++	    mtd->oobavail < sizeof(struct yaffs_packed_tags2)) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags");
++		options.inband_tags = 1;
++	}
+ 
+-	if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++	err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags,
++			       options.tags_9bytes);
++	if (err < 0)
+ 		return NULL;
+ 
+ 	/* OK, so if we got here, we have an MTD that's NAND and looks
+@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna
+ 
+ 	param->n_reserved_blocks = 5;
+ 	param->n_caches = (options.no_cache) ? 0 : 10;
+-	param->inband_tags = inband_tags;
++	param->inband_tags = options.inband_tags;
++	param->tags_9bytes = options.tags_9bytes;
+ 
+ 	param->enable_xattr = 1;
+ 	if (options.lazy_loading_overridden)
+--- a/fs/yaffs2/yaffs_mtdif.c
++++ b/fs/yaffs2/yaffs_mtdif.c
+@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d
+ 	return mtd;
+ }
+ 
+-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
++		     int tags_9bytes)
+ {
+ 	if (yaffs_version == 2) {
+ 		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt
+ 			);
+ 			return -1;
+ 		}
++
++		if (tags_9bytes && mtd->oobavail < 9) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				    "MTD device does not support 9-byte tags");
++			return -1;
++		}
+ 	}
+ 
+ 	return 0;
+--- a/fs/yaffs2/yaffs_mtdif.h
++++ b/fs/yaffs2/yaffs_mtdif.h
+@@ -21,5 +21,6 @@
+ void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+ struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
+ void yaffs_put_mtd_device(struct mtd_info *mtd);
+-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
++		     int tags_9bytes);
+ #endif
diff --git a/target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch
new file mode 100644
index 0000000000..32b4fdfa39
--- /dev/null
+++ b/target/linux/generic/patches-4.1/504-yaffs-3.16-new-fops.patch
@@ -0,0 +1,29 @@
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -774,7 +774,25 @@ static int yaffs_sync_object(struct file
+ }
+ 
+ 
+-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
++static const struct file_operations yaffs_file_operations = {
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
++	.read = new_sync_read,
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */
++	.read_iter = generic_file_read_iter,
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
++	.write = new_sync_write,
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */
++	.write_iter = generic_file_write_iter,
++	.mmap = generic_file_mmap,
++	.flush = yaffs_file_flush,
++	.fsync = yaffs_sync_object,
++	.splice_read = generic_file_splice_read,
++	.splice_write = iter_file_splice_write,
++	.llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+ static const struct file_operations yaffs_file_operations = {
+ 	.read = do_sync_read,
+ 	.write = do_sync_write,
diff --git a/target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch b/target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch
new file mode 100644
index 0000000000..0d4b6bf04f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/505-yaffs-3.19-f_dentry-remove.patch
@@ -0,0 +1,95 @@
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -283,7 +283,7 @@ static int yaffs_readpage_nolock(struct
+ 		(long long)pos,
+ 		(unsigned)PAGE_CACHE_SIZE);
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	dev = obj->my_dev;
+ 
+@@ -481,7 +481,7 @@ static ssize_t yaffs_hold_space(struct f
+ 
+ 	int n_free_chunks;
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	dev = obj->my_dev;
+ 
+@@ -499,7 +499,7 @@ static void yaffs_release_space(struct f
+ 	struct yaffs_obj *obj;
+ 	struct yaffs_dev *dev;
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	dev = obj->my_dev;
+ 
+@@ -591,7 +591,7 @@ static ssize_t yaffs_file_write(struct f
+ 	struct inode *inode;
+ 	struct yaffs_dev *dev;
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	if (!obj) {
+ 		yaffs_trace(YAFFS_TRACE_OS,
+@@ -603,7 +603,7 @@ static ssize_t yaffs_file_write(struct f
+ 
+ 	yaffs_gross_lock(dev);
+ 
+-	inode = f->f_dentry->d_inode;
++	inode = f->f_path.dentry->d_inode;
+ 
+ 	if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
+ 		ipos = inode->i_size;
+@@ -727,7 +727,7 @@ static int yaffs_file_flush(struct file
+ static int yaffs_file_flush(struct file *file)
+ #endif
+ {
+-	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_path.dentry);
+ 
+ 	struct yaffs_dev *dev = obj->my_dev;
+ 
+@@ -1734,7 +1734,7 @@ static int yaffs_iterate(struct file *f,
+ 
+ 	char name[YAFFS_MAX_NAME_LENGTH + 1];
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 	dev = obj->my_dev;
+ 
+ 	yaffs_gross_lock(dev);
+@@ -1798,14 +1798,14 @@ static int yaffs_readdir(struct file *f,
+ 	struct yaffs_obj *obj;
+ 	struct yaffs_dev *dev;
+ 	struct yaffs_search_context *sc;
+-	struct inode *inode = f->f_dentry->d_inode;
++	struct inode *inode = f->f_path.dentry->d_inode;
+ 	unsigned long offset, curoffs;
+ 	struct yaffs_obj *l;
+ 	int ret_val = 0;
+ 
+ 	char name[YAFFS_MAX_NAME_LENGTH + 1];
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 	dev = obj->my_dev;
+ 
+ 	yaffs_gross_lock(dev);
+@@ -1839,10 +1839,10 @@ static int yaffs_readdir(struct file *f,
+ 	if (offset == 1) {
+ 		yaffs_trace(YAFFS_TRACE_OS,
+ 			"yaffs_readdir: entry .. ino %d",
+-			(int)f->f_dentry->d_parent->d_inode->i_ino);
++			(int)f->f_path.dentry->d_parent->d_inode->i_ino);
+ 		yaffs_gross_unlock(dev);
+ 		if (filldir(dirent, "..", 2, offset,
+-			    f->f_dentry->d_parent->d_inode->i_ino,
++			    f->f_path.dentry->d_parent->d_inode->i_ino,
+ 			    DT_DIR) < 0) {
+ 			yaffs_gross_lock(dev);
+ 			goto out;
diff --git a/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch
new file mode 100644
index 0000000000..c8301f00c8
--- /dev/null
+++ b/target/linux/generic/patches-4.1/530-jffs2_make_lzma_available.patch
@@ -0,0 +1,5142 @@
+--- a/fs/jffs2/Kconfig
++++ b/fs/jffs2/Kconfig
+@@ -139,6 +139,15 @@ config JFFS2_LZO
+ 	  This feature was added in July, 2007. Say 'N' if you need
+ 	  compatibility with older bootloaders or kernels.
+ 
++config JFFS2_LZMA
++	bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS
++	select LZMA_COMPRESS
++	select LZMA_DECOMPRESS
++	depends on JFFS2_FS
++	default n
++	help
++	  JFFS2 wrapper to the LZMA C SDK
++
+ config JFFS2_RTIME
+ 	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+ 	depends on JFFS2_FS
+--- a/fs/jffs2/Makefile
++++ b/fs/jffs2/Makefile
+@@ -18,4 +18,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rub
+ jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
+ jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
+ jffs2-$(CONFIG_JFFS2_LZO)	+= compr_lzo.o
++jffs2-$(CONFIG_JFFS2_LZMA)      += compr_lzma.o
+ jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
++
++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma
+--- a/fs/jffs2/compr.c
++++ b/fs/jffs2/compr.c
+@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_init();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_init();
++#endif
+ /* Setting default compression mode */
+ #ifdef CONFIG_JFFS2_CMODE_NONE
+ 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void)
+ int jffs2_compressors_exit(void)
+ {
+ /* Unregistering compressors */
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_exit();
++#endif
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_exit();
+ #endif
+--- a/fs/jffs2/compr.h
++++ b/fs/jffs2/compr.h
+@@ -29,9 +29,9 @@
+ #define JFFS2_DYNRUBIN_PRIORITY  20
+ #define JFFS2_LZARI_PRIORITY     30
+ #define JFFS2_RTIME_PRIORITY     50
+-#define JFFS2_ZLIB_PRIORITY      60
+-#define JFFS2_LZO_PRIORITY       80
+-
++#define JFFS2_LZMA_PRIORITY      70
++#define JFFS2_ZLIB_PRIORITY      80
++#define JFFS2_LZO_PRIORITY       90
+ 
+ #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
+ #define JFFS2_DYNRUBIN_DISABLED  /*	   for decompression */
+@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void);
+ int jffs2_lzo_init(void);
+ void jffs2_lzo_exit(void);
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++int jffs2_lzma_init(void);
++void jffs2_lzma_exit(void);
++#endif
+ 
+ #endif /* __JFFS2_COMPR_H__ */
+--- /dev/null
++++ b/fs/jffs2/compr_lzma.c
+@@ -0,0 +1,128 @@
++/*
++ * JFFS2 -- Journalling Flash File System, Version 2.
++ *
++ * For licensing information, see the file 'LICENCE' in this directory.
++ *
++ * JFFS2 wrapper to the LZMA C SDK
++ *
++ */
++
++#include <linux/lzma.h>
++#include "compr.h"
++
++#ifdef __KERNEL__
++	static DEFINE_MUTEX(deflate_mutex);
++#endif
++
++CLzmaEncHandle *p;
++Byte propsEncoded[LZMA_PROPS_SIZE];
++SizeT propsSize = sizeof(propsEncoded);
++
++STATIC void lzma_free_workspace(void)
++{
++	LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
++}
++
++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
++{
++	if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
++	{
++		PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
++		return -ENOMEM;
++	}
++
++	if (LzmaEnc_SetProps(p, props) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++	
++	if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++        return 0;
++}
++
++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
++			      uint32_t *sourcelen, uint32_t *dstlen)
++{
++	SizeT compress_size = (SizeT)(*dstlen);
++	int ret;
++
++	#ifdef __KERNEL__
++		mutex_lock(&deflate_mutex);
++	#endif
++
++	ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
++		0, NULL, &lzma_alloc, &lzma_alloc);
++
++	#ifdef __KERNEL__
++		mutex_unlock(&deflate_mutex);
++	#endif
++
++	if (ret != SZ_OK)
++		return -1;
++
++	*dstlen = (uint32_t)compress_size;
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
++				 uint32_t srclen, uint32_t destlen)
++{
++	int ret;
++	SizeT dl = (SizeT)destlen;
++	SizeT sl = (SizeT)srclen;
++	ELzmaStatus status;
++	
++	ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
++		propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
++
++	if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
++		return -1;
++
++	return 0;
++}
++
++static struct jffs2_compressor jffs2_lzma_comp = {
++	.priority = JFFS2_LZMA_PRIORITY,
++	.name = "lzma",
++	.compr = JFFS2_COMPR_LZMA,
++	.compress = &jffs2_lzma_compress,
++	.decompress = &jffs2_lzma_decompress,
++	.disabled = 0,
++};
++
++int INIT jffs2_lzma_init(void)
++{
++        int ret;
++	CLzmaEncProps props;
++	LzmaEncProps_Init(&props);
++
++        props.dictSize = LZMA_BEST_DICT(0x2000);
++        props.level = LZMA_BEST_LEVEL;
++        props.lc = LZMA_BEST_LC;
++        props.lp = LZMA_BEST_LP;
++        props.pb = LZMA_BEST_PB;
++        props.fb = LZMA_BEST_FB;
++
++	ret = lzma_alloc_workspace(&props);
++        if (ret < 0)
++                return ret;
++
++	ret = jffs2_register_compressor(&jffs2_lzma_comp);
++	if (ret)
++		lzma_free_workspace();
++	
++        return ret;
++}
++
++void jffs2_lzma_exit(void)
++{
++	jffs2_unregister_compressor(&jffs2_lzma_comp);
++	lzma_free_workspace();
++}
+--- a/fs/jffs2/super.c
++++ b/fs/jffs2/super.c
+@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void)
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
+ 
+-	pr_info("version 2.2."
++	pr_info("version 2.2"
+ #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ 	       " (NAND)"
+ #endif
+ #ifdef CONFIG_JFFS2_SUMMARY
+-	       " (SUMMARY) "
++	       " (SUMMARY)"
+ #endif
+-	       " © 2001-2006 Red Hat, Inc.\n");
++#ifdef CONFIG_JFFS2_ZLIB
++	       " (ZLIB)"
++#endif
++#ifdef CONFIG_JFFS2_LZO
++	       " (LZO)"
++#endif
++#ifdef CONFIG_JFFS2_LZMA
++	       " (LZMA)"
++#endif
++#ifdef CONFIG_JFFS2_RTIME
++	       " (RTIME)"
++#endif
++#ifdef CONFIG_JFFS2_RUBIN
++	       " (RUBIN)"
++#endif
++#ifdef  CONFIG_JFFS2_CMODE_NONE
++	       " (CMODE_NONE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_PRIORITY
++	       " (CMODE_PRIORITY)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_SIZE
++	       " (CMODE_SIZE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
++	       " (CMODE_FAVOURLZO)"
++#endif
++	       " (c) 2001-2006 Red Hat, Inc.\n");
+ 
+ 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
+ 					     sizeof(struct jffs2_inode_info),
+--- a/include/uapi/linux/jffs2.h
++++ b/include/uapi/linux/jffs2.h
+@@ -46,6 +46,7 @@
+ #define JFFS2_COMPR_DYNRUBIN	0x05
+ #define JFFS2_COMPR_ZLIB	0x06
+ #define JFFS2_COMPR_LZO		0x07
++#define JFFS2_COMPR_LZMA	0x08
+ /* Compatibility flags. */
+ #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+ #define JFFS2_NODE_ACCURATE 0x2000
+--- /dev/null
++++ b/include/linux/lzma.h
+@@ -0,0 +1,62 @@
++#ifndef __LZMA_H__
++#define __LZMA_H__
++
++#ifdef __KERNEL__
++	#include <linux/kernel.h>
++	#include <linux/sched.h>
++	#include <linux/slab.h>
++	#include <linux/vmalloc.h>
++	#include <linux/init.h>
++	#define LZMA_MALLOC vmalloc
++	#define LZMA_FREE vfree
++	#define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
++	#define INIT __init
++	#define STATIC static
++#else
++	#include <stdint.h>
++	#include <stdlib.h>
++	#include <stdio.h>
++	#include <unistd.h>
++	#include <string.h>
++	#include <asm/types.h>
++	#include <errno.h>
++	#include <linux/jffs2.h>
++	#ifndef PAGE_SIZE
++		extern int page_size;
++		#define PAGE_SIZE page_size
++	#endif
++	#define LZMA_MALLOC malloc
++	#define LZMA_FREE free
++	#define PRINT_ERROR(msg) fprintf(stderr, msg)
++	#define INIT
++	#define STATIC
++#endif
++
++#include "lzma/LzmaDec.h"
++#include "lzma/LzmaEnc.h"
++
++#define LZMA_BEST_LEVEL (9)
++#define LZMA_BEST_LC    (0)
++#define LZMA_BEST_LP    (0)
++#define LZMA_BEST_PB    (0)
++#define LZMA_BEST_FB  (273)
++
++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
++
++static void *p_lzma_malloc(void *p, size_t size)
++{
++        if (size == 0)
++                return NULL;
++
++        return LZMA_MALLOC(size);
++}
++
++static void p_lzma_free(void *p, void *address)
++{
++        if (address != NULL)
++                LZMA_FREE(address);
++}
++
++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free};
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzFind.h
+@@ -0,0 +1,115 @@
++/* LzFind.h -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_FIND_H
++#define __LZ_FIND_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef UInt32 CLzRef;
++
++typedef struct _CMatchFinder
++{
++  Byte *buffer;
++  UInt32 pos;
++  UInt32 posLimit;
++  UInt32 streamPos;
++  UInt32 lenLimit;
++
++  UInt32 cyclicBufferPos;
++  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
++
++  UInt32 matchMaxLen;
++  CLzRef *hash;
++  CLzRef *son;
++  UInt32 hashMask;
++  UInt32 cutValue;
++
++  Byte *bufferBase;
++  ISeqInStream *stream;
++  int streamEndWasReached;
++
++  UInt32 blockSize;
++  UInt32 keepSizeBefore;
++  UInt32 keepSizeAfter;
++
++  UInt32 numHashBytes;
++  int directInput;
++  size_t directInputRem;
++  int btMode;
++  int bigHash;
++  UInt32 historySize;
++  UInt32 fixedHashSize;
++  UInt32 hashSizeSum;
++  UInt32 numSons;
++  SRes result;
++  UInt32 crc[256];
++} CMatchFinder;
++
++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
++
++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
++
++int MatchFinder_NeedMove(CMatchFinder *p);
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
++void MatchFinder_MoveBlock(CMatchFinder *p);
++void MatchFinder_ReadIfRequired(CMatchFinder *p);
++
++void MatchFinder_Construct(CMatchFinder *p);
++
++/* Conditions:
++     historySize <= 3 GB
++     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
++*/
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc);
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
++    UInt32 *distances, UInt32 maxLen);
++
++/*
++Conditions:
++  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
++  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
++*/
++
++typedef void (*Mf_Init_Func)(void *object);
++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
++typedef void (*Mf_Skip_Func)(void *object, UInt32);
++
++typedef struct _IMatchFinder
++{
++  Mf_Init_Func Init;
++  Mf_GetIndexByte_Func GetIndexByte;
++  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
++  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
++  Mf_GetMatches_Func GetMatches;
++  Mf_Skip_Func Skip;
++} IMatchFinder;
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
++
++void MatchFinder_Init(CMatchFinder *p);
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzHash.h
+@@ -0,0 +1,54 @@
++/* LzHash.h -- HASH functions for LZ algorithms
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_HASH_H
++#define __LZ_HASH_H
++
++#define kHash2Size (1 << 10)
++#define kHash3Size (1 << 16)
++#define kHash4Size (1 << 20)
++
++#define kFix3HashSize (kHash2Size)
++#define kFix4HashSize (kHash2Size + kHash3Size)
++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
++
++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
++
++#define HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
++
++#define HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
++
++#define HASH5_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
++  hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
++  hash4Value &= (kHash4Size - 1); }
++
++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
++
++
++#define MT_HASH2_CALC \
++  hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
++
++#define MT_HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
++
++#define MT_HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaDec.h
+@@ -0,0 +1,231 @@
++/* LzmaDec.h -- LZMA Decoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_DEC_H
++#define __LZMA_DEC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* #define _LZMA_PROB32 */
++/* _LZMA_PROB32 can increase the speed on some CPUs,
++   but memory usage for CLzmaDec::probs will be doubled in that case */
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++
++/* ---------- LZMA Properties ---------- */
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaProps
++{
++  unsigned lc, lp, pb;
++  UInt32 dicSize;
++} CLzmaProps;
++
++/* LzmaProps_Decode - decodes properties
++Returns:
++  SZ_OK
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
++
++
++/* ---------- LZMA Decoder state ---------- */
++
++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
++   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
++
++#define LZMA_REQUIRED_INPUT_MAX 20
++
++typedef struct
++{
++  CLzmaProps prop;
++  CLzmaProb *probs;
++  Byte *dic;
++  const Byte *buf;
++  UInt32 range, code;
++  SizeT dicPos;
++  SizeT dicBufSize;
++  UInt32 processedPos;
++  UInt32 checkDicSize;
++  unsigned state;
++  UInt32 reps[4];
++  unsigned remainLen;
++  int needFlush;
++  int needInitState;
++  UInt32 numProbs;
++  unsigned tempBufSize;
++  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
++} CLzmaDec;
++
++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
++
++void LzmaDec_Init(CLzmaDec *p);
++
++/* There are two types of LZMA streams:
++     0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
++     1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
++
++typedef enum
++{
++  LZMA_FINISH_ANY,   /* finish at any point */
++  LZMA_FINISH_END    /* block must be finished at the end */
++} ELzmaFinishMode;
++
++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
++
++   You must use LZMA_FINISH_END, when you know that current output buffer
++   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
++
++   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
++   and output value of destLen will be less than output buffer size limit.
++   You can check status result also.
++
++   You can use multiple checks to test data integrity after full decompression:
++     1) Check Result and "status" variable.
++     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
++     3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
++        You must use correct finish mode in that case. */
++
++typedef enum
++{
++  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
++  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
++  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
++  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */
++  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
++} ELzmaStatus;
++
++/* ELzmaStatus is used only as output value for function call */
++
++
++/* ---------- Interfaces ---------- */
++
++/* There are 3 levels of interfaces:
++     1) Dictionary Interface
++     2) Buffer Interface
++     3) One Call Interface
++   You can select any of these interfaces, but don't mix functions from different
++   groups for same object. */
++
++
++/* There are two variants to allocate state for Dictionary Interface:
++     1) LzmaDec_Allocate / LzmaDec_Free
++     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
++   You can use variant 2, if you set dictionary buffer manually.
++   For Buffer Interface you must always use variant 1.
++
++LzmaDec_Allocate* can return:
++  SZ_OK
++  SZ_ERROR_MEM         - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++   
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
++
++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
++
++/* ---------- Dictionary Interface ---------- */
++
++/* You can use it, if you want to eliminate the overhead for data copying from
++   dictionary to some other external buffer.
++   You must work with CLzmaDec variables directly in this interface.
++
++   STEPS:
++     LzmaDec_Constr()
++     LzmaDec_Allocate()
++     for (each new stream)
++     {
++       LzmaDec_Init()
++       while (it needs more decompression)
++       {
++         LzmaDec_DecodeToDic()
++         use data from CLzmaDec::dic and update CLzmaDec::dicPos
++       }
++     }
++     LzmaDec_Free()
++*/
++
++/* LzmaDec_DecodeToDic
++   
++   The decoding to internal dictionary buffer (CLzmaDec::dic).
++   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (dicLimit).
++  LZMA_FINISH_ANY - Decode just dicLimit bytes.
++  LZMA_FINISH_END - Stream must be finished after dicLimit.
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_NEEDS_MORE_INPUT
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++*/
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- Buffer Interface ---------- */
++
++/* It's zlib-like interface.
++   See LzmaDec_DecodeToDic description for information about STEPS and return results,
++   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
++   to work with CLzmaDec variables manually.
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++*/
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaDecode
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++  SZ_ERROR_MEM  - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
++*/
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -0,0 +1,80 @@
++/*  LzmaEnc.h -- LZMA Encoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_ENC_H
++#define __LZMA_ENC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaEncProps
++{
++  int level;       /*  0 <= level <= 9 */
++  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
++                      (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
++                       default = (1 << 24) */
++  int lc;          /* 0 <= lc <= 8, default = 3 */
++  int lp;          /* 0 <= lp <= 4, default = 0 */
++  int pb;          /* 0 <= pb <= 4, default = 2 */
++  int algo;        /* 0 - fast, 1 - normal, default = 1 */
++  int fb;          /* 5 <= fb <= 273, default = 32 */
++  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
++  int numHashBytes; /* 2, 3 or 4, default = 4 */
++  UInt32 mc;        /* 1 <= mc <= (1 << 30), default = 32 */
++  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
++  int numThreads;  /* 1 or 2, default = 2 */
++} CLzmaEncProps;
++
++void LzmaEncProps_Init(CLzmaEncProps *p);
++void LzmaEncProps_Normalize(CLzmaEncProps *p);
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
++
++
++/* ---------- CLzmaEncHandle Interface ---------- */
++
++/* LzmaEnc_* functions can return the following exit codes:
++Returns:
++  SZ_OK           - OK
++  SZ_ERROR_MEM    - Memory allocation error
++  SZ_ERROR_PARAM  - Incorrect paramater in props
++  SZ_ERROR_WRITE  - Write callback error.
++  SZ_ERROR_PROGRESS - some break from progress callback
++  SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
++*/
++
++typedef void * CLzmaEncHandle;
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaEncode
++Return code:
++  SZ_OK               - OK
++  SZ_ERROR_MEM        - Memory allocation error
++  SZ_ERROR_PARAM      - Incorrect paramater
++  SZ_ERROR_OUTPUT_EOF - output buffer overflow
++  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
++*/
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/Types.h
+@@ -0,0 +1,226 @@
++/* Types.h -- Basic types
++2009-11-23 : Igor Pavlov : Public domain */
++
++#ifndef __7Z_TYPES_H
++#define __7Z_TYPES_H
++
++#include <stddef.h>
++
++#ifdef _WIN32
++#include <windows.h>
++#endif
++
++#ifndef EXTERN_C_BEGIN
++#ifdef __cplusplus
++#define EXTERN_C_BEGIN extern "C" {
++#define EXTERN_C_END }
++#else
++#define EXTERN_C_BEGIN
++#define EXTERN_C_END
++#endif
++#endif
++
++EXTERN_C_BEGIN
++
++#define SZ_OK 0
++
++#define SZ_ERROR_DATA 1
++#define SZ_ERROR_MEM 2
++#define SZ_ERROR_CRC 3
++#define SZ_ERROR_UNSUPPORTED 4
++#define SZ_ERROR_PARAM 5
++#define SZ_ERROR_INPUT_EOF 6
++#define SZ_ERROR_OUTPUT_EOF 7
++#define SZ_ERROR_READ 8
++#define SZ_ERROR_WRITE 9
++#define SZ_ERROR_PROGRESS 10
++#define SZ_ERROR_FAIL 11
++#define SZ_ERROR_THREAD 12
++
++#define SZ_ERROR_ARCHIVE 16
++#define SZ_ERROR_NO_ARCHIVE 17
++
++typedef int SRes;
++
++#ifdef _WIN32
++typedef DWORD WRes;
++#else
++typedef int WRes;
++#endif
++
++#ifndef RINOK
++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
++#endif
++
++typedef unsigned char Byte;
++typedef short Int16;
++typedef unsigned short UInt16;
++
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef long Int32;
++typedef unsigned long UInt32;
++#else
++typedef int Int32;
++typedef unsigned int UInt32;
++#endif
++
++#ifdef _SZ_NO_INT_64
++
++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
++   NOTES: Some code will work incorrectly in that case! */
++
++typedef long Int64;
++typedef unsigned long UInt64;
++
++#else
++
++#if defined(_MSC_VER) || defined(__BORLANDC__)
++typedef __int64 Int64;
++typedef unsigned __int64 UInt64;
++#else
++typedef long long int Int64;
++typedef unsigned long long int UInt64;
++#endif
++
++#endif
++
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++typedef size_t SizeT;
++#endif
++
++typedef int Bool;
++#define True 1
++#define False 0
++
++
++#ifdef _WIN32
++#define MY_STD_CALL __stdcall
++#else
++#define MY_STD_CALL
++#endif
++
++#ifdef _MSC_VER
++
++#if _MSC_VER >= 1300
++#define MY_NO_INLINE __declspec(noinline)
++#else
++#define MY_NO_INLINE
++#endif
++
++#define MY_CDECL __cdecl
++#define MY_FAST_CALL __fastcall
++
++#else
++
++#define MY_CDECL
++#define MY_FAST_CALL
++
++#endif
++
++
++/* The following interfaces use first parameter as pointer to structure */
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) < input(*size)) is allowed */
++} ISeqInStream;
++
++/* it can return SZ_ERROR_INPUT_EOF */
++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
++
++typedef struct
++{
++  size_t (*Write)(void *p, const void *buf, size_t size);
++    /* Returns: result - the number of actually written bytes.
++       (result < size) means error */
++} ISeqOutStream;
++
++typedef enum
++{
++  SZ_SEEK_SET = 0,
++  SZ_SEEK_CUR = 1,
++  SZ_SEEK_END = 2
++} ESzSeek;
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);  /* same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ISeekInStream;
++
++typedef struct
++{
++  SRes (*Look)(void *p, void **buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) > input(*size)) is not allowed
++       (output(*size) < input(*size)) is allowed */
++  SRes (*Skip)(void *p, size_t offset);
++    /* offset must be <= output(*size) of Look */
++
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* reads directly (without buffer). It's same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ILookInStream;
++
++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
++
++/* reads via ILookInStream::Read */
++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
++
++#define LookToRead_BUF_SIZE (1 << 14)
++
++typedef struct
++{
++  ILookInStream s;
++  ISeekInStream *realStream;
++  size_t pos;
++  size_t size;
++  Byte buf[LookToRead_BUF_SIZE];
++} CLookToRead;
++
++void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
++void LookToRead_Init(CLookToRead *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToLook;
++
++void SecToLook_CreateVTable(CSecToLook *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToRead;
++
++void SecToRead_CreateVTable(CSecToRead *p);
++
++typedef struct
++{
++  SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
++    /* Returns: result. (result != SZ_OK) means break.
++       Value (UInt64)(Int64)-1 for size means unknown value. */
++} ICompressProgress;
++
++typedef struct
++{
++  void *(*Alloc)(void *p, size_t size);
++  void (*Free)(void *p, void *address); /* address can be 0 */
++} ISzAlloc;
++
++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
++#define IAlloc_Free(p, a) (p)->Free((p), a)
++
++EXTERN_C_END
++
++#endif
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -235,6 +235,12 @@ config LZ4_DECOMPRESS
+ 
+ source "lib/xz/Kconfig"
+ 
++config LZMA_COMPRESS
++    tristate
++
++config LZMA_DECOMPRESS
++    tristate
++
+ #
+ # These all provide a common interface (hence the apparent duplication with
+ # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.)
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -2,6 +2,16 @@
+ # Makefile for some libs needed in the kernel.
+ #
+ 
++ifdef CONFIG_JFFS2_ZLIB
++	CONFIG_ZLIB_INFLATE:=y
++	CONFIG_ZLIB_DEFLATE:=y
++endif
++
++ifdef CONFIG_JFFS2_LZMA
++	CONFIG_LZMA_DECOMPRESS:=y
++	CONFIG_LZMA_COMPRESS:=y
++endif
++
+ ifdef CONFIG_FUNCTION_TRACER
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
+@@ -89,6 +99,8 @@ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
+ obj-$(CONFIG_XZ_DEC) += xz/
+ obj-$(CONFIG_RAID6_PQ) += raid6/
++obj-$(CONFIG_LZMA_COMPRESS) += lzma/
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/
+ 
+ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
+ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+--- /dev/null
++++ b/lib/lzma/LzFind.c
+@@ -0,0 +1,761 @@
++/* LzFind.c -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++#include "LzFind.h"
++#include "LzHash.h"
++
++#define kEmptyHashValue 0
++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
++#define kNormalizeMask (~(kNormalizeStepMin - 1))
++#define kMaxHistorySize ((UInt32)3 << 30)
++
++#define kStartMaxLen 3
++
++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  if (!p->directInput)
++  {
++    alloc->Free(alloc, p->bufferBase);
++    p->bufferBase = 0;
++  }
++}
++
++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
++
++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
++{
++  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
++  if (p->directInput)
++  {
++    p->blockSize = blockSize;
++    return 1;
++  }
++  if (p->bufferBase == 0 || p->blockSize != blockSize)
++  {
++    LzInWindow_Free(p, alloc);
++    p->blockSize = blockSize;
++    p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
++  }
++  return (p->bufferBase != 0);
++}
++
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++
++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++{
++  p->posLimit -= subValue;
++  p->pos -= subValue;
++  p->streamPos -= subValue;
++}
++
++static void MatchFinder_ReadBlock(CMatchFinder *p)
++{
++  if (p->streamEndWasReached || p->result != SZ_OK)
++    return;
++  if (p->directInput)
++  {
++    UInt32 curSize = 0xFFFFFFFF - p->streamPos;
++    if (curSize > p->directInputRem)
++      curSize = (UInt32)p->directInputRem;
++    p->directInputRem -= curSize;
++    p->streamPos += curSize;
++    if (p->directInputRem == 0)
++      p->streamEndWasReached = 1;
++    return;
++  }
++  for (;;)
++  {
++    Byte *dest = p->buffer + (p->streamPos - p->pos);
++    size_t size = (p->bufferBase + p->blockSize - dest);
++    if (size == 0)
++      return;
++    p->result = p->stream->Read(p->stream, dest, &size);
++    if (p->result != SZ_OK)
++      return;
++    if (size == 0)
++    {
++      p->streamEndWasReached = 1;
++      return;
++    }
++    p->streamPos += (UInt32)size;
++    if (p->streamPos - p->pos > p->keepSizeAfter)
++      return;
++  }
++}
++
++void MatchFinder_MoveBlock(CMatchFinder *p)
++{
++  memmove(p->bufferBase,
++    p->buffer - p->keepSizeBefore,
++    (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
++  p->buffer = p->bufferBase + p->keepSizeBefore;
++}
++
++int MatchFinder_NeedMove(CMatchFinder *p)
++{
++  if (p->directInput)
++    return 0;
++  /* if (p->streamEndWasReached) return 0; */
++  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
++}
++
++void MatchFinder_ReadIfRequired(CMatchFinder *p)
++{
++  if (p->streamEndWasReached)
++    return;
++  if (p->keepSizeAfter >= p->streamPos - p->pos)
++    MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
++{
++  if (MatchFinder_NeedMove(p))
++    MatchFinder_MoveBlock(p);
++  MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
++{
++  p->cutValue = 32;
++  p->btMode = 1;
++  p->numHashBytes = 4;
++  p->bigHash = 0;
++}
++
++#define kCrcPoly 0xEDB88320
++
++void MatchFinder_Construct(CMatchFinder *p)
++{
++  UInt32 i;
++  p->bufferBase = 0;
++  p->directInput = 0;
++  p->hash = 0;
++  MatchFinder_SetDefaultSettings(p);
++
++  for (i = 0; i < 256; i++)
++  {
++    UInt32 r = i;
++    int j;
++    for (j = 0; j < 8; j++)
++      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
++    p->crc[i] = r;
++  }
++}
++
++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->hash);
++  p->hash = 0;
++}
++
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  MatchFinder_FreeThisClassMemory(p, alloc);
++  LzInWindow_Free(p, alloc);
++}
++
++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
++{
++  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
++  if (sizeInBytes / sizeof(CLzRef) != num)
++    return 0;
++  return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
++}
++
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc)
++{
++  UInt32 sizeReserv;
++  if (historySize > kMaxHistorySize)
++  {
++    MatchFinder_Free(p, alloc);
++    return 0;
++  }
++  sizeReserv = historySize >> 1;
++  if (historySize > ((UInt32)2 << 30))
++    sizeReserv = historySize >> 2;
++  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
++
++  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
++  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
++  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
++  if (LzInWindow_Create(p, sizeReserv, alloc))
++  {
++    UInt32 newCyclicBufferSize = historySize + 1;
++    UInt32 hs;
++    p->matchMaxLen = matchMaxLen;
++    {
++      p->fixedHashSize = 0;
++      if (p->numHashBytes == 2)
++        hs = (1 << 16) - 1;
++      else
++      {
++        hs = historySize - 1;
++        hs |= (hs >> 1);
++        hs |= (hs >> 2);
++        hs |= (hs >> 4);
++        hs |= (hs >> 8);
++        hs >>= 1;
++        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
++        if (hs > (1 << 24))
++        {
++          if (p->numHashBytes == 3)
++            hs = (1 << 24) - 1;
++          else
++            hs >>= 1;
++        }
++      }
++      p->hashMask = hs;
++      hs++;
++      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
++      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
++      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
++      hs += p->fixedHashSize;
++    }
++
++    {
++      UInt32 prevSize = p->hashSizeSum + p->numSons;
++      UInt32 newSize;
++      p->historySize = historySize;
++      p->hashSizeSum = hs;
++      p->cyclicBufferSize = newCyclicBufferSize;
++      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
++      newSize = p->hashSizeSum + p->numSons;
++      if (p->hash != 0 && prevSize == newSize)
++        return 1;
++      MatchFinder_FreeThisClassMemory(p, alloc);
++      p->hash = AllocRefs(newSize, alloc);
++      if (p->hash != 0)
++      {
++        p->son = p->hash + p->hashSizeSum;
++        return 1;
++      }
++    }
++  }
++  MatchFinder_Free(p, alloc);
++  return 0;
++}
++
++static void MatchFinder_SetLimits(CMatchFinder *p)
++{
++  UInt32 limit = kMaxValForNormalize - p->pos;
++  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
++  if (limit2 < limit)
++    limit = limit2;
++  limit2 = p->streamPos - p->pos;
++  if (limit2 <= p->keepSizeAfter)
++  {
++    if (limit2 > 0)
++      limit2 = 1;
++  }
++  else
++    limit2 -= p->keepSizeAfter;
++  if (limit2 < limit)
++    limit = limit2;
++  {
++    UInt32 lenLimit = p->streamPos - p->pos;
++    if (lenLimit > p->matchMaxLen)
++      lenLimit = p->matchMaxLen;
++    p->lenLimit = lenLimit;
++  }
++  p->posLimit = p->pos + limit;
++}
++
++void MatchFinder_Init(CMatchFinder *p)
++{
++  UInt32 i;
++  for (i = 0; i < p->hashSizeSum; i++)
++    p->hash[i] = kEmptyHashValue;
++  p->cyclicBufferPos = 0;
++  p->buffer = p->bufferBase;
++  p->pos = p->streamPos = p->cyclicBufferSize;
++  p->result = SZ_OK;
++  p->streamEndWasReached = 0;
++  MatchFinder_ReadBlock(p);
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
++{
++  return (p->pos - p->historySize - 1) & kNormalizeMask;
++}
++
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++{
++  UInt32 i;
++  for (i = 0; i < numItems; i++)
++  {
++    UInt32 value = items[i];
++    if (value <= subValue)
++      value = kEmptyHashValue;
++    else
++      value -= subValue;
++    items[i] = value;
++  }
++}
++
++static void MatchFinder_Normalize(CMatchFinder *p)
++{
++  UInt32 subValue = MatchFinder_GetSubValue(p);
++  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
++  MatchFinder_ReduceOffsets(p, subValue);
++}
++
++static void MatchFinder_CheckLimits(CMatchFinder *p)
++{
++  if (p->pos == kMaxValForNormalize)
++    MatchFinder_Normalize(p);
++  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
++    MatchFinder_CheckAndMoveAndRead(p);
++  if (p->cyclicBufferPos == p->cyclicBufferSize)
++    p->cyclicBufferPos = 0;
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  son[_cyclicBufferPos] = curMatch;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++      return distances;
++    {
++      const Byte *pb = cur - delta;
++      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
++      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
++      {
++        UInt32 len = 0;
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++            return distances;
++        }
++      }
++    }
++  }
++}
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return distances;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        if (++len != lenLimit && pb[len] == cur[len])
++          while (++len != lenLimit)
++            if (pb[len] != cur[len])
++              break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return distances;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        {
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++#define MOVE_POS \
++  ++p->cyclicBufferPos; \
++  p->buffer++; \
++  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
++
++#define MOVE_POS_RET MOVE_POS return offset;
++
++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
++
++#define GET_MATCHES_HEADER2(minLen, ret_op) \
++  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
++  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
++  cur = p->buffer;
++
++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
++#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
++
++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
++
++#define GET_MATCHES_FOOTER(offset, maxLen) \
++  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
++  distances + offset, maxLen) - distances); MOVE_POS_RET;
++
++#define SKIP_FOOTER \
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
++
++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(2)
++  HASH2_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 1)
++}
++
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 2)
++}
++
++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, delta2, maxLen, offset;
++  GET_MATCHES_HEADER(3)
++
++  HASH3_CALC;
++
++  delta2 = p->pos - p->hash[hash2Value];
++  curMatch = p->hash[kFix3HashSize + hashValue];
++  
++  p->hash[hash2Value] =
++  p->hash[kFix3HashSize + hashValue] = p->pos;
++
++
++  maxLen = 2;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[0] = maxLen;
++    distances[1] = delta2 - 1;
++    offset = 2;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++  
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      p->son[p->cyclicBufferPos] = curMatch;
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances + offset, maxLen) - (distances));
++  MOVE_POS_RET
++}
++
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances, 2) - (distances));
++  MOVE_POS_RET
++}
++
++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(2)
++    HASH2_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value;
++    SKIP_HEADER(3)
++    HASH3_CALC;
++    curMatch = p->hash[kFix3HashSize + hashValue];
++    p->hash[hash2Value] =
++    p->hash[kFix3HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] = p->pos;
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] =
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
++{
++  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
++  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
++  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
++  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
++  if (!p->btMode)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 2)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 3)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
++  }
++  else
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
++  }
++}
+--- /dev/null
++++ b/lib/lzma/LzmaDec.c
+@@ -0,0 +1,999 @@
++/* LzmaDec.c -- LZMA Decoder
++2009-09-20 : Igor Pavlov : Public domain */
++
++#include "LzmaDec.h"
++
++#include <string.h>
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_INIT_SIZE 5
++
++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
++  { UPDATE_0(p); i = (i + i); A0; } else \
++  { UPDATE_1(p); i = (i + i) + 1; A1; }
++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
++
++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
++#define TREE_DECODE(probs, limit, i) \
++  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
++
++/* #define _LZMA_SIZE_OPT */
++
++#ifdef _LZMA_SIZE_OPT
++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
++#else
++#define TREE_6_DECODE(probs, i) \
++  { i = 1; \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  i -= 0x40; }
++#endif
++
++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0_CHECK range = bound;
++#define UPDATE_1_CHECK range -= bound; code -= bound;
++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
++  { UPDATE_0_CHECK; i = (i + i); A0; } else \
++  { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
++#define TREE_DECODE_CHECK(probs, limit, i) \
++  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#define LZMA_DIC_MIN (1 << 12)
++
++/* First LZMA-symbol is always decoded.
++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
++Out:
++  Result:
++    SZ_OK - OK
++    SZ_ERROR_DATA - Error
++  p->remainLen:
++    < kMatchSpecLenStart : normal remain
++    = kMatchSpecLenStart : finished
++    = kMatchSpecLenStart + 1 : Flush marker
++    = kMatchSpecLenStart + 2 : State Init Marker
++*/
++
++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  CLzmaProb *probs = p->probs;
++
++  unsigned state = p->state;
++  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
++  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
++  unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
++  unsigned lc = p->prop.lc;
++
++  Byte *dic = p->dic;
++  SizeT dicBufSize = p->dicBufSize;
++  SizeT dicPos = p->dicPos;
++  
++  UInt32 processedPos = p->processedPos;
++  UInt32 checkDicSize = p->checkDicSize;
++  unsigned len = 0;
++
++  const Byte *buf = p->buf;
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++
++  do
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = processedPos & pbMask;
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0(prob)
++    {
++      unsigned symbol;
++      UPDATE_0(prob);
++      prob = probs + Literal;
++      if (checkDicSize != 0 || processedPos != 0)
++        prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
++        (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
++
++      if (state < kNumLitStates)
++      {
++        state -= (state < 4) ? state : 3;
++        symbol = 1;
++        do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++        unsigned offs = 0x100;
++        state -= (state < 10) ? 3 : 6;
++        symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      dic[dicPos++] = (Byte)symbol;
++      processedPos++;
++      continue;
++    }
++    else
++    {
++      UPDATE_1(prob);
++      prob = probs + IsRep + state;
++      IF_BIT_0(prob)
++      {
++        UPDATE_0(prob);
++        state += kNumStates;
++        prob = probs + LenCoder;
++      }
++      else
++      {
++        UPDATE_1(prob);
++        if (checkDicSize == 0 && processedPos == 0)
++          return SZ_ERROR_DATA;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0(prob)
++        {
++          UPDATE_0(prob);
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++            dicPos++;
++            processedPos++;
++            state = state < kNumLitStates ? 9 : 11;
++            continue;
++          }
++          UPDATE_1(prob);
++        }
++        else
++        {
++          UInt32 distance;
++          UPDATE_1(prob);
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            distance = rep1;
++          }
++          else
++          {
++            UPDATE_1(prob);
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0(prob)
++            {
++              UPDATE_0(prob);
++              distance = rep2;
++            }
++            else
++            {
++              UPDATE_1(prob);
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        state = state < kNumLitStates ? 8 : 11;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0(probLen)
++        {
++          UPDATE_0(probLen);
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = (1 << kLenNumLowBits);
++        }
++        else
++        {
++          UPDATE_1(probLen);
++          probLen = prob + LenChoice2;
++          IF_BIT_0(probLen)
++          {
++            UPDATE_0(probLen);
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = (1 << kLenNumMidBits);
++          }
++          else
++          {
++            UPDATE_1(probLen);
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = (1 << kLenNumHighBits);
++          }
++        }
++        TREE_DECODE(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state >= kNumStates)
++      {
++        UInt32 distance;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
++        TREE_6_DECODE(prob, distance);
++        if (distance >= kStartPosModelIndex)
++        {
++          unsigned posSlot = (unsigned)distance;
++          int numDirectBits = (int)(((distance >> 1) - 1));
++          distance = (2 | (distance & 1));
++          if (posSlot < kEndPosModelIndex)
++          {
++            distance <<= numDirectBits;
++            prob = probs + SpecPos + distance - posSlot - 1;
++            {
++              UInt32 mask = 1;
++              unsigned i = 1;
++              do
++              {
++                GET_BIT2(prob + i, i, ; , distance |= mask);
++                mask <<= 1;
++              }
++              while (--numDirectBits != 0);
++            }
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE
++              range >>= 1;
++              
++              {
++                UInt32 t;
++                code -= range;
++                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
++                distance = (distance << 1) + (t + 1);
++                code += range & t;
++              }
++              /*
++              distance <<= 1;
++              if (code >= range)
++              {
++                code -= range;
++                distance |= 1;
++              }
++              */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            distance <<= kNumAlignBits;
++            {
++              unsigned i = 1;
++              GET_BIT2(prob + i, i, ; , distance |= 1);
++              GET_BIT2(prob + i, i, ; , distance |= 2);
++              GET_BIT2(prob + i, i, ; , distance |= 4);
++              GET_BIT2(prob + i, i, ; , distance |= 8);
++            }
++            if (distance == (UInt32)0xFFFFFFFF)
++            {
++              len += kMatchSpecLenStart;
++              state -= kNumStates;
++              break;
++            }
++          }
++        }
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        rep0 = distance + 1;
++        if (checkDicSize == 0)
++        {
++          if (distance >= processedPos)
++            return SZ_ERROR_DATA;
++        }
++        else if (distance >= checkDicSize)
++          return SZ_ERROR_DATA;
++        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
++      }
++
++      len += kMatchMinLen;
++
++      if (limit == dicPos)
++        return SZ_ERROR_DATA;
++      {
++        SizeT rem = limit - dicPos;
++        unsigned curLen = ((rem < len) ? (unsigned)rem : len);
++        SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
++
++        processedPos += curLen;
++
++        len -= curLen;
++        if (pos + curLen <= dicBufSize)
++        {
++          Byte *dest = dic + dicPos;
++          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
++          const Byte *lim = dest + curLen;
++          dicPos += curLen;
++          do
++            *(dest) = (Byte)*(dest + src);
++          while (++dest != lim);
++        }
++        else
++        {
++          do
++          {
++            dic[dicPos++] = dic[pos];
++            if (++pos == dicBufSize)
++              pos = 0;
++          }
++          while (--curLen != 0);
++        }
++      }
++    }
++  }
++  while (dicPos < limit && buf < bufLimit);
++  NORMALIZE;
++  p->buf = buf;
++  p->range = range;
++  p->code = code;
++  p->remainLen = len;
++  p->dicPos = dicPos;
++  p->processedPos = processedPos;
++  p->reps[0] = rep0;
++  p->reps[1] = rep1;
++  p->reps[2] = rep2;
++  p->reps[3] = rep3;
++  p->state = state;
++
++  return SZ_OK;
++}
++
++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
++{
++  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
++  {
++    Byte *dic = p->dic;
++    SizeT dicPos = p->dicPos;
++    SizeT dicBufSize = p->dicBufSize;
++    unsigned len = p->remainLen;
++    UInt32 rep0 = p->reps[0];
++    if (limit - dicPos < len)
++      len = (unsigned)(limit - dicPos);
++
++    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
++      p->checkDicSize = p->prop.dicSize;
++
++    p->processedPos += len;
++    p->remainLen -= len;
++    while (len-- != 0)
++    {
++      dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++      dicPos++;
++    }
++    p->dicPos = dicPos;
++  }
++}
++
++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  do
++  {
++    SizeT limit2 = limit;
++    if (p->checkDicSize == 0)
++    {
++      UInt32 rem = p->prop.dicSize - p->processedPos;
++      if (limit - p->dicPos > rem)
++        limit2 = p->dicPos + rem;
++    }
++    RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
++    if (p->processedPos >= p->prop.dicSize)
++      p->checkDicSize = p->prop.dicSize;
++    LzmaDec_WriteRem(p, limit);
++  }
++  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
++
++  if (p->remainLen > kMatchSpecLenStart)
++  {
++    p->remainLen = kMatchSpecLenStart;
++  }
++  return 0;
++}
++
++typedef enum
++{
++  DUMMY_ERROR, /* unexpected end of input stream */
++  DUMMY_LIT,
++  DUMMY_MATCH,
++  DUMMY_REP
++} ELzmaDummy;
++
++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
++{
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++  const Byte *bufLimit = buf + inSize;
++  CLzmaProb *probs = p->probs;
++  unsigned state = p->state;
++  ELzmaDummy res;
++
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0_CHECK(prob)
++    {
++      UPDATE_0_CHECK
++
++      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
++
++      prob = probs + Literal;
++      if (p->checkDicSize != 0 || p->processedPos != 0)
++        prob += (LZMA_LIT_SIZE *
++          ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
++          (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
++
++      if (state < kNumLitStates)
++      {
++        unsigned symbol = 1;
++        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
++            ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
++        unsigned offs = 0x100;
++        unsigned symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      res = DUMMY_LIT;
++    }
++    else
++    {
++      unsigned len;
++      UPDATE_1_CHECK;
++
++      prob = probs + IsRep + state;
++      IF_BIT_0_CHECK(prob)
++      {
++        UPDATE_0_CHECK;
++        state = 0;
++        prob = probs + LenCoder;
++        res = DUMMY_MATCH;
++      }
++      else
++      {
++        UPDATE_1_CHECK;
++        res = DUMMY_REP;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0_CHECK(prob)
++        {
++          UPDATE_0_CHECK;
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++            NORMALIZE_CHECK;
++            return DUMMY_REP;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++          }
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0_CHECK(prob)
++            {
++              UPDATE_0_CHECK;
++            }
++            else
++            {
++              UPDATE_1_CHECK;
++            }
++          }
++        }
++        state = kNumStates;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0_CHECK(probLen)
++        {
++          UPDATE_0_CHECK;
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = 1 << kLenNumLowBits;
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          probLen = prob + LenChoice2;
++          IF_BIT_0_CHECK(probLen)
++          {
++            UPDATE_0_CHECK;
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = 1 << kLenNumMidBits;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = 1 << kLenNumHighBits;
++          }
++        }
++        TREE_DECODE_CHECK(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state < 4)
++      {
++        unsigned posSlot;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++            kNumPosSlotBits);
++        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++
++          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
++
++          if (posSlot < kEndPosModelIndex)
++          {
++            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE_CHECK
++              range >>= 1;
++              code -= range & (((code - range) >> 31) - 1);
++              /* if (code >= range) code -= range; */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            numDirectBits = kNumAlignBits;
++          }
++          {
++            unsigned i = 1;
++            do
++            {
++              GET_BIT_CHECK(prob + i, i);
++            }
++            while (--numDirectBits != 0);
++          }
++        }
++      }
++    }
++  }
++  NORMALIZE_CHECK;
++  return res;
++}
++
++
++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
++{
++  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->range = 0xFFFFFFFF;
++  p->needFlush = 0;
++}
++
++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++{
++  p->needFlush = 1;
++  p->remainLen = 0;
++  p->tempBufSize = 0;
++
++  if (initDic)
++  {
++    p->processedPos = 0;
++    p->checkDicSize = 0;
++    p->needInitState = 1;
++  }
++  if (initState)
++    p->needInitState = 1;
++}
++
++void LzmaDec_Init(CLzmaDec *p)
++{
++  p->dicPos = 0;
++  LzmaDec_InitDicAndState(p, True, True);
++}
++
++static void LzmaDec_InitStateReal(CLzmaDec *p)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
++  UInt32 i;
++  CLzmaProb *probs = p->probs;
++  for (i = 0; i < numProbs; i++)
++    probs[i] = kBitModelTotal >> 1;
++  p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
++  p->state = 0;
++  p->needInitState = 0;
++}
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++    ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT inSize = *srcLen;
++  (*srcLen) = 0;
++  LzmaDec_WriteRem(p, dicLimit);
++  
++  *status = LZMA_STATUS_NOT_SPECIFIED;
++
++  while (p->remainLen != kMatchSpecLenStart)
++  {
++      int checkEndMarkNow;
++
++      if (p->needFlush != 0)
++      {
++        for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
++          p->tempBuf[p->tempBufSize++] = *src++;
++        if (p->tempBufSize < RC_INIT_SIZE)
++        {
++          *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++          return SZ_OK;
++        }
++        if (p->tempBuf[0] != 0)
++          return SZ_ERROR_DATA;
++
++        LzmaDec_InitRc(p, p->tempBuf);
++        p->tempBufSize = 0;
++      }
++
++      checkEndMarkNow = 0;
++      if (p->dicPos >= dicLimit)
++      {
++        if (p->remainLen == 0 && p->code == 0)
++        {
++          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
++          return SZ_OK;
++        }
++        if (finishMode == LZMA_FINISH_ANY)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_OK;
++        }
++        if (p->remainLen != 0)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_ERROR_DATA;
++        }
++        checkEndMarkNow = 1;
++      }
++
++      if (p->needInitState)
++        LzmaDec_InitStateReal(p);
++  
++      if (p->tempBufSize == 0)
++      {
++        SizeT processed;
++        const Byte *bufLimit;
++        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            memcpy(p->tempBuf, src, inSize);
++            p->tempBufSize = (unsigned)inSize;
++            (*srcLen) += inSize;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++          bufLimit = src;
++        }
++        else
++          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
++        p->buf = src;
++        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
++          return SZ_ERROR_DATA;
++        processed = (SizeT)(p->buf - src);
++        (*srcLen) += processed;
++        src += processed;
++        inSize -= processed;
++      }
++      else
++      {
++        unsigned rem = p->tempBufSize, lookAhead = 0;
++        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
++          p->tempBuf[rem++] = src[lookAhead++];
++        p->tempBufSize = rem;
++        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            (*srcLen) += lookAhead;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++        }
++        p->buf = p->tempBuf;
++        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
++          return SZ_ERROR_DATA;
++        lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
++        (*srcLen) += lookAhead;
++        src += lookAhead;
++        inSize -= lookAhead;
++        p->tempBufSize = 0;
++      }
++  }
++  if (p->code == 0)
++    *status = LZMA_STATUS_FINISHED_WITH_MARK;
++  return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
++}
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT outSize = *destLen;
++  SizeT inSize = *srcLen;
++  *srcLen = *destLen = 0;
++  for (;;)
++  {
++    SizeT inSizeCur = inSize, outSizeCur, dicPos;
++    ELzmaFinishMode curFinishMode;
++    SRes res;
++    if (p->dicPos == p->dicBufSize)
++      p->dicPos = 0;
++    dicPos = p->dicPos;
++    if (outSize > p->dicBufSize - dicPos)
++    {
++      outSizeCur = p->dicBufSize;
++      curFinishMode = LZMA_FINISH_ANY;
++    }
++    else
++    {
++      outSizeCur = dicPos + outSize;
++      curFinishMode = finishMode;
++    }
++
++    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
++    src += inSizeCur;
++    inSize -= inSizeCur;
++    *srcLen += inSizeCur;
++    outSizeCur = p->dicPos - dicPos;
++    memcpy(dest, p->dic + dicPos, outSizeCur);
++    dest += outSizeCur;
++    outSize -= outSizeCur;
++    *destLen += outSizeCur;
++    if (res != 0)
++      return res;
++    if (outSizeCur == 0 || outSize == 0)
++      return SZ_OK;
++  }
++}
++
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->probs);
++  p->probs = 0;
++}
++
++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->dic);
++  p->dic = 0;
++}
++
++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
++{
++  LzmaDec_FreeProbs(p, alloc);
++  LzmaDec_FreeDict(p, alloc);
++}
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++{
++  UInt32 dicSize;
++  Byte d;
++  
++  if (size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_UNSUPPORTED;
++  else
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++ 
++  if (dicSize < LZMA_DIC_MIN)
++    dicSize = LZMA_DIC_MIN;
++  p->dicSize = dicSize;
++
++  d = data[0];
++  if (d >= (9 * 5 * 5))
++    return SZ_ERROR_UNSUPPORTED;
++
++  p->lc = d % 9;
++  d /= 9;
++  p->pb = d / 5;
++  p->lp = d % 5;
++
++  return SZ_OK;
++}
++
++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
++{
++  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
++  if (p->probs == 0 || numProbs != p->numProbs)
++  {
++    LzmaDec_FreeProbs(p, alloc);
++    p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
++    p->numProbs = numProbs;
++    if (p->probs == 0)
++      return SZ_ERROR_MEM;
++  }
++  return SZ_OK;
++}
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  SizeT dicBufSize;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  dicBufSize = propNew.dicSize;
++  if (p->dic == 0 || dicBufSize != p->dicBufSize)
++  {
++    LzmaDec_FreeDict(p, alloc);
++    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
++    if (p->dic == 0)
++    {
++      LzmaDec_FreeProbs(p, alloc);
++      return SZ_ERROR_MEM;
++    }
++  }
++  p->dicBufSize = dicBufSize;
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc)
++{
++  CLzmaDec p;
++  SRes res;
++  SizeT inSize = *srcLen;
++  SizeT outSize = *destLen;
++  *srcLen = *destLen = 0;
++  if (inSize < RC_INIT_SIZE)
++    return SZ_ERROR_INPUT_EOF;
++
++  LzmaDec_Construct(&p);
++  res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
++  if (res != 0)
++    return res;
++  p.dic = dest;
++  p.dicBufSize = outSize;
++
++  LzmaDec_Init(&p);
++  
++  *srcLen = inSize;
++  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
++
++  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
++    res = SZ_ERROR_INPUT_EOF;
++
++  (*destLen) = p.dicPos;
++  LzmaDec_FreeProbs(&p, alloc);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/LzmaEnc.c
+@@ -0,0 +1,2271 @@
++/* LzmaEnc.c -- LZMA Encoder
++2009-11-24 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++/* #define SHOW_STAT */
++/* #define SHOW_STAT2 */
++
++#if defined(SHOW_STAT) || defined(SHOW_STAT2)
++#include <stdio.h>
++#endif
++
++#include "LzmaEnc.h"
++
++/* disable MT */
++#define _7ZIP_ST
++
++#include "LzFind.h"
++#ifndef _7ZIP_ST
++#include "LzFindMt.h"
++#endif
++
++#ifdef SHOW_STAT
++static int ttt = 0;
++#endif
++
++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
++
++#define kBlockSize (9 << 10)
++#define kUnpackBlockSize (1 << 18)
++#define kMatchArraySize (1 << 21)
++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
++
++#define kNumMaxDirectBits (31)
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++#define kProbInitValue (kBitModelTotal >> 1)
++
++#define kNumMoveReducingBits 4
++#define kNumBitPriceShiftBits 4
++#define kBitPrice (1 << kNumBitPriceShiftBits)
++
++void LzmaEncProps_Init(CLzmaEncProps *p)
++{
++  p->level = 5;
++  p->dictSize = p->mc = 0;
++  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
++  p->writeEndMark = 0;
++}
++
++void LzmaEncProps_Normalize(CLzmaEncProps *p)
++{
++  int level = p->level;
++  if (level < 0) level = 5;
++  p->level = level;
++  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
++  if (p->lc < 0) p->lc = 3;
++  if (p->lp < 0) p->lp = 0;
++  if (p->pb < 0) p->pb = 2;
++  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
++  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
++  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
++  if (p->numHashBytes < 0) p->numHashBytes = 4;
++  if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
++  if (p->numThreads < 0)
++    p->numThreads =
++      #ifndef _7ZIP_ST
++      ((p->btMode && p->algo) ? 2 : 1);
++      #else
++      1;
++      #endif
++}
++
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++{
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++  return props.dictSize;
++}
++
++/* #define LZMA_LOG_BSR */
++/* Define it for Intel's CPU */
++
++
++#ifdef LZMA_LOG_BSR
++
++#define kDicLogSizeMaxCompress 30
++
++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
++
++UInt32 GetPosSlot1(UInt32 pos)
++{
++  UInt32 res;
++  BSR2_RET(pos, res);
++  return res;
++}
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
++
++#else
++
++#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
++
++void LzmaEnc_FastPosInit(Byte *g_FastPos)
++{
++  int c = 2, slotFast;
++  g_FastPos[0] = 0;
++  g_FastPos[1] = 1;
++  
++  for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
++  {
++    UInt32 k = (1 << ((slotFast >> 1) - 1));
++    UInt32 j;
++    for (j = 0; j < k; j++, c++)
++      g_FastPos[c] = (Byte)slotFast;
++  }
++}
++
++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
++  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
++  res = p->g_FastPos[pos >> i] + (i * 2); }
++/*
++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
++  p->g_FastPos[pos >> 6] + 12 : \
++  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
++*/
++
++#define GetPosSlot1(pos) p->g_FastPos[pos]
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
++
++#endif
++
++
++#define LZMA_NUM_REPS 4
++
++typedef unsigned CState;
++
++typedef struct
++{
++  UInt32 price;
++
++  CState state;
++  int prev1IsChar;
++  int prev2;
++
++  UInt32 posPrev2;
++  UInt32 backPrev2;
++
++  UInt32 posPrev;
++  UInt32 backPrev;
++  UInt32 backs[LZMA_NUM_REPS];
++} COptimal;
++
++#define kNumOpts (1 << 12)
++
++#define kNumLenToPosStates 4
++#define kNumPosSlotBits 6
++#define kDicLogSizeMin 0
++#define kDicLogSizeMax 32
++#define kDistTableSizeMax (kDicLogSizeMax * 2)
++
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++#define kAlignMask (kAlignTableSize - 1)
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
++
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++#define LZMA_PB_MAX 4
++#define LZMA_LC_MAX 8
++#define LZMA_LP_MAX 4
++
++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
++
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define LZMA_MATCH_LEN_MIN 2
++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
++
++#define kNumStates 12
++
++typedef struct
++{
++  CLzmaProb choice;
++  CLzmaProb choice2;
++  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
++  CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
++  CLzmaProb high[kLenNumHighSymbols];
++} CLenEnc;
++
++typedef struct
++{
++  CLenEnc p;
++  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
++  UInt32 tableSize;
++  UInt32 counters[LZMA_NUM_PB_STATES_MAX];
++} CLenPriceEnc;
++
++typedef struct
++{
++  UInt32 range;
++  Byte cache;
++  UInt64 low;
++  UInt64 cacheSize;
++  Byte *buf;
++  Byte *bufLim;
++  Byte *bufBase;
++  ISeqOutStream *outStream;
++  UInt64 processed;
++  SRes res;
++} CRangeEnc;
++
++typedef struct
++{
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++} CSaveState;
++
++typedef struct
++{
++  IMatchFinder matchFinder;
++  void *matchFinderObj;
++
++  #ifndef _7ZIP_ST
++  Bool mtMode;
++  CMatchFinderMt matchFinderMt;
++  #endif
++
++  CMatchFinder matchFinderBase;
++
++  #ifndef _7ZIP_ST
++  Byte pad[128];
++  #endif
++  
++  UInt32 optimumEndIndex;
++  UInt32 optimumCurrentIndex;
++
++  UInt32 longestMatchLength;
++  UInt32 numPairs;
++  UInt32 numAvail;
++  COptimal opt[kNumOpts];
++  
++  #ifndef LZMA_LOG_BSR
++  Byte g_FastPos[1 << kNumLogBits];
++  #endif
++
++  UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
++  UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
++  UInt32 numFastBytes;
++  UInt32 additionalOffset;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++
++  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
++  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
++  UInt32 alignPrices[kAlignTableSize];
++  UInt32 alignPriceCount;
++
++  UInt32 distTableSize;
++
++  unsigned lc, lp, pb;
++  unsigned lpMask, pbMask;
++
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  unsigned lclp;
++
++  Bool fastMode;
++  
++  CRangeEnc rc;
++
++  Bool writeEndMark;
++  UInt64 nowPos64;
++  UInt32 matchPriceCount;
++  Bool finished;
++  Bool multiThread;
++
++  SRes result;
++  UInt32 dictSize;
++  UInt32 matchFinderCycles;
++
++  int needInit;
++
++  CSaveState saveState;
++} CLzmaEnc;
++
++void LzmaEnc_SaveState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CSaveState *dest = &p->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
++}
++
++void LzmaEnc_RestoreState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *dest = (CLzmaEnc *)pp;
++  const CSaveState *p = &dest->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
++}
++
++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++
++  if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
++      props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
++    return SZ_ERROR_PARAM;
++  p->dictSize = props.dictSize;
++  p->matchFinderCycles = props.mc;
++  {
++    unsigned fb = props.fb;
++    if (fb < 5)
++      fb = 5;
++    if (fb > LZMA_MATCH_LEN_MAX)
++      fb = LZMA_MATCH_LEN_MAX;
++    p->numFastBytes = fb;
++  }
++  p->lc = props.lc;
++  p->lp = props.lp;
++  p->pb = props.pb;
++  p->fastMode = (props.algo == 0);
++  p->matchFinderBase.btMode = props.btMode;
++  {
++    UInt32 numHashBytes = 4;
++    if (props.btMode)
++    {
++      if (props.numHashBytes < 2)
++        numHashBytes = 2;
++      else if (props.numHashBytes < 4)
++        numHashBytes = props.numHashBytes;
++    }
++    p->matchFinderBase.numHashBytes = numHashBytes;
++  }
++
++  p->matchFinderBase.cutValue = props.mc;
++
++  p->writeEndMark = props.writeEndMark;
++
++  #ifndef _7ZIP_ST
++  /*
++  if (newMultiThread != _multiThread)
++  {
++    ReleaseMatchFinder();
++    _multiThread = newMultiThread;
++  }
++  */
++  p->multiThread = (props.numThreads > 1);
++  #endif
++
++  return SZ_OK;
++}
++
++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
++static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
++static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
++
++#define IsCharState(s) ((s) < 7)
++
++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
++
++#define kInfinityPrice (1 << 30)
++
++static void RangeEnc_Construct(CRangeEnc *p)
++{
++  p->outStream = 0;
++  p->bufBase = 0;
++}
++
++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
++
++#define RC_BUF_SIZE (1 << 16)
++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
++{
++  if (p->bufBase == 0)
++  {
++    p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
++    if (p->bufBase == 0)
++      return 0;
++    p->bufLim = p->bufBase + RC_BUF_SIZE;
++  }
++  return 1;
++}
++
++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->bufBase);
++  p->bufBase = 0;
++}
++
++static void RangeEnc_Init(CRangeEnc *p)
++{
++  /* Stream.Init(); */
++  p->low = 0;
++  p->range = 0xFFFFFFFF;
++  p->cacheSize = 1;
++  p->cache = 0;
++
++  p->buf = p->bufBase;
++
++  p->processed = 0;
++  p->res = SZ_OK;
++}
++
++static void RangeEnc_FlushStream(CRangeEnc *p)
++{
++  size_t num;
++  if (p->res != SZ_OK)
++    return;
++  num = p->buf - p->bufBase;
++  if (num != p->outStream->Write(p->outStream, p->bufBase, num))
++    p->res = SZ_ERROR_WRITE;
++  p->processed += num;
++  p->buf = p->bufBase;
++}
++
++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
++{
++  if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
++  {
++    Byte temp = p->cache;
++    do
++    {
++      Byte *buf = p->buf;
++      *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
++      p->buf = buf;
++      if (buf == p->bufLim)
++        RangeEnc_FlushStream(p);
++      temp = 0xFF;
++    }
++    while (--p->cacheSize != 0);
++    p->cache = (Byte)((UInt32)p->low >> 24);
++  }
++  p->cacheSize++;
++  p->low = (UInt32)p->low << 8;
++}
++
++static void RangeEnc_FlushData(CRangeEnc *p)
++{
++  int i;
++  for (i = 0; i < 5; i++)
++    RangeEnc_ShiftLow(p);
++}
++
++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
++{
++  do
++  {
++    p->range >>= 1;
++    p->low += p->range & (0 - ((value >> --numBits) & 1));
++    if (p->range < kTopValue)
++    {
++      p->range <<= 8;
++      RangeEnc_ShiftLow(p);
++    }
++  }
++  while (numBits != 0);
++}
++
++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
++{
++  UInt32 ttt = *prob;
++  UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
++  if (symbol == 0)
++  {
++    p->range = newBound;
++    ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
++  }
++  else
++  {
++    p->low += newBound;
++    p->range -= newBound;
++    ttt -= ttt >> kNumMoveBits;
++  }
++  *prob = (CLzmaProb)ttt;
++  if (p->range < kTopValue)
++  {
++    p->range <<= 8;
++    RangeEnc_ShiftLow(p);
++  }
++}
++
++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
++{
++  symbol |= 0x100;
++  do
++  {
++    RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++}
++
++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
++{
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++}
++
++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++{
++  UInt32 i;
++  for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
++  {
++    const int kCyclesBits = kNumBitPriceShiftBits;
++    UInt32 w = i;
++    UInt32 bitCount = 0;
++    int j;
++    for (j = 0; j < kCyclesBits; j++)
++    {
++      w = w * w;
++      bitCount <<= 1;
++      while (w >= ((UInt32)1 << 16))
++      {
++        w >>= 1;
++        bitCount++;
++      }
++    }
++    ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
++  }
++}
++
++
++#define GET_PRICE(prob, symbol) \
++  p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICEa(prob, symbol) \
++  ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= 0x100;
++  do
++  {
++    price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++
++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0;)
++  {
++    UInt32 bit;
++    i--;
++    bit = (symbol >> i) & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++  }
++}
++
++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = 0; i < numBitLevels; i++)
++  {
++    UInt32 bit = symbol & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++    symbol >>= 1;
++  }
++}
++
++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= (1 << numBitLevels);
++  while (symbol != 1)
++  {
++    price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
++    symbol >>= 1;
++  }
++  return price;
++}
++
++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0; i--)
++  {
++    UInt32 bit = symbol & 1;
++    symbol >>= 1;
++    price += GET_PRICEa(probs[m], bit);
++    m = (m << 1) | bit;
++  }
++  return price;
++}
++
++
++static void LenEnc_Init(CLenEnc *p)
++{
++  unsigned i;
++  p->choice = p->choice2 = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
++    p->low[i] = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
++    p->mid[i] = kProbInitValue;
++  for (i = 0; i < kLenNumHighSymbols; i++)
++    p->high[i] = kProbInitValue;
++}
++
++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
++{
++  if (symbol < kLenNumLowSymbols)
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 0);
++    RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
++  }
++  else
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 1);
++    if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 0);
++      RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
++    }
++    else
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 1);
++      RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
++    }
++  }
++}
++
++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
++{
++  UInt32 a0 = GET_PRICE_0a(p->choice);
++  UInt32 a1 = GET_PRICE_1a(p->choice);
++  UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
++  UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
++  UInt32 i = 0;
++  for (i = 0; i < kLenNumLowSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
++  }
++  for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
++  }
++  for (; i < numSymbols; i++)
++    prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
++}
++
++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
++{
++  LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
++  p->counters[posState] = p->tableSize;
++}
++
++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
++{
++  UInt32 posState;
++  for (posState = 0; posState < numPosStates; posState++)
++    LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
++{
++  LenEnc_Encode(&p->p, rc, symbol, posState);
++  if (updatePrice)
++    if (--p->counters[posState] == 0)
++      LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++
++
++
++static void MovePos(CLzmaEnc *p, UInt32 num)
++{
++  #ifdef SHOW_STAT
++  ttt += num;
++  printf("\n MovePos %d", num);
++  #endif
++  if (num != 0)
++  {
++    p->additionalOffset += num;
++    p->matchFinder.Skip(p->matchFinderObj, num);
++  }
++}
++
++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
++{
++  UInt32 lenRes = 0, numPairs;
++  p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++  numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
++  #ifdef SHOW_STAT
++  printf("\n i = %d numPairs = %d    ", ttt, numPairs / 2);
++  ttt++;
++  {
++    UInt32 i;
++    for (i = 0; i < numPairs; i += 2)
++      printf("%2d %6d   | ", p->matches[i], p->matches[i + 1]);
++  }
++  #endif
++  if (numPairs > 0)
++  {
++    lenRes = p->matches[numPairs - 2];
++    if (lenRes == p->numFastBytes)
++    {
++      const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++      UInt32 distance = p->matches[numPairs - 1] + 1;
++      UInt32 numAvail = p->numAvail;
++      if (numAvail > LZMA_MATCH_LEN_MAX)
++        numAvail = LZMA_MATCH_LEN_MAX;
++      {
++        const Byte *pby2 = pby - distance;
++        for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
++      }
++    }
++  }
++  p->additionalOffset++;
++  *numDistancePairsRes = numPairs;
++  return lenRes;
++}
++
++
++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
++#define IsShortRep(p) ((p)->backPrev == 0)
++
++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
++{
++  return
++    GET_PRICE_0(p->isRepG0[state]) +
++    GET_PRICE_0(p->isRep0Long[state][posState]);
++}
++
++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
++{
++  UInt32 price;
++  if (repIndex == 0)
++  {
++    price = GET_PRICE_0(p->isRepG0[state]);
++    price += GET_PRICE_1(p->isRep0Long[state][posState]);
++  }
++  else
++  {
++    price = GET_PRICE_1(p->isRepG0[state]);
++    if (repIndex == 1)
++      price += GET_PRICE_0(p->isRepG1[state]);
++    else
++    {
++      price += GET_PRICE_1(p->isRepG1[state]);
++      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
++    }
++  }
++  return price;
++}
++
++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
++{
++  return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
++    GetPureRepPrice(p, repIndex, state, posState);
++}
++
++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
++{
++  UInt32 posMem = p->opt[cur].posPrev;
++  UInt32 backMem = p->opt[cur].backPrev;
++  p->optimumEndIndex = cur;
++  do
++  {
++    if (p->opt[cur].prev1IsChar)
++    {
++      MakeAsChar(&p->opt[posMem])
++      p->opt[posMem].posPrev = posMem - 1;
++      if (p->opt[cur].prev2)
++      {
++        p->opt[posMem - 1].prev1IsChar = False;
++        p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
++        p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
++      }
++    }
++    {
++      UInt32 posPrev = posMem;
++      UInt32 backCur = backMem;
++      
++      backMem = p->opt[posPrev].backPrev;
++      posMem = p->opt[posPrev].posPrev;
++      
++      p->opt[posPrev].backPrev = backCur;
++      p->opt[posPrev].posPrev = cur;
++      cur = posPrev;
++    }
++  }
++  while (cur != 0);
++  *backRes = p->opt[0].backPrev;
++  p->optimumCurrentIndex  = p->opt[0].posPrev;
++  return p->optimumCurrentIndex;
++}
++
++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
++
++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
++  UInt32 matchPrice, repMatchPrice, normalMatchPrice;
++  UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
++  UInt32 *matches;
++  const Byte *data;
++  Byte curByte, matchByte;
++  if (p->optimumEndIndex != p->optimumCurrentIndex)
++  {
++    const COptimal *opt = &p->opt[p->optimumCurrentIndex];
++    UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
++    *backRes = opt->backPrev;
++    p->optimumCurrentIndex = opt->posPrev;
++    return lenRes;
++  }
++  p->optimumCurrentIndex = p->optimumEndIndex = 0;
++  
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  if (numAvail < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  repMaxIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 lenTest;
++    const Byte *data2;
++    reps[i] = p->reps[i];
++    data2 = data - (reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++    repLens[i] = lenTest;
++    if (lenTest > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  if (repLens[repMaxIndex] >= p->numFastBytes)
++  {
++    UInt32 lenRes;
++    *backRes = repMaxIndex;
++    lenRes = repLens[repMaxIndex];
++    MovePos(p, lenRes - 1);
++    return lenRes;
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++  curByte = *data;
++  matchByte = *(data - (reps[0] + 1));
++
++  if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
++  {
++    *backRes = (UInt32)-1;
++    return 1;
++  }
++
++  p->opt[0].state = (CState)p->state;
++
++  posState = (position & p->pbMask);
++
++  {
++    const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++    p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
++        (!IsCharState(p->state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++  }
++
++  MakeAsChar(&p->opt[1]);
++
++  matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
++  repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
++
++  if (matchByte == curByte)
++  {
++    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
++    if (shortRepPrice < p->opt[1].price)
++    {
++      p->opt[1].price = shortRepPrice;
++      MakeAsShortRep(&p->opt[1]);
++    }
++  }
++  lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
++
++  if (lenEnd < 2)
++  {
++    *backRes = p->opt[1].backPrev;
++    return 1;
++  }
++
++  p->opt[1].posPrev = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++    p->opt[0].backs[i] = reps[i];
++
++  len = lenEnd;
++  do
++    p->opt[len--].price = kInfinityPrice;
++  while (len >= 2);
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 repLen = repLens[i];
++    UInt32 price;
++    if (repLen < 2)
++      continue;
++    price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
++    do
++    {
++      UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
++      COptimal *opt = &p->opt[repLen];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = i;
++        opt->prev1IsChar = False;
++      }
++    }
++    while (--repLen >= 2);
++  }
++
++  normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
++
++  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
++  if (len <= mainLen)
++  {
++    UInt32 offs = 0;
++    while (len > matches[offs])
++      offs += 2;
++    for (; ; len++)
++    {
++      COptimal *opt;
++      UInt32 distance = matches[offs + 1];
++
++      UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
++      UInt32 lenToPosState = GetLenToPosState(len);
++      if (distance < kNumFullDistances)
++        curAndLenPrice += p->distancesPrices[lenToPosState][distance];
++      else
++      {
++        UInt32 slot;
++        GetPosSlot2(distance, slot);
++        curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
++      }
++      opt = &p->opt[len];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = distance + LZMA_NUM_REPS;
++        opt->prev1IsChar = False;
++      }
++      if (len == matches[offs])
++      {
++        offs += 2;
++        if (offs == numPairs)
++          break;
++      }
++    }
++  }
++
++  cur = 0;
++
++    #ifdef SHOW_STAT2
++    if (position >= 0)
++    {
++      unsigned i;
++      printf("\n pos = %4X", position);
++      for (i = cur; i <= lenEnd; i++)
++      printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
++    }
++    #endif
++
++  for (;;)
++  {
++    UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
++    UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
++    Bool nextIsChar;
++    Byte curByte, matchByte;
++    const Byte *data;
++    COptimal *curOpt;
++    COptimal *nextOpt;
++
++    cur++;
++    if (cur == lenEnd)
++      return Backward(p, backRes, cur);
++
++    newLen = ReadMatchDistances(p, &numPairs);
++    if (newLen >= p->numFastBytes)
++    {
++      p->numPairs = numPairs;
++      p->longestMatchLength = newLen;
++      return Backward(p, backRes, cur);
++    }
++    position++;
++    curOpt = &p->opt[cur];
++    posPrev = curOpt->posPrev;
++    if (curOpt->prev1IsChar)
++    {
++      posPrev--;
++      if (curOpt->prev2)
++      {
++        state = p->opt[curOpt->posPrev2].state;
++        if (curOpt->backPrev2 < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      else
++        state = p->opt[posPrev].state;
++      state = kLiteralNextStates[state];
++    }
++    else
++      state = p->opt[posPrev].state;
++    if (posPrev == cur - 1)
++    {
++      if (IsShortRep(curOpt))
++        state = kShortRepNextStates[state];
++      else
++        state = kLiteralNextStates[state];
++    }
++    else
++    {
++      UInt32 pos;
++      const COptimal *prevOpt;
++      if (curOpt->prev1IsChar && curOpt->prev2)
++      {
++        posPrev = curOpt->posPrev2;
++        pos = curOpt->backPrev2;
++        state = kRepNextStates[state];
++      }
++      else
++      {
++        pos = curOpt->backPrev;
++        if (pos < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      prevOpt = &p->opt[posPrev];
++      if (pos < LZMA_NUM_REPS)
++      {
++        UInt32 i;
++        reps[0] = prevOpt->backs[pos];
++        for (i = 1; i <= pos; i++)
++          reps[i] = prevOpt->backs[i - 1];
++        for (; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i];
++      }
++      else
++      {
++        UInt32 i;
++        reps[0] = (pos - LZMA_NUM_REPS);
++        for (i = 1; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i - 1];
++      }
++    }
++    curOpt->state = (CState)state;
++
++    curOpt->backs[0] = reps[0];
++    curOpt->backs[1] = reps[1];
++    curOpt->backs[2] = reps[2];
++    curOpt->backs[3] = reps[3];
++
++    curPrice = curOpt->price;
++    nextIsChar = False;
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    curByte = *data;
++    matchByte = *(data - (reps[0] + 1));
++
++    posState = (position & p->pbMask);
++
++    curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
++    {
++      const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++      curAnd1Price +=
++        (!IsCharState(state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++    }
++
++    nextOpt = &p->opt[cur + 1];
++
++    if (curAnd1Price < nextOpt->price)
++    {
++      nextOpt->price = curAnd1Price;
++      nextOpt->posPrev = cur;
++      MakeAsChar(nextOpt);
++      nextIsChar = True;
++    }
++
++    matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
++    repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
++    
++    if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
++    {
++      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
++      if (shortRepPrice <= nextOpt->price)
++      {
++        nextOpt->price = shortRepPrice;
++        nextOpt->posPrev = cur;
++        MakeAsShortRep(nextOpt);
++        nextIsChar = True;
++      }
++    }
++    numAvailFull = p->numAvail;
++    {
++      UInt32 temp = kNumOpts - 1 - cur;
++      if (temp < numAvailFull)
++        numAvailFull = temp;
++    }
++
++    if (numAvailFull < 2)
++      continue;
++    numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
++
++    if (!nextIsChar && matchByte != curByte) /* speed optimization */
++    {
++      /* try Literal + rep0 */
++      UInt32 temp;
++      UInt32 lenTest2;
++      const Byte *data2 = data - (reps[0] + 1);
++      UInt32 limit = p->numFastBytes + 1;
++      if (limit > numAvailFull)
++        limit = numAvailFull;
++
++      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
++      lenTest2 = temp - 1;
++      if (lenTest2 >= 2)
++      {
++        UInt32 state2 = kLiteralNextStates[state];
++        UInt32 posStateNext = (position + 1) & p->pbMask;
++        UInt32 nextRepMatchPrice = curAnd1Price +
++            GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++            GET_PRICE_1(p->isRep[state2]);
++        /* for (; lenTest2 >= 2; lenTest2--) */
++        {
++          UInt32 curAndLenPrice;
++          COptimal *opt;
++          UInt32 offset = cur + 1 + lenTest2;
++          while (lenEnd < offset)
++            p->opt[++lenEnd].price = kInfinityPrice;
++          curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++          opt = &p->opt[offset];
++          if (curAndLenPrice < opt->price)
++          {
++            opt->price = curAndLenPrice;
++            opt->posPrev = cur + 1;
++            opt->backPrev = 0;
++            opt->prev1IsChar = True;
++            opt->prev2 = False;
++          }
++        }
++      }
++    }
++    
++    startLen = 2; /* speed optimization */
++    {
++    UInt32 repIndex;
++    for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
++    {
++      UInt32 lenTest;
++      UInt32 lenTestTemp;
++      UInt32 price;
++      const Byte *data2 = data - (reps[repIndex] + 1);
++      if (data[0] != data2[0] || data[1] != data2[1])
++        continue;
++      for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++      while (lenEnd < cur + lenTest)
++        p->opt[++lenEnd].price = kInfinityPrice;
++      lenTestTemp = lenTest;
++      price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
++      do
++      {
++        UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
++        COptimal *opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = repIndex;
++          opt->prev1IsChar = False;
++        }
++      }
++      while (--lenTest >= 2);
++      lenTest = lenTestTemp;
++      
++      if (repIndex == 0)
++        startLen = lenTest + 1;
++        
++      /* if (_maxMode) */
++        {
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kRepNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice =
++                price + p->repLenEnc.prices[posState][lenTest - 2] +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (position + lenTest + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = repIndex;
++              }
++            }
++          }
++        }
++    }
++    }
++    /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
++    if (newLen > numAvail)
++    {
++      newLen = numAvail;
++      for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
++      matches[numPairs] = newLen;
++      numPairs += 2;
++    }
++    if (newLen >= startLen)
++    {
++      UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
++      UInt32 offs, curBack, posSlot;
++      UInt32 lenTest;
++      while (lenEnd < cur + newLen)
++        p->opt[++lenEnd].price = kInfinityPrice;
++
++      offs = 0;
++      while (startLen > matches[offs])
++        offs += 2;
++      curBack = matches[offs + 1];
++      GetPosSlot2(curBack, posSlot);
++      for (lenTest = /*2*/ startLen; ; lenTest++)
++      {
++        UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
++        UInt32 lenToPosState = GetLenToPosState(lenTest);
++        COptimal *opt;
++        if (curBack < kNumFullDistances)
++          curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
++        else
++          curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
++        
++        opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = curBack + LZMA_NUM_REPS;
++          opt->prev1IsChar = False;
++        }
++
++        if (/*_maxMode && */lenTest == matches[offs])
++        {
++          /* Try Match + Literal + Rep0 */
++          const Byte *data2 = data - (curBack + 1);
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kMatchNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = curAndLenPrice +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (posStateNext + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = curBack + LZMA_NUM_REPS;
++              }
++            }
++          }
++          offs += 2;
++          if (offs == numPairs)
++            break;
++          curBack = matches[offs + 1];
++          if (curBack >= kNumFullDistances)
++            GetPosSlot2(curBack, posSlot);
++        }
++      }
++    }
++  }
++}
++
++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
++
++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
++  const Byte *data;
++  const UInt32 *matches;
++
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  *backRes = (UInt32)-1;
++  if (numAvail < 2)
++    return 1;
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++
++  repLen = repIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    for (len = 2; len < numAvail && data[len] == data2[len]; len++);
++    if (len >= p->numFastBytes)
++    {
++      *backRes = i;
++      MovePos(p, len - 1);
++      return len;
++    }
++    if (len > repLen)
++    {
++      repIndex = i;
++      repLen = len;
++    }
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++
++  mainDist = 0; /* for GCC */
++  if (mainLen >= 2)
++  {
++    mainDist = matches[numPairs - 1];
++    while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
++    {
++      if (!ChangePair(matches[numPairs - 3], mainDist))
++        break;
++      numPairs -= 2;
++      mainLen = matches[numPairs - 2];
++      mainDist = matches[numPairs - 1];
++    }
++    if (mainLen == 2 && mainDist >= 0x80)
++      mainLen = 1;
++  }
++
++  if (repLen >= 2 && (
++        (repLen + 1 >= mainLen) ||
++        (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
++        (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
++  {
++    *backRes = repIndex;
++    MovePos(p, repLen - 1);
++    return repLen;
++  }
++  
++  if (mainLen < 2 || numAvail <= 2)
++    return 1;
++
++  p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
++  if (p->longestMatchLength >= 2)
++  {
++    UInt32 newDistance = matches[p->numPairs - 1];
++    if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
++        (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
++        (p->longestMatchLength > mainLen + 1) ||
++        (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
++      return 1;
++  }
++  
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len, limit;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    limit = mainLen - 1;
++    for (len = 2; len < limit && data[len] == data2[len]; len++);
++    if (len >= limit)
++      return 1;
++  }
++  *backRes = mainDist + LZMA_NUM_REPS;
++  MovePos(p, mainLen - 2);
++  return mainLen;
++}
++
++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
++{
++  UInt32 len;
++  RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++  RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++  p->state = kMatchNextStates[p->state];
++  len = LZMA_MATCH_LEN_MIN;
++  LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++  RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
++  RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
++  RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
++}
++
++static SRes CheckErrors(CLzmaEnc *p)
++{
++  if (p->result != SZ_OK)
++    return p->result;
++  if (p->rc.res != SZ_OK)
++    p->result = SZ_ERROR_WRITE;
++  if (p->matchFinderBase.result != SZ_OK)
++    p->result = SZ_ERROR_READ;
++  if (p->result != SZ_OK)
++    p->finished = True;
++  return p->result;
++}
++
++static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
++{
++  /* ReleaseMFStream(); */
++  p->finished = True;
++  if (p->writeEndMark)
++    WriteEndMarker(p, nowPos & p->pbMask);
++  RangeEnc_FlushData(&p->rc);
++  RangeEnc_FlushStream(&p->rc);
++  return CheckErrors(p);
++}
++
++static void FillAlignPrices(CLzmaEnc *p)
++{
++  UInt32 i;
++  for (i = 0; i < kAlignTableSize; i++)
++    p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
++  p->alignPriceCount = 0;
++}
++
++static void FillDistancesPrices(CLzmaEnc *p)
++{
++  UInt32 tempPrices[kNumFullDistances];
++  UInt32 i, lenToPosState;
++  for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
++  {
++    UInt32 posSlot = GetPosSlot1(i);
++    UInt32 footerBits = ((posSlot >> 1) - 1);
++    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++    tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
++  }
++
++  for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
++  {
++    UInt32 posSlot;
++    const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
++    UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
++    for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
++    for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
++
++    {
++      UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
++      UInt32 i;
++      for (i = 0; i < kStartPosModelIndex; i++)
++        distancesPrices[i] = posSlotPrices[i];
++      for (; i < kNumFullDistances; i++)
++        distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
++    }
++  }
++  p->matchPriceCount = 0;
++}
++
++void LzmaEnc_Construct(CLzmaEnc *p)
++{
++  RangeEnc_Construct(&p->rc);
++  MatchFinder_Construct(&p->matchFinderBase);
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Construct(&p->matchFinderMt);
++  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
++  #endif
++
++  {
++    CLzmaEncProps props;
++    LzmaEncProps_Init(&props);
++    LzmaEnc_SetProps(p, &props);
++  }
++
++  #ifndef LZMA_LOG_BSR
++  LzmaEnc_FastPosInit(p->g_FastPos);
++  #endif
++
++  LzmaEnc_InitPriceTables(p->ProbPrices);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
++{
++  void *p;
++  p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
++  if (p != 0)
++    LzmaEnc_Construct((CLzmaEnc *)p);
++  return p;
++}
++
++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->litProbs);
++  alloc->Free(alloc, p->saveState.litProbs);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
++  #endif
++  MatchFinder_Free(&p->matchFinderBase, allocBig);
++  LzmaEnc_FreeLits(p, alloc);
++  RangeEnc_Free(&p->rc, alloc);
++}
++
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
++  alloc->Free(alloc, p);
++}
++
++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
++{
++  UInt32 nowPos32, startPos32;
++  if (p->needInit)
++  {
++    p->matchFinder.Init(p->matchFinderObj);
++    p->needInit = 0;
++  }
++
++  if (p->finished)
++    return p->result;
++  RINOK(CheckErrors(p));
++
++  nowPos32 = (UInt32)p->nowPos64;
++  startPos32 = nowPos32;
++
++  if (p->nowPos64 == 0)
++  {
++    UInt32 numPairs;
++    Byte curByte;
++    if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++      return Flush(p, nowPos32);
++    ReadMatchDistances(p, &numPairs);
++    RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
++    p->state = kLiteralNextStates[p->state];
++    curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
++    LitEnc_Encode(&p->rc, p->litProbs, curByte);
++    p->additionalOffset--;
++    nowPos32++;
++  }
++
++  if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
++  for (;;)
++  {
++    UInt32 pos, len, posState;
++
++    if (p->fastMode)
++      len = GetOptimumFast(p, &pos);
++    else
++      len = GetOptimum(p, nowPos32, &pos);
++
++    #ifdef SHOW_STAT2
++    printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
++    #endif
++
++    posState = nowPos32 & p->pbMask;
++    if (len == 1 && pos == (UInt32)-1)
++    {
++      Byte curByte;
++      CLzmaProb *probs;
++      const Byte *data;
++
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
++      data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++      curByte = *data;
++      probs = LIT_PROBS(nowPos32, *(data - 1));
++      if (IsCharState(p->state))
++        LitEnc_Encode(&p->rc, probs, curByte);
++      else
++        LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
++      p->state = kLiteralNextStates[p->state];
++    }
++    else
++    {
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++      if (pos < LZMA_NUM_REPS)
++      {
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
++        if (pos == 0)
++        {
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
++          RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
++        }
++        else
++        {
++          UInt32 distance = p->reps[pos];
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
++          if (pos == 1)
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
++          else
++          {
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
++            if (pos == 3)
++              p->reps[3] = p->reps[2];
++            p->reps[2] = p->reps[1];
++          }
++          p->reps[1] = p->reps[0];
++          p->reps[0] = distance;
++        }
++        if (len == 1)
++          p->state = kShortRepNextStates[p->state];
++        else
++        {
++          LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++          p->state = kRepNextStates[p->state];
++        }
++      }
++      else
++      {
++        UInt32 posSlot;
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++        p->state = kMatchNextStates[p->state];
++        LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++        pos -= LZMA_NUM_REPS;
++        GetPosSlot(pos, posSlot);
++        RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
++        
++        if (posSlot >= kStartPosModelIndex)
++        {
++          UInt32 footerBits = ((posSlot >> 1) - 1);
++          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++          UInt32 posReduced = pos - base;
++
++          if (posSlot < kEndPosModelIndex)
++            RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
++          else
++          {
++            RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
++            RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
++            p->alignPriceCount++;
++          }
++        }
++        p->reps[3] = p->reps[2];
++        p->reps[2] = p->reps[1];
++        p->reps[1] = p->reps[0];
++        p->reps[0] = pos;
++        p->matchPriceCount++;
++      }
++    }
++    p->additionalOffset -= len;
++    nowPos32 += len;
++    if (p->additionalOffset == 0)
++    {
++      UInt32 processed;
++      if (!p->fastMode)
++      {
++        if (p->matchPriceCount >= (1 << 7))
++          FillDistancesPrices(p);
++        if (p->alignPriceCount >= kAlignTableSize)
++          FillAlignPrices(p);
++      }
++      if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++        break;
++      processed = nowPos32 - startPos32;
++      if (useLimits)
++      {
++        if (processed + kNumOpts + 300 >= maxUnpackSize ||
++            RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
++          break;
++      }
++      else if (processed >= (1 << 15))
++      {
++        p->nowPos64 += nowPos32 - startPos32;
++        return CheckErrors(p);
++      }
++    }
++  }
++  p->nowPos64 += nowPos32 - startPos32;
++  return Flush(p, nowPos32);
++}
++
++#define kBigHashDicLimit ((UInt32)1 << 24)
++
++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 beforeSize = kNumOpts;
++  Bool btMode;
++  if (!RangeEnc_Alloc(&p->rc, alloc))
++    return SZ_ERROR_MEM;
++  btMode = (p->matchFinderBase.btMode != 0);
++  #ifndef _7ZIP_ST
++  p->mtMode = (p->multiThread && !p->fastMode && btMode);
++  #endif
++
++  {
++    unsigned lclp = p->lc + p->lp;
++    if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
++    {
++      LzmaEnc_FreeLits(p, alloc);
++      p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      if (p->litProbs == 0 || p->saveState.litProbs == 0)
++      {
++        LzmaEnc_FreeLits(p, alloc);
++        return SZ_ERROR_MEM;
++      }
++      p->lclp = lclp;
++    }
++  }
++
++  p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
++
++  if (beforeSize + p->dictSize < keepWindowSize)
++    beforeSize = keepWindowSize - p->dictSize;
++
++  #ifndef _7ZIP_ST
++  if (p->mtMode)
++  {
++    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
++    p->matchFinderObj = &p->matchFinderMt;
++    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
++  }
++  else
++  #endif
++  {
++    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
++      return SZ_ERROR_MEM;
++    p->matchFinderObj = &p->matchFinderBase;
++    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
++  }
++  return SZ_OK;
++}
++
++void LzmaEnc_Init(CLzmaEnc *p)
++{
++  UInt32 i;
++  p->state = 0;
++  for (i = 0 ; i < LZMA_NUM_REPS; i++)
++    p->reps[i] = 0;
++
++  RangeEnc_Init(&p->rc);
++
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    UInt32 j;
++    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
++    {
++      p->isMatch[i][j] = kProbInitValue;
++      p->isRep0Long[i][j] = kProbInitValue;
++    }
++    p->isRep[i] = kProbInitValue;
++    p->isRepG0[i] = kProbInitValue;
++    p->isRepG1[i] = kProbInitValue;
++    p->isRepG2[i] = kProbInitValue;
++  }
++
++  {
++    UInt32 num = 0x300 << (p->lp + p->lc);
++    for (i = 0; i < num; i++)
++      p->litProbs[i] = kProbInitValue;
++  }
++
++  {
++    for (i = 0; i < kNumLenToPosStates; i++)
++    {
++      CLzmaProb *probs = p->posSlotEncoder[i];
++      UInt32 j;
++      for (j = 0; j < (1 << kNumPosSlotBits); j++)
++        probs[j] = kProbInitValue;
++    }
++  }
++  {
++    for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
++      p->posEncoders[i] = kProbInitValue;
++  }
++
++  LenEnc_Init(&p->lenEnc.p);
++  LenEnc_Init(&p->repLenEnc.p);
++
++  for (i = 0; i < (1 << kNumAlignBits); i++)
++    p->posAlignEncoder[i] = kProbInitValue;
++
++  p->optimumEndIndex = 0;
++  p->optimumCurrentIndex = 0;
++  p->additionalOffset = 0;
++
++  p->pbMask = (1 << p->pb) - 1;
++  p->lpMask = (1 << p->lp) - 1;
++}
++
++void LzmaEnc_InitPrices(CLzmaEnc *p)
++{
++  if (!p->fastMode)
++  {
++    FillDistancesPrices(p);
++    FillAlignPrices(p);
++  }
++
++  p->lenEnc.tableSize =
++  p->repLenEnc.tableSize =
++      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
++  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
++  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
++}
++
++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 i;
++  for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
++    if (p->dictSize <= ((UInt32)1 << i))
++      break;
++  p->distTableSize = i * 2;
++
++  p->finished = False;
++  p->result = SZ_OK;
++  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
++  LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  p->nowPos64 = 0;
++  return SZ_OK;
++}
++
++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  p->rc.outStream = outStream;
++  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
++}
++
++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
++    ISeqInStream *inStream, UInt32 keepWindowSize,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
++{
++  p->matchFinderBase.directInput = 1;
++  p->matchFinderBase.bufferBase = (Byte *)src;
++  p->matchFinderBase.directInputRem = srcLen;
++}
++
++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++    UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++  p->needInit = 1;
++
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++void LzmaEnc_Finish(CLzmaEncHandle pp)
++{
++  #ifndef _7ZIP_ST
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  if (p->mtMode)
++    MatchFinderMt_ReleaseStream(&p->matchFinderMt);
++  #else
++  pp = pp;
++  #endif
++}
++
++typedef struct
++{
++  ISeqOutStream funcTable;
++  Byte *data;
++  SizeT rem;
++  Bool overflow;
++} CSeqOutStreamBuf;
++
++static size_t MyWrite(void *pp, const void *data, size_t size)
++{
++  CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
++  if (p->rem < size)
++  {
++    size = p->rem;
++    p->overflow = True;
++  }
++  memcpy(p->data, data, size);
++  p->rem -= size;
++  p->data += size;
++  return size;
++}
++
++
++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++}
++
++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++}
++
++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
++    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  UInt64 nowPos64;
++  SRes res;
++  CSeqOutStreamBuf outStream;
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = False;
++  p->finished = False;
++  p->result = SZ_OK;
++
++  if (reInit)
++    LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  nowPos64 = p->nowPos64;
++  RangeEnc_Init(&p->rc);
++  p->rc.outStream = &outStream.funcTable;
++
++  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
++  
++  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++
++  return res;
++}
++
++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
++{
++  SRes res = SZ_OK;
++
++  #ifndef _7ZIP_ST
++  Byte allocaDummy[0x300];
++  int i = 0;
++  for (i = 0; i < 16; i++)
++    allocaDummy[i] = (Byte)i;
++  #endif
++
++  for (;;)
++  {
++    res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
++    if (res != SZ_OK || p->finished != 0)
++      break;
++    if (progress != 0)
++    {
++      res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
++      if (res != SZ_OK)
++      {
++        res = SZ_ERROR_PROGRESS;
++        break;
++      }
++    }
++  }
++  LzmaEnc_Finish(p);
++  return res;
++}
++
++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
++  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
++}
++
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  int i;
++  UInt32 dictSize = p->dictSize;
++  if (*size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_PARAM;
++  *size = LZMA_PROPS_SIZE;
++  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
++
++  for (i = 11; i <= 30; i++)
++  {
++    if (dictSize <= ((UInt32)2 << i))
++    {
++      dictSize = (2 << i);
++      break;
++    }
++    if (dictSize <= ((UInt32)3 << i))
++    {
++      dictSize = (3 << i);
++      break;
++    }
++  }
++
++  for (i = 0; i < 4; i++)
++    props[1 + i] = (Byte)(dictSize >> (8 * i));
++  return SZ_OK;
++}
++
++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  SRes res;
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++
++  CSeqOutStreamBuf outStream;
++
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = writeEndMark;
++
++  p->rc.outStream = &outStream.funcTable;
++  res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
++  if (res == SZ_OK)
++    res = LzmaEnc_Encode2(p, progress);
++
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++  return res;
++}
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
++  SRes res;
++  if (p == 0)
++    return SZ_ERROR_MEM;
++
++  res = LzmaEnc_SetProps(p, props);
++  if (res == SZ_OK)
++  {
++    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
++    if (res == SZ_OK)
++      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
++          writeEndMark, progress, alloc, allocBig);
++  }
++
++  LzmaEnc_Destroy(p, alloc, allocBig);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/Makefile
+@@ -0,0 +1,7 @@
++lzma_compress-objs := LzFind.o LzmaEnc.o
++lzma_decompress-objs := LzmaDec.o
++
++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o
++
++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h
diff --git a/target/linux/generic/patches-4.1/531-debloat_lzma.patch b/target/linux/generic/patches-4.1/531-debloat_lzma.patch
new file mode 100644
index 0000000000..aa3c498016
--- /dev/null
+++ b/target/linux/generic/patches-4.1/531-debloat_lzma.patch
@@ -0,0 +1,1024 @@
+--- a/include/linux/lzma/LzmaDec.h
++++ b/include/linux/lzma/LzmaDec.h
+@@ -31,14 +31,6 @@ typedef struct _CLzmaProps
+   UInt32 dicSize;
+ } CLzmaProps;
+ 
+-/* LzmaProps_Decode - decodes properties
+-Returns:
+-  SZ_OK
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+-
+ 
+ /* ---------- LZMA Decoder state ---------- */
+ 
+@@ -70,8 +62,6 @@ typedef struct
+ 
+ #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+ 
+-void LzmaDec_Init(CLzmaDec *p);
+-
+ /* There are two types of LZMA streams:
+      0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+      1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+@@ -108,97 +98,6 @@ typedef enum
+ 
+ /* ELzmaStatus is used only as output value for function call */
+ 
+-
+-/* ---------- Interfaces ---------- */
+-
+-/* There are 3 levels of interfaces:
+-     1) Dictionary Interface
+-     2) Buffer Interface
+-     3) One Call Interface
+-   You can select any of these interfaces, but don't mix functions from different
+-   groups for same object. */
+-
+-
+-/* There are two variants to allocate state for Dictionary Interface:
+-     1) LzmaDec_Allocate / LzmaDec_Free
+-     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+-   You can use variant 2, if you set dictionary buffer manually.
+-   For Buffer Interface you must always use variant 1.
+-
+-LzmaDec_Allocate* can return:
+-  SZ_OK
+-  SZ_ERROR_MEM         - Memory allocation error
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-   
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+-
+-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+-
+-/* ---------- Dictionary Interface ---------- */
+-
+-/* You can use it, if you want to eliminate the overhead for data copying from
+-   dictionary to some other external buffer.
+-   You must work with CLzmaDec variables directly in this interface.
+-
+-   STEPS:
+-     LzmaDec_Constr()
+-     LzmaDec_Allocate()
+-     for (each new stream)
+-     {
+-       LzmaDec_Init()
+-       while (it needs more decompression)
+-       {
+-         LzmaDec_DecodeToDic()
+-         use data from CLzmaDec::dic and update CLzmaDec::dicPos
+-       }
+-     }
+-     LzmaDec_Free()
+-*/
+-
+-/* LzmaDec_DecodeToDic
+-   
+-   The decoding to internal dictionary buffer (CLzmaDec::dic).
+-   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (dicLimit).
+-  LZMA_FINISH_ANY - Decode just dicLimit bytes.
+-  LZMA_FINISH_END - Stream must be finished after dicLimit.
+-
+-Returns:
+-  SZ_OK
+-    status:
+-      LZMA_STATUS_FINISHED_WITH_MARK
+-      LZMA_STATUS_NOT_FINISHED
+-      LZMA_STATUS_NEEDS_MORE_INPUT
+-      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+-  SZ_ERROR_DATA - Data error
+-*/
+-
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+-/* ---------- Buffer Interface ---------- */
+-
+-/* It's zlib-like interface.
+-   See LzmaDec_DecodeToDic description for information about STEPS and return results,
+-   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+-   to work with CLzmaDec variables manually.
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (*destLen).
+-  LZMA_FINISH_ANY - Decode just destLen bytes.
+-  LZMA_FINISH_END - Stream must be finished after (*destLen).
+-*/
+-
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+ /* ---------- One Call Interface ---------- */
+ 
+ /* LzmaDecode
+--- a/lib/lzma/LzmaDec.c
++++ b/lib/lzma/LzmaDec.c
+@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p,
+   p->needFlush = 0;
+ }
+ 
+-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+ {
+   p->needFlush = 1;
+   p->remainLen = 0;
+@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p
+     p->needInitState = 1;
+ }
+ 
+-void LzmaDec_Init(CLzmaDec *p)
++static void LzmaDec_Init(CLzmaDec *p)
+ {
+   p->dicPos = 0;
+   LzmaDec_InitDicAndState(p, True, True);
+@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD
+   p->needInitState = 0;
+ }
+ 
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+     ELzmaFinishMode finishMode, ELzmaStatus *status)
+ {
+   SizeT inSize = *srcLen;
+@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si
+   return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+ }
+ 
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+-{
+-  SizeT outSize = *destLen;
+-  SizeT inSize = *srcLen;
+-  *srcLen = *destLen = 0;
+-  for (;;)
+-  {
+-    SizeT inSizeCur = inSize, outSizeCur, dicPos;
+-    ELzmaFinishMode curFinishMode;
+-    SRes res;
+-    if (p->dicPos == p->dicBufSize)
+-      p->dicPos = 0;
+-    dicPos = p->dicPos;
+-    if (outSize > p->dicBufSize - dicPos)
+-    {
+-      outSizeCur = p->dicBufSize;
+-      curFinishMode = LZMA_FINISH_ANY;
+-    }
+-    else
+-    {
+-      outSizeCur = dicPos + outSize;
+-      curFinishMode = finishMode;
+-    }
+-
+-    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+-    src += inSizeCur;
+-    inSize -= inSizeCur;
+-    *srcLen += inSizeCur;
+-    outSizeCur = p->dicPos - dicPos;
+-    memcpy(dest, p->dic + dicPos, outSizeCur);
+-    dest += outSizeCur;
+-    outSize -= outSizeCur;
+-    *destLen += outSizeCur;
+-    if (res != 0)
+-      return res;
+-    if (outSizeCur == 0 || outSize == 0)
+-      return SZ_OK;
+-  }
+-}
+-
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->probs);
+   p->probs = 0;
+ }
+ 
+-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  alloc->Free(alloc, p->dic);
+-  p->dic = 0;
+-}
+-
+-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  LzmaDec_FreeProbs(p, alloc);
+-  LzmaDec_FreeDict(p, alloc);
+-}
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+ {
+   UInt32 dicSize;
+   Byte d;
+@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma
+   return SZ_OK;
+ }
+ 
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+ {
+   CLzmaProps propNew;
+   RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p,
+   p->prop = propNew;
+   return SZ_OK;
+ }
+-
+-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+-{
+-  CLzmaProps propNew;
+-  SizeT dicBufSize;
+-  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+-  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+-  dicBufSize = propNew.dicSize;
+-  if (p->dic == 0 || dicBufSize != p->dicBufSize)
+-  {
+-    LzmaDec_FreeDict(p, alloc);
+-    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+-    if (p->dic == 0)
+-    {
+-      LzmaDec_FreeProbs(p, alloc);
+-      return SZ_ERROR_MEM;
+-    }
+-  }
+-  p->dicBufSize = dicBufSize;
+-  p->prop = propNew;
+-  return SZ_OK;
+-}
+ 
+ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+     const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+--- a/include/linux/lzma/LzmaEnc.h
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps
+ } CLzmaEncProps;
+ 
+ void LzmaEncProps_Init(CLzmaEncProps *p);
+-void LzmaEncProps_Normalize(CLzmaEncProps *p);
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+-
+ 
+ /* ---------- CLzmaEncHandle Interface ---------- */
+ 
+@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+ void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+     int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ 
+-/* ---------- One Call Interface ---------- */
+-
+-/* LzmaEncode
+-Return code:
+-  SZ_OK               - OK
+-  SZ_ERROR_MEM        - Memory allocation error
+-  SZ_ERROR_PARAM      - Incorrect paramater
+-  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+-  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+-*/
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzmaEnc.c
++++ b/lib/lzma/LzmaEnc.c
+@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p)
+   p->writeEndMark = 0;
+ }
+ 
+-void LzmaEncProps_Normalize(CLzmaEncProps *p)
++static void LzmaEncProps_Normalize(CLzmaEncProps *p)
+ {
+   int level = p->level;
+   if (level < 0) level = 5;
+@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp
+       #endif
+ }
+ 
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+ {
+   CLzmaEncProps props = *props2;
+   LzmaEncProps_Normalize(&props);
+@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL
+ 
+ #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+ 
+-UInt32 GetPosSlot1(UInt32 pos)
++static UInt32 GetPosSlot1(UInt32 pos)
+ {
+   UInt32 res;
+   BSR2_RET(pos, res);
+@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos)
+ #define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+ #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+ 
+-void LzmaEnc_FastPosInit(Byte *g_FastPos)
++static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+ {
+   int c = 2, slotFast;
+   g_FastPos[0] = 0;
+@@ -339,58 +339,6 @@ typedef struct
+   CSaveState saveState;
+ } CLzmaEnc;
+ 
+-void LzmaEnc_SaveState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  CSaveState *dest = &p->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+-}
+-
+-void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *dest = (CLzmaEnc *)pp;
+-  const CSaveState *p = &dest->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+-}
+-
+ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE
+   while (symbol < 0x10000);
+ }
+ 
+-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+ {
+   UInt32 i;
+   for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc
+   p->matchPriceCount = 0;
+ }
+ 
+-void LzmaEnc_Construct(CLzmaEnc *p)
++static void LzmaEnc_Construct(CLzmaEnc *p)
+ {
+   RangeEnc_Construct(&p->rc);
+   MatchFinder_Construct(&p->matchFinderBase);
+@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+   return p;
+ }
+ 
+-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->litProbs);
+   alloc->Free(alloc, p->saveState.litProbs);
+@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl
+   p->saveState.litProbs = 0;
+ }
+ 
+-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   #ifndef _7ZIP_ST
+   MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U
+   return SZ_OK;
+ }
+ 
+-void LzmaEnc_Init(CLzmaEnc *p)
++static void LzmaEnc_Init(CLzmaEnc *p)
+ {
+   UInt32 i;
+   p->state = 0;
+@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p)
+   p->lpMask = (1 << p->lp) - 1;
+ }
+ 
+-void LzmaEnc_InitPrices(CLzmaEnc *p)
++static void LzmaEnc_InitPrices(CLzmaEnc *p)
+ {
+   if (!p->fastMode)
+   {
+@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn
+   return SZ_OK;
+ }
+ 
+-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  p->rc.outStream = outStream;
+-  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+-}
+-
+-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+-    ISeqInStream *inStream, UInt32 keepWindowSize,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+-}
+-
+ static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+ {
+   p->matchFinderBase.directInput = 1;
+@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc
+   p->matchFinderBase.directInputRem = srcLen;
+ }
+ 
+-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+     UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p
+   return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+ }
+ 
+-void LzmaEnc_Finish(CLzmaEncHandle pp)
++static void LzmaEnc_Finish(CLzmaEncHandle pp)
+ {
+   #ifndef _7ZIP_ST
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo
+   return size;
+ }
+ 
+-
+-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+-}
+-
+-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+-}
+-
+-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+-    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  UInt64 nowPos64;
+-  SRes res;
+-  CSeqOutStreamBuf outStream;
+-
+-  outStream.funcTable.Write = MyWrite;
+-  outStream.data = dest;
+-  outStream.rem = *destLen;
+-  outStream.overflow = False;
+-
+-  p->writeEndMark = False;
+-  p->finished = False;
+-  p->result = SZ_OK;
+-
+-  if (reInit)
+-    LzmaEnc_Init(p);
+-  LzmaEnc_InitPrices(p);
+-  nowPos64 = p->nowPos64;
+-  RangeEnc_Init(&p->rc);
+-  p->rc.outStream = &outStream.funcTable;
+-
+-  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+-  
+-  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+-  *destLen -= outStream.rem;
+-  if (outStream.overflow)
+-    return SZ_ERROR_OUTPUT_EOF;
+-
+-  return res;
+-}
+-
+ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+ {
+   SRes res = SZ_OK;
+@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p,
+   return res;
+ }
+ 
+-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+-  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+-}
+-
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp
+     return SZ_ERROR_OUTPUT_EOF;
+   return res;
+ }
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+-  SRes res;
+-  if (p == 0)
+-    return SZ_ERROR_MEM;
+-
+-  res = LzmaEnc_SetProps(p, props);
+-  if (res == SZ_OK)
+-  {
+-    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+-    if (res == SZ_OK)
+-      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+-          writeEndMark, progress, alloc, allocBig);
+-  }
+-
+-  LzmaEnc_Destroy(p, alloc, allocBig);
+-  return res;
+-}
+--- a/include/linux/lzma/LzFind.h
++++ b/include/linux/lzma/LzFind.h
+@@ -55,11 +55,6 @@ typedef struct _CMatchFinder
+ 
+ #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p);
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+-void MatchFinder_MoveBlock(CMatchFinder *p);
+-void MatchFinder_ReadIfRequired(CMatchFinder *p);
+-
+ void MatchFinder_Construct(CMatchFinder *p);
+ 
+ /* Conditions:
+@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p,
+     UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+     ISzAlloc *alloc);
+ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+-    UInt32 *distances, UInt32 maxLen);
+ 
+ /*
+ Conditions:
+@@ -102,12 +91,6 @@ typedef struct _IMatchFinder
+ 
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+ 
+-void MatchFinder_Init(CMatchFinder *p);
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzFind.c
++++ b/lib/lzma/LzFind.c
+@@ -14,9 +14,15 @@
+ 
+ #define kStartMaxLen 3
+ 
++#if 0
++#define DIRECT_INPUT	p->directInput
++#else
++#define DIRECT_INPUT	1
++#endif
++
+ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+ {
+-  if (!p->directInput)
++  if (!DIRECT_INPUT)
+   {
+     alloc->Free(alloc, p->bufferBase);
+     p->bufferBase = 0;
+@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder
+ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+ {
+   UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     p->blockSize = blockSize;
+     return 1;
+@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde
+   return (p->bufferBase != 0);
+ }
+ 
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+ 
+-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+ 
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+ {
+   p->posLimit -= subValue;
+   p->pos -= subValue;
+@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch
+ {
+   if (p->streamEndWasReached || p->result != SZ_OK)
+     return;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+     if (curSize > p->directInputRem)
+@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch
+   }
+ }
+ 
+-void MatchFinder_MoveBlock(CMatchFinder *p)
++static void MatchFinder_MoveBlock(CMatchFinder *p)
+ {
+   memmove(p->bufferBase,
+     p->buffer - p->keepSizeBefore,
+@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder
+   p->buffer = p->bufferBase + p->keepSizeBefore;
+ }
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p)
++static int MatchFinder_NeedMove(CMatchFinder *p)
+ {
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+     return 0;
+   /* if (p->streamEndWasReached) return 0; */
+   return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+ }
+ 
+-void MatchFinder_ReadIfRequired(CMatchFinder *p)
+-{
+-  if (p->streamEndWasReached)
+-    return;
+-  if (p->keepSizeAfter >= p->streamPos - p->pos)
+-    MatchFinder_ReadBlock(p);
+-}
+-
+ static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+ {
+   if (MatchFinder_NeedMove(p))
+@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch
+   p->posLimit = p->pos + limit;
+ }
+ 
+-void MatchFinder_Init(CMatchFinder *p)
++static void MatchFinder_Init(CMatchFinder *p)
+ {
+   UInt32 i;
+   for (i = 0; i < p->hashSizeSum; i++)
+@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM
+   return (p->pos - p->historySize - 1) & kNormalizeMask;
+ }
+ 
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+ {
+   UInt32 i;
+   for (i = 0; i < numItems; i++)
+@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat
+   MatchFinder_SetLimits(p);
+ }
+ 
+-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+-    UInt32 *distances, UInt32 maxLen)
+-{
+-  son[_cyclicBufferPos] = curMatch;
+-  for (;;)
+-  {
+-    UInt32 delta = pos - curMatch;
+-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+-      return distances;
+-    {
+-      const Byte *pb = cur - delta;
+-      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+-      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+-      {
+-        UInt32 len = 0;
+-        while (++len != lenLimit)
+-          if (pb[len] != cur[len])
+-            break;
+-        if (maxLen < len)
+-        {
+-          *distances++ = maxLen = len;
+-          *distances++ = delta - 1;
+-          if (len == lenLimit)
+-            return distances;
+-        }
+-      }
+-    }
+-  }
+-}
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+     UInt32 *distances, UInt32 maxLen)
+ {
+@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi
+   p->buffer++; \
+   if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+ 
+-#define MOVE_POS_RET MOVE_POS return offset;
+-
+ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+ 
++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset;
++
+ #define GET_MATCHES_HEADER2(minLen, ret_op) \
+   UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+   lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi
+   distances + offset, maxLen) - distances); MOVE_POS_RET;
+ 
+ #define SKIP_FOOTER \
+-  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+-
+-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(2)
+-  HASH2_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 1)
+-}
+-
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 2)
+-}
+-
+-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, delta2, maxLen, offset;
+-  GET_MATCHES_HEADER(3)
+-
+-  HASH3_CALC;
+-
+-  delta2 = p->pos - p->hash[hash2Value];
+-  curMatch = p->hash[kFix3HashSize + hashValue];
+-  
+-  p->hash[hash2Value] =
+-  p->hash[kFix3HashSize + hashValue] = p->pos;
+-
+-
+-  maxLen = 2;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[0] = maxLen;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-    if (maxLen == lenLimit)
+-    {
+-      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+-      MOVE_POS_RET;
+-    }
+-  }
+-  GET_MATCHES_FOOTER(offset, maxLen)
+-}
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p);
+ 
+ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+ {
+@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches
+   GET_MATCHES_FOOTER(offset, maxLen)
+ }
+ 
+-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+-  GET_MATCHES_HEADER(4)
+-
+-  HASH4_CALC;
+-
+-  delta2 = p->pos - p->hash[                hash2Value];
+-  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+-  curMatch = p->hash[kFix4HashSize + hashValue];
+-
+-  p->hash[                hash2Value] =
+-  p->hash[kFix3HashSize + hash3Value] =
+-  p->hash[kFix4HashSize + hashValue] = p->pos;
+-
+-  maxLen = 1;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    distances[0] = maxLen = 2;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-  }
+-  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+-  {
+-    maxLen = 3;
+-    distances[offset + 1] = delta3 - 1;
+-    offset += 2;
+-    delta2 = delta3;
+-  }
+-  if (offset != 0)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[offset - 2] = maxLen;
+-    if (maxLen == lenLimit)
+-    {
+-      p->son[p->cyclicBufferPos] = curMatch;
+-      MOVE_POS_RET;
+-    }
+-  }
+-  if (maxLen < 3)
+-    maxLen = 3;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances + offset, maxLen) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances, 2) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(2)
+-    HASH2_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value;
+-    SKIP_HEADER(3)
+-    HASH3_CALC;
+-    curMatch = p->hash[kFix3HashSize + hashValue];
+-    p->hash[hash2Value] =
+-    p->hash[kFix3HashSize + hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+ {
+   do
+@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF
+   while (--num != 0);
+ }
+ 
+-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value, hash3Value;
+-    SKIP_HEADER(4)
+-    HASH4_CALC;
+-    curMatch = p->hash[kFix4HashSize + hashValue];
+-    p->hash[                hash2Value] =
+-    p->hash[kFix3HashSize + hash3Value] =
+-    p->hash[kFix4HashSize + hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+ {
+   vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+   vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+   vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+   vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+-  if (!p->btMode)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 2)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 3)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+-  }
+-  else
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+-  }
++  vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++  vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
diff --git a/target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch b/target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch
new file mode 100644
index 0000000000..8ce53d8bed
--- /dev/null
+++ b/target/linux/generic/patches-4.1/532-jffs2_eofdetect.patch
@@ -0,0 +1,56 @@
+--- a/fs/jffs2/build.c
++++ b/fs/jffs2/build.c
+@@ -116,6 +116,16 @@ static int jffs2_build_filesystem(struct
+ 	dbg_fsbuild("scanned flash completely\n");
+ 	jffs2_dbg_dump_block_lists_nolock(c);
+ 
++	if (c->flags & (1 << 7)) {
++		printk("%s(): unlocking the mtd device... ", __func__);
++		mtd_unlock(c->mtd, 0, c->mtd->size);
++		printk("done.\n");
++
++		printk("%s(): erasing all blocks after the end marker... ", __func__);
++		jffs2_erase_pending_blocks(c, -1);
++		printk("done.\n");
++	}
++
+ 	dbg_fsbuild("pass 1 starting\n");
+ 	c->flags |= JFFS2_SB_FLAG_BUILDING;
+ 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
+--- a/fs/jffs2/scan.c
++++ b/fs/jffs2/scan.c
+@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
+ 		/* reset summary info for next eraseblock scan */
+ 		jffs2_sum_reset_collected(s);
+ 
+-		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+-						buf_size, s);
++		if (c->flags & (1 << 7)) {
++			if (mtd_block_isbad(c->mtd, jeb->offset))
++				ret = BLK_STATE_BADBLOCK;
++			else
++				ret = BLK_STATE_ALLFF;
++		} else
++			ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
++							buf_size, s);
+ 
+ 		if (ret < 0)
+ 			goto out;
+@@ -561,6 +567,17 @@ full_scan:
+ 			return err;
+ 	}
+ 
++	if ((buf[0] == 0xde) &&
++		(buf[1] == 0xad) &&
++		(buf[2] == 0xc0) &&
++		(buf[3] == 0xde)) {
++		/* end of filesystem. erase everything after this point */
++		printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
++		c->flags |= (1 << 7);
++
++		return BLK_STATE_ALLFF;
++	}
++
+ 	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+ 	ofs = 0;
+ 	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
diff --git a/target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch b/target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch
new file mode 100644
index 0000000000..c250e9f024
--- /dev/null
+++ b/target/linux/generic/patches-4.1/540-crypto-xz-decompression-support.patch
@@ -0,0 +1,146 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1435,6 +1435,13 @@ config CRYPTO_LZ4HC
+ 	help
+ 	  This is the LZ4 high compression mode algorithm.
+ 
++config CRYPTO_XZ
++	tristate "XZ compression algorithm"
++	select CRYPTO_ALGAPI
++	select XZ_DEC
++	help
++	  This is the XZ algorithm. Only decompression is supported for now.
++
+ comment "Random Number Generation"
+ 
+ config CRYPTO_ANSI_CPRNG
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -89,6 +89,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.
+ obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+ obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
+ obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
++obj-$(CONFIG_CRYPTO_XZ) += xz.o
+ obj-$(CONFIG_CRYPTO_842) += 842.o
+ obj-$(CONFIG_CRYPTO_RNG2) += rng.o
+ obj-$(CONFIG_CRYPTO_RNG2) += krng.o
+--- /dev/null
++++ b/crypto/xz.c
+@@ -0,0 +1,117 @@
++/*
++ * Cryptographic API.
++ *
++ * XZ decompression support.
++ *
++ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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/init.h>
++#include <linux/module.h>
++#include <linux/crypto.h>
++#include <linux/xz.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/net.h>
++
++struct xz_comp_ctx {
++	struct xz_dec	*decomp_state;
++	struct xz_buf	decomp_buf;
++};
++
++static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx)
++{
++	ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0);
++	if (!ctx->decomp_state)
++		return -ENOMEM;
++
++	return 0;
++}
++
++static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx)
++{
++	xz_dec_end(ctx->decomp_state);
++}
++
++static int crypto_xz_init(struct crypto_tfm *tfm)
++{
++	struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	return crypto_xz_decomp_init(ctx);
++}
++
++static void crypto_xz_exit(struct crypto_tfm *tfm)
++{
++	struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_xz_decomp_exit(ctx);
++}
++
++static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src,
++			      unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++	return -EOPNOTSUPP;
++}
++
++static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src,
++				unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++	struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm);
++	struct xz_buf *xz_buf = &dctx->decomp_buf;
++	int ret;
++
++	memset(xz_buf, '\0', sizeof(struct xz_buf));
++
++	xz_buf->in = (u8 *) src;
++	xz_buf->in_pos = 0;
++	xz_buf->in_size = slen;
++	xz_buf->out = (u8 *) dst;
++	xz_buf->out_pos = 0;
++	xz_buf->out_size = *dlen;
++
++	ret = xz_dec_run(dctx->decomp_state, xz_buf);
++	if (ret != XZ_STREAM_END) {
++		ret = -EINVAL;
++		goto out;
++	}
++
++	*dlen = xz_buf->out_pos;
++	ret = 0;
++
++out:
++	return ret;
++}
++
++static struct crypto_alg crypto_xz_alg = {
++	.cra_name		= "xz",
++	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
++	.cra_ctxsize		= sizeof(struct xz_comp_ctx),
++	.cra_module		= THIS_MODULE,
++	.cra_list		= LIST_HEAD_INIT(crypto_xz_alg.cra_list),
++	.cra_init		= crypto_xz_init,
++	.cra_exit		= crypto_xz_exit,
++	.cra_u			= { .compress = {
++	.coa_compress 		= crypto_xz_compress,
++	.coa_decompress  	= crypto_xz_decompress } }
++};
++
++static int __init crypto_xz_mod_init(void)
++{
++	return crypto_register_alg(&crypto_xz_alg);
++}
++
++static void __exit crypto_xz_mod_exit(void)
++{
++	crypto_unregister_alg(&crypto_xz_alg);
++}
++
++module_init(crypto_xz_mod_init);
++module_exit(crypto_xz_mod_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Crypto XZ decompression support");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
diff --git a/target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch b/target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch
new file mode 100644
index 0000000000..f85689c586
--- /dev/null
+++ b/target/linux/generic/patches-4.1/541-ubifs-xz-decompression-support.patch
@@ -0,0 +1,92 @@
+--- a/fs/ubifs/Kconfig
++++ b/fs/ubifs/Kconfig
+@@ -5,8 +5,10 @@ config UBIFS_FS
+ 	select CRYPTO if UBIFS_FS_ADVANCED_COMPR
+ 	select CRYPTO if UBIFS_FS_LZO
+ 	select CRYPTO if UBIFS_FS_ZLIB
++	select CRYPTO if UBIFS_FS_XZ
+ 	select CRYPTO_LZO if UBIFS_FS_LZO
+ 	select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
++	select CRYPTO_XZ if UBIFS_FS_XZ
+ 	depends on MTD_UBI
+ 	help
+ 	  UBIFS is a file system for flash devices which works on top of UBI.
+@@ -35,3 +37,12 @@ config UBIFS_FS_ZLIB
+ 	default y
+ 	help
+ 	  Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
++
++config UBIFS_FS_XZ
++	bool "XZ decompression support" if UBIFS_FS_ADVANCED_COMPR
++	depends on UBIFS_FS
++	default y
++	help
++	  XZ compresses better the ZLIB but it is slower..
++	  Say 'Y' if unsure.
++
+--- a/fs/ubifs/compress.c
++++ b/fs/ubifs/compress.c
+@@ -71,6 +71,24 @@ static struct ubifs_compressor zlib_comp
+ };
+ #endif
+ 
++#ifdef CONFIG_UBIFS_FS_XZ
++static DEFINE_MUTEX(xz_enc_mutex);
++static DEFINE_MUTEX(xz_dec_mutex);
++
++static struct ubifs_compressor xz_compr = {
++	.compr_type = UBIFS_COMPR_XZ,
++	.comp_mutex = &xz_enc_mutex,
++	.decomp_mutex = &xz_dec_mutex,
++	.name = "xz",
++	.capi_name = "xz",
++};
++#else
++static struct ubifs_compressor xz_compr = {
++	.compr_type = UBIFS_COMPR_XZ,
++	.name = "xz",
++};
++#endif
++
+ /* All UBIFS compressors */
+ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+ 
+@@ -232,9 +250,15 @@ int __init ubifs_compressors_init(void)
+ 	if (err)
+ 		goto out_lzo;
+ 
++	err = compr_init(&xz_compr);
++	if (err)
++		goto out_zlib;
++
+ 	ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
+ 	return 0;
+ 
++out_zlib:
++	compr_exit(&zlib_compr);
+ out_lzo:
+ 	compr_exit(&lzo_compr);
+ 	return err;
+@@ -247,4 +271,5 @@ void ubifs_compressors_exit(void)
+ {
+ 	compr_exit(&lzo_compr);
+ 	compr_exit(&zlib_compr);
++	compr_exit(&xz_compr);
+ }
+--- a/fs/ubifs/ubifs-media.h
++++ b/fs/ubifs/ubifs-media.h
+@@ -332,12 +332,14 @@ enum {
+  * UBIFS_COMPR_NONE: no compression
+  * UBIFS_COMPR_LZO: LZO compression
+  * UBIFS_COMPR_ZLIB: ZLIB compression
++ * UBIFS_COMPR_XZ: XZ compression
+  * UBIFS_COMPR_TYPES_CNT: count of supported compression types
+  */
+ enum {
+ 	UBIFS_COMPR_NONE,
+ 	UBIFS_COMPR_LZO,
+ 	UBIFS_COMPR_ZLIB,
++	UBIFS_COMPR_XZ,
+ 	UBIFS_COMPR_TYPES_CNT,
+ };
+ 
diff --git a/target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch b/target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch
new file mode 100644
index 0000000000..1b0f30718c
--- /dev/null
+++ b/target/linux/generic/patches-4.1/551-ubifs-fix-default-compression-selection.patch
@@ -0,0 +1,29 @@
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -63,6 +63,17 @@
+ /* Default time granularity in nanoseconds */
+ #define DEFAULT_TIME_GRAN 1000000000
+ 
++static int get_default_compressor(void)
++{
++	if (ubifs_compr_present(UBIFS_COMPR_LZO))
++		return UBIFS_COMPR_LZO;
++
++	if (ubifs_compr_present(UBIFS_COMPR_ZLIB))
++		return UBIFS_COMPR_ZLIB;
++
++	return UBIFS_COMPR_NONE;
++}
++
+ /**
+  * create_default_filesystem - format empty UBI volume.
+  * @c: UBIFS file-system description object
+@@ -183,7 +194,7 @@ static int create_default_filesystem(str
+ 	if (c->mount_opts.override_compr)
+ 		sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
+ 	else
+-		sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
++		sup->default_compr = cpu_to_le16(get_default_compressor());
+ 
+ 	generate_random_uuid(sup->uuid);
+ 
diff --git a/target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch b/target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch
new file mode 100644
index 0000000000..bd7a7ffdef
--- /dev/null
+++ b/target/linux/generic/patches-4.1/600-netfilter_conntrack_flush.patch
@@ -0,0 +1,86 @@
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -17,6 +17,7 @@
+ #include <linux/percpu.h>
+ #include <linux/netdevice.h>
+ #include <linux/security.h>
++#include <linux/inet.h>
+ #include <net/net_namespace.h>
+ #ifdef CONFIG_SYSCTL
+ #include <linux/sysctl.h>
+@@ -259,10 +260,66 @@ static int ct_open(struct inode *inode,
+ 			sizeof(struct ct_iter_state));
+ }
+ 
++struct kill_request {
++	u16 family;
++	union nf_inet_addr addr;
++};
++
++static int kill_matching(struct nf_conn *i, void *data)
++{
++	struct kill_request *kr = data;
++	struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++	struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
++
++	if (!kr->family)
++		return 1;
++
++	if (t1->src.l3num != kr->family)
++		return 0;
++
++	return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
++}
++
++static ssize_t ct_file_write(struct file *file, const char __user *buf,
++			     size_t count, loff_t *ppos)
++{
++	struct seq_file *seq = file->private_data;
++	struct net *net = seq_file_net(seq);
++	struct kill_request kr = { };
++	char req[INET6_ADDRSTRLEN] = { };
++
++	if (count == 0)
++		return 0;
++
++	if (count >= INET6_ADDRSTRLEN)
++		count = INET6_ADDRSTRLEN - 1;
++
++	if (copy_from_user(req, buf, count))
++		return -EFAULT;
++
++	if (strnchr(req, count, ':')) {
++		kr.family = AF_INET6;
++		if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	} else if (strnchr(req, count, '.')) {
++		kr.family = AF_INET;
++		if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	}
++
++	nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0);
++
++	return count;
++}
++
+ static const struct file_operations ct_file_ops = {
+ 	.owner   = THIS_MODULE,
+ 	.open    = ct_open,
+ 	.read    = seq_read,
++	.write	 = ct_file_write,
+ 	.llseek  = seq_lseek,
+ 	.release = seq_release_net,
+ };
+@@ -364,7 +421,7 @@ static int nf_conntrack_standalone_init_
+ {
+ 	struct proc_dir_entry *pde;
+ 
+-	pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops);
++	pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops);
+ 	if (!pde)
+ 		goto out_nf_conntrack;
+ 
diff --git a/target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch
new file mode 100644
index 0000000000..1187845879
--- /dev/null
+++ b/target/linux/generic/patches-4.1/610-netfilter_match_bypass_default_checks.patch
@@ -0,0 +1,84 @@
+--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
+@@ -87,6 +87,7 @@ struct ipt_ip {
+ #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
+ #define IPT_F_GOTO		0x02	/* Set if jump is a goto */
+ #define IPT_F_MASK		0x03	/* All possible flag bits mask. */
++#define IPT_F_NO_DEF_MATCH	0x80	/* Internal: no default match rules present */
+ 
+ /* Values for "inv" field in struct ipt_ip. */
+ #define IPT_INV_VIA_IN		0x01	/* Invert the sense of IN IFACE. */
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -82,6 +82,9 @@ ip_packet_match(const struct iphdr *ip,
+ 
+ #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
+ 
++	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
++		return true;
++
+ 	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+ 		  IPT_INV_SRCIP) ||
+ 	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+@@ -135,6 +138,29 @@ ip_packet_match(const struct iphdr *ip,
+ 	return true;
+ }
+ 
++static void
++ip_checkdefault(struct ipt_ip *ip)
++{
++	static const char iface_mask[IFNAMSIZ] = {};
++
++	if (ip->invflags || ip->flags & IPT_F_FRAG)
++		return;
++
++	if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (ip->smsk.s_addr || ip->dmsk.s_addr)
++		return;
++
++	if (ip->proto)
++		return;
++
++	ip->flags |= IPT_F_NO_DEF_MATCH;
++}
++
+ static bool
+ ip_checkentry(const struct ipt_ip *ip)
+ {
+@@ -649,6 +675,8 @@ find_check_entry(struct ipt_entry *e, st
+ 	struct xt_mtchk_param mtpar;
+ 	struct xt_entry_match *ematch;
+ 
++	ip_checkdefault(&e->ip);
++
+ 	j = 0;
+ 	mtpar.net	= net;
+ 	mtpar.table     = name;
+@@ -941,6 +969,7 @@ copy_entries_to_user(unsigned int total_
+ 	const struct xt_table_info *private = table->private;
+ 	int ret = 0;
+ 	const void *loc_cpu_entry;
++	u8 flags;
+ 
+ 	counters = alloc_counters(table);
+ 	if (IS_ERR(counters))
+@@ -971,6 +1000,14 @@ copy_entries_to_user(unsigned int total_
+ 			ret = -EFAULT;
+ 			goto free_counters;
+ 		}
++
++		flags = e->ip.flags & IPT_F_MASK;
++		if (copy_to_user(userptr + off
++				 + offsetof(struct ipt_entry, ip.flags),
++				 &flags, sizeof(flags)) != 0) {
++			ret = -EFAULT;
++			goto free_counters;
++		}
+ 
+ 		for (i = sizeof(struct ipt_entry);
+ 		     i < e->target_offset;
diff --git a/target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch
new file mode 100644
index 0000000000..9e2290d7d6
--- /dev/null
+++ b/target/linux/generic/patches-4.1/611-netfilter_match_bypass_default_table.patch
@@ -0,0 +1,94 @@
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -310,6 +310,33 @@ struct ipt_entry *ipt_next_entry(const s
+ 	return (void *)entry + entry->next_offset;
+ }
+ 
++static bool
++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
++{
++	struct xt_entry_target *t;
++	struct xt_standard_target *st;
++
++	if (e->target_offset != sizeof(struct ipt_entry))
++		return false;
++
++	if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
++		return false;
++
++	t = ipt_get_target(e);
++	if (t->u.kernel.target->target)
++		return false;
++
++	st = (struct xt_standard_target *) t;
++	if (st->verdict == XT_RETURN)
++		return false;
++
++	if (st->verdict >= 0)
++		return false;
++
++	*verdict = (unsigned)(-st->verdict) - 1;
++	return true;
++}
++
+ /* Returns one of the generic firewall policies, like NF_ACCEPT. */
+ unsigned int
+ ipt_do_table(struct sk_buff *skb,
+@@ -330,9 +357,33 @@ ipt_do_table(struct sk_buff *skb,
+ 	unsigned int addend;
+ 
+ 	/* Initialization */
++	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
++	local_bh_disable();
++	private = table->private;
++	cpu        = smp_processor_id();
++	/*
++	 * Ensure we load private-> members after we've fetched the base
++	 * pointer.
++	 */
++	smp_read_barrier_depends();
++	table_base = private->entries[cpu];
++
++	e = get_entry(table_base, private->hook_entry[hook]);
++	if (ipt_handle_default_rule(e, &verdict)) {
++		ADD_COUNTER(e->counters, skb->len, 1);
++		local_bh_enable();
++		return verdict;
++	}
++
+ 	ip = ip_hdr(skb);
+ 	indev = state->in ? state->in->name : nulldevname;
+ 	outdev = state->out ? state->out->name : nulldevname;
++
++	addend = xt_write_recseq_begin();
++	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
++	stackptr   = per_cpu_ptr(private->stackptr, cpu);
++	origptr    = *stackptr;
++
+ 	/* We handle fragments by dealing with the first fragment as
+ 	 * if it was a normal packet.  All other fragments are treated
+ 	 * normally, except that they will NEVER match rules that ask
+@@ -347,23 +398,6 @@ ipt_do_table(struct sk_buff *skb,
+ 	acpar.family  = NFPROTO_IPV4;
+ 	acpar.hooknum = hook;
+ 
+-	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
+-	local_bh_disable();
+-	addend = xt_write_recseq_begin();
+-	private = table->private;
+-	cpu        = smp_processor_id();
+-	/*
+-	 * Ensure we load private-> members after we've fetched the base
+-	 * pointer.
+-	 */
+-	smp_read_barrier_depends();
+-	table_base = private->entries[cpu];
+-	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
+-	stackptr   = per_cpu_ptr(private->stackptr, cpu);
+-	origptr    = *stackptr;
+-
+-	e = get_entry(table_base, private->hook_entry[hook]);
+-
+ 	pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n",
+ 		 table->name, hook, origptr,
+ 		 get_entry(table_base, private->underflow[hook]));
diff --git a/target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch
new file mode 100644
index 0000000000..72172d8bb4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/612-netfilter_match_reduce_memory_access.patch
@@ -0,0 +1,16 @@
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -85,9 +85,11 @@ ip_packet_match(const struct iphdr *ip,
+ 	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+ 		return true;
+ 
+-	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
++	if (FWINV(ipinfo->smsk.s_addr &&
++		  (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+ 		  IPT_INV_SRCIP) ||
+-	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
++	    FWINV(ipinfo->dmsk.s_addr &&
++		  (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+ 		  IPT_INV_DSTIP)) {
+ 		dprintf("Source or dest mismatch.\n");
+ 
diff --git a/target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch b/target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch
new file mode 100644
index 0000000000..3740dd74e5
--- /dev/null
+++ b/target/linux/generic/patches-4.1/613-netfilter_optional_tcp_window_check.patch
@@ -0,0 +1,36 @@
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -33,6 +33,9 @@
+ #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+ #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+ 
++/* Do not check the TCP window for incoming packets  */
++static int nf_ct_tcp_no_window_check __read_mostly = 1;
++
+ /* "Be conservative in what you do,
+     be liberal in what you accept from others."
+     If it's non-zero, we mark only out of window RST segments as INVALID. */
+@@ -515,6 +518,9 @@ static bool tcp_in_window(const struct n
+ 	s32 receiver_offset;
+ 	bool res, in_recv_win;
+ 
++	if (nf_ct_tcp_no_window_check)
++		return true;
++
+ 	/*
+ 	 * Get the required data from the packet.
+ 	 */
+@@ -1481,6 +1487,13 @@ static struct ctl_table tcp_sysctl_table
+ 		.mode		= 0644,
+ 		.proc_handler	= proc_dointvec,
+ 	},
++	{
++		.procname       = "nf_conntrack_tcp_no_window_check",
++		.data           = &nf_ct_tcp_no_window_check,
++		.maxlen         = sizeof(unsigned int),
++		.mode           = 0644,
++		.proc_handler   = proc_dointvec,
++	},
+ 	{ }
+ };
+ 
diff --git a/target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch b/target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch
new file mode 100644
index 0000000000..7d0fe27e98
--- /dev/null
+++ b/target/linux/generic/patches-4.1/615-netfilter_add_xt_id_match.patch
@@ -0,0 +1,95 @@
+--- a/include/uapi/linux/netfilter/Kbuild
++++ b/include/uapi/linux/netfilter/Kbuild
+@@ -55,6 +55,7 @@ header-y += xt_ecn.h
+ header-y += xt_esp.h
+ header-y += xt_hashlimit.h
+ header-y += xt_helper.h
++header-y += xt_id.h
+ header-y += xt_ipcomp.h
+ header-y += xt_iprange.h
+ header-y += xt_ipvs.h
+--- /dev/null
++++ b/include/uapi/linux/netfilter/xt_id.h
+@@ -0,0 +1,8 @@
++#ifndef _XT_ID_H
++#define _XT_ID_H
++
++struct xt_id_info {
++	u32 id;
++};
++
++#endif /* XT_ID_H */
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -1164,6 +1164,13 @@ config NETFILTER_XT_MATCH_IPCOMP
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config NETFILTER_XT_MATCH_ID
++	tristate '"id" match support'
++	depends on NETFILTER_ADVANCED
++	---help---
++	This option adds a `id' dummy-match, which allows you to put
++	numeric IDs into your iptables ruleset.
++
+ config NETFILTER_XT_MATCH_IPRANGE
+ 	tristate '"iprange" address range match support'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -145,6 +145,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) +=
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
++obj-$(CONFIG_NETFILTER_XT_MATCH_ID) += xt_id.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
+--- /dev/null
++++ b/net/netfilter/xt_id.c
+@@ -0,0 +1,45 @@
++/*
++ * Implements a dummy match to allow attaching IDs to rules
++ *
++ * 2014-08-01 Jo-Philipp Wich <jo@mein.io>
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_id.h>
++
++MODULE_AUTHOR("Jo-Philipp Wich <jo@mein.io>");
++MODULE_DESCRIPTION("Xtables: No-op match which can be tagged with a 32bit ID");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_id");
++MODULE_ALIAS("ip6t_id");
++
++static bool
++id_mt(const struct sk_buff *skb, struct xt_action_param *par)
++{
++	/* We always match */
++	return true;
++}
++
++static struct xt_match id_mt_reg __read_mostly = {
++	.name      = "id",
++	.revision  = 0,
++	.family    = NFPROTO_UNSPEC,
++	.match     = id_mt,
++	.matchsize = sizeof(struct xt_id_info),
++	.me        = THIS_MODULE,
++};
++
++static int __init id_mt_init(void)
++{
++	return xt_register_match(&id_mt_reg);
++}
++
++static void __exit id_mt_exit(void)
++{
++	xt_unregister_match(&id_mt_reg);
++}
++
++module_init(id_mt_init);
++module_exit(id_mt_exit);
diff --git a/target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch b/target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch
new file mode 100644
index 0000000000..2a64d5420a
--- /dev/null
+++ b/target/linux/generic/patches-4.1/616-net_optimize_xfrm_calls.patch
@@ -0,0 +1,12 @@
+--- a/net/netfilter/nf_nat_core.c
++++ b/net/netfilter/nf_nat_core.c
+@@ -90,6 +90,9 @@ int nf_xfrm_me_harder(struct sk_buff *sk
+ 	struct dst_entry *dst;
+ 	int err;
+ 
++	if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT])
++		return 0;
++
+ 	err = xfrm_decode_session(skb, &fl, family);
+ 	if (err < 0)
+ 		return err;
diff --git a/target/linux/generic/patches-4.1/630-packet_socket_type.patch b/target/linux/generic/patches-4.1/630-packet_socket_type.patch
new file mode 100644
index 0000000000..a59cba33d6
--- /dev/null
+++ b/target/linux/generic/patches-4.1/630-packet_socket_type.patch
@@ -0,0 +1,134 @@
+This patch allows the user to specify desired packet types (outgoing,
+broadcast, unicast, etc.) on packet sockets via setsockopt.
+This can reduce the load in situations where only a limited number
+of packet types are necessary
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/include/uapi/linux/if_packet.h
++++ b/include/uapi/linux/if_packet.h
+@@ -31,6 +31,8 @@ struct sockaddr_ll {
+ #define PACKET_KERNEL		7		/* To kernel space	*/
+ /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
+ #define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
++#define PACKET_MASK_ANY		0xffffffff	/* mask for packet type bits */
++
+ 
+ /* Packet socket options */
+ 
+@@ -54,6 +56,7 @@ struct sockaddr_ll {
+ #define PACKET_FANOUT			18
+ #define PACKET_TX_HAS_OFF		19
+ #define PACKET_QDISC_BYPASS		20
++#define PACKET_RECV_TYPE		21
+ 
+ #define PACKET_FANOUT_HASH		0
+ #define PACKET_FANOUT_LB		1
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -1547,6 +1547,7 @@ static int packet_rcv_spkt(struct sk_buf
+ {
+ 	struct sock *sk;
+ 	struct sockaddr_pkt *spkt;
++	struct packet_sock *po;
+ 
+ 	/*
+ 	 *	When we registered the protocol we saved the socket in the data
+@@ -1554,6 +1555,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 */
+ 
+ 	sk = pt->af_packet_priv;
++	po = pkt_sk(sk);
+ 
+ 	/*
+ 	 *	Yank back the headers [hope the device set this
+@@ -1566,7 +1568,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 *	so that this procedure is noop.
+ 	 */
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
+ 		goto out;
+ 
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+@@ -1769,12 +1771,12 @@ static int packet_rcv(struct sk_buff *sk
+ 	int skb_len = skb->len;
+ 	unsigned int snaplen, res;
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -1894,12 +1896,12 @@ static int tpacket_rcv(struct sk_buff *s
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -2866,6 +2868,7 @@ static int packet_create(struct net *net
+ 	spin_lock_init(&po->bind_lock);
+ 	mutex_init(&po->pg_vec_lock);
+ 	po->prot_hook.func = packet_rcv;
++	po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
+ 
+ 	if (sock->type == SOCK_PACKET)
+ 		po->prot_hook.func = packet_rcv_spkt;
+@@ -3472,6 +3475,16 @@ packet_setsockopt(struct socket *sock, i
+ 		po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
+ 		return 0;
+ 	}
++        case PACKET_RECV_TYPE:
++        {
++                unsigned int val;
++                if (optlen != sizeof(val))
++                        return -EINVAL;
++                if (copy_from_user(&val, optval, sizeof(val)))
++                        return -EFAULT;
++                po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
++                return 0;
++        }
+ 	default:
+ 		return -ENOPROTOOPT;
+ 	}
+@@ -3523,6 +3536,13 @@ static int packet_getsockopt(struct sock
+ 	case PACKET_VNET_HDR:
+ 		val = po->has_vnet_hdr;
+ 		break;
++	case PACKET_RECV_TYPE:
++		if (len > sizeof(unsigned int))
++			len = sizeof(unsigned int);
++		val = po->pkt_type;
++
++		data = &val;
++		break;
+ 	case PACKET_VERSION:
+ 		val = po->tp_version;
+ 		break;
+--- a/net/packet/internal.h
++++ b/net/packet/internal.h
+@@ -115,6 +115,7 @@ struct packet_sock {
+ 	struct net_device __rcu	*cached_dev;
+ 	int			(*xmit)(struct sk_buff *skb);
+ 	struct packet_type	prot_hook ____cacheline_aligned_in_smp;
++	unsigned int		pkt_type;
+ };
+ 
+ static struct packet_sock *pkt_sk(struct sock *sk)
diff --git a/target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch b/target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch
new file mode 100644
index 0000000000..2b55f13bbc
--- /dev/null
+++ b/target/linux/generic/patches-4.1/640-bridge_no_eap_forward.patch
@@ -0,0 +1,23 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: no EAP forward
+
+When bridging, do not forward EAP frames to other ports, only deliver
+them locally.
+Fixes WPA authentication issues with multiples APs that are connected to
+each other via bridges.
+---
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -162,7 +162,11 @@ int br_handle_frame_finish(struct sock *
+ 	if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
+ 		br_do_proxy_arp(skb, br, vid, p);
+ 
+-	if (is_broadcast_ether_addr(dest)) {
++	if (skb->protocol == htons(ETH_P_PAE)) {
++		skb2 = skb;
++		/* Do not forward 802.1x/EAP frames */
++		skb = NULL;
++	} else if (is_broadcast_ether_addr(dest)) {
+ 		skb2 = skb;
+ 		unicast = false;
+ 	} else if (is_multicast_ether_addr(dest)) {
diff --git a/target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch b/target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch
new file mode 100644
index 0000000000..a4b3ed48a3
--- /dev/null
+++ b/target/linux/generic/patches-4.1/641-bridge_always_accept_eap.patch
@@ -0,0 +1,17 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: always accept EAP
+
+Allow EAP frames to pass through bridges even in learning state. Fixes
+issues with WDS.
+---
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -146,7 +146,7 @@ int br_handle_frame_finish(struct sock *
+ 	    br_multicast_rcv(br, p, skb, vid))
+ 		goto drop;
+ 
+-	if (p->state == BR_STATE_LEARNING)
++	if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE))
+ 		goto drop;
+ 
+ 	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
diff --git a/target/linux/generic/patches-4.1/642-bridge_port_isolate.patch b/target/linux/generic/patches-4.1/642-bridge_port_isolate.patch
new file mode 100644
index 0000000000..d7ae041b25
--- /dev/null
+++ b/target/linux/generic/patches-4.1/642-bridge_port_isolate.patch
@@ -0,0 +1,107 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: port isolate
+
+Isolating individual bridge ports
+---
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -45,6 +45,7 @@ struct br_ip_list {
+ #define BR_PROXYARP		BIT(8)
+ #define BR_LEARNING_SYNC	BIT(9)
+ #define BR_PROXYARP_WIFI	BIT(10)
++#define BR_ISOLATE_MODE	BIT(11)
+ 
+ extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
+ 
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -173,6 +173,22 @@ BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD
+ BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
+ BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
+ 
++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf)
++{
++	int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0;
++	return sprintf(buf, "%d\n", isolate_mode);
++}
++static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v)
++{
++	if (v)
++		p->flags |= BR_ISOLATE_MODE;
++	else
++		p->flags &= ~BR_ISOLATE_MODE;
++	return 0;
++}
++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR,
++		   show_isolate_mode, store_isolate_mode);
++
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
+ {
+@@ -217,6 +233,7 @@ static const struct brport_attribute *br
+ #endif
+ 	&brport_attr_proxyarp,
+ 	&brport_attr_proxyarp_wifi,
++	&brport_attr_isolate_mode,
+ 	NULL
+ };
+ 
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -185,8 +185,8 @@ int br_handle_frame_finish(struct sock *
+ 
+ 		unicast = false;
+ 		br->dev->stats.multicast++;
+-	} else if ((dst = __br_fdb_get(br, dest, vid)) &&
+-			dst->is_local) {
++	} else if ((p->flags & BR_ISOLATE_MODE) ||
++		   ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local)) {
+ 		skb2 = skb;
+ 		/* Do not forward the packet since it's local. */
+ 		skb = NULL;
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(br_deliver);
+ /* called with rcu_read_lock */
+ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
+ {
+-	if (should_deliver(to, skb)) {
++	if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) {
+ 		if (skb0)
+ 			deliver_clone(to, skb, __br_forward);
+ 		else
+@@ -175,7 +175,7 @@ static void br_flood(struct net_bridge *
+ 		     struct sk_buff *skb0,
+ 		     void (*__packet_hook)(const struct net_bridge_port *p,
+ 					   struct sk_buff *skb),
+-		     bool unicast)
++		     				bool unicast, bool forward)
+ {
+ 	struct net_bridge_port *p;
+ 	struct net_bridge_port *prev;
+@@ -183,6 +183,8 @@ static void br_flood(struct net_bridge *
+ 	prev = NULL;
+ 
+ 	list_for_each_entry_rcu(p, &br->port_list, list) {
++		if (forward && (p->flags & BR_ISOLATE_MODE))
++			continue;
+ 		/* Do not flood unicast traffic to ports that turn it off */
+ 		if (unicast && !(p->flags & BR_FLOOD))
+ 			continue;
+@@ -217,14 +219,14 @@ out:
+ /* called with rcu_read_lock */
+ void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast)
+ {
+-	br_flood(br, skb, NULL, __br_deliver, unicast);
++	br_flood(br, skb, NULL, __br_deliver, unicast, false);
+ }
+ 
+ /* called under bridge lock */
+ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
+ 		      struct sk_buff *skb2, bool unicast)
+ {
+-	br_flood(br, skb, skb2, __br_forward, unicast);
++	br_flood(br, skb, skb2, __br_forward, unicast, true);
+ }
+ 
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
diff --git a/target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch
new file mode 100644
index 0000000000..1361b92183
--- /dev/null
+++ b/target/linux/generic/patches-4.1/645-bridge_multicast_to_unicast.patch
@@ -0,0 +1,397 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: multicast to unicast
+
+Implement optinal multicast->unicast conversion for igmp snooping
+---
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -46,6 +46,7 @@ struct br_ip_list {
+ #define BR_LEARNING_SYNC	BIT(9)
+ #define BR_PROXYARP_WIFI	BIT(10)
+ #define BR_ISOLATE_MODE	BIT(11)
++#define BR_MULTICAST_TO_UCAST	BIT(12)
+ 
+ extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
+ 
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -635,7 +635,8 @@ struct net_bridge_port_group *br_multica
+ 			struct net_bridge_port *port,
+ 			struct br_ip *group,
+ 			struct net_bridge_port_group __rcu *next,
+-			unsigned char state)
++			unsigned char state,
++			const unsigned char *src)
+ {
+ 	struct net_bridge_port_group *p;
+ 
+@@ -650,12 +651,33 @@ struct net_bridge_port_group *br_multica
+ 	hlist_add_head(&p->mglist, &port->mglist);
+ 	setup_timer(&p->timer, br_multicast_port_group_expired,
+ 		    (unsigned long)p);
++	if ((port->flags & BR_MULTICAST_TO_UCAST) && src) {
++		memcpy(p->eth_addr, src, ETH_ALEN);
++		p->unicast = true;
++	}
+ 	return p;
+ }
+ 
++static bool br_port_group_equal(struct net_bridge_port_group *p,
++				struct net_bridge_port *port,
++				const unsigned char *src)
++{
++	if (p->port != port)
++		return false;
++
++	if (!p->unicast)
++		return true;
++
++	if (!src)
++		return false;
++
++	return ether_addr_equal(src, p->eth_addr);
++}
++
+ static int br_multicast_add_group(struct net_bridge *br,
+ 				  struct net_bridge_port *port,
+-				  struct br_ip *group)
++				  struct br_ip *group,
++				  const unsigned char *src)
+ {
+ 	struct net_bridge_mdb_entry *mp;
+ 	struct net_bridge_port_group *p;
+@@ -682,13 +704,13 @@ static int br_multicast_add_group(struct
+ 	for (pp = &mp->ports;
+ 	     (p = mlock_dereference(*pp, br)) != NULL;
+ 	     pp = &p->next) {
+-		if (p->port == port)
++		if (br_port_group_equal(p, port, src))
+ 			goto found;
+ 		if ((unsigned long)p->port < (unsigned long)port)
+ 			break;
+ 	}
+ 
+-	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
++	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src);
+ 	if (unlikely(!p))
+ 		goto err;
+ 	rcu_assign_pointer(*pp, p);
+@@ -707,7 +729,7 @@ err:
+ static int br_ip4_multicast_add_group(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      __be32 group,
+-				      __u16 vid)
++				      __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 
+@@ -718,14 +740,14 @@ static int br_ip4_multicast_add_group(st
+ 	br_group.proto = htons(ETH_P_IP);
+ 	br_group.vid = vid;
+ 
+-	return br_multicast_add_group(br, port, &br_group);
++	return br_multicast_add_group(br, port, &br_group, src);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static int br_ip6_multicast_add_group(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      const struct in6_addr *group,
+-				      __u16 vid)
++				      __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 
+@@ -736,7 +758,7 @@ static int br_ip6_multicast_add_group(st
+ 	br_group.proto = htons(ETH_P_IPV6);
+ 	br_group.vid = vid;
+ 
+-	return br_multicast_add_group(br, port, &br_group);
++	return br_multicast_add_group(br, port, &br_group, src);
+ }
+ #endif
+ 
+@@ -966,6 +988,7 @@ static int br_ip4_multicast_igmp3_report
+ 					 struct sk_buff *skb,
+ 					 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct igmpv3_report *ih;
+ 	struct igmpv3_grec *grec;
+ 	int i;
+@@ -1009,7 +1032,8 @@ static int br_ip4_multicast_igmp3_report
+ 			continue;
+ 		}
+ 
+-		err = br_ip4_multicast_add_group(br, port, group, vid);
++		src = eth_hdr(skb)->h_source;
++		err = br_ip4_multicast_add_group(br, port, group, vid, src);
+ 		if (err)
+ 			break;
+ 	}
+@@ -1023,6 +1047,7 @@ static int br_ip6_multicast_mld2_report(
+ 					struct sk_buff *skb,
+ 					u16 vid)
+ {
++	const unsigned char *src = eth_hdr(skb)->h_source;
+ 	struct icmp6hdr *icmp6h;
+ 	struct mld2_grec *grec;
+ 	int i;
+@@ -1071,7 +1096,7 @@ static int br_ip6_multicast_mld2_report(
+ 		}
+ 
+ 		err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
+-						 vid);
++						 vid, src);
+ 		if (err)
+ 			break;
+ 	}
+@@ -1407,7 +1432,8 @@ br_multicast_leave_group(struct net_brid
+ 			 struct net_bridge_port *port,
+ 			 struct br_ip *group,
+ 			 struct bridge_mcast_other_query *other_query,
+-			 struct bridge_mcast_own_query *own_query)
++			 struct bridge_mcast_own_query *own_query,
++			 const unsigned char *src)
+ {
+ 	struct net_bridge_mdb_htable *mdb;
+ 	struct net_bridge_mdb_entry *mp;
+@@ -1457,7 +1483,7 @@ br_multicast_leave_group(struct net_brid
+ 		for (pp = &mp->ports;
+ 		     (p = mlock_dereference(*pp, br)) != NULL;
+ 		     pp = &p->next) {
+-			if (p->port != port)
++			if (!br_port_group_equal(p, port, src))
+ 				continue;
+ 
+ 			rcu_assign_pointer(*pp, p->next);
+@@ -1491,7 +1517,7 @@ br_multicast_leave_group(struct net_brid
+ 	for (p = mlock_dereference(mp->ports, br);
+ 	     p != NULL;
+ 	     p = mlock_dereference(p->next, br)) {
+-		if (p->port != port)
++		if (!br_port_group_equal(p, port, src))
+ 			continue;
+ 
+ 		if (!hlist_unhashed(&p->mglist) &&
+@@ -1509,8 +1535,8 @@ out:
+ 
+ static void br_ip4_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+-					 __be32 group,
+-					 __u16 vid)
++					 __be32 group, __u16 vid,
++					 const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 	struct bridge_mcast_own_query *own_query;
+@@ -1525,14 +1551,14 @@ static void br_ip4_multicast_leave_group
+ 	br_group.vid = vid;
+ 
+ 	br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
+-				 own_query);
++				 own_query, src);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static void br_ip6_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+ 					 const struct in6_addr *group,
+-					 __u16 vid)
++					 __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 	struct bridge_mcast_own_query *own_query;
+@@ -1547,7 +1573,7 @@ static void br_ip6_multicast_leave_group
+ 	br_group.vid = vid;
+ 
+ 	br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
+-				 own_query);
++				 own_query, src);
+ }
+ #endif
+ 
+@@ -1556,6 +1582,7 @@ static int br_multicast_ipv4_rcv(struct
+ 				 struct sk_buff *skb,
+ 				 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct sk_buff *skb2 = skb;
+ 	const struct iphdr *iph;
+ 	struct igmphdr *ih;
+@@ -1624,12 +1651,13 @@ static int br_multicast_ipv4_rcv(struct
+ 
+ 	BR_INPUT_SKB_CB(skb)->igmp = 1;
+ 	ih = igmp_hdr(skb2);
++	src = eth_hdr(skb)->h_source;
+ 
+ 	switch (ih->type) {
+ 	case IGMP_HOST_MEMBERSHIP_REPORT:
+ 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
+ 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
+-		err = br_ip4_multicast_add_group(br, port, ih->group, vid);
++		err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
+ 		break;
+ 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
+ 		err = br_ip4_multicast_igmp3_report(br, port, skb2, vid);
+@@ -1638,7 +1666,7 @@ static int br_multicast_ipv4_rcv(struct
+ 		err = br_ip4_multicast_query(br, port, skb2, vid);
+ 		break;
+ 	case IGMP_HOST_LEAVE_MESSAGE:
+-		br_ip4_multicast_leave_group(br, port, ih->group, vid);
++		br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
+ 		break;
+ 	}
+ 
+@@ -1656,6 +1684,7 @@ static int br_multicast_ipv6_rcv(struct
+ 				 struct sk_buff *skb,
+ 				 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct sk_buff *skb2;
+ 	const struct ipv6hdr *ip6h;
+ 	u8 icmp6_type;
+@@ -1763,9 +1792,11 @@ static int br_multicast_ipv6_rcv(struct
+ 			err = -EINVAL;
+ 			goto out;
+ 		}
++		src = eth_hdr(skb)->h_source;
+ 		mld = (struct mld_msg *)skb_transport_header(skb2);
+ 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
+-		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
++		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid,
++						 src);
+ 		break;
+ 	    }
+ 	case ICMPV6_MLD2_REPORT:
+@@ -1781,8 +1812,9 @@ static int br_multicast_ipv6_rcv(struct
+ 			err = -EINVAL;
+ 			goto out;
+ 		}
++		src = eth_hdr(skb)->h_source;
+ 		mld = (struct mld_msg *)skb_transport_header(skb2);
+-		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
++		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
+ 	    }
+ 	}
+ 
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -113,6 +113,9 @@ struct net_bridge_port_group {
+ 	struct timer_list		timer;
+ 	struct br_ip			addr;
+ 	unsigned char			state;
++
++	unsigned char			eth_addr[ETH_ALEN];
++	bool				unicast;
+ };
+ 
+ struct net_bridge_mdb_entry
+@@ -481,7 +484,8 @@ void br_multicast_free_pg(struct rcu_hea
+ struct net_bridge_port_group *
+ br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
+ 			    struct net_bridge_port_group __rcu *next,
+-			    unsigned char state);
++			    unsigned char state,
++		       const unsigned char *src);
+ void br_mdb_init(void);
+ void br_mdb_uninit(void);
+ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+--- a/net/bridge/br_mdb.c
++++ b/net/bridge/br_mdb.c
+@@ -343,7 +343,7 @@ static int br_mdb_add_group(struct net_b
+ 			break;
+ 	}
+ 
+-	p = br_multicast_new_port_group(port, group, *pp, state);
++	p = br_multicast_new_port_group(port, group, *pp, state, NULL);
+ 	if (unlikely(!p))
+ 		return -ENOMEM;
+ 	rcu_assign_pointer(*pp, p);
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -170,6 +170,34 @@ out:
+ 	return p;
+ }
+ 
++static struct net_bridge_port *maybe_deliver_addr(
++	struct net_bridge_port *prev, struct net_bridge_port *p,
++	struct sk_buff *skb, const unsigned char *addr,
++	void (*__packet_hook)(const struct net_bridge_port *p,
++			      struct sk_buff *skb))
++{
++	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
++	const unsigned char *src = eth_hdr(skb)->h_source;
++
++	if (!should_deliver(p, skb))
++		return prev;
++
++	/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
++	if (skb->dev == p->dev && ether_addr_equal(src, addr))
++		return prev;
++
++	skb = skb_copy(skb, GFP_ATOMIC);
++	if (!skb) {
++		dev->stats.tx_dropped++;
++		return prev;
++	}
++
++	memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
++	__packet_hook(p, skb);
++
++	return prev;
++}
++
+ /* called under bridge lock */
+ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
+ 		     struct sk_buff *skb0,
+@@ -242,6 +270,7 @@ static void br_multicast_flood(struct ne
+ 	struct net_bridge_port *prev = NULL;
+ 	struct net_bridge_port_group *p;
+ 	struct hlist_node *rp;
++	const unsigned char *addr;
+ 
+ 	rp = rcu_dereference(hlist_first_rcu(&br->router_list));
+ 	p = mdst ? rcu_dereference(mdst->ports) : NULL;
+@@ -252,10 +281,19 @@ static void br_multicast_flood(struct ne
+ 		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
+ 			     NULL;
+ 
+-		port = (unsigned long)lport > (unsigned long)rport ?
+-		       lport : rport;
+-
+-		prev = maybe_deliver(prev, port, skb, __packet_hook);
++		if ((unsigned long)lport > (unsigned long)rport) {
++			port = lport;
++			addr = p->unicast ? p->eth_addr : NULL;
++		} else {
++			port = rport;
++			addr = NULL;
++		}
++
++		if (addr)
++			prev = maybe_deliver_addr(prev, port, skb, addr,
++						  __packet_hook);
++		else
++			prev = maybe_deliver(prev, port, skb, __packet_hook);
+ 		if (IS_ERR(prev))
+ 			goto out;
+ 
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -204,6 +204,7 @@ static BRPORT_ATTR(multicast_router, S_I
+ 		   store_multicast_router);
+ 
+ BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
++BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST);
+ #endif
+ 
+ static const struct brport_attribute *brport_attrs[] = {
+@@ -230,6 +231,7 @@ static const struct brport_attribute *br
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ 	&brport_attr_multicast_router,
+ 	&brport_attr_multicast_fast_leave,
++	&brport_attr_multicast_to_unicast,
+ #endif
+ 	&brport_attr_proxyarp,
+ 	&brport_attr_proxyarp_wifi,
diff --git a/target/linux/generic/patches-4.1/650-pppoe_header_pad.patch b/target/linux/generic/patches-4.1/650-pppoe_header_pad.patch
new file mode 100644
index 0000000000..409de58c28
--- /dev/null
+++ b/target/linux/generic/patches-4.1/650-pppoe_header_pad.patch
@@ -0,0 +1,20 @@
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -879,7 +879,7 @@ static int pppoe_sendmsg(struct socket *
+ 		goto end;
+ 
+ 
+-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
++	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD,
+ 			   0, GFP_KERNEL);
+ 	if (!skb) {
+ 		error = -ENOMEM;
+@@ -887,7 +887,7 @@ static int pppoe_sendmsg(struct socket *
+ 	}
+ 
+ 	/* Reserve space for headers. */
+-	skb_reserve(skb, dev->hard_header_len);
++	skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD);
+ 	skb_reset_network_header(skb);
+ 
+ 	skb->dev = dev;
diff --git a/target/linux/generic/patches-4.1/651-wireless_mesh_header.patch b/target/linux/generic/patches-4.1/651-wireless_mesh_header.patch
new file mode 100644
index 0000000000..17bcb6d24d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/651-wireless_mesh_header.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -133,7 +133,7 @@ static inline bool dev_xmit_complete(int
+  */
+ 
+ #if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
+-# if defined(CONFIG_MAC80211_MESH)
++# if 1 || defined(CONFIG_MAC80211_MESH)
+ #  define LL_MAX_HEADER 128
+ # else
+ #  define LL_MAX_HEADER 96
diff --git a/target/linux/generic/patches-4.1/653-disable_netlink_trim.patch b/target/linux/generic/patches-4.1/653-disable_netlink_trim.patch
new file mode 100644
index 0000000000..be8bf7eede
--- /dev/null
+++ b/target/linux/generic/patches-4.1/653-disable_netlink_trim.patch
@@ -0,0 +1,30 @@
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1776,27 +1776,7 @@ void netlink_detachskb(struct sock *sk,
+ 
+ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
+ {
+-	int delta;
+-
+ 	WARN_ON(skb->sk != NULL);
+-	if (netlink_skb_is_mmaped(skb))
+-		return skb;
+-
+-	delta = skb->end - skb->tail;
+-	if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize)
+-		return skb;
+-
+-	if (skb_shared(skb)) {
+-		struct sk_buff *nskb = skb_clone(skb, allocation);
+-		if (!nskb)
+-			return skb;
+-		consume_skb(skb);
+-		skb = nskb;
+-	}
+-
+-	if (!pskb_expand_head(skb, 0, -delta, allocation))
+-		skb->truesize -= delta;
+-
+ 	return skb;
+ }
+ 
diff --git a/target/linux/generic/patches-4.1/655-increase_skb_pad.patch b/target/linux/generic/patches-4.1/655-increase_skb_pad.patch
new file mode 100644
index 0000000000..dfc93efad3
--- /dev/null
+++ b/target/linux/generic/patches-4.1/655-increase_skb_pad.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2052,7 +2052,7 @@ static inline int pskb_network_may_pull(
+  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
+  */
+ #ifndef NET_SKB_PAD
+-#define NET_SKB_PAD	max(32, L1_CACHE_BYTES)
++#define NET_SKB_PAD	max(64, L1_CACHE_BYTES)
+ #endif
+ 
+ int ___pskb_trim(struct sk_buff *skb, unsigned int len);
diff --git a/target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch b/target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch
new file mode 100644
index 0000000000..6baee5220b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/656-skb_reduce_truesize-helper.patch
@@ -0,0 +1,41 @@
+From 4593a806e31119c5bd3faa00c7210ad862d515af Mon Sep 17 00:00:00 2001
+From: Dave Taht <dave.taht@bufferbloat.net>
+Date: Mon, 31 Dec 2012 10:02:21 -0800
+Subject: [PATCH 3/7] skb_reduce_truesize: helper function for shrinking skbs
+ whenever needed
+
+On embedded devices in particular, large queues of small packets from the rx
+path with a large truesize can exist. Reducing their size can reduce
+memory pressure. skb_reduce_truesize is a helper function for doing this,
+when needed.
+---
+ include/linux/skbuff.h |   18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2097,6 +2097,24 @@ static inline void pskb_trim_unique(stru
+ 	BUG_ON(err);
+ }
+ 
++/*
++ * Caller wants to reduce memory needs before queueing skb
++ * The (expensive) copy should not be be done in fast path.
++ */
++static inline struct sk_buff *skb_reduce_truesize(struct sk_buff *skb)
++{
++	if (skb->truesize > 2 * SKB_TRUESIZE(skb->len)) {
++		struct sk_buff *nskb;
++		nskb = skb_copy_expand(skb, skb_headroom(skb), 0,
++			GFP_ATOMIC | __GFP_NOWARN);
++		if (nskb) {
++			__kfree_skb(skb);
++			skb = nskb;
++		}
++	}
++	return skb;
++}
++
+ /**
+  *	skb_orphan - orphan a buffer
+  *	@skb: buffer to orphan
diff --git a/target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch b/target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch
new file mode 100644
index 0000000000..410e0b763d
--- /dev/null
+++ b/target/linux/generic/patches-4.1/657-qdisc_reduce_truesize.patch
@@ -0,0 +1,63 @@
+From bc9fec2f87d57bdbff30d296605e24504513f65c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Dave=20T=C3=A4ht?= <dave.taht@bufferbloat.net>
+Date: Mon, 17 Sep 2012 19:20:22 -0700
+Subject: [PATCH 4/7] net: add skb_reduce_truesize support to common qdiscs
+
+Reduce skb size under load when queues begin to fill on the
+commont qdiscs.
+---
+ net/sched/sch_codel.c    |    2 ++
+ net/sched/sch_fifo.c     |   12 ++++++++----
+ net/sched/sch_fq_codel.c |    2 ++
+ 3 files changed, 12 insertions(+), 4 deletions(-)
+
+--- a/net/sched/sch_codel.c
++++ b/net/sched/sch_codel.c
+@@ -97,6 +97,8 @@ static int codel_qdisc_enqueue(struct sk
+ 	struct codel_sched_data *q;
+ 
+ 	if (likely(qdisc_qlen(sch) < sch->limit)) {
++		if(qdisc_qlen(sch) > 128)
++			skb = skb_reduce_truesize(skb);
+ 		codel_set_enqueue_time(skb);
+ 		return qdisc_enqueue_tail(skb, sch);
+ 	}
+--- a/net/sched/sch_fifo.c
++++ b/net/sched/sch_fifo.c
+@@ -29,17 +29,21 @@ static int bfifo_enqueue(struct sk_buff
+ 
+ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+-	if (likely(skb_queue_len(&sch->q) < sch->limit))
++	if (likely(skb_queue_len(&sch->q) < sch->limit)) {
++		if (skb_queue_len(&sch->q) > 128)
++			skb = skb_reduce_truesize(skb);
+ 		return qdisc_enqueue_tail(skb, sch);
+-
++	}
+ 	return qdisc_reshape_fail(skb, sch);
+ }
+ 
+ static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+-	if (likely(skb_queue_len(&sch->q) < sch->limit))
++	if (likely(skb_queue_len(&sch->q) < sch->limit)) {
++		if (skb_queue_len(&sch->q) > 128)
++			skb = skb_reduce_truesize(skb);
+ 		return qdisc_enqueue_tail(skb, sch);
+-
++	}
+ 	/* queue full, remove one skb to fulfill the limit */
+ 	__qdisc_queue_drop_head(sch, &sch->q);
+ 	qdisc_qstats_drop(sch);
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -185,6 +185,8 @@ static int fq_codel_enqueue(struct sk_bu
+ 		return ret;
+ 	}
+ 	idx--;
++	if (sch->q.qlen > 128)
++		skb = skb_reduce_truesize(skb);
+ 
+ 	codel_set_enqueue_time(skb);
+ 	flow = &q->flows[idx];
diff --git a/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch
new file mode 100644
index 0000000000..8a870cccc1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/660-fq_codel_defaults.patch
@@ -0,0 +1,13 @@
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -394,8 +394,8 @@ static int fq_codel_init(struct Qdisc *s
+ 	struct fq_codel_sched_data *q = qdisc_priv(sch);
+ 	int i;
+ 
+-	sch->limit = 10*1024;
+-	q->flows_cnt = 1024;
++	sch->limit = 1024;
++	q->flows_cnt = 128;
+ 	q->quantum = psched_mtu(qdisc_dev(sch));
+ 	q->perturbation = prandom_u32();
+ 	INIT_LIST_HEAD(&q->new_flows);
diff --git a/target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch
new file mode 100644
index 0000000000..45a8d68367
--- /dev/null
+++ b/target/linux/generic/patches-4.1/661-fq_codel_keep_dropped_stats.patch
@@ -0,0 +1,10 @@
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -198,7 +198,6 @@ static int fq_codel_enqueue(struct sk_bu
+ 		list_add_tail(&flow->flowchain, &q->new_flows);
+ 		q->new_flow_count++;
+ 		flow->deficit = q->quantum;
+-		flow->dropped = 0;
+ 	}
+ 	if (++sch->q.qlen <= sch->limit)
+ 		return NET_XMIT_SUCCESS;
diff --git a/target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch
new file mode 100644
index 0000000000..cb80c3f54c
--- /dev/null
+++ b/target/linux/generic/patches-4.1/662-use_fq_codel_by_default.patch
@@ -0,0 +1,75 @@
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -3,8 +3,9 @@
+ # 
+ 
+ menuconfig NET_SCHED
+-	bool "QoS and/or fair queueing"
++	def_bool y
+ 	select NET_SCH_FIFO
++	select NET_SCH_FQ_CODEL
+ 	---help---
+ 	  When the kernel has several packets to send out over a network
+ 	  device, it has to decide which ones to send first, which ones to
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -599,7 +599,7 @@ static const struct Qdisc_class_ops fq_c
+ 	.walk		=	fq_codel_walk,
+ };
+ 
+-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
+ 	.cl_ops		=	&fq_codel_class_ops,
+ 	.id		=	"fq_codel",
+ 	.priv_size	=	sizeof(struct fq_codel_sched_data),
+@@ -615,6 +615,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
+ 	.dump_stats =	fq_codel_dump_stats,
+ 	.owner		=	THIS_MODULE,
+ };
++EXPORT_SYMBOL(fq_codel_qdisc_ops);
+ 
+ static int __init fq_codel_module_init(void)
+ {
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -343,6 +343,7 @@ extern struct Qdisc noop_qdisc;
+ extern struct Qdisc_ops noop_qdisc_ops;
+ extern struct Qdisc_ops pfifo_fast_ops;
+ extern struct Qdisc_ops mq_qdisc_ops;
++extern struct Qdisc_ops fq_codel_qdisc_ops;
+ extern const struct Qdisc_ops *default_qdisc_ops;
+ 
+ struct Qdisc_class_common {
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -742,7 +742,7 @@ static void attach_one_default_qdisc(str
+ 
+ 	if (dev->tx_queue_len) {
+ 		qdisc = qdisc_create_dflt(dev_queue,
+-					  default_qdisc_ops, TC_H_ROOT);
++					  &fq_codel_qdisc_ops, TC_H_ROOT);
+ 		if (!qdisc) {
+ 			netdev_info(dev, "activation failed\n");
+ 			return;
+--- a/net/sched/sch_mq.c
++++ b/net/sched/sch_mq.c
+@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, st
+ 
+ 	for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+ 		dev_queue = netdev_get_tx_queue(dev, ntx);
+-		qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
++		qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops,
+ 					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+ 						    TC_H_MIN(ntx + 1)));
+ 		if (qdisc == NULL)
+--- a/net/sched/sch_mqprio.c
++++ b/net/sched/sch_mqprio.c
+@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch
+ 
+ 	for (i = 0; i < dev->num_tx_queues; i++) {
+ 		dev_queue = netdev_get_tx_queue(dev, i);
+-		qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
++		qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops,
+ 					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+ 						    TC_H_MIN(i + 1)));
+ 		if (qdisc == NULL) {
diff --git a/target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch b/target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch
new file mode 100644
index 0000000000..50b90b375f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/663-remove_pfifo_fast.patch
@@ -0,0 +1,143 @@
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -445,140 +445,6 @@ static struct Qdisc noqueue_qdisc = {
+ 	.busylock	=	__SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock),
+ };
+ 
+-
+-static const u8 prio2band[TC_PRIO_MAX + 1] = {
+-	1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
+-};
+-
+-/* 3-band FIFO queue: old style, but should be a bit faster than
+-   generic prio+fifo combination.
+- */
+-
+-#define PFIFO_FAST_BANDS 3
+-
+-/*
+- * Private data for a pfifo_fast scheduler containing:
+- * 	- queues for the three band
+- * 	- bitmap indicating which of the bands contain skbs
+- */
+-struct pfifo_fast_priv {
+-	u32 bitmap;
+-	struct sk_buff_head q[PFIFO_FAST_BANDS];
+-};
+-
+-/*
+- * Convert a bitmap to the first band number where an skb is queued, where:
+- * 	bitmap=0 means there are no skbs on any band.
+- * 	bitmap=1 means there is an skb on band 0.
+- *	bitmap=7 means there are skbs on all 3 bands, etc.
+- */
+-static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0};
+-
+-static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv,
+-					     int band)
+-{
+-	return priv->q + band;
+-}
+-
+-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc)
+-{
+-	if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) {
+-		int band = prio2band[skb->priority & TC_PRIO_MAX];
+-		struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-		struct sk_buff_head *list = band2list(priv, band);
+-
+-		priv->bitmap |= (1 << band);
+-		qdisc->q.qlen++;
+-		return __qdisc_enqueue_tail(skb, qdisc, list);
+-	}
+-
+-	return qdisc_drop(skb, qdisc);
+-}
+-
+-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int band = bitmap2band[priv->bitmap];
+-
+-	if (likely(band >= 0)) {
+-		struct sk_buff_head *list = band2list(priv, band);
+-		struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list);
+-
+-		qdisc->q.qlen--;
+-		if (skb_queue_empty(list))
+-			priv->bitmap &= ~(1 << band);
+-
+-		return skb;
+-	}
+-
+-	return NULL;
+-}
+-
+-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int band = bitmap2band[priv->bitmap];
+-
+-	if (band >= 0) {
+-		struct sk_buff_head *list = band2list(priv, band);
+-
+-		return skb_peek(list);
+-	}
+-
+-	return NULL;
+-}
+-
+-static void pfifo_fast_reset(struct Qdisc *qdisc)
+-{
+-	int prio;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+-		__qdisc_reset_queue(qdisc, band2list(priv, prio));
+-
+-	priv->bitmap = 0;
+-	qdisc->qstats.backlog = 0;
+-	qdisc->q.qlen = 0;
+-}
+-
+-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
+-{
+-	struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
+-
+-	memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1);
+-	if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+-		goto nla_put_failure;
+-	return skb->len;
+-
+-nla_put_failure:
+-	return -1;
+-}
+-
+-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
+-{
+-	int prio;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+-		__skb_queue_head_init(band2list(priv, prio));
+-
+-	/* Can by-pass the queue discipline */
+-	qdisc->flags |= TCQ_F_CAN_BYPASS;
+-	return 0;
+-}
+-
+-struct Qdisc_ops pfifo_fast_ops __read_mostly = {
+-	.id		=	"pfifo_fast",
+-	.priv_size	=	sizeof(struct pfifo_fast_priv),
+-	.enqueue	=	pfifo_fast_enqueue,
+-	.dequeue	=	pfifo_fast_dequeue,
+-	.peek		=	pfifo_fast_peek,
+-	.init		=	pfifo_fast_init,
+-	.reset		=	pfifo_fast_reset,
+-	.dump		=	pfifo_fast_dump,
+-	.owner		=	THIS_MODULE,
+-};
+-
+ static struct lock_class_key qdisc_tx_busylock;
+ 
+ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
diff --git a/target/linux/generic/patches-4.1/664-codel_fix_3_12.patch b/target/linux/generic/patches-4.1/664-codel_fix_3_12.patch
new file mode 100644
index 0000000000..d17acd02ed
--- /dev/null
+++ b/target/linux/generic/patches-4.1/664-codel_fix_3_12.patch
@@ -0,0 +1,22 @@
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -1962,7 +1962,7 @@ static int __init pktsched_init(void)
+ 		return err;
+ 	}
+ 
+-	register_qdisc(&pfifo_fast_ops);
++	register_qdisc(&fq_codel_qdisc_ops);
+ 	register_qdisc(&pfifo_qdisc_ops);
+ 	register_qdisc(&bfifo_qdisc_ops);
+ 	register_qdisc(&pfifo_head_drop_qdisc_ops);
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -31,7 +31,7 @@
+ #include <net/dst.h>
+ 
+ /* Qdisc to use by default */
+-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
+ EXPORT_SYMBOL(default_qdisc_ops);
+ 
+ /* Main transmission queue. */
diff --git a/target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
new file mode 100644
index 0000000000..b990f50608
--- /dev/null
+++ b/target/linux/generic/patches-4.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
@@ -0,0 +1,495 @@
+From 775d6fe74d1eaec2ba387535b068dde2dc89de9e Mon Sep 17 00:00:00 2001
+From: Steven Barth <steven@midlink.org>
+Date: Thu, 22 May 2014 09:49:05 +0200
+Subject: [PATCH] Add support for MAP-E FMRs (mesh mode)
+
+MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
+between MAP CEs (mesh mode) without the need to forward such data to a
+border relay. This is similar to how 6rd works but for IPv4 over IPv6.
+
+Signed-off-by: Steven Barth <cyrus@openwrt.org>
+---
+ include/net/ip6_tunnel.h       |  13 ++
+ include/uapi/linux/if_tunnel.h |  13 ++
+ net/ipv6/ip6_tunnel.c          | 276 +++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 291 insertions(+), 11 deletions(-)
+
+--- a/include/net/ip6_tunnel.h
++++ b/include/net/ip6_tunnel.h
+@@ -15,6 +15,18 @@
+ /* determine capability on a per-packet basis */
+ #define IP6_TNL_F_CAP_PER_PACKET 0x40000
+ 
++/* IPv6 tunnel FMR */
++struct __ip6_tnl_fmr {
++	struct __ip6_tnl_fmr *next; /* next fmr in list */
++	struct in6_addr ip6_prefix;
++	struct in_addr ip4_prefix;
++
++	__u8 ip6_prefix_len;
++	__u8 ip4_prefix_len;
++	__u8 ea_len;
++	__u8 offset;
++};
++
+ struct __ip6_tnl_parm {
+ 	char name[IFNAMSIZ];	/* name of tunnel device */
+ 	int link;		/* ifindex of underlying L2 interface */
+@@ -25,6 +37,7 @@ struct __ip6_tnl_parm {
+ 	__u32 flags;		/* tunnel flags */
+ 	struct in6_addr laddr;	/* local tunnel end-point address */
+ 	struct in6_addr raddr;	/* remote tunnel end-point address */
++	struct __ip6_tnl_fmr *fmrs;	/* FMRs */
+ 
+ 	__be16			i_flags;
+ 	__be16			o_flags;
+--- a/include/uapi/linux/if_tunnel.h
++++ b/include/uapi/linux/if_tunnel.h
+@@ -57,10 +57,23 @@ enum {
+ 	IFLA_IPTUN_ENCAP_FLAGS,
+ 	IFLA_IPTUN_ENCAP_SPORT,
+ 	IFLA_IPTUN_ENCAP_DPORT,
++	IFLA_IPTUN_FMRS,
+ 	__IFLA_IPTUN_MAX,
+ };
+ #define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
+ 
++enum {
++	IFLA_IPTUN_FMR_UNSPEC,
++	IFLA_IPTUN_FMR_IP6_PREFIX,
++	IFLA_IPTUN_FMR_IP4_PREFIX,
++	IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
++	IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
++	IFLA_IPTUN_FMR_EA_LEN,
++	IFLA_IPTUN_FMR_OFFSET,
++	__IFLA_IPTUN_FMR_MAX,
++};
++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
++
+ enum tunnel_encap_types {
+ 	TUNNEL_ENCAP_NONE,
+ 	TUNNEL_ENCAP_FOU,
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -16,6 +16,8 @@
+  *      as published by the Free Software Foundation; either version
+  *      2 of the License, or (at your option) any later version.
+  *
++ *	Changes:
++ * Steven Barth <cyrus@openwrt.org>:		MAP-E FMR support
+  */
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+@@ -71,11 +73,9 @@ static bool log_ecn_error = true;
+ module_param(log_ecn_error, bool, 0644);
+ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
+ 
+-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
++static u32 HASH(const struct in6_addr *addr)
+ {
+-	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
+-
+-	return hash_32(hash, HASH_SIZE_SHIFT);
++	return hash_32(ipv6_addr_hash(addr), HASH_SIZE_SHIFT);
+ }
+ 
+ static int ip6_tnl_dev_init(struct net_device *dev);
+@@ -174,27 +174,36 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
+ static struct ip6_tnl *
+ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
+ {
+-	unsigned int hash = HASH(remote, local);
++	unsigned int hash = HASH(local);
+ 	struct ip6_tnl *t;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 	struct in6_addr any;
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+-		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+-		    ipv6_addr_equal(remote, &t->parms.raddr) &&
+-		    (t->dev->flags & IFF_UP))
++		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
++				!(t->dev->flags & IFF_UP))
++			continue;
++
++		if (ipv6_addr_equal(remote, &t->parms.raddr))
+ 			return t;
++
++		for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++			if (ipv6_prefix_equal(remote, &fmr->ip6_prefix,
++					fmr->ip6_prefix_len))
++				return t;
++		}
+ 	}
+ 
+ 	memset(&any, 0, sizeof(any));
+-	hash = HASH(&any, local);
++	hash = HASH(local);
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ 		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+ 		    (t->dev->flags & IFF_UP))
+ 			return t;
+ 	}
+ 
+-	hash = HASH(remote, &any);
++	hash = HASH(&any);
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ 		if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+ 		    (t->dev->flags & IFF_UP))
+@@ -229,7 +238,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
+ 
+ 	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ 		prio = 1;
+-		h = HASH(remote, local);
++		h = HASH(local);
+ 	}
+ 	return &ip6n->tnls[prio][h];
+ }
+@@ -399,6 +408,12 @@ ip6_tnl_dev_uninit(struct net_device *de
+ 	struct net *net = t->net;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++
+ 	if (dev == ip6n->fb_tnl_dev)
+ 		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
+ 	else
+@@ -785,6 +800,108 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
+ }
+ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
+ 
++
++/**
++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
++ *   @dest: destination IPv6 address buffer
++ *   @skb: received socket buffer
++ *   @fmr: MAP FMR
++ *   @xmit: Calculate for xmit or rcv
++ **/
++static void ip4ip6_fmr_calc(struct in6_addr *dest,
++		const struct iphdr *iph, const uint8_t *end,
++		const struct __ip6_tnl_fmr *fmr, bool xmit)
++{
++	int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
++	u8 *portp = NULL;
++	bool use_dest_addr;
++	const struct iphdr *dsth = iph;
++
++	if ((u8*)dsth >= end)
++		return;
++
++	/* find significant IP header */
++	if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++		if (ih && ((u8*)&ih[1]) <= end && (
++			ih->type == ICMP_DEST_UNREACH ||
++			ih->type == ICMP_SOURCE_QUENCH ||
++			ih->type == ICMP_TIME_EXCEEDED ||
++			ih->type == ICMP_PARAMETERPROB ||
++			ih->type == ICMP_REDIRECT))
++				dsth = (const struct iphdr*)&ih[1];
++	}
++
++	/* in xmit-path use dest port by default and source port only if
++		this is an ICMP reply to something else; vice versa in rcv-path */
++	use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
++
++	/* get dst port */
++	if (((u8*)&dsth[1]) <= end && (
++		dsth->protocol == IPPROTO_UDP ||
++		dsth->protocol == IPPROTO_TCP ||
++		dsth->protocol == IPPROTO_SCTP ||
++		dsth->protocol == IPPROTO_DCCP)) {
++			/* for UDP, TCP, SCTP and DCCP source and dest port
++			follow IPv4 header directly */
++			portp = ((u8*)dsth) + dsth->ihl * 4;
++
++			if (use_dest_addr)
++				portp += sizeof(u16);
++	} else if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++
++		/* use icmp identifier as port */
++		if (((u8*)&ih) <= end && (
++		    (use_dest_addr && (
++		    ih->type == ICMP_ECHOREPLY ||
++			ih->type == ICMP_TIMESTAMPREPLY ||
++			ih->type == ICMP_INFO_REPLY ||
++			ih->type == ICMP_ADDRESSREPLY)) ||
++			(!use_dest_addr && (
++			ih->type == ICMP_ECHO ||
++			ih->type == ICMP_TIMESTAMP ||
++			ih->type == ICMP_INFO_REQUEST ||
++			ih->type == ICMP_ADDRESS)
++			)))
++				portp = (u8*)&ih->un.echo.id;
++	}
++
++	if ((portp && &portp[2] <= end) || psidlen == 0) {
++		int frombyte = fmr->ip6_prefix_len / 8;
++		int fromrem = fmr->ip6_prefix_len % 8;
++		int bytes = sizeof(struct in6_addr) - frombyte;
++		const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
++		u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
++		u64 t = 0;
++
++		/* extract PSID from port and add it to eabits */
++		u16 psidbits = 0;
++		if (psidlen > 0) {
++			psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
++			psidbits >>= 16 - psidlen - fmr->offset;
++			psidbits = (u16)(psidbits << (16 - psidlen));
++			eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
++		}
++
++		/* rewrite destination address */
++		*dest = fmr->ip6_prefix;
++		memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
++		dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
++
++		if (bytes > sizeof(u64))
++			bytes = sizeof(u64);
++
++		/* insert eabits */
++		memcpy(&t, &dest->s6_addr[frombyte], bytes);
++		t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
++			<< (64 - fmr->ea_len - fromrem));
++		t = cpu_to_be64(t | (eabits >> fromrem));
++		memcpy(&dest->s6_addr[frombyte], &t, bytes);
++	}
++}
++
++
+ /**
+  * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
+  *   @skb: received socket buffer
+@@ -830,6 +947,26 @@ static int ip6_tnl_rcv(struct sk_buff *s
+ 		skb_reset_network_header(skb);
+ 		skb->protocol = htons(protocol);
+ 		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
++		if (protocol == ETH_P_IP &&
++			!ipv6_addr_equal(&ipv6h->saddr, &t->parms.raddr)) {
++				/* Packet didn't come from BR, so lookup FMR */
++				struct __ip6_tnl_fmr *fmr;
++				struct in6_addr expected = t->parms.raddr;
++				for (fmr = t->parms.fmrs; fmr; fmr = fmr->next)
++					if (ipv6_prefix_equal(&ipv6h->saddr,
++						&fmr->ip6_prefix, fmr->ip6_prefix_len))
++							break;
++
++				/* Check that IPv6 matches IPv4 source to prevent spoofing */
++				if (fmr)
++					ip4ip6_fmr_calc(&expected, ip_hdr(skb),
++							skb_tail_pointer(skb), fmr, false);
++
++				if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
++					rcu_read_unlock();
++					goto discard;
++				}
++		}
+ 
+ 		__skb_tunnel_rx(skb, t->dev, t->net);
+ 
+@@ -1168,6 +1305,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ 	__u32 mtu;
+ 	u8 tproto;
+ 	int err;
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	tproto = ACCESS_ONCE(t->parms.proto);
+ 	if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
+@@ -1198,6 +1336,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+ 		fl6.flowi6_mark = skb->mark;
+ 
++	/* try to find matching FMR */
++	for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++		unsigned mshift = 32 - fmr->ip4_prefix_len;
++		if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
++				ntohl(ip_hdr(skb)->daddr) >> mshift)
++			break;
++	}
++
++	/* change dstaddr according to FMR */
++	if (fmr)
++		ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true);
++
+ 	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+ 	if (err != 0) {
+ 		if (err == -EMSGSIZE)
+@@ -1312,6 +1462,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
+ 	t->parms.flowinfo = p->flowinfo;
+ 	t->parms.link = p->link;
+ 	t->parms.proto = p->proto;
++
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++	t->parms.fmrs = p->fmrs;
++
+ 	ip6_tnl_dst_reset(t);
+ 	ip6_tnl_link_config(t);
+ 	return 0;
+@@ -1350,6 +1508,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
+ 	p->flowinfo = u->flowinfo;
+ 	p->link = u->link;
+ 	p->proto = u->proto;
++	p->fmrs = NULL;
+ 	memcpy(p->name, u->name, sizeof(u->name));
+ }
+ 
+@@ -1636,6 +1795,15 @@ static int ip6_tnl_validate(struct nlatt
+ 	return 0;
+ }
+ 
++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
++	[IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
++	[IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
++	[IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
++};
++
+ static void ip6_tnl_netlink_parms(struct nlattr *data[],
+ 				  struct __ip6_tnl_parm *parms)
+ {
+@@ -1667,6 +1835,46 @@ static void ip6_tnl_netlink_parms(struct
+ 
+ 	if (data[IFLA_IPTUN_PROTO])
+ 		parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
++
++	if (data[IFLA_IPTUN_FMRS]) {
++		unsigned rem;
++		struct nlattr *fmr;
++		nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
++			struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
++			struct __ip6_tnl_fmr *nfmr;
++
++			nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
++				fmr, ip6_tnl_fmr_policy);
++
++			if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
++				continue;
++
++			nfmr->offset = 6;
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
++				nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
++					sizeof(nfmr->ip6_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
++				nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
++					sizeof(nfmr->ip4_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
++				nfmr->ip6_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
++				nfmr->ip4_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
++				nfmr->ea_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
++				nfmr->offset = nla_get_u8(c);
++
++			nfmr->next = parms->fmrs;
++			parms->fmrs = nfmr;
++		}
++	}
+ }
+ 
+ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
+@@ -1719,6 +1927,12 @@ static void ip6_tnl_dellink(struct net_d
+ 
+ static size_t ip6_tnl_get_size(const struct net_device *dev)
+ {
++	const struct ip6_tnl *t = netdev_priv(dev);
++	struct __ip6_tnl_fmr *c;
++	int fmrs = 0;
++	for (c = t->parms.fmrs; c; c = c->next)
++		++fmrs;
++
+ 	return
+ 		/* IFLA_IPTUN_LINK */
+ 		nla_total_size(4) +
+@@ -1736,6 +1950,24 @@ static size_t ip6_tnl_get_size(const str
+ 		nla_total_size(4) +
+ 		/* IFLA_IPTUN_PROTO */
+ 		nla_total_size(1) +
++		/* IFLA_IPTUN_FMRS */
++		nla_total_size(0) +
++		(
++			/* nest */
++			nla_total_size(0) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX */
++			nla_total_size(sizeof(struct in6_addr)) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX */
++			nla_total_size(sizeof(struct in_addr)) +
++			/* IFLA_IPTUN_FMR_EA_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_OFFSET */
++			nla_total_size(1)
++		) * fmrs +
+ 		0;
+ }
+ 
+@@ -1743,6 +1975,9 @@ static int ip6_tnl_fill_info(struct sk_b
+ {
+ 	struct ip6_tnl *tunnel = netdev_priv(dev);
+ 	struct __ip6_tnl_parm *parm = &tunnel->parms;
++	struct __ip6_tnl_fmr *c;
++	int fmrcnt = 0;
++	struct nlattr *fmrs;
+ 
+ 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
+ 	    nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
+@@ -1751,8 +1986,27 @@ static int ip6_tnl_fill_info(struct sk_b
+ 	    nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
+ 	    nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
+ 	    nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
+-	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto))
++	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
++	    !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
+ 		goto nla_put_failure;
++
++	for (c = parm->fmrs; c; c = c->next) {
++		struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
++		if (!fmr ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
++				sizeof(c->ip6_prefix), &c->ip6_prefix) ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
++				sizeof(c->ip4_prefix), &c->ip4_prefix) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
++				goto nla_put_failure;
++
++		nla_nest_end(skb, fmr);
++	}
++	nla_nest_end(skb, fmrs);
++
+ 	return 0;
+ 
+ nla_put_failure:
+@@ -1776,6 +2030,7 @@ static const struct nla_policy ip6_tnl_p
+ 	[IFLA_IPTUN_FLOWINFO]		= { .type = NLA_U32 },
+ 	[IFLA_IPTUN_FLAGS]		= { .type = NLA_U32 },
+ 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
++	[IFLA_IPTUN_FMRS]		= { .type = NLA_NESTED },
+ };
+ 
+ static struct rtnl_link_ops ip6_link_ops __read_mostly = {
diff --git a/target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
new file mode 100644
index 0000000000..2892109837
--- /dev/null
+++ b/target/linux/generic/patches-4.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
@@ -0,0 +1,249 @@
+From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Fri, 24 May 2013 14:40:54 +0200
+Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy"
+
+RFC6204 L-14 requires rejecting traffic from invalid addresses with
+ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
+egress policy) on the LAN side, so add an appropriate rule for that.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/net/netns/ipv6.h       |  1 +
+ include/uapi/linux/fib_rules.h |  4 +++
+ include/uapi/linux/rtnetlink.h |  1 +
+ net/ipv4/fib_semantics.c       |  4 +++
+ net/ipv4/fib_trie.c            |  1 +
+ net/ipv4/ipmr.c                |  1 +
+ net/ipv6/fib6_rules.c          |  4 +++
+ net/ipv6/ip6mr.c               |  2 ++
+ net/ipv6/route.c               | 58 +++++++++++++++++++++++++++++++++++++++++-
+ 9 files changed, 75 insertions(+), 1 deletion(-)
+
+--- a/include/net/netns/ipv6.h
++++ b/include/net/netns/ipv6.h
+@@ -61,6 +61,7 @@ struct netns_ipv6 {
+ 	unsigned long		 ip6_rt_last_gc;
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	struct rt6_info         *ip6_prohibit_entry;
++	struct rt6_info		*ip6_policy_failed_entry;
+ 	struct rt6_info         *ip6_blk_hole_entry;
+ 	struct fib6_table       *fib6_local_tbl;
+ 	struct fib_rules_ops    *fib6_rules_ops;
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -64,6 +64,10 @@ enum {
+ 	FR_ACT_BLACKHOLE,	/* Drop without notification */
+ 	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
+ 	FR_ACT_PROHIBIT,	/* Drop with EACCES */
++	FR_ACT_RES9,
++	FR_ACT_RES10,
++	FR_ACT_RES11,
++	FR_ACT_POLICY_FAILED,	/* Drop with EACCES */
+ 	__FR_ACT_MAX,
+ };
+ 
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -210,6 +210,7 @@ enum {
+ 	RTN_THROW,		/* Not in this table		*/
+ 	RTN_NAT,		/* Translate this address	*/
+ 	RTN_XRESOLVE,		/* Use external resolver	*/
++	RTN_POLICY_FAILED,	/* Failed ingress/egress policy */
+ 	__RTN_MAX
+ };
+ 
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
+ 		.error	= -EINVAL,
+ 		.scope	= RT_SCOPE_NOWHERE,
+ 	},
++	[RTN_POLICY_FAILED] = {
++		.error	= -EACCES,
++		.scope	= RT_SCOPE_UNIVERSE,
++	},
+ };
+ 
+ static void rt_fibinfo_free(struct rtable __rcu **rtp)
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2348,6 +2348,7 @@ static const char *const rtn_type_names[
+ 	[RTN_THROW] = "THROW",
+ 	[RTN_NAT] = "NAT",
+ 	[RTN_XRESOLVE] = "XRESOLVE",
++	[RTN_POLICY_FAILED] = "POLICY_FAILED",
+ };
+ 
+ static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
+--- a/net/ipv4/ipmr.c
++++ b/net/ipv4/ipmr.c
+@@ -182,6 +182,7 @@ static int ipmr_rule_action(struct fib_r
+ 	case FR_ACT_UNREACHABLE:
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
++	case FR_ACT_POLICY_FAILED:
+ 		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+--- a/net/ipv6/fib6_rules.c
++++ b/net/ipv6/fib6_rules.c
+@@ -73,6 +73,10 @@ static int fib6_rule_action(struct fib_r
+ 		err = -EACCES;
+ 		rt = net->ipv6.ip6_prohibit_entry;
+ 		goto discard_pkt;
++	case FR_ACT_POLICY_FAILED:
++		err = -EACCES;
++		rt = net->ipv6.ip6_policy_failed_entry;
++		goto discard_pkt;
+ 	}
+ 
+ 	table = fib6_get_table(net, rule->table);
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -167,6 +167,8 @@ static int ip6mr_rule_action(struct fib_
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
+ 		return -EACCES;
++	case FR_ACT_POLICY_FAILED:
++		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+ 		return -EINVAL;
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -87,6 +87,8 @@ static int		ip6_pkt_discard(struct sk_bu
+ static int		ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb);
+ static int		ip6_pkt_prohibit(struct sk_buff *skb);
+ static int		ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb);
++static int		ip6_pkt_policy_failed(struct sk_buff *skb);
++static int		ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb);
+ static void		ip6_link_failure(struct sk_buff *skb);
+ static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ 					   struct sk_buff *skb, u32 mtu);
+@@ -281,6 +283,21 @@ static const struct rt6_info ip6_prohibi
+ 	.rt6i_ref	= ATOMIC_INIT(1),
+ };
+ 
++static const struct rt6_info ip6_policy_failed_entry_template = {
++	.dst = {
++		.__refcnt	= ATOMIC_INIT(1),
++		.__use		= 1,
++		.obsolete	= DST_OBSOLETE_FORCE_CHK,
++		.error		= -EACCES,
++		.input		= ip6_pkt_policy_failed,
++		.output		= ip6_pkt_policy_failed_out,
++	},
++	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
++	.rt6i_protocol	= RTPROT_KERNEL,
++	.rt6i_metric	= ~(u32) 0,
++	.rt6i_ref	= ATOMIC_INIT(1),
++};
++
+ static const struct rt6_info ip6_blk_hole_entry_template = {
+ 	.dst = {
+ 		.__refcnt	= ATOMIC_INIT(1),
+@@ -1632,6 +1649,11 @@ int ip6_route_info_create(struct fib6_co
+ 			rt->dst.output = ip6_pkt_prohibit_out;
+ 			rt->dst.input = ip6_pkt_prohibit;
+ 			break;
++		case RTN_POLICY_FAILED:
++			rt->dst.error = -EACCES;
++			rt->dst.output = ip6_pkt_policy_failed_out;
++			rt->dst.input = ip6_pkt_policy_failed;
++			break;
+ 		case RTN_THROW:
+ 		default:
+ 			rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
+@@ -2223,6 +2245,17 @@ static int ip6_pkt_prohibit_out(struct s
+ 	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
+ }
+ 
++static int ip6_pkt_policy_failed(struct sk_buff *skb)
++{
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
++}
++
++static int ip6_pkt_policy_failed_out(struct sock *sk, struct sk_buff *skb)
++{
++	skb->dev = skb_dst(skb)->dev;
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
++}
++
+ /*
+  *	Allocate a dst for local (unicast / anycast) address.
+  */
+@@ -2449,7 +2482,8 @@ static int rtm_to_fib6_config(struct sk_
+ 	if (rtm->rtm_type == RTN_UNREACHABLE ||
+ 	    rtm->rtm_type == RTN_BLACKHOLE ||
+ 	    rtm->rtm_type == RTN_PROHIBIT ||
+-	    rtm->rtm_type == RTN_THROW)
++	    rtm->rtm_type == RTN_THROW ||
++	    rtm->rtm_type == RTN_POLICY_FAILED)
+ 		cfg->fc_flags |= RTF_REJECT;
+ 
+ 	if (rtm->rtm_type == RTN_LOCAL)
+@@ -2791,6 +2825,9 @@ static int rt6_fill_node(struct net *net
+ 		case -EACCES:
+ 			rtm->rtm_type = RTN_PROHIBIT;
+ 			break;
++		case -EPERM:
++			rtm->rtm_type = RTN_POLICY_FAILED;
++			break;
+ 		case -EAGAIN:
+ 			rtm->rtm_type = RTN_THROW;
+ 			break;
+@@ -3048,6 +3085,8 @@ static int ip6_route_dev_notify(struct n
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
+ 		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
++		net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
++		net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
+ 		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
+ 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
+ #endif
+@@ -3264,6 +3303,17 @@ static int __net_init ip6_route_net_init
+ 	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+ 	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
+ 			 ip6_template_metrics, true);
++
++	net->ipv6.ip6_policy_failed_entry =
++		kmemdup(&ip6_policy_failed_entry_template,
++			sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
++	if (!net->ipv6.ip6_policy_failed_entry)
++		goto out_ip6_blk_hole_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.path =
++		(struct dst_entry *)net->ipv6.ip6_policy_failed_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
++	dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
++			 ip6_template_metrics, true);
+ #endif
+ 
+ 	net->ipv6.sysctl.flush_delay = 0;
+@@ -3282,6 +3332,8 @@ out:
+ 	return ret;
+ 
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
++out_ip6_blk_hole_entry:
++	kfree(net->ipv6.ip6_blk_hole_entry);
+ out_ip6_prohibit_entry:
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ out_ip6_null_entry:
+@@ -3299,6 +3351,7 @@ static void __net_exit ip6_route_net_exi
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ 	kfree(net->ipv6.ip6_blk_hole_entry);
++	kfree(net->ipv6.ip6_policy_failed_entry);
+ #endif
+ 	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
+ }
+@@ -3395,6 +3448,9 @@ int __init ip6_route_init(void)
+ 	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ 	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+ 	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
++	init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
++	init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
++		in6_dev_get(init_net.loopback_dev);
+   #endif
+ 	ret = fib6_init();
+ 	if (ret)
diff --git a/target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
new file mode 100644
index 0000000000..dafb56cd8b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
@@ -0,0 +1,53 @@
+From 7749b481ce5d7e232b1f7da5e6b2c44816f51681 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 19 Jan 2014 20:45:51 +0100
+Subject: [PATCH 2/2] net: provide defines for _POLICY_FAILED until all code is
+ updated
+
+Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination
+unreachable, conflicting with our name.
+
+Add appropriate defines to allow our code to build with the new
+name until we have updated our local patches for older kernels
+and userspace packages.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/fib_rules.h | 2 ++
+ include/uapi/linux/icmpv6.h    | 2 ++
+ include/uapi/linux/rtnetlink.h | 2 ++
+ 3 files changed, 6 insertions(+)
+
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -71,6 +71,8 @@ enum {
+ 	__FR_ACT_MAX,
+ };
+ 
++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED
++
+ #define FR_ACT_MAX (__FR_ACT_MAX - 1)
+ 
+ #endif
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -118,6 +118,8 @@ struct icmp6hdr {
+ #define ICMPV6_POLICY_FAIL		5
+ #define ICMPV6_REJECT_ROUTE		6
+ 
++#define ICMPV6_FAILED_POLICY		ICMPV6_POLICY_FAIL
++
+ /*
+  *	Codes for Time Exceeded
+  */
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -214,6 +214,8 @@ enum {
+ 	__RTN_MAX
+ };
+ 
++#define RTN_FAILED_POLICY RTN_POLICY_FAILED
++
+ #define RTN_MAX (__RTN_MAX - 1)
+ 
+ 
diff --git a/target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
new file mode 100644
index 0000000000..98abfacb85
--- /dev/null
+++ b/target/linux/generic/patches-4.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
@@ -0,0 +1,160 @@
+Subject: NET: skip GRO for foreign MAC addresses
+
+For network drivers using napi_gro_receive, packets are run through GRO,
+even when the destination MAC address does not match, and they're supposed
+to be delivered to another host behind a different bridge port.
+
+This can be very expensive, because for drivers without TSO or scatter-
+gather, this can only be undone by copying the skb and checksumming it
+again.
+
+To be able to track foreign MAC addresses in an inexpensive way, create
+a mask of changed bits in MAC addresses of upper devices. This allows
+handling VLANs and bridge devices with different addresses (as long as
+they are not too different).
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -4041,6 +4041,9 @@ static enum gro_result dev_gro_receive(s
+ 	enum gro_result ret;
+ 	int grow;
+ 
++	if (skb->gro_skip)
++		goto normal;
++
+ 	if (!(skb->dev->features & NETIF_F_GRO))
+ 		goto normal;
+ 
+@@ -5190,6 +5193,48 @@ static void __netdev_adjacent_dev_unlink
+ 					   &upper_dev->adj_list.lower);
+ }
+ 
++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
++			       struct net_device *dev)
++{
++	int i;
++
++	for (i = 0; i < dev->addr_len; i++)
++		mask[i] |= addr[i] ^ dev->dev_addr[i];
++}
++
++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
++				struct net_device *lower)
++{
++	struct net_device *cur;
++	struct list_head *iter;
++
++	netdev_for_each_upper_dev_rcu(dev, cur, iter) {
++		__netdev_addr_mask(mask, cur->dev_addr, lower);
++		__netdev_upper_mask(mask, cur, lower);
++	}
++}
++
++static void __netdev_update_addr_mask(struct net_device *dev)
++{
++	unsigned char mask[MAX_ADDR_LEN];
++	struct net_device *cur;
++	struct list_head *iter;
++
++	memset(mask, 0, sizeof(mask));
++	__netdev_upper_mask(mask, dev, dev);
++	memcpy(dev->local_addr_mask, mask, dev->addr_len);
++
++	netdev_for_each_lower_dev(dev, cur, iter)
++		__netdev_update_addr_mask(cur);
++}
++
++static void netdev_update_addr_mask(struct net_device *dev)
++{
++	rcu_read_lock();
++	__netdev_update_addr_mask(dev);
++	rcu_read_unlock();
++}
++
+ static int __netdev_upper_dev_link(struct net_device *dev,
+ 				   struct net_device *upper_dev, bool master,
+ 				   void *private)
+@@ -5250,6 +5295,7 @@ static int __netdev_upper_dev_link(struc
+ 			goto rollback_lower_mesh;
+ 	}
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
+ 	return 0;
+ 
+@@ -5367,6 +5413,7 @@ void netdev_upper_dev_unlink(struct net_
+ 	list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
+ 		__netdev_adjacent_dev_unlink(dev, i->dev);
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
+ }
+ EXPORT_SYMBOL(netdev_upper_dev_unlink);
+@@ -5906,6 +5953,7 @@ int dev_set_mac_address(struct net_devic
+ 	if (err)
+ 		return err;
+ 	dev->addr_assign_type = NET_ADDR_SET;
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ 	add_device_randomness(dev->dev_addr, dev->addr_len);
+ 	return 0;
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1603,6 +1603,8 @@ struct net_device {
+ 	struct netdev_hw_addr_list	mc;
+ 	struct netdev_hw_addr_list	dev_addrs;
+ 
++	unsigned char		local_addr_mask[MAX_ADDR_LEN];
++
+ #ifdef CONFIG_SYSFS
+ 	struct kset		*queues_kset;
+ #endif
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -616,7 +616,8 @@ struct sk_buff {
+ 	__u8			ipvs_property:1;
+ 	__u8			inner_protocol_type:1;
+ 	__u8			remcsum_offload:1;
+-	/* 3 or 5 bit hole */
++	__u8			gro_skip:1;
++	/* 2 or 4 bit hole */
+ 
+ #ifdef CONFIG_NET_SCHED
+ 	__u16			tc_index;	/* traffic control index */
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -139,6 +139,18 @@ u32 eth_get_headlen(void *data, unsigned
+ }
+ EXPORT_SYMBOL(eth_get_headlen);
+ 
++static inline bool
++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
++{
++	const u16 *a1 = addr1;
++	const u16 *a2 = addr2;
++	const u16 *m = mask;
++
++	return (((a1[0] ^ a2[0]) & ~m[0]) |
++		((a1[1] ^ a2[1]) & ~m[1]) |
++		((a1[2] ^ a2[2]) & ~m[2]));
++}
++
+ /**
+  * eth_type_trans - determine the packet's protocol ID.
+  * @skb: received socket data
+@@ -166,8 +178,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 			skb->pkt_type = PACKET_MULTICAST;
+ 	}
+ 	else if (unlikely(!ether_addr_equal_64bits(eth->h_dest,
+-						   dev->dev_addr)))
++						   dev->dev_addr))) {
+ 		skb->pkt_type = PACKET_OTHERHOST;
++		if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
++					 dev->local_addr_mask))
++			skb->gro_skip = 1;
++	}
+ 
+ 	/*
+ 	 * Some variants of DSA tagging don't have an ethertype field
diff --git a/target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch b/target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch
new file mode 100644
index 0000000000..688cf6e44a
--- /dev/null
+++ b/target/linux/generic/patches-4.1/681-NET-add-of_get_mac_address_mtd.patch
@@ -0,0 +1,88 @@
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:40:01 +0100
+Subject: NET: add of_get_mac_address_mtd()
+
+Many embedded devices have information such as mac addresses stored inside mtd
+devices. This patch allows us to add a property inside a node describing a
+network interface. The new property points at a mtd partition with an offset
+where the mac address can be found.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/of/of_net.c    |   37 +++++++++++++++++++++++++++++++++++++
+ include/linux/of_net.h |    1 +
+ 2 files changed, 38 insertions(+)
+
+--- a/drivers/of/of_net.c
++++ b/drivers/of/of_net.c
+@@ -10,6 +10,7 @@
+ #include <linux/of_net.h>
+ #include <linux/phy.h>
+ #include <linux/export.h>
++#include <linux/mtd/mtd.h>
+ 
+ /**
+  * of_get_phy_mode - Get phy mode for given device_node
+@@ -80,3 +81,45 @@ const void *of_get_mac_address(struct de
+ 	return of_get_mac_addr(np, "address");
+ }
+ EXPORT_SYMBOL(of_get_mac_address);
++
++#ifdef CONFIG_MTD
++int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac)
++{
++	struct device_node *mtd_np = NULL;
++	size_t retlen;
++	int size, ret;
++	struct mtd_info *mtd;
++	const char *part;
++	const __be32 *list;
++	phandle phandle;
++	u32 mac_inc = 0;
++
++	list = of_get_property(np, "mtd-mac-address", &size);
++	if (!list || (size != (2 * sizeof(*list))))
++		return -ENOENT;
++
++	phandle = be32_to_cpup(list++);
++	if (phandle)
++		mtd_np = of_find_node_by_phandle(phandle);
++
++	if (!mtd_np)
++		return -ENOENT;
++
++	part = of_get_property(mtd_np, "label", NULL);
++	if (!part)
++		part = mtd_np->name;
++
++	mtd = get_mtd_device_nm(part);
++	if (IS_ERR(mtd))
++		return PTR_ERR(mtd);
++
++	ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
++	put_mtd_device(mtd);
++
++	if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
++		mac[5] += mac_inc;
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(of_get_mac_address_mtd);
++#endif
+--- a/include/linux/of_net.h
++++ b/include/linux/of_net.h
+@@ -13,6 +13,14 @@
+ struct net_device;
+ extern int of_get_phy_mode(struct device_node *np);
+ extern const void *of_get_mac_address(struct device_node *np);
++#ifdef CONFIG_MTD
++extern int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac);
++#else
++static inline int of_get_mac_address_mtd(struct device_node *np, unsigned char *mac)
++{
++	return -ENOENT;
++}
++#endif
+ extern struct net_device *of_find_net_device_by_node(struct device_node *np);
+ #else
+ static inline int of_get_phy_mode(struct device_node *np)
diff --git a/target/linux/generic/patches-4.1/700-swconfig.patch b/target/linux/generic/patches-4.1/700-swconfig.patch
new file mode 100644
index 0000000000..cdce89e239
--- /dev/null
+++ b/target/linux/generic/patches-4.1/700-swconfig.patch
@@ -0,0 +1,39 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,16 @@ menuconfig PHYLIB
+ 
+ if PHYLIB
+ 
++config SWCONFIG
++	tristate "Switch configuration API"
++	---help---
++	  Switch configuration API using netlink. This allows
++	  you to configure the VLAN features of certain switches.
++
++config SWCONFIG_LEDS
++	bool "Switch LED trigger support"
++	depends on (SWCONFIG && LEDS_TRIGGERS)
++
+ comment "MII PHY device drivers"
+ 
+ config AT803X_PHY
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -3,6 +3,7 @@
+ libphy-objs			:= phy.o phy_device.o mdio_bus.o
+ 
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
++obj-$(CONFIG_SWCONFIG)		+= swconfig.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+ obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
+ obj-$(CONFIG_CICADA_PHY)	+= cicada.o
+--- a/include/uapi/linux/Kbuild
++++ b/include/uapi/linux/Kbuild
+@@ -380,6 +380,7 @@ header-y += stddef.h
+ header-y += string.h
+ header-y += suspend_ioctls.h
+ header-y += swab.h
++header-y += switch.h
+ header-y += synclink.h
+ header-y += sysctl.h
+ header-y += sysinfo.h
diff --git a/target/linux/generic/patches-4.1/701-phy_extension.patch b/target/linux/generic/patches-4.1/701-phy_extension.patch
new file mode 100644
index 0000000000..55b37bacb9
--- /dev/null
+++ b/target/linux/generic/patches-4.1/701-phy_extension.patch
@@ -0,0 +1,63 @@
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -357,6 +357,50 @@ int phy_ethtool_gset(struct phy_device *
+ }
+ EXPORT_SYMBOL(phy_ethtool_gset);
+ 
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
++{
++	u32 cmd;
++	int tmp;
++	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++	struct ethtool_value edata = { ETHTOOL_GLINK };
++
++	if (get_user(cmd, (u32 *) useraddr))
++		return -EFAULT;
++
++	switch (cmd) {
++	case ETHTOOL_GSET:
++		phy_ethtool_gset(phydev, &ecmd);
++		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++			return -EFAULT;
++		return 0;
++
++	case ETHTOOL_SSET:
++		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++			return -EFAULT;
++		return phy_ethtool_sset(phydev, &ecmd);
++
++	case ETHTOOL_NWAY_RST:
++		/* if autoneg is off, it's an error */
++		tmp = phy_read(phydev, MII_BMCR);
++		if (tmp & BMCR_ANENABLE) {
++			tmp |= (BMCR_ANRESTART);
++			phy_write(phydev, MII_BMCR, tmp);
++			return 0;
++		}
++		return -EINVAL;
++
++	case ETHTOOL_GLINK:
++		edata.data = (phy_read(phydev,
++				MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
++		if (copy_to_user(useraddr, &edata, sizeof(edata)))
++			return -EFAULT;
++		return 0;
++	}
++
++	return -EOPNOTSUPP;
++}
++EXPORT_SYMBOL(phy_ethtool_ioctl);
++
+ /**
+  * phy_mii_ioctl - generic PHY MII ioctl interface
+  * @phydev: the phy_device struct
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -762,6 +762,7 @@ void phy_start_machine(struct phy_device
+ void phy_stop_machine(struct phy_device *phydev);
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
+ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
+ int phy_start_interrupts(struct phy_device *phydev);
+ void phy_print_status(struct phy_device *phydev);
diff --git a/target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch b/target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch
new file mode 100644
index 0000000000..c743cefc5a
--- /dev/null
+++ b/target/linux/generic/patches-4.1/702-phy_add_aneg_done_function.patch
@@ -0,0 +1,27 @@
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -489,6 +489,12 @@ struct phy_driver {
+ 	/* Determines the negotiated speed and duplex */
+ 	int (*read_status)(struct phy_device *phydev);
+ 
++	/* 
++	 * Update the value in phydev->link to reflect the 
++	 * current link value
++	 */
++	int (*update_link)(struct phy_device *phydev);
++
+ 	/* Clears any pending interrupts */
+ 	int (*ack_interrupt)(struct phy_device *phydev);
+ 
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -929,6 +929,9 @@ int genphy_update_link(struct phy_device
+ {
+ 	int status;
+ 
++	if (phydev->drv->update_link)
++		return phydev->drv->update_link(phydev);
++
+ 	/* Do a fake read */
+ 	status = phy_read(phydev, MII_BMSR);
+ 	if (status < 0)
diff --git a/target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch
new file mode 100644
index 0000000000..85888f7c24
--- /dev/null
+++ b/target/linux/generic/patches-4.1/703-phy-add-detach-callback-to-struct-phy_driver.patch
@@ -0,0 +1,27 @@
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -674,6 +674,9 @@ void phy_detach(struct phy_device *phyde
+ {
+ 	int i;
+ 
++	if (phydev->drv && phydev->drv->detach)
++		phydev->drv->detach(phydev);
++
+ 	if (phydev->bus->dev.driver)
+ 		module_put(phydev->bus->dev.driver->owner);
+ 
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -507,6 +507,12 @@ struct phy_driver {
+ 	 */
+ 	int (*did_interrupt)(struct phy_device *phydev);
+ 
++	/*
++	 * Called before an ethernet device is detached
++	 * from the PHY.
++	 */
++	void (*detach)(struct phy_device *phydev);
++
+ 	/* Clears up any memory if needed */
+ 	void (*remove)(struct phy_device *phydev);
+ 
diff --git a/target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch b/target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch
new file mode 100644
index 0000000000..41a6d91588
--- /dev/null
+++ b/target/linux/generic/patches-4.1/704-phy-no-genphy-soft-reset.patch
@@ -0,0 +1,29 @@
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1147,7 +1147,7 @@ int genphy_config_init(struct phy_device
+ 	return 0;
+ }
+ 
+-static int gen10g_soft_reset(struct phy_device *phydev)
++static int no_soft_reset(struct phy_device *phydev)
+ {
+ 	/* Do nothing for now */
+ 	return 0;
+@@ -1361,7 +1361,7 @@ static struct phy_driver genphy_driver[]
+ 	.phy_id		= 0xffffffff,
+ 	.phy_id_mask	= 0xffffffff,
+ 	.name		= "Generic PHY",
+-	.soft_reset	= genphy_soft_reset,
++	.soft_reset	= no_soft_reset,
+ 	.config_init	= genphy_config_init,
+ 	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
+ 			  SUPPORTED_AUI | SUPPORTED_FIBRE |
+@@ -1376,7 +1376,7 @@ static struct phy_driver genphy_driver[]
+ 	.phy_id         = 0xffffffff,
+ 	.phy_id_mask    = 0xffffffff,
+ 	.name           = "Generic 10G PHY",
+-	.soft_reset	= gen10g_soft_reset,
++	.soft_reset	= no_soft_reset,
+ 	.config_init    = gen10g_config_init,
+ 	.features       = 0,
+ 	.config_aneg    = gen10g_config_aneg,
diff --git a/target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch b/target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch
new file mode 100644
index 0000000000..2bc91d5d72
--- /dev/null
+++ b/target/linux/generic/patches-4.1/710-phy-add-mdio_register_board_info.patch
@@ -0,0 +1,193 @@
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -38,6 +38,8 @@
+ 
+ #include <asm/irq.h>
+ 
++#include "mdio-boardinfo.h"
++
+ /**
+  * mdiobus_alloc_size - allocate a mii_bus structure
+  * @size: extra amount of memory to allocate for private storage.
+@@ -335,9 +337,21 @@ void mdiobus_free(struct mii_bus *bus)
+ }
+ EXPORT_SYMBOL(mdiobus_free);
+ 
++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus,
++						struct phy_device *phydev,
++						struct mdio_board_info *bi)
++{
++	if (strcmp(bus->id, bi->bus_id) ||
++	    bi->phy_addr != phydev->addr)
++	    return;
++
++	phydev->dev.platform_data = (void *) bi->platform_data;
++}
++
+ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+ {
+ 	struct phy_device *phydev;
++	struct mdio_board_entry *be;
+ 	int err;
+ 
+ 	phydev = get_phy_device(bus, addr, false);
+@@ -350,6 +364,12 @@ struct phy_device *mdiobus_scan(struct m
+ 	 */
+ 	of_mdiobus_link_phydev(bus, phydev);
+ 
++	mutex_lock(&__mdio_board_lock);
++	list_for_each_entry(be, &__mdio_board_list, list)
++		mdiobus_setup_phydev_from_boardinfo(bus, phydev,
++						    &be->board_info);
++	mutex_unlock(&__mdio_board_lock);
++
+ 	err = phy_device_register(phydev);
+ 	if (err) {
+ 		phy_device_free(phydev);
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -800,6 +800,23 @@ void mdio_bus_exit(void);
+ 
+ extern struct bus_type mdio_bus_type;
+ 
++struct mdio_board_info {
++	const char	*bus_id;
++	int		phy_addr;
++
++	const void	*platform_data;
++};
++
++#ifdef CONFIG_MDIO_BOARDINFO
++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n);
++#else
++static inline int
++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n)
++{
++	return 0;
++}
++#endif
++
+ /**
+  * module_phy_driver() - Helper macro for registering PHY drivers
+  * @__phy_drivers: array of PHY drivers to register
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,10 @@ menuconfig PHYLIB
+ 
+ if PHYLIB
+ 
++config MDIO_BOARDINFO
++	bool
++	default y
++
+ config SWCONFIG
+ 	tristate "Switch configuration API"
+ 	---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -2,6 +2,8 @@
+ 
+ libphy-objs			:= phy.o phy_device.o mdio_bus.o
+ 
++obj-$(CONFIG_MDIO_BOARDINFO)	+= mdio-boardinfo.o
++
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
+ obj-$(CONFIG_SWCONFIG)		+= swconfig.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.c
+@@ -0,0 +1,58 @@
++/*
++ * mdio-boardinfo.c - collect pre-declarations of PHY devices
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/phy.h>
++#include <linux/slab.h>
++#include <linux/export.h>
++#include <linux/mutex.h>
++#include <linux/phy.h>
++
++#include "mdio-boardinfo.h"
++
++/*
++ * These symbols are exported ONLY FOR the mdio_bus component.
++ * No other users will be supported.
++ */
++
++LIST_HEAD(__mdio_board_list);
++EXPORT_SYMBOL_GPL(__mdio_board_list);
++
++DEFINE_MUTEX(__mdio_board_lock);
++EXPORT_SYMBOL_GPL(__mdio_board_lock);
++
++/**
++ * mdio_register_board_info - register PHY devices for a given board
++ * @info: array of chip descriptors
++ * @n: how many descriptors are provided
++ * Context: can sleep
++ *
++ * The board info passed can safely be __initdata ... but be careful of
++ * any embedded pointers (platform_data, etc), they're copied as-is.
++ */
++int __init
++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n)
++{
++	struct mdio_board_entry *be;
++	int i;
++
++	be = kzalloc(n * sizeof(*be), GFP_KERNEL);
++	if (!be)
++		return -ENOMEM;
++
++	for (i = 0; i < n; i++, be++, info++) {
++		memcpy(&be->board_info, info, sizeof(*info));
++		mutex_lock(&__mdio_board_lock);
++		list_add_tail(&be->list, &__mdio_board_list);
++		mutex_unlock(&__mdio_board_lock);
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.h
+@@ -0,0 +1,22 @@
++/*
++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/mutex.h>
++
++struct mdio_board_entry {
++	struct list_head	list;
++	struct mdio_board_info	board_info;
++};
++
++/* __mdio_board_lock protects __mdio_board_list
++ * only mdio_bus components are allowed to use these symbols.
++ */
++extern struct mutex __mdio_board_lock;
++extern struct list_head __mdio_board_list;
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -16,7 +16,7 @@ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_MDIO) += mdio.o
+ obj-$(CONFIG_NET) += Space.o loopback.o
+ obj-$(CONFIG_NETCONSOLE) += netconsole.o
+-obj-$(CONFIG_PHYLIB) += phy/
++obj-y += phy/
+ obj-$(CONFIG_RIONET) += rionet.o
+ obj-$(CONFIG_NET_TEAM) += team/
+ obj-$(CONFIG_TUN) += tun.o
diff --git a/target/linux/generic/patches-4.1/720-phy_adm6996.patch b/target/linux/generic/patches-4.1/720-phy_adm6996.patch
new file mode 100644
index 0000000000..7107316dc4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/720-phy_adm6996.patch
@@ -0,0 +1,26 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -133,6 +133,13 @@ config MICREL_PHY
+ 	---help---
+ 	  Supports the KSZ9021, VSC8201, KS8001 PHYs.
+ 
++config ADM6996_PHY
++	tristate "Driver for ADM6996 switches"
++	select SWCONFIG
++	---help---
++	  Currently supports the ADM6996FC and ADM6996M switches.
++	  Support for FC is very limited.
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
+ obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
+ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
++obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
diff --git a/target/linux/generic/patches-4.1/721-phy_packets.patch b/target/linux/generic/patches-4.1/721-phy_packets.patch
new file mode 100644
index 0000000000..ecf1851dfb
--- /dev/null
+++ b/target/linux/generic/patches-4.1/721-phy_packets.patch
@@ -0,0 +1,161 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1271,6 +1271,7 @@ enum netdev_priv_flags {
+ 	IFF_XMIT_DST_RELEASE_PERM	= 1<<22,
+ 	IFF_IPVLAN_MASTER		= 1<<23,
+ 	IFF_IPVLAN_SLAVE		= 1<<24,
++	IFF_NO_IP_ALIGN			= 1<<25,
+ };
+ 
+ #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
+@@ -1298,6 +1299,7 @@ enum netdev_priv_flags {
+ #define IFF_XMIT_DST_RELEASE_PERM	IFF_XMIT_DST_RELEASE_PERM
+ #define IFF_IPVLAN_MASTER		IFF_IPVLAN_MASTER
+ #define IFF_IPVLAN_SLAVE		IFF_IPVLAN_SLAVE
++#define IFF_NO_IP_ALIGN			IFF_NO_IP_ALIGN
+ 
+ /**
+  *	struct net_device - The DEVICE structure.
+@@ -1568,6 +1570,11 @@ struct net_device {
+ 	const struct swdev_ops *swdev_ops;
+ #endif
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
++	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
++#endif
++
+ 	const struct header_ops *header_ops;
+ 
+ 	unsigned int		flags;
+@@ -1634,6 +1641,10 @@ struct net_device {
+ 	struct mpls_dev __rcu	*mpls_ptr;
+ #endif
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void			*phy_ptr; /* PHY device specific data */
++#endif
++
+ /*
+  * Cache lines mostly used on receive path (including eth_type_trans())
+  */
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2083,6 +2083,10 @@ static inline int pskb_trim(struct sk_bu
+ 	return (len < skb->len) ? __pskb_trim(skb, len) : 0;
+ }
+ 
++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp);
++
++
+ /**
+  *	pskb_trim_unique - remove end from a paged unique (not cloned) buffer
+  *	@skb: buffer to alter
+@@ -2209,16 +2213,6 @@ static inline struct sk_buff *dev_alloc_
+ }
+ 
+ 
+-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+-		unsigned int length, gfp_t gfp)
+-{
+-	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
+-
+-	if (NET_IP_ALIGN && skb)
+-		skb_reserve(skb, NET_IP_ALIGN);
+-	return skb;
+-}
+-
+ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
+ 		unsigned int length)
+ {
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -25,6 +25,12 @@ menuconfig NET
+ 
+ if NET
+ 
++config ETHERNET_PACKET_MANGLE
++	bool
++	help
++	  This option can be selected by phy drivers that need to mangle
++	  packets going in or out of an ethernet device.
++
+ config WANT_COMPAT_NETLINK_MESSAGES
+ 	bool
+ 	help
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2650,10 +2650,20 @@ static int xmit_one(struct sk_buff *skb,
+ 	if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
+ 		dev_queue_xmit_nit(skb, dev);
+ 
+-	len = skb->len;
+-	trace_net_dev_start_xmit(skb, dev);
+-	rc = netdev_start_xmit(skb, dev, txq, more);
+-	trace_net_dev_xmit(skb, rc, dev, len);
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (!dev->eth_mangle_tx ||
++	    (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
++#else
++	if (1)
++#endif
++	{
++		len = skb->len;
++		trace_net_dev_start_xmit(skb, dev);
++		rc = netdev_start_xmit(skb, dev, txq, more);
++		trace_net_dev_xmit(skb, rc, dev, len);
++	} else {
++		rc = NETDEV_TX_OK;
++	}
+ 
+ 	return rc;
+ }
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -63,6 +63,7 @@
+ #include <linux/errqueue.h>
+ #include <linux/prefetch.h>
+ #include <linux/if_vlan.h>
++#include <linux/if.h>
+ 
+ #include <net/protocol.h>
+ #include <net/dst.h>
+@@ -570,6 +571,22 @@ struct sk_buff *__napi_alloc_skb(struct
+ }
+ EXPORT_SYMBOL(__napi_alloc_skb);
+ 
++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp)
++{
++	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
++		return skb;
++#endif
++
++	if (NET_IP_ALIGN && skb)
++		skb_reserve(skb, NET_IP_ALIGN);
++	return skb;
++}
++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
++
+ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+ 		     int size, unsigned int truesize)
+ {
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -167,6 +167,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 	const struct ethhdr *eth;
+ 
+ 	skb->dev = dev;
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev->eth_mangle_rx)
++		dev->eth_mangle_rx(dev, skb);
++#endif
++
+ 	skb_reset_mac_header(skb);
+ 	skb_pull_inline(skb, ETH_HLEN);
+ 	eth = eth_hdr(skb);
diff --git a/target/linux/generic/patches-4.1/722-phy_mvswitch.patch b/target/linux/generic/patches-4.1/722-phy_mvswitch.patch
new file mode 100644
index 0000000000..209c5003ff
--- /dev/null
+++ b/target/linux/generic/patches-4.1/722-phy_mvswitch.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -140,6 +140,10 @@ config ADM6996_PHY
+ 	  Currently supports the ADM6996FC and ADM6996M switches.
+ 	  Support for FC is very limited.
+ 
++config MVSWITCH_PHY
++	tristate "Driver for Marvell 88E6060 switches"
++	select ETHERNET_PACKET_MANGLE
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
+ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
++obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
diff --git a/target/linux/generic/patches-4.1/723-phy_ip175c.patch b/target/linux/generic/patches-4.1/723-phy_ip175c.patch
new file mode 100644
index 0000000000..2293ca5ba7
--- /dev/null
+++ b/target/linux/generic/patches-4.1/723-phy_ip175c.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -144,6 +144,10 @@ config MVSWITCH_PHY
+ 	tristate "Driver for Marvell 88E6060 switches"
+ 	select ETHERNET_PACKET_MANGLE
+ 
++config IP17XX_PHY
++	tristate "Driver for IC+ IP17xx switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
diff --git a/target/linux/generic/patches-4.1/724-phy_ar8216.patch b/target/linux/generic/patches-4.1/724-phy_ar8216.patch
new file mode 100644
index 0000000000..3a669bad67
--- /dev/null
+++ b/target/linux/generic/patches-4.1/724-phy_ar8216.patch
@@ -0,0 +1,24 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -148,6 +148,11 @@ config IP17XX_PHY
+ 	tristate "Driver for IC+ IP17xx switches"
+ 	select SWCONFIG
+ 
++config AR8216_PHY
++	tristate "Driver for Atheros AR8216 switches"
++	select ETHERNET_PACKET_MANGLE
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
++obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.1/725-phy_rtl8306.patch b/target/linux/generic/patches-4.1/725-phy_rtl8306.patch
new file mode 100644
index 0000000000..5d4ce7c5be
--- /dev/null
+++ b/target/linux/generic/patches-4.1/725-phy_rtl8306.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -153,6 +153,10 @@ config AR8216_PHY
+ 	select ETHERNET_PACKET_MANGLE
+ 	select SWCONFIG
+ 
++config RTL8306_PHY
++	tristate "Driver for Realtek RTL8306S switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
++obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.1/726-phy_rtl8366.patch b/target/linux/generic/patches-4.1/726-phy_rtl8366.patch
new file mode 100644
index 0000000000..83c7c4e222
--- /dev/null
+++ b/target/linux/generic/patches-4.1/726-phy_rtl8366.patch
@@ -0,0 +1,45 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -251,6 +251,30 @@ config MDIO_BCM_UNIMAC
+ 	  controllers as well as some Broadcom Ethernet switches such as the
+ 	  Starfighter 2 switches.
+ 
++config RTL8366_SMI
++	tristate "Driver for the RTL8366 SMI interface"
++	depends on GPIOLIB
++	---help---
++	  This module implements the SMI interface protocol which is used
++	  by some RTL8366 ethernet switch devices via the generic GPIO API.
++
++if RTL8366_SMI
++
++config RTL8366_SMI_DEBUG_FS
++	bool "RTL8366 SMI interface debugfs support"
++        depends on DEBUG_FS
++        default n
++
++config RTL8366S_PHY
++	tristate "Driver for the Realtek RTL8366S switch"
++	select SWCONFIG
++
++config RTL8366RB_PHY
++	tristate "Driver for the Realtek RTL8366RB switch"
++	select SWCONFIG
++
++endif # RTL8366_SMI
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -24,6 +24,9 @@ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
+ obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
++obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
++obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
++obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.1/727-phy-rtl8367.patch b/target/linux/generic/patches-4.1/727-phy-rtl8367.patch
new file mode 100644
index 0000000000..7e6b0359aa
--- /dev/null
+++ b/target/linux/generic/patches-4.1/727-phy-rtl8367.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -273,6 +273,10 @@ config RTL8366RB_PHY
+ 	tristate "Driver for the Realtek RTL8366RB switch"
+ 	select SWCONFIG
+ 
++config RTL8367_PHY
++	tristate "Driver for the Realtek RTL8367R/M switches"
++	select SWCONFIG
++
+ endif # RTL8366_SMI
+ 
+ endif # PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
+ obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
+ obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
+ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
++obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.1/728-phy-rtl8367b.patch b/target/linux/generic/patches-4.1/728-phy-rtl8367b.patch
new file mode 100644
index 0000000000..670168ee8c
--- /dev/null
+++ b/target/linux/generic/patches-4.1/728-phy-rtl8367b.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -277,6 +277,10 @@ config RTL8367_PHY
+ 	tristate "Driver for the Realtek RTL8367R/M switches"
+ 	select SWCONFIG
+ 
++config RTL8367B_PHY
++	tristate "Driver fot the Realtek RTL8367R-VB switch"
++	select SWCONFIG
++
+ endif # RTL8366_SMI
+ 
+ endif # PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi
+ obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
+ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
+ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
++obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.1/729-phy-tantos.patch b/target/linux/generic/patches-4.1/729-phy-tantos.patch
new file mode 100644
index 0000000000..67b879f2d8
--- /dev/null
+++ b/target/linux/generic/patches-4.1/729-phy-tantos.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -288,3 +288,8 @@ endif # PHYLIB
+ config MICREL_KS8995MA
+ 	tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch"
+ 	depends on SPI
++
++config PSB6970_PHY
++	tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
++	select SWCONFIG
++	select ETHERNET_PACKET_MANGLE
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb
+ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
++obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
diff --git a/target/linux/generic/patches-4.1/730-phy_b53.patch b/target/linux/generic/patches-4.1/730-phy_b53.patch
new file mode 100644
index 0000000000..ff166890d4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/730-phy_b53.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -283,6 +283,8 @@ config RTL8367B_PHY
+ 
+ endif # RTL8366_SMI
+ 
++source "drivers/net/phy/b53/Kconfig"
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
++obj-$(CONFIG_SWCONFIG_B53)	+= b53/
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
diff --git a/target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch b/target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch
new file mode 100644
index 0000000000..e38cf7806e
--- /dev/null
+++ b/target/linux/generic/patches-4.1/732-phy-ar8216-led-support.patch
@@ -0,0 +1,13 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -153,6 +153,10 @@ config AR8216_PHY
+ 	select ETHERNET_PACKET_MANGLE
+ 	select SWCONFIG
+ 
++config AR8216_PHY_LEDS
++	bool "Atheros AR8216 switch LED support"
++	depends on (AR8216_PHY && LEDS_CLASS)
++
+ config RTL8306_PHY
+ 	tristate "Driver for Realtek RTL8306S switches"
+ 	select SWCONFIG
diff --git a/target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch b/target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch
new file mode 100644
index 0000000000..b70326b082
--- /dev/null
+++ b/target/linux/generic/patches-4.1/733-phy_mvsw61xx.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -144,6 +144,10 @@ config MVSWITCH_PHY
+ 	tristate "Driver for Marvell 88E6060 switches"
+ 	select ETHERNET_PACKET_MANGLE
+ 
++config MVSW61XX_PHY
++	tristate "Driver for Marvell 88E6171/6172 switches"
++	select SWCONFIG
++
+ config IP17XX_PHY
+ 	tristate "Driver for IC+ IP17xx switches"
+ 	select SWCONFIG
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_MVSW61XX_PHY)	+= mvsw61xx.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
diff --git a/target/linux/generic/patches-4.1/734-net-phy-at803x-allow-to-configure-via-pdata.patch b/target/linux/generic/patches-4.1/734-net-phy-at803x-allow-to-configure-via-pdata.patch
new file mode 100644
index 0000000000..53abcc33ed
--- /dev/null
+++ b/target/linux/generic/patches-4.1/734-net-phy-at803x-allow-to-configure-via-pdata.patch
@@ -0,0 +1,180 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -12,12 +12,14 @@
+  */
+ 
+ #include <linux/phy.h>
++#include <linux/mdio.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/of_gpio.h>
+ #include <linux/gpio/consumer.h>
++#include <linux/platform_data/phy-at803x.h>
+ 
+ #define AT803X_INTR_ENABLE			0x12
+ #define AT803X_INTR_STATUS			0x13
+@@ -34,8 +36,16 @@
+ #define AT803X_INER				0x0012
+ #define AT803X_INER_INIT			0xec00
+ #define AT803X_INSR				0x0013
++
++#define AT803X_PCS_SMART_EEE_CTRL3			0x805D
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK	0x3
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT	12
++#define AT803X_SMART_EEE_CTRL3_LPI_EN			BIT(8)
++
+ #define AT803X_DEBUG_ADDR			0x1D
+ #define AT803X_DEBUG_DATA			0x1E
++#define AT803X_DBG0_REG				0x00
++#define AT803X_DEBUG_RGMII_RX_CLK_DLY		BIT(8)
+ #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
+ #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
+ 
+@@ -50,6 +60,7 @@ MODULE_LICENSE("GPL");
+ struct at803x_priv {
+ 	bool phy_reset:1;
+ 	struct gpio_desc *gpiod_reset;
++	int prev_speed;
+ };
+ 
+ struct at803x_context {
+@@ -61,6 +72,43 @@ struct at803x_context {
+ 	u16 led_control;
+ };
+ 
++static u16
++at803x_dbg_reg_rmw(struct phy_device *phydev, u16 reg, u16 clear, u16 set)
++{
++	struct mii_bus *bus = phydev->bus;
++	int val;
++
++	mutex_lock(&bus->mdio_lock);
++
++	bus->write(bus, phydev->addr, AT803X_DEBUG_ADDR, reg);
++	val = bus->read(bus, phydev->addr, AT803X_DEBUG_DATA);
++	if (val < 0) {
++		val = 0xffff;
++		goto out;
++	}
++
++	val &= ~clear;
++	val |= set;
++	bus->write(bus, phydev->addr, AT803X_DEBUG_DATA, val);
++
++out:
++	mutex_unlock(&bus->mdio_lock);
++	return val;
++}
++
++static inline void
++at803x_dbg_reg_set(struct phy_device *phydev, u16 reg, u16 set)
++{
++	at803x_dbg_reg_rmw(phydev, reg, 0, set);
++}
++
++static inline void
++at803x_dbg_reg_clr(struct phy_device *phydev, u16 reg, u16 clear)
++{
++	at803x_dbg_reg_rmw(phydev, reg, clear, 0);
++}
++
++
+ /* save relevant PHY registers to private copy */
+ static void at803x_context_save(struct phy_device *phydev,
+ 				struct at803x_context *context)
+@@ -209,8 +257,16 @@ static int at803x_probe(struct phy_devic
+ 	return 0;
+ }
+ 
++static void at803x_disable_smarteee(struct phy_device *phydev)
++{
++	phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
++		1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
++	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
++}
++
+ static int at803x_config_init(struct phy_device *phydev)
+ {
++	struct at803x_platform_data *pdata;
+ 	int ret;
+ 
+ 	ret = genphy_config_init(phydev);
+@@ -228,6 +284,26 @@ static int at803x_config_init(struct phy
+ 			return ret;
+ 	}
+ 
++	pdata = dev_get_platdata(&phydev->dev);
++	if (pdata) {
++		if (pdata->disable_smarteee)
++			at803x_disable_smarteee(phydev);
++
++		if (pdata->enable_rgmii_rx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DBG0_REG,
++				AT803X_DEBUG_RGMII_RX_CLK_DLY);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DBG0_REG,
++				AT803X_DEBUG_RGMII_RX_CLK_DLY);
++
++		if (pdata->enable_rgmii_tx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++	}
++
+ 	return 0;
+ }
+ 
+@@ -259,6 +335,8 @@ static int at803x_config_intr(struct phy
+ static void at803x_link_change_notify(struct phy_device *phydev)
+ {
+ 	struct at803x_priv *priv = phydev->priv;
++	struct at803x_platform_data *pdata;
++	pdata = dev_get_platdata(&phydev->dev);
+ 
+ 	/*
+ 	 * Conduct a hardware reset for AT8030 every time a link loss is
+@@ -289,6 +367,26 @@ static void at803x_link_change_notify(st
+ 			priv->phy_reset = false;
+ 		}
+ 	}
++	if (pdata && pdata->fixup_rgmii_tx_delay &&
++	    phydev->speed != priv->prev_speed) {
++		switch (phydev->speed) {
++		case SPEED_10:
++		case SPEED_100:
++			at803x_dbg_reg_set(phydev,
++				AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++			break;
++		case SPEED_1000:
++			at803x_dbg_reg_clr(phydev,
++				AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++			break;
++		default:
++			break;
++		}
++
++		priv->prev_speed = phydev->speed;
++	}
+ }
+ 
+ static struct phy_driver at803x_driver[] = {
+--- /dev/null
++++ b/include/linux/platform_data/phy-at803x.h
+@@ -0,0 +1,11 @@
++#ifndef _PHY_AT803X_PDATA_H
++#define _PHY_AT803X_PDATA_H
++
++struct at803x_platform_data {
++	int disable_smarteee:1;
++	int enable_rgmii_tx_delay:1;
++	int enable_rgmii_rx_delay:1;
++	int fixup_rgmii_tx_delay:1;
++};
++
++#endif /* _PHY_AT803X_PDATA_H */
diff --git a/target/linux/generic/patches-4.1/735-net-phy-at803x-fix-at8033-sgmii-mode.patch b/target/linux/generic/patches-4.1/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
new file mode 100644
index 0000000000..117f15d634
--- /dev/null
+++ b/target/linux/generic/patches-4.1/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
@@ -0,0 +1,96 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -36,6 +36,9 @@
+ #define AT803X_INER				0x0012
+ #define AT803X_INER_INIT			0xec00
+ #define AT803X_INSR				0x0013
++#define AT803X_REG_CHIP_CONFIG			0x1f
++#define AT803X_BT_BX_REG_SEL			0x8000
++#define AT803X_SGMII_ANEG_EN			0x1000
+ 
+ #define AT803X_PCS_SMART_EEE_CTRL3			0x805D
+ #define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK	0x3
+@@ -49,9 +52,10 @@
+ #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
+ #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
+ 
+-#define ATH8030_PHY_ID 0x004dd076
+-#define ATH8031_PHY_ID 0x004dd074
+-#define ATH8035_PHY_ID 0x004dd072
++#define AT803X_PHY_ID_MASK			0xffffffef
++#define ATH8030_PHY_ID				0x004dd076
++#define ATH8031_PHY_ID				0x004dd074
++#define ATH8035_PHY_ID				0x004dd072
+ 
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi");
+@@ -268,6 +272,27 @@ static int at803x_config_init(struct phy
+ {
+ 	struct at803x_platform_data *pdata;
+ 	int ret;
++	u32 v;
++
++	if (phydev->drv->phy_id == ATH8031_PHY_ID &&
++		phydev->interface == PHY_INTERFACE_MODE_SGMII)
++	{
++		v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
++		/* select SGMII/fiber page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v & ~AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++		/* enable SGMII autonegotiation */
++		ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
++		if (ret)
++			return ret;
++		/* select copper page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v | AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++	}
+ 
+ 	ret = genphy_config_init(phydev);
+ 	if (ret < 0)
+@@ -394,7 +419,7 @@ static struct phy_driver at803x_driver[]
+ 	/* ATHEROS 8035 */
+ 	.phy_id			= ATH8035_PHY_ID,
+ 	.name			= "Atheros 8035 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -413,7 +438,7 @@ static struct phy_driver at803x_driver[]
+ 	/* ATHEROS 8030 */
+ 	.phy_id			= ATH8030_PHY_ID,
+ 	.name			= "Atheros 8030 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -431,8 +456,8 @@ static struct phy_driver at803x_driver[]
+ }, {
+ 	/* ATHEROS 8031 */
+ 	.phy_id			= ATH8031_PHY_ID,
+-	.name			= "Atheros 8031 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.name			= "Atheros 8031/8033 ethernet",
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -454,9 +479,9 @@ static struct phy_driver at803x_driver[]
+ module_phy_driver(at803x_driver);
+ 
+ static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+-	{ ATH8030_PHY_ID, 0xffffffef },
+-	{ ATH8031_PHY_ID, 0xffffffef },
+-	{ ATH8035_PHY_ID, 0xffffffef },
++	{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ }
+ };
+ 
diff --git a/target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch b/target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch
new file mode 100644
index 0000000000..832e425632
--- /dev/null
+++ b/target/linux/generic/patches-4.1/760-8139cp-fixes-from-4.3.patch
@@ -0,0 +1,365 @@
+commit 41b976414c88016e2c9d9b2f6667ee67a998d388
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:45:31 2015 +0100
+
+    8139cp: Dump contents of descriptor ring on TX timeout
+    
+    We are seeing unexplained TX timeouts under heavy load. Let's try to get
+    a better idea of what's going on.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 7f4c685633e2df9ba10d49a31dda13715745db37
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:45:16 2015 +0100
+
+    8139cp: Fix DMA unmapping of transmitted buffers
+    
+    The low 16 bits of the 'opts1' field in the TX descriptor are supposed
+    to still contain the buffer length when the descriptor is handed back to
+    us. In practice, at least on my hardware, they don't. So stash the
+    original value of the opts1 field and get the length to unmap from
+    there.
+    
+    There are other ways we could have worked out the length, but I actually
+    want a stash of the opts1 field anyway so that I can dump it alongside
+    the contents of the descriptor ring when we suffer a TX timeout.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 0a5aeee0b79fa99d8e04c98dd4e87d4f52aa497b
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:44:57 2015 +0100
+
+    8139cp: Reduce duplicate csum/tso code in cp_start_xmit()
+    
+    We calculate the value of the opts1 descriptor field in three different
+    places. With two different behaviours when given an invalid packet to
+    be checksummed — none of them correct. Sort that out.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit a3b804043f490aeec57d8ca5baccdd35e6250857
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:44:38 2015 +0100
+
+    8139cp: Fix TSO/scatter-gather descriptor setup
+    
+    When sending a TSO frame in multiple buffers, we were neglecting to set
+    the first descriptor up in TSO mode.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 26b0bad6ac3a0167792dc4ffb276c29bc597d239
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:44:06 2015 +0100
+
+    8139cp: Fix tx_queued debug message to print correct slot numbers
+    
+    After a certain amount of staring at the debug output of this driver, I
+    realised it was lying to me.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit aaa0062ecf4877a26dea66bee1039c6eaf906c94
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:43:41 2015 +0100
+
+    8139cp: Do not re-enable RX interrupts in cp_tx_timeout()
+    
+    If an RX interrupt was already received but NAPI has not yet run when
+    the RX timeout happens, we end up in cp_tx_timeout() with RX interrupts
+    already disabled. Blindly re-enabling them will cause an IRQ storm.
+    
+    (This is made particularly horrid by the fact that cp_interrupt() always
+    returns that it's handled the interrupt, even when it hasn't actually
+    done anything. If it didn't do that, the core IRQ code would have
+    detected the storm and handled it, I'd have had a clear smoking gun
+    backtrace instead of just a spontaneously resetting router, and I'd have
+    at *least* two days of my life back. Changing the return value of
+    cp_interrupt() will be argued about under separate cover.)
+    
+    Unconditionally leave RX interrupts disabled after the reset, and
+    schedule NAPI to check the receive ring and re-enable them.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 7a8a8e75d505147358b225173e890ada43a267e2
+Author: David Woodhouse <dwmw2@infradead.org>
+Date:   Fri Sep 18 00:21:54 2015 +0100
+
+    8139cp: Call __cp_set_rx_mode() from cp_tx_timeout()
+    
+    Unless we reset the RX config, on real hardware I don't seem to receive
+    any packets after a TX timeout.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit fc27bd115b334e3ebdc682a42a47c3aea2566dcc
+Author: David Woodhouse <dwmw2@infradead.org>
+Date:   Fri Sep 18 00:19:08 2015 +0100
+
+    8139cp: Use dev_kfree_skb_any() instead of dev_kfree_skb() in cp_clean_rings()
+    
+    This can be called from cp_tx_timeout() with interrupts disabled.
+    Spotted by Francois Romieu <romieu@fr.zoreil.com>
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+--- a/drivers/net/ethernet/realtek/8139cp.c
++++ b/drivers/net/ethernet/realtek/8139cp.c
+@@ -157,6 +157,7 @@ enum {
+ 	NWayAdvert	= 0x66, /* MII ADVERTISE */
+ 	NWayLPAR	= 0x68, /* MII LPA */
+ 	NWayExpansion	= 0x6A, /* MII Expansion */
++	TxDmaOkLowDesc  = 0x82, /* Low 16 bit address of a Tx descriptor. */
+ 	Config5		= 0xD8,	/* Config5 */
+ 	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */
+ 	RxMaxSize	= 0xDA, /* Max size of an Rx packet (8169 only) */
+@@ -341,6 +342,7 @@ struct cp_private {
+ 	unsigned		tx_tail;
+ 	struct cp_desc		*tx_ring;
+ 	struct sk_buff		*tx_skb[CP_TX_RING_SIZE];
++	u32			tx_opts[CP_TX_RING_SIZE];
+ 
+ 	unsigned		rx_buf_sz;
+ 	unsigned		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
+@@ -665,7 +667,7 @@ static void cp_tx (struct cp_private *cp
+ 		BUG_ON(!skb);
+ 
+ 		dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
+-				 le32_to_cpu(txd->opts1) & 0xffff,
++				 cp->tx_opts[tx_tail] & 0xffff,
+ 				 PCI_DMA_TODEVICE);
+ 
+ 		if (status & LastFrag) {
+@@ -733,7 +735,7 @@ static netdev_tx_t cp_start_xmit (struct
+ {
+ 	struct cp_private *cp = netdev_priv(dev);
+ 	unsigned entry;
+-	u32 eor, flags;
++	u32 eor, opts1;
+ 	unsigned long intr_flags;
+ 	__le32 opts2;
+ 	int mss = 0;
+@@ -753,6 +755,21 @@ static netdev_tx_t cp_start_xmit (struct
+ 	mss = skb_shinfo(skb)->gso_size;
+ 
+ 	opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
++	opts1 = DescOwn;
++	if (mss)
++		opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
++	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
++		const struct iphdr *ip = ip_hdr(skb);
++		if (ip->protocol == IPPROTO_TCP)
++			opts1 |= IPCS | TCPCS;
++		else if (ip->protocol == IPPROTO_UDP)
++			opts1 |= IPCS | UDPCS;
++		else {
++			WARN_ONCE(1,
++				  "Net bug: asked to checksum invalid Legacy IP packet\n");
++			goto out_dma_error;
++		}
++	}
+ 
+ 	if (skb_shinfo(skb)->nr_frags == 0) {
+ 		struct cp_desc *txd = &cp->tx_ring[entry];
+@@ -768,31 +785,20 @@ static netdev_tx_t cp_start_xmit (struct
+ 		txd->addr = cpu_to_le64(mapping);
+ 		wmb();
+ 
+-		flags = eor | len | DescOwn | FirstFrag | LastFrag;
+-
+-		if (mss)
+-			flags |= LargeSend | ((mss & MSSMask) << MSSShift);
+-		else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-			const struct iphdr *ip = ip_hdr(skb);
+-			if (ip->protocol == IPPROTO_TCP)
+-				flags |= IPCS | TCPCS;
+-			else if (ip->protocol == IPPROTO_UDP)
+-				flags |= IPCS | UDPCS;
+-			else
+-				WARN_ON(1);	/* we need a WARN() */
+-		}
++		opts1 |= eor | len | FirstFrag | LastFrag;
+ 
+-		txd->opts1 = cpu_to_le32(flags);
++		txd->opts1 = cpu_to_le32(opts1);
+ 		wmb();
+ 
+ 		cp->tx_skb[entry] = skb;
+-		entry = NEXT_TX(entry);
++		cp->tx_opts[entry] = opts1;
++		netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
++			  entry, skb->len);
+ 	} else {
+ 		struct cp_desc *txd;
+-		u32 first_len, first_eor;
++		u32 first_len, first_eor, ctrl;
+ 		dma_addr_t first_mapping;
+ 		int frag, first_entry = entry;
+-		const struct iphdr *ip = ip_hdr(skb);
+ 
+ 		/* We must give this initial chunk to the device last.
+ 		 * Otherwise we could race with the device.
+@@ -805,14 +811,14 @@ static netdev_tx_t cp_start_xmit (struct
+ 			goto out_dma_error;
+ 
+ 		cp->tx_skb[entry] = skb;
+-		entry = NEXT_TX(entry);
+ 
+ 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+ 			const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ 			u32 len;
+-			u32 ctrl;
+ 			dma_addr_t mapping;
+ 
++			entry = NEXT_TX(entry);
++
+ 			len = skb_frag_size(this_frag);
+ 			mapping = dma_map_single(&cp->pdev->dev,
+ 						 skb_frag_address(this_frag),
+@@ -824,19 +830,7 @@ static netdev_tx_t cp_start_xmit (struct
+ 
+ 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+ 
+-			ctrl = eor | len | DescOwn;
+-
+-			if (mss)
+-				ctrl |= LargeSend |
+-					((mss & MSSMask) << MSSShift);
+-			else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-				if (ip->protocol == IPPROTO_TCP)
+-					ctrl |= IPCS | TCPCS;
+-				else if (ip->protocol == IPPROTO_UDP)
+-					ctrl |= IPCS | UDPCS;
+-				else
+-					BUG();
+-			}
++			ctrl = opts1 | eor | len;
+ 
+ 			if (frag == skb_shinfo(skb)->nr_frags - 1)
+ 				ctrl |= LastFrag;
+@@ -849,8 +843,8 @@ static netdev_tx_t cp_start_xmit (struct
+ 			txd->opts1 = cpu_to_le32(ctrl);
+ 			wmb();
+ 
++			cp->tx_opts[entry] = ctrl;
+ 			cp->tx_skb[entry] = skb;
+-			entry = NEXT_TX(entry);
+ 		}
+ 
+ 		txd = &cp->tx_ring[first_entry];
+@@ -858,27 +852,17 @@ static netdev_tx_t cp_start_xmit (struct
+ 		txd->addr = cpu_to_le64(first_mapping);
+ 		wmb();
+ 
+-		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-			if (ip->protocol == IPPROTO_TCP)
+-				txd->opts1 = cpu_to_le32(first_eor | first_len |
+-							 FirstFrag | DescOwn |
+-							 IPCS | TCPCS);
+-			else if (ip->protocol == IPPROTO_UDP)
+-				txd->opts1 = cpu_to_le32(first_eor | first_len |
+-							 FirstFrag | DescOwn |
+-							 IPCS | UDPCS);
+-			else
+-				BUG();
+-		} else
+-			txd->opts1 = cpu_to_le32(first_eor | first_len |
+-						 FirstFrag | DescOwn);
++		ctrl = opts1 | first_eor | first_len | FirstFrag;
++		txd->opts1 = cpu_to_le32(ctrl);
+ 		wmb();
++
++		cp->tx_opts[first_entry] = ctrl;
++		netif_dbg(cp, tx_queued, cp->dev, "tx queued, slots %d-%d, skblen %d\n",
++			  first_entry, entry, skb->len);
+ 	}
+-	cp->tx_head = entry;
++	cp->tx_head = NEXT_TX(entry);
+ 
+ 	netdev_sent_queue(dev, skb->len);
+-	netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
+-		  entry, skb->len);
+ 	if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
+ 		netif_stop_queue(dev);
+ 
+@@ -1115,6 +1099,7 @@ static int cp_init_rings (struct cp_priv
+ {
+ 	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+ 	cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
++	memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
+ 
+ 	cp_init_rings_index(cp);
+ 
+@@ -1151,7 +1136,7 @@ static void cp_clean_rings (struct cp_pr
+ 			desc = cp->rx_ring + i;
+ 			dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
+ 					 cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+-			dev_kfree_skb(cp->rx_skb[i]);
++			dev_kfree_skb_any(cp->rx_skb[i]);
+ 		}
+ 	}
+ 
+@@ -1164,7 +1149,7 @@ static void cp_clean_rings (struct cp_pr
+ 					 le32_to_cpu(desc->opts1) & 0xffff,
+ 					 PCI_DMA_TODEVICE);
+ 			if (le32_to_cpu(desc->opts1) & LastFrag)
+-				dev_kfree_skb(skb);
++				dev_kfree_skb_any(skb);
+ 			cp->dev->stats.tx_dropped++;
+ 		}
+ 	}
+@@ -1172,6 +1157,7 @@ static void cp_clean_rings (struct cp_pr
+ 
+ 	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+ 	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
++	memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
+ 
+ 	memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
+ 	memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
+@@ -1249,7 +1235,7 @@ static void cp_tx_timeout(struct net_dev
+ {
+ 	struct cp_private *cp = netdev_priv(dev);
+ 	unsigned long flags;
+-	int rc;
++	int rc, i;
+ 
+ 	netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
+ 		    cpr8(Cmd), cpr16(CpCmd),
+@@ -1257,13 +1243,26 @@ static void cp_tx_timeout(struct net_dev
+ 
+ 	spin_lock_irqsave(&cp->lock, flags);
+ 
++	netif_dbg(cp, tx_err, cp->dev, "TX ring head %d tail %d desc %x\n",
++		  cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc));
++	for (i = 0; i < CP_TX_RING_SIZE; i++) {
++		netif_dbg(cp, tx_err, cp->dev,
++			  "TX slot %d @%p: %08x (%08x) %08x %llx %p\n",
++			  i, &cp->tx_ring[i], le32_to_cpu(cp->tx_ring[i].opts1),
++			  cp->tx_opts[i], le32_to_cpu(cp->tx_ring[i].opts2),
++			  le64_to_cpu(cp->tx_ring[i].addr),
++			  cp->tx_skb[i]);
++	}
++
+ 	cp_stop_hw(cp);
+ 	cp_clean_rings(cp);
+ 	rc = cp_init_rings(cp);
+ 	cp_start_hw(cp);
+-	cp_enable_irq(cp);
++	__cp_set_rx_mode(dev);
++	cpw16_f(IntrMask, cp_norx_intr_mask);
+ 
+ 	netif_wake_queue(dev);
++	napi_schedule_irqoff(&cp->napi);
+ 
+ 	spin_unlock_irqrestore(&cp->lock, flags);
+ }
diff --git a/target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch b/target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch
new file mode 100644
index 0000000000..8fdf5f382f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/761-8139cp-fixes-from-4.4.patch
@@ -0,0 +1,103 @@
+commit 8b7a7048220f86547db31de0abe1ea6dd2cfa892
+Author: David Woodhouse <dwmw2@infradead.org>
+Date:   Thu Sep 24 11:38:22 2015 +0100
+
+    8139cp: Fix GSO MSS handling
+    
+    When fixing the TSO support I noticed we just mask ->gso_size with the
+    MSSMask value and don't care about the consequences.
+    
+    Provide a .ndo_features_check() method which drops the NETIF_F_TSO
+    feature for any skb which would exceed the maximum, and thus forces it
+    to be segmented by software.
+    
+    Then we can stop the masking in cp_start_xmit(), and just WARN if the
+    maximum is exceeded, which should now never happen.
+    
+    Finally, Francois Romieu noticed that we didn't even have the right
+    value for MSSMask anyway; it should be 0x7ff (11 bits) not 0xfff.
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+commit 5a58f227790faded5a3ef6075f3ddd65093e0f86
+Author: David Woodhouse <David.Woodhouse@intel.com>
+Date:   Wed Sep 23 09:46:09 2015 +0100
+
+    8139cp: Enable offload features by default
+    
+    I fixed TSO. Hardware checksum and scatter/gather also appear to be
+    working correctly both on real hardware and in QEMU's emulation.
+    
+    Let's enable them by default and see if anyone screams...
+    
+    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+--- a/drivers/net/ethernet/realtek/8139cp.c
++++ b/drivers/net/ethernet/realtek/8139cp.c
+@@ -175,7 +175,7 @@ enum {
+ 	LastFrag	= (1 << 28), /* Final segment of a packet */
+ 	LargeSend	= (1 << 27), /* TCP Large Send Offload (TSO) */
+ 	MSSShift	= 16,	     /* MSS value position */
+-	MSSMask		= 0xfff,     /* MSS value: 11 bits */
++	MSSMask		= 0x7ff,     /* MSS value: 11 bits */
+ 	TxError		= (1 << 23), /* Tx error summary */
+ 	RxError		= (1 << 20), /* Rx error summary */
+ 	IPCS		= (1 << 18), /* Calculate IP checksum */
+@@ -754,10 +754,16 @@ static netdev_tx_t cp_start_xmit (struct
+ 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+ 	mss = skb_shinfo(skb)->gso_size;
+ 
++	if (mss > MSSMask) {
++		WARN_ONCE(1, "Net bug: GSO size %d too large for 8139CP\n",
++			  mss);
++		goto out_dma_error;
++	}
++
+ 	opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
+ 	opts1 = DescOwn;
+ 	if (mss)
+-		opts1 |= LargeSend | ((mss & MSSMask) << MSSShift);
++		opts1 |= LargeSend | (mss << MSSShift);
+ 	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ 		const struct iphdr *ip = ip_hdr(skb);
+ 		if (ip->protocol == IPPROTO_TCP)
+@@ -1852,6 +1858,15 @@ static void cp_set_d3_state (struct cp_p
+ 	pci_set_power_state (cp->pdev, PCI_D3hot);
+ }
+ 
++static netdev_features_t cp_features_check(struct sk_buff *skb,
++					   struct net_device *dev,
++					   netdev_features_t features)
++{
++	if (skb_shinfo(skb)->gso_size > MSSMask)
++		features &= ~NETIF_F_TSO;
++
++	return vlan_features_check(skb, features);
++}
+ static const struct net_device_ops cp_netdev_ops = {
+ 	.ndo_open		= cp_open,
+ 	.ndo_stop		= cp_close,
+@@ -1864,6 +1879,7 @@ static const struct net_device_ops cp_ne
+ 	.ndo_tx_timeout		= cp_tx_timeout,
+ 	.ndo_set_features	= cp_set_features,
+ 	.ndo_change_mtu		= cp_change_mtu,
++	.ndo_features_check	= cp_features_check,
+ 
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ 	.ndo_poll_controller	= cp_poll_controller,
+@@ -1983,12 +1999,12 @@ static int cp_init_one (struct pci_dev *
+ 	dev->ethtool_ops = &cp_ethtool_ops;
+ 	dev->watchdog_timeo = TX_TIMEOUT;
+ 
+-	dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
++	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
++		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
+ 
+ 	if (pci_using_dac)
+ 		dev->features |= NETIF_F_HIGHDMA;
+ 
+-	/* disabled by default until verified */
+ 	dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
+ 		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
+ 	dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
diff --git a/target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch b/target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch
new file mode 100644
index 0000000000..ae7cb1c92b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/773-bgmac-add-srab-switch.patch
@@ -0,0 +1,72 @@
+Register switch connected to srab
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -17,6 +17,7 @@
+ #include <linux/phy_fixed.h>
+ #include <linux/interrupt.h>
+ #include <linux/dma-mapping.h>
++#include <linux/platform_data/b53.h>
+ #include <linux/bcm47xx_nvram.h>
+ 
+ static const struct bcma_device_id bgmac_bcma_tbl[] = {
+@@ -1538,6 +1539,17 @@ static void bgmac_mii_unregister(struct
+ 	mdiobus_free(mii_bus);
+ }
+ 
++static struct b53_platform_data bgmac_b53_pdata = {
++};
++
++static struct platform_device bgmac_b53_dev = {
++	.name		= "b53-srab-switch",
++	.id		= -1,
++	.dev		= {
++		.platform_data = &bgmac_b53_pdata,
++	},
++};
++
+ /**************************************************
+  * BCMA bus ops
+  **************************************************/
+@@ -1664,6 +1676,16 @@ static int bgmac_probe(struct bcma_devic
+ 	net_dev->hw_features = net_dev->features;
+ 	net_dev->vlan_features = net_dev->features;
+ 
++	if ((ci->id == BCMA_CHIP_ID_BCM4707 ||
++	     ci->id == BCMA_CHIP_ID_BCM53018) &&
++	    !bgmac_b53_pdata.regs) {
++		bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000);
++
++		err = platform_device_register(&bgmac_b53_dev);
++		if (!err)
++			bgmac->b53_device = &bgmac_b53_dev;
++	}
++
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+ 		bgmac_err(bgmac, "Cannot register net device\n");
+@@ -1690,6 +1712,10 @@ static void bgmac_remove(struct bcma_dev
+ {
+ 	struct bgmac *bgmac = bcma_get_drvdata(core);
+ 
++	if (bgmac->b53_device)
++		platform_device_unregister(&bgmac_b53_dev);
++	bgmac->b53_device = NULL;
++
+ 	unregister_netdev(bgmac->net_dev);
+ 	bgmac_mii_unregister(bgmac);
+ 	netif_napi_del(&bgmac->napi);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -462,6 +462,9 @@ struct bgmac {
+ 	bool has_robosw;
+ 
+ 	bool loopback;
++
++	/* platform device for associated switch */
++	struct platform_device *b53_device;
+ };
+ 
+ static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
diff --git a/target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch b/target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch
new file mode 100644
index 0000000000..621d08f4f1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/785-hso-support-0af0-9300.patch
@@ -0,0 +1,25 @@
+--- a/drivers/net/usb/hso.c
++++ b/drivers/net/usb/hso.c
+@@ -466,6 +466,7 @@ static const struct usb_device_id hso_id
+ 	{USB_DEVICE(0x0af0, 0x8900)},
+ 	{USB_DEVICE(0x0af0, 0x9000)},
+ 	{USB_DEVICE(0x0af0, 0x9200)},		/* Option GTM671WFS */
++	{USB_DEVICE(0x0af0, 0x9300)},		/* GTM 66xxWFS */
+ 	{USB_DEVICE(0x0af0, 0xd035)},
+ 	{USB_DEVICE(0x0af0, 0xd055)},
+ 	{USB_DEVICE(0x0af0, 0xd155)},
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -1330,6 +1330,12 @@ UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0
+ 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 		0 ),
+ 
++UNUSUAL_DEV( 0x0af0, 0x9300, 0x0000, 0x0000,
++		"Option",
++		"Globetrotter 66xxWFS SD-Card",
++		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++		0 ),
++
+ UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+ 		"Option",
+ 		"GI 070x SD-Card",
diff --git a/target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch b/target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch
new file mode 100644
index 0000000000..742618b03a
--- /dev/null
+++ b/target/linux/generic/patches-4.1/810-pci_disable_common_quirks.patch
@@ -0,0 +1,51 @@
+--- a/drivers/pci/Kconfig
++++ b/drivers/pci/Kconfig
+@@ -68,6 +68,12 @@ config XEN_PCIDEV_FRONTEND
+           The PCI device frontend driver allows the kernel to import arbitrary
+           PCI devices from a PCI backend to support PCI driver domains.
+ 
++config PCI_DISABLE_COMMON_QUIRKS
++	bool "PCI disable common quirks"
++	depends on PCI
++	help
++	  If you don't know what to do here, say N.
++
+ config HT_IRQ
+ 	bool "Interrupts on hypertransport devices"
+ 	default y
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct
+ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+ 				PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ /* The Mellanox Tavor device gives false positive parity errors
+  * Mark this device with a broken_parity_status, to allow
+  * PCI scanning code to "skip" this now blacklisted device.
+@@ -2977,6 +2978,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
+ 
+ /*
+  * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.  To
+@@ -3033,6 +3035,8 @@ static void fixup_debug_report(struct pc
+ 	}
+ }
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ /*
+  * Some BIOS implementations leave the Intel GPU interrupts enabled,
+  * even though no one is handling them (f.e. i915 driver is never loaded).
+@@ -3067,6 +3071,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
+ /*
+  * PCI devices which are on Intel chips can skip the 10ms delay
+  * before entering D3 mode.
diff --git a/target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch
new file mode 100644
index 0000000000..e078b4e8aa
--- /dev/null
+++ b/target/linux/generic/patches-4.1/811-pci_disable_usb_common_quirks.patch
@@ -0,0 +1,101 @@
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -97,6 +97,8 @@ struct amd_chipset_type {
+ 	u8 rev;
+ };
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static struct amd_chipset_info {
+ 	struct pci_dev	*nb_dev;
+ 	struct pci_dev	*smbus_dev;
+@@ -450,6 +452,10 @@ void usb_amd_dev_put(void)
+ }
+ EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+ 
++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
++#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
++
+ /*
+  * Make sure the controller is completely inactive, unable to
+  * generate interrupts or do DMA.
+@@ -529,8 +535,17 @@ reset_needed:
+ 	uhci_reset_hc(pdev, base);
+ 	return 1;
+ }
++#else
++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
++{
++	return 0;
++}
++
++#endif
+ EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
+ {
+ 	u16 cmd;
+@@ -1095,3 +1110,4 @@ static void quirk_usb_early_handoff(stru
+ }
+ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ 			PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
++#endif
+--- a/drivers/usb/host/pci-quirks.h
++++ b/drivers/usb/host/pci-quirks.h
+@@ -4,6 +4,9 @@
+ #ifdef CONFIG_PCI
+ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
+ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
++#endif  /* CONFIG_PCI */
++
++#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
+ int usb_amd_find_chipset_info(void);
+ int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
+ bool usb_amd_hang_symptom_quirk(void);
+@@ -16,11 +19,24 @@ void usb_disable_xhci_ports(struct pci_d
+ void sb800_prefetch(struct device *dev, int on);
+ #else
+ struct pci_dev;
++static inline int usb_amd_find_chipset_info(void)
++{
++	return 0;
++}
++static inline bool usb_amd_hang_symptom_quirk(void)
++{
++	return false;
++}
++static inline bool usb_amd_prefetch_quirk(void)
++{
++	return false;
++}
+ static inline void usb_amd_quirk_pll_disable(void) {}
+ static inline void usb_amd_quirk_pll_enable(void) {}
+ static inline void usb_amd_dev_put(void) {}
+ static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
+ static inline void sb800_prefetch(struct device *dev, int on) {}
+-#endif  /* CONFIG_PCI */
++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
++#endif
+ 
+ #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -448,7 +448,14 @@ extern int usb_hcd_pci_probe(struct pci_
+ extern void usb_hcd_pci_remove(struct pci_dev *dev);
+ extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
++#else
++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
++{
++	return 0;
++}
++#endif
+ 
+ #ifdef CONFIG_PM
+ extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
diff --git a/target/linux/generic/patches-4.1/831-ledtrig_netdev.patch b/target/linux/generic/patches-4.1/831-ledtrig_netdev.patch
new file mode 100644
index 0000000000..f6f1f51b93
--- /dev/null
+++ b/target/linux/generic/patches-4.1/831-ledtrig_netdev.patch
@@ -0,0 +1,21 @@
+--- a/drivers/leds/trigger/Kconfig
++++ b/drivers/leds/trigger/Kconfig
+@@ -108,4 +108,11 @@ config LEDS_TRIGGER_CAMERA
+ 	  This enables direct flash/torch on/off by the driver, kernel space.
+ 	  If unsure, say Y.
+ 
++config LEDS_TRIGGER_NETDEV
++	tristate "LED Netdev Trigger"
++	depends on NET && LEDS_TRIGGERS
++	help
++	  This allows LEDs to be controlled by network device activity.
++	  If unsure, say Y.
++
+ endif # LEDS_TRIGGERS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -65,3 +65,4 @@ obj-$(CONFIG_LEDS_DAC124S085)		+= leds-d
+ 
+ # LED Triggers
+ obj-$(CONFIG_LEDS_TRIGGERS)		+= trigger/
++obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
diff --git a/target/linux/generic/patches-4.1/834-ledtrig-libata.patch b/target/linux/generic/patches-4.1/834-ledtrig-libata.patch
new file mode 100644
index 0000000000..41b7d9aa30
--- /dev/null
+++ b/target/linux/generic/patches-4.1/834-ledtrig-libata.patch
@@ -0,0 +1,153 @@
+From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 12 Dec 2014 13:38:33 +0100
+Subject: [PATCH] libata: add ledtrig support
+To: linux-ide@vger.kernel.org,
+    Tejun Heo <tj@kernel.org>
+
+This adds a LED trigger for each ATA port indicating disk activity.
+
+As this is needed only on specific platforms (NAS SoCs and such),
+these platforms should define ARCH_WANTS_LIBATA_LEDS if there
+are boards with LED(s) intended to indicate ATA disk activity and
+need the OS to take care of that.
+In that way, if not selected, LED trigger support not will be
+included in libata-core and both, codepaths and structures remain
+untouched.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/ata/Kconfig       | 16 ++++++++++++++++
+ drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/libata.h    |  9 +++++++++
+ 3 files changed, 66 insertions(+)
+
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
+ 
+ 	  If unsure, say Y.
+ 
++config ARCH_WANT_LIBATA_LEDS
++	bool
++
++config ATA_LEDS
++	bool "support ATA port LED triggers"
++	depends on ARCH_WANT_LIBATA_LEDS
++	select NEW_LEDS
++	select LEDS_CLASS
++	select LEDS_TRIGGERS
++	default y
++	help
++	  This option adds a LED trigger for each registered ATA port.
++	  It is used to drive disk activity leds connected via GPIO.
++
++	  If unsure, say N.
++
+ config ATA_ACPI
+ 	bool "ATA ACPI Support"
+ 	depends on ACPI && PCI
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -728,6 +728,19 @@ u64 ata_tf_read_block(struct ata_taskfil
+ 	return block;
+ }
+ 
++#ifdef CONFIG_ATA_LEDS
++#define LIBATA_BLINK_DELAY 20 /* ms */
++static inline void ata_led_act(struct ata_port *ap)
++{
++	unsigned long led_delay = LIBATA_BLINK_DELAY;
++
++	if (unlikely(!ap->ledtrig))
++		return;
++
++	led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
++}
++#endif
++
+ /**
+  *	ata_build_rw_tf - Build ATA taskfile for given read/write request
+  *	@tf: Target ATA taskfile
+@@ -4779,6 +4792,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
+ 		if (tag < 0)
+ 			return NULL;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	ata_led_act(ap);
++#endif
+ 
+ 	qc = __ata_qc_from_tag(ap, tag);
+ 	qc->tag = tag;
+@@ -5676,6 +5692,9 @@ struct ata_port *ata_port_alloc(struct a
+ 	ap->stats.unhandled_irq = 1;
+ 	ap->stats.idle_irq = 1;
+ #endif
++#ifdef CONFIG_ATA_LEDS
++	ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
++#endif
+ 	ata_sff_port_init(ap);
+ 
+ 	return ap;
+@@ -5697,6 +5716,12 @@ static void ata_host_release(struct devi
+ 
+ 		kfree(ap->pmp_link);
+ 		kfree(ap->slave_link);
++#ifdef CONFIG_ATA_LEDS
++		if (ap->ledtrig) {
++			led_trigger_unregister(ap->ledtrig);
++			kfree(ap->ledtrig);
++		};
++#endif
+ 		kfree(ap);
+ 		host->ports[i] = NULL;
+ 	}
+@@ -6143,7 +6168,23 @@ int ata_host_register(struct ata_host *h
+ 		host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+ 		host->ports[i]->local_port_no = i + 1;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	for (i = 0; i < host->n_ports; i++) {
++		if (unlikely(!host->ports[i]->ledtrig))
++			continue;
+ 
++		snprintf(host->ports[i]->ledtrig_name,
++			sizeof(host->ports[i]->ledtrig_name), "ata%u",
++			host->ports[i]->print_id);
++
++		host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
++
++		if (led_trigger_register(host->ports[i]->ledtrig)) {
++			kfree(host->ports[i]->ledtrig);
++			host->ports[i]->ledtrig = NULL;
++		}
++	}
++#endif
+ 	/* Create associated sysfs transport objects  */
+ 	for (i = 0; i < host->n_ports; i++) {
+ 		rc = ata_tport_add(host->dev,host->ports[i]);
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -38,6 +38,9 @@
+ #include <linux/acpi.h>
+ #include <linux/cdrom.h>
+ #include <linux/sched.h>
++#ifdef CONFIG_ATA_LEDS
++#include <linux/leds.h>
++#endif
+ 
+ /*
+  * Define if arch has non-standard setup.  This is a _PCI_ standard
+@@ -876,6 +879,12 @@ struct ata_port {
+ #ifdef CONFIG_ATA_ACPI
+ 	struct ata_acpi_gtm	__acpi_init_gtm; /* use ata_acpi_init_gtm() */
+ #endif
++
++#ifdef CONFIG_ATA_LEDS
++	struct led_trigger	*ledtrig;
++	char			ledtrig_name[8];
++#endif
++
+ 	/* owned by EH */
+ 	u8			sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ };
diff --git a/target/linux/generic/patches-4.1/840-rtc7301.patch b/target/linux/generic/patches-4.1/840-rtc7301.patch
new file mode 100644
index 0000000000..148ccaa9d7
--- /dev/null
+++ b/target/linux/generic/patches-4.1/840-rtc7301.patch
@@ -0,0 +1,250 @@
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -1109,6 +1109,15 @@ config RTC_DRV_OPAL
+ 	  This driver can also be built as a module. If so, the module
+ 	  will be called rtc-opal.
+ 
++config RTC_DRV_RTC7301
++	tristate "Epson RTC-7301 SF/DG"
++	help
++	  If you say Y here you will get support for the
++	  Epson RTC-7301 SF/DG RTC chips.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-7301.
++
+ comment "on-CPU RTC drivers"
+ 
+ config RTC_DRV_DAVINCI
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -121,6 +121,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01)	+= rtc-rp5c
+ obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
+ obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o
+ obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
++obj-$(CONFIG_RTC_DRV_RTC7301)	+= rtc-rtc7301.o
+ obj-$(CONFIG_RTC_DRV_RV3029C2)	+= rtc-rv3029c2.o
+ obj-$(CONFIG_RTC_DRV_RX4581)	+= rtc-rx4581.o
+ obj-$(CONFIG_RTC_DRV_RX8025)	+= rtc-rx8025.o
+--- /dev/null
++++ b/drivers/rtc/rtc-rtc7301.c
+@@ -0,0 +1,219 @@
++/*
++ * Driver for Epson RTC-7301SF/DG
++ *
++ * Copyright (C) 2009 Jose Vasconcellos
++ *
++ * 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/module.h>
++#include <linux/rtc.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/bcd.h>
++
++#define RTC_NAME "rtc7301"
++#define RTC_VERSION "0.1"
++
++/* Epson RTC-7301 register addresses */
++#define RTC7301_SEC		0x00
++#define RTC7301_SEC10		0x01
++#define RTC7301_MIN		0x02
++#define RTC7301_MIN10		0x03
++#define RTC7301_HOUR		0x04
++#define RTC7301_HOUR10		0x05
++#define RTC7301_WEEKDAY		0x06
++#define RTC7301_DAY		0x07
++#define RTC7301_DAY10		0x08
++#define RTC7301_MON		0x09
++#define RTC7301_MON10		0x0A
++#define RTC7301_YEAR		0x0B
++#define RTC7301_YEAR10		0x0C
++#define RTC7301_YEAR100		0x0D
++#define RTC7301_YEAR1000	0x0E
++#define RTC7301_CTRLREG		0x0F
++
++static uint8_t __iomem *rtc7301_base;
++
++#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf)
++#define write_reg(offset, data) writeb(data, rtc7301_base + (offset))
++
++#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1)
++
++static void rtc7301_init_settings(void)
++{
++	int i;
++
++	write_reg(RTC7301_CTRLREG, 2);
++	write_reg(RTC7301_YEAR1000, 2);
++	udelay(122);
++
++	/* bank 1 */
++	write_reg(RTC7301_CTRLREG, 6);
++	for (i=0; i<15; i++)
++		write_reg(i, 0);
++
++	/* bank 2 */
++	write_reg(RTC7301_CTRLREG, 14);
++	for (i=0; i<15; i++)
++		write_reg(i, 0);
++	write_reg(RTC7301_CTRLREG, 0);
++}
++
++static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt)
++{
++	int cnt;
++	uint8_t buf[16];
++
++	cnt = 0;
++	while (rtc7301_isbusy()) {
++		udelay(244);
++		if (cnt++ > 100) {
++			dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]);
++			return -EIO;
++		}
++	}
++
++	for (cnt=0; cnt<16; cnt++)
++		buf[cnt] = read_reg(cnt);
++
++	if (buf[RTC7301_SEC10] & 8) {
++		dev_err(dev, "%s: RTC not set\n", __func__);
++		return -EINVAL;
++	}
++
++	memset(dt, 0, sizeof(*dt));
++
++	dt->tm_sec =  buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10;
++	dt->tm_min =  buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10;
++	dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10;
++
++	dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10;
++	dt->tm_mon =  buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1;
++	dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 +
++		      buf[RTC7301_YEAR100]*100 +
++		      ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900;
++
++	/* the rtc device may contain illegal values on power up
++	 * according to the data sheet. make sure they are valid.
++	 */
++
++	return rtc_valid_tm(dt);
++}
++
++static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt)
++{
++	int data;
++
++	data = dt->tm_year + 1900;
++	if (data >= 2100 || data < 1900)
++		return -EINVAL;
++
++	write_reg(RTC7301_CTRLREG, 2);
++       	udelay(122);
++
++	data = bin2bcd(dt->tm_sec);
++	write_reg(RTC7301_SEC, data);
++	write_reg(RTC7301_SEC10, (data >> 4));
++
++	data = bin2bcd(dt->tm_min);
++	write_reg(RTC7301_MIN, data );
++	write_reg(RTC7301_MIN10, (data >> 4));
++
++	data = bin2bcd(dt->tm_hour);
++	write_reg(RTC7301_HOUR, data);
++	write_reg(RTC7301_HOUR10, (data >> 4));
++
++	data = bin2bcd(dt->tm_mday);
++	write_reg(RTC7301_DAY, data);
++	write_reg(RTC7301_DAY10, (data>> 4));
++
++	data = bin2bcd(dt->tm_mon + 1);
++	write_reg(RTC7301_MON, data);
++	write_reg(RTC7301_MON10, (data >> 4));
++
++	data = bin2bcd(dt->tm_year % 100);
++	write_reg(RTC7301_YEAR, data);
++	write_reg(RTC7301_YEAR10, (data >> 4));
++	data = bin2bcd((1900 + dt->tm_year) / 100);
++	write_reg(RTC7301_YEAR100, data);
++
++	data = bin2bcd(dt->tm_wday);
++	write_reg(RTC7301_WEEKDAY, data);
++
++	write_reg(RTC7301_CTRLREG, 0);
++
++	return 0;
++}
++
++static const struct rtc_class_ops rtc7301_rtc_ops = {
++	.read_time	= rtc7301_get_datetime,
++	.set_time	= rtc7301_set_datetime,
++};
++
++static int rtc7301_probe(struct platform_device *pdev)
++{
++	struct rtc_device *rtc;
++	struct resource *res;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENOENT;
++
++	rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/);
++	if (!rtc7301_base)
++		return -EINVAL;
++
++	rtc = rtc_device_register(RTC_NAME, &pdev->dev,
++				&rtc7301_rtc_ops, THIS_MODULE);
++	if (IS_ERR(rtc)) {
++		iounmap(rtc7301_base);
++		return PTR_ERR(rtc);
++	}
++
++	platform_set_drvdata(pdev, rtc);
++
++	rtc7301_init_settings();
++	return 0;
++}
++
++static int rtc7301_remove(struct platform_device *pdev)
++{
++	struct rtc_device *rtc = platform_get_drvdata(pdev);
++
++	if (rtc)
++		rtc_device_unregister(rtc);
++	if (rtc7301_base)
++		iounmap(rtc7301_base);
++	return 0;
++}
++
++static struct platform_driver rtc7301_driver = {
++	.driver = {
++		.name	= RTC_NAME,
++		.owner	= THIS_MODULE,
++	},
++	.probe	= rtc7301_probe,
++	.remove = rtc7301_remove,
++};
++
++static __init int rtc7301_init(void)
++{
++	return platform_driver_register(&rtc7301_driver);
++}
++module_init(rtc7301_init);
++
++static __exit void rtc7301_exit(void)
++{
++	platform_driver_unregister(&rtc7301_driver);
++}
++module_exit(rtc7301_exit);
++
++MODULE_DESCRIPTION("Epson 7301 RTC driver");
++MODULE_AUTHOR("Jose Vasconcellos <jvasco@verizon.net>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" RTC_NAME);
++MODULE_VERSION(RTC_VERSION);
diff --git a/target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch b/target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch
new file mode 100644
index 0000000000..5de1b874b3
--- /dev/null
+++ b/target/linux/generic/patches-4.1/841-rtc_pt7c4338.patch
@@ -0,0 +1,247 @@
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -596,6 +596,15 @@ config RTC_DRV_S5M
+ 	  This driver can also be built as a module. If so, the module
+ 	  will be called rtc-s5m.
+ 
++config RTC_DRV_PT7C4338
++	tristate "Pericom Technology Inc. PT7C4338 RTC"
++	help
++	  If you say yes here you get support for the Pericom Technology
++	  Inc. PT7C4338 RTC chip.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-pt7c4338.
++
+ endif # I2C
+ 
+ comment "SPI RTC drivers"
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -112,6 +112,7 @@ obj-$(CONFIG_RTC_DRV_PL030)	+= rtc-pl030
+ obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
+ obj-$(CONFIG_RTC_DRV_PM8XXX)	+= rtc-pm8xxx.o
+ obj-$(CONFIG_RTC_DRV_PS3)	+= rtc-ps3.o
++obj-$(CONFIG_RTC_DRV_PT7C4338)	+= rtc-pt7c4338.o
+ obj-$(CONFIG_RTC_DRV_PUV3)	+= rtc-puv3.o
+ obj-$(CONFIG_RTC_DRV_PXA)	+= rtc-pxa.o
+ obj-$(CONFIG_RTC_DRV_R9701)	+= rtc-r9701.o
+--- /dev/null
++++ b/drivers/rtc/rtc-pt7c4338.c
+@@ -0,0 +1,216 @@
++/*
++ * Copyright 2010 Freescale Semiconductor, Inc.
++ *
++ * Author:	Priyanka Jain <Priyanka.Jain@freescale.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++/*
++ * This file provides Date & Time support (no alarms) for PT7C4338 chip.
++ *
++ * This file is based on drivers/rtc/rtc-ds1307.c
++ *
++ * PT7C4338 chip is manufactured by Pericom Technology Inc.
++ * It is a serial real-time clock which provides
++ * 1)Low-power clock/calendar.
++ * 2)Programmable square-wave output.
++ * It has 56 bytes of nonvolatile RAM.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/rtc.h>
++#include <linux/bcd.h>
++
++/* RTC register addresses */
++#define PT7C4338_REG_SECONDS          0x00
++#define PT7C4338_REG_MINUTES          0x01
++#define PT7C4338_REG_HOURS            0x02
++#define PT7C4338_REG_AMPM             0x02
++#define PT7C4338_REG_DAY              0x03
++#define PT7C4338_REG_DATE             0x04
++#define PT7C4338_REG_MONTH            0x05
++#define PT7C4338_REG_YEAR             0x06
++#define PT7C4338_REG_CTRL_STAT        0x07
++
++/* RTC second register address bit */
++#define PT7C4338_SEC_BIT_CH           0x80	/*Clock Halt (in Register 0)*/
++
++/* RTC control and status register bits */
++#define PT7C4338_CTRL_STAT_BIT_RS0    0x1	/*Rate select 0*/
++#define PT7C4338_CTRL_STAT_BIT_RS1    0x2	/*Rate select 1*/
++#define PT7C4338_CTRL_STAT_BIT_SQWE   0x10	/*Square Wave Enable*/
++#define PT7C4338_CTRL_STAT_BIT_OSF    0x20	/*Oscillator Stop Flag*/
++#define PT7C4338_CTRL_STAT_BIT_OUT    0x80	/*Output Level Control*/
++
++static const struct i2c_device_id pt7c4338_id[] = {
++	{ "pt7c4338", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, pt7c4338_id);
++
++struct pt7c4338{
++	struct i2c_client *client;
++	struct rtc_device *rtc;
++};
++
++static int pt7c4338_read_time(struct device *dev, struct rtc_time *time)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	int ret;
++	u8 buf[7];
++	u8 year, month, day, hour, minute, second;
++	u8 week, twelve_hr, am_pm;
++
++	ret = i2c_smbus_read_i2c_block_data(client,
++			PT7C4338_REG_SECONDS, 7, buf);
++	if (ret < 0)
++		return ret;
++	if (ret < 7)
++		return -EIO;
++
++	second = buf[0];
++	minute = buf[1];
++	hour = buf[2];
++	week = buf[3];
++	day = buf[4];
++	month = buf[5];
++	year = buf[6];
++
++	/* Extract additional information for AM/PM */
++	twelve_hr = hour & 0x40;
++	am_pm = hour & 0x20;
++
++	/* Write to rtc_time structure */
++	time->tm_sec = bcd2bin(second & 0x7f);
++	time->tm_min = bcd2bin(minute & 0x7f);
++	if (twelve_hr) {
++		/* Convert to 24 hr */
++		if (am_pm)
++			time->tm_hour = bcd2bin(hour & 0x10) + 12;
++		else
++			time->tm_hour = bcd2bin(hour & 0xBF);
++	} else {
++		time->tm_hour = bcd2bin(hour);
++	}
++
++	time->tm_wday = bcd2bin(week & 0x07) - 1;
++	time->tm_mday = bcd2bin(day & 0x3f);
++	time->tm_mon = bcd2bin(month & 0x1F) - 1;
++	/* assume 20YY not 19YY */
++	time->tm_year = bcd2bin(year) + 100;
++
++	return 0;
++}
++
++static int pt7c4338_set_time(struct device *dev, struct rtc_time *time)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	u8 buf[7];
++
++	/* Extract time from rtc_time and load into pt7c4338*/
++	buf[0] = bin2bcd(time->tm_sec);
++	buf[1] = bin2bcd(time->tm_min);
++	buf[2] = bin2bcd(time->tm_hour);
++	buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */
++	buf[4] = bin2bcd(time->tm_mday); /* Date */
++	buf[5] = bin2bcd(time->tm_mon + 1);
++
++	/* assume 20YY not 19YY */
++	if (time->tm_year >= 100)
++		buf[6] = bin2bcd(time->tm_year - 100);
++	else
++		buf[6] = bin2bcd(time->tm_year);
++
++	return i2c_smbus_write_i2c_block_data(client,
++					PT7C4338_REG_SECONDS, 7, buf);
++}
++
++static const struct rtc_class_ops pt7c4338_rtc_ops = {
++	.read_time = pt7c4338_read_time,
++	.set_time = pt7c4338_set_time,
++};
++
++static int pt7c4338_probe(struct i2c_client *client,
++		const struct i2c_device_id *id)
++{
++	struct pt7c4338 *pt7c4338;
++	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
++	int ret;
++
++	pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL);
++	if (!pt7c4338)
++		return -ENOMEM;
++
++	pt7c4338->client = client;
++	i2c_set_clientdata(client, pt7c4338);
++	pt7c4338->rtc = rtc_device_register(client->name, &client->dev,
++					&pt7c4338_rtc_ops, THIS_MODULE);
++	if (IS_ERR(pt7c4338->rtc)) {
++		ret = PTR_ERR(pt7c4338->rtc);
++		dev_err(&client->dev, "unable to register the class device\n");
++		goto out_free;
++	}
++
++	return 0;
++out_free:
++	i2c_set_clientdata(client, NULL);
++	kfree(pt7c4338);
++	return ret;
++}
++
++static int pt7c4338_remove(struct i2c_client *client)
++{
++	struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client);
++
++	rtc_device_unregister(pt7c4338->rtc);
++	i2c_set_clientdata(client, NULL);
++	kfree(pt7c4338);
++	return 0;
++}
++
++static struct i2c_driver pt7c4338_driver = {
++	.driver = {
++		.name = "rtc-pt7c4338",
++		.owner = THIS_MODULE,
++	},
++	.probe = pt7c4338_probe,
++	.remove = pt7c4338_remove,
++	.id_table = pt7c4338_id,
++};
++
++static int __init pt7c4338_init(void)
++{
++	return i2c_add_driver(&pt7c4338_driver);
++}
++
++static void __exit pt7c4338_exit(void)
++{
++	i2c_del_driver(&pt7c4338_driver);
++}
++
++module_init(pt7c4338_init);
++module_exit(pt7c4338_exit);
++
++MODULE_AUTHOR("Priyanka Jain <Priyanka.Jain@freescale.com>");
++MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch b/target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch
new file mode 100644
index 0000000000..fc1b40c035
--- /dev/null
+++ b/target/linux/generic/patches-4.1/861-04_spi_gpio_implement_spi_delay.patch
@@ -0,0 +1,58 @@
+Implement the SPI-GPIO delay function for busses that need speed limitation.
+
+--mb
+
+
+
+--- a/drivers/spi/spi-gpio.c
++++ b/drivers/spi/spi-gpio.c
+@@ -17,6 +17,7 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/gpio.h>
++#include <linux/delay.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_gpio.h>
+@@ -69,6 +70,7 @@ struct spi_gpio {
+  *		#define	SPI_MOSI_GPIO	120
+  *		#define	SPI_SCK_GPIO	121
+  *		#define	SPI_N_CHIPSEL	4
++ *		#undef NEED_SPIDELAY
+  *		#include "spi-gpio.c"
+  */
+ 
+@@ -76,6 +78,7 @@ struct spi_gpio {
+ #define DRIVER_NAME	"spi_gpio"
+ 
+ #define GENERIC_BITBANG	/* vs tight inlines */
++#define NEED_SPIDELAY	1
+ 
+ /* all functions referencing these symbols must define pdata */
+ #define SPI_MISO_GPIO	((pdata)->miso)
+@@ -126,12 +129,20 @@ static inline int getmiso(const struct s
+ #undef pdata
+ 
+ /*
+- * NOTE:  this clocks "as fast as we can".  It "should" be a function of the
+- * requested device clock.  Software overhead means we usually have trouble
+- * reaching even one Mbit/sec (except when we can inline bitops), so for now
+- * we'll just assume we never need additional per-bit slowdowns.
++ * NOTE:  to clock "as fast as we can", set spi_device.max_speed_hz
++ * and spi_transfer.speed_hz to 0.
++ * Otherwise this is a function of the requested device clock.
++ * Software overhead means we usually have trouble
++ * reaching even one Mbit/sec (except when we can inline bitops). So on small
++ * embedded devices with fast SPI slaves you usually don't need a delay.
+  */
+-#define spidelay(nsecs)	do {} while (0)
++static inline void spidelay(unsigned nsecs)
++{
++#ifdef NEED_SPIDELAY
++	if (unlikely(nsecs))
++		ndelay(nsecs);
++#endif /* NEED_SPIDELAY */
++}
+ 
+ #include "spi-bitbang-txrx.h"
+ 
diff --git a/target/linux/generic/patches-4.1/862-gpio_spi_driver.patch b/target/linux/generic/patches-4.1/862-gpio_spi_driver.patch
new file mode 100644
index 0000000000..be059383f3
--- /dev/null
+++ b/target/linux/generic/patches-4.1/862-gpio_spi_driver.patch
@@ -0,0 +1,373 @@
+THIS CODE IS DEPRECATED.
+
+Please use the new mainline SPI-GPIO driver, as of 2.6.29.
+
+--mb
+
+
+
+---
+ drivers/spi/Kconfig              |    9 +
+ drivers/spi/Makefile             |    1 
+ drivers/spi/spi_gpio_old.c       |  251 +++++++++++++++++++++++++++++++++++++++
+ include/linux/spi/spi_gpio_old.h |   73 +++++++++++
+ 4 files changed, 334 insertions(+)
+
+--- /dev/null
++++ b/include/linux/spi/spi_gpio_old.h
+@@ -0,0 +1,73 @@
++/*
++ * spi_gpio interface to platform code
++ *
++ * Copyright (c) 2008 Piotr Skamruk
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * 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.
++ */
++#ifndef _LINUX_SPI_SPI_GPIO
++#define _LINUX_SPI_SPI_GPIO
++
++#include <linux/types.h>
++#include <linux/spi/spi.h>
++
++
++/**
++ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
++ *
++ * This structure holds information about a GPIO-based SPI device.
++ *
++ * @pin_clk: The GPIO pin number of the CLOCK pin.
++ *
++ * @pin_miso: The GPIO pin number of the MISO pin.
++ *
++ * @pin_mosi: The GPIO pin number of the MOSI pin.
++ *
++ * @pin_cs: The GPIO pin number of the CHIPSELECT pin.
++ *
++ * @cs_activelow: If true, the chip is selected when the CS line is low.
++ *
++ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
++ *                Note that doing no delay is not standards compliant,
++ *                but it might be needed to speed up transfers on some
++ *                slow embedded machines.
++ *
++ * @boardinfo_setup: This callback is called after the
++ *                   SPI master device was registered, but before the
++ *                   device is registered.
++ * @boardinfo_setup_data: Data argument passed to boardinfo_setup().
++ */
++struct spi_gpio_platform_data {
++	unsigned int pin_clk;
++	unsigned int pin_miso;
++	unsigned int pin_mosi;
++	unsigned int pin_cs;
++	bool cs_activelow;
++	bool no_spi_delay;
++	int (*boardinfo_setup)(struct spi_board_info *bi,
++			       struct spi_master *master,
++			       void *data);
++	void *boardinfo_setup_data;
++};
++
++/**
++ * SPI_GPIO_PLATDEV_NAME - The platform device name string.
++ *
++ * The name string that has to be used for platform_device_alloc
++ * when allocating a spi-gpio device.
++ */
++#define SPI_GPIO_PLATDEV_NAME	"spi-gpio"
++
++/**
++ * spi_gpio_next_id - Get another platform device ID number.
++ *
++ * This returns the next platform device ID number that has to be used
++ * for platform_device_alloc. The ID is opaque and should not be used for
++ * anything else.
++ */
++int spi_gpio_next_id(void);
++
++#endif /* _LINUX_SPI_SPI_GPIO */
+--- /dev/null
++++ b/drivers/spi/spi_gpio_old.c
+@@ -0,0 +1,251 @@
++/*
++ * Bitbanging SPI bus driver using GPIO API
++ *
++ * Copyright (c) 2008 Piotr Skamruk
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * based on spi_s3c2410_gpio.c
++ *   Copyright (c) 2006 Ben Dooks
++ *   Copyright (c) 2006 Simtec Electronics
++ * and on i2c-gpio.c
++ *   Copyright (C) 2007 Atmel Corporation
++ *
++ * 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/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/gpio.h>
++#include <asm/atomic.h>
++
++
++struct spi_gpio {
++	struct spi_bitbang bitbang;
++	struct spi_gpio_platform_data *info;
++	struct platform_device *pdev;
++	struct spi_board_info bi;
++};
++
++
++static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
++{
++	return dev->controller_data;
++}
++
++static inline void setsck(struct spi_device *dev, int val)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
++}
++
++static inline void setmosi(struct spi_device *dev, int val)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
++}
++
++static inline u32 getmiso(struct spi_device *dev)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
++}
++
++static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++
++	if (!sp->info->no_spi_delay)
++		ndelay(nsecs);
++}
++
++#define spidelay(nsecs) do {					\
++	/* Steal the spi_device pointer from our caller.	\
++	 * The bitbang-API should probably get fixed here... */	\
++	do_spidelay(spi, nsecs);				\
++  } while (0)
++
++#define EXPAND_BITBANG_TXRX
++#include "spi-bitbang-txrx.h"
++
++static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
++}
++
++static void spi_gpio_chipselect(struct spi_device *dev, int on)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++
++	if (sp->info->cs_activelow)
++		on = !on;
++	gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
++}
++
++static int spi_gpio_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct spi_gpio_platform_data *pdata;
++	struct spi_gpio *sp;
++	struct spi_device *spidev;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata)
++		return -ENXIO;
++
++	err = -ENOMEM;
++	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
++	if (!master)
++		goto err_alloc_master;
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++	sp->info = pdata;
++
++	err = gpio_request(pdata->pin_clk, "spi_clock");
++	if (err)
++		goto err_request_clk;
++	err = gpio_request(pdata->pin_mosi, "spi_mosi");
++	if (err)
++		goto err_request_mosi;
++	err = gpio_request(pdata->pin_miso, "spi_miso");
++	if (err)
++		goto err_request_miso;
++	err = gpio_request(pdata->pin_cs, "spi_cs");
++	if (err)
++		goto err_request_cs;
++
++	sp->bitbang.master = spi_master_get(master);
++	sp->bitbang.master->bus_num = -1;
++	sp->bitbang.master->num_chipselect = 1;
++	sp->bitbang.chipselect = spi_gpio_chipselect;
++	sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
++	sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
++	sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
++	sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
++
++	gpio_direction_output(pdata->pin_clk, 0);
++	gpio_direction_output(pdata->pin_mosi, 0);
++	gpio_direction_output(pdata->pin_cs,
++			      pdata->cs_activelow ? 1 : 0);
++	gpio_direction_input(pdata->pin_miso);
++
++	err = spi_bitbang_start(&sp->bitbang);
++	if (err)
++		goto err_no_bitbang;
++	err = pdata->boardinfo_setup(&sp->bi, master,
++				     pdata->boardinfo_setup_data);
++	if (err)
++		goto err_bi_setup;
++	sp->bi.controller_data = sp;
++	spidev = spi_new_device(master, &sp->bi);
++	if (!spidev)
++		goto err_new_dev;
++
++	return 0;
++
++err_new_dev:
++err_bi_setup:
++	spi_bitbang_stop(&sp->bitbang);
++err_no_bitbang:
++	spi_master_put(sp->bitbang.master);
++	gpio_free(pdata->pin_cs);
++err_request_cs:
++	gpio_free(pdata->pin_miso);
++err_request_miso:
++	gpio_free(pdata->pin_mosi);
++err_request_mosi:
++	gpio_free(pdata->pin_clk);
++err_request_clk:
++	kfree(master);
++
++err_alloc_master:
++	return err;
++}
++
++static int spi_gpio_remove(struct platform_device *pdev)
++{
++	struct spi_gpio *sp;
++	struct spi_gpio_platform_data *pdata;
++
++	pdata = pdev->dev.platform_data;
++	sp = platform_get_drvdata(pdev);
++
++	gpio_free(pdata->pin_clk);
++	gpio_free(pdata->pin_mosi);
++	gpio_free(pdata->pin_miso);
++	gpio_free(pdata->pin_cs);
++	spi_bitbang_stop(&sp->bitbang);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++static struct platform_driver spi_gpio_driver = {
++	.driver		= {
++		.name	= SPI_GPIO_PLATDEV_NAME,
++		.owner	= THIS_MODULE,
++	},
++	.probe		= spi_gpio_probe,
++	.remove		= spi_gpio_remove,
++};
++
++int spi_gpio_next_id(void)
++{
++	static atomic_t counter = ATOMIC_INIT(-1);
++
++	return atomic_inc_return(&counter);
++}
++EXPORT_SYMBOL(spi_gpio_next_id);
++
++static int __init spi_gpio_init(void)
++{
++	int err;
++
++	err = platform_driver_register(&spi_gpio_driver);
++	if (err)
++		printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
++
++	return err;
++}
++module_init(spi_gpio_init);
++
++static void __exit spi_gpio_exit(void)
++{
++	platform_driver_unregister(&spi_gpio_driver);
++}
++module_exit(spi_gpio_exit);
++
++MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
++MODULE_AUTHOR("Michael Buesch");
++MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver");
++MODULE_LICENSE("GPL v2");
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -242,6 +242,15 @@ config SPI_IMG_SPFI
+ 	  This enables support for the SPFI master controller found on
+ 	  IMG SoCs.
+ 
++config SPI_GPIO_OLD
++	tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)"
++	depends on SPI_MASTER && GPIOLIB
++	select SPI_BITBANG
++	help
++	  This code is deprecated. Please use the new mainline SPI-GPIO driver.
++
++	  If unsure, say N.
++
+ config SPI_IMX
+ 	tristate "Freescale i.MX SPI controllers"
+ 	depends on ARCH_MXC || COMPILE_TEST
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -41,6 +41,7 @@ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-li
+ obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o
+ obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o
+ obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o
++obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o
+ obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o
+ obj-$(CONFIG_SPI_IMX)			+= spi-imx.o
+ obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
diff --git a/target/linux/generic/patches-4.1/863-gpiommc.patch b/target/linux/generic/patches-4.1/863-gpiommc.patch
new file mode 100644
index 0000000000..a8a8ec6502
--- /dev/null
+++ b/target/linux/generic/patches-4.1/863-gpiommc.patch
@@ -0,0 +1,844 @@
+--- /dev/null
++++ b/drivers/mmc/host/gpiommc.c
+@@ -0,0 +1,609 @@
++/*
++ * Driver an MMC/SD card on a bitbanging GPIO SPI bus.
++ * This module hooks up the mmc_spi and spi_gpio modules and also
++ * provides a configfs interface.
++ *
++ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/module.h>
++#include <linux/mmc/gpiommc.h>
++#include <linux/platform_device.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/configfs.h>
++#include <linux/gpio.h>
++#include <asm/atomic.h>
++
++
++#define PFX				"gpio-mmc: "
++
++
++struct gpiommc_device {
++	struct platform_device *pdev;
++	struct platform_device *spi_pdev;
++	struct spi_board_info boardinfo;
++};
++
++
++MODULE_DESCRIPTION("GPIO based MMC driver");
++MODULE_AUTHOR("Michael Buesch");
++MODULE_LICENSE("GPL");
++
++
++static int gpiommc_boardinfo_setup(struct spi_board_info *bi,
++				   struct spi_master *master,
++				   void *data)
++{
++	struct gpiommc_device *d = data;
++	struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
++
++	/* Bind the SPI master to the MMC-SPI host driver. */
++	strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias));
++
++	bi->max_speed_hz = pdata->max_bus_speed;
++	bi->bus_num = master->bus_num;
++	bi->mode = pdata->mode;
++
++	return 0;
++}
++
++static int gpiommc_probe(struct platform_device *pdev)
++{
++	struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data;
++	struct spi_gpio_platform_data spi_pdata;
++	struct gpiommc_device *d;
++	int err;
++
++	err = -ENXIO;
++	if (!mmc_pdata)
++		goto error;
++
++#ifdef CONFIG_MMC_SPI_MODULE
++	err = request_module("mmc_spi");
++	if (err) {
++		printk(KERN_WARNING PFX
++		       "Failed to request mmc_spi module.\n");
++	}
++#endif /* CONFIG_MMC_SPI_MODULE */
++
++	/* Allocate the GPIO-MMC device */
++	err = -ENOMEM;
++	d = kzalloc(sizeof(*d), GFP_KERNEL);
++	if (!d)
++		goto error;
++	d->pdev = pdev;
++
++	/* Create the SPI-GPIO device */
++	d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME,
++					    spi_gpio_next_id());
++	if (!d->spi_pdev)
++		goto err_free_d;
++
++	memset(&spi_pdata, 0, sizeof(spi_pdata));
++	spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk;
++	spi_pdata.pin_miso = mmc_pdata->pins.gpio_do;
++	spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di;
++	spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs;
++	spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow;
++	spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay;
++	spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup;
++	spi_pdata.boardinfo_setup_data = d;
++
++	err = platform_device_add_data(d->spi_pdev, &spi_pdata,
++				       sizeof(spi_pdata));
++	if (err)
++		goto err_free_pdev;
++	err = platform_device_add(d->spi_pdev);
++	if (err)
++		goto err_free_pdata;
++	platform_set_drvdata(pdev, d);
++
++	printk(KERN_INFO PFX "MMC-Card \"%s\" "
++	       "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n",
++	       mmc_pdata->name, mmc_pdata->pins.gpio_di,
++	       mmc_pdata->pins.gpio_do,
++	       mmc_pdata->pins.gpio_clk,
++	       mmc_pdata->pins.gpio_cs);
++
++	return 0;
++
++err_free_pdata:
++	kfree(d->spi_pdev->dev.platform_data);
++	d->spi_pdev->dev.platform_data = NULL;
++err_free_pdev:
++	platform_device_put(d->spi_pdev);
++err_free_d:
++	kfree(d);
++error:
++	return err;
++}
++
++static int gpiommc_remove(struct platform_device *pdev)
++{
++	struct gpiommc_device *d = platform_get_drvdata(pdev);
++	struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
++
++	platform_device_unregister(d->spi_pdev);
++	printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n",
++	       pdata->name);
++	platform_device_put(d->spi_pdev);
++
++	return 0;
++}
++
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++
++/* A device that was created through configfs */
++struct gpiommc_configfs_device {
++	struct config_item item;
++	/* The platform device, after registration. */
++	struct platform_device *pdev;
++	/* The configuration */
++	struct gpiommc_platform_data pdata;
++};
++
++#define GPIO_INVALID	-1
++
++static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev)
++{
++	return (dev->pdev != NULL);
++}
++
++static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item)
++{
++	return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL;
++}
++
++static struct configfs_attribute gpiommc_attr_DI = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_data_in",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_DO = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_data_out",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CLK = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_clock",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CS = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_chipselect",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CS_activelow = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_chipselect_activelow",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_spimode = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "spi_mode",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_spidelay = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "spi_delay",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_max_bus_speed = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "max_bus_speed",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_register = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "register",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute *gpiommc_config_attrs[] = {
++	&gpiommc_attr_DI,
++	&gpiommc_attr_DO,
++	&gpiommc_attr_CLK,
++	&gpiommc_attr_CS,
++	&gpiommc_attr_CS_activelow,
++	&gpiommc_attr_spimode,
++	&gpiommc_attr_spidelay,
++	&gpiommc_attr_max_bus_speed,
++	&gpiommc_attr_register,
++	NULL,
++};
++
++static ssize_t gpiommc_config_attr_show(struct config_item *item,
++					struct configfs_attribute *attr,
++					char *page)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++	ssize_t count = 0;
++	unsigned int gpio;
++	int err = 0;
++
++	if (attr == &gpiommc_attr_DI) {
++		gpio = dev->pdata.pins.gpio_di;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_DO) {
++		gpio = dev->pdata.pins.gpio_do;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CLK) {
++		gpio = dev->pdata.pins.gpio_clk;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS) {
++		gpio = dev->pdata.pins.gpio_cs;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS_activelow) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.pins.cs_activelow);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spimode) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.mode);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spidelay) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 !dev->pdata.no_spi_delay);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_max_bus_speed) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.max_bus_speed);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_register) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 gpiommc_is_registered(dev));
++		goto out;
++	}
++	WARN_ON(1);
++	err = -ENOSYS;
++out:
++	return err ? err : count;
++}
++
++static int gpiommc_do_register(struct gpiommc_configfs_device *dev,
++			       const char *name)
++{
++	int err;
++
++	if (gpiommc_is_registered(dev))
++		return 0;
++
++	if (!gpio_is_valid(dev->pdata.pins.gpio_di) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_do) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_clk) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_cs)) {
++		printk(KERN_ERR PFX
++		       "configfs: Invalid GPIO pin number(s)\n");
++		return -EINVAL;
++	}
++
++	strlcpy(dev->pdata.name, name,
++		sizeof(dev->pdata.name));
++
++	dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME,
++					  gpiommc_next_id());
++	if (!dev->pdev)
++		return -ENOMEM;
++	err = platform_device_add_data(dev->pdev, &dev->pdata,
++				       sizeof(dev->pdata));
++	if (err) {
++		platform_device_put(dev->pdev);
++		return err;
++	}
++	err = platform_device_add(dev->pdev);
++	if (err) {
++		platform_device_put(dev->pdev);
++		return err;
++	}
++
++	return 0;
++}
++
++static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev)
++{
++	if (!gpiommc_is_registered(dev))
++		return;
++
++	platform_device_unregister(dev->pdev);
++	dev->pdev = NULL;
++}
++
++static ssize_t gpiommc_config_attr_store(struct config_item *item,
++					 struct configfs_attribute *attr,
++					 const char *page, size_t count)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++	int err = -EINVAL;
++	unsigned long data;
++
++	if (attr == &gpiommc_attr_register) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data == 1)
++			err = gpiommc_do_register(dev, item->ci_name);
++		if (data == 0) {
++			gpiommc_do_unregister(dev);
++			err = 0;
++		}
++		goto out;
++	}
++
++	if (gpiommc_is_registered(dev)) {
++		/* The rest of the config parameters can only be set
++		 * as long as the device is not registered, yet. */
++		err = -EBUSY;
++		goto out;
++	}
++
++	if (attr == &gpiommc_attr_DI) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_di = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_DO) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_do = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CLK) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_clk = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_cs = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS_activelow) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data != 0 && data != 1)
++			goto out;
++		dev->pdata.pins.cs_activelow = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spimode) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		switch (data) {
++		case 0:
++			dev->pdata.mode = SPI_MODE_0;
++			break;
++		case 1:
++			dev->pdata.mode = SPI_MODE_1;
++			break;
++		case 2:
++			dev->pdata.mode = SPI_MODE_2;
++			break;
++		case 3:
++			dev->pdata.mode = SPI_MODE_3;
++			break;
++		default:
++			goto out;
++		}
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spidelay) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data != 0 && data != 1)
++			goto out;
++		dev->pdata.no_spi_delay = !data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_max_bus_speed) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data > UINT_MAX)
++			goto out;
++		dev->pdata.max_bus_speed = data;
++		err = 0;
++		goto out;
++	}
++	WARN_ON(1);
++	err = -ENOSYS;
++out:
++	return err ? err : count;
++}
++
++static void gpiommc_config_item_release(struct config_item *item)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++
++	kfree(dev);
++}
++
++static struct configfs_item_operations gpiommc_config_item_ops = {
++	.release		= gpiommc_config_item_release,
++	.show_attribute		= gpiommc_config_attr_show,
++	.store_attribute	= gpiommc_config_attr_store,
++};
++
++static struct config_item_type gpiommc_dev_ci_type = {
++	.ct_item_ops	= &gpiommc_config_item_ops,
++	.ct_attrs	= gpiommc_config_attrs,
++	.ct_owner	= THIS_MODULE,
++};
++
++static struct config_item *gpiommc_make_item(struct config_group *group,
++					     const char *name)
++{
++	struct gpiommc_configfs_device *dev;
++
++	if (strlen(name) > GPIOMMC_MAX_NAMELEN) {
++		printk(KERN_ERR PFX "configfs: device name too long\n");
++		return NULL;
++	}
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++	if (!dev)
++		return NULL;
++
++	config_item_init_type_name(&dev->item, name,
++				   &gpiommc_dev_ci_type);
++
++	/* Assign default configuration */
++	dev->pdata.pins.gpio_di = GPIO_INVALID;
++	dev->pdata.pins.gpio_do = GPIO_INVALID;
++	dev->pdata.pins.gpio_clk = GPIO_INVALID;
++	dev->pdata.pins.gpio_cs = GPIO_INVALID;
++	dev->pdata.pins.cs_activelow = 1;
++	dev->pdata.mode = SPI_MODE_0;
++	dev->pdata.no_spi_delay = 0;
++	dev->pdata.max_bus_speed = 5000000; /* 5 MHz */
++
++	return &(dev->item);
++}
++
++static void gpiommc_drop_item(struct config_group *group,
++			      struct config_item *item)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++
++	gpiommc_do_unregister(dev);
++	kfree(dev);
++}
++
++static struct configfs_group_operations gpiommc_ct_group_ops = {
++	.make_item	= gpiommc_make_item,
++	.drop_item	= gpiommc_drop_item,
++};
++
++static struct config_item_type gpiommc_ci_type = {
++	.ct_group_ops	= &gpiommc_ct_group_ops,
++	.ct_owner	= THIS_MODULE,
++};
++
++static struct configfs_subsystem gpiommc_subsys = {
++	.su_group = {
++		.cg_item = {
++			.ci_namebuf = GPIOMMC_PLATDEV_NAME,
++			.ci_type = &gpiommc_ci_type,
++		},
++	},
++	.su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex),
++};
++
++#endif /* CONFIG_GPIOMMC_CONFIGFS */
++
++static struct platform_driver gpiommc_plat_driver = {
++	.probe	= gpiommc_probe,
++	.remove	= gpiommc_remove,
++	.driver	= {
++		.name	= GPIOMMC_PLATDEV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++int gpiommc_next_id(void)
++{
++	static atomic_t counter = ATOMIC_INIT(-1);
++
++	return atomic_inc_return(&counter);
++}
++EXPORT_SYMBOL(gpiommc_next_id);
++
++static int __init gpiommc_modinit(void)
++{
++	int err;
++
++	err = platform_driver_register(&gpiommc_plat_driver);
++	if (err)
++		return err;
++
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++	config_group_init(&gpiommc_subsys.su_group);
++	err = configfs_register_subsystem(&gpiommc_subsys);
++	if (err) {
++		platform_driver_unregister(&gpiommc_plat_driver);
++		return err;
++	}
++#endif /* CONFIG_GPIOMMC_CONFIGFS */
++
++	return 0;
++}
++module_init(gpiommc_modinit);
++
++static void __exit gpiommc_modexit(void)
++{
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++	configfs_unregister_subsystem(&gpiommc_subsys);
++#endif
++	platform_driver_unregister(&gpiommc_plat_driver);
++}
++module_exit(gpiommc_modexit);
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -556,6 +556,31 @@ config MMC_SDHI
+ 	  This provides support for the SDHI SD/SDIO controller found in
+ 	  SuperH and ARM SH-Mobile SoCs
+ 
++config GPIOMMC
++	tristate "MMC/SD over GPIO-based SPI"
++	depends on MMC && MMC_SPI && SPI_GPIO_OLD
++	help
++	  This driver hooks up the mmc_spi and spi_gpio modules so that
++	  MMC/SD cards can be used on a GPIO based bus by bitbanging
++	  the SPI protocol in software.
++
++	  This driver provides a configfs interface to dynamically create
++	  and destroy GPIO-based MMC/SD card devices. It also provides
++	  a platform device interface API.
++	  See Documentation/gpiommc.txt for details.
++
++	  The module will be called gpiommc.
++
++	  If unsure, say N.
++
++config GPIOMMC_CONFIGFS
++	bool
++	depends on GPIOMMC && CONFIGFS_FS
++	default y
++	help
++	  This option automatically enables configfs support for gpiommc
++	  if configfs is available.
++
+ config MMC_CB710
+ 	tristate "ENE CB710 MMC/SD Interface support"
+ 	depends on PCI
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -40,6 +40,7 @@ tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_S
+ obj-$(CONFIG_MMC_SDHI)		+= sh_mobile_sdhi.o
+ obj-$(CONFIG_MMC_CB710)		+= cb710-mmc.o
+ obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
++obj-$(CONFIG_GPIOMMC)		+= gpiommc.o
+ obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
+ obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
+ obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
+--- /dev/null
++++ b/include/linux/mmc/gpiommc.h
+@@ -0,0 +1,71 @@
++/*
++ * Device driver for MMC/SD cards driven over a GPIO bus.
++ *
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * Licensed under the GNU/GPL version 2.
++ */
++#ifndef LINUX_GPIOMMC_H_
++#define LINUX_GPIOMMC_H_
++
++#include <linux/types.h>
++
++
++#define GPIOMMC_MAX_NAMELEN		15
++#define GPIOMMC_MAX_NAMELEN_STR		__stringify(GPIOMMC_MAX_NAMELEN)
++
++/**
++ * struct gpiommc_pins - Hardware pin assignments
++ *
++ * @gpio_di: The GPIO number of the DATA IN pin
++ * @gpio_do: The GPIO number of the DATA OUT pin
++ * @gpio_clk: The GPIO number of the CLOCK pin
++ * @gpio_cs: The GPIO number of the CHIPSELECT pin
++ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low.
++ */
++struct gpiommc_pins {
++	unsigned int gpio_di;
++	unsigned int gpio_do;
++	unsigned int gpio_clk;
++	unsigned int gpio_cs;
++	bool cs_activelow;
++};
++
++/**
++ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device.
++ *
++ * @name: The unique name string of the device.
++ * @pins: The hardware pin assignments.
++ * @mode: The hardware mode. This is either SPI_MODE_0,
++ *        SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation.
++ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code.
++ *                This is not standards compliant, but may be required for some
++ *                embedded machines to gain reasonable speed.
++ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz.
++ */
++struct gpiommc_platform_data {
++	char name[GPIOMMC_MAX_NAMELEN + 1];
++	struct gpiommc_pins pins;
++	u8 mode;
++	bool no_spi_delay;
++	unsigned int max_bus_speed;
++};
++
++/**
++ * GPIOMMC_PLATDEV_NAME - The platform device name string.
++ *
++ * The name string that has to be used for platform_device_alloc
++ * when allocating a gpiommc device.
++ */
++#define GPIOMMC_PLATDEV_NAME	"gpiommc"
++
++/**
++ * gpiommc_next_id - Get another platform device ID number.
++ *
++ * This returns the next platform device ID number that has to be used
++ * for platform_device_alloc. The ID is opaque and should not be used for
++ * anything else.
++ */
++int gpiommc_next_id(void);
++
++#endif /* LINUX_GPIOMMC_H_ */
+--- /dev/null
++++ b/Documentation/gpiommc.txt
+@@ -0,0 +1,97 @@
++GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus
++================================================================
++
++The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an
++MMC or SD card on GPIO pins.
++
++Two interfaces for registering a new MMC/SD card device are provided:
++A static platform-device based mechanism and a dynamic configfs based interface.
++
++
++Registering devices via platform-device
++=======================================
++
++The platform-device interface is used for registering MMC/SD devices that are
++part of the hardware platform. This is most useful only for embedded machines
++with MMC/SD devices statically connected to the platform GPIO bus.
++
++The data structures are declared in <linux/mmc/gpiommc.h>.
++
++To register a new device, define an instance of struct gpiommc_platform_data.
++This structure holds any information about how the device is hooked up to the
++GPIO pins and what hardware modes the device supports. See the docbook-style
++documentation in the header file for more information on the struct fields.
++
++Then allocate a new instance of a platform device by doing:
++
++	pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id());
++
++This will allocate the platform device data structures and hook it up to the
++gpiommc driver.
++Then add the gpiommc_platform_data to the platform device.
++
++	err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data));
++
++You may free the local instance of struct gpiommc_platform_data now. (So the
++struct may be allocated on the stack, too).
++Now simply register the platform device.
++
++	err = platform_device_add(pdev);
++
++Done. The gpiommc probe routine will be invoked now and you should see a kernel
++log message for the added device.
++
++
++Registering devices via configfs
++================================
++
++MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example
++selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded
++hardware are a common situation.
++So we provide a dynamic interface to conveniently handle adding and removing
++devices from userspace, without the need to recompile the kernel.
++
++The "gpiommc" subdirectory at the configfs mountpoint is used for handling
++the dynamic configuration.
++
++To create a new device, it must first be allocated with mkdir.
++The following command will allocate a device named "my_mmc":
++	mkdir /config/gpiommc/my_mmc
++
++There are several configuration files available in the new
++/config/gpiommc/my_mmc/ directory:
++
++gpio_data_in			= The SPI data-IN GPIO pin number.
++gpio_data_out			= The SPI data-OUT GPIO pin number.
++gpio_clock			= The SPI Clock GPIO pin number.
++gpio_chipselect			= The SPI Chipselect GPIO pin number.
++gpio_chipselect_activelow	= Boolean. If 0, Chipselect is active-HIGH.
++				  If 1, Chipselect is active-LOW.
++spi_mode			= The SPI data mode. Can be 0-3.
++spi_delay			= Enable all delays in the lowlevel bitbanging.
++max_bus_speed			= The maximum SPI bus speed. In Hertz.
++
++register			= Not a configuration parameter.
++				  Used to register the configured card
++				  with the kernel.
++
++The device must first get configured and then registered by writing "1" to
++the "register" file.
++The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock"
++and "gpio_chipselect" are essential and _must_ be configured before writing
++"1" to the "register" file. The registration will fail, otherwise.
++
++The default values for the other parameters are:
++gpio_chipselect_activelow	= 1		(CS active-LOW)
++spi_mode			= 0		(SPI_MODE_0)
++spi_delay			= 1		(enabled)
++max_bus_speed			= 5000000	(5 Mhz)
++
++Configuration values can not be changed after registration. To unregister
++the device, write a "0" to the "register" file. The configuration can be
++changed again after unregistering.
++
++To completely remove the device, simply rmdir the directory
++(/config/gpiommc/my_mmc in this example).
++There's no need to first unregister the device before removing it. That will
++be done automatically.
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4541,6 +4541,11 @@ T:	git git://linuxtv.org/anttip/media_tr
+ S:	Maintained
+ F:	drivers/media/usb/hackrf/
+ 
++GPIOMMC DRIVER
++P:	Michael Buesch
++M:	mb@bu3sch.de
++S:	Maintained
++
+ HARDWARE MONITORING
+ M:	Jean Delvare <jdelvare@suse.de>
+ M:	Guenter Roeck <linux@roeck-us.net>
diff --git a/target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch b/target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch
new file mode 100644
index 0000000000..92815d91f4
--- /dev/null
+++ b/target/linux/generic/patches-4.1/864-gpiommc_configfs_locking.patch
@@ -0,0 +1,58 @@
+The gpiommc configfs context structure needs locking, as configfs
+does not lock access between files.
+
+--- a/drivers/mmc/host/gpiommc.c
++++ b/drivers/mmc/host/gpiommc.c
+@@ -144,6 +144,8 @@ struct gpiommc_configfs_device {
+ 	struct platform_device *pdev;
+ 	/* The configuration */
+ 	struct gpiommc_platform_data pdata;
++	/* Mutex to protect this structure */
++	struct mutex mutex;
+ };
+ 
+ #define GPIO_INVALID	-1
+@@ -234,6 +236,8 @@ static ssize_t gpiommc_config_attr_show(
+ 	unsigned int gpio;
+ 	int err = 0;
+ 
++	mutex_lock(&dev->mutex);
++
+ 	if (attr == &gpiommc_attr_DI) {
+ 		gpio = dev->pdata.pins.gpio_di;
+ 		if (gpio == GPIO_INVALID)
+@@ -294,6 +298,8 @@ static ssize_t gpiommc_config_attr_show(
+ 	WARN_ON(1);
+ 	err = -ENOSYS;
+ out:
++	mutex_unlock(&dev->mutex);
++
+ 	return err ? err : count;
+ }
+ 
+@@ -353,6 +359,8 @@ static ssize_t gpiommc_config_attr_store
+ 	int err = -EINVAL;
+ 	unsigned long data;
+ 
++	mutex_lock(&dev->mutex);
++
+ 	if (attr == &gpiommc_attr_register) {
+ 		err = kstrtoul(page, 10, &data);
+ 		if (err)
+@@ -478,6 +486,8 @@ static ssize_t gpiommc_config_attr_store
+ 	WARN_ON(1);
+ 	err = -ENOSYS;
+ out:
++	mutex_unlock(&dev->mutex);
++
+ 	return err ? err : count;
+ }
+ 
+@@ -514,6 +524,7 @@ static struct config_item *gpiommc_make_
+ 	if (!dev)
+ 		return NULL;
+ 
++	mutex_init(&dev->mutex);
+ 	config_item_init_type_name(&dev->item, name,
+ 				   &gpiommc_dev_ci_type);
+ 
diff --git a/target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch b/target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch
new file mode 100644
index 0000000000..3a37c951ec
--- /dev/null
+++ b/target/linux/generic/patches-4.1/870-hifn795x_byteswap.patch
@@ -0,0 +1,17 @@
+--- a/drivers/crypto/hifn_795x.c
++++ b/drivers/crypto/hifn_795x.c
+@@ -682,12 +682,12 @@ static inline u32 hifn_read_1(struct hif
+ 
+ static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
+ {
+-	writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg);
++	writel(val, dev->bar[0] + reg);
+ }
+ 
+ static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
+ {
+-	writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg);
++	writel(val, dev->bar[1] + reg);
+ }
+ 
+ static void hifn_wait_puc(struct hifn_device *dev)
diff --git a/target/linux/generic/patches-4.1/880-gateworks_system_controller.patch b/target/linux/generic/patches-4.1/880-gateworks_system_controller.patch
new file mode 100644
index 0000000000..265772309b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/880-gateworks_system_controller.patch
@@ -0,0 +1,339 @@
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -507,6 +507,15 @@ config SENSORS_G762
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called g762.
+ 
++config SENSORS_GSC
++	tristate "Gateworks System Controller"
++	depends on I2C
++	help
++	  If you say yes here you get support for the Gateworks System Controller.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called gsc.
++
+ config SENSORS_GPIO_FAN
+ 	tristate "GPIO fan"
+ 	depends on GPIOLIB
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -156,6 +156,7 @@ obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l7
+ obj-$(CONFIG_SENSORS_W83L786NG)	+= w83l786ng.o
+ obj-$(CONFIG_SENSORS_WM831X)	+= wm831x-hwmon.o
+ obj-$(CONFIG_SENSORS_WM8350)	+= wm8350-hwmon.o
++obj-$(CONFIG_SENSORS_GSC)	+= gsc.o
+ 
+ obj-$(CONFIG_PMBUS)		+= pmbus/
+ 
+--- /dev/null
++++ b/drivers/hwmon/gsc.c
+@@ -0,0 +1,308 @@
++/*
++ * A hwmon driver for the Gateworks System Controller 
++ * Copyright (C) 2009 Gateworks Corporation
++ *
++ * Author: Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License,
++ * as published by the Free Software Foundation - version 2.
++ */
++
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++
++#define DRV_VERSION "0.2"
++
++enum chips { gsp };
++
++/* AD7418 registers */
++#define GSP_REG_TEMP_IN		0x00
++#define GSP_REG_VIN		0x02
++#define GSP_REG_3P3		0x05
++#define GSP_REG_BAT		0x08
++#define GSP_REG_5P0		0x0b
++#define GSP_REG_CORE		0x0e
++#define GSP_REG_CPU1		0x11
++#define GSP_REG_CPU2		0x14
++#define GSP_REG_DRAM		0x17
++#define GSP_REG_EXT_BAT		0x1a
++#define GSP_REG_IO1		0x1d
++#define GSP_REG_IO2 		0x20
++#define GSP_REG_PCIE		0x23
++#define GSP_REG_CURRENT		0x26
++#define GSP_FAN_0		0x2C
++#define GSP_FAN_1		0x2E
++#define GSP_FAN_2		0x30
++#define GSP_FAN_3		0x32
++#define GSP_FAN_4		0x34
++#define GSP_FAN_5		0x36
++
++struct gsp_sensor_info {
++	const char* name;
++	int reg;
++};
++
++static const struct gsp_sensor_info gsp_sensors[] = {
++	{"temp", GSP_REG_TEMP_IN},
++	{"vin", GSP_REG_VIN},
++	{"3p3", GSP_REG_3P3},
++	{"bat", GSP_REG_BAT},
++	{"5p0", GSP_REG_5P0},
++	{"core", GSP_REG_CORE},
++	{"cpu1", GSP_REG_CPU1},
++	{"cpu2", GSP_REG_CPU2},
++	{"dram", GSP_REG_DRAM},
++	{"ext_bat", GSP_REG_EXT_BAT},
++	{"io1", GSP_REG_IO1},
++	{"io2", GSP_REG_IO2},
++	{"pci2", GSP_REG_PCIE},
++	{"current", GSP_REG_CURRENT},
++	{"fan_point0", GSP_FAN_0},
++	{"fan_point1", GSP_FAN_1},
++	{"fan_point2", GSP_FAN_2},
++	{"fan_point3", GSP_FAN_3},
++	{"fan_point4", GSP_FAN_4},
++	{"fan_point5", GSP_FAN_5},
++};
++
++struct gsp_data {
++	struct device		*hwmon_dev;
++	struct attribute_group	attrs;
++	enum chips		type;
++};
++
++static int gsp_probe(struct i2c_client *client,
++			const struct i2c_device_id *id);
++static int gsp_remove(struct i2c_client *client);
++
++static const struct i2c_device_id gsp_id[] = {
++	{ "gsp", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, gsp_id);
++
++static struct i2c_driver gsp_driver = {
++	.driver = {
++		.name	= "gsp",
++	},
++	.probe		= gsp_probe,
++	.remove		= gsp_remove,
++	.id_table	= gsp_id,
++};
++
++/* All registers are word-sized, except for the configuration registers.
++ * AD7418 uses a high-byte first convention. Do NOT use those functions to
++ * access the configuration registers CONF and CONF2, as they are byte-sized.
++ */
++static inline int gsp_read(struct i2c_client *client, u8 reg)
++{
++	unsigned int adc = 0;
++	if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT)
++	{
++		adc |= i2c_smbus_read_byte_data(client, reg);
++		adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
++		return adc;
++	}
++	else
++	{
++		adc |= i2c_smbus_read_byte_data(client, reg);
++		adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
++		adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16;
++		return adc;
++	}
++}
++
++static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value)
++{
++	i2c_smbus_write_byte_data(client, reg, value & 0xff);
++	i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff));
++	return 1;
++}
++
++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
++			char *buf)
++{
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++	struct i2c_client *client = to_i2c_client(dev);
++	return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg));
++}
++
++static ssize_t show_label(struct device *dev,
++			struct device_attribute *devattr, char *buf)
++{
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++
++	return sprintf(buf, "%s\n", gsp_sensors[attr->index].name);
++}
++
++static ssize_t store_fan(struct device *dev,
++			struct device_attribute *devattr, const char *buf, size_t count)
++{
++	u16 val;
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++	struct i2c_client *client = to_i2c_client(dev);
++	val = simple_strtoul(buf, NULL, 10);
++	gsp_write(client, gsp_sensors[attr->index].reg, val);
++	return count;
++}
++
++static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0);
++
++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1);
++static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1);
++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2);
++static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2);
++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3);
++static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3);
++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4);
++static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4);
++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5);
++static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5);
++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6);
++static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6);
++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7);
++static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7);
++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8);
++static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8);
++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9);
++static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9);
++static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10);
++static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10);
++static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11);
++static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11);
++static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12);
++static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12);
++static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13);
++static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13);
++
++static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14);
++static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15);
++static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16);
++static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17);
++static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18);
++static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19);
++
++static struct attribute *gsp_attributes[] = {
++	&sensor_dev_attr_temp0_input.dev_attr.attr,
++	&sensor_dev_attr_in0_input.dev_attr.attr,
++	&sensor_dev_attr_in1_input.dev_attr.attr,
++	&sensor_dev_attr_in2_input.dev_attr.attr,
++	&sensor_dev_attr_in3_input.dev_attr.attr,
++	&sensor_dev_attr_in4_input.dev_attr.attr,
++	&sensor_dev_attr_in5_input.dev_attr.attr,
++	&sensor_dev_attr_in6_input.dev_attr.attr,
++	&sensor_dev_attr_in7_input.dev_attr.attr,
++	&sensor_dev_attr_in8_input.dev_attr.attr,
++	&sensor_dev_attr_in9_input.dev_attr.attr,
++	&sensor_dev_attr_in10_input.dev_attr.attr,
++	&sensor_dev_attr_in11_input.dev_attr.attr,
++	&sensor_dev_attr_in12_input.dev_attr.attr,
++
++	&sensor_dev_attr_temp0_label.dev_attr.attr,
++	&sensor_dev_attr_in0_label.dev_attr.attr,
++	&sensor_dev_attr_in1_label.dev_attr.attr,
++	&sensor_dev_attr_in2_label.dev_attr.attr,
++	&sensor_dev_attr_in3_label.dev_attr.attr,
++	&sensor_dev_attr_in4_label.dev_attr.attr,
++	&sensor_dev_attr_in5_label.dev_attr.attr,
++	&sensor_dev_attr_in6_label.dev_attr.attr,
++	&sensor_dev_attr_in7_label.dev_attr.attr,
++	&sensor_dev_attr_in8_label.dev_attr.attr,
++	&sensor_dev_attr_in9_label.dev_attr.attr,
++	&sensor_dev_attr_in10_label.dev_attr.attr,
++	&sensor_dev_attr_in11_label.dev_attr.attr,
++	&sensor_dev_attr_in12_label.dev_attr.attr,
++
++	&sensor_dev_attr_fan0_point0.dev_attr.attr,
++	&sensor_dev_attr_fan0_point1.dev_attr.attr,
++	&sensor_dev_attr_fan0_point2.dev_attr.attr,
++	&sensor_dev_attr_fan0_point3.dev_attr.attr,
++	&sensor_dev_attr_fan0_point4.dev_attr.attr,
++	&sensor_dev_attr_fan0_point5.dev_attr.attr,
++	NULL
++};
++
++
++static int gsp_probe(struct i2c_client *client,
++			 const struct i2c_device_id *id)
++{
++	struct i2c_adapter *adapter = client->adapter;
++	struct gsp_data *data;
++	int err;
++
++	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
++					I2C_FUNC_SMBUS_WORD_DATA)) {
++		err = -EOPNOTSUPP;
++		goto exit;
++	}
++
++	if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) {
++		err = -ENOMEM;
++		goto exit;
++	}
++
++	i2c_set_clientdata(client, data);
++
++	data->type = id->driver_data;
++
++	switch (data->type) {
++	case 0:
++		data->attrs.attrs = gsp_attributes;
++		break;
++	}
++
++	dev_info(&client->dev, "%s chip found\n", client->name);
++
++	/* Register sysfs hooks */
++	if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
++		goto exit_free;
++
++	data->hwmon_dev = hwmon_device_register(&client->dev);
++	if (IS_ERR(data->hwmon_dev)) {
++		err = PTR_ERR(data->hwmon_dev);
++		goto exit_remove;
++	}
++
++	return 0;
++
++exit_remove:
++	sysfs_remove_group(&client->dev.kobj, &data->attrs);
++exit_free:
++	kfree(data);
++exit:
++	return err;
++}
++
++static int gsp_remove(struct i2c_client *client)
++{
++	struct gsp_data *data = i2c_get_clientdata(client);
++	hwmon_device_unregister(data->hwmon_dev);
++	sysfs_remove_group(&client->dev.kobj, &data->attrs);
++	kfree(data);
++	return 0;
++}
++
++static int __init gsp_init(void)
++{
++	return i2c_add_driver(&gsp_driver);
++}
++
++static void __exit gsp_exit(void)
++{
++	i2c_del_driver(&gsp_driver);
++}
++
++module_init(gsp_init);
++module_exit(gsp_exit);
++
++MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
++MODULE_DESCRIPTION("GSC HWMON driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
diff --git a/target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch b/target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch
new file mode 100644
index 0000000000..8815e4c644
--- /dev/null
+++ b/target/linux/generic/patches-4.1/890-8250_optional_sysrq.patch
@@ -0,0 +1,24 @@
+--- a/drivers/tty/serial/8250/8250_core.c
++++ b/drivers/tty/serial/8250/8250_core.c
+@@ -16,7 +16,7 @@
+  *  membase is an 'ioremapped' cookie.
+  */
+ 
+-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#if defined(CONFIG_SERIAL_8250_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+ 
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -91,6 +91,10 @@ config SERIAL_8250_CONSOLE
+ 
+ 	  If unsure, say N.
+ 
++config SERIAL_8250_SYSRQ
++	bool "Magic sysrq support on 8250/16550 devices"
++	depends on SERIAL_8250_CONSOLE
++
+ config SERIAL_8250_GSC
+ 	tristate
+ 	depends on SERIAL_8250 && GSC
diff --git a/target/linux/generic/patches-4.1/901-debloat_sock_diag.patch b/target/linux/generic/patches-4.1/901-debloat_sock_diag.patch
new file mode 100644
index 0000000000..071616942f
--- /dev/null
+++ b/target/linux/generic/patches-4.1/901-debloat_sock_diag.patch
@@ -0,0 +1,65 @@
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -89,6 +89,9 @@ source "net/netlabel/Kconfig"
+ 
+ endif # if INET
+ 
++config SOCK_DIAG
++	bool
++
+ config NETWORK_SECMARK
+ 	bool "Security Marking"
+ 	help
+--- a/net/core/Makefile
++++ b/net/core/Makefile
+@@ -9,8 +9,9 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
+ 
+ obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
+ 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
+-			sock_diag.o dev_ioctl.o tso.o
++			dev_ioctl.o tso.o
+ 
++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
+ obj-$(CONFIG_XFRM) += flow.o
+ obj-y += net-sysfs.o
+ obj-$(CONFIG_PROC_FS) += net-procfs.o
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -428,6 +428,7 @@ config INET_LRO
+ 
+ config INET_DIAG
+ 	tristate "INET: socket monitoring interface"
++	select SOCK_DIAG
+ 	default y
+ 	---help---
+ 	  Support for INET (TCP, DCCP, etc) socket monitoring interface used by
+--- a/net/unix/Kconfig
++++ b/net/unix/Kconfig
+@@ -22,6 +22,7 @@ config UNIX
+ config UNIX_DIAG
+ 	tristate "UNIX: socket monitoring interface"
+ 	depends on UNIX
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for UNIX socket monitoring interface used by the ss tool.
+--- a/net/netlink/Kconfig
++++ b/net/netlink/Kconfig
+@@ -13,6 +13,7 @@ config NETLINK_MMAP
+ 
+ config NETLINK_DIAG
+ 	tristate "NETLINK: socket monitoring interface"
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for NETLINK socket monitoring interface used by the ss tool.
+--- a/net/packet/Kconfig
++++ b/net/packet/Kconfig
+@@ -18,6 +18,7 @@ config PACKET
+ config PACKET_DIAG
+ 	tristate "Packet: sockets monitoring interface"
+ 	depends on PACKET
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for PF_PACKET sockets monitoring interface used by the ss tool.
diff --git a/target/linux/generic/patches-4.1/902-debloat_proc.patch b/target/linux/generic/patches-4.1/902-debloat_proc.patch
new file mode 100644
index 0000000000..b0dce818b5
--- /dev/null
+++ b/target/linux/generic/patches-4.1/902-debloat_proc.patch
@@ -0,0 +1,385 @@
+--- a/fs/locks.c
++++ b/fs/locks.c
+@@ -2683,6 +2683,8 @@ static const struct file_operations proc
+ 
+ static int __init proc_locks_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("locks", 0, NULL, &proc_locks_operations);
+ 	return 0;
+ }
+--- a/fs/proc/Kconfig
++++ b/fs/proc/Kconfig
+@@ -71,3 +71,8 @@ config PROC_PAGE_MONITOR
+ 	  /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+ 	  /proc/kpagecount, and /proc/kpageflags. Disabling these
+           interfaces will reduce the size of the kernel by approximately 4kb.
++
++config PROC_STRIPPED
++	default n
++	depends on EXPERT
++	bool "Strip non-essential /proc functionality to reduce code size"
+--- a/fs/proc/consoles.c
++++ b/fs/proc/consoles.c
+@@ -106,6 +106,9 @@ static const struct file_operations proc
+ 
+ static int __init proc_consoles_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	proc_create("consoles", 0, NULL, &proc_consoles_operations);
+ 	return 0;
+ }
+--- a/fs/proc/proc_tty.c
++++ b/fs/proc/proc_tty.c
+@@ -143,7 +143,10 @@ static const struct file_operations proc
+ void proc_tty_register_driver(struct tty_driver *driver)
+ {
+ 	struct proc_dir_entry *ent;
+-		
++
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!driver->driver_name || driver->proc_entry ||
+ 	    !driver->ops->proc_fops)
+ 		return;
+@@ -160,6 +163,9 @@ void proc_tty_unregister_driver(struct t
+ {
+ 	struct proc_dir_entry *ent;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ent = driver->proc_entry;
+ 	if (!ent)
+ 		return;
+@@ -174,6 +180,9 @@ void proc_tty_unregister_driver(struct t
+  */
+ void __init proc_tty_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!proc_mkdir("tty", NULL))
+ 		return;
+ 	proc_mkdir("tty/ldisc", NULL);	/* Preserved: it's userspace visible */
+--- a/kernel/exec_domain.c
++++ b/kernel/exec_domain.c
+@@ -41,6 +41,8 @@ static const struct file_operations exec
+ 
+ static int __init proc_execdomains_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
+ 	return 0;
+ }
+--- a/kernel/irq/proc.c
++++ b/kernel/irq/proc.c
+@@ -327,6 +327,9 @@ void register_irq_proc(unsigned int irq,
+ 	static DEFINE_MUTEX(register_lock);
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
+ 		return;
+ 
+@@ -376,6 +379,9 @@ void unregister_irq_proc(unsigned int ir
+ {
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || !desc->dir)
+ 		return;
+ #ifdef CONFIG_SMP
+@@ -411,6 +417,9 @@ void init_irq_proc(void)
+ 	unsigned int irq;
+ 	struct irq_desc *desc;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	/* create /proc/irq */
+ 	root_irq_dir = proc_mkdir("irq", NULL);
+ 	if (!root_irq_dir)
+--- a/kernel/time/timer_list.c
++++ b/kernel/time/timer_list.c
+@@ -388,6 +388,8 @@ static int __init init_timer_list_procfs
+ {
+ 	struct proc_dir_entry *pe;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	pe = proc_create("timer_list", 0444, NULL, &timer_list_fops);
+ 	if (!pe)
+ 		return -ENOMEM;
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -2683,6 +2683,8 @@ static const struct file_operations proc
+ 
+ static int __init proc_vmalloc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
+ 	return 0;
+ }
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -1528,10 +1528,12 @@ static int __init setup_vmstat(void)
+ 	cpu_notifier_register_done();
+ #endif
+ #ifdef CONFIG_PROC_FS
+-	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
+-	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
++		proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
++		proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
++	}
+ 	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
+-	proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
+ #endif
+ 	return 0;
+ }
+--- a/net/8021q/vlanproc.c
++++ b/net/8021q/vlanproc.c
+@@ -127,6 +127,9 @@ void vlan_proc_cleanup(struct net *net)
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (vn->proc_vlan_conf)
+ 		remove_proc_entry(name_conf, vn->proc_vlan_dir);
+ 
+@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
+ 	if (!vn->proc_vlan_dir)
+ 		goto err;
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -2970,6 +2970,8 @@ static __net_initdata struct pernet_oper
+ 
+ static int __init proto_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	return register_pernet_subsys(&proto_net_ops);
+ }
+ 
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2626,10 +2626,12 @@ static const struct file_operations fib_
+ 
+ int __net_init fib_proc_init(struct net *net)
+ {
+-	if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops))
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops))
+ 		goto out1;
+ 
+-	if (!proc_create("fib_triestat", S_IRUGO, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("fib_triestat", S_IRUGO, net->proc_net,
+ 			 &fib_triestat_fops))
+ 		goto out2;
+ 
+@@ -2639,17 +2641,21 @@ int __net_init fib_proc_init(struct net
+ 	return 0;
+ 
+ out3:
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_triestat", net->proc_net);
+ out2:
+-	remove_proc_entry("fib_trie", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_trie", net->proc_net);
+ out1:
+ 	return -ENOMEM;
+ }
+ 
+ void __net_exit fib_proc_exit(struct net *net)
+ {
+-	remove_proc_entry("fib_trie", net->proc_net);
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("fib_trie", net->proc_net);
++		remove_proc_entry("fib_triestat", net->proc_net);
++	}
+ 	remove_proc_entry("route", net->proc_net);
+ }
+ 
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -535,6 +535,9 @@ static __net_initdata struct pernet_oper
+ 
+ int __init ip_misc_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_proc_ops);
+ }
+ 
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -416,6 +416,9 @@ static struct pernet_operations ip_rt_pr
+ 
+ static int __init ip_rt_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_rt_proc_ops);
+ }
+ 
+--- a/ipc/msg.c
++++ b/ipc/msg.c
+@@ -1040,6 +1040,9 @@ void __init msg_init(void)
+ {
+ 	msg_init_ns(&init_ipc_ns);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ipc_init_proc_interface("sysvipc/msg",
+ 				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
+ 				IPC_MSG_IDS, sysvipc_msg_proc_show);
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -191,6 +191,8 @@ void sem_exit_ns(struct ipc_namespace *n
+ void __init sem_init(void)
+ {
+ 	sem_init_ns(&init_ipc_ns);
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/sem",
+ 				"       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
+ 				IPC_SEM_IDS, sysvipc_sem_proc_show);
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -118,6 +118,8 @@ pure_initcall(ipc_ns_init);
+ 
+ void __init shm_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/shm",
+ #if BITS_PER_LONG <= 32
+ 				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n",
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -121,6 +121,9 @@ void __init ipc_init_proc_interface(cons
+ 	struct proc_dir_entry *pde;
+ 	struct ipc_proc_iface *iface;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ 	if (!iface)
+ 		return;
+--- a/net/core/net-procfs.c
++++ b/net/core/net-procfs.c
+@@ -318,10 +318,12 @@ static int __net_init dev_proc_net_init(
+ 
+ 	if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
+ 		goto out;
+-	if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("softnet_stat", S_IRUGO, net->proc_net,
+ 			 &softnet_seq_fops))
+ 		goto out_dev;
+-	if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
+ 		goto out_softnet;
+ 
+ 	if (wext_proc_init(net))
+@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init(
+ out:
+ 	return rc;
+ out_ptype:
+-	remove_proc_entry("ptype", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("ptype", net->proc_net);
+ out_softnet:
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("softnet_stat", net->proc_net);
+ out_dev:
+ 	remove_proc_entry("dev", net->proc_net);
+ 	goto out;
+@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit
+ {
+ 	wext_proc_exit(net);
+ 
+-	remove_proc_entry("ptype", net->proc_net);
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("ptype", net->proc_net);
++		remove_proc_entry("softnet_stat", net->proc_net);
++	}
+ 	remove_proc_entry("dev", net->proc_net);
+ }
+ 
+--- a/include/net/snmp.h
++++ b/include/net/snmp.h
+@@ -123,6 +123,30 @@ struct linux_xfrm_mib {
+ #define DECLARE_SNMP_STAT(type, name)	\
+ 	extern __typeof__(type) __percpu *name
+ 
++#ifdef CONFIG_PROC_STRIPPED
++#define SNMP_INC_STATS_BH(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_INC_STATS_USER(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_INC_STATS_ATOMIC_LONG(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_INC_STATS(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_DEC_STATS(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_ADD_STATS_BH(mib, field, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_ADD_STATS_USER(mib, field, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_ADD_STATS(mib, field, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_UPD_PO_STATS(mib, basefield, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++
++#else
++
+ #define SNMP_INC_STATS_BH(mib, field)	\
+ 			__this_cpu_inc(mib->mibs[field])
+ 
+@@ -159,8 +183,9 @@ struct linux_xfrm_mib {
+ 		__this_cpu_add(ptr[basefield##OCTETS], addend);	\
+ 	} while (0)
+ 
++#endif
+ 
+-#if BITS_PER_LONG==32
++#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
+ 
+ #define SNMP_ADD_STATS64_BH(mib, field, addend) 			\
+ 	do {								\
diff --git a/target/linux/generic/patches-4.1/903-debloat_direct_io.patch b/target/linux/generic/patches-4.1/903-debloat_direct_io.patch
new file mode 100644
index 0000000000..92e36f0bb1
--- /dev/null
+++ b/target/linux/generic/patches-4.1/903-debloat_direct_io.patch
@@ -0,0 +1,80 @@
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -71,6 +71,11 @@ config FILE_LOCKING
+           for filesystems like NFS and for the flock() system
+           call. Disabling this option saves about 11k.
+ 
++config DIRECT_IO
++	bool "Enable O_DIRECT support" if EXPERT
++	depends on BLOCK
++	default y
++
+ source "fs/notify/Kconfig"
+ 
+ source "fs/quota/Kconfig"
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -14,7 +14,8 @@ obj-y :=	open.o read_write.o file_table.
+ 		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
+ 
+ ifeq ($(CONFIG_BLOCK),y)
+-obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
++obj-y +=	buffer.o block_dev.o mpage.o
++obj-$(CONFIG_DIRECT_IO) += direct-io.o
+ else
+ obj-y +=	no-block.o
+ endif
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2659,6 +2659,7 @@ enum {
+ 	DIO_SKIP_DIO_COUNT = 0x08,
+ };
+ 
++#ifdef CONFIG_DIRECT_IO
+ void dio_end_io(struct bio *bio, int error);
+ 
+ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
+@@ -2666,6 +2667,18 @@ ssize_t __blockdev_direct_IO(struct kioc
+ 			     loff_t offset, get_block_t get_block,
+ 			     dio_iodone_t end_io, dio_submit_t submit_io,
+ 			     int flags);
++#else
++static inline void dio_end_io(struct bio *bio, int error)
++{
++}
++static inline ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
++	struct block_device *bdev, struct iov_iter *iter, loff_t offset,
++	get_block_t get_block, dio_iodone_t end_io,
++	dio_submit_t submit_io,	int flags)
++{
++	return -EOPNOTSUPP;
++}
++#endif
+ 
+ static inline ssize_t blockdev_direct_IO(struct kiocb *iocb,
+ 					 struct inode *inode,
+--- a/fs/fcntl.c
++++ b/fs/fcntl.c
+@@ -52,8 +52,10 @@ static int setfl(int fd, struct file * f
+ 		   arg |= O_NONBLOCK;
+ 
+ 	if (arg & O_DIRECT) {
++#ifdef CONFIG_DIRECT_IO
+ 		if (!filp->f_mapping || !filp->f_mapping->a_ops ||
+ 			!filp->f_mapping->a_ops->direct_IO)
++#endif
+ 				return -EINVAL;
+ 	}
+ 
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -671,7 +671,9 @@ int open_check_o_direct(struct file *f)
+ {
+ 	/* NB: we're sure to have correct a_ops only after f_op->open */
+ 	if (f->f_flags & O_DIRECT) {
++#ifdef CONFIG_DIRECT_IO
+ 		if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
++#endif
+ 			return -EINVAL;
+ 	}
+ 	return 0;
diff --git a/target/linux/generic/patches-4.1/904-debloat_dma_buf.patch b/target/linux/generic/patches-4.1/904-debloat_dma_buf.patch
new file mode 100644
index 0000000000..8aca297377
--- /dev/null
+++ b/target/linux/generic/patches-4.1/904-debloat_dma_buf.patch
@@ -0,0 +1,44 @@
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -229,7 +229,7 @@ config SOC_BUS
+ source "drivers/base/regmap/Kconfig"
+ 
+ config DMA_SHARED_BUFFER
+-	bool
++	tristate
+ 	default n
+ 	select ANON_INODES
+ 	help
+--- a/drivers/dma-buf/Makefile
++++ b/drivers/dma-buf/Makefile
+@@ -1 +1,2 @@
+-obj-y := dma-buf.o fence.o reservation.o seqno-fence.o
++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
++dma-shared-buffer-objs := dma-buf.o fence.o reservation.o seqno-fence.o
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -32,6 +32,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/poll.h>
+ #include <linux/reservation.h>
++#include <linux/module.h>
+ 
+ static inline int is_dma_buf_file(struct file *);
+ 
+@@ -901,4 +902,5 @@ static void __exit dma_buf_deinit(void)
+ {
+ 	dma_buf_uninit_debugfs();
+ }
+-__exitcall(dma_buf_deinit);
++module_exit(dma_buf_deinit);
++MODULE_LICENSE("GPL");
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -1790,6 +1790,7 @@ int wake_up_state(struct task_struct *p,
+ {
+ 	return try_to_wake_up(p, state, 0);
+ }
++EXPORT_SYMBOL_GPL(wake_up_state);
+ 
+ /*
+  * This function clears the sched_dl_entity static params.
diff --git a/target/linux/generic/patches-4.1/910-kobject_uevent.patch b/target/linux/generic/patches-4.1/910-kobject_uevent.patch
new file mode 100644
index 0000000000..a2c935f26b
--- /dev/null
+++ b/target/linux/generic/patches-4.1/910-kobject_uevent.patch
@@ -0,0 +1,21 @@
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -52,6 +52,18 @@ static const char *kobject_actions[] = {
+ 	[KOBJ_OFFLINE] =	"offline",
+ };
+ 
++u64 uevent_next_seqnum(void)
++{
++	u64 seq;
++
++	mutex_lock(&uevent_sock_mutex);
++	seq = ++uevent_seqnum;
++	mutex_unlock(&uevent_sock_mutex);
++
++	return seq;
++}
++EXPORT_SYMBOL_GPL(uevent_next_seqnum);
++
+ /**
+  * kobject_action_type - translate action string to numeric type
+  *
diff --git a/target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch
new file mode 100644
index 0000000000..3afaac1efe
--- /dev/null
+++ b/target/linux/generic/patches-4.1/911-kobject_add_broadcast_uevent.patch
@@ -0,0 +1,65 @@
+--- a/include/linux/kobject.h
++++ b/include/linux/kobject.h
+@@ -32,6 +32,8 @@
+ #define UEVENT_NUM_ENVP			32	/* number of env pointers */
+ #define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */
+ 
++struct sk_buff;
++
+ #ifdef CONFIG_UEVENT_HELPER
+ /* path to the userspace helper executed on an event */
+ extern char uevent_helper[];
+@@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_en
+ int kobject_action_type(const char *buf, size_t count,
+ 			enum kobject_action *type);
+ 
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation);
++
+ #endif /* _KOBJECT_H_ */
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -423,6 +423,43 @@ int add_uevent_var(struct kobj_uevent_en
+ EXPORT_SYMBOL_GPL(add_uevent_var);
+ 
+ #if defined(CONFIG_NET)
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	struct uevent_sock *ue_sk;
++	int err = 0;
++
++	/* send netlink message */
++	mutex_lock(&uevent_sock_mutex);
++	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
++		struct sock *uevent_sock = ue_sk->sk;
++		struct sk_buff *skb2;
++
++		skb2 = skb_clone(skb, allocation);
++		if (!skb2)
++			break;
++
++		err = netlink_broadcast(uevent_sock, skb2, pid, group,
++					allocation);
++		if (err)
++			break;
++	}
++	mutex_unlock(&uevent_sock_mutex);
++
++	kfree_skb(skb);
++	return err;
++}
++#else
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	kfree_skb(skb);
++	return 0;
++}
++#endif
++EXPORT_SYMBOL_GPL(broadcast_uevent);
++
++#if defined(CONFIG_NET)
+ static int uevent_net_init(struct net *net)
+ {
+ 	struct uevent_sock *ue_sk;
diff --git a/target/linux/generic/patches-4.1/921-use_preinit_as_init.patch b/target/linux/generic/patches-4.1/921-use_preinit_as_init.patch
new file mode 100644
index 0000000000..73da5b3a54
--- /dev/null
+++ b/target/linux/generic/patches-4.1/921-use_preinit_as_init.patch
@@ -0,0 +1,12 @@
+--- a/init/main.c
++++ b/init/main.c
+@@ -960,7 +960,8 @@ static int __ref kernel_init(void *unuse
+ 		panic("Requested init %s failed (error %d).",
+ 		      execute_command, ret);
+ 	}
+-	if (!try_to_run_init_process("/sbin/init") ||
++	if (!try_to_run_init_process("/etc/preinit") ||
++	    !try_to_run_init_process("/sbin/init") ||
+ 	    !try_to_run_init_process("/etc/init") ||
+ 	    !try_to_run_init_process("/bin/init") ||
+ 	    !try_to_run_init_process("/bin/sh"))
diff --git a/target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch b/target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch
new file mode 100644
index 0000000000..988de35ce0
--- /dev/null
+++ b/target/linux/generic/patches-4.1/922-always-create-console-node-in-initramfs.patch
@@ -0,0 +1,30 @@
+--- a/scripts/gen_initramfs_list.sh
++++ b/scripts/gen_initramfs_list.sh
+@@ -59,6 +59,18 @@ default_initramfs() {
+ 	EOF
+ }
+ 
++list_openwrt_initramfs() {
++	:
++}
++
++openwrt_initramfs() {
++	# make sure that /dev/console exists
++	cat <<-EOF >> ${output}
++		dir /dev 0755 0 0
++		nod /dev/console 0600 0 0 c 5 1
++	EOF
++}
++
+ filetype() {
+ 	local argv1="$1"
+ 
+@@ -177,6 +189,8 @@ dir_filelist() {
+ 	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+ 		${dep_list}print_mtime "$1"
+ 
++		${dep_list}openwrt_initramfs
++
+ 		echo "${dirlist}" | \
+ 		while read x; do
+ 			${dep_list}parse ${x}
diff --git a/target/linux/generic/patches-4.1/930-crashlog.patch b/target/linux/generic/patches-4.1/930-crashlog.patch
new file mode 100644
index 0000000000..ca6cf11064
--- /dev/null
+++ b/target/linux/generic/patches-4.1/930-crashlog.patch
@@ -0,0 +1,276 @@
+--- /dev/null
++++ b/include/linux/crashlog.h
+@@ -0,0 +1,17 @@
++#ifndef __CRASHLOG_H
++#define __CRASHLOG_H
++
++#ifdef CONFIG_CRASHLOG
++void crashlog_init_bootmem(struct bootmem_data *bdata);
++void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size);
++#else
++static inline void crashlog_init_bootmem(struct bootmem_data *bdata)
++{
++}
++
++static inline void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
++{
++}
++#endif
++
++#endif
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1275,6 +1275,10 @@ config RELAY
+ 
+ 	  If unsure, say N.
+ 
++config CRASHLOG
++	bool "Crash logging"
++	depends on (!NO_BOOTMEM || HAVE_MEMBLOCK) && !(ARM || SPARC || PPC)
++
+ config BLK_DEV_INITRD
+ 	bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
+ 	depends on BROKEN || !FRV
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -98,6 +98,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+ obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
+ obj-$(CONFIG_TORTURE_TEST) += torture.o
++obj-$(CONFIG_CRASHLOG) += crashlog.o
+ 
+ $(obj)/configs.o: $(obj)/config_data.h
+ 
+--- /dev/null
++++ b/kernel/crashlog.c
+@@ -0,0 +1,181 @@
++/*
++ * Crash information logger
++ * Copyright (C) 2010 Felix Fietkau <nbd@nbd.name>
++ *
++ * Based on ramoops.c
++ *   Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/bootmem.h>
++#include <linux/memblock.h>
++#include <linux/debugfs.h>
++#include <linux/crashlog.h>
++#include <linux/kmsg_dump.h>
++#include <linux/module.h>
++#include <linux/pfn.h>
++#include <asm/io.h>
++
++#define CRASHLOG_PAGES	4
++#define CRASHLOG_SIZE	(CRASHLOG_PAGES * PAGE_SIZE)
++#define CRASHLOG_MAGIC	0xa1eedead
++
++/*
++ * Start the log at 1M before the end of RAM, as some boot loaders like
++ * to use the end of the RAM for stack usage and other things
++ * If this fails, fall back to using the last part.
++ */
++#define CRASHLOG_OFFSET	(1024 * 1024)
++
++struct crashlog_data {
++	u32 magic;
++	u32 len;
++	u8 data[];
++};
++
++static struct debugfs_blob_wrapper crashlog_blob;
++static unsigned long crashlog_addr = 0;
++static struct crashlog_data *crashlog_buf;
++static struct kmsg_dumper dump;
++static bool first = true;
++
++extern struct list_head *crashlog_modules;
++
++#ifndef CONFIG_NO_BOOTMEM
++void __init crashlog_init_bootmem(bootmem_data_t *bdata)
++{
++	unsigned long addr;
++
++	if (crashlog_addr)
++		return;
++
++	addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET;
++	if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) {
++		printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr);
++		bdata->node_low_pfn -= CRASHLOG_PAGES;
++		addr = PFN_PHYS(bdata->node_low_pfn);
++	}
++	crashlog_addr = addr;
++}
++#endif
++
++#ifdef CONFIG_HAVE_MEMBLOCK
++void __init_memblock crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
++{
++	if (crashlog_addr)
++		return;
++
++	addr += size - CRASHLOG_OFFSET;
++	if (memblock_reserve(addr, CRASHLOG_SIZE)) {
++		printk("Crashlog failed to allocate RAM at address 0x%lx\n", (unsigned long) addr);
++		return;
++	}
++
++	crashlog_addr = addr;
++}
++#endif
++
++static void __init crashlog_copy(void)
++{
++	if (crashlog_buf->magic != CRASHLOG_MAGIC)
++		return;
++
++	if (!crashlog_buf->len || crashlog_buf->len >
++	    CRASHLOG_SIZE - sizeof(*crashlog_buf))
++		return;
++
++	crashlog_blob.size = crashlog_buf->len;
++	crashlog_blob.data = kmemdup(crashlog_buf->data,
++		crashlog_buf->len, GFP_KERNEL);
++
++	debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob);
++}
++
++static int get_maxlen(void)
++{
++	return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len;
++}
++
++static void crashlog_printf(const char *fmt, ...)
++{
++	va_list args;
++	int len = get_maxlen();
++
++	if (!len)
++		return;
++
++	va_start(args, fmt);
++	crashlog_buf->len += vscnprintf(
++		&crashlog_buf->data[crashlog_buf->len],
++		len, fmt, args);
++	va_end(args);
++}
++
++static void crashlog_do_dump(struct kmsg_dumper *dumper,
++		enum kmsg_dump_reason reason)
++{
++	struct timeval tv;
++	struct module *m;
++	char *buf;
++	size_t len;
++
++	if (!first)
++		crashlog_printf("\n===================================\n");
++
++	do_gettimeofday(&tv);
++	crashlog_printf("Time: %lu.%lu\n",
++		(long)tv.tv_sec, (long)tv.tv_usec);
++
++	if (first) {
++		crashlog_printf("Modules:");
++		list_for_each_entry(m, crashlog_modules, list) {
++			crashlog_printf("\t%s@%p+%x", m->name,
++			m->module_core, m->core_size,
++			m->module_init, m->init_size);
++		}
++		crashlog_printf("\n");
++		first = false;
++	}
++
++	buf = (char *)&crashlog_buf->data[crashlog_buf->len];
++
++	kmsg_dump_get_buffer(dumper, true, buf, get_maxlen(), &len);
++
++	crashlog_buf->len += len;
++}
++
++
++int __init crashlog_init_fs(void)
++{
++	if (!crashlog_addr)
++		return -ENOMEM;
++
++	crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE);
++
++	crashlog_copy();
++
++	crashlog_buf->magic = CRASHLOG_MAGIC;
++	crashlog_buf->len = 0;
++
++	dump.max_reason = KMSG_DUMP_OOPS;
++	dump.dump = crashlog_do_dump;
++	kmsg_dump_register(&dump);
++
++	return 0;
++}
++module_init(crashlog_init_fs);
+--- a/mm/bootmem.c
++++ b/mm/bootmem.c
+@@ -15,6 +15,7 @@
+ #include <linux/export.h>
+ #include <linux/kmemleak.h>
+ #include <linux/range.h>
++#include <linux/crashlog.h>
+ #include <linux/memblock.h>
+ #include <linux/bug.h>
+ #include <linux/io.h>
+@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo
+ 	if (!bdata->node_bootmem_map)
+ 		return 0;
+ 
++	crashlog_init_bootmem(bdata);
+ 	map = bdata->node_bootmem_map;
+ 	start = bdata->node_min_pfn;
+ 	end = bdata->node_low_pfn;
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -104,6 +104,9 @@ static LIST_HEAD(modules);
+ #ifdef CONFIG_KGDB_KDB
+ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+ #endif /* CONFIG_KGDB_KDB */
++#ifdef CONFIG_CRASHLOG
++struct list_head *crashlog_modules = &modules;
++#endif
+ 
+ #ifdef CONFIG_MODULE_SIG
+ #ifdef CONFIG_MODULE_SIG_FORCE
+--- a/mm/memblock.c
++++ b/mm/memblock.c
+@@ -19,6 +19,7 @@
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
+ #include <linux/memblock.h>
++#include <linux/crashlog.h>
+ 
+ #include <asm-generic/sections.h>
+ #include <linux/io.h>
+@@ -477,6 +478,8 @@ static void __init_memblock memblock_ins
+ 	memblock_set_region_node(rgn, nid);
+ 	type->cnt++;
+ 	type->total_size += size;
++	if (type == &memblock.memory && idx == 0)
++		crashlog_init_memblock(base, size);
+ }
+ 
+ /**
diff --git a/target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch
new file mode 100644
index 0000000000..ac13c9e673
--- /dev/null
+++ b/target/linux/generic/patches-4.1/970-remove-unsane-filenames-from-deps_initramfs-list.patch
@@ -0,0 +1,29 @@
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data
+ 	include $(obj)/.initramfs_data.cpio.d
+ endif
+ 
++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
++
+ quiet_cmd_initfs = GEN     $@
+       cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
+ 
+@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra
+ 	initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \
+ 	initramfs_data.cpio
+ # do not try to update files included in initramfs
+-$(deps_initramfs): ;
++$(deps_initramfs_sane): ;
+ 
+-$(deps_initramfs): klibcdirs
++$(deps_initramfs_sane): klibcdirs
+ # We rebuild initramfs_data.cpio if:
+ # 1) Any included file is newer then initramfs_data.cpio
+ # 2) There are changes in which files are included (added or deleted)
+ # 3) If gen_init_cpio are newer than initramfs_data.cpio
+ # 4) arguments to gen_initramfs.sh changes
+-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
++$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
+ 	$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d
+ 	$(call if_changed,initfs)
diff --git a/target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch b/target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch
new file mode 100644
index 0000000000..60ca07e1a2
--- /dev/null
+++ b/target/linux/generic/patches-4.1/980-arm_openwrt_machtypes.patch
@@ -0,0 +1,32 @@
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -1006,3 +1006,29 @@ eco5_bx2		MACH_ECO5_BX2		ECO5_BX2		4572
+ eukrea_cpuimx28sd	MACH_EUKREA_CPUIMX28SD	EUKREA_CPUIMX28SD	4573
+ domotab			MACH_DOMOTAB		DOMOTAB			4574
+ pfla03			MACH_PFLA03		PFLA03			4575
++#
++# Additional mach-types supported by OpenWrt
++#
++wg302v1			MACH_WG302V1		WG302V1			889
++pronghorn		MACH_PRONGHORN		PRONGHORN		928
++pronghorn_metro		MACH_PRONGHORNMETRO	PRONGHORNMETRO		1040
++sidewinder		MACH_SIDEWINDER		SIDEWINDER		1041
++wrt300nv2		MACH_WRT300NV2		WRT300NV2		1077
++compex42x		MACH_COMPEXWP18		COMPEXWP18		1273
++goldfish		MACH_GOLDFISH		GOLDFISH		1441
++cambria			MACH_CAMBRIA		CAMBRIA			1468
++dt2			MACH_DT2		DT2			1514
++ap1000			MACH_AP1000		AP1000			1543
++tw2662			MACH_TW2662		TW2662			1658
++tw5334			MACH_TW5334		TW5334			1664
++usr8200			MACH_USR8200		USR8200			1762
++mi424wr			MACH_MI424WR		MI424WR			1778
++gw2388			MACH_GW2388		GW2388			2635
++iconnect		MACH_ICONNECT		ICONNECT		2870
++nsb3ast			MACH_NSB3AST		NSB3AST			2917
++goflexnet		MACH_GOFLEXNET		GOFLEXNET		3089
++nas6210			MACH_NAS6210		NAS6210			3104
++ns_k330			MACH_NS_K330		NS_K330			3108
++bcm2708			MACH_BCM2708		BCM2708			3138
++wn802t			MACH_WN802T		WN802T			3306
++nsa310			MACH_NSA310		NSA310			4022
diff --git a/target/linux/generic/patches-4.1/995-mangle_bootargs.patch b/target/linux/generic/patches-4.1/995-mangle_bootargs.patch
new file mode 100644
index 0000000000..1062a694a3
--- /dev/null
+++ b/target/linux/generic/patches-4.1/995-mangle_bootargs.patch
@@ -0,0 +1,58 @@
+--- a/init/main.c
++++ b/init/main.c
+@@ -352,6 +352,29 @@ static inline void setup_nr_cpu_ids(void
+ static inline void smp_prepare_cpus(unsigned int maxcpus) { }
+ #endif
+ 
++#ifdef CONFIG_MANGLE_BOOTARGS
++static void __init mangle_bootargs(char *command_line)
++{
++	char *rootdev;
++	char *rootfs;
++
++	rootdev = strstr(command_line, "root=/dev/mtdblock");
++
++	if (rootdev)
++		strncpy(rootdev, "mangled_rootblock=", 18);
++
++	rootfs = strstr(command_line, "rootfstype");
++
++	if (rootfs)
++		strncpy(rootfs, "mangled_fs", 10);
++
++}
++#else
++static void __init mangle_bootargs(char *command_line)
++{
++}
++#endif
++
+ /*
+  * We need to store the untouched command line for future reference.
+  * We also need to store the touched command line since the parameter
+@@ -522,6 +545,7 @@ asmlinkage __visible void __init start_k
+ 	pr_notice("%s", linux_banner);
+ 	setup_arch(&command_line);
+ 	mm_init_cpumask(&init_mm);
++	mangle_bootargs(command_line);
+ 	setup_command_line(command_line);
+ 	setup_nr_cpu_ids();
+ 	setup_per_cpu_areas();
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1607,6 +1607,15 @@ config EMBEDDED
+ 	  an embedded system so certain expert options are available
+ 	  for configuration.
+ 
++config MANGLE_BOOTARGS
++	bool "Rename offending bootargs"
++	depends on EXPERT
++	help
++	  Sometimes the bootloader passed bogus root= and rootfstype=
++	  parameters to the kernel, and while you want to ignore them,
++	  you need to know the values f.e. to support dual firmware
++	  layouts on the flash.
++
+ config HAVE_PERF_EVENTS
+ 	bool
+ 	help
diff --git a/target/linux/generic/patches-4.1/997-device_tree_cmdline.patch b/target/linux/generic/patches-4.1/997-device_tree_cmdline.patch
new file mode 100644
index 0000000000..076cb6d709
--- /dev/null
+++ b/target/linux/generic/patches-4.1/997-device_tree_cmdline.patch
@@ -0,0 +1,24 @@
+--- a/drivers/of/fdt.c
++++ b/drivers/of/fdt.c
+@@ -935,6 +935,9 @@ int __init early_init_dt_scan_chosen(uns
+ 	p = of_get_flat_dt_prop(node, "bootargs", &l);
+ 	if (p != NULL && l > 0)
+ 		strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
++	p = of_get_flat_dt_prop(node, "bootargs-append", &l);
++	if (p != NULL && l > 0)
++		strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
+ 
+ 	/*
+ 	 * CONFIG_CMDLINE is meant to be a default in case nothing else
+--- a/arch/mips/kernel/prom.c
++++ b/arch/mips/kernel/prom.c
+@@ -50,6 +50,9 @@ void * __init early_init_dt_alloc_memory
+ 
+ void __init __dt_setup_arch(void *bph)
+ {
++	if (boot_command_line[0] == '\0')
++		strcpy(boot_command_line, arcs_cmdline);
++
+ 	if (!early_init_dt_scan(bph))
+ 		return;
+ 
diff --git a/target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch b/target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch
new file mode 100644
index 0000000000..d317de1102
--- /dev/null
+++ b/target/linux/generic/patches-4.1/998-enable_wilink_platform_without_drivers.patch
@@ -0,0 +1,15 @@
+We use backports for driver updates - make sure we can compile in the glue code regardless
+
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+
+--- a/drivers/net/wireless/ti/Kconfig
++++ b/drivers/net/wireless/ti/Kconfig
+@@ -15,7 +15,7 @@ source "drivers/net/wireless/ti/wlcore/K
+ 
+ config WILINK_PLATFORM_DATA
+ 	bool "TI WiLink platform data"
+-	depends on WLCORE_SDIO || WL1251_SDIO
++	depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
+ 	default y
+ 	---help---
+ 	Small platform data bit needed to pass data to the sdio modules.
diff --git a/target/linux/generic/patches-4.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch b/target/linux/generic/patches-4.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
new file mode 100644
index 0000000000..f6c9d1edad
--- /dev/null
+++ b/target/linux/generic/patches-4.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 18 Jan 2016 12:27:49 +0100
+Subject: [PATCH] Kbuild: don't hardcode path to awk in scripts/ld-version.sh
+
+On some systems /usr/bin/awk does not exist, or is broken. Find it via
+$PATH instead.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/scripts/ld-version.sh
++++ b/scripts/ld-version.sh
+@@ -1,8 +1,10 @@
+-#!/usr/bin/awk -f
++#!/bin/sh
+ # extract linker version number from stdin and turn into single number
++exec awk '
+ 	{
+ 	gsub(".*\\)", "");
+ 	split($1,a, ".");
+ 	print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5];
+ 	exit
+ 	}
++'
diff --git a/target/linux/generic/patches-4.4/020-bcma-from-4.5.patch b/target/linux/generic/patches-4.4/020-bcma-from-4.5.patch
new file mode 100644
index 0000000000..21ebff58b6
--- /dev/null
+++ b/target/linux/generic/patches-4.4/020-bcma-from-4.5.patch
@@ -0,0 +1,49 @@
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -668,11 +668,36 @@ static int bcma_device_uevent(struct dev
+ 			      core->id.rev, core->id.class);
+ }
+ 
+-static int __init bcma_modinit(void)
++static unsigned int bcma_bus_registered;
++
++/*
++ * If built-in, bus has to be registered early, before any driver calls
++ * bcma_driver_register.
++ * Otherwise registering driver would trigger BUG in driver_register.
++ */
++static int __init bcma_init_bus_register(void)
+ {
+ 	int err;
+ 
++	if (bcma_bus_registered)
++		return 0;
++
+ 	err = bus_register(&bcma_bus_type);
++	if (!err)
++		bcma_bus_registered = 1;
++
++	return err;
++}
++#ifndef MODULE
++fs_initcall(bcma_init_bus_register);
++#endif
++
++/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */
++static int __init bcma_modinit(void)
++{
++	int err;
++
++	err = bcma_init_bus_register();
+ 	if (err)
+ 		return err;
+ 
+@@ -691,7 +716,7 @@ static int __init bcma_modinit(void)
+ 
+ 	return err;
+ }
+-fs_initcall(bcma_modinit);
++module_init(bcma_modinit);
+ 
+ static void __exit bcma_modexit(void)
+ {
diff --git a/target/linux/generic/patches-4.4/021-bcma-from-4.6.patch b/target/linux/generic/patches-4.4/021-bcma-from-4.6.patch
new file mode 100644
index 0000000000..dede2f1f23
--- /dev/null
+++ b/target/linux/generic/patches-4.4/021-bcma-from-4.6.patch
@@ -0,0 +1,761 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -15,6 +15,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ 
++static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++
+ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
+ 					 u32 mask, u32 value)
+ {
+@@ -113,8 +115,37 @@ int bcma_chipco_watchdog_register(struct
+ 	return 0;
+ }
+ 
++static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
++{
++	struct bcma_bus *bus = cc->core->bus;
++
++	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++	case BCMA_CC_FLASHT_STSER:
++	case BCMA_CC_FLASHT_ATSER:
++		bcma_debug(bus, "Found serial flash\n");
++		bcma_sflash_init(cc);
++		break;
++	case BCMA_CC_FLASHT_PARA:
++		bcma_debug(bus, "Found parallel flash\n");
++		bcma_pflash_init(cc);
++		break;
++	default:
++		bcma_err(bus, "Flash type not supported\n");
++	}
++
++	if (cc->core->id.rev == 38 ||
++	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
++		if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
++			bcma_debug(bus, "Found NAND flash\n");
++			bcma_nflash_init(cc);
++		}
++	}
++}
++
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
++
+ 	if (cc->early_setup_done)
+ 		return;
+ 
+@@ -129,6 +160,12 @@ void bcma_core_chipcommon_early_init(str
+ 	if (cc->capabilities & BCMA_CC_CAP_PMU)
+ 		bcma_pmu_early_init(cc);
+ 
++	if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
++		bcma_chipco_serial_init(cc);
++
++	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++		bcma_core_chipcommon_flash_detect(cc);
++
+ 	cc->early_setup_done = true;
+ }
+ 
+@@ -185,11 +222,12 @@ u32 bcma_chipco_watchdog_timer_set(struc
+ 			ticks = 2;
+ 		else if (ticks > maxt)
+ 			ticks = maxt;
+-		bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+ 	} else {
+ 		struct bcma_bus *bus = cc->core->bus;
+ 
+ 		if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
++		    bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
+ 		    bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
+ 			bcma_core_set_clockmode(cc->core,
+ 						ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
+@@ -314,9 +352,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
+ 	return res;
+ }
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+ {
++#if IS_BUILTIN(CONFIG_BCM47XX)
+ 	unsigned int irq;
+ 	u32 baud_base;
+ 	u32 i;
+@@ -358,5 +396,5 @@ void bcma_chipco_serial_init(struct bcma
+ 		ports[i].baud_base = baud_base;
+ 		ports[i].reg_shift = 0;
+ 	}
++#endif /* CONFIG_BCM47XX */
+ }
+-#endif /* CONFIG_BCMA_DRIVER_MIPS */
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -15,44 +15,44 @@
+ 
+ u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
+ 
+ void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
+ 
+ void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ 			     u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
+ 
+ void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ 				 u32 offset, u32 mask, u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
+ 
+ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+ 				u32 set)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
+-	bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
+-	bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
++	bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
++	bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
+ 
+@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma
+ {
+ 	u32 ilp_ctl, alp_hz;
+ 
+-	if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
++	if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
+ 	      BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
+ 		return 0;
+ 
+-	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+-			BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
++	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
++			 BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+ 	usleep_range(1000, 2000);
+ 
+-	ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
++	ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+ 	ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
+ 
+-	bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+ 
+ 	alp_hz = ilp_ctl * 32768 / 4;
+ 	return (alp_hz + 50000) / 100000 * 100;
+@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct b
+ 		mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
+ 			      BCMA_RES_4314_MACPHY_CLK_AVAIL);
+ 
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+ 		bcma_wait_value(cc->core, BCMA_CLKCTLST,
+ 				BCMA_CLKCTLST_HAVEHT, 0, 20000);
+ 		break;
+@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct b
+ 
+ 	/* Flush */
+ 	if (cc->pmu.rev >= 2)
+-		bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
++		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+ 
+ 	/* TODO: Do we need to update OTP? */
+ }
+@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(stru
+ 
+ 	/* Set the resource masks. */
+ 	if (min_msk)
+-		bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+ 	if (max_msk)
+-		bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+ 
+ 	/*
+ 	 * Add some delay; allow resources to come up and settle.
+@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct
+ 
+ void bcma_pmu_early_init(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
+ 	u32 pmucap;
+ 
+-	pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
++	if (cc->core->id.rev >= 35 &&
++	    cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
++		cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
++		if (!cc->pmu.core)
++			bcma_warn(bus, "Couldn't find expected PMU core");
++	}
++	if (!cc->pmu.core)
++		cc->pmu.core = cc->core;
++
++	pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
+ 	cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
+ 
+-	bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
+-		   cc->pmu.rev, pmucap);
++	bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
++		   pmucap);
+ }
+ 
+ void bcma_pmu_init(struct bcma_drv_cc *cc)
+ {
+ 	if (cc->pmu.rev == 1)
+-		bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
+-			      ~BCMA_CC_PMU_CTL_NOILPONW);
++		bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
++				~BCMA_CC_PMU_CTL_NOILPONW);
+ 	else
+-		bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+-			     BCMA_CC_PMU_CTL_NOILPONW);
++		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
++			       BCMA_CC_PMU_CTL_NOILPONW);
+ 
+ 	bcma_pmu_pll_init(cc);
+ 	bcma_pmu_resources_init(cc);
+@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
+ static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ 					 u32 value)
+ {
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+-	bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
+ }
+ 
+ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
+@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct
+ 		       bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
+ 
+ 		/* RMW only the P1 divider */
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
+ 				BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
+-		tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ 		tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
+ 		tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
+ 
+ 		/* RMW only the int feedback divider */
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
+ 				BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
+-		tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
+ 		tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
+ 		tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
+-		bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
++		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
+ 
+ 		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
+ 		break;
+@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
+ 		break;
+ 	}
+ 
+-	tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
+-	bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
++	tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
++	bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
+ }
+ EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bc
+ 	{ "M25P32", 0x15, 0x10000, 64, },
+ 	{ "M25P64", 0x16, 0x10000, 128, },
+ 	{ "M25FL128", 0x17, 0x10000, 256, },
++	{ "MX25L25635F", 0x18, 0x10000, 512, },
+ 	{ NULL },
+ };
+ 
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -98,6 +98,9 @@ static const struct bcma_device_id_name
+ 	{ BCMA_CORE_SHIM, "SHIM" },
+ 	{ BCMA_CORE_PCIE2, "PCIe Gen2" },
+ 	{ BCMA_CORE_ARM_CR4, "ARM CR4" },
++	{ BCMA_CORE_GCI, "GCI" },
++	{ BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
++	{ BCMA_CORE_ARM_CA7, "ARM CA7" },
+ 	{ BCMA_CORE_DEFAULT, "Default" },
+ };
+ 
+@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcm
+ 		switch (core->id.id) {
+ 		case BCMA_CORE_4706_MAC_GBIT_COMMON:
+ 		case BCMA_CORE_NS_CHIPCOMMON_B:
++		case BCMA_CORE_PMU:
++		case BCMA_CORE_GCI:
+ 		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
+ 			break;
+ 		default:
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(str
+ 	case B43_BUS_BCMA:
+ 		bcma_cc = &dev->dev->bdev->bus->drv_cc;
+ 
+-		bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
+-		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+-		bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
+-		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
++		bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
++		bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
++		bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
++		bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
+ 		break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -151,6 +151,8 @@ struct bcma_host_ops {
+ #define BCMA_CORE_PCIE2			0x83C	/* PCI Express Gen2 */
+ #define BCMA_CORE_USB30_DEV		0x83D
+ #define BCMA_CORE_ARM_CR4		0x83E
++#define BCMA_CORE_GCI			0x840
++#define BCMA_CORE_CMEM			0x846	/* CNDS DDR2/3 memory controller */
+ #define BCMA_CORE_ARM_CA7		0x847
+ #define BCMA_CORE_SYS_MEM		0x849
+ #define BCMA_CORE_DEFAULT		0xFFF
+@@ -200,6 +202,7 @@ struct bcma_host_ops {
+ #define  BCMA_PKG_ID_BCM4707	1
+ #define  BCMA_PKG_ID_BCM4708	2
+ #define  BCMA_PKG_ID_BCM4709	0
++#define BCMA_CHIP_ID_BCM47094	53030
+ #define BCMA_CHIP_ID_BCM53018	53018
+ 
+ /* Board types (on PCI usually equals to the subsystem dev id) */
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -217,6 +217,11 @@
+ #define	 BCMA_CC_CLKDIV_JTAG_SHIFT	8
+ #define	 BCMA_CC_CLKDIV_UART		0x000000FF
+ #define BCMA_CC_CAP_EXT			0x00AC		/* Capabilities */
++#define  BCMA_CC_CAP_EXT_SECI_PRESENT	0x00000001
++#define  BCMA_CC_CAP_EXT_GSIO_PRESENT	0x00000002
++#define  BCMA_CC_CAP_EXT_GCI_PRESENT	0x00000004
++#define  BCMA_CC_CAP_EXT_SECI_PUART_PRESENT		0x00000008    /* UART present */
++#define  BCMA_CC_CAP_EXT_AOB_PRESENT	0x00000040
+ #define BCMA_CC_PLLONDELAY		0x00B0		/* Rev >= 4 only */
+ #define BCMA_CC_FREFSELDELAY		0x00B4		/* Rev >= 4 only */
+ #define BCMA_CC_SLOWCLKCTL		0x00B8		/* 6 <= Rev <= 9 only */
+@@ -351,12 +356,12 @@
+ #define BCMA_CC_PMU_RES_REQTS		0x0640 /* PMU res req timer sel */
+ #define BCMA_CC_PMU_RES_REQT		0x0644 /* PMU res req timer */
+ #define BCMA_CC_PMU_RES_REQM		0x0648 /* PMU res req mask */
+-#define BCMA_CC_CHIPCTL_ADDR		0x0650
+-#define BCMA_CC_CHIPCTL_DATA		0x0654
+-#define BCMA_CC_REGCTL_ADDR		0x0658
+-#define BCMA_CC_REGCTL_DATA		0x065C
+-#define BCMA_CC_PLLCTL_ADDR		0x0660
+-#define BCMA_CC_PLLCTL_DATA		0x0664
++#define BCMA_CC_PMU_CHIPCTL_ADDR	0x0650
++#define BCMA_CC_PMU_CHIPCTL_DATA	0x0654
++#define BCMA_CC_PMU_REGCTL_ADDR		0x0658
++#define BCMA_CC_PMU_REGCTL_DATA		0x065C
++#define BCMA_CC_PMU_PLLCTL_ADDR		0x0660
++#define BCMA_CC_PMU_PLLCTL_DATA		0x0664
+ #define BCMA_CC_PMU_STRAPOPT		0x0668 /* (corerev >= 28) */
+ #define BCMA_CC_PMU_XTAL_FREQ		0x066C /* (pmurev >= 10) */
+ #define  BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK	0x00001FFF
+@@ -566,17 +571,16 @@
+  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+  */
+ struct bcma_chipcommon_pmu {
++	struct bcma_device *core;	/* Can be separated core or just ChipCommon one */
+ 	u8 rev;			/* PMU revision */
+ 	u32 crystalfreq;	/* The active crystal frequency (in kHz) */
+ };
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ struct bcma_pflash {
+ 	bool present;
+-	u8 buswidth;
+-	u32 window;
+-	u32 window_size;
+ };
++#endif
+ 
+ #ifdef CONFIG_BCMA_SFLASH
+ struct bcma_sflash {
+@@ -602,6 +606,7 @@ struct bcma_nflash {
+ };
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_serial_port {
+ 	void *regs;
+ 	unsigned long clockspeed;
+@@ -621,8 +626,9 @@ struct bcma_drv_cc {
+ 	/* Fast Powerup Delay constant */
+ 	u16 fast_pwrup_delay;
+ 	struct bcma_chipcommon_pmu pmu;
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ 	struct bcma_pflash pflash;
++#endif
+ #ifdef CONFIG_BCMA_SFLASH
+ 	struct bcma_sflash sflash;
+ #endif
+@@ -630,6 +636,7 @@ struct bcma_drv_cc {
+ 	struct bcma_nflash nflash;
+ #endif
+ 
++#ifdef CONFIG_BCMA_DRIVER_MIPS
+ 	int nr_serial_ports;
+ 	struct bcma_serial_port serial_ports[4];
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+@@ -662,6 +669,19 @@ struct bcma_drv_cc_b {
+ #define bcma_cc_maskset32(cc, offset, mask, set) \
+ 	bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+ 
++/* PMU registers access */
++#define bcma_pmu_read32(cc, offset) \
++	bcma_read32((cc)->pmu.core, offset)
++#define bcma_pmu_write32(cc, offset, val) \
++	bcma_write32((cc)->pmu.core, offset, val)
++
++#define bcma_pmu_mask32(cc, offset, mask) \
++	bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
++#define bcma_pmu_set32(cc, offset, set) \
++	bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
++#define bcma_pmu_maskset32(cc, offset, mask, set) \
++	bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
++
+ extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+ 
+ extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -45,10 +45,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
+ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
+-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+-extern struct platform_device bcma_pflash_dev;
+-#endif /* CONFIG_BCMA_DRIVER_MIPS */
+ 
+ /* driver_chipcommon_b.c */
+ int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
+@@ -60,6 +56,21 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
+ 
++/**************************************************
++ * driver_chipcommon_sflash.c
++ **************************************************/
++
++#ifdef CONFIG_BCMA_PFLASH
++extern struct platform_device bcma_pflash_dev;
++int bcma_pflash_init(struct bcma_drv_cc *cc);
++#else
++static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
++{
++	bcma_err(cc->core->bus, "Parallel flash not supported\n");
++	return 0;
++}
++#endif /* CONFIG_BCMA_PFLASH */
++
+ #ifdef CONFIG_BCMA_SFLASH
+ /* driver_chipcommon_sflash.c */
+ int bcma_sflash_init(struct bcma_drv_cc *cc);
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -197,6 +197,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+ 	case BCMA_CHIP_ID_BCM4707:
+ 	case BCMA_CHIP_ID_BCM5357:
+ 	case BCMA_CHIP_ID_BCM53572:
++	case BCMA_CHIP_ID_BCM47094:
+ 		chip->ngpio	= 32;
+ 		break;
+ 	default:
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -14,8 +14,6 @@
+ 
+ #include <linux/bcma/bcma.h>
+ 
+-#include <linux/mtd/physmap.h>
+-#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+@@ -32,26 +30,6 @@ enum bcma_boot_dev {
+ 	BCMA_BOOT_DEV_NAND,
+ };
+ 
+-static const char * const part_probes[] = { "bcm47xxpart", NULL };
+-
+-static struct physmap_flash_data bcma_pflash_data = {
+-	.part_probe_types	= part_probes,
+-};
+-
+-static struct resource bcma_pflash_resource = {
+-	.name	= "bcma_pflash",
+-	.flags  = IORESOURCE_MEM,
+-};
+-
+-struct platform_device bcma_pflash_dev = {
+-	.name		= "physmap-flash",
+-	.dev		= {
+-		.platform_data  = &bcma_pflash_data,
+-	},
+-	.resource	= &bcma_pflash_resource,
+-	.num_resources	= 1,
+-};
+-
+ /* The 47162a0 hangs when reading MIPS DMP registers registers */
+ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+ {
+@@ -272,48 +250,11 @@ static enum bcma_boot_dev bcma_boot_dev(
+ 	return BCMA_BOOT_DEV_SERIAL;
+ }
+ 
+-static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
+ {
+ 	struct bcma_bus *bus = mcore->core->bus;
+-	struct bcma_drv_cc *cc = &bus->drv_cc;
+-	struct bcma_pflash *pflash = &cc->pflash;
+ 	enum bcma_boot_dev boot_dev;
+ 
+-	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+-	case BCMA_CC_FLASHT_STSER:
+-	case BCMA_CC_FLASHT_ATSER:
+-		bcma_debug(bus, "Found serial flash\n");
+-		bcma_sflash_init(cc);
+-		break;
+-	case BCMA_CC_FLASHT_PARA:
+-		bcma_debug(bus, "Found parallel flash\n");
+-		pflash->present = true;
+-		pflash->window = BCMA_SOC_FLASH2;
+-		pflash->window_size = BCMA_SOC_FLASH2_SZ;
+-
+-		if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
+-		     BCMA_CC_FLASH_CFG_DS) == 0)
+-			pflash->buswidth = 1;
+-		else
+-			pflash->buswidth = 2;
+-
+-		bcma_pflash_data.width = pflash->buswidth;
+-		bcma_pflash_resource.start = pflash->window;
+-		bcma_pflash_resource.end = pflash->window + pflash->window_size;
+-
+-		break;
+-	default:
+-		bcma_err(bus, "Flash type not supported\n");
+-	}
+-
+-	if (cc->core->id.rev == 38 ||
+-	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+-		if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
+-			bcma_debug(bus, "Found NAND flash\n");
+-			bcma_nflash_init(cc);
+-		}
+-	}
+-
+ 	/* Determine flash type this SoC boots from */
+ 	boot_dev = bcma_boot_dev(bus);
+ 	switch (boot_dev) {
+@@ -337,13 +278,10 @@ static void bcma_core_mips_flash_detect(
+ 
+ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
+ {
+-	struct bcma_bus *bus = mcore->core->bus;
+-
+ 	if (mcore->early_setup_done)
+ 		return;
+ 
+-	bcma_chipco_serial_init(&bus->drv_cc);
+-	bcma_core_mips_flash_detect(mcore);
++	bcma_core_mips_nvram_init(mcore);
+ 
+ 	mcore->early_setup_done = true;
+ }
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -294,7 +294,8 @@ static const struct pci_device_id bcma_p
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
+-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
++	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
+ 
+ 	  If unsure, say N
+ 
++config BCMA_PFLASH
++	bool
++	depends on BCMA_DRIVER_MIPS
++	default y
++
+ config BCMA_SFLASH
+ 	bool
+ 	depends on BCMA_DRIVER_MIPS
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -1,6 +1,7 @@
+ bcma-y					+= main.o scan.o core.o sprom.o
+ bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
+ bcma-y					+= driver_chipcommon_b.o
++bcma-$(CONFIG_BCMA_PFLASH)		+= driver_chipcommon_pflash.o
+ bcma-$(CONFIG_BCMA_SFLASH)		+= driver_chipcommon_sflash.o
+ bcma-$(CONFIG_BCMA_NFLASH)		+= driver_chipcommon_nflash.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI)		+= driver_pci.o
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_pflash.c
+@@ -0,0 +1,49 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon parallel flash
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++
++static const char * const part_probes[] = { "bcm47xxpart", NULL };
++
++static struct physmap_flash_data bcma_pflash_data = {
++	.part_probe_types	= part_probes,
++};
++
++static struct resource bcma_pflash_resource = {
++	.name	= "bcma_pflash",
++	.flags  = IORESOURCE_MEM,
++};
++
++struct platform_device bcma_pflash_dev = {
++	.name		= "physmap-flash",
++	.dev		= {
++		.platform_data  = &bcma_pflash_data,
++	},
++	.resource	= &bcma_pflash_resource,
++	.num_resources	= 1,
++};
++
++int bcma_pflash_init(struct bcma_drv_cc *cc)
++{
++	struct bcma_pflash *pflash = &cc->pflash;
++
++	pflash->present = true;
++
++	if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
++		bcma_pflash_data.width = 1;
++	else
++		bcma_pflash_data.width = 2;
++
++	bcma_pflash_resource.start = BCMA_SOC_FLASH2;
++	bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
++
++	return 0;
++}
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -136,7 +136,6 @@ static bool bcma_is_core_needed_early(u1
+ 	return false;
+ }
+ 
+-#if defined(CONFIG_OF) && defined(CONFIG_OF_ADDRESS)
+ static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
+ 						     struct bcma_device *core)
+ {
+@@ -184,7 +183,7 @@ static unsigned int bcma_of_get_irq(stru
+ 	struct of_phandle_args out_irq;
+ 	int ret;
+ 
+-	if (!parent || !parent->dev.of_node)
++	if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent || !parent->dev.of_node)
+ 		return 0;
+ 
+ 	ret = bcma_of_irq_parse(parent, core, &out_irq, num);
+@@ -202,23 +201,15 @@ static void bcma_of_fill_device(struct p
+ {
+ 	struct device_node *node;
+ 
++	if (!IS_ENABLED(CONFIG_OF_IRQ))
++		return;
++
+ 	node = bcma_of_find_child_device(parent, core);
+ 	if (node)
+ 		core->dev.of_node = node;
+ 
+ 	core->irq = bcma_of_get_irq(parent, core, 0);
+ }
+-#else
+-static void bcma_of_fill_device(struct platform_device *parent,
+-				struct bcma_device *core)
+-{
+-}
+-static inline unsigned int bcma_of_get_irq(struct platform_device *parent,
+-					   struct bcma_device *core, int num)
+-{
+-	return 0;
+-}
+-#endif /* CONFIG_OF */
+ 
+ unsigned int bcma_core_irq(struct bcma_device *core, int num)
+ {
+@@ -350,7 +341,7 @@ static int bcma_register_devices(struct
+ 		bcma_register_core(bus, core);
+ 	}
+ 
+-#ifdef CONFIG_BCMA_DRIVER_MIPS
++#ifdef CONFIG_BCMA_PFLASH
+ 	if (bus->drv_cc.pflash.present) {
+ 		err = platform_device_register(&bcma_pflash_dev);
+ 		if (err)
diff --git a/target/linux/generic/patches-4.4/022-bcma-from-4.8.patch b/target/linux/generic/patches-4.4/022-bcma-from-4.8.patch
new file mode 100644
index 0000000000..3ff4e94967
--- /dev/null
+++ b/target/linux/generic/patches-4.4/022-bcma-from-4.8.patch
@@ -0,0 +1,52 @@
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -76,9 +76,16 @@ config BCMA_PFLASH
+ 	default y
+ 
+ config BCMA_SFLASH
+-	bool
+-	depends on BCMA_DRIVER_MIPS
++	bool "ChipCommon-attached serial flash support"
++	depends on BCMA_HOST_SOC
+ 	default y
++	help
++	  Some cheap devices have serial flash connected to the ChipCommon
++	  instead of independent SPI controller. It requires using a separated
++	  driver that implements ChipCommon specific interface communication.
++
++	  Enabling this symbol will let bcma recognize serial flash and register
++	  it as platform device.
+ 
+ config BCMA_NFLASH
+ 	bool
+--- a/drivers/bcma/driver_chipcommon_b.c
++++ b/drivers/bcma/driver_chipcommon_b.c
+@@ -33,11 +33,12 @@ static bool bcma_wait_reg(struct bcma_bu
+ void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
+ {
+ 	struct bcma_bus *bus = ccb->core->bus;
++	void __iomem *mii = ccb->mii;
+ 
+-	writel(offset, ccb->mii + 0x00);
+-	bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
+-	writel(value, ccb->mii + 0x04);
+-	bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
++	writel(offset, mii + BCMA_CCB_MII_MNG_CTL);
++	bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
++	writel(value, mii + BCMA_CCB_MII_MNG_CMD_DATA);
++	bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
+ 
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -504,6 +504,9 @@
+ #define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK	0x1ff00000
+ #define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT	20
+ 
++#define BCMA_CCB_MII_MNG_CTL		0x0000
++#define BCMA_CCB_MII_MNG_CMD_DATA	0x0004
++
+ /* BCM4331 ChipControl numbers. */
+ #define BCMA_CHIPCTL_4331_BT_COEXIST		BIT(0)	/* 0 disable */
+ #define BCMA_CHIPCTL_4331_SECI			BIT(1)	/* 0 SECI is disabled (JATG functional) */
diff --git a/target/linux/generic/patches-4.4/023-bcma-from-4.9.patch b/target/linux/generic/patches-4.4/023-bcma-from-4.9.patch
new file mode 100644
index 0000000000..0391bcb802
--- /dev/null
+++ b/target/linux/generic/patches-4.4/023-bcma-from-4.9.patch
@@ -0,0 +1,82 @@
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -36,12 +36,31 @@ u32 bcma_chipco_get_alp_clock(struct bcm
+ }
+ EXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock);
+ 
++static bool bcma_core_cc_has_pmu_watchdog(struct bcma_drv_cc *cc)
++{
++	struct bcma_bus *bus = cc->core->bus;
++
++	if (cc->capabilities & BCMA_CC_CAP_PMU) {
++		if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573) {
++			WARN(bus->chipinfo.rev <= 1, "No watchdog available\n");
++			/* 53573B0 and 53573B1 have bugged PMU watchdog. It can
++			 * be enabled but timer can't be bumped. Use CC one
++			 * instead.
++			 */
++			return false;
++		}
++		return true;
++	} else {
++		return false;
++	}
++}
++
+ static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
+ {
+ 	struct bcma_bus *bus = cc->core->bus;
+ 	u32 nb;
+ 
+-	if (cc->capabilities & BCMA_CC_CAP_PMU) {
++	if (bcma_core_cc_has_pmu_watchdog(cc)) {
+ 		if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
+ 			nb = 32;
+ 		else if (cc->core->id.rev < 26)
+@@ -95,9 +114,16 @@ static int bcma_chipco_watchdog_ticks_pe
+ 
+ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
+ {
++	struct bcma_bus *bus = cc->core->bus;
+ 	struct bcm47xx_wdt wdt = {};
+ 	struct platform_device *pdev;
+ 
++	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573 &&
++	    bus->chipinfo.rev <= 1) {
++		pr_debug("No watchdog on 53573A0 / 53573A1\n");
++		return 0;
++	}
++
+ 	wdt.driver_data = cc;
+ 	wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
+ 	wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
+@@ -105,7 +131,7 @@ int bcma_chipco_watchdog_register(struct
+ 		bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+ 
+ 	pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
+-					     cc->core->bus->num, &wdt,
++					     bus->num, &wdt,
+ 					     sizeof(wdt));
+ 	if (IS_ERR(pdev))
+ 		return PTR_ERR(pdev);
+@@ -217,7 +243,7 @@ u32 bcma_chipco_watchdog_timer_set(struc
+ 	u32 maxt;
+ 
+ 	maxt = bcma_chipco_watchdog_get_max_timer(cc);
+-	if (cc->capabilities & BCMA_CC_CAP_PMU) {
++	if (bcma_core_cc_has_pmu_watchdog(cc)) {
+ 		if (ticks == 1)
+ 			ticks = 2;
+ 		else if (ticks > maxt)
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -204,6 +204,9 @@ struct bcma_host_ops {
+ #define  BCMA_PKG_ID_BCM4709	0
+ #define BCMA_CHIP_ID_BCM47094	53030
+ #define BCMA_CHIP_ID_BCM53018	53018
++#define BCMA_CHIP_ID_BCM53573	53573
++#define  BCMA_PKG_ID_BCM53573	0
++#define  BCMA_PKG_ID_BCM47189	1
+ 
+ /* Board types (on PCI usually equals to the subsystem dev id) */
+ /* BCM4313 */
diff --git a/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch b/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch
new file mode 100644
index 0000000000..d1390348cb
--- /dev/null
+++ b/target/linux/generic/patches-4.4/032-fq_codel-add-batch-ability-to-fq_codel_drop.patch
@@ -0,0 +1,189 @@
+From: Eric Dumazet <edumazet@google.com>
+Date: Sun, 1 May 2016 16:47:26 -0700
+Subject: [PATCH] fq_codel: add batch ability to fq_codel_drop()
+
+In presence of inelastic flows and stress, we can call
+fq_codel_drop() for every packet entering fq_codel qdisc.
+
+fq_codel_drop() is quite expensive, as it does a linear scan
+of 4 KB of memory to find a fat flow.
+Once found, it drops the oldest packet of this flow.
+
+Instead of dropping a single packet, try to drop 50% of the backlog
+of this fat flow, with a configurable limit of 64 packets per round.
+
+TCA_FQ_CODEL_DROP_BATCH_SIZE is the new attribute to make this
+limit configurable.
+
+With this strategy the 4 KB search is amortized to a single cache line
+per drop [1], so fq_codel_drop() no longer appears at the top of kernel
+profile in presence of few inelastic flows.
+
+[1] Assuming a 64byte cache line, and 1024 buckets
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: Dave Taht <dave.taht@gmail.com>
+Cc: Jonathan Morton <chromatix99@gmail.com>
+Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
+Acked-by: Dave Taht
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/include/uapi/linux/pkt_sched.h
++++ b/include/uapi/linux/pkt_sched.h
+@@ -711,6 +711,7 @@ enum {
+ 	TCA_FQ_CODEL_FLOWS,
+ 	TCA_FQ_CODEL_QUANTUM,
+ 	TCA_FQ_CODEL_CE_THRESHOLD,
++	TCA_FQ_CODEL_DROP_BATCH_SIZE,
+ 	__TCA_FQ_CODEL_MAX
+ };
+ 
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -57,6 +57,7 @@ struct fq_codel_sched_data {
+ 	u32		flows_cnt;	/* number of flows */
+ 	u32		perturbation;	/* hash perturbation */
+ 	u32		quantum;	/* psched_mtu(qdisc_dev(sch)); */
++	u32		drop_batch_size;
+ 	struct codel_params cparams;
+ 	struct codel_stats cstats;
+ 	u32		drop_overlimit;
+@@ -133,17 +134,20 @@ static inline void flow_queue_add(struct
+ 	skb->next = NULL;
+ }
+ 
+-static unsigned int fq_codel_drop(struct Qdisc *sch)
++static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets)
+ {
+ 	struct fq_codel_sched_data *q = qdisc_priv(sch);
+ 	struct sk_buff *skb;
+ 	unsigned int maxbacklog = 0, idx = 0, i, len;
+ 	struct fq_codel_flow *flow;
++	unsigned int threshold;
+ 
+-	/* Queue is full! Find the fat flow and drop packet from it.
++	/* Queue is full! Find the fat flow and drop packet(s) from it.
+ 	 * This might sound expensive, but with 1024 flows, we scan
+ 	 * 4KB of memory, and we dont need to handle a complex tree
+ 	 * in fast path (packet queue/enqueue) with many cache misses.
++	 * In stress mode, we'll try to drop 64 packets from the flow,
++	 * amortizing this linear lookup to one cache line per drop.
+ 	 */
+ 	for (i = 0; i < q->flows_cnt; i++) {
+ 		if (q->backlogs[i] > maxbacklog) {
+@@ -151,15 +155,24 @@ static unsigned int fq_codel_drop(struct
+ 			idx = i;
+ 		}
+ 	}
++
++	/* Our goal is to drop half of this fat flow backlog */
++	threshold = maxbacklog >> 1;
++
+ 	flow = &q->flows[idx];
+-	skb = dequeue_head(flow);
+-	len = qdisc_pkt_len(skb);
++	len = 0;
++	i = 0;
++	do {
++		skb = dequeue_head(flow);
++		len += qdisc_pkt_len(skb);
++		kfree_skb(skb);
++	} while (++i < max_packets && len < threshold);
++
++	flow->dropped += i;
+ 	q->backlogs[idx] -= len;
+-	sch->q.qlen--;
+-	qdisc_qstats_drop(sch);
+-	qdisc_qstats_backlog_dec(sch, skb);
+-	kfree_skb(skb);
+-	flow->dropped++;
++	sch->qstats.drops += i;
++	sch->qstats.backlog -= len;
++	sch->q.qlen -= i;
+ 	return idx;
+ }
+ 
+@@ -168,14 +181,14 @@ static unsigned int fq_codel_qdisc_drop(
+ 	unsigned int prev_backlog;
+ 
+ 	prev_backlog = sch->qstats.backlog;
+-	fq_codel_drop(sch);
++	fq_codel_drop(sch, 1U);
+ 	return prev_backlog - sch->qstats.backlog;
+ }
+ 
+ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+ {
+ 	struct fq_codel_sched_data *q = qdisc_priv(sch);
+-	unsigned int idx, prev_backlog;
++	unsigned int idx, prev_backlog, prev_qlen;
+ 	struct fq_codel_flow *flow;
+ 	int uninitialized_var(ret);
+ 
+@@ -204,16 +217,22 @@ static int fq_codel_enqueue(struct sk_bu
+ 		return NET_XMIT_SUCCESS;
+ 
+ 	prev_backlog = sch->qstats.backlog;
+-	q->drop_overlimit++;
+-	/* Return Congestion Notification only if we dropped a packet
+-	 * from this flow.
++	prev_qlen = sch->q.qlen;
++
++	/* fq_codel_drop() is quite expensive, as it performs a linear search
++	 * in q->backlogs[] to find a fat flow.
++	 * So instead of dropping a single packet, drop half of its backlog
++	 * with a 64 packets limit to not add a too big cpu spike here.
+ 	 */
+-	if (fq_codel_drop(sch) == idx)
+-		return NET_XMIT_CN;
++	ret = fq_codel_drop(sch, q->drop_batch_size);
++
++	q->drop_overlimit += prev_qlen - sch->q.qlen;
+ 
+-	/* As we dropped a packet, better let upper stack know this */
+-	qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
+-	return NET_XMIT_SUCCESS;
++	/* As we dropped packet(s), better let upper stack know this */
++	qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
++				  prev_backlog - sch->qstats.backlog);
++
++	return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS;
+ }
+ 
+ /* This is the specific function called from codel_dequeue()
+@@ -323,6 +342,7 @@ static const struct nla_policy fq_codel_
+ 	[TCA_FQ_CODEL_FLOWS]	= { .type = NLA_U32 },
+ 	[TCA_FQ_CODEL_QUANTUM]	= { .type = NLA_U32 },
+ 	[TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 },
++	[TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NLA_U32 },
+ };
+ 
+ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
+@@ -374,6 +394,9 @@ static int fq_codel_change(struct Qdisc
+ 	if (tb[TCA_FQ_CODEL_QUANTUM])
+ 		q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
+ 
++	if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])
++		q->drop_batch_size = min(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]));
++
+ 	while (sch->q.qlen > sch->limit) {
+ 		struct sk_buff *skb = fq_codel_dequeue(sch);
+ 
+@@ -419,6 +442,7 @@ static int fq_codel_init(struct Qdisc *s
+ 
+ 	sch->limit = 10*1024;
+ 	q->flows_cnt = 1024;
++	q->drop_batch_size = 64;
+ 	q->quantum = psched_mtu(qdisc_dev(sch));
+ 	q->perturbation = prandom_u32();
+ 	INIT_LIST_HEAD(&q->new_flows);
+@@ -476,6 +500,8 @@ static int fq_codel_dump(struct Qdisc *s
+ 			q->cparams.ecn) ||
+ 	    nla_put_u32(skb, TCA_FQ_CODEL_QUANTUM,
+ 			q->quantum) ||
++	    nla_put_u32(skb, TCA_FQ_CODEL_DROP_BATCH_SIZE,
++			q->drop_batch_size) ||
+ 	    nla_put_u32(skb, TCA_FQ_CODEL_FLOWS,
+ 			q->flows_cnt))
+ 		goto nla_put_failure;
diff --git a/target/linux/generic/patches-4.4/033-fq_codel-add-memory-limitation-per-queue.patch b/target/linux/generic/patches-4.4/033-fq_codel-add-memory-limitation-per-queue.patch
new file mode 100644
index 0000000000..455add9eae
--- /dev/null
+++ b/target/linux/generic/patches-4.4/033-fq_codel-add-memory-limitation-per-queue.patch
@@ -0,0 +1,182 @@
+From: Eric Dumazet <edumazet@google.com>
+Date: Fri, 6 May 2016 08:55:12 -0700
+Subject: [PATCH] fq_codel: add memory limitation per queue
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On small embedded routers, one wants to control maximal amount of
+memory used by fq_codel, instead of controlling number of packets or
+bytes, since GRO/TSO make these not practical.
+
+Assuming skb->truesize is accurate, we have to keep track of
+skb->truesize sum for skbs in queue.
+
+This patch adds a new TCA_FQ_CODEL_MEMORY_LIMIT attribute.
+
+I chose a default value of 32 MBytes, which looks reasonable even
+for heavy duty usages. (Prior fq_codel users should not be hurt
+when they upgrade their kernels)
+
+Two fields are added to tc_fq_codel_qd_stats to report :
+ - Current memory usage
+ - Number of drops caused by memory limits
+
+# tc qd replace dev eth1 root est 1sec 4sec fq_codel memory_limit 4M
+..
+# tc -s -d qd sh dev eth1
+qdisc fq_codel 8008: root refcnt 257 limit 10240p flows 1024
+ quantum 1514 target 5.0ms interval 100.0ms memory_limit 4Mb ecn
+ Sent 2083566791363 bytes 1376214889 pkt (dropped 4994406, overlimits 0
+requeues 21705223)
+ rate 9841Mbit 812549pps backlog 3906120b 376p requeues 21705223
+  maxpacket 68130 drop_overlimit 4994406 new_flow_count 28855414
+  ecn_mark 0 memory_used 4190048 drop_overmemory 4994406
+  new_flows_len 1 old_flows_len 177
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: Jesper Dangaard Brouer <brouer@redhat.com>
+Cc: Dave Täht <dave.taht@gmail.com>
+Cc: Sebastian Möller <moeller0@gmx.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/include/uapi/linux/pkt_sched.h
++++ b/include/uapi/linux/pkt_sched.h
+@@ -712,6 +712,7 @@ enum {
+ 	TCA_FQ_CODEL_QUANTUM,
+ 	TCA_FQ_CODEL_CE_THRESHOLD,
+ 	TCA_FQ_CODEL_DROP_BATCH_SIZE,
++	TCA_FQ_CODEL_MEMORY_LIMIT,
+ 	__TCA_FQ_CODEL_MAX
+ };
+ 
+@@ -736,6 +737,8 @@ struct tc_fq_codel_qd_stats {
+ 	__u32	new_flows_len;	/* count of flows in new list */
+ 	__u32	old_flows_len;	/* count of flows in old list */
+ 	__u32	ce_mark;	/* packets above ce_threshold */
++	__u32	memory_usage;	/* in bytes */
++	__u32	drop_overmemory;
+ };
+ 
+ struct tc_fq_codel_cl_stats {
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -58,8 +58,11 @@ struct fq_codel_sched_data {
+ 	u32		perturbation;	/* hash perturbation */
+ 	u32		quantum;	/* psched_mtu(qdisc_dev(sch)); */
+ 	u32		drop_batch_size;
++	u32		memory_limit;
+ 	struct codel_params cparams;
+ 	struct codel_stats cstats;
++	u32		memory_usage;
++	u32		drop_overmemory;
+ 	u32		drop_overlimit;
+ 	u32		new_flow_count;
+ 
+@@ -141,6 +144,7 @@ static unsigned int fq_codel_drop(struct
+ 	unsigned int maxbacklog = 0, idx = 0, i, len;
+ 	struct fq_codel_flow *flow;
+ 	unsigned int threshold;
++	unsigned int mem = 0;
+ 
+ 	/* Queue is full! Find the fat flow and drop packet(s) from it.
+ 	 * This might sound expensive, but with 1024 flows, we scan
+@@ -165,11 +169,13 @@ static unsigned int fq_codel_drop(struct
+ 	do {
+ 		skb = dequeue_head(flow);
+ 		len += qdisc_pkt_len(skb);
++		mem += skb->truesize;
+ 		kfree_skb(skb);
+ 	} while (++i < max_packets && len < threshold);
+ 
+ 	flow->dropped += i;
+ 	q->backlogs[idx] -= len;
++	q->memory_usage -= mem;
+ 	sch->qstats.drops += i;
+ 	sch->qstats.backlog -= len;
+ 	sch->q.qlen -= i;
+@@ -191,6 +197,7 @@ static int fq_codel_enqueue(struct sk_bu
+ 	unsigned int idx, prev_backlog, prev_qlen;
+ 	struct fq_codel_flow *flow;
+ 	int uninitialized_var(ret);
++	bool memory_limited;
+ 
+ 	idx = fq_codel_classify(skb, sch, &ret);
+ 	if (idx == 0) {
+@@ -213,7 +220,9 @@ static int fq_codel_enqueue(struct sk_bu
+ 		flow->deficit = q->quantum;
+ 		flow->dropped = 0;
+ 	}
+-	if (++sch->q.qlen <= sch->limit)
++	q->memory_usage += skb->truesize;
++	memory_limited = q->memory_usage > q->memory_limit;
++	if (++sch->q.qlen <= sch->limit && !memory_limited)
+ 		return NET_XMIT_SUCCESS;
+ 
+ 	prev_backlog = sch->qstats.backlog;
+@@ -227,7 +236,8 @@ static int fq_codel_enqueue(struct sk_bu
+ 	ret = fq_codel_drop(sch, q->drop_batch_size);
+ 
+ 	q->drop_overlimit += prev_qlen - sch->q.qlen;
+-
++	if (memory_limited)
++		q->drop_overmemory += prev_qlen - sch->q.qlen;
+ 	/* As we dropped packet(s), better let upper stack know this */
+ 	qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
+ 				  prev_backlog - sch->qstats.backlog);
+@@ -296,6 +306,7 @@ begin:
+ 			list_del_init(&flow->flowchain);
+ 		goto begin;
+ 	}
++	q->memory_usage -= skb->truesize;
+ 	qdisc_bstats_update(sch, skb);
+ 	flow->deficit -= qdisc_pkt_len(skb);
+ 	/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
+@@ -343,6 +354,7 @@ static const struct nla_policy fq_codel_
+ 	[TCA_FQ_CODEL_QUANTUM]	= { .type = NLA_U32 },
+ 	[TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 },
+ 	[TCA_FQ_CODEL_DROP_BATCH_SIZE] = { .type = NLA_U32 },
++	[TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NLA_U32 },
+ };
+ 
+ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
+@@ -397,7 +409,11 @@ static int fq_codel_change(struct Qdisc
+ 	if (tb[TCA_FQ_CODEL_DROP_BATCH_SIZE])
+ 		q->drop_batch_size = min(1U, nla_get_u32(tb[TCA_FQ_CODEL_DROP_BATCH_SIZE]));
+ 
+-	while (sch->q.qlen > sch->limit) {
++	if (tb[TCA_FQ_CODEL_MEMORY_LIMIT])
++		q->memory_limit = min(1U << 31, nla_get_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]));
++
++	while (sch->q.qlen > sch->limit ||
++	       q->memory_usage > q->memory_limit) {
+ 		struct sk_buff *skb = fq_codel_dequeue(sch);
+ 
+ 		q->cstats.drop_len += qdisc_pkt_len(skb);
+@@ -442,6 +458,7 @@ static int fq_codel_init(struct Qdisc *s
+ 
+ 	sch->limit = 10*1024;
+ 	q->flows_cnt = 1024;
++	q->memory_limit = 32 << 20; /* 32 MBytes */
+ 	q->drop_batch_size = 64;
+ 	q->quantum = psched_mtu(qdisc_dev(sch));
+ 	q->perturbation = prandom_u32();
+@@ -502,6 +519,8 @@ static int fq_codel_dump(struct Qdisc *s
+ 			q->quantum) ||
+ 	    nla_put_u32(skb, TCA_FQ_CODEL_DROP_BATCH_SIZE,
+ 			q->drop_batch_size) ||
++	    nla_put_u32(skb, TCA_FQ_CODEL_MEMORY_LIMIT,
++			q->memory_limit) ||
+ 	    nla_put_u32(skb, TCA_FQ_CODEL_FLOWS,
+ 			q->flows_cnt))
+ 		goto nla_put_failure;
+@@ -530,6 +549,8 @@ static int fq_codel_dump_stats(struct Qd
+ 	st.qdisc_stats.ecn_mark = q->cstats.ecn_mark;
+ 	st.qdisc_stats.new_flow_count = q->new_flow_count;
+ 	st.qdisc_stats.ce_mark = q->cstats.ce_mark;
++	st.qdisc_stats.memory_usage  = q->memory_usage;
++	st.qdisc_stats.drop_overmemory = q->drop_overmemory;
+ 
+ 	list_for_each(pos, &q->new_flows)
+ 		st.qdisc_stats.new_flows_len++;
diff --git a/target/linux/generic/patches-4.4/034-fq_codel-fix-memory-limitation-drift.patch b/target/linux/generic/patches-4.4/034-fq_codel-fix-memory-limitation-drift.patch
new file mode 100644
index 0000000000..45fff7bae9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/034-fq_codel-fix-memory-limitation-drift.patch
@@ -0,0 +1,40 @@
+From: Eric Dumazet <edumazet@google.com>
+Date: Sun, 15 May 2016 18:16:38 -0700
+Subject: [PATCH] fq_codel: fix memory limitation drift
+
+memory_usage must be decreased in dequeue_func(), not in
+fq_codel_dequeue(), otherwise packets dropped by Codel algo
+are missing this decrease.
+
+Also we need to clear memory_usage in fq_codel_reset()
+
+Fixes: 95b58430abe7 ("fq_codel: add memory limitation per queue")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+---
+
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -259,6 +259,7 @@ static struct sk_buff *dequeue(struct co
+ 	if (flow->head) {
+ 		skb = dequeue_head(flow);
+ 		q->backlogs[flow - q->flows] -= qdisc_pkt_len(skb);
++		q->memory_usage -= skb->truesize;
+ 		sch->q.qlen--;
+ 	}
+ 	return skb;
+@@ -306,7 +307,6 @@ begin:
+ 			list_del_init(&flow->flowchain);
+ 		goto begin;
+ 	}
+-	q->memory_usage -= skb->truesize;
+ 	qdisc_bstats_update(sch, skb);
+ 	flow->deficit -= qdisc_pkt_len(skb);
+ 	/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
+@@ -343,6 +343,7 @@ static void fq_codel_reset(struct Qdisc
+ 	}
+ 	memset(q->backlogs, 0, q->flows_cnt * sizeof(u32));
+ 	sch->q.qlen = 0;
++	q->memory_usage = 0;
+ }
+ 
+ static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
diff --git a/target/linux/generic/patches-4.4/035-fq_codel-fix-NET_XMIT_CN-behavior.patch b/target/linux/generic/patches-4.4/035-fq_codel-fix-NET_XMIT_CN-behavior.patch
new file mode 100644
index 0000000000..a1902fea07
--- /dev/null
+++ b/target/linux/generic/patches-4.4/035-fq_codel-fix-NET_XMIT_CN-behavior.patch
@@ -0,0 +1,70 @@
+From: Eric Dumazet <edumazet@google.com>
+Date: Sat, 4 Jun 2016 12:55:13 -0700
+Subject: [PATCH] fq_codel: fix NET_XMIT_CN behavior
+
+My prior attempt to fix the backlogs of parents failed.
+
+If we return NET_XMIT_CN, our parents wont increase their backlog,
+so our qdisc_tree_reduce_backlog() should take this into account.
+
+v2: Florian Westphal pointed out that we could drop the packet,
+so we need to save qdisc_pkt_len(skb) in a temp variable before
+calling fq_codel_drop()
+
+Fixes: 9d18562a2278 ("fq_codel: add batch ability to fq_codel_drop()")
+Fixes: 2ccccf5fb43f ("net_sched: update hierarchical backlog too")
+Reported-by: Stas Nichiporovich <stasn77@gmail.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: WANG Cong <xiyou.wangcong@gmail.com>
+Cc: Jamal Hadi Salim <jhs@mojatatu.com>
+---
+
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -197,6 +197,7 @@ static int fq_codel_enqueue(struct sk_bu
+ 	unsigned int idx, prev_backlog, prev_qlen;
+ 	struct fq_codel_flow *flow;
+ 	int uninitialized_var(ret);
++	unsigned int pkt_len;
+ 	bool memory_limited;
+ 
+ 	idx = fq_codel_classify(skb, sch, &ret);
+@@ -228,6 +229,8 @@ static int fq_codel_enqueue(struct sk_bu
+ 	prev_backlog = sch->qstats.backlog;
+ 	prev_qlen = sch->q.qlen;
+ 
++	/* save this packet length as it might be dropped by fq_codel_drop() */
++	pkt_len = qdisc_pkt_len(skb);
+ 	/* fq_codel_drop() is quite expensive, as it performs a linear search
+ 	 * in q->backlogs[] to find a fat flow.
+ 	 * So instead of dropping a single packet, drop half of its backlog
+@@ -235,14 +238,23 @@ static int fq_codel_enqueue(struct sk_bu
+ 	 */
+ 	ret = fq_codel_drop(sch, q->drop_batch_size);
+ 
+-	q->drop_overlimit += prev_qlen - sch->q.qlen;
++	prev_qlen -= sch->q.qlen;
++	prev_backlog -= sch->qstats.backlog;
++	q->drop_overlimit += prev_qlen;
+ 	if (memory_limited)
+-		q->drop_overmemory += prev_qlen - sch->q.qlen;
+-	/* As we dropped packet(s), better let upper stack know this */
+-	qdisc_tree_reduce_backlog(sch, prev_qlen - sch->q.qlen,
+-				  prev_backlog - sch->qstats.backlog);
++		q->drop_overmemory += prev_qlen;
+ 
+-	return ret == idx ? NET_XMIT_CN : NET_XMIT_SUCCESS;
++	/* As we dropped packet(s), better let upper stack know this.
++	 * If we dropped a packet for this flow, return NET_XMIT_CN,
++	 * but in this case, our parents wont increase their backlogs.
++	 */
++	if (ret == idx) {
++		qdisc_tree_reduce_backlog(sch, prev_qlen - 1,
++					  prev_backlog - pkt_len);
++		return NET_XMIT_CN;
++	}
++	qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog);
++	return NET_XMIT_SUCCESS;
+ }
+ 
+ /* This is the specific function called from codel_dequeue()
diff --git a/target/linux/generic/patches-4.4/040-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch b/target/linux/generic/patches-4.4/040-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
new file mode 100644
index 0000000000..2429b113d0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/040-mtd-bcm47xxpart-limit-scanned-flash-area-on-BCM47XX-.patch
@@ -0,0 +1,35 @@
+From 2a36a5c30eab9cd1c9d2d08bd27cd763325d70c5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 5 Dec 2015 02:09:43 +0100
+Subject: [PATCH] mtd: bcm47xxpart: limit scanned flash area on BCM47XX (MIPS)
+ only
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We allowed using bcm47xxpart on BCM5301X arch with commit:
+9e3afa5f5c7 ("mtd: bcm47xxpart: allow enabling on ARCH_BCM_5301X")
+
+BCM5301X devices may contain some partitions in higher memory, e.g.
+Netgear R8000 has board_data at 0x2600000. To detect them we should
+use size limit on MIPS only.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -118,8 +118,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 	/* Parse block by block looking for magics */
+ 	for (offset = 0; offset <= master->size - blocksize;
+ 	     offset += blocksize) {
+-		/* Nothing more in higher memory */
+-		if (offset >= 0x2000000)
++		/* Nothing more in higher memory on BCM47XX (MIPS) */
++		if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
+ 			break;
+ 
+ 		if (curr_part >= BCM47XXPART_MAX_PARTS) {
diff --git a/target/linux/generic/patches-4.4/041-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch b/target/linux/generic/patches-4.4/041-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
new file mode 100644
index 0000000000..8a04852bc4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/041-mtd-bcm47xxpart-don-t-fail-because-of-bit-flips.patch
@@ -0,0 +1,93 @@
+From 36bcc0c9c2bc8f56569cd735ba531a51358d7c2b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 6 Dec 2015 11:31:38 +0100
+Subject: [PATCH] mtd: bcm47xxpart: don't fail because of bit-flips
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Bit-flip errors may occur on NAND flashes and are harmless. Handle them
+gracefully as read content is still reliable and can be parsed.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 38 ++++++++++++++++++++++----------------
+ 1 file changed, 22 insertions(+), 16 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_
+ {
+ 	uint32_t buf;
+ 	size_t bytes_read;
++	int err;
+ 
+-	if (mtd_read(master, offset, sizeof(buf), &bytes_read,
+-		     (uint8_t *)&buf) < 0) {
+-		pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			offset);
++	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
++			(uint8_t *)&buf);
++	if (err && !mtd_is_bitflip(err)) {
++		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			offset, err);
+ 		goto out_default;
+ 	}
+ 
+@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_
+ 	int trx_part = -1;
+ 	int last_trx_part = -1;
+ 	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
++	int err;
+ 
+ 	/*
+ 	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
+@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Read beginning of the block */
+-		if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+-			     &bytes_read, (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			       offset);
++		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
++			       &bytes_read, (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
+@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		/* Read middle of the block */
+-		if (mtd_read(master, offset + 0x8000, 0x4,
+-			     &bytes_read, (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+-			       offset);
++		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
++			       (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
+@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 		}
+ 
+ 		offset = master->size - possible_nvram_sizes[i];
+-		if (mtd_read(master, offset, 0x4, &bytes_read,
+-			     (uint8_t *)buf) < 0) {
+-			pr_err("mtd_read error while reading at offset 0x%X!\n",
+-			       offset);
++		err = mtd_read(master, offset, 0x4, &bytes_read,
++			       (uint8_t *)buf);
++		if (err && !mtd_is_bitflip(err)) {
++			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
++			       offset, err);
+ 			continue;
+ 		}
+ 
diff --git a/target/linux/generic/patches-4.4/042-0001-mtd-bcm47xxsflash-use-ioremap_cache-instead-of-KSEG0.patch b/target/linux/generic/patches-4.4/042-0001-mtd-bcm47xxsflash-use-ioremap_cache-instead-of-KSEG0.patch
new file mode 100644
index 0000000000..89f1e5eccf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/042-0001-mtd-bcm47xxsflash-use-ioremap_cache-instead-of-KSEG0.patch
@@ -0,0 +1,138 @@
+From 5651d6aaf489d1db48c253cf884b40214e91c2c5 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 26 Feb 2016 11:50:28 +0100
+Subject: [PATCH] mtd: bcm47xxsflash: use ioremap_cache() instead of
+ KSEG0ADDR()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Using KSEG0ADDR makes code highly MIPS dependent and not portable.
+Thanks to the fix a68f376 ("MIPS: io.h: Define `ioremap_cache'") we can
+use ioremap_cache which is generic and supported on MIPS as well now.
+
+KSEG0ADDR was translating 0x1c000000 into 0x9c000000. With ioremap_cache
+we use MIPS's __ioremap (and then remap_area_pages). This results in
+different address (e.g. 0xc0080000) but it still should be cached as
+expected and it was successfully tested with BCM47186B0.
+
+Other than that drivers/bcma/driver_chipcommon_sflash.c nicely setups a
+struct resource for access window, but we wren't using it. Use it now
+and drop duplicated info.
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -146,7 +146,6 @@ int bcma_sflash_init(struct bcma_drv_cc
+ 		return -ENOTSUPP;
+ 	}
+ 
+-	sflash->window = BCMA_SOC_FLASH2;
+ 	sflash->blocksize = e->blocksize;
+ 	sflash->numblocks = e->numblocks;
+ 	sflash->size = sflash->blocksize * sflash->numblocks;
+--- a/drivers/mtd/devices/bcm47xxsflash.c
++++ b/drivers/mtd/devices/bcm47xxsflash.c
+@@ -2,6 +2,7 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/delay.h>
++#include <linux/ioport.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+@@ -109,8 +110,7 @@ static int bcm47xxsflash_read(struct mtd
+ 	if ((from + len) > mtd->size)
+ 		return -EINVAL;
+ 
+-	memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
+-		      len);
++	memcpy_fromio(buf, b47s->window + from, len);
+ 	*retlen = len;
+ 
+ 	return len;
+@@ -275,15 +275,33 @@ static void bcm47xxsflash_bcma_cc_write(
+ 
+ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
+ {
+-	struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
++	struct device *dev = &pdev->dev;
++	struct bcma_sflash *sflash = dev_get_platdata(dev);
+ 	struct bcm47xxsflash *b47s;
++	struct resource *res;
+ 	int err;
+ 
+-	b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
++	b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL);
+ 	if (!b47s)
+ 		return -ENOMEM;
+ 	sflash->priv = b47s;
+ 
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(dev, "invalid resource\n");
++		return -EINVAL;
++	}
++	if (!devm_request_mem_region(dev, res->start, resource_size(res),
++				     res->name)) {
++		dev_err(dev, "can't request region for resource %pR\n", res);
++		return -EBUSY;
++	}
++	b47s->window = ioremap_cache(res->start, resource_size(res));
++	if (!b47s->window) {
++		dev_err(dev, "ioremap failed for resource %pR\n", res);
++		return -ENOMEM;
++	}
++
+ 	b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
+ 	b47s->cc_read = bcm47xxsflash_bcma_cc_read;
+ 	b47s->cc_write = bcm47xxsflash_bcma_cc_write;
+@@ -297,7 +315,6 @@ static int bcm47xxsflash_bcma_probe(stru
+ 		break;
+ 	}
+ 
+-	b47s->window = sflash->window;
+ 	b47s->blocksize = sflash->blocksize;
+ 	b47s->numblocks = sflash->numblocks;
+ 	b47s->size = sflash->size;
+@@ -306,6 +323,7 @@ static int bcm47xxsflash_bcma_probe(stru
+ 	err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
+ 	if (err) {
+ 		pr_err("Failed to register MTD device: %d\n", err);
++		iounmap(b47s->window);
+ 		return err;
+ 	}
+ 
+@@ -321,6 +339,7 @@ static int bcm47xxsflash_bcma_remove(str
+ 	struct bcm47xxsflash *b47s = sflash->priv;
+ 
+ 	mtd_device_unregister(&b47s->mtd);
++	iounmap(b47s->window);
+ 
+ 	return 0;
+ }
+--- a/drivers/mtd/devices/bcm47xxsflash.h
++++ b/drivers/mtd/devices/bcm47xxsflash.h
+@@ -65,7 +65,8 @@ struct bcm47xxsflash {
+ 
+ 	enum bcm47xxsflash_type type;
+ 
+-	u32 window;
++	void __iomem *window;
++
+ 	u32 blocksize;
+ 	u16 numblocks;
+ 	u32 size;
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -588,7 +588,6 @@ struct bcma_pflash {
+ #ifdef CONFIG_BCMA_SFLASH
+ struct bcma_sflash {
+ 	bool present;
+-	u32 window;
+ 	u32 blocksize;
+ 	u16 numblocks;
+ 	u32 size;
diff --git a/target/linux/generic/patches-4.4/042-0002-mtd-add-arch-dependency-for-MTD_BCM47XXSFLASH-symbol.patch b/target/linux/generic/patches-4.4/042-0002-mtd-add-arch-dependency-for-MTD_BCM47XXSFLASH-symbol.patch
new file mode 100644
index 0000000000..b7ff055ab1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/042-0002-mtd-add-arch-dependency-for-MTD_BCM47XXSFLASH-symbol.patch
@@ -0,0 +1,41 @@
+From efacc699139e13f9d3ed8b47df92acb88ff8479f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 19 Jul 2016 09:08:32 +0200
+Subject: [PATCH] mtd: add arch dependency for MTD_BCM47XXSFLASH symbol
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We dropped strict MIPS dependency for bcm47xxsflash driver in:
+commit 5651d6aaf489 ("mtd: bcm47xxsflash: use ioremap_cache() instead of
+KSEG0ADDR()") but using ioremap_cache still limits building it to few
+selected architectures only.
+
+A recent commit 57d8f7dd2132 ("bcma: allow enabling serial flash support
+on non-MIPS SoCs") automatically dropped MIPS dependency for
+MTD_BCM47XXSFLASH which broke building e.g. on powerpc and cris.
+
+The bcma change is alright as it doesn't break building bcma code in any
+way. MTD_BCM47XXSFLASH on the other hand should be limited to archs
+which need it and can build it (by providing ioremap_cache).
+
+Fixes: 57d8f7dd2132 ("bcma: allow enabling serial flash support on non-MIPS SoCs")
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Cc: Brian Norris <computersforpeace@gmail.com>
+Acked-by: Brian Norris <computersforpeace@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/mtd/devices/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -114,7 +114,7 @@ config MTD_SST25L
+ 
+ config MTD_BCM47XXSFLASH
+ 	tristate "R/O support for serial flash on BCMA bus"
+-	depends on BCMA_SFLASH
++	depends on BCMA_SFLASH && (MIPS || ARM)
+ 	help
+ 	  BCMA bus can have various flash memories attached, they are
+ 	  registered by bcma as platform devices. This enables driver for
diff --git a/target/linux/generic/patches-4.4/042-0003-mtd-bcm47xxsflash-use-uncached-MMIO-access-for-BCM53.patch b/target/linux/generic/patches-4.4/042-0003-mtd-bcm47xxsflash-use-uncached-MMIO-access-for-BCM53.patch
new file mode 100644
index 0000000000..c2f2d21d03
--- /dev/null
+++ b/target/linux/generic/patches-4.4/042-0003-mtd-bcm47xxsflash-use-uncached-MMIO-access-for-BCM53.patch
@@ -0,0 +1,59 @@
+From 64ad46379fcf14f437553f654d1adcd3d0e0d7f9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 15 Aug 2016 14:21:28 +0200
+Subject: [PATCH] mtd: bcm47xxsflash: use uncached MMIO access for BCM53573
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM53573 is a new series of Broadcom's SoCs. It's based on ARM and uses
+this old ChipCommon-based flash access. Early tests resulted in flash
+corruptions that were tracked down to using cached MMIO for flash read
+access. Switch to ioremap_nocache conditionally to support BCM53573 and
+don't break performance on old MIPS devices.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/devices/bcm47xxsflash.c | 24 +++++++++++++++++++-----
+ 1 file changed, 19 insertions(+), 5 deletions(-)
+
+--- a/drivers/mtd/devices/bcm47xxsflash.c
++++ b/drivers/mtd/devices/bcm47xxsflash.c
+@@ -296,16 +296,30 @@ static int bcm47xxsflash_bcma_probe(stru
+ 		dev_err(dev, "can't request region for resource %pR\n", res);
+ 		return -EBUSY;
+ 	}
+-	b47s->window = ioremap_cache(res->start, resource_size(res));
+-	if (!b47s->window) {
+-		dev_err(dev, "ioremap failed for resource %pR\n", res);
+-		return -ENOMEM;
+-	}
+ 
+ 	b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
+ 	b47s->cc_read = bcm47xxsflash_bcma_cc_read;
+ 	b47s->cc_write = bcm47xxsflash_bcma_cc_write;
+ 
++	/*
++	 * On old MIPS devices cache was magically invalidated when needed,
++	 * allowing us to use cached access and gain some performance. Trying
++	 * the same on ARM based BCM53573 results in flash corruptions, we need
++	 * to use uncached access for it.
++	 *
++	 * It may be arch specific, but right now there is only 1 ARM SoC using
++	 * this driver, so let's follow Broadcom's reference code and check
++	 * ChipCommon revision.
++	 */
++	if (b47s->bcma_cc->core->id.rev == 54)
++		b47s->window = ioremap_nocache(res->start, resource_size(res));
++	else
++		b47s->window = ioremap_cache(res->start, resource_size(res));
++	if (!b47s->window) {
++		dev_err(dev, "ioremap failed for resource %pR\n", res);
++		return -ENOMEM;
++	}
++
+ 	switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
+ 	case BCMA_CC_FLASHT_STSER:
+ 		b47s->type = BCM47XXSFLASH_TYPE_ST;
diff --git a/target/linux/generic/patches-4.4/042-0004-mtd-bcm47xxpart-fix-parsing-first-block-after-aligne.patch b/target/linux/generic/patches-4.4/042-0004-mtd-bcm47xxpart-fix-parsing-first-block-after-aligne.patch
new file mode 100644
index 0000000000..7eed77775a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/042-0004-mtd-bcm47xxpart-fix-parsing-first-block-after-aligne.patch
@@ -0,0 +1,40 @@
+From bd5d21310133921021d78995ad6346f908483124 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Sun, 20 Nov 2016 16:09:30 +0100
+Subject: [PATCH] mtd: bcm47xxpart: fix parsing first block after aligned TRX
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+After parsing TRX we should skip to the first block placed behind it.
+Our code was working only with TRX with length not aligned to the
+blocksize. In other cases (length aligned) it was missing the block
+places right after TRX.
+
+This fixes calculation and simplifies the comment.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -229,12 +229,10 @@ static int bcm47xxpart_parse(struct mtd_
+ 
+ 			last_trx_part = curr_part - 1;
+ 
+-			/*
+-			 * We have whole TRX scanned, skip to the next part. Use
+-			 * roundown (not roundup), as the loop will increase
+-			 * offset in next step.
+-			 */
+-			offset = rounddown(offset + trx->length, blocksize);
++			/* Jump to the end of TRX */
++			offset = roundup(offset + trx->length, blocksize);
++			/* Next loop iteration will increase the offset */
++			offset -= blocksize;
+ 			continue;
+ 		}
+ 
diff --git a/target/linux/generic/patches-4.4/043-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch b/target/linux/generic/patches-4.4/043-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
new file mode 100644
index 0000000000..b7fd046a23
--- /dev/null
+++ b/target/linux/generic/patches-4.4/043-mtd-spi-nor-mx25l3205d-mx25l6405d-append-SECT_4K.patch
@@ -0,0 +1,27 @@
+From 0501f2e5ff28a02295e42fc9e7164a20ef4c30d5 Mon Sep 17 00:00:00 2001
+From: Andreas Fenkart <afenkart@gmail.com>
+Date: Thu, 5 Nov 2015 10:04:23 +0100
+Subject: [PATCH] mtd: spi-nor: mx25l3205d/mx25l6405d: append SECT_4K
+
+according datasheet both chips can erase 4kByte sectors individually
+
+Signed-off-by: Andreas Fenkart <andreas.fenkart@dev.digitalstrom.org>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -715,9 +715,9 @@ static const struct flash_info spi_nor_i
+ 	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
+ 	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
+ 	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
+-	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
++	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
+ 	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
++	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+ 	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ 	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
diff --git a/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch b/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch
new file mode 100644
index 0000000000..c4c7e6e01d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/045-mtd-devices-m25p80-add-support-for-mmap-read-request.patch
@@ -0,0 +1,46 @@
+From 08922f644878c9163ada8df3ef9def89be1d5e90 Mon Sep 17 00:00:00 2001
+From: Vignesh R <vigneshr@ti.com>
+Date: Tue, 29 Mar 2016 11:16:17 +0530
+Subject: [PATCH] mtd: devices: m25p80: add support for mmap read request
+
+Certain SPI controllers may provide accelerated hardware interface to
+read from m25p80 type flash devices in order to provide better read
+performance. SPI core supports such devices with spi_flash_read() API.
+Call spi_flash_read(), if supported, to make use of such interface.
+
+Signed-off-by: Vignesh R <vigneshr@ti.com>
+[Brian: add memset()]
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *n
+ 	/* convert the dummy cycles to the number of bytes */
+ 	dummy /= 8;
+ 
++	if (spi_flash_read_supported(spi)) {
++		struct spi_flash_read_message msg;
++		int ret;
++
++		memset(&msg, 0, sizeof(msg));
++
++		msg.buf = buf;
++		msg.from = from;
++		msg.len = len;
++		msg.read_opcode = nor->read_opcode;
++		msg.addr_width = nor->addr_width;
++		msg.dummy_bytes = dummy;
++		/* TODO: Support other combinations */
++		msg.opcode_nbits = SPI_NBITS_SINGLE;
++		msg.addr_nbits = SPI_NBITS_SINGLE;
++		msg.data_nbits = m25p80_rx_nbits(nor);
++
++		ret = spi_flash_read(spi, &msg);
++		*retlen = msg.retlen;
++		return ret;
++	}
++
+ 	spi_message_init(&m);
+ 	memset(t, 0, (sizeof t));
+ 
diff --git a/target/linux/generic/patches-4.4/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch b/target/linux/generic/patches-4.4/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch
new file mode 100644
index 0000000000..95de680989
--- /dev/null
+++ b/target/linux/generic/patches-4.4/046-ubifs-silence-error-output-if-MS_SILENT-is-set.patch
@@ -0,0 +1,32 @@
+From 1ae92642e5900316011736072b4fa91710840620 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 18 Jun 2016 17:53:45 +0200
+Subject: [PATCH] ubifs: Silence error output if MS_SILENT is set
+
+This change completes commit
+90bea5a3f0 ("UBIFS: respect MS_SILENT mount flag")
+which already implements support for MS_SILENT except for that one
+error message which is still being displayed despite MS_SILENT being
+set. Suppress that error message as well in case MS_SILENT is set.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+[rw: massaged commit message]
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ fs/ubifs/super.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -2107,8 +2107,9 @@ static struct dentry *ubifs_mount(struct
+ 	 */
+ 	ubi = open_ubi(name, UBI_READONLY);
+ 	if (IS_ERR(ubi)) {
+-		pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
+-		       current->pid, name, (int)PTR_ERR(ubi));
++		if (!(flags & MS_SILENT))
++			pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
++			       current->pid, name, (int)PTR_ERR(ubi));
+ 		return ERR_CAST(ubi);
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.4/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch b/target/linux/generic/patches-4.4/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch
new file mode 100644
index 0000000000..189b96c41c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/047-ubifs-silence-early-error-if-MS_SILENT-is-set.patch
@@ -0,0 +1,54 @@
+From dccbc9197d2c3614f2fd6811874e1d982e4415f0 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 19 Jul 2016 00:26:55 +0200
+Subject: [PATCH] ubifs: Silence early error messages if MS_SILENT is set
+
+Probe-mounting a volume too small for UBIFS results in kernel log
+polution which might irritate users.
+Address this by silencing errors which may happen during boot if the
+rootfs is e.g. squashfs (and thus rather small) stored on a UBI volume.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ fs/ubifs/super.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -520,19 +520,19 @@ static int init_constants_early(struct u
+ 	c->max_write_shift = fls(c->max_write_size) - 1;
+ 
+ 	if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+-		ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
+-			  c->leb_size, UBIFS_MIN_LEB_SZ);
++		ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
++			   c->leb_size, UBIFS_MIN_LEB_SZ);
+ 		return -EINVAL;
+ 	}
+ 
+ 	if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+-		ubifs_err(c, "too few LEBs (%d), min. is %d",
+-			  c->leb_cnt, UBIFS_MIN_LEB_CNT);
++		ubifs_errc(c, "too few LEBs (%d), min. is %d",
++			   c->leb_cnt, UBIFS_MIN_LEB_CNT);
+ 		return -EINVAL;
+ 	}
+ 
+ 	if (!is_power_of_2(c->min_io_size)) {
+-		ubifs_err(c, "bad min. I/O size %d", c->min_io_size);
++		ubifs_errc(c, "bad min. I/O size %d", c->min_io_size);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -543,8 +543,8 @@ static int init_constants_early(struct u
+ 	if (c->max_write_size < c->min_io_size ||
+ 	    c->max_write_size % c->min_io_size ||
+ 	    !is_power_of_2(c->max_write_size)) {
+-		ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
+-			  c->max_write_size, c->min_io_size);
++		ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
++			   c->max_write_size, c->min_io_size);
+ 		return -EINVAL;
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.4/050-backport_netfilter_rtcache.patch b/target/linux/generic/patches-4.4/050-backport_netfilter_rtcache.patch
new file mode 100644
index 0000000000..ddf5ba96b6
--- /dev/null
+++ b/target/linux/generic/patches-4.4/050-backport_netfilter_rtcache.patch
@@ -0,0 +1,531 @@
+Subject: netfilter: conntrack: cache route for forwarded connections
+
+... to avoid per-packet FIB lookup if possible.
+
+The cached dst is re-used provided the input interface
+is the same as that of the previous packet in the same direction.
+
+If not, the cached dst is invalidated.
+
+For ipv6 we also need to store sernum, else dst_check doesn't work,
+pointed out by Eric Dumazet.
+
+This should speed up forwarding when conntrack is already in use
+anyway, especially when using reverse path filtering -- active RPF
+enforces two FIB lookups for each packet.
+
+Before the routing cache removal this didn't matter since RPF was performed
+only when route cache didn't yield a result; but without route cache it
+comes at higher price.
+
+Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
+avoid holding on to dsts of 'frozen' conntracks.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+
+--- a/include/net/netfilter/nf_conntrack_extend.h
++++ b/include/net/netfilter/nf_conntrack_extend.h
+@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
+ #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
+ 	NF_CT_EXT_SYNPROXY,
+ #endif
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++	NF_CT_EXT_RTCACHE,
++#endif
+ 	NF_CT_EXT_NUM,
+ };
+ 
+@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
+ #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+ #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
+ #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
+ 
+ /* Extensions: optional stuff which isn't permanently in struct. */
+ struct nf_ct_ext {
+--- /dev/null
++++ b/include/net/netfilter/nf_conntrack_rtcache.h
+@@ -0,0 +1,34 @@
++#include <linux/gfp.h>
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++
++struct dst_entry;
++
++struct nf_conn_dst_cache {
++	struct dst_entry *dst;
++	int iif;
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	u32 cookie;
++#endif
++
++};
++
++struct nf_conn_rtcache {
++	struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
++};
++
++static inline
++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++	return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
++#else
++	return NULL;
++#endif
++}
++
++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
++					  enum ip_conntrack_dir dir)
++{
++	return rtc->cached_dst[dir].iif;
++}
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -114,6 +114,18 @@ config NF_CONNTRACK_EVENTS
+ 
+ 	  If unsure, say `N'.
+ 
++config NF_CONNTRACK_RTCACHE
++	tristate "Cache route entries in conntrack objects"
++	depends on NETFILTER_ADVANCED
++	depends on NF_CONNTRACK
++	help
++	  If this option is enabled, the connection tracking code will
++	  cache routing information for each connection that is being
++	  forwarded, at a cost of 32 bytes per conntrack object.
++
++	  To compile it as a module, choose M here.  If unsure, say N.
++	  The module will be called nf_conntrack_rtcache.
++
+ config NF_CONNTRACK_TIMEOUT
+ 	bool  'Connection tracking timeout'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -16,6 +16,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
+ # connection tracking
+ obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
+ 
++# optional conntrack route cache extension
++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
++
+ # SCTP protocol connection tracking
+ obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
+ obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
+--- /dev/null
++++ b/net/netfilter/nf_conntrack_rtcache.c
+@@ -0,0 +1,413 @@
++/* route cache for netfilter.
++ *
++ * (C) 2014 Red Hat GmbH
++ *
++ * 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.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/types.h>
++#include <linux/netfilter.h>
++#include <linux/skbuff.h>
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/export.h>
++#include <linux/module.h>
++
++#include <net/dst.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++#include <net/netfilter/nf_conntrack_rtcache.h>
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++#include <net/ip6_fib.h>
++#endif
++
++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
++				      enum ip_conntrack_dir dir)
++{
++	struct dst_entry *dst = rtc->cached_dst[dir].dst;
++
++	dst_release(dst);
++}
++
++static void nf_conn_rtcache_destroy(struct nf_conn *ct)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++	if (!rtc)
++		return;
++
++	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
++	__nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
++}
++
++static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
++{
++	struct nf_conn_rtcache *rtc;
++
++	rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
++	if (rtc) {
++		rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
++		rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
++		rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
++		rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
++	}
++}
++
++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
++{
++	if (nf_ct_is_untracked(ct))
++		return NULL;
++	return nf_ct_rtcache_find(ct);
++}
++
++static struct dst_entry *
++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
++			enum ip_conntrack_dir dir)
++{
++	return rtc->cached_dst[dir].dst;
++}
++
++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	if (pf == NFPROTO_IPV6) {
++		const struct rt6_info *rt = (const struct rt6_info *)dst;
++
++		if (rt->rt6i_node)
++			return (u32)rt->rt6i_node->fn_sernum;
++	}
++#endif
++	return 0;
++}
++
++static void nf_conn_rtcache_dst_set(int pf,
++				    struct nf_conn_rtcache *rtc,
++				    struct dst_entry *dst,
++				    enum ip_conntrack_dir dir, int iif)
++{
++	if (rtc->cached_dst[dir].iif != iif)
++		rtc->cached_dst[dir].iif = iif;
++
++	if (rtc->cached_dst[dir].dst != dst) {
++		struct dst_entry *old;
++
++		dst_hold(dst);
++
++		old = xchg(&rtc->cached_dst[dir].dst, dst);
++		dst_release(old);
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++		if (pf == NFPROTO_IPV6)
++			rtc->cached_dst[dir].cookie =
++				nf_rtcache_get_cookie(pf, dst);
++#endif
++	}
++}
++
++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
++					 enum ip_conntrack_dir dir)
++{
++	struct dst_entry *old;
++
++	pr_debug("Invalidate iif %d for dir %d on cache %p\n",
++		 rtc->cached_dst[dir].iif, dir, rtc);
++
++	old = xchg(&rtc->cached_dst[dir].dst, NULL);
++	dst_release(old);
++	rtc->cached_dst[dir].iif = -1;
++}
++
++static unsigned int nf_rtcache_in(u_int8_t pf,
++				  struct sk_buff *skb,
++				  const struct nf_hook_state *state)
++{
++	struct nf_conn_rtcache *rtc;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct dst_entry *dst;
++	struct nf_conn *ct;
++	int iif;
++	u32 cookie;
++
++	if (skb_dst(skb) || skb->sk)
++		return NF_ACCEPT;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return NF_ACCEPT;
++
++	rtc = nf_ct_rtcache_find_usable(ct);
++	if (!rtc)
++		return NF_ACCEPT;
++
++	/* if iif changes, don't use cache and let ip stack
++	 * do route lookup.
++	 *
++	 * If rp_filter is enabled it might toss skb, so
++	 * we don't want to avoid these checks.
++	 */
++	dir = CTINFO2DIR(ctinfo);
++	iif = nf_conn_rtcache_iif_get(rtc, dir);
++	if (state->in->ifindex != iif) {
++		pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
++			 ct, iif, state->in->ifindex);
++		return NF_ACCEPT;
++	}
++	dst = nf_conn_rtcache_dst_get(rtc, dir);
++	if (dst == NULL)
++		return NF_ACCEPT;
++
++	cookie = nf_rtcache_get_cookie(pf, dst);
++
++	dst = dst_check(dst, cookie);
++	pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
++	if (likely(dst))
++		skb_dst_set_noref(skb, dst);
++	else
++		nf_conn_rtcache_dst_obsolete(rtc, dir);
++
++	return NF_ACCEPT;
++}
++
++static unsigned int nf_rtcache_forward(u_int8_t pf,
++				       struct sk_buff *skb,
++				       const struct nf_hook_state *state)
++{
++	struct nf_conn_rtcache *rtc;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct nf_conn *ct;
++	struct dst_entry *dst = skb_dst(skb);
++	int iif;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (!ct)
++		return NF_ACCEPT;
++
++	if (dst && dst_xfrm(dst))
++		return NF_ACCEPT;
++
++	if (!nf_ct_is_confirmed(ct)) {
++		if (WARN_ON(nf_ct_rtcache_find(ct)))
++			return NF_ACCEPT;
++		nf_ct_rtcache_ext_add(ct);
++		return NF_ACCEPT;
++	}
++
++	rtc = nf_ct_rtcache_find_usable(ct);
++	if (!rtc)
++		return NF_ACCEPT;
++
++	dir = CTINFO2DIR(ctinfo);
++	iif = nf_conn_rtcache_iif_get(rtc, dir);
++	pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
++		 ct, skb, dir, iif, state->in->ifindex);
++	if (likely(state->in->ifindex == iif))
++		return NF_ACCEPT;
++
++	nf_conn_rtcache_dst_set(pf, rtc, skb_dst(skb), dir, state->in->ifindex);
++	return NF_ACCEPT;
++}
++
++static unsigned int nf_rtcache_in4(void *priv,
++				  struct sk_buff *skb,
++				  const struct nf_hook_state *state)
++{
++	return nf_rtcache_in(NFPROTO_IPV4, skb, state);
++}
++
++static unsigned int nf_rtcache_forward4(void *priv,
++				       struct sk_buff *skb,
++				       const struct nf_hook_state *state)
++{
++	return nf_rtcache_forward(NFPROTO_IPV4, skb, state);
++}
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++static unsigned int nf_rtcache_in6(void *priv,
++				  struct sk_buff *skb,
++				  const struct nf_hook_state *state)
++{
++	return nf_rtcache_in(NFPROTO_IPV6, skb, state);
++}
++
++static unsigned int nf_rtcache_forward6(void *priv,
++				       struct sk_buff *skb,
++				       const struct nf_hook_state *state)
++{
++ 	return nf_rtcache_forward(NFPROTO_IPV6, skb, state);
++}
++#endif
++
++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++	struct net_device *dev = data;
++
++	if (!rtc)
++		return 0;
++
++	if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
++	    dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
++		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
++		nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
++	}
++
++	return 0;
++}
++
++static int nf_rtcache_netdev_event(struct notifier_block *this,
++				   unsigned long event, void *ptr)
++{
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++	struct net *net = dev_net(dev);
++
++	if (event == NETDEV_DOWN)
++		nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
++
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block nf_rtcache_notifier = {
++	.notifier_call = nf_rtcache_netdev_event,
++};
++
++static struct nf_hook_ops rtcache_ops[] = {
++	{
++		.hook		= nf_rtcache_in4,
++		.pf		= NFPROTO_IPV4,
++		.hooknum	= NF_INET_PRE_ROUTING,
++		.priority       = NF_IP_PRI_LAST,
++	},
++	{
++		.hook           = nf_rtcache_forward4,
++		.pf             = NFPROTO_IPV4,
++		.hooknum        = NF_INET_FORWARD,
++		.priority       = NF_IP_PRI_LAST,
++	},
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++	{
++		.hook		= nf_rtcache_in6,
++		.pf		= NFPROTO_IPV6,
++		.hooknum	= NF_INET_PRE_ROUTING,
++		.priority       = NF_IP_PRI_LAST,
++	},
++	{
++		.hook           = nf_rtcache_forward6,
++		.pf             = NFPROTO_IPV6,
++		.hooknum        = NF_INET_FORWARD,
++		.priority       = NF_IP_PRI_LAST,
++	},
++#endif
++};
++
++static struct nf_ct_ext_type rtcache_extend __read_mostly = {
++	.len	= sizeof(struct nf_conn_rtcache),
++	.align	= __alignof__(struct nf_conn_rtcache),
++	.id	= NF_CT_EXT_RTCACHE,
++	.destroy = nf_conn_rtcache_destroy,
++};
++
++static int __init nf_conntrack_rtcache_init(void)
++{
++	int ret = nf_ct_extend_register(&rtcache_extend);
++
++	if (ret < 0) {
++		pr_err("nf_conntrack_rtcache: Unable to register extension\n");
++		return ret;
++	}
++
++	ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++	if (ret < 0) {
++		nf_ct_extend_unregister(&rtcache_extend);
++		return ret;
++	}
++
++	ret = register_netdevice_notifier(&nf_rtcache_notifier);
++	if (ret) {
++		nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++		nf_ct_extend_unregister(&rtcache_extend);
++	}
++
++	return ret;
++}
++
++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
++{
++	struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++	return rtc != NULL;
++}
++
++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
++{
++	bool wait = false;
++	int cpu;
++
++	for_each_possible_cpu(cpu) {
++		struct nf_conntrack_tuple_hash *h;
++		struct hlist_nulls_node *n;
++		struct nf_conn *ct;
++		struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
++
++		rcu_read_lock();
++		spin_lock_bh(&pcpu->lock);
++
++		hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
++			ct = nf_ct_tuplehash_to_ctrack(h);
++			if (nf_ct_rtcache_find(ct) != NULL) {
++				wait = true;
++				break;
++			}
++		}
++		spin_unlock_bh(&pcpu->lock);
++		rcu_read_unlock();
++	}
++
++	return wait;
++}
++
++static void __exit nf_conntrack_rtcache_fini(void)
++{
++	struct net *net;
++	int count = 0;
++
++	/* remove hooks so no new connections get rtcache extension */
++	nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
++
++	synchronize_net();
++
++	unregister_netdevice_notifier(&nf_rtcache_notifier);
++
++	rtnl_lock();
++
++	/* zap all conntracks with rtcache extension */
++	for_each_net(net)
++		nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
++
++	for_each_net(net) {
++		/* .. and make sure they're gone from dying list, too */
++		while (nf_conntrack_rtcache_wait_for_dying(net)) {
++			msleep(200);
++			WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
++		}
++	}
++
++	rtnl_unlock();
++	synchronize_net();
++	nf_ct_extend_unregister(&rtcache_extend);
++}
++module_init(nf_conntrack_rtcache_init);
++module_exit(nf_conntrack_rtcache_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
++MODULE_DESCRIPTION("Conntrack route cache extension");
diff --git a/target/linux/generic/patches-4.4/051-0001-ovl-rename-is_merge-to-is_lowest.patch b/target/linux/generic/patches-4.4/051-0001-ovl-rename-is_merge-to-is_lowest.patch
new file mode 100644
index 0000000000..79140b9008
--- /dev/null
+++ b/target/linux/generic/patches-4.4/051-0001-ovl-rename-is_merge-to-is_lowest.patch
@@ -0,0 +1,72 @@
+From 56656e960b555cb98bc414382566dcb59aae99a2 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 21 Mar 2016 17:31:46 +0100
+Subject: [PATCH] ovl: rename is_merge to is_lowest
+
+The 'is_merge' is an historical naming from when only a single lower layer
+could exist.  With the introduction of multiple lower layers the meaning of
+this flag was changed to mean only the "lowest layer" (while all lower
+layers were being merged).
+
+So now 'is_merge' is inaccurate and hence renaming to 'is_lowest'
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+---
+ fs/overlayfs/readdir.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/fs/overlayfs/readdir.c
++++ b/fs/overlayfs/readdir.c
+@@ -36,7 +36,7 @@ struct ovl_dir_cache {
+ 
+ struct ovl_readdir_data {
+ 	struct dir_context ctx;
+-	bool is_merge;
++	bool is_lowest;
+ 	struct rb_root root;
+ 	struct list_head *list;
+ 	struct list_head middle;
+@@ -139,9 +139,9 @@ static int ovl_cache_entry_add_rb(struct
+ 	return 0;
+ }
+ 
+-static int ovl_fill_lower(struct ovl_readdir_data *rdd,
+-			  const char *name, int namelen,
+-			  loff_t offset, u64 ino, unsigned int d_type)
++static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
++			   const char *name, int namelen,
++			   loff_t offset, u64 ino, unsigned int d_type)
+ {
+ 	struct ovl_cache_entry *p;
+ 
+@@ -193,10 +193,10 @@ static int ovl_fill_merge(struct dir_con
+ 		container_of(ctx, struct ovl_readdir_data, ctx);
+ 
+ 	rdd->count++;
+-	if (!rdd->is_merge)
++	if (!rdd->is_lowest)
+ 		return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
+ 	else
+-		return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type);
++		return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
+ }
+ 
+ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
+@@ -289,7 +289,7 @@ static int ovl_dir_read_merged(struct de
+ 		.ctx.actor = ovl_fill_merge,
+ 		.list = list,
+ 		.root = RB_ROOT,
+-		.is_merge = false,
++		.is_lowest = false,
+ 	};
+ 	int idx, next;
+ 
+@@ -306,7 +306,7 @@ static int ovl_dir_read_merged(struct de
+ 			 * allows offsets to be reasonably constant
+ 			 */
+ 			list_add(&rdd.middle, rdd.list);
+-			rdd.is_merge = true;
++			rdd.is_lowest = true;
+ 			err = ovl_dir_read(&realpath, &rdd);
+ 			list_del(&rdd.middle);
+ 		}
diff --git a/target/linux/generic/patches-4.4/051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch b/target/linux/generic/patches-4.4/051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch
new file mode 100644
index 0000000000..208bc61ec5
--- /dev/null
+++ b/target/linux/generic/patches-4.4/051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch
@@ -0,0 +1,336 @@
+From 3fe6e52f062643676eb4518d68cee3bc1272091b Mon Sep 17 00:00:00 2001
+From: Antonio Murdaca <amurdaca@redhat.com>
+Date: Thu, 7 Apr 2016 15:48:25 +0200
+Subject: [PATCH] ovl: override creds with the ones from the superblock mounter
+
+In user namespace the whiteout creation fails with -EPERM because the
+current process isn't capable(CAP_SYS_ADMIN) when setting xattr.
+
+A simple reproducer:
+
+$ mkdir upper lower work merged lower/dir
+$ sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
+$ unshare -m -p -f -U -r bash
+
+Now as root in the user namespace:
+
+\# touch merged/dir/{1,2,3} # this will force a copy up of lower/dir
+\# rm -fR merged/*
+
+This ends up failing with -EPERM after the files in dir has been
+correctly deleted:
+
+unlinkat(4, "2", 0)                     = 0
+unlinkat(4, "1", 0)                     = 0
+unlinkat(4, "3", 0)                     = 0
+close(4)                                = 0
+unlinkat(AT_FDCWD, "merged/dir", AT_REMOVEDIR) = -1 EPERM (Operation not
+permitted)
+
+Interestingly, if you don't place files in merged/dir you can remove it,
+meaning if upper/dir does not exist, creating the char device file works
+properly in that same location.
+
+This patch uses ovl_sb_creator_cred() to get the cred struct from the
+superblock mounter and override the old cred with these new ones so that
+the whiteout creation is possible because overlay is wrong in assuming that
+the creds it will get with prepare_creds will be in the initial user
+namespace.  The old cap_raise game is removed in favor of just overriding
+the old cred struct.
+
+This patch also drops from ovl_copy_up_one() the following two lines:
+
+override_cred->fsuid = stat->uid;
+override_cred->fsgid = stat->gid;
+
+This is because the correct uid and gid are taken directly with the stat
+struct and correctly set with ovl_set_attr().
+
+Signed-off-by: Antonio Murdaca <runcom@redhat.com>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+---
+ fs/overlayfs/copy_up.c   | 26 +------------------
+ fs/overlayfs/dir.c       | 67 ++++--------------------------------------------
+ fs/overlayfs/overlayfs.h |  1 +
+ fs/overlayfs/readdir.c   | 14 +++-------
+ fs/overlayfs/super.c     | 18 ++++++++++++-
+ 5 files changed, 27 insertions(+), 99 deletions(-)
+
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *paren
+ 	struct dentry *upperdir;
+ 	struct dentry *upperdentry;
+ 	const struct cred *old_cred;
+-	struct cred *override_cred;
+ 	char *link = NULL;
+ 
+ 	if (WARN_ON(!workdir))
+@@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *paren
+ 			return PTR_ERR(link);
+ 	}
+ 
+-	err = -ENOMEM;
+-	override_cred = prepare_creds();
+-	if (!override_cred)
+-		goto out_free_link;
+-
+-	override_cred->fsuid = stat->uid;
+-	override_cred->fsgid = stat->gid;
+-	/*
+-	 * CAP_SYS_ADMIN for copying up extended attributes
+-	 * CAP_DAC_OVERRIDE for create
+-	 * CAP_FOWNER for chmod, timestamp update
+-	 * CAP_FSETID for chmod
+-	 * CAP_CHOWN for chown
+-	 * CAP_MKNOD for mknod
+-	 */
+-	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
+-	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
+-	cap_raise(override_cred->cap_effective, CAP_FOWNER);
+-	cap_raise(override_cred->cap_effective, CAP_FSETID);
+-	cap_raise(override_cred->cap_effective, CAP_CHOWN);
+-	cap_raise(override_cred->cap_effective, CAP_MKNOD);
+-	old_cred = override_creds(override_cred);
++	old_cred = ovl_override_creds(dentry->d_sb);
+ 
+ 	err = -EIO;
+ 	if (lock_rename(workdir, upperdir) != NULL) {
+@@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *paren
+ out_unlock:
+ 	unlock_rename(workdir, upperdir);
+ 	revert_creds(old_cred);
+-	put_cred(override_cred);
+ 
+-out_free_link:
+ 	if (link)
+ 		free_page((unsigned long) link);
+ 
+--- a/fs/overlayfs/dir.c
++++ b/fs/overlayfs/dir.c
+@@ -408,28 +408,13 @@ static int ovl_create_or_link(struct den
+ 		err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
+ 	} else {
+ 		const struct cred *old_cred;
+-		struct cred *override_cred;
+ 
+-		err = -ENOMEM;
+-		override_cred = prepare_creds();
+-		if (!override_cred)
+-			goto out_iput;
+-
+-		/*
+-		 * CAP_SYS_ADMIN for setting opaque xattr
+-		 * CAP_DAC_OVERRIDE for create in workdir, rename
+-		 * CAP_FOWNER for removing whiteout from sticky dir
+-		 */
+-		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
+-		cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
+-		cap_raise(override_cred->cap_effective, CAP_FOWNER);
+-		old_cred = override_creds(override_cred);
++		old_cred = ovl_override_creds(dentry->d_sb);
+ 
+ 		err = ovl_create_over_whiteout(dentry, inode, &stat, link,
+ 					       hardlink);
+ 
+ 		revert_creds(old_cred);
+-		put_cred(override_cred);
+ 	}
+ 
+ 	if (!err)
+@@ -659,32 +644,11 @@ static int ovl_do_remove(struct dentry *
+ 	if (OVL_TYPE_PURE_UPPER(type)) {
+ 		err = ovl_remove_upper(dentry, is_dir);
+ 	} else {
+-		const struct cred *old_cred;
+-		struct cred *override_cred;
+-
+-		err = -ENOMEM;
+-		override_cred = prepare_creds();
+-		if (!override_cred)
+-			goto out_drop_write;
+-
+-		/*
+-		 * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
+-		 * CAP_DAC_OVERRIDE for create in workdir, rename
+-		 * CAP_FOWNER for removing whiteout from sticky dir
+-		 * CAP_FSETID for chmod of opaque dir
+-		 * CAP_CHOWN for chown of opaque dir
+-		 */
+-		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
+-		cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
+-		cap_raise(override_cred->cap_effective, CAP_FOWNER);
+-		cap_raise(override_cred->cap_effective, CAP_FSETID);
+-		cap_raise(override_cred->cap_effective, CAP_CHOWN);
+-		old_cred = override_creds(override_cred);
++		const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
+ 
+ 		err = ovl_remove_and_whiteout(dentry, is_dir);
+ 
+ 		revert_creds(old_cred);
+-		put_cred(override_cred);
+ 	}
+ out_drop_write:
+ 	ovl_drop_write(dentry);
+@@ -723,7 +687,6 @@ static int ovl_rename2(struct inode *old
+ 	bool new_is_dir = false;
+ 	struct dentry *opaquedir = NULL;
+ 	const struct cred *old_cred = NULL;
+-	struct cred *override_cred = NULL;
+ 
+ 	err = -EINVAL;
+ 	if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
+@@ -792,26 +755,8 @@ static int ovl_rename2(struct inode *old
+ 	old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
+ 	new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
+ 
+-	if (old_opaque || new_opaque) {
+-		err = -ENOMEM;
+-		override_cred = prepare_creds();
+-		if (!override_cred)
+-			goto out_drop_write;
+-
+-		/*
+-		 * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
+-		 * CAP_DAC_OVERRIDE for create in workdir
+-		 * CAP_FOWNER for removing whiteout from sticky dir
+-		 * CAP_FSETID for chmod of opaque dir
+-		 * CAP_CHOWN for chown of opaque dir
+-		 */
+-		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
+-		cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
+-		cap_raise(override_cred->cap_effective, CAP_FOWNER);
+-		cap_raise(override_cred->cap_effective, CAP_FSETID);
+-		cap_raise(override_cred->cap_effective, CAP_CHOWN);
+-		old_cred = override_creds(override_cred);
+-	}
++	if (old_opaque || new_opaque)
++		old_cred = ovl_override_creds(old->d_sb);
+ 
+ 	if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
+ 		opaquedir = ovl_check_empty_and_clear(new);
+@@ -942,10 +887,8 @@ out_dput_old:
+ out_unlock:
+ 	unlock_rename(new_upperdir, old_upperdir);
+ out_revert_creds:
+-	if (old_opaque || new_opaque) {
++	if (old_opaque || new_opaque)
+ 		revert_creds(old_cred);
+-		put_cred(override_cred);
+-	}
+ out_drop_write:
+ 	ovl_drop_write(old);
+ out:
+--- a/fs/overlayfs/overlayfs.h
++++ b/fs/overlayfs/overlayfs.h
+@@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentr
+ bool ovl_dentry_is_opaque(struct dentry *dentry);
+ void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
+ bool ovl_is_whiteout(struct dentry *dentry);
++const struct cred *ovl_override_creds(struct super_block *sb);
+ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
+ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
+ 			  unsigned int flags);
+--- a/fs/overlayfs/readdir.c
++++ b/fs/overlayfs/readdir.c
+@@ -36,6 +36,7 @@ struct ovl_dir_cache {
+ 
+ struct ovl_readdir_data {
+ 	struct dir_context ctx;
++	struct dentry *dentry;
+ 	bool is_lowest;
+ 	struct rb_root root;
+ 	struct list_head *list;
+@@ -205,17 +206,8 @@ static int ovl_check_whiteouts(struct de
+ 	struct ovl_cache_entry *p;
+ 	struct dentry *dentry;
+ 	const struct cred *old_cred;
+-	struct cred *override_cred;
+-
+-	override_cred = prepare_creds();
+-	if (!override_cred)
+-		return -ENOMEM;
+ 
+-	/*
+-	 * CAP_DAC_OVERRIDE for lookup
+-	 */
+-	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
+-	old_cred = override_creds(override_cred);
++	old_cred = ovl_override_creds(rdd->dentry->d_sb);
+ 
+ 	err = mutex_lock_killable(&dir->d_inode->i_mutex);
+ 	if (!err) {
+@@ -231,7 +223,6 @@ static int ovl_check_whiteouts(struct de
+ 		mutex_unlock(&dir->d_inode->i_mutex);
+ 	}
+ 	revert_creds(old_cred);
+-	put_cred(override_cred);
+ 
+ 	return err;
+ }
+@@ -287,6 +278,7 @@ static int ovl_dir_read_merged(struct de
+ 	struct path realpath;
+ 	struct ovl_readdir_data rdd = {
+ 		.ctx.actor = ovl_fill_merge,
++		.dentry = dentry,
+ 		.list = list,
+ 		.root = RB_ROOT,
+ 		.is_lowest = false,
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -42,6 +42,8 @@ struct ovl_fs {
+ 	long lower_namelen;
+ 	/* pathnames of lower and upper dirs, for show_options */
+ 	struct ovl_config config;
++	/* creds of process who forced instantiation of super block */
++	const struct cred *creator_cred;
+ };
+ 
+ struct ovl_dir_cache;
+@@ -246,6 +248,13 @@ bool ovl_is_whiteout(struct dentry *dent
+ 	return inode && IS_WHITEOUT(inode);
+ }
+ 
++const struct cred *ovl_override_creds(struct super_block *sb)
++{
++	struct ovl_fs *ofs = sb->s_fs_info;
++
++	return override_creds(ofs->creator_cred);
++}
++
+ static bool ovl_is_opaquedir(struct dentry *dentry)
+ {
+ 	int res;
+@@ -587,6 +596,7 @@ static void ovl_put_super(struct super_b
+ 	kfree(ufs->config.lowerdir);
+ 	kfree(ufs->config.upperdir);
+ 	kfree(ufs->config.workdir);
++	put_cred(ufs->creator_cred);
+ 	kfree(ufs);
+ }
+ 
+@@ -1087,10 +1097,14 @@ static int ovl_fill_super(struct super_b
+ 	else
+ 		sb->s_d_op = &ovl_dentry_operations;
+ 
++	ufs->creator_cred = prepare_creds();
++	if (!ufs->creator_cred)
++		goto out_put_lower_mnt;
++
+ 	err = -ENOMEM;
+ 	oe = ovl_alloc_entry(numlower);
+ 	if (!oe)
+-		goto out_put_lower_mnt;
++		goto out_put_cred;
+ 
+ 	root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
+ 	if (!root_dentry)
+@@ -1123,6 +1137,8 @@ static int ovl_fill_super(struct super_b
+ 
+ out_free_oe:
+ 	kfree(oe);
++out_put_cred:
++	put_cred(ufs->creator_cred);
+ out_put_lower_mnt:
+ 	for (i = 0; i < ufs->numlower; i++)
+ 		mntput(ufs->lower_mnt[i]);
diff --git a/target/linux/generic/patches-4.4/051-0005-ovl-proper-cleanup-of-workdir.patch b/target/linux/generic/patches-4.4/051-0005-ovl-proper-cleanup-of-workdir.patch
new file mode 100644
index 0000000000..eb095b7a2e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/051-0005-ovl-proper-cleanup-of-workdir.patch
@@ -0,0 +1,131 @@
+From eea2fb4851e9dcbab6b991aaf47e2e024f1f55a0 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Thu, 1 Sep 2016 11:11:59 +0200
+Subject: [PATCH] ovl: proper cleanup of workdir
+
+When mounting overlayfs it needs a clean "work" directory under the
+supplied workdir.
+
+Previously the mount code removed this directory if it already existed and
+created a new one.  If the removal failed (e.g. directory was not empty)
+then it fell back to a read-only mount not using the workdir.
+
+While this has never been reported, it is possible to get a non-empty
+"work" dir from a previous mount of overlayfs in case of crash in the
+middle of an operation using the work directory.
+
+In this case the left over state should be discarded and the overlay
+filesystem will be consistent, guaranteed by the atomicity of operations on
+moving to/from the workdir to the upper layer.
+
+This patch implements cleaning out any files left in workdir.  It is
+implemented using real recursion for simplicity, but the depth is limited
+to 2, because the worst case is that of a directory containing whiteouts
+under "work".
+
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Cc: <stable@vger.kernel.org>
+---
+ fs/overlayfs/overlayfs.h |  2 ++
+ fs/overlayfs/readdir.c   | 63 +++++++++++++++++++++++++++++++++++++++++++++++-
+ fs/overlayfs/super.c     |  2 +-
+ 3 files changed, 65 insertions(+), 2 deletions(-)
+
+--- a/fs/overlayfs/overlayfs.h
++++ b/fs/overlayfs/overlayfs.h
+@@ -164,6 +164,8 @@ extern const struct file_operations ovl_
+ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
+ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
+ void ovl_cache_free(struct list_head *list);
++void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
++			 struct dentry *dentry, int level);
+ 
+ /* inode.c */
+ int ovl_setattr(struct dentry *dentry, struct iattr *attr);
+--- a/fs/overlayfs/readdir.c
++++ b/fs/overlayfs/readdir.c
+@@ -247,7 +247,7 @@ static inline int ovl_dir_read(struct pa
+ 			err = rdd->err;
+ 	} while (!err && rdd->count);
+ 
+-	if (!err && rdd->first_maybe_whiteout)
++	if (!err && rdd->first_maybe_whiteout && rdd->dentry)
+ 		err = ovl_check_whiteouts(realpath->dentry, rdd);
+ 
+ 	fput(realfile);
+@@ -569,3 +569,64 @@ void ovl_cleanup_whiteouts(struct dentry
+ 	}
+ 	mutex_unlock(&upper->d_inode->i_mutex);
+ }
++
++static void ovl_workdir_cleanup_recurse(struct path *path, int level)
++{
++	int err;
++	struct inode *dir = path->dentry->d_inode;
++	LIST_HEAD(list);
++	struct ovl_cache_entry *p;
++	struct ovl_readdir_data rdd = {
++		.ctx.actor = ovl_fill_merge,
++		.dentry = NULL,
++		.list = &list,
++		.root = RB_ROOT,
++		.is_lowest = false,
++	};
++
++	err = ovl_dir_read(path, &rdd);
++	if (err)
++		goto out;
++
++	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
++	list_for_each_entry(p, &list, l_node) {
++		struct dentry *dentry;
++
++		if (p->name[0] == '.') {
++			if (p->len == 1)
++				continue;
++			if (p->len == 2 && p->name[1] == '.')
++				continue;
++		}
++		dentry = lookup_one_len(p->name, path->dentry, p->len);
++		if (IS_ERR(dentry))
++			continue;
++		if (dentry->d_inode)
++			ovl_workdir_cleanup(dir, path->mnt, dentry, level);
++		dput(dentry);
++	}
++	mutex_unlock(&dir->i_mutex);
++out:
++	ovl_cache_free(&list);
++}
++
++void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
++			 struct dentry *dentry, int level)
++{
++	int err;
++
++	if (!d_is_dir(dentry) || level > 1) {
++		ovl_cleanup(dir, dentry);
++		return;
++	}
++
++	err = ovl_do_rmdir(dir, dentry);
++	if (err) {
++		struct path path = { .mnt = mnt, .dentry = dentry };
++
++		mutex_unlock(&dir->i_mutex);
++		ovl_workdir_cleanup_recurse(&path, level + 1);
++		mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
++		ovl_cleanup(dir, dentry);
++	}
++}
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -784,7 +784,7 @@ retry:
+ 				goto out_dput;
+ 
+ 			retried = true;
+-			ovl_cleanup(dir, work);
++			ovl_workdir_cleanup(dir, mnt, work, 0);
+ 			dput(work);
+ 			goto retry;
+ 		}
diff --git a/target/linux/generic/patches-4.4/052-01-ubifs-Implement-O_TMPFILE.patch b/target/linux/generic/patches-4.4/052-01-ubifs-Implement-O_TMPFILE.patch
new file mode 100644
index 0000000000..1c55a89acf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/052-01-ubifs-Implement-O_TMPFILE.patch
@@ -0,0 +1,99 @@
+From: Richard Weinberger <richard@nod.at>
+Date: Tue, 13 Sep 2016 16:18:55 +0200
+Subject: [PATCH] ubifs: Implement O_TMPFILE
+
+This patchs adds O_TMPFILE support to UBIFS.
+A temp file is a reference to an unlinked inode, a user
+holding the reference can use it. As soon it is being closed
+all data vanishes.
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -301,6 +301,76 @@ out_budg:
+ 	return err;
+ }
+ 
++static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
++			 umode_t mode)
++{
++	struct inode *inode;
++	struct ubifs_info *c = dir->i_sb->s_fs_info;
++	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1};
++	struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
++	struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
++	int err, instantiated = 0;
++
++	/*
++	 * Budget request settings: new dirty inode, new direntry,
++	 * budget for dirtied inode will be released via writeback.
++	 */
++
++	dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
++		dentry, mode, dir->i_ino);
++
++	err = ubifs_budget_space(c, &req);
++	if (err)
++		return err;
++
++	err = ubifs_budget_space(c, &ino_req);
++	if (err) {
++		ubifs_release_budget(c, &req);
++		return err;
++	}
++
++	inode = ubifs_new_inode(c, dir, mode);
++	if (IS_ERR(inode)) {
++		err = PTR_ERR(inode);
++		goto out_budg;
++	}
++	ui = ubifs_inode(inode);
++
++	err = ubifs_init_security(dir, inode, &dentry->d_name);
++	if (err)
++		goto out_inode;
++
++	mutex_lock(&ui->ui_mutex);
++	insert_inode_hash(inode);
++	d_tmpfile(dentry, inode);
++	ubifs_assert(ui->dirty);
++	instantiated = 1;
++	mutex_unlock(&ui->ui_mutex);
++
++	mutex_lock(&dir_ui->ui_mutex);
++	err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
++	if (err)
++		goto out_cancel;
++	mutex_unlock(&dir_ui->ui_mutex);
++
++	ubifs_release_budget(c, &req);
++
++	return 0;
++
++out_cancel:
++	mutex_unlock(&dir_ui->ui_mutex);
++out_inode:
++	make_bad_inode(inode);
++	if (!instantiated)
++		iput(inode);
++out_budg:
++	ubifs_release_budget(c, &req);
++	if (!instantiated)
++		ubifs_release_budget(c, &ino_req);
++	ubifs_err(c, "cannot create temporary file, error %d", err);
++	return err;
++}
++
+ /**
+  * vfs_dent_type - get VFS directory entry type.
+  * @type: UBIFS directory entry type
+@@ -1195,6 +1265,7 @@ const struct inode_operations ubifs_dir_
+ #ifdef CONFIG_UBIFS_ATIME_SUPPORT
+ 	.update_time = ubifs_update_time,
+ #endif
++	.tmpfile     = ubifs_tmpfile,
+ };
+ 
+ const struct file_operations ubifs_dir_operations = {
diff --git a/target/linux/generic/patches-4.4/052-02-ubifs-Implement-RENAME_WHITEOUT.patch b/target/linux/generic/patches-4.4/052-02-ubifs-Implement-RENAME_WHITEOUT.patch
new file mode 100644
index 0000000000..c2ec904939
--- /dev/null
+++ b/target/linux/generic/patches-4.4/052-02-ubifs-Implement-RENAME_WHITEOUT.patch
@@ -0,0 +1,343 @@
+From: Richard Weinberger <richard@nod.at>
+Date: Tue, 13 Sep 2016 16:18:56 +0200
+Subject: [PATCH] ubifs: Implement RENAME_WHITEOUT
+
+Adds RENAME_WHITEOUT support to UBIFS, we implement
+it in the same way as ext4 and xfs do.
+For an overview of other ways to implement it please
+refere to commit 7dcf5c3e4527 ("xfs: add RENAME_WHITEOUT support").
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -301,8 +301,8 @@ out_budg:
+ 	return err;
+ }
+ 
+-static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
+-			 umode_t mode)
++static int do_tmpfile(struct inode *dir, struct dentry *dentry,
++		      umode_t mode, struct inode **whiteout)
+ {
+ 	struct inode *inode;
+ 	struct ubifs_info *c = dir->i_sb->s_fs_info;
+@@ -336,14 +336,27 @@ static int ubifs_tmpfile(struct inode *d
+ 	}
+ 	ui = ubifs_inode(inode);
+ 
++	if (whiteout) {
++		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
++		ubifs_assert(inode->i_op == &ubifs_file_inode_operations);
++	}
++
+ 	err = ubifs_init_security(dir, inode, &dentry->d_name);
+ 	if (err)
+ 		goto out_inode;
+ 
+ 	mutex_lock(&ui->ui_mutex);
+ 	insert_inode_hash(inode);
+-	d_tmpfile(dentry, inode);
++
++	if (whiteout) {
++		mark_inode_dirty(inode);
++		drop_nlink(inode);
++		*whiteout = inode;
++	} else {
++		d_tmpfile(dentry, inode);
++	}
+ 	ubifs_assert(ui->dirty);
++
+ 	instantiated = 1;
+ 	mutex_unlock(&ui->ui_mutex);
+ 
+@@ -371,6 +384,12 @@ out_budg:
+ 	return err;
+ }
+ 
++static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
++			 umode_t mode)
++{
++	return do_tmpfile(dir, dentry, mode, NULL);
++}
++
+ /**
+  * vfs_dent_type - get VFS directory entry type.
+  * @type: UBIFS directory entry type
+@@ -1003,37 +1022,43 @@ out_budg:
+ }
+ 
+ /**
+- * lock_3_inodes - a wrapper for locking three UBIFS inodes.
++ * lock_4_inodes - a wrapper for locking three UBIFS inodes.
+  * @inode1: first inode
+  * @inode2: second inode
+  * @inode3: third inode
++ * @inode4: fouth inode
+  *
+  * This function is used for 'ubifs_rename()' and @inode1 may be the same as
+- * @inode2 whereas @inode3 may be %NULL.
++ * @inode2 whereas @inode3 and @inode4 may be %NULL.
+  *
+  * We do not implement any tricks to guarantee strict lock ordering, because
+  * VFS has already done it for us on the @i_mutex. So this is just a simple
+  * wrapper function.
+  */
+-static void lock_3_inodes(struct inode *inode1, struct inode *inode2,
+-			  struct inode *inode3)
++static void lock_4_inodes(struct inode *inode1, struct inode *inode2,
++			  struct inode *inode3, struct inode *inode4)
+ {
+ 	mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
+ 	if (inode2 != inode1)
+ 		mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
+ 	if (inode3)
+ 		mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3);
++	if (inode4)
++		mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4);
+ }
+ 
+ /**
+- * unlock_3_inodes - a wrapper for unlocking three UBIFS inodes for rename.
++ * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename.
+  * @inode1: first inode
+  * @inode2: second inode
+  * @inode3: third inode
++ * @inode4: fouth inode
+  */
+-static void unlock_3_inodes(struct inode *inode1, struct inode *inode2,
+-			    struct inode *inode3)
++static void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
++			    struct inode *inode3, struct inode *inode4)
+ {
++	if (inode4)
++		mutex_unlock(&ubifs_inode(inode4)->ui_mutex);
+ 	if (inode3)
+ 		mutex_unlock(&ubifs_inode(inode3)->ui_mutex);
+ 	if (inode1 != inode2)
+@@ -1042,12 +1067,15 @@ static void unlock_3_inodes(struct inode
+ }
+ 
+ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
+-			struct inode *new_dir, struct dentry *new_dentry)
++			struct inode *new_dir, struct dentry *new_dentry,
++			unsigned int flags)
+ {
+ 	struct ubifs_info *c = old_dir->i_sb->s_fs_info;
+ 	struct inode *old_inode = d_inode(old_dentry);
+ 	struct inode *new_inode = d_inode(new_dentry);
++	struct inode *whiteout = NULL;
+ 	struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode);
++	struct ubifs_inode *whiteout_ui = NULL;
+ 	int err, release, sync = 0, move = (new_dir != old_dir);
+ 	int is_dir = S_ISDIR(old_inode->i_mode);
+ 	int unlink = !!new_inode;
+@@ -1069,9 +1097,13 @@ static int ubifs_rename(struct inode *ol
+ 	 * separately.
+ 	 */
+ 
+-	dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu",
++	dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x",
+ 		old_dentry, old_inode->i_ino, old_dir->i_ino,
+-		new_dentry, new_dir->i_ino);
++		new_dentry, new_dir->i_ino, flags);
++
++	if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT))
++		return -EINVAL;
++
+ 	ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
+ 	ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
+ 	if (unlink)
+@@ -1093,7 +1125,32 @@ static int ubifs_rename(struct inode *ol
+ 		return err;
+ 	}
+ 
+-	lock_3_inodes(old_dir, new_dir, new_inode);
++	if (flags & RENAME_WHITEOUT) {
++		union ubifs_dev_desc *dev = NULL;
++
++		dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
++		if (!dev) {
++			ubifs_release_budget(c, &req);
++			ubifs_release_budget(c, &ino_req);
++			return -ENOMEM;
++		}
++
++		err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout);
++		if (err) {
++			ubifs_release_budget(c, &req);
++			ubifs_release_budget(c, &ino_req);
++			kfree(dev);
++			return err;
++		}
++
++		whiteout->i_state |= I_LINKABLE;
++		whiteout_ui = ubifs_inode(whiteout);
++		whiteout_ui->data = dev;
++		whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0));
++		ubifs_assert(!whiteout_ui->dirty);
++	}
++
++	lock_4_inodes(old_dir, new_dir, new_inode, whiteout);
+ 
+ 	/*
+ 	 * Like most other Unix systems, set the @i_ctime for inodes on a
+@@ -1163,12 +1220,34 @@ static int ubifs_rename(struct inode *ol
+ 		if (unlink && IS_SYNC(new_inode))
+ 			sync = 1;
+ 	}
+-	err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry,
++
++	if (whiteout) {
++		struct ubifs_budget_req wht_req = { .dirtied_ino = 1,
++				.dirtied_ino_d = \
++				ALIGN(ubifs_inode(whiteout)->data_len, 8) };
++
++		err = ubifs_budget_space(c, &wht_req);
++		if (err) {
++			ubifs_release_budget(c, &req);
++			ubifs_release_budget(c, &ino_req);
++			kfree(whiteout_ui->data);
++			whiteout_ui->data_len = 0;
++			iput(whiteout);
++			return err;
++		}
++
++		inc_nlink(whiteout);
++		mark_inode_dirty(whiteout);
++		whiteout->i_state &= ~I_LINKABLE;
++		iput(whiteout);
++	}
++
++	err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, whiteout,
+ 			       sync);
+ 	if (err)
+ 		goto out_cancel;
+ 
+-	unlock_3_inodes(old_dir, new_dir, new_inode);
++	unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
+ 	ubifs_release_budget(c, &req);
+ 
+ 	mutex_lock(&old_inode_ui->ui_mutex);
+@@ -1201,7 +1280,11 @@ out_cancel:
+ 				inc_nlink(old_dir);
+ 		}
+ 	}
+-	unlock_3_inodes(old_dir, new_dir, new_inode);
++	if (whiteout) {
++		drop_nlink(whiteout);
++		iput(whiteout);
++	}
++	unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
+ 	ubifs_release_budget(c, &ino_req);
+ 	ubifs_release_budget(c, &req);
+ 	return err;
+@@ -1255,7 +1338,7 @@ const struct inode_operations ubifs_dir_
+ 	.mkdir       = ubifs_mkdir,
+ 	.rmdir       = ubifs_rmdir,
+ 	.mknod       = ubifs_mknod,
+-	.rename      = ubifs_rename,
++	.rename2     = ubifs_rename,
+ 	.setattr     = ubifs_setattr,
+ 	.getattr     = ubifs_getattr,
+ 	.setxattr    = ubifs_setxattr,
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -917,14 +917,15 @@ int ubifs_jnl_delete_inode(struct ubifs_
+  * @sync: non-zero if the write-buffer has to be synchronized
+  *
+  * This function implements the re-name operation which may involve writing up
+- * to 3 inodes and 2 directory entries. It marks the written inodes as clean
++ * to 4 inodes and 2 directory entries. It marks the written inodes as clean
+  * and returns zero on success. In case of failure, a negative error code is
+  * returned.
+  */
+ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
+ 		     const struct dentry *old_dentry,
+ 		     const struct inode *new_dir,
+-		     const struct dentry *new_dentry, int sync)
++		     const struct dentry *new_dentry,
++		     const struct inode *whiteout, int sync)
+ {
+ 	void *p;
+ 	union ubifs_key key;
+@@ -980,13 +981,19 @@ int ubifs_jnl_rename(struct ubifs_info *
+ 	zero_dent_node_unused(dent);
+ 	ubifs_prep_grp_node(c, dent, dlen1, 0);
+ 
+-	/* Make deletion dent */
+ 	dent2 = (void *)dent + aligned_dlen1;
+ 	dent2->ch.node_type = UBIFS_DENT_NODE;
+ 	dent_key_init_flash(c, &dent2->key, old_dir->i_ino,
+ 			    &old_dentry->d_name);
+-	dent2->inum = 0;
+-	dent2->type = DT_UNKNOWN;
++
++	if (whiteout) {
++		dent2->inum = cpu_to_le64(whiteout->i_ino);
++		dent2->type = get_dent_type(whiteout->i_mode);
++	} else {
++		/* Make deletion dent */
++		dent2->inum = 0;
++		dent2->type = DT_UNKNOWN;
++	}
+ 	dent2->nlen = cpu_to_le16(old_dentry->d_name.len);
+ 	memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len);
+ 	dent2->name[old_dentry->d_name.len] = '\0';
+@@ -1035,16 +1042,26 @@ int ubifs_jnl_rename(struct ubifs_info *
+ 	if (err)
+ 		goto out_ro;
+ 
+-	err = ubifs_add_dirt(c, lnum, dlen2);
+-	if (err)
+-		goto out_ro;
+-
+-	dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
+-	err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
+-	if (err)
+-		goto out_ro;
++	offs += aligned_dlen1;
++	if (whiteout) {
++		dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
++		err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &old_dentry->d_name);
++		if (err)
++			goto out_ro;
++
++		ubifs_delete_orphan(c, whiteout->i_ino);
++	} else {
++		err = ubifs_add_dirt(c, lnum, dlen2);
++		if (err)
++			goto out_ro;
++
++		dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
++		err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
++		if (err)
++			goto out_ro;
++	}
+ 
+-	offs += aligned_dlen1 + aligned_dlen2;
++	offs += aligned_dlen2;
+ 	if (new_inode) {
+ 		ino_key_init(c, &key, new_inode->i_ino);
+ 		err = ubifs_tnc_add(c, &key, lnum, offs, ilen);
+--- a/fs/ubifs/ubifs.h
++++ b/fs/ubifs/ubifs.h
+@@ -180,6 +180,7 @@ enum {
+ 	WB_MUTEX_1 = 0,
+ 	WB_MUTEX_2 = 1,
+ 	WB_MUTEX_3 = 2,
++	WB_MUTEX_4 = 3,
+ };
+ 
+ /*
+@@ -1546,7 +1547,8 @@ int ubifs_jnl_delete_inode(struct ubifs_
+ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
+ 		     const struct dentry *old_dentry,
+ 		     const struct inode *new_dir,
+-		     const struct dentry *new_dentry, int sync);
++		     const struct dentry *new_dentry,
++		     const struct inode *whiteout, int sync);
+ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
+ 		       loff_t old_size, loff_t new_size);
+ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
diff --git a/target/linux/generic/patches-4.4/052-03-ubifs-Implement-RENAME_EXCHANGE.patch b/target/linux/generic/patches-4.4/052-03-ubifs-Implement-RENAME_EXCHANGE.patch
new file mode 100644
index 0000000000..1830cd0eeb
--- /dev/null
+++ b/target/linux/generic/patches-4.4/052-03-ubifs-Implement-RENAME_EXCHANGE.patch
@@ -0,0 +1,267 @@
+From: Richard Weinberger <richard@nod.at>
+Date: Tue, 13 Sep 2016 16:18:57 +0200
+Subject: [PATCH] ubifs: Implement RENAME_EXCHANGE
+
+Adds RENAME_EXCHANGE to UBIFS, the operation itself
+is completely disjunct from a regular rename() that's
+why we dispatch very early in ubifs_reaname().
+
+RENAME_EXCHANGE used by the renameat2() system call
+allows the caller to exchange two paths atomically.
+Both paths have to exist and have to be on the same
+filesystem.
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -1101,11 +1101,6 @@ static int ubifs_rename(struct inode *ol
+ 		old_dentry, old_inode->i_ino, old_dir->i_ino,
+ 		new_dentry, new_dir->i_ino, flags);
+ 
+-	if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT))
+-		return -EINVAL;
+-
+-	ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
+-	ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
+ 	if (unlink)
+ 		ubifs_assert(mutex_is_locked(&new_inode->i_mutex));
+ 
+@@ -1290,6 +1285,64 @@ out_cancel:
+ 	return err;
+ }
+ 
++static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
++			struct inode *new_dir, struct dentry *new_dentry)
++{
++	struct ubifs_info *c = old_dir->i_sb->s_fs_info;
++	struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
++				.dirtied_ino = 2 };
++	int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir);
++	struct inode *fst_inode = d_inode(old_dentry);
++	struct inode *snd_inode = d_inode(new_dentry);
++	struct timespec time;
++	int err;
++
++	ubifs_assert(fst_inode && snd_inode);
++
++	lock_4_inodes(old_dir, new_dir, NULL, NULL);
++
++	time = ubifs_current_time(old_dir);
++	fst_inode->i_ctime = time;
++	snd_inode->i_ctime = time;
++	old_dir->i_mtime = old_dir->i_ctime = time;
++	new_dir->i_mtime = new_dir->i_ctime = time;
++
++	if (old_dir != new_dir) {
++		if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
++			inc_nlink(new_dir);
++			drop_nlink(old_dir);
++		}
++		else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
++			drop_nlink(new_dir);
++			inc_nlink(old_dir);
++		}
++	}
++
++	err = ubifs_jnl_xrename(c, old_dir, old_dentry, new_dir, new_dentry,
++				sync);
++
++	unlock_4_inodes(old_dir, new_dir, NULL, NULL);
++	ubifs_release_budget(c, &req);
++
++	return err;
++}
++
++static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry,
++			struct inode *new_dir, struct dentry *new_dentry,
++			unsigned int flags)
++{
++	if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE))
++		return -EINVAL;
++
++	ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
++	ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
++
++	if (flags & RENAME_EXCHANGE)
++		return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry);
++
++	return ubifs_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
++}
++
+ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ 		  struct kstat *stat)
+ {
+@@ -1338,7 +1391,7 @@ const struct inode_operations ubifs_dir_
+ 	.mkdir       = ubifs_mkdir,
+ 	.rmdir       = ubifs_rmdir,
+ 	.mknod       = ubifs_mknod,
+-	.rename2     = ubifs_rename,
++	.rename2     = ubifs_rename2,
+ 	.setattr     = ubifs_setattr,
+ 	.getattr     = ubifs_getattr,
+ 	.setxattr    = ubifs_setxattr,
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -908,6 +908,147 @@ int ubifs_jnl_delete_inode(struct ubifs_
+ }
+ 
+ /**
++ * ubifs_jnl_xrename - cross rename two directory entries.
++ * @c: UBIFS file-system description object
++ * @fst_dir: parent inode of 1st directory entry to exchange
++ * @fst_dentry: 1st directory entry to exchange
++ * @snd_dir: parent inode of 2nd directory entry to exchange
++ * @snd_dentry: 2nd directory entry to exchange
++ * @sync: non-zero if the write-buffer has to be synchronized
++ *
++ * This function implements the cross rename operation which may involve
++ * writing 2 inodes and 2 directory entries. It marks the written inodes as clean
++ * and returns zero on success. In case of failure, a negative error code is
++ * returned.
++ */
++int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
++		      const struct dentry *fst_dentry,
++		      const struct inode *snd_dir,
++		      const struct dentry *snd_dentry, int sync)
++{
++	union ubifs_key key;
++	struct ubifs_dent_node *dent1, *dent2;
++	int err, dlen1, dlen2, lnum, offs, len, plen = UBIFS_INO_NODE_SZ;
++	int aligned_dlen1, aligned_dlen2;
++	int twoparents = (fst_dir != snd_dir);
++	const struct inode *fst_inode = d_inode(fst_dentry);
++	const struct inode *snd_inode = d_inode(snd_dentry);
++	void *p;
++
++	dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
++		fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
++
++	ubifs_assert(ubifs_inode(fst_dir)->data_len == 0);
++	ubifs_assert(ubifs_inode(snd_dir)->data_len == 0);
++	ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex));
++	ubifs_assert(mutex_is_locked(&ubifs_inode(snd_dir)->ui_mutex));
++
++	dlen1 = UBIFS_DENT_NODE_SZ + snd_dentry->d_name.len + 1;
++	dlen2 = UBIFS_DENT_NODE_SZ + fst_dentry->d_name.len + 1;
++	aligned_dlen1 = ALIGN(dlen1, 8);
++	aligned_dlen2 = ALIGN(dlen2, 8);
++
++	len = aligned_dlen1 + aligned_dlen2 + ALIGN(plen, 8);
++	if (twoparents)
++		len += plen;
++
++	dent1 = kmalloc(len, GFP_NOFS);
++	if (!dent1)
++		return -ENOMEM;
++
++	/* Make reservation before allocating sequence numbers */
++	err = make_reservation(c, BASEHD, len);
++	if (err)
++		goto out_free;
++
++	/* Make new dent for 1st entry */
++	dent1->ch.node_type = UBIFS_DENT_NODE;
++	dent_key_init_flash(c, &dent1->key, snd_dir->i_ino, &snd_dentry->d_name);
++	dent1->inum = cpu_to_le64(fst_inode->i_ino);
++	dent1->type = get_dent_type(fst_inode->i_mode);
++	dent1->nlen = cpu_to_le16(snd_dentry->d_name.len);
++	memcpy(dent1->name, snd_dentry->d_name.name, snd_dentry->d_name.len);
++	dent1->name[snd_dentry->d_name.len] = '\0';
++	zero_dent_node_unused(dent1);
++	ubifs_prep_grp_node(c, dent1, dlen1, 0);
++
++	/* Make new dent for 2nd entry */
++	dent2 = (void *)dent1 + aligned_dlen1;
++	dent2->ch.node_type = UBIFS_DENT_NODE;
++	dent_key_init_flash(c, &dent2->key, fst_dir->i_ino, &fst_dentry->d_name);
++	dent2->inum = cpu_to_le64(snd_inode->i_ino);
++	dent2->type = get_dent_type(snd_inode->i_mode);
++	dent2->nlen = cpu_to_le16(fst_dentry->d_name.len);
++	memcpy(dent2->name, fst_dentry->d_name.name, fst_dentry->d_name.len);
++	dent2->name[fst_dentry->d_name.len] = '\0';
++	zero_dent_node_unused(dent2);
++	ubifs_prep_grp_node(c, dent2, dlen2, 0);
++
++	p = (void *)dent2 + aligned_dlen2;
++	if (!twoparents)
++		pack_inode(c, p, fst_dir, 1);
++	else {
++		pack_inode(c, p, fst_dir, 0);
++		p += ALIGN(plen, 8);
++		pack_inode(c, p, snd_dir, 1);
++	}
++
++	err = write_head(c, BASEHD, dent1, len, &lnum, &offs, sync);
++	if (err)
++		goto out_release;
++	if (!sync) {
++		struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf;
++
++		ubifs_wbuf_add_ino_nolock(wbuf, fst_dir->i_ino);
++		ubifs_wbuf_add_ino_nolock(wbuf, snd_dir->i_ino);
++	}
++	release_head(c, BASEHD);
++
++	dent_key_init(c, &key, snd_dir->i_ino, &snd_dentry->d_name);
++	err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &snd_dentry->d_name);
++	if (err)
++		goto out_ro;
++
++	offs += aligned_dlen1;
++	dent_key_init(c, &key, fst_dir->i_ino, &fst_dentry->d_name);
++	err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &fst_dentry->d_name);
++	if (err)
++		goto out_ro;
++
++	offs += aligned_dlen2;
++
++	ino_key_init(c, &key, fst_dir->i_ino);
++	err = ubifs_tnc_add(c, &key, lnum, offs, plen);
++	if (err)
++		goto out_ro;
++
++	if (twoparents) {
++		offs += ALIGN(plen, 8);
++		ino_key_init(c, &key, snd_dir->i_ino);
++		err = ubifs_tnc_add(c, &key, lnum, offs, plen);
++		if (err)
++			goto out_ro;
++	}
++
++	finish_reservation(c);
++
++	mark_inode_clean(c, ubifs_inode(fst_dir));
++	if (twoparents)
++		mark_inode_clean(c, ubifs_inode(snd_dir));
++	kfree(dent1);
++	return 0;
++
++out_release:
++	release_head(c, BASEHD);
++out_ro:
++	ubifs_ro_mode(c, err);
++	finish_reservation(c);
++out_free:
++	kfree(dent1);
++	return err;
++}
++
++/**
+  * ubifs_jnl_rename - rename a directory entry.
+  * @c: UBIFS file-system description object
+  * @old_dir: parent inode of directory entry to rename
+--- a/fs/ubifs/ubifs.h
++++ b/fs/ubifs/ubifs.h
+@@ -1544,6 +1544,10 @@ int ubifs_jnl_write_data(struct ubifs_in
+ 			 const union ubifs_key *key, const void *buf, int len);
+ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
+ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
++int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
++		      const struct dentry *fst_dentry,
++		      const struct inode *snd_dir,
++		      const struct dentry *snd_dentry, int sync);
+ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
+ 		     const struct dentry *old_dentry,
+ 		     const struct inode *new_dir,
diff --git a/target/linux/generic/patches-4.4/052-04-ubifs-Use-move-variable-in-ubifs_rename.patch b/target/linux/generic/patches-4.4/052-04-ubifs-Use-move-variable-in-ubifs_rename.patch
new file mode 100644
index 0000000000..81129359d3
--- /dev/null
+++ b/target/linux/generic/patches-4.4/052-04-ubifs-Use-move-variable-in-ubifs_rename.patch
@@ -0,0 +1,30 @@
+From: Richard Weinberger <richard@nod.at>
+Date: Tue, 13 Sep 2016 16:18:58 +0200
+Subject: [PATCH] ubifs: Use move variable in ubifs_rename()
+
+...to make the code more consistent since we use
+move already in other places.
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -1100,7 +1100,7 @@ int ubifs_jnl_rename(struct ubifs_info *
+ 	aligned_dlen1 = ALIGN(dlen1, 8);
+ 	aligned_dlen2 = ALIGN(dlen2, 8);
+ 	len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
+-	if (old_dir != new_dir)
++	if (move)
+ 		len += plen;
+ 	dent = kmalloc(len, GFP_NOFS);
+ 	if (!dent)
+@@ -1216,7 +1216,7 @@ int ubifs_jnl_rename(struct ubifs_info *
+ 	if (err)
+ 		goto out_ro;
+ 
+-	if (old_dir != new_dir) {
++	if (move) {
+ 		offs += ALIGN(plen, 8);
+ 		ino_key_init(c, &key, new_dir->i_ino);
+ 		err = ubifs_tnc_add(c, &key, lnum, offs, plen);
diff --git a/target/linux/generic/patches-4.4/060-mips_decompressor_memmove.patch b/target/linux/generic/patches-4.4/060-mips_decompressor_memmove.patch
new file mode 100644
index 0000000000..d215b80ab2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/060-mips_decompressor_memmove.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/boot/compressed/string.c
++++ b/arch/mips/boot/compressed/string.c
+@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
+ 		ss[i] = c;
+ 	return s;
+ }
++
++void *memmove(void *__dest, __const void *__src, size_t count)
++{
++	unsigned char *d = __dest;
++	const unsigned char *s = __src;
++
++	if (__dest == __src)
++		return __dest;
++
++	if (__dest < __src)
++		return memcpy(__dest, __src, count);
++
++	while (count--)
++		d[count] = s[count];
++	return __dest;
++}
diff --git a/target/linux/generic/patches-4.4/061-softirq-let-ksoftirqd-do-its-job.patch b/target/linux/generic/patches-4.4/061-softirq-let-ksoftirqd-do-its-job.patch
new file mode 100644
index 0000000000..a2de48093c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/061-softirq-let-ksoftirqd-do-its-job.patch
@@ -0,0 +1,83 @@
+From: Eric Dumazet <edumazet@google.com>
+Date: Wed, 31 Aug 2016 10:42:29 -0700
+Subject: [PATCH] softirq: let ksoftirqd do its job
+
+A while back, Paolo and Hannes sent an RFC patch adding threaded-able
+napi poll loop support : (https://patchwork.ozlabs.org/patch/620657/)
+
+The problem seems to be that softirqs are very aggressive and are often
+handled by the current process, even if we are under stress and that
+ksoftirqd was scheduled, so that innocent threads would have more chance
+to make progress.
+
+This patch makes sure that if ksoftirq is running, we let it
+perform the softirq work.
+
+Jonathan Corbet summarized the issue in https://lwn.net/Articles/687617/
+
+Tested:
+
+ - NIC receiving traffic handled by CPU 0
+ - UDP receiver running on CPU 0, using a single UDP socket.
+ - Incoming flood of UDP packets targeting the UDP socket.
+
+Before the patch, the UDP receiver could almost never get cpu cycles and
+could only receive ~2,000 packets per second.
+
+After the patch, cpu cycles are split 50/50 between user application and
+ksoftirqd/0, and we can effectively read ~900,000 packets per second,
+a huge improvement in DOS situation. (Note that more packets are now
+dropped by the NIC itself, since the BH handlers get less cpu cycles to
+drain RX ring buffer)
+
+Since the load runs in well identified threads context, an admin can
+more easily tune process scheduling parameters if needed.
+
+Reported-by: Paolo Abeni <pabeni@redhat.com>
+Reported-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: David Miller <davem@davemloft.net
+Cc: Jesper Dangaard Brouer <jbrouer@redhat.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Rik van Riel <riel@redhat.com>
+---
+
+--- a/kernel/softirq.c
++++ b/kernel/softirq.c
+@@ -78,6 +78,17 @@ static void wakeup_softirqd(void)
+ }
+ 
+ /*
++ * If ksoftirqd is scheduled, we do not want to process pending softirqs
++ * right now. Let ksoftirqd handle this at its own rate, to get fairness.
++ */
++static bool ksoftirqd_running(void)
++{
++	struct task_struct *tsk = __this_cpu_read(ksoftirqd);
++
++	return tsk && (tsk->state == TASK_RUNNING);
++}
++
++/*
+  * preempt_count and SOFTIRQ_OFFSET usage:
+  * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
+  *   softirq processing.
+@@ -313,7 +324,7 @@ asmlinkage __visible void do_softirq(voi
+ 
+ 	pending = local_softirq_pending();
+ 
+-	if (pending)
++	if (pending && !ksoftirqd_running())
+ 		do_softirq_own_stack();
+ 
+ 	local_irq_restore(flags);
+@@ -340,6 +351,9 @@ void irq_enter(void)
+ 
+ static inline void invoke_softirq(void)
+ {
++	if (ksoftirqd_running())
++		return;
++
+ 	if (!force_irqthreads) {
+ #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
+ 		/*
diff --git a/target/linux/generic/patches-4.4/070-0001-bgmac-fix-a-missing-check-for-build_skb.patch b/target/linux/generic/patches-4.4/070-0001-bgmac-fix-a-missing-check-for-build_skb.patch
new file mode 100644
index 0000000000..99f9de65a7
--- /dev/null
+++ b/target/linux/generic/patches-4.4/070-0001-bgmac-fix-a-missing-check-for-build_skb.patch
@@ -0,0 +1,28 @@
+From f1640c3ddeec12804bc9a21feee85fc15aca95f6 Mon Sep 17 00:00:00 2001
+From: wangweidong <wangweidong1@huawei.com>
+Date: Wed, 13 Jan 2016 11:06:41 +0800
+Subject: [PATCH] bgmac: fix a missing check for build_skb
+
+when build_skb failed, it may occure a NULL pointer.
+So add a 'NULL check' for it.
+
+Signed-off-by: Weidong Wang <wangweidong1@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -469,6 +469,11 @@ static int bgmac_dma_rx_read(struct bgma
+ 			len -= ETH_FCS_LEN;
+ 
+ 			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
++			if (unlikely(skb)) {
++				bgmac_err(bgmac, "build_skb failed\n");
++				put_page(virt_to_head_page(buf));
++				break;
++			}
+ 			skb_put(skb, BGMAC_RX_FRAME_OFFSET +
+ 				BGMAC_RX_BUF_OFFSET + len);
+ 			skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
diff --git a/target/linux/generic/patches-4.4/070-0002-bgmac-Fix-reversed-test-of-build_skb-return-value.patch b/target/linux/generic/patches-4.4/070-0002-bgmac-Fix-reversed-test-of-build_skb-return-value.patch
new file mode 100644
index 0000000000..eebcded6fa
--- /dev/null
+++ b/target/linux/generic/patches-4.4/070-0002-bgmac-Fix-reversed-test-of-build_skb-return-value.patch
@@ -0,0 +1,22 @@
+From 750afbf8ee9c6a1c74a1fe5fc9852146b1d72687 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Fri, 15 Jan 2016 16:07:13 -0500
+Subject: [PATCH] bgmac: Fix reversed test of build_skb() return value.
+
+Fixes: f1640c3ddeec ("bgmac: fix a missing check for build_skb")
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -469,7 +469,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 			len -= ETH_FCS_LEN;
+ 
+ 			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+-			if (unlikely(skb)) {
++			if (unlikely(!skb)) {
+ 				bgmac_err(bgmac, "build_skb failed\n");
+ 				put_page(virt_to_head_page(buf));
+ 				break;
diff --git a/target/linux/generic/patches-4.4/071-0000-net-bgmac-clarify-CONFIG_BCMA-dependency.patch b/target/linux/generic/patches-4.4/071-0000-net-bgmac-clarify-CONFIG_BCMA-dependency.patch
new file mode 100644
index 0000000000..cd0d09887f
--- /dev/null
+++ b/target/linux/generic/patches-4.4/071-0000-net-bgmac-clarify-CONFIG_BCMA-dependency.patch
@@ -0,0 +1,46 @@
+From 1f820f538f7396db7fd40684b9c3620816acc5a3 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Fri, 29 Jan 2016 12:39:12 +0100
+Subject: [PATCH] net: bgmac: clarify CONFIG_BCMA dependency
+
+The bgmac driver depends on BCMA_HOST_SOC, which is only used
+when CONFIG_BCMA is enabled. However, it is a bool option and can
+be set when CONFIG_BCMA=m, and then bgmac can be built-in, leading
+to an obvious link error:
+
+drivers/built-in.o: In function `bgmac_init':
+:(.init.text+0x7f2c): undefined reference to `__bcma_driver_register'
+drivers/built-in.o: In function `bgmac_exit':
+:(.exit.text+0x110a): undefined reference to `bcma_driver_unregister'
+
+To avoid this case, we need to depend on both BCMA and BCMA_SOC,
+as this patch does. I'm also trying to make the dependency more
+readable by splitting it into three lines, and adding a COMPILE_TEST
+alternative so we can test-build it in all configurations that
+support BCMA.
+
+The added dependency on FIXED_PHY addresses a related issue where
+we cannot call fixed_phy_register() when CONFIG_FIXED_PHY=m and
+CONFIG_BGMAC=y.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/Kconfig | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/Kconfig
++++ b/drivers/net/ethernet/broadcom/Kconfig
+@@ -151,8 +151,11 @@ config BNX2X_VXLAN
+ 
+ config BGMAC
+ 	tristate "BCMA bus GBit core support"
+-	depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X)
++	depends on BCMA && BCMA_HOST_SOC
++	depends on HAS_DMA
++	depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST
+ 	select PHYLIB
++	select FIXED_PHY
+ 	---help---
+ 	  This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
+ 	  They can be found on BCM47xx SoCs and provide gigabit ethernet.
diff --git a/target/linux/generic/patches-4.4/071-0001-bgmac-add-helper-checking-for-BCM4707-BCM53018-chip-.patch b/target/linux/generic/patches-4.4/071-0001-bgmac-add-helper-checking-for-BCM4707-BCM53018-chip-.patch
new file mode 100644
index 0000000000..0c007569fb
--- /dev/null
+++ b/target/linux/generic/patches-4.4/071-0001-bgmac-add-helper-checking-for-BCM4707-BCM53018-chip-.patch
@@ -0,0 +1,106 @@
+From 387b75f8b31437792e8334390fdf5cf060d1e3da Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 2 Feb 2016 07:47:14 +0100
+Subject: [PATCH] bgmac: add helper checking for BCM4707 / BCM53018 chip id
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Chipsets with BCM4707 / BCM53018 ID require special handling at a few
+places in the code. It's likely there will be more IDs to check in the
+future. To simplify it add this trivial helper.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 30 ++++++++++++++++--------------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -26,6 +26,17 @@ static const struct bcma_device_id bgmac
+ };
+ MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
+ 
++static inline bool bgmac_is_bcm4707_family(struct bgmac *bgmac)
++{
++	switch (bgmac->core->bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM4707:
++	case BCMA_CHIP_ID_BCM53018:
++		return true;
++	default:
++		return false;
++	}
++}
++
+ static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
+ 			     u32 value, int timeout)
+ {
+@@ -990,11 +1001,9 @@ static void bgmac_mac_speed(struct bgmac
+ static void bgmac_miiconfig(struct bgmac *bgmac)
+ {
+ 	struct bcma_device *core = bgmac->core;
+-	struct bcma_chipinfo *ci = &core->bus->chipinfo;
+ 	u8 imode;
+ 
+-	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
+-	    ci->id == BCMA_CHIP_ID_BCM53018) {
++	if (bgmac_is_bcm4707_family(bgmac)) {
+ 		bcma_awrite32(core, BCMA_IOCTL,
+ 			      bcma_aread32(core, BCMA_IOCTL) | 0x40 |
+ 			      BGMAC_BCMA_IOCTL_SW_CLKEN);
+@@ -1058,9 +1067,7 @@ static void bgmac_chip_reset(struct bgma
+ 	}
+ 
+ 	/* Request Misc PLL for corerev > 2 */
+-	if (core->id.rev > 2 &&
+-	    ci->id != BCMA_CHIP_ID_BCM4707 &&
+-	    ci->id != BCMA_CHIP_ID_BCM53018) {
++	if (core->id.rev > 2 && !bgmac_is_bcm4707_family(bgmac)) {
+ 		bgmac_set(bgmac, BCMA_CLKCTLST,
+ 			  BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ);
+ 		bgmac_wait_value(bgmac->core, BCMA_CLKCTLST,
+@@ -1196,8 +1203,7 @@ static void bgmac_enable(struct bgmac *b
+ 		break;
+ 	}
+ 
+-	if (ci->id != BCMA_CHIP_ID_BCM4707 &&
+-	    ci->id != BCMA_CHIP_ID_BCM53018) {
++	if (!bgmac_is_bcm4707_family(bgmac)) {
+ 		rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
+ 		rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
+ 		bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) /
+@@ -1475,14 +1481,12 @@ static int bgmac_fixed_phy_register(stru
+ 
+ static int bgmac_mii_register(struct bgmac *bgmac)
+ {
+-	struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+ 	struct mii_bus *mii_bus;
+ 	struct phy_device *phy_dev;
+ 	char bus_id[MII_BUS_ID_SIZE + 3];
+ 	int i, err = 0;
+ 
+-	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
+-	    ci->id == BCMA_CHIP_ID_BCM53018)
++	if (bgmac_is_bcm4707_family(bgmac))
+ 		return bgmac_fixed_phy_register(bgmac);
+ 
+ 	mii_bus = mdiobus_alloc();
+@@ -1553,7 +1557,6 @@ static void bgmac_mii_unregister(struct
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+ static int bgmac_probe(struct bcma_device *core)
+ {
+-	struct bcma_chipinfo *ci = &core->bus->chipinfo;
+ 	struct net_device *net_dev;
+ 	struct bgmac *bgmac;
+ 	struct ssb_sprom *sprom = &core->bus->sprom;
+@@ -1634,8 +1637,7 @@ static int bgmac_probe(struct bcma_devic
+ 	bgmac_chip_reset(bgmac);
+ 
+ 	/* For Northstar, we have to take all GMAC core out of reset */
+-	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
+-	    ci->id == BCMA_CHIP_ID_BCM53018) {
++	if (bgmac_is_bcm4707_family(bgmac)) {
+ 		struct bcma_device *ns_core;
+ 		int ns_gmac;
+ 
diff --git a/target/linux/generic/patches-4.4/071-0002-bgmac-support-Ethernet-device-on-BCM47094-SoC.patch b/target/linux/generic/patches-4.4/071-0002-bgmac-support-Ethernet-device-on-BCM47094-SoC.patch
new file mode 100644
index 0000000000..d00c2bd551
--- /dev/null
+++ b/target/linux/generic/patches-4.4/071-0002-bgmac-support-Ethernet-device-on-BCM47094-SoC.patch
@@ -0,0 +1,39 @@
+From 9e4e6206c67ae11d68fc96882256f37c237087d4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 22 Feb 2016 22:51:13 +0100
+Subject: [PATCH] bgmac: support Ethernet device on BCM47094 SoC
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It needs very similar workarounds to the one on BCM4707. It was tested
+on D-Link DIR-885L home router.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -30,6 +30,7 @@ static inline bool bgmac_is_bcm4707_fami
+ {
+ 	switch (bgmac->core->bus->chipinfo.id) {
+ 	case BCMA_CHIP_ID_BCM4707:
++	case BCMA_CHIP_ID_BCM47094:
+ 	case BCMA_CHIP_ID_BCM53018:
+ 		return true;
+ 	default:
+@@ -1055,8 +1056,9 @@ static void bgmac_chip_reset(struct bgma
+ 	    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188))
+ 		iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+ 
+-	/* 3GMAC: for BCM4707, only do core reset at bgmac_probe() */
+-	if (ci->id != BCMA_CHIP_ID_BCM4707) {
++	/* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
++	if (ci->id != BCMA_CHIP_ID_BCM4707 &&
++	    ci->id != BCMA_CHIP_ID_BCM47094) {
+ 		flags = 0;
+ 		if (iost & BGMAC_BCMA_IOST_ATTACHED) {
+ 			flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
diff --git a/target/linux/generic/patches-4.4/071-0003-bgmac-reset-enable-Ethernet-core-before-using-it.patch b/target/linux/generic/patches-4.4/071-0003-bgmac-reset-enable-Ethernet-core-before-using-it.patch
new file mode 100644
index 0000000000..021a5913aa
--- /dev/null
+++ b/target/linux/generic/patches-4.4/071-0003-bgmac-reset-enable-Ethernet-core-before-using-it.patch
@@ -0,0 +1,31 @@
+From b4dfd8e92956b396d3438212bc9a0be6267b8b34 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 12 Apr 2016 13:30:45 +0200
+Subject: [PATCH] bgmac: reset & enable Ethernet core before using it
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes Ethernet on D-Link DIR-885L with BCM47094 SoC. Felix reported
+similar fix was needed for his BCM4709 device (Buffalo WXR-1900DHP?).
+I tested this for regressions on BCM4706, BCM4708A0 and BCM47081A0.
+
+Cc: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1586,6 +1586,11 @@ static int bgmac_probe(struct bcma_devic
+ 		dev_warn(&core->dev, "Using random MAC: %pM\n", mac);
+ 	}
+ 
++	/* This (reset &) enable is not preset in specs or reference driver but
++	 * Broadcom does it in arch PCI code when enabling fake PCI device.
++	 */
++	bcma_core_enable(core, 0);
++
+ 	/* Allocation and references */
+ 	net_dev = alloc_etherdev(sizeof(*bgmac));
+ 	if (!net_dev)
diff --git a/target/linux/generic/patches-4.4/071-0004-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch b/target/linux/generic/patches-4.4/071-0004-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
new file mode 100644
index 0000000000..a5fcaab51c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/071-0004-bgmac-fix-MAC-soft-reset-bit-for-corerev-4.patch
@@ -0,0 +1,34 @@
+From c02bc350f9dbce7d637c394a6e1c4d29dc5b28b2 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 12 Apr 2016 18:27:29 +0200
+Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0. This mainly
+fixes support for BCM4708A0KF SoCs with Ethernet core rev 5 (it means
+only some devices as most of BCM4708A0KF-s got core rev 4).
+This was tested for regressions on BCM47094 which doesn't seem to care
+which bit gets used.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -199,9 +199,9 @@
+ #define  BGMAC_CMDCFG_TAI			0x00000200
+ #define  BGMAC_CMDCFG_HD			0x00000400	/* Set if in half duplex mode */
+ #define  BGMAC_CMDCFG_HD_SHIFT			10
+-#define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for other revs */
+-#define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, only for core rev 4 */
+-#define  BGMAC_CMDCFG_SR(rev)  ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
++#define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for core rev 0-3 */
++#define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, for core rev >= 4 */
++#define  BGMAC_CMDCFG_SR(rev)  ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
+ #define  BGMAC_CMDCFG_ML			0x00008000	/* Set to activate mac loopback mode */
+ #define  BGMAC_CMDCFG_AE			0x00400000
+ #define  BGMAC_CMDCFG_CFE			0x00800000
diff --git a/target/linux/generic/patches-4.4/072-0001-bgmac-Bind-net_device-with-backing-device-structure.patch b/target/linux/generic/patches-4.4/072-0001-bgmac-Bind-net_device-with-backing-device-structure.patch
new file mode 100644
index 0000000000..4d00094aa8
--- /dev/null
+++ b/target/linux/generic/patches-4.4/072-0001-bgmac-Bind-net_device-with-backing-device-structure.patch
@@ -0,0 +1,25 @@
+From 2022e9d50798aa592887ccb5a7d045e537f3855f Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Tue, 7 Jun 2016 15:06:13 -0700
+Subject: [PATCH 1/3] bgmac: Bind net_device with backing device structure
+
+In preparation for allowing different helpers to be utilized against
+network devices created by the bgmac driver, make sure that we bind the
+net_device with core->dev.
+
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1602,6 +1602,7 @@ static int bgmac_probe(struct bcma_devic
+ 	bgmac->net_dev = net_dev;
+ 	bgmac->core = core;
+ 	bcma_set_drvdata(core, bgmac);
++	SET_NETDEV_DEV(net_dev, &core->dev);
+ 
+ 	/* Defaults */
+ 	memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
diff --git a/target/linux/generic/patches-4.4/072-0002-bgmac-Add-support-for-ethtool-statistics.patch b/target/linux/generic/patches-4.4/072-0002-bgmac-Add-support-for-ethtool-statistics.patch
new file mode 100644
index 0000000000..cff70802d2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/072-0002-bgmac-Add-support-for-ethtool-statistics.patch
@@ -0,0 +1,175 @@
+From f6613d4fa937fa8388f2c1cb4e69ccc25e9e2336 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Tue, 7 Jun 2016 15:06:14 -0700
+Subject: [PATCH 2/3] bgmac: Add support for ethtool statistics
+
+Read the statistics from the BGMAC's builtin MAC and return them to
+user-space using the standard ethtool helpers.
+
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 124 ++++++++++++++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/bgmac.h |   4 +-
+ 2 files changed, 126 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1385,6 +1385,127 @@ static const struct net_device_ops bgmac
+  * ethtool_ops
+  **************************************************/
+ 
++struct bgmac_stat {
++	u8 size;
++	u32 offset;
++	const char *name;
++};
++
++static struct bgmac_stat bgmac_get_strings_stats[] = {
++	{ 8, BGMAC_TX_GOOD_OCTETS, "tx_good_octets" },
++	{ 4, BGMAC_TX_GOOD_PKTS, "tx_good" },
++	{ 8, BGMAC_TX_OCTETS, "tx_octets" },
++	{ 4, BGMAC_TX_PKTS, "tx_pkts" },
++	{ 4, BGMAC_TX_BROADCAST_PKTS, "tx_broadcast" },
++	{ 4, BGMAC_TX_MULTICAST_PKTS, "tx_multicast" },
++	{ 4, BGMAC_TX_LEN_64, "tx_64" },
++	{ 4, BGMAC_TX_LEN_65_TO_127, "tx_65_127" },
++	{ 4, BGMAC_TX_LEN_128_TO_255, "tx_128_255" },
++	{ 4, BGMAC_TX_LEN_256_TO_511, "tx_256_511" },
++	{ 4, BGMAC_TX_LEN_512_TO_1023, "tx_512_1023" },
++	{ 4, BGMAC_TX_LEN_1024_TO_1522, "tx_1024_1522" },
++	{ 4, BGMAC_TX_LEN_1523_TO_2047, "tx_1523_2047" },
++	{ 4, BGMAC_TX_LEN_2048_TO_4095, "tx_2048_4095" },
++	{ 4, BGMAC_TX_LEN_4096_TO_8191, "tx_4096_8191" },
++	{ 4, BGMAC_TX_LEN_8192_TO_MAX, "tx_8192_max" },
++	{ 4, BGMAC_TX_JABBER_PKTS, "tx_jabber" },
++	{ 4, BGMAC_TX_OVERSIZE_PKTS, "tx_oversize" },
++	{ 4, BGMAC_TX_FRAGMENT_PKTS, "tx_fragment" },
++	{ 4, BGMAC_TX_UNDERRUNS, "tx_underruns" },
++	{ 4, BGMAC_TX_TOTAL_COLS, "tx_total_cols" },
++	{ 4, BGMAC_TX_SINGLE_COLS, "tx_single_cols" },
++	{ 4, BGMAC_TX_MULTIPLE_COLS, "tx_multiple_cols" },
++	{ 4, BGMAC_TX_EXCESSIVE_COLS, "tx_excessive_cols" },
++	{ 4, BGMAC_TX_LATE_COLS, "tx_late_cols" },
++	{ 4, BGMAC_TX_DEFERED, "tx_defered" },
++	{ 4, BGMAC_TX_CARRIER_LOST, "tx_carrier_lost" },
++	{ 4, BGMAC_TX_PAUSE_PKTS, "tx_pause" },
++	{ 4, BGMAC_TX_UNI_PKTS, "tx_unicast" },
++	{ 4, BGMAC_TX_Q0_PKTS, "tx_q0" },
++	{ 8, BGMAC_TX_Q0_OCTETS, "tx_q0_octets" },
++	{ 4, BGMAC_TX_Q1_PKTS, "tx_q1" },
++	{ 8, BGMAC_TX_Q1_OCTETS, "tx_q1_octets" },
++	{ 4, BGMAC_TX_Q2_PKTS, "tx_q2" },
++	{ 8, BGMAC_TX_Q2_OCTETS, "tx_q2_octets" },
++	{ 4, BGMAC_TX_Q3_PKTS, "tx_q3" },
++	{ 8, BGMAC_TX_Q3_OCTETS, "tx_q3_octets" },
++	{ 8, BGMAC_RX_GOOD_OCTETS, "rx_good_octets" },
++	{ 4, BGMAC_RX_GOOD_PKTS, "rx_good" },
++	{ 8, BGMAC_RX_OCTETS, "rx_octets" },
++	{ 4, BGMAC_RX_PKTS, "rx_pkts" },
++	{ 4, BGMAC_RX_BROADCAST_PKTS, "rx_broadcast" },
++	{ 4, BGMAC_RX_MULTICAST_PKTS, "rx_multicast" },
++	{ 4, BGMAC_RX_LEN_64, "rx_64" },
++	{ 4, BGMAC_RX_LEN_65_TO_127, "rx_65_127" },
++	{ 4, BGMAC_RX_LEN_128_TO_255, "rx_128_255" },
++	{ 4, BGMAC_RX_LEN_256_TO_511, "rx_256_511" },
++	{ 4, BGMAC_RX_LEN_512_TO_1023, "rx_512_1023" },
++	{ 4, BGMAC_RX_LEN_1024_TO_1522, "rx_1024_1522" },
++	{ 4, BGMAC_RX_LEN_1523_TO_2047, "rx_1523_2047" },
++	{ 4, BGMAC_RX_LEN_2048_TO_4095, "rx_2048_4095" },
++	{ 4, BGMAC_RX_LEN_4096_TO_8191, "rx_4096_8191" },
++	{ 4, BGMAC_RX_LEN_8192_TO_MAX, "rx_8192_max" },
++	{ 4, BGMAC_RX_JABBER_PKTS, "rx_jabber" },
++	{ 4, BGMAC_RX_OVERSIZE_PKTS, "rx_oversize" },
++	{ 4, BGMAC_RX_FRAGMENT_PKTS, "rx_fragment" },
++	{ 4, BGMAC_RX_MISSED_PKTS, "rx_missed" },
++	{ 4, BGMAC_RX_CRC_ALIGN_ERRS, "rx_crc_align" },
++	{ 4, BGMAC_RX_UNDERSIZE, "rx_undersize" },
++	{ 4, BGMAC_RX_CRC_ERRS, "rx_crc" },
++	{ 4, BGMAC_RX_ALIGN_ERRS, "rx_align" },
++	{ 4, BGMAC_RX_SYMBOL_ERRS, "rx_symbol" },
++	{ 4, BGMAC_RX_PAUSE_PKTS, "rx_pause" },
++	{ 4, BGMAC_RX_NONPAUSE_PKTS, "rx_nonpause" },
++	{ 4, BGMAC_RX_SACHANGES, "rx_sa_changes" },
++	{ 4, BGMAC_RX_UNI_PKTS, "rx_unicast" },
++};
++
++#define BGMAC_STATS_LEN	ARRAY_SIZE(bgmac_get_strings_stats)
++
++static int bgmac_get_sset_count(struct net_device *dev, int string_set)
++{
++	switch (string_set) {
++	case ETH_SS_STATS:
++		return BGMAC_STATS_LEN;
++	}
++
++	return -EOPNOTSUPP;
++}
++
++static void bgmac_get_strings(struct net_device *dev, u32 stringset,
++			      u8 *data)
++{
++	int i;
++
++	if (stringset != ETH_SS_STATS)
++		return;
++
++	for (i = 0; i < BGMAC_STATS_LEN; i++)
++		strlcpy(data + i * ETH_GSTRING_LEN,
++			bgmac_get_strings_stats[i].name, ETH_GSTRING_LEN);
++}
++
++static void bgmac_get_ethtool_stats(struct net_device *dev,
++				    struct ethtool_stats *ss, uint64_t *data)
++{
++	struct bgmac *bgmac = netdev_priv(dev);
++	const struct bgmac_stat *s;
++	unsigned int i;
++	u64 val;
++
++	if (!netif_running(dev))
++		return;
++
++	for (i = 0; i < BGMAC_STATS_LEN; i++) {
++		s = &bgmac_get_strings_stats[i];
++		val = 0;
++		if (s->size == 8)
++			val = (u64)bgmac_read(bgmac, s->offset + 4) << 32;
++		val |= bgmac_read(bgmac, s->offset);
++		data[i] = val;
++	}
++}
++
+ static int bgmac_get_settings(struct net_device *net_dev,
+ 			      struct ethtool_cmd *cmd)
+ {
+@@ -1409,6 +1530,9 @@ static void bgmac_get_drvinfo(struct net
+ }
+ 
+ static const struct ethtool_ops bgmac_ethtool_ops = {
++	.get_strings		= bgmac_get_strings,
++	.get_sset_count		= bgmac_get_sset_count,
++	.get_ethtool_stats	= bgmac_get_ethtool_stats,
+ 	.get_settings		= bgmac_get_settings,
+ 	.set_settings		= bgmac_set_settings,
+ 	.get_drvinfo		= bgmac_get_drvinfo,
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -123,7 +123,7 @@
+ #define BGMAC_TX_LEN_1024_TO_1522		0x334
+ #define BGMAC_TX_LEN_1523_TO_2047		0x338
+ #define BGMAC_TX_LEN_2048_TO_4095		0x33c
+-#define BGMAC_TX_LEN_4095_TO_8191		0x340
++#define BGMAC_TX_LEN_4096_TO_8191		0x340
+ #define BGMAC_TX_LEN_8192_TO_MAX		0x344
+ #define BGMAC_TX_JABBER_PKTS			0x348		/* Error */
+ #define BGMAC_TX_OVERSIZE_PKTS			0x34c		/* Error */
+@@ -166,7 +166,7 @@
+ #define BGMAC_RX_LEN_1024_TO_1522		0x3e4
+ #define BGMAC_RX_LEN_1523_TO_2047		0x3e8
+ #define BGMAC_RX_LEN_2048_TO_4095		0x3ec
+-#define BGMAC_RX_LEN_4095_TO_8191		0x3f0
++#define BGMAC_RX_LEN_4096_TO_8191		0x3f0
+ #define BGMAC_RX_LEN_8192_TO_MAX		0x3f4
+ #define BGMAC_RX_JABBER_PKTS			0x3f8		/* Error */
+ #define BGMAC_RX_OVERSIZE_PKTS			0x3fc		/* Error */
diff --git a/target/linux/generic/patches-4.4/072-0003-bgmac-Maintain-some-netdev-statistics.patch b/target/linux/generic/patches-4.4/072-0003-bgmac-Maintain-some-netdev-statistics.patch
new file mode 100644
index 0000000000..322851d026
--- /dev/null
+++ b/target/linux/generic/patches-4.4/072-0003-bgmac-Maintain-some-netdev-statistics.patch
@@ -0,0 +1,68 @@
+From 6d490f62a4c7f11c552591bdd08eda3636aa0db9 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Tue, 7 Jun 2016 15:06:15 -0700
+Subject: [PATCH 3/3] bgmac: Maintain some netdev statistics
+
+Add a few netdev statistics to report transmitted and received bytes and
+packets and a few obvious errors.
+
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -246,6 +246,8 @@ err_dma_head:
+ 
+ err_drop:
+ 	dev_kfree_skb(skb);
++	net_dev->stats.tx_dropped++;
++	net_dev->stats.tx_errors++;
+ 	return NETDEV_TX_OK;
+ }
+ 
+@@ -284,6 +286,8 @@ static void bgmac_dma_tx_free(struct bgm
+ 				       DMA_TO_DEVICE);
+ 
+ 		if (slot->skb) {
++			bgmac->net_dev->stats.tx_bytes += slot->skb->len;
++			bgmac->net_dev->stats.tx_packets++;
+ 			bytes_compl += slot->skb->len;
+ 			pkts_compl++;
+ 
+@@ -467,6 +471,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 				bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+ 					  ring->start);
+ 				put_page(virt_to_head_page(buf));
++				bgmac->net_dev->stats.rx_errors++;
+ 				break;
+ 			}
+ 
+@@ -474,6 +479,8 @@ static int bgmac_dma_rx_read(struct bgma
+ 				bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
+ 					  ring->start);
+ 				put_page(virt_to_head_page(buf));
++				bgmac->net_dev->stats.rx_length_errors++;
++				bgmac->net_dev->stats.rx_errors++;
+ 				break;
+ 			}
+ 
+@@ -484,6 +491,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 			if (unlikely(!skb)) {
+ 				bgmac_err(bgmac, "build_skb failed\n");
+ 				put_page(virt_to_head_page(buf));
++				bgmac->net_dev->stats.rx_errors++;
+ 				break;
+ 			}
+ 			skb_put(skb, BGMAC_RX_FRAME_OFFSET +
+@@ -493,6 +501,8 @@ static int bgmac_dma_rx_read(struct bgma
+ 
+ 			skb_checksum_none_assert(skb);
+ 			skb->protocol = eth_type_trans(skb, bgmac->net_dev);
++			bgmac->net_dev->stats.rx_bytes += len;
++			bgmac->net_dev->stats.rx_packets++;
+ 			napi_gro_receive(&bgmac->napi, skb);
+ 			handled++;
+ 		} while (0);
diff --git a/target/linux/generic/patches-4.4/073-0001-net-ethernet-bgmac-use-phydev-from-struct-net_device.patch b/target/linux/generic/patches-4.4/073-0001-net-ethernet-bgmac-use-phydev-from-struct-net_device.patch
new file mode 100644
index 0000000000..8c97b09970
--- /dev/null
+++ b/target/linux/generic/patches-4.4/073-0001-net-ethernet-bgmac-use-phydev-from-struct-net_device.patch
@@ -0,0 +1,105 @@
+From b21fcb259313bcf7d4f73ecd5e44948995c8957c Mon Sep 17 00:00:00 2001
+From: Philippe Reynes <tremyfr@gmail.com>
+Date: Sun, 19 Jun 2016 22:37:05 +0200
+Subject: [PATCH 1/2] net: ethernet: bgmac: use phydev from struct net_device
+
+The private structure contain a pointer to phydev, but the structure
+net_device already contain such pointer. So we can remove the pointer
+phydev in the private structure, and update the driver to use the
+one contained in struct net_device.
+
+Signed-off-by: Philippe Reynes <tremyfr@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 17 ++++++-----------
+ drivers/net/ethernet/broadcom/bgmac.h |  1 -
+ 2 files changed, 6 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1323,7 +1323,7 @@ static int bgmac_open(struct net_device
+ 	}
+ 	napi_enable(&bgmac->napi);
+ 
+-	phy_start(bgmac->phy_dev);
++	phy_start(net_dev->phydev);
+ 
+ 	netif_carrier_on(net_dev);
+ 	return 0;
+@@ -1335,7 +1335,7 @@ static int bgmac_stop(struct net_device
+ 
+ 	netif_carrier_off(net_dev);
+ 
+-	phy_stop(bgmac->phy_dev);
++	phy_stop(net_dev->phydev);
+ 
+ 	napi_disable(&bgmac->napi);
+ 	bgmac_chip_intrs_off(bgmac);
+@@ -1373,12 +1373,10 @@ static int bgmac_set_mac_address(struct
+ 
+ static int bgmac_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+ {
+-	struct bgmac *bgmac = netdev_priv(net_dev);
+-
+ 	if (!netif_running(net_dev))
+ 		return -EINVAL;
+ 
+-	return phy_mii_ioctl(bgmac->phy_dev, ifr, cmd);
++	return phy_mii_ioctl(net_dev->phydev, ifr, cmd);
+ }
+ 
+ static const struct net_device_ops bgmac_netdev_ops = {
+@@ -1521,7 +1519,7 @@ static int bgmac_get_settings(struct net
+ {
+ 	struct bgmac *bgmac = netdev_priv(net_dev);
+ 
+-	return phy_ethtool_gset(bgmac->phy_dev, cmd);
++	return phy_ethtool_gset(net_dev->phydev, cmd);
+ }
+ 
+ static int bgmac_set_settings(struct net_device *net_dev,
+@@ -1529,7 +1527,7 @@ static int bgmac_set_settings(struct net
+ {
+ 	struct bgmac *bgmac = netdev_priv(net_dev);
+ 
+-	return phy_ethtool_sset(bgmac->phy_dev, cmd);
++	return phy_ethtool_sset(net_dev->phydev, cmd);
+ }
+ 
+ static void bgmac_get_drvinfo(struct net_device *net_dev,
+@@ -1566,7 +1564,7 @@ static int bgmac_mii_write(struct mii_bu
+ static void bgmac_adjust_link(struct net_device *net_dev)
+ {
+ 	struct bgmac *bgmac = netdev_priv(net_dev);
+-	struct phy_device *phy_dev = bgmac->phy_dev;
++	struct phy_device *phy_dev = net_dev->phydev;
+ 	bool update = false;
+ 
+ 	if (phy_dev->link) {
+@@ -1610,8 +1608,6 @@ static int bgmac_fixed_phy_register(stru
+ 		return err;
+ 	}
+ 
+-	bgmac->phy_dev = phy_dev;
+-
+ 	return err;
+ }
+ 
+@@ -1664,7 +1660,6 @@ static int bgmac_mii_register(struct bgm
+ 		err = PTR_ERR(phy_dev);
+ 		goto err_unregister_bus;
+ 	}
+-	bgmac->phy_dev = phy_dev;
+ 
+ 	return err;
+ 
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -441,7 +441,6 @@ struct bgmac {
+ 	struct net_device *net_dev;
+ 	struct napi_struct napi;
+ 	struct mii_bus *mii_bus;
+-	struct phy_device *phy_dev;
+ 
+ 	/* DMA */
+ 	struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
diff --git a/target/linux/generic/patches-4.4/074-0001-net-bgmac-Fix-SOF-bit-checking.patch b/target/linux/generic/patches-4.4/074-0001-net-bgmac-Fix-SOF-bit-checking.patch
new file mode 100644
index 0000000000..ea73fda6ff
--- /dev/null
+++ b/target/linux/generic/patches-4.4/074-0001-net-bgmac-Fix-SOF-bit-checking.patch
@@ -0,0 +1,37 @@
+From d2b13233879ca1268a1c027d4573109e5a777811 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Thu, 23 Jun 2016 14:23:12 -0700
+Subject: [PATCH 1/3] net: bgmac: Fix SOF bit checking
+
+We are checking for the Start of Frame bit in the ctl1 word, while this
+bit is set in the ctl0 word instead. Read the ctl0 word and update the
+check to verify that.
+
+Fixes: 9cde94506eac ("bgmac: implement scatter/gather support")
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -269,15 +269,16 @@ static void bgmac_dma_tx_free(struct bgm
+ 	while (ring->start != ring->end) {
+ 		int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
+ 		struct bgmac_slot_info *slot = &ring->slots[slot_idx];
+-		u32 ctl1;
++		u32 ctl0, ctl1;
+ 		int len;
+ 
+ 		if (slot_idx == empty_slot)
+ 			break;
+ 
++		ctl0 = le32_to_cpu(ring->cpu_base[slot_idx].ctl0);
+ 		ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
+ 		len = ctl1 & BGMAC_DESC_CTL1_LEN;
+-		if (ctl1 & BGMAC_DESC_CTL0_SOF)
++		if (ctl0 & BGMAC_DESC_CTL0_SOF)
+ 			/* Unmap no longer used buffer */
+ 			dma_unmap_single(dma_dev, slot->dma_addr, len,
+ 					 DMA_TO_DEVICE);
diff --git a/target/linux/generic/patches-4.4/074-0002-net-bgmac-Start-transmit-queue-in-bgmac_open.patch b/target/linux/generic/patches-4.4/074-0002-net-bgmac-Start-transmit-queue-in-bgmac_open.patch
new file mode 100644
index 0000000000..6a866bccdb
--- /dev/null
+++ b/target/linux/generic/patches-4.4/074-0002-net-bgmac-Start-transmit-queue-in-bgmac_open.patch
@@ -0,0 +1,28 @@
+From c3897f2a69e54dd113fc9abd2daf872e5b495798 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Thu, 23 Jun 2016 14:25:32 -0700
+Subject: [PATCH 2/3] net: bgmac: Start transmit queue in bgmac_open
+
+The driver does not start the transmit queue in bgmac_open(). If the
+queue was stopped prior to closing then re-opening the interface, we
+would never be able to wake-up again.
+
+Fixes: dd4544f05469 ("bgmac: driver for GBit MAC core on BCMA bus")
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1327,6 +1327,9 @@ static int bgmac_open(struct net_device
+ 	phy_start(net_dev->phydev);
+ 
+ 	netif_carrier_on(net_dev);
++
++	netif_start_queue(net_dev);
++
+ 	return 0;
+ }
+ 
diff --git a/target/linux/generic/patches-4.4/074-0003-net-bgmac-Remove-superflous-netif_carrier_on.patch b/target/linux/generic/patches-4.4/074-0003-net-bgmac-Remove-superflous-netif_carrier_on.patch
new file mode 100644
index 0000000000..0edf9ee9fa
--- /dev/null
+++ b/target/linux/generic/patches-4.4/074-0003-net-bgmac-Remove-superflous-netif_carrier_on.patch
@@ -0,0 +1,28 @@
+From 3894396e64994f31c3ef5c7e6f63dded0593e567 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Thu, 23 Jun 2016 14:25:33 -0700
+Subject: [PATCH 3/3] net: bgmac: Remove superflous netif_carrier_on()
+
+bgmac_open() calls phy_start() to initialize the PHY state machine,
+which will set the interface's carrier state accordingly, no need to
+force that as this could be conflicting with the PHY state determined by
+PHYLIB.
+
+Fixes: dd4544f05469 ("bgmac: driver for GBit MAC core on BCMA bus")
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1326,8 +1326,6 @@ static int bgmac_open(struct net_device
+ 
+ 	phy_start(net_dev->phydev);
+ 
+-	netif_carrier_on(net_dev);
+-
+ 	netif_start_queue(net_dev);
+ 
+ 	return 0;
diff --git a/target/linux/generic/patches-4.4/075-0001-net-ethernet-bgmac-change-bgmac_-prints-to-dev_-prin.patch b/target/linux/generic/patches-4.4/075-0001-net-ethernet-bgmac-change-bgmac_-prints-to-dev_-prin.patch
new file mode 100644
index 0000000000..3837b60943
--- /dev/null
+++ b/target/linux/generic/patches-4.4/075-0001-net-ethernet-bgmac-change-bgmac_-prints-to-dev_-prin.patch
@@ -0,0 +1,407 @@
+From d00a8281bcc962027dfe409c2f3e3f0546be9200 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jon.mason@broadcom.com>
+Date: Thu, 7 Jul 2016 19:08:53 -0400
+Subject: [PATCH 1/5] net: ethernet: bgmac: change bgmac_* prints to dev_*
+ prints
+
+The bgmac_* print wrappers call dev_* prints with the dev pointer from
+the bcma core.  In anticipation of removing the bcma requirement for
+this driver, these must be changed to not reference that struct.  So,
+simply change all of the bgmac_* prints to their dev_* counterparts.  In
+some cases netdev_* prints are more appropriate, so change those as
+well.
+
+Signed-off-by: Jon Mason <jon.mason@broadcom.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 103 +++++++++++++++++-----------------
+ drivers/net/ethernet/broadcom/bgmac.h |  14 +----
+ 2 files changed, 55 insertions(+), 62 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -50,7 +50,7 @@ static bool bgmac_wait_value(struct bcma
+ 			return true;
+ 		udelay(10);
+ 	}
+-	pr_err("Timeout waiting for reg 0x%X\n", reg);
++	dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
+ 	return false;
+ }
+ 
+@@ -84,8 +84,8 @@ static void bgmac_dma_tx_reset(struct bg
+ 		udelay(10);
+ 	}
+ 	if (i)
+-		bgmac_err(bgmac, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
+-			  ring->mmio_base, val);
++		dev_err(bgmac->dev, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
++			ring->mmio_base, val);
+ 
+ 	/* Remove SUSPEND bit */
+ 	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
+@@ -93,13 +93,13 @@ static void bgmac_dma_tx_reset(struct bg
+ 			      ring->mmio_base + BGMAC_DMA_TX_STATUS,
+ 			      BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
+ 			      10000)) {
+-		bgmac_warn(bgmac, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
+-			   ring->mmio_base);
++		dev_warn(bgmac->dev, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
++			 ring->mmio_base);
+ 		udelay(300);
+ 		val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+ 		if ((val & BGMAC_DMA_TX_STAT) != BGMAC_DMA_TX_STAT_DISABLED)
+-			bgmac_err(bgmac, "Reset of DMA TX ring 0x%X failed\n",
+-				  ring->mmio_base);
++			dev_err(bgmac->dev, "Reset of DMA TX ring 0x%X failed\n",
++				ring->mmio_base);
+ 	}
+ }
+ 
+@@ -161,7 +161,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 	int i;
+ 
+ 	if (skb->len > BGMAC_DESC_CTL1_LEN) {
+-		bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
++		netdev_err(bgmac->net_dev, "Too long skb (%d)\n", skb->len);
+ 		goto err_drop;
+ 	}
+ 
+@@ -174,7 +174,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 	 * even when ring->end overflows
+ 	 */
+ 	if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
+-		bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
++		netdev_err(bgmac->net_dev, "TX ring is full, queue should be stopped!\n");
+ 		netif_stop_queue(net_dev);
+ 		return NETDEV_TX_BUSY;
+ 	}
+@@ -241,8 +241,8 @@ err_dma:
+ 	}
+ 
+ err_dma_head:
+-	bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
+-		  ring->mmio_base);
++	netdev_err(bgmac->net_dev, "Mapping error of skb on ring 0x%X\n",
++		   ring->mmio_base);
+ 
+ err_drop:
+ 	dev_kfree_skb(skb);
+@@ -321,8 +321,8 @@ static void bgmac_dma_rx_reset(struct bg
+ 			      ring->mmio_base + BGMAC_DMA_RX_STATUS,
+ 			      BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
+ 			      10000))
+-		bgmac_err(bgmac, "Reset of ring 0x%X RX failed\n",
+-			  ring->mmio_base);
++		dev_err(bgmac->dev, "Reset of ring 0x%X RX failed\n",
++			ring->mmio_base);
+ }
+ 
+ static void bgmac_dma_rx_enable(struct bgmac *bgmac,
+@@ -374,7 +374,7 @@ static int bgmac_dma_rx_skb_for_slot(str
+ 	dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET,
+ 				  BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+ 	if (dma_mapping_error(dma_dev, dma_addr)) {
+-		bgmac_err(bgmac, "DMA mapping error\n");
++		netdev_err(bgmac->net_dev, "DMA mapping error\n");
+ 		put_page(virt_to_head_page(buf));
+ 		return -ENOMEM;
+ 	}
+@@ -469,16 +469,16 @@ static int bgmac_dma_rx_read(struct bgma
+ 
+ 			/* Check for poison and drop or pass the packet */
+ 			if (len == 0xdead && flags == 0xbeef) {
+-				bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+-					  ring->start);
++				netdev_err(bgmac->net_dev, "Found poisoned packet at slot %d, DMA issue!\n",
++					   ring->start);
+ 				put_page(virt_to_head_page(buf));
+ 				bgmac->net_dev->stats.rx_errors++;
+ 				break;
+ 			}
+ 
+ 			if (len > BGMAC_RX_ALLOC_SIZE) {
+-				bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
+-					  ring->start);
++				netdev_err(bgmac->net_dev, "Found oversized packet at slot %d, DMA issue!\n",
++					   ring->start);
+ 				put_page(virt_to_head_page(buf));
+ 				bgmac->net_dev->stats.rx_length_errors++;
+ 				bgmac->net_dev->stats.rx_errors++;
+@@ -490,7 +490,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 
+ 			skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
+ 			if (unlikely(!skb)) {
+-				bgmac_err(bgmac, "build_skb failed\n");
++				netdev_err(bgmac->net_dev, "build_skb failed\n");
+ 				put_page(virt_to_head_page(buf));
+ 				bgmac->net_dev->stats.rx_errors++;
+ 				break;
+@@ -644,7 +644,7 @@ static int bgmac_dma_alloc(struct bgmac
+ 	BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
+ 
+ 	if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
+-		bgmac_err(bgmac, "Core does not report 64-bit DMA\n");
++		dev_err(bgmac->dev, "Core does not report 64-bit DMA\n");
+ 		return -ENOTSUPP;
+ 	}
+ 
+@@ -658,8 +658,8 @@ static int bgmac_dma_alloc(struct bgmac
+ 						     &ring->dma_base,
+ 						     GFP_KERNEL);
+ 		if (!ring->cpu_base) {
+-			bgmac_err(bgmac, "Allocation of TX ring 0x%X failed\n",
+-				  ring->mmio_base);
++			dev_err(bgmac->dev, "Allocation of TX ring 0x%X failed\n",
++				ring->mmio_base);
+ 			goto err_dma_free;
+ 		}
+ 
+@@ -683,8 +683,8 @@ static int bgmac_dma_alloc(struct bgmac
+ 						     &ring->dma_base,
+ 						     GFP_KERNEL);
+ 		if (!ring->cpu_base) {
+-			bgmac_err(bgmac, "Allocation of RX ring 0x%X failed\n",
+-				  ring->mmio_base);
++			dev_err(bgmac->dev, "Allocation of RX ring 0x%X failed\n",
++				ring->mmio_base);
+ 			err = -ENOMEM;
+ 			goto err_dma_free;
+ 		}
+@@ -803,8 +803,8 @@ static u16 bgmac_phy_read(struct bgmac *
+ 	bcma_write32(core, phy_access_addr, tmp);
+ 
+ 	if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+-		bgmac_err(bgmac, "Reading PHY %d register 0x%X failed\n",
+-			  phyaddr, reg);
++		dev_err(bgmac->dev, "Reading PHY %d register 0x%X failed\n",
++			phyaddr, reg);
+ 		return 0xffff;
+ 	}
+ 
+@@ -836,7 +836,7 @@ static int bgmac_phy_write(struct bgmac
+ 
+ 	bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
+ 	if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
+-		bgmac_warn(bgmac, "Error setting MDIO int\n");
++		dev_warn(bgmac->dev, "Error setting MDIO int\n");
+ 
+ 	tmp = BGMAC_PA_START;
+ 	tmp |= BGMAC_PA_WRITE;
+@@ -846,8 +846,8 @@ static int bgmac_phy_write(struct bgmac
+ 	bcma_write32(core, phy_access_addr, tmp);
+ 
+ 	if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+-		bgmac_err(bgmac, "Writing to PHY %d register 0x%X failed\n",
+-			  phyaddr, reg);
++		dev_err(bgmac->dev, "Writing to PHY %d register 0x%X failed\n",
++			phyaddr, reg);
+ 		return -ETIMEDOUT;
+ 	}
+ 
+@@ -900,7 +900,7 @@ static void bgmac_phy_reset(struct bgmac
+ 	bgmac_phy_write(bgmac, bgmac->phyaddr, MII_BMCR, BMCR_RESET);
+ 	udelay(100);
+ 	if (bgmac_phy_read(bgmac, bgmac->phyaddr, MII_BMCR) & BMCR_RESET)
+-		bgmac_err(bgmac, "PHY reset failed\n");
++		dev_err(bgmac->dev, "PHY reset failed\n");
+ 	bgmac_phy_init(bgmac);
+ }
+ 
+@@ -1001,7 +1001,8 @@ static void bgmac_mac_speed(struct bgmac
+ 		set |= BGMAC_CMDCFG_ES_2500;
+ 		break;
+ 	default:
+-		bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed);
++		dev_err(bgmac->dev, "Unsupported speed: %d\n",
++			bgmac->mac_speed);
+ 	}
+ 
+ 	if (bgmac->mac_duplex == DUPLEX_HALF)
+@@ -1100,8 +1101,8 @@ static void bgmac_chip_reset(struct bgma
+ 
+ 		if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
+ 			if (kstrtou8(buf, 0, &et_swtype))
+-				bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
+-					  buf);
++				dev_err(bgmac->dev, "Failed to parse et_swtype (%s)\n",
++					buf);
+ 			et_swtype &= 0x0f;
+ 			et_swtype <<= 4;
+ 			sw_type = et_swtype;
+@@ -1264,7 +1265,7 @@ static irqreturn_t bgmac_interrupt(int i
+ 
+ 	int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX);
+ 	if (int_status)
+-		bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status);
++		dev_err(bgmac->dev, "Unknown IRQs: 0x%08X\n", int_status);
+ 
+ 	/* Disable new interrupts until handling existing ones */
+ 	bgmac_chip_intrs_off(bgmac);
+@@ -1318,7 +1319,7 @@ static int bgmac_open(struct net_device
+ 	err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
+ 			  KBUILD_MODNAME, net_dev);
+ 	if (err < 0) {
+-		bgmac_err(bgmac, "IRQ request error: %d!\n", err);
++		dev_err(bgmac->dev, "IRQ request error: %d!\n", err);
+ 		bgmac_dma_cleanup(bgmac);
+ 		return err;
+ 	}
+@@ -1599,14 +1600,14 @@ static int bgmac_fixed_phy_register(stru
+ 
+ 	phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL);
+ 	if (!phy_dev || IS_ERR(phy_dev)) {
+-		bgmac_err(bgmac, "Failed to register fixed PHY device\n");
++		dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
+ 		return -ENODEV;
+ 	}
+ 
+ 	err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
+ 				 PHY_INTERFACE_MODE_MII);
+ 	if (err) {
+-		bgmac_err(bgmac, "Connecting PHY failed\n");
++		dev_err(bgmac->dev, "Connecting PHY failed\n");
+ 		return err;
+ 	}
+ 
+@@ -1646,7 +1647,7 @@ static int bgmac_mii_register(struct bgm
+ 
+ 	err = mdiobus_register(mii_bus);
+ 	if (err) {
+-		bgmac_err(bgmac, "Registration of mii bus failed\n");
++		dev_err(bgmac->dev, "Registration of mii bus failed\n");
+ 		goto err_free_irq;
+ 	}
+ 
+@@ -1658,7 +1659,7 @@ static int bgmac_mii_register(struct bgm
+ 	phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
+ 			      PHY_INTERFACE_MODE_MII);
+ 	if (IS_ERR(phy_dev)) {
+-		bgmac_err(bgmac, "PHY connecton failed\n");
++		dev_err(bgmac->dev, "PHY connecton failed\n");
+ 		err = PTR_ERR(phy_dev);
+ 		goto err_unregister_bus;
+ 	}
+@@ -1707,7 +1708,8 @@ static int bgmac_probe(struct bcma_devic
+ 		mac = sprom->et2mac;
+ 		break;
+ 	default:
+-		pr_err("Unsupported core_unit %d\n", core->core_unit);
++		dev_err(&core->dev, "Unsupported core_unit %d\n",
++			core->core_unit);
+ 		return -ENOTSUPP;
+ 	}
+ 
+@@ -1730,6 +1732,7 @@ static int bgmac_probe(struct bcma_devic
+ 	net_dev->irq = core->irq;
+ 	net_dev->ethtool_ops = &bgmac_ethtool_ops;
+ 	bgmac = netdev_priv(net_dev);
++	bgmac->dev = &core->dev;
+ 	bgmac->net_dev = net_dev;
+ 	bgmac->core = core;
+ 	bcma_set_drvdata(core, bgmac);
+@@ -1741,7 +1744,7 @@ static int bgmac_probe(struct bcma_devic
+ 	/* On BCM4706 we need common core to access PHY */
+ 	if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+ 	    !core->bus->drv_gmac_cmn.core) {
+-		bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n");
++		dev_err(bgmac->dev, "GMAC CMN core not found (required for BCM4706)\n");
+ 		err = -ENODEV;
+ 		goto err_netdev_free;
+ 	}
+@@ -1760,15 +1763,15 @@ static int bgmac_probe(struct bcma_devic
+ 	}
+ 	bgmac->phyaddr &= BGMAC_PHY_MASK;
+ 	if (bgmac->phyaddr == BGMAC_PHY_MASK) {
+-		bgmac_err(bgmac, "No PHY found\n");
++		dev_err(bgmac->dev, "No PHY found\n");
+ 		err = -ENODEV;
+ 		goto err_netdev_free;
+ 	}
+-	bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr,
+-		   bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
++	dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
++		 bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
+ 
+ 	if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
+-		bgmac_err(bgmac, "PCI setup not implemented\n");
++		dev_err(bgmac->dev, "PCI setup not implemented\n");
+ 		err = -ENOTSUPP;
+ 		goto err_netdev_free;
+ 	}
+@@ -1797,7 +1800,7 @@ static int bgmac_probe(struct bcma_devic
+ 
+ 	err = bgmac_dma_alloc(bgmac);
+ 	if (err) {
+-		bgmac_err(bgmac, "Unable to alloc memory for DMA\n");
++		dev_err(bgmac->dev, "Unable to alloc memory for DMA\n");
+ 		goto err_netdev_free;
+ 	}
+ 
+@@ -1811,16 +1814,16 @@ static int bgmac_probe(struct bcma_devic
+ 	bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
+ 			       BGMAC_BFL_ENETROBO);
+ 	if (bgmac->has_robosw)
+-		bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
++		dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n");
+ 
+ 	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+-		bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
++		dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
+ 
+ 	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+ 
+ 	err = bgmac_mii_register(bgmac);
+ 	if (err) {
+-		bgmac_err(bgmac, "Cannot register MDIO\n");
++		dev_err(bgmac->dev, "Cannot connect to phy\n");
+ 		goto err_dma_free;
+ 	}
+ 
+@@ -1830,7 +1833,7 @@ static int bgmac_probe(struct bcma_devic
+ 
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+-		bgmac_err(bgmac, "Cannot register net device\n");
++		dev_err(bgmac->dev, "Cannot register net device\n");
+ 		goto err_mii_unregister;
+ 	}
+ 
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -1,17 +1,6 @@
+ #ifndef _BGMAC_H
+ #define _BGMAC_H
+ 
+-#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
+-
+-#define bgmac_err(bgmac, fmt, ...) \
+-	dev_err(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+-#define bgmac_warn(bgmac, fmt, ...) \
+-	dev_warn(&(bgmac)->core->dev, fmt,  ##__VA_ARGS__)
+-#define bgmac_info(bgmac, fmt, ...) \
+-	dev_info(&(bgmac)->core->dev, fmt,  ##__VA_ARGS__)
+-#define bgmac_dbg(bgmac, fmt, ...) \
+-	dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+-
+ #include <linux/bcma/bcma.h>
+ #include <linux/brcmphy.h>
+ #include <linux/netdevice.h>
+@@ -438,6 +427,8 @@ struct bgmac_rx_header {
+ struct bgmac {
+ 	struct bcma_device *core;
+ 	struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
++
++	struct device *dev;
+ 	struct net_device *net_dev;
+ 	struct napi_struct napi;
+ 	struct mii_bus *mii_bus;
+@@ -489,5 +480,4 @@ static inline void bgmac_set(struct bgma
+ {
+ 	bgmac_maskset(bgmac, offset, ~0, set);
+ }
+-
+ #endif /* _BGMAC_H */
diff --git a/target/linux/generic/patches-4.4/075-0002-net-ethernet-bgmac-add-dma_dev-pointer.patch b/target/linux/generic/patches-4.4/075-0002-net-ethernet-bgmac-add-dma_dev-pointer.patch
new file mode 100644
index 0000000000..dd5b8772e3
--- /dev/null
+++ b/target/linux/generic/patches-4.4/075-0002-net-ethernet-bgmac-add-dma_dev-pointer.patch
@@ -0,0 +1,112 @@
+From a0b68486f6f680c7c0352a47c60042d7d95ffd87 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jon.mason@broadcom.com>
+Date: Thu, 7 Jul 2016 19:08:54 -0400
+Subject: [PATCH 2/5] net: ethernet: bgmac: add dma_dev pointer
+
+The dma buffer allocation, etc references a dma_dev device pointer from
+the bcma core.  In anticipation of removing the bcma requirement for
+this driver, these must be changed to not reference that struct.  Add a
+dma_dev device pointer to the bgmac stuct and reference that instead.
+
+Signed-off-by: Jon Mason <jon.mason@broadcom.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 17 +++++++++--------
+ drivers/net/ethernet/broadcom/bgmac.h |  1 +
+ 2 files changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -152,7 +152,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
+ 				    struct bgmac_dma_ring *ring,
+ 				    struct sk_buff *skb)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	struct net_device *net_dev = bgmac->net_dev;
+ 	int index = ring->end % BGMAC_TX_RING_SLOTS;
+ 	struct bgmac_slot_info *slot = &ring->slots[index];
+@@ -254,7 +254,7 @@ err_drop:
+ /* Free transmitted packets */
+ static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	int empty_slot;
+ 	bool freed = false;
+ 	unsigned bytes_compl = 0, pkts_compl = 0;
+@@ -355,7 +355,7 @@ static void bgmac_dma_rx_enable(struct b
+ static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
+ 				     struct bgmac_slot_info *slot)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	dma_addr_t dma_addr;
+ 	struct bgmac_rx_header *rx;
+ 	void *buf;
+@@ -444,7 +444,7 @@ static int bgmac_dma_rx_read(struct bgma
+ 	end_slot /= sizeof(struct bgmac_dma_desc);
+ 
+ 	while (ring->start != end_slot) {
+-		struct device *dma_dev = bgmac->core->dma_dev;
++		struct device *dma_dev = bgmac->dma_dev;
+ 		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+ 		struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
+ 		struct sk_buff *skb;
+@@ -547,7 +547,7 @@ static bool bgmac_dma_unaligned(struct b
+ static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
+ 				   struct bgmac_dma_ring *ring)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	struct bgmac_dma_desc *dma_desc = ring->cpu_base;
+ 	struct bgmac_slot_info *slot;
+ 	int i;
+@@ -573,7 +573,7 @@ static void bgmac_dma_tx_ring_free(struc
+ static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
+ 				   struct bgmac_dma_ring *ring)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	struct bgmac_slot_info *slot;
+ 	int i;
+ 
+@@ -594,7 +594,7 @@ static void bgmac_dma_ring_desc_free(str
+ 				     struct bgmac_dma_ring *ring,
+ 				     int num_slots)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	int size;
+ 
+ 	if (!ring->cpu_base)
+@@ -632,7 +632,7 @@ static void bgmac_dma_free(struct bgmac
+ 
+ static int bgmac_dma_alloc(struct bgmac *bgmac)
+ {
+-	struct device *dma_dev = bgmac->core->dma_dev;
++	struct device *dma_dev = bgmac->dma_dev;
+ 	struct bgmac_dma_ring *ring;
+ 	static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
+ 					 BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
+@@ -1733,6 +1733,7 @@ static int bgmac_probe(struct bcma_devic
+ 	net_dev->ethtool_ops = &bgmac_ethtool_ops;
+ 	bgmac = netdev_priv(net_dev);
+ 	bgmac->dev = &core->dev;
++	bgmac->dma_dev = core->dma_dev;
+ 	bgmac->net_dev = net_dev;
+ 	bgmac->core = core;
+ 	bcma_set_drvdata(core, bgmac);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -429,6 +429,7 @@ struct bgmac {
+ 	struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
+ 
+ 	struct device *dev;
++	struct device *dma_dev;
+ 	struct net_device *net_dev;
+ 	struct napi_struct napi;
+ 	struct mii_bus *mii_bus;
diff --git a/target/linux/generic/patches-4.4/075-0003-net-ethernet-bgmac-move-BCMA-MDIO-Phy-code-into-a-se.patch b/target/linux/generic/patches-4.4/075-0003-net-ethernet-bgmac-move-BCMA-MDIO-Phy-code-into-a-se.patch
new file mode 100644
index 0000000000..bc7b246cc1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/075-0003-net-ethernet-bgmac-move-BCMA-MDIO-Phy-code-into-a-se.patch
@@ -0,0 +1,676 @@
+From 55954f3bfdacc5908515b0c306cea23e77fab740 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jon.mason@broadcom.com>
+Date: Thu, 7 Jul 2016 19:08:55 -0400
+Subject: [PATCH 3/5] net: ethernet: bgmac: move BCMA MDIO Phy code into a
+ separate file
+
+Move the BCMA MDIO phy into a separate file, as it is very tightly
+coupled with the BCMA bus.  This will help with the upcoming BCMA
+removal from the bgmac driver.  Optimally, this should be moved into
+phy drivers, but it is too tightly coupled with the bgmac driver to
+effectively move it without more changes to the driver.
+
+Note: the phy_reset was intentionally removed, as the mdio phy subsystem
+automatically resets the phy if a reset function pointer is present.  In
+addition to the moving of the driver, this reset function is added.
+
+Signed-off-by: Jon Mason <jon.mason@broadcom.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/Makefile          |   2 +-
+ drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 264 ++++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/bgmac.c           | 246 +++-------------------
+ drivers/net/ethernet/broadcom/bgmac.h           |   3 +
+ 4 files changed, 298 insertions(+), 217 deletions(-)
+ create mode 100644 drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
+
+--- a/drivers/net/ethernet/broadcom/Makefile
++++ b/drivers/net/ethernet/broadcom/Makefile
+@@ -10,6 +10,6 @@ obj-$(CONFIG_CNIC) += cnic.o
+ obj-$(CONFIG_BNX2X) += bnx2x/
+ obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
+ obj-$(CONFIG_TIGON3) += tg3.o
+-obj-$(CONFIG_BGMAC) += bgmac.o
++obj-$(CONFIG_BGMAC) += bgmac.o bgmac-bcma-mdio.o
+ obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
+ obj-$(CONFIG_BNXT) += bnxt/
+--- /dev/null
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
+@@ -0,0 +1,275 @@
++/*
++ * Driver for (BCM4706)? GBit MAC core on BCMA bus.
++ *
++ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
++
++#include <linux/bcma/bcma.h>
++#include <linux/brcmphy.h>
++#include "bgmac.h"
++
++struct bcma_mdio {
++	struct bcma_device *core;
++	u8 phyaddr;
++};
++
++static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
++				 u32 value, int timeout)
++{
++	u32 val;
++	int i;
++
++	for (i = 0; i < timeout / 10; i++) {
++		val = bcma_read32(core, reg);
++		if ((val & mask) == value)
++			return true;
++		udelay(10);
++	}
++	dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
++	return false;
++}
++
++/**************************************************
++ * PHY ops
++ **************************************************/
++
++static u16 bcma_mdio_phy_read(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg)
++{
++	struct bcma_device *core;
++	u16 phy_access_addr;
++	u16 phy_ctl_addr;
++	u32 tmp;
++
++	BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
++	BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
++	BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
++	BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
++	BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
++	BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
++	BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
++	BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
++	BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
++	BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
++	BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
++
++	if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
++		core = bcma_mdio->core->bus->drv_gmac_cmn.core;
++		phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
++		phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
++	} else {
++		core = bcma_mdio->core;
++		phy_access_addr = BGMAC_PHY_ACCESS;
++		phy_ctl_addr = BGMAC_PHY_CNTL;
++	}
++
++	tmp = bcma_read32(core, phy_ctl_addr);
++	tmp &= ~BGMAC_PC_EPA_MASK;
++	tmp |= phyaddr;
++	bcma_write32(core, phy_ctl_addr, tmp);
++
++	tmp = BGMAC_PA_START;
++	tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
++	tmp |= reg << BGMAC_PA_REG_SHIFT;
++	bcma_write32(core, phy_access_addr, tmp);
++
++	if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
++				  1000)) {
++		dev_err(&core->dev, "Reading PHY %d register 0x%X failed\n",
++			phyaddr, reg);
++		return 0xffff;
++	}
++
++	return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
++}
++
++/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
++static int bcma_mdio_phy_write(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg,
++			       u16 value)
++{
++	struct bcma_device *core;
++	u16 phy_access_addr;
++	u16 phy_ctl_addr;
++	u32 tmp;
++
++	if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
++		core = bcma_mdio->core->bus->drv_gmac_cmn.core;
++		phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
++		phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
++	} else {
++		core = bcma_mdio->core;
++		phy_access_addr = BGMAC_PHY_ACCESS;
++		phy_ctl_addr = BGMAC_PHY_CNTL;
++	}
++
++	tmp = bcma_read32(core, phy_ctl_addr);
++	tmp &= ~BGMAC_PC_EPA_MASK;
++	tmp |= phyaddr;
++	bcma_write32(core, phy_ctl_addr, tmp);
++
++	bcma_write32(bcma_mdio->core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
++	if (bcma_read32(bcma_mdio->core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
++		dev_warn(&core->dev, "Error setting MDIO int\n");
++
++	tmp = BGMAC_PA_START;
++	tmp |= BGMAC_PA_WRITE;
++	tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
++	tmp |= reg << BGMAC_PA_REG_SHIFT;
++	tmp |= value;
++	bcma_write32(core, phy_access_addr, tmp);
++
++	if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
++				  1000)) {
++		dev_err(&core->dev, "Writing to PHY %d register 0x%X failed\n",
++			phyaddr, reg);
++		return -ETIMEDOUT;
++	}
++
++	return 0;
++}
++
++/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
++static void bcma_mdio_phy_init(struct bcma_mdio *bcma_mdio)
++{
++	struct bcma_chipinfo *ci = &bcma_mdio->core->bus->chipinfo;
++	u8 i;
++
++	if (ci->id == BCMA_CHIP_ID_BCM5356) {
++		for (i = 0; i < 5; i++) {
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x008b);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x15, 0x0100);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x12, 0x2aaa);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
++		}
++	}
++	if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
++	    (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
++	    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
++		struct bcma_drv_cc *cc = &bcma_mdio->core->bus->drv_cc;
++
++		bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
++		bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
++		for (i = 0; i < 5; i++) {
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5284);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x0010);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5296);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x1073);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9073);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x52b6);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9273);
++			bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
++		}
++	}
++}
++
++/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
++static int bcma_mdio_phy_reset(struct mii_bus *bus)
++{
++	struct bcma_mdio *bcma_mdio = bus->priv;
++	u8 phyaddr = bcma_mdio->phyaddr;
++
++	if (bcma_mdio->phyaddr == BGMAC_PHY_NOREGS)
++		return 0;
++
++	bcma_mdio_phy_write(bcma_mdio, phyaddr, MII_BMCR, BMCR_RESET);
++	udelay(100);
++	if (bcma_mdio_phy_read(bcma_mdio, phyaddr, MII_BMCR) & BMCR_RESET)
++		dev_err(&bcma_mdio->core->dev, "PHY reset failed\n");
++	bcma_mdio_phy_init(bcma_mdio);
++
++	return 0;
++}
++
++/**************************************************
++ * MII
++ **************************************************/
++
++static int bcma_mdio_mii_read(struct mii_bus *bus, int mii_id, int regnum)
++{
++	return bcma_mdio_phy_read(bus->priv, mii_id, regnum);
++}
++
++static int bcma_mdio_mii_write(struct mii_bus *bus, int mii_id, int regnum,
++			       u16 value)
++{
++	return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value);
++}
++
++struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr)
++{
++	struct bcma_mdio *bcma_mdio;
++	struct mii_bus *mii_bus;
++	int i, err;
++
++	bcma_mdio = kzalloc(sizeof(*bcma_mdio), GFP_KERNEL);
++	if (!bcma_mdio)
++		return ERR_PTR(-ENOMEM);
++
++	mii_bus = mdiobus_alloc();
++	if (!mii_bus) {
++		err = -ENOMEM;
++		goto err;
++	}
++
++	mii_bus->name = "bcma_mdio mii bus";
++	sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num,
++		core->core_unit);
++	mii_bus->priv = bcma_mdio;
++	mii_bus->read = bcma_mdio_mii_read;
++	mii_bus->write = bcma_mdio_mii_write;
++	mii_bus->reset = bcma_mdio_phy_reset;
++	mii_bus->parent = &core->dev;
++	mii_bus->phy_mask = ~(1 << phyaddr);
++ 
++	mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
++	if (!mii_bus->irq) {
++		err = -ENOMEM;
++		goto err_free_bus;
++	}
++	for (i = 0; i < PHY_MAX_ADDR; i++)
++		mii_bus->irq[i] = PHY_POLL;
++
++	bcma_mdio->core = core;
++	bcma_mdio->phyaddr = phyaddr;
++
++	err = mdiobus_register(mii_bus);
++	if (err) {
++		dev_err(&core->dev, "Registration of mii bus failed\n");
++		goto err_free_irq;
++	}
++
++	return mii_bus;
++
++err_free_irq:
++	kfree(mii_bus->irq);
++err_free_bus:
++	mdiobus_free(mii_bus);
++err:
++	kfree(bcma_mdio);
++	return ERR_PTR(err);
++}
++
++void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
++{
++	struct bcma_mdio *bcma_mdio;
++
++	if (!mii_bus)
++		return;
++
++	bcma_mdio = mii_bus->priv;
++
++	mdiobus_unregister(mii_bus);
++	kfree(mii_bus->irq);
++	mdiobus_free(mii_bus);
++	kfree(bcma_mdio);
++}
++
++MODULE_AUTHOR("Rafał Miłecki");
++MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -759,150 +759,6 @@ error:
+ 	return err;
+ }
+ 
+-/**************************************************
+- * PHY ops
+- **************************************************/
+-
+-static u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
+-{
+-	struct bcma_device *core;
+-	u16 phy_access_addr;
+-	u16 phy_ctl_addr;
+-	u32 tmp;
+-
+-	BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
+-	BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
+-	BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
+-	BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
+-	BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
+-	BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
+-	BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
+-	BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
+-	BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
+-	BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
+-	BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
+-
+-	if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+-		core = bgmac->core->bus->drv_gmac_cmn.core;
+-		phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+-		phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+-	} else {
+-		core = bgmac->core;
+-		phy_access_addr = BGMAC_PHY_ACCESS;
+-		phy_ctl_addr = BGMAC_PHY_CNTL;
+-	}
+-
+-	tmp = bcma_read32(core, phy_ctl_addr);
+-	tmp &= ~BGMAC_PC_EPA_MASK;
+-	tmp |= phyaddr;
+-	bcma_write32(core, phy_ctl_addr, tmp);
+-
+-	tmp = BGMAC_PA_START;
+-	tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+-	tmp |= reg << BGMAC_PA_REG_SHIFT;
+-	bcma_write32(core, phy_access_addr, tmp);
+-
+-	if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+-		dev_err(bgmac->dev, "Reading PHY %d register 0x%X failed\n",
+-			phyaddr, reg);
+-		return 0xffff;
+-	}
+-
+-	return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
+-}
+-
+-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
+-static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
+-{
+-	struct bcma_device *core;
+-	u16 phy_access_addr;
+-	u16 phy_ctl_addr;
+-	u32 tmp;
+-
+-	if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+-		core = bgmac->core->bus->drv_gmac_cmn.core;
+-		phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+-		phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+-	} else {
+-		core = bgmac->core;
+-		phy_access_addr = BGMAC_PHY_ACCESS;
+-		phy_ctl_addr = BGMAC_PHY_CNTL;
+-	}
+-
+-	tmp = bcma_read32(core, phy_ctl_addr);
+-	tmp &= ~BGMAC_PC_EPA_MASK;
+-	tmp |= phyaddr;
+-	bcma_write32(core, phy_ctl_addr, tmp);
+-
+-	bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
+-	if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
+-		dev_warn(bgmac->dev, "Error setting MDIO int\n");
+-
+-	tmp = BGMAC_PA_START;
+-	tmp |= BGMAC_PA_WRITE;
+-	tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+-	tmp |= reg << BGMAC_PA_REG_SHIFT;
+-	tmp |= value;
+-	bcma_write32(core, phy_access_addr, tmp);
+-
+-	if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+-		dev_err(bgmac->dev, "Writing to PHY %d register 0x%X failed\n",
+-			phyaddr, reg);
+-		return -ETIMEDOUT;
+-	}
+-
+-	return 0;
+-}
+-
+-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
+-static void bgmac_phy_init(struct bgmac *bgmac)
+-{
+-	struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+-	struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+-	u8 i;
+-
+-	if (ci->id == BCMA_CHIP_ID_BCM5356) {
+-		for (i = 0; i < 5; i++) {
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x008b);
+-			bgmac_phy_write(bgmac, i, 0x15, 0x0100);
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+-			bgmac_phy_write(bgmac, i, 0x12, 0x2aaa);
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+-		}
+-	}
+-	if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
+-	    (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
+-	    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
+-		bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
+-		bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
+-		for (i = 0; i < 5; i++) {
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+-			bgmac_phy_write(bgmac, i, 0x16, 0x5284);
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+-			bgmac_phy_write(bgmac, i, 0x17, 0x0010);
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+-			bgmac_phy_write(bgmac, i, 0x16, 0x5296);
+-			bgmac_phy_write(bgmac, i, 0x17, 0x1073);
+-			bgmac_phy_write(bgmac, i, 0x17, 0x9073);
+-			bgmac_phy_write(bgmac, i, 0x16, 0x52b6);
+-			bgmac_phy_write(bgmac, i, 0x17, 0x9273);
+-			bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+-		}
+-	}
+-}
+-
+-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
+-static void bgmac_phy_reset(struct bgmac *bgmac)
+-{
+-	if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+-		return;
+-
+-	bgmac_phy_write(bgmac, bgmac->phyaddr, MII_BMCR, BMCR_RESET);
+-	udelay(100);
+-	if (bgmac_phy_read(bgmac, bgmac->phyaddr, MII_BMCR) & BMCR_RESET)
+-		dev_err(bgmac->dev, "PHY reset failed\n");
+-	bgmac_phy_init(bgmac);
+-}
+ 
+ /**************************************************
+  * Chip ops
+@@ -1159,7 +1015,8 @@ static void bgmac_chip_reset(struct bgma
+ 	else
+ 		bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE);
+ 	bgmac_miiconfig(bgmac);
+-	bgmac_phy_init(bgmac);
++	if (bgmac->mii_bus)
++		bgmac->mii_bus->reset(bgmac->mii_bus);
+ 
+ 	netdev_reset_queue(bgmac->net_dev);
+ }
+@@ -1553,17 +1410,6 @@ static const struct ethtool_ops bgmac_et
+  * MII
+  **************************************************/
+ 
+-static int bgmac_mii_read(struct mii_bus *bus, int mii_id, int regnum)
+-{
+-	return bgmac_phy_read(bus->priv, mii_id, regnum);
+-}
+-
+-static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum,
+-			   u16 value)
+-{
+-	return bgmac_phy_write(bus->priv, mii_id, regnum, value);
+-}
+-
+ static void bgmac_adjust_link(struct net_device *net_dev)
+ {
+ 	struct bgmac *bgmac = netdev_priv(net_dev);
+@@ -1588,7 +1434,7 @@ static void bgmac_adjust_link(struct net
+ 	}
+ }
+ 
+-static int bgmac_fixed_phy_register(struct bgmac *bgmac)
++static int bgmac_phy_connect_direct(struct bgmac *bgmac)
+ {
+ 	struct fixed_phy_status fphy_status = {
+ 		.link = 1,
+@@ -1614,81 +1460,24 @@ static int bgmac_fixed_phy_register(stru
+ 	return err;
+ }
+ 
+-static int bgmac_mii_register(struct bgmac *bgmac)
++static int bgmac_phy_connect(struct bgmac *bgmac)
+ {
+-	struct mii_bus *mii_bus;
+ 	struct phy_device *phy_dev;
+ 	char bus_id[MII_BUS_ID_SIZE + 3];
+-	int i, err = 0;
+-
+-	if (bgmac_is_bcm4707_family(bgmac))
+-		return bgmac_fixed_phy_register(bgmac);
+-
+-	mii_bus = mdiobus_alloc();
+-	if (!mii_bus)
+-		return -ENOMEM;
+-
+-	mii_bus->name = "bgmac mii bus";
+-	sprintf(mii_bus->id, "%s-%d-%d", "bgmac", bgmac->core->bus->num,
+-		bgmac->core->core_unit);
+-	mii_bus->priv = bgmac;
+-	mii_bus->read = bgmac_mii_read;
+-	mii_bus->write = bgmac_mii_write;
+-	mii_bus->parent = &bgmac->core->dev;
+-	mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
+-
+-	mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+-	if (!mii_bus->irq) {
+-		err = -ENOMEM;
+-		goto err_free_bus;
+-	}
+-	for (i = 0; i < PHY_MAX_ADDR; i++)
+-		mii_bus->irq[i] = PHY_POLL;
+-
+-	err = mdiobus_register(mii_bus);
+-	if (err) {
+-		dev_err(bgmac->dev, "Registration of mii bus failed\n");
+-		goto err_free_irq;
+-	}
+-
+-	bgmac->mii_bus = mii_bus;
+ 
+ 	/* Connect to the PHY */
+-	snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id,
++	snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id,
+ 		 bgmac->phyaddr);
+ 	phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
+ 			      PHY_INTERFACE_MODE_MII);
+ 	if (IS_ERR(phy_dev)) {
+ 		dev_err(bgmac->dev, "PHY connecton failed\n");
+-		err = PTR_ERR(phy_dev);
+-		goto err_unregister_bus;
++		return PTR_ERR(phy_dev);
+ 	}
+ 
+-	return err;
+-
+-err_unregister_bus:
+-	mdiobus_unregister(mii_bus);
+-err_free_irq:
+-	kfree(mii_bus->irq);
+-err_free_bus:
+-	mdiobus_free(mii_bus);
+-	return err;
+-}
+-
+-static void bgmac_mii_unregister(struct bgmac *bgmac)
+-{
+-	struct mii_bus *mii_bus = bgmac->mii_bus;
+-
+-	mdiobus_unregister(mii_bus);
+-	kfree(mii_bus->irq);
+-	mdiobus_free(mii_bus);
++	return 0;
+ }
+ 
+-/**************************************************
+- * BCMA bus ops
+- **************************************************/
+-
+-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+ static int bgmac_probe(struct bcma_device *core)
+ {
+ 	struct net_device *net_dev;
+@@ -1809,9 +1598,6 @@ static int bgmac_probe(struct bcma_devic
+ 	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+ 		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
+ 
+-	/* TODO: reset the external phy. Specs are needed */
+-	bgmac_phy_reset(bgmac);
+-
+ 	bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
+ 			       BGMAC_BFL_ENETROBO);
+ 	if (bgmac->has_robosw)
+@@ -1822,10 +1608,25 @@ static int bgmac_probe(struct bcma_devic
+ 
+ 	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+ 
+-	err = bgmac_mii_register(bgmac);
++	if (!bgmac_is_bcm4707_family(bgmac)) {
++		struct mii_bus *mii_bus;
++
++		mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
++		if (!IS_ERR(mii_bus)) {
++			err = PTR_ERR(mii_bus);
++			goto err_dma_free;
++		}
++
++		bgmac->mii_bus = mii_bus;
++	}
++
++	if (!bgmac->mii_bus)
++		err = bgmac_phy_connect_direct(bgmac);
++	else
++		err = bgmac_phy_connect(bgmac);
+ 	if (err) {
+ 		dev_err(bgmac->dev, "Cannot connect to phy\n");
+-		goto err_dma_free;
++		goto err_mii_unregister;
+ 	}
+ 
+ 	net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+@@ -1835,18 +1636,19 @@ static int bgmac_probe(struct bcma_devic
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+ 		dev_err(bgmac->dev, "Cannot register net device\n");
+-		goto err_mii_unregister;
++		goto err_phy_disconnect;
+ 	}
+ 
+ 	netif_carrier_off(net_dev);
+ 
+ 	return 0;
+ 
++err_phy_disconnect:
++	phy_disconnect(net_dev->phydev);
+ err_mii_unregister:
+-	bgmac_mii_unregister(bgmac);
++	bcma_mdio_mii_unregister(bgmac->mii_bus);
+ err_dma_free:
+ 	bgmac_dma_free(bgmac);
+-
+ err_netdev_free:
+ 	bcma_set_drvdata(core, NULL);
+ 	free_netdev(net_dev);
+@@ -1859,7 +1661,8 @@ static void bgmac_remove(struct bcma_dev
+ 	struct bgmac *bgmac = bcma_get_drvdata(core);
+ 
+ 	unregister_netdev(bgmac->net_dev);
+-	bgmac_mii_unregister(bgmac);
++	phy_disconnect(bgmac->net_dev->phydev);
++	bcma_mdio_mii_unregister(bgmac->mii_bus);
+ 	netif_napi_del(&bgmac->napi);
+ 	bgmac_dma_free(bgmac);
+ 	bcma_set_drvdata(core, NULL);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -456,6 +456,9 @@ struct bgmac {
+ 	bool loopback;
+ };
+ 
++struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
++void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
++
+ static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
+ {
+ 	return bcma_read32(bgmac->core, offset);
diff --git a/target/linux/generic/patches-4.4/075-0004-net-ethernet-bgmac-convert-to-feature-flags.patch b/target/linux/generic/patches-4.4/075-0004-net-ethernet-bgmac-convert-to-feature-flags.patch
new file mode 100644
index 0000000000..0f627919d0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/075-0004-net-ethernet-bgmac-convert-to-feature-flags.patch
@@ -0,0 +1,384 @@
+From db791eb2970bad193b1dc95a4461b222dd22cb64 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jon.mason@broadcom.com>
+Date: Thu, 7 Jul 2016 19:08:56 -0400
+Subject: [PATCH 4/5] net: ethernet: bgmac: convert to feature flags
+
+The bgmac driver is using the bcma provides device ID and revision, as
+well as the SoC ID and package, to determine which features are
+necessary to enable, reset, etc in the driver.   In anticipation of
+removing the bcma requirement for this driver, these must be changed to
+not reference that struct.  In place of that, each "feature" has been
+given a flag, and the flags are enabled for their respective device and
+SoC.
+
+Signed-off-by: Jon Mason <jon.mason@broadcom.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 167 ++++++++++++++++++++++++----------
+ drivers/net/ethernet/broadcom/bgmac.h |  21 ++++-
+ 2 files changed, 140 insertions(+), 48 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -109,7 +109,7 @@ static void bgmac_dma_tx_enable(struct b
+ 	u32 ctl;
+ 
+ 	ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL);
+-	if (bgmac->core->id.rev >= 4) {
++	if (bgmac->feature_flags & BGMAC_FEAT_TX_MASK_SETUP) {
+ 		ctl &= ~BGMAC_DMA_TX_BL_MASK;
+ 		ctl |= BGMAC_DMA_TX_BL_128 << BGMAC_DMA_TX_BL_SHIFT;
+ 
+@@ -335,7 +335,7 @@ static void bgmac_dma_rx_enable(struct b
+ 	/* preserve ONLY bits 16-17 from current hardware value */
+ 	ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
+ 
+-	if (bgmac->core->id.rev >= 4) {
++	if (bgmac->feature_flags & BGMAC_FEAT_RX_MASK_SETUP) {
+ 		ctl &= ~BGMAC_DMA_RX_BL_MASK;
+ 		ctl |= BGMAC_DMA_RX_BL_128 << BGMAC_DMA_RX_BL_SHIFT;
+ 
+@@ -772,14 +772,20 @@ static void bgmac_cmdcfg_maskset(struct
+ {
+ 	u32 cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+ 	u32 new_val = (cmdcfg & mask) | set;
++	u32 cmdcfg_sr;
+ 
+-	bgmac_set(bgmac, BGMAC_CMDCFG, BGMAC_CMDCFG_SR(bgmac->core->id.rev));
++	if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4)
++		cmdcfg_sr = BGMAC_CMDCFG_SR_REV4;
++	else
++		cmdcfg_sr = BGMAC_CMDCFG_SR_REV0;
++
++	bgmac_set(bgmac, BGMAC_CMDCFG, cmdcfg_sr);
+ 	udelay(2);
+ 
+ 	if (new_val != cmdcfg || force)
+ 		bgmac_write(bgmac, BGMAC_CMDCFG, new_val);
+ 
+-	bgmac_mask(bgmac, BGMAC_CMDCFG, ~BGMAC_CMDCFG_SR(bgmac->core->id.rev));
++	bgmac_mask(bgmac, BGMAC_CMDCFG, ~cmdcfg_sr);
+ 	udelay(2);
+ }
+ 
+@@ -808,7 +814,7 @@ static void bgmac_chip_stats_update(stru
+ {
+ 	int i;
+ 
+-	if (bgmac->core->id.id != BCMA_CORE_4706_MAC_GBIT) {
++	if (!(bgmac->feature_flags & BGMAC_FEAT_NO_CLR_MIB)) {
+ 		for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+ 			bgmac->mib_tx_regs[i] =
+ 				bgmac_read(bgmac,
+@@ -827,7 +833,7 @@ static void bgmac_clear_mib(struct bgmac
+ {
+ 	int i;
+ 
+-	if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT)
++	if (bgmac->feature_flags & BGMAC_FEAT_NO_CLR_MIB)
+ 		return;
+ 
+ 	bgmac_set(bgmac, BGMAC_DEV_CTL, BGMAC_DC_MROR);
+@@ -870,9 +876,8 @@ static void bgmac_mac_speed(struct bgmac
+ static void bgmac_miiconfig(struct bgmac *bgmac)
+ {
+ 	struct bcma_device *core = bgmac->core;
+-	u8 imode;
+ 
+-	if (bgmac_is_bcm4707_family(bgmac)) {
++	if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500) {
+ 		bcma_awrite32(core, BCMA_IOCTL,
+ 			      bcma_aread32(core, BCMA_IOCTL) | 0x40 |
+ 			      BGMAC_BCMA_IOCTL_SW_CLKEN);
+@@ -880,6 +885,8 @@ static void bgmac_miiconfig(struct bgmac
+ 		bgmac->mac_duplex = DUPLEX_FULL;
+ 		bgmac_mac_speed(bgmac);
+ 	} else {
++		u8 imode;
++
+ 		imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) &
+ 			BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT;
+ 		if (imode == 0 || imode == 1) {
+@@ -894,9 +901,7 @@ static void bgmac_miiconfig(struct bgmac
+ static void bgmac_chip_reset(struct bgmac *bgmac)
+ {
+ 	struct bcma_device *core = bgmac->core;
+-	struct bcma_bus *bus = core->bus;
+-	struct bcma_chipinfo *ci = &bus->chipinfo;
+-	u32 flags;
++	u32 cmdcfg_sr;
+ 	u32 iost;
+ 	int i;
+ 
+@@ -919,15 +924,12 @@ static void bgmac_chip_reset(struct bgma
+ 	}
+ 
+ 	iost = bcma_aread32(core, BCMA_IOST);
+-	if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) ||
+-	    (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
+-	    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188))
++	if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED)
+ 		iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+ 
+ 	/* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
+-	if (ci->id != BCMA_CHIP_ID_BCM4707 &&
+-	    ci->id != BCMA_CHIP_ID_BCM47094) {
+-		flags = 0;
++	if (!(bgmac->feature_flags & BGMAC_FEAT_NO_RESET)) {
++		u32 flags = 0;
+ 		if (iost & BGMAC_BCMA_IOST_ATTACHED) {
+ 			flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
+ 			if (!bgmac->has_robosw)
+@@ -937,7 +939,7 @@ static void bgmac_chip_reset(struct bgma
+ 	}
+ 
+ 	/* Request Misc PLL for corerev > 2 */
+-	if (core->id.rev > 2 && !bgmac_is_bcm4707_family(bgmac)) {
++	if (bgmac->feature_flags & BGMAC_FEAT_MISC_PLL_REQ) {
+ 		bgmac_set(bgmac, BCMA_CLKCTLST,
+ 			  BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ);
+ 		bgmac_wait_value(bgmac->core, BCMA_CLKCTLST,
+@@ -946,9 +948,7 @@ static void bgmac_chip_reset(struct bgma
+ 				 1000);
+ 	}
+ 
+-	if (ci->id == BCMA_CHIP_ID_BCM5357 ||
+-	    ci->id == BCMA_CHIP_ID_BCM4749 ||
+-	    ci->id == BCMA_CHIP_ID_BCM53572) {
++	if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_PHY) {
+ 		struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+ 		u8 et_swtype = 0;
+ 		u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
+@@ -962,11 +962,9 @@ static void bgmac_chip_reset(struct bgma
+ 			et_swtype &= 0x0f;
+ 			et_swtype <<= 4;
+ 			sw_type = et_swtype;
+-		} else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358) {
++		} else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_EPHYRMII) {
+ 			sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
+-		} else if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) ||
+-			   (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
+-			   (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) {
++		} else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_RGMII) {
+ 			sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
+ 				  BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
+ 		}
+@@ -986,6 +984,11 @@ static void bgmac_chip_reset(struct bgma
+ 	 * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to
+ 	 * be keps until taking MAC out of the reset.
+ 	 */
++	if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4)
++		cmdcfg_sr = BGMAC_CMDCFG_SR_REV4;
++	else
++		cmdcfg_sr = BGMAC_CMDCFG_SR_REV0;
++
+ 	bgmac_cmdcfg_maskset(bgmac,
+ 			     ~(BGMAC_CMDCFG_TE |
+ 			       BGMAC_CMDCFG_RE |
+@@ -1003,13 +1006,13 @@ static void bgmac_chip_reset(struct bgma
+ 			     BGMAC_CMDCFG_PROM |
+ 			     BGMAC_CMDCFG_NLC |
+ 			     BGMAC_CMDCFG_CFE |
+-			     BGMAC_CMDCFG_SR(core->id.rev),
++			     cmdcfg_sr,
+ 			     false);
+ 	bgmac->mac_speed = SPEED_UNKNOWN;
+ 	bgmac->mac_duplex = DUPLEX_UNKNOWN;
+ 
+ 	bgmac_clear_mib(bgmac);
+-	if (core->id.id == BCMA_CORE_4706_MAC_GBIT)
++	if (bgmac->feature_flags & BGMAC_FEAT_CMN_PHY_CTL)
+ 		bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0,
+ 			       BCMA_GMAC_CMN_PC_MTE);
+ 	else
+@@ -1035,46 +1038,48 @@ static void bgmac_chip_intrs_off(struct
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */
+ static void bgmac_enable(struct bgmac *bgmac)
+ {
+-	struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
++	u32 cmdcfg_sr;
+ 	u32 cmdcfg;
+ 	u32 mode;
+-	u32 rxq_ctl;
+-	u32 fl_ctl;
+-	u16 bp_clk;
+-	u8 mdp;
++
++	if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4)
++		cmdcfg_sr = BGMAC_CMDCFG_SR_REV4;
++	else
++		cmdcfg_sr = BGMAC_CMDCFG_SR_REV0;
+ 
+ 	cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+ 	bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE),
+-			     BGMAC_CMDCFG_SR(bgmac->core->id.rev), true);
++			     cmdcfg_sr, true);
+ 	udelay(2);
+ 	cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE;
+ 	bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg);
+ 
+ 	mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+ 		BGMAC_DS_MM_SHIFT;
+-	if (ci->id != BCMA_CHIP_ID_BCM47162 || mode != 0)
++	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
+ 		bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+-	if (ci->id == BCMA_CHIP_ID_BCM47162 && mode == 2)
++	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
+ 		bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0,
+ 					    BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
+ 
+-	switch (ci->id) {
+-	case BCMA_CHIP_ID_BCM5357:
+-	case BCMA_CHIP_ID_BCM4749:
+-	case BCMA_CHIP_ID_BCM53572:
+-	case BCMA_CHIP_ID_BCM4716:
+-	case BCMA_CHIP_ID_BCM47162:
+-		fl_ctl = 0x03cb04cb;
+-		if (ci->id == BCMA_CHIP_ID_BCM5357 ||
+-		    ci->id == BCMA_CHIP_ID_BCM4749 ||
+-		    ci->id == BCMA_CHIP_ID_BCM53572)
++	if (bgmac->feature_flags & (BGMAC_FEAT_FLW_CTRL1 |
++				    BGMAC_FEAT_FLW_CTRL2)) {
++		u32 fl_ctl;
++
++		if (bgmac->feature_flags & BGMAC_FEAT_FLW_CTRL1)
+ 			fl_ctl = 0x2300e1;
++		else
++			fl_ctl = 0x03cb04cb;
++
+ 		bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl);
+ 		bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff);
+-		break;
+ 	}
+ 
+-	if (!bgmac_is_bcm4707_family(bgmac)) {
++	if (bgmac->feature_flags & BGMAC_FEAT_SET_RXQ_CLK) {
++		u32 rxq_ctl;
++		u16 bp_clk;
++		u8 mdp;
++
+ 		rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
+ 		rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
+ 		bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) /
+@@ -1606,6 +1611,74 @@ static int bgmac_probe(struct bcma_devic
+ 	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+ 		dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
+ 
++	/* Feature Flags */
++	switch (core->bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM5357:
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
++		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
++		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47186) {
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
++		}
++		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM5358)
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
++		break;
++	case BCMA_CHIP_ID_BCM53572:
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
++		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
++		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47188) {
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++		}
++		break;
++	case BCMA_CHIP_ID_BCM4749:
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
++		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
++		if (core->bus->chipinfo.pkg == 10) {
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++		}
++		break;
++	case BCMA_CHIP_ID_BCM4716:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		/* fallthrough */
++	case BCMA_CHIP_ID_BCM47162:
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		break;
++	/* bcm4707_family */
++	case BCMA_CHIP_ID_BCM4707:
++	case BCMA_CHIP_ID_BCM47094:
++	case BCMA_CHIP_ID_BCM53018:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
++		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
++		break;
++	default:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++	}
++
++	if (!bgmac_is_bcm4707_family(bgmac) && core->id.rev > 2)
++		bgmac->feature_flags |= BGMAC_FEAT_MISC_PLL_REQ;
++
++	if (core->id.id == BCMA_CORE_4706_MAC_GBIT) {
++		bgmac->feature_flags |= BGMAC_FEAT_CMN_PHY_CTL;
++		bgmac->feature_flags |= BGMAC_FEAT_NO_CLR_MIB;
++	}
++
++	if (core->id.rev >= 4) {
++		bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
++		bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
++		bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
++	}
++
+ 	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+ 
+ 	if (!bgmac_is_bcm4707_family(bgmac)) {
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -190,7 +190,6 @@
+ #define  BGMAC_CMDCFG_HD_SHIFT			10
+ #define  BGMAC_CMDCFG_SR_REV0			0x00000800	/* Set to reset mode, for core rev 0-3 */
+ #define  BGMAC_CMDCFG_SR_REV4			0x00002000	/* Set to reset mode, for core rev >= 4 */
+-#define  BGMAC_CMDCFG_SR(rev)  ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
+ #define  BGMAC_CMDCFG_ML			0x00008000	/* Set to activate mac loopback mode */
+ #define  BGMAC_CMDCFG_AE			0x00400000
+ #define  BGMAC_CMDCFG_CFE			0x00800000
+@@ -376,6 +375,24 @@
+ 
+ #define ETHER_MAX_LEN   1518
+ 
++/* Feature Flags */
++#define BGMAC_FEAT_TX_MASK_SETUP	BIT(0)
++#define BGMAC_FEAT_RX_MASK_SETUP	BIT(1)
++#define BGMAC_FEAT_IOST_ATTACHED	BIT(2)
++#define BGMAC_FEAT_NO_RESET		BIT(3)
++#define BGMAC_FEAT_MISC_PLL_REQ		BIT(4)
++#define BGMAC_FEAT_SW_TYPE_PHY		BIT(5)
++#define BGMAC_FEAT_SW_TYPE_EPHYRMII	BIT(6)
++#define BGMAC_FEAT_SW_TYPE_RGMII	BIT(7)
++#define BGMAC_FEAT_CMN_PHY_CTL		BIT(8)
++#define BGMAC_FEAT_FLW_CTRL1		BIT(9)
++#define BGMAC_FEAT_FLW_CTRL2		BIT(10)
++#define BGMAC_FEAT_SET_RXQ_CLK		BIT(11)
++#define BGMAC_FEAT_CLKCTLST		BIT(12)
++#define BGMAC_FEAT_NO_CLR_MIB		BIT(13)
++#define BGMAC_FEAT_FORCE_SPEED_2500	BIT(14)
++#define BGMAC_FEAT_CMDCFG_SR_REV4	BIT(15)
++
+ struct bgmac_slot_info {
+ 	union {
+ 		struct sk_buff *skb;
+@@ -430,6 +447,8 @@ struct bgmac {
+ 
+ 	struct device *dev;
+ 	struct device *dma_dev;
++	u32 feature_flags;
++
+ 	struct net_device *net_dev;
+ 	struct napi_struct napi;
+ 	struct mii_bus *mii_bus;
diff --git a/target/linux/generic/patches-4.4/075-0005-net-ethernet-bgmac-Add-platform-device-support.patch b/target/linux/generic/patches-4.4/075-0005-net-ethernet-bgmac-Add-platform-device-support.patch
new file mode 100644
index 0000000000..5755184949
--- /dev/null
+++ b/target/linux/generic/patches-4.4/075-0005-net-ethernet-bgmac-Add-platform-device-support.patch
@@ -0,0 +1,1260 @@
+From f6a95a24957aec5bb488c3f978c4ed508177998f Mon Sep 17 00:00:00 2001
+From: Jon Mason <jon.mason@broadcom.com>
+Date: Thu, 7 Jul 2016 19:08:57 -0400
+Subject: [PATCH 5/5] net: ethernet: bgmac: Add platform device support
+
+The bcma portion of the driver has been split off into a bcma specific
+driver.  This has been mirrored for the platform driver.  The last
+references to the bcma core struct have been changed into a generic
+function call.  These function calls are wrappers to either the original
+bcma code or new platform functions that access the same areas via MMIO.
+This necessitated adding function pointers for both platform and bcma to
+hide which backend is being used from the generic bgmac code.
+
+Signed-off-by: Jon Mason <jon.mason@broadcom.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/Kconfig           |  23 +-
+ drivers/net/ethernet/broadcom/Makefile          |   4 +-
+ drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c |   2 +
+ drivers/net/ethernet/broadcom/bgmac-bcma.c      | 315 +++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/bgmac-platform.c  | 189 ++++++++++++++
+ drivers/net/ethernet/broadcom/bgmac.c           | 329 ++++--------------------
+ drivers/net/ethernet/broadcom/bgmac.h           |  73 +++++-
+ 7 files changed, 650 insertions(+), 285 deletions(-)
+ create mode 100644 drivers/net/ethernet/broadcom/bgmac-bcma.c
+ create mode 100644 drivers/net/ethernet/broadcom/bgmac-platform.c
+
+--- a/drivers/net/ethernet/broadcom/Kconfig
++++ b/drivers/net/ethernet/broadcom/Kconfig
+@@ -150,10 +150,18 @@ config BNX2X_VXLAN
+ 	  Virtual eXtensible Local Area Network (VXLAN) in the driver.
+ 
+ config BGMAC
+-	tristate "BCMA bus GBit core support"
++	tristate
++	help
++	  This enables the integrated ethernet controller support for many
++	  Broadcom (mostly iProc) SoCs. An appropriate bus interface driver
++	  needs to be enabled to select this.
++
++config BGMAC_BCMA
++	tristate "Broadcom iProc GBit BCMA support"
+ 	depends on BCMA && BCMA_HOST_SOC
+ 	depends on HAS_DMA
+ 	depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST
++	select BGMAC
+ 	select PHYLIB
+ 	select FIXED_PHY
+ 	---help---
+@@ -162,6 +170,19 @@ config BGMAC
+ 	  In case of using this driver on BCM4706 it's also requires to enable
+ 	  BCMA_DRIVER_GMAC_CMN to make it work.
+ 
++config BGMAC_PLATFORM
++	tristate "Broadcom iProc GBit platform support"
++	depends on HAS_DMA
++	depends on ARCH_BCM_IPROC || COMPILE_TEST
++	depends on OF
++	select BGMAC
++	select PHYLIB
++	select FIXED_PHY
++	default ARCH_BCM_IPROC
++	---help---
++	  Say Y here if you want to use the Broadcom iProc Gigabit Ethernet
++	  controller through the generic platform interface
++
+ config SYSTEMPORT
+ 	tristate "Broadcom SYSTEMPORT internal MAC support"
+ 	depends on OF
+--- a/drivers/net/ethernet/broadcom/Makefile
++++ b/drivers/net/ethernet/broadcom/Makefile
+@@ -10,6 +10,8 @@ obj-$(CONFIG_CNIC) += cnic.o
+ obj-$(CONFIG_BNX2X) += bnx2x/
+ obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
+ obj-$(CONFIG_TIGON3) += tg3.o
+-obj-$(CONFIG_BGMAC) += bgmac.o bgmac-bcma-mdio.o
++obj-$(CONFIG_BGMAC) += bgmac.o
++obj-$(CONFIG_BGMAC_BCMA) += bgmac-bcma.o bgmac-bcma-mdio.o
++obj-$(CONFIG_BGMAC_PLATFORM) += bgmac-platform.o
+ obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
+ obj-$(CONFIG_BNXT) += bnxt/
+--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
+@@ -255,6 +255,7 @@ err:
+ 	kfree(bcma_mdio);
+ 	return ERR_PTR(err);
+ }
++EXPORT_SYMBOL_GPL(bcma_mdio_mii_register);
+ 
+ void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
+ {
+@@ -270,6 +271,7 @@ void bcma_mdio_mii_unregister(struct mii
+ 	mdiobus_free(mii_bus);
+ 	kfree(bcma_mdio);
+ }
++EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister);
+ 
+ MODULE_AUTHOR("Rafał Miłecki");
+ MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
+@@ -0,0 +1,315 @@
++/*
++ * Driver for (BCM4706)? GBit MAC core on BCMA bus.
++ *
++ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
++
++#include <linux/bcma/bcma.h>
++#include <linux/brcmphy.h>
++#include <linux/etherdevice.h>
++#include "bgmac.h"
++
++static inline bool bgmac_is_bcm4707_family(struct bcma_device *core)
++{
++	switch (core->bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM4707:
++	case BCMA_CHIP_ID_BCM47094:
++	case BCMA_CHIP_ID_BCM53018:
++		return true;
++	default:
++		return false;
++	}
++}
++
++/**************************************************
++ * BCMA bus ops
++ **************************************************/
++
++static u32 bcma_bgmac_read(struct bgmac *bgmac, u16 offset)
++{
++	return bcma_read32(bgmac->bcma.core, offset);
++}
++
++static void bcma_bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
++{
++	bcma_write32(bgmac->bcma.core, offset, value);
++}
++
++static u32 bcma_bgmac_idm_read(struct bgmac *bgmac, u16 offset)
++{
++	return bcma_aread32(bgmac->bcma.core, offset);
++}
++
++static void bcma_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
++{
++	return bcma_awrite32(bgmac->bcma.core, offset, value);
++}
++
++static bool bcma_bgmac_clk_enabled(struct bgmac *bgmac)
++{
++	return bcma_core_is_enabled(bgmac->bcma.core);
++}
++
++static void bcma_bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
++{
++	bcma_core_enable(bgmac->bcma.core, flags);
++}
++
++static void bcma_bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset,
++				       u32 mask, u32 set)
++{
++	struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
++
++	bcma_chipco_chipctl_maskset(cc, offset, mask, set);
++}
++
++static u32 bcma_bgmac_get_bus_clock(struct bgmac *bgmac)
++{
++	struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
++
++	return bcma_pmu_get_bus_clock(cc);
++}
++
++static void bcma_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset, u32 mask,
++				     u32 set)
++{
++	bcma_maskset32(bgmac->bcma.cmn, offset, mask, set);
++}
++
++static const struct bcma_device_id bgmac_bcma_tbl[] = {
++	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT,
++		  BCMA_ANY_REV, BCMA_ANY_CLASS),
++	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV,
++		  BCMA_ANY_CLASS),
++	{},
++};
++MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
++
++/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
++static int bgmac_probe(struct bcma_device *core)
++{
++	struct ssb_sprom *sprom = &core->bus->sprom;
++	struct mii_bus *mii_bus;
++	struct bgmac *bgmac;
++	u8 *mac;
++	int err;
++
++	bgmac = kzalloc(sizeof(*bgmac), GFP_KERNEL);
++	if (!bgmac)
++		return -ENOMEM;
++
++	bgmac->bcma.core = core;
++	bgmac->dev = &core->dev;
++	bgmac->dma_dev = core->dma_dev;
++	bgmac->irq = core->irq;
++
++	bcma_set_drvdata(core, bgmac);
++
++	switch (core->core_unit) {
++	case 0:
++		mac = sprom->et0mac;
++		break;
++	case 1:
++		mac = sprom->et1mac;
++		break;
++	case 2:
++		mac = sprom->et2mac;
++		break;
++	default:
++		dev_err(bgmac->dev, "Unsupported core_unit %d\n",
++			core->core_unit);
++		err = -ENOTSUPP;
++		goto err;
++	}
++
++	ether_addr_copy(bgmac->mac_addr, mac);
++
++	/* On BCM4706 we need common core to access PHY */
++	if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
++	    !core->bus->drv_gmac_cmn.core) {
++		dev_err(bgmac->dev, "GMAC CMN core not found (required for BCM4706)\n");
++		err = -ENODEV;
++		goto err;
++	}
++	bgmac->bcma.cmn = core->bus->drv_gmac_cmn.core;
++
++	switch (core->core_unit) {
++	case 0:
++		bgmac->phyaddr = sprom->et0phyaddr;
++		break;
++	case 1:
++		bgmac->phyaddr = sprom->et1phyaddr;
++		break;
++	case 2:
++		bgmac->phyaddr = sprom->et2phyaddr;
++		break;
++	}
++	bgmac->phyaddr &= BGMAC_PHY_MASK;
++	if (bgmac->phyaddr == BGMAC_PHY_MASK) {
++		dev_err(bgmac->dev, "No PHY found\n");
++		err = -ENODEV;
++		goto err;
++	}
++	dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
++		 bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
++
++	if (!bgmac_is_bcm4707_family(core)) {
++		mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
++		if (!IS_ERR(mii_bus)) {
++			err = PTR_ERR(mii_bus);
++			goto err;
++		}
++
++		bgmac->mii_bus = mii_bus;
++	}
++
++	if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
++		dev_err(bgmac->dev, "PCI setup not implemented\n");
++		err = -ENOTSUPP;
++		goto err1;
++	}
++
++	bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
++			       BGMAC_BFL_ENETROBO);
++	if (bgmac->has_robosw)
++		dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n");
++
++	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
++		dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
++
++	/* Feature Flags */
++	switch (core->bus->chipinfo.id) {
++	case BCMA_CHIP_ID_BCM5357:
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
++		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
++		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47186) {
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
++		}
++		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM5358)
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
++		break;
++	case BCMA_CHIP_ID_BCM53572:
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
++		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
++		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47188) {
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++		}
++		break;
++	case BCMA_CHIP_ID_BCM4749:
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
++		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
++		if (core->bus->chipinfo.pkg == 10) {
++			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++		}
++		break;
++	case BCMA_CHIP_ID_BCM4716:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		/* fallthrough */
++	case BCMA_CHIP_ID_BCM47162:
++		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		break;
++	/* bcm4707_family */
++	case BCMA_CHIP_ID_BCM4707:
++	case BCMA_CHIP_ID_BCM47094:
++	case BCMA_CHIP_ID_BCM53018:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
++		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
++		break;
++	default:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++	}
++
++	if (!bgmac_is_bcm4707_family(core) && core->id.rev > 2)
++		bgmac->feature_flags |= BGMAC_FEAT_MISC_PLL_REQ;
++
++	if (core->id.id == BCMA_CORE_4706_MAC_GBIT) {
++		bgmac->feature_flags |= BGMAC_FEAT_CMN_PHY_CTL;
++		bgmac->feature_flags |= BGMAC_FEAT_NO_CLR_MIB;
++	}
++
++	if (core->id.rev >= 4) {
++		bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
++		bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
++		bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
++	}
++
++	bgmac->read = bcma_bgmac_read;
++	bgmac->write = bcma_bgmac_write;
++	bgmac->idm_read = bcma_bgmac_idm_read;
++	bgmac->idm_write = bcma_bgmac_idm_write;
++	bgmac->clk_enabled = bcma_bgmac_clk_enabled;
++	bgmac->clk_enable = bcma_bgmac_clk_enable;
++	bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset;
++	bgmac->get_bus_clock = bcma_bgmac_get_bus_clock;
++	bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32;
++
++	err = bgmac_enet_probe(bgmac);
++	if (err)
++		goto err1;
++
++	return 0;
++
++err1:
++	bcma_mdio_mii_unregister(bgmac->mii_bus);
++err:
++	kfree(bgmac);
++	bcma_set_drvdata(core, NULL);
++
++	return err;
++}
++
++static void bgmac_remove(struct bcma_device *core)
++{
++	struct bgmac *bgmac = bcma_get_drvdata(core);
++
++	bcma_mdio_mii_unregister(bgmac->mii_bus);
++	bgmac_enet_remove(bgmac);
++	bcma_set_drvdata(core, NULL);
++	kfree(bgmac);
++}
++
++static struct bcma_driver bgmac_bcma_driver = {
++	.name		= KBUILD_MODNAME,
++	.id_table	= bgmac_bcma_tbl,
++	.probe		= bgmac_probe,
++	.remove		= bgmac_remove,
++};
++
++static int __init bgmac_init(void)
++{
++	int err;
++
++	err = bcma_driver_register(&bgmac_bcma_driver);
++	if (err)
++		return err;
++	pr_info("Broadcom 47xx GBit MAC driver loaded\n");
++
++	return 0;
++}
++
++static void __exit bgmac_exit(void)
++{
++	bcma_driver_unregister(&bgmac_bcma_driver);
++}
++
++module_init(bgmac_init)
++module_exit(bgmac_exit)
++
++MODULE_AUTHOR("Rafał Miłecki");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
+@@ -0,0 +1,189 @@
++/*
++ * Copyright (C) 2016 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
++
++#include <linux/bcma/bcma.h>
++#include <linux/etherdevice.h>
++#include <linux/of_address.h>
++#include <linux/of_net.h>
++#include "bgmac.h"
++
++static u32 platform_bgmac_read(struct bgmac *bgmac, u16 offset)
++{
++	return readl(bgmac->plat.base + offset);
++}
++
++static void platform_bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
++{
++	writel(value, bgmac->plat.base + offset);
++}
++
++static u32 platform_bgmac_idm_read(struct bgmac *bgmac, u16 offset)
++{
++	return readl(bgmac->plat.idm_base + offset);
++}
++
++static void platform_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
++{
++	return writel(value, bgmac->plat.idm_base + offset);
++}
++
++static bool platform_bgmac_clk_enabled(struct bgmac *bgmac)
++{
++	if ((bgmac_idm_read(bgmac, BCMA_IOCTL) &
++	     (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) != BCMA_IOCTL_CLK)
++		return false;
++	if (bgmac_idm_read(bgmac, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
++		return false;
++	return true;
++}
++
++static void platform_bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
++{
++	bgmac_idm_write(bgmac, BCMA_IOCTL,
++			(BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags));
++	bgmac_idm_read(bgmac, BCMA_IOCTL);
++
++	bgmac_idm_write(bgmac, BCMA_RESET_CTL, 0);
++	bgmac_idm_read(bgmac, BCMA_RESET_CTL);
++	udelay(1);
++
++	bgmac_idm_write(bgmac, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
++	bgmac_idm_read(bgmac, BCMA_IOCTL);
++	udelay(1);
++}
++
++static void platform_bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset,
++					   u32 mask, u32 set)
++{
++	/* This shouldn't be encountered */
++	WARN_ON(1);
++}
++
++static u32 platform_bgmac_get_bus_clock(struct bgmac *bgmac)
++{
++	/* This shouldn't be encountered */
++	WARN_ON(1);
++
++	return 0;
++}
++
++static void platform_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset,
++					 u32 mask, u32 set)
++{
++	/* This shouldn't be encountered */
++	WARN_ON(1);
++}
++
++static int bgmac_probe(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct bgmac *bgmac;
++	struct resource *regs;
++	const u8 *mac_addr;
++
++	bgmac = devm_kzalloc(&pdev->dev, sizeof(*bgmac), GFP_KERNEL);
++	if (!bgmac)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, bgmac);
++
++	/* Set the features of the 4707 family */
++	bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++	bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
++	bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
++	bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
++	bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
++	bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
++
++	bgmac->dev = &pdev->dev;
++	bgmac->dma_dev = &pdev->dev;
++
++	mac_addr = of_get_mac_address(np);
++	if (mac_addr)
++		ether_addr_copy(bgmac->mac_addr, mac_addr);
++	else
++		dev_warn(&pdev->dev, "MAC address not present in device tree\n");
++
++	bgmac->irq = platform_get_irq(pdev, 0);
++	if (bgmac->irq < 0) {
++		dev_err(&pdev->dev, "Unable to obtain IRQ\n");
++		return bgmac->irq;
++	}
++
++	regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "amac_base");
++	if (!regs) {
++		dev_err(&pdev->dev, "Unable to obtain base resource\n");
++		return -EINVAL;
++	}
++
++	bgmac->plat.base = devm_ioremap_resource(&pdev->dev, regs);
++	if (IS_ERR(bgmac->plat.base)) {
++		dev_err(&pdev->dev, "Unable to map base resource\n");
++		return PTR_ERR(bgmac->plat.base);
++	}
++
++	regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
++	if (!regs) {
++		dev_err(&pdev->dev, "Unable to obtain idm resource\n");
++		return -EINVAL;
++	}
++
++	bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
++	if (!bgmac->plat.idm_base) {
++		dev_err(&pdev->dev, "Unable to map idm resource\n");
++		return PTR_ERR(bgmac->plat.idm_base);
++	}
++
++	bgmac->read = platform_bgmac_read;
++	bgmac->write = platform_bgmac_write;
++	bgmac->idm_read = platform_bgmac_idm_read;
++	bgmac->idm_write = platform_bgmac_idm_write;
++	bgmac->clk_enabled = platform_bgmac_clk_enabled;
++	bgmac->clk_enable = platform_bgmac_clk_enable;
++	bgmac->cco_ctl_maskset = platform_bgmac_cco_ctl_maskset;
++	bgmac->get_bus_clock = platform_bgmac_get_bus_clock;
++	bgmac->cmn_maskset32 = platform_bgmac_cmn_maskset32;
++
++	return bgmac_enet_probe(bgmac);
++}
++
++static int bgmac_remove(struct platform_device *pdev)
++{
++	struct bgmac *bgmac = platform_get_drvdata(pdev);
++
++	bgmac_enet_remove(bgmac);
++
++	return 0;
++}
++
++static const struct of_device_id bgmac_of_enet_match[] = {
++	{.compatible = "brcm,amac",},
++	{.compatible = "brcm,nsp-amac",},
++	{},
++};
++
++MODULE_DEVICE_TABLE(of, bgmac_of_enet_match);
++
++static struct platform_driver bgmac_enet_driver = {
++	.driver = {
++		.name  = "bgmac-enet",
++		.of_match_table = bgmac_of_enet_match,
++	},
++	.probe = bgmac_probe,
++	.remove = bgmac_remove,
++};
++
++module_platform_driver(bgmac_enet_driver);
++MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -6,51 +6,27 @@
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ 
+-#include "bgmac.h"
+ 
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/delay.h>
++#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
++
++#include <linux/bcma/bcma.h>
+ #include <linux/etherdevice.h>
+-#include <linux/mii.h>
+-#include <linux/phy.h>
+-#include <linux/phy_fixed.h>
+-#include <linux/interrupt.h>
+-#include <linux/dma-mapping.h>
+ #include <linux/bcm47xx_nvram.h>
++#include "bgmac.h"
+ 
+-static const struct bcma_device_id bgmac_bcma_tbl[] = {
+-	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+-	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+-	{},
+-};
+-MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
+-
+-static inline bool bgmac_is_bcm4707_family(struct bgmac *bgmac)
+-{
+-	switch (bgmac->core->bus->chipinfo.id) {
+-	case BCMA_CHIP_ID_BCM4707:
+-	case BCMA_CHIP_ID_BCM47094:
+-	case BCMA_CHIP_ID_BCM53018:
+-		return true;
+-	default:
+-		return false;
+-	}
+-}
+-
+-static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
++static bool bgmac_wait_value(struct bgmac *bgmac, u16 reg, u32 mask,
+ 			     u32 value, int timeout)
+ {
+ 	u32 val;
+ 	int i;
+ 
+ 	for (i = 0; i < timeout / 10; i++) {
+-		val = bcma_read32(core, reg);
++		val = bgmac_read(bgmac, reg);
+ 		if ((val & mask) == value)
+ 			return true;
+ 		udelay(10);
+ 	}
+-	dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
++	dev_err(bgmac->dev, "Timeout waiting for reg 0x%X\n", reg);
+ 	return false;
+ }
+ 
+@@ -89,7 +65,7 @@ static void bgmac_dma_tx_reset(struct bg
+ 
+ 	/* Remove SUSPEND bit */
+ 	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
+-	if (!bgmac_wait_value(bgmac->core,
++	if (!bgmac_wait_value(bgmac,
+ 			      ring->mmio_base + BGMAC_DMA_TX_STATUS,
+ 			      BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
+ 			      10000)) {
+@@ -317,7 +293,7 @@ static void bgmac_dma_rx_reset(struct bg
+ 		return;
+ 
+ 	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, 0);
+-	if (!bgmac_wait_value(bgmac->core,
++	if (!bgmac_wait_value(bgmac,
+ 			      ring->mmio_base + BGMAC_DMA_RX_STATUS,
+ 			      BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
+ 			      10000))
+@@ -643,7 +619,7 @@ static int bgmac_dma_alloc(struct bgmac
+ 	BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
+ 	BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
+ 
+-	if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
++	if (!(bgmac_idm_read(bgmac, BCMA_IOST) & BCMA_IOST_DMA64)) {
+ 		dev_err(bgmac->dev, "Core does not report 64-bit DMA\n");
+ 		return -ENOTSUPP;
+ 	}
+@@ -875,12 +851,10 @@ static void bgmac_mac_speed(struct bgmac
+ 
+ static void bgmac_miiconfig(struct bgmac *bgmac)
+ {
+-	struct bcma_device *core = bgmac->core;
+-
+ 	if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500) {
+-		bcma_awrite32(core, BCMA_IOCTL,
+-			      bcma_aread32(core, BCMA_IOCTL) | 0x40 |
+-			      BGMAC_BCMA_IOCTL_SW_CLKEN);
++		bgmac_idm_write(bgmac, BCMA_IOCTL,
++				bgmac_idm_read(bgmac, BCMA_IOCTL) | 0x40 |
++				BGMAC_BCMA_IOCTL_SW_CLKEN);
+ 		bgmac->mac_speed = SPEED_2500;
+ 		bgmac->mac_duplex = DUPLEX_FULL;
+ 		bgmac_mac_speed(bgmac);
+@@ -900,12 +874,11 @@ static void bgmac_miiconfig(struct bgmac
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */
+ static void bgmac_chip_reset(struct bgmac *bgmac)
+ {
+-	struct bcma_device *core = bgmac->core;
+ 	u32 cmdcfg_sr;
+ 	u32 iost;
+ 	int i;
+ 
+-	if (bcma_core_is_enabled(core)) {
++	if (bgmac_clk_enabled(bgmac)) {
+ 		if (!bgmac->stats_grabbed) {
+ 			/* bgmac_chip_stats_update(bgmac); */
+ 			bgmac->stats_grabbed = true;
+@@ -923,7 +896,7 @@ static void bgmac_chip_reset(struct bgma
+ 		/* TODO: Clear software multicast filter list */
+ 	}
+ 
+-	iost = bcma_aread32(core, BCMA_IOST);
++	iost = bgmac_idm_read(bgmac, BCMA_IOST);
+ 	if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED)
+ 		iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+ 
+@@ -935,21 +908,20 @@ static void bgmac_chip_reset(struct bgma
+ 			if (!bgmac->has_robosw)
+ 				flags |= BGMAC_BCMA_IOCTL_SW_RESET;
+ 		}
+-		bcma_core_enable(core, flags);
++		bgmac_clk_enable(bgmac, flags);
+ 	}
+ 
+ 	/* Request Misc PLL for corerev > 2 */
+ 	if (bgmac->feature_flags & BGMAC_FEAT_MISC_PLL_REQ) {
+ 		bgmac_set(bgmac, BCMA_CLKCTLST,
+ 			  BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ);
+-		bgmac_wait_value(bgmac->core, BCMA_CLKCTLST,
++		bgmac_wait_value(bgmac, BCMA_CLKCTLST,
+ 				 BGMAC_BCMA_CLKCTLST_MISC_PLL_ST,
+ 				 BGMAC_BCMA_CLKCTLST_MISC_PLL_ST,
+ 				 1000);
+ 	}
+ 
+ 	if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_PHY) {
+-		struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+ 		u8 et_swtype = 0;
+ 		u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
+ 			     BGMAC_CHIPCTL_1_IF_TYPE_MII;
+@@ -968,16 +940,15 @@ static void bgmac_chip_reset(struct bgma
+ 			sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
+ 				  BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
+ 		}
+-		bcma_chipco_chipctl_maskset(cc, 1,
+-					    ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
+-					      BGMAC_CHIPCTL_1_SW_TYPE_MASK),
+-					    sw_type);
++		bgmac_cco_ctl_maskset(bgmac, 1, ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
++						  BGMAC_CHIPCTL_1_SW_TYPE_MASK),
++				      sw_type);
+ 	}
+ 
+ 	if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+-		bcma_awrite32(core, BCMA_IOCTL,
+-			      bcma_aread32(core, BCMA_IOCTL) &
+-			      ~BGMAC_BCMA_IOCTL_SW_RESET);
++		bgmac_idm_write(bgmac, BCMA_IOCTL,
++				bgmac_idm_read(bgmac, BCMA_IOCTL) &
++				~BGMAC_BCMA_IOCTL_SW_RESET);
+ 
+ 	/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset
+ 	 * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine
+@@ -1013,8 +984,8 @@ static void bgmac_chip_reset(struct bgma
+ 
+ 	bgmac_clear_mib(bgmac);
+ 	if (bgmac->feature_flags & BGMAC_FEAT_CMN_PHY_CTL)
+-		bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0,
+-			       BCMA_GMAC_CMN_PC_MTE);
++		bgmac_cmn_maskset32(bgmac, BCMA_GMAC_CMN_PHY_CTL, ~0,
++				    BCMA_GMAC_CMN_PC_MTE);
+ 	else
+ 		bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE);
+ 	bgmac_miiconfig(bgmac);
+@@ -1059,8 +1030,8 @@ static void bgmac_enable(struct bgmac *b
+ 	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
+ 		bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+ 	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
+-		bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0,
+-					    BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
++		bgmac_cco_ctl_maskset(bgmac, 1, ~0,
++				      BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
+ 
+ 	if (bgmac->feature_flags & (BGMAC_FEAT_FLW_CTRL1 |
+ 				    BGMAC_FEAT_FLW_CTRL2)) {
+@@ -1082,8 +1053,7 @@ static void bgmac_enable(struct bgmac *b
+ 
+ 		rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
+ 		rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
+-		bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) /
+-				1000000;
++		bp_clk = bgmac_get_bus_clock(bgmac) / 1000000;
+ 		mdp = (bp_clk * 128 / 1000) - 3;
+ 		rxq_ctl |= (mdp << BGMAC_RXQ_CTL_MDP_SHIFT);
+ 		bgmac_write(bgmac, BGMAC_RXQ_CTL, rxq_ctl);
+@@ -1178,7 +1148,7 @@ static int bgmac_open(struct net_device
+ 	/* Specs say about reclaiming rings here, but we do that in DMA init */
+ 	bgmac_chip_init(bgmac);
+ 
+-	err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
++	err = request_irq(bgmac->irq, bgmac_interrupt, IRQF_SHARED,
+ 			  KBUILD_MODNAME, net_dev);
+ 	if (err < 0) {
+ 		dev_err(bgmac->dev, "IRQ request error: %d!\n", err);
+@@ -1204,7 +1174,7 @@ static int bgmac_stop(struct net_device
+ 
+ 	napi_disable(&bgmac->napi);
+ 	bgmac_chip_intrs_off(bgmac);
+-	free_irq(bgmac->core->irq, net_dev);
++	free_irq(bgmac->irq, net_dev);
+ 
+ 	bgmac_chip_reset(bgmac);
+ 	bgmac_dma_cleanup(bgmac);
+@@ -1399,7 +1369,7 @@ static void bgmac_get_drvinfo(struct net
+ 			      struct ethtool_drvinfo *info)
+ {
+ 	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+-	strlcpy(info->bus_info, "BCMA", sizeof(info->bus_info));
++	strlcpy(info->bus_info, "AXI", sizeof(info->bus_info));
+ }
+ 
+ static const struct ethtool_ops bgmac_ethtool_ops = {
+@@ -1483,116 +1453,41 @@ static int bgmac_phy_connect(struct bgma
+ 	return 0;
+ }
+ 
+-static int bgmac_probe(struct bcma_device *core)
++int bgmac_enet_probe(struct bgmac *info)
+ {
+ 	struct net_device *net_dev;
+ 	struct bgmac *bgmac;
+-	struct ssb_sprom *sprom = &core->bus->sprom;
+-	u8 *mac;
+ 	int err;
+ 
+-	switch (core->core_unit) {
+-	case 0:
+-		mac = sprom->et0mac;
+-		break;
+-	case 1:
+-		mac = sprom->et1mac;
+-		break;
+-	case 2:
+-		mac = sprom->et2mac;
+-		break;
+-	default:
+-		dev_err(&core->dev, "Unsupported core_unit %d\n",
+-			core->core_unit);
+-		return -ENOTSUPP;
+-	}
+-
+-	if (!is_valid_ether_addr(mac)) {
+-		dev_err(&core->dev, "Invalid MAC addr: %pM\n", mac);
+-		eth_random_addr(mac);
+-		dev_warn(&core->dev, "Using random MAC: %pM\n", mac);
+-	}
+-
+-	/* This (reset &) enable is not preset in specs or reference driver but
+-	 * Broadcom does it in arch PCI code when enabling fake PCI device.
+-	 */
+-	bcma_core_enable(core, 0);
+-
+ 	/* Allocation and references */
+ 	net_dev = alloc_etherdev(sizeof(*bgmac));
+ 	if (!net_dev)
+ 		return -ENOMEM;
++
+ 	net_dev->netdev_ops = &bgmac_netdev_ops;
+-	net_dev->irq = core->irq;
+ 	net_dev->ethtool_ops = &bgmac_ethtool_ops;
+ 	bgmac = netdev_priv(net_dev);
+-	bgmac->dev = &core->dev;
+-	bgmac->dma_dev = core->dma_dev;
++	memcpy(bgmac, info, sizeof(*bgmac));
+ 	bgmac->net_dev = net_dev;
+-	bgmac->core = core;
+-	bcma_set_drvdata(core, bgmac);
+-	SET_NETDEV_DEV(net_dev, &core->dev);
+-
+-	/* Defaults */
+-	memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
+-
+-	/* On BCM4706 we need common core to access PHY */
+-	if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+-	    !core->bus->drv_gmac_cmn.core) {
+-		dev_err(bgmac->dev, "GMAC CMN core not found (required for BCM4706)\n");
+-		err = -ENODEV;
+-		goto err_netdev_free;
+-	}
+-	bgmac->cmn = core->bus->drv_gmac_cmn.core;
++	net_dev->irq = bgmac->irq;
++	SET_NETDEV_DEV(net_dev, bgmac->dev);
+ 
+-	switch (core->core_unit) {
+-	case 0:
+-		bgmac->phyaddr = sprom->et0phyaddr;
+-		break;
+-	case 1:
+-		bgmac->phyaddr = sprom->et1phyaddr;
+-		break;
+-	case 2:
+-		bgmac->phyaddr = sprom->et2phyaddr;
+-		break;
++	if (!is_valid_ether_addr(bgmac->mac_addr)) {
++		dev_err(bgmac->dev, "Invalid MAC addr: %pM\n",
++			bgmac->mac_addr);
++		eth_random_addr(bgmac->mac_addr);
++		dev_warn(bgmac->dev, "Using random MAC: %pM\n",
++			 bgmac->mac_addr);
+ 	}
+-	bgmac->phyaddr &= BGMAC_PHY_MASK;
+-	if (bgmac->phyaddr == BGMAC_PHY_MASK) {
+-		dev_err(bgmac->dev, "No PHY found\n");
+-		err = -ENODEV;
+-		goto err_netdev_free;
+-	}
+-	dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
+-		 bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
++	ether_addr_copy(net_dev->dev_addr, bgmac->mac_addr);
+ 
+-	if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
+-		dev_err(bgmac->dev, "PCI setup not implemented\n");
+-		err = -ENOTSUPP;
+-		goto err_netdev_free;
+-	}
++	/* This (reset &) enable is not preset in specs or reference driver but
++	 * Broadcom does it in arch PCI code when enabling fake PCI device.
++	 */
++	bgmac_clk_enable(bgmac, 0);
+ 
+ 	bgmac_chip_reset(bgmac);
+ 
+-	/* For Northstar, we have to take all GMAC core out of reset */
+-	if (bgmac_is_bcm4707_family(bgmac)) {
+-		struct bcma_device *ns_core;
+-		int ns_gmac;
+-
+-		/* Northstar has 4 GMAC cores */
+-		for (ns_gmac = 0; ns_gmac < 4; ns_gmac++) {
+-			/* As Northstar requirement, we have to reset all GMACs
+-			 * before accessing one. bgmac_chip_reset() call
+-			 * bcma_core_enable() for this core. Then the other
+-			 * three GMACs didn't reset.  We do it here.
+-			 */
+-			ns_core = bcma_find_core_unit(core->bus,
+-						      BCMA_CORE_MAC_GBIT,
+-						      ns_gmac);
+-			if (ns_core && !bcma_core_is_enabled(ns_core))
+-				bcma_core_enable(ns_core, 0);
+-		}
+-	}
+-
+ 	err = bgmac_dma_alloc(bgmac);
+ 	if (err) {
+ 		dev_err(bgmac->dev, "Unable to alloc memory for DMA\n");
+@@ -1603,103 +1498,15 @@ static int bgmac_probe(struct bcma_devic
+ 	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+ 		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
+ 
+-	bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
+-			       BGMAC_BFL_ENETROBO);
+-	if (bgmac->has_robosw)
+-		dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n");
+-
+-	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+-		dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
+-
+-	/* Feature Flags */
+-	switch (core->bus->chipinfo.id) {
+-	case BCMA_CHIP_ID_BCM5357:
+-		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
+-		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+-		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
+-		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
+-		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47186) {
+-			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
+-			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
+-		}
+-		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM5358)
+-			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
+-		break;
+-	case BCMA_CHIP_ID_BCM53572:
+-		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
+-		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+-		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
+-		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
+-		if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47188) {
+-			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
+-			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
+-		}
+-		break;
+-	case BCMA_CHIP_ID_BCM4749:
+-		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
+-		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+-		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
+-		bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
+-		if (core->bus->chipinfo.pkg == 10) {
+-			bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
+-			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
+-		}
+-		break;
+-	case BCMA_CHIP_ID_BCM4716:
+-		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+-		/* fallthrough */
+-	case BCMA_CHIP_ID_BCM47162:
+-		bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
+-		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
+-		break;
+-	/* bcm4707_family */
+-	case BCMA_CHIP_ID_BCM4707:
+-	case BCMA_CHIP_ID_BCM47094:
+-	case BCMA_CHIP_ID_BCM53018:
+-		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+-		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
+-		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
+-		break;
+-	default:
+-		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+-		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
+-	}
+-
+-	if (!bgmac_is_bcm4707_family(bgmac) && core->id.rev > 2)
+-		bgmac->feature_flags |= BGMAC_FEAT_MISC_PLL_REQ;
+-
+-	if (core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+-		bgmac->feature_flags |= BGMAC_FEAT_CMN_PHY_CTL;
+-		bgmac->feature_flags |= BGMAC_FEAT_NO_CLR_MIB;
+-	}
+-
+-	if (core->id.rev >= 4) {
+-		bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
+-		bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
+-		bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
+-	}
+-
+ 	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+ 
+-	if (!bgmac_is_bcm4707_family(bgmac)) {
+-		struct mii_bus *mii_bus;
+-
+-		mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
+-		if (!IS_ERR(mii_bus)) {
+-			err = PTR_ERR(mii_bus);
+-			goto err_dma_free;
+-		}
+-
+-		bgmac->mii_bus = mii_bus;
+-	}
+-
+ 	if (!bgmac->mii_bus)
+ 		err = bgmac_phy_connect_direct(bgmac);
+ 	else
+ 		err = bgmac_phy_connect(bgmac);
+ 	if (err) {
+ 		dev_err(bgmac->dev, "Cannot connect to phy\n");
+-		goto err_mii_unregister;
++		goto err_dma_free;
+ 	}
+ 
+ 	net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+@@ -1718,56 +1525,24 @@ static int bgmac_probe(struct bcma_devic
+ 
+ err_phy_disconnect:
+ 	phy_disconnect(net_dev->phydev);
+-err_mii_unregister:
+-	bcma_mdio_mii_unregister(bgmac->mii_bus);
+ err_dma_free:
+ 	bgmac_dma_free(bgmac);
+ err_netdev_free:
+-	bcma_set_drvdata(core, NULL);
+ 	free_netdev(net_dev);
+ 
+ 	return err;
+ }
++EXPORT_SYMBOL_GPL(bgmac_enet_probe);
+ 
+-static void bgmac_remove(struct bcma_device *core)
++void bgmac_enet_remove(struct bgmac *bgmac)
+ {
+-	struct bgmac *bgmac = bcma_get_drvdata(core);
+-
+ 	unregister_netdev(bgmac->net_dev);
+ 	phy_disconnect(bgmac->net_dev->phydev);
+-	bcma_mdio_mii_unregister(bgmac->mii_bus);
+ 	netif_napi_del(&bgmac->napi);
+ 	bgmac_dma_free(bgmac);
+-	bcma_set_drvdata(core, NULL);
+ 	free_netdev(bgmac->net_dev);
+ }
+-
+-static struct bcma_driver bgmac_bcma_driver = {
+-	.name		= KBUILD_MODNAME,
+-	.id_table	= bgmac_bcma_tbl,
+-	.probe		= bgmac_probe,
+-	.remove		= bgmac_remove,
+-};
+-
+-static int __init bgmac_init(void)
+-{
+-	int err;
+-
+-	err = bcma_driver_register(&bgmac_bcma_driver);
+-	if (err)
+-		return err;
+-	pr_info("Broadcom 47xx GBit MAC driver loaded\n");
+-
+-	return 0;
+-}
+-
+-static void __exit bgmac_exit(void)
+-{
+-	bcma_driver_unregister(&bgmac_bcma_driver);
+-}
+-
+-module_init(bgmac_init)
+-module_exit(bgmac_exit)
++EXPORT_SYMBOL_GPL(bgmac_enet_remove);
+ 
+ MODULE_AUTHOR("Rafał Miłecki");
+ MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -1,8 +1,6 @@
+ #ifndef _BGMAC_H
+ #define _BGMAC_H
+ 
+-#include <linux/bcma/bcma.h>
+-#include <linux/brcmphy.h>
+ #include <linux/netdevice.h>
+ 
+ #define BGMAC_DEV_CTL				0x000
+@@ -442,11 +440,21 @@ struct bgmac_rx_header {
+ };
+ 
+ struct bgmac {
+-	struct bcma_device *core;
+-	struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
++	union {
++		struct {
++			void *base;
++			void *idm_base;
++		} plat;
++		struct {
++			struct bcma_device *core;
++			/* Reference to CMN core for BCM4706 */
++			struct bcma_device *cmn;
++		} bcma;
++	};
+ 
+ 	struct device *dev;
+ 	struct device *dma_dev;
++	unsigned char mac_addr[ETH_ALEN];
+ 	u32 feature_flags;
+ 
+ 	struct net_device *net_dev;
+@@ -463,6 +471,7 @@ struct bgmac {
+ 	u32 mib_rx_regs[BGMAC_NUM_MIB_RX_REGS];
+ 
+ 	/* Int */
++	int irq;
+ 	u32 int_mask;
+ 
+ 	/* Current MAC state */
+@@ -473,19 +482,71 @@ struct bgmac {
+ 	bool has_robosw;
+ 
+ 	bool loopback;
++
++	u32 (*read)(struct bgmac *bgmac, u16 offset);
++	void (*write)(struct bgmac *bgmac, u16 offset, u32 value);
++	u32 (*idm_read)(struct bgmac *bgmac, u16 offset);
++	void (*idm_write)(struct bgmac *bgmac, u16 offset, u32 value);
++	bool (*clk_enabled)(struct bgmac *bgmac);
++	void (*clk_enable)(struct bgmac *bgmac, u32 flags);
++	void (*cco_ctl_maskset)(struct bgmac *bgmac, u32 offset, u32 mask,
++				u32 set);
++	u32 (*get_bus_clock)(struct bgmac *bgmac);
++	void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
++			      u32 set);
+ };
+ 
++int bgmac_enet_probe(struct bgmac *info);
++void bgmac_enet_remove(struct bgmac *bgmac);
++
+ struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
+ void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
+ 
+ static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
+ {
+-	return bcma_read32(bgmac->core, offset);
++	return bgmac->read(bgmac, offset);
+ }
+ 
+ static inline void bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
+ {
+-	bcma_write32(bgmac->core, offset, value);
++	bgmac->write(bgmac, offset, value);
++}
++
++static inline u32 bgmac_idm_read(struct bgmac *bgmac, u16 offset)
++{
++	return bgmac->idm_read(bgmac, offset);
++}
++
++static inline void bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
++{
++	bgmac->idm_write(bgmac, offset, value);
++}
++
++static inline bool bgmac_clk_enabled(struct bgmac *bgmac)
++{
++	return bgmac->clk_enabled(bgmac);
++}
++
++static inline void bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
++{
++	bgmac->clk_enable(bgmac, flags);
++}
++
++static inline void bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset,
++					 u32 mask, u32 set)
++{
++	bgmac->cco_ctl_maskset(bgmac, offset, mask, set);
++}
++
++static inline u32 bgmac_get_bus_clock(struct bgmac *bgmac)
++{
++	return bgmac->get_bus_clock(bgmac);
++}
++
++static inline void bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset,
++				       u32 mask, u32 set)
++{
++	bgmac->cmn_maskset32(bgmac, offset, mask, set);
+ }
+ 
+ static inline void bgmac_maskset(struct bgmac *bgmac, u16 offset, u32 mask,
diff --git a/target/linux/generic/patches-4.4/076-0001-net-ethernet-bgmac-Fix-return-value-check-in-bgmac_p.patch b/target/linux/generic/patches-4.4/076-0001-net-ethernet-bgmac-Fix-return-value-check-in-bgmac_p.patch
new file mode 100644
index 0000000000..e0431c1235
--- /dev/null
+++ b/target/linux/generic/patches-4.4/076-0001-net-ethernet-bgmac-Fix-return-value-check-in-bgmac_p.patch
@@ -0,0 +1,26 @@
+From 12c2e32f14da857b58af281b029d4549d24c3292 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Date: Tue, 12 Jul 2016 00:17:28 +0000
+Subject: [PATCH] net: ethernet: bgmac: Fix return value check in bgmac_probe()
+
+In case of error, the function devm_ioremap_resource() returns ERR_PTR()
+and never returns NULL. The NULL test in the return value check should be
+replaced with IS_ERR().
+
+Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac-platform.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
++++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
+@@ -141,7 +141,7 @@ static int bgmac_probe(struct platform_d
+ 	}
+ 
+ 	bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
+-	if (!bgmac->plat.idm_base) {
++	if (IS_ERR(bgmac->plat.idm_base)) {
+ 		dev_err(&pdev->dev, "Unable to map idm resource\n");
+ 		return PTR_ERR(bgmac->plat.idm_base);
+ 	}
diff --git a/target/linux/generic/patches-4.4/076-0002-net-ethernet-bgmac-Remove-redundant-dev_err-call-in-.patch b/target/linux/generic/patches-4.4/076-0002-net-ethernet-bgmac-Remove-redundant-dev_err-call-in-.patch
new file mode 100644
index 0000000000..479094830e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/076-0002-net-ethernet-bgmac-Remove-redundant-dev_err-call-in-.patch
@@ -0,0 +1,42 @@
+From ce3a380dddd0cb16cb3d8d947b69657d7646c121 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Date: Wed, 13 Jul 2016 12:46:57 +0000
+Subject: [PATCH] net: ethernet: bgmac: Remove redundant dev_err call in
+ bgmac_probe()
+
+There is a error message within devm_ioremap_resource
+already, so remove the dev_err call to avoid redundant
+error message.
+
+Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac-platform.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
++++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
+@@ -129,10 +129,8 @@ static int bgmac_probe(struct platform_d
+ 	}
+ 
+ 	bgmac->plat.base = devm_ioremap_resource(&pdev->dev, regs);
+-	if (IS_ERR(bgmac->plat.base)) {
+-		dev_err(&pdev->dev, "Unable to map base resource\n");
++	if (IS_ERR(bgmac->plat.base))
+ 		return PTR_ERR(bgmac->plat.base);
+-	}
+ 
+ 	regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
+ 	if (!regs) {
+@@ -141,10 +139,8 @@ static int bgmac_probe(struct platform_d
+ 	}
+ 
+ 	bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
+-	if (IS_ERR(bgmac->plat.idm_base)) {
+-		dev_err(&pdev->dev, "Unable to map idm resource\n");
++	if (IS_ERR(bgmac->plat.idm_base))
+ 		return PTR_ERR(bgmac->plat.idm_base);
+-	}
+ 
+ 	bgmac->read = platform_bgmac_read;
+ 	bgmac->write = platform_bgmac_write;
diff --git a/target/linux/generic/patches-4.4/076-0004-net-bgmac-fix-reversed-check-for-MII-registration-er.patch b/target/linux/generic/patches-4.4/076-0004-net-bgmac-fix-reversed-check-for-MII-registration-er.patch
new file mode 100644
index 0000000000..945546d6df
--- /dev/null
+++ b/target/linux/generic/patches-4.4/076-0004-net-bgmac-fix-reversed-check-for-MII-registration-er.patch
@@ -0,0 +1,28 @@
+From b9f63ae7ba2de2ba19137c5757c0607ce40f3ed5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 17 Aug 2016 15:37:14 +0200
+Subject: [PATCH] net: bgmac: fix reversed check for MII registration error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It was failing on successful registration returning meaningless errors.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Fixes: 55954f3bfdac ("net: ethernet: bgmac: move BCMA MDIO Phy code into a separate file")
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac-bcma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
+@@ -159,7 +159,7 @@ static int bgmac_probe(struct bcma_devic
+ 
+ 	if (!bgmac_is_bcm4707_family(core)) {
+ 		mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
+-		if (!IS_ERR(mii_bus)) {
++		if (IS_ERR(mii_bus)) {
+ 			err = PTR_ERR(mii_bus);
+ 			goto err;
+ 		}
diff --git a/target/linux/generic/patches-4.4/077-0001-net-bgmac-support-Ethernet-core-on-BCM53573-SoCs.patch b/target/linux/generic/patches-4.4/077-0001-net-bgmac-support-Ethernet-core-on-BCM53573-SoCs.patch
new file mode 100644
index 0000000000..82d3fe4d6d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/077-0001-net-bgmac-support-Ethernet-core-on-BCM53573-SoCs.patch
@@ -0,0 +1,161 @@
+From 1cb94db3d1bfe0075bde78fb2989f17e0a8a3936 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 17 Aug 2016 23:00:30 +0200
+Subject: [PATCH] net: bgmac: support Ethernet core on BCM53573 SoCs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM53573 is a new series of Broadcom's SoCs. It's based on ARM and can
+be found in two packages (versions): BCM53573 and BCM47189. It shares
+some code with the Northstar family, but also requires some new quirks.
+
+First of all there can be up to 2 Ethernet cores on this SoC. If that is
+the case, they are connected to two different switch ports allowing some
+more complex/optimized setups. It seems the second unit doesn't come
+fully configured and requires some IRQ quirk.
+
+Other than that only the first core is connected to the PHY. For the
+second one we have to register fixed PHY (similarly to the Northstar),
+otherwise generic PHY driver would get some invalid info.
+
+This has been successfully tested on Tenda AC9 (BCM47189B0).
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac-bcma.c | 19 ++++++++++++++++++-
+ drivers/net/ethernet/broadcom/bgmac.c      | 25 +++++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/bgmac.h      | 19 +++++++++++++++++++
+ include/linux/bcma/bcma.h                  |  3 +++
+ include/linux/bcma/bcma_regs.h             |  1 +
+ 5 files changed, 66 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
+@@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+ static int bgmac_probe(struct bcma_device *core)
+ {
++	struct bcma_chipinfo *ci = &core->bus->chipinfo;
+ 	struct ssb_sprom *sprom = &core->bus->sprom;
+ 	struct mii_bus *mii_bus;
+ 	struct bgmac *bgmac;
+@@ -157,7 +158,8 @@ static int bgmac_probe(struct bcma_devic
+ 	dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
+ 		 bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
+ 
+-	if (!bgmac_is_bcm4707_family(core)) {
++	if (!bgmac_is_bcm4707_family(core) &&
++	    !(ci->id == BCMA_CHIP_ID_BCM53573 && core->core_unit == 1)) {
+ 		mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
+ 		if (IS_ERR(mii_bus)) {
+ 			err = PTR_ERR(mii_bus);
+@@ -230,6 +232,21 @@ static int bgmac_probe(struct bcma_devic
+ 		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
+ 		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
+ 		break;
++	case BCMA_CHIP_ID_BCM53573:
++		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
++		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
++		if (ci->pkg == BCMA_PKG_ID_BCM47189)
++			bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
++		if (core->core_unit == 0) {
++			bgmac->feature_flags |= BGMAC_FEAT_CC4_IF_SW_TYPE;
++			if (ci->pkg == BCMA_PKG_ID_BCM47189)
++				bgmac->feature_flags |=
++					BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII;
++		} else if (core->core_unit == 1) {
++			bgmac->feature_flags |= BGMAC_FEAT_IRQ_ID_OOB_6;
++			bgmac->feature_flags |= BGMAC_FEAT_CC7_IF_TYPE_RGMII;
++		}
++		break;
+ 	default:
+ 		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+ 		bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -943,6 +943,27 @@ static void bgmac_chip_reset(struct bgma
+ 		bgmac_cco_ctl_maskset(bgmac, 1, ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
+ 						  BGMAC_CHIPCTL_1_SW_TYPE_MASK),
+ 				      sw_type);
++	} else if (bgmac->feature_flags & BGMAC_FEAT_CC4_IF_SW_TYPE) {
++		u32 sw_type = BGMAC_CHIPCTL_4_IF_TYPE_MII |
++			      BGMAC_CHIPCTL_4_SW_TYPE_EPHY;
++		u8 et_swtype = 0;
++		char buf[4];
++
++		if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
++			if (kstrtou8(buf, 0, &et_swtype))
++				dev_err(bgmac->dev, "Failed to parse et_swtype (%s)\n",
++					buf);
++			sw_type = (et_swtype & 0x0f) << 12;
++		} else if (bgmac->feature_flags & BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII) {
++			sw_type = BGMAC_CHIPCTL_4_IF_TYPE_RGMII |
++				  BGMAC_CHIPCTL_4_SW_TYPE_RGMII;
++		}
++		bgmac_cco_ctl_maskset(bgmac, 4, ~(BGMAC_CHIPCTL_4_IF_TYPE_MASK |
++						  BGMAC_CHIPCTL_4_SW_TYPE_MASK),
++				      sw_type);
++	} else if (bgmac->feature_flags & BGMAC_FEAT_CC7_IF_TYPE_RGMII) {
++		bgmac_cco_ctl_maskset(bgmac, 7, ~BGMAC_CHIPCTL_7_IF_TYPE_MASK,
++				      BGMAC_CHIPCTL_7_IF_TYPE_RGMII);
+ 	}
+ 
+ 	if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+@@ -1486,6 +1507,10 @@ int bgmac_enet_probe(struct bgmac *info)
+ 	 */
+ 	bgmac_clk_enable(bgmac, 0);
+ 
++	/* This seems to be fixing IRQ by assigning OOB #6 to the core */
++	if (bgmac->feature_flags & BGMAC_FEAT_IRQ_ID_OOB_6)
++		bgmac_idm_write(bgmac, BCMA_OOB_SEL_OUT_A30, 0x86);
++
+ 	bgmac_chip_reset(bgmac);
+ 
+ 	err = bgmac_dma_alloc(bgmac);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -369,6 +369,21 @@
+ #define BGMAC_CHIPCTL_1_SW_TYPE_RGMII		0x000000C0
+ #define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS		0x00010000
+ 
++#define BGMAC_CHIPCTL_4_IF_TYPE_MASK		0x00003000
++#define BGMAC_CHIPCTL_4_IF_TYPE_RMII		0x00000000
++#define BGMAC_CHIPCTL_4_IF_TYPE_MII		0x00001000
++#define BGMAC_CHIPCTL_4_IF_TYPE_RGMII		0x00002000
++#define BGMAC_CHIPCTL_4_SW_TYPE_MASK		0x0000C000
++#define BGMAC_CHIPCTL_4_SW_TYPE_EPHY		0x00000000
++#define BGMAC_CHIPCTL_4_SW_TYPE_EPHYMII		0x00004000
++#define BGMAC_CHIPCTL_4_SW_TYPE_EPHYRMII	0x00008000
++#define BGMAC_CHIPCTL_4_SW_TYPE_RGMII		0x0000C000
++
++#define BGMAC_CHIPCTL_7_IF_TYPE_MASK		0x000000C0
++#define BGMAC_CHIPCTL_7_IF_TYPE_RMII		0x00000000
++#define BGMAC_CHIPCTL_7_IF_TYPE_MII		0x00000040
++#define BGMAC_CHIPCTL_7_IF_TYPE_RGMII		0x00000080
++
+ #define BGMAC_WEIGHT	64
+ 
+ #define ETHER_MAX_LEN   1518
+@@ -390,6 +405,10 @@
+ #define BGMAC_FEAT_NO_CLR_MIB		BIT(13)
+ #define BGMAC_FEAT_FORCE_SPEED_2500	BIT(14)
+ #define BGMAC_FEAT_CMDCFG_SR_REV4	BIT(15)
++#define BGMAC_FEAT_IRQ_ID_OOB_6		BIT(16)
++#define BGMAC_FEAT_CC4_IF_SW_TYPE	BIT(17)
++#define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII	BIT(18)
++#define BGMAC_FEAT_CC7_IF_TYPE_RGMII	BIT(19)
+ 
+ struct bgmac_slot_info {
+ 	union {
+--- a/include/linux/bcma/bcma_regs.h
++++ b/include/linux/bcma/bcma_regs.h
+@@ -23,6 +23,7 @@
+ #define  BCMA_CLKCTLST_4328A0_HAVEALP	0x00020000 /* 4328a0 has reversed bits */
+ 
+ /* Agent registers (common for every core) */
++#define BCMA_OOB_SEL_OUT_A30		0x0100
+ #define BCMA_IOCTL			0x0408 /* IO control */
+ #define  BCMA_IOCTL_CLK			0x0001
+ #define  BCMA_IOCTL_FGC			0x0002
diff --git a/target/linux/generic/patches-4.4/077-0002-net-bgmac-make-it-clear-when-setting-interface-type-.patch b/target/linux/generic/patches-4.4/077-0002-net-bgmac-make-it-clear-when-setting-interface-type-.patch
new file mode 100644
index 0000000000..272ec5c3f3
--- /dev/null
+++ b/target/linux/generic/patches-4.4/077-0002-net-bgmac-make-it-clear-when-setting-interface-type-.patch
@@ -0,0 +1,31 @@
+From e2d8f646c79f26e094bfaf9b21be614d1e148a67 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 17 Aug 2016 23:11:52 +0200
+Subject: [PATCH] net: bgmac: make it clear when setting interface type to RMII
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It doesn't really change anything as BGMAC_CHIPCTL_1_IF_TYPE_RMII is
+equal to 0. It make code a bit clener, so far when reading it one could
+think we forgot to set a proper mode. It also keeps this mode code in
+sync with other ones.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -935,7 +935,8 @@ static void bgmac_chip_reset(struct bgma
+ 			et_swtype <<= 4;
+ 			sw_type = et_swtype;
+ 		} else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_EPHYRMII) {
+-			sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
++			sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RMII |
++				  BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
+ 		} else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_RGMII) {
+ 			sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
+ 				  BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
diff --git a/target/linux/generic/patches-4.4/077-0003-net-bgmac-Fix-errant-feature-flag-check.patch b/target/linux/generic/patches-4.4/077-0003-net-bgmac-Fix-errant-feature-flag-check.patch
new file mode 100644
index 0000000000..830d8ccde4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/077-0003-net-bgmac-Fix-errant-feature-flag-check.patch
@@ -0,0 +1,33 @@
+From 4af1474e6198b10fee7bb20e81f7e033ad1b586c Mon Sep 17 00:00:00 2001
+From: Jon Mason <jon.mason@broadcom.com>
+Date: Wed, 5 Oct 2016 15:36:49 -0400
+Subject: [PATCH] net: bgmac: Fix errant feature flag check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+During the conversion to the feature flags, a check against
+ci->id != BCMA_CHIP_ID_BCM47162
+became
+bgmac->feature_flags & BGMAC_FEAT_CLKCTLS
+instead of
+!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLS)
+
+Reported-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Jon Mason <jon.mason@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1049,7 +1049,7 @@ static void bgmac_enable(struct bgmac *b
+ 
+ 	mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+ 		BGMAC_DS_MM_SHIFT;
+-	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
++	if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) || mode != 0)
+ 		bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+ 	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
+ 		bgmac_cco_ctl_maskset(bgmac, 1, ~0,
diff --git a/target/linux/generic/patches-4.4/077-0004-net-bgmac-fix-spelling-mistake-connecton-connection.patch b/target/linux/generic/patches-4.4/077-0004-net-bgmac-fix-spelling-mistake-connecton-connection.patch
new file mode 100644
index 0000000000..5721abcf95
--- /dev/null
+++ b/target/linux/generic/patches-4.4/077-0004-net-bgmac-fix-spelling-mistake-connecton-connection.patch
@@ -0,0 +1,25 @@
+From c121f72a66c5f92fbe2fc53baa274eef39875cec Mon Sep 17 00:00:00 2001
+From: Colin Ian King <colin.king@canonical.com>
+Date: Mon, 24 Oct 2016 23:46:18 +0100
+Subject: [PATCH] net: bgmac: fix spelling mistake: "connecton" -> "connection"
+
+trivial fix to spelling mistake in dev_err message
+
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Acked-by: Jon Mason <jon.mason@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1468,7 +1468,7 @@ static int bgmac_phy_connect(struct bgma
+ 	phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
+ 			      PHY_INTERFACE_MODE_MII);
+ 	if (IS_ERR(phy_dev)) {
+-		dev_err(bgmac->dev, "PHY connecton failed\n");
++		dev_err(bgmac->dev, "PHY connection failed\n");
+ 		return PTR_ERR(phy_dev);
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.4/080-spi-introduce-accelerated-read-support-for-spi-flash.patch b/target/linux/generic/patches-4.4/080-spi-introduce-accelerated-read-support-for-spi-flash.patch
new file mode 100644
index 0000000000..5e116b0bbf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/080-spi-introduce-accelerated-read-support-for-spi-flash.patch
@@ -0,0 +1,179 @@
+From 556351f14e74db4cd3ddde386457edce7bf0b27f Mon Sep 17 00:00:00 2001
+From: Vignesh R <vigneshr@ti.com>
+Date: Fri, 11 Dec 2015 09:39:56 +0530
+Subject: [PATCH] spi: introduce accelerated read support for spi flash devices
+
+In addition to providing direct access to SPI bus, some spi controller
+hardwares (like ti-qspi) provide special port (like memory mapped port)
+that are optimized to improve SPI flash read performance.
+This means the controller can automatically send the SPI signals
+required to read data from the SPI flash device.
+For this, SPI controller needs to know flash specific information like
+read command to use, dummy bytes and address width.
+
+Introduce spi_flash_read() interface to support accelerated read
+over SPI flash devices. SPI master drivers can implement this callback to
+support interfaces such as memory mapped read etc. m25p80 flash driver
+and other flash drivers can call this make use of such interfaces. The
+interface should only be used with SPI flashes and cannot be used with
+other SPI devices.
+
+Signed-off-by: Vignesh R <vigneshr@ti.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1135,6 +1135,7 @@ static void __spi_pump_messages(struct s
+ 		}
+ 	}
+ 
++	mutex_lock(&master->bus_lock_mutex);
+ 	trace_spi_message_start(master->cur_msg);
+ 
+ 	if (master->prepare_message) {
+@@ -1144,6 +1145,7 @@ static void __spi_pump_messages(struct s
+ 				"failed to prepare message: %d\n", ret);
+ 			master->cur_msg->status = ret;
+ 			spi_finalize_current_message(master);
++			mutex_unlock(&master->bus_lock_mutex);
+ 			return;
+ 		}
+ 		master->cur_msg_prepared = true;
+@@ -1153,6 +1155,7 @@ static void __spi_pump_messages(struct s
+ 	if (ret) {
+ 		master->cur_msg->status = ret;
+ 		spi_finalize_current_message(master);
++		mutex_unlock(&master->bus_lock_mutex);
+ 		return;
+ 	}
+ 
+@@ -1160,8 +1163,10 @@ static void __spi_pump_messages(struct s
+ 	if (ret) {
+ 		dev_err(&master->dev,
+ 			"failed to transfer one message from queue\n");
++		mutex_unlock(&master->bus_lock_mutex);
+ 		return;
+ 	}
++	mutex_unlock(&master->bus_lock_mutex);
+ }
+ 
+ /**
+@@ -2329,6 +2334,46 @@ int spi_async_locked(struct spi_device *
+ EXPORT_SYMBOL_GPL(spi_async_locked);
+ 
+ 
++int spi_flash_read(struct spi_device *spi,
++		   struct spi_flash_read_message *msg)
++
++{
++	struct spi_master *master = spi->master;
++	int ret;
++
++	if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
++	     msg->addr_nbits == SPI_NBITS_DUAL) &&
++	    !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
++		return -EINVAL;
++	if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
++	     msg->addr_nbits == SPI_NBITS_QUAD) &&
++	    !(spi->mode & SPI_TX_QUAD))
++		return -EINVAL;
++	if (msg->data_nbits == SPI_NBITS_DUAL &&
++	    !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
++		return -EINVAL;
++	if (msg->data_nbits == SPI_NBITS_QUAD &&
++	    !(spi->mode &  SPI_RX_QUAD))
++		return -EINVAL;
++
++	if (master->auto_runtime_pm) {
++		ret = pm_runtime_get_sync(master->dev.parent);
++		if (ret < 0) {
++			dev_err(&master->dev, "Failed to power device: %d\n",
++				ret);
++			return ret;
++		}
++	}
++	mutex_lock(&master->bus_lock_mutex);
++	ret = master->spi_flash_read(spi, msg);
++	mutex_unlock(&master->bus_lock_mutex);
++	if (master->auto_runtime_pm)
++		pm_runtime_put(master->dev.parent);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(spi_flash_read);
++
+ /*-------------------------------------------------------------------------*/
+ 
+ /* Utility methods for SPI master protocol drivers, layered on
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -25,6 +25,7 @@
+ struct dma_chan;
+ struct spi_master;
+ struct spi_transfer;
++struct spi_flash_read_message;
+ 
+ /*
+  * INTERFACES between SPI master-side drivers and SPI infrastructure.
+@@ -361,6 +362,8 @@ static inline void spi_unregister_driver
+  * @handle_err: the subsystem calls the driver to handle an error that occurs
+  *		in the generic implementation of transfer_one_message().
+  * @unprepare_message: undo any work done by prepare_message().
++ * @spi_flash_read: to support spi-controller hardwares that provide
++ *                  accelerated interface to read from flash devices.
+  * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
+  *	number. Any individual value may be -ENOENT for CS lines that
+  *	are not GPIOs (driven by the SPI controller itself).
+@@ -507,6 +510,8 @@ struct spi_master {
+ 			       struct spi_message *message);
+ 	int (*unprepare_message)(struct spi_master *master,
+ 				 struct spi_message *message);
++	int (*spi_flash_read)(struct  spi_device *spi,
++			      struct spi_flash_read_message *msg);
+ 
+ 	/*
+ 	 * These hooks are for drivers that use a generic implementation
+@@ -999,6 +1004,42 @@ static inline ssize_t spi_w8r16be(struct
+ 	return be16_to_cpu(result);
+ }
+ 
++/**
++ * struct spi_flash_read_message - flash specific information for
++ * spi-masters that provide accelerated flash read interfaces
++ * @buf: buffer to read data
++ * @from: offset within the flash from where data is to be read
++ * @len: length of data to be read
++ * @retlen: actual length of data read
++ * @read_opcode: read_opcode to be used to communicate with flash
++ * @addr_width: number of address bytes
++ * @dummy_bytes: number of dummy bytes
++ * @opcode_nbits: number of lines to send opcode
++ * @addr_nbits: number of lines to send address
++ * @data_nbits: number of lines for data
++ */
++struct spi_flash_read_message {
++	void *buf;
++	loff_t from;
++	size_t len;
++	size_t retlen;
++	u8 read_opcode;
++	u8 addr_width;
++	u8 dummy_bytes;
++	u8 opcode_nbits;
++	u8 addr_nbits;
++	u8 data_nbits;
++};
++
++/* SPI core interface for flash read support */
++static inline bool spi_flash_read_supported(struct spi_device *spi)
++{
++	return spi->master->spi_flash_read ? true : false;
++}
++
++int spi_flash_read(struct spi_device *spi,
++		   struct spi_flash_read_message *msg);
++
+ /*---------------------------------------------------------------------------*/
+ 
+ /*
diff --git a/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch b/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
new file mode 100644
index 0000000000..730f41e4a5
--- /dev/null
+++ b/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
@@ -0,0 +1,157 @@
+From a7b221d8f0d75511c5f959584712a5dd35f88a86 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 18 Apr 2016 14:39:30 +0200
+Subject: [PATCH] spi: bcm53xx: add spi_flash_read callback for MMIO-based
+ reads
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This implements more efficient reads of SPI-attached flash content.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+
+--- a/drivers/spi/spi-bcm53xx.c
++++ b/drivers/spi/spi-bcm53xx.c
+@@ -10,6 +10,7 @@
+ #include "spi-bcm53xx.h"
+ 
+ #define BCM53XXSPI_MAX_SPI_BAUD	13500000	/* 216 MHz? */
++#define BCM53XXSPI_FLASH_WINDOW	SZ_32M
+ 
+ /* The longest observed required wait was 19 ms */
+ #define BCM53XXSPI_SPE_TIMEOUT_MS	80
+@@ -17,8 +18,10 @@
+ struct bcm53xxspi {
+ 	struct bcma_device *core;
+ 	struct spi_master *master;
++	void __iomem *mmio_base;
+ 
+ 	size_t read_offset;
++	bool bspi;				/* Boot SPI mode with memory mapping */
+ };
+ 
+ static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
+@@ -32,6 +35,50 @@ static inline void bcm53xxspi_write(stru
+ 	bcma_write32(b53spi->core, offset, value);
+ }
+ 
++static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi)
++{
++	struct device *dev = &b53spi->core->dev;
++	unsigned long deadline;
++	u32 tmp;
++
++	if (!b53spi->bspi)
++		return;
++
++	tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
++	if (tmp & 0x1)
++		return;
++
++	deadline = jiffies + usecs_to_jiffies(200);
++	do {
++		tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS);
++		if (!(tmp & 0x1)) {
++			bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL,
++					 0x1);
++			ndelay(200);
++			b53spi->bspi = false;
++			return;
++		}
++		udelay(1);
++	} while (!time_after_eq(jiffies, deadline));
++
++	dev_warn(dev, "Timeout disabling BSPI\n");
++}
++
++static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi)
++{
++	u32 tmp;
++
++	if (b53spi->bspi)
++		return;
++
++	tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
++	if (!(tmp & 0x1))
++		return;
++
++	bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0);
++	b53spi->bspi = true;
++}
++
+ static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
+ {
+ 	/* Do some magic calculation based on length and buad. Add 10% and 1. */
+@@ -176,6 +223,8 @@ static int bcm53xxspi_transfer_one(struc
+ 	u8 *buf;
+ 	size_t left;
+ 
++	bcm53xxspi_disable_bspi(b53spi);
++
+ 	if (t->tx_buf) {
+ 		buf = (u8 *)t->tx_buf;
+ 		left = t->len;
+@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struc
+ 	return 0;
+ }
+ 
++static int bcm53xxspi_flash_read(struct spi_device *spi,
++				 struct spi_flash_read_message *msg)
++{
++	struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master);
++	int ret = 0;
++
++	if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW)
++		return -EINVAL;
++
++	bcm53xxspi_enable_bspi(b53spi);
++	memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
++	msg->retlen = msg->len;
++
++	return ret;
++}
++
+ /**************************************************
+  * BCMA
+  **************************************************/
+@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcm
+ 
+ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+ {
++	struct device *dev = &core->dev;
+ 	struct bcm53xxspi *b53spi;
+ 	struct spi_master *master;
+ 	int err;
+@@ -231,7 +297,7 @@ static int bcm53xxspi_bcma_probe(struct
+ 		return -ENOTSUPP;
+ 	}
+ 
+-	master = spi_alloc_master(&core->dev, sizeof(*b53spi));
++	master = spi_alloc_master(dev, sizeof(*b53spi));
+ 	if (!master)
+ 		return -ENOMEM;
+ 
+@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct
+ 	b53spi->master = master;
+ 	b53spi->core = core;
+ 
++	if (core->addr_s[0])
++		b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0],
++						 BCM53XXSPI_FLASH_WINDOW);
++	b53spi->bspi = true;
++	bcm53xxspi_disable_bspi(b53spi);
++
+ 	master->transfer_one = bcm53xxspi_transfer_one;
++	if (b53spi->mmio_base)
++		master->spi_flash_read = bcm53xxspi_flash_read;
+ 
+ 	bcma_set_drvdata(core, b53spi);
+ 
+-	err = devm_spi_register_master(&core->dev, master);
++	err = devm_spi_register_master(dev, master);
+ 	if (err) {
+ 		spi_master_put(master);
+ 		bcma_set_drvdata(core, NULL);
diff --git a/target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch b/target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch
new file mode 100644
index 0000000000..901cdf7e83
--- /dev/null
+++ b/target/linux/generic/patches-4.4/082-0001-USB-core-let-USB-device-know-device-node.patch
@@ -0,0 +1,179 @@
+From 69bec725985324e79b1c47ea287815ac4ddb0521 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@freescale.com>
+Date: Fri, 19 Feb 2016 17:26:15 +0800
+Subject: [PATCH] USB: core: let USB device know device node
+
+Although most of USB devices are hot-plug's, there are still some devices
+are hard wired on the board, eg, for HSIC and SSIC interface USB devices.
+If these kinds of USB devices are multiple functions, and they can supply
+other interfaces like i2c, gpios for other devices, we may need to
+describe these at device tree.
+
+In this commit, it uses "reg" in dts as physical port number to match
+the phyiscal port number decided by USB core, if they are the same,
+then the device node is for the device we are creating for USB core.
+
+Signed-off-by: Peter Chen <peter.chen@freescale.com>
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: Rob Herring <robh@kernel.org>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ .../devicetree/bindings/usb/usb-device.txt         | 28 +++++++++++++
+ drivers/usb/core/Makefile                          |  2 +-
+ drivers/usb/core/of.c                              | 47 ++++++++++++++++++++++
+ drivers/usb/core/usb.c                             | 10 +++++
+ include/linux/usb/of.h                             |  7 ++++
+ 5 files changed, 93 insertions(+), 1 deletion(-)
+ create mode 100644 Documentation/devicetree/bindings/usb/usb-device.txt
+ create mode 100644 drivers/usb/core/of.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/usb/usb-device.txt
+@@ -0,0 +1,28 @@
++Generic USB Device Properties
++
++Usually, we only use device tree for hard wired USB device.
++The reference binding doc is from:
++http://www.firmware.org/1275/bindings/usb/usb-1_0.ps
++
++Required properties:
++- compatible: usbVID,PID. The textual representation of VID, PID shall
++  be in lower case hexadecimal with leading zeroes suppressed. The
++  other compatible strings from the above standard binding could also
++  be used, but a device adhering to this binding may leave out all except
++  for usbVID,PID.
++- reg: the port number which this device is connecting to, the range
++  is 1-31.
++
++Example:
++
++&usb1 {
++	status = "okay";
++
++	#address-cells = <1>;
++	#size-cells = <0>;
++
++	hub: genesys@1 {
++		compatible = "usb5e3,608";
++		reg = <1>;
++	};
++}
+--- a/drivers/usb/core/Makefile
++++ b/drivers/usb/core/Makefile
+@@ -5,7 +5,7 @@
+ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
+ usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
+ usbcore-y += devio.o notify.o generic.o quirks.o devices.o
+-usbcore-y += port.o
++usbcore-y += port.o of.o
+ 
+ usbcore-$(CONFIG_PCI)		+= hcd-pci.o
+ usbcore-$(CONFIG_ACPI)		+= usb-acpi.o
+--- /dev/null
++++ b/drivers/usb/core/of.c
+@@ -0,0 +1,47 @@
++/*
++ * of.c		The helpers for hcd device tree support
++ *
++ * Copyright (C) 2016 Freescale Semiconductor, Inc.
++ * Author: Peter Chen <peter.chen@freescale.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2  of
++ * the License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/of.h>
++
++/**
++ * usb_of_get_child_node - Find the device node match port number
++ * @parent: the parent device node
++ * @portnum: the port number which device is connecting
++ *
++ * Find the node from device tree according to its port number.
++ *
++ * Return: On success, a pointer to the device node, %NULL on failure.
++ */
++struct device_node *usb_of_get_child_node(struct device_node *parent,
++					int portnum)
++{
++	struct device_node *node;
++	u32 port;
++
++	for_each_child_of_node(parent, node) {
++		if (!of_property_read_u32(node, "reg", &port)) {
++			if (port == portnum)
++				return node;
++		}
++	}
++
++	return NULL;
++}
++EXPORT_SYMBOL_GPL(usb_of_get_child_node);
++
+--- a/drivers/usb/core/usb.c
++++ b/drivers/usb/core/usb.c
+@@ -36,6 +36,7 @@
+ #include <linux/mutex.h>
+ #include <linux/workqueue.h>
+ #include <linux/debugfs.h>
++#include <linux/usb/of.h>
+ 
+ #include <asm/io.h>
+ #include <linux/scatterlist.h>
+@@ -469,6 +470,7 @@ struct usb_device *usb_alloc_dev(struct
+ 		dev->route = 0;
+ 
+ 		dev->dev.parent = bus->controller;
++		dev->dev.of_node = bus->controller->of_node;
+ 		dev_set_name(&dev->dev, "usb%d", bus->busnum);
+ 		root_hub = 1;
+ 	} else {
+@@ -493,6 +495,14 @@ struct usb_device *usb_alloc_dev(struct
+ 		dev->dev.parent = &parent->dev;
+ 		dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
+ 
++		if (!parent->parent) {
++			/* device under root hub's port */
++			port1 = usb_hcd_find_raw_port_number(usb_hcd,
++				port1);
++		}
++		dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
++				port1);
++
+ 		/* hub driver sets up TT records */
+ 	}
+ 
+--- a/include/linux/usb/of.h
++++ b/include/linux/usb/of.h
+@@ -15,6 +15,8 @@
+ bool of_usb_host_tpl_support(struct device_node *np);
+ int of_usb_update_otg_caps(struct device_node *np,
+ 			struct usb_otg_caps *otg_caps);
++struct device_node *usb_of_get_child_node(struct device_node *parent,
++			int portnum);
+ #else
+ static inline bool of_usb_host_tpl_support(struct device_node *np)
+ {
+@@ -25,6 +27,11 @@ static inline int of_usb_update_otg_caps
+ {
+ 	return 0;
+ }
++static inline struct device_node *usb_of_get_child_node
++		(struct device_node *parent, int portnum)
++{
++	return NULL;
++}
+ #endif
+ 
+ #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
diff --git a/target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch b/target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch
new file mode 100644
index 0000000000..15cf4cae56
--- /dev/null
+++ b/target/linux/generic/patches-4.4/082-0002-usb-core-usb_alloc_dev-fix-setting-of-portnum.patch
@@ -0,0 +1,108 @@
+From 7222c832254a75dcd67d683df75753d4a4e125bb Mon Sep 17 00:00:00 2001
+From: Nicolai Stange <nicstange@gmail.com>
+Date: Thu, 17 Mar 2016 23:53:02 +0100
+Subject: [PATCH] usb/core: usb_alloc_dev(): fix setting of ->portnum
+
+With commit 69bec7259853 ("USB: core: let USB device know device node"),
+the port1 argument of usb_alloc_dev() gets overwritten as follows:
+
+  ... usb_alloc_dev(..., unsigned port1)
+  {
+    ...
+    if (!parent->parent) {
+      port1 = usb_hcd_find_raw_port_number(..., port1);
+    }
+    ...
+  }
+
+Later on, this now overwritten port1 gets assigned to ->portnum:
+
+  dev->portnum = port1;
+
+However, since xhci_find_raw_port_number() isn't idempotent, the
+aforementioned commit causes a number of KASAN splats like the following:
+
+  BUG: KASAN: slab-out-of-bounds in xhci_find_raw_port_number+0x98/0x170
+                                       at addr ffff8801d9311670
+  Read of size 8 by task kworker/2:1/87
+  [...]
+  Workqueue: usb_hub_wq hub_event
+   0000000000000188 000000005814b877 ffff8800cba17588 ffffffff8191447e
+   0000000041b58ab3 ffffffff82a03209 ffffffff819143a2 ffffffff82a252f4
+   ffff8801d93115e0 0000000000000188 ffff8801d9311628 ffff8800cba17588
+  Call Trace:
+   [<ffffffff8191447e>] dump_stack+0xdc/0x15e
+   [<ffffffff819143a2>] ? _atomic_dec_and_lock+0xa2/0xa2
+   [<ffffffff814e2cd1>] ? print_section+0x61/0xb0
+   [<ffffffff814e4939>] print_trailer+0x179/0x2c0
+   [<ffffffff814f0d84>] object_err+0x34/0x40
+   [<ffffffff814f4388>] kasan_report_error+0x2f8/0x8b0
+   [<ffffffff814eb91e>] ? __slab_alloc+0x5e/0x90
+   [<ffffffff812178c0>] ? __lock_is_held+0x90/0x130
+   [<ffffffff814f5091>] kasan_report+0x71/0xa0
+   [<ffffffff814ec082>] ? kmem_cache_alloc_trace+0x212/0x560
+   [<ffffffff81d99468>] ? xhci_find_raw_port_number+0x98/0x170
+   [<ffffffff814f33d4>] __asan_load8+0x64/0x70
+   [<ffffffff81d99468>] xhci_find_raw_port_number+0x98/0x170
+   [<ffffffff81db0105>] xhci_setup_addressable_virt_dev+0x235/0xa10
+   [<ffffffff81d9ea51>] xhci_setup_device+0x3c1/0x1430
+   [<ffffffff8121cddd>] ? trace_hardirqs_on+0xd/0x10
+   [<ffffffff81d9fac0>] ? xhci_setup_device+0x1430/0x1430
+   [<ffffffff81d9fad3>] xhci_address_device+0x13/0x20
+   [<ffffffff81d2081a>] hub_port_init+0x55a/0x1550
+   [<ffffffff81d28705>] hub_event+0xef5/0x24d0
+   [<ffffffff81d27810>] ? hub_port_debounce+0x2f0/0x2f0
+   [<ffffffff8195e1ee>] ? debug_object_deactivate+0x1be/0x270
+   [<ffffffff81210203>] ? print_rt_rq+0x53/0x2d0
+   [<ffffffff8121657d>] ? trace_hardirqs_off+0xd/0x10
+   [<ffffffff8226acfb>] ? _raw_spin_unlock_irqrestore+0x5b/0x60
+   [<ffffffff81250000>] ? irq_domain_set_hwirq_and_chip+0x30/0xb0
+   [<ffffffff81256339>] ? debug_lockdep_rcu_enabled+0x39/0x40
+   [<ffffffff812178c0>] ? __lock_is_held+0x90/0x130
+   [<ffffffff81196877>] process_one_work+0x567/0xec0
+  [...]
+
+Afterwards, xhci reports some functional errors:
+
+  xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion
+                                code 0x11.
+  xhci_hcd 0000:00:14.0: ERROR: unexpected setup address command completion
+                                code 0x11.
+  usb 4-3: device not accepting address 2, error -22
+
+Fix this by not overwriting the port1 argument in usb_alloc_dev(), but
+storing the raw port number as required by OF in an additional variable,
+raw_port.
+
+Fixes: 69bec7259853 ("USB: core: let USB device know device node")
+Signed-off-by: Nicolai Stange <nicstange@gmail.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/core/usb.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/core/usb.c
++++ b/drivers/usb/core/usb.c
+@@ -423,6 +423,7 @@ struct usb_device *usb_alloc_dev(struct
+ 	struct usb_device *dev;
+ 	struct usb_hcd *usb_hcd = bus_to_hcd(bus);
+ 	unsigned root_hub = 0;
++	unsigned raw_port = port1;
+ 
+ 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ 	if (!dev)
+@@ -497,11 +498,11 @@ struct usb_device *usb_alloc_dev(struct
+ 
+ 		if (!parent->parent) {
+ 			/* device under root hub's port */
+-			port1 = usb_hcd_find_raw_port_number(usb_hcd,
++			raw_port = usb_hcd_find_raw_port_number(usb_hcd,
+ 				port1);
+ 		}
+ 		dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
+-				port1);
++				raw_port);
+ 
+ 		/* hub driver sets up TT records */
+ 	}
diff --git a/target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch b/target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch
new file mode 100644
index 0000000000..0408353138
--- /dev/null
+++ b/target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch
@@ -0,0 +1,182 @@
+From 4143804c4fdef40358c654d1fb2271a1a0f1fedf Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 5 Feb 2016 17:02:52 -0800
+Subject: [PATCH] clk: Add {devm_}clk_hw_{register,unregister}() APIs
+
+We've largely split the clk consumer and provider APIs along
+struct clk and struct clk_hw, but clk_register() still returns a
+struct clk pointer for each struct clk_hw that's registered.
+Eventually we'd like to only allocate struct clks when there's a
+user, because struct clk is per-user now, so clk_register() needs
+to change.
+
+Let's add new APIs to register struct clk_hws, but this time
+we'll hide the struct clk from the caller by returning an int
+error code. Also add an unregistration API that takes the clk_hw
+structure that was passed to the registration API. This way
+provider drivers never have to deal with a struct clk pointer
+unless they're using the clk consumer APIs.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ Documentation/driver-model/devres.txt |  1 +
+ drivers/clk/clk.c                     | 86 +++++++++++++++++++++++++++++++++++
+ include/linux/clk-provider.h          |  6 +++
+ 3 files changed, 93 insertions(+)
+
+--- a/Documentation/driver-model/devres.txt
++++ b/Documentation/driver-model/devres.txt
+@@ -236,6 +236,7 @@ certainly invest a bit more effort into
+ CLOCK
+   devm_clk_get()
+   devm_clk_put()
++  devm_clk_hw_register()
+ 
+ DMA
+   dmam_alloc_coherent()
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -2595,6 +2595,22 @@ fail_out:
+ }
+ EXPORT_SYMBOL_GPL(clk_register);
+ 
++/**
++ * clk_hw_register - register a clk_hw and return an error code
++ * @dev: device that is registering this clock
++ * @hw: link to hardware-specific clock data
++ *
++ * clk_hw_register is the primary interface for populating the clock tree with
++ * new clock nodes. It returns an integer equal to zero indicating success or
++ * less than zero indicating failure. Drivers must test for an error code after
++ * calling clk_hw_register().
++ */
++int clk_hw_register(struct device *dev, struct clk_hw *hw)
++{
++	return PTR_ERR_OR_ZERO(clk_register(dev, hw));
++}
++EXPORT_SYMBOL_GPL(clk_hw_register);
++
+ /* Free memory allocated for a clock. */
+ static void __clk_release(struct kref *ref)
+ {
+@@ -2696,11 +2712,26 @@ void clk_unregister(struct clk *clk)
+ }
+ EXPORT_SYMBOL_GPL(clk_unregister);
+ 
++/**
++ * clk_hw_unregister - unregister a currently registered clk_hw
++ * @hw: hardware-specific clock data to unregister
++ */
++void clk_hw_unregister(struct clk_hw *hw)
++{
++	clk_unregister(hw->clk);
++}
++EXPORT_SYMBOL_GPL(clk_hw_unregister);
++
+ static void devm_clk_release(struct device *dev, void *res)
+ {
+ 	clk_unregister(*(struct clk **)res);
+ }
+ 
++static void devm_clk_hw_release(struct device *dev, void *res)
++{
++	clk_hw_unregister(*(struct clk_hw **)res);
++}
++
+ /**
+  * devm_clk_register - resource managed clk_register()
+  * @dev: device that is registering this clock
+@@ -2731,6 +2762,36 @@ struct clk *devm_clk_register(struct dev
+ }
+ EXPORT_SYMBOL_GPL(devm_clk_register);
+ 
++/**
++ * devm_clk_hw_register - resource managed clk_hw_register()
++ * @dev: device that is registering this clock
++ * @hw: link to hardware-specific clock data
++ *
++ * Managed clk_hw_register(). Clocks returned from this function are
++ * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register()
++ * for more information.
++ */
++int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
++{
++	struct clk_hw **hwp;
++	int ret;
++
++	hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
++	if (!hwp)
++		return -ENOMEM;
++
++	ret = clk_hw_register(dev, hw);
++	if (!ret) {
++		*hwp = hw;
++		devres_add(dev, hwp);
++	} else {
++		devres_free(hwp);
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(devm_clk_hw_register);
++
+ static int devm_clk_match(struct device *dev, void *res, void *data)
+ {
+ 	struct clk *c = res;
+@@ -2739,6 +2800,15 @@ static int devm_clk_match(struct device
+ 	return c == data;
+ }
+ 
++static int devm_clk_hw_match(struct device *dev, void *res, void *data)
++{
++	struct clk_hw *hw = res;
++
++	if (WARN_ON(!hw))
++		return 0;
++	return hw == data;
++}
++
+ /**
+  * devm_clk_unregister - resource managed clk_unregister()
+  * @clk: clock to unregister
+@@ -2753,6 +2823,22 @@ void devm_clk_unregister(struct device *
+ }
+ EXPORT_SYMBOL_GPL(devm_clk_unregister);
+ 
++/**
++ * devm_clk_hw_unregister - resource managed clk_hw_unregister()
++ * @dev: device that is unregistering the hardware-specific clock data
++ * @hw: link to hardware-specific clock data
++ *
++ * Unregister a clk_hw registered with devm_clk_hw_register(). Normally
++ * this function will not need to be called and the resource management
++ * code will ensure that the resource is freed.
++ */
++void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
++{
++	WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
++				hw));
++}
++EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
++
+ /*
+  * clkdev helpers
+  */
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -639,9 +639,15 @@ void of_gpio_mux_clk_setup(struct device
+ struct clk *clk_register(struct device *dev, struct clk_hw *hw);
+ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
+ 
++int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw);
++int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw);
++
+ void clk_unregister(struct clk *clk);
+ void devm_clk_unregister(struct device *dev, struct clk *clk);
+ 
++void clk_hw_unregister(struct clk_hw *hw);
++void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
++
+ /* helper functions */
+ const char *__clk_get_name(const struct clk *clk);
+ const char *clk_hw_get_name(const struct clk_hw *hw);
diff --git a/target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch b/target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch
new file mode 100644
index 0000000000..0bcb5bb805
--- /dev/null
+++ b/target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch
@@ -0,0 +1,234 @@
+From 0861e5b8cf80038e91942f1005c8dfce79d18c38 Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 5 Feb 2016 17:38:26 -0800
+Subject: [PATCH] clk: Add clk_hw OF clk providers
+
+Now that we have a clk registration API that doesn't return
+struct clks, we need to have some way to hand out struct clks via
+the clk_get() APIs that doesn't involve associating struct clk
+pointers with an OF node. Currently we ask the OF provider to
+give us a struct clk pointer for some clkspec, turn that struct
+clk into a struct clk_hw and then allocate a new struct clk to
+return to the caller.
+
+Let's add a clk_hw based OF provider hook that returns a struct
+clk_hw directly, so that we skip the intermediate step of
+converting from struct clk to struct clk_hw. Eventually when
+we've converted all OF clk providers to struct clk_hw based APIs
+we can remove the struct clk based ones.
+
+It should also be noted that we change the onecell provider to
+have a flex array instead of a pointer for the array of clk_hw
+pointers. This allows providers to allocate one structure of the
+correct length in one step instead of two.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/clk.c            | 85 +++++++++++++++++++++++++++++++++++++++++---
+ include/linux/clk-provider.h | 30 ++++++++++++++++
+ 2 files changed, 111 insertions(+), 4 deletions(-)
+
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -3001,6 +3001,7 @@ struct of_clk_provider {
+ 
+ 	struct device_node *node;
+ 	struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
++	struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
+ 	void *data;
+ };
+ 
+@@ -3017,6 +3018,12 @@ struct clk *of_clk_src_simple_get(struct
+ }
+ EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
+ 
++struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
++{
++	return data;
++}
++EXPORT_SYMBOL_GPL(of_clk_hw_simple_get);
++
+ struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
+ {
+ 	struct clk_onecell_data *clk_data = data;
+@@ -3031,6 +3038,21 @@ struct clk *of_clk_src_onecell_get(struc
+ }
+ EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
+ 
++struct clk_hw *
++of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
++{
++	struct clk_hw_onecell_data *hw_data = data;
++	unsigned int idx = clkspec->args[0];
++
++	if (idx >= hw_data->num) {
++		pr_err("%s: invalid index %u\n", __func__, idx);
++		return ERR_PTR(-EINVAL);
++	}
++
++	return hw_data->hws[idx];
++}
++EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
++
+ /**
+  * of_clk_add_provider() - Register a clock provider for a node
+  * @np: Device node pointer associated with clock provider
+@@ -3067,6 +3089,41 @@ int of_clk_add_provider(struct device_no
+ EXPORT_SYMBOL_GPL(of_clk_add_provider);
+ 
+ /**
++ * of_clk_add_hw_provider() - Register a clock provider for a node
++ * @np: Device node pointer associated with clock provider
++ * @get: callback for decoding clk_hw
++ * @data: context pointer for @get callback.
++ */
++int of_clk_add_hw_provider(struct device_node *np,
++			   struct clk_hw *(*get)(struct of_phandle_args *clkspec,
++						 void *data),
++			   void *data)
++{
++	struct of_clk_provider *cp;
++	int ret;
++
++	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
++	if (!cp)
++		return -ENOMEM;
++
++	cp->node = of_node_get(np);
++	cp->data = data;
++	cp->get_hw = get;
++
++	mutex_lock(&of_clk_mutex);
++	list_add(&cp->link, &of_clk_providers);
++	mutex_unlock(&of_clk_mutex);
++	pr_debug("Added clk_hw provider from %s\n", np->full_name);
++
++	ret = of_clk_set_defaults(np, true);
++	if (ret < 0)
++		of_clk_del_provider(np);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
++
++/**
+  * of_clk_del_provider() - Remove a previously registered clock provider
+  * @np: Device node pointer associated with clock provider
+  */
+@@ -3087,11 +3144,32 @@ void of_clk_del_provider(struct device_n
+ }
+ EXPORT_SYMBOL_GPL(of_clk_del_provider);
+ 
++static struct clk_hw *
++__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
++			      struct of_phandle_args *clkspec)
++{
++	struct clk *clk;
++	struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
++
++	if (provider->get_hw) {
++		hw = provider->get_hw(clkspec, provider->data);
++	} else if (provider->get) {
++		clk = provider->get(clkspec, provider->data);
++		if (!IS_ERR(clk))
++			hw = __clk_get_hw(clk);
++		else
++			hw = ERR_CAST(clk);
++	}
++
++	return hw;
++}
++
+ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ 				       const char *dev_id, const char *con_id)
+ {
+ 	struct of_clk_provider *provider;
+ 	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
++	struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
+ 
+ 	if (!clkspec)
+ 		return ERR_PTR(-EINVAL);
+@@ -3100,10 +3178,9 @@ struct clk *__of_clk_get_from_provider(s
+ 	mutex_lock(&of_clk_mutex);
+ 	list_for_each_entry(provider, &of_clk_providers, link) {
+ 		if (provider->node == clkspec->np)
+-			clk = provider->get(clkspec, provider->data);
+-		if (!IS_ERR(clk)) {
+-			clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
+-					       con_id);
++			hw = __of_clk_get_hw_from_provider(provider, clkspec);
++		if (!IS_ERR(hw)) {
++			clk = __clk_create_clk(hw, dev_id, con_id);
+ 
+ 			if (!IS_ERR(clk) && !__clk_get(clk)) {
+ 				__clk_free_clk(clk);
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -693,6 +693,11 @@ struct clk_onecell_data {
+ 	unsigned int clk_num;
+ };
+ 
++struct clk_hw_onecell_data {
++	size_t num;
++	struct clk_hw *hws[];
++};
++
+ extern struct of_device_id __clk_of_table;
+ 
+ #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
+@@ -702,10 +707,19 @@ int of_clk_add_provider(struct device_no
+ 			struct clk *(*clk_src_get)(struct of_phandle_args *args,
+ 						   void *data),
+ 			void *data);
++int of_clk_add_hw_provider(struct device_node *np,
++			   struct clk_hw *(*get)(struct of_phandle_args *clkspec,
++						 void *data),
++			   void *data);
+ void of_clk_del_provider(struct device_node *np);
+ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
+ 				  void *data);
++
++struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec,
++				    void *data);
+ struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
++struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec,
++				     void *data);
+ int of_clk_get_parent_count(struct device_node *np);
+ int of_clk_parent_fill(struct device_node *np, const char **parents,
+ 		       unsigned int size);
+@@ -722,6 +736,13 @@ static inline int of_clk_add_provider(st
+ {
+ 	return 0;
+ }
++static inline int of_clk_add_hw_provider(struct device_node *np,
++			struct clk_hw *(*get)(struct of_phandle_args *clkspec,
++					      void *data),
++			void *data)
++{
++	return 0;
++}
+ #define of_clk_del_provider(np) \
+ 	{ while (0); }
+ static inline struct clk *of_clk_src_simple_get(
+@@ -729,11 +750,21 @@ static inline struct clk *of_clk_src_sim
+ {
+ 	return ERR_PTR(-ENOENT);
+ }
++static inline struct clk_hw *
++of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
++{
++	return ERR_PTR(-ENOENT);
++}
+ static inline struct clk *of_clk_src_onecell_get(
+ 	struct of_phandle_args *clkspec, void *data)
+ {
+ 	return ERR_PTR(-ENOENT);
+ }
++static inline struct clk_hw *
++of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
++{
++	return ERR_PTR(-ENOENT);
++}
+ static inline int of_clk_get_parent_count(struct device_node *np)
+ {
+ 	return 0;
diff --git a/target/linux/generic/patches-4.4/084-0001-usb-core-Introduce-a-USB-port-LED-trigger.patch b/target/linux/generic/patches-4.4/084-0001-usb-core-Introduce-a-USB-port-LED-trigger.patch
new file mode 100644
index 0000000000..68039f67bb
--- /dev/null
+++ b/target/linux/generic/patches-4.4/084-0001-usb-core-Introduce-a-USB-port-LED-trigger.patch
@@ -0,0 +1,465 @@
+From 0f247626cbbfa2010d2b86fdee652605e084e248 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 16 Sep 2016 16:13:48 +0200
+Subject: [PATCH] usb: core: Introduce a USB port LED trigger
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This commit adds a new trigger responsible for turning on LED when USB
+device gets connected to the selected USB port. This can can useful for
+various home routers that have USB port(s) and a proper LED telling user
+a device is connected.
+
+The trigger gets its documentation file but basically it just requires
+enabling it and selecting USB ports (e.g. echo 1 > ports/usb1-1).
+
+There was a long discussion on design of this driver. Its current state
+is a result of picking them most adjustable solution as others couldn't
+handle all cases.
+
+1) It wasn't possible for the driver to register separated trigger for
+   each USB port. Some physical USB ports are handled by more than one
+   controller and so by more than one USB port. E.g. USB 2.0 physical
+   port may be handled by OHCI's port and EHCI's port.
+   It's also not possible to assign more than 1 trigger to a single LED
+   and implementing such feature would be tricky due to syncing triggers
+   and sysfs conflicts with old triggers.
+
+2) Another idea was to register trigger per USB hub. This wouldn't allow
+   handling devices with multiple USB LEDs and controllers (hubs)
+   controlling more than 1 physical port. It's common for hubs to have
+   few ports and each may have its own LED.
+
+This final trigger is highly flexible. It allows selecting any USB ports
+for any LED. It was also modified (comparing to the initial version) to
+allow choosing ports rather than having user /guess/ proper names. It
+was successfully tested on SmartRG SR400ac which has 3 USB LEDs,
+2 physical ports and 3 controllers.
+
+It was noted USB subsystem already has usb-gadget and usb-host triggers
+but they are pretty trivial ones. They indicate activity only and can't
+have ports specified.
+
+In future it may be good idea to consider adding activity support to
+usbport as well. This should allow switching to this more generic driver
+and maybe marking old ones as obsolete.
+This can be implemented with another sysfs file for setting mode. The
+default mode wouldn't change so there won't be ABI breakage and so such
+feature can be safely implemented later.
+
+There was also an idea of supporting other devices (PCI, SDIO, etc.) but
+as this driver already contains some USB specific code (and will get
+more) these should be probably separated drivers (triggers).
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ .../ABI/testing/sysfs-class-led-trigger-usbport    |  12 +
+ Documentation/leds/ledtrig-usbport.txt             |  41 +++
+ drivers/usb/core/Kconfig                           |   8 +
+ drivers/usb/core/Makefile                          |   2 +
+ drivers/usb/core/ledtrig-usbport.c                 | 314 +++++++++++++++++++++
+ 5 files changed, 377 insertions(+)
+ create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-usbport
+ create mode 100644 Documentation/leds/ledtrig-usbport.txt
+ create mode 100644 drivers/usb/core/ledtrig-usbport.c
+
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-led-trigger-usbport
+@@ -0,0 +1,12 @@
++What:		/sys/class/leds/<led>/ports/<port>
++Date:		September 2016
++KernelVersion:	4.9
++Contact:	linux-leds@vger.kernel.org
++		linux-usb@vger.kernel.org
++Description:
++		Every dir entry represents a single USB port that can be
++		selected for the USB port trigger. Selecting ports makes trigger
++		observing them for any connected devices and lighting on LED if
++		there are any.
++		Echoing "1" value selects USB port. Echoing "0" unselects it.
++		Current state can be also read.
+--- /dev/null
++++ b/Documentation/leds/ledtrig-usbport.txt
+@@ -0,0 +1,41 @@
++USB port LED trigger
++====================
++
++This LED trigger can be used for signalling to the user a presence of USB device
++in a given port. It simply turns on LED when device appears and turns it off
++when it disappears.
++
++It requires selecting USB ports that should be observed. All available ones are
++listed as separated entries in a "ports" subdirectory. Selecting is handled by
++echoing "1" to a chosen port.
++
++Please note that this trigger allows selecting multiple USB ports for a single
++LED. This can be useful in two cases:
++
++1) Device with single USB LED and few physical ports
++
++In such a case LED will be turned on as long as there is at least one connected
++USB device.
++
++2) Device with a physical port handled by few controllers
++
++Some devices may have one controller per PHY standard. E.g. USB 3.0 physical
++port may be handled by ohci-platform, ehci-platform and xhci-hcd. If there is
++only one LED user will most likely want to assign ports from all 3 hubs.
++
++
++This trigger can be activated from user space on led class devices as shown
++below:
++
++  echo usbport > trigger
++
++This adds sysfs attributes to the LED that are documented in:
++Documentation/ABI/testing/sysfs-class-led-trigger-usbport
++
++Example use-case:
++
++  echo usbport > trigger
++  echo 1 > ports/usb1-port1
++  echo 1 > ports/usb2-port1
++  cat ports/usb1-port1
++  echo 0 > ports/usb1-port1
+--- a/drivers/usb/core/Kconfig
++++ b/drivers/usb/core/Kconfig
+@@ -103,3 +103,11 @@ config USB_ULPI_BUS
+ 
+ 	  To compile this driver as a module, choose M here: the module will
+ 	  be called ulpi.
++
++config USB_LEDS_TRIGGER_USBPORT
++	tristate "USB port LED trigger"
++	depends on USB && LEDS_TRIGGERS
++	help
++	  This driver allows LEDs to be controlled by USB events. Enabling this
++	  trigger allows specifying list of USB ports that should turn on LED
++	  when some USB device gets connected.
+--- a/drivers/usb/core/Makefile
++++ b/drivers/usb/core/Makefile
+@@ -11,3 +11,5 @@ usbcore-$(CONFIG_PCI)		+= hcd-pci.o
+ usbcore-$(CONFIG_ACPI)		+= usb-acpi.o
+ 
+ obj-$(CONFIG_USB)		+= usbcore.o
++
++obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT)	+= ledtrig-usbport.o
+--- /dev/null
++++ b/drivers/usb/core/ledtrig-usbport.c
+@@ -0,0 +1,314 @@
++/*
++ * USB port LED trigger
++ *
++ * Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
++ *
++ * 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/device.h>
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/usb.h>
++
++struct usbport_trig_data {
++	struct led_classdev *led_cdev;
++	struct list_head ports;
++	struct notifier_block nb;
++	int count; /* Amount of connected matching devices */
++};
++
++struct usbport_trig_port {
++	struct usbport_trig_data *data;
++	struct usb_device *hub;
++	int portnum;
++	char *port_name;
++	bool observed;
++	struct device_attribute attr;
++	struct list_head list;
++};
++
++/***************************************
++ * Helpers
++ ***************************************/
++
++/**
++ * usbport_trig_usb_dev_observed - Check if dev is connected to observed port
++ */
++static bool usbport_trig_usb_dev_observed(struct usbport_trig_data *usbport_data,
++					  struct usb_device *usb_dev)
++{
++	struct usbport_trig_port *port;
++
++	if (!usb_dev->parent)
++		return false;
++
++	list_for_each_entry(port, &usbport_data->ports, list) {
++		if (usb_dev->parent == port->hub &&
++		    usb_dev->portnum == port->portnum)
++			return port->observed;
++	}
++
++	return false;
++}
++
++static int usbport_trig_usb_dev_check(struct usb_device *usb_dev, void *data)
++{
++	struct usbport_trig_data *usbport_data = data;
++
++	if (usbport_trig_usb_dev_observed(usbport_data, usb_dev))
++		usbport_data->count++;
++
++	return 0;
++}
++
++/**
++ * usbport_trig_update_count - Recalculate amount of connected matching devices
++ */
++static void usbport_trig_update_count(struct usbport_trig_data *usbport_data)
++{
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++
++	usbport_data->count = 0;
++	usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
++	led_cdev->brightness_set(led_cdev,
++				 usbport_data->count ? LED_FULL : LED_OFF);
++}
++
++/***************************************
++ * Device attr
++ ***************************************/
++
++static ssize_t usbport_trig_port_show(struct device *dev,
++				      struct device_attribute *attr, char *buf)
++{
++	struct usbport_trig_port *port = container_of(attr,
++						      struct usbport_trig_port,
++						      attr);
++
++	return sprintf(buf, "%d\n", port->observed) + 1;
++}
++
++static ssize_t usbport_trig_port_store(struct device *dev,
++				       struct device_attribute *attr,
++				       const char *buf, size_t size)
++{
++	struct usbport_trig_port *port = container_of(attr,
++						      struct usbport_trig_port,
++						      attr);
++
++	if (!strcmp(buf, "0") || !strcmp(buf, "0\n"))
++		port->observed = 0;
++	else if (!strcmp(buf, "1") || !strcmp(buf, "1\n"))
++		port->observed = 1;
++	else
++		return -EINVAL;
++
++	usbport_trig_update_count(port->data);
++
++	return size;
++}
++
++static struct attribute *ports_attrs[] = {
++	NULL,
++};
++static const struct attribute_group ports_group = {
++	.name = "ports",
++	.attrs = ports_attrs,
++};
++
++/***************************************
++ * Adding & removing ports
++ ***************************************/
++
++static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,
++				 struct usb_device *usb_dev,
++				 const char *hub_name, int portnum)
++{
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++	struct usbport_trig_port *port;
++	size_t len;
++	int err;
++
++	port = kzalloc(sizeof(*port), GFP_KERNEL);
++	if (!port) {
++		err = -ENOMEM;
++		goto err_out;
++	}
++
++	port->data = usbport_data;
++	port->hub = usb_dev;
++	port->portnum = portnum;
++
++	len = strlen(hub_name) + 8;
++	port->port_name = kzalloc(len, GFP_KERNEL);
++	if (!port->port_name) {
++		err = -ENOMEM;
++		goto err_free_port;
++	}
++	snprintf(port->port_name, len, "%s-port%d", hub_name, portnum);
++
++	port->attr.attr.name = port->port_name;
++	port->attr.attr.mode = S_IRUSR | S_IWUSR;
++	port->attr.show = usbport_trig_port_show;
++	port->attr.store = usbport_trig_port_store;
++
++	err = sysfs_add_file_to_group(&led_cdev->dev->kobj, &port->attr.attr,
++				      ports_group.name);
++	if (err)
++		goto err_free_port_name;
++
++	list_add_tail(&port->list, &usbport_data->ports);
++
++	return 0;
++
++err_free_port_name:
++	kfree(port->port_name);
++err_free_port:
++	kfree(port);
++err_out:
++	return err;
++}
++
++static int usbport_trig_add_usb_dev_ports(struct usb_device *usb_dev,
++					  void *data)
++{
++	struct usbport_trig_data *usbport_data = data;
++	int i;
++
++	for (i = 1; i <= usb_dev->maxchild; i++)
++		usbport_trig_add_port(usbport_data, usb_dev,
++				      dev_name(&usb_dev->dev), i);
++
++	return 0;
++}
++
++static void usbport_trig_remove_port(struct usbport_trig_data *usbport_data,
++				     struct usbport_trig_port *port)
++{
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++
++	list_del(&port->list);
++	sysfs_remove_file_from_group(&led_cdev->dev->kobj, &port->attr.attr,
++				     ports_group.name);
++	kfree(port->port_name);
++	kfree(port);
++}
++
++static void usbport_trig_remove_usb_dev_ports(struct usbport_trig_data *usbport_data,
++					      struct usb_device *usb_dev)
++{
++	struct usbport_trig_port *port, *tmp;
++
++	list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
++		if (port->hub == usb_dev)
++			usbport_trig_remove_port(usbport_data, port);
++	}
++}
++
++/***************************************
++ * Init, exit, etc.
++ ***************************************/
++
++static int usbport_trig_notify(struct notifier_block *nb, unsigned long action,
++			       void *data)
++{
++	struct usbport_trig_data *usbport_data =
++		container_of(nb, struct usbport_trig_data, nb);
++	struct led_classdev *led_cdev = usbport_data->led_cdev;
++	struct usb_device *usb_dev = data;
++	bool observed;
++
++	observed = usbport_trig_usb_dev_observed(usbport_data, usb_dev);
++
++	switch (action) {
++	case USB_DEVICE_ADD:
++		usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
++		if (observed && usbport_data->count++ == 0)
++			led_cdev->brightness_set(led_cdev, LED_FULL);
++		return NOTIFY_OK;
++	case USB_DEVICE_REMOVE:
++		usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
++		if (observed && --usbport_data->count == 0)
++			led_cdev->brightness_set(led_cdev, LED_OFF);
++		return NOTIFY_OK;
++	}
++
++	return NOTIFY_DONE;
++}
++
++static void usbport_trig_activate(struct led_classdev *led_cdev)
++{
++	struct usbport_trig_data *usbport_data;
++	int err;
++
++	usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL);
++	if (!usbport_data)
++		return;
++	usbport_data->led_cdev = led_cdev;
++
++	/* List of ports */
++	INIT_LIST_HEAD(&usbport_data->ports);
++	err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group);
++	if (err)
++		goto err_free;
++	usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
++
++	/* Notifications */
++	usbport_data->nb.notifier_call = usbport_trig_notify,
++	led_cdev->trigger_data = usbport_data;
++	usb_register_notify(&usbport_data->nb);
++
++	led_cdev->activated = true;
++	return;
++
++err_free:
++	kfree(usbport_data);
++}
++
++static void usbport_trig_deactivate(struct led_classdev *led_cdev)
++{
++	struct usbport_trig_data *usbport_data = led_cdev->trigger_data;
++	struct usbport_trig_port *port, *tmp;
++
++	if (!led_cdev->activated)
++		return;
++
++	list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
++		usbport_trig_remove_port(usbport_data, port);
++	}
++
++	usb_unregister_notify(&usbport_data->nb);
++
++	sysfs_remove_group(&led_cdev->dev->kobj, &ports_group);
++
++	kfree(usbport_data);
++
++	led_cdev->activated = false;
++}
++
++static struct led_trigger usbport_led_trigger = {
++	.name     = "usbport",
++	.activate = usbport_trig_activate,
++	.deactivate = usbport_trig_deactivate,
++};
++
++static int __init usbport_trig_init(void)
++{
++	return led_trigger_register(&usbport_led_trigger);
++}
++
++static void __exit usbport_trig_exit(void)
++{
++	led_trigger_unregister(&usbport_led_trigger);
++}
++
++module_init(usbport_trig_init);
++module_exit(usbport_trig_exit);
++
++MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>");
++MODULE_DESCRIPTION("USB port trigger");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/generic/patches-4.4/084-0002-usb-core-usbport-Use-proper-LED-API-to-fix-potential.patch b/target/linux/generic/patches-4.4/084-0002-usb-core-usbport-Use-proper-LED-API-to-fix-potential.patch
new file mode 100644
index 0000000000..ec41a2dc21
--- /dev/null
+++ b/target/linux/generic/patches-4.4/084-0002-usb-core-usbport-Use-proper-LED-API-to-fix-potential.patch
@@ -0,0 +1,70 @@
+From 89778ba335e302a450932ce5b703c1ee6216e949 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 6 Dec 2016 00:39:33 +0100
+Subject: [PATCH] usb: core: usbport: Use proper LED API to fix potential crash
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Calling brightness_set manually isn't safe as some LED drivers don't
+implement this callback. The best idea is to just use a proper helper
+which will fallback to the brightness_set_blocking callback if needed.
+
+This fixes:
+[ 1461.761528] Unable to handle kernel NULL pointer dereference at virtual address 00000000
+(...)
+[ 1462.117049] Backtrace:
+[ 1462.119521] [<bf228164>] (usbport_trig_port_store [ledtrig_usbport]) from [<c023f758>] (dev_attr_store+0x20/0x2c)
+[ 1462.129826]  r7:dcabc7c0 r6:dee0ff80 r5:00000002 r4:bf228164
+[ 1462.135511] [<c023f738>] (dev_attr_store) from [<c0169310>] (sysfs_kf_write+0x48/0x4c)
+[ 1462.143459]  r5:00000002 r4:c023f738
+[ 1462.147049] [<c01692c8>] (sysfs_kf_write) from [<c0168ab8>] (kernfs_fop_write+0xf8/0x1f8)
+[ 1462.155258]  r5:00000002 r4:df4a1000
+[ 1462.158850] [<c01689c0>] (kernfs_fop_write) from [<c0100c78>] (__vfs_write+0x34/0x120)
+[ 1462.166800]  r10:00000000 r9:dee0e000 r8:c000fc24 r7:00000002 r6:dee0ff80 r5:c01689c0
+[ 1462.174660]  r4:df727a80
+[ 1462.177204] [<c0100c44>] (__vfs_write) from [<c0101ae4>] (vfs_write+0xac/0x170)
+[ 1462.184543]  r9:dee0e000 r8:c000fc24 r7:dee0ff80 r6:b6f092d0 r5:df727a80 r4:00000002
+[ 1462.192319] [<c0101a38>] (vfs_write) from [<c01028dc>] (SyS_write+0x4c/0xa8)
+[ 1462.199396]  r9:dee0e000 r8:c000fc24 r7:00000002 r6:b6f092d0 r5:df727a80 r4:df727a80
+[ 1462.207174] [<c0102890>] (SyS_write) from [<c000fa60>] (ret_fast_syscall+0x0/0x3c)
+[ 1462.214774]  r7:00000004 r6:ffffffff r5:00000000 r4:00000000
+[ 1462.220456] Code: bad PC value
+[ 1462.223560] ---[ end trace 676638a3a12c7a56 ]---
+
+Reported-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Fixes: 0f247626cbb ("usb: core: Introduce a USB port LED trigger")
+Cc: stable@vger.kernel.org # 4.9+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/core/ledtrig-usbport.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/core/ledtrig-usbport.c
++++ b/drivers/usb/core/ledtrig-usbport.c
+@@ -74,8 +74,7 @@ static void usbport_trig_update_count(st
+ 
+ 	usbport_data->count = 0;
+ 	usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check);
+-	led_cdev->brightness_set(led_cdev,
+-				 usbport_data->count ? LED_FULL : LED_OFF);
++	led_set_brightness(led_cdev, usbport_data->count ? LED_FULL : LED_OFF);
+ }
+ 
+ /***************************************
+@@ -228,12 +227,12 @@ static int usbport_trig_notify(struct no
+ 	case USB_DEVICE_ADD:
+ 		usbport_trig_add_usb_dev_ports(usb_dev, usbport_data);
+ 		if (observed && usbport_data->count++ == 0)
+-			led_cdev->brightness_set(led_cdev, LED_FULL);
++			led_set_brightness(led_cdev, LED_FULL);
+ 		return NOTIFY_OK;
+ 	case USB_DEVICE_REMOVE:
+ 		usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev);
+ 		if (observed && --usbport_data->count == 0)
+-			led_cdev->brightness_set(led_cdev, LED_OFF);
++			led_set_brightness(led_cdev, LED_OFF);
+ 		return NOTIFY_OK;
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.4/085-0001-leds-leds-gpio-Set-of_node-for-created-LED-devices.patch b/target/linux/generic/patches-4.4/085-0001-leds-leds-gpio-Set-of_node-for-created-LED-devices.patch
new file mode 100644
index 0000000000..f60b1fc16b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/085-0001-leds-leds-gpio-Set-of_node-for-created-LED-devices.patch
@@ -0,0 +1,53 @@
+From bff23714bc36a1322d0f14519022df0d1a4b21f3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 8 Jul 2016 14:53:38 +0200
+Subject: [PATCH] leds: leds-gpio: Set of_node for created LED devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When working with Device Tree we iterate over children of "gpio-leds"
+compatible node and create LED device for each of them. We take care of
+all common DT properties (label, default trigger, state, etc.), however
+some triggers may want to support more of them.
+
+It could be useful for timer trigger to support setting delay on/off
+values with Device Tree property. Or for transient trigger to support
+e.g. duration property.
+
+We obviously should handle such properties in triggers, not in generic
+code. To let trigger drivers read properties from DT node we need to set
+of_node to point the relevant node. This change allows using all kind of
+of helpers in e.g. "activate" callbacks.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
+---
+ drivers/leds/leds-gpio.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/leds/leds-gpio.c
++++ b/drivers/leds/leds-gpio.c
+@@ -182,6 +182,7 @@ static struct gpio_leds_priv *gpio_leds_
+ 		return ERR_PTR(-ENOMEM);
+ 
+ 	device_for_each_child_node(dev, child) {
++		struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
+ 		struct gpio_led led = {};
+ 		const char *state = NULL;
+ 
+@@ -220,12 +221,12 @@ static struct gpio_leds_priv *gpio_leds_
+ 		if (fwnode_property_present(child, "retain-state-suspended"))
+ 			led.retain_state_suspended = 1;
+ 
+-		ret = create_gpio_led(&led, &priv->leds[priv->num_leds],
+-				      dev, NULL);
++		ret = create_gpio_led(&led, led_dat, dev, NULL);
+ 		if (ret < 0) {
+ 			fwnode_handle_put(child);
+ 			goto err;
+ 		}
++		led_dat->cdev.dev->of_node = np;
+ 		priv->num_leds++;
+ 	}
+ 
diff --git a/target/linux/generic/patches-4.4/090-MIPS-c-r4k-Use-IPI-calls-for-CM-indexed-cache-ops.patch b/target/linux/generic/patches-4.4/090-MIPS-c-r4k-Use-IPI-calls-for-CM-indexed-cache-ops.patch
new file mode 100644
index 0000000000..0c1c0a4509
--- /dev/null
+++ b/target/linux/generic/patches-4.4/090-MIPS-c-r4k-Use-IPI-calls-for-CM-indexed-cache-ops.patch
@@ -0,0 +1,317 @@
+From: James Hogan <james.hogan@imgtec.com>
+Date: Mon, 25 Jan 2016 21:30:00 +0000
+Subject: [PATCH] MIPS: c-r4k: Use IPI calls for CM indexed cache ops
+
+The Coherence Manager (CM) can propagate address-based ("hit") cache
+operations to other cores in the coherent system, alleviating software
+of the need to use IPI calls, however indexed cache operations are not
+propagated since doing so makes no sense for separate caches.
+
+r4k_on_each_cpu() previously had a special case for CONFIG_MIPS_MT_SMP,
+intended to avoid the IPIs when the only other CPUs in the system were
+other VPEs in the same core, and hence sharing the same caches. This was
+changed by commit cccf34e9411c ("MIPS: c-r4k: Fix cache flushing for MT
+cores") to apparently handle multi-core multi-VPE systems, but it
+focussed mainly on hit cache ops, so the IPI calls were still disabled
+entirely for CM systems.
+
+This doesn't normally cause problems, but tests can be written to hit
+these corner cases by using multiple threads, or changing task
+affinities to force the process to migrate cores. For example the
+failure of mprotect RW->RX to globally sync icaches (via
+flush_cache_range) can be detected by modifying and mprotecting a code
+page on one core, and migrating to a different core to execute from it.
+
+Most of the functions called by r4k_on_each_cpu() perform cache
+operations exclusively with a single addressing-type (virtual address vs
+indexed), so add a type argument and modify the callers to pass in
+R4K_USER (user virtual addressing), R4K_KERN (global kernel virtual
+addressing) or R4K_INDEX (index into cache).
+
+local_r4k_flush_icache_range() is split up, to allow it to be called
+from the rest of the kernel, or from r4k_flush_icache_range() where it
+will choose either indexed or hit cache operations based on the size of
+the range and the cache sizes.
+
+local_r4k_flush_kernel_vmap_range() is split into two functions, each of
+which uses cache operations with a single addressing-type, with
+r4k_flush_kernel_vmap_range() making the decision whether to use indexed
+cache ops or not.
+
+Signed-off-by: James Hogan <james.hogan@imgtec.com>
+Cc: Ralf Baechle <ralf@linux-mips.org>
+Cc: Paul Burton <paul.burton@imgtec.com>
+Cc: Leonid Yegoshin <leonid.yegoshin@imgtec.com>
+Cc: linux-mips@linux-mips.org
+---
+
+--- a/arch/mips/mm/c-r4k.c
++++ b/arch/mips/mm/c-r4k.c
+@@ -40,6 +40,50 @@
+ #include <asm/mips-cm.h>
+ 
+ /*
++ * Bits describing what cache ops an IPI callback function may perform.
++ *
++ * R4K_USER   -	Virtual user address based cache operations.
++ *		Ineffective on other CPUs.
++ * R4K_KERN   -	Virtual kernel address based cache operations (including kmap).
++ *		Effective on other CPUs.
++ * R4K_INDEX -	Index based cache operations.
++ *		Effective on other CPUs.
++ */
++
++#define R4K_USER	BIT(0)
++#define R4K_KERN	BIT(1)
++#define R4K_INDEX	BIT(2)
++
++#ifdef CONFIG_SMP
++/* The Coherence manager propagates address-based cache ops to other cores */
++#define r4k_hit_globalized	mips_cm_present()
++#define r4k_index_globalized	0
++#else
++/* If there's only 1 CPU, then all cache ops are globalized to that 1 CPU */
++#define r4k_hit_globalized	1
++#define r4k_index_globalized	1
++#endif
++
++/**
++ * r4k_op_needs_ipi() - Decide if a cache op needs to be done on every core.
++ * @type:	Type of cache operations (R4K_USER, R4K_KERN or R4K_INDEX).
++ *
++ * Returns:	1 if the cache operation @type should be done on every core in
++ *		the system.
++ *		0 if the cache operation @type is globalized and only needs to
++ *		be performed on a simple CPU.
++ */
++static inline bool r4k_op_needs_ipi(unsigned int type)
++{
++	/*
++	 * If hardware doesn't globalize the required cache ops we must use IPIs
++	 * to do so.
++	 */
++	return (type & R4K_KERN  && !r4k_hit_globalized) ||
++	       (type & R4K_INDEX && !r4k_index_globalized);
++}
++
++/*
+  * Special Variant of smp_call_function for use by cache functions:
+  *
+  *  o No return value
+@@ -48,19 +92,11 @@
+  *    primary cache.
+  *  o doesn't disable interrupts on the local CPU
+  */
+-static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
++static inline void r4k_on_each_cpu(unsigned int type,
++				   void (*func) (void *info), void *info)
+ {
+ 	preempt_disable();
+-
+-	/*
+-	 * The Coherent Manager propagates address-based cache ops to other
+-	 * cores but not index-based ops. However, r4k_on_each_cpu is used
+-	 * in both cases so there is no easy way to tell what kind of op is
+-	 * executed to the other cores. The best we can probably do is
+-	 * to restrict that call when a CM is not present because both
+-	 * CM-based SMP protocols (CMP & CPS) restrict index-based cache ops.
+-	 */
+-	if (!mips_cm_present())
++	if (r4k_op_needs_ipi(type))
+ 		smp_call_function_many(&cpu_foreign_map, func, info, 1);
+ 	func(info);
+ 	preempt_enable();
+@@ -456,7 +492,7 @@ static inline void local_r4k___flush_cac
+ 
+ static void r4k___flush_cache_all(void)
+ {
+-	r4k_on_each_cpu(local_r4k___flush_cache_all, NULL);
++	r4k_on_each_cpu(R4K_INDEX, local_r4k___flush_cache_all, NULL);
+ }
+ 
+ static inline int has_valid_asid(const struct mm_struct *mm)
+@@ -503,7 +539,7 @@ static void r4k_flush_cache_range(struct
+ 	int exec = vma->vm_flags & VM_EXEC;
+ 
+ 	if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
+-		r4k_on_each_cpu(local_r4k_flush_cache_range, vma);
++		r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_range, vma);
+ }
+ 
+ static inline void local_r4k_flush_cache_mm(void * args)
+@@ -535,7 +571,7 @@ static void r4k_flush_cache_mm(struct mm
+ 	if (!cpu_has_dc_aliases)
+ 		return;
+ 
+-	r4k_on_each_cpu(local_r4k_flush_cache_mm, mm);
++	r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_mm, mm);
+ }
+ 
+ struct flush_cache_page_args {
+@@ -629,7 +665,7 @@ static void r4k_flush_cache_page(struct
+ 	args.addr = addr;
+ 	args.pfn = pfn;
+ 
+-	r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
++	r4k_on_each_cpu(R4K_KERN, local_r4k_flush_cache_page, &args);
+ }
+ 
+ static inline void local_r4k_flush_data_cache_page(void * addr)
+@@ -642,18 +678,23 @@ static void r4k_flush_data_cache_page(un
+ 	if (in_atomic())
+ 		local_r4k_flush_data_cache_page((void *)addr);
+ 	else
+-		r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr);
++		r4k_on_each_cpu(R4K_KERN, local_r4k_flush_data_cache_page,
++				(void *) addr);
+ }
+ 
+ struct flush_icache_range_args {
+ 	unsigned long start;
+ 	unsigned long end;
++	unsigned int type;
+ };
+ 
+-static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end)
++static inline void __local_r4k_flush_icache_range(unsigned long start,
++						  unsigned long end,
++						  unsigned int type)
+ {
+ 	if (!cpu_has_ic_fills_f_dc) {
+-		if (end - start >= dcache_size) {
++		if (type == R4K_INDEX ||
++		    (type & R4K_INDEX && end - start >= dcache_size)) {
+ 			r4k_blast_dcache();
+ 		} else {
+ 			R4600_HIT_CACHEOP_WAR_IMPL;
+@@ -661,7 +702,8 @@ static inline void local_r4k_flush_icach
+ 		}
+ 	}
+ 
+-	if (end - start > icache_size)
++	if (type == R4K_INDEX ||
++	    (type & R4K_INDEX && end - start > icache_size))
+ 		r4k_blast_icache();
+ 	else {
+ 		switch (boot_cpu_type()) {
+@@ -687,23 +729,59 @@ static inline void local_r4k_flush_icach
+ #endif
+ }
+ 
++static inline void local_r4k_flush_icache_range(unsigned long start,
++						unsigned long end)
++{
++	__local_r4k_flush_icache_range(start, end, R4K_KERN | R4K_INDEX);
++}
++
+ static inline void local_r4k_flush_icache_range_ipi(void *args)
+ {
+ 	struct flush_icache_range_args *fir_args = args;
+ 	unsigned long start = fir_args->start;
+ 	unsigned long end = fir_args->end;
++	unsigned int type = fir_args->type;
+ 
+-	local_r4k_flush_icache_range(start, end);
++	__local_r4k_flush_icache_range(start, end, type);
+ }
+ 
+ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
+ {
+ 	struct flush_icache_range_args args;
++	unsigned long size, cache_size;
+ 
+ 	args.start = start;
+ 	args.end = end;
++	args.type = R4K_KERN | R4K_INDEX;
+ 
+-	r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args);
++	if (in_atomic()) {
++		/*
++		 * We can't do blocking IPI calls from atomic context, so fall
++		 * back to pure address-based cache ops if they globalize.
++		 */
++		if (!r4k_index_globalized && r4k_hit_globalized) {
++			args.type &= ~R4K_INDEX;
++		} else {
++			/* Just do it locally instead. */
++			local_r4k_flush_icache_range(start, end);
++			instruction_hazard();
++			return;
++		}
++	} else if (!r4k_index_globalized && r4k_hit_globalized) {
++		/*
++		 * If address-based cache ops are globalized, then we may be
++		 * able to avoid the IPI for small flushes.
++		 */
++		size = start - end;
++		cache_size = icache_size;
++		if (!cpu_has_ic_fills_f_dc) {
++			size *= 2;
++			cache_size += dcache_size;
++		}
++		if (size <= cache_size)
++			args.type &= ~R4K_INDEX;
++	}
++	r4k_on_each_cpu(args.type, local_r4k_flush_icache_range_ipi, &args);
+ 	instruction_hazard();
+ }
+ 
+@@ -823,7 +901,12 @@ static void local_r4k_flush_cache_sigtra
+ 
+ static void r4k_flush_cache_sigtramp(unsigned long addr)
+ {
+-	r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr);
++	/*
++	 * FIXME this is a bit broken when !r4k_hit_globalized, since the user
++	 * code probably won't be mapped on other CPUs, so if the process is
++	 * migrated, it could end up hitting stale icache lines.
++	 */
++	r4k_on_each_cpu(R4K_USER, local_r4k_flush_cache_sigtramp, (void *)addr);
+ }
+ 
+ static void r4k_flush_icache_all(void)
+@@ -837,6 +920,15 @@ struct flush_kernel_vmap_range_args {
+ 	int		size;
+ };
+ 
++static inline void local_r4k_flush_kernel_vmap_range_index(void *args)
++{
++	/*
++	 * Aliases only affect the primary caches so don't bother with
++	 * S-caches or T-caches.
++	 */
++	r4k_blast_dcache();
++}
++
+ static inline void local_r4k_flush_kernel_vmap_range(void *args)
+ {
+ 	struct flush_kernel_vmap_range_args *vmra = args;
+@@ -847,12 +939,8 @@ static inline void local_r4k_flush_kerne
+ 	 * Aliases only affect the primary caches so don't bother with
+ 	 * S-caches or T-caches.
+ 	 */
+-	if (cpu_has_safe_index_cacheops && size >= dcache_size)
+-		r4k_blast_dcache();
+-	else {
+-		R4600_HIT_CACHEOP_WAR_IMPL;
+-		blast_dcache_range(vaddr, vaddr + size);
+-	}
++	R4600_HIT_CACHEOP_WAR_IMPL;
++	blast_dcache_range(vaddr, vaddr + size);
+ }
+ 
+ static void r4k_flush_kernel_vmap_range(unsigned long vaddr, int size)
+@@ -862,7 +950,12 @@ static void r4k_flush_kernel_vmap_range(
+ 	args.vaddr = (unsigned long) vaddr;
+ 	args.size = size;
+ 
+-	r4k_on_each_cpu(local_r4k_flush_kernel_vmap_range, &args);
++	if (cpu_has_safe_index_cacheops && size >= dcache_size)
++		r4k_on_each_cpu(R4K_INDEX,
++				local_r4k_flush_kernel_vmap_range_index, NULL);
++	else
++		r4k_on_each_cpu(R4K_KERN, local_r4k_flush_kernel_vmap_range,
++				&args);
+ }
+ 
+ static inline void rm7k_erratum31(void)
diff --git a/target/linux/generic/patches-4.4/091-MIPS-c-r4k-Exclude-sibling-CPUs-in-SMP-calls.patch b/target/linux/generic/patches-4.4/091-MIPS-c-r4k-Exclude-sibling-CPUs-in-SMP-calls.patch
new file mode 100644
index 0000000000..8d5030c84b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/091-MIPS-c-r4k-Exclude-sibling-CPUs-in-SMP-calls.patch
@@ -0,0 +1,37 @@
+From: James Hogan <james.hogan@imgtec.com>
+Date: Thu, 3 Mar 2016 21:30:42 +0000
+Subject: [PATCH] MIPS: c-r4k: Exclude sibling CPUs in SMP calls
+
+When performing SMP calls to foreign cores, exclude sibling CPUs from
+the provided map, as we already handle the local core on the current
+CPU. This prevents an IPI call from for example core 0, VPE 1 to VPE 0
+on the same core.
+
+Signed-off-by: James Hogan <james.hogan@imgtec.com>
+Cc: Ralf Baechle <ralf@linux-mips.org>
+Cc: Paul Burton <paul.burton@imgtec.com>
+Cc: linux-mips@linux-mips.org
+---
+
+--- a/arch/mips/mm/c-r4k.c
++++ b/arch/mips/mm/c-r4k.c
+@@ -96,8 +96,17 @@ static inline void r4k_on_each_cpu(unsig
+ 				   void (*func) (void *info), void *info)
+ {
+ 	preempt_disable();
+-	if (r4k_op_needs_ipi(type))
+-		smp_call_function_many(&cpu_foreign_map, func, info, 1);
++	/* cpu_foreign_map and cpu_sibling_map[] undeclared when !CONFIG_SMP */
++#ifdef CONFIG_SMP
++	if (r4k_op_needs_ipi(type)) {
++		struct cpumask mask;
++
++		/* exclude sibling CPUs */
++		cpumask_andnot(&mask, &cpu_foreign_map,
++			       &cpu_sibling_map[smp_processor_id()]);
++		smp_call_function_many(&mask, func, info, 1);
++	}
++#endif
+ 	func(info);
+ 	preempt_enable();
+ }
diff --git a/target/linux/generic/patches-4.4/092-MIPS-ZBOOT-copy-appended-dtb-to-the-end-of-the-kerne.patch b/target/linux/generic/patches-4.4/092-MIPS-ZBOOT-copy-appended-dtb-to-the-end-of-the-kerne.patch
new file mode 100644
index 0000000000..71df42992b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/092-MIPS-ZBOOT-copy-appended-dtb-to-the-end-of-the-kerne.patch
@@ -0,0 +1,132 @@
+From b8f54f2cde788623f41d11327688c75aed34092f Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Mon, 20 Jun 2016 11:27:36 +0200
+Subject: [PATCH 1/2] MIPS: ZBOOT: copy appended dtb to the end of the kernel
+
+Instead of rewriting the arguments, just move the appended dtb to where
+the decompressed kernel expects it. This eliminates the need for special
+casing vmlinuz.bin appended dtb files.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+Cc: Kevin Cernekee <cernekee@gmail.com>
+Cc: Florian Fainelli <f.fainelli@gmail.com>
+Cc: John Crispin <john@phrozen.org>
+Cc: Paul Burton <paul.burton@imgtec.com>
+Cc: James Hogan <james.hogan@imgtec.com>
+Cc: Alban Bedel <albeu@free.fr>
+Cc: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
+Cc: Antony Pavlov <antonynpavlov@gmail.com>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/13698/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/Kconfig                      | 22 ++--------------------
+ arch/mips/boot/compressed/decompress.c | 17 +++++++++++++++++
+ arch/mips/boot/compressed/head.S       | 16 ----------------
+ 3 files changed, 19 insertions(+), 36 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -2752,10 +2752,10 @@ choice
+ 		  the documented boot protocol using a device tree.
+ 
+ 	config MIPS_RAW_APPENDED_DTB
+-		bool "vmlinux.bin"
++		bool "vmlinux.bin or vmlinuz.bin"
+ 		help
+ 		  With this option, the boot code will look for a device tree binary
+-		  DTB) appended to raw vmlinux.bin (without decompressor).
++		  DTB) appended to raw vmlinux.bin or vmlinuz.bin.
+ 		  (e.g. cat vmlinux.bin <filename>.dtb > vmlinux_w_dtb).
+ 
+ 		  This is meant as a backward compatibility convenience for those
+@@ -2767,24 +2767,6 @@ choice
+ 		  look like a DTB header after a reboot if no actual DTB is appended
+ 		  to vmlinux.bin.  Do not leave this option active in a production kernel
+ 		  if you don't intend to always append a DTB.
+-
+-	config MIPS_ZBOOT_APPENDED_DTB
+-		bool "vmlinuz.bin"
+-		depends on SYS_SUPPORTS_ZBOOT
+-		help
+-		  With this option, the boot code will look for a device tree binary
+-		  DTB) appended to raw vmlinuz.bin (with decompressor).
+-		  (e.g. cat vmlinuz.bin <filename>.dtb > vmlinuz_w_dtb).
+-
+-		  This is meant as a backward compatibility convenience for those
+-		  systems with a bootloader that can't be upgraded to accommodate
+-		  the documented boot protocol using a device tree.
+-
+-		  Beware that there is very little in terms of protection against
+-		  this option being confused by leftover garbage in memory that might
+-		  look like a DTB header after a reboot if no actual DTB is appended
+-		  to vmlinuz.bin.  Do not leave this option active in a production kernel
+-		  if you don't intend to always append a DTB.
+ endchoice
+ 
+ choice
+--- a/arch/mips/boot/compressed/decompress.c
++++ b/arch/mips/boot/compressed/decompress.c
+@@ -14,6 +14,7 @@
+ #include <linux/types.h>
+ #include <linux/kernel.h>
+ #include <linux/string.h>
++#include <linux/libfdt.h>
+ 
+ #include <asm/addrspace.h>
+ 
+@@ -36,6 +37,8 @@ extern void puthex(unsigned long long va
+ #define puthex(val) do {} while (0)
+ #endif
+ 
++extern char __appended_dtb[];
++
+ void error(char *x)
+ {
+ 	puts("\n\n");
+@@ -114,6 +117,20 @@ void decompress_kernel(unsigned long boo
+ 	__decompress((char *)zimage_start, zimage_size, 0, 0,
+ 		   (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, 0, error);
+ 
++	if (IS_ENABLED(CONFIG_MIPS_RAW_APPENDED_DTB) &&
++	    fdt_magic((void *)&__appended_dtb) == FDT_MAGIC) {
++		unsigned int image_size, dtb_size;
++
++		dtb_size = fdt_totalsize((void *)&__appended_dtb);
++
++		/* last four bytes is always image size in little endian */
++		image_size = le32_to_cpup((void *)&__image_end - 4);
++
++		/* copy dtb to where the booted kernel will expect it */
++		memcpy((void *)VMLINUX_LOAD_ADDRESS_ULL + image_size,
++		       __appended_dtb, dtb_size);
++	}
++
+ 	/* FIXME: should we flush cache here? */
+ 	puts("Now, booting the kernel...\n");
+ }
+--- a/arch/mips/boot/compressed/head.S
++++ b/arch/mips/boot/compressed/head.S
+@@ -25,22 +25,6 @@ start:
+ 	move	s2, a2
+ 	move	s3, a3
+ 
+-#ifdef CONFIG_MIPS_ZBOOT_APPENDED_DTB
+-	PTR_LA	t0, __appended_dtb
+-#ifdef CONFIG_CPU_BIG_ENDIAN
+-	li	t1, 0xd00dfeed
+-#else
+-	li	t1, 0xedfe0dd0
+-#endif
+-	lw	t2, (t0)
+-	bne	t1, t2, not_found
+-	 nop
+-
+-	move	s1, t0
+-	PTR_LI	s0, -2
+-not_found:
+-#endif
+-
+ 	/* Clear BSS */
+ 	PTR_LA	a0, _edata
+ 	PTR_LA	a2, _end
diff --git a/target/linux/generic/patches-4.4/093-MIPS-store-the-appended-dtb-address-in-a-variable.patch b/target/linux/generic/patches-4.4/093-MIPS-store-the-appended-dtb-address-in-a-variable.patch
new file mode 100644
index 0000000000..764c1cb830
--- /dev/null
+++ b/target/linux/generic/patches-4.4/093-MIPS-store-the-appended-dtb-address-in-a-variable.patch
@@ -0,0 +1,132 @@
+From 15f37e1588920e010f20b53f04af94e91b8ee714 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Mon, 20 Jun 2016 11:27:37 +0200
+Subject: [PATCH] MIPS: store the appended dtb address in a variable
+
+Instead of rewriting the arguments to match the UHI spec, store the
+address of a appended or UHI supplied dtb in fw_supplied_dtb.
+
+That way the original bootloader arugments are kept intact while still
+making the use of an appended dtb invisible for mach code.
+
+Mach code can still find out if it is an appended dtb by comparing
+fw_arg1 with fw_supplied_dtb.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+Cc: Kevin Cernekee <cernekee@gmail.com>
+Cc: Florian Fainelli <f.fainelli@gmail.com>
+Cc: John Crispin <john@phrozen.org>
+Cc: Paul Burton <paul.burton@imgtec.com>
+Cc: James Hogan <james.hogan@imgtec.com>
+Cc: Alban Bedel <albeu@free.fr>
+Cc: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
+Cc: Antony Pavlov <antonynpavlov@gmail.com>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/13699/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/ath79/setup.c          |  4 ++--
+ arch/mips/bmips/setup.c          |  4 ++--
+ arch/mips/include/asm/bootinfo.h |  4 ++++
+ arch/mips/kernel/head.S          | 21 ++++++++++++++-------
+ arch/mips/kernel/setup.c         |  4 ++++
+ arch/mips/lantiq/prom.c          |  4 ++--
+ arch/mips/pic32/pic32mzda/init.c |  4 ++--
+ 7 files changed, 30 insertions(+), 15 deletions(-)
+
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -207,6 +207,8 @@ void __init plat_mem_setup(void)
+ 	fdt_start = fw_getenvl("fdt_start");
+ 	if (fdt_start)
+ 		__dt_setup_arch((void *)KSEG0ADDR(fdt_start));
++	else if (fw_passed_dtb)
++		__dt_setup_arch((void *)KSEG0ADDR(fw_passed_dtb));
+ #ifdef CONFIG_BUILTIN_DTB
+ 	else
+ 		__dt_setup_arch(__dtb_start);
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -149,8 +149,8 @@ void __init plat_mem_setup(void)
+ 	/* intended to somewhat resemble ARM; see Documentation/arm/Booting */
+ 	if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
+ 		dtb = phys_to_virt(fw_arg2);
+-	else if (fw_arg0 == -2) /* UHI interface */
+-		dtb = (void *)fw_arg1;
++	else if (fw_passed_dtb) /* UHI interface */
++		dtb = (void *)fw_passed_dtb;
+ 	else if (__dtb_start != __dtb_end)
+ 		dtb = (void *)__dtb_start;
+ 	else
+--- a/arch/mips/include/asm/bootinfo.h
++++ b/arch/mips/include/asm/bootinfo.h
+@@ -127,6 +127,10 @@ extern char arcs_cmdline[COMMAND_LINE_SI
+  */
+ extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
+ 
++#ifdef CONFIG_USE_OF
++extern unsigned long fw_passed_dtb;
++#endif
++
+ /*
+  * Platform memory detection hook called by setup_arch
+  */
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -94,21 +94,24 @@ NESTED(kernel_entry, 16, sp)			# kernel
+ 	jr	t0
+ 0:
+ 
++#ifdef CONFIG_USE_OF
+ #ifdef CONFIG_MIPS_RAW_APPENDED_DTB
+-	PTR_LA		t0, __appended_dtb
++	PTR_LA		t2, __appended_dtb
+ 
+ #ifdef CONFIG_CPU_BIG_ENDIAN
+ 	li		t1, 0xd00dfeed
+ #else
+ 	li		t1, 0xedfe0dd0
+ #endif
+-	lw		t2, (t0)
+-	bne		t1, t2, not_found
+-	 nop
+-
+-	move		a1, t0
+-	PTR_LI		a0, -2
+-not_found:
++	lw		t0, (t2)
++	beq		t0, t1, dtb_found
++#endif
++	li		t1, -2
++	beq		a0, t1, dtb_found
++	move		t2, a1
++
++	li		t2, 0
++dtb_found:
+ #endif
+ 	PTR_LA		t0, __bss_start		# clear .bss
+ 	LONG_S		zero, (t0)
+@@ -123,6 +126,10 @@ not_found:
+ 	LONG_S		a2, fw_arg2
+ 	LONG_S		a3, fw_arg3
+ 
++#ifdef CONFIG_USE_OF
++	LONG_S		t2, fw_passed_dtb
++#endif
++
+ 	MTC0		zero, CP0_CONTEXT	# clear context register
+ 	PTR_LA		$28, init_thread_union
+ 	/* Set the SP after an empty pt_regs.  */
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -814,6 +814,10 @@ void __init setup_arch(char **cmdline_p)
+ unsigned long kernelsp[NR_CPUS];
+ unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
+ 
++#ifdef CONFIG_USE_OF
++unsigned long fw_passed_dtb;
++#endif
++
+ #ifdef CONFIG_DEBUG_FS
+ struct dentry *mips_debugfs_dir;
+ static int __init debugfs_mips(void)
diff --git a/target/linux/generic/patches-4.4/096-arc-add-model-property-in-dts.patch b/target/linux/generic/patches-4.4/096-arc-add-model-property-in-dts.patch
new file mode 100644
index 0000000000..85019ed008
--- /dev/null
+++ b/target/linux/generic/patches-4.4/096-arc-add-model-property-in-dts.patch
@@ -0,0 +1,163 @@
+From f1e53ac0a99e3754465bd87ae1a6fdbfb8340d15 Mon Sep 17 00:00:00 2001
+From: Alexey Brodkin <abrodkin@synopsys.com>
+Date: Mon, 15 Aug 2016 14:42:44 +0300
+Subject: [PATCH] arc: Add "model" properly in device tree description of all
+ boards
+
+As it was discussed quite some time ago (see
+https://lkml.org/lkml/2015/11/5/862) it's a good practice to add
+"model" property in .dts. Moreover as per ePAPR "model" property is
+required and should look like "manufacturer,model" so we do here.
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+Cc: Vineet Gupta <vgupta@synopsys.com>
+Cc: Jonas Gorski <jonas.gorski@gmail.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Rob Herring <robh@kernel.org>
+Cc: Christian Ruppert <christian.ruppert@alitech.com>
+---
+ arch/arc/boot/dts/abilis_tb100_dvk.dts | 1 +
+ arch/arc/boot/dts/abilis_tb101_dvk.dts | 1 +
+ arch/arc/boot/dts/axs101.dts           | 1 +
+ arch/arc/boot/dts/axs103.dts           | 1 +
+ arch/arc/boot/dts/axs103_idu.dts       | 1 +
+ arch/arc/boot/dts/nsim_700.dts         | 1 +
+ arch/arc/boot/dts/nsim_hs.dts          | 1 +
+ arch/arc/boot/dts/nsim_hs_idu.dts      | 1 +
+ arch/arc/boot/dts/nsimosci.dts         | 1 +
+ arch/arc/boot/dts/nsimosci_hs.dts      | 1 +
+ arch/arc/boot/dts/nsimosci_hs_idu.dts  | 1 +
+ arch/arc/boot/dts/vdk_hs38.dts         | 1 +
+ arch/arc/boot/dts/vdk_hs38_smp.dts     | 1 +
+ 13 files changed, 13 insertions(+)
+
+--- a/arch/arc/boot/dts/abilis_tb100_dvk.dts
++++ b/arch/arc/boot/dts/abilis_tb100_dvk.dts
+@@ -24,6 +24,7 @@
+ /include/ "abilis_tb100.dtsi"
+ 
+ / {
++	model = "abilis,tb100";
+ 	chosen {
+ 		bootargs = "earlycon=uart8250,mmio32,0xff100000,9600n8 console=ttyS0,9600n8";
+ 	};
+--- a/arch/arc/boot/dts/abilis_tb101_dvk.dts
++++ b/arch/arc/boot/dts/abilis_tb101_dvk.dts
+@@ -24,6 +24,7 @@
+ /include/ "abilis_tb101.dtsi"
+ 
+ / {
++	model = "abilis,tb101";
+ 	chosen {
+ 		bootargs = "earlycon=uart8250,mmio32,0xff100000,9600n8 console=ttyS0,9600n8";
+ 	};
+--- a/arch/arc/boot/dts/axs101.dts
++++ b/arch/arc/boot/dts/axs101.dts
+@@ -13,6 +13,7 @@
+ /include/ "axs10x_mb.dtsi"
+ 
+ / {
++	model = "snps,axs101";
+ 	compatible = "snps,axs101", "snps,arc-sdp";
+ 
+ 	chosen {
+--- a/arch/arc/boot/dts/axs103.dts
++++ b/arch/arc/boot/dts/axs103.dts
+@@ -16,6 +16,7 @@
+ /include/ "axs10x_mb.dtsi"
+ 
+ / {
++	model = "snps,axs103";
+ 	compatible = "snps,axs103", "snps,arc-sdp";
+ 
+ 	chosen {
+--- a/arch/arc/boot/dts/axs103_idu.dts
++++ b/arch/arc/boot/dts/axs103_idu.dts
+@@ -16,6 +16,7 @@
+ /include/ "axs10x_mb.dtsi"
+ 
+ / {
++	model = "snps,axs103-smp";
+ 	compatible = "snps,axs103", "snps,arc-sdp";
+ 
+ 	chosen {
+--- a/arch/arc/boot/dts/nsim_700.dts
++++ b/arch/arc/boot/dts/nsim_700.dts
+@@ -10,6 +10,7 @@
+ /include/ "skeleton.dtsi"
+ 
+ / {
++	model = "snps,nsim";
+ 	compatible = "snps,nsim";
+ 	clock-frequency = <80000000>;	/* 80 MHZ */
+ 	#address-cells = <1>;
+--- a/arch/arc/boot/dts/nsim_hs.dts
++++ b/arch/arc/boot/dts/nsim_hs.dts
+@@ -10,6 +10,7 @@
+ /include/ "skeleton.dtsi"
+ 
+ / {
++	model = "snps,nsim_hs";
+ 	compatible = "snps,nsim_hs";
+ 	#address-cells = <2>;
+ 	#size-cells = <2>;
+--- a/arch/arc/boot/dts/nsim_hs_idu.dts
++++ b/arch/arc/boot/dts/nsim_hs_idu.dts
+@@ -10,6 +10,7 @@
+ /include/ "skeleton.dtsi"
+ 
+ / {
++	model = "snps,nsim_hs-smp";
+ 	compatible = "snps,nsim_hs";
+ 	interrupt-parent = <&core_intc>;
+ 
+--- a/arch/arc/boot/dts/nsimosci.dts
++++ b/arch/arc/boot/dts/nsimosci.dts
+@@ -10,6 +10,7 @@
+ /include/ "skeleton.dtsi"
+ 
+ / {
++	model = "snps,nsimosci";
+ 	compatible = "snps,nsimosci";
+ 	clock-frequency = <20000000>;	/* 20 MHZ */
+ 	#address-cells = <1>;
+--- a/arch/arc/boot/dts/nsimosci_hs.dts
++++ b/arch/arc/boot/dts/nsimosci_hs.dts
+@@ -10,6 +10,7 @@
+ /include/ "skeleton.dtsi"
+ 
+ / {
++	model = "snps,nsimosci_hs";
+ 	compatible = "snps,nsimosci_hs";
+ 	clock-frequency = <20000000>;	/* 20 MHZ */
+ 	#address-cells = <1>;
+--- a/arch/arc/boot/dts/nsimosci_hs_idu.dts
++++ b/arch/arc/boot/dts/nsimosci_hs_idu.dts
+@@ -10,6 +10,7 @@
+ /include/ "skeleton.dtsi"
+ 
+ / {
++	model = "snps,nsimosci_hs-smp";
+ 	compatible = "snps,nsimosci_hs";
+ 	clock-frequency = <5000000>;	/* 5 MHZ */
+ 	#address-cells = <1>;
+--- a/arch/arc/boot/dts/vdk_hs38.dts
++++ b/arch/arc/boot/dts/vdk_hs38.dts
+@@ -13,6 +13,7 @@
+ /include/ "vdk_axs10x_mb.dtsi"
+ 
+ / {
++	model = "snps,vdk_archs";
+ 	compatible = "snps,axs103";
+ 
+ 	chosen {
+--- a/arch/arc/boot/dts/vdk_hs38_smp.dts
++++ b/arch/arc/boot/dts/vdk_hs38_smp.dts
+@@ -13,6 +13,7 @@
+ /include/ "vdk_axs10x_mb.dtsi"
+ 
+ / {
++	model = "snps,vdk_archs-smp";
+ 	compatible = "snps,axs103";
+ 
+ 	chosen {
diff --git a/target/linux/generic/patches-4.4/097-MIPS-io.h-Define-ioremap_cache.patch b/target/linux/generic/patches-4.4/097-MIPS-io.h-Define-ioremap_cache.patch
new file mode 100644
index 0000000000..e048410e42
--- /dev/null
+++ b/target/linux/generic/patches-4.4/097-MIPS-io.h-Define-ioremap_cache.patch
@@ -0,0 +1,29 @@
+From a68f376844605399cbd28b662d5ed213639f46f7 Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@imgtec.com>
+Date: Sat, 9 Jan 2016 02:05:31 +0000
+Subject: [PATCH] MIPS: io.h: Define `ioremap_cache'
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
+Cc: Brian Norris <computersforpeace@gmail.com>
+Cc: Rafał Miłecki <zajec5@gmail.com>
+Cc: linux-mips@linux-mips.org
+Cc: linux-kernel@vger.kernel.org
+Patchwork: https://patchwork.linux-mips.org/patch/12040/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/include/asm/io.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/mips/include/asm/io.h
++++ b/arch/mips/include/asm/io.h
+@@ -275,6 +275,7 @@ static inline void __iomem * __ioremap_m
+  */
+ #define ioremap_cachable(offset, size)					\
+ 	__ioremap_mode((offset), (size), _page_cachable_default)
++#define ioremap_cache ioremap_cachable
+ 
+ /*
+  * These two are MIPS specific ioremap variant.	 ioremap_cacheable_cow
diff --git a/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch b/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
new file mode 100644
index 0000000000..e4ac2cd583
--- /dev/null
+++ b/target/linux/generic/patches-4.4/101-MIPS-fix-cache-flushing-for-highmem-pages.patch
@@ -0,0 +1,31 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 24 Jan 2016 01:03:51 +0100
+Subject: [PATCH] MIPS: fix cache flushing for highmem pages
+
+Most cache flush ops were no-op for highmem pages. This led to nasty
+segfaults and (in the case of page_address(page) == NULL) kernel
+crashes.
+
+Fix this by always flushing highmem pages using kmap/kunmap_atomic
+around the actual cache flush. This might be a bit inefficient, but at
+least it's stable.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/mm/cache.c
++++ b/arch/mips/mm/cache.c
+@@ -111,6 +111,13 @@ void __flush_anon_page(struct page *page
+ {
+ 	unsigned long addr = (unsigned long) page_address(page);
+ 
++	if (PageHighMem(page)) {
++		addr = (unsigned long)kmap_atomic(page);
++		flush_data_cache_page(addr);
++		__kunmap_atomic((void *)addr);
++		return;
++	}
++
+ 	if (pages_do_alias(addr, vmaddr)) {
+ 		if (page_mapped(page) && !Page_dcache_dirty(page)) {
+ 			void *kaddr;
diff --git a/target/linux/generic/patches-4.4/102-ehci_hcd_ignore_oc.patch b/target/linux/generic/patches-4.4/102-ehci_hcd_ignore_oc.patch
new file mode 100644
index 0000000000..71e3a74ad5
--- /dev/null
+++ b/target/linux/generic/patches-4.4/102-ehci_hcd_ignore_oc.patch
@@ -0,0 +1,82 @@
+From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <florian@openwrt.org>
+Date: Mon, 28 Jan 2013 20:06:29 +0100
+Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent
+ checking
+
+This patch adds an ignore_oc flag which can be set by EHCI controller
+not supporting or wanting to disable overcurrent checking. The EHCI
+platform data in include/linux/usb/ehci_pdriver.h is also augmented to
+take advantage of this new flag.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ drivers/usb/host/ehci-hcd.c      |    2 +-
+ drivers/usb/host/ehci-hub.c      |    4 ++--
+ drivers/usb/host/ehci-platform.c |    1 +
+ drivers/usb/host/ehci.h          |    1 +
+ include/linux/usb/ehci_pdriver.h |    1 +
+ 5 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -639,7 +639,7 @@ static int ehci_run (struct usb_hcd *hcd
+ 		"USB %x.%x started, EHCI %x.%02x%s\n",
+ 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
+ 		temp >> 8, temp & 0xff,
+-		ignore_oc ? ", overcurrent ignored" : "");
++		(ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
+ 
+ 	ehci_writel(ehci, INTR_MASK,
+ 		    &ehci->regs->intr_enable); /* Turn On Interrupts */
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -634,7 +634,7 @@ ehci_hub_status_data (struct usb_hcd *hc
+ 	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
+ 	 * PORT_POWER; that's surprising, but maybe within-spec.
+ 	 */
+-	if (!ignore_oc)
++	if (!ignore_oc && !ehci->ignore_oc)
+ 		mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ 	else
+ 		mask = PORT_CSC | PORT_PEC;
+@@ -996,7 +996,7 @@ int ehci_hub_control(
+ 		if (temp & PORT_PEC)
+ 			status |= USB_PORT_STAT_C_ENABLE << 16;
+ 
+-		if ((temp & PORT_OCC) && !ignore_oc){
++		if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
+ 			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ 
+ 			/*
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -254,6 +254,8 @@ static int ehci_platform_probe(struct pl
+ 		hcd->has_tt = 1;
+ 	if (pdata->reset_on_resume)
+ 		priv->reset_on_resume = true;
++	if (pdata->ignore_oc)
++		ehci->ignore_oc = 1;
+ 
+ #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ 	if (ehci->big_endian_mmio) {
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -227,6 +227,7 @@ struct ehci_hcd {			/* one per controlle
+ 	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
+ 	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
+ 	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
++	unsigned		ignore_oc:1;
+ 
+ 	/* required for usb32 quirk */
+ 	#define OHCI_CTRL_HCFS          (3 << 6)
+--- a/include/linux/usb/ehci_pdriver.h
++++ b/include/linux/usb/ehci_pdriver.h
+@@ -49,6 +49,7 @@ struct usb_ehci_pdata {
+ 	unsigned	no_io_watchdog:1;
+ 	unsigned	reset_on_resume:1;
+ 	unsigned	dma_mask_64:1;
++	unsigned	ignore_oc:1;
+ 
+ 	/* Turn on all power and clocks */
+ 	int (*power_on)(struct platform_device *pdev);
diff --git a/target/linux/generic/patches-4.4/103-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/target/linux/generic/patches-4.4/103-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
new file mode 100644
index 0000000000..b2daa17d9a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/103-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
@@ -0,0 +1,86 @@
+From: Tobias Wolf <dev-NTEO@vplace.de>
+Date: Wed, 30 Nov 2016 09:16:41 +0100
+Subject: [PATCH] mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET
+ calculation
+
+Dear folks,
+
+An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any
+kernel beyond version 4.3 resulting in:
+
+BUG: Bad page state in process swapper  pfn:086ac
+
+bisect resulted in:
+
+a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit
+commit a1c34a3bf00af2cede839879502e12dc68491ad5
+Author: Laura Abbott <laura@labbott.name>
+Date:   Thu Nov 5 18:48:46 2015 -0800
+
+    mm: Don't offset memmap for flatmem
+
+    Srinivas Kandagatla reported bad page messages when trying to remove the
+    bottom 2MB on an ARM based IFC6410 board
+
+      BUG: Bad page state in process swapper  pfn:fffa8
+      page:ef7fb500 count:0 mapcount:0 mapping:  (null) index:0x0
+      flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked)
+      page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
+      bad because of flags:
+      flags: 0x200041(locked|active|mlocked)
+      Modules linked in:
+      CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty
+#816
+      Hardware name: Qualcomm (Flattened Device Tree)
+        unwind_backtrace
+        show_stack
+        dump_stack
+        bad_page
+        free_pages_prepare
+        free_hot_cold_page
+        __free_pages
+        free_highmem_page
+        mem_init
+        start_kernel
+      Disabling lock debugging due to kernel taint
+    [...]
+:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4
+0a8156f848733dfa21e16c196dfb6c0a76290709 M      mm
+
+This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by
+page_to_pfn anymore.
+
+The following output was generated with two hacked in printk statements:
+
+printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map -
+(pgdat->node_start_pfn - ARCH_PFN_OFFSET));
+		if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
+			mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
+printk("after %p\n", mem_map);
+
+Output:
+
+[    0.000000] before 8861b280 vs. 8861b280 or 8851b280
+[    0.000000] after 8851b280
+
+As seen in the first line mem_map with subtraction of offset does not equal the
+mem_map after subtraction of ARCH_PFN_OFFSET.
+
+After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the
+previously calculated offset is zero for the named platform it is able to boot
+4.4 and 4.9-rc7 again.
+
+Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
+---
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -5326,7 +5326,7 @@ static void __init_refok alloc_node_mem_
+ 		mem_map = NODE_DATA(0)->node_mem_map;
+ #if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
+ 		if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
+-			mem_map -= offset;
++			mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
+ #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
+ 	}
+ #endif
diff --git a/target/linux/generic/patches-4.4/104-of-Add-check-to-of_scan_flat_dt-before-accessing-ini.patch b/target/linux/generic/patches-4.4/104-of-Add-check-to-of_scan_flat_dt-before-accessing-ini.patch
new file mode 100644
index 0000000000..e7c125d8ec
--- /dev/null
+++ b/target/linux/generic/patches-4.4/104-of-Add-check-to-of_scan_flat_dt-before-accessing-ini.patch
@@ -0,0 +1,30 @@
+From: Tobias Wolf <dev-NTEO@vplace.de>
+Date: Wed, 23 Nov 2016 10:40:07 +0100
+Subject: [PATCH] of: Add check to of_scan_flat_dt() before accessing
+ initial_boot_params
+
+An empty __dtb_start to __dtb_end section might result in initial_boot_params
+being null for arch/mips/ralink. This showed that the boot process hangs
+indefinitely in of_scan_flat_dt().
+
+Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
+---
+
+--- a/drivers/of/fdt.c
++++ b/drivers/of/fdt.c
+@@ -632,9 +632,12 @@ int __init of_scan_flat_dt(int (*it)(uns
+ 	const char *pathp;
+ 	int offset, rc = 0, depth = -1;
+ 
+-        for (offset = fdt_next_node(blob, -1, &depth);
+-             offset >= 0 && depth >= 0 && !rc;
+-             offset = fdt_next_node(blob, offset, &depth)) {
++	if (!blob)
++		return 0;
++
++	for (offset = fdt_next_node(blob, -1, &depth);
++	     offset >= 0 && depth >= 0 && !rc;
++	     offset = fdt_next_node(blob, offset, &depth)) {
+ 
+ 		pathp = fdt_get_name(blob, offset, NULL);
+ 		if (*pathp == '/')
diff --git a/target/linux/generic/patches-4.4/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-4.4/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
new file mode 100644
index 0000000000..b7ff845343
--- /dev/null
+++ b/target/linux/generic/patches-4.4/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
@@ -0,0 +1,86 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 10 Apr 2015 13:35:29 +0200
+Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support
+
+It is required for renames on overlayfs
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s
+ static int jffs2_rmdir (struct inode *,struct dentry *);
+ static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
+ static int jffs2_rename (struct inode *, struct dentry *,
+-			 struct inode *, struct dentry *);
++			 struct inode *, struct dentry *, unsigned int);
+ 
+ const struct file_operations jffs2_dir_operations =
+ {
+@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_
+ 	.mkdir =	jffs2_mkdir,
+ 	.rmdir =	jffs2_rmdir,
+ 	.mknod =	jffs2_mknod,
+-	.rename =	jffs2_rename,
++	.rename2 =	jffs2_rename,
+ 	.get_acl =	jffs2_get_acl,
+ 	.set_acl =	jffs2_set_acl,
+ 	.setattr =	jffs2_setattr,
+@@ -754,8 +754,27 @@ static int jffs2_mknod (struct inode *di
+ 	return ret;
+ }
+ 
++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry)
++{
++	struct dentry *wh;
++	int err;
++
++	wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
++	if (!wh)
++		return -ENOMEM;
++
++	err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
++			  WHITEOUT_DEV);
++	if (err)
++		return err;
++
++	d_rehash(wh);
++	return 0;
++}
++
+ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
+-			 struct inode *new_dir_i, struct dentry *new_dentry)
++			 struct inode *new_dir_i, struct dentry *new_dentry,
++			 unsigned int flags)
+ {
+ 	int ret;
+ 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
+@@ -763,6 +782,9 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
++	if (flags & ~RENAME_WHITEOUT)
++		return -EINVAL;
++
+ 	/* The VFS will check for us and prevent trying to rename a
+ 	 * file over a directory and vice versa, but if it's a directory,
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+@@ -826,9 +848,14 @@ static int jffs2_rename (struct inode *o
+ 	if (d_is_dir(old_dentry) && !victim_f)
+ 		inc_nlink(new_dir_i);
+ 
+-	/* Unlink the original */
+-	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+-			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
++	if (flags & RENAME_WHITEOUT)
++		/* Replace with whiteout */
++		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else
++		/* Unlink the original */
++		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
++				      old_dentry->d_name.name,
++				      old_dentry->d_name.len, NULL, now);
+ 
+ 	/* We don't touch inode->i_nlink */
+ 
diff --git a/target/linux/generic/patches-4.4/111-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/patches-4.4/111-jffs2-add-RENAME_EXCHANGE-support.patch
new file mode 100644
index 0000000000..b62408717e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/111-jffs2-add-RENAME_EXCHANGE-support.patch
@@ -0,0 +1,58 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 25 Apr 2015 12:41:32 +0200
+Subject: [PATCH] jffs2: add RENAME_EXCHANGE support
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -782,7 +782,7 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
+-	if (flags & ~RENAME_WHITEOUT)
++	if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE))
+ 		return -EINVAL;
+ 
+ 	/* The VFS will check for us and prevent trying to rename a
+@@ -790,7 +790,7 @@ static int jffs2_rename (struct inode *o
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+ 	 * needs to do that for itself.
+ 	 */
+-	if (d_really_is_positive(new_dentry)) {
++	if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
+ 		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
+ 		if (d_is_dir(new_dentry)) {
+ 			struct jffs2_full_dirent *fd;
+@@ -825,7 +825,7 @@ static int jffs2_rename (struct inode *o
+ 	if (ret)
+ 		return ret;
+ 
+-	if (victim_f) {
++	if (victim_f && !(flags & RENAME_EXCHANGE)) {
+ 		/* There was a victim. Kill it off nicely */
+ 		if (d_is_dir(new_dentry))
+ 			clear_nlink(d_inode(new_dentry));
+@@ -851,6 +851,12 @@ static int jffs2_rename (struct inode *o
+ 	if (flags & RENAME_WHITEOUT)
+ 		/* Replace with whiteout */
+ 		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else if (flags & RENAME_EXCHANGE)
++		/* Replace the original */
++		ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
++				    d_inode(new_dentry)->i_ino, type,
++				    old_dentry->d_name.name, old_dentry->d_name.len,
++				    now);
+ 	else
+ 		/* Unlink the original */
+ 		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+@@ -882,7 +888,7 @@ static int jffs2_rename (struct inode *o
+ 		return ret;
+ 	}
+ 
+-	if (d_is_dir(old_dentry))
++	if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
+ 		drop_nlink(old_dir_i);
+ 
+ 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
diff --git a/target/linux/generic/patches-4.4/120-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/patches-4.4/120-bridge_allow_receiption_on_disabled_port.patch
new file mode 100644
index 0000000000..727ab752e9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/120-bridge_allow_receiption_on_disabled_port.patch
@@ -0,0 +1,54 @@
+From: Stephen Hemminger <stephen@networkplumber.org>
+Subject: bridge: allow receiption on disabled port
+
+When an ethernet device is enslaved to a bridge, and the bridge STP
+detects loss of carrier (or operational state down), then normally
+packet receiption is blocked.
+
+This breaks control applications like WPA which maybe expecting to
+receive packets to negotiate to bring link up. The bridge needs to
+block forwarding packets from these disabled ports, but there is no
+hard requirement to not allow local packet delivery.
+
+Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -217,11 +217,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish
+ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
+ {
+ 	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
+-	u16 vid = 0;
++	if (p->state != BR_STATE_DISABLED) {
++		u16 vid = 0;
+ 
+-	/* check if vlan is allowed, to avoid spoofing */
+-	if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
+-		br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
++		/* check if vlan is allowed, to avoid spoofing */
++		if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
++			br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
++	}
+ 	return 0;	 /* process further */
+ }
+ 
+@@ -296,6 +298,18 @@ rx_handler_result_t br_handle_frame(stru
+ 
+ forward:
+ 	switch (p->state) {
++	case BR_STATE_DISABLED:
++		if (ether_addr_equal(p->br->dev->dev_addr, dest))
++			skb->pkt_type = PACKET_HOST;
++
++		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, dev_net(skb->dev), NULL, skb, skb->dev, NULL,
++			br_handle_local_finish))
++			break;
++
++		BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
++		br_pass_frame_up(skb);
++		break;
++
+ 	case BR_STATE_FORWARDING:
+ 		rhook = rcu_dereference(br_should_route_hook);
+ 		if (rhook) {
diff --git a/target/linux/generic/patches-4.4/132-mips_inline_dma_ops.patch b/target/linux/generic/patches-4.4/132-mips_inline_dma_ops.patch
new file mode 100644
index 0000000000..bf7dca6a33
--- /dev/null
+++ b/target/linux/generic/patches-4.4/132-mips_inline_dma_ops.patch
@@ -0,0 +1,778 @@
+From 2c58080407554e1bac8fd50d23cb02420524caed Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 12 Aug 2013 12:50:22 +0200
+Subject: [PATCH] MIPS: partially inline dma ops
+
+Several DMA ops are no-op on many platforms, and the indirection through
+the mips_dma_map_ops function table is causing the compiler to emit
+unnecessary code.
+
+Inlining visibly improves network performance in my tests (on a 24Kc
+based system), and also slightly reduces code size of a few drivers.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/Kconfig                   |   4 +
+ arch/mips/include/asm/dma-mapping.h | 360 +++++++++++++++++++++++++++++++++++-
+ arch/mips/mm/dma-default.c          | 163 ++--------------
+ 3 files changed, 373 insertions(+), 154 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1618,6 +1618,7 @@ config CPU_CAVIUM_OCTEON
+ 	select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
+ 	select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
+ 	select MIPS_L1_CACHE_SHIFT_7
++	select SYS_HAS_DMA_OPS
+ 	help
+ 	  The Cavium Octeon processor is a highly integrated chip containing
+ 	  many ethernet hardware widgets for networking tasks. The processor
+@@ -1913,6 +1914,9 @@ config MIPS_MALTA_PM
+ 	bool
+ 	default y
+ 
++config SYS_HAS_DMA_OPS
++	bool
++
+ #
+ # CPU may reorder R->R, R->W, W->R, W->W
+ # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+--- a/arch/mips/include/asm/dma-mapping.h
++++ b/arch/mips/include/asm/dma-mapping.h
+@@ -1,9 +1,16 @@
+ #ifndef _ASM_DMA_MAPPING_H
+ #define _ASM_DMA_MAPPING_H
+ 
++#include <linux/kmemcheck.h>
++#include <linux/bug.h>
+ #include <linux/scatterlist.h>
++#include <linux/dma-debug.h>
++#include <linux/dma-attrs.h>
++
+ #include <asm/dma-coherence.h>
+ #include <asm/cache.h>
++#include <asm/cpu-type.h>
++#include <asm-generic/dma-coherent.h>
+ 
+ #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
+ #include <dma-coherence.h>
+@@ -11,12 +18,53 @@
+ 
+ extern struct dma_map_ops *mips_dma_map_ops;
+ 
++void __dma_sync(struct page *page, unsigned long offset, size_t size,
++		enum dma_data_direction direction);
++void *mips_dma_alloc_coherent(struct device *dev, size_t size,
++			      dma_addr_t *dma_handle, gfp_t gfp,
++			      struct dma_attrs *attrs);
++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++			    dma_addr_t dma_handle, struct dma_attrs *attrs);
++
+ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+ {
++#ifdef CONFIG_SYS_HAS_DMA_OPS
+ 	if (dev && dev->archdata.dma_ops)
+ 		return dev->archdata.dma_ops;
+ 	else
+ 		return mips_dma_map_ops;
++#else
++	return NULL;
++#endif
++}
++
++/*
++ * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
++ * speculatively fill random cachelines with stale data at any time,
++ * requiring an extra flush post-DMA.
++ *
++ * Warning on the terminology - Linux calls an uncached area coherent;
++ * MIPS terminology calls memory areas with hardware maintained coherency
++ * coherent.
++ *
++ * Note that the R14000 and R16000 should also be checked for in this
++ * condition.  However this function is only called on non-I/O-coherent
++ * systems and only the R10000 and R12000 are used in such systems, the
++ * SGI IP28 Indigo² rsp. SGI IP32 aka O2.
++ */
++static inline int cpu_needs_post_dma_flush(struct device *dev)
++{
++	return !plat_device_is_coherent(dev) &&
++	       (boot_cpu_type() == CPU_R10000 ||
++		boot_cpu_type() == CPU_R12000 ||
++		boot_cpu_type() == CPU_BMIPS5000);
++}
++
++static inline struct page *dma_addr_to_page(struct device *dev,
++	dma_addr_t dma_addr)
++{
++	return pfn_to_page(
++		plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
+ }
+ 
+ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+@@ -29,9 +77,399 @@ static inline bool dma_capable(struct de
+ 
+ static inline void dma_mark_clean(void *addr, size_t size) {}
+ 
+-#include <asm-generic/dma-mapping-common.h>
++static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
++					      size_t size,
++					      enum dma_data_direction dir,
++					      struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	unsigned long offset = (unsigned long)ptr & ~PAGE_MASK;
++	struct page *page = virt_to_page(ptr);
++	dma_addr_t addr;
++
++	kmemcheck_mark_initialized(ptr, size);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		addr = ops->map_page(dev, page, offset, size, dir, attrs);
++	} else {
++		if (!plat_device_is_coherent(dev))
++			__dma_sync(page, offset, size, dir);
++
++		addr = plat_map_dma_mem_page(dev, page) + offset;
++	}
++	debug_dma_map_page(dev, page, offset, size, dir, addr, true);
++	return addr;
++}
++
++static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
++					  size_t size,
++					  enum dma_data_direction dir,
++					  struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->unmap_page(dev, addr, size, dir, attrs);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++		plat_post_dma_flush(dev);
++		plat_unmap_dma_mem(dev, addr, size, dir);
++	}
++	debug_dma_unmap_page(dev, addr, size, dir, true);
++}
++
++/*
++ * dma_maps_sg_attrs returns 0 on error and > 0 on success.
++ * It should never return a value < 0.
++ */
++static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
++				   int nents, enum dma_data_direction dir,
++				   struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	int i, ents;
++	struct scatterlist *s;
++
++	for_each_sg(sg, s, nents, i)
++		kmemcheck_mark_initialized(sg_virt(s), s->length);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ents = ops->map_sg(dev, sg, nents, dir, attrs);
++	} else {
++		for_each_sg(sg, s, nents, i) {
++			struct page *page = sg_page(s);
++
++			if (!plat_device_is_coherent(dev))
++				__dma_sync(page, s->offset, s->length, dir);
++#ifdef CONFIG_NEED_SG_DMA_LENGTH
++			s->dma_length = s->length;
++#endif
++			s->dma_address =
++				plat_map_dma_mem_page(dev, page) + s->offset;
++		}
++		ents = nents;
++	}
++	BUG_ON(ents < 0);
++	debug_dma_map_sg(dev, sg, nents, ents, dir);
++
++	return ents;
++}
++
++static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
++				      int nents, enum dma_data_direction dir,
++				      struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	debug_dma_unmap_sg(dev, sg, nents, dir);
++	if (ops) {
++		ops->unmap_sg(dev, sg, nents, dir, attrs);
++		return;
++	}
++	for_each_sg(sg, s, nents, i) {
++		if (!plat_device_is_coherent(dev) && dir != DMA_TO_DEVICE)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++		plat_unmap_dma_mem(dev, s->dma_address, s->length, dir);
++	}
++}
++
++static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
++				      size_t offset, size_t size,
++				      enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	dma_addr_t addr;
++
++	kmemcheck_mark_initialized(page_address(page) + offset, size);
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		addr = ops->map_page(dev, page, offset, size, dir, NULL);
++	} else {
++		if (!plat_device_is_coherent(dev))
++			__dma_sync(page, offset, size, dir);
++
++		addr = plat_map_dma_mem_page(dev, page) + offset;
++	}
++	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
++
++	return addr;
++}
++
++static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
++				  size_t size, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->unmap_page(dev, addr, size, dir, NULL);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++		plat_post_dma_flush(dev);
++		plat_unmap_dma_mem(dev, addr, size, dir);
++	}
++	debug_dma_unmap_page(dev, addr, size, dir, false);
++}
++
++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
++					   size_t size,
++					   enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->sync_single_for_cpu(dev, addr, size, dir);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr),
++				   addr & ~PAGE_MASK, size, dir);
++		plat_post_dma_flush(dev);
++	}
++	debug_dma_sync_single_for_cpu(dev, addr, size, dir);
++}
++
++static inline void dma_sync_single_for_device(struct device *dev,
++					      dma_addr_t addr, size_t size,
++					      enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_device(dev, addr, size, dir);
++	else if (!plat_device_is_coherent(dev))
++		__dma_sync(dma_addr_to_page(dev, addr),
++			   addr & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_for_device(dev, addr, size, dir);
++}
++
++static inline void dma_sync_single_range_for_cpu(struct device *dev,
++						 dma_addr_t addr,
++						 unsigned long offset,
++						 size_t size,
++						 enum dma_data_direction dir)
++{
++	const struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->sync_single_for_cpu(dev, addr + offset, size, dir);
++	} else {
++		if (cpu_needs_post_dma_flush(dev))
++			__dma_sync(dma_addr_to_page(dev, addr + offset),
++				   (addr + offset) & ~PAGE_MASK, size, dir);
++		plat_post_dma_flush(dev);
++	}
++
++	debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
++}
++
++static inline void dma_sync_single_range_for_device(struct device *dev,
++						    dma_addr_t addr,
++						    unsigned long offset,
++						    size_t size,
++						    enum dma_data_direction dir)
++{
++	const struct dma_map_ops *ops = get_dma_ops(dev);
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops)
++		ops->sync_single_for_device(dev, addr + offset, size, dir);
++	else if (!plat_device_is_coherent(dev))
++		__dma_sync(dma_addr_to_page(dev, addr + offset),
++			   (addr + offset) & ~PAGE_MASK, size, dir);
++	debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
++}
++
++static inline void
++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
++		    int nelems, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->sync_sg_for_cpu(dev, sg, nelems, dir);
++	} else if (cpu_needs_post_dma_flush(dev)) {
++		for_each_sg(sg, s, nelems, i)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++	}
++	plat_post_dma_flush(dev);
++	debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
++}
++
++static inline void
++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
++		       int nelems, enum dma_data_direction dir)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	struct scatterlist *s;
++	int i;
++
++	BUG_ON(!valid_dma_direction(dir));
++	if (ops) {
++		ops->sync_sg_for_device(dev, sg, nelems, dir);
++	} else if (!plat_device_is_coherent(dev)) {
++		for_each_sg(sg, s, nelems, i)
++			__dma_sync(sg_page(s), s->offset, s->length, dir);
++	}
++	debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
++
++}
++
++#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
++#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
++#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
++#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
++
++extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
++			   void *cpu_addr, dma_addr_t dma_addr, size_t size);
++
++/**
++ * dma_mmap_attrs - map a coherent DMA allocation into user space
++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
++ * @vma: vm_area_struct describing requested user mapping
++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
++ * @handle: device-view address returned from dma_alloc_attrs
++ * @size: size of memory originally requested in dma_alloc_attrs
++ * @attrs: attributes of mapping properties requested in dma_alloc_attrs
++ *
++ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs
++ * into user space.  The coherent DMA buffer must not be freed by the
++ * driver until the user space mapping has been released.
++ */
++static inline int
++dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
++	       dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	BUG_ON(!ops);
++	if (ops && ops->mmap)
++		return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
++	return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
++}
++
++#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
++
++int
++dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
++		       void *cpu_addr, dma_addr_t dma_addr, size_t size);
++
++static inline int
++dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
++		      dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	BUG_ON(!ops);
++	if (ops && ops->get_sgtable)
++		return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
++					attrs);
++	return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
++}
++
++#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
++
++static inline int dma_supported(struct device *dev, u64 mask)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++	if (ops)
++		return ops->dma_supported(dev, mask);
++	return plat_dma_supported(dev, mask);
++}
++
++static inline int dma_mapping_error(struct device *dev, u64 mask)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	debug_dma_mapping_error(dev, mask);
++	if (ops)
++		return ops->mapping_error(dev, mask);
++	return 0;
++}
++
++static inline int
++dma_set_mask(struct device *dev, u64 mask)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	if(!dev->dma_mask || !dma_supported(dev, mask))
++		return -EIO;
++
++	if (ops && ops->set_dma_mask)
++		return ops->set_dma_mask(dev, mask);
++
++	*dev->dma_mask = mask;
++
++	return 0;
++}
+ 
+ extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ 	       enum dma_data_direction direction);
+ 
++#define dma_alloc_coherent(d,s,h,f)	dma_alloc_attrs(d,s,h,f,NULL)
++
++static inline void *dma_alloc_attrs(struct device *dev, size_t size,
++				    dma_addr_t *dma_handle, gfp_t gfp,
++				    struct dma_attrs *attrs)
++{
++	void *ret;
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	if (ops)
++		ret = ops->alloc(dev, size, dma_handle, gfp, attrs);
++	else
++		ret = mips_dma_alloc_coherent(dev, size, dma_handle, gfp,
++					      attrs);
++
++	debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
++
++	return ret;
++}
++
++#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
++
++static inline void dma_free_attrs(struct device *dev, size_t size,
++				  void *vaddr, dma_addr_t dma_handle,
++				  struct dma_attrs *attrs)
++{
++	struct dma_map_ops *ops = get_dma_ops(dev);
++
++	if (ops)
++		ops->free(dev, size, vaddr, dma_handle, attrs);
++	else
++		mips_dma_free_coherent(dev, size, vaddr, dma_handle, attrs);
++
++	debug_dma_free_coherent(dev, size, vaddr, dma_handle);
++}
++
++static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
++		dma_addr_t *dma_handle, gfp_t gfp)
++{
++	DEFINE_DMA_ATTRS(attrs);
++
++	dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
++	return dma_alloc_attrs(dev, size, dma_handle, gfp, &attrs);
++}
++
++static inline void dma_free_noncoherent(struct device *dev, size_t size,
++		void *cpu_addr, dma_addr_t dma_handle)
++{
++	DEFINE_DMA_ATTRS(attrs);
++
++	dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
++	dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
++}
++
++
+ #endif /* _ASM_DMA_MAPPING_H */
+--- a/arch/mips/mm/dma-default.c
++++ b/arch/mips/mm/dma-default.c
+@@ -46,35 +46,6 @@ static int __init setnocoherentio(char *
+ early_param("nocoherentio", setnocoherentio);
+ #endif
+ 
+-static inline struct page *dma_addr_to_page(struct device *dev,
+-	dma_addr_t dma_addr)
+-{
+-	return pfn_to_page(
+-		plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
+-}
+-
+-/*
+- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
+- * speculatively fill random cachelines with stale data at any time,
+- * requiring an extra flush post-DMA.
+- *
+- * Warning on the terminology - Linux calls an uncached area coherent;
+- * MIPS terminology calls memory areas with hardware maintained coherency
+- * coherent.
+- *
+- * Note that the R14000 and R16000 should also be checked for in this
+- * condition.  However this function is only called on non-I/O-coherent
+- * systems and only the R10000 and R12000 are used in such systems, the
+- * SGI IP28 Indigo² rsp. SGI IP32 aka O2.
+- */
+-static inline int cpu_needs_post_dma_flush(struct device *dev)
+-{
+-	return !plat_device_is_coherent(dev) &&
+-	       (boot_cpu_type() == CPU_R10000 ||
+-		boot_cpu_type() == CPU_R12000 ||
+-		boot_cpu_type() == CPU_BMIPS5000);
+-}
+-
+ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
+ {
+ 	gfp_t dma_flag;
+@@ -129,7 +100,7 @@ static void *mips_dma_alloc_noncoherent(
+ 	return ret;
+ }
+ 
+-static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
++void *mips_dma_alloc_coherent(struct device *dev, size_t size,
+ 	dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+ {
+ 	void *ret;
+@@ -165,6 +136,7 @@ static void *mips_dma_alloc_coherent(str
+ 
+ 	return ret;
+ }
++EXPORT_SYMBOL(mips_dma_alloc_coherent);
+ 
+ 
+ static void mips_dma_free_noncoherent(struct device *dev, size_t size,
+@@ -174,7 +146,7 @@ static void mips_dma_free_noncoherent(st
+ 	free_pages((unsigned long) vaddr, get_order(size));
+ }
+ 
+-static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
++void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+ 	dma_addr_t dma_handle, struct dma_attrs *attrs)
+ {
+ 	unsigned long addr = (unsigned long) vaddr;
+@@ -196,40 +168,7 @@ static void mips_dma_free_coherent(struc
+ 	if (!dma_release_from_contiguous(dev, page, count))
+ 		__free_pages(page, get_order(size));
+ }
+-
+-static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+-	void *cpu_addr, dma_addr_t dma_addr, size_t size,
+-	struct dma_attrs *attrs)
+-{
+-	unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+-	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+-	unsigned long addr = (unsigned long)cpu_addr;
+-	unsigned long off = vma->vm_pgoff;
+-	unsigned long pfn;
+-	int ret = -ENXIO;
+-
+-	if (!plat_device_is_coherent(dev) && !hw_coherentio)
+-		addr = CAC_ADDR(addr);
+-
+-	pfn = page_to_pfn(virt_to_page((void *)addr));
+-
+-	if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+-		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+-	else
+-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+-
+-	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+-		return ret;
+-
+-	if (off < count && user_count <= (count - off)) {
+-		ret = remap_pfn_range(vma, vma->vm_start,
+-				      pfn + off,
+-				      user_count << PAGE_SHIFT,
+-				      vma->vm_page_prot);
+-	}
+-
+-	return ret;
+-}
++EXPORT_SYMBOL(mips_dma_free_coherent);
+ 
+ static inline void __dma_sync_virtual(void *addr, size_t size,
+ 	enum dma_data_direction direction)
+@@ -258,7 +197,7 @@ static inline void __dma_sync_virtual(vo
+  * If highmem is not configured then the bulk of this loop gets
+  * optimized out.
+  */
+-static inline void __dma_sync(struct page *page,
++void __dma_sync(struct page *page,
+ 	unsigned long offset, size_t size, enum dma_data_direction direction)
+ {
+ 	size_t left = size;
+@@ -288,120 +227,7 @@ static inline void __dma_sync(struct pag
+ 		left -= len;
+ 	} while (left);
+ }
+-
+-static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+-	size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
+-{
+-	if (cpu_needs_post_dma_flush(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_addr),
+-			   dma_addr & ~PAGE_MASK, size, direction);
+-	plat_post_dma_flush(dev);
+-	plat_unmap_dma_mem(dev, dma_addr, size, direction);
+-}
+-
+-static int mips_dma_map_sg(struct device *dev, struct scatterlist *sglist,
+-	int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+-{
+-	int i;
+-	struct scatterlist *sg;
+-
+-	for_each_sg(sglist, sg, nents, i) {
+-		if (!plat_device_is_coherent(dev))
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-#ifdef CONFIG_NEED_SG_DMA_LENGTH
+-		sg->dma_length = sg->length;
+-#endif
+-		sg->dma_address = plat_map_dma_mem_page(dev, sg_page(sg)) +
+-				  sg->offset;
+-	}
+-
+-	return nents;
+-}
+-
+-static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
+-	unsigned long offset, size_t size, enum dma_data_direction direction,
+-	struct dma_attrs *attrs)
+-{
+-	if (!plat_device_is_coherent(dev))
+-		__dma_sync(page, offset, size, direction);
+-
+-	return plat_map_dma_mem_page(dev, page) + offset;
+-}
+-
+-static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+-	int nhwentries, enum dma_data_direction direction,
+-	struct dma_attrs *attrs)
+-{
+-	int i;
+-	struct scatterlist *sg;
+-
+-	for_each_sg(sglist, sg, nhwentries, i) {
+-		if (!plat_device_is_coherent(dev) &&
+-		    direction != DMA_TO_DEVICE)
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-		plat_unmap_dma_mem(dev, sg->dma_address, sg->length, direction);
+-	}
+-}
+-
+-static void mips_dma_sync_single_for_cpu(struct device *dev,
+-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+-{
+-	if (cpu_needs_post_dma_flush(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_handle),
+-			   dma_handle & ~PAGE_MASK, size, direction);
+-	plat_post_dma_flush(dev);
+-}
+-
+-static void mips_dma_sync_single_for_device(struct device *dev,
+-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+-{
+-	if (!plat_device_is_coherent(dev))
+-		__dma_sync(dma_addr_to_page(dev, dma_handle),
+-			   dma_handle & ~PAGE_MASK, size, direction);
+-}
+-
+-static void mips_dma_sync_sg_for_cpu(struct device *dev,
+-	struct scatterlist *sglist, int nelems,
+-	enum dma_data_direction direction)
+-{
+-	int i;
+-	struct scatterlist *sg;
+-
+-	if (cpu_needs_post_dma_flush(dev)) {
+-		for_each_sg(sglist, sg, nelems, i) {
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-		}
+-	}
+-	plat_post_dma_flush(dev);
+-}
+-
+-static void mips_dma_sync_sg_for_device(struct device *dev,
+-	struct scatterlist *sglist, int nelems,
+-	enum dma_data_direction direction)
+-{
+-	int i;
+-	struct scatterlist *sg;
+-
+-	if (!plat_device_is_coherent(dev)) {
+-		for_each_sg(sglist, sg, nelems, i) {
+-			__dma_sync(sg_page(sg), sg->offset, sg->length,
+-				   direction);
+-		}
+-	}
+-}
+-
+-int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+-{
+-	return 0;
+-}
+-
+-int mips_dma_supported(struct device *dev, u64 mask)
+-{
+-	return plat_dma_supported(dev, mask);
+-}
++EXPORT_SYMBOL(__dma_sync);
+ 
+ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ 			 enum dma_data_direction direction)
+@@ -414,24 +240,10 @@ void dma_cache_sync(struct device *dev,
+ 
+ EXPORT_SYMBOL(dma_cache_sync);
+ 
+-static struct dma_map_ops mips_default_dma_map_ops = {
+-	.alloc = mips_dma_alloc_coherent,
+-	.free = mips_dma_free_coherent,
+-	.mmap = mips_dma_mmap,
+-	.map_page = mips_dma_map_page,
+-	.unmap_page = mips_dma_unmap_page,
+-	.map_sg = mips_dma_map_sg,
+-	.unmap_sg = mips_dma_unmap_sg,
+-	.sync_single_for_cpu = mips_dma_sync_single_for_cpu,
+-	.sync_single_for_device = mips_dma_sync_single_for_device,
+-	.sync_sg_for_cpu = mips_dma_sync_sg_for_cpu,
+-	.sync_sg_for_device = mips_dma_sync_sg_for_device,
+-	.mapping_error = mips_dma_mapping_error,
+-	.dma_supported = mips_dma_supported
+-};
+-
+-struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops;
++#ifdef CONFIG_SYS_HAS_DMA_OPS
++struct dma_map_ops *mips_dma_map_ops = NULL;
+ EXPORT_SYMBOL(mips_dma_map_ops);
++#endif
+ 
+ #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+ 
diff --git a/target/linux/generic/patches-4.4/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch b/target/linux/generic/patches-4.4/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
new file mode 100644
index 0000000000..e1b84ae52c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/140-mtd-part-add-generic-parsing-of-linux-part-probe.patch
@@ -0,0 +1,183 @@
+From 3e7056c3a369e9ef9ca804bc626b60ef6b62ee27 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 May 2015 18:48:38 +0200
+Subject: [PATCH 2/3] mtd: part: add generic parsing of linux,part-probe
+
+This moves the linux,part-probe device tree parsing code from
+physmap_of.c to mtdpart.c. Now all drivers can use this feature by just
+providing a reference to their device tree node in struct
+mtd_part_parser_data.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ Documentation/devicetree/bindings/mtd/nand.txt | 16 +++++++++
+ drivers/mtd/maps/physmap_of.c                  | 46 +-------------------------
+ drivers/mtd/mtdpart.c                          | 45 +++++++++++++++++++++++++
+ 3 files changed, 62 insertions(+), 45 deletions(-)
+
+--- a/Documentation/devicetree/bindings/mtd/nand.txt
++++ b/Documentation/devicetree/bindings/mtd/nand.txt
+@@ -12,6 +12,22 @@
+ - nand-ecc-step-size: integer representing the number of data bytes
+ 		      that are covered by a single ECC step.
+ 
++- linux,part-probe: list of name as strings of the partition parser
++		    which should be used to parse the partition table.
++		    They will be tried in the specified ordering and
++		    the next one will be used if the previous one
++		    failed.
++
++		    Example: linux,part-probe = "cmdlinepart", "ofpart";
++
++		    This is also the default value, which will be used
++		    if this attribute is not specified. It could be
++		    that the flash driver in use overwrote the default
++		    value and uses some other default.
++
++		    Possible values are: bcm47xxpart, afs, ar7part,
++		    ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart
++
+ The ECC strength and ECC step size properties define the correction capability
+ of a controller. Together, they say a controller can correct "{strength} bit
+ errors per {size} bytes".
+--- a/drivers/mtd/maps/physmap_of.c
++++ b/drivers/mtd/maps/physmap_of.c
+@@ -112,47 +112,9 @@ static struct mtd_info *obsolete_probe(s
+ static const char * const part_probe_types_def[] = {
+ 	"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
+ 
+-static const char * const *of_get_probes(struct device_node *dp)
+-{
+-	const char *cp;
+-	int cplen;
+-	unsigned int l;
+-	unsigned int count;
+-	const char **res;
+-
+-	cp = of_get_property(dp, "linux,part-probe", &cplen);
+-	if (cp == NULL)
+-		return part_probe_types_def;
+-
+-	count = 0;
+-	for (l = 0; l != cplen; l++)
+-		if (cp[l] == 0)
+-			count++;
+-
+-	res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
+-	if (!res)
+-		return NULL;
+-	count = 0;
+-	while (cplen > 0) {
+-		res[count] = cp;
+-		l = strlen(cp) + 1;
+-		cp += l;
+-		cplen -= l;
+-		count++;
+-	}
+-	return res;
+-}
+-
+-static void of_free_probes(const char * const *probes)
+-{
+-	if (probes != part_probe_types_def)
+-		kfree(probes);
+-}
+-
+ static const struct of_device_id of_flash_match[];
+ static int of_flash_probe(struct platform_device *dev)
+ {
+-	const char * const *part_probe_types;
+ 	const struct of_device_id *match;
+ 	struct device_node *dp = dev->dev.of_node;
+ 	struct resource res;
+@@ -311,14 +273,8 @@ static int of_flash_probe(struct platfor
+ 		goto err_out;
+ 
+ 	ppdata.of_node = dp;
+-	part_probe_types = of_get_probes(dp);
+-	if (!part_probe_types) {
+-		err = -ENOMEM;
+-		goto err_out;
+-	}
+-	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
++	mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata,
+ 			NULL, 0);
+-	of_free_probes(part_probe_types);
+ 
+ 	kfree(mtd_list);
+ 
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -29,6 +29,7 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/of.h>
+ #include <linux/err.h>
+ #include <linux/kconfig.h>
+ 
+@@ -721,6 +722,42 @@ void deregister_mtd_parser(struct mtd_pa
+ EXPORT_SYMBOL_GPL(deregister_mtd_parser);
+ 
+ /*
++ * Parses the linux,part-probe device tree property.
++ * When a non null value is returned it has to be freed with kfree() by
++ * the caller.
++ */
++static const char * const *of_get_probes(struct device_node *dp)
++{
++	const char *cp;
++	int cplen;
++	unsigned int l;
++	unsigned int count;
++	const char **res;
++
++	cp = of_get_property(dp, "linux,part-probe", &cplen);
++	if (cp == NULL)
++		return NULL;
++
++	count = 0;
++	for (l = 0; l != cplen; l++)
++		if (cp[l] == 0)
++			count++;
++
++	res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
++	if (!res)
++		return NULL;
++	count = 0;
++	while (cplen > 0) {
++		res[count] = cp;
++		l = strlen(cp) + 1;
++		cp += l;
++		cplen -= l;
++		count++;
++	}
++	return res;
++}
++
++/*
+  * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
+  * are changing this array!
+  */
+@@ -756,6 +793,13 @@ int parse_mtd_partitions(struct mtd_info
+ {
+ 	struct mtd_part_parser *parser;
+ 	int ret, err = 0;
++	const char *const *types_of = NULL;
++
++	if (data && data->of_node) {
++		types_of = of_get_probes(data->of_node);
++		if (types_of != NULL)
++			types = types_of;
++	}
+ 
+ 	if (!types)
+ 		types = default_mtd_part_types;
+@@ -785,6 +829,7 @@ int parse_mtd_partitions(struct mtd_info
+ 		if (ret < 0 && !err)
+ 			err = ret;
+ 	}
++	kfree(types_of);
+ 	return err;
+ }
+ 
diff --git a/target/linux/generic/patches-4.4/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch b/target/linux/generic/patches-4.4/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
new file mode 100644
index 0000000000..b0a064fb4e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/142-mtd-spi-nor-include-mtd.h-header-for-struct-mtd_info.patch
@@ -0,0 +1,38 @@
+From 72fc448c4c970bdbba604ab340f16080b4f3bb17 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Thu, 26 Nov 2015 08:52:09 +0100
+Subject: [PATCH] mtd: spi-nor: include mtd.h header for struct mtd_info
+ definition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So far struct spi_nor was using just a pointer to struct mtd_info so it
+wasn't needed to have it fully defined there. After recent change we
+embed whole struct so we need to include a proper header.
+
+Fixes: 1976367173a4 ("mtd: spi-nor: embed struct mtd_info within struct spi_nor")
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ include/linux/mtd/spi-nor.h | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -12,6 +12,7 @@
+ 
+ #include <linux/bitops.h>
+ #include <linux/mtd/cfi.h>
++#include <linux/mtd/mtd.h>
+ 
+ /*
+  * Manufacturer IDs
+@@ -117,8 +118,6 @@ enum spi_nor_option_flags {
+ 	SNOR_F_USE_FSR		= BIT(0),
+ };
+ 
+-struct mtd_info;
+-
+ /**
+  * struct spi_nor - Structure for defining a the SPI NOR layer
+  * @mtd:		point to a mtd_info structure
diff --git a/target/linux/generic/patches-4.4/150-mtd-spi-nor-add-support-for-ESMT_f25l32qa-and-ESMT_f.patch b/target/linux/generic/patches-4.4/150-mtd-spi-nor-add-support-for-ESMT_f25l32qa-and-ESMT_f.patch
new file mode 100644
index 0000000000..65f1b708a1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/150-mtd-spi-nor-add-support-for-ESMT_f25l32qa-and-ESMT_f.patch
@@ -0,0 +1,21 @@
+From: "L. D. Pinney" <ldpinney@gmail.com>
+Date: Thu, 25 Aug 2016 13:07:56 -0500
+Subject: [PATCH] mtd: spi-nor: add support for ESMT_f25l32qa and ESMT_f25l64qa
+
+Add Support for the ESMT_F25L32QA and ESMT_F25L64QA
+These are 4MB and 8MB SPI NOR Chips from Elite Semiconductor Memory Technology
+
+Signed-off-by: L. D. Pinney <ldpinney@gmail.com>
+---
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -688,6 +688,8 @@ static const struct flash_info spi_nor_i
+ 
+ 	/* ESMT */
+ 	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
++	{ "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K) },
++	{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K) },
+ 
+ 	/* Everspin */
+ 	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
diff --git a/target/linux/generic/patches-4.4/160-usb-gadget-udc-net2280-add-usb2380-support.patch b/target/linux/generic/patches-4.4/160-usb-gadget-udc-net2280-add-usb2380-support.patch
new file mode 100644
index 0000000000..c03280149e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/160-usb-gadget-udc-net2280-add-usb2380-support.patch
@@ -0,0 +1,253 @@
+From 5185c91385d73cdf79836eb8548e4726e43ae831 Mon Sep 17 00:00:00 2001
+From: Tim Harvey <tharvey@gateworks.com>
+Date: Mon, 23 May 2016 06:58:41 -0700
+Subject: [PATCH] usb: gadget: net2280: add USB2380 support
+
+The PLX USB2380 is a PCIe version of the NET2280 and behaves more like the
+USB338x but without the USB3.0 superspeed support.
+
+This was tested with g_ether, g_serial, g_mass_storage on a Gateworks
+Ventana GW2383.
+
+Cc: Justin DeFields <justindefields@gmail.com>
+Signed-off-by: Tim Harvey <tharvey@gateworks.com>
+Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
+---
+ drivers/usb/gadget/udc/Kconfig   |  4 +++-
+ drivers/usb/gadget/udc/net2280.c | 51 +++++++++++++++++++++++-----------------
+ drivers/usb/gadget/udc/net2280.h |  1 +
+ 3 files changed, 34 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/gadget/udc/Kconfig
++++ b/drivers/usb/gadget/udc/Kconfig
+@@ -298,7 +298,7 @@ config USB_NET2272_DMA
+ 	  If unsure, say "N" here.  The driver works fine in PIO mode.
+ 
+ config USB_NET2280
+-	tristate "NetChip 228x / PLX USB338x"
++	tristate "NetChip NET228x / PLX USB3x8x"
+ 	depends on PCI
+ 	help
+ 	   NetChip 2280 / 2282 is a PCI based USB peripheral controller which
+@@ -308,6 +308,8 @@ config USB_NET2280
+ 	   (for control transfers) and several endpoints with dedicated
+ 	   functions.
+ 
++	   PLX 2380 is a PCIe version of the PLX 2380.
++
+ 	   PLX 3380 / 3382 is a PCIe based USB peripheral controller which
+ 	   supports full, high speed USB 2.0 and super speed USB 3.0
+ 	   data transfers.
+--- a/drivers/usb/gadget/udc/net2280.c
++++ b/drivers/usb/gadget/udc/net2280.c
+@@ -211,7 +211,7 @@ net2280_enable(struct usb_ep *_ep, const
+ 		goto print_err;
+ 	}
+ 
+-	if (dev->quirks & PLX_SUPERSPEED) {
++	if (dev->quirks & PLX_PCIE) {
+ 		if ((desc->bEndpointAddress & 0x0f) >= 0x0c) {
+ 			ret = -EDOM;
+ 			goto print_err;
+@@ -245,7 +245,7 @@ net2280_enable(struct usb_ep *_ep, const
+ 	/* set type, direction, address; reset fifo counters */
+ 	writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
+ 
+-	if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
++	if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
+ 		tmp = readl(&ep->cfg->ep_cfg);
+ 		/* If USB ep number doesn't match hardware ep number */
+ 		if ((tmp & 0xf) != usb_endpoint_num(desc)) {
+@@ -316,7 +316,7 @@ net2280_enable(struct usb_ep *_ep, const
+ 			BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
+ 	}
+ 
+-	if (dev->quirks & PLX_SUPERSPEED)
++	if (dev->quirks & PLX_PCIE)
+ 		ep_clear_seqnum(ep);
+ 	writel(tmp, &ep->cfg->ep_cfg);
+ 
+@@ -527,7 +527,7 @@ static int net2280_disable(struct usb_ep
+ 	spin_lock_irqsave(&ep->dev->lock, flags);
+ 	nuke(ep);
+ 
+-	if (ep->dev->quirks & PLX_SUPERSPEED)
++	if (ep->dev->quirks & PLX_PCIE)
+ 		ep_reset_338x(ep->dev->regs, ep);
+ 	else
+ 		ep_reset_228x(ep->dev->regs, ep);
+@@ -862,7 +862,7 @@ static void start_queue(struct net2280_e
+ 	writel(readl(&dma->dmastat), &dma->dmastat);
+ 
+ 	writel(td_dma, &dma->dmadesc);
+-	if (ep->dev->quirks & PLX_SUPERSPEED)
++	if (ep->dev->quirks & PLX_PCIE)
+ 		dmactl |= BIT(DMA_REQUEST_OUTSTANDING);
+ 	writel(dmactl, &dma->dmactl);
+ 
+@@ -1046,7 +1046,7 @@ net2280_queue(struct usb_ep *_ep, struct
+ 
+ 	/* kickstart this i/o queue? */
+ 	if  (list_empty(&ep->queue) && !ep->stopped &&
+-		!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
++		!((dev->quirks & PLX_PCIE) && ep->dma &&
+ 		  (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
+ 
+ 		/* use DMA if the endpoint supports it, else pio */
+@@ -1169,7 +1169,7 @@ static void scan_dma_completions(struct
+ 			break;
+ 		} else if (!ep->is_in &&
+ 			   (req->req.length % ep->ep.maxpacket) &&
+-			   !(ep->dev->quirks & PLX_SUPERSPEED)) {
++			   !(ep->dev->quirks & PLX_PCIE)) {
+ 
+ 			tmp = readl(&ep->regs->ep_stat);
+ 			/* AVOID TROUBLE HERE by not issuing short reads from
+@@ -1367,7 +1367,7 @@ net2280_set_halt_and_wedge(struct usb_ep
+ 				ep->wedged = 1;
+ 		} else {
+ 			clear_halt(ep);
+-			if (ep->dev->quirks & PLX_SUPERSPEED &&
++			if (ep->dev->quirks & PLX_PCIE &&
+ 				!list_empty(&ep->queue) && ep->td_dma)
+ 					restart_dma(ep);
+ 			ep->wedged = 0;
+@@ -2394,7 +2394,7 @@ static int net2280_start(struct usb_gadg
+ 	 */
+ 	net2280_led_active(dev, 1);
+ 
+-	if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
++	if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
+ 		defect7374_enable_data_eps_zero(dev);
+ 
+ 	ep0_start(dev);
+@@ -3063,7 +3063,7 @@ static void handle_stat0_irqs(struct net
+ 		}
+ 		ep->stopped = 0;
+ 		dev->protocol_stall = 0;
+-		if (!(dev->quirks & PLX_SUPERSPEED)) {
++		if (!(dev->quirks & PLX_PCIE)) {
+ 			if (ep->dev->quirks & PLX_2280)
+ 				tmp = BIT(FIFO_OVERFLOW) |
+ 				    BIT(FIFO_UNDERFLOW);
+@@ -3090,7 +3090,7 @@ static void handle_stat0_irqs(struct net
+ 		cpu_to_le32s(&u.raw[0]);
+ 		cpu_to_le32s(&u.raw[1]);
+ 
+-		if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
++		if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
+ 			defect7374_workaround(dev, u.r);
+ 
+ 		tmp = 0;
+@@ -3173,7 +3173,7 @@ static void handle_stat0_irqs(struct net
+ 			} else {
+ 				ep_vdbg(dev, "%s clear halt\n", e->ep.name);
+ 				clear_halt(e);
+-				if ((ep->dev->quirks & PLX_SUPERSPEED) &&
++				if ((ep->dev->quirks & PLX_PCIE) &&
+ 					!list_empty(&e->queue) && e->td_dma)
+ 						restart_dma(e);
+ 			}
+@@ -3195,7 +3195,7 @@ static void handle_stat0_irqs(struct net
+ 			if (e->ep.name == ep0name)
+ 				goto do_stall;
+ 			set_halt(e);
+-			if ((dev->quirks & PLX_SUPERSPEED) && e->dma)
++			if ((dev->quirks & PLX_PCIE) && e->dma)
+ 				abort_dma(e);
+ 			allow_status(ep);
+ 			ep_vdbg(dev, "%s set halt\n", ep->ep.name);
+@@ -3234,7 +3234,7 @@ do_stall:
+ #undef	w_length
+ 
+ next_endpoints:
+-	if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
++	if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
+ 		u32 mask = (BIT(ENDPOINT_0_INTERRUPT) |
+ 			USB3380_IRQSTAT0_EP_INTR_MASK_IN |
+ 			USB3380_IRQSTAT0_EP_INTR_MASK_OUT);
+@@ -3399,7 +3399,7 @@ __acquires(dev->lock)
+ 		writel(tmp, &dma->dmastat);
+ 
+ 		/* dma sync*/
+-		if (dev->quirks & PLX_SUPERSPEED) {
++		if (dev->quirks & PLX_PCIE) {
+ 			u32 r_dmacount = readl(&dma->dmacount);
+ 			if (!ep->is_in &&  (r_dmacount & 0x00FFFFFF) &&
+ 			    (tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT)))
+@@ -3468,7 +3468,7 @@ static irqreturn_t net2280_irq(int irq,
+ 	/* control requests and PIO */
+ 	handle_stat0_irqs(dev, readl(&dev->regs->irqstat0));
+ 
+-	if (dev->quirks & PLX_SUPERSPEED) {
++	if (dev->quirks & PLX_PCIE) {
+ 		/* re-enable interrupt to trigger any possible new interrupt */
+ 		u32 pciirqenb1 = readl(&dev->regs->pciirqenb1);
+ 		writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1);
+@@ -3513,7 +3513,7 @@ static void net2280_remove(struct pci_de
+ 	}
+ 	if (dev->got_irq)
+ 		free_irq(pdev->irq, dev);
+-	if (dev->quirks & PLX_SUPERSPEED)
++	if (dev->quirks & PLX_PCIE)
+ 		pci_disable_msi(pdev);
+ 	if (dev->regs)
+ 		iounmap(dev->regs);
+@@ -3593,7 +3593,7 @@ static int net2280_probe(struct pci_dev
+ 	dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200);
+ 	dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300);
+ 
+-	if (dev->quirks & PLX_SUPERSPEED) {
++	if (dev->quirks & PLX_PCIE) {
+ 		u32 fsmvalue;
+ 		u32 usbstat;
+ 		dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *)
+@@ -3637,7 +3637,7 @@ static int net2280_probe(struct pci_dev
+ 		goto done;
+ 	}
+ 
+-	if (dev->quirks & PLX_SUPERSPEED)
++	if (dev->quirks & PLX_PCIE)
+ 		if (pci_enable_msi(pdev))
+ 			ep_err(dev, "Failed to enable MSI mode\n");
+ 
+@@ -3755,10 +3755,19 @@ static const struct pci_device_id pci_id
+ 	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ 	.class_mask =	~0,
+ 	.vendor =	PCI_VENDOR_ID_PLX,
++	.device =	0x2380,
++	.subvendor =	PCI_ANY_ID,
++	.subdevice =	PCI_ANY_ID,
++	.driver_data =	PLX_PCIE,
++	 },
++	{
++	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
++	.class_mask =	~0,
++	.vendor =	PCI_VENDOR_ID_PLX,
+ 	.device =	0x3380,
+ 	.subvendor =	PCI_ANY_ID,
+ 	.subdevice =	PCI_ANY_ID,
+-	.driver_data =	PLX_SUPERSPEED,
++	.driver_data =	PLX_PCIE | PLX_SUPERSPEED,
+ 	 },
+ 	{
+ 	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+@@ -3767,7 +3776,7 @@ static const struct pci_device_id pci_id
+ 	.device =	0x3382,
+ 	.subvendor =	PCI_ANY_ID,
+ 	.subdevice =	PCI_ANY_ID,
+-	.driver_data =	PLX_SUPERSPEED,
++	.driver_data =	PLX_PCIE | PLX_SUPERSPEED,
+ 	 },
+ { /* end: all zeroes */ }
+ };
+--- a/drivers/usb/gadget/udc/net2280.h
++++ b/drivers/usb/gadget/udc/net2280.h
+@@ -47,6 +47,7 @@ set_idx_reg(struct net2280_regs __iomem
+ #define PLX_LEGACY		BIT(0)
+ #define PLX_2280		BIT(1)
+ #define PLX_SUPERSPEED		BIT(2)
++#define PLX_PCIE		BIT(3)
+ 
+ #define REG_DIAG		0x0
+ #define     RETRY_COUNTER                                       16
diff --git a/target/linux/generic/patches-4.4/170-net-bgmac-fix-reversed-checks-for-clock-control-flag.patch b/target/linux/generic/patches-4.4/170-net-bgmac-fix-reversed-checks-for-clock-control-flag.patch
new file mode 100644
index 0000000000..97d8951589
--- /dev/null
+++ b/target/linux/generic/patches-4.4/170-net-bgmac-fix-reversed-checks-for-clock-control-flag.patch
@@ -0,0 +1,32 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 7 Nov 2016 13:19:42 +0100
+Subject: [PATCH] net: bgmac: fix reversed checks for clock control flag
+
+This fixes regression introduced by patch adding feature flags. It was
+already reported and patch followed (it got accepted) but it appears it
+was incorrect. Instead of fixing reversed condition it broke a good one.
+
+This patch was verified to actually fix SoC hanges caused by bgmac on
+BCM47186B0.
+
+Fixes: db791eb2970b ("net: ethernet: bgmac: convert to feature flags")
+Fixes: 4af1474e6198 ("net: bgmac: Fix errant feature flag check")
+Cc: Jon Mason <jon.mason@broadcom.com>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1049,9 +1049,9 @@ static void bgmac_enable(struct bgmac *b
+ 
+ 	mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+ 		BGMAC_DS_MM_SHIFT;
+-	if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) || mode != 0)
++	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
+ 		bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+-	if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
++	if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) && mode == 2)
+ 		bgmac_cco_ctl_maskset(bgmac, 1, ~0,
+ 				      BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
+ 
diff --git a/target/linux/generic/patches-4.4/200-fix_localversion.patch b/target/linux/generic/patches-4.4/200-fix_localversion.patch
new file mode 100644
index 0000000000..70228bb5f4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/200-fix_localversion.patch
@@ -0,0 +1,11 @@
+--- a/scripts/setlocalversion
++++ b/scripts/setlocalversion
+@@ -165,7 +165,7 @@ else
+ 	# annotated or signed tagged state (as git describe only
+ 	# looks at signed or annotated tags - git tag -a/-s) and
+ 	# LOCALVERSION= is not specified
+-	if test "${LOCALVERSION+set}" != "set"; then
++	if test "${CONFIG_LOCALVERSION+set}" != "set"; then
+ 		scm=$(scm_version --short)
+ 		res="$res${scm:++}"
+ 	fi
diff --git a/target/linux/generic/patches-4.4/201-extra_optimization.patch b/target/linux/generic/patches-4.4/201-extra_optimization.patch
new file mode 100644
index 0000000000..04192727c0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/201-extra_optimization.patch
@@ -0,0 +1,18 @@
+--- a/Makefile
++++ b/Makefile
+@@ -621,12 +621,12 @@ KBUILD_CFLAGS	+= $(call cc-disable-warni
+ KBUILD_CFLAGS	+= $(call cc-disable-warning,frame-address,)
+ 
+ ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+-KBUILD_CFLAGS	+= -Os
++KBUILD_CFLAGS	+= -Os $(EXTRA_OPTIMIZATION)
+ else
+ ifdef CONFIG_PROFILE_ALL_BRANCHES
+-KBUILD_CFLAGS	+= -O2
++KBUILD_CFLAGS	+= -O2 $(EXTRA_OPTIMIZATION)
+ else
+-KBUILD_CFLAGS   += -O2
++KBUILD_CFLAGS   += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
+ endif
+ endif
+ 
diff --git a/target/linux/generic/patches-4.4/202-reduce_module_size.patch b/target/linux/generic/patches-4.4/202-reduce_module_size.patch
new file mode 100644
index 0000000000..d68c463648
--- /dev/null
+++ b/target/linux/generic/patches-4.4/202-reduce_module_size.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -403,7 +403,7 @@ KBUILD_CFLAGS_KERNEL :=
+ KBUILD_AFLAGS   := -D__ASSEMBLY__ $(call cc-option,-fno-PIE)
+ KBUILD_AFLAGS_MODULE  := -DMODULE
+ KBUILD_CFLAGS_MODULE  := -DMODULE
+-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
++KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
+ 
+ # Read KERNELRELEASE from include/config/kernel.release (if it exists)
+ KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
diff --git a/target/linux/generic/patches-4.4/203-kallsyms_uncompressed.patch b/target/linux/generic/patches-4.4/203-kallsyms_uncompressed.patch
new file mode 100644
index 0000000000..cf8a447bbc
--- /dev/null
+++ b/target/linux/generic/patches-4.4/203-kallsyms_uncompressed.patch
@@ -0,0 +1,108 @@
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -58,6 +58,7 @@ static struct addr_range percpu_range =
+ static struct sym_entry *table;
+ static unsigned int table_size, table_cnt;
+ static int all_symbols = 0;
++static int uncompressed = 0;
+ static int absolute_percpu = 0;
+ static char symbol_prefix_char = '\0';
+ static unsigned long long kernel_start_addr = 0;
+@@ -403,6 +404,9 @@ static void write_src(void)
+ 
+ 	free(markers);
+ 
++	if (uncompressed)
++		return;
++
+ 	output_label("kallsyms_token_table");
+ 	off = 0;
+ 	for (i = 0; i < 256; i++) {
+@@ -461,6 +465,9 @@ static void *find_token(unsigned char *s
+ {
+ 	int i;
+ 
++	if (uncompressed)
++		return NULL;
++
+ 	for (i = 0; i < len - 1; i++) {
+ 		if (str[i] == token[0] && str[i+1] == token[1])
+ 			return &str[i];
+@@ -533,6 +540,9 @@ static void optimize_result(void)
+ {
+ 	int i, best;
+ 
++	if (uncompressed)
++		return;
++
+ 	/* using the '\0' symbol last allows compress_symbols to use standard
+ 	 * fast string functions */
+ 	for (i = 255; i >= 0; i--) {
+@@ -703,7 +713,9 @@ int main(int argc, char **argv)
+ 			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+ 				const char *p = &argv[i][14];
+ 				kernel_start_addr = strtoull(p, NULL, 16);
+-			} else
++			} else if (strcmp(argv[i], "--uncompressed") == 0)
++				uncompressed = 1;
++			else
+ 				usage();
+ 		}
+ 	} else if (argc != 1)
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1345,6 +1345,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
+ 	  the unaligned access emulation.
+ 	  see arch/parisc/kernel/unaligned.c for reference
+ 
++config KALLSYMS_UNCOMPRESSED
++	bool "Keep kallsyms uncompressed"
++	depends on KALLSYMS
++	help
++		Normally kallsyms contains compressed symbols (using a token table),
++		reducing the uncompressed kernel image size. Keeping the symbol table
++		uncompressed significantly improves the size of this part in compressed
++		kernel images.
++
++		Say N unless you need compressed kernel images to be small.
++
+ config HAVE_PCSPKR_PLATFORM
+ 	bool
+ 
+--- a/scripts/link-vmlinux.sh
++++ b/scripts/link-vmlinux.sh
+@@ -90,6 +90,10 @@ kallsyms()
+ 		kallsymopt="${kallsymopt} --absolute-percpu"
+ 	fi
+ 
++	if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
++		kallsymopt="${kallsymopt} --uncompressed"
++	fi
++
+ 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
+ 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
+ 
+--- a/kernel/kallsyms.c
++++ b/kernel/kallsyms.c
+@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb
+ 	 * For every byte on the compressed symbol data, copy the table
+ 	 * entry for that byte.
+ 	 */
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	memcpy(result, data + 1, len - 1);
++	result += len - 1;
++	len = 0;
++#endif
+ 	while (len) {
+ 		tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
+ 		data++;
+@@ -141,6 +146,9 @@ tail:
+  */
+ static char kallsyms_get_symbol_type(unsigned int off)
+ {
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	return kallsyms_names[off + 1];
++#endif
+ 	/*
+ 	 * Get just the first code, look it up in the token table,
+ 	 * and return the first char from this token.
diff --git a/target/linux/generic/patches-4.4/204-module_strip.patch b/target/linux/generic/patches-4.4/204-module_strip.patch
new file mode 100644
index 0000000000..8b807da542
--- /dev/null
+++ b/target/linux/generic/patches-4.4/204-module_strip.patch
@@ -0,0 +1,194 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] build: add a hack for removing non-essential module info
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -169,9 +169,10 @@ void trim_init_extable(struct module *m)
+ 
+ /* Generic info of form tag = "info" */
+ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
+ 
+ /* For userspace: you can also call me... */
+-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
++#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias)
+ 
+ /* Soft module dependencies. See man modprobe.d for details.
+  * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
+@@ -212,12 +213,12 @@ void trim_init_extable(struct module *m)
+  * Author(s), use "Name <email>" or just "Name", for multiple
+  * authors use multiple MODULE_AUTHOR() statements/lines.
+  */
+-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
+ 
+ /* What your module does. */
+-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
+ 
+-#ifdef MODULE
++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
+ /* Creates an alias so file2alias.c can find device table. */
+ #define MODULE_DEVICE_TABLE(type, name)					\
+ extern const typeof(name) __mod_##type##__##name##_device_table		\
+@@ -244,7 +245,9 @@ extern const typeof(name) __mod_##type##
+  */
+ 
+ #if defined(MODULE) || !defined(CONFIG_SYSFS)
+-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
++#elif defined(CONFIG_MODULE_STRIPPED)
++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
+ #else
+ #define MODULE_VERSION(_version)					\
+ 	static struct module_version_attribute ___modver_attr = {	\
+@@ -266,7 +269,7 @@ extern const typeof(name) __mod_##type##
+ /* Optional firmware file (or files) needed by the module
+  * format is simply firmware file name.  Multiple firmware
+  * files require multiple MODULE_FIRMWARE() specifiers */
+-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
+ 
+ /* Given an address, look for it in the exception tables */
+ const struct exception_table_entry *search_exception_tables(unsigned long add);
+--- a/include/linux/moduleparam.h
++++ b/include/linux/moduleparam.h
+@@ -16,6 +16,16 @@
+ /* Chosen so that structs with an unsigned long line up. */
+ #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
+ 
++/* This struct is here for syntactic coherency, it is not used */
++#define __MODULE_INFO_DISABLED(name)					  \
++  struct __UNIQUE_ID(name) {}
++
++#ifdef CONFIG_MODULE_STRIPPED
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
++#else
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
++#endif
++
+ #ifdef MODULE
+ #define __MODULE_INFO(tag, name, info)					  \
+ static const char __UNIQUE_ID(name)[]					  \
+@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[]
+   = __stringify(tag) "=" info
+ #else  /* !MODULE */
+ /* This struct is here for syntactic coherency, it is not used */
+-#define __MODULE_INFO(tag, name, info)					  \
+-  struct __UNIQUE_ID(name) {}
++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
+ #endif
+ #define __MODULE_PARM_TYPE(name, _type)					  \
+   __MODULE_INFO(parmtype, name##type, #name ":" _type)
+@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[]
+ /* One for each parameter, describing how to use it.  Some files do
+    multiple of these per line, so can't just use MODULE_INFO. */
+ #define MODULE_PARM_DESC(_parm, desc) \
+-	__MODULE_INFO(parm, _parm, #_parm ":" desc)
++	__MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
+ 
+ struct kernel_param;
+ 
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -2026,6 +2026,13 @@ config MODULE_COMPRESS_XZ
+ 
+ endchoice
+ 
++config MODULE_STRIPPED
++	bool "Reduce module size"
++	depends on MODULES
++	help
++	  Remove module parameter descriptions, author info, version, aliases,
++	  device tables, etc.
++
+ endif # MODULES
+ 
+ config MODULES_TREE_LOOKUP
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2864,6 +2864,7 @@ static struct module *setup_load_info(st
+ 
+ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	const char *modmagic = get_modinfo(info, "vermagic");
+ 	int err;
+ 
+@@ -2889,6 +2890,7 @@ static int check_modinfo(struct module *
+ 		pr_warn("%s: module is from the staging directory, the quality "
+ 			"is unknown, you have been warned.\n", mod->name);
+ 	}
++#endif
+ 
+ 	/* Set up license info based on the info section */
+ 	set_license(mod, get_modinfo(info, "license"));
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -1963,7 +1963,9 @@ static void read_symbols(char *modname)
+ 		symname = remove_dot(info.strtab + sym->st_name);
+ 
+ 		handle_modversions(mod, &info, sym, symname);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		handle_moddevtable(mod, &info, sym, symname);
++#endif
+ 	}
+ 	if (!is_vmlinux(modname) ||
+ 	     (is_vmlinux(modname) && vmlinux_section_warnings))
+@@ -2107,7 +2109,9 @@ static void add_header(struct buffer *b,
+ 	buf_printf(b, "#include <linux/vermagic.h>\n");
+ 	buf_printf(b, "#include <linux/compiler.h>\n");
+ 	buf_printf(b, "\n");
++#ifndef CONFIG_MODULE_STRIPPED
+ 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
++#endif
+ 	buf_printf(b, "\n");
+ 	buf_printf(b, "__visible struct module __this_module\n");
+ 	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
+@@ -2124,16 +2128,20 @@ static void add_header(struct buffer *b,
+ 
+ static void add_intree_flag(struct buffer *b, int is_intree)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (is_intree)
+ 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
++#endif
+ }
+ 
+ static void add_staging_flag(struct buffer *b, const char *name)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	static const char *staging_dir = "drivers/staging";
+ 
+ 	if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
+ 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
++#endif
+ }
+ 
+ /* In kernel, this size is defined in linux/module.h;
+@@ -2237,11 +2245,13 @@ static void add_depends(struct buffer *b
+ 
+ static void add_srcversion(struct buffer *b, struct module *mod)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (mod->srcversion[0]) {
+ 		buf_printf(b, "\n");
+ 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ 			   mod->srcversion);
+ 	}
++#endif
+ }
+ 
+ static void write_if_changed(struct buffer *b, const char *fname)
+@@ -2475,7 +2485,9 @@ int main(int argc, char **argv)
+ 		add_staging_flag(&buf, mod->name);
+ 		err |= add_versions(&buf, mod);
+ 		add_depends(&buf, mod, modules);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		add_moddevtable(&buf, mod);
++#endif
+ 		add_srcversion(&buf, mod);
+ 
+ 		sprintf(fname, "%s.mod.c", mod->name);
diff --git a/target/linux/generic/patches-4.4/205-backtrace_module_info.patch b/target/linux/generic/patches-4.4/205-backtrace_module_info.patch
new file mode 100644
index 0000000000..0550ec4399
--- /dev/null
+++ b/target/linux/generic/patches-4.4/205-backtrace_module_info.patch
@@ -0,0 +1,36 @@
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -618,8 +618,10 @@ char *symbol_string(char *buf, char *end
+ 		    struct printf_spec spec, const char *fmt)
+ {
+ 	unsigned long value;
+-#ifdef CONFIG_KALLSYMS
+ 	char sym[KSYM_SYMBOL_LEN];
++#ifndef CONFIG_KALLSYMS
++	struct module *mod;
++	int len;
+ #endif
+ 
+ 	if (fmt[1] == 'R')
+@@ -633,15 +635,15 @@ char *symbol_string(char *buf, char *end
+ 		sprint_symbol(sym, value);
+ 	else
+ 		sprint_symbol_no_offset(sym, value);
+-
+-	return string(buf, end, sym, spec);
+ #else
+-	spec.field_width = 2 * sizeof(void *);
+-	spec.flags |= SPECIAL | SMALL | ZEROPAD;
+-	spec.base = 16;
++	len = snprintf(sym, sizeof(sym), "0x%lx", value);
+ 
+-	return number(buf, end, value, spec);
++	mod = __module_address(value);
++	if (mod)
++		snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
++			 mod->name, mod->module_core, mod->core_size);
+ #endif
++	return string(buf, end, sym, spec);
+ }
+ 
+ static noinline_for_stack
diff --git a/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch b/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch
new file mode 100644
index 0000000000..51b1d041bf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/206-mips-disable-vdso.patch
@@ -0,0 +1,21 @@
+Disable MIPS VDSO until the cache issues have been sorted out.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/arch/mips/vdso/Makefile
++++ b/arch/mips/vdso/Makefile
+@@ -28,11 +28,11 @@ aflags-vdso := $(ccflags-vdso) \
+ # the comments on that file.
+ #
+ ifndef CONFIG_CPU_MIPSR6
+-  ifeq ($(call ld-ifversion, -lt, 22500000, y),y)
+-    $(warning MIPS VDSO requires binutils >= 2.25)
++#  ifeq ($(call ld-ifversion, -lt, 22500000, y),y)
++#    $(warning MIPS VDSO requires binutils >= 2.25)
+     obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
+     ccflags-vdso += -DDISABLE_MIPS_VDSO
+-  endif
++#  endif
+ endif
+ 
+ # VDSO linker flags.
diff --git a/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch b/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch
new file mode 100644
index 0000000000..cfcd0b33a0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/207-mips-vdso-dbg-rebuild-after-genvdso.patch
@@ -0,0 +1,29 @@
+--- a/arch/mips/vdso/Makefile
++++ b/arch/mips/vdso/Makefile
+@@ -77,7 +77,7 @@ $(obj-vdso): KBUILD_AFLAGS := $(aflags-v
+ 
+ $(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi)
+ 
+-$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
++$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) $(obj)/genvdso FORCE
+ 	$(call if_changed,vdsold)
+ 
+ $(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE
+@@ -111,7 +111,7 @@ $(obj)/vdso-o32.lds: KBUILD_CPPFLAGS :=
+ $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
+ 	$(call if_changed_dep,cpp_lds_S)
+ 
+-$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE
++$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) $(obj)/genvdso FORCE
+ 	$(call if_changed,vdsold)
+ 
+ $(obj)/vdso-o32-image.c: VDSO_NAME := o32
+@@ -147,7 +147,7 @@ $(obj)/vdso-n32.lds: KBUILD_CPPFLAGS :=
+ $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
+ 	$(call if_changed_dep,cpp_lds_S)
+ 
+-$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE
++$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) $(obj)/genvdso FORCE
+ 	$(call if_changed,vdsold)
+ 
+ $(obj)/vdso-n32-image.c: VDSO_NAME := n32
diff --git a/target/linux/generic/patches-4.4/210-darwin_scripts_include.patch b/target/linux/generic/patches-4.4/210-darwin_scripts_include.patch
new file mode 100644
index 0000000000..2afeb23b52
--- /dev/null
+++ b/target/linux/generic/patches-4.4/210-darwin_scripts_include.patch
@@ -0,0 +1,3088 @@
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -22,6 +22,35 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
++#ifdef __APPLE__
++/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */
++void *memmem (const void *haystack, size_t haystack_len,
++                          const void *needle,  size_t needle_len)
++{
++  const char *begin;
++  const char *const last_possible
++    = (const char *) haystack + haystack_len - needle_len;
++
++  if (needle_len == 0)
++    /* The first occurrence of the empty string is deemed to occur at
++       the beginning of the string.  */
++    return (void *) haystack;
++
++  /* Sanity check, otherwise the loop might search through the whole
++     memory.  */
++  if (__builtin_expect (haystack_len < needle_len, 0))
++    return NULL;
++
++  for (begin = (const char *) haystack; begin <= last_possible; ++begin)
++    if (begin[0] == ((const char *) needle)[0] &&
++        !memcmp ((const void *) &begin[1],
++                 (const void *) ((const char *) needle + 1),
++                 needle_len - 1))
++      return (void *) begin;
++
++  return NULL;
++}
++#endif
+ 
+ #ifndef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+--- a/scripts/kconfig/Makefile
++++ b/scripts/kconfig/Makefile
+@@ -161,6 +161,9 @@ check-lxdialog  := $(srctree)/$(src)/lxd
+ # we really need to do so. (Do not call gcc as part of make mrproper)
+ HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+                     -DLOCALE
++ifeq ($(shell uname -s),Darwin)
++HOST_LOADLIBES  += -lncurses
++endif
+ 
+ # ===========================================================================
+ # Shared Makefile for the various kconfig executables:
+--- a/scripts/mod/mk_elfconfig.c
++++ b/scripts/mod/mk_elfconfig.c
+@@ -1,7 +1,11 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#ifndef __APPLE__
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ int
+ main(int argc, char **argv)
+--- a/scripts/mod/modpost.h
++++ b/scripts/mod/modpost.h
+@@ -7,7 +7,11 @@
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <unistd.h>
++#if !(defined(__APPLE__) || defined(__CYGWIN__))
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ #include "elfconfig.h"
+ 
+--- /dev/null
++++ b/scripts/mod/elf.h
+@@ -0,0 +1,3007 @@
++/* This file defines standard ELF types, structures, and macros.
++   Copyright (C) 1995-2012 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef _ELF_H
++#define	_ELF_H 1
++
++/* Standard ELF types.  */
++
++#include <stdint.h>
++
++/* Type for a 16-bit quantity.  */
++typedef uint16_t Elf32_Half;
++typedef uint16_t Elf64_Half;
++
++/* Types for signed and unsigned 32-bit quantities.  */
++typedef uint32_t Elf32_Word;
++typedef	int32_t  Elf32_Sword;
++typedef uint32_t Elf64_Word;
++typedef	int32_t  Elf64_Sword;
++
++/* Types for signed and unsigned 64-bit quantities.  */
++typedef uint64_t Elf32_Xword;
++typedef	int64_t  Elf32_Sxword;
++typedef uint64_t Elf64_Xword;
++typedef	int64_t  Elf64_Sxword;
++
++/* Type of addresses.  */
++typedef uint32_t Elf32_Addr;
++typedef uint64_t Elf64_Addr;
++
++/* Type of file offsets.  */
++typedef uint32_t Elf32_Off;
++typedef uint64_t Elf64_Off;
++
++/* Type for section indices, which are 16-bit quantities.  */
++typedef uint16_t Elf32_Section;
++typedef uint16_t Elf64_Section;
++
++/* Type for version symbol information.  */
++typedef Elf32_Half Elf32_Versym;
++typedef Elf64_Half Elf64_Versym;
++
++
++/* The ELF file header.  This appears at the start of every ELF file.  */
++
++#define EI_NIDENT (16)
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf32_Half	e_type;			/* Object file type */
++  Elf32_Half	e_machine;		/* Architecture */
++  Elf32_Word	e_version;		/* Object file version */
++  Elf32_Addr	e_entry;		/* Entry point virtual address */
++  Elf32_Off	e_phoff;		/* Program header table file offset */
++  Elf32_Off	e_shoff;		/* Section header table file offset */
++  Elf32_Word	e_flags;		/* Processor-specific flags */
++  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf32_Half	e_phentsize;		/* Program header table entry size */
++  Elf32_Half	e_phnum;		/* Program header table entry count */
++  Elf32_Half	e_shentsize;		/* Section header table entry size */
++  Elf32_Half	e_shnum;		/* Section header table entry count */
++  Elf32_Half	e_shstrndx;		/* Section header string table index */
++} Elf32_Ehdr;
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf64_Half	e_type;			/* Object file type */
++  Elf64_Half	e_machine;		/* Architecture */
++  Elf64_Word	e_version;		/* Object file version */
++  Elf64_Addr	e_entry;		/* Entry point virtual address */
++  Elf64_Off	e_phoff;		/* Program header table file offset */
++  Elf64_Off	e_shoff;		/* Section header table file offset */
++  Elf64_Word	e_flags;		/* Processor-specific flags */
++  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf64_Half	e_phentsize;		/* Program header table entry size */
++  Elf64_Half	e_phnum;		/* Program header table entry count */
++  Elf64_Half	e_shentsize;		/* Section header table entry size */
++  Elf64_Half	e_shnum;		/* Section header table entry count */
++  Elf64_Half	e_shstrndx;		/* Section header string table index */
++} Elf64_Ehdr;
++
++/* Fields in the e_ident array.  The EI_* macros are indices into the
++   array.  The macros under each EI_* macro are the values the byte
++   may have.  */
++
++#define EI_MAG0		0		/* File identification byte 0 index */
++#define ELFMAG0		0x7f		/* Magic number byte 0 */
++
++#define EI_MAG1		1		/* File identification byte 1 index */
++#define ELFMAG1		'E'		/* Magic number byte 1 */
++
++#define EI_MAG2		2		/* File identification byte 2 index */
++#define ELFMAG2		'L'		/* Magic number byte 2 */
++
++#define EI_MAG3		3		/* File identification byte 3 index */
++#define ELFMAG3		'F'		/* Magic number byte 3 */
++
++/* Conglomeration of the identification bytes, for easy testing as a word.  */
++#define	ELFMAG		"\177ELF"
++#define	SELFMAG		4
++
++#define EI_CLASS	4		/* File class byte index */
++#define ELFCLASSNONE	0		/* Invalid class */
++#define ELFCLASS32	1		/* 32-bit objects */
++#define ELFCLASS64	2		/* 64-bit objects */
++#define ELFCLASSNUM	3
++
++#define EI_DATA		5		/* Data encoding byte index */
++#define ELFDATANONE	0		/* Invalid data encoding */
++#define ELFDATA2LSB	1		/* 2's complement, little endian */
++#define ELFDATA2MSB	2		/* 2's complement, big endian */
++#define ELFDATANUM	3
++
++#define EI_VERSION	6		/* File version byte index */
++					/* Value must be EV_CURRENT */
++
++#define EI_OSABI	7		/* OS ABI identification */
++#define ELFOSABI_NONE		0	/* UNIX System V ABI */
++#define ELFOSABI_SYSV		0	/* Alias.  */
++#define ELFOSABI_HPUX		1	/* HP-UX */
++#define ELFOSABI_NETBSD		2	/* NetBSD.  */
++#define ELFOSABI_GNU		3	/* Object uses GNU ELF extensions.  */
++#define ELFOSABI_LINUX		ELFOSABI_GNU /* Compatibility alias.  */
++#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
++#define ELFOSABI_AIX		7	/* IBM AIX.  */
++#define ELFOSABI_IRIX		8	/* SGI Irix.  */
++#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
++#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
++#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
++#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
++#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
++#define ELFOSABI_ARM		97	/* ARM */
++#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
++
++#define EI_ABIVERSION	8		/* ABI version */
++
++#define EI_PAD		9		/* Byte index of padding bytes */
++
++/* Legal values for e_type (object file type).  */
++
++#define ET_NONE		0		/* No file type */
++#define ET_REL		1		/* Relocatable file */
++#define ET_EXEC		2		/* Executable file */
++#define ET_DYN		3		/* Shared object file */
++#define ET_CORE		4		/* Core file */
++#define	ET_NUM		5		/* Number of defined types */
++#define ET_LOOS		0xfe00		/* OS-specific range start */
++#define ET_HIOS		0xfeff		/* OS-specific range end */
++#define ET_LOPROC	0xff00		/* Processor-specific range start */
++#define ET_HIPROC	0xffff		/* Processor-specific range end */
++
++/* Legal values for e_machine (architecture).  */
++
++#define EM_NONE		 0		/* No machine */
++#define EM_M32		 1		/* AT&T WE 32100 */
++#define EM_SPARC	 2		/* SUN SPARC */
++#define EM_386		 3		/* Intel 80386 */
++#define EM_68K		 4		/* Motorola m68k family */
++#define EM_88K		 5		/* Motorola m88k family */
++#define EM_860		 7		/* Intel 80860 */
++#define EM_MIPS		 8		/* MIPS R3000 big-endian */
++#define EM_S370		 9		/* IBM System/370 */
++#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
++
++#define EM_PARISC	15		/* HPPA */
++#define EM_VPP500	17		/* Fujitsu VPP500 */
++#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
++#define EM_960		19		/* Intel 80960 */
++#define EM_PPC		20		/* PowerPC */
++#define EM_PPC64	21		/* PowerPC 64-bit */
++#define EM_S390		22		/* IBM S390 */
++
++#define EM_V800		36		/* NEC V800 series */
++#define EM_FR20		37		/* Fujitsu FR20 */
++#define EM_RH32		38		/* TRW RH-32 */
++#define EM_RCE		39		/* Motorola RCE */
++#define EM_ARM		40		/* ARM */
++#define EM_FAKE_ALPHA	41		/* Digital Alpha */
++#define EM_SH		42		/* Hitachi SH */
++#define EM_SPARCV9	43		/* SPARC v9 64-bit */
++#define EM_TRICORE	44		/* Siemens Tricore */
++#define EM_ARC		45		/* Argonaut RISC Core */
++#define EM_H8_300	46		/* Hitachi H8/300 */
++#define EM_H8_300H	47		/* Hitachi H8/300H */
++#define EM_H8S		48		/* Hitachi H8S */
++#define EM_H8_500	49		/* Hitachi H8/500 */
++#define EM_IA_64	50		/* Intel Merced */
++#define EM_MIPS_X	51		/* Stanford MIPS-X */
++#define EM_COLDFIRE	52		/* Motorola Coldfire */
++#define EM_68HC12	53		/* Motorola M68HC12 */
++#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
++#define EM_PCP		55		/* Siemens PCP */
++#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
++#define EM_NDR1		57		/* Denso NDR1 microprocessor */
++#define EM_STARCORE	58		/* Motorola Start*Core processor */
++#define EM_ME16		59		/* Toyota ME16 processor */
++#define EM_ST100	60		/* STMicroelectronic ST100 processor */
++#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
++#define EM_X86_64	62		/* AMD x86-64 architecture */
++#define EM_PDSP		63		/* Sony DSP Processor */
++
++#define EM_FX66		66		/* Siemens FX66 microcontroller */
++#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
++#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
++#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
++#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
++#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
++#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
++#define EM_SVX		73		/* Silicon Graphics SVx */
++#define EM_ST19		74		/* STMicroelectronics ST19 8 bit mc */
++#define EM_VAX		75		/* Digital VAX */
++#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
++#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
++#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
++#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
++#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
++#define EM_HUANY	81		/* Harvard University machine-independent object files */
++#define EM_PRISM	82		/* SiTera Prism */
++#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
++#define EM_FR30		84		/* Fujitsu FR30 */
++#define EM_D10V		85		/* Mitsubishi D10V */
++#define EM_D30V		86		/* Mitsubishi D30V */
++#define EM_V850		87		/* NEC v850 */
++#define EM_M32R		88		/* Mitsubishi M32R */
++#define EM_MN10300	89		/* Matsushita MN10300 */
++#define EM_MN10200	90		/* Matsushita MN10200 */
++#define EM_PJ		91		/* picoJava */
++#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
++#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
++#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
++#define EM_TILEPRO	188		/* Tilera TILEPro */
++#define EM_TILEGX	191		/* Tilera TILE-Gx */
++#define EM_NUM		192
++
++/* If it is necessary to assign new unofficial EM_* values, please
++   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
++   chances of collision with official or non-GNU unofficial values.  */
++
++#define EM_ALPHA	0x9026
++
++/* Legal values for e_version (version).  */
++
++#define EV_NONE		0		/* Invalid ELF version */
++#define EV_CURRENT	1		/* Current version */
++#define EV_NUM		2
++
++/* Section header.  */
++
++typedef struct
++{
++  Elf32_Word	sh_name;		/* Section name (string tbl index) */
++  Elf32_Word	sh_type;		/* Section type */
++  Elf32_Word	sh_flags;		/* Section flags */
++  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf32_Off	sh_offset;		/* Section file offset */
++  Elf32_Word	sh_size;		/* Section size in bytes */
++  Elf32_Word	sh_link;		/* Link to another section */
++  Elf32_Word	sh_info;		/* Additional section information */
++  Elf32_Word	sh_addralign;		/* Section alignment */
++  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
++} Elf32_Shdr;
++
++typedef struct
++{
++  Elf64_Word	sh_name;		/* Section name (string tbl index) */
++  Elf64_Word	sh_type;		/* Section type */
++  Elf64_Xword	sh_flags;		/* Section flags */
++  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf64_Off	sh_offset;		/* Section file offset */
++  Elf64_Xword	sh_size;		/* Section size in bytes */
++  Elf64_Word	sh_link;		/* Link to another section */
++  Elf64_Word	sh_info;		/* Additional section information */
++  Elf64_Xword	sh_addralign;		/* Section alignment */
++  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
++} Elf64_Shdr;
++
++/* Special section indices.  */
++
++#define SHN_UNDEF	0		/* Undefined section */
++#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
++#define SHN_LOPROC	0xff00		/* Start of processor-specific */
++#define SHN_BEFORE	0xff00		/* Order section before all others
++					   (Solaris).  */
++#define SHN_AFTER	0xff01		/* Order section after all others
++					   (Solaris).  */
++#define SHN_HIPROC	0xff1f		/* End of processor-specific */
++#define SHN_LOOS	0xff20		/* Start of OS-specific */
++#define SHN_HIOS	0xff3f		/* End of OS-specific */
++#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
++#define SHN_COMMON	0xfff2		/* Associated symbol is common */
++#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
++#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
++
++/* Legal values for sh_type (section type).  */
++
++#define SHT_NULL	  0		/* Section header table entry unused */
++#define SHT_PROGBITS	  1		/* Program data */
++#define SHT_SYMTAB	  2		/* Symbol table */
++#define SHT_STRTAB	  3		/* String table */
++#define SHT_RELA	  4		/* Relocation entries with addends */
++#define SHT_HASH	  5		/* Symbol hash table */
++#define SHT_DYNAMIC	  6		/* Dynamic linking information */
++#define SHT_NOTE	  7		/* Notes */
++#define SHT_NOBITS	  8		/* Program space with no data (bss) */
++#define SHT_REL		  9		/* Relocation entries, no addends */
++#define SHT_SHLIB	  10		/* Reserved */
++#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
++#define SHT_INIT_ARRAY	  14		/* Array of constructors */
++#define SHT_FINI_ARRAY	  15		/* Array of destructors */
++#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
++#define SHT_GROUP	  17		/* Section group */
++#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
++#define	SHT_NUM		  19		/* Number of defined types.  */
++#define SHT_LOOS	  0x60000000	/* Start OS-specific.  */
++#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes.  */
++#define SHT_GNU_HASH	  0x6ffffff6	/* GNU-style hash table.  */
++#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
++#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
++#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
++#define SHT_SUNW_move	  0x6ffffffa
++#define SHT_SUNW_COMDAT   0x6ffffffb
++#define SHT_SUNW_syminfo  0x6ffffffc
++#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
++#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
++#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
++#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
++#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
++#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
++#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
++#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
++#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
++
++/* Legal values for sh_flags (section flags).  */
++
++#define SHF_WRITE	     (1 << 0)	/* Writable */
++#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
++#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
++#define SHF_MERGE	     (1 << 4)	/* Might be merged */
++#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
++#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
++#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
++#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
++					   required */
++#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
++#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
++#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
++#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
++#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
++					   (Solaris).  */
++#define SHF_EXCLUDE	     (1 << 31)	/* Section is excluded unless
++					   referenced or allocated (Solaris).*/
++
++/* Section group handling.  */
++#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
++
++/* Symbol table entry.  */
++
++typedef struct
++{
++  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
++  Elf32_Addr	st_value;		/* Symbol value */
++  Elf32_Word	st_size;		/* Symbol size */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char	st_other;		/* Symbol visibility */
++  Elf32_Section	st_shndx;		/* Section index */
++} Elf32_Sym;
++
++typedef struct
++{
++  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char st_other;		/* Symbol visibility */
++  Elf64_Section	st_shndx;		/* Section index */
++  Elf64_Addr	st_value;		/* Symbol value */
++  Elf64_Xword	st_size;		/* Symbol size */
++} Elf64_Sym;
++
++/* The syminfo section if available contains additional information about
++   every dynamic symbol.  */
++
++typedef struct
++{
++  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf32_Half si_flags;			/* Per symbol flags */
++} Elf32_Syminfo;
++
++typedef struct
++{
++  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf64_Half si_flags;			/* Per symbol flags */
++} Elf64_Syminfo;
++
++/* Possible values for si_boundto.  */
++#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
++#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
++#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
++
++/* Possible bitmasks for si_flags.  */
++#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
++#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
++#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
++#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
++					   loaded */
++/* Syminfo version values.  */
++#define SYMINFO_NONE		0
++#define SYMINFO_CURRENT		1
++#define SYMINFO_NUM		2
++
++
++/* How to extract and insert information held in the st_info field.  */
++
++#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
++#define ELF32_ST_TYPE(val)		((val) & 0xf)
++#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
++
++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
++#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
++#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
++#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
++
++/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
++
++#define STB_LOCAL	0		/* Local symbol */
++#define STB_GLOBAL	1		/* Global symbol */
++#define STB_WEAK	2		/* Weak symbol */
++#define	STB_NUM		3		/* Number of defined types.  */
++#define STB_LOOS	10		/* Start of OS-specific */
++#define STB_GNU_UNIQUE	10		/* Unique symbol.  */
++#define STB_HIOS	12		/* End of OS-specific */
++#define STB_LOPROC	13		/* Start of processor-specific */
++#define STB_HIPROC	15		/* End of processor-specific */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_NOTYPE	0		/* Symbol type is unspecified */
++#define STT_OBJECT	1		/* Symbol is a data object */
++#define STT_FUNC	2		/* Symbol is a code object */
++#define STT_SECTION	3		/* Symbol associated with a section */
++#define STT_FILE	4		/* Symbol's name is file name */
++#define STT_COMMON	5		/* Symbol is a common data object */
++#define STT_TLS		6		/* Symbol is thread-local data object*/
++#define	STT_NUM		7		/* Number of defined types.  */
++#define STT_LOOS	10		/* Start of OS-specific */
++#define STT_GNU_IFUNC	10		/* Symbol is indirect code object */
++#define STT_HIOS	12		/* End of OS-specific */
++#define STT_LOPROC	13		/* Start of processor-specific */
++#define STT_HIPROC	15		/* End of processor-specific */
++
++
++/* Symbol table indices are found in the hash buckets and chain table
++   of a symbol hash table section.  This special index value indicates
++   the end of a chain, meaning no further symbols are found in that bucket.  */
++
++#define STN_UNDEF	0		/* End of a chain.  */
++
++
++/* How to extract and insert information held in the st_other field.  */
++
++#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
++
++/* For ELF64 the definitions are the same.  */
++#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
++
++/* Symbol visibility specification encoded in the st_other field.  */
++#define STV_DEFAULT	0		/* Default symbol visibility rules */
++#define STV_INTERNAL	1		/* Processor specific hidden class */
++#define STV_HIDDEN	2		/* Sym unavailable in other modules */
++#define STV_PROTECTED	3		/* Not preemptible, not exported */
++
++
++/* Relocation table entry without addend (in section of type SHT_REL).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++} Elf32_Rel;
++
++/* I have seen two different definitions of the Elf64_Rel and
++   Elf64_Rela structures, so we'll leave them out until Novell (or
++   whoever) gets their act together.  */
++/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++} Elf64_Rel;
++
++/* Relocation table entry with addend (in section of type SHT_RELA).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++  Elf32_Sword	r_addend;		/* Addend */
++} Elf32_Rela;
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++  Elf64_Sxword	r_addend;		/* Addend */
++} Elf64_Rela;
++
++/* How to extract and insert information held in the r_info field.  */
++
++#define ELF32_R_SYM(val)		((val) >> 8)
++#define ELF32_R_TYPE(val)		((val) & 0xff)
++#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
++
++#define ELF64_R_SYM(i)			((i) >> 32)
++#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
++#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
++
++/* Program segment header.  */
++
++typedef struct
++{
++  Elf32_Word	p_type;			/* Segment type */
++  Elf32_Off	p_offset;		/* Segment file offset */
++  Elf32_Addr	p_vaddr;		/* Segment virtual address */
++  Elf32_Addr	p_paddr;		/* Segment physical address */
++  Elf32_Word	p_filesz;		/* Segment size in file */
++  Elf32_Word	p_memsz;		/* Segment size in memory */
++  Elf32_Word	p_flags;		/* Segment flags */
++  Elf32_Word	p_align;		/* Segment alignment */
++} Elf32_Phdr;
++
++typedef struct
++{
++  Elf64_Word	p_type;			/* Segment type */
++  Elf64_Word	p_flags;		/* Segment flags */
++  Elf64_Off	p_offset;		/* Segment file offset */
++  Elf64_Addr	p_vaddr;		/* Segment virtual address */
++  Elf64_Addr	p_paddr;		/* Segment physical address */
++  Elf64_Xword	p_filesz;		/* Segment size in file */
++  Elf64_Xword	p_memsz;		/* Segment size in memory */
++  Elf64_Xword	p_align;		/* Segment alignment */
++} Elf64_Phdr;
++
++/* Special value for e_phnum.  This indicates that the real number of
++   program headers is too large to fit into e_phnum.  Instead the real
++   value is in the field sh_info of section 0.  */
++
++#define PN_XNUM		0xffff
++
++/* Legal values for p_type (segment type).  */
++
++#define	PT_NULL		0		/* Program header table entry unused */
++#define PT_LOAD		1		/* Loadable program segment */
++#define PT_DYNAMIC	2		/* Dynamic linking information */
++#define PT_INTERP	3		/* Program interpreter */
++#define PT_NOTE		4		/* Auxiliary information */
++#define PT_SHLIB	5		/* Reserved */
++#define PT_PHDR		6		/* Entry for header table itself */
++#define PT_TLS		7		/* Thread-local storage segment */
++#define	PT_NUM		8		/* Number of defined types */
++#define PT_LOOS		0x60000000	/* Start of OS-specific */
++#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
++#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
++#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
++#define PT_LOSUNW	0x6ffffffa
++#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
++#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
++#define PT_HISUNW	0x6fffffff
++#define PT_HIOS		0x6fffffff	/* End of OS-specific */
++#define PT_LOPROC	0x70000000	/* Start of processor-specific */
++#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
++
++/* Legal values for p_flags (segment flags).  */
++
++#define PF_X		(1 << 0)	/* Segment is executable */
++#define PF_W		(1 << 1)	/* Segment is writable */
++#define PF_R		(1 << 2)	/* Segment is readable */
++#define PF_MASKOS	0x0ff00000	/* OS-specific */
++#define PF_MASKPROC	0xf0000000	/* Processor-specific */
++
++/* Legal values for note segment descriptor types for core files. */
++
++#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
++#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
++#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
++#define NT_PRXREG	4		/* Contains copy of prxregset struct */
++#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
++#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
++#define NT_AUXV		6		/* Contains copy of auxv array */
++#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
++#define NT_ASRS		8		/* Contains copy of asrset struct */
++#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
++#define NT_PSINFO	13		/* Contains copy of psinfo struct */
++#define NT_PRCRED	14		/* Contains copy of prcred struct */
++#define NT_UTSNAME	15		/* Contains copy of utsname struct */
++#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
++#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
++#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct */
++#define NT_PRXFPREG	0x46e62b7f	/* Contains copy of user_fxsr_struct */
++#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
++#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
++#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
++#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
++#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
++#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
++
++/* Legal values for the note segment descriptor types for object files.  */
++
++#define NT_VERSION	1		/* Contains a version string.  */
++
++
++/* Dynamic section entry.  */
++
++typedef struct
++{
++  Elf32_Sword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf32_Word d_val;			/* Integer value */
++      Elf32_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf32_Dyn;
++
++typedef struct
++{
++  Elf64_Sxword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf64_Xword d_val;		/* Integer value */
++      Elf64_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf64_Dyn;
++
++/* Legal values for d_tag (dynamic entry type).  */
++
++#define DT_NULL		0		/* Marks end of dynamic section */
++#define DT_NEEDED	1		/* Name of needed library */
++#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
++#define DT_PLTGOT	3		/* Processor defined value */
++#define DT_HASH		4		/* Address of symbol hash table */
++#define DT_STRTAB	5		/* Address of string table */
++#define DT_SYMTAB	6		/* Address of symbol table */
++#define DT_RELA		7		/* Address of Rela relocs */
++#define DT_RELASZ	8		/* Total size of Rela relocs */
++#define DT_RELAENT	9		/* Size of one Rela reloc */
++#define DT_STRSZ	10		/* Size of string table */
++#define DT_SYMENT	11		/* Size of one symbol table entry */
++#define DT_INIT		12		/* Address of init function */
++#define DT_FINI		13		/* Address of termination function */
++#define DT_SONAME	14		/* Name of shared object */
++#define DT_RPATH	15		/* Library search path (deprecated) */
++#define DT_SYMBOLIC	16		/* Start symbol search here */
++#define DT_REL		17		/* Address of Rel relocs */
++#define DT_RELSZ	18		/* Total size of Rel relocs */
++#define DT_RELENT	19		/* Size of one Rel reloc */
++#define DT_PLTREL	20		/* Type of reloc in PLT */
++#define DT_DEBUG	21		/* For debugging; unspecified */
++#define DT_TEXTREL	22		/* Reloc might modify .text */
++#define DT_JMPREL	23		/* Address of PLT relocs */
++#define	DT_BIND_NOW	24		/* Process relocations of object */
++#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
++#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
++#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
++#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
++#define DT_RUNPATH	29		/* Library search path */
++#define DT_FLAGS	30		/* Flags for the object being loaded */
++#define DT_ENCODING	32		/* Start of encoded range */
++#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
++#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
++#define	DT_NUM		34		/* Number used */
++#define DT_LOOS		0x6000000d	/* Start of OS-specific */
++#define DT_HIOS		0x6ffff000	/* End of OS-specific */
++#define DT_LOPROC	0x70000000	/* Start of processor-specific */
++#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
++#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
++
++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
++   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
++   approach.  */
++#define DT_VALRNGLO	0x6ffffd00
++#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
++#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
++#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
++#define DT_CHECKSUM	0x6ffffdf8
++#define DT_PLTPADSZ	0x6ffffdf9
++#define DT_MOVEENT	0x6ffffdfa
++#define DT_MOVESZ	0x6ffffdfb
++#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
++#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
++					   the following DT_* entry.  */
++#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
++#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
++#define DT_VALRNGHI	0x6ffffdff
++#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
++#define DT_VALNUM 12
++
++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
++   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
++
++   If any adjustment is made to the ELF object after it has been
++   built these entries will need to be adjusted.  */
++#define DT_ADDRRNGLO	0x6ffffe00
++#define DT_GNU_HASH	0x6ffffef5	/* GNU-style hash table.  */
++#define DT_TLSDESC_PLT	0x6ffffef6
++#define DT_TLSDESC_GOT	0x6ffffef7
++#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
++#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
++#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
++#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
++#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
++#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
++#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
++#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
++#define DT_ADDRRNGHI	0x6ffffeff
++#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
++#define DT_ADDRNUM 11
++
++/* The versioning entry types.  The next are defined as part of the
++   GNU extension.  */
++#define DT_VERSYM	0x6ffffff0
++
++#define DT_RELACOUNT	0x6ffffff9
++#define DT_RELCOUNT	0x6ffffffa
++
++/* These were chosen by Sun.  */
++#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
++#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
++					   table */
++#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
++#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
++					   versions */
++#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
++#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
++#define DT_VERSIONTAGNUM 16
++
++/* Sun added these machine-independent extensions in the "processor-specific"
++   range.  Be compatible.  */
++#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
++#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
++#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
++#define DT_EXTRANUM	3
++
++/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
++#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
++#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
++#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
++#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
++#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
++
++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
++   entry in the dynamic section.  */
++#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
++#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
++#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
++#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
++#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
++#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
++#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
++#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
++#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
++#define DF_1_TRANS	0x00000200
++#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
++#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
++#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
++#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
++#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
++#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
++#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
++
++/* Flags for the feature selection in DT_FEATURE_1.  */
++#define DTF_1_PARINIT	0x00000001
++#define DTF_1_CONFEXP	0x00000002
++
++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
++#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
++#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
++					   generally available.  */
++
++/* Version definition sections.  */
++
++typedef struct
++{
++  Elf32_Half	vd_version;		/* Version revision */
++  Elf32_Half	vd_flags;		/* Version information */
++  Elf32_Half	vd_ndx;			/* Version Index */
++  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vd_hash;		/* Version name hash value */
++  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf32_Verdef;
++
++typedef struct
++{
++  Elf64_Half	vd_version;		/* Version revision */
++  Elf64_Half	vd_flags;		/* Version information */
++  Elf64_Half	vd_ndx;			/* Version Index */
++  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vd_hash;		/* Version name hash value */
++  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf64_Verdef;
++
++
++/* Legal values for vd_version (version revision).  */
++#define VER_DEF_NONE	0		/* No version */
++#define VER_DEF_CURRENT	1		/* Current version */
++#define VER_DEF_NUM	2		/* Given version number */
++
++/* Legal values for vd_flags (version information flags).  */
++#define VER_FLG_BASE	0x1		/* Version definition of file itself */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++/* Versym symbol index values.  */
++#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
++#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
++#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
++#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
++
++/* Auxialiary version information.  */
++
++typedef struct
++{
++  Elf32_Word	vda_name;		/* Version or dependency names */
++  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf32_Verdaux;
++
++typedef struct
++{
++  Elf64_Word	vda_name;		/* Version or dependency names */
++  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf64_Verdaux;
++
++
++/* Version dependency section.  */
++
++typedef struct
++{
++  Elf32_Half	vn_version;		/* Version of structure */
++  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf32_Verneed;
++
++typedef struct
++{
++  Elf64_Half	vn_version;		/* Version of structure */
++  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf64_Verneed;
++
++
++/* Legal values for vn_version (version revision).  */
++#define VER_NEED_NONE	 0		/* No version */
++#define VER_NEED_CURRENT 1		/* Current version */
++#define VER_NEED_NUM	 2		/* Given version number */
++
++/* Auxiliary needed version information.  */
++
++typedef struct
++{
++  Elf32_Word	vna_hash;		/* Hash value of dependency name */
++  Elf32_Half	vna_flags;		/* Dependency specific information */
++  Elf32_Half	vna_other;		/* Unused */
++  Elf32_Word	vna_name;		/* Dependency name string offset */
++  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf32_Vernaux;
++
++typedef struct
++{
++  Elf64_Word	vna_hash;		/* Hash value of dependency name */
++  Elf64_Half	vna_flags;		/* Dependency specific information */
++  Elf64_Half	vna_other;		/* Unused */
++  Elf64_Word	vna_name;		/* Dependency name string offset */
++  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf64_Vernaux;
++
++
++/* Legal values for vna_flags.  */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++
++/* Auxiliary vector.  */
++
++/* This vector is normally only used by the program interpreter.  The
++   usual definition in an ABI supplement uses the name auxv_t.  The
++   vector is not usually defined in a standard <elf.h> file, but it
++   can't hurt.  We rename it to avoid conflicts.  The sizes of these
++   types are an arrangement between the exec server and the program
++   interpreter, so we don't fully specify them here.  */
++
++typedef struct
++{
++  uint32_t a_type;		/* Entry type */
++  union
++    {
++      uint32_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf32_auxv_t;
++
++typedef struct
++{
++  uint64_t a_type;		/* Entry type */
++  union
++    {
++      uint64_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf64_auxv_t;
++
++/* Legal values for a_type (entry type).  */
++
++#define AT_NULL		0		/* End of vector */
++#define AT_IGNORE	1		/* Entry should be ignored */
++#define AT_EXECFD	2		/* File descriptor of program */
++#define AT_PHDR		3		/* Program headers for program */
++#define AT_PHENT	4		/* Size of program header entry */
++#define AT_PHNUM	5		/* Number of program headers */
++#define AT_PAGESZ	6		/* System page size */
++#define AT_BASE		7		/* Base address of interpreter */
++#define AT_FLAGS	8		/* Flags */
++#define AT_ENTRY	9		/* Entry point of program */
++#define AT_NOTELF	10		/* Program is not ELF */
++#define AT_UID		11		/* Real uid */
++#define AT_EUID		12		/* Effective uid */
++#define AT_GID		13		/* Real gid */
++#define AT_EGID		14		/* Effective gid */
++#define AT_CLKTCK	17		/* Frequency of times() */
++
++/* Some more special a_type values describing the hardware.  */
++#define AT_PLATFORM	15		/* String identifying platform.  */
++#define AT_HWCAP	16		/* Machine dependent hints about
++					   processor capabilities.  */
++
++/* This entry gives some information about the FPU initialization
++   performed by the kernel.  */
++#define AT_FPUCW	18		/* Used FPU control word.  */
++
++/* Cache block sizes.  */
++#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
++#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
++#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
++
++/* A special ignored value for PPC, used by the kernel to control the
++   interpretation of the AUXV. Must be > 16.  */
++#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
++
++#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
++
++#define AT_BASE_PLATFORM 24		/* String identifying real platforms.*/
++
++#define AT_RANDOM	25		/* Address of 16 random bytes.  */
++
++#define AT_EXECFN	31		/* Filename of executable.  */
++
++/* Pointer to the global system page used for system calls and other
++   nice things.  */
++#define AT_SYSINFO	32
++#define AT_SYSINFO_EHDR	33
++
++/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
++   log2 of line size; mask those to get cache size.  */
++#define AT_L1I_CACHESHAPE	34
++#define AT_L1D_CACHESHAPE	35
++#define AT_L2_CACHESHAPE	36
++#define AT_L3_CACHESHAPE	37
++
++/* Note section contents.  Each entry in the note section begins with
++   a header of a fixed form.  */
++
++typedef struct
++{
++  Elf32_Word n_namesz;			/* Length of the note's name.  */
++  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf32_Word n_type;			/* Type of the note.  */
++} Elf32_Nhdr;
++
++typedef struct
++{
++  Elf64_Word n_namesz;			/* Length of the note's name.  */
++  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf64_Word n_type;			/* Type of the note.  */
++} Elf64_Nhdr;
++
++/* Known names of notes.  */
++
++/* Solaris entries in the note section have this name.  */
++#define ELF_NOTE_SOLARIS	"SUNW Solaris"
++
++/* Note entries for GNU systems have this name.  */
++#define ELF_NOTE_GNU		"GNU"
++
++
++/* Defined types of notes for Solaris.  */
++
++/* Value of descriptor (one word) is desired pagesize for the binary.  */
++#define ELF_NOTE_PAGESIZE_HINT	1
++
++
++/* Defined note types for GNU systems.  */
++
++/* ABI information.  The descriptor consists of words:
++   word 0: OS descriptor
++   word 1: major version of the ABI
++   word 2: minor version of the ABI
++   word 3: subminor version of the ABI
++*/
++#define NT_GNU_ABI_TAG	1
++#define ELF_NOTE_ABI	NT_GNU_ABI_TAG /* Old name.  */
++
++/* Known OSes.  These values can appear in word 0 of an
++   NT_GNU_ABI_TAG note section entry.  */
++#define ELF_NOTE_OS_LINUX	0
++#define ELF_NOTE_OS_GNU		1
++#define ELF_NOTE_OS_SOLARIS2	2
++#define ELF_NOTE_OS_FREEBSD	3
++
++/* Synthetic hwcap information.  The descriptor begins with two words:
++   word 0: number of entries
++   word 1: bitmask of enabled entries
++   Then follow variable-length entries, one byte followed by a
++   '\0'-terminated hwcap name string.  The byte gives the bit
++   number to test if enabled, (1U << bit) & bitmask.  */
++#define NT_GNU_HWCAP	2
++
++/* Build ID bits as generated by ld --build-id.
++   The descriptor consists of any nonzero number of bytes.  */
++#define NT_GNU_BUILD_ID	3
++
++/* Version note generated by GNU gold containing a version string.  */
++#define NT_GNU_GOLD_VERSION	4
++
++
++/* Move records.  */
++typedef struct
++{
++  Elf32_Xword m_value;		/* Symbol value.  */
++  Elf32_Word m_info;		/* Size and index.  */
++  Elf32_Word m_poffset;		/* Symbol offset.  */
++  Elf32_Half m_repeat;		/* Repeat count.  */
++  Elf32_Half m_stride;		/* Stride info.  */
++} Elf32_Move;
++
++typedef struct
++{
++  Elf64_Xword m_value;		/* Symbol value.  */
++  Elf64_Xword m_info;		/* Size and index.  */
++  Elf64_Xword m_poffset;	/* Symbol offset.  */
++  Elf64_Half m_repeat;		/* Repeat count.  */
++  Elf64_Half m_stride;		/* Stride info.  */
++} Elf64_Move;
++
++/* Macro to construct move records.  */
++#define ELF32_M_SYM(info)	((info) >> 8)
++#define ELF32_M_SIZE(info)	((unsigned char) (info))
++#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
++
++#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
++#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
++#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
++
++
++/* Motorola 68k specific definitions.  */
++
++/* Values for Elf32_Ehdr.e_flags.  */
++#define EF_CPU32	0x00810000
++
++/* m68k relocs.  */
++
++#define R_68K_NONE	0		/* No reloc */
++#define R_68K_32	1		/* Direct 32 bit  */
++#define R_68K_16	2		/* Direct 16 bit  */
++#define R_68K_8		3		/* Direct 8 bit  */
++#define R_68K_PC32	4		/* PC relative 32 bit */
++#define R_68K_PC16	5		/* PC relative 16 bit */
++#define R_68K_PC8	6		/* PC relative 8 bit */
++#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
++#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
++#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
++#define R_68K_GOT32O	10		/* 32 bit GOT offset */
++#define R_68K_GOT16O	11		/* 16 bit GOT offset */
++#define R_68K_GOT8O	12		/* 8 bit GOT offset */
++#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
++#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
++#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
++#define R_68K_PLT32O	16		/* 32 bit PLT offset */
++#define R_68K_PLT16O	17		/* 16 bit PLT offset */
++#define R_68K_PLT8O	18		/* 8 bit PLT offset */
++#define R_68K_COPY	19		/* Copy symbol at runtime */
++#define R_68K_GLOB_DAT	20		/* Create GOT entry */
++#define R_68K_JMP_SLOT	21		/* Create PLT entry */
++#define R_68K_RELATIVE	22		/* Adjust by program base */
++#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
++#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
++#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
++#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
++#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
++#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
++#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
++#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
++#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
++#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
++#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
++#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
++#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
++#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
++#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
++/* Keep this the last entry.  */
++#define R_68K_NUM	43
++
++/* Intel 80386 specific definitions.  */
++
++/* i386 relocs.  */
++
++#define R_386_NONE	   0		/* No reloc */
++#define R_386_32	   1		/* Direct 32 bit  */
++#define R_386_PC32	   2		/* PC relative 32 bit */
++#define R_386_GOT32	   3		/* 32 bit GOT entry */
++#define R_386_PLT32	   4		/* 32 bit PLT address */
++#define R_386_COPY	   5		/* Copy symbol at runtime */
++#define R_386_GLOB_DAT	   6		/* Create GOT entry */
++#define R_386_JMP_SLOT	   7		/* Create PLT entry */
++#define R_386_RELATIVE	   8		/* Adjust by program base */
++#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
++#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
++#define R_386_32PLT	   11
++#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
++#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
++					   block offset */
++#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
++					   offset */
++#define R_386_TLS_LE	   17		/* Offset relative to static TLS
++					   block */
++#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
++					   general dynamic thread local data */
++#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
++					   local dynamic thread local data
++					   in LE code */
++#define R_386_16	   20
++#define R_386_PC16	   21
++#define R_386_8		   22
++#define R_386_PC8	   23
++#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
++					   thread local data */
++#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
++#define R_386_TLS_GD_CALL  26		/* Relocation for call to
++					   __tls_get_addr() */
++#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
++#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
++					   thread local data in LE code */
++#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
++#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
++					   __tls_get_addr() in LDM code */
++#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
++#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
++#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
++					   block offset */
++#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
++					   TLS block */
++#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
++#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
++#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
++/* 38? */
++#define R_386_TLS_GOTDESC  39		/* GOT offset for TLS descriptor.  */
++#define R_386_TLS_DESC_CALL 40		/* Marker of call through TLS
++					   descriptor for
++					   relaxation.  */
++#define R_386_TLS_DESC     41		/* TLS descriptor containing
++					   pointer to code and to
++					   argument, returning the TLS
++					   offset for the symbol.  */
++#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
++/* Keep this the last entry.  */
++#define R_386_NUM	   43
++
++/* SUN SPARC specific definitions.  */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
++
++/* Values for Elf64_Ehdr.e_flags.  */
++
++#define EF_SPARCV9_MM		3
++#define EF_SPARCV9_TSO		0
++#define EF_SPARCV9_PSO		1
++#define EF_SPARCV9_RMO		2
++#define EF_SPARC_LEDATA		0x800000 /* little endian data */
++#define EF_SPARC_EXT_MASK	0xFFFF00
++#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
++#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
++#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
++#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
++
++/* SPARC relocs.  */
++
++#define R_SPARC_NONE		0	/* No reloc */
++#define R_SPARC_8		1	/* Direct 8 bit */
++#define R_SPARC_16		2	/* Direct 16 bit */
++#define R_SPARC_32		3	/* Direct 32 bit */
++#define R_SPARC_DISP8		4	/* PC relative 8 bit */
++#define R_SPARC_DISP16		5	/* PC relative 16 bit */
++#define R_SPARC_DISP32		6	/* PC relative 32 bit */
++#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
++#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
++#define R_SPARC_HI22		9	/* High 22 bit */
++#define R_SPARC_22		10	/* Direct 22 bit */
++#define R_SPARC_13		11	/* Direct 13 bit */
++#define R_SPARC_LO10		12	/* Truncated 10 bit */
++#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
++#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
++#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
++#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
++#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
++#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
++#define R_SPARC_COPY		19	/* Copy symbol at runtime */
++#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
++#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
++#define R_SPARC_RELATIVE	22	/* Adjust by program base */
++#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
++
++/* Additional Sparc64 relocs.  */
++
++#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
++#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
++#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
++#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
++#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
++#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
++#define R_SPARC_10		30	/* Direct 10 bit */
++#define R_SPARC_11		31	/* Direct 11 bit */
++#define R_SPARC_64		32	/* Direct 64 bit */
++#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
++#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
++#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
++#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
++#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
++#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
++#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
++#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
++#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
++#define R_SPARC_GLOB_JMP	42	/* was part of v9 ABI but was removed */
++#define R_SPARC_7		43	/* Direct 7 bit */
++#define R_SPARC_5		44	/* Direct 5 bit */
++#define R_SPARC_6		45	/* Direct 6 bit */
++#define R_SPARC_DISP64		46	/* PC relative 64 bit */
++#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
++#define R_SPARC_HIX22		48	/* High 22 bit complemented */
++#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
++#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
++#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
++#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
++#define R_SPARC_REGISTER	53	/* Global register usage */
++#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
++#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
++#define R_SPARC_TLS_GD_HI22	56
++#define R_SPARC_TLS_GD_LO10	57
++#define R_SPARC_TLS_GD_ADD	58
++#define R_SPARC_TLS_GD_CALL	59
++#define R_SPARC_TLS_LDM_HI22	60
++#define R_SPARC_TLS_LDM_LO10	61
++#define R_SPARC_TLS_LDM_ADD	62
++#define R_SPARC_TLS_LDM_CALL	63
++#define R_SPARC_TLS_LDO_HIX22	64
++#define R_SPARC_TLS_LDO_LOX10	65
++#define R_SPARC_TLS_LDO_ADD	66
++#define R_SPARC_TLS_IE_HI22	67
++#define R_SPARC_TLS_IE_LO10	68
++#define R_SPARC_TLS_IE_LD	69
++#define R_SPARC_TLS_IE_LDX	70
++#define R_SPARC_TLS_IE_ADD	71
++#define R_SPARC_TLS_LE_HIX22	72
++#define R_SPARC_TLS_LE_LOX10	73
++#define R_SPARC_TLS_DTPMOD32	74
++#define R_SPARC_TLS_DTPMOD64	75
++#define R_SPARC_TLS_DTPOFF32	76
++#define R_SPARC_TLS_DTPOFF64	77
++#define R_SPARC_TLS_TPOFF32	78
++#define R_SPARC_TLS_TPOFF64	79
++#define R_SPARC_GOTDATA_HIX22	80
++#define R_SPARC_GOTDATA_LOX10	81
++#define R_SPARC_GOTDATA_OP_HIX22	82
++#define R_SPARC_GOTDATA_OP_LOX10	83
++#define R_SPARC_GOTDATA_OP	84
++#define R_SPARC_H34		85
++#define R_SPARC_SIZE32		86
++#define R_SPARC_SIZE64		87
++#define R_SPARC_WDISP10		88
++#define R_SPARC_JMP_IREL	248
++#define R_SPARC_IRELATIVE	249
++#define R_SPARC_GNU_VTINHERIT	250
++#define R_SPARC_GNU_VTENTRY	251
++#define R_SPARC_REV32		252
++/* Keep this the last entry.  */
++#define R_SPARC_NUM		253
++
++/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
++
++#define DT_SPARC_REGISTER 0x70000001
++#define DT_SPARC_NUM	2
++
++/* MIPS R3000 specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
++#define EF_MIPS_PIC	    2		/* Contains PIC code */
++#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
++#define EF_MIPS_XGOT	    8
++#define EF_MIPS_64BIT_WHIRL 16
++#define EF_MIPS_ABI2	    32
++#define EF_MIPS_ABI_ON32    64
++#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
++
++/* Legal values for MIPS architecture level.  */
++
++#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
++#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
++#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
++#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
++#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
++#define EF_MIPS_ARCH_32	    0x60000000	/* MIPS32 code.  */
++#define EF_MIPS_ARCH_64	    0x70000000	/* MIPS64 code.  */
++
++/* The following are non-official names and should not be used.  */
++
++#define E_MIPS_ARCH_1	  0x00000000	/* -mips1 code.  */
++#define E_MIPS_ARCH_2	  0x10000000	/* -mips2 code.  */
++#define E_MIPS_ARCH_3	  0x20000000	/* -mips3 code.  */
++#define E_MIPS_ARCH_4	  0x30000000	/* -mips4 code.  */
++#define E_MIPS_ARCH_5	  0x40000000	/* -mips5 code.  */
++#define E_MIPS_ARCH_32	  0x60000000	/* MIPS32 code.  */
++#define E_MIPS_ARCH_64	  0x70000000	/* MIPS64 code.  */
++
++/* Special section indices.  */
++
++#define SHN_MIPS_ACOMMON    0xff00	/* Allocated common symbols */
++#define SHN_MIPS_TEXT	    0xff01	/* Allocated test symbols.  */
++#define SHN_MIPS_DATA	    0xff02	/* Allocated data symbols.  */
++#define SHN_MIPS_SCOMMON    0xff03	/* Small common symbols */
++#define SHN_MIPS_SUNDEFINED 0xff04	/* Small undefined symbols */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
++#define SHT_MIPS_MSYM	       0x70000001
++#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
++#define SHT_MIPS_GPTAB	       0x70000003 /* Global data area sizes */
++#define SHT_MIPS_UCODE	       0x70000004 /* Reserved for SGI/MIPS compilers */
++#define SHT_MIPS_DEBUG	       0x70000005 /* MIPS ECOFF debugging information*/
++#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
++#define SHT_MIPS_PACKAGE       0x70000007
++#define SHT_MIPS_PACKSYM       0x70000008
++#define SHT_MIPS_RELD	       0x70000009
++#define SHT_MIPS_IFACE         0x7000000b
++#define SHT_MIPS_CONTENT       0x7000000c
++#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
++#define SHT_MIPS_SHDR	       0x70000010
++#define SHT_MIPS_FDESC	       0x70000011
++#define SHT_MIPS_EXTSYM	       0x70000012
++#define SHT_MIPS_DENSE	       0x70000013
++#define SHT_MIPS_PDESC	       0x70000014
++#define SHT_MIPS_LOCSYM	       0x70000015
++#define SHT_MIPS_AUXSYM	       0x70000016
++#define SHT_MIPS_OPTSYM	       0x70000017
++#define SHT_MIPS_LOCSTR	       0x70000018
++#define SHT_MIPS_LINE	       0x70000019
++#define SHT_MIPS_RFDESC	       0x7000001a
++#define SHT_MIPS_DELTASYM      0x7000001b
++#define SHT_MIPS_DELTAINST     0x7000001c
++#define SHT_MIPS_DELTACLASS    0x7000001d
++#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
++#define SHT_MIPS_DELTADECL     0x7000001f
++#define SHT_MIPS_SYMBOL_LIB    0x70000020
++#define SHT_MIPS_EVENTS	       0x70000021 /* Event section.  */
++#define SHT_MIPS_TRANSLATE     0x70000022
++#define SHT_MIPS_PIXIE	       0x70000023
++#define SHT_MIPS_XLATE	       0x70000024
++#define SHT_MIPS_XLATE_DEBUG   0x70000025
++#define SHT_MIPS_WHIRL	       0x70000026
++#define SHT_MIPS_EH_REGION     0x70000027
++#define SHT_MIPS_XLATE_OLD     0x70000028
++#define SHT_MIPS_PDR_EXCEPTION 0x70000029
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_MIPS_GPREL	 0x10000000	/* Must be part of global data area */
++#define SHF_MIPS_MERGE	 0x20000000
++#define SHF_MIPS_ADDR	 0x40000000
++#define SHF_MIPS_STRINGS 0x80000000
++#define SHF_MIPS_NOSTRIP 0x08000000
++#define SHF_MIPS_LOCAL	 0x04000000
++#define SHF_MIPS_NAMES	 0x02000000
++#define SHF_MIPS_NODUPE	 0x01000000
++
++
++/* Symbol tables.  */
++
++/* MIPS specific values for `st_other'.  */
++#define STO_MIPS_DEFAULT		0x0
++#define STO_MIPS_INTERNAL		0x1
++#define STO_MIPS_HIDDEN			0x2
++#define STO_MIPS_PROTECTED		0x3
++#define STO_MIPS_PLT			0x8
++#define STO_MIPS_SC_ALIGN_UNUSED	0xff
++
++/* MIPS specific values for `st_info'.  */
++#define STB_MIPS_SPLIT_COMMON		13
++
++/* Entries found in sections of type SHT_MIPS_GPTAB.  */
++
++typedef union
++{
++  struct
++    {
++      Elf32_Word gt_current_g_value;	/* -G value used for compilation */
++      Elf32_Word gt_unused;		/* Not used */
++    } gt_header;			/* First entry in section */
++  struct
++    {
++      Elf32_Word gt_g_value;		/* If this value were used for -G */
++      Elf32_Word gt_bytes;		/* This many bytes would be used */
++    } gt_entry;				/* Subsequent entries in section */
++} Elf32_gptab;
++
++/* Entry found in sections of type SHT_MIPS_REGINFO.  */
++
++typedef struct
++{
++  Elf32_Word	ri_gprmask;		/* General registers used */
++  Elf32_Word	ri_cprmask[4];		/* Coprocessor registers used */
++  Elf32_Sword	ri_gp_value;		/* $gp register value */
++} Elf32_RegInfo;
++
++/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
++
++typedef struct
++{
++  unsigned char kind;		/* Determines interpretation of the
++				   variable part of descriptor.  */
++  unsigned char size;		/* Size of descriptor, including header.  */
++  Elf32_Section section;	/* Section header index of section affected,
++				   0 for global options.  */
++  Elf32_Word info;		/* Kind-specific information.  */
++} Elf_Options;
++
++/* Values for `kind' field in Elf_Options.  */
++
++#define ODK_NULL	0	/* Undefined.  */
++#define ODK_REGINFO	1	/* Register usage information.  */
++#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
++#define ODK_PAD		3	/* Section padding options.  */
++#define ODK_HWPATCH	4	/* Hardware workarounds performed */
++#define ODK_FILL	5	/* record the fill value used by the linker. */
++#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
++#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
++#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
++
++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
++
++#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
++#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
++#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
++#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
++#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
++#define OEX_PRECISEFP	OEX_FPDBUG
++#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
++
++#define OEX_FPU_INVAL	0x10
++#define OEX_FPU_DIV0	0x08
++#define OEX_FPU_OFLO	0x04
++#define OEX_FPU_UFLO	0x02
++#define OEX_FPU_INEX	0x01
++
++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
++
++#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
++#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
++#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
++#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
++
++#define OPAD_PREFIX	0x1
++#define OPAD_POSTFIX	0x2
++#define OPAD_SYMBOL	0x4
++
++/* Entry found in `.options' section.  */
++
++typedef struct
++{
++  Elf32_Word hwp_flags1;	/* Extra flags.  */
++  Elf32_Word hwp_flags2;	/* Extra flags.  */
++} Elf_Options_Hw;
++
++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
++
++#define OHWA0_R4KEOP_CHECKED	0x00000001
++#define OHWA1_R4KEOP_CLEAN	0x00000002
++
++/* MIPS relocs.  */
++
++#define R_MIPS_NONE		0	/* No reloc */
++#define R_MIPS_16		1	/* Direct 16 bit */
++#define R_MIPS_32		2	/* Direct 32 bit */
++#define R_MIPS_REL32		3	/* PC relative 32 bit */
++#define R_MIPS_26		4	/* Direct 26 bit shifted */
++#define R_MIPS_HI16		5	/* High 16 bit */
++#define R_MIPS_LO16		6	/* Low 16 bit */
++#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
++#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
++#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
++#define R_MIPS_PC16		10	/* PC relative 16 bit */
++#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
++#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
++
++#define R_MIPS_SHIFT5		16
++#define R_MIPS_SHIFT6		17
++#define R_MIPS_64		18
++#define R_MIPS_GOT_DISP		19
++#define R_MIPS_GOT_PAGE		20
++#define R_MIPS_GOT_OFST		21
++#define R_MIPS_GOT_HI16		22
++#define R_MIPS_GOT_LO16		23
++#define R_MIPS_SUB		24
++#define R_MIPS_INSERT_A		25
++#define R_MIPS_INSERT_B		26
++#define R_MIPS_DELETE		27
++#define R_MIPS_HIGHER		28
++#define R_MIPS_HIGHEST		29
++#define R_MIPS_CALL_HI16	30
++#define R_MIPS_CALL_LO16	31
++#define R_MIPS_SCN_DISP		32
++#define R_MIPS_REL16		33
++#define R_MIPS_ADD_IMMEDIATE	34
++#define R_MIPS_PJUMP		35
++#define R_MIPS_RELGOT		36
++#define R_MIPS_JALR		37
++#define R_MIPS_TLS_DTPMOD32	38	/* Module number 32 bit */
++#define R_MIPS_TLS_DTPREL32	39	/* Module-relative offset 32 bit */
++#define R_MIPS_TLS_DTPMOD64	40	/* Module number 64 bit */
++#define R_MIPS_TLS_DTPREL64	41	/* Module-relative offset 64 bit */
++#define R_MIPS_TLS_GD		42	/* 16 bit GOT offset for GD */
++#define R_MIPS_TLS_LDM		43	/* 16 bit GOT offset for LDM */
++#define R_MIPS_TLS_DTPREL_HI16	44	/* Module-relative offset, high 16 bits */
++#define R_MIPS_TLS_DTPREL_LO16	45	/* Module-relative offset, low 16 bits */
++#define R_MIPS_TLS_GOTTPREL	46	/* 16 bit GOT offset for IE */
++#define R_MIPS_TLS_TPREL32	47	/* TP-relative offset, 32 bit */
++#define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
++#define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
++#define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
++#define R_MIPS_GLOB_DAT		51
++#define R_MIPS_COPY		126
++#define R_MIPS_JUMP_SLOT        127
++/* Keep this the last entry.  */
++#define R_MIPS_NUM		128
++
++/* Legal values for p_type field of Elf32_Phdr.  */
++
++#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
++#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
++#define PT_MIPS_OPTIONS 0x70000002
++
++/* Special program header types.  */
++
++#define PF_MIPS_LOCAL	0x10000000
++
++/* Legal values for d_tag field of Elf32_Dyn.  */
++
++#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
++#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
++#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
++#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
++#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
++#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
++#define DT_MIPS_MSYM	     0x70000007
++#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
++#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
++#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
++#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
++#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
++#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
++#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
++#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
++#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
++#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
++#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
++#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
++						DT_MIPS_DELTA_CLASS.  */
++#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
++						DT_MIPS_DELTA_INSTANCE.  */
++#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
++					     DT_MIPS_DELTA_RELOC.  */
++#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
++					   relocations refer to.  */
++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
++					   DT_MIPS_DELTA_SYM.  */
++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
++					     class declaration.  */
++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
++						DT_MIPS_DELTA_CLASSSYM.  */
++#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
++#define DT_MIPS_PIXIE_INIT   0x70000023
++#define DT_MIPS_SYMBOL_LIB   0x70000024
++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
++#define DT_MIPS_LOCAL_GOTIDX 0x70000026
++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
++#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
++#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
++						    function stored in GOT.  */
++#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
++					   by rld on dlopen() calls.  */
++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
++#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
++#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
++/* The address of .got.plt in an executable using the new non-PIC ABI.  */
++#define DT_MIPS_PLTGOT	     0x70000032
++/* The base of the PLT in an executable using the new non-PIC ABI if that
++   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
++   value.  */
++#define DT_MIPS_RWPLT        0x70000034
++#define DT_MIPS_NUM	     0x35
++
++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
++
++#define RHF_NONE		   0		/* No flags */
++#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
++#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
++#define RHF_NO_MOVE		   (1 << 3)
++#define RHF_SGI_ONLY		   (1 << 4)
++#define RHF_GUARANTEE_INIT	   (1 << 5)
++#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
++#define RHF_GUARANTEE_START_INIT   (1 << 7)
++#define RHF_PIXIE		   (1 << 8)
++#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
++#define RHF_REQUICKSTART	   (1 << 10)
++#define RHF_REQUICKSTARTED	   (1 << 11)
++#define RHF_CORD		   (1 << 12)
++#define RHF_NO_UNRES_UNDEF	   (1 << 13)
++#define RHF_RLD_ORDER_SAFE	   (1 << 14)
++
++/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
++
++typedef struct
++{
++  Elf32_Word l_name;		/* Name (string table index) */
++  Elf32_Word l_time_stamp;	/* Timestamp */
++  Elf32_Word l_checksum;	/* Checksum */
++  Elf32_Word l_version;		/* Interface version */
++  Elf32_Word l_flags;		/* Flags */
++} Elf32_Lib;
++
++typedef struct
++{
++  Elf64_Word l_name;		/* Name (string table index) */
++  Elf64_Word l_time_stamp;	/* Timestamp */
++  Elf64_Word l_checksum;	/* Checksum */
++  Elf64_Word l_version;		/* Interface version */
++  Elf64_Word l_flags;		/* Flags */
++} Elf64_Lib;
++
++
++/* Legal values for l_flags.  */
++
++#define LL_NONE		  0
++#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
++#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
++#define LL_REQUIRE_MINOR  (1 << 2)
++#define LL_EXPORTS	  (1 << 3)
++#define LL_DELAY_LOAD	  (1 << 4)
++#define LL_DELTA	  (1 << 5)
++
++/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
++
++typedef Elf32_Addr Elf32_Conflict;
++
++
++/* HPPA specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
++#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
++#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
++#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
++#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
++					      prediction.  */
++#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
++#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
++
++/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
++
++#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
++#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
++#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
++
++/* Additional section indeces.  */
++
++#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
++					      symbols in ANSI C.  */
++#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
++#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
++#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
++#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
++#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
++
++#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
++#define STT_HP_STUB		(STT_LOOS + 0x2)
++
++/* HPPA relocs.  */
++
++#define R_PARISC_NONE		0	/* No reloc.  */
++#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
++#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
++#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
++#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
++#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
++#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
++#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
++#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
++#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
++#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
++#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
++#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
++#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
++#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
++#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
++#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
++#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
++#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
++#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
++#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
++#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
++#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
++#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
++#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
++#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
++#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fdesc address.  */
++#define R_PARISC_PLABEL14R	70	/* Right 14 bits of fdesc address.  */
++#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
++#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
++#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
++#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
++#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
++#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
++#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
++#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
++#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
++#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
++#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
++#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
++#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
++#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
++#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LORESERVE	128
++#define R_PARISC_COPY		128	/* Copy relocation.  */
++#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
++#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
++#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
++#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
++#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
++#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
++#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
++#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
++#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_GNU_VTENTRY	232
++#define R_PARISC_GNU_VTINHERIT	233
++#define R_PARISC_TLS_GD21L	234	/* GD 21-bit left.  */
++#define R_PARISC_TLS_GD14R	235	/* GD 14-bit right.  */
++#define R_PARISC_TLS_GDCALL	236	/* GD call to __t_g_a.  */
++#define R_PARISC_TLS_LDM21L	237	/* LD module 21-bit left.  */
++#define R_PARISC_TLS_LDM14R	238	/* LD module 14-bit right.  */
++#define R_PARISC_TLS_LDMCALL	239	/* LD module call to __t_g_a.  */
++#define R_PARISC_TLS_LDO21L	240	/* LD offset 21-bit left.  */
++#define R_PARISC_TLS_LDO14R	241	/* LD offset 14-bit right.  */
++#define R_PARISC_TLS_DTPMOD32	242	/* DTP module 32-bit.  */
++#define R_PARISC_TLS_DTPMOD64	243	/* DTP module 64-bit.  */
++#define R_PARISC_TLS_DTPOFF32	244	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_DTPOFF64	245	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L
++#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R
++#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L
++#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R
++#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32
++#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64
++#define R_PARISC_HIRESERVE	255
++
++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PT_HP_TLS		(PT_LOOS + 0x0)
++#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
++#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
++#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
++#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
++#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
++#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
++#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
++#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
++#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
++#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
++#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
++#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
++#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
++#define PT_HP_STACK		(PT_LOOS + 0x14)
++
++#define PT_PARISC_ARCHEXT	0x70000000
++#define PT_PARISC_UNWIND	0x70000001
++
++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PF_PARISC_SBP		0x08000000
++
++#define PF_HP_PAGE_SIZE		0x00100000
++#define PF_HP_FAR_SHARED	0x00200000
++#define PF_HP_NEAR_SHARED	0x00400000
++#define PF_HP_CODE		0x01000000
++#define PF_HP_MODIFY		0x02000000
++#define PF_HP_LAZYSWAP		0x04000000
++#define PF_HP_SBP		0x08000000
++
++
++/* Alpha specific definitions.  */
++
++/* Legal values for e_flags field of Elf64_Ehdr.  */
++
++#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
++#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
++
++/* Legal values for sh_type field of Elf64_Shdr.  */
++
++/* These two are primerily concerned with ECOFF debugging info.  */
++#define SHT_ALPHA_DEBUG		0x70000001
++#define SHT_ALPHA_REGINFO	0x70000002
++
++/* Legal values for sh_flags field of Elf64_Shdr.  */
++
++#define SHF_ALPHA_GPREL		0x10000000
++
++/* Legal values for st_other field of Elf64_Sym.  */
++#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
++#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
++
++/* Alpha relocs.  */
++
++#define R_ALPHA_NONE		0	/* No reloc */
++#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
++#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
++#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
++#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
++#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
++#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
++#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
++#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
++#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
++#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
++#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
++#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
++#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
++#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
++#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
++#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
++#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
++#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
++#define R_ALPHA_TLS_GD_HI	28
++#define R_ALPHA_TLSGD		29
++#define R_ALPHA_TLS_LDM		30
++#define R_ALPHA_DTPMOD64	31
++#define R_ALPHA_GOTDTPREL	32
++#define R_ALPHA_DTPREL64	33
++#define R_ALPHA_DTPRELHI	34
++#define R_ALPHA_DTPRELLO	35
++#define R_ALPHA_DTPREL16	36
++#define R_ALPHA_GOTTPREL	37
++#define R_ALPHA_TPREL64		38
++#define R_ALPHA_TPRELHI		39
++#define R_ALPHA_TPRELLO		40
++#define R_ALPHA_TPREL16		41
++/* Keep this the last entry.  */
++#define R_ALPHA_NUM		46
++
++/* Magic values of the LITUSE relocation addend.  */
++#define LITUSE_ALPHA_ADDR	0
++#define LITUSE_ALPHA_BASE	1
++#define LITUSE_ALPHA_BYTOFF	2
++#define LITUSE_ALPHA_JSR	3
++#define LITUSE_ALPHA_TLS_GD	4
++#define LITUSE_ALPHA_TLS_LDM	5
++
++/* Legal values for d_tag of Elf64_Dyn.  */
++#define DT_ALPHA_PLTRO		(DT_LOPROC + 0)
++#define DT_ALPHA_NUM		1
++
++/* PowerPC specific declarations */
++
++/* Values for Elf32/64_Ehdr.e_flags.  */
++#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
++
++/* Cygnus local bits below */
++#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
++#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
++						   flag */
++
++/* PowerPC relocations defined by the ABIs */
++#define R_PPC_NONE		0
++#define R_PPC_ADDR32		1	/* 32bit absolute address */
++#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
++#define R_PPC_ADDR16		3	/* 16bit absolute address */
++#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
++#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
++#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
++#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
++#define R_PPC_ADDR14_BRTAKEN	8
++#define R_PPC_ADDR14_BRNTAKEN	9
++#define R_PPC_REL24		10	/* PC relative 26 bit */
++#define R_PPC_REL14		11	/* PC relative 16 bit */
++#define R_PPC_REL14_BRTAKEN	12
++#define R_PPC_REL14_BRNTAKEN	13
++#define R_PPC_GOT16		14
++#define R_PPC_GOT16_LO		15
++#define R_PPC_GOT16_HI		16
++#define R_PPC_GOT16_HA		17
++#define R_PPC_PLTREL24		18
++#define R_PPC_COPY		19
++#define R_PPC_GLOB_DAT		20
++#define R_PPC_JMP_SLOT		21
++#define R_PPC_RELATIVE		22
++#define R_PPC_LOCAL24PC		23
++#define R_PPC_UADDR32		24
++#define R_PPC_UADDR16		25
++#define R_PPC_REL32		26
++#define R_PPC_PLT32		27
++#define R_PPC_PLTREL32		28
++#define R_PPC_PLT16_LO		29
++#define R_PPC_PLT16_HI		30
++#define R_PPC_PLT16_HA		31
++#define R_PPC_SDAREL16		32
++#define R_PPC_SECTOFF		33
++#define R_PPC_SECTOFF_LO	34
++#define R_PPC_SECTOFF_HI	35
++#define R_PPC_SECTOFF_HA	36
++
++/* PowerPC relocations defined for the TLS access ABI.  */
++#define R_PPC_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
++#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
++#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
++#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
++#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
++#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
++#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
++#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
++#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
++#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
++
++/* The remaining relocs are from the Embedded ELF ABI, and are not
++   in the SVR4 ELF ABI.  */
++#define R_PPC_EMB_NADDR32	101
++#define R_PPC_EMB_NADDR16	102
++#define R_PPC_EMB_NADDR16_LO	103
++#define R_PPC_EMB_NADDR16_HI	104
++#define R_PPC_EMB_NADDR16_HA	105
++#define R_PPC_EMB_SDAI16	106
++#define R_PPC_EMB_SDA2I16	107
++#define R_PPC_EMB_SDA2REL	108
++#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
++#define R_PPC_EMB_MRKREF	110
++#define R_PPC_EMB_RELSEC16	111
++#define R_PPC_EMB_RELST_LO	112
++#define R_PPC_EMB_RELST_HI	113
++#define R_PPC_EMB_RELST_HA	114
++#define R_PPC_EMB_BIT_FLD	115
++#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
++
++/* Diab tool relocations.  */
++#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
++#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
++#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
++#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
++#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
++#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC_IRELATIVE		248
++
++/* GNU relocs used in PIC code sequences.  */
++#define R_PPC_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC_REL16_LO		250	/* half16   (sym+add-.)@l */
++#define R_PPC_REL16_HI		251	/* half16   (sym+add-.)@h */
++#define R_PPC_REL16_HA		252	/* half16   (sym+add-.)@ha */
++
++/* This is a phony reloc to handle any old fashioned TOC16 references
++   that may still be in object files.  */
++#define R_PPC_TOC16		255
++
++/* PowerPC specific values for the Dyn d_tag field.  */
++#define DT_PPC_GOT		(DT_LOPROC + 0)
++#define DT_PPC_NUM		1
++
++/* PowerPC64 relocations defined by the ABIs */
++#define R_PPC64_NONE		R_PPC_NONE
++#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
++#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
++#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
++#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
++#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
++#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
++#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
++#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
++#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
++#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
++#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
++#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
++#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
++#define R_PPC64_GOT16		R_PPC_GOT16
++#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
++#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
++#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
++
++#define R_PPC64_COPY		R_PPC_COPY
++#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
++#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
++#define R_PPC64_RELATIVE	R_PPC_RELATIVE
++
++#define R_PPC64_UADDR32		R_PPC_UADDR32
++#define R_PPC64_UADDR16		R_PPC_UADDR16
++#define R_PPC64_REL32		R_PPC_REL32
++#define R_PPC64_PLT32		R_PPC_PLT32
++#define R_PPC64_PLTREL32	R_PPC_PLTREL32
++#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
++#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
++#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
++
++#define R_PPC64_SECTOFF		R_PPC_SECTOFF
++#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
++#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
++#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
++#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
++#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
++#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
++#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
++#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
++#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
++#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
++#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
++#define R_PPC64_PLT64		45 /* doubleword64 L + A */
++#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
++#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
++#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
++#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
++#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
++#define R_PPC64_TOC		51 /* doubleword64 .TOC */
++#define R_PPC64_PLTGOT16	52 /* half16* M + A */
++#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
++#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
++#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
++
++#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
++#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
++#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
++#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
++#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
++#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
++#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
++#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
++#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
++#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
++#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
++
++/* PowerPC64 relocations defined for the TLS access ABI.  */
++#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
++#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
++#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
++#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
++#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
++#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
++#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
++#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
++#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
++#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
++#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC64_JMP_IREL	247
++#define R_PPC64_IRELATIVE	248
++#define R_PPC64_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC64_REL16_LO	250	/* half16   (sym+add-.)@l */
++#define R_PPC64_REL16_HI	251	/* half16   (sym+add-.)@h */
++#define R_PPC64_REL16_HA	252	/* half16   (sym+add-.)@ha */
++
++/* PowerPC64 specific values for the Dyn d_tag field.  */
++#define DT_PPC64_GLINK  (DT_LOPROC + 0)
++#define DT_PPC64_OPD	(DT_LOPROC + 1)
++#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
++#define DT_PPC64_NUM    3
++
++
++/* ARM specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_ARM_RELEXEC		0x01
++#define EF_ARM_HASENTRY		0x02
++#define EF_ARM_INTERWORK	0x04
++#define EF_ARM_APCS_26		0x08
++#define EF_ARM_APCS_FLOAT	0x10
++#define EF_ARM_PIC		0x20
++#define EF_ARM_ALIGN8		0x40 /* 8-bit structure alignment is in use */
++#define EF_ARM_NEW_ABI		0x80
++#define EF_ARM_OLD_ABI		0x100
++#define EF_ARM_SOFT_FLOAT	0x200
++#define EF_ARM_VFP_FLOAT	0x400
++#define EF_ARM_MAVERICK_FLOAT	0x800
++
++
++/* Other constants defined in the ARM ELF spec. version B-01.  */
++/* NB. These conflict with values defined above.  */
++#define EF_ARM_SYMSARESORTED	0x04
++#define EF_ARM_DYNSYMSUSESEGIDX	0x08
++#define EF_ARM_MAPSYMSFIRST	0x10
++#define EF_ARM_EABIMASK		0XFF000000
++
++/* Constants defined in AAELF.  */
++#define EF_ARM_BE8	    0x00800000
++#define EF_ARM_LE8	    0x00400000
++
++#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK)
++#define EF_ARM_EABI_UNKNOWN	0x00000000
++#define EF_ARM_EABI_VER1	0x01000000
++#define EF_ARM_EABI_VER2	0x02000000
++#define EF_ARM_EABI_VER3	0x03000000
++#define EF_ARM_EABI_VER4	0x04000000
++#define EF_ARM_EABI_VER5	0x05000000
++
++/* Additional symbol types for Thumb.  */
++#define STT_ARM_TFUNC		STT_LOPROC /* A Thumb function.  */
++#define STT_ARM_16BIT		STT_HIPROC /* A Thumb label.  */
++
++/* ARM-specific values for sh_flags */
++#define SHF_ARM_ENTRYSECT	0x10000000 /* Section contains an entry point */
++#define SHF_ARM_COMDEF		0x80000000 /* Section may be multiply defined
++					      in the input to a link step.  */
++
++/* ARM-specific program header flags */
++#define PF_ARM_SB		0x10000000 /* Segment contains the location
++					      addressed by the static base. */
++#define PF_ARM_PI		0x20000000 /* Position-independent segment.  */
++#define PF_ARM_ABS		0x40000000 /* Absolute segment.  */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
++#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
++#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
++
++
++/* ARM relocs.  */
++
++#define R_ARM_NONE		0	/* No reloc */
++#define R_ARM_PC24		1	/* PC relative 26 bit branch */
++#define R_ARM_ABS32		2	/* Direct 32 bit  */
++#define R_ARM_REL32		3	/* PC relative 32 bit */
++#define R_ARM_PC13		4
++#define R_ARM_ABS16		5	/* Direct 16 bit */
++#define R_ARM_ABS12		6	/* Direct 12 bit */
++#define R_ARM_THM_ABS5		7
++#define R_ARM_ABS8		8	/* Direct 8 bit */
++#define R_ARM_SBREL32		9
++#define R_ARM_THM_PC22		10
++#define R_ARM_THM_PC8		11
++#define R_ARM_AMP_VCALL9	12
++#define R_ARM_SWI24		13	/* Obsolete static relocation.  */
++#define R_ARM_TLS_DESC		13      /* Dynamic relocation.  */
++#define R_ARM_THM_SWI8		14
++#define R_ARM_XPC25		15
++#define R_ARM_THM_XPC22		16
++#define R_ARM_TLS_DTPMOD32	17	/* ID of module containing symbol */
++#define R_ARM_TLS_DTPOFF32	18	/* Offset in TLS block */
++#define R_ARM_TLS_TPOFF32	19	/* Offset in static TLS block */
++#define R_ARM_COPY		20	/* Copy symbol at runtime */
++#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
++#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
++#define R_ARM_RELATIVE		23	/* Adjust by program base */
++#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
++#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
++#define R_ARM_GOT32		26	/* 32 bit GOT entry */
++#define R_ARM_PLT32		27	/* 32 bit PLT address */
++#define R_ARM_ALU_PCREL_7_0	32
++#define R_ARM_ALU_PCREL_15_8	33
++#define R_ARM_ALU_PCREL_23_15	34
++#define R_ARM_LDR_SBREL_11_0	35
++#define R_ARM_ALU_SBREL_19_12	36
++#define R_ARM_ALU_SBREL_27_20	37
++#define R_ARM_TLS_GOTDESC	90
++#define R_ARM_TLS_CALL		91
++#define R_ARM_TLS_DESCSEQ	92
++#define R_ARM_THM_TLS_CALL	93
++#define R_ARM_GNU_VTENTRY	100
++#define R_ARM_GNU_VTINHERIT	101
++#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
++#define R_ARM_THM_PC9		103	/* thumb conditional branch */
++#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
++					   thread local data */
++#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
++					   thread local data */
++#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
++					   block */
++#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
++					   static TLS block offset */
++#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
++					   TLS block */
++#define	R_ARM_THM_TLS_DESCSEQ	129
++#define R_ARM_IRELATIVE		160
++#define R_ARM_RXPC25		249
++#define R_ARM_RSBREL32		250
++#define R_ARM_THM_RPC22		251
++#define R_ARM_RREL32		252
++#define R_ARM_RABS22		253
++#define R_ARM_RPC24		254
++#define R_ARM_RBASE		255
++/* Keep this the last entry.  */
++#define R_ARM_NUM		256
++
++/* IA-64 specific declarations.  */
++
++/* Processor specific flags for the Ehdr e_flags field.  */
++#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
++#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
++#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
++#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
++#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
++#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
++#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
++
++/* Processor specific flags for the Phdr p_flags field.  */
++#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
++#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
++
++/* Processor specific flags for the Shdr sh_flags field.  */
++#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
++#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Dyn d_tag field.  */
++#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
++#define DT_IA_64_NUM		1
++
++/* IA-64 relocations.  */
++#define R_IA64_NONE		0x00	/* none */
++#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
++#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
++#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
++#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
++#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
++#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
++#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
++#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
++#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
++#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
++#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
++#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
++#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
++#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
++#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
++#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
++#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
++#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
++#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
++#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
++#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
++#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
++#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
++#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
++#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
++#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
++#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
++#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
++#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
++#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
++#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
++#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
++#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
++#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
++#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
++#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
++#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
++#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
++#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
++#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
++#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
++#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
++#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
++#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
++#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
++#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
++#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
++#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
++#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
++#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
++#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
++#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
++#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
++#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
++#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
++#define R_IA64_COPY		0x84	/* copy relocation */
++#define R_IA64_SUB		0x85	/* Addend and symbol difference */
++#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
++#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
++#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
++#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
++#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
++#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
++#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
++#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
++#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
++#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
++#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
++#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
++#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
++#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
++#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
++#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
++
++/* SH specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_SH_MACH_MASK		0x1f
++#define EF_SH_UNKNOWN		0x0
++#define EF_SH1			0x1
++#define EF_SH2			0x2
++#define EF_SH3			0x3
++#define EF_SH_DSP		0x4
++#define EF_SH3_DSP		0x5
++#define EF_SH4AL_DSP		0x6
++#define EF_SH3E			0x8
++#define EF_SH4			0x9
++#define EF_SH2E			0xb
++#define EF_SH4A			0xc
++#define EF_SH2A			0xd
++#define EF_SH4_NOFPU		0x10
++#define EF_SH4A_NOFPU		0x11
++#define EF_SH4_NOMMU_NOFPU	0x12
++#define EF_SH2A_NOFPU		0x13
++#define EF_SH3_NOMMU		0x14
++#define EF_SH2A_SH4_NOFPU	0x15
++#define EF_SH2A_SH3_NOFPU	0x16
++#define EF_SH2A_SH4		0x17
++#define EF_SH2A_SH3E		0x18
++
++/* SH relocs.  */
++#define	R_SH_NONE		0
++#define	R_SH_DIR32		1
++#define	R_SH_REL32		2
++#define	R_SH_DIR8WPN		3
++#define	R_SH_IND12W		4
++#define	R_SH_DIR8WPL		5
++#define	R_SH_DIR8WPZ		6
++#define	R_SH_DIR8BP		7
++#define	R_SH_DIR8W		8
++#define	R_SH_DIR8L		9
++#define	R_SH_SWITCH16		25
++#define	R_SH_SWITCH32		26
++#define	R_SH_USES		27
++#define	R_SH_COUNT		28
++#define	R_SH_ALIGN		29
++#define	R_SH_CODE		30
++#define	R_SH_DATA		31
++#define	R_SH_LABEL		32
++#define	R_SH_SWITCH8		33
++#define	R_SH_GNU_VTINHERIT	34
++#define	R_SH_GNU_VTENTRY	35
++#define	R_SH_TLS_GD_32		144
++#define	R_SH_TLS_LD_32		145
++#define	R_SH_TLS_LDO_32		146
++#define	R_SH_TLS_IE_32		147
++#define	R_SH_TLS_LE_32		148
++#define	R_SH_TLS_DTPMOD32	149
++#define	R_SH_TLS_DTPOFF32	150
++#define	R_SH_TLS_TPOFF32	151
++#define	R_SH_GOT32		160
++#define	R_SH_PLT32		161
++#define	R_SH_COPY		162
++#define	R_SH_GLOB_DAT		163
++#define	R_SH_JMP_SLOT		164
++#define	R_SH_RELATIVE		165
++#define	R_SH_GOTOFF		166
++#define	R_SH_GOTPC		167
++/* Keep this the last entry.  */
++#define	R_SH_NUM		256
++
++/* S/390 specific definitions.  */
++
++/* Valid values for the e_flags field.  */
++
++#define EF_S390_HIGH_GPRS    0x00000001  /* High GPRs kernel facility needed.  */
++
++/* Additional s390 relocs */
++
++#define R_390_NONE		0	/* No reloc.  */
++#define R_390_8			1	/* Direct 8 bit.  */
++#define R_390_12		2	/* Direct 12 bit.  */
++#define R_390_16		3	/* Direct 16 bit.  */
++#define R_390_32		4	/* Direct 32 bit.  */
++#define R_390_PC32		5	/* PC relative 32 bit.	*/
++#define R_390_GOT12		6	/* 12 bit GOT offset.  */
++#define R_390_GOT32		7	/* 32 bit GOT offset.  */
++#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
++#define R_390_COPY		9	/* Copy symbol at runtime.  */
++#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
++#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
++#define R_390_RELATIVE		12	/* Adjust by program base.  */
++#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
++#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
++#define R_390_GOT16		15	/* 16 bit GOT offset.  */
++#define R_390_PC16		16	/* PC relative 16 bit.	*/
++#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
++#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
++#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
++#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
++#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
++#define R_390_64		22	/* Direct 64 bit.  */
++#define R_390_PC64		23	/* PC relative 64 bit.	*/
++#define R_390_GOT64		24	/* 64 bit GOT offset.  */
++#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
++#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
++#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
++#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
++#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
++#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
++#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
++#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
++#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
++#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
++#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
++#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
++#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
++#define R_390_TLS_GDCALL	38	/* Tag for function call in general
++					   dynamic TLS code. */
++#define R_390_TLS_LDCALL	39	/* Tag for function call in local
++					   dynamic TLS code. */
++#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
++					   thread local data.  */
++#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
++					  thread local data.  */
++#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
++					   block offset. */
++#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
++#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
++#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
++					   block.  */
++#define R_390_20		57	/* Direct 20 bit.  */
++#define R_390_GOT20		58	/* 20 bit GOT offset.  */
++#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
++#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
++/* Keep this the last entry.  */
++#define R_390_NUM		62
++
++
++/* CRIS relocations.  */
++#define R_CRIS_NONE		0
++#define R_CRIS_8		1
++#define R_CRIS_16		2
++#define R_CRIS_32		3
++#define R_CRIS_8_PCREL		4
++#define R_CRIS_16_PCREL		5
++#define R_CRIS_32_PCREL		6
++#define R_CRIS_GNU_VTINHERIT	7
++#define R_CRIS_GNU_VTENTRY	8
++#define R_CRIS_COPY		9
++#define R_CRIS_GLOB_DAT		10
++#define R_CRIS_JUMP_SLOT	11
++#define R_CRIS_RELATIVE		12
++#define R_CRIS_16_GOT		13
++#define R_CRIS_32_GOT		14
++#define R_CRIS_16_GOTPLT	15
++#define R_CRIS_32_GOTPLT	16
++#define R_CRIS_32_GOTREL	17
++#define R_CRIS_32_PLT_GOTREL	18
++#define R_CRIS_32_PLT_PCREL	19
++
++#define R_CRIS_NUM		20
++
++
++/* AMD x86-64 relocations.  */
++#define R_X86_64_NONE		0	/* No reloc */
++#define R_X86_64_64		1	/* Direct 64 bit  */
++#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
++#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
++#define R_X86_64_PLT32		4	/* 32 bit PLT address */
++#define R_X86_64_COPY		5	/* Copy symbol at runtime */
++#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
++#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
++#define R_X86_64_RELATIVE	8	/* Adjust by program base */
++#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
++					   offset to GOT */
++#define R_X86_64_32		10	/* Direct 32 bit zero extended */
++#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
++#define R_X86_64_16		12	/* Direct 16 bit zero extended */
++#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
++#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
++#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
++#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
++#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
++#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
++#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
++					   to two GOT entries for GD symbol */
++#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
++					   to two GOT entries for LD symbol */
++#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
++#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
++					   to GOT entry for IE symbol */
++#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
++#define R_X86_64_PC64		24	/* PC relative 64 bit */
++#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
++#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
++					   offset to GOT */
++#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
++#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
++					   to GOT entry */
++#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
++#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
++#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
++					   to PLT entry */
++#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
++#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
++#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
++#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
++					   descriptor.  */
++#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
++#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
++#define R_X86_64_RELATIVE64	38	/* 64-bit adjust by program base */
++
++#define R_X86_64_NUM		39
++
++
++/* AM33 relocations.  */
++#define R_MN10300_NONE		0	/* No reloc.  */
++#define R_MN10300_32		1	/* Direct 32 bit.  */
++#define R_MN10300_16		2	/* Direct 16 bit.  */
++#define R_MN10300_8		3	/* Direct 8 bit.  */
++#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
++#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
++#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
++#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
++#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
++#define R_MN10300_24		9	/* Direct 24 bit.  */
++#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
++#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
++#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
++#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
++#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
++#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
++#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
++#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
++#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
++#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
++#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
++#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
++
++#define R_MN10300_NUM		24
++
++
++/* M32R relocs.  */
++#define R_M32R_NONE		0	/* No reloc. */
++#define R_M32R_16		1	/* Direct 16 bit. */
++#define R_M32R_32		2	/* Direct 32 bit. */
++#define R_M32R_24		3	/* Direct 24 bit. */
++#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
++#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
++#define R_M32R_LO16		9	/* Low 16 bit. */
++#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
++#define R_M32R_GNU_VTINHERIT	11
++#define R_M32R_GNU_VTENTRY	12
++/* M32R relocs use SHT_RELA.  */
++#define R_M32R_16_RELA		33	/* Direct 16 bit. */
++#define R_M32R_32_RELA		34	/* Direct 32 bit. */
++#define R_M32R_24_RELA		35	/* Direct 24 bit. */
++#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
++#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
++#define R_M32R_LO16_RELA	41	/* Low 16 bit */
++#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
++#define R_M32R_RELA_GNU_VTINHERIT	43
++#define R_M32R_RELA_GNU_VTENTRY	44
++#define R_M32R_REL32		45	/* PC relative 32 bit.  */
++
++#define R_M32R_GOT24		48	/* 24 bit GOT entry */
++#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
++#define R_M32R_COPY		50	/* Copy symbol at runtime */
++#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
++#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
++#define R_M32R_RELATIVE		53	/* Adjust by program base */
++#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
++#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
++#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
++					   low */
++#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
++					   low */
++#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
++#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
++					   GOT with unsigned low */
++#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
++					   GOT with signed low */
++#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
++					   GOT */
++#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
++					   with unsigned low */
++#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
++					   with signed low */
++#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
++#define R_M32R_NUM		256	/* Keep this the last entry. */
++
++
++/* TILEPro relocations.  */
++#define R_TILEPRO_NONE		0	/* No reloc */
++#define R_TILEPRO_32		1	/* Direct 32 bit */
++#define R_TILEPRO_16		2	/* Direct 16 bit */
++#define R_TILEPRO_8		3	/* Direct 8 bit */
++#define R_TILEPRO_32_PCREL	4	/* PC relative 32 bit */
++#define R_TILEPRO_16_PCREL	5	/* PC relative 16 bit */
++#define R_TILEPRO_8_PCREL	6	/* PC relative 8 bit */
++#define R_TILEPRO_LO16		7	/* Low 16 bit */
++#define R_TILEPRO_HI16		8	/* High 16 bit */
++#define R_TILEPRO_HA16		9	/* High 16 bit, adjusted */
++#define R_TILEPRO_COPY		10	/* Copy relocation */
++#define R_TILEPRO_GLOB_DAT	11	/* Create GOT entry */
++#define R_TILEPRO_JMP_SLOT	12	/* Create PLT entry */
++#define R_TILEPRO_RELATIVE	13	/* Adjust by program base */
++#define R_TILEPRO_BROFF_X1	14	/* X1 pipe branch offset */
++#define R_TILEPRO_JOFFLONG_X1	15	/* X1 pipe jump offset */
++#define R_TILEPRO_JOFFLONG_X1_PLT 16	/* X1 pipe jump offset to PLT */
++#define R_TILEPRO_IMM8_X0	17	/* X0 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y0	18	/* Y0 pipe 8-bit */
++#define R_TILEPRO_IMM8_X1	19	/* X1 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y1	20	/* Y1 pipe 8-bit */
++#define R_TILEPRO_MT_IMM15_X1	21	/* X1 pipe mtspr */
++#define R_TILEPRO_MF_IMM15_X1	22	/* X1 pipe mfspr */
++#define R_TILEPRO_IMM16_X0	23	/* X0 pipe 16-bit */
++#define R_TILEPRO_IMM16_X1	24	/* X1 pipe 16-bit */
++#define R_TILEPRO_IMM16_X0_LO	25	/* X0 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X1_LO	26	/* X1 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X0_HI	27	/* X0 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X1_HI	28	/* X1 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X0_HA	29	/* X0 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X1_HA	30	/* X1 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X0_PCREL 31	/* X0 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X1_PCREL 32	/* X1 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X0_LO_PCREL 33	/* X0 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X1_LO_PCREL 34	/* X1 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X0_HI_PCREL 35	/* X0 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X1_HI_PCREL 36	/* X1 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X0_HA_PCREL 37	/* X0 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X1_HA_PCREL 38	/* X1 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X0_GOT	39	/* X0 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT	40	/* X1 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_LO 41	/* X0 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_LO 42	/* X1 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HI 43	/* X0 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HI 44	/* X1 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HA 45	/* X0 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HA 46	/* X1 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_MMSTART_X0	47	/* X0 pipe mm "start" */
++#define R_TILEPRO_MMEND_X0	48	/* X0 pipe mm "end" */
++#define R_TILEPRO_MMSTART_X1	49	/* X1 pipe mm "start" */
++#define R_TILEPRO_MMEND_X1	50	/* X1 pipe mm "end" */
++#define R_TILEPRO_SHAMT_X0	51	/* X0 pipe shift amount */
++#define R_TILEPRO_SHAMT_X1	52	/* X1 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y0	53	/* Y0 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y1	54	/* Y1 pipe shift amount */
++#define R_TILEPRO_DEST_IMM8_X1	55	/* X1 pipe destination 8-bit */
++/* Relocs 56-59 are currently not defined.  */
++#define R_TILEPRO_TLS_GD_CALL	60	/* "jal" for TLS GD */
++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61	/* X0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62	/* X1 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEPRO_TLS_IE_LOAD	65	/* "lw_tls" for TLS IE */
++#define R_TILEPRO_IMM16_X0_TLS_GD 66	/* X0 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD 67	/* X1 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68	/* X0 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69	/* X1 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70	/* X0 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71	/* X1 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72	/* X0 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73	/* X1 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE 74	/* X0 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE 75	/* X1 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76	/* X0 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77	/* X1 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78	/* X0 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79	/* X1 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80	/* X0 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81	/* X1 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_TLS_DTPMOD32	82	/* ID of module containing symbol */
++#define R_TILEPRO_TLS_DTPOFF32	83	/* Offset in TLS block */
++#define R_TILEPRO_TLS_TPOFF32	84	/* Offset in static TLS block */
++#define R_TILEPRO_IMM16_X0_TLS_LE 85	/* X0 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE 86	/* X1 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87	/* X0 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88	/* X1 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89	/* X0 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90	/* X1 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91	/* X0 pipe ha() 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92	/* X1 pipe ha() 16-bit TLS LE offset */
++
++#define R_TILEPRO_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEPRO_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEPRO_NUM		130
++
++
++/* TILE-Gx relocations.  */
++#define R_TILEGX_NONE		0	/* No reloc */
++#define R_TILEGX_64		1	/* Direct 64 bit */
++#define R_TILEGX_32		2	/* Direct 32 bit */
++#define R_TILEGX_16		3	/* Direct 16 bit */
++#define R_TILEGX_8		4	/* Direct 8 bit */
++#define R_TILEGX_64_PCREL	5	/* PC relative 64 bit */
++#define R_TILEGX_32_PCREL	6	/* PC relative 32 bit */
++#define R_TILEGX_16_PCREL	7	/* PC relative 16 bit */
++#define R_TILEGX_8_PCREL	8	/* PC relative 8 bit */
++#define R_TILEGX_HW0		9	/* hword 0 16-bit */
++#define R_TILEGX_HW1		10	/* hword 1 16-bit */
++#define R_TILEGX_HW2		11	/* hword 2 16-bit */
++#define R_TILEGX_HW3		12	/* hword 3 16-bit */
++#define R_TILEGX_HW0_LAST	13	/* last hword 0 16-bit */
++#define R_TILEGX_HW1_LAST	14	/* last hword 1 16-bit */
++#define R_TILEGX_HW2_LAST	15	/* last hword 2 16-bit */
++#define R_TILEGX_COPY		16	/* Copy relocation */
++#define R_TILEGX_GLOB_DAT	17	/* Create GOT entry */
++#define R_TILEGX_JMP_SLOT	18	/* Create PLT entry */
++#define R_TILEGX_RELATIVE	19	/* Adjust by program base */
++#define R_TILEGX_BROFF_X1	20	/* X1 pipe branch offset */
++#define R_TILEGX_JUMPOFF_X1	21	/* X1 pipe jump offset */
++#define R_TILEGX_JUMPOFF_X1_PLT	22	/* X1 pipe jump offset to PLT */
++#define R_TILEGX_IMM8_X0	23	/* X0 pipe 8-bit */
++#define R_TILEGX_IMM8_Y0	24	/* Y0 pipe 8-bit */
++#define R_TILEGX_IMM8_X1	25	/* X1 pipe 8-bit */
++#define R_TILEGX_IMM8_Y1	26	/* Y1 pipe 8-bit */
++#define R_TILEGX_DEST_IMM8_X1	27	/* X1 pipe destination 8-bit */
++#define R_TILEGX_MT_IMM14_X1	28	/* X1 pipe mtspr */
++#define R_TILEGX_MF_IMM14_X1	29	/* X1 pipe mfspr */
++#define R_TILEGX_MMSTART_X0	30	/* X0 pipe mm "start" */
++#define R_TILEGX_MMEND_X0	31	/* X0 pipe mm "end" */
++#define R_TILEGX_SHAMT_X0	32	/* X0 pipe shift amount */
++#define R_TILEGX_SHAMT_X1	33	/* X1 pipe shift amount */
++#define R_TILEGX_SHAMT_Y0	34	/* Y0 pipe shift amount */
++#define R_TILEGX_SHAMT_Y1	35	/* Y1 pipe shift amount */
++#define R_TILEGX_IMM16_X0_HW0	36	/* X0 pipe hword 0 */
++#define R_TILEGX_IMM16_X1_HW0	37	/* X1 pipe hword 0 */
++#define R_TILEGX_IMM16_X0_HW1	38	/* X0 pipe hword 1 */
++#define R_TILEGX_IMM16_X1_HW1	39	/* X1 pipe hword 1 */
++#define R_TILEGX_IMM16_X0_HW2	40	/* X0 pipe hword 2 */
++#define R_TILEGX_IMM16_X1_HW2	41	/* X1 pipe hword 2 */
++#define R_TILEGX_IMM16_X0_HW3	42	/* X0 pipe hword 3 */
++#define R_TILEGX_IMM16_X1_HW3	43	/* X1 pipe hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST 44	/* X0 pipe last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST 45	/* X1 pipe last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST 46	/* X0 pipe last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST 47	/* X1 pipe last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST 48	/* X0 pipe last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST 49	/* X1 pipe last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_PCREL 50	/* X0 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_PCREL 51	/* X1 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_PCREL 52	/* X0 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_PCREL 53	/* X1 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_PCREL 54	/* X0 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_PCREL 55	/* X1 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X0_HW3_PCREL 56	/* X0 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X1_HW3_PCREL 57	/* X1 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_GOT 64	/* X0 pipe hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_GOT 65	/* X1 pipe hword 0 GOT offset */
++/* Relocs 66-71 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
++/* Relocs 76-77 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78	/* X0 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79	/* X1 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80	/* X0 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81	/* X1 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
++/* Relocs 90-91 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92	/* X0 pipe hword 0 TLS IE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93	/* X1 pipe hword 0 TLS IE offset */
++/* Relocs 94-99 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
++/* Relocs 104-105 are currently not defined.  */
++#define R_TILEGX_TLS_DTPMOD64	106	/* 64-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF64	107	/* 64-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF64	108	/* 64-bit offset in static TLS block */
++#define R_TILEGX_TLS_DTPMOD32	109	/* 32-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF32	110	/* 32-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF32	111	/* 32-bit offset in static TLS block */
++#define R_TILEGX_TLS_GD_CALL	112	/* "jal" for TLS GD */
++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113	/* X0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114	/* X1 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEGX_TLS_IE_LOAD	117	/* "ld_tls" for TLS IE */
++#define R_TILEGX_IMM8_X0_TLS_ADD 118	/* X0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_X1_TLS_ADD 119	/* X1 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y0_TLS_ADD 120	/* Y0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y1_TLS_ADD 121	/* Y1 pipe "addi" for TLS GD/IE */
++
++#define R_TILEGX_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEGX_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEGX_NUM		130
++
++#endif	/* elf.h */
diff --git a/target/linux/generic/patches-4.4/211-sign-file-libressl.patch b/target/linux/generic/patches-4.4/211-sign-file-libressl.patch
new file mode 100644
index 0000000000..c174087f10
--- /dev/null
+++ b/target/linux/generic/patches-4.4/211-sign-file-libressl.patch
@@ -0,0 +1,16 @@
+LibreSSL disables the CMS subsystem, so sign-file.c needs to fall back to using
+PKCS#7 in that case.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/scripts/sign-file.c
++++ b/scripts/sign-file.c
+@@ -39,7 +39,7 @@
+  * signing with anything other than SHA1 - so we're stuck with that if such is
+  * the case.
+  */
+-#if OPENSSL_VERSION_NUMBER < 0x10000000L
++#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10000000L
+ #define USE_PKCS7
+ #endif
+ #ifndef USE_PKCS7
diff --git a/target/linux/generic/patches-4.4/212-byteshift_portability.patch b/target/linux/generic/patches-4.4/212-byteshift_portability.patch
new file mode 100644
index 0000000000..0f23ba9be9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/212-byteshift_portability.patch
@@ -0,0 +1,51 @@
+--- a/tools/include/tools/be_byteshift.h
++++ b/tools/include/tools/be_byteshift.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_BE_BYTESHIFT_H
+ #define _TOOLS_BE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_be16(const uint8_t *p)
+--- a/tools/include/tools/le_byteshift.h
++++ b/tools/include/tools/le_byteshift.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_LE_BYTESHIFT_H
+ #define _TOOLS_LE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_le16(const uint8_t *p)
+--- /dev/null
++++ b/tools/include/tools/linux_types.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_TYPES_H
++#define __LINUX_TYPES_H
++
++#include <stdint.h>
++
++typedef uint8_t __u8;
++typedef uint8_t __be8;
++typedef uint8_t __le8;
++
++typedef uint16_t __u16;
++typedef uint16_t __be16;
++typedef uint16_t __le16;
++
++typedef uint32_t __u32;
++typedef uint32_t __be32;
++typedef uint32_t __le32;
++
++typedef uint64_t __u64;
++typedef uint64_t __be64;
++typedef uint64_t __le64;
++
++#endif
diff --git a/target/linux/generic/patches-4.4/214-spidev_h_portability.patch b/target/linux/generic/patches-4.4/214-spidev_h_portability.patch
new file mode 100644
index 0000000000..dbee090547
--- /dev/null
+++ b/target/linux/generic/patches-4.4/214-spidev_h_portability.patch
@@ -0,0 +1,11 @@
+--- a/include/uapi/linux/spi/spidev.h
++++ b/include/uapi/linux/spi/spidev.h
+@@ -111,7 +111,7 @@ struct spi_ioc_transfer {
+ 
+ /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+ #define SPI_MSGSIZE(N) \
+-	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
++	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
+ 		? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+ #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+ 
diff --git a/target/linux/generic/patches-4.4/220-gc_sections.patch b/target/linux/generic/patches-4.4/220-gc_sections.patch
new file mode 100644
index 0000000000..cbe03d5c5e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/220-gc_sections.patch
@@ -0,0 +1,536 @@
+From: Felix Fietkau <nbd@nbd.name>
+
+use -ffunction-sections, -fdata-sections and --gc-sections
+
+In combination with kernel symbol export stripping this significantly reduces
+the kernel image size. Used on both ARM and MIPS architectures.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ #
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
+ cflags-y			+= -msoft-float
+-LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
++LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
+ 
++ifndef CONFIG_FUNCTION_TRACER
++KBUILD_CFLAGS_KERNEL		+= -ffunction-sections -fdata-sections
++endif
++
+ #
+ # pass -msoft-float to GAS if it supports it.  However on newer binutils
+ # (specifically newer than 2.24.51.20140728) we then also need to explicitly
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -69,7 +69,7 @@ SECTIONS
+ 	/* Exception table for data bus errors */
+ 	__dbe_table : {
+ 		__start___dbe_table = .;
+-		*(__dbe_table)
++		KEEP(*(__dbe_table))
+ 		__stop___dbe_table = .;
+ 	}
+ 
+@@ -119,7 +119,7 @@ SECTIONS
+ 	. = ALIGN(4);
+ 	.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
+ 		__mips_machines_start = .;
+-		*(.mips.machines.init)
++		KEEP(*(.mips.machines.init))
+ 		__mips_machines_end = .;
+ 	}
+ 
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -89,7 +89,7 @@
+ #ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ #define MCOUNT_REC()	. = ALIGN(8);				\
+ 			VMLINUX_SYMBOL(__start_mcount_loc) = .; \
+-			*(__mcount_loc)				\
++			KEEP(*(__mcount_loc))			\
+ 			VMLINUX_SYMBOL(__stop_mcount_loc) = .;
+ #else
+ #define MCOUNT_REC()
+@@ -97,7 +97,7 @@
+ 
+ #ifdef CONFIG_TRACE_BRANCH_PROFILING
+ #define LIKELY_PROFILE()	VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
+-				*(_ftrace_annotated_branch)			      \
++				KEEP(*(_ftrace_annotated_branch))		      \
+ 				VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .;
+ #else
+ #define LIKELY_PROFILE()
+@@ -105,7 +105,7 @@
+ 
+ #ifdef CONFIG_PROFILE_ALL_BRANCHES
+ #define BRANCH_PROFILE()	VMLINUX_SYMBOL(__start_branch_profile) = .;   \
+-				*(_ftrace_branch)			      \
++				KEEP(*(_ftrace_branch))			      \
+ 				VMLINUX_SYMBOL(__stop_branch_profile) = .;
+ #else
+ #define BRANCH_PROFILE()
+@@ -114,7 +114,7 @@
+ #ifdef CONFIG_KPROBES
+ #define KPROBE_BLACKLIST()	. = ALIGN(8);				      \
+ 				VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
+-				*(_kprobe_blacklist)			      \
++				KEEP(*(_kprobe_blacklist))		      \
+ 				VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
+ #else
+ #define KPROBE_BLACKLIST()
+@@ -123,10 +123,10 @@
+ #ifdef CONFIG_EVENT_TRACING
+ #define FTRACE_EVENTS()	. = ALIGN(8);					\
+ 			VMLINUX_SYMBOL(__start_ftrace_events) = .;	\
+-			*(_ftrace_events)				\
++			KEEP(*(_ftrace_events))				\
+ 			VMLINUX_SYMBOL(__stop_ftrace_events) = .;	\
+ 			VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .;	\
+-			*(_ftrace_enum_map)				\
++			KEEP(*(_ftrace_enum_map))			\
+ 			VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
+ #else
+ #define FTRACE_EVENTS()
+@@ -134,7 +134,7 @@
+ 
+ #ifdef CONFIG_TRACING
+ #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .;      \
+-			 *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
++			 KEEP(*(__trace_printk_fmt)) /* Trace_printk fmt' pointer */ \
+ 			 VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
+ #define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .;	\
+ 			 *(__tracepoint_str) /* Trace_printk fmt' pointer */ \
+@@ -147,7 +147,7 @@
+ #ifdef CONFIG_FTRACE_SYSCALLS
+ #define TRACE_SYSCALLS() . = ALIGN(8);					\
+ 			 VMLINUX_SYMBOL(__start_syscalls_metadata) = .;	\
+-			 *(__syscalls_metadata)				\
++			 KEEP(*(__syscalls_metadata))			\
+ 			 VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
+ #else
+ #define TRACE_SYSCALLS()
+@@ -169,8 +169,8 @@
+ #define _OF_TABLE_1(name)						\
+ 	. = ALIGN(8);							\
+ 	VMLINUX_SYMBOL(__##name##_of_table) = .;			\
+-	*(__##name##_of_table)						\
+-	*(__##name##_of_table_end)
++	KEEP(*(__##name##_of_table))					\
++	KEEP(*(__##name##_of_table_end))
+ 
+ #define CLKSRC_OF_TABLES()	OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
+ #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
+@@ -194,7 +194,7 @@
+ #define KERNEL_DTB()							\
+ 	STRUCT_ALIGN();							\
+ 	VMLINUX_SYMBOL(__dtb_start) = .;				\
+-	*(.dtb.init.rodata)						\
++	KEEP(*(.dtb.init.rodata))					\
+ 	VMLINUX_SYMBOL(__dtb_end) = .;
+ 
+ /* .data section */
+@@ -210,16 +210,17 @@
+ 	/* implement dynamic printk debug */				\
+ 	. = ALIGN(8);                                                   \
+ 	VMLINUX_SYMBOL(__start___jump_table) = .;                       \
+-	*(__jump_table)                                                 \
++	KEEP(*(__jump_table))                                           \
+ 	VMLINUX_SYMBOL(__stop___jump_table) = .;                        \
+ 	. = ALIGN(8);							\
+ 	VMLINUX_SYMBOL(__start___verbose) = .;                          \
+-	*(__verbose)                                                    \
++	KEEP(*(__verbose))                                              \
+ 	VMLINUX_SYMBOL(__stop___verbose) = .;				\
+ 	LIKELY_PROFILE()		       				\
+ 	BRANCH_PROFILE()						\
+ 	TRACE_PRINTKS()							\
+-	TRACEPOINT_STR()
++	TRACEPOINT_STR()                                                \
++	*(.data.[a-zA-Z_]*)
+ 
+ /*
+  * Data section helpers
+@@ -273,35 +274,35 @@
+ 	/* PCI quirks */						\
+ 	.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_early) = .;		\
+-		*(.pci_fixup_early)					\
++		KEEP(*(.pci_fixup_early))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_early) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_header) = .;		\
+-		*(.pci_fixup_header)					\
++		KEEP(*(.pci_fixup_header))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_header) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_final) = .;		\
+-		*(.pci_fixup_final)					\
++		KEEP(*(.pci_fixup_final))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_final) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_enable) = .;		\
+-		*(.pci_fixup_enable)					\
++		KEEP(*(.pci_fixup_enable))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_resume) = .;		\
+-		*(.pci_fixup_resume)					\
++		KEEP(*(.pci_fixup_resume))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_resume) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .;	\
+-		*(.pci_fixup_resume_early)				\
++		KEEP(*(.pci_fixup_resume_early))			\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .;	\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .;		\
+-		*(.pci_fixup_suspend)					\
++		KEEP(*(.pci_fixup_suspend))				\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .;		\
+ 		VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .;	\
+-		*(.pci_fixup_suspend_late)				\
++		KEEP(*(.pci_fixup_suspend_late))			\
+ 		VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .;	\
+ 	}								\
+ 									\
+ 	/* Built-in firmware blobs */					\
+ 	.builtin_fw        : AT(ADDR(.builtin_fw) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start_builtin_fw) = .;			\
+-		*(.builtin_fw)						\
++		KEEP(*(.builtin_fw))					\
+ 		VMLINUX_SYMBOL(__end_builtin_fw) = .;			\
+ 	}								\
+ 									\
+@@ -310,49 +311,49 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
+-		*(SORT(___ksymtab+*))					\
++		KEEP(*(SORT(___ksymtab+*)))				\
+ 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
+-		*(SORT(___ksymtab_gpl+*))				\
++		KEEP(*(SORT(___ksymtab_gpl+*)))				\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: Normal unused symbols */		\
+ 	__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_unused) = .;		\
+-		*(SORT(___ksymtab_unused+*))				\
++		KEEP(*(SORT(___ksymtab_unused+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;		\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only unused symbols */		\
+ 	__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;	\
+-		*(SORT(___ksymtab_unused_gpl+*))			\
++		KEEP(*(SORT(___ksymtab_unused_gpl+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-future-only symbols */		\
+ 	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
+-		*(SORT(___ksymtab_gpl_future+*))			\
++		KEEP(*(SORT(___ksymtab_gpl_future+*)))			\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___kcrctab) = .;			\
+-		*(SORT(___kcrctab+*))					\
++		KEEP(*(SORT(___kcrctab+*)))				\
+ 		VMLINUX_SYMBOL(__stop___kcrctab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__kcrctab_gpl     : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___kcrctab_gpl) = .;		\
+-		*(SORT(___kcrctab_gpl+*))				\
++		KEEP(*(SORT(___kcrctab_gpl+*)))				\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;		\
+ 	}								\
+ 									\
+@@ -366,14 +367,14 @@
+ 	/* Kernel symbol table: GPL-only unused symbols */		\
+ 	__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .;	\
+-		*(SORT(___kcrctab_unused_gpl+*))			\
++		KEEP(*(SORT(___kcrctab_unused_gpl+*)))			\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .;	\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-future-only symbols */		\
+ 	__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+ 		VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;	\
+-		*(SORT(___kcrctab_gpl_future+*))			\
++		KEEP(*(SORT(___kcrctab_gpl_future+*)))			\
+ 		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
+ 	}								\
+ 									\
+@@ -392,14 +393,14 @@
+ 	/* Built-in module parameters. */				\
+ 	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
+ 		VMLINUX_SYMBOL(__start___param) = .;			\
+-		*(__param)						\
++		KEEP(*(__param))					\
+ 		VMLINUX_SYMBOL(__stop___param) = .;			\
+ 	}								\
+ 									\
+ 	/* Built-in module versions. */					\
+ 	__modver : AT(ADDR(__modver) - LOAD_OFFSET) {			\
+ 		VMLINUX_SYMBOL(__start___modver) = .;			\
+-		*(__modver)						\
++		KEEP(*(__modver))					\
+ 		VMLINUX_SYMBOL(__stop___modver) = .;			\
+ 		. = ALIGN((align));					\
+ 		VMLINUX_SYMBOL(__end_rodata) = .;			\
+@@ -453,7 +454,7 @@
+ #define ENTRY_TEXT							\
+ 		ALIGN_FUNCTION();					\
+ 		VMLINUX_SYMBOL(__entry_text_start) = .;			\
+-		*(.entry.text)						\
++		KEEP(*(.entry.text))					\
+ 		VMLINUX_SYMBOL(__entry_text_end) = .;
+ 
+ #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+@@ -481,7 +482,7 @@
+ 	. = ALIGN(align);						\
+ 	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ex_table) = .;			\
+-		*(__ex_table)						\
++		KEEP(*(__ex_table))						\
+ 		VMLINUX_SYMBOL(__stop___ex_table) = .;			\
+ 	}
+ 
+@@ -497,9 +498,9 @@
+ #ifdef CONFIG_CONSTRUCTORS
+ #define KERNEL_CTORS()	. = ALIGN(8);			   \
+ 			VMLINUX_SYMBOL(__ctors_start) = .; \
+-			*(.ctors)			   \
++			KEEP(*(.ctors))			   \
+ 			*(SORT(.init_array.*))		   \
+-			*(.init_array)			   \
++			KEEP(*(.init_array))		   \
+ 			VMLINUX_SYMBOL(__ctors_end) = .;
+ #else
+ #define KERNEL_CTORS()
+@@ -556,7 +557,7 @@
+ #define SBSS(sbss_align)						\
+ 	. = ALIGN(sbss_align);						\
+ 	.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {				\
+-		*(.sbss)						\
++		*(.sbss .sbss.*)					\
+ 		*(.scommon)						\
+ 	}
+ 
+@@ -574,7 +575,7 @@
+ 		BSS_FIRST_SECTIONS					\
+ 		*(.bss..page_aligned)					\
+ 		*(.dynbss)						\
+-		*(.bss)							\
++		*(.bss .bss.*)						\
+ 		*(COMMON)						\
+ 	}
+ 
+@@ -623,7 +624,7 @@
+ 	. = ALIGN(8);							\
+ 	__bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___bug_table) = .;		\
+-		*(__bug_table)						\
++		KEEP(*(__bug_table))					\
+ 		VMLINUX_SYMBOL(__stop___bug_table) = .;			\
+ 	}
+ #else
+@@ -635,7 +636,7 @@
+ 	. = ALIGN(4);							\
+ 	.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__tracedata_start) = .;			\
+-		*(.tracedata)						\
++		KEEP(*(.tracedata))					\
+ 		VMLINUX_SYMBOL(__tracedata_end) = .;			\
+ 	}
+ #else
+@@ -652,17 +653,17 @@
+ #define INIT_SETUP(initsetup_align)					\
+ 		. = ALIGN(initsetup_align);				\
+ 		VMLINUX_SYMBOL(__setup_start) = .;			\
+-		*(.init.setup)						\
++		KEEP(*(.init.setup))					\
+ 		VMLINUX_SYMBOL(__setup_end) = .;
+ 
+ #define INIT_CALLS_LEVEL(level)						\
+ 		VMLINUX_SYMBOL(__initcall##level##_start) = .;		\
+-		*(.initcall##level##.init)				\
+-		*(.initcall##level##s.init)				\
++		KEEP(*(.initcall##level##.init))			\
++		KEEP(*(.initcall##level##s.init))			\
+ 
+ #define INIT_CALLS							\
+ 		VMLINUX_SYMBOL(__initcall_start) = .;			\
+-		*(.initcallearly.init)					\
++		KEEP(*(.initcallearly.init))				\
+ 		INIT_CALLS_LEVEL(0)					\
+ 		INIT_CALLS_LEVEL(1)					\
+ 		INIT_CALLS_LEVEL(2)					\
+@@ -676,21 +677,21 @@
+ 
+ #define CON_INITCALL							\
+ 		VMLINUX_SYMBOL(__con_initcall_start) = .;		\
+-		*(.con_initcall.init)					\
++		KEEP(*(.con_initcall.init))				\
+ 		VMLINUX_SYMBOL(__con_initcall_end) = .;
+ 
+ #define SECURITY_INITCALL						\
+ 		VMLINUX_SYMBOL(__security_initcall_start) = .;		\
+-		*(.security_initcall.init)				\
++		KEEP(*(.security_initcall.init))			\
+ 		VMLINUX_SYMBOL(__security_initcall_end) = .;
+ 
+ #ifdef CONFIG_BLK_DEV_INITRD
+ #define INIT_RAM_FS							\
+ 	. = ALIGN(4);							\
+ 	VMLINUX_SYMBOL(__initramfs_start) = .;				\
+-	*(.init.ramfs)							\
++	KEEP(*(.init.ramfs))						\
+ 	. = ALIGN(8);							\
+-	*(.init.ramfs.info)
++	KEEP(*(.init.ramfs.info))
+ #else
+ #define INIT_RAM_FS
+ #endif
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -22,11 +22,16 @@ endif
+ ifeq ($(CONFIG_ARM_MODULE_PLTS),y)
+ LDFLAGS_MODULE	+= -T $(srctree)/arch/arm/kernel/module.lds
+ endif
++LDFLAGS_vmlinux += --gc-sections
+ 
+ OBJCOPYFLAGS	:=-O binary -R .comment -S
+ GZFLAGS		:=-9
+ #KBUILD_CFLAGS	+=-pipe
+ 
++ifndef CONFIG_FUNCTION_TRACER
++KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
++endif
++
+ # Never generate .eh_frame
+ KBUILD_CFLAGS	+= $(call cc-option,-fno-dwarf2-cfi-asm)
+ 
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -15,13 +15,13 @@
+ #define PROC_INFO							\
+ 	. = ALIGN(4);							\
+ 	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
+-	*(.proc.info.init)						\
++	KEEP(*(.proc.info.init))					\
+ 	VMLINUX_SYMBOL(__proc_info_end) = .;
+ 
+ #define IDMAP_TEXT							\
+ 	ALIGN_FUNCTION();						\
+ 	VMLINUX_SYMBOL(__idmap_text_start) = .;				\
+-	*(.idmap.text)							\
++	KEEP(*(.idmap.text))						\
+ 	VMLINUX_SYMBOL(__idmap_text_end) = .;				\
+ 	. = ALIGN(PAGE_SIZE);						\
+ 	VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;			\
+@@ -102,7 +102,7 @@ SECTIONS
+ 		_stext = .;		/* Text and read-only data	*/
+ 			IDMAP_TEXT
+ 			__exception_text_start = .;
+-			*(.exception.text)
++			KEEP(*(.exception.text))
+ 			__exception_text_end = .;
+ 			IRQENTRY_TEXT
+ 			TEXT_TEXT
+@@ -126,7 +126,7 @@ SECTIONS
+ 	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+ 		__start___ex_table = .;
+ #ifdef CONFIG_MMU
+-		*(__ex_table)
++		KEEP(*(__ex_table))
+ #endif
+ 		__stop___ex_table = .;
+ 	}
+@@ -138,12 +138,12 @@ SECTIONS
+ 	. = ALIGN(8);
+ 	.ARM.unwind_idx : {
+ 		__start_unwind_idx = .;
+-		*(.ARM.exidx*)
++		KEEP(*(.ARM.exidx*))
+ 		__stop_unwind_idx = .;
+ 	}
+ 	.ARM.unwind_tab : {
+ 		__start_unwind_tab = .;
+-		*(.ARM.extab*)
++		KEEP(*(.ARM.extab*))
+ 		__stop_unwind_tab = .;
+ 	}
+ #endif
+@@ -166,14 +166,14 @@ SECTIONS
+ 	 */
+ 	__vectors_start = .;
+ 	.vectors 0 : AT(__vectors_start) {
+-		*(.vectors)
++		KEEP(*(.vectors))
+ 	}
+ 	. = __vectors_start + SIZEOF(.vectors);
+ 	__vectors_end = .;
+ 
+ 	__stubs_start = .;
+ 	.stubs 0x1000 : AT(__stubs_start) {
+-		*(.stubs)
++		KEEP(*(.stubs))
+ 	}
+ 	. = __stubs_start + SIZEOF(.stubs);
+ 	__stubs_end = .;
+@@ -187,24 +187,24 @@ SECTIONS
+ 	}
+ 	.init.arch.info : {
+ 		__arch_info_begin = .;
+-		*(.arch.info.init)
++		KEEP(*(.arch.info.init))
+ 		__arch_info_end = .;
+ 	}
+ 	.init.tagtable : {
+ 		__tagtable_begin = .;
+-		*(.taglist.init)
++		KEEP(*(.taglist.init))
+ 		__tagtable_end = .;
+ 	}
+ #ifdef CONFIG_SMP_ON_UP
+ 	.init.smpalt : {
+ 		__smpalt_begin = .;
+-		*(.alt.smp.init)
++		KEEP(*(.alt.smp.init))
+ 		__smpalt_end = .;
+ 	}
+ #endif
+ 	.init.pv_table : {
+ 		__pv_table_begin = .;
+-		*(.pv_table)
++		KEEP(*(.pv_table))
+ 		__pv_table_end = .;
+ 	}
+ 	.init.data : {
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -105,6 +105,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+ endif
++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
+ 
+ ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj)
+ asflags-y := -DZIMAGE
diff --git a/target/linux/generic/patches-4.4/221-module_exports.patch b/target/linux/generic/patches-4.4/221-module_exports.patch
new file mode 100644
index 0000000000..510a86c468
--- /dev/null
+++ b/target/linux/generic/patches-4.4/221-module_exports.patch
@@ -0,0 +1,88 @@
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -54,6 +54,16 @@
+ #define LOAD_OFFSET 0
+ #endif
+ 
++#ifndef SYMTAB_KEEP
++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
++#endif
++
++#ifndef SYMTAB_DISCARD
++#define SYMTAB_DISCARD
++#define SYMTAB_DISCARD_GPL
++#endif
++
+ #include <linux/export.h>
+ 
+ /* Align . to a 8 byte boundary equals to maximum function alignment. */
+@@ -311,14 +321,14 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
+-		KEEP(*(SORT(___ksymtab+*)))				\
++		SYMTAB_KEEP						\
+ 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
+-		KEEP(*(SORT(___ksymtab_gpl+*)))				\
++		SYMTAB_KEEP_GPL						\
+ 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
+ 	}								\
+ 									\
+@@ -380,7 +390,7 @@
+ 									\
+ 	/* Kernel symbol table: strings */				\
+         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
+-		*(__ksymtab_strings)					\
++		*(__ksymtab_strings+*)					\
+ 	}								\
+ 									\
+ 	/* __*init sections */						\
+@@ -710,6 +720,8 @@
+ 	EXIT_TEXT							\
+ 	EXIT_DATA							\
+ 	EXIT_CALL							\
++	SYMTAB_DISCARD							\
++	SYMTAB_DISCARD_GPL						\
+ 	*(.discard)							\
+ 	*(.discard.*)							\
+ 	}
+--- a/scripts/Makefile.build
++++ b/scripts/Makefile.build
+@@ -299,7 +299,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
+ # Linker scripts preprocessor (.lds.S -> .lds)
+ # ---------------------------------------------------------------------------
+ quiet_cmd_cpp_lds_S = LDS     $@
+-      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
++      cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \
+ 	                     -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+ 
+ $(obj)/%.lds: $(src)/%.lds.S FORCE
+--- a/include/linux/export.h
++++ b/include/linux/export.h
+@@ -52,12 +52,19 @@ extern struct module __this_module;
+ #define __CRC_SYMBOL(sym, sec)
+ #endif
+ 
++#ifdef MODULE
++#define __EXPORT_SUFFIX(sym)
++#else
++#define __EXPORT_SUFFIX(sym) "+" #sym
++#endif
++
+ /* For every exported symbol, place a struct in the __ksymtab section */
+ #define __EXPORT_SYMBOL(sym, sec)				\
+ 	extern typeof(sym) sym;					\
+ 	__CRC_SYMBOL(sym, sec)					\
+ 	static const char __kstrtab_##sym[]			\
+-	__attribute__((section("__ksymtab_strings"), aligned(1))) \
++	__attribute__((section("__ksymtab_strings"		\
++	  __EXPORT_SUFFIX(sym)), aligned(1)))			\
+ 	= VMLINUX_SYMBOL_STR(sym);				\
+ 	extern const struct kernel_symbol __ksymtab_##sym;	\
+ 	__visible const struct kernel_symbol __ksymtab_##sym	\
diff --git a/target/linux/generic/patches-4.4/222-arm_zimage_none.patch b/target/linux/generic/patches-4.4/222-arm_zimage_none.patch
new file mode 100644
index 0000000000..47fa6c928d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/222-arm_zimage_none.patch
@@ -0,0 +1,133 @@
+ARM: implement "uncompressed zImage"
+
+Based on RFC patch by Uwe Kleine-König
+http://www.spinics.net/lists/arm-kernel/msg230153.html
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -71,6 +71,7 @@ suffix_$(CONFIG_KERNEL_LZO)  = lzo
+ suffix_$(CONFIG_KERNEL_LZMA) = lzma
+ suffix_$(CONFIG_KERNEL_XZ)   = xzkern
+ suffix_$(CONFIG_KERNEL_LZ4)  = lz4
++suffix_$(CONFIG_KERNEL_CAT)  = cat
+ 
+ # Borrowed libfdt files for the ATAG compatibility mode
+ 
+@@ -95,7 +96,7 @@ targets       := vmlinux vmlinux.lds \
+ 		 bswapsdi2.S font.o font.c head.o misc.o $(OBJS)
+ 
+ # Make sure files are removed during clean
+-extra-y       += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern piggy.lz4 \
++extra-y       += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern piggy.lz4 piggy.cat \
+ 		 lib1funcs.S ashldi3.S bswapsdi2.S $(libfdt) $(libfdt_hdrs) \
+ 		 hyp-stub.S
+ 
+--- a/arch/arm/boot/compressed/decompress.c
++++ b/arch/arm/boot/compressed/decompress.c
+@@ -55,6 +55,10 @@ extern char * strstr(const char * s1, co
+ #include "../../../../lib/decompress_unlz4.c"
+ #endif
+ 
++#ifdef CONFIG_KERNEL_CAT
++#include "../../../../lib/decompress_uncat.c"
++#endif
++
+ int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
+ {
+ 	return __decompress(input, len, NULL, NULL, output, 0, NULL, error);
+--- /dev/null
++++ b/arch/arm/boot/compressed/piggy.cat.S
+@@ -0,0 +1,6 @@
++	.section .piggydata,#alloc
++	.globl	input_data
++input_data:
++	.incbin	"arch/arm/boot/compressed/piggy.cat"
++	.globl	input_data_end
++input_data_end:
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -115,6 +115,9 @@ config HAVE_KERNEL_LZO
+ config HAVE_KERNEL_LZ4
+ 	bool
+ 
++config HAVE_KERNEL_CAT
++	bool
++
+ choice
+ 	prompt "Kernel compression mode"
+ 	default KERNEL_GZIP
+@@ -181,9 +184,10 @@ config KERNEL_LZO
+ 	bool "LZO"
+ 	depends on HAVE_KERNEL_LZO
+ 	help
+-	  Its compression ratio is the poorest among the choices. The kernel
+-	  size is about 10% bigger than gzip; however its speed
+-	  (both compression and decompression) is the fastest.
++	  Its compression ratio is the poorest among the choices (apart from
++	  uncompressed below). The kernel size is about 10% bigger than gzip;
++	  however its speed (both compression and decompression) is the
++	  fastest.
+ 
+ config KERNEL_LZ4
+ 	bool "LZ4"
+@@ -197,6 +201,12 @@ config KERNEL_LZ4
+ 	  is about 8% bigger than LZO. But the decompression speed is
+ 	  faster than LZO.
+ 
++config KERNEL_CAT
++	bool "uncompressed"
++	depends on HAVE_KERNEL_CAT
++	help
++	  Don't use compression at all.
++
+ endchoice
+ 
+ config DEFAULT_HOSTNAME
+--- /dev/null
++++ b/lib/decompress_uncat.c
+@@ -0,0 +1,17 @@
++#include <linux/types.h>
++#include <linux/compiler.h>
++
++#ifdef STATIC
++
++STATIC int __decompress(unsigned char *buf, long in_len,
++			long (*fill)(void*, unsigned long),
++			long (*flush)(void*, unsigned long),
++			unsigned char *output, long out_len,
++			long *posp,
++			void (*error)(char *x))
++{
++	memmove(output, buf, in_len);
++	return 0;
++}
++
++#endif
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -337,6 +337,13 @@ cmd_lz4 = (cat $(filter-out FORCE,$^) |
+ 	lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+ 	(rm -f $@ ; false)
+ 
++# uncompressed
++# ---------------------------------------------------------------------------
++quiet_cmd_cat = CAT     $@
++cmd_cat = (cat $(filter-out FORCE,$^) \
++	&& $(call size_append, $(filter-out FORCE,$^))) > $@ || \
++	(rm -f $@ ; false)
++
+ # U-Boot mkimage
+ # ---------------------------------------------------------------------------
+ 
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -59,6 +59,7 @@ config ARM
+ 	select HAVE_KERNEL_LZMA
+ 	select HAVE_KERNEL_LZO
+ 	select HAVE_KERNEL_XZ
++	select HAVE_KERNEL_CAT
+ 	select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M
+ 	select HAVE_KRETPROBES if (HAVE_KPROBES)
+ 	select HAVE_MEMBLOCK
diff --git a/target/linux/generic/patches-4.4/230-openwrt_lzma_options.patch b/target/linux/generic/patches-4.4/230-openwrt_lzma_options.patch
new file mode 100644
index 0000000000..d5bbb19cfe
--- /dev/null
+++ b/target/linux/generic/patches-4.4/230-openwrt_lzma_options.patch
@@ -0,0 +1,58 @@
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -324,7 +324,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
+ 
+ quiet_cmd_lzma = LZMA    $@
+ cmd_lzma = (cat $(filter-out FORCE,$^) | \
+-	lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
++	lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+ 	(rm -f $@ ; false)
+ 
+ quiet_cmd_lzo = LZO     $@
+--- a/scripts/gen_initramfs_list.sh
++++ b/scripts/gen_initramfs_list.sh
+@@ -226,7 +226,7 @@ cpio_list=
+ output="/dev/stdout"
+ output_file=""
+ is_cpio_compressed=
+-compr="gzip -n -9 -f"
++compr="gzip -n -9 -f -"
+ 
+ arg="$1"
+ case "$arg" in
+@@ -242,13 +242,13 @@ case "$arg" in
+ 		output=${cpio_list}
+ 		echo "$output_file" | grep -q "\.gz$" \
+                 && [ -x "`which gzip 2> /dev/null`" ] \
+-                && compr="gzip -n -9 -f"
++                && compr="gzip -n -9 -f -"
+ 		echo "$output_file" | grep -q "\.bz2$" \
+                 && [ -x "`which bzip2 2> /dev/null`" ] \
+-                && compr="bzip2 -9 -f"
++                && compr="bzip2 -9 -f -"
+ 		echo "$output_file" | grep -q "\.lzma$" \
+                 && [ -x "`which lzma 2> /dev/null`" ] \
+-                && compr="lzma -9 -f"
++                && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
+ 		echo "$output_file" | grep -q "\.xz$" \
+                 && [ -x "`which xz 2> /dev/null`" ] \
+                 && compr="xz --check=crc32 --lzma2=dict=1MiB"
+@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then
+ 	if [ "${is_cpio_compressed}" = "compressed" ]; then
+ 		cat ${cpio_tfile} > ${output_file}
+ 	else
+-		(cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
++		(cat ${cpio_tfile} | ${compr} > ${output_file}) \
+ 		|| (rm -f ${output_file} ; false)
+ 	fi
+ 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
+--- a/lib/decompress.c
++++ b/lib/decompress.c
+@@ -48,6 +48,7 @@ static const struct compress_format comp
+ 	{ {0x1f, 0x9e}, "gzip", gunzip },
+ 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
+ 	{ {0x5d, 0x00}, "lzma", unlzma },
++	{ {0x6d, 0x00}, "lzma-openwrt", unlzma },
+ 	{ {0xfd, 0x37}, "xz", unxz },
+ 	{ {0x89, 0x4c}, "lzo", unlzo },
+ 	{ {0x02, 0x21}, "lz4", unlz4 },
diff --git a/target/linux/generic/patches-4.4/250-netfilter_depends.patch b/target/linux/generic/patches-4.4/250-netfilter_depends.patch
new file mode 100644
index 0000000000..b39d971a76
--- /dev/null
+++ b/target/linux/generic/patches-4.4/250-netfilter_depends.patch
@@ -0,0 +1,18 @@
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -218,7 +218,6 @@ config NF_CONNTRACK_FTP
+ 
+ config NF_CONNTRACK_H323
+ 	tristate "H.323 protocol support"
+-	depends on IPV6 || IPV6=n
+ 	depends on NETFILTER_ADVANCED
+ 	help
+ 	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
+@@ -930,7 +929,6 @@ config NETFILTER_XT_TARGET_SECMARK
+ 
+ config NETFILTER_XT_TARGET_TCPMSS
+ 	tristate '"TCPMSS" target support'
+-	depends on IPV6 || IPV6=n
+ 	default m if NETFILTER_ADVANCED=n
+ 	---help---
+ 	  This option adds a `TCPMSS' target, which allows you to alter the
diff --git a/target/linux/generic/patches-4.4/251-sound_kconfig.patch b/target/linux/generic/patches-4.4/251-sound_kconfig.patch
new file mode 100644
index 0000000000..4cb67adc70
--- /dev/null
+++ b/target/linux/generic/patches-4.4/251-sound_kconfig.patch
@@ -0,0 +1,18 @@
+--- a/sound/core/Kconfig
++++ b/sound/core/Kconfig
+@@ -16,13 +16,13 @@ config SND_DMAENGINE_PCM
+ 	tristate
+ 
+ config SND_HWDEP
+-	tristate
++	tristate "Sound hardware support"
+ 
+ config SND_RAWMIDI
+ 	tristate
+ 
+ config SND_COMPRESS_OFFLOAD
+-	tristate
++	tristate "Compression offloading support"
+ 
+ # To be effective this also requires INPUT - users should say:
+ #    select SND_JACK if INPUT=y || INPUT=SND
diff --git a/target/linux/generic/patches-4.4/252-mv_cesa_depends.patch b/target/linux/generic/patches-4.4/252-mv_cesa_depends.patch
new file mode 100644
index 0000000000..f54f3c7fcc
--- /dev/null
+++ b/target/linux/generic/patches-4.4/252-mv_cesa_depends.patch
@@ -0,0 +1,10 @@
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -163,6 +163,7 @@ config CRYPTO_DEV_MV_CESA
+ 	tristate "Marvell's Cryptographic Engine"
+ 	depends on PLAT_ORION
+ 	select CRYPTO_AES
++	select CRYPTO_HASH2
+ 	select CRYPTO_BLKCIPHER
+ 	select CRYPTO_HASH
+ 	select SRAM
diff --git a/target/linux/generic/patches-4.4/253-ssb_b43_default_on.patch b/target/linux/generic/patches-4.4/253-ssb_b43_default_on.patch
new file mode 100644
index 0000000000..29d2a41a3b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/253-ssb_b43_default_on.patch
@@ -0,0 +1,29 @@
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -29,6 +29,7 @@ config SSB_SPROM
+ config SSB_BLOCKIO
+ 	bool
+ 	depends on SSB
++	default y
+ 
+ config SSB_PCIHOST_POSSIBLE
+ 	bool
+@@ -49,7 +50,7 @@ config SSB_PCIHOST
+ config SSB_B43_PCI_BRIDGE
+ 	bool
+ 	depends on SSB_PCIHOST
+-	default n
++	default y
+ 
+ config SSB_PCMCIAHOST_POSSIBLE
+ 	bool
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -17,6 +17,7 @@ config BCMA
+ config BCMA_BLOCKIO
+ 	bool
+ 	depends on BCMA
++	default y
+ 
+ config BCMA_HOST_PCI_POSSIBLE
+ 	bool
diff --git a/target/linux/generic/patches-4.4/254-textsearch_kconfig_hacks.patch b/target/linux/generic/patches-4.4/254-textsearch_kconfig_hacks.patch
new file mode 100644
index 0000000000..12cedbed15
--- /dev/null
+++ b/target/linux/generic/patches-4.4/254-textsearch_kconfig_hacks.patch
@@ -0,0 +1,23 @@
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -334,16 +334,16 @@ config BCH_CONST_T
+ # Textsearch support is select'ed if needed
+ #
+ config TEXTSEARCH
+-	bool
++	boolean	"Textsearch support"
+ 
+ config TEXTSEARCH_KMP
+-	tristate
++	tristate "Textsearch KMP"
+ 
+ config TEXTSEARCH_BM
+-	tristate
++	tristate "Textsearch BM"
+ 
+ config TEXTSEARCH_FSM
+-	tristate
++	tristate "Textsearch FSM"
+ 
+ config BTREE
+ 	bool
diff --git a/target/linux/generic/patches-4.4/255-lib80211_kconfig_hacks.patch b/target/linux/generic/patches-4.4/255-lib80211_kconfig_hacks.patch
new file mode 100644
index 0000000000..be75806e6b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/255-lib80211_kconfig_hacks.patch
@@ -0,0 +1,31 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -201,7 +201,7 @@ config CFG80211_WEXT_EXPORT
+ 	  wext compatibility symbols to be exported.
+ 
+ config LIB80211
+-	tristate
++	tristate "LIB80211"
+ 	default n
+ 	help
+ 	  This options enables a library of common routines used
+@@ -210,13 +210,16 @@ config LIB80211
+ 	  Drivers should select this themselves if needed.
+ 
+ config LIB80211_CRYPT_WEP
+-	tristate
++	tristate "LIB80211_CRYPT_WEP"
++	select LIB80211
+ 
+ config LIB80211_CRYPT_CCMP
+-	tristate
++	tristate "LIB80211_CRYPT_CCMP"
++	select LIB80211
+ 
+ config LIB80211_CRYPT_TKIP
+-	tristate
++	tristate "LIB80211_CRYPT_TKIP"
++	select LIB80211
+ 
+ config LIB80211_DEBUG
+ 	bool "lib80211 debugging messages"
diff --git a/target/linux/generic/patches-4.4/256-crypto_add_kconfig_prompts.patch b/target/linux/generic/patches-4.4/256-crypto_add_kconfig_prompts.patch
new file mode 100644
index 0000000000..fb5d5dc4b4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/256-crypto_add_kconfig_prompts.patch
@@ -0,0 +1,47 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -32,7 +32,7 @@ config CRYPTO_FIPS
+ 	  this is.
+ 
+ config CRYPTO_ALGAPI
+-	tristate
++	tristate "ALGAPI"
+ 	select CRYPTO_ALGAPI2
+ 	help
+ 	  This option provides the API for cryptographic algorithms.
+@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2
+ 	tristate
+ 
+ config CRYPTO_AEAD
+-	tristate
++	tristate "AEAD"
+ 	select CRYPTO_AEAD2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -52,7 +52,7 @@ config CRYPTO_AEAD2
+ 	select CRYPTO_RNG2
+ 
+ config CRYPTO_BLKCIPHER
+-	tristate
++	tristate "BLKCIPHER"
+ 	select CRYPTO_BLKCIPHER2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -63,7 +63,7 @@ config CRYPTO_BLKCIPHER2
+ 	select CRYPTO_WORKQUEUE
+ 
+ config CRYPTO_HASH
+-	tristate
++	tristate "HASH"
+ 	select CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -72,7 +72,7 @@ config CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI2
+ 
+ config CRYPTO_RNG
+-	tristate
++	tristate "RNG"
+ 	select CRYPTO_RNG2
+ 	select CRYPTO_ALGAPI
+ 
diff --git a/target/linux/generic/patches-4.4/257-wireless_ext_kconfig_hack.patch b/target/linux/generic/patches-4.4/257-wireless_ext_kconfig_hack.patch
new file mode 100644
index 0000000000..daac5898ae
--- /dev/null
+++ b/target/linux/generic/patches-4.4/257-wireless_ext_kconfig_hack.patch
@@ -0,0 +1,22 @@
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -1,5 +1,5 @@
+ config WIRELESS_EXT
+-	bool
++	bool "Wireless extensions"
+ 
+ config WEXT_CORE
+ 	def_bool y
+@@ -11,10 +11,10 @@ config WEXT_PROC
+ 	depends on WEXT_CORE
+ 
+ config WEXT_SPY
+-	bool
++	bool "WEXT_SPY"
+ 
+ config WEXT_PRIV
+-	bool
++	bool "WEXT_PRIV"
+ 
+ config CFG80211
+ 	tristate "cfg80211 - wireless configuration API"
diff --git a/target/linux/generic/patches-4.4/258-netfilter_netlink_kconfig_hack.patch b/target/linux/generic/patches-4.4/258-netfilter_netlink_kconfig_hack.patch
new file mode 100644
index 0000000000..4206c9a74a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/258-netfilter_netlink_kconfig_hack.patch
@@ -0,0 +1,11 @@
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -10,7 +10,7 @@ config NETFILTER_INGRESS
+ 	  infrastructure.
+ 
+ config NETFILTER_NETLINK
+-	tristate
++	tristate "Netfilter NFNETLINK interface"
+ 
+ config NETFILTER_NETLINK_ACCT
+ tristate "Netfilter NFACCT over NFNETLINK interface"
diff --git a/target/linux/generic/patches-4.4/259-regmap_dynamic.patch b/target/linux/generic/patches-4.4/259-regmap_dynamic.patch
new file mode 100644
index 0000000000..fb039841c1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/259-regmap_dynamic.patch
@@ -0,0 +1,87 @@
+--- a/drivers/base/regmap/Kconfig
++++ b/drivers/base/regmap/Kconfig
+@@ -3,29 +3,35 @@
+ # subsystems should select the appropriate symbols.
+ 
+ config REGMAP
+-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+ 	select LZO_COMPRESS
+ 	select LZO_DECOMPRESS
+ 	select IRQ_DOMAIN if REGMAP_IRQ
+-	bool
++	tristate "Regmap"
+ 
+ config REGMAP_AC97
++	select REGMAP
+ 	tristate
+ 
+ config REGMAP_I2C
+-	tristate
++	tristate "Regmap I2C"
++	select REGMAP
+ 	depends on I2C
+ 
+ config REGMAP_SPI
+-	tristate
++	tristate "Regmap SPI"
++	select REGMAP
++	depends on SPI_MASTER
+ 	depends on SPI
+ 
+ config REGMAP_SPMI
++	select REGMAP
+ 	tristate
+ 	depends on SPMI
+ 
+ config REGMAP_MMIO
+-	tristate
++	tristate "Regmap MMIO"
++	select REGMAP
+ 
+ config REGMAP_IRQ
++	select REGMAP
+ 	bool
+--- a/include/linux/regmap.h
++++ b/include/linux/regmap.h
+@@ -65,7 +65,7 @@ struct reg_sequence {
+ 	unsigned int delay_us;
+ };
+ 
+-#ifdef CONFIG_REGMAP
++#if IS_ENABLED(CONFIG_REGMAP)
+ 
+ enum regmap_endian {
+ 	/* Unspecified -> 0 -> Backwards compatible default */
+--- a/drivers/base/regmap/Makefile
++++ b/drivers/base/regmap/Makefile
+@@ -1,9 +1,11 @@
+ # For include/trace/define_trace.h to include trace.h
+ CFLAGS_regmap.o := -I$(src)
+ 
+-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
+-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
+-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o
++ifdef CONFIG_DEBUG_FS
++regmap-core-objs += regmap-debugfs.o
++endif
++obj-$(CONFIG_REGMAP) += regmap-core.o
+ obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
+ obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
+ obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
+--- a/drivers/base/regmap/regmap.c
++++ b/drivers/base/regmap/regmap.c
+@@ -13,6 +13,7 @@
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/export.h>
++#include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/err.h>
+ #include <linux/of.h>
+@@ -2869,3 +2870,5 @@ static int __init regmap_initcall(void)
+ 	return 0;
+ }
+ postcore_initcall(regmap_initcall);
++
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-4.4/260-crypto_test_dependencies.patch b/target/linux/generic/patches-4.4/260-crypto_test_dependencies.patch
new file mode 100644
index 0000000000..54b8730a93
--- /dev/null
+++ b/target/linux/generic/patches-4.4/260-crypto_test_dependencies.patch
@@ -0,0 +1,48 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -118,12 +118,12 @@ config CRYPTO_MANAGER
+ 	  cbc(aes).
+ 
+ config CRYPTO_MANAGER2
+-	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
+-	select CRYPTO_AEAD2
+-	select CRYPTO_HASH2
+-	select CRYPTO_BLKCIPHER2
+-	select CRYPTO_PCOMP2
+-	select CRYPTO_AKCIPHER2
++	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS)
++	select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_PCOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ 
+ config CRYPTO_USER
+ 	tristate "Userspace cryptographic algorithm configuration"
+@@ -136,7 +136,6 @@ config CRYPTO_USER
+ config CRYPTO_MANAGER_DISABLE_TESTS
+ 	bool "Disable run-time self tests"
+ 	default y
+-	depends on CRYPTO_MANAGER2
+ 	help
+ 	  Disable run-time self tests that normally take place at
+ 	  algorithm registration.
+--- a/crypto/algboss.c
++++ b/crypto/algboss.c
+@@ -248,12 +248,16 @@ static int cryptomgr_schedule_test(struc
+ 	type = alg->cra_flags;
+ 
+ 	/* This piece of crap needs to disappear into per-type test hooks. */
++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
++	type |= CRYPTO_ALG_TESTED;
++#else
+ 	if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
+ 	      CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) &&
+ 	    ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+ 	     CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+ 					 alg->cra_ablkcipher.ivsize))
+ 		type |= CRYPTO_ALG_TESTED;
++#endif
+ 
+ 	param->type = type;
+ 
diff --git a/target/linux/generic/patches-4.4/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch b/target/linux/generic/patches-4.4/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
new file mode 100644
index 0000000000..762f4989b6
--- /dev/null
+++ b/target/linux/generic/patches-4.4/270-uapi-kernel.h-glibc-specific-inclusion-of-sysinfo.h.patch
@@ -0,0 +1,34 @@
+From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 14:37:54 +0200
+Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h
+
+including sysinfo.h from kernel.h makes no sense whatsoever,
+but removing it breaks glibc's userspace header,
+which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h.
+this seems to be a historical mistake.
+on musl, including any header that uses kernel.h directly or indirectly
+plus sys/sysinfo.h will produce a compile error due to redefinition of
+struct sysinfo from sys/sysinfo.h.
+so for now, only include it on glibc or when including from kernel
+in order not to break their headers.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Signed-off-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/kernel.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/uapi/linux/kernel.h
++++ b/include/uapi/linux/kernel.h
+@@ -1,7 +1,9 @@
+ #ifndef _UAPI_LINUX_KERNEL_H
+ #define _UAPI_LINUX_KERNEL_H
+ 
++#if defined(__KERNEL__) || defined( __GLIBC__)
+ #include <linux/sysinfo.h>
++#endif
+ 
+ /*
+  * 'kernel.h' contains some often-used function prototypes etc
diff --git a/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch b/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
new file mode 100644
index 0000000000..2a29535eed
--- /dev/null
+++ b/target/linux/generic/patches-4.4/271-uapi-libc-compat.h-do-not-rely-on-__GLIBC__.patch
@@ -0,0 +1,94 @@
+From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 16:50:40 +0200
+Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__
+
+Musl provides the same structs as glibc, but does not provide a define to
+allow its detection. Since the absence of __GLIBC__ also can mean that it
+is included from the kernel, change the __GLIBC__ detection to
+!__KERNEL__, which should always be true when included from userspace.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/libc-compat.h | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -48,13 +48,13 @@
+ #ifndef _UAPI_LIBC_COMPAT_H
+ #define _UAPI_LIBC_COMPAT_H
+ 
+-/* We have included glibc headers... */
+-#if defined(__GLIBC__)
++/* We have included libc headers... */
++#if !defined(__KERNEL__)
+ 
+-/* Coordinate with glibc net/if.h header. */
++/* Coordinate with libc net/if.h header. */
+ #if defined(_NET_IF_H) && defined(__USE_MISC)
+ 
+-/* GLIBC headers included first so don't define anything
++/* LIBC headers included first so don't define anything
+  * that would already be defined. */
+ 
+ #define __UAPI_DEF_IF_IFCONF 0
+@@ -85,10 +85,10 @@
+ 
+ #endif /* _NET_IF_H */
+ 
+-/* Coordinate with glibc netinet/in.h header. */
++/* Coordinate with libc netinet/in.h header. */
+ #if defined(_NETINET_IN_H)
+ 
+-/* GLIBC headers included first so don't define anything
++/* LIBC headers included first so don't define anything
+  * that would already be defined. */
+ #define __UAPI_DEF_IN_ADDR		0
+ #define __UAPI_DEF_IN_IPPROTO		0
+@@ -102,7 +102,7 @@
+  * if the glibc code didn't define them. This guard matches
+  * the guard in glibc/inet/netinet/in.h which defines the
+  * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
+-#if defined(__USE_MISC) || defined (__USE_GNU)
++#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU)
+ #define __UAPI_DEF_IN6_ADDR_ALT		0
+ #else
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
+@@ -117,7 +117,7 @@
+ #else
+ 
+ /* Linux headers included first, and we must define everything
+- * we need. The expectation is that glibc will check the
++ * we need. The expectation is that the libc will check the
+  * __UAPI_DEF_* defines and adjust appropriately. */
+ #define __UAPI_DEF_IN_ADDR		1
+ #define __UAPI_DEF_IN_IPPROTO		1
+@@ -127,7 +127,7 @@
+ #define __UAPI_DEF_IN_CLASS		1
+ 
+ #define __UAPI_DEF_IN6_ADDR		1
+-/* We unconditionally define the in6_addr macros and glibc must
++/* We unconditionally define the in6_addr macros and the libc must
+  * coordinate. */
+ #define __UAPI_DEF_IN6_ADDR_ALT		1
+ #define __UAPI_DEF_SOCKADDR_IN6		1
+@@ -149,7 +149,7 @@
+ /* If we did not see any headers from any supported C libraries,
+  * or we are being included in the kernel, then define everything
+  * that we need. */
+-#else /* !defined(__GLIBC__) */
++#else /* defined(__KERNEL__) */
+ 
+ /* Definitions for if.h */
+ #define __UAPI_DEF_IF_IFCONF 1
+@@ -182,6 +182,6 @@
+ /* Definitions for xattr.h */
+ #define __UAPI_DEF_XATTR		1
+ 
+-#endif /* __GLIBC__ */
++#endif /* __KERNEL__ */
+ 
+ #endif /* _UAPI_LIBC_COMPAT_H */
diff --git a/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch b/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
new file mode 100644
index 0000000000..9065369040
--- /dev/null
+++ b/target/linux/generic/patches-4.4/272-uapi-if_ether.h-prevent-redefinition-of-struct-ethhd.patch
@@ -0,0 +1,67 @@
+From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001
+From: David Heidelberger <david.heidelberger@ixit.cz>
+Date: Mon, 29 Jun 2015 16:53:03 +0200
+Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr
+
+Musl provides its own ethhdr struct definition. Add a guard to prevent
+its definition of the appropriate musl header has already been included.
+
+Signed-off-by: John Spencer <maillist-linux@barfooze.de>
+Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/if_ether.h    |  3 +++
+ include/uapi/linux/libc-compat.h | 11 +++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/include/uapi/linux/if_ether.h
++++ b/include/uapi/linux/if_ether.h
+@@ -22,6 +22,7 @@
+ #define _UAPI_LINUX_IF_ETHER_H
+ 
+ #include <linux/types.h>
++#include <linux/libc-compat.h>
+ 
+ /*
+  *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+@@ -135,11 +136,13 @@
+  *	This is an Ethernet frame header.
+  */
+ 
++#if __UAPI_DEF_ETHHDR
+ struct ethhdr {
+ 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+ 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+ 	__be16		h_proto;		/* packet type ID field	*/
+ } __attribute__((packed));
++#endif
+ 
+ 
+ #endif /* _UAPI_LINUX_IF_ETHER_H */
+--- a/include/uapi/linux/libc-compat.h
++++ b/include/uapi/linux/libc-compat.h
+@@ -85,6 +85,14 @@
+ 
+ #endif /* _NET_IF_H */
+ 
++/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
++ * Glibc just includes the kernel header and uses a different guard. */
++#if defined(_NETINET_IF_ETHER_H)
++#define __UAPI_DEF_ETHHDR		0
++#else
++#define __UAPI_DEF_ETHHDR		1
++#endif
++
+ /* Coordinate with libc netinet/in.h header. */
+ #if defined(_NETINET_IN_H)
+ 
+@@ -161,6 +169,9 @@
+ /* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+ #define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+ 
++/* Definitions for if_ether.h */
++#define __UAPI_DEF_ETHHDR 		1
++
+ /* Definitions for in.h */
+ #define __UAPI_DEF_IN_ADDR		1
+ #define __UAPI_DEF_IN_IPPROTO		1
diff --git a/target/linux/generic/patches-4.4/280-rfkill-stubs.patch b/target/linux/generic/patches-4.4/280-rfkill-stubs.patch
new file mode 100644
index 0000000000..96a98e219a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/280-rfkill-stubs.patch
@@ -0,0 +1,79 @@
+--- a/net/rfkill/Kconfig
++++ b/net/rfkill/Kconfig
+@@ -1,7 +1,11 @@
+ #
+ # RF switch subsystem configuration
+ #
+-menuconfig RFKILL
++config RFKILL
++	bool
++	default y
++
++menuconfig RFKILL_FULL
+ 	tristate "RF switch subsystem support"
+ 	help
+ 	  Say Y here if you want to have control over RF switches
+@@ -13,19 +17,19 @@ menuconfig RFKILL
+ # LED trigger support
+ config RFKILL_LEDS
+ 	bool
+-	depends on RFKILL
++	depends on RFKILL_FULL
+ 	depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
+ 	default y
+ 
+ config RFKILL_INPUT
+ 	bool "RF switch input support" if EXPERT
+-	depends on RFKILL
++	depends on RFKILL_FULL
+ 	depends on INPUT = y || RFKILL = INPUT
+ 	default y if !EXPERT
+ 
+ config RFKILL_REGULATOR
+ 	tristate "Generic rfkill regulator driver"
+-	depends on RFKILL || !RFKILL
++	depends on RFKILL_FULL || !RFKILL_FULL
+ 	depends on REGULATOR
+ 	help
+           This options enable controlling radio transmitters connected to
+@@ -36,7 +40,7 @@ config RFKILL_REGULATOR
+ 
+ config RFKILL_GPIO
+ 	tristate "GPIO RFKILL driver"
+-	depends on RFKILL
++	depends on RFKILL_FULL
+ 	depends on GPIOLIB || COMPILE_TEST
+ 	default n
+ 	help
+--- a/net/rfkill/Makefile
++++ b/net/rfkill/Makefile
+@@ -4,6 +4,6 @@
+ 
+ rfkill-y			+= core.o
+ rfkill-$(CONFIG_RFKILL_INPUT)	+= input.o
+-obj-$(CONFIG_RFKILL)		+= rfkill.o
++obj-$(CONFIG_RFKILL_FULL)	+= rfkill.o
+ obj-$(CONFIG_RFKILL_REGULATOR)	+= rfkill-regulator.o
+ obj-$(CONFIG_RFKILL_GPIO)	+= rfkill-gpio.o
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -49,7 +49,7 @@ obj-$(CONFIG_MAC80211)		+= mac80211/
+ obj-$(CONFIG_TIPC)		+= tipc/
+ obj-$(CONFIG_NETLABEL)		+= netlabel/
+ obj-$(CONFIG_IUCV)		+= iucv/
+-obj-$(CONFIG_RFKILL)		+= rfkill/
++obj-$(CONFIG_RFKILL_FULL)	+= rfkill/
+ obj-$(CONFIG_NET_9P)		+= 9p/
+ obj-$(CONFIG_CAIF)		+= caif/
+ ifneq ($(CONFIG_DCB),)
+--- a/include/linux/rfkill.h
++++ b/include/linux/rfkill.h
+@@ -64,7 +64,7 @@ struct rfkill_ops {
+ 	int	(*set_block)(void *data, bool blocked);
+ };
+ 
+-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
++#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE)
+ /**
+  * rfkill_alloc - allocate rfkill structure
+  * @name: name of the struct -- the string is not copied internally
diff --git a/target/linux/generic/patches-4.4/300-mips_expose_boot_raw.patch b/target/linux/generic/patches-4.4/300-mips_expose_boot_raw.patch
new file mode 100644
index 0000000000..76c70782a9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/300-mips_expose_boot_raw.patch
@@ -0,0 +1,39 @@
+From: Mark Miller <mark@mirell.org>
+
+This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
+certain Broadcom chipsets running CFE in order to load the kernel.
+
+Signed-off-by: Mark Miller <mark@mirell.org>
+Acked-by: Rob Landley <rob@landley.net>
+---
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1032,9 +1032,6 @@ config FW_ARC
+ config ARCH_MAY_HAVE_PC_FDC
+ 	bool
+ 
+-config BOOT_RAW
+-	bool
+-
+ config CEVT_BCM1480
+ 	bool
+ 
+@@ -2792,6 +2789,18 @@ choice
+ 		bool "Bootloader kernel arguments if available"
+ endchoice
+ 
++config BOOT_RAW
++	bool "Enable the kernel to be executed from the load address"
++	default n
++	help
++	 Allow the kernel to be executed from the load address for
++	 bootloaders which cannot read the ELF format. This places
++	 a jump to start_kernel at the load address.
++
++	 If unsure, say N.
++
++
++
+ endmenu
+ 
+ config LOCKDEP_SUPPORT
diff --git a/target/linux/generic/patches-4.4/301-mips_image_cmdline_hack.patch b/target/linux/generic/patches-4.4/301-mips_image_cmdline_hack.patch
new file mode 100644
index 0000000000..878f74d69f
--- /dev/null
+++ b/target/linux/generic/patches-4.4/301-mips_image_cmdline_hack.patch
@@ -0,0 +1,28 @@
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1123,6 +1123,10 @@ config SYNC_R4K
+ config MIPS_MACHINE
+ 	def_bool n
+ 
++config IMAGE_CMDLINE_HACK
++	bool "OpenWrt specific image command line hack"
++	default n
++
+ config NO_IOPORT_MAP
+ 	def_bool n
+ 
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry)
+ 	j	kernel_entry
+ #endif
+ 
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++	.ascii	"CMDLINE:"
++EXPORT(__image_cmdline)
++	.fill	0x400
++#endif /* CONFIG_IMAGE_CMDLINE_HACK */
++
+ 	__REF
+ 
+ NESTED(kernel_entry, 16, sp)			# kernel entry point
diff --git a/target/linux/generic/patches-4.4/302-mips_no_branch_likely.patch b/target/linux/generic/patches-4.4/302-mips_no_branch_likely.patch
new file mode 100644
index 0000000000..44c6b04fcf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/302-mips_no_branch_likely.patch
@@ -0,0 +1,11 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ # machines may also.  Since BFD is incredibly buggy with respect to
+ # crossformat linking we rely on the elf2ecoff tool for format conversion.
+ #
+-cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
++cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
diff --git a/target/linux/generic/patches-4.4/304-mips_disable_fpu.patch b/target/linux/generic/patches-4.4/304-mips_disable_fpu.patch
new file mode 100644
index 0000000000..aabb4f12b2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/304-mips_disable_fpu.patch
@@ -0,0 +1,106 @@
+From:   Manuel Lauss <manuel.lauss@gmail.com>
+Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
+Date:   Mon,  7 Apr 2014 12:57:04 +0200
+Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com>
+
+This small patch makes the MIPS FPU emulator optional. The kernel
+kills float-users on systems without a hardware FPU by sending a SIGILL.
+
+Disabling the emulator shrinks vmlinux by about 54kBytes (32bit,
+optimizing for size).
+
+Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
+---
+v4: rediffed because of patch 1/2, should now work with micromips as well
+v3: updated patch description with size savings.
+v2: incorporated changes suggested by Jonas Gorski
+    force the fpu emulator on for micromips: relocating the parts
+    of the mmips code in the emulator to other areas would be a
+    much larger change; I went the cheap route instead with this.
+
+ arch/mips/Kbuild                     |  2 +-
+ arch/mips/Kconfig                    | 14 ++++++++++++++
+ arch/mips/include/asm/fpu.h          |  5 +++--
+ arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++
+ 4 files changed, 33 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -2724,6 +2724,20 @@ config MIPS_O32_FP64_SUPPORT
+ 
+ 	  If unsure, say N.
+ 
++config MIPS_FPU_EMULATOR
++	bool "MIPS FPU Emulator"
++	default y
++	help
++	  This option lets you disable the built-in MIPS FPU (Coprocessor 1)
++	  emulator, which handles floating-point instructions on processors
++	  without a hardware FPU.  It is generally a good idea to keep the
++	  emulator built-in, unless you are perfectly sure you have a
++	  complete soft-float environment.  With the emulator disabled, all
++	  users of float operations will be killed with an illegal instr-
++	  uction exception.
++
++	  Say Y, please.
++
+ config USE_OF
+ 	bool
+ 	select OF
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -285,7 +285,7 @@ OBJCOPYFLAGS		+= --remove-section=.regin
+ head-y := arch/mips/kernel/head.o
+ 
+ libs-y			+= arch/mips/lib/
+-libs-y			+= arch/mips/math-emu/
++libs-$(CONFIG_MIPS_FPU_EMULATOR)	+= arch/mips/math-emu/
+ 
+ # See arch/mips/Kbuild for content of core part of the kernel
+ core-y += arch/mips/
+--- a/arch/mips/include/asm/fpu.h
++++ b/arch/mips/include/asm/fpu.h
+@@ -223,8 +223,10 @@ static inline int init_fpu(void)
+ 		/* Restore FRE */
+ 		write_c0_config5(config5);
+ 		enable_fpu_hazard();
+-	} else
++	} else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR))
+ 		fpu_emulator_init_fpu();
++	else
++		ret = SIGILL;
+ 
+ 	return ret;
+ }
+--- a/arch/mips/include/asm/fpu_emulator.h
++++ b/arch/mips/include/asm/fpu_emulator.h
+@@ -30,6 +30,7 @@
+ #include <asm/local.h>
+ #include <asm/processor.h>
+ 
++#ifdef CONFIG_MIPS_FPU_EMULATOR
+ #ifdef CONFIG_DEBUG_FS
+ 
+ struct mips_fpu_emulator_stats {
+@@ -66,6 +67,21 @@ extern int do_dsemulret(struct pt_regs *
+ extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
+ 				    struct mips_fpu_struct *ctx, int has_fpu,
+ 				    void *__user *fault_addr);
++#else	/* no CONFIG_MIPS_FPU_EMULATOR */
++static inline int do_dsemulret(struct pt_regs *xcp)
++{
++	return 0;	/* 0 means error, should never get here anyway */
++}
++
++static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
++				struct mips_fpu_struct *ctx, int has_fpu,
++				void *__user *fault_addr)
++{
++	*fault_addr = NULL;
++	return SIGILL;	/* we don't speak MIPS FPU */
++}
++#endif	/* CONFIG_MIPS_FPU_EMULATOR */
++
+ int process_fpemu_return(int sig, void __user *fault_addr,
+ 			 unsigned long fcr31);
+ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
diff --git a/target/linux/generic/patches-4.4/305-mips_module_reloc.patch b/target/linux/generic/patches-4.4/305-mips_module_reloc.patch
new file mode 100644
index 0000000000..8b3975fe09
--- /dev/null
+++ b/target/linux/generic/patches-4.4/305-mips_module_reloc.patch
@@ -0,0 +1,352 @@
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib --gc-sections
++ifdef CONFIG_64BIT
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
++else
++KBUILD_AFLAGS_MODULE		+= -mno-long-calls
++KBUILD_CFLAGS_MODULE		+= -mno-long-calls
++endif
+ 
+ ifndef CONFIG_FUNCTION_TRACER
+ KBUILD_CFLAGS_KERNEL		+= -ffunction-sections -fdata-sections
+--- a/arch/mips/include/asm/module.h
++++ b/arch/mips/include/asm/module.h
+@@ -11,6 +11,11 @@ struct mod_arch_specific {
+ 	const struct exception_table_entry *dbe_start;
+ 	const struct exception_table_entry *dbe_end;
+ 	struct mips_hi16 *r_mips_hi16_list;
++
++	void *phys_plt_tbl;
++	void *virt_plt_tbl;
++	unsigned int phys_plt_offset;
++	unsigned int virt_plt_offset;
+ };
+ 
+ typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */
+--- a/arch/mips/kernel/module.c
++++ b/arch/mips/kernel/module.c
+@@ -43,14 +43,221 @@ struct mips_hi16 {
+ static LIST_HEAD(dbe_list);
+ static DEFINE_SPINLOCK(dbe_lock);
+ 
+-#ifdef MODULE_START
++/*
++ * Get the potential max trampolines size required of the init and
++ * non-init sections. Only used if we cannot find enough contiguous
++ * physically mapped memory to put the module into.
++ */
++static unsigned int
++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
++             const char *secstrings, unsigned int symindex, bool is_init)
++{
++	unsigned long ret = 0;
++	unsigned int i, j;
++	Elf_Sym *syms;
++
++	/* Everything marked ALLOC (this includes the exported symbols) */
++	for (i = 1; i < hdr->e_shnum; ++i) {
++		unsigned int info = sechdrs[i].sh_info;
++
++		if (sechdrs[i].sh_type != SHT_REL
++		    && sechdrs[i].sh_type != SHT_RELA)
++			continue;
++
++		/* Not a valid relocation section? */
++		if (info >= hdr->e_shnum)
++			continue;
++
++		/* Don't bother with non-allocated sections */
++		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
++			continue;
++
++		/* If it's called *.init*, and we're not init, we're
++                   not interested */
++		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
++		    != is_init)
++			continue;
++
++		syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
++		if (sechdrs[i].sh_type == SHT_REL) {
++			Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rel[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		} else {
++			Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rela[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		}
++	}
++
++	return ret;
++}
++
++#ifndef MODULE_START
++static void *alloc_phys(unsigned long size)
++{
++	unsigned order;
++	struct page *page;
++	struct page *p;
++
++	size = PAGE_ALIGN(size);
++	order = get_order(size);
++
++	page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
++			__GFP_THISNODE, order);
++	if (!page)
++		return NULL;
++
++	split_page(page, order);
++
++	/* mark all pages except for the last one */
++	for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
++		set_bit(PG_owner_priv_1, &p->flags);
++
++	for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
++		__free_page(p);
++
++	return page_address(page);
++}
++#endif
++
++static void free_phys(void *ptr)
++{
++	struct page *page;
++	bool free;
++
++	page = virt_to_page(ptr);
++	do {
++		free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
++		__free_page(page);
++		page++;
++	} while (free);
++}
++
++
+ void *module_alloc(unsigned long size)
+ {
++#ifdef MODULE_START
+ 	return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
+ 				GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
+ 				__builtin_return_address(0));
++#else
++	void *ptr;
++
++	if (size == 0)
++		return NULL;
++
++	ptr = alloc_phys(size);
++
++	/* If we failed to allocate physically contiguous memory,
++	 * fall back to regular vmalloc. The module loader code will
++	 * create jump tables to handle long jumps */
++	if (!ptr)
++		return vmalloc(size);
++
++	return ptr;
++#endif
+ }
++
++static inline bool is_phys_addr(void *ptr)
++{
++#ifdef CONFIG_64BIT
++	return (KSEGX((unsigned long)ptr) == CKSEG0);
++#else
++	return (KSEGX(ptr) == KSEG0);
+ #endif
++}
++
++/* Free memory returned from module_alloc */
++void module_memfree(void *module_region)
++{
++	if (is_phys_addr(module_region))
++		free_phys(module_region);
++	else
++		vfree(module_region);
++}
++
++static void *__module_alloc(int size, bool phys)
++{
++	void *ptr;
++
++	if (phys)
++		ptr = kmalloc(size, GFP_KERNEL);
++	else
++		ptr = vmalloc(size);
++	return ptr;
++}
++
++static void __module_free(void *ptr)
++{
++	if (is_phys_addr(ptr))
++		kfree(ptr);
++	else
++		vfree(ptr);
++}
++
++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
++			      char *secstrings, struct module *mod)
++{
++	unsigned int symindex = 0;
++	unsigned int core_size, init_size;
++	int i;
++
++	mod->arch.phys_plt_offset = 0;
++	mod->arch.virt_plt_offset = 0;
++	mod->arch.phys_plt_tbl = NULL;
++	mod->arch.virt_plt_tbl = NULL;
++
++	if (IS_ENABLED(CONFIG_64BIT))
++		return 0;
++
++	for (i = 1; i < hdr->e_shnum; i++)
++		if (sechdrs[i].sh_type == SHT_SYMTAB)
++			symindex = i;
++
++	core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
++	init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
++
++	if ((core_size + init_size) == 0)
++		return 0;
++
++	mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
++	if (!mod->arch.phys_plt_tbl)
++		return -ENOMEM;
++
++	mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
++	if (!mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++		return -ENOMEM;
++	}
++
++	return 0;
++}
+ 
+ int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
+ {
+@@ -64,8 +271,39 @@ static int apply_r_mips_32_rel(struct mo
+ 	return 0;
+ }
+ 
++static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
++				 void *start, Elf_Addr v)
++{
++	unsigned *tramp = start + *plt_offset;
++	*plt_offset += 4 * sizeof(int);
++
++	/* adjust carry for addiu */
++	if (v & 0x00008000)
++		v += 0x10000;
++
++	tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
++	tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
++	tramp[2] = 0x03200008;                  /* jr t9 */
++	tramp[3] = 0x00000000;                  /* nop */
++
++	return (Elf_Addr) tramp;
++}
++
++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
++{
++	if (is_phys_addr(location))
++		return add_plt_entry_to(&me->arch.phys_plt_offset,
++				me->arch.phys_plt_tbl, v);
++	else
++		return add_plt_entry_to(&me->arch.virt_plt_offset,
++				me->arch.virt_plt_tbl, v);
++
++}
++
+ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
+ {
++	u32 ofs = *location & 0x03ffffff;
++
+ 	if (v % 4) {
+ 		pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
+ 		       me->name);
+@@ -73,14 +311,17 @@ static int apply_r_mips_26_rel(struct mo
+ 	}
+ 
+ 	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
+-		printk(KERN_ERR
+-		       "module %s: relocation overflow\n",
+-		       me->name);
+-		return -ENOEXEC;
++		v = add_plt_entry(me, location, v + (ofs << 2));
++		if (!v) {
++			printk(KERN_ERR
++				"module %s: relocation overflow\n", me->name);
++			return -ENOEXEC;
++		}
++		ofs = 0;
+ 	}
+ 
+ 	*location = (*location & ~0x03ffffff) |
+-		    ((*location + (v >> 2)) & 0x03ffffff);
++		    ((ofs + (v >> 2)) & 0x03ffffff);
+ 
+ 	return 0;
+ }
+@@ -287,9 +528,33 @@ int module_finalize(const Elf_Ehdr *hdr,
+ 		list_add(&me->arch.dbe_list, &dbe_list);
+ 		spin_unlock_irq(&dbe_lock);
+ 	}
++
++	/* Get rid of the fixup trampoline if we're running the module
++	 * from physically mapped address space */
++	if (me->arch.phys_plt_offset == 0) {
++		__module_free(me->arch.phys_plt_tbl);
++		me->arch.phys_plt_tbl = NULL;
++	}
++	if (me->arch.virt_plt_offset == 0) {
++		__module_free(me->arch.virt_plt_tbl);
++		me->arch.virt_plt_tbl = NULL;
++	}
++
+ 	return 0;
+ }
+ 
++void module_arch_freeing_init(struct module *mod)
++{
++	if (mod->arch.phys_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++	}
++	if (mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.virt_plt_tbl);
++		mod->arch.virt_plt_tbl = NULL;
++	}
++}
++
+ void module_arch_cleanup(struct module *mod)
+ {
+ 	spin_lock_irq(&dbe_lock);
diff --git a/target/linux/generic/patches-4.4/306-mips_mem_functions_performance.patch b/target/linux/generic/patches-4.4/306-mips_mem_functions_performance.patch
new file mode 100644
index 0000000000..9818677425
--- /dev/null
+++ b/target/linux/generic/patches-4.4/306-mips_mem_functions_performance.patch
@@ -0,0 +1,83 @@
+--- a/arch/mips/include/asm/string.h
++++ b/arch/mips/include/asm/string.h
+@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__
+ 
+ #define __HAVE_ARCH_MEMSET
+ extern void *memset(void *__s, int __c, size_t __count);
++#define memset(__s, __c, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memset((__s), (__c), __len);		\
++	else							\
++		__ret = __builtin_memset((__s), (__c), __len);	\
++	__ret;							\
++})
+ 
+ #define __HAVE_ARCH_MEMCPY
+ extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
++#define memcpy(dst, src, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memcpy((dst), (src), __len);		\
++	else							\
++		__ret = __builtin_memcpy((dst), (src), __len);	\
++	__ret;							\
++})
+ 
+ #define __HAVE_ARCH_MEMMOVE
+ extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
++#define memmove(dst, src, len)					\
++({								\
++	size_t __len = (len);					\
++	void *__ret;						\
++	if (__builtin_constant_p(len) && __len >= 64)		\
++		__ret = memmove((dst), (src), __len);		\
++	else							\
++		__ret = __builtin_memmove((dst), (src), __len);	\
++	__ret;							\
++})
++
++#define __HAVE_ARCH_MEMCMP
++#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len))
+ 
+ #endif /* _ASM_STRING_H */
+--- a/arch/mips/lib/Makefile
++++ b/arch/mips/lib/Makefile
+@@ -4,7 +4,7 @@
+ 
+ lib-y	+= bitops.o csum_partial.o delay.o memcpy.o memset.o \
+ 	   mips-atomic.o strlen_user.o strncpy_user.o \
+-	   strnlen_user.o uncached.o
++	   strnlen_user.o uncached.o memcmp.o
+ 
+ obj-y			+= iomap.o
+ obj-$(CONFIG_PCI)	+= iomap-pci.o
+--- /dev/null
++++ b/arch/mips/lib/memcmp.c
+@@ -0,0 +1,22 @@
++/*
++ *  copied from linux/lib/string.c
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++
++#undef memcmp
++int memcmp(const void *cs, const void *ct, size_t count)
++{
++	const unsigned char *su1, *su2;
++	int res = 0;
++
++	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
++		if ((res = *su1 - *su2) != 0)
++			break;
++	return res;
++}
++EXPORT_SYMBOL(memcmp);
++
diff --git a/target/linux/generic/patches-4.4/307-mips_highmem_offset.patch b/target/linux/generic/patches-4.4/307-mips_highmem_offset.patch
new file mode 100644
index 0000000000..5a7dc9cee9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/307-mips_highmem_offset.patch
@@ -0,0 +1,17 @@
+Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations
+stay within the same 256M boundary. This ensures that -mlong-calls is not
+needed on systems with more than 256M RAM.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/arch/mips/include/asm/mach-generic/spaces.h
++++ b/arch/mips/include/asm/mach-generic/spaces.h
+@@ -44,7 +44,7 @@
+  * Memory above this physical address will be considered highmem.
+  */
+ #ifndef HIGHMEM_START
+-#define HIGHMEM_START		_AC(0x20000000, UL)
++#define HIGHMEM_START		_AC(0x10000000, UL)
+ #endif
+ 
+ #endif /* CONFIG_32BIT */
diff --git a/target/linux/generic/patches-4.4/308-mips32r2_tune.patch b/target/linux/generic/patches-4.4/308-mips32r2_tune.patch
new file mode 100644
index 0000000000..f4ab89ef28
--- /dev/null
+++ b/target/linux/generic/patches-4.4/308-mips32r2_tune.patch
@@ -0,0 +1,17 @@
+Add -mtune=34kc to MIPS CFLAGS when building for mips32r2
+This provides a good tradeoff across at least 24Kc-74Kc, while also
+producing smaller code.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -145,7 +145,7 @@ cflags-$(CONFIG_CPU_R4X00)	+= -march=r46
+ cflags-$(CONFIG_CPU_TX49XX)	+= -march=r4600 -Wa,--trap
+ cflags-$(CONFIG_CPU_MIPS32_R1)	+= $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
+ 			-Wa,-mips32 -Wa,--trap
+-cflags-$(CONFIG_CPU_MIPS32_R2)	+= $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
++cflags-$(CONFIG_CPU_MIPS32_R2)	+= $(call cc-option,-march=mips32r2 -mtune=34kc,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
+ 			-Wa,-mips32r2 -Wa,--trap
+ cflags-$(CONFIG_CPU_MIPS32_R6)	+= -march=mips32r6 -Wa,--trap
+ cflags-$(CONFIG_CPU_MIPS64_R1)	+= $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
diff --git a/target/linux/generic/patches-4.4/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/patches-4.4/310-arm_module_unresolved_weak_sym.patch
new file mode 100644
index 0000000000..327a475208
--- /dev/null
+++ b/target/linux/generic/patches-4.4/310-arm_module_unresolved_weak_sym.patch
@@ -0,0 +1,13 @@
+--- a/arch/arm/kernel/module.c
++++ b/arch/arm/kernel/module.c
+@@ -88,6 +88,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
+ 			return -ENOEXEC;
+ 		}
+ 
++		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
++		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
++			continue;
++
+ 		loc = dstsec->sh_addr + rel->r_offset;
+ 
+ 		switch (ELF32_R_TYPE(rel->r_info)) {
diff --git a/target/linux/generic/patches-4.4/320-ppc4xx_optimization.patch b/target/linux/generic/patches-4.4/320-ppc4xx_optimization.patch
new file mode 100644
index 0000000000..c1ce37da2f
--- /dev/null
+++ b/target/linux/generic/patches-4.4/320-ppc4xx_optimization.patch
@@ -0,0 +1,31 @@
+Upstream doesn't optimize the kernel and bootwrappers for ppc44x because
+they still want to support gcc 3.3 -- well, we don't.
+
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -205,7 +205,8 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ KBUILD_CFLAGS		+= -mno-sched-epilog
+ endif
+ 
+-cpu-as-$(CONFIG_4xx)		+= -Wa,-m405
++cpu-as-$(CONFIG_40x)		+= -Wa,-m405
++cpu-as-$(CONFIG_44x)		+= -Wa,-m440
+ cpu-as-$(CONFIG_ALTIVEC)	+= -Wa,-maltivec
+ cpu-as-$(CONFIG_E200)		+= -Wa,-me200
+ 
+--- a/arch/powerpc/boot/Makefile
++++ b/arch/powerpc/boot/Makefile
+@@ -48,10 +48,10 @@ BOOTCFLAGS	+= -I$(obj) -I$(srctree)/$(ob
+ DTC_FLAGS	?= -p 1024
+ 
+ $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
++$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
+ $(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
+-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
++$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440
++$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440
+ $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
+ $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
+ $(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405
diff --git a/target/linux/generic/patches-4.4/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/patches-4.4/321-powerpc_crtsavres_prereq.patch
new file mode 100644
index 0000000000..a1773feb39
--- /dev/null
+++ b/target/linux/generic/patches-4.4/321-powerpc_crtsavres_prereq.patch
@@ -0,0 +1,10 @@
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -167,7 +167,6 @@ CPP		= $(CC) -E $(KBUILD_CFLAGS)
+ 
+ CHECKFLAGS	+= -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
+ 
+-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+ 
+ ifeq ($(CONFIG_476FPE_ERR46),y)
+ 	KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
diff --git a/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
new file mode 100644
index 0000000000..a69d197e62
--- /dev/null
+++ b/target/linux/generic/patches-4.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
@@ -0,0 +1,298 @@
+From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Sat, 31 Jan 2015 22:26:03 +0800
+Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from
+ userspace.
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ arch/mips/kernel/machine_kexec.c   |  153 +++++++++++++++++++++++++++++++-----
+ arch/mips/kernel/machine_kexec.h   |   20 +++++
+ arch/mips/kernel/relocate_kernel.S |   21 +++--
+ 3 files changed, 167 insertions(+), 27 deletions(-)
+ create mode 100644 arch/mips/kernel/machine_kexec.h
+
+--- a/arch/mips/kernel/machine_kexec.c
++++ b/arch/mips/kernel/machine_kexec.c
+@@ -10,45 +10,145 @@
+ #include <linux/mm.h>
+ #include <linux/delay.h>
+ 
++#include <asm/bootinfo.h>
+ #include <asm/cacheflush.h>
+ #include <asm/page.h>
+-
+-extern const unsigned char relocate_new_kernel[];
+-extern const size_t relocate_new_kernel_size;
+-
+-extern unsigned long kexec_start_address;
+-extern unsigned long kexec_indirection_page;
++#include <asm/uaccess.h>
++#include "machine_kexec.h"
+ 
+ int (*_machine_kexec_prepare)(struct kimage *) = NULL;
+ void (*_machine_kexec_shutdown)(void) = NULL;
+ void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
++
+ #ifdef CONFIG_SMP
+ void (*relocated_kexec_smp_wait) (void *);
+ atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
+ #endif
+ 
+-int
+-machine_kexec_prepare(struct kimage *kimage)
++static void machine_kexec_print_args(void)
+ {
++	unsigned long argc = (int)kexec_args[0];
++	int i;
++
++	pr_info("kexec_args[0] (argc): %lu\n", argc);
++	pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
++	pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
++	pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
++
++	for (i = 0; i < argc; i++) {
++		pr_info("kexec_argv[%d] = %p, %s\n",
++				i, kexec_argv[i], kexec_argv[i]);
++	}
++}
++
++static void machine_kexec_init_argv(struct kimage *image)
++{
++	void __user *buf = NULL;
++	size_t bufsz;
++	size_t size;
++	int i;
++
++	bufsz = 0;
++	for (i = 0; i < image->nr_segments; i++) {
++		struct kexec_segment *seg;
++
++		seg = &image->segment[i];
++		if (seg->bufsz < 6)
++			continue;
++
++		if (strncmp((char *) seg->buf, "kexec ", 6))
++			continue;
++
++		buf = seg->buf;
++		bufsz = seg->bufsz;
++		break;
++	}
++
++	if (!buf)
++		return;
++
++	size = KEXEC_COMMAND_LINE_SIZE;
++	size = min(size, bufsz);
++	if (size < bufsz)
++		pr_warn("kexec command line truncated to %zd bytes\n", size);
++
++	/* Copy to kernel space */
++	copy_from_user(kexec_argv_buf, buf, size);
++	kexec_argv_buf[size - 1] = 0;
++}
++
++static void machine_kexec_parse_argv(struct kimage *image)
++{
++	char *reboot_code_buffer;
++	int reloc_delta;
++	char *ptr;
++	int argc;
++	int i;
++
++	ptr = kexec_argv_buf;
++	argc = 0;
++
++	/*
++	 * convert command line string to array of parameters
++	 * (as bootloader does).
++	 */
++	while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
++		if (*ptr == ' ') {
++			*ptr++ = '\0';
++			continue;
++		}
++
++		kexec_argv[argc++] = ptr;
++		ptr = strchr(ptr, ' ');
++	}
++
++	if (!argc)
++		return;
++
++	kexec_args[0] = argc;
++	kexec_args[1] = (unsigned long)kexec_argv;
++	kexec_args[2] = 0;
++	kexec_args[3] = 0;
++
++	reboot_code_buffer = page_address(image->control_code_page);
++	reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
++
++	kexec_args[1] += reloc_delta;
++	for (i = 0; i < argc; i++)
++		kexec_argv[i] += reloc_delta;
++}
++
++int machine_kexec_prepare(struct kimage *kimage)
++{
++	/*
++	 * Whenever arguments passed from kexec-tools, Init the arguments as
++	 * the original ones to try avoiding booting failure.
++	 */
++
++	kexec_args[0] = fw_arg0;
++	kexec_args[1] = fw_arg1;
++	kexec_args[2] = fw_arg2;
++	kexec_args[3] = fw_arg3;
++
++	machine_kexec_init_argv(kimage);
++	machine_kexec_parse_argv(kimage);
++
+ 	if (_machine_kexec_prepare)
+ 		return _machine_kexec_prepare(kimage);
+ 	return 0;
+ }
+ 
+-void
+-machine_kexec_cleanup(struct kimage *kimage)
++void machine_kexec_cleanup(struct kimage *kimage)
+ {
+ }
+ 
+-void
+-machine_shutdown(void)
++void machine_shutdown(void)
+ {
+ 	if (_machine_kexec_shutdown)
+ 		_machine_kexec_shutdown();
+ }
+ 
+-void
+-machine_crash_shutdown(struct pt_regs *regs)
++void machine_crash_shutdown(struct pt_regs *regs)
+ {
+ 	if (_machine_crash_shutdown)
+ 		_machine_crash_shutdown(regs);
+@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image)
+ 	unsigned long *ptr;
+ 
+ 	reboot_code_buffer =
+-	  (unsigned long)page_address(image->control_code_page);
++		(unsigned long)page_address(image->control_code_page);
++	pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
+ 
+ 	kexec_start_address =
+ 		(unsigned long) phys_to_virt(image->start);
++	pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
+ 
+ 	if (image->type == KEXEC_TYPE_DEFAULT) {
+ 		kexec_indirection_page =
+@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image)
+ 	} else {
+ 		kexec_indirection_page = (unsigned long)&image->head;
+ 	}
++	pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
+ 
+-	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
+-	       relocate_new_kernel_size);
++	pr_info("Where is memcpy: %p\n", memcpy);
++	pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
++		(void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
++	pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
++		(void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
++	memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
++	       KEXEC_RELOCATE_NEW_KERNEL_SIZE);
++
++	pr_info("Before _print_args().\n");
++	machine_kexec_print_args();
++	pr_info("Before eval loop.\n");
+ 
+ 	/*
+ 	 * The generic kexec code builds a page list with physical
+@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image)
+ 	/*
+ 	 * we do not want to be bothered.
+ 	 */
++	pr_info("Before irq_disable.\n");
+ 	local_irq_disable();
+ 
+-	printk("Will call new kernel at %08lx\n", image->start);
+-	printk("Bye ...\n");
++	pr_info("Will call new kernel at %08lx\n", image->start);
++	pr_info("Bye ...\n");
+ 	__flush_cache_all();
+ #ifdef CONFIG_SMP
+ 	/* All secondary cpus now may jump to kexec_wait cycle */
+ 	relocated_kexec_smp_wait = reboot_code_buffer +
+-		(void *)(kexec_smp_wait - relocate_new_kernel);
++		(void *)(kexec_smp_wait - kexec_relocate_new_kernel);
+ 	smp_wmb();
+ 	atomic_set(&kexec_ready_to_reboot, 1);
+ #endif
+--- /dev/null
++++ b/arch/mips/kernel/machine_kexec.h
+@@ -0,0 +1,20 @@
++#ifndef _MACHINE_KEXEC_H
++#define _MACHINE_KEXEC_H
++
++#ifndef __ASSEMBLY__
++extern const unsigned char kexec_relocate_new_kernel[];
++extern unsigned long kexec_relocate_new_kernel_end;
++extern unsigned long kexec_start_address;
++extern unsigned long kexec_indirection_page;
++
++extern char kexec_argv_buf[];
++extern char *kexec_argv[];
++
++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE	((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
++#endif /* !__ASSEMBLY__ */
++
++#define KEXEC_COMMAND_LINE_SIZE		256
++#define KEXEC_ARGV_SIZE			(KEXEC_COMMAND_LINE_SIZE / 16)
++#define KEXEC_MAX_ARGC			(KEXEC_ARGV_SIZE / sizeof(long))
++
++#endif
+--- a/arch/mips/kernel/relocate_kernel.S
++++ b/arch/mips/kernel/relocate_kernel.S
+@@ -12,8 +12,9 @@
+ #include <asm/mipsregs.h>
+ #include <asm/stackframe.h>
+ #include <asm/addrspace.h>
++#include "machine_kexec.h"
+ 
+-LEAF(relocate_new_kernel)
++LEAF(kexec_relocate_new_kernel)
+ 	PTR_L a0,	arg0
+ 	PTR_L a1,	arg1
+ 	PTR_L a2,	arg2
+@@ -98,7 +99,7 @@ done:
+ #endif
+ 	/* jump to kexec_start_address */
+ 	j		s1
+-	END(relocate_new_kernel)
++	END(kexec_relocate_new_kernel)
+ 
+ #ifdef CONFIG_SMP
+ /*
+@@ -184,9 +185,15 @@ kexec_indirection_page:
+ 	PTR		0
+ 	.size		kexec_indirection_page, PTRSIZE
+ 
+-relocate_new_kernel_end:
++kexec_argv_buf:
++	EXPORT(kexec_argv_buf)
++	.skip		KEXEC_COMMAND_LINE_SIZE
++	.size		kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
++
++kexec_argv:
++	EXPORT(kexec_argv)
++	.skip		KEXEC_ARGV_SIZE
++	.size		kexec_argv, KEXEC_ARGV_SIZE
+ 
+-relocate_new_kernel_size:
+-	EXPORT(relocate_new_kernel_size)
+-	PTR		relocate_new_kernel_end - relocate_new_kernel
+-	.size		relocate_new_kernel_size, PTRSIZE
++kexec_relocate_new_kernel_end:
++	EXPORT(kexec_relocate_new_kernel_end)
diff --git a/target/linux/generic/patches-4.4/331-arc-remove-dependency-on-DEVTMPFS.patch b/target/linux/generic/patches-4.4/331-arc-remove-dependency-on-DEVTMPFS.patch
new file mode 100644
index 0000000000..48b3f9b428
--- /dev/null
+++ b/target/linux/generic/patches-4.4/331-arc-remove-dependency-on-DEVTMPFS.patch
@@ -0,0 +1,31 @@
+From adfbf9e6cad93281cffceab078e7f6f2a8e094f9 Mon Sep 17 00:00:00 2001
+From: Alexey Brodkin <abrodkin@synopsys.com>
+Date: Thu, 13 Aug 2015 01:56:02 +0300
+Subject: [PATCH 1/2] openwrt: arc - remove dependency on DEVTMPFS
+
+OpenWRT builds initramfs so that it doesn't require DEVTMPFS so dropping
+this dependency. That helps to escape 2 separate kernel rebuilds with
+and without initramfs.
+
+2 builds happen because OpenWRT first builds kernel and later modules.
+When building entire kernel with simple "make" INITRAMFS sets to a real
+value and so was triggering DEVTMPFS selection. Then when building only
+modules with "make modules" command INITRAMFS is zeroed and so kernel
+config was changing that lead to full kernel rebuild.
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+---
+ arch/arc/Kconfig | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/arch/arc/Kconfig
++++ b/arch/arc/Kconfig
+@@ -12,8 +12,6 @@ config ARC
+ 	select BUILDTIME_EXTABLE_SORT
+ 	select COMMON_CLK
+ 	select CLONE_BACKWARDS
+-	# ARC Busybox based initramfs absolutely relies on DEVTMPFS for /dev
+-	select DEVTMPFS if !INITRAMFS_SOURCE=""
+ 	select GENERIC_ATOMIC64
+ 	select GENERIC_CLOCKEVENTS
+ 	select GENERIC_FIND_FIRST_BIT
diff --git a/target/linux/generic/patches-4.4/332-arc-add-OWRTDTB-section.patch b/target/linux/generic/patches-4.4/332-arc-add-OWRTDTB-section.patch
new file mode 100644
index 0000000000..5a2b67cfcd
--- /dev/null
+++ b/target/linux/generic/patches-4.4/332-arc-add-OWRTDTB-section.patch
@@ -0,0 +1,82 @@
+From 690e7f2cad271595ff68cace1c45fb10779bde41 Mon Sep 17 00:00:00 2001
+From: Alexey Brodkin <abrodkin@synopsys.com>
+Date: Fri, 15 Jan 2016 00:34:01 +0300
+Subject: [PATCH 2/2] openwrt: arc - add OWRTDTB section
+
+This change allows OpenWRT to patch resulting kernel binary with
+external .dtb.
+
+That allows us to re-use exactky the same vmlinux on different boards
+given its ARC core configurations match (at least cache line sizes etc).
+
+""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external
+.dtb right after it, keeping the string in place.
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+---
+ arch/arc/kernel/head.S        | 10 ++++++++++
+ arch/arc/kernel/setup.c       |  4 +++-
+ arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++
+ 3 files changed, 26 insertions(+), 1 deletion(-)
+
+--- a/arch/arc/kernel/head.S
++++ b/arch/arc/kernel/head.S
+@@ -49,6 +49,16 @@
+ 1:
+ .endm
+ 
++; Here "patch-dtb" will embed external .dtb
++; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
++; and pastes .dtb right after it, hense the string precedes
++; __image_dtb symbol.
++	.section .owrt, "aw",@progbits
++	.ascii	"OWRTDTB:"
++ENTRY(__image_dtb)
++	.fill	0x4000
++END(__image_dtb)
++
+ 	.section .init.text, "ax",@progbits
+ 
+ ;----------------------------------------------------------------
+--- a/arch/arc/kernel/setup.c
++++ b/arch/arc/kernel/setup.c
+@@ -366,6 +366,8 @@ static inline int is_kernel(unsigned lon
+ 	return 0;
+ }
+ 
++extern struct boot_param_header __image_dtb;
++
+ void __init setup_arch(char **cmdline_p)
+ {
+ #ifdef CONFIG_ARC_UBOOT_SUPPORT
+@@ -379,7 +381,7 @@ void __init setup_arch(char **cmdline_p)
+ #endif
+ 	{
+ 		/* No, so try the embedded one */
+-		machine_desc = setup_machine_fdt(__dtb_start);
++		machine_desc = setup_machine_fdt(&__image_dtb);
+ 		if (!machine_desc)
+ 			panic("Embedded DT invalid\n");
+ 
+--- a/arch/arc/kernel/vmlinux.lds.S
++++ b/arch/arc/kernel/vmlinux.lds.S
+@@ -30,6 +30,19 @@ SECTIONS
+ 
+ 	. = CONFIG_LINUX_LINK_BASE;
+ 
++	/*
++	 * In OpenWRT we want to patch built binary embedding .dtb of choice.
++	 * This is implemented with "patch-dtb" utility which searches for
++	 * "OWRTDTB:" string in first 16k of image and if it is found
++	 * copies .dtb right after mentioned string.
++	 *
++	 * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
++	 */
++	.owrt : {
++		*(.owrt)
++		. = ALIGN(PAGE_SIZE);
++	}
++
+ 	_int_vec_base_lds = .;
+ 	.vector : {
+ 		*(.vector)
diff --git a/target/linux/generic/patches-4.4/333-arc-enable-unaligned-access-in-kernel-mode.patch b/target/linux/generic/patches-4.4/333-arc-enable-unaligned-access-in-kernel-mode.patch
new file mode 100644
index 0000000000..082f525f1b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/333-arc-enable-unaligned-access-in-kernel-mode.patch
@@ -0,0 +1,26 @@
+From af737b55fc7c61f17da9ae89fba536e0a9338e98 Mon Sep 17 00:00:00 2001
+From: Alexey Brodkin <abrodkin@synopsys.com>
+Date: Mon, 14 Mar 2016 17:26:34 +0300
+Subject: [PATCH] arc: enable unaligned access in kernel mode
+
+This enables misaligned access handling even in kernel mode.
+Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses
+here and there and to cope with that without fixing stuff in the drivers
+we're just gracefully handling it on ARC.
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+---
+ arch/arc/kernel/unaligned.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arc/kernel/unaligned.c
++++ b/arch/arc/kernel/unaligned.c
+@@ -206,7 +206,7 @@ int misaligned_fixup(unsigned long addre
+ 	char buf[TASK_COMM_LEN];
+ 
+ 	/* handle user mode only and only if enabled by sysadmin */
+-	if (!user_mode(regs) || !unaligned_enabled)
++	if (!unaligned_enabled)
+ 		return 1;
+ 
+ 	if (no_unaligned_warning) {
diff --git a/target/linux/generic/patches-4.4/400-mtd-add-rootfs-split-support.patch b/target/linux/generic/patches-4.4/400-mtd-add-rootfs-split-support.patch
new file mode 100644
index 0000000000..7925caf97c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/400-mtd-add-rootfs-split-support.patch
@@ -0,0 +1,113 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -12,6 +12,23 @@ menuconfig MTD
+ 
+ if MTD
+ 
++menu "OpenWrt specific MTD options"
++
++config MTD_ROOTFS_ROOT_DEV
++	bool "Automatically set 'rootfs' partition to be root filesystem"
++	default y
++
++config MTD_SPLIT_FIRMWARE
++	bool "Automatically split firmware partition for kernel+rootfs"
++	default y
++
++config MTD_SPLIT_FIRMWARE_NAME
++	string "Firmware partition name"
++	depends on MTD_SPLIT_FIRMWARE
++	default "firmware"
++
++endmenu
++
+ config MTD_TESTS
+ 	tristate "MTD tests support (DANGEROUS)"
+ 	depends on m
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -29,11 +29,13 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/magic.h>
+ #include <linux/of.h>
+ #include <linux/err.h>
+ #include <linux/kconfig.h>
+ 
+ #include "mtdcore.h"
++#include "mtdsplit/mtdsplit.h"
+ 
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+@@ -47,6 +49,8 @@ struct mtd_part {
+ 	struct list_head list;
+ };
+ 
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
++
+ /*
+  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+  * the pointer to that structure with this macro.
+@@ -612,6 +616,7 @@ int mtd_add_partition(struct mtd_info *m
+ 	mutex_unlock(&mtd_partitions_mutex);
+ 
+ 	add_mtd_device(&new->mtd);
++	mtd_partition_split(master, new);
+ 
+ 	mtd_add_partition_attrs(new);
+ 
+@@ -644,6 +649,35 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#else
++#define SPLIT_FIRMWARE_NAME	"unused"
++#endif
++
++static void split_firmware(struct mtd_info *master, struct mtd_part *part)
++{
++}
++
++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
++                                int offset, int size)
++{
++}
++
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
++{
++	static int rootfs_found = 0;
++
++	if (rootfs_found)
++		return;
++
++	if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
++	    config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
++		split_firmware(master, part);
++
++	arch_split_mtd_part(master, part->mtd.name, part->offset,
++			    part->mtd.size);
++}
+ /*
+  * This function, given a master MTD object and a partition table, creates
+  * and registers slave MTD objects which are bound to the master according to
+@@ -675,6 +709,7 @@ int add_mtd_partitions(struct mtd_info *
+ 		mutex_unlock(&mtd_partitions_mutex);
+ 
+ 		add_mtd_device(&slave->mtd);
++		mtd_partition_split(master, slave);
+ 		mtd_add_partition_attrs(slave);
+ 
+ 		cur_offset = slave->offset + slave->mtd.size;
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -84,5 +84,7 @@ int mtd_add_partition(struct mtd_info *m
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
++extern void __weak arch_split_mtd_part(struct mtd_info *master,
++				       const char *name, int offset, int size);
+ 
+ #endif
diff --git a/target/linux/generic/patches-4.4/401-mtd-add-support-for-different-partition-parser-types.patch b/target/linux/generic/patches-4.4/401-mtd-add-support-for-different-partition-parser-types.patch
new file mode 100644
index 0000000000..7695d56de9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/401-mtd-add-support-for-different-partition-parser-types.patch
@@ -0,0 +1,113 @@
+From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Tue, 3 Sep 2013 18:11:50 +0200
+Subject: [PATCH] mtd: add support for different partition parser types
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdpart.c          |   56 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/partitions.h |   11 ++++++++
+ 2 files changed, 67 insertions(+)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -740,6 +740,30 @@ static struct mtd_part_parser *get_parti
+ 
+ #define put_partition_parser(p) do { module_put((p)->owner); } while (0)
+ 
++static struct mtd_part_parser *
++get_partition_parser_by_type(enum mtd_parser_type type,
++			     struct mtd_part_parser *start)
++{
++	struct mtd_part_parser *p, *ret = NULL;
++
++	spin_lock(&part_parser_lock);
++
++	p = list_prepare_entry(start, &part_parsers, list);
++	if (start)
++		put_partition_parser(start);
++
++	list_for_each_entry_continue(p, &part_parsers, list) {
++		if (p->type == type && try_module_get(p->owner)) {
++			ret = p;
++			break;
++		}
++	}
++
++	spin_unlock(&part_parser_lock);
++
++	return ret;
++}
++
+ void register_mtd_parser(struct mtd_part_parser *p)
+ {
+ 	spin_lock(&part_parser_lock);
+@@ -868,6 +892,38 @@ int parse_mtd_partitions(struct mtd_info
+ 	return err;
+ }
+ 
++int parse_mtd_partitions_by_type(struct mtd_info *master,
++				 enum mtd_parser_type type,
++				 struct mtd_partition **pparts,
++				 struct mtd_part_parser_data *data)
++{
++	struct mtd_part_parser *prev = NULL;
++	int ret = 0;
++
++	while (1) {
++		struct mtd_part_parser *parser;
++
++		parser = get_partition_parser_by_type(type, prev);
++		if (!parser)
++			break;
++
++		ret = (*parser->parse_fn)(master, pparts, data);
++
++		if (ret > 0) {
++			put_partition_parser(parser);
++			printk(KERN_NOTICE
++			       "%d %s partitions found on MTD device %s\n",
++			       ret, parser->name, master->name);
++			break;
++		}
++
++		prev = parser;
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
++
+ int mtd_is_partition(const struct mtd_info *mtd)
+ {
+ 	struct mtd_part *part;
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -68,12 +68,17 @@ struct mtd_part_parser_data {
+  * Functions dealing with the various ways of partitioning the space
+  */
+ 
++enum mtd_parser_type {
++	MTD_PARSER_TYPE_DEVICE = 0,
++};
++
+ struct mtd_part_parser {
+ 	struct list_head list;
+ 	struct module *owner;
+ 	const char *name;
+ 	int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
+ 			struct mtd_part_parser_data *);
++	enum mtd_parser_type type;
+ };
+ 
+ extern void register_mtd_parser(struct mtd_part_parser *parser);
+@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc
+ extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ 				       const char *name, int offset, int size);
+ 
++int parse_mtd_partitions_by_type(struct mtd_info *master,
++				 enum mtd_parser_type type,
++				 struct mtd_partition **pparts,
++				 struct mtd_part_parser_data *data);
++
+ #endif
diff --git a/target/linux/generic/patches-4.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/target/linux/generic/patches-4.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
new file mode 100644
index 0000000000..2ea2056ba2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
@@ -0,0 +1,71 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -649,6 +649,36 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++static int
++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
++{
++	struct mtd_partition *parts;
++	int nr_parts;
++	int i;
++
++	nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts,
++						NULL);
++	if (nr_parts <= 0)
++		return nr_parts;
++
++	if (WARN_ON(!parts))
++		return 0;
++
++	for (i = 0; i < nr_parts; i++) {
++		/* adjust partition offsets */
++		parts[i].offset += slave->offset;
++
++		mtd_add_partition(slave->master,
++				  parts[i].name,
++				  parts[i].offset,
++				  parts[i].size);
++	}
++
++	kfree(parts);
++
++	return nr_parts;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -657,6 +687,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
+ static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+ {
++	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+ }
+ 
+ void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
+@@ -671,6 +702,12 @@ static void mtd_partition_split(struct m
+ 	if (rootfs_found)
+ 		return;
+ 
++	if (!strcmp(part->mtd.name, "rootfs")) {
++		run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++
++		rootfs_found = 1;
++	}
++
+ 	if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
+ 	    config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
+ 		split_firmware(master, part);
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -70,6 +70,8 @@ struct mtd_part_parser_data {
+ 
+ enum mtd_parser_type {
+ 	MTD_PARSER_TYPE_DEVICE = 0,
++	MTD_PARSER_TYPE_ROOTFS,
++	MTD_PARSER_TYPE_FIRMWARE,
+ };
+ 
+ struct mtd_part_parser {
diff --git a/target/linux/generic/patches-4.4/403-mtd-hook-mtdsplit-to-Kbuild.patch b/target/linux/generic/patches-4.4/403-mtd-hook-mtdsplit-to-Kbuild.patch
new file mode 100644
index 0000000000..0cf1c38555
--- /dev/null
+++ b/target/linux/generic/patches-4.4/403-mtd-hook-mtdsplit-to-Kbuild.patch
@@ -0,0 +1,22 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
+ 	depends on MTD_SPLIT_FIRMWARE
+ 	default "firmware"
+ 
++source "drivers/mtd/mtdsplit/Kconfig"
++
+ endmenu
+ 
+ config MTD_TESTS
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -6,6 +6,8 @@
+ obj-$(CONFIG_MTD)		+= mtd.o
+ mtd-y				:= mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
+ 
++obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit/
++
+ obj-$(CONFIG_MTD_OF_PARTS)	+= ofpart.o
+ obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
diff --git a/target/linux/generic/patches-4.4/404-mtd-add-more-helper-functions.patch b/target/linux/generic/patches-4.4/404-mtd-add-more-helper-functions.patch
new file mode 100644
index 0000000000..3773e1f195
--- /dev/null
+++ b/target/linux/generic/patches-4.4/404-mtd-add-more-helper-functions.patch
@@ -0,0 +1,101 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -454,14 +454,12 @@ static struct mtd_part *allocate_partiti
+ 	if (slave->offset == MTDPART_OFS_APPEND)
+ 		slave->offset = cur_offset;
+ 	if (slave->offset == MTDPART_OFS_NXTBLK) {
+-		slave->offset = cur_offset;
+-		if (mtd_mod_by_eb(cur_offset, master) != 0) {
+-			/* Round up to next erasesize */
+-			slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
++		/* Round up to next erasesize */
++		slave->offset = mtd_roundup_to_eb(cur_offset, master);
++		if (slave->offset != cur_offset)
+ 			printk(KERN_NOTICE "Moving partition %d: "
+ 			       "0x%012llx -> 0x%012llx\n", partno,
+ 			       (unsigned long long)cur_offset, (unsigned long long)slave->offset);
+-		}
+ 	}
+ 	if (slave->offset == MTDPART_OFS_RETAIN) {
+ 		slave->offset = cur_offset;
+@@ -679,6 +677,17 @@ run_parsers_by_type(struct mtd_part *sla
+ 	return nr_parts;
+ }
+ 
++static inline unsigned long
++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
++{
++	unsigned long mask = mtd->erasesize - 1;
++
++	len += offset & mask;
++	len = (len + mask) & ~mask;
++	len -= offset & mask;
++	return len;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -978,6 +987,24 @@ int mtd_is_partition(const struct mtd_in
+ }
+ EXPORT_SYMBOL_GPL(mtd_is_partition);
+ 
++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return (struct mtd_info *)mtd;
++
++	return PART(mtd)->master;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_master);
++
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return 0;
++
++	return PART(mtd)->offset;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_offset);
++
+ /* Returns the size of the entire flash chip */
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd)
+ {
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in
+ int mtd_add_partition(struct mtd_info *master, const char *name,
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
+ extern void __weak arch_split_mtd_part(struct mtd_info *master,
+ 				       const char *name, int offset, int size);
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -334,6 +334,24 @@ static inline uint32_t mtd_mod_by_eb(uin
+ 	return do_div(sz, mtd->erasesize);
+ }
+ 
++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round up to next erase block */
++	return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
++}
++
++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round down to the start of the current erase block */
++	return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
++}
++
+ static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
+ {
+ 	if (mtd->writesize_shift)
diff --git a/target/linux/generic/patches-4.4/410-mtd-move-forward-declaration-of-struct-mtd_info.patch b/target/linux/generic/patches-4.4/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
new file mode 100644
index 0000000000..78ebbf88ca
--- /dev/null
+++ b/target/linux/generic/patches-4.4/410-mtd-move-forward-declaration-of-struct-mtd_info.patch
@@ -0,0 +1,18 @@
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -35,6 +35,7 @@
+  * Note: writeable partitions require their size and offset be
+  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
+  */
++struct mtd_info;
+ 
+ struct mtd_partition {
+ 	const char *name;		/* identifier string */
+@@ -50,7 +51,6 @@ struct mtd_partition {
+ #define MTDPART_SIZ_FULL	(0)
+ 
+ 
+-struct mtd_info;
+ struct device_node;
+ 
+ /**
diff --git a/target/linux/generic/patches-4.4/411-mtd-partial_eraseblock_write.patch b/target/linux/generic/patches-4.4/411-mtd-partial_eraseblock_write.patch
new file mode 100644
index 0000000000..7ab8eb3442
--- /dev/null
+++ b/target/linux/generic/patches-4.4/411-mtd-partial_eraseblock_write.patch
@@ -0,0 +1,142 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -37,6 +37,8 @@
+ #include "mtdcore.h"
+ #include "mtdsplit/mtdsplit.h"
+ 
++#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
++
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+ static DEFINE_MUTEX(mtd_partitions_mutex);
+@@ -236,13 +238,61 @@ static int part_erase(struct mtd_info *m
+ 	struct mtd_part *part = PART(mtd);
+ 	int ret;
+ 
++
++	instr->partial_start = false;
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		size_t readlen = 0;
++		u64 mtd_ofs;
++
++		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
++		if (!instr->erase_buf)
++			return -ENOMEM;
++
++		mtd_ofs = part->offset + instr->addr;
++		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
++
++		if (instr->erase_buf_ofs > 0) {
++			instr->addr -= instr->erase_buf_ofs;
++			ret = mtd_read(part->master,
++				instr->addr + part->offset,
++				part->master->erasesize,
++				&readlen, instr->erase_buf);
++
++			instr->len += instr->erase_buf_ofs;
++			instr->partial_start = true;
++		} else {
++			mtd_ofs = part->offset + part->mtd.size;
++			instr->erase_buf_ofs = part->master->erasesize -
++				do_div(mtd_ofs, part->master->erasesize);
++
++			if (instr->erase_buf_ofs > 0) {
++				instr->len += instr->erase_buf_ofs;
++				ret = mtd_read(part->master,
++					part->offset + instr->addr +
++					instr->len - part->master->erasesize,
++					part->master->erasesize, &readlen,
++					instr->erase_buf);
++			} else {
++				ret = 0;
++			}
++		}
++		if (ret < 0) {
++			kfree(instr->erase_buf);
++			return ret;
++		}
++
++	}
++
+ 	instr->addr += part->offset;
+ 	ret = part->master->_erase(part->master, instr);
+ 	if (ret) {
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+ 		instr->addr -= part->offset;
++		if (mtd->flags & MTD_ERASE_PARTIAL)
++			kfree(instr->erase_buf);
+ 	}
++
+ 	return ret;
+ }
+ 
+@@ -250,7 +300,25 @@ void mtd_erase_callback(struct erase_inf
+ {
+ 	if (instr->mtd->_erase == part_erase) {
+ 		struct mtd_part *part = PART(instr->mtd);
++		size_t wrlen = 0;
+ 
++		if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
++			if (instr->partial_start) {
++				part->master->_write(part->master,
++					instr->addr, instr->erase_buf_ofs,
++					&wrlen, instr->erase_buf);
++				instr->addr += instr->erase_buf_ofs;
++			} else {
++				instr->len -= instr->erase_buf_ofs;
++				part->master->_write(part->master,
++					instr->addr + instr->len,
++					instr->erase_buf_ofs, &wrlen,
++					instr->erase_buf +
++					part->master->erasesize -
++					instr->erase_buf_ofs);
++			}
++			kfree(instr->erase_buf);
++		}
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+ 		instr->addr -= part->offset;
+@@ -523,17 +591,20 @@ static struct mtd_part *allocate_partiti
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
+ 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
+ 		/* Doesn't start on a boundary of major erase size */
+-		/* FIXME: Let it be writable if it is on a boundary of
+-		 * _minor_ erase size though */
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+-			part->name);
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++		if (((u32) slave->mtd.size) > master->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
+-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+-			part->name);
++	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++
++		if ((u32) slave->mtd.size > master->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 
+ 	slave->mtd.ecclayout = master->ecclayout;
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -55,6 +55,10 @@ struct erase_info {
+ 	u_long priv;
+ 	u_char state;
+ 	struct erase_info *next;
++
++	u8 *erase_buf;
++	u32 erase_buf_ofs;
++	bool partial_start;
+ };
+ 
+ struct mtd_erase_region_info {
diff --git a/target/linux/generic/patches-4.4/412-mtd-partial_eraseblock_unlock.patch b/target/linux/generic/patches-4.4/412-mtd-partial_eraseblock_unlock.patch
new file mode 100644
index 0000000000..990c2aba6e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/412-mtd-partial_eraseblock_unlock.patch
@@ -0,0 +1,18 @@
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -337,7 +337,14 @@ static int part_lock(struct mtd_info *mt
+ static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+ 	struct mtd_part *part = PART(mtd);
+-	return part->master->_unlock(part->master, ofs + part->offset, len);
++
++	ofs += part->offset;
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		/* round up len to next erasesize and round down offset to prev block */
++		len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
++		ofs &= ~(part->master->erasesize - 1);
++	}
++	return part->master->_unlock(part->master, ofs, len);
+ }
+ 
+ static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
diff --git a/target/linux/generic/patches-4.4/420-mtd-redboot_space.patch b/target/linux/generic/patches-4.4/420-mtd-redboot_space.patch
new file mode 100644
index 0000000000..f74affcef7
--- /dev/null
+++ b/target/linux/generic/patches-4.4/420-mtd-redboot_space.patch
@@ -0,0 +1,30 @@
+--- a/drivers/mtd/redboot.c
++++ b/drivers/mtd/redboot.c
+@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru
+ #endif
+ 		names += strlen(names)+1;
+ 
+-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ 		if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+-			i++;
+-			parts[i].offset = parts[i-1].size + parts[i-1].offset;
+-			parts[i].size = fl->next->img->flash_base - parts[i].offset;
+-			parts[i].name = nullname;
+-		}
++			if (!strcmp(parts[i].name, "rootfs")) {
++				parts[i].size = fl->next->img->flash_base;
++				parts[i].size &= ~(master->erasesize - 1);
++				parts[i].size -= parts[i].offset;
++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
++				nrparts--;
++			} else {
++				i++;
++				parts[i].offset = parts[i-1].size + parts[i-1].offset;
++				parts[i].size = fl->next->img->flash_base - parts[i].offset;
++				parts[i].name = nullname;
+ #endif
++			}
++		}
+ 		tmp_fl = fl;
+ 		fl = fl->next;
+ 		kfree(tmp_fl);
diff --git a/target/linux/generic/patches-4.4/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/patches-4.4/430-mtd-add-myloader-partition-parser.patch
new file mode 100644
index 0000000000..a022564e9e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/430-mtd-add-myloader-partition-parser.patch
@@ -0,0 +1,35 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -174,6 +174,22 @@ config MTD_BCM47XX_PARTS
+ 	  This provides partitions parser for devices based on BCM47xx
+ 	  boards.
+ 
++config MTD_MYLOADER_PARTS
++	tristate "MyLoader partition parsing"
++	depends on ADM5120 || ATH25 || ATH79
++	---help---
++	  MyLoader is a bootloader which allows the user to define partitions
++	  in flash devices, by putting a table in the second erase block
++	  on the device, similar to a partition table. This table gives the 
++	  offsets and lengths of the user defined partitions.
++
++	  If you need code which can detect and parse these tables, and
++	  register MTD 'partitions' corresponding to each image detected,
++	  enable this option.
++
++	  You will still need the parsing functions to be called by the driver
++	  for your particular device. It won't happen automatically.
++
+ comment "User Modules And Translation Layers"
+ 
+ #
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
+ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)	+= bcm47xxpart.o
++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
+ 
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS)	+= mtd_blkdevs.o
diff --git a/target/linux/generic/patches-4.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch b/target/linux/generic/patches-4.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
new file mode 100644
index 0000000000..5ad82f1f51
--- /dev/null
+++ b/target/linux/generic/patches-4.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
@@ -0,0 +1,100 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 2 Jan 2016 01:04:52 +0100
+Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating
+ offsets
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 50 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 40 insertions(+), 10 deletions(-)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -61,6 +61,34 @@ static void bcm47xxpart_add_part(struct
+ 	part->mask_flags = mask_flags;
+ }
+ 
++/*
++ * Calculate real end offset (address) for a given amount of data. It checks
++ * all blocks skipping bad ones.
++ */
++static size_t bcm47xxpart_real_offset(struct mtd_info *master, size_t offset,
++				      size_t bytes)
++{
++	size_t real_offset = offset;
++
++	if (mtd_block_isbad(master, real_offset))
++		pr_warn("Base offset shouldn't be at bad block");
++
++	while (bytes >= master->erasesize) {
++		bytes -= master->erasesize;
++		real_offset += master->erasesize;
++		while (mtd_block_isbad(master, real_offset)) {
++			real_offset += master->erasesize;
++
++			if (real_offset >= master->size)
++				return real_offset - master->erasesize;
++		}
++	}
++
++	real_offset += bytes;
++
++	return real_offset;
++}
++
+ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
+ 						  size_t offset)
+ {
+@@ -182,6 +210,8 @@ static int bcm47xxpart_parse(struct mtd_
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
++			uint32_t tmp;
++
+ 			if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
+ 				pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
+ 				break;
+@@ -196,18 +226,18 @@ static int bcm47xxpart_parse(struct mtd_
+ 			i = 0;
+ 			/* We have LZMA loader if offset[2] points to sth */
+ 			if (trx->offset[2]) {
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "loader",
+-						     offset + trx->offset[i],
+-						     0);
++						     "loader", tmp, 0);
+ 				i++;
+ 			}
+ 
+ 			if (trx->offset[i]) {
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     "linux",
+-						     offset + trx->offset[i],
+-						     0);
++						     "linux", tmp, 0);
+ 				i++;
+ 			}
+ 
+@@ -219,11 +249,11 @@ static int bcm47xxpart_parse(struct mtd_
+ 			if (trx->offset[i]) {
+ 				const char *name;
+ 
+-				name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
++				tmp = bcm47xxpart_real_offset(master, offset,
++							      trx->offset[i]);
++				name = bcm47xxpart_trx_data_part_name(master, tmp);
+ 				bcm47xxpart_add_part(&parts[curr_part++],
+-						     name,
+-						     offset + trx->offset[i],
+-						     0);
++						     name, tmp, 0);
+ 				i++;
+ 			}
+ 
diff --git a/target/linux/generic/patches-4.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/patches-4.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
new file mode 100644
index 0000000000..9e5ca91e55
--- /dev/null
+++ b/target/linux/generic/patches-4.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
@@ -0,0 +1,42 @@
+From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 28 Jan 2015 22:14:41 +0100
+Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It can be found on many Netgear devices. It consists of many 0x30 blocks
+starting with 4D 54.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -38,6 +38,7 @@
+ #define NVRAM_HEADER			0x48534C46	/* FLSH */
+ #define POT_MAGIC1			0x54544f50	/* POTT */
+ #define POT_MAGIC2			0x504f		/* OP */
++#define T_METER_MAGIC			0x4D540000	/* MT */
+ #define ML_MAGIC1			0x39685a42
+ #define ML_MAGIC2			0x26594131
+ #define TRX_MAGIC			0x30524448
+@@ -207,6 +208,15 @@ static int bcm47xxpart_parse(struct mtd_
+ 					     MTD_WRITEABLE);
+ 			continue;
+ 		}
++
++		/* T_Meter */
++		if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
++			bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
++					     MTD_WRITEABLE);
++			continue;
++		}
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
diff --git a/target/linux/generic/patches-4.4/440-block2mtd_init.patch b/target/linux/generic/patches-4.4/440-block2mtd_init.patch
new file mode 100644
index 0000000000..f2e62b4401
--- /dev/null
+++ b/target/linux/generic/patches-4.4/440-block2mtd_init.patch
@@ -0,0 +1,108 @@
+--- a/drivers/mtd/devices/block2mtd.c
++++ b/drivers/mtd/devices/block2mtd.c
+@@ -26,6 +26,7 @@
+ #include <linux/list.h>
+ #include <linux/init.h>
+ #include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
+ #include <linux/mutex.h>
+ #include <linux/mount.h>
+ #include <linux/slab.h>
+@@ -219,7 +220,7 @@ static void block2mtd_free_device(struct
+ 
+ 
+ static struct block2mtd_dev *add_device(char *devname, int erase_size,
+-		int timeout)
++		const char *mtdname, int timeout)
+ {
+ #ifndef MODULE
+ 	int i;
+@@ -227,6 +228,7 @@ static struct block2mtd_dev *add_device(
+ 	const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
+ 	struct block_device *bdev = ERR_PTR(-ENODEV);
+ 	struct block2mtd_dev *dev;
++	struct mtd_partition *part;
+ 	char *name;
+ 
+ 	if (!devname)
+@@ -283,13 +285,16 @@ static struct block2mtd_dev *add_device(
+ 
+ 	/* Setup the MTD structure */
+ 	/* make the name contain the block device in */
+-	name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
++	if (!mtdname)
++		mtdname = devname;
++	name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
+ 	if (!name)
+ 		goto err_destroy_mutex;
+ 
++	strcpy(name, mtdname);
+ 	dev->mtd.name = name;
+ 
+-	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
++	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
+ 	dev->mtd.erasesize = erase_size;
+ 	dev->mtd.writesize = 1;
+ 	dev->mtd.writebufsize = PAGE_SIZE;
+@@ -302,7 +307,11 @@ static struct block2mtd_dev *add_device(
+ 	dev->mtd.priv = dev;
+ 	dev->mtd.owner = THIS_MODULE;
+ 
+-	if (mtd_device_register(&dev->mtd, NULL, 0)) {
++	part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
++	part->name = name;
++	part->offset = 0;
++	part->size = dev->mtd.size;
++	if (mtd_device_register(&dev->mtd, part, 1)) {
+ 		/* Device didn't get added, so free the entry */
+ 		goto err_destroy_mutex;
+ 	}
+@@ -310,8 +319,7 @@ static struct block2mtd_dev *add_device(
+ 	list_add(&dev->list, &blkmtd_device_list);
+ 	pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
+ 		dev->mtd.index,
+-		dev->mtd.name + strlen("block2mtd: "),
+-		dev->mtd.erasesize >> 10, dev->mtd.erasesize);
++		mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ 	return dev;
+ 
+ err_destroy_mutex:
+@@ -384,7 +392,7 @@ static int block2mtd_setup2(const char *
+ 	/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
+ 	char buf[80 + 12 + 80 + 8];
+ 	char *str = buf;
+-	char *token[2];
++	char *token[3];
+ 	char *name;
+ 	size_t erase_size = PAGE_SIZE;
+ 	unsigned long timeout = MTD_DEFAULT_TIMEOUT;
+@@ -398,7 +406,7 @@ static int block2mtd_setup2(const char *
+ 	strcpy(str, val);
+ 	kill_final_newline(str);
+ 
+-	for (i = 0; i < 2; i++)
++	for (i = 0; i < 3; i++)
+ 		token[i] = strsep(&str, ",");
+ 
+ 	if (str) {
+@@ -424,8 +432,10 @@ static int block2mtd_setup2(const char *
+ 			return 0;
+ 		}
+ 	}
++	if (token[2] && (strlen(token[2]) + 1 > 80))
++		pr_err("mtd device name too long\n");
+ 
+-	add_device(name, erase_size, timeout);
++	add_device(name, erase_size, token[2], timeout);
+ 
+ 	return 0;
+ }
+@@ -459,7 +469,7 @@ static int block2mtd_setup(const char *v
+ 
+ 
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
+ 
+ static int __init block2mtd_init(void)
+ {
diff --git a/target/linux/generic/patches-4.4/441-block2mtd_probe.patch b/target/linux/generic/patches-4.4/441-block2mtd_probe.patch
new file mode 100644
index 0000000000..ed14537a6c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/441-block2mtd_probe.patch
@@ -0,0 +1,39 @@
+--- a/drivers/mtd/devices/block2mtd.c
++++ b/drivers/mtd/devices/block2mtd.c
+@@ -392,7 +392,7 @@ static int block2mtd_setup2(const char *
+ 	/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
+ 	char buf[80 + 12 + 80 + 8];
+ 	char *str = buf;
+-	char *token[3];
++	char *token[4];
+ 	char *name;
+ 	size_t erase_size = PAGE_SIZE;
+ 	unsigned long timeout = MTD_DEFAULT_TIMEOUT;
+@@ -406,7 +406,7 @@ static int block2mtd_setup2(const char *
+ 	strcpy(str, val);
+ 	kill_final_newline(str);
+ 
+-	for (i = 0; i < 3; i++)
++	for (i = 0; i < 4; i++)
+ 		token[i] = strsep(&str, ",");
+ 
+ 	if (str) {
+@@ -435,6 +435,9 @@ static int block2mtd_setup2(const char *
+ 	if (token[2] && (strlen(token[2]) + 1 > 80))
+ 		pr_err("mtd device name too long\n");
+ 
++	if (token[3] && kstrtoul(token[3], 0, &timeout))
++		pr_err("invalid timeout\n");
++
+ 	add_device(name, erase_size, token[2], timeout);
+ 
+ 	return 0;
+@@ -469,7 +472,7 @@ static int block2mtd_setup(const char *v
+ 
+ 
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
++MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>[,<timeout>]]]\"");
+ 
+ static int __init block2mtd_init(void)
+ {
diff --git a/target/linux/generic/patches-4.4/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch b/target/linux/generic/patches-4.4/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
new file mode 100644
index 0000000000..3ce7f13dc4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/450-mtd-nand-allow-to-use-platform-specific-chip-fixup.patch
@@ -0,0 +1,37 @@
+---
+ drivers/mtd/nand/plat_nand.c |   13 ++++++++++++-
+ include/linux/mtd/nand.h     |    1 +
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -863,6 +863,7 @@ struct platform_nand_chip {
+ 	unsigned int options;
+ 	unsigned int bbt_options;
+ 	const char **part_probe_types;
++	int (*chip_fixup)(struct mtd_info *mtd);
+ };
+ 
+ /* Keep gcc happy */
+--- a/drivers/mtd/nand/plat_nand.c
++++ b/drivers/mtd/nand/plat_nand.c
+@@ -87,7 +87,18 @@ static int plat_nand_probe(struct platfo
+ 	}
+ 
+ 	/* Scan to find existence of the device */
+-	if (nand_scan(&data->mtd, pdata->chip.nr_chips)) {
++	if (nand_scan_ident(&data->mtd, pdata->chip.nr_chips, NULL)) {
++		err = -ENXIO;
++		goto out;
++	}
++
++	if (pdata->chip.chip_fixup) {
++		err = pdata->chip.chip_fixup(&data->mtd);
++		if (err)
++			goto out;
++	}
++
++	if (nand_scan_tail(&data->mtd)) {
+ 		err = -ENXIO;
+ 		goto out;
+ 	}
diff --git a/target/linux/generic/patches-4.4/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch b/target/linux/generic/patches-4.4/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
new file mode 100644
index 0000000000..6a2092ce20
--- /dev/null
+++ b/target/linux/generic/patches-4.4/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patch
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/nand/nand_ecc.c
++++ b/drivers/mtd/nand/nand_ecc.c
+@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b
+ 		return 1;	/* error in ECC data; no action needed */
+ 
+ 	pr_err("%s: uncorrectable ECC error\n", __func__);
+-	return -1;
++	return -EBADMSG;
+ }
+ EXPORT_SYMBOL(__nand_correct_data);
+ 
diff --git a/target/linux/generic/patches-4.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/patches-4.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
new file mode 100644
index 0000000000..68fbd12466
--- /dev/null
+++ b/target/linux/generic/patches-4.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
@@ -0,0 +1,11 @@
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map
+ 		return 0;
+ 
+ 	case FL_ERASING:
+-		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
++		if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
+ 		    !(mode == FL_READY || mode == FL_POINT ||
+ 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
+ 			goto sleep;
diff --git a/target/linux/generic/patches-4.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/patches-4.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
new file mode 100644
index 0000000000..c437a140f0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
@@ -0,0 +1,18 @@
+From: George Kashperko <george@znau.edu.ua>
+
+Issue map read after Write Buffer Load command to ensure chip is ready
+to receive data.
+Signed-off-by: George Kashperko <george@znau.edu.ua>
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    1 +
+ 1 file changed, 1 insertion(+)
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru
+ 
+ 	/* Write Buffer Load */
+ 	map_write(map, CMD(0x25), cmd_adr);
++	(void) map_read(map, cmd_adr);
+ 
+ 	chip->state = FL_WRITING_TO_BUFFER;
+ 
diff --git a/target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch b/target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch
new file mode 100644
index 0000000000..070f4c6023
--- /dev/null
+++ b/target/linux/generic/patches-4.4/465-m25p80-mx-disable-software-protection.patch
@@ -0,0 +1,14 @@
+Disable software protection bits for Macronix flashes.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1158,6 +1158,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 
+ 	if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ 	    JEDEC_MFR(info) == SNOR_MFR_INTEL ||
++	    JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
+ 	    JEDEC_MFR(info) == SNOR_MFR_SST) {
+ 		write_enable(nor);
+ 		write_sr(nor, 0);
diff --git a/target/linux/generic/patches-4.4/475-mtd-spi-nor-add-macronix-mx25u25635f.patch b/target/linux/generic/patches-4.4/475-mtd-spi-nor-add-macronix-mx25u25635f.patch
new file mode 100644
index 0000000000..3db4a41968
--- /dev/null
+++ b/target/linux/generic/patches-4.4/475-mtd-spi-nor-add-macronix-mx25u25635f.patch
@@ -0,0 +1,10 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -724,6 +724,7 @@ static const struct flash_info spi_nor_i
+ 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ 	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+ 	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
++	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, 0) },
+ 	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+ 	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
+ 	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
diff --git a/target/linux/generic/patches-4.4/476-mtd-spi-nor-add-eon-en25q128.patch b/target/linux/generic/patches-4.4/476-mtd-spi-nor-add-eon-en25q128.patch
new file mode 100644
index 0000000000..38f3255b14
--- /dev/null
+++ b/target/linux/generic/patches-4.4/476-mtd-spi-nor-add-eon-en25q128.patch
@@ -0,0 +1,10 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -682,6 +682,7 @@ static const struct flash_info spi_nor_i
+ 	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
+ 	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
+ 	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
++	{ "en25q128",   INFO(0x1c3018, 0, 64 * 1024,  256, SECT_4K) },
+ 	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 0) },
+ 	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
+ 	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, SECT_4K) },
diff --git a/target/linux/generic/patches-4.4/477-mtd-add-spi-nor-add-mx25u3235f.patch b/target/linux/generic/patches-4.4/477-mtd-add-spi-nor-add-mx25u3235f.patch
new file mode 100644
index 0000000000..eb99b28a55
--- /dev/null
+++ b/target/linux/generic/patches-4.4/477-mtd-add-spi-nor-add-mx25u3235f.patch
@@ -0,0 +1,10 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -721,6 +721,7 @@ static const struct flash_info spi_nor_i
+ 	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
+ 	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
+ 	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
++	{ "mx25u3235f",	 INFO(0xc22536, 0, 64 * 1024, 64, 0) },
+ 	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ 	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ 	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
diff --git a/target/linux/generic/patches-4.4/480-mtd-set-rootfs-to-be-root-dev.patch b/target/linux/generic/patches-4.4/480-mtd-set-rootfs-to-be-root-dev.patch
new file mode 100644
index 0000000000..d20bd8d4ec
--- /dev/null
+++ b/target/linux/generic/patches-4.4/480-mtd-set-rootfs-to-be-root-dev.patch
@@ -0,0 +1,26 @@
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -39,6 +39,7 @@
+ #include <linux/slab.h>
+ #include <linux/reboot.h>
+ #include <linux/kconfig.h>
++#include <linux/root_dev.h>
+ 
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -464,6 +465,15 @@ int add_mtd_device(struct mtd_info *mtd)
+ 	   of this try_ nonsense, and no bitching about it
+ 	   either. :) */
+ 	__module_get(THIS_MODULE);
++
++	if (!strcmp(mtd->name, "rootfs") &&
++	    config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("mtd: device %d (%s) set to be root filesystem\n",
++			  mtd->index, mtd->name);
++		ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
++	}
++
+ 	return 0;
+ 
+ fail_added:
diff --git a/target/linux/generic/patches-4.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-4.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
new file mode 100644
index 0000000000..f08f9b4a7c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
@@ -0,0 +1,76 @@
+From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:36:18 +0200
+Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -1203,6 +1203,49 @@ static struct mtd_info * __init open_mtd
+ 	return mtd;
+ }
+ 
++/*
++ * This function tries attaching mtd partitions named either "ubi" or "data"
++ * during boot.
++ */
++static void __init ubi_auto_attach(void)
++{
++	int err;
++	struct mtd_info *mtd;
++
++	/* try attaching mtd device named "ubi" or "data" */
++	mtd = open_mtd_device("ubi");
++	if (IS_ERR(mtd))
++		mtd = open_mtd_device("data");
++
++	if (!IS_ERR(mtd)) {
++		size_t len;
++		char magic[4];
++
++		/* check for a valid ubi magic */
++		err = mtd_read(mtd, 0, 4, &len, (void *) magic);
++		if (!err && len == 4 && strncmp(magic, "UBI#", 4)) {
++			pr_err("UBI error: no valid UBI magic found inside mtd%d", mtd->index);
++			put_mtd_device(mtd);
++			return;
++		}
++
++		/* auto-add only media types where UBI makes sense */
++		if (mtd->type == MTD_NANDFLASH ||
++		    mtd->type == MTD_NORFLASH ||
++		    mtd->type == MTD_DATAFLASH ||
++		    mtd->type == MTD_MLCNANDFLASH) {
++			mutex_lock(&ubi_devices_mutex);
++			pr_notice("UBI: auto-attach mtd%d", mtd->index);
++			err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
++			mutex_unlock(&ubi_devices_mutex);
++			if (err < 0) {
++				pr_err("UBI error: cannot attach mtd%d", mtd->index);
++				put_mtd_device(mtd);
++			}
++		}
++	}
++}
++
+ static int __init ubi_init(void)
+ {
+ 	int err, i, k;
+@@ -1286,6 +1329,12 @@ static int __init ubi_init(void)
+ 		}
+ 	}
+ 
++	/* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
++	 * parameter was given */
++	if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    !ubi_is_module() && !mtd_devs)
++		ubi_auto_attach();
++
+ 	err = ubiblock_init();
+ 	if (err) {
+ 		pr_err("UBI error: block: cannot initialize, error %d", err);
diff --git a/target/linux/generic/patches-4.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-4.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
new file mode 100644
index 0000000000..da3111266a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
@@ -0,0 +1,69 @@
+From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 21:06:33 +0200
+Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -628,6 +628,44 @@ static void __init ubiblock_create_from_
+ 	}
+ }
+ 
++#define UBIFS_NODE_MAGIC  0x06101831
++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
++{
++	int ret;
++	uint32_t magic_of, magic;
++	ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
++	if (ret)
++		return 0;
++	magic = le32_to_cpu(magic_of);
++	return magic == UBIFS_NODE_MAGIC;
++}
++
++static void __init ubiblock_create_auto_rootfs(void)
++{
++	int ubi_num, ret, is_ubifs;
++	struct ubi_volume_desc *desc;
++	struct ubi_volume_info vi;
++
++	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
++		desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
++		if (IS_ERR(desc))
++			continue;
++
++		ubi_get_volume_info(desc, &vi);
++		is_ubifs = ubi_vol_is_ubifs(desc);
++		ubi_close_volume(desc);
++		if (is_ubifs)
++			break;
++
++		ret = ubiblock_create(&vi);
++		if (ret)
++			pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
++				vi.name, ret);
++		/* always break if we get here */
++		break;
++	}
++}
++
+ static void ubiblock_remove_all(void)
+ {
+ 	struct ubiblock *next;
+@@ -658,6 +696,10 @@ int __init ubiblock_init(void)
+ 	 */
+ 	ubiblock_create_from_param();
+ 
++	/* auto-attach "rootfs" volume if existing and non-ubifs */
++	if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV))
++		ubiblock_create_auto_rootfs();
++
+ 	/*
+ 	 * Block devices are only created upon user requests, so we ignore
+ 	 * existing volumes.
diff --git a/target/linux/generic/patches-4.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-4.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
new file mode 100644
index 0000000000..ab8b8bb0a2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
@@ -0,0 +1,54 @@
+From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:35:02 +0200
+Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ init/do_mounts.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -438,7 +438,28 @@ retry:
+ out:
+ 	put_page(page);
+ }
+- 
++
++static int __init mount_ubi_rootfs(void)
++{
++	int flags = MS_SILENT;
++	int err, tried = 0;
++
++	while (tried < 2) {
++		err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
++					root_mount_data);
++		switch (err) {
++			case -EACCES:
++				flags |= MS_RDONLY;
++				tried++;
++				break;
++			default:
++				return err;
++		}
++	}
++
++	return -EINVAL;
++}
++
+ #ifdef CONFIG_ROOT_NFS
+ 
+ #define NFSROOT_TIMEOUT_MIN	5
+@@ -532,6 +553,10 @@ void __init mount_root(void)
+ 			change_floppy("root floppy");
+ 	}
+ #endif
++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
++	if (!mount_ubi_rootfs())
++		return;
++#endif
+ #ifdef CONFIG_BLOCK
+ 	{
+ 		int err = create_dev("/dev/root", ROOT_DEV);
diff --git a/target/linux/generic/patches-4.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-4.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
new file mode 100644
index 0000000000..f55e8e3a4d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
@@ -0,0 +1,37 @@
+From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 20:55:42 +0200
+Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -50,6 +50,7 @@
+ #include <linux/scatterlist.h>
+ #include <linux/idr.h>
+ #include <asm/div64.h>
++#include <linux/root_dev.h>
+ 
+ #include "ubi-media.h"
+ #include "ubi.h"
+@@ -448,6 +449,15 @@ int ubiblock_create(struct ubi_volume_in
+ 	add_disk(dev->gd);
+ 	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
+ 		 dev->ubi_num, dev->vol_id, vi->name);
++
++	if (!strcmp(vi->name, "rootfs") &&
++	    config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
++			  dev->ubi_num, dev->vol_id, vi->name);
++		ROOT_DEV = MKDEV(gd->major, gd->first_minor);
++	}
++
+ 	return 0;
+ 
+ out_free_queue:
diff --git a/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch
new file mode 100644
index 0000000000..dd5ee306ef
--- /dev/null
+++ b/target/linux/generic/patches-4.4/494-mtd-ubi-add-EOF-marker-support.patch
@@ -0,0 +1,51 @@
+--- a/drivers/mtd/ubi/attach.c
++++ b/drivers/mtd/ubi/attach.c
+@@ -803,6 +803,13 @@ out_unlock:
+ 	return err;
+ }
+ 
++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
++{
++	return ech->padding1[0] == 'E' &&
++	       ech->padding1[1] == 'O' &&
++	       ech->padding1[2] == 'F';
++}
++
+ /**
+  * scan_peb - scan and process UBI headers of a PEB.
+  * @ubi: UBI device description object
+@@ -833,9 +840,21 @@ static int scan_peb(struct ubi_device *u
+ 		return 0;
+ 	}
+ 
+-	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+-	if (err < 0)
+-		return err;
++	if (!ai->eof_found) {
++		err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
++		if (err < 0)
++			return err;
++
++		if (ec_hdr_has_eof(ech)) {
++			pr_notice("UBI: EOF marker found, PEBs from %d will be erased",
++				pnum);
++			ai->eof_found = true;
++		}
++	}
++
++	if (ai->eof_found)
++		err = UBI_IO_FF_BITFLIPS;
++
+ 	switch (err) {
+ 	case 0:
+ 		break;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -741,6 +741,7 @@ struct ubi_attach_info {
+ 	int mean_ec;
+ 	uint64_t ec_sum;
+ 	int ec_count;
++	bool eof_found;
+ 	struct kmem_cache *aeb_slab_cache;
+ };
+ 
diff --git a/target/linux/generic/patches-4.4/500-yaffs-Kbuild-integration.patch b/target/linux/generic/patches-4.4/500-yaffs-Kbuild-integration.patch
new file mode 100644
index 0000000000..fe1a612945
--- /dev/null
+++ b/target/linux/generic/patches-4.4/500-yaffs-Kbuild-integration.patch
@@ -0,0 +1,18 @@
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -30,6 +30,7 @@ source "fs/ocfs2/Kconfig"
+ source "fs/btrfs/Kconfig"
+ source "fs/nilfs2/Kconfig"
+ source "fs/f2fs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ 
+ config FS_DAX
+ 	bool "Direct Access (DAX) support"
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -126,3 +126,5 @@ obj-y				+= exofs/ # Multiple modules
+ obj-$(CONFIG_CEPH_FS)		+= ceph/
+ obj-$(CONFIG_PSTORE)		+= pstore/
+ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
++obj-$(CONFIG_YAFFS_FS)		+= yaffs2/
++
diff --git a/target/linux/generic/patches-4.4/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-4.4/502-yaffs-fix-compat-tags-handling.patch
new file mode 100644
index 0000000000..a18cf6fd7b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/502-yaffs-fix-compat-tags-handling.patch
@@ -0,0 +1,239 @@
+Subject: yaffs: fix compat tags handling
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+--- a/fs/yaffs2/yaffs_tagscompat.c
++++ b/fs/yaffs2/yaffs_tagscompat.c
+@@ -17,7 +17,9 @@
+ #include "yaffs_getblockinfo.h"
+ #include "yaffs_trace.h"
+ 
++#if 0
+ static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
++#endif
+ 
+ 
+ /********** Tags ECC calculations  *********/
+@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
+ 	return 0;
+ }
+ 
++#if 0
+ /********** Tags **********/
+ 
+ static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
+ 	if(!dev->tagger.mark_bad_fn)
+ 		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
+ }
++#else
++
++#include "yaffs_packedtags1.h"
++
++static int yaffs_tags_compat_write(struct yaffs_dev *dev,
++				   int nand_chunk,
++				   const u8 *data,
++				   const struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags1 pt1;
++	u8 tag_buf[9];
++	int retval;
++
++	/* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
++	compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
++	compile_time_assertion(sizeof(struct yaffs_tags) == 8);
++
++	yaffs_pack_tags1(&pt1, tags);
++	yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
++
++	/* When deleting a chunk, the upper layer provides only skeletal
++	 * tags, one with is_deleted set.  However, we need to update the
++	 * tags, not erase them completely.  So we use the NAND write property
++	 * that only zeroed-bits stick and set tag bytes to all-ones and
++	 * zero just the (not) deleted bit.
++	 */
++	if (!dev->param.tags_9bytes) {
++		if (tags->is_deleted) {
++			memset(&pt1, 0xff, 8);
++			/* clear delete status bit to indicate deleted */
++			pt1.deleted = 0;
++		}
++		memcpy(tag_buf, &pt1, 8);
++	} else {
++		if (tags->is_deleted) {
++			memset(tag_buf, 0xff, 8);
++			tag_buf[8] = 0;
++		} else {
++			memcpy(tag_buf, &pt1, 8);
++			tag_buf[8] = 0xff;
++		}
++	}
++
++	retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
++			data,
++			(data) ? dev->data_bytes_per_chunk : 0,
++			tag_buf,
++			(dev->param.tags_9bytes) ? 9 : 8);
++
++	return retval;
++}
++
++/* Return with empty extended tags but add ecc_result.
++ */
++static int return_empty_tags(struct yaffs_ext_tags *tags,
++			     enum yaffs_ecc_result ecc_result,
++			     int retval)
++{
++	if (tags) {
++		memset(tags, 0, sizeof(*tags));
++		tags->ecc_result = ecc_result;
++	}
++
++	return retval;
++}
++
++static int yaffs_tags_compat_read(struct yaffs_dev *dev,
++				  int nand_chunk,
++				  u8 *data,
++				  struct yaffs_ext_tags *tags)
++{
++	struct yaffs_packed_tags1 pt1;
++	enum yaffs_ecc_result ecc_result;
++	int retval;
++	int deleted;
++	u8 tag_buf[9];
++
++	retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
++			data, dev->param.total_bytes_per_chunk,
++			tag_buf,
++			(dev->param.tags_9bytes) ? 9 : 8,
++			&ecc_result);
++
++	switch (ecc_result) {
++	case YAFFS_ECC_RESULT_NO_ERROR:
++	case YAFFS_ECC_RESULT_FIXED:
++		break;
++
++	case YAFFS_ECC_RESULT_UNFIXED:
++	default:
++		return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
++		tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
++		return YAFFS_FAIL;
++	}
++
++	/* Check for a blank/erased chunk. */
++	if (yaffs_check_ff(tag_buf, 8)) {
++		/* when blank, upper layers want ecc_result to be <= NO_ERROR */
++		return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
++					 YAFFS_OK);
++	}
++
++	memcpy(&pt1, tag_buf, 8);
++
++	if (!dev->param.tags_9bytes) {
++		/* Read deleted status (bit) then return it to it's non-deleted
++		 * state before performing tags mini-ECC check. pt1.deleted is
++		 * inverted.
++		 */
++		deleted = !pt1.deleted;
++		pt1.deleted = 1;
++	} else {
++		deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
++	}
++
++	/* Check the packed tags mini-ECC and correct if necessary/possible. */
++	retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
++	switch (retval) {
++	case 0:
++		/* no tags error, use MTD result */
++		break;
++	case 1:
++		/* recovered tags-ECC error */
++		dev->n_tags_ecc_fixed++;
++		if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
++			ecc_result = YAFFS_ECC_RESULT_FIXED;
++		break;
++	default:
++		/* unrecovered tags-ECC error */
++		dev->n_tags_ecc_unfixed++;
++		return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
++					 YAFFS_FAIL);
++	}
++
++	/* Unpack the tags to extended form and set ECC result.
++	 * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
++	 */
++	pt1.should_be_ff = 0xffffffff;
++	yaffs_unpack_tags1(tags, &pt1);
++	tags->ecc_result = ecc_result;
++
++	/* Set deleted state */
++	tags->is_deleted = deleted;
++	return YAFFS_OK;
++}
++
++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
++{
++	return dev->drv.drv_mark_bad_fn(dev, block_no);
++}
++
++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
++					 int block_no,
++					 enum yaffs_block_state *state,
++					 u32 *seq_number)
++{
++	struct yaffs_ext_tags tags;
++	int retval;
++
++	yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
++
++	*seq_number = 0;
++
++	retval = dev->drv.drv_check_bad_fn(dev, block_no);
++	if (retval == YAFFS_FAIL) {
++		*state = YAFFS_BLOCK_STATE_DEAD;
++		goto out;
++	}
++
++	yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
++			       NULL, &tags);
++
++	if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
++		yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
++			    block_no);
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++	} else if (tags.chunk_used) {
++		*seq_number = tags.seq_number;
++		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
++	} else {
++		*state = YAFFS_BLOCK_STATE_EMPTY;
++	}
++
++	retval = YAFFS_OK;
++
++out:
++	yaffs_trace(YAFFS_TRACE_MTD,
++		    "block query returns seq %u state %d",
++		    *seq_number, *state);
++
++	return retval;
++}
++
++void yaffs_tags_compat_install(struct yaffs_dev *dev)
++{
++	if (dev->param.is_yaffs2)
++		return;
++
++	if (!dev->tagger.write_chunk_tags_fn)
++		dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
++
++	if (!dev->tagger.read_chunk_tags_fn)
++		dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
++
++	if (!dev->tagger.query_block_fn)
++		dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
++
++	if (!dev->tagger.mark_bad_fn)
++		dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
++}
++#endif
diff --git a/target/linux/generic/patches-4.4/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-4.4/503-yaffs-add-tags-9bytes-mount-option.patch
new file mode 100644
index 0000000000..3f51bafc11
--- /dev/null
+++ b/target/linux/generic/patches-4.4/503-yaffs-add-tags-9bytes-mount-option.patch
@@ -0,0 +1,115 @@
+Subject: yaffs: add support for tags-9bytes mount option
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -2644,6 +2644,7 @@ static const struct super_operations yaf
+ 
+ struct yaffs_options {
+ 	int inband_tags;
++	int tags_9bytes;
+ 	int skip_checkpoint_read;
+ 	int skip_checkpoint_write;
+ 	int no_cache;
+@@ -2683,6 +2684,8 @@ static int yaffs_parse_options(struct ya
+ 
+ 		if (!strcmp(cur_opt, "inband-tags")) {
+ 			options->inband_tags = 1;
++		} else if (!strcmp(cur_opt, "tags-9bytes")) {
++			options->tags_9bytes = 1;
+ 		} else if (!strcmp(cur_opt, "tags-ecc-off")) {
+ 			options->tags_ecc_on = 0;
+ 			options->tags_ecc_overridden = 1;
+@@ -2756,7 +2759,6 @@ static struct super_block *yaffs_interna
+ 	struct yaffs_param *param;
+ 
+ 	int read_only = 0;
+-	int inband_tags = 0;
+ 
+ 	struct yaffs_options options;
+ 
+@@ -2796,6 +2798,9 @@ static struct super_block *yaffs_interna
+ 
+ 	memset(&options, 0, sizeof(options));
+ 
++	if (IS_ENABLED(CONFIG_YAFFS_9BYTE_TAGS))
++		options.tags_9bytes = 1;
++
+ 	if (yaffs_parse_options(&options, data_str)) {
+ 		/* Option parsing failed */
+ 		return NULL;
+@@ -2829,17 +2834,22 @@ static struct super_block *yaffs_interna
+ 	}
+ 
+ 	/* Added NCB 26/5/2006 for completeness */
+-	if (yaffs_version == 2 && !options.inband_tags
+-	    && WRITE_SIZE(mtd) == 512) {
++	if (yaffs_version == 2 &&
++	    (!options.inband_tags || options.tags_9bytes) &&
++	    WRITE_SIZE(mtd) == 512) {
+ 		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
+ 		yaffs_version = 1;
+ 	}
+ 
+-	if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
+-	    options.inband_tags)
+-		inband_tags = 1;
++	if (yaffs_version == 2 &&
++	    mtd->oobavail < sizeof(struct yaffs_packed_tags2)) {
++		yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting inband tags");
++		options.inband_tags = 1;
++	}
+ 
+-	if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
++	err = yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags,
++			       options.tags_9bytes);
++	if (err < 0)
+ 		return NULL;
+ 
+ 	/* OK, so if we got here, we have an MTD that's NAND and looks
+@@ -2896,7 +2906,8 @@ static struct super_block *yaffs_interna
+ 
+ 	param->n_reserved_blocks = 5;
+ 	param->n_caches = (options.no_cache) ? 0 : 10;
+-	param->inband_tags = inband_tags;
++	param->inband_tags = options.inband_tags;
++	param->tags_9bytes = options.tags_9bytes;
+ 
+ 	param->enable_xattr = 1;
+ 	if (options.lazy_loading_overridden)
+--- a/fs/yaffs2/yaffs_mtdif.c
++++ b/fs/yaffs2/yaffs_mtdif.c
+@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d
+ 	return mtd;
+ }
+ 
+-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
++		     int tags_9bytes)
+ {
+ 	if (yaffs_version == 2) {
+ 		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt
+ 			);
+ 			return -1;
+ 		}
++
++		if (tags_9bytes && mtd->oobavail < 9) {
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				    "MTD device does not support 9-byte tags");
++			return -1;
++		}
+ 	}
+ 
+ 	return 0;
+--- a/fs/yaffs2/yaffs_mtdif.h
++++ b/fs/yaffs2/yaffs_mtdif.h
+@@ -21,5 +21,6 @@
+ void yaffs_mtd_drv_install(struct yaffs_dev *dev);
+ struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
+ void yaffs_put_mtd_device(struct mtd_info *mtd);
+-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
++int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags,
++		     int tags_9bytes);
+ #endif
diff --git a/target/linux/generic/patches-4.4/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-4.4/504-yaffs-3.16-new-fops.patch
new file mode 100644
index 0000000000..32b4fdfa39
--- /dev/null
+++ b/target/linux/generic/patches-4.4/504-yaffs-3.16-new-fops.patch
@@ -0,0 +1,29 @@
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -774,7 +774,25 @@ static int yaffs_sync_object(struct file
+ }
+ 
+ 
+-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
++static const struct file_operations yaffs_file_operations = {
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
++	.read = new_sync_read,
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */
++	.read_iter = generic_file_read_iter,
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
++	.write = new_sync_write,
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) */
++	.write_iter = generic_file_write_iter,
++	.mmap = generic_file_mmap,
++	.flush = yaffs_file_flush,
++	.fsync = yaffs_sync_object,
++	.splice_read = generic_file_splice_read,
++	.splice_write = iter_file_splice_write,
++	.llseek = generic_file_llseek,
++};
++
++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+ static const struct file_operations yaffs_file_operations = {
+ 	.read = do_sync_read,
+ 	.write = do_sync_write,
diff --git a/target/linux/generic/patches-4.4/505-yaffs-3.19-f_dentry-remove.patch b/target/linux/generic/patches-4.4/505-yaffs-3.19-f_dentry-remove.patch
new file mode 100644
index 0000000000..0d4b6bf04f
--- /dev/null
+++ b/target/linux/generic/patches-4.4/505-yaffs-3.19-f_dentry-remove.patch
@@ -0,0 +1,95 @@
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -283,7 +283,7 @@ static int yaffs_readpage_nolock(struct
+ 		(long long)pos,
+ 		(unsigned)PAGE_CACHE_SIZE);
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	dev = obj->my_dev;
+ 
+@@ -481,7 +481,7 @@ static ssize_t yaffs_hold_space(struct f
+ 
+ 	int n_free_chunks;
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	dev = obj->my_dev;
+ 
+@@ -499,7 +499,7 @@ static void yaffs_release_space(struct f
+ 	struct yaffs_obj *obj;
+ 	struct yaffs_dev *dev;
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	dev = obj->my_dev;
+ 
+@@ -591,7 +591,7 @@ static ssize_t yaffs_file_write(struct f
+ 	struct inode *inode;
+ 	struct yaffs_dev *dev;
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 
+ 	if (!obj) {
+ 		yaffs_trace(YAFFS_TRACE_OS,
+@@ -603,7 +603,7 @@ static ssize_t yaffs_file_write(struct f
+ 
+ 	yaffs_gross_lock(dev);
+ 
+-	inode = f->f_dentry->d_inode;
++	inode = f->f_path.dentry->d_inode;
+ 
+ 	if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
+ 		ipos = inode->i_size;
+@@ -727,7 +727,7 @@ static int yaffs_file_flush(struct file
+ static int yaffs_file_flush(struct file *file)
+ #endif
+ {
+-	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
++	struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_path.dentry);
+ 
+ 	struct yaffs_dev *dev = obj->my_dev;
+ 
+@@ -1734,7 +1734,7 @@ static int yaffs_iterate(struct file *f,
+ 
+ 	char name[YAFFS_MAX_NAME_LENGTH + 1];
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 	dev = obj->my_dev;
+ 
+ 	yaffs_gross_lock(dev);
+@@ -1798,14 +1798,14 @@ static int yaffs_readdir(struct file *f,
+ 	struct yaffs_obj *obj;
+ 	struct yaffs_dev *dev;
+ 	struct yaffs_search_context *sc;
+-	struct inode *inode = f->f_dentry->d_inode;
++	struct inode *inode = f->f_path.dentry->d_inode;
+ 	unsigned long offset, curoffs;
+ 	struct yaffs_obj *l;
+ 	int ret_val = 0;
+ 
+ 	char name[YAFFS_MAX_NAME_LENGTH + 1];
+ 
+-	obj = yaffs_dentry_to_obj(f->f_dentry);
++	obj = yaffs_dentry_to_obj(f->f_path.dentry);
+ 	dev = obj->my_dev;
+ 
+ 	yaffs_gross_lock(dev);
+@@ -1839,10 +1839,10 @@ static int yaffs_readdir(struct file *f,
+ 	if (offset == 1) {
+ 		yaffs_trace(YAFFS_TRACE_OS,
+ 			"yaffs_readdir: entry .. ino %d",
+-			(int)f->f_dentry->d_parent->d_inode->i_ino);
++			(int)f->f_path.dentry->d_parent->d_inode->i_ino);
+ 		yaffs_gross_unlock(dev);
+ 		if (filldir(dirent, "..", 2, offset,
+-			    f->f_dentry->d_parent->d_inode->i_ino,
++			    f->f_path.dentry->d_parent->d_inode->i_ino,
+ 			    DT_DIR) < 0) {
+ 			yaffs_gross_lock(dev);
+ 			goto out;
diff --git a/target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch b/target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch
new file mode 100644
index 0000000000..60c4e378e0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/506-yaffs2-using-new-follow_link-and-put_link.patch
@@ -0,0 +1,47 @@
+From d4eb3ab036f8c37c5bc5f45ad0fa4dc34b7228c8 Mon Sep 17 00:00:00 2001
+From: Kevin Hao <kexin.hao@windriver.com>
+Date: Wed, 24 Feb 2016 14:37:13 +0800
+Subject: [PATCH 3/3] yaffs2: using new ->follow_link() and ->put_link()
+ calling conventions
+
+As what we did in commit 680baacbca69 ("new ->follow_link() and
+->put_link() calling conventions").
+
+Signed-off-by: Kevin Hao <kexin.hao@windriver.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+---
+ fs/yaffs2/yaffs_vfs.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/fs/yaffs2/yaffs_vfs.c
++++ b/fs/yaffs2/yaffs_vfs.c
+@@ -1060,7 +1060,7 @@ static int yaffs_readlink(struct dentry
+ }
+ 
+ #if (YAFFS_NEW_FOLLOW_LINK == 1)
+-static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
++static const char *yaffs_follow_link(struct dentry *dentry, void **cookie)
+ {
+ 	void *ret;
+ #else
+@@ -1082,7 +1082,7 @@ static int yaffs_follow_link(struct dent
+ 		goto out;
+ 	}
+ #if (YAFFS_NEW_FOLLOW_LINK == 1)
+-	nd_set_link(nd, alias);
++	*cookie = alias;
+ 	ret = alias;
+ out:
+ 	if (ret_int)
+@@ -1114,9 +1114,9 @@ static void yaffs_put_inode(struct inode
+ #endif
+ 
+ #if (YAFFS_NEW_FOLLOW_LINK == 1)
+-void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
++void yaffs_put_link(struct inode *inode, void *cookie)
+ {
+-	kfree(alias);
++	kfree(cookie);
+ }
+ #endif
+ 
diff --git a/target/linux/generic/patches-4.4/530-jffs2_make_lzma_available.patch b/target/linux/generic/patches-4.4/530-jffs2_make_lzma_available.patch
new file mode 100644
index 0000000000..b75dd0f9ff
--- /dev/null
+++ b/target/linux/generic/patches-4.4/530-jffs2_make_lzma_available.patch
@@ -0,0 +1,5142 @@
+--- a/fs/jffs2/Kconfig
++++ b/fs/jffs2/Kconfig
+@@ -139,6 +139,15 @@ config JFFS2_LZO
+ 	  This feature was added in July, 2007. Say 'N' if you need
+ 	  compatibility with older bootloaders or kernels.
+ 
++config JFFS2_LZMA
++	bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS
++	select LZMA_COMPRESS
++	select LZMA_DECOMPRESS
++	depends on JFFS2_FS
++	default n
++	help
++	  JFFS2 wrapper to the LZMA C SDK
++
+ config JFFS2_RTIME
+ 	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+ 	depends on JFFS2_FS
+--- a/fs/jffs2/Makefile
++++ b/fs/jffs2/Makefile
+@@ -18,4 +18,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rub
+ jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
+ jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
+ jffs2-$(CONFIG_JFFS2_LZO)	+= compr_lzo.o
++jffs2-$(CONFIG_JFFS2_LZMA)      += compr_lzma.o
+ jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
++
++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma
+--- a/fs/jffs2/compr.c
++++ b/fs/jffs2/compr.c
+@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_init();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_init();
++#endif
+ /* Setting default compression mode */
+ #ifdef CONFIG_JFFS2_CMODE_NONE
+ 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void)
+ int jffs2_compressors_exit(void)
+ {
+ /* Unregistering compressors */
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_exit();
++#endif
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_exit();
+ #endif
+--- a/fs/jffs2/compr.h
++++ b/fs/jffs2/compr.h
+@@ -29,9 +29,9 @@
+ #define JFFS2_DYNRUBIN_PRIORITY  20
+ #define JFFS2_LZARI_PRIORITY     30
+ #define JFFS2_RTIME_PRIORITY     50
+-#define JFFS2_ZLIB_PRIORITY      60
+-#define JFFS2_LZO_PRIORITY       80
+-
++#define JFFS2_LZMA_PRIORITY      70
++#define JFFS2_ZLIB_PRIORITY      80
++#define JFFS2_LZO_PRIORITY       90
+ 
+ #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
+ #define JFFS2_DYNRUBIN_DISABLED  /*	   for decompression */
+@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void);
+ int jffs2_lzo_init(void);
+ void jffs2_lzo_exit(void);
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++int jffs2_lzma_init(void);
++void jffs2_lzma_exit(void);
++#endif
+ 
+ #endif /* __JFFS2_COMPR_H__ */
+--- /dev/null
++++ b/fs/jffs2/compr_lzma.c
+@@ -0,0 +1,128 @@
++/*
++ * JFFS2 -- Journalling Flash File System, Version 2.
++ *
++ * For licensing information, see the file 'LICENCE' in this directory.
++ *
++ * JFFS2 wrapper to the LZMA C SDK
++ *
++ */
++
++#include <linux/lzma.h>
++#include "compr.h"
++
++#ifdef __KERNEL__
++	static DEFINE_MUTEX(deflate_mutex);
++#endif
++
++CLzmaEncHandle *p;
++Byte propsEncoded[LZMA_PROPS_SIZE];
++SizeT propsSize = sizeof(propsEncoded);
++
++STATIC void lzma_free_workspace(void)
++{
++	LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
++}
++
++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
++{
++	if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
++	{
++		PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
++		return -ENOMEM;
++	}
++
++	if (LzmaEnc_SetProps(p, props) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++	
++	if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++        return 0;
++}
++
++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
++			      uint32_t *sourcelen, uint32_t *dstlen)
++{
++	SizeT compress_size = (SizeT)(*dstlen);
++	int ret;
++
++	#ifdef __KERNEL__
++		mutex_lock(&deflate_mutex);
++	#endif
++
++	ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
++		0, NULL, &lzma_alloc, &lzma_alloc);
++
++	#ifdef __KERNEL__
++		mutex_unlock(&deflate_mutex);
++	#endif
++
++	if (ret != SZ_OK)
++		return -1;
++
++	*dstlen = (uint32_t)compress_size;
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
++				 uint32_t srclen, uint32_t destlen)
++{
++	int ret;
++	SizeT dl = (SizeT)destlen;
++	SizeT sl = (SizeT)srclen;
++	ELzmaStatus status;
++	
++	ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
++		propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
++
++	if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
++		return -1;
++
++	return 0;
++}
++
++static struct jffs2_compressor jffs2_lzma_comp = {
++	.priority = JFFS2_LZMA_PRIORITY,
++	.name = "lzma",
++	.compr = JFFS2_COMPR_LZMA,
++	.compress = &jffs2_lzma_compress,
++	.decompress = &jffs2_lzma_decompress,
++	.disabled = 0,
++};
++
++int INIT jffs2_lzma_init(void)
++{
++        int ret;
++	CLzmaEncProps props;
++	LzmaEncProps_Init(&props);
++
++        props.dictSize = LZMA_BEST_DICT(0x2000);
++        props.level = LZMA_BEST_LEVEL;
++        props.lc = LZMA_BEST_LC;
++        props.lp = LZMA_BEST_LP;
++        props.pb = LZMA_BEST_PB;
++        props.fb = LZMA_BEST_FB;
++
++	ret = lzma_alloc_workspace(&props);
++        if (ret < 0)
++                return ret;
++
++	ret = jffs2_register_compressor(&jffs2_lzma_comp);
++	if (ret)
++		lzma_free_workspace();
++	
++        return ret;
++}
++
++void jffs2_lzma_exit(void)
++{
++	jffs2_unregister_compressor(&jffs2_lzma_comp);
++	lzma_free_workspace();
++}
+--- a/fs/jffs2/super.c
++++ b/fs/jffs2/super.c
+@@ -375,14 +375,41 @@ static int __init init_jffs2_fs(void)
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
+ 
+-	pr_info("version 2.2."
++	pr_info("version 2.2"
+ #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ 	       " (NAND)"
+ #endif
+ #ifdef CONFIG_JFFS2_SUMMARY
+-	       " (SUMMARY) "
++	       " (SUMMARY)"
+ #endif
+-	       " © 2001-2006 Red Hat, Inc.\n");
++#ifdef CONFIG_JFFS2_ZLIB
++	       " (ZLIB)"
++#endif
++#ifdef CONFIG_JFFS2_LZO
++	       " (LZO)"
++#endif
++#ifdef CONFIG_JFFS2_LZMA
++	       " (LZMA)"
++#endif
++#ifdef CONFIG_JFFS2_RTIME
++	       " (RTIME)"
++#endif
++#ifdef CONFIG_JFFS2_RUBIN
++	       " (RUBIN)"
++#endif
++#ifdef  CONFIG_JFFS2_CMODE_NONE
++	       " (CMODE_NONE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_PRIORITY
++	       " (CMODE_PRIORITY)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_SIZE
++	       " (CMODE_SIZE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
++	       " (CMODE_FAVOURLZO)"
++#endif
++	       " (c) 2001-2006 Red Hat, Inc.\n");
+ 
+ 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
+ 					     sizeof(struct jffs2_inode_info),
+--- a/include/uapi/linux/jffs2.h
++++ b/include/uapi/linux/jffs2.h
+@@ -46,6 +46,7 @@
+ #define JFFS2_COMPR_DYNRUBIN	0x05
+ #define JFFS2_COMPR_ZLIB	0x06
+ #define JFFS2_COMPR_LZO		0x07
++#define JFFS2_COMPR_LZMA	0x08
+ /* Compatibility flags. */
+ #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+ #define JFFS2_NODE_ACCURATE 0x2000
+--- /dev/null
++++ b/include/linux/lzma.h
+@@ -0,0 +1,62 @@
++#ifndef __LZMA_H__
++#define __LZMA_H__
++
++#ifdef __KERNEL__
++	#include <linux/kernel.h>
++	#include <linux/sched.h>
++	#include <linux/slab.h>
++	#include <linux/vmalloc.h>
++	#include <linux/init.h>
++	#define LZMA_MALLOC vmalloc
++	#define LZMA_FREE vfree
++	#define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
++	#define INIT __init
++	#define STATIC static
++#else
++	#include <stdint.h>
++	#include <stdlib.h>
++	#include <stdio.h>
++	#include <unistd.h>
++	#include <string.h>
++	#include <asm/types.h>
++	#include <errno.h>
++	#include <linux/jffs2.h>
++	#ifndef PAGE_SIZE
++		extern int page_size;
++		#define PAGE_SIZE page_size
++	#endif
++	#define LZMA_MALLOC malloc
++	#define LZMA_FREE free
++	#define PRINT_ERROR(msg) fprintf(stderr, msg)
++	#define INIT
++	#define STATIC
++#endif
++
++#include "lzma/LzmaDec.h"
++#include "lzma/LzmaEnc.h"
++
++#define LZMA_BEST_LEVEL (9)
++#define LZMA_BEST_LC    (0)
++#define LZMA_BEST_LP    (0)
++#define LZMA_BEST_PB    (0)
++#define LZMA_BEST_FB  (273)
++
++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
++
++static void *p_lzma_malloc(void *p, size_t size)
++{
++        if (size == 0)
++                return NULL;
++
++        return LZMA_MALLOC(size);
++}
++
++static void p_lzma_free(void *p, void *address)
++{
++        if (address != NULL)
++                LZMA_FREE(address);
++}
++
++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free};
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzFind.h
+@@ -0,0 +1,115 @@
++/* LzFind.h -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_FIND_H
++#define __LZ_FIND_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef UInt32 CLzRef;
++
++typedef struct _CMatchFinder
++{
++  Byte *buffer;
++  UInt32 pos;
++  UInt32 posLimit;
++  UInt32 streamPos;
++  UInt32 lenLimit;
++
++  UInt32 cyclicBufferPos;
++  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
++
++  UInt32 matchMaxLen;
++  CLzRef *hash;
++  CLzRef *son;
++  UInt32 hashMask;
++  UInt32 cutValue;
++
++  Byte *bufferBase;
++  ISeqInStream *stream;
++  int streamEndWasReached;
++
++  UInt32 blockSize;
++  UInt32 keepSizeBefore;
++  UInt32 keepSizeAfter;
++
++  UInt32 numHashBytes;
++  int directInput;
++  size_t directInputRem;
++  int btMode;
++  int bigHash;
++  UInt32 historySize;
++  UInt32 fixedHashSize;
++  UInt32 hashSizeSum;
++  UInt32 numSons;
++  SRes result;
++  UInt32 crc[256];
++} CMatchFinder;
++
++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
++
++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
++
++int MatchFinder_NeedMove(CMatchFinder *p);
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
++void MatchFinder_MoveBlock(CMatchFinder *p);
++void MatchFinder_ReadIfRequired(CMatchFinder *p);
++
++void MatchFinder_Construct(CMatchFinder *p);
++
++/* Conditions:
++     historySize <= 3 GB
++     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
++*/
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc);
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
++    UInt32 *distances, UInt32 maxLen);
++
++/*
++Conditions:
++  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
++  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
++*/
++
++typedef void (*Mf_Init_Func)(void *object);
++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
++typedef void (*Mf_Skip_Func)(void *object, UInt32);
++
++typedef struct _IMatchFinder
++{
++  Mf_Init_Func Init;
++  Mf_GetIndexByte_Func GetIndexByte;
++  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
++  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
++  Mf_GetMatches_Func GetMatches;
++  Mf_Skip_Func Skip;
++} IMatchFinder;
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
++
++void MatchFinder_Init(CMatchFinder *p);
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzHash.h
+@@ -0,0 +1,54 @@
++/* LzHash.h -- HASH functions for LZ algorithms
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_HASH_H
++#define __LZ_HASH_H
++
++#define kHash2Size (1 << 10)
++#define kHash3Size (1 << 16)
++#define kHash4Size (1 << 20)
++
++#define kFix3HashSize (kHash2Size)
++#define kFix4HashSize (kHash2Size + kHash3Size)
++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
++
++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
++
++#define HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
++
++#define HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
++
++#define HASH5_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
++  hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
++  hash4Value &= (kHash4Size - 1); }
++
++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
++
++
++#define MT_HASH2_CALC \
++  hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
++
++#define MT_HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
++
++#define MT_HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaDec.h
+@@ -0,0 +1,231 @@
++/* LzmaDec.h -- LZMA Decoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_DEC_H
++#define __LZMA_DEC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* #define _LZMA_PROB32 */
++/* _LZMA_PROB32 can increase the speed on some CPUs,
++   but memory usage for CLzmaDec::probs will be doubled in that case */
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++
++/* ---------- LZMA Properties ---------- */
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaProps
++{
++  unsigned lc, lp, pb;
++  UInt32 dicSize;
++} CLzmaProps;
++
++/* LzmaProps_Decode - decodes properties
++Returns:
++  SZ_OK
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
++
++
++/* ---------- LZMA Decoder state ---------- */
++
++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
++   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
++
++#define LZMA_REQUIRED_INPUT_MAX 20
++
++typedef struct
++{
++  CLzmaProps prop;
++  CLzmaProb *probs;
++  Byte *dic;
++  const Byte *buf;
++  UInt32 range, code;
++  SizeT dicPos;
++  SizeT dicBufSize;
++  UInt32 processedPos;
++  UInt32 checkDicSize;
++  unsigned state;
++  UInt32 reps[4];
++  unsigned remainLen;
++  int needFlush;
++  int needInitState;
++  UInt32 numProbs;
++  unsigned tempBufSize;
++  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
++} CLzmaDec;
++
++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
++
++void LzmaDec_Init(CLzmaDec *p);
++
++/* There are two types of LZMA streams:
++     0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
++     1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
++
++typedef enum
++{
++  LZMA_FINISH_ANY,   /* finish at any point */
++  LZMA_FINISH_END    /* block must be finished at the end */
++} ELzmaFinishMode;
++
++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
++
++   You must use LZMA_FINISH_END, when you know that current output buffer
++   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
++
++   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
++   and output value of destLen will be less than output buffer size limit.
++   You can check status result also.
++
++   You can use multiple checks to test data integrity after full decompression:
++     1) Check Result and "status" variable.
++     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
++     3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
++        You must use correct finish mode in that case. */
++
++typedef enum
++{
++  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
++  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
++  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
++  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */
++  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
++} ELzmaStatus;
++
++/* ELzmaStatus is used only as output value for function call */
++
++
++/* ---------- Interfaces ---------- */
++
++/* There are 3 levels of interfaces:
++     1) Dictionary Interface
++     2) Buffer Interface
++     3) One Call Interface
++   You can select any of these interfaces, but don't mix functions from different
++   groups for same object. */
++
++
++/* There are two variants to allocate state for Dictionary Interface:
++     1) LzmaDec_Allocate / LzmaDec_Free
++     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
++   You can use variant 2, if you set dictionary buffer manually.
++   For Buffer Interface you must always use variant 1.
++
++LzmaDec_Allocate* can return:
++  SZ_OK
++  SZ_ERROR_MEM         - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++   
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
++
++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
++
++/* ---------- Dictionary Interface ---------- */
++
++/* You can use it, if you want to eliminate the overhead for data copying from
++   dictionary to some other external buffer.
++   You must work with CLzmaDec variables directly in this interface.
++
++   STEPS:
++     LzmaDec_Constr()
++     LzmaDec_Allocate()
++     for (each new stream)
++     {
++       LzmaDec_Init()
++       while (it needs more decompression)
++       {
++         LzmaDec_DecodeToDic()
++         use data from CLzmaDec::dic and update CLzmaDec::dicPos
++       }
++     }
++     LzmaDec_Free()
++*/
++
++/* LzmaDec_DecodeToDic
++   
++   The decoding to internal dictionary buffer (CLzmaDec::dic).
++   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (dicLimit).
++  LZMA_FINISH_ANY - Decode just dicLimit bytes.
++  LZMA_FINISH_END - Stream must be finished after dicLimit.
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_NEEDS_MORE_INPUT
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++*/
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- Buffer Interface ---------- */
++
++/* It's zlib-like interface.
++   See LzmaDec_DecodeToDic description for information about STEPS and return results,
++   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
++   to work with CLzmaDec variables manually.
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++*/
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaDecode
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++  SZ_ERROR_MEM  - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
++*/
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -0,0 +1,80 @@
++/*  LzmaEnc.h -- LZMA Encoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_ENC_H
++#define __LZMA_ENC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaEncProps
++{
++  int level;       /*  0 <= level <= 9 */
++  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
++                      (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
++                       default = (1 << 24) */
++  int lc;          /* 0 <= lc <= 8, default = 3 */
++  int lp;          /* 0 <= lp <= 4, default = 0 */
++  int pb;          /* 0 <= pb <= 4, default = 2 */
++  int algo;        /* 0 - fast, 1 - normal, default = 1 */
++  int fb;          /* 5 <= fb <= 273, default = 32 */
++  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
++  int numHashBytes; /* 2, 3 or 4, default = 4 */
++  UInt32 mc;        /* 1 <= mc <= (1 << 30), default = 32 */
++  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
++  int numThreads;  /* 1 or 2, default = 2 */
++} CLzmaEncProps;
++
++void LzmaEncProps_Init(CLzmaEncProps *p);
++void LzmaEncProps_Normalize(CLzmaEncProps *p);
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
++
++
++/* ---------- CLzmaEncHandle Interface ---------- */
++
++/* LzmaEnc_* functions can return the following exit codes:
++Returns:
++  SZ_OK           - OK
++  SZ_ERROR_MEM    - Memory allocation error
++  SZ_ERROR_PARAM  - Incorrect paramater in props
++  SZ_ERROR_WRITE  - Write callback error.
++  SZ_ERROR_PROGRESS - some break from progress callback
++  SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
++*/
++
++typedef void * CLzmaEncHandle;
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaEncode
++Return code:
++  SZ_OK               - OK
++  SZ_ERROR_MEM        - Memory allocation error
++  SZ_ERROR_PARAM      - Incorrect paramater
++  SZ_ERROR_OUTPUT_EOF - output buffer overflow
++  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
++*/
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/Types.h
+@@ -0,0 +1,226 @@
++/* Types.h -- Basic types
++2009-11-23 : Igor Pavlov : Public domain */
++
++#ifndef __7Z_TYPES_H
++#define __7Z_TYPES_H
++
++#include <stddef.h>
++
++#ifdef _WIN32
++#include <windows.h>
++#endif
++
++#ifndef EXTERN_C_BEGIN
++#ifdef __cplusplus
++#define EXTERN_C_BEGIN extern "C" {
++#define EXTERN_C_END }
++#else
++#define EXTERN_C_BEGIN
++#define EXTERN_C_END
++#endif
++#endif
++
++EXTERN_C_BEGIN
++
++#define SZ_OK 0
++
++#define SZ_ERROR_DATA 1
++#define SZ_ERROR_MEM 2
++#define SZ_ERROR_CRC 3
++#define SZ_ERROR_UNSUPPORTED 4
++#define SZ_ERROR_PARAM 5
++#define SZ_ERROR_INPUT_EOF 6
++#define SZ_ERROR_OUTPUT_EOF 7
++#define SZ_ERROR_READ 8
++#define SZ_ERROR_WRITE 9
++#define SZ_ERROR_PROGRESS 10
++#define SZ_ERROR_FAIL 11
++#define SZ_ERROR_THREAD 12
++
++#define SZ_ERROR_ARCHIVE 16
++#define SZ_ERROR_NO_ARCHIVE 17
++
++typedef int SRes;
++
++#ifdef _WIN32
++typedef DWORD WRes;
++#else
++typedef int WRes;
++#endif
++
++#ifndef RINOK
++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
++#endif
++
++typedef unsigned char Byte;
++typedef short Int16;
++typedef unsigned short UInt16;
++
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef long Int32;
++typedef unsigned long UInt32;
++#else
++typedef int Int32;
++typedef unsigned int UInt32;
++#endif
++
++#ifdef _SZ_NO_INT_64
++
++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
++   NOTES: Some code will work incorrectly in that case! */
++
++typedef long Int64;
++typedef unsigned long UInt64;
++
++#else
++
++#if defined(_MSC_VER) || defined(__BORLANDC__)
++typedef __int64 Int64;
++typedef unsigned __int64 UInt64;
++#else
++typedef long long int Int64;
++typedef unsigned long long int UInt64;
++#endif
++
++#endif
++
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++typedef size_t SizeT;
++#endif
++
++typedef int Bool;
++#define True 1
++#define False 0
++
++
++#ifdef _WIN32
++#define MY_STD_CALL __stdcall
++#else
++#define MY_STD_CALL
++#endif
++
++#ifdef _MSC_VER
++
++#if _MSC_VER >= 1300
++#define MY_NO_INLINE __declspec(noinline)
++#else
++#define MY_NO_INLINE
++#endif
++
++#define MY_CDECL __cdecl
++#define MY_FAST_CALL __fastcall
++
++#else
++
++#define MY_CDECL
++#define MY_FAST_CALL
++
++#endif
++
++
++/* The following interfaces use first parameter as pointer to structure */
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) < input(*size)) is allowed */
++} ISeqInStream;
++
++/* it can return SZ_ERROR_INPUT_EOF */
++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
++
++typedef struct
++{
++  size_t (*Write)(void *p, const void *buf, size_t size);
++    /* Returns: result - the number of actually written bytes.
++       (result < size) means error */
++} ISeqOutStream;
++
++typedef enum
++{
++  SZ_SEEK_SET = 0,
++  SZ_SEEK_CUR = 1,
++  SZ_SEEK_END = 2
++} ESzSeek;
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);  /* same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ISeekInStream;
++
++typedef struct
++{
++  SRes (*Look)(void *p, void **buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) > input(*size)) is not allowed
++       (output(*size) < input(*size)) is allowed */
++  SRes (*Skip)(void *p, size_t offset);
++    /* offset must be <= output(*size) of Look */
++
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* reads directly (without buffer). It's same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ILookInStream;
++
++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
++
++/* reads via ILookInStream::Read */
++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
++
++#define LookToRead_BUF_SIZE (1 << 14)
++
++typedef struct
++{
++  ILookInStream s;
++  ISeekInStream *realStream;
++  size_t pos;
++  size_t size;
++  Byte buf[LookToRead_BUF_SIZE];
++} CLookToRead;
++
++void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
++void LookToRead_Init(CLookToRead *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToLook;
++
++void SecToLook_CreateVTable(CSecToLook *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToRead;
++
++void SecToRead_CreateVTable(CSecToRead *p);
++
++typedef struct
++{
++  SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
++    /* Returns: result. (result != SZ_OK) means break.
++       Value (UInt64)(Int64)-1 for size means unknown value. */
++} ICompressProgress;
++
++typedef struct
++{
++  void *(*Alloc)(void *p, size_t size);
++  void (*Free)(void *p, void *address); /* address can be 0 */
++} ISzAlloc;
++
++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
++#define IAlloc_Free(p, a) (p)->Free((p), a)
++
++EXTERN_C_END
++
++#endif
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -241,6 +241,12 @@ config LZ4_DECOMPRESS
+ 
+ source "lib/xz/Kconfig"
+ 
++config LZMA_COMPRESS
++    tristate
++
++config LZMA_DECOMPRESS
++    tristate
++
+ #
+ # These all provide a common interface (hence the apparent duplication with
+ # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.)
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -2,6 +2,16 @@
+ # Makefile for some libs needed in the kernel.
+ #
+ 
++ifdef CONFIG_JFFS2_ZLIB
++	CONFIG_ZLIB_INFLATE:=y
++	CONFIG_ZLIB_DEFLATE:=y
++endif
++
++ifdef CONFIG_JFFS2_LZMA
++	CONFIG_LZMA_DECOMPRESS:=y
++	CONFIG_LZMA_COMPRESS:=y
++endif
++
+ ifdef CONFIG_FUNCTION_TRACER
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
+@@ -98,6 +108,8 @@ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
+ obj-$(CONFIG_XZ_DEC) += xz/
+ obj-$(CONFIG_RAID6_PQ) += raid6/
++obj-$(CONFIG_LZMA_COMPRESS) += lzma/
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/
+ 
+ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
+ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+--- /dev/null
++++ b/lib/lzma/LzFind.c
+@@ -0,0 +1,761 @@
++/* LzFind.c -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++#include "LzFind.h"
++#include "LzHash.h"
++
++#define kEmptyHashValue 0
++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
++#define kNormalizeMask (~(kNormalizeStepMin - 1))
++#define kMaxHistorySize ((UInt32)3 << 30)
++
++#define kStartMaxLen 3
++
++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  if (!p->directInput)
++  {
++    alloc->Free(alloc, p->bufferBase);
++    p->bufferBase = 0;
++  }
++}
++
++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
++
++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
++{
++  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
++  if (p->directInput)
++  {
++    p->blockSize = blockSize;
++    return 1;
++  }
++  if (p->bufferBase == 0 || p->blockSize != blockSize)
++  {
++    LzInWindow_Free(p, alloc);
++    p->blockSize = blockSize;
++    p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
++  }
++  return (p->bufferBase != 0);
++}
++
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++
++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++{
++  p->posLimit -= subValue;
++  p->pos -= subValue;
++  p->streamPos -= subValue;
++}
++
++static void MatchFinder_ReadBlock(CMatchFinder *p)
++{
++  if (p->streamEndWasReached || p->result != SZ_OK)
++    return;
++  if (p->directInput)
++  {
++    UInt32 curSize = 0xFFFFFFFF - p->streamPos;
++    if (curSize > p->directInputRem)
++      curSize = (UInt32)p->directInputRem;
++    p->directInputRem -= curSize;
++    p->streamPos += curSize;
++    if (p->directInputRem == 0)
++      p->streamEndWasReached = 1;
++    return;
++  }
++  for (;;)
++  {
++    Byte *dest = p->buffer + (p->streamPos - p->pos);
++    size_t size = (p->bufferBase + p->blockSize - dest);
++    if (size == 0)
++      return;
++    p->result = p->stream->Read(p->stream, dest, &size);
++    if (p->result != SZ_OK)
++      return;
++    if (size == 0)
++    {
++      p->streamEndWasReached = 1;
++      return;
++    }
++    p->streamPos += (UInt32)size;
++    if (p->streamPos - p->pos > p->keepSizeAfter)
++      return;
++  }
++}
++
++void MatchFinder_MoveBlock(CMatchFinder *p)
++{
++  memmove(p->bufferBase,
++    p->buffer - p->keepSizeBefore,
++    (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
++  p->buffer = p->bufferBase + p->keepSizeBefore;
++}
++
++int MatchFinder_NeedMove(CMatchFinder *p)
++{
++  if (p->directInput)
++    return 0;
++  /* if (p->streamEndWasReached) return 0; */
++  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
++}
++
++void MatchFinder_ReadIfRequired(CMatchFinder *p)
++{
++  if (p->streamEndWasReached)
++    return;
++  if (p->keepSizeAfter >= p->streamPos - p->pos)
++    MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
++{
++  if (MatchFinder_NeedMove(p))
++    MatchFinder_MoveBlock(p);
++  MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
++{
++  p->cutValue = 32;
++  p->btMode = 1;
++  p->numHashBytes = 4;
++  p->bigHash = 0;
++}
++
++#define kCrcPoly 0xEDB88320
++
++void MatchFinder_Construct(CMatchFinder *p)
++{
++  UInt32 i;
++  p->bufferBase = 0;
++  p->directInput = 0;
++  p->hash = 0;
++  MatchFinder_SetDefaultSettings(p);
++
++  for (i = 0; i < 256; i++)
++  {
++    UInt32 r = i;
++    int j;
++    for (j = 0; j < 8; j++)
++      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
++    p->crc[i] = r;
++  }
++}
++
++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->hash);
++  p->hash = 0;
++}
++
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  MatchFinder_FreeThisClassMemory(p, alloc);
++  LzInWindow_Free(p, alloc);
++}
++
++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
++{
++  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
++  if (sizeInBytes / sizeof(CLzRef) != num)
++    return 0;
++  return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
++}
++
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc)
++{
++  UInt32 sizeReserv;
++  if (historySize > kMaxHistorySize)
++  {
++    MatchFinder_Free(p, alloc);
++    return 0;
++  }
++  sizeReserv = historySize >> 1;
++  if (historySize > ((UInt32)2 << 30))
++    sizeReserv = historySize >> 2;
++  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
++
++  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
++  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
++  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
++  if (LzInWindow_Create(p, sizeReserv, alloc))
++  {
++    UInt32 newCyclicBufferSize = historySize + 1;
++    UInt32 hs;
++    p->matchMaxLen = matchMaxLen;
++    {
++      p->fixedHashSize = 0;
++      if (p->numHashBytes == 2)
++        hs = (1 << 16) - 1;
++      else
++      {
++        hs = historySize - 1;
++        hs |= (hs >> 1);
++        hs |= (hs >> 2);
++        hs |= (hs >> 4);
++        hs |= (hs >> 8);
++        hs >>= 1;
++        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
++        if (hs > (1 << 24))
++        {
++          if (p->numHashBytes == 3)
++            hs = (1 << 24) - 1;
++          else
++            hs >>= 1;
++        }
++      }
++      p->hashMask = hs;
++      hs++;
++      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
++      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
++      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
++      hs += p->fixedHashSize;
++    }
++
++    {
++      UInt32 prevSize = p->hashSizeSum + p->numSons;
++      UInt32 newSize;
++      p->historySize = historySize;
++      p->hashSizeSum = hs;
++      p->cyclicBufferSize = newCyclicBufferSize;
++      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
++      newSize = p->hashSizeSum + p->numSons;
++      if (p->hash != 0 && prevSize == newSize)
++        return 1;
++      MatchFinder_FreeThisClassMemory(p, alloc);
++      p->hash = AllocRefs(newSize, alloc);
++      if (p->hash != 0)
++      {
++        p->son = p->hash + p->hashSizeSum;
++        return 1;
++      }
++    }
++  }
++  MatchFinder_Free(p, alloc);
++  return 0;
++}
++
++static void MatchFinder_SetLimits(CMatchFinder *p)
++{
++  UInt32 limit = kMaxValForNormalize - p->pos;
++  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
++  if (limit2 < limit)
++    limit = limit2;
++  limit2 = p->streamPos - p->pos;
++  if (limit2 <= p->keepSizeAfter)
++  {
++    if (limit2 > 0)
++      limit2 = 1;
++  }
++  else
++    limit2 -= p->keepSizeAfter;
++  if (limit2 < limit)
++    limit = limit2;
++  {
++    UInt32 lenLimit = p->streamPos - p->pos;
++    if (lenLimit > p->matchMaxLen)
++      lenLimit = p->matchMaxLen;
++    p->lenLimit = lenLimit;
++  }
++  p->posLimit = p->pos + limit;
++}
++
++void MatchFinder_Init(CMatchFinder *p)
++{
++  UInt32 i;
++  for (i = 0; i < p->hashSizeSum; i++)
++    p->hash[i] = kEmptyHashValue;
++  p->cyclicBufferPos = 0;
++  p->buffer = p->bufferBase;
++  p->pos = p->streamPos = p->cyclicBufferSize;
++  p->result = SZ_OK;
++  p->streamEndWasReached = 0;
++  MatchFinder_ReadBlock(p);
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
++{
++  return (p->pos - p->historySize - 1) & kNormalizeMask;
++}
++
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++{
++  UInt32 i;
++  for (i = 0; i < numItems; i++)
++  {
++    UInt32 value = items[i];
++    if (value <= subValue)
++      value = kEmptyHashValue;
++    else
++      value -= subValue;
++    items[i] = value;
++  }
++}
++
++static void MatchFinder_Normalize(CMatchFinder *p)
++{
++  UInt32 subValue = MatchFinder_GetSubValue(p);
++  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
++  MatchFinder_ReduceOffsets(p, subValue);
++}
++
++static void MatchFinder_CheckLimits(CMatchFinder *p)
++{
++  if (p->pos == kMaxValForNormalize)
++    MatchFinder_Normalize(p);
++  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
++    MatchFinder_CheckAndMoveAndRead(p);
++  if (p->cyclicBufferPos == p->cyclicBufferSize)
++    p->cyclicBufferPos = 0;
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  son[_cyclicBufferPos] = curMatch;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++      return distances;
++    {
++      const Byte *pb = cur - delta;
++      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
++      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
++      {
++        UInt32 len = 0;
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++            return distances;
++        }
++      }
++    }
++  }
++}
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return distances;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        if (++len != lenLimit && pb[len] == cur[len])
++          while (++len != lenLimit)
++            if (pb[len] != cur[len])
++              break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return distances;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        {
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++#define MOVE_POS \
++  ++p->cyclicBufferPos; \
++  p->buffer++; \
++  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
++
++#define MOVE_POS_RET MOVE_POS return offset;
++
++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
++
++#define GET_MATCHES_HEADER2(minLen, ret_op) \
++  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
++  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
++  cur = p->buffer;
++
++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
++#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
++
++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
++
++#define GET_MATCHES_FOOTER(offset, maxLen) \
++  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
++  distances + offset, maxLen) - distances); MOVE_POS_RET;
++
++#define SKIP_FOOTER \
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
++
++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(2)
++  HASH2_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 1)
++}
++
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 2)
++}
++
++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, delta2, maxLen, offset;
++  GET_MATCHES_HEADER(3)
++
++  HASH3_CALC;
++
++  delta2 = p->pos - p->hash[hash2Value];
++  curMatch = p->hash[kFix3HashSize + hashValue];
++  
++  p->hash[hash2Value] =
++  p->hash[kFix3HashSize + hashValue] = p->pos;
++
++
++  maxLen = 2;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[0] = maxLen;
++    distances[1] = delta2 - 1;
++    offset = 2;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++  
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      p->son[p->cyclicBufferPos] = curMatch;
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances + offset, maxLen) - (distances));
++  MOVE_POS_RET
++}
++
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances, 2) - (distances));
++  MOVE_POS_RET
++}
++
++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(2)
++    HASH2_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value;
++    SKIP_HEADER(3)
++    HASH3_CALC;
++    curMatch = p->hash[kFix3HashSize + hashValue];
++    p->hash[hash2Value] =
++    p->hash[kFix3HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] = p->pos;
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] =
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
++{
++  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
++  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
++  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
++  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
++  if (!p->btMode)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 2)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 3)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
++  }
++  else
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
++  }
++}
+--- /dev/null
++++ b/lib/lzma/LzmaDec.c
+@@ -0,0 +1,999 @@
++/* LzmaDec.c -- LZMA Decoder
++2009-09-20 : Igor Pavlov : Public domain */
++
++#include "LzmaDec.h"
++
++#include <string.h>
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_INIT_SIZE 5
++
++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
++  { UPDATE_0(p); i = (i + i); A0; } else \
++  { UPDATE_1(p); i = (i + i) + 1; A1; }
++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
++
++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
++#define TREE_DECODE(probs, limit, i) \
++  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
++
++/* #define _LZMA_SIZE_OPT */
++
++#ifdef _LZMA_SIZE_OPT
++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
++#else
++#define TREE_6_DECODE(probs, i) \
++  { i = 1; \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  i -= 0x40; }
++#endif
++
++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0_CHECK range = bound;
++#define UPDATE_1_CHECK range -= bound; code -= bound;
++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
++  { UPDATE_0_CHECK; i = (i + i); A0; } else \
++  { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
++#define TREE_DECODE_CHECK(probs, limit, i) \
++  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#define LZMA_DIC_MIN (1 << 12)
++
++/* First LZMA-symbol is always decoded.
++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
++Out:
++  Result:
++    SZ_OK - OK
++    SZ_ERROR_DATA - Error
++  p->remainLen:
++    < kMatchSpecLenStart : normal remain
++    = kMatchSpecLenStart : finished
++    = kMatchSpecLenStart + 1 : Flush marker
++    = kMatchSpecLenStart + 2 : State Init Marker
++*/
++
++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  CLzmaProb *probs = p->probs;
++
++  unsigned state = p->state;
++  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
++  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
++  unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
++  unsigned lc = p->prop.lc;
++
++  Byte *dic = p->dic;
++  SizeT dicBufSize = p->dicBufSize;
++  SizeT dicPos = p->dicPos;
++  
++  UInt32 processedPos = p->processedPos;
++  UInt32 checkDicSize = p->checkDicSize;
++  unsigned len = 0;
++
++  const Byte *buf = p->buf;
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++
++  do
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = processedPos & pbMask;
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0(prob)
++    {
++      unsigned symbol;
++      UPDATE_0(prob);
++      prob = probs + Literal;
++      if (checkDicSize != 0 || processedPos != 0)
++        prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
++        (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
++
++      if (state < kNumLitStates)
++      {
++        state -= (state < 4) ? state : 3;
++        symbol = 1;
++        do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++        unsigned offs = 0x100;
++        state -= (state < 10) ? 3 : 6;
++        symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      dic[dicPos++] = (Byte)symbol;
++      processedPos++;
++      continue;
++    }
++    else
++    {
++      UPDATE_1(prob);
++      prob = probs + IsRep + state;
++      IF_BIT_0(prob)
++      {
++        UPDATE_0(prob);
++        state += kNumStates;
++        prob = probs + LenCoder;
++      }
++      else
++      {
++        UPDATE_1(prob);
++        if (checkDicSize == 0 && processedPos == 0)
++          return SZ_ERROR_DATA;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0(prob)
++        {
++          UPDATE_0(prob);
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++            dicPos++;
++            processedPos++;
++            state = state < kNumLitStates ? 9 : 11;
++            continue;
++          }
++          UPDATE_1(prob);
++        }
++        else
++        {
++          UInt32 distance;
++          UPDATE_1(prob);
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            distance = rep1;
++          }
++          else
++          {
++            UPDATE_1(prob);
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0(prob)
++            {
++              UPDATE_0(prob);
++              distance = rep2;
++            }
++            else
++            {
++              UPDATE_1(prob);
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        state = state < kNumLitStates ? 8 : 11;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0(probLen)
++        {
++          UPDATE_0(probLen);
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = (1 << kLenNumLowBits);
++        }
++        else
++        {
++          UPDATE_1(probLen);
++          probLen = prob + LenChoice2;
++          IF_BIT_0(probLen)
++          {
++            UPDATE_0(probLen);
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = (1 << kLenNumMidBits);
++          }
++          else
++          {
++            UPDATE_1(probLen);
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = (1 << kLenNumHighBits);
++          }
++        }
++        TREE_DECODE(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state >= kNumStates)
++      {
++        UInt32 distance;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
++        TREE_6_DECODE(prob, distance);
++        if (distance >= kStartPosModelIndex)
++        {
++          unsigned posSlot = (unsigned)distance;
++          int numDirectBits = (int)(((distance >> 1) - 1));
++          distance = (2 | (distance & 1));
++          if (posSlot < kEndPosModelIndex)
++          {
++            distance <<= numDirectBits;
++            prob = probs + SpecPos + distance - posSlot - 1;
++            {
++              UInt32 mask = 1;
++              unsigned i = 1;
++              do
++              {
++                GET_BIT2(prob + i, i, ; , distance |= mask);
++                mask <<= 1;
++              }
++              while (--numDirectBits != 0);
++            }
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE
++              range >>= 1;
++              
++              {
++                UInt32 t;
++                code -= range;
++                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
++                distance = (distance << 1) + (t + 1);
++                code += range & t;
++              }
++              /*
++              distance <<= 1;
++              if (code >= range)
++              {
++                code -= range;
++                distance |= 1;
++              }
++              */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            distance <<= kNumAlignBits;
++            {
++              unsigned i = 1;
++              GET_BIT2(prob + i, i, ; , distance |= 1);
++              GET_BIT2(prob + i, i, ; , distance |= 2);
++              GET_BIT2(prob + i, i, ; , distance |= 4);
++              GET_BIT2(prob + i, i, ; , distance |= 8);
++            }
++            if (distance == (UInt32)0xFFFFFFFF)
++            {
++              len += kMatchSpecLenStart;
++              state -= kNumStates;
++              break;
++            }
++          }
++        }
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        rep0 = distance + 1;
++        if (checkDicSize == 0)
++        {
++          if (distance >= processedPos)
++            return SZ_ERROR_DATA;
++        }
++        else if (distance >= checkDicSize)
++          return SZ_ERROR_DATA;
++        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
++      }
++
++      len += kMatchMinLen;
++
++      if (limit == dicPos)
++        return SZ_ERROR_DATA;
++      {
++        SizeT rem = limit - dicPos;
++        unsigned curLen = ((rem < len) ? (unsigned)rem : len);
++        SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
++
++        processedPos += curLen;
++
++        len -= curLen;
++        if (pos + curLen <= dicBufSize)
++        {
++          Byte *dest = dic + dicPos;
++          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
++          const Byte *lim = dest + curLen;
++          dicPos += curLen;
++          do
++            *(dest) = (Byte)*(dest + src);
++          while (++dest != lim);
++        }
++        else
++        {
++          do
++          {
++            dic[dicPos++] = dic[pos];
++            if (++pos == dicBufSize)
++              pos = 0;
++          }
++          while (--curLen != 0);
++        }
++      }
++    }
++  }
++  while (dicPos < limit && buf < bufLimit);
++  NORMALIZE;
++  p->buf = buf;
++  p->range = range;
++  p->code = code;
++  p->remainLen = len;
++  p->dicPos = dicPos;
++  p->processedPos = processedPos;
++  p->reps[0] = rep0;
++  p->reps[1] = rep1;
++  p->reps[2] = rep2;
++  p->reps[3] = rep3;
++  p->state = state;
++
++  return SZ_OK;
++}
++
++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
++{
++  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
++  {
++    Byte *dic = p->dic;
++    SizeT dicPos = p->dicPos;
++    SizeT dicBufSize = p->dicBufSize;
++    unsigned len = p->remainLen;
++    UInt32 rep0 = p->reps[0];
++    if (limit - dicPos < len)
++      len = (unsigned)(limit - dicPos);
++
++    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
++      p->checkDicSize = p->prop.dicSize;
++
++    p->processedPos += len;
++    p->remainLen -= len;
++    while (len-- != 0)
++    {
++      dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++      dicPos++;
++    }
++    p->dicPos = dicPos;
++  }
++}
++
++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  do
++  {
++    SizeT limit2 = limit;
++    if (p->checkDicSize == 0)
++    {
++      UInt32 rem = p->prop.dicSize - p->processedPos;
++      if (limit - p->dicPos > rem)
++        limit2 = p->dicPos + rem;
++    }
++    RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
++    if (p->processedPos >= p->prop.dicSize)
++      p->checkDicSize = p->prop.dicSize;
++    LzmaDec_WriteRem(p, limit);
++  }
++  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
++
++  if (p->remainLen > kMatchSpecLenStart)
++  {
++    p->remainLen = kMatchSpecLenStart;
++  }
++  return 0;
++}
++
++typedef enum
++{
++  DUMMY_ERROR, /* unexpected end of input stream */
++  DUMMY_LIT,
++  DUMMY_MATCH,
++  DUMMY_REP
++} ELzmaDummy;
++
++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
++{
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++  const Byte *bufLimit = buf + inSize;
++  CLzmaProb *probs = p->probs;
++  unsigned state = p->state;
++  ELzmaDummy res;
++
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0_CHECK(prob)
++    {
++      UPDATE_0_CHECK
++
++      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
++
++      prob = probs + Literal;
++      if (p->checkDicSize != 0 || p->processedPos != 0)
++        prob += (LZMA_LIT_SIZE *
++          ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
++          (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
++
++      if (state < kNumLitStates)
++      {
++        unsigned symbol = 1;
++        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
++            ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
++        unsigned offs = 0x100;
++        unsigned symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      res = DUMMY_LIT;
++    }
++    else
++    {
++      unsigned len;
++      UPDATE_1_CHECK;
++
++      prob = probs + IsRep + state;
++      IF_BIT_0_CHECK(prob)
++      {
++        UPDATE_0_CHECK;
++        state = 0;
++        prob = probs + LenCoder;
++        res = DUMMY_MATCH;
++      }
++      else
++      {
++        UPDATE_1_CHECK;
++        res = DUMMY_REP;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0_CHECK(prob)
++        {
++          UPDATE_0_CHECK;
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++            NORMALIZE_CHECK;
++            return DUMMY_REP;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++          }
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0_CHECK(prob)
++            {
++              UPDATE_0_CHECK;
++            }
++            else
++            {
++              UPDATE_1_CHECK;
++            }
++          }
++        }
++        state = kNumStates;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0_CHECK(probLen)
++        {
++          UPDATE_0_CHECK;
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = 1 << kLenNumLowBits;
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          probLen = prob + LenChoice2;
++          IF_BIT_0_CHECK(probLen)
++          {
++            UPDATE_0_CHECK;
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = 1 << kLenNumMidBits;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = 1 << kLenNumHighBits;
++          }
++        }
++        TREE_DECODE_CHECK(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state < 4)
++      {
++        unsigned posSlot;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++            kNumPosSlotBits);
++        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++
++          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
++
++          if (posSlot < kEndPosModelIndex)
++          {
++            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE_CHECK
++              range >>= 1;
++              code -= range & (((code - range) >> 31) - 1);
++              /* if (code >= range) code -= range; */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            numDirectBits = kNumAlignBits;
++          }
++          {
++            unsigned i = 1;
++            do
++            {
++              GET_BIT_CHECK(prob + i, i);
++            }
++            while (--numDirectBits != 0);
++          }
++        }
++      }
++    }
++  }
++  NORMALIZE_CHECK;
++  return res;
++}
++
++
++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
++{
++  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->range = 0xFFFFFFFF;
++  p->needFlush = 0;
++}
++
++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++{
++  p->needFlush = 1;
++  p->remainLen = 0;
++  p->tempBufSize = 0;
++
++  if (initDic)
++  {
++    p->processedPos = 0;
++    p->checkDicSize = 0;
++    p->needInitState = 1;
++  }
++  if (initState)
++    p->needInitState = 1;
++}
++
++void LzmaDec_Init(CLzmaDec *p)
++{
++  p->dicPos = 0;
++  LzmaDec_InitDicAndState(p, True, True);
++}
++
++static void LzmaDec_InitStateReal(CLzmaDec *p)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
++  UInt32 i;
++  CLzmaProb *probs = p->probs;
++  for (i = 0; i < numProbs; i++)
++    probs[i] = kBitModelTotal >> 1;
++  p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
++  p->state = 0;
++  p->needInitState = 0;
++}
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++    ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT inSize = *srcLen;
++  (*srcLen) = 0;
++  LzmaDec_WriteRem(p, dicLimit);
++  
++  *status = LZMA_STATUS_NOT_SPECIFIED;
++
++  while (p->remainLen != kMatchSpecLenStart)
++  {
++      int checkEndMarkNow;
++
++      if (p->needFlush != 0)
++      {
++        for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
++          p->tempBuf[p->tempBufSize++] = *src++;
++        if (p->tempBufSize < RC_INIT_SIZE)
++        {
++          *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++          return SZ_OK;
++        }
++        if (p->tempBuf[0] != 0)
++          return SZ_ERROR_DATA;
++
++        LzmaDec_InitRc(p, p->tempBuf);
++        p->tempBufSize = 0;
++      }
++
++      checkEndMarkNow = 0;
++      if (p->dicPos >= dicLimit)
++      {
++        if (p->remainLen == 0 && p->code == 0)
++        {
++          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
++          return SZ_OK;
++        }
++        if (finishMode == LZMA_FINISH_ANY)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_OK;
++        }
++        if (p->remainLen != 0)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_ERROR_DATA;
++        }
++        checkEndMarkNow = 1;
++      }
++
++      if (p->needInitState)
++        LzmaDec_InitStateReal(p);
++  
++      if (p->tempBufSize == 0)
++      {
++        SizeT processed;
++        const Byte *bufLimit;
++        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            memcpy(p->tempBuf, src, inSize);
++            p->tempBufSize = (unsigned)inSize;
++            (*srcLen) += inSize;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++          bufLimit = src;
++        }
++        else
++          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
++        p->buf = src;
++        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
++          return SZ_ERROR_DATA;
++        processed = (SizeT)(p->buf - src);
++        (*srcLen) += processed;
++        src += processed;
++        inSize -= processed;
++      }
++      else
++      {
++        unsigned rem = p->tempBufSize, lookAhead = 0;
++        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
++          p->tempBuf[rem++] = src[lookAhead++];
++        p->tempBufSize = rem;
++        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            (*srcLen) += lookAhead;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++        }
++        p->buf = p->tempBuf;
++        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
++          return SZ_ERROR_DATA;
++        lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
++        (*srcLen) += lookAhead;
++        src += lookAhead;
++        inSize -= lookAhead;
++        p->tempBufSize = 0;
++      }
++  }
++  if (p->code == 0)
++    *status = LZMA_STATUS_FINISHED_WITH_MARK;
++  return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
++}
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT outSize = *destLen;
++  SizeT inSize = *srcLen;
++  *srcLen = *destLen = 0;
++  for (;;)
++  {
++    SizeT inSizeCur = inSize, outSizeCur, dicPos;
++    ELzmaFinishMode curFinishMode;
++    SRes res;
++    if (p->dicPos == p->dicBufSize)
++      p->dicPos = 0;
++    dicPos = p->dicPos;
++    if (outSize > p->dicBufSize - dicPos)
++    {
++      outSizeCur = p->dicBufSize;
++      curFinishMode = LZMA_FINISH_ANY;
++    }
++    else
++    {
++      outSizeCur = dicPos + outSize;
++      curFinishMode = finishMode;
++    }
++
++    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
++    src += inSizeCur;
++    inSize -= inSizeCur;
++    *srcLen += inSizeCur;
++    outSizeCur = p->dicPos - dicPos;
++    memcpy(dest, p->dic + dicPos, outSizeCur);
++    dest += outSizeCur;
++    outSize -= outSizeCur;
++    *destLen += outSizeCur;
++    if (res != 0)
++      return res;
++    if (outSizeCur == 0 || outSize == 0)
++      return SZ_OK;
++  }
++}
++
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->probs);
++  p->probs = 0;
++}
++
++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->dic);
++  p->dic = 0;
++}
++
++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
++{
++  LzmaDec_FreeProbs(p, alloc);
++  LzmaDec_FreeDict(p, alloc);
++}
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++{
++  UInt32 dicSize;
++  Byte d;
++  
++  if (size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_UNSUPPORTED;
++  else
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++ 
++  if (dicSize < LZMA_DIC_MIN)
++    dicSize = LZMA_DIC_MIN;
++  p->dicSize = dicSize;
++
++  d = data[0];
++  if (d >= (9 * 5 * 5))
++    return SZ_ERROR_UNSUPPORTED;
++
++  p->lc = d % 9;
++  d /= 9;
++  p->pb = d / 5;
++  p->lp = d % 5;
++
++  return SZ_OK;
++}
++
++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
++{
++  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
++  if (p->probs == 0 || numProbs != p->numProbs)
++  {
++    LzmaDec_FreeProbs(p, alloc);
++    p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
++    p->numProbs = numProbs;
++    if (p->probs == 0)
++      return SZ_ERROR_MEM;
++  }
++  return SZ_OK;
++}
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  SizeT dicBufSize;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  dicBufSize = propNew.dicSize;
++  if (p->dic == 0 || dicBufSize != p->dicBufSize)
++  {
++    LzmaDec_FreeDict(p, alloc);
++    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
++    if (p->dic == 0)
++    {
++      LzmaDec_FreeProbs(p, alloc);
++      return SZ_ERROR_MEM;
++    }
++  }
++  p->dicBufSize = dicBufSize;
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc)
++{
++  CLzmaDec p;
++  SRes res;
++  SizeT inSize = *srcLen;
++  SizeT outSize = *destLen;
++  *srcLen = *destLen = 0;
++  if (inSize < RC_INIT_SIZE)
++    return SZ_ERROR_INPUT_EOF;
++
++  LzmaDec_Construct(&p);
++  res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
++  if (res != 0)
++    return res;
++  p.dic = dest;
++  p.dicBufSize = outSize;
++
++  LzmaDec_Init(&p);
++  
++  *srcLen = inSize;
++  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
++
++  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
++    res = SZ_ERROR_INPUT_EOF;
++
++  (*destLen) = p.dicPos;
++  LzmaDec_FreeProbs(&p, alloc);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/LzmaEnc.c
+@@ -0,0 +1,2271 @@
++/* LzmaEnc.c -- LZMA Encoder
++2009-11-24 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++/* #define SHOW_STAT */
++/* #define SHOW_STAT2 */
++
++#if defined(SHOW_STAT) || defined(SHOW_STAT2)
++#include <stdio.h>
++#endif
++
++#include "LzmaEnc.h"
++
++/* disable MT */
++#define _7ZIP_ST
++
++#include "LzFind.h"
++#ifndef _7ZIP_ST
++#include "LzFindMt.h"
++#endif
++
++#ifdef SHOW_STAT
++static int ttt = 0;
++#endif
++
++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
++
++#define kBlockSize (9 << 10)
++#define kUnpackBlockSize (1 << 18)
++#define kMatchArraySize (1 << 21)
++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
++
++#define kNumMaxDirectBits (31)
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++#define kProbInitValue (kBitModelTotal >> 1)
++
++#define kNumMoveReducingBits 4
++#define kNumBitPriceShiftBits 4
++#define kBitPrice (1 << kNumBitPriceShiftBits)
++
++void LzmaEncProps_Init(CLzmaEncProps *p)
++{
++  p->level = 5;
++  p->dictSize = p->mc = 0;
++  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
++  p->writeEndMark = 0;
++}
++
++void LzmaEncProps_Normalize(CLzmaEncProps *p)
++{
++  int level = p->level;
++  if (level < 0) level = 5;
++  p->level = level;
++  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
++  if (p->lc < 0) p->lc = 3;
++  if (p->lp < 0) p->lp = 0;
++  if (p->pb < 0) p->pb = 2;
++  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
++  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
++  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
++  if (p->numHashBytes < 0) p->numHashBytes = 4;
++  if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
++  if (p->numThreads < 0)
++    p->numThreads =
++      #ifndef _7ZIP_ST
++      ((p->btMode && p->algo) ? 2 : 1);
++      #else
++      1;
++      #endif
++}
++
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++{
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++  return props.dictSize;
++}
++
++/* #define LZMA_LOG_BSR */
++/* Define it for Intel's CPU */
++
++
++#ifdef LZMA_LOG_BSR
++
++#define kDicLogSizeMaxCompress 30
++
++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
++
++UInt32 GetPosSlot1(UInt32 pos)
++{
++  UInt32 res;
++  BSR2_RET(pos, res);
++  return res;
++}
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
++
++#else
++
++#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
++
++void LzmaEnc_FastPosInit(Byte *g_FastPos)
++{
++  int c = 2, slotFast;
++  g_FastPos[0] = 0;
++  g_FastPos[1] = 1;
++  
++  for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
++  {
++    UInt32 k = (1 << ((slotFast >> 1) - 1));
++    UInt32 j;
++    for (j = 0; j < k; j++, c++)
++      g_FastPos[c] = (Byte)slotFast;
++  }
++}
++
++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
++  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
++  res = p->g_FastPos[pos >> i] + (i * 2); }
++/*
++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
++  p->g_FastPos[pos >> 6] + 12 : \
++  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
++*/
++
++#define GetPosSlot1(pos) p->g_FastPos[pos]
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
++
++#endif
++
++
++#define LZMA_NUM_REPS 4
++
++typedef unsigned CState;
++
++typedef struct
++{
++  UInt32 price;
++
++  CState state;
++  int prev1IsChar;
++  int prev2;
++
++  UInt32 posPrev2;
++  UInt32 backPrev2;
++
++  UInt32 posPrev;
++  UInt32 backPrev;
++  UInt32 backs[LZMA_NUM_REPS];
++} COptimal;
++
++#define kNumOpts (1 << 12)
++
++#define kNumLenToPosStates 4
++#define kNumPosSlotBits 6
++#define kDicLogSizeMin 0
++#define kDicLogSizeMax 32
++#define kDistTableSizeMax (kDicLogSizeMax * 2)
++
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++#define kAlignMask (kAlignTableSize - 1)
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
++
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++#define LZMA_PB_MAX 4
++#define LZMA_LC_MAX 8
++#define LZMA_LP_MAX 4
++
++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
++
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define LZMA_MATCH_LEN_MIN 2
++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
++
++#define kNumStates 12
++
++typedef struct
++{
++  CLzmaProb choice;
++  CLzmaProb choice2;
++  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
++  CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
++  CLzmaProb high[kLenNumHighSymbols];
++} CLenEnc;
++
++typedef struct
++{
++  CLenEnc p;
++  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
++  UInt32 tableSize;
++  UInt32 counters[LZMA_NUM_PB_STATES_MAX];
++} CLenPriceEnc;
++
++typedef struct
++{
++  UInt32 range;
++  Byte cache;
++  UInt64 low;
++  UInt64 cacheSize;
++  Byte *buf;
++  Byte *bufLim;
++  Byte *bufBase;
++  ISeqOutStream *outStream;
++  UInt64 processed;
++  SRes res;
++} CRangeEnc;
++
++typedef struct
++{
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++} CSaveState;
++
++typedef struct
++{
++  IMatchFinder matchFinder;
++  void *matchFinderObj;
++
++  #ifndef _7ZIP_ST
++  Bool mtMode;
++  CMatchFinderMt matchFinderMt;
++  #endif
++
++  CMatchFinder matchFinderBase;
++
++  #ifndef _7ZIP_ST
++  Byte pad[128];
++  #endif
++  
++  UInt32 optimumEndIndex;
++  UInt32 optimumCurrentIndex;
++
++  UInt32 longestMatchLength;
++  UInt32 numPairs;
++  UInt32 numAvail;
++  COptimal opt[kNumOpts];
++  
++  #ifndef LZMA_LOG_BSR
++  Byte g_FastPos[1 << kNumLogBits];
++  #endif
++
++  UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
++  UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
++  UInt32 numFastBytes;
++  UInt32 additionalOffset;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++
++  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
++  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
++  UInt32 alignPrices[kAlignTableSize];
++  UInt32 alignPriceCount;
++
++  UInt32 distTableSize;
++
++  unsigned lc, lp, pb;
++  unsigned lpMask, pbMask;
++
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  unsigned lclp;
++
++  Bool fastMode;
++  
++  CRangeEnc rc;
++
++  Bool writeEndMark;
++  UInt64 nowPos64;
++  UInt32 matchPriceCount;
++  Bool finished;
++  Bool multiThread;
++
++  SRes result;
++  UInt32 dictSize;
++  UInt32 matchFinderCycles;
++
++  int needInit;
++
++  CSaveState saveState;
++} CLzmaEnc;
++
++void LzmaEnc_SaveState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CSaveState *dest = &p->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
++}
++
++void LzmaEnc_RestoreState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *dest = (CLzmaEnc *)pp;
++  const CSaveState *p = &dest->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
++}
++
++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++
++  if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
++      props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
++    return SZ_ERROR_PARAM;
++  p->dictSize = props.dictSize;
++  p->matchFinderCycles = props.mc;
++  {
++    unsigned fb = props.fb;
++    if (fb < 5)
++      fb = 5;
++    if (fb > LZMA_MATCH_LEN_MAX)
++      fb = LZMA_MATCH_LEN_MAX;
++    p->numFastBytes = fb;
++  }
++  p->lc = props.lc;
++  p->lp = props.lp;
++  p->pb = props.pb;
++  p->fastMode = (props.algo == 0);
++  p->matchFinderBase.btMode = props.btMode;
++  {
++    UInt32 numHashBytes = 4;
++    if (props.btMode)
++    {
++      if (props.numHashBytes < 2)
++        numHashBytes = 2;
++      else if (props.numHashBytes < 4)
++        numHashBytes = props.numHashBytes;
++    }
++    p->matchFinderBase.numHashBytes = numHashBytes;
++  }
++
++  p->matchFinderBase.cutValue = props.mc;
++
++  p->writeEndMark = props.writeEndMark;
++
++  #ifndef _7ZIP_ST
++  /*
++  if (newMultiThread != _multiThread)
++  {
++    ReleaseMatchFinder();
++    _multiThread = newMultiThread;
++  }
++  */
++  p->multiThread = (props.numThreads > 1);
++  #endif
++
++  return SZ_OK;
++}
++
++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
++static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
++static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
++
++#define IsCharState(s) ((s) < 7)
++
++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
++
++#define kInfinityPrice (1 << 30)
++
++static void RangeEnc_Construct(CRangeEnc *p)
++{
++  p->outStream = 0;
++  p->bufBase = 0;
++}
++
++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
++
++#define RC_BUF_SIZE (1 << 16)
++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
++{
++  if (p->bufBase == 0)
++  {
++    p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
++    if (p->bufBase == 0)
++      return 0;
++    p->bufLim = p->bufBase + RC_BUF_SIZE;
++  }
++  return 1;
++}
++
++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->bufBase);
++  p->bufBase = 0;
++}
++
++static void RangeEnc_Init(CRangeEnc *p)
++{
++  /* Stream.Init(); */
++  p->low = 0;
++  p->range = 0xFFFFFFFF;
++  p->cacheSize = 1;
++  p->cache = 0;
++
++  p->buf = p->bufBase;
++
++  p->processed = 0;
++  p->res = SZ_OK;
++}
++
++static void RangeEnc_FlushStream(CRangeEnc *p)
++{
++  size_t num;
++  if (p->res != SZ_OK)
++    return;
++  num = p->buf - p->bufBase;
++  if (num != p->outStream->Write(p->outStream, p->bufBase, num))
++    p->res = SZ_ERROR_WRITE;
++  p->processed += num;
++  p->buf = p->bufBase;
++}
++
++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
++{
++  if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
++  {
++    Byte temp = p->cache;
++    do
++    {
++      Byte *buf = p->buf;
++      *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
++      p->buf = buf;
++      if (buf == p->bufLim)
++        RangeEnc_FlushStream(p);
++      temp = 0xFF;
++    }
++    while (--p->cacheSize != 0);
++    p->cache = (Byte)((UInt32)p->low >> 24);
++  }
++  p->cacheSize++;
++  p->low = (UInt32)p->low << 8;
++}
++
++static void RangeEnc_FlushData(CRangeEnc *p)
++{
++  int i;
++  for (i = 0; i < 5; i++)
++    RangeEnc_ShiftLow(p);
++}
++
++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
++{
++  do
++  {
++    p->range >>= 1;
++    p->low += p->range & (0 - ((value >> --numBits) & 1));
++    if (p->range < kTopValue)
++    {
++      p->range <<= 8;
++      RangeEnc_ShiftLow(p);
++    }
++  }
++  while (numBits != 0);
++}
++
++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
++{
++  UInt32 ttt = *prob;
++  UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
++  if (symbol == 0)
++  {
++    p->range = newBound;
++    ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
++  }
++  else
++  {
++    p->low += newBound;
++    p->range -= newBound;
++    ttt -= ttt >> kNumMoveBits;
++  }
++  *prob = (CLzmaProb)ttt;
++  if (p->range < kTopValue)
++  {
++    p->range <<= 8;
++    RangeEnc_ShiftLow(p);
++  }
++}
++
++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
++{
++  symbol |= 0x100;
++  do
++  {
++    RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++}
++
++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
++{
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++}
++
++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++{
++  UInt32 i;
++  for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
++  {
++    const int kCyclesBits = kNumBitPriceShiftBits;
++    UInt32 w = i;
++    UInt32 bitCount = 0;
++    int j;
++    for (j = 0; j < kCyclesBits; j++)
++    {
++      w = w * w;
++      bitCount <<= 1;
++      while (w >= ((UInt32)1 << 16))
++      {
++        w >>= 1;
++        bitCount++;
++      }
++    }
++    ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
++  }
++}
++
++
++#define GET_PRICE(prob, symbol) \
++  p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICEa(prob, symbol) \
++  ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= 0x100;
++  do
++  {
++    price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++
++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0;)
++  {
++    UInt32 bit;
++    i--;
++    bit = (symbol >> i) & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++  }
++}
++
++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = 0; i < numBitLevels; i++)
++  {
++    UInt32 bit = symbol & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++    symbol >>= 1;
++  }
++}
++
++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= (1 << numBitLevels);
++  while (symbol != 1)
++  {
++    price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
++    symbol >>= 1;
++  }
++  return price;
++}
++
++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0; i--)
++  {
++    UInt32 bit = symbol & 1;
++    symbol >>= 1;
++    price += GET_PRICEa(probs[m], bit);
++    m = (m << 1) | bit;
++  }
++  return price;
++}
++
++
++static void LenEnc_Init(CLenEnc *p)
++{
++  unsigned i;
++  p->choice = p->choice2 = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
++    p->low[i] = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
++    p->mid[i] = kProbInitValue;
++  for (i = 0; i < kLenNumHighSymbols; i++)
++    p->high[i] = kProbInitValue;
++}
++
++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
++{
++  if (symbol < kLenNumLowSymbols)
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 0);
++    RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
++  }
++  else
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 1);
++    if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 0);
++      RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
++    }
++    else
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 1);
++      RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
++    }
++  }
++}
++
++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
++{
++  UInt32 a0 = GET_PRICE_0a(p->choice);
++  UInt32 a1 = GET_PRICE_1a(p->choice);
++  UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
++  UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
++  UInt32 i = 0;
++  for (i = 0; i < kLenNumLowSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
++  }
++  for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
++  }
++  for (; i < numSymbols; i++)
++    prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
++}
++
++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
++{
++  LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
++  p->counters[posState] = p->tableSize;
++}
++
++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
++{
++  UInt32 posState;
++  for (posState = 0; posState < numPosStates; posState++)
++    LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
++{
++  LenEnc_Encode(&p->p, rc, symbol, posState);
++  if (updatePrice)
++    if (--p->counters[posState] == 0)
++      LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++
++
++
++static void MovePos(CLzmaEnc *p, UInt32 num)
++{
++  #ifdef SHOW_STAT
++  ttt += num;
++  printf("\n MovePos %d", num);
++  #endif
++  if (num != 0)
++  {
++    p->additionalOffset += num;
++    p->matchFinder.Skip(p->matchFinderObj, num);
++  }
++}
++
++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
++{
++  UInt32 lenRes = 0, numPairs;
++  p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++  numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
++  #ifdef SHOW_STAT
++  printf("\n i = %d numPairs = %d    ", ttt, numPairs / 2);
++  ttt++;
++  {
++    UInt32 i;
++    for (i = 0; i < numPairs; i += 2)
++      printf("%2d %6d   | ", p->matches[i], p->matches[i + 1]);
++  }
++  #endif
++  if (numPairs > 0)
++  {
++    lenRes = p->matches[numPairs - 2];
++    if (lenRes == p->numFastBytes)
++    {
++      const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++      UInt32 distance = p->matches[numPairs - 1] + 1;
++      UInt32 numAvail = p->numAvail;
++      if (numAvail > LZMA_MATCH_LEN_MAX)
++        numAvail = LZMA_MATCH_LEN_MAX;
++      {
++        const Byte *pby2 = pby - distance;
++        for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
++      }
++    }
++  }
++  p->additionalOffset++;
++  *numDistancePairsRes = numPairs;
++  return lenRes;
++}
++
++
++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
++#define IsShortRep(p) ((p)->backPrev == 0)
++
++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
++{
++  return
++    GET_PRICE_0(p->isRepG0[state]) +
++    GET_PRICE_0(p->isRep0Long[state][posState]);
++}
++
++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
++{
++  UInt32 price;
++  if (repIndex == 0)
++  {
++    price = GET_PRICE_0(p->isRepG0[state]);
++    price += GET_PRICE_1(p->isRep0Long[state][posState]);
++  }
++  else
++  {
++    price = GET_PRICE_1(p->isRepG0[state]);
++    if (repIndex == 1)
++      price += GET_PRICE_0(p->isRepG1[state]);
++    else
++    {
++      price += GET_PRICE_1(p->isRepG1[state]);
++      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
++    }
++  }
++  return price;
++}
++
++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
++{
++  return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
++    GetPureRepPrice(p, repIndex, state, posState);
++}
++
++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
++{
++  UInt32 posMem = p->opt[cur].posPrev;
++  UInt32 backMem = p->opt[cur].backPrev;
++  p->optimumEndIndex = cur;
++  do
++  {
++    if (p->opt[cur].prev1IsChar)
++    {
++      MakeAsChar(&p->opt[posMem])
++      p->opt[posMem].posPrev = posMem - 1;
++      if (p->opt[cur].prev2)
++      {
++        p->opt[posMem - 1].prev1IsChar = False;
++        p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
++        p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
++      }
++    }
++    {
++      UInt32 posPrev = posMem;
++      UInt32 backCur = backMem;
++      
++      backMem = p->opt[posPrev].backPrev;
++      posMem = p->opt[posPrev].posPrev;
++      
++      p->opt[posPrev].backPrev = backCur;
++      p->opt[posPrev].posPrev = cur;
++      cur = posPrev;
++    }
++  }
++  while (cur != 0);
++  *backRes = p->opt[0].backPrev;
++  p->optimumCurrentIndex  = p->opt[0].posPrev;
++  return p->optimumCurrentIndex;
++}
++
++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
++
++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
++  UInt32 matchPrice, repMatchPrice, normalMatchPrice;
++  UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
++  UInt32 *matches;
++  const Byte *data;
++  Byte curByte, matchByte;
++  if (p->optimumEndIndex != p->optimumCurrentIndex)
++  {
++    const COptimal *opt = &p->opt[p->optimumCurrentIndex];
++    UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
++    *backRes = opt->backPrev;
++    p->optimumCurrentIndex = opt->posPrev;
++    return lenRes;
++  }
++  p->optimumCurrentIndex = p->optimumEndIndex = 0;
++  
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  if (numAvail < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  repMaxIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 lenTest;
++    const Byte *data2;
++    reps[i] = p->reps[i];
++    data2 = data - (reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++    repLens[i] = lenTest;
++    if (lenTest > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  if (repLens[repMaxIndex] >= p->numFastBytes)
++  {
++    UInt32 lenRes;
++    *backRes = repMaxIndex;
++    lenRes = repLens[repMaxIndex];
++    MovePos(p, lenRes - 1);
++    return lenRes;
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++  curByte = *data;
++  matchByte = *(data - (reps[0] + 1));
++
++  if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
++  {
++    *backRes = (UInt32)-1;
++    return 1;
++  }
++
++  p->opt[0].state = (CState)p->state;
++
++  posState = (position & p->pbMask);
++
++  {
++    const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++    p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
++        (!IsCharState(p->state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++  }
++
++  MakeAsChar(&p->opt[1]);
++
++  matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
++  repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
++
++  if (matchByte == curByte)
++  {
++    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
++    if (shortRepPrice < p->opt[1].price)
++    {
++      p->opt[1].price = shortRepPrice;
++      MakeAsShortRep(&p->opt[1]);
++    }
++  }
++  lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
++
++  if (lenEnd < 2)
++  {
++    *backRes = p->opt[1].backPrev;
++    return 1;
++  }
++
++  p->opt[1].posPrev = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++    p->opt[0].backs[i] = reps[i];
++
++  len = lenEnd;
++  do
++    p->opt[len--].price = kInfinityPrice;
++  while (len >= 2);
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 repLen = repLens[i];
++    UInt32 price;
++    if (repLen < 2)
++      continue;
++    price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
++    do
++    {
++      UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
++      COptimal *opt = &p->opt[repLen];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = i;
++        opt->prev1IsChar = False;
++      }
++    }
++    while (--repLen >= 2);
++  }
++
++  normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
++
++  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
++  if (len <= mainLen)
++  {
++    UInt32 offs = 0;
++    while (len > matches[offs])
++      offs += 2;
++    for (; ; len++)
++    {
++      COptimal *opt;
++      UInt32 distance = matches[offs + 1];
++
++      UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
++      UInt32 lenToPosState = GetLenToPosState(len);
++      if (distance < kNumFullDistances)
++        curAndLenPrice += p->distancesPrices[lenToPosState][distance];
++      else
++      {
++        UInt32 slot;
++        GetPosSlot2(distance, slot);
++        curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
++      }
++      opt = &p->opt[len];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = distance + LZMA_NUM_REPS;
++        opt->prev1IsChar = False;
++      }
++      if (len == matches[offs])
++      {
++        offs += 2;
++        if (offs == numPairs)
++          break;
++      }
++    }
++  }
++
++  cur = 0;
++
++    #ifdef SHOW_STAT2
++    if (position >= 0)
++    {
++      unsigned i;
++      printf("\n pos = %4X", position);
++      for (i = cur; i <= lenEnd; i++)
++      printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
++    }
++    #endif
++
++  for (;;)
++  {
++    UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
++    UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
++    Bool nextIsChar;
++    Byte curByte, matchByte;
++    const Byte *data;
++    COptimal *curOpt;
++    COptimal *nextOpt;
++
++    cur++;
++    if (cur == lenEnd)
++      return Backward(p, backRes, cur);
++
++    newLen = ReadMatchDistances(p, &numPairs);
++    if (newLen >= p->numFastBytes)
++    {
++      p->numPairs = numPairs;
++      p->longestMatchLength = newLen;
++      return Backward(p, backRes, cur);
++    }
++    position++;
++    curOpt = &p->opt[cur];
++    posPrev = curOpt->posPrev;
++    if (curOpt->prev1IsChar)
++    {
++      posPrev--;
++      if (curOpt->prev2)
++      {
++        state = p->opt[curOpt->posPrev2].state;
++        if (curOpt->backPrev2 < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      else
++        state = p->opt[posPrev].state;
++      state = kLiteralNextStates[state];
++    }
++    else
++      state = p->opt[posPrev].state;
++    if (posPrev == cur - 1)
++    {
++      if (IsShortRep(curOpt))
++        state = kShortRepNextStates[state];
++      else
++        state = kLiteralNextStates[state];
++    }
++    else
++    {
++      UInt32 pos;
++      const COptimal *prevOpt;
++      if (curOpt->prev1IsChar && curOpt->prev2)
++      {
++        posPrev = curOpt->posPrev2;
++        pos = curOpt->backPrev2;
++        state = kRepNextStates[state];
++      }
++      else
++      {
++        pos = curOpt->backPrev;
++        if (pos < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      prevOpt = &p->opt[posPrev];
++      if (pos < LZMA_NUM_REPS)
++      {
++        UInt32 i;
++        reps[0] = prevOpt->backs[pos];
++        for (i = 1; i <= pos; i++)
++          reps[i] = prevOpt->backs[i - 1];
++        for (; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i];
++      }
++      else
++      {
++        UInt32 i;
++        reps[0] = (pos - LZMA_NUM_REPS);
++        for (i = 1; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i - 1];
++      }
++    }
++    curOpt->state = (CState)state;
++
++    curOpt->backs[0] = reps[0];
++    curOpt->backs[1] = reps[1];
++    curOpt->backs[2] = reps[2];
++    curOpt->backs[3] = reps[3];
++
++    curPrice = curOpt->price;
++    nextIsChar = False;
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    curByte = *data;
++    matchByte = *(data - (reps[0] + 1));
++
++    posState = (position & p->pbMask);
++
++    curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
++    {
++      const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++      curAnd1Price +=
++        (!IsCharState(state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++    }
++
++    nextOpt = &p->opt[cur + 1];
++
++    if (curAnd1Price < nextOpt->price)
++    {
++      nextOpt->price = curAnd1Price;
++      nextOpt->posPrev = cur;
++      MakeAsChar(nextOpt);
++      nextIsChar = True;
++    }
++
++    matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
++    repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
++    
++    if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
++    {
++      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
++      if (shortRepPrice <= nextOpt->price)
++      {
++        nextOpt->price = shortRepPrice;
++        nextOpt->posPrev = cur;
++        MakeAsShortRep(nextOpt);
++        nextIsChar = True;
++      }
++    }
++    numAvailFull = p->numAvail;
++    {
++      UInt32 temp = kNumOpts - 1 - cur;
++      if (temp < numAvailFull)
++        numAvailFull = temp;
++    }
++
++    if (numAvailFull < 2)
++      continue;
++    numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
++
++    if (!nextIsChar && matchByte != curByte) /* speed optimization */
++    {
++      /* try Literal + rep0 */
++      UInt32 temp;
++      UInt32 lenTest2;
++      const Byte *data2 = data - (reps[0] + 1);
++      UInt32 limit = p->numFastBytes + 1;
++      if (limit > numAvailFull)
++        limit = numAvailFull;
++
++      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
++      lenTest2 = temp - 1;
++      if (lenTest2 >= 2)
++      {
++        UInt32 state2 = kLiteralNextStates[state];
++        UInt32 posStateNext = (position + 1) & p->pbMask;
++        UInt32 nextRepMatchPrice = curAnd1Price +
++            GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++            GET_PRICE_1(p->isRep[state2]);
++        /* for (; lenTest2 >= 2; lenTest2--) */
++        {
++          UInt32 curAndLenPrice;
++          COptimal *opt;
++          UInt32 offset = cur + 1 + lenTest2;
++          while (lenEnd < offset)
++            p->opt[++lenEnd].price = kInfinityPrice;
++          curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++          opt = &p->opt[offset];
++          if (curAndLenPrice < opt->price)
++          {
++            opt->price = curAndLenPrice;
++            opt->posPrev = cur + 1;
++            opt->backPrev = 0;
++            opt->prev1IsChar = True;
++            opt->prev2 = False;
++          }
++        }
++      }
++    }
++    
++    startLen = 2; /* speed optimization */
++    {
++    UInt32 repIndex;
++    for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
++    {
++      UInt32 lenTest;
++      UInt32 lenTestTemp;
++      UInt32 price;
++      const Byte *data2 = data - (reps[repIndex] + 1);
++      if (data[0] != data2[0] || data[1] != data2[1])
++        continue;
++      for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++      while (lenEnd < cur + lenTest)
++        p->opt[++lenEnd].price = kInfinityPrice;
++      lenTestTemp = lenTest;
++      price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
++      do
++      {
++        UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
++        COptimal *opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = repIndex;
++          opt->prev1IsChar = False;
++        }
++      }
++      while (--lenTest >= 2);
++      lenTest = lenTestTemp;
++      
++      if (repIndex == 0)
++        startLen = lenTest + 1;
++        
++      /* if (_maxMode) */
++        {
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kRepNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice =
++                price + p->repLenEnc.prices[posState][lenTest - 2] +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (position + lenTest + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = repIndex;
++              }
++            }
++          }
++        }
++    }
++    }
++    /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
++    if (newLen > numAvail)
++    {
++      newLen = numAvail;
++      for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
++      matches[numPairs] = newLen;
++      numPairs += 2;
++    }
++    if (newLen >= startLen)
++    {
++      UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
++      UInt32 offs, curBack, posSlot;
++      UInt32 lenTest;
++      while (lenEnd < cur + newLen)
++        p->opt[++lenEnd].price = kInfinityPrice;
++
++      offs = 0;
++      while (startLen > matches[offs])
++        offs += 2;
++      curBack = matches[offs + 1];
++      GetPosSlot2(curBack, posSlot);
++      for (lenTest = /*2*/ startLen; ; lenTest++)
++      {
++        UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
++        UInt32 lenToPosState = GetLenToPosState(lenTest);
++        COptimal *opt;
++        if (curBack < kNumFullDistances)
++          curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
++        else
++          curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
++        
++        opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = curBack + LZMA_NUM_REPS;
++          opt->prev1IsChar = False;
++        }
++
++        if (/*_maxMode && */lenTest == matches[offs])
++        {
++          /* Try Match + Literal + Rep0 */
++          const Byte *data2 = data - (curBack + 1);
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kMatchNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = curAndLenPrice +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (posStateNext + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = curBack + LZMA_NUM_REPS;
++              }
++            }
++          }
++          offs += 2;
++          if (offs == numPairs)
++            break;
++          curBack = matches[offs + 1];
++          if (curBack >= kNumFullDistances)
++            GetPosSlot2(curBack, posSlot);
++        }
++      }
++    }
++  }
++}
++
++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
++
++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
++  const Byte *data;
++  const UInt32 *matches;
++
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  *backRes = (UInt32)-1;
++  if (numAvail < 2)
++    return 1;
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++
++  repLen = repIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    for (len = 2; len < numAvail && data[len] == data2[len]; len++);
++    if (len >= p->numFastBytes)
++    {
++      *backRes = i;
++      MovePos(p, len - 1);
++      return len;
++    }
++    if (len > repLen)
++    {
++      repIndex = i;
++      repLen = len;
++    }
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++
++  mainDist = 0; /* for GCC */
++  if (mainLen >= 2)
++  {
++    mainDist = matches[numPairs - 1];
++    while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
++    {
++      if (!ChangePair(matches[numPairs - 3], mainDist))
++        break;
++      numPairs -= 2;
++      mainLen = matches[numPairs - 2];
++      mainDist = matches[numPairs - 1];
++    }
++    if (mainLen == 2 && mainDist >= 0x80)
++      mainLen = 1;
++  }
++
++  if (repLen >= 2 && (
++        (repLen + 1 >= mainLen) ||
++        (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
++        (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
++  {
++    *backRes = repIndex;
++    MovePos(p, repLen - 1);
++    return repLen;
++  }
++  
++  if (mainLen < 2 || numAvail <= 2)
++    return 1;
++
++  p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
++  if (p->longestMatchLength >= 2)
++  {
++    UInt32 newDistance = matches[p->numPairs - 1];
++    if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
++        (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
++        (p->longestMatchLength > mainLen + 1) ||
++        (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
++      return 1;
++  }
++  
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len, limit;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    limit = mainLen - 1;
++    for (len = 2; len < limit && data[len] == data2[len]; len++);
++    if (len >= limit)
++      return 1;
++  }
++  *backRes = mainDist + LZMA_NUM_REPS;
++  MovePos(p, mainLen - 2);
++  return mainLen;
++}
++
++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
++{
++  UInt32 len;
++  RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++  RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++  p->state = kMatchNextStates[p->state];
++  len = LZMA_MATCH_LEN_MIN;
++  LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++  RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
++  RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
++  RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
++}
++
++static SRes CheckErrors(CLzmaEnc *p)
++{
++  if (p->result != SZ_OK)
++    return p->result;
++  if (p->rc.res != SZ_OK)
++    p->result = SZ_ERROR_WRITE;
++  if (p->matchFinderBase.result != SZ_OK)
++    p->result = SZ_ERROR_READ;
++  if (p->result != SZ_OK)
++    p->finished = True;
++  return p->result;
++}
++
++static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
++{
++  /* ReleaseMFStream(); */
++  p->finished = True;
++  if (p->writeEndMark)
++    WriteEndMarker(p, nowPos & p->pbMask);
++  RangeEnc_FlushData(&p->rc);
++  RangeEnc_FlushStream(&p->rc);
++  return CheckErrors(p);
++}
++
++static void FillAlignPrices(CLzmaEnc *p)
++{
++  UInt32 i;
++  for (i = 0; i < kAlignTableSize; i++)
++    p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
++  p->alignPriceCount = 0;
++}
++
++static void FillDistancesPrices(CLzmaEnc *p)
++{
++  UInt32 tempPrices[kNumFullDistances];
++  UInt32 i, lenToPosState;
++  for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
++  {
++    UInt32 posSlot = GetPosSlot1(i);
++    UInt32 footerBits = ((posSlot >> 1) - 1);
++    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++    tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
++  }
++
++  for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
++  {
++    UInt32 posSlot;
++    const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
++    UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
++    for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
++    for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
++
++    {
++      UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
++      UInt32 i;
++      for (i = 0; i < kStartPosModelIndex; i++)
++        distancesPrices[i] = posSlotPrices[i];
++      for (; i < kNumFullDistances; i++)
++        distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
++    }
++  }
++  p->matchPriceCount = 0;
++}
++
++void LzmaEnc_Construct(CLzmaEnc *p)
++{
++  RangeEnc_Construct(&p->rc);
++  MatchFinder_Construct(&p->matchFinderBase);
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Construct(&p->matchFinderMt);
++  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
++  #endif
++
++  {
++    CLzmaEncProps props;
++    LzmaEncProps_Init(&props);
++    LzmaEnc_SetProps(p, &props);
++  }
++
++  #ifndef LZMA_LOG_BSR
++  LzmaEnc_FastPosInit(p->g_FastPos);
++  #endif
++
++  LzmaEnc_InitPriceTables(p->ProbPrices);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
++{
++  void *p;
++  p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
++  if (p != 0)
++    LzmaEnc_Construct((CLzmaEnc *)p);
++  return p;
++}
++
++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->litProbs);
++  alloc->Free(alloc, p->saveState.litProbs);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
++  #endif
++  MatchFinder_Free(&p->matchFinderBase, allocBig);
++  LzmaEnc_FreeLits(p, alloc);
++  RangeEnc_Free(&p->rc, alloc);
++}
++
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
++  alloc->Free(alloc, p);
++}
++
++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
++{
++  UInt32 nowPos32, startPos32;
++  if (p->needInit)
++  {
++    p->matchFinder.Init(p->matchFinderObj);
++    p->needInit = 0;
++  }
++
++  if (p->finished)
++    return p->result;
++  RINOK(CheckErrors(p));
++
++  nowPos32 = (UInt32)p->nowPos64;
++  startPos32 = nowPos32;
++
++  if (p->nowPos64 == 0)
++  {
++    UInt32 numPairs;
++    Byte curByte;
++    if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++      return Flush(p, nowPos32);
++    ReadMatchDistances(p, &numPairs);
++    RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
++    p->state = kLiteralNextStates[p->state];
++    curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
++    LitEnc_Encode(&p->rc, p->litProbs, curByte);
++    p->additionalOffset--;
++    nowPos32++;
++  }
++
++  if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
++  for (;;)
++  {
++    UInt32 pos, len, posState;
++
++    if (p->fastMode)
++      len = GetOptimumFast(p, &pos);
++    else
++      len = GetOptimum(p, nowPos32, &pos);
++
++    #ifdef SHOW_STAT2
++    printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
++    #endif
++
++    posState = nowPos32 & p->pbMask;
++    if (len == 1 && pos == (UInt32)-1)
++    {
++      Byte curByte;
++      CLzmaProb *probs;
++      const Byte *data;
++
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
++      data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++      curByte = *data;
++      probs = LIT_PROBS(nowPos32, *(data - 1));
++      if (IsCharState(p->state))
++        LitEnc_Encode(&p->rc, probs, curByte);
++      else
++        LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
++      p->state = kLiteralNextStates[p->state];
++    }
++    else
++    {
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++      if (pos < LZMA_NUM_REPS)
++      {
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
++        if (pos == 0)
++        {
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
++          RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
++        }
++        else
++        {
++          UInt32 distance = p->reps[pos];
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
++          if (pos == 1)
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
++          else
++          {
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
++            if (pos == 3)
++              p->reps[3] = p->reps[2];
++            p->reps[2] = p->reps[1];
++          }
++          p->reps[1] = p->reps[0];
++          p->reps[0] = distance;
++        }
++        if (len == 1)
++          p->state = kShortRepNextStates[p->state];
++        else
++        {
++          LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++          p->state = kRepNextStates[p->state];
++        }
++      }
++      else
++      {
++        UInt32 posSlot;
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++        p->state = kMatchNextStates[p->state];
++        LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++        pos -= LZMA_NUM_REPS;
++        GetPosSlot(pos, posSlot);
++        RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
++        
++        if (posSlot >= kStartPosModelIndex)
++        {
++          UInt32 footerBits = ((posSlot >> 1) - 1);
++          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++          UInt32 posReduced = pos - base;
++
++          if (posSlot < kEndPosModelIndex)
++            RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
++          else
++          {
++            RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
++            RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
++            p->alignPriceCount++;
++          }
++        }
++        p->reps[3] = p->reps[2];
++        p->reps[2] = p->reps[1];
++        p->reps[1] = p->reps[0];
++        p->reps[0] = pos;
++        p->matchPriceCount++;
++      }
++    }
++    p->additionalOffset -= len;
++    nowPos32 += len;
++    if (p->additionalOffset == 0)
++    {
++      UInt32 processed;
++      if (!p->fastMode)
++      {
++        if (p->matchPriceCount >= (1 << 7))
++          FillDistancesPrices(p);
++        if (p->alignPriceCount >= kAlignTableSize)
++          FillAlignPrices(p);
++      }
++      if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++        break;
++      processed = nowPos32 - startPos32;
++      if (useLimits)
++      {
++        if (processed + kNumOpts + 300 >= maxUnpackSize ||
++            RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
++          break;
++      }
++      else if (processed >= (1 << 15))
++      {
++        p->nowPos64 += nowPos32 - startPos32;
++        return CheckErrors(p);
++      }
++    }
++  }
++  p->nowPos64 += nowPos32 - startPos32;
++  return Flush(p, nowPos32);
++}
++
++#define kBigHashDicLimit ((UInt32)1 << 24)
++
++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 beforeSize = kNumOpts;
++  Bool btMode;
++  if (!RangeEnc_Alloc(&p->rc, alloc))
++    return SZ_ERROR_MEM;
++  btMode = (p->matchFinderBase.btMode != 0);
++  #ifndef _7ZIP_ST
++  p->mtMode = (p->multiThread && !p->fastMode && btMode);
++  #endif
++
++  {
++    unsigned lclp = p->lc + p->lp;
++    if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
++    {
++      LzmaEnc_FreeLits(p, alloc);
++      p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      if (p->litProbs == 0 || p->saveState.litProbs == 0)
++      {
++        LzmaEnc_FreeLits(p, alloc);
++        return SZ_ERROR_MEM;
++      }
++      p->lclp = lclp;
++    }
++  }
++
++  p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
++
++  if (beforeSize + p->dictSize < keepWindowSize)
++    beforeSize = keepWindowSize - p->dictSize;
++
++  #ifndef _7ZIP_ST
++  if (p->mtMode)
++  {
++    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
++    p->matchFinderObj = &p->matchFinderMt;
++    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
++  }
++  else
++  #endif
++  {
++    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
++      return SZ_ERROR_MEM;
++    p->matchFinderObj = &p->matchFinderBase;
++    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
++  }
++  return SZ_OK;
++}
++
++void LzmaEnc_Init(CLzmaEnc *p)
++{
++  UInt32 i;
++  p->state = 0;
++  for (i = 0 ; i < LZMA_NUM_REPS; i++)
++    p->reps[i] = 0;
++
++  RangeEnc_Init(&p->rc);
++
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    UInt32 j;
++    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
++    {
++      p->isMatch[i][j] = kProbInitValue;
++      p->isRep0Long[i][j] = kProbInitValue;
++    }
++    p->isRep[i] = kProbInitValue;
++    p->isRepG0[i] = kProbInitValue;
++    p->isRepG1[i] = kProbInitValue;
++    p->isRepG2[i] = kProbInitValue;
++  }
++
++  {
++    UInt32 num = 0x300 << (p->lp + p->lc);
++    for (i = 0; i < num; i++)
++      p->litProbs[i] = kProbInitValue;
++  }
++
++  {
++    for (i = 0; i < kNumLenToPosStates; i++)
++    {
++      CLzmaProb *probs = p->posSlotEncoder[i];
++      UInt32 j;
++      for (j = 0; j < (1 << kNumPosSlotBits); j++)
++        probs[j] = kProbInitValue;
++    }
++  }
++  {
++    for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
++      p->posEncoders[i] = kProbInitValue;
++  }
++
++  LenEnc_Init(&p->lenEnc.p);
++  LenEnc_Init(&p->repLenEnc.p);
++
++  for (i = 0; i < (1 << kNumAlignBits); i++)
++    p->posAlignEncoder[i] = kProbInitValue;
++
++  p->optimumEndIndex = 0;
++  p->optimumCurrentIndex = 0;
++  p->additionalOffset = 0;
++
++  p->pbMask = (1 << p->pb) - 1;
++  p->lpMask = (1 << p->lp) - 1;
++}
++
++void LzmaEnc_InitPrices(CLzmaEnc *p)
++{
++  if (!p->fastMode)
++  {
++    FillDistancesPrices(p);
++    FillAlignPrices(p);
++  }
++
++  p->lenEnc.tableSize =
++  p->repLenEnc.tableSize =
++      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
++  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
++  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
++}
++
++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 i;
++  for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
++    if (p->dictSize <= ((UInt32)1 << i))
++      break;
++  p->distTableSize = i * 2;
++
++  p->finished = False;
++  p->result = SZ_OK;
++  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
++  LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  p->nowPos64 = 0;
++  return SZ_OK;
++}
++
++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  p->rc.outStream = outStream;
++  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
++}
++
++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
++    ISeqInStream *inStream, UInt32 keepWindowSize,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
++{
++  p->matchFinderBase.directInput = 1;
++  p->matchFinderBase.bufferBase = (Byte *)src;
++  p->matchFinderBase.directInputRem = srcLen;
++}
++
++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++    UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++  p->needInit = 1;
++
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++void LzmaEnc_Finish(CLzmaEncHandle pp)
++{
++  #ifndef _7ZIP_ST
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  if (p->mtMode)
++    MatchFinderMt_ReleaseStream(&p->matchFinderMt);
++  #else
++  pp = pp;
++  #endif
++}
++
++typedef struct
++{
++  ISeqOutStream funcTable;
++  Byte *data;
++  SizeT rem;
++  Bool overflow;
++} CSeqOutStreamBuf;
++
++static size_t MyWrite(void *pp, const void *data, size_t size)
++{
++  CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
++  if (p->rem < size)
++  {
++    size = p->rem;
++    p->overflow = True;
++  }
++  memcpy(p->data, data, size);
++  p->rem -= size;
++  p->data += size;
++  return size;
++}
++
++
++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++}
++
++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++}
++
++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
++    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  UInt64 nowPos64;
++  SRes res;
++  CSeqOutStreamBuf outStream;
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = False;
++  p->finished = False;
++  p->result = SZ_OK;
++
++  if (reInit)
++    LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  nowPos64 = p->nowPos64;
++  RangeEnc_Init(&p->rc);
++  p->rc.outStream = &outStream.funcTable;
++
++  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
++  
++  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++
++  return res;
++}
++
++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
++{
++  SRes res = SZ_OK;
++
++  #ifndef _7ZIP_ST
++  Byte allocaDummy[0x300];
++  int i = 0;
++  for (i = 0; i < 16; i++)
++    allocaDummy[i] = (Byte)i;
++  #endif
++
++  for (;;)
++  {
++    res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
++    if (res != SZ_OK || p->finished != 0)
++      break;
++    if (progress != 0)
++    {
++      res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
++      if (res != SZ_OK)
++      {
++        res = SZ_ERROR_PROGRESS;
++        break;
++      }
++    }
++  }
++  LzmaEnc_Finish(p);
++  return res;
++}
++
++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
++  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
++}
++
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  int i;
++  UInt32 dictSize = p->dictSize;
++  if (*size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_PARAM;
++  *size = LZMA_PROPS_SIZE;
++  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
++
++  for (i = 11; i <= 30; i++)
++  {
++    if (dictSize <= ((UInt32)2 << i))
++    {
++      dictSize = (2 << i);
++      break;
++    }
++    if (dictSize <= ((UInt32)3 << i))
++    {
++      dictSize = (3 << i);
++      break;
++    }
++  }
++
++  for (i = 0; i < 4; i++)
++    props[1 + i] = (Byte)(dictSize >> (8 * i));
++  return SZ_OK;
++}
++
++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  SRes res;
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++
++  CSeqOutStreamBuf outStream;
++
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = writeEndMark;
++
++  p->rc.outStream = &outStream.funcTable;
++  res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
++  if (res == SZ_OK)
++    res = LzmaEnc_Encode2(p, progress);
++
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++  return res;
++}
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
++  SRes res;
++  if (p == 0)
++    return SZ_ERROR_MEM;
++
++  res = LzmaEnc_SetProps(p, props);
++  if (res == SZ_OK)
++  {
++    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
++    if (res == SZ_OK)
++      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
++          writeEndMark, progress, alloc, allocBig);
++  }
++
++  LzmaEnc_Destroy(p, alloc, allocBig);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/Makefile
+@@ -0,0 +1,7 @@
++lzma_compress-objs := LzFind.o LzmaEnc.o
++lzma_decompress-objs := LzmaDec.o
++
++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o
++
++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h
diff --git a/target/linux/generic/patches-4.4/531-debloat_lzma.patch b/target/linux/generic/patches-4.4/531-debloat_lzma.patch
new file mode 100644
index 0000000000..aa3c498016
--- /dev/null
+++ b/target/linux/generic/patches-4.4/531-debloat_lzma.patch
@@ -0,0 +1,1024 @@
+--- a/include/linux/lzma/LzmaDec.h
++++ b/include/linux/lzma/LzmaDec.h
+@@ -31,14 +31,6 @@ typedef struct _CLzmaProps
+   UInt32 dicSize;
+ } CLzmaProps;
+ 
+-/* LzmaProps_Decode - decodes properties
+-Returns:
+-  SZ_OK
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+-
+ 
+ /* ---------- LZMA Decoder state ---------- */
+ 
+@@ -70,8 +62,6 @@ typedef struct
+ 
+ #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+ 
+-void LzmaDec_Init(CLzmaDec *p);
+-
+ /* There are two types of LZMA streams:
+      0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+      1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+@@ -108,97 +98,6 @@ typedef enum
+ 
+ /* ELzmaStatus is used only as output value for function call */
+ 
+-
+-/* ---------- Interfaces ---------- */
+-
+-/* There are 3 levels of interfaces:
+-     1) Dictionary Interface
+-     2) Buffer Interface
+-     3) One Call Interface
+-   You can select any of these interfaces, but don't mix functions from different
+-   groups for same object. */
+-
+-
+-/* There are two variants to allocate state for Dictionary Interface:
+-     1) LzmaDec_Allocate / LzmaDec_Free
+-     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+-   You can use variant 2, if you set dictionary buffer manually.
+-   For Buffer Interface you must always use variant 1.
+-
+-LzmaDec_Allocate* can return:
+-  SZ_OK
+-  SZ_ERROR_MEM         - Memory allocation error
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-   
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+-
+-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+-
+-/* ---------- Dictionary Interface ---------- */
+-
+-/* You can use it, if you want to eliminate the overhead for data copying from
+-   dictionary to some other external buffer.
+-   You must work with CLzmaDec variables directly in this interface.
+-
+-   STEPS:
+-     LzmaDec_Constr()
+-     LzmaDec_Allocate()
+-     for (each new stream)
+-     {
+-       LzmaDec_Init()
+-       while (it needs more decompression)
+-       {
+-         LzmaDec_DecodeToDic()
+-         use data from CLzmaDec::dic and update CLzmaDec::dicPos
+-       }
+-     }
+-     LzmaDec_Free()
+-*/
+-
+-/* LzmaDec_DecodeToDic
+-   
+-   The decoding to internal dictionary buffer (CLzmaDec::dic).
+-   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (dicLimit).
+-  LZMA_FINISH_ANY - Decode just dicLimit bytes.
+-  LZMA_FINISH_END - Stream must be finished after dicLimit.
+-
+-Returns:
+-  SZ_OK
+-    status:
+-      LZMA_STATUS_FINISHED_WITH_MARK
+-      LZMA_STATUS_NOT_FINISHED
+-      LZMA_STATUS_NEEDS_MORE_INPUT
+-      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+-  SZ_ERROR_DATA - Data error
+-*/
+-
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+-/* ---------- Buffer Interface ---------- */
+-
+-/* It's zlib-like interface.
+-   See LzmaDec_DecodeToDic description for information about STEPS and return results,
+-   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+-   to work with CLzmaDec variables manually.
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (*destLen).
+-  LZMA_FINISH_ANY - Decode just destLen bytes.
+-  LZMA_FINISH_END - Stream must be finished after (*destLen).
+-*/
+-
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+ /* ---------- One Call Interface ---------- */
+ 
+ /* LzmaDecode
+--- a/lib/lzma/LzmaDec.c
++++ b/lib/lzma/LzmaDec.c
+@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p,
+   p->needFlush = 0;
+ }
+ 
+-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+ {
+   p->needFlush = 1;
+   p->remainLen = 0;
+@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p
+     p->needInitState = 1;
+ }
+ 
+-void LzmaDec_Init(CLzmaDec *p)
++static void LzmaDec_Init(CLzmaDec *p)
+ {
+   p->dicPos = 0;
+   LzmaDec_InitDicAndState(p, True, True);
+@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD
+   p->needInitState = 0;
+ }
+ 
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+     ELzmaFinishMode finishMode, ELzmaStatus *status)
+ {
+   SizeT inSize = *srcLen;
+@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si
+   return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+ }
+ 
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+-{
+-  SizeT outSize = *destLen;
+-  SizeT inSize = *srcLen;
+-  *srcLen = *destLen = 0;
+-  for (;;)
+-  {
+-    SizeT inSizeCur = inSize, outSizeCur, dicPos;
+-    ELzmaFinishMode curFinishMode;
+-    SRes res;
+-    if (p->dicPos == p->dicBufSize)
+-      p->dicPos = 0;
+-    dicPos = p->dicPos;
+-    if (outSize > p->dicBufSize - dicPos)
+-    {
+-      outSizeCur = p->dicBufSize;
+-      curFinishMode = LZMA_FINISH_ANY;
+-    }
+-    else
+-    {
+-      outSizeCur = dicPos + outSize;
+-      curFinishMode = finishMode;
+-    }
+-
+-    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+-    src += inSizeCur;
+-    inSize -= inSizeCur;
+-    *srcLen += inSizeCur;
+-    outSizeCur = p->dicPos - dicPos;
+-    memcpy(dest, p->dic + dicPos, outSizeCur);
+-    dest += outSizeCur;
+-    outSize -= outSizeCur;
+-    *destLen += outSizeCur;
+-    if (res != 0)
+-      return res;
+-    if (outSizeCur == 0 || outSize == 0)
+-      return SZ_OK;
+-  }
+-}
+-
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->probs);
+   p->probs = 0;
+ }
+ 
+-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  alloc->Free(alloc, p->dic);
+-  p->dic = 0;
+-}
+-
+-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  LzmaDec_FreeProbs(p, alloc);
+-  LzmaDec_FreeDict(p, alloc);
+-}
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+ {
+   UInt32 dicSize;
+   Byte d;
+@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma
+   return SZ_OK;
+ }
+ 
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+ {
+   CLzmaProps propNew;
+   RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p,
+   p->prop = propNew;
+   return SZ_OK;
+ }
+-
+-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+-{
+-  CLzmaProps propNew;
+-  SizeT dicBufSize;
+-  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+-  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+-  dicBufSize = propNew.dicSize;
+-  if (p->dic == 0 || dicBufSize != p->dicBufSize)
+-  {
+-    LzmaDec_FreeDict(p, alloc);
+-    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+-    if (p->dic == 0)
+-    {
+-      LzmaDec_FreeProbs(p, alloc);
+-      return SZ_ERROR_MEM;
+-    }
+-  }
+-  p->dicBufSize = dicBufSize;
+-  p->prop = propNew;
+-  return SZ_OK;
+-}
+ 
+ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+     const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+--- a/include/linux/lzma/LzmaEnc.h
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps
+ } CLzmaEncProps;
+ 
+ void LzmaEncProps_Init(CLzmaEncProps *p);
+-void LzmaEncProps_Normalize(CLzmaEncProps *p);
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+-
+ 
+ /* ---------- CLzmaEncHandle Interface ---------- */
+ 
+@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+ void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+     int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ 
+-/* ---------- One Call Interface ---------- */
+-
+-/* LzmaEncode
+-Return code:
+-  SZ_OK               - OK
+-  SZ_ERROR_MEM        - Memory allocation error
+-  SZ_ERROR_PARAM      - Incorrect paramater
+-  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+-  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+-*/
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzmaEnc.c
++++ b/lib/lzma/LzmaEnc.c
+@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p)
+   p->writeEndMark = 0;
+ }
+ 
+-void LzmaEncProps_Normalize(CLzmaEncProps *p)
++static void LzmaEncProps_Normalize(CLzmaEncProps *p)
+ {
+   int level = p->level;
+   if (level < 0) level = 5;
+@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp
+       #endif
+ }
+ 
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+ {
+   CLzmaEncProps props = *props2;
+   LzmaEncProps_Normalize(&props);
+@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL
+ 
+ #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+ 
+-UInt32 GetPosSlot1(UInt32 pos)
++static UInt32 GetPosSlot1(UInt32 pos)
+ {
+   UInt32 res;
+   BSR2_RET(pos, res);
+@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos)
+ #define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+ #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+ 
+-void LzmaEnc_FastPosInit(Byte *g_FastPos)
++static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+ {
+   int c = 2, slotFast;
+   g_FastPos[0] = 0;
+@@ -339,58 +339,6 @@ typedef struct
+   CSaveState saveState;
+ } CLzmaEnc;
+ 
+-void LzmaEnc_SaveState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  CSaveState *dest = &p->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+-}
+-
+-void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *dest = (CLzmaEnc *)pp;
+-  const CSaveState *p = &dest->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+-}
+-
+ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE
+   while (symbol < 0x10000);
+ }
+ 
+-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+ {
+   UInt32 i;
+   for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc
+   p->matchPriceCount = 0;
+ }
+ 
+-void LzmaEnc_Construct(CLzmaEnc *p)
++static void LzmaEnc_Construct(CLzmaEnc *p)
+ {
+   RangeEnc_Construct(&p->rc);
+   MatchFinder_Construct(&p->matchFinderBase);
+@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+   return p;
+ }
+ 
+-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->litProbs);
+   alloc->Free(alloc, p->saveState.litProbs);
+@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl
+   p->saveState.litProbs = 0;
+ }
+ 
+-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   #ifndef _7ZIP_ST
+   MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U
+   return SZ_OK;
+ }
+ 
+-void LzmaEnc_Init(CLzmaEnc *p)
++static void LzmaEnc_Init(CLzmaEnc *p)
+ {
+   UInt32 i;
+   p->state = 0;
+@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p)
+   p->lpMask = (1 << p->lp) - 1;
+ }
+ 
+-void LzmaEnc_InitPrices(CLzmaEnc *p)
++static void LzmaEnc_InitPrices(CLzmaEnc *p)
+ {
+   if (!p->fastMode)
+   {
+@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn
+   return SZ_OK;
+ }
+ 
+-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  p->rc.outStream = outStream;
+-  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+-}
+-
+-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+-    ISeqInStream *inStream, UInt32 keepWindowSize,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+-}
+-
+ static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+ {
+   p->matchFinderBase.directInput = 1;
+@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc
+   p->matchFinderBase.directInputRem = srcLen;
+ }
+ 
+-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+     UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p
+   return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+ }
+ 
+-void LzmaEnc_Finish(CLzmaEncHandle pp)
++static void LzmaEnc_Finish(CLzmaEncHandle pp)
+ {
+   #ifndef _7ZIP_ST
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo
+   return size;
+ }
+ 
+-
+-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+-}
+-
+-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+-}
+-
+-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+-    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  UInt64 nowPos64;
+-  SRes res;
+-  CSeqOutStreamBuf outStream;
+-
+-  outStream.funcTable.Write = MyWrite;
+-  outStream.data = dest;
+-  outStream.rem = *destLen;
+-  outStream.overflow = False;
+-
+-  p->writeEndMark = False;
+-  p->finished = False;
+-  p->result = SZ_OK;
+-
+-  if (reInit)
+-    LzmaEnc_Init(p);
+-  LzmaEnc_InitPrices(p);
+-  nowPos64 = p->nowPos64;
+-  RangeEnc_Init(&p->rc);
+-  p->rc.outStream = &outStream.funcTable;
+-
+-  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+-  
+-  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+-  *destLen -= outStream.rem;
+-  if (outStream.overflow)
+-    return SZ_ERROR_OUTPUT_EOF;
+-
+-  return res;
+-}
+-
+ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+ {
+   SRes res = SZ_OK;
+@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p,
+   return res;
+ }
+ 
+-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+-  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+-}
+-
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp
+     return SZ_ERROR_OUTPUT_EOF;
+   return res;
+ }
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+-  SRes res;
+-  if (p == 0)
+-    return SZ_ERROR_MEM;
+-
+-  res = LzmaEnc_SetProps(p, props);
+-  if (res == SZ_OK)
+-  {
+-    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+-    if (res == SZ_OK)
+-      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+-          writeEndMark, progress, alloc, allocBig);
+-  }
+-
+-  LzmaEnc_Destroy(p, alloc, allocBig);
+-  return res;
+-}
+--- a/include/linux/lzma/LzFind.h
++++ b/include/linux/lzma/LzFind.h
+@@ -55,11 +55,6 @@ typedef struct _CMatchFinder
+ 
+ #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p);
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+-void MatchFinder_MoveBlock(CMatchFinder *p);
+-void MatchFinder_ReadIfRequired(CMatchFinder *p);
+-
+ void MatchFinder_Construct(CMatchFinder *p);
+ 
+ /* Conditions:
+@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p,
+     UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+     ISzAlloc *alloc);
+ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+-    UInt32 *distances, UInt32 maxLen);
+ 
+ /*
+ Conditions:
+@@ -102,12 +91,6 @@ typedef struct _IMatchFinder
+ 
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+ 
+-void MatchFinder_Init(CMatchFinder *p);
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzFind.c
++++ b/lib/lzma/LzFind.c
+@@ -14,9 +14,15 @@
+ 
+ #define kStartMaxLen 3
+ 
++#if 0
++#define DIRECT_INPUT	p->directInput
++#else
++#define DIRECT_INPUT	1
++#endif
++
+ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+ {
+-  if (!p->directInput)
++  if (!DIRECT_INPUT)
+   {
+     alloc->Free(alloc, p->bufferBase);
+     p->bufferBase = 0;
+@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder
+ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+ {
+   UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     p->blockSize = blockSize;
+     return 1;
+@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde
+   return (p->bufferBase != 0);
+ }
+ 
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+ 
+-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+ 
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+ {
+   p->posLimit -= subValue;
+   p->pos -= subValue;
+@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch
+ {
+   if (p->streamEndWasReached || p->result != SZ_OK)
+     return;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+     if (curSize > p->directInputRem)
+@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch
+   }
+ }
+ 
+-void MatchFinder_MoveBlock(CMatchFinder *p)
++static void MatchFinder_MoveBlock(CMatchFinder *p)
+ {
+   memmove(p->bufferBase,
+     p->buffer - p->keepSizeBefore,
+@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder
+   p->buffer = p->bufferBase + p->keepSizeBefore;
+ }
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p)
++static int MatchFinder_NeedMove(CMatchFinder *p)
+ {
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+     return 0;
+   /* if (p->streamEndWasReached) return 0; */
+   return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+ }
+ 
+-void MatchFinder_ReadIfRequired(CMatchFinder *p)
+-{
+-  if (p->streamEndWasReached)
+-    return;
+-  if (p->keepSizeAfter >= p->streamPos - p->pos)
+-    MatchFinder_ReadBlock(p);
+-}
+-
+ static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+ {
+   if (MatchFinder_NeedMove(p))
+@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch
+   p->posLimit = p->pos + limit;
+ }
+ 
+-void MatchFinder_Init(CMatchFinder *p)
++static void MatchFinder_Init(CMatchFinder *p)
+ {
+   UInt32 i;
+   for (i = 0; i < p->hashSizeSum; i++)
+@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM
+   return (p->pos - p->historySize - 1) & kNormalizeMask;
+ }
+ 
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+ {
+   UInt32 i;
+   for (i = 0; i < numItems; i++)
+@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat
+   MatchFinder_SetLimits(p);
+ }
+ 
+-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+-    UInt32 *distances, UInt32 maxLen)
+-{
+-  son[_cyclicBufferPos] = curMatch;
+-  for (;;)
+-  {
+-    UInt32 delta = pos - curMatch;
+-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+-      return distances;
+-    {
+-      const Byte *pb = cur - delta;
+-      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+-      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+-      {
+-        UInt32 len = 0;
+-        while (++len != lenLimit)
+-          if (pb[len] != cur[len])
+-            break;
+-        if (maxLen < len)
+-        {
+-          *distances++ = maxLen = len;
+-          *distances++ = delta - 1;
+-          if (len == lenLimit)
+-            return distances;
+-        }
+-      }
+-    }
+-  }
+-}
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+     UInt32 *distances, UInt32 maxLen)
+ {
+@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi
+   p->buffer++; \
+   if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+ 
+-#define MOVE_POS_RET MOVE_POS return offset;
+-
+ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+ 
++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset;
++
+ #define GET_MATCHES_HEADER2(minLen, ret_op) \
+   UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+   lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi
+   distances + offset, maxLen) - distances); MOVE_POS_RET;
+ 
+ #define SKIP_FOOTER \
+-  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+-
+-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(2)
+-  HASH2_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 1)
+-}
+-
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 2)
+-}
+-
+-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, delta2, maxLen, offset;
+-  GET_MATCHES_HEADER(3)
+-
+-  HASH3_CALC;
+-
+-  delta2 = p->pos - p->hash[hash2Value];
+-  curMatch = p->hash[kFix3HashSize + hashValue];
+-  
+-  p->hash[hash2Value] =
+-  p->hash[kFix3HashSize + hashValue] = p->pos;
+-
+-
+-  maxLen = 2;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[0] = maxLen;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-    if (maxLen == lenLimit)
+-    {
+-      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+-      MOVE_POS_RET;
+-    }
+-  }
+-  GET_MATCHES_FOOTER(offset, maxLen)
+-}
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p);
+ 
+ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+ {
+@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches
+   GET_MATCHES_FOOTER(offset, maxLen)
+ }
+ 
+-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+-  GET_MATCHES_HEADER(4)
+-
+-  HASH4_CALC;
+-
+-  delta2 = p->pos - p->hash[                hash2Value];
+-  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+-  curMatch = p->hash[kFix4HashSize + hashValue];
+-
+-  p->hash[                hash2Value] =
+-  p->hash[kFix3HashSize + hash3Value] =
+-  p->hash[kFix4HashSize + hashValue] = p->pos;
+-
+-  maxLen = 1;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    distances[0] = maxLen = 2;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-  }
+-  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+-  {
+-    maxLen = 3;
+-    distances[offset + 1] = delta3 - 1;
+-    offset += 2;
+-    delta2 = delta3;
+-  }
+-  if (offset != 0)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[offset - 2] = maxLen;
+-    if (maxLen == lenLimit)
+-    {
+-      p->son[p->cyclicBufferPos] = curMatch;
+-      MOVE_POS_RET;
+-    }
+-  }
+-  if (maxLen < 3)
+-    maxLen = 3;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances + offset, maxLen) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances, 2) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(2)
+-    HASH2_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value;
+-    SKIP_HEADER(3)
+-    HASH3_CALC;
+-    curMatch = p->hash[kFix3HashSize + hashValue];
+-    p->hash[hash2Value] =
+-    p->hash[kFix3HashSize + hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+ {
+   do
+@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF
+   while (--num != 0);
+ }
+ 
+-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value, hash3Value;
+-    SKIP_HEADER(4)
+-    HASH4_CALC;
+-    curMatch = p->hash[kFix4HashSize + hashValue];
+-    p->hash[                hash2Value] =
+-    p->hash[kFix3HashSize + hash3Value] =
+-    p->hash[kFix4HashSize + hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+ {
+   vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+   vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+   vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+   vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+-  if (!p->btMode)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 2)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 3)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+-  }
+-  else
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+-  }
++  vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++  vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
diff --git a/target/linux/generic/patches-4.4/532-jffs2_eofdetect.patch b/target/linux/generic/patches-4.4/532-jffs2_eofdetect.patch
new file mode 100644
index 0000000000..8ce53d8bed
--- /dev/null
+++ b/target/linux/generic/patches-4.4/532-jffs2_eofdetect.patch
@@ -0,0 +1,56 @@
+--- a/fs/jffs2/build.c
++++ b/fs/jffs2/build.c
+@@ -116,6 +116,16 @@ static int jffs2_build_filesystem(struct
+ 	dbg_fsbuild("scanned flash completely\n");
+ 	jffs2_dbg_dump_block_lists_nolock(c);
+ 
++	if (c->flags & (1 << 7)) {
++		printk("%s(): unlocking the mtd device... ", __func__);
++		mtd_unlock(c->mtd, 0, c->mtd->size);
++		printk("done.\n");
++
++		printk("%s(): erasing all blocks after the end marker... ", __func__);
++		jffs2_erase_pending_blocks(c, -1);
++		printk("done.\n");
++	}
++
+ 	dbg_fsbuild("pass 1 starting\n");
+ 	c->flags |= JFFS2_SB_FLAG_BUILDING;
+ 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
+--- a/fs/jffs2/scan.c
++++ b/fs/jffs2/scan.c
+@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
+ 		/* reset summary info for next eraseblock scan */
+ 		jffs2_sum_reset_collected(s);
+ 
+-		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+-						buf_size, s);
++		if (c->flags & (1 << 7)) {
++			if (mtd_block_isbad(c->mtd, jeb->offset))
++				ret = BLK_STATE_BADBLOCK;
++			else
++				ret = BLK_STATE_ALLFF;
++		} else
++			ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
++							buf_size, s);
+ 
+ 		if (ret < 0)
+ 			goto out;
+@@ -561,6 +567,17 @@ full_scan:
+ 			return err;
+ 	}
+ 
++	if ((buf[0] == 0xde) &&
++		(buf[1] == 0xad) &&
++		(buf[2] == 0xc0) &&
++		(buf[3] == 0xde)) {
++		/* end of filesystem. erase everything after this point */
++		printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
++		c->flags |= (1 << 7);
++
++		return BLK_STATE_ALLFF;
++	}
++
+ 	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+ 	ofs = 0;
+ 	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
diff --git a/target/linux/generic/patches-4.4/540-crypto-xz-decompression-support.patch b/target/linux/generic/patches-4.4/540-crypto-xz-decompression-support.patch
new file mode 100644
index 0000000000..86017b5660
--- /dev/null
+++ b/target/linux/generic/patches-4.4/540-crypto-xz-decompression-support.patch
@@ -0,0 +1,146 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1544,6 +1544,13 @@ config CRYPTO_LZ4HC
+ 	help
+ 	  This is the LZ4 high compression mode algorithm.
+ 
++config CRYPTO_XZ
++	tristate "XZ compression algorithm"
++	select CRYPTO_ALGAPI
++	select XZ_DEC
++	help
++	  This is the XZ algorithm. Only decompression is supported for now.
++
+ comment "Random Number Generation"
+ 
+ config CRYPTO_ANSI_CPRNG
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -107,6 +107,7 @@ obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.
+ obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+ obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
+ obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
++obj-$(CONFIG_CRYPTO_XZ) += xz.o
+ obj-$(CONFIG_CRYPTO_842) += 842.o
+ obj-$(CONFIG_CRYPTO_RNG2) += rng.o
+ obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
+--- /dev/null
++++ b/crypto/xz.c
+@@ -0,0 +1,117 @@
++/*
++ * Cryptographic API.
++ *
++ * XZ decompression support.
++ *
++ * Copyright (c) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * 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/init.h>
++#include <linux/module.h>
++#include <linux/crypto.h>
++#include <linux/xz.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/net.h>
++
++struct xz_comp_ctx {
++	struct xz_dec	*decomp_state;
++	struct xz_buf	decomp_buf;
++};
++
++static int crypto_xz_decomp_init(struct xz_comp_ctx *ctx)
++{
++	ctx->decomp_state = xz_dec_init(XZ_SINGLE, 0);
++	if (!ctx->decomp_state)
++		return -ENOMEM;
++
++	return 0;
++}
++
++static void crypto_xz_decomp_exit(struct xz_comp_ctx *ctx)
++{
++	xz_dec_end(ctx->decomp_state);
++}
++
++static int crypto_xz_init(struct crypto_tfm *tfm)
++{
++	struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	return crypto_xz_decomp_init(ctx);
++}
++
++static void crypto_xz_exit(struct crypto_tfm *tfm)
++{
++	struct xz_comp_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_xz_decomp_exit(ctx);
++}
++
++static int crypto_xz_compress(struct crypto_tfm *tfm, const u8 *src,
++			      unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++	return -EOPNOTSUPP;
++}
++
++static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src,
++				unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++	struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm);
++	struct xz_buf *xz_buf = &dctx->decomp_buf;
++	int ret;
++
++	memset(xz_buf, '\0', sizeof(struct xz_buf));
++
++	xz_buf->in = (u8 *) src;
++	xz_buf->in_pos = 0;
++	xz_buf->in_size = slen;
++	xz_buf->out = (u8 *) dst;
++	xz_buf->out_pos = 0;
++	xz_buf->out_size = *dlen;
++
++	ret = xz_dec_run(dctx->decomp_state, xz_buf);
++	if (ret != XZ_STREAM_END) {
++		ret = -EINVAL;
++		goto out;
++	}
++
++	*dlen = xz_buf->out_pos;
++	ret = 0;
++
++out:
++	return ret;
++}
++
++static struct crypto_alg crypto_xz_alg = {
++	.cra_name		= "xz",
++	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
++	.cra_ctxsize		= sizeof(struct xz_comp_ctx),
++	.cra_module		= THIS_MODULE,
++	.cra_list		= LIST_HEAD_INIT(crypto_xz_alg.cra_list),
++	.cra_init		= crypto_xz_init,
++	.cra_exit		= crypto_xz_exit,
++	.cra_u			= { .compress = {
++	.coa_compress 		= crypto_xz_compress,
++	.coa_decompress  	= crypto_xz_decompress } }
++};
++
++static int __init crypto_xz_mod_init(void)
++{
++	return crypto_register_alg(&crypto_xz_alg);
++}
++
++static void __exit crypto_xz_mod_exit(void)
++{
++	crypto_unregister_alg(&crypto_xz_alg);
++}
++
++module_init(crypto_xz_mod_init);
++module_exit(crypto_xz_mod_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Crypto XZ decompression support");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
diff --git a/target/linux/generic/patches-4.4/541-ubifs-xz-decompression-support.patch b/target/linux/generic/patches-4.4/541-ubifs-xz-decompression-support.patch
new file mode 100644
index 0000000000..277d91507b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/541-ubifs-xz-decompression-support.patch
@@ -0,0 +1,94 @@
+--- a/fs/ubifs/Kconfig
++++ b/fs/ubifs/Kconfig
+@@ -5,8 +5,10 @@ config UBIFS_FS
+ 	select CRYPTO if UBIFS_FS_ADVANCED_COMPR
+ 	select CRYPTO if UBIFS_FS_LZO
+ 	select CRYPTO if UBIFS_FS_ZLIB
++	select CRYPTO if UBIFS_FS_XZ
+ 	select CRYPTO_LZO if UBIFS_FS_LZO
+ 	select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
++	select CRYPTO_XZ if UBIFS_FS_XZ
+ 	depends on MTD_UBI
+ 	help
+ 	  UBIFS is a file system for flash devices which works on top of UBI.
+@@ -36,6 +38,14 @@ config UBIFS_FS_ZLIB
+ 	help
+ 	  Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
+ 
++config UBIFS_FS_XZ
++	bool "XZ decompression support" if UBIFS_FS_ADVANCED_COMPR
++	depends on UBIFS_FS
++	default y
++	help
++	  XZ compresses better the ZLIB but it is slower..
++	  Say 'Y' if unsure.
++
+ config UBIFS_ATIME_SUPPORT
+ 	bool "Access time support" if UBIFS_FS
+ 	depends on UBIFS_FS
+--- a/fs/ubifs/compress.c
++++ b/fs/ubifs/compress.c
+@@ -71,6 +71,24 @@ static struct ubifs_compressor zlib_comp
+ };
+ #endif
+ 
++#ifdef CONFIG_UBIFS_FS_XZ
++static DEFINE_MUTEX(xz_enc_mutex);
++static DEFINE_MUTEX(xz_dec_mutex);
++
++static struct ubifs_compressor xz_compr = {
++	.compr_type = UBIFS_COMPR_XZ,
++	.comp_mutex = &xz_enc_mutex,
++	.decomp_mutex = &xz_dec_mutex,
++	.name = "xz",
++	.capi_name = "xz",
++};
++#else
++static struct ubifs_compressor xz_compr = {
++	.compr_type = UBIFS_COMPR_XZ,
++	.name = "xz",
++};
++#endif
++
+ /* All UBIFS compressors */
+ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+ 
+@@ -232,9 +250,15 @@ int __init ubifs_compressors_init(void)
+ 	if (err)
+ 		goto out_lzo;
+ 
++	err = compr_init(&xz_compr);
++	if (err)
++		goto out_zlib;
++
+ 	ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
+ 	return 0;
+ 
++out_zlib:
++	compr_exit(&zlib_compr);
+ out_lzo:
+ 	compr_exit(&lzo_compr);
+ 	return err;
+@@ -247,4 +271,5 @@ void ubifs_compressors_exit(void)
+ {
+ 	compr_exit(&lzo_compr);
+ 	compr_exit(&zlib_compr);
++	compr_exit(&xz_compr);
+ }
+--- a/fs/ubifs/ubifs-media.h
++++ b/fs/ubifs/ubifs-media.h
+@@ -332,12 +332,14 @@ enum {
+  * UBIFS_COMPR_NONE: no compression
+  * UBIFS_COMPR_LZO: LZO compression
+  * UBIFS_COMPR_ZLIB: ZLIB compression
++ * UBIFS_COMPR_XZ: XZ compression
+  * UBIFS_COMPR_TYPES_CNT: count of supported compression types
+  */
+ enum {
+ 	UBIFS_COMPR_NONE,
+ 	UBIFS_COMPR_LZO,
+ 	UBIFS_COMPR_ZLIB,
++	UBIFS_COMPR_XZ,
+ 	UBIFS_COMPR_TYPES_CNT,
+ };
+ 
diff --git a/target/linux/generic/patches-4.4/551-ubifs-fix-default-compression-selection.patch b/target/linux/generic/patches-4.4/551-ubifs-fix-default-compression-selection.patch
new file mode 100644
index 0000000000..1b0f30718c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/551-ubifs-fix-default-compression-selection.patch
@@ -0,0 +1,29 @@
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -63,6 +63,17 @@
+ /* Default time granularity in nanoseconds */
+ #define DEFAULT_TIME_GRAN 1000000000
+ 
++static int get_default_compressor(void)
++{
++	if (ubifs_compr_present(UBIFS_COMPR_LZO))
++		return UBIFS_COMPR_LZO;
++
++	if (ubifs_compr_present(UBIFS_COMPR_ZLIB))
++		return UBIFS_COMPR_ZLIB;
++
++	return UBIFS_COMPR_NONE;
++}
++
+ /**
+  * create_default_filesystem - format empty UBI volume.
+  * @c: UBIFS file-system description object
+@@ -183,7 +194,7 @@ static int create_default_filesystem(str
+ 	if (c->mount_opts.override_compr)
+ 		sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
+ 	else
+-		sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
++		sup->default_compr = cpu_to_le16(get_default_compressor());
+ 
+ 	generate_random_uuid(sup->uuid);
+ 
diff --git a/target/linux/generic/patches-4.4/600-netfilter_conntrack_flush.patch b/target/linux/generic/patches-4.4/600-netfilter_conntrack_flush.patch
new file mode 100644
index 0000000000..8794739658
--- /dev/null
+++ b/target/linux/generic/patches-4.4/600-netfilter_conntrack_flush.patch
@@ -0,0 +1,86 @@
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -17,6 +17,7 @@
+ #include <linux/percpu.h>
+ #include <linux/netdevice.h>
+ #include <linux/security.h>
++#include <linux/inet.h>
+ #include <net/net_namespace.h>
+ #ifdef CONFIG_SYSCTL
+ #include <linux/sysctl.h>
+@@ -288,10 +289,66 @@ static int ct_open(struct inode *inode,
+ 			sizeof(struct ct_iter_state));
+ }
+ 
++struct kill_request {
++	u16 family;
++	union nf_inet_addr addr;
++};
++
++static int kill_matching(struct nf_conn *i, void *data)
++{
++	struct kill_request *kr = data;
++	struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++	struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
++
++	if (!kr->family)
++		return 1;
++
++	if (t1->src.l3num != kr->family)
++		return 0;
++
++	return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
++}
++
++static ssize_t ct_file_write(struct file *file, const char __user *buf,
++			     size_t count, loff_t *ppos)
++{
++	struct seq_file *seq = file->private_data;
++	struct net *net = seq_file_net(seq);
++	struct kill_request kr = { };
++	char req[INET6_ADDRSTRLEN] = { };
++
++	if (count == 0)
++		return 0;
++
++	if (count >= INET6_ADDRSTRLEN)
++		count = INET6_ADDRSTRLEN - 1;
++
++	if (copy_from_user(req, buf, count))
++		return -EFAULT;
++
++	if (strnchr(req, count, ':')) {
++		kr.family = AF_INET6;
++		if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	} else if (strnchr(req, count, '.')) {
++		kr.family = AF_INET;
++		if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	}
++
++	nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0);
++
++	return count;
++}
++
+ static const struct file_operations ct_file_ops = {
+ 	.owner   = THIS_MODULE,
+ 	.open    = ct_open,
+ 	.read    = seq_read,
++	.write	 = ct_file_write,
+ 	.llseek  = seq_lseek,
+ 	.release = seq_release_net,
+ };
+@@ -393,7 +450,7 @@ static int nf_conntrack_standalone_init_
+ {
+ 	struct proc_dir_entry *pde;
+ 
+-	pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops);
++	pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops);
+ 	if (!pde)
+ 		goto out_nf_conntrack;
+ 
diff --git a/target/linux/generic/patches-4.4/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/patches-4.4/610-netfilter_match_bypass_default_checks.patch
new file mode 100644
index 0000000000..ea9558fccf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/610-netfilter_match_bypass_default_checks.patch
@@ -0,0 +1,84 @@
+--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
+@@ -87,6 +87,7 @@ struct ipt_ip {
+ #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
+ #define IPT_F_GOTO		0x02	/* Set if jump is a goto */
+ #define IPT_F_MASK		0x03	/* All possible flag bits mask. */
++#define IPT_F_NO_DEF_MATCH	0x80	/* Internal: no default match rules present */
+ 
+ /* Values for "inv" field in struct ipt_ip. */
+ #define IPT_INV_VIA_IN		0x01	/* Invert the sense of IN IFACE. */
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -82,6 +82,9 @@ ip_packet_match(const struct iphdr *ip,
+ 
+ #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
+ 
++	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
++		return true;
++
+ 	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+ 		  IPT_INV_SRCIP) ||
+ 	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+@@ -135,6 +138,29 @@ ip_packet_match(const struct iphdr *ip,
+ 	return true;
+ }
+ 
++static void
++ip_checkdefault(struct ipt_ip *ip)
++{
++	static const char iface_mask[IFNAMSIZ] = {};
++
++	if (ip->invflags || ip->flags & IPT_F_FRAG)
++		return;
++
++	if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (ip->smsk.s_addr || ip->dmsk.s_addr)
++		return;
++
++	if (ip->proto)
++		return;
++
++	ip->flags |= IPT_F_NO_DEF_MATCH;
++}
++
+ static bool
+ ip_checkentry(const struct ipt_ip *ip)
+ {
+@@ -664,6 +690,8 @@ find_check_entry(struct ipt_entry *e, st
+ 	struct xt_mtchk_param mtpar;
+ 	struct xt_entry_match *ematch;
+ 
++	ip_checkdefault(&e->ip);
++
+ 	e->counters.pcnt = xt_percpu_counter_alloc();
+ 	if (IS_ERR_VALUE(e->counters.pcnt))
+ 		return -ENOMEM;
+@@ -948,6 +976,7 @@ copy_entries_to_user(unsigned int total_
+ 	const struct xt_table_info *private = table->private;
+ 	int ret = 0;
+ 	const void *loc_cpu_entry;
++	u8 flags;
+ 
+ 	counters = alloc_counters(table);
+ 	if (IS_ERR(counters))
+@@ -974,6 +1003,14 @@ copy_entries_to_user(unsigned int total_
+ 			ret = -EFAULT;
+ 			goto free_counters;
+ 		}
++
++		flags = e->ip.flags & IPT_F_MASK;
++		if (copy_to_user(userptr + off
++				 + offsetof(struct ipt_entry, ip.flags),
++				 &flags, sizeof(flags)) != 0) {
++			ret = -EFAULT;
++			goto free_counters;
++		}
+ 
+ 		for (i = sizeof(struct ipt_entry);
+ 		     i < e->target_offset;
diff --git a/target/linux/generic/patches-4.4/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/patches-4.4/611-netfilter_match_bypass_default_table.patch
new file mode 100644
index 0000000000..1c565198b4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/611-netfilter_match_bypass_default_table.patch
@@ -0,0 +1,111 @@
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -308,6 +308,33 @@ struct ipt_entry *ipt_next_entry(const s
+ 	return (void *)entry + entry->next_offset;
+ }
+ 
++static bool
++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
++{
++	struct xt_entry_target *t;
++	struct xt_standard_target *st;
++
++	if (e->target_offset != sizeof(struct ipt_entry))
++		return false;
++
++	if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
++		return false;
++
++	t = ipt_get_target(e);
++	if (t->u.kernel.target->target)
++		return false;
++
++	st = (struct xt_standard_target *) t;
++	if (st->verdict == XT_RETURN)
++		return false;
++
++	if (st->verdict >= 0)
++		return false;
++
++	*verdict = (unsigned)(-st->verdict) - 1;
++	return true;
++}
++
+ /* Returns one of the generic firewall policies, like NF_ACCEPT. */
+ unsigned int
+ ipt_do_table(struct sk_buff *skb,
+@@ -328,28 +355,8 @@ ipt_do_table(struct sk_buff *skb,
+ 	unsigned int addend;
+ 
+ 	/* Initialization */
+-	stackidx = 0;
+-	ip = ip_hdr(skb);
+-	indev = state->in ? state->in->name : nulldevname;
+-	outdev = state->out ? state->out->name : nulldevname;
+-	/* We handle fragments by dealing with the first fragment as
+-	 * if it was a normal packet.  All other fragments are treated
+-	 * normally, except that they will NEVER match rules that ask
+-	 * things we don't know, ie. tcp syn flag or ports).  If the
+-	 * rule is also a fragment-specific rule, non-fragments won't
+-	 * match it. */
+-	acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+-	acpar.thoff   = ip_hdrlen(skb);
+-	acpar.hotdrop = false;
+-	acpar.net     = state->net;
+-	acpar.in      = state->in;
+-	acpar.out     = state->out;
+-	acpar.family  = NFPROTO_IPV4;
+-	acpar.hooknum = hook;
+-
+ 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
+ 	local_bh_disable();
+-	addend = xt_write_recseq_begin();
+ 	private = table->private;
+ 	cpu        = smp_processor_id();
+ 	/*
+@@ -358,6 +365,23 @@ ipt_do_table(struct sk_buff *skb,
+ 	 */
+ 	smp_read_barrier_depends();
+ 	table_base = private->entries;
++
++	e = get_entry(table_base, private->hook_entry[hook]);
++	if (ipt_handle_default_rule(e, &verdict)) {
++		struct xt_counters *counter;
++
++		counter = xt_get_this_cpu_counter(&e->counters);
++		ADD_COUNTER(*counter, skb->len, 1);
++		local_bh_enable();
++		return verdict;
++	}
++
++	stackidx = 0;
++	ip = ip_hdr(skb);
++	indev = state->in ? state->in->name : nulldevname;
++	outdev = state->out ? state->out->name : nulldevname;
++
++	addend = xt_write_recseq_begin();
+ 	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
+ 
+ 	/* Switch to alternate jumpstack if we're being invoked via TEE.
+@@ -370,7 +394,20 @@ ipt_do_table(struct sk_buff *skb,
+ 	if (static_key_false(&xt_tee_enabled))
+ 		jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
+ 
+-	e = get_entry(table_base, private->hook_entry[hook]);
++	/* We handle fragments by dealing with the first fragment as
++	 * if it was a normal packet.  All other fragments are treated
++	 * normally, except that they will NEVER match rules that ask
++	 * things we don't know, ie. tcp syn flag or ports).  If the
++	 * rule is also a fragment-specific rule, non-fragments won't
++	 * match it. */
++	acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
++	acpar.thoff   = ip_hdrlen(skb);
++	acpar.hotdrop = false;
++	acpar.net     = state->net;
++	acpar.in      = state->in;
++	acpar.out     = state->out;
++	acpar.family  = NFPROTO_IPV4;
++	acpar.hooknum = hook;
+ 
+ 	pr_debug("Entering %s(hook %u), UF %p\n",
+ 		 table->name, hook,
diff --git a/target/linux/generic/patches-4.4/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/patches-4.4/612-netfilter_match_reduce_memory_access.patch
new file mode 100644
index 0000000000..72172d8bb4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/612-netfilter_match_reduce_memory_access.patch
@@ -0,0 +1,16 @@
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -85,9 +85,11 @@ ip_packet_match(const struct iphdr *ip,
+ 	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+ 		return true;
+ 
+-	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
++	if (FWINV(ipinfo->smsk.s_addr &&
++		  (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+ 		  IPT_INV_SRCIP) ||
+-	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
++	    FWINV(ipinfo->dmsk.s_addr &&
++		  (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+ 		  IPT_INV_DSTIP)) {
+ 		dprintf("Source or dest mismatch.\n");
+ 
diff --git a/target/linux/generic/patches-4.4/613-netfilter_optional_tcp_window_check.patch b/target/linux/generic/patches-4.4/613-netfilter_optional_tcp_window_check.patch
new file mode 100644
index 0000000000..3740dd74e5
--- /dev/null
+++ b/target/linux/generic/patches-4.4/613-netfilter_optional_tcp_window_check.patch
@@ -0,0 +1,36 @@
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -33,6 +33,9 @@
+ #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+ #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+ 
++/* Do not check the TCP window for incoming packets  */
++static int nf_ct_tcp_no_window_check __read_mostly = 1;
++
+ /* "Be conservative in what you do,
+     be liberal in what you accept from others."
+     If it's non-zero, we mark only out of window RST segments as INVALID. */
+@@ -515,6 +518,9 @@ static bool tcp_in_window(const struct n
+ 	s32 receiver_offset;
+ 	bool res, in_recv_win;
+ 
++	if (nf_ct_tcp_no_window_check)
++		return true;
++
+ 	/*
+ 	 * Get the required data from the packet.
+ 	 */
+@@ -1481,6 +1487,13 @@ static struct ctl_table tcp_sysctl_table
+ 		.mode		= 0644,
+ 		.proc_handler	= proc_dointvec,
+ 	},
++	{
++		.procname       = "nf_conntrack_tcp_no_window_check",
++		.data           = &nf_ct_tcp_no_window_check,
++		.maxlen         = sizeof(unsigned int),
++		.mode           = 0644,
++		.proc_handler   = proc_dointvec,
++	},
+ 	{ }
+ };
+ 
diff --git a/target/linux/generic/patches-4.4/615-netfilter_add_xt_id_match.patch b/target/linux/generic/patches-4.4/615-netfilter_add_xt_id_match.patch
new file mode 100644
index 0000000000..b403c79a07
--- /dev/null
+++ b/target/linux/generic/patches-4.4/615-netfilter_add_xt_id_match.patch
@@ -0,0 +1,95 @@
+--- a/include/uapi/linux/netfilter/Kbuild
++++ b/include/uapi/linux/netfilter/Kbuild
+@@ -55,6 +55,7 @@ header-y += xt_ecn.h
+ header-y += xt_esp.h
+ header-y += xt_hashlimit.h
+ header-y += xt_helper.h
++header-y += xt_id.h
+ header-y += xt_ipcomp.h
+ header-y += xt_iprange.h
+ header-y += xt_ipvs.h
+--- /dev/null
++++ b/include/uapi/linux/netfilter/xt_id.h
+@@ -0,0 +1,8 @@
++#ifndef _XT_ID_H
++#define _XT_ID_H
++
++struct xt_id_info {
++	u32 id;
++};
++
++#endif /* XT_ID_H */
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -1180,6 +1180,13 @@ config NETFILTER_XT_MATCH_IPCOMP
+ 
+ 	  To compile it as a module, choose M here.  If unsure, say N.
+ 
++config NETFILTER_XT_MATCH_ID
++	tristate '"id" match support'
++	depends on NETFILTER_ADVANCED
++	---help---
++	This option adds a `id' dummy-match, which allows you to put
++	numeric IDs into your iptables ruleset.
++
+ config NETFILTER_XT_MATCH_IPRANGE
+ 	tristate '"iprange" address range match support'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -144,6 +144,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) +=
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
++obj-$(CONFIG_NETFILTER_XT_MATCH_ID) += xt_id.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
+ obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
+--- /dev/null
++++ b/net/netfilter/xt_id.c
+@@ -0,0 +1,45 @@
++/*
++ * Implements a dummy match to allow attaching IDs to rules
++ *
++ * 2014-08-01 Jo-Philipp Wich <jo@mein.io>
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter/x_tables.h>
++#include <linux/netfilter/xt_id.h>
++
++MODULE_AUTHOR("Jo-Philipp Wich <jo@mein.io>");
++MODULE_DESCRIPTION("Xtables: No-op match which can be tagged with a 32bit ID");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("ipt_id");
++MODULE_ALIAS("ip6t_id");
++
++static bool
++id_mt(const struct sk_buff *skb, struct xt_action_param *par)
++{
++	/* We always match */
++	return true;
++}
++
++static struct xt_match id_mt_reg __read_mostly = {
++	.name      = "id",
++	.revision  = 0,
++	.family    = NFPROTO_UNSPEC,
++	.match     = id_mt,
++	.matchsize = sizeof(struct xt_id_info),
++	.me        = THIS_MODULE,
++};
++
++static int __init id_mt_init(void)
++{
++	return xt_register_match(&id_mt_reg);
++}
++
++static void __exit id_mt_exit(void)
++{
++	xt_unregister_match(&id_mt_reg);
++}
++
++module_init(id_mt_init);
++module_exit(id_mt_exit);
diff --git a/target/linux/generic/patches-4.4/616-net_optimize_xfrm_calls.patch b/target/linux/generic/patches-4.4/616-net_optimize_xfrm_calls.patch
new file mode 100644
index 0000000000..e4634e321b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/616-net_optimize_xfrm_calls.patch
@@ -0,0 +1,12 @@
+--- a/net/netfilter/nf_nat_core.c
++++ b/net/netfilter/nf_nat_core.c
+@@ -90,6 +90,9 @@ int nf_xfrm_me_harder(struct net *net, s
+ 	struct dst_entry *dst;
+ 	int err;
+ 
++	if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT])
++		return 0;
++
+ 	err = xfrm_decode_session(skb, &fl, family);
+ 	if (err < 0)
+ 		return err;
diff --git a/target/linux/generic/patches-4.4/630-packet_socket_type.patch b/target/linux/generic/patches-4.4/630-packet_socket_type.patch
new file mode 100644
index 0000000000..b14afdde69
--- /dev/null
+++ b/target/linux/generic/patches-4.4/630-packet_socket_type.patch
@@ -0,0 +1,134 @@
+This patch allows the user to specify desired packet types (outgoing,
+broadcast, unicast, etc.) on packet sockets via setsockopt.
+This can reduce the load in situations where only a limited number
+of packet types are necessary
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/include/uapi/linux/if_packet.h
++++ b/include/uapi/linux/if_packet.h
+@@ -31,6 +31,8 @@ struct sockaddr_ll {
+ #define PACKET_KERNEL		7		/* To kernel space	*/
+ /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
+ #define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
++#define PACKET_MASK_ANY		0xffffffff	/* mask for packet type bits */
++
+ 
+ /* Packet socket options */
+ 
+@@ -56,6 +58,7 @@ struct sockaddr_ll {
+ #define PACKET_QDISC_BYPASS		20
+ #define PACKET_ROLLOVER_STATS		21
+ #define PACKET_FANOUT_DATA		22
++#define PACKET_RECV_TYPE		23
+ 
+ #define PACKET_FANOUT_HASH		0
+ #define PACKET_FANOUT_LB		1
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -1763,6 +1763,7 @@ static int packet_rcv_spkt(struct sk_buf
+ {
+ 	struct sock *sk;
+ 	struct sockaddr_pkt *spkt;
++	struct packet_sock *po;
+ 
+ 	/*
+ 	 *	When we registered the protocol we saved the socket in the data
+@@ -1770,6 +1771,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 */
+ 
+ 	sk = pt->af_packet_priv;
++	po = pkt_sk(sk);
+ 
+ 	/*
+ 	 *	Yank back the headers [hope the device set this
+@@ -1782,7 +1784,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 *	so that this procedure is noop.
+ 	 */
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
+ 		goto out;
+ 
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+@@ -1985,12 +1987,12 @@ static int packet_rcv(struct sk_buff *sk
+ 	int skb_len = skb->len;
+ 	unsigned int snaplen, res;
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -2110,12 +2112,12 @@ static int tpacket_rcv(struct sk_buff *s
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -3091,6 +3093,7 @@ static int packet_create(struct net *net
+ 	mutex_init(&po->pg_vec_lock);
+ 	po->rollover = NULL;
+ 	po->prot_hook.func = packet_rcv;
++	po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
+ 
+ 	if (sock->type == SOCK_PACKET)
+ 		po->prot_hook.func = packet_rcv_spkt;
+@@ -3707,6 +3710,16 @@ packet_setsockopt(struct socket *sock, i
+ 		po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
+ 		return 0;
+ 	}
++        case PACKET_RECV_TYPE:
++        {
++                unsigned int val;
++                if (optlen != sizeof(val))
++                        return -EINVAL;
++                if (copy_from_user(&val, optval, sizeof(val)))
++                        return -EFAULT;
++                po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
++                return 0;
++        }
+ 	default:
+ 		return -ENOPROTOOPT;
+ 	}
+@@ -3759,6 +3772,13 @@ static int packet_getsockopt(struct sock
+ 	case PACKET_VNET_HDR:
+ 		val = po->has_vnet_hdr;
+ 		break;
++	case PACKET_RECV_TYPE:
++		if (len > sizeof(unsigned int))
++			len = sizeof(unsigned int);
++		val = po->pkt_type;
++
++		data = &val;
++		break;
+ 	case PACKET_VERSION:
+ 		val = po->tp_version;
+ 		break;
+--- a/net/packet/internal.h
++++ b/net/packet/internal.h
+@@ -129,6 +129,7 @@ struct packet_sock {
+ 	struct net_device __rcu	*cached_dev;
+ 	int			(*xmit)(struct sk_buff *skb);
+ 	struct packet_type	prot_hook ____cacheline_aligned_in_smp;
++	unsigned int		pkt_type;
+ };
+ 
+ static struct packet_sock *pkt_sk(struct sock *sk)
diff --git a/target/linux/generic/patches-4.4/640-bridge_no_eap_forward.patch b/target/linux/generic/patches-4.4/640-bridge_no_eap_forward.patch
new file mode 100644
index 0000000000..24cc2b2961
--- /dev/null
+++ b/target/linux/generic/patches-4.4/640-bridge_no_eap_forward.patch
@@ -0,0 +1,23 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: no EAP forward
+
+When bridging, do not forward EAP frames to other ports, only deliver
+them locally.
+Fixes WPA authentication issues with multiples APs that are connected to
+each other via bridges.
+---
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -168,7 +168,11 @@ int br_handle_frame_finish(struct net *n
+ 	if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
+ 		br_do_proxy_arp(skb, br, vid, p);
+ 
+-	if (is_broadcast_ether_addr(dest)) {
++	if (skb->protocol == htons(ETH_P_PAE)) {
++		skb2 = skb;
++		/* Do not forward 802.1x/EAP frames */
++		skb = NULL;
++	} else if (is_broadcast_ether_addr(dest)) {
+ 		skb2 = skb;
+ 		unicast = false;
+ 	} else if (is_multicast_ether_addr(dest)) {
diff --git a/target/linux/generic/patches-4.4/641-bridge_always_accept_eap.patch b/target/linux/generic/patches-4.4/641-bridge_always_accept_eap.patch
new file mode 100644
index 0000000000..5da6ab64a1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/641-bridge_always_accept_eap.patch
@@ -0,0 +1,17 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: always accept EAP
+
+Allow EAP frames to pass through bridges even in learning state. Fixes
+issues with WDS.
+---
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -152,7 +152,7 @@ int br_handle_frame_finish(struct net *n
+ 	    br_multicast_rcv(br, p, skb, vid))
+ 		goto drop;
+ 
+-	if (p->state == BR_STATE_LEARNING)
++	if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE))
+ 		goto drop;
+ 
+ 	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
diff --git a/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch b/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch
new file mode 100644
index 0000000000..3ece047317
--- /dev/null
+++ b/target/linux/generic/patches-4.4/642-bridge_port_isolate.patch
@@ -0,0 +1,107 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: port isolate
+
+Isolating individual bridge ports
+---
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -45,6 +45,7 @@ struct br_ip_list {
+ #define BR_PROXYARP		BIT(8)
+ #define BR_LEARNING_SYNC	BIT(9)
+ #define BR_PROXYARP_WIFI	BIT(10)
++#define BR_ISOLATE_MODE	BIT(11)
+ 
+ #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
+ 
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -173,6 +173,22 @@ BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD
+ BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
+ BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
+ 
++static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf)
++{
++	int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0;
++	return sprintf(buf, "%d\n", isolate_mode);
++}
++static int store_isolate_mode(struct net_bridge_port *p, unsigned long v)
++{
++	if (v)
++		p->flags |= BR_ISOLATE_MODE;
++	else
++		p->flags &= ~BR_ISOLATE_MODE;
++	return 0;
++}
++static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR,
++		   show_isolate_mode, store_isolate_mode);
++
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
+ {
+@@ -217,6 +233,7 @@ static const struct brport_attribute *br
+ #endif
+ 	&brport_attr_proxyarp,
+ 	&brport_attr_proxyarp_wifi,
++	&brport_attr_isolate_mode,
+ 	NULL
+ };
+ 
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -191,8 +191,8 @@ int br_handle_frame_finish(struct net *n
+ 
+ 		unicast = false;
+ 		br->dev->stats.multicast++;
+-	} else if ((dst = __br_fdb_get(br, dest, vid)) &&
+-			dst->is_local) {
++	} else if ((p->flags & BR_ISOLATE_MODE) ||
++		   ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local)) {
+ 		skb2 = skb;
+ 		/* Do not forward the packet since it's local. */
+ 		skb = NULL;
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -141,7 +141,7 @@ EXPORT_SYMBOL_GPL(br_deliver);
+ /* called with rcu_read_lock */
+ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
+ {
+-	if (to && should_deliver(to, skb)) {
++	if (to && should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) {
+ 		if (skb0)
+ 			deliver_clone(to, skb, __br_forward);
+ 		else
+@@ -197,7 +197,7 @@ static void br_flood(struct net_bridge *
+ 		     struct sk_buff *skb0,
+ 		     void (*__packet_hook)(const struct net_bridge_port *p,
+ 					   struct sk_buff *skb),
+-		     bool unicast)
++		     				bool unicast, bool forward)
+ {
+ 	struct net_bridge_port *p;
+ 	struct net_bridge_port *prev;
+@@ -205,6 +205,8 @@ static void br_flood(struct net_bridge *
+ 	prev = NULL;
+ 
+ 	list_for_each_entry_rcu(p, &br->port_list, list) {
++		if (forward && (p->flags & BR_ISOLATE_MODE))
++			continue;
+ 		/* Do not flood unicast traffic to ports that turn it off */
+ 		if (unicast && !(p->flags & BR_FLOOD))
+ 			continue;
+@@ -239,14 +241,14 @@ out:
+ /* called with rcu_read_lock */
+ void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast)
+ {
+-	br_flood(br, skb, NULL, __br_deliver, unicast);
++	br_flood(br, skb, NULL, __br_deliver, unicast, false);
+ }
+ 
+ /* called under bridge lock */
+ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
+ 		      struct sk_buff *skb2, bool unicast)
+ {
+-	br_flood(br, skb, skb2, __br_forward, unicast);
++	br_flood(br, skb, skb2, __br_forward, unicast, true);
+ }
+ 
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
diff --git a/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch b/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch
new file mode 100644
index 0000000000..f1c7ab1d9c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/645-bridge_multicast_to_unicast.patch
@@ -0,0 +1,420 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: [PATCH] bridge: multicast to unicast
+
+Implement optinal multicast->unicast conversion for igmp snooping
+---
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -46,6 +46,7 @@ struct br_ip_list {
+ #define BR_LEARNING_SYNC	BIT(9)
+ #define BR_PROXYARP_WIFI	BIT(10)
+ #define BR_ISOLATE_MODE	BIT(11)
++#define BR_MULTICAST_TO_UCAST	BIT(12)
+ 
+ #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
+ 
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -42,12 +42,13 @@ static void br_multicast_add_router(stru
+ static void br_ip4_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+ 					 __be32 group,
+-					 __u16 vid);
++					 __u16 vid,
++					 const unsigned char *src);
+ #if IS_ENABLED(CONFIG_IPV6)
+ static void br_ip6_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+ 					 const struct in6_addr *group,
+-					 __u16 vid);
++					 __u16 vid, const unsigned char *src);
+ #endif
+ unsigned int br_mdb_rehash_seq;
+ 
+@@ -652,7 +653,8 @@ struct net_bridge_port_group *br_multica
+ 			struct net_bridge_port *port,
+ 			struct br_ip *group,
+ 			struct net_bridge_port_group __rcu *next,
+-			unsigned char state)
++			unsigned char state,
++			const unsigned char *src)
+ {
+ 	struct net_bridge_port_group *p;
+ 
+@@ -667,12 +669,33 @@ struct net_bridge_port_group *br_multica
+ 	hlist_add_head(&p->mglist, &port->mglist);
+ 	setup_timer(&p->timer, br_multicast_port_group_expired,
+ 		    (unsigned long)p);
++	if ((port->flags & BR_MULTICAST_TO_UCAST) && src) {
++		memcpy(p->eth_addr, src, ETH_ALEN);
++		p->unicast = true;
++	}
+ 	return p;
+ }
+ 
++static bool br_port_group_equal(struct net_bridge_port_group *p,
++				struct net_bridge_port *port,
++				const unsigned char *src)
++{
++	if (p->port != port)
++		return false;
++
++	if (!p->unicast)
++		return true;
++
++	if (!src)
++		return false;
++
++	return ether_addr_equal(src, p->eth_addr);
++}
++
+ static int br_multicast_add_group(struct net_bridge *br,
+ 				  struct net_bridge_port *port,
+-				  struct br_ip *group)
++				  struct br_ip *group,
++				  const unsigned char *src)
+ {
+ 	struct net_bridge_mdb_entry *mp;
+ 	struct net_bridge_port_group *p;
+@@ -699,13 +722,13 @@ static int br_multicast_add_group(struct
+ 	for (pp = &mp->ports;
+ 	     (p = mlock_dereference(*pp, br)) != NULL;
+ 	     pp = &p->next) {
+-		if (p->port == port)
++		if (br_port_group_equal(p, port, src))
+ 			goto found;
+ 		if ((unsigned long)p->port < (unsigned long)port)
+ 			break;
+ 	}
+ 
+-	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
++	p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src);
+ 	if (unlikely(!p))
+ 		goto err;
+ 	rcu_assign_pointer(*pp, p);
+@@ -724,7 +747,7 @@ err:
+ static int br_ip4_multicast_add_group(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      __be32 group,
+-				      __u16 vid)
++				      __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 
+@@ -735,14 +758,14 @@ static int br_ip4_multicast_add_group(st
+ 	br_group.proto = htons(ETH_P_IP);
+ 	br_group.vid = vid;
+ 
+-	return br_multicast_add_group(br, port, &br_group);
++	return br_multicast_add_group(br, port, &br_group, src);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static int br_ip6_multicast_add_group(struct net_bridge *br,
+ 				      struct net_bridge_port *port,
+ 				      const struct in6_addr *group,
+-				      __u16 vid)
++				      __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 
+@@ -753,7 +776,7 @@ static int br_ip6_multicast_add_group(st
+ 	br_group.proto = htons(ETH_P_IPV6);
+ 	br_group.vid = vid;
+ 
+-	return br_multicast_add_group(br, port, &br_group);
++	return br_multicast_add_group(br, port, &br_group, src);
+ }
+ #endif
+ 
+@@ -1003,6 +1026,7 @@ static int br_ip4_multicast_igmp3_report
+ 					 struct sk_buff *skb,
+ 					 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct igmpv3_report *ih;
+ 	struct igmpv3_grec *grec;
+ 	int i;
+@@ -1043,12 +1067,13 @@ static int br_ip4_multicast_igmp3_report
+ 			continue;
+ 		}
+ 
++		src = eth_hdr(skb)->h_source;
+ 		if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
+ 		     type == IGMPV3_MODE_IS_INCLUDE) &&
+ 		    ntohs(grec->grec_nsrcs) == 0) {
+-			br_ip4_multicast_leave_group(br, port, group, vid);
++			br_ip4_multicast_leave_group(br, port, group, vid, src);
+ 		} else {
+-			err = br_ip4_multicast_add_group(br, port, group, vid);
++			err = br_ip4_multicast_add_group(br, port, group, vid, src);
+ 			if (err)
+ 				break;
+ 		}
+@@ -1063,6 +1088,7 @@ static int br_ip6_multicast_mld2_report(
+ 					struct sk_buff *skb,
+ 					u16 vid)
+ {
++	const unsigned char *src = eth_hdr(skb)->h_source;
+ 	struct icmp6hdr *icmp6h;
+ 	struct mld2_grec *grec;
+ 	int i;
+@@ -1114,10 +1140,10 @@ static int br_ip6_multicast_mld2_report(
+ 		     grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
+ 		    ntohs(*nsrcs) == 0) {
+ 			br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
+-						     vid);
++						     vid, src);
+ 		} else {
+ 			err = br_ip6_multicast_add_group(br, port,
+-							 &grec->grec_mca, vid);
++							 &grec->grec_mca, vid, src);
+ 			if (err)
+ 				break;
+ 		}
+@@ -1432,7 +1458,8 @@ br_multicast_leave_group(struct net_brid
+ 			 struct net_bridge_port *port,
+ 			 struct br_ip *group,
+ 			 struct bridge_mcast_other_query *other_query,
+-			 struct bridge_mcast_own_query *own_query)
++			 struct bridge_mcast_own_query *own_query,
++			 const unsigned char *src)
+ {
+ 	struct net_bridge_mdb_htable *mdb;
+ 	struct net_bridge_mdb_entry *mp;
+@@ -1456,7 +1483,7 @@ br_multicast_leave_group(struct net_brid
+ 		for (pp = &mp->ports;
+ 		     (p = mlock_dereference(*pp, br)) != NULL;
+ 		     pp = &p->next) {
+-			if (p->port != port)
++			if (!br_port_group_equal(p, port, src))
+ 				continue;
+ 
+ 			rcu_assign_pointer(*pp, p->next);
+@@ -1519,7 +1546,7 @@ br_multicast_leave_group(struct net_brid
+ 	for (p = mlock_dereference(mp->ports, br);
+ 	     p != NULL;
+ 	     p = mlock_dereference(p->next, br)) {
+-		if (p->port != port)
++		if (!br_port_group_equal(p, port, src))
+ 			continue;
+ 
+ 		if (!hlist_unhashed(&p->mglist) &&
+@@ -1537,8 +1564,8 @@ out:
+ 
+ static void br_ip4_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+-					 __be32 group,
+-					 __u16 vid)
++					 __be32 group, __u16 vid,
++					 const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 	struct bridge_mcast_own_query *own_query;
+@@ -1553,14 +1580,14 @@ static void br_ip4_multicast_leave_group
+ 	br_group.vid = vid;
+ 
+ 	br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
+-				 own_query);
++				 own_query, src);
+ }
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static void br_ip6_multicast_leave_group(struct net_bridge *br,
+ 					 struct net_bridge_port *port,
+ 					 const struct in6_addr *group,
+-					 __u16 vid)
++					 __u16 vid, const unsigned char *src)
+ {
+ 	struct br_ip br_group;
+ 	struct bridge_mcast_own_query *own_query;
+@@ -1575,7 +1602,7 @@ static void br_ip6_multicast_leave_group
+ 	br_group.vid = vid;
+ 
+ 	br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
+-				 own_query);
++				 own_query, src);
+ }
+ #endif
+ 
+@@ -1584,6 +1611,7 @@ static int br_multicast_ipv4_rcv(struct
+ 				 struct sk_buff *skb,
+ 				 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct sk_buff *skb_trimmed = NULL;
+ 	struct igmphdr *ih;
+ 	int err;
+@@ -1600,12 +1628,13 @@ static int br_multicast_ipv4_rcv(struct
+ 
+ 	BR_INPUT_SKB_CB(skb)->igmp = 1;
+ 	ih = igmp_hdr(skb);
++	src = eth_hdr(skb)->h_source;
+ 
+ 	switch (ih->type) {
+ 	case IGMP_HOST_MEMBERSHIP_REPORT:
+ 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
+ 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
+-		err = br_ip4_multicast_add_group(br, port, ih->group, vid);
++		err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
+ 		break;
+ 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
+ 		err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid);
+@@ -1614,7 +1643,7 @@ static int br_multicast_ipv4_rcv(struct
+ 		err = br_ip4_multicast_query(br, port, skb_trimmed, vid);
+ 		break;
+ 	case IGMP_HOST_LEAVE_MESSAGE:
+-		br_ip4_multicast_leave_group(br, port, ih->group, vid);
++		br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
+ 		break;
+ 	}
+ 
+@@ -1630,6 +1659,7 @@ static int br_multicast_ipv6_rcv(struct
+ 				 struct sk_buff *skb,
+ 				 u16 vid)
+ {
++	const unsigned char *src;
+ 	struct sk_buff *skb_trimmed = NULL;
+ 	struct mld_msg *mld;
+ 	int err;
+@@ -1649,8 +1679,9 @@ static int br_multicast_ipv6_rcv(struct
+ 
+ 	switch (mld->mld_type) {
+ 	case ICMPV6_MGM_REPORT:
++		src = eth_hdr(skb)->h_source;
+ 		BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
+-		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
++		err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, src);
+ 		break;
+ 	case ICMPV6_MLD2_REPORT:
+ 		err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid);
+@@ -1659,7 +1690,8 @@ static int br_multicast_ipv6_rcv(struct
+ 		err = br_ip6_multicast_query(br, port, skb_trimmed, vid);
+ 		break;
+ 	case ICMPV6_MGM_REDUCTION:
+-		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
++		src = eth_hdr(skb)->h_source;
++		br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
+ 		break;
+ 	}
+ 
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -157,7 +157,9 @@ struct net_bridge_port_group {
+ 	struct rcu_head			rcu;
+ 	struct timer_list		timer;
+ 	struct br_ip			addr;
++	unsigned char			eth_addr[ETH_ALEN];
+ 	unsigned char			state;
++	bool				unicast;
+ };
+ 
+ struct net_bridge_mdb_entry
+@@ -555,7 +557,8 @@ void br_multicast_free_pg(struct rcu_hea
+ struct net_bridge_port_group *
+ br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
+ 			    struct net_bridge_port_group __rcu *next,
+-			    unsigned char state);
++			    unsigned char state,
++		       const unsigned char *src);
+ void br_mdb_init(void);
+ void br_mdb_uninit(void);
+ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+--- a/net/bridge/br_mdb.c
++++ b/net/bridge/br_mdb.c
+@@ -416,7 +416,7 @@ static int br_mdb_add_group(struct net_b
+ 			break;
+ 	}
+ 
+-	p = br_multicast_new_port_group(port, group, *pp, state);
++	p = br_multicast_new_port_group(port, group, *pp, state, NULL);
+ 	if (unlikely(!p))
+ 		return -ENOMEM;
+ 	rcu_assign_pointer(*pp, p);
+--- a/net/bridge/br_forward.c
++++ b/net/bridge/br_forward.c
+@@ -192,6 +192,34 @@ out:
+ 	return p;
+ }
+ 
++static struct net_bridge_port *maybe_deliver_addr(
++	struct net_bridge_port *prev, struct net_bridge_port *p,
++	struct sk_buff *skb, const unsigned char *addr,
++	void (*__packet_hook)(const struct net_bridge_port *p,
++			      struct sk_buff *skb))
++{
++	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
++	const unsigned char *src = eth_hdr(skb)->h_source;
++
++	if (!should_deliver(p, skb))
++		return prev;
++
++	/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
++	if (skb->dev == p->dev && ether_addr_equal(src, addr))
++		return prev;
++
++	skb = skb_copy(skb, GFP_ATOMIC);
++	if (!skb) {
++		dev->stats.tx_dropped++;
++		return prev;
++	}
++
++	memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
++	__packet_hook(p, skb);
++
++	return prev;
++}
++
+ /* called under bridge lock */
+ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
+ 		     struct sk_buff *skb0,
+@@ -264,6 +292,7 @@ static void br_multicast_flood(struct ne
+ 	struct net_bridge_port *prev = NULL;
+ 	struct net_bridge_port_group *p;
+ 	struct hlist_node *rp;
++	const unsigned char *addr;
+ 
+ 	rp = rcu_dereference(hlist_first_rcu(&br->router_list));
+ 	p = mdst ? rcu_dereference(mdst->ports) : NULL;
+@@ -274,10 +303,19 @@ static void br_multicast_flood(struct ne
+ 		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
+ 			     NULL;
+ 
+-		port = (unsigned long)lport > (unsigned long)rport ?
+-		       lport : rport;
+-
+-		prev = maybe_deliver(prev, port, skb, __packet_hook);
++		if ((unsigned long)lport > (unsigned long)rport) {
++			port = lport;
++			addr = p->unicast ? p->eth_addr : NULL;
++		} else {
++			port = rport;
++			addr = NULL;
++		}
++
++		if (addr)
++			prev = maybe_deliver_addr(prev, port, skb, addr,
++						  __packet_hook);
++		else
++			prev = maybe_deliver(prev, port, skb, __packet_hook);
+ 		if (IS_ERR(prev))
+ 			goto out;
+ 
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -204,6 +204,7 @@ static BRPORT_ATTR(multicast_router, S_I
+ 		   store_multicast_router);
+ 
+ BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
++BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST);
+ #endif
+ 
+ static const struct brport_attribute *brport_attrs[] = {
+@@ -230,6 +231,7 @@ static const struct brport_attribute *br
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ 	&brport_attr_multicast_router,
+ 	&brport_attr_multicast_fast_leave,
++	&brport_attr_multicast_to_unicast,
+ #endif
+ 	&brport_attr_proxyarp,
+ 	&brport_attr_proxyarp_wifi,
diff --git a/target/linux/generic/patches-4.4/650-pppoe_header_pad.patch b/target/linux/generic/patches-4.4/650-pppoe_header_pad.patch
new file mode 100644
index 0000000000..409de58c28
--- /dev/null
+++ b/target/linux/generic/patches-4.4/650-pppoe_header_pad.patch
@@ -0,0 +1,20 @@
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -879,7 +879,7 @@ static int pppoe_sendmsg(struct socket *
+ 		goto end;
+ 
+ 
+-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
++	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD,
+ 			   0, GFP_KERNEL);
+ 	if (!skb) {
+ 		error = -ENOMEM;
+@@ -887,7 +887,7 @@ static int pppoe_sendmsg(struct socket *
+ 	}
+ 
+ 	/* Reserve space for headers. */
+-	skb_reserve(skb, dev->hard_header_len);
++	skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD);
+ 	skb_reset_network_header(skb);
+ 
+ 	skb->dev = dev;
diff --git a/target/linux/generic/patches-4.4/651-wireless_mesh_header.patch b/target/linux/generic/patches-4.4/651-wireless_mesh_header.patch
new file mode 100644
index 0000000000..17bcb6d24d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/651-wireless_mesh_header.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -133,7 +133,7 @@ static inline bool dev_xmit_complete(int
+  */
+ 
+ #if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
+-# if defined(CONFIG_MAC80211_MESH)
++# if 1 || defined(CONFIG_MAC80211_MESH)
+ #  define LL_MAX_HEADER 128
+ # else
+ #  define LL_MAX_HEADER 96
diff --git a/target/linux/generic/patches-4.4/653-disable_netlink_trim.patch b/target/linux/generic/patches-4.4/653-disable_netlink_trim.patch
new file mode 100644
index 0000000000..2f64696c5d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/653-disable_netlink_trim.patch
@@ -0,0 +1,30 @@
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1795,27 +1795,7 @@ void netlink_detachskb(struct sock *sk,
+ 
+ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
+ {
+-	int delta;
+-
+ 	WARN_ON(skb->sk != NULL);
+-	if (netlink_skb_is_mmaped(skb))
+-		return skb;
+-
+-	delta = skb->end - skb->tail;
+-	if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize)
+-		return skb;
+-
+-	if (skb_shared(skb)) {
+-		struct sk_buff *nskb = skb_clone(skb, allocation);
+-		if (!nskb)
+-			return skb;
+-		consume_skb(skb);
+-		skb = nskb;
+-	}
+-
+-	if (!pskb_expand_head(skb, 0, -delta, allocation))
+-		skb->truesize -= delta;
+-
+ 	return skb;
+ }
+ 
diff --git a/target/linux/generic/patches-4.4/655-increase_skb_pad.patch b/target/linux/generic/patches-4.4/655-increase_skb_pad.patch
new file mode 100644
index 0000000000..09685b13bf
--- /dev/null
+++ b/target/linux/generic/patches-4.4/655-increase_skb_pad.patch
@@ -0,0 +1,11 @@
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2180,7 +2180,7 @@ static inline int pskb_network_may_pull(
+  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
+  */
+ #ifndef NET_SKB_PAD
+-#define NET_SKB_PAD	max(32, L1_CACHE_BYTES)
++#define NET_SKB_PAD	max(64, L1_CACHE_BYTES)
+ #endif
+ 
+ int ___pskb_trim(struct sk_buff *skb, unsigned int len);
diff --git a/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch b/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch
new file mode 100644
index 0000000000..46fceffcf1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/660-fq_codel_defaults.patch
@@ -0,0 +1,11 @@
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -471,7 +471,7 @@ static int fq_codel_init(struct Qdisc *s
+ 
+ 	sch->limit = 10*1024;
+ 	q->flows_cnt = 1024;
+-	q->memory_limit = 32 << 20; /* 32 MBytes */
++	q->memory_limit = 4 << 20; /* 4 MBytes */
+ 	q->drop_batch_size = 64;
+ 	q->quantum = psched_mtu(qdisc_dev(sch));
+ 	q->perturbation = prandom_u32();
diff --git a/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch b/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch
new file mode 100644
index 0000000000..3cb950c0db
--- /dev/null
+++ b/target/linux/generic/patches-4.4/661-fq_codel_keep_dropped_stats.patch
@@ -0,0 +1,10 @@
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -219,7 +219,6 @@ static int fq_codel_enqueue(struct sk_bu
+ 		list_add_tail(&flow->flowchain, &q->new_flows);
+ 		q->new_flow_count++;
+ 		flow->deficit = q->quantum;
+-		flow->dropped = 0;
+ 	}
+ 	q->memory_usage += skb->truesize;
+ 	memory_limited = q->memory_usage > q->memory_limit;
diff --git a/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch b/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch
new file mode 100644
index 0000000000..8952ab4e20
--- /dev/null
+++ b/target/linux/generic/patches-4.4/662-use_fq_codel_by_default.patch
@@ -0,0 +1,95 @@
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -3,8 +3,9 @@
+ # 
+ 
+ menuconfig NET_SCHED
+-	bool "QoS and/or fair queueing"
++	def_bool y
+ 	select NET_SCH_FIFO
++	select NET_SCH_FQ_CODEL
+ 	---help---
+ 	  When the kernel has several packets to send out over a network
+ 	  device, it has to decide which ones to send first, which ones to
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -688,7 +688,7 @@ static const struct Qdisc_class_ops fq_c
+ 	.walk		=	fq_codel_walk,
+ };
+ 
+-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
+ 	.cl_ops		=	&fq_codel_class_ops,
+ 	.id		=	"fq_codel",
+ 	.priv_size	=	sizeof(struct fq_codel_sched_data),
+@@ -704,6 +704,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
+ 	.dump_stats =	fq_codel_dump_stats,
+ 	.owner		=	THIS_MODULE,
+ };
++EXPORT_SYMBOL(fq_codel_qdisc_ops);
+ 
+ static int __init fq_codel_module_init(void)
+ {
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -344,6 +344,7 @@ extern struct Qdisc_ops noop_qdisc_ops;
+ extern struct Qdisc_ops pfifo_fast_ops;
+ extern struct Qdisc_ops mq_qdisc_ops;
+ extern struct Qdisc_ops noqueue_qdisc_ops;
++extern struct Qdisc_ops fq_codel_qdisc_ops;
+ extern const struct Qdisc_ops *default_qdisc_ops;
+ 
+ struct Qdisc_class_common {
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -31,7 +31,7 @@
+ #include <net/dst.h>
+ 
+ /* Qdisc to use by default */
+-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
+ EXPORT_SYMBOL(default_qdisc_ops);
+ 
+ /* Main transmission queue. */
+@@ -731,7 +731,7 @@ static void attach_one_default_qdisc(str
+ 				     void *_unused)
+ {
+ 	struct Qdisc *qdisc;
+-	const struct Qdisc_ops *ops = default_qdisc_ops;
++	const struct Qdisc_ops *ops = &fq_codel_qdisc_ops;
+ 
+ 	if (dev->priv_flags & IFF_NO_QUEUE)
+ 		ops = &noqueue_qdisc_ops;
+--- a/net/sched/sch_mq.c
++++ b/net/sched/sch_mq.c
+@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, st
+ 
+ 	for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+ 		dev_queue = netdev_get_tx_queue(dev, ntx);
+-		qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
++		qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops,
+ 					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+ 						    TC_H_MIN(ntx + 1)));
+ 		if (qdisc == NULL)
+--- a/net/sched/sch_mqprio.c
++++ b/net/sched/sch_mqprio.c
+@@ -124,7 +124,7 @@ static int mqprio_init(struct Qdisc *sch
+ 
+ 	for (i = 0; i < dev->num_tx_queues; i++) {
+ 		dev_queue = netdev_get_tx_queue(dev, i);
+-		qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
++		qdisc = qdisc_create_dflt(dev_queue, &fq_codel_qdisc_ops,
+ 					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+ 						    TC_H_MIN(i + 1)));
+ 		if (qdisc == NULL) {
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -1948,7 +1948,7 @@ static int __init pktsched_init(void)
+ 		return err;
+ 	}
+ 
+-	register_qdisc(&pfifo_fast_ops);
++	register_qdisc(&fq_codel_qdisc_ops);
+ 	register_qdisc(&pfifo_qdisc_ops);
+ 	register_qdisc(&bfifo_qdisc_ops);
+ 	register_qdisc(&pfifo_head_drop_qdisc_ops);
diff --git a/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch b/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch
new file mode 100644
index 0000000000..6f72b19358
--- /dev/null
+++ b/target/linux/generic/patches-4.4/663-remove_pfifo_fast.patch
@@ -0,0 +1,142 @@
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -438,139 +438,6 @@ struct Qdisc_ops noqueue_qdisc_ops __rea
+ 	.owner		=	THIS_MODULE,
+ };
+ 
+-static const u8 prio2band[TC_PRIO_MAX + 1] = {
+-	1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
+-};
+-
+-/* 3-band FIFO queue: old style, but should be a bit faster than
+-   generic prio+fifo combination.
+- */
+-
+-#define PFIFO_FAST_BANDS 3
+-
+-/*
+- * Private data for a pfifo_fast scheduler containing:
+- * 	- queues for the three band
+- * 	- bitmap indicating which of the bands contain skbs
+- */
+-struct pfifo_fast_priv {
+-	u32 bitmap;
+-	struct sk_buff_head q[PFIFO_FAST_BANDS];
+-};
+-
+-/*
+- * Convert a bitmap to the first band number where an skb is queued, where:
+- * 	bitmap=0 means there are no skbs on any band.
+- * 	bitmap=1 means there is an skb on band 0.
+- *	bitmap=7 means there are skbs on all 3 bands, etc.
+- */
+-static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0};
+-
+-static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv,
+-					     int band)
+-{
+-	return priv->q + band;
+-}
+-
+-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc)
+-{
+-	if (skb_queue_len(&qdisc->q) < qdisc_dev(qdisc)->tx_queue_len) {
+-		int band = prio2band[skb->priority & TC_PRIO_MAX];
+-		struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-		struct sk_buff_head *list = band2list(priv, band);
+-
+-		priv->bitmap |= (1 << band);
+-		qdisc->q.qlen++;
+-		return __qdisc_enqueue_tail(skb, qdisc, list);
+-	}
+-
+-	return qdisc_drop(skb, qdisc);
+-}
+-
+-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int band = bitmap2band[priv->bitmap];
+-
+-	if (likely(band >= 0)) {
+-		struct sk_buff_head *list = band2list(priv, band);
+-		struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list);
+-
+-		qdisc->q.qlen--;
+-		if (skb_queue_empty(list))
+-			priv->bitmap &= ~(1 << band);
+-
+-		return skb;
+-	}
+-
+-	return NULL;
+-}
+-
+-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int band = bitmap2band[priv->bitmap];
+-
+-	if (band >= 0) {
+-		struct sk_buff_head *list = band2list(priv, band);
+-
+-		return skb_peek(list);
+-	}
+-
+-	return NULL;
+-}
+-
+-static void pfifo_fast_reset(struct Qdisc *qdisc)
+-{
+-	int prio;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+-		__qdisc_reset_queue(qdisc, band2list(priv, prio));
+-
+-	priv->bitmap = 0;
+-	qdisc->qstats.backlog = 0;
+-	qdisc->q.qlen = 0;
+-}
+-
+-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
+-{
+-	struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
+-
+-	memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1);
+-	if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+-		goto nla_put_failure;
+-	return skb->len;
+-
+-nla_put_failure:
+-	return -1;
+-}
+-
+-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
+-{
+-	int prio;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
+-		__skb_queue_head_init(band2list(priv, prio));
+-
+-	/* Can by-pass the queue discipline */
+-	qdisc->flags |= TCQ_F_CAN_BYPASS;
+-	return 0;
+-}
+-
+-struct Qdisc_ops pfifo_fast_ops __read_mostly = {
+-	.id		=	"pfifo_fast",
+-	.priv_size	=	sizeof(struct pfifo_fast_priv),
+-	.enqueue	=	pfifo_fast_enqueue,
+-	.dequeue	=	pfifo_fast_dequeue,
+-	.peek		=	pfifo_fast_peek,
+-	.init		=	pfifo_fast_init,
+-	.reset		=	pfifo_fast_reset,
+-	.dump		=	pfifo_fast_dump,
+-	.owner		=	THIS_MODULE,
+-};
+-
+ static struct lock_class_key qdisc_tx_busylock;
+ 
+ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
diff --git a/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
new file mode 100644
index 0000000000..c4e1904183
--- /dev/null
+++ b/target/linux/generic/patches-4.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
@@ -0,0 +1,496 @@
+From 775d6fe74d1eaec2ba387535b068dde2dc89de9e Mon Sep 17 00:00:00 2001
+From: Steven Barth <steven@midlink.org>
+Date: Thu, 22 May 2014 09:49:05 +0200
+Subject: [PATCH] Add support for MAP-E FMRs (mesh mode)
+
+MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
+between MAP CEs (mesh mode) without the need to forward such data to a
+border relay. This is similar to how 6rd works but for IPv4 over IPv6.
+
+Signed-off-by: Steven Barth <cyrus@openwrt.org>
+---
+ include/net/ip6_tunnel.h       |  13 ++
+ include/uapi/linux/if_tunnel.h |  13 ++
+ net/ipv6/ip6_tunnel.c          | 276 +++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 291 insertions(+), 11 deletions(-)
+
+--- a/include/net/ip6_tunnel.h
++++ b/include/net/ip6_tunnel.h
+@@ -15,6 +15,18 @@
+ /* determine capability on a per-packet basis */
+ #define IP6_TNL_F_CAP_PER_PACKET 0x40000
+ 
++/* IPv6 tunnel FMR */
++struct __ip6_tnl_fmr {
++	struct __ip6_tnl_fmr *next; /* next fmr in list */
++	struct in6_addr ip6_prefix;
++	struct in_addr ip4_prefix;
++
++	__u8 ip6_prefix_len;
++	__u8 ip4_prefix_len;
++	__u8 ea_len;
++	__u8 offset;
++};
++
+ struct __ip6_tnl_parm {
+ 	char name[IFNAMSIZ];	/* name of tunnel device */
+ 	int link;		/* ifindex of underlying L2 interface */
+@@ -25,6 +37,7 @@ struct __ip6_tnl_parm {
+ 	__u32 flags;		/* tunnel flags */
+ 	struct in6_addr laddr;	/* local tunnel end-point address */
+ 	struct in6_addr raddr;	/* remote tunnel end-point address */
++	struct __ip6_tnl_fmr *fmrs;	/* FMRs */
+ 
+ 	__be16			i_flags;
+ 	__be16			o_flags;
+--- a/include/uapi/linux/if_tunnel.h
++++ b/include/uapi/linux/if_tunnel.h
+@@ -57,10 +57,23 @@ enum {
+ 	IFLA_IPTUN_ENCAP_FLAGS,
+ 	IFLA_IPTUN_ENCAP_SPORT,
+ 	IFLA_IPTUN_ENCAP_DPORT,
++	IFLA_IPTUN_FMRS,
+ 	__IFLA_IPTUN_MAX,
+ };
+ #define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
+ 
++enum {
++	IFLA_IPTUN_FMR_UNSPEC,
++	IFLA_IPTUN_FMR_IP6_PREFIX,
++	IFLA_IPTUN_FMR_IP4_PREFIX,
++	IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
++	IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
++	IFLA_IPTUN_FMR_EA_LEN,
++	IFLA_IPTUN_FMR_OFFSET,
++	__IFLA_IPTUN_FMR_MAX,
++};
++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
++
+ enum tunnel_encap_types {
+ 	TUNNEL_ENCAP_NONE,
+ 	TUNNEL_ENCAP_FOU,
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -16,6 +16,8 @@
+  *      as published by the Free Software Foundation; either version
+  *      2 of the License, or (at your option) any later version.
+  *
++ *	Changes:
++ * Steven Barth <cyrus@openwrt.org>:		MAP-E FMR support
+  */
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+@@ -71,11 +73,9 @@ static bool log_ecn_error = true;
+ module_param(log_ecn_error, bool, 0644);
+ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
+ 
+-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
++static u32 HASH(const struct in6_addr *addr)
+ {
+-	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
+-
+-	return hash_32(hash, HASH_SIZE_SHIFT);
++	return hash_32(ipv6_addr_hash(addr), HASH_SIZE_SHIFT);
+ }
+ 
+ static int ip6_tnl_dev_init(struct net_device *dev);
+@@ -230,20 +230,29 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_init);
+ static struct ip6_tnl *
+ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
+ {
+-	unsigned int hash = HASH(remote, local);
++	unsigned int hash = HASH(local);
+ 	struct ip6_tnl *t;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 	struct in6_addr any;
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+-		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+-		    ipv6_addr_equal(remote, &t->parms.raddr) &&
+-		    (t->dev->flags & IFF_UP))
++		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
++				!(t->dev->flags & IFF_UP))
++			continue;
++
++		if (ipv6_addr_equal(remote, &t->parms.raddr))
+ 			return t;
++
++		for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++			if (ipv6_prefix_equal(remote, &fmr->ip6_prefix,
++					fmr->ip6_prefix_len))
++				return t;
++		}
+ 	}
+ 
+ 	memset(&any, 0, sizeof(any));
+-	hash = HASH(&any, local);
++	hash = HASH(local);
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ 		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+ 		    ipv6_addr_any(&t->parms.raddr) &&
+@@ -251,7 +260,7 @@ ip6_tnl_lookup(struct net *net, const st
+ 			return t;
+ 	}
+ 
+-	hash = HASH(remote, &any);
++	hash = HASH(&any);
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ 		if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+ 		    ipv6_addr_any(&t->parms.laddr) &&
+@@ -287,7 +296,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
+ 
+ 	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ 		prio = 1;
+-		h = HASH(remote, local);
++		h = HASH(local);
+ 	}
+ 	return &ip6n->tnls[prio][h];
+ }
+@@ -460,6 +469,12 @@ ip6_tnl_dev_uninit(struct net_device *de
+ 	struct net *net = t->net;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++
+ 	if (dev == ip6n->fb_tnl_dev)
+ 		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
+ 	else
+@@ -846,6 +861,108 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
+ }
+ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
+ 
++
++/**
++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
++ *   @dest: destination IPv6 address buffer
++ *   @skb: received socket buffer
++ *   @fmr: MAP FMR
++ *   @xmit: Calculate for xmit or rcv
++ **/
++static void ip4ip6_fmr_calc(struct in6_addr *dest,
++		const struct iphdr *iph, const uint8_t *end,
++		const struct __ip6_tnl_fmr *fmr, bool xmit)
++{
++	int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
++	u8 *portp = NULL;
++	bool use_dest_addr;
++	const struct iphdr *dsth = iph;
++
++	if ((u8*)dsth >= end)
++		return;
++
++	/* find significant IP header */
++	if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++		if (ih && ((u8*)&ih[1]) <= end && (
++			ih->type == ICMP_DEST_UNREACH ||
++			ih->type == ICMP_SOURCE_QUENCH ||
++			ih->type == ICMP_TIME_EXCEEDED ||
++			ih->type == ICMP_PARAMETERPROB ||
++			ih->type == ICMP_REDIRECT))
++				dsth = (const struct iphdr*)&ih[1];
++	}
++
++	/* in xmit-path use dest port by default and source port only if
++		this is an ICMP reply to something else; vice versa in rcv-path */
++	use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
++
++	/* get dst port */
++	if (((u8*)&dsth[1]) <= end && (
++		dsth->protocol == IPPROTO_UDP ||
++		dsth->protocol == IPPROTO_TCP ||
++		dsth->protocol == IPPROTO_SCTP ||
++		dsth->protocol == IPPROTO_DCCP)) {
++			/* for UDP, TCP, SCTP and DCCP source and dest port
++			follow IPv4 header directly */
++			portp = ((u8*)dsth) + dsth->ihl * 4;
++
++			if (use_dest_addr)
++				portp += sizeof(u16);
++	} else if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++
++		/* use icmp identifier as port */
++		if (((u8*)&ih) <= end && (
++		    (use_dest_addr && (
++		    ih->type == ICMP_ECHOREPLY ||
++			ih->type == ICMP_TIMESTAMPREPLY ||
++			ih->type == ICMP_INFO_REPLY ||
++			ih->type == ICMP_ADDRESSREPLY)) ||
++			(!use_dest_addr && (
++			ih->type == ICMP_ECHO ||
++			ih->type == ICMP_TIMESTAMP ||
++			ih->type == ICMP_INFO_REQUEST ||
++			ih->type == ICMP_ADDRESS)
++			)))
++				portp = (u8*)&ih->un.echo.id;
++	}
++
++	if ((portp && &portp[2] <= end) || psidlen == 0) {
++		int frombyte = fmr->ip6_prefix_len / 8;
++		int fromrem = fmr->ip6_prefix_len % 8;
++		int bytes = sizeof(struct in6_addr) - frombyte;
++		const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
++		u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
++		u64 t = 0;
++
++		/* extract PSID from port and add it to eabits */
++		u16 psidbits = 0;
++		if (psidlen > 0) {
++			psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
++			psidbits >>= 16 - psidlen - fmr->offset;
++			psidbits = (u16)(psidbits << (16 - psidlen));
++			eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
++		}
++
++		/* rewrite destination address */
++		*dest = fmr->ip6_prefix;
++		memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
++		dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
++
++		if (bytes > sizeof(u64))
++			bytes = sizeof(u64);
++
++		/* insert eabits */
++		memcpy(&t, &dest->s6_addr[frombyte], bytes);
++		t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
++			<< (64 - fmr->ea_len - fromrem));
++		t = cpu_to_be64(t | (eabits >> fromrem));
++		memcpy(&dest->s6_addr[frombyte], &t, bytes);
++	}
++}
++
++
+ /**
+  * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
+  *   @skb: received socket buffer
+@@ -891,6 +1008,26 @@ static int ip6_tnl_rcv(struct sk_buff *s
+ 		skb_reset_network_header(skb);
+ 		skb->protocol = htons(protocol);
+ 		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
++		if (protocol == ETH_P_IP &&
++			!ipv6_addr_equal(&ipv6h->saddr, &t->parms.raddr)) {
++				/* Packet didn't come from BR, so lookup FMR */
++				struct __ip6_tnl_fmr *fmr;
++				struct in6_addr expected = t->parms.raddr;
++				for (fmr = t->parms.fmrs; fmr; fmr = fmr->next)
++					if (ipv6_prefix_equal(&ipv6h->saddr,
++						&fmr->ip6_prefix, fmr->ip6_prefix_len))
++							break;
++
++				/* Check that IPv6 matches IPv4 source to prevent spoofing */
++				if (fmr)
++					ip4ip6_fmr_calc(&expected, ip_hdr(skb),
++							skb_tail_pointer(skb), fmr, false);
++
++				if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
++					rcu_read_unlock();
++					goto discard;
++				}
++		}
+ 
+ 		__skb_tunnel_rx(skb, t->dev, t->net);
+ 
+@@ -1226,6 +1363,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ 	__u32 mtu;
+ 	u8 tproto;
+ 	int err;
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	tproto = ACCESS_ONCE(t->parms.proto);
+ 	if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
+@@ -1256,6 +1394,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ 	if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+ 		fl6.flowi6_mark = skb->mark;
+ 
++	/* try to find matching FMR */
++	for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++		unsigned mshift = 32 - fmr->ip4_prefix_len;
++		if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
++				ntohl(ip_hdr(skb)->daddr) >> mshift)
++			break;
++	}
++
++	/* change dstaddr according to FMR */
++	if (fmr)
++		ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true);
++
+ 	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+ 	if (err != 0) {
+ 		if (err == -EMSGSIZE)
+@@ -1370,6 +1520,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
+ 	t->parms.flowinfo = p->flowinfo;
+ 	t->parms.link = p->link;
+ 	t->parms.proto = p->proto;
++
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++	t->parms.fmrs = p->fmrs;
++
+ 	ip6_tnl_dst_reset(t);
+ 	ip6_tnl_link_config(t);
+ 	return 0;
+@@ -1408,6 +1566,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
+ 	p->flowinfo = u->flowinfo;
+ 	p->link = u->link;
+ 	p->proto = u->proto;
++	p->fmrs = NULL;
+ 	memcpy(p->name, u->name, sizeof(u->name));
+ }
+ 
+@@ -1703,6 +1862,15 @@ static int ip6_tnl_validate(struct nlatt
+ 	return 0;
+ }
+ 
++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
++	[IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
++	[IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
++	[IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
++};
++
+ static void ip6_tnl_netlink_parms(struct nlattr *data[],
+ 				  struct __ip6_tnl_parm *parms)
+ {
+@@ -1734,6 +1902,46 @@ static void ip6_tnl_netlink_parms(struct
+ 
+ 	if (data[IFLA_IPTUN_PROTO])
+ 		parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
++
++	if (data[IFLA_IPTUN_FMRS]) {
++		unsigned rem;
++		struct nlattr *fmr;
++		nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
++			struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
++			struct __ip6_tnl_fmr *nfmr;
++
++			nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
++				fmr, ip6_tnl_fmr_policy);
++
++			if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
++				continue;
++
++			nfmr->offset = 6;
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
++				nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
++					sizeof(nfmr->ip6_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
++				nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
++					sizeof(nfmr->ip4_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
++				nfmr->ip6_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
++				nfmr->ip4_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
++				nfmr->ea_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
++				nfmr->offset = nla_get_u8(c);
++
++			nfmr->next = parms->fmrs;
++			parms->fmrs = nfmr;
++		}
++	}
+ }
+ 
+ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
+@@ -1786,6 +1994,12 @@ static void ip6_tnl_dellink(struct net_d
+ 
+ static size_t ip6_tnl_get_size(const struct net_device *dev)
+ {
++	const struct ip6_tnl *t = netdev_priv(dev);
++	struct __ip6_tnl_fmr *c;
++	int fmrs = 0;
++	for (c = t->parms.fmrs; c; c = c->next)
++		++fmrs;
++
+ 	return
+ 		/* IFLA_IPTUN_LINK */
+ 		nla_total_size(4) +
+@@ -1803,6 +2017,24 @@ static size_t ip6_tnl_get_size(const str
+ 		nla_total_size(4) +
+ 		/* IFLA_IPTUN_PROTO */
+ 		nla_total_size(1) +
++		/* IFLA_IPTUN_FMRS */
++		nla_total_size(0) +
++		(
++			/* nest */
++			nla_total_size(0) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX */
++			nla_total_size(sizeof(struct in6_addr)) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX */
++			nla_total_size(sizeof(struct in_addr)) +
++			/* IFLA_IPTUN_FMR_EA_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_OFFSET */
++			nla_total_size(1)
++		) * fmrs +
+ 		0;
+ }
+ 
+@@ -1810,6 +2042,9 @@ static int ip6_tnl_fill_info(struct sk_b
+ {
+ 	struct ip6_tnl *tunnel = netdev_priv(dev);
+ 	struct __ip6_tnl_parm *parm = &tunnel->parms;
++	struct __ip6_tnl_fmr *c;
++	int fmrcnt = 0;
++	struct nlattr *fmrs;
+ 
+ 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
+ 	    nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
+@@ -1818,8 +2053,27 @@ static int ip6_tnl_fill_info(struct sk_b
+ 	    nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
+ 	    nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
+ 	    nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
+-	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto))
++	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
++	    !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
+ 		goto nla_put_failure;
++
++	for (c = parm->fmrs; c; c = c->next) {
++		struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
++		if (!fmr ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
++				sizeof(c->ip6_prefix), &c->ip6_prefix) ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
++				sizeof(c->ip4_prefix), &c->ip4_prefix) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
++				goto nla_put_failure;
++
++		nla_nest_end(skb, fmr);
++	}
++	nla_nest_end(skb, fmrs);
++
+ 	return 0;
+ 
+ nla_put_failure:
+@@ -1843,6 +2097,7 @@ static const struct nla_policy ip6_tnl_p
+ 	[IFLA_IPTUN_FLOWINFO]		= { .type = NLA_U32 },
+ 	[IFLA_IPTUN_FLAGS]		= { .type = NLA_U32 },
+ 	[IFLA_IPTUN_PROTO]		= { .type = NLA_U8 },
++	[IFLA_IPTUN_FMRS]		= { .type = NLA_NESTED },
+ };
+ 
+ static struct rtnl_link_ops ip6_link_ops __read_mostly = {
diff --git a/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
new file mode 100644
index 0000000000..5e84542bf7
--- /dev/null
+++ b/target/linux/generic/patches-4.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
@@ -0,0 +1,249 @@
+From 1b5aaa4b16f6e6471ab1c07b38068197a1b4c395 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Fri, 24 May 2013 14:40:54 +0200
+Subject: [PATCH 1/2] ipv6: allow rejecting with "source address failed policy"
+
+RFC6204 L-14 requires rejecting traffic from invalid addresses with
+ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
+egress policy) on the LAN side, so add an appropriate rule for that.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/net/netns/ipv6.h       |  1 +
+ include/uapi/linux/fib_rules.h |  4 +++
+ include/uapi/linux/rtnetlink.h |  1 +
+ net/ipv4/fib_semantics.c       |  4 +++
+ net/ipv4/fib_trie.c            |  1 +
+ net/ipv4/ipmr.c                |  1 +
+ net/ipv6/fib6_rules.c          |  4 +++
+ net/ipv6/ip6mr.c               |  2 ++
+ net/ipv6/route.c               | 58 +++++++++++++++++++++++++++++++++++++++++-
+ 9 files changed, 75 insertions(+), 1 deletion(-)
+
+--- a/include/net/netns/ipv6.h
++++ b/include/net/netns/ipv6.h
+@@ -63,6 +63,7 @@ struct netns_ipv6 {
+ 	unsigned long		 ip6_rt_last_gc;
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	struct rt6_info         *ip6_prohibit_entry;
++	struct rt6_info		*ip6_policy_failed_entry;
+ 	struct rt6_info         *ip6_blk_hole_entry;
+ 	struct fib6_table       *fib6_local_tbl;
+ 	struct fib_rules_ops    *fib6_rules_ops;
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -64,6 +64,10 @@ enum {
+ 	FR_ACT_BLACKHOLE,	/* Drop without notification */
+ 	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
+ 	FR_ACT_PROHIBIT,	/* Drop with EACCES */
++	FR_ACT_RES9,
++	FR_ACT_RES10,
++	FR_ACT_RES11,
++	FR_ACT_POLICY_FAILED,	/* Drop with EACCES */
+ 	__FR_ACT_MAX,
+ };
+ 
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -210,6 +210,7 @@ enum {
+ 	RTN_THROW,		/* Not in this table		*/
+ 	RTN_NAT,		/* Translate this address	*/
+ 	RTN_XRESOLVE,		/* Use external resolver	*/
++	RTN_POLICY_FAILED,	/* Failed ingress/egress policy */
+ 	__RTN_MAX
+ };
+ 
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
+ 		.error	= -EINVAL,
+ 		.scope	= RT_SCOPE_NOWHERE,
+ 	},
++	[RTN_POLICY_FAILED] = {
++		.error	= -EACCES,
++		.scope	= RT_SCOPE_UNIVERSE,
++	},
+ };
+ 
+ static void rt_fibinfo_free(struct rtable __rcu **rtp)
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2368,6 +2368,7 @@ static const char *const rtn_type_names[
+ 	[RTN_THROW] = "THROW",
+ 	[RTN_NAT] = "NAT",
+ 	[RTN_XRESOLVE] = "XRESOLVE",
++	[RTN_POLICY_FAILED] = "POLICY_FAILED",
+ };
+ 
+ static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
+--- a/net/ipv4/ipmr.c
++++ b/net/ipv4/ipmr.c
+@@ -182,6 +182,7 @@ static int ipmr_rule_action(struct fib_r
+ 	case FR_ACT_UNREACHABLE:
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
++	case FR_ACT_POLICY_FAILED:
+ 		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+--- a/net/ipv6/fib6_rules.c
++++ b/net/ipv6/fib6_rules.c
+@@ -84,6 +84,10 @@ static int fib6_rule_action(struct fib_r
+ 		err = -EACCES;
+ 		rt = net->ipv6.ip6_prohibit_entry;
+ 		goto discard_pkt;
++	case FR_ACT_POLICY_FAILED:
++		err = -EACCES;
++		rt = net->ipv6.ip6_policy_failed_entry;
++		goto discard_pkt;
+ 	}
+ 
+ 	table = fib6_get_table(net, rule->table);
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -167,6 +167,8 @@ static int ip6mr_rule_action(struct fib_
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
+ 		return -EACCES;
++	case FR_ACT_POLICY_FAILED:
++		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+ 		return -EINVAL;
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -90,6 +90,8 @@ static int		ip6_pkt_discard(struct sk_bu
+ static int		ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+ static int		ip6_pkt_prohibit(struct sk_buff *skb);
+ static int		ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
++static int		ip6_pkt_policy_failed(struct sk_buff *skb);
++static int		ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+ static void		ip6_link_failure(struct sk_buff *skb);
+ static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ 					   struct sk_buff *skb, u32 mtu);
+@@ -297,6 +299,21 @@ static const struct rt6_info ip6_prohibi
+ 	.rt6i_ref	= ATOMIC_INIT(1),
+ };
+ 
++static const struct rt6_info ip6_policy_failed_entry_template = {
++	.dst = {
++		.__refcnt	= ATOMIC_INIT(1),
++		.__use		= 1,
++		.obsolete	= DST_OBSOLETE_FORCE_CHK,
++		.error		= -EACCES,
++		.input		= ip6_pkt_policy_failed,
++		.output		= ip6_pkt_policy_failed_out,
++	},
++	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
++	.rt6i_protocol	= RTPROT_KERNEL,
++	.rt6i_metric	= ~(u32) 0,
++	.rt6i_ref	= ATOMIC_INIT(1),
++};
++
+ static const struct rt6_info ip6_blk_hole_entry_template = {
+ 	.dst = {
+ 		.__refcnt	= ATOMIC_INIT(1),
+@@ -1885,6 +1902,11 @@ static struct rt6_info *ip6_route_info_c
+ 			rt->dst.output = ip6_pkt_prohibit_out;
+ 			rt->dst.input = ip6_pkt_prohibit;
+ 			break;
++		case RTN_POLICY_FAILED:
++			rt->dst.error = -EACCES;
++			rt->dst.output = ip6_pkt_policy_failed_out;
++			rt->dst.input = ip6_pkt_policy_failed;
++			break;
+ 		case RTN_THROW:
+ 		case RTN_UNREACHABLE:
+ 		default:
+@@ -2486,6 +2508,17 @@ static int ip6_pkt_prohibit_out(struct n
+ 	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
+ }
+ 
++static int ip6_pkt_policy_failed(struct sk_buff *skb)
++{
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
++}
++
++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb)
++{
++	skb->dev = skb_dst(skb)->dev;
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
++}
++
+ /*
+  *	Allocate a dst for local (unicast / anycast) address.
+  */
+@@ -2728,7 +2761,8 @@ static int rtm_to_fib6_config(struct sk_
+ 	if (rtm->rtm_type == RTN_UNREACHABLE ||
+ 	    rtm->rtm_type == RTN_BLACKHOLE ||
+ 	    rtm->rtm_type == RTN_PROHIBIT ||
+-	    rtm->rtm_type == RTN_THROW)
++	    rtm->rtm_type == RTN_THROW ||
++	    rtm->rtm_type == RTN_POLICY_FAILED)
+ 		cfg->fc_flags |= RTF_REJECT;
+ 
+ 	if (rtm->rtm_type == RTN_LOCAL)
+@@ -3087,6 +3121,9 @@ static int rt6_fill_node(struct net *net
+ 		case -EACCES:
+ 			rtm->rtm_type = RTN_PROHIBIT;
+ 			break;
++		case -EPERM:
++			rtm->rtm_type = RTN_POLICY_FAILED;
++			break;
+ 		case -EAGAIN:
+ 			rtm->rtm_type = RTN_THROW;
+ 			break;
+@@ -3362,6 +3399,8 @@ static int ip6_route_dev_notify(struct n
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
+ 		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
++		net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
++		net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
+ 		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
+ 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
+ #endif
+@@ -3578,6 +3617,17 @@ static int __net_init ip6_route_net_init
+ 	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+ 	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
+ 			 ip6_template_metrics, true);
++
++	net->ipv6.ip6_policy_failed_entry =
++		kmemdup(&ip6_policy_failed_entry_template,
++			sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
++	if (!net->ipv6.ip6_policy_failed_entry)
++		goto out_ip6_blk_hole_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.path =
++		(struct dst_entry *)net->ipv6.ip6_policy_failed_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
++	dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
++			 ip6_template_metrics, true);
+ #endif
+ 
+ 	net->ipv6.sysctl.flush_delay = 0;
+@@ -3596,6 +3646,8 @@ out:
+ 	return ret;
+ 
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
++out_ip6_blk_hole_entry:
++	kfree(net->ipv6.ip6_blk_hole_entry);
+ out_ip6_prohibit_entry:
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ out_ip6_null_entry:
+@@ -3613,6 +3665,7 @@ static void __net_exit ip6_route_net_exi
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ 	kfree(net->ipv6.ip6_blk_hole_entry);
++	kfree(net->ipv6.ip6_policy_failed_entry);
+ #endif
+ 	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
+ }
+@@ -3710,6 +3763,9 @@ int __init ip6_route_init(void)
+ 	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ 	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+ 	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
++	init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
++	init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
++		in6_dev_get(init_net.loopback_dev);
+   #endif
+ 	ret = fib6_init();
+ 	if (ret)
diff --git a/target/linux/generic/patches-4.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/patches-4.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
new file mode 100644
index 0000000000..dafb56cd8b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
@@ -0,0 +1,53 @@
+From 7749b481ce5d7e232b1f7da5e6b2c44816f51681 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo@openwrt.org>
+Date: Sun, 19 Jan 2014 20:45:51 +0100
+Subject: [PATCH 2/2] net: provide defines for _POLICY_FAILED until all code is
+ updated
+
+Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination
+unreachable, conflicting with our name.
+
+Add appropriate defines to allow our code to build with the new
+name until we have updated our local patches for older kernels
+and userspace packages.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/fib_rules.h | 2 ++
+ include/uapi/linux/icmpv6.h    | 2 ++
+ include/uapi/linux/rtnetlink.h | 2 ++
+ 3 files changed, 6 insertions(+)
+
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -71,6 +71,8 @@ enum {
+ 	__FR_ACT_MAX,
+ };
+ 
++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED
++
+ #define FR_ACT_MAX (__FR_ACT_MAX - 1)
+ 
+ #endif
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -118,6 +118,8 @@ struct icmp6hdr {
+ #define ICMPV6_POLICY_FAIL		5
+ #define ICMPV6_REJECT_ROUTE		6
+ 
++#define ICMPV6_FAILED_POLICY		ICMPV6_POLICY_FAIL
++
+ /*
+  *	Codes for Time Exceeded
+  */
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -214,6 +214,8 @@ enum {
+ 	__RTN_MAX
+ };
+ 
++#define RTN_FAILED_POLICY RTN_POLICY_FAILED
++
+ #define RTN_MAX (__RTN_MAX - 1)
+ 
+ 
diff --git a/target/linux/generic/patches-4.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/patches-4.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
new file mode 100644
index 0000000000..698d394b8c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
@@ -0,0 +1,160 @@
+Subject: NET: skip GRO for foreign MAC addresses
+
+For network drivers using napi_gro_receive, packets are run through GRO,
+even when the destination MAC address does not match, and they're supposed
+to be delivered to another host behind a different bridge port.
+
+This can be very expensive, because for drivers without TSO or scatter-
+gather, this can only be undone by copying the skb and checksumming it
+again.
+
+To be able to track foreign MAC addresses in an inexpensive way, create
+a mask of changed bits in MAC addresses of upper devices. This allows
+handling VLANs and bridge devices with different addresses (as long as
+they are not too different).
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -4222,6 +4222,9 @@ static enum gro_result dev_gro_receive(s
+ 	enum gro_result ret;
+ 	int grow;
+ 
++	if (skb->gro_skip)
++		goto normal;
++
+ 	if (!(skb->dev->features & NETIF_F_GRO))
+ 		goto normal;
+ 
+@@ -5381,6 +5384,48 @@ static void __netdev_adjacent_dev_unlink
+ 					   &upper_dev->adj_list.lower);
+ }
+ 
++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
++			       struct net_device *dev)
++{
++	int i;
++
++	for (i = 0; i < dev->addr_len; i++)
++		mask[i] |= addr[i] ^ dev->dev_addr[i];
++}
++
++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
++				struct net_device *lower)
++{
++	struct net_device *cur;
++	struct list_head *iter;
++
++	netdev_for_each_upper_dev_rcu(dev, cur, iter) {
++		__netdev_addr_mask(mask, cur->dev_addr, lower);
++		__netdev_upper_mask(mask, cur, lower);
++	}
++}
++
++static void __netdev_update_addr_mask(struct net_device *dev)
++{
++	unsigned char mask[MAX_ADDR_LEN];
++	struct net_device *cur;
++	struct list_head *iter;
++
++	memset(mask, 0, sizeof(mask));
++	__netdev_upper_mask(mask, dev, dev);
++	memcpy(dev->local_addr_mask, mask, dev->addr_len);
++
++	netdev_for_each_lower_dev(dev, cur, iter)
++		__netdev_update_addr_mask(cur);
++}
++
++static void netdev_update_addr_mask(struct net_device *dev)
++{
++	rcu_read_lock();
++	__netdev_update_addr_mask(dev);
++	rcu_read_unlock();
++}
++
+ static int __netdev_upper_dev_link(struct net_device *dev,
+ 				   struct net_device *upper_dev, bool master,
+ 				   void *private)
+@@ -5452,6 +5497,7 @@ static int __netdev_upper_dev_link(struc
+ 			goto rollback_lower_mesh;
+ 	}
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
+ 				      &changeupper_info.info);
+ 	return 0;
+@@ -5578,6 +5624,7 @@ void netdev_upper_dev_unlink(struct net_
+ 	list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
+ 		__netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
+ 				      &changeupper_info.info);
+ }
+@@ -6118,6 +6165,7 @@ int dev_set_mac_address(struct net_devic
+ 	if (err)
+ 		return err;
+ 	dev->addr_assign_type = NET_ADDR_SET;
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ 	add_device_randomness(dev->dev_addr, dev->addr_len);
+ 	return 0;
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1637,6 +1637,8 @@ struct net_device {
+ 	struct netdev_hw_addr_list	mc;
+ 	struct netdev_hw_addr_list	dev_addrs;
+ 
++	unsigned char		local_addr_mask[MAX_ADDR_LEN];
++
+ #ifdef CONFIG_SYSFS
+ 	struct kset		*queues_kset;
+ #endif
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -642,7 +642,8 @@ struct sk_buff {
+ 	__u8			ipvs_property:1;
+ 	__u8			inner_protocol_type:1;
+ 	__u8			remcsum_offload:1;
+-	/* 3 or 5 bit hole */
++	__u8			gro_skip:1;
++	/* 2 or 4 bit hole */
+ 
+ #ifdef CONFIG_NET_SCHED
+ 	__u16			tc_index;	/* traffic control index */
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -140,6 +140,18 @@ u32 eth_get_headlen(void *data, unsigned
+ }
+ EXPORT_SYMBOL(eth_get_headlen);
+ 
++static inline bool
++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
++{
++	const u16 *a1 = addr1;
++	const u16 *a2 = addr2;
++	const u16 *m = mask;
++
++	return (((a1[0] ^ a2[0]) & ~m[0]) |
++		((a1[1] ^ a2[1]) & ~m[1]) |
++		((a1[2] ^ a2[2]) & ~m[2]));
++}
++
+ /**
+  * eth_type_trans - determine the packet's protocol ID.
+  * @skb: received socket data
+@@ -168,8 +180,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 			skb->pkt_type = PACKET_MULTICAST;
+ 	}
+ 	else if (unlikely(!ether_addr_equal_64bits(eth->h_dest,
+-						   dev->dev_addr)))
++						   dev->dev_addr))) {
+ 		skb->pkt_type = PACKET_OTHERHOST;
++		if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
++					 dev->local_addr_mask))
++			skb->gro_skip = 1;
++	}
+ 
+ 	/*
+ 	 * Some variants of DSA tagging don't have an ethertype field
diff --git a/target/linux/generic/patches-4.4/681-NET-add-of_get_mac_address_mtd.patch b/target/linux/generic/patches-4.4/681-NET-add-of_get_mac_address_mtd.patch
new file mode 100644
index 0000000000..2044872973
--- /dev/null
+++ b/target/linux/generic/patches-4.4/681-NET-add-of_get_mac_address_mtd.patch
@@ -0,0 +1,128 @@
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:40:01 +0100
+Subject: NET: add mtd-mac-address support to of_get_mac_address()
+
+Many embedded devices have information such as mac addresses stored inside mtd
+devices. This patch allows us to add a property inside a node describing a
+network interface. The new property points at a mtd partition with an offset
+where the mac address can be found.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/of/of_net.c    |   37 +++++++++++++++++++++++++++++++++++++
+ include/linux/of_net.h |    1 +
+ 2 files changed, 38 insertions(+)
+
+--- a/drivers/of/of_net.c
++++ b/drivers/of/of_net.c
+@@ -10,6 +10,7 @@
+ #include <linux/of_net.h>
+ #include <linux/phy.h>
+ #include <linux/export.h>
++#include <linux/mtd/mtd.h>
+ 
+ /**
+  * of_get_phy_mode - Get phy mode for given device_node
+@@ -38,7 +39,7 @@ int of_get_phy_mode(struct device_node *
+ }
+ EXPORT_SYMBOL_GPL(of_get_phy_mode);
+ 
+-static const void *of_get_mac_addr(struct device_node *np, const char *name)
++static void *of_get_mac_addr(struct device_node *np, const char *name)
+ {
+ 	struct property *pp = of_find_property(np, name, NULL);
+ 
+@@ -47,6 +48,73 @@ static const void *of_get_mac_addr(struc
+ 	return NULL;
+ }
+ 
++static const void *of_get_mac_address_mtd(struct device_node *np)
++{
++#ifdef CONFIG_MTD
++	struct device_node *mtd_np = NULL;
++	struct property *prop;
++	size_t retlen;
++	int size, ret;
++	struct mtd_info *mtd;
++	const char *part;
++	const __be32 *list;
++	phandle phandle;
++	u32 mac_inc = 0;
++	u8 mac[ETH_ALEN];
++	void *addr;
++
++	list = of_get_property(np, "mtd-mac-address", &size);
++	if (!list || (size != (2 * sizeof(*list))))
++		return NULL;
++
++	phandle = be32_to_cpup(list++);
++	if (phandle)
++		mtd_np = of_find_node_by_phandle(phandle);
++
++	if (!mtd_np)
++		return NULL;
++
++	part = of_get_property(mtd_np, "label", NULL);
++	if (!part)
++		part = mtd_np->name;
++
++	mtd = get_mtd_device_nm(part);
++	if (IS_ERR(mtd))
++		return NULL;
++
++	ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
++	put_mtd_device(mtd);
++
++	if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
++		mac[5] += mac_inc;
++
++	if (!is_valid_ether_addr(mac))
++		return NULL;
++
++	addr = of_get_mac_addr(np, "mac-address");
++	if (addr) {
++		memcpy(addr, mac, ETH_ALEN);
++		return addr;
++	}
++
++	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
++	if (!prop)
++		return NULL;
++
++	prop->name = "mac-address";
++	prop->length = ETH_ALEN;
++	prop->value = kmemdup(mac, ETH_ALEN, GFP_KERNEL);
++	if (!prop->value || of_add_property(np, prop))
++		goto free;
++
++	return prop->value;
++free:
++	kfree(prop->value);
++	kfree(prop);
++#endif
++	return NULL;
++}
++
+ /**
+  * Search the device tree for the best MAC address to use.  'mac-address' is
+  * checked first, because that is supposed to contain to "most recent" MAC
+@@ -64,11 +132,18 @@ static const void *of_get_mac_addr(struc
+  * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
+  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
+  * but is all zeros.
++ *
++ * If a mtd-mac-address property exists, try to fetch the MAC address from the
++ * specified mtd device, and store it as a 'mac-address' property
+ */
+ const void *of_get_mac_address(struct device_node *np)
+ {
+ 	const void *addr;
+ 
++	addr = of_get_mac_address_mtd(np);
++	if (addr)
++		return addr;
++
+ 	addr = of_get_mac_addr(np, "mac-address");
+ 	if (addr)
+ 		return addr;
diff --git a/target/linux/generic/patches-4.4/700-swconfig.patch b/target/linux/generic/patches-4.4/700-swconfig.patch
new file mode 100644
index 0000000000..122dd446c6
--- /dev/null
+++ b/target/linux/generic/patches-4.4/700-swconfig.patch
@@ -0,0 +1,39 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,16 @@ menuconfig PHYLIB
+ 
+ if PHYLIB
+ 
++config SWCONFIG
++	tristate "Switch configuration API"
++	---help---
++	  Switch configuration API using netlink. This allows
++	  you to configure the VLAN features of certain switches.
++
++config SWCONFIG_LEDS
++	bool "Switch LED trigger support"
++	depends on (SWCONFIG && LEDS_TRIGGERS)
++
+ comment "MII PHY device drivers"
+ 
+ config AQUANTIA_PHY
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -3,6 +3,7 @@
+ libphy-objs			:= phy.o phy_device.o mdio_bus.o
+ 
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
++obj-$(CONFIG_SWCONFIG)		+= swconfig.o
+ obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+ obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
+--- a/include/uapi/linux/Kbuild
++++ b/include/uapi/linux/Kbuild
+@@ -388,6 +388,7 @@ header-y += stddef.h
+ header-y += string.h
+ header-y += suspend_ioctls.h
+ header-y += swab.h
++header-y += switch.h
+ header-y += synclink.h
+ header-y += sysctl.h
+ header-y += sysinfo.h
diff --git a/target/linux/generic/patches-4.4/701-phy_extension.patch b/target/linux/generic/patches-4.4/701-phy_extension.patch
new file mode 100644
index 0000000000..6cb3fdfd44
--- /dev/null
+++ b/target/linux/generic/patches-4.4/701-phy_extension.patch
@@ -0,0 +1,63 @@
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -385,6 +385,50 @@ int phy_ethtool_gset(struct phy_device *
+ }
+ EXPORT_SYMBOL(phy_ethtool_gset);
+ 
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
++{
++	u32 cmd;
++	int tmp;
++	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++	struct ethtool_value edata = { ETHTOOL_GLINK };
++
++	if (get_user(cmd, (u32 *) useraddr))
++		return -EFAULT;
++
++	switch (cmd) {
++	case ETHTOOL_GSET:
++		phy_ethtool_gset(phydev, &ecmd);
++		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++			return -EFAULT;
++		return 0;
++
++	case ETHTOOL_SSET:
++		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++			return -EFAULT;
++		return phy_ethtool_sset(phydev, &ecmd);
++
++	case ETHTOOL_NWAY_RST:
++		/* if autoneg is off, it's an error */
++		tmp = phy_read(phydev, MII_BMCR);
++		if (tmp & BMCR_ANENABLE) {
++			tmp |= (BMCR_ANRESTART);
++			phy_write(phydev, MII_BMCR, tmp);
++			return 0;
++		}
++		return -EINVAL;
++
++	case ETHTOOL_GLINK:
++		edata.data = (phy_read(phydev,
++				MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
++		if (copy_to_user(useraddr, &edata, sizeof(edata)))
++			return -EFAULT;
++		return 0;
++	}
++
++	return -EOPNOTSUPP;
++}
++EXPORT_SYMBOL(phy_ethtool_ioctl);
++
+ /**
+  * phy_mii_ioctl - generic PHY MII ioctl interface
+  * @phydev: the phy_device struct
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -796,6 +796,7 @@ void phy_start_machine(struct phy_device
+ void phy_stop_machine(struct phy_device *phydev);
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
+ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
+ int phy_start_interrupts(struct phy_device *phydev);
+ void phy_print_status(struct phy_device *phydev);
diff --git a/target/linux/generic/patches-4.4/702-phy_add_aneg_done_function.patch b/target/linux/generic/patches-4.4/702-phy_add_aneg_done_function.patch
new file mode 100644
index 0000000000..f16efa495e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/702-phy_add_aneg_done_function.patch
@@ -0,0 +1,27 @@
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -501,6 +501,12 @@ struct phy_driver {
+ 	/* Determines the negotiated speed and duplex */
+ 	int (*read_status)(struct phy_device *phydev);
+ 
++	/* 
++	 * Update the value in phydev->link to reflect the 
++	 * current link value
++	 */
++	int (*update_link)(struct phy_device *phydev);
++
+ 	/* Clears any pending interrupts */
+ 	int (*ack_interrupt)(struct phy_device *phydev);
+ 
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -995,6 +995,9 @@ int genphy_update_link(struct phy_device
+ {
+ 	int status;
+ 
++	if (phydev->drv->update_link)
++		return phydev->drv->update_link(phydev);
++
+ 	/* Do a fake read */
+ 	status = phy_read(phydev, MII_BMSR);
+ 	if (status < 0)
diff --git a/target/linux/generic/patches-4.4/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/patches-4.4/703-phy-add-detach-callback-to-struct-phy_driver.patch
new file mode 100644
index 0000000000..5babfdf5e2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/703-phy-add-detach-callback-to-struct-phy_driver.patch
@@ -0,0 +1,27 @@
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -734,6 +734,9 @@ void phy_detach(struct phy_device *phyde
+ 	struct mii_bus *bus;
+ 	int i;
+ 
++	if (phydev->drv && phydev->drv->detach)
++		phydev->drv->detach(phydev);
++
+ 	phydev->attached_dev->phydev = NULL;
+ 	phydev->attached_dev = NULL;
+ 	phy_suspend(phydev);
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -519,6 +519,12 @@ struct phy_driver {
+ 	 */
+ 	int (*did_interrupt)(struct phy_device *phydev);
+ 
++	/*
++	 * Called before an ethernet device is detached
++	 * from the PHY.
++	 */
++	void (*detach)(struct phy_device *phydev);
++
+ 	/* Clears up any memory if needed */
+ 	void (*remove)(struct phy_device *phydev);
+ 
diff --git a/target/linux/generic/patches-4.4/704-phy-no-genphy-soft-reset.patch b/target/linux/generic/patches-4.4/704-phy-no-genphy-soft-reset.patch
new file mode 100644
index 0000000000..d876187d7c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/704-phy-no-genphy-soft-reset.patch
@@ -0,0 +1,29 @@
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1213,7 +1213,7 @@ int genphy_config_init(struct phy_device
+ 	return 0;
+ }
+ 
+-static int gen10g_soft_reset(struct phy_device *phydev)
++static int no_soft_reset(struct phy_device *phydev)
+ {
+ 	/* Do nothing for now */
+ 	return 0;
+@@ -1448,7 +1448,7 @@ static struct phy_driver genphy_driver[]
+ 	.phy_id		= 0xffffffff,
+ 	.phy_id_mask	= 0xffffffff,
+ 	.name		= "Generic PHY",
+-	.soft_reset	= genphy_soft_reset,
++	.soft_reset	= no_soft_reset,
+ 	.config_init	= genphy_config_init,
+ 	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
+ 			  SUPPORTED_AUI | SUPPORTED_FIBRE |
+@@ -1463,7 +1463,7 @@ static struct phy_driver genphy_driver[]
+ 	.phy_id         = 0xffffffff,
+ 	.phy_id_mask    = 0xffffffff,
+ 	.name           = "Generic 10G PHY",
+-	.soft_reset	= gen10g_soft_reset,
++	.soft_reset	= no_soft_reset,
+ 	.config_init    = gen10g_config_init,
+ 	.features       = 0,
+ 	.config_aneg    = gen10g_config_aneg,
diff --git a/target/linux/generic/patches-4.4/710-phy-add-mdio_register_board_info.patch b/target/linux/generic/patches-4.4/710-phy-add-mdio_register_board_info.patch
new file mode 100644
index 0000000000..4886dd0e3a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/710-phy-add-mdio_register_board_info.patch
@@ -0,0 +1,193 @@
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -38,6 +38,8 @@
+ 
+ #include <asm/irq.h>
+ 
++#include "mdio-boardinfo.h"
++
+ /**
+  * mdiobus_alloc_size - allocate a mii_bus structure
+  * @size: extra amount of memory to allocate for private storage.
+@@ -346,9 +348,21 @@ void mdiobus_free(struct mii_bus *bus)
+ }
+ EXPORT_SYMBOL(mdiobus_free);
+ 
++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus,
++						struct phy_device *phydev,
++						struct mdio_board_info *bi)
++{
++	if (strcmp(bus->id, bi->bus_id) ||
++	    bi->phy_addr != phydev->addr)
++	    return;
++
++	phydev->dev.platform_data = (void *) bi->platform_data;
++}
++
+ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+ {
+ 	struct phy_device *phydev;
++	struct mdio_board_entry *be;
+ 	int err;
+ 
+ 	phydev = get_phy_device(bus, addr, false);
+@@ -361,6 +375,12 @@ struct phy_device *mdiobus_scan(struct m
+ 	 */
+ 	of_mdiobus_link_phydev(bus, phydev);
+ 
++	mutex_lock(&__mdio_board_lock);
++	list_for_each_entry(be, &__mdio_board_list, list)
++		mdiobus_setup_phydev_from_boardinfo(bus, phydev,
++						    &be->board_info);
++	mutex_unlock(&__mdio_board_lock);
++
+ 	err = phy_device_register(phydev);
+ 	if (err) {
+ 		phy_device_free(phydev);
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -835,6 +835,23 @@ void mdio_bus_exit(void);
+ 
+ extern struct bus_type mdio_bus_type;
+ 
++struct mdio_board_info {
++	const char	*bus_id;
++	int		phy_addr;
++
++	const void	*platform_data;
++};
++
++#ifdef CONFIG_MDIO_BOARDINFO
++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n);
++#else
++static inline int
++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n)
++{
++	return 0;
++}
++#endif
++
+ /**
+  * module_phy_driver() - Helper macro for registering PHY drivers
+  * @__phy_drivers: array of PHY drivers to register
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,10 @@ menuconfig PHYLIB
+ 
+ if PHYLIB
+ 
++config MDIO_BOARDINFO
++	bool
++	default y
++
+ config SWCONFIG
+ 	tristate "Switch configuration API"
+ 	---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -2,6 +2,8 @@
+ 
+ libphy-objs			:= phy.o phy_device.o mdio_bus.o
+ 
++obj-$(CONFIG_MDIO_BOARDINFO)	+= mdio-boardinfo.o
++
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
+ obj-$(CONFIG_SWCONFIG)		+= swconfig.o
+ obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.c
+@@ -0,0 +1,58 @@
++/*
++ * mdio-boardinfo.c - collect pre-declarations of PHY devices
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/phy.h>
++#include <linux/slab.h>
++#include <linux/export.h>
++#include <linux/mutex.h>
++#include <linux/phy.h>
++
++#include "mdio-boardinfo.h"
++
++/*
++ * These symbols are exported ONLY FOR the mdio_bus component.
++ * No other users will be supported.
++ */
++
++LIST_HEAD(__mdio_board_list);
++EXPORT_SYMBOL_GPL(__mdio_board_list);
++
++DEFINE_MUTEX(__mdio_board_lock);
++EXPORT_SYMBOL_GPL(__mdio_board_lock);
++
++/**
++ * mdio_register_board_info - register PHY devices for a given board
++ * @info: array of chip descriptors
++ * @n: how many descriptors are provided
++ * Context: can sleep
++ *
++ * The board info passed can safely be __initdata ... but be careful of
++ * any embedded pointers (platform_data, etc), they're copied as-is.
++ */
++int __init
++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n)
++{
++	struct mdio_board_entry *be;
++	int i;
++
++	be = kzalloc(n * sizeof(*be), GFP_KERNEL);
++	if (!be)
++		return -ENOMEM;
++
++	for (i = 0; i < n; i++, be++, info++) {
++		memcpy(&be->board_info, info, sizeof(*info));
++		mutex_lock(&__mdio_board_lock);
++		list_add_tail(&be->list, &__mdio_board_list);
++		mutex_unlock(&__mdio_board_lock);
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.h
+@@ -0,0 +1,22 @@
++/*
++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component
++ *
++ * This program is free software; you can redistribute  it and/or modify it
++ * under  the terms of  the GNU General  Public License as published by the
++ * Free Software Foundation;  either version 2 of the  License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/mutex.h>
++
++struct mdio_board_entry {
++	struct list_head	list;
++	struct mdio_board_info	board_info;
++};
++
++/* __mdio_board_lock protects __mdio_board_list
++ * only mdio_bus components are allowed to use these symbols.
++ */
++extern struct mutex __mdio_board_lock;
++extern struct list_head __mdio_board_list;
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -16,7 +16,7 @@ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_MDIO) += mdio.o
+ obj-$(CONFIG_NET) += Space.o loopback.o
+ obj-$(CONFIG_NETCONSOLE) += netconsole.o
+-obj-$(CONFIG_PHYLIB) += phy/
++obj-y += phy/
+ obj-$(CONFIG_RIONET) += rionet.o
+ obj-$(CONFIG_NET_TEAM) += team/
+ obj-$(CONFIG_TUN) += tun.o
diff --git a/target/linux/generic/patches-4.4/720-phy_adm6996.patch b/target/linux/generic/patches-4.4/720-phy_adm6996.patch
new file mode 100644
index 0000000000..3ee02f1005
--- /dev/null
+++ b/target/linux/generic/patches-4.4/720-phy_adm6996.patch
@@ -0,0 +1,26 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -170,6 +170,13 @@ config MICROCHIP_PHY
+ 	help
+ 	  Supports the LAN88XX PHYs.
+ 
++config ADM6996_PHY
++	tristate "Driver for ADM6996 switches"
++	select SWCONFIG
++	---help---
++	  Currently supports the ADM6996FC and ADM6996M switches.
++	  Support for FC is very limited.
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
+ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_BCM_CYGNUS_PHY)	+= bcm-cygnus.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
++obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
diff --git a/target/linux/generic/patches-4.4/721-phy_packets.patch b/target/linux/generic/patches-4.4/721-phy_packets.patch
new file mode 100644
index 0000000000..7f288f884c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/721-phy_packets.patch
@@ -0,0 +1,161 @@
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1297,6 +1297,7 @@ enum netdev_priv_flags {
+ 	IFF_NO_QUEUE			= 1<<21,
+ 	IFF_OPENVSWITCH			= 1<<22,
+ 	IFF_L3MDEV_SLAVE		= 1<<23,
++	IFF_NO_IP_ALIGN			= 1<<24,
+ };
+ 
+ #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
+@@ -1323,6 +1324,7 @@ enum netdev_priv_flags {
+ #define IFF_NO_QUEUE			IFF_NO_QUEUE
+ #define IFF_OPENVSWITCH			IFF_OPENVSWITCH
+ #define IFF_L3MDEV_SLAVE		IFF_L3MDEV_SLAVE
++#define IFF_NO_IP_ALIGN			IFF_NO_IP_ALIGN
+ 
+ /**
+  *	struct net_device - The DEVICE structure.
+@@ -1602,6 +1604,11 @@ struct net_device {
+ 	const struct l3mdev_ops	*l3mdev_ops;
+ #endif
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
++	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
++#endif
++
+ 	const struct header_ops *header_ops;
+ 
+ 	unsigned int		flags;
+@@ -1668,6 +1675,10 @@ struct net_device {
+ 	struct mpls_dev __rcu	*mpls_ptr;
+ #endif
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void			*phy_ptr; /* PHY device specific data */
++#endif
++
+ /*
+  * Cache lines mostly used on receive path (including eth_type_trans())
+  */
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2211,6 +2211,10 @@ static inline int pskb_trim(struct sk_bu
+ 	return (len < skb->len) ? __pskb_trim(skb, len) : 0;
+ }
+ 
++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp);
++
++
+ /**
+  *	pskb_trim_unique - remove end from a paged unique (not cloned) buffer
+  *	@skb: buffer to alter
+@@ -2315,16 +2319,6 @@ static inline struct sk_buff *dev_alloc_
+ }
+ 
+ 
+-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+-		unsigned int length, gfp_t gfp)
+-{
+-	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
+-
+-	if (NET_IP_ALIGN && skb)
+-		skb_reserve(skb, NET_IP_ALIGN);
+-	return skb;
+-}
+-
+ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
+ 		unsigned int length)
+ {
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -25,6 +25,12 @@ menuconfig NET
+ 
+ if NET
+ 
++config ETHERNET_PACKET_MANGLE
++	bool
++	help
++	  This option can be selected by phy drivers that need to mangle
++	  packets going in or out of an ethernet device.
++
+ config WANT_COMPAT_NETLINK_MESSAGES
+ 	bool
+ 	help
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2713,10 +2713,20 @@ static int xmit_one(struct sk_buff *skb,
+ 	if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
+ 		dev_queue_xmit_nit(skb, dev);
+ 
+-	len = skb->len;
+-	trace_net_dev_start_xmit(skb, dev);
+-	rc = netdev_start_xmit(skb, dev, txq, more);
+-	trace_net_dev_xmit(skb, rc, dev, len);
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (!dev->eth_mangle_tx ||
++	    (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
++#else
++	if (1)
++#endif
++	{
++		len = skb->len;
++		trace_net_dev_start_xmit(skb, dev);
++		rc = netdev_start_xmit(skb, dev, txq, more);
++		trace_net_dev_xmit(skb, rc, dev, len);
++	} else {
++		rc = NETDEV_TX_OK;
++	}
+ 
+ 	return rc;
+ }
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -63,6 +63,7 @@
+ #include <linux/errqueue.h>
+ #include <linux/prefetch.h>
+ #include <linux/if_vlan.h>
++#include <linux/if.h>
+ 
+ #include <net/protocol.h>
+ #include <net/dst.h>
+@@ -520,6 +521,22 @@ skb_fail:
+ }
+ EXPORT_SYMBOL(__napi_alloc_skb);
+ 
++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp)
++{
++	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
++		return skb;
++#endif
++
++	if (NET_IP_ALIGN && skb)
++		skb_reserve(skb, NET_IP_ALIGN);
++	return skb;
++}
++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
++
+ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+ 		     int size, unsigned int truesize)
+ {
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -168,6 +168,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 	const struct ethhdr *eth;
+ 
+ 	skb->dev = dev;
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev->eth_mangle_rx)
++		dev->eth_mangle_rx(dev, skb);
++#endif
++
+ 	skb_reset_mac_header(skb);
+ 
+ 	eth = (struct ethhdr *)skb->data;
diff --git a/target/linux/generic/patches-4.4/722-phy_mvswitch.patch b/target/linux/generic/patches-4.4/722-phy_mvswitch.patch
new file mode 100644
index 0000000000..9cfca24b95
--- /dev/null
+++ b/target/linux/generic/patches-4.4/722-phy_mvswitch.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -177,6 +177,10 @@ config ADM6996_PHY
+ 	  Currently supports the ADM6996FC and ADM6996M switches.
+ 	  Support for FC is very limited.
+ 
++config MVSWITCH_PHY
++	tristate "Driver for Marvell 88E6060 switches"
++	select ETHERNET_PACKET_MANGLE
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_BCM_CYGNUS_PHY)	+= bcm-cygnus.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
++obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
diff --git a/target/linux/generic/patches-4.4/723-phy_ip175c.patch b/target/linux/generic/patches-4.4/723-phy_ip175c.patch
new file mode 100644
index 0000000000..60b79a2aae
--- /dev/null
+++ b/target/linux/generic/patches-4.4/723-phy_ip175c.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -181,6 +181,10 @@ config MVSWITCH_PHY
+ 	tristate "Driver for Marvell 88E6060 switches"
+ 	select ETHERNET_PACKET_MANGLE
+ 
++config IP17XX_PHY
++	tristate "Driver for IC+ IP17xx switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -24,6 +24,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY)	+= bcm-cygn
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
diff --git a/target/linux/generic/patches-4.4/724-phy_ar8216.patch b/target/linux/generic/patches-4.4/724-phy_ar8216.patch
new file mode 100644
index 0000000000..626a2f3cba
--- /dev/null
+++ b/target/linux/generic/patches-4.4/724-phy_ar8216.patch
@@ -0,0 +1,24 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -185,6 +185,11 @@ config IP17XX_PHY
+ 	tristate "Driver for IC+ IP17xx switches"
+ 	select SWCONFIG
+ 
++config AR8216_PHY
++	tristate "Driver for Atheros AR8216 switches"
++	select ETHERNET_PACKET_MANGLE
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -26,6 +26,7 @@ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
++obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.4/725-phy_rtl8306.patch b/target/linux/generic/patches-4.4/725-phy_rtl8306.patch
new file mode 100644
index 0000000000..f38922f6e1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/725-phy_rtl8306.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -190,6 +190,10 @@ config AR8216_PHY
+ 	select ETHERNET_PACKET_MANGLE
+ 	select SWCONFIG
+ 
++config RTL8306_PHY
++	tristate "Driver for Realtek RTL8306S switches"
++	select SWCONFIG
++
+ config FIXED_PHY
+ 	tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ 	depends on PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
++obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.4/726-phy_rtl8366.patch b/target/linux/generic/patches-4.4/726-phy_rtl8366.patch
new file mode 100644
index 0000000000..5f50cf48b0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/726-phy_rtl8366.patch
@@ -0,0 +1,45 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -294,6 +294,30 @@ config MDIO_BCM_IPROC
+ 	  This module provides a driver for the MDIO busses found in the
+ 	  Broadcom iProc SoC's.
+ 
++config RTL8366_SMI
++	tristate "Driver for the RTL8366 SMI interface"
++	depends on GPIOLIB
++	---help---
++	  This module implements the SMI interface protocol which is used
++	  by some RTL8366 ethernet switch devices via the generic GPIO API.
++
++if RTL8366_SMI
++
++config RTL8366_SMI_DEBUG_FS
++	bool "RTL8366 SMI interface debugfs support"
++        depends on DEBUG_FS
++        default n
++
++config RTL8366S_PHY
++	tristate "Driver for the Realtek RTL8366S switch"
++	select SWCONFIG
++
++config RTL8366RB_PHY
++	tristate "Driver for the Realtek RTL8366RB switch"
++	select SWCONFIG
++
++endif # RTL8366_SMI
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -28,6 +28,9 @@ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
+ obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
++obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
++obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
++obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.4/727-phy-rtl8367.patch b/target/linux/generic/patches-4.4/727-phy-rtl8367.patch
new file mode 100644
index 0000000000..887d12dd95
--- /dev/null
+++ b/target/linux/generic/patches-4.4/727-phy-rtl8367.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -316,6 +316,10 @@ config RTL8366RB_PHY
+ 	tristate "Driver for the Realtek RTL8366RB switch"
+ 	select SWCONFIG
+ 
++config RTL8367_PHY
++	tristate "Driver for the Realtek RTL8367R/M switches"
++	select SWCONFIG
++
+ endif # RTL8366_SMI
+ 
+ endif # PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
+ obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
+ obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
+ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
++obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.4/728-phy-rtl8367b.patch b/target/linux/generic/patches-4.4/728-phy-rtl8367b.patch
new file mode 100644
index 0000000000..d96bead4dc
--- /dev/null
+++ b/target/linux/generic/patches-4.4/728-phy-rtl8367b.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -320,6 +320,10 @@ config RTL8367_PHY
+ 	tristate "Driver for the Realtek RTL8367R/M switches"
+ 	select SWCONFIG
+ 
++config RTL8367B_PHY
++	tristate "Driver fot the Realtek RTL8367R-VB switch"
++	select SWCONFIG
++
+ endif # RTL8366_SMI
+ 
+ endif # PHYLIB
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi
+ obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
+ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
+ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
++obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/target/linux/generic/patches-4.4/729-phy-tantos.patch b/target/linux/generic/patches-4.4/729-phy-tantos.patch
new file mode 100644
index 0000000000..a09032b6c8
--- /dev/null
+++ b/target/linux/generic/patches-4.4/729-phy-tantos.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -331,3 +331,8 @@ endif # PHYLIB
+ config MICREL_KS8995MA
+ 	tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch"
+ 	depends on SPI
++
++config PSB6970_PHY
++	tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
++	select SWCONFIG
++	select ETHERNET_PACKET_MANGLE
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb
+ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
++obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
diff --git a/target/linux/generic/patches-4.4/730-phy_b53.patch b/target/linux/generic/patches-4.4/730-phy_b53.patch
new file mode 100644
index 0000000000..1a6de96726
--- /dev/null
+++ b/target/linux/generic/patches-4.4/730-phy_b53.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -326,6 +326,8 @@ config RTL8367B_PHY
+ 
+ endif # RTL8366_SMI
+ 
++source "drivers/net/phy/b53/Kconfig"
++
+ endif # PHYLIB
+ 
+ config MICREL_KS8995MA
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
+ obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
+ obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
++obj-$(CONFIG_SWCONFIG_B53)	+= b53/
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
+ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
+ obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
diff --git a/target/linux/generic/patches-4.4/732-phy-ar8216-led-support.patch b/target/linux/generic/patches-4.4/732-phy-ar8216-led-support.patch
new file mode 100644
index 0000000000..f4fea5ce50
--- /dev/null
+++ b/target/linux/generic/patches-4.4/732-phy-ar8216-led-support.patch
@@ -0,0 +1,13 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -190,6 +190,10 @@ config AR8216_PHY
+ 	select ETHERNET_PACKET_MANGLE
+ 	select SWCONFIG
+ 
++config AR8216_PHY_LEDS
++	bool "Atheros AR8216 switch LED support"
++	depends on (AR8216_PHY && LEDS_CLASS)
++
+ config RTL8306_PHY
+ 	tristate "Driver for Realtek RTL8306S switches"
+ 	select SWCONFIG
diff --git a/target/linux/generic/patches-4.4/733-phy_mvsw61xx.patch b/target/linux/generic/patches-4.4/733-phy_mvsw61xx.patch
new file mode 100644
index 0000000000..2e131368b9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/733-phy_mvsw61xx.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -181,6 +181,10 @@ config MVSWITCH_PHY
+ 	tristate "Driver for Marvell 88E6060 switches"
+ 	select ETHERNET_PACKET_MANGLE
+ 
++config MVSW61XX_PHY
++	tristate "Driver for Marvell 88E6171/6172 switches"
++	select SWCONFIG
++
+ config IP17XX_PHY
+ 	tristate "Driver for IC+ IP17xx switches"
+ 	select SWCONFIG
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -24,6 +24,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY)	+= bcm-cygn
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
+ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_MVSW61XX_PHY)	+= mvsw61xx.o
+ obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
+ obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
+ obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
diff --git a/target/linux/generic/patches-4.4/734-net-phy-at803x-allow-to-configure-via-pdata.patch b/target/linux/generic/patches-4.4/734-net-phy-at803x-allow-to-configure-via-pdata.patch
new file mode 100644
index 0000000000..53abcc33ed
--- /dev/null
+++ b/target/linux/generic/patches-4.4/734-net-phy-at803x-allow-to-configure-via-pdata.patch
@@ -0,0 +1,180 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -12,12 +12,14 @@
+  */
+ 
+ #include <linux/phy.h>
++#include <linux/mdio.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/of_gpio.h>
+ #include <linux/gpio/consumer.h>
++#include <linux/platform_data/phy-at803x.h>
+ 
+ #define AT803X_INTR_ENABLE			0x12
+ #define AT803X_INTR_STATUS			0x13
+@@ -34,8 +36,16 @@
+ #define AT803X_INER				0x0012
+ #define AT803X_INER_INIT			0xec00
+ #define AT803X_INSR				0x0013
++
++#define AT803X_PCS_SMART_EEE_CTRL3			0x805D
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK	0x3
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT	12
++#define AT803X_SMART_EEE_CTRL3_LPI_EN			BIT(8)
++
+ #define AT803X_DEBUG_ADDR			0x1D
+ #define AT803X_DEBUG_DATA			0x1E
++#define AT803X_DBG0_REG				0x00
++#define AT803X_DEBUG_RGMII_RX_CLK_DLY		BIT(8)
+ #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
+ #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
+ 
+@@ -50,6 +60,7 @@ MODULE_LICENSE("GPL");
+ struct at803x_priv {
+ 	bool phy_reset:1;
+ 	struct gpio_desc *gpiod_reset;
++	int prev_speed;
+ };
+ 
+ struct at803x_context {
+@@ -61,6 +72,43 @@ struct at803x_context {
+ 	u16 led_control;
+ };
+ 
++static u16
++at803x_dbg_reg_rmw(struct phy_device *phydev, u16 reg, u16 clear, u16 set)
++{
++	struct mii_bus *bus = phydev->bus;
++	int val;
++
++	mutex_lock(&bus->mdio_lock);
++
++	bus->write(bus, phydev->addr, AT803X_DEBUG_ADDR, reg);
++	val = bus->read(bus, phydev->addr, AT803X_DEBUG_DATA);
++	if (val < 0) {
++		val = 0xffff;
++		goto out;
++	}
++
++	val &= ~clear;
++	val |= set;
++	bus->write(bus, phydev->addr, AT803X_DEBUG_DATA, val);
++
++out:
++	mutex_unlock(&bus->mdio_lock);
++	return val;
++}
++
++static inline void
++at803x_dbg_reg_set(struct phy_device *phydev, u16 reg, u16 set)
++{
++	at803x_dbg_reg_rmw(phydev, reg, 0, set);
++}
++
++static inline void
++at803x_dbg_reg_clr(struct phy_device *phydev, u16 reg, u16 clear)
++{
++	at803x_dbg_reg_rmw(phydev, reg, clear, 0);
++}
++
++
+ /* save relevant PHY registers to private copy */
+ static void at803x_context_save(struct phy_device *phydev,
+ 				struct at803x_context *context)
+@@ -209,8 +257,16 @@ static int at803x_probe(struct phy_devic
+ 	return 0;
+ }
+ 
++static void at803x_disable_smarteee(struct phy_device *phydev)
++{
++	phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
++		1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
++	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
++}
++
+ static int at803x_config_init(struct phy_device *phydev)
+ {
++	struct at803x_platform_data *pdata;
+ 	int ret;
+ 
+ 	ret = genphy_config_init(phydev);
+@@ -228,6 +284,26 @@ static int at803x_config_init(struct phy
+ 			return ret;
+ 	}
+ 
++	pdata = dev_get_platdata(&phydev->dev);
++	if (pdata) {
++		if (pdata->disable_smarteee)
++			at803x_disable_smarteee(phydev);
++
++		if (pdata->enable_rgmii_rx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DBG0_REG,
++				AT803X_DEBUG_RGMII_RX_CLK_DLY);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DBG0_REG,
++				AT803X_DEBUG_RGMII_RX_CLK_DLY);
++
++		if (pdata->enable_rgmii_tx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++	}
++
+ 	return 0;
+ }
+ 
+@@ -259,6 +335,8 @@ static int at803x_config_intr(struct phy
+ static void at803x_link_change_notify(struct phy_device *phydev)
+ {
+ 	struct at803x_priv *priv = phydev->priv;
++	struct at803x_platform_data *pdata;
++	pdata = dev_get_platdata(&phydev->dev);
+ 
+ 	/*
+ 	 * Conduct a hardware reset for AT8030 every time a link loss is
+@@ -289,6 +367,26 @@ static void at803x_link_change_notify(st
+ 			priv->phy_reset = false;
+ 		}
+ 	}
++	if (pdata && pdata->fixup_rgmii_tx_delay &&
++	    phydev->speed != priv->prev_speed) {
++		switch (phydev->speed) {
++		case SPEED_10:
++		case SPEED_100:
++			at803x_dbg_reg_set(phydev,
++				AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++			break;
++		case SPEED_1000:
++			at803x_dbg_reg_clr(phydev,
++				AT803X_DEBUG_SYSTEM_MODE_CTRL,
++				AT803X_DEBUG_RGMII_TX_CLK_DLY);
++			break;
++		default:
++			break;
++		}
++
++		priv->prev_speed = phydev->speed;
++	}
+ }
+ 
+ static struct phy_driver at803x_driver[] = {
+--- /dev/null
++++ b/include/linux/platform_data/phy-at803x.h
+@@ -0,0 +1,11 @@
++#ifndef _PHY_AT803X_PDATA_H
++#define _PHY_AT803X_PDATA_H
++
++struct at803x_platform_data {
++	int disable_smarteee:1;
++	int enable_rgmii_tx_delay:1;
++	int enable_rgmii_rx_delay:1;
++	int fixup_rgmii_tx_delay:1;
++};
++
++#endif /* _PHY_AT803X_PDATA_H */
diff --git a/target/linux/generic/patches-4.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch b/target/linux/generic/patches-4.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
new file mode 100644
index 0000000000..60de6b4f7d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
@@ -0,0 +1,96 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -36,6 +36,9 @@
+ #define AT803X_INER				0x0012
+ #define AT803X_INER_INIT			0xec00
+ #define AT803X_INSR				0x0013
++#define AT803X_REG_CHIP_CONFIG			0x1f
++#define AT803X_BT_BX_REG_SEL			0x8000
++#define AT803X_SGMII_ANEG_EN			0x1000
+ 
+ #define AT803X_PCS_SMART_EEE_CTRL3			0x805D
+ #define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK	0x3
+@@ -49,9 +52,10 @@
+ #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
+ #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
+ 
+-#define ATH8030_PHY_ID 0x004dd076
+-#define ATH8031_PHY_ID 0x004dd074
+-#define ATH8035_PHY_ID 0x004dd072
++#define AT803X_PHY_ID_MASK			0xffffffef
++#define ATH8030_PHY_ID				0x004dd076
++#define ATH8031_PHY_ID				0x004dd074
++#define ATH8035_PHY_ID				0x004dd072
+ 
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi");
+@@ -268,6 +272,27 @@ static int at803x_config_init(struct phy
+ {
+ 	struct at803x_platform_data *pdata;
+ 	int ret;
++	u32 v;
++
++	if (phydev->drv->phy_id == ATH8031_PHY_ID &&
++		phydev->interface == PHY_INTERFACE_MODE_SGMII)
++	{
++		v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
++		/* select SGMII/fiber page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v & ~AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++		/* enable SGMII autonegotiation */
++		ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
++		if (ret)
++			return ret;
++		/* select copper page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v | AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++	}
+ 
+ 	ret = genphy_config_init(phydev);
+ 	if (ret < 0)
+@@ -394,7 +419,7 @@ static struct phy_driver at803x_driver[]
+ 	/* ATHEROS 8035 */
+ 	.phy_id			= ATH8035_PHY_ID,
+ 	.name			= "Atheros 8035 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -415,7 +440,7 @@ static struct phy_driver at803x_driver[]
+ 	/* ATHEROS 8030 */
+ 	.phy_id			= ATH8030_PHY_ID,
+ 	.name			= "Atheros 8030 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -435,8 +460,8 @@ static struct phy_driver at803x_driver[]
+ }, {
+ 	/* ATHEROS 8031 */
+ 	.phy_id			= ATH8031_PHY_ID,
+-	.name			= "Atheros 8031 ethernet",
+-	.phy_id_mask		= 0xffffffef,
++	.name			= "Atheros 8031/8033 ethernet",
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+ 	.link_change_notify	= at803x_link_change_notify,
+@@ -458,9 +483,9 @@ static struct phy_driver at803x_driver[]
+ module_phy_driver(at803x_driver);
+ 
+ static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+-	{ ATH8030_PHY_ID, 0xffffffef },
+-	{ ATH8031_PHY_ID, 0xffffffef },
+-	{ ATH8035_PHY_ID, 0xffffffef },
++	{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ }
+ };
+ 
diff --git a/target/linux/generic/patches-4.4/736-at803x-fix-reset-handling.patch b/target/linux/generic/patches-4.4/736-at803x-fix-reset-handling.patch
new file mode 100644
index 0000000000..91c2334e55
--- /dev/null
+++ b/target/linux/generic/patches-4.4/736-at803x-fix-reset-handling.patch
@@ -0,0 +1,43 @@
+From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+Date: Wed, 23 Mar 2016 00:44:40 +0300
+Subject: [PATCH] at803x: fix reset handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The driver of course "knows" that the chip's reset signal is active low,
+so  it drives the GPIO to 0  to reset the PHY and to 1 otherwise; however
+all this will only work iff the GPIO  is  specified as active-high in the
+device tree!  I think both the driver and the device trees (if there are
+any -- I was unable to find them) need to be fixed in this case...
+
+Fixes: 13a56b449325 ("net: phy: at803x: Add support for hardware reset")
+Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -250,7 +250,7 @@ static int at803x_probe(struct phy_devic
+ 	if (!priv)
+ 		return -ENOMEM;
+ 
+-	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
++	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ 	if (IS_ERR(gpiod_reset))
+ 		return PTR_ERR(gpiod_reset);
+ 
+@@ -377,10 +377,10 @@ static void at803x_link_change_notify(st
+ 
+ 				at803x_context_save(phydev, &context);
+ 
+-				gpiod_set_value(priv->gpiod_reset, 0);
+-				msleep(1);
+ 				gpiod_set_value(priv->gpiod_reset, 1);
+ 				msleep(1);
++				gpiod_set_value(priv->gpiod_reset, 0);
++				msleep(1);
+ 
+ 				at803x_context_restore(phydev, &context);
+ 
diff --git a/target/linux/generic/patches-4.4/737-net-phy-at803x-Request-reset-GPIO-only-for-AT8030-PH.patch b/target/linux/generic/patches-4.4/737-net-phy-at803x-Request-reset-GPIO-only-for-AT8030-PH.patch
new file mode 100644
index 0000000000..b30ba7aaae
--- /dev/null
+++ b/target/linux/generic/patches-4.4/737-net-phy-at803x-Request-reset-GPIO-only-for-AT8030-PH.patch
@@ -0,0 +1,42 @@
+From: Sebastian Frias <sf84@laposte.net>
+Date: Wed, 23 Mar 2016 11:49:09 +0100
+Subject: [PATCH] net: phy: at803x: Request 'reset' GPIO only for AT8030 PHY
+
+This removes the dependency on GPIOLIB for non faulty PHYs.
+
+Indeed, without this patch, if GPIOLIB is not selected
+devm_gpiod_get_optional() will return -ENOSYS and the driver probe
+call will fail, regardless of the actual PHY hardware.
+
+Out of the 3 PHYs supported by this driver (AT8030, AT8031, AT8035),
+only AT8030 presents the issues that commit 13a56b449325 ("net: phy:
+at803x: Add support for hardware reset") attempts to work-around by
+using a 'reset' GPIO line.
+
+Hence, only AT8030 should depend on GPIOLIB operating properly.
+
+Fixes: 13a56b449325 ("net: phy: at803x: Add support for hardware reset")
+
+Signed-off-by: Sebastian Frias <sf84@laposte.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -250,12 +250,16 @@ static int at803x_probe(struct phy_devic
+ 	if (!priv)
+ 		return -ENOMEM;
+ 
++	if (phydev->drv->phy_id != ATH8030_PHY_ID)
++		goto does_not_require_reset_workaround;
++
+ 	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ 	if (IS_ERR(gpiod_reset))
+ 		return PTR_ERR(gpiod_reset);
+ 
+ 	priv->gpiod_reset = gpiod_reset;
+ 
++does_not_require_reset_workaround:
+ 	phydev->priv = priv;
+ 
+ 	return 0;
diff --git a/target/linux/generic/patches-4.4/738-net-phy-at803x-only-the-AT8030-needs-a-hardware-rese.patch b/target/linux/generic/patches-4.4/738-net-phy-at803x-only-the-AT8030-needs-a-hardware-rese.patch
new file mode 100644
index 0000000000..4e6baac0c3
--- /dev/null
+++ b/target/linux/generic/patches-4.4/738-net-phy-at803x-only-the-AT8030-needs-a-hardware-rese.patch
@@ -0,0 +1,81 @@
+From: Timur Tabi <timur@codeaurora.org>
+Date: Tue, 26 Apr 2016 12:44:18 -0500
+Subject: [PATCH] net: phy: at803x: only the AT8030 needs a hardware reset on
+ link change
+
+Commit 13a56b44 ("at803x: Add support for hardware reset") added a
+work-around for a hardware bug on the AT8030.  However, the work-around
+was being called for all 803x PHYs, even those that don't need it.
+Function at803x_link_change_notify() checks to make sure that it only
+resets the PHY on the 8030, but it makes more sense to not call that
+function at all if it isn't needed.
+
+Signed-off-by: Timur Tabi <timur@codeaurora.org>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -374,27 +374,25 @@ static void at803x_link_change_notify(st
+ 	 * in the FIFO. In such cases, the FIFO enters an error mode it
+ 	 * cannot recover from by software.
+ 	 */
+-	if (phydev->drv->phy_id == ATH8030_PHY_ID) {
+-		if (phydev->state == PHY_NOLINK) {
+-			if (priv->gpiod_reset && !priv->phy_reset) {
+-				struct at803x_context context;
+-
+-				at803x_context_save(phydev, &context);
+-
+-				gpiod_set_value(priv->gpiod_reset, 1);
+-				msleep(1);
+-				gpiod_set_value(priv->gpiod_reset, 0);
+-				msleep(1);
+-
+-				at803x_context_restore(phydev, &context);
+-
+-				dev_dbg(&phydev->dev, "%s(): phy was reset\n",
+-					__func__);
+-				priv->phy_reset = true;
+-			}
+-		} else {
+-			priv->phy_reset = false;
++	if (phydev->state == PHY_NOLINK) {
++		if (priv->gpiod_reset && !priv->phy_reset) {
++			struct at803x_context context;
++
++			at803x_context_save(phydev, &context);
++
++			gpiod_set_value(priv->gpiod_reset, 1);
++			msleep(1);
++			gpiod_set_value(priv->gpiod_reset, 0);
++			msleep(1);
++
++			at803x_context_restore(phydev, &context);
++
++			dev_dbg(&phydev->dev, "%s(): phy was reset\n",
++				__func__);
++			priv->phy_reset = true;
+ 		}
++	} else {
++		priv->phy_reset = false;
+ 	}
+ 	if (pdata && pdata->fixup_rgmii_tx_delay &&
+ 	    phydev->speed != priv->prev_speed) {
+@@ -426,7 +424,6 @@ static struct phy_driver at803x_driver[]
+ 	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+-	.link_change_notify	= at803x_link_change_notify,
+ 	.set_wol		= at803x_set_wol,
+ 	.get_wol		= at803x_get_wol,
+ 	.suspend		= at803x_suspend,
+@@ -468,7 +465,6 @@ static struct phy_driver at803x_driver[]
+ 	.phy_id_mask		= AT803X_PHY_ID_MASK,
+ 	.probe			= at803x_probe,
+ 	.config_init		= at803x_config_init,
+-	.link_change_notify	= at803x_link_change_notify,
+ 	.set_wol		= at803x_set_wol,
+ 	.get_wol		= at803x_get_wol,
+ 	.suspend		= at803x_suspend,
diff --git a/target/linux/generic/patches-4.4/739-net-phy-at803x-add-support-for-AT8032.patch b/target/linux/generic/patches-4.4/739-net-phy-at803x-add-support-for-AT8032.patch
new file mode 100644
index 0000000000..4455ec49e1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/739-net-phy-at803x-add-support-for-AT8032.patch
@@ -0,0 +1,65 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 30 Nov 2016 11:31:03 +0100
+Subject: [PATCH] net: phy: at803x: add support for AT8032
+
+Like AT8030, this PHY needs the GPIO reset workaround
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -55,6 +55,7 @@
+ #define AT803X_PHY_ID_MASK			0xffffffef
+ #define ATH8030_PHY_ID				0x004dd076
+ #define ATH8031_PHY_ID				0x004dd074
++#define ATH8032_PHY_ID				0x004dd023
+ #define ATH8035_PHY_ID				0x004dd072
+ 
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+@@ -250,7 +251,8 @@ static int at803x_probe(struct phy_devic
+ 	if (!priv)
+ 		return -ENOMEM;
+ 
+-	if (phydev->drv->phy_id != ATH8030_PHY_ID)
++	if (phydev->drv->phy_id != ATH8030_PHY_ID &&
++	    phydev->drv->phy_id != ATH8032_PHY_ID)
+ 		goto does_not_require_reset_workaround;
+ 
+ 	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+@@ -478,6 +480,27 @@ static struct phy_driver at803x_driver[]
+ 	.driver			= {
+ 		.owner = THIS_MODULE,
+ 	},
++}, {
++	/* ATHEROS 8032 */
++	.phy_id			= ATH8032_PHY_ID,
++	.name			= "Atheros 8032 ethernet",
++	.phy_id_mask		= AT803X_PHY_ID_MASK,
++	.probe			= at803x_probe,
++	.config_init		= at803x_config_init,
++	.link_change_notify	= at803x_link_change_notify,
++	.set_wol		= at803x_set_wol,
++	.get_wol		= at803x_get_wol,
++	.suspend		= at803x_suspend,
++	.resume			= at803x_resume,
++	.features		= PHY_GBIT_FEATURES,
++	.flags			= PHY_HAS_INTERRUPT,
++	.config_aneg		= genphy_config_aneg,
++	.read_status		= genphy_read_status,
++	.ack_interrupt		= &at803x_ack_interrupt,
++	.config_intr		= &at803x_config_intr,
++	.driver			= {
++		.owner = THIS_MODULE,
++	},
+ } };
+ 
+ module_phy_driver(at803x_driver);
+@@ -485,6 +508,7 @@ module_phy_driver(at803x_driver);
+ static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+ 	{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8032_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ }
+ };
diff --git a/target/linux/generic/patches-4.4/773-bgmac-add-srab-switch.patch b/target/linux/generic/patches-4.4/773-bgmac-add-srab-switch.patch
new file mode 100644
index 0000000000..990d23dc8e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/773-bgmac-add-srab-switch.patch
@@ -0,0 +1,88 @@
+Register switch connected to srab
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -11,6 +11,7 @@
+ 
+ #include <linux/bcma/bcma.h>
+ #include <linux/etherdevice.h>
++#include <linux/platform_data/b53.h>
+ #include <linux/bcm47xx_nvram.h>
+ #include "bgmac.h"
+ 
+@@ -1403,6 +1404,17 @@ static const struct ethtool_ops bgmac_et
+ 	.get_drvinfo		= bgmac_get_drvinfo,
+ };
+ 
++static struct b53_platform_data bgmac_b53_pdata = {
++};
++
++static struct platform_device bgmac_b53_dev = {
++	.name		= "b53-srab-switch",
++	.id		= -1,
++	.dev		= {
++		.platform_data = &bgmac_b53_pdata,
++	},
++};
++
+ /**************************************************
+  * MII
+  **************************************************/
+@@ -1539,6 +1551,14 @@ int bgmac_enet_probe(struct bgmac *info)
+ 	net_dev->hw_features = net_dev->features;
+ 	net_dev->vlan_features = net_dev->features;
+ 
++	if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) {
++		bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000);
++
++		err = platform_device_register(&bgmac_b53_dev);
++		if (!err)
++			bgmac->b53_device = &bgmac_b53_dev;
++	}
++
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+ 		dev_err(bgmac->dev, "Cannot register net device\n");
+@@ -1562,6 +1582,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe);
+ 
+ void bgmac_enet_remove(struct bgmac *bgmac)
+ {
++	if (bgmac->b53_device)
++		platform_device_unregister(&bgmac_b53_dev);
++	bgmac->b53_device = NULL;
++
+ 	unregister_netdev(bgmac->net_dev);
+ 	phy_disconnect(bgmac->net_dev->phydev);
+ 	netif_napi_del(&bgmac->napi);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -409,6 +409,7 @@
+ #define BGMAC_FEAT_CC4_IF_SW_TYPE	BIT(17)
+ #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII	BIT(18)
+ #define BGMAC_FEAT_CC7_IF_TYPE_RGMII	BIT(19)
++#define BGMAC_FEAT_SRAB			BIT(20)
+ 
+ struct bgmac_slot_info {
+ 	union {
+@@ -513,6 +514,9 @@ struct bgmac {
+ 	u32 (*get_bus_clock)(struct bgmac *bgmac);
+ 	void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
+ 			      u32 set);
++
++	/* platform device for associated switch */
++	struct platform_device *b53_device;
+ };
+ 
+ int bgmac_enet_probe(struct bgmac *info);
+--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
+@@ -231,6 +231,7 @@ static int bgmac_probe(struct bcma_devic
+ 		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+ 		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
+ 		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
++		bgmac->feature_flags |= BGMAC_FEAT_SRAB;
+ 		break;
+ 	case BCMA_CHIP_ID_BCM53573:
+ 		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
diff --git a/target/linux/generic/patches-4.4/785-hso-support-0af0-9300.patch b/target/linux/generic/patches-4.4/785-hso-support-0af0-9300.patch
new file mode 100644
index 0000000000..621d08f4f1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/785-hso-support-0af0-9300.patch
@@ -0,0 +1,25 @@
+--- a/drivers/net/usb/hso.c
++++ b/drivers/net/usb/hso.c
+@@ -466,6 +466,7 @@ static const struct usb_device_id hso_id
+ 	{USB_DEVICE(0x0af0, 0x8900)},
+ 	{USB_DEVICE(0x0af0, 0x9000)},
+ 	{USB_DEVICE(0x0af0, 0x9200)},		/* Option GTM671WFS */
++	{USB_DEVICE(0x0af0, 0x9300)},		/* GTM 66xxWFS */
+ 	{USB_DEVICE(0x0af0, 0xd035)},
+ 	{USB_DEVICE(0x0af0, 0xd055)},
+ 	{USB_DEVICE(0x0af0, 0xd155)},
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -1330,6 +1330,12 @@ UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0
+ 		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 		0 ),
+ 
++UNUSUAL_DEV( 0x0af0, 0x9300, 0x0000, 0x0000,
++		"Option",
++		"Globetrotter 66xxWFS SD-Card",
++		USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++		0 ),
++
+ UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+ 		"Option",
+ 		"GI 070x SD-Card",
diff --git a/target/linux/generic/patches-4.4/810-pci_disable_common_quirks.patch b/target/linux/generic/patches-4.4/810-pci_disable_common_quirks.patch
new file mode 100644
index 0000000000..e5c9043065
--- /dev/null
+++ b/target/linux/generic/patches-4.4/810-pci_disable_common_quirks.patch
@@ -0,0 +1,51 @@
+--- a/drivers/pci/Kconfig
++++ b/drivers/pci/Kconfig
+@@ -68,6 +68,12 @@ config XEN_PCIDEV_FRONTEND
+           The PCI device frontend driver allows the kernel to import arbitrary
+           PCI devices from a PCI backend to support PCI driver domains.
+ 
++config PCI_DISABLE_COMMON_QUIRKS
++	bool "PCI disable common quirks"
++	depends on PCI
++	help
++	  If you don't know what to do here, say N.
++
+ config HT_IRQ
+ 	bool "Interrupts on hypertransport devices"
+ 	default y
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct
+ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+ 				PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ /* The Mellanox Tavor device gives false positive parity errors
+  * Mark this device with a broken_parity_status, to allow
+  * PCI scanning code to "skip" this now blacklisted device.
+@@ -2975,6 +2976,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
+ 
+ /*
+  * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.  To
+@@ -3031,6 +3033,8 @@ static void fixup_debug_report(struct pc
+ 	}
+ }
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ /*
+  * Some BIOS implementations leave the Intel GPU interrupts enabled,
+  * even though no one is handling them (f.e. i915 driver is never loaded).
+@@ -3065,6 +3069,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
+ /*
+  * PCI devices which are on Intel chips can skip the 10ms delay
+  * before entering D3 mode.
diff --git a/target/linux/generic/patches-4.4/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/patches-4.4/811-pci_disable_usb_common_quirks.patch
new file mode 100644
index 0000000000..a4b93df72d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/811-pci_disable_usb_common_quirks.patch
@@ -0,0 +1,101 @@
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -97,6 +97,8 @@ struct amd_chipset_type {
+ 	u8 rev;
+ };
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static struct amd_chipset_info {
+ 	struct pci_dev	*nb_dev;
+ 	struct pci_dev	*smbus_dev;
+@@ -450,6 +452,10 @@ void usb_amd_dev_put(void)
+ }
+ EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+ 
++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
++#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
++
+ /*
+  * Make sure the controller is completely inactive, unable to
+  * generate interrupts or do DMA.
+@@ -529,8 +535,17 @@ reset_needed:
+ 	uhci_reset_hc(pdev, base);
+ 	return 1;
+ }
++#else
++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
++{
++	return 0;
++}
++
++#endif
+ EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
+ {
+ 	u16 cmd;
+@@ -1095,3 +1110,4 @@ static void quirk_usb_early_handoff(stru
+ }
+ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ 			PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
++#endif
+--- a/drivers/usb/host/pci-quirks.h
++++ b/drivers/usb/host/pci-quirks.h
+@@ -4,6 +4,9 @@
+ #ifdef CONFIG_PCI
+ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
+ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
++#endif  /* CONFIG_PCI */
++
++#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
+ int usb_amd_find_chipset_info(void);
+ int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
+ bool usb_amd_hang_symptom_quirk(void);
+@@ -16,11 +19,24 @@ void usb_disable_xhci_ports(struct pci_d
+ void sb800_prefetch(struct device *dev, int on);
+ #else
+ struct pci_dev;
++static inline int usb_amd_find_chipset_info(void)
++{
++	return 0;
++}
++static inline bool usb_amd_hang_symptom_quirk(void)
++{
++	return false;
++}
++static inline bool usb_amd_prefetch_quirk(void)
++{
++	return false;
++}
+ static inline void usb_amd_quirk_pll_disable(void) {}
+ static inline void usb_amd_quirk_pll_enable(void) {}
+ static inline void usb_amd_dev_put(void) {}
+ static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
+ static inline void sb800_prefetch(struct device *dev, int on) {}
+-#endif  /* CONFIG_PCI */
++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
++#endif
+ 
+ #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -459,7 +459,14 @@ extern int usb_hcd_pci_probe(struct pci_
+ extern void usb_hcd_pci_remove(struct pci_dev *dev);
+ extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
++#else
++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
++{
++	return 0;
++}
++#endif
+ 
+ #ifdef CONFIG_PM
+ extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
diff --git a/target/linux/generic/patches-4.4/821-usb-Remove-annoying-warning-about-bogus-URB.patch b/target/linux/generic/patches-4.4/821-usb-Remove-annoying-warning-about-bogus-URB.patch
new file mode 100644
index 0000000000..eb7cc809c7
--- /dev/null
+++ b/target/linux/generic/patches-4.4/821-usb-Remove-annoying-warning-about-bogus-URB.patch
@@ -0,0 +1,78 @@
+From f13ad28ba4280d2283ca2b49f0bd384bc51e6a68 Mon Sep 17 00:00:00 2001
+From: Alexey Brodkin <abrodkin@synopsys.com>
+Date: Tue, 5 Jul 2016 14:28:31 +0300
+Subject: [PATCH] usb: Remove annoying warning about bogus URB
+
+When ath9k-htc Wi-Fi dongle is used with generic OHCI controller
+infinite stream of warnings appears in debug console like this:
+-------------------------->8----------------------
+usb 1-1: new full-speed USB device number 2 using ohci-platform
+usb 1-1: ath9k_htc: Firmware ath9k_htc/htc_9271-1.4.0.fw requested
+usb 1-1: ath9k_htc: Transferred FW: ath9k_htc/htc_9271-1.4.0.fw, size:
+51008
+------------[ cut here ]------------
+WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
+usb_submit_urb+0x1b4/0x498()
+usb 1-1: BOGUS urb xfer, pipe 1 != type 3
+Modules linked in:
+CPU: 0 PID: 19 Comm: kworker/0:1 Not tainted
+4.4.0-rc4-00017-g00e2d79-dirty #3
+Workqueue: events request_firmware_work_func
+
+Stack Trace:
+  arc_unwind_core.constprop.1+0xa4/0x110
+---[ end trace 649ef8c342817fc2 ]---
+------------[ cut here ]------------
+WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
+usb_submit_urb+0x1b4/0x498()
+usb 1-1: BOGUS urb xfer, pipe 1 != type 3
+Modules linked in:
+CPU: 0 PID: 19 Comm: kworker/0:1 Tainted: G        W
+4.4.0-rc4-00017-g00e2d79-dirty #3
+Workqueue: events request_firmware_work_func
+
+Stack Trace:
+  arc_unwind_core.constprop.1+0xa4/0x110
+---[ end trace 649ef8c342817fc3 ]---
+------------[ cut here ]------------
+-------------------------->8----------------------
+
+There're some discussions in mailing lists proposing to disable
+that particular check alltogether and magically all seem to work
+fine with muted warning.
+
+Anyways new thread on that regard could be found here:
+http://lists.infradead.org/pipermail/linux-snps-arc/2016-July/001310.html
+
+Let's see what comes out of that new discussion, hopefully patching
+of generic USB stuff won't be required then.
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+---
+ drivers/usb/core/urb.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/usb/core/urb.c
++++ b/drivers/usb/core/urb.c
+@@ -323,9 +323,6 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
+  */
+ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+ {
+-	static int			pipetypes[4] = {
+-		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+-	};
+ 	int				xfertype, max;
+ 	struct usb_device		*dev;
+ 	struct usb_host_endpoint	*ep;
+@@ -443,11 +440,6 @@ int usb_submit_urb(struct urb *urb, gfp_
+ 	 * cause problems in HCDs if they get it wrong.
+ 	 */
+ 
+-	/* Check that the pipe's type matches the endpoint's type */
+-	if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+-		dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
+-			usb_pipetype(urb->pipe), pipetypes[xfertype]);
+-
+ 	/* Check against a simple/standard policy */
+ 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
+ 			URB_FREE_BUFFER);
diff --git a/target/linux/generic/patches-4.4/831-ledtrig_netdev.patch b/target/linux/generic/patches-4.4/831-ledtrig_netdev.patch
new file mode 100644
index 0000000000..a28de899ac
--- /dev/null
+++ b/target/linux/generic/patches-4.4/831-ledtrig_netdev.patch
@@ -0,0 +1,21 @@
+--- a/drivers/leds/trigger/Kconfig
++++ b/drivers/leds/trigger/Kconfig
+@@ -108,4 +108,11 @@ config LEDS_TRIGGER_CAMERA
+ 	  This enables direct flash/torch on/off by the driver, kernel space.
+ 	  If unsure, say Y.
+ 
++config LEDS_TRIGGER_NETDEV
++	tristate "LED Netdev Trigger"
++	depends on NET && LEDS_TRIGGERS
++	help
++	  This allows LEDs to be controlled by network device activity.
++	  If unsure, say Y.
++
+ endif # LEDS_TRIGGERS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -72,3 +72,4 @@ obj-$(CONFIG_LEDS_DAC124S085)		+= leds-d
+ 
+ # LED Triggers
+ obj-$(CONFIG_LEDS_TRIGGERS)		+= trigger/
++obj-$(CONFIG_LEDS_TRIGGER_NETDEV)	+= ledtrig-netdev.o
diff --git a/target/linux/generic/patches-4.4/834-ledtrig-libata.patch b/target/linux/generic/patches-4.4/834-ledtrig-libata.patch
new file mode 100644
index 0000000000..c3d187a098
--- /dev/null
+++ b/target/linux/generic/patches-4.4/834-ledtrig-libata.patch
@@ -0,0 +1,153 @@
+From 52cfd51cdf6a6e14d4fb270c6343abac3bac00f4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 12 Dec 2014 13:38:33 +0100
+Subject: [PATCH] libata: add ledtrig support
+To: linux-ide@vger.kernel.org,
+    Tejun Heo <tj@kernel.org>
+
+This adds a LED trigger for each ATA port indicating disk activity.
+
+As this is needed only on specific platforms (NAS SoCs and such),
+these platforms should define ARCH_WANTS_LIBATA_LEDS if there
+are boards with LED(s) intended to indicate ATA disk activity and
+need the OS to take care of that.
+In that way, if not selected, LED trigger support not will be
+included in libata-core and both, codepaths and structures remain
+untouched.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/ata/Kconfig       | 16 ++++++++++++++++
+ drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/libata.h    |  9 +++++++++
+ 3 files changed, 66 insertions(+)
+
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
+ 
+ 	  If unsure, say Y.
+ 
++config ARCH_WANT_LIBATA_LEDS
++	bool
++
++config ATA_LEDS
++	bool "support ATA port LED triggers"
++	depends on ARCH_WANT_LIBATA_LEDS
++	select NEW_LEDS
++	select LEDS_CLASS
++	select LEDS_TRIGGERS
++	default y
++	help
++	  This option adds a LED trigger for each registered ATA port.
++	  It is used to drive disk activity leds connected via GPIO.
++
++	  If unsure, say N.
++
+ config ATA_ACPI
+ 	bool "ATA ACPI Support"
+ 	depends on ACPI
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -728,6 +728,19 @@ u64 ata_tf_read_block(struct ata_taskfil
+ 	return block;
+ }
+ 
++#ifdef CONFIG_ATA_LEDS
++#define LIBATA_BLINK_DELAY 20 /* ms */
++static inline void ata_led_act(struct ata_port *ap)
++{
++	unsigned long led_delay = LIBATA_BLINK_DELAY;
++
++	if (unlikely(!ap->ledtrig))
++		return;
++
++	led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
++}
++#endif
++
+ /**
+  *	ata_build_rw_tf - Build ATA taskfile for given read/write request
+  *	@tf: Target ATA taskfile
+@@ -4780,6 +4793,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
+ 		if (tag < 0)
+ 			return NULL;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	ata_led_act(ap);
++#endif
+ 
+ 	qc = __ata_qc_from_tag(ap, tag);
+ 	qc->tag = tag;
+@@ -5677,6 +5693,9 @@ struct ata_port *ata_port_alloc(struct a
+ 	ap->stats.unhandled_irq = 1;
+ 	ap->stats.idle_irq = 1;
+ #endif
++#ifdef CONFIG_ATA_LEDS
++	ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
++#endif
+ 	ata_sff_port_init(ap);
+ 
+ 	return ap;
+@@ -5698,6 +5717,12 @@ static void ata_host_release(struct devi
+ 
+ 		kfree(ap->pmp_link);
+ 		kfree(ap->slave_link);
++#ifdef CONFIG_ATA_LEDS
++		if (ap->ledtrig) {
++			led_trigger_unregister(ap->ledtrig);
++			kfree(ap->ledtrig);
++		};
++#endif
+ 		kfree(ap);
+ 		host->ports[i] = NULL;
+ 	}
+@@ -6144,7 +6169,23 @@ int ata_host_register(struct ata_host *h
+ 		host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+ 		host->ports[i]->local_port_no = i + 1;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	for (i = 0; i < host->n_ports; i++) {
++		if (unlikely(!host->ports[i]->ledtrig))
++			continue;
+ 
++		snprintf(host->ports[i]->ledtrig_name,
++			sizeof(host->ports[i]->ledtrig_name), "ata%u",
++			host->ports[i]->print_id);
++
++		host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
++
++		if (led_trigger_register(host->ports[i]->ledtrig)) {
++			kfree(host->ports[i]->ledtrig);
++			host->ports[i]->ledtrig = NULL;
++		}
++	}
++#endif
+ 	/* Create associated sysfs transport objects  */
+ 	for (i = 0; i < host->n_ports; i++) {
+ 		rc = ata_tport_add(host->dev,host->ports[i]);
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -38,6 +38,9 @@
+ #include <linux/acpi.h>
+ #include <linux/cdrom.h>
+ #include <linux/sched.h>
++#ifdef CONFIG_ATA_LEDS
++#include <linux/leds.h>
++#endif
+ 
+ /*
+  * Define if arch has non-standard setup.  This is a _PCI_ standard
+@@ -877,6 +880,12 @@ struct ata_port {
+ #ifdef CONFIG_ATA_ACPI
+ 	struct ata_acpi_gtm	__acpi_init_gtm; /* use ata_acpi_init_gtm() */
+ #endif
++
++#ifdef CONFIG_ATA_LEDS
++	struct led_trigger	*ledtrig;
++	char			ledtrig_name[8];
++#endif
++
+ 	/* owned by EH */
+ 	u8			sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ };
diff --git a/target/linux/generic/patches-4.4/835-misc-owl_loader.patch b/target/linux/generic/patches-4.4/835-misc-owl_loader.patch
new file mode 100644
index 0000000000..c179020680
--- /dev/null
+++ b/target/linux/generic/patches-4.4/835-misc-owl_loader.patch
@@ -0,0 +1,31 @@
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -150,6 +150,18 @@ config SGI_IOC4
+ 	  If you have an SGI Altix with an IOC4-based card say Y.
+ 	  Otherwise say N.
+ 
++config OWL_LOADER
++	tristate "Owl loader for initializing Atheros PCI(e) Wifi chips"
++	depends on PCI
++	---help---
++	This kernel module helps to initialize certain Qualcomm
++	Atheros' PCI(e) Wifi chips, which have the init data
++	(which contains the PCI device ID for example) stored
++	together with the calibration data in the file system.
++
++	This is necessary for devices like the Cisco Meraki Z1, say M.
++	Otherwise say N.
++
+ config TIFM_CORE
+ 	tristate "TI Flash Media interface support"
+ 	depends on PCI
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_BMP085_SPI)	+= bmp085-spi.o
+ obj-$(CONFIG_DUMMY_IRQ)		+= dummy-irq.o
+ obj-$(CONFIG_ICS932S401)	+= ics932s401.o
+ obj-$(CONFIG_LKDTM)		+= lkdtm.o
++obj-$(CONFIG_OWL_LOADER)	+= owl-loader.o
+ obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
+ obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
+ obj-$(CONFIG_PHANTOM)		+= phantom.o
diff --git a/target/linux/generic/patches-4.4/840-rtc7301.patch b/target/linux/generic/patches-4.4/840-rtc7301.patch
new file mode 100644
index 0000000000..fafeb830e9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/840-rtc7301.patch
@@ -0,0 +1,250 @@
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -1132,6 +1132,15 @@ config RTC_DRV_ZYNQMP
+ 	  If you say yes here you get support for the RTC controller found on
+ 	  Xilinx Zynq Ultrascale+ MPSoC.
+ 
++config RTC_DRV_RTC7301
++	tristate "Epson RTC-7301 SF/DG"
++	help
++	  If you say Y here you will get support for the
++	  Epson RTC-7301 SF/DG RTC chips.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-7301.
++
+ comment "on-CPU RTC drivers"
+ 
+ config RTC_DRV_DAVINCI
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -125,6 +125,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01)	+= rtc-rp5c
+ obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
+ obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o
+ obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
++obj-$(CONFIG_RTC_DRV_RTC7301)	+= rtc-rtc7301.o
+ obj-$(CONFIG_RTC_DRV_RV3029C2)	+= rtc-rv3029c2.o
+ obj-$(CONFIG_RTC_DRV_RV8803)	+= rtc-rv8803.o
+ obj-$(CONFIG_RTC_DRV_RX4581)	+= rtc-rx4581.o
+--- /dev/null
++++ b/drivers/rtc/rtc-rtc7301.c
+@@ -0,0 +1,219 @@
++/*
++ * Driver for Epson RTC-7301SF/DG
++ *
++ * Copyright (C) 2009 Jose Vasconcellos
++ *
++ * 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/module.h>
++#include <linux/rtc.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/bcd.h>
++
++#define RTC_NAME "rtc7301"
++#define RTC_VERSION "0.1"
++
++/* Epson RTC-7301 register addresses */
++#define RTC7301_SEC		0x00
++#define RTC7301_SEC10		0x01
++#define RTC7301_MIN		0x02
++#define RTC7301_MIN10		0x03
++#define RTC7301_HOUR		0x04
++#define RTC7301_HOUR10		0x05
++#define RTC7301_WEEKDAY		0x06
++#define RTC7301_DAY		0x07
++#define RTC7301_DAY10		0x08
++#define RTC7301_MON		0x09
++#define RTC7301_MON10		0x0A
++#define RTC7301_YEAR		0x0B
++#define RTC7301_YEAR10		0x0C
++#define RTC7301_YEAR100		0x0D
++#define RTC7301_YEAR1000	0x0E
++#define RTC7301_CTRLREG		0x0F
++
++static uint8_t __iomem *rtc7301_base;
++
++#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf)
++#define write_reg(offset, data) writeb(data, rtc7301_base + (offset))
++
++#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1)
++
++static void rtc7301_init_settings(void)
++{
++	int i;
++
++	write_reg(RTC7301_CTRLREG, 2);
++	write_reg(RTC7301_YEAR1000, 2);
++	udelay(122);
++
++	/* bank 1 */
++	write_reg(RTC7301_CTRLREG, 6);
++	for (i=0; i<15; i++)
++		write_reg(i, 0);
++
++	/* bank 2 */
++	write_reg(RTC7301_CTRLREG, 14);
++	for (i=0; i<15; i++)
++		write_reg(i, 0);
++	write_reg(RTC7301_CTRLREG, 0);
++}
++
++static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt)
++{
++	int cnt;
++	uint8_t buf[16];
++
++	cnt = 0;
++	while (rtc7301_isbusy()) {
++		udelay(244);
++		if (cnt++ > 100) {
++			dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]);
++			return -EIO;
++		}
++	}
++
++	for (cnt=0; cnt<16; cnt++)
++		buf[cnt] = read_reg(cnt);
++
++	if (buf[RTC7301_SEC10] & 8) {
++		dev_err(dev, "%s: RTC not set\n", __func__);
++		return -EINVAL;
++	}
++
++	memset(dt, 0, sizeof(*dt));
++
++	dt->tm_sec =  buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10;
++	dt->tm_min =  buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10;
++	dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10;
++
++	dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10;
++	dt->tm_mon =  buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1;
++	dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 +
++		      buf[RTC7301_YEAR100]*100 +
++		      ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900;
++
++	/* the rtc device may contain illegal values on power up
++	 * according to the data sheet. make sure they are valid.
++	 */
++
++	return rtc_valid_tm(dt);
++}
++
++static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt)
++{
++	int data;
++
++	data = dt->tm_year + 1900;
++	if (data >= 2100 || data < 1900)
++		return -EINVAL;
++
++	write_reg(RTC7301_CTRLREG, 2);
++       	udelay(122);
++
++	data = bin2bcd(dt->tm_sec);
++	write_reg(RTC7301_SEC, data);
++	write_reg(RTC7301_SEC10, (data >> 4));
++
++	data = bin2bcd(dt->tm_min);
++	write_reg(RTC7301_MIN, data );
++	write_reg(RTC7301_MIN10, (data >> 4));
++
++	data = bin2bcd(dt->tm_hour);
++	write_reg(RTC7301_HOUR, data);
++	write_reg(RTC7301_HOUR10, (data >> 4));
++
++	data = bin2bcd(dt->tm_mday);
++	write_reg(RTC7301_DAY, data);
++	write_reg(RTC7301_DAY10, (data>> 4));
++
++	data = bin2bcd(dt->tm_mon + 1);
++	write_reg(RTC7301_MON, data);
++	write_reg(RTC7301_MON10, (data >> 4));
++
++	data = bin2bcd(dt->tm_year % 100);
++	write_reg(RTC7301_YEAR, data);
++	write_reg(RTC7301_YEAR10, (data >> 4));
++	data = bin2bcd((1900 + dt->tm_year) / 100);
++	write_reg(RTC7301_YEAR100, data);
++
++	data = bin2bcd(dt->tm_wday);
++	write_reg(RTC7301_WEEKDAY, data);
++
++	write_reg(RTC7301_CTRLREG, 0);
++
++	return 0;
++}
++
++static const struct rtc_class_ops rtc7301_rtc_ops = {
++	.read_time	= rtc7301_get_datetime,
++	.set_time	= rtc7301_set_datetime,
++};
++
++static int rtc7301_probe(struct platform_device *pdev)
++{
++	struct rtc_device *rtc;
++	struct resource *res;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENOENT;
++
++	rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/);
++	if (!rtc7301_base)
++		return -EINVAL;
++
++	rtc = rtc_device_register(RTC_NAME, &pdev->dev,
++				&rtc7301_rtc_ops, THIS_MODULE);
++	if (IS_ERR(rtc)) {
++		iounmap(rtc7301_base);
++		return PTR_ERR(rtc);
++	}
++
++	platform_set_drvdata(pdev, rtc);
++
++	rtc7301_init_settings();
++	return 0;
++}
++
++static int rtc7301_remove(struct platform_device *pdev)
++{
++	struct rtc_device *rtc = platform_get_drvdata(pdev);
++
++	if (rtc)
++		rtc_device_unregister(rtc);
++	if (rtc7301_base)
++		iounmap(rtc7301_base);
++	return 0;
++}
++
++static struct platform_driver rtc7301_driver = {
++	.driver = {
++		.name	= RTC_NAME,
++		.owner	= THIS_MODULE,
++	},
++	.probe	= rtc7301_probe,
++	.remove = rtc7301_remove,
++};
++
++static __init int rtc7301_init(void)
++{
++	return platform_driver_register(&rtc7301_driver);
++}
++module_init(rtc7301_init);
++
++static __exit void rtc7301_exit(void)
++{
++	platform_driver_unregister(&rtc7301_driver);
++}
++module_exit(rtc7301_exit);
++
++MODULE_DESCRIPTION("Epson 7301 RTC driver");
++MODULE_AUTHOR("Jose Vasconcellos <jvasco@verizon.net>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" RTC_NAME);
++MODULE_VERSION(RTC_VERSION);
diff --git a/target/linux/generic/patches-4.4/841-rtc_pt7c4338.patch b/target/linux/generic/patches-4.4/841-rtc_pt7c4338.patch
new file mode 100644
index 0000000000..4235efa38a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/841-rtc_pt7c4338.patch
@@ -0,0 +1,247 @@
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -612,6 +612,15 @@ config RTC_DRV_S5M
+ 	  This driver can also be built as a module. If so, the module
+ 	  will be called rtc-s5m.
+ 
++config RTC_DRV_PT7C4338
++	tristate "Pericom Technology Inc. PT7C4338 RTC"
++	help
++	  If you say yes here you get support for the Pericom Technology
++	  Inc. PT7C4338 RTC chip.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-pt7c4338.
++
+ endif # I2C
+ 
+ comment "SPI RTC drivers"
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -116,6 +116,7 @@ obj-$(CONFIG_RTC_DRV_PL030)	+= rtc-pl030
+ obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
+ obj-$(CONFIG_RTC_DRV_PM8XXX)	+= rtc-pm8xxx.o
+ obj-$(CONFIG_RTC_DRV_PS3)	+= rtc-ps3.o
++obj-$(CONFIG_RTC_DRV_PT7C4338)	+= rtc-pt7c4338.o
+ obj-$(CONFIG_RTC_DRV_PUV3)	+= rtc-puv3.o
+ obj-$(CONFIG_RTC_DRV_PXA)	+= rtc-pxa.o
+ obj-$(CONFIG_RTC_DRV_R9701)	+= rtc-r9701.o
+--- /dev/null
++++ b/drivers/rtc/rtc-pt7c4338.c
+@@ -0,0 +1,216 @@
++/*
++ * Copyright 2010 Freescale Semiconductor, Inc.
++ *
++ * Author:	Priyanka Jain <Priyanka.Jain@freescale.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++/*
++ * This file provides Date & Time support (no alarms) for PT7C4338 chip.
++ *
++ * This file is based on drivers/rtc/rtc-ds1307.c
++ *
++ * PT7C4338 chip is manufactured by Pericom Technology Inc.
++ * It is a serial real-time clock which provides
++ * 1)Low-power clock/calendar.
++ * 2)Programmable square-wave output.
++ * It has 56 bytes of nonvolatile RAM.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/rtc.h>
++#include <linux/bcd.h>
++
++/* RTC register addresses */
++#define PT7C4338_REG_SECONDS          0x00
++#define PT7C4338_REG_MINUTES          0x01
++#define PT7C4338_REG_HOURS            0x02
++#define PT7C4338_REG_AMPM             0x02
++#define PT7C4338_REG_DAY              0x03
++#define PT7C4338_REG_DATE             0x04
++#define PT7C4338_REG_MONTH            0x05
++#define PT7C4338_REG_YEAR             0x06
++#define PT7C4338_REG_CTRL_STAT        0x07
++
++/* RTC second register address bit */
++#define PT7C4338_SEC_BIT_CH           0x80	/*Clock Halt (in Register 0)*/
++
++/* RTC control and status register bits */
++#define PT7C4338_CTRL_STAT_BIT_RS0    0x1	/*Rate select 0*/
++#define PT7C4338_CTRL_STAT_BIT_RS1    0x2	/*Rate select 1*/
++#define PT7C4338_CTRL_STAT_BIT_SQWE   0x10	/*Square Wave Enable*/
++#define PT7C4338_CTRL_STAT_BIT_OSF    0x20	/*Oscillator Stop Flag*/
++#define PT7C4338_CTRL_STAT_BIT_OUT    0x80	/*Output Level Control*/
++
++static const struct i2c_device_id pt7c4338_id[] = {
++	{ "pt7c4338", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, pt7c4338_id);
++
++struct pt7c4338{
++	struct i2c_client *client;
++	struct rtc_device *rtc;
++};
++
++static int pt7c4338_read_time(struct device *dev, struct rtc_time *time)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	int ret;
++	u8 buf[7];
++	u8 year, month, day, hour, minute, second;
++	u8 week, twelve_hr, am_pm;
++
++	ret = i2c_smbus_read_i2c_block_data(client,
++			PT7C4338_REG_SECONDS, 7, buf);
++	if (ret < 0)
++		return ret;
++	if (ret < 7)
++		return -EIO;
++
++	second = buf[0];
++	minute = buf[1];
++	hour = buf[2];
++	week = buf[3];
++	day = buf[4];
++	month = buf[5];
++	year = buf[6];
++
++	/* Extract additional information for AM/PM */
++	twelve_hr = hour & 0x40;
++	am_pm = hour & 0x20;
++
++	/* Write to rtc_time structure */
++	time->tm_sec = bcd2bin(second & 0x7f);
++	time->tm_min = bcd2bin(minute & 0x7f);
++	if (twelve_hr) {
++		/* Convert to 24 hr */
++		if (am_pm)
++			time->tm_hour = bcd2bin(hour & 0x10) + 12;
++		else
++			time->tm_hour = bcd2bin(hour & 0xBF);
++	} else {
++		time->tm_hour = bcd2bin(hour);
++	}
++
++	time->tm_wday = bcd2bin(week & 0x07) - 1;
++	time->tm_mday = bcd2bin(day & 0x3f);
++	time->tm_mon = bcd2bin(month & 0x1F) - 1;
++	/* assume 20YY not 19YY */
++	time->tm_year = bcd2bin(year) + 100;
++
++	return 0;
++}
++
++static int pt7c4338_set_time(struct device *dev, struct rtc_time *time)
++{
++	struct i2c_client *client = to_i2c_client(dev);
++	u8 buf[7];
++
++	/* Extract time from rtc_time and load into pt7c4338*/
++	buf[0] = bin2bcd(time->tm_sec);
++	buf[1] = bin2bcd(time->tm_min);
++	buf[2] = bin2bcd(time->tm_hour);
++	buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */
++	buf[4] = bin2bcd(time->tm_mday); /* Date */
++	buf[5] = bin2bcd(time->tm_mon + 1);
++
++	/* assume 20YY not 19YY */
++	if (time->tm_year >= 100)
++		buf[6] = bin2bcd(time->tm_year - 100);
++	else
++		buf[6] = bin2bcd(time->tm_year);
++
++	return i2c_smbus_write_i2c_block_data(client,
++					PT7C4338_REG_SECONDS, 7, buf);
++}
++
++static const struct rtc_class_ops pt7c4338_rtc_ops = {
++	.read_time = pt7c4338_read_time,
++	.set_time = pt7c4338_set_time,
++};
++
++static int pt7c4338_probe(struct i2c_client *client,
++		const struct i2c_device_id *id)
++{
++	struct pt7c4338 *pt7c4338;
++	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
++	int ret;
++
++	pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL);
++	if (!pt7c4338)
++		return -ENOMEM;
++
++	pt7c4338->client = client;
++	i2c_set_clientdata(client, pt7c4338);
++	pt7c4338->rtc = rtc_device_register(client->name, &client->dev,
++					&pt7c4338_rtc_ops, THIS_MODULE);
++	if (IS_ERR(pt7c4338->rtc)) {
++		ret = PTR_ERR(pt7c4338->rtc);
++		dev_err(&client->dev, "unable to register the class device\n");
++		goto out_free;
++	}
++
++	return 0;
++out_free:
++	i2c_set_clientdata(client, NULL);
++	kfree(pt7c4338);
++	return ret;
++}
++
++static int pt7c4338_remove(struct i2c_client *client)
++{
++	struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client);
++
++	rtc_device_unregister(pt7c4338->rtc);
++	i2c_set_clientdata(client, NULL);
++	kfree(pt7c4338);
++	return 0;
++}
++
++static struct i2c_driver pt7c4338_driver = {
++	.driver = {
++		.name = "rtc-pt7c4338",
++		.owner = THIS_MODULE,
++	},
++	.probe = pt7c4338_probe,
++	.remove = pt7c4338_remove,
++	.id_table = pt7c4338_id,
++};
++
++static int __init pt7c4338_init(void)
++{
++	return i2c_add_driver(&pt7c4338_driver);
++}
++
++static void __exit pt7c4338_exit(void)
++{
++	i2c_del_driver(&pt7c4338_driver);
++}
++
++module_init(pt7c4338_init);
++module_exit(pt7c4338_exit);
++
++MODULE_AUTHOR("Priyanka Jain <Priyanka.Jain@freescale.com>");
++MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic/patches-4.4/861-04_spi_gpio_implement_spi_delay.patch b/target/linux/generic/patches-4.4/861-04_spi_gpio_implement_spi_delay.patch
new file mode 100644
index 0000000000..fc1b40c035
--- /dev/null
+++ b/target/linux/generic/patches-4.4/861-04_spi_gpio_implement_spi_delay.patch
@@ -0,0 +1,58 @@
+Implement the SPI-GPIO delay function for busses that need speed limitation.
+
+--mb
+
+
+
+--- a/drivers/spi/spi-gpio.c
++++ b/drivers/spi/spi-gpio.c
+@@ -17,6 +17,7 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/gpio.h>
++#include <linux/delay.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_gpio.h>
+@@ -69,6 +70,7 @@ struct spi_gpio {
+  *		#define	SPI_MOSI_GPIO	120
+  *		#define	SPI_SCK_GPIO	121
+  *		#define	SPI_N_CHIPSEL	4
++ *		#undef NEED_SPIDELAY
+  *		#include "spi-gpio.c"
+  */
+ 
+@@ -76,6 +78,7 @@ struct spi_gpio {
+ #define DRIVER_NAME	"spi_gpio"
+ 
+ #define GENERIC_BITBANG	/* vs tight inlines */
++#define NEED_SPIDELAY	1
+ 
+ /* all functions referencing these symbols must define pdata */
+ #define SPI_MISO_GPIO	((pdata)->miso)
+@@ -126,12 +129,20 @@ static inline int getmiso(const struct s
+ #undef pdata
+ 
+ /*
+- * NOTE:  this clocks "as fast as we can".  It "should" be a function of the
+- * requested device clock.  Software overhead means we usually have trouble
+- * reaching even one Mbit/sec (except when we can inline bitops), so for now
+- * we'll just assume we never need additional per-bit slowdowns.
++ * NOTE:  to clock "as fast as we can", set spi_device.max_speed_hz
++ * and spi_transfer.speed_hz to 0.
++ * Otherwise this is a function of the requested device clock.
++ * Software overhead means we usually have trouble
++ * reaching even one Mbit/sec (except when we can inline bitops). So on small
++ * embedded devices with fast SPI slaves you usually don't need a delay.
+  */
+-#define spidelay(nsecs)	do {} while (0)
++static inline void spidelay(unsigned nsecs)
++{
++#ifdef NEED_SPIDELAY
++	if (unlikely(nsecs))
++		ndelay(nsecs);
++#endif /* NEED_SPIDELAY */
++}
+ 
+ #include "spi-bitbang-txrx.h"
+ 
diff --git a/target/linux/generic/patches-4.4/862-gpio_spi_driver.patch b/target/linux/generic/patches-4.4/862-gpio_spi_driver.patch
new file mode 100644
index 0000000000..8f334ec396
--- /dev/null
+++ b/target/linux/generic/patches-4.4/862-gpio_spi_driver.patch
@@ -0,0 +1,373 @@
+THIS CODE IS DEPRECATED.
+
+Please use the new mainline SPI-GPIO driver, as of 2.6.29.
+
+--mb
+
+
+
+---
+ drivers/spi/Kconfig              |    9 +
+ drivers/spi/Makefile             |    1 
+ drivers/spi/spi_gpio_old.c       |  251 +++++++++++++++++++++++++++++++++++++++
+ include/linux/spi/spi_gpio_old.h |   73 +++++++++++
+ 4 files changed, 334 insertions(+)
+
+--- /dev/null
++++ b/include/linux/spi/spi_gpio_old.h
+@@ -0,0 +1,73 @@
++/*
++ * spi_gpio interface to platform code
++ *
++ * Copyright (c) 2008 Piotr Skamruk
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * 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.
++ */
++#ifndef _LINUX_SPI_SPI_GPIO
++#define _LINUX_SPI_SPI_GPIO
++
++#include <linux/types.h>
++#include <linux/spi/spi.h>
++
++
++/**
++ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
++ *
++ * This structure holds information about a GPIO-based SPI device.
++ *
++ * @pin_clk: The GPIO pin number of the CLOCK pin.
++ *
++ * @pin_miso: The GPIO pin number of the MISO pin.
++ *
++ * @pin_mosi: The GPIO pin number of the MOSI pin.
++ *
++ * @pin_cs: The GPIO pin number of the CHIPSELECT pin.
++ *
++ * @cs_activelow: If true, the chip is selected when the CS line is low.
++ *
++ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
++ *                Note that doing no delay is not standards compliant,
++ *                but it might be needed to speed up transfers on some
++ *                slow embedded machines.
++ *
++ * @boardinfo_setup: This callback is called after the
++ *                   SPI master device was registered, but before the
++ *                   device is registered.
++ * @boardinfo_setup_data: Data argument passed to boardinfo_setup().
++ */
++struct spi_gpio_platform_data {
++	unsigned int pin_clk;
++	unsigned int pin_miso;
++	unsigned int pin_mosi;
++	unsigned int pin_cs;
++	bool cs_activelow;
++	bool no_spi_delay;
++	int (*boardinfo_setup)(struct spi_board_info *bi,
++			       struct spi_master *master,
++			       void *data);
++	void *boardinfo_setup_data;
++};
++
++/**
++ * SPI_GPIO_PLATDEV_NAME - The platform device name string.
++ *
++ * The name string that has to be used for platform_device_alloc
++ * when allocating a spi-gpio device.
++ */
++#define SPI_GPIO_PLATDEV_NAME	"spi-gpio"
++
++/**
++ * spi_gpio_next_id - Get another platform device ID number.
++ *
++ * This returns the next platform device ID number that has to be used
++ * for platform_device_alloc. The ID is opaque and should not be used for
++ * anything else.
++ */
++int spi_gpio_next_id(void);
++
++#endif /* _LINUX_SPI_SPI_GPIO */
+--- /dev/null
++++ b/drivers/spi/spi_gpio_old.c
+@@ -0,0 +1,251 @@
++/*
++ * Bitbanging SPI bus driver using GPIO API
++ *
++ * Copyright (c) 2008 Piotr Skamruk
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * based on spi_s3c2410_gpio.c
++ *   Copyright (c) 2006 Ben Dooks
++ *   Copyright (c) 2006 Simtec Electronics
++ * and on i2c-gpio.c
++ *   Copyright (C) 2007 Atmel Corporation
++ *
++ * 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/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/gpio.h>
++#include <asm/atomic.h>
++
++
++struct spi_gpio {
++	struct spi_bitbang bitbang;
++	struct spi_gpio_platform_data *info;
++	struct platform_device *pdev;
++	struct spi_board_info bi;
++};
++
++
++static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
++{
++	return dev->controller_data;
++}
++
++static inline void setsck(struct spi_device *dev, int val)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
++}
++
++static inline void setmosi(struct spi_device *dev, int val)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
++}
++
++static inline u32 getmiso(struct spi_device *dev)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++	return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
++}
++
++static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++
++	if (!sp->info->no_spi_delay)
++		ndelay(nsecs);
++}
++
++#define spidelay(nsecs) do {					\
++	/* Steal the spi_device pointer from our caller.	\
++	 * The bitbang-API should probably get fixed here... */	\
++	do_spidelay(spi, nsecs);				\
++  } while (0)
++
++#define EXPAND_BITBANG_TXRX
++#include "spi-bitbang-txrx.h"
++
++static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
++}
++
++static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
++			       unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
++}
++
++static void spi_gpio_chipselect(struct spi_device *dev, int on)
++{
++	struct spi_gpio *sp = spidev_to_sg(dev);
++
++	if (sp->info->cs_activelow)
++		on = !on;
++	gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
++}
++
++static int spi_gpio_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct spi_gpio_platform_data *pdata;
++	struct spi_gpio *sp;
++	struct spi_device *spidev;
++	int err;
++
++	pdata = pdev->dev.platform_data;
++	if (!pdata)
++		return -ENXIO;
++
++	err = -ENOMEM;
++	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
++	if (!master)
++		goto err_alloc_master;
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++	sp->info = pdata;
++
++	err = gpio_request(pdata->pin_clk, "spi_clock");
++	if (err)
++		goto err_request_clk;
++	err = gpio_request(pdata->pin_mosi, "spi_mosi");
++	if (err)
++		goto err_request_mosi;
++	err = gpio_request(pdata->pin_miso, "spi_miso");
++	if (err)
++		goto err_request_miso;
++	err = gpio_request(pdata->pin_cs, "spi_cs");
++	if (err)
++		goto err_request_cs;
++
++	sp->bitbang.master = spi_master_get(master);
++	sp->bitbang.master->bus_num = -1;
++	sp->bitbang.master->num_chipselect = 1;
++	sp->bitbang.chipselect = spi_gpio_chipselect;
++	sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
++	sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
++	sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
++	sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
++
++	gpio_direction_output(pdata->pin_clk, 0);
++	gpio_direction_output(pdata->pin_mosi, 0);
++	gpio_direction_output(pdata->pin_cs,
++			      pdata->cs_activelow ? 1 : 0);
++	gpio_direction_input(pdata->pin_miso);
++
++	err = spi_bitbang_start(&sp->bitbang);
++	if (err)
++		goto err_no_bitbang;
++	err = pdata->boardinfo_setup(&sp->bi, master,
++				     pdata->boardinfo_setup_data);
++	if (err)
++		goto err_bi_setup;
++	sp->bi.controller_data = sp;
++	spidev = spi_new_device(master, &sp->bi);
++	if (!spidev)
++		goto err_new_dev;
++
++	return 0;
++
++err_new_dev:
++err_bi_setup:
++	spi_bitbang_stop(&sp->bitbang);
++err_no_bitbang:
++	spi_master_put(sp->bitbang.master);
++	gpio_free(pdata->pin_cs);
++err_request_cs:
++	gpio_free(pdata->pin_miso);
++err_request_miso:
++	gpio_free(pdata->pin_mosi);
++err_request_mosi:
++	gpio_free(pdata->pin_clk);
++err_request_clk:
++	kfree(master);
++
++err_alloc_master:
++	return err;
++}
++
++static int spi_gpio_remove(struct platform_device *pdev)
++{
++	struct spi_gpio *sp;
++	struct spi_gpio_platform_data *pdata;
++
++	pdata = pdev->dev.platform_data;
++	sp = platform_get_drvdata(pdev);
++
++	gpio_free(pdata->pin_clk);
++	gpio_free(pdata->pin_mosi);
++	gpio_free(pdata->pin_miso);
++	gpio_free(pdata->pin_cs);
++	spi_bitbang_stop(&sp->bitbang);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++static struct platform_driver spi_gpio_driver = {
++	.driver		= {
++		.name	= SPI_GPIO_PLATDEV_NAME,
++		.owner	= THIS_MODULE,
++	},
++	.probe		= spi_gpio_probe,
++	.remove		= spi_gpio_remove,
++};
++
++int spi_gpio_next_id(void)
++{
++	static atomic_t counter = ATOMIC_INIT(-1);
++
++	return atomic_inc_return(&counter);
++}
++EXPORT_SYMBOL(spi_gpio_next_id);
++
++static int __init spi_gpio_init(void)
++{
++	int err;
++
++	err = platform_driver_register(&spi_gpio_driver);
++	if (err)
++		printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
++
++	return err;
++}
++module_init(spi_gpio_init);
++
++static void __exit spi_gpio_exit(void)
++{
++	platform_driver_unregister(&spi_gpio_driver);
++}
++module_exit(spi_gpio_exit);
++
++MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
++MODULE_AUTHOR("Michael Buesch");
++MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver");
++MODULE_LICENSE("GPL v2");
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -254,6 +254,15 @@ config SPI_IMG_SPFI
+ 	  This enables support for the SPFI master controller found on
+ 	  IMG SoCs.
+ 
++config SPI_GPIO_OLD
++	tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)"
++	depends on SPI_MASTER && GPIOLIB
++	select SPI_BITBANG
++	help
++	  This code is deprecated. Please use the new mainline SPI-GPIO driver.
++
++	  If unsure, say N.
++
+ config SPI_IMX
+ 	tristate "Freescale i.MX SPI controllers"
+ 	depends on ARCH_MXC || COMPILE_TEST
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -42,6 +42,7 @@ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-li
+ obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o
+ obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o
+ obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o
++obj-$(CONFIG_SPI_GPIO_OLD)		+= spi_gpio_old.o
+ obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o
+ obj-$(CONFIG_SPI_IMX)			+= spi-imx.o
+ obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
diff --git a/target/linux/generic/patches-4.4/863-gpiommc.patch b/target/linux/generic/patches-4.4/863-gpiommc.patch
new file mode 100644
index 0000000000..ea3599ea0d
--- /dev/null
+++ b/target/linux/generic/patches-4.4/863-gpiommc.patch
@@ -0,0 +1,844 @@
+--- /dev/null
++++ b/drivers/mmc/host/gpiommc.c
+@@ -0,0 +1,609 @@
++/*
++ * Driver an MMC/SD card on a bitbanging GPIO SPI bus.
++ * This module hooks up the mmc_spi and spi_gpio modules and also
++ * provides a configfs interface.
++ *
++ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/module.h>
++#include <linux/mmc/gpiommc.h>
++#include <linux/platform_device.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/spi/spi_gpio_old.h>
++#include <linux/configfs.h>
++#include <linux/gpio.h>
++#include <asm/atomic.h>
++
++
++#define PFX				"gpio-mmc: "
++
++
++struct gpiommc_device {
++	struct platform_device *pdev;
++	struct platform_device *spi_pdev;
++	struct spi_board_info boardinfo;
++};
++
++
++MODULE_DESCRIPTION("GPIO based MMC driver");
++MODULE_AUTHOR("Michael Buesch");
++MODULE_LICENSE("GPL");
++
++
++static int gpiommc_boardinfo_setup(struct spi_board_info *bi,
++				   struct spi_master *master,
++				   void *data)
++{
++	struct gpiommc_device *d = data;
++	struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
++
++	/* Bind the SPI master to the MMC-SPI host driver. */
++	strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias));
++
++	bi->max_speed_hz = pdata->max_bus_speed;
++	bi->bus_num = master->bus_num;
++	bi->mode = pdata->mode;
++
++	return 0;
++}
++
++static int gpiommc_probe(struct platform_device *pdev)
++{
++	struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data;
++	struct spi_gpio_platform_data spi_pdata;
++	struct gpiommc_device *d;
++	int err;
++
++	err = -ENXIO;
++	if (!mmc_pdata)
++		goto error;
++
++#ifdef CONFIG_MMC_SPI_MODULE
++	err = request_module("mmc_spi");
++	if (err) {
++		printk(KERN_WARNING PFX
++		       "Failed to request mmc_spi module.\n");
++	}
++#endif /* CONFIG_MMC_SPI_MODULE */
++
++	/* Allocate the GPIO-MMC device */
++	err = -ENOMEM;
++	d = kzalloc(sizeof(*d), GFP_KERNEL);
++	if (!d)
++		goto error;
++	d->pdev = pdev;
++
++	/* Create the SPI-GPIO device */
++	d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME,
++					    spi_gpio_next_id());
++	if (!d->spi_pdev)
++		goto err_free_d;
++
++	memset(&spi_pdata, 0, sizeof(spi_pdata));
++	spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk;
++	spi_pdata.pin_miso = mmc_pdata->pins.gpio_do;
++	spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di;
++	spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs;
++	spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow;
++	spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay;
++	spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup;
++	spi_pdata.boardinfo_setup_data = d;
++
++	err = platform_device_add_data(d->spi_pdev, &spi_pdata,
++				       sizeof(spi_pdata));
++	if (err)
++		goto err_free_pdev;
++	err = platform_device_add(d->spi_pdev);
++	if (err)
++		goto err_free_pdata;
++	platform_set_drvdata(pdev, d);
++
++	printk(KERN_INFO PFX "MMC-Card \"%s\" "
++	       "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n",
++	       mmc_pdata->name, mmc_pdata->pins.gpio_di,
++	       mmc_pdata->pins.gpio_do,
++	       mmc_pdata->pins.gpio_clk,
++	       mmc_pdata->pins.gpio_cs);
++
++	return 0;
++
++err_free_pdata:
++	kfree(d->spi_pdev->dev.platform_data);
++	d->spi_pdev->dev.platform_data = NULL;
++err_free_pdev:
++	platform_device_put(d->spi_pdev);
++err_free_d:
++	kfree(d);
++error:
++	return err;
++}
++
++static int gpiommc_remove(struct platform_device *pdev)
++{
++	struct gpiommc_device *d = platform_get_drvdata(pdev);
++	struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
++
++	platform_device_unregister(d->spi_pdev);
++	printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n",
++	       pdata->name);
++	platform_device_put(d->spi_pdev);
++
++	return 0;
++}
++
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++
++/* A device that was created through configfs */
++struct gpiommc_configfs_device {
++	struct config_item item;
++	/* The platform device, after registration. */
++	struct platform_device *pdev;
++	/* The configuration */
++	struct gpiommc_platform_data pdata;
++};
++
++#define GPIO_INVALID	-1
++
++static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev)
++{
++	return (dev->pdev != NULL);
++}
++
++static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item)
++{
++	return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL;
++}
++
++static struct configfs_attribute gpiommc_attr_DI = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_data_in",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_DO = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_data_out",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CLK = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_clock",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CS = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_chipselect",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_CS_activelow = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "gpio_chipselect_activelow",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_spimode = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "spi_mode",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_spidelay = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "spi_delay",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_max_bus_speed = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "max_bus_speed",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute gpiommc_attr_register = {
++	.ca_owner = THIS_MODULE,
++	.ca_name = "register",
++	.ca_mode = S_IRUGO | S_IWUSR,
++};
++
++static struct configfs_attribute *gpiommc_config_attrs[] = {
++	&gpiommc_attr_DI,
++	&gpiommc_attr_DO,
++	&gpiommc_attr_CLK,
++	&gpiommc_attr_CS,
++	&gpiommc_attr_CS_activelow,
++	&gpiommc_attr_spimode,
++	&gpiommc_attr_spidelay,
++	&gpiommc_attr_max_bus_speed,
++	&gpiommc_attr_register,
++	NULL,
++};
++
++static ssize_t gpiommc_config_attr_show(struct config_item *item,
++					struct configfs_attribute *attr,
++					char *page)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++	ssize_t count = 0;
++	unsigned int gpio;
++	int err = 0;
++
++	if (attr == &gpiommc_attr_DI) {
++		gpio = dev->pdata.pins.gpio_di;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_DO) {
++		gpio = dev->pdata.pins.gpio_do;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CLK) {
++		gpio = dev->pdata.pins.gpio_clk;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS) {
++		gpio = dev->pdata.pins.gpio_cs;
++		if (gpio == GPIO_INVALID)
++			count = snprintf(page, PAGE_SIZE, "not configured\n");
++		else
++			count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS_activelow) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.pins.cs_activelow);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spimode) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.mode);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spidelay) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 !dev->pdata.no_spi_delay);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_max_bus_speed) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 dev->pdata.max_bus_speed);
++		goto out;
++	}
++	if (attr == &gpiommc_attr_register) {
++		count = snprintf(page, PAGE_SIZE, "%u\n",
++				 gpiommc_is_registered(dev));
++		goto out;
++	}
++	WARN_ON(1);
++	err = -ENOSYS;
++out:
++	return err ? err : count;
++}
++
++static int gpiommc_do_register(struct gpiommc_configfs_device *dev,
++			       const char *name)
++{
++	int err;
++
++	if (gpiommc_is_registered(dev))
++		return 0;
++
++	if (!gpio_is_valid(dev->pdata.pins.gpio_di) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_do) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_clk) ||
++	    !gpio_is_valid(dev->pdata.pins.gpio_cs)) {
++		printk(KERN_ERR PFX
++		       "configfs: Invalid GPIO pin number(s)\n");
++		return -EINVAL;
++	}
++
++	strlcpy(dev->pdata.name, name,
++		sizeof(dev->pdata.name));
++
++	dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME,
++					  gpiommc_next_id());
++	if (!dev->pdev)
++		return -ENOMEM;
++	err = platform_device_add_data(dev->pdev, &dev->pdata,
++				       sizeof(dev->pdata));
++	if (err) {
++		platform_device_put(dev->pdev);
++		return err;
++	}
++	err = platform_device_add(dev->pdev);
++	if (err) {
++		platform_device_put(dev->pdev);
++		return err;
++	}
++
++	return 0;
++}
++
++static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev)
++{
++	if (!gpiommc_is_registered(dev))
++		return;
++
++	platform_device_unregister(dev->pdev);
++	dev->pdev = NULL;
++}
++
++static ssize_t gpiommc_config_attr_store(struct config_item *item,
++					 struct configfs_attribute *attr,
++					 const char *page, size_t count)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++	int err = -EINVAL;
++	unsigned long data;
++
++	if (attr == &gpiommc_attr_register) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data == 1)
++			err = gpiommc_do_register(dev, item->ci_name);
++		if (data == 0) {
++			gpiommc_do_unregister(dev);
++			err = 0;
++		}
++		goto out;
++	}
++
++	if (gpiommc_is_registered(dev)) {
++		/* The rest of the config parameters can only be set
++		 * as long as the device is not registered, yet. */
++		err = -EBUSY;
++		goto out;
++	}
++
++	if (attr == &gpiommc_attr_DI) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_di = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_DO) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_do = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CLK) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_clk = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (!gpio_is_valid(data))
++			goto out;
++		dev->pdata.pins.gpio_cs = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_CS_activelow) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data != 0 && data != 1)
++			goto out;
++		dev->pdata.pins.cs_activelow = data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spimode) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		switch (data) {
++		case 0:
++			dev->pdata.mode = SPI_MODE_0;
++			break;
++		case 1:
++			dev->pdata.mode = SPI_MODE_1;
++			break;
++		case 2:
++			dev->pdata.mode = SPI_MODE_2;
++			break;
++		case 3:
++			dev->pdata.mode = SPI_MODE_3;
++			break;
++		default:
++			goto out;
++		}
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_spidelay) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data != 0 && data != 1)
++			goto out;
++		dev->pdata.no_spi_delay = !data;
++		err = 0;
++		goto out;
++	}
++	if (attr == &gpiommc_attr_max_bus_speed) {
++		err = kstrtoul(page, 10, &data);
++		if (err)
++			goto out;
++		err = -EINVAL;
++		if (data > UINT_MAX)
++			goto out;
++		dev->pdata.max_bus_speed = data;
++		err = 0;
++		goto out;
++	}
++	WARN_ON(1);
++	err = -ENOSYS;
++out:
++	return err ? err : count;
++}
++
++static void gpiommc_config_item_release(struct config_item *item)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++
++	kfree(dev);
++}
++
++static struct configfs_item_operations gpiommc_config_item_ops = {
++	.release		= gpiommc_config_item_release,
++	.show_attribute		= gpiommc_config_attr_show,
++	.store_attribute	= gpiommc_config_attr_store,
++};
++
++static struct config_item_type gpiommc_dev_ci_type = {
++	.ct_item_ops	= &gpiommc_config_item_ops,
++	.ct_attrs	= gpiommc_config_attrs,
++	.ct_owner	= THIS_MODULE,
++};
++
++static struct config_item *gpiommc_make_item(struct config_group *group,
++					     const char *name)
++{
++	struct gpiommc_configfs_device *dev;
++
++	if (strlen(name) > GPIOMMC_MAX_NAMELEN) {
++		printk(KERN_ERR PFX "configfs: device name too long\n");
++		return NULL;
++	}
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++	if (!dev)
++		return NULL;
++
++	config_item_init_type_name(&dev->item, name,
++				   &gpiommc_dev_ci_type);
++
++	/* Assign default configuration */
++	dev->pdata.pins.gpio_di = GPIO_INVALID;
++	dev->pdata.pins.gpio_do = GPIO_INVALID;
++	dev->pdata.pins.gpio_clk = GPIO_INVALID;
++	dev->pdata.pins.gpio_cs = GPIO_INVALID;
++	dev->pdata.pins.cs_activelow = 1;
++	dev->pdata.mode = SPI_MODE_0;
++	dev->pdata.no_spi_delay = 0;
++	dev->pdata.max_bus_speed = 5000000; /* 5 MHz */
++
++	return &(dev->item);
++}
++
++static void gpiommc_drop_item(struct config_group *group,
++			      struct config_item *item)
++{
++	struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
++
++	gpiommc_do_unregister(dev);
++	kfree(dev);
++}
++
++static struct configfs_group_operations gpiommc_ct_group_ops = {
++	.make_item	= gpiommc_make_item,
++	.drop_item	= gpiommc_drop_item,
++};
++
++static struct config_item_type gpiommc_ci_type = {
++	.ct_group_ops	= &gpiommc_ct_group_ops,
++	.ct_owner	= THIS_MODULE,
++};
++
++static struct configfs_subsystem gpiommc_subsys = {
++	.su_group = {
++		.cg_item = {
++			.ci_namebuf = GPIOMMC_PLATDEV_NAME,
++			.ci_type = &gpiommc_ci_type,
++		},
++	},
++	.su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex),
++};
++
++#endif /* CONFIG_GPIOMMC_CONFIGFS */
++
++static struct platform_driver gpiommc_plat_driver = {
++	.probe	= gpiommc_probe,
++	.remove	= gpiommc_remove,
++	.driver	= {
++		.name	= GPIOMMC_PLATDEV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++int gpiommc_next_id(void)
++{
++	static atomic_t counter = ATOMIC_INIT(-1);
++
++	return atomic_inc_return(&counter);
++}
++EXPORT_SYMBOL(gpiommc_next_id);
++
++static int __init gpiommc_modinit(void)
++{
++	int err;
++
++	err = platform_driver_register(&gpiommc_plat_driver);
++	if (err)
++		return err;
++
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++	config_group_init(&gpiommc_subsys.su_group);
++	err = configfs_register_subsystem(&gpiommc_subsys);
++	if (err) {
++		platform_driver_unregister(&gpiommc_plat_driver);
++		return err;
++	}
++#endif /* CONFIG_GPIOMMC_CONFIGFS */
++
++	return 0;
++}
++module_init(gpiommc_modinit);
++
++static void __exit gpiommc_modexit(void)
++{
++#ifdef CONFIG_GPIOMMC_CONFIGFS
++	configfs_unregister_subsystem(&gpiommc_subsys);
++#endif
++	platform_driver_unregister(&gpiommc_plat_driver);
++}
++module_exit(gpiommc_modexit);
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -567,6 +567,31 @@ config MMC_SDHI
+ 	  This provides support for the SDHI SD/SDIO controller found in
+ 	  SuperH and ARM SH-Mobile SoCs
+ 
++config GPIOMMC
++	tristate "MMC/SD over GPIO-based SPI"
++	depends on MMC && MMC_SPI && SPI_GPIO_OLD
++	help
++	  This driver hooks up the mmc_spi and spi_gpio modules so that
++	  MMC/SD cards can be used on a GPIO based bus by bitbanging
++	  the SPI protocol in software.
++
++	  This driver provides a configfs interface to dynamically create
++	  and destroy GPIO-based MMC/SD card devices. It also provides
++	  a platform device interface API.
++	  See Documentation/gpiommc.txt for details.
++
++	  The module will be called gpiommc.
++
++	  If unsure, say N.
++
++config GPIOMMC_CONFIGFS
++	bool
++	depends on GPIOMMC && CONFIGFS_FS
++	default y
++	help
++	  This option automatically enables configfs support for gpiommc
++	  if configfs is available.
++
+ config MMC_CB710
+ 	tristate "ENE CB710 MMC/SD Interface support"
+ 	depends on PCI
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -41,6 +41,7 @@ tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_S
+ obj-$(CONFIG_MMC_SDHI)		+= sh_mobile_sdhi.o
+ obj-$(CONFIG_MMC_CB710)		+= cb710-mmc.o
+ obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
++obj-$(CONFIG_GPIOMMC)		+= gpiommc.o
+ obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
+ obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
+ obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
+--- /dev/null
++++ b/include/linux/mmc/gpiommc.h
+@@ -0,0 +1,71 @@
++/*
++ * Device driver for MMC/SD cards driven over a GPIO bus.
++ *
++ * Copyright (c) 2008 Michael Buesch
++ *
++ * Licensed under the GNU/GPL version 2.
++ */
++#ifndef LINUX_GPIOMMC_H_
++#define LINUX_GPIOMMC_H_
++
++#include <linux/types.h>
++
++
++#define GPIOMMC_MAX_NAMELEN		15
++#define GPIOMMC_MAX_NAMELEN_STR		__stringify(GPIOMMC_MAX_NAMELEN)
++
++/**
++ * struct gpiommc_pins - Hardware pin assignments
++ *
++ * @gpio_di: The GPIO number of the DATA IN pin
++ * @gpio_do: The GPIO number of the DATA OUT pin
++ * @gpio_clk: The GPIO number of the CLOCK pin
++ * @gpio_cs: The GPIO number of the CHIPSELECT pin
++ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low.
++ */
++struct gpiommc_pins {
++	unsigned int gpio_di;
++	unsigned int gpio_do;
++	unsigned int gpio_clk;
++	unsigned int gpio_cs;
++	bool cs_activelow;
++};
++
++/**
++ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device.
++ *
++ * @name: The unique name string of the device.
++ * @pins: The hardware pin assignments.
++ * @mode: The hardware mode. This is either SPI_MODE_0,
++ *        SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation.
++ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code.
++ *                This is not standards compliant, but may be required for some
++ *                embedded machines to gain reasonable speed.
++ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz.
++ */
++struct gpiommc_platform_data {
++	char name[GPIOMMC_MAX_NAMELEN + 1];
++	struct gpiommc_pins pins;
++	u8 mode;
++	bool no_spi_delay;
++	unsigned int max_bus_speed;
++};
++
++/**
++ * GPIOMMC_PLATDEV_NAME - The platform device name string.
++ *
++ * The name string that has to be used for platform_device_alloc
++ * when allocating a gpiommc device.
++ */
++#define GPIOMMC_PLATDEV_NAME	"gpiommc"
++
++/**
++ * gpiommc_next_id - Get another platform device ID number.
++ *
++ * This returns the next platform device ID number that has to be used
++ * for platform_device_alloc. The ID is opaque and should not be used for
++ * anything else.
++ */
++int gpiommc_next_id(void);
++
++#endif /* LINUX_GPIOMMC_H_ */
+--- /dev/null
++++ b/Documentation/gpiommc.txt
+@@ -0,0 +1,97 @@
++GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus
++================================================================
++
++The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an
++MMC or SD card on GPIO pins.
++
++Two interfaces for registering a new MMC/SD card device are provided:
++A static platform-device based mechanism and a dynamic configfs based interface.
++
++
++Registering devices via platform-device
++=======================================
++
++The platform-device interface is used for registering MMC/SD devices that are
++part of the hardware platform. This is most useful only for embedded machines
++with MMC/SD devices statically connected to the platform GPIO bus.
++
++The data structures are declared in <linux/mmc/gpiommc.h>.
++
++To register a new device, define an instance of struct gpiommc_platform_data.
++This structure holds any information about how the device is hooked up to the
++GPIO pins and what hardware modes the device supports. See the docbook-style
++documentation in the header file for more information on the struct fields.
++
++Then allocate a new instance of a platform device by doing:
++
++	pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id());
++
++This will allocate the platform device data structures and hook it up to the
++gpiommc driver.
++Then add the gpiommc_platform_data to the platform device.
++
++	err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data));
++
++You may free the local instance of struct gpiommc_platform_data now. (So the
++struct may be allocated on the stack, too).
++Now simply register the platform device.
++
++	err = platform_device_add(pdev);
++
++Done. The gpiommc probe routine will be invoked now and you should see a kernel
++log message for the added device.
++
++
++Registering devices via configfs
++================================
++
++MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example
++selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded
++hardware are a common situation.
++So we provide a dynamic interface to conveniently handle adding and removing
++devices from userspace, without the need to recompile the kernel.
++
++The "gpiommc" subdirectory at the configfs mountpoint is used for handling
++the dynamic configuration.
++
++To create a new device, it must first be allocated with mkdir.
++The following command will allocate a device named "my_mmc":
++	mkdir /config/gpiommc/my_mmc
++
++There are several configuration files available in the new
++/config/gpiommc/my_mmc/ directory:
++
++gpio_data_in			= The SPI data-IN GPIO pin number.
++gpio_data_out			= The SPI data-OUT GPIO pin number.
++gpio_clock			= The SPI Clock GPIO pin number.
++gpio_chipselect			= The SPI Chipselect GPIO pin number.
++gpio_chipselect_activelow	= Boolean. If 0, Chipselect is active-HIGH.
++				  If 1, Chipselect is active-LOW.
++spi_mode			= The SPI data mode. Can be 0-3.
++spi_delay			= Enable all delays in the lowlevel bitbanging.
++max_bus_speed			= The maximum SPI bus speed. In Hertz.
++
++register			= Not a configuration parameter.
++				  Used to register the configured card
++				  with the kernel.
++
++The device must first get configured and then registered by writing "1" to
++the "register" file.
++The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock"
++and "gpio_chipselect" are essential and _must_ be configured before writing
++"1" to the "register" file. The registration will fail, otherwise.
++
++The default values for the other parameters are:
++gpio_chipselect_activelow	= 1		(CS active-LOW)
++spi_mode			= 0		(SPI_MODE_0)
++spi_delay			= 1		(enabled)
++max_bus_speed			= 5000000	(5 Mhz)
++
++Configuration values can not be changed after registration. To unregister
++the device, write a "0" to the "register" file. The configuration can be
++changed again after unregistering.
++
++To completely remove the device, simply rmdir the directory
++(/config/gpiommc/my_mmc in this example).
++There's no need to first unregister the device before removing it. That will
++be done automatically.
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4880,6 +4880,11 @@ T:	git git://linuxtv.org/anttip/media_tr
+ S:	Maintained
+ F:	drivers/media/usb/hackrf/
+ 
++GPIOMMC DRIVER
++P:	Michael Buesch
++M:	mb@bu3sch.de
++S:	Maintained
++
+ HARDWARE MONITORING
+ M:	Jean Delvare <jdelvare@suse.com>
+ M:	Guenter Roeck <linux@roeck-us.net>
diff --git a/target/linux/generic/patches-4.4/864-gpiommc_configfs_locking.patch b/target/linux/generic/patches-4.4/864-gpiommc_configfs_locking.patch
new file mode 100644
index 0000000000..92815d91f4
--- /dev/null
+++ b/target/linux/generic/patches-4.4/864-gpiommc_configfs_locking.patch
@@ -0,0 +1,58 @@
+The gpiommc configfs context structure needs locking, as configfs
+does not lock access between files.
+
+--- a/drivers/mmc/host/gpiommc.c
++++ b/drivers/mmc/host/gpiommc.c
+@@ -144,6 +144,8 @@ struct gpiommc_configfs_device {
+ 	struct platform_device *pdev;
+ 	/* The configuration */
+ 	struct gpiommc_platform_data pdata;
++	/* Mutex to protect this structure */
++	struct mutex mutex;
+ };
+ 
+ #define GPIO_INVALID	-1
+@@ -234,6 +236,8 @@ static ssize_t gpiommc_config_attr_show(
+ 	unsigned int gpio;
+ 	int err = 0;
+ 
++	mutex_lock(&dev->mutex);
++
+ 	if (attr == &gpiommc_attr_DI) {
+ 		gpio = dev->pdata.pins.gpio_di;
+ 		if (gpio == GPIO_INVALID)
+@@ -294,6 +298,8 @@ static ssize_t gpiommc_config_attr_show(
+ 	WARN_ON(1);
+ 	err = -ENOSYS;
+ out:
++	mutex_unlock(&dev->mutex);
++
+ 	return err ? err : count;
+ }
+ 
+@@ -353,6 +359,8 @@ static ssize_t gpiommc_config_attr_store
+ 	int err = -EINVAL;
+ 	unsigned long data;
+ 
++	mutex_lock(&dev->mutex);
++
+ 	if (attr == &gpiommc_attr_register) {
+ 		err = kstrtoul(page, 10, &data);
+ 		if (err)
+@@ -478,6 +486,8 @@ static ssize_t gpiommc_config_attr_store
+ 	WARN_ON(1);
+ 	err = -ENOSYS;
+ out:
++	mutex_unlock(&dev->mutex);
++
+ 	return err ? err : count;
+ }
+ 
+@@ -514,6 +524,7 @@ static struct config_item *gpiommc_make_
+ 	if (!dev)
+ 		return NULL;
+ 
++	mutex_init(&dev->mutex);
+ 	config_item_init_type_name(&dev->item, name,
+ 				   &gpiommc_dev_ci_type);
+ 
diff --git a/target/linux/generic/patches-4.4/870-hifn795x_byteswap.patch b/target/linux/generic/patches-4.4/870-hifn795x_byteswap.patch
new file mode 100644
index 0000000000..956b78902e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/870-hifn795x_byteswap.patch
@@ -0,0 +1,17 @@
+--- a/drivers/crypto/hifn_795x.c
++++ b/drivers/crypto/hifn_795x.c
+@@ -680,12 +680,12 @@ static inline u32 hifn_read_1(struct hif
+ 
+ static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
+ {
+-	writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg);
++	writel(val, dev->bar[0] + reg);
+ }
+ 
+ static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
+ {
+-	writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg);
++	writel(val, dev->bar[1] + reg);
+ }
+ 
+ static void hifn_wait_puc(struct hifn_device *dev)
diff --git a/target/linux/generic/patches-4.4/880-gateworks_system_controller.patch b/target/linux/generic/patches-4.4/880-gateworks_system_controller.patch
new file mode 100644
index 0000000000..a19f30082e
--- /dev/null
+++ b/target/linux/generic/patches-4.4/880-gateworks_system_controller.patch
@@ -0,0 +1,339 @@
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -527,6 +527,15 @@ config SENSORS_G762
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called g762.
+ 
++config SENSORS_GSC
++	tristate "Gateworks System Controller"
++	depends on I2C
++	help
++	  If you say yes here you get support for the Gateworks System Controller.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called gsc.
++
+ config SENSORS_GPIO_FAN
+ 	tristate "GPIO fan"
+ 	depends on GPIOLIB || COMPILE_TEST
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -160,6 +160,7 @@ obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l7
+ obj-$(CONFIG_SENSORS_W83L786NG)	+= w83l786ng.o
+ obj-$(CONFIG_SENSORS_WM831X)	+= wm831x-hwmon.o
+ obj-$(CONFIG_SENSORS_WM8350)	+= wm8350-hwmon.o
++obj-$(CONFIG_SENSORS_GSC)	+= gsc.o
+ 
+ obj-$(CONFIG_PMBUS)		+= pmbus/
+ 
+--- /dev/null
++++ b/drivers/hwmon/gsc.c
+@@ -0,0 +1,308 @@
++/*
++ * A hwmon driver for the Gateworks System Controller 
++ * Copyright (C) 2009 Gateworks Corporation
++ *
++ * Author: Chris Lang <clang@gateworks.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License,
++ * as published by the Free Software Foundation - version 2.
++ */
++
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++
++#define DRV_VERSION "0.2"
++
++enum chips { gsp };
++
++/* AD7418 registers */
++#define GSP_REG_TEMP_IN		0x00
++#define GSP_REG_VIN		0x02
++#define GSP_REG_3P3		0x05
++#define GSP_REG_BAT		0x08
++#define GSP_REG_5P0		0x0b
++#define GSP_REG_CORE		0x0e
++#define GSP_REG_CPU1		0x11
++#define GSP_REG_CPU2		0x14
++#define GSP_REG_DRAM		0x17
++#define GSP_REG_EXT_BAT		0x1a
++#define GSP_REG_IO1		0x1d
++#define GSP_REG_IO2 		0x20
++#define GSP_REG_PCIE		0x23
++#define GSP_REG_CURRENT		0x26
++#define GSP_FAN_0		0x2C
++#define GSP_FAN_1		0x2E
++#define GSP_FAN_2		0x30
++#define GSP_FAN_3		0x32
++#define GSP_FAN_4		0x34
++#define GSP_FAN_5		0x36
++
++struct gsp_sensor_info {
++	const char* name;
++	int reg;
++};
++
++static const struct gsp_sensor_info gsp_sensors[] = {
++	{"temp", GSP_REG_TEMP_IN},
++	{"vin", GSP_REG_VIN},
++	{"3p3", GSP_REG_3P3},
++	{"bat", GSP_REG_BAT},
++	{"5p0", GSP_REG_5P0},
++	{"core", GSP_REG_CORE},
++	{"cpu1", GSP_REG_CPU1},
++	{"cpu2", GSP_REG_CPU2},
++	{"dram", GSP_REG_DRAM},
++	{"ext_bat", GSP_REG_EXT_BAT},
++	{"io1", GSP_REG_IO1},
++	{"io2", GSP_REG_IO2},
++	{"pci2", GSP_REG_PCIE},
++	{"current", GSP_REG_CURRENT},
++	{"fan_point0", GSP_FAN_0},
++	{"fan_point1", GSP_FAN_1},
++	{"fan_point2", GSP_FAN_2},
++	{"fan_point3", GSP_FAN_3},
++	{"fan_point4", GSP_FAN_4},
++	{"fan_point5", GSP_FAN_5},
++};
++
++struct gsp_data {
++	struct device		*hwmon_dev;
++	struct attribute_group	attrs;
++	enum chips		type;
++};
++
++static int gsp_probe(struct i2c_client *client,
++			const struct i2c_device_id *id);
++static int gsp_remove(struct i2c_client *client);
++
++static const struct i2c_device_id gsp_id[] = {
++	{ "gsp", 0 },
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, gsp_id);
++
++static struct i2c_driver gsp_driver = {
++	.driver = {
++		.name	= "gsp",
++	},
++	.probe		= gsp_probe,
++	.remove		= gsp_remove,
++	.id_table	= gsp_id,
++};
++
++/* All registers are word-sized, except for the configuration registers.
++ * AD7418 uses a high-byte first convention. Do NOT use those functions to
++ * access the configuration registers CONF and CONF2, as they are byte-sized.
++ */
++static inline int gsp_read(struct i2c_client *client, u8 reg)
++{
++	unsigned int adc = 0;
++	if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT)
++	{
++		adc |= i2c_smbus_read_byte_data(client, reg);
++		adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
++		return adc;
++	}
++	else
++	{
++		adc |= i2c_smbus_read_byte_data(client, reg);
++		adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
++		adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16;
++		return adc;
++	}
++}
++
++static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value)
++{
++	i2c_smbus_write_byte_data(client, reg, value & 0xff);
++	i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff));
++	return 1;
++}
++
++static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
++			char *buf)
++{
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++	struct i2c_client *client = to_i2c_client(dev);
++	return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg));
++}
++
++static ssize_t show_label(struct device *dev,
++			struct device_attribute *devattr, char *buf)
++{
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++
++	return sprintf(buf, "%s\n", gsp_sensors[attr->index].name);
++}
++
++static ssize_t store_fan(struct device *dev,
++			struct device_attribute *devattr, const char *buf, size_t count)
++{
++	u16 val;
++	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++	struct i2c_client *client = to_i2c_client(dev);
++	val = simple_strtoul(buf, NULL, 10);
++	gsp_write(client, gsp_sensors[attr->index].reg, val);
++	return count;
++}
++
++static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0);
++static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0);
++
++static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1);
++static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1);
++static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2);
++static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2);
++static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3);
++static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3);
++static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4);
++static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4);
++static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5);
++static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5);
++static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6);
++static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6);
++static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7);
++static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7);
++static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8);
++static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8);
++static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9);
++static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9);
++static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10);
++static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10);
++static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11);
++static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11);
++static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12);
++static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12);
++static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13);
++static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13);
++
++static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14);
++static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15);
++static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16);
++static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17);
++static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18);
++static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19);
++
++static struct attribute *gsp_attributes[] = {
++	&sensor_dev_attr_temp0_input.dev_attr.attr,
++	&sensor_dev_attr_in0_input.dev_attr.attr,
++	&sensor_dev_attr_in1_input.dev_attr.attr,
++	&sensor_dev_attr_in2_input.dev_attr.attr,
++	&sensor_dev_attr_in3_input.dev_attr.attr,
++	&sensor_dev_attr_in4_input.dev_attr.attr,
++	&sensor_dev_attr_in5_input.dev_attr.attr,
++	&sensor_dev_attr_in6_input.dev_attr.attr,
++	&sensor_dev_attr_in7_input.dev_attr.attr,
++	&sensor_dev_attr_in8_input.dev_attr.attr,
++	&sensor_dev_attr_in9_input.dev_attr.attr,
++	&sensor_dev_attr_in10_input.dev_attr.attr,
++	&sensor_dev_attr_in11_input.dev_attr.attr,
++	&sensor_dev_attr_in12_input.dev_attr.attr,
++
++	&sensor_dev_attr_temp0_label.dev_attr.attr,
++	&sensor_dev_attr_in0_label.dev_attr.attr,
++	&sensor_dev_attr_in1_label.dev_attr.attr,
++	&sensor_dev_attr_in2_label.dev_attr.attr,
++	&sensor_dev_attr_in3_label.dev_attr.attr,
++	&sensor_dev_attr_in4_label.dev_attr.attr,
++	&sensor_dev_attr_in5_label.dev_attr.attr,
++	&sensor_dev_attr_in6_label.dev_attr.attr,
++	&sensor_dev_attr_in7_label.dev_attr.attr,
++	&sensor_dev_attr_in8_label.dev_attr.attr,
++	&sensor_dev_attr_in9_label.dev_attr.attr,
++	&sensor_dev_attr_in10_label.dev_attr.attr,
++	&sensor_dev_attr_in11_label.dev_attr.attr,
++	&sensor_dev_attr_in12_label.dev_attr.attr,
++
++	&sensor_dev_attr_fan0_point0.dev_attr.attr,
++	&sensor_dev_attr_fan0_point1.dev_attr.attr,
++	&sensor_dev_attr_fan0_point2.dev_attr.attr,
++	&sensor_dev_attr_fan0_point3.dev_attr.attr,
++	&sensor_dev_attr_fan0_point4.dev_attr.attr,
++	&sensor_dev_attr_fan0_point5.dev_attr.attr,
++	NULL
++};
++
++
++static int gsp_probe(struct i2c_client *client,
++			 const struct i2c_device_id *id)
++{
++	struct i2c_adapter *adapter = client->adapter;
++	struct gsp_data *data;
++	int err;
++
++	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
++					I2C_FUNC_SMBUS_WORD_DATA)) {
++		err = -EOPNOTSUPP;
++		goto exit;
++	}
++
++	if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) {
++		err = -ENOMEM;
++		goto exit;
++	}
++
++	i2c_set_clientdata(client, data);
++
++	data->type = id->driver_data;
++
++	switch (data->type) {
++	case 0:
++		data->attrs.attrs = gsp_attributes;
++		break;
++	}
++
++	dev_info(&client->dev, "%s chip found\n", client->name);
++
++	/* Register sysfs hooks */
++	if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
++		goto exit_free;
++
++	data->hwmon_dev = hwmon_device_register(&client->dev);
++	if (IS_ERR(data->hwmon_dev)) {
++		err = PTR_ERR(data->hwmon_dev);
++		goto exit_remove;
++	}
++
++	return 0;
++
++exit_remove:
++	sysfs_remove_group(&client->dev.kobj, &data->attrs);
++exit_free:
++	kfree(data);
++exit:
++	return err;
++}
++
++static int gsp_remove(struct i2c_client *client)
++{
++	struct gsp_data *data = i2c_get_clientdata(client);
++	hwmon_device_unregister(data->hwmon_dev);
++	sysfs_remove_group(&client->dev.kobj, &data->attrs);
++	kfree(data);
++	return 0;
++}
++
++static int __init gsp_init(void)
++{
++	return i2c_add_driver(&gsp_driver);
++}
++
++static void __exit gsp_exit(void)
++{
++	i2c_del_driver(&gsp_driver);
++}
++
++module_init(gsp_init);
++module_exit(gsp_exit);
++
++MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
++MODULE_DESCRIPTION("GSC HWMON driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
diff --git a/target/linux/generic/patches-4.4/890-uart_optional_sysrq.patch b/target/linux/generic/patches-4.4/890-uart_optional_sysrq.patch
new file mode 100644
index 0000000000..0e37f9456c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/890-uart_optional_sysrq.patch
@@ -0,0 +1,25 @@
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -382,6 +382,11 @@ config MAGIC_SYSRQ_DEFAULT_ENABLE
+ 	  This may be set to 1 or 0 to enable or disable them all, or
+ 	  to a bitmask as described in Documentation/sysrq.txt.
+ 
++config MAGIC_SYSRQ_SERIAL
++	bool "Enable magic SysRq key over serial"
++	depends on MAGIC_SYSRQ
++	default y
++
+ config DEBUG_KERNEL
+ 	bool "Kernel debugging"
+ 	help
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -426,7 +426,7 @@ extern void uart_handle_cts_change(struc
+ extern void uart_insert_char(struct uart_port *port, unsigned int status,
+ 		 unsigned int overrun, unsigned int ch, unsigned int flag);
+ 
+-#ifdef SUPPORT_SYSRQ
++#if defined(SUPPORT_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ_SERIAL)
+ static inline int
+ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
+ {
diff --git a/target/linux/generic/patches-4.4/901-debloat_sock_diag.patch b/target/linux/generic/patches-4.4/901-debloat_sock_diag.patch
new file mode 100644
index 0000000000..b70f44efca
--- /dev/null
+++ b/target/linux/generic/patches-4.4/901-debloat_sock_diag.patch
@@ -0,0 +1,79 @@
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -92,6 +92,9 @@ source "net/netlabel/Kconfig"
+ 
+ endif # if INET
+ 
++config SOCK_DIAG
++	bool
++
+ config NETWORK_SECMARK
+ 	bool "Security Marking"
+ 	help
+--- a/net/core/Makefile
++++ b/net/core/Makefile
+@@ -9,8 +9,9 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
+ 
+ obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
+ 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
+-			sock_diag.o dev_ioctl.o tso.o
++			dev_ioctl.o tso.o
+ 
++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
+ obj-$(CONFIG_XFRM) += flow.o
+ obj-y += net-sysfs.o
+ obj-$(CONFIG_PROC_FS) += net-procfs.o
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -1469,9 +1469,11 @@ void sk_destruct(struct sock *sk)
+ 
+ static void __sk_free(struct sock *sk)
+ {
++#ifdef CONFIG_SOCK_DIAG
+ 	if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt))
+ 		sock_diag_broadcast_destroy(sk);
+ 	else
++#endif
+ 		sk_destruct(sk);
+ }
+ 
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -414,6 +414,7 @@ config INET_LRO
+ 
+ config INET_DIAG
+ 	tristate "INET: socket monitoring interface"
++	select SOCK_DIAG
+ 	default y
+ 	---help---
+ 	  Support for INET (TCP, DCCP, etc) socket monitoring interface used by
+--- a/net/unix/Kconfig
++++ b/net/unix/Kconfig
+@@ -22,6 +22,7 @@ config UNIX
+ config UNIX_DIAG
+ 	tristate "UNIX: socket monitoring interface"
+ 	depends on UNIX
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for UNIX socket monitoring interface used by the ss tool.
+--- a/net/netlink/Kconfig
++++ b/net/netlink/Kconfig
+@@ -13,6 +13,7 @@ config NETLINK_MMAP
+ 
+ config NETLINK_DIAG
+ 	tristate "NETLINK: socket monitoring interface"
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for NETLINK socket monitoring interface used by the ss tool.
+--- a/net/packet/Kconfig
++++ b/net/packet/Kconfig
+@@ -18,6 +18,7 @@ config PACKET
+ config PACKET_DIAG
+ 	tristate "Packet: sockets monitoring interface"
+ 	depends on PACKET
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for PF_PACKET sockets monitoring interface used by the ss tool.
diff --git a/target/linux/generic/patches-4.4/902-debloat_proc.patch b/target/linux/generic/patches-4.4/902-debloat_proc.patch
new file mode 100644
index 0000000000..3123a4be68
--- /dev/null
+++ b/target/linux/generic/patches-4.4/902-debloat_proc.patch
@@ -0,0 +1,385 @@
+--- a/fs/locks.c
++++ b/fs/locks.c
+@@ -2712,6 +2712,8 @@ static const struct file_operations proc
+ 
+ static int __init proc_locks_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("locks", 0, NULL, &proc_locks_operations);
+ 	return 0;
+ }
+--- a/fs/proc/Kconfig
++++ b/fs/proc/Kconfig
+@@ -81,3 +81,8 @@ config PROC_CHILDREN
+ 
+ 	  Say Y if you are running any user-space software which takes benefit from
+ 	  this interface. For example, rkt is such a piece of software.
++
++config PROC_STRIPPED
++	default n
++	depends on EXPERT
++	bool "Strip non-essential /proc functionality to reduce code size"
+--- a/fs/proc/consoles.c
++++ b/fs/proc/consoles.c
+@@ -106,6 +106,9 @@ static const struct file_operations proc
+ 
+ static int __init proc_consoles_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	proc_create("consoles", 0, NULL, &proc_consoles_operations);
+ 	return 0;
+ }
+--- a/fs/proc/proc_tty.c
++++ b/fs/proc/proc_tty.c
+@@ -143,7 +143,10 @@ static const struct file_operations proc
+ void proc_tty_register_driver(struct tty_driver *driver)
+ {
+ 	struct proc_dir_entry *ent;
+-		
++
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!driver->driver_name || driver->proc_entry ||
+ 	    !driver->ops->proc_fops)
+ 		return;
+@@ -160,6 +163,9 @@ void proc_tty_unregister_driver(struct t
+ {
+ 	struct proc_dir_entry *ent;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ent = driver->proc_entry;
+ 	if (!ent)
+ 		return;
+@@ -174,6 +180,9 @@ void proc_tty_unregister_driver(struct t
+  */
+ void __init proc_tty_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!proc_mkdir("tty", NULL))
+ 		return;
+ 	proc_mkdir("tty/ldisc", NULL);	/* Preserved: it's userspace visible */
+--- a/kernel/exec_domain.c
++++ b/kernel/exec_domain.c
+@@ -41,6 +41,8 @@ static const struct file_operations exec
+ 
+ static int __init proc_execdomains_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("execdomains", 0, NULL, &execdomains_proc_fops);
+ 	return 0;
+ }
+--- a/kernel/irq/proc.c
++++ b/kernel/irq/proc.c
+@@ -327,6 +327,9 @@ void register_irq_proc(unsigned int irq,
+ 	static DEFINE_MUTEX(register_lock);
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
+ 		return;
+ 
+@@ -376,6 +379,9 @@ void unregister_irq_proc(unsigned int ir
+ {
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || !desc->dir)
+ 		return;
+ #ifdef CONFIG_SMP
+@@ -411,6 +417,9 @@ void init_irq_proc(void)
+ 	unsigned int irq;
+ 	struct irq_desc *desc;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	/* create /proc/irq */
+ 	root_irq_dir = proc_mkdir("irq", NULL);
+ 	if (!root_irq_dir)
+--- a/kernel/time/timer_list.c
++++ b/kernel/time/timer_list.c
+@@ -393,6 +393,8 @@ static int __init init_timer_list_procfs
+ {
+ 	struct proc_dir_entry *pe;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	pe = proc_create("timer_list", 0444, NULL, &timer_list_fops);
+ 	if (!pe)
+ 		return -ENOMEM;
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -2684,6 +2684,8 @@ static const struct file_operations proc
+ 
+ static int __init proc_vmalloc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
+ 	return 0;
+ }
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -1553,10 +1553,12 @@ static int __init setup_vmstat(void)
+ 	cpu_notifier_register_done();
+ #endif
+ #ifdef CONFIG_PROC_FS
+-	proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
+-	proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
++		proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
++		proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
++	}
+ 	proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
+-	proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
+ #endif
+ 	return 0;
+ }
+--- a/net/8021q/vlanproc.c
++++ b/net/8021q/vlanproc.c
+@@ -127,6 +127,9 @@ void vlan_proc_cleanup(struct net *net)
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (vn->proc_vlan_conf)
+ 		remove_proc_entry(name_conf, vn->proc_vlan_dir);
+ 
+@@ -146,6 +149,9 @@ int __net_init vlan_proc_init(struct net
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
+ 	if (!vn->proc_vlan_dir)
+ 		goto err;
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -3036,6 +3036,8 @@ static __net_initdata struct pernet_oper
+ 
+ static int __init proto_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	return register_pernet_subsys(&proto_net_ops);
+ }
+ 
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2639,10 +2639,12 @@ static const struct file_operations fib_
+ 
+ int __net_init fib_proc_init(struct net *net)
+ {
+-	if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops))
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops))
+ 		goto out1;
+ 
+-	if (!proc_create("fib_triestat", S_IRUGO, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("fib_triestat", S_IRUGO, net->proc_net,
+ 			 &fib_triestat_fops))
+ 		goto out2;
+ 
+@@ -2652,17 +2654,21 @@ int __net_init fib_proc_init(struct net
+ 	return 0;
+ 
+ out3:
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_triestat", net->proc_net);
+ out2:
+-	remove_proc_entry("fib_trie", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_trie", net->proc_net);
+ out1:
+ 	return -ENOMEM;
+ }
+ 
+ void __net_exit fib_proc_exit(struct net *net)
+ {
+-	remove_proc_entry("fib_trie", net->proc_net);
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("fib_trie", net->proc_net);
++		remove_proc_entry("fib_triestat", net->proc_net);
++	}
+ 	remove_proc_entry("route", net->proc_net);
+ }
+ 
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -539,6 +539,9 @@ static __net_initdata struct pernet_oper
+ 
+ int __init ip_misc_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_proc_ops);
+ }
+ 
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -420,6 +420,9 @@ static struct pernet_operations ip_rt_pr
+ 
+ static int __init ip_rt_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_rt_proc_ops);
+ }
+ 
+--- a/ipc/msg.c
++++ b/ipc/msg.c
+@@ -1068,6 +1068,9 @@ void __init msg_init(void)
+ {
+ 	msg_init_ns(&init_ipc_ns);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ipc_init_proc_interface("sysvipc/msg",
+ 				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
+ 				IPC_MSG_IDS, sysvipc_msg_proc_show);
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -198,6 +198,8 @@ void sem_exit_ns(struct ipc_namespace *n
+ void __init sem_init(void)
+ {
+ 	sem_init_ns(&init_ipc_ns);
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/sem",
+ 				"       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
+ 				IPC_SEM_IDS, sysvipc_sem_proc_show);
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -118,6 +118,8 @@ pure_initcall(ipc_ns_init);
+ 
+ void __init shm_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/shm",
+ #if BITS_PER_LONG <= 32
+ 				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n",
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -121,6 +121,9 @@ void __init ipc_init_proc_interface(cons
+ 	struct proc_dir_entry *pde;
+ 	struct ipc_proc_iface *iface;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ 	if (!iface)
+ 		return;
+--- a/net/core/net-procfs.c
++++ b/net/core/net-procfs.c
+@@ -318,10 +318,12 @@ static int __net_init dev_proc_net_init(
+ 
+ 	if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
+ 		goto out;
+-	if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("softnet_stat", S_IRUGO, net->proc_net,
+ 			 &softnet_seq_fops))
+ 		goto out_dev;
+-	if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++		!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
+ 		goto out_softnet;
+ 
+ 	if (wext_proc_init(net))
+@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init(
+ out:
+ 	return rc;
+ out_ptype:
+-	remove_proc_entry("ptype", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("ptype", net->proc_net);
+ out_softnet:
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("softnet_stat", net->proc_net);
+ out_dev:
+ 	remove_proc_entry("dev", net->proc_net);
+ 	goto out;
+@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit
+ {
+ 	wext_proc_exit(net);
+ 
+-	remove_proc_entry("ptype", net->proc_net);
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("ptype", net->proc_net);
++		remove_proc_entry("softnet_stat", net->proc_net);
++	}
+ 	remove_proc_entry("dev", net->proc_net);
+ }
+ 
+--- a/include/net/snmp.h
++++ b/include/net/snmp.h
+@@ -123,6 +123,30 @@ struct linux_xfrm_mib {
+ #define DECLARE_SNMP_STAT(type, name)	\
+ 	extern __typeof__(type) __percpu *name
+ 
++#ifdef CONFIG_PROC_STRIPPED
++#define SNMP_INC_STATS_BH(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_INC_STATS_USER(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_INC_STATS_ATOMIC_LONG(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_INC_STATS(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_DEC_STATS(mib, field)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_ADD_STATS_BH(mib, field, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_ADD_STATS_USER(mib, field, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_ADD_STATS(mib, field, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_UPD_PO_STATS(mib, basefield, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend)	\
++	do { (void) mib->mibs[0]; } while(0)
++
++#else
++
+ #define SNMP_INC_STATS_BH(mib, field)	\
+ 			__this_cpu_inc(mib->mibs[field])
+ 
+@@ -159,8 +183,9 @@ struct linux_xfrm_mib {
+ 		__this_cpu_add(ptr[basefield##OCTETS], addend);	\
+ 	} while (0)
+ 
++#endif
+ 
+-#if BITS_PER_LONG==32
++#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
+ 
+ #define SNMP_ADD_STATS64_BH(mib, field, addend) 			\
+ 	do {								\
diff --git a/target/linux/generic/patches-4.4/903-debloat_direct_io.patch b/target/linux/generic/patches-4.4/903-debloat_direct_io.patch
new file mode 100644
index 0000000000..7f6c529940
--- /dev/null
+++ b/target/linux/generic/patches-4.4/903-debloat_direct_io.patch
@@ -0,0 +1,80 @@
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -74,6 +74,11 @@ config FILE_LOCKING
+           for filesystems like NFS and for the flock() system
+           call. Disabling this option saves about 11k.
+ 
++config DIRECT_IO
++	bool "Enable O_DIRECT support" if EXPERT
++	depends on BLOCK
++	default y
++
+ source "fs/notify/Kconfig"
+ 
+ source "fs/quota/Kconfig"
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -14,7 +14,8 @@ obj-y :=	open.o read_write.o file_table.
+ 		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
+ 
+ ifeq ($(CONFIG_BLOCK),y)
+-obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
++obj-y +=	buffer.o block_dev.o mpage.o
++obj-$(CONFIG_DIRECT_IO) += direct-io.o
+ else
+ obj-y +=	no-block.o
+ endif
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2717,6 +2717,7 @@ enum {
+ 	DIO_SKIP_DIO_COUNT = 0x08,
+ };
+ 
++#ifdef CONFIG_DIRECT_IO
+ void dio_end_io(struct bio *bio, int error);
+ 
+ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
+@@ -2724,6 +2725,18 @@ ssize_t __blockdev_direct_IO(struct kioc
+ 			     loff_t offset, get_block_t get_block,
+ 			     dio_iodone_t end_io, dio_submit_t submit_io,
+ 			     int flags);
++#else
++static inline void dio_end_io(struct bio *bio, int error)
++{
++}
++static inline ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
++	struct block_device *bdev, struct iov_iter *iter, loff_t offset,
++	get_block_t get_block, dio_iodone_t end_io,
++	dio_submit_t submit_io,	int flags)
++{
++	return -EOPNOTSUPP;
++}
++#endif
+ 
+ static inline ssize_t blockdev_direct_IO(struct kiocb *iocb,
+ 					 struct inode *inode,
+--- a/fs/fcntl.c
++++ b/fs/fcntl.c
+@@ -52,8 +52,10 @@ static int setfl(int fd, struct file * f
+ 		   arg |= O_NONBLOCK;
+ 
+ 	if (arg & O_DIRECT) {
++#ifdef CONFIG_DIRECT_IO
+ 		if (!filp->f_mapping || !filp->f_mapping->a_ops ||
+ 			!filp->f_mapping->a_ops->direct_IO)
++#endif
+ 				return -EINVAL;
+ 	}
+ 
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -673,7 +673,9 @@ int open_check_o_direct(struct file *f)
+ {
+ 	/* NB: we're sure to have correct a_ops only after f_op->open */
+ 	if (f->f_flags & O_DIRECT) {
++#ifdef CONFIG_DIRECT_IO
+ 		if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
++#endif
+ 			return -EINVAL;
+ 	}
+ 	return 0;
diff --git a/target/linux/generic/patches-4.4/904-debloat_dma_buf.patch b/target/linux/generic/patches-4.4/904-debloat_dma_buf.patch
new file mode 100644
index 0000000000..10613de852
--- /dev/null
+++ b/target/linux/generic/patches-4.4/904-debloat_dma_buf.patch
@@ -0,0 +1,44 @@
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -229,7 +229,7 @@ config SOC_BUS
+ source "drivers/base/regmap/Kconfig"
+ 
+ config DMA_SHARED_BUFFER
+-	bool
++	tristate
+ 	default n
+ 	select ANON_INODES
+ 	help
+--- a/drivers/dma-buf/Makefile
++++ b/drivers/dma-buf/Makefile
+@@ -1 +1,2 @@
+-obj-y := dma-buf.o fence.o reservation.o seqno-fence.o
++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
++dma-shared-buffer-objs := dma-buf.o fence.o reservation.o seqno-fence.o
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -33,6 +33,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/poll.h>
+ #include <linux/reservation.h>
++#include <linux/module.h>
+ 
+ static inline int is_dma_buf_file(struct file *);
+ 
+@@ -914,4 +915,5 @@ static void __exit dma_buf_deinit(void)
+ {
+ 	dma_buf_uninit_debugfs();
+ }
+-__exitcall(dma_buf_deinit);
++module_exit(dma_buf_deinit);
++MODULE_LICENSE("GPL");
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -2097,6 +2097,7 @@ int wake_up_state(struct task_struct *p,
+ {
+ 	return try_to_wake_up(p, state, 0);
+ }
++EXPORT_SYMBOL_GPL(wake_up_state);
+ 
+ /*
+  * This function clears the sched_dl_entity static params.
diff --git a/target/linux/generic/patches-4.4/910-kobject_uevent.patch b/target/linux/generic/patches-4.4/910-kobject_uevent.patch
new file mode 100644
index 0000000000..a2c935f26b
--- /dev/null
+++ b/target/linux/generic/patches-4.4/910-kobject_uevent.patch
@@ -0,0 +1,21 @@
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -52,6 +52,18 @@ static const char *kobject_actions[] = {
+ 	[KOBJ_OFFLINE] =	"offline",
+ };
+ 
++u64 uevent_next_seqnum(void)
++{
++	u64 seq;
++
++	mutex_lock(&uevent_sock_mutex);
++	seq = ++uevent_seqnum;
++	mutex_unlock(&uevent_sock_mutex);
++
++	return seq;
++}
++EXPORT_SYMBOL_GPL(uevent_next_seqnum);
++
+ /**
+  * kobject_action_type - translate action string to numeric type
+  *
diff --git a/target/linux/generic/patches-4.4/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/patches-4.4/911-kobject_add_broadcast_uevent.patch
new file mode 100644
index 0000000000..a3401ff4b3
--- /dev/null
+++ b/target/linux/generic/patches-4.4/911-kobject_add_broadcast_uevent.patch
@@ -0,0 +1,65 @@
+--- a/include/linux/kobject.h
++++ b/include/linux/kobject.h
+@@ -32,6 +32,8 @@
+ #define UEVENT_NUM_ENVP			32	/* number of env pointers */
+ #define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */
+ 
++struct sk_buff;
++
+ #ifdef CONFIG_UEVENT_HELPER
+ /* path to the userspace helper executed on an event */
+ extern char uevent_helper[];
+@@ -222,4 +224,7 @@ int add_uevent_var(struct kobj_uevent_en
+ int kobject_action_type(const char *buf, size_t count,
+ 			enum kobject_action *type);
+ 
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation);
++
+ #endif /* _KOBJECT_H_ */
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -423,6 +423,43 @@ int add_uevent_var(struct kobj_uevent_en
+ EXPORT_SYMBOL_GPL(add_uevent_var);
+ 
+ #if defined(CONFIG_NET)
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	struct uevent_sock *ue_sk;
++	int err = 0;
++
++	/* send netlink message */
++	mutex_lock(&uevent_sock_mutex);
++	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
++		struct sock *uevent_sock = ue_sk->sk;
++		struct sk_buff *skb2;
++
++		skb2 = skb_clone(skb, allocation);
++		if (!skb2)
++			break;
++
++		err = netlink_broadcast(uevent_sock, skb2, pid, group,
++					allocation);
++		if (err)
++			break;
++	}
++	mutex_unlock(&uevent_sock_mutex);
++
++	kfree_skb(skb);
++	return err;
++}
++#else
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	kfree_skb(skb);
++	return 0;
++}
++#endif
++EXPORT_SYMBOL_GPL(broadcast_uevent);
++
++#if defined(CONFIG_NET)
+ static int uevent_net_init(struct net *net)
+ {
+ 	struct uevent_sock *ue_sk;
diff --git a/target/linux/generic/patches-4.4/921-use_preinit_as_init.patch b/target/linux/generic/patches-4.4/921-use_preinit_as_init.patch
new file mode 100644
index 0000000000..1f4e6322b1
--- /dev/null
+++ b/target/linux/generic/patches-4.4/921-use_preinit_as_init.patch
@@ -0,0 +1,12 @@
+--- a/init/main.c
++++ b/init/main.c
+@@ -964,7 +964,8 @@ static int __ref kernel_init(void *unuse
+ 		panic("Requested init %s failed (error %d).",
+ 		      execute_command, ret);
+ 	}
+-	if (!try_to_run_init_process("/sbin/init") ||
++	if (!try_to_run_init_process("/etc/preinit") ||
++	    !try_to_run_init_process("/sbin/init") ||
+ 	    !try_to_run_init_process("/etc/init") ||
+ 	    !try_to_run_init_process("/bin/init") ||
+ 	    !try_to_run_init_process("/bin/sh"))
diff --git a/target/linux/generic/patches-4.4/922-always-create-console-node-in-initramfs.patch b/target/linux/generic/patches-4.4/922-always-create-console-node-in-initramfs.patch
new file mode 100644
index 0000000000..988de35ce0
--- /dev/null
+++ b/target/linux/generic/patches-4.4/922-always-create-console-node-in-initramfs.patch
@@ -0,0 +1,30 @@
+--- a/scripts/gen_initramfs_list.sh
++++ b/scripts/gen_initramfs_list.sh
+@@ -59,6 +59,18 @@ default_initramfs() {
+ 	EOF
+ }
+ 
++list_openwrt_initramfs() {
++	:
++}
++
++openwrt_initramfs() {
++	# make sure that /dev/console exists
++	cat <<-EOF >> ${output}
++		dir /dev 0755 0 0
++		nod /dev/console 0600 0 0 c 5 1
++	EOF
++}
++
+ filetype() {
+ 	local argv1="$1"
+ 
+@@ -177,6 +189,8 @@ dir_filelist() {
+ 	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+ 		${dep_list}print_mtime "$1"
+ 
++		${dep_list}openwrt_initramfs
++
+ 		echo "${dirlist}" | \
+ 		while read x; do
+ 			${dep_list}parse ${x}
diff --git a/target/linux/generic/patches-4.4/930-crashlog.patch b/target/linux/generic/patches-4.4/930-crashlog.patch
new file mode 100644
index 0000000000..fdc80d750a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/930-crashlog.patch
@@ -0,0 +1,317 @@
+--- /dev/null
++++ b/include/linux/crashlog.h
+@@ -0,0 +1,17 @@
++#ifndef __CRASHLOG_H
++#define __CRASHLOG_H
++
++#ifdef CONFIG_CRASHLOG
++void crashlog_init_bootmem(struct bootmem_data *bdata);
++void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size);
++#else
++static inline void crashlog_init_bootmem(struct bootmem_data *bdata)
++{
++}
++
++static inline void crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
++{
++}
++#endif
++
++#endif
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1296,6 +1296,10 @@ config RELAY
+ 
+ 	  If unsure, say N.
+ 
++config CRASHLOG
++	bool "Crash logging"
++	depends on (!NO_BOOTMEM || HAVE_MEMBLOCK)
++
+ config BLK_DEV_INITRD
+ 	bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
+ 	depends on BROKEN || !FRV
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -103,6 +103,7 @@ obj-$(CONFIG_TORTURE_TEST) += torture.o
+ obj-$(CONFIG_MEMBARRIER) += membarrier.o
+ 
+ obj-$(CONFIG_HAS_IOMEM) += memremap.o
++obj-$(CONFIG_CRASHLOG) += crashlog.o
+ 
+ $(obj)/configs.o: $(obj)/config_data.h
+ 
+--- /dev/null
++++ b/kernel/crashlog.c
+@@ -0,0 +1,213 @@
++/*
++ * Crash information logger
++ * Copyright (C) 2010 Felix Fietkau <nbd@nbd.name>
++ *
++ * Based on ramoops.c
++ *   Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/bootmem.h>
++#include <linux/memblock.h>
++#include <linux/debugfs.h>
++#include <linux/crashlog.h>
++#include <linux/kmsg_dump.h>
++#include <linux/module.h>
++#include <linux/pfn.h>
++#include <linux/vmalloc.h>
++#include <asm/io.h>
++
++#define CRASHLOG_PAGES	4
++#define CRASHLOG_SIZE	(CRASHLOG_PAGES * PAGE_SIZE)
++#define CRASHLOG_MAGIC	0xa1eedead
++
++/*
++ * Start the log at 1M before the end of RAM, as some boot loaders like
++ * to use the end of the RAM for stack usage and other things
++ * If this fails, fall back to using the last part.
++ */
++#define CRASHLOG_OFFSET	(1024 * 1024)
++
++struct crashlog_data {
++	u32 magic;
++	u32 len;
++	u8 data[];
++};
++
++static struct debugfs_blob_wrapper crashlog_blob;
++static unsigned long crashlog_addr = 0;
++static struct crashlog_data *crashlog_buf;
++static struct kmsg_dumper dump;
++static bool first = true;
++
++extern struct list_head *crashlog_modules;
++
++static bool crashlog_set_addr(phys_addr_t addr, phys_addr_t size)
++{
++	/* Limit to lower 64 MB to avoid highmem */
++	phys_addr_t limit = 64 * 1024 * 1024;
++
++	if (crashlog_addr)
++		return false;
++
++	if (addr > limit)
++		return false;
++
++	if (addr + size > limit)
++		size = limit - addr;
++
++	crashlog_addr = addr;
++
++	if (addr + size > CRASHLOG_OFFSET)
++		crashlog_addr += size - CRASHLOG_OFFSET;
++
++	return true;
++}
++
++#ifndef CONFIG_NO_BOOTMEM
++void __init crashlog_init_bootmem(bootmem_data_t *bdata)
++{
++	phys_addr_t start, end;
++
++	start = PFN_PHYS(bdata->node_low_pfn);
++	end = PFN_PHYS(bdata->node_min_pfn);
++	if (!crashlog_set_addr(start, end - start))
++		return;
++
++	if (reserve_bootmem(crashlog_addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) {
++		printk("Crashlog failed to allocate RAM at address 0x%lx\n",
++		       crashlog_addr);
++		crashlog_addr = 0;
++	}
++}
++#endif
++
++#ifdef CONFIG_HAVE_MEMBLOCK
++void __init_memblock crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
++{
++	if (!crashlog_set_addr(addr, size))
++		return;
++
++	if (memblock_reserve(crashlog_addr, CRASHLOG_SIZE)) {
++		printk("Crashlog failed to allocate RAM at address 0x%lx\n",
++		       crashlog_addr);
++		crashlog_addr = 0;
++	}
++}
++#endif
++
++static void __init crashlog_copy(void)
++{
++	if (crashlog_buf->magic != CRASHLOG_MAGIC)
++		return;
++
++	if (!crashlog_buf->len || crashlog_buf->len >
++	    CRASHLOG_SIZE - sizeof(*crashlog_buf))
++		return;
++
++	crashlog_blob.size = crashlog_buf->len;
++	crashlog_blob.data = kmemdup(crashlog_buf->data,
++		crashlog_buf->len, GFP_KERNEL);
++
++	debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob);
++}
++
++static int get_maxlen(void)
++{
++	return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len;
++}
++
++static void crashlog_printf(const char *fmt, ...)
++{
++	va_list args;
++	int len = get_maxlen();
++
++	if (!len)
++		return;
++
++	va_start(args, fmt);
++	crashlog_buf->len += vscnprintf(
++		&crashlog_buf->data[crashlog_buf->len],
++		len, fmt, args);
++	va_end(args);
++}
++
++static void crashlog_do_dump(struct kmsg_dumper *dumper,
++		enum kmsg_dump_reason reason)
++{
++	struct timeval tv;
++	struct module *m;
++	char *buf;
++	size_t len;
++
++	if (!first)
++		crashlog_printf("\n===================================\n");
++
++	do_gettimeofday(&tv);
++	crashlog_printf("Time: %lu.%lu\n",
++		(long)tv.tv_sec, (long)tv.tv_usec);
++
++	if (first) {
++		crashlog_printf("Modules:");
++		list_for_each_entry(m, crashlog_modules, list) {
++			crashlog_printf("\t%s@%p+%x", m->name,
++			m->module_core, m->core_size,
++			m->module_init, m->init_size);
++		}
++		crashlog_printf("\n");
++		first = false;
++	}
++
++	buf = (char *)&crashlog_buf->data[crashlog_buf->len];
++
++	kmsg_dump_get_buffer(dumper, true, buf, get_maxlen(), &len);
++
++	crashlog_buf->len += len;
++}
++
++
++int __init crashlog_init_fs(void)
++{
++	struct page *pages[CRASHLOG_PAGES];
++	pgprot_t prot;
++	int i;
++
++	if (!crashlog_addr) {
++		printk("No memory allocated for crashlog\n");
++		return -ENOMEM;
++	}
++
++	printk("Crashlog allocated RAM at address 0x%lx\n", (unsigned long) crashlog_addr);
++	for (i = 0; i < CRASHLOG_PAGES; i++)
++		pages[i] = pfn_to_page((crashlog_addr >> PAGE_SHIFT) + i);
++
++	prot = pgprot_writecombine(PAGE_KERNEL);
++	crashlog_buf = vmap(pages, CRASHLOG_PAGES, VM_MAP, prot);
++
++	crashlog_copy();
++
++	crashlog_buf->magic = CRASHLOG_MAGIC;
++	crashlog_buf->len = 0;
++
++	dump.max_reason = KMSG_DUMP_OOPS;
++	dump.dump = crashlog_do_dump;
++	kmsg_dump_register(&dump);
++
++	return 0;
++}
++module_init(crashlog_init_fs);
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -275,6 +275,9 @@ static void mod_update_bounds(struct mod
+ #ifdef CONFIG_KGDB_KDB
+ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+ #endif /* CONFIG_KGDB_KDB */
++#ifdef CONFIG_CRASHLOG
++struct list_head *crashlog_modules = &modules;
++#endif
+ 
+ static void module_assert_mutex(void)
+ {
+--- a/mm/memblock.c
++++ b/mm/memblock.c
+@@ -19,6 +19,7 @@
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
+ #include <linux/memblock.h>
++#include <linux/crashlog.h>
+ 
+ #include <asm-generic/sections.h>
+ #include <linux/io.h>
+@@ -503,6 +504,8 @@ static void __init_memblock memblock_ins
+ 	memblock_set_region_node(rgn, nid);
+ 	type->cnt++;
+ 	type->total_size += size;
++	if (type == &memblock.memory)
++		crashlog_init_memblock(base, size);
+ }
+ 
+ /**
+@@ -541,6 +544,8 @@ int __init_memblock memblock_add_range(s
+ 		type->regions[0].flags = flags;
+ 		memblock_set_region_node(&type->regions[0], nid);
+ 		type->total_size = size;
++		if (type == &memblock.memory)
++			crashlog_init_memblock(base, size);
+ 		return 0;
+ 	}
+ repeat:
+--- a/mm/bootmem.c
++++ b/mm/bootmem.c
+@@ -15,6 +15,7 @@
+ #include <linux/export.h>
+ #include <linux/kmemleak.h>
+ #include <linux/range.h>
++#include <linux/crashlog.h>
+ #include <linux/memblock.h>
+ #include <linux/bug.h>
+ #include <linux/io.h>
+@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo
+ 	if (!bdata->node_bootmem_map)
+ 		return 0;
+ 
++	crashlog_init_bootmem(bdata);
+ 	map = bdata->node_bootmem_map;
+ 	start = bdata->node_min_pfn;
+ 	end = bdata->node_low_pfn;
diff --git a/target/linux/generic/patches-4.4/970-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/patches-4.4/970-remove-unsane-filenames-from-deps_initramfs-list.patch
new file mode 100644
index 0000000000..ac13c9e673
--- /dev/null
+++ b/target/linux/generic/patches-4.4/970-remove-unsane-filenames-from-deps_initramfs-list.patch
@@ -0,0 +1,29 @@
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data
+ 	include $(obj)/.initramfs_data.cpio.d
+ endif
+ 
++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
++
+ quiet_cmd_initfs = GEN     $@
+       cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
+ 
+@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra
+ 	initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \
+ 	initramfs_data.cpio
+ # do not try to update files included in initramfs
+-$(deps_initramfs): ;
++$(deps_initramfs_sane): ;
+ 
+-$(deps_initramfs): klibcdirs
++$(deps_initramfs_sane): klibcdirs
+ # We rebuild initramfs_data.cpio if:
+ # 1) Any included file is newer then initramfs_data.cpio
+ # 2) There are changes in which files are included (added or deleted)
+ # 3) If gen_init_cpio are newer than initramfs_data.cpio
+ # 4) arguments to gen_initramfs.sh changes
+-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
++$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
+ 	$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d
+ 	$(call if_changed,initfs)
diff --git a/target/linux/generic/patches-4.4/980-arm_openwrt_machtypes.patch b/target/linux/generic/patches-4.4/980-arm_openwrt_machtypes.patch
new file mode 100644
index 0000000000..60ca07e1a2
--- /dev/null
+++ b/target/linux/generic/patches-4.4/980-arm_openwrt_machtypes.patch
@@ -0,0 +1,32 @@
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -1006,3 +1006,29 @@ eco5_bx2		MACH_ECO5_BX2		ECO5_BX2		4572
+ eukrea_cpuimx28sd	MACH_EUKREA_CPUIMX28SD	EUKREA_CPUIMX28SD	4573
+ domotab			MACH_DOMOTAB		DOMOTAB			4574
+ pfla03			MACH_PFLA03		PFLA03			4575
++#
++# Additional mach-types supported by OpenWrt
++#
++wg302v1			MACH_WG302V1		WG302V1			889
++pronghorn		MACH_PRONGHORN		PRONGHORN		928
++pronghorn_metro		MACH_PRONGHORNMETRO	PRONGHORNMETRO		1040
++sidewinder		MACH_SIDEWINDER		SIDEWINDER		1041
++wrt300nv2		MACH_WRT300NV2		WRT300NV2		1077
++compex42x		MACH_COMPEXWP18		COMPEXWP18		1273
++goldfish		MACH_GOLDFISH		GOLDFISH		1441
++cambria			MACH_CAMBRIA		CAMBRIA			1468
++dt2			MACH_DT2		DT2			1514
++ap1000			MACH_AP1000		AP1000			1543
++tw2662			MACH_TW2662		TW2662			1658
++tw5334			MACH_TW5334		TW5334			1664
++usr8200			MACH_USR8200		USR8200			1762
++mi424wr			MACH_MI424WR		MI424WR			1778
++gw2388			MACH_GW2388		GW2388			2635
++iconnect		MACH_ICONNECT		ICONNECT		2870
++nsb3ast			MACH_NSB3AST		NSB3AST			2917
++goflexnet		MACH_GOFLEXNET		GOFLEXNET		3089
++nas6210			MACH_NAS6210		NAS6210			3104
++ns_k330			MACH_NS_K330		NS_K330			3108
++bcm2708			MACH_BCM2708		BCM2708			3138
++wn802t			MACH_WN802T		WN802T			3306
++nsa310			MACH_NSA310		NSA310			4022
diff --git a/target/linux/generic/patches-4.4/995-mangle_bootargs.patch b/target/linux/generic/patches-4.4/995-mangle_bootargs.patch
new file mode 100644
index 0000000000..2483e1bb98
--- /dev/null
+++ b/target/linux/generic/patches-4.4/995-mangle_bootargs.patch
@@ -0,0 +1,58 @@
+--- a/init/main.c
++++ b/init/main.c
+@@ -355,6 +355,29 @@ static inline void setup_nr_cpu_ids(void
+ static inline void smp_prepare_cpus(unsigned int maxcpus) { }
+ #endif
+ 
++#ifdef CONFIG_MANGLE_BOOTARGS
++static void __init mangle_bootargs(char *command_line)
++{
++	char *rootdev;
++	char *rootfs;
++
++	rootdev = strstr(command_line, "root=/dev/mtdblock");
++
++	if (rootdev)
++		strncpy(rootdev, "mangled_rootblock=", 18);
++
++	rootfs = strstr(command_line, "rootfstype");
++
++	if (rootfs)
++		strncpy(rootfs, "mangled_fs", 10);
++
++}
++#else
++static void __init mangle_bootargs(char *command_line)
++{
++}
++#endif
++
+ /*
+  * We need to store the untouched command line for future reference.
+  * We also need to store the touched command line since the parameter
+@@ -527,6 +550,7 @@ asmlinkage __visible void __init start_k
+ 	pr_notice("%s", linux_banner);
+ 	setup_arch(&command_line);
+ 	mm_init_cpumask(&init_mm);
++	mangle_bootargs(command_line);
+ 	setup_command_line(command_line);
+ 	setup_nr_cpu_ids();
+ 	setup_per_cpu_areas();
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1648,6 +1648,15 @@ config EMBEDDED
+ 	  an embedded system so certain expert options are available
+ 	  for configuration.
+ 
++config MANGLE_BOOTARGS
++	bool "Rename offending bootargs"
++	depends on EXPERT
++	help
++	  Sometimes the bootloader passed bogus root= and rootfstype=
++	  parameters to the kernel, and while you want to ignore them,
++	  you need to know the values f.e. to support dual firmware
++	  layouts on the flash.
++
+ config HAVE_PERF_EVENTS
+ 	bool
+ 	help
diff --git a/target/linux/generic/patches-4.4/998-enable_wilink_platform_without_drivers.patch b/target/linux/generic/patches-4.4/998-enable_wilink_platform_without_drivers.patch
new file mode 100644
index 0000000000..d317de1102
--- /dev/null
+++ b/target/linux/generic/patches-4.4/998-enable_wilink_platform_without_drivers.patch
@@ -0,0 +1,15 @@
+We use backports for driver updates - make sure we can compile in the glue code regardless
+
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+
+--- a/drivers/net/wireless/ti/Kconfig
++++ b/drivers/net/wireless/ti/Kconfig
+@@ -15,7 +15,7 @@ source "drivers/net/wireless/ti/wlcore/K
+ 
+ config WILINK_PLATFORM_DATA
+ 	bool "TI WiLink platform data"
+-	depends on WLCORE_SDIO || WL1251_SDIO
++	depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
+ 	default y
+ 	---help---
+ 	Small platform data bit needed to pass data to the sdio modules.
diff --git a/target/linux/sunxi/Makefile b/target/linux/sunxi/Makefile
new file mode 100644
index 0000000000..cca3a14896
--- /dev/null
+++ b/target/linux/sunxi/Makefile
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+ARCH:=arm
+BOARD:=sunxi
+BOARDNAME:=Allwinner A1x/A20/A3x
+FEATURES:=fpu usb ext4 display rtc
+CPU_TYPE:=cortex-a8
+CPU_SUBTYPE:=vfpv3
+MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>
+
+KERNEL_PATCHVER:=4.4
+KERNELNAME:=zImage dtbs
+
+# A10: Cortex-A8
+# A13: Cortex-A8
+# A20: dual Cortex-A7
+# A31: quad Cortex-A7
+# A80: octa Cortex-A15/A7
+# H3: quad Cortex-A7
+
+include $(INCLUDE_DIR)/target.mk
+
+DEFAULT_PACKAGES += uboot-envtools kmod-eeprom-sunxi kmod-wdt-sunxi
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/sunxi/base-files/etc/board.d/02_network b/target/linux/sunxi/base-files/etc/board.d/02_network
new file mode 100755
index 0000000000..74fa2a0e6d
--- /dev/null
+++ b/target/linux/sunxi/base-files/etc/board.d/02_network
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2015 OpenWrt.org
+#
+
+. /lib/sunxi.sh
+. /lib/functions/uci-defaults.sh
+
+board_config_update
+
+case "$( sunxi_board_name )" in
+"olinuxino-micro"*)
+	ucidef_set_interface_lan 'wlan0'
+	;;
+"lamobo-r1")
+	ucidef_add_switch "switch0" \
+		"4:lan:1" "0:lan:2" "1:lan:3" "2:lan:4" "3:wan" "8@eth0"
+	;;
+*)
+	ucidef_set_interface_lan 'eth0'
+	;;
+esac
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/sunxi/base-files/etc/inittab b/target/linux/sunxi/base-files/etc/inittab
new file mode 100644
index 0000000000..be81ab3e23
--- /dev/null
+++ b/target/linux/sunxi/base-files/etc/inittab
@@ -0,0 +1,5 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+tts/0::askfirst:/usr/libexec/login.sh
+ttyS0::askfirst:/usr/libexec/login.sh
+tty1::askfirst:/usr/libexec/login.sh
diff --git a/target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac4329-sdio.txt b/target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac4329-sdio.txt
new file mode 100644
index 0000000000..6cb3fd730e
--- /dev/null
+++ b/target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac4329-sdio.txt
@@ -0,0 +1,57 @@
+#AP6210_NVRAM_V1.2_03192013
+manfid=0x2d0
+prodid=0x492
+vendid=0x14e4
+devid=0x4343
+boardtype=0x0598
+
+# Board Revision is P307, same nvram file can be used for P304, P305, P306 and P307 as the tssi pa params used are same
+#Please force the automatic RX PER data to the respective board directory if not using P307 board, for e.g. for P305 boards force the data into the following directory /projects/BCM43362/a1_labdata/boardtests/results/sdg_rev0305
+boardrev=0x1307
+boardnum=777
+xtalfreq=26000
+boardflags=0x80201
+boardflags2=0x80
+sromrev=3
+wl0id=0x431b
+macaddr=00:90:4c:07:71:12
+aa2g=1
+ag0=2
+maxp2ga0=74
+cck2gpo=0x2222
+ofdm2gpo=0x44444444
+mcs2gpo0=0x6666
+mcs2gpo1=0x6666
+pa0maxpwr=56
+
+#P207 PA params
+#pa0b0=5447
+#pa0b1=-658
+#pa0b2=-175<div></div>
+
+#Same PA params for P304,P305, P306, P307
+
+pa0b0=5447
+pa0b1=-607
+pa0b2=-160
+pa0itssit=62
+pa1itssit=62
+
+
+cckPwrOffset=5
+ccode=0
+rssismf2g=0xa
+rssismc2g=0x3
+rssisav2g=0x7
+triso2g=0
+noise_cal_enable_2g=0
+noise_cal_po_2g=0
+swctrlmap_2g=0x04040404,0x02020202,0x02020202,0x010101,0x1ff
+temp_add=29767
+temp_mult=425
+
+btc_flags=0x6
+btc_params0=5000
+btc_params1=1000
+btc_params6=63
+
diff --git a/target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac43362-sdio.txt b/target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac43362-sdio.txt
new file mode 100644
index 0000000000..901e7825b8
--- /dev/null
+++ b/target/linux/sunxi/base-files/lib/firmware/brcm/brcmfmac43362-sdio.txt
@@ -0,0 +1,51 @@
+#AP6181_NVRAM_V1.1_01152013
+#adjuest PA parameter for g/n mode
+manfid=0x2d0
+prodid=0x492
+vendid=0x14e4
+devid=0x4343
+boardtype=0x0598
+
+# Board Revision is P307, same nvram file can be used for P304, P305, P306 and P307 as the tssi pa params used are same
+#Please force the automatic RX PER data to the respective board directory if not using P307 board, for e.g. for P305 boards force the data into the following directory /projects/BCM43362/a1_labdata/boardtests/results/sdg_rev0305
+boardrev=0x1307
+boardnum=777
+xtalfreq=26000
+boardflags=0xa00
+sromrev=3
+wl0id=0x431b
+macaddr=00:90:4c:07:71:12
+aa2g=1
+ag0=2
+maxp2ga0=74
+cck2gpo=0x2222
+ofdm2gpo=0x66666666
+mcs2gpo0=0x7777
+mcs2gpo1=0x7777
+pa0maxpwr=56
+
+#P207 PA params
+#pa0b0=5447
+#pa0b1=-658
+#pa0b2=-175<div></div>
+
+#Same PA params for P304,P305, P306, P307
+
+pa0b0=5447
+pa0b1=-607
+pa0b2=-160
+pa0itssit=62
+pa1itssit=62
+
+
+cckPwrOffset=5
+ccode=0
+rssismf2g=0xa
+rssismc2g=0x3
+rssisav2g=0x7
+triso2g=0
+noise_cal_enable_2g=0
+noise_cal_po_2g=0
+swctrlmap_2g=0x04040404,0x02020202,0x02020202,0x010101,0x1ff
+temp_add=29767
+temp_mult=425
diff --git a/target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh b/target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh
new file mode 100644
index 0000000000..f221dbc582
--- /dev/null
+++ b/target/linux/sunxi/base-files/lib/preinit/01_preinit_sunxi.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+do_sunxi() {
+        . /lib/sunxi.sh
+
+        sunxi_board_detect
+}
+
+boot_hook_add preinit_main do_sunxi
diff --git a/target/linux/sunxi/base-files/lib/preinit/02_b53_hack.sh b/target/linux/sunxi/base-files/lib/preinit/02_b53_hack.sh
new file mode 100644
index 0000000000..84070de3eb
--- /dev/null
+++ b/target/linux/sunxi/base-files/lib/preinit/02_b53_hack.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+. /lib/sunxi.sh
+
+do_b53_hack() {
+	# hack: enable switch on Lamobo R1 and reset counters
+	case "$( sunxi_board_name )" in
+	"lamobo-r1")
+		ifconfig eth0 up
+		sleep 1
+		swconfig dev switch0 set reset 1
+		swconfig dev switch0 set reset_mib 1
+		swconfig dev switch0 set apply 1
+		;;
+	esac
+}
+
+boot_hook_add preinit_main do_b53_hack
diff --git a/target/linux/sunxi/base-files/lib/sunxi.sh b/target/linux/sunxi/base-files/lib/sunxi.sh
new file mode 100644
index 0000000000..ce1292b5fd
--- /dev/null
+++ b/target/linux/sunxi/base-files/lib/sunxi.sh
@@ -0,0 +1,150 @@
+#!/bin/sh
+
+# defaults
+SUNXI_BOARD_NAME="generic"
+SUNXI_BOARD_MODEL="Generic sunxi board"
+
+sunxi_board_detect() {
+	local board
+	local model
+
+	[ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/"
+
+	model="$( cat /proc/device-tree/model )"
+
+	case "$model" in
+		"Mele A1000")
+			board="a1000"
+			;;
+
+		"BA10 tvbox")
+			board="ba10-tvbox"
+			;;
+
+		"Cubietech Cubieboard")
+			board="cubieboard"
+			;;
+
+		"Miniand Hackberry")
+			board="hackberry"
+			;;
+
+		"INet-97F Rev 02")
+			board="inet97fv2"
+			;;
+
+		"PineRiver Mini X-Plus")
+			board="mini-xplus"
+			;;
+
+		"Olimex A10-OLinuXino-LIME")
+			board="olinuxino-lime"
+			;;
+
+		"LinkSprite pcDuino")
+			board="pcduino"
+			;;
+
+		"Olimex A10s-Olinuxino Micro")
+			board="olinuxino-micro"
+			;;
+
+		"R7 A10s hdmi tv-stick")
+			board="r7-tv-dongle"
+			;;
+
+		"HSG H702")
+			board="hsg-h702"
+			;;
+
+		"Olimex A13-Olinuxino")
+			board="olinuxino"
+			;;
+
+		"Olimex A13-Olinuxino Micro")
+			board="olinuxino-micro"
+			;;
+
+		"Allwinner A31 APP4 EVB1 Evaluation Board")
+			board="app4-evb1"
+			;;
+
+		"WITS A31 Colombus Evaluation Board")
+			board="colombus"
+			;;
+
+		"Merrii A31 Hummingbird")
+			board="hummingbird"
+			;;
+
+		"Mele M9 / A1000G Quad top set box")
+			board="m9"
+			;;
+
+		"LeMaker Banana Pi")
+			board="bananapi"
+			;;
+
+		"LeMaker Banana Pro")
+			board="bananapro"
+			;;
+
+		"Cubietech Cubieboard2")
+			board="cubieboard2"
+			;;
+
+		"Cubietech Cubietruck")
+			board="cubietruck"
+			;;
+
+		"Merrii A20 Hummingbird")
+			board="hummingbird"
+			;;
+
+		"I12 / Q5 / QT840A A20 tvbox")
+			board="i12-tvbox"
+			;;
+
+		"Lamobo R1")
+			board="lamobo-r1"
+			;;
+
+		"Olimex A20-OLinuXino-LIME")
+			board="olinuxino-lime"
+			;;
+
+		"Olimex A20-Olinuxino Micro")
+			board="olinuxino-a20-micro"
+			;;
+
+		"LinkSprite pcDuino3")
+			board="pcduino3"
+			;;
+
+		"Ippo Q8H Dual Core Tablet (v5)")
+			board="ippo-q8h-v5"
+			;;
+	esac
+
+	if [ "$board" != "" ]; then
+		SUNXI_BOARD_NAME="$board"
+	fi
+
+	if [ "$model" != "" ]; then
+		SUNXI_BOARD_MODEL="$model"
+	fi
+
+
+	echo "$SUNXI_BOARD_NAME" > /tmp/sysinfo/board_name
+	echo "$SUNXI_BOARD_MODEL" > /tmp/sysinfo/model
+	echo "Detected $SUNXI_BOARD_NAME // $SUNXI_BOARD_MODEL"
+}
+
+sunxi_board_name() {
+	local name
+
+	[ -f /tmp/sysinfo/board_name ] && name="$(cat /tmp/sysinfo/board_name)"
+	[ -z "$name" ] && name="unknown"
+
+	echo "$name"
+}
diff --git a/target/linux/sunxi/config-4.4 b/target/linux/sunxi/config-4.4
new file mode 100644
index 0000000000..1962f77984
--- /dev/null
+++ b/target/linux/sunxi/config-4.4
@@ -0,0 +1,533 @@
+CONFIG_ADVISE_SYSCALLS=y
+# CONFIG_AHCI_SUNXI is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_ARCH_AXXIA is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=416
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_ERRATA_643719=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_HEAVY_MB=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_LPAE=y
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_ARM_PMU=y
+CONFIG_ARM_PSCI=y
+CONFIG_ARM_PSCI_FW=y
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_ATA=y
+CONFIG_ATAGS=y
+# CONFIG_ATA_SFF is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_AXP20X_POWER=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BINFMT_MISC=y
+CONFIG_BOUNCE=y
+# CONFIG_BPF_SYSCALL is not set
+CONFIG_CACHE_L2X0=y
+CONFIG_CAN=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMPACTION=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONNECTOR=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_COREDUMP=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_THERMAL=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_DEV_SUN4I_SS=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DIRECT_IO=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_SUN4I=y
+CONFIG_DMA_SUN6I=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DWMAC_GENERIC=y
+CONFIG_DWMAC_SUNXI=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ELF_CORE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXTCON=y
+CONFIG_FB=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_LITTLE_ENDIAN=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_SIMPLE=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FRAME_WARN=2048
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GLOB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_GENERIC_RCU_GUP=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL=y
+CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
+CONFIG_HAVE_KVM_EVENTFD=y
+CONFIG_HAVE_KVM_IRQFD=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_RCU_TABLE_FREE=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_HWMON=y
+CONFIG_HW_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=y
+CONFIG_HZ_FIXED=0
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_SUN6I_P2WI=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+# CONFIG_KERNEL_MODE_NEON is not set
+CONFIG_KEYBOARD_SUN4I_LRADC=y
+CONFIG_KSM=y
+CONFIG_KVM=y
+CONFIG_KVM_ARM_HOST=y
+CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
+CONFIG_KVM_MMIO=y
+CONFIG_KVM_VFIO=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LIBFDT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MACH_SUN4I=y
+CONFIG_MACH_SUN5I=y
+CONFIG_MACH_SUN6I=y
+CONFIG_MACH_SUN7I=y
+CONFIG_MACH_SUN8I=y
+CONFIG_MACH_SUN9I=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MDIO_SUN4I=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MFD_AXP20X=y
+CONFIG_MFD_CORE=y
+CONFIG_MFD_SUN6I_PRCM=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_SUNXI=y
+CONFIG_MMU_NOTIFIER=y
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD is not set
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEON=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NET_VENDOR_ALLWINNER=y
+CONFIG_NLS=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=8
+CONFIG_NVMEM=y
+# CONFIG_NVMEM_SUNXI_SID is not set
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PARTITION_ADVANCED is not set
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PHY_SUN4I_USB=y
+CONFIG_PHY_SUN9I_USB=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_PINCTRL_SUN4I_A10=y
+CONFIG_PINCTRL_SUN5I_A10S=y
+CONFIG_PINCTRL_SUN5I_A13=y
+CONFIG_PINCTRL_SUN6I_A31=y
+CONFIG_PINCTRL_SUN6I_A31S=y
+CONFIG_PINCTRL_SUN6I_A31_R=y
+CONFIG_PINCTRL_SUN7I_A20=y
+CONFIG_PINCTRL_SUN8I_A23=y
+CONFIG_PINCTRL_SUN8I_A23_R=y
+CONFIG_PINCTRL_SUN8I_A33=y
+CONFIG_PINCTRL_SUN8I_A83T=y
+CONFIG_PINCTRL_SUN8I_H3=y
+CONFIG_PINCTRL_SUN9I_A80=y
+CONFIG_PINCTRL_SUNXI_COMMON=y
+# CONFIG_PL310_ERRATA_588369 is not set
+# CONFIG_PL310_ERRATA_727915 is not set
+# CONFIG_PL310_ERRATA_753970 is not set
+# CONFIG_PL310_ERRATA_769419 is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_OPP=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPS=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_NOTIFIERS=y
+CONFIG_PREEMPT_RCU=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_EVENTS=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PWM=y
+CONFIG_PWM_SUN4I=y
+CONFIG_PWM_SYSFS=y
+CONFIG_RATIONAL=y
+# CONFIG_RCU_BOOST is not set
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_SPI=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_AXP20X=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_RELAY=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_SUNXI is not set
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SATA_PMP=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCSI=y
+CONFIG_SDIO_UART=y
+CONFIG_SECURITYFS=y
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SND=y
+CONFIG_SND_COMPRESS_OFFLOAD=y
+CONFIG_SND_JACK=y
+CONFIG_SND_PCM=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_USB is not set
+CONFIG_SOUND=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_SUN4I=y
+CONFIG_SPI_SUN6I=y
+CONFIG_SRCU=y
+# CONFIG_STAGING is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+CONFIG_STRICT_DEVMEM=y
+# CONFIG_SUN4I_EMAC is not set
+CONFIG_SUN4I_TIMER=y
+CONFIG_SUN5I_HSTIMER=y
+CONFIG_SUNXI_RSB=y
+CONFIG_SUNXI_SRAM=y
+CONFIG_SUNXI_WATCHDOG=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_B53=y
+# CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set
+CONFIG_SWCONFIG_B53_PHY_DRIVER=y
+CONFIG_SWCONFIG_B53_PHY_FIXUP=y
+# CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TOUCHSCREEN_PROPERTIES=y
+CONFIG_TOUCHSCREEN_SUN4I=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_COMMON=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_DWC2_HOST=y
+# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+# CONFIG_USB_ETH is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USERIO=y
+CONFIG_USE_OF=y
+CONFIG_VDSO=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VHOST_NET=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/sunxi/image/Config.in b/target/linux/sunxi/image/Config.in
new file mode 100644
index 0000000000..0d6861c631
--- /dev/null
+++ b/target/linux/sunxi/image/Config.in
@@ -0,0 +1,5 @@
+config SUNXI_SD_BOOT_PARTSIZE
+	int "Boot (SD Card) filesystem partition size (in MB)"
+	depends on TARGET_sunxi
+	default 20
+
diff --git a/target/linux/sunxi/image/Makefile b/target/linux/sunxi/image/Makefile
new file mode 100644
index 0000000000..ce805f616f
--- /dev/null
+++ b/target/linux/sunxi/image/Makefile
@@ -0,0 +1,121 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+include $(INCLUDE_DIR)/host.mk
+
+FAT32_BLOCK_SIZE=1024
+FAT32_BLOCKS=$(shell echo $$(($(CONFIG_SUNXI_SD_BOOT_PARTSIZE)*1024*1024/$(FAT32_BLOCK_SIZE))))
+
+define Image/BuildKernel
+	-mkdir -p $(KDIR_TMP)
+
+	mkimage -A arm -O linux -T kernel -C none \
+		-a 0x40008000 -e 0x40008000 \
+		-n 'ARM OpenWrt Linux-$(LINUX_VERSION)' \
+		-d $(KDIR)/zImage $(BIN_DIR)/$(IMG_PREFIX)-uImage
+
+    ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
+	$(CP) $(KDIR)/zImage-initramfs $(BIN_DIR)/$(IMG_PREFIX)-zImage-initramfs
+	echo -ne '\x00\x00\x00\x00' >> $(BIN_DIR)/$(IMG_PREFIX)-zImage-initramfs
+	$(call Image/BuildKernel/MkuImage, \
+		none, 0x40008000, 0x40008000, \
+		$(BIN_DIR)/$(IMG_PREFIX)-zImage-initramfs, \
+		$(BIN_DIR)/$(IMG_PREFIX)-uImage-initramfs \
+	)
+    endif
+endef
+
+define Image/Build/SDCard
+	rm -f $(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img
+	mkfs.fat $(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img -C $(FAT32_BLOCKS)
+
+	mcopy -i $(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img $(KDIR)/uboot-sunxi-$(PROFILE)-boot.scr ::boot.scr
+	mcopy -i $(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img $(DTS_DIR)/$(2).dtb ::dtb
+	mcopy -i $(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img $(BIN_DIR)/$(IMG_PREFIX)-uImage ::uImage
+
+	./gen_sunxi_sdcard_img.sh \
+		$(BIN_DIR)/$(IMG_PREFIX)-$(PROFILE)-sdcard-vfat-$(1).img \
+		$(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img \
+		$(KDIR)/root.$(1) \
+		$(CONFIG_SUNXI_SD_BOOT_PARTSIZE) \
+		$(CONFIG_TARGET_ROOTFS_PARTSIZE) \
+		$(KDIR)/uboot-sunxi-$(PROFILE)-u-boot-with-spl.bin
+
+  ifneq ($(CONFIG_TARGET_IMAGES_GZIP),)
+	gzip -f9n $(BIN_DIR)/$(IMG_PREFIX)-$(PROFILE)-sdcard-vfat-$(1).img
+  endif
+endef
+
+define Image/Build/Profile/A10-OLinuXino-Lime
+	$(call Image/Build/SDCard,$(1),sun4i-a10-olinuxino-lime)
+endef
+
+define Image/Build/Profile/A13-OLinuXino
+	$(call Image/Build/SDCard,$(1),sun5i-a13-olinuxino)
+endef
+
+define Image/Build/Profile/A20-OLinuXino-Lime
+	$(call Image/Build/SDCard,$(1),sun7i-a20-olinuxino-lime)
+endef
+
+define Image/Build/Profile/A20-OLinuXino_MICRO
+	$(call Image/Build/SDCard,$(1),sun7i-a20-olinuxino-micro)
+endef
+
+define Image/Build/Profile/Bananapi
+	$(call Image/Build/SDCard,$(1),sun7i-a20-bananapi)
+endef
+
+define Image/Build/Profile/Bananapro
+	$(call Image/Build/SDCard,$(1),sun7i-a20-bananapro)
+endef
+
+define Image/Build/Profile/Lamobo_R1
+	$(call Image/Build/SDCard,$(1),sun7i-a20-lamobo-r1)
+endef
+
+define Image/Build/Profile/Cubieboard
+	$(call Image/Build/SDCard,$(1),sun4i-a10-cubieboard)
+endef
+
+define Image/Build/Profile/Cubieboard2
+	$(call Image/Build/SDCard,$(1),sun7i-a20-cubieboard2)
+endef
+
+define Image/Build/Profile/Cubietruck
+	$(call Image/Build/SDCard,$(1),sun7i-a20-cubietruck)
+endef
+
+define Image/Build/Profile/OLIMEX_A13_SOM
+	$(call Image/Build/SDCard,$(1),sun5i-a13-olinuxino)
+endef
+
+define Image/Build/Profile/Mele_M9
+	$(call Image/Build/SDCard,$(1),sun6i-a31-hummingbird)
+endef
+
+define Image/Build/Profile/Linksprite_pcDuino
+	$(call Image/Build/SDCard,$(1),sun4i-a10-pcduino)
+endef
+
+define Image/Build/Profile/Linksprite_pcDuino3
+	$(call Image/Build/SDCard,$(1),sun7i-a20-pcduino3)
+endef
+
+define Image/Build/Profile/orangepi_plus
+	$(call Image/Build/SDCard,$(1),sun8i-h3-orangepi-plus)
+endef
+
+define Image/Build
+	$(call Image/Build/$(1),$(1))
+	$(call Image/Build/Profile/$(PROFILE),$(1))
+
+	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/sunxi/image/gen_sunxi_sdcard_img.sh b/target/linux/sunxi/image/gen_sunxi_sdcard_img.sh
new file mode 100755
index 0000000000..2a09306af6
--- /dev/null
+++ b/target/linux/sunxi/image/gen_sunxi_sdcard_img.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+set -x 
+[ $# -eq 6 ] || {
+    echo "SYNTAX: $0 <file> <bootfs image> <rootfs image> <bootfs size> <rootfs size> <u-boot image>"
+    exit 1
+}
+
+OUTPUT="$1"
+BOOTFS="$2"
+ROOTFS="$3"
+BOOTFSSIZE="$4"
+ROOTFSSIZE="$5"
+UBOOT="$6"
+
+head=4
+sect=63
+
+set `ptgen -o $OUTPUT -h $head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M -t 83 -p ${ROOTFSSIZE}M`
+
+BOOTOFFSET="$(($1 / 512))"
+BOOTSIZE="$(($2 / 512))"
+ROOTFSOFFSET="$(($3 / 512))"
+ROOTFSSIZE="$(($4 / 512))"
+
+dd bs=1024 if="$UBOOT" of="$OUTPUT" seek=8 conv=notrunc
+dd bs=512 if="$BOOTFS" of="$OUTPUT" seek="$BOOTOFFSET" conv=notrunc
+dd bs=512 if="$ROOTFS" of="$OUTPUT" seek="$ROOTFSOFFSET" conv=notrunc
diff --git a/target/linux/sunxi/modules.mk b/target/linux/sunxi/modules.mk
new file mode 100644
index 0000000000..6f4991798d
--- /dev/null
+++ b/target/linux/sunxi/modules.mk
@@ -0,0 +1,125 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+define KernelPackage/rtc-sunxi
+    SUBMENU:=$(OTHER_MENU)
+    TITLE:=Sunxi SoC built-in RTC support
+    DEPENDS:=@TARGET_sunxi
+    $(call AddDepends/rtc)
+    KCONFIG:= \
+	CONFIG_RTC_CLASS=y \
+	CONFIG_RTC_DRV_SUNXI=m
+    FILES:=$(LINUX_DIR)/drivers/rtc/rtc-sunxi.ko
+    AUTOLOAD:=$(call AutoLoad,50,rtc-sunxi)
+endef
+
+define KernelPackage/rtc-sunxi/description
+ Support for the AllWinner sunXi SoC's onboard RTC
+endef
+
+$(eval $(call KernelPackage,rtc-sunxi))
+
+define KernelPackage/sunxi-ir
+    SUBMENU:=$(OTHER_MENU)
+    TITLE:=Sunxi SoC built-in IR support (A20)
+    DEPENDS:=@TARGET_sunxi @!LINUX_4_4 +kmod-input-core 
+    $(call AddDepends/rtc)
+    KCONFIG:= \
+	CONFIG_MEDIA_SUPPORT=y \
+	CONFIG_MEDIA_RC_SUPPORT=y \
+	CONFIG_RC_DEVICES=y \
+	CONFIG_IR_SUNXI
+    FILES:=$(LINUX_DIR)/drivers/media/rc/sunxi-cir.ko
+    AUTOLOAD:=$(call AutoLoad,50,sunxi-cir)
+endef
+
+define KernelPackage/sunxi-ir/description
+ Support for the AllWinner sunXi SoC's onboard IR (A20)
+endef
+
+$(eval $(call KernelPackage,sunxi-ir))
+
+define KernelPackage/eeprom-sunxi
+    SUBMENU:=$(OTHER_MENU)
+    TITLE:=AllWinner Security ID fuse support
+    DEPENDS:=@TARGET_sunxi @!LINUX_4_4
+    KCONFIG:= \
+	CONFIG_EEPROM_SUNXI_SID
+    FILES:=$(LINUX_DIR)/drivers/misc/eeprom/sunxi_sid.ko
+    AUTOLOAD:=$(call AutoLoad,50,sunxi_sid)
+endef
+
+define KernelPackage/eeprom-sunxi/description
+ Support for the AllWinner Security ID fuse support
+endef
+
+$(eval $(call KernelPackage,eeprom-sunxi))
+
+define KernelPackage/ata-sunxi
+    TITLE:=AllWinner sunXi AHCI SATA support
+    SUBMENU:=$(BLOCK_MENU)
+    DEPENDS:=@TARGET_sunxi +kmod-ata-ahci-platform +kmod-scsi-core
+    KCONFIG:=CONFIG_AHCI_SUNXI
+    FILES:=$(LINUX_DIR)/drivers/ata/ahci_sunxi.ko
+    AUTOLOAD:=$(call AutoLoad,41,ahci_sunxi,1)
+endef
+
+define KernelPackage/ata-sunxi/description
+ SATA support for the AllWinner sunXi SoC's onboard AHCI SATA
+endef
+
+$(eval $(call KernelPackage,ata-sunxi))
+
+define KernelPackage/sun4i-emac
+  SUBMENU:=$(NETWORK_DEVICES_MENU)
+  TITLE:=AllWinner EMAC Ethernet support
+  DEPENDS:=@TARGET_sunxi +LINUX_4_4:kmod-of-mdio +LINUX_4_4:kmod-libphy
+  KCONFIG:=CONFIG_SUN4I_EMAC
+  FILES:=$(LINUX_DIR)/drivers/net/ethernet/allwinner/sun4i-emac.ko
+  AUTOLOAD:=$(call AutoProbe,sun4i-emac)
+endef
+
+$(eval $(call KernelPackage,sun4i-emac))
+
+
+define KernelPackage/wdt-sunxi
+    SUBMENU:=$(OTHER_MENU)
+    TITLE:=AllWinner sunXi Watchdog timer
+    DEPENDS:=@TARGET_sunxi
+    KCONFIG:=CONFIG_SUNXI_WATCHDOG
+    FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/sunxi_wdt.ko
+    AUTOLOAD:=$(call AutoLoad,51,sunxi_wdt)
+endef
+
+define KernelPackage/wdt-sunxi/description
+    Kernel module for AllWinner sunXi watchdog timer.
+endef
+
+$(eval $(call KernelPackage,wdt-sunxi))
+
+
+define KernelPackage/sound-soc-sunxi
+  TITLE:=AllWinner built-in SoC sound support
+  KCONFIG:= \
+	CONFIG_SND_SUNXI_SOC_CODEC \
+	CONFIG_SND_SUN4I_CODEC
+ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),lt,4.4.0)),1)
+  FILES+=$(LINUX_DIR)/sound/soc/sunxi/sunxi-codec.ko
+  AUTOLOAD:=$(call AutoLoad,65,sunxi-codec)
+endif
+ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),ge,4.4.0)),1)
+  FILES:=$(LINUX_DIR)/sound/soc/sunxi/sun4i-codec.ko
+  AUTOLOAD:=$(call AutoLoad,65,sun4i-codec)
+endif
+  DEPENDS:=@TARGET_sunxi +kmod-sound-soc-core
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-sunxi/description
+  Kernel support for AllWinner built-in SoC audio
+endef
+
+$(eval $(call KernelPackage,sound-soc-sunxi))
diff --git a/target/linux/sunxi/patches-4.4/100-clk-sunxi-add-dram-gates-support.patch b/target/linux/sunxi/patches-4.4/100-clk-sunxi-add-dram-gates-support.patch
new file mode 100644
index 0000000000..4d353f3789
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/100-clk-sunxi-add-dram-gates-support.patch
@@ -0,0 +1,39 @@
+From 6d3a47c29186aa8d26ff05a6209c94291ace0696 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Sat, 5 Dec 2015 21:16:42 +0800
+Subject: [PATCH] clk: sunxi: Add DRAM gates support for sun4i-a10
+
+The A10/A20 share the same set of DRAM clock gates, which controls
+direct memory access for some peripherals.
+
+On the A10, bit 15 controls the system's DRAM clock output (possibly
+to the DRAM chips), which we need to keep on.
+
+On the A20 this has been moved to the DRAM controller, becoming a no-op.
+However it is still listed in the user manual, so add it anyway.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
+ drivers/clk/sunxi/clk-simple-gates.c              | 12 ++++++++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/drivers/clk/sunxi/clk-simple-gates.c
++++ b/drivers/clk/sunxi/clk-simple-gates.c
+@@ -158,3 +158,15 @@ CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner
+ 	       sun4i_a10_ahb_init);
+ CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
+ 	       sun4i_a10_ahb_init);
++
++static const int sun4i_a10_dram_critical_clocks[] __initconst = {
++	15,	/* dram_output */
++};
++
++static void __init sun4i_a10_dram_init(struct device_node *node)
++{
++	sunxi_simple_gates_setup(node, sun4i_a10_dram_critical_clocks,
++				 ARRAY_SIZE(sun4i_a10_dram_critical_clocks));
++}
++CLK_OF_DECLARE(sun4i_a10_dram, "allwinner,sun4i-a10-dram-gates-clk",
++	       sun4i_a10_dram_init);
diff --git a/target/linux/sunxi/patches-4.4/101-dt-sun4i-add-dram-gates.patch b/target/linux/sunxi/patches-4.4/101-dt-sun4i-add-dram-gates.patch
new file mode 100644
index 0000000000..e21eca4e1f
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/101-dt-sun4i-add-dram-gates.patch
@@ -0,0 +1,88 @@
+From 82f8582feef4c048ee7ef0155a71c23614a7856d Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Sat, 5 Dec 2015 21:16:44 +0800
+Subject: [PATCH] ARM: dts: sun4i: Add DRAM gates
+
+The DRAM gates controls direct memory access for some peripherals.
+These peripherals include the display pipeline, so add the required
+gates to the simplefb nodes as well.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -66,7 +66,7 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-hdmi";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+-				 <&ahb_gates 44>;
++				 <&ahb_gates 44>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -75,7 +75,8 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+-				 <&ahb_gates 44>, <&ahb_gates 46>;
++				 <&ahb_gates 44>, <&ahb_gates 46>,
++				 <&dram_gates 25>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -84,7 +85,8 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_fe0-de_be0-lcd0";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
+-				 <&ahb_gates 46>;
++				 <&ahb_gates 46>, <&dram_gates 25>,
++				 <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -93,7 +95,8 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_fe0-de_be0-lcd0-tve0";
+ 			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+-				 <&ahb_gates 44>, <&ahb_gates 46>;
++				 <&ahb_gates 44>, <&ahb_gates 46>,
++				 <&dram_gates 25>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 	};
+@@ -492,6 +495,31 @@
+ 			clock-output-names = "spi3";
+ 		};
+ 
++		dram_gates: clk@01c20100 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-dram-gates-clk";
++			reg = <0x01c20100 0x4>;
++			clocks = <&pll5 0>;
++			clock-indices = <0>,
++					<1>, <2>,
++					<3>,
++					<4>,
++					<5>, <6>,
++					<15>,
++					<24>, <25>,
++					<26>, <27>,
++					<28>, <29>;
++			clock-output-names = "dram_ve",
++					     "dram_csi0", "dram_csi1",
++					     "dram_ts",
++					     "dram_tvd",
++					     "dram_tve0", "dram_tve1",
++					     "dram_output",
++					     "dram_de_fe1", "dram_de_fe0",
++					     "dram_de_be0", "dram_de_be1",
++					     "dram_de_mp", "dram_ace";
++		};
++
+ 		codec_clk: clk@01c20140 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-codec-clk";
diff --git a/target/linux/sunxi/patches-4.4/102-dt-sun7i-add-dram-gates.patch b/target/linux/sunxi/patches-4.4/102-dt-sun7i-add-dram-gates.patch
new file mode 100644
index 0000000000..397269076c
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/102-dt-sun7i-add-dram-gates.patch
@@ -0,0 +1,77 @@
+From 0b4bf5a5200b9ac5ddf545665f171feb5594677d Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Sat, 5 Dec 2015 21:16:46 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add DRAM gates
+
+The DRAM gates controls direct memory access for some peripherals.
+These peripherals include the display pipeline, so add the required
+gates to the simplefb nodes as well.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 32 +++++++++++++++++++++++++++++---
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -68,7 +68,7 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-hdmi";
+ 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+-				 <&ahb_gates 44>;
++				 <&ahb_gates 44>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -76,7 +76,8 @@
+ 			compatible = "allwinner,simple-framebuffer",
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0";
+-			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
++			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
++				 <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 
+@@ -85,7 +86,7 @@
+ 				     "simple-framebuffer";
+ 			allwinner,pipeline = "de_be0-lcd0-tve0";
+ 			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+-				 <&ahb_gates 44>;
++				 <&ahb_gates 44>, <&dram_gates 26>;
+ 			status = "disabled";
+ 		};
+ 	};
+@@ -501,6 +502,31 @@
+ 			clock-output-names = "spi3";
+ 		};
+ 
++		dram_gates: clk@01c20100 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-dram-gates-clk";
++			reg = <0x01c20100 0x4>;
++			clocks = <&pll5 0>;
++			clock-indices = <0>,
++					<1>, <2>,
++					<3>,
++					<4>,
++					<5>, <6>,
++					<15>,
++					<24>, <25>,
++					<26>, <27>,
++					<28>, <29>;
++			clock-output-names = "dram_ve",
++					     "dram_csi0", "dram_csi1",
++					     "dram_ts",
++					     "dram_tvd",
++					     "dram_tve0", "dram_tve1",
++					     "dram_output",
++					     "dram_de_fe1", "dram_de_fe0",
++					     "dram_de_be0", "dram_de_be1",
++					     "dram_de_mp", "dram_ace";
++		};
++
+ 		codec_clk: clk@01c20140 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-codec-clk";
diff --git a/target/linux/sunxi/patches-4.4/103-clk-sunxi-add-h3-clksupport.patch b/target/linux/sunxi/patches-4.4/103-clk-sunxi-add-h3-clksupport.patch
new file mode 100644
index 0000000000..8bc66274c3
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/103-clk-sunxi-add-h3-clksupport.patch
@@ -0,0 +1,180 @@
+From ab6e23a4e388f5f2696b8e92c350f845142da118 Mon Sep 17 00:00:00 2001
+From: Jens Kuske <jenskuske@gmail.com>
+Date: Fri, 4 Dec 2015 22:24:40 +0100
+Subject: [PATCH] clk: sunxi: Add H3 clocks support
+
+The H3 clock control unit is similar to the those of other sun8i family
+members like the A23.
+
+It adds a new bus gates clock similar to the simple gates, but with a
+different parent clock for each single gate.
+Some of the gates use the new AHB2 clock as parent, whose clock source
+is muxable between AHB1 and PLL6/2. The documentation isn't totally clear
+about which devices belong to AHB2 now, especially USB EHIC/OHIC, so it
+is mostly based on Allwinner kernel source code.
+
+Signed-off-by: Jens Kuske <jenskuske@gmail.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
+ drivers/clk/sunxi/Makefile                        |   1 +
+ drivers/clk/sunxi/clk-sun8i-bus-gates.c           | 112 ++++++++++++++++++++++
+ drivers/clk/sunxi/clk-sunxi.c                     |   6 ++
+ 4 files changed, 121 insertions(+)
+ create mode 100644 drivers/clk/sunxi/clk-sun8i-bus-gates.c
+
+--- a/drivers/clk/sunxi/Makefile
++++ b/drivers/clk/sunxi/Makefile
+@@ -10,6 +10,7 @@ obj-y += clk-a10-pll2.o
+ obj-y += clk-a20-gmac.o
+ obj-y += clk-mod0.o
+ obj-y += clk-simple-gates.o
++obj-y += clk-sun8i-bus-gates.o
+ obj-y += clk-sun8i-mbus.o
+ obj-y += clk-sun9i-core.o
+ obj-y += clk-sun9i-mmc.o
+--- /dev/null
++++ b/drivers/clk/sunxi/clk-sun8i-bus-gates.c
+@@ -0,0 +1,112 @@
++/*
++ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
++ *
++ * Based on clk-simple-gates.c, which is:
++ * Copyright 2015 Maxime Ripard
++ *
++ * Maxime Ripard <maxime.ripard@free-electrons.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++static DEFINE_SPINLOCK(gates_lock);
++
++static void __init sun8i_h3_bus_gates_init(struct device_node *node)
++{
++	static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" };
++	enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent;
++	const char *parents[PARENT_MAX];
++	struct clk_onecell_data *clk_data;
++	const char *clk_name;
++	struct property *prop;
++	struct resource res;
++	void __iomem *clk_reg;
++	void __iomem *reg;
++	const __be32 *p;
++	int number, i;
++	u8 clk_bit;
++	u32 index;
++
++	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
++	if (IS_ERR(reg))
++		return;
++
++	for (i = 0; i < ARRAY_SIZE(names); i++) {
++		index = of_property_match_string(node, "clock-names",
++						 names[i]);
++		if (index < 0)
++			return;
++
++		parents[i] = of_clk_get_parent_name(node, index);
++	}
++
++	clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
++	if (!clk_data)
++		goto err_unmap;
++
++	number = of_property_count_u32_elems(node, "clock-indices");
++	of_property_read_u32_index(node, "clock-indices", number - 1, &number);
++
++	clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
++	if (!clk_data->clks)
++		goto err_free_data;
++
++	i = 0;
++	of_property_for_each_u32(node, "clock-indices", prop, p, index) {
++		of_property_read_string_index(node, "clock-output-names",
++					      i, &clk_name);
++
++		if (index == 17 || (index >= 29 && index <= 31))
++			clk_parent = AHB2;
++		else if (index <= 63 || index >= 128)
++			clk_parent = AHB1;
++		else if (index >= 64 && index <= 95)
++			clk_parent = APB1;
++		else if (index >= 96 && index <= 127)
++			clk_parent = APB2;
++
++		clk_reg = reg + 4 * (index / 32);
++		clk_bit = index % 32;
++
++		clk_data->clks[index] = clk_register_gate(NULL, clk_name,
++							  parents[clk_parent],
++							  0, clk_reg, clk_bit,
++							  0, &gates_lock);
++		i++;
++
++		if (IS_ERR(clk_data->clks[index])) {
++			WARN_ON(true);
++			continue;
++		}
++	}
++
++	clk_data->clk_num = number + 1;
++	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++
++	return;
++
++err_free_data:
++	kfree(clk_data);
++err_unmap:
++	iounmap(reg);
++	of_address_to_resource(node, 0, &res);
++	release_mem_region(res.start, resource_size(&res));
++}
++
++CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk",
++	       sun8i_h3_bus_gates_init);
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -778,6 +778,10 @@ static const struct mux_data sun6i_a31_a
+ 	.shift = 12,
+ };
+ 
++static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = {
++	.shift = 0,
++};
++
+ static void __init sunxi_mux_clk_setup(struct device_node *node,
+ 				       struct mux_data *data)
+ {
+@@ -1130,6 +1134,7 @@ static const struct of_device_id clk_div
+ static const struct of_device_id clk_mux_match[] __initconst = {
+ 	{.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
+ 	{.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
++	{.compatible = "allwinner,sun8i-h3-ahb2-clk", .data = &sun8i_h3_ahb2_mux_data,},
+ 	{}
+ };
+ 
+@@ -1212,6 +1217,7 @@ CLK_OF_DECLARE(sun6i_a31_clk_init, "allw
+ CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
+ CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
+ CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks);
++CLK_OF_DECLARE(sun8i_h3_clk_init, "allwinner,sun8i-h3", sun6i_init_clocks);
+ 
+ static void __init sun9i_init_clocks(struct device_node *node)
+ {
diff --git a/target/linux/sunxi/patches-4.4/104-1-dt-sunxi-add-h3-dtsi.patch b/target/linux/sunxi/patches-4.4/104-1-dt-sunxi-add-h3-dtsi.patch
new file mode 100644
index 0000000000..35a653c5fe
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/104-1-dt-sunxi-add-h3-dtsi.patch
@@ -0,0 +1,515 @@
+From 318d93bc41823e86967c8251eef0444a72e4d687 Mon Sep 17 00:00:00 2001
+From: Jens Kuske <jenskuske@gmail.com>
+Date: Fri, 4 Dec 2015 22:24:42 +0100
+Subject: [PATCH] ARM: dts: sunxi: Add Allwinner H3 DTSI
+
+The Allwinner H3 is a home entertainment system oriented SoC with
+four Cortex-A7 cores and a Mali-400MP2 GPU.
+
+Signed-off-by: Jens Kuske <jenskuske@gmail.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun8i-h3.dtsi | 497 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 497 insertions(+)
+ create mode 100644 arch/arm/boot/dts/sun8i-h3.dtsi
+
+--- /dev/null
++++ b/arch/arm/boot/dts/sun8i-h3.dtsi
+@@ -0,0 +1,497 @@
++/*
++ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#include "skeleton.dtsi"
++
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	interrupt-parent = <&gic>;
++
++	cpus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		cpu@0 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			reg = <0>;
++		};
++
++		cpu@1 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			reg = <1>;
++		};
++
++		cpu@2 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			reg = <2>;
++		};
++
++		cpu@3 {
++			compatible = "arm,cortex-a7";
++			device_type = "cpu";
++			reg = <3>;
++		};
++	};
++
++	timer {
++		compatible = "arm,armv7-timer";
++		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
++			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
++	};
++
++	clocks {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		ranges;
++
++		osc24M: osc24M_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-clock";
++			clock-frequency = <24000000>;
++			clock-output-names = "osc24M";
++		};
++
++		osc32k: osc32k_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-clock";
++			clock-frequency = <32768>;
++			clock-output-names = "osc32k";
++		};
++
++		pll1: clk@01c20000 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun8i-a23-pll1-clk";
++			reg = <0x01c20000 0x4>;
++			clocks = <&osc24M>;
++			clock-output-names = "pll1";
++		};
++
++		/* dummy clock until actually implemented */
++		pll5: pll5_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-clock";
++			clock-frequency = <0>;
++			clock-output-names = "pll5";
++		};
++
++		pll6: clk@01c20028 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun6i-a31-pll6-clk";
++			reg = <0x01c20028 0x4>;
++			clocks = <&osc24M>;
++			clock-output-names = "pll6", "pll6x2";
++		};
++
++		pll6d2: pll6d2_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-factor-clock";
++			clock-div = <2>;
++			clock-mult = <1>;
++			clocks = <&pll6 0>;
++			clock-output-names = "pll6d2";
++		};
++
++		/* dummy clock until pll6 can be reused */
++		pll8: pll8_clk {
++			#clock-cells = <0>;
++			compatible = "fixed-clock";
++			clock-frequency = <1>;
++			clock-output-names = "pll8";
++		};
++
++		cpu: cpu_clk@01c20050 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-cpu-clk";
++			reg = <0x01c20050 0x4>;
++			clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
++			clock-output-names = "cpu";
++		};
++
++		axi: axi_clk@01c20050 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-axi-clk";
++			reg = <0x01c20050 0x4>;
++			clocks = <&cpu>;
++			clock-output-names = "axi";
++		};
++
++		ahb1: ahb1_clk@01c20054 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun6i-a31-ahb1-clk";
++			reg = <0x01c20054 0x4>;
++			clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
++			clock-output-names = "ahb1";
++		};
++
++		ahb2: ahb2_clk@01c2005c {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun8i-h3-ahb2-clk";
++			reg = <0x01c2005c 0x4>;
++			clocks = <&ahb1>, <&pll6d2>;
++			clock-output-names = "ahb2";
++		};
++
++		apb1: apb1_clk@01c20054 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-apb0-clk";
++			reg = <0x01c20054 0x4>;
++			clocks = <&ahb1>;
++			clock-output-names = "apb1";
++		};
++
++		apb2: apb2_clk@01c20058 {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun4i-a10-apb1-clk";
++			reg = <0x01c20058 0x4>;
++			clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
++			clock-output-names = "apb2";
++		};
++
++		bus_gates: clk@01c20060 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun8i-h3-bus-gates-clk";
++			reg = <0x01c20060 0x14>;
++			clocks = <&ahb1>, <&ahb2>, <&apb1>, <&apb2>;
++			clock-names = "ahb1", "ahb2", "apb1", "apb2";
++			clock-indices = <5>, <6>, <8>,
++					<9>, <10>, <13>,
++					<14>, <17>, <18>,
++					<19>, <20>,
++					<21>, <23>,
++					<24>, <25>,
++					<26>, <27>,
++					<28>, <29>,
++					<30>, <31>, <32>,
++					<35>, <36>, <37>,
++					<40>, <41>, <43>,
++					<44>, <52>, <53>,
++					<54>, <64>,
++					<65>, <69>, <72>,
++					<76>, <77>, <78>,
++					<96>, <97>, <98>,
++					<112>, <113>,
++					<114>, <115>,
++					<116>, <128>, <135>;
++			clock-output-names = "bus_ce", "bus_dma", "bus_mmc0",
++					     "bus_mmc1", "bus_mmc2", "bus_nand",
++					     "bus_sdram", "bus_gmac", "bus_ts",
++					     "bus_hstimer", "bus_spi0",
++					     "bus_spi1", "bus_otg",
++					     "bus_otg_ehci0", "bus_ehci1",
++					     "bus_ehci2", "bus_ehci3",
++					     "bus_otg_ohci0", "bus_ohci1",
++					     "bus_ohci2", "bus_ohci3", "bus_ve",
++					     "bus_lcd0", "bus_lcd1", "bus_deint",
++					     "bus_csi", "bus_tve", "bus_hdmi",
++					     "bus_de", "bus_gpu", "bus_msgbox",
++					     "bus_spinlock", "bus_codec",
++					     "bus_spdif", "bus_pio", "bus_ths",
++					     "bus_i2s0", "bus_i2s1", "bus_i2s2",
++					     "bus_i2c0", "bus_i2c1", "bus_i2c2",
++					     "bus_uart0", "bus_uart1",
++					     "bus_uart2", "bus_uart3",
++					     "bus_scr", "bus_ephy", "bus_dbg";
++		};
++
++		mmc0_clk: clk@01c20088 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-mmc-clk";
++			reg = <0x01c20088 0x4>;
++			clocks = <&osc24M>, <&pll6 0>, <&pll8>;
++			clock-output-names = "mmc0",
++					     "mmc0_output",
++					     "mmc0_sample";
++		};
++
++		mmc1_clk: clk@01c2008c {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-mmc-clk";
++			reg = <0x01c2008c 0x4>;
++			clocks = <&osc24M>, <&pll6 0>, <&pll8>;
++			clock-output-names = "mmc1",
++					     "mmc1_output",
++					     "mmc1_sample";
++		};
++
++		mmc2_clk: clk@01c20090 {
++			#clock-cells = <1>;
++			compatible = "allwinner,sun4i-a10-mmc-clk";
++			reg = <0x01c20090 0x4>;
++			clocks = <&osc24M>, <&pll6 0>, <&pll8>;
++			clock-output-names = "mmc2",
++					     "mmc2_output",
++					     "mmc2_sample";
++		};
++
++		mbus_clk: clk@01c2015c {
++			#clock-cells = <0>;
++			compatible = "allwinner,sun8i-a23-mbus-clk";
++			reg = <0x01c2015c 0x4>;
++			clocks = <&osc24M>, <&pll6 1>, <&pll5>;
++			clock-output-names = "mbus";
++		};
++	};
++
++	soc {
++		compatible = "simple-bus";
++		#address-cells = <1>;
++		#size-cells = <1>;
++		ranges;
++
++		dma: dma-controller@01c02000 {
++			compatible = "allwinner,sun8i-h3-dma";
++			reg = <0x01c02000 0x1000>;
++			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 6>;
++			resets = <&ahb_rst 6>;
++			#dma-cells = <1>;
++		};
++
++		mmc0: mmc@01c0f000 {
++			compatible = "allwinner,sun5i-a13-mmc";
++			reg = <0x01c0f000 0x1000>;
++			clocks = <&bus_gates 8>,
++				 <&mmc0_clk 0>,
++				 <&mmc0_clk 1>,
++				 <&mmc0_clk 2>;
++			clock-names = "ahb",
++				      "mmc",
++				      "output",
++				      "sample";
++			resets = <&ahb_rst 8>;
++			reset-names = "ahb";
++			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		mmc1: mmc@01c10000 {
++			compatible = "allwinner,sun5i-a13-mmc";
++			reg = <0x01c10000 0x1000>;
++			clocks = <&bus_gates 9>,
++				 <&mmc1_clk 0>,
++				 <&mmc1_clk 1>,
++				 <&mmc1_clk 2>;
++			clock-names = "ahb",
++				      "mmc",
++				      "output",
++				      "sample";
++			resets = <&ahb_rst 9>;
++			reset-names = "ahb";
++			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		mmc2: mmc@01c11000 {
++			compatible = "allwinner,sun5i-a13-mmc";
++			reg = <0x01c11000 0x1000>;
++			clocks = <&bus_gates 10>,
++				 <&mmc2_clk 0>,
++				 <&mmc2_clk 1>,
++				 <&mmc2_clk 2>;
++			clock-names = "ahb",
++				      "mmc",
++				      "output",
++				      "sample";
++			resets = <&ahb_rst 10>;
++			reset-names = "ahb";
++			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++			#address-cells = <1>;
++			#size-cells = <0>;
++		};
++
++		pio: pinctrl@01c20800 {
++			compatible = "allwinner,sun8i-h3-pinctrl";
++			reg = <0x01c20800 0x400>;
++			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 69>;
++			gpio-controller;
++			#gpio-cells = <3>;
++			interrupt-controller;
++			#interrupt-cells = <2>;
++
++			uart0_pins_a: uart0@0 {
++				allwinner,pins = "PA4", "PA5";
++				allwinner,function = "uart0";
++				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++
++			mmc0_pins_a: mmc0@0 {
++				allwinner,pins = "PF0", "PF1", "PF2", "PF3",
++						 "PF4", "PF5";
++				allwinner,function = "mmc0";
++				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++
++			mmc0_cd_pin: mmc0_cd_pin@0 {
++				allwinner,pins = "PF6";
++				allwinner,function = "gpio_in";
++				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++			};
++
++			mmc1_pins_a: mmc1@0 {
++				allwinner,pins = "PG0", "PG1", "PG2", "PG3",
++						 "PG4", "PG5";
++				allwinner,function = "mmc1";
++				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
++				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++			};
++		};
++
++		ahb_rst: reset@01c202c0 {
++			#reset-cells = <1>;
++			compatible = "allwinner,sun6i-a31-ahb1-reset";
++			reg = <0x01c202c0 0xc>;
++		};
++
++		apb1_rst: reset@01c202d0 {
++			#reset-cells = <1>;
++			compatible = "allwinner,sun6i-a31-clock-reset";
++			reg = <0x01c202d0 0x4>;
++		};
++
++		apb2_rst: reset@01c202d8 {
++			#reset-cells = <1>;
++			compatible = "allwinner,sun6i-a31-clock-reset";
++			reg = <0x01c202d8 0x4>;
++		};
++
++		timer@01c20c00 {
++			compatible = "allwinner,sun4i-a10-timer";
++			reg = <0x01c20c00 0xa0>;
++			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&osc24M>;
++		};
++
++		wdt0: watchdog@01c20ca0 {
++			compatible = "allwinner,sun6i-a31-wdt";
++			reg = <0x01c20ca0 0x20>;
++			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
++		};
++
++		uart0: serial@01c28000 {
++			compatible = "snps,dw-apb-uart";
++			reg = <0x01c28000 0x400>;
++			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
++			reg-shift = <2>;
++			reg-io-width = <4>;
++			clocks = <&bus_gates 112>;
++			resets = <&apb2_rst 16>;
++			dmas = <&dma 6>, <&dma 6>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
++		uart1: serial@01c28400 {
++			compatible = "snps,dw-apb-uart";
++			reg = <0x01c28400 0x400>;
++			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
++			reg-shift = <2>;
++			reg-io-width = <4>;
++			clocks = <&bus_gates 113>;
++			resets = <&apb2_rst 17>;
++			dmas = <&dma 7>, <&dma 7>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
++		uart2: serial@01c28800 {
++			compatible = "snps,dw-apb-uart";
++			reg = <0x01c28800 0x400>;
++			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
++			reg-shift = <2>;
++			reg-io-width = <4>;
++			clocks = <&bus_gates 114>;
++			resets = <&apb2_rst 18>;
++			dmas = <&dma 8>, <&dma 8>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
++		uart3: serial@01c28c00 {
++			compatible = "snps,dw-apb-uart";
++			reg = <0x01c28c00 0x400>;
++			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
++			reg-shift = <2>;
++			reg-io-width = <4>;
++			clocks = <&bus_gates 115>;
++			resets = <&apb2_rst 19>;
++			dmas = <&dma 9>, <&dma 9>;
++			dma-names = "rx", "tx";
++			status = "disabled";
++		};
++
++		gic: interrupt-controller@01c81000 {
++			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
++			reg = <0x01c81000 0x1000>,
++			      <0x01c82000 0x1000>,
++			      <0x01c84000 0x2000>,
++			      <0x01c86000 0x2000>;
++			interrupt-controller;
++			#interrupt-cells = <3>;
++			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++		};
++
++		rtc: rtc@01f00000 {
++			compatible = "allwinner,sun6i-a31-rtc";
++			reg = <0x01f00000 0x54>;
++			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
++		};
++	};
++};
diff --git a/target/linux/sunxi/patches-4.4/104-2-dt-sun8i-add-orangepi-plus.patch b/target/linux/sunxi/patches-4.4/104-2-dt-sun8i-add-orangepi-plus.patch
new file mode 100644
index 0000000000..67094a4beb
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/104-2-dt-sun8i-add-orangepi-plus.patch
@@ -0,0 +1,111 @@
+From dfcf8196de7411a5e7fd49795938b1bc8c56859c Mon Sep 17 00:00:00 2001
+From: Jens Kuske <jenskuske@gmail.com>
+Date: Fri, 4 Dec 2015 22:24:43 +0100
+Subject: [PATCH] ARM: dts: sun8i: Add Orange Pi Plus support
+
+The Orange Pi Plus is a SBC based on the Allwinner H3 SoC
+with 8GB eMMC, multiple USB ports through a USB hub chip, SATA through
+a USB-SATA bridge, one uSD slot, a 10/100/1000M ethernet port,
+WiFi, HDMI, headphone jack, IR receiver, a microphone, a CSI connector
+and a 40-pin GPIO header.
+
+Signed-off-by: Jens Kuske <jenskuske@gmail.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/Makefile                   |  3 +-
+ arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts | 77 ++++++++++++++++++++++++++++
+ 2 files changed, 79 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -660,7 +660,8 @@ dtb-$(CONFIG_MACH_SUN8I) += \
+ 	sun8i-a33-ga10h-v1.1.dtb \
+ 	sun8i-a33-ippo-q8h-v1.2.dtb \
+ 	sun8i-a33-q8-tablet.dtb \
+-	sun8i-a33-sinlinx-sina33.dtb
++	sun8i-a33-sinlinx-sina33.dtb \
++	sun8i-h3-orangepi-plus.dtb
+ dtb-$(CONFIG_MACH_SUN9I) += \
+ 	sun9i-a80-optimus.dtb \
+ 	sun9i-a80-cubieboard4.dtb
+--- /dev/null
++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
+@@ -0,0 +1,77 @@
++/*
++ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun8i-h3.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "Xunlong Orange Pi Plus";
++	compatible = "xunlong,orangepi-plus", "allwinner,sun8i-h3";
++
++	aliases {
++		serial0 = &uart0;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
++	vmmc-supply = <&reg_vcc3v3>;
++	bus-width = <4>;
++	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
++	cd-inverted;
++	status = "okay";
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
diff --git a/target/linux/sunxi/patches-4.4/105-phy-use_of_match_node.patch b/target/linux/sunxi/patches-4.4/105-phy-use_of_match_node.patch
new file mode 100644
index 0000000000..7715b585d0
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/105-phy-use_of_match_node.patch
@@ -0,0 +1,218 @@
+From 5c627d8e7660c170c591ef281184fd11d0493440 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 11 Dec 2015 16:32:17 +0100
+Subject: [PATCH] phy-sun4i-usb: Use of_match_node to get model specific config
+ data
+
+Use of_match_node instead of calling of_device_is_compatible a ton of
+times to get model specific config data.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
+---
+ drivers/phy/phy-sun4i-usb.c | 121 +++++++++++++++++++++++++++++---------------
+ 1 file changed, 79 insertions(+), 42 deletions(-)
+
+--- a/drivers/phy/phy-sun4i-usb.c
++++ b/drivers/phy/phy-sun4i-usb.c
+@@ -32,6 +32,7 @@
+ #include <linux/mutex.h>
+ #include <linux/of.h>
+ #include <linux/of_address.h>
++#include <linux/of_device.h>
+ #include <linux/of_gpio.h>
+ #include <linux/phy/phy.h>
+ #include <linux/phy/phy-sun4i-usb.h>
+@@ -88,12 +89,23 @@
+ #define DEBOUNCE_TIME			msecs_to_jiffies(50)
+ #define POLL_TIME			msecs_to_jiffies(250)
+ 
++enum sun4i_usb_phy_type {
++	sun4i_a10_phy,
++	sun8i_a33_phy,
++};
++
++struct sun4i_usb_phy_cfg {
++	int num_phys;
++	enum sun4i_usb_phy_type type;
++	u32 disc_thresh;
++	u8 phyctl_offset;
++	bool dedicated_clocks;
++};
++
+ struct sun4i_usb_phy_data {
+ 	void __iomem *base;
++	const struct sun4i_usb_phy_cfg *cfg;
+ 	struct mutex mutex;
+-	int num_phys;
+-	u32 disc_thresh;
+-	bool has_a33_phyctl;
+ 	struct sun4i_usb_phy {
+ 		struct phy *phy;
+ 		void __iomem *pmu;
+@@ -159,17 +171,14 @@ static void sun4i_usb_phy_write(struct s
+ {
+ 	struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
+ 	u32 temp, usbc_bit = BIT(phy->index * 2);
+-	void *phyctl;
++	void *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
+ 	int i;
+ 
+ 	mutex_lock(&phy_data->mutex);
+ 
+-	if (phy_data->has_a33_phyctl) {
+-		phyctl = phy_data->base + REG_PHYCTL_A33;
++	if (phy_data->cfg->type == sun8i_a33_phy) {
+ 		/* A33 needs us to set phyctl to 0 explicitly */
+ 		writel(0, phyctl);
+-	} else {
+-		phyctl = phy_data->base + REG_PHYCTL_A10;
+ 	}
+ 
+ 	for (i = 0; i < len; i++) {
+@@ -249,7 +258,8 @@ static int sun4i_usb_phy_init(struct phy
+ 	sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+ 
+ 	/* Disconnect threshold adjustment */
+-	sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->disc_thresh, 2);
++	sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
++			    data->cfg->disc_thresh, 2);
+ 
+ 	sun4i_usb_phy_passby(phy, 1);
+ 
+@@ -476,7 +486,7 @@ static struct phy *sun4i_usb_phy_xlate(s
+ {
+ 	struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
+ 
+-	if (args->args[0] >= data->num_phys)
++	if (args->args[0] >= data->cfg->num_phys)
+ 		return ERR_PTR(-ENODEV);
+ 
+ 	return data->phys[args->args[0]].phy;
+@@ -511,7 +521,6 @@ static int sun4i_usb_phy_probe(struct pl
+ 	struct device *dev = &pdev->dev;
+ 	struct device_node *np = dev->of_node;
+ 	struct phy_provider *phy_provider;
+-	bool dedicated_clocks;
+ 	struct resource *res;
+ 	int i, ret;
+ 
+@@ -522,29 +531,9 @@ static int sun4i_usb_phy_probe(struct pl
+ 	mutex_init(&data->mutex);
+ 	INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan);
+ 	dev_set_drvdata(dev, data);
+-
+-	if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
+-	    of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
+-	    of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
+-		data->num_phys = 2;
+-	else
+-		data->num_phys = 3;
+-
+-	if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
+-	    of_device_is_compatible(np, "allwinner,sun7i-a20-usb-phy"))
+-		data->disc_thresh = 2;
+-	else
+-		data->disc_thresh = 3;
+-
+-	if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") ||
+-	    of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
+-	    of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
+-		dedicated_clocks = true;
+-	else
+-		dedicated_clocks = false;
+-
+-	if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
+-		data->has_a33_phyctl = true;
++	data->cfg = of_device_get_match_data(dev);
++	if (!data->cfg)
++		return -EINVAL;
+ 
+ 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+ 	data->base = devm_ioremap_resource(dev, res);
+@@ -590,7 +579,7 @@ static int sun4i_usb_phy_probe(struct pl
+ 		}
+ 	}
+ 
+-	for (i = 0; i < data->num_phys; i++) {
++	for (i = 0; i < data->cfg->num_phys; i++) {
+ 		struct sun4i_usb_phy *phy = data->phys + i;
+ 		char name[16];
+ 
+@@ -602,7 +591,7 @@ static int sun4i_usb_phy_probe(struct pl
+ 			phy->vbus = NULL;
+ 		}
+ 
+-		if (dedicated_clocks)
++		if (data->cfg->dedicated_clocks)
+ 			snprintf(name, sizeof(name), "usb%d_phy", i);
+ 		else
+ 			strlcpy(name, "usb_phy", sizeof(name));
+@@ -689,13 +678,61 @@ static int sun4i_usb_phy_probe(struct pl
+ 	return 0;
+ }
+ 
++static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
++	.num_phys = 3,
++	.type = sun4i_a10_phy,
++	.disc_thresh = 3,
++	.phyctl_offset = REG_PHYCTL_A10,
++	.dedicated_clocks = false,
++};
++
++static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
++	.num_phys = 2,
++	.type = sun4i_a10_phy,
++	.disc_thresh = 2,
++	.phyctl_offset = REG_PHYCTL_A10,
++	.dedicated_clocks = false,
++};
++
++static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
++	.num_phys = 3,
++	.type = sun4i_a10_phy,
++	.disc_thresh = 3,
++	.phyctl_offset = REG_PHYCTL_A10,
++	.dedicated_clocks = true,
++};
++
++static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
++	.num_phys = 3,
++	.type = sun4i_a10_phy,
++	.disc_thresh = 2,
++	.phyctl_offset = REG_PHYCTL_A10,
++	.dedicated_clocks = false,
++};
++
++static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
++	.num_phys = 2,
++	.type = sun4i_a10_phy,
++	.disc_thresh = 3,
++	.phyctl_offset = REG_PHYCTL_A10,
++	.dedicated_clocks = true,
++};
++
++static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
++	.num_phys = 2,
++	.type = sun8i_a33_phy,
++	.disc_thresh = 3,
++	.phyctl_offset = REG_PHYCTL_A33,
++	.dedicated_clocks = true,
++};
++
+ static const struct of_device_id sun4i_usb_phy_of_match[] = {
+-	{ .compatible = "allwinner,sun4i-a10-usb-phy" },
+-	{ .compatible = "allwinner,sun5i-a13-usb-phy" },
+-	{ .compatible = "allwinner,sun6i-a31-usb-phy" },
+-	{ .compatible = "allwinner,sun7i-a20-usb-phy" },
+-	{ .compatible = "allwinner,sun8i-a23-usb-phy" },
+-	{ .compatible = "allwinner,sun8i-a33-usb-phy" },
++	{ .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
++	{ .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
++	{ .compatible = "allwinner,sun6i-a31-usb-phy", .data = &sun6i_a31_cfg },
++	{ .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
++	{ .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
++	{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
+ 	{ },
+ };
+ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
diff --git a/target/linux/sunxi/patches-4.4/106-phy-add-h3-usbphys.patch b/target/linux/sunxi/patches-4.4/106-phy-add-h3-usbphys.patch
new file mode 100644
index 0000000000..33943230e8
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/106-phy-add-h3-usbphys.patch
@@ -0,0 +1,124 @@
+From 317c5224795b41a08ba8c08573d74ba95096faa5 Mon Sep 17 00:00:00 2001
+From: Reinder de Haan <patchesrdh@mveas.com>
+Date: Fri, 11 Dec 2015 16:32:18 +0100
+Subject: [PATCH] phy-sun4i-usb: Add support for the host usb-phys found on the
+ H3 SoC
+
+Note this commit only adds support for phys 1-3, phy 0, the otg phy, is
+not yet (fully) supported after this commit.
+
+Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
+---
+ .../devicetree/bindings/phy/sun4i-usb-phy.txt      |  1 +
+ drivers/phy/phy-sun4i-usb.c                        | 41 +++++++++++++++++-----
+ 2 files changed, 33 insertions(+), 9 deletions(-)
+
+--- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
++++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+@@ -9,6 +9,7 @@ Required properties:
+   * allwinner,sun7i-a20-usb-phy
+   * allwinner,sun8i-a23-usb-phy
+   * allwinner,sun8i-a33-usb-phy
++  * allwinner,sun8i-h3-usb-phy
+ - reg : a list of offset + length pairs
+ - reg-names :
+   * "phy_ctrl"
+--- a/drivers/phy/phy-sun4i-usb.c
++++ b/drivers/phy/phy-sun4i-usb.c
+@@ -47,6 +47,9 @@
+ #define REG_PHYBIST			0x08
+ #define REG_PHYTUNE			0x0c
+ #define REG_PHYCTL_A33			0x10
++#define REG_PHY_UNK_H3			0x20
++
++#define REG_PMU_UNK_H3			0x10
+ 
+ #define PHYCTL_DATA			BIT(7)
+ 
+@@ -80,7 +83,7 @@
+ #define PHY_DISCON_TH_SEL		0x2a
+ #define PHY_SQUELCH_DETECT		0x3c
+ 
+-#define MAX_PHYS			3
++#define MAX_PHYS			4
+ 
+ /*
+  * Note do not raise the debounce time, we must report Vusb high within 100ms
+@@ -92,6 +95,7 @@
+ enum sun4i_usb_phy_type {
+ 	sun4i_a10_phy,
+ 	sun8i_a33_phy,
++	sun8i_h3_phy,
+ };
+ 
+ struct sun4i_usb_phy_cfg {
+@@ -239,6 +243,7 @@ static int sun4i_usb_phy_init(struct phy
+ 	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ 	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+ 	int ret;
++	u32 val;
+ 
+ 	ret = clk_prepare_enable(phy->clk);
+ 	if (ret)
+@@ -250,16 +255,26 @@ static int sun4i_usb_phy_init(struct phy
+ 		return ret;
+ 	}
+ 
+-	/* Enable USB 45 Ohm resistor calibration */
+-	if (phy->index == 0)
+-		sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
+-
+-	/* Adjust PHY's magnitude and rate */
+-	sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+-
+-	/* Disconnect threshold adjustment */
+-	sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
+-			    data->cfg->disc_thresh, 2);
++	if (data->cfg->type == sun8i_h3_phy) {
++		if (phy->index == 0) {
++			val = readl(data->base + REG_PHY_UNK_H3);
++			writel(val & ~1, data->base + REG_PHY_UNK_H3);
++		}
++
++		val = readl(phy->pmu + REG_PMU_UNK_H3);
++		writel(val & ~2, phy->pmu + REG_PMU_UNK_H3);
++	} else {
++		/* Enable USB 45 Ohm resistor calibration */
++		if (phy->index == 0)
++			sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
++
++		/* Adjust PHY's magnitude and rate */
++		sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
++
++		/* Disconnect threshold adjustment */
++		sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
++				    data->cfg->disc_thresh, 2);
++	}
+ 
+ 	sun4i_usb_phy_passby(phy, 1);
+ 
+@@ -726,6 +741,13 @@ static const struct sun4i_usb_phy_cfg su
+ 	.dedicated_clocks = true,
+ };
+ 
++static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
++	.num_phys = 4,
++	.type = sun8i_h3_phy,
++	.disc_thresh = 3,
++	.dedicated_clocks = true,
++};
++
+ static const struct of_device_id sun4i_usb_phy_of_match[] = {
+ 	{ .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
+ 	{ .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
+@@ -733,6 +755,7 @@ static const struct of_device_id sun4i_u
+ 	{ .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
+ 	{ .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
+ 	{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
++	{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
+ 	{ },
+ };
+ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
diff --git a/target/linux/sunxi/patches-4.4/107-clk-sunxi-add-h3-usbphy-clocks.patch b/target/linux/sunxi/patches-4.4/107-clk-sunxi-add-h3-usbphy-clocks.patch
new file mode 100644
index 0000000000..ddd5e978f4
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/107-clk-sunxi-add-h3-usbphy-clocks.patch
@@ -0,0 +1,47 @@
+From 7bec0200ac214b5cba44e2c2c4385815be4b9f00 Mon Sep 17 00:00:00 2001
+From: Reinder de Haan <patchesrdh@mveas.com>
+Date: Sun, 15 Nov 2015 20:46:13 +0100
+Subject: [PATCH] clk: sunxi: Add support for the H3 usb phy clocks
+
+The H3 has a usb-phy clk register which is similar to that of earlier
+SoCs, but with support for a larger number of phys. So we can simply add
+a new set of clk-data and a new compatible and be done with it.
+
+Acked-by: Chen-Yu Tsai <wens@csie.org>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
+ drivers/clk/sunxi/clk-usb.c                       | 12 ++++++++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/Documentation/devicetree/bindings/clock/sunxi.txt
++++ b/Documentation/devicetree/bindings/clock/sunxi.txt
+@@ -68,6 +68,7 @@ Required properties:
+ 	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
+ 	"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
+ 	"allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23
++	"allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3
+ 	"allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
+ 	"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
+ 
+--- a/drivers/clk/sunxi/clk-usb.c
++++ b/drivers/clk/sunxi/clk-usb.c
+@@ -243,3 +243,15 @@ static void __init sun9i_a80_usb_phy_set
+ 	sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
+ }
+ CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
++
++static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
++	.clk_mask =  BIT(19) | BIT(18) | BIT(17) | BIT(16) |
++		     BIT(11) | BIT(10) | BIT(9) | BIT(8),
++	.reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
++};
++
++static void __init sun8i_h3_usb_setup(struct device_node *node)
++{
++	sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
++}
++CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);
diff --git a/target/linux/sunxi/patches-4.4/110-clk-sunxi-add-ve-for-sun457i.patch b/target/linux/sunxi/patches-4.4/110-clk-sunxi-add-ve-for-sun457i.patch
new file mode 100644
index 0000000000..780e034062
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/110-clk-sunxi-add-ve-for-sun457i.patch
@@ -0,0 +1,226 @@
+From 3cdd9f5c4953465abb87ec757159cc0576ae6b0a Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Sat, 5 Dec 2015 21:16:43 +0800
+Subject: [PATCH] clk: sunxi: Add VE (Video Engine) module clock driver for
+ sun[457]i
+
+The video engine has its own special module clock, consisting of a clock
+gate, configurable dividers, and a reset control.
+
+On later (sun[68]i) families, the reset control is moved out of this
+piece of hardware and grouped with reset controls of other peripherals.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Tested-by: Jens Kuske <jenskuske@gmail.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt |   4 +
+ drivers/clk/sunxi/Makefile                        |   1 +
+ drivers/clk/sunxi/clk-a10-ve.c                    | 171 ++++++++++++++++++++++
+ 3 files changed, 176 insertions(+)
+ create mode 100644 drivers/clk/sunxi/clk-a10-ve.c
+
+--- a/Documentation/devicetree/bindings/clock/sunxi.txt
++++ b/Documentation/devicetree/bindings/clock/sunxi.txt
+@@ -71,6 +71,7 @@ Required properties:
+ 	"allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3
+ 	"allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
+ 	"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
++	"allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
+ 
+ Required properties for all clocks:
+ - reg : shall be the control register address for the clock.
+@@ -90,6 +91,9 @@ Required properties for all clocks:
+ And "allwinner,*-usb-clk" clocks also require:
+ - reset-cells : shall be set to 1
+ 
++The "allwinner,sun4i-a10-ve-clk" clock also requires:
++- reset-cells : shall be set to 0
++
+ The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
+ - #reset-cells : shall be set to 1
+ - resets : shall be the reset control phandle for the mmc block.
+--- a/drivers/clk/sunxi/Makefile
++++ b/drivers/clk/sunxi/Makefile
+@@ -7,6 +7,7 @@ obj-y += clk-a10-codec.o
+ obj-y += clk-a10-hosc.o
+ obj-y += clk-a10-mod1.o
+ obj-y += clk-a10-pll2.o
++obj-y += clk-a10-ve.o
+ obj-y += clk-a20-gmac.o
+ obj-y += clk-mod0.o
+ obj-y += clk-simple-gates.o
+--- /dev/null
++++ b/drivers/clk/sunxi/clk-a10-ve.c
+@@ -0,0 +1,171 @@
++/*
++ * Copyright 2015 Chen-Yu Tsai
++ *
++ * Chen-Yu Tsai <wens@csie.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/reset-controller.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++static DEFINE_SPINLOCK(ve_lock);
++
++#define SUN4I_VE_ENABLE		31
++#define SUN4I_VE_DIVIDER_SHIFT	16
++#define SUN4I_VE_DIVIDER_WIDTH	3
++#define SUN4I_VE_RESET		0
++
++/**
++ * sunxi_ve_reset... - reset bit in ve clk registers handling
++ */
++
++struct ve_reset_data {
++	void __iomem			*reg;
++	spinlock_t			*lock;
++	struct reset_controller_dev	rcdev;
++};
++
++static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
++				 unsigned long id)
++{
++	struct ve_reset_data *data = container_of(rcdev,
++						  struct ve_reset_data,
++						  rcdev);
++	unsigned long flags;
++	u32 reg;
++
++	spin_lock_irqsave(data->lock, flags);
++
++	reg = readl(data->reg);
++	writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
++
++	spin_unlock_irqrestore(data->lock, flags);
++
++	return 0;
++}
++
++static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
++				   unsigned long id)
++{
++	struct ve_reset_data *data = container_of(rcdev,
++						  struct ve_reset_data,
++						  rcdev);
++	unsigned long flags;
++	u32 reg;
++
++	spin_lock_irqsave(data->lock, flags);
++
++	reg = readl(data->reg);
++	writel(reg | BIT(SUN4I_VE_RESET), data->reg);
++
++	spin_unlock_irqrestore(data->lock, flags);
++
++	return 0;
++}
++
++static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
++			     const struct of_phandle_args *reset_spec)
++{
++	if (WARN_ON(reset_spec->args_count != 0))
++		return -EINVAL;
++
++	return 0;
++}
++
++static struct reset_control_ops sunxi_ve_reset_ops = {
++	.assert		= sunxi_ve_reset_assert,
++	.deassert	= sunxi_ve_reset_deassert,
++};
++
++static void __init sun4i_ve_clk_setup(struct device_node *node)
++{
++	struct clk *clk;
++	struct clk_divider *div;
++	struct clk_gate *gate;
++	struct ve_reset_data *reset_data;
++	const char *parent;
++	const char *clk_name = node->name;
++	void __iomem *reg;
++	int err;
++
++	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
++	if (IS_ERR(reg))
++		return;
++
++	div = kzalloc(sizeof(*div), GFP_KERNEL);
++	if (!div)
++		goto err_unmap;
++
++	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
++	if (!gate)
++		goto err_free_div;
++
++	of_property_read_string(node, "clock-output-names", &clk_name);
++	parent = of_clk_get_parent_name(node, 0);
++
++	gate->reg = reg;
++	gate->bit_idx = SUN4I_VE_ENABLE;
++	gate->lock = &ve_lock;
++
++	div->reg = reg;
++	div->shift = SUN4I_VE_DIVIDER_SHIFT;
++	div->width = SUN4I_VE_DIVIDER_WIDTH;
++	div->lock = &ve_lock;
++
++	clk = clk_register_composite(NULL, clk_name, &parent, 1,
++				     NULL, NULL,
++				     &div->hw, &clk_divider_ops,
++				     &gate->hw, &clk_gate_ops,
++				     CLK_SET_RATE_PARENT);
++	if (IS_ERR(clk))
++		goto err_free_gate;
++
++	err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
++	if (err)
++		goto err_unregister_clk;
++
++	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
++	if (!reset_data)
++		goto err_del_provider;
++
++	reset_data->reg = reg;
++	reset_data->lock = &ve_lock;
++	reset_data->rcdev.nr_resets = 1;
++	reset_data->rcdev.ops = &sunxi_ve_reset_ops;
++	reset_data->rcdev.of_node = node;
++	reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
++	reset_data->rcdev.of_reset_n_cells = 0;
++	err = reset_controller_register(&reset_data->rcdev);
++	if (err)
++		goto err_free_reset;
++
++	return;
++
++err_free_reset:
++	kfree(reset_data);
++err_del_provider:
++	of_clk_del_provider(node);
++err_unregister_clk:
++	clk_unregister(clk);
++err_free_gate:
++	kfree(gate);
++err_free_div:
++	kfree(div);
++err_unmap:
++	iounmap(reg);
++}
++CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
++	       sun4i_ve_clk_setup);
diff --git a/target/linux/sunxi/patches-4.4/111-1-dt-sun4i-add-ve-clock-module.patch b/target/linux/sunxi/patches-4.4/111-1-dt-sun4i-add-ve-clock-module.patch
new file mode 100644
index 0000000000..cfcf9bfb40
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/111-1-dt-sun4i-add-ve-clock-module.patch
@@ -0,0 +1,32 @@
+From 1ccc4939220cf815c309feddcf82dba260499194 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Sat, 5 Dec 2015 21:16:45 +0800
+Subject: [PATCH] ARM: dts: sun4i: Add VE (Video Engine) module clock node
+
+The video engine has its own module clock, which also includes a
+reset control for it.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -520,6 +520,15 @@
+ 					     "dram_de_mp", "dram_ace";
+ 		};
+ 
++		ve_clk: clk@01c2013c {
++			#clock-cells = <0>;
++			#reset-cells = <0>;
++			compatible = "allwinner,sun4i-a10-ve-clk";
++			reg = <0x01c2013c 0x4>;
++			clocks = <&pll4>;
++			clock-output-names = "ve";
++		};
++
+ 		codec_clk: clk@01c20140 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-codec-clk";
diff --git a/target/linux/sunxi/patches-4.4/111-2-dt-sun7i-add-ve-clock-module.patch b/target/linux/sunxi/patches-4.4/111-2-dt-sun7i-add-ve-clock-module.patch
new file mode 100644
index 0000000000..85d2d31615
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/111-2-dt-sun7i-add-ve-clock-module.patch
@@ -0,0 +1,32 @@
+From f0571ab140723f9a898d4a404118580534dcc468 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Sat, 5 Dec 2015 21:16:47 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add VE (Video Engine) module clock node
+
+The video engine has its own module clock, which also includes a
+reset control for it.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -527,6 +527,15 @@
+ 					     "dram_de_mp", "dram_ace";
+ 		};
+ 
++		ve_clk: clk@01c2013c {
++			#clock-cells = <0>;
++			#reset-cells = <0>;
++			compatible = "allwinner,sun4i-a10-ve-clk";
++			reg = <0x01c2013c 0x4>;
++			clocks = <&pll4>;
++			clock-output-names = "ve";
++		};
++
+ 		codec_clk: clk@01c20140 {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun4i-a10-codec-clk";
diff --git a/target/linux/sunxi/patches-4.4/115-musb-ignore-vbus-errors.patch b/target/linux/sunxi/patches-4.4/115-musb-ignore-vbus-errors.patch
new file mode 100644
index 0000000000..49c7162a6a
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/115-musb-ignore-vbus-errors.patch
@@ -0,0 +1,26 @@
+From fce20ac5d8c98f1a8ea5298051d9fa669e455f04 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 4 Aug 2015 23:22:45 +0200
+Subject: [PATCH] musb: sunxi: Ignore VBus errors in host-only mode
+
+For some unclear reason sometimes we get VBus errors in host-only mode,
+even though we do not have any vbus-detection then. Ignore these.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/usb/musb/sunxi.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/musb/sunxi.c
++++ b/drivers/usb/musb/sunxi.c
+@@ -194,6 +194,10 @@ static irqreturn_t sunxi_musb_interrupt(
+ 		musb_writeb(musb->mregs, MUSB_FADDR, 0);
+ 	}
+ 
++	/*  Ignore Vbus errors when in host only mode */
++	if (musb->port_mode == MUSB_PORT_MODE_HOST)
++		musb->int_usb &= ~MUSB_INTR_VBUSERROR;
++
+ 	musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX);
+ 	if (musb->int_tx)
+ 		writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX);
diff --git a/target/linux/sunxi/patches-4.4/130-pinctrl-sunxi-add-h3-pio.patch b/target/linux/sunxi/patches-4.4/130-pinctrl-sunxi-add-h3-pio.patch
new file mode 100644
index 0000000000..47dce12a9d
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/130-pinctrl-sunxi-add-h3-pio.patch
@@ -0,0 +1,568 @@
+From 03b83828e452418c18ba506e3e02b5deadbb53fa Mon Sep 17 00:00:00 2001
+From: Jens Kuske <jenskuske@gmail.com>
+Date: Tue, 27 Oct 2015 17:50:23 +0100
+Subject: [PATCH] pinctrl: sunxi: Add H3 PIO controller support
+
+The H3 uses the same pin controller as previous SoC's from Allwinner.
+Add support for the pins controlled by the main PIO controller.
+
+Signed-off-by: Jens Kuske <jenskuske@gmail.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ .../bindings/pinctrl/allwinner,sunxi-pinctrl.txt   |   1 +
+ drivers/pinctrl/sunxi/Kconfig                      |   4 +
+ drivers/pinctrl/sunxi/Makefile                     |   1 +
+ drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c           | 516 +++++++++++++++++++++
+ 4 files changed, 522 insertions(+)
+ create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
+
+--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
++++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+@@ -18,6 +18,7 @@ Required properties:
+   "allwinner,sun8i-a23-r-pinctrl"
+   "allwinner,sun8i-a33-pinctrl"
+   "allwinner,sun8i-a83t-pinctrl"
++  "allwinner,sun8i-h3-pinctrl"
+ 
+ - reg: Should contain the register physical address and length for the
+   pin controller.
+--- a/drivers/pinctrl/sunxi/Kconfig
++++ b/drivers/pinctrl/sunxi/Kconfig
+@@ -51,6 +51,10 @@ config PINCTRL_SUN8I_A23_R
+ 	depends on RESET_CONTROLLER
+ 	select PINCTRL_SUNXI_COMMON
+ 
++config PINCTRL_SUN8I_H3
++	def_bool MACH_SUN8I
++	select PINCTRL_SUNXI_COMMON
++
+ config PINCTRL_SUN9I_A80
+ 	def_bool MACH_SUN9I
+ 	select PINCTRL_SUNXI_COMMON
+--- a/drivers/pinctrl/sunxi/Makefile
++++ b/drivers/pinctrl/sunxi/Makefile
+@@ -13,4 +13,5 @@ obj-$(CONFIG_PINCTRL_SUN8I_A23)		+= pinc
+ obj-$(CONFIG_PINCTRL_SUN8I_A23_R)	+= pinctrl-sun8i-a23-r.o
+ obj-$(CONFIG_PINCTRL_SUN8I_A33)		+= pinctrl-sun8i-a33.o
+ obj-$(CONFIG_PINCTRL_SUN8I_A83T)	+= pinctrl-sun8i-a83t.o
++obj-$(CONFIG_PINCTRL_SUN8I_H3)		+= pinctrl-sun8i-h3.o
+ obj-$(CONFIG_PINCTRL_SUN9I_A80)		+= pinctrl-sun9i-a80.o
+--- /dev/null
++++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
+@@ -0,0 +1,516 @@
++/*
++ * Allwinner H3 SoCs pinctrl driver.
++ *
++ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
++ *
++ * Based on pinctrl-sun8i-a23.c, which is:
++ * Copyright (C) 2014 Chen-Yu Tsai <wens@csie.org>
++ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2.  This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/pinctrl.h>
++
++#include "pinctrl-sunxi.h"
++
++static const struct sunxi_desc_pin sun8i_h3_pins[] = {
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart2"),		/* TX */
++		  SUNXI_FUNCTION(0x3, "jtag"),		/* MS */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),	/* PA_EINT0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart2"),		/* RX */
++		  SUNXI_FUNCTION(0x3, "jtag"),		/* CK */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),	/* PA_EINT1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart2"),		/* RTS */
++		  SUNXI_FUNCTION(0x3, "jtag"),		/* DO */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),	/* PA_EINT2 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart2"),		/* CTS */
++		  SUNXI_FUNCTION(0x3, "jtag"),		/* DI */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),	/* PA_EINT3 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart0"),		/* TX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),	/* PA_EINT4 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart0"),		/* RX */
++		  SUNXI_FUNCTION(0x3, "pwm0"),
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),	/* PA_EINT5 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "sim"),		/* PWREN */
++		  SUNXI_FUNCTION(0x3, "pwm1"),
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),	/* PA_EINT6 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "sim"),		/* CLK */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),	/* PA_EINT7 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "sim"),		/* DATA */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),	/* PA_EINT8 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "sim"),		/* RST */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),	/* PA_EINT9 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "sim"),		/* DET */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)),	/* PA_EINT10 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2c0"),		/* SCK */
++		  SUNXI_FUNCTION(0x3, "di"),		/* TX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)),	/* PA_EINT11 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2c0"),		/* SDA */
++		  SUNXI_FUNCTION(0x3, "di"),		/* RX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)),	/* PA_EINT12 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS */
++		  SUNXI_FUNCTION(0x3, "uart3"),		/* TX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)),	/* PA_EINT13 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "spi1"),		/* CLK */
++		  SUNXI_FUNCTION(0x3, "uart3"),		/* RX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)),	/* PA_EINT14 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "spi1"),		/* MOSI */
++		  SUNXI_FUNCTION(0x3, "uart3"),		/* RTS */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)),	/* PA_EINT15 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "spi1"),		/* MISO */
++		  SUNXI_FUNCTION(0x3, "uart3"),		/* CTS */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)),	/* PA_EINT16 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "spdif"),		/* OUT */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)),	/* PA_EINT17 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s0"),		/* SYNC */
++		  SUNXI_FUNCTION(0x3, "i2c1"),		/* SCK */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)),	/* PA_EINT18 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s0"),		/* CLK */
++		  SUNXI_FUNCTION(0x3, "i2c1"),		/* SDA */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)),	/* PA_EINT19 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DOUT */
++		  SUNXI_FUNCTION(0x3, "sim"),		/* VPPEN */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)),	/* PA_EINT20 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DIN */
++		  SUNXI_FUNCTION(0x3, "sim"),		/* VPPPP */
++		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)),	/* PA_EINT21 */
++	/* Hole */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* WE */
++		  SUNXI_FUNCTION(0x3, "spi0")),		/* MOSI */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* ALE */
++		  SUNXI_FUNCTION(0x3, "spi0")),		/* MISO */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* CLE */
++		  SUNXI_FUNCTION(0x3, "spi0")),		/* CLK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* CE1 */
++		  SUNXI_FUNCTION(0x3, "spi0")),		/* CS */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0")),	/* CE0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* RE */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* CLK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* RB0 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* CMD */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0")),	/* RB1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ0 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ1 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ2 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D2 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ3 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D3 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ4 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D4 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ5 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D5 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand"),		/* DQ6 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D6 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand"),		/* DQ7 */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D7 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "nand"),		/* DQS */
++		  SUNXI_FUNCTION(0x3, "mmc2")),		/* RST */
++	/* Hole */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXD3 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXD2 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXD1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXD0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXCK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXCTL/RCDV */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* RXERR */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXD3 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXD2L */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXD1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXD0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* CRS */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXCK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXCTL/TXEN */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* TXERR */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* CLKIN/COL */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* MDC */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "emac")),		/* MDIO */
++	/* Hole */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* PCLK */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* CLK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* MCLK */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* ERR */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* HSYNC */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* SYNC */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* VSYNC */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* DVLD */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D0 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D1 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D2 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D2 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D3 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D3 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D4 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D4 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D5 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D5 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D6 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D6 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* D7 */
++		  SUNXI_FUNCTION(0x3, "ts")),		/* D7 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* SCK */
++		  SUNXI_FUNCTION(0x3, "i2c2")),		/* SCK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "csi"),		/* SDA */
++		  SUNXI_FUNCTION(0x3, "i2c2")),		/* SDA */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out")),
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out")),
++	/* Hole */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D1 */
++		  SUNXI_FUNCTION(0x3, "jtag")),		/* MS */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D0 */
++		  SUNXI_FUNCTION(0x3, "jtag")),		/* DI */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CLK */
++		  SUNXI_FUNCTION(0x3, "uart0")),	/* TX */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CMD */
++		  SUNXI_FUNCTION(0x3, "jtag")),		/* DO */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D3 */
++		  SUNXI_FUNCTION(0x3, "uart0")),	/* RX */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D2 */
++		  SUNXI_FUNCTION(0x3, "jtag")),		/* CK */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc0")),		/* DET */
++	/* Hole */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc1"),		/* CLK */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 0)),	/* PG_EINT0 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc1"),		/* CMD */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 1)),	/* PG_EINT1 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D0 */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 2)),	/* PG_EINT2 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D1 */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 3)),	/* PG_EINT3 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D2 */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 4)),	/* PG_EINT4 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D3 */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 5)),	/* PG_EINT5 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart1"),		/* TX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 6)),	/* PG_EINT6 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart1"),		/* RX */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 7)),	/* PG_EINT7 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart1"),		/* RTS */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 8)),	/* PG_EINT8 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "uart1"),		/* CTS */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 9)),	/* PG_EINT9 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s1"),		/* SYNC */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 10)),	/* PG_EINT10 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s1"),		/* CLK */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 11)),	/* PG_EINT11 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s1"),		/* DOUT */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 12)),	/* PG_EINT12 */
++	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
++		  SUNXI_FUNCTION(0x0, "gpio_in"),
++		  SUNXI_FUNCTION(0x1, "gpio_out"),
++		  SUNXI_FUNCTION(0x2, "i2s1"),		/* DIN */
++		  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 13)),	/* PG_EINT13 */
++};
++
++static const struct sunxi_pinctrl_desc sun8i_h3_pinctrl_data = {
++	.pins = sun8i_h3_pins,
++	.npins = ARRAY_SIZE(sun8i_h3_pins),
++	.irq_banks = 2,
++};
++
++static int sun8i_h3_pinctrl_probe(struct platform_device *pdev)
++{
++	return sunxi_pinctrl_init(pdev,
++				  &sun8i_h3_pinctrl_data);
++}
++
++static const struct of_device_id sun8i_h3_pinctrl_match[] = {
++	{ .compatible = "allwinner,sun8i-h3-pinctrl", },
++	{}
++};
++
++static struct platform_driver sun8i_h3_pinctrl_driver = {
++	.probe	= sun8i_h3_pinctrl_probe,
++	.driver	= {
++		.name		= "sun8i-h3-pinctrl",
++		.of_match_table	= sun8i_h3_pinctrl_match,
++	},
++};
++builtin_platform_driver(sun8i_h3_pinctrl_driver);
diff --git a/target/linux/sunxi/patches-4.4/131-reset-add-h3-resets.patch b/target/linux/sunxi/patches-4.4/131-reset-add-h3-resets.patch
new file mode 100644
index 0000000000..f8e599fbe3
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/131-reset-add-h3-resets.patch
@@ -0,0 +1,92 @@
+From 5f0bb9d0bc545ef53a83f7bd176fdc0736eed8e5 Mon Sep 17 00:00:00 2001
+From: Jens Kuske <jenskuske@gmail.com>
+Date: Tue, 27 Oct 2015 17:50:24 +0100
+Subject: [PATCH] reset: sunxi: Add Allwinner H3 bus resets
+
+The H3 bus resets have some holes between the registers, so we add
+an of_xlate() function to skip them according to the datasheet.
+
+Signed-off-by: Jens Kuske <jenskuske@gmail.com>
+---
+ .../bindings/reset/allwinner,sunxi-clock-reset.txt |  1 +
+ drivers/reset/reset-sunxi.c                        | 30 +++++++++++++++++++---
+ 2 files changed, 28 insertions(+), 3 deletions(-)
+
+--- a/Documentation/devicetree/bindings/reset/allwinner,sunxi-clock-reset.txt
++++ b/Documentation/devicetree/bindings/reset/allwinner,sunxi-clock-reset.txt
+@@ -8,6 +8,7 @@ Required properties:
+ - compatible: Should be one of the following:
+   "allwinner,sun6i-a31-ahb1-reset"
+   "allwinner,sun6i-a31-clock-reset"
++  "allwinner,sun8i-h3-bus-reset"
+ - reg: should be register base and length as documented in the
+   datasheet
+ - #reset-cells: 1, see below
+--- a/drivers/reset/reset-sunxi.c
++++ b/drivers/reset/reset-sunxi.c
+@@ -75,7 +75,9 @@ static struct reset_control_ops sunxi_re
+ 	.deassert	= sunxi_reset_deassert,
+ };
+ 
+-static int sunxi_reset_init(struct device_node *np)
++static int sunxi_reset_init(struct device_node *np,
++			    int (*of_xlate)(struct reset_controller_dev *rcdev,
++				    const struct of_phandle_args *reset_spec))
+ {
+ 	struct sunxi_reset_data *data;
+ 	struct resource res;
+@@ -108,6 +110,7 @@ static int sunxi_reset_init(struct devic
+ 	data->rcdev.nr_resets = size * 32;
+ 	data->rcdev.ops = &sunxi_reset_ops;
+ 	data->rcdev.of_node = np;
++	data->rcdev.of_xlate = of_xlate;
+ 	reset_controller_register(&data->rcdev);
+ 
+ 	return 0;
+@@ -117,6 +120,21 @@ err_alloc:
+ 	return ret;
+ };
+ 
++static int sun8i_h3_bus_reset_xlate(struct reset_controller_dev *rcdev,
++				    const struct of_phandle_args *reset_spec)
++{
++	unsigned int index = reset_spec->args[0];
++
++	if (index < 96)
++		return index;
++	else if (index < 128)
++		return index + 32;
++	else if (index < 160)
++		return index + 64;
++	else
++		return -EINVAL;
++}
++
+ /*
+  * These are the reset controller we need to initialize early on in
+  * our system, before we can even think of using a regular device
+@@ -124,15 +142,21 @@ err_alloc:
+  */
+ static const struct of_device_id sunxi_early_reset_dt_ids[] __initdata = {
+ 	{ .compatible = "allwinner,sun6i-a31-ahb1-reset", },
++	{ .compatible = "allwinner,sun8i-h3-bus-reset", .data = sun8i_h3_bus_reset_xlate, },
+ 	{ /* sentinel */ },
+ };
+ 
+ void __init sun6i_reset_init(void)
+ {
+ 	struct device_node *np;
+-
+-	for_each_matching_node(np, sunxi_early_reset_dt_ids)
+-		sunxi_reset_init(np);
++	const struct of_device_id *match;
++	int (*of_xlate)(struct reset_controller_dev *rcdev,
++			const struct of_phandle_args *reset_spec);
++
++	for_each_matching_node_and_match(np, sunxi_early_reset_dt_ids, &match) {
++		of_xlate = match->data;
++		sunxi_reset_init(np, of_xlate);
++	}
+ }
+ 
+ /*
diff --git a/target/linux/sunxi/patches-4.4/132-dt-sun8i-add-h3-usbclocks.patch b/target/linux/sunxi/patches-4.4/132-dt-sun8i-add-h3-usbclocks.patch
new file mode 100644
index 0000000000..13d44e4468
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/132-dt-sun8i-add-h3-usbclocks.patch
@@ -0,0 +1,34 @@
+From d6a71e3caae07fb2d98e93ee62477273abaceb27 Mon Sep 17 00:00:00 2001
+From: Reinder de Haan <patchesrdh@mveas.com>
+Date: Tue, 3 Nov 2015 15:13:00 +0100
+Subject: [PATCH] ARM: dts: sun8i: Add support for H3 usb clocks
+
+Add a node describing the usb-clks found on the H3.
+
+Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun8i-h3.dtsi | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/arch/arm/boot/dts/sun8i-h3.dtsi
++++ b/arch/arm/boot/dts/sun8i-h3.dtsi
+@@ -269,6 +269,18 @@
+ 					     "mmc2_sample";
+ 		};
+ 
++		usb_clk: clk@01c200cc {
++			#clock-cells = <1>;
++			#reset-cells = <1>;
++			compatible = "allwinner,sun8i-h3-usb-clk";
++			reg = <0x01c200cc 0x4>;
++			clocks = <&osc24M>;
++			clock-output-names = "usb_phy0", "usb_phy1",
++					     "usb_phy2", "usb_phy3",
++					     "usb_ohci0", "usb_ohci1",
++					     "usb_ohci2", "usb_ohci3";
++		};
++
+ 		mbus_clk: clk@01c2015c {
+ 			#clock-cells = <0>;
+ 			compatible = "allwinner,sun8i-a23-mbus-clk";
diff --git a/target/linux/sunxi/patches-4.4/133-dt-sun8i-add-usbphy-usbhost-ctrl-nodes.patch b/target/linux/sunxi/patches-4.4/133-dt-sun8i-add-usbphy-usbhost-ctrl-nodes.patch
new file mode 100644
index 0000000000..78dcaa9fec
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/133-dt-sun8i-add-usbphy-usbhost-ctrl-nodes.patch
@@ -0,0 +1,123 @@
+From 5971a2f283d21eab36d7de24d35301f081f83418 Mon Sep 17 00:00:00 2001
+From: Reinder de Haan <patchesrdh@mveas.com>
+Date: Tue, 3 Nov 2015 15:14:20 +0100
+Subject: [PATCH] ARM: dts: sun8i: Add usbphy and usb host controller nodes
+
+Add nodes describing the H3's usbphy and usb host controller nodes.
+
+Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun8i-h3.dtsi | 101 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 101 insertions(+)
+
+--- a/arch/arm/boot/dts/sun8i-h3.dtsi
++++ b/arch/arm/boot/dts/sun8i-h3.dtsi
+@@ -362,6 +362,107 @@
+ 			#size-cells = <0>;
+ 		};
+ 
++		usbphy: phy@01c19400 {
++			compatible = "allwinner,sun8i-h3-usb-phy";
++			reg = <0x01c19400 0x2c>,
++			      <0x01c1a800 0x4>,
++			      <0x01c1b800 0x4>,
++			      <0x01c1c800 0x4>,
++			      <0x01c1d800 0x4>;
++			reg-names = "phy_ctrl",
++				    "pmu0",
++				    "pmu1",
++				    "pmu2",
++				    "pmu3";
++			clocks = <&usb_clk 8>,
++				 <&usb_clk 9>,
++				 <&usb_clk 10>,
++				 <&usb_clk 11>;
++			clock-names = "usb0_phy",
++				      "usb1_phy",
++				      "usb2_phy",
++				      "usb3_phy";
++			resets = <&usb_clk 0>,
++				 <&usb_clk 1>,
++				 <&usb_clk 2>,
++				 <&usb_clk 3>;
++			reset-names = "usb0_reset",
++				      "usb1_reset",
++				      "usb2_reset",
++				      "usb3_reset";
++			status = "disabled";
++			#phy-cells = <1>;
++		};
++
++		ehci1: usb@01c1b000 {
++			compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
++			reg = <0x01c1b000 0x100>;
++			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 25>, <&bus_gates 29>;
++			resets = <&ahb_rst 25>, <&ahb_rst 29>;
++			phys = <&usbphy 1>;
++			phy-names = "usb";
++			status = "disabled";
++		};
++
++		ohci1: usb@01c1b400 {
++			compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
++			reg = <0x01c1b400 0x100>;
++			interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 29>, <&bus_gates 25>,
++				 <&usb_clk 17>;
++			resets = <&ahb_rst 29>, <&ahb_rst 25>;
++			phys = <&usbphy 1>;
++			phy-names = "usb";
++			status = "disabled";
++		};
++
++		ehci2: usb@01c1c000 {
++			compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
++			reg = <0x01c1c000 0x100>;
++			interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 26>, <&bus_gates 30>;
++			resets = <&ahb_rst 26>, <&ahb_rst 30>;
++			phys = <&usbphy 2>;
++			phy-names = "usb";
++			status = "disabled";
++		};
++
++		ohci2: usb@01c1c400 {
++			compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
++			reg = <0x01c1c400 0x100>;
++			interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 30>, <&bus_gates 26>,
++				 <&usb_clk 18>;
++			resets = <&ahb_rst 30>, <&ahb_rst 26>;
++			phys = <&usbphy 2>;
++			phy-names = "usb";
++			status = "disabled";
++		};
++
++		ehci3: usb@01c1d000 {
++			compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
++			reg = <0x01c1d000 0x100>;
++			interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 27>, <&bus_gates 31>;
++			resets = <&ahb_rst 27>, <&ahb_rst 31>;
++			phys = <&usbphy 3>;
++			phy-names = "usb";
++			status = "disabled";
++		};
++
++		ohci3: usb@01c1d400 {
++			compatible = "allwinner,sun8i-h3-ohci", "generic-ohci";
++			reg = <0x01c1d400 0x100>;
++			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&bus_gates 31>, <&bus_gates 27>,
++				 <&usb_clk 19>;
++			resets = <&ahb_rst 31>, <&ahb_rst 27>;
++			phys = <&usbphy 3>;
++			phy-names = "usb";
++			status = "disabled";
++		};
++
+ 		pio: pinctrl@01c20800 {
+ 			compatible = "allwinner,sun8i-h3-pinctrl";
+ 			reg = <0x01c20800 0x400>;
diff --git a/target/linux/sunxi/patches-4.4/134-dt-sun8i-orangepiplus-enable-usbhost.patch b/target/linux/sunxi/patches-4.4/134-dt-sun8i-orangepiplus-enable-usbhost.patch
new file mode 100644
index 0000000000..733639225c
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/134-dt-sun8i-orangepiplus-enable-usbhost.patch
@@ -0,0 +1,77 @@
+From 37e04fd781d3fc6d08116d38d34ec8124d916441 Mon Sep 17 00:00:00 2001
+From: Jens Kuske <jenskuske@gmail.com>
+Date: Tue, 17 Nov 2015 17:12:07 +0100
+Subject: [PATCH] ARM: dts: sun8i-h3-orangepi-plus: Enable USB host controllers
+
+Enable the 2 USB host controllers used on the Orange Pi Plus
+and add the necessary regulators.
+
+Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Jens Kuske <jenskuske@gmail.com>
+---
+ arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts | 44 ++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+--- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
+@@ -58,6 +58,35 @@
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+ 	};
++
++	reg_usb3_vbus: usb3-vbus {
++		compatible = "regulator-fixed";
++		pinctrl-names = "default";
++		pinctrl-0 = <&usb3_vbus_pin_a>;
++		regulator-name = "usb3-vbus";
++		regulator-min-microvolt = <5000000>;
++		regulator-max-microvolt = <5000000>;
++		regulator-boot-on;
++		enable-active-high;
++		gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
++	};
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&ehci3 {
++	status = "okay";
++};
++
++&pio {
++	usb3_vbus_pin_a: usb3_vbus_pin@0 {
++		allwinner,pins = "PG11";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
+ };
+ 
+ &mmc0 {
+@@ -70,8 +99,23 @@
+ 	status = "okay";
+ };
+ 
++&reg_usb1_vbus {
++	gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
++	status = "okay";
++};
++
+ &uart0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&uart0_pins_a>;
+ 	status = "okay";
+ };
++
++&usb1_vbus_pin_a {
++	allwinner,pins = "PG13";
++};
++
++&usbphy {
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++	usb3_vbus-supply = <&reg_usb3_vbus>;
++	status = "okay";
++};
diff --git a/target/linux/sunxi/patches-4.4/135-clk-sunxi-fix-signedness-bug.patch b/target/linux/sunxi/patches-4.4/135-clk-sunxi-fix-signedness-bug.patch
new file mode 100644
index 0000000000..a4b2af9e5a
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/135-clk-sunxi-fix-signedness-bug.patch
@@ -0,0 +1,25 @@
+From b1558f168f4ef5956913d73fe330c4da85c74349 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Sat, 12 Dec 2015 15:43:46 +0300
+Subject: [PATCH] clk: sunxi: signedness bug in sun8i_h3_bus_gates_init()
+
+"index" needs to be signed for the error handling to work.
+
+Fixes: ab6e23a4e388 ('clk: sunxi: Add H3 clocks support')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/clk/sunxi/clk-sun8i-bus-gates.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/sunxi/clk-sun8i-bus-gates.c
++++ b/drivers/clk/sunxi/clk-sun8i-bus-gates.c
+@@ -40,7 +40,7 @@ static void __init sun8i_h3_bus_gates_in
+ 	const __be32 *p;
+ 	int number, i;
+ 	u8 clk_bit;
+-	u32 index;
++	int index;
+ 
+ 	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ 	if (IS_ERR(reg))
diff --git a/target/linux/sunxi/patches-4.4/140-reset-add-of_reset_control_get_by_index.patch b/target/linux/sunxi/patches-4.4/140-reset-add-of_reset_control_get_by_index.patch
new file mode 100644
index 0000000000..c7e0e2bf64
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/140-reset-add-of_reset_control_get_by_index.patch
@@ -0,0 +1,109 @@
+From b4faa163a7ebae9faab5d0aefe70143e3379178b Mon Sep 17 00:00:00 2001
+From: Vince Hsu <vinceh@nvidia.com>
+Date: Mon, 13 Jul 2015 13:39:39 +0100
+Subject: [PATCH] reset: add of_reset_control_get_by_index()
+
+Add of_reset_control_get_by_index() to allow the drivers to get reset
+device without knowing its name.
+
+Signed-off-by: Vince Hsu <vinceh@nvidia.com>
+[jonathanh@nvidia.com: Updated stub function to return -ENOTSUPP instead
+ of -ENOSYS which should only be used for system calls.]
+Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/reset/core.c  | 40 +++++++++++++++++++++++++++++-----------
+ include/linux/reset.h |  9 +++++++++
+ 2 files changed, 38 insertions(+), 11 deletions(-)
+
+--- a/drivers/reset/core.c
++++ b/drivers/reset/core.c
+@@ -141,27 +141,24 @@ int reset_control_status(struct reset_co
+ EXPORT_SYMBOL_GPL(reset_control_status);
+ 
+ /**
+- * of_reset_control_get - Lookup and obtain a reference to a reset controller.
++ * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
++ * controller by index.
+  * @node: device to be reset by the controller
+- * @id: reset line name
+- *
+- * Returns a struct reset_control or IS_ERR() condition containing errno.
++ * @index: index of the reset controller
+  *
+- * Use of id names is optional.
++ * This is to be used to perform a list of resets for a device or power domain
++ * in whatever order. Returns a struct reset_control or IS_ERR() condition
++ * containing errno.
+  */
+-struct reset_control *of_reset_control_get(struct device_node *node,
+-					   const char *id)
++struct reset_control *of_reset_control_get_by_index(struct device_node *node,
++					   int index)
+ {
+ 	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+ 	struct reset_controller_dev *r, *rcdev;
+ 	struct of_phandle_args args;
+-	int index = 0;
+ 	int rstc_id;
+ 	int ret;
+ 
+-	if (id)
+-		index = of_property_match_string(node,
+-						 "reset-names", id);
+ 	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
+ 					 index, &args);
+ 	if (ret)
+@@ -202,6 +199,27 @@ struct reset_control *of_reset_control_g
+ 
+ 	return rstc;
+ }
++EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
++
++/**
++ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
++ * @node: device to be reset by the controller
++ * @id: reset line name
++ *
++ * Returns a struct reset_control or IS_ERR() condition containing errno.
++ *
++ * Use of id names is optional.
++ */
++struct reset_control *of_reset_control_get(struct device_node *node,
++					   const char *id)
++{
++	int index = 0;
++
++	if (id)
++		index = of_property_match_string(node,
++						 "reset-names", id);
++	return of_reset_control_get_by_index(node, index);
++}
+ EXPORT_SYMBOL_GPL(of_reset_control_get);
+ 
+ /**
+--- a/include/linux/reset.h
++++ b/include/linux/reset.h
+@@ -38,6 +38,9 @@ static inline struct reset_control *devm
+ struct reset_control *of_reset_control_get(struct device_node *node,
+ 					   const char *id);
+ 
++struct reset_control *of_reset_control_get_by_index(
++					struct device_node *node, int index);
++
+ #else
+ 
+ static inline int reset_control_reset(struct reset_control *rstc)
+@@ -106,6 +109,12 @@ static inline struct reset_control *of_r
+ 	return ERR_PTR(-ENOSYS);
+ }
+ 
++static inline struct reset_control *of_reset_control_get_by_index(
++				struct device_node *node, int index)
++{
++	return ERR_PTR(-ENOTSUPP);
++}
++
+ #endif /* CONFIG_RESET_CONTROLLER */
+ 
+ #endif
diff --git a/target/linux/sunxi/patches-4.4/141-reset-fix-of_reset_control_get.patch b/target/linux/sunxi/patches-4.4/141-reset-fix-of_reset_control_get.patch
new file mode 100644
index 0000000000..eeab4972ba
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/141-reset-fix-of_reset_control_get.patch
@@ -0,0 +1,39 @@
+From 7fd7a26b60090a7df15f30ba10b0d39cbbd6a94e Mon Sep 17 00:00:00 2001
+From: Alban Bedel <albeu@free.fr>
+Date: Tue, 1 Sep 2015 17:28:31 +0200
+Subject: [PATCH] reset: Fix of_reset_control_get() for consistent return
+ values
+
+When of_reset_control_get() is called without connection ID it returns
+-ENOENT when the 'resets' property doesn't exists or is an empty entry.
+However when a connection ID is given it returns -EINVAL when the 'resets'
+property doesn't exists or the requested name can't be found. This is
+because the error code returned by of_property_match_string() is just
+passed down as an index to of_parse_phandle_with_args(), which then
+returns -EINVAL.
+
+To get a consistent return value with both code paths we must return
+-ENOENT when of_property_match_string() fails.
+
+Signed-off-by: Alban Bedel <albeu@free.fr>
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/reset/core.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/reset/core.c
++++ b/drivers/reset/core.c
+@@ -215,9 +215,12 @@ struct reset_control *of_reset_control_g
+ {
+ 	int index = 0;
+ 
+-	if (id)
++	if (id) {
+ 		index = of_property_match_string(node,
+ 						 "reset-names", id);
++		if (index < 0)
++			return ERR_PTR(-ENOENT);
++	}
+ 	return of_reset_control_get_by_index(node, index);
+ }
+ EXPORT_SYMBOL_GPL(of_reset_control_get);
diff --git a/target/linux/sunxi/patches-4.4/142-reset-use-ENOTSUPP-instead-of-ENOSYS.patch b/target/linux/sunxi/patches-4.4/142-reset-use-ENOTSUPP-instead-of-ENOSYS.patch
new file mode 100644
index 0000000000..665b15b00a
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/142-reset-use-ENOTSUPP-instead-of-ENOSYS.patch
@@ -0,0 +1,87 @@
+From 5a819175b911ce33f3337e1e069d4bcea1ec4788 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Thu, 29 Oct 2015 09:55:00 +0100
+Subject: [PATCH] reset: use ENOTSUPP instead of ENOSYS
+
+ENOSYS is reserved to report invalid syscalls to userspace.
+Consistently return ENOTSUPP to indicate that the driver doesn't support
+the functionality or the reset framework is not enabled at all.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/reset/core.c  | 8 ++++----
+ include/linux/reset.h | 8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/reset/core.c
++++ b/drivers/reset/core.c
+@@ -95,7 +95,7 @@ int reset_control_reset(struct reset_con
+ 	if (rstc->rcdev->ops->reset)
+ 		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+ 
+-	return -ENOSYS;
++	return -ENOTSUPP;
+ }
+ EXPORT_SYMBOL_GPL(reset_control_reset);
+ 
+@@ -108,7 +108,7 @@ int reset_control_assert(struct reset_co
+ 	if (rstc->rcdev->ops->assert)
+ 		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+ 
+-	return -ENOSYS;
++	return -ENOTSUPP;
+ }
+ EXPORT_SYMBOL_GPL(reset_control_assert);
+ 
+@@ -121,7 +121,7 @@ int reset_control_deassert(struct reset_
+ 	if (rstc->rcdev->ops->deassert)
+ 		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+ 
+-	return -ENOSYS;
++	return -ENOTSUPP;
+ }
+ EXPORT_SYMBOL_GPL(reset_control_deassert);
+ 
+@@ -136,7 +136,7 @@ int reset_control_status(struct reset_co
+ 	if (rstc->rcdev->ops->status)
+ 		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
+ 
+-	return -ENOSYS;
++	return -ENOTSUPP;
+ }
+ EXPORT_SYMBOL_GPL(reset_control_status);
+ 
+--- a/include/linux/reset.h
++++ b/include/linux/reset.h
+@@ -74,7 +74,7 @@ static inline void reset_control_put(str
+ 
+ static inline int device_reset_optional(struct device *dev)
+ {
+-	return -ENOSYS;
++	return -ENOTSUPP;
+ }
+ 
+ static inline struct reset_control *__must_check reset_control_get(
+@@ -94,19 +94,19 @@ static inline struct reset_control *__mu
+ static inline struct reset_control *reset_control_get_optional(
+ 					struct device *dev, const char *id)
+ {
+-	return ERR_PTR(-ENOSYS);
++	return ERR_PTR(-ENOTSUPP);
+ }
+ 
+ static inline struct reset_control *devm_reset_control_get_optional(
+ 					struct device *dev, const char *id)
+ {
+-	return ERR_PTR(-ENOSYS);
++	return ERR_PTR(-ENOTSUPP);
+ }
+ 
+ static inline struct reset_control *of_reset_control_get(
+ 				struct device_node *node, const char *id)
+ {
+-	return ERR_PTR(-ENOSYS);
++	return ERR_PTR(-ENOTSUPP);
+ }
+ 
+ static inline struct reset_control *of_reset_control_get_by_index(
diff --git a/target/linux/sunxi/patches-4.4/143-reset-add-shared-resetcontrol-asserts.patch b/target/linux/sunxi/patches-4.4/143-reset-add-shared-resetcontrol-asserts.patch
new file mode 100644
index 0000000000..e1078e9696
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/143-reset-add-shared-resetcontrol-asserts.patch
@@ -0,0 +1,265 @@
+From d25cfe9b4f9663216ce4e011e3f1e7fa669ab58a Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 27 Nov 2015 21:09:05 +0100
+Subject: [PATCH] reset: Add shared reset_control_[de]assert variants
+
+Add reset_control_deassert_shared / reset_control_assert_shared
+functions which are intended for use by drivers for hw blocks which
+(may) share a reset line with another driver / hw block.
+
+Unlike the regular reset_control_[de]assert functions these functions
+keep track of how often deassert_shared / assert_shared have been called
+and keep the line deasserted as long as deassert has been called more
+times than assert.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+Changes in v2:
+-This is a new patch in v2 of this patch-set
+---
+ drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
+ include/linux/reset-controller.h |   2 +
+ include/linux/reset.h            |   2 +
+ 3 files changed, 116 insertions(+), 9 deletions(-)
+
+--- a/drivers/reset/core.c
++++ b/drivers/reset/core.c
+@@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_lis
+ static LIST_HEAD(reset_controller_list);
+ 
+ /**
++ * struct reset_line - a reset line
++ * @list:         list entry for the reset controllers reset line list
++ * @id:           ID of the reset line in the reset controller device
++ * @refcnt:       Number of reset_control structs referencing this device
++ * @deassert_cnt: Number of times this reset line has been deasserted
++ */
++struct reset_line {
++	struct list_head list;
++	unsigned int id;
++	unsigned int refcnt;
++	unsigned int deassert_cnt;
++};
++
++/**
+  * struct reset_control - a reset control
+  * @rcdev: a pointer to the reset controller device
+  *         this reset control belongs to
+- * @id: ID of the reset controller in the reset
+- *      controller device
++ * @line:  reset line for this reset control
+  */
+ struct reset_control {
+ 	struct reset_controller_dev *rcdev;
++	struct reset_line *line;
+ 	struct device *dev;
+-	unsigned int id;
+ };
+ 
+ /**
+@@ -66,6 +79,8 @@ int reset_controller_register(struct res
+ 		rcdev->of_xlate = of_reset_simple_xlate;
+ 	}
+ 
++	INIT_LIST_HEAD(&rcdev->reset_line_head);
++
+ 	mutex_lock(&reset_controller_list_mutex);
+ 	list_add(&rcdev->list, &reset_controller_list);
+ 	mutex_unlock(&reset_controller_list_mutex);
+@@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unreg
+ int reset_control_reset(struct reset_control *rstc)
+ {
+ 	if (rstc->rcdev->ops->reset)
+-		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
++		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
+ 
+ 	return -ENOTSUPP;
+ }
+@@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
+ int reset_control_assert(struct reset_control *rstc)
+ {
+ 	if (rstc->rcdev->ops->assert)
+-		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
++		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
+ 
+ 	return -ENOTSUPP;
+ }
+@@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
+ int reset_control_deassert(struct reset_control *rstc)
+ {
+ 	if (rstc->rcdev->ops->deassert)
+-		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
++		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
+ 
+ 	return -ENOTSUPP;
+ }
+ EXPORT_SYMBOL_GPL(reset_control_deassert);
+ 
+ /**
++ * reset_control_assert_shared - asserts a shared reset line
++ * @rstc: reset controller
++ *
++ * Assert a shared reset line, this functions decreases the deassert count
++ * of the line by one and asserts it if, and only if, the deassert count
++ * reaches 0.
++ */
++int reset_control_assert_shared(struct reset_control *rstc)
++{
++	if (!rstc->rcdev->ops->assert)
++		return -ENOTSUPP;
++
++	rstc->line->deassert_cnt--;
++	if (rstc->line->deassert_cnt)
++		return 0;
++
++	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
++}
++EXPORT_SYMBOL_GPL(reset_control_assert_shared);
++
++/**
++ * reset_control_deassert_shared - deasserts a shared reset line
++ * @rstc: reset controller
++ *
++ * Assert a shared reset line, this functions increases the deassert count
++ * of the line by one and deasserts the reset line (if it was not already
++ * deasserted).
++ */
++int reset_control_deassert_shared(struct reset_control *rstc)
++{
++	if (!rstc->rcdev->ops->deassert)
++		return -ENOTSUPP;
++
++	rstc->line->deassert_cnt++;
++	if (rstc->line->deassert_cnt != 1)
++		return 0;
++
++	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
++}
++EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
++
++/**
+  * reset_control_status - returns a negative errno if not supported, a
+  * positive value if the reset line is asserted, or zero if the reset
+  * line is not asserted.
+@@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert
+ int reset_control_status(struct reset_control *rstc)
+ {
+ 	if (rstc->rcdev->ops->status)
+-		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
++		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
+ 
+ 	return -ENOTSUPP;
+ }
+ EXPORT_SYMBOL_GPL(reset_control_status);
+ 
++static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
++					 unsigned int index)
++{
++	struct reset_line *line;
++
++	list_for_each_entry(line, &rcdev->reset_line_head, list) {
++		if (line->id == index) {
++			line->refcnt++;
++			return line;
++		}
++	}
++
++	line = kzalloc(sizeof(*line), GFP_KERNEL);
++	if (!line)
++		return NULL;
++
++	list_add(&line->list, &rcdev->reset_line_head);
++	line->id = index;
++	line->refcnt = 1;
++
++	return line;
++}
++
++static void reset_line_put(struct reset_line *line)
++{
++	if (!line)
++		return;
++
++	if (--line->refcnt)
++		return;
++
++	list_del(&line->list);
++	kfree(line);
++}
++
+ /**
+  * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
+  * controller by index.
+@@ -155,6 +247,7 @@ struct reset_control *of_reset_control_g
+ {
+ 	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+ 	struct reset_controller_dev *r, *rcdev;
++	struct reset_line *line;
+ 	struct of_phandle_args args;
+ 	int rstc_id;
+ 	int ret;
+@@ -186,16 +279,22 @@ struct reset_control *of_reset_control_g
+ 	}
+ 
+ 	try_module_get(rcdev->owner);
++
++	/* reset_controller_list_mutex also protects the reset_line list */
++	line = reset_line_get(rcdev, rstc_id);
++
+ 	mutex_unlock(&reset_controller_list_mutex);
+ 
+ 	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+-	if (!rstc) {
++	if (!line || !rstc) {
++		kfree(rstc);
++		reset_line_put(line);
+ 		module_put(rcdev->owner);
+ 		return ERR_PTR(-ENOMEM);
+ 	}
+ 
+ 	rstc->rcdev = rcdev;
+-	rstc->id = rstc_id;
++	rstc->line = line;
+ 
+ 	return rstc;
+ }
+@@ -259,6 +358,10 @@ void reset_control_put(struct reset_cont
+ 	if (IS_ERR(rstc))
+ 		return;
+ 
++	mutex_lock(&reset_controller_list_mutex);
++	reset_line_put(rstc->line);
++	mutex_unlock(&reset_controller_list_mutex);
++
+ 	module_put(rstc->rcdev->owner);
+ 	kfree(rstc);
+ }
+--- a/include/linux/reset-controller.h
++++ b/include/linux/reset-controller.h
+@@ -31,6 +31,7 @@ struct of_phandle_args;
+  * @ops: a pointer to device specific struct reset_control_ops
+  * @owner: kernel module of the reset controller driver
+  * @list: internal list of reset controller devices
++ * @reset_line_head: head of internal list of reset lines
+  * @of_node: corresponding device tree node as phandle target
+  * @of_reset_n_cells: number of cells in reset line specifiers
+  * @of_xlate: translation function to translate from specifier as found in the
+@@ -41,6 +42,7 @@ struct reset_controller_dev {
+ 	struct reset_control_ops *ops;
+ 	struct module *owner;
+ 	struct list_head list;
++	struct list_head reset_line_head;
+ 	struct device_node *of_node;
+ 	int of_reset_n_cells;
+ 	int (*of_xlate)(struct reset_controller_dev *rcdev,
+--- a/include/linux/reset.h
++++ b/include/linux/reset.h
+@@ -11,6 +11,8 @@ int reset_control_reset(struct reset_con
+ int reset_control_assert(struct reset_control *rstc);
+ int reset_control_deassert(struct reset_control *rstc);
+ int reset_control_status(struct reset_control *rstc);
++int reset_control_assert_shared(struct reset_control *rstc);
++int reset_control_deassert_shared(struct reset_control *rstc);
+ 
+ struct reset_control *reset_control_get(struct device *dev, const char *id);
+ void reset_control_put(struct reset_control *rstc);
diff --git a/target/linux/sunxi/patches-4.4/144-usb-ehci-plat-support-multiple-reset-ctrllines.patch b/target/linux/sunxi/patches-4.4/144-usb-ehci-plat-support-multiple-reset-ctrllines.patch
new file mode 100644
index 0000000000..73cd3027bf
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/144-usb-ehci-plat-support-multiple-reset-ctrllines.patch
@@ -0,0 +1,127 @@
+From 957e8f96c67052ca843ea9ffc5223662b973e5de Mon Sep 17 00:00:00 2001
+From: Reinder de Haan <patchesrdh@mveas.com>
+Date: Sun, 15 Nov 2015 14:24:46 +0100
+Subject: [PATCH] ehci-platform: Add support for controllers with multiple
+ reset lines
+
+At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
+reset lines, the controller will not initialize while the reset for
+its companion is still asserted, which means we need to de-assert
+2 resets for the controller to work.
+
+Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+Changes in v2:
+-Use the new reset_control_[de]assert_shared reset-controller functions
+---
+ Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
+ drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
+ 2 files changed, 30 insertions(+), 19 deletions(-)
+
+--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
+@@ -18,7 +18,7 @@ Optional properties:
+  - clocks : a list of phandle + clock specifier pairs
+  - phys : phandle + phy specifier pair
+  - phy-names : "usb"
+- - resets : phandle + reset specifier pair
++ - resets : a list of phandle + reset specifier pairs
+ 
+ Example (Sequoia 440EPx):
+     ehci@e0000300 {
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -39,11 +39,12 @@
+ 
+ #define DRIVER_DESC "EHCI generic platform driver"
+ #define EHCI_MAX_CLKS 3
++#define EHCI_MAX_RESETS 2
+ #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
+ 
+ struct ehci_platform_priv {
+ 	struct clk *clks[EHCI_MAX_CLKS];
+-	struct reset_control *rst;
++	struct reset_control *resets[EHCI_MAX_RESETS];
+ 	struct phy **phys;
+ 	int num_phys;
+ 	bool reset_on_resume;
+@@ -149,7 +150,7 @@ static int ehci_platform_probe(struct pl
+ 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ 	struct ehci_platform_priv *priv;
+ 	struct ehci_hcd *ehci;
+-	int err, irq, phy_num, clk = 0;
++	int err, irq, phy_num, clk = 0, rst = 0;
+ 
+ 	if (usb_disabled())
+ 		return -ENODEV;
+@@ -232,18 +233,24 @@ static int ehci_platform_probe(struct pl
+ 				break;
+ 			}
+ 		}
+-	}
+ 
+-	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
+-	if (IS_ERR(priv->rst)) {
+-		err = PTR_ERR(priv->rst);
+-		if (err == -EPROBE_DEFER)
+-			goto err_put_clks;
+-		priv->rst = NULL;
+-	} else {
+-		err = reset_control_deassert(priv->rst);
+-		if (err)
+-			goto err_put_clks;
++		for (rst = 0; rst < EHCI_MAX_RESETS; rst++) {
++			priv->resets[rst] =
++				of_reset_control_get_by_index(dev->dev.of_node,
++							      rst);
++			if (IS_ERR(priv->resets[rst])) {
++				err = PTR_ERR(priv->resets[rst]);
++				if (err == -EPROBE_DEFER)
++					goto err_reset;
++				priv->resets[rst] = NULL;
++				break;
++			}
++			err = reset_control_deassert_shared(priv->resets[rst]);
++			if (err) {
++				reset_control_put(priv->resets[rst]);
++				goto err_reset;
++			}
++		}
+ 	}
+ 
+ 	if (pdata->big_endian_desc)
+@@ -302,8 +309,10 @@ err_power:
+ 	if (pdata->power_off)
+ 		pdata->power_off(dev);
+ err_reset:
+-	if (priv->rst)
+-		reset_control_assert(priv->rst);
++	while (--rst >= 0) {
++		reset_control_assert_shared(priv->resets[rst]);
++		reset_control_put(priv->resets[rst]);
++	}
+ err_put_clks:
+ 	while (--clk >= 0)
+ 		clk_put(priv->clks[clk]);
+@@ -321,15 +330,17 @@ static int ehci_platform_remove(struct p
+ 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+ 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
+-	int clk;
++	int clk, rst;
+ 
+ 	usb_remove_hcd(hcd);
+ 
+ 	if (pdata->power_off)
+ 		pdata->power_off(dev);
+ 
+-	if (priv->rst)
+-		reset_control_assert(priv->rst);
++	for (rst = 0; rst < EHCI_MAX_RESETS && priv->resets[rst]; rst++) {
++		reset_control_assert_shared(priv->resets[rst]);
++		reset_control_put(priv->resets[rst]);
++	}
+ 
+ 	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
+ 		clk_put(priv->clks[clk]);
diff --git a/target/linux/sunxi/patches-4.4/145-usb-ohci-plat-support-multiple-reset-ctrllines.patch b/target/linux/sunxi/patches-4.4/145-usb-ohci-plat-support-multiple-reset-ctrllines.patch
new file mode 100644
index 0000000000..a25d487aad
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/145-usb-ohci-plat-support-multiple-reset-ctrllines.patch
@@ -0,0 +1,128 @@
+From 5f0c864c1f207dba1db587747a58ec6b362dadf8 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 29 Nov 2015 18:44:14 +0100
+Subject: [PATCH] ohci-platform: Add support for controllers with multiple
+ reset lines
+
+At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
+reset lines, the controller will not initialize while the reset for
+its companion is still asserted, which means we need to de-assert
+2 resets for the controller to work.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+Changes in v2:
+-New patch in v2 of this patch-set, to complement the identical patch for
+ the ehci-platform code
+---
+ Documentation/devicetree/bindings/usb/usb-ohci.txt |  2 +-
+ drivers/usb/host/ohci-platform.c                   | 49 +++++++++++++---------
+ 2 files changed, 30 insertions(+), 21 deletions(-)
+
+--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+@@ -14,7 +14,7 @@ Optional properties:
+ - clocks : a list of phandle + clock specifier pairs
+ - phys : phandle + phy specifier pair
+ - phy-names : "usb"
+-- resets : phandle + reset specifier pair
++- resets : a list of phandle + reset specifier pairs
+ 
+ Example:
+ 
+--- a/drivers/usb/host/ohci-platform.c
++++ b/drivers/usb/host/ohci-platform.c
+@@ -33,11 +33,12 @@
+ 
+ #define DRIVER_DESC "OHCI generic platform driver"
+ #define OHCI_MAX_CLKS 3
++#define OHCI_MAX_RESETS 2
+ #define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
+ 
+ struct ohci_platform_priv {
+ 	struct clk *clks[OHCI_MAX_CLKS];
+-	struct reset_control *rst;
++	struct reset_control *resets[OHCI_MAX_RESETS];
+ 	struct phy **phys;
+ 	int num_phys;
+ };
+@@ -117,7 +118,7 @@ static int ohci_platform_probe(struct pl
+ 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
+ 	struct ohci_platform_priv *priv;
+ 	struct ohci_hcd *ohci;
+-	int err, irq, phy_num, clk = 0;
++	int err, irq, phy_num, clk = 0, rst = 0;
+ 
+ 	if (usb_disabled())
+ 		return -ENODEV;
+@@ -195,19 +196,23 @@ static int ohci_platform_probe(struct pl
+ 				break;
+ 			}
+ 		}
+-
+-	}
+-
+-	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
+-	if (IS_ERR(priv->rst)) {
+-		err = PTR_ERR(priv->rst);
+-		if (err == -EPROBE_DEFER)
+-			goto err_put_clks;
+-		priv->rst = NULL;
+-	} else {
+-		err = reset_control_deassert(priv->rst);
+-		if (err)
+-			goto err_put_clks;
++		for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
++			priv->resets[rst] =
++				of_reset_control_get_by_index(dev->dev.of_node,
++							      rst);
++			if (IS_ERR(priv->resets[rst])) {
++				err = PTR_ERR(priv->resets[rst]);
++				if (err == -EPROBE_DEFER)
++					goto err_reset;
++				priv->resets[rst] = NULL;
++				break;
++			}
++			err = reset_control_deassert_shared(priv->resets[rst]);
++			if (err) {
++				reset_control_put(priv->resets[rst]);
++				goto err_reset;
++			}
++		}
+ 	}
+ 
+ 	if (pdata->big_endian_desc)
+@@ -265,8 +270,10 @@ err_power:
+ 	if (pdata->power_off)
+ 		pdata->power_off(dev);
+ err_reset:
+-	if (priv->rst)
+-		reset_control_assert(priv->rst);
++	while (--rst >= 0) {
++		reset_control_assert_shared(priv->resets[rst]);
++		reset_control_put(priv->resets[rst]);
++	}
+ err_put_clks:
+ 	while (--clk >= 0)
+ 		clk_put(priv->clks[clk]);
+@@ -284,15 +291,17 @@ static int ohci_platform_remove(struct p
+ 	struct usb_hcd *hcd = platform_get_drvdata(dev);
+ 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
+ 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+-	int clk;
++	int clk, rst;
+ 
+ 	usb_remove_hcd(hcd);
+ 
+ 	if (pdata->power_off)
+ 		pdata->power_off(dev);
+ 
+-	if (priv->rst)
+-		reset_control_assert(priv->rst);
++	for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++) {
++		reset_control_assert_shared(priv->resets[rst]);
++		reset_control_put(priv->resets[rst]);
++	}
+ 
+ 	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
+ 		clk_put(priv->clks[clk]);
diff --git a/target/linux/sunxi/patches-4.4/150-dt-sun7i-enable-codec-on-pcduino3.patch b/target/linux/sunxi/patches-4.4/150-dt-sun7i-enable-codec-on-pcduino3.patch
new file mode 100644
index 0000000000..c967ca91a7
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/150-dt-sun7i-enable-codec-on-pcduino3.patch
@@ -0,0 +1,27 @@
+From 5296d8ff65298091758aa8d50d00539cd3781042 Mon Sep 17 00:00:00 2001
+From: Jelle van der Waa <jelle@vdwaa.nl>
+Date: Sun, 9 Aug 2015 18:51:22 +0200
+Subject: [PATCH] ARM: dts: sun7i: Enable audio codec on pcDuino
+
+Enable the on-chip audio codec
+
+Signed-off-by: Jelle van der Waa <jelle@vdwaa.nl>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-pcduino3.dts | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
++++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+@@ -111,6 +111,11 @@
+ 	allwinner,pins = "PH2";
+ };
+ 
++
++&codec {
++	status = "okay";
++};
++
+ &cpu0 {
+ 	cpu-supply = <&reg_dcdc2>;
+ };
diff --git a/target/linux/sunxi/patches-4.4/200-dt-sun7i-add-lamobo-r1.patch b/target/linux/sunxi/patches-4.4/200-dt-sun7i-add-lamobo-r1.patch
new file mode 100644
index 0000000000..b1e00b45ab
--- /dev/null
+++ b/target/linux/sunxi/patches-4.4/200-dt-sun7i-add-lamobo-r1.patch
@@ -0,0 +1,330 @@
+From 46662c86b453d7098ff22d6112d0481f07d523a1 Mon Sep 17 00:00:00 2001
+From: Jelle de Jong <jelledejong@powercraft.nl>
+Date: Sun, 18 Oct 2015 16:34:39 +0200
+Subject: [PATCH] ARM: dts: sun7i: Add dts file for the lamobo-r1 board
+
+The lamobo-r1 board, sometimes called the BPI-R1 but not labelled as such
+on the PCB, is meant as a A20 based router board. As such the board comes
+with a built-in switch chip giving it 5 gigabit ethernet boards, and it
+has a large empty area on the pcb with mounting holes which will fit a
+2.5 inch harddisk. To complete its networking features it has a
+Realtek RTL8192CU for WiFi 802.11 b/g/n.
+
+Signed-off-by: Jelle de Jong <jelledejong@powercraft.nl>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/Makefile                |   1 +
+ arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts | 297 ++++++++++++++++++++++++++++++
+ 2 files changed, 298 insertions(+)
+ create mode 100644 arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -638,6 +638,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
+ 	sun7i-a20-cubietruck.dtb \
+ 	sun7i-a20-hummingbird.dtb \
+ 	sun7i-a20-i12-tvbox.dtb \
++	sun7i-a20-lamobo-r1.dtb \
+ 	sun7i-a20-m3.dtb \
+ 	sun7i-a20-mk808c.dtb \
+ 	sun7i-a20-olimex-som-evb.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
+@@ -0,0 +1,297 @@
++/*
++ * Copyright 2015 Jelle de Jong <jelledejong@powercraft.nl>
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file is distributed in the hope that it will be useful,
++ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *     GNU General Public License for more details.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun7i-a20.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "Lamobo R1";
++	compatible = "lamobo,lamobo-r1", "allwinner,sun7i-a20";
++
++	aliases {
++		serial0 = &uart0;
++		serial1 = &uart3;
++		serial2 = &uart7;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&led_pins_lamobo_r1>;
++
++		green {
++			label = "lamobo_r1:green:usr";
++			gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
++		};
++	};
++
++	reg_gmac_3v3: gmac-3v3 {
++		compatible = "regulator-fixed";
++		pinctrl-names = "default";
++		pinctrl-0 = <&gmac_power_pin_lamobo_r1>;
++		regulator-name = "gmac-3v3";
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		startup-delay-us = <100000>;
++		enable-active-high;
++		gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>; /* PH23 */
++	};
++};
++
++&ahci_pwr_pin_a {
++	allwinner,pins = "PB3";
++};
++
++&ahci {
++	target-supply = <&reg_ahci_5v>;
++	status = "okay";
++};
++
++&cpu0 {
++	cpu-supply = <&reg_dcdc2>;
++	operating-points = <
++		/* kHz	  uV */
++		960000	1400000
++		912000	1400000
++		864000	1350000
++		720000	1250000
++		528000	1150000
++		312000	1100000
++		144000	1050000
++		>;
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&gmac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&gmac_pins_rgmii_a>;
++	phy = <&phy1>;
++	phy-mode = "rgmii";
++	phy-supply = <&reg_gmac_3v3>;
++	status = "okay";
++
++	phy1: ethernet-phy@1 {
++		reg = <1>;
++	};
++};
++
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++
++	axp209: pmic@34 {
++		reg = <0x34>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++	};
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++};
++
++&ir0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ir0_rx_pins_a>;
++	status = "okay";
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_lamobo_r1>;
++	vmmc-supply = <&reg_vcc3v3>;
++	bus-width = <4>;
++	cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
++	cd-inverted;
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++&otg_sram {
++	status = "okay";
++};
++
++&pio {
++	usb0_id_detect_pin: usb0_id_detect_pin@0 {
++		allwinner,pins = "PH4";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	mmc0_cd_pin_lamobo_r1: mmc0_cd_pin@0 {
++		allwinner,pins = "PH10";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	gmac_power_pin_lamobo_r1: gmac_power_pin@0 {
++		allwinner,pins = "PH23";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	led_pins_lamobo_r1: led_pins@0 {
++		allwinner,pins = "PH24";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++#include "axp209.dtsi"
++
++&reg_ahci_5v {
++	gpio = <&pio 1 3 0>; /* PB3 */
++	status = "okay";
++};
++
++&reg_dcdc2 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-cpu";
++};
++
++&reg_dcdc3 {
++	regulator-always-on;
++	regulator-min-microvolt = <1000000>;
++	regulator-max-microvolt = <1400000>;
++	regulator-name = "vdd-int-dll";
++};
++
++&reg_ldo1 {
++	regulator-name = "vdd-rtc";
++};
++
++&reg_ldo2 {
++	regulator-always-on;
++	regulator-min-microvolt = <3000000>;
++	regulator-max-microvolt = <3000000>;
++	regulator-name = "avcc";
++};
++
++&reg_usb0_vbus {
++	status = "okay";
++};
++
++&reg_usb1_vbus {
++	status = "okay";
++};
++
++&reg_usb2_vbus {
++	status = "okay";
++};
++
++&spi0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&spi0_pins_a>,
++		    <&spi0_cs0_pins_a>,
++		    <&spi0_cs1_pins_a>;
++	status = "okay";
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
++&uart3 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart3_pins_b>;
++	status = "okay";
++};
++
++&uart7 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart7_pins_a>;
++	status = "okay";
++};
++
++&usb_otg {
++	dr_mode = "otg";
++	status = "okay";
++};
++
++&usb_power_supply {
++	status = "okay";
++};
++
++&usbphy {
++	pinctrl-names = "default";
++	pinctrl-0 = <&usb0_id_detect_pin>;
++	usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
++	usb0_vbus_power-supply = <&usb_power_supply>;
++	usb0_vbus-supply = <&reg_usb0_vbus>;
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++	usb2_vbus-supply = <&reg_usb2_vbus>;
++	status = "okay";
++};
diff --git a/target/linux/sunxi/profiles/01-default.mk b/target/linux/sunxi/profiles/01-default.mk
new file mode 100644
index 0000000000..7d83440220
--- /dev/null
+++ b/target/linux/sunxi/profiles/01-default.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Default
+  NAME:=Default package set
+  PACKAGES += uboot-sunxi-A13-OLinuXino
+endef
+
+define Profile/Default/Description
+	Default package set compatible with most boards.
+endef
+$(eval $(call Profile,Default))
+
diff --git a/target/linux/sunxi/profiles/a10-olinuxino.mk b/target/linux/sunxi/profiles/a10-olinuxino.mk
new file mode 100644
index 0000000000..b307373250
--- /dev/null
+++ b/target/linux/sunxi/profiles/a10-olinuxino.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/A10-OLinuXino-Lime
+	NAME:=A10 OLinuXino LIME
+	PACKAGES:=\
+		uboot-sunxi-A10-OLinuXino-Lime kmod-ata-core kmod-ata-sunxi \
+		kmod-sun4i-emac kmod-rtc-sunxi
+endef
+
+define Profile/A10-OLinuXino-Lime/Description
+	Package set optimized for the Olimex A10 OLinuXino LIME
+endef
+
+$(eval $(call Profile,A10-OLinuXino-Lime))
diff --git a/target/linux/sunxi/profiles/a13-olimex-som.mk b/target/linux/sunxi/profiles/a13-olimex-som.mk
new file mode 100644
index 0000000000..8dc7339de4
--- /dev/null
+++ b/target/linux/sunxi/profiles/a13-olimex-som.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/OLIMEX_A13_SOM
+	NAME:=Olimex A13 SOM
+	PACKAGES:=\
+		uboot-sunxi-OLIMEX_A13_SOM kmod-rtl8192cu
+endef
+
+define Profile/OLIMEX_A13_SOM/Description
+	Package set optimized for the Olimex A13 SOM
+endef
+
+$(eval $(call Profile,OLIMEX_A13_SOM))
diff --git a/target/linux/sunxi/profiles/a13-olinuxino.mk b/target/linux/sunxi/profiles/a13-olinuxino.mk
new file mode 100644
index 0000000000..0757098ce1
--- /dev/null
+++ b/target/linux/sunxi/profiles/a13-olinuxino.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/A13-OLinuXino
+	NAME:=A13 OLinuXino
+	PACKAGES:=\
+		uboot-sunxi-A13-OLinuXino kmod-rtl8192cu
+endef
+
+define Profile/A13-OLinuXino/Description
+	Package set optimized for the Olimex A13 OLinuXino
+endef
+
+$(eval $(call Profile,A13-OLinuXino))
diff --git a/target/linux/sunxi/profiles/a20-olinuxino.mk b/target/linux/sunxi/profiles/a20-olinuxino.mk
new file mode 100644
index 0000000000..92c9ae56e0
--- /dev/null
+++ b/target/linux/sunxi/profiles/a20-olinuxino.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/A20-OLinuXino-Lime
+	NAME:=A20 OLinuXino Lime
+	PACKAGES:=\
+		uboot-sunxi-A20-OLinuXino-Lime kmod-ata-core kmod-ata-sunxi \
+		kmod-rtc-sunxi
+endef
+
+define Profile/A20-OLinuXino-Lime/Description
+	Package set optimized for the Olimex A20 OLinuXino Lime
+endef
+
+$(eval $(call Profile,A20-OLinuXino-Lime))
+
+
+define Profile/A20-OLinuXino_MICRO
+	NAME:=A20 OLinuXino Micro
+	PACKAGES:=\
+		uboot-sunxi-A20-OLinuXino_MICRO kmod-ata-core kmod-ata-sunxi \
+		kmod-sun4i-emac kmod-rtc-sunxi
+endef
+
+define Profile/A20-OLinuXino_MICRO/Description
+	Package set optimized for the Olimex A20 OLinuXino micro
+endef
+
+$(eval $(call Profile,A20-OLinuXino_MICRO))
diff --git a/target/linux/sunxi/profiles/bananapi.mk b/target/linux/sunxi/profiles/bananapi.mk
new file mode 100644
index 0000000000..96b8aeb920
--- /dev/null
+++ b/target/linux/sunxi/profiles/bananapi.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Bananapi
+	NAME:=Bananapi
+	PACKAGES:=\
+		uboot-sunxi-Bananapi kmod-rtc-sunxi kmod-ata-core kmod-ata-sunxi
+endef
+
+define Profile/Bananapi/Description
+	Package set optimized for the Bananapi
+endef
+
+$(eval $(call Profile,Bananapi))
diff --git a/target/linux/sunxi/profiles/bananapro.mk b/target/linux/sunxi/profiles/bananapro.mk
new file mode 100644
index 0000000000..853b0d4d56
--- /dev/null
+++ b/target/linux/sunxi/profiles/bananapro.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Bananapro
+	NAME:=Bananapro
+	PACKAGES:=\
+		uboot-sunxi-Bananapro kmod-rtc-sunxi kmod-ata-core kmod-ata-sunxi \
+		kmod-brcmfmac
+endef
+
+define Profile/Bananapro/Description
+	Package set optimized for the Bananapro
+endef
+
+$(eval $(call Profile,Bananapro))
diff --git a/target/linux/sunxi/profiles/cubieboard.mk b/target/linux/sunxi/profiles/cubieboard.mk
new file mode 100644
index 0000000000..c95efe6ece
--- /dev/null
+++ b/target/linux/sunxi/profiles/cubieboard.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Cubieboard
+	NAME:=Cubieboard
+	PACKAGES:=\
+		uboot-sunxi-Cubieboard kmod-ata-core kmod-ata-sunxi \
+		kmod-sun4i-emac kmod-rtc-sunxi
+endef
+
+define Profile/Cubieboard/Description
+	Package set optimized for the Cubieboard
+endef
+
+$(eval $(call Profile,Cubieboard))
diff --git a/target/linux/sunxi/profiles/cubieboard2.mk b/target/linux/sunxi/profiles/cubieboard2.mk
new file mode 100644
index 0000000000..cfeb968796
--- /dev/null
+++ b/target/linux/sunxi/profiles/cubieboard2.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Cubieboard2
+	NAME:=Cubieboard2
+	PACKAGES:=\
+		uboot-sunxi-Cubieboard2 kmod-ata-core kmod-ata-sunxi \
+		kmod-sun4i-emac kmod-rtc-sunxi
+endef
+
+define Profile/Cubieboard2/Description
+	Package set optimized for the Cubieboard2
+endef
+
+$(eval $(call Profile,Cubieboard2))
diff --git a/target/linux/sunxi/profiles/cubietruck.mk b/target/linux/sunxi/profiles/cubietruck.mk
new file mode 100644
index 0000000000..3e28334570
--- /dev/null
+++ b/target/linux/sunxi/profiles/cubietruck.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Cubietruck
+	NAME:=Cubietruck
+	PACKAGES:=\
+		uboot-sunxi-Cubietruck kmod-ata-core kmod-ata-sunxi \
+		kmod-rtc-sunxi kmod-brcmfmac
+endef
+
+define Profile/Cubietruck/Description
+	Package set optimized for the Cubietruck
+endef
+
+$(eval $(call Profile,Cubietruck))
diff --git a/target/linux/sunxi/profiles/lamobo-r1.mk b/target/linux/sunxi/profiles/lamobo-r1.mk
new file mode 100644
index 0000000000..4bc1185209
--- /dev/null
+++ b/target/linux/sunxi/profiles/lamobo-r1.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Lamobo_R1
+	NAME:=Lamobo R1
+	PACKAGES:=\
+		uboot-sunxi-Lamobo_R1 kmod-ata-sunxi kmod-rtl8192cu \
+		swconfig wpad-mini
+endef
+
+define Profile/Lamobo_R1/Description
+	Package set optimized for the Lamobo R1
+endef
+
+$(eval $(call Profile,Lamobo_R1))
diff --git a/target/linux/sunxi/profiles/mele_m9.mk b/target/linux/sunxi/profiles/mele_m9.mk
new file mode 100644
index 0000000000..1313da4ce7
--- /dev/null
+++ b/target/linux/sunxi/profiles/mele_m9.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Mele_M9
+	NAME:=Mele_M9
+	PACKAGES:=\
+		uboot-sunxi-Mele_M9 kmod-sun4i-emac kmod-rtc-sunxi kmod-rtl8192cu
+endef
+
+define Profile/Mele_M9/Description
+	Package set optimized for the Mele M9
+endef
+
+$(eval $(call Profile,Mele_M9))
diff --git a/target/linux/sunxi/profiles/orangepi_plus.mk b/target/linux/sunxi/profiles/orangepi_plus.mk
new file mode 100644
index 0000000000..3da9da7fb1
--- /dev/null
+++ b/target/linux/sunxi/profiles/orangepi_plus.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/orangepi_plus
+	NAME:=orangepi_plus
+	PACKAGES:=\
+		kmod-rtc-sunxi uboot-sunxi-orangepi_plus
+endef
+
+define Profile/orangepi_plus/Description
+	Package set optimized for the OrangePi Plus (H3)
+endef
+
+$(eval $(call Profile,orangepi_plus))
diff --git a/target/linux/sunxi/profiles/pcduino.mk b/target/linux/sunxi/profiles/pcduino.mk
new file mode 100644
index 0000000000..3a4202d303
--- /dev/null
+++ b/target/linux/sunxi/profiles/pcduino.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Linksprite_pcDuino
+	NAME:=Linksprite_pcDuino
+	PACKAGES:=\
+		uboot-sunxi-Linksprite_pcDuino kmod-sun4i-emac kmod-rtc-sunxi kmod-rtl8192cu
+endef
+
+define Profile/Linksprite_pcDuino/Description
+	Package set optimized for the Linksprite pcDuino
+endef
+
+$(eval $(call Profile,Linksprite_pcDuino))
diff --git a/target/linux/sunxi/profiles/pcduino3.mk b/target/linux/sunxi/profiles/pcduino3.mk
new file mode 100644
index 0000000000..257d40fbf5
--- /dev/null
+++ b/target/linux/sunxi/profiles/pcduino3.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Linksprite_pcDuino3
+	NAME:=pcDuino3
+	PACKAGES:=\
+		uboot-sunxi-Linksprite_pcDuino3 kmod-sun4i-emac kmod-rtc-sunxi \
+		kmod-ata-core kmod-ata-sunxi kmod-rtl8xxxu rtl8188eu-firmware
+endef
+
+define Profile/Linksprite_pcDuino3/Description
+	Package set optimized for the pcDuino3
+endef
+
+$(eval $(call Profile,Linksprite_pcDuino3))
diff --git a/target/linux/uml/Makefile b/target/linux/uml/Makefile
new file mode 100644
index 0000000000..91631391a7
--- /dev/null
+++ b/target/linux/uml/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/host.mk
+
+# UML only makes sense on linux
+ifeq ($(HOST_OS),Linux)
+
+ARCH:=$(shell uname -m | sed \
+	-e 's/i[3-9]86/i386/' \
+	-e 's/mipsel/mips/' \
+	-e 's/mipseb/mips/' \
+	-e 's/powerpc/ppc/' \
+	-e 's/sh[234]/sh/' \
+	-e 's/armeb/arm/' \
+)
+BOARD:=uml
+BOARDNAME:=User Mode Linux
+FEATURES:=squashfs ext4 audio
+MAINTAINER:=Florian Fainelli <florian@openwrt.org>
+
+KERNEL_PATCHVER:=4.4
+
+include $(INCLUDE_DIR)/target.mk
+
+define Kernel/Patch
+	mkdir -p $(LINUX_DIR)/arch/um/include/uapi
+	mv $(LINUX_DIR)/arch/um/include/asm $(LINUX_DIR)/arch/um/include/uapi/
+	$(Kernel/Patch/Default)
+endef
+
+LINUX_TARGET_CONFIG:=$(CURDIR)/config/$(ARCH)
+
+DEFAULT_PACKAGES += wpad-mini kmod-mac80211-hwsim mkf2fs e2fsprogs
+
+endif
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/uml/README b/target/linux/uml/README
new file mode 100644
index 0000000000..85684ae2bd
--- /dev/null
+++ b/target/linux/uml/README
@@ -0,0 +1,45 @@
+Openwrt inside a user mode linux.  Why would we even want this many ask?
+
+There are potentially a lot of reasons, one obvious one to me, it allows
+folks to 'kick the tires' without actually flashing up any hardware.  It's
+also a great environment for porting over packages, you can get a package
+fully functional in the uclibc root environment inside a uml without actually
+disturbing your 'real router', and then rebuild for a specific target once
+it's fully tested.
+
+This is a first stab at a build that 'just works' and there will be more
+cleanup to come.  The simple directions are:-
+
+Configure for uml target
+Configure with an ext4 root file system
+build it all
+
+In your bin directory you will find a kernel and an ext4 root file system
+when it's finished.  Just run it like this:-
+
+bin/uml/openwrt-uml-vmlinux ubd0=bin/uml/openwrt-uml-ext4.img
+
+The uml will start, and eventually the serial console of the uml will be at your
+console prompt.  If you would like it in xterms, substitute con=xterm and con0=xterm.
+No networking is configured, but, it's a starting point.  The resulting file system
+has just enough free space to start kicking the tires and playing in the world of
+'embedded routers' along with all the resource restrictions that come with that
+world.  
+
+To configure networking and more, refer to the user mode linux documentation online.
+A quick start goes along this line.  install the uml-utilities packages so you have
+the uml switch in and running, then add a command param to your uml start like this
+
+eth0=daemon,00:01:01:01:01:01,unix,/<your uml switch control socket here>
+
+With that in, and uml networking actually functional (can be a challenge at times),
+you should be able to ifconfig the interface and talk to the host side, or, if you
+bridged the uml switch to your host network, you should be able to run udhcp and be
+away with networking off to the world.  Again, if you are unfamiliar with uml and
+uml networking, please read the docs and how-to stuff available on the net.  It does
+take some fiddling to get it started and working right the first time, but after that,
+it opens up a whole new world of virtual machines.
+
+
+
+http://user-mode-linux.sourceforge.net/
diff --git a/target/linux/uml/base-files/etc/inittab b/target/linux/uml/base-files/etc/inittab
new file mode 100644
index 0000000000..22b83aa360
--- /dev/null
+++ b/target/linux/uml/base-files/etc/inittab
@@ -0,0 +1,4 @@
+# Copyright (c) 2013 The Linux Foundation. All rights reserved.
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+tty0::askfirst:/usr/libexec/login.sh
diff --git a/target/linux/uml/config/i386 b/target/linux/uml/config/i386
new file mode 100644
index 0000000000..dd14784f2a
--- /dev/null
+++ b/target/linux/uml/config/i386
@@ -0,0 +1,178 @@
+# CONFIG_3_LEVEL_PGTABLES is not set
+# CONFIG_64BIT is not set
+CONFIG_ARCH_DEFCONFIG="arch/um/configs/i386_defconfig"
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+CONFIG_ARCH_HAS_SC_SIGNALS=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_BLK_DEV_COW_COMMON=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_UBD=y
+CONFIG_BLK_DEV_UBD_SYNC=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CON_CHAN="xterm"
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
+# CONFIG_CRASHLOG is not set
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DNOTIFY=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_EXT4_FS=y
+# CONFIG_F2FS_CHECK_FS is not set
+CONFIG_F2FS_FS=y
+# CONFIG_F2FS_FS_SECURITY is not set
+CONFIG_F2FS_FS_XATTR=y
+CONFIG_F2FS_STAT_FS=y
+CONFIG_FS_MBCACHE=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CPU_DEVICES=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_FUTEX_CMPXCHG=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_UID16=y
+CONFIG_HOSTAUDIO=m
+CONFIG_HOSTFS=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INIT_ENV_ARG_LIMIT=128
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQ_WORK=y
+CONFIG_ISO9660_FS=y
+CONFIG_JBD2=y
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_KALLSYMS=y
+CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M686 is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MATOM is not set
+CONFIG_MCONSOLE=y
+# CONFIG_MCORE2 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MELAN is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MMAPPER is not set
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MPENTIUM4 is not set
+CONFIG_MPENTIUMII=y
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MWINCHIPC6 is not set
+CONFIG_NAMESPACES=y
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_NET_NS is not set
+CONFIG_NLS=y
+# CONFIG_NOCONFIG_CHAN is not set
+CONFIG_NO_DMA=y
+CONFIG_NO_IOMEM=y
+# CONFIG_NSC_GPIO is not set
+CONFIG_NULL_CHAN=y
+# CONFIG_OF is not set
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PORT_CHAN=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PTY_CHAN=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RD_BZIP2=y
+CONFIG_RD_GZIP=y
+CONFIG_RELAY=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCSI_DMA is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_SRCU=y
+CONFIG_SSL=y
+CONFIG_SSL_CHAN="pty"
+CONFIG_STACKTRACE=y
+CONFIG_STATIC_LINK=y
+CONFIG_STDERR_CONSOLE=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_TRACE_IRQFLAGS_SUPPORT is not set
+CONFIG_TTY_CHAN=y
+CONFIG_UML=y
+CONFIG_UML_NET=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_MCAST=y
+# CONFIG_UML_NET_PCAP is not set
+# CONFIG_UML_NET_RANDOM_MAC is not set
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_SLIRP=y
+CONFIG_UML_NET_TUNTAP=y
+# CONFIG_UML_NET_VDE is not set
+CONFIG_UML_RANDOM=y
+CONFIG_UML_SOUND=m
+CONFIG_UML_WATCHDOG=m
+CONFIG_UML_X86=y
+# CONFIG_USER_NS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_X86_32=y
+# CONFIG_X86_64 is not set
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_GENERIC=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_X86_TSC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_XTERM_CHAN=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/uml/config/x86_64 b/target/linux/uml/config/x86_64
new file mode 100644
index 0000000000..342a069684
--- /dev/null
+++ b/target/linux/uml/config/x86_64
@@ -0,0 +1,153 @@
+CONFIG_3_LEVEL_PGTABLES=y
+CONFIG_64BIT=y
+CONFIG_ARCH_DEFCONFIG="arch/um/configs/x86_64_defconfig"
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+# CONFIG_ARCH_HAS_SC_SIGNALS is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+# CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_BLK_DEV_COW_COMMON=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_UBD=y
+CONFIG_BLK_DEV_UBD_SYNC=y
+CONFIG_CON_CHAN="xterm"
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_INTEL=y
+# CONFIG_CRASHLOG is not set
+CONFIG_CRC16=y
+# CONFIG_CRYPTO_AES_X86_64 is not set
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+# CONFIG_CRYPTO_SALSA20_X86_64 is not set
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SKEIN is not set
+# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DNOTIFY=y
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_EXT4_FS=y
+# CONFIG_F2FS_CHECK_FS is not set
+CONFIG_F2FS_FS=y
+# CONFIG_F2FS_FS_SECURITY is not set
+CONFIG_F2FS_FS_XATTR=y
+CONFIG_F2FS_STAT_FS=y
+CONFIG_FS_MBCACHE=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_GENERIC_CPU is not set
+CONFIG_GENERIC_CPU_DEVICES=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_FUTEX_CMPXCHG=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HOSTAUDIO=m
+CONFIG_HOSTFS=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INIT_ENV_ARG_LIMIT=128
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQ_WORK=y
+CONFIG_ISO9660_FS=y
+CONFIG_JBD2=y
+# CONFIG_JFFS2_FS is not set
+CONFIG_KALLSYMS=y
+CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_MATOM is not set
+CONFIG_MCONSOLE=y
+# CONFIG_MCORE2 is not set
+CONFIG_MK8=y
+# CONFIG_MMAPPER is not set
+CONFIG_MODULES_USE_ELF_RELA=y
+# CONFIG_MPSC is not set
+CONFIG_NAMESPACES=y
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_NET_NS is not set
+CONFIG_NLS=y
+# CONFIG_NOCONFIG_CHAN is not set
+CONFIG_NO_DMA=y
+CONFIG_NO_IOMEM=y
+CONFIG_NULL_CHAN=y
+# CONFIG_OF is not set
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PORT_CHAN=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PTY_CHAN=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RD_BZIP2=y
+CONFIG_RD_GZIP=y
+CONFIG_RELAY=y
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCSI_DMA is not set
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_SRCU=y
+CONFIG_SSL=y
+CONFIG_SSL_CHAN="pty"
+CONFIG_STACKTRACE=y
+CONFIG_STATIC_LINK=y
+CONFIG_STDERR_CONSOLE=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_TRACE_IRQFLAGS_SUPPORT is not set
+CONFIG_TTY_CHAN=y
+CONFIG_UML=y
+CONFIG_UML_NET=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_MCAST=y
+# CONFIG_UML_NET_PCAP is not set
+# CONFIG_UML_NET_RANDOM_MAC is not set
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_SLIRP=y
+CONFIG_UML_NET_TUNTAP=y
+# CONFIG_UML_NET_VDE is not set
+CONFIG_UML_RANDOM=y
+CONFIG_UML_SOUND=m
+CONFIG_UML_WATCHDOG=m
+CONFIG_UML_X86=y
+# CONFIG_USER_NS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_X86_32 is not set
+CONFIG_X86_64=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+CONFIG_X86_TSC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_XTERM_CHAN=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/uml/image/Makefile b/target/linux/uml/image/Makefile
new file mode 100644
index 0000000000..8e83bfeecc
--- /dev/null
+++ b/target/linux/uml/image/Makefile
@@ -0,0 +1,24 @@
+# 
+# Copyright (C) 2006-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Image/Prepare
+	cp $(LINUX_DIR)/linux $(KDIR)/vmlinux.elf
+endef
+
+define Image/Build/squashfs
+	dd if=/dev/zero of=$(KDIR)/root.squashfs bs=1024k count=0 seek=$(CONFIG_TARGET_ROOTFS_PARTSIZE)
+endef
+
+define Image/Build
+	$(call Image/Build/$(1))
+	cp $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).img
+	cp $(KDIR)/vmlinux.elf $(BIN_DIR)/$(IMG_PREFIX)-vmlinux
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/uml/patches-4.4/101-mconsole-exec.patch b/target/linux/uml/patches-4.4/101-mconsole-exec.patch
new file mode 100644
index 0000000000..879b106bfa
--- /dev/null
+++ b/target/linux/uml/patches-4.4/101-mconsole-exec.patch
@@ -0,0 +1,211 @@
+#
+# Minimalist mconsole exec patch 
+#
+# 3.10 version (with bit more synchronous behavior) by fingon at iki dot fi
+# Adaptation to kernel 3.3.8 made by David Fernández (david at dit.upm.es) for 
+# Starting point: mconsole-exec-2.6.30.patch for kernel 2.6.30
+# Author of original patch: Paolo Giarrusso, aka Blaisorblade 
+#                           (http://www.user-mode-linux.org/~blaisorblade)
+#
+# Known misfeatures:
+#
+# - If output is too long, blocks (and breaks horribly) 
+# (this misfeature from 3.10 patches, when minimalizing the patch;
+#  workaround: redirect to a shared filesystem if long output is expected)
+#
+# - Nothing useful is done with stdin
+#
+--- a/arch/um/drivers/mconsole.h
++++ b/arch/um/drivers/mconsole.h
+@@ -85,6 +85,7 @@ extern void mconsole_cad(struct mc_reque
+ extern void mconsole_stop(struct mc_request *req);
+ extern void mconsole_go(struct mc_request *req);
+ extern void mconsole_log(struct mc_request *req);
++extern void mconsole_exec(struct mc_request *req);
+ extern void mconsole_proc(struct mc_request *req);
+ extern void mconsole_stack(struct mc_request *req);
+ 
+--- a/arch/um/drivers/mconsole_kern.c
++++ b/arch/um/drivers/mconsole_kern.c
+@@ -4,6 +4,7 @@
+  * Licensed under the GPL
+  */
+ 
++#include "linux/kmod.h"
+ #include <linux/console.h>
+ #include <linux/ctype.h>
+ #include <linux/string.h>
+@@ -24,6 +25,7 @@
+ #include <linux/fs.h>
+ #include <linux/mount.h>
+ #include <linux/file.h>
++#include <linux/completion.h>
+ #include <asm/uaccess.h>
+ #include <asm/switch_to.h>
+ 
+@@ -121,6 +123,59 @@ void mconsole_log(struct mc_request *req
+ 	mconsole_reply(req, "", 0, 0);
+ }
+ 
++void mconsole_exec(struct mc_request *req)
++{
++  struct subprocess_info *sub_info;
++  int res, len;
++  struct file *out;
++  char buf[MCONSOLE_MAX_DATA];
++
++  char *envp[] = {
++    "HOME=/", "TERM=linux",
++    "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
++    NULL
++  };
++  char *argv[] = {
++    "/bin/sh", "-c",
++    req->request.data + strlen("exec "),
++    NULL
++  };
++
++  sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC, NULL, NULL, NULL);
++  if (sub_info == NULL) {
++    mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0);
++    return;
++  }
++  res = call_usermodehelper_stdoutpipe(sub_info, &out);
++  if (res < 0) {
++    kfree(sub_info);
++    mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0);
++    return;
++  }
++
++  res = call_usermodehelper_exec(sub_info, UMH_WAIT_PROC);
++  if (res < 0) {
++    kfree(sub_info);
++    mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0);
++    return;
++  }
++
++  for (;;) {
++    len = out->f_op->read(out, buf, sizeof(buf), &out->f_pos);
++    if (len < 0) {
++      mconsole_reply(req, "reading output failed", 1, 0);
++      break;
++    }
++    if (len == 0)
++      break;
++    mconsole_reply_len(req, buf, len, 0, 1);
++  }
++  fput(out);
++
++  mconsole_reply_len(req, NULL, 0, 0, 0);
++}
++
++
+ void mconsole_proc(struct mc_request *req)
+ {
+ 	struct vfsmount *mnt = task_active_pid_ns(current)->proc_mnt;
+@@ -187,6 +242,7 @@ void mconsole_proc(struct mc_request *re
+     stop - pause the UML; it will do nothing until it receives a 'go' \n\
+     go - continue the UML after a 'stop' \n\
+     log <string> - make UML enter <string> into the kernel log\n\
++    exec <string> - pass <string> to /bin/sh -c synchronously\n\
+     proc <file> - returns the contents of the UML's /proc/<file>\n\
+     stack <pid> - returns the stack of the specified pid\n\
+ "
+--- a/arch/um/drivers/mconsole_user.c
++++ b/arch/um/drivers/mconsole_user.c
+@@ -30,6 +30,7 @@ static struct mconsole_command commands[
+ 	{ "stop", mconsole_stop, MCONSOLE_PROC },
+ 	{ "go", mconsole_go, MCONSOLE_INTR },
+ 	{ "log", mconsole_log, MCONSOLE_INTR },
++	{ "exec", mconsole_exec, MCONSOLE_PROC },
+ 	{ "proc", mconsole_proc, MCONSOLE_PROC },
+ 	{ "stack", mconsole_stack, MCONSOLE_INTR },
+ };
+--- a/arch/um/os-Linux/file.c
++++ b/arch/um/os-Linux/file.c
+@@ -535,6 +535,8 @@ int os_create_unix_socket(const char *fi
+ 
+ 	addr.sun_family = AF_UNIX;
+ 
++	if (len > sizeof(addr.sun_path))
++		len = sizeof(addr.sun_path);
+ 	snprintf(addr.sun_path, len, "%s", file);
+ 
+ 	err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+--- a/include/linux/kmod.h
++++ b/include/linux/kmod.h
+@@ -62,6 +62,7 @@ struct subprocess_info {
+ 	int wait;
+ 	int retval;
+ 	int (*init)(struct subprocess_info *info, struct cred *new);
++	struct file *stdout;
+ 	void (*cleanup)(struct subprocess_info *info);
+ 	void *data;
+ };
+@@ -102,4 +103,6 @@ extern int usermodehelper_read_trylock(v
+ extern long usermodehelper_read_lock_wait(long timeout);
+ extern void usermodehelper_read_unlock(void);
+ 
++int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, struct file **filp);
++
+ #endif /* __LINUX_KMOD_H__ */
+--- a/kernel/kmod.c
++++ b/kernel/kmod.c
+@@ -39,6 +39,7 @@
+ #include <linux/rwsem.h>
+ #include <linux/ptrace.h>
+ #include <linux/async.h>
++#include <linux/pipe_fs_i.h>
+ #include <asm/uaccess.h>
+ 
+ #include <trace/events/module.h>
+@@ -222,6 +223,28 @@ static int call_usermodehelper_exec_asyn
+ 	flush_signal_handlers(current, 1);
+ 	spin_unlock_irq(&current->sighand->siglock);
+ 
++	/* Install output when needed */
++	if (sub_info->stdout) {
++		struct files_struct *f = current->files;
++		struct fdtable *fdt;
++
++		sys_close(1);
++		sys_close(2);
++		get_file(sub_info->stdout);
++		fd_install(1, sub_info->stdout);
++		fd_install(2, sub_info->stdout);
++		spin_lock(&f->file_lock);
++		fdt = files_fdtable(f);
++		__set_bit(1, fdt->open_fds);
++		__clear_bit(1, fdt->close_on_exec);
++		__set_bit(2, fdt->open_fds);
++		__clear_bit(2, fdt->close_on_exec);
++		spin_unlock(&f->file_lock);
++
++		/* disallow core files */
++		current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0};
++	}
++
+ 	/*
+ 	 * Our parent (unbound workqueue) runs with elevated scheduling
+ 	 * priority. Avoid propagating that into the userspace child.
+@@ -540,6 +563,20 @@ struct subprocess_info *call_usermodehel
+ }
+ EXPORT_SYMBOL(call_usermodehelper_setup);
+ 
++int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
++                                 struct file **filp)
++{
++  struct file *f[2];
++
++  if (create_pipe_files(f, 0)<0)
++    return PTR_ERR(f);
++  sub_info->stdout = f[1];
++  *filp = f[0];
++  return 0;
++}
++EXPORT_SYMBOL(call_usermodehelper_stdoutpipe);
++
++
+ /**
+  * call_usermodehelper_exec - start a usermode application
+  * @sub_info: information about the subprocessa
diff --git a/target/linux/uml/patches-4.4/102-pseudo-random-mac.patch b/target/linux/uml/patches-4.4/102-pseudo-random-mac.patch
new file mode 100644
index 0000000000..fc54f603c0
--- /dev/null
+++ b/target/linux/uml/patches-4.4/102-pseudo-random-mac.patch
@@ -0,0 +1,124 @@
+===============================================================================
+
+This patch makes MAC addresses of network interfaces predictable. In
+particular, it adds a small routine that computes MAC addresses of based on
+a SHA1 hash of the virtual machine name and interface ID.
+
+TECHNICAL INFORMATION:
+
+Applies to vanilla kernel 3.9.4.
+
+===============================================================================
+--- a/arch/um/Kconfig.net
++++ b/arch/um/Kconfig.net
+@@ -21,6 +21,19 @@ config UML_NET
+         enable at least one of the following transport options to actually
+         make use of UML networking.
+ 
++config UML_NET_RANDOM_MAC
++	bool "Use random MAC addresses for network interfaces"
++	default n
++	depends on UML_NET
++	help
++        Virtual network devices inside a User-Mode Linux instance must be
++        assigned a MAC (Ethernet) address. If none is specified on the UML
++        command line, one must be automatically computed. If this option is
++        enabled, a randomly generated address is used. Otherwise, if this
++        option is disabled, the address is generated from a SHA1 hash of
++        the umid of the UML instance and the interface name. The latter choice
++        is useful to make MAC addresses predictable.
++
+ config UML_NET_ETHERTAP
+ 	bool "Ethertap transport"
+ 	depends on UML_NET
+--- a/arch/um/drivers/net_kern.c
++++ b/arch/um/drivers/net_kern.c
+@@ -25,6 +25,13 @@
+ #include <net_kern.h>
+ #include <net_user.h>
+ 
++#include <crypto/sha.h>
++#include <linux/string.h>
++#include <linux/crypto.h>
++#include <linux/err.h>
++#include <linux/scatterlist.h>
++#include "os.h"
++
+ #define DRIVER_NAME "uml-netdev"
+ 
+ static DEFINE_SPINLOCK(opened_lock);
+@@ -295,11 +302,47 @@ static void uml_net_user_timer_expire(un
+ #endif
+ }
+ 
++#ifndef CONFIG_UML_NET_RANDOM_MAC
++
++/* Compute a SHA1 hash of the UML instance's id and
++ *  * an interface name. */
++static int compute_hash(const char *umid, const char *ifname, char *hash) {
++	char vmif[1024];
++	struct scatterlist sg;
++	struct crypto_hash *tfm;
++	struct hash_desc desc;
++
++	strcpy (vmif, umid);
++	strcat (vmif, ifname);
++
++	tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
++	if (IS_ERR(tfm))
++		return 1;
++
++	desc.tfm = tfm;
++	desc.flags = 0;
++
++	sg_init_table(&sg, 1);
++	sg_set_buf(&sg, vmif, strlen(vmif));
++
++	if (crypto_hash_digest(&desc, &sg, strlen(vmif), hash)) {
++		crypto_free_hash(tfm);
++		return 1;
++	}
++
++	crypto_free_hash(tfm);
++
++	return 0;
++}
++
++#endif
++
+ static void setup_etheraddr(struct net_device *dev, char *str)
+ {
+ 	unsigned char *addr = dev->dev_addr;
+ 	char *end;
+ 	int i;
++	u8 hash[SHA1_DIGEST_SIZE];
+ 
+ 	if (str == NULL)
+ 		goto random;
+@@ -340,9 +383,26 @@ static void setup_etheraddr(struct net_d
+ 	return;
+ 
+ random:
++#ifdef CONFIG_UML_NET_RANDOM_MAC
+ 	printk(KERN_INFO
+ 	       "Choosing a random ethernet address for device %s\n", dev->name);
+ 	eth_hw_addr_random(dev);
++#else
++	printk(KERN_INFO
++	       "Computing a digest to use as ethernet address for device %s\n", dev->name);
++	if (compute_hash(get_umid(), dev->name, hash)) {
++		printk(KERN_WARNING
++		       "Could not compute digest to use as ethernet address for device %s. "
++		       "Using random address instead.\n", dev->name);
++		random_ether_addr(addr);
++	}
++	else {
++		for (i=0; i < 6; i++)
++			addr[i] = (hash[i] + hash[i+6]) % 0x100;
++	}
++	addr [0] &= 0xfe; /* clear multicast bit */
++	addr [0] |= 0x02; /* set local assignment bit (IEEE802) */
++#endif
+ }
+ 
+ static DEFINE_SPINLOCK(devices_lock);
diff --git a/target/linux/x86/64/config-default b/target/linux/x86/64/config-default
new file mode 100644
index 0000000000..c9f1a11c02
--- /dev/null
+++ b/target/linux/x86/64/config-default
@@ -0,0 +1,271 @@
+CONFIG_64BIT=y
+CONFIG_ACPI=y
+CONFIG_ACPI_AC=y
+CONFIG_ACPI_BATTERY=y
+CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_CMPC is not set
+# CONFIG_ACPI_CONTAINER is not set
+CONFIG_ACPI_CPU_FREQ_PSS=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_DEBUGGER is not set
+# CONFIG_ACPI_DOCK is not set
+# CONFIG_ACPI_EC_DEBUGFS is not set
+CONFIG_ACPI_FAN=y
+CONFIG_ACPI_HOTPLUG_IOAPIC=y
+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
+# CONFIG_ACPI_NFIT is not set
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_PROCESSOR_IDLE=y
+# CONFIG_ACPI_PROCFS_POWER is not set
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
+# CONFIG_ACPI_SBS is not set
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_VIDEO is not set
+# CONFIG_ACPI_WMI is not set
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11"
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+CONFIG_AUDIT_ARCH=y
+# CONFIG_BACKLIGHT_APPLE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_CALGARY_IOMMU=y
+CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y
+CONFIG_CPU_RMAP=y
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRYPTO_AES_X86_64 is not set
+# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set
+# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set
+# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set
+# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set
+# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set
+# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set
+# CONFIG_CRYPTO_CHACHA20_X86_64 is not set
+CONFIG_CRYPTO_CRCT10DIF=y
+# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set
+# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set
+# CONFIG_CRYPTO_POLY1305_X86_64 is not set
+# CONFIG_CRYPTO_SALSA20_X86_64 is not set
+# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set
+# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set
+# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set
+# CONFIG_CRYPTO_SHA1_MB is not set
+# CONFIG_CRYPTO_SHA1_SSSE3 is not set
+# CONFIG_CRYPTO_SHA256_SSSE3 is not set
+# CONFIG_CRYPTO_SHA512_SSSE3 is not set
+# CONFIG_CRYPTO_SKEIN is not set
+# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set
+# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
+# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set
+# CONFIG_EFI is not set
+CONFIG_FB=y
+CONFIG_FB_CMDLINE=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_VESA is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_GART_IOMMU=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CPU=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+# CONFIG_HAVE_AOUT is not set
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_ARCH_SOFT_DIRTY=y
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_FENTRY=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
+CONFIG_HAVE_LIVEPATCH=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HID=y
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+CONFIG_HPET=y
+CONFIG_HPET_MMAP=y
+# CONFIG_HP_ACCEL is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HW_RANDOM_AMD=y
+CONFIG_HW_RANDOM_INTEL=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_HYPERVISOR_GUEST=y
+# CONFIG_I7300_IDLE is not set
+# CONFIG_IA32_EMULATION is not set
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_INTEL_MIC_BUS is not set
+# CONFIG_INTEL_PMC_IPC is not set
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IOMMU_HELPER=y
+# CONFIG_ISCSI_IBFT_FIND is not set
+# CONFIG_ITCO_VENDOR_SUPPORT is not set
+CONFIG_ITCO_WDT=y
+# CONFIG_KVM_DEBUG_FS is not set
+CONFIG_KVM_GUEST=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_LEGACY_VSYSCALL_EMULATE is not set
+# CONFIG_LEGACY_VSYSCALL_NATIVE is not set
+CONFIG_LEGACY_VSYSCALL_NONE=y
+# CONFIG_LIQUIDIO is not set
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LPC_ICH=y
+# CONFIG_MAXSMP is not set
+CONFIG_MEMORY_BALLOON=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_INTEL_LPSS_ACPI is not set
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_RICOH_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PCI=y
+# CONFIG_MMC_SDHCI_PLTFM is not set
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_WBSD is not set
+CONFIG_MODULES_USE_ELF_RELA=y
+# CONFIG_MPSC is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NR_CPUS=8
+# CONFIG_NUMA is not set
+CONFIG_OUTPUT_FORMAT="elf64-x86-64"
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_CLOCK=y
+# CONFIG_PARAVIRT_DEBUG is not set
+CONFIG_PARAVIRT_SPINLOCKS=y
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+CONFIG_PATA_AMD=y
+CONFIG_PATA_ATIIXP=y
+CONFIG_PATA_LEGACY=y
+CONFIG_PATA_MPIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_PLATFORM=y
+CONFIG_PATA_VIA=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_BUS_ADDR_T_64BIT=y
+# CONFIG_PCI_MMCONFIG is not set
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_PHYSICAL_ALIGN=0x1000000
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PMIC_OPREGION is not set
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
+CONFIG_PNP_DEBUG_MESSAGES=y
+# CONFIG_PVPANIC is not set
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RAS=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+# CONFIG_SAMSUNG_Q10 is not set
+CONFIG_SATA_AHCI=y
+# CONFIG_SCIF_BUS is not set
+CONFIG_SCSI_VIRTIO=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SMP=y
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_MANUAL=y
+# CONFIG_SPARSEMEM_VMEMMAP is not set
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+# CONFIG_SURFACE_PRO3_BUTTON is not set
+CONFIG_SWIOTLB=y
+# CONFIG_THUNDER_NIC_BGX is not set
+# CONFIG_THUNDER_NIC_PF is not set
+# CONFIG_THUNDER_NIC_VF is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+CONFIG_TREE_RCU=y
+# CONFIG_UNISYSSPAR is not set
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PCI=y
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PCI=y
+# CONFIG_USB_XHCI_PLATFORM is not set
+CONFIG_VGACON_SOFT_SCROLLBACK=y
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+CONFIG_VIRTIO_NET=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRT_DRIVERS=y
+CONFIG_VMWARE_BALLOON=y
+CONFIG_VMWARE_PVSCSI=y
+CONFIG_VMWARE_VMCI=y
+CONFIG_VMWARE_VMCI_VSOCKETS=y
+CONFIG_VMXNET3=y
+CONFIG_VSOCKETS=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_X86_64=y
+CONFIG_X86_64_SMP=y
+CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_ACPI_CPUFREQ_CPB is not set
+CONFIG_X86_AMD_FREQ_SENSITIVITY=y
+# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_DEV_DMA_OPS=y
+CONFIG_X86_DIRECT_GBPAGES=y
+# CONFIG_X86_INTEL_LPSS is not set
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_PCC_CPUFREQ is not set
+# CONFIG_X86_PMEM_LEGACY is not set
+CONFIG_X86_PM_TIMER=y
+# CONFIG_X86_POWERNOW_K8 is not set
+CONFIG_X86_TSC=y
+# CONFIG_X86_VSYSCALL_EMULATION is not set
+CONFIG_X86_X2APIC=y
+# CONFIG_X86_X32 is not set
+CONFIG_XPS=y
+CONFIG_ZONE_DMA32=y
diff --git a/target/linux/x86/64/profiles/000-Generic.mk b/target/linux/x86/64/profiles/000-Generic.mk
new file mode 100644
index 0000000000..ccd125afa2
--- /dev/null
+++ b/target/linux/x86/64/profiles/000-Generic.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Generic
+  NAME:=Generic
+endef
+
+define Profile/Generic/Description
+	Generic Profile
+endef
+$(eval $(call Profile,Generic))
diff --git a/target/linux/x86/64/target.mk b/target/linux/x86/64/target.mk
new file mode 100644
index 0000000000..a3420b89b2
--- /dev/null
+++ b/target/linux/x86/64/target.mk
@@ -0,0 +1,7 @@
+ARCH:=x86_64
+BOARDNAME:=x86_64
+DEFAULT_PACKAGES += kmod-button-hotplug kmod-e1000e kmod-e1000 kmod-r8169 kmod-igb
+
+define Target/Description
+        Build images for 64 bit systems including virtualized guests.
+endef
diff --git a/target/linux/x86/Makefile b/target/linux/x86/Makefile
new file mode 100644
index 0000000000..d702e4e8a0
--- /dev/null
+++ b/target/linux/x86/Makefile
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=i386
+BOARD:=x86
+BOARDNAME:=x86
+FEATURES:=squashfs ext4 vdi vmdk pcmcia targz fpu
+SUBTARGETS:=generic legacy xen_domu geode 64
+MAINTAINER:=Felix Fietkau <nbd@nbd.name>
+
+KERNEL_PATCHVER:=4.4
+
+KERNELNAME:=bzImage
+
+include $(INCLUDE_DIR)/target.mk
+
+DEFAULT_PACKAGES += partx-utils mkf2fs e2fsprogs
+
+$(eval $(call BuildTarget))
+
+$(eval $(call $(if $(CONFIG_TARGET_ROOTFS_ISO),RequireCommand,Ignore),mkisofs, \
+   	Please install mkisofs. \
+))
diff --git a/target/linux/x86/base-files/etc/inittab b/target/linux/x86/base-files/etc/inittab
new file mode 100644
index 0000000000..d1b5a0fa22
--- /dev/null
+++ b/target/linux/x86/base-files/etc/inittab
@@ -0,0 +1,4 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K shutdown
+ttyS0::askfirst:/usr/libexec/login.sh
+tty1::askfirst:/usr/libexec/login.sh
diff --git a/target/linux/x86/base-files/lib/preinit/15_essential_fs_x86 b/target/linux/x86/base-files/lib/preinit/15_essential_fs_x86
new file mode 100644
index 0000000000..5d5453093f
--- /dev/null
+++ b/target/linux/x86/base-files/lib/preinit/15_essential_fs_x86
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Copyright (C) 2006-2010 OpenWrt.org
+# Copyright (C) 2010 Vertical Communications
+
+do_mount_procfs() {
+	mount -o noatime -t proc none /proc
+}
+
diff --git a/target/linux/x86/base-files/lib/preinit/20_check_iso b/target/linux/x86/base-files/lib/preinit/20_check_iso
new file mode 100644
index 0000000000..beff6eba09
--- /dev/null
+++ b/target/linux/x86/base-files/lib/preinit/20_check_iso
@@ -0,0 +1,5 @@
+check_for_iso() {
+	grep -qE '/dev/root.*iso9660' /proc/mounts && ramoverlay
+}
+
+boot_hook_add preinit_mount_root check_for_iso
diff --git a/target/linux/x86/base-files/lib/preinit/20_sysinfo b/target/linux/x86/base-files/lib/preinit/20_sysinfo
new file mode 100644
index 0000000000..cb63a04014
--- /dev/null
+++ b/target/linux/x86/base-files/lib/preinit/20_sysinfo
@@ -0,0 +1,28 @@
+do_sysinfo_x86() {
+	local vendor product file
+
+	for file in sys_vendor board_vendor; do
+		vendor="$(cat /sys/devices/virtual/dmi/id/$file 2>/dev/null)"
+		[ -n "$vendor" ] && break
+	done
+
+	for file in product_name board_name; do
+		product="$(cat /sys/devices/virtual/dmi/id/$file 2>/dev/null)"
+		[ -n "$product" ] && break
+	done
+
+	[ -n "$vendor" -a -n "$product" ] || return
+
+	mkdir -p /tmp/sysinfo
+
+	echo "$vendor $product" > /tmp/sysinfo/model
+
+	sed -e '
+		y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;
+		s/[^a-z0-9_-]\+/-/g;
+		s/^-//;
+		s/-$//;
+	' /tmp/sysinfo/model > /tmp/sysinfo/board_name
+}
+
+boot_hook_add preinit_main do_sysinfo_x86
diff --git a/target/linux/x86/base-files/lib/preinit/79_move_config b/target/linux/x86/base-files/lib/preinit/79_move_config
new file mode 100644
index 0000000000..5ac81cb90d
--- /dev/null
+++ b/target/linux/x86/base-files/lib/preinit/79_move_config
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Copyright (C) 2012-2015 OpenWrt.org
+
+move_config() {
+	local partdev
+
+	. /lib/upgrade/platform.sh
+
+	if platform_export_bootdevice && platform_export_partdevice partdev 1; then
+		mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
+		mv -f /mnt/sysupgrade.tgz /
+		umount /mnt
+	fi
+}
+
+boot_hook_add preinit_mount_root move_config
+
diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
new file mode 100644
index 0000000000..c8bc3f7f60
--- /dev/null
+++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
@@ -0,0 +1,163 @@
+platform_export_partdevice() {
+	local var="$1" offset="$2"
+	local uevent MAJOR MINOR DEVNAME DEVTYPE
+
+	for uevent in /sys/class/block/*/uevent; do
+		. "$uevent"
+		if [ $BOOTDEV_MAJOR = $MAJOR -a $(($BOOTDEV_MINOR + $offset)) = $MINOR -a -b "/dev/$DEVNAME" ]; then
+			export "$var=$DEVNAME"
+			return 0
+		fi
+	done
+
+	return 1
+}
+
+platform_export_bootdevice() {
+	local cmdline uuid disk uevent
+	local MAJOR MINOR DEVNAME DEVTYPE
+
+	if read cmdline < /proc/cmdline; then
+		case "$cmdline" in
+			*block2mtd=*)
+				disk="${cmdline##*block2mtd=}"
+				disk="${disk%%,*}"
+			;;
+			*root=*)
+				disk="${cmdline##*root=}"
+				disk="${disk%% *}"
+			;;
+		esac
+
+		case "$disk" in
+			PARTUUID=[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]-02)
+				uuid="${disk#PARTUUID=}"
+				uuid="${uuid%-02}"
+				for disk in $(find /dev -type b); do
+					set -- $(dd if=$disk bs=1 skip=440 count=4 2>/dev/null | hexdump -v -e '4/1 "%02x "')
+					if [ "$4$3$2$1" = "$uuid" ]; then
+						uevent="/sys/class/block/${disk##*/}/uevent"
+						break
+					fi
+				done
+			;;
+			/dev/*)
+				uevent="/sys/class/block/${disk##*/}/uevent"
+			;;
+		esac
+
+		if [ -e "$uevent" ]; then
+			. "$uevent"
+
+			export BOOTDEV_MAJOR=$MAJOR
+			export BOOTDEV_MINOR=$MINOR
+
+			return 0
+		fi
+	fi
+
+	return 1
+}
+
+platform_check_image() {
+	[ "$#" -gt 1 ] && return 1
+
+	case "$(get_magic_word "$1")" in
+		eb48|eb63) return 0;;
+		*)
+			echo "Invalid image type"
+			return 1
+		;;
+	esac
+}
+
+platform_copy_config() {
+	local partdev
+
+	if platform_export_partdevice partdev 1; then
+		mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
+		cp -af "$CONF_TAR" /mnt/
+		umount /mnt
+	fi
+}
+
+get_partitions() { # <device> <filename>
+	local disk="$1"
+	local filename="$2"
+
+	if [ -b "$disk" -o -f "$disk" ]; then
+		echo "Reading partition table from $filename..."
+
+		local magic="$(hexdump -v -n 2 -s 0x1FE -e '1/2 "0x%04X"' "$disk")"
+		if [ "$magic" != 0xAA55 ]; then
+			echo "Invalid partition table on $disk"
+			exit
+		fi
+
+		rm -f "/tmp/partmap.$filename"
+
+		local part
+		for part in 1 2 3 4; do
+			set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk")
+
+			local type="$(($1 % 256))"
+			local lba="$(($2))"
+			local num="$(($3))"
+
+			[ $type -gt 0 ] || continue
+
+			printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
+		done
+	fi
+}
+
+platform_do_upgrade() {
+	local diskdev partdev ibs diff
+
+	if platform_export_bootdevice && platform_export_partdevice diskdev 0; then
+		sync
+		if [ "$SAVE_PARTITIONS" = "1" ]; then
+			get_partitions "/dev/$diskdev" bootdisk
+
+			#get block size
+			if [ -f "/sys/block/$diskdev/queue/physical_block_size" ]; then
+				ibs="$(cat "/sys/block/$diskdev/queue/physical_block_size")"
+			else
+				ibs=512
+			fi
+
+			#extract the boot sector from the image
+			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
+
+			get_partitions /tmp/image.bs image
+
+			#compare tables
+			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+			if [ -n "$diff" ]; then
+				echo "Partition layout is changed.  Full image will be written."
+				ask_bool 0 "Abort" && exit
+
+				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+				return 0
+			fi
+
+			#iterate over each partition from the image and write it to the boot disk
+			while read part start size; do
+				if platform_export_partdevice partdev $part; then
+					echo "Writing image to /dev/$partdev..."
+					get_image "$@" | dd of="/dev/$partdev" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
+				else
+					echo "Unable to find partition $part device, skipped."
+				fi
+			done < /tmp/partmap.image
+
+			#copy partition uuid
+			echo "Writing new UUID to /dev/$diskdev..."
+			get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
+		else
+			get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+		fi
+
+		sleep 1
+	fi
+}
diff --git a/target/linux/x86/config-4.4 b/target/linux/x86/config-4.4
new file mode 100644
index 0000000000..894fed09d2
--- /dev/null
+++ b/target/linux/x86/config-4.4
@@ -0,0 +1,450 @@
+# CONFIG_60XX_WDT is not set
+# CONFIG_64BIT is not set
+# CONFIG_ACPI is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIX is not set
+CONFIG_AMD_NB=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_MMIO_FLUSH=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+# CONFIG_ARCH_RANDOM is not set
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT=y
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
+CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
+CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_ATA_PIIX=y
+CONFIG_BINFMT_MISC=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BOUNCE=y
+CONFIG_CLKBLD_I8253=y
+CONFIG_CLKEVT_I8253=y
+CONFIG_CLKSRC_I8253=y
+CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMPAT_VDSO=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+# CONFIG_CPU5_WDT is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_GOV_COMMON=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_AES_586=y
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32_PCLMUL is not set
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CX_ECAT is not set
+CONFIG_DCACHE_WORD_ACCESS=y
+# CONFIG_DCDBAS is not set
+# CONFIG_DEBUG_BOOT_PARAMS is not set
+# CONFIG_DEBUG_ENTRY is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+# CONFIG_DEBUG_TLBFLUSH is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+# CONFIG_DELL_RBU is not set
+CONFIG_DMI=y
+CONFIG_DMIID=y
+CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
+CONFIG_DMI_SYSFS=y
+CONFIG_DNOTIFY=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK_DBGP is not set
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+# CONFIG_EDD is not set
+# CONFIG_EUROTECH_WDT is not set
+CONFIG_EXT4_FS=y
+# CONFIG_F2FS_CHECK_FS is not set
+CONFIG_F2FS_FS=y
+# CONFIG_F2FS_FS_SECURITY is not set
+CONFIG_F2FS_FS_XATTR=y
+CONFIG_F2FS_STAT_FS=y
+# CONFIG_F71808E_WDT is not set
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FS_MBCACHE=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+# CONFIG_GEOS is not set
+CONFIG_GLOB=y
+# CONFIG_GOOGLE_FIRMWARE is not set
+# CONFIG_HANGCHECK_TIMER is not set
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+CONFIG_HAVE_AOUT=y
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ATOMIC_IOMAP=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_COPY_THREAD_TLS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KPROBES_ON_FTRACE=y
+CONFIG_HAVE_KVM=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+# CONFIG_HIGHMEM4G is not set
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_HPET_TIMER=y
+# CONFIG_HP_WATCHDOG is not set
+CONFIG_HT_IRQ=y
+# CONFIG_HUGETLBFS is not set
+CONFIG_HW_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_GEODE=y
+CONFIG_HW_RANDOM_VIA=y
+# CONFIG_HYPERVISOR_GUEST is not set
+CONFIG_HZ_PERIODIC=y
+CONFIG_I8253_LOCK=y
+# CONFIG_I8K is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_IBMASR is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_IE6XX_WDT is not set
+CONFIG_ILLEGAL_POINTER_VALUE=0
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INSTRUCTION_DECODER=y
+# CONFIG_INTEL_PCH_THERMAL is not set
+# CONFIG_INTEL_POWERCLAMP is not set
+# CONFIG_INTEL_SOC_DTS_THERMAL is not set
+# CONFIG_IOMMU_STRESS is not set
+# CONFIG_IOSF_MBI is not set
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+# CONFIG_IO_DELAY_UDELAY is not set
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+# CONFIG_ISA is not set
+CONFIG_ISA_DMA_API=y
+# CONFIG_IT8712F_WDT is not set
+# CONFIG_IT87_WDT is not set
+# CONFIG_ITCO_WDT is not set
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+CONFIG_KEXEC=y
+CONFIG_KEXEC_CORE=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_LEDS_CLEVO_MAIL is not set
+CONFIG_M486=y
+# CONFIG_M586 is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M686 is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_MATOM is not set
+# CONFIG_MCORE2 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MELAN is not set
+# CONFIG_MFD_INTEL_LPSS_PCI is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MICROCODE is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MODIFY_LDT_SYSCALL is not set
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MTD is not set
+CONFIG_MTRR=y
+# CONFIG_MTRR_SANITIZER is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MWINCHIPC6 is not set
+CONFIG_NAMESPACES=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+# CONFIG_NET5501 is not set
+# CONFIG_NET_NS is not set
+CONFIG_NLS=y
+CONFIG_NOHIGHMEM=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NR_CPUS=1
+# CONFIG_NSC_GPIO is not set
+CONFIG_NVRAM=y
+# CONFIG_OF is not set
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+# CONFIG_OLPC is not set
+CONFIG_OPROFILE_NMI_TIMER=y
+# CONFIG_OPTIMIZE_INLINING is not set
+CONFIG_OUTPUT_FORMAT="elf32-i386"
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PC8736x_GPIO is not set
+# CONFIG_PC87413_WDT is not set
+CONFIG_PCI=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_GOANY=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_EVENTS_INTEL_UNCORE=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYSICAL_ALIGN=0x100000
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_PMC_ATOM=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+# CONFIG_PUNIT_ATOM_DEBUG is not set
+CONFIG_RATIONAL=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RD_BZIP2=y
+CONFIG_RD_GZIP=y
+# CONFIG_RELOCATABLE is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SBC7240_WDT is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_SBC_EPX_C3_WATCHDOG is not set
+# CONFIG_SC1200_WDT is not set
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCSI=y
+CONFIG_SCx200=y
+CONFIG_SCx200HR_TIMER=y
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SERIAL_8250_FSL is not set
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SMSC37B787_WDT is not set
+# CONFIG_SMSC_SCH311X_WDT is not set
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SRCU=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+# CONFIG_TELCLOCK is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_TOSHIBA is not set
+CONFIG_UP_LATE_INIT=y
+CONFIG_USB_SUPPORT=y
+# CONFIG_USERIO is not set
+# CONFIG_USER_NS is not set
+CONFIG_USER_STACKTRACE_SUPPORT=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VIA_WDT is not set
+# CONFIG_VM86 is not set
+# CONFIG_VMWARE_VMCI is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_WAFER_WDT is not set
+CONFIG_X86=y
+CONFIG_X86_32=y
+# CONFIG_X86_32_IRIS is not set
+CONFIG_X86_32_LAZY_GS=y
+CONFIG_X86_ALIGNMENT_16=y
+# CONFIG_X86_ANCIENT_MCE is not set
+# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
+# CONFIG_X86_CPUFREQ_NFORCE2 is not set
+# CONFIG_X86_CPUID is not set
+# CONFIG_X86_DEBUG_FPU is not set
+# CONFIG_X86_EXTENDED_PLATFORM is not set
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_FEATURE_NAMES=y
+CONFIG_X86_GENERIC=y
+# CONFIG_X86_GX_SUSPMOD is not set
+# CONFIG_X86_INTEL_MPX is not set
+# CONFIG_X86_INTEL_PSTATE is not set
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_INVD_BUG=y
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_L1_CACHE_SHIFT=6
+# CONFIG_X86_LEGACY_VM86 is not set
+CONFIG_X86_LOCAL_APIC=y
+# CONFIG_X86_LONGRUN is not set
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_AMD=y
+# CONFIG_X86_MCE_INJECT is not set
+CONFIG_X86_MCE_INTEL=y
+CONFIG_X86_MCE_THRESHOLD=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=4
+CONFIG_X86_MPPARSE=y
+CONFIG_X86_MSR=y
+# CONFIG_X86_P4_CLOCKMOD is not set
+# CONFIG_X86_PAE is not set
+CONFIG_X86_PAT=y
+CONFIG_X86_PLATFORM_DEVICES=y
+# CONFIG_X86_POWERNOW_K6 is not set
+# CONFIG_X86_POWERNOW_K7 is not set
+CONFIG_X86_PPRO_FENCE=y
+# CONFIG_X86_PTDUMP is not set
+# CONFIG_X86_PTDUMP_CORE is not set
+# CONFIG_X86_REBOOTFIXUPS is not set
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
+CONFIG_X86_RESERVE_LOW=64
+# CONFIG_X86_SMAP is not set
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+# CONFIG_X86_SPEEDSTEP_ICH is not set
+# CONFIG_X86_SPEEDSTEP_LIB is not set
+# CONFIG_X86_SPEEDSTEP_SMI is not set
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_X86_UP_APIC=y
+CONFIG_X86_UP_IOAPIC=y
+CONFIG_X86_VERBOSE_BOOTUP=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZLIB_INFLATE=y
diff --git a/target/linux/x86/generic/config-default b/target/linux/x86/generic/config-default
new file mode 100644
index 0000000000..bef606935b
--- /dev/null
+++ b/target/linux/x86/generic/config-default
@@ -0,0 +1,345 @@
+# CONFIG_3C515 is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_AC=y
+CONFIG_ACPI_BATTERY=y
+# CONFIG_ACPI_BGRT is not set
+CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_CMPC is not set
+# CONFIG_ACPI_CONTAINER is not set
+CONFIG_ACPI_CPU_FREQ_PSS=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_DEBUGGER is not set
+# CONFIG_ACPI_DOCK is not set
+# CONFIG_ACPI_EC_DEBUGFS is not set
+# CONFIG_ACPI_FAN is not set
+CONFIG_ACPI_HOTPLUG_IOAPIC=y
+# CONFIG_ACPI_I2C_OPREGION is not set
+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
+# CONFIG_ACPI_NFIT is not set
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_PROCESSOR_IDLE=y
+# CONFIG_ACPI_PROCFS_POWER is not set
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
+# CONFIG_ACPI_SBS is not set
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_VIDEO=y
+# CONFIG_ACPI_WMI is not set
+CONFIG_AGP=y
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD64 is not set
+# CONFIG_AGP_ATI is not set
+# CONFIG_AGP_EFFICEON is not set
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_NVIDIA is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_SWORKS is not set
+# CONFIG_AGP_VIA is not set
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_RANDOM=y
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+# CONFIG_BACKLIGHT_APPLE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_COMMON_CLK=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_RMAP=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DRM=y
+CONFIG_DRM_AMDGPU=y
+# CONFIG_DRM_AMDGPU_CIK is not set
+# CONFIG_DRM_AMDGPU_USERPTR is not set
+# CONFIG_DRM_AST is not set
+CONFIG_DRM_BOCHS=y
+CONFIG_DRM_BRIDGE=y
+# CONFIG_DRM_CIRRUS_QEMU is not set
+CONFIG_DRM_FBDEV_EMULATION=y
+# CONFIG_DRM_GMA500 is not set
+# CONFIG_DRM_I2C_ADV7511 is not set
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_NXP_TDA998X is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I810 is not set
+CONFIG_DRM_I915=y
+# CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT is not set
+CONFIG_DRM_KMS_FB_HELPER=y
+CONFIG_DRM_KMS_HELPER=y
+# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_MGAG200 is not set
+CONFIG_DRM_MIPI_DSI=y
+# CONFIG_DRM_NOUVEAU is not set
+CONFIG_DRM_PANEL=y
+# CONFIG_DRM_QXL is not set
+# CONFIG_DRM_R128 is not set
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_RADEON_UMS is not set
+# CONFIG_DRM_RADEON_USERPTR is not set
+# CONFIG_DRM_SAVAGE is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_TTM=y
+# CONFIG_DRM_UDL is not set
+# CONFIG_DRM_VGEM is not set
+# CONFIG_DRM_VIA is not set
+CONFIG_DRM_VIRTIO_GPU=y
+# CONFIG_DRM_VMWGFX is not set
+CONFIG_EARLY_PRINTK_EFI=y
+CONFIG_EFI=y
+CONFIG_EFIVAR_FS=m
+CONFIG_EFI_ESRT=y
+# CONFIG_EFI_FAKE_MEMMAP is not set
+# CONFIG_EFI_PGT_DUMP is not set
+CONFIG_EFI_RUNTIME_MAP=y
+CONFIG_EFI_RUNTIME_WRAPPERS=y
+CONFIG_EFI_STUB=y
+CONFIG_EFI_VARS=y
+# CONFIG_EISA is not set
+# CONFIG_EL3 is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+CONFIG_FB_EFI=y
+# CONFIG_FB_I810 is not set
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_VESA is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+# CONFIG_GPIO_104_IDIO_16 is not set
+CONFIG_GPIO_ACPI=y
+# CONFIG_GPIO_AMDPT is not set
+CONFIG_GPIO_DEVRES=y
+# CONFIG_GPIO_F7188X is not set
+# CONFIG_GPIO_INTEL_MID is not set
+# CONFIG_GPIO_IT87 is not set
+# CONFIG_GPIO_LYNXPOINT is not set
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
+CONFIG_HAVE_KVM_EVENTFD=y
+CONFIG_HAVE_KVM_IRQCHIP=y
+CONFIG_HAVE_KVM_IRQFD=y
+CONFIG_HAVE_KVM_IRQ_BYPASS=y
+CONFIG_HAVE_KVM_IRQ_ROUTING=y
+CONFIG_HAVE_KVM_MSI=y
+CONFIG_HDMI=y
+CONFIG_HID=y
+CONFIG_HID_BATTERY_STRENGTH=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HPET=y
+CONFIG_HPET_MMAP=y
+# CONFIG_HP_ACCEL is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HWMON=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INTEL_GTT=y
+CONFIG_INTEL_IDLE=y
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_INTEL_PMC_IPC is not set
+CONFIG_INTERVAL_TREE=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_IRQ_BYPASS_MANAGER=y
+CONFIG_ISA=y
+CONFIG_ISAPNP=y
+# CONFIG_ISCSI_IBFT_FIND is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+CONFIG_KVM=y
+CONFIG_KVM_AMD=y
+CONFIG_KVM_APIC_ARCHITECTURE=y
+CONFIG_KVM_ASYNC_PF=y
+# CONFIG_KVM_DEBUG_FS is not set
+CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
+CONFIG_KVM_GUEST=y
+CONFIG_KVM_INTEL=y
+CONFIG_KVM_MMIO=y
+CONFIG_KVM_VFIO=y
+# CONFIG_LANCE is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_LGUEST is not set
+# CONFIG_LGUEST_GUEST is not set
+CONFIG_LOCK_SPIN_ON_OWNER=y
+# CONFIG_M486 is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_MEMORY_BALLOON=y
+CONFIG_MFD_CORE=y
+CONFIG_MFD_INTEL_LPSS=y
+CONFIG_MFD_INTEL_LPSS_ACPI=y
+# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
+# CONFIG_MIXCOMWD is not set
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_RICOH_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PCI=y
+# CONFIG_MMC_SDHCI_PLTFM is not set
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_WBSD is not set
+CONFIG_MMU_NOTIFIER=y
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_CYAPA is not set
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+# CONFIG_MOUSE_PS2_CYPRESS is not set
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_VMMOUSE is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_MPENTIUM4=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NO_HZ=y
+CONFIG_NR_CPUS=4
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_CLOCK=y
+# CONFIG_PARAVIRT_DEBUG is not set
+CONFIG_PARAVIRT_SPINLOCKS=y
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+CONFIG_PATA_AMD=y
+CONFIG_PATA_ATIIXP=y
+CONFIG_PATA_LEGACY=y
+CONFIG_PATA_MPIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_PLATFORM=y
+CONFIG_PATA_SC1200=y
+CONFIG_PATA_VIA=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_MMCONFIG=y
+# CONFIG_PCWATCHDOG is not set
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_BAYTRAIL=y
+CONFIG_PINCTRL_BROXTON=y
+CONFIG_PINCTRL_CHERRYVIEW=y
+CONFIG_PINCTRL_INTEL=y
+CONFIG_PINCTRL_SUNRISEPOINT=y
+# CONFIG_PMIC_OPREGION is not set
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
+# CONFIG_PNPBIOS is not set
+CONFIG_PNP_DEBUG_MESSAGES=y
+CONFIG_PREEMPT_NOTIFIERS=y
+# CONFIG_PVPANIC is not set
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+# CONFIG_RANDOMIZE_BASE is not set
+CONFIG_RAS=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RELOCATABLE=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+# CONFIG_SAMSUNG_Q10 is not set
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_VIA=y
+CONFIG_SCHED_INFO=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SMP=y
+# CONFIG_SURFACE_PRO3_BUTTON is not set
+CONFIG_SWIOTLB=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+# CONFIG_TASK_XACCT is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+CONFIG_TREE_RCU=y
+CONFIG_UCS2_STRING=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USER_RETURN_NOTIFIER=y
+CONFIG_VGACON_SOFT_SCROLLBACK=y
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
+CONFIG_VHOST=y
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+CONFIG_VHOST_NET=y
+CONFIG_VHOST_RING=y
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_MMIO=y
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+CONFIG_VIRTIO_NET=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTUALIZATION=y
+# CONFIG_WDT is not set
+CONFIG_X86_32_SMP=y
+CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_ACPI_CPUFREQ_CPB is not set
+CONFIG_X86_AMD_FREQ_SENSITIVITY=y
+# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
+# CONFIG_X86_BIGSMP is not set
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_DEBUGCTLMSR=y
+# CONFIG_X86_E_POWERSAVER is not set
+CONFIG_X86_INTEL_LPSS=y
+CONFIG_X86_INTEL_PSTATE=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=7
+# CONFIG_X86_LONGHAUL is not set
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_X86_NEED_RELOCS=y
+CONFIG_X86_PAE=y
+# CONFIG_X86_PCC_CPUFREQ is not set
+# CONFIG_X86_PMEM_LEGACY is not set
+CONFIG_X86_PM_TIMER=y
+# CONFIG_X86_POWERNOW_K8 is not set
+CONFIG_X86_TSC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_XPS=y
diff --git a/target/linux/x86/generic/profiles/000-Generic.mk b/target/linux/x86/generic/profiles/000-Generic.mk
new file mode 100644
index 0000000000..90f989a91d
--- /dev/null
+++ b/target/linux/x86/generic/profiles/000-Generic.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Generic
+  NAME:=Generic
+  PACKAGES:=kmod-3c59x kmod-e100 kmod-e1000 kmod-natsemi kmod-ne2k-pci \
+	kmod-pcnet32 kmod-8139too kmod-r8169 kmod-sis900 kmod-tg3 \
+	kmod-via-rhine kmod-via-velocity
+endef
+
+define Profile/Generic/Description
+	Generic Profile
+endef
+$(eval $(call Profile,Generic))
diff --git a/target/linux/x86/generic/target.mk b/target/linux/x86/generic/target.mk
new file mode 100644
index 0000000000..90586f56d6
--- /dev/null
+++ b/target/linux/x86/generic/target.mk
@@ -0,0 +1,11 @@
+BOARDNAME:=Generic
+CPU_TYPE :=pentium4
+FEATURES += audio pci pcie usb
+DEFAULT_PACKAGES += kmod-button-hotplug
+
+define Target/Description
+	Build firmware images for modern x86 based boards with CPUs
+	supporting at least the Intel Pentium 4 instruction set with
+	MMX, SSE and SSE2.
+endef
+
diff --git a/target/linux/x86/geode/config-default b/target/linux/x86/geode/config-default
new file mode 100644
index 0000000000..fdfa9b412f
--- /dev/null
+++ b/target/linux/x86/geode/config-default
@@ -0,0 +1,76 @@
+# CONFIG_3C515 is not set
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
+CONFIG_8139TOO_8129=y
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_ALIX=y
+# CONFIG_ATA_PIIX is not set
+CONFIG_CS5535_CLOCK_EVENT_SRC=y
+CONFIG_CS5535_MFGPT=y
+CONFIG_CS5535_MFGPT_DEFAULT_IRQ=7
+# CONFIG_EISA is not set
+# CONFIG_EL3 is not set
+CONFIG_GEODE_WDT=y
+CONFIG_GEOS=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_104_IDIO_16 is not set
+CONFIG_GPIO_CS5535=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_GPIO_F7188X is not set
+# CONFIG_GPIO_INTEL_MID is not set
+# CONFIG_GPIO_IT87 is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HWMON=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_ALGOPCA=y
+CONFIG_I2C_ALGOPCF=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_ISA=y
+# CONFIG_LANCE is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_M486 is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_MFD_CORE=y
+CONFIG_MFD_CS5535=y
+CONFIG_MGEODEGX1=y
+# CONFIG_MIXCOMWD is not set
+CONFIG_NATSEMI=y
+CONFIG_NET5501=y
+CONFIG_NLS=y
+CONFIG_NSC_GPIO=y
+CONFIG_PATA_CS5520=y
+CONFIG_PATA_CS5530=y
+CONFIG_PATA_CS5535=y
+CONFIG_PATA_CS5536=y
+CONFIG_PATA_SC1200=y
+CONFIG_PC8736x_GPIO=y
+CONFIG_PCI_LABEL=y
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_PNP is not set
+CONFIG_SC1200_WDT=y
+CONFIG_SCx200_ACB=y
+CONFIG_SCx200_WDT=y
+CONFIG_SENSORS_LM90=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PCI=y
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+# CONFIG_USB_UHCI_HCD is not set
+CONFIG_VGACON_SOFT_SCROLLBACK=y
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
+CONFIG_VIA_RHINE=y
+CONFIG_VIA_RHINE_MMIO=y
+# CONFIG_WDT is not set
+CONFIG_X86_CPUID=y
+CONFIG_X86_DEBUGCTLMSR=y
+# CONFIG_X86_MCE is not set
+CONFIG_X86_REBOOTFIXUPS=y
+CONFIG_X86_TSC=y
diff --git a/target/linux/x86/geode/target.mk b/target/linux/x86/geode/target.mk
new file mode 100644
index 0000000000..d98adac5b5
--- /dev/null
+++ b/target/linux/x86/geode/target.mk
@@ -0,0 +1,14 @@
+BOARDNAME:=AMD Geode based systems
+FEATURES:=squashfs ext4 pci usb gpio
+DEFAULT_PACKAGES += \
+			kmod-crypto-hw-geode kmod-crypto-cbc \
+			kmod-ath5k kmod-ath9k \
+			kmod-button-hotplug \
+			kmod-ledtrig-heartbeat kmod-ledtrig-gpio \
+			kmod-ledtrig-netdev hwclock wpad-mini
+
+CPU_TYPE := geode
+
+define Target/Description
+	Build firmware images for AMD Geode GX/LX based systems (net5501, alix, geos)
+endef
diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile
new file mode 100644
index 0000000000..99887cb32b
--- /dev/null
+++ b/target/linux/x86/image/Makefile
@@ -0,0 +1,194 @@
+# 
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+export PATH=$(TARGET_PATH):/sbin
+
+GRUB2_MODULES = biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga
+GRUB2_MODULES_ISO = biosdisk boot chain configfile iso9660 linux ls part_msdos reboot serial vga
+GRUB_TERMINALS =
+GRUB_SERIAL_CONFIG =
+GRUB_TERMINAL_CONFIG =
+GRUB_CONSOLE_CMDLINE =
+GRUB_ROOT = hd0,msdos1
+
+USE_ATKBD = generic 64
+
+ifneq ($(strip $(foreach subtarget,$(USE_ATKBD),$(CONFIG_TARGET_x86_$(subtarget)))),)
+  GRUB2_MODULES += at_keyboard
+  GRUB2_MODULES_ISO += at_keyboard
+endif
+
+ifneq ($(CONFIG_GRUB_CONSOLE),)
+  GRUB_CONSOLE_CMDLINE += console=tty0
+  GRUB_TERMINALS += console
+endif
+
+GRUB_SERIAL:=$(call qstrip,$(CONFIG_GRUB_SERIAL))
+
+ifneq ($(GRUB_SERIAL),)
+  GRUB_CONSOLE_CMDLINE += console=$(GRUB_SERIAL),$(CONFIG_GRUB_BAUDRATE)n8
+  GRUB_SERIAL_CONFIG := serial --unit=0 --speed=$(CONFIG_GRUB_BAUDRATE) --word=8 --parity=no --stop=1 --rtscts=off
+  GRUB_TERMINALS += serial
+endif
+
+ifneq ($(GRUB_TERMINALS),)
+  GRUB_TERMINAL_CONFIG := terminal_input $(GRUB_TERMINALS); terminal_output $(GRUB_TERMINALS)
+endif
+
+SIGNATURE:=$(shell perl -e 'printf("%08x", rand(0xFFFFFFFF))')
+ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME))
+ROOTPART:=$(if $(ROOTPART),$(ROOTPART),PARTUUID=$(SIGNATURE)-02)
+
+GRUB_TIMEOUT:=$(call qstrip,$(CONFIG_GRUB_TIMEOUT))
+
+ifneq ($(CONFIG_TARGET_x86_xen_domu),)
+  GRUB_ROOT = xen/xvda,msdos1
+endif
+
+ifneq ($(CONFIG_GRUB_IMAGES),)
+
+  BOOTOPTS:=$(call qstrip,$(CONFIG_GRUB_BOOTOPTS))
+
+  define Image/cmdline/ext4
+    root=$(ROOTPART) rootfstype=ext4 rootwait
+  endef
+
+  define Image/cmdline/squashfs
+    root=$(ROOTPART) rootfstype=squashfs rootwait
+  endef
+
+  define Image/Build/grub2
+	# left here because the image builder doesnt need these
+	$(INSTALL_DIR) $(KDIR)/root.grub/boot/grub $(KDIR)/grub2
+	$(CP) $(KDIR)/bzImage $(KDIR)/root.grub/boot/vmlinuz
+	grub-mkimage \
+		-d $(STAGING_DIR_HOST)/lib/grub/i386-pc \
+		-o $(KDIR)/grub2/core.img \
+		-O i386-pc \
+		-c ./grub-early.cfg \
+		$(GRUB2_MODULES)
+	$(CP) $(STAGING_DIR_HOST)/lib/grub/i386-pc/*.img $(KDIR)/grub2/
+	echo '(hd0) $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img' > $(KDIR)/grub2/device.map
+	sed \
+		-e 's#@SERIAL_CONFIG@#$(strip $(GRUB_SERIAL_CONFIG))#g' \
+		-e 's#@TERMINAL_CONFIG@#$(strip $(GRUB_TERMINAL_CONFIG))#g' \
+		-e 's#@CMDLINE@#$(strip $(call Image/cmdline/$(1)) $(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE))#g' \
+		-e 's#@TIMEOUT@#$(GRUB_TIMEOUT)#g' \
+		-e 's#@ROOT@#$(GRUB_ROOT)#g' \
+		./grub.cfg > $(KDIR)/root.grub/boot/grub/grub.cfg
+	PADDING="$(CONFIG_TARGET_IMAGES_PAD)" SIGNATURE="$(SIGNATURE)" PATH="$(TARGET_PATH)" ./gen_image_generic.sh \
+		$(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img \
+		$(CONFIG_TARGET_KERNEL_PARTSIZE) $(KDIR)/root.grub \
+		$(CONFIG_TARGET_ROOTFS_PARTSIZE) $(KDIR)/root.$(1) \
+		256
+	grub-bios-setup \
+		--device-map="$(KDIR)/grub2/device.map" \
+		-d "$(KDIR)/grub2" \
+		-r "hd0,msdos1" \
+		"$(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img"
+	$(call Image/Build/grub/$(1))
+  endef
+endif
+
+ROOTDELAY=10
+
+define Image/Build/squashfs
+	dd if=/dev/zero bs=128k count=1 >> $(KDIR)/root.squashfs
+endef
+
+define Image/Build/iso
+	$(INSTALL_DIR) $(KDIR)/root.grub/boot/grub $(KDIR)/grub2
+	$(CP) $(KDIR)/bzImage $(KDIR)/root.grub/boot/vmlinuz
+	grub-mkimage \
+		-d $(STAGING_DIR_HOST)/lib/grub/i386-pc \
+		-o $(KDIR)/grub2/eltorito.img \
+		-O i386-pc \
+		-c ./grub-early.cfg \
+		$(GRUB2_MODULES_ISO)
+	cat \
+		$(STAGING_DIR_HOST)/lib/grub/i386-pc/cdboot.img \
+		$(KDIR)/grub2/eltorito.img \
+		> $(KDIR)/root.grub/boot/grub/eltorito.img
+	sed \
+		-e 's#@SERIAL_CONFIG@#$(strip $(GRUB_SERIAL_CONFIG))#g' \
+		-e 's#@TERMINAL_CONFIG@#$(strip $(GRUB_TERMINAL_CONFIG))#g' \
+		-e 's#@CMDLINE@#root=/dev/sr0 rootfstype=iso9660 rootwait $(strip $(call Image/cmdline/$(1)) $(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE))#g' \
+		-e 's#@TIMEOUT@#$(GRUB_TIMEOUT)#g' \
+		./grub-iso.cfg > $(KDIR)/root.grub/boot/grub/grub.cfg
+	$(CP) $(KDIR)/bzImage $(KDIR)/root.grub/boot/vmlinuz
+	mkisofs -R -b boot/grub/eltorito.img -no-emul-boot -boot-info-table \
+		-o $(KDIR)/root.iso $(KDIR)/root.grub $(TARGET_DIR)
+endef
+
+ifneq ($(CONFIG_VDI_IMAGES),)
+  define Image/Build/vdi
+	rm $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vdi || true
+	qemu-img convert -f raw -O vdi \
+		$(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img \
+		$(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vdi
+	# XXX: VBoxManage insists on setting perms to 0600
+	chmod 0644 $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vdi
+  endef
+endif
+
+ifneq ($(CONFIG_VMDK_IMAGES),)
+  define Image/Build/vmdk
+	rm $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vmdk || true
+	qemu-img convert -f raw -O vmdk \
+		$(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img \
+		$(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).vmdk
+  endef
+endif
+
+define Image/Build/gzip
+	gzip -f9n $(BIN_DIR)/$(IMG_PREFIX)-combined-$(1).img
+	gzip -f9n $(BIN_DIR)/$(IMG_PREFIX)-rootfs-$(1).img
+endef
+
+ifneq ($(CONFIG_TARGET_IMAGES_GZIP),)
+  define Image/Build/gzip/ext4
+	$(call Image/Build/gzip,ext4)
+  endef
+  ifneq ($(CONFIG_TARGET_IMAGES_PAD),)
+    define Image/Build/gzip/squashfs
+	$(call Image/Build/gzip,squashfs)
+    endef
+  endif
+endif
+
+define Image/BuildKernel
+	$(CP) $(KDIR)/bzImage $(BIN_DIR)/$(IMG_PREFIX)-vmlinuz
+endef
+
+define Image/Prepare
+	$(call Image/Prepare/grub2)
+endef
+
+define Image/Build/Initramfs
+	$(CP) $(KDIR)/bzImage-initramfs $(BIN_DIR)/$(IMG_PREFIX)-ramfs.bzImage
+endef
+
+define Image/Build
+	$(call Image/Build/$(1))
+  ifneq ($(1),iso)
+	$(call Image/Build/grub2,$(1))
+	$(call Image/Build/vdi,$(1))
+	$(call Image/Build/vmdk,$(1))
+	$(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-rootfs-$(1).img
+  else
+	$(CP) $(KDIR)/root.iso $(BIN_DIR)/$(IMG_PREFIX).iso
+  endif
+	$(CP) $(KDIR)/bzImage $(BIN_DIR)/$(IMG_PREFIX)-vmlinuz
+	$(call Image/Build/gzip/$(1))
+ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
+	$(call Image/Build/Initramfs)
+endif
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/x86/image/gen_image_generic.sh b/target/linux/x86/image/gen_image_generic.sh
new file mode 100755
index 0000000000..17d969b96b
--- /dev/null
+++ b/target/linux/x86/image/gen_image_generic.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# Copyright (C) 2006-2012 OpenWrt.org
+set -x
+[ $# == 5 -o $# == 6 ] || {
+    echo "SYNTAX: $0 <file> <kernel size> <kernel directory> <rootfs size> <rootfs image> [<align>]"
+    exit 1
+}
+
+OUTPUT="$1"
+KERNELSIZE="$2"
+KERNELDIR="$3"
+ROOTFSSIZE="$4"
+ROOTFSIMAGE="$5"
+ALIGN="$6"
+
+rm -f "$OUTPUT"
+
+head=16
+sect=63
+cyl=$(( ($KERNELSIZE + $ROOTFSSIZE) * 1024 * 1024 / ($head * $sect * 512)))
+
+# create partition table
+set `ptgen -o "$OUTPUT" -h $head -s $sect -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE}`
+
+KERNELOFFSET="$(($1 / 512))"
+KERNELSIZE="$2"
+ROOTFSOFFSET="$(($3 / 512))"
+ROOTFSSIZE="$(($4 / 512))"
+
+[ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc count="$ROOTFSSIZE"
+dd if="$ROOTFSIMAGE" of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc
+
+[ -n "$NOGRUB" ] && exit 0
+
+make_ext4fs -J -l "$KERNELSIZE" "$OUTPUT.kernel" "$KERNELDIR"
+dd if="$OUTPUT.kernel" of="$OUTPUT" bs=512 seek="$KERNELOFFSET" conv=notrunc
+rm -f "$OUTPUT.kernel"
diff --git a/target/linux/x86/image/grub-early.cfg b/target/linux/x86/image/grub-early.cfg
new file mode 100644
index 0000000000..4a5b5a6092
--- /dev/null
+++ b/target/linux/x86/image/grub-early.cfg
@@ -0,0 +1 @@
+configfile (hd0,msdos1)/boot/grub/grub.cfg
diff --git a/target/linux/x86/image/grub-iso.cfg b/target/linux/x86/image/grub-iso.cfg
new file mode 100644
index 0000000000..32ee687c68
--- /dev/null
+++ b/target/linux/x86/image/grub-iso.cfg
@@ -0,0 +1,10 @@
+@SERIAL_CONFIG@
+@TERMINAL_CONFIG@
+
+set default="0"
+set timeout="@TIMEOUT@"
+set root='(cd)'
+
+menuentry "LEDE" {
+	linux /boot/vmlinuz @CMDLINE@ noinitrd
+}
diff --git a/target/linux/x86/image/grub.cfg b/target/linux/x86/image/grub.cfg
new file mode 100644
index 0000000000..acca036a2e
--- /dev/null
+++ b/target/linux/x86/image/grub.cfg
@@ -0,0 +1,13 @@
+@SERIAL_CONFIG@
+@TERMINAL_CONFIG@
+
+set default="0"
+set timeout="@TIMEOUT@"
+set root='(@ROOT@)'
+
+menuentry "LEDE" {
+	linux /boot/vmlinuz @CMDLINE@ noinitrd
+}
+menuentry "LEDE (failsafe)" {
+	linux /boot/vmlinuz failsafe=true @CMDLINE@ noinitrd
+}
diff --git a/target/linux/x86/legacy/config-default b/target/linux/x86/legacy/config-default
new file mode 100644
index 0000000000..60b55c7ee7
--- /dev/null
+++ b/target/linux/x86/legacy/config-default
@@ -0,0 +1,215 @@
+# CONFIG_3C515 is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_AC=y
+# CONFIG_ACPI_ALS is not set
+CONFIG_ACPI_BATTERY=y
+CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_CMPC is not set
+# CONFIG_ACPI_CONTAINER is not set
+CONFIG_ACPI_CPU_FREQ_PSS=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_DEBUGGER is not set
+# CONFIG_ACPI_DOCK is not set
+# CONFIG_ACPI_EC_DEBUGFS is not set
+# CONFIG_ACPI_FAN is not set
+CONFIG_ACPI_HOTPLUG_IOAPIC=y
+# CONFIG_ACPI_I2C_OPREGION is not set
+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_PROCESSOR_IDLE=y
+# CONFIG_ACPI_PROCFS_POWER is not set
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
+# CONFIG_ACPI_SBS is not set
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
+CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_VIDEO=y
+# CONFIG_ACPI_WMI is not set
+CONFIG_AGP=y
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD64 is not set
+# CONFIG_AGP_ATI is not set
+# CONFIG_AGP_EFFICEON is not set
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_NVIDIA is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_SWORKS is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_APPLE_GMUX is not set
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
+# CONFIG_BACKLIGHT_APPLE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BACKLIGHT_SAHARA is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_COMMON_CLK=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_DRM=y
+CONFIG_DRM_AMDGPU=y
+# CONFIG_DRM_AMDGPU_CIK is not set
+# CONFIG_DRM_AMDGPU_USERPTR is not set
+# CONFIG_DRM_AST is not set
+CONFIG_DRM_BOCHS=y
+CONFIG_DRM_BRIDGE=y
+# CONFIG_DRM_CIRRUS_QEMU is not set
+CONFIG_DRM_FBDEV_EMULATION=y
+# CONFIG_DRM_GMA500 is not set
+# CONFIG_DRM_I2C_ADV7511 is not set
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_NXP_TDA998X is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I810 is not set
+CONFIG_DRM_I915=y
+# CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT is not set
+CONFIG_DRM_KMS_FB_HELPER=y
+CONFIG_DRM_KMS_HELPER=y
+# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_MGAG200 is not set
+CONFIG_DRM_MIPI_DSI=y
+# CONFIG_DRM_NOUVEAU is not set
+CONFIG_DRM_PANEL=y
+# CONFIG_DRM_QXL is not set
+# CONFIG_DRM_R128 is not set
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_RADEON_UMS is not set
+# CONFIG_DRM_RADEON_USERPTR is not set
+# CONFIG_DRM_SAVAGE is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_TTM=y
+# CONFIG_DRM_UDL is not set
+# CONFIG_DRM_VGEM is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_VMWGFX is not set
+# CONFIG_EFI is not set
+# CONFIG_EISA is not set
+# CONFIG_EL3 is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_I810 is not set
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_VESA is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FUJITSU_LAPTOP is not set
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HDMI=y
+CONFIG_HID=y
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HPET=y
+CONFIG_HPET_MMAP=y
+# CONFIG_HP_ACCEL is not set
+CONFIG_HWMON=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INTEL_GTT=y
+CONFIG_INTEL_IDLE=y
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_INTEL_PMC_IPC is not set
+CONFIG_INTERVAL_TREE=y
+CONFIG_ISA=y
+CONFIG_ISAPNP=y
+# CONFIG_ISCSI_IBFT_FIND is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_LANCE is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_MFD_CORE=y
+CONFIG_MFD_INTEL_LPSS=y
+CONFIG_MFD_INTEL_LPSS_ACPI=y
+# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_CYAPA is not set
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+# CONFIG_MOUSE_PS2_CYPRESS is not set
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_NLS=y
+CONFIG_NO_HZ=y
+# CONFIG_PANASONIC_LAPTOP is not set
+CONFIG_PATA_AMD=y
+CONFIG_PATA_ATIIXP=y
+CONFIG_PATA_LEGACY=y
+CONFIG_PATA_MPIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_PLATFORM=y
+CONFIG_PATA_SC1200=y
+CONFIG_PATA_VIA=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_MMCONFIG=y
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_PMIC_OPREGION is not set
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
+# CONFIG_PNPBIOS is not set
+CONFIG_PNP_DEBUG_MESSAGES=y
+# CONFIG_PVPANIC is not set
+CONFIG_RAS=y
+# CONFIG_SAMSUNG_Q10 is not set
+CONFIG_SATA_AHCI=y
+CONFIG_SERIAL_8250_PNP=y
+# CONFIG_SURFACE_PRO3_BUTTON is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_VGACON_SOFT_SCROLLBACK=y
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
+# CONFIG_WDT is not set
+CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_ACPI_CPUFREQ_CPB is not set
+# CONFIG_X86_POWERNOW_K8 is not set
+# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set
+# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
+# CONFIG_X86_E_POWERSAVER is not set
+# CONFIG_X86_INTEL_LPSS is not set
+# CONFIG_X86_LONGHAUL is not set
+# CONFIG_X86_PCC_CPUFREQ is not set
+CONFIG_X86_PM_TIMER=y
diff --git a/target/linux/x86/legacy/profiles/000-Generic.mk b/target/linux/x86/legacy/profiles/000-Generic.mk
new file mode 100644
index 0000000000..90f989a91d
--- /dev/null
+++ b/target/linux/x86/legacy/profiles/000-Generic.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Generic
+  NAME:=Generic
+  PACKAGES:=kmod-3c59x kmod-e100 kmod-e1000 kmod-natsemi kmod-ne2k-pci \
+	kmod-pcnet32 kmod-8139too kmod-r8169 kmod-sis900 kmod-tg3 \
+	kmod-via-rhine kmod-via-velocity
+endef
+
+define Profile/Generic/Description
+	Generic Profile
+endef
+$(eval $(call Profile,Generic))
diff --git a/target/linux/x86/legacy/target.mk b/target/linux/x86/legacy/target.mk
new file mode 100644
index 0000000000..bd0a87d67f
--- /dev/null
+++ b/target/linux/x86/legacy/target.mk
@@ -0,0 +1,7 @@
+BOARDNAME:=Legacy
+
+define Target/Description
+	Build firmware images for legacy x86 based boards
+	(e.g : Soekris, ...)
+endef
+
diff --git a/target/linux/x86/patches-4.4/011-tune_lzma_options.patch b/target/linux/x86/patches-4.4/011-tune_lzma_options.patch
new file mode 100644
index 0000000000..5f8f5d8218
--- /dev/null
+++ b/target/linux/x86/patches-4.4/011-tune_lzma_options.patch
@@ -0,0 +1,22 @@
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -324,7 +324,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
+ 
+ quiet_cmd_lzma = LZMA    $@
+ cmd_lzma = (cat $(filter-out FORCE,$^) | \
+-	lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
++	lzma e -lc8 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+ 	(rm -f $@ ; false)
+ 
+ quiet_cmd_lzo = LZO     $@
+--- a/arch/x86/include/asm/boot.h
++++ b/arch/x86/include/asm/boot.h
+@@ -23,7 +23,7 @@
+ #error "Invalid value for CONFIG_PHYSICAL_ALIGN"
+ #endif
+ 
+-#ifdef CONFIG_KERNEL_BZIP2
++#if defined(CONFIG_KERNEL_BZIP2) || defined(CONFIG_KERNEL_LZMA)
+ #define BOOT_HEAP_SIZE             0x400000
+ #else /* !CONFIG_KERNEL_BZIP2 */
+ 
diff --git a/target/linux/x86/patches-4.4/100-fix_cs5535_clockevt.patch b/target/linux/x86/patches-4.4/100-fix_cs5535_clockevt.patch
new file mode 100644
index 0000000000..c49ddca7d6
--- /dev/null
+++ b/target/linux/x86/patches-4.4/100-fix_cs5535_clockevt.patch
@@ -0,0 +1,12 @@
+--- a/drivers/clocksource/cs5535-clockevt.c
++++ b/drivers/clocksource/cs5535-clockevt.c
+@@ -129,7 +129,8 @@ static irqreturn_t mfgpt_tick(int irq, v
+ 		cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP,
+ 				MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+ 
+-	cs5535_clockevent.event_handler(&cs5535_clockevent);
++	if (cs5535_clockevent.event_handler)
++		cs5535_clockevent.event_handler(&cs5535_clockevent);
+ 	return IRQ_HANDLED;
+ }
+ 
diff --git a/target/linux/x86/xen_domu/base-files/etc/inittab b/target/linux/x86/xen_domu/base-files/etc/inittab
new file mode 100644
index 0000000000..72e19c5b3d
--- /dev/null
+++ b/target/linux/x86/xen_domu/base-files/etc/inittab
@@ -0,0 +1,5 @@
+::sysinit:/etc/init.d/rcS S boot
+::shutdown:/etc/init.d/rcS K stop
+tts/0::askfirst:/usr/libexec/login.sh
+hvc0::askfirst:/usr/libexec/login.sh
+tty1::askfirst:/usr/libexec/login.sh
diff --git a/target/linux/x86/xen_domu/base-files/lib/preinit/45_mount_xenfs b/target/linux/x86/xen_domu/base-files/lib/preinit/45_mount_xenfs
new file mode 100644
index 0000000000..7b0760516e
--- /dev/null
+++ b/target/linux/x86/xen_domu/base-files/lib/preinit/45_mount_xenfs
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Copyright (C) 2010 OpenWrt.org
+
+do_mount_xenfs() {
+	[ -f /etc/modules.d/??-xenfs ] && {
+		insmod $(cat /etc/modules.d/??-xenfs)
+		mount -o noatime none /proc/xen -t xenfs
+	}
+}
+
+boot_hook_add preinit_mount_root do_mount_xenfs
diff --git a/target/linux/x86/xen_domu/config-default b/target/linux/x86/xen_domu/config-default
new file mode 100644
index 0000000000..aeb1e2a635
--- /dev/null
+++ b/target/linux/x86/xen_domu/config-default
@@ -0,0 +1,100 @@
+# CONFIG_APM is not set
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set
+CONFIG_CPU_RMAP=y
+# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
+CONFIG_FB=y
+CONFIG_FB_CMDLINE=y
+CONFIG_FB_DEFERRED_IO=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_VESA is not set
+CONFIG_FREEZER=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HIBERNATE_CALLBACKS=y
+# CONFIG_HIGHMEM64G is not set
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_XEN=y
+CONFIG_HVC_XEN_FRONTEND=y
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_LGUEST_GUEST is not set
+CONFIG_LOCK_SPIN_ON_OWNER=y
+# CONFIG_M486 is not set
+CONFIG_MMU_NOTIFIER=y
+CONFIG_MPENTIUM4=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NR_CPUS=4
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_CLOCK=y
+# CONFIG_PARAVIRT_DEBUG is not set
+CONFIG_PARAVIRT_SPINLOCKS=y
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+CONFIG_PCI_XEN=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_SCHED_MC=y
+CONFIG_SMP=y
+CONFIG_SWIOTLB=y
+CONFIG_SWIOTLB_XEN=y
+CONFIG_SYS_HYPERVISOR=y
+CONFIG_TREE_RCU=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_X86_32_SMP=y
+# CONFIG_X86_BIGSMP is not set
+CONFIG_X86_CMOV=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_X86_PAE=y
+# CONFIG_X86_PMEM_LEGACY is not set
+CONFIG_X86_TSC=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_XEN=y
+CONFIG_XENFS=y
+CONFIG_XEN_AUTO_XLATE=y
+CONFIG_XEN_BALLOON=y
+CONFIG_XEN_BLKDEV_FRONTEND=y
+CONFIG_XEN_COMPAT_XENFS=y
+CONFIG_XEN_DEBUG_FS=y
+CONFIG_XEN_DEV_EVTCHN=y
+CONFIG_XEN_FBDEV_FRONTEND=y
+CONFIG_XEN_GNTDEV=y
+CONFIG_XEN_GRANT_DEV_ALLOC=y
+CONFIG_XEN_HAVE_PVMMU=y
+CONFIG_XEN_HAVE_VPMU=y
+CONFIG_XEN_NETDEV_FRONTEND=y
+CONFIG_XEN_PCIDEV_FRONTEND=y
+CONFIG_XEN_PRIVCMD=y
+CONFIG_XEN_PVHVM=y
+CONFIG_XEN_SAVE_RESTORE=y
+CONFIG_XEN_SCRUB_PAGES=y
+CONFIG_XEN_SCSI_FRONTEND=y
+CONFIG_XEN_SYS_HYPERVISOR=y
+# CONFIG_XEN_WDT is not set
+CONFIG_XEN_XENBUS_FRONTEND=y
+CONFIG_XPS=y
diff --git a/target/linux/x86/xen_domu/profiles/000-Generic.mk b/target/linux/x86/xen_domu/profiles/000-Generic.mk
new file mode 100644
index 0000000000..ccd125afa2
--- /dev/null
+++ b/target/linux/x86/xen_domu/profiles/000-Generic.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Generic
+  NAME:=Generic
+endef
+
+define Profile/Generic/Description
+	Generic Profile
+endef
+$(eval $(call Profile,Generic))
diff --git a/target/linux/x86/xen_domu/target.mk b/target/linux/x86/xen_domu/target.mk
new file mode 100644
index 0000000000..31d110c5c3
--- /dev/null
+++ b/target/linux/x86/xen_domu/target.mk
@@ -0,0 +1,4 @@
+BOARDNAME:=Xen Paravirt Guest
+DEFAULT_PACKAGES += kmod-xen-fs kmod-xen-evtchn kmod-xen-netdev kmod-xen-kbddev
+FEATURES:=display ext4 targz
+CPU_TYPE := pentium4
diff --git a/target/linux/xburst/Makefile b/target/linux/xburst/Makefile
new file mode 100644
index 0000000000..2a64b7c46f
--- /dev/null
+++ b/target/linux/xburst/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2009-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=mipsel
+BOARD:=xburst
+BOARDNAME:=Ingenic XBurst
+FEATURES:=targz nand ubifs audio
+SUBTARGETS:=qi_lb60
+
+KERNEL_PATCHVER:=3.18
+
+DEVICE_TYPE:=other
+
+define Target/Description
+	Build firmware images for XBurst JZ47x0 based boards.
+endef
+
+include $(INCLUDE_DIR)/target.mk
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/xburst/base-files/etc/board.d/01_system b/target/linux/xburst/base-files/etc/board.d/01_system
new file mode 100755
index 0000000000..16f4987aae
--- /dev/null
+++ b/target/linux/xburst/base-files/etc/board.d/01_system
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+. /lib/functions/uci-defaults.sh
+
+board_config_update
+
+ucidef_set_hostname "BenNanoNote"
+ucidef_set_ntpserver
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/xburst/base-files/etc/config/fstab b/target/linux/xburst/base-files/etc/config/fstab
new file mode 100644
index 0000000000..522356112f
--- /dev/null
+++ b/target/linux/xburst/base-files/etc/config/fstab
@@ -0,0 +1,6 @@
+config mount
+	option target   /card
+	option device   /dev/mmcblk0p1
+	option fstype   auto
+	option options  rw,sync
+	option enabled  1
diff --git a/target/linux/xburst/base-files/etc/config/network b/target/linux/xburst/base-files/etc/config/network
new file mode 100644
index 0000000000..a086003e32
--- /dev/null
+++ b/target/linux/xburst/base-files/etc/config/network
@@ -0,0 +1,13 @@
+# Copyright (C) 2006 OpenWrt.org
+
+config interface loopback
+	option ifname	lo
+	option proto	static
+	option ipaddr	127.0.0.1
+	option netmask	255.0.0.0
+
+config interface lan
+	option ifname	usb0
+	option proto	static
+	option ipaddr	192.168.1.1
+	option netmask	255.255.255.0
diff --git a/target/linux/xburst/config-3.18 b/target/linux/xburst/config-3.18
new file mode 100644
index 0000000000..fbc2891673
--- /dev/null
+++ b/target/linux/xburst/config-3.18
@@ -0,0 +1,354 @@
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BACKLIGHT_PWM is not set
+CONFIG_BATTERY_JZ4740=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CHARGER_GPIO=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_XZ=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_JZ4740=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_DW_DMAC_CORE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_EXT4_FS=y
+CONFIG_FAT_FS=y
+CONFIG_FB=y
+CONFIG_FB_CMDLINE=y
+CONFIG_FB_JZ4740=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+CONFIG_FONTS=y
+# CONFIG_FONT_10x18 is not set
+# CONFIG_FONT_6x10 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_SUN8x16 is not set
+CONFIG_FONT_SUPPORT=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_HAMRADIO is not set
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_HW_CONSOLE=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_INPUT=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INPUT_MATRIXKMAP=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_PWM_BEEPER=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_IRQ_CPU=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_JZ4740_QI_LB60=y
+CONFIG_KALLSYMS=y
+CONFIG_KERNFS=y
+CONFIG_KEXEC=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+# CONFIG_LCD_AMS369FG06 is not set
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_ILI8960=y
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LD9040 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_PLATFORM is not set
+# CONFIG_LCD_S6E63M0 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MACH_JZ4740=y
+CONFIG_MFD_CORE=y
+CONFIG_MFD_JZ4740_ADC=y
+CONFIG_MIPS=y
+# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MACHINE is not set
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_JZ4740=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_CYAPA is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_JZ4740=y
+CONFIG_MTD_SPLIT_SUPPORT=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+# CONFIG_MTD_UBI_BLOCK is not set
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+CONFIG_NOP_USB_XCEIV=y
+# CONFIG_NO_IOPORT_MAP is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_RCU=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PWM=y
+CONFIG_PWM_JZ4740=y
+# CONFIG_RCU_BOOST is not set
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_SPI=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_CMOS is not set
+CONFIG_RTC_DRV_JZ4740=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SENSORS_JZ4740 is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SND=y
+CONFIG_SND_COMPRESS_OFFLOAD=y
+CONFIG_SND_DMAENGINE_PCM=y
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_JACK=y
+CONFIG_SND_JZ4740_SOC=y
+CONFIG_SND_JZ4740_SOC_I2S=y
+CONFIG_SND_JZ4740_SOC_QI_LB60=y
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+CONFIG_SND_PCM=y
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+CONFIG_SND_SOC=y
+# CONFIG_SND_SOC_FSL_SSI is not set
+CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_IMX_AUDMUX is not set
+CONFIG_SND_SOC_JZ4740_CODEC=y
+CONFIG_SND_TIMER=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_STAGING is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_SYN_COOKIES is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_XZ=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USB=y
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_COMMON=y
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_ETH_RNDIS is not set
+CONFIG_USB_F_ECM=y
+CONFIG_USB_F_SUBSET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_LIBCOMPOSITE=y
+# CONFIG_USB_MUSB_DUAL_ROLE is not set
+CONFIG_USB_MUSB_GADGET=y
+CONFIG_USB_MUSB_HDRC=y
+# CONFIG_USB_MUSB_HOST is not set
+CONFIG_USB_MUSB_JZ4740=y
+# CONFIG_USB_MUSB_TUSB6010 is not set
+# CONFIG_USB_MUSB_UX500 is not set
+CONFIG_USB_OTG_BLACKLIST_HUB=y
+CONFIG_USB_PHY=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_U_ETHER=y
+CONFIG_VFAT_FS=y
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_VLAN_8021Q is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_WATCHDOG is not set
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/xburst/image/Makefile b/target/linux/xburst/image/Makefile
new file mode 100644
index 0000000000..0853607506
--- /dev/null
+++ b/target/linux/xburst/image/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2009-2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+JFFS2_BLOCKSIZE=256k 512k
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+ifneq ($(CONFIG_TARGET_xburst_qi_lb60),)
+UBI_OPTS = -m 4096 -p 512KiB
+UBIFS_OPTS = -m 4096 -e 516096 -c 4095
+else
+UBI_OPTS = -m 2048 -p 128KiB -s 512
+UBIFS_OPTS = -m 2048 -e 126KiB -c 4096
+endif
+
+UIMAGE:=$(BIN_DIR)/$(IMG_PREFIX)-uImage.bin
+
+define kernel_entry
+0x$(shell $(TARGET_CROSS)nm $(1) 2>/dev/null | grep " kernel_entry" | cut -f1 -d ' ')
+endef
+
+
+define MkImageGzip
+	gzip -9n -c $(1) > $(1).gz
+	mkimage -A mips -O linux -T kernel -a 0x80010000 -C gzip \
+		-e $(call kernel_entry,$(KDIR)/vmlinux.debug) -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
+		-d $(1).gz $(2)
+endef
+
+define Image/Prepare
+	$(call MkImageGzip,$(KDIR)/vmlinux,$(KDIR)/uimage)
+endef
+
+define Image/BuildKernel
+	cp $(KDIR)/uimage $(UIMAGE)
+endef
+
+define Image/Build/squashfs
+	$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
+endef
+
+define Image/Build
+	dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=128k conv=sync
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/xburst/image/ubinize.cfg b/target/linux/xburst/image/ubinize.cfg
new file mode 100644
index 0000000000..49d55b9840
--- /dev/null
+++ b/target/linux/xburst/image/ubinize.cfg
@@ -0,0 +1,14 @@
+[rootfs]
+# Volume mode (other option is static)
+mode=ubi
+# Source image
+image=root.ubifs
+# Volume ID in UBI image
+vol_id=0
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs
+# Autoresize volume at first mount
+vol_flags=autoresize
+
diff --git a/target/linux/xburst/modules.mk b/target/linux/xburst/modules.mk
new file mode 100644
index 0000000000..95cebdad6a
--- /dev/null
+++ b/target/linux/xburst/modules.mk
@@ -0,0 +1,40 @@
+
+
+SOUND_MENU:=Sound Support
+
+define KernelPackage/sound-soc-jz4740
+  SUBMENU:=$(SOUND_MENU)
+  DEPENDS:=kmod-sound-soc-core @TARGET_xburst @BROKEN
+  TITLE:=JZ4740 SoC sound support
+  KCONFIG:=CONFIG_SND_JZ4740_SOC CONFIG_SND_JZ4740_SOC_I2S
+  FILES:= \
+	$(LINUX_DIR)/sound/soc/jz4740/snd-soc-jz4740.ko \
+	$(LINUX_DIR)/sound/soc/jz4740/snd-soc-jz4740-i2s.ko
+  AUTOLOAD:=$(call AutoLoad,60,snd-soc-jz4740 snd-soc-jz4740-i2s)
+endef
+
+define KernelPackage/sound-soc-jz4740-codec
+  SUBMENU:=$(SOUND_MENU)
+  DEPENDS:=kmod-sound-soc-core @TARGET_xburst @BROKEN
+  TITLE:=JZ4740 SoC internal codec support
+  KCONFIG:=CONFIG_SND_SOC_JZ4740_CODEC
+  FILES:=$(LINUX_DIR)/sound/soc/codecs/snd-soc-jz4740-codec.ko
+  AUTOLOAD:=$(call AutoLoad,60,snd-soc-jz4740-codec)
+endef
+
+define KernelPackage/sound-soc-xburst/default
+  SUBMENU:=$(SOUND_MENU)
+  DEPENDS:=kmod-sound-soc-jz4740 kmod-sound-soc-jz4740-codec @TARGET_xburst_$(if $(4),$(4),$(3)) @BROKEN
+  TITLE:=$(1) sound support
+  KCONFIG:=CONFIG_SND_JZ4740_SOC_$(2)
+  FILES:=$(LINUX_DIR)/sound/soc/jz4740/snd-soc-$(3).ko
+  AUTOLOAD:=$(call AutoLoad,65,snd-soc-$(3))
+endef
+
+define KernelPackage/sound-soc-qilb60
+$(call KernelPackage/sound-soc-xburst/default,QI NanoNote,QI_LB60,qi-lb60,qi_lb60)
+endef
+
+$(eval $(call KernelPackage,sound-soc-jz4740))
+$(eval $(call KernelPackage,sound-soc-jz4740-codec))
+$(eval $(call KernelPackage,sound-soc-qilb60))
diff --git a/target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch b/target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch
new file mode 100644
index 0000000000..93851d7283
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch
@@ -0,0 +1,20 @@
+From b0eb5175e0de3e5134a36a7da382d8811562af12 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 15 Mar 2011 12:49:15 +0100
+Subject: [PATCH 1/7] ubi: Read only the vid header instead of the whole page
+
+---
+ drivers/mtd/ubi/io.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/ubi/io.c
++++ b/drivers/mtd/ubi/io.c
+@@ -1014,7 +1014,7 @@ int ubi_io_read_vid_hdr(struct ubi_devic
+ 
+ 	p = (char *)vid_hdr - ubi->vid_hdr_shift;
+ 	read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+-			  ubi->vid_hdr_alsize);
++			  UBI_VID_HDR_SIZE + ubi->vid_hdr_shift);
+ 	if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
+ 		return read_err;
+ 
diff --git a/target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch b/target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch
new file mode 100644
index 0000000000..046da51912
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch
@@ -0,0 +1,43 @@
+From 98d33db1c87e2447b9b203399d2f995e05ecdb52 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Sat, 26 Feb 2011 15:30:07 +0100
+Subject: [PATCH 2/7] NAND: Optimize NAND_ECC_HW_OOB_FIRST read
+
+Avoid sending unnecessary READ commands to the chip.
+---
+ drivers/mtd/nand/nand_base.c |   17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1360,9 +1360,16 @@ static int nand_read_page_hwecc_oob_firs
+ 	unsigned int max_bitflips = 0;
+ 
+ 	/* Read the OOB area first */
+-	chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+-	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+-	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++	/* Read the OOB area first */
++	if (mtd->writesize > 512) {
++		chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
++	} else {
++		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++		chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
++	}
+ 
+ 	for (i = 0; i < chip->ecc.total; i++)
+ 		ecc_code[i] = chip->oob_poi[eccpos[i]];
+@@ -1575,7 +1582,9 @@ static int nand_do_read_ops(struct mtd_i
+ 						 __func__, buf);
+ 
+ read_retry:
+-			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++			if (chip->ecc.mode != NAND_ECC_HW_OOB_FIRST) {
++				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
++			}
+ 
+ 			/*
+ 			 * Now read the page into the buffer.  Absent an error,
diff --git a/target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch b/target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch
new file mode 100644
index 0000000000..974eb7a5db
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch
@@ -0,0 +1,104 @@
+From 6031a240816d1c9a10f596d0648e586f6b878809 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 15 Mar 2011 12:33:41 +0100
+Subject: [PATCH 3/7] NAND: Add support for subpage reads for
+ NAND_ECC_HW_OOB_FIRST
+
+---
+ drivers/mtd/nand/nand_base.c |   77 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 76 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1393,6 +1393,75 @@ static int nand_read_page_hwecc_oob_firs
+ }
+ 
+ /**
++ * nand_read_subpage_hwecc_oob_first - [REPLACABLE] hw ecc based sub-page read function
++ * @mtd:	mtd info structure
++ * @chip:	nand chip info structure
++ * @data_offs:	offset of requested data within the page
++ * @readlen:	data length
++ * @bufpoi:	buffer to store read data
++ * @page:	page number to read
++ *
++ * Hardware ECC for large page chips, require OOB to be read first.
++ * For this ECC mode, the write_page method is re-used from ECC_HW.
++ * These methods read/write ECC from the OOB area, unlike the
++ * ECC_HW_SYNDROME support with multiple ECC steps, follows the
++ * "infix ECC" scheme and reads/writes ECC from the data area, by
++ * overwriting the NAND manufacturer bad block markings.
++ */
++static int nand_read_subpage_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip,
++			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page)
++{
++	int start_step, end_step, num_steps;
++	uint32_t *eccpos = chip->ecc.layout->eccpos;
++	uint8_t *p;
++	int data_col_addr;
++	int eccsize = chip->ecc.size;
++	int eccbytes = chip->ecc.bytes;
++	uint8_t *ecc_code = chip->buffers->ecccode;
++	uint8_t *ecc_calc = chip->buffers->ecccalc;
++	int i;
++
++	/* Column address wihin the page aligned to ECC size */
++	start_step = data_offs / chip->ecc.size;
++	end_step = (data_offs + readlen - 1) / chip->ecc.size;
++	num_steps = end_step - start_step + 1;
++
++	data_col_addr = start_step * chip->ecc.size;
++
++	/* Read the OOB area first */
++	if (mtd->writesize > 512) {
++		chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
++	} else {
++		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
++		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
++		chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page);
++	}
++
++	for (i = 0; i < chip->ecc.total; i++)
++		ecc_code[i] = chip->oob_poi[eccpos[i]];
++
++	p = bufpoi + data_col_addr;
++
++	for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) {
++		int stat;
++
++		chip->ecc.hwctl(mtd, NAND_ECC_READ);
++		chip->read_buf(mtd, p, eccsize);
++		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
++
++		stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
++		if (stat < 0)
++			mtd->ecc_stats.failed++;
++		else
++			mtd->ecc_stats.corrected += stat;
++	}
++
++	return 0;
++}
++
++/**
+  * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
+  * @mtd: mtd info structure
+  * @chip: nand chip info structure
+@@ -3950,8 +4019,14 @@ int nand_scan_tail(struct mtd_info *mtd)
+ 			pr_warn("No ECC functions supplied; hardware ECC not possible\n");
+ 			BUG();
+ 		}
+-		if (!ecc->read_page)
++
++		if (!ecc->read_page) {
+ 			ecc->read_page = nand_read_page_hwecc_oob_first;
++			if (!ecc->read_subpage) {
++				ecc->read_subpage = nand_read_subpage_hwecc_oob_first;
++				chip->options |= NAND_SUBPAGE_READ;
++			}
++		}
+ 
+ 	case NAND_ECC_HW:
+ 		/* Use standard hwecc read page function? */
diff --git a/target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch b/target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch
new file mode 100644
index 0000000000..f2c26ade09
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/004-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch
@@ -0,0 +1,33 @@
+From 1a1095927d224403af8ad57c354cc64521bf3081 Mon Sep 17 00:00:00 2001
+From: Paul Cercueil <paul@crapouillou.net>
+Date: Sat, 16 Jun 2012 19:36:31 +0200
+Subject: [PATCH 4/7] ASoC: JZ4740: delay activation of the DAC to work around
+ a sound bug.
+
+A proper fix of that bug would require a big rewrite of the driver,
+which (I hope) will be done eventually.
+---
+ sound/soc/codecs/jz4740.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/codecs/jz4740.c
++++ b/sound/soc/codecs/jz4740.c
+@@ -249,12 +249,15 @@ static int jz4740_codec_set_bias_level(s
+ 	case SND_SOC_BIAS_ON:
+ 		break;
+ 	case SND_SOC_BIAS_PREPARE:
+-		mask = JZ4740_CODEC_1_VREF_DISABLE |
+-				JZ4740_CODEC_1_VREF_AMP_DISABLE |
+-				JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
++		mask = JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+ 		value = 0;
+ 
+ 		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value);
++
++		msleep(500);
++		mask = JZ4740_CODEC_1_VREF_DISABLE |
++						JZ4740_CODEC_1_VREF_AMP_DISABLE;
++		regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, 0);
+ 		break;
+ 	case SND_SOC_BIAS_STANDBY:
+ 		/* The only way to clear the suspend flag is to reset the codec */
diff --git a/target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch b/target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch
new file mode 100644
index 0000000000..f38483ab5c
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/005-RTC-JZ4740-Init-the-regulator-register-on-startup.patch
@@ -0,0 +1,55 @@
+From f05b1ecd7e4fde7e69320a4b7be461636e982991 Mon Sep 17 00:00:00 2001
+From: Paul Cercueil <paul@crapouillou.net>
+Date: Thu, 13 Sep 2012 00:09:20 +0200
+Subject: [PATCH 5/7] RTC: JZ4740: Init the "regulator" register on startup.
+
+This register controls the accuracy of the RTC. uC/OS-II use
+the RTC as a 100Hz clock, and writes a completely wrong value
+on that register, that we have to overwrite if we want a working
+real-time clock.
+
+Signed-off-by: Paul Cercueil <paul@crapouillou.net>
+---
+ drivers/rtc/rtc-jz4740.c |   17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/drivers/rtc/rtc-jz4740.c
++++ b/drivers/rtc/rtc-jz4740.c
+@@ -15,6 +15,7 @@
+  */
+ 
+ #include <linux/io.h>
++#include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+@@ -216,6 +217,7 @@ static int jz4740_rtc_probe(struct platf
+ 	struct jz4740_rtc *rtc;
+ 	uint32_t scratchpad;
+ 	struct resource *mem;
++	struct clk *rtc_clk;
+ 
+ 	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ 	if (!rtc)
+@@ -263,6 +265,21 @@ static int jz4740_rtc_probe(struct platf
+ 		}
+ 	}
+ 
++	rtc_clk = clk_get(&pdev->dev, "rtc");
++	if (IS_ERR(rtc_clk)) {
++		dev_err(&pdev->dev, "Failed to get RTC clock\n");
++		return PTR_ERR(rtc_clk);
++	}
++
++	/* TODO: initialize the ADJC bits (25:16) to fine-tune
++	 * the accuracy of the RTC */
++	ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_REGULATOR,
++				(clk_get_rate(rtc_clk) - 1) & 0xffff);
++	clk_put(rtc_clk);
++
++	if (ret)
++		dev_warn(&pdev->dev, "Could not update RTC regulator register\n");
++
+ 	return 0;
+ }
+ 
diff --git a/target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch b/target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch
new file mode 100644
index 0000000000..dc12d93409
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/006-Add-ili8960-lcd-driver.patch
@@ -0,0 +1,309 @@
+From 8741ead92bc93e66740237e51b88b8690ebcbba3 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Sun, 1 Aug 2010 21:19:40 +0200
+Subject: [PATCH 6/7] Add ili8960 lcd driver
+
+Includes the following changes from the jz-3.5 branch:
+- Use module_spi_driver
+- Use devm_kzalloc
+- Use kstrtoul
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+---
+ drivers/video/backlight/Kconfig   |    7 +
+ drivers/video/backlight/Makefile  |    1 +
+ drivers/video/backlight/ili8960.c |  262 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 270 insertions(+)
+ create mode 100644 drivers/video/backlight/ili8960.c
+
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -59,6 +59,13 @@ config LCD_LTV350QV
+ 
+ 	  The LTV350QV panel is present on all ATSTK1000 boards.
+ 
++config LCD_ILI8960
++	tristate "Ilitek ili8960 LCD driver"
++	depends on LCD_CLASS_DEVICE && SPI
++	default n
++	help
++	  Driver for the Ilitek ili8960 LCD controller chip.
++
+ config LCD_ILI922X
+ 	tristate "ILI Technology ILI9221/ILI9222 support"
+ 	depends on SPI
+--- a/drivers/video/backlight/Makefile
++++ b/drivers/video/backlight/Makefile
+@@ -5,6 +5,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE)		+= lcd.o
+ obj-$(CONFIG_LCD_CORGI)			+= corgi_lcd.o
+ obj-$(CONFIG_LCD_HP700)			+= jornada720_lcd.o
+ obj-$(CONFIG_LCD_HX8357)		+= hx8357.o
++obj-$(CONFIG_LCD_ILI8960)		+= ili8960.o
+ obj-$(CONFIG_LCD_ILI922X)		+= ili922x.o
+ obj-$(CONFIG_LCD_ILI9320)		+= ili9320.o
+ obj-$(CONFIG_LCD_L4F00242T03)		+= l4f00242t03.o
+--- /dev/null
++++ b/drivers/video/backlight/ili8960.c
+@@ -0,0 +1,262 @@
++/*
++ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
++ *  Driver for Ilitek ili8960 LCD
++ *
++ *  This program is free software; you can redistribute	 it and/or modify it
++ *  under  the terms of	 the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the	License, or (at your
++ *  option) any later version.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/spi/spi.h>
++#include <linux/lcd.h>
++#include <linux/delay.h>
++
++struct ili8960 {
++	struct spi_device *spi;
++	struct lcd_device *lcd;
++	bool enabled;
++	unsigned int brightness;
++};
++
++#define ILI8960_REG_BRIGHTNESS	0x03
++#define ILI8960_REG_POWER	0x05
++#define ILI8960_REG_CONTRAST	0x0d
++
++static int ili8960_write_reg(struct spi_device *spi, uint8_t reg,
++				uint8_t data)
++{
++	uint8_t buf[2];
++	buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f);
++	buf[1] = data;
++
++	return spi_write(spi, buf, sizeof(buf));
++}
++
++static int ili8960_programm_power(struct spi_device *spi, bool enabled)
++{
++	int ret;
++
++	if (enabled)
++		mdelay(20);
++
++	ret = ili8960_write_reg(spi, ILI8960_REG_POWER, enabled ? 0xc7 : 0xc6);
++
++	if (!enabled)
++		mdelay(20);
++
++	return ret;
++}
++
++static int ili8960_set_power(struct lcd_device *lcd, int power)
++{
++	struct ili8960 *ili8960 = lcd_get_data(lcd);
++
++	switch (power) {
++	case FB_BLANK_UNBLANK:
++		ili8960->enabled = true;
++		break;
++	default:
++		return 0;
++	}
++
++	return ili8960_programm_power(ili8960->spi, ili8960->enabled);
++}
++
++static int ili8960_early_set_power(struct lcd_device *lcd, int power)
++{
++	struct ili8960 *ili8960 = lcd_get_data(lcd);
++
++	switch (power) {
++	case FB_BLANK_UNBLANK:
++		return 0;
++	default:
++		ili8960->enabled = false;
++		break;
++	}
++
++	return ili8960_programm_power(ili8960->spi, ili8960->enabled);
++}
++
++static int ili8960_get_power(struct lcd_device *lcd)
++{
++	struct ili8960 *ili8960 = lcd_get_data(lcd);
++	return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
++}
++
++static int ili8960_set_contrast(struct lcd_device *lcd, int contrast)
++{
++	struct ili8960 *ili8960 = lcd_get_data(lcd);
++
++	return ili8960_write_reg(ili8960->spi, ILI8960_REG_CONTRAST, contrast);
++}
++
++static int ili8960_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
++{
++	if (mode->xres != 320 && mode->yres != 240)
++		return -EINVAL;
++
++	return 0;
++}
++
++static int ili8960_set_brightness(struct ili8960 *ili8960, int brightness)
++{
++	int ret;
++
++	ret = ili8960_write_reg(ili8960->spi, ILI8960_REG_BRIGHTNESS, brightness);
++
++	if (ret == 0)
++		ili8960->brightness = brightness;
++
++	return ret;
++}
++
++static ssize_t ili8960_show_brightness(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct lcd_device *ld = to_lcd_device(dev);
++	struct ili8960 *ili8960 = lcd_get_data(ld);
++
++	return sprintf(buf, "%u\n", ili8960->brightness);
++}
++
++static ssize_t ili8960_store_brightness(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t count)
++{
++	struct lcd_device *ld = to_lcd_device(dev);
++	struct ili8960 *ili8960 = lcd_get_data(ld);
++	unsigned long brightness;
++	int ret;
++
++	ret = kstrtoul(buf, 0, &brightness);
++	if (ret)
++		return ret;
++
++	if (brightness > 255)
++		return -EINVAL;
++
++	ili8960_set_brightness(ili8960, brightness);
++
++	return count;
++}
++
++
++static DEVICE_ATTR(brightness, 0644, ili8960_show_brightness,
++	ili8960_store_brightness);
++
++static struct lcd_ops ili8960_lcd_ops = {
++	.set_power = ili8960_set_power,
++	.early_set_power = ili8960_early_set_power,
++	.get_power = ili8960_get_power,
++	.set_contrast = ili8960_set_contrast,
++	.set_mode = ili8960_set_mode,
++};
++
++static int ili8960_probe(struct spi_device *spi)
++{
++	int ret;
++	struct ili8960 *ili8960;
++
++	ili8960 = devm_kzalloc(&spi->dev, sizeof(*ili8960), GFP_KERNEL);
++	if (!ili8960)
++		return -ENOMEM;
++
++	spi->bits_per_word = 8;
++	spi->mode = SPI_MODE_3;
++
++	ret = spi_setup(spi);
++	if (ret) {
++		dev_err(&spi->dev, "Failed to setup spi\n");
++		return ret;
++	}
++
++	ili8960->spi = spi;
++
++	ili8960->lcd = lcd_device_register("ili8960-lcd", &spi->dev, ili8960,
++						&ili8960_lcd_ops);
++
++	if (IS_ERR(ili8960->lcd)) {
++		ret = PTR_ERR(ili8960->lcd);
++		dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret);
++		return ret;
++	}
++
++	ili8960->lcd->props.max_contrast = 255;
++
++	ret = device_create_file(&ili8960->lcd->dev, &dev_attr_brightness);
++	if (ret)
++		goto err_unregister_lcd;
++
++	ili8960_programm_power(ili8960->spi, true);
++	ili8960->enabled = true;
++
++	spi_set_drvdata(spi, ili8960);
++
++	ili8960_write_reg(spi, 0x13, 0x01);
++
++	return 0;
++err_unregister_lcd:
++	lcd_device_unregister(ili8960->lcd);
++	return ret;
++}
++
++static int ili8960_remove(struct spi_device *spi)
++{
++	struct ili8960 *ili8960 = spi_get_drvdata(spi);
++
++	device_remove_file(&ili8960->lcd->dev, &dev_attr_brightness);
++	lcd_device_unregister(ili8960->lcd);
++
++	spi_set_drvdata(spi, NULL);
++	return 0;
++}
++
++#ifdef CONFIG_PM
++
++static int ili8960_suspend(struct spi_device *spi, pm_message_t state)
++{
++	struct ili8960 *ili8960 = spi_get_drvdata(spi);
++
++	if (ili8960->enabled)
++		ili8960_programm_power(ili8960->spi, false);
++
++	return 0;
++}
++
++static int ili8960_resume(struct spi_device *spi)
++{
++	struct ili8960 *ili8960 = spi_get_drvdata(spi);
++
++	if (ili8960->enabled)
++		ili8960_programm_power(ili8960->spi, true);
++
++	return 0;
++}
++
++#else
++#define ili8960_suspend NULL
++#define ili8960_resume NULL
++#endif
++
++static struct spi_driver ili8960_driver = {
++	.driver = {
++		.name = "ili8960",
++		.owner = THIS_MODULE,
++	},
++	.probe = ili8960_probe,
++	.remove = ili8960_remove,
++	.suspend = ili8960_suspend,
++	.resume = ili8960_resume,
++};
++module_spi_driver(ili8960_driver);
++
++MODULE_AUTHOR("Lars-Peter Clausen");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("LCD driver for Ilitek ili8960");
++MODULE_ALIAS("spi:ili8960");
diff --git a/target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch b/target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch
new file mode 100644
index 0000000000..b8aac66b3e
--- /dev/null
+++ b/target/linux/xburst/patches-3.18/007-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch
@@ -0,0 +1,21 @@
+From 4371d60ae342c76708c4317e06fb7dcf0159c2f1 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 13 Oct 2010 01:17:24 +0200
+Subject: [PATCH 7/7] qi_lb60: Don't use 3-wire spi mode for the display for
+ now
+
+The spi_gpio driver does not support 3-wire mode.
+---
+ arch/mips/jz4740/board-qi_lb60.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/mips/jz4740/board-qi_lb60.c
++++ b/arch/mips/jz4740/board-qi_lb60.c
+@@ -312,7 +312,6 @@ static struct spi_board_info qi_lb60_spi
+ 		.chip_select = 0,
+ 		.bus_num = 1,
+ 		.max_speed_hz = 30 * 1000,
+-		.mode = SPI_3WIRE,
+ 	},
+ };
+ 
diff --git a/target/linux/xburst/qi_lb60/config-default b/target/linux/xburst/qi_lb60/config-default
new file mode 100644
index 0000000000..1fd421b5fc
--- /dev/null
+++ b/target/linux/xburst/qi_lb60/config-default
@@ -0,0 +1,33 @@
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_INPUT_MATRIXKMAP=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_ILI8960=y
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_PLATFORM is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_REGMAP_SPI=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_SEQ_DUMMY=y
+# CONFIG_SND_VIRMIDI is not set
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+# CONFIG_USB_FUSB300 is not set
+CONFIG_USB_JZ4740=y
diff --git a/target/linux/xburst/qi_lb60/target.mk b/target/linux/xburst/qi_lb60/target.mk
new file mode 100644
index 0000000000..8ae71bd9cb
--- /dev/null
+++ b/target/linux/xburst/qi_lb60/target.mk
@@ -0,0 +1 @@
+BOARDNAME:=QI Ben Nanonote (qi_lb60)
diff --git a/target/sdk/Config.in b/target/sdk/Config.in
new file mode 100644
index 0000000000..37d2ca0ede
--- /dev/null
+++ b/target/sdk/Config.in
@@ -0,0 +1,9 @@
+config SDK
+	bool "Build the libreCMC SDK"
+	depends on !EXTERNAL_TOOLCHAIN
+	help
+	  This is essentially a stripped-down version of the buildroot
+	  with a precompiled toolchain. It can be used to develop and
+	  test packages for libreCMC before including them in the buildroot
+
+
diff --git a/target/sdk/Makefile b/target/sdk/Makefile
new file mode 100644
index 0000000000..de77d1a31a
--- /dev/null
+++ b/target/sdk/Makefile
@@ -0,0 +1,136 @@
+# 
+# Copyright (C) 2006-2014 OpenWrt.org
+# Copyright (C) 2016 LEDE Project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/version.mk
+
+override MAKEFLAGS=
+
+SDK_NAME:=$(VERSION_DIST_SANITIZED)-sdk-$(if $(CONFIG_VERSION_FILENAMES),$(VERSION_NUMBER)-)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))$(if $(GCCV),_gcc-$(GCCV))$(DIR_SUFFIX).$(HOST_OS)-$(HOST_ARCH)
+SDK_BUILD_DIR:=$(BUILD_DIR)/$(SDK_NAME)
+
+STAGING_SUBDIR_HOST := staging_dir/host
+STAGING_SUBDIR_TOOLCHAIN := staging_dir/toolchain-$(ARCH)$(ARCH_SUFFIX)_gcc-$(GCCV)_$(LIBC)-$(LIBCV)$(if $(CONFIG_arm),_eabi)
+
+EXCLUDE_DIRS:=*/ccache/* \
+	*/stamp \
+	*/stampfiles \
+	*/man \
+	*/info \
+	*/root-* \
+	initial \
+	*.install.clean \
+	*.install.flags \
+	*.install \
+	*/doc
+
+SDK_DIRS = \
+		$(STAGING_SUBDIR_HOST) \
+		$(STAGING_SUBDIR_TOOLCHAIN)
+
+BASE_FEED:=$(shell git config --get remote.origin.url 2>/dev/null | sed -ne 's/^/src-git base /p')
+BASE_FEED:=$(if $(BASE_FEED),$(BASE_FEED),$(shell cd $(TOPDIR); LC_ALL=C git svn info 2>/dev/null | sed -ne 's/^URL: /src-gitsvn base /p'))
+BASE_FEED:=$(if $(BASE_FEED),$(BASE_FEED),$(shell cd $(TOPDIR); LC_ALL=C svn info 2>/dev/null | sed -ne 's/^URL: /src-svn base /p'))
+BASE_FEED:=$(if $(BASE_FEED),$(BASE_FEED),src-git base https://git.lede-project.org/source.git$(filter-out ;master,;$(shell git rev-parse --abbrev-ref HEAD)))
+
+KDIR_BASE = $(patsubst $(TOPDIR)/%,%,$(LINUX_DIR))
+
+KERNEL_FILES_ARCH = \
+	Makefile* \
+	module.lds \
+	Kbuild.platforms \
+	*/Platform \
+	include \
+	*/include \
+	scripts \
+	kernel/asm-offsets.s
+
+KERNEL_FILES_BASE := \
+	.config \
+	Makefile \
+	scripts \
+	include \
+	Module.symvers \
+	modules.builtin \
+	$(addprefix arch/$(LINUX_KARCH)/,$(KERNEL_FILES_ARCH))
+
+KERNEL_FILES := $(patsubst $(TOPDIR)/%,%,$(wildcard $(addprefix $(LINUX_DIR)/,$(KERNEL_FILES_BASE))))
+
+all: compile
+
+$(BIN_DIR)/$(SDK_NAME).tar.xz: clean
+	mkdir -p $(SDK_BUILD_DIR)/dl $(SDK_BUILD_DIR)/package
+	$(CP) -L $(INCLUDE_DIR) $(SCRIPT_DIR) $(SDK_BUILD_DIR)/
+	$(TAR) -cf - -C $(TOPDIR) \
+		`cd $(TOPDIR); find $(KDIR_BASE) -name \*.ko` \
+		`cd $(TOPDIR); find $(KDIR_BASE)/firmware/ -newer $(KDIR_BASE)/firmware/Makefile \
+			-type f -name '*.bin' -or -name '*.cis' -or -name '*.csp' -or -name '*.dsp' -or -name '*.fw'` \
+		$(foreach exclude,$(EXCLUDE_DIRS),--exclude="$(exclude)") \
+		$(SDK_DIRS) $(KERNEL_FILES) | \
+		$(TAR) -xf - -C $(SDK_BUILD_DIR)
+
+	@-( \
+		find \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_HOST)/bin \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_HOST)/usr/bin \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_TOOLCHAIN)/bin \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_TOOLCHAIN)/*/bin \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_TOOLCHAIN)/libexec \
+			-type f; \
+		find \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_HOST)/lib \
+			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_HOST)/usr/lib \
+			-type f -name \*.so\* -or -name \*.a; \
+	) | xargs strip 2>/dev/null >/dev/null
+
+	mkdir -p $(SDK_BUILD_DIR)/target/linux
+	$(CP) $(GENERIC_PLATFORM_DIR) $(PLATFORM_DIR) $(SDK_BUILD_DIR)/target/linux/
+	rm -rf \
+		$(SDK_BUILD_DIR)/target/linux/*/files* \
+		$(SDK_BUILD_DIR)/target/linux/*/patches*
+	./convert-config.pl $(TOPDIR)/.config > $(SDK_BUILD_DIR)/Config-build.in
+	$(CP) -L \
+		$(TOPDIR)/LICENSE \
+		$(TOPDIR)/rules.mk \
+		./files/Config.in \
+		./files/Makefile \
+		./files/include/prepare.mk \
+		./files/README.SDK \
+		$(SDK_BUILD_DIR)/
+	$(CP) \
+		$(TOPDIR)/package/Makefile \
+		$(TOPDIR)/package/libs/toolchain \
+		$(TOPDIR)/package/kernel/linux \
+		$(SDK_BUILD_DIR)/package/
+
+	-rm -f $(SDK_BUILD_DIR)/feeds.conf.default
+	$(if $(BASE_FEED),echo "$(BASE_FEED)" > $(SDK_BUILD_DIR)/feeds.conf.default)
+	if [ -f $(TOPDIR)/feeds.conf ]; then \
+		cat $(TOPDIR)/feeds.conf >> $(SDK_BUILD_DIR)/feeds.conf.default; \
+	else \
+		cat $(TOPDIR)/feeds.conf.default >> $(SDK_BUILD_DIR)/feeds.conf.default; \
+	fi
+	$(SED) 's,^# REVISION:=.*,REVISION:=$(REVISION),g' $(SDK_BUILD_DIR)/include/version.mk
+	$(SED) 's,^# SOURCE_DATE_EPOCH:=.*,SOURCE_DATE_EPOCH:=$(SOURCE_DATE_EPOCH),g' $(SDK_BUILD_DIR)/include/version.mk
+	$(SED) '/LINUX_VERMAGIC:=/ { s,unknown,$(LINUX_VERMAGIC),g }' $(SDK_BUILD_DIR)/include/kernel.mk
+	find $(SDK_BUILD_DIR) -name .git | $(XARGS) rm -rf
+	find $(SDK_BUILD_DIR) -name .svn | $(XARGS) rm -rf
+	find $(SDK_BUILD_DIR) -name CVS | $(XARGS) rm -rf
+	(cd $(BUILD_DIR); \
+		tar -I 'xz -7e' -cf $@ $(SDK_NAME); \
+	)
+
+download:
+prepare:
+compile: $(BIN_DIR)/$(SDK_NAME).tar.xz
+install: compile
+
+clean:
+	rm -rf $(SDK_BUILD_DIR) $(BIN_DIR)/$(SDK_NAME).tar.xz
diff --git a/target/sdk/convert-config.pl b/target/sdk/convert-config.pl
new file mode 100755
index 0000000000..f73744af09
--- /dev/null
+++ b/target/sdk/convert-config.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/env perl
+use strict;
+
+while (<>) {
+	my $match;
+	my $var;
+	my $val;
+	my $type;
+	chomp;
+	next if /^CONFIG_SIGNED_PACKAGES/;
+
+	if (/^CONFIG_([^=]+)=(.*)$/) {
+		$var = $1;
+		$val = $2;
+
+		next if $var eq 'ALL';
+
+		if ($val eq 'y') {
+			$type = "bool";
+		} elsif ($val eq 'm') {
+			$type = "tristate";
+		} elsif ($val =~ /^".*"$/) {
+			$type = "string";
+		} elsif ($val =~ /^\d+$/) {
+			$type = "int";
+		} else {
+			warn "WARNING: no type found for symbol CONFIG_$var=$val\n";
+			next;
+		}
+	} elsif (/^# CONFIG_BUSYBOX_(.*) is not set/) {
+		$var = "BUSYBOX_$1";
+		$val = 'n';
+		$type = "bool";
+	} else {
+		# We don't want to preserve a record of deselecting
+		# packages because we may want build them in the SDK.
+		# non-package configs however may be important to preserve
+		# the same compilation settings for packages that get
+		# recompiled in the SDK.
+		# Also we want avoid preserving image generation settings
+		# because we set those while in ImageBuilder
+		next if /^(# )?CONFIG_PACKAGE/;
+		next if /^(# )?CONFIG_TARGET/;
+		if (/^# CONFIG_(.*) is not set/) {
+			$var = $1;
+			$val = 'n';
+			$type = "bool";
+                }
+	}
+
+	if (($var ne '') && ($type ne '') && ($val ne '')) {
+		print <<EOF;
+config $var
+	$type
+	default $val
+
+EOF
+	}
+}
diff --git a/target/sdk/files/Config.in b/target/sdk/files/Config.in
new file mode 100644
index 0000000000..0614f31d60
--- /dev/null
+++ b/target/sdk/files/Config.in
@@ -0,0 +1,31 @@
+menu "Global build settings"
+
+	config ALL_NONSHARED
+		bool "Select all target specific packages by default"
+		default ALL
+
+	config ALL_KMODS
+		bool "Select all kernel module packages by default"
+		default ALL
+
+	config ALL
+		bool "Select all userspace packages by default"
+		default y
+
+	config SIGNED_PACKAGES
+		bool "Cryptographically sign package lists"
+		default y
+
+endmenu
+
+config IN_SDK
+	default y
+	bool
+
+config MODULES
+	bool
+	default y
+	option modules
+
+source "Config-build.in"
+source "tmp/.config-package.in"
diff --git a/target/sdk/files/Makefile b/target/sdk/files/Makefile
new file mode 100644
index 0000000000..2edf7b3a20
--- /dev/null
+++ b/target/sdk/files/Makefile
@@ -0,0 +1,59 @@
+# Makefile for OpenWrt
+#
+# Copyright (C) 2007-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+TOPDIR:=${CURDIR}
+LC_ALL:=C
+LANG:=C
+SDK:=1
+export TOPDIR LC_ALL LANG SDK
+
+world:
+
+include $(TOPDIR)/include/host.mk
+
+ifneq ($(OPENWRT_BUILD),1)
+  override OPENWRT_BUILD=1
+  export OPENWRT_BUILD
+
+  empty:=
+  space:= $(empty) $(empty)
+  _SINGLE=export MAKEFLAGS=$(space);
+
+  include $(TOPDIR)/include/debug.mk
+  include $(TOPDIR)/include/depends.mk
+  include $(TOPDIR)/include/toplevel.mk
+else
+  include rules.mk
+  include $(INCLUDE_DIR)/depends.mk
+  include $(INCLUDE_DIR)/subdir.mk
+  include package/Makefile
+
+$(package/stamp-compile): $(BUILD_DIR)/.prepared
+$(BUILD_DIR)/.prepared: Makefile
+	@mkdir -p $$(dirname $@)
+	@touch $@
+
+clean: FORCE
+	git clean -f -d $(STAGING_DIR); true
+	git clean -f -d $(BUILD_DIR); true
+	git clean -f -d $(BIN_DIR); true
+
+dirclean: clean
+	git reset --hard HEAD
+	git clean -f -d
+	rm -rf feeds/
+
+# check prerequisites before starting to build
+prereq: $(package/stamp-prereq) ;
+
+world: prepare $(package/stamp-compile) FORCE
+	@$(MAKE) package/index
+
+.PHONY: clean dirclean prereq prepare world
+
+endif
diff --git a/target/sdk/files/README.SDK b/target/sdk/files/README.SDK
new file mode 100644
index 0000000000..6f04f94d2c
--- /dev/null
+++ b/target/sdk/files/README.SDK
@@ -0,0 +1,11 @@
+This is the LEDE SDK. It contains a stripped-down version of
+the buildroot. You can use it to test/develop packages without
+having to compile your own toolchain or any of the libraries
+included with LEDE.
+
+To use it, just put your buildroot-compatible package directory
+(including its dependencies) in the subdir 'package/' and run
+'make' from this directory.
+
+To make dependency handling easier, you can use ./scripts/feeds
+to install any core package that you need
diff --git a/target/sdk/files/include/prepare.mk b/target/sdk/files/include/prepare.mk
new file mode 100644
index 0000000000..76bad05a02
--- /dev/null
+++ b/target/sdk/files/include/prepare.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+prepare: .git/config
+
+.git/config:
+	@( \
+		printf "Initializing SDK ... "; \
+		git init -q .; \
+		find . -mindepth 1 -maxdepth 1 -not -name feeds | xargs git add; \
+		git commit -q -m "Initial state"; \
+		echo "ok."; \
+	)
diff --git a/target/toolchain/Config.in b/target/toolchain/Config.in
new file mode 100644
index 0000000000..c7548d4f28
--- /dev/null
+++ b/target/toolchain/Config.in
@@ -0,0 +1,8 @@
+config MAKE_TOOLCHAIN
+	bool "Package the libreCMC-based Toolchain"
+	depends on !EXTERNAL_TOOLCHAIN
+	help
+	  Package the created toolchain as a tarball under the bin/ directory as
+	  libreCMC-Toolchain-$(BOARD)-for-$(ARCH)$(ARCH_SUFFIX)-gcc-$(GCCV)$(DIR_SUFFIX).
+	  For example, a toolchain for the MIPS architecture might be named
+	  libreCMC-Toolchain-malta-for-mipsel_mips32-gcc-4.8-linaro_uClibc-0.9.33.2.tar.bz2.
diff --git a/target/toolchain/Makefile b/target/toolchain/Makefile
new file mode 100644
index 0000000000..2fcda3e25f
--- /dev/null
+++ b/target/toolchain/Makefile
@@ -0,0 +1,72 @@
+#
+# Copyright (C) 2008-2009 Industrie Dial Face S.p.A.
+#               Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com>
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/host.mk
+include $(INCLUDE_DIR)/version.mk
+
+override MAKEFLAGS=
+
+TOOLCHAIN_NAME:=$(VERSION_DIST_SANITIZED)-toolchain-$(if $(CONFIG_VERSION_FILENAMES),$(VERSION_NUMBER)-)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))_gcc-$(GCCV)$(DIR_SUFFIX).$(HOST_OS)-$(HOST_ARCH)
+TOOLCHAIN_BUILD_DIR:=$(BUILD_DIR)/$(TOOLCHAIN_NAME)
+EXCLUDE_DIRS:=*/ccache \
+	*/initial \
+	*/stamp \
+	*/stampfiles \
+	*/man \
+	*/info
+
+all: compile
+
+TOOLCHAIN_PREFIX:=$(TOOLCHAIN_BUILD_DIR)/toolchain-$(ARCH)$(ARCH_SUFFIX)_gcc-$(GCCV)$(DIR_SUFFIX)
+
+$(BIN_DIR)/$(TOOLCHAIN_NAME).tar.bz2: clean
+	mkdir -p $(TOOLCHAIN_BUILD_DIR)
+	$(TAR) -cf - -C $(TOPDIR)/staging_dir/  \
+	       $(foreach exclude,$(EXCLUDE_DIRS),--exclude="$(exclude)") \
+	       toolchain-$(ARCH)$(ARCH_SUFFIX)_gcc-$(GCCV)$(DIR_SUFFIX) | \
+	       $(TAR) -xf - -C $(TOOLCHAIN_BUILD_DIR)
+
+	$(CP)  $(TOPDIR)/LICENSE ./files/README.TOOLCHAIN \
+		$(TOOLCHAIN_BUILD_DIR)/
+
+	$(CP) ./files/wrapper.sh $(TOOLCHAIN_PREFIX)/bin/$(REAL_GNU_TARGET_NAME)-wrapper.sh
+	chmod +x $(TOOLCHAIN_PREFIX)/bin/$(REAL_GNU_TARGET_NAME)-wrapper.sh
+	(cd $(TOOLCHAIN_PREFIX)/bin; \
+		for app in cc gcc g++ c++ cpp ld as ; do \
+			[ -f $(REAL_GNU_TARGET_NAME)-$${app} ] && mv $(REAL_GNU_TARGET_NAME)-$${app} $(REAL_GNU_TARGET_NAME)-$${app}.bin ; \
+			ln -sf $(REAL_GNU_TARGET_NAME)-wrapper.sh $(REAL_GNU_TARGET_NAME)-$${app} ; \
+		done; \
+	)
+
+	@-( \
+		find \
+			$(TOOLCHAIN_BUILD_DIR)/*/bin \
+			$(TOOLCHAIN_BUILD_DIR)/*/*/bin \
+			$(TOOLCHAIN_BUILD_DIR)/*/libexec \
+			-type f; \
+	) | xargs strip 2>/dev/null >/dev/null
+
+	echo REVISION:="$(REVISION)" > $(TOOLCHAIN_BUILD_DIR)/version.mk
+	find $(TOOLCHAIN_BUILD_DIR) -name .git | $(XARGS) rm -rf
+	find $(TOOLCHAIN_BUILD_DIR) -name .svn | $(XARGS) rm -rf
+	find $(TOOLCHAIN_BUILD_DIR) -name CVS | $(XARGS) rm -rf
+	mkdir -p $(BIN_DIR)
+	(cd $(BUILD_DIR); \
+		tar cfj $@ $(TOOLCHAIN_NAME); \
+	)
+
+download:
+prepare:
+compile: $(BIN_DIR)/$(TOOLCHAIN_NAME).tar.bz2
+install: compile
+
+clean:
+	rm -rf $(TOOLCHAIN_BUILD_DIR) $(BIN_DIR)/$(TOOLCHAIN_NAME).tar.bz2
diff --git a/target/toolchain/files/README.TOOLCHAIN b/target/toolchain/files/README.TOOLCHAIN
new file mode 100644
index 0000000000..86b0189d35
--- /dev/null
+++ b/target/toolchain/files/README.TOOLCHAIN
@@ -0,0 +1,2 @@
+This is the LEDE SDK. It contains just the toolchain created
+by buildroot.
diff --git a/target/toolchain/files/wrapper.sh b/target/toolchain/files/wrapper.sh
new file mode 100755
index 0000000000..2b760840d8
--- /dev/null
+++ b/target/toolchain/files/wrapper.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+
+# 2009 (C) Copyright Industrie Dial Face S.p.A.
+#          Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com>
+#
+# Based on original idea from WindRiver
+#
+# Toolchain wrapper script.
+#
+# This script allows us to use a small number of GCC / binutils cross-tools
+# (one toolchain per instruction set architecture) to implement a larger
+# number of processor- or board-specific tools.  The wrapper script is
+# configured at install time with information covering basic CFLAGS,
+# LD options and the toolchain triplet name.
+#
+
+PROGNAME=$0
+REALNAME=`readlink -f $0`
+
+REALNAME_BASE=`basename $REALNAME`
+REALNAME_DIR=`dirname $REALNAME`
+
+TARGET_FUNDAMENTAL_ASFLAGS=''
+TARGET_FUNDAMENTAL_CFLAGS=''
+TARGET_ROOTFS_CFLAGS=''
+TARGET_FUNDAMENTAL_LDFLAGS=''
+TARGET_TOOLCHAIN_TRIPLET=${REALNAME_BASE%-*}
+
+# Parse our tool name, splitting it at '-' characters.
+BINARY=${PROGNAME##*-}
+
+# Parse our tool name, splitting it at '-' characters.
+IFS=- read TOOLCHAIN_ARCH TOOLCHAIN_BUILDROOT TOOLCHAIN_OS TOOLCHAIN_PLATFORM PROGNAME << EOF
+$REALNAME_BASE
+EOF
+
+#
+# We add the directory this was executed from to the PATH
+# The toolchains (links) should be in this directory or in the users
+# PATH.
+#
+TOOLCHAIN_BIN_DIR="$REALNAME_DIR/"
+
+# Set the PATH so that our run-time location is first
+# (get_feature is run from the path, so this has to be set)
+export PATH="$TOOLCHAIN_BIN_DIR":$PATH
+export GCC_HONOUR_COPTS
+
+TOOLCHAIN_SYSROOT="$TOOLCHAIN_BIN_DIR/../.."
+if [ ! -d "$TOOLCHAIN_SYSROOT" ]; then
+  echo "Error: Unable to determine sysroot (looking for $TOOLCHAIN_SYSROOT)!" >&2
+  exit 1
+fi
+
+# -Wl,--dynamic-linker=$TOOLCHAIN_SYSROOT/lib/ld-uClibc.so.0 
+# --dynamic-linker=$TOOLCHAIN_SYSROOT/lib/ld-uClibc.so.0 
+
+case $TOOLCHAIN_PLATFORM in
+   gnu|glibc|eglibc)
+	GCC_SYSROOT_FLAGS="--sysroot=$TOOLCHAIN_SYSROOT -Wl,-rpath=$TOOLCHAIN_SYSROOT/lib:$TOOLCHAIN_SYSROOT/usr/lib"
+	LD_SYSROOT_FLAGS="-rpath=$TOOLCHAIN_SYSROOT/lib:$TOOLCHAIN_SYSROOT/usr/lib"
+       ;;
+   uclibc)
+	GCC_SYSROOT_FLAGS="--sysroot=$TOOLCHAIN_SYSROOT -Wl,-rpath=$TOOLCHAIN_SYSROOT/lib:$TOOLCHAIN_SYSROOT/usr/lib"
+	LD_SYSROOT_FLAGS="-rpath=$TOOLCHAIN_SYSROOT/lib:$TOOLCHAIN_SYSROOT/usr/lib"
+       ;;
+   musl)
+	GCC_SYSROOT_FLAGS="--sysroot=$TOOLCHAIN_SYSROOT -Wl,-rpath=$TOOLCHAIN_SYSROOT/lib:$TOOLCHAIN_SYSROOT/usr/lib"
+	LD_SYSROOT_FLAGS="-rpath=$TOOLCHAIN_SYSROOT/lib:$TOOLCHAIN_SYSROOT/usr/lib"
+       ;;
+   *)
+	GCC_SYSROOT_FLAGS=""
+	LD_SYSROOT_FLAGS=""
+       ;;
+esac
+
+#
+# Run the cross-tool.
+#
+case $BINARY in
+	cc|gcc|g++|c++|cpp)
+		exec $TARGET_TOOLCHAIN_TRIPLET-$BINARY.bin $GCC_SYSROOT_FLAGS $TARGET_FUNDAMENTAL_CFLAGS $TARGET_ROOTFS_CFLAGS "$@"
+		;;
+	ld)
+		exec $TARGET_TOOLCHAIN_TRIPLET-$BINARY.bin $LD_SYSROOT_FLAGS $TARGET_FUNDAMENTAL_LDFLAGS "$@"
+		;;
+	as)
+		exec $TARGET_TOOLCHAIN_TRIPLET-$BINARY.bin $TARGET_FUNDAMENTAL_ASFLAGS "$@"
+		;;
+	*)
+		exec $TARGET_TOOLCHAIN_TRIPLET-$BINARY.bin "$@"
+		;;
+esac
+
+exit 0
diff --git a/toolchain/Config.in b/toolchain/Config.in
new file mode 100644
index 0000000000..b53b8e63ec
--- /dev/null
+++ b/toolchain/Config.in
@@ -0,0 +1,337 @@
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+menuconfig TARGET_OPTIONS
+	bool "Target Options"  if DEVEL
+
+	config TARGET_OPTIMIZATION
+		string "Target Optimizations" if TARGET_OPTIONS
+		default DEFAULT_TARGET_OPTIMIZATION
+		help
+		  Optimizations to use when building for the target host.
+
+	config SOFT_FLOAT
+		bool "Use software floating point by default" if TARGET_OPTIONS
+		default y if !HAS_FPU
+		depends on arm || armeb || powerpc || mipsel || mips || mips64el || mips64
+		help
+		  If your target CPU does not have a Floating Point Unit (FPU) or a
+		  kernel FPU emulator, but you still wish to support floating point
+		  functions, then everything will need to be compiled with soft floating
+		  point support (-msoft-float).
+
+		  Most people will answer N.
+
+	config USE_MIPS16
+		bool "Build packages with MIPS16 instructions" if TARGET_OPTIONS
+		depends on HAS_MIPS16
+		default y
+		help
+		  If your target CPU does support the MIPS16 instruction set
+		  and you want to use it for packages, enable this option.
+		  MIPS16 produces smaller binaries thus reducing pressure on
+		  caches and TLB.
+
+		  Most people will answer N.
+
+
+menuconfig EXTERNAL_TOOLCHAIN
+	bool
+	prompt "Use external toolchain"  if DEVEL
+	help
+	  If enabled, LEDE will compile using an existing toolchain instead of
+	  compiling one.
+
+	config NATIVE_TOOLCHAIN
+		bool
+		prompt "Use host's toolchain"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN
+		select NO_STRIP
+		help
+		  If enabled, LEDE will compile using the native toolchain for your
+		  host instead of compiling one.
+
+	config TARGET_NAME
+		string
+		prompt "Target name"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "aarch64-unknown-linux-gnu"  if aarch64
+		default "aarch64_be-unknown-linux-gnu"  if aarch64_be
+		default "arm-unknown-linux-gnu"      if arm
+		default "armeb-unknown-linux-gnu"    if armeb
+		default "i486-unknown-linux-gnu"     if i386
+		default "mips-unknown-linux-gnu"     if mips
+		default "mipsel-unknown-linux-gnu"   if mipsel
+		default "powerpc-unknown-linux-gnu"  if powerpc
+		default "x86_64-unknown-linux-gnu"   if x86_64
+
+	config TOOLCHAIN_PREFIX
+		string
+		prompt "Toolchain prefix"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "aarch64-unknown-linux-gnu"  if aarch64
+		default "aarch64_be-unknown-linux-gnu"  if aarch64_be
+		default "arm-unknown-linux-gnu-"      if arm
+		default "armeb-unknown-linux-gnu-"    if armeb
+		default "i486-unknown-linux-gnu-"     if i386
+		default "mips-unknown-linux-gnu-"     if mips
+		default "mipsel-unknown-linux-gnu-"   if mipsel
+		default "powerpc-unknown-linux-gnu-"  if powerpc
+		default "x86_64-unknown-linux-gnu-"   if x86_64
+
+	config TOOLCHAIN_ROOT
+		string
+		prompt "Toolchain root"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "/opt/cross/aarch64-unknown-linux-gnu"  if aarch64
+		default "/opt/cross/aarch64_be-unknown-linux-gnu"  if aarch64_be
+		default "/opt/cross/arm-unknown-linux-gnu"      if arm
+		default "/opt/cross/armeb-unknown-linux-gnu"    if armeb
+		default "/opt/cross/i486-unknown-linux-gnu"     if i386
+		default "/opt/cross/mips-unknown-linux-gnu"     if mips
+		default "/opt/cross/mipsel-unknown-linux-gnu"   if mipsel
+		default "/opt/cross/powerpc-unknown-linux-gnu"  if powerpc
+		default "/opt/cross/x86_64-unknown-linux-gnu"   if x86_64
+
+	choice TOOLCHAIN_LIBC_TYPE
+		prompt "Toolchain libc"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default EXTERNAL_TOOLCHAIN_LIBC_USE_MUSL
+		help
+		  Specify the libc type used by the external toolchain. The given value
+		  is passed as -m flag to all gcc and g++ invocations. This is mainly
+		  intended for multilib toolchains which support glibc and uclibc at
+		  the same time. If no value is specified, no -m flag is passed.
+
+		config EXTERNAL_TOOLCHAIN_LIBC_USE_GLIBC
+			bool "glibc"
+			select USE_GLIBC
+
+		config EXTERNAL_TOOLCHAIN_LIBC_USE_UCLIBC
+			bool "uClibc"
+			select USE_UCLIBC
+			depends on !(aarch64 || aarch64_be)
+
+		config EXTERNAL_TOOLCHAIN_LIBC_USE_MUSL
+			bool "musl"
+			select USE_MUSL
+
+	endchoice
+
+	config TOOLCHAIN_LIBC
+		string
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "glibc" if EXTERNAL_TOOLCHAIN_LIBC_USE_GLIBC
+		default "uclibc" if EXTERNAL_TOOLCHAIN_LIBC_USE_UCLIBC
+		default "musl" if EXTERNAL_TOOLCHAIN_LIBC_USE_MUSL
+
+	config TOOLCHAIN_BIN_PATH
+		string
+		prompt "Toolchain program path"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "./usr/bin ./bin"
+		help
+		  Specify additional directories searched for toolchain binaries
+		  (override PATH). Use ./DIR for directories relative to the root above.
+
+	config TOOLCHAIN_INC_PATH
+		string
+		prompt "Toolchain include path"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "./usr/include ./include"
+		help
+		  Specify additional directories searched for header files (override
+		  CPPFLAGS). Use ./DIR for directories relative to the root above.
+
+	config TOOLCHAIN_LIB_PATH
+		string
+		prompt "Toolchain library path"  if DEVEL
+		depends on EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN
+		default "./usr/lib ./lib"
+		help
+		  Specify additional directories searched for libraries (override LDFLAGS).
+		  Use ./DIR for directories relative to the root above.
+
+config NEED_TOOLCHAIN
+	bool
+	depends on DEVEL
+	default y if !EXTERNAL_TOOLCHAIN
+
+menuconfig TOOLCHAINOPTS
+	bool "Toolchain Options"  if DEVEL
+	depends on NEED_TOOLCHAIN
+
+menuconfig EXTRA_TARGET_ARCH
+	bool
+	prompt "Enable an extra toolchain target architecture" if TOOLCHAINOPTS
+	depends on !sparc
+	default y	if powerpc64
+	default n
+	help
+	  Some builds may require a 'biarch' toolchain. This option
+	  allows you to specify an additional target arch.
+
+	  Most people will answer N here.
+
+	config EXTRA_TARGET_ARCH_NAME
+		string
+		default "powerpc64"	if powerpc64
+		prompt "Extra architecture name" if EXTRA_TARGET_ARCH
+		help
+		  Specify the cpu name (eg powerpc64 or x86_64) of the
+		  additional target architecture.
+
+	config EXTRA_TARGET_ARCH_OPTS
+		string
+		default "-m64"		if powerpc64
+		prompt "Extra architecture compiler options" if EXTRA_TARGET_ARCH
+		help
+		  If you're specifying an addition target architecture,
+		  you'll probably need to also provide options to make
+		  the compiler use this alternate arch.
+
+		  For example, if you're building a compiler that can build
+		  both powerpc and powerpc64 binaries, you'll need to
+		  specify -m64 here.
+
+
+	choice
+		prompt "MIPS64 user-land ABI" if TOOLCHAINOPTS && (mips64 || mips64el)
+		default MIPS64_ABI_N64
+		help
+		   MIPS64 supports 3 different user-land ABIs: o32 (legacy),
+		   n32 and n64.
+
+		config MIPS64_ABI_N64
+			bool "n64"
+
+		config MIPS64_ABI_N32
+			depends on !LIBC_USE_MUSL
+			bool "n32"
+
+		config MIPS64_ABI_O32
+			bool "o32"
+
+	endchoice
+
+comment "Binary tools"
+	depends on TOOLCHAINOPTS
+
+source "toolchain/binutils/Config.in"
+
+comment "Compiler"
+	depends on TOOLCHAINOPTS
+
+source "toolchain/gcc/Config.in"
+
+config YASM
+	bool
+	depends on ( i386 || x86_64 )
+	prompt "Build yasm" if TOOLCHAINOPTS
+	default y
+	help
+	  Enable if you want to build yasm
+
+comment "C Library"
+	depends on TOOLCHAINOPTS
+
+choice
+	prompt "C Library implementation" if TOOLCHAINOPTS
+	default LIBC_USE_UCLIBC if arc
+	default LIBC_USE_MUSL
+	help
+	  Select the C library implementation.
+
+	config LIBC_USE_GLIBC
+		bool "Use glibc"
+		select USE_GLIBC
+		depends on !arc
+
+	config LIBC_USE_UCLIBC
+		select USE_UCLIBC
+		bool "Use uClibc"
+		depends on !(aarch64 || aarch64_be)
+		depends on BROKEN || !(arm || armeb || i386 || x86_64 || mips || mipsel || mips64 || mips64el || powerpc)
+
+	config LIBC_USE_MUSL
+		select USE_MUSL
+		bool "Use musl"
+		depends on !(arc)
+
+endchoice
+
+source "toolchain/glibc/Config.in"
+source "toolchain/uClibc/Config.in"
+
+comment "Debuggers"
+	depends on TOOLCHAINOPTS
+
+config GDB
+	bool
+	depends on !(aarch64 || aarch64_be)
+	prompt "Build gdb" if TOOLCHAINOPTS
+	default y if !EXTERNAL_TOOLCHAIN
+	help
+	  Enable if you want to build the gdb.
+
+config INSIGHT
+	bool
+	prompt "Build insight-gdb" if TOOLCHAINOPTS
+	select GDB
+	default n
+	help
+	  Enable if you want to build insight-gdb.
+
+config USE_GLIBC
+	bool
+
+config USE_UCLIBC
+	default y if !TOOLCHAINOPTS && !EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN && (arc)
+	bool
+
+config USE_MUSL
+	default y if !TOOLCHAINOPTS && !EXTERNAL_TOOLCHAIN && !NATIVE_TOOLCHAIN && !(arc)
+	bool
+
+config USE_EXTERNAL_LIBC
+	bool
+	default y if EXTERNAL_TOOLCHAIN || NATIVE_TOOLCHAIN
+
+source "toolchain/binutils/Config.version"
+source "toolchain/gcc/Config.version"
+
+source "toolchain/glibc/Config.version"
+source "toolchain/uClibc/Config.version"
+source "toolchain/musl/Config.version"
+
+config LIBC
+	string
+	default "glibc"   if USE_GLIBC
+	default "uClibc"  if USE_UCLIBC
+	default "musl"	  if USE_MUSL
+
+config LIBC_VERSION
+	string
+	default GLIBC_VERSION   if USE_GLIBC
+	default UCLIBC_VERSION  if USE_UCLIBC
+	default MUSL_VERSION	if USE_MUSL
+
+config TARGET_SUFFIX
+	string
+	default "gnueabi"         if USE_GLIBC && (arm || armeb)
+	default "gnu"             if USE_GLIBC && !(arm || armeb)
+	default "uclibcgnueabi"   if USE_UCLIBC && (arm || armeb)
+	default "uclibc"          if USE_UCLIBC && !(arm || armeb)
+	default "muslgnueabi"     if USE_MUSL && (arm || armeb)
+	default "musl"            if USE_MUSL && !(arm || armeb)
+
+config MIPS64_ABI
+	depends on mips64 || mips64el
+	string
+	default "64" if MIPS64_ABI_N64
+	default "n32" if MIPS64_ABI_N32
+	default "32" if MIPS64_ABI_O32
+	default "64"
diff --git a/toolchain/Makefile b/toolchain/Makefile
new file mode 100644
index 0000000000..a656a86b0d
--- /dev/null
+++ b/toolchain/Makefile
@@ -0,0 +1,91 @@
+# 
+# Copyright (C) 2007-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# Main makefile for the toolchain
+#
+# Steps:
+# 1) toolchain/binutils/install
+#    build & install binutils
+# 2) toolchain/gcc/minimal/install
+#    build & install a minimal gcc, needed for steps 3 & 4
+# 3) toolchain/kernel-headers/install
+#    install kernel headers, needed for step 4
+# 4) toolchain/libc/headers/install
+#    build & install libc headers & support files, needed for step 5
+# 5) toolchain/gcc/initial/install
+#    build & install an initial gcc, needed for step 6
+# 6) toolchain/libc/install
+#    build & install the final libc
+# 7) toolchain/gcc/final/install
+#    build & install the final gcc
+# 8) toolchain/libc/utils/install
+#    build & install libc utilities
+#
+# For musl, steps 2 and 4 are skipped, and step 3 is done after 5
+
+curdir:=toolchain
+
+# subdirectories to descend into
+$(curdir)/builddirs := $(if $(CONFIG_GDB),gdb) $(if $(CONFIG_INSIGHT),insight) $(if $(CONFIG_EXTERNAL_TOOLCHAIN),wrapper,kernel-headers binutils gcc/initial gcc/final $(LIBC) fortify-headers) $(if $(CONFIG_YASM),yasm)
+ifdef CONFIG_USE_UCLIBC
+  $(curdir)/builddirs += $(LIBC)/utils
+endif
+
+# builddir dependencies
+ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+  ifdef CONFIG_USE_MUSL
+    $(curdir)/kernel-headers/compile:=$(curdir)/gcc/initial/install
+    $(curdir)/$(LIBC)/compile:=$(curdir)/kernel-headers/install
+  else
+    $(curdir)/builddirs += $(LIBC)/headers gcc/minimal
+    $(curdir)/gcc/minimal/compile:=$(curdir)/binutils/install
+    $(curdir)/kernel-headers/compile:=$(curdir)/gcc/minimal/install
+    $(curdir)/gcc/initial/prepare:=$(curdir)/gcc/minimal/prepare
+    $(curdir)/$(LIBC)/prepare:=$(curdir)/$(LIBC)/headers/prepare
+    $(curdir)/$(LIBC)/headers/compile:=$(curdir)/kernel-headers/install
+    $(curdir)/gcc/initial/compile:=$(curdir)/$(LIBC)/headers/install
+  endif
+
+  $(curdir)/gcc/initial/compile+=$(curdir)/binutils/install
+  $(curdir)/gcc/final/prepare:=$(curdir)/gcc/initial/prepare
+  $(curdir)/$(LIBC)/compile:=$(curdir)/gcc/initial/install
+  $(curdir)/gcc/final/compile:=$(curdir)/$(LIBC)/install
+  $(curdir)/$(LIBC)/utils/compile:=$(curdir)/gcc/final/install
+  $(curdir)/$(LIBC)/utils/prepare:=$(curdir)/$(LIBC)/headers/prepare
+endif
+
+$(curdir)/builddirs-compile:=$($(curdir)/builddirs-prepare)
+$(curdir)/builddirs-install:=$($(curdir)/builddirs-compile)
+
+ifndef DUMP_TARGET_DB
+ifneq ($(ARCH),)
+  $(TOOLCHAIN_DIR)/info.mk: .config
+	@for dir in $(TOOLCHAIN_DIR); do ( \
+		$(if $(QUIET),,set -x;) \
+		mkdir -p "$$dir"; \
+		cd "$$dir"; \
+		ln -nsf lib lib64; \
+		ln -nsf lib lib32; \
+		mkdir -p stamp lib usr/include usr/lib ; \
+	); done
+	@grep GCC_VERSION $@ >/dev/null 2>&1 || $(INSTALL_DATA) $(TOPDIR)/toolchain/info.mk $@
+	@touch $@
+endif
+endif
+
+# prerequisites for the individual targets
+$(curdir)/ := .config prereq
+$(curdir)//prepare = $(STAGING_DIR)/.prepared $(TOOLCHAIN_DIR)/info.mk $(tools/stamp-install)
+$(curdir)//compile = $(1)/prepare
+$(curdir)//install = $(1)/compile
+
+ifndef DUMP_TARGET_DB
+$(TOOLCHAIN_DIR)/stamp/.gcc-initial_installed:
+endif
+
+$(eval $(call stampfile,$(curdir),toolchain,install,$(TOOLCHAIN_DIR)/stamp/.gcc-initial_installed,,$(TOOLCHAIN_DIR)))
+$(eval $(call subdir,$(curdir)))
+
diff --git a/toolchain/binutils/Config.in b/toolchain/binutils/Config.in
new file mode 100644
index 0000000000..9e535c4b99
--- /dev/null
+++ b/toolchain/binutils/Config.in
@@ -0,0 +1,32 @@
+# Choose binutils version.
+
+choice
+	prompt "Binutils Version" if TOOLCHAINOPTS
+	default BINUTILS_USE_VERSION_2_25_1 if !arc
+	default BINUTILS_USE_VERSION_2_26_ARC if arc
+	help
+	  Select the version of binutils you wish to use.
+
+	config BINUTILS_USE_VERSION_2_25_1
+		depends on !arc
+		bool "Binutils 2.25.1"
+		select BINUTILS_VERSION_2_25_1
+
+	config BINUTILS_USE_VERSION_2_27
+		depends on !arc
+		bool "Binutils 2.27"
+		select BINUTILS_VERSION_2_27
+
+	config BINUTILS_USE_VERSION_2_26_ARC
+		depends on arc
+		bool "ARC binutils 2.26"
+		select BINUTILS_VERSION_2_26_ARC
+
+endchoice
+
+config EXTRA_BINUTILS_CONFIG_OPTIONS
+	string
+	prompt "Additional binutils configure options" if TOOLCHAINOPTS
+	default ""
+	help
+	    Any additional binutils options you may want to include....
diff --git a/toolchain/binutils/Config.version b/toolchain/binutils/Config.version
new file mode 100644
index 0000000000..5ef8df6085
--- /dev/null
+++ b/toolchain/binutils/Config.version
@@ -0,0 +1,17 @@
+config BINUTILS_VERSION_2_25_1
+	default y if (!TOOLCHAINOPTS && !arc)
+	bool
+
+config BINUTILS_VERSION_2_27
+	bool
+
+config BINUTILS_VERSION_2_26_ARC
+	default y if (!TOOLCHAINOPTS && arc)
+	bool
+
+config BINUTILS_VERSION
+	string
+	default "2.25.1"               if BINUTILS_VERSION_2_25_1
+	default "2.27"		       if BINUTILS_VERSION_2_27
+	default "arc-2016.03"          if BINUTILS_VERSION_2_26_ARC
+
diff --git a/toolchain/binutils/Makefile b/toolchain/binutils/Makefile
new file mode 100644
index 0000000000..8816dda518
--- /dev/null
+++ b/toolchain/binutils/Makefile
@@ -0,0 +1,127 @@
+#
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=binutils
+PKG_VERSION:=$(call qstrip,$(CONFIG_BINUTILS_VERSION))
+BIN_VERSION:=$(PKG_VERSION)
+
+PKG_SOURCE_URL:=@GNU/binutils/
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+
+ifeq ($(PKG_VERSION),2.25.1)
+  PKG_MD5SUM:=ac493a78de4fee895961d025b7905be4
+endif
+
+ifeq ($(PKG_VERSION),2.26.1)
+  PKG_MD5SUM:=d2b24e5b5301b7ff0207414c34c3e0fb
+endif
+
+ifeq ($(PKG_VERSION),2.27)
+  PKG_MD5SUM:=2869c9bf3e60ee97c74ac2a6bf4e9d68
+endif
+
+ifeq ($(findstring linaro, $(CONFIG_BINUTILS_VERSION)),linaro)
+  PKG_SOURCE_URL:=https://releases.linaro.org/14.09/components/toolchain/binutils-linaro/
+  PKG_REV:=2.24.0-2014.09
+  PKG_SOURCE:=$(PKG_NAME)-linaro-$(PKG_REV).tar.xz
+  PKG_MD5SUM:=8f9b2b2e049d59b1b86ce9657802a353
+  BINUTILS_DIR:=$(PKG_NAME)-linaro-$(PKG_REV)
+  HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(BINUTILS_DIR)
+endif
+
+ifneq ($(CONFIG_BINUTILS_VERSION_2_26_ARC),)
+  PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/arc-2016.03/
+  PKG_REV:=2016.03
+  PKG_SOURCE:=$(PKG_NAME)-arc-$(PKG_REV).tar.gz
+  PKG_MD5SUM:=d4387bab089df77a8049c81980b9fa12
+  BINUTILS_DIR:=$(PKG_NAME)-gdb-arc-$(PKG_REV)
+  HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(BINUTILS_DIR)
+endif
+
+HOST_BUILD_PARALLEL:=1
+
+PATCH_DIR:=./patches/$(PKG_VERSION)
+
+REAL_STAGING_DIR_HOST:=$(STAGING_DIR_HOST)
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+BINUTILS_CONFIGURE:= \
+	./configure \
+		--prefix=$(TOOLCHAIN_DIR) \
+		--build=$(GNU_HOST_NAME) \
+		--host=$(GNU_HOST_NAME) \
+		--target=$(REAL_GNU_TARGET_NAME) \
+		--with-sysroot=$(TOOLCHAIN_DIR) \
+		--enable-deterministic-archives \
+		--enable-plugins \
+		--disable-multilib \
+		--disable-werror \
+		--disable-nls \
+		--disable-sim \
+		--disable-gdb \
+		$(GRAPHITE_CONFIGURE) \
+		$(SOFT_FLOAT_CONFIG_OPTION) \
+		$(call qstrip,$(CONFIG_EXTRA_BINUTILS_CONFIG_OPTIONS)) 
+
+ifneq ($(CONFIG_SSP_SUPPORT),)
+  BINUTILS_CONFIGURE+= \
+		--enable-libssp
+else
+  BINUTILS_CONFIGURE+= \
+		--disable-libssp
+endif
+
+ifneq ($(CONFIG_EXTRA_TARGET_ARCH),)
+  BINUTILS_CONFIGURE+= \
+		--enable-targets=$(call qstrip,$(CONFIG_EXTRA_TARGET_ARCH_NAME))-linux-$(TARGET_SUFFIX)
+endif
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	ln -snf $(notdir $(HOST_BUILD_DIR)) $(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+	$(CP) $(SCRIPT_DIR)/config.{guess,sub} $(HOST_BUILD_DIR)/
+	$(SED) 's, " Linaro.*,,' $(HOST_BUILD_DIR)/bfd/version.h
+endef
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR); \
+		$(BINUTILS_CONFIGURE) \
+	);
+endef
+
+define Host/Compile
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) all
+endef
+
+define Host/Install
+	mkdir -p $(TOOLCHAIN_DIR)/initial
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		prefix=$(TOOLCHAIN_DIR)/initial \
+		install
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		prefix=$(TOOLCHAIN_DIR) \
+		install
+	$(call FixupLibdir,$(TOOLCHAIN_DIR)/initial)
+	$(RM) $(TOOLCHAIN_DIR)/initial/lib/libiberty.a
+	$(CP) $(TOOLCHAIN_DIR)/bin/$(REAL_GNU_TARGET_NAME)-readelf $(REAL_STAGING_DIR_HOST)/bin/readelf
+	# ARC gcc requires extlib.
+	# If extlib is not available in "initial" folder
+	# initial gcc will fail to build libc.
+	if [ -d $(TOOLCHAIN_DIR)/extlib ]; then \
+		$(CP) -r $(TOOLCHAIN_DIR)/extlib $(TOOLCHAIN_DIR)/initial/; \
+	fi
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/binutils/patches/2.25.1/300-001_ld_makefile_patch.patch b/toolchain/binutils/patches/2.25.1/300-001_ld_makefile_patch.patch
new file mode 100644
index 0000000000..c51fc003fd
--- /dev/null
+++ b/toolchain/binutils/patches/2.25.1/300-001_ld_makefile_patch.patch
@@ -0,0 +1,22 @@
+--- a/ld/Makefile.am
++++ b/ld/Makefile.am
+@@ -54,7 +54,7 @@ endif
+ # We put the scripts in the directory $(scriptdir)/ldscripts.
+ # We can't put the scripts in $(datadir) because the SEARCH_DIR
+ # directives need to be different for native and cross linkers.
+-scriptdir = $(tooldir)/lib
++scriptdir = $(libdir)
+ 
+ EMUL = @EMUL@
+ EMULATION_OFILES = @EMULATION_OFILES@
+--- a/ld/Makefile.in
++++ b/ld/Makefile.in
+@@ -388,7 +388,7 @@ AM_CFLAGS = $(WARN_CFLAGS)
+ # We put the scripts in the directory $(scriptdir)/ldscripts.
+ # We can't put the scripts in $(datadir) because the SEARCH_DIR
+ # directives need to be different for native and cross linkers.
+-scriptdir = $(tooldir)/lib
++scriptdir = $(libdir)
+ BASEDIR = $(srcdir)/..
+ BFDDIR = $(BASEDIR)/bfd
+ INCDIR = $(BASEDIR)/include
diff --git a/toolchain/binutils/patches/2.25.1/300-012_check_ldrunpath_length.patch b/toolchain/binutils/patches/2.25.1/300-012_check_ldrunpath_length.patch
new file mode 100644
index 0000000000..2e24b38cad
--- /dev/null
+++ b/toolchain/binutils/patches/2.25.1/300-012_check_ldrunpath_length.patch
@@ -0,0 +1,20 @@
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -1198,6 +1198,8 @@ fragment <<EOF
+ 	      && command_line.rpath == NULL)
+ 	    {
+ 	      lib_path = (const char *) getenv ("LD_RUN_PATH");
++	      if ((lib_path) && (strlen (lib_path) == 0))
++	      	lib_path = NULL;
+ 	      if (gld${EMULATION_NAME}_search_needed (lib_path, &n,
+ 						      force))
+ 		break;
+@@ -1461,6 +1463,8 @@ gld${EMULATION_NAME}_before_allocation (
+   rpath = command_line.rpath;
+   if (rpath == NULL)
+     rpath = (const char *) getenv ("LD_RUN_PATH");
++  if ((rpath) && (strlen (rpath) == 0))
++  	rpath = NULL;
+ 
+   for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next)
+     if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
diff --git a/toolchain/binutils/patches/2.25.1/400-mips_no_dynamic_linking_sym.patch b/toolchain/binutils/patches/2.25.1/400-mips_no_dynamic_linking_sym.patch
new file mode 100644
index 0000000000..a63203d1cc
--- /dev/null
+++ b/toolchain/binutils/patches/2.25.1/400-mips_no_dynamic_linking_sym.patch
@@ -0,0 +1,18 @@
+--- a/bfd/elfxx-mips.c
++++ b/bfd/elfxx-mips.c
+@@ -7689,6 +7689,7 @@ _bfd_mips_elf_create_dynamic_sections (b
+ 
+       name = SGI_COMPAT (abfd) ? "_DYNAMIC_LINK" : "_DYNAMIC_LINKING";
+       bh = NULL;
++      if (0) {
+       if (!(_bfd_generic_link_add_one_symbol
+ 	    (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 0,
+ 	     NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+@@ -7701,6 +7702,7 @@ _bfd_mips_elf_create_dynamic_sections (b
+ 
+       if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ 	return FALSE;
++      }
+ 
+       if (! mips_elf_hash_table (info)->use_rld_obj_head)
+ 	{
diff --git a/toolchain/binutils/patches/2.25.1/500-Change-default-emulation-for-mips64-linux.patch b/toolchain/binutils/patches/2.25.1/500-Change-default-emulation-for-mips64-linux.patch
new file mode 100644
index 0000000000..3343a85661
--- /dev/null
+++ b/toolchain/binutils/patches/2.25.1/500-Change-default-emulation-for-mips64-linux.patch
@@ -0,0 +1,37 @@
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -1062,12 +1062,12 @@ case "${targ}" in
+     targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_be_vec mips_ecoff_le_vec"
+     ;;
+   mips64*el-*-linux*)
+-    targ_defvec=mips_elf32_ntrad_le_vec
+-    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec"
++    targ_defvec=mips_elf64_trad_le_vec
++    targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_be_vec"
+     ;;
+   mips64*-*-linux*)
+-    targ_defvec=mips_elf32_ntrad_be_vec
+-    targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec"
++    targ_defvec=mips_elf64_trad_be_vec
++    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_le_vec"
+     ;;
+   mips*el-*-linux*)
+     targ_defvec=mips_elf32_trad_le_vec
+--- a/ld/configure.tgt
++++ b/ld/configure.tgt
+@@ -476,11 +476,11 @@ mips*el-*-vxworks*)	targ_emul=elf32elmip
+ mips*-*-vxworks*)	targ_emul=elf32ebmipvxworks
+ 		        targ_extra_emuls="elf32elmipvxworks" ;;
+ mips*-*-windiss)	targ_emul=elf32mipswindiss ;;
+-mips64*el-*-linux-*)	targ_emul=elf32ltsmipn32
+-			targ_extra_emuls="elf32btsmipn32 elf32ltsmip elf32btsmip elf64ltsmip elf64btsmip"
++mips64*el-*-linux-*)	targ_emul=elf64ltsmip
++			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32ltsmip elf32btsmip elf64btsmip"
+ 			targ_extra_libpath=$targ_extra_emuls ;;
+-mips64*-*-linux-*)	targ_emul=elf32btsmipn32
+-			targ_extra_emuls="elf32ltsmipn32 elf32btsmip elf32ltsmip elf64btsmip elf64ltsmip"
++mips64*-*-linux-*)	targ_emul=elf64btsmip
++			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32btsmip elf32ltsmip elf64ltsmip"
+ 			targ_extra_libpath=$targ_extra_emuls ;;
+ mips*el-*-linux-*)	targ_emul=elf32ltsmip
+ 			targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip"
diff --git a/toolchain/binutils/patches/2.27/300-001_ld_makefile_patch.patch b/toolchain/binutils/patches/2.27/300-001_ld_makefile_patch.patch
new file mode 100644
index 0000000000..e4cec7f69e
--- /dev/null
+++ b/toolchain/binutils/patches/2.27/300-001_ld_makefile_patch.patch
@@ -0,0 +1,22 @@
+--- a/ld/Makefile.am
++++ b/ld/Makefile.am
+@@ -57,7 +57,7 @@ endif
+ # We put the scripts in the directory $(scriptdir)/ldscripts.
+ # We can't put the scripts in $(datadir) because the SEARCH_DIR
+ # directives need to be different for native and cross linkers.
+-scriptdir = $(tooldir)/lib
++scriptdir = $(libdir)
+ 
+ EMUL = @EMUL@
+ EMULATION_OFILES = @EMULATION_OFILES@
+--- a/ld/Makefile.in
++++ b/ld/Makefile.in
+@@ -451,7 +451,7 @@ AM_CFLAGS = $(WARN_CFLAGS) $(ELF_CLFAGS)
+ # We put the scripts in the directory $(scriptdir)/ldscripts.
+ # We can't put the scripts in $(datadir) because the SEARCH_DIR
+ # directives need to be different for native and cross linkers.
+-scriptdir = $(tooldir)/lib
++scriptdir = $(libdir)
+ BASEDIR = $(srcdir)/..
+ BFDDIR = $(BASEDIR)/bfd
+ INCDIR = $(BASEDIR)/include
diff --git a/toolchain/binutils/patches/2.27/300-012_check_ldrunpath_length.patch b/toolchain/binutils/patches/2.27/300-012_check_ldrunpath_length.patch
new file mode 100644
index 0000000000..95d3f75b85
--- /dev/null
+++ b/toolchain/binutils/patches/2.27/300-012_check_ldrunpath_length.patch
@@ -0,0 +1,20 @@
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -1244,6 +1244,8 @@ fragment <<EOF
+ 	      && command_line.rpath == NULL)
+ 	    {
+ 	      lib_path = (const char *) getenv ("LD_RUN_PATH");
++	      if ((lib_path) && (strlen (lib_path) == 0))
++	      	lib_path = NULL;
+ 	      if (gld${EMULATION_NAME}_search_needed (lib_path, &n,
+ 						      force))
+ 		break;
+@@ -1525,6 +1527,8 @@ gld${EMULATION_NAME}_before_allocation (
+   rpath = command_line.rpath;
+   if (rpath == NULL)
+     rpath = (const char *) getenv ("LD_RUN_PATH");
++  if ((rpath) && (strlen (rpath) == 0))
++  	rpath = NULL;
+ 
+   for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next)
+     if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
diff --git a/toolchain/binutils/patches/2.27/400-mips_no_dynamic_linking_sym.patch b/toolchain/binutils/patches/2.27/400-mips_no_dynamic_linking_sym.patch
new file mode 100644
index 0000000000..b7458e58aa
--- /dev/null
+++ b/toolchain/binutils/patches/2.27/400-mips_no_dynamic_linking_sym.patch
@@ -0,0 +1,18 @@
+--- a/bfd/elfxx-mips.c
++++ b/bfd/elfxx-mips.c
+@@ -7713,6 +7713,7 @@ _bfd_mips_elf_create_dynamic_sections (b
+ 
+       name = SGI_COMPAT (abfd) ? "_DYNAMIC_LINK" : "_DYNAMIC_LINKING";
+       bh = NULL;
++      if (0) {
+       if (!(_bfd_generic_link_add_one_symbol
+ 	    (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 0,
+ 	     NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+@@ -7725,6 +7726,7 @@ _bfd_mips_elf_create_dynamic_sections (b
+ 
+       if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ 	return FALSE;
++      }
+ 
+       if (! mips_elf_hash_table (info)->use_rld_obj_head)
+ 	{
diff --git a/toolchain/binutils/patches/2.27/500-Change-default-emulation-for-mips64-linux.patch b/toolchain/binutils/patches/2.27/500-Change-default-emulation-for-mips64-linux.patch
new file mode 100644
index 0000000000..7a8f0ae13a
--- /dev/null
+++ b/toolchain/binutils/patches/2.27/500-Change-default-emulation-for-mips64-linux.patch
@@ -0,0 +1,37 @@
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -1101,12 +1101,12 @@ case "${targ}" in
+     targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_be_vec mips_ecoff_le_vec"
+     ;;
+   mips64*el-*-linux*)
+-    targ_defvec=mips_elf32_ntrad_le_vec
+-    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec"
++    targ_defvec=mips_elf64_trad_le_vec
++    targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_be_vec"
+     ;;
+   mips64*-*-linux*)
+-    targ_defvec=mips_elf32_ntrad_be_vec
+-    targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec"
++    targ_defvec=mips_elf64_trad_be_vec
++    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_le_vec"
+     ;;
+   mips*el-*-linux*)
+     targ_defvec=mips_elf32_trad_le_vec
+--- a/ld/configure.tgt
++++ b/ld/configure.tgt
+@@ -513,11 +513,11 @@ mips*el-*-vxworks*)	targ_emul=elf32elmip
+ mips*-*-vxworks*)	targ_emul=elf32ebmipvxworks
+ 		        targ_extra_emuls="elf32elmipvxworks" ;;
+ mips*-*-windiss)	targ_emul=elf32mipswindiss ;;
+-mips64*el-*-linux-*)	targ_emul=elf32ltsmipn32
+-			targ_extra_emuls="elf32btsmipn32 elf32ltsmip elf32btsmip elf64ltsmip elf64btsmip"
++mips64*el-*-linux-*)	targ_emul=elf64ltsmip
++			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32ltsmip elf32btsmip elf64btsmip"
+ 			targ_extra_libpath=$targ_extra_emuls ;;
+-mips64*-*-linux-*)	targ_emul=elf32btsmipn32
+-			targ_extra_emuls="elf32ltsmipn32 elf32btsmip elf32ltsmip elf64btsmip elf64ltsmip"
++mips64*-*-linux-*)	targ_emul=elf64btsmip
++			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32btsmip elf32ltsmip elf64ltsmip"
+ 			targ_extra_libpath=$targ_extra_emuls ;;
+ mips*el-*-linux-*)	targ_emul=elf32ltsmip
+ 			targ_extra_emuls="elf32btsmip elf32ltsmipn32 elf64ltsmip elf32btsmipn32 elf64btsmip"
diff --git a/toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch b/toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch
new file mode 100644
index 0000000000..7e51d588ae
--- /dev/null
+++ b/toolchain/binutils/patches/arc-2016.03/200-arc-fix-target-mask.patch
@@ -0,0 +1,13 @@
+diff --git a/bfd/config.bfd b/bfd/config.bfd
+index 5145d4a..a9c9c99 100644
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -275,7 +275,7 @@ case "${targ}" in
+     targ_defvec=am33_elf32_linux_vec
+     ;;
+ 
+-  arc*-*-elf* | arc*-*-linux-uclibc*)
++  arc*-*-elf* | arc*-*-linux-*)
+     targ_defvec=arc_elf32_le_vec
+     targ_selvecs=arc_elf32_be_vec
+     ;;
diff --git a/toolchain/fortify-headers/Makefile b/toolchain/fortify-headers/Makefile
new file mode 100644
index 0000000000..6f273a4c59
--- /dev/null
+++ b/toolchain/fortify-headers/Makefile
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+PKG_NAME:=fortify-headers
+PKG_VERSION:=0.8
+PKG_RELEASE=1
+
+PKG_SOURCE_URL:=http://dl.2f30.org/releases
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_MD5SUM:=678ebdac0c3278b934c6524cd1e3dc4c
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+define Host/Compile
+	true
+endef
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) PREFIX="" DESTDIR="$(TOOLCHAIN_DIR)" install
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in
new file mode 100644
index 0000000000..41ea61cb8a
--- /dev/null
+++ b/toolchain/gcc/Config.in
@@ -0,0 +1,80 @@
+# Choose gcc version.
+
+choice
+	prompt "GCC compiler Version" if TOOLCHAINOPTS
+	default GCC_USE_VERSION_4_8_ARC if arc
+	default GCC_USE_VERSION_5
+	help
+	  Select the version of gcc you wish to use.
+
+	config GCC_USE_VERSION_4_8_ARC
+		select GCC_VERSION_4_8_ARC
+		bool "gcc 4.8.x with support of ARC cores"
+		depends on arc
+
+	config GCC_USE_VERSION_5
+		bool "gcc 5.x"
+		depends on !arc
+
+	config GCC_USE_VERSION_6
+		bool "gcc 6.x"
+		depends on !arc
+
+endchoice
+
+config GCC_USE_GRAPHITE
+	bool
+	prompt "Compile in support for the new Graphite framework in GCC 4.4+" if TOOLCHAINOPTS
+
+config GCC_USE_SYSTEM_PPL_CLOOG
+	bool
+	prompt "Use the system versions of PPL and CLooG"
+	depends on GCC_USE_GRAPHITE && GCC_VERSION_4_8
+	default n
+
+config EXTRA_GCC_CONFIG_OPTIONS
+	string
+	prompt "Additional gcc configure options" if TOOLCHAINOPTS
+	default ""
+	help
+	    Any additional gcc options you may want to include....
+
+config SSP_SUPPORT
+	bool
+	prompt "Enable Stack-Smashing Protection support" if TOOLCHAINOPTS
+	depends on !USE_MUSL
+	default y if !USE_MUSL
+	help
+	    Enable Stack-Smashing Protection support
+
+config SJLJ_EXCEPTIONS
+	bool
+	prompt "Use setjump()/longjump() exceptions" if TOOLCHAINOPTS
+	default n
+	help
+	    Use old setjump()/longjump() exceptions instead of the newer
+	    frame unwinding exceptions handling routines.  Warning: increases
+	    code size and runtime memory usage.
+
+config INSTALL_LIBGCJ
+	bool
+	prompt "Build/install java compiler and GNU classpath ?" if TOOLCHAINOPTS
+	default n
+	help
+	    Build/install java compiler and GNU classpath ?
+
+
+config INSTALL_GFORTRAN
+	bool
+	prompt "Build/install fortran compiler?" if TOOLCHAINOPTS
+	default n
+	help
+	    Build/install GNU fortran compiler ?
+
+config INSTALL_GCCGO
+	bool
+	prompt "Build/install Go compiler?" if TOOLCHAINOPTS
+	depends on !GCC_VERSION_4_8 && (USE_GLIBC || BROKEN)
+	default n
+	help
+	    Build/install GNU gccgo compiler ?
diff --git a/toolchain/gcc/Config.version b/toolchain/gcc/Config.version
new file mode 100644
index 0000000000..27aa20cb39
--- /dev/null
+++ b/toolchain/gcc/Config.version
@@ -0,0 +1,13 @@
+config GCC_VERSION_4_8_ARC
+	default y if (!TOOLCHAINOPTS && arc)
+	bool
+
+config GCC_VERSION
+	string
+	default "arc-2016.03"   if GCC_VERSION_4_8_ARC
+	default "6.2.0"         if GCC_USE_VERSION_6
+	default "5.4.0"
+
+config GCC_VERSION_4_8
+	bool
+	default y	if GCC_VERSION_4_8_ARC
diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk
new file mode 100644
index 0000000000..c6949dc7b4
--- /dev/null
+++ b/toolchain/gcc/common.mk
@@ -0,0 +1,221 @@
+#
+# Copyright (C) 2002-2003 Erik Andersen <andersen@uclibc.org>
+# Copyright (C) 2004 Manuel Novoa III <mjn3@uclibc.org>
+# Copyright (C) 2005-2006 Felix Fietkau <nbd@nbd.name>
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gcc
+GCC_VERSION:=$(call qstrip,$(CONFIG_GCC_VERSION))
+PKG_VERSION:=$(firstword $(subst +, ,$(GCC_VERSION)))
+GCC_DIR:=$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_SOURCE_URL:=@GNU/gcc/gcc-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+
+ifeq ($(PKG_VERSION),5.4.0)
+  PKG_MD5SUM:=4c626ac2a83ef30dfb9260e6f59c2b30
+endif
+
+ifeq ($(PKG_VERSION),6.2.0)
+  PKG_MD5SUM:=9768625159663b300ae4de2f4745fcc4
+endif
+
+ifneq ($(CONFIG_GCC_VERSION_4_8_ARC),)
+    PKG_VERSION:=4.8.5
+    PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/gcc/archive/arc-2016.03
+    PKG_SOURCE:=$(PKG_NAME)-$(GCC_VERSION).tar.gz
+    PKG_MD5SUM:=ca59c8140d6efd07b97a18869bddbb53
+    PKG_REV:=2016.03
+    GCC_DIR:=gcc-arc-$(PKG_REV)
+    HOST_BUILD_DIR = $(BUILD_DIR_HOST)/$(PKG_NAME)-$(GCC_VERSION)
+endif
+
+PATCH_DIR=../patches/$(GCC_VERSION)
+
+BUGURL=http://www.lede-project.org/bugs/
+PKGVERSION=LEDE GCC $(PKG_VERSION) $(REVISION)
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+HOST_SOURCE_DIR:=$(HOST_BUILD_DIR)
+ifeq ($(GCC_VARIANT),minimal)
+  GCC_BUILD_DIR:=$(HOST_BUILD_DIR)-$(GCC_VARIANT)
+else
+  HOST_BUILD_DIR:=$(HOST_BUILD_DIR)-$(GCC_VARIANT)
+  GCC_BUILD_DIR:=$(HOST_BUILD_DIR)
+endif
+
+HOST_STAMP_PREPARED:=$(HOST_BUILD_DIR)/.prepared
+HOST_STAMP_BUILT:=$(GCC_BUILD_DIR)/.built
+HOST_STAMP_CONFIGURED:=$(GCC_BUILD_DIR)/.configured
+HOST_STAMP_INSTALLED:=$(STAGING_DIR_HOST)/stamp/.gcc_$(GCC_VARIANT)_installed
+
+SEP:=,
+TARGET_LANGUAGES:="c,c++$(if $(CONFIG_INSTALL_LIBGCJ),$(SEP)java)$(if $(CONFIG_INSTALL_GFORTRAN),$(SEP)fortran)$(if $(CONFIG_INSTALL_GCCGO),$(SEP)go)"
+
+export libgcc_cv_fixed_point=no
+ifdef CONFIG_USE_UCLIBC
+  export glibcxx_cv_c99_math_tr1=no
+endif
+ifdef CONFIG_INSTALL_GCCGO
+  export libgo_cv_c_split_stack_supported=no
+endif
+
+ifdef CONFIG_GCC_USE_GRAPHITE
+  ifdef CONFIG_GCC_VERSION_4_8
+    GRAPHITE_CONFIGURE=--with-cloog=$(REAL_STAGING_DIR_HOST)
+  else
+    GRAPHITE_CONFIGURE=--with-isl=$(REAL_STAGING_DIR_HOST)
+  endif
+else
+  GRAPHITE_CONFIGURE=--without-isl --without-cloog
+endif
+
+GCC_CONFIGURE:= \
+	SHELL="$(BASH)" \
+	$(if $(shell gcc --version 2>&1 | grep LLVM), \
+		CFLAGS="-O2 -fbracket-depth=512 -pipe" \
+		CXXFLAGS="-O2 -fbracket-depth=512 -pipe" \
+	) \
+	$(HOST_SOURCE_DIR)/configure \
+		--with-bugurl=$(BUGURL) \
+		--with-pkgversion="$(PKGVERSION)" \
+		--prefix=$(TOOLCHAIN_DIR) \
+		--build=$(GNU_HOST_NAME) \
+		--host=$(GNU_HOST_NAME) \
+		--target=$(REAL_GNU_TARGET_NAME) \
+		--with-gnu-ld \
+		--enable-target-optspace \
+		--disable-libgomp \
+		--disable-libmudflap \
+		--disable-multilib \
+		--disable-libmpx \
+		--disable-nls \
+		$(GRAPHITE_CONFIGURE) \
+		--with-host-libstdcxx=-lstdc++ \
+		$(SOFT_FLOAT_CONFIG_OPTION) \
+		$(call qstrip,$(CONFIG_EXTRA_GCC_CONFIG_OPTIONS)) \
+		$(if $(CONFIG_mips64)$(CONFIG_mips64el),--with-arch=mips64 \
+			--with-abi=$(call qstrip,$(CONFIG_MIPS64_ABI))) \
+		$(if $(CONFIG_arc),--with-cpu=$(CONFIG_CPU_TYPE)) \
+		--with-gmp=$(TOPDIR)/staging_dir/host \
+		--with-mpfr=$(TOPDIR)/staging_dir/host \
+		--with-mpc=$(TOPDIR)/staging_dir/host \
+		--disable-decimal-float
+ifneq ($(CONFIG_mips)$(CONFIG_mipsel),)
+  GCC_CONFIGURE += --with-mips-plt
+endif
+
+ifndef GCC_VERSION_4_8
+  GCC_CONFIGURE += --with-diagnostics-color=auto-if-env
+endif
+
+ifneq ($(CONFIG_SSP_SUPPORT),)
+  GCC_CONFIGURE+= \
+		--enable-libssp
+else
+  GCC_CONFIGURE+= \
+		--disable-libssp
+endif
+
+ifneq ($(CONFIG_EXTRA_TARGET_ARCH),)
+  GCC_CONFIGURE+= \
+		--enable-biarch \
+		--enable-targets=$(call qstrip,$(CONFIG_EXTRA_TARGET_ARCH_NAME))-linux-$(TARGET_SUFFIX)
+endif
+
+ifdef CONFIG_sparc
+  GCC_CONFIGURE+= \
+		--enable-targets=all \
+		--with-long-double-128
+endif
+
+ifeq ($(LIBC),uClibc)
+  GCC_CONFIGURE+= \
+		--disable-__cxa_atexit
+else
+  GCC_CONFIGURE+= \
+		--enable-__cxa_atexit
+endif
+
+ifneq ($(GCC_ARCH),)
+  GCC_CONFIGURE+= --with-arch=$(GCC_ARCH)
+endif
+
+ifneq ($(CONFIG_SOFT_FLOAT),y)
+  ifeq ($(CONFIG_arm),y)
+    GCC_CONFIGURE+= \
+		--with-float=hard
+  endif
+endif
+
+ifeq ($(CONFIG_TARGET_x86)$(CONFIG_USE_GLIBC)$(CONFIG_INSTALL_GCCGO),yyy)
+  TARGET_CFLAGS+=-fno-split-stack
+endif
+
+GCC_MAKE:= \
+	export SHELL="$(BASH)"; \
+	$(MAKE) \
+		CFLAGS="$(HOST_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(TARGET_CFLAGS)" \
+		CXXFLAGS_FOR_TARGET="$(TARGET_CFLAGS)" \
+		GOCFLAGS_FOR_TARGET="$(TARGET_CFLAGS)"
+
+define Host/SetToolchainInfo
+	$(SED) 's,TARGET_CROSS=.*,TARGET_CROSS=$(REAL_GNU_TARGET_NAME)-,' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,GCC_VERSION=.*,GCC_VERSION=$(GCC_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+endef
+
+ifneq ($(GCC_PREPARE),)
+  define Host/Prepare
+	$(call Host/SetToolchainInfo)
+	$(call Host/Prepare/Default)
+	ln -snf $(GCC_DIR) $(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+	$(CP) $(SCRIPT_DIR)/config.{guess,sub} $(HOST_SOURCE_DIR)/
+	$(SED) 's,^MULTILIB_OSDIRNAMES,# MULTILIB_OSDIRNAMES,' $(HOST_SOURCE_DIR)/gcc/config/*/t-*
+	$(SED) 'd' $(HOST_SOURCE_DIR)/gcc/DEV-PHASE
+	$(SED) 's, DATESTAMP,,' $(HOST_SOURCE_DIR)/gcc/version.c
+	#(cd $(HOST_SOURCE_DIR)/libstdc++-v3; autoconf;);
+	$(SED) 's,gcc_no_link=yes,gcc_no_link=no,' $(HOST_SOURCE_DIR)/libstdc++-v3/configure
+	mkdir -p $(GCC_BUILD_DIR)
+  endef
+else
+  define Host/Prepare
+	mkdir -p $(GCC_BUILD_DIR)
+  endef
+endif
+
+define Host/Configure
+	(cd $(GCC_BUILD_DIR) && rm -f config.cache; \
+		$(GCC_CONFIGURE) \
+	);
+endef
+
+define Host/Clean
+	rm -rf $(if $(GCC_PREPARE),$(HOST_SOURCE_DIR)) \
+		$(STAGING_DIR_HOST)/stamp/.gcc_* \
+		$(STAGING_DIR_HOST)/stamp/.binutils_* \
+		$(GCC_BUILD_DIR) \
+		$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME) \
+		$(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME) \
+		$(TOOLCHAIN_DIR)/bin/$(REAL_GNU_TARGET_NAME)-gc* \
+		$(TOOLCHAIN_DIR)/bin/$(REAL_GNU_TARGET_NAME)-c*
+endef
diff --git a/toolchain/gcc/files/alternate-arch-cc.in b/toolchain/gcc/files/alternate-arch-cc.in
new file mode 100644
index 0000000000..e169951ebe
--- /dev/null
+++ b/toolchain/gcc/files/alternate-arch-cc.in
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec @CC_BASE@ @EXTRA_ARCH_OPTS@ "$@"
diff --git a/toolchain/gcc/final/Makefile b/toolchain/gcc/final/Makefile
new file mode 100644
index 0000000000..01fec38027
--- /dev/null
+++ b/toolchain/gcc/final/Makefile
@@ -0,0 +1,87 @@
+GCC_VARIANT:=final
+
+include ../common.mk
+
+GCC_CONFIGURE += \
+	--with-headers=$(TOOLCHAIN_DIR)/include \
+	--disable-libsanitizer \
+	--enable-languages=$(TARGET_LANGUAGES) \
+	--enable-shared \
+	--enable-threads \
+	--with-slibdir=$(TOOLCHAIN_DIR)/lib \
+	--enable-lto \
+	--with-libelf=$(TOPDIR)/staging_dir/host
+
+ifdef CONFIG_USE_MUSL
+  GCC_MAKE += gcc_cv_libc_provides_ssp=yes
+endif
+
+ifneq ($(CONFIG_SJLJ_EXCEPTIONS),)
+  GCC_CONFIGURE += \
+	--enable-sjlj-exceptions
+endif
+
+define CleanupToolchain
+	$(INSTALL_DIR) $(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME)
+	# Important!  Required for limits.h to be fixed.
+	rm -rf $(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include
+	ln -sf ../include $(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include
+	rm -rf $(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME)/lib
+	ln -sf ../lib $(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME)/lib
+	$(if $(CONFIG_ARCH_64BIT),ln -sf ../lib64 $(TOOLCHAIN_DIR)/$(REAL_GNU_TARGET_NAME)/lib64)
+endef
+
+define Host/Configure
+	$(CleanupToolchain)
+	mkdir -p $(GCC_BUILD_DIR)
+	(cd $(GCC_BUILD_DIR) && rm -f config.cache; \
+		$(GCC_CONFIGURE) \
+	);
+endef
+
+ifeq ($(CONFIG_USE_GLIBC)$(CONFIG_INSTALL_GCCGO),yy)
+define FixGogccCrt
+	# link crtX.o for gotools
+	mkdir -p $(GCC_BUILD_DIR)/gotools
+	$(foreach crt, i 1 n, ln -sf ../../glibc-dev/lib/crt$(crt).o $(GCC_BUILD_DIR)/gotools/ ; )
+endef
+endif
+
+define Host/Compile
+	$(FixGogccCrt)
+	+$(GCC_MAKE) $(HOST_JOBS) -C $(GCC_BUILD_DIR) all
+endef
+
+define SetupExtraArch
+	for app in $(TOOLCHAIN_DIR)/bin/$(OPTIMIZE_FOR_CPU)*-{gcc,gcc-*,g++}; do \
+		[ -e $$$$app ] || continue; \
+		old_base=$$$$(basename $$$$app); \
+		new_base=$(call qstrip,$(CONFIG_EXTRA_TARGET_ARCH_NAME))-$$$${old_base##$(OPTIMIZE_FOR_CPU)-}; \
+		sed -e "s/@CC_BASE@/$$$$old_base/" \
+			-e 's/@EXTRA_ARCH_OPTS@/$(call qstrip,$(CONFIG_EXTRA_TARGET_ARCH_OPTS))/' \
+			 ../files/alternate-arch-cc.in > \
+			 $(TOOLCHAIN_DIR)/bin/$$$$new_base; \
+		chmod a+x $(TOOLCHAIN_DIR)/bin/$$$$new_base; \
+	done
+endef
+
+define Host/Install
+	$(CleanupToolchain)
+	$(_SINGLE)$(GCC_MAKE) -C $(GCC_BUILD_DIR) install
+	# Set up the symlinks to enable lying about target name.
+	set -e; \
+	(cd $(TOOLCHAIN_DIR); \
+		ln -sf $(REAL_GNU_TARGET_NAME) $(GNU_TARGET_NAME); \
+		cd bin; \
+		for app in $(REAL_GNU_TARGET_NAME)-* ; do \
+			ln -sf $$$${app} \
+		   	$(GNU_TARGET_NAME)$$$${app##$(REAL_GNU_TARGET_NAME)}; \
+		done; \
+	);
+	$(if $(CONFIG_EXTRA_TARGET_ARCH),$(call SetupExtraArch))
+	$(RM) $(TOOLCHAIN_DIR)/lib/libiberty.a
+	$(SCRIPT_DIR)/patch-specs.sh "$(TOOLCHAIN_DIR)"
+endef
+
+$(eval $(call HostBuild))
+
diff --git a/toolchain/gcc/initial/Makefile b/toolchain/gcc/initial/Makefile
new file mode 100644
index 0000000000..1ed548436e
--- /dev/null
+++ b/toolchain/gcc/initial/Makefile
@@ -0,0 +1,36 @@
+GCC_VARIANT:=initial
+GCC_PREPARE=$(CONFIG_USE_MUSL)
+
+include ../common.mk
+
+GCC_CONFIGURE += \
+	--with-newlib \
+	--with-sysroot=$(TOOLCHAIN_DIR) \
+	--enable-languages=c \
+	--disable-shared \
+	--disable-threads \
+
+define Host/Compile
+	+$(GCC_MAKE) $(HOST_JOBS) -C $(GCC_BUILD_DIR) \
+		all-build-libiberty \
+		all-gcc \
+		all-target-libgcc
+endef
+
+define Host/Install
+	$(GCC_MAKE) -C $(GCC_BUILD_DIR) \
+		prefix="$(TOOLCHAIN_DIR)/initial" \
+		install-gcc \
+		install-target-libgcc
+
+	# XXX: glibc insists on linking against libgcc_eh
+	( cd $(TOOLCHAIN_DIR)/initial/lib/gcc/$(REAL_GNU_TARGET_NAME)/$(PKG_VERSION) ; \
+		[ -e libgcc_eh.a ] || ln -sf libgcc.a libgcc_eh.a ; \
+		cp libgcc.a libgcc_initial.a; \
+	)
+
+	$(call FixupLibdir,$(TOOLCHAIN_DIR)/initial)
+	$$(call file_copy,$(TOOLCHAIN_DIR)/initial/.,$(TOOLCHAIN_DIR)/)
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/gcc/minimal/Makefile b/toolchain/gcc/minimal/Makefile
new file mode 100644
index 0000000000..31d6f675ab
--- /dev/null
+++ b/toolchain/gcc/minimal/Makefile
@@ -0,0 +1,29 @@
+GCC_VARIANT:=minimal
+GCC_PREPARE=$(if $(CONFIG_USE_MUSL),,1)
+
+include ../common.mk
+
+GCC_CONFIGURE += \
+	--with-newlib \
+	--without-headers \
+	--enable-languages=c \
+	--disable-libsanitizer \
+	--disable-libssp \
+	--disable-shared \
+	--disable-threads
+
+define Host/Compile
+	+$(GCC_MAKE) $(HOST_JOBS) -C $(GCC_BUILD_DIR) all-gcc all-target-libgcc
+endef
+
+define Host/Install
+	$(GCC_MAKE) -C $(GCC_BUILD_DIR) install-gcc install-target-libgcc
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(GCC_BUILD_DIR)
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/gcc/patches/5.4.0/001-revert_register_mode_search.patch b/toolchain/gcc/patches/5.4.0/001-revert_register_mode_search.patch
new file mode 100644
index 0000000000..06373eb6a0
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/001-revert_register_mode_search.patch
@@ -0,0 +1,65 @@
+Revert of:
+
+commit 275035b56823b26d5fb7e90fad945b998648edf2
+Author: bergner <bergner@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date:   Thu Sep 5 14:09:07 2013 +0000
+
+        PR target/58139
+        * reginfo.c (choose_hard_reg_mode): Scan through all mode classes
+        looking for widest mode.
+
+
+    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202286 138bc75d-0d04-0410-961f-82ee72b054a4
+
+
+--- a/gcc/reginfo.c
++++ b/gcc/reginfo.c
+@@ -665,35 +665,40 @@ choose_hard_reg_mode (unsigned int regno
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
+   if (found_mode != VOIDmode)
diff --git a/toolchain/gcc/patches/5.4.0/002-case_insensitive.patch b/toolchain/gcc/patches/5.4.0/002-case_insensitive.patch
new file mode 100644
index 0000000000..b3d2dbe291
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/002-case_insensitive.patch
@@ -0,0 +1,14 @@
+--- a/include/filenames.h
++++ b/include/filenames.h
+@@ -43,11 +43,6 @@ extern "C" {
+ #  define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c)
+ #  define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f)
+ #else /* not DOSish */
+-#  if defined(__APPLE__)
+-#    ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+-#      define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1
+-#    endif
+-#  endif /* __APPLE__ */
+ #  define HAS_DRIVE_SPEC(f) (0)
+ #  define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c)
+ #  define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f)
diff --git a/toolchain/gcc/patches/5.4.0/010-documentation.patch b/toolchain/gcc/patches/5.4.0/010-documentation.patch
new file mode 100644
index 0000000000..07064a97bc
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/010-documentation.patch
@@ -0,0 +1,23 @@
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -2941,18 +2941,10 @@ doc/gcc.info: $(TEXI_GCC_FILES)
+ doc/gccint.info: $(TEXI_GCCINT_FILES)
+ doc/cppinternals.info: $(TEXI_CPPINT_FILES)
+ 
+-doc/%.info: %.texi
+-	if [ x$(BUILD_INFO) = xinfo ]; then \
+-		$(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \
+-			-I $(gcc_docdir)/include -o $@ $<; \
+-	fi
++doc/%.info:
+ 
+ # Duplicate entry to handle renaming of gccinstall.info
+-doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES)
+-	if [ x$(BUILD_INFO) = xinfo ]; then \
+-		$(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+-			-I $(gcc_docdir)/include -o $@ $<; \
+-	fi
++doc/gccinstall.info:
+ 
+ doc/cpp.dvi: $(TEXI_CPP_FILES)
+ doc/gcc.dvi: $(TEXI_GCC_FILES)
diff --git a/toolchain/gcc/patches/5.4.0/020-no-plt-backport.patch b/toolchain/gcc/patches/5.4.0/020-no-plt-backport.patch
new file mode 100644
index 0000000000..b9702c9520
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/020-no-plt-backport.patch
@@ -0,0 +1,28 @@
+--- a/gcc/calls.c
++++ b/gcc/calls.c
+@@ -225,6 +225,12 @@ prepare_call_address (tree fndecl_or_typ
+ 	       && targetm.small_register_classes_for_mode_p (FUNCTION_MODE))
+ 	      ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
+ 	      : memory_address (FUNCTION_MODE, funexp));
++  else if (flag_pic && !flag_plt && fndecl_or_type
++	   && TREE_CODE (fndecl_or_type) == FUNCTION_DECL
++	   && !targetm.binds_local_p (fndecl_or_type))
++    {
++      funexp = force_reg (Pmode, funexp);
++    }
+   else if (! sibcallp)
+     {
+ #ifndef NO_FUNCTION_CSE
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1779,6 +1779,10 @@ fpie
+ Common Report Var(flag_pie,1) Negative(fPIC)
+ Generate position-independent code for executables if possible (small mode)
+ 
++fplt
++Common Report Var(flag_plt) Init(1)
++Use PLT for PIC calls (-fno-plt: load the address from GOT at call site)
++
+ fplugin=
+ Common Joined RejectNegative Var(common_deferred_options) Defer
+ Specify a plugin to load
diff --git a/toolchain/gcc/patches/5.4.0/040-fix-mips-ICE-PR-68400.patch b/toolchain/gcc/patches/5.4.0/040-fix-mips-ICE-PR-68400.patch
new file mode 100644
index 0000000000..e88af34032
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/040-fix-mips-ICE-PR-68400.patch
@@ -0,0 +1,23 @@
+--- a/gcc/config/mips/mips.c
++++ b/gcc/config/mips/mips.c
+@@ -8001,9 +8001,17 @@ mask_low_and_shift_p (machine_mode mode,
+ bool
+ and_operands_ok (machine_mode mode, rtx op1, rtx op2)
+ {
+-  return (memory_operand (op1, mode)
+-	  ? and_load_operand (op2, mode)
+-	  : and_reg_operand (op2, mode));
++  if (!memory_operand (op1, mode))
++    return and_reg_operand (op2, mode);
++
++  if (!and_load_operand (op2, mode))
++    return false;
++
++  if (!TARGET_MIPS16 || si_mask_operand(op2, mode))
++    return true;
++
++  op1 = XEXP (op1, 0);
++  return !(REG_P (op1) && REGNO (op1) == STACK_POINTER_REGNUM);
+ }
+ 
+ /* The canonical form of a mask-low-and-shift-left operation is
diff --git a/toolchain/gcc/patches/5.4.0/100-uclibc-conf.patch b/toolchain/gcc/patches/5.4.0/100-uclibc-conf.patch
new file mode 100644
index 0000000000..ff9ad94f62
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/100-uclibc-conf.patch
@@ -0,0 +1,33 @@
+--- a/contrib/regression/objs-gcc.sh
++++ b/contrib/regression/objs-gcc.sh
+@@ -106,6 +106,10 @@ if [ $H_REAL_TARGET = $H_REAL_HOST -a $H
+  then
+   make all-gdb all-dejagnu all-ld || exit 1
+   make install-gdb install-dejagnu install-ld || exit 1
++elif [ $H_REAL_TARGET = $H_REAL_HOST -a $H_REAL_TARGET = i686-pc-linux-uclibc ]
++ then
++  make all-gdb all-dejagnu all-ld || exit 1
++  make install-gdb install-dejagnu install-ld || exit 1
+ elif [ $H_REAL_TARGET = $H_REAL_HOST ] ; then
+   make bootstrap || exit 1
+   make install || exit 1
+--- a/libjava/classpath/ltconfig
++++ b/libjava/classpath/ltconfig
+@@ -603,7 +603,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-
+ 
+ # Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+ case $host_os in
+-linux-gnu*) ;;
++linux-gnu*|linux-uclibc*) ;;
+ linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+ esac
+ 
+@@ -1247,7 +1247,7 @@ linux-gnuoldld* | linux-gnuaout* | linux
+   ;;
+ 
+ # This must be Linux ELF.
+-linux-gnu*)
++linux*)
+   version_type=linux
+   need_lib_prefix=no
+   need_version=no
diff --git a/toolchain/gcc/patches/5.4.0/200-musl_config.patch b/toolchain/gcc/patches/5.4.0/200-musl_config.patch
new file mode 100644
index 0000000000..b9a5b28274
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/200-musl_config.patch
@@ -0,0 +1,309 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Fri, 8 May 2015 08:25:47 +0000 (+0000)
+Subject: [PATCH 2/13] musl libc config
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=a9173ceabaf29c16f8ef226fbf98af373a4b2ceb
+
+[PATCH 2/13] musl libc config
+
+2015-05-08  Gregor Richards  <gregor.richards@uwaterloo.ca>
+	    Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config.gcc (LIBC_MUSL): New tm_defines macro.
+	* config/linux.h (OPTION_MUSL): Define.
+	(MUSL_DYNAMIC_LINKER, MUSL_DYNAMIC_LINKER32,)
+	(MUSL_DYNAMIC_LINKER64, MUSL_DYNAMIC_LINKERX32,)
+	(INCLUDE_DEFAULTS_MUSL_GPP, INCLUDE_DEFAULTS_MUSL_LOCAL,)
+	(INCLUDE_DEFAULTS_MUSL_PREFIX, INCLUDE_DEFAULTS_MUSL_CROSS,)
+	(INCLUDE_DEFAULTS_MUSL_TOOL, INCLUDE_DEFAULTS_MUSL_NATIVE): Define.
+	* config/linux.opt (mmusl): New option.
+	* doc/invoke.texi (GNU/Linux Options): Document -mmusl.
+	* configure.ac (gcc_cv_libc_provides_ssp): Add *-*-musl*.
+	(gcc_cv_target_dl_iterate_phdr): Add *-linux-musl*.
+	* configure: Regenerate.
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222904 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -575,7 +575,7 @@ case ${target} in
+ esac
+ 
+ # Common C libraries.
+-tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3"
++tm_defines="$tm_defines LIBC_GLIBC=1 LIBC_UCLIBC=2 LIBC_BIONIC=3 LIBC_MUSL=4"
+ 
+ # 32-bit x86 processors supported by --with-arch=.  Each processor
+ # MUST be separated by exactly one space.
+@@ -720,6 +720,9 @@ case ${target} in
+     *-*-*uclibc*)
+       tm_defines="$tm_defines DEFAULT_LIBC=LIBC_UCLIBC"
+       ;;
++    *-*-*musl*)
++      tm_defines="$tm_defines DEFAULT_LIBC=LIBC_MUSL"
++      ;;
+     *)
+       tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC"
+       ;;
+--- a/gcc/config/linux.h
++++ b/gcc/config/linux.h
+@@ -32,10 +32,12 @@ see the files COPYING3 and COPYING.RUNTI
+ #define OPTION_GLIBC  (DEFAULT_LIBC == LIBC_GLIBC)
+ #define OPTION_UCLIBC (DEFAULT_LIBC == LIBC_UCLIBC)
+ #define OPTION_BIONIC (DEFAULT_LIBC == LIBC_BIONIC)
++#define OPTION_MUSL   (DEFAULT_LIBC == LIBC_MUSL)
+ #else
+ #define OPTION_GLIBC  (linux_libc == LIBC_GLIBC)
+ #define OPTION_UCLIBC (linux_libc == LIBC_UCLIBC)
+ #define OPTION_BIONIC (linux_libc == LIBC_BIONIC)
++#define OPTION_MUSL   (linux_libc == LIBC_MUSL)
+ #endif
+ 
+ #define GNU_USER_TARGET_OS_CPP_BUILTINS()			\
+@@ -50,21 +52,25 @@ see the files COPYING3 and COPYING.RUNTI
+     } while (0)
+ 
+ /* Determine which dynamic linker to use depending on whether GLIBC or
+-   uClibc or Bionic is the default C library and whether
+-   -muclibc or -mglibc or -mbionic has been passed to change the default.  */
++   uClibc or Bionic or musl is the default C library and whether
++   -muclibc or -mglibc or -mbionic or -mmusl has been passed to change
++   the default.  */
+ 
+-#define CHOOSE_DYNAMIC_LINKER1(LIBC1, LIBC2, LIBC3, LD1, LD2, LD3)	\
+-  "%{" LIBC2 ":" LD2 ";:%{" LIBC3 ":" LD3 ";:" LD1 "}}"
++#define CHOOSE_DYNAMIC_LINKER1(LIBC1, LIBC2, LIBC3, LIBC4, LD1, LD2, LD3, LD4)	\
++  "%{" LIBC2 ":" LD2 ";:%{" LIBC3 ":" LD3 ";:%{" LIBC4 ":" LD4 ";:" LD1 "}}}"
+ 
+ #if DEFAULT_LIBC == LIBC_GLIBC
+-#define CHOOSE_DYNAMIC_LINKER(G, U, B) \
+-  CHOOSE_DYNAMIC_LINKER1 ("mglibc", "muclibc", "mbionic", G, U, B)
++#define CHOOSE_DYNAMIC_LINKER(G, U, B, M) \
++  CHOOSE_DYNAMIC_LINKER1 ("mglibc", "muclibc", "mbionic", "mmusl", G, U, B, M)
+ #elif DEFAULT_LIBC == LIBC_UCLIBC
+-#define CHOOSE_DYNAMIC_LINKER(G, U, B) \
+-  CHOOSE_DYNAMIC_LINKER1 ("muclibc", "mglibc", "mbionic", U, G, B)
++#define CHOOSE_DYNAMIC_LINKER(G, U, B, M) \
++  CHOOSE_DYNAMIC_LINKER1 ("muclibc", "mglibc", "mbionic", "mmusl", U, G, B, M)
+ #elif DEFAULT_LIBC == LIBC_BIONIC
+-#define CHOOSE_DYNAMIC_LINKER(G, U, B) \
+-  CHOOSE_DYNAMIC_LINKER1 ("mbionic", "mglibc", "muclibc", B, G, U)
++#define CHOOSE_DYNAMIC_LINKER(G, U, B, M) \
++  CHOOSE_DYNAMIC_LINKER1 ("mbionic", "mglibc", "muclibc", "mmusl", B, G, U, M)
++#elif DEFAULT_LIBC == LIBC_MUSL
++#define CHOOSE_DYNAMIC_LINKER(G, U, B, M) \
++  CHOOSE_DYNAMIC_LINKER1 ("mmusl", "mglibc", "muclibc", "mbionic", M, G, U, B)
+ #else
+ #error "Unsupported DEFAULT_LIBC"
+ #endif /* DEFAULT_LIBC */
+@@ -81,24 +87,100 @@ see the files COPYING3 and COPYING.RUNTI
+ #define BIONIC_DYNAMIC_LINKER32 "/system/bin/linker"
+ #define BIONIC_DYNAMIC_LINKER64 "/system/bin/linker64"
+ #define BIONIC_DYNAMIC_LINKERX32 "/system/bin/linkerx32"
++/* Should be redefined for each target that supports musl.  */
++#define MUSL_DYNAMIC_LINKER "/dev/null"
++#define MUSL_DYNAMIC_LINKER32 "/dev/null"
++#define MUSL_DYNAMIC_LINKER64 "/dev/null"
++#define MUSL_DYNAMIC_LINKERX32 "/dev/null"
+ 
+ #define GNU_USER_DYNAMIC_LINKER						\
+   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER, UCLIBC_DYNAMIC_LINKER,	\
+-			 BIONIC_DYNAMIC_LINKER)
++			 BIONIC_DYNAMIC_LINKER, MUSL_DYNAMIC_LINKER)
+ #define GNU_USER_DYNAMIC_LINKER32					\
+   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER32, UCLIBC_DYNAMIC_LINKER32, \
+-			 BIONIC_DYNAMIC_LINKER32)
++			 BIONIC_DYNAMIC_LINKER32, MUSL_DYNAMIC_LINKER32)
+ #define GNU_USER_DYNAMIC_LINKER64					\
+   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER64, UCLIBC_DYNAMIC_LINKER64, \
+-			 BIONIC_DYNAMIC_LINKER64)
++			 BIONIC_DYNAMIC_LINKER64, MUSL_DYNAMIC_LINKER64)
+ #define GNU_USER_DYNAMIC_LINKERX32					\
+   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKERX32, UCLIBC_DYNAMIC_LINKERX32, \
+-			 BIONIC_DYNAMIC_LINKERX32)
++			 BIONIC_DYNAMIC_LINKERX32, MUSL_DYNAMIC_LINKERX32)
+ 
+ /* Whether we have Bionic libc runtime */
+ #undef TARGET_HAS_BIONIC
+ #define TARGET_HAS_BIONIC (OPTION_BIONIC)
+ 
++/* musl avoids problematic includes by rearranging the include directories.
++ * Unfortunately, this is mostly duplicated from cppdefault.c */
++#if DEFAULT_LIBC == LIBC_MUSL
++#define INCLUDE_DEFAULTS_MUSL_GPP			\
++    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1,		\
++      GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 0 },		\
++    { GPLUSPLUS_TOOL_INCLUDE_DIR, "G++", 1, 1,		\
++      GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 1 },		\
++    { GPLUSPLUS_BACKWARD_INCLUDE_DIR, "G++", 1, 1,	\
++      GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 0 },
++
++#ifdef LOCAL_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_LOCAL			\
++    { LOCAL_INCLUDE_DIR, 0, 0, 1, 1, 2 },		\
++    { LOCAL_INCLUDE_DIR, 0, 0, 1, 1, 0 },
++#else
++#define INCLUDE_DEFAULTS_MUSL_LOCAL
++#endif
++
++#ifdef PREFIX_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_PREFIX			\
++    { PREFIX_INCLUDE_DIR, 0, 0, 1, 0, 0},
++#else
++#define INCLUDE_DEFAULTS_MUSL_PREFIX
++#endif
++
++#ifdef CROSS_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_CROSS			\
++    { CROSS_INCLUDE_DIR, "GCC", 0, 0, 0, 0},
++#else
++#define INCLUDE_DEFAULTS_MUSL_CROSS
++#endif
++
++#ifdef TOOL_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_TOOL			\
++    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1, 0, 0},
++#else
++#define INCLUDE_DEFAULTS_MUSL_TOOL
++#endif
++
++#ifdef NATIVE_SYSTEM_HEADER_DIR
++#define INCLUDE_DEFAULTS_MUSL_NATIVE			\
++    { NATIVE_SYSTEM_HEADER_DIR, 0, 0, 0, 1, 2 },	\
++    { NATIVE_SYSTEM_HEADER_DIR, 0, 0, 0, 1, 0 },
++#else
++#define INCLUDE_DEFAULTS_MUSL_NATIVE
++#endif
++
++#if defined (CROSS_DIRECTORY_STRUCTURE) && !defined (TARGET_SYSTEM_ROOT)
++# undef INCLUDE_DEFAULTS_MUSL_LOCAL
++# define INCLUDE_DEFAULTS_MUSL_LOCAL
++# undef INCLUDE_DEFAULTS_MUSL_NATIVE
++# define INCLUDE_DEFAULTS_MUSL_NATIVE
++#else
++# undef INCLUDE_DEFAULTS_MUSL_CROSS
++# define INCLUDE_DEFAULTS_MUSL_CROSS
++#endif
++
++#undef INCLUDE_DEFAULTS
++#define INCLUDE_DEFAULTS				\
++  {							\
++    INCLUDE_DEFAULTS_MUSL_GPP				\
++    INCLUDE_DEFAULTS_MUSL_PREFIX			\
++    INCLUDE_DEFAULTS_MUSL_CROSS				\
++    INCLUDE_DEFAULTS_MUSL_TOOL				\
++    INCLUDE_DEFAULTS_MUSL_NATIVE			\
++    { GCC_INCLUDE_DIR, "GCC", 0, 1, 0, 0 },		\
++    { 0, 0, 0, 0, 0, 0 }				\
++  }
++#endif
++
+ #if (DEFAULT_LIBC == LIBC_UCLIBC) && defined (SINGLE_LIBC) /* uClinux */
+ /* This is a *uclinux* target.  We don't define below macros to normal linux
+    versions, because doing so would require *uclinux* targets to include
+--- a/gcc/config/linux.opt
++++ b/gcc/config/linux.opt
+@@ -28,5 +28,9 @@ Target Report RejectNegative Var(linux_l
+ Use GNU C library
+ 
+ muclibc
+-Target Report RejectNegative Var(linux_libc,LIBC_UCLIBC) Negative(mbionic)
++Target Report RejectNegative Var(linux_libc,LIBC_UCLIBC) Negative(mmusl)
+ Use uClibc C library
++
++mmusl
++Target Report RejectNegative Var(linux_libc,LIBC_MUSL) Negative(mbionic)
++Use musl C library
+--- a/gcc/configure
++++ b/gcc/configure
+@@ -27833,6 +27833,9 @@ if test "${gcc_cv_libc_provides_ssp+set}
+ else
+   gcc_cv_libc_provides_ssp=no
+     case "$target" in
++       *-*-musl*)
++	 # All versions of musl provide stack protector
++	 gcc_cv_libc_provides_ssp=yes;;
+        *-*-linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu)
+       # glibc 2.4 and later provides __stack_chk_fail and
+       # either __stack_chk_guard, or TLS access to stack guard canary.
+@@ -27865,6 +27868,7 @@ fi
+ 	 # <http://gcc.gnu.org/ml/gcc/2008-10/msg00130.html>) and for now
+ 	 # simply assert that glibc does provide this, which is true for all
+ 	 # realistically usable GNU/Hurd configurations.
++	 # All supported versions of musl provide it as well
+ 	 gcc_cv_libc_provides_ssp=yes;;
+        *-*-darwin* | *-*-freebsd*)
+ 	 ac_fn_c_check_func "$LINENO" "__stack_chk_fail" "ac_cv_func___stack_chk_fail"
+@@ -27961,6 +27965,9 @@ case "$target" in
+       gcc_cv_target_dl_iterate_phdr=no
+     fi
+     ;;
++  *-linux-musl*)
++    gcc_cv_target_dl_iterate_phdr=yes
++    ;;
+ esac
+ 
+ if test x$gcc_cv_target_dl_iterate_phdr = xyes; then
+--- a/gcc/configure.ac
++++ b/gcc/configure.ac
+@@ -5287,6 +5287,9 @@ AC_CACHE_CHECK(__stack_chk_fail in targe
+       gcc_cv_libc_provides_ssp,
+       [gcc_cv_libc_provides_ssp=no
+     case "$target" in
++       *-*-musl*)
++	 # All versions of musl provide stack protector
++	 gcc_cv_libc_provides_ssp=yes;;
+        *-*-linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu)
+       # glibc 2.4 and later provides __stack_chk_fail and
+       # either __stack_chk_guard, or TLS access to stack guard canary.
+@@ -5313,6 +5316,7 @@ AC_CACHE_CHECK(__stack_chk_fail in targe
+ 	 # <http://gcc.gnu.org/ml/gcc/2008-10/msg00130.html>) and for now
+ 	 # simply assert that glibc does provide this, which is true for all
+ 	 # realistically usable GNU/Hurd configurations.
++	 # All supported versions of musl provide it as well
+ 	 gcc_cv_libc_provides_ssp=yes;;
+        *-*-darwin* | *-*-freebsd*)
+ 	 AC_CHECK_FUNC(__stack_chk_fail,[gcc_cv_libc_provides_ssp=yes],
+@@ -5386,6 +5390,9 @@ case "$target" in
+       gcc_cv_target_dl_iterate_phdr=no
+     fi
+     ;;
++  *-linux-musl*)
++    gcc_cv_target_dl_iterate_phdr=yes
++    ;;
+ esac
+ GCC_TARGET_TEMPLATE([TARGET_DL_ITERATE_PHDR])
+ if test x$gcc_cv_target_dl_iterate_phdr = xyes; then
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -667,7 +667,7 @@ Objective-C and Objective-C++ Dialects}.
+ -mcpu=@var{cpu}}
+ 
+ @emph{GNU/Linux Options}
+-@gccoptlist{-mglibc -muclibc -mbionic -mandroid @gol
++@gccoptlist{-mglibc -muclibc -mmusl -mbionic -mandroid @gol
+ -tno-android-cc -tno-android-ld}
+ 
+ @emph{H8/300 Options}
+@@ -15340,13 +15340,19 @@ These @samp{-m} options are defined for
+ @item -mglibc
+ @opindex mglibc
+ Use the GNU C library.  This is the default except
+-on @samp{*-*-linux-*uclibc*} and @samp{*-*-linux-*android*} targets.
++on @samp{*-*-linux-*uclibc*}, @samp{*-*-linux-*musl*} and
++@samp{*-*-linux-*android*} targets.
+ 
+ @item -muclibc
+ @opindex muclibc
+ Use uClibc C library.  This is the default on
+ @samp{*-*-linux-*uclibc*} targets.
+ 
++@item -mmusl
++@opindex mmusl
++Use the musl C library.  This is the default on
++@samp{*-*-linux-*musl*} targets.
++
+ @item -mbionic
+ @opindex mbionic
+ Use Bionic C library.  This is the default on
diff --git a/toolchain/gcc/patches/5.4.0/201-musl_arm.patch b/toolchain/gcc/patches/5.4.0/201-musl_arm.patch
new file mode 100644
index 0000000000..27a26afc05
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/201-musl_arm.patch
@@ -0,0 +1,43 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Wed, 27 May 2015 13:17:11 +0000 (+0000)
+Subject: [PATCH 4/13] arm musl support
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=de799bd087ab9a179768fea75bd195a31d3432a4
+
+[PATCH 4/13] arm musl support
+
+On behalf of szabolcs.nagy@arm.com
+
+2015-05-27  Gregor Richards  <gregor.richards@uwaterloo.ca>
+
+	* config/arm/linux-eabi.h (MUSL_DYNAMIC_LINKER): Define.
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223749 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -77,6 +77,23 @@
+     %{mfloat-abi=soft*:" GLIBC_DYNAMIC_LINKER_SOFT_FLOAT "} \
+     %{!mfloat-abi=*:" GLIBC_DYNAMIC_LINKER_DEFAULT "}"
+ 
++/* For ARM musl currently supports four dynamic linkers:
++   - ld-musl-arm.so.1 - for the EABI-derived soft-float ABI
++   - ld-musl-armhf.so.1 - for the EABI-derived hard-float ABI
++   - ld-musl-armeb.so.1 - for the EABI-derived soft-float ABI, EB
++   - ld-musl-armebhf.so.1 - for the EABI-derived hard-float ABI, EB
++   musl does not support the legacy OABI mode.
++   All the dynamic linkers live in /lib.
++   We default to soft-float, EL. */
++#undef  MUSL_DYNAMIC_LINKER
++#if TARGET_BIG_ENDIAN_DEFAULT
++#define MUSL_DYNAMIC_LINKER_E "%{mlittle-endian:;:eb}"
++#else
++#define MUSL_DYNAMIC_LINKER_E "%{mbig-endian:eb}"
++#endif
++#define MUSL_DYNAMIC_LINKER \
++  "/lib/ld-musl-arm" MUSL_DYNAMIC_LINKER_E "%{mfloat-abi=hard:hf}.so.1"
++
+ /* At this point, bpabi.h will have clobbered LINK_SPEC.  We want to
+    use the GNU/Linux version, not the generic BPABI version.  */
+ #undef  LINK_SPEC
diff --git a/toolchain/gcc/patches/5.4.0/202-musl_mips.patch b/toolchain/gcc/patches/5.4.0/202-musl_mips.patch
new file mode 100644
index 0000000000..816dd8d101
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/202-musl_mips.patch
@@ -0,0 +1,35 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Fri, 8 May 2015 15:16:50 +0000 (+0000)
+Subject: [PATCH 6/13] mips musl support
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=2550b6a866c887472b587bef87d433c51cf1ebc8
+
+[PATCH 6/13] mips musl support
+
+2015-05-08  Gregor Richards  <gregor.richards@uwaterloo.ca>
+	    Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config/mips/linux.h (MUSL_DYNAMIC_LINKER32): Define.
+	(MUSL_DYNAMIC_LINKER64, MUSL_DYNAMIC_LINKERN32): Define.
+	(GNU_USER_DYNAMIC_LINKERN32): Update.
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222915 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/gcc/config/mips/linux.h
++++ b/gcc/config/mips/linux.h
+@@ -37,7 +37,13 @@ along with GCC; see the file COPYING3.
+ #define UCLIBC_DYNAMIC_LINKERN32 \
+   "%{mnan=2008:/lib32/ld-uClibc-mipsn8.so.0;:/lib32/ld-uClibc.so.0}"
+ 
++#undef MUSL_DYNAMIC_LINKER32
++#define MUSL_DYNAMIC_LINKER32 "/lib/ld-musl-mips%{EL:el}%{msoft-float:-sf}.so.1"
++#undef MUSL_DYNAMIC_LINKER64
++#define MUSL_DYNAMIC_LINKER64 "/lib/ld-musl-mips64%{EL:el}%{msoft-float:-sf}.so.1"
++#define MUSL_DYNAMIC_LINKERN32 "/lib/ld-musl-mipsn32%{EL:el}%{msoft-float:-sf}.so.1"
++
+ #define BIONIC_DYNAMIC_LINKERN32 "/system/bin/linker32"
+ #define GNU_USER_DYNAMIC_LINKERN32 \
+   CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKERN32, UCLIBC_DYNAMIC_LINKERN32, \
+-                         BIONIC_DYNAMIC_LINKERN32)
++                         BIONIC_DYNAMIC_LINKERN32, MUSL_DYNAMIC_LINKERN32)
diff --git a/toolchain/gcc/patches/5.4.0/203-musl_powerpc.patch b/toolchain/gcc/patches/5.4.0/203-musl_powerpc.patch
new file mode 100644
index 0000000000..b4f34e81ca
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/203-musl_powerpc.patch
@@ -0,0 +1,209 @@
+
+gcc/Changelog:
+
+2015-04-24  Gregor Richards  <gregor.richards@uwaterloo.ca>
+	    Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config.gcc (secure_plt): Add *-linux*-musl*.
+	* config/rs6000/linux64.h (MUSL_DYNAMIC_LINKER32): Define.
+	(MUSL_DYNAMIC_LINKER64): Define.
+	(GNU_USER_DYNAMIC_LINKER32): Update.
+	(GNU_USER_DYNAMIC_LINKER64): Update.
+	(CHOOSE_DYNAMIC_LINKER): Update.
+
+	* config/rs6000/secureplt.h (LINK_SECURE_PLT_DEFAULT_SPEC): Define.
+	* config/rs6000/sysv4.h (GNU_USER_DYNAMIC_LINKER): Update.
+	(MUSL_DYNAMIC_LINKER, MUSL_DYNAMIC_LINKER_E,)
+	(INCLUDE_DEFAULTS_MUSL_GPP, INCLUDE_DEFAULTS_MUSL_LOCAL,)
+	(INCLUDE_DEFAULTS_MUSL_PREFIX, INCLUDE_DEFAULTS_MUSL_CROSS,)
+	(INCLUDE_DEFAULTS_MUSL_TOOL, INCLUDE_DEFAULTS_MUSL_NATIVE): Define.
+	(LINK_SECURE_PLT_DEFAULT_SPEC): Define.
+	(CHOOSE_DYNAMIC_LINKER, LINK_TARGET_SPEC, LINK_OS_LINUX_SPEC): Update.
+
+	* config/rs6000/sysv4le.h (MUSL_DYNAMIC_LINKER_E): Define.
+
+--- a/gcc/config/rs6000/linux64.h
++++ b/gcc/config/rs6000/linux64.h
+@@ -365,17 +365,21 @@ extern int dot_symbols;
+ #endif
+ #define UCLIBC_DYNAMIC_LINKER32 "/lib/ld-uClibc.so.0"
+ #define UCLIBC_DYNAMIC_LINKER64 "/lib/ld64-uClibc.so.0"
++#define MUSL_DYNAMIC_LINKER32 "/lib/ld-musl-powerpc" MUSL_DYNAMIC_LINKER_E ".so.1"
++#define MUSL_DYNAMIC_LINKER64 "/lib/ld-musl-powerpc64" MUSL_DYNAMIC_LINKER_E ".so.1"
+ #if DEFAULT_LIBC == LIBC_UCLIBC
+-#define CHOOSE_DYNAMIC_LINKER(G, U) "%{mglibc:" G ";:" U "}"
++#define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{mglibc:" G ";:%{mmusl:" M ";:" U "}}"
+ #elif DEFAULT_LIBC == LIBC_GLIBC
+-#define CHOOSE_DYNAMIC_LINKER(G, U) "%{muclibc:" U ";:" G "}"
++#define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{muclibc:" U ";:%{mmusl:" M ";:" G "}}"
++#elif DEFAULT_LIBC == LIBC_MUSL
++#define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{mglibc:" G ";:%{muclibc:" U ";:" M "}}"
+ #else
+ #error "Unsupported DEFAULT_LIBC"
+ #endif
+ #define GNU_USER_DYNAMIC_LINKER32 \
+-  CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER32, UCLIBC_DYNAMIC_LINKER32)
++  CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER32, UCLIBC_DYNAMIC_LINKER32, MUSL_DYNAMIC_LINKER32)
+ #define GNU_USER_DYNAMIC_LINKER64 \
+-  CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER64, UCLIBC_DYNAMIC_LINKER64)
++  CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER64, UCLIBC_DYNAMIC_LINKER64, MUSL_DYNAMIC_LINKER64)
+ 
+ #undef  DEFAULT_ASM_ENDIAN
+ #if (TARGET_DEFAULT & MASK_LITTLE_ENDIAN)
+--- a/gcc/config/rs6000/secureplt.h
++++ b/gcc/config/rs6000/secureplt.h
+@@ -18,3 +18,4 @@ along with GCC; see the file COPYING3.
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #define CC1_SECURE_PLT_DEFAULT_SPEC "-msecure-plt"
++#define LINK_SECURE_PLT_DEFAULT_SPEC "--secure-plt"
+--- a/gcc/config/rs6000/sysv4.h
++++ b/gcc/config/rs6000/sysv4.h
+@@ -537,6 +537,9 @@ ENDIAN_SELECT(" -mbig", " -mlittle", DEF
+ #ifndef CC1_SECURE_PLT_DEFAULT_SPEC
+ #define CC1_SECURE_PLT_DEFAULT_SPEC ""
+ #endif
++#ifndef LINK_SECURE_PLT_DEFAULT_SPEC
++#define LINK_SECURE_PLT_DEFAULT_SPEC ""
++#endif
+ 
+ /* Pass -G xxx to the compiler.  */
+ #undef CC1_SPEC
+@@ -574,7 +577,8 @@ ENDIAN_SELECT(" -mbig", " -mlittle", DEF
+ %{R*} \
+ %(link_shlib) \
+ %{!T*: %(link_start) } \
+-%(link_os)"
++%(link_os)" \
++"%{!mbss-plt: %{!msecure-plt: %(link_secure_plt_default)}}"
+ 
+ /* Shared libraries are not default.  */
+ #define LINK_SHLIB_SPEC "\
+@@ -757,17 +761,22 @@ ENDIAN_SELECT(" -mbig", " -mlittle", DEF
+ 
+ #define LINK_START_LINUX_SPEC ""
+ 
++#define MUSL_DYNAMIC_LINKER_E ENDIAN_SELECT("","le","")
++
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
+ #define UCLIBC_DYNAMIC_LINKER "/lib/ld-uClibc.so.0"
++#define MUSL_DYNAMIC_LINKER "/lib/ld-musl-powerpc" MUSL_DYNAMIC_LINKER_E ".so.1"
+ #if DEFAULT_LIBC == LIBC_UCLIBC
+-#define CHOOSE_DYNAMIC_LINKER(G, U) "%{mglibc:" G ";:" U "}"
++#define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{mglibc:" G ";:%{mmusl:" M ";:" U "}}"
++#elif DEFAULT_LIBC == LIBC_MUSL
++#define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{mglibc:" G ";:%{muclibc:" U ";:" M "}}"
+ #elif !defined (DEFAULT_LIBC) || DEFAULT_LIBC == LIBC_GLIBC
+-#define CHOOSE_DYNAMIC_LINKER(G, U) "%{muclibc:" U ";:" G "}"
++#define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{muclibc:" U ";:%{mmusl:" M ";:" G "}}"
+ #else
+ #error "Unsupported DEFAULT_LIBC"
+ #endif
+ #define GNU_USER_DYNAMIC_LINKER \
+-  CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER, UCLIBC_DYNAMIC_LINKER)
++  CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER, UCLIBC_DYNAMIC_LINKER, MUSL_DYNAMIC_LINKER)
+ 
+ #define LINK_OS_LINUX_SPEC "-m elf32ppclinux %{!shared: %{!static: \
+   %{rdynamic:-export-dynamic} \
+@@ -889,6 +898,7 @@ ncrtn.o%s"
+   { "link_os_openbsd",		LINK_OS_OPENBSD_SPEC },			\
+   { "link_os_default",		LINK_OS_DEFAULT_SPEC },			\
+   { "cc1_secure_plt_default",	CC1_SECURE_PLT_DEFAULT_SPEC },		\
++  { "link_secure_plt_default",	LINK_SECURE_PLT_DEFAULT_SPEC },		\
+   { "cpp_os_ads",		CPP_OS_ADS_SPEC },			\
+   { "cpp_os_yellowknife",	CPP_OS_YELLOWKNIFE_SPEC },		\
+   { "cpp_os_mvme",		CPP_OS_MVME_SPEC },			\
+@@ -943,3 +953,72 @@ ncrtn.o%s"
+ /* This target uses the sysv4.opt file.  */
+ #define TARGET_USES_SYSV4_OPT 1
+ 
++/* Include order changes for musl, same as in generic linux.h.  */
++#if DEFAULT_LIBC == LIBC_MUSL
++#define INCLUDE_DEFAULTS_MUSL_GPP			\
++    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1,		\
++      GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 0 },		\
++    { GPLUSPLUS_TOOL_INCLUDE_DIR, "G++", 1, 1,		\
++      GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 1 },		\
++    { GPLUSPLUS_BACKWARD_INCLUDE_DIR, "G++", 1, 1,	\
++      GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 0 },
++
++#ifdef LOCAL_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_LOCAL			\
++    { LOCAL_INCLUDE_DIR, 0, 0, 1, 1, 2 },		\
++    { LOCAL_INCLUDE_DIR, 0, 0, 1, 1, 0 },
++#else
++#define INCLUDE_DEFAULTS_MUSL_LOCAL
++#endif
++
++#ifdef PREFIX_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_PREFIX			\
++    { PREFIX_INCLUDE_DIR, 0, 0, 1, 0, 0},
++#else
++#define INCLUDE_DEFAULTS_MUSL_PREFIX
++#endif
++
++#ifdef CROSS_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_CROSS			\
++    { CROSS_INCLUDE_DIR, "GCC", 0, 0, 0, 0},
++#else
++#define INCLUDE_DEFAULTS_MUSL_CROSS
++#endif
++
++#ifdef TOOL_INCLUDE_DIR
++#define INCLUDE_DEFAULTS_MUSL_TOOL			\
++    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1, 0, 0},
++#else
++#define INCLUDE_DEFAULTS_MUSL_TOOL
++#endif
++
++#ifdef NATIVE_SYSTEM_HEADER_DIR
++#define INCLUDE_DEFAULTS_MUSL_NATIVE			\
++    { NATIVE_SYSTEM_HEADER_DIR, 0, 0, 0, 1, 2 },	\
++    { NATIVE_SYSTEM_HEADER_DIR, 0, 0, 0, 1, 0 },
++#else
++#define INCLUDE_DEFAULTS_MUSL_NATIVE
++#endif
++
++#if defined (CROSS_DIRECTORY_STRUCTURE) && !defined (TARGET_SYSTEM_ROOT)
++# undef INCLUDE_DEFAULTS_MUSL_LOCAL
++# define INCLUDE_DEFAULTS_MUSL_LOCAL
++# undef INCLUDE_DEFAULTS_MUSL_NATIVE
++# define INCLUDE_DEFAULTS_MUSL_NATIVE
++#else
++# undef INCLUDE_DEFAULTS_MUSL_CROSS
++# define INCLUDE_DEFAULTS_MUSL_CROSS
++#endif
++
++#undef INCLUDE_DEFAULTS
++#define INCLUDE_DEFAULTS				\
++  {							\
++    INCLUDE_DEFAULTS_MUSL_GPP				\
++    INCLUDE_DEFAULTS_MUSL_PREFIX			\
++    INCLUDE_DEFAULTS_MUSL_CROSS				\
++    INCLUDE_DEFAULTS_MUSL_TOOL				\
++    INCLUDE_DEFAULTS_MUSL_NATIVE			\
++    { GCC_INCLUDE_DIR, "GCC", 0, 1, 0, 0 },		\
++    { 0, 0, 0, 0, 0, 0 }				\
++  }
++#endif
+--- a/gcc/config/rs6000/sysv4le.h
++++ b/gcc/config/rs6000/sysv4le.h
+@@ -31,3 +31,5 @@
+ /* Little-endian PowerPC64 Linux uses the ELF v2 ABI by default.  */
+ #define LINUX64_DEFAULT_ABI_ELFv2
+ 
++#undef MUSL_DYNAMIC_LINKER_E
++#define MUSL_DYNAMIC_LINKER_E ENDIAN_SELECT("","le","le")
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -2416,6 +2416,10 @@ powerpc*-*-linux*)
+ 	    powerpc*-*-linux*paired*)
+ 		tm_file="${tm_file} rs6000/750cl.h" ;;
+ 	esac
++	case ${target} in
++		*-linux*-musl*)
++			enable_secureplt=yes ;;
++	esac
+ 	if test x${enable_secureplt} = xyes; then
+ 		tm_file="rs6000/secureplt.h ${tm_file}"
+ 	fi
diff --git a/toolchain/gcc/patches/5.4.0/204-musl_sh.patch b/toolchain/gcc/patches/5.4.0/204-musl_sh.patch
new file mode 100644
index 0000000000..8c3753d530
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/204-musl_sh.patch
@@ -0,0 +1,39 @@
+gcc/Changelog:
+
+2015-04-27  Gregor Richards  <gregor.richards@uwaterloo.ca>
+	    Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config/sh/linux.h (MUSL_DYNAMIC_LINKER): Define.
+	(MUSL_DYNAMIC_LINKER_E, MUSL_DYNAMIC_LINKER_FP): Define.
+
+--- a/gcc/config/sh/linux.h
++++ b/gcc/config/sh/linux.h
+@@ -43,6 +43,28 @@ along with GCC; see the file COPYING3.
+ 
+ #define TARGET_ASM_FILE_END file_end_indicate_exec_stack
+ 
++#if TARGET_ENDIAN_DEFAULT == MASK_LITTLE_ENDIAN
++#define MUSL_DYNAMIC_LINKER_E "%{mb:eb}"
++#else
++#define MUSL_DYNAMIC_LINKER_E "%{!ml:eb}"
++#endif
++
++#if TARGET_CPU_DEFAULT & ( MASK_HARD_SH2A_DOUBLE | MASK_SH4 )
++/* "-nofpu" if any nofpu option is specified */
++#define MUSL_DYNAMIC_LINKER_FP \
++  "%{m1|m2|m2a-nofpu|m3|m4-nofpu|m4-100-nofpu|m4-200-nofpu|m4-300-nofpu|" \
++  "m4-340|m4-400|m4-500|m4al|m5-32media-nofpu|m5-64media-nofpu|" \
++  "m5-compact-nofpu:-nofpu}"
++#else
++/* "-nofpu" if none of the hard fpu options are specified */
++#define MUSL_DYNAMIC_LINKER_FP \
++  "%{m2a|m4|m4-100|m4-200|m4-300|m4a|m5-32media|m5-64media|m5-compact:;:-nofpu}"
++#endif
++
++#undef MUSL_DYNAMIC_LINKER
++#define MUSL_DYNAMIC_LINKER \
++  "/lib/ld-musl-sh" MUSL_DYNAMIC_LINKER_E MUSL_DYNAMIC_LINKER_FP ".so.1"
++
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
+ 
+ #undef SUBTARGET_LINK_EMUL_SUFFIX
diff --git a/toolchain/gcc/patches/5.4.0/205-musl_x86.patch b/toolchain/gcc/patches/5.4.0/205-musl_x86.patch
new file mode 100644
index 0000000000..8772328d64
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/205-musl_x86.patch
@@ -0,0 +1,41 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Fri, 15 May 2015 13:20:01 +0000 (+0000)
+Subject: [PATCH 9/13] x86 musl support
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=5551c8d927c17f60837f15f8dfe46f945ba3fa9c
+
+[PATCH 9/13] x86 musl support
+
+On behalf of Szabolcs Nagy.
+
+2015-05-15  Gregor Richards  <gregor.richards@uwaterloo.ca>
+
+	* config/i386/linux.h (MUSL_DYNAMIC_LINKER): Define.
+	* config/i386/linux64.h (MUSL_DYNAMIC_LINKER32): Define.
+	(MUSL_DYNAMIC_LINKER64, MUSL_DYNAMIC_LINKERX32): Define.
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223218 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/gcc/config/i386/linux.h
++++ b/gcc/config/i386/linux.h
+@@ -21,3 +21,6 @@ along with GCC; see the file COPYING3.
+ 
+ #define GNU_USER_LINK_EMULATION "elf_i386"
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
++
++#undef MUSL_DYNAMIC_LINKER
++#define MUSL_DYNAMIC_LINKER "/lib/ld-musl-i386.so.1"
+--- a/gcc/config/i386/linux64.h
++++ b/gcc/config/i386/linux64.h
+@@ -30,3 +30,10 @@ see the files COPYING3 and COPYING.RUNTI
+ #define GLIBC_DYNAMIC_LINKER32 "/lib/ld-linux.so.2"
+ #define GLIBC_DYNAMIC_LINKER64 "/lib64/ld-linux-x86-64.so.2"
+ #define GLIBC_DYNAMIC_LINKERX32 "/libx32/ld-linux-x32.so.2"
++
++#undef MUSL_DYNAMIC_LINKER32
++#define MUSL_DYNAMIC_LINKER32 "/lib/ld-musl-i386.so.1"
++#undef MUSL_DYNAMIC_LINKER64
++#define MUSL_DYNAMIC_LINKER64 "/lib/ld-musl-x86_64.so.1"
++#undef MUSL_DYNAMIC_LINKERX32
++#define MUSL_DYNAMIC_LINKERX32 "/lib/ld-musl-x32.so.1"
diff --git a/toolchain/gcc/patches/5.4.0/206-musl_aarch64.patch b/toolchain/gcc/patches/5.4.0/206-musl_aarch64.patch
new file mode 100644
index 0000000000..6925a026e7
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/206-musl_aarch64.patch
@@ -0,0 +1,31 @@
+From: jgreenhalgh <jgreenhalgh@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Wed, 27 May 2015 16:46:39 +0000 (+0000)
+Subject: [PATCH 3/13] aarch64 musl support
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=b3ff21cf0531be91bc3fb8200296a7633090ec78
+
+[PATCH 3/13] aarch64 musl support
+
+gcc/Changelog:
+
+2015-05-27  Gregor Richards  <gregor.richards@uwaterloo.ca>
+	    Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config/aarch64/aarch64-linux.h (MUSL_DYNAMIC_LINKER): Define.
+
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223766 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/gcc/config/aarch64/aarch64-linux.h
++++ b/gcc/config/aarch64/aarch64-linux.h
+@@ -23,6 +23,9 @@
+ 
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux-aarch64%{mbig-endian:_be}%{mabi=ilp32:_ilp32}.so.1"
+ 
++#undef MUSL_DYNAMIC_LINKER
++#define MUSL_DYNAMIC_LINKER "/lib/ld-musl-aarch64%{mbig-endian:_be}%{mabi=ilp32:_ilp32}.so.1"
++
+ #undef  ASAN_CC1_SPEC
+ #define ASAN_CC1_SPEC "%{%:sanitize(address):-funwind-tables}"
+ 
diff --git a/toolchain/gcc/patches/5.4.0/207-musl_fixincludes.patch b/toolchain/gcc/patches/5.4.0/207-musl_fixincludes.patch
new file mode 100644
index 0000000000..0ff33d39d8
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/207-musl_fixincludes.patch
@@ -0,0 +1,30 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Wed, 22 Apr 2015 14:18:16 +0000 (+0000)
+Subject: fixincludes update for musl support
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=2dc727de2e87c2756a514cbb43cea23c99deaa3d
+
+fixincludes update for musl support
+
+On behalf of Szabolcs.Nagy@arm.com
+
+2015-04-22  Gregor Richards  <gregor.richards@uwaterloo.ca>
+
+	* mkfixinc.sh: Add *-musl* with no fixes.
+
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222327 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/fixincludes/mkfixinc.sh
++++ b/fixincludes/mkfixinc.sh
+@@ -19,7 +19,8 @@ case $machine in
+     powerpc-*-eabi*    | \
+     powerpc-*-rtems*   | \
+     powerpcle-*-eabisim* | \
+-    powerpcle-*-eabi* )
++    powerpcle-*-eabi* | \
++    *-musl* )
+ 	#  IF there is no include fixing,
+ 	#  THEN create a no-op fixer and exit
+ 	(echo "#! /bin/sh" ; echo "exit 0" ) > ${target}
diff --git a/toolchain/gcc/patches/5.4.0/209-musl_libstdc++.patch b/toolchain/gcc/patches/5.4.0/209-musl_libstdc++.patch
new file mode 100644
index 0000000000..d2414d0232
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/209-musl_libstdc++.patch
@@ -0,0 +1,72 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Wed, 22 Apr 2015 14:24:11 +0000 (+0000)
+Subject: libstdc++, libgfortran gthr workaround for musl
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=1e5f711c11cb80ce609db9e9c1d8b2da0f7b5b61
+
+libstdc++, libgfortran gthr workaround for musl
+
+On behalf of szabolcs.nagy@arm.com
+
+[libstdc++-v3/]
+2015-04-22  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config/os/generic/os_defines.h (_GLIBCXX_GTHREAD_USE_WEAK): Define.
+	* configure.host (os_include_dir): Set to "os/generic" for linux-musl*.
+
+[libgfortran/]
+2015-04-22  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* acinclude.m4 (GTHREAD_USE_WEAK): Define as 0 for *-*-musl*.
+	* configure: Regenerate.
+
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222329 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/libgfortran/acinclude.m4
++++ b/libgfortran/acinclude.m4
+@@ -100,7 +100,7 @@ void foo (void);
+ 	      [Define to 1 if the target supports #pragma weak])
+   fi
+   case "$host" in
+-    *-*-darwin* | *-*-hpux* | *-*-cygwin* | *-*-mingw* )
++    *-*-darwin* | *-*-hpux* | *-*-cygwin* | *-*-mingw* | *-*-musl* )
+       AC_DEFINE(GTHREAD_USE_WEAK, 0,
+ 		[Define to 0 if the target shouldn't use #pragma weak])
+       ;;
+--- a/libgfortran/configure
++++ b/libgfortran/configure
+@@ -26456,7 +26456,7 @@ $as_echo "#define SUPPORTS_WEAK 1" >>con
+ 
+   fi
+   case "$host" in
+-    *-*-darwin* | *-*-hpux* | *-*-cygwin* | *-*-mingw* )
++    *-*-darwin* | *-*-hpux* | *-*-cygwin* | *-*-mingw* | *-*-musl* )
+ 
+ $as_echo "#define GTHREAD_USE_WEAK 0" >>confdefs.h
+ 
+--- a/libstdc++-v3/config/os/generic/os_defines.h
++++ b/libstdc++-v3/config/os/generic/os_defines.h
+@@ -33,4 +33,9 @@
+ // System-specific #define, typedefs, corrections, etc, go here.  This
+ // file will come before all others.
+ 
++// Disable the weak reference logic in gthr.h for os/generic because it
++// is broken on every platform unless there is implementation specific
++// workaround in gthr-posix.h and at link-time for static linking.
++#define _GLIBCXX_GTHREAD_USE_WEAK 0
++
+ #endif
+--- a/libstdc++-v3/configure.host
++++ b/libstdc++-v3/configure.host
+@@ -273,6 +273,9 @@ case "${host_os}" in
+   freebsd*)
+     os_include_dir="os/bsd/freebsd"
+     ;;
++  linux-musl*)
++    os_include_dir="os/generic"
++    ;;
+   gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu)
+     if [ "$uclibc" = "yes" ]; then
+       os_include_dir="os/uclibc"
diff --git a/toolchain/gcc/patches/5.4.0/230-musl_libssp.patch b/toolchain/gcc/patches/5.4.0/230-musl_libssp.patch
new file mode 100644
index 0000000000..30f42e9f7c
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/230-musl_libssp.patch
@@ -0,0 +1,13 @@
+--- a/gcc/gcc.c
++++ b/gcc/gcc.c
+@@ -727,7 +727,9 @@ proper position among the other output f
+ #endif
+ 
+ #ifndef LINK_SSP_SPEC
+-#ifdef TARGET_LIBC_PROVIDES_SSP
++#if DEFAULT_LIBC == LIBC_MUSL
++#define LINK_SSP_SPEC "-lssp_nonshared"
++#elif defined(TARGET_LIBC_PROVIDES_SSP)
+ #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \
+ 		       "|fstack-protector-strong|fstack-protector-explicit:}"
+ #else
diff --git a/toolchain/gcc/patches/5.4.0/240-musl-libitm-fixes.patch b/toolchain/gcc/patches/5.4.0/240-musl-libitm-fixes.patch
new file mode 100644
index 0000000000..533cb68499
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/240-musl-libitm-fixes.patch
@@ -0,0 +1,61 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Wed, 22 Apr 2015 14:11:25 +0000 (+0000)
+Subject: libitm fixes for musl support
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=e53a4d49c3d03ab8eaddb073cf972c1c46d75338
+
+libitm fixes for musl support
+
+On behalf of Szabolcs.Nagy@arm.com
+
+2015-04-22  Gregor Richards  <gregor.richards@uwaterloo.ca>
+
+       * config/arm/hwcap.cc: Use fcntl.h instead of sys/fcntl.h.
+       * config/linux/x86/tls.h: Only use __GLIBC_PREREQ if defined.
+
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222325 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/libitm/config/arm/hwcap.cc
++++ b/libitm/config/arm/hwcap.cc
+@@ -40,7 +40,7 @@ int GTM_hwcap HIDDEN = 0
+ 
+ #ifdef __linux__
+ #include <unistd.h>
+-#include <sys/fcntl.h>
++#include <fcntl.h>
+ #include <elf.h>
+ 
+ static void __attribute__((constructor))
+--- a/libitm/config/linux/x86/tls.h
++++ b/libitm/config/linux/x86/tls.h
+@@ -25,16 +25,19 @@
+ #ifndef LIBITM_X86_TLS_H
+ #define LIBITM_X86_TLS_H 1
+ 
+-#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10)
++#if defined(__GLIBC_PREREQ)
++#if __GLIBC_PREREQ(2, 10)
+ /* Use slots in the TCB head rather than __thread lookups.
+    GLIBC has reserved words 10 through 13 for TM.  */
+ #define HAVE_ARCH_GTM_THREAD 1
+ #define HAVE_ARCH_GTM_THREAD_DISP 1
+ #endif
++#endif
+ 
+ #include "config/generic/tls.h"
+ 
+-#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10)
++#if defined(__GLIBC_PREREQ)
++#if __GLIBC_PREREQ(2, 10)
+ namespace GTM HIDDEN {
+ 
+ #ifdef __x86_64__
+@@ -101,5 +104,6 @@ static inline void set_abi_disp(struct a
+ 
+ } // namespace GTM
+ #endif /* >= GLIBC 2.10 */
++#endif
+ 
+ #endif // LIBITM_X86_TLS_H
diff --git a/toolchain/gcc/patches/5.4.0/250-add-musl.patch b/toolchain/gcc/patches/5.4.0/250-add-musl.patch
new file mode 100644
index 0000000000..8cbeddea33
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/250-add-musl.patch
@@ -0,0 +1,120 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Fri, 8 May 2015 08:30:40 +0000 (+0000)
+Subject: [PATCH 0/13] Add musl support to GCC
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=f2d678afa5b8385d763b93772d73d6bf80a9739e
+
+[PATCH 0/13] Add musl support to GCC
+
+2015-05-08  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* config/glibc-stdint.h (OPTION_MUSL): Define.
+	(INT_FAST16_TYPE, INT_FAST32_TYPE, UINT_FAST16_TYPE, UINT_FAST32_TYPE):
+	Change the definition based on OPTION_MUSL for 64 bit targets.
+	* config/linux.h (OPTION_MUSL): Redefine.
+	* config/alpha/linux.h (OPTION_MUSL): Redefine.
+	* config/rs6000/linux.h (OPTION_MUSL): Redefine.
+	* config/rs6000/linux64.h (OPTION_MUSL): Redefine.
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222905 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/gcc/config/alpha/linux.h
++++ b/gcc/config/alpha/linux.h
+@@ -61,10 +61,14 @@ along with GCC; see the file COPYING3.
+ #define OPTION_GLIBC  (DEFAULT_LIBC == LIBC_GLIBC)
+ #define OPTION_UCLIBC (DEFAULT_LIBC == LIBC_UCLIBC)
+ #define OPTION_BIONIC (DEFAULT_LIBC == LIBC_BIONIC)
++#undef OPTION_MUSL
++#define OPTION_MUSL   (DEFAULT_LIBC == LIBC_MUSL)
+ #else
+ #define OPTION_GLIBC  (linux_libc == LIBC_GLIBC)
+ #define OPTION_UCLIBC (linux_libc == LIBC_UCLIBC)
+ #define OPTION_BIONIC (linux_libc == LIBC_BIONIC)
++#undef OPTION_MUSL
++#define OPTION_MUSL   (linux_libc == LIBC_MUSL)
+ #endif
+ 
+ /* Determine what functions are present at the runtime;
+--- a/gcc/config/glibc-stdint.h
++++ b/gcc/config/glibc-stdint.h
+@@ -22,6 +22,12 @@ a copy of the GCC Runtime Library Except
+ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ <http://www.gnu.org/licenses/>.  */
+ 
++/* Systems using musl libc should use this header and make sure
++   OPTION_MUSL is defined correctly before using the TYPE macros. */
++#ifndef OPTION_MUSL
++#define OPTION_MUSL 0
++#endif
++
+ #define SIG_ATOMIC_TYPE "int"
+ 
+ #define INT8_TYPE "signed char"
+@@ -43,12 +49,12 @@ see the files COPYING3 and COPYING.RUNTI
+ #define UINT_LEAST64_TYPE (LONG_TYPE_SIZE == 64 ? "long unsigned int" : "long long unsigned int")
+ 
+ #define INT_FAST8_TYPE "signed char"
+-#define INT_FAST16_TYPE (LONG_TYPE_SIZE == 64 ? "long int" : "int")
+-#define INT_FAST32_TYPE (LONG_TYPE_SIZE == 64 ? "long int" : "int")
++#define INT_FAST16_TYPE (LONG_TYPE_SIZE == 64 && !OPTION_MUSL ? "long int" : "int")
++#define INT_FAST32_TYPE (LONG_TYPE_SIZE == 64 && !OPTION_MUSL ? "long int" : "int")
+ #define INT_FAST64_TYPE (LONG_TYPE_SIZE == 64 ? "long int" : "long long int")
+ #define UINT_FAST8_TYPE "unsigned char"
+-#define UINT_FAST16_TYPE (LONG_TYPE_SIZE == 64 ? "long unsigned int" : "unsigned int")
+-#define UINT_FAST32_TYPE (LONG_TYPE_SIZE == 64 ? "long unsigned int" : "unsigned int")
++#define UINT_FAST16_TYPE (LONG_TYPE_SIZE == 64 && !OPTION_MUSL ? "long unsigned int" : "unsigned int")
++#define UINT_FAST32_TYPE (LONG_TYPE_SIZE == 64 && !OPTION_MUSL ? "long unsigned int" : "unsigned int")
+ #define UINT_FAST64_TYPE (LONG_TYPE_SIZE == 64 ? "long unsigned int" : "long long unsigned int")
+ 
+ #define INTPTR_TYPE (LONG_TYPE_SIZE == 64 ? "long int" : "int")
+--- a/gcc/config/linux.h
++++ b/gcc/config/linux.h
+@@ -32,11 +32,13 @@ see the files COPYING3 and COPYING.RUNTI
+ #define OPTION_GLIBC  (DEFAULT_LIBC == LIBC_GLIBC)
+ #define OPTION_UCLIBC (DEFAULT_LIBC == LIBC_UCLIBC)
+ #define OPTION_BIONIC (DEFAULT_LIBC == LIBC_BIONIC)
++#undef OPTION_MUSL
+ #define OPTION_MUSL   (DEFAULT_LIBC == LIBC_MUSL)
+ #else
+ #define OPTION_GLIBC  (linux_libc == LIBC_GLIBC)
+ #define OPTION_UCLIBC (linux_libc == LIBC_UCLIBC)
+ #define OPTION_BIONIC (linux_libc == LIBC_BIONIC)
++#undef OPTION_MUSL
+ #define OPTION_MUSL   (linux_libc == LIBC_MUSL)
+ #endif
+ 
+--- a/gcc/config/rs6000/linux.h
++++ b/gcc/config/rs6000/linux.h
+@@ -30,10 +30,14 @@
+ #define OPTION_GLIBC  (DEFAULT_LIBC == LIBC_GLIBC)
+ #define OPTION_UCLIBC (DEFAULT_LIBC == LIBC_UCLIBC)
+ #define OPTION_BIONIC (DEFAULT_LIBC == LIBC_BIONIC)
++#undef OPTION_MUSL
++#define OPTION_MUSL   (DEFAULT_LIBC == LIBC_MUSL)
+ #else
+ #define OPTION_GLIBC  (linux_libc == LIBC_GLIBC)
+ #define OPTION_UCLIBC (linux_libc == LIBC_UCLIBC)
+ #define OPTION_BIONIC (linux_libc == LIBC_BIONIC)
++#undef OPTION_MUSL
++#define OPTION_MUSL   (linux_libc == LIBC_MUSL)
+ #endif
+ 
+ /* Determine what functions are present at the runtime;
+--- a/gcc/config/rs6000/linux64.h
++++ b/gcc/config/rs6000/linux64.h
+@@ -299,10 +299,14 @@ extern int dot_symbols;
+ #define OPTION_GLIBC  (DEFAULT_LIBC == LIBC_GLIBC)
+ #define OPTION_UCLIBC (DEFAULT_LIBC == LIBC_UCLIBC)
+ #define OPTION_BIONIC (DEFAULT_LIBC == LIBC_BIONIC)
++#undef OPTION_MUSL
++#define OPTION_MUSL   (DEFAULT_LIBC == LIBC_MUSL)
+ #else
+ #define OPTION_GLIBC  (linux_libc == LIBC_GLIBC)
+ #define OPTION_UCLIBC (linux_libc == LIBC_UCLIBC)
+ #define OPTION_BIONIC (linux_libc == LIBC_BIONIC)
++#undef OPTION_MUSL
++#define OPTION_MUSL   (linux_libc == LIBC_MUSL)
+ #endif
+ 
+ /* Determine what functions are present at the runtime;
diff --git a/toolchain/gcc/patches/5.4.0/260-musl-add-unwind-fix.patch b/toolchain/gcc/patches/5.4.0/260-musl-add-unwind-fix.patch
new file mode 100644
index 0000000000..a3b83e2074
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/260-musl-add-unwind-fix.patch
@@ -0,0 +1,34 @@
+From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Wed, 22 Apr 2015 14:20:01 +0000 (+0000)
+Subject: unwind fix for musl
+X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=a2e31d0681d8a47389b8a3552622fbd9827bcef4
+
+unwind fix for musl
+
+On behalf of szabolcs.nagy@arm.com
+
+2015-04-22  Gregor Richards  <gregor.richards@uwaterloo.ca>
+	    Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* unwind-dw2-fde-dip.c (USE_PT_GNU_EH_FRAME): Define it on
+	Linux if target provides dl_iterate_phdr.
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222328 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+
+--- a/libgcc/unwind-dw2-fde-dip.c
++++ b/libgcc/unwind-dw2-fde-dip.c
+@@ -59,6 +59,12 @@
+ 
+ #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
+     && defined(TARGET_DL_ITERATE_PHDR) \
++    && defined(__linux__)
++# define USE_PT_GNU_EH_FRAME
++#endif
++
++#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
++    && defined(TARGET_DL_ITERATE_PHDR) \
+     && (defined(__DragonFly__) || defined(__FreeBSD__))
+ # define ElfW __ElfN
+ # define USE_PT_GNU_EH_FRAME
diff --git a/toolchain/gcc/patches/5.4.0/270-musl-add-powerpc-softfloat-fix.patch b/toolchain/gcc/patches/5.4.0/270-musl-add-powerpc-softfloat-fix.patch
new file mode 100644
index 0000000000..bdebf6c01f
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/270-musl-add-powerpc-softfloat-fix.patch
@@ -0,0 +1,24 @@
+--- a/gcc/config/rs6000/linux64.h
++++ b/gcc/config/rs6000/linux64.h
+@@ -369,8 +369,8 @@ extern int dot_symbols;
+ #endif
+ #define UCLIBC_DYNAMIC_LINKER32 "/lib/ld-uClibc.so.0"
+ #define UCLIBC_DYNAMIC_LINKER64 "/lib/ld64-uClibc.so.0"
+-#define MUSL_DYNAMIC_LINKER32 "/lib/ld-musl-powerpc" MUSL_DYNAMIC_LINKER_E ".so.1"
+-#define MUSL_DYNAMIC_LINKER64 "/lib/ld-musl-powerpc64" MUSL_DYNAMIC_LINKER_E ".so.1"
++#define MUSL_DYNAMIC_LINKER32 "/lib/ld-musl-powerpc" MUSL_DYNAMIC_LINKER_E "%{msoft-float:-sf}.so.1"
++#define MUSL_DYNAMIC_LINKER64 "/lib/ld-musl-powerpc64" MUSL_DYNAMIC_LINKER_E "%{msoft-float:-sf}.so.1"
+ #if DEFAULT_LIBC == LIBC_UCLIBC
+ #define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{mglibc:" G ";:%{mmusl:" M ";:" U "}}"
+ #elif DEFAULT_LIBC == LIBC_GLIBC
+--- a/gcc/config/rs6000/sysv4.h
++++ b/gcc/config/rs6000/sysv4.h
+@@ -765,7 +765,7 @@ ENDIAN_SELECT(" -mbig", " -mlittle", DEF
+ 
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
+ #define UCLIBC_DYNAMIC_LINKER "/lib/ld-uClibc.so.0"
+-#define MUSL_DYNAMIC_LINKER "/lib/ld-musl-powerpc" MUSL_DYNAMIC_LINKER_E ".so.1"
++#define MUSL_DYNAMIC_LINKER "/lib/ld-musl-powerpc" MUSL_DYNAMIC_LINKER_E "%{msoft-float:-sf}.so.1"
+ #if DEFAULT_LIBC == LIBC_UCLIBC
+ #define CHOOSE_DYNAMIC_LINKER(G, U, M) "%{mglibc:" G ";:%{mmusl:" M ";:" U "}}"
+ #elif DEFAULT_LIBC == LIBC_MUSL
diff --git a/toolchain/gcc/patches/5.4.0/280-musl-disable-ifunc-by-default.patch b/toolchain/gcc/patches/5.4.0/280-musl-disable-ifunc-by-default.patch
new file mode 100644
index 0000000000..af5acf8cc9
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/280-musl-disable-ifunc-by-default.patch
@@ -0,0 +1,38 @@
+From 450fb05e2a7510d37744f044009f8237d902f65c Mon Sep 17 00:00:00 2001
+From: nsz <nsz@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Tue, 30 Aug 2016 10:26:22 +0000
+Subject: [PATCH] disable ifunc on *-musl by default
+
+gcc/
+	* config.gcc (*-*-*musl*): Disable gnu-indirect-function.
+
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@239859 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+ gcc/ChangeLog  | 4 ++++
+ gcc/config.gcc | 4 ++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/gcc/config.gcc b/gcc/config.gcc
+index 8827dc8..e544d76 100644
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -1465,7 +1465,7 @@ i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-gnu* | i[34567]8
+ 		extra_options="${extra_options} linux-android.opt"
+ 		# Assume modern glibc if not targeting Android nor uclibc.
+ 		case ${target} in
+-		*-*-*android*|*-*-*uclibc*)
++		*-*-*android*|*-*-*uclibc*|*-*-*musl*)
+ 		  ;;
+ 		*)
+ 		  default_gnu_indirect_function=yes
+@@ -1531,7 +1531,7 @@ x86_64-*-linux* | x86_64-*-kfreebsd*-gnu)
+ 		extra_options="${extra_options} linux-android.opt"
+ 		# Assume modern glibc if not targeting Android nor uclibc.
+ 		case ${target} in
+-		*-*-*android*|*-*-*uclibc*)
++		*-*-*android*|*-*-*uclibc*|*-*-*musl*)
+ 		  ;;
+ 		*)
+ 		  default_gnu_indirect_function=yes
diff --git a/toolchain/gcc/patches/5.4.0/300-mips_Os_cpu_rtx_cost_model.patch b/toolchain/gcc/patches/5.4.0/300-mips_Os_cpu_rtx_cost_model.patch
new file mode 100644
index 0000000000..1743658ac6
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/300-mips_Os_cpu_rtx_cost_model.patch
@@ -0,0 +1,14 @@
+Use the proper rtx cost model for the selected CPU, even when optimizing
+for size. This generates better code.
+
+--- a/gcc/config/mips/mips.c
++++ b/gcc/config/mips/mips.c
+@@ -17483,7 +17483,7 @@ mips_option_override (void)
+     flag_pcc_struct_return = 0;
+ 
+   /* Decide which rtx_costs structure to use.  */
+-  if (optimize_size)
++  if (0 && optimize_size)
+     mips_cost = &mips_rtx_cost_optimize_size;
+   else
+     mips_cost = &mips_rtx_cost_data[mips_tune];
diff --git a/toolchain/gcc/patches/5.4.0/800-arm_v5te_no_ldrd_strd.patch b/toolchain/gcc/patches/5.4.0/800-arm_v5te_no_ldrd_strd.patch
new file mode 100644
index 0000000000..0edeb13c75
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/800-arm_v5te_no_ldrd_strd.patch
@@ -0,0 +1,11 @@
+--- a/gcc/config/arm/arm.h
++++ b/gcc/config/arm/arm.h
+@@ -285,7 +285,7 @@ extern void (*arm_lang_output_object_att
+ /* Thumb-1 only.  */
+ #define TARGET_THUMB1_ONLY		(TARGET_THUMB1 && !arm_arch_notm)
+ 
+-#define TARGET_LDRD			(arm_arch5e && ARM_DOUBLEWORD_ALIGN \
++#define TARGET_LDRD			(arm_arch6 && ARM_DOUBLEWORD_ALIGN \
+                                          && !TARGET_THUMB1)
+ 
+ #define TARGET_CRC32			(arm_arch_crc)
diff --git a/toolchain/gcc/patches/5.4.0/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches/5.4.0/810-arm-softfloat-libgcc.patch
new file mode 100644
index 0000000000..1d06f5b2ec
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/810-arm-softfloat-libgcc.patch
@@ -0,0 +1,25 @@
+--- a/libgcc/config/arm/t-linux
++++ b/libgcc/config/arm/t-linux
+@@ -1,6 +1,10 @@
+ LIB1ASMSRC = arm/lib1funcs.S
+ LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \
+-	_ctzsi2 _arm_addsubdf3 _arm_addsubsf3
++	_ctzsi2 _arm_addsubdf3 _arm_addsubsf3 \
++	_arm_negdf2 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \
++	_arm_fixdfsi _arm_fixunsdfsi _arm_truncdfsf2 \
++	_arm_negsf2 _arm_muldivsf3 _arm_cmpsf2 _arm_unordsf2 \
++	_arm_fixsfsi _arm_fixunssfsi
+ 
+ # Just for these, we omit the frame pointer since it makes such a big
+ # difference.
+--- a/gcc/config/arm/linux-elf.h
++++ b/gcc/config/arm/linux-elf.h
+@@ -60,8 +60,6 @@
+    %{shared:-lc} \
+    %{!shared:%{profile:-lc_p}%{!profile:-lc}}"
+ 
+-#define LIBGCC_SPEC "%{mfloat-abi=soft*:-lfloat} -lgcc"
+-
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
+ 
+ #define LINUX_TARGET_LINK_SPEC  "%{h*} \
diff --git a/toolchain/gcc/patches/5.4.0/820-libgcc_pic.patch b/toolchain/gcc/patches/5.4.0/820-libgcc_pic.patch
new file mode 100644
index 0000000000..42bf0c8ccc
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/820-libgcc_pic.patch
@@ -0,0 +1,36 @@
+--- a/libgcc/Makefile.in
++++ b/libgcc/Makefile.in
+@@ -887,11 +887,12 @@ $(libgcov-driver-objects): %$(objext): $
+ 
+ # Static libraries.
+ libgcc.a: $(libgcc-objects)
++libgcc_pic.a: $(libgcc-s-objects)
+ libgcov.a: $(libgcov-objects)
+ libunwind.a: $(libunwind-objects)
+ libgcc_eh.a: $(libgcc-eh-objects)
+ 
+-libgcc.a libgcov.a libunwind.a libgcc_eh.a:
++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a:
+ 	-rm -f $@
+ 
+ 	objects="$(objects)";					\
+@@ -913,7 +914,7 @@ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_E
+ endif
+ 
+ ifeq ($(enable_shared),yes)
+-all: libgcc_eh.a libgcc_s$(SHLIB_EXT)
++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT)
+ ifneq ($(LIBUNWIND),)
+ all: libunwind$(SHLIB_EXT)
+ endif
+@@ -1108,6 +1109,10 @@ install-shared:
+ 	chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a
+ 	$(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a
+ 
++	$(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/
++	chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a
++	$(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a
++
+ 	$(subst @multilib_dir@,$(MULTIDIR),$(subst \
+ 		@shlib_base_name@,libgcc_s,$(subst \
+ 		@shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL))))
diff --git a/toolchain/gcc/patches/5.4.0/830-arm_unbreak_armv4t.patch b/toolchain/gcc/patches/5.4.0/830-arm_unbreak_armv4t.patch
new file mode 100644
index 0000000000..37f8f2a54d
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/830-arm_unbreak_armv4t.patch
@@ -0,0 +1,13 @@
+http://sourceware.org/ml/crossgcc/2008-05/msg00009.html
+
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -45,7 +45,7 @@
+    The ARM10TDMI core is the default for armv5t, so set
+    SUBTARGET_CPU_DEFAULT to achieve this.  */
+ #undef  SUBTARGET_CPU_DEFAULT
+-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi
++#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm9tdmi
+ 
+ /* TARGET_BIG_ENDIAN_DEFAULT is set in
+    config.gcc for big endian configurations.  */
diff --git a/toolchain/gcc/patches/5.4.0/840-armv4_pass_fix-v4bx_to_ld.patch b/toolchain/gcc/patches/5.4.0/840-armv4_pass_fix-v4bx_to_ld.patch
new file mode 100644
index 0000000000..cb1fb98235
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/840-armv4_pass_fix-v4bx_to_ld.patch
@@ -0,0 +1,19 @@
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -94,10 +94,15 @@
+ #define MUSL_DYNAMIC_LINKER \
+   "/lib/ld-musl-arm" MUSL_DYNAMIC_LINKER_E "%{mfloat-abi=hard:hf}.so.1"
+ 
++/* For armv4 we pass --fix-v4bx to linker to support EABI */
++#undef TARGET_FIX_V4BX_SPEC
++#define TARGET_FIX_V4BX_SPEC " %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*"\
++  "|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}"
++
+ /* At this point, bpabi.h will have clobbered LINK_SPEC.  We want to
+    use the GNU/Linux version, not the generic BPABI version.  */
+ #undef  LINK_SPEC
+-#define LINK_SPEC EABI_LINK_SPEC					\
++#define LINK_SPEC EABI_LINK_SPEC TARGET_FIX_V4BX_SPEC			\
+   LINUX_OR_ANDROID_LD (LINUX_TARGET_LINK_SPEC,				\
+ 		       LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC)
+ 
diff --git a/toolchain/gcc/patches/5.4.0/850-use_shared_libgcc.patch b/toolchain/gcc/patches/5.4.0/850-use_shared_libgcc.patch
new file mode 100644
index 0000000000..5818cf4da0
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/850-use_shared_libgcc.patch
@@ -0,0 +1,47 @@
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -131,10 +131,6 @@
+ #define ENDFILE_SPEC \
+   LINUX_OR_ANDROID_LD (GNU_USER_TARGET_ENDFILE_SPEC, ANDROID_ENDFILE_SPEC)
+ 
+-/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we
+-   do not use -lfloat.  */
+-#undef LIBGCC_SPEC
+-
+ /* Clear the instruction cache from `beg' to `end'.  This is
+    implemented in lib1funcs.S, so ensure an error if this definition
+    is used.  */
+--- a/gcc/config/linux.h
++++ b/gcc/config/linux.h
+@@ -53,6 +53,10 @@ see the files COPYING3 and COPYING.RUNTI
+ 	builtin_assert ("system=posix");			\
+     } while (0)
+ 
++#ifndef LIBGCC_SPEC
++#define LIBGCC_SPEC "%{static|static-libgcc:-lgcc}%{!static:%{!static-libgcc:-lgcc_s}}"
++#endif
++
+ /* Determine which dynamic linker to use depending on whether GLIBC or
+    uClibc or Bionic or musl is the default C library and whether
+    -muclibc or -mglibc or -mbionic or -mmusl has been passed to change
+--- a/libgcc/mkmap-symver.awk
++++ b/libgcc/mkmap-symver.awk
+@@ -132,5 +132,5 @@ function output(lib) {
+   else if (inherit[lib])
+     printf("} %s;\n", inherit[lib]);
+   else
+-    printf ("\n  local:\n\t*;\n};\n");
++    printf ("\n\t*;\n};\n");
+ }
+--- a/gcc/config/rs6000/linux.h
++++ b/gcc/config/rs6000/linux.h
+@@ -60,6 +60,9 @@
+ #undef	CPP_OS_DEFAULT_SPEC
+ #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)"
+ 
++#undef LIBGCC_SPEC
++#define LIBGCC_SPEC "%{!static:%{!static-libgcc:-lgcc_s}} -lgcc"
++
+ #undef  LINK_SHLIB_SPEC
+ #define LINK_SHLIB_SPEC "%{shared:-shared} %{!shared: %{static:-static}}"
+ 
diff --git a/toolchain/gcc/patches/5.4.0/851-libgcc_no_compat.patch b/toolchain/gcc/patches/5.4.0/851-libgcc_no_compat.patch
new file mode 100644
index 0000000000..80c3476841
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/851-libgcc_no_compat.patch
@@ -0,0 +1,12 @@
+--- a/libgcc/config/t-libunwind
++++ b/libgcc/config/t-libunwind
+@@ -2,8 +2,7 @@
+ 
+ HOST_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER
+ 
+-LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \
+-  $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c
++LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
+ LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
+ 
+ # Override the default value from t-slibgcc-elf-ver and mention -lunwind
diff --git a/toolchain/gcc/patches/5.4.0/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches/5.4.0/870-ppc_no_crtsavres.patch
new file mode 100644
index 0000000000..0e64a4164b
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/870-ppc_no_crtsavres.patch
@@ -0,0 +1,11 @@
+--- a/gcc/config/rs6000/rs6000.c
++++ b/gcc/config/rs6000/rs6000.c
+@@ -21500,7 +21500,7 @@ rs6000_savres_strategy (rs6000_stack_t *
+   /* Define cutoff for using out-of-line functions to save registers.  */
+   if (DEFAULT_ABI == ABI_V4 || TARGET_ELF)
+     {
+-      if (!optimize_size)
++      if (1)
+ 	{
+ 	  strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
+ 	  strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
diff --git a/toolchain/gcc/patches/5.4.0/880-no_java_section.patch b/toolchain/gcc/patches/5.4.0/880-no_java_section.patch
new file mode 100644
index 0000000000..def6c9f4a0
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/880-no_java_section.patch
@@ -0,0 +1,11 @@
+--- a/gcc/defaults.h
++++ b/gcc/defaults.h
+@@ -380,7 +380,7 @@ see the files COPYING3 and COPYING.RUNTI
+ /* If we have named section and we support weak symbols, then use the
+    .jcr section for recording java classes which need to be registered
+    at program start-up time.  */
+-#if defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
++#if 0 && defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
+ #ifndef JCR_SECTION_NAME
+ #define JCR_SECTION_NAME ".jcr"
+ #endif
diff --git a/toolchain/gcc/patches/5.4.0/900-bad-mips16-crt.patch b/toolchain/gcc/patches/5.4.0/900-bad-mips16-crt.patch
new file mode 100644
index 0000000000..dd6e9dc889
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/900-bad-mips16-crt.patch
@@ -0,0 +1,9 @@
+--- a/libgcc/config/mips/t-mips16
++++ b/libgcc/config/mips/t-mips16
+@@ -43,3 +43,6 @@ SYNC_CFLAGS = -mno-mips16
+ 
+ # Version these symbols if building libgcc.so.
+ SHLIB_MAPFILES += $(srcdir)/config/mips/libgcc-mips16.ver
++
++CRTSTUFF_T_CFLAGS += -mno-mips16
++CRTSTUFF_T_CFLAGS_S += -mno-mips16
diff --git a/toolchain/gcc/patches/5.4.0/910-mbsd_multi.patch b/toolchain/gcc/patches/5.4.0/910-mbsd_multi.patch
new file mode 100644
index 0000000000..32fc9da962
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/910-mbsd_multi.patch
@@ -0,0 +1,222 @@
+
+	This patch brings over a few features from MirBSD:
+	* -fhonour-copts
+	  If this option is not given, it's warned (depending
+	  on environment variables). This is to catch errors
+	  of misbuilt packages which override CFLAGS themselves.
+	* -Werror-maybe-reset
+	  Has the effect of -Wno-error if GCC_NO_WERROR is
+	  set and not '0', a no-operation otherwise. This is
+	  to be able to use -Werror in "make" but prevent
+	  GNU autoconf generated configure scripts from
+	  freaking out.
+
+	This patch was authored by Thorsten Glaser <tg at mirbsd.de>
+	with copyright assignment to the FSF in effect.
+
+--- a/gcc/c-family/c-opts.c
++++ b/gcc/c-family/c-opts.c
+@@ -122,6 +122,9 @@ static int class_dump_flags;
+ /* Whether any standard preincluded header has been preincluded.  */
+ static bool done_preinclude;
+ 
++/* Check if a port honours COPTS.  */
++static int honour_copts = 0;
++
+ static void handle_OPT_d (const char *);
+ static void set_std_cxx98 (int);
+ static void set_std_cxx11 (int);
+@@ -449,6 +452,12 @@ c_common_handle_option (size_t scode, co
+       flag_no_builtin = !value;
+       break;
+ 
++    case OPT_fhonour_copts:
++      if (c_language == clk_c) {
++        honour_copts++;
++      }
++      break;
++
+     case OPT_fconstant_string_class_:
+       constant_string_class_name = arg;
+       break;
+@@ -1034,6 +1043,47 @@ c_common_init (void)
+       return false;
+     }
+ 
++  if (c_language == clk_c) {
++    char *ev = getenv ("GCC_HONOUR_COPTS");
++    int evv;
++    if (ev == NULL)
++      evv = -1;
++    else if ((*ev == '0') || (*ev == '\0'))
++      evv = 0;
++    else if (*ev == '1')
++      evv = 1;
++    else if (*ev == '2')
++      evv = 2;
++    else if (*ev == 's')
++      evv = -1;
++    else {
++      warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1");
++      evv = 1; /* maybe depend this on something like MIRBSD_NATIVE?  */
++    }
++    if (evv == 1) {
++      if (honour_copts == 0) {
++        error ("someone does not honour COPTS at all in lenient mode");
++        return false;
++      } else if (honour_copts != 1) {
++        warning (0, "someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++      }
++    } else if (evv == 2) {
++      if (honour_copts == 0) {
++        error ("someone does not honour COPTS at all in strict mode");
++        return false;
++      } else if (honour_copts != 1) {
++        error ("someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++        return false;
++      }
++    } else if (evv == 0) {
++      if (honour_copts != 1)
++        inform (0, "someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++    }
++  }
++
+   return true;
+ }
+ 
+--- a/gcc/c-family/c.opt
++++ b/gcc/c-family/c.opt
+@@ -431,6 +431,10 @@ Wfloat-conversion
+ C ObjC C++ ObjC++ Var(warn_float_conversion) LangEnabledBy(C ObjC C++ ObjC++,Wconversion)
+ Warn for implicit type conversions that cause loss of floating point precision
+ 
++Werror-maybe-reset
++C ObjC C++ ObjC++
++; Documented in common.opt
++
+ Wfloat-equal
+ C ObjC C++ ObjC++ Var(warn_float_equal) Warning
+ Warn if testing floating point numbers for equality
+@@ -1161,6 +1165,9 @@ C++ ObjC++ Optimization Alias(fexception
+ fhonor-std
+ C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+ 
++fhonour-copts
++C ObjC C++ ObjC++ RejectNegative
++
+ fhosted
+ C ObjC
+ Assume normal C execution environment
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -561,6 +561,10 @@ Werror=
+ Common Joined
+ Treat specified warning as error
+ 
++Werror-maybe-reset
++Common
++If environment variable GCC_NO_WERROR is set, act as -Wno-error
++
+ Wextra
+ Common Var(extra_warnings) Warning
+ Print extra (possibly unwanted) warnings
+@@ -1360,6 +1364,9 @@ fguess-branch-probability
+ Common Report Var(flag_guess_branch_prob) Optimization
+ Enable guessing of branch probabilities
+ 
++fhonour-copts
++Common RejectNegative
++
+ ; Nonzero means ignore `#ident' directives.  0 means handle them.
+ ; Generate position-independent code for executables if possible
+ ; On SVR4 targets, it also controls whether or not to emit a
+--- a/gcc/opts.c
++++ b/gcc/opts.c
+@@ -1699,6 +1699,17 @@ common_handle_option (struct gcc_options
+ 			       opts, opts_set, loc, dc);
+       break;
+ 
++    case OPT_Werror_maybe_reset:
++      {
++        char *ev = getenv ("GCC_NO_WERROR");
++        if ((ev != NULL) && (*ev != '0'))
++          warnings_are_errors = 0;
++      }
++      break;
++
++    case OPT_fhonour_copts:
++      break;
++
+     case OPT_Wlarger_than_:
+       opts->x_larger_than_size = value;
+       opts->x_warn_larger_than = value != -1;
+--- a/gcc/doc/cppopts.texi
++++ b/gcc/doc/cppopts.texi
+@@ -163,6 +163,11 @@ in older programs.  This warning is on b
+ Make all warnings into hard errors.  Source code which triggers warnings
+ will be rejected.
+ 
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
+ @item -Wsystem-headers
+ @opindex Wsystem-headers
+ Issue warnings for code in system headers.  These are normally unhelpful
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -251,7 +251,7 @@ Objective-C and Objective-C++ Dialects}.
+ -Wdisabled-optimization @gol
+ -Wno-discarded-qualifiers -Wno-discarded-array-qualifiers @gol
+ -Wno-div-by-zero -Wdouble-promotion -Wempty-body  -Wenum-compare @gol
+--Wno-endif-labels -Werror  -Werror=* @gol
++-Wno-endif-labels -Werror  -Werror=* -Werror-maybe-reset @gol
+ -Wfatal-errors  -Wfloat-equal  -Wformat  -Wformat=2 @gol
+ -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol
+ -Wformat-security  -Wformat-signedness  -Wformat-y2k @gol
+@@ -5382,6 +5382,22 @@ This option is only supported for C and
+ @option{-Wall} and by @option{-Wpedantic}, which can be disabled with
+ @option{-Wno-pointer-sign}.
+ 
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
++ at item -fhonour-copts
++ at opindex fhonour-copts
++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not
++given at least once, and warn if it is given more than once.
++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not
++given exactly once.
++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option
++is not given exactly once.
++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}.
++This flag and environment variable only affect the C language.
++
+ @item -Wstack-protector
+ @opindex Wstack-protector
+ @opindex Wno-stack-protector
+@@ -7860,7 +7876,7 @@ so, the first branch is redirected to ei
+ second branch or a point immediately following it, depending on whether
+ the condition is known to be true or false.
+ 
+-Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
++Enabled at levels @option{-O3}.
+ 
+ @item -fsplit-wide-types
+ @opindex fsplit-wide-types
+--- a/gcc/java/jvspec.c
++++ b/gcc/java/jvspec.c
+@@ -629,6 +629,7 @@ lang_specific_pre_link (void)
+      class name.  Append dummy `.c' that can be stripped by set_input so %b
+      is correct.  */ 
+   set_input (concat (main_class_name, "main.c", NULL));
++  putenv ("GCC_HONOUR_COPTS=s"); /* XXX hack!  */
+   err = do_spec (jvgenmain_spec);
+   if (err == 0)
+     {
diff --git a/toolchain/gcc/patches/5.4.0/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches/5.4.0/920-specs_nonfatal_getenv.patch
new file mode 100644
index 0000000000..3d708f24c3
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/920-specs_nonfatal_getenv.patch
@@ -0,0 +1,15 @@
+--- a/gcc/gcc.c
++++ b/gcc/gcc.c
+@@ -8807,8 +8807,10 @@ getenv_spec_function (int argc, const ch
+ 
+   value = getenv (argv[0]);
+   if (!value)
+-    fatal_error (input_location,
+-		 "environment variable %qs not defined", argv[0]);
++    {
++      warning (input_location, "environment variable %qs not defined", argv[0]);
++      value = "";
++    }
+ 
+   /* We have to escape every character of the environment variable so
+      they are not interpreted as active spec characters.  A
diff --git a/toolchain/gcc/patches/5.4.0/930-fix-mips-noexecstack.patch b/toolchain/gcc/patches/5.4.0/930-fix-mips-noexecstack.patch
new file mode 100644
index 0000000000..c05844d2e4
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/930-fix-mips-noexecstack.patch
@@ -0,0 +1,111 @@
+From da45b3fde60095756f5f6030f6012c23a3d34429 Mon Sep 17 00:00:00 2001
+From: Andrew McDonnell <bugs@andrewmcdonnell.net>
+Date: Fri, 3 Oct 2014 19:09:00 +0930
+Subject: Add .note.GNU-stack section
+
+See http://lists.busybox.net/pipermail/uclibc/2014-October/048671.html
+Below copied from https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02430.html
+
+Re: [Patch, MIPS] Add .note.GNU-stack section
+
+    From: Steve Ellcey <sellcey at mips dot com>
+
+On Wed, 2014-09-10 at 10:15 -0700, Eric Christopher wrote:
+>
+>
+> On Wed, Sep 10, 2014 at 9:27 AM, <pinskia@gmail.com> wrote:
+
+>         This works except you did not update the assembly files in
+>         libgcc or glibc. We (Cavium) have the same patch in our tree
+>         for a few released versions.
+
+> Mind just checking yours in then Andrew?
+
+> Thanks!
+> -eric
+
+I talked to Andrew about what files he changed in GCC and created and
+tested this new patch.  Andrew also mentioned changing some assembly
+files in glibc but I don't see any use of '.section .note.GNU-stack' in
+any assembly files in glibc (for any platform) so I wasn't planning on
+creating a glibc to add them to mips glibc assembly language files.
+
+OK to check in this patch?
+
+Steve Ellcey
+sellcey@mips.com
+
+
+
+2014-09-26  Steve Ellcey  <sellcey@mips.com>
+---
+ gcc/config/mips/mips.c          | 3 +++
+ libgcc/config/mips/crti.S       | 4 ++++
+ libgcc/config/mips/crtn.S       | 3 +++
+ libgcc/config/mips/mips16.S     | 4 ++++
+ libgcc/config/mips/vr4120-div.S | 4 ++++
+ 5 files changed, 18 insertions(+)
+
+--- a/gcc/config/mips/mips.c
++++ b/gcc/config/mips/mips.c
+@@ -19629,6 +19629,9 @@ mips_lra_p (void)
+ #undef TARGET_LRA_P
+ #define TARGET_LRA_P mips_lra_p
+ 
++#undef TARGET_ASM_FILE_END
++#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
++
+ struct gcc_target targetm = TARGET_INITIALIZER;
+ 
+ #include "gt-mips.h"
+--- a/libgcc/config/mips/crti.S
++++ b/libgcc/config/mips/crti.S
+@@ -21,6 +21,10 @@ a copy of the GCC Runtime Library Except
+ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ <http://www.gnu.org/licenses/>.  */
+ 
++
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++
+ /* 4 slots for argument spill area.  1 for cpreturn, 1 for stack.
+    Return spill offset of 40 and 20.  Aligned to 16 bytes for n32.  */
+ 
+--- a/libgcc/config/mips/crtn.S
++++ b/libgcc/config/mips/crtn.S
+@@ -21,6 +21,9 @@ a copy of the GCC Runtime Library Except
+ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ <http://www.gnu.org/licenses/>.  */
+ 
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++
+ /* 4 slots for argument spill area.  1 for cpreturn, 1 for stack.
+    Return spill offset of 40 and 20.  Aligned to 16 bytes for n32.  */
+ 
+--- a/libgcc/config/mips/mips16.S
++++ b/libgcc/config/mips/mips16.S
+@@ -48,6 +48,10 @@ see the files COPYING3 and COPYING.RUNTI
+    values using the soft-float calling convention, but do the actual
+    operation using the hard floating point instructions.  */
+ 
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++	.previous
++
+ #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
+ 
+ /* This file contains 32-bit assembly code.  */
+--- a/libgcc/config/mips/vr4120-div.S
++++ b/libgcc/config/mips/vr4120-div.S
+@@ -26,6 +26,10 @@ see the files COPYING3 and COPYING.RUNTI
+    -mfix-vr4120.  div and ddiv do not give the correct result when one
+    of the operands is negative.  */
+ 
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++	.previous
++
+ 	.set	nomips16
+ 
+ #define DIV								\
diff --git a/toolchain/gcc/patches/5.4.0/931-fix-MIPS-softfloat-build-issue.patch b/toolchain/gcc/patches/5.4.0/931-fix-MIPS-softfloat-build-issue.patch
new file mode 100644
index 0000000000..c8461a9618
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/931-fix-MIPS-softfloat-build-issue.patch
@@ -0,0 +1,174 @@
+From 2b46f9187b6f994fc450628a7cd97fc703dd23e0 Mon Sep 17 00:00:00 2001
+From: BangLang Huang <banglang.huang@foxmail.com>
+Date: Wed, 9 Nov 2016 10:36:49 +0800
+Subject: [PATCH] fix MIPS softfloat build issue
+
+    This patch is backport from github/libffi #272
+
+Signed-off-by: BangLang Huang <banglang.huang@foxmail.com>
+---
+ libffi/src/mips/n32.S | 17 +++++++++++++++++
+ libffi/src/mips/o32.S | 17 +++++++++++++++++
+ 2 files changed, 34 insertions(+)
+
+diff --git a/libffi/src/mips/n32.S b/libffi/src/mips/n32.S
+index c6985d3..8f25994 100644
+--- a/libffi/src/mips/n32.S
++++ b/libffi/src/mips/n32.S
+@@ -107,6 +107,16 @@ loadregs:
+ 
+ 	REG_L	t6, 3*FFI_SIZEOF_ARG($fp)  # load the flags word into t6.
+ 
++#ifdef __mips_soft_float
++	REG_L	a0, 0*FFI_SIZEOF_ARG(t9)
++	REG_L	a1, 1*FFI_SIZEOF_ARG(t9)
++	REG_L	a2, 2*FFI_SIZEOF_ARG(t9)
++	REG_L	a3, 3*FFI_SIZEOF_ARG(t9)
++	REG_L	a4, 4*FFI_SIZEOF_ARG(t9)
++	REG_L	a5, 5*FFI_SIZEOF_ARG(t9)
++	REG_L	a6, 6*FFI_SIZEOF_ARG(t9)
++	REG_L	a7, 7*FFI_SIZEOF_ARG(t9)
++#else
+ 	and	t4, t6, ((1<<FFI_FLAG_BITS)-1)
+ 	REG_L	a0, 0*FFI_SIZEOF_ARG(t9)
+ 	beqz	t4, arg1_next
+@@ -193,6 +203,7 @@ arg7_next:
+ arg8_doublep:	
+  	l.d	$f19, 7*FFI_SIZEOF_ARG(t9)	
+ arg8_next:	
++#endif
+ 
+ callit:		
+ 	# Load the function pointer
+@@ -214,6 +225,7 @@ retint:
+ 	b	epilogue
+ 
+ retfloat:
++#ifndef __mips_soft_float
+ 	bne     t6, FFI_TYPE_FLOAT, retdouble
+ 	jal	t9
+ 	REG_L	t4, 4*FFI_SIZEOF_ARG($fp)
+@@ -272,6 +284,7 @@ retstruct_f_d:
+ 	s.s	$f0, 0(t4)
+ 	s.d	$f2, 8(t4)
+ 	b	epilogue
++#endif
+ 
+ retstruct_d_soft:
+ 	bne	t6, FFI_TYPE_STRUCT_D_SOFT, retstruct_f_soft
+@@ -429,6 +442,7 @@ ffi_closure_N32:
+ 	REG_S	a6, A6_OFF2($sp)
+ 	REG_S	a7, A7_OFF2($sp)
+ 
++#ifndef __mips_soft_float
+ 	# Store all possible float/double registers.
+ 	s.d	$f12, F12_OFF2($sp)
+ 	s.d	$f13, F13_OFF2($sp)
+@@ -438,6 +452,7 @@ ffi_closure_N32:
+ 	s.d	$f17, F17_OFF2($sp)
+ 	s.d	$f18, F18_OFF2($sp)
+ 	s.d	$f19, F19_OFF2($sp)
++#endif
+ 
+ 	# Call ffi_closure_mips_inner_N32 to do the real work.
+ 	LA	t9, ffi_closure_mips_inner_N32
+@@ -458,6 +473,7 @@ cls_retint:
+ 	b	cls_epilogue
+ 
+ cls_retfloat:
++#ifndef __mips_soft_float
+ 	bne     v0, FFI_TYPE_FLOAT, cls_retdouble
+ 	l.s	$f0, V0_OFF2($sp)
+ 	b	cls_epilogue
+@@ -500,6 +516,7 @@ cls_retstruct_f_d:
+ 	l.s	$f0, V0_OFF2($sp)
+ 	l.d	$f2, V1_OFF2($sp)
+ 	b	cls_epilogue
++#endif
+ 	
+ cls_retstruct_small2:	
+ 	REG_L	v0, V0_OFF2($sp)
+diff --git a/libffi/src/mips/o32.S b/libffi/src/mips/o32.S
+index eb27981..1aff4b1 100644
+--- a/libffi/src/mips/o32.S
++++ b/libffi/src/mips/o32.S
+@@ -82,13 +82,16 @@ sixteen:
+ 		
+ 	ADDU	$sp, 4 * FFI_SIZEOF_ARG		# adjust $sp to new args
+ 
++#ifndef __mips_soft_float
+ 	bnez	t0, pass_d			# make it quick for int
++#endif
+ 	REG_L	a0, 0*FFI_SIZEOF_ARG($sp)	# just go ahead and load the
+ 	REG_L	a1, 1*FFI_SIZEOF_ARG($sp)	# four regs.
+ 	REG_L	a2, 2*FFI_SIZEOF_ARG($sp)
+ 	REG_L	a3, 3*FFI_SIZEOF_ARG($sp)
+ 	b	call_it
+ 
++#ifndef __mips_soft_float
+ pass_d:
+ 	bne	t0, FFI_ARGS_D, pass_f
+ 	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
+@@ -130,6 +133,7 @@ pass_f_d:
+  #	bne	t0, FFI_ARGS_F_D, call_it
+ 	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
+ 	l.d	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing double and float
++#endif
+ 
+ call_it:	
+ 	# Load the function pointer
+@@ -158,14 +162,23 @@ retfloat:
+ 	bne     t2, FFI_TYPE_FLOAT, retdouble
+ 	jalr	t9
+ 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
++#ifndef __mips_soft_float
+ 	s.s	$f0, 0(t0)
++#else
++	REG_S v0, 0(t0)
++#endif
+ 	b	epilogue
+ 
+ retdouble:	
+ 	bne	t2, FFI_TYPE_DOUBLE, noretval
+ 	jalr	t9
+ 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
++#ifndef __mips_soft_float
+ 	s.d	$f0, 0(t0)
++#else
++	REG_S v1, 4(t0)
++	REG_S v0, 0(t0)
++#endif
+ 	b	epilogue
+ 	
+ noretval:	
+@@ -261,9 +274,11 @@ $LCFI7:
+ 	li	$13, 1		# FFI_O32
+ 	bne	$16, $13, 1f	# Skip fp save if FFI_O32_SOFT_FLOAT
+ 	
++#ifndef __mips_soft_float
+ 	# Store all possible float/double registers.
+ 	s.d	$f12, FA_0_0_OFF2($fp)
+ 	s.d	$f14, FA_1_0_OFF2($fp)
++#endif
+ 1:	
+ 	# Call ffi_closure_mips_inner_O32 to do the work.
+ 	la	t9, ffi_closure_mips_inner_O32
+@@ -281,6 +296,7 @@ $LCFI7:
+ 	li	$13, 1		# FFI_O32
+ 	bne	$16, $13, 1f	# Skip fp restore if FFI_O32_SOFT_FLOAT
+ 
++#ifndef __mips_soft_float
+ 	li	$9, FFI_TYPE_FLOAT
+ 	l.s	$f0, V0_OFF2($fp)
+ 	beq	$8, $9, closure_done
+@@ -288,6 +304,7 @@ $LCFI7:
+ 	li	$9, FFI_TYPE_DOUBLE
+ 	l.d	$f0, V0_OFF2($fp)
+ 	beq	$8, $9, closure_done
++#endif
+ 1:	
+ 	REG_L	$3, V1_OFF2($fp)
+ 	REG_L	$2, V0_OFF2($fp)
+-- 
+2.7.4
+
diff --git a/toolchain/gcc/patches/5.4.0/940-no-clobber-stamp-bits.patch b/toolchain/gcc/patches/5.4.0/940-no-clobber-stamp-bits.patch
new file mode 100644
index 0000000000..0b21ffaf09
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/940-no-clobber-stamp-bits.patch
@@ -0,0 +1,11 @@
+--- a/libstdc++-v3/include/Makefile.in
++++ b/libstdc++-v3/include/Makefile.in
+@@ -1421,7 +1421,7 @@ stamp-bits: ${bits_headers}
+ 	@$(STAMP) stamp-bits
+ 
+ stamp-bits-sup: stamp-bits ${bits_sup_headers}
+-	@-cd ${bits_builddir} && $(LN_S) $? . 2>/dev/null
++	@-cd ${bits_builddir} && $(LN_S) $(filter-out stamp-bits,$?) . 2>/dev/null
+ 	@$(STAMP) stamp-bits-sup
+ 
+ stamp-c_base: ${c_base_headers}
diff --git a/toolchain/gcc/patches/5.4.0/950-cpp_file_path_translation.patch b/toolchain/gcc/patches/5.4.0/950-cpp_file_path_translation.patch
new file mode 100644
index 0000000000..dc0938ab63
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/950-cpp_file_path_translation.patch
@@ -0,0 +1,182 @@
+Forward ported from attachment to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47047
+
+--- a/gcc/c-family/c-opts.c
++++ b/gcc/c-family/c-opts.c
+@@ -581,6 +581,10 @@ c_common_handle_option (size_t scode, co
+       add_path (xstrdup (arg), SYSTEM, 0, true);
+       break;
+ 
++    case OPT_iremap:
++      add_cpp_remap_path (arg);
++      break;
++
+     case OPT_iwithprefix:
+       add_prefixed_path (arg, SYSTEM);
+       break;
+--- a/gcc/c-family/c.opt
++++ b/gcc/c-family/c.opt
+@@ -1528,6 +1528,10 @@ iquote
+ C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+ -iquote <dir>	Add <dir> to the end of the quote include path
+ 
++iremap
++C ObjC C++ ObjC++ Joined Separate
++-iremap <src:dst>  Convert <src> to <dst> if it occurs as prefix in __FILE__.
++
+ iwithprefix
+ C ObjC C++ ObjC++ Joined Separate
+ -iwithprefix <dir>	Add <dir> to the end of the system include path
+--- a/gcc/doc/cpp.texi
++++ b/gcc/doc/cpp.texi
+@@ -4441,6 +4441,7 @@ without notice.
+ @c man begin SYNOPSIS
+ cpp [@option{-D}@var{macro}[=@var{defn}]@dots{}] [@option{-U}@var{macro}]
+     [@option{-I}@var{dir}@dots{}] [@option{-iquote}@var{dir}@dots{}]
++    [@option{-iremap}@var{src}:@var{dst}]
+     [@option{-W}@var{warn}@dots{}]
+     [@option{-M}|@option{-MM}] [@option{-MG}] [@option{-MF} @var{filename}]
+     [@option{-MP}] [@option{-MQ} @var{target}@dots{}]
+--- a/gcc/doc/cppopts.texi
++++ b/gcc/doc/cppopts.texi
+@@ -532,6 +532,12 @@ Search @var{dir} only for header files r
+ If @var{dir} begins with @code{=}, then the @code{=} will be replaced
+ by the sysroot prefix; see @option{--sysroot} and @option{-isysroot}.
+ 
++@item -iremap @var{src}:@var{dst}
++@opindex iremap
++Replace the prefix @var{src} in __FILE__ with @var{dst} at expansion time.
++This option can be specified more than once.  Processing stops at the first
++match.
++
+ @item -fdirectives-only
+ @opindex fdirectives-only
+ When preprocessing, handle directives, but do not expand macros.
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -494,8 +494,8 @@ Objective-C and Objective-C++ Dialects}.
+ @item Directory Options
+ @xref{Directory Options,,Options for Directory Search}.
+ @gccoptlist{-B@var{prefix} -I@var{dir} -iplugindir=@var{dir} @gol
+--iquote@var{dir} -L@var{dir} -specs=@var{file} -I- @gol
+---sysroot=@var{dir} --no-sysroot-suffix}
++-iquote@var{dir} -iremap@var{src}:@var{dst} -L@var{dir} -specs=@var{file} @gol
++-I- --sysroot=@var{dir} --no-sysroot-suffix}
+ 
+ @item Machine Dependent Options
+ @xref{Submodel Options,,Hardware Models and Configurations}.
+@@ -11479,6 +11479,12 @@ be searched for header files only for th
+ "@var{file}"}; they are not searched for @code{#include <@var{file}>},
+ otherwise just like @option{-I}.
+ 
++@item -iremap @var{src}:@var{dst}
++@opindex iremap
++Replace the prefix @var{src} in __FILE__ with @var{dst} at expansion time.
++This option can be specified more than once.  Processing stops at the first
++match.
++
+ @item -L@var{dir}
+ @opindex L
+ Add directory @var{dir} to the list of directories to be searched
+--- a/libcpp/include/cpplib.h
++++ b/libcpp/include/cpplib.h
+@@ -751,6 +751,9 @@ extern void cpp_set_lang (cpp_reader *,
+ /* Set the include paths.  */
+ extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int);
+ 
++/* Provide src:dst pair for __FILE__ remapping.  */
++extern void add_cpp_remap_path (const char *);
++
+ /* Call these to get pointers to the options, callback, and deps
+    structures for a given reader.  These pointers are good until you
+    call cpp_finish on that reader.  You can either edit the callbacks
+--- a/libcpp/macro.c
++++ b/libcpp/macro.c
+@@ -224,6 +224,64 @@ static const char * const monthnames[] =
+   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ 
++static size_t remap_pairs;
++static char **remap_src;
++static char **remap_dst;
++
++void
++add_cpp_remap_path (const char *arg)
++{
++  const char *arg_dst;
++  size_t len;
++
++  arg_dst = strchr(arg, ':');
++  if (arg_dst == NULL)
++    {
++      fprintf(stderr, "Invalid argument for -iremap\n");
++      exit(1);
++    }
++
++  len = arg_dst - arg;
++  ++arg_dst;
++
++  remap_src = (char **) xrealloc(remap_src, sizeof(char *) * (remap_pairs + 1));
++  remap_dst = (char **) xrealloc(remap_dst, sizeof(char *) * (remap_pairs + 1));
++
++  remap_src[remap_pairs] = (char *) xmalloc(len + 1);
++  memcpy(remap_src[remap_pairs], arg, len);
++  remap_src[remap_pairs][len] = '\0';
++  remap_dst[remap_pairs] = xstrdup(arg_dst);
++  ++remap_pairs;
++}
++
++static const char *
++cpp_remap_file (const char *arg, char **tmp_name)
++{
++  char *result;
++  size_t i, len;
++
++  for (i = 0; i < remap_pairs; ++i)
++    {
++      len = strlen (remap_src[i]);
++      if (strncmp (remap_src[i], arg, len))
++	continue;
++      if (arg[len] == '\0')
++	return xstrdup (remap_dst[i]);
++      if (arg[len] != '/')
++	continue;
++      arg += len;
++      len = strlen (remap_dst[i]);
++      result = (char *) xmalloc (len + strlen (arg) + 1);
++      memcpy(result, remap_dst[i], len);
++      strcpy(result + len, arg);
++      *tmp_name = result;
++
++      return result;
++    }
++
++   return arg;
++}
++
+ /* Helper function for builtin_macro.  Returns the text generated by
+    a builtin macro. */
+ const uchar *
+@@ -286,6 +344,7 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+       {
+ 	unsigned int len;
+ 	const char *name;
++	char *tmp_name = NULL;
+ 	uchar *buf;
+ 	
+ 	if (node->value.builtin == BT_FILE)
+@@ -297,6 +356,7 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+ 	    if (!name)
+ 	      abort ();
+ 	  }
++	name = cpp_remap_file (name, &tmp_name);
+ 	len = strlen (name);
+ 	buf = _cpp_unaligned_alloc (pfile, len * 2 + 3);
+ 	result = buf;
+@@ -304,6 +364,7 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+ 	buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
+ 	*buf++ = '"';
+ 	*buf = '\0';
++	free (tmp_name);
+       }
+       break;
+ 
diff --git a/toolchain/gcc/patches/5.4.0/960-go_libm.patch b/toolchain/gcc/patches/5.4.0/960-go_libm.patch
new file mode 100644
index 0000000000..d16b0200c0
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/960-go_libm.patch
@@ -0,0 +1,11 @@
+--- a/gcc/go/Make-lang.in
++++ b/gcc/go/Make-lang.in
+@@ -74,7 +74,7 @@ go_OBJS = $(GO_OBJS) go/gospec.o
+ 
+ go1$(exeext): $(GO_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+ 	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+-	      $(GO_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
++	      $(GO_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS) -lm
+ 
+ # Documentation.
+ 
diff --git a/toolchain/gcc/patches/5.4.0/970-warn_bug.patch b/toolchain/gcc/patches/5.4.0/970-warn_bug.patch
new file mode 100644
index 0000000000..2c5cf9be20
--- /dev/null
+++ b/toolchain/gcc/patches/5.4.0/970-warn_bug.patch
@@ -0,0 +1,11 @@
+--- a/libgo/runtime/mprof.goc
++++ b/libgo/runtime/mprof.goc
+@@ -403,7 +403,7 @@ func ThreadCreateProfile(p Slice) (n int
+ 
+ func Stack(b Slice, all bool) (n int) {
+ 	byte *pc, *sp;
+-	bool enablegc;
++	bool enablegc = false; /* workaround GCC bug #36550 */
+ 	
+ 	sp = runtime_getcallersp(&b);
+ 	pc = (byte*)(uintptr)runtime_getcallerpc(&b);
diff --git a/toolchain/gcc/patches/6.2.0/001-revert_register_mode_search.patch b/toolchain/gcc/patches/6.2.0/001-revert_register_mode_search.patch
new file mode 100644
index 0000000000..bd6fbdb4a9
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/001-revert_register_mode_search.patch
@@ -0,0 +1,65 @@
+Revert of:
+
+commit 275035b56823b26d5fb7e90fad945b998648edf2
+Author: bergner <bergner@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date:   Thu Sep 5 14:09:07 2013 +0000
+
+        PR target/58139
+        * reginfo.c (choose_hard_reg_mode): Scan through all mode classes
+        looking for widest mode.
+
+
+    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202286 138bc75d-0d04-0410-961f-82ee72b054a4
+
+
+--- a/gcc/reginfo.c
++++ b/gcc/reginfo.c
+@@ -625,35 +625,40 @@ choose_hard_reg_mode (unsigned int regno
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
+   if (found_mode != VOIDmode)
diff --git a/toolchain/gcc/patches/6.2.0/002-case_insensitive.patch b/toolchain/gcc/patches/6.2.0/002-case_insensitive.patch
new file mode 100644
index 0000000000..b3d2dbe291
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/002-case_insensitive.patch
@@ -0,0 +1,14 @@
+--- a/include/filenames.h
++++ b/include/filenames.h
+@@ -43,11 +43,6 @@ extern "C" {
+ #  define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c)
+ #  define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f)
+ #else /* not DOSish */
+-#  if defined(__APPLE__)
+-#    ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+-#      define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1
+-#    endif
+-#  endif /* __APPLE__ */
+ #  define HAS_DRIVE_SPEC(f) (0)
+ #  define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c)
+ #  define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f)
diff --git a/toolchain/gcc/patches/6.2.0/010-documentation.patch b/toolchain/gcc/patches/6.2.0/010-documentation.patch
new file mode 100644
index 0000000000..2adb28c83d
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/010-documentation.patch
@@ -0,0 +1,23 @@
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -3021,18 +3021,10 @@ doc/gcc.info: $(TEXI_GCC_FILES)
+ doc/gccint.info: $(TEXI_GCCINT_FILES)
+ doc/cppinternals.info: $(TEXI_CPPINT_FILES)
+ 
+-doc/%.info: %.texi
+-	if [ x$(BUILD_INFO) = xinfo ]; then \
+-		$(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \
+-			-I $(gcc_docdir)/include -o $@ $<; \
+-	fi
++doc/%.info:
+ 
+ # Duplicate entry to handle renaming of gccinstall.info
+-doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES)
+-	if [ x$(BUILD_INFO) = xinfo ]; then \
+-		$(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+-			-I $(gcc_docdir)/include -o $@ $<; \
+-	fi
++doc/gccinstall.info:
+ 
+ doc/cpp.dvi: $(TEXI_CPP_FILES)
+ doc/gcc.dvi: $(TEXI_GCC_FILES)
diff --git a/toolchain/gcc/patches/6.2.0/100-uclibc-conf.patch b/toolchain/gcc/patches/6.2.0/100-uclibc-conf.patch
new file mode 100644
index 0000000000..ff9ad94f62
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/100-uclibc-conf.patch
@@ -0,0 +1,33 @@
+--- a/contrib/regression/objs-gcc.sh
++++ b/contrib/regression/objs-gcc.sh
+@@ -106,6 +106,10 @@ if [ $H_REAL_TARGET = $H_REAL_HOST -a $H
+  then
+   make all-gdb all-dejagnu all-ld || exit 1
+   make install-gdb install-dejagnu install-ld || exit 1
++elif [ $H_REAL_TARGET = $H_REAL_HOST -a $H_REAL_TARGET = i686-pc-linux-uclibc ]
++ then
++  make all-gdb all-dejagnu all-ld || exit 1
++  make install-gdb install-dejagnu install-ld || exit 1
+ elif [ $H_REAL_TARGET = $H_REAL_HOST ] ; then
+   make bootstrap || exit 1
+   make install || exit 1
+--- a/libjava/classpath/ltconfig
++++ b/libjava/classpath/ltconfig
+@@ -603,7 +603,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-
+ 
+ # Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+ case $host_os in
+-linux-gnu*) ;;
++linux-gnu*|linux-uclibc*) ;;
+ linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+ esac
+ 
+@@ -1247,7 +1247,7 @@ linux-gnuoldld* | linux-gnuaout* | linux
+   ;;
+ 
+ # This must be Linux ELF.
+-linux-gnu*)
++linux*)
+   version_type=linux
+   need_lib_prefix=no
+   need_version=no
diff --git a/toolchain/gcc/patches/6.2.0/230-musl_libssp.patch b/toolchain/gcc/patches/6.2.0/230-musl_libssp.patch
new file mode 100644
index 0000000000..8dfd1fc287
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/230-musl_libssp.patch
@@ -0,0 +1,13 @@
+--- a/gcc/gcc.c
++++ b/gcc/gcc.c
+@@ -858,7 +858,9 @@ proper position among the other output f
+ #endif
+ 
+ #ifndef LINK_SSP_SPEC
+-#ifdef TARGET_LIBC_PROVIDES_SSP
++#if DEFAULT_LIBC == LIBC_MUSL
++#define LINK_SSP_SPEC "-lssp_nonshared"
++#elif defined(TARGET_LIBC_PROVIDES_SSP)
+ #define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \
+ 		       "|fstack-protector-strong|fstack-protector-explicit:}"
+ #else
diff --git a/toolchain/gcc/patches/6.2.0/280-musl-disable-ifunc-by-default.patch b/toolchain/gcc/patches/6.2.0/280-musl-disable-ifunc-by-default.patch
new file mode 100644
index 0000000000..af5acf8cc9
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/280-musl-disable-ifunc-by-default.patch
@@ -0,0 +1,38 @@
+From 450fb05e2a7510d37744f044009f8237d902f65c Mon Sep 17 00:00:00 2001
+From: nsz <nsz@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date: Tue, 30 Aug 2016 10:26:22 +0000
+Subject: [PATCH] disable ifunc on *-musl by default
+
+gcc/
+	* config.gcc (*-*-*musl*): Disable gnu-indirect-function.
+
+
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@239859 138bc75d-0d04-0410-961f-82ee72b054a4
+---
+ gcc/ChangeLog  | 4 ++++
+ gcc/config.gcc | 4 ++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/gcc/config.gcc b/gcc/config.gcc
+index 8827dc8..e544d76 100644
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -1465,7 +1465,7 @@ i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-gnu* | i[34567]8
+ 		extra_options="${extra_options} linux-android.opt"
+ 		# Assume modern glibc if not targeting Android nor uclibc.
+ 		case ${target} in
+-		*-*-*android*|*-*-*uclibc*)
++		*-*-*android*|*-*-*uclibc*|*-*-*musl*)
+ 		  ;;
+ 		*)
+ 		  default_gnu_indirect_function=yes
+@@ -1531,7 +1531,7 @@ x86_64-*-linux* | x86_64-*-kfreebsd*-gnu)
+ 		extra_options="${extra_options} linux-android.opt"
+ 		# Assume modern glibc if not targeting Android nor uclibc.
+ 		case ${target} in
+-		*-*-*android*|*-*-*uclibc*)
++		*-*-*android*|*-*-*uclibc*|*-*-*musl*)
+ 		  ;;
+ 		*)
+ 		  default_gnu_indirect_function=yes
diff --git a/toolchain/gcc/patches/6.2.0/300-mips_Os_cpu_rtx_cost_model.patch b/toolchain/gcc/patches/6.2.0/300-mips_Os_cpu_rtx_cost_model.patch
new file mode 100644
index 0000000000..d76bd8cb1d
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/300-mips_Os_cpu_rtx_cost_model.patch
@@ -0,0 +1,11 @@
+--- a/gcc/config/mips/mips.c
++++ b/gcc/config/mips/mips.c
+@@ -17928,7 +17928,7 @@ mips_option_override (void)
+     flag_pcc_struct_return = 0;
+ 
+   /* Decide which rtx_costs structure to use.  */
+-  if (optimize_size)
++  if (0 && optimize_size)
+     mips_cost = &mips_rtx_cost_optimize_size;
+   else
+     mips_cost = &mips_rtx_cost_data[mips_tune];
diff --git a/toolchain/gcc/patches/6.2.0/800-arm_v5te_no_ldrd_strd.patch b/toolchain/gcc/patches/6.2.0/800-arm_v5te_no_ldrd_strd.patch
new file mode 100644
index 0000000000..2e7c23f851
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/800-arm_v5te_no_ldrd_strd.patch
@@ -0,0 +1,11 @@
+--- a/gcc/config/arm/arm.h
++++ b/gcc/config/arm/arm.h
+@@ -166,7 +166,7 @@ extern void (*arm_lang_output_object_att
+ /* Thumb-1 only.  */
+ #define TARGET_THUMB1_ONLY		(TARGET_THUMB1 && !arm_arch_notm)
+ 
+-#define TARGET_LDRD			(arm_arch5e && ARM_DOUBLEWORD_ALIGN \
++#define TARGET_LDRD			(arm_arch6 && ARM_DOUBLEWORD_ALIGN \
+                                          && !TARGET_THUMB1)
+ 
+ #define TARGET_CRC32			(arm_arch_crc)
diff --git a/toolchain/gcc/patches/6.2.0/810-arm-softfloat-libgcc.patch b/toolchain/gcc/patches/6.2.0/810-arm-softfloat-libgcc.patch
new file mode 100644
index 0000000000..1d06f5b2ec
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/810-arm-softfloat-libgcc.patch
@@ -0,0 +1,25 @@
+--- a/libgcc/config/arm/t-linux
++++ b/libgcc/config/arm/t-linux
+@@ -1,6 +1,10 @@
+ LIB1ASMSRC = arm/lib1funcs.S
+ LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx _clzsi2 _clzdi2 \
+-	_ctzsi2 _arm_addsubdf3 _arm_addsubsf3
++	_ctzsi2 _arm_addsubdf3 _arm_addsubsf3 \
++	_arm_negdf2 _arm_muldivdf3 _arm_cmpdf2 _arm_unorddf2 \
++	_arm_fixdfsi _arm_fixunsdfsi _arm_truncdfsf2 \
++	_arm_negsf2 _arm_muldivsf3 _arm_cmpsf2 _arm_unordsf2 \
++	_arm_fixsfsi _arm_fixunssfsi
+ 
+ # Just for these, we omit the frame pointer since it makes such a big
+ # difference.
+--- a/gcc/config/arm/linux-elf.h
++++ b/gcc/config/arm/linux-elf.h
+@@ -60,8 +60,6 @@
+    %{shared:-lc} \
+    %{!shared:%{profile:-lc_p}%{!profile:-lc}}"
+ 
+-#define LIBGCC_SPEC "%{mfloat-abi=soft*:-lfloat} -lgcc"
+-
+ #define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
+ 
+ #define LINUX_TARGET_LINK_SPEC  "%{h*} \
diff --git a/toolchain/gcc/patches/6.2.0/820-libgcc_pic.patch b/toolchain/gcc/patches/6.2.0/820-libgcc_pic.patch
new file mode 100644
index 0000000000..f925d96f66
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/820-libgcc_pic.patch
@@ -0,0 +1,36 @@
+--- a/libgcc/Makefile.in
++++ b/libgcc/Makefile.in
+@@ -888,11 +888,12 @@ $(libgcov-driver-objects): %$(objext): $
+ 
+ # Static libraries.
+ libgcc.a: $(libgcc-objects)
++libgcc_pic.a: $(libgcc-s-objects)
+ libgcov.a: $(libgcov-objects)
+ libunwind.a: $(libunwind-objects)
+ libgcc_eh.a: $(libgcc-eh-objects)
+ 
+-libgcc.a libgcov.a libunwind.a libgcc_eh.a:
++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a:
+ 	-rm -f $@
+ 
+ 	objects="$(objects)";					\
+@@ -913,7 +914,7 @@ all: libunwind.a
+ endif
+ 
+ ifeq ($(enable_shared),yes)
+-all: libgcc_eh.a libgcc_s$(SHLIB_EXT)
++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT)
+ ifneq ($(LIBUNWIND),)
+ all: libunwind$(SHLIB_EXT)
+ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_EXT)
+@@ -1115,6 +1116,10 @@ install-shared:
+ 	chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a
+ 	$(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a
+ 
++	$(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/
++	chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a
++	$(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a
++
+ 	$(subst @multilib_dir@,$(MULTIDIR),$(subst \
+ 		@shlib_base_name@,libgcc_s,$(subst \
+ 		@shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL))))
diff --git a/toolchain/gcc/patches/6.2.0/830-arm_unbreak_armv4t.patch b/toolchain/gcc/patches/6.2.0/830-arm_unbreak_armv4t.patch
new file mode 100644
index 0000000000..37f8f2a54d
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/830-arm_unbreak_armv4t.patch
@@ -0,0 +1,13 @@
+http://sourceware.org/ml/crossgcc/2008-05/msg00009.html
+
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -45,7 +45,7 @@
+    The ARM10TDMI core is the default for armv5t, so set
+    SUBTARGET_CPU_DEFAULT to achieve this.  */
+ #undef  SUBTARGET_CPU_DEFAULT
+-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi
++#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm9tdmi
+ 
+ /* TARGET_BIG_ENDIAN_DEFAULT is set in
+    config.gcc for big endian configurations.  */
diff --git a/toolchain/gcc/patches/6.2.0/840-armv4_pass_fix-v4bx_to_ld.patch b/toolchain/gcc/patches/6.2.0/840-armv4_pass_fix-v4bx_to_ld.patch
new file mode 100644
index 0000000000..cb1fb98235
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/840-armv4_pass_fix-v4bx_to_ld.patch
@@ -0,0 +1,19 @@
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -94,10 +94,15 @@
+ #define MUSL_DYNAMIC_LINKER \
+   "/lib/ld-musl-arm" MUSL_DYNAMIC_LINKER_E "%{mfloat-abi=hard:hf}.so.1"
+ 
++/* For armv4 we pass --fix-v4bx to linker to support EABI */
++#undef TARGET_FIX_V4BX_SPEC
++#define TARGET_FIX_V4BX_SPEC " %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*"\
++  "|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}"
++
+ /* At this point, bpabi.h will have clobbered LINK_SPEC.  We want to
+    use the GNU/Linux version, not the generic BPABI version.  */
+ #undef  LINK_SPEC
+-#define LINK_SPEC EABI_LINK_SPEC					\
++#define LINK_SPEC EABI_LINK_SPEC TARGET_FIX_V4BX_SPEC			\
+   LINUX_OR_ANDROID_LD (LINUX_TARGET_LINK_SPEC,				\
+ 		       LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC)
+ 
diff --git a/toolchain/gcc/patches/6.2.0/850-use_shared_libgcc.patch b/toolchain/gcc/patches/6.2.0/850-use_shared_libgcc.patch
new file mode 100644
index 0000000000..cd20244c69
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/850-use_shared_libgcc.patch
@@ -0,0 +1,47 @@
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -132,10 +132,6 @@
+   "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} "	\
+   LINUX_OR_ANDROID_LD (GNU_USER_TARGET_ENDFILE_SPEC, ANDROID_ENDFILE_SPEC)
+ 
+-/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we
+-   do not use -lfloat.  */
+-#undef LIBGCC_SPEC
+-
+ /* Clear the instruction cache from `beg' to `end'.  This is
+    implemented in lib1funcs.S, so ensure an error if this definition
+    is used.  */
+--- a/gcc/config/linux.h
++++ b/gcc/config/linux.h
+@@ -53,6 +53,10 @@ see the files COPYING3 and COPYING.RUNTI
+ 	builtin_assert ("system=posix");			\
+     } while (0)
+ 
++#ifndef LIBGCC_SPEC
++#define LIBGCC_SPEC "%{static|static-libgcc:-lgcc}%{!static:%{!static-libgcc:-lgcc_s}}"
++#endif
++
+ /* Determine which dynamic linker to use depending on whether GLIBC or
+    uClibc or Bionic or musl is the default C library and whether
+    -muclibc or -mglibc or -mbionic or -mmusl has been passed to change
+--- a/libgcc/mkmap-symver.awk
++++ b/libgcc/mkmap-symver.awk
+@@ -132,5 +132,5 @@ function output(lib) {
+   else if (inherit[lib])
+     printf("} %s;\n", inherit[lib]);
+   else
+-    printf ("\n  local:\n\t*;\n};\n");
++    printf ("\n\t*;\n};\n");
+ }
+--- a/gcc/config/rs6000/linux.h
++++ b/gcc/config/rs6000/linux.h
+@@ -60,6 +60,9 @@
+ #undef	CPP_OS_DEFAULT_SPEC
+ #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)"
+ 
++#undef LIBGCC_SPEC
++#define LIBGCC_SPEC "%{!static:%{!static-libgcc:-lgcc_s}} -lgcc"
++
+ #undef  LINK_SHLIB_SPEC
+ #define LINK_SHLIB_SPEC "%{shared:-shared} %{!shared: %{static:-static}}"
+ 
diff --git a/toolchain/gcc/patches/6.2.0/851-libgcc_no_compat.patch b/toolchain/gcc/patches/6.2.0/851-libgcc_no_compat.patch
new file mode 100644
index 0000000000..80c3476841
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/851-libgcc_no_compat.patch
@@ -0,0 +1,12 @@
+--- a/libgcc/config/t-libunwind
++++ b/libgcc/config/t-libunwind
+@@ -2,8 +2,7 @@
+ 
+ HOST_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER
+ 
+-LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \
+-  $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c
++LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
+ LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
+ 
+ # Override the default value from t-slibgcc-elf-ver and mention -lunwind
diff --git a/toolchain/gcc/patches/6.2.0/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches/6.2.0/870-ppc_no_crtsavres.patch
new file mode 100644
index 0000000000..c1eaf975c3
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/870-ppc_no_crtsavres.patch
@@ -0,0 +1,11 @@
+--- a/gcc/config/rs6000/rs6000.c
++++ b/gcc/config/rs6000/rs6000.c
+@@ -24141,7 +24141,7 @@ rs6000_savres_strategy (rs6000_stack_t *
+   /* Define cutoff for using out-of-line functions to save registers.  */
+   if (DEFAULT_ABI == ABI_V4 || TARGET_ELF)
+     {
+-      if (!optimize_size)
++      if (1)
+ 	{
+ 	  strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
+ 	  strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
diff --git a/toolchain/gcc/patches/6.2.0/880-no_java_section.patch b/toolchain/gcc/patches/6.2.0/880-no_java_section.patch
new file mode 100644
index 0000000000..0fa9e627c2
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/880-no_java_section.patch
@@ -0,0 +1,11 @@
+--- a/gcc/defaults.h
++++ b/gcc/defaults.h
+@@ -395,7 +395,7 @@ see the files COPYING3 and COPYING.RUNTI
+ /* If we have named section and we support weak symbols, then use the
+    .jcr section for recording java classes which need to be registered
+    at program start-up time.  */
+-#if defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
++#if 0 && defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
+ #ifndef JCR_SECTION_NAME
+ #define JCR_SECTION_NAME ".jcr"
+ #endif
diff --git a/toolchain/gcc/patches/6.2.0/900-bad-mips16-crt.patch b/toolchain/gcc/patches/6.2.0/900-bad-mips16-crt.patch
new file mode 100644
index 0000000000..dd6e9dc889
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/900-bad-mips16-crt.patch
@@ -0,0 +1,9 @@
+--- a/libgcc/config/mips/t-mips16
++++ b/libgcc/config/mips/t-mips16
+@@ -43,3 +43,6 @@ SYNC_CFLAGS = -mno-mips16
+ 
+ # Version these symbols if building libgcc.so.
+ SHLIB_MAPFILES += $(srcdir)/config/mips/libgcc-mips16.ver
++
++CRTSTUFF_T_CFLAGS += -mno-mips16
++CRTSTUFF_T_CFLAGS_S += -mno-mips16
diff --git a/toolchain/gcc/patches/6.2.0/910-mbsd_multi.patch b/toolchain/gcc/patches/6.2.0/910-mbsd_multi.patch
new file mode 100644
index 0000000000..62203dfcf6
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/910-mbsd_multi.patch
@@ -0,0 +1,222 @@
+
+	This patch brings over a few features from MirBSD:
+	* -fhonour-copts
+	  If this option is not given, it's warned (depending
+	  on environment variables). This is to catch errors
+	  of misbuilt packages which override CFLAGS themselves.
+	* -Werror-maybe-reset
+	  Has the effect of -Wno-error if GCC_NO_WERROR is
+	  set and not '0', a no-operation otherwise. This is
+	  to be able to use -Werror in "make" but prevent
+	  GNU autoconf generated configure scripts from
+	  freaking out.
+
+	This patch was authored by Thorsten Glaser <tg at mirbsd.de>
+	with copyright assignment to the FSF in effect.
+
+--- a/gcc/c-family/c-opts.c
++++ b/gcc/c-family/c-opts.c
+@@ -107,6 +107,9 @@ static int class_dump_flags;
+ /* Whether any standard preincluded header has been preincluded.  */
+ static bool done_preinclude;
+ 
++/* Check if a port honours COPTS.  */
++static int honour_copts = 0;
++
+ static void handle_OPT_d (const char *);
+ static void set_std_cxx98 (int);
+ static void set_std_cxx11 (int);
+@@ -442,6 +445,12 @@ c_common_handle_option (size_t scode, co
+       flag_no_builtin = !value;
+       break;
+ 
++    case OPT_fhonour_copts:
++      if (c_language == clk_c) {
++        honour_copts++;
++      }
++      break;
++
+     case OPT_fconstant_string_class_:
+       constant_string_class_name = arg;
+       break;
+@@ -1041,6 +1050,47 @@ c_common_init (void)
+       return false;
+     }
+ 
++  if (c_language == clk_c) {
++    char *ev = getenv ("GCC_HONOUR_COPTS");
++    int evv;
++    if (ev == NULL)
++      evv = -1;
++    else if ((*ev == '0') || (*ev == '\0'))
++      evv = 0;
++    else if (*ev == '1')
++      evv = 1;
++    else if (*ev == '2')
++      evv = 2;
++    else if (*ev == 's')
++      evv = -1;
++    else {
++      warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1");
++      evv = 1; /* maybe depend this on something like MIRBSD_NATIVE?  */
++    }
++    if (evv == 1) {
++      if (honour_copts == 0) {
++        error ("someone does not honour COPTS at all in lenient mode");
++        return false;
++      } else if (honour_copts != 1) {
++        warning (0, "someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++      }
++    } else if (evv == 2) {
++      if (honour_copts == 0) {
++        error ("someone does not honour COPTS at all in strict mode");
++        return false;
++      } else if (honour_copts != 1) {
++        error ("someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++        return false;
++      }
++    } else if (evv == 0) {
++      if (honour_copts != 1)
++        inform (0, "someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++    }
++  }
++
+   return true;
+ }
+ 
+--- a/gcc/c-family/c.opt
++++ b/gcc/c-family/c.opt
+@@ -438,6 +438,10 @@ Wfloat-conversion
+ C ObjC C++ ObjC++ Var(warn_float_conversion) Warning LangEnabledBy(C ObjC C++ ObjC++,Wconversion)
+ Warn for implicit type conversions that cause loss of floating point precision.
+ 
++Werror-maybe-reset
++C ObjC C++ ObjC++
++; Documented in common.opt
++
+ Wfloat-equal
+ C ObjC C++ ObjC++ Var(warn_float_equal) Warning
+ Warn if testing floating point numbers for equality.
+@@ -1252,6 +1256,9 @@ C++ ObjC++ Optimization Alias(fexception
+ fhonor-std
+ C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+ 
++fhonour-copts
++C ObjC C++ ObjC++ RejectNegative
++
+ fhosted
+ C ObjC
+ Assume normal C execution environment.
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -581,6 +581,10 @@ Werror=
+ Common Joined
+ Treat specified warning as error.
+ 
++Werror-maybe-reset
++Common
++If environment variable GCC_NO_WERROR is set, act as -Wno-error
++
+ Wextra
+ Common Var(extra_warnings) Warning
+ Print extra (possibly unwanted) warnings.
+@@ -1432,6 +1436,9 @@ fguess-branch-probability
+ Common Report Var(flag_guess_branch_prob) Optimization
+ Enable guessing of branch probabilities.
+ 
++fhonour-copts
++Common RejectNegative
++
+ ; Nonzero means ignore `#ident' directives.  0 means handle them.
+ ; Generate position-independent code for executables if possible
+ ; On SVR4 targets, it also controls whether or not to emit a
+--- a/gcc/opts.c
++++ b/gcc/opts.c
+@@ -1783,6 +1783,17 @@ common_handle_option (struct gcc_options
+ 			       opts, opts_set, loc, dc);
+       break;
+ 
++    case OPT_Werror_maybe_reset:
++      {
++        char *ev = getenv ("GCC_NO_WERROR");
++        if ((ev != NULL) && (*ev != '0'))
++          warnings_are_errors = 0;
++      }
++      break;
++
++    case OPT_fhonour_copts:
++      break;
++
+     case OPT_Wlarger_than_:
+       opts->x_larger_than_size = value;
+       opts->x_warn_larger_than = value != -1;
+--- a/gcc/doc/cppopts.texi
++++ b/gcc/doc/cppopts.texi
+@@ -163,6 +163,11 @@ in older programs.  This warning is on b
+ Make all warnings into hard errors.  Source code which triggers warnings
+ will be rejected.
+ 
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
+ @item -Wsystem-headers
+ @opindex Wsystem-headers
+ Issue warnings for code in system headers.  These are normally unhelpful
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -263,7 +263,7 @@ Objective-C and Objective-C++ Dialects}.
+ -Wno-discarded-qualifiers -Wno-discarded-array-qualifiers @gol
+ -Wno-div-by-zero -Wdouble-promotion -Wduplicated-cond @gol
+ -Wempty-body  -Wenum-compare -Wno-endif-labels @gol
+--Werror  -Werror=* -Wfatal-errors -Wfloat-equal  -Wformat  -Wformat=2 @gol
++-Werror  -Werror=* -Werror-maybe-reset -Wfatal-errors -Wfloat-equal  -Wformat  -Wformat=2 @gol
+ -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol
+ -Wformat-security  -Wformat-signedness  -Wformat-y2k -Wframe-address @gol
+ -Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol
+@@ -5737,6 +5737,22 @@ This option is only supported for C and
+ @option{-Wall} and by @option{-Wpedantic}, which can be disabled with
+ @option{-Wno-pointer-sign}.
+ 
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
++ at item -fhonour-copts
++ at opindex fhonour-copts
++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not
++given at least once, and warn if it is given more than once.
++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not
++given exactly once.
++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option
++is not given exactly once.
++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}.
++This flag and environment variable only affect the C language.
++
+ @item -Wstack-protector
+ @opindex Wstack-protector
+ @opindex Wno-stack-protector
+@@ -6605,7 +6621,7 @@ so, the first branch is redirected to ei
+ second branch or a point immediately following it, depending on whether
+ the condition is known to be true or false.
+ 
+-Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
++Enabled at levels @option{-O3}.
+ 
+ @item -fsplit-wide-types
+ @opindex fsplit-wide-types
+--- a/gcc/java/jvspec.c
++++ b/gcc/java/jvspec.c
+@@ -629,6 +629,7 @@ lang_specific_pre_link (void)
+      class name.  Append dummy `.c' that can be stripped by set_input so %b
+      is correct.  */ 
+   set_input (concat (main_class_name, "main.c", NULL));
++  putenv ("GCC_HONOUR_COPTS=s"); /* XXX hack!  */
+   err = do_spec (jvgenmain_spec);
+   if (err == 0)
+     {
diff --git a/toolchain/gcc/patches/6.2.0/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches/6.2.0/920-specs_nonfatal_getenv.patch
new file mode 100644
index 0000000000..dc0acb95a8
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/920-specs_nonfatal_getenv.patch
@@ -0,0 +1,15 @@
+--- a/gcc/gcc.c
++++ b/gcc/gcc.c
+@@ -9198,8 +9198,10 @@ getenv_spec_function (int argc, const ch
+     value = varname;
+ 
+   if (!value)
+-    fatal_error (input_location,
+-		 "environment variable %qs not defined", varname);
++    {
++      warning (input_location, "environment variable %qs not defined", varname);
++      value = "";
++    }
+ 
+   /* We have to escape every character of the environment variable so
+      they are not interpreted as active spec characters.  A
diff --git a/toolchain/gcc/patches/6.2.0/930-fix-mips-noexecstack.patch b/toolchain/gcc/patches/6.2.0/930-fix-mips-noexecstack.patch
new file mode 100644
index 0000000000..2a99840b63
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/930-fix-mips-noexecstack.patch
@@ -0,0 +1,111 @@
+From da45b3fde60095756f5f6030f6012c23a3d34429 Mon Sep 17 00:00:00 2001
+From: Andrew McDonnell <bugs@andrewmcdonnell.net>
+Date: Fri, 3 Oct 2014 19:09:00 +0930
+Subject: Add .note.GNU-stack section
+
+See http://lists.busybox.net/pipermail/uclibc/2014-October/048671.html
+Below copied from https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02430.html
+
+Re: [Patch, MIPS] Add .note.GNU-stack section
+
+    From: Steve Ellcey <sellcey at mips dot com>
+
+On Wed, 2014-09-10 at 10:15 -0700, Eric Christopher wrote:
+>
+>
+> On Wed, Sep 10, 2014 at 9:27 AM, <pinskia@gmail.com> wrote:
+
+>         This works except you did not update the assembly files in
+>         libgcc or glibc. We (Cavium) have the same patch in our tree
+>         for a few released versions.
+
+> Mind just checking yours in then Andrew?
+
+> Thanks!
+> -eric
+
+I talked to Andrew about what files he changed in GCC and created and
+tested this new patch.  Andrew also mentioned changing some assembly
+files in glibc but I don't see any use of '.section .note.GNU-stack' in
+any assembly files in glibc (for any platform) so I wasn't planning on
+creating a glibc to add them to mips glibc assembly language files.
+
+OK to check in this patch?
+
+Steve Ellcey
+sellcey@mips.com
+
+
+
+2014-09-26  Steve Ellcey  <sellcey@mips.com>
+---
+ gcc/config/mips/mips.c          | 3 +++
+ libgcc/config/mips/crti.S       | 4 ++++
+ libgcc/config/mips/crtn.S       | 3 +++
+ libgcc/config/mips/mips16.S     | 4 ++++
+ libgcc/config/mips/vr4120-div.S | 4 ++++
+ 5 files changed, 18 insertions(+)
+
+--- a/gcc/config/mips/mips.c
++++ b/gcc/config/mips/mips.c
+@@ -20228,6 +20228,9 @@ mips_promote_function_mode (const_tree t
+ #undef TARGET_HARD_REGNO_SCRATCH_OK
+ #define TARGET_HARD_REGNO_SCRATCH_OK mips_hard_regno_scratch_ok
+ 
++#undef TARGET_ASM_FILE_END
++#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
++
+ struct gcc_target targetm = TARGET_INITIALIZER;
+ 
+ #include "gt-mips.h"
+--- a/libgcc/config/mips/crti.S
++++ b/libgcc/config/mips/crti.S
+@@ -21,6 +21,10 @@ a copy of the GCC Runtime Library Except
+ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ <http://www.gnu.org/licenses/>.  */
+ 
++
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++
+ /* 4 slots for argument spill area.  1 for cpreturn, 1 for stack.
+    Return spill offset of 40 and 20.  Aligned to 16 bytes for n32.  */
+ 
+--- a/libgcc/config/mips/crtn.S
++++ b/libgcc/config/mips/crtn.S
+@@ -21,6 +21,9 @@ a copy of the GCC Runtime Library Except
+ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ <http://www.gnu.org/licenses/>.  */
+ 
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++
+ /* 4 slots for argument spill area.  1 for cpreturn, 1 for stack.
+    Return spill offset of 40 and 20.  Aligned to 16 bytes for n32.  */
+ 
+--- a/libgcc/config/mips/mips16.S
++++ b/libgcc/config/mips/mips16.S
+@@ -48,6 +48,10 @@ see the files COPYING3 and COPYING.RUNTI
+    values using the soft-float calling convention, but do the actual
+    operation using the hard floating point instructions.  */
+ 
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++	.previous
++
+ #if defined _MIPS_SIM && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
+ 
+ /* This file contains 32-bit assembly code.  */
+--- a/libgcc/config/mips/vr4120-div.S
++++ b/libgcc/config/mips/vr4120-div.S
+@@ -26,6 +26,10 @@ see the files COPYING3 and COPYING.RUNTI
+    -mfix-vr4120.  div and ddiv do not give the correct result when one
+    of the operands is negative.  */
+ 
++/* An executable stack is *not* required for these functions.  */
++	.section .note.GNU-stack,"",%progbits
++	.previous
++
+ 	.set	nomips16
+ 
+ #define DIV								\
diff --git a/toolchain/gcc/patches/6.2.0/940-no-clobber-stamp-bits.patch b/toolchain/gcc/patches/6.2.0/940-no-clobber-stamp-bits.patch
new file mode 100644
index 0000000000..65f59fcfa7
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/940-no-clobber-stamp-bits.patch
@@ -0,0 +1,11 @@
+--- a/libstdc++-v3/include/Makefile.in
++++ b/libstdc++-v3/include/Makefile.in
+@@ -1458,7 +1458,7 @@ stamp-bits: ${bits_headers}
+ 	@$(STAMP) stamp-bits
+ 
+ stamp-bits-sup: stamp-bits ${bits_sup_headers}
+-	@-cd ${bits_builddir} && $(LN_S) $? . 2>/dev/null
++	@-cd ${bits_builddir} && $(LN_S) $(filter-out stamp-bits,$?) . 2>/dev/null
+ 	@$(STAMP) stamp-bits-sup
+ 
+ stamp-c_base: ${c_base_headers}
diff --git a/toolchain/gcc/patches/6.2.0/950-cpp_file_path_translation.patch b/toolchain/gcc/patches/6.2.0/950-cpp_file_path_translation.patch
new file mode 100644
index 0000000000..d467eb7c9a
--- /dev/null
+++ b/toolchain/gcc/patches/6.2.0/950-cpp_file_path_translation.patch
@@ -0,0 +1,182 @@
+Forward ported from attachment to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47047
+
+--- a/gcc/c-family/c-opts.c
++++ b/gcc/c-family/c-opts.c
+@@ -574,6 +574,10 @@ c_common_handle_option (size_t scode, co
+       add_path (xstrdup (arg), SYSTEM, 0, true);
+       break;
+ 
++    case OPT_iremap:
++      add_cpp_remap_path (arg);
++      break;
++
+     case OPT_iwithprefix:
+       add_prefixed_path (arg, SYSTEM);
+       break;
+--- a/gcc/c-family/c.opt
++++ b/gcc/c-family/c.opt
+@@ -1632,6 +1632,10 @@ iquote
+ C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
+ -iquote <dir>	Add <dir> to the end of the quote include path.
+ 
++iremap
++C ObjC C++ ObjC++ Joined Separate
++-iremap <src:dst>  Convert <src> to <dst> if it occurs as prefix in __FILE__.
++
+ iwithprefix
+ C ObjC C++ ObjC++ Joined Separate
+ -iwithprefix <dir>	Add <dir> to the end of the system include path.
+--- a/gcc/doc/cpp.texi
++++ b/gcc/doc/cpp.texi
+@@ -4444,6 +4444,7 @@ without notice.
+ @c man begin SYNOPSIS
+ cpp [@option{-D}@var{macro}[=@var{defn}]@dots{}] [@option{-U}@var{macro}]
+     [@option{-I}@var{dir}@dots{}] [@option{-iquote}@var{dir}@dots{}]
++    [@option{-iremap}@var{src}:@var{dst}]
+     [@option{-W}@var{warn}@dots{}]
+     [@option{-M}|@option{-MM}] [@option{-MG}] [@option{-MF} @var{filename}]
+     [@option{-MP}] [@option{-MQ} @var{target}@dots{}]
+--- a/gcc/doc/cppopts.texi
++++ b/gcc/doc/cppopts.texi
+@@ -532,6 +532,12 @@ Search @var{dir} only for header files r
+ If @var{dir} begins with @code{=}, then the @code{=} will be replaced
+ by the sysroot prefix; see @option{--sysroot} and @option{-isysroot}.
+ 
++@item -iremap @var{src}:@var{dst}
++@opindex iremap
++Replace the prefix @var{src} in __FILE__ with @var{dst} at expansion time.
++This option can be specified more than once.  Processing stops at the first
++match.
++
+ @item -fdirectives-only
+ @opindex fdirectives-only
+ When preprocessing, handle directives, but do not expand macros.
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -476,8 +476,8 @@ Objective-C and Objective-C++ Dialects}.
+ @item Directory Options
+ @xref{Directory Options,,Options for Directory Search}.
+ @gccoptlist{-B@var{prefix} -I@var{dir} -iplugindir=@var{dir} @gol
+--iquote@var{dir} -L@var{dir} -no-canonical-prefixes -I- @gol
+---sysroot=@var{dir} --no-sysroot-suffix}
++-iquote@var{dir} -iremap@var{src}:@var{dst} -L@var{dir} -no-canonical-prefixes @gol
++-I- --sysroot=@var{dir} --no-sysroot-suffix}
+ 
+ @item Code Generation Options
+ @xref{Code Gen Options,,Options for Code Generation Conventions}.
+@@ -10861,6 +10861,12 @@ be searched for header files only for th
+ "@var{file}"}; they are not searched for @code{#include <@var{file}>},
+ otherwise just like @option{-I}.
+ 
++@item -iremap @var{src}:@var{dst}
++@opindex iremap
++Replace the prefix @var{src} in __FILE__ with @var{dst} at expansion time.
++This option can be specified more than once.  Processing stops at the first
++match.
++
+ @item -L@var{dir}
+ @opindex L
+ Add directory @var{dir} to the list of directories to be searched
+--- a/libcpp/include/cpplib.h
++++ b/libcpp/include/cpplib.h
+@@ -760,6 +760,9 @@ extern void cpp_set_lang (cpp_reader *,
+ /* Set the include paths.  */
+ extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int);
+ 
++/* Provide src:dst pair for __FILE__ remapping.  */
++extern void add_cpp_remap_path (const char *);
++
+ /* Call these to get pointers to the options, callback, and deps
+    structures for a given reader.  These pointers are good until you
+    call cpp_finish on that reader.  You can either edit the callbacks
+--- a/libcpp/macro.c
++++ b/libcpp/macro.c
+@@ -227,6 +227,64 @@ static const char * const monthnames[] =
+   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ 
++static size_t remap_pairs;
++static char **remap_src;
++static char **remap_dst;
++
++void
++add_cpp_remap_path (const char *arg)
++{
++  const char *arg_dst;
++  size_t len;
++
++  arg_dst = strchr(arg, ':');
++  if (arg_dst == NULL)
++    {
++      fprintf(stderr, "Invalid argument for -iremap\n");
++      exit(1);
++    }
++
++  len = arg_dst - arg;
++  ++arg_dst;
++
++  remap_src = (char **) xrealloc(remap_src, sizeof(char *) * (remap_pairs + 1));
++  remap_dst = (char **) xrealloc(remap_dst, sizeof(char *) * (remap_pairs + 1));
++
++  remap_src[remap_pairs] = (char *) xmalloc(len + 1);
++  memcpy(remap_src[remap_pairs], arg, len);
++  remap_src[remap_pairs][len] = '\0';
++  remap_dst[remap_pairs] = xstrdup(arg_dst);
++  ++remap_pairs;
++}
++
++static const char *
++cpp_remap_file (const char *arg, char **tmp_name)
++{
++  char *result;
++  size_t i, len;
++
++  for (i = 0; i < remap_pairs; ++i)
++    {
++      len = strlen (remap_src[i]);
++      if (strncmp (remap_src[i], arg, len))
++	continue;
++      if (arg[len] == '\0')
++	return xstrdup (remap_dst[i]);
++      if (arg[len] != '/')
++	continue;
++      arg += len;
++      len = strlen (remap_dst[i]);
++      result = (char *) xmalloc (len + strlen (arg) + 1);
++      memcpy(result, remap_dst[i], len);
++      strcpy(result + len, arg);
++      *tmp_name = result;
++
++      return result;
++    }
++
++   return arg;
++}
++
+ /* Helper function for builtin_macro.  Returns the text generated by
+    a builtin macro. */
+ const uchar *
+@@ -290,6 +348,7 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+       {
+ 	unsigned int len;
+ 	const char *name;
++	char *tmp_name = NULL;
+ 	uchar *buf;
+ 	
+ 	if (node->value.builtin == BT_FILE)
+@@ -301,6 +360,7 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+ 	    if (!name)
+ 	      abort ();
+ 	  }
++	name = cpp_remap_file (name, &tmp_name);
+ 	len = strlen (name);
+ 	buf = _cpp_unaligned_alloc (pfile, len * 2 + 3);
+ 	result = buf;
+@@ -308,6 +368,7 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+ 	buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
+ 	*buf++ = '"';
+ 	*buf = '\0';
++	free (tmp_name);
+       }
+       break;
+ 
diff --git a/toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch b/toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch
new file mode 100644
index 0000000000..162d651394
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/001-revert_register_mode_search.patch
@@ -0,0 +1,65 @@
+Revert of:
+
+commit 275035b56823b26d5fb7e90fad945b998648edf2
+Author: bergner <bergner@138bc75d-0d04-0410-961f-82ee72b054a4>
+Date:   Thu Sep 5 14:09:07 2013 +0000
+
+        PR target/58139
+        * reginfo.c (choose_hard_reg_mode): Scan through all mode classes
+        looking for widest mode.
+
+
+    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202286 138bc75d-0d04-0410-961f-82ee72b054a4
+
+
+--- a/gcc/reginfo.c
++++ b/gcc/reginfo.c
+@@ -620,35 +620,40 @@ choose_hard_reg_mode (unsigned int regno
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
++  if (found_mode != VOIDmode)
++    return found_mode;
++
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
+        mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     if ((unsigned) hard_regno_nregs[regno][mode] == nregs
+ 	&& HARD_REGNO_MODE_OK (regno, mode)
+-	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+-	&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (found_mode))
++	&& (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
+       found_mode = mode;
+ 
+   if (found_mode != VOIDmode)
diff --git a/toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch b/toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch
new file mode 100644
index 0000000000..a740b4ce9e
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/002-weak_data_fix.patch
@@ -0,0 +1,42 @@
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/visibility-21.c
+@@ -0,0 +1,14 @@
++/* PR target/32219 */
++/* { dg-do run } */
++/* { dg-require-visibility "" } */
++/* { dg-options "-fPIC" { target fpic } } */
++
++extern void f() __attribute__((weak,visibility("hidden")));
++extern int puts( char const* );
++int main()
++{
++	if (f)
++		f();
++	return 0;
++}
++
+--- a/gcc/varasm.c
++++ b/gcc/varasm.c
+@@ -6677,6 +6677,10 @@ default_binds_local_p_1 (const_tree exp,
+   /* Static variables are always local.  */
+   else if (! TREE_PUBLIC (exp))
+     local_p = true;
++  /* hidden weak can't be overridden by something non-local, all
++     that is possible is that it is not defined at all. */
++  else if (DECL_WEAK (exp))
++    local_p = false;
+   /* A variable is local if the user has said explicitly that it will
+      be.  */
+   else if ((DECL_VISIBILITY_SPECIFIED (exp)
+@@ -6690,11 +6694,6 @@ default_binds_local_p_1 (const_tree exp,
+      local.  */
+   else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+     local_p = true;
+-  /* Default visibility weak data can be overridden by a strong symbol
+-     in another module and so are not local.  */
+-  else if (DECL_WEAK (exp)
+-	   && !resolved_locally)
+-    local_p = false;
+   /* If PIC, then assume that any global name can be overridden by
+      symbols resolved from other modules.  */
+   else if (shlib)
diff --git a/toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch b/toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch
new file mode 100644
index 0000000000..1b9a5b3081
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/003-universal_initializer.patch
@@ -0,0 +1,94 @@
+--- a/gcc/c/c-typeck.c
++++ b/gcc/c/c-typeck.c
+@@ -62,9 +62,9 @@ int in_typeof;
+    if expr.original_code == SIZEOF_EXPR.  */
+ tree c_last_sizeof_arg;
+ 
+-/* Nonzero if we've already printed a "missing braces around initializer"
+-   message within this initializer.  */
+-static int missing_braces_mentioned;
++/* Nonzero if we might need to print a "missing braces around
++   initializer" message within this initializer.  */
++static int found_missing_braces;
+ 
+ static int require_constant_value;
+ static int require_constant_elements;
+@@ -6363,6 +6363,9 @@ static int constructor_nonconst;
+ /* 1 if this constructor is erroneous so far.  */
+ static int constructor_erroneous;
+ 
++/* 1 if this constructor is the universal zero initializer { 0 }.  */
++static int constructor_zeroinit;
++
+ /* Structure for managing pending initializer elements, organized as an
+    AVL tree.  */
+ 
+@@ -6524,7 +6527,7 @@ start_init (tree decl, tree asmspec_tree
+   constructor_stack = 0;
+   constructor_range_stack = 0;
+ 
+-  missing_braces_mentioned = 0;
++  found_missing_braces = 0;
+ 
+   spelling_base = 0;
+   spelling_size = 0;
+@@ -6619,6 +6622,7 @@ really_start_incremental_init (tree type
+   constructor_type = type;
+   constructor_incremental = 1;
+   constructor_designated = 0;
++  constructor_zeroinit = 1;
+   designator_depth = 0;
+   designator_erroneous = 0;
+ 
+@@ -6816,11 +6820,8 @@ push_init_level (int implicit, struct ob
+ 	set_nonincremental_init (braced_init_obstack);
+     }
+ 
+-  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
+-    {
+-      missing_braces_mentioned = 1;
+-      warning_init (OPT_Wmissing_braces, "missing braces around initializer");
+-    }
++  if (implicit == 1)
++    found_missing_braces = 1;
+ 
+   if (TREE_CODE (constructor_type) == RECORD_TYPE
+ 	   || TREE_CODE (constructor_type) == UNION_TYPE)
+@@ -6953,16 +6954,23 @@ pop_init_level (int implicit, struct obs
+ 	}
+     }
+ 
++  if (vec_safe_length (constructor_elements) != 1)
++    constructor_zeroinit = 0;
++
++  /* Warn when some structs are initialized with direct aggregation.  */
++  if (!implicit && found_missing_braces && warn_missing_braces
++      && !constructor_zeroinit)
++    {
++      warning_init (OPT_Wmissing_braces,
++		    "missing braces around initializer");
++    }
++
+   /* Warn when some struct elements are implicitly initialized to zero.  */
+   if (warn_missing_field_initializers
+       && constructor_type
+       && TREE_CODE (constructor_type) == RECORD_TYPE
+       && constructor_unfilled_fields)
+     {
+-	bool constructor_zeroinit =
+-	 (vec_safe_length (constructor_elements) == 1
+-	  && integer_zerop ((*constructor_elements)[0].value));
+-
+ 	/* Do not warn for flexible array members or zero-length arrays.  */
+ 	while (constructor_unfilled_fields
+ 	       && (!DECL_SIZE (constructor_unfilled_fields)
+@@ -8077,6 +8085,9 @@ process_init_element (struct c_expr valu
+   designator_depth = 0;
+   designator_erroneous = 0;
+ 
++  if (!implicit && value.value && !integer_zerop (value.value))
++    constructor_zeroinit = 0;
++
+   /* Handle superfluous braces around string cst as in
+      char x[] = {"foo"}; */
+   if (string_flag
diff --git a/toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch b/toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch
new file mode 100644
index 0000000000..b3d2dbe291
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/004-case_insensitive.patch
@@ -0,0 +1,14 @@
+--- a/include/filenames.h
++++ b/include/filenames.h
+@@ -43,11 +43,6 @@ extern "C" {
+ #  define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c)
+ #  define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f)
+ #else /* not DOSish */
+-#  if defined(__APPLE__)
+-#    ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+-#      define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1
+-#    endif
+-#  endif /* __APPLE__ */
+ #  define HAS_DRIVE_SPEC(f) (0)
+ #  define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c)
+ #  define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f)
diff --git a/toolchain/gcc/patches/arc-2016.03/010-documentation.patch b/toolchain/gcc/patches/arc-2016.03/010-documentation.patch
new file mode 100644
index 0000000000..5548069d1b
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/010-documentation.patch
@@ -0,0 +1,23 @@
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -4327,18 +4327,10 @@ doc/gcc.info: $(TEXI_GCC_FILES)
+ doc/gccint.info: $(TEXI_GCCINT_FILES)
+ doc/cppinternals.info: $(TEXI_CPPINT_FILES)
+ 
+-doc/%.info: %.texi
+-	if [ x$(BUILD_INFO) = xinfo ]; then \
+-		$(MAKEINFO) $(MAKEINFOFLAGS) -I . -I $(gcc_docdir) \
+-			-I $(gcc_docdir)/include -o $@ $<; \
+-	fi
++doc/%.info:
+ 
+ # Duplicate entry to handle renaming of gccinstall.info
+-doc/gccinstall.info: $(TEXI_GCCINSTALL_FILES)
+-	if [ x$(BUILD_INFO) = xinfo ]; then \
+-		$(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+-			-I $(gcc_docdir)/include -o $@ $<; \
+-	fi
++doc/gccinstall.info:
+ 
+ doc/cpp.dvi: $(TEXI_CPP_FILES)
+ doc/gcc.dvi: $(TEXI_GCC_FILES)
diff --git a/toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch b/toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch
new file mode 100644
index 0000000000..b225376865
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/020-no-plt-backport.patch
@@ -0,0 +1,28 @@
+--- a/gcc/calls.c
++++ b/gcc/calls.c
+@@ -176,6 +176,12 @@ prepare_call_address (tree fndecl, rtx f
+ 	       && targetm.small_register_classes_for_mode_p (FUNCTION_MODE))
+ 	      ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
+ 	      : memory_address (FUNCTION_MODE, funexp));
++  else if (flag_pic && !flag_plt && fndecl
++	   && TREE_CODE (fndecl) == FUNCTION_DECL
++	   && !targetm.binds_local_p (fndecl))
++    {
++      funexp = force_reg (Pmode, funexp);
++    }
+   else if (! sibcallp)
+     {
+ #ifndef NO_FUNCTION_CSE
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1617,6 +1617,10 @@ fpie
+ Common Report Var(flag_pie,1) Negative(fPIC)
+ Generate position-independent code for executables if possible (small mode)
+ 
++fplt
++Common Report Var(flag_plt) Init(1)
++Use PLT for PIC calls (-fno-plt: load the address from GOT at call site)
++
+ fplugin=
+ Common Joined RejectNegative Var(common_deferred_options) Defer
+ Specify a plugin to load
diff --git a/toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch b/toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch
new file mode 100644
index 0000000000..ff9ad94f62
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/100-uclibc-conf.patch
@@ -0,0 +1,33 @@
+--- a/contrib/regression/objs-gcc.sh
++++ b/contrib/regression/objs-gcc.sh
+@@ -106,6 +106,10 @@ if [ $H_REAL_TARGET = $H_REAL_HOST -a $H
+  then
+   make all-gdb all-dejagnu all-ld || exit 1
+   make install-gdb install-dejagnu install-ld || exit 1
++elif [ $H_REAL_TARGET = $H_REAL_HOST -a $H_REAL_TARGET = i686-pc-linux-uclibc ]
++ then
++  make all-gdb all-dejagnu all-ld || exit 1
++  make install-gdb install-dejagnu install-ld || exit 1
+ elif [ $H_REAL_TARGET = $H_REAL_HOST ] ; then
+   make bootstrap || exit 1
+   make install || exit 1
+--- a/libjava/classpath/ltconfig
++++ b/libjava/classpath/ltconfig
+@@ -603,7 +603,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-
+ 
+ # Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+ case $host_os in
+-linux-gnu*) ;;
++linux-gnu*|linux-uclibc*) ;;
+ linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+ esac
+ 
+@@ -1247,7 +1247,7 @@ linux-gnuoldld* | linux-gnuaout* | linux
+   ;;
+ 
+ # This must be Linux ELF.
+-linux-gnu*)
++linux*)
+   version_type=linux
+   need_lib_prefix=no
+   need_version=no
diff --git a/toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch b/toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch
new file mode 100644
index 0000000000..56084692a1
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/210-disable_libsanitizer_off_t_check.patch
@@ -0,0 +1,11 @@
+--- a/libsanitizer/interception/interception_type_test.cc
++++ b/libsanitizer/interception/interception_type_test.cc
+@@ -31,7 +31,7 @@ COMPILER_CHECK(sizeof(OFF64_T) == sizeof
+ // rest (they depend on _FILE_OFFSET_BITS setting when building an application).
+ # if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
+   _FILE_OFFSET_BITS != 64
+-COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
++// COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
+ # endif
+ 
+ #endif
diff --git a/toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch b/toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch
new file mode 100644
index 0000000000..612883c98c
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/800-arc-disablelibgmon.patch
@@ -0,0 +1,18 @@
+diff --git a/libgcc/config.host b/libgcc/config.host
+index e768389..aec10c7 100644
+--- a/libgcc/config.host
++++ b/libgcc/config.host
+@@ -320,11 +320,11 @@ alpha*-dec-*vms*)
+ 	;;
+ arc*-*-elf*)
+ 	tmake_file="arc/t-arc-newlib arc/t-arc"
+-	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o libgmon.a crtg.o crtgend.o crttls_r25.o crttls_r30.o"
++	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o crtg.o crtgend.o crttls_r25.o crttls_r30.o"
+ 	;;
+ arc*-*-linux-uclibc*)
+ 	tmake_file="${tmake_file} t-slibgcc-libgcc t-slibgcc-nolc-override arc/t-arc700-uClibc arc/t-arc"
+-	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o libgmon.a crtg.o crtgend.o"
++	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o crtg.o crtgend.o"
+ 	;;
+ arm-wrs-vxworks)
+ 	tmake_file="$tmake_file arm/t-arm arm/t-vxworks t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp"
diff --git a/toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch b/toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch
new file mode 100644
index 0000000000..7a0ac7353e
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/820-libgcc_pic.patch
@@ -0,0 +1,36 @@
+--- a/libgcc/Makefile.in
++++ b/libgcc/Makefile.in
+@@ -865,11 +865,12 @@ $(libgcov-objects): %$(objext): $(srcdir
+ 
+ # Static libraries.
+ libgcc.a: $(libgcc-objects)
++libgcc_pic.a: $(libgcc-s-objects)
+ libgcov.a: $(libgcov-objects)
+ libunwind.a: $(libunwind-objects)
+ libgcc_eh.a: $(libgcc-eh-objects)
+ 
+-libgcc.a libgcov.a libunwind.a libgcc_eh.a:
++libgcc.a libgcov.a libunwind.a libgcc_eh.a libgcc_pic.a:
+ 	-rm -f $@
+ 
+ 	objects="$(objects)";					\
+@@ -891,7 +892,7 @@ libgcc_s$(SHLIB_EXT): libunwind$(SHLIB_E
+ endif
+ 
+ ifeq ($(enable_shared),yes)
+-all: libgcc_eh.a libgcc_s$(SHLIB_EXT)
++all: libgcc_eh.a libgcc_pic.a libgcc_s$(SHLIB_EXT)
+ ifneq ($(LIBUNWIND),)
+ all: libunwind$(SHLIB_EXT)
+ endif
+@@ -1058,6 +1059,10 @@ install-shared:
+ 	chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_eh.a
+ 	$(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_eh.a
+ 
++	$(INSTALL_DATA) libgcc_pic.a $(mapfile) $(DESTDIR)$(inst_libdir)/
++	chmod 644 $(DESTDIR)$(inst_libdir)/libgcc_pic.a
++	$(RANLIB) $(DESTDIR)$(inst_libdir)/libgcc_pic.a
++
+ 	$(subst @multilib_dir@,$(MULTIDIR),$(subst \
+ 		@shlib_base_name@,libgcc_s,$(subst \
+ 		@shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIB_INSTALL))))
diff --git a/toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch b/toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch
new file mode 100644
index 0000000000..6934bc97f6
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/850-use_shared_libgcc.patch
@@ -0,0 +1,47 @@
+--- a/gcc/config/arm/linux-eabi.h
++++ b/gcc/config/arm/linux-eabi.h
+@@ -131,10 +131,6 @@
+ #define ENDFILE_SPEC \
+   LINUX_OR_ANDROID_LD (GNU_USER_TARGET_ENDFILE_SPEC, ANDROID_ENDFILE_SPEC)
+ 
+-/* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we
+-   do not use -lfloat.  */
+-#undef LIBGCC_SPEC
+-
+ /* Clear the instruction cache from `beg' to `end'.  This is
+    implemented in lib1funcs.S, so ensure an error if this definition
+    is used.  */
+--- a/gcc/config/linux.h
++++ b/gcc/config/linux.h
+@@ -51,6 +51,10 @@ see the files COPYING3 and COPYING.RUNTI
+ 	builtin_assert ("system=posix");			\
+     } while (0)
+ 
++#ifndef LIBGCC_SPEC
++#define LIBGCC_SPEC "%{static|static-libgcc:-lgcc}%{!static:%{!static-libgcc:-lgcc_s}}"
++#endif
++
+ /* Determine which dynamic linker to use depending on whether GLIBC or
+    uClibc or Bionic is the default C library and whether
+    -muclibc or -mglibc or -mbionic has been passed to change the default.  */
+--- a/libgcc/mkmap-symver.awk
++++ b/libgcc/mkmap-symver.awk
+@@ -132,5 +132,5 @@ function output(lib) {
+   else if (inherit[lib])
+     printf("} %s;\n", inherit[lib]);
+   else
+-    printf ("\n  local:\n\t*;\n};\n");
++    printf ("\n\t*;\n};\n");
+ }
+--- a/gcc/config/rs6000/linux.h
++++ b/gcc/config/rs6000/linux.h
+@@ -61,6 +61,9 @@
+ #undef  CPLUSPLUS_CPP_SPEC
+ #define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+ 
++#undef LIBGCC_SPEC
++#define LIBGCC_SPEC "%{!static:%{!static-libgcc:-lgcc_s}} -lgcc"
++
+ #undef  LINK_SHLIB_SPEC
+ #define LINK_SHLIB_SPEC "%{shared:-shared} %{!shared: %{static:-static}}"
+ 
diff --git a/toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch b/toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch
new file mode 100644
index 0000000000..80c3476841
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/851-libgcc_no_compat.patch
@@ -0,0 +1,12 @@
+--- a/libgcc/config/t-libunwind
++++ b/libgcc/config/t-libunwind
+@@ -2,8 +2,7 @@
+ 
+ HOST_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER
+ 
+-LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \
+-  $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c
++LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
+ LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
+ 
+ # Override the default value from t-slibgcc-elf-ver and mention -lunwind
diff --git a/toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch b/toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch
new file mode 100644
index 0000000000..1ac83fe4dc
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/860-use_eh_frame.patch
@@ -0,0 +1,42 @@
+--- a/libgcc/unwind-dw2-fde-dip.c
++++ b/libgcc/unwind-dw2-fde-dip.c
+@@ -46,33 +46,13 @@
+ #include "unwind-compat.h"
+ #include "gthr.h"
+ 
+-#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
+-    && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
+-	|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
+-# define USE_PT_GNU_EH_FRAME
+-#endif
+-
+-#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
+-    && defined(__BIONIC__)
+-# define USE_PT_GNU_EH_FRAME
+-#endif
+-
+-#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
+-    && defined(__FreeBSD__) && __FreeBSD__ >= 7
+-# define ElfW __ElfN
+-# define USE_PT_GNU_EH_FRAME
+-#endif
+-
+-#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
+-    && defined(__OpenBSD__)
+-# define ElfW(type) Elf_##type
+-# define USE_PT_GNU_EH_FRAME
+-#endif
+-
+-#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
+-    && defined(TARGET_DL_ITERATE_PHDR) \
+-    && defined(__sun__) && defined(__svr4__)
++#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR)
+ # define USE_PT_GNU_EH_FRAME
++# ifdef __OpenBSD__
++#  define ElfW(type) Elf_##type
++# elif defined(__FreeBSD__) && __FreeBSD__ >= 7
++#  define ElfW __ElfN
++# endif
+ #endif
+ 
+ #if defined(USE_PT_GNU_EH_FRAME)
diff --git a/toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch b/toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch
new file mode 100644
index 0000000000..4b7fcbd5e1
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/870-ppc_no_crtsavres.patch
@@ -0,0 +1,11 @@
+--- a/gcc/config/rs6000/rs6000.c
++++ b/gcc/config/rs6000/rs6000.c
+@@ -17662,7 +17662,7 @@ rs6000_savres_strategy (rs6000_stack_t *
+   /* Define cutoff for using out-of-line functions to save registers.  */
+   if (DEFAULT_ABI == ABI_V4 || TARGET_ELF)
+     {
+-      if (!optimize_size)
++      if (1)
+ 	{
+ 	  strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
+ 	  strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
diff --git a/toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch b/toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch
new file mode 100644
index 0000000000..def6c9f4a0
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/880-no_java_section.patch
@@ -0,0 +1,11 @@
+--- a/gcc/defaults.h
++++ b/gcc/defaults.h
+@@ -380,7 +380,7 @@ see the files COPYING3 and COPYING.RUNTI
+ /* If we have named section and we support weak symbols, then use the
+    .jcr section for recording java classes which need to be registered
+    at program start-up time.  */
+-#if defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
++#if 0 && defined (TARGET_ASM_NAMED_SECTION) && SUPPORTS_WEAK
+ #ifndef JCR_SECTION_NAME
+ #define JCR_SECTION_NAME ".jcr"
+ #endif
diff --git a/toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch b/toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch
new file mode 100644
index 0000000000..5387f8e86f
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/910-mbsd_multi.patch
@@ -0,0 +1,253 @@
+
+	This patch brings over a few features from MirBSD:
+	* -fhonour-copts
+	  If this option is not given, it's warned (depending
+	  on environment variables). This is to catch errors
+	  of misbuilt packages which override CFLAGS themselves.
+	* -Werror-maybe-reset
+	  Has the effect of -Wno-error if GCC_NO_WERROR is
+	  set and not '0', a no-operation otherwise. This is
+	  to be able to use -Werror in "make" but prevent
+	  GNU autoconf generated configure scripts from
+	  freaking out.
+	* Make -fno-strict-aliasing and -fno-delete-null-pointer-checks
+	  the default for -O2/-Os, because they trigger gcc bugs
+	  and can delete code with security implications.
+
+	This patch was authored by Thorsten Glaser <tg at mirbsd.de>
+	with copyright assignment to the FSF in effect.
+
+--- a/gcc/c-family/c-opts.c
++++ b/gcc/c-family/c-opts.c
+@@ -104,6 +104,9 @@ static size_t include_cursor;
+ /* Whether any standard preincluded header has been preincluded.  */
+ static bool done_preinclude;
+ 
++/* Check if a port honours COPTS.  */
++static int honour_copts = 0;
++
+ static void handle_OPT_d (const char *);
+ static void set_std_cxx98 (int);
+ static void set_std_cxx11 (int);
+@@ -383,6 +386,9 @@ c_common_handle_option (size_t scode, co
+       cpp_opts->warn_endif_labels = value;
+       break;
+ 
++    case OPT_Werror_maybe_reset:
++      break;
++
+     case OPT_Winvalid_pch:
+       cpp_opts->warn_invalid_pch = value;
+       break;
+@@ -491,6 +497,12 @@ c_common_handle_option (size_t scode, co
+       flag_no_builtin = !value;
+       break;
+ 
++    case OPT_fhonour_copts:
++      if (c_language == clk_c) {
++        honour_copts++;
++      }
++      break;
++
+     case OPT_fconstant_string_class_:
+       constant_string_class_name = arg;
+       break;
+@@ -1027,6 +1039,47 @@ c_common_init (void)
+       return false;
+     }
+ 
++  if (c_language == clk_c) {
++    char *ev = getenv ("GCC_HONOUR_COPTS");
++    int evv;
++    if (ev == NULL)
++      evv = -1;
++    else if ((*ev == '0') || (*ev == '\0'))
++      evv = 0;
++    else if (*ev == '1')
++      evv = 1;
++    else if (*ev == '2')
++      evv = 2;
++    else if (*ev == 's')
++      evv = -1;
++    else {
++      warning (0, "unknown GCC_HONOUR_COPTS value, assuming 1");
++      evv = 1; /* maybe depend this on something like MIRBSD_NATIVE?  */
++    }
++    if (evv == 1) {
++      if (honour_copts == 0) {
++        error ("someone does not honour COPTS at all in lenient mode");
++        return false;
++      } else if (honour_copts != 1) {
++        warning (0, "someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++      }
++    } else if (evv == 2) {
++      if (honour_copts == 0) {
++        error ("someone does not honour COPTS at all in strict mode");
++        return false;
++      } else if (honour_copts != 1) {
++        error ("someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++        return false;
++      }
++    } else if (evv == 0) {
++      if (honour_copts != 1)
++        inform (0, "someone does not honour COPTS correctly, passed %d times",
++         honour_copts);
++    }
++  }
++
+   return true;
+ }
+ 
+--- a/gcc/c-family/c.opt
++++ b/gcc/c-family/c.opt
+@@ -379,6 +379,10 @@ Werror-implicit-function-declaration
+ C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration)
+ This switch is deprecated; use -Werror=implicit-function-declaration instead
+ 
++Werror-maybe-reset
++C ObjC C++ ObjC++
++; Documented in common.opt
++
+ Wfloat-equal
+ C ObjC C++ ObjC++ Var(warn_float_equal) Warning
+ Warn if testing floating point numbers for equality
+@@ -949,6 +953,9 @@ C++ ObjC++ Optimization Alias(fexception
+ fhonor-std
+ C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
+ 
++fhonour-copts
++C ObjC C++ ObjC++ RejectNegative
++
+ fhosted
+ C ObjC
+ Assume normal C execution environment
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -541,6 +541,10 @@ Werror=
+ Common Joined
+ Treat specified warning as error
+ 
++Werror-maybe-reset
++Common
++If environment variable GCC_NO_WERROR is set, act as -Wno-error
++
+ Wextra
+ Common Var(extra_warnings) Warning
+ Print extra (possibly unwanted) warnings
+@@ -1242,6 +1246,9 @@ fguess-branch-probability
+ Common Report Var(flag_guess_branch_prob) Optimization
+ Enable guessing of branch probabilities
+ 
++fhonour-copts
++Common RejectNegative
++
+ ; Nonzero means ignore `#ident' directives.  0 means handle them.
+ ; Generate position-independent code for executables if possible
+ ; On SVR4 targets, it also controls whether or not to emit a
+--- a/gcc/opts.c
++++ b/gcc/opts.c
+@@ -468,8 +468,6 @@ static const struct default_options defa
+     { OPT_LEVELS_2_PLUS, OPT_fschedule_insns2, NULL, 1 },
+ #endif
+     { OPT_LEVELS_2_PLUS, OPT_fregmove, NULL, 1 },
+-    { OPT_LEVELS_2_PLUS, OPT_fstrict_aliasing, NULL, 1 },
+-    { OPT_LEVELS_2_PLUS, OPT_fstrict_overflow, NULL, 1 },
+     { OPT_LEVELS_2_PLUS, OPT_freorder_blocks, NULL, 1 },
+     { OPT_LEVELS_2_PLUS, OPT_freorder_functions, NULL, 1 },
+     { OPT_LEVELS_2_PLUS, OPT_ftree_vrp, NULL, 1 },
+@@ -489,6 +487,8 @@ static const struct default_options defa
+     { OPT_LEVELS_2_PLUS, OPT_fhoist_adjacent_loads, NULL, 1 },
+ 
+     /* -O3 optimizations.  */
++    { OPT_LEVELS_3_PLUS, OPT_fstrict_aliasing, NULL, 1 },
++    { OPT_LEVELS_3_PLUS, OPT_fstrict_overflow, NULL, 1 },
+     { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
+     { OPT_LEVELS_3_PLUS, OPT_fpredictive_commoning, NULL, 1 },
+     /* Inlining of functions reducing size is a good idea with -Os
+@@ -1435,6 +1435,17 @@ common_handle_option (struct gcc_options
+ 			       opts, opts_set, loc, dc);
+       break;
+ 
++    case OPT_Werror_maybe_reset:
++      {
++        char *ev = getenv ("GCC_NO_WERROR");
++        if ((ev != NULL) && (*ev != '0'))
++          warnings_are_errors = 0;
++      }
++      break;
++
++    case OPT_fhonour_copts:
++      break;
++
+     case OPT_Wlarger_than_:
+       opts->x_larger_than_size = value;
+       opts->x_warn_larger_than = value != -1;
+--- a/gcc/doc/cppopts.texi
++++ b/gcc/doc/cppopts.texi
+@@ -163,6 +163,11 @@ in older programs.  This warning is on b
+ Make all warnings into hard errors.  Source code which triggers warnings
+ will be rejected.
+ 
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
+ @item -Wsystem-headers
+ @opindex Wsystem-headers
+ Issue warnings for code in system headers.  These are normally unhelpful
+--- a/gcc/doc/invoke.texi
++++ b/gcc/doc/invoke.texi
+@@ -240,7 +240,7 @@ Objective-C and Objective-C++ Dialects}.
+ -Wconversion  -Wcoverage-mismatch  -Wno-cpp  -Wno-deprecated  @gol
+ -Wno-deprecated-declarations -Wdisabled-optimization  @gol
+ -Wno-div-by-zero -Wdouble-promotion -Wempty-body  -Wenum-compare @gol
+--Wno-endif-labels -Werror  -Werror=* @gol
++-Wno-endif-labels -Werror  -Werror=* -Werror-maybe-reset @gol
+ -Wfatal-errors  -Wfloat-equal  -Wformat  -Wformat=2 @gol
+ -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol
+ -Wformat-security  -Wformat-y2k @gol
+@@ -4817,6 +4817,22 @@ This option is only supported for C and 
+ @option{-Wall} and by @option{-Wpedantic}, which can be disabled with
+ @option{-Wno-pointer-sign}.
+ 
++ at item -Werror-maybe-reset
++ at opindex Werror-maybe-reset
++Act like @samp{-Wno-error} if the @env{GCC_NO_WERROR} environment
++variable is set to anything other than 0 or empty.
++
++ at item -fhonour-copts
++ at opindex fhonour-copts
++If @env{GCC_HONOUR_COPTS} is set to 1, abort if this option is not
++given at least once, and warn if it is given more than once.
++If @env{GCC_HONOUR_COPTS} is set to 2, abort if this option is not
++given exactly once.
++If @env{GCC_HONOUR_COPTS} is set to 0 or unset, warn if this option
++is not given exactly once.
++The warning is quelled if @env{GCC_HONOUR_COPTS} is set to @samp{s}.
++This flag and environment variable only affect the C language.
++
+ @item -Wstack-protector
+ @opindex Wstack-protector
+ @opindex Wno-stack-protector
+@@ -6928,7 +6944,7 @@ so, the first branch is redirected to ei
+ second branch or a point immediately following it, depending on whether
+ the condition is known to be true or false.
+ 
+-Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
++Enabled at levels @option{-O3}.
+ 
+ @item -fsplit-wide-types
+ @opindex fsplit-wide-types
+--- a/gcc/java/jvspec.c
++++ b/gcc/java/jvspec.c
+@@ -626,6 +626,7 @@ lang_specific_pre_link (void)
+      class name.  Append dummy `.c' that can be stripped by set_input so %b
+      is correct.  */ 
+   set_input (concat (main_class_name, "main.c", NULL));
++  putenv ("GCC_HONOUR_COPTS=s"); /* XXX hack!  */
+   err = do_spec (jvgenmain_spec);
+   if (err == 0)
+     {
diff --git a/toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch b/toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch
new file mode 100644
index 0000000000..09768f525b
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/920-specs_nonfatal_getenv.patch
@@ -0,0 +1,14 @@
+--- a/gcc/gcc.c
++++ b/gcc/gcc.c
+@@ -8029,7 +8029,10 @@ getenv_spec_function (int argc, const ch
+ 
+   value = getenv (argv[0]);
+   if (!value)
+-    fatal_error ("environment variable %qs not defined", argv[0]);
++    {
++      warning (0, "environment variable %qs not defined", argv[0]);
++      value = "";
++    }
+ 
+   /* We have to escape every character of the environment variable so
+      they are not interpreted as active spec characters.  A
diff --git a/toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch b/toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch
new file mode 100644
index 0000000000..dbecef2d57
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/940-no-clobber-stamp-bits.patch
@@ -0,0 +1,11 @@
+--- a/libstdc++-v3/include/Makefile.in
++++ b/libstdc++-v3/include/Makefile.in
+@@ -1342,7 +1342,7 @@
+ 	@$(STAMP) stamp-bits
+ 
+ stamp-bits-sup: stamp-bits ${bits_sup_headers}
+-	@-cd ${bits_builddir} && $(LN_S) $? . 2>/dev/null
++	@-cd ${bits_builddir} && $(LN_S) $(filter-out stamp-bits,$?) . 2>/dev/null
+ 	@$(STAMP) stamp-bits-sup
+ 
+ stamp-c_base: ${c_base_headers}
diff --git a/toolchain/gcc/patches/arc-2016.03/950-fix-building-with-gcc6.patch b/toolchain/gcc/patches/arc-2016.03/950-fix-building-with-gcc6.patch
new file mode 100644
index 0000000000..e958380696
--- /dev/null
+++ b/toolchain/gcc/patches/arc-2016.03/950-fix-building-with-gcc6.patch
@@ -0,0 +1,153 @@
+From 5dce741e00f86a08a4c174fb3605d896f210ab52 Mon Sep 17 00:00:00 2001
+From: Bernd Edlinger <bernd.edlinger@hotmail.de>
+Date: Wed, 27 Jul 2016 13:30:03 +0300
+Subject: [PATCH] 2016-02-19  Jakub Jelinek  <jakub@redhat.com>  Bernd Edlinger
+  <bernd.edlinger@hotmail.de>
+
+        * Make-lang.in: Invoke gperf with -L C++.
+        * cfns.gperf: Remove prototypes for hash and libc_name_p
+        inlines.
+        * cfns.h: Regenerated.
+        * except.c (nothrow_libfn_p): Adjust.
+
+git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233572138bc75d-0d04-0410-961f-82ee72b054a4
+
+This patch fixes building of gcc-4.x by gcc-6.x, for more details see
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69959
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+---
+ gcc/cp/Make-lang.in |  2 +-
+ gcc/cp/cfns.gperf   | 10 ++--------
+ gcc/cp/cfns.h       | 41 ++++++++++++++---------------------------
+ gcc/cp/except.c     |  3 ++-
+ 4 files changed, 19 insertions(+), 37 deletions(-)
+
+diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
+index dce523a..36a1a97 100644
+--- a/gcc/cp/Make-lang.in
++++ b/gcc/cp/Make-lang.in
+@@ -115,7 +115,7 @@ else
+ # deleting the $(srcdir)/cp/cfns.h file.
+ $(srcdir)/cp/cfns.h:
+ endif
+-	gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' -L ANSI-C \
++	gperf -o -C -E -k '1-6,$$' -j1 -D -N 'libc_name_p' -L C++ \
+ 		$(srcdir)/cp/cfns.gperf --output-file $(srcdir)/cp/cfns.h
+ 
+ #
+diff --git a/gcc/cp/cfns.gperf b/gcc/cp/cfns.gperf
+index c4c4e2a..5c40933 100644
+--- a/gcc/cp/cfns.gperf
++++ b/gcc/cp/cfns.gperf
+@@ -1,3 +1,5 @@
++%language=C++
++%define class-name libc_name
+ %{
+ /* Copyright (C) 2000-2013 Free Software Foundation, Inc.
+ 
+@@ -16,14 +18,6 @@ for more details.
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+-#ifdef __GNUC__
+-__inline
+-#endif
+-static unsigned int hash (const char *, unsigned int);
+-#ifdef __GNUC__
+-__inline
+-#endif
+-const char * libc_name_p (const char *, unsigned int);
+ %}
+ %%
+ # The standard C library functions, for feeding to gperf; the result is used
+diff --git a/gcc/cp/cfns.h b/gcc/cp/cfns.h
+index 42dd3cf..6c79864 100644
+--- a/gcc/cp/cfns.h
++++ b/gcc/cp/cfns.h
+@@ -1,5 +1,5 @@
+-/* ANSI-C code produced by gperf version 3.0.3 */
+-/* Command-line: gperf -o -C -E -k '1-6,$' -j1 -D -N libc_name_p -L ANSI-C cfns.gperf  */
++/* C++ code produced by gperf version 3.0.4 */
++/* Command-line: gperf -o -C -E -k '1-6,$' -j1 -D -N libc_name_p -L C++ --output-file cfns.h cfns.gperf  */
+ 
+ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+@@ -28,7 +28,7 @@
+ #error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+ #endif
+ 
+-#line 1 "cfns.gperf"
++#line 3 "cfns.gperf"
+ 
+ /* Copyright (C) 2000-2013 Free Software Foundation, Inc.
+ 
+@@ -47,25 +47,18 @@ for more details.
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+-#ifdef __GNUC__
+-__inline
+-#endif
+-static unsigned int hash (const char *, unsigned int);
+-#ifdef __GNUC__
+-__inline
+-#endif
+-const char * libc_name_p (const char *, unsigned int);
+ /* maximum key range = 391, duplicates = 0 */
+ 
+-#ifdef __GNUC__
+-__inline
+-#else
+-#ifdef __cplusplus
+-inline
+-#endif
+-#endif
+-static unsigned int
+-hash (register const char *str, register unsigned int len)
++class libc_name
++{
++private:
++  static inline unsigned int hash (const char *str, unsigned int len);
++public:
++  static const char *libc_name_p (const char *str, unsigned int len);
++};
++
++inline unsigned int
++libc_name::hash (register const char *str, register unsigned int len)
+ {
+   static const unsigned short asso_values[] =
+     {
+@@ -122,14 +115,8 @@ hash (register const char *str, register unsigned int len)
+   return hval + asso_values[(unsigned char)str[len - 1]];
+ }
+ 
+-#ifdef __GNUC__
+-__inline
+-#ifdef __GNUC_STDC_INLINE__
+-__attribute__ ((__gnu_inline__))
+-#endif
+-#endif
+ const char *
+-libc_name_p (register const char *str, register unsigned int len)
++libc_name::libc_name_p (register const char *str, register unsigned int len)
+ {
+   enum
+     {
+diff --git a/gcc/cp/except.c b/gcc/cp/except.c
+index 604f274..c3298cb 100644
+--- a/gcc/cp/except.c
++++ b/gcc/cp/except.c
+@@ -1025,7 +1025,8 @@ nothrow_libfn_p (const_tree fn)
+      unless the system headers are playing rename tricks, and if
+      they are, we don't want to be confused by them.  */
+   id = DECL_NAME (fn);
+-  return !!libc_name_p (IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
++  return !!libc_name::libc_name_p (IDENTIFIER_POINTER (id),
++				   IDENTIFIER_LENGTH (id));
+ }
+ 
+ /* Returns nonzero if an exception of type FROM will be caught by a
+-- 
+2.7.4
+
diff --git a/toolchain/gdb/Makefile b/toolchain/gdb/Makefile
new file mode 100644
index 0000000000..78f4fca420
--- /dev/null
+++ b/toolchain/gdb/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gdb
+
+ifeq ($(CONFIG_arc),y)
+PKG_VERSION:=arc-2016.03-gdb
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/archive/arc-2016.03-gdb
+PKG_MD5SUM:=775caaf6385c16f20b6f53c0a2b95f79
+GDB_DIR:=binutils-$(PKG_NAME)-$(PKG_VERSION)
+PATCH_DIR:=./patches-arc
+else
+PKG_VERSION:=7.12
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/gdb
+PKG_MD5SUM:=834ff3c5948b30718343ea57b11cbc3235d7995c6a4f3a5cecec8c8114164f94
+GDB_DIR:=$(PKG_NAME)-$(PKG_VERSION)
+endif
+
+HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(GDB_DIR)
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+HOST_CONFIGURE_VARS += \
+	gdb_cv_func_sigsetjmp=yes
+
+HOST_CONFIGURE_ARGS = \
+	--prefix=$(TOOLCHAIN_DIR) \
+	--build=$(GNU_HOST_NAME) \
+	--host=$(GNU_HOST_NAME) \
+	--target=$(REAL_GNU_TARGET_NAME) \
+	--disable-werror \
+	--without-uiout \
+	--disable-tui --disable-gdbtk --without-x \
+	--without-included-gettext \
+	--enable-threads \
+	--with-expat \
+	--without-python \
+	--disable-binutils \
+	--disable-ld \
+	--disable-gas \
+	--disable-sim
+
+define Host/Install
+	mkdir -p $(TOOLCHAIN_DIR)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/gdb/gdb $(TOOLCHAIN_DIR)/bin/$(TARGET_CROSS)gdb
+	ln -fs $(TARGET_CROSS)gdb $(TOOLCHAIN_DIR)/bin/$(GNU_TARGET_NAME)-gdb
+	strip $(TOOLCHAIN_DIR)/bin/$(TARGET_CROSS)gdb
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(TOOLCHAIN_DIR)/bin/$(TARGET_CROSS)gdb \
+		$(TOOLCHAIN_DIR)/bin/$(GNU_TARGET_NAME)-gdb
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/gdb/patches-arc/100-no_extern_inline.patch b/toolchain/gdb/patches-arc/100-no_extern_inline.patch
new file mode 100644
index 0000000000..8c18c6e2e7
--- /dev/null
+++ b/toolchain/gdb/patches-arc/100-no_extern_inline.patch
@@ -0,0 +1,32 @@
+--- a/sim/common/sim-arange.c
++++ b/sim/common/sim-arange.c
+@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a
+   build_search_tree (ar);
+ }
+ 
+-#endif /* DEFINE_NON_INLINE_P */
+-
+-#if DEFINE_INLINE_P
+-
+-SIM_ARANGE_INLINE int
++int
+ sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
+ {
+   ADDR_RANGE_TREE *t = ar->range_tree;
+@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad
+   return 0;
+ }
+ 
+-#endif /* DEFINE_INLINE_P */
++#endif /* DEFINE_NON_INLINE_P */
+--- a/sim/common/sim-arange.h
++++ b/sim/common/sim-arange.h
+@@ -73,7 +73,7 @@ extern void sim_addr_range_delete (ADDR_
+ 
+ /* Return non-zero if ADDR is in range AR, traversing the entire tree.
+    If no range is specified, that is defined to mean "everything".  */
+-SIM_ARANGE_INLINE int
++extern int
+ sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
+ #define ADDR_RANGE_HIT_P(ar, addr) \
+   ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
diff --git a/toolchain/gdb/patches-arc/110-no_testsuite.patch b/toolchain/gdb/patches-arc/110-no_testsuite.patch
new file mode 100644
index 0000000000..1b284ea767
--- /dev/null
+++ b/toolchain/gdb/patches-arc/110-no_testsuite.patch
@@ -0,0 +1,21 @@
+--- a/gdb/configure
++++ b/gdb/configure
+@@ -870,8 +870,7 @@ MAKEINFOFLAGS
+ YACC
+ YFLAGS
+ XMKMF'
+-ac_subdirs_all='testsuite
+-gdbtk
++ac_subdirs_all='gdbtk
+ multi-ice
+ gdbserver'
+ 
+@@ -5610,7 +5610,7 @@ $as_echo "$with_auto_load_safe_path" >&6
+ 
+ 
+ 
+-subdirs="$subdirs testsuite"
++subdirs="$subdirs"
+ 
+ 
+ # Check whether to support alternative target configurations
diff --git a/toolchain/gdb/patches-arc/120-fix-compile-flag-mismatch.patch b/toolchain/gdb/patches-arc/120-fix-compile-flag-mismatch.patch
new file mode 100644
index 0000000000..c8b41f264a
--- /dev/null
+++ b/toolchain/gdb/patches-arc/120-fix-compile-flag-mismatch.patch
@@ -0,0 +1,11 @@
+--- a/gdb/gdbserver/configure
++++ b/gdb/gdbserver/configure
+@@ -2468,7 +2468,7 @@ $as_echo "$as_me: error: \`$ac_var' was
+       ac_cache_corrupted=: ;;
+     ,);;
+     *)
+-      if test "x$ac_old_val" != "x$ac_new_val"; then
++      if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
+ 	# differences in whitespace do not lead to failure.
+ 	ac_old_val_w=`echo x $ac_old_val`
+ 	ac_new_val_w=`echo x $ac_new_val`
diff --git a/toolchain/gdb/patches/100-no_extern_inline.patch b/toolchain/gdb/patches/100-no_extern_inline.patch
new file mode 100644
index 0000000000..8c18c6e2e7
--- /dev/null
+++ b/toolchain/gdb/patches/100-no_extern_inline.patch
@@ -0,0 +1,32 @@
+--- a/sim/common/sim-arange.c
++++ b/sim/common/sim-arange.c
+@@ -280,11 +280,7 @@ sim_addr_range_delete (ADDR_RANGE *ar, a
+   build_search_tree (ar);
+ }
+ 
+-#endif /* DEFINE_NON_INLINE_P */
+-
+-#if DEFINE_INLINE_P
+-
+-SIM_ARANGE_INLINE int
++int
+ sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
+ {
+   ADDR_RANGE_TREE *t = ar->range_tree;
+@@ -301,4 +297,4 @@ sim_addr_range_hit_p (ADDR_RANGE *ar, ad
+   return 0;
+ }
+ 
+-#endif /* DEFINE_INLINE_P */
++#endif /* DEFINE_NON_INLINE_P */
+--- a/sim/common/sim-arange.h
++++ b/sim/common/sim-arange.h
+@@ -73,7 +73,7 @@ extern void sim_addr_range_delete (ADDR_
+ 
+ /* Return non-zero if ADDR is in range AR, traversing the entire tree.
+    If no range is specified, that is defined to mean "everything".  */
+-SIM_ARANGE_INLINE int
++extern int
+ sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
+ #define ADDR_RANGE_HIT_P(ar, addr) \
+   ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
diff --git a/toolchain/gdb/patches/110-no_testsuite.patch b/toolchain/gdb/patches/110-no_testsuite.patch
new file mode 100644
index 0000000000..68d1c90359
--- /dev/null
+++ b/toolchain/gdb/patches/110-no_testsuite.patch
@@ -0,0 +1,21 @@
+--- a/gdb/configure
++++ b/gdb/configure
+@@ -874,8 +874,7 @@ MAKEINFOFLAGS
+ YACC
+ YFLAGS
+ XMKMF'
+-ac_subdirs_all='testsuite
+-gdbtk
++ac_subdirs_all='gdbtk
+ multi-ice
+ gdbserver'
+ 
+@@ -5617,7 +5616,7 @@ $as_echo "$with_auto_load_safe_path" >&6
+ 
+ 
+ 
+-subdirs="$subdirs testsuite"
++subdirs="$subdirs"
+ 
+ 
+ # Check whether to support alternative target configurations
diff --git a/toolchain/gdb/patches/120-fix-compile-flag-mismatch.patch b/toolchain/gdb/patches/120-fix-compile-flag-mismatch.patch
new file mode 100644
index 0000000000..562902c50f
--- /dev/null
+++ b/toolchain/gdb/patches/120-fix-compile-flag-mismatch.patch
@@ -0,0 +1,11 @@
+--- a/gdb/gdbserver/configure
++++ b/gdb/gdbserver/configure
+@@ -2476,7 +2476,7 @@ $as_echo "$as_me: error: \`$ac_var' was
+       ac_cache_corrupted=: ;;
+     ,);;
+     *)
+-      if test "x$ac_old_val" != "x$ac_new_val"; then
++      if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
+ 	# differences in whitespace do not lead to failure.
+ 	ac_old_val_w=`echo x $ac_old_val`
+ 	ac_new_val_w=`echo x $ac_new_val`
diff --git a/toolchain/glibc/Config.in b/toolchain/glibc/Config.in
new file mode 100644
index 0000000000..5adbeb6f82
--- /dev/null
+++ b/toolchain/glibc/Config.in
@@ -0,0 +1,12 @@
+choice
+	prompt "glibc version"
+	depends on TOOLCHAINOPTS && USE_GLIBC && !EXTERNAL_TOOLCHAIN
+	default GLIBC_USE_VERSION_2_24
+	help
+	  Select the version of glibc you wish to use.
+
+	config GLIBC_USE_VERSION_2_24
+		bool "glibc 2.24"
+		select GLIBC_VERSION_2_24
+
+endchoice
diff --git a/toolchain/glibc/Config.version b/toolchain/glibc/Config.version
new file mode 100644
index 0000000000..1df7719ac8
--- /dev/null
+++ b/toolchain/glibc/Config.version
@@ -0,0 +1,11 @@
+if USE_GLIBC
+
+config GLIBC_VERSION
+	string
+	default "2.24" if GLIBC_VERSION_2_24
+
+config GLIBC_VERSION_2_24
+	default y if !TOOLCHAINOPTS
+	bool
+
+endif
diff --git a/toolchain/glibc/Makefile b/toolchain/glibc/Makefile
new file mode 100644
index 0000000000..974691c1c9
--- /dev/null
+++ b/toolchain/glibc/Makefile
@@ -0,0 +1,31 @@
+PATH_PREFIX := .
+VARIANT:=final
+HOST_BUILD_PARALLEL:=1
+
+include ./common.mk
+
+define Host/Compile
+	+$(MAKE) -C $(CUR_BUILD_DIR) \
+		PARALLELMFLAGS="$(HOST_JOBS)" \
+		BUILD_CFLAGS="$(HOST_CFLAGS)" \
+		all
+endef
+
+define Host/Install
+	$(call Host/SetToolchainInfo)
+	$(MAKE) -C $(CUR_BUILD_DIR) \
+		BUILD_CFLAGS="$(HOST_CFLAGS)" \
+		install_root="$(TOOLCHAIN_DIR)" \
+		install
+	( cd $(TOOLCHAIN_DIR) ; \
+		for d in lib usr/lib ; do \
+		  for f in libc.so libpthread.so libgcc_s.so ; do \
+		    if [ -f $$$$d/$$$$f -a ! -L $$$$d/$$$$f ] ; then \
+		      $(SED) 's,/usr/lib/,,g;s,/lib/,,g' $$$$d/$$$$f ; \
+		    fi \
+		  done \
+		done \
+	)
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/glibc/common.mk b/toolchain/glibc/common.mk
new file mode 100644
index 0000000000..0ffa44f320
--- /dev/null
+++ b/toolchain/glibc/common.mk
@@ -0,0 +1,107 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+
+MD5SUM_2.24 = 5c5a6f1ac6fce866e37643c41ac116f3
+REVISION_2.24 = 8c716c2
+
+
+PKG_NAME:=glibc
+PKG_VERSION:=$(call qstrip,$(CONFIG_GLIBC_VERSION))
+
+PKG_REVISION:=$(REVISION_$(PKG_VERSION))
+PKG_MIRROR_MD5SUM:=$(MD5SUM_$(PKG_VERSION))
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://sourceware.org/git/glibc.git
+PKG_SOURCE_VERSION:=$(PKG_REVISION)
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_REVISION)
+PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.bz2
+
+GLIBC_PATH:=
+
+PATCH_DIR:=$(PATH_PREFIX)/patches/$(PKG_VERSION)
+
+HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(PKG_SOURCE_SUBDIR)
+CUR_BUILD_DIR:=$(HOST_BUILD_DIR)-$(VARIANT)
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+HOST_STAMP_PREPARED:=$(HOST_BUILD_DIR)/.prepared
+HOST_STAMP_CONFIGURED:=$(CUR_BUILD_DIR)/.configured
+HOST_STAMP_BUILT:=$(CUR_BUILD_DIR)/.built
+HOST_STAMP_INSTALLED:=$(TOOLCHAIN_DIR)/stamp/.glibc_$(VARIANT)_installed
+
+ifeq ($(ARCH),mips64)
+  ifdef CONFIG_MIPS64_ABI_N64
+    TARGET_CFLAGS += -mabi=64
+  endif
+  ifdef CONFIG_MIPS64_ABI_N32
+    TARGET_CFLAGS += -mabi=n32
+  endif
+  ifdef CONFIG_MIPS64_ABI_O32
+    TARGET_CFLAGS += -mabi=32
+  endif
+endif
+
+
+# -Os miscompiles w. 2.24 gcc5/gcc6
+# only -O2 tested by upstream changeset
+# "Optimize i386 syscall inlining for GCC 5"
+GLIBC_CONFIGURE:= \
+	BUILD_CC="$(HOSTCC)" \
+	$(TARGET_CONFIGURE_OPTS) \
+	CFLAGS="-O2 $(filter-out -Os,$(call qstrip,$(TARGET_CFLAGS)))" \
+	libc_cv_slibdir="/lib" \
+	use_ldconfig=no \
+	$(HOST_BUILD_DIR)/$(GLIBC_PATH)configure \
+		--prefix= \
+		--build=$(GNU_HOST_NAME) \
+		--host=$(REAL_GNU_TARGET_NAME) \
+		--with-headers=$(TOOLCHAIN_DIR)/include \
+		--disable-profile \
+		--disable-werror \
+		--without-gd \
+		--without-cvs \
+		--enable-add-ons \
+		--$(if $(CONFIG_SOFT_FLOAT),without,with)-fp
+
+export libc_cv_ssp=no
+export libc_cv_ssp_strong=no
+export ac_cv_header_cpuid_h=yes
+export HOST_CFLAGS := $(HOST_CFLAGS) -idirafter $(CURDIR)/$(PATH_PREFIX)/include
+
+define Host/SetToolchainInfo
+	$(SED) 's,^\(LIBC_TYPE\)=.*,\1=$(PKG_NAME),' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_URL\)=.*,\1=http://www.gnu.org/software/libc/,' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_VERSION\)=.*,\1=$(PKG_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_SO_VERSION\)=.*,\1=$(PKG_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+endef
+
+define Host/Configure
+	[ -f $(HOST_BUILD_DIR)/.autoconf ] || { \
+		cd $(HOST_BUILD_DIR)/$(GLIBC_PATH); \
+		autoconf --force && \
+		touch $(HOST_BUILD_DIR)/.autoconf; \
+	}
+	mkdir -p $(CUR_BUILD_DIR)
+	( cd $(CUR_BUILD_DIR); rm -f config.cache; \
+		$(GLIBC_CONFIGURE) \
+	);
+endef
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	ln -snf $(PKG_SOURCE_SUBDIR) $(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+endef
+
+define Host/Clean
+	rm -rf $(CUR_BUILD_DIR)* \
+		$(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev \
+		$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+endef
diff --git a/toolchain/glibc/headers/Makefile b/toolchain/glibc/headers/Makefile
new file mode 100644
index 0000000000..f1d8a8bc61
--- /dev/null
+++ b/toolchain/glibc/headers/Makefile
@@ -0,0 +1,28 @@
+PATH_PREFIX:=..
+VARIANT:=headers
+
+include ../common.mk
+
+define Host/Compile
+
+endef
+
+define Host/Install
+	$(call Host/SetToolchainInfo)
+	mkdir -p $(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/{include,lib}
+	$(MAKE) -C $(CUR_BUILD_DIR) \
+		BUILD_CFLAGS="$(HOST_CFLAGS)" \
+		install_root="$(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev" \
+		install-bootstrap-headers=yes \
+		install-headers
+	$(CP) $(BUILD_DIR_TOOLCHAIN)/linux-dev/* $(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/
+	$(MAKE) -C $(CUR_BUILD_DIR) \
+		csu/subdir_lib
+	( cd $(CUR_BUILD_DIR); \
+		$(CP) csu/crt1.o csu/crti.o csu/crtn.o $(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/lib/ \
+	)
+	$(TARGET_CC) -nostdlib -nostartfiles -shared -x c /dev/null \
+		-o $(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/lib/libc.so
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/glibc/include/libintl.h b/toolchain/glibc/include/libintl.h
new file mode 100644
index 0000000000..69cb887a26
--- /dev/null
+++ b/toolchain/glibc/include/libintl.h
@@ -0,0 +1,6 @@
+#ifndef __FAKE_LIBINTL_H
+#define __FAKE_LIBINTL_H
+
+#define _(X) (X)
+
+#endif
diff --git a/toolchain/glibc/patches/2.24/100-fix_cross_rpcgen.patch b/toolchain/glibc/patches/2.24/100-fix_cross_rpcgen.patch
new file mode 100644
index 0000000000..6a5e537b77
--- /dev/null
+++ b/toolchain/glibc/patches/2.24/100-fix_cross_rpcgen.patch
@@ -0,0 +1,52 @@
+--- a/sunrpc/rpc/types.h
++++ b/sunrpc/rpc/types.h
+@@ -75,18 +75,23 @@ typedef unsigned long rpcport_t;
+ #endif
+ 
+ #ifndef __u_char_defined
+-typedef __u_char u_char;
+-typedef __u_short u_short;
+-typedef __u_int u_int;
+-typedef __u_long u_long;
+-typedef __quad_t quad_t;
+-typedef __u_quad_t u_quad_t;
+-typedef __fsid_t fsid_t;
++typedef unsigned char u_char;
++typedef unsigned short u_short;
++typedef unsigned int u_int;
++typedef unsigned long u_long;
++#if __WORDSIZE == 64
++typedef long int quad_t;
++typedef unsigned long int u_quad_t;
++#elif defined __GLIBC_HAVE_LONG_LONG
++typedef long long int quad_t;
++typedef unsigned long long int u_quad_t;
++#endif
++typedef u_quad_t fsid_t;
+ # define __u_char_defined
+ #endif
+-#ifndef __daddr_t_defined
+-typedef __daddr_t daddr_t;
+-typedef __caddr_t caddr_t;
++#if !defined(__daddr_t_defined) && defined(linux)
++typedef long int daddr_t;
++typedef char *caddr_t;
+ # define __daddr_t_defined
+ #endif
+ 
+--- a/sunrpc/rpc_main.c
++++ b/sunrpc/rpc_main.c
+@@ -958,9 +958,10 @@ mkfile_output (struct commandline *cmd)
+ 	abort ();
+       temp = rindex (cmd->infile, '.');
+       cp = stpcpy (mkfilename, "Makefile.");
+-      if (temp != NULL)
+-	*((char *) stpncpy (cp, cmd->infile, temp - cmd->infile)) = '\0';
+-      else
++      if (temp != NULL) {
++        strncpy(cp, cmd->infile, temp - cmd->infile);
++        cp[temp - cmd->infile - 1] = 0;
++      } else
+ 	stpcpy (cp, cmd->infile);
+ 
+     }
diff --git a/toolchain/glibc/patches/2.24/200-add-dl-search-paths.patch b/toolchain/glibc/patches/2.24/200-add-dl-search-paths.patch
new file mode 100644
index 0000000000..d65a0bcdd0
--- /dev/null
+++ b/toolchain/glibc/patches/2.24/200-add-dl-search-paths.patch
@@ -0,0 +1,14 @@
+add /usr/lib to default search path for the dynamic linker
+
+--- a/Makeconfig
++++ b/Makeconfig
+@@ -526,6 +526,9 @@ else
+ default-rpath = $(libdir)
+ endif
+ 
++# Add /usr/lib to default search path for the dynamic linker
++user-defined-trusted-dirs := /usr/lib
++
+ ifndef link-extra-libs
+ link-extra-libs = $(LDLIBS-$(@F))
+ link-extra-libs-static = $(link-extra-libs)
diff --git a/toolchain/info.mk b/toolchain/info.mk
new file mode 100644
index 0000000000..4f311c5506
--- /dev/null
+++ b/toolchain/info.mk
@@ -0,0 +1,6 @@
+TARGET_CROSS=
+GCC_VERSION=unknown
+LIBC_TYPE=unknown
+LIBC_URL=unknown
+LIBC_VERSION=unknown
+LIBC_SO_VERSION=unknown
diff --git a/toolchain/insight/Makefile b/toolchain/insight/Makefile
new file mode 100644
index 0000000000..3744f56451
--- /dev/null
+++ b/toolchain/insight/Makefile
@@ -0,0 +1,54 @@
+# 
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=insight
+PKG_VERSION:=6.8-1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)a.tar.bz2
+PKG_MD5SUM:=f7dd764a102beb75c2bb6b8d83455f8e
+PKG_SOURCE_URL:=ftp://sourceware.org/pub/insight/releases
+PKG_CAT:=bzcat
+
+STAGING_DIR_HOST:=$(TOOLCHAIN_DIR)
+BUILD_DIR_HOST:=$(BUILD_DIR_TOOLCHAIN)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR); \
+		gdb_cv_func_sigsetjmp=yes \
+		CFLAGS="-O2" \
+		$(HOST_BUILD_DIR)/configure \
+		--prefix=$(TOOLCHAIN_DIR) \
+		--build=$(GNU_HOST_NAME) \
+		--host=$(GNU_HOST_NAME) \
+		--target=$(REAL_GNU_TARGET_NAME) \
+		--enable-threads \
+		--enable-werror=no \
+	);
+endef
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR)
+endef
+
+define Host/Install
+	mkdir -p $(TOOLCHAIN_DIR)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/gdb/insight $(TOOLCHAIN_DIR)/bin/$(TARGET_CROSS)insight
+	ln -fs $(TARGET_CROSS)insight $(TOOLCHAIN_DIR)/bin/$(GNU_TARGET_NAME)-insight
+	strip $(TOOLCHAIN_DIR)/bin/$(TARGET_CROSS)insight
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(TOOLCHAIN_DIR)/bin/$(TARGET_CROSS)insight \
+		$(TOOLCHAIN_DIR)/bin/$(GNU_TARGET_NAME)-insight
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/insight/patches/600-fix-compile-flag-mismatch.patch b/toolchain/insight/patches/600-fix-compile-flag-mismatch.patch
new file mode 100644
index 0000000000..13b72bb96d
--- /dev/null
+++ b/toolchain/insight/patches/600-fix-compile-flag-mismatch.patch
@@ -0,0 +1,31 @@
+--- a/gdb/gdbserver/configure
++++ b/gdb/gdbserver/configure
+@@ -1239,7 +1239,7 @@
+       ac_cache_corrupted=: ;;
+     ,);;
+     *)
+-      if test "x$ac_old_val" != "x$ac_new_val"; then
++      if test "`echo x$ac_old_val`" != "`echo x$ac_new_val`"; then
+ 	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+ echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ 	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+--- a/gdb/configure
++++ b/gdb/configure
+@@ -272,7 +272,7 @@
+ PACKAGE_BUGREPORT=
+ 
+ ac_unique_file="main.c"
+-ac_subdirs_all="$ac_subdirs_all doc testsuite"
++ac_subdirs_all="$ac_subdirs_all doc"
+ # Factoring default headers for most tests.
+ ac_includes_default="\
+ #include <stdio.h>
+@@ -3077,7 +3077,7 @@
+ 
+ 
+ 
+-subdirs="$subdirs doc testsuite"
++subdirs="$subdirs doc"
+ 
+ 
+ # Provide defaults for some variables set by the per-host and per-target
diff --git a/toolchain/kernel-headers/Makefile b/toolchain/kernel-headers/Makefile
new file mode 100644
index 0000000000..fa7d349baa
--- /dev/null
+++ b/toolchain/kernel-headers/Makefile
@@ -0,0 +1,101 @@
+# 
+# Copyright (C) 2006-2009 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+KERNEL_BUILD_DIR := $(BUILD_DIR_TOOLCHAIN)
+BUILD_DIR := $(KERNEL_BUILD_DIR)
+
+override QUILT:=
+override HOST_QUILT:=
+
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=linux
+PKG_VERSION:=$(LINUX_VERSION)
+PKG_SOURCE:=$(LINUX_SOURCE)
+PKG_SOURCE_URL:=$(LINUX_SITE)
+HOST_BUILD_DIR:=$(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)
+PKG_MD5SUM:=$(LINUX_KERNEL_MD5SUM)
+LINUX_DIR := $(HOST_BUILD_DIR)
+FILES_DIR := 
+PATCH_DIR := ./patches$(if $(wildcard ./patches-$(LINUX_VERSION)),-$(LINUX_VERSION))
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+include $(INCLUDE_DIR)/kernel-defaults.mk
+
+ifeq ($(strip $(BOARD)),uml)
+  LINUX_KARCH:=$(subst x86_64,x86,$(subst i386,x86,$(ARCH)))
+endif
+
+HOST_EXTRACFLAGS=
+
+LINUX_HAS_HEADERS_INSTALL:=y
+
+KMAKE := $(MAKE) -C $(HOST_BUILD_DIR) \
+	HOSTCFLAGS="$(HOST_CFLAGS) -Wall -Wmissing-prototypes -Wstrict-prototypes" \
+	ARCH=$(LINUX_KARCH) \
+	CC="$(KERNEL_CC)" \
+	CFLAGS="$(TARGET_CFLAGS)" \
+	CROSS_COMPILE=$(TARGET_CROSS) \
+	KBUILD_HAVE_NLS=no \
+	CONFIG_SHELL=$(BASH)
+
+define Host/Configure/all
+	mkdir -p $(BUILD_DIR_TOOLCHAIN)/linux-dev
+	$(KMAKE) \
+		INSTALL_HDR_PATH="$(BUILD_DIR_TOOLCHAIN)/linux-dev/" \
+		headers_install
+endef
+
+# XXX: the following is needed to build lzma-loader
+ifneq ($(CONFIG_mips)$(CONFIG_mipsel),)
+  define Host/Configure/lzma
+	$(CP) \
+		$(HOST_BUILD_DIR)/arch/mips/include/asm/asm.h \
+		$(HOST_BUILD_DIR)/arch/mips/include/asm/regdef.h \
+		$(HOST_BUILD_DIR)/arch/mips/include/asm/asm-eva.h \
+		$(BUILD_DIR_TOOLCHAIN)/linux-dev/include/asm/
+  endef
+endif
+
+define Host/Configure/post/mips
+	$(call Host/Configure/lzma)
+endef
+
+define Host/Configure/post/mipsel
+	$(call Host/Configure/lzma)
+endef
+
+define Host/Prepare
+	$(call Kernel/Prepare/Default)
+	rm -f $(BUILD_DIR_TOOLCHAIN)/linux
+	ln -s linux-$(LINUX_VERSION) $(BUILD_DIR_TOOLCHAIN)/linux
+	$(SED) 's/@expr length/@-expr length/' $(HOST_BUILD_DIR)/Makefile
+endef
+
+define Host/Configure
+	env
+	yes '' | $(KMAKE) oldconfig
+	$(call Host/Configure/all)
+	$(call Host/Configure/post/$(ARCH))
+endef
+
+define Host/Compile
+endef
+
+define Host/Install
+	$(CP) $(BUILD_DIR_TOOLCHAIN)/linux-dev/* $(TOOLCHAIN_DIR)/
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(BUILD_DIR_TOOLCHAIN)/linux \
+		$(BUILD_DIR_TOOLCHAIN)/linux-dev
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/musl/Config.version b/toolchain/musl/Config.version
new file mode 100644
index 0000000000..537f3d834b
--- /dev/null
+++ b/toolchain/musl/Config.version
@@ -0,0 +1,8 @@
+if USE_MUSL
+
+config MUSL_VERSION
+	string
+	depends on USE_MUSL
+	default "1.1.15"
+
+endif
diff --git a/toolchain/musl/Makefile b/toolchain/musl/Makefile
new file mode 100644
index 0000000000..1533f51a0d
--- /dev/null
+++ b/toolchain/musl/Makefile
@@ -0,0 +1,31 @@
+PATH_PREFIX=.
+
+include ./common.mk
+
+HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.built
+HOST_STAMP_INSTALLED:=$(TOOLCHAIN_DIR)/stamp/.musl_installed
+
+HOST_BUILD_PARALLEL:=1
+
+MUSL_MAKEOPTS = -C $(HOST_BUILD_DIR) \
+	DESTDIR="$(TOOLCHAIN_DIR)/" \
+	LIBCC="$(subst libgcc.a,libgcc_initial.a,$(shell $(TARGET_CC) -print-libgcc-file-name))"
+
+define Host/SetToolchainInfo
+	$(SED) 's,^\(LIBC_TYPE\)=.*,\1=$(PKG_NAME),' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_URL\)=.*,\1=http://www.musl-libc.org/,' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_VERSION\)=.*,\1=$(PKG_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_SO_VERSION\)=.*,\1=$(LIBC_SO_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+endef
+
+define Host/Compile
+	+$(MAKE) $(HOST_JOBS) $(MUSL_MAKEOPTS) all
+endef
+
+define Host/Install
+	$(call Host/SetToolchainInfo)
+	$(MAKE) $(MUSL_MAKEOPTS) DESTDIR="$(TOOLCHAIN_DIR)/" install
+	$(CP) ./include $(TOOLCHAIN_DIR)/
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/musl/common.mk b/toolchain/musl/common.mk
new file mode 100644
index 0000000000..aa1789930e
--- /dev/null
+++ b/toolchain/musl/common.mk
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2012-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+PKG_NAME:=musl
+PKG_VERSION:=$(call qstrip,$(CONFIG_MUSL_VERSION))
+PKG_RELEASE=1
+
+PKG_MD5SUM:=9590a9d47ee64f220b3c12f7afb864ca
+
+PKG_SOURCE_URL:=http://www.musl-libc.org/releases
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+LIBC_SO_VERSION:=$(PKG_VERSION)
+PATCH_DIR:=$(PATH_PREFIX)/patches
+
+HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+include $(INCLUDE_DIR)/hardening.mk
+
+MUSL_CONFIGURE:= \
+	$(TARGET_CONFIGURE_OPTS) \
+	CFLAGS="$(TARGET_CFLAGS)" \
+	CROSS_COMPILE="$(TARGET_CROSS)" \
+	$(HOST_BUILD_DIR)/configure \
+		--prefix=/ \
+		--host=$(GNU_HOST_NAME) \
+		--target=$(REAL_GNU_TARGET_NAME) \
+		--disable-gcc-wrapper \
+		--enable-debug
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	$(if $(strip $(QUILT)), \
+		cd $(HOST_BUILD_DIR); \
+		if $(QUILT_CMD) next >/dev/null 2>&1; then \
+			$(QUILT_CMD) push -a; \
+		fi
+	)
+	ln -snf $(PKG_NAME)-$(PKG_VERSION) $(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+endef
+
+define Host/Configure
+	( cd $(HOST_BUILD_DIR); rm -f config.cache; \
+		$(MUSL_CONFIGURE) \
+	);
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME) \
+		$(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev
+endef
diff --git a/toolchain/musl/include/bits/wordsize.h b/toolchain/musl/include/bits/wordsize.h
new file mode 100644
index 0000000000..2d4cbe8317
--- /dev/null
+++ b/toolchain/musl/include/bits/wordsize.h
@@ -0,0 +1 @@
+#include <sys/user.h>
diff --git a/toolchain/musl/include/features.h b/toolchain/musl/include/features.h
new file mode 100644
index 0000000000..edb8cc72d4
--- /dev/null
+++ b/toolchain/musl/include/features.h
@@ -0,0 +1,48 @@
+#ifndef _FEATURES_H
+#define _FEATURES_H
+
+#ifdef _ALL_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \
+ && !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \
+ && !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__)
+#define _BSD_SOURCE 1
+#define _XOPEN_SOURCE 700
+#endif
+
+#if __STDC_VERSION__ >= 199901L
+#define __restrict restrict
+#elif !defined(__GNUC__)
+#define __restrict
+#endif
+
+#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
+#define __inline inline
+#endif
+
+#if __STDC_VERSION__ >= 201112L
+#elif defined(__GNUC__)
+#define _Noreturn __attribute__((__noreturn__))
+#else
+#define _Noreturn
+#endif
+
+/* Convenience macros to test the versions of glibc and gcc.
+   Use them like this:
+   #if __GNUC_PREREQ (2,8)
+   ... code requiring gcc 2.8 or later ...
+   #endif
+   Note - they won't work for gcc1 or glibc1, since the _MINOR macros
+   were not defined then.  */
+#if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+	((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define __GNUC_PREREQ(maj, min) 0
+#endif
+
+#include <sys/glibc-types.h>
+
+#endif
diff --git a/toolchain/musl/include/sgidefs.h b/toolchain/musl/include/sgidefs.h
new file mode 100644
index 0000000000..74509fdbd0
--- /dev/null
+++ b/toolchain/musl/include/sgidefs.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 1996, 1997, 1998, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ralf Baechle <ralf@gnu.org>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SGIDEFS_H
+#define _SGIDEFS_H	1
+
+/*
+ * A crude hack to stop <asm/sgidefs.h>
+ */
+#undef __ASM_SGIDEFS_H
+#define __ASM_SGIDEFS_H
+
+/*
+ * And remove any damage it might have already done
+ */
+#undef _MIPS_ISA_MIPS1
+#undef _MIPS_ISA_MIPS2
+#undef _MIPS_ISA_MIPS3
+#undef _MIPS_ISA_MIPS4
+#undef _MIPS_ISA_MIPS5
+#undef _MIPS_ISA_MIPS32
+#undef _MIPS_ISA_MIPS64
+
+#undef _MIPS_SIM_ABI32
+#undef _MIPS_SIM_NABI32
+#undef _MIPS_SIM_ABI64
+
+/*
+ * Definitions for the ISA level
+ */
+#define _MIPS_ISA_MIPS1 1
+#define _MIPS_ISA_MIPS2 2
+#define _MIPS_ISA_MIPS3 3
+#define _MIPS_ISA_MIPS4 4
+#define _MIPS_ISA_MIPS5 5
+#define _MIPS_ISA_MIPS32 6
+#define _MIPS_ISA_MIPS64 7
+
+/*
+ * Subprogram calling convention
+ */
+#ifndef _ABIO32
+# define _ABIO32		1
+#endif
+#define _MIPS_SIM_ABI32		_ABIO32
+
+#ifndef _ABIN32
+# define _ABIN32		2
+#endif
+#define _MIPS_SIM_NABI32	_ABIN32
+
+#ifndef _ABI64
+# define _ABI64			3
+#endif
+#define _MIPS_SIM_ABI64		_ABI64
+
+#endif /* sgidefs.h */
diff --git a/toolchain/musl/include/sys/cdefs.h b/toolchain/musl/include/sys/cdefs.h
new file mode 100644
index 0000000000..e9866700d0
--- /dev/null
+++ b/toolchain/musl/include/sys/cdefs.h
@@ -0,0 +1,378 @@
+/* Copyright (C) 1992-2002, 2004, 2005, 2006, 2007, 2009, 2011, 2012
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_SYS_CDEFS_H
+#define	_SYS_CDEFS_H	1
+
+/* We are almost always included from features.h. */
+#ifndef _FEATURES_H
+# include <features.h>
+#endif
+
+/* The GNU libc does not support any K&R compilers or the traditional mode
+   of ISO C compilers anymore.  Check for some of the combinations not
+   anymore supported.  */
+#if defined __GNUC__ && !defined __STDC__
+# error "You need a ISO C conforming compiler to use the glibc headers"
+#endif
+
+/* Some user header file might have defined this before.  */
+#undef	__P
+#undef	__PMT
+
+#ifdef __GNUC__
+
+/* All functions, except those with callbacks or those that
+   synchronize memory, are leaf functions.  */
+# if __GNUC_PREREQ (4, 6) && !defined _LIBC
+#  define __LEAF , __leaf__
+#  define __LEAF_ATTR __attribute__ ((__leaf__))
+# else
+#  define __LEAF
+#  define __LEAF_ATTR
+# endif
+
+/* GCC can always grok prototypes.  For C++ programs we add throw()
+   to help it optimize the function calls.  But this works only with
+   gcc 2.8.x and egcs.  For gcc 3.2 and up we even mark C functions
+   as non-throwing using a function attribute since programs can use
+   the -fexceptions options for C code as well.  */
+# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
+#  define __THROW	__attribute__ ((__nothrow__ __LEAF))
+#  define __THROWNL	__attribute__ ((__nothrow__))
+#  define __NTH(fct)	__attribute__ ((__nothrow__ __LEAF)) fct
+# else
+#  if defined __cplusplus && __GNUC_PREREQ (2,8)
+#   define __THROW	throw ()
+#   define __THROWNL	throw ()
+#   define __NTH(fct)	__LEAF_ATTR fct throw ()
+#  else
+#   define __THROW
+#   define __THROWNL
+#   define __NTH(fct)	fct
+#  endif
+# endif
+
+#else	/* Not GCC.  */
+
+# define __inline		/* No inline functions.  */
+
+# define __THROW
+# define __THROWNL
+# define __NTH(fct)	fct
+
+#endif	/* GCC.  */
+
+/* These two macros are not used in glibc anymore.  They are kept here
+   only because some other projects expect the macros to be defined.  */
+#define __P(args)	args
+#define __PMT(args)	args
+
+/* For these things, GCC behaves the ANSI way normally,
+   and the non-ANSI way under -traditional.  */
+
+#define __CONCAT(x,y)	x ## y
+#define __STRING(x)	#x
+
+/* This is not a typedef so `const __ptr_t' does the right thing.  */
+#define __ptr_t void *
+#define __long_double_t  long double
+
+
+/* C++ needs to know that types and declarations are C, not C++.  */
+#ifdef	__cplusplus
+# define __BEGIN_DECLS	extern "C" {
+# define __END_DECLS	}
+#else
+# define __BEGIN_DECLS
+# define __END_DECLS
+#endif
+
+
+/* The standard library needs the functions from the ISO C90 standard
+   in the std namespace.  At the same time we want to be safe for
+   future changes and we include the ISO C99 code in the non-standard
+   namespace __c99.  The C++ wrapper header take case of adding the
+   definitions to the global namespace.  */
+#if defined __cplusplus && defined _GLIBCPP_USE_NAMESPACES
+# define __BEGIN_NAMESPACE_STD	namespace std {
+# define __END_NAMESPACE_STD	}
+# define __USING_NAMESPACE_STD(name) using std::name;
+# define __BEGIN_NAMESPACE_C99	namespace __c99 {
+# define __END_NAMESPACE_C99	}
+# define __USING_NAMESPACE_C99(name) using __c99::name;
+#else
+/* For compatibility we do not add the declarations into any
+   namespace.  They will end up in the global namespace which is what
+   old code expects.  */
+# define __BEGIN_NAMESPACE_STD
+# define __END_NAMESPACE_STD
+# define __USING_NAMESPACE_STD(name)
+# define __BEGIN_NAMESPACE_C99
+# define __END_NAMESPACE_C99
+# define __USING_NAMESPACE_C99(name)
+#endif
+
+
+/* Support for bounded pointers.  */
+#ifndef __BOUNDED_POINTERS__
+# define __bounded	/* nothing */
+# define __unbounded	/* nothing */
+# define __ptrvalue	/* nothing */
+#endif
+
+
+/* Fortify support.  */
+#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
+#define __bos0(ptr) __builtin_object_size (ptr, 0)
+#define __fortify_function __extern_always_inline __attribute_artificial__
+
+#if __GNUC_PREREQ (4,3)
+# define __warndecl(name, msg) \
+  extern void name (void) __attribute__((__warning__ (msg)))
+# define __warnattr(msg) __attribute__((__warning__ (msg)))
+# define __errordecl(name, msg) \
+  extern void name (void) __attribute__((__error__ (msg)))
+#else
+# define __warndecl(name, msg) extern void name (void)
+# define __warnattr(msg)
+# define __errordecl(name, msg) extern void name (void)
+#endif
+
+/* Support for flexible arrays.  */
+#if __GNUC_PREREQ (2,97)
+/* GCC 2.97 supports C99 flexible array members.  */
+# define __flexarr	[]
+#else
+# ifdef __GNUC__
+#  define __flexarr	[0]
+# else
+#  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#   define __flexarr	[]
+#  else
+/* Some other non-C99 compiler.  Approximate with [1].  */
+#   define __flexarr	[1]
+#  endif
+# endif
+#endif
+
+
+/* __asm__ ("xyz") is used throughout the headers to rename functions
+   at the assembly language level.  This is wrapped by the __REDIRECT
+   macro, in order to support compilers that can do this some other
+   way.  When compilers don't support asm-names at all, we have to do
+   preprocessor tricks instead (which don't have exactly the right
+   semantics, but it's the best we can do).
+
+   Example:
+   int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */
+
+#if defined __GNUC__ && __GNUC__ >= 2
+
+# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))
+# ifdef __cplusplus
+#  define __REDIRECT_NTH(name, proto, alias) \
+     name proto __THROW __asm__ (__ASMNAME (#alias))
+#  define __REDIRECT_NTHNL(name, proto, alias) \
+     name proto __THROWNL __asm__ (__ASMNAME (#alias))
+# else
+#  define __REDIRECT_NTH(name, proto, alias) \
+     name proto __asm__ (__ASMNAME (#alias)) __THROW
+#  define __REDIRECT_NTHNL(name, proto, alias) \
+     name proto __asm__ (__ASMNAME (#alias)) __THROWNL
+# endif
+# define __ASMNAME(cname)  __ASMNAME2 (__USER_LABEL_PREFIX__, cname)
+# define __ASMNAME2(prefix, cname) __STRING (prefix) cname
+
+/*
+#elif __SOME_OTHER_COMPILER__
+
+# define __REDIRECT(name, proto, alias) name proto; \
+	_Pragma("let " #name " = " #alias)
+*/
+#endif
+
+/* GCC has various useful declarations that can be made with the
+   `__attribute__' syntax.  All of the ways we use this do fine if
+   they are omitted for compilers that don't understand it. */
+#if !defined __GNUC__ || __GNUC__ < 2
+# define __attribute__(xyz)	/* Ignore */
+#endif
+
+/* At some point during the gcc 2.96 development the `malloc' attribute
+   for functions was introduced.  We don't want to use it unconditionally
+   (although this would be possible) since it generates warnings.  */
+#if __GNUC_PREREQ (2,96)
+# define __attribute_malloc__ __attribute__ ((__malloc__))
+#else
+# define __attribute_malloc__ /* Ignore */
+#endif
+
+/* At some point during the gcc 2.96 development the `pure' attribute
+   for functions was introduced.  We don't want to use it unconditionally
+   (although this would be possible) since it generates warnings.  */
+#if __GNUC_PREREQ (2,96)
+# define __attribute_pure__ __attribute__ ((__pure__))
+#else
+# define __attribute_pure__ /* Ignore */
+#endif
+
+/* This declaration tells the compiler that the value is constant.  */
+#if __GNUC_PREREQ (2,5)
+# define __attribute_const__ __attribute__ ((__const__))
+#else
+# define __attribute_const__ /* Ignore */
+#endif
+
+/* At some point during the gcc 3.1 development the `used' attribute
+   for functions was introduced.  We don't want to use it unconditionally
+   (although this would be possible) since it generates warnings.  */
+#if __GNUC_PREREQ (3,1)
+# define __attribute_used__ __attribute__ ((__used__))
+# define __attribute_noinline__ __attribute__ ((__noinline__))
+#else
+# define __attribute_used__ __attribute__ ((__unused__))
+# define __attribute_noinline__ /* Ignore */
+#endif
+
+/* gcc allows marking deprecated functions.  */
+#if __GNUC_PREREQ (3,2)
+# define __attribute_deprecated__ __attribute__ ((__deprecated__))
+#else
+# define __attribute_deprecated__ /* Ignore */
+#endif
+
+/* At some point during the gcc 2.8 development the `format_arg' attribute
+   for functions was introduced.  We don't want to use it unconditionally
+   (although this would be possible) since it generates warnings.
+   If several `format_arg' attributes are given for the same function, in
+   gcc-3.0 and older, all but the last one are ignored.  In newer gccs,
+   all designated arguments are considered.  */
+#if __GNUC_PREREQ (2,8)
+# define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x)))
+#else
+# define __attribute_format_arg__(x) /* Ignore */
+#endif
+
+/* At some point during the gcc 2.97 development the `strfmon' format
+   attribute for functions was introduced.  We don't want to use it
+   unconditionally (although this would be possible) since it
+   generates warnings.  */
+#if __GNUC_PREREQ (2,97)
+# define __attribute_format_strfmon__(a,b) \
+  __attribute__ ((__format__ (__strfmon__, a, b)))
+#else
+# define __attribute_format_strfmon__(a,b) /* Ignore */
+#endif
+
+/* The nonull function attribute allows to mark pointer parameters which
+   must not be NULL.  */
+#if __GNUC_PREREQ (3,3)
+# define __nonnull(params) __attribute__ ((__nonnull__ params))
+#else
+# define __nonnull(params)
+#endif
+
+/* If fortification mode, we warn about unused results of certain
+   function calls which can lead to problems.  */
+#if __GNUC_PREREQ (3,4)
+# define __attribute_warn_unused_result__ \
+   __attribute__ ((__warn_unused_result__))
+# if __USE_FORTIFY_LEVEL > 0
+#  define __wur __attribute_warn_unused_result__
+# endif
+#else
+# define __attribute_warn_unused_result__ /* empty */
+#endif
+#ifndef __wur
+# define __wur /* Ignore */
+#endif
+
+/* Forces a function to be always inlined.  */
+#if __GNUC_PREREQ (3,2)
+# define __always_inline __inline __attribute__ ((__always_inline__))
+#else
+# define __always_inline __inline
+#endif
+
+/* Associate error messages with the source location of the call site rather
+   than with the source location inside the function.  */
+#if __GNUC_PREREQ (4,3)
+# define __attribute_artificial__ __attribute__ ((__artificial__))
+#else
+# define __attribute_artificial__ /* Ignore */
+#endif
+
+/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+   inline semantics, unless -fgnu89-inline is used.  */
+#if !defined __cplusplus || __GNUC_PREREQ (4,3)
+# if defined __GNUC_STDC_INLINE__ || defined __cplusplus
+#  define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
+#  define __extern_always_inline \
+  extern __always_inline __attribute__ ((__gnu_inline__))
+# else
+#  define __extern_inline extern __inline
+#  define __extern_always_inline extern __always_inline
+# endif
+#endif
+
+/* GCC 4.3 and above allow passing all anonymous arguments of an
+   __extern_always_inline function to some other vararg function.  */
+#if __GNUC_PREREQ (4,3)
+# define __va_arg_pack() __builtin_va_arg_pack ()
+# define __va_arg_pack_len() __builtin_va_arg_pack_len ()
+#endif
+
+/* It is possible to compile containing GCC extensions even if GCC is
+   run in pedantic mode if the uses are carefully marked using the
+   `__extension__' keyword.  But this is not generally available before
+   version 2.8.  */
+#if !__GNUC_PREREQ (2,8)
+# define __extension__		/* Ignore */
+#endif
+
+/* __restrict is known in EGCS 1.2 and above. */
+#if !__GNUC_PREREQ (2,92)
+# define __restrict	/* Ignore */
+#endif
+
+/* ISO C99 also allows to declare arrays as non-overlapping.  The syntax is
+     array_name[restrict]
+   GCC 3.1 supports this.  */
+#if __GNUC_PREREQ (3,1) && !defined __GNUG__
+# define __restrict_arr	__restrict
+#else
+# ifdef __GNUC__
+#  define __restrict_arr	/* Not supported in old GCC.  */
+# else
+#  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#   define __restrict_arr	restrict
+#  else
+/* Some other non-C99 compiler.  */
+#   define __restrict_arr	/* Not supported.  */
+#  endif
+# endif
+#endif
+
+#if __GNUC__ >= 3
+# define __glibc_unlikely(cond) __builtin_expect((cond), 0)
+#else
+# define __glibc_unlikely(cond) (cond)
+#endif
+
+#endif	 /* sys/cdefs.h */
diff --git a/toolchain/musl/include/sys/glibc-types.h b/toolchain/musl/include/sys/glibc-types.h
new file mode 100644
index 0000000000..fa0684ced2
--- /dev/null
+++ b/toolchain/musl/include/sys/glibc-types.h
@@ -0,0 +1,35 @@
+#ifndef __MUSL_GLIBC_TYPES_H
+#define __MUSL_GLIBC_TYPES_H
+
+#include <sys/cdefs.h>
+
+/* Convenience types.  */
+typedef unsigned char __u_char;
+typedef unsigned short int __u_short;
+typedef unsigned int __u_int;
+typedef unsigned long int __u_long;
+
+/* Fixed-size types, underlying types depend on word size and compiler.  */
+typedef signed char __int8_t;
+typedef unsigned char __uint8_t;
+typedef signed short int __int16_t;
+typedef unsigned short int __uint16_t;
+typedef signed int __int32_t;
+typedef unsigned int __uint32_t;
+#if __WORDSIZE == 64
+typedef signed long int __int64_t;
+typedef unsigned long int __uint64_t;
+#else
+__extension__ typedef signed long long int __int64_t;
+__extension__ typedef unsigned long long int __uint64_t;
+#endif
+
+#define __off64_t off_t
+#define __loff_t off_t
+typedef char *__caddr_t;
+#define __locale_t locale_t
+
+#define __gid_t gid_t
+#define __uid_t uid_t
+
+#endif
diff --git a/toolchain/musl/include/sys/queue.h b/toolchain/musl/include/sys/queue.h
new file mode 100644
index 0000000000..daf4553d33
--- /dev/null
+++ b/toolchain/musl/include/sys/queue.h
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef	_SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list.  Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction.  Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+#define	LIST_INIT(head) do {						\
+	(head)->lh_first = NULL;					\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	(elm)->field.le_next = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &(elm)->field.le_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev = 			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = ((head)->lh_first);				\
+		(var);							\
+		(var) = ((var)->field.le_next))
+
+/*
+ * List access methods.
+ */
+#define	LIST_EMPTY(head)		((head)->lh_first == NULL)
+#define	LIST_FIRST(head)		((head)->lh_first)
+#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
+
+
+/*
+ * Singly-linked List definitions.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_INIT(head) do {						\
+	(head)->slh_first = NULL;					\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	(slistelm)->field.sle_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.sle_next = (head)->slh_first;			\
+	(head)->slh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if ((head)->slh_first == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = (head)->slh_first;		\
+		while(curelm->field.sle_next != (elm))			\
+			curelm = curelm->field.sle_next;		\
+		curelm->field.sle_next =				\
+		    curelm->field.sle_next->field.sle_next;		\
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
+
+/*
+ * Singly-linked List access methods.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+#define	SLIST_FIRST(head)	((head)->slh_first)
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)					\
+struct name {								\
+	struct type *stqh_first;	/* first element */			\
+	struct type **stqh_last;	/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_INIT(head) do {						\
+	(head)->stqh_first = NULL;					\
+	(head)->stqh_last = &(head)->stqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)	\
+		(head)->stqh_last = &(elm)->field.stqe_next;		\
+	(head)->stqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.stqe_next = NULL;					\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &(elm)->field.stqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
+		(head)->stqh_last = &(elm)->field.stqe_next;		\
+	(listelm)->field.stqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
+		(head)->stqh_last = &(head)->stqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if ((head)->stqh_first == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->stqh_first;		\
+		while (curelm->field.stqe_next != (elm))			\
+			curelm = curelm->field.stqe_next;		\
+		if ((curelm->field.stqe_next =				\
+			curelm->field.stqe_next->field.stqe_next) == NULL) \
+			    (head)->stqh_last = &(curelm)->field.stqe_next; \
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->stqh_first);				\
+		(var);							\
+		(var) = ((var)->field.stqe_next))
+
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (/*CONSTCOND*/0)
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+
+/*
+ * Simple queue definitions.
+ */
+#define	SIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqh_first;	/* first element */			\
+	struct type **sqh_last;	/* addr of last next element */		\
+}
+
+#define	SIMPLEQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).sqh_first }
+
+#define	SIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqe_next;	/* next element */			\
+}
+
+/*
+ * Simple queue functions.
+ */
+#define	SIMPLEQ_INIT(head) do {						\
+	(head)->sqh_first = NULL;					\
+	(head)->sqh_last = &(head)->sqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(head)->sqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqe_next = NULL;					\
+	*(head)->sqh_last = (elm);					\
+	(head)->sqh_last = &(elm)->field.sqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(listelm)->field.sqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_REMOVE_HEAD(head, field) do {				\
+	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+		(head)->sqh_last = &(head)->sqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_REMOVE(head, elm, type, field) do {			\
+	if ((head)->sqh_first == (elm)) {				\
+		SIMPLEQ_REMOVE_HEAD((head), field);			\
+	} else {							\
+		struct type *curelm = (head)->sqh_first;		\
+		while (curelm->field.sqe_next != (elm))			\
+			curelm = curelm->field.sqe_next;		\
+		if ((curelm->field.sqe_next =				\
+			curelm->field.sqe_next->field.sqe_next) == NULL) \
+			    (head)->sqh_last = &(curelm)->field.sqe_next; \
+	}								\
+} while (/*CONSTCOND*/0)
+
+#define	SIMPLEQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->sqh_first);				\
+		(var);							\
+		(var) = ((var)->field.sqe_next))
+
+/*
+ * Simple queue access methods.
+ */
+#define	SIMPLEQ_EMPTY(head)		((head)->sqh_first == NULL)
+#define	SIMPLEQ_FIRST(head)		((head)->sqh_first)
+#define	SIMPLEQ_NEXT(elm, field)	((elm)->field.sqe_next)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define	_TAILQ_HEAD(name, type, qual)					\
+struct name {								\
+	qual type *tqh_first;		/* first element */		\
+	qual type *qual *tqh_last;	/* addr of last next element */	\
+}
+#define TAILQ_HEAD(name, type)	_TAILQ_HEAD(name, struct type,)
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	_TAILQ_ENTRY(type, qual)					\
+struct {								\
+	qual type *tqe_next;		/* next element */		\
+	qual type *qual *tqe_prev;	/* address of previous next element */\
+}
+#define TAILQ_ENTRY(type)	_TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_INIT(head) do {						\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+} while (/*CONSTCOND*/0)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = ((head)->tqh_first);				\
+		(var);							\
+		(var) = ((var)->field.tqe_next))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));	\
+		(var);							\
+		(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+	}								\
+} while (/*CONSTCOND*/0)
+
+/*
+ * Tail queue access methods.
+ */
+#define	TAILQ_EMPTY(head)		((head)->tqh_first == NULL)
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+
+#define	TAILQ_LAST(head, headname) \
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define	TAILQ_PREV(elm, headname, field) \
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+
+/*
+ * Circular queue definitions.
+ */
+#define	CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define	CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ (void *)&head, (void *)&head }
+
+#define	CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_INIT(head) do {						\
+	(head)->cqh_first = (void *)(head);				\
+	(head)->cqh_last = (void *)(head);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == (void *)(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == (void *)(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = (void *)(head);				\
+	if ((head)->cqh_last == (void *)(head))				\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.cqe_next = (void *)(head);				\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == (void *)(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	if ((elm)->field.cqe_next == (void *)(head))			\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == (void *)(head))			\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+} while (/*CONSTCOND*/0)
+
+#define	CIRCLEQ_FOREACH(var, head, field)				\
+	for ((var) = ((head)->cqh_first);				\
+		(var) != (const void *)(head);				\
+		(var) = ((var)->field.cqe_next))
+
+#define	CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for ((var) = ((head)->cqh_last);				\
+		(var) != (const void *)(head);				\
+		(var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define	CIRCLEQ_EMPTY(head)		((head)->cqh_first == (void *)(head))
+#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
+#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
+#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
+#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field)				\
+	(((elm)->field.cqe_next == (void *)(head))			\
+	    ? ((head)->cqh_first)					\
+	    : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field)				\
+	(((elm)->field.cqe_prev == (void *)(head))			\
+	    ? ((head)->cqh_last)					\
+	    : (elm->field.cqe_prev))
+
+#endif	/* sys/queue.h */
diff --git a/toolchain/musl/patches/010-fix-regression-in-tcsetattr-on-all-mips-archs.patch b/toolchain/musl/patches/010-fix-regression-in-tcsetattr-on-all-mips-archs.patch
new file mode 100644
index 0000000000..f3def26b2a
--- /dev/null
+++ b/toolchain/musl/patches/010-fix-regression-in-tcsetattr-on-all-mips-archs.patch
@@ -0,0 +1,67 @@
+From cff5747c74c41b22f1ce1340978b1c226a8cdf32 Mon Sep 17 00:00:00 2001
+From: Rich Felker <dalias@aerifal.cx>
+Date: Wed, 13 Jul 2016 15:04:30 -0400
+Subject: [PATCH] fix regression in tcsetattr on all mips archs
+
+revert commit 8c316e9e49d37ad92c2e7493e16166a2afca419f. it was wrong
+and does not match how the kernel API works.
+---
+ arch/mips/bits/termios.h    | 6 +++---
+ arch/mips64/bits/termios.h  | 6 +++---
+ arch/mipsn32/bits/termios.h | 6 +++---
+ 4 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/arch/mips/bits/termios.h b/arch/mips/bits/termios.h
+index f559f76..6a1205d 100644
+--- a/arch/mips/bits/termios.h
++++ b/arch/mips/bits/termios.h
+@@ -141,9 +141,9 @@ struct termios {
+ #define TCOFLUSH  1
+ #define TCIOFLUSH 2
+ 
+-#define TCSANOW 0x540e
+-#define TCSADRAIN 0x540f
+-#define TCSAFLUSH 0x5410
++#define TCSANOW   0
++#define TCSADRAIN 1
++#define TCSAFLUSH 2
+ 
+ #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+ #define EXTA    0000016
+diff --git a/arch/mips64/bits/termios.h b/arch/mips64/bits/termios.h
+index f559f76..6a1205d 100644
+--- a/arch/mips64/bits/termios.h
++++ b/arch/mips64/bits/termios.h
+@@ -141,9 +141,9 @@ struct termios {
+ #define TCOFLUSH  1
+ #define TCIOFLUSH 2
+ 
+-#define TCSANOW 0x540e
+-#define TCSADRAIN 0x540f
+-#define TCSAFLUSH 0x5410
++#define TCSANOW   0
++#define TCSADRAIN 1
++#define TCSAFLUSH 2
+ 
+ #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+ #define EXTA    0000016
+diff --git a/arch/mipsn32/bits/termios.h b/arch/mipsn32/bits/termios.h
+index f559f76..6a1205d 100644
+--- a/arch/mipsn32/bits/termios.h
++++ b/arch/mipsn32/bits/termios.h
+@@ -141,9 +141,9 @@ struct termios {
+ #define TCOFLUSH  1
+ #define TCIOFLUSH 2
+ 
+-#define TCSANOW 0x540e
+-#define TCSADRAIN 0x540f
+-#define TCSAFLUSH 0x5410
++#define TCSANOW   0
++#define TCSADRAIN 1
++#define TCSAFLUSH 2
+ 
+ #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+ #define EXTA    0000016
+-- 
+2.8.1
+
diff --git a/toolchain/musl/patches/040-Add-format-attribute-to-some-function-declarations.patch b/toolchain/musl/patches/040-Add-format-attribute-to-some-function-declarations.patch
new file mode 100644
index 0000000000..c495d67e08
--- /dev/null
+++ b/toolchain/musl/patches/040-Add-format-attribute-to-some-function-declarations.patch
@@ -0,0 +1,197 @@
+From e6683d001a95d7c3d4d992496f00f77e01fcd268 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 22 Nov 2015 15:04:23 +0100
+Subject: [PATCH v2] Add format attribute to some function declarations
+
+GCC and Clang are able to check the format arguments given to a
+function and warn the user if there is a error in the format arguments
+or if there is a potential uncontrolled format string security problem
+in the code. GCC does this automatically for some functions like
+printf(), but it is also possible to annotate other functions in a way
+that it will check them too. This feature is used by glibc for many
+functions. This patch adds the attribute to the some functions of musl
+expect for these functions where gcc automatically adds it.
+
+GCC automatically adds checks for these functions: printf, fprintf,
+sprintf, scanf, fscanf, sscanf, strftime, vprintf, vfprintf and
+vsprintf.
+
+The documentation from gcc is here:
+https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
+
+The documentation from Clang is here:
+http://clang.llvm.org/docs/AttributeReference.html#format-gnu-format
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ include/err.h      | 26 +++++++++++++++++---------
+ include/monetary.h | 12 ++++++++++--
+ include/stdio.h    | 29 ++++++++++++++++++++---------
+ include/syslog.h   | 12 ++++++++++--
+ 4 files changed, 57 insertions(+), 22 deletions(-)
+
+--- a/include/err.h
++++ b/include/err.h
+@@ -8,15 +8,23 @@
+ extern "C" {
+ #endif
+ 
+-void warn(const char *, ...);
+-void vwarn(const char *, va_list);
+-void warnx(const char *, ...);
+-void vwarnx(const char *, va_list);
++#if __GNUC__ >= 3
++#define __fp(x, y) __attribute__ ((__format__ (__printf__, x, y)))
++#else
++#define __fp(x, y)
++#endif
+ 
+-_Noreturn void err(int, const char *, ...);
+-_Noreturn void verr(int, const char *, va_list);
+-_Noreturn void errx(int, const char *, ...);
+-_Noreturn void verrx(int, const char *, va_list);
++void warn(const char *, ...) __fp(1, 2);
++void vwarn(const char *, va_list) __fp(1, 0);
++void warnx(const char *, ...) __fp(1, 2);
++void vwarnx(const char *, va_list) __fp(1, 0);
++
++_Noreturn void err(int, const char *, ...) __fp(2, 3);
++_Noreturn void verr(int, const char *, va_list) __fp(2, 0);
++_Noreturn void errx(int, const char *, ...) __fp(2, 3);
++_Noreturn void verrx(int, const char *, va_list) __fp(2, 0);
++
++#undef __fp
+ 
+ #ifdef __cplusplus
+ }
+--- a/include/monetary.h
++++ b/include/monetary.h
+@@ -13,8 +13,16 @@ extern "C" {
+ 
+ #include <bits/alltypes.h>
+ 
+-ssize_t strfmon(char *__restrict, size_t, const char *__restrict, ...);
+-ssize_t strfmon_l(char *__restrict, size_t, locale_t, const char *__restrict, ...);
++#if __GNUC__ >= 3
++#define __fsfm(x, y) __attribute__ ((__format__ (__strfmon__, x, y)))
++#else
++#define __fsfm(x, y)
++#endif
++
++ssize_t strfmon(char *__restrict, size_t, const char *__restrict, ...) __fsfm(3, 4);
++ssize_t strfmon_l(char *__restrict, size_t, locale_t, const char *__restrict, ...) __fsfm(4, 5);
++
++#undef __fsfm
+ 
+ #ifdef __cplusplus
+ }
+--- a/include/stdio.h
++++ b/include/stdio.h
+@@ -21,6 +21,14 @@ extern "C" {
+ 
+ #include <bits/alltypes.h>
+ 
++#if __GNUC__ >= 3
++#define __fp(x, y) __attribute__ ((__format__ (__printf__, x, y)))
++#define __fs(x, y) __attribute__ ((__format__ (__scanf__, x, y)))
++#else
++#define __fp(x, y)
++#define __fs(x, y)
++#endif
++
+ #ifdef __cplusplus
+ #define NULL 0L
+ #else
+@@ -102,19 +110,19 @@ int puts(const char *);
+ int printf(const char *__restrict, ...);
+ int fprintf(FILE *__restrict, const char *__restrict, ...);
+ int sprintf(char *__restrict, const char *__restrict, ...);
+-int snprintf(char *__restrict, size_t, const char *__restrict, ...);
++int snprintf(char *__restrict, size_t, const char *__restrict, ...) __fp(3, 4);
+ 
+ int vprintf(const char *__restrict, __isoc_va_list);
+ int vfprintf(FILE *__restrict, const char *__restrict, __isoc_va_list);
+ int vsprintf(char *__restrict, const char *__restrict, __isoc_va_list);
+-int vsnprintf(char *__restrict, size_t, const char *__restrict, __isoc_va_list);
++int vsnprintf(char *__restrict, size_t, const char *__restrict, __isoc_va_list) __fp(3, 0);
+ 
+ int scanf(const char *__restrict, ...);
+ int fscanf(FILE *__restrict, const char *__restrict, ...);
+ int sscanf(const char *__restrict, const char *__restrict, ...);
+-int vscanf(const char *__restrict, __isoc_va_list);
+-int vfscanf(FILE *__restrict, const char *__restrict, __isoc_va_list);
+-int vsscanf(const char *__restrict, const char *__restrict, __isoc_va_list);
++int vscanf(const char *__restrict, __isoc_va_list) __fs(1, 0);
++int vfscanf(FILE *__restrict, const char *__restrict, __isoc_va_list) __fs(2, 0);
++int vsscanf(const char *__restrict, const char *__restrict, __isoc_va_list) __fs(2, 0);
+ 
+ void perror(const char *);
+ 
+@@ -135,8 +143,8 @@ int pclose(FILE *);
+ int fileno(FILE *);
+ int fseeko(FILE *, off_t, int);
+ off_t ftello(FILE *);
+-int dprintf(int, const char *__restrict, ...);
+-int vdprintf(int, const char *__restrict, __isoc_va_list);
++int dprintf(int, const char *__restrict, ...) __fp(2, 3);
++int vdprintf(int, const char *__restrict, __isoc_va_list) __fp(2, 0);
+ void flockfile(FILE *);
+ int ftrylockfile(FILE *);
+ void funlockfile(FILE *);
+@@ -175,8 +183,8 @@ int fileno_unlocked(FILE *);
+ int getw(FILE *);
+ int putw(int, FILE *);
+ char *fgetln(FILE *, size_t *);
+-int asprintf(char **, const char *, ...);
+-int vasprintf(char **, const char *, __isoc_va_list);
++int asprintf(char **, const char *, ...) __fp(2, 3);
++int vasprintf(char **, const char *, __isoc_va_list) __fp(2, 0);
+ #endif
+ 
+ #ifdef _GNU_SOURCE
+@@ -184,6 +192,9 @@ char *fgets_unlocked(char *, int, FILE *
+ int fputs_unlocked(const char *, FILE *);
+ #endif
+ 
++#undef __fp
++#undef __fs
++
+ #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
+ #define tmpfile64 tmpfile
+ #define fopen64 fopen
+--- a/include/syslog.h
++++ b/include/syslog.h
+@@ -56,16 +56,22 @@ extern "C" {
+ #define LOG_NOWAIT 0x10
+ #define LOG_PERROR 0x20
+ 
++#if __GNUC__ >= 3
++#define __fp(x, y) __attribute__ ((__format__ (__printf__, x, y)))
++#else
++#define __fp(x, y)
++#endif
++
+ void closelog (void);
+ void openlog (const char *, int, int);
+ int setlogmask (int);
+-void syslog (int, const char *, ...);
++void syslog (int, const char *, ...) __fp(2, 3);
+ 
+ #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+ #define _PATH_LOG "/dev/log"
+ #define __NEED_va_list
+ #include <bits/alltypes.h>
+-void vsyslog (int, const char *, va_list);
++void vsyslog (int, const char *, va_list) __fp(2, 0);
+ #if defined(SYSLOG_NAMES)
+ #define	INTERNAL_NOPRI 0x10
+ #define	INTERNAL_MARK (LOG_NFACILITIES<<3)
+@@ -93,6 +99,8 @@ typedef struct {
+ #endif
+ #endif
+ 
++#undef __fp
++
+ #ifdef __cplusplus
+ }
+ #endif
diff --git a/toolchain/musl/patches/100-add_glob_onlydir.patch b/toolchain/musl/patches/100-add_glob_onlydir.patch
new file mode 100644
index 0000000000..db0bc22afa
--- /dev/null
+++ b/toolchain/musl/patches/100-add_glob_onlydir.patch
@@ -0,0 +1,11 @@
+--- a/include/glob.h
++++ b/include/glob.h
+@@ -31,6 +31,8 @@ void globfree(glob_t *);
+ #define GLOB_NOESCAPE 0x40
+ #define	GLOB_PERIOD   0x80
+ 
++#define GLOB_ONLYDIR	0x100
++
+ #define GLOB_NOSPACE 1
+ #define GLOB_ABORTED 2
+ #define GLOB_NOMATCH 3
diff --git a/toolchain/musl/patches/110-read_timezone_from_fs.patch b/toolchain/musl/patches/110-read_timezone_from_fs.patch
new file mode 100644
index 0000000000..b4349e7367
--- /dev/null
+++ b/toolchain/musl/patches/110-read_timezone_from_fs.patch
@@ -0,0 +1,28 @@
+--- a/src/time/__tz.c
++++ b/src/time/__tz.c
+@@ -23,6 +23,9 @@ static int r0[5], r1[5];
+ static const unsigned char *zi, *trans, *index, *types, *abbrevs, *abbrevs_end;
+ static size_t map_size;
+ 
++static const char *tzfile;
++static size_t tzfile_size;
++
+ static char old_tz_buf[32];
+ static char *old_tz = old_tz_buf;
+ static size_t old_tz_size = sizeof old_tz_buf;
+@@ -125,6 +128,15 @@ static void do_tzset()
+ 		"/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0";
+ 
+ 	s = getenv("TZ");
++
++	/* if TZ is empty try to read it from /etc/TZ */
++	if (!s || !*s) {
++		if (tzfile)
++			__munmap((void*)tzfile, tzfile_size);
++
++		s = tzfile = (void *)__map_file("/etc/TZ", &tzfile_size);
++	}
++
+ 	if (!s) s = "/etc/localtime";
+ 	if (!*s) s = __gmt;
+ 
diff --git a/toolchain/musl/patches/200-add_libssp_nonshared.patch b/toolchain/musl/patches/200-add_libssp_nonshared.patch
new file mode 100644
index 0000000000..218ca41402
--- /dev/null
+++ b/toolchain/musl/patches/200-add_libssp_nonshared.patch
@@ -0,0 +1,50 @@
+From 7ec87fbbc3cac99b4173d082dd6195f47c9a32e7 Mon Sep 17 00:00:00 2001
+From: Steven Barth <steven@midlink.org>
+Date: Mon, 22 Jun 2015 11:01:56 +0200
+Subject: [PATCH] Add libssp_nonshared.a so GCC's is not needed
+
+Signed-off-by: Steven Barth <steven@midlink.org>
+---
+ Makefile                                  | 10 ++++++++--
+ libssp_nonshared/__stack_chk_fail_local.c |  2 ++
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+ create mode 100644 libssp_nonshared/__stack_chk_fail_local.c
+
+--- a/Makefile
++++ b/Makefile
+@@ -66,7 +66,7 @@ CRT_LIBS = $(addprefix lib/,$(notdir $(C
+ STATIC_LIBS = lib/libc.a
+ SHARED_LIBS = lib/libc.so
+ TOOL_LIBS = lib/musl-gcc.specs
+-ALL_LIBS = $(CRT_LIBS) $(STATIC_LIBS) $(SHARED_LIBS) $(EMPTY_LIBS) $(TOOL_LIBS)
++ALL_LIBS = $(CRT_LIBS) $(STATIC_LIBS) $(SHARED_LIBS) $(EMPTY_LIBS) $(TOOL_LIBS) lib/libssp_nonshared.a
+ ALL_TOOLS = obj/musl-gcc
+ 
+ WRAPCC_GCC = gcc
+@@ -129,7 +129,8 @@ NOSSP_SRCS = $(wildcard crt/*.c) \
+ 	src/thread/__set_thread_area.c src/thread/$(ARCH)/__set_thread_area.c \
+ 	src/string/memset.c src/string/$(ARCH)/memset.c \
+ 	src/string/memcpy.c src/string/$(ARCH)/memcpy.c \
+-	ldso/dlstart.c ldso/dynlink.c
++	ldso/dlstart.c ldso/dynlink.c \
++	src/libssp_nonshared/__stack_chk_fail_local.c
+ $(NOSSP_SRCS:%.c=obj/%.o) $(NOSSP_SRCS:%.c=obj/%.lo): CFLAGS_ALL += $(CFLAGS_NOSSP)
+ 
+ $(CRT_OBJS): CFLAGS_ALL += -DCRT
+@@ -172,6 +173,11 @@ lib/libc.a: $(AOBJS)
+ 	$(AR) rc $@ $(AOBJS)
+ 	$(RANLIB) $@
+ 
++lib/libssp_nonshared.a: obj/src/libssp_nonshared/__stack_chk_fail_local.o
++	rm -f $@
++	$(AR) rc $@ $<
++	$(RANLIB) $@
++
+ $(EMPTY_LIBS):
+ 	rm -f $@
+ 	$(AR) rc $@
+--- /dev/null
++++ b/src/libssp_nonshared/__stack_chk_fail_local.c
+@@ -0,0 +1,2 @@
++#include "atomic.h"
++void __attribute__((visibility ("hidden"))) __stack_chk_fail_local(void) { a_crash(); }
diff --git a/toolchain/musl/patches/300-relative.patch b/toolchain/musl/patches/300-relative.patch
new file mode 100644
index 0000000000..e34e60a09d
--- /dev/null
+++ b/toolchain/musl/patches/300-relative.patch
@@ -0,0 +1,11 @@
+--- a/Makefile
++++ b/Makefile
+@@ -215,7 +215,7 @@ $(DESTDIR)$(includedir)/%: $(srcdir)/inc
+ 	$(INSTALL) -D -m 644 $< $@
+ 
+ $(DESTDIR)$(LDSO_PATHNAME): $(DESTDIR)$(libdir)/libc.so
+-	$(INSTALL) -D -l $(libdir)/libc.so $@ || true
++	$(INSTALL) -D -l libc.so $@ || true
+ 
+ install-libs: $(ALL_LIBS:lib/%=$(DESTDIR)$(libdir)/%) $(if $(SHARED_LIBS),$(DESTDIR)$(LDSO_PATHNAME),)
+ 
diff --git a/toolchain/musl/patches/400-fix_quoted_timezone.patch b/toolchain/musl/patches/400-fix_quoted_timezone.patch
new file mode 100644
index 0000000000..79afa4a63b
--- /dev/null
+++ b/toolchain/musl/patches/400-fix_quoted_timezone.patch
@@ -0,0 +1,11 @@
+--- a/src/time/__tz.c
++++ b/src/time/__tz.c
+@@ -87,7 +87,7 @@
+ 	int i;
+ 	if (**p == '<') {
+ 		++*p;
+-		for (i=0; **p!='>' && i<TZNAME_MAX; i++)
++		for (i=0; (*p)[i]!='>' && i<TZNAME_MAX; i++)
+ 			d[i] = (*p)[i];
+ 		++*p;
+ 	} else {
diff --git a/toolchain/musl/patches/900-iconv_size_hack.patch b/toolchain/musl/patches/900-iconv_size_hack.patch
new file mode 100644
index 0000000000..343915fb06
--- /dev/null
+++ b/toolchain/musl/patches/900-iconv_size_hack.patch
@@ -0,0 +1,68 @@
+--- a/src/locale/iconv.c
++++ b/src/locale/iconv.c
+@@ -39,6 +39,7 @@ static const unsigned char charmaps[] =
+ "ucs4\0ucs4be\0utf32\0utf32be\0\0\300"
+ "ucs4le\0utf32le\0\0\303"
+ "ascii\0usascii\0iso646\0iso646us\0\0\307"
++#ifdef FULL_ICONV
+ "eucjp\0\0\320"
+ "shiftjis\0sjis\0\0\321"
+ "gb18030\0\0\330"
+@@ -46,6 +47,7 @@ static const unsigned char charmaps[] =
+ "gb2312\0\0\332"
+ "big5\0bigfive\0cp950\0big5hkscs\0\0\340"
+ "euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
++#endif
+ #include "codepages.h"
+ ;
+ 
+@@ -53,6 +55,7 @@ static const unsigned short legacy_chars
+ #include "legacychars.h"
+ };
+ 
++#ifdef FULL_ICONV
+ static const unsigned short jis0208[84][94] = {
+ #include "jis0208.h"
+ };
+@@ -72,6 +75,7 @@ static const unsigned short hkscs[] = {
+ static const unsigned short ksc[93][94] = {
+ #include "ksc.h"
+ };
++#endif
+ 
+ static int fuzzycmp(const unsigned char *a, const unsigned char *b)
+ {
+@@ -216,6 +220,7 @@ size_t iconv(iconv_t cd0, char **restric
+ 				c = ((c-0xd7c0)<<10) + (d-0xdc00);
+ 			}
+ 			break;
++#ifdef FULL_ICONV
+ 		case SHIFT_JIS:
+ 			if (c-0xa1 <= 0xdf-0xa1) {
+ 				c += 0xff61-0xa1;
+@@ -362,6 +367,7 @@ size_t iconv(iconv_t cd0, char **restric
+ 			c = ksc[c][d];
+ 			if (!c) goto ilseq;
+ 			break;
++#endif
+ 		default:
+ 			if (c < 128+type) break;
+ 			c -= 128+type;
+--- a/src/locale/codepages.h
++++ b/src/locale/codepages.h
+@@ -118,6 +118,7 @@
+ "\0\0\0\100\15\0\344\0\0\0\0\0\0\0\0\0\0\0\0\0\103\270\1\0\0\0\340\1\200\40"
+ "\230\0\0\0\0\0\44\341\12\0"
+ 
++#ifdef FULL_ICONV
+ "cp1250\0"
+ "windows1250\0"
+ "\0\0"
+@@ -214,6 +215,7 @@
+ "\0\0\0\0\0\0\0\0\0\15\0\0\0\0\0\0\0\0\0\0\266\0\0\0\0\102\0\220\13\0"
+ "\0\234\2\0\0\0\0\0\0\0\0\244\202\13\0\0\0\0\100\15\0\0\0\0\0\0\0\0\0\0"
+ "\267\0\0\0\0\103\0\240\13\0\0\240\2\0\0\0\0\0\0\0\0\250\62\45\0"
++#endif
+ 
+ "koi8r\0"
+ "\0\0"
diff --git a/toolchain/musl/patches/901-crypt_size_hack.patch b/toolchain/musl/patches/901-crypt_size_hack.patch
new file mode 100644
index 0000000000..8cd7b1989c
--- /dev/null
+++ b/toolchain/musl/patches/901-crypt_size_hack.patch
@@ -0,0 +1,60 @@
+--- a/src/crypt/crypt_r.c
++++ b/src/crypt/crypt_r.c
+@@ -19,12 +19,6 @@ char *__crypt_r(const char *key, const c
+ 	if (salt[0] == '$' && salt[1] && salt[2]) {
+ 		if (salt[1] == '1' && salt[2] == '$')
+ 			return __crypt_md5(key, salt, output);
+-		if (salt[1] == '2' && salt[3] == '$')
+-			return __crypt_blowfish(key, salt, output);
+-		if (salt[1] == '5' && salt[2] == '$')
+-			return __crypt_sha256(key, salt, output);
+-		if (salt[1] == '6' && salt[2] == '$')
+-			return __crypt_sha512(key, salt, output);
+ 	}
+ 	return __crypt_des(key, salt, output);
+ }
+--- a/src/crypt/crypt_sha512.c
++++ b/src/crypt/crypt_sha512.c
+@@ -12,6 +12,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdint.h>
++#if 0
+ 
+ /* public domain sha512 implementation based on fips180-3 */
+ /* >=2^64 bits messages are not supported (about 2000 peta bytes) */
+@@ -369,3 +370,4 @@ char *__crypt_sha512(const char *key, co
+ 		return "*";
+ 	return p;
+ }
++#endif
+--- a/src/crypt/crypt_blowfish.c
++++ b/src/crypt/crypt_blowfish.c
+@@ -50,6 +50,7 @@
+ #include <string.h>
+ #include <stdint.h>
+ 
++#if 0
+ typedef uint32_t BF_word;
+ typedef int32_t BF_word_signed;
+ 
+@@ -796,3 +797,4 @@ char *__crypt_blowfish(const char *key,
+ 
+ 	return "*";
+ }
++#endif
+--- a/src/crypt/crypt_sha256.c
++++ b/src/crypt/crypt_sha256.c
+@@ -13,6 +13,7 @@
+ #include <string.h>
+ #include <stdint.h>
+ 
++#if 0
+ /* public domain sha256 implementation based on fips180-3 */
+ 
+ struct sha256 {
+@@ -320,3 +321,4 @@ char *__crypt_sha256(const char *key, co
+ 		return "*";
+ 	return p;
+ }
++#endif
diff --git a/toolchain/uClibc/Config.in b/toolchain/uClibc/Config.in
new file mode 100644
index 0000000000..3bcb0037e9
--- /dev/null
+++ b/toolchain/uClibc/Config.in
@@ -0,0 +1,6 @@
+# Debug version.
+
+config UCLIBC_ENABLE_DEBUG
+	bool "Build with debug information"
+	depends on TOOLCHAINOPTS && USE_UCLIBC && !EXTERNAL_TOOLCHAIN
+	default n
diff --git a/toolchain/uClibc/Config.version b/toolchain/uClibc/Config.version
new file mode 100644
index 0000000000..3c1c54d61e
--- /dev/null
+++ b/toolchain/uClibc/Config.version
@@ -0,0 +1,9 @@
+config UCLIBC_VERSION
+	string
+	depends on USE_UCLIBC
+	default "1.0.14"
+
+config UCLIBC_VERSION_NG
+	bool
+	depends on USE_UCLIBC
+	default y
diff --git a/toolchain/uClibc/Makefile b/toolchain/uClibc/Makefile
new file mode 100644
index 0000000000..a5fb54bd76
--- /dev/null
+++ b/toolchain/uClibc/Makefile
@@ -0,0 +1,41 @@
+PATH_PREFIX=.
+
+include ./common.mk
+
+HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.built
+HOST_STAMP_INSTALLED:=$(TOOLCHAIN_DIR)/stamp/.uclibc_installed
+
+HOST_BUILD_PARALLEL:=1
+
+define Host/SetToolchainInfo
+	$(SED) 's,^\(LIBC_TYPE\)=.*,\1=$(PKG_NAME),' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_URL\)=.*,\1=http://www.uclibc.org/,' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_VERSION\)=.*,\1=$(PKG_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+	$(SED) 's,^\(LIBC_SO_VERSION\)=.*,\1=$(LIBC_SO_VERSION),' $(TOOLCHAIN_DIR)/info.mk
+endef
+
+define Host/Compile
+	$(SED) 's,^CROSS=.*,CROSS=$(TARGET_CROSS),g' $(HOST_BUILD_DIR)/Rules.mak
+	$(UCLIBC_MAKE) PREFIX= all
+endef
+
+define Host/Install
+	$(call Host/SetToolchainInfo)
+	$(UCLIBC_MAKE) PREFIX="$(TOOLCHAIN_DIR)/" install_runtime install_dev
+	$(CP) $(HOST_BUILD_DIR)/libc/libc_so.a $(TOOLCHAIN_DIR)/lib/
+	$(CP) $(HOST_BUILD_DIR)/libpthread/*/libpthread_so.a $(TOOLCHAIN_DIR)/lib/
+	( cd $(TOOLCHAIN_DIR) ; \
+		for d in lib usr/lib ; do \
+		  for f in libc.so libpthread.so libgcc_s.so ; do \
+		    if [ -f $$$$d/$$$$f -a ! -L $$$$d/$$$$f ] ; then \
+		      $(SED) 's,/usr/lib/,,g;s,/lib/,,g' $$$$d/$$$$f ; \
+		    fi \
+		  done \
+		done \
+	)
+	rm -f \
+		$(TOOLCHAIN_DIR)/lib/libresolv*.so* \
+		$(TOOLCHAIN_DIR)/lib/libnsl*.so*
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/uClibc/common.mk b/toolchain/uClibc/common.mk
new file mode 100644
index 0000000000..952f67d386
--- /dev/null
+++ b/toolchain/uClibc/common.mk
@@ -0,0 +1,97 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+PKG_VERSION:=$(call qstrip,$(CONFIG_UCLIBC_VERSION))
+
+PKG_NAME:=uClibc-ng
+PKG_SOURCE_URL = http://downloads.uclibc-ng.org/releases/$(PKG_VERSION)/
+PATCH_DIR:=$(PATH_PREFIX)/patches
+CONFIG_DIR:=$(PATH_PREFIX)/config
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+LIBC_SO_VERSION:=$(PKG_VERSION)
+
+PKG_MD5SUM=8eed7f3635216142c1c5e122874b89c6
+
+HOST_BUILD_DIR:=$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+UCLIBC_TARGET_ARCH:=$(shell echo $(ARCH) | sed -e s'/-.*//' \
+		-e 's/arc.*/arc/' \
+		-e 's/i.86/i386/' \
+		-e 's/sparc.*/sparc/' \
+		-e 's/arm.*/arm/g' \
+		-e 's/m68k.*/m68k/' \
+		-e 's/ppc/powerpc/g' \
+		-e 's/v850.*/v850/g' \
+		-e 's/sh64/sh/' \
+		-e 's/sh[234].*/sh/' \
+		-e 's/mips.*/mips/' \
+		-e 's/mipsel.*/mips/' \
+)
+
+GEN_CONFIG=$(SCRIPT_DIR)/kconfig.pl -n \
+	$(if $(wildcard $(CONFIG_DIR)/common),'+' $(CONFIG_DIR)/common) \
+	$(if $(CONFIG_UCLIBC_ENABLE_DEBUG),$(if $(wildcard $(CONFIG_DIR)/debug),'+' $(CONFIG_DIR)/debug)) \
+	$(CONFIG_DIR)/$(ARCH)$(strip \
+		$(if $(wildcard $(CONFIG_DIR)/$(ARCH).$(BOARD)),.$(BOARD), \
+			$(if $(filter archs,$(subst ",,$(CONFIG_CPU_TYPE))),hs, \
+			$(if $(CONFIG_MIPS64_ABI),.$(subst ",,$(CONFIG_MIPS64_ABI)), \
+			$(if $(CONFIG_HAS_SPE_FPU),$(if $(wildcard $(CONFIG_DIR)/$(ARCH).e500),.e500))))))
+
+CPU_CFLAGS = \
+	-funsigned-char -fno-builtin -fno-asm \
+	--std=gnu99 -ffunction-sections -fdata-sections \
+	-Wno-unused-but-set-variable \
+	$(TARGET_CFLAGS) -ggdb
+
+UCLIBC_MAKE = PATH='$(TOOLCHAIN_DIR)/initial/bin:$(TARGET_PATH)' $(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) \
+	$(TARGET_CONFIGURE_OPTS) \
+	DEVEL_PREFIX=/ \
+	RUNTIME_PREFIX=/ \
+	HOSTCC="$(HOSTCC)" \
+	CPU_CFLAGS="$(CPU_CFLAGS)" \
+	ARCH="$(CONFIG_ARCH)" \
+	LIBGCC="$(subst libgcc.a,libgcc_initial.a,$(shell $(TARGET_CC) -print-libgcc-file-name))" \
+	DOSTRIP=""
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	$(if $(strip $(QUILT)), \
+		cd $(HOST_BUILD_DIR); \
+		if $(QUILT_CMD) next >/dev/null 2>&1; then \
+			$(QUILT_CMD) push -a; \
+		fi
+	)
+	ln -snf $(PKG_NAME)-$(PKG_VERSION) $(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+endef
+
+define Host/Configure
+	$(GEN_CONFIG) > $(HOST_BUILD_DIR)/.config.new
+	$(SED) 's,^KERNEL_HEADERS=.*,KERNEL_HEADERS=\"$(BUILD_DIR_TOOLCHAIN)/linux-dev/include\",g' \
+		-e 's,^.*UCLIBC_HAS_FPU.*,UCLIBC_HAS_FPU=$(if $(CONFIG_SOFT_FLOAT),n,y),g' \
+		-e 's,^.*UCLIBC_HAS_SOFT_FLOAT.*,UCLIBC_HAS_SOFT_FLOAT=$(if $(CONFIG_SOFT_FLOAT),y,n),g' \
+		-e 's,^.*UCLIBC_HAS_LOCALE.*,UCLIBC_HAS_LOCALE=$(if $(CONFIG_BUILD_NLS),y,n),g' \
+		-e 's,^.*UCLIBC_BUILD_ALL_LOCALE.*,UCLIBC_BUILD_ALL_LOCALE=$(if $(CONFIG_BUILD_NLS),y,n),g' \
+		-e 's,^.*UCLIBC_HAS_SSP[^_].*,UCLIBC_HAS_SSP=$(if $(or $(CONFIG_PKG_CC_STACKPROTECTOR_REGULAR),$(CONFIG_PKG_CC_STACKPROTECTOR_STRONG)),y,n),g' \
+		$(HOST_BUILD_DIR)/.config.new
+	cmp -s $(HOST_BUILD_DIR)/.config.new $(HOST_BUILD_DIR)/.config.last || { \
+		cp $(HOST_BUILD_DIR)/.config.new $(HOST_BUILD_DIR)/.config && \
+		$(MAKE) -C $(HOST_BUILD_DIR) oldconfig KBUILD_HAVE_NLS= HOSTCFLAGS="-DKBUILD_NO_NLS" && \
+		$(MAKE) -C $(HOST_BUILD_DIR)/extra/config conf KBUILD_HAVE_NLS= HOSTCFLAGS="-DKBUILD_NO_NLS" && \
+		cp $(HOST_BUILD_DIR)/.config.new $(HOST_BUILD_DIR)/.config.last; \
+	}
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME) \
+		$(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev
+endef
diff --git a/toolchain/uClibc/config/arc b/toolchain/uClibc/config/arc
new file mode 100644
index 0000000000..de1ffc4415
--- /dev/null
+++ b/toolchain/uClibc/config/arc
@@ -0,0 +1,10 @@
+ARCH_ANY_ENDIAN=y
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+TARGET_ARCH="arc"
+TARGET_arc=y
+CONFIG_ARC_CPU_700=y
+# CONFIG_ARC_CPU_HS is not set
+CONFIG_ARC_PAGE_SIZE_8K=y
+# CONFIG_ARC_PAGE_SIZE_16K is not set
+# CONFIG_ARC_PAGE_SIZE_4K is not set
diff --git a/toolchain/uClibc/config/archs b/toolchain/uClibc/config/archs
new file mode 100644
index 0000000000..961628ed8c
--- /dev/null
+++ b/toolchain/uClibc/config/archs
@@ -0,0 +1,10 @@
+ARCH_ANY_ENDIAN=y
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+TARGET_ARCH="arc"
+TARGET_arc=y
+# CONFIG_ARC_CPU_700 is not set
+CONFIG_ARC_CPU_HS=y
+CONFIG_ARC_PAGE_SIZE_8K=y
+# CONFIG_ARC_PAGE_SIZE_16K is not set
+# CONFIG_ARC_PAGE_SIZE_4K is not set
diff --git a/toolchain/uClibc/config/arm b/toolchain/uClibc/config/arm
new file mode 100644
index 0000000000..41a60b1c38
--- /dev/null
+++ b/toolchain/uClibc/config/arm
@@ -0,0 +1,9 @@
+ARCH_ANY_ENDIAN=y
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# COMPILE_IN_THUMB_MODE is not set
+TARGET_ARCH="arm"
+TARGET_arm=y
+# USE_BX is not set
+CONFIG_ARM_EABI=y
+
diff --git a/toolchain/uClibc/config/armeb b/toolchain/uClibc/config/armeb
new file mode 100644
index 0000000000..2e46dd67d9
--- /dev/null
+++ b/toolchain/uClibc/config/armeb
@@ -0,0 +1,9 @@
+ARCH_ANY_ENDIAN=y
+ARCH_BIG_ENDIAN=y
+ARCH_WANTS_BIG_ENDIAN=y
+# COMPILE_IN_THUMB_MODE is not set
+TARGET_ARCH="arm"
+TARGET_arm=y
+# USE_BX is not set
+CONFIG_ARM_EABI=y
+
diff --git a/toolchain/uClibc/config/common b/toolchain/uClibc/config/common
new file mode 100644
index 0000000000..b679c0a1ec
--- /dev/null
+++ b/toolchain/uClibc/config/common
@@ -0,0 +1,226 @@
+# ARCH_ANY_ENDIAN is not set
+ARCH_HAS_MMU=y
+# ARCH_HAS_NO_LDSO is not set
+# ARCH_HAS_NO_SHARED is not set
+# ARCH_LITTLE_ENDIAN is not set
+ARCH_USE_MMU=y
+# ARCH_WANTS_BIG_ENDIAN is not set
+# ARCH_WANTS_LITTLE_ENDIAN is not set
+ASSUME_DEVPTS=y
+# COMPAT_ATEXIT is not set
+CROSS_COMPILER_PREFIX=""
+DEVEL_PREFIX="/usr/"
+# DOASSERTS is not set
+# DODEBUG is not set
+# DODEBUG_PT is not set
+# DOMULTI is not set
+DOPIC=y
+DOSTRIP=y
+DO_C99_MATH=y
+# DO_XSI_MATH is not set
+# EXTRA_WARNINGS is not set
+FORCE_OPTIONS_FOR_ARCH=y
+# FORCE_SHAREABLE_TEXT_SEGMENTS is not set
+# HARDWIRED_ABSPATH is not set
+# HAS_NO_THREADS is not set
+HAVE_DOT_CONFIG=y
+# HAVE_NO_PIC is not set
+# HAVE_NO_SSP is not set
+HAVE_SHARED=y
+KERNEL_HEADERS="."
+LDSO_BASE_FILENAME="ld.so"
+LDSO_CACHE_SUPPORT=y
+# LDSO_GNU_HASH_SUPPORT is not set
+LDSO_LD_LIBRARY_PATH=y
+LDSO_LDD_SUPPORT=y
+# LDSO_NO_CLEANUP is not set
+# LDSO_PRELINK_SUPPORT is not set
+# LDSO_PRELOAD_FILE_SUPPORT is not set
+LDSO_PRELOAD_ENV_SUPPORT=y
+LDSO_RUNPATH=y
+LDSO_SAFE_RUNPATH=y
+# LDSO_RUNPATH_OF_EXECUTABLE is not set
+# LDSO_SEARCH_INTERP_PATH is not set
+# LDSO_STANDALONE_SUPPORT is not set
+# LINUXTHREADS_NEW is not set
+# LINUXTHREADS_OLD is not set
+# UCLIBC_HAS_BACKTRACE is not set
+UCLIBC_HAS_THREADS_NATIVE=y
+# MALLOC is not set
+MALLOC_GLIBC_COMPAT=y
+# MALLOC_SIMPLE is not set
+MALLOC_STANDARD=y
+MULTILIB_DIR="lib"
+PTHREADS_DEBUG_SUPPORT=y
+RUNTIME_PREFIX="/"
+# SUPPORT_LD_DEBUG is not set
+# SUPPORT_LD_DEBUG_EARLY is not set
+TARGET_SUBARCH=""
+# TARGET_alpha is not set
+# TARGET_arc is not set
+# TARGET_arm is not set
+# TARGET_avr32 is not set
+# TARGET_bfin is not set
+# TARGET_c6x is not set
+# TARGET_cris is not set
+# TARGET_e1 is not set
+# TARGET_frv is not set
+# TARGET_h8300 is not set
+# TARGET_hppa is not set
+# TARGET_i386 is not set
+# TARGET_i960 is not set
+# TARGET_ia64 is not set
+# TARGET_lm32 is not set
+# TARGET_m68k is not set
+# TARGET_metag is not set
+# TARGET_microblaze is not set
+# TARGET_mips is not set
+# TARGET_nios is not set
+# TARGET_nios2 is not set
+# TARGET_or1k is not set
+# TARGET_powerpc is not set
+# TARGET_sh is not set
+# TARGET_sh64 is not set
+# TARGET_sparc is not set
+# TARGET_v850 is not set
+# TARGET_vax is not set
+# TARGET_x86_64 is not set
+# TARGET_xtensa is not set
+UCLIBC_BSD_SPECIFIC=y
+UCLIBC_BUILD_NOEXECSTACK=y
+# UCLIBC_BUILD_NOW is not set
+# UCLIBC_BUILD_PIE is not set
+UCLIBC_BUILD_RELRO=y
+UCLIBC_CTOR_DTOR=y
+UCLIBC_DYNAMIC_ATEXIT=y
+UCLIBC_EXTRA_CFLAGS=""
+UCLIBC_GRP_BUFFER_SIZE=256
+UCLIBC_HAS_ADVANCED_REALTIME=y
+# UCLIBC_HAS_ARC4RANDOM is not set
+# UCLIBC_HAS_ARGP is not set
+UCLIBC_HAS_BSD_ERR=y
+UCLIBC_HAS_BSD_RES_CLOSE=y
+# UCLIBC_HAS_COMPAT_RES_STATE is not set
+UCLIBC_HAS_CRYPT=y
+UCLIBC_HAS_CRYPT_IMPL=y
+UCLIBC_HAS_CTYPE_CHECKED=y
+# UCLIBC_HAS_CTYPE_ENFORCED is not set
+UCLIBC_HAS_CTYPE_SIGNED=y
+UCLIBC_HAS_CTYPE_TABLES=y
+# UCLIBC_HAS_CTYPE_UNSAFE is not set
+UCLIBC_HAS_EPOLL=y
+UCLIBC_HAS_ERRNO_MESSAGES=y
+# UCLIBC_HAS_EXTRA_COMPAT_RES_STATE is not set
+# UCLIBC_HAS_FENV is not set
+UCLIBC_HAS_FLOATS=y
+UCLIBC_HAS_FNMATCH=y
+UCLIBC_HAS_FNMATCH_OLD=y
+# UCLIBC_HAS_FOPEN_CLOSEEXEC_MODE is not set
+UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y
+# UCLIBC_HAS_FOPEN_LARGEFILE_MODE is not set
+# UCLIBC_HAS_FPU is not set
+UCLIBC_HAS_FTS=y
+UCLIBC_HAS_FTW=y
+# UCLIBC_HAS_FULL_RPC is not set
+UCLIBC_HAS_GETPT=y
+UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
+UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y
+# UCLIBC_HAS_GLIBC_DIGIT_GROUPING is not set
+UCLIBC_HAS_GLOB=y
+UCLIBC_HAS_GNU_ERROR=y
+UCLIBC_HAS_GNU_GETOPT=y
+UCLIBC_HAS_GNU_GETSUBOPT=y
+UCLIBC_HAS_GNU_GLOB=y
+UCLIBC_HAS_HEXADECIMAL_FLOATS=y
+UCLIBC_HAS_IPV4=y
+UCLIBC_HAS_IPV6=y
+UCLIBC_HAS_LFS=y
+UCLIBC_HAS_LIBNSL_STUB=y
+UCLIBC_HAS_LIBRESOLV_STUB=y
+UCLIBC_HAS_LIBUTIL=y
+# UCLIBC_HAS_LOCALE is not set
+# UCLIBC_BUILD_ALL_LOCALE is not set
+# UCLIBC_BUILD_MINIMAL_LOCALE is not set
+# UCLIBC_PREGENERATED_LOCALE_DATA is not set
+UCLIBC_HAS_LONG_DOUBLE_MATH=y
+UCLIBC_HAS_NETWORK_SUPPORT=y
+UCLIBC_HAS_NFTW=y
+UCLIBC_HAS_OBSOLETE_BSD_SIGNAL=y
+# UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL is not set
+UCLIBC_HAS_PRINTF_M_SPEC=y
+# UCLIBC_HAS_PROFILING is not set
+UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y
+UCLIBC_HAS_PTY=y
+UCLIBC_HAS_REALTIME=y
+# UCLIBC_HAS_REENTRANT_RPC is not set
+UCLIBC_HAS_REGEX=y
+UCLIBC_HAS_REGEX_OLD=y
+UCLIBC_HAS_RESOLVER_SUPPORT=y
+# UCLIBC_HAS_RPC is not set
+UCLIBC_HAS_SCANF_GLIBC_A_FLAG=y
+# UCLIBC_HAS_SHA256_CRYPT_IMPL is not set
+# UCLIBC_HAS_SHA512_CRYPT_IMPL is not set
+UCLIBC_HAS_SHADOW=y
+UCLIBC_HAS_SIGNUM_MESSAGES=y
+UCLIBC_HAS_SOCKET=y
+UCLIBC_HAS_SOFT_FLOAT=y
+# UCLIBC_HAS_SSP is not set
+# UCLIBC_HAS_SSP_COMPAT is not set
+UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
+# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
+UCLIBC_HAS_STDIO_BUFSIZ_4096=y
+# UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_8192 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4 is not set
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set
+UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
+UCLIBC_HAS_STDIO_GETC_MACRO=y
+UCLIBC_HAS_STDIO_PUTC_MACRO=y
+# UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT is not set
+UCLIBC_HAS_STRING_ARCH_OPT=y
+UCLIBC_HAS_STRING_GENERIC_OPT=y
+# UCLIBC_HAS_STUBS is not set
+UCLIBC_HAS_SYSLOG=y
+# UCLIBC_HAS_SYS_ERRLIST is not set
+# UCLIBC_HAS_SYS_SIGLIST is not set
+UCLIBC_HAS_THREADS=y
+UCLIBC_HAS_TM_EXTENSIONS=y
+UCLIBC_HAS_TZ_CACHING=y
+UCLIBC_HAS_TZ_FILE=y
+UCLIBC_HAS_TZ_FILE_READ_MANY=y
+UCLIBC_HAS_UTMPX=y
+UCLIBC_HAS_UTMP=y
+UCLIBC_HAS_WCHAR=y
+UCLIBC_HAS_WORDEXP=y
+UCLIBC_HAS_XATTR=y
+# UCLIBC_HAS_XLOCALE is not set
+UCLIBC_HAS___PROGNAME=y
+# UCLIBC_LINUX_MODULE_24 is not set
+UCLIBC_LINUX_MODULE_26=y
+UCLIBC_LINUX_SPECIFIC=y
+# UCLIBC_MALLOC_DEBUGGING is not set
+# UCLIBC_MJN3_ONLY is not set
+# UCLIBC_NTP_LEGACY is not set
+# USE_OLD_VFPRINTF is not set
+UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+UCLIBC_PWD_BUFFER_SIZE=256
+# UCLIBC_STATIC_LDCONFIG is not set
+# UCLIBC_STRICT_HEADERS is not set
+UCLIBC_SUPPORT_AI_ADDRCONFIG=y
+UCLIBC_SUSV3_LEGACY=y
+UCLIBC_SUSV3_LEGACY_MACROS=y
+UCLIBC_SUSV4_LEGACY=y
+# UCLIBC_SV4_DEPRECATED is not set
+UCLIBC_TZ_FILE_PATH="/etc/TZ"
+# UCLIBC_FALLBACK_TO_ETC_LOCALTIME is not set
+UCLIBC_USE_NETLINK=y
+# UNIX98PTY_ONLY is not set
+USE_BX=y
+WARNINGS="-Wall"
+# UCLIBC_HAS_OBSTACK is not set
+# UCLIBC_SUSV2_LEGACY is not set
+# UCLIBC_HAS_CONTEXT_FUNCS is not set
+UCLIBC_HAS_GETOPT_LONG=y
diff --git a/toolchain/uClibc/config/debug b/toolchain/uClibc/config/debug
new file mode 100644
index 0000000000..b366e66e39
--- /dev/null
+++ b/toolchain/uClibc/config/debug
@@ -0,0 +1,6 @@
+DODEBUG=y
+DODEBUG_PT=y
+PTHREADS_DEBUG_SUPPORT=y
+SUPPORT_LD_DEBUG=y
+SUPPORT_LD_DEBUG_EARLY=y
+UCLIBC_MALLOC_DEBUGGING=y
diff --git a/toolchain/uClibc/config/i386 b/toolchain/uClibc/config/i386
new file mode 100644
index 0000000000..5ef264c271
--- /dev/null
+++ b/toolchain/uClibc/config/i386
@@ -0,0 +1,21 @@
+ARCH_LITTLE_ENDIAN=y
+# CONFIG_386 is not set
+CONFIG_486=y
+# CONFIG_586 is not set
+# CONFIG_586MMX is not set
+# CONFIG_686 is not set
+# CONFIG_CRUSOE is not set
+# CONFIG_CYRIXIII is not set
+# CONFIG_ELAN is not set
+# CONFIG_GENERIC_386 is not set
+# CONFIG_K6 is not set
+# CONFIG_K7 is not set
+# CONFIG_NEHEMIAH is not set
+# CONFIG_PENTIUM4 is not set
+# CONFIG_PENTIUMII is not set
+# CONFIG_PENTIUMIII is not set
+# CONFIG_WINCHIP2 is not set
+# CONFIG_WINCHIPC6 is not set
+TARGET_ARCH="i386"
+TARGET_i386=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/i686 b/toolchain/uClibc/config/i686
new file mode 100644
index 0000000000..ba615f6b86
--- /dev/null
+++ b/toolchain/uClibc/config/i686
@@ -0,0 +1,21 @@
+ARCH_LITTLE_ENDIAN=y
+# CONFIG_386 is not set
+# CONFIG_486 is not set
+# CONFIG_586 is not set
+# CONFIG_586MMX is not set
+CONFIG_686=y
+# CONFIG_CRUSOE is not set
+# CONFIG_CYRIXIII is not set
+# CONFIG_ELAN is not set
+# CONFIG_GENERIC_386 is not set
+# CONFIG_K6 is not set
+# CONFIG_K7 is not set
+# CONFIG_NEHEMIAH is not set
+# CONFIG_PENTIUM4 is not set
+# CONFIG_PENTIUMII is not set
+# CONFIG_PENTIUMIII is not set
+# CONFIG_WINCHIP2 is not set
+# CONFIG_WINCHIPC6 is not set
+TARGET_ARCH="i386"
+TARGET_i386=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/m68k b/toolchain/uClibc/config/m68k
new file mode 100644
index 0000000000..14ce5aef7b
--- /dev/null
+++ b/toolchain/uClibc/config/m68k
@@ -0,0 +1,6 @@
+ARCH_BIG_ENDIAN=y
+LINUXTHREADS_OLD=y
+TARGET_ARCH="m68k"
+TARGET_SUBARCH=""
+TARGET_m68k=y
+# UCLIBC_HAS_THREADS_NATIVE is not set
diff --git a/toolchain/uClibc/config/mips b/toolchain/uClibc/config/mips
new file mode 100644
index 0000000000..8cec22f4de
--- /dev/null
+++ b/toolchain/uClibc/config/mips
@@ -0,0 +1,18 @@
+ARCH_ANY_ENDIAN=y
+ARCH_BIG_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_WANTS_BIG_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+CONFIG_MIPS_ISA_MIPS32=y
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+# CONFIG_MIPS_ISA_MIPS64 is not set
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+# CONFIG_MIPS_N64_ABI is not set
+CONFIG_MIPS_O32_ABI=y
+TARGET_ARCH="mips"
+TARGET_mips=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64 b/toolchain/uClibc/config/mips64
new file mode 100644
index 0000000000..566d87a6e4
--- /dev/null
+++ b/toolchain/uClibc/config/mips64
@@ -0,0 +1,18 @@
+ARCH_ANY_ENDIAN=y
+ARCH_BIG_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_WANTS_BIG_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+CONFIG_MIPS_N64_ABI=y
+# CONFIG_MIPS_O32_ABI is not set
+TARGET_ARCH="mips"
+TARGET_mips=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64.32 b/toolchain/uClibc/config/mips64.32
new file mode 100644
index 0000000000..b7ea8f457e
--- /dev/null
+++ b/toolchain/uClibc/config/mips64.32
@@ -0,0 +1,19 @@
+ARCH_ANY_ENDIAN=y
+ARCH_BIG_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_WANTS_BIG_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+# CONFIG_MIPS_N64_ABI is not set
+CONFIG_MIPS_O32_ABI=y
+TARGET_ARCH="mips"
+TARGET_mips=y
+TARGET_SUBARCH="mips64"
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64.64 b/toolchain/uClibc/config/mips64.64
new file mode 100644
index 0000000000..2a0b755a73
--- /dev/null
+++ b/toolchain/uClibc/config/mips64.64
@@ -0,0 +1,19 @@
+ARCH_ANY_ENDIAN=y
+ARCH_BIG_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_WANTS_BIG_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+CONFIG_MIPS_N64_ABI=y
+# CONFIG_MIPS_O32_ABI is not set
+TARGET_ARCH="mips"
+TARGET_mips=y
+TARGET_SUBARCH="mips64"
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64.n32 b/toolchain/uClibc/config/mips64.n32
new file mode 100644
index 0000000000..f8def5837f
--- /dev/null
+++ b/toolchain/uClibc/config/mips64.n32
@@ -0,0 +1,19 @@
+ARCH_ANY_ENDIAN=y
+ARCH_BIG_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_WANTS_BIG_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+CONFIG_MIPS_N32_ABI=y
+# CONFIG_MIPS_N64_ABI is not set
+# CONFIG_MIPS_O32_ABI is not set
+TARGET_ARCH="mips"
+TARGET_mips=y
+TARGET_SUBARCH="mips64"
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64el b/toolchain/uClibc/config/mips64el
new file mode 100644
index 0000000000..53580787b5
--- /dev/null
+++ b/toolchain/uClibc/config/mips64el
@@ -0,0 +1,18 @@
+ARCH_ANY_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+CONFIG_MIPS_N64_ABI=y
+# CONFIG_MIPS_O32_ABI is not set
+TARGET_ARCH="mips"
+TARGET_mips=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64el.32 b/toolchain/uClibc/config/mips64el.32
new file mode 100644
index 0000000000..a10840bf96
--- /dev/null
+++ b/toolchain/uClibc/config/mips64el.32
@@ -0,0 +1,19 @@
+ARCH_ANY_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+# CONFIG_MIPS_N64_ABI is not set
+CONFIG_MIPS_O32_ABI=y
+TARGET_ARCH="mips"
+TARGET_mips=y
+TARGET_SUBARCH="mips64"
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64el.64 b/toolchain/uClibc/config/mips64el.64
new file mode 100644
index 0000000000..8b90a54a57
--- /dev/null
+++ b/toolchain/uClibc/config/mips64el.64
@@ -0,0 +1,19 @@
+ARCH_ANY_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+CONFIG_MIPS_N64_ABI=y
+# CONFIG_MIPS_O32_ABI is not set
+TARGET_ARCH="mips"
+TARGET_mips=y
+TARGET_SUBARCH="mips64"
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mips64el.n32 b/toolchain/uClibc/config/mips64el.n32
new file mode 100644
index 0000000000..4ac4d06c0d
--- /dev/null
+++ b/toolchain/uClibc/config/mips64el.n32
@@ -0,0 +1,19 @@
+ARCH_ANY_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+CONFIG_MIPS_ISA_MIPS64=y
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+CONFIG_MIPS_N32_ABI=y
+# CONFIG_MIPS_N64_ABI is not set
+# CONFIG_MIPS_O32_ABI is not set
+TARGET_ARCH="mips"
+TARGET_mips=y
+TARGET_SUBARCH="mips64"
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mipsel b/toolchain/uClibc/config/mipsel
new file mode 100644
index 0000000000..d9dedbb02c
--- /dev/null
+++ b/toolchain/uClibc/config/mipsel
@@ -0,0 +1,18 @@
+ARCH_ANY_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+# CONFIG_MIPS_ISA_3 is not set
+# CONFIG_MIPS_ISA_4 is not set
+CONFIG_MIPS_ISA_MIPS32=y
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+# CONFIG_MIPS_ISA_MIPS64 is not set
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+# CONFIG_MIPS_N64_ABI is not set
+CONFIG_MIPS_O32_ABI=y
+TARGET_ARCH="mips"
+TARGET_mips=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/mipsel.cobalt b/toolchain/uClibc/config/mipsel.cobalt
new file mode 100644
index 0000000000..1d42a70f23
--- /dev/null
+++ b/toolchain/uClibc/config/mipsel.cobalt
@@ -0,0 +1,18 @@
+ARCH_ANY_ENDIAN=y
+ARCH_CFLAGS="-mno-split-addresses"
+ARCH_LITTLE_ENDIAN=y
+ARCH_WANTS_LITTLE_ENDIAN=y
+# CONFIG_MIPS_ISA_1 is not set
+# CONFIG_MIPS_ISA_2 is not set
+CONFIG_MIPS_ISA_3=y
+# CONFIG_MIPS_ISA_4 is not set
+# CONFIG_MIPS_ISA_MIPS32 is not set
+# CONFIG_MIPS_ISA_MIPS32R2 is not set
+# CONFIG_MIPS_ISA_MIPS64 is not set
+# CONFIG_MIPS_ISA_MIPS64R2 is not set
+# CONFIG_MIPS_N32_ABI is not set
+# CONFIG_MIPS_N64_ABI is not set
+CONFIG_MIPS_O32_ABI=y
+TARGET_ARCH="mips"
+TARGET_mips=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/config/powerpc b/toolchain/uClibc/config/powerpc
new file mode 100644
index 0000000000..5b1292d12e
--- /dev/null
+++ b/toolchain/uClibc/config/powerpc
@@ -0,0 +1,6 @@
+ARCH_BIG_ENDIAN=y
+CONFIG_CLASSIC=y
+# CONFIG_E500 is not set
+TARGET_ARCH="powerpc"
+TARGET_SUBARCH="classic"
+TARGET_powerpc=y
diff --git a/toolchain/uClibc/config/powerpc.e500 b/toolchain/uClibc/config/powerpc.e500
new file mode 100644
index 0000000000..a835c3d5e7
--- /dev/null
+++ b/toolchain/uClibc/config/powerpc.e500
@@ -0,0 +1,6 @@
+ARCH_BIG_ENDIAN=y
+# CONFIG_CLASSIC is not set
+CONFIG_E500=y
+TARGET_ARCH="powerpc"
+TARGET_SUBARCH="classic"
+TARGET_powerpc=y
diff --git a/toolchain/uClibc/config/sparc b/toolchain/uClibc/config/sparc
new file mode 100644
index 0000000000..e1596c4100
--- /dev/null
+++ b/toolchain/uClibc/config/sparc
@@ -0,0 +1,8 @@
+ARCH_BIG_ENDIAN=y
+# CONFIG_SPARC_V7 is not set
+# CONFIG_SPARC_V8 is not set
+CONFIG_SPARC_V9=y
+# CONFIG_SPARC_V9B is not set
+TARGET_ARCH="sparc"
+TARGET_sparc=y
+UCLIBC_HAS_LONG_DOUBLE_MATH=y
diff --git a/toolchain/uClibc/config/sparc.leon b/toolchain/uClibc/config/sparc.leon
new file mode 100644
index 0000000000..eb725ac05d
--- /dev/null
+++ b/toolchain/uClibc/config/sparc.leon
@@ -0,0 +1,8 @@
+ARCH_BIG_ENDIAN=y
+# CONFIG_SPARC_V7 is not set
+CONFIG_SPARC_V8=y
+# CONFIG_SPARC_V9 is not set
+# CONFIG_SPARC_V9B is not set
+TARGET_ARCH="sparc"
+TARGET_sparc=y
+UCLIBC_HAS_LONG_DOUBLE_MATH=y
diff --git a/toolchain/uClibc/config/x86_64 b/toolchain/uClibc/config/x86_64
new file mode 100644
index 0000000000..b6dc2c2afe
--- /dev/null
+++ b/toolchain/uClibc/config/x86_64
@@ -0,0 +1,6 @@
+ARCH_LITTLE_ENDIAN=y
+# LINUXTHREADS_NEW is not set
+TARGET_ARCH="x86_64"
+TARGET_x86_64=y
+UCLIBC_BSD_SPECIFIC=y
+UCLIBC_HAS_FPU=y
diff --git a/toolchain/uClibc/headers/Makefile b/toolchain/uClibc/headers/Makefile
new file mode 100644
index 0000000000..abd3620d33
--- /dev/null
+++ b/toolchain/uClibc/headers/Makefile
@@ -0,0 +1,27 @@
+PATH_PREFIX:=..
+
+include ../common.mk
+
+HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.headers_built
+HOST_STAMP_INSTALLED:=$(TOOLCHAIN_DIR)/stamp/.uclibc_headers_installed
+
+define Host/Compile
+
+endef
+
+define Host/Install
+	PATH='$(TARGET_PATH)' $(MAKE) -C $(HOST_BUILD_DIR) \
+		PREFIX="$(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/" \
+		DEVEL_PREFIX=/ \
+		RUNTIME_PREFIX="$(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/" \
+		HOSTCC="$(HOSTCC)" \
+		CC="$(TARGET_CC)" \
+		CPU_CFLAGS="$(TARGET_CFLAGS)" \
+		ARCH="$(CONFIG_ARCH)" \
+		pregen \
+		install_headers
+	$(CP) $(BUILD_DIR_TOOLCHAIN)/linux-dev/* $(BUILD_DIR_TOOLCHAIN)/$(LIBC)-dev/
+endef
+
+$(eval $(call HostBuild))
+
diff --git a/toolchain/uClibc/utils/Makefile b/toolchain/uClibc/utils/Makefile
new file mode 100644
index 0000000000..83100d70c1
--- /dev/null
+++ b/toolchain/uClibc/utils/Makefile
@@ -0,0 +1,24 @@
+PATH_PREFIX=..
+
+include ../common.mk
+
+HOST_STAMP_BUILT:=$(HOST_BUILD_DIR)/.utils_built
+HOST_STAMP_INSTALLED:=$(TOOLCHAIN_DIR)/stamp/.uclibc_utils_installed
+
+define Host/Compile
+	$(SED) 's,^CROSS=.*,CROSS=$(TARGET_CROSS),g' $(HOST_BUILD_DIR)/Rules.mak
+	$(UCLIBC_MAKE) PREFIX= utils
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(TOOLCHAIN_DIR)/bin
+	$(INSTALL_BIN) \
+		$(HOST_BUILD_DIR)/utils/ldd \
+		$(TOOLCHAIN_DIR)/bin/
+	$(INSTALL_DIR) $(TOOLCHAIN_DIR)/sbin
+	$(INSTALL_BIN) \
+		$(HOST_BUILD_DIR)/utils/ldconfig \
+		$(TOOLCHAIN_DIR)/sbin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/wrapper/Makefile b/toolchain/wrapper/Makefile
new file mode 100644
index 0000000000..3398e407c9
--- /dev/null
+++ b/toolchain/wrapper/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wrapper
+PKG_VERSION:=1
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+
+# 1: args
+define toolchain_util
+$(strip $(SCRIPT_DIR)/ext-toolchain.sh --toolchain $(CONFIG_TOOLCHAIN_ROOT) \
+	--cflags $(CONFIG_TARGET_OPTIMIZATION) \
+	--cflags "$(if $(call qstrip,$(CONFIG_TOOLCHAIN_LIBC)),-m$(call qstrip,$(CONFIG_TOOLCHAIN_LIBC))) $(if $(CONFIG_SOFT_FLOAT),-msoft-float)" \
+	--cflags "$(patsubst ./%,-I$(TOOLCHAIN_ROOT_DIR)/%,$(call qstrip,$(CONFIG_TOOLCHAIN_INC_PATH)))" \
+	--cflags "$(patsubst ./%,-L$(TOOLCHAIN_ROOT_DIR)/%,$(call qstrip,$(CONFIG_TOOLCHAIN_LIB_PATH)))" \
+	$(1))
+endef
+
+# 1: config symbol
+# 2: feature
+define toolchain_test
+$$(if $$($(1)), \
+	@echo -n "Testing external toolchain for $(2) support ... "; \
+	if $(call toolchain_util,--test "$(2)"); then \
+		echo "ok"; exit 0; \
+	else \
+		echo "failed"; \
+		echo "ERROR: $(1) is enabled but the external toolchain does not support it"; \
+		exit 1; \
+	fi)
+endef
+
+
+define Host/Prepare
+	$(call toolchain_test,CONFIG_SOFT_FLOAT,softfloat)
+	$(call toolchain_test,CONFIG_IPV6,ipv6)
+	$(call toolchain_test,CONFIG_NLS,wchar)
+	$(call toolchain_test,CONFIG_PACKAGE_libpthread,threads)
+endef
+
+define Host/Configure
+endef
+
+define Host/Compile
+endef
+
+define Host/Install
+	$(call toolchain_util,--wrap "$(TOOLCHAIN_DIR)/bin")
+endef
+
+define Host/Clean
+	rm -rf $(TOOLCHAIN_DIR)/bin
+endef
+
+$(eval $(call HostBuild))
diff --git a/toolchain/yasm/Makefile b/toolchain/yasm/Makefile
new file mode 100644
index 0000000000..bf0b8c5c48
--- /dev/null
+++ b/toolchain/yasm/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2016 Daniel Golle <daniel@makrotopia.org>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=yasm
+PKG_VERSION:=1.3.0
+
+PKG_SOURCE_URL:=http://www.tortall.net/projects/yasm/releases/
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+
+PKG_MD5SUM:=fc9e586751ff789b34b1f21d572d96af
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/toolchain-build.mk
+
+YASM_CONFIGURE:= \
+	./configure \
+		--prefix=$(TOOLCHAIN_DIR) \
+		--build=$(GNU_HOST_NAME) \
+		--host=$(GNU_HOST_NAME) \
+		--target=$(REAL_GNU_TARGET_NAME) \
+		--with-sysroot=$(TOOLCHAIN_DIR) \
+		--disable-multilib \
+		--disable-werror \
+		--disable-nls \
+		--disable-sim \
+		--disable-gdb \
+		$(SOFT_FLOAT_CONFIG_OPTION) \
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	ln -snf $(notdir $(HOST_BUILD_DIR)) $(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+	$(CP) $(SCRIPT_DIR)/config.{guess,sub} $(HOST_BUILD_DIR)/
+endef
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR); \
+		$(YASM_CONFIGURE) \
+	);
+endef
+
+define Host/Compile
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) all
+endef
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		prefix=$(TOOLCHAIN_DIR) \
+		install
+endef
+
+define Host/Clean
+	rm -rf \
+		$(HOST_BUILD_DIR) \
+		$(BUILD_DIR_TOOLCHAIN)/$(PKG_NAME)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 0000000000..a784d3d99d
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,143 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# Main makefile for the host tools
+#
+curdir:=tools
+
+# subdirectories to descend into
+tools-y :=
+
+ifeq ($(CONFIG_EXTERNAL_TOOLCHAIN),)
+  BUILD_TOOLCHAIN := y
+  ifdef CONFIG_GCC_USE_GRAPHITE
+    ifneq ($(CONFIG_GCC_VERSION_4_8),)
+      ifeq ($(CONFIG_GCC_USE_SYSTEM_PPL_CLOOG),)
+        BUILD_PPL_CLOOG = y
+      endif
+    else
+      BUILD_ISL = y
+    endif
+  endif
+endif
+
+tools-$(BUILD_TOOLCHAIN) += gmp mpfr mpc libelf expat
+tools-y += m4 libtool autoconf automake flex bison pkg-config sed mklibs
+tools-y += sstrip make-ext4fs e2fsprogs mtd-utils mkimage
+tools-y += firmware-utils patch-image patch quilt yaffs2 padjffs2
+tools-y += mm-macros missing-macros xz cmake scons bc findutils gengetopt patchelf
+tools-y += mtools dosfstools
+tools-$(CONFIG_TARGET_orion_generic) += wrt350nv2-builder upslug2
+tools-$(CONFIG_powerpc) += upx
+tools-$(CONFIG_TARGET_x86) += qemu
+tools-$(CONFIG_TARGET_mxs) += elftosb sdimage
+tools-$(CONFIG_TARGET_ar71xx) += lzma-old squashfs
+tools-$(CONFIG_USES_MINOR) += kernel2minor
+tools-y += lzma squashfs4
+tools-$(BUILD_PPL_CLOOG) += ppl cloog
+tools-$(BUILD_ISL) += isl
+tools-$(CONFIG_USE_SPARSE) += sparse
+tools-$(CONFIG_TARGET_apm821xx) += genext2fs
+
+# builddir dependencies
+$(curdir)/bison/compile := $(curdir)/flex/install
+$(curdir)/flex/compile := $(curdir)/libtool/install
+$(curdir)/pkg-config/compile := $(curdir)/sed/install
+$(curdir)/libtool/compile := $(curdir)/sed/install $(curdir)/m4/install $(curdir)/autoconf/install $(curdir)/automake/install $(curdir)/missing-macros/install
+$(curdir)/squashfs/compile := $(curdir)/lzma-old/install
+$(curdir)/squashfs4/compile := $(curdir)/xz/install
+$(curdir)/quilt/compile := $(curdir)/sed/install $(curdir)/autoconf/install $(curdir)/findutils/install
+$(curdir)/autoconf/compile := $(curdir)/m4/install
+$(curdir)/automake/compile := $(curdir)/m4/install $(curdir)/autoconf/install $(curdir)/pkg-config/install $(curdir)/xz/install
+$(curdir)/gmp/compile := $(curdir)/libtool/install
+$(curdir)/mpc/compile := $(curdir)/mpfr/install $(curdir)/gmp/install
+$(curdir)/mpfr/compile := $(curdir)/gmp/install
+$(curdir)/ppl/compile := $(curdir)/gmp/install
+$(curdir)/cloog/compile := $(curdir)/ppl/install
+$(curdir)/mtd-utils/compile := $(curdir)/e2fsprogs/install $(curdir)/xz/install
+$(curdir)/mkimage/compile := $(curdir)/sed/install
+$(curdir)/mklibs/compile := $(curdir)/libtool/install
+$(curdir)/qemu/compile := $(curdir)/e2fsprogs/install
+$(curdir)/upslug2/compile := $(curdir)/libtool/install
+$(curdir)/mm-macros/compile := $(curdir)/libtool/install
+$(curdir)/missing-macros/compile := $(curdir)/autoconf/install
+$(curdir)/e2fsprogs/compile := $(curdir)/libtool/install
+$(curdir)/libelf/compile := $(curdir)/libtool/install
+$(curdir)/sdcc/compile := $(curdir)/bison/install
+$(curdir)/padjffs2/compile := $(curdir)/findutils/install
+$(curdir)/cloog/compile := $(curdir)/ppl/install
+$(curdir)/isl/compile := $(curdir)/gmp/install
+$(curdir)/bc/compile := $(curdir)/bison/install
+$(curdir)/findutils/compile := $(curdir)/bison/install
+$(curdir)/gengetopt/compile := $(curdir)/libtool/install
+$(curdir)/patchelf/compile := $(curdir)/libtool/install
+$(curdir)/dosfstools/compile := $(curdir)/autoconf/install $(curdir)/automake/install
+ifeq ($(HOST_OS),Darwin)
+tools-y += libressl
+$(curdir)/mkimage/compile += $(curdir)/libressl/install
+$(curdir)/firmware-utils/compile += $(curdir)/libressl/install
+endif
+ifneq ($(HOST_OS),Linux)
+  tools-y += coreutils
+endif
+
+ifneq ($(CONFIG_CCACHE)$(CONFIG_SDK),)
+$(foreach tool, $(filter-out xz patch,$(tools-y)), $(eval $(curdir)/$(tool)/compile += $(curdir)/ccache/install))
+tools-y += ccache
+endif
+
+# in case there is no patch tool on the host we need to make patch tool a
+# dependency for tools which have patches directory
+$(foreach tool, $(tools-y), $(if $(wildcard $(curdir)/$(tool)/patches),$(eval $(curdir)/$(tool)/compile += $(curdir)/patch/install)))
+
+# make any tool (except xz itself) depend on XZ to ensure that *.tar.xz source archives can be unpacked
+$(foreach tool, $(filter-out xz,$(tools-y)), $(eval $(curdir)/$(tool)/compile += $(curdir)/xz/install))
+
+$(foreach tool, $(tools-y), $(eval $(curdir)/$(tool)/compile += $(curdir)/tar/install))
+tools-y += tar
+
+$(curdir)/tar/compile := $(curdir)/flock/install
+tools-y += flock
+
+$(curdir)/builddirs := $(tools-y) $(tools-dep) $(tools-)
+$(curdir)/builddirs-default := $(tools-y)
+
+ifndef DUMP_TARGET_DB
+define PrepareStaging
+	@for dir in $(1); do ( \
+		$(if $(QUIET),,set -x;) \
+		mkdir -p "$$dir"; \
+		cd "$$dir"; \
+		mkdir -p bin lib include stamp; \
+	); done
+endef
+
+# preparatory work
+$(STAGING_DIR)/.prepared: $(TMP_DIR)/.build
+	$(call PrepareStaging,$(STAGING_DIR))
+	mkdir -p $(BUILD_DIR)/stamp
+	touch $@
+
+$(STAGING_DIR_HOST)/.prepared: $(TMP_DIR)/.build
+	$(call PrepareStaging,$(STAGING_DIR_HOST))
+	mkdir -p $(BUILD_DIR_HOST)/stamp $(STAGING_DIR_HOST)/include/sys
+	$(INSTALL_DATA) $(TOPDIR)/tools/include/*.h $(STAGING_DIR_HOST)/include/
+	$(INSTALL_DATA) $(TOPDIR)/tools/include/sys/*.h $(STAGING_DIR_HOST)/include/sys/
+	ln -sf lib $(STAGING_DIR_HOST)/lib64
+	touch $@
+
+endif
+
+$(curdir)//prepare = $(STAGING_DIR)/.prepared $(STAGING_DIR_HOST)/.prepared
+$(curdir)//compile = $(STAGING_DIR)/.prepared $(STAGING_DIR_HOST)/.prepared
+
+# prerequisites for the individual targets
+$(curdir)/ := .config prereq
+$(curdir)//install = $(1)/compile
+
+tools_enabled = $(foreach tool,$(sort $(tools-y) $(tools-)),$(if $(filter $(tool),$(tools-y)),y,n))
+$(eval $(call stampfile,$(curdir),tools,install,,_$(subst $(space),,$(tools_enabled))))
+$(eval $(call subdir,$(curdir)))
diff --git a/tools/autoconf/Makefile b/tools/autoconf/Makefile
new file mode 100644
index 0000000000..c45855c03d
--- /dev/null
+++ b/tools/autoconf/Makefile
@@ -0,0 +1,37 @@
+# 
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=autoconf
+PKG_VERSION:=2.69
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/autoconf
+PKG_MD5SUM:=50f97f4159805e374639a73e2636f22e
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS += \
+	--datarootdir=$(STAGING_DIR_HOST)/share
+
+HOST_CONFIGURE_VARS += \
+	PERL="/usr/bin/env perl"
+
+define Host/Compile
+	export SHELL="$(BASH)"; $(MAKE) -C $(HOST_BUILD_DIR)
+endef
+
+define Host/Install
+	export SHELL="$(BASH)"; $(MAKE) -C $(HOST_BUILD_DIR) install
+endef
+
+define Host/Clean
+	-export SHELL="$(BASH)"; $(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/autoconf/patches/000-relocatable.patch b/tools/autoconf/patches/000-relocatable.patch
new file mode 100644
index 0000000000..12e94ae9a1
--- /dev/null
+++ b/tools/autoconf/patches/000-relocatable.patch
@@ -0,0 +1,229 @@
+--- a/bin/autoheader.in
++++ b/bin/autoheader.in
+@@ -28,7 +28,8 @@ eval 'case $# in 0) exec @PERL@ -S "$0";
+ 
+ BEGIN
+ {
+-  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
++  my $pkgdatadir = $ENV{'autom4te_perllibdir'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+   unshift @INC, "$pkgdatadir";
+ 
+   # Override SHELL.  On DJGPP SHELL may not be set to a shell
+@@ -50,7 +51,7 @@ use strict;
+ use vars qw ($config_h %verbatim %symbol);
+ 
+ # Lib files.
+-my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
++my $autom4te = $ENV{'AUTOM4TE'} || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/@autom4te-name@' : '@bindir@/@autom4te-name@');
+ local $config_h;
+ my $config_h_in;
+ my @prepend_include;
+--- a/bin/autom4te.in
++++ b/bin/autom4te.in
+@@ -1,10 +1,12 @@
+-#! @PERL@ -w
++#! @PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ # autom4te - Wrapper around M4 libraries.
+ # Copyright (C) 2001-2003, 2005-2012 Free Software Foundation, Inc.
+ 
+@@ -24,7 +26,8 @@ eval 'case $# in 0) exec @PERL@ -S "$0";
+ 
+ BEGIN
+ {
+-  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
++  my $pkgdatadir = $ENV{'autom4te_perllibdir'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+   unshift @INC, $pkgdatadir;
+ 
+   # Override SHELL.  On DJGPP SHELL may not be set to a shell
+@@ -44,7 +47,8 @@ use File::Basename;
+ use strict;
+ 
+ # Data directory.
+-my $pkgdatadir = $ENV{'AC_MACRODIR'} || '@pkgdatadir@';
++my $pkgdatadir = $ENV{'AC_MACRODIR'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+ 
+ # $LANGUAGE{LANGUAGE} -- Automatic options for LANGUAGE.
+ my %language;
+@@ -87,7 +91,7 @@ my @include;
+ my $freeze = 0;
+ 
+ # $M4.
+-my $m4 = $ENV{"M4"} || '@M4@';
++my $m4 = $ENV{"M4"} || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/m4' : '@M4@');
+ # Some non-GNU m4's don't reject the --help option, so give them /dev/null.
+ fatal "need GNU m4 1.4 or later: $m4"
+   if system "$m4 --help </dev/null 2>&1 | grep reload-state >/dev/null";
+@@ -269,6 +273,12 @@ sub load_configuration ($)
+ 
+       my @words = shellwords ($_);
+       my $type = shift @words;
++
++      if ($ENV{'STAGING_DIR'})
++      {
++        @words = map { s!^@pkgdatadir@!$ENV{'STAGING_DIR'}/../host/share/autoconf!; $_ } @words;
++      }
++
+       if ($type eq 'begin-language:')
+ 	{
+ 	  fatal "$file:$.: end-language missing for: $lang"
+--- a/bin/autoreconf.in
++++ b/bin/autoreconf.in
+@@ -1,10 +1,12 @@
+-#! @PERL@ -w
++#! @PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ # autoreconf - install the GNU Build System in a directory tree
+ # Copyright (C) 1994, 1999-2012 Free Software Foundation, Inc.
+ 
+@@ -26,7 +28,8 @@ eval 'case $# in 0) exec @PERL@ -S "$0";
+ 
+ BEGIN
+ {
+-  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
++  my $pkgdatadir = $ENV{'autom4te_perllibdir'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+   unshift @INC, $pkgdatadir;
+ 
+   # Override SHELL.  On DJGPP SHELL may not be set to a shell
+@@ -106,9 +109,9 @@ Written by David J. MacKenzie and Akim D
+ ";
+ 
+ # Lib files.
+-my $autoconf   = $ENV{'AUTOCONF'}   || '@bindir@/@autoconf-name@';
+-my $autoheader = $ENV{'AUTOHEADER'} || '@bindir@/@autoheader-name@';
+-my $autom4te   = $ENV{'AUTOM4TE'}   || '@bindir@/@autom4te-name@';
++my $autoconf   = $ENV{'AUTOCONF'}   || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/@autoconf-name@' : '@bindir@/@autoconf-name@');
++my $autoheader = $ENV{'AUTOHEADER'} || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/@autoheader-name@' : '@bindir@/@autoheader-name@');
++my $autom4te   = $ENV{'AUTOM4TE'}   || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/@autom4te-name@' : '@bindir@/@autom4te-name@');
+ my $automake   = $ENV{'AUTOMAKE'}   || 'automake';
+ my $aclocal    = $ENV{'ACLOCAL'}    || 'aclocal';
+ my $libtoolize = $ENV{'LIBTOOLIZE'} || 'libtoolize';
+--- a/bin/autoscan.in
++++ b/bin/autoscan.in
+@@ -1,4 +1,4 @@
+-#! @PERL@ -w
++#! @PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+@@ -23,9 +23,12 @@
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ BEGIN
+ {
+-  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
++  my $pkgdatadir = $ENV{'autom4te_perllibdir'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+   unshift @INC, $pkgdatadir;
+ 
+   # Override SHELL.  On DJGPP SHELL may not be set to a shell
+@@ -91,10 +94,10 @@ my $configure_scan = 'configure.scan';
+ my $log;
+ 
+ # Autoconf and lib files.
+-my $autom4te = $ENV{'AUTOM4TE'} || '@bindir@/@autom4te-name@';
++my $autom4te = $ENV{'AUTOM4TE'} || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/@autom4te-name@' : '@bindir@/@autom4te-name@');
+ my $autoconf = "$autom4te --language=autoconf";
+ my @prepend_include;
+-my @include = ('@pkgdatadir@');
++my @include = ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+ 
+ # $help
+ # -----
+--- a/bin/autoupdate.in
++++ b/bin/autoupdate.in
+@@ -1,4 +1,4 @@
+-#! @PERL@ -w
++#! @PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+@@ -24,9 +24,12 @@
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ BEGIN
+ {
+-  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
++  my $pkgdatadir = $ENV{'autom4te_perllibdir'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+   unshift @INC, $pkgdatadir;
+ 
+   # Override SHELL.  On DJGPP SHELL may not be set to a shell
+@@ -50,10 +53,10 @@ my $autom4te = $ENV{'AUTOM4TE'} || '@bin
+ my $autoconf = "$autom4te --language=autoconf";
+ # We need to find m4sugar.
+ my @prepend_include;
+-my @include = ('@pkgdatadir@');
++my @include = ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+ my $force = 0;
+ # m4.
+-my $m4 = $ENV{"M4"} || '@M4@';
++my $m4 = $ENV{"M4"} || ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/bin/m4' : '@M4@');
+ 
+ 
+ # $HELP
+--- a/bin/ifnames.in
++++ b/bin/ifnames.in
+@@ -1,10 +1,12 @@
+-#! @PERL@ -w
++#! @PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ # ifnames - print the identifiers used in C preprocessor conditionals
+ 
+ # Copyright (C) 1994-1995, 1999-2003, 2005-2012 Free Software
+@@ -31,7 +33,8 @@ eval 'case $# in 0) exec @PERL@ -S "$0";
+ 
+ BEGIN
+ {
+-  my $pkgdatadir = $ENV{'autom4te_perllibdir'} || '@pkgdatadir@';
++  my $pkgdatadir = $ENV{'autom4te_perllibdir'} ||
++	($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/autoconf' : '@pkgdatadir@');
+   unshift @INC, $pkgdatadir;
+ 
+   # Override SHELL.  On DJGPP SHELL may not be set to a shell
+--- a/bin/autoconf.as
++++ b/bin/autoconf.as
+@@ -84,7 +84,11 @@ exit_missing_arg='
+ # restore font-lock: '
+ 
+ # Variables.
+-: ${AUTOM4TE='@bindir@/@autom4te-name@'}
++if test -n "$STAGING_DIR"; then
++	: ${AUTOM4TE="$STAGING_DIR/../host/bin/@autom4te-name@"}
++else
++	: ${AUTOM4TE='@bindir@/@autom4te-name@'}
++fi
+ autom4te_options=
+ outfile=
+ verbose=false
diff --git a/tools/autoconf/patches/001-no_emacs_lib.patch b/tools/autoconf/patches/001-no_emacs_lib.patch
new file mode 100644
index 0000000000..35c51642e8
--- /dev/null
+++ b/tools/autoconf/patches/001-no_emacs_lib.patch
@@ -0,0 +1,22 @@
+--- a/lib/Makefile.am
++++ b/lib/Makefile.am
+@@ -15,7 +15,7 @@
+ # You should have received a copy of the GNU General Public License
+ # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ 
+-SUBDIRS = Autom4te m4sugar autoconf autotest autoscan emacs
++SUBDIRS = Autom4te m4sugar autoconf autotest autoscan
+ nodist_pkgdata_DATA = autom4te.cfg
+ EXTRA_DIST = autom4te.in freeze.mk
+ 
+--- a/lib/Makefile.in
++++ b/lib/Makefile.in
+@@ -225,7 +225,7 @@ target_alias = @target_alias@
+ top_build_prefix = @top_build_prefix@
+ top_builddir = @top_builddir@
+ top_srcdir = @top_srcdir@
+-SUBDIRS = Autom4te m4sugar autoconf autotest autoscan emacs
++SUBDIRS = Autom4te m4sugar autoconf autotest autoscan
+ nodist_pkgdata_DATA = autom4te.cfg
+ EXTRA_DIST = autom4te.in freeze.mk
+ edit = sed \
diff --git a/tools/autoconf/patches/002-musl_host_fixup.patch b/tools/autoconf/patches/002-musl_host_fixup.patch
new file mode 100644
index 0000000000..4dcb1ec3c1
--- /dev/null
+++ b/tools/autoconf/patches/002-musl_host_fixup.patch
@@ -0,0 +1,24 @@
+--- a/build-aux/config.sub
++++ b/build-aux/config.sub
+@@ -122,9 +122,9 @@ esac
+ # Here we must recognize all the valid KERNEL-OS combinations.
+ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+ case $maybe_os in
+-  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+-  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+-  knetbsd*-gnu* | netbsd*-gnu* | \
++  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-musl* | \
++  linux-newlib* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
++  kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+   kopensolaris*-gnu* | \
+   storm-chaos* | os2-emx* | rtmk-nova*)
+     os=-$maybe_os
+@@ -1360,7 +1360,7 @@ case $os in
+ 	      | -chorusos* | -chorusrdb* | -cegcc* \
+ 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ 	      | -mingw32* | -linux-gnu* | -linux-android* \
+-	      | -linux-newlib* | -linux-uclibc* \
++	      | -linux-musl* | -linux-newlib* | -linux-uclibc* \
+ 	      | -uxpv* | -beos* | -mpeix* | -udk* \
+ 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
diff --git a/tools/automake/Makefile b/tools/automake/Makefile
new file mode 100644
index 0000000000..0eea101983
--- /dev/null
+++ b/tools/automake/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=automake
+PKG_VERSION:=1.15
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/automake
+PKG_MD5SUM:=9a1ddb0e053474d9d1105cfe39b0c48d
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS += \
+	--datarootdir=$(STAGING_DIR_HOST)/share \
+	--disable-silent-rules
+
+HOST_CONFIGURE_VARS += \
+	PERL="/usr/bin/env perl" \
+	am_cv_prog_PERL_ithreads=no
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR); $(AM_TOOL_PATHS) STAGING_DIR="" ./bootstrap.sh)
+	$(call Host/Configure/Default)
+endef
+
+define Host/Install
+	# remove old automake resources to avoid version conflicts
+	rm -rf $(STAGING_DIR_HOST)/share/aclocal-[0-9]*
+	rm -rf $(STAGING_DIR_HOST)/share/automake-[0-9]*
+	$(MAKE) -C $(HOST_BUILD_DIR) install
+	mv $(STAGING_DIR_HOST)/bin/aclocal $(STAGING_DIR_HOST)/bin/aclocal.real
+	$(INSTALL_BIN) ./files/aclocal $(STAGING_DIR_HOST)/bin
+	ln -sf aclocal $(STAGING_DIR_HOST)/bin/aclocal-1.9
+	ln -sf aclocal $(STAGING_DIR_HOST)/bin/aclocal-1.10
+	ln -sf aclocal $(STAGING_DIR_HOST)/bin/aclocal-1.11
+	ln -sf aclocal $(STAGING_DIR_HOST)/bin/aclocal-1.11.6
+	ln -sf aclocal $(STAGING_DIR_HOST)/bin/aclocal-1.15
+endef
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/automake/files/aclocal b/tools/automake/files/aclocal
new file mode 100755
index 0000000000..a60df10c42
--- /dev/null
+++ b/tools/automake/files/aclocal
@@ -0,0 +1,2 @@
+#!/usr/bin/env sh
+aclocal.real $ACLOCAL_INCLUDE $@
diff --git a/tools/automake/patches/000-relocatable.patch b/tools/automake/patches/000-relocatable.patch
new file mode 100644
index 0000000000..59864f2ad5
--- /dev/null
+++ b/tools/automake/patches/000-relocatable.patch
@@ -0,0 +1,96 @@
+--- a/lib/Automake/Config.in
++++ b/lib/Automake/Config.in
+@@ -32,7 +32,7 @@ our $PACKAGE = '@PACKAGE@';
+ our $PACKAGE_BUGREPORT = '@PACKAGE_BUGREPORT@';
+ our $VERSION = '@VERSION@';
+ our $RELEASE_YEAR = '@RELEASE_YEAR@';
+-our $libdir = '@datadir@/@PACKAGE@-@APIVERSION@';
++our $libdir = $ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/@PACKAGE@-@APIVERSION@' : '@datadir@/@PACKAGE@-@APIVERSION@';
+ 
+ our $perl_threads = 0;
+ # We need at least this version for CLONE support.
+--- a/bin/aclocal.in
++++ b/bin/aclocal.in
+@@ -1,10 +1,12 @@
+-#!@PERL@ -w
++#!@PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ # aclocal - create aclocal.m4 by scanning configure.ac
+ 
+ # Copyright (C) 1996-2014 Free Software Foundation, Inc.
+@@ -27,7 +29,7 @@ eval 'case $# in 0) exec @PERL@ -S "$0";
+ 
+ BEGIN
+ {
+-  @Aclocal::perl_libdirs = ('@datadir@/@PACKAGE@-@APIVERSION@')
++  @Aclocal::perl_libdirs = ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/@PACKAGE@-@APIVERSION@' : '@datadir@/@PACKAGE@-@APIVERSION@')
+     unless @Aclocal::perl_libdirs;
+   unshift @INC, @Aclocal::perl_libdirs;
+ }
+@@ -69,8 +71,8 @@ $perl_threads = 0;
+ # ACLOCAL_PATH environment variable, and reset with the '--system-acdir'
+ # option.
+ my @user_includes = ();
+-my @automake_includes = ("@datadir@/aclocal-$APIVERSION");
+-my @system_includes = ('@datadir@/aclocal');
++my @automake_includes = ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . "/../host/share/aclocal-$APIVERSION" : "@datadir@/aclocal-$APIVERSION");
++my @system_includes = ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/aclocal' : '@datadir@/aclocal');
+ 
+ # Whether we should copy M4 file in $user_includes[0].
+ my $install = 0;
+--- a/bin/automake.in
++++ b/bin/automake.in
+@@ -1,10 +1,12 @@
+-#!@PERL@ -w
++#!@PERL@
+ # -*- perl -*-
+ # @configure_input@
+ 
+ eval 'case $# in 0) exec @PERL@ -S "$0";; *) exec @PERL@ -S "$0" "$@";; esac'
+     if 0;
+ 
++$^W = 1;
++
+ # automake - create Makefile.in from Makefile.am
+ # Copyright (C) 1994-2014 Free Software Foundation, Inc.
+ 
+@@ -31,7 +33,7 @@ use strict;
+ 
+ BEGIN
+ {
+-  @Automake::perl_libdirs = ('@datadir@/@PACKAGE@-@APIVERSION@')
++  @Automake::perl_libdirs = ($ENV{'STAGING_DIR'} ? $ENV{'STAGING_DIR'} . '/../host/share/@PACKAGE@-@APIVERSION@' : '@datadir@/@PACKAGE@-@APIVERSION@')
+     unless @Automake::perl_libdirs;
+   unshift @INC, @Automake::perl_libdirs;
+ 
+--- a/t/wrap/aclocal.in
++++ b/t/wrap/aclocal.in
+@@ -1,6 +1,8 @@
+-#!@PERL@ -w
++#!@PERL@
+ # @configure_input@
+ 
++$^W = 1;
++
+ # Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ 
+ # This program is free software; you can redistribute it and/or modify
+--- a/t/wrap/automake.in
++++ b/t/wrap/automake.in
+@@ -1,6 +1,8 @@
+-#!@PERL@ -w
++#!@PERL@
+ # @configure_input@
+ 
++$^W = 1;
++
+ # Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ 
+ # This program is free software; you can redistribute it and/or modify
diff --git a/tools/automake/patches/100-aclocal-skip-not-existing-directories.patch b/tools/automake/patches/100-aclocal-skip-not-existing-directories.patch
new file mode 100644
index 0000000000..ad019ddd1a
--- /dev/null
+++ b/tools/automake/patches/100-aclocal-skip-not-existing-directories.patch
@@ -0,0 +1,15 @@
+--- a/bin/aclocal.in
++++ b/bin/aclocal.in
+@@ -356,6 +356,12 @@ sub scan_m4_dirs ($$@)
+ 
+   foreach my $m4dir (@dirlist)
+     {
++      if (! -d $m4dir)
++        {
++          msg ('override', "warning: skipping not existing directory `$m4dir'");
++          next;
++        }
++
+       if (! opendir (DIR, $m4dir))
+ 	{
+ 	  # TODO: maybe avoid complaining only if errno == ENONENT?
diff --git a/tools/automake/patches/200-do-not-override-silent-rules.patch b/tools/automake/patches/200-do-not-override-silent-rules.patch
new file mode 100644
index 0000000000..e8ba8c5ca5
--- /dev/null
+++ b/tools/automake/patches/200-do-not-override-silent-rules.patch
@@ -0,0 +1,13 @@
+diff -ruN automake-1.15/m4/silent.m4 automake-1.15.mod/m4/silent.m4
+--- automake-1.15/m4/silent.m4	2014-12-30 22:53:05.000000000 +0100
++++ automake-1.15.mod/m4/silent.m4	2015-03-11 12:00:26.280586399 +0100
+@@ -41,7 +41,8 @@
+ else
+   am_cv_make_support_nested_variables=no
+ fi])
+-if test $am_cv_make_support_nested_variables = yes; then
++#if test $am_cv_make_support_nested_variables = yes; then
++if false; then
+   dnl Using '$V' instead of '$(V)' breaks IRIX make.
+   AM_V='$(V)'
+   AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
diff --git a/tools/bc/Makefile b/tools/bc/Makefile
new file mode 100644
index 0000000000..2e99b43643
--- /dev/null
+++ b/tools/bc/Makefile
@@ -0,0 +1,21 @@
+# 
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bc
+PKG_VERSION:=1.06.95
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://alpha.gnu.org/gnu/bc \
+	http://gnualpha.uib.no/bc/ \
+	http://mirrors.fe.up.pt/pub/gnu-alpha/bc/ \
+	http://www.nic.funet.fi/pub/gnu/alpha/gnu/bc/
+PKG_MD5SUM:=5126a721b73f97d715bb72c13c889035
+
+include $(INCLUDE_DIR)/host-build.mk
+
+$(eval $(call HostBuild))
diff --git a/tools/bc/patches/001-no_doc.patch b/tools/bc/patches/001-no_doc.patch
new file mode 100644
index 0000000000..50deee8c89
--- /dev/null
+++ b/tools/bc/patches/001-no_doc.patch
@@ -0,0 +1,23 @@
+diff -urN bc-1.06.95/Makefile.am bc-1.06.95.new/Makefile.am
+--- bc-1.06.95/Makefile.am	2005-05-27 01:05:41.000000000 +0100
++++ bc-1.06.95.new/Makefile.am	2013-07-09 09:33:31.521490710 +0100
+@@ -1,6 +1,6 @@
+ ## Process this file with automake to produce Makefile.in
+ 
+-SUBDIRS = lib bc dc doc
++SUBDIRS = lib bc dc
+ 
+ MAINTAINERCLEANFILES =  aclocal.m4 config.h.in configure Makefile.in \
+ 			stamp-h $(distdir).tar.gz h/number.h depcomp missing
+diff -urN bc-1.06.95/Makefile.in bc-1.06.95.new/Makefile.in
+--- bc-1.06.95/Makefile.in	2006-09-05 03:39:30.000000000 +0100
++++ bc-1.06.95.new/Makefile.in	2013-07-09 09:33:28.565490767 +0100
+@@ -149,7 +149,7 @@
+ sharedstatedir = @sharedstatedir@
+ sysconfdir = @sysconfdir@
+ target_alias = @target_alias@
+-SUBDIRS = lib bc dc doc
++SUBDIRS = lib bc dc
+ MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in \
+ 			stamp-h $(distdir).tar.gz h/number.h depcomp missing
+ 
diff --git a/tools/bison/Makefile b/tools/bison/Makefile
new file mode 100644
index 0000000000..b8ad32c561
--- /dev/null
+++ b/tools/bison/Makefile
@@ -0,0 +1,30 @@
+# 
+# Copyright (C) 2008-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=bison
+PKG_VERSION:=3.0.4
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=c342201de104cc9ce0a21e0ad10d4021
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+define Host/Install
+	$(call Host/Install/Default)
+	$(INSTALL_BIN) ./scripts/yacc $(STAGING_DIR_HOST)/bin/yacc
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/bison/patches/010-intl-stub-compat.patch b/tools/bison/patches/010-intl-stub-compat.patch
new file mode 100644
index 0000000000..98234209cd
--- /dev/null
+++ b/tools/bison/patches/010-intl-stub-compat.patch
@@ -0,0 +1,15 @@
+--- a/src/main.c
++++ b/src/main.c
+@@ -60,9 +60,9 @@
+ {
+   set_program_name (argv[0]);
+   setlocale (LC_ALL, "");
+-  (void) bindtextdomain (PACKAGE, LOCALEDIR);
+-  (void) bindtextdomain ("bison-runtime", LOCALEDIR);
+-  (void) textdomain (PACKAGE);
++  bindtextdomain (PACKAGE, LOCALEDIR);
++  bindtextdomain ("bison-runtime", LOCALEDIR);
++  textdomain (PACKAGE);
+ 
+   {
+     char const *cp = getenv ("LC_CTYPE");
diff --git a/tools/bison/patches/100-fix-gets-removal.patch b/tools/bison/patches/100-fix-gets-removal.patch
new file mode 100644
index 0000000000..20b18cf2e7
--- /dev/null
+++ b/tools/bison/patches/100-fix-gets-removal.patch
@@ -0,0 +1,16 @@
+--- a/lib/stdio.in.h
++++ b/lib/stdio.in.h
+@@ -719,13 +719,6 @@
+ # endif
+ #endif
+ 
+-/* It is very rare that the developer ever has full control of stdin,
+-   so any use of gets warrants an unconditional warning; besides, C11
+-   removed it.  */
+-#undef gets
+-#if HAVE_RAW_DECL_GETS
+-_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+-#endif
+ 
+ 
+ #if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
diff --git a/tools/bison/scripts/yacc b/tools/bison/scripts/yacc
new file mode 100755
index 0000000000..8f73e26fb1
--- /dev/null
+++ b/tools/bison/scripts/yacc
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec bison -y "$@"
diff --git a/tools/ccache/Makefile b/tools/ccache/Makefile
new file mode 100644
index 0000000000..2dbf03ce82
--- /dev/null
+++ b/tools/ccache/Makefile
@@ -0,0 +1,35 @@
+# 
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+PKG_NAME:=ccache
+PKG_VERSION:=3.3.2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=http://samba.org/ftp/ccache/
+PKG_MD5SUM:=2767d8f88f5ec218983a2f05c9e20df2
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_VARS += CC="$(HOSTCC_NOCACHE)"
+
+define Host/Install/ccache
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin/
+	$(CP) ./files/* $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+define Host/Install
+	$(call Host/Install/Default)
+	$(call Host/Install/ccache)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/ccache/files/ccache_cc b/tools/ccache/files/ccache_cc
new file mode 100755
index 0000000000..01c4ad42a2
--- /dev/null
+++ b/tools/ccache/files/ccache_cc
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec ccache "${TARGET_CC_NOCACHE}" "$@"
diff --git a/tools/ccache/files/ccache_cxx b/tools/ccache/files/ccache_cxx
new file mode 100755
index 0000000000..cc60eb3a13
--- /dev/null
+++ b/tools/ccache/files/ccache_cxx
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec ccache "${TARGET_CXX_NOCACHE}" "$@"
diff --git a/tools/ccache/patches/100-honour-copts.patch b/tools/ccache/patches/100-honour-copts.patch
new file mode 100644
index 0000000000..fc82aa4614
--- /dev/null
+++ b/tools/ccache/patches/100-honour-copts.patch
@@ -0,0 +1,12 @@
+diff --git a/ccache.c b/ccache.c
+index 88e0ec5..7dffeb4 100644
+--- a/ccache.c
++++ b/ccache.c
+@@ -1762,6 +1762,7 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
+ 			"CPLUS_INCLUDE_PATH",
+ 			"OBJC_INCLUDE_PATH",
+ 			"OBJCPLUS_INCLUDE_PATH", // clang
++			"GCC_HONOUR_COPTS",
+ 			NULL
+ 		};
+ 		for (const char **p = envvars; *p; ++p) {
diff --git a/tools/ccache/patches/110-disable-assembler-support.patch b/tools/ccache/patches/110-disable-assembler-support.patch
new file mode 100644
index 0000000000..3e6cd8cac7
--- /dev/null
+++ b/tools/ccache/patches/110-disable-assembler-support.patch
@@ -0,0 +1,32 @@
+--- a/language.c
++++ b/language.c
+@@ -37,14 +37,18 @@ static const struct {
+ 	{".m",   "objective-c"},
+ 	{".M",   "objective-c++"},
+ 	{".mm",  "objective-c++"},
++#if 0
+ 	{".sx",  "assembler-with-cpp"},
+ 	{".S",   "assembler-with-cpp"},
++#endif
+ 	// Preprocessed:
+ 	{".i",   "cpp-output"},
+ 	{".ii",  "c++-cpp-output"},
+ 	{".mi",  "objective-c-cpp-output"},
+ 	{".mii", "objective-c++-cpp-output"},
++#if 0
+ 	{".s",   "assembler"},
++#endif
+ 	// Header file (for precompilation):
+ 	{".h",   "c-header"},
+ 	{".H",   "c++-header"},
+@@ -109,8 +113,10 @@ static const struct {
+ 	{"objective-c++-header",     "objective-c++-cpp-output"},
+ 	{"objective-c++-cpp-output", "objective-c++-cpp-output"},
+ 	{"cuda",                     "cuda-output"},
++#if 0
+ 	{"assembler-with-cpp",       "assembler"},
+ 	{"assembler",                "assembler"},
++#endif
+ 	{"f77-cpp-input",            "f77"},
+ 	{"f77",                      "f77"},
+ #if 0 // Could generate module files, ignore for now!
diff --git a/tools/cloog/Makefile b/tools/cloog/Makefile
new file mode 100644
index 0000000000..b1e6aa4398
--- /dev/null
+++ b/tools/cloog/Makefile
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=cloog
+PKG_VERSION:=0.18.1
+
+PKG_SOURCE_URL:=http://www.bastoul.net/cloog/pages/download/
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_MD5SUM:=e34fca0540d840e5d0f6427e98c92252
+
+HOST_FIXUP:=autoreconf
+
+HOST_BUILD_PARALLEL:=1
+HOST_CONFIGURE_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport CFLAGS
+
+HOST_CONFIGURE_VARS += \
+	LIBS=-lstdc++
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static \
+	--disable-shared \
+	--with-ppl=$(BUILD_DIR_HOST)
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR)/$(3); \
+		$(HOST_CONFIGURE_CMD) \
+		$(HOST_CONFIGURE_VARS) \
+		$(HOST_CONFIGURE_ARGS); \
+	)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/cmake/Makefile b/tools/cmake/Makefile
new file mode 100644
index 0000000000..489c27f1d8
--- /dev/null
+++ b/tools/cmake/Makefile
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=cmake
+PKG_VERSION:=3.7.0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://cmake.org/files/v3.7/ \
+		https://fossies.org/linux/misc/
+PKG_MD5SUM:=3801dc4e54c1c957a7378d8b0d4254ba
+
+HOST_BUILD_PARALLEL:=1
+HOST_CONFIGURE_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_CMD := MAKEFLAGS="$(HOST_JOBS)" $(BASH) ./configure
+
+HOST_CONFIGURE_VARS :=
+
+HOST_CONFIGURE_ARGS := \
+	--prefix=$(STAGING_DIR_HOST)
+
+$(eval $(call HostBuild))
diff --git a/tools/cmake/patches/100-disable_qt_tests.patch b/tools/cmake/patches/100-disable_qt_tests.patch
new file mode 100644
index 0000000000..6f28c435e0
--- /dev/null
+++ b/tools/cmake/patches/100-disable_qt_tests.patch
@@ -0,0 +1,31 @@
+--- a/Tests/RunCMake/CMakeLists.txt
++++ b/Tests/RunCMake/CMakeLists.txt
+@@ -225,15 +225,6 @@ add_RunCMake_test(no_install_prefix)
+ add_RunCMake_test(configure_file)
+ add_RunCMake_test(CTestTimeoutAfterMatch)
+ 
+-find_package(Qt4 QUIET)
+-find_package(Qt5Core QUIET)
+-if (QT4_FOUND AND Qt5Core_FOUND AND NOT Qt5Core_VERSION VERSION_LESS 5.1.0)
+-  add_RunCMake_test(IncompatibleQt)
+-endif()
+-if (QT4_FOUND)
+-  add_RunCMake_test(ObsoleteQtMacros -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE})
+-endif()
+-
+ find_package(PkgConfig QUIET)
+ if(PKG_CONFIG_FOUND)
+   add_RunCMake_test(FindPkgConfig)
+--- a/Tests/CMakeLists.txt
++++ b/Tests/CMakeLists.txt
+@@ -393,10 +393,6 @@ if(BUILD_TESTING)
+ 
+   list(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX})
+ 
+-  if(NOT QT4_FOUND)
+-    find_package(Qt4 QUIET)
+-  endif()
+-
+   if(QT4_FOUND)
+     # test whether the Qt4 which has been found works, on some machines
+     # which run nightly builds there were errors like "wrong file format"
diff --git a/tools/cmake/patches/110-freebsd-compat.patch b/tools/cmake/patches/110-freebsd-compat.patch
new file mode 100644
index 0000000000..c1d4a274d6
--- /dev/null
+++ b/tools/cmake/patches/110-freebsd-compat.patch
@@ -0,0 +1,39 @@
+From 6eab64c3adc7a38c322cd4d9a1a1881f2d49cb9c Mon Sep 17 00:00:00 2001
+From: Raphael Kubo da Costa <rakuco@FreeBSD.org>
+Date: Tue, 15 Oct 2013 00:10:56 +0300
+Subject: [PATCH] SystemInformation: Include backtrace-related headers on
+ FreeBSD
+
+This was probably broken for a long while, but the problem was not apparent
+because the check for execinfo.h would fail by default because
+-I/usr/local/include was not being passed to the compiler when making the
+checks for the header's existence.
+
+Now that very recent FreeBSD versions (ie. 10-CURRENT) have NetBSD's
+libexecinfo in base (and it is thus installed into /usr), the
+backtrace-related checks would pass, but the required headers were not being
+included in SystemInformation.cxx.
+
+Change-Id: I3b91ed7ac0e6878035aee202b3336c536cc6d2ff
+---
+ Source/kwsys/SystemInformation.cxx |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/Source/kwsys/SystemInformation.cxx
++++ b/Source/kwsys/SystemInformation.cxx
+@@ -89,6 +89,15 @@ typedef int siginfo_t;
+ #  include <ifaddrs.h>
+ #  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
+ # endif
++# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
++#  include <execinfo.h>
++#  if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
++#    include <cxxabi.h>
++#  endif
++#  if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
++#    include <dlfcn.h>
++#  endif
++# endif
+ #endif
+ 
+ #if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
diff --git a/tools/cmake/patches/120-alpine_musl-compat.patch b/tools/cmake/patches/120-alpine_musl-compat.patch
new file mode 100644
index 0000000000..ae93201e53
--- /dev/null
+++ b/tools/cmake/patches/120-alpine_musl-compat.patch
@@ -0,0 +1,17 @@
+--- a/Utilities/cmjsoncpp/include/json/assertions.h
++++ b/Utilities/cmjsoncpp/include/json/assertions.h
+@@ -6,12 +6,12 @@
+ #ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+ #define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+ 
++#include <stdlib.h>
++
+ #if !defined(JSON_IS_AMALGAMATION)
+ #include "config.h"
+ #endif // if !defined(JSON_IS_AMALGAMATION)
+ 
+-#include <stdlib.h>
+-
+ #if JSON_USE_EXCEPTION
+ #include <stdexcept>
+ #define JSON_ASSERT(condition)                                                 \
diff --git a/tools/cmake/patches/130-upstream-libarchive-openssl-compat-headers.patch b/tools/cmake/patches/130-upstream-libarchive-openssl-compat-headers.patch
new file mode 100644
index 0000000000..fba8745843
--- /dev/null
+++ b/tools/cmake/patches/130-upstream-libarchive-openssl-compat-headers.patch
@@ -0,0 +1,190 @@
+From 7d433206cf7de8f28aa2d169ed25cd401fcfc413 Mon Sep 17 00:00:00 2001
+From: Brad King <brad.king@kitware.com>
+Date: Thu, 17 Nov 2016 15:26:41 -0500
+Subject: [PATCH] libarchive: Add headers to adapt between OpenSSL 1.1 and older versions
+
+Add private forwarding headers for `openssl/{evp,hmac}.h` to give us a
+central place to add adaptation code to work across multiple
+incompatible OpenSSL versions.  Provide compatibility implementations of
+some OpenSSL 1.1 APIs when using older OpenSSL versions.
+---
+ Utilities/cmlibarchive/libarchive/CMakeLists.txt                 |  2 ++
+ Utilities/cmlibarchive/libarchive/archive_cryptor_private.h      |  2 +-
+ Utilities/cmlibarchive/libarchive/archive_digest_private.h       |  2 +-
+ Utilities/cmlibarchive/libarchive/archive_hmac_private.h         |  2 +-
+ Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h  | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 108 insertions(+), 3 deletions(-)
+ create mode 100644 Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
+ create mode 100644 Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
+
+diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+index 4eeb5e3..eaa7b20 100644
+--- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt
++++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+@@ -38,6 +38,8 @@ SET(libarchive_SOURCES
+   archive_hmac.c
+   archive_hmac_private.h
+   archive_match.c
++  archive_openssl_evp_private.h
++  archive_openssl_hmac_private.h
+   archive_options.c
+   archive_options_private.h
+   archive_pack_dev.h
+diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
+index 37eaad3..1c1a8c0 100644
+--- a/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
+@@ -99,7 +99,7 @@ typedef struct {
+ } archive_crypto_ctx;
+ 
+ #elif defined(HAVE_LIBCRYPTO)
+-#include <openssl/evp.h>
++#include "archive_openssl_evp_private.h"
+ #define AES_BLOCK_SIZE	16
+ #define AES_MAX_KEY_SIZE 32
+ 
+diff --git a/Utilities/cmlibarchive/libarchive/archive_digest_private.h b/Utilities/cmlibarchive/libarchive/archive_digest_private.h
+index 77fad58..00697ae 100644
+--- a/Utilities/cmlibarchive/libarchive/archive_digest_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_digest_private.h
+@@ -134,7 +134,7 @@
+   defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+   defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+ #define	ARCHIVE_CRYPTO_OPENSSL 1
+-#include <openssl/evp.h>
++#include "archive_openssl_evp_private.h"
+ #endif
+ 
+ /* Windows crypto headers */
+diff --git a/Utilities/cmlibarchive/libarchive/archive_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
+index 64de743..f36d694 100644
+--- a/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
+@@ -70,7 +70,7 @@ typedef struct {
+ typedef	struct hmac_sha1_ctx archive_hmac_sha1_ctx;
+ 
+ #elif defined(HAVE_LIBCRYPTO)
+-#include <openssl/hmac.h>
++#include "archive_openssl_hmac_private.h"
+ 
+ typedef	HMAC_CTX archive_hmac_sha1_ctx;
+ 
+diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
+new file mode 100644
+index 0000000..0e97e27
+--- /dev/null
++++ b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
+@@ -0,0 +1,51 @@
++/*-
++ * Copyright (c) 2003-2007 Tim Kientzle
++ * 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 AUTHOR(S) ``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 AUTHOR(S) 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.
++ */
++#ifndef ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED
++#define ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED
++
++#include <openssl/evp.h>
++#include <openssl/opensslv.h>
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#include <stdlib.h> /* malloc, free */
++#include <string.h> /* memset */
++static inline EVP_MD_CTX *EVP_MD_CTX_new(void)
++{
++	EVP_MD_CTX *ctx = (EVP_MD_CTX *)malloc(sizeof(EVP_MD_CTX));
++	if (ctx != NULL) {
++		memset(ctx, 0, sizeof(*ctx));
++	}
++	return ctx;
++}
++
++static inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
++{
++	EVP_MD_CTX_cleanup(ctx);
++	memset(ctx, 0, sizeof(*ctx));
++	free(ctx);
++}
++#endif
++
++#endif
+diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
+new file mode 100644
+index 0000000..d4ae0d1
+--- /dev/null
++++ b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
+@@ -0,0 +1,52 @@
++/*-
++ * Copyright (c) 2003-2007 Tim Kientzle
++ * 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 AUTHOR(S) ``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 AUTHOR(S) 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.
++ */
++#ifndef ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED
++#define ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED
++
++#include <openssl/hmac.h>
++#include <openssl/opensslv.h>
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#include <stdlib.h> /* malloc, free */
++#include <string.h> /* memset */
++static inline HMAC_CTX *HMAC_CTX_new(void)
++{
++	HMAC_CTX *ctx = (HMAC_CTX *)malloc(sizeof(HMAC_CTX));
++	if (ctx != NULL) {
++		memset(ctx, 0, sizeof(*ctx));
++		HMAC_CTX_init(ctx);
++	}
++	return ctx;
++}
++
++static inline void HMAC_CTX_free(HMAC_CTX *ctx)
++{
++	HMAC_CTX_cleanup(ctx);
++	memset(ctx, 0, sizeof(*ctx));
++	free(ctx);
++}
++#endif
++
++#endif
+--
+libgit2 0.24.0
+
diff --git a/tools/cmake/patches/140-upstream-libarchive-openssl-1.1.x-support.patch b/tools/cmake/patches/140-upstream-libarchive-openssl-1.1.x-support.patch
new file mode 100644
index 0000000000..de0490248b
--- /dev/null
+++ b/tools/cmake/patches/140-upstream-libarchive-openssl-1.1.x-support.patch
@@ -0,0 +1,379 @@
+From 6f23daea4391c2db8bc27d2e4cb42eac02368822 Mon Sep 17 00:00:00 2001
+From: Brad King <brad.king@kitware.com>
+Date: Thu, 17 Nov 2016 15:44:44 -0500
+Subject: [PATCH] libarchive: Add support for building with OpenSSL 1.1
+
+OpenSSL 1.1 made some CTX structures opaque.  Port our code to use the
+structures only through pointers via OpenSSL 1.1 APIs.  Use our adaption
+layer to make this work with OpenSSL 1.0 and below.
+
+Patch-by: Tomas Mraz <tmraz@redhat.com>
+Patch-from: https://bugzilla.redhat.com/1383744
+---
+ Utilities/cmlibarchive/libarchive/archive_cryptor.c         |  9 +++++----
+ Utilities/cmlibarchive/libarchive/archive_cryptor_private.h |  2 +-
+ Utilities/cmlibarchive/libarchive/archive_digest.c          | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
+ Utilities/cmlibarchive/libarchive/archive_digest_private.h  | 12 ++++++------
+ Utilities/cmlibarchive/libarchive/archive_hmac.c            | 14 ++++++++------
+ Utilities/cmlibarchive/libarchive/archive_hmac_private.h    |  2 +-
+ 6 files changed, 75 insertions(+), 38 deletions(-)
+
+--- a/Utilities/cmlibarchive/libarchive/archive_cryptor.c
++++ b/Utilities/cmlibarchive/libarchive/archive_cryptor.c
+@@ -302,6 +302,7 @@ aes_ctr_release(archive_crypto_ctx *ctx)
+ static int
+ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+ {
++	ctx->ctx = EVP_CIPHER_CTX_new();
+ 
+ 	switch (key_len) {
+ 	case 16: ctx->type = EVP_aes_128_ecb(); break;
+@@ -314,7 +315,7 @@ aes_ctr_init(archive_crypto_ctx *ctx, co
+ 	memcpy(ctx->key, key, key_len);
+ 	memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ 	ctx->encr_pos = AES_BLOCK_SIZE;
+-	EVP_CIPHER_CTX_init(&ctx->ctx);
++	EVP_CIPHER_CTX_init(ctx->ctx);
+ 	return 0;
+ }
+ 
+@@ -324,10 +325,10 @@ aes_ctr_encrypt_counter(archive_crypto_c
+ 	int outl = 0;
+ 	int r;
+ 
+-	r = EVP_EncryptInit_ex(&ctx->ctx, ctx->type, NULL, ctx->key, NULL);
++	r = EVP_EncryptInit_ex(ctx->ctx, ctx->type, NULL, ctx->key, NULL);
+ 	if (r == 0)
+ 		return -1;
+-	r = EVP_EncryptUpdate(&ctx->ctx, ctx->encr_buf, &outl, ctx->nonce,
++	r = EVP_EncryptUpdate(ctx->ctx, ctx->encr_buf, &outl, ctx->nonce,
+ 	    AES_BLOCK_SIZE);
+ 	if (r == 0 || outl != AES_BLOCK_SIZE)
+ 		return -1;
+@@ -337,7 +338,7 @@ aes_ctr_encrypt_counter(archive_crypto_c
+ static int
+ aes_ctr_release(archive_crypto_ctx *ctx)
+ {
+-	EVP_CIPHER_CTX_cleanup(&ctx->ctx);
++	EVP_CIPHER_CTX_free(ctx->ctx);
+ 	memset(ctx->key, 0, ctx->key_len);
+ 	memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ 	return 0;
+--- a/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
+@@ -104,7 +104,7 @@ typedef struct {
+ #define AES_MAX_KEY_SIZE 32
+ 
+ typedef struct {
+-	EVP_CIPHER_CTX	ctx;
++	EVP_CIPHER_CTX	*ctx;
+ 	const EVP_CIPHER *type;
+ 	uint8_t		key[AES_MAX_KEY_SIZE];
+ 	unsigned	key_len;
+--- a/Utilities/cmlibarchive/libarchive/archive_digest.c
++++ b/Utilities/cmlibarchive/libarchive/archive_digest.c
+@@ -207,7 +207,9 @@ __archive_nettle_md5final(archive_md5_ct
+ static int
+ __archive_openssl_md5init(archive_md5_ctx *ctx)
+ {
+-  EVP_DigestInit(ctx, EVP_md5());
++  if ((*ctx = EVP_MD_CTX_new()) == NULL)
++	return (ARCHIVE_FAILED);
++  EVP_DigestInit(*ctx, EVP_md5());
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -215,7 +217,7 @@ static int
+ __archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
+     size_t insize)
+ {
+-  EVP_DigestUpdate(ctx, indata, insize);
++  EVP_DigestUpdate(*ctx, indata, insize);
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -226,8 +228,11 @@ __archive_openssl_md5final(archive_md5_c
+    * this is meant to cope with that. Real fix is probably to fix
+    * archive_write_set_format_xar.c
+    */
+-  if (ctx->digest)
+-    EVP_DigestFinal(ctx, md, NULL);
++  if (*ctx) {
++    EVP_DigestFinal(*ctx, md, NULL);
++    EVP_MD_CTX_free(*ctx);
++    *ctx = NULL;
++  }
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -359,7 +364,9 @@ __archive_nettle_ripemd160final(archive_
+ static int
+ __archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
+ {
+-  EVP_DigestInit(ctx, EVP_ripemd160());
++  if ((*ctx = EVP_MD_CTX_new()) == NULL)
++	return (ARCHIVE_FAILED);
++  EVP_DigestInit(*ctx, EVP_ripemd160());
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -367,14 +374,18 @@ static int
+ __archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+     size_t insize)
+ {
+-  EVP_DigestUpdate(ctx, indata, insize);
++  EVP_DigestUpdate(*ctx, indata, insize);
+   return (ARCHIVE_OK);
+ }
+ 
+ static int
+ __archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+ {
+-  EVP_DigestFinal(ctx, md, NULL);
++  if (*ctx) {
++    EVP_DigestFinal(*ctx, md, NULL);
++    EVP_MD_CTX_free(*ctx);
++    *ctx = NULL;
++  }
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -509,7 +520,9 @@ __archive_nettle_sha1final(archive_sha1_
+ static int
+ __archive_openssl_sha1init(archive_sha1_ctx *ctx)
+ {
+-  EVP_DigestInit(ctx, EVP_sha1());
++  if ((*ctx = EVP_MD_CTX_new()) == NULL)
++	return (ARCHIVE_FAILED);
++  EVP_DigestInit(*ctx, EVP_sha1());
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -517,7 +530,7 @@ static int
+ __archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
+     size_t insize)
+ {
+-  EVP_DigestUpdate(ctx, indata, insize);
++  EVP_DigestUpdate(*ctx, indata, insize);
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -528,8 +541,11 @@ __archive_openssl_sha1final(archive_sha1
+    * this is meant to cope with that. Real fix is probably to fix
+    * archive_write_set_format_xar.c
+    */
+-  if (ctx->digest)
+-    EVP_DigestFinal(ctx, md, NULL);
++  if (*ctx) {
++    EVP_DigestFinal(*ctx, md, NULL);
++    EVP_MD_CTX_free(*ctx);
++    *ctx = NULL;
++  }
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -733,7 +749,9 @@ __archive_nettle_sha256final(archive_sha
+ static int
+ __archive_openssl_sha256init(archive_sha256_ctx *ctx)
+ {
+-  EVP_DigestInit(ctx, EVP_sha256());
++  if ((*ctx = EVP_MD_CTX_new()) == NULL)
++	return (ARCHIVE_FAILED);
++  EVP_DigestInit(*ctx, EVP_sha256());
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -741,14 +759,18 @@ static int
+ __archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
+     size_t insize)
+ {
+-  EVP_DigestUpdate(ctx, indata, insize);
++  EVP_DigestUpdate(*ctx, indata, insize);
+   return (ARCHIVE_OK);
+ }
+ 
+ static int
+ __archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
+ {
+-  EVP_DigestFinal(ctx, md, NULL);
++  if (*ctx) {
++    EVP_DigestFinal(*ctx, md, NULL);
++    EVP_MD_CTX_free(*ctx);
++    *ctx = NULL;
++  }
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -928,7 +950,9 @@ __archive_nettle_sha384final(archive_sha
+ static int
+ __archive_openssl_sha384init(archive_sha384_ctx *ctx)
+ {
+-  EVP_DigestInit(ctx, EVP_sha384());
++  if ((*ctx = EVP_MD_CTX_new()) == NULL)
++	return (ARCHIVE_FAILED);
++  EVP_DigestInit(*ctx, EVP_sha384());
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -936,14 +960,18 @@ static int
+ __archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
+     size_t insize)
+ {
+-  EVP_DigestUpdate(ctx, indata, insize);
++  EVP_DigestUpdate(*ctx, indata, insize);
+   return (ARCHIVE_OK);
+ }
+ 
+ static int
+ __archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
+ {
+-  EVP_DigestFinal(ctx, md, NULL);
++  if (*ctx) {
++    EVP_DigestFinal(*ctx, md, NULL);
++    EVP_MD_CTX_free(*ctx);
++    *ctx = NULL;
++  }
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -1147,7 +1175,9 @@ __archive_nettle_sha512final(archive_sha
+ static int
+ __archive_openssl_sha512init(archive_sha512_ctx *ctx)
+ {
+-  EVP_DigestInit(ctx, EVP_sha512());
++  if ((*ctx = EVP_MD_CTX_new()) == NULL)
++	return (ARCHIVE_FAILED);
++  EVP_DigestInit(*ctx, EVP_sha512());
+   return (ARCHIVE_OK);
+ }
+ 
+@@ -1155,14 +1185,18 @@ static int
+ __archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
+     size_t insize)
+ {
+-  EVP_DigestUpdate(ctx, indata, insize);
++  EVP_DigestUpdate(*ctx, indata, insize);
+   return (ARCHIVE_OK);
+ }
+ 
+ static int
+ __archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
+ {
+-  EVP_DigestFinal(ctx, md, NULL);
++  if (*ctx) {
++    EVP_DigestFinal(*ctx, md, NULL);
++    EVP_MD_CTX_free(*ctx);
++    *ctx = NULL;
++  }
+   return (ARCHIVE_OK);
+ }
+ 
+--- a/Utilities/cmlibarchive/libarchive/archive_digest_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_digest_private.h
+@@ -161,7 +161,7 @@ typedef CC_MD5_CTX archive_md5_ctx;
+ #elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+ typedef struct md5_ctx archive_md5_ctx;
+ #elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+-typedef EVP_MD_CTX archive_md5_ctx;
++typedef EVP_MD_CTX *archive_md5_ctx;
+ #elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+ typedef Digest_CTX archive_md5_ctx;
+ #else
+@@ -175,7 +175,7 @@ typedef RIPEMD160_CTX archive_rmd160_ctx
+ #elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+ typedef struct ripemd160_ctx archive_rmd160_ctx;
+ #elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+-typedef EVP_MD_CTX archive_rmd160_ctx;
++typedef EVP_MD_CTX *archive_rmd160_ctx;
+ #else
+ typedef unsigned char archive_rmd160_ctx;
+ #endif
+@@ -189,7 +189,7 @@ typedef CC_SHA1_CTX archive_sha1_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+ typedef struct sha1_ctx archive_sha1_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+-typedef EVP_MD_CTX archive_sha1_ctx;
++typedef EVP_MD_CTX *archive_sha1_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+ typedef Digest_CTX archive_sha1_ctx;
+ #else
+@@ -209,7 +209,7 @@ typedef CC_SHA256_CTX archive_sha256_ctx
+ #elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+ typedef struct sha256_ctx archive_sha256_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+-typedef EVP_MD_CTX archive_sha256_ctx;
++typedef EVP_MD_CTX *archive_sha256_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+ typedef Digest_CTX archive_sha256_ctx;
+ #else
+@@ -227,7 +227,7 @@ typedef CC_SHA512_CTX archive_sha384_ctx
+ #elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+ typedef struct sha384_ctx archive_sha384_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+-typedef EVP_MD_CTX archive_sha384_ctx;
++typedef EVP_MD_CTX *archive_sha384_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+ typedef Digest_CTX archive_sha384_ctx;
+ #else
+@@ -247,7 +247,7 @@ typedef CC_SHA512_CTX archive_sha512_ctx
+ #elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+ typedef struct sha512_ctx archive_sha512_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+-typedef EVP_MD_CTX archive_sha512_ctx;
++typedef EVP_MD_CTX *archive_sha512_ctx;
+ #elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+ typedef Digest_CTX archive_sha512_ctx;
+ #else
+--- a/Utilities/cmlibarchive/libarchive/archive_hmac.c
++++ b/Utilities/cmlibarchive/libarchive/archive_hmac.c
+@@ -176,8 +176,10 @@ __hmac_sha1_cleanup(archive_hmac_sha1_ct
+ static int
+ __hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+ {
+-	HMAC_CTX_init(ctx);
+-	HMAC_Init(ctx, key, key_len, EVP_sha1());
++	*ctx = HMAC_CTX_new();
++	if (*ctx == NULL)
++		return -1;
++	HMAC_Init_ex(*ctx, key, key_len, EVP_sha1(), NULL);
+ 	return 0;
+ }
+ 
+@@ -185,22 +187,22 @@ static void
+ __hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+     size_t data_len)
+ {
+-	HMAC_Update(ctx, data, data_len);
++	HMAC_Update(*ctx, data, data_len);
+ }
+ 
+ static void
+ __hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+ {
+ 	unsigned int len = (unsigned int)*out_len;
+-	HMAC_Final(ctx, out, &len);
++	HMAC_Final(*ctx, out, &len);
+ 	*out_len = len;
+ }
+ 
+ static void
+ __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+ {
+-	HMAC_CTX_cleanup(ctx);
+-	memset(ctx, 0, sizeof(*ctx));
++	HMAC_CTX_free(*ctx);
++	*ctx = NULL;
+ }
+ 
+ #else
+--- a/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
+@@ -72,7 +72,7 @@ typedef	struct hmac_sha1_ctx archive_hma
+ #elif defined(HAVE_LIBCRYPTO)
+ #include "archive_openssl_hmac_private.h"
+ 
+-typedef	HMAC_CTX archive_hmac_sha1_ctx;
++typedef	HMAC_CTX* archive_hmac_sha1_ctx;
+ 
+ #else
+ 
diff --git a/tools/cmake/patches/150-libarchive-fix-libressl-compat.patch b/tools/cmake/patches/150-libarchive-fix-libressl-compat.patch
new file mode 100644
index 0000000000..a56ac2ed0c
--- /dev/null
+++ b/tools/cmake/patches/150-libarchive-fix-libressl-compat.patch
@@ -0,0 +1,22 @@
+--- a/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
+@@ -28,7 +28,7 @@
+ #include <openssl/evp.h>
+ #include <openssl/opensslv.h>
+ 
+-#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ #include <stdlib.h> /* malloc, free */
+ #include <string.h> /* memset */
+ static inline EVP_MD_CTX *EVP_MD_CTX_new(void)
+--- a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
++++ b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
+@@ -28,7 +28,7 @@
+ #include <openssl/hmac.h>
+ #include <openssl/opensslv.h>
+ 
+-#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ #include <stdlib.h> /* malloc, free */
+ #include <string.h> /* memset */
+ static inline HMAC_CTX *HMAC_CTX_new(void)
diff --git a/tools/coreutils/Makefile b/tools/coreutils/Makefile
new file mode 100644
index 0000000000..8e0585044c
--- /dev/null
+++ b/tools/coreutils/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=coreutils
+PKG_VERSION:=8.25
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/coreutils
+PKG_MD5SUM:=070e43ba7f618d747414ef56ab248a48
+
+HOST_BUILD_PARALLEL := 1
+
+BUILD_PROGRAMS = date
+
+include $(INCLUDE_DIR)/host-build.mk
+
+BUILD_BINS = $(patsubst %,src/%,$(BUILD_PROGRAMS))
+
+HOST_CONFIGURE_ARGS += \
+	 --enable-install-program=date
+
+HOST_MAKE_FLAGS += \
+	PROGRAMS="$(BUILD_BINS)" \
+	LIBRARIES= MANS= SUBDIRS=.
+
+define Host/Install
+	$(INSTALL_DIR) $(1)/bin
+	$(CP) $(patsubst %,$(HOST_BUILD_DIR)/%,$(BUILD_BINS)) $(1)/bin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/dosfstools/Makefile b/tools/dosfstools/Makefile
new file mode 100644
index 0000000000..d637a3b4c2
--- /dev/null
+++ b/tools/dosfstools/Makefile
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2012-2015 OpenWrt.org
+# Copyright (C) 2016 LEDE-Project.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dosfstools
+PKG_VERSION:=4.0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=https://github.com/dosfstools/dosfstools/releases/download/v$(PKG_VERSION)/ \
+		http://fossies.org/linux/misc
+PKG_MD5SUM:=9037738953559d1efe04fc5408b6846216cc0138f7f9d32de80b6ec3c35e7daf
+
+HOST_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/host-build.mk
+
+ifeq ($(HOST_OS),Darwin)
+HOST_CFLAGS += -UHAVE_ENDIAN_H
+endif
+
+$(eval $(call HostBuild))
diff --git a/tools/dosfstools/patches/0001-mkfs-Default-to-64-32-heads-sectors-for-targets-smal.patch b/tools/dosfstools/patches/0001-mkfs-Default-to-64-32-heads-sectors-for-targets-smal.patch
new file mode 100644
index 0000000000..76672e0e34
--- /dev/null
+++ b/tools/dosfstools/patches/0001-mkfs-Default-to-64-32-heads-sectors-for-targets-smal.patch
@@ -0,0 +1,34 @@
+From 1e76e5778a1885452939a79d9145b80634a5b023 Mon Sep 17 00:00:00 2001
+From: Andreas Bombe <aeb@debian.org>
+Date: Wed, 11 May 2016 03:44:58 +0200
+Subject: [PATCH] mkfs: Default to 64/32 heads/sectors for targets smaller than
+ 512 MB
+
+This may put defaults in certain use cases a little bit more in line
+with the old defaults in versions up to 3.0.28. It has mostly aesthetic
+value in most cases.
+
+Signed-off-by: Andreas Bombe <aeb@debian.org>
+---
+ src/mkfs.fat.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/src/mkfs.fat.c
++++ b/src/mkfs.fat.c
+@@ -519,6 +519,16 @@ static void establish_params(struct devi
+     unsigned int cluster_size = 4;  /* starting point for FAT12 and FAT16 */
+     int def_root_dir_entries = 512;
+ 
++    if (info->size < 512 * 1024 * 1024) {
++	/*
++	 * These values are more or less meaningless, but we can at least
++	 * use less extreme values for smaller filesystems where the large
++	 * dummy values signifying LBA only access are not needed.
++	 */
++	sec_per_track = 32;
++	heads = 64;
++    }
++
+     if (info->type != TYPE_FIXED) {
+ 	/* enter default parameters for floppy disks if the size matches */
+ 	switch (info->size / 1024) {
diff --git a/tools/dosfstools/patches/0002-Switch-to-AC_CHECK_LIB-for-iconv-library-linking.patch b/tools/dosfstools/patches/0002-Switch-to-AC_CHECK_LIB-for-iconv-library-linking.patch
new file mode 100644
index 0000000000..72a932dfd5
--- /dev/null
+++ b/tools/dosfstools/patches/0002-Switch-to-AC_CHECK_LIB-for-iconv-library-linking.patch
@@ -0,0 +1,27 @@
+From 1c6c135ee15e449c1bf2e76d5307f83a3a1d7425 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Tue, 11 Oct 2016 12:07:48 +0200
+Subject: [PATCH] Switch to AC_CHECK_LIB for iconv library linking.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+AC_SEARCH_LIB doesn't work properly for openwrt/lede when building dosfstools
+as a package.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/configure.ac
++++ b/configure.ac
+@@ -59,7 +59,7 @@ if test "x$with_udev" != "xno"; then
+ 		  [true])
+ fi
+ 
+-AC_SEARCH_LIBS(iconv_open, iconv)
++AC_CHECK_LIB(iconv, iconv_open)
+ 
+ AC_CONFIG_FILES([Makefile src/Makefile src/version.h
+ 		 manpages/Makefile manpages/mkfs.fat.8
diff --git a/tools/e2fsprogs/Makefile b/tools/e2fsprogs/Makefile
new file mode 100644
index 0000000000..ffe1782eb1
--- /dev/null
+++ b/tools/e2fsprogs/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2010-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=e2fsprogs
+PKG_VERSION:=1.43.3
+PKG_MD5SUM:=ec0cd4faac71b2fcf9f73733e4d50ead
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/e2fsprogs
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CFLAGS += $(FPIC)
+
+HOST_CONFIGURE_ARGS += \
+	--disable-elf-shlibs \
+	--enable-libuuid \
+	--disable-tls \
+	--disable-nls
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	rm -rf $(HOST_BUILD_DIR)/doc
+endef
+
+define Host/Install
+	$(Host/Install/Default)
+	$(MAKE) -C $(HOST_BUILD_DIR)/lib/uuid install
+	mkdir -p $(STAGING_DIR_HOST)/include/e2fsprogs
+	$(CP) $(STAGING_DIR_HOST)/include/uuid $(STAGING_DIR_HOST)/include/e2fsprogs/
+	rm -rf $(STAGING_DIR_HOST)/include/uuid
+	$(INSTALL_DATA) $(HOST_BUILD_DIR)/lib/uuid/libuuid.a $(STAGING_DIR_HOST)/lib/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/e2fsck
+	rm -f $(STAGING_DIR_HOST)/bin/tune2fs
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/e2fsprogs/patches/001-exit_0_on_corrected_errors.patch b/tools/e2fsprogs/patches/001-exit_0_on_corrected_errors.patch
new file mode 100644
index 0000000000..67a30f610b
--- /dev/null
+++ b/tools/e2fsprogs/patches/001-exit_0_on_corrected_errors.patch
@@ -0,0 +1,11 @@
+--- a/e2fsck/e2fsck.h
++++ b/e2fsck/e2fsck.h
+@@ -73,7 +73,7 @@
+  * Exit codes used by fsck-type programs
+  */
+ #define FSCK_OK          0	/* No errors */
+-#define FSCK_NONDESTRUCT 1	/* File system errors corrected */
++#define FSCK_NONDESTRUCT 0	/* File system errors corrected */
+ #define FSCK_REBOOT      2	/* System should be rebooted */
+ #define FSCK_UNCORRECTED 4	/* File system errors left uncorrected */
+ #define FSCK_ERROR       8	/* Operational error */
diff --git a/tools/e2fsprogs/patches/002-dont-build-e4defrag.patch b/tools/e2fsprogs/patches/002-dont-build-e4defrag.patch
new file mode 100644
index 0000000000..2a7842f655
--- /dev/null
+++ b/tools/e2fsprogs/patches/002-dont-build-e4defrag.patch
@@ -0,0 +1,11 @@
+--- a/misc/Makefile.in
++++ b/misc/Makefile.in
+@@ -11,7 +11,7 @@ INSTALL = @INSTALL@
+ 
+ @MCONFIG@
+ 
+-@DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_PROG= e4defrag
++@DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_PROG=
+ @DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_MAN= e4defrag.8
+ 
+ @LINUX_CMT@E4CRYPT_PROG = e4crypt
diff --git a/tools/e2fsprogs/patches/003-openbsd-compat.patch b/tools/e2fsprogs/patches/003-openbsd-compat.patch
new file mode 100644
index 0000000000..492b8a8860
--- /dev/null
+++ b/tools/e2fsprogs/patches/003-openbsd-compat.patch
@@ -0,0 +1,12 @@
+--- a/lib/blkid/getsize.c
++++ b/lib/blkid/getsize.c
+@@ -29,6 +29,9 @@
+ #include <fcntl.h>
+ #ifdef HAVE_SYS_IOCTL_H
+ #include <sys/ioctl.h>
++#ifdef __OpenBSD__
++#include <sys/dkio.h>
++#endif
+ #endif
+ #ifdef HAVE_LINUX_FD_H
+ #include <linux/fd.h>
diff --git a/tools/e2fsprogs/patches/004-freebsd-compat.patch b/tools/e2fsprogs/patches/004-freebsd-compat.patch
new file mode 100644
index 0000000000..d102e1cd9c
--- /dev/null
+++ b/tools/e2fsprogs/patches/004-freebsd-compat.patch
@@ -0,0 +1,12 @@
+--- a/lib/ext2fs/tdb.c
++++ b/lib/ext2fs/tdb.c
+@@ -58,7 +58,9 @@ Last Changed Date: 2007-06-22 13:36:10 -
+ #include <utime.h>
+ #endif
+ #include <sys/stat.h>
++#ifndef __FreeBSD__
+ #include <sys/file.h>
++#endif
+ #include <fcntl.h>
+ 
+ #ifdef HAVE_SYS_MMAN_H
diff --git a/tools/e2fsprogs/patches/005-darwin-compat.patch b/tools/e2fsprogs/patches/005-darwin-compat.patch
new file mode 100644
index 0000000000..d84aa121ca
--- /dev/null
+++ b/tools/e2fsprogs/patches/005-darwin-compat.patch
@@ -0,0 +1,22 @@
+--- a/lib/blkid/blkid_types.h.in
++++ b/lib/blkid/blkid_types.h.in
+@@ -9,6 +9,8 @@
+ 
+ @ASM_TYPES_HEADER@
+ 
++#include <stdint.h>
++
+ #ifndef HAVE___U8
+ #define HAVE___U8
+ #ifdef __U8_TYPEDEF
+--- a/lib/ext2fs/ext2_types.h.in
++++ b/lib/ext2fs/ext2_types.h.in
+@@ -9,6 +9,8 @@
+ 
+ @ASM_TYPES_HEADER@
+ 
++#include <stdint.h>
++
+ #ifndef HAVE___U8
+ #define HAVE___U8
+ #ifdef __U8_TYPEDEF
diff --git a/tools/e2fsprogs/patches/010-old-libmagic.patch b/tools/e2fsprogs/patches/010-old-libmagic.patch
new file mode 100644
index 0000000000..9156b73372
--- /dev/null
+++ b/tools/e2fsprogs/patches/010-old-libmagic.patch
@@ -0,0 +1,25 @@
+From b482eb7af94885b6bbad9329e40702c958d5b448 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 30 Jun 2016 19:53:03 +0200
+Subject: [PATCH] fix build problem with very old libmagic
+
+The libmagic shipped with RedHat 5 does not define
+MAGIC_NO_CHECK_ELF and MAGIC_NO_CHECK_COMPRESS. e2fsprogs should
+check for that otherwise the build will fail.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ lib/support/plausible.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/lib/support/plausible.c
++++ b/lib/support/plausible.c
+@@ -247,7 +247,7 @@ int check_plausibility(const char *devic
+ 		return 0;
+ 	}
+ 
+-#ifdef HAVE_MAGIC_H
++#if defined(HAVE_MAGIC_H) && defined(MAGIC_NO_CHECK_ELF) && defined(MAGIC_NO_CHECK_COMPRESS)
+ 	if ((flags & CHECK_FS_EXIST) &&
+ 	    !getenv("E2FSPROGS_LIBMAGIC_SUPPRESS") &&
+ 	    magic_library_available()) {
diff --git a/tools/elftosb/Makefile b/tools/elftosb/Makefile
new file mode 100644
index 0000000000..5adafef736
--- /dev/null
+++ b/tools/elftosb/Makefile
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=elftosb
+PKG_VERSION:=10.12.01
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://repository.timesys.com/buildsources/e/elftosb/elftosb-10.12.01/
+PKG_MD5SUM:=e8005d606c1e0bb3507c82f6eceb3056
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) LDFLAGS="$(HOST_LDFLAGS)"
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/bld/linux/elftosb $(STAGING_DIR_HOST)/bin/elftosb
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/elftosb/patches/001-libm.patch b/tools/elftosb/patches/001-libm.patch
new file mode 100644
index 0000000000..02705d24bb
--- /dev/null
+++ b/tools/elftosb/patches/001-libm.patch
@@ -0,0 +1,11 @@
+--- elftosb-10.12.01/makefile.rules	2012-03-15 11:01:44.979020178 -0400
++++ elftosb-10.12.01/makefile.rules	2012-03-15 11:01:16.332761989 -0400
+@@ -101,7 +101,7 @@
+ 	keygen.o
+ 
+ 
+-LIBS =     -lstdc++
++LIBS =     -lstdc++ -lm
+ 
+ 
+ ifeq ("${UNAMES}", "Linux")
diff --git a/tools/elftosb/patches/002-fix-header-path.patch b/tools/elftosb/patches/002-fix-header-path.patch
new file mode 100644
index 0000000000..5e3b5091b9
--- /dev/null
+++ b/tools/elftosb/patches/002-fix-header-path.patch
@@ -0,0 +1,19 @@
+This package had an absolute path for sys/types.h, which doesn't
+make much sense. It breaks on newer Ubuntu systems, and probably many
+others once multiarch becomes more common.
+
+This patch makes the types a relative path, and allows the system
+to use whatever include paths it feels are correct.
+
+diff -Naurp elftosb-10.12.01-orig/common/stdafx.h elftosb-10.12.01/common/stdafx.h
+--- elftosb-10.12.01-orig/common/stdafx.h	2012-07-12 13:30:10.990249396 -0400
++++ elftosb-10.12.01/common/stdafx.h	2012-07-12 13:30:06.858249391 -0400
+@@ -27,7 +27,7 @@
+ // For Linux systems only, types.h only defines the signed
+ // integer types.  This is not professional code.
+ // Update: They are defined in the header files in the more recent version of redhat enterprise gcc.
+-#include "/usr/include/sys/types.h"
++#include <sys/types.h>
+ #include <stdint.h>
+ //typedef unsigned long uint32_t;
+ //typedef unsigned short uint16_t;
diff --git a/tools/elftosb/patches/003-use-ldflags.patch b/tools/elftosb/patches/003-use-ldflags.patch
new file mode 100644
index 0000000000..82fd1e8d0a
--- /dev/null
+++ b/tools/elftosb/patches/003-use-ldflags.patch
@@ -0,0 +1,26 @@
+--- a/makefile.rules
++++ b/makefile.rules
+@@ -131,19 +131,20 @@ exec_always:
+ 	@echo "LIBS = ${LIBS}"
+ 	@echo "EXEC_FILE = ${EXEC_FILE}"
+ 	@echo "BUILD_DIR = ${BUILD_DIR}"
++	@echo "LDFLAGS = ${LDFLAGS}"
+ 
+ clean:
+ 	rm -f ${OBJ_FILES_ELFTOSB2} ${OBJ_FILES_SBTOOL} ${OBJ_FILES_KEYGEN} \
+ 		${EXEC_FILE_ELFTOSB2} ${EXEC_FILE_SBTOOL} ${EXEC_FILE_KEYGEN}
+ 
+ elftosb: ${OBJ_FILES_ELFTOSB2}
+-	gcc ${OBJ_FILES_ELFTOSB2} ${LIBS} -o ${EXEC_FILE_ELFTOSB2}
++	gcc ${OBJ_FILES_ELFTOSB2} ${LIBS} ${LDFLAGS} -o ${EXEC_FILE_ELFTOSB2}
+ 
+ sbtool: ${OBJ_FILES_SBTOOL}
+-	gcc ${OBJ_FILES_SBTOOL} ${LIBS} -o ${EXEC_FILE_SBTOOL}
++	gcc ${OBJ_FILES_SBTOOL} ${LIBS} ${LDFLAGS} -o ${EXEC_FILE_SBTOOL}
+ 
+ keygen: ${OBJ_FILES_KEYGEN}
+-	gcc ${OBJ_FILES_KEYGEN} ${LIBS} -o ${EXEC_FILE_KEYGEN}
++	gcc ${OBJ_FILES_KEYGEN} ${LIBS} ${LDFLAGS} -o ${EXEC_FILE_KEYGEN}
+ 
+ 
+ #ifeq ("${UNAMES}", "Linux")
diff --git a/tools/expat/Makefile b/tools/expat/Makefile
new file mode 100644
index 0000000000..93e0f74cd5
--- /dev/null
+++ b/tools/expat/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=expat
+PKG_VERSION:=2.2.0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_MD5SUM:=2f47841c829facb346eb6e3fab5212e2
+PKG_SOURCE_URL:=@SF/expat
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) install
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/findutils/Makefile b/tools/findutils/Makefile
new file mode 100644
index 0000000000..188257925e
--- /dev/null
+++ b/tools/findutils/Makefile
@@ -0,0 +1,20 @@
+# 
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=findutils
+PKG_VERSION:=4.6.0
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=9936aa8009438ce185bea2694a997fc1
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+$(eval $(call HostBuild))
diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
new file mode 100644
index 0000000000..456b7a39f5
--- /dev/null
+++ b/tools/firmware-utils/Makefile
@@ -0,0 +1,88 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME := firmware-utils
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define cc
+	$(HOSTCC) $(HOST_CFLAGS) -include endian.h $(HOST_LDFLAGS) -o $(HOST_BUILD_DIR)/bin/$(firstword $(1)) $(foreach src,$(1),src/$(src).c) $(2)
+endef
+
+define Host/Compile
+	mkdir -p $(HOST_BUILD_DIR)/bin
+	$(call cc,addpattern)
+	$(call cc,asustrx)
+	$(call cc,trx)
+	$(call cc,motorola-bin)
+	$(call cc,dgfirmware)
+	$(call cc,mksenaofw md5)
+	$(call cc,trx2usr)
+	$(call cc,ptgen)
+	$(call cc,srec2bin)
+	$(call cc,mkmylofw)
+	$(call cc,mkcsysimg)
+	$(call cc,mkzynfw)
+	$(call cc,lzma2eva,-lz)
+	$(call cc,mkcasfw)
+	$(call cc,mkfwimage,-lz -Wall)
+	$(call cc,mkfwimage2,-lz)
+	$(call cc,imagetag imagetag_cmdline cyg_crc32)
+	$(call cc,add_header)
+	$(call cc,makeamitbin)
+	$(call cc,encode_crc)
+	$(call cc,nand_ecc)
+	$(call cc,mkplanexfw sha1)
+	$(call cc,mktplinkfw md5, -Wall)
+	$(call cc,mktplinkfw2 md5)
+	$(call cc,tplink-safeloader md5, -Wall)
+	$(call cc,pc1crypt)
+	$(call cc,osbridge-crc)
+	$(call cc,wrt400n cyg_crc32)
+	$(call cc,mkdniimg)
+	$(call cc,mktitanimg)
+	$(call cc,mkchkimg)
+	$(call cc,mkzcfw cyg_crc32)
+	$(call cc,spw303v)
+	$(call cc,zyxbcm)
+	$(call cc,trx2edips)
+	$(call cc,xorimage)
+	$(call cc,buffalo-enc buffalo-lib, -Wall)
+	$(call cc,buffalo-tag buffalo-lib, -Wall)
+	$(call cc,buffalo-tftp buffalo-lib, -Wall)
+	$(call cc,mkwrgimg md5, -Wall)
+	$(call cc,mkwrggimg md5, -Wall)
+	$(call cc,mkedimaximg)
+	$(call cc,mkbrncmdline)
+	$(call cc,mkbrnimg)
+	$(call cc,mkdapimg)
+	$(call cc, mkcameofw, -Wall)
+	$(call cc,seama md5)
+	$(call cc,oseama md5, -Wall)
+	$(call cc,fix-u-media-header cyg_crc32,-Wall)
+	$(call cc,hcsmakeimage bcmalgo)
+	$(call cc,mkporayfw, -Wall)
+	$(call cc,mkhilinkfw, -lcrypto)
+	$(call cc,mkdcs932, -Wall)
+	$(call cc,mkheader_gemtek,-lz)
+	$(call cc,mkrtn56uimg, -lz)
+	$(call cc,dgn3500sum)
+	$(call cc,edimax_fw_header, -Wall)
+	$(call cc,mkmerakifw sha1, -Wall)
+	$(call cc,mkmerakifw-old, -Wall)
+	$(call cc,jcgimage, -lz -Wall)
+	$(call cc,mkbuffaloimg, -Wall)
+	$(call cc,zyimage, -Wall)
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/bin/* $(STAGING_DIR_HOST)/bin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/firmware-utils/src/add_header.c b/tools/firmware-utils/src/add_header.c
new file mode 100644
index 0000000000..37775c3e0c
--- /dev/null
+++ b/tools/firmware-utils/src/add_header.c
@@ -0,0 +1,138 @@
+/*
+ * add_header.c - partially based on OpenWrt's motorola-bin.c
+ *
+ * Copyright (C) 2008 Imre Kaloz  <kaloz@openwrt.org>
+ *                    Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * The add_header utility used by various vendors preprends the buf
+ * image with a header containing a CRC32 value which is generated for the
+ * model id + reserved space for CRC32 + buf, then replaces the reserved
+ * area with the actual CRC32. This replacement tool mimics this behavior.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#define BPB 8 /* bits/byte */
+
+static uint32_t crc32[1<<BPB];
+
+static void init_crc32()
+{
+	const uint32_t poly = ntohl(0x2083b8ed);
+	int n;
+
+	for (n = 0; n < 1<<BPB; n++) {
+		uint32_t crc = n;
+		int bit;
+
+		for (bit = 0; bit < BPB; bit++)
+			crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+		crc32[n] = crc;
+	}
+}
+
+static uint32_t crc32buf(unsigned char *buf, size_t len)
+{
+	uint32_t crc = 0xFFFFFFFF;
+
+	for (; len; len--, buf++)
+		crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
+	return ~crc;
+}
+
+struct header {
+	unsigned char model[16];
+	uint32_t crc;
+};
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+	fprintf(stderr, "Error: %s\n", mess);
+	fprintf(stderr, "Usage: add_header model_id input_file output_file\n");
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	off_t len;			// of original buf
+	off_t buflen;			// of the output file
+	int fd;
+	void *input_file;		// pointer to the input file (mmmapped)
+	struct header header;
+	unsigned char *buf;	// pointer to prefix + copy of original buf
+
+	// verify parameters
+
+	if (argc != 4)
+		usage("wrong number of arguments");
+
+	// mmap input_file
+	if ((fd = open(argv[2], O_RDONLY))  < 0
+	|| (len = lseek(fd, 0, SEEK_END)) < 0
+	|| (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+	|| close(fd) < 0)
+	{
+		fprintf(stderr, "Error loading file %s: %s\n", argv[2], strerror(errno));
+		exit(1);
+	}
+
+	buflen = len + sizeof(header);
+
+	init_crc32();
+
+	// copy model name into header
+	strncpy(header.model, argv[1], sizeof(header.model));
+	header.crc = 0;
+
+	// create a firmware image in memory and copy the input_file to it
+	buf = malloc(buflen);
+	memcpy(buf, &header, sizeof(header));
+	memcpy(&buf[sizeof(header)], input_file, len);
+
+	// CRC of temporary header + buf
+	header.crc = htonl(crc32buf(buf, buflen));
+
+	memcpy(buf, &header, sizeof(header));
+
+	// write the buf
+	if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
+	|| write(fd, buf, buflen) != buflen
+	|| close(fd) < 0)
+	{
+		fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno));
+		exit(2);
+ 	}
+
+	free(buf);
+
+	munmap(input_file,len);
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/addpattern.c b/tools/firmware-utils/src/addpattern.c
new file mode 100644
index 0000000000..1d72285610
--- /dev/null
+++ b/tools/firmware-utils/src/addpattern.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2004  Manuel Novoa III  <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* July 29, 2004
+ *
+ * This is a hacked replacement for the 'addpattern' utility used to
+ * create wrt54g .bin firmware files.  It isn't pretty, but it does
+ * the job for me.
+ *
+ * Extensions:
+ *  -v allows setting the version string on the command line.
+ *  -{0|1} sets the (currently ignored) hw_ver flag in the header
+ *      to 0 or 1 respectively.
+ */
+
+/* January 12, 2005
+ *
+ * Modified by rodent at rodent dot za dot net
+ * Support added for the new WRT54G v2.2 and WRT54GS v1.1 "flags"
+ * Without the flags set to 0x7, the above units will refuse to flash.
+ *
+ * Extensions:
+ *  -{0|1|2} sets {0|1} sets hw_ver flag to 0/1. {2} sets hw_ver to 1
+ *     and adds the new hardware "flags" for the v2.2/v1.1 units
+*/
+
+/* January 1, 2007
+ *
+ * Modified by juan.i.gonzalez at subdown dot net
+ * Support added for the AG241v2  and similar
+ *
+ * Extensions:
+ *  -r #.# adds revision hardware flags. AG241v2 and similar.
+ *
+ * AG241V2 firmware sets the hw_ver to 0x44.
+ *
+ * Example: -r 2.0
+ *
+ * Convert 2.0 to 20 to be an integer, and add 0x30 to skip special ASCII
+ * #define HW_Version ((HW_REV * 10) + 0x30)  -> from cyutils.h
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+/**********************************************************************/
+
+#define CODE_ID		"U2ND"		/* from code_pattern.h */
+#define CODE_PATTERN   "W54S"	/* from code_pattern.h */
+#define PBOT_PATTERN   "PBOT"
+
+#define CYBERTAN_VERSION	"v3.37.2" /* from cyutils.h */
+
+/* WRT54G v2.2 and WRT54GS v1.1 "flags" (from 3.37.32 firmware cyutils.h) */
+#define SUPPORT_4712_CHIP      0x0001
+#define SUPPORT_INTEL_FLASH    0x0002
+#define SUPPORT_5325E_SWITCH   0x0004
+/* (from 3.00.24 firmware cyutils.h) */
+#define SUPPORT_4704_CHIP      0x0008
+#define SUPPORT_5352E_CHIP     0x0010
+/* (from WD My Net Wi-Fi Range Extender's cyutils.s) */
+#define SUPPORT_4703_CHIP      0x0020
+
+struct code_header {			/* from cyutils.h */
+	char magic[8];
+	char fwdate[3];
+	char fwvern[3];
+	char id[4];					/* U2ND */
+	char hw_ver;    			/* 0: for 4702, 1: for 4712 -- new in 2.04.3 */
+
+	unsigned char  sn;		// Serial Number
+	unsigned char  flags[2];	/* SUPPORT_ flags new for 3.37.2 (WRT54G v2.2 and WRT54GS v1.1) */
+	unsigned char  stable[2];	// The image is stable (for dual image)
+	unsigned char  try1[2];		// Try to boot image first time (for dual image)
+	unsigned char  try2[2];		// Try to boot image second time (for dual image)
+	unsigned char  try3[2];		// Try to boot image third time (for dual_image)
+	unsigned char  res3[2];
+} ;
+
+struct board_info {
+	char	*id;
+	char	*pattern;
+	char	hw_ver;
+	char	sn;
+	char	flags[2];
+};
+
+struct board_info boards[] = {
+	{
+		.id		= "WRT160NL",
+		.pattern	= "NL16",
+		.hw_ver		= 0x00,
+		.sn		= 0x0f,
+		.flags		= {0x3f, 0x00},
+	},
+	{
+		.id		= "mynet-rext",
+		.pattern	= "WDHNSTFH",
+		.hw_ver		= 0x00,
+		.sn		= 0x00,
+		.flags		= {0x3f, 0x00},
+	}, {
+		/* Terminating entry */
+		.id	= NULL,
+	}
+};
+
+/**********************************************************************/
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+	fprintf(stderr, "Usage: addpattern [-i trxfile] [-o binfile] [-B board_id] [-p pattern] [-s serial] [-g] [-b] [-v v#.#.#] [-r #.#] [-{0|1|2|4|5}] -h\n");
+	exit(EXIT_FAILURE);
+}
+
+struct board_info *find_board(char *id)
+{
+	struct board_info *board;
+
+	for (board = boards; board->id != NULL; board++)
+		if (strcasecmp(id, board->id) == 0)
+			return board;
+
+	return NULL;
+}
+
+int main(int argc, char **argv)
+{
+	char buf[1024];	/* keep this at 1k or adjust garbage calc below */
+	struct code_header *hdr;
+	FILE *in = stdin;
+	FILE *out = stdout;
+	char *ifn = NULL;
+	char *ofn = NULL;
+	char *pattern = CODE_PATTERN;
+	char *pbotpat = PBOT_PATTERN;
+	char *version = CYBERTAN_VERSION;
+	char *board_id = NULL;
+	struct board_info *board = NULL;
+	int gflag = 0;
+	int pbotflag = 0;
+	int c;
+	int v0, v1, v2;
+	size_t off, n;
+	time_t t;
+	struct tm *ptm;
+
+	fprintf(stderr, "mjn3's addpattern replacement - v0.81\n");
+
+	hdr = (struct code_header *) buf;
+	memset(hdr, 0, sizeof(struct code_header));
+
+	while ((c = getopt(argc, argv, "i:o:p:s:gbv:01245hr:B:")) != -1) {
+		switch (c) {
+			case 'i':
+				ifn = optarg;
+				break;
+			case 'o':
+				ofn = optarg;
+				break;
+			case 'p':
+				pattern = optarg;
+				break;
+			case 's':
+				hdr->sn = (unsigned char) atoi (optarg);
+				break;
+			case 'g':
+				gflag = 1;
+				break;
+			case 'b':
+				pbotflag = 1;
+				break;
+			case 'v':			/* extension to allow setting version */
+				version = optarg;
+				break;
+			case '0':
+				hdr->hw_ver = 0;
+				break;
+			case '1':
+				hdr->hw_ver = 1;
+				break;
+			case '2': 			/* new 54G v2.2 and 54GS v1.1 flags */
+				hdr->hw_ver = 1;
+				hdr->flags[0] |= SUPPORT_4712_CHIP;
+				hdr->flags[0] |= SUPPORT_INTEL_FLASH;
+				hdr->flags[0] |= SUPPORT_5325E_SWITCH;
+				break;
+			case '4':
+				/* V4 firmware sets the flags to 0x1f */
+				hdr->hw_ver = 0;
+				hdr->flags[0] = 0x1f;
+				break;
+			case '5':
+				/* V5 is appended to trxV2 image */
+				hdr->stable[0] = 0x73; // force image to be stable
+				hdr->stable[1] = 0x00;
+				hdr->try1[0]   = 0x74; // force try1 to be set
+				hdr->try1[1]   = 0x00;
+				hdr->try2[0]   = hdr->try2[1]   = 0xFF;
+				hdr->try3[0]   = hdr->try3[1]   = 0xFF;
+				break;
+                        case 'r':
+                                hdr->hw_ver = (char)(atof(optarg)*10)+0x30;
+                                break;
+                        case 'B':
+                                board_id = optarg;
+                                break;
+
+                        case 'h':
+			default:
+				usage();
+		}
+	}
+
+    	if (optind != argc || optind == 1) {
+		fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+		usage();
+	}
+
+	if (board_id) {
+		board = find_board(board_id);
+		if (board == NULL) {
+			fprintf(stderr, "unknown board \"%s\"\n", board_id);
+			usage();
+		}
+		pattern = board->pattern;
+		hdr->hw_ver = board->hw_ver;
+		hdr->sn = board->sn;
+		hdr->flags[0] = board->flags[0];
+		hdr->flags[1] = board->flags[1];
+	}
+
+	if (strlen(pattern) > 8) {
+		fprintf(stderr, "illegal pattern \"%s\"\n", pattern);
+		usage();
+	}
+
+	if (ifn && !(in = fopen(ifn, "r"))) {
+		fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+		usage();
+	}
+
+	if (ofn && !(out = fopen(ofn, "w"))) {
+		fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+		usage();
+	}
+
+	if (time(&t) == (time_t)(-1)) {
+		fprintf(stderr, "time call failed\n");
+		return EXIT_FAILURE;
+	}
+
+	ptm = localtime(&t);
+
+	if (3 != sscanf(version, "v%d.%d.%d", &v0, &v1, &v2)) {
+		fprintf(stderr, "bad version string \"%s\"\n", version);
+		return EXIT_FAILURE;
+	}
+
+	memcpy(hdr->magic, pattern, strlen(pattern));
+	if (pbotflag)
+		memcpy(&hdr->magic[4], pbotpat, 4);
+	hdr->fwdate[0] = ptm->tm_year % 100;
+	hdr->fwdate[1] = ptm->tm_mon + 1;
+	hdr->fwdate[2] = ptm->tm_mday;
+	hdr->fwvern[0] = v0;
+	hdr->fwvern[1] = v1;
+	hdr->fwvern[2] = v2;
+	memcpy(hdr->id, CODE_ID, strlen(CODE_ID));
+
+	off = sizeof(struct code_header);
+
+	fprintf(stderr, "writing firmware v%d.%d.%d on %d/%d/%d (y/m/d)\n",
+			v0, v1, v2,
+			hdr->fwdate[0], hdr->fwdate[1], hdr->fwdate[2]);
+
+
+	while ((n = fread(buf + off, 1, sizeof(buf)-off, in) + off) > 0) {
+		off = 0;
+		if (n < sizeof(buf)) {
+			if (ferror(in)) {
+			FREAD_ERROR:
+				fprintf(stderr, "fread error\n");
+				return EXIT_FAILURE;
+			}
+			if (gflag) {
+				gflag = sizeof(buf) - n;
+				memset(buf + n, 0xff, gflag);
+				fprintf(stderr, "adding %d bytes of garbage\n", gflag);
+				n = sizeof(buf);
+			}
+		}
+		if (!fwrite(buf, n, 1, out)) {
+		FWRITE_ERROR:
+			fprintf(stderr, "fwrite error\n");
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (ferror(in)) {
+		goto FREAD_ERROR;
+	}
+
+	if (fflush(out)) {
+		goto FWRITE_ERROR;
+	}
+
+	fclose(in);
+	fclose(out);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/asustrx.c b/tools/firmware-utils/src/asustrx.c
new file mode 100644
index 0000000000..67f2680b31
--- /dev/null
+++ b/tools/firmware-utils/src/asustrx.c
@@ -0,0 +1,256 @@
+/*
+ * asustrx
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <byteswap.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le32(x)	bswap_32(x)
+#define le32_to_cpu(x)	bswap_32(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le32(x)	(x)
+#define le32_to_cpu(x)	(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define TRX_MAGIC			0x30524448
+#define TRX_FLAGS_OFFSET		12
+
+struct trx_header {
+	uint32_t magic;
+	uint32_t length;
+	uint32_t crc32;
+	uint16_t flags;
+	uint16_t version;
+	uint32_t offset[3];
+};
+
+struct asustrx_tail {
+	uint8_t version[4];
+	char productid[12];
+	uint8_t unused[48];
+};
+
+char *in_path = NULL;
+char *out_path = NULL;
+char *productid = NULL;
+uint8_t version[4] = { };
+
+static const uint32_t crc32_tbl[] = {
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static void parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "i:o:p:v:")) != -1) {
+		switch (c) {
+		case 'i':
+			in_path = optarg;
+			break;
+		case 'o':
+			out_path = optarg;
+			break;
+		case 'p':
+			productid = optarg;
+			break;
+		case 'v':
+			if (sscanf(optarg, "%hu.%hu.%hu.%hu", &version[0], &version[1], &version[2], &version[3]) != 4)
+				fprintf(stderr, "Version %s doesn't match suppored 4-digits format\n", optarg);
+			break;
+		}
+	}
+}
+
+static void usage() {
+	printf("Usage:\n");
+	printf("\t-i file\t\t\t\tinput TRX file\n");
+	printf("\t-o file\t\t\t\toutput Asus TRX file\n");
+	printf("\t-p productid\t\t\tproduct (device) ID\n");
+	printf("\t-v version\t\t\tfirmware version formatted with 4 digits like: 1.2.3.4\n");
+}
+
+int main(int argc, char **argv) {
+	struct trx_header hdr;
+	struct asustrx_tail tail = { };
+	FILE *in, *out;
+	uint8_t buf[1024];
+	size_t bytes;
+	size_t length = 0;
+	uint32_t crc32 = 0xffffffff;
+	int i;
+	int err = 0;
+
+	/* Parse & validate arguments */
+	parse_options(argc, argv);
+	if (!in_path || !out_path || !productid) {
+		usage();
+		err = -EINVAL;
+		goto err;
+	}
+
+	/* Fill Asus tail */
+	tail.version[0] = version[0];
+	tail.version[1] = version[1];
+	tail.version[2] = version[2];
+	tail.version[3] = version[3];
+	strncpy(tail.productid, productid, sizeof(tail.productid));
+
+	/* Open files */
+	in = fopen(in_path, "r");
+	if (!in) {
+		fprintf(stderr, "Couldn't open %s\n", in_path);
+		err = -EIO;
+		goto err;
+	}
+	out = fopen(out_path, "w+");
+	if (!out) {
+		fprintf(stderr, "Couldn't open %s\n", out_path);
+		err = -EIO;
+		goto err;
+	}
+
+	/* Check is there is empty place for Asus tail */
+	bytes = sizeof(struct asustrx_tail);
+	fseek(in, -bytes, SEEK_END);
+	if (fread(buf, 1, bytes, in) != bytes) {
+		fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
+		err = -EIO;
+		goto err;
+	}
+	for (i = 0; i < bytes; i++) {
+		if (buf[i]) {
+			fprintf(stderr, "Input TRX doesn't have last 64 B empty %s\n", out_path);
+			err = -ENOSPC;
+			goto err;
+		}
+	}
+
+	/* Copy whole TRX */
+	rewind(in);
+	while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (fwrite(buf, 1, bytes, out) != bytes) {
+			fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+			err = -EIO;
+			goto err;
+		}
+	}
+
+	/* Overwrite last 64 B with Asus tail */
+	bytes = sizeof(tail);
+	fseek(out, -bytes, SEEK_CUR);
+	if (fwrite(&tail, 1, bytes, out) != bytes) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+		err = -EIO;
+		goto err;
+	}
+
+	/* Calculate crc32 */
+	fseek(out, TRX_FLAGS_OFFSET, SEEK_SET);
+	length = TRX_FLAGS_OFFSET;
+	while ((bytes = fread(buf, 1, sizeof(buf), out )) > 0) {
+		length += bytes;
+		for (i = 0; i < bytes; i++)
+			crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
+	}
+
+	/* Update header */
+	bytes = sizeof(hdr);
+	rewind(out);
+	if (fread(&hdr, 1, sizeof(hdr), out) != bytes) {
+		fprintf(stderr, "Couldn't read %zu B from %s\n", bytes, in_path);
+		err = -EIO;
+		goto err;
+	}
+	hdr.crc32 = cpu_to_le32(crc32);
+	rewind(out);
+	if (fwrite(&hdr, 1, bytes, out) != bytes) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+		err = -EIO;
+		goto err;
+	}
+
+err:
+	if (out)
+		fclose(out);
+	if (in)
+		fclose(in);
+	return err;
+}
diff --git a/tools/firmware-utils/src/bcm_tag.h b/tools/firmware-utils/src/bcm_tag.h
new file mode 100644
index 0000000000..2730edc9ad
--- /dev/null
+++ b/tools/firmware-utils/src/bcm_tag.h
@@ -0,0 +1,70 @@
+#ifndef __BCM63XX_TAG_H
+#define __BCM63XX_TAG_H
+
+#define TAGVER_LEN 4                   /* Length of Tag Version */
+#define TAGLAYOUT_LEN 4                /* Length of FlashLayoutVer */
+#define SIG1_LEN 20		       /* Company Signature 1 Length */
+#define SIG2_LEN 14                    /* Company Signature 2 Lenght */
+#define BOARDID_LEN 16		       /* Length of BoardId */
+#define ENDIANFLAG_LEN 2               /* Endian Flag Length */
+#define CHIPID_LEN 6		       /* Chip Id Length */
+#define IMAGE_LEN 10                   /* Length of Length Field */
+#define ADDRESS_LEN 12                 /* Length of Address field */
+#define DUALFLAG_LEN 2		       /* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2	       /* Inactie Flag Length */
+#define RSASIG_LEN 20   	       /* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30                /* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4	       /* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16                /* Length of vendor information field2 in tag */
+#define CRC_LEN 4                      /* Length of CRC in bytes */
+#define ALTTAGINFO_LEN 54              /* Alternate length for vendor information; Pirelli */
+
+#define NUM_PIRELLI 2
+#define IMAGETAG_CRC_START		0xFFFFFFFF
+
+#define PIRELLI_BOARDS { \
+  "AGPF-S0", \
+  "DWV-S0", \
+}
+
+/*
+ * The broadcom firmware assumes the rootfs starts the image,
+ * therefore uses the rootfs start (flashImageAddress)
+ * to determine where to flash the image.  Since we have the kernel first
+ * we have to give it the kernel address, but the crc uses the length
+ * associated with this address (rootLength), which is added to the kernel
+ * length (kernelLength) to determine the length of image to flash and thus
+ * needs to be rootfs + deadcode (jffs2 EOF marker)
+*/
+
+struct bcm_tag {
+	char tagVersion[TAGVER_LEN];           // 0-3: Version of the image tag
+	char sig_1[SIG1_LEN];                  // 4-23: Company Line 1
+	char sig_2[SIG2_LEN];                  // 24-37: Company Line 2
+	char chipid[CHIPID_LEN];               // 38-43: Chip this image is for
+	char boardid[BOARDID_LEN];             // 44-59: Board name
+	char big_endian[ENDIANFLAG_LEN];       // 60-61: Map endianness -- 1 BE 0 LE
+	char totalLength[IMAGE_LEN];           // 62-71: Total length of image
+	char cfeAddress[ADDRESS_LEN];          // 72-83: Address in memory of CFE
+	char cfeLength[IMAGE_LEN];             // 84-93: Size of CFE
+	char flashImageStart[ADDRESS_LEN];     // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
+	char flashRootLength[IMAGE_LEN];            // 106-115: Size of rootfs for flashing
+	char kernelAddress[ADDRESS_LEN];       // 116-127: Address in memory of kernel
+	char kernelLength[IMAGE_LEN];          // 128-137: Size of kernel
+	char dualImage[DUALFLAG_LEN];          // 138-139: Unused at present
+	char inactiveFlag[INACTIVEFLAG_LEN];   // 140-141: Unused at present
+        char rsa_signature[RSASIG_LEN];        // 142-161: RSA Signature (unused at present; some vendors may use this)
+	char information1[TAGINFO1_LEN];       // 162-191: Compilation and related information (not generated/used by OpenWRT)
+        char flashLayoutVer[FLASHLAYOUTVER_LEN];// 192-195: Version flash layout
+        char fskernelCRC[CRC_LEN];             // 196-199: kernel+rootfs CRC32
+	char information2[TAGINFO2_LEN];       // 200-215: Unused at present except Alice Gate where is is information
+	char imageCRC[CRC_LEN];                // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+        char rootfsCRC[CRC_LEN];               // 220-223: CRC32 of rootfs partition
+        char kernelCRC[CRC_LEN];               // 224-227: CRC32 of kernel partition
+        char imageSequence[4];		       // 228-231: Image sequence number
+        char rootLength[4];                    // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+        char headerCRC[CRC_LEN];               // 236-239: CRC32 of header excluding tagVersion
+        char reserved2[16];                    // 240-255: Unused at present
+};
+
+#endif /* __BCM63XX_TAG_H */
diff --git a/tools/firmware-utils/src/bcmalgo.c b/tools/firmware-utils/src/bcmalgo.c
new file mode 100644
index 0000000000..e7d3b113be
--- /dev/null
+++ b/tools/firmware-utils/src/bcmalgo.c
@@ -0,0 +1,248 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "bcmalgo.h"
+
+
+#define UTIL_VERSION "0.1"
+#define ENDIAN_REVERSE_NEEDED
+
+uint32_t reverse_endian32 ( uint32_t data )
+{
+#ifdef ENDIAN_REVERSE_NEEDED
+	return 0 | ( data & 0x000000ff ) << 24
+	       | ( data & 0x0000ff00 ) << 8
+	       | ( data & 0x00ff0000 ) >> 8
+	       | ( data & 0xff000000 ) >> 24;
+#else
+	return data;
+#endif
+}
+
+uint16_t reverse_endian16 ( uint16_t data )
+{
+#ifdef ENDIAN_REVERSE_NEEDED
+	return 0 | ( data & 0x00ff ) << 8
+	       | ( data & 0xff00 ) >> 8;
+#else
+	return data;
+#endif
+}
+
+
+
+uint32_t get_buffer_crc ( char* filebuffer,size_t size )
+{
+
+	long crc=0xffffffffL;
+	long crcxor = 0xffffffffL;
+	long num4 = 0xffffffffL;
+	long num5 = size;
+	long num6 = 0x4c11db7L;
+	long num7 = 0x80000000L;
+	int i;
+	long j;
+	for ( i = 0; i < ( num5 ); i++ )
+	{
+		long num2 = filebuffer[i];
+		for ( j = 0x80L; j != 0L; j = j >> 1 )
+		{
+			long num3 = crc & num7;
+			crc = crc << 1;
+			if ( ( num2 & j ) != 0L )
+			{
+				num3 ^= num7;
+			}
+			if ( num3 != 0L )
+			{
+				crc ^= num6;
+			}
+		}
+	}
+	crc ^= crcxor;
+	crc &= num4;
+
+	uint8_t b1 = ( uint8_t ) ( ( crc & -16777216L ) >> 0x18 );
+	uint8_t b2 = ( uint8_t ) ( ( crc & 0xff0000L ) >> 0x10 );
+	uint8_t b3 = ( uint8_t ) ( ( crc & 0xff00L ) >> 8 );
+	uint8_t b4 = ( uint8_t ) ( crc & 0xffL );
+	int32_t crc_result = ( b1 | b2 << 8| b3 << 16| b4 <<24 );
+	return reverse_endian32 ( crc_result );
+}
+
+//Thnx to Vector for the algo.
+uint32_t get_file_crc ( char* filename )
+{
+	struct stat buf;
+	stat ( filename,&buf );
+	char* filebuffer = malloc ( buf.st_size+10 );
+	FILE* fd = fopen ( filename,"r" );
+	fread ( filebuffer, 1, buf.st_size,fd );
+	fclose ( fd );
+	uint32_t crc = get_buffer_crc ( filebuffer,buf.st_size );
+	free ( filebuffer );
+	return crc;
+}
+
+
+
+uint16_t get_hcs ( ldr_header_t* hd )
+{
+	uint8_t* head = ( uint8_t* ) hd;
+	uint8_t hcs_minor;
+	uint8_t hcs_major;
+	uint16_t n = 0xffff;
+	uint16_t m = 0;
+	int state = 0;
+	int i,j;
+	for ( i = 0; i < 0x54; i++ )
+	{
+		uint16_t m = head[i];
+		m = m << 8;
+		for ( j = 0; j < 8; j++ )
+		{
+			if ( ( ( n ^ m ) & 0x8000 ) == 0 )
+			{
+				state = 0;
+			}
+			else
+			{
+				state = 1;
+			}
+			n = n << 1;
+			if ( state )
+			{
+				n ^= 0x1021;
+			}
+			m = m << 1;
+		}
+		n &= 0xffff;
+	}
+	n ^= 0xffff;
+	hcs_major = ( uint8_t ) ( ( n & 0xff00 ) >> 8 );
+	hcs_minor = ( uint8_t ) ( n & 0xff );
+	uint16_t hcs = hcs_major <<8 | hcs_minor;
+	return hcs;
+}
+
+ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data )
+{
+	ldr_header_t* hd = malloc ( sizeof ( ldr_header_t ) );
+	hd->magic=reverse_endian16 ( magic );
+	hd->control=0; //FixMe: Make use of it once compression is around
+	hd->rev_min = reverse_endian16 ( rev_min );
+	hd->rev_maj = reverse_endian16 ( rev_maj );
+	hd->build_date = reverse_endian32 ( build_date );
+	hd->filelen = reverse_endian32 ( filelen );
+	hd->ldaddress = reverse_endian32 ( ldaddress );
+	printf ( "Creating header for %s...\n", filename );
+	if ( strlen ( filename ) >63 )
+	{
+		printf ( "[!] Filename too long - stripping it to 63 bytes.\n" );
+		strncpy ( ( char* ) &hd->filename, filename, 63 );
+		hd->filename[63]=0x00;
+	}
+	else
+	{
+		strcpy ( ( char* ) &hd->filename, filename );
+	}
+	hd->crc=reverse_endian32 ( crc_data );
+	hd->hcs = reverse_endian16 ( get_hcs ( hd ) );
+	return hd;
+}
+
+static char control_unc[]  = "Uncompressed";
+static char control_lz[]   = "LZRW1/KH";
+static char control_mlzo[] = "mini-LZO";
+static char control_nrv[] = "NRV2D99 [Bootloader?]";
+static char control_nstdlzma[] = "(non-standard) LZMA";
+static char control_unk[] = "Unknown";
+char* get_control_info ( uint16_t control )
+{
+	control = reverse_endian16 ( control );
+	switch ( control )
+	{
+		case 0:
+			return control_unc;
+			break;
+		case 1:
+			return control_lz;
+			break;
+		case 2:
+			return control_mlzo;
+			break;
+		case 3:
+			return control_unc;
+			break;
+		case 4:
+			return control_nrv;
+			break;
+		case 5:
+			return control_nstdlzma;
+			break;
+		case 6:
+			return control_unc;
+			break;
+		case 7:
+			return control_unc;
+			break;
+		default:
+			return control_unk;
+			break;
+	}
+
+}
+
+int dump_header ( ldr_header_t* hd )
+{
+	printf ( "=== Header Information ===\n" );
+	printf ( "Header magic:\t0x%04X\n",reverse_endian16 ( hd->magic ) );
+	printf ( "Control:\t0x%04X (%s)\n",reverse_endian16 ( hd->control ), get_control_info ( hd->control ) );
+	printf ( "Major rev. :\t0x%04X\n",reverse_endian16 ( hd->rev_maj ) );
+	printf ( "Minor rev. :\t0x%04X\n",reverse_endian16 ( hd->rev_min ) );
+	printf ( "File name :\t%s\n", ( char* ) &hd->filename );
+	printf ( "File length:\t%d bytes\n", reverse_endian32 ( hd->filelen ) );
+	printf ( "Build time:\t0x%08X //FixMe: print in human-readable form\n", reverse_endian32 ( hd->build_date ) ); //FixMe:
+	printf ( "HCS:\t\t0x%04X  ",reverse_endian16 ( hd->hcs ) );
+	uint16_t hcs = get_hcs ( hd );
+	int ret=0;
+	if ( hcs ==reverse_endian16 ( hd->hcs ) )
+	{
+		printf ( "(OK!)\n" );
+	}
+	else
+	{
+		printf ( "(ERROR! expected 0x%04X)\n",hcs );
+		ret=1;
+	}
+//printf("HCS:\t0x%02X",reverse_endian32(hd->hcs));
+	printf ( "Load address:\t0x%08X\n", reverse_endian32 ( hd->ldaddress ) ); //FixMe:
+	printf ( "HNW:\t\t0x%04X\n",reverse_endian16 ( hd->her_znaet_chto ) ); //Hell knows what
+	printf ( "CRC:\t\t0x%08X\n",reverse_endian32 ( hd->crc ) );
+	printf ( "=== Binary Header Dump===\n" );
+	int i,j;
+	uint8_t* head = ( uint8_t* ) hd;
+	for ( i=0;i<=sizeof ( ldr_header_t );i++ )
+	{
+		if ( i % 8==0 )
+			printf ( "\n" );
+		printf ( "0x%02x   ",head[i] );
+	}
+	printf ( "\n\n== End Of Header dump ==\n" );
+	return ret;
+}
+
+
+void print_copyright()
+{
+	printf ( "Part of bcm-utils package ver. " UTIL_VERSION " \n" );
+	printf ( "Copyright (C) 2009  Andrew 'Necromant' Andrianov\n"
+	         "This is free software, and you are welcome to redistribute it\n"
+	         "under certain conditions. See COPYING for details\n" );
+}
diff --git a/tools/firmware-utils/src/bcmalgo.h b/tools/firmware-utils/src/bcmalgo.h
new file mode 100644
index 0000000000..46647cf6d3
--- /dev/null
+++ b/tools/firmware-utils/src/bcmalgo.h
@@ -0,0 +1,83 @@
+#ifndef bcmutils_H
+#define bcmutils_H
+
+typedef struct
+{
+	uint16_t magic;
+	uint16_t control;
+	uint16_t rev_maj;
+	uint16_t rev_min;
+	uint32_t build_date;
+	uint32_t filelen;
+	uint32_t ldaddress;
+	char filename[64];
+	uint16_t hcs;
+	uint16_t her_znaet_chto; //v dushe ne ebu
+	uint32_t crc;
+} ldr_header_t;
+
+
+/**
+ * Reverses endianess of a 32bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time
+ * @param data
+ * @return
+ */
+uint32_t reverse_endian32 ( uint32_t data );
+
+/**
+ * Reverses endianess of a 16bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time
+ * @param data
+ * @return
+ */
+uint16_t reverse_endian16 ( uint16_t data );
+/**
+ * Calculates the strange crc (used by bcm modems) of the file. Thnx fly out to Vector for the algorithm.
+ * @param filename
+ * @return
+ */
+uint32_t get_file_crc ( char* filename );
+
+/**
+ * Calculates HCS of the header.
+ * @param hd
+ * @return
+ */
+uint16_t get_hcs ( ldr_header_t* hd );
+
+/**
+ * Constructs the header of the image with the information given It also automagically calculates HCS and writes it there.
+ * @param magic - magic device bytes
+ * @param rev_maj - major revision
+ * @param rev_min - minor revision
+ * @param build_date - build date (seconds from EPOCH UTC)
+ * @param filelen - file length in bytes
+ * @param ldaddress - Load adress
+ * @param filename - filename
+ * @param crc_data - the crc of the data
+ * @return
+ */
+ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data );
+
+/**
+ * Dumps header information to stdout.
+ * @param hd
+ */
+int dump_header ( ldr_header_t* hd );
+
+
+/**
+ * Returns a null terminated string describing what the control number meens
+ * DO NOT FREE IT!!!
+ * @param control
+ * @return
+ */
+char* get_control_info ( uint16_t control );
+#endif
+
+/**
+ * Calculates bcmCRC of a data buffer.
+ * @param filebuffer - pointer to buffer
+ * @param size - buffer size
+ * @return
+ */
+uint32_t get_buffer_crc ( char* filebuffer, size_t size );
diff --git a/tools/firmware-utils/src/buffalo-enc.c b/tools/firmware-utils/src/buffalo-enc.c
new file mode 100644
index 0000000000..794659eb41
--- /dev/null
+++ b/tools/firmware-utils/src/buffalo-enc.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+
+#include "buffalo-lib.h"
+
+#define ERR(fmt, args...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## args ); \
+} while (0)
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static char *crypt_key = "Buffalo";
+static char *magic = "start";
+static int longstate;
+static unsigned char seed = 'O';
+
+static char *product;
+static char *version;
+static int do_decrypt;
+static int offset;
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -d              decrypt instead of encrypt\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -l              use longstate {en,de}cryption method\n"
+"  -k <key>        use <key> for encryption (default: Buffalo)\n"
+"  -m <magic>      set magic to <magic>\n"
+"  -p <product>    set product name to <product>\n"
+"  -v <version>    set version to <version>\n"
+"  -h              show this screen\n"
+"  -O              Offset of encrypted data in file (decryption)\n"
+	);
+
+	exit(status);
+}
+
+static int decrypt_file(void)
+{
+	struct enc_param ep;
+	ssize_t src_len;
+	unsigned char *buf = NULL;
+	int err;
+	int ret = -1;
+
+	src_len = get_file_size(ifname);
+	if (src_len < 0) {
+		ERR("unable to get size of '%s'", ifname);
+		goto out;
+	}
+
+	buf = malloc(src_len);
+	if (buf == NULL) {
+		ERR("no memory for the buffer");
+		goto out;
+	}
+
+	err = read_file_to_buf(ifname, buf, src_len);
+	if (err) {
+		ERR("unable to read from file '%s'", ifname);
+		goto out;
+	}
+
+	memset(&ep, '\0', sizeof(ep));
+	ep.key = (unsigned char *) crypt_key;
+	ep.longstate = longstate;
+
+	err = decrypt_buf(&ep, buf + offset, src_len - offset);
+	if (err) {
+		ERR("unable to decrypt '%s'", ifname);
+		goto out;
+	}
+
+	printf("Magic\t\t: '%s'\n", ep.magic);
+	printf("Seed\t\t: 0x%02x\n", ep.seed);
+	printf("Product\t\t: '%s'\n", ep.product);
+	printf("Version\t\t: '%s'\n", ep.version);
+	printf("Data len\t: %u\n", ep.datalen);
+	printf("Checksum\t: 0x%08x\n", ep.csum);
+
+	err = write_buf_to_file(ofname, buf + offset, ep.datalen);
+	if (err) {
+		ERR("unable to write to file '%s'", ofname);
+		goto out;
+	}
+
+	ret = 0;
+
+out:
+	free(buf);
+	return ret;
+}
+
+static int encrypt_file(void)
+{
+	struct enc_param ep;
+	ssize_t src_len;
+	unsigned char *buf;
+	uint32_t hdrlen;
+	ssize_t totlen = 0;
+	int err;
+	int ret = -1;
+
+	src_len = get_file_size(ifname);
+	if (src_len < 0) {
+		ERR("unable to get size of '%s'", ifname);
+		goto out;
+	}
+
+	totlen = enc_compute_buf_len(product, version, src_len);
+	hdrlen = enc_compute_header_len(product, version);
+
+	buf = malloc(totlen);
+	if (buf == NULL) {
+		ERR("no memory for the buffer");
+		goto out;
+	}
+
+	err = read_file_to_buf(ifname, &buf[hdrlen], src_len);
+	if (err) {
+		ERR("unable to read from file '%s'", ofname);
+		goto free_buf;
+	}
+
+	memset(&ep, '\0', sizeof(ep));
+	ep.key = (unsigned char *) crypt_key;
+	ep.seed = seed;
+	ep.longstate = longstate;
+	ep.csum = buffalo_csum(src_len, &buf[hdrlen], src_len);
+	ep.datalen = src_len;
+	strcpy((char *) ep.magic, magic);
+	strcpy((char *) ep.product, product);
+	strcpy((char *) ep.version, version);
+
+	err = encrypt_buf(&ep, buf, &buf[hdrlen]);
+	if (err) {
+		ERR("invalid input file");
+		goto free_buf;
+	}
+
+	err = write_buf_to_file(ofname, buf, totlen);
+	if (err) {
+		ERR("unable to write to file '%s'", ofname);
+		goto free_buf;
+	}
+
+	ret = 0;
+
+free_buf:
+ 	free(buf);
+out:
+ 	return ret;
+}
+
+static int check_params(void)
+{
+	int ret = -1;
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto out;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto out;
+	}
+
+	if (crypt_key == NULL) {
+		ERR("no key specified");
+		goto out;
+	} else if (strlen(crypt_key) > BCRYPT_MAX_KEYLEN) {
+		ERR("key '%s' is too long", crypt_key);
+		goto out;
+	}
+
+	if (strlen(magic) != (ENC_MAGIC_LEN - 1)) {
+		ERR("length of magic must be %d", ENC_MAGIC_LEN - 1);
+		goto out;
+	}
+
+	if (!do_decrypt) {
+		if (product == NULL) {
+			ERR("no product specified");
+			goto out;
+		}
+
+		if (version == NULL) {
+			ERR("no version specified");
+			goto out;
+		}
+
+		if (strlen(product) > (ENC_PRODUCT_LEN - 1)) {
+			ERR("product name '%s' is too long", product);
+			goto out;
+		}
+
+		if (strlen(version) > (ENC_VERSION_LEN - 1)) {
+			ERR("version '%s' is too long", version);
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int err;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "adi:m:o:hlp:v:k:O:r:s:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'd':
+			do_decrypt = 1;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'l':
+			longstate = 1;
+			break;
+		case 'm':
+			magic = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'p':
+			product = optarg;
+			break;
+		case 'v':
+			version = optarg;
+			break;
+		case 'k':
+			crypt_key = optarg;
+			break;
+		case 's':
+			seed = strtoul(optarg, NULL, 16);
+			break;
+		case 'O':
+			offset = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	err = check_params();
+	if (err)
+		goto out;
+
+	if (do_decrypt)
+		err = decrypt_file();
+	else
+		err = encrypt_file();
+
+	if (err)
+		goto out;
+
+	res = EXIT_SUCCESS;
+
+out:
+	return res;
+}
diff --git a/tools/firmware-utils/src/buffalo-lib.c b/tools/firmware-utils/src/buffalo-lib.c
new file mode 100644
index 0000000000..b1d5ede0a2
--- /dev/null
+++ b/tools/firmware-utils/src/buffalo-lib.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "buffalo-lib.h"
+
+static uint32_t crc32_table[256] =
+{
+	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+	0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+	0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+	0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+	0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+	0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+	0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+	0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+	0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+	0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+	0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+	0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+	0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+	0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+	0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+	0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+	0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+	0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+	0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+	0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+	0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+	0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+	0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+	0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+	0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+	0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+	0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+	0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+	0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+	0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+	0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+	0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+	0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+	0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+	0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+	0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+	0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+	0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+	0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+	0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+	0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+	0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+	0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+	0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+	0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+	0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+	0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+	0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+	0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+	0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+	0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+int bcrypt_init(struct bcrypt_ctx *ctx, void *key, int keylen,
+		unsigned long state_len)
+{
+	unsigned char *state;
+	unsigned char *p = key;
+	unsigned long i, j;
+	unsigned long k = 0;
+
+	state = malloc(state_len);
+	if (state == NULL)
+		return -1;
+
+	ctx->i = 0;
+	ctx->j = 0;
+	ctx->state = state;
+	ctx->state_len = state_len;
+
+	for (i = 0; i < state_len; i++)
+		state[i] = i;
+
+	for(i = 0, j = 0; i < state_len; i++, j = (j + 1) % keylen) {
+		unsigned char t;
+
+		t = state[i];
+		k = (k + p[j] + t) % state_len;
+		state[i] = state[k];
+		state[k] = t;
+	}
+
+	return 0;
+}
+
+int bcrypt_process(struct bcrypt_ctx *ctx, unsigned char *src,
+		   unsigned char *dst, unsigned long len)
+{
+	unsigned char *state = ctx->state;
+	unsigned long state_len = ctx->state_len;
+	unsigned char i, j;
+	unsigned long k;
+
+	i = ctx->i;
+	j = ctx->j;
+
+	for (k = 0; k < len; k++) {
+		unsigned char t;
+
+		i = (i + 1) % state_len;
+		j = (j + state[i]) % state_len;
+		t = state[j];
+		state[j] = state[i];
+		state[i] = t;
+
+		dst[k] = src[k] ^ state[(state[i] + state[j]) % state_len];
+	}
+
+	ctx->i = i;
+	ctx->j = j;
+
+	return len;
+}
+
+void bcrypt_finish(struct bcrypt_ctx *ctx)
+{
+	if (ctx->state)
+		free(ctx->state);
+}
+
+int bcrypt_buf(unsigned char seed, unsigned char *key, unsigned char *src,
+	       unsigned char *dst, unsigned long len, int longstate)
+{
+	unsigned char bckey[BCRYPT_MAX_KEYLEN + 1];
+	unsigned int keylen;
+	struct bcrypt_ctx ctx;
+	int ret;
+
+	/* setup decryption key */
+	keylen = strlen((char *) key);
+	bckey[0] = seed;
+	memcpy(&bckey[1], key, keylen);
+
+	keylen++;
+
+	ret = bcrypt_init(&ctx, bckey, keylen,
+			  (longstate) ? len : BCRYPT_DEFAULT_STATE_LEN);
+	if (ret)
+		return ret;
+
+	bcrypt_process(&ctx, src, dst, len);
+	bcrypt_finish(&ctx);
+
+	return 0;
+}
+
+uint32_t buffalo_csum(uint32_t csum, void *buf, unsigned long len)
+{
+	signed char *p = buf;
+
+	while (len--) {
+		int i;
+
+		csum ^= *p++;
+		for (i = 0; i < 8; i++)
+			csum = (csum >> 1) ^ ((csum & 1) ? 0xedb88320ul : 0);
+	}
+
+	return csum;
+}
+
+uint32_t buffalo_crc(void *buf, unsigned long len)
+{
+	unsigned char *p = buf;
+	unsigned long t = len;
+	uint32_t crc = 0;
+
+	while (len--)
+		crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *p++) & 0xFF];
+
+	while (t) {
+		crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ t) & 0xFF];
+		t >>= 8;
+	}
+
+	return ~crc;
+}
+
+unsigned long enc_compute_header_len(char *product, char *version)
+{
+	return ENC_MAGIC_LEN + 1 + strlen(product) + 1 +
+	       strlen(version) + 1 + 3 * sizeof(uint32_t);
+}
+
+unsigned long enc_compute_buf_len(char *product, char *version,
+				  unsigned long datalen)
+{
+	unsigned long ret;
+
+	ret = enc_compute_header_len(product, version);
+	ret += datalen + sizeof(uint32_t);
+	ret += (4 - ret % 4);
+
+	return ret;
+}
+
+static void put_be32(void *data, uint32_t val)
+{
+	unsigned char *p = data;
+
+	p[0] = (val >> 24) & 0xff;
+	p[1] = (val >> 16) & 0xff;
+	p[2] = (val >> 8) & 0xff;
+	p[3] = val & 0xff;
+}
+
+static uint32_t get_be32(void *data)
+{
+	unsigned char *p = data;
+
+	return (((uint32_t)p[0]) << 24) |
+	       (((uint32_t)p[1]) << 16) |
+	       (((uint32_t)p[2]) << 8) |
+	       ((uint32_t)p[3]);
+}
+
+static int check_magic(void *magic)
+{
+	if (!memcmp("start", magic, ENC_MAGIC_LEN))
+		return 0;
+
+	if (!memcmp("asar1", magic, ENC_MAGIC_LEN))
+		return 0;
+
+	return -1;
+}
+
+int encrypt_buf(struct enc_param *ep, unsigned char *hdr,
+		unsigned char *data)
+{
+	unsigned char *p;
+	uint32_t len;
+	int err;
+	int ret = -1;
+	unsigned char s;
+
+	p = (unsigned char *) hdr;
+
+	/* setup magic */
+	len = strlen((char *) ep->magic) + 1;
+	memcpy(p, ep->magic, len);
+	p += len;
+
+	/* setup seed */
+	*p++ = ep->seed;
+
+	/* put product len */
+	len = strlen((char *) ep->product) + 1;
+	put_be32(p, len);
+	p += sizeof(uint32_t);
+
+	/* copy and crypt product name */
+	memcpy(p, ep->product, len);
+	err = bcrypt_buf(ep->seed, ep->key, p, p, len, ep->longstate);
+	if (err)
+		goto out;
+	s = *p;
+	p += len;
+
+	/* put version length */
+	len = strlen((char *) ep->version) + 1;
+	put_be32(p, len);
+	p += sizeof(uint32_t);
+
+	/* copy and crypt version */
+	memcpy(p, ep->version, len);
+	err = bcrypt_buf(s, ep->key, p, p, len, ep->longstate);
+	if (err)
+		goto out;
+	s = *p;
+	p += len;
+
+	/* put data length */
+	put_be32(p, ep->datalen);
+
+	/* encrypt data */
+	err = bcrypt_buf(s, ep->key, data, data, ep->datalen, ep->longstate);
+	if (err)
+		goto out;
+
+	/* put checksum */
+	put_be32(&data[ep->datalen], ep->csum);
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+int decrypt_buf(struct enc_param *ep, unsigned char *data,
+		unsigned long datalen)
+{
+	unsigned char *p;
+	uint32_t prod_len;
+	uint32_t ver_len;
+	uint32_t len;
+	uint32_t csum;
+	ssize_t remain;
+	int err;
+	int ret = -1;
+
+#define CHECKLEN(_l) do {		\
+	len = (_l);			\
+	if (remain < len) {		\
+		goto out;		\
+	}				\
+} while (0)
+
+#define INCP() do {			\
+	p += len;			\
+	remain -= len;			\
+} while (0)
+
+	remain = datalen;
+	p = data;
+
+	CHECKLEN(ENC_MAGIC_LEN);
+	err = check_magic(p);
+	if (err)
+		goto out;
+	memcpy(ep->magic, p, ENC_MAGIC_LEN);
+	INCP();
+
+	CHECKLEN(1);
+	ep->seed = *p;
+	INCP();
+
+	CHECKLEN(sizeof(uint32_t));
+	prod_len = get_be32(p);
+	if (prod_len > ENC_PRODUCT_LEN)
+		goto out;
+	INCP();
+
+	CHECKLEN(prod_len);
+	memcpy(ep->product, p, prod_len);
+	INCP();
+
+	CHECKLEN(sizeof(uint32_t));
+	ver_len = get_be32(p);
+	if (ver_len > ENC_VERSION_LEN)
+		goto out;
+	INCP();
+
+	CHECKLEN(ver_len);
+	memcpy(ep->version, p, ver_len);
+	INCP();
+
+	CHECKLEN(sizeof(uint32_t));
+	ep->datalen = get_be32(p);
+	INCP();
+
+	/* decrypt data */
+	CHECKLEN(ep->datalen);
+	err = bcrypt_buf(ep->version[0], ep->key, p, data, ep->datalen,
+			 ep->longstate);
+	if (err)
+		goto out;
+	INCP();
+
+	CHECKLEN(sizeof(uint32_t));
+	ep->csum = get_be32(p);
+	INCP();
+
+	csum = buffalo_csum(ep->datalen, data, ep->datalen);
+	if (csum != ep->csum)
+		goto out;
+
+	/* decrypt product name */
+	err = bcrypt_buf(ep->product[0], ep->key, ep->version, ep->version,
+			 ver_len, ep->longstate);
+	if (err)
+		goto out;
+
+	/* decrypt version */
+	err = bcrypt_buf(ep->seed, ep->key, ep->product, ep->product, prod_len,
+			 ep->longstate);
+	if (err)
+		goto out;
+
+	ret = 0;
+out:
+	return ret;
+
+#undef CHECKLEN
+#undef INCP
+}
+
+ssize_t get_file_size(char *name)
+{
+	struct stat st;
+	int err;
+
+	err = stat(name, &st);
+	if (err)
+		return -1;
+
+	return st.st_size;
+}
+
+int read_file_to_buf(char *name, void *buf, ssize_t buflen)
+{
+	FILE *f;
+	size_t done;
+	int ret = -1;
+
+	f = fopen(name, "r");
+	if (f == NULL)
+		goto out;
+
+	errno = 0;
+	done = fread(buf, buflen, 1, f);
+	if (done != 1)
+		goto close;
+
+	ret = 0;
+
+close:
+	fclose(f);
+out:
+	return ret;
+}
+
+int write_buf_to_file(char *name, void *buf, ssize_t buflen)
+{
+	FILE *f;
+	size_t done;
+	int ret = -1;
+
+	f = fopen(name, "w");
+	if (f == NULL)
+		goto out;
+
+	errno = 0;
+	done = fwrite(buf, buflen, 1, f);
+	if (done != 1)
+		goto close;
+
+	ret = 0;
+
+close:
+	fflush(f);
+	fclose(f);
+	if (ret)
+		unlink(name);
+out:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/buffalo-lib.h b/tools/firmware-utils/src/buffalo-lib.h
new file mode 100644
index 0000000000..ba8a508129
--- /dev/null
+++ b/tools/firmware-utils/src/buffalo-lib.h
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ */
+
+#ifndef _BUFFALO_LIB_H
+#define _BUFFALO_LIB_H
+
+#include <stdint.h>
+
+#define ARRAY_SIZE(_a)	(sizeof((_a)) / sizeof((_a)[0]))
+#define BIT(_x)		(1UL << (_x))
+
+#define TAG_BRAND_LEN		32
+#define TAG_PRODUCT_LEN		32
+#define TAG_VERSION_LEN		8
+#define TAG_REGION_LEN		2
+#define TAG_LANGUAGE_LEN	8
+#define TAG_PLATFORM_LEN	8
+#define TAG_HWVER_LEN		4
+#define TAG_HWVER_VAL_LEN	4
+
+struct buffalo_tag {
+	unsigned char	product[TAG_PRODUCT_LEN];
+	unsigned char	brand[TAG_BRAND_LEN];
+	unsigned char	ver_major[TAG_VERSION_LEN];
+	unsigned char	ver_minor[TAG_VERSION_LEN];
+	unsigned char	region_code[2];
+	uint32_t	region_mask;
+	unsigned char	unknown0[2];
+	unsigned char	language[TAG_LANGUAGE_LEN];
+	unsigned char	platform[TAG_PLATFORM_LEN];
+	unsigned char	hwv[TAG_HWVER_LEN];
+	unsigned char	hwv_val[TAG_HWVER_VAL_LEN];
+	uint8_t		unknown1[24];
+
+	uint32_t	len;
+	uint32_t	crc;
+	uint32_t	base1;
+	uint32_t	base2;
+	uint32_t	data_len;
+	uint8_t		flag;
+	uint8_t		unknown2[3];
+} __attribute ((packed));
+
+struct buffalo_tag2 {
+	unsigned char	product[TAG_PRODUCT_LEN];
+	unsigned char	brand[TAG_BRAND_LEN];
+	unsigned char	ver_major[TAG_VERSION_LEN];
+	unsigned char	ver_minor[TAG_VERSION_LEN];
+	unsigned char	region_code[2];
+	uint32_t	region_mask;
+	unsigned char	unknown0[2];
+	unsigned char	language[TAG_LANGUAGE_LEN];
+	unsigned char	platform[TAG_PLATFORM_LEN];
+	unsigned char	hwv[TAG_HWVER_LEN];
+	unsigned char	hwv_val[TAG_HWVER_VAL_LEN];
+	uint8_t		unknown1[24];
+
+	uint32_t	total_len;
+	uint32_t	crc;
+	uint32_t	len1;
+	uint32_t	len2;
+	uint8_t		flag;
+	uint8_t		unknown2[3];
+} __attribute ((packed));
+
+#define ENC_PRODUCT_LEN		32
+#define ENC_VERSION_LEN		8
+#define ENC_MAGIC_LEN		6
+
+unsigned long enc_compute_header_len(char *product, char *version);
+unsigned long enc_compute_buf_len(char *product, char *version,
+				  unsigned long datalen);
+
+struct enc_param {
+	unsigned char *key;
+	unsigned char magic[ENC_MAGIC_LEN];
+	unsigned char product[ENC_PRODUCT_LEN];
+	unsigned char version[ENC_VERSION_LEN];
+	unsigned char seed;
+	int longstate;
+	unsigned datalen;
+	uint32_t csum;
+};
+
+int encrypt_buf(struct enc_param *ep, unsigned char *hdr,
+	        unsigned char *data);
+int decrypt_buf(struct enc_param *ep, unsigned char *data,
+		unsigned long datalen);
+
+#define BCRYPT_DEFAULT_STATE_LEN	256
+#define BCRYPT_MAX_KEYLEN		254
+
+struct bcrypt_ctx {
+	unsigned long i;
+	unsigned long j;
+	unsigned char *state;
+	unsigned long state_len;
+};
+
+int bcrypt_init(struct bcrypt_ctx *ctx, void *key, int keylen,
+		unsigned long state_len);
+int bcrypt_process(struct bcrypt_ctx *ctx, unsigned char *src,
+		   unsigned char *dst, unsigned long len);
+void bcrypt_finish(struct bcrypt_ctx *ctx);
+int bcrypt_buf(unsigned char seed, unsigned char *key, unsigned char *src,
+	       unsigned char *dst, unsigned long len, int longstate);
+
+uint32_t buffalo_csum(uint32_t csum, void *buf, unsigned long len);
+uint32_t buffalo_crc(void *buf, unsigned long len);
+
+ssize_t get_file_size(char *name);
+int read_file_to_buf(char *name, void *buf, ssize_t buflen);
+int write_buf_to_file(char *name, void *buf, ssize_t buflen);
+
+#endif /* _BUFFALO_LIB_H */
diff --git a/tools/firmware-utils/src/buffalo-tag.c b/tools/firmware-utils/src/buffalo-tag.c
new file mode 100644
index 0000000000..b5db72ef96
--- /dev/null
+++ b/tools/firmware-utils/src/buffalo-tag.c
@@ -0,0 +1,374 @@
+/*
+ *  Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <netinet/in.h>
+
+#include "buffalo-lib.h"
+
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static char *region_table[] = {
+	"JP", "US", "EU", "AP", "TW", "KR"
+};
+
+#define MAX_INPUT_FILES	2
+
+static char *progname;
+static char *ifname[MAX_INPUT_FILES];
+static ssize_t fsize[MAX_INPUT_FILES];
+static int num_files;
+static char *ofname;
+static char *product;
+static char *brand;
+static char *language;
+static char *hwver;
+static char *platform;
+static int flag;
+static char *major;
+static char *minor = "1.01";
+static int skipcrc;
+static uint32_t base1;
+static uint32_t base2;
+static char *region_code;
+static uint32_t region_mask;
+static int num_regions;
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -a <platform>   set platform to <platform>\n"
+"  -b <brand>      set brand to <brand>\n"
+"  -c <base1>\n"
+"  -d <base2>\n"
+"  -f <flag>       set flag to <flag>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -l <language>   set language to <language>\n"
+"  -m <version>    set minor version to <version>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -p <product>    set product to <product>\n"
+"  -r <region>     set image region to <region>\n"
+"		   valid regions: JP, US, EU, AP, TW, KR, M_\n"
+"  -s              skip CRC calculation\n"
+"  -v <version>    set major version to <version>\n"
+"  -w <version>    set harwdware version to <version>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static int check_params(void)
+{
+
+#define CHECKSTR(_var, _name, _len)	do {		\
+	if ((_var) == NULL) {				\
+		ERR("no %s specified", (_name));	\
+		return -1;				\
+	}						\
+	if ((_len) > 0 &&				\
+	    strlen((_var)) > ((_len) - 1)) {		\
+		ERR("%s is too long", (_name));		\
+		return -1;				\
+	}						\
+} while (0)
+
+	if (num_files == 0)
+		ERR("no input files specified");
+
+	CHECKSTR(ofname, "output file", 0);
+	CHECKSTR(brand, "brand", TAG_BRAND_LEN);
+	CHECKSTR(product, "product", TAG_PRODUCT_LEN);
+	CHECKSTR(platform, "platform", TAG_PLATFORM_LEN);
+	CHECKSTR(major, "major version", TAG_VERSION_LEN);
+	CHECKSTR(minor, "minor version", TAG_VERSION_LEN);
+	CHECKSTR(language, "language", TAG_LANGUAGE_LEN);
+
+	if (hwver)
+		CHECKSTR(hwver, "hardware version", 2);
+
+	if (num_regions == 0) {
+		ERR("no region code specified");
+		return -1;
+	}
+
+	return 0;
+
+#undef CHECKSTR
+}
+
+static int process_region(char *reg)
+{
+	int i;
+
+	if (strlen(reg) != 2) {
+		ERR("invalid region code '%s'", reg);
+		return -1;
+	}
+
+	if (strcmp(reg, "M_") == 0) {
+		region_code = reg;
+		region_mask |= ~0;
+		num_regions = 32;
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(region_table); i++)
+		if (strcmp(reg, region_table[i]) == 0) {
+			region_code = reg;
+			region_mask |= 1 << i;
+			num_regions++;
+			return 0;
+		}
+
+	ERR("unknown region code '%s'", reg);
+	return -1;
+}
+
+static int process_ifname(char *name)
+{
+	if (num_files >= ARRAY_SIZE(ifname)) {
+		ERR("too many input files specified");
+		return -1;
+	}
+
+	ifname[num_files++] = name;
+	return 0;
+}
+
+static void fixup_tag(unsigned char *buf, ssize_t buflen)
+{
+	struct buffalo_tag *tag = (struct buffalo_tag *) buf;
+
+	memset(tag, '\0', sizeof(*tag));
+
+	memcpy(tag->brand, brand, strlen(brand));
+	memcpy(tag->product, product, strlen(product));
+	memcpy(tag->platform, platform, strlen(platform));
+	memcpy(tag->ver_major, major, strlen(major));
+	memcpy(tag->ver_minor, minor, strlen(minor));
+	memcpy(tag->language, language, strlen(language));
+
+	if (num_regions > 1) {
+		tag->region_code[0] = 'M';
+		tag->region_code[1] = '_';
+		tag->region_mask = htonl(region_mask);
+	} else {
+		memcpy(tag->region_code, region_code, 2);
+	}
+
+	tag->len = htonl(buflen);
+	tag->data_len = htonl(fsize[0]);
+	tag->base1 = htonl(base1);
+	tag->base2 = htonl(base2);
+	tag->flag = flag;
+
+	if (hwver) {
+		memcpy(tag->hwv, "hwv", 3);
+		memcpy(tag->hwv_val, hwver, strlen(hwver));
+	}
+
+	if (!skipcrc)
+		tag->crc = htonl(buffalo_crc(buf, buflen));
+}
+
+static void fixup_tag2(unsigned char *buf, ssize_t buflen)
+{
+	struct buffalo_tag2 *tag = (struct buffalo_tag2 *) buf;
+
+	memset(tag, '\0', sizeof(*tag));
+
+	memcpy(tag->brand, brand, strlen(brand));
+	memcpy(tag->product, product, strlen(product));
+	memcpy(tag->platform, platform, strlen(platform));
+	memcpy(tag->ver_major, major, strlen(major));
+	memcpy(tag->ver_minor, minor, strlen(minor));
+	memcpy(tag->language, language, strlen(language));
+
+	if (num_regions > 1) {
+		tag->region_code[0] = 'M';
+		tag->region_code[1] = '_';
+		tag->region_mask = htonl(region_mask);
+	} else {
+		memcpy(tag->region_code, region_code, 2);
+	}
+
+	tag->total_len = htonl(buflen);
+	tag->len1 = htonl(fsize[0]);
+	tag->len2 = htonl(fsize[1]);
+	tag->flag = flag;
+
+	if (hwver) {
+		memcpy(tag->hwv, "hwv", 3);
+		memcpy(tag->hwv_val, hwver, strlen(hwver));
+	}
+
+	if (!skipcrc)
+		tag->crc = htonl(buffalo_crc(buf, buflen));
+}
+
+static int tag_file(void)
+{
+	unsigned char *buf;
+	ssize_t offset;
+	ssize_t hdrlen;
+	ssize_t buflen;
+	int err;
+	int ret = -1;
+	int i;
+
+	if (num_files == 1)
+		hdrlen = sizeof(struct buffalo_tag);
+	else
+		hdrlen = sizeof(struct buffalo_tag2);
+
+	buflen = hdrlen;
+
+	for (i = 0; i < num_files; i++) {
+		fsize[i] = get_file_size(ifname[i]);
+		if (fsize[i] < 0) {
+			ERR("unable to get size of '%s'", ifname[i]);
+			goto out;
+		}
+		buflen += fsize[i];
+	}
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	offset = hdrlen;
+	for (i = 0; i < num_files; i++) {
+		err = read_file_to_buf(ifname[i], buf + offset, fsize[i]);
+		if (err) {
+			ERR("unable to read from file '%s'", ifname[i]);
+			goto free_buf;
+		}
+
+		offset += fsize[i];
+	}
+
+	if (num_files == 1)
+		fixup_tag(buf, buflen);
+	else
+		fixup_tag2(buf, buflen);
+
+	err = write_buf_to_file(ofname, buf, buflen);
+	if (err) {
+		ERR("unable to write to file '%s'", ofname);
+		goto free_buf;
+	}
+
+	ret = 0;
+
+free_buf:
+	free(buf);
+out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int err;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "a:b:c:d:f:hi:l:m:o:p:r:sv:w:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'a':
+			platform = optarg;
+			break;
+		case 'b':
+			brand = optarg;
+			break;
+		case 'c':
+			base1 = strtoul(optarg, NULL, 16);
+			break;
+		case 'd':
+			base2 = strtoul(optarg, NULL, 16);
+			break;
+		case 'f':
+			flag = strtoul(optarg, NULL, 2);
+			break;
+		case 'i':
+			err = process_ifname(optarg);
+			if (err)
+				goto out;
+			break;
+		case 'l':
+			language = optarg;
+			break;
+		case 'm':
+			minor = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'p':
+			product = optarg;
+			break;
+		case 'r':
+			err = process_region(optarg);
+			if (err)
+				goto out;
+			break;
+		case 's':
+			skipcrc = 1;
+			break;
+		case 'v':
+			major = optarg;
+			break;
+		case 'w':
+			hwver = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	err = check_params();
+	if (err)
+		goto out;
+
+	err = tag_file();
+	if (err)
+		goto out;
+
+	res = EXIT_SUCCESS;
+
+out:
+	return res;
+}
diff --git a/tools/firmware-utils/src/buffalo-tftp.c b/tools/firmware-utils/src/buffalo-tftp.c
new file mode 100644
index 0000000000..087f9955b6
--- /dev/null
+++ b/tools/firmware-utils/src/buffalo-tftp.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+
+#include "buffalo-lib.h"
+
+#define ERR(fmt, args...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## args ); \
+} while (0)
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static int do_decrypt;
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -d              decrypt instead of encrypt\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static const unsigned char *crypt_key1 = (unsigned char *)
+	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+static const unsigned char *crypt_key2 = (unsigned char *)
+	"XYZ0123hijklmnopqABCDEFGHrstuvabcdefgwxyzIJKLMSTUVW456789NOPQR";
+
+static void crypt_header(unsigned char *buf, ssize_t len,
+			 const unsigned char *key1, const unsigned char *key2)
+{
+	ssize_t i;
+
+	for (i = 0; i < len; i++) {
+		unsigned int j;
+
+		for (j = 0; key1[j]; j++)
+			if (buf[i] == key1[j]) {
+				buf[i] = key2[j];
+				break;
+			}
+	}
+}
+
+static int crypt_file(void)
+{
+	unsigned char *buf = NULL;
+	ssize_t src_len;
+	int err;
+	int ret = -1;
+
+	src_len = get_file_size(ifname);
+	if (src_len < 0) {
+		ERR("unable to get size of '%s'", ifname);
+		goto out;
+	}
+
+	buf = malloc(src_len);
+	if (buf == NULL) {
+		ERR("no memory for the buffer");
+		goto out;
+	}
+
+	err = read_file_to_buf(ifname, buf, src_len);
+	if (err) {
+		ERR("unable to read from file '%s'", ifname);
+		goto out;
+	}
+
+	if (do_decrypt)
+		crypt_header(buf, 512, crypt_key2, crypt_key1);
+	else
+		crypt_header(buf, 512, crypt_key1, crypt_key2);
+
+	err = write_buf_to_file(ofname, buf, src_len);
+	if (err) {
+		ERR("unable to write to file '%s'", ofname);
+		goto out;
+	}
+
+	ret = 0;
+
+out:
+	free(buf);
+	return ret;
+}
+
+static int check_params(void)
+{
+	int ret = -1;
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto out;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto out;
+	}
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int err;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "di:o:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'd':
+			do_decrypt = 1;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	err = check_params();
+	if (err)
+		goto out;
+
+	err = crypt_file();
+	if (err)
+		goto out;
+
+	res = EXIT_SUCCESS;
+
+out:
+	return res;
+}
diff --git a/tools/firmware-utils/src/csysimg.h b/tools/firmware-utils/src/csysimg.h
new file mode 100644
index 0000000000..65ab062f31
--- /dev/null
+++ b/tools/firmware-utils/src/csysimg.h
@@ -0,0 +1,79 @@
+/*
+ *
+ *  Copyright (C) 2007,2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program was based on the code found in various Linux
+ *  source tarballs released by Edimax for it's devices.
+ *  Original author: David Hsu <davidhsu@realtek.com.tw>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the
+ *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+
+#define SIG_LEN		4
+
+#define ADM_CODE_ADDR	0x80500000
+#define ADM_WEBP_ADDR	0x10000
+#define ADM_WEBP_SIZE	0x10000
+#define ADM_BOOT_SIZE	0x8000
+#define ADM_CONF_SIZE	0x8000
+#define ADM_BOOT_SIG	"\x00\x60\x1A\x40"
+
+
+/*
+ * Generic signatures
+ */
+#define SIG_CSYS	"CSYS"
+#define SIG_CONF	"HS\x00\x00"
+#define SIG_BOOT_RTL	"\x00\x00\x40\x21"
+
+/*
+ * Web page signatures
+ */
+#define SIG_BR6104K	"WB4K"
+#define SIG_BR6104KP	"WBKP"
+#define SIG_BR6104Wg	"WBGW"
+#define SIG_BR6104IPC	"WBIP"
+#define SIG_BR6114WG	SIG_BR6104IPC
+#define SIG_BR6524K	"2-K-"
+#define SIG_BR6524KP	"2-KP"	/* FIXME: valid? */
+#define SIG_BR6524N	"WNRA"
+#define SIG_BR6524WG	"2-WG"	/* FIXME: valid? */
+#define SIG_BR6524WP	"2-WP"	/* FIXME: valid? */
+#define SIG_BR6541K	"4--K"
+#define SIG_BR6541KP	"4-KP"	/* FIXME: valid? */
+#define SIG_BR6541WP	"4-WP"	/* FIXME: valid? */
+#define SIG_C54BSR4	SIG_BR6104IPC
+#define SIG_EW7207APg	"EWAS"
+#define SIG_PS1205UWg	"4000"
+#define SIG_PS3205U	"5010"
+#define SIG_PS3205UWg	"5011"
+#define SIG_RALINK	"RNRA"
+#define SIG_5GXI	"5GXI"	/* fake signature */
+
+#define SIG_H2BR4	SIG_BR6524K
+#define SIG_H2WR54G	SIG_BR6524WG
+
+#define SIG_XRT401D	SIG_BR6104K
+#define SIG_XRT402D	SIG_BR6524K
+
+/*
+ * CSYS image file header
+ */
+struct csys_header {
+	unsigned char sig[SIG_LEN];
+	uint32_t addr;
+	uint32_t size;
+};
diff --git a/tools/firmware-utils/src/cyg_crc.h b/tools/firmware-utils/src/cyg_crc.h
new file mode 100644
index 0000000000..7b59803446
--- /dev/null
+++ b/tools/firmware-utils/src/cyg_crc.h
@@ -0,0 +1,109 @@
+//==========================================================================
+//
+//      crc.h
+//
+//      Interface for the CRC algorithms.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Andrew Lunn
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2002-08-06
+// Purpose:
+// Description:
+//
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef _SERVICES_CRC_CRC_H_
+#define _SERVICES_CRC_CRC_H_
+
+#if 0
+#include <cyg/infra/cyg_type.h>
+#else
+#include <stdint.h>
+typedef uint32_t cyg_uint32;
+typedef uint16_t cyg_uint16;
+#endif
+
+#ifndef __externC
+# ifdef __cplusplus
+#  define __externC extern "C"
+# else
+#  define __externC extern
+# endif
+#endif
+
+// Compute a CRC, using the POSIX 1003 definition
+
+__externC cyg_uint32
+cyg_posix_crc32(unsigned char *s, int len);
+
+// Gary S. Brown's 32 bit CRC
+
+__externC cyg_uint32
+cyg_crc32(unsigned char *s, int len);
+
+// Gary S. Brown's 32 bit CRC, but accumulate the result from a
+// previous CRC calculation
+
+__externC cyg_uint32
+cyg_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len);
+
+// Ethernet FCS Algorithm
+
+__externC cyg_uint32
+cyg_ether_crc32(unsigned char *s, int len);
+
+// Ethernet FCS algorithm, but accumulate the result from a previous
+// CRC calculation.
+
+__externC cyg_uint32
+cyg_ether_crc32_accumulate(cyg_uint32 crc, unsigned char *s, int len);
+
+// 16 bit CRC with polynomial x^16+x^12+x^5+1
+
+__externC cyg_uint16
+cyg_crc16(unsigned char *s, int len);
+
+#endif // _SERVICES_CRC_CRC_H_
+
+
+
diff --git a/tools/firmware-utils/src/cyg_crc16.c b/tools/firmware-utils/src/cyg_crc16.c
new file mode 100644
index 0000000000..8b3735289f
--- /dev/null
+++ b/tools/firmware-utils/src/cyg_crc16.c
@@ -0,0 +1,110 @@
+//==========================================================================
+//
+//      crc16.c
+//
+//      16 bit CRC with polynomial x^16+x^12+x^5+1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas,asl
+// Date:         2001-01-31
+// Purpose:      
+// Description:  
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#if 0
+#include <cyg/crc/crc.h>
+#else
+#include "cyg_crc.h"
+#endif
+
+// Table of CRC constants - implements x^16+x^12+x^5+1
+static const cyg_uint16 crc16_tab[] = {
+    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 
+    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 
+    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 
+    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 
+    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 
+    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 
+    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 
+    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 
+    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 
+    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 
+    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 
+    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 
+    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 
+    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 
+    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 
+    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 
+    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 
+    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 
+    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 
+    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 
+    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 
+    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 
+    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 
+    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 
+    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 
+    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 
+    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 
+    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 
+    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 
+    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 
+    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 
+    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, 
+};
+
+cyg_uint16
+cyg_crc16(unsigned char *buf, int len)
+{
+    int i;
+    cyg_uint16 cksum;
+
+    cksum = 0;
+    for (i = 0;  i < len;  i++) {
+        cksum = crc16_tab[((cksum>>8) ^ *buf++) & 0xFF] ^ (cksum << 8);
+    }
+    return cksum;
+}
+
diff --git a/tools/firmware-utils/src/cyg_crc32.c b/tools/firmware-utils/src/cyg_crc32.c
new file mode 100644
index 0000000000..9462598ae6
--- /dev/null
+++ b/tools/firmware-utils/src/cyg_crc32.c
@@ -0,0 +1,172 @@
+//==========================================================================
+//
+//      crc32.c
+//
+//      Gary S. Brown's 32 bit CRC
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas,asl
+// Date:         2001-01-31
+// Purpose:      
+// Description:  
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#if 0
+#include <cyg/crc/crc.h>
+#else
+#include "cyg_crc.h"
+#endif
+
+  /* ====================================================================== */
+  /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
+  /*  code or tables extracted from it, as desired without restriction.     */
+  /*                                                                        */
+  /*  First, the polynomial itself and its table of feedback terms.  The    */
+  /*  polynomial is                                                         */
+  /*  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0   */
+  /*                                                                        */
+  /* ====================================================================== */
+
+static const cyg_uint32 crc32_tab[] = {
+      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+      0x2d02ef8dL
+   };
+
+/* This is the standard Gary S. Brown's 32 bit CRC algorithm, but
+   accumulate the CRC into the result of a previous CRC. */
+cyg_uint32 
+cyg_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len)
+{
+  int i;
+
+  for (i = 0;  i < len;  i++) {
+    crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val;
+}
+
+/* This is the standard Gary S. Brown's 32 bit CRC algorithm */
+cyg_uint32
+cyg_crc32(unsigned char *s, int len)
+{
+  return (cyg_crc32_accumulate(0,s,len));
+}
+
+/* Return a 32-bit CRC of the contents of the buffer accumulating the
+   result from a previous CRC calculation. This uses the Ethernet FCS
+   algorithm.*/
+cyg_uint32
+cyg_ether_crc32_accumulate(cyg_uint32 crc32val, unsigned char *s, int len)
+{
+  int i;
+
+  if (s == 0) return 0L;
+  
+  crc32val = crc32val ^ 0xffffffff;
+  for (i = 0;  i < len;  i++) {
+      crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val ^ 0xffffffff;
+}
+
+/* Return a 32-bit CRC of the contents of the buffer, using the
+   Ethernet FCS algorithm. */
+cyg_uint32
+cyg_ether_crc32(unsigned char *s, int len)
+{
+  return cyg_ether_crc32_accumulate(0,s,len);
+}
+
+
diff --git a/tools/firmware-utils/src/dgfirmware.c b/tools/firmware-utils/src/dgfirmware.c
new file mode 100644
index 0000000000..e3257f1077
--- /dev/null
+++ b/tools/firmware-utils/src/dgfirmware.c
@@ -0,0 +1,377 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#define IMG_SIZE     0x3e0000
+
+#define KERNEL_START 0x020000
+#define KERNEL_SIZE  0x0b0000
+
+#define ROOTFS_START 0x0d0000
+#define ROOTFS_SIZE  0x30ffb2
+
+char* app_name;
+
+
+
+
+void print_usage(void)
+{
+  fprintf(stderr, "usage: dgfirmware [<opts>] <img>\n");
+  fprintf(stderr, "  <img>               firmware image filename\n");
+  fprintf(stderr, "  <opts>  -h          print this message\n");
+  fprintf(stderr, "          -f          fix the checksum\n");
+  fprintf(stderr, "          -x  <file>  extract the rootfs file to <file>\n");
+  fprintf(stderr, "          -xk <file>  extract the kernel to <file>\n");
+  fprintf(stderr, "          -m  <file>  merge in rootfs fil\e from <file>\n");
+  fprintf(stderr, "          -k  <file>  merge in kernel from <file>\n");
+  fprintf(stderr, "          -w  <file>  write back the modified firmware\n");
+}
+
+
+unsigned char* read_img(const char *fname)
+{
+  FILE *fp;
+  int size;
+  unsigned char *img;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size != IMG_SIZE) {
+    fprintf(stderr, "%s: image file has wrong size\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  img = malloc(IMG_SIZE);
+  if (img == NULL) {
+    perror(app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  if (fread(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+    fprintf(stderr, "%s: can't read image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+void write_img(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  if (fwrite(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+    fprintf(stderr, "%s: can't write image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+void write_rootfs(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+  
+  if (fwrite(img+ROOTFS_START, 1, ROOTFS_SIZE, fp) != ROOTFS_SIZE) {
+    fprintf(stderr, "%s: can't write image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+void write_kernel(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+
+  fp = fopen(fname, "wb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+  
+  if (fwrite(img+KERNEL_START, 1, KERNEL_SIZE, fp) != KERNEL_SIZE) {
+    fprintf(stderr, "%s: can't write kernel file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+}
+
+
+unsigned char* read_rootfs(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+  int size;
+  int i;
+
+  for (i=ROOTFS_START; i<ROOTFS_START+ROOTFS_SIZE; i++)
+    img[i] = 0xff;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size > ROOTFS_SIZE) {
+    fprintf(stderr, "%s: rootfs image file is too big\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  if (fread(img+ROOTFS_START, 1, size, fp) != size) {
+    fprintf(stderr, "%s: can't read rootfs image file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+unsigned char* read_kernel(unsigned char* img, const char *fname)
+{
+  FILE *fp;
+  int size;
+  int i;
+
+  for (i=KERNEL_START; i<KERNEL_START+KERNEL_SIZE; i++)
+    img[i] = 0xff;
+
+  fp = fopen(fname, "rb");
+  if (fp == NULL) {
+    perror(app_name);
+    exit(-1);
+  }
+
+  fseek(fp, 0, SEEK_END);
+  size = ftell(fp);
+  
+  if (size > KERNEL_SIZE) {
+    fprintf(stderr, "%s: kernel binary file is too big\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  rewind(fp);
+
+  if (fread(img+KERNEL_START, 1, size, fp) != size) {
+    fprintf(stderr, "%s: can't read kernel file\n", app_name);
+    fclose(fp);
+    exit(-1);
+  }
+
+  fclose(fp);
+  return img;
+}
+
+
+int get_checksum(unsigned char* img)
+{
+  short unsigned s;
+
+  s = img[0x3dfffc] + (img[0x3dfffd]<<8);
+
+  return s;
+}
+
+
+void set_checksum(unsigned char*img, unsigned short sum)
+{
+  img[0x3dfffc] = sum & 0xff;
+  img[0x3dfffd] = (sum>>8) & 0xff;
+}
+
+
+int compute_checksum(unsigned char* img)
+{
+  int i;
+  short s=0;
+
+  for (i=0; i<0x3dfffc; i++)
+    s += img[i];
+
+  return s;
+}
+
+
+int main(int argc, char* argv[])
+{
+  char *img_fname     = NULL;
+  char *rootfs_fname  = NULL;
+  char *kernel_fname  = NULL;
+  char *new_img_fname = NULL;
+
+  int do_fix_checksum = 0;
+  int do_write        = 0;
+  int do_write_rootfs = 0;
+  int do_read_rootfs  = 0;
+  int do_write_kernel = 0;
+  int do_read_kernel  = 0;
+
+  int i;
+  unsigned char *img;
+  unsigned short img_checksum;
+  unsigned short real_checksum;
+
+  app_name = argv[0];
+
+  for (i=1; i<argc; i++) {
+    if (!strcmp(argv[i], "-h")) {
+      print_usage();
+      return 0;
+    }
+    else if (!strcmp(argv[i], "-f")) {
+      do_fix_checksum = 1;
+    }
+    else if (!strcmp(argv[i], "-x")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_write_rootfs = 1;
+      rootfs_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-xk")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_write_kernel = 1;
+      kernel_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-m")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_read_rootfs = 1;
+      rootfs_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-k")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_read_kernel = 1;
+      kernel_fname = argv[i+1];
+      i++;
+    }
+    else if (!strcmp(argv[i], "-w")) {
+      if (i+1 >= argc) {
+	fprintf(stderr, "%s: missing argument\n", app_name);
+	return -1;
+      }
+      do_write = 1;
+      new_img_fname = argv[i+1];
+      i++;
+    }
+    else if (img_fname != 0) {
+      fprintf(stderr, "%s: too many arguments\n", app_name);
+      return -1;
+    }
+    else {
+      img_fname = argv[i];
+    }
+  }
+
+  if (img_fname == NULL) {
+    fprintf(stderr, "%s: missing argument\n", app_name);
+    return -1;
+  }
+
+  if ((do_read_rootfs && do_write_rootfs) ||
+      (do_read_kernel && do_write_kernel)) {
+    fprintf(stderr, "%s: conflictuous options\n", app_name);
+    return -1;
+  }
+
+  printf ("** Read firmware file\n");
+  img = read_img(img_fname);
+
+  printf ("Firmware product: %s\n", img+0x3dffbd);
+  printf ("Firmware version: 1.%02d.%02d\n", (img[0x3dffeb] & 0x7f), img[0x3dffec]);
+
+  if (do_write_rootfs) {
+    printf ("** Write rootfs file\n");
+    write_rootfs(img, rootfs_fname);
+  }
+
+  if (do_write_kernel) {
+    printf ("** Write kernel file\n");
+    write_kernel(img, kernel_fname);
+  }
+
+  if (do_read_rootfs) {
+    printf ("** Read rootfs file\n");
+    read_rootfs(img, rootfs_fname);
+    do_fix_checksum = 1;
+  }
+
+  if (do_read_kernel) {
+    printf ("** Read kernel file\n");
+    read_kernel(img, kernel_fname);
+    do_fix_checksum = 1;
+  }
+
+  img_checksum = get_checksum(img);
+  real_checksum = compute_checksum(img);
+  
+  printf ("image checksum = %04x\n", img_checksum);
+  printf ("real checksum  = %04x\n", real_checksum);
+
+  if (do_fix_checksum) {
+    if (img_checksum != real_checksum) {
+      printf ("** Bad Checksum, fix it\n");
+      set_checksum(img, real_checksum);
+    }
+    else {
+      printf ("** Checksum is correct, good\n");
+    }
+  }
+
+  if (do_write) {
+    printf ("** Write image file\n");
+    write_img(img, new_img_fname);
+  }
+
+  free(img);
+  return 0;
+}
+
diff --git a/tools/firmware-utils/src/dgn3500sum.c b/tools/firmware-utils/src/dgn3500sum.c
new file mode 100644
index 0000000000..00a0c5f837
--- /dev/null
+++ b/tools/firmware-utils/src/dgn3500sum.c
@@ -0,0 +1,167 @@
+/* **************************************************************************
+
+   This program creates a modified 16bit checksum used for the Netgear
+   DGN3500 series routers. The difference between this and a standard
+   checksum is that every 0x100 bytes added 0x100 have to be subtracted
+   from the sum.
+
+   (C) 2013 Marco Antonio Mauro <marcus90 at gmail.com>
+
+   Based on previous unattributed work.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ************************************************************************* */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+unsigned char PidDataWW[70] =
+{
+    0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+    0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37,
+    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+    0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+unsigned char PidDataDE[70] =
+{
+    0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x37,
+    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+    0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+unsigned char PidDataNA[70] =
+{
+    0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32,
+    0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37,
+    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
+    0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D,
+} ;
+
+/* *******************************************************************
+   Reads the file into memory and returns pointer to the buffer. */
+static char *readfile(char *filename, int *size)
+{
+	FILE		*fp;
+	char		*buffer;
+	struct stat	info;
+
+	if (stat(filename,&info)!=0)
+		return NULL;
+
+	if ((fp=fopen(filename,"r"))==NULL)
+		return NULL;
+
+	buffer=NULL;
+	for (;;)
+	{
+		if ((buffer=(char *)malloc(info.st_size+1))==NULL)
+			break;
+
+		if (fread(buffer,1,info.st_size,fp)!=info.st_size)
+		{
+			free(buffer);
+			buffer=NULL;
+			break;
+		}
+
+		buffer[info.st_size]='\0';
+		if(size) *size = info.st_size;
+
+		break;
+	}
+
+	(void)fclose(fp);
+
+	return buffer;
+}
+
+
+/* ******************************************************************* */
+int main(int argc, char** argv)
+{
+  unsigned long start, i;
+  char *endptr, *buffer, *p;
+  int count;  // size of file in bytes
+  unsigned short sum, sum1;
+  char sumbuf[9];
+
+  if(argc < 3) {
+    printf("ERROR: Argument missing!\n\nUsage %s filename starting offset in hex [PID code]\n\n", argv[0]);
+    return 1;
+  }
+
+
+  FILE *fp = fopen(argv[1], "a");
+  if(!fp) {
+    printf("ERROR: File not writeable!\n");
+    return 1;
+  }
+  if(argc = 4)
+  {
+    printf("%s: PID type: %s\n", argv[0], argv[3]);
+    if(strcmp(argv[3], "DE")==0)
+      fwrite(PidDataDE, sizeof(PidDataDE), sizeof(char), fp);  /* write DE pid */
+    else if(strcmp(argv[3], "NA")==0)
+      fwrite(PidDataNA, sizeof(PidDataNA), sizeof(char), fp);  /* write NA pid */
+    else /* if(strcmp(argv[3], "WW")) */
+      fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp);  /* write WW pid */
+  }
+  else
+    fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp);  /* write WW pid if unspecified */
+
+  fclose(fp);
+
+  /* Read the file to calculate the checksums */
+  buffer = readfile(argv[1], &count);
+  if(!buffer) {
+    printf("ERROR: File %s not found!\n", argv[1]);
+    return 1;
+  }
+
+  p = buffer;
+  for(i = 0; i < count; i++)
+  {
+	sum += p[i];
+  }
+
+  start = strtol(argv[2], &endptr, 16);
+  p = buffer+start;
+  sum1 = 0;
+  for(i = 0; i < count - start; i++)
+  {
+	sum1 += p[i];
+  }
+
+  sprintf(sumbuf,"%04X%04X",sum1,sum);
+  /* Append the 2 checksums to end of file */
+  fp = fopen(argv[1], "a");
+  if(!fp) {
+    printf("ERROR: File not writeable!\n");
+    return 1;
+  }
+  fwrite(sumbuf, 8, sizeof(char), fp);
+  fclose(fp);
+  free(buffer);
+  return 0;
+}
diff --git a/tools/firmware-utils/src/edimax_fw_header.c b/tools/firmware-utils/src/edimax_fw_header.c
new file mode 100644
index 0000000000..b85e3a1781
--- /dev/null
+++ b/tools/firmware-utils/src/edimax_fw_header.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define MAX_MAGIC_LEN		16
+#define MAX_MODEL_LEN		32
+#define MAX_VERSION_LEN		14
+#define MAX_MTD_NAME_LEN	16
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+struct edimax_header {
+	char		magic[MAX_MAGIC_LEN];
+	char		model[MAX_MODEL_LEN];
+	unsigned char	force;
+	unsigned char	header_csum;
+	unsigned char	data_csum;
+	uint32_t	data_size;
+	uint32_t	start_addr;
+	uint32_t	end_addr;
+	char		fw_version[MAX_VERSION_LEN];
+	unsigned char	type;
+	char		mtd_name[MAX_MTD_NAME_LEN];
+} __attribute__ ((packed));
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *ifname;
+static char *progname;
+
+static char *model;
+static char *magic = "eDiMaX";
+static char *fw_version = "";
+static char *mtd_name;
+static int force;
+static uint32_t start_addr;
+static uint32_t end_addr;
+static uint8_t image_type;
+static int data_size;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -e <addr>       set end addr to <addr>\n"
+"  -f              set force flag\n"
+"  -h              show this screen\n"
+"  -i <file>       read input data from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -m <model>      set model to <model>\n"
+"  -M <magic>      set image magic to <magic>\n"
+"  -n <name>       set MTD device name to <name>\n"
+"  -s <addr>       set start address to <addr>\n"
+"  -t <type>       set image type to <type>\n"
+"  -v <version>    set firmware version to <version>\n"
+	);
+
+	exit(status);
+}
+
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+		return -1;
+	}
+
+	*val = t & 0xFF;
+	return 0;
+}
+
+static int get_file_size(char *name)
+{
+	struct stat st;
+	int res;
+
+	res = stat(name, &st);
+	if (res){
+		ERRS("stat failed on %s", name);
+		return -1;
+	}
+
+	return st.st_size;
+}
+
+static int read_to_buf(char *name, char *buf, int buflen)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, buflen, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+out_close:
+	fclose(f);
+out:
+	return ret;
+}
+
+static int check_options(void)
+{
+#define CHKSTR(_name, _msg)				\
+	do {						\
+		if (_name == NULL) {			\
+			ERR("no %s specified", _msg);	\
+			return -1;			\
+		}					\
+	} while (0)
+
+#define CHKSTRLEN(_name, _msg)						\
+	do {								\
+		int field_len;						\
+		CHKSTR(_name, _msg);					\
+		field_len = FIELD_SIZEOF(struct edimax_header, _name) - 1; \
+		if (strlen(_name) > field_len) { 			\
+			ERR("'%s' is too long, max %s length is %d",	\
+			    _name, _msg, field_len);			\
+			return -1;					\
+		}							\
+	} while (0)
+
+	CHKSTR(ofname, "output file");
+	CHKSTR(ifname, "input file");
+
+	CHKSTRLEN(magic, "magic");
+	CHKSTRLEN(model, "model");
+	CHKSTRLEN(mtd_name, "MTD device name");
+	CHKSTRLEN(fw_version, "firware version");
+
+	data_size = get_file_size(ifname);
+	if (data_size < 0)
+		return -1;
+
+	return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+out:
+	return ret;
+}
+
+static unsigned char checksum(unsigned char *p, unsigned len)
+{
+	unsigned char csum = 0;
+
+	while (len--)
+		csum += *p++;
+
+	csum ^= 0xb9;
+
+	return csum;
+}
+
+static int build_fw(void)
+{
+	int buflen;
+	char *buf;
+	char *data;
+	struct edimax_header *hdr;
+	int ret = EXIT_FAILURE;
+
+	buflen = sizeof(struct edimax_header) + data_size;
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	data = buf + sizeof(struct edimax_header);
+
+	/* read input file */
+	ret = read_to_buf(ifname, data, data_size);
+	if (ret)
+		goto out_free_buf;
+
+	/* fill firmware header */
+	hdr = (struct edimax_header *)buf;
+	memset(hdr, 0, sizeof(struct edimax_header));
+
+	strncpy(hdr->model, model, sizeof(hdr->model));
+	strncpy(hdr->magic, magic, sizeof(hdr->magic));
+	strncpy(hdr->fw_version, fw_version, sizeof(hdr->fw_version));
+	strncpy(hdr->mtd_name, mtd_name, sizeof(hdr->mtd_name));
+
+	hdr->force = force;
+	hdr->start_addr = htonl(start_addr);
+	hdr->end_addr = htonl(end_addr);
+	hdr->data_size = htonl(data_size);
+	hdr->type = image_type;
+
+	hdr->data_csum = checksum((unsigned char *)data, data_size);
+	hdr->header_csum = checksum((unsigned char *)hdr,
+				    sizeof(struct edimax_header));
+
+	ret = write_fw(buf, buflen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+out_free_buf:
+	free(buf);
+out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	progname = basename(argv[0]);
+
+	while (1) {
+		int c;
+
+		c = getopt(argc, argv, "e:fhi:o:m:M:n:s:t:v:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'e':
+			if (str2u32(optarg, &end_addr)) {
+				ERR("%s is invalid '%s'",
+				    "end address", optarg);
+				goto out;
+			}
+			break;
+		case 'f':
+			force = 1;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'm':
+			model = optarg;
+			break;
+		case 'M':
+			magic = optarg;
+			break;
+		case 'n':
+			mtd_name = optarg;
+			break;
+		case 's':
+			if (str2u32(optarg, &start_addr)) {
+				ERR("%s is invalid '%s'",
+				    "start address", optarg);
+				goto out;
+			}
+			break;
+		case 't':
+			if (str2u8(optarg, &image_type)) {
+				ERR("%s is invalid '%s'",
+				    "image type", optarg);
+				goto out;
+			}
+			break;
+		case 'v':
+			fw_version = optarg;
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	ret = build_fw();
+
+out:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/encode_crc.c b/tools/firmware-utils/src/encode_crc.c
new file mode 100644
index 0000000000..647fb92e89
--- /dev/null
+++ b/tools/firmware-utils/src/encode_crc.c
@@ -0,0 +1,151 @@
+/* **************************************************************************
+
+   This program creates a CRC checksum and encodes the file that is named
+   in the command line.
+   
+   Compile with:  gcc encode_crc.c -Wall -o encode_crc
+
+   Author:     Michael Margraf  (michael.margraf@freecom.com)
+   Copyright:  Freecom Technology GmbH, Berlin, 2004
+               www.freecom.com
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ ************************************************************************* */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+// *******************************************************************
+// CCITT polynom G(x)=x^16+x^12+x^5+1
+#define POLYNOM  0x1021
+
+// CRC algorithm with MSB first
+int make_crc16(int crc, char new)
+{
+  int i;
+  crc = crc ^ (((int)new) << 8);
+  
+  for(i=0; i<8; i++) {  // work on 8 bits in "new"
+    crc <<= 1;          // MSBs first
+    if(crc & 0x10000)  crc ^= POLYNOM;
+  }
+  return crc & 0xFFFF;
+}
+
+// *******************************************************************
+// Reads the file "filename" into memory and returns pointer to the buffer.
+static char *readfile(char *filename, int *size)
+{
+	FILE		*fp;
+	char		*buffer;
+	struct stat	info;
+	
+	if (stat(filename,&info)!=0)
+		return NULL;
+
+	if ((fp=fopen(filename,"r"))==NULL)
+		return NULL;
+
+	buffer=NULL;
+	for (;;)
+	{
+		if ((buffer=(char *)malloc(info.st_size+1))==NULL)
+			break;
+
+		if (fread(buffer,1,info.st_size,fp)!=info.st_size)
+		{
+			free(buffer);
+			buffer=NULL;
+			break;
+		}
+
+		buffer[info.st_size]='\0';
+		if(size) *size = info.st_size;
+
+		break;
+	}
+
+	(void)fclose(fp);
+
+	return buffer;
+}
+
+
+// *******************************************************************
+int main(int argc, char** argv)
+{
+  if(argc < 3) {
+    printf("ERROR: Argument missing!\n\n");
+    return 1;
+  }
+
+  int count;  // size of file in bytes
+  char *p, *master = readfile(argv[1], &count);
+  if(!master) {
+    printf("ERROR: File not found!\n");
+    return 1;
+  }
+
+  int crc = 0xFFFF, z;
+
+  p = master;
+  for(z=0; z<count; z++)
+    crc = make_crc16(crc, *(p++));  // calculate CRC
+  short crc16 = (short)crc;
+
+	/*
+  if(argc > 2) {   // with flag for device recognition ?
+    p = argv[2];
+    for(z=strlen(p); z>0; z--) {
+      crc ^= (int)(*p);
+      *(p++) = (char)crc;  // encode device flag
+    }
+  }
+	*/
+
+  p = master;
+  for(z=0; z<count; z++) {
+    crc ^= (int)(*p);
+    *(p++) = (char)crc;  // encode file
+  }
+
+
+  // write encoded file...
+  FILE *fp = fopen(argv[2], "w");
+  if(!fp) {
+    printf("ERROR: File not writeable!\n");
+    return 1;
+  }
+
+  if(argc > 3) {  // add flag for device recognition ?
+    fwrite(argv[3], strlen(argv[3]), sizeof(char), fp);
+  }
+  else {
+    // Device is an FSG, so byte swap (IXP4xx is big endian)
+    crc16 = ((crc16 >> 8) & 0xFF) | ((crc16 << 8) & 0xFF00);
+  }
+
+  fwrite(&crc16, 1, sizeof(short), fp);     // first write CRC
+
+  fwrite(master, count, sizeof(char), fp);  // write content
+  fclose(fp);
+
+  free(master);
+  return 0;
+}
diff --git a/tools/firmware-utils/src/fix-u-media-header.c b/tools/firmware-utils/src/fix-u-media-header.c
new file mode 100644
index 0000000000..21f184e66d
--- /dev/null
+++ b/tools/firmware-utils/src/fix-u-media-header.c
@@ -0,0 +1,354 @@
+/*
+ *  Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "cyg_crc.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN	32		/* Image Name Length		*/
+
+#define UM_MAGIC	0x55525F46
+#define UM_HEADER_LEN	12
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+struct u_media_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN - UM_HEADER_LEN]; /* Image Name		*/
+
+	uint32_t	ih_UMedia_magic;	/* U-Media magic number	*/
+	uint32_t	ih_UMedia_boardID;	/* U-Media board ID	*/
+	uint8_t		ih_UMedia_imageType;	/* U-Media image type */
+	uint8_t		ih_UMedia_LoadDefault;	/* U-Media load to factory default setting */
+	uint8_t		ih_UMedia_temp1;	/* U-Media didn't use this tag */
+	uint8_t		ih_UMedia_temp2;	/* U-Media didn't use this tag */
+} __attribute__ ((packed));
+
+struct if_info {
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+};
+
+static char *progname;
+static char *ofname;
+static struct if_info if_info;
+static int factory_defaults;
+static uint32_t board_id;
+static uint8_t image_type;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board_id>   set board ID to <board_id>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -F              load factory defaults\n"
+"  -o <file>       write output to the file <file>\n"
+"  -T <type>       set image type to <type>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static int str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+static int str2u8(char *arg, uint8_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	if (t > 255)
+		return -1;
+
+	*val = t;
+	return 0;
+}
+
+static int get_file_stat(struct if_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL)
+		return 0;
+
+	res = stat(fdata->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	return 0;
+}
+
+static int read_to_buf(struct if_info *fdata, char *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+out_close:
+	fclose(f);
+out:
+	return ret;
+}
+
+static int check_options(void)
+{
+	int ret;
+
+	if (ofname == NULL) {
+		ERR("no %s specified", "output file");
+		return -1;
+	}
+
+	if (if_info.file_name == NULL) {
+		ERR("no %s specified", "input file");
+		return -1;
+	}
+
+	ret = get_file_stat(&if_info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	ret = EXIT_SUCCESS;
+
+out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+out:
+	return ret;
+}
+
+static int fix_header(void)
+{
+	int buflen;
+	char *buf;
+	uint32_t crc, crc_orig;
+	struct u_media_header *hdr;
+	int ret = EXIT_FAILURE;
+
+	buflen = if_info.file_size;
+	if (buflen < sizeof(*hdr)) {
+		ERR("invalid input file\n");
+		return ret;
+	}
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	ret = read_to_buf(&if_info, buf);
+	if (ret)
+		goto out_free_buf;
+
+	hdr = (struct u_media_header *) buf;
+	if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+		ERR("invalid input file, bad magic\n");
+		goto out_free_buf;
+	}
+
+	/* verify header CRC */
+	crc_orig = ntohl(hdr->ih_hcrc);
+	hdr->ih_hcrc = 0;
+	crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
+	if (crc != crc_orig) {
+		ERR("invalid input file, bad header CRC\n");
+		goto out_free_buf;
+	}
+
+	hdr->ih_name[IH_NMLEN - UM_HEADER_LEN - 1] = '\0';
+
+	/* set U-Media specific fields */
+	hdr->ih_UMedia_magic = htonl(UM_MAGIC);
+	hdr->ih_UMedia_boardID = htonl(board_id);
+	hdr->ih_UMedia_imageType = image_type;
+	hdr->ih_UMedia_LoadDefault = (factory_defaults) ? 1 : 0;
+
+	/* update header CRC */
+	crc = cyg_ether_crc32((unsigned char *)hdr, sizeof(*hdr));
+	hdr->ih_hcrc = htonl(crc);
+
+	ret = write_fw(buf, buflen);
+	if (ret)
+		goto out_free_buf;
+
+	DBG("U-Media header fixed in \"%s\"", ofname);
+
+	ret = EXIT_SUCCESS;
+
+out_free_buf:
+	free(buf);
+out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	progname = basename(argv[0]);
+
+	while (1) {
+		int c;
+
+		c = getopt(argc, argv, "B:Fi:o:T:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			if (str2u32(optarg, &board_id)) {
+				ERR("%s is invalid '%s'",
+				    "board ID", optarg);
+				goto out;
+			}
+			break;
+		case 'T':
+			if (str2u8(optarg, &image_type)) {
+				ERR("%s is invalid '%s'",
+				    "image type", optarg);
+				goto out;
+			}
+			break;
+		case 'F':
+			factory_defaults = 1;
+			break;
+		case 'i':
+			if_info.file_name = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	ret = fix_header();
+
+out:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/fw.h b/tools/firmware-utils/src/fw.h
new file mode 100644
index 0000000000..e37859c52d
--- /dev/null
+++ b/tools/firmware-utils/src/fw.h
@@ -0,0 +1,70 @@
+/*
+ *  * Copyright (C) 2007 Ubiquiti Networks, Inc.
+ *   *
+ *    * This program is free software; you can redistribute it and/or
+ *     * modify it under the terms of the GNU General Public License as
+ *      * published by the Free Software Foundation; either version 2 of the
+ *       * License, or (at your option) any later version.
+ *        *
+ *         * This program is distributed in the hope that it will be useful, but
+ *          * WITHOUT ANY WARRANTY; without even the implied warranty of
+ *           * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *            * General Public License for more details.
+ *             *
+ *              * You should have received a copy of the GNU General Public License
+ *               * along with this program; if not, write to the Free Software
+ *                * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *                 */
+
+#ifndef FW_INCLUDED
+#define FW_INCLUDED
+
+#include <sys/types.h>
+
+#define MAGIC_HEADER	"OPEN"
+#define MAGIC_PART	"PART"
+#define MAGIC_END	"END."
+
+#define MAGIC_LENGTH	4
+
+typedef struct header {
+	char magic[MAGIC_LENGTH];
+	char version[256];
+	u_int32_t crc;
+	u_int32_t pad;
+} __attribute__ ((packed)) header_t;
+
+typedef struct part {
+	char magic[MAGIC_LENGTH];
+	char name[16];
+	char pad[12];
+	u_int32_t memaddr;
+	u_int32_t index;
+	u_int32_t baseaddr;
+	u_int32_t entryaddr;
+	u_int32_t data_size;
+	u_int32_t part_size;
+} __attribute__ ((packed)) part_t;
+
+typedef struct part_crc {
+	u_int32_t crc;
+	u_int32_t pad;
+} __attribute__ ((packed)) part_crc_t;
+
+typedef struct signature {
+	char magic[MAGIC_LENGTH];
+	u_int32_t crc;
+	u_int32_t pad;
+} __attribute__ ((packed)) signature_t;
+
+#define VERSION "1.2"
+
+#define INFO(...) fprintf(stdout, __VA_ARGS__)
+#define ERROR(...) fprintf(stderr, "ERROR: "__VA_ARGS__)
+#define WARN(...) fprintf(stderr, "WARN: "__VA_ARGS__)
+#define DEBUG(...) do {\
+        if (debug) \
+                fprintf(stdout, "DEBUG: "__VA_ARGS__); \
+} while (0);
+
+#endif
diff --git a/tools/firmware-utils/src/hcsmakeimage.c b/tools/firmware-utils/src/hcsmakeimage.c
new file mode 100644
index 0000000000..603ea882b1
--- /dev/null
+++ b/tools/firmware-utils/src/hcsmakeimage.c
@@ -0,0 +1,181 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include "bcmalgo.h"
+
+
+int flag_print_version;
+int flag_print_help;
+int flag_compress;
+
+uint16_t sa2100_magic  = 0x2100;
+uint16_t sa3349_magic  = 0x3349;
+uint32_t default_date = 0x00000000; //A long time ago in a galaxy far far away....
+uint32_t default_load_address = 0x80010000; //The default load_address for the firmware image
+
+static void print_help ( const char* ename )
+{
+	printf ( "Firmware image packer and calculator for broadcom-based modems.\n" );
+	printf ( "Part of bcm-utils package.\n" );
+	printf ( "(c) 2009 Necromant (http://necromant.ath.cx). Thanks to Luke-jr for his initial work.\n" );
+	printf ( "usage: %s [options]\n", ename );
+	printf ( "Valid options are:\n" );
+	printf ( "--magic_bytes=value \t- specify magic bytes at the beginning of the image. default - 3349\n" );
+	printf ( "\t\t\t these can be sa2100 (for DPC2100 modem),\n\t\t\t sa3349 (haxorware guys use this one for some reason),\n\t\t\t or a custom hex value e.g. 0xFFFF\n" );
+	printf ( "--compress \t\t - Make use of LZMA (weird!) compression (Doesn't work yet).\n" );
+	printf ( "--rev_maj=value\t\t - major revision number. default 0\n" );
+	printf ( "--rev_min=value\t\t - minor revision number default 0\n" );
+	printf ( "--filename=value\t - use this filename in header instead of default (input filename)\n" );
+	printf ( "--ldaddress=value\t - hex value of the target load address. defaults to 0x80010000\n" );
+	printf ( "--input_file=value\t - What file are we packing?\n" );
+	printf ( "--output_file=value\t - What file shall we write? (default: image.bin)\n" );
+#ifdef _HAX0RSTYLE
+	printf ( "--credz\t - Give some credz!\n" );
+#endif
+	printf ( "\n" );
+}
+
+
+int main ( int argc, char** argv )
+{
+	if ( argc<2 )
+	{
+		print_help ( argv[0] );
+	}
+
+	static struct option long_options[] =
+	{
+		{"magic_bytes",          required_argument,   0,        'm'},
+		{"rev_maj",        required_argument,   0,      'j'},
+		{"rev_min",       required_argument,   0,     'n'},
+		{"ldaddress",       required_argument,   0,     'l'},
+		{"filename",       required_argument,   0,     'f'},
+		{"input_file",       required_argument,   0,     'i'},
+		{"output_file",       required_argument,   0,     'o'},
+		{"compress",     no_argument,       &flag_compress,    'c'},
+		{"version",     no_argument,       &flag_print_version,    'v'},
+		{"help",        no_argument,       &flag_print_help,    'h'},
+		{0, 0, 0, 0}
+	};
+	int option_index = 0;
+	int opt_result=0;
+	char* filename=NULL;
+	char* input=NULL;
+	char* magic=NULL;
+	char* major=NULL;
+	char* minor=NULL;
+	char* ldaddr=NULL;
+	char* output=NULL;
+
+	while ( opt_result>=0 )
+	{
+		opt_result = getopt_long ( argc, argv, "m:j:n:f:i:o:vh", long_options, &option_index );
+		switch ( opt_result )
+		{
+			case 0:
+				printf ( "o!\n" );
+				break;
+			case 'h':
+				print_help ( argv[0] );
+				break;
+			case 'l':
+				ldaddr=optarg;
+				break;
+			case 'f':
+				filename=optarg;
+				break;
+			case 'i':
+				input=optarg;
+				break;
+			case 'o':
+				output=optarg;
+				break;
+			case 'm':
+				magic=optarg;
+				break;
+			case 'j':
+				major=optarg;
+				break;
+			case 'n':
+				minor=optarg;
+				break;
+		}
+	}
+	if ( input==NULL )
+	{
+		printf ( "Telepaths are still on holidays. I guess you should tell me what file should I process.\n\n" );
+		exit ( 1 );
+	}
+	if ( access ( input,R_OK ) !=0 )
+	{
+		printf ( "I cannot access the file %s. Is it there? Am I allowed?\n\n", input );
+		exit ( 1 );
+	}
+	uint32_t magicnum=sa2100_magic;
+
+	if ( magic )
+	{
+		if ( strcmp ( magic,"sa2100" ) ==0 ) magicnum=sa2100_magic; else
+				if ( strcmp ( magic,"sa3349" ) ==0 ) magicnum=sa3349_magic; else
+			{
+				sscanf ( magic, "0x%04X", &magicnum );
+			}
+	}
+	unsigned int majrev=0;
+	if ( major )
+	{
+		sscanf ( major, "%d", &majrev );
+	}
+	unsigned int minrev=0;
+	if ( minor )
+	{
+		sscanf ( minor, "%d", &minrev );
+	}
+	uint32_t ldaddress = default_load_address;
+	if ( ldaddr )
+	{
+		sscanf ( ldaddr, "0x%08X", &ldaddress );
+	}
+	char* dupe = strdup(input);
+	char* fname = basename ( dupe );
+	if ( filename )
+	{
+		fname = filename;
+	}
+	struct timeval tm;
+	gettimeofday ( &tm,NULL );
+	struct stat buf;
+	stat ( input,&buf );
+	ldr_header_t* head = construct_header ( magicnum, (uint16_t) majrev, (uint16_t) minrev, ( uint32_t ) tm.tv_sec, ( uint32_t ) buf.st_size, ldaddress, fname, get_file_crc ( input ) );
+	free(dupe);
+	//uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc
+	//FILE* fd = fopen ("/tftpboot/haxorware11rev32.bin","r");
+	//fread(head,sizeof(ldr_header_t),1,fd);
+	char* filebuffer = malloc ( buf.st_size+10 );
+	FILE* fd = fopen ( input,"r" );
+	fread ( filebuffer, 1, buf.st_size,fd );
+	if (!output)
+		{
+		output = malloc(strlen(input+5));
+		strcpy(output,input);
+		strcat(output,".bin");
+		}
+	dump_header ( head );
+	FILE* fd_out = fopen ( output,"w+" );
+	if (!fd_out)
+		{
+		fprintf(stderr, "Failed to open output file: %s\n", output);
+		exit(1);
+		}
+	fwrite ( head,1,sizeof ( ldr_header_t ),fd_out );
+	fwrite ( filebuffer,1,buf.st_size,fd_out );
+	printf("Firmware image %s is ready\n", output);
+	return 0;
+}
diff --git a/tools/firmware-utils/src/imagetag.c b/tools/firmware-utils/src/imagetag.c
new file mode 100644
index 0000000000..90fb7a4c73
--- /dev/null
+++ b/tools/firmware-utils/src/imagetag.c
@@ -0,0 +1,492 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Axel Gembe <ago@bastart.eu.org>
+ * Copyright (C) 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include "bcm_tag.h"
+#include "imagetag_cmdline.h"
+#include "cyg_crc.h"
+
+#define DEADCODE			0xDEADC0DE
+
+/* Kernel header */
+struct kernelhdr {
+	uint32_t		loadaddr;	/* Kernel load address */
+	uint32_t		entry;		/* Kernel entry point address */
+	uint32_t		lzmalen;	/* Compressed length of the LZMA data that follows */
+};
+
+static char pirellitab[NUM_PIRELLI][BOARDID_LEN] = PIRELLI_BOARDS;
+
+void int2tag(char *tag, uint32_t value) {
+  uint32_t network = htonl(value);
+  memcpy(tag, (char *)(&network), 4);
+}
+
+uint32_t compute_crc32(uint32_t crc, FILE *binfile, size_t compute_start, size_t compute_len)
+{
+	uint8_t readbuf[1024];
+	size_t read;
+
+	fseek(binfile, compute_start, SEEK_SET);
+
+	/* read block of 1024 bytes */
+	while (binfile && !feof(binfile) && !ferror(binfile) && (compute_len >= sizeof(readbuf))) {
+		read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), binfile);
+		crc = cyg_crc32_accumulate(crc, readbuf, read);
+		compute_len = compute_len - read;
+	}
+
+	/* Less than 1024 bytes remains, read compute_len bytes */
+	if (binfile && !feof(binfile) && !ferror(binfile) && (compute_len > 0)) {
+		read = fread(readbuf, sizeof(uint8_t), compute_len, binfile);
+		crc = cyg_crc32_accumulate(crc, readbuf, read);
+	}
+
+	return crc;
+}
+
+size_t getlen(FILE *fp)
+{
+	size_t retval, curpos;
+
+	if (!fp)
+		return 0;
+
+	curpos = ftell(fp);
+	fseek(fp, 0, SEEK_END);
+	retval = ftell(fp);
+	fseek(fp, curpos, SEEK_SET);
+
+	return retval;
+}
+
+int tagfile(const char *kernel, const char *rootfs, const char *bin, \
+			const struct gengetopt_args_info *args, \
+			uint32_t flash_start, uint32_t image_offset, \
+			uint32_t block_size, uint32_t load_address, uint32_t entry)
+{
+	struct bcm_tag tag;
+	struct kernelhdr khdr;
+	FILE *kernelfile = NULL, *rootfsfile = NULL, *binfile = NULL, *cfefile = NULL;
+	size_t cfeoff, cfelen, kerneloff, kernellen, rootfsoff, rootfslen, \
+	  read, imagelen, rootfsoffpadlen = 0, kernelfslen, kerneloffpadlen = 0, oldrootfslen, \
+	  rootfsend;
+	uint8_t readbuf[1024];
+	uint32_t imagecrc = IMAGETAG_CRC_START;
+	uint32_t kernelcrc = IMAGETAG_CRC_START;
+	uint32_t rootfscrc = IMAGETAG_CRC_START;
+	uint32_t kernelfscrc = IMAGETAG_CRC_START;
+	uint32_t fwaddr = 0;
+	uint8_t crc_val;
+	const uint32_t deadcode = htonl(DEADCODE);
+	int i;
+	int is_pirelli = 0;
+
+
+	memset(&tag, 0, sizeof(struct bcm_tag));
+
+	if (!kernel || !rootfs) {
+		fprintf(stderr, "imagetag can't create an image without both kernel and rootfs\n");
+	}
+
+	if (kernel && !(kernelfile = fopen(kernel, "rb"))) {
+		fprintf(stderr, "Unable to open kernel \"%s\"\n", kernel);
+		return 1;
+	}
+
+	if (rootfs && !(rootfsfile = fopen(rootfs, "rb"))) {
+		fprintf(stderr, "Unable to open rootfs \"%s\"\n", rootfs);
+		return 1;
+	}
+
+	if (!bin || !(binfile = fopen(bin, "wb+"))) {
+		fprintf(stderr, "Unable to open output file \"%s\"\n", bin);
+		return 1;
+	}
+
+	if ((args->cfe_given) && (args->cfe_arg)) {
+	  if (!(cfefile = fopen(args->cfe_arg, "rb"))) {
+		fprintf(stderr, "Unable to open CFE file \"%s\"\n", args->cfe_arg);
+	  }
+	}
+
+	fwaddr = flash_start + image_offset;
+	if (cfefile) {
+	  cfeoff = flash_start;		  
+	  cfelen = getlen(cfefile);
+	  /* Seek to the start of the file after tag */
+	  fseek(binfile, sizeof(tag), SEEK_SET);
+	  
+	  /* Write the cfe */
+	  while (cfefile && !feof(cfefile) && !ferror(cfefile)) {
+		read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), cfefile);
+		fwrite(readbuf, sizeof(uint8_t), read, binfile);
+	  }
+
+	} else {
+	  cfeoff = 0;
+	  cfelen = 0;
+	}
+
+	if (!args->root_first_flag) {
+	  /* Build the kernel address and length (doesn't need to be aligned, read only) */
+	  kerneloff = fwaddr + sizeof(tag);
+	  
+	  kernellen = getlen(kernelfile);
+	  
+	  if (!args->kernel_file_has_header_flag) {
+		/* Build the kernel header */
+		khdr.loadaddr	= htonl(load_address);
+		khdr.entry	= htonl(entry);
+		khdr.lzmalen	= htonl(kernellen);
+		
+		/* Increase the kernel size by the header size */
+		kernellen += sizeof(khdr);	  
+	  }
+	  
+	  /* Build the rootfs address and length */
+	  rootfsoff = kerneloff + kernellen;
+	  /* align the start if requested */
+	  if (args->align_rootfs_flag)
+		rootfsoff = (rootfsoff % block_size) > 0 ? (((rootfsoff / block_size) + 1) * block_size) : rootfsoff;
+          else
+		rootfsoff = (rootfsoff % 4) > 0 ? (((rootfsoff / 4) + 1) * 4) : rootfsoff;
+
+	  /* align the end */
+	  rootfsend = rootfsoff + getlen(rootfsfile);
+	  if ((rootfsend % block_size) > 0)
+		rootfsend = (((rootfsend / block_size) + 1) * block_size);
+	  rootfslen = rootfsend - rootfsoff;
+	  imagelen = rootfsoff + rootfslen - kerneloff + sizeof(deadcode);
+	  rootfsoffpadlen = rootfsoff - (kerneloff + kernellen);
+	  
+	  /* Seek to the start of the kernel */
+	  fseek(binfile, kerneloff - fwaddr + cfelen, SEEK_SET);
+	  
+	  /* Write the kernel header */
+	  fwrite(&khdr, sizeof(khdr), 1, binfile);
+	  
+	  /* Write the kernel */
+	  while (kernelfile && !feof(kernelfile) && !ferror(kernelfile)) {
+		read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), kernelfile);
+		fwrite(readbuf, sizeof(uint8_t), read, binfile);
+	  }
+
+	  /* Write the RootFS */
+	  fseek(binfile, rootfsoff - fwaddr + cfelen, SEEK_SET);
+	  while (rootfsfile && !feof(rootfsfile) && !ferror(rootfsfile)) {
+		read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), rootfsfile);
+		fwrite(readbuf, sizeof(uint8_t), read, binfile);
+	  }
+
+	  /* Align image to specified erase block size and append deadc0de */
+	  printf("Data alignment to %dk with 'deadc0de' appended\n", block_size/1024);
+	  fseek(binfile, rootfsoff + rootfslen - fwaddr + cfelen, SEEK_SET);
+	  fwrite(&deadcode, sizeof(uint32_t), 1, binfile);
+
+	  oldrootfslen = rootfslen;
+	  if (args->pad_given) {
+		uint32_t allfs = 0xffffffff;
+		uint32_t pad_size = args->pad_arg * 1024 * 1024;
+
+		printf("Padding image to %d bytes ...\n", pad_size);
+		while (imagelen < pad_size) {
+			fwrite(&allfs, sizeof(uint32_t), 1, binfile);
+			imagelen += 4;
+			rootfslen += 4;
+		}
+	  }
+
+	  /* Flush the binfile buffer so that when we read from file, it contains
+	   * everything in the buffer
+	   */
+	  fflush(binfile);
+
+	  /* Compute the crc32 of the entire image (deadC0de included) */
+	  imagecrc = compute_crc32(imagecrc, binfile, kerneloff - fwaddr + cfelen, imagelen);
+	  /* Compute the crc32 of the kernel and padding between kernel and rootfs) */
+	  kernelcrc = compute_crc32(kernelcrc, binfile, kerneloff - fwaddr + cfelen, kernellen + rootfsoffpadlen);
+	  /* Compute the crc32 of the kernel and padding between kernel and rootfs) */
+	  kernelfscrc = compute_crc32(kernelfscrc, binfile, kerneloff - fwaddr + cfelen, kernellen + rootfsoffpadlen + rootfslen + sizeof(deadcode));
+	  /* Compute the crc32 of the flashImageStart to rootLength.
+	   * The broadcom firmware assumes the rootfs starts the image,
+	   * therefore uses the rootfs start to determine where to flash
+	   * the image.  Since we have the kernel first we have to give
+	   * it the kernel address, but the crc uses the length
+	   * associated with this address, which is added to the kernel
+	   * length to determine the length of image to flash and thus
+	   * needs to be rootfs + deadcode
+	   */
+	  rootfscrc = compute_crc32(rootfscrc, binfile, kerneloff - fwaddr + cfelen, rootfslen + sizeof(deadcode));
+
+	} else {
+	  /* Build the kernel address and length (doesn't need to be aligned, read only) */
+	  rootfsoff = fwaddr + sizeof(tag);
+	  oldrootfslen = getlen(rootfsfile);
+	  rootfslen = oldrootfslen;
+	  rootfslen = ( (rootfslen % block_size) > 0 ? (((rootfslen / block_size) + 1) * block_size) : rootfslen );
+	  kerneloffpadlen = rootfslen - oldrootfslen;
+	  oldrootfslen = rootfslen;
+
+	  kerneloff = rootfsoff + rootfslen;
+	  kernellen = getlen(kernelfile);
+
+	  imagelen = cfelen + rootfslen + kernellen;
+	  
+	  /* Seek to the start of the kernel */
+	  fseek(binfile, kerneloff - fwaddr + cfelen, SEEK_SET);
+	  
+	  if (!args->kernel_file_has_header_flag) {
+		/* Build the kernel header */
+		khdr.loadaddr	= htonl(load_address);
+		khdr.entry	= htonl(entry);
+		khdr.lzmalen	= htonl(kernellen);
+		
+		/* Write the kernel header */
+		fwrite(&khdr, sizeof(khdr), 1, binfile);
+	  
+		/* Increase the kernel size by the header size */
+		kernellen += sizeof(khdr);	  
+	  }
+	  
+	  /* Write the kernel */
+	  while (kernelfile && !feof(kernelfile) && !ferror(kernelfile)) {
+		read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), kernelfile);
+		fwrite(readbuf, sizeof(uint8_t), read, binfile);
+	  }
+
+	  /* Write the RootFS */
+	  fseek(binfile, rootfsoff - fwaddr + cfelen, SEEK_SET);
+	  while (rootfsfile && !feof(rootfsfile) && !ferror(rootfsfile)) {
+		read = fread(readbuf, sizeof(uint8_t), sizeof(readbuf), rootfsfile);
+		fwrite(readbuf, sizeof(uint8_t), read, binfile);
+	  }
+
+	  /* Flush the binfile buffer so that when we read from file, it contains
+	   * everything in the buffer
+	   */
+	  fflush(binfile);
+
+	  /* Compute the crc32 of the entire image (deadC0de included) */
+	  imagecrc = compute_crc32(imagecrc, binfile, sizeof(tag), imagelen);
+	  /* Compute the crc32 of the kernel and padding between kernel and rootfs) */
+	  kernelcrc = compute_crc32(kernelcrc, binfile, kerneloff - fwaddr + cfelen, kernellen + rootfsoffpadlen);
+	  kernelfscrc = compute_crc32(kernelfscrc, binfile, rootfsoff - fwaddr + cfelen, kernellen + rootfslen);
+	  rootfscrc = compute_crc32(rootfscrc, binfile, rootfsoff - fwaddr + cfelen, rootfslen);
+	}
+
+	/* Close the files */
+	if (cfefile) {
+	  fclose(cfefile);
+	}
+	fclose(kernelfile);
+	fclose(rootfsfile);
+
+	/* Build the tag */
+	strncpy(tag.tagVersion, args->tag_version_arg, sizeof(tag.tagVersion) - 1);
+	strncpy(tag.sig_1, args->signature_arg, sizeof(tag.sig_1) - 1);
+	strncpy(tag.sig_2, args->signature2_arg, sizeof(tag.sig_2) - 1);
+	strncpy(tag.chipid, args->chipid_arg, sizeof(tag.chipid) - 1);
+	strncpy(tag.boardid, args->boardid_arg, sizeof(tag.boardid) - 1);
+	strcpy(tag.big_endian, "1");
+	sprintf(tag.totalLength, "%lu", imagelen);
+
+	if (args->cfe_given) {
+	  sprintf(tag.cfeAddress, "%" PRIu32, flash_start);
+	  sprintf(tag.cfeLength, "%lu", cfelen);
+	} else {
+	  /* We don't include CFE */
+	  strcpy(tag.cfeAddress, "0");
+	  strcpy(tag.cfeLength, "0");
+	}
+
+	sprintf(tag.kernelAddress, "%lu", kerneloff);
+	sprintf(tag.kernelLength, "%lu", kernellen + rootfsoffpadlen);
+
+	if (args->root_first_flag) {
+	  sprintf(tag.flashImageStart, "%lu", rootfsoff);
+	  sprintf(tag.flashRootLength, "%lu", rootfslen);	  
+	} else {
+	  sprintf(tag.flashImageStart, "%lu", kerneloff);
+	  sprintf(tag.flashRootLength, "%lu", rootfslen + sizeof(deadcode));
+	}
+	int2tag(tag.rootLength, oldrootfslen + sizeof(deadcode));
+
+	if (args->rsa_signature_given) {
+	    strncpy(tag.rsa_signature, args->rsa_signature_arg, RSASIG_LEN);
+	}
+
+	if (args->layoutver_given) {
+	    strncpy(tag.flashLayoutVer, args->layoutver_arg, TAGLAYOUT_LEN);
+	}
+
+	if (args->info1_given) {
+	  strncpy(tag.information1, args->info1_arg, TAGINFO1_LEN);
+	}
+
+	if (args->info2_given) {
+	  strncpy(tag.information2, args->info2_arg, TAGINFO2_LEN);
+	}
+
+	if (args->reserved2_given) {
+	  strncpy(tag.reserved2, args->reserved2_arg, 16);
+	}
+
+	if (args->altinfo_given) {
+	  strncpy(tag.information1, args->altinfo_arg, TAGINFO1_LEN);
+	}
+
+	if (args->second_image_flag_given) {
+	  if (strncmp(args->second_image_flag_arg, "2", DUALFLAG_LEN) != 0) {		
+		strncpy(tag.dualImage, args->second_image_flag_arg, DUALFLAG_LEN);
+	  }
+	}
+
+	if (args->inactive_given) {
+	  if (strncmp(args->inactive_arg, "2", INACTIVEFLAG_LEN) != 0) {		
+		strncpy(tag.inactiveFlag, args->second_image_flag_arg, INACTIVEFLAG_LEN);
+	  }
+	}
+
+	for (i = 0; i < NUM_PIRELLI; i++) {
+		if (strncmp(args->boardid_arg, pirellitab[i], BOARDID_LEN) == 0) {
+			is_pirelli = 1;
+			break;
+		}
+	}
+
+	if ( !is_pirelli ) {
+	  int2tag(tag.imageCRC, kernelfscrc);
+	} else {
+	  int2tag(tag.imageCRC, kernelcrc);
+	}
+
+	int2tag(&(tag.rootfsCRC[0]), rootfscrc);
+	int2tag(tag.kernelCRC, kernelcrc);
+	int2tag(tag.fskernelCRC, kernelfscrc);
+	int2tag(tag.headerCRC, cyg_crc32_accumulate(IMAGETAG_CRC_START, (uint8_t*)&tag, sizeof(tag) - 20));
+
+	fseek(binfile, 0L, SEEK_SET);
+	fwrite(&tag, sizeof(uint8_t), sizeof(tag), binfile);
+
+    fflush(binfile);
+	fclose(binfile);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+    int c, i;
+	char *kernel, *rootfs, *bin;
+	uint32_t flash_start, image_offset, block_size, load_address, entry;
+	flash_start = image_offset = block_size = load_address = entry = 0;
+	struct gengetopt_args_info parsed_args;
+
+	kernel = rootfs = bin = NULL;
+
+	if (imagetag_cmdline(argc, argv, &parsed_args)) {
+	  exit(1);
+	}
+
+	printf("Broadcom 63xx image tagger - v2.0.0\n");
+	printf("Copyright (C) 2008 Axel Gembe\n");
+	printf("Copyright (C) 2009-2010 Daniel Dickinson\n");
+	printf("Licensed under the terms of the Gnu General Public License\n");
+
+	kernel = parsed_args.kernel_arg;
+	rootfs = parsed_args.rootfs_arg;
+	bin = parsed_args.output_arg;
+	if (strlen(parsed_args.tag_version_arg) >= TAGVER_LEN) {
+	  fprintf(stderr, "Error: Tag Version (tag_version,v) too long.\n");
+	  exit(1);
+	}
+	if (strlen(parsed_args.boardid_arg) >= BOARDID_LEN) {
+	  fprintf(stderr, "Error: Board ID (boardid,b) too long.\n");
+	  exit(1);
+	}
+	if (strlen(parsed_args.chipid_arg) >= CHIPID_LEN) {
+	  fprintf(stderr, "Error: Chip ID (chipid,c) too long.\n");
+	  exit(1);
+	}
+	if (strlen(parsed_args.signature_arg) >= SIG1_LEN) {
+	  fprintf(stderr, "Error: Magic string (signature,a) too long.\n");
+	  exit(1);
+	}
+	if (strlen(parsed_args.signature2_arg) >= SIG2_LEN) {
+	  fprintf(stderr, "Error: Second magic string (signature2,m) too long.\n");
+	  exit(1);
+	}
+	if (parsed_args.layoutver_given) {
+	  if (strlen(parsed_args.layoutver_arg) > FLASHLAYOUTVER_LEN) {
+		fprintf(stderr, "Error: Flash layout version (layoutver,y) too long.\n");
+		exit(1);
+	  }
+	}
+	if (parsed_args.rsa_signature_given) {
+	  if (strlen(parsed_args.rsa_signature_arg) > RSASIG_LEN) {
+		fprintf(stderr, "Error: RSA Signature (rsa_signature,r) too long.\n");
+		exit(1);
+	  }
+	}
+
+	if (parsed_args.info1_given) {
+	  if (strlen(parsed_args.info1_arg) >= TAGINFO1_LEN) {
+		fprintf(stderr, "Error: Vendor Information 1 (info1) too long.\n");
+		exit(1);
+	  }
+	}
+
+	if (parsed_args.info2_given) {
+	  if (strlen(parsed_args.info2_arg) >= TAGINFO2_LEN) {
+		fprintf(stderr, "Error: Vendor Information 2 (info2) too long.\n");
+		exit(1);
+	  }
+	}
+
+	if (parsed_args.altinfo_given) {
+	  if (strlen(parsed_args.altinfo_arg) >= ALTTAGINFO_LEN) {
+		fprintf(stderr, "Error: Vendor Information 1 (info1) too long.\n");
+		exit(1);
+	  }
+	}
+
+	if (parsed_args.pad_given) {
+	  if (parsed_args.pad_arg < 0) {
+		fprintf(stderr, "Error: pad size must be positive.\r");
+		exit(1);
+	  }
+	}
+
+	flash_start = strtoul(parsed_args.flash_start_arg, NULL, 16);
+	image_offset = strtoul(parsed_args.image_offset_arg, NULL, 16);
+	block_size = strtoul(parsed_args.block_size_arg, NULL, 16);
+
+	if (!parsed_args.kernel_file_has_header_flag) {
+	  load_address = strtoul(parsed_args.load_addr_arg, NULL, 16);
+	  entry = strtoul(parsed_args.entry_arg, NULL, 16);
+	  if (load_address == 0) {
+		fprintf(stderr, "Error: Invalid value for load address\n");
+	  }
+	  if (entry == 0) {
+		fprintf(stderr, "Error: Invalid value for entry\n");
+	  }
+	}
+	
+	return tagfile(kernel, rootfs, bin, &parsed_args, flash_start, image_offset, block_size, load_address, entry);
+}
diff --git a/tools/firmware-utils/src/imagetag.ggo b/tools/firmware-utils/src/imagetag.ggo
new file mode 100644
index 0000000000..7318485293
--- /dev/null
+++ b/tools/firmware-utils/src/imagetag.ggo
@@ -0,0 +1,46 @@
+# Command line option parsing generator file for imagetag
+# Supplied-To: gengetopt
+#
+# Copyright 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+package "imagetag"
+version "2.0.0"
+purpose "Generate image with CFE imagetag for Broadcom 63xx routers."
+description "Copyright (C) 2008 Axel Gembe
+Copyright (C) 2009-2010 Daniel Dickinson
+Licensed unter the terms of the Gnu General Public License.
+
+Given a root filesystem, a linux kernel, and an optional CFE, generates an image with an imagetag for a Broadcom 63xx-based router.  Additional parameters to be specified depend on the specfic brand and model of router."
+args "--file-name=imagetag_cmdline"
+
+option "kernel" i "File with LZMA compressed kernel to include in the image." string typestr="filename"  required
+option "rootfs" f "File with RootFS to include in the image." string typestr="filename" required
+option "output" o "Name of output file." string typestr="filename" required
+option "cfe" - "File with CFE to include in the image." string typestr="filename" optional
+option "boardid" b "Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")." string required
+option "chipid" c "Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")." string required
+option "flash-start" s "Flash start address." string typestr="address" optional default="0xBFC00000"
+option "image-offset" n "Offset from start address for the first byte after the CFE (in memory)." string typestr="offset" default="0x10000" optional
+option "tag-version" v "Version number for imagetag format." string default="6" optional
+option "signature" a "Magic string (signature), for boards that need it." string default="Broadcom Corporatio" optional
+option "signature2" m "Second magic string (signature2)." string default="ver. 2.0" optional
+option "block-size" k "Flash erase block size." string optional default="0x10000"
+option "load-addr" l "Kernel load address." string typestr="address" required
+option "entry" e "Address where the kernel entry point will be for booting." string typestr="address" required
+option "layoutver" y "Flash layout version (version 2.2x of the Broadcom code requires this)." string optional
+option "info1" 1 "String for first vendor information section." string optional
+option "altinfo" - "String for vendor information section (alternate/pirelli)." string optional
+option "info2" 2 "String for second vendor information section." string optional
+option "root-first" - "Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory)." flag off
+option "rsa-signature" r "String for RSA Signature section." string optional
+option "second-image-flag" - "Dual Image Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional
+option "inactive" - "Inactive Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional
+option "reserved2" - "String for second reserved section." string optional
+option "kernel-file-has-header" - "Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed" flag off
+option "pad" p "Pad the image to this size if smaller (in MiB)" int typestr="size (in MiB)" optional
+option "align-rootfs" - "Align the rootfs start to erase block size" flag off
diff --git a/tools/firmware-utils/src/imagetag_cmdline.c b/tools/firmware-utils/src/imagetag_cmdline.c
new file mode 100644
index 0000000000..86c90bbb67
--- /dev/null
+++ b/tools/firmware-utils/src/imagetag_cmdline.c
@@ -0,0 +1,1193 @@
+/*
+  File autogenerated by gengetopt version 2.22.5
+  generated with the following command:
+  gengetopt -i imagetag.ggo -f imagetag_cmdline --file-name=imagetag_cmdline
+
+  The developers of gengetopt consider the fixed text that goes in all
+  gengetopt output files to be in the public domain:
+  we make no copyright claims on it.
+*/
+
+/* If we use autoconf.  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef FIX_UNUSED
+#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */
+#endif
+
+#include <getopt.h>
+
+#include "imagetag_cmdline.h"
+
+const char *gengetopt_args_info_purpose = "Generate image with CFE imagetag for Broadcom 63xx routers.";
+
+const char *gengetopt_args_info_usage = "Usage: imagetag [OPTIONS]...";
+
+const char *gengetopt_args_info_description = "Copyright (C) 2008 Axel Gembe\nCopyright (C) 2009-2010 Daniel Dickinson\nLicensed unter the terms of the Gnu General Public License.\n\nGiven a root filesystem, a linux kernel, and an optional CFE, generates an \nimage with an imagetag for a Broadcom 63xx-based router.  Additional parameters \nto be specified depend on the specfic brand and model of router.";
+
+const char *gengetopt_args_info_help[] = {
+  "  -h, --help                    Print help and exit",
+  "  -V, --version                 Print version and exit",
+  "  -i, --kernel=filename         File with LZMA compressed kernel to include in \n                                  the image.",
+  "  -f, --rootfs=filename         File with RootFS to include in the image.",
+  "  -o, --output=filename         Name of output file.",
+  "      --cfe=filename            File with CFE to include in the image.",
+  "  -b, --boardid=STRING          Board ID to set in the image (must match what \n                                  router expects, e.g. \"96345GW2\").",
+  "  -c, --chipid=STRING           Chip ID to set in the image (must match the \n                                  actual hardware, e.g. \"6345\").",
+  "  -s, --flash-start=address     Flash start address.  (default=`0xBFC00000')",
+  "  -n, --image-offset=offset     Offset from start address for the first byte \n                                  after the CFE (in memory).  \n                                  (default=`0x10000')",
+  "  -v, --tag-version=STRING      Version number for imagetag format.  \n                                  (default=`6')",
+  "  -a, --signature=STRING        Magic string (signature), for boards that need \n                                  it.  (default=`Broadcom Corporatio')",
+  "  -m, --signature2=STRING       Second magic string (signature2).  \n                                  (default=`ver. 2.0')",
+  "  -k, --block-size=STRING       Flash erase block size.  (default=`0x10000')",
+  "  -l, --load-addr=address       Kernel load address.",
+  "  -e, --entry=address           Address where the kernel entry point will be \n                                  for booting.",
+  "  -y, --layoutver=STRING        Flash layout version (version 2.2x of the \n                                  Broadcom code requires this).",
+  "  -1, --info1=STRING            String for first vendor information section.",
+  "      --altinfo=STRING          String for vendor information section \n                                  (alternate/pirelli).",
+  "  -2, --info2=STRING            String for second vendor information section.",
+  "      --root-first              Put the rootfs before the kernel (only for \n                                  stock images, e.g. captured from the router's \n                                  flash memory).  (default=off)",
+  "  -r, --rsa-signature=STRING    String for RSA Signature section.",
+  "      --second-image-flag=flag-value\n                                Dual Image Flag (2=not-specified).  (possible \n                                  values=\"0\", \"1\", \"2\" default=`2')",
+  "      --inactive=flag-value     Inactive Flag (2=not-specified).  (possible \n                                  values=\"0\", \"1\", \"2\" default=`2')",
+  "      --reserved2=STRING        String for second reserved section.",
+  "      --kernel-file-has-header  Indicates that the kernel file includes the \n                                  kernel header with correct load address and \n                                  entry point, so no changes are needed  \n                                  (default=off)",
+  "  -p, --pad=size (in MiB)       Pad the image to this size if smaller (in MiB)",
+  "      --align-rootfs            Align the rootfs start to erase block size  \n                                  (default=off)",
+    0
+};
+
+typedef enum {ARG_NO
+  , ARG_FLAG
+  , ARG_STRING
+  , ARG_INT
+} imagetag_cmdline_arg_type;
+
+static
+void clear_given (struct gengetopt_args_info *args_info);
+static
+void clear_args (struct gengetopt_args_info *args_info);
+
+static int
+imagetag_cmdline_internal (int argc, char **argv, struct gengetopt_args_info *args_info,
+                        struct imagetag_cmdline_params *params, const char *additional_error);
+
+static int
+imagetag_cmdline_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error);
+
+const char *imagetag_cmdline_second_image_flag_values[] = {"0", "1", "2", 0}; /*< Possible values for second-image-flag. */
+const char *imagetag_cmdline_inactive_values[] = {"0", "1", "2", 0}; /*< Possible values for inactive. */
+
+static char *
+gengetopt_strdup (const char *s);
+
+static
+void clear_given (struct gengetopt_args_info *args_info)
+{
+  args_info->help_given = 0 ;
+  args_info->version_given = 0 ;
+  args_info->kernel_given = 0 ;
+  args_info->rootfs_given = 0 ;
+  args_info->output_given = 0 ;
+  args_info->cfe_given = 0 ;
+  args_info->boardid_given = 0 ;
+  args_info->chipid_given = 0 ;
+  args_info->flash_start_given = 0 ;
+  args_info->image_offset_given = 0 ;
+  args_info->tag_version_given = 0 ;
+  args_info->signature_given = 0 ;
+  args_info->signature2_given = 0 ;
+  args_info->block_size_given = 0 ;
+  args_info->load_addr_given = 0 ;
+  args_info->entry_given = 0 ;
+  args_info->layoutver_given = 0 ;
+  args_info->info1_given = 0 ;
+  args_info->altinfo_given = 0 ;
+  args_info->info2_given = 0 ;
+  args_info->root_first_given = 0 ;
+  args_info->rsa_signature_given = 0 ;
+  args_info->second_image_flag_given = 0 ;
+  args_info->inactive_given = 0 ;
+  args_info->reserved2_given = 0 ;
+  args_info->kernel_file_has_header_given = 0 ;
+  args_info->pad_given = 0 ;
+  args_info->align_rootfs_given = 0 ;
+}
+
+static
+void clear_args (struct gengetopt_args_info *args_info)
+{
+  FIX_UNUSED (args_info);
+  args_info->kernel_arg = NULL;
+  args_info->kernel_orig = NULL;
+  args_info->rootfs_arg = NULL;
+  args_info->rootfs_orig = NULL;
+  args_info->output_arg = NULL;
+  args_info->output_orig = NULL;
+  args_info->cfe_arg = NULL;
+  args_info->cfe_orig = NULL;
+  args_info->boardid_arg = NULL;
+  args_info->boardid_orig = NULL;
+  args_info->chipid_arg = NULL;
+  args_info->chipid_orig = NULL;
+  args_info->flash_start_arg = gengetopt_strdup ("0xBFC00000");
+  args_info->flash_start_orig = NULL;
+  args_info->image_offset_arg = gengetopt_strdup ("0x10000");
+  args_info->image_offset_orig = NULL;
+  args_info->tag_version_arg = gengetopt_strdup ("6");
+  args_info->tag_version_orig = NULL;
+  args_info->signature_arg = gengetopt_strdup ("Broadcom Corporatio");
+  args_info->signature_orig = NULL;
+  args_info->signature2_arg = gengetopt_strdup ("ver. 2.0");
+  args_info->signature2_orig = NULL;
+  args_info->block_size_arg = gengetopt_strdup ("0x10000");
+  args_info->block_size_orig = NULL;
+  args_info->load_addr_arg = NULL;
+  args_info->load_addr_orig = NULL;
+  args_info->entry_arg = NULL;
+  args_info->entry_orig = NULL;
+  args_info->layoutver_arg = NULL;
+  args_info->layoutver_orig = NULL;
+  args_info->info1_arg = NULL;
+  args_info->info1_orig = NULL;
+  args_info->altinfo_arg = NULL;
+  args_info->altinfo_orig = NULL;
+  args_info->info2_arg = NULL;
+  args_info->info2_orig = NULL;
+  args_info->root_first_flag = 0;
+  args_info->rsa_signature_arg = NULL;
+  args_info->rsa_signature_orig = NULL;
+  args_info->second_image_flag_arg = gengetopt_strdup ("2");
+  args_info->second_image_flag_orig = NULL;
+  args_info->inactive_arg = gengetopt_strdup ("2");
+  args_info->inactive_orig = NULL;
+  args_info->reserved2_arg = NULL;
+  args_info->reserved2_orig = NULL;
+  args_info->kernel_file_has_header_flag = 0;
+  args_info->pad_orig = NULL;
+  args_info->align_rootfs_flag = 0;
+  
+}
+
+static
+void init_args_info(struct gengetopt_args_info *args_info)
+{
+
+
+  args_info->help_help = gengetopt_args_info_help[0] ;
+  args_info->version_help = gengetopt_args_info_help[1] ;
+  args_info->kernel_help = gengetopt_args_info_help[2] ;
+  args_info->rootfs_help = gengetopt_args_info_help[3] ;
+  args_info->output_help = gengetopt_args_info_help[4] ;
+  args_info->cfe_help = gengetopt_args_info_help[5] ;
+  args_info->boardid_help = gengetopt_args_info_help[6] ;
+  args_info->chipid_help = gengetopt_args_info_help[7] ;
+  args_info->flash_start_help = gengetopt_args_info_help[8] ;
+  args_info->image_offset_help = gengetopt_args_info_help[9] ;
+  args_info->tag_version_help = gengetopt_args_info_help[10] ;
+  args_info->signature_help = gengetopt_args_info_help[11] ;
+  args_info->signature2_help = gengetopt_args_info_help[12] ;
+  args_info->block_size_help = gengetopt_args_info_help[13] ;
+  args_info->load_addr_help = gengetopt_args_info_help[14] ;
+  args_info->entry_help = gengetopt_args_info_help[15] ;
+  args_info->layoutver_help = gengetopt_args_info_help[16] ;
+  args_info->info1_help = gengetopt_args_info_help[17] ;
+  args_info->altinfo_help = gengetopt_args_info_help[18] ;
+  args_info->info2_help = gengetopt_args_info_help[19] ;
+  args_info->root_first_help = gengetopt_args_info_help[20] ;
+  args_info->rsa_signature_help = gengetopt_args_info_help[21] ;
+  args_info->second_image_flag_help = gengetopt_args_info_help[22] ;
+  args_info->inactive_help = gengetopt_args_info_help[23] ;
+  args_info->reserved2_help = gengetopt_args_info_help[24] ;
+  args_info->kernel_file_has_header_help = gengetopt_args_info_help[25] ;
+  args_info->pad_help = gengetopt_args_info_help[26] ;
+  args_info->align_rootfs_help = gengetopt_args_info_help[27] ;
+  
+}
+
+void
+imagetag_cmdline_print_version (void)
+{
+  printf ("%s %s\n",
+     (strlen(IMAGETAG_CMDLINE_PACKAGE_NAME) ? IMAGETAG_CMDLINE_PACKAGE_NAME : IMAGETAG_CMDLINE_PACKAGE),
+     IMAGETAG_CMDLINE_VERSION);
+}
+
+static void print_help_common(void) {
+  imagetag_cmdline_print_version ();
+
+  if (strlen(gengetopt_args_info_purpose) > 0)
+    printf("\n%s\n", gengetopt_args_info_purpose);
+
+  if (strlen(gengetopt_args_info_usage) > 0)
+    printf("\n%s\n", gengetopt_args_info_usage);
+
+  printf("\n");
+
+  if (strlen(gengetopt_args_info_description) > 0)
+    printf("%s\n\n", gengetopt_args_info_description);
+}
+
+void
+imagetag_cmdline_print_help (void)
+{
+  int i = 0;
+  print_help_common();
+  while (gengetopt_args_info_help[i])
+    printf("%s\n", gengetopt_args_info_help[i++]);
+}
+
+void
+imagetag_cmdline_init (struct gengetopt_args_info *args_info)
+{
+  clear_given (args_info);
+  clear_args (args_info);
+  init_args_info (args_info);
+}
+
+void
+imagetag_cmdline_params_init(struct imagetag_cmdline_params *params)
+{
+  if (params)
+    { 
+      params->override = 0;
+      params->initialize = 1;
+      params->check_required = 1;
+      params->check_ambiguity = 0;
+      params->print_errors = 1;
+    }
+}
+
+struct imagetag_cmdline_params *
+imagetag_cmdline_params_create(void)
+{
+  struct imagetag_cmdline_params *params = 
+    (struct imagetag_cmdline_params *)malloc(sizeof(struct imagetag_cmdline_params));
+  imagetag_cmdline_params_init(params);  
+  return params;
+}
+
+static void
+free_string_field (char **s)
+{
+  if (*s)
+    {
+      free (*s);
+      *s = 0;
+    }
+}
+
+
+static void
+imagetag_cmdline_release (struct gengetopt_args_info *args_info)
+{
+
+  free_string_field (&(args_info->kernel_arg));
+  free_string_field (&(args_info->kernel_orig));
+  free_string_field (&(args_info->rootfs_arg));
+  free_string_field (&(args_info->rootfs_orig));
+  free_string_field (&(args_info->output_arg));
+  free_string_field (&(args_info->output_orig));
+  free_string_field (&(args_info->cfe_arg));
+  free_string_field (&(args_info->cfe_orig));
+  free_string_field (&(args_info->boardid_arg));
+  free_string_field (&(args_info->boardid_orig));
+  free_string_field (&(args_info->chipid_arg));
+  free_string_field (&(args_info->chipid_orig));
+  free_string_field (&(args_info->flash_start_arg));
+  free_string_field (&(args_info->flash_start_orig));
+  free_string_field (&(args_info->image_offset_arg));
+  free_string_field (&(args_info->image_offset_orig));
+  free_string_field (&(args_info->tag_version_arg));
+  free_string_field (&(args_info->tag_version_orig));
+  free_string_field (&(args_info->signature_arg));
+  free_string_field (&(args_info->signature_orig));
+  free_string_field (&(args_info->signature2_arg));
+  free_string_field (&(args_info->signature2_orig));
+  free_string_field (&(args_info->block_size_arg));
+  free_string_field (&(args_info->block_size_orig));
+  free_string_field (&(args_info->load_addr_arg));
+  free_string_field (&(args_info->load_addr_orig));
+  free_string_field (&(args_info->entry_arg));
+  free_string_field (&(args_info->entry_orig));
+  free_string_field (&(args_info->layoutver_arg));
+  free_string_field (&(args_info->layoutver_orig));
+  free_string_field (&(args_info->info1_arg));
+  free_string_field (&(args_info->info1_orig));
+  free_string_field (&(args_info->altinfo_arg));
+  free_string_field (&(args_info->altinfo_orig));
+  free_string_field (&(args_info->info2_arg));
+  free_string_field (&(args_info->info2_orig));
+  free_string_field (&(args_info->rsa_signature_arg));
+  free_string_field (&(args_info->rsa_signature_orig));
+  free_string_field (&(args_info->second_image_flag_arg));
+  free_string_field (&(args_info->second_image_flag_orig));
+  free_string_field (&(args_info->inactive_arg));
+  free_string_field (&(args_info->inactive_orig));
+  free_string_field (&(args_info->reserved2_arg));
+  free_string_field (&(args_info->reserved2_orig));
+  free_string_field (&(args_info->pad_orig));
+  
+  
+
+  clear_given (args_info);
+}
+
+/**
+ * @param val the value to check
+ * @param values the possible values
+ * @return the index of the matched value:
+ * -1 if no value matched,
+ * -2 if more than one value has matched
+ */
+static int
+check_possible_values(const char *val, const char *values[])
+{
+  int i, found, last;
+  size_t len;
+
+  if (!val)   /* otherwise strlen() crashes below */
+    return -1; /* -1 means no argument for the option */
+
+  found = last = 0;
+
+  for (i = 0, len = strlen(val); values[i]; ++i)
+    {
+      if (strncmp(val, values[i], len) == 0)
+        {
+          ++found;
+          last = i;
+          if (strlen(values[i]) == len)
+            return i; /* exact macth no need to check more */
+        }
+    }
+
+  if (found == 1) /* one match: OK */
+    return last;
+
+  return (found ? -2 : -1); /* return many values or none matched */
+}
+
+
+static void
+write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[])
+{
+  int found = -1;
+  if (arg) {
+    if (values) {
+      found = check_possible_values(arg, values);      
+    }
+    if (found >= 0)
+      fprintf(outfile, "%s=\"%s\" # %s\n", opt, arg, values[found]);
+    else
+      fprintf(outfile, "%s=\"%s\"\n", opt, arg);
+  } else {
+    fprintf(outfile, "%s\n", opt);
+  }
+}
+
+
+int
+imagetag_cmdline_dump(FILE *outfile, struct gengetopt_args_info *args_info)
+{
+  int i = 0;
+
+  if (!outfile)
+    {
+      fprintf (stderr, "%s: cannot dump options to stream\n", IMAGETAG_CMDLINE_PACKAGE);
+      return EXIT_FAILURE;
+    }
+
+  if (args_info->help_given)
+    write_into_file(outfile, "help", 0, 0 );
+  if (args_info->version_given)
+    write_into_file(outfile, "version", 0, 0 );
+  if (args_info->kernel_given)
+    write_into_file(outfile, "kernel", args_info->kernel_orig, 0);
+  if (args_info->rootfs_given)
+    write_into_file(outfile, "rootfs", args_info->rootfs_orig, 0);
+  if (args_info->output_given)
+    write_into_file(outfile, "output", args_info->output_orig, 0);
+  if (args_info->cfe_given)
+    write_into_file(outfile, "cfe", args_info->cfe_orig, 0);
+  if (args_info->boardid_given)
+    write_into_file(outfile, "boardid", args_info->boardid_orig, 0);
+  if (args_info->chipid_given)
+    write_into_file(outfile, "chipid", args_info->chipid_orig, 0);
+  if (args_info->flash_start_given)
+    write_into_file(outfile, "flash-start", args_info->flash_start_orig, 0);
+  if (args_info->image_offset_given)
+    write_into_file(outfile, "image-offset", args_info->image_offset_orig, 0);
+  if (args_info->tag_version_given)
+    write_into_file(outfile, "tag-version", args_info->tag_version_orig, 0);
+  if (args_info->signature_given)
+    write_into_file(outfile, "signature", args_info->signature_orig, 0);
+  if (args_info->signature2_given)
+    write_into_file(outfile, "signature2", args_info->signature2_orig, 0);
+  if (args_info->block_size_given)
+    write_into_file(outfile, "block-size", args_info->block_size_orig, 0);
+  if (args_info->load_addr_given)
+    write_into_file(outfile, "load-addr", args_info->load_addr_orig, 0);
+  if (args_info->entry_given)
+    write_into_file(outfile, "entry", args_info->entry_orig, 0);
+  if (args_info->layoutver_given)
+    write_into_file(outfile, "layoutver", args_info->layoutver_orig, 0);
+  if (args_info->info1_given)
+    write_into_file(outfile, "info1", args_info->info1_orig, 0);
+  if (args_info->altinfo_given)
+    write_into_file(outfile, "altinfo", args_info->altinfo_orig, 0);
+  if (args_info->info2_given)
+    write_into_file(outfile, "info2", args_info->info2_orig, 0);
+  if (args_info->root_first_given)
+    write_into_file(outfile, "root-first", 0, 0 );
+  if (args_info->rsa_signature_given)
+    write_into_file(outfile, "rsa-signature", args_info->rsa_signature_orig, 0);
+  if (args_info->second_image_flag_given)
+    write_into_file(outfile, "second-image-flag", args_info->second_image_flag_orig, imagetag_cmdline_second_image_flag_values);
+  if (args_info->inactive_given)
+    write_into_file(outfile, "inactive", args_info->inactive_orig, imagetag_cmdline_inactive_values);
+  if (args_info->reserved2_given)
+    write_into_file(outfile, "reserved2", args_info->reserved2_orig, 0);
+  if (args_info->kernel_file_has_header_given)
+    write_into_file(outfile, "kernel-file-has-header", 0, 0 );
+  if (args_info->pad_given)
+    write_into_file(outfile, "pad", args_info->pad_orig, 0);
+  if (args_info->align_rootfs_given)
+    write_into_file(outfile, "align-rootfs", 0, 0 );
+  
+
+  i = EXIT_SUCCESS;
+  return i;
+}
+
+int
+imagetag_cmdline_file_save(const char *filename, struct gengetopt_args_info *args_info)
+{
+  FILE *outfile;
+  int i = 0;
+
+  outfile = fopen(filename, "w");
+
+  if (!outfile)
+    {
+      fprintf (stderr, "%s: cannot open file for writing: %s\n", IMAGETAG_CMDLINE_PACKAGE, filename);
+      return EXIT_FAILURE;
+    }
+
+  i = imagetag_cmdline_dump(outfile, args_info);
+  fclose (outfile);
+
+  return i;
+}
+
+void
+imagetag_cmdline_free (struct gengetopt_args_info *args_info)
+{
+  imagetag_cmdline_release (args_info);
+}
+
+/** @brief replacement of strdup, which is not standard */
+char *
+gengetopt_strdup (const char *s)
+{
+  char *result = 0;
+  if (!s)
+    return result;
+
+  result = (char*)malloc(strlen(s) + 1);
+  if (result == (char*)0)
+    return (char*)0;
+  strcpy(result, s);
+  return result;
+}
+
+int
+imagetag_cmdline (int argc, char **argv, struct gengetopt_args_info *args_info)
+{
+  return imagetag_cmdline2 (argc, argv, args_info, 0, 1, 1);
+}
+
+int
+imagetag_cmdline_ext (int argc, char **argv, struct gengetopt_args_info *args_info,
+                   struct imagetag_cmdline_params *params)
+{
+  int result;
+  result = imagetag_cmdline_internal (argc, argv, args_info, params, 0);
+
+  if (result == EXIT_FAILURE)
+    {
+      imagetag_cmdline_free (args_info);
+      exit (EXIT_FAILURE);
+    }
+  
+  return result;
+}
+
+int
+imagetag_cmdline2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required)
+{
+  int result;
+  struct imagetag_cmdline_params params;
+  
+  params.override = override;
+  params.initialize = initialize;
+  params.check_required = check_required;
+  params.check_ambiguity = 0;
+  params.print_errors = 1;
+
+  result = imagetag_cmdline_internal (argc, argv, args_info, &params, 0);
+
+  if (result == EXIT_FAILURE)
+    {
+      imagetag_cmdline_free (args_info);
+      exit (EXIT_FAILURE);
+    }
+  
+  return result;
+}
+
+int
+imagetag_cmdline_required (struct gengetopt_args_info *args_info, const char *prog_name)
+{
+  int result = EXIT_SUCCESS;
+
+  if (imagetag_cmdline_required2(args_info, prog_name, 0) > 0)
+    result = EXIT_FAILURE;
+
+  if (result == EXIT_FAILURE)
+    {
+      imagetag_cmdline_free (args_info);
+      exit (EXIT_FAILURE);
+    }
+  
+  return result;
+}
+
+int
+imagetag_cmdline_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error)
+{
+  int error = 0;
+  FIX_UNUSED (additional_error);
+
+  /* checks for required options */
+  if (! args_info->kernel_given)
+    {
+      fprintf (stderr, "%s: '--kernel' ('-i') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->rootfs_given)
+    {
+      fprintf (stderr, "%s: '--rootfs' ('-f') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->output_given)
+    {
+      fprintf (stderr, "%s: '--output' ('-o') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->boardid_given)
+    {
+      fprintf (stderr, "%s: '--boardid' ('-b') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->chipid_given)
+    {
+      fprintf (stderr, "%s: '--chipid' ('-c') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->load_addr_given)
+    {
+      fprintf (stderr, "%s: '--load-addr' ('-l') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  if (! args_info->entry_given)
+    {
+      fprintf (stderr, "%s: '--entry' ('-e') option required%s\n", prog_name, (additional_error ? additional_error : ""));
+      error = 1;
+    }
+  
+  
+  /* checks for dependences among options */
+
+  return error;
+}
+
+
+static char *package_name = 0;
+
+/**
+ * @brief updates an option
+ * @param field the generic pointer to the field to update
+ * @param orig_field the pointer to the orig field
+ * @param field_given the pointer to the number of occurrence of this option
+ * @param prev_given the pointer to the number of occurrence already seen
+ * @param value the argument for this option (if null no arg was specified)
+ * @param possible_values the possible values for this option (if specified)
+ * @param default_value the default value (in case the option only accepts fixed values)
+ * @param arg_type the type of this option
+ * @param check_ambiguity @see imagetag_cmdline_params.check_ambiguity
+ * @param override @see imagetag_cmdline_params.override
+ * @param no_free whether to free a possible previous value
+ * @param multiple_option whether this is a multiple option
+ * @param long_opt the corresponding long option
+ * @param short_opt the corresponding short option (or '-' if none)
+ * @param additional_error possible further error specification
+ */
+static
+int update_arg(void *field, char **orig_field,
+               unsigned int *field_given, unsigned int *prev_given, 
+               char *value, const char *possible_values[],
+               const char *default_value,
+               imagetag_cmdline_arg_type arg_type,
+               int check_ambiguity, int override,
+               int no_free, int multiple_option,
+               const char *long_opt, char short_opt,
+               const char *additional_error)
+{
+  char *stop_char = 0;
+  const char *val = value;
+  int found;
+  char **string_field;
+  FIX_UNUSED (field);
+
+  stop_char = 0;
+  found = 0;
+
+  if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given)))
+    {
+      if (short_opt != '-')
+        fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", 
+               package_name, long_opt, short_opt,
+               (additional_error ? additional_error : ""));
+      else
+        fprintf (stderr, "%s: `--%s' option given more than once%s\n", 
+               package_name, long_opt,
+               (additional_error ? additional_error : ""));
+      return 1; /* failure */
+    }
+
+  if (possible_values && (found = check_possible_values((value ? value : default_value), possible_values)) < 0)
+    {
+      if (short_opt != '-')
+        fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s' (`-%c')%s\n", 
+          package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, short_opt,
+          (additional_error ? additional_error : ""));
+      else
+        fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s'%s\n", 
+          package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt,
+          (additional_error ? additional_error : ""));
+      return 1; /* failure */
+    }
+    
+  if (field_given && *field_given && ! override)
+    return 0;
+  if (prev_given)
+    (*prev_given)++;
+  if (field_given)
+    (*field_given)++;
+  if (possible_values)
+    val = possible_values[found];
+
+  switch(arg_type) {
+  case ARG_FLAG:
+    *((int *)field) = !*((int *)field);
+    break;
+  case ARG_INT:
+    if (val) *((int *)field) = strtol (val, &stop_char, 0);
+    break;
+  case ARG_STRING:
+    if (val) {
+      string_field = (char **)field;
+      if (!no_free && *string_field)
+        free (*string_field); /* free previous string */
+      *string_field = gengetopt_strdup (val);
+    }
+    break;
+  default:
+    break;
+  };
+
+  /* check numeric conversion */
+  switch(arg_type) {
+  case ARG_INT:
+    if (val && !(stop_char && *stop_char == '\0')) {
+      fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val);
+      return 1; /* failure */
+    }
+    break;
+  default:
+    ;
+  };
+
+  /* store the original value */
+  switch(arg_type) {
+  case ARG_NO:
+  case ARG_FLAG:
+    break;
+  default:
+    if (value && orig_field) {
+      if (no_free) {
+        *orig_field = value;
+      } else {
+        if (*orig_field)
+          free (*orig_field); /* free previous string */
+        *orig_field = gengetopt_strdup (value);
+      }
+    }
+  };
+
+  return 0; /* OK */
+}
+
+
+int
+imagetag_cmdline_internal (
+  int argc, char **argv, struct gengetopt_args_info *args_info,
+                        struct imagetag_cmdline_params *params, const char *additional_error)
+{
+  int c;	/* Character of the parsed option.  */
+
+  int error = 0;
+  struct gengetopt_args_info local_args_info;
+  
+  int override;
+  int initialize;
+  int check_required;
+  int check_ambiguity;
+  
+  package_name = argv[0];
+  
+  override = params->override;
+  initialize = params->initialize;
+  check_required = params->check_required;
+  check_ambiguity = params->check_ambiguity;
+
+  if (initialize)
+    imagetag_cmdline_init (args_info);
+
+  imagetag_cmdline_init (&local_args_info);
+
+  optarg = 0;
+  optind = 0;
+  opterr = params->print_errors;
+  optopt = '?';
+
+  while (1)
+    {
+      int option_index = 0;
+
+      static struct option long_options[] = {
+        { "help",	0, NULL, 'h' },
+        { "version",	0, NULL, 'V' },
+        { "kernel",	1, NULL, 'i' },
+        { "rootfs",	1, NULL, 'f' },
+        { "output",	1, NULL, 'o' },
+        { "cfe",	1, NULL, 0 },
+        { "boardid",	1, NULL, 'b' },
+        { "chipid",	1, NULL, 'c' },
+        { "flash-start",	1, NULL, 's' },
+        { "image-offset",	1, NULL, 'n' },
+        { "tag-version",	1, NULL, 'v' },
+        { "signature",	1, NULL, 'a' },
+        { "signature2",	1, NULL, 'm' },
+        { "block-size",	1, NULL, 'k' },
+        { "load-addr",	1, NULL, 'l' },
+        { "entry",	1, NULL, 'e' },
+        { "layoutver",	1, NULL, 'y' },
+        { "info1",	1, NULL, '1' },
+        { "altinfo",	1, NULL, 0 },
+        { "info2",	1, NULL, '2' },
+        { "root-first",	0, NULL, 0 },
+        { "rsa-signature",	1, NULL, 'r' },
+        { "second-image-flag",	1, NULL, 0 },
+        { "inactive",	1, NULL, 0 },
+        { "reserved2",	1, NULL, 0 },
+        { "kernel-file-has-header",	0, NULL, 0 },
+        { "pad",	1, NULL, 'p' },
+        { "align-rootfs",	0, NULL, 0 },
+        { 0,  0, 0, 0 }
+      };
+
+      c = getopt_long (argc, argv, "hVi:f:o:b:c:s:n:v:a:m:k:l:e:y:1:2:r:p:", long_options, &option_index);
+
+      if (c == -1) break;	/* Exit from `while (1)' loop.  */
+
+      switch (c)
+        {
+        case 'h':	/* Print help and exit.  */
+          imagetag_cmdline_print_help ();
+          imagetag_cmdline_free (&local_args_info);
+          exit (EXIT_SUCCESS);
+
+        case 'V':	/* Print version and exit.  */
+          imagetag_cmdline_print_version ();
+          imagetag_cmdline_free (&local_args_info);
+          exit (EXIT_SUCCESS);
+
+        case 'i':	/* File with LZMA compressed kernel to include in the image..  */
+        
+        
+          if (update_arg( (void *)&(args_info->kernel_arg), 
+               &(args_info->kernel_orig), &(args_info->kernel_given),
+              &(local_args_info.kernel_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "kernel", 'i',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'f':	/* File with RootFS to include in the image..  */
+        
+        
+          if (update_arg( (void *)&(args_info->rootfs_arg), 
+               &(args_info->rootfs_orig), &(args_info->rootfs_given),
+              &(local_args_info.rootfs_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "rootfs", 'f',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'o':	/* Name of output file..  */
+        
+        
+          if (update_arg( (void *)&(args_info->output_arg), 
+               &(args_info->output_orig), &(args_info->output_given),
+              &(local_args_info.output_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "output", 'o',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'b':	/* Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")..  */
+        
+        
+          if (update_arg( (void *)&(args_info->boardid_arg), 
+               &(args_info->boardid_orig), &(args_info->boardid_given),
+              &(local_args_info.boardid_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "boardid", 'b',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'c':	/* Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")..  */
+        
+        
+          if (update_arg( (void *)&(args_info->chipid_arg), 
+               &(args_info->chipid_orig), &(args_info->chipid_given),
+              &(local_args_info.chipid_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "chipid", 'c',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 's':	/* Flash start address..  */
+        
+        
+          if (update_arg( (void *)&(args_info->flash_start_arg), 
+               &(args_info->flash_start_orig), &(args_info->flash_start_given),
+              &(local_args_info.flash_start_given), optarg, 0, "0xBFC00000", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "flash-start", 's',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'n':	/* Offset from start address for the first byte after the CFE (in memory)..  */
+        
+        
+          if (update_arg( (void *)&(args_info->image_offset_arg), 
+               &(args_info->image_offset_orig), &(args_info->image_offset_given),
+              &(local_args_info.image_offset_given), optarg, 0, "0x10000", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "image-offset", 'n',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'v':	/* Version number for imagetag format..  */
+        
+        
+          if (update_arg( (void *)&(args_info->tag_version_arg), 
+               &(args_info->tag_version_orig), &(args_info->tag_version_given),
+              &(local_args_info.tag_version_given), optarg, 0, "6", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "tag-version", 'v',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'a':	/* Magic string (signature), for boards that need it..  */
+        
+        
+          if (update_arg( (void *)&(args_info->signature_arg), 
+               &(args_info->signature_orig), &(args_info->signature_given),
+              &(local_args_info.signature_given), optarg, 0, "Broadcom Corporatio", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "signature", 'a',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'm':	/* Second magic string (signature2)..  */
+        
+        
+          if (update_arg( (void *)&(args_info->signature2_arg), 
+               &(args_info->signature2_orig), &(args_info->signature2_given),
+              &(local_args_info.signature2_given), optarg, 0, "ver. 2.0", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "signature2", 'm',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'k':	/* Flash erase block size..  */
+        
+        
+          if (update_arg( (void *)&(args_info->block_size_arg), 
+               &(args_info->block_size_orig), &(args_info->block_size_given),
+              &(local_args_info.block_size_given), optarg, 0, "0x10000", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "block-size", 'k',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'l':	/* Kernel load address..  */
+        
+        
+          if (update_arg( (void *)&(args_info->load_addr_arg), 
+               &(args_info->load_addr_orig), &(args_info->load_addr_given),
+              &(local_args_info.load_addr_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "load-addr", 'l',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'e':	/* Address where the kernel entry point will be for booting..  */
+        
+        
+          if (update_arg( (void *)&(args_info->entry_arg), 
+               &(args_info->entry_orig), &(args_info->entry_given),
+              &(local_args_info.entry_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "entry", 'e',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'y':	/* Flash layout version (version 2.2x of the Broadcom code requires this)..  */
+        
+        
+          if (update_arg( (void *)&(args_info->layoutver_arg), 
+               &(args_info->layoutver_orig), &(args_info->layoutver_given),
+              &(local_args_info.layoutver_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "layoutver", 'y',
+              additional_error))
+            goto failure;
+        
+          break;
+        case '1':	/* String for first vendor information section..  */
+        
+        
+          if (update_arg( (void *)&(args_info->info1_arg), 
+               &(args_info->info1_orig), &(args_info->info1_given),
+              &(local_args_info.info1_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "info1", '1',
+              additional_error))
+            goto failure;
+        
+          break;
+        case '2':	/* String for second vendor information section..  */
+        
+        
+          if (update_arg( (void *)&(args_info->info2_arg), 
+               &(args_info->info2_orig), &(args_info->info2_given),
+              &(local_args_info.info2_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "info2", '2',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'r':	/* String for RSA Signature section..  */
+        
+        
+          if (update_arg( (void *)&(args_info->rsa_signature_arg), 
+               &(args_info->rsa_signature_orig), &(args_info->rsa_signature_given),
+              &(local_args_info.rsa_signature_given), optarg, 0, 0, ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "rsa-signature", 'r',
+              additional_error))
+            goto failure;
+        
+          break;
+        case 'p':	/* Pad the image to this size if smaller (in MiB).  */
+        
+        
+          if (update_arg( (void *)&(args_info->pad_arg), 
+               &(args_info->pad_orig), &(args_info->pad_given),
+              &(local_args_info.pad_given), optarg, 0, 0, ARG_INT,
+              check_ambiguity, override, 0, 0,
+              "pad", 'p',
+              additional_error))
+            goto failure;
+        
+          break;
+
+        case 0:	/* Long option with no short option */
+          /* File with CFE to include in the image..  */
+          if (strcmp (long_options[option_index].name, "cfe") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->cfe_arg), 
+                 &(args_info->cfe_orig), &(args_info->cfe_given),
+                &(local_args_info.cfe_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "cfe", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* String for vendor information section (alternate/pirelli)..  */
+          else if (strcmp (long_options[option_index].name, "altinfo") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->altinfo_arg), 
+                 &(args_info->altinfo_orig), &(args_info->altinfo_given),
+                &(local_args_info.altinfo_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "altinfo", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory)..  */
+          else if (strcmp (long_options[option_index].name, "root-first") == 0)
+          {
+          
+          
+            if (update_arg((void *)&(args_info->root_first_flag), 0, &(args_info->root_first_given),
+                &(local_args_info.root_first_given), optarg, 0, 0, ARG_FLAG,
+                check_ambiguity, override, 1, 0, "root-first", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Dual Image Flag (2=not-specified)..  */
+          else if (strcmp (long_options[option_index].name, "second-image-flag") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->second_image_flag_arg), 
+                 &(args_info->second_image_flag_orig), &(args_info->second_image_flag_given),
+                &(local_args_info.second_image_flag_given), optarg, imagetag_cmdline_second_image_flag_values, "2", ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "second-image-flag", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Inactive Flag (2=not-specified)..  */
+          else if (strcmp (long_options[option_index].name, "inactive") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->inactive_arg), 
+                 &(args_info->inactive_orig), &(args_info->inactive_given),
+                &(local_args_info.inactive_given), optarg, imagetag_cmdline_inactive_values, "2", ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "inactive", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* String for second reserved section..  */
+          else if (strcmp (long_options[option_index].name, "reserved2") == 0)
+          {
+          
+          
+            if (update_arg( (void *)&(args_info->reserved2_arg), 
+                 &(args_info->reserved2_orig), &(args_info->reserved2_given),
+                &(local_args_info.reserved2_given), optarg, 0, 0, ARG_STRING,
+                check_ambiguity, override, 0, 0,
+                "reserved2", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed.  */
+          else if (strcmp (long_options[option_index].name, "kernel-file-has-header") == 0)
+          {
+          
+          
+            if (update_arg((void *)&(args_info->kernel_file_has_header_flag), 0, &(args_info->kernel_file_has_header_given),
+                &(local_args_info.kernel_file_has_header_given), optarg, 0, 0, ARG_FLAG,
+                check_ambiguity, override, 1, 0, "kernel-file-has-header", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          /* Align the rootfs start to erase block size.  */
+          else if (strcmp (long_options[option_index].name, "align-rootfs") == 0)
+          {
+          
+          
+            if (update_arg((void *)&(args_info->align_rootfs_flag), 0, &(args_info->align_rootfs_given),
+                &(local_args_info.align_rootfs_given), optarg, 0, 0, ARG_FLAG,
+                check_ambiguity, override, 1, 0, "align-rootfs", '-',
+                additional_error))
+              goto failure;
+          
+          }
+          
+          break;
+        case '?':	/* Invalid option.  */
+          /* `getopt_long' already printed an error message.  */
+          goto failure;
+
+        default:	/* bug: option not considered.  */
+          fprintf (stderr, "%s: option unknown: %c%s\n", IMAGETAG_CMDLINE_PACKAGE, c, (additional_error ? additional_error : ""));
+          abort ();
+        } /* switch */
+    } /* while */
+
+
+
+  if (check_required)
+    {
+      error += imagetag_cmdline_required2 (args_info, argv[0], additional_error);
+    }
+
+  imagetag_cmdline_release (&local_args_info);
+
+  if ( error )
+    return (EXIT_FAILURE);
+
+  return 0;
+
+failure:
+  
+  imagetag_cmdline_release (&local_args_info);
+  return (EXIT_FAILURE);
+}
diff --git a/tools/firmware-utils/src/imagetag_cmdline.h b/tools/firmware-utils/src/imagetag_cmdline.h
new file mode 100644
index 0000000000..3f55c509bb
--- /dev/null
+++ b/tools/firmware-utils/src/imagetag_cmdline.h
@@ -0,0 +1,275 @@
+/** @file imagetag_cmdline.h
+ *  @brief The header file for the command line option parser
+ *  generated by GNU Gengetopt version 2.22.5
+ *  http://www.gnu.org/software/gengetopt.
+ *  DO NOT modify this file, since it can be overwritten
+ *  @author GNU Gengetopt by Lorenzo Bettini */
+
+#ifndef IMAGETAG_CMDLINE_H
+#define IMAGETAG_CMDLINE_H
+
+/* If we use autoconf.  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h> /* for FILE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef IMAGETAG_CMDLINE_PACKAGE
+/** @brief the program name (used for printing errors) */
+#define IMAGETAG_CMDLINE_PACKAGE "imagetag"
+#endif
+
+#ifndef IMAGETAG_CMDLINE_PACKAGE_NAME
+/** @brief the complete program name (used for help and version) */
+#define IMAGETAG_CMDLINE_PACKAGE_NAME "imagetag"
+#endif
+
+#ifndef IMAGETAG_CMDLINE_VERSION
+/** @brief the program version */
+#define IMAGETAG_CMDLINE_VERSION "2.0.0"
+#endif
+
+/** @brief Where the command line options are stored */
+struct gengetopt_args_info
+{
+  const char *help_help; /**< @brief Print help and exit help description.  */
+  const char *version_help; /**< @brief Print version and exit help description.  */
+  char * kernel_arg;	/**< @brief File with LZMA compressed kernel to include in the image..  */
+  char * kernel_orig;	/**< @brief File with LZMA compressed kernel to include in the image. original value given at command line.  */
+  const char *kernel_help; /**< @brief File with LZMA compressed kernel to include in the image. help description.  */
+  char * rootfs_arg;	/**< @brief File with RootFS to include in the image..  */
+  char * rootfs_orig;	/**< @brief File with RootFS to include in the image. original value given at command line.  */
+  const char *rootfs_help; /**< @brief File with RootFS to include in the image. help description.  */
+  char * output_arg;	/**< @brief Name of output file..  */
+  char * output_orig;	/**< @brief Name of output file. original value given at command line.  */
+  const char *output_help; /**< @brief Name of output file. help description.  */
+  char * cfe_arg;	/**< @brief File with CFE to include in the image..  */
+  char * cfe_orig;	/**< @brief File with CFE to include in the image. original value given at command line.  */
+  const char *cfe_help; /**< @brief File with CFE to include in the image. help description.  */
+  char * boardid_arg;	/**< @brief Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")..  */
+  char * boardid_orig;	/**< @brief Board ID to set in the image (must match what router expects, e.g. \"96345GW2\"). original value given at command line.  */
+  const char *boardid_help; /**< @brief Board ID to set in the image (must match what router expects, e.g. \"96345GW2\"). help description.  */
+  char * chipid_arg;	/**< @brief Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")..  */
+  char * chipid_orig;	/**< @brief Chip ID to set in the image (must match the actual hardware, e.g. \"6345\"). original value given at command line.  */
+  const char *chipid_help; /**< @brief Chip ID to set in the image (must match the actual hardware, e.g. \"6345\"). help description.  */
+  char * flash_start_arg;	/**< @brief Flash start address. (default='0xBFC00000').  */
+  char * flash_start_orig;	/**< @brief Flash start address. original value given at command line.  */
+  const char *flash_start_help; /**< @brief Flash start address. help description.  */
+  char * image_offset_arg;	/**< @brief Offset from start address for the first byte after the CFE (in memory). (default='0x10000').  */
+  char * image_offset_orig;	/**< @brief Offset from start address for the first byte after the CFE (in memory). original value given at command line.  */
+  const char *image_offset_help; /**< @brief Offset from start address for the first byte after the CFE (in memory). help description.  */
+  char * tag_version_arg;	/**< @brief Version number for imagetag format. (default='6').  */
+  char * tag_version_orig;	/**< @brief Version number for imagetag format. original value given at command line.  */
+  const char *tag_version_help; /**< @brief Version number for imagetag format. help description.  */
+  char * signature_arg;	/**< @brief Magic string (signature), for boards that need it. (default='Broadcom Corporatio').  */
+  char * signature_orig;	/**< @brief Magic string (signature), for boards that need it. original value given at command line.  */
+  const char *signature_help; /**< @brief Magic string (signature), for boards that need it. help description.  */
+  char * signature2_arg;	/**< @brief Second magic string (signature2). (default='ver. 2.0').  */
+  char * signature2_orig;	/**< @brief Second magic string (signature2). original value given at command line.  */
+  const char *signature2_help; /**< @brief Second magic string (signature2). help description.  */
+  char * block_size_arg;	/**< @brief Flash erase block size. (default='0x10000').  */
+  char * block_size_orig;	/**< @brief Flash erase block size. original value given at command line.  */
+  const char *block_size_help; /**< @brief Flash erase block size. help description.  */
+  char * load_addr_arg;	/**< @brief Kernel load address..  */
+  char * load_addr_orig;	/**< @brief Kernel load address. original value given at command line.  */
+  const char *load_addr_help; /**< @brief Kernel load address. help description.  */
+  char * entry_arg;	/**< @brief Address where the kernel entry point will be for booting..  */
+  char * entry_orig;	/**< @brief Address where the kernel entry point will be for booting. original value given at command line.  */
+  const char *entry_help; /**< @brief Address where the kernel entry point will be for booting. help description.  */
+  char * layoutver_arg;	/**< @brief Flash layout version (version 2.2x of the Broadcom code requires this)..  */
+  char * layoutver_orig;	/**< @brief Flash layout version (version 2.2x of the Broadcom code requires this). original value given at command line.  */
+  const char *layoutver_help; /**< @brief Flash layout version (version 2.2x of the Broadcom code requires this). help description.  */
+  char * info1_arg;	/**< @brief String for first vendor information section..  */
+  char * info1_orig;	/**< @brief String for first vendor information section. original value given at command line.  */
+  const char *info1_help; /**< @brief String for first vendor information section. help description.  */
+  char * altinfo_arg;	/**< @brief String for vendor information section (alternate/pirelli)..  */
+  char * altinfo_orig;	/**< @brief String for vendor information section (alternate/pirelli). original value given at command line.  */
+  const char *altinfo_help; /**< @brief String for vendor information section (alternate/pirelli). help description.  */
+  char * info2_arg;	/**< @brief String for second vendor information section..  */
+  char * info2_orig;	/**< @brief String for second vendor information section. original value given at command line.  */
+  const char *info2_help; /**< @brief String for second vendor information section. help description.  */
+  int root_first_flag;	/**< @brief Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory). (default=off).  */
+  const char *root_first_help; /**< @brief Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory). help description.  */
+  char * rsa_signature_arg;	/**< @brief String for RSA Signature section..  */
+  char * rsa_signature_orig;	/**< @brief String for RSA Signature section. original value given at command line.  */
+  const char *rsa_signature_help; /**< @brief String for RSA Signature section. help description.  */
+  char * second_image_flag_arg;	/**< @brief Dual Image Flag (2=not-specified). (default='2').  */
+  char * second_image_flag_orig;	/**< @brief Dual Image Flag (2=not-specified). original value given at command line.  */
+  const char *second_image_flag_help; /**< @brief Dual Image Flag (2=not-specified). help description.  */
+  char * inactive_arg;	/**< @brief Inactive Flag (2=not-specified). (default='2').  */
+  char * inactive_orig;	/**< @brief Inactive Flag (2=not-specified). original value given at command line.  */
+  const char *inactive_help; /**< @brief Inactive Flag (2=not-specified). help description.  */
+  char * reserved2_arg;	/**< @brief String for second reserved section..  */
+  char * reserved2_orig;	/**< @brief String for second reserved section. original value given at command line.  */
+  const char *reserved2_help; /**< @brief String for second reserved section. help description.  */
+  int kernel_file_has_header_flag;	/**< @brief Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed (default=off).  */
+  const char *kernel_file_has_header_help; /**< @brief Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed help description.  */
+  int pad_arg;	/**< @brief Pad the image to this size if smaller (in MiB).  */
+  char * pad_orig;	/**< @brief Pad the image to this size if smaller (in MiB) original value given at command line.  */
+  const char *pad_help; /**< @brief Pad the image to this size if smaller (in MiB) help description.  */
+  int align_rootfs_flag;	/**< @brief Align the rootfs start to erase block size (default=off).  */
+  const char *align_rootfs_help; /**< @brief Align the rootfs start to erase block size help description.  */
+  
+  unsigned int help_given ;	/**< @brief Whether help was given.  */
+  unsigned int version_given ;	/**< @brief Whether version was given.  */
+  unsigned int kernel_given ;	/**< @brief Whether kernel was given.  */
+  unsigned int rootfs_given ;	/**< @brief Whether rootfs was given.  */
+  unsigned int output_given ;	/**< @brief Whether output was given.  */
+  unsigned int cfe_given ;	/**< @brief Whether cfe was given.  */
+  unsigned int boardid_given ;	/**< @brief Whether boardid was given.  */
+  unsigned int chipid_given ;	/**< @brief Whether chipid was given.  */
+  unsigned int flash_start_given ;	/**< @brief Whether flash-start was given.  */
+  unsigned int image_offset_given ;	/**< @brief Whether image-offset was given.  */
+  unsigned int tag_version_given ;	/**< @brief Whether tag-version was given.  */
+  unsigned int signature_given ;	/**< @brief Whether signature was given.  */
+  unsigned int signature2_given ;	/**< @brief Whether signature2 was given.  */
+  unsigned int block_size_given ;	/**< @brief Whether block-size was given.  */
+  unsigned int load_addr_given ;	/**< @brief Whether load-addr was given.  */
+  unsigned int entry_given ;	/**< @brief Whether entry was given.  */
+  unsigned int layoutver_given ;	/**< @brief Whether layoutver was given.  */
+  unsigned int info1_given ;	/**< @brief Whether info1 was given.  */
+  unsigned int altinfo_given ;	/**< @brief Whether altinfo was given.  */
+  unsigned int info2_given ;	/**< @brief Whether info2 was given.  */
+  unsigned int root_first_given ;	/**< @brief Whether root-first was given.  */
+  unsigned int rsa_signature_given ;	/**< @brief Whether rsa-signature was given.  */
+  unsigned int second_image_flag_given ;	/**< @brief Whether second-image-flag was given.  */
+  unsigned int inactive_given ;	/**< @brief Whether inactive was given.  */
+  unsigned int reserved2_given ;	/**< @brief Whether reserved2 was given.  */
+  unsigned int kernel_file_has_header_given ;	/**< @brief Whether kernel-file-has-header was given.  */
+  unsigned int pad_given ;	/**< @brief Whether pad was given.  */
+  unsigned int align_rootfs_given ;	/**< @brief Whether align-rootfs was given.  */
+
+} ;
+
+/** @brief The additional parameters to pass to parser functions */
+struct imagetag_cmdline_params
+{
+  int override; /**< @brief whether to override possibly already present options (default 0) */
+  int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
+  int check_required; /**< @brief whether to check that all required options were provided (default 1) */
+  int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
+  int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
+} ;
+
+/** @brief the purpose string of the program */
+extern const char *gengetopt_args_info_purpose;
+/** @brief the usage string of the program */
+extern const char *gengetopt_args_info_usage;
+/** @brief all the lines making the help output */
+extern const char *gengetopt_args_info_help[];
+
+/**
+ * The command line parser
+ * @param argc the number of command line options
+ * @param argv the command line options
+ * @param args_info the structure where option information will be stored
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline (int argc, char **argv,
+  struct gengetopt_args_info *args_info);
+
+/**
+ * The command line parser (version with additional parameters - deprecated)
+ * @param argc the number of command line options
+ * @param argv the command line options
+ * @param args_info the structure where option information will be stored
+ * @param override whether to override possibly already present options
+ * @param initialize whether to initialize the option structure my_args_info
+ * @param check_required whether to check that all required options were provided
+ * @return 0 if everything went fine, NON 0 if an error took place
+ * @deprecated use imagetag_cmdline_ext() instead
+ */
+int imagetag_cmdline2 (int argc, char **argv,
+  struct gengetopt_args_info *args_info,
+  int override, int initialize, int check_required);
+
+/**
+ * The command line parser (version with additional parameters)
+ * @param argc the number of command line options
+ * @param argv the command line options
+ * @param args_info the structure where option information will be stored
+ * @param params additional parameters for the parser
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline_ext (int argc, char **argv,
+  struct gengetopt_args_info *args_info,
+  struct imagetag_cmdline_params *params);
+
+/**
+ * Save the contents of the option struct into an already open FILE stream.
+ * @param outfile the stream where to dump options
+ * @param args_info the option struct to dump
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline_dump(FILE *outfile,
+  struct gengetopt_args_info *args_info);
+
+/**
+ * Save the contents of the option struct into a (text) file.
+ * This file can be read by the config file parser (if generated by gengetopt)
+ * @param filename the file where to save
+ * @param args_info the option struct to save
+ * @return 0 if everything went fine, NON 0 if an error took place
+ */
+int imagetag_cmdline_file_save(const char *filename,
+  struct gengetopt_args_info *args_info);
+
+/**
+ * Print the help
+ */
+void imagetag_cmdline_print_help(void);
+/**
+ * Print the version
+ */
+void imagetag_cmdline_print_version(void);
+
+/**
+ * Initializes all the fields a imagetag_cmdline_params structure 
+ * to their default values
+ * @param params the structure to initialize
+ */
+void imagetag_cmdline_params_init(struct imagetag_cmdline_params *params);
+
+/**
+ * Allocates dynamically a imagetag_cmdline_params structure and initializes
+ * all its fields to their default values
+ * @return the created and initialized imagetag_cmdline_params structure
+ */
+struct imagetag_cmdline_params *imagetag_cmdline_params_create(void);
+
+/**
+ * Initializes the passed gengetopt_args_info structure's fields
+ * (also set default values for options that have a default)
+ * @param args_info the structure to initialize
+ */
+void imagetag_cmdline_init (struct gengetopt_args_info *args_info);
+/**
+ * Deallocates the string fields of the gengetopt_args_info structure
+ * (but does not deallocate the structure itself)
+ * @param args_info the structure to deallocate
+ */
+void imagetag_cmdline_free (struct gengetopt_args_info *args_info);
+
+/**
+ * Checks that all the required options were specified
+ * @param args_info the structure to check
+ * @param prog_name the name of the program that will be used to print
+ *   possible errors
+ * @return
+ */
+int imagetag_cmdline_required (struct gengetopt_args_info *args_info,
+  const char *prog_name);
+
+extern const char *imagetag_cmdline_second_image_flag_values[];  /**< @brief Possible values for second-image-flag. */
+extern const char *imagetag_cmdline_inactive_values[];  /**< @brief Possible values for inactive. */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* IMAGETAG_CMDLINE_H */
diff --git a/tools/firmware-utils/src/jcgimage.c b/tools/firmware-utils/src/jcgimage.c
new file mode 100644
index 0000000000..7755eab1ed
--- /dev/null
+++ b/tools/firmware-utils/src/jcgimage.c
@@ -0,0 +1,403 @@
+/*
+ * jcgimage - Create a JCG firmware image
+ *
+ * Copyright (C) 2015 Reinhard Max <reinhard@m4x.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/*
+ * JCG firmware update images consist of a 512 byte header and a
+ * modified uImage (details below) as the payload.
+ *
+ * The payload is obfuscated by XORing it with a key that is generated
+ * from parts of the header. Fortunately only non-essential parts of
+ * the header are used for this and zeroing them results in a zero
+ * key, effectively disabling the obfuscation and allowing us to use
+ * clear text payloads.
+ *
+ * The mandatory parts of the header are:
+ *
+ * - A magic string of "YSZJ" at offset 0.
+ * - A value of 1 at offset 39 (header format version?)
+ * - A CRC32 checksum of the payload at offset 504.
+ * - A CRC32 checksum of the header at offset 508.
+ *
+ * An image constructed by these rules will be accepted by JCG's
+ * U-Boot in resuce mode via TFTP and the payload will be written to
+ * the flash starting at offset 0x00050000.
+ *
+ * JCG's U-Boot does check the content or size of the payload
+ * image. If it is too large, it wraps around and overwrites U-Boot,
+ * requiring JTAG to revive the board. To prevent such bricking from
+ * happening, this tool refuses to build such overlong images.
+ *
+ * Two more conditions have to be met for a JCG image to be accepted
+ * as a valid update by the web interface of the stock firware:
+ *
+ *   - The bytes at offsets 109 and 111 in the header must be a binary
+ *   representation of the first two components of the firmware
+ *   version as displayed in the update web form, or it will be
+ *   rejected as "incorrect product".
+ *
+ *   - The payload must start with a valid uImage header whose data
+ *   CRC checksum matches the whole rest of the update file rather
+ *   than just the number of bytes specified in the size field of the
+ *   header.
+ *
+ * This last condition is met by JCG's original firmware images,
+ * because they have both, kernel and rootfs inside the uImage and
+ * abuse the last four bytes of the name field to record the offset of
+ * the file system from the start of the uImage header. This tool
+ * produces such images when called with -k and -r, which are meant to
+ * repack the original firmware after modifying the file systen,
+ * e.g. to add debugging tools and enable shell access.
+ *
+ * In contrast, OpenWrt sysupgrade images consist of a uImage that
+ * only contains the kernel and has the rootfs appended to it. Hence,
+ * the CRC over kernel and file system does not match the one in the
+ * uImage header. Fixing this by adjusting the uImage header is not
+ * possible, because it makes the uImage unusable for booting. Instead
+ * we append four "patch" bytes to the end of the file system, that
+ * are calculated to force the checksum of kernel+fs to be the same as
+ * for the kernel alone.
+ *
+ */
+
+#include <zlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+/*
+ * JCG Firmware image header
+ */
+#define JH_MAGIC 0x59535a4a        /* "YSZJ" */
+struct jcg_header {
+	uint32_t jh_magic;
+	uint8_t  jh_version[32];   /* Firmware version string.
+				      Fill with zeros to avoid encryption  */
+	uint32_t jh_type;          /* must be 1                            */
+	uint8_t  jh_info[64];      /* Firmware info string. Fill with
+				      zeros to avoid encryption            */
+	uint32_t jh_time;          /* Image creation time in seconds since
+				    * the Epoch. Does not seem to be used
+				    * by the stock firmware.               */
+	uint16_t jh_major;         /* Major fimware version                */
+	uint16_t jh_minor;         /* Minor fimrmware version              */
+	uint8_t  jh_unknown[392];  /* Apparently unused and all zeros      */
+	uint32_t jh_dcrc;          /* CRC checksum of the payload          */
+	uint32_t jh_hcrc;          /* CRC checksum of the header           */
+};
+
+/*
+ * JCG uses a modified uImage header that replaces the last four bytes
+ * of the image name with the length of the kernel in the image.
+ */
+#define IH_MAGIC    0x27051956    /* Image Magic Number     */
+#define IH_NMLEN    28            /* Image Name Length      */
+
+struct uimage_header {
+	uint32_t    ih_magic;         /* Image Header Magic Number   */
+	uint32_t    ih_hcrc;          /* Image Header CRC Checksum   */
+	uint32_t    ih_time;          /* Image Creation Timestamp    */
+	uint32_t    ih_size;          /* Image Data Size             */
+	uint32_t    ih_load;          /* Data     Load  Address      */
+	uint32_t    ih_ep;            /* Entry Point Address         */
+	uint32_t    ih_dcrc;          /* Image Data CRC Checksum     */
+	uint8_t     ih_os;            /* Operating System            */
+	uint8_t     ih_arch;          /* CPU architecture            */
+	uint8_t     ih_type;          /* Image Type                  */
+	uint8_t     ih_comp;          /* Compression Type            */
+	uint8_t     ih_name[IH_NMLEN];/* Image Name                  */
+	uint32_t    ih_fsoff;         /* Offset of the file system
+					 partition from the start of
+					 the header                  */
+};
+
+/*
+ * Open the named file and return its size and file descriptor.
+ * Exit in case of errors.
+ */
+int
+opensize(char *name, size_t *size)
+{
+	struct stat s;
+	int fd = open(name, O_RDONLY);
+	if (fd < 0) {
+		err(1, "cannot open \"%s\"", name);
+	}
+	if (fstat(fd, &s) == -1) {
+		err(1, "cannot stat \"%s\"", name);
+	}
+	*size = s.st_size;
+	return fd;
+}
+
+/*
+ * Write the JCG header
+ */
+void
+mkjcgheader(struct jcg_header *h, size_t psize, char *version)
+{
+	uLong crc;
+	uint16_t major = 0, minor = 0;
+	void *payload = (void *)h + sizeof(*h);
+
+	if (version != NULL) {
+		if (sscanf(version, "%hu.%hu", &major, &minor) != 2) {
+			err(1, "cannot parse version \"%s\"", version);
+		}
+	}
+
+	memset(h, 0, sizeof(*h));
+	h->jh_magic = htonl(JH_MAGIC);
+	h->jh_type  = htonl(1);
+	h->jh_time  = htonl(time(NULL));
+	h->jh_major = htons(major);
+	h->jh_minor = htons(minor);
+
+	/* CRC over JCG payload (uImage) */
+	crc = crc32(0L, Z_NULL, 0);
+	crc = crc32(crc, payload, psize);
+	h->jh_dcrc  = htonl(crc);
+
+	/* CRC over JCG header */
+	crc = crc32(0L, Z_NULL, 0);
+	crc = crc32(crc, (void *)h, sizeof(*h));
+	h->jh_hcrc  = htonl(crc);
+}
+
+/*
+ * Write the uImage header
+ */
+void
+mkuheader(struct uimage_header *h, size_t ksize, size_t fsize)
+{
+	uLong crc;
+	void *payload = (void *)h + sizeof(*h);
+
+	// printf("mkuheader: %p, %zd, %zd\n", h, ksize, fsize);
+	memset(h, 0, sizeof(*h));
+	h->ih_magic = htonl(IH_MAGIC);
+	h->ih_time  = htonl(time(NULL));
+	h->ih_size  = htonl(ksize + fsize);
+	h->ih_load  = htonl(0x80000000);
+	h->ih_ep    = htonl(0x80292000);
+	h->ih_os    = 0x05;
+	h->ih_arch  = 0x05;
+	h->ih_type  = 0x02;
+	h->ih_comp  = 0x03;
+	h->ih_fsoff = htonl(sizeof(*h) + ksize);
+	strcpy((char *)h->ih_name, "Linux Kernel Image");
+
+	/* CRC over uImage payload (kernel and file system) */
+	crc = crc32(0L, Z_NULL, 0);
+	crc = crc32(crc, payload, ntohl(h->ih_size));
+	h->ih_dcrc  = htonl(crc);
+	printf("CRC1: %08lx\n", crc);
+
+	/* CRC over uImage header */
+	crc = crc32(0L, Z_NULL, 0);
+	crc = crc32(crc, (void *)h, sizeof(*h));
+	h->ih_hcrc  = htonl(crc);
+	printf("CRC2: %08lx\n", crc);
+}
+
+/*
+ * Calculate a "patch" value and write it into the last four bytes of
+ * buf, so that the CRC32 checksum of the whole buffer is dcrc.
+ *
+ * Based on: SAR-PR-2006-05: Reversing CRC – Theory and Practice.
+ * Martin Stigge, Henryk Plötz, Wolf Müller, Jens-Peter Redlich.
+ * http://sar.informatik.hu-berlin.de/research/publications/#SAR-PR-2006-05
+ */
+void
+craftcrc(uint32_t dcrc, uint8_t *buf, size_t len)
+{
+	int i;
+	uint32_t a;
+	uint32_t patch = 0;
+	uint32_t crc = crc32(0L, Z_NULL, 0);
+
+	a = ~dcrc;
+	for (i = 0; i < 32; i++) {
+		if (patch & 1) {
+			patch = (patch >> 1) ^ 0xedb88320L;
+		} else {
+			patch >>= 1;
+		}
+		if (a & 1) {
+			patch ^= 0x5b358fd3L;
+		}
+		a >>= 1;
+	}
+	patch ^= ~crc32(crc, buf, len - 4);
+	for (i = 0; i < 4; i++) {
+		buf[len - 4 + i] = patch & 0xff;
+		patch >>= 8;
+	}
+	/* Verify that we actually get the desired result */
+	crc = crc32(0L, Z_NULL, 0);
+	crc = crc32(crc, buf, len);
+	if (crc != dcrc) {
+		errx(1, "CRC patching is broken: wanted %08x, but got %08x.",
+		     dcrc, crc);
+	}
+}
+
+void
+usage() {
+	fprintf(stderr, "Usage:\n"
+		"jcgimage -o outfile -u uImage [-v version]\n"
+		"jcgimage -o outfile -k kernel -f rootfs [-v version]\n");
+	exit(1);
+}
+
+#define MODE_UNKNOWN 0
+#define MODE_UIMAGE 1
+#define MODE_KR 2
+
+/* The output image must not be larger than 4MiB - 5*64kiB */
+#define MAXSIZE (size_t)(4 * 1024 * 1024 - 5 * 64 * 1024)
+
+int
+main(int argc, char **argv)
+{
+	struct jcg_header *jh;
+	struct uimage_header *uh;
+	int c;
+	char *imagefile = NULL;
+	char *file1 = NULL;
+	char *file2 = NULL;
+	char *version = NULL;
+	int mode = MODE_UNKNOWN;
+	int fdo, fd1, fd2;
+	size_t size1, size2, sizeu, sizeo, off1, off2;
+	void *map;
+
+	/* Make sure the headers have the right size */
+	assert(sizeof(struct jcg_header) == 512);
+	assert(sizeof(struct uimage_header) == 64);
+
+	while ((c = getopt(argc, argv, "o:k:f:u:v:h")) != -1) {
+		switch (c) {
+		case 'o':
+			imagefile = optarg;
+			break;
+		case 'k':
+			if (mode == MODE_UIMAGE) {
+				errx(1,"-k cannot be combined with -u");
+			}
+			mode = MODE_KR;
+			file1 = optarg;
+			break;
+		case 'f':
+			if (mode == MODE_UIMAGE) {
+				errx(1,"-f cannot be combined with -u");
+			}
+			mode = MODE_KR;
+			file2 = optarg;
+			break;
+		case 'u':
+			if (mode == MODE_KR) {
+				errx(1,"-u cannot be combined with -k and -r");
+			}
+			mode = MODE_UIMAGE;
+			file1 = optarg;
+			break;
+		case 'v':
+			version = optarg;
+			break;
+		case 'h':
+		default:
+			usage();
+		}
+	}
+	if (optind != argc) {
+		errx(1, "illegal arg \"%s\"", argv[optind]);
+	}
+	if (imagefile == NULL) {
+		errx(1, "no output file specified");
+	}
+	if (mode == MODE_UNKNOWN) {
+		errx(1, "specify either -u or -k and -r");
+	}
+	if (mode == MODE_KR) {
+		if (file1 == NULL || file2 == NULL) {
+			errx(1,"need -k and -r");
+		}
+		fd2 = opensize(file2, &size2);
+	}
+	fd1 = opensize(file1, &size1);
+	if (mode == MODE_UIMAGE) {
+		off1 = sizeof(*jh);
+		sizeu = size1 + 4;
+		sizeo = sizeof(*jh) + sizeu;
+	} else {
+		off1 = sizeof(*jh) + sizeof(*uh);
+		off2 = sizeof(*jh) + sizeof(*uh) + size1;
+		sizeu = sizeof(*uh) + size1 + size2;
+		sizeo = sizeof(*jh) + sizeu;
+	}
+
+	if (sizeo > MAXSIZE) {
+		errx(1,"payload too large: %zd > %zd\n", sizeo, MAXSIZE);
+	}
+
+	fdo = open(imagefile, O_RDWR | O_CREAT | O_TRUNC, 00644);
+	if (fdo < 0) {
+		err(1, "cannot open \"%s\"", imagefile);
+	}
+
+	if (ftruncate(fdo, sizeo) == -1) {
+		err(1, "cannot grow \"%s\" to %zd bytes", imagefile, sizeo);
+	}
+	map = mmap(NULL, sizeo, PROT_READ|PROT_WRITE, MAP_SHARED, fdo, 0);
+	uh = map + sizeof(*jh);
+	if (map == MAP_FAILED) {
+		err(1, "cannot mmap \"%s\"", imagefile);
+	}
+
+	if (read(fd1, map + off1, size1) != size1) {
+		err(1, "cannot copy %s", file1);
+	}
+
+	if (mode == MODE_KR) {
+		if (read(fd2, map+off2, size2) != size2) {
+			err(1, "cannot copy %s", file2);
+		}
+		mkuheader(uh, size1, size2);
+	} else if (mode == MODE_UIMAGE) {
+		craftcrc(ntohl(uh->ih_dcrc), (void*)uh + sizeof(*uh),
+			 sizeu - sizeof(*uh));
+	}
+	mkjcgheader(map, sizeu, version);
+	munmap(map, sizeo);
+	close(fdo);
+	return 0;
+}
diff --git a/tools/firmware-utils/src/lzma2eva.c b/tools/firmware-utils/src/lzma2eva.c
new file mode 100644
index 0000000000..1d7e364889
--- /dev/null
+++ b/tools/firmware-utils/src/lzma2eva.c
@@ -0,0 +1,190 @@
+/*
+    lzma2eva - convert lzma-compressed file to AVM EVA bootloader format
+    Copyright (C) 2007  Enrik Berkhan <Enrik.Berkhan@inka.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+*/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h> /* crc32 */
+
+#define checksum_add32(csum, data) \
+  csum += ((uint8_t *)&data)[0]; \
+  csum += ((uint8_t *)&data)[1]; \
+  csum += ((uint8_t *)&data)[2]; \
+  csum += ((uint8_t *)&data)[3];
+
+void
+usage(void)
+{
+  fprintf(stderr, "usage: lzma2eva <loadadddr> <entry> <lzmafile> <evafile>\n");
+  exit(1);
+}
+
+void
+pexit(const char *msg)
+{
+  perror(msg);
+  exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+  const char *infile, *outfile;
+  FILE *in, *out;
+  static uint8_t buf[4096];
+  size_t elems;
+
+  uint8_t properties;
+  uint32_t dictsize;
+  uint64_t datasize;
+
+  uint32_t magic = 0xfeed1281L;
+  uint32_t reclength = 0;
+  fpos_t reclengthpos;
+  uint32_t loadaddress = 0;
+  uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */
+  uint32_t checksum = 0;
+
+  uint32_t compsize = 0;
+  fpos_t compsizepos;
+  uint32_t datasize32 = 0;
+  uint32_t datacrc32 = crc32(0, 0, 0);
+
+  uint32_t zero = 0;
+  uint32_t entry = 0;
+
+  if (argc != 5)
+    usage();
+
+  /* "parse" command line */
+  loadaddress = strtoul(argv[1], 0, 0);
+  entry = strtoul(argv[2], 0, 0);
+  infile = argv[3];
+  outfile = argv[4];
+
+  in = fopen(infile, "rb");
+  if (!in)
+    pexit("fopen");
+  out = fopen(outfile, "w+b");
+  if (!out)
+    pexit("fopen");
+
+  /* read LZMA header */
+  if (1 != fread(&properties, sizeof properties, 1, in))
+    pexit("fread");
+  if (1 != fread(&dictsize, sizeof dictsize, 1, in))
+    pexit("fread");
+  if (1 != fread(&datasize, sizeof datasize, 1, in))
+    pexit("fread");
+
+  /* write EVA header */
+  if (1 != fwrite(&magic, sizeof magic, 1, out))
+    pexit("fwrite");
+  if (fgetpos(out, &reclengthpos))
+    pexit("fgetpos");
+  if (1 != fwrite(&reclength, sizeof reclength, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&loadaddress, sizeof loadaddress, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&type, sizeof type, 1, out))
+    pexit("fwrite");
+
+  /* write EVA LZMA header */
+  if (fgetpos(out, &compsizepos))
+    pexit("fgetpos");
+  if (1 != fwrite(&compsize, sizeof compsize, 1, out))
+    pexit("fwrite");
+  /* XXX check length */
+  datasize32 = (uint32_t)datasize;
+  if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
+    pexit("fwrite");
+
+  /* write modified LZMA header */
+  if (1 != fwrite(&properties, sizeof properties, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&dictsize, sizeof dictsize, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&zero, 3, 1, out))
+    pexit("fwrite");
+
+  /* copy compressed data, calculate crc32 */
+  while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) {
+    compsize += elems;
+    if (elems != fwrite(&buf, sizeof buf[0], elems, out))
+      pexit("fwrite");
+    datacrc32 = crc32(datacrc32, buf, elems);
+  }
+  if (ferror(in))
+    pexit("fread");
+  fclose(in);
+
+  /* re-write record length */
+  reclength = compsize + 24;
+  if (fsetpos(out, &reclengthpos))
+    pexit("fsetpos");
+  if (1 != fwrite(&reclength, sizeof reclength, 1, out))
+    pexit("fwrite");
+
+  /* re-write EVA LZMA header including size and data crc */
+  if (fsetpos(out, &compsizepos))
+    pexit("fsetpos");
+  if (1 != fwrite(&compsize, sizeof compsize, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
+    pexit("fwrite");
+
+  /* calculate record checksum */
+  checksum += reclength;
+  checksum += loadaddress;
+  checksum_add32(checksum, type);
+  checksum_add32(checksum, compsize);
+  checksum_add32(checksum, datasize32);
+  checksum_add32(checksum, datacrc32);
+  if (fseek(out, 0, SEEK_CUR))
+    pexit("fseek");
+  while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) {
+    size_t i;
+    for (i = 0; i < elems; ++i)
+      checksum += buf[i];
+  }
+  if (ferror(out))
+    pexit("fread");
+  if (fseek(out, 0, SEEK_CUR))
+    pexit("fseek");
+
+  checksum = ~checksum + 1;
+  if (1 != fwrite(&checksum, sizeof checksum, 1, out))
+    pexit("fwrite");
+
+  /* write entry record */
+  if (1 != fwrite(&zero, sizeof zero, 1, out))
+    pexit("fwrite");
+  if (1 != fwrite(&entry, sizeof entry, 1, out))
+    pexit("fwrite");
+
+  if (fclose(out))
+    pexit("fclose");
+
+  return 0;
+}
diff --git a/tools/firmware-utils/src/makeamitbin.c b/tools/firmware-utils/src/makeamitbin.c
new file mode 100644
index 0000000000..5c334424e6
--- /dev/null
+++ b/tools/firmware-utils/src/makeamitbin.c
@@ -0,0 +1,316 @@
+/*
+ *  makeamitbin - create firmware binaries for MGB100
+ *
+ *  Copyright (C) 2007 Volker Weiss     <dev@tintuc.de>
+ *                     Christian Welzel <dev@welzel-online.ch>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/* defaults: Level One WAP-0007 */
+static char *ascii1 = "DDC_RUS001";
+static char *ascii2 = "Queen";
+
+static struct hdrinfo {
+  char *name;
+	unsigned long unknown; /* can probably be any number, maybe version number */
+	int topalign;
+	unsigned int addr;
+	unsigned int size;
+} hdrinfo[] = {
+	{ "bios", 0xc76be111, 1, 0x3fa000, 0x006000 },        /* BIOS */
+	{ "recovery", 0xc76be222, 0, 0x3f0000, 0x004000 },    /* Recovery Loader */
+	{ "linux", 0xc76bee9d, 0, 0x000000, 0x100000 },       /* Linux */
+	{ "ramdisk", 0xc76bee9d, 0, 0x100000, 0x280000 },     /* ramdisk */
+	{ "amitconfig", 0xc76bee8b, 0, 0x380000, 0x060000 },  /* AMIT config */
+	{ "redboot", 0x00000000, 1, 0x3d0000, 0x030000 },     /* Redboot 128kB image */
+	{ "redbootlow", 0, 0, 0x3e0000, 0x18000 },            /* Redboot 1. part */
+	{ "redboothigh", 0, 0, 0x3fa000, 0x6000 },            /* Redboot 2. part */
+	{ "linux3g", 0xcb5f06b5, 0, 0x000000, 0x100000 },       /* Linux */
+	{ "ramdisk3g", 0xcb5f06b5, 0, 0x100000, 0x280000 },     /* ramdisk */
+	{ NULL }
+};
+
+/*
+CHD2WLANU_R400b7
+
+11e1 6bc7
+22e2 6bc7
+5dc3 47c8
+5cc3 47c8
+21c3 47c8
+*/
+
+/*
+20060106_DDC_WAP-0007_R400b4
+
+11e1 6bc7
+22e2 6bc7
+9dee 6bc7
+9dee 6bc7
+8bee 6bc7
+*/
+
+/*
+WMU-6000FS_R400b6
+
+11e1 6bc7
+22e2 6bc7
+6d2d 0fc8
+6c2d 0fc8
+542d 0fc8
+*/
+
+/*
+WAP-0007(R4.00b8)_2006-10-02
+
+9979 5fc8
+22e2 6bc7
+c46e cec8
+c36e cec8
+a76e cec8
+*/
+
+
+
+#define HDRSIZE              80
+
+#define COPY_SHORT(d, o, v)  d[o+0] = (unsigned char)((v) & 0xff); \
+                             d[o+1] = (unsigned char)(((v) >> 8) & 0xff)
+#define COPY_LONG(d, o, v)   d[o+0] = (unsigned char)((v) & 0xff); \
+                             d[o+1] = (unsigned char)(((v) >> 8) & 0xff); \
+													   d[o+2] = (unsigned char)(((v) >> 16) & 0xff); \
+													   d[o+3] = (unsigned char)(((v) >> 24) & 0xff)
+#define READ_SHORT(d, o)     ((unsigned short)(d[o+0]) + \
+                             (((unsigned short)(d[o+1])) << 8))
+
+/*
+00..0d ASCII product ID
+0e..0f checksum of payload
+10..1b ASCII Queen
+1c..1f AMIT BIOS: 11e1 6bc7, Recovery Tool: 22e2 6bc7
+       Linux: 5dc3 47c8, ramdisk: 5cc3 47c8
+			 AMIT FS: 21c3 47c8    VERSION NUMBER??????
+20..23 offset in flash aligned to segment boundary
+24..27 length in flash aligned to segment boundary
+28..2b offset in flash (payload)
+2c..2f length (payload)
+30..3f always 0
+40..47 always 4248 0101 5000 0001 (last maybe .....0501)
+48..4b same as 20..23
+4c..4d always 0b00
+4e..4f inverted checksum of header
+*/
+
+unsigned short checksum(unsigned char *data, long size)
+{
+	long n;
+	unsigned short d, cs = 0;
+	for (n = 0; n < size; n += 2)
+	{
+		d = READ_SHORT(data, n);
+		cs += d;
+		if (cs < d)
+			cs++;
+	}
+	if (size & 1)
+	{
+		d = data[n];
+		cs += d;
+		if (cs < d)
+			cs++;
+	}
+	return cs;
+}
+
+void showhdr(unsigned char *hdr)
+{
+	int i, j;
+	for (j = 0; j < 5; j++)
+	{
+		for (i = 0; i < 16; i++)
+		{
+			printf("%02x ", (unsigned int)(hdr[j * 16 + i]));
+		}
+		printf("   ");
+		for (i = 0; i < 16; i++)
+		{
+			unsigned char d = hdr[j * 16 + i];
+			printf("%c", (d >= ' ' && d < 127) ? d : '.');
+		}
+		printf("\n");
+	}
+}
+
+void makehdr(unsigned char *hdr, struct hdrinfo *info,
+             unsigned char *data, long size, int last)
+{
+	unsigned int offset = info->addr + 0x10;
+	memset(hdr, 0, HDRSIZE);
+	if (info->topalign)
+		offset = info->addr + info->size - size;	/* top align */
+	strncpy((char *)hdr + 0x00, ascii1, 14);
+	strncpy((char *)hdr + 0x10, ascii2, 12);
+	COPY_LONG(hdr, 0x1c, info->unknown);
+	COPY_LONG(hdr, 0x20, info->addr);
+	COPY_LONG(hdr, 0x24, info->size);
+	COPY_LONG(hdr, 0x28, offset);
+	COPY_LONG(hdr, 0x2c, size);
+	COPY_LONG(hdr, 0x40, 0x01014842);
+	COPY_LONG(hdr, 0x44, last ? 0x01050050 : 0x01000050);
+	COPY_LONG(hdr, 0x48, info->addr);
+	COPY_SHORT(hdr, 0x4c, info->unknown == 0xcb5f06b5 ? 0x0016 : 0x000b);
+	COPY_SHORT(hdr, 0x0e, checksum(data, size));
+	COPY_SHORT(hdr, 0x4e, ~checksum(hdr, HDRSIZE));
+}
+
+unsigned char *read_file(const char *name, long *size)
+{
+	FILE *f;
+	unsigned char *data = NULL;
+	*size = 0;
+	f = fopen(name, "r");
+	if (f != NULL)
+	{
+		if (fseek(f, 0, SEEK_END) == 0)
+		{
+	    *size = ftell(f);
+			if (*size != -1)
+			{
+				if (fseek(f, 0, SEEK_SET) == 0)
+				{
+					data = (unsigned char *)malloc(*size);
+					if (data != NULL)
+					{
+						if (fread(data, sizeof(char), *size, f) != *size)
+						{
+							free(data);
+							data = NULL;
+						}
+					}
+				}
+			}
+		}
+		fclose(f);
+	}
+	return data;
+}
+
+struct hdrinfo *find_hdrinfo(const char *name)
+{
+	int n;
+	for (n = 0; hdrinfo[n].name != NULL; n++)
+	{
+		if (strcmp(name, hdrinfo[n].name) == 0)
+			return &hdrinfo[n];
+	}
+	return NULL;
+}
+
+void oferror(FILE *f)
+{
+	printf("file error\n");
+	exit(2);
+}
+
+void showhelp(void)
+{
+	printf("Syntax: makeamitbin [options]\n");
+	printf("Options:\n");
+	printf("  -1 ID1\tFirmware identifier 1, e.g. 'DDC_RUS001' for manufacturer LevelOne\n");
+	printf("  -2 ID2\tFirmware identifier 2, 'Queen' in all known cases\n");
+	printf("  -o FILE\tOutput file\n");
+	printf("  -ids\t\tShow a list of known firmware identifiers.\n");
+	exit(1);
+}
+
+void show_fwids(void)
+{
+	printf("List of known firmware identifiers:\n");
+	printf("Manufacturer\t\tProduct\t\tIdentifier\n");
+	printf("=====================================================\n");
+	printf("Conceptronic\t\tCHD2WLANU\tLLM_RUS001\n");
+	printf("Pearl\t\t\tPE6643\t\tQueen\n");
+	printf("Micronica\t\tMGB100\t\tQueen\n");
+	printf("LevelOne\t\tWAP-0007\tDDC_RUS001\n");
+	printf("SMC\t\t\tWAPS-G\t\tSMC_RUS001\n");
+	printf("OvisLink (AirLive)\tWMU-6\t\tOVS_RUS001\n");
+	printf("SafeCom SWSAPUR-5\tFMW\t\tSafeco_RPS001\n");
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned char hdr[HDRSIZE];
+	unsigned char *data;
+	FILE *of;
+	char *outfile = NULL;
+	char *type;
+	struct hdrinfo *info;
+	long size;
+	int last = 0;
+	int n;
+	for (n = 1; n < argc; n++)
+	{
+		if (strcmp(argv[n], "-1") == 0)
+			ascii1 = argv[n+1];
+		if (strcmp(argv[n], "-2") == 0)
+			ascii2 = argv[n+1];
+		if (strcmp(argv[n], "-o") == 0)
+			outfile = argv[n+1];
+		if (strcmp(argv[n], "-ids") == 0)
+			show_fwids();
+	}
+	if (ascii1 == NULL || ascii2 == NULL || outfile == NULL)
+		showhelp();
+	of = fopen(outfile, "w");
+	if (of == NULL)
+		oferror(of);
+	for (n = 1; n < argc; n++)
+	{
+		if (strncmp(argv[n], "-", 1) != 0)
+		{
+			type = argv[n++];
+			if (n >= argc)
+				showhelp();
+			last = ((n + 1) >= argc);		/* dirty, options first! */
+			info = find_hdrinfo(type);
+			if (info == NULL)
+				showhelp();
+			data = read_file(argv[n], &size);
+			if (data == NULL)
+				showhelp();
+			makehdr(hdr, info, data, size, last);
+			/* showhdr(hdr); */
+			if (fwrite(hdr, HDRSIZE, 1, of) != 1)
+				oferror(of);
+			if (fwrite(data, size, 1, of) != 1)
+				oferror(of);
+			free(data);
+		}
+		else
+			n++;
+	}
+	if (fclose(of) != 0)
+		oferror(NULL);
+	return 0;
+}
diff --git a/tools/firmware-utils/src/md5.c b/tools/firmware-utils/src/md5.c
new file mode 100644
index 0000000000..52d96accd3
--- /dev/null
+++ b/tools/firmware-utils/src/md5.c
@@ -0,0 +1,296 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's.  No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible.  Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#ifndef HAVE_OPENSSL
+
+#include <string.h>
+
+#include "md5.h"
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z)			((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)			((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z)			(((x) ^ (y)) ^ (z))
+#define H2(x, y, z)			((x) ^ ((y) ^ (z)))
+#define I(x, y, z)			((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+	(a) += f((b), (c), (d)) + (x) + (t); \
+	(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+	(a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+	(*(MD5_u32plus *)&ptr[(n) * 4])
+#define GET(n) \
+	SET(n)
+#else
+#define SET(n) \
+	(ctx->block[(n)] = \
+	(MD5_u32plus)ptr[(n) * 4] | \
+	((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+	((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+	((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+	(ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There are no alignment requirements.
+ */
+static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+	const unsigned char *ptr;
+	MD5_u32plus a, b, c, d;
+	MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+	ptr = (const unsigned char *)data;
+
+	a = ctx->a;
+	b = ctx->b;
+	c = ctx->c;
+	d = ctx->d;
+
+	do {
+		saved_a = a;
+		saved_b = b;
+		saved_c = c;
+		saved_d = d;
+
+/* Round 1 */
+		STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+		STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+		STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+		STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+		STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+		STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+		STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+		STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+		STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+		STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+		STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+		STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+		STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+		STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+		STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+		STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+		STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+		STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+		STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+		STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+		STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+		STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+		STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+		STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+		STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+		STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+		STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+		STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+		STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+		STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+		STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+		STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+		STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+		STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+		STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+		STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+		STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+		STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+		STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+		STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+		STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+		STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+		STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+		STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+		STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+		STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+		STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+		STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+		STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+		STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+		STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+		STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+		STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+		STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+		STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+		STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+		STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+		STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+		STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+		STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+		STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+		STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+		STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+		STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+		a += saved_a;
+		b += saved_b;
+		c += saved_c;
+		d += saved_d;
+
+		ptr += 64;
+	} while (size -= 64);
+
+	ctx->a = a;
+	ctx->b = b;
+	ctx->c = c;
+	ctx->d = d;
+
+	return ptr;
+}
+
+void MD5_Init(MD5_CTX *ctx)
+{
+	ctx->a = 0x67452301;
+	ctx->b = 0xefcdab89;
+	ctx->c = 0x98badcfe;
+	ctx->d = 0x10325476;
+
+	ctx->lo = 0;
+	ctx->hi = 0;
+}
+
+void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+	MD5_u32plus saved_lo;
+	unsigned long used, available;
+
+	saved_lo = ctx->lo;
+	if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+		ctx->hi++;
+	ctx->hi += size >> 29;
+
+	used = saved_lo & 0x3f;
+
+	if (used) {
+		available = 64 - used;
+
+		if (size < available) {
+			memcpy(&ctx->buffer[used], data, size);
+			return;
+		}
+
+		memcpy(&ctx->buffer[used], data, available);
+		data = (const unsigned char *)data + available;
+		size -= available;
+		body(ctx, ctx->buffer, 64);
+	}
+
+	if (size >= 64) {
+		data = body(ctx, data, size & ~(unsigned long)0x3f);
+		size &= 0x3f;
+	}
+
+	memcpy(ctx->buffer, data, size);
+}
+
+void MD5_Final(unsigned char *result, MD5_CTX *ctx)
+{
+	unsigned long used, available;
+
+	used = ctx->lo & 0x3f;
+
+	ctx->buffer[used++] = 0x80;
+
+	available = 64 - used;
+
+	if (available < 8) {
+		memset(&ctx->buffer[used], 0, available);
+		body(ctx, ctx->buffer, 64);
+		used = 0;
+		available = 64;
+	}
+
+	memset(&ctx->buffer[used], 0, available - 8);
+
+	ctx->lo <<= 3;
+	ctx->buffer[56] = ctx->lo;
+	ctx->buffer[57] = ctx->lo >> 8;
+	ctx->buffer[58] = ctx->lo >> 16;
+	ctx->buffer[59] = ctx->lo >> 24;
+	ctx->buffer[60] = ctx->hi;
+	ctx->buffer[61] = ctx->hi >> 8;
+	ctx->buffer[62] = ctx->hi >> 16;
+	ctx->buffer[63] = ctx->hi >> 24;
+
+	body(ctx, ctx->buffer, 64);
+
+	result[0] = ctx->a;
+	result[1] = ctx->a >> 8;
+	result[2] = ctx->a >> 16;
+	result[3] = ctx->a >> 24;
+	result[4] = ctx->b;
+	result[5] = ctx->b >> 8;
+	result[6] = ctx->b >> 16;
+	result[7] = ctx->b >> 24;
+	result[8] = ctx->c;
+	result[9] = ctx->c >> 8;
+	result[10] = ctx->c >> 16;
+	result[11] = ctx->c >> 24;
+	result[12] = ctx->d;
+	result[13] = ctx->d >> 8;
+	result[14] = ctx->d >> 16;
+	result[15] = ctx->d >> 24;
+
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif
diff --git a/tools/firmware-utils/src/md5.h b/tools/firmware-utils/src/md5.h
new file mode 100644
index 0000000000..2da44bf355
--- /dev/null
+++ b/tools/firmware-utils/src/md5.h
@@ -0,0 +1,45 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001.  No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
+ */
+
+#ifdef HAVE_OPENSSL
+#include <openssl/md5.h>
+#elif !defined(_MD5_H)
+#define _MD5_H
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+typedef struct {
+	MD5_u32plus lo, hi;
+	MD5_u32plus a, b, c, d;
+	unsigned char buffer[64];
+	MD5_u32plus block[16];
+} MD5_CTX;
+
+extern void MD5_Init(MD5_CTX *ctx);
+extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
+extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
+
+#endif
diff --git a/tools/firmware-utils/src/mkbrncmdline.c b/tools/firmware-utils/src/mkbrncmdline.c
new file mode 100644
index 0000000000..6eb4bfe7cf
--- /dev/null
+++ b/tools/firmware-utils/src/mkbrncmdline.c
@@ -0,0 +1,168 @@
+/*
+ * mkbrncmdline.c - partially based on OpenWrt's wndr3700.c
+ *
+ * Copyright (C) 2011 Tobias Diedrich <ranma+openwrt@tdiedrich.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+	fprintf(stderr, "Error: %s\n", mess);
+	fprintf(stderr, "Usage: mkbrncmdline -i input_file -o output_file [-a loadaddress] arg1 [argx ...]\n");
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+static char *input_file = NULL;
+static char *output_file = NULL;
+static unsigned loadaddr = 0x80002000;
+
+static void parseopts(int *argc, char ***argv)
+{
+	char *endptr;
+	int res;
+
+	while ((res = getopt(*argc, *argv, "a:i:o:")) != -1) {
+		switch (res) {
+		default:
+			usage("Unknown option");
+			break;
+		case 'a':
+			loadaddr = strtoul(optarg, &endptr, 0);
+			if (endptr == optarg || *endptr != 0)
+				usage("loadaddress must be a decimal or hexadecimal 32-bit value");
+			break;
+		case 'i':
+			input_file = optarg;
+			break;
+		case 'o':
+			output_file = optarg;
+			break;
+		}
+	}
+	*argc -= optind;
+	*argv += optind;
+}
+
+static void emitload(int outfd, int reg, unsigned value)
+{
+	char buf[8] = {
+		0x3c, 0x04 + reg,
+		value >> 24, value >> 16,
+		0x34, 0x84 + reg + (reg << 5),
+		value >> 8, value,
+	};
+	if (write(outfd, buf, sizeof(buf)) != sizeof(buf)) {
+		fprintf(stderr, "write: %s\n", strerror(errno));
+		exit(1);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int outfd;
+	int i;
+	int fd;
+	size_t len, skip, buf_len;
+	unsigned cmdline_addr;
+	unsigned s_ofs;
+	char *buf;
+
+	parseopts(&argc, &argv);
+
+	if (argc < 1)
+		usage("must specify at least one kernel cmdline argument");
+
+	if (input_file == NULL || output_file == NULL)
+		usage("must specify input and output file");
+
+	if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
+	{
+		fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
+		exit(1);
+	}
+
+	// mmap input_file
+	if ((fd = open(input_file, O_RDONLY))  < 0
+	|| (len = lseek(fd, 0, SEEK_END)) < 0
+	|| (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+	|| close(fd) < 0)
+	{
+		fprintf(stderr, "Error mapping file '%s': %s\n", input_file, strerror(errno));
+		exit(1);
+	}
+
+	cmdline_addr = loadaddr + len;
+
+	// Kernel args are passed in registers a0,a1,a2 and a3
+	emitload(outfd, 0, 0);              /* a0 = 0 */
+	emitload(outfd, 1, 0);              /* a1 = 0 */
+	emitload(outfd, 2, cmdline_addr);   /* a2 = &cmdline */
+	emitload(outfd, 3, 0);              /* a3 = 0 */
+	skip = lseek(outfd, 0, SEEK_END);
+
+	// write the kernel
+	if (write(outfd, input_file + skip, len - skip) != len -skip) {
+		fprintf(stderr, "write: %s\n", strerror(errno));
+		exit(1);
+	}
+
+	// write cmdline structure
+	buf_len = (argc + 1) * 4;
+	for (i=0; i<argc; i++) {
+		buf_len += strlen(argv[i]) + 1;
+	}
+	buf = malloc(buf_len + 16);
+	if (!buf) {
+		fprintf(stderr, "Could not allocate memory for cmdline buffer\n");
+		exit(1);
+	}
+	memset(buf, 0, buf_len);
+
+	s_ofs = 4 * (argc + 1);
+	for (i=0; i<argc; i++) {
+		unsigned s_ptr = cmdline_addr + s_ofs;
+		buf[i * 4 + 0] = s_ptr >> 24;
+		buf[i * 4 + 1] = s_ptr >> 16;
+		buf[i * 4 + 2] = s_ptr >>  8;
+		buf[i * 4 + 3] = s_ptr >>  0;
+		memcpy(&buf[s_ofs], argv[i], strlen(argv[i]));
+		s_ofs += strlen(argv[i]) + 1;
+	}
+	if (write(outfd, buf, buf_len) != buf_len) {
+		fprintf(stderr, "write: %s\n", strerror(errno));
+		exit(1);
+	}
+
+
+	munmap(input_file, len);
+	close(outfd);
+	free(buf);
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/mkbrnimg.c b/tools/firmware-utils/src/mkbrnimg.c
new file mode 100644
index 0000000000..b7a73ff59d
--- /dev/null
+++ b/tools/firmware-utils/src/mkbrnimg.c
@@ -0,0 +1,189 @@
+/*
+ * mkbrnimg.c - partially based on OpenWrt's wndr3700.c
+ *
+ * Copyright (C) 2011 Tobias Diedrich <ranma+openwrt@tdiedrich.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#define BPB 8 /* bits/byte */
+
+static uint32_t crc32[1<<BPB];
+
+static char *output_file = "default-brnImage";
+static uint32_t magic = 0x12345678;
+static char *signature = "BRNDTW502";
+static uint32_t crc32_poly = 0x2083b8ed;
+
+static void init_crc32()
+{
+	const uint32_t poly = ntohl(crc32_poly);
+	int n;
+
+	for (n = 0; n < 1<<BPB; n++) {
+		uint32_t crc = n;
+		int bit;
+
+		for (bit = 0; bit < BPB; bit++)
+			crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+		crc32[n] = crc;
+	}
+}
+
+static uint32_t crc32buf(unsigned char *buf, size_t len)
+{
+	uint32_t crc = 0xFFFFFFFF;
+
+	for (; len; len--, buf++)
+		crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
+	return ~crc;
+}
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+	fprintf(stderr, "Error: %s\n", mess);
+	fprintf(stderr, "Usage: mkbrnimg [-o output_file] [-m magic] [-s signature] [-p crc32 poly] kernel_file [additional files]\n");
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+static void parseopts(int *argc, char ***argv)
+{
+	char *endptr;
+	int res;
+
+	while ((res = getopt(*argc, *argv, "o:m:s:p:")) != -1) {
+		switch (res) {
+		default:
+			usage("Unknown option");
+			break;
+		case 'o':
+			output_file = optarg;
+			break;
+		case 'm':
+			magic = strtoul(optarg, &endptr, 0);
+			if (endptr == optarg || *endptr != 0)
+				usage("magic must be a decimal or hexadecimal 32-bit value");
+			break;
+		case 's':
+			signature = optarg;
+			break;
+		case 'p':
+			crc32_poly = strtoul(optarg, &endptr, 0);
+			if (endptr == optarg || *endptr != 0)
+				usage("'crc32 poly' must be a decimal or hexadecimal 32-bit value");
+			break;
+		}
+	}
+	*argc -= optind;
+	*argv += optind;
+}
+
+static void appendfile(int outfd, char *path, int kernel) {
+	int fd;
+	size_t len, padded_len;
+	char *input_file;
+	uint32_t crc;
+	char padding[0x400];
+	char footer[12];
+
+	memset(padding, 0xff, sizeof(padding));
+
+	// mmap input_file
+	if ((fd = open(path, O_RDONLY))  < 0
+	|| (len = lseek(fd, 0, SEEK_END)) < 0
+	|| (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+	|| close(fd) < 0)
+	{
+		fprintf(stderr, "Error mapping file '%s': %s\n", path, strerror(errno));
+		exit(1);
+	}
+
+	// kernel should be lzma compressed image, not uImage
+	if (kernel &&
+	    (input_file[0] != (char)0x5d ||
+	     input_file[1] != (char)0x00 ||
+	     input_file[2] != (char)0x00 ||
+	     input_file[3] != (char)0x80)) {
+		fprintf(stderr, "lzma signature not found on kernel image.\n");
+		exit(1);
+	}
+
+	init_crc32();
+	crc = crc32buf(input_file, len);
+	fprintf(stderr, "crc32 for '%s' is %08x.\n", path, crc);
+
+	// write the file
+	write(outfd, input_file, len);
+
+	// write padding
+	padded_len = ((len + sizeof(footer) + sizeof(padding) - 1) & ~(sizeof(padding) - 1)) - sizeof(footer);
+	fprintf(stderr, "len=%08zx padded_len=%08zx\n", len, padded_len);
+	write(outfd, padding, padded_len - len);
+
+	// write footer
+	footer[0]  = (len   >>  0) & 0xff;
+	footer[1]  = (len   >>  8) & 0xff;
+	footer[2]  = (len   >> 16) & 0xff;
+	footer[3]  = (len   >> 24) & 0xff;
+	footer[4]  = (magic >>  0) & 0xff;
+	footer[5]  = (magic >>  8) & 0xff;
+	footer[6]  = (magic >> 16) & 0xff;
+	footer[7]  = (magic >> 24) & 0xff;
+	footer[8]  = (crc   >>  0) & 0xff;
+	footer[9]  = (crc   >>  8) & 0xff;
+	footer[10] = (crc   >> 16) & 0xff;
+	footer[11] = (crc   >> 24) & 0xff;
+	write(outfd, footer, sizeof(footer));
+
+	munmap(input_file, len);
+}
+
+int main(int argc, char **argv)
+{
+	int outfd;
+	int i;
+
+	parseopts(&argc, &argv);
+
+	if (argc < 1)
+		usage("wrong number of arguments");
+
+	if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
+	{
+		fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
+		exit(1);
+	}
+
+	for (i=0; i<argc; i++) {
+		appendfile(outfd, argv[i], i == 0);
+	}
+	write(outfd, signature, strlen(signature)+1);
+	close(outfd);
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/mkbuffaloimg.c b/tools/firmware-utils/src/mkbuffaloimg.c
new file mode 100644
index 0000000000..364dda005b
--- /dev/null
+++ b/tools/firmware-utils/src/mkbuffaloimg.c
@@ -0,0 +1,223 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2016 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ *  Based on mkdniimg.c
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#define DNI_HDR_LEN	128
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static char *version = "0.00_0.00";
+static char *region = "JP";
+static char *rootfs_size;
+static char *kernel_size;
+
+static char *board_id;
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>       create image for the board specified with <board>\n"
+"  -i <file>        read input from the file <file>\n"
+"  -o <file>        write output to the file <file>\n"
+"  -v <version>     set image version to <version>\n"
+"  -r <region>      set image region to <region>\n"
+"  -R <rootfs_size> set RootfsSize to <rootfs_size>\n"
+"  -K <kernel_size> set KernelSize to <kernel_size>\n"
+"  -h               show this screen\n"
+	);
+
+	exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int buflen;
+	int err;
+	struct stat st;
+	char *buf;
+	int i;
+	uint8_t csum;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "B:i:o:v:r:R:K:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'v':
+			version = optarg;
+			break;
+		case 'r':
+			region = optarg;
+			break;
+		case 'R':
+			rootfs_size = optarg;
+			break;
+		case 'K':
+			kernel_size = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (board_id == NULL) {
+		ERR("no board specified");
+		goto err;
+	}
+
+	if (rootfs_size == NULL) {
+		ERR("no rootfs_size specified");
+		goto err;
+	}
+
+	if (kernel_size == NULL) {
+		ERR("no kernel_size specified");
+		goto err;
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	buflen = st.st_size + DNI_HDR_LEN + 1;
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	memset(buf, 0, DNI_HDR_LEN);
+	snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:%s\nregion:%s\n"
+		 "RootfsSize:%s\nKernelSize:%s\nInfoHeadSize:128\n",
+		 board_id, version, region, rootfs_size, kernel_size);
+	buf[DNI_HDR_LEN - 2] = 0x12;
+	buf[DNI_HDR_LEN - 1] = 0x32;
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	errno = 0;
+	fread(buf +  DNI_HDR_LEN, st.st_size, 1, infile);
+	if (errno != 0) {
+		ERRS("unable to read from file %s", ifname);
+		goto err_close_in;
+	}
+
+	csum = 0;
+	for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++)
+		csum += buf[i];
+
+	csum = 0xff - csum;
+	buf[st.st_size + DNI_HDR_LEN] = csum;
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto err_close_in;
+	}
+
+	errno = 0;
+	fwrite(buf, buflen, 1, outfile);
+	if (errno) {
+		ERRS("unable to write to file %s", ofname);
+		goto err_close_out;
+	}
+
+	res = EXIT_SUCCESS;
+
+	fflush(outfile);
+
+ err_close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+
+ err_close_in:
+	fclose(infile);
+
+ err_free:
+	free(buf);
+
+ err:
+	return res;
+}
diff --git a/tools/firmware-utils/src/mkcameofw.c b/tools/firmware-utils/src/mkcameofw.c
new file mode 100644
index 0000000000..e0da4baf33
--- /dev/null
+++ b/tools/firmware-utils/src/mkcameofw.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define MAX_MODEL_LEN		20
+#define MAX_SIGNATURE_LEN	30
+#define MAX_REGION_LEN		4
+#define MAX_VERSION_LEN		12
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+struct file_info {
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+	uint32_t	write_size;
+};
+
+struct img_header {
+	uint32_t	checksum;
+	uint32_t	image_size;
+	uint32_t	kernel_size;
+	char		model[MAX_MODEL_LEN];
+	char		signature[MAX_SIGNATURE_LEN];
+	char		region[MAX_REGION_LEN];
+	char		version[MAX_VERSION_LEN];
+	unsigned char	header_len;
+	unsigned char	is_tgz;
+	unsigned char	pad[4];
+} __attribute__ ((packed));
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *model;
+static char *signature;
+static char *region = "DEF";
+static char *version;
+static struct file_info kernel_info;
+static struct file_info rootfs_info;
+static uint32_t kernel_size;
+static uint32_t image_size;
+static int combined;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -c              use the kernel image as a combined image\n"
+"  -M <model>      set model to <model>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -S <signature>  set image signature to <signature>\n"
+"  -R <region>     set image region to <region>\n"
+"  -V <version>    set image version to <version>\n"
+"  -I <size>       set image size to <size>\n"
+"  -K <size>       set kernel size to <size>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL)
+		return 0;
+
+	res = stat(fdata->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	fdata->write_size = fdata->file_size;
+	return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+out_close:
+	fclose(f);
+out:
+	return ret;
+}
+
+static int check_options(void)
+{
+	int ret;
+
+#define CHKSTR(_name, _msg)				\
+	do {						\
+		if (_name == NULL) {			\
+			ERR("no %s specified", _msg);	\
+			return -1;			\
+		}					\
+	} while (0)
+
+#define CHKSTRLEN(_name, _msg)					\
+	do {							\
+		int field_len;					\
+		CHKSTR(_name, _msg);				\
+		field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
+		if (strlen(_name) > field_len) { 		\
+			ERR("%s is too long, max length is %d",	\
+			    _msg, field_len);			\
+			return -1;				\
+		}						\
+	} while (0)
+
+	CHKSTRLEN(model, "model");
+	CHKSTRLEN(signature, "signature");
+	CHKSTRLEN(region, "region");
+	CHKSTRLEN(version, "version");
+	CHKSTR(ofname, "output file");
+	CHKSTR(kernel_info.file_name, "kernel image");
+
+	ret = get_file_stat(&kernel_info);
+	if (ret)
+		return ret;
+
+	if (combined) {
+		if (!kernel_size) {
+			ERR("kernel size must be specified for combined images");
+			return -1;				\
+		}
+
+		if (!image_size)
+			image_size = kernel_info.file_size;
+
+		if (kernel_info.file_size > image_size) {
+			ERR("kernel image is too big");
+			return -1;
+		}
+
+		kernel_info.write_size = image_size;
+	} else {
+		CHKSTR(rootfs_info.file_name, "rootfs image");
+
+		ret = get_file_stat(&rootfs_info);
+		if (ret)
+			return ret;
+
+		if (kernel_size) {
+			/* override kernel size */
+			kernel_info.write_size = kernel_size;
+		}
+
+		if (image_size) {
+			if (image_size < kernel_info.write_size)
+				kernel_info.write_size = image_size;
+
+			/* override rootfs size */
+			rootfs_info.write_size = image_size - kernel_info.write_size;
+		}
+
+		if (kernel_info.file_size > kernel_info.write_size) {
+			ERR("kernel image is too big");
+			return -1;
+		}
+
+		if (rootfs_info.file_size > rootfs_info.write_size) {
+			ERR("rootfs image is too big");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+out:
+	return ret;
+}
+
+static uint32_t get_csum(unsigned char *p, uint32_t len)
+{
+	uint32_t csum = 0;
+
+	while (len--)
+		csum += *p++;
+
+	return csum;
+}
+
+static int build_fw(void)
+{
+	int buflen;
+	char *buf;
+	char *p;
+	uint32_t csum;
+	struct img_header *hdr;
+	int ret = EXIT_FAILURE;
+
+	buflen = sizeof(struct img_header) +
+		 kernel_info.write_size + rootfs_info.write_size;
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	memset(buf, 0, buflen);
+
+	p = buf + sizeof(struct img_header);
+
+	/* read kernel data */
+	ret = read_to_buf(&kernel_info, p);
+	if (ret)
+		goto out_free_buf;
+
+	if (!combined) {
+		p += kernel_info.write_size;
+
+		/* read rootfs data */
+		ret = read_to_buf(&rootfs_info, p);
+		if (ret)
+			goto out_free_buf;
+	}
+
+	csum = get_csum((unsigned char *)(buf + sizeof(struct img_header)),
+			buflen - sizeof(struct img_header));
+
+	/* fill firmware header */
+	hdr = (struct img_header *) buf;
+
+	hdr->checksum = htonl(csum);
+	hdr->image_size = htonl(buflen - sizeof(struct img_header));
+	if (!combined)
+		hdr->kernel_size = htonl(kernel_info.write_size);
+	else
+		hdr->kernel_size = htonl(kernel_size);
+	hdr->header_len = sizeof(struct img_header);
+	strncpy(hdr->model, model, sizeof(hdr->model));
+	strncpy(hdr->signature, signature, sizeof(hdr->signature));
+	strncpy(hdr->version, version, sizeof(hdr->version));
+	strncpy(hdr->region, region, sizeof(hdr->region));
+
+	ret = write_fw(buf, buflen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+out_free_buf:
+	free(buf);
+out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	progname = basename(argv[0]);
+
+	while (1) {
+		int c;
+
+		c = getopt(argc, argv, "M:S:V:R:k:K:I:r:o:hc");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'M':
+			model = optarg;
+			break;
+		case 'S':
+			signature = optarg;
+			break;
+		case 'V':
+			version = optarg;
+			break;
+		case 'R':
+			region = optarg;
+			break;
+		case 'k':
+			kernel_info.file_name = optarg;
+			break;
+		case 'K':
+			if (str2u32(optarg, &kernel_size)) {
+				ERR("%s is invalid '%s'",
+				    "kernel size", optarg);
+				goto out;
+			}
+			break;
+		case 'I':
+			if (str2u32(optarg, &image_size)) {
+				ERR("%s is invalid '%s'",
+				    "image size", optarg);
+				goto out;
+			}
+			break;
+		case 'r':
+			rootfs_info.file_name = optarg;
+			break;
+		case 'c':
+			combined = 1;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	ret = build_fw();
+
+out:
+	return ret;
+}
+
diff --git a/tools/firmware-utils/src/mkcasfw.c b/tools/firmware-utils/src/mkcasfw.c
new file mode 100644
index 0000000000..5655bf1894
--- /dev/null
+++ b/tools/firmware-utils/src/mkcasfw.c
@@ -0,0 +1,1030 @@
+/*
+ *
+ *  Copyright (C) 2007 OpenWrt.org
+ *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE16_TO_HOST(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#else
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE16_TO_HOST(x)	bswap_16(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#endif
+
+#define MAX_NUM_BLOCKS	2
+#define MAX_ARG_COUNT	32
+#define MAX_ARG_LEN	1024
+#define FILE_BUF_LEN	(16*1024)
+#define DEFAULT_PADC	0xFF
+
+#define DEFAULT_BLOCK_ALIGN	0x10000U
+
+#define CSUM_TYPE_NONE	0
+#define CSUM_TYPE_8	1
+#define CSUM_TYPE_16	2
+#define CSUM_TYPE_32	3
+
+struct csum_state{
+	int	size;
+	uint32_t val;
+	uint32_t tmp;
+	int	odd;
+};
+
+struct image_desc {
+	int		need_file;
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+
+	uint32_t	csum;
+	uint32_t	out_size;
+	uint8_t		padc;
+};
+
+struct fwhdr_nfs {
+	uint32_t	type;
+	uint32_t	kernel_offs;
+	uint32_t	kernel_size;
+	uint32_t	fs_offs;
+	uint32_t	fs_size;
+	uint32_t	kernel_csum;
+	uint32_t	fs_csum;
+	uint32_t	id;
+} __attribute__ ((packed));
+
+struct fwhdr_cas {
+	uint32_t	type;
+	uint32_t	kernel_offs;
+	uint32_t	kernel_size;
+	uint32_t	id;
+	uint32_t	kernel_csum;
+	uint32_t	magic1;
+	uint32_t	magic2;
+	uint32_t	magic3;
+} __attribute__ ((packed));
+
+union file_hdr {
+	struct fwhdr_cas cas;
+	struct fwhdr_nfs nfs;
+};
+
+struct board_info {
+	char		*model;
+	char		*name;
+	int		header_type;
+	uint32_t	id;
+	uint32_t	max_kernel_size;
+	uint32_t	max_fs_size;
+};
+
+#define HEADER_TYPE_NFS		0
+#define HEADER_TYPE_CAS		1
+
+#define KERNEL_SIZE_CAS		(61*64*1024)
+#define KERNEL_SIZE_NFS		(52*64*1024)
+#define FS_SIZE_NFS		(9*64*1024)
+
+#define CAS_MAGIC1	0x5241AA55
+#define CAS_MAGIC2	0x524F4741
+#define CAS_MAGIC3	0xD3F22D4E
+
+/* Cellvision/SparkLAN products */
+#define MODEL_CAS_630		0x01000000
+#define MODEL_CAS_630W		0x01000000
+#define MODEL_CAS_670		0x01000000
+#define MODEL_CAS_670W		0x01000000
+#define MODEL_NFS_101U		0x01000000
+#define MODEL_NFS_101WU		0x01000003
+#define MODEL_NFS_202U		0x01000001
+#define MODEL_NFS_202WU		0x01000002
+
+/* Corega products */
+#define MODEL_CG_NSADP		0x01000020 /* NFS-101U */
+#define MODEL_CG_NSADPCR	0x01000021 /* NFS-202U */
+
+/* D-Link products */
+#define MODEL_DCS_950		0x01010102 /* CAS-630 */
+#define MODEL_DCS_950G		0x01020102 /* CAS-630W */
+#define MODEL_DNS_120		0x01000030 /* NFS-101U */
+#define MODEL_DNS_G120		0x01000032 /* NFS-101WU */
+
+/* Digitus products */
+#define MODEL_DN_16021		MODEL_CAS_630
+#define MODEL_DN_16022		MODEL_CAS_630W
+#define MODEL_DN_16030		MODEL_CAS_670
+#define MODEL_DN_16031		MODEL_CAS_670W
+#define MODEL_DN_7013		MODEL_NFS_101U
+
+/* Lobos products */
+#define MODEL_LB_SS01TXU	0x00000000
+
+/* Neu-Fusion products */
+
+/* Ovislink products */
+#define MODEL_MU_5000FS		0x01000040 /* NFS-101U */
+#define MODEL_WL_5420CAM	0x020B0101 /* CAS-630W? */
+#define MODEL_WL_5460CAM	0x020B0001 /* CAS-670W */
+
+/* Repotec products */
+
+/* Sitecom products */
+#define MODEL_LN_350		/* unknown */
+#define MODEL_LN_403		0x01020402
+#define MODEL_WL_401		0x01010402
+
+/* Surecom products */
+#define MODEL_EP_4001_MM	0x01030A02 /* CAS-630 */
+#define MODEL_EP_4002_MM	0x01020A02 /* CAS-630W */
+#define MODEL_EP_4011_MM	0x01010A02 /* CAS-670 */
+#define MODEL_EP_4012_MM	0x01000A02 /* CAS-670W */
+#define MODEL_EP_9812_U		/* unknown */
+
+/* Trendnet products */
+#define MODEL_TN_U100		0x01000081 /* NFS-101U */
+#define MODEL_TN_U200		0x01000082 /* NFS-202U */
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname;
+int verblevel;
+int keep_invalid_images;
+int invalid_causes_error = 1;
+union file_hdr header;
+
+struct image_desc kernel_image;
+struct image_desc fs_image;
+
+struct board_info *board = NULL;
+
+#define BOARD(m, n, i, ks, fs, h) {		\
+		.model = (m),			\
+		.name = (n),			\
+		.id = (i),			\
+		.max_kernel_size = (ks), 	\
+		.max_fs_size = (fs), 		\
+		.header_type = (h)		\
+	}
+
+#define BOARD_CAS(m,n,i) \
+		BOARD(m, n, i, KERNEL_SIZE_CAS, 0, HEADER_TYPE_CAS)
+#define BOARD_NFS(m,n,i) \
+		BOARD(m, n, i, KERNEL_SIZE_NFS, FS_SIZE_NFS, HEADER_TYPE_NFS)
+
+static struct board_info boards[] = {
+	/* Cellvision/Sparklan products */
+	BOARD_CAS("CAS-630", "Cellvision CAS-630", MODEL_CAS_630),
+	BOARD_CAS("CAS-630W", "Cellvision CAS-630W", MODEL_CAS_630W),
+	BOARD_CAS("CAS-670", "Cellvision CAS-670", MODEL_CAS_670),
+	BOARD_CAS("CAS-670W", "Cellvision CAS-670W", MODEL_CAS_670W),
+	BOARD_NFS("NFS-101U", "Cellvision NFS-101U", MODEL_NFS_101U),
+	BOARD_NFS("NFS-101WU", "Cellvision NFS-101WU", MODEL_NFS_101WU),
+	BOARD_NFS("NFS-202U", "Cellvision NFS-202U", MODEL_NFS_202U),
+	BOARD_NFS("NFS-202WU", "Cellvision NFS-202WU", MODEL_NFS_202WU),
+
+	/* Corega products */
+	BOARD_NFS("CG-NSADP", "Corega CG-NSADP", MODEL_CG_NSADP),
+	BOARD_NFS("CG-NSADPCR", "Corega CG-NSADPCR", MODEL_CG_NSADPCR),
+
+	/* D-Link products */
+	BOARD_CAS("DCS-950", "D-Link DCS-950", MODEL_DCS_950),
+	BOARD_CAS("DCS-950G", "D-Link DCS-950G", MODEL_DCS_950G),
+	BOARD_NFS("DNS-120", "D-Link DNS-120", MODEL_DNS_120),
+	BOARD_NFS("DNS-G120", "D-Link DNS-G120", MODEL_DNS_G120),
+
+	/* Digitus products */
+	BOARD_NFS("DN-7013", "Digitus DN-7013", MODEL_DN_7013),
+
+	/* Lobos products */
+	BOARD_NFS("LB-SS01TXU", "Lobos LB-SS01TXU", MODEL_LB_SS01TXU),
+
+	/* Ovislink products */
+	BOARD_NFS("MU-5000FS", "Ovislink MU-5000FS", MODEL_MU_5000FS),
+	BOARD_CAS("WL-5420CAM", "Ovislink WL-5420 CAM", MODEL_WL_5420CAM),
+	BOARD_CAS("WL-5460CAM", "Ovislink WL-5460 CAM", MODEL_WL_5460CAM),
+
+	/* Sitecom products */
+	BOARD_CAS("LN-403", "Sitecom LN-403", MODEL_LN_403),
+	BOARD_CAS("WL-401", "Sitecom WL-401", MODEL_WL_401),
+
+	/* Surecom products */
+	BOARD_CAS("EP-4001-MM", "Surecom EP-4001-MM", MODEL_EP_4001_MM),
+	BOARD_CAS("EP-4002-MM", "Surecom EP-4002-MM", MODEL_EP_4002_MM),
+	BOARD_CAS("EP-4011-MM", "Surecom EP-4011-MM", MODEL_EP_4011_MM),
+	BOARD_CAS("EP-4012-MM", "Surecom EP-4012-MM", MODEL_EP_4012_MM),
+
+	/* TrendNET products */
+	BOARD_NFS("TN-U100", "TrendNET TN-U100", MODEL_TN_U100),
+	BOARD_NFS("TN-U200", "TrendNET TN-U200", MODEL_TN_U200),
+
+	{.model = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+	fprintf(stderr, "[%s] *** warning: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+	if (verblevel < lev) \
+		break;\
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL		-1
+#define ERR_INVALID_IMAGE	-2
+
+void
+usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+	);
+	for (board = boards; board->model != NULL; board++){
+		fprintf(stream,
+"                  %-12s: %s\n",
+		 board->model, board->name);
+	};
+	fprintf(stream,
+"  -d              don't throw error on invalid images\n"
+"  -k              keep invalid images\n"
+"  -K <file>       add kernel to the image\n"
+"  -C <file>       add custom filesystem to the image\n"
+"  -h              show this screen\n"
+"Parameters:\n"
+"  <file>          write output to the file <file>\n"
+	);
+
+	exit(status);
+}
+
+static inline uint32_t align(uint32_t base, uint32_t alignment)
+{
+	uint32_t ret;
+
+	if (alignment) {
+		ret = (base + alignment - 1);
+		ret &= ~(alignment-1);
+	} else {
+		ret = base;
+	}
+
+	return ret;
+}
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+		return -1;
+	}
+
+	*val = t & 0xFFFF;
+	return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+		return -1;
+	}
+
+	*val = t & 0xFF;
+	return 0;
+}
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+	int res = 0;
+	size_t argl;
+	char *tok;
+	char **ap = &buf;
+	int i;
+
+	memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+	if ((arg == NULL)) {
+		/* no arguments */
+		return 0;
+	}
+
+	argl = strlen(arg);
+	if (argl == 0) {
+		/* no arguments */
+		return 0;
+	}
+
+	if (argl >= MAX_ARG_LEN) {
+		/* argument is too long */
+		argl = MAX_ARG_LEN-1;
+	}
+
+	memcpy(buf, arg, argl);
+	buf[argl] = '\0';
+
+	for (i = 0; i < MAX_ARG_COUNT; i++) {
+		tok = strsep(ap, ":");
+		if (tok == NULL) {
+			break;
+		}
+#if 0
+		else if (tok[0] == '\0') {
+			break;
+		}
+#endif
+		argv[i] = tok;
+		res++;
+	}
+
+	return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+	if (arg == NULL || *arg != '-')
+		return 0;
+
+	ERR("option -%c requires an argument\n", c);
+	return ERR_FATAL;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+	int ret = 1;
+	if (arg != NULL) {
+		if (*arg) ret = 0;
+	};
+	return ret;
+}
+
+
+void
+csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	for ( ; len > 0; len --) {
+		css->val += *p++;
+	}
+}
+
+
+uint16_t
+csum8_get(struct csum_state *css)
+{
+	uint8_t t;
+
+	t = css->val;
+	return ~t + 1;
+}
+
+
+void
+csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	uint16_t t;
+
+	if (css->odd) {
+		t = css->tmp + (p[0]<<8);
+		css->val += LE16_TO_HOST(t);
+		css->odd = 0;
+		len--;
+		p++;
+	}
+
+	for ( ; len > 1; len -= 2, p +=2 ) {
+		t = p[0] + (p[1] << 8);
+		css->val += LE16_TO_HOST(t);
+	}
+
+	if (len == 1) {
+		css->tmp = p[0];
+		css->odd = 1;
+	}
+}
+
+
+uint16_t
+csum16_get(struct csum_state *css)
+{
+	char pad = 0;
+
+	csum16_update(&pad, 1, css);
+	return ~css->val + 1;
+}
+
+void
+csum32_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	uint32_t t;
+
+	for ( ; len > 3; len -= 4, p += 4 ) {
+		t = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+		css->val ^= t;
+	}
+}
+
+uint32_t
+csum32_get(struct csum_state *css)
+{
+	return css->val;
+}
+
+
+void
+csum_init(struct csum_state *css, int size)
+{
+	css->val = 0;
+	css->tmp = 0;
+	css->odd = 0;
+	css->size = size;
+}
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	switch (css->size) {
+	case CSUM_TYPE_8:
+		csum8_update(p,len,css);
+		break;
+	case CSUM_TYPE_16:
+		csum16_update(p,len,css);
+		break;
+	case CSUM_TYPE_32:
+		csum32_update(p,len,css);
+		break;
+	}
+}
+
+
+uint32_t
+csum_get(struct csum_state *css)
+{
+	uint32_t ret;
+
+	switch (css->size) {
+	case CSUM_TYPE_8:
+		ret = csum8_get(css);
+		break;
+	case CSUM_TYPE_16:
+		ret = csum16_get(css);
+		break;
+	case CSUM_TYPE_32:
+		ret = csum32_get(css);
+	}
+
+	return ret;
+}
+
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+		struct csum_state *css)
+{
+	errno = 0;
+
+	fwrite(data, len, 1, outfile);
+	if (errno) {
+		ERRS("unable to write output file");
+		return ERR_FATAL;
+	}
+
+	if (css) {
+		csum_update(data, len, css);
+	}
+
+	return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+		 struct csum_state *css)
+{
+	uint8_t buf[512];
+	size_t buflen = sizeof(buf);
+	int err;
+
+	memset(buf, padc, buflen);
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		err = write_out_data(outfile, buf, buflen, css);
+		if (err)
+			return err;
+
+		len -= buflen;
+	}
+
+	return 0;
+}
+
+
+int
+image_stat_file(struct image_desc *desc)
+{
+	struct stat st;
+	int err;
+
+	if (desc->file_name == NULL)
+		return 0;
+
+	err = stat(desc->file_name, &st);
+	if (err){
+		ERRS("stat failed on %s", desc->file_name);
+		return ERR_FATAL;
+	}
+
+	if (st.st_size > desc->out_size) {
+		WARN("file %s is too big, will be truncated to %d bytes\n",
+			desc->file_name, desc->out_size);
+		desc->file_size = desc->out_size;
+		return ERR_INVALID_IMAGE;
+	}
+
+
+	desc->file_size = st.st_size;
+	desc->out_size = align(desc->file_size,1);
+	return 0;
+}
+
+
+int
+image_writeout_file(FILE *outfile, struct image_desc *desc,
+			struct csum_state *css)
+{
+	char buf[FILE_BUF_LEN];
+	size_t buflen = sizeof(buf);
+	FILE *f;
+	size_t len;
+	int res;
+
+	if (desc->file_name == NULL)
+		return 0;
+
+	if (desc->file_size == 0)
+		return 0;
+
+	errno = 0;
+	f = fopen(desc->file_name,"r");
+	if (errno) {
+		ERRS("unable to open file: %s", desc->file_name);
+		return ERR_FATAL;
+	}
+
+	len = desc->file_size;
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		/* read data from source file */
+		errno = 0;
+		fread(buf, buflen, 1, f);
+		if (errno != 0) {
+			ERRS("unable to read from file: %s", desc->file_name);
+			res = ERR_FATAL;
+			break;
+		}
+
+		res = write_out_data(outfile, buf, buflen, css);
+		if (res)
+			break;
+
+		len -= buflen;
+	}
+
+	fclose(f);
+	return res;
+}
+
+
+int
+image_writeout(FILE *outfile, struct image_desc *desc)
+{
+	int res;
+	struct csum_state css;
+	size_t padlen;
+
+	res = 0;
+
+	if (!desc->file_size)
+		return 0;
+
+	DBG(2, "writing image, file=%s, file_size=%d\n",
+		desc->file_name, desc->file_size);
+
+	csum_init(&css, CSUM_TYPE_32);
+
+	res = image_writeout_file(outfile, desc, &css);
+	if (res)
+		return res;
+
+	/* write padding data if neccesary */
+	padlen = desc->out_size - desc->file_size;
+	DBG(1,"padding desc, length=%zu", padlen);
+	res = write_out_padding(outfile, padlen, desc->padc, &css);
+
+	desc->csum = csum_get(&css);
+
+	return res;
+}
+
+
+int
+write_out_header(FILE *outfile)
+{
+	union file_hdr tmp;
+	int res;
+
+	errno = 0;
+	if (fseek(outfile, 0, SEEK_SET) != 0) {
+		ERRS("fseek failed on output file");
+		return ERR_FATAL;
+	}
+
+	switch (board->header_type) {
+	case HEADER_TYPE_CAS:
+		tmp.cas.type = HOST_TO_LE32(header.cas.type);
+		tmp.cas.id = HOST_TO_LE32(header.cas.id);
+		tmp.cas.kernel_offs = HOST_TO_LE32(sizeof(tmp.cas));
+		tmp.cas.kernel_size = HOST_TO_LE32(kernel_image.out_size);
+		tmp.cas.kernel_csum = HOST_TO_LE32(kernel_image.csum);
+		tmp.cas.magic1 = HOST_TO_LE32(CAS_MAGIC1);
+		tmp.cas.magic2 = HOST_TO_LE32(CAS_MAGIC2);
+		tmp.cas.magic3 = HOST_TO_LE32(CAS_MAGIC3);
+		res = write_out_data(outfile, (uint8_t *)&tmp.cas,
+					sizeof(tmp.cas), NULL);
+		break;
+	case HEADER_TYPE_NFS:
+		tmp.nfs.type = HOST_TO_LE32(header.nfs.type);
+		tmp.nfs.id = HOST_TO_LE32(header.nfs.id);
+		tmp.nfs.kernel_offs = HOST_TO_LE32(sizeof(tmp.nfs));
+		tmp.nfs.kernel_size = HOST_TO_LE32(kernel_image.out_size);
+		tmp.nfs.kernel_csum = HOST_TO_LE32(kernel_image.csum);
+		tmp.nfs.fs_offs = HOST_TO_LE32(sizeof(tmp.nfs)
+					+ kernel_image.out_size);
+		tmp.nfs.fs_size = HOST_TO_LE32(fs_image.out_size);
+		tmp.nfs.fs_csum = HOST_TO_LE32(fs_image.csum);
+		res = write_out_data(outfile, (uint8_t *)&tmp.nfs,
+					sizeof(tmp.nfs), NULL);
+		break;
+	}
+
+	return res;
+}
+
+int
+write_out_images(FILE *outfile)
+{
+	struct image_desc *desc;
+	int i, res;
+
+	res = image_writeout(outfile, &kernel_image);
+	if (res)
+		return res;
+
+	res = image_writeout(outfile, &fs_image);
+	if (res)
+		return res;
+
+	return 0;
+}
+
+
+struct board_info *
+find_board(char *model)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->model != NULL; board++){
+		if (strcasecmp(model, board->model) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+	DBG(1,"parsing board option: -%c %s", ch, arg);
+
+	if (board != NULL) {
+		ERR("only one board option allowed");
+		return ERR_FATAL;
+	}
+
+	if (required_arg(ch, arg))
+		return ERR_FATAL;
+
+	board = find_board(arg);
+	if (board == NULL){
+		ERR("invalid/unknown board specified: %s", arg);
+		return ERR_FATAL;
+	}
+
+	switch (board->header_type) {
+	case HEADER_TYPE_CAS:
+		header.cas.type = HEADER_TYPE_CAS;
+		header.cas.id = board->id;
+		break;
+	case HEADER_TYPE_NFS:
+		header.nfs.type = HEADER_TYPE_NFS;
+		header.nfs.id = board->id;
+		break;
+	default:
+		ERR("internal error, unknown header type\n");
+		return ERR_FATAL;
+	}
+
+	return 0;
+}
+
+
+int
+parse_opt_image(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	char *p;
+	struct image_desc *desc = NULL;
+	int i;
+
+	switch (ch) {
+	case 'K':
+		if (kernel_image.file_name) {
+			WARN("only one kernel option allowed");
+			break;
+		}
+		desc = &kernel_image;
+		break;
+	case 'F':
+		if (fs_image.file_name) {
+			WARN("only one fs option allowed");
+			break;
+		}
+		desc = &fs_image;
+		break;
+	}
+
+	if (!desc)
+		return ERR_FATAL;
+
+	argc = parse_arg(arg, buf, argv);
+
+	i = 0;
+	p = argv[i++];
+	if (!is_empty_arg(p)) {
+		desc->file_name = strdup(p);
+		if (desc->file_name == NULL) {
+			ERR("not enough memory");
+			return ERR_FATAL;
+		}
+	} else {
+		ERR("no file specified for option %c", ch);
+		return ERR_FATAL;
+	}
+
+	return 0;
+}
+
+
+int
+process_images(void)
+{
+	struct image_desc *desc;
+	uint32_t offs = 0;
+	int i;
+	int res;
+
+	kernel_image.out_size = board->max_kernel_size;
+	kernel_image.padc = DEFAULT_PADC;
+	res = image_stat_file(&kernel_image);
+	if (res)
+		return res;
+
+	if (!fs_image.file_name)
+		return 0;
+
+	fs_image.out_size = board->max_fs_size;
+	fs_image.padc = DEFAULT_PADC;
+	res = image_stat_file(&fs_image);
+	if (res)
+		return res;
+
+	return 0;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	int optinvalid = 0;   /* flag for invalid option */
+	int c;
+	int res = ERR_FATAL;
+
+	FILE *outfile;
+
+	progname=basename(argv[0]);
+
+	opterr = 0;  /* could not print standard getopt error messages */
+	while ( 1 ) {
+		optinvalid = 0;
+
+		c = getopt(argc, argv, "B:C:dhK:r:vw:x:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			optinvalid = parse_opt_board(c,optarg);
+			break;
+		case 'd':
+			invalid_causes_error = 0;
+			break;
+		case 'C':
+		case 'K':
+			optinvalid = parse_opt_image(c,optarg);
+			break;
+		case 'k':
+			keep_invalid_images = 1;
+			break;
+		case 'v':
+			verblevel++;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			optinvalid = 1;
+			break;
+		}
+		if (optinvalid != 0 ){
+			ERR("invalid option: -%c", optopt);
+			goto out;
+		}
+	}
+
+	if (board == NULL) {
+		ERR("no board specified");
+		goto out;
+	}
+
+	if (optind == argc) {
+		ERR("no output file specified");
+		goto out;
+	}
+
+	ofname = argv[optind++];
+
+	if (optind < argc) {
+		ERR("invalid option: %s", argv[optind]);
+		goto out;
+	}
+
+	res = process_images();
+	if (res == ERR_FATAL)
+		goto out;
+
+	if (res == ERR_INVALID_IMAGE) {
+		if (invalid_causes_error)
+			res = ERR_FATAL;
+
+		if (keep_invalid_images == 0) {
+			WARN("generation of invalid images \"%s\" disabled", ofname);
+			goto out;
+		}
+
+		WARN("generating invalid image: \"%s\"", ofname);
+	}
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		res = ERR_FATAL;
+		goto out;
+	}
+
+	if (write_out_header(outfile) != 0) {
+		res = ERR_FATAL;
+		goto out_flush;
+	}
+
+	if (write_out_images(outfile) != 0) {
+		res = ERR_FATAL;
+		goto out_flush;
+	}
+
+	if (write_out_header(outfile) != 0) {
+		res = ERR_FATAL;
+		goto out_flush;
+	}
+
+	DBG(1,"Image file %s completed.", ofname);
+
+out_flush:
+	fflush(outfile);
+	fclose(outfile);
+	if (res == ERR_FATAL) {
+		unlink(ofname);
+	}
+out:
+	if (res == ERR_FATAL)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/mkchkimg.c b/tools/firmware-utils/src/mkchkimg.c
new file mode 100644
index 0000000000..e152f7d468
--- /dev/null
+++ b/tools/firmware-utils/src/mkchkimg.c
@@ -0,0 +1,327 @@
+/*
+ * 	Make CHK Image
+ *
+ * 	This utility creates Netgear .chk files.
+ *
+ * 	Copyright (C) 2008 Dave C. Reeve <Dave.Reeve@dreeve.org>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *	
+ *	You should have received a copy of the GNU General Public License along
+ *	with this program; if not, write to the Free Software Foundation, Inc.,
+ *	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#define BUF_LEN (2048)
+
+#define MAX_BOARD_ID_LEN (64)
+
+struct chk_header {
+	uint32_t magic;
+	uint32_t header_len;
+	uint8_t  reserved[8];
+	uint32_t kernel_chksum;
+	uint32_t rootfs_chksum;
+	uint32_t kernel_len;
+	uint32_t rootfs_len;
+	uint32_t image_chksum;
+	uint32_t header_chksum;
+	/* char board_id[] - upto MAX_BOARD_ID_LEN */
+};
+
+static void __attribute__ ((format (printf, 2, 3)))
+fatal_error (int maybe_errno, const char * format, ...)
+{
+	va_list ap;
+
+	fprintf (stderr, "mkchkimg: ");
+	va_start (ap, format);
+	vfprintf (stderr, format, ap);
+	va_end (ap);
+
+	if (maybe_errno) {
+		fprintf (stderr, ": %s\n", strerror (maybe_errno));
+	} else {
+		fprintf (stderr, "\n");
+	}
+
+	exit (EXIT_FAILURE);
+}
+
+static void __attribute__ ((format (printf, 1, 2)))
+message (const char * format, ...)
+{
+	va_list ap;
+
+	fprintf (stderr, "mkchkimg: ");
+	va_start (ap, format);
+	vfprintf (stderr, format, ap);
+	va_end (ap);
+	fprintf (stderr, "\n");
+}
+
+struct ngr_checksum {
+	uint32_t c0;
+	uint32_t c1;
+};
+
+static inline void
+netgear_checksum_init (struct ngr_checksum * c)
+{
+	c->c0 = c->c1 = 0;
+}
+
+static inline void
+netgear_checksum_add (struct ngr_checksum * c, unsigned char * buf, size_t len)
+{
+	size_t i;
+
+	for (i=0; i<len; i++) {
+		c->c0 += buf[i] & 0xff;
+		c->c1 += c->c0;
+	}
+}
+
+static inline unsigned long
+netgear_checksum_fini (struct ngr_checksum * c)
+{
+	uint32_t b, checksum;
+
+	b = (c->c0 & 65535) + ((c->c0 >> 16) & 65535);
+	c->c0 = ((b >> 16) + b) & 65535;
+	b = (c->c1 & 65535) + ((c->c1 >> 16) & 65535);
+	c->c1 = ((b >> 16) + b) & 65535;
+	checksum = ((c->c1 << 16) | c->c0);
+	return checksum;
+}
+
+static void
+print_help (void)
+{
+	fprintf (stderr, "Usage: mkchkimg -o output -k kernel [-f filesys] [-b board_id] [-r region]\n");
+}
+
+int
+main (int argc, char * argv[])
+{
+	int opt;
+	char * ptr;
+	size_t len;
+	size_t header_len;
+	struct chk_header * hdr;
+	struct ngr_checksum chk_part, chk_whole;
+	char buf[BUF_LEN];
+	char * output_file, * kern_file, * fs_file;
+	FILE * out_fp, * kern_fp, * fs_fp;
+	char * board_id;
+	unsigned long region;
+
+	/* Default values */
+	board_id = "U12H072T00_NETGEAR";
+	region = 1;	/* 1=WW, 2=NA */
+	output_file = NULL;
+	kern_file = NULL;
+	fs_file = NULL;
+	fs_fp = NULL;
+
+	while ((opt = getopt (argc, argv, ":b:r:k:f:o:h")) != -1) {
+		switch (opt) {
+		    case 'b':
+		    	/* Board Identity */
+			if (strlen (optarg) > MAX_BOARD_ID_LEN) {
+				fatal_error (0, "Board lenght exceeds %d", 
+					MAX_BOARD_ID_LEN);
+			}
+			board_id = optarg;
+			break;
+
+		    case 'r':
+		    	/* Region */
+			errno = 0;
+			region = strtoul (optarg, &ptr, 0);
+			if (errno || ptr==optarg || *ptr!='\0') {
+				fatal_error (0, "Cannot parse region %s", optarg);
+			}
+			if (region > 0xff) {
+				fatal_error (0, "Region cannot exceed 0xff");
+			}
+			break;
+
+		    case 'k':
+		    	/* Kernel */
+			kern_file = optarg;
+			break;
+
+		    case 'f':
+		    	/* Filing System */
+			fs_file = optarg;
+			break;
+
+		    case 'o':
+		    	/* Output file */
+			output_file = optarg;
+			break;
+
+		    case 'h':
+		    	print_help ();
+			return EXIT_SUCCESS;
+
+		    case ':':
+		    	print_help ();
+		    	fatal_error (0, "Option -%c missing argument", optopt);
+			break;
+
+		    case '?':
+		    	print_help ();
+		    	fatal_error (0, "Unknown argument -%c", optopt);
+			break;
+		    
+		    default:
+		    	break;
+		}
+	}
+
+	/* Check we have all the options expected */
+	if (!kern_file) {
+		print_help ();
+		fatal_error (0, "Kernel file expected");
+	}
+	if (!output_file) {
+		print_help ();
+		fatal_error (0, "Output file required");
+	}
+	message ("Netgear CHK writer - v0.1");
+
+	/* Open the input file */
+	kern_fp = fopen (kern_file, "r");
+	if (!kern_fp) {
+		fatal_error (errno, "Cannot open %s", kern_file);
+	}
+
+	/* Open the fs file, if specified */
+	if (fs_file) {
+		fs_fp = fopen (fs_file, "r");
+		if (!fs_fp) {
+			fatal_error (errno, "Cannot open %s", fs_file);
+		}
+	}
+
+	/* Open the output file */
+	out_fp = fopen (output_file, "w+");
+	if (!out_fp) {
+		fatal_error (errno, "Cannot open %s", output_file);
+	}
+
+	/* Write zeros when the chk header will be */
+	buf[0] = '\0';
+	header_len = sizeof (struct chk_header) + strlen (board_id);
+	if (fwrite (buf, 1, header_len, out_fp) != header_len) {
+		fatal_error (errno, "Cannot write header");
+	}
+
+	/* Allocate storage for header, we fill in as we go */
+	hdr = malloc (sizeof (struct chk_header));
+	if (!hdr) {
+		fatal_error (0, "malloc failed");
+	}
+	bzero (hdr, sizeof (struct chk_header));
+
+	/* Fill in known values */
+	hdr->magic = htonl (0x2a23245e);
+	hdr->header_len = htonl(header_len);
+	hdr->reserved[0] = (unsigned char)(region & 0xff);
+	hdr->reserved[1] = 1;		/* Major */
+	hdr->reserved[2] = 1;		/* Minor */
+	hdr->reserved[3] = 99;		/* Build */
+	hdr->reserved[4] = 0;		/* Unknown t1 ? was 1 */
+	hdr->reserved[5] = 0;		/* Unknonw t2 ? was 0 */
+	hdr->reserved[6] = 0;		/* Unknonw t3 ? was 1 */
+	hdr->reserved[7] = 0;		/* Unused ? */
+	message ("       Board Id: %s", board_id);
+	message ("         Region: %s", region == 1 ? "World Wide (WW)" 
+			: (region == 2 ? "North America (NA)" : "Unknown"));
+
+	/* Copy the trx file, calculating the checksum as we go */
+	netgear_checksum_init (&chk_part);
+	netgear_checksum_init (&chk_whole);
+	while (!feof (kern_fp)) {
+		len = fread (buf, 1, BUF_LEN, kern_fp);
+		if (len < 1) {
+			break;
+		}
+		if (fwrite (buf, len, 1, out_fp) != 1) {
+			fatal_error (errno, "Write error");
+		}
+		hdr->kernel_len += len;
+		netgear_checksum_add (&chk_part, (unsigned char *)buf, len);
+		netgear_checksum_add (&chk_whole, (unsigned char *)buf, len);
+	}
+	hdr->kernel_chksum = netgear_checksum_fini (&chk_part);
+	message ("     Kernel Len: %u", hdr->kernel_len);
+	message ("Kernel Checksum: 0x%08x", hdr->kernel_chksum);
+	hdr->kernel_len = htonl (hdr->kernel_len);
+	hdr->kernel_chksum = htonl (hdr->kernel_chksum);
+
+	/* Now copy the root fs, calculating the checksum as we go */
+	if (fs_fp) {
+		netgear_checksum_init (&chk_part);
+		while (!feof (fs_fp)) {
+			len = fread (buf, 1, BUF_LEN, fs_fp);
+			if (len < 1) {
+				break;
+			}
+			if (fwrite (buf, len, 1, out_fp) != 1) {
+				fatal_error (errno, "Write error");
+			}
+			hdr->rootfs_len += len;
+			netgear_checksum_add (&chk_part, (unsigned char *)buf, len);
+			netgear_checksum_add (&chk_whole, (unsigned char *)buf, len);
+		}
+		hdr->rootfs_chksum = (netgear_checksum_fini (&chk_part));
+		message ("     Rootfs Len: %u", hdr->rootfs_len);
+		message ("Rootfs Checksum: 0x%08x", hdr->rootfs_chksum);
+		hdr->rootfs_len = htonl (hdr->rootfs_len);
+		hdr->rootfs_chksum = htonl (hdr->rootfs_chksum);
+	}
+
+	/* Calcautate the image checksum */
+	hdr->image_chksum = netgear_checksum_fini (&chk_whole);
+	message (" Image Checksum: 0x%08x", hdr->image_chksum);
+	hdr->image_chksum = htonl (hdr->image_chksum);
+
+	/* Calculate the header checksum */
+	netgear_checksum_init (&chk_part);
+	netgear_checksum_add (&chk_part, (unsigned char *)hdr, 
+				sizeof (struct chk_header));
+	netgear_checksum_add (&chk_part, (unsigned char *)board_id,
+				strlen (board_id));
+	hdr->header_chksum = htonl (netgear_checksum_fini (&chk_part));
+
+	/* Finally rewind the output and write headers */
+	rewind (out_fp);
+	if (fwrite (hdr, sizeof (struct chk_header), 1, out_fp) != 1) {
+		fatal_error (errno, "Cannot write header");
+	}
+	if (fwrite (board_id, strlen (board_id), 1, out_fp) != 1) {
+		fatal_error (errno, "Cannot write board id");
+	}
+
+	/* Success */
+	return EXIT_SUCCESS;
+}
+
diff --git a/tools/firmware-utils/src/mkcsysimg.c b/tools/firmware-utils/src/mkcsysimg.c
new file mode 100644
index 0000000000..77fbbaa57f
--- /dev/null
+++ b/tools/firmware-utils/src/mkcsysimg.c
@@ -0,0 +1,1157 @@
+/*
+ *
+ *  Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program was based on the code found in various Linux
+ *  source tarballs released by Edimax for it's devices.
+ *  Original author: David Hsu <davidhsu@realtek.com.tw>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the
+ *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#include "csysimg.h"
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE16_TO_HOST(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#else
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE16_TO_HOST(x)	bswap_16(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#endif
+
+#define MAX_NUM_BLOCKS	8
+#define MAX_ARG_COUNT	32
+#define MAX_ARG_LEN	1024
+#define FILE_BUF_LEN	(16*1024)
+#define CSYS_PADC	0xFF
+
+#define BLOCK_TYPE_BOOT	0
+#define BLOCK_TYPE_CONF	1
+#define BLOCK_TYPE_WEBP	2
+#define BLOCK_TYPE_CODE	3
+#define BLOCK_TYPE_XTRA	4
+
+#define DEFAULT_BLOCK_ALIGN	0x10000U
+
+#define CSUM_SIZE_NONE	0
+#define CSUM_SIZE_8	1
+#define CSUM_SIZE_16	2
+
+
+struct csum_state{
+	int	size;
+	uint16_t val;
+	uint16_t tmp;
+	int	odd;
+};
+
+
+struct csys_block {
+	int		type;	/* type of the block */
+
+	int		need_file;
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+
+	unsigned char	sig[SIG_LEN];
+	uint32_t	addr;
+	int		addr_set;
+	uint32_t	align;
+	int		align_set;
+	uint8_t		padc;
+
+	uint32_t	size;
+	uint32_t	size_hdr;
+	uint32_t	size_csum;
+	uint32_t	size_avail;
+
+	struct csum_state *css;
+};
+
+
+struct board_info {
+	char *model;
+	char *name;
+	uint32_t flash_size;
+
+	char sig_boot[SIG_LEN];
+	char sig_conf[SIG_LEN];
+	char sig_webp[SIG_LEN];
+
+	uint32_t boot_size;
+	uint32_t conf_size;
+	uint32_t webp_size;
+	uint32_t webp_size_max;
+	uint32_t code_size;
+
+	uint32_t addr_code;
+	uint32_t addr_webp;
+};
+
+#define BOARD(m, n, f, sigb, sigw, bs, cs, ws, ac, aw) {\
+	.model = m, .name = n, .flash_size = f<<20, \
+	.sig_boot = sigb, .sig_conf = SIG_CONF, .sig_webp = sigw, \
+	.boot_size = bs, .conf_size = cs, \
+	.webp_size = ws, .webp_size_max = 3*0x10000, \
+	.addr_code = ac, .addr_webp = aw \
+	}
+
+#define BOARD_ADM(m,n,f, sigw) BOARD(m,n,f, ADM_BOOT_SIG, sigw, \
+	ADM_BOOT_SIZE, ADM_CONF_SIZE, ADM_WEBP_SIZE, \
+	ADM_CODE_ADDR, ADM_WEBP_ADDR)
+
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname = NULL;
+int verblevel = 0;
+int invalid_causes_error = 1;
+int keep_invalid_images = 0;
+
+struct board_info *board = NULL;
+
+struct csys_block *boot_block = NULL;
+struct csys_block *conf_block = NULL;
+struct csys_block *webp_block = NULL;
+struct csys_block *code_block = NULL;
+
+struct csys_block blocks[MAX_NUM_BLOCKS];
+int num_blocks = 0;
+
+static struct board_info boards[] = {
+	/* The original Edimax products */
+	BOARD_ADM("BR-6104K", "Edimax BR-6104K", 2, SIG_BR6104K),
+	BOARD_ADM("BR-6104KP", "Edimax BR-6104KP", 2, SIG_BR6104KP),
+	BOARD_ADM("BR-6104Wg", "Edimax BR-6104Wg", 2, SIG_BR6104Wg),
+	BOARD_ADM("BR-6114WG", "Edimax BR-6114WG", 2, SIG_BR6114WG),
+	BOARD_ADM("BR-6524K", "Edimax BR-6524K", 2, SIG_BR6524K),
+	BOARD_ADM("BR-6524KP", "Edimax BR-6524KP", 2, SIG_BR6524KP),
+	BOARD_ADM("BR-6524N", "Edimax BR-6524N", 2, SIG_BR6524N),
+	BOARD_ADM("BR-6524WG", "Edimax BR-6524WG", 4, SIG_BR6524WG),
+	BOARD_ADM("BR-6524WP", "Edimax BR-6524WP", 4, SIG_BR6524WP),
+	BOARD_ADM("BR-6541K", "Edimax BR-6541K", 2, SIG_BR6541K),
+	BOARD_ADM("BR-6541KP", "Edimax BR-6541K", 2, SIG_BR6541KP),
+	BOARD_ADM("BR-6541WP", "Edimax BR-6541WP", 4, SIG_BR6541WP),
+	BOARD_ADM("EW-7207APg", "Edimax EW-7207APg", 2, SIG_EW7207APg),
+	BOARD_ADM("PS-1205UWg", "Edimax PS-1205UWg", 2, SIG_PS1205UWg),
+	BOARD_ADM("PS-3205U", "Edimax PS-3205U", 2, SIG_PS3205U),
+	BOARD_ADM("PS-3205UWg", "Edimax PS-3205UWg", 2, SIG_PS3205UWg),
+
+	/* Hawking products */
+	BOARD_ADM("H2BR4", "Hawking H2BR4", 2, SIG_H2BR4),
+	BOARD_ADM("H2WR54G", "Hawking H2WR54G", 4, SIG_H2WR54G),
+
+	/* Planet products */
+	BOARD_ADM("XRT-401D", "Planet XRT-401D", 2, SIG_XRT401D),
+	BOARD_ADM("XRT-402D", "Planet XRT-402D", 2, SIG_XRT402D),
+
+	/* Conceptronic products */
+	BOARD_ADM("C54BSR4", "Conceptronic C54BSR4", 2, SIG_C54BSR4),
+
+	/* OSBRiDGE products */
+	BOARD_ADM("5GXi", "OSBDRiDGE 5GXi", 2, SIG_5GXI),
+
+	{.model = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", progname, ## __VA_ARGS__ \
+		, strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+	fprintf(stderr, "[%s] *** warning: " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+	if (verblevel < lev) \
+		break;\
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL		-1
+#define ERR_INVALID_IMAGE	-2
+
+void
+usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+	);
+	for (board = boards; board->model != NULL; board++){
+		fprintf(stream,
+"                  %-12s: %s\n",
+		 board->model, board->name);
+	};
+	fprintf(stream,
+"  -d              don't throw error on invalid images\n"
+"  -k              keep invalid images\n"
+"  -b <file>[:<align>[:<padc>]]\n"
+"                  add boot code to the image\n"
+"  -c <file>[:<align>[:<padc>]]\n"
+"                  add configuration settings to the image\n"
+"  -r <file>:[<addr>][:<align>[:<padc>]]\n"
+"                  add runtime code to the image\n"
+"  -w [<file>:[<addr>][:<align>[:<padc>]]]\n"
+"                  add webpages to the image\n"
+"  -x <file>[:<align>[:<padc>]]\n"
+"                  add extra data at the end of the image\n"
+"  -h              show this screen\n"
+"Parameters:\n"
+"  <file>          write output to the file <file>\n"
+	);
+
+	exit(status);
+}
+
+static inline uint32_t align(uint32_t base, uint32_t alignment)
+{
+	uint32_t ret;
+
+	if (alignment) {
+		ret = (base + alignment - 1);
+		ret &= ~(alignment-1);
+	} else {
+		ret = base;
+	}
+
+	return ret;
+}
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+		return -1;
+	}
+
+	*val = t & 0xFFFF;
+	return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+		return -1;
+	}
+
+	*val = t & 0xFF;
+	return 0;
+}
+
+int
+str2sig(char *arg, uint32_t *sig)
+{
+	if (strlen(arg) != 4)
+		return -1;
+
+	*sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
+
+	return 0;
+}
+
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+	int res = 0;
+	size_t argl;
+	char *tok;
+	char **ap = &buf;
+	int i;
+
+	memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+	if ((arg == NULL)) {
+		/* no arguments */
+		return 0;
+	}
+
+	argl = strlen(arg);
+	if (argl == 0) {
+		/* no arguments */
+		return 0;
+	}
+
+	if (argl >= MAX_ARG_LEN) {
+		/* argument is too long */
+		argl = MAX_ARG_LEN-1;
+	}
+
+	memcpy(buf, arg, argl);
+	buf[argl] = '\0';
+
+	for (i = 0; i < MAX_ARG_COUNT; i++) {
+		tok = strsep(ap, ":");
+		if (tok == NULL) {
+			break;
+		}
+#if 0
+		else if (tok[0] == '\0') {
+			break;
+		}
+#endif
+		argv[i] = tok;
+		res++;
+	}
+
+	return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+	if (arg == NULL || *arg != '-')
+		return 0;
+
+	ERR("option -%c requires an argument\n", c);
+	return ERR_FATAL;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+	int ret = 1;
+	if (arg != NULL) {
+		if (*arg) ret = 0;
+	};
+	return ret;
+}
+
+
+void
+csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	for ( ; len > 0; len --) {
+		css->val += *p++;
+	}
+}
+
+
+uint16_t
+csum8_get(struct csum_state *css)
+{
+	uint8_t t;
+
+	t = css->val;
+	return ~t + 1;
+}
+
+
+void
+csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	uint16_t t;
+
+	if (css->odd) {
+		t = css->tmp + (p[0]<<8);
+		css->val += LE16_TO_HOST(t);
+		css->odd = 0;
+		len--;
+		p++;
+	}
+
+	for ( ; len > 1; len -= 2, p +=2 ) {
+		t = p[0] + (p[1] << 8);
+		css->val += LE16_TO_HOST(t);
+	}
+
+	if (len == 1) {
+		css->tmp = p[0];
+		css->odd = 1;
+	}
+}
+
+
+uint16_t
+csum16_get(struct csum_state *css)
+{
+	char pad = 0;
+
+	csum16_update(&pad, 1, css);
+	return ~css->val + 1;
+}
+
+
+void
+csum_init(struct csum_state *css, int size)
+{
+	css->val = 0;
+	css->tmp = 0;
+	css->odd = 0;
+	css->size = size;
+}
+
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	switch (css->size) {
+	case CSUM_SIZE_8:
+		csum8_update(p,len,css);
+		break;
+	case CSUM_SIZE_16:
+		csum16_update(p,len,css);
+		break;
+	}
+}
+
+
+uint16_t
+csum_get(struct csum_state *css)
+{
+	uint16_t ret;
+
+	switch (css->size) {
+	case CSUM_SIZE_8:
+		ret = csum8_get(css);
+		break;
+	case CSUM_SIZE_16:
+		ret = csum16_get(css);
+		break;
+	}
+
+	return ret;
+}
+
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+		struct csum_state *css)
+{
+	errno = 0;
+
+	fwrite(data, len, 1, outfile);
+	if (errno) {
+		ERRS("unable to write output file");
+		return ERR_FATAL;
+	}
+
+	if (css) {
+		csum_update(data, len, css);
+	}
+
+	return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+		 struct csum_state *css)
+{
+	uint8_t buf[512];
+	size_t buflen = sizeof(buf);
+	int err;
+
+	memset(buf, padc, buflen);
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		err = write_out_data(outfile, buf, buflen, css);
+		if (err)
+			return err;
+
+		len -= buflen;
+	}
+
+	return 0;
+}
+
+
+int
+block_stat_file(struct csys_block *block)
+{
+	struct stat st;
+	int err;
+
+	if (block->file_name == NULL)
+		return 0;
+
+	err = stat(block->file_name, &st);
+	if (err){
+		ERRS("stat failed on %s", block->file_name);
+		return ERR_FATAL;
+	}
+
+	block->file_size = st.st_size;
+	return 0;
+}
+
+
+int
+block_writeout_hdr(FILE *outfile, struct csys_block *block)
+{
+	struct csys_header hdr;
+	int res;
+
+	if (block->size_hdr == 0)
+		return 0;
+
+	/* setup header fields */
+	memcpy(hdr.sig, block->sig, 4);
+	hdr.addr = HOST_TO_LE32(block->addr);
+	hdr.size = HOST_TO_LE32(block->size - block->size_hdr - block->size_csum);
+
+	DBG(1,"writing header for block");
+	res = write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr),NULL);
+	return res;
+
+}
+
+
+int
+block_writeout_file(FILE *outfile, struct csys_block *block)
+{
+	char buf[FILE_BUF_LEN];
+	size_t buflen = sizeof(buf);
+	FILE *f;
+	size_t len;
+	int res;
+
+	if (block->file_name == NULL)
+		return 0;
+
+	if (block->file_size == 0)
+		return 0;
+
+	errno = 0;
+	f = fopen(block->file_name,"r");
+	if (errno) {
+		ERRS("unable to open file: %s", block->file_name);
+		return ERR_FATAL;
+	}
+
+	len = block->file_size;
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		/* read data from source file */
+		errno = 0;
+		fread(buf, buflen, 1, f);
+		if (errno != 0) {
+			ERRS("unable to read from file: %s", block->file_name);
+			res = ERR_FATAL;
+			break;
+		}
+
+		res = write_out_data(outfile, buf, buflen, block->css);
+		if (res)
+			break;
+
+		len -= buflen;
+	}
+
+	fclose(f);
+	return res;
+}
+
+
+int
+block_writeout_data(FILE *outfile, struct csys_block *block)
+{
+	int res;
+	size_t padlen;
+
+	res = block_writeout_file(outfile, block);
+	if (res)
+		return res;
+
+	/* write padding data if neccesary */
+	padlen = block->size_avail - block->file_size;
+	DBG(1,"padding block, length=%zu", padlen);
+	res = write_out_padding(outfile, padlen, block->padc, block->css);
+
+	return res;
+}
+
+
+int
+block_writeout_csum(FILE *outfile, struct csys_block *block)
+{
+	uint16_t csum;
+	int res;
+
+	if (block->size_csum == 0)
+		return 0;
+
+	DBG(1,"writing checksum for block");
+	csum = HOST_TO_LE16(csum_get(block->css));
+	res = write_out_data(outfile, (uint8_t *)&csum, block->size_csum, NULL);
+
+	return res;
+}
+
+
+int
+block_writeout(FILE *outfile, struct csys_block *block)
+{
+	int res;
+	struct csum_state css;
+
+	res = 0;
+
+	if (block == NULL)
+		return res;
+
+	block->css = NULL;
+
+	DBG(2, "writing block, file=%s, file_size=%d, space=%d",
+		block->file_name, block->file_size, block->size_avail);
+	res = block_writeout_hdr(outfile, block);
+	if (res)
+		return res;
+
+	if (block->size_csum != 0) {
+		block->css = &css;
+		csum_init(&css, block->size_csum);
+	}
+
+	res = block_writeout_data(outfile, block);
+	if (res)
+		return res;
+
+	res = block_writeout_csum(outfile, block);
+	if (res)
+		return res;
+
+	return res;
+}
+
+
+int
+write_out_blocks(FILE *outfile)
+{
+	struct csys_block *block;
+	int i, res;
+
+	res = block_writeout(outfile, boot_block);
+	if (res)
+		return res;
+
+	res = block_writeout(outfile, conf_block);
+	if (res)
+		return res;
+
+	res = block_writeout(outfile, webp_block);
+	if (res)
+		return res;
+
+	res = block_writeout(outfile, code_block);
+	if (res)
+		return res;
+
+	res = 0;
+	for (i=0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		if (block->type != BLOCK_TYPE_XTRA)
+			continue;
+
+		res = block_writeout(outfile, block);
+		if (res)
+			break;
+	}
+
+	return res;
+}
+
+
+struct board_info *
+find_board(char *model)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->model != NULL; board++){
+		if (strcasecmp(model, board->model) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+	DBG(1,"parsing board option: -%c %s", ch, arg);
+
+	if (board != NULL) {
+		ERR("only one board option allowed");
+		return ERR_FATAL;
+	}
+
+	if (required_arg(ch, arg))
+		return ERR_FATAL;
+
+	board = find_board(arg);
+	if (board == NULL){
+		ERR("invalid/unknown board specified: %s", arg);
+		return ERR_FATAL;
+	}
+
+	return 0;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	char *p;
+	struct csys_block *block;
+	int i;
+
+	if ( num_blocks > MAX_NUM_BLOCKS ) {
+		ERR("too many blocks specified");
+		return ERR_FATAL;
+	}
+
+	block = &blocks[num_blocks];
+
+	/* setup default field values */
+	block->need_file = 1;
+	block->padc = 0xFF;
+
+	switch (ch) {
+	case 'b':
+		if (boot_block) {
+			WARN("only one boot block allowed");
+			break;
+		}
+		block->type = BLOCK_TYPE_BOOT;
+		boot_block = block;
+		break;
+	case 'c':
+		if (conf_block) {
+			WARN("only one config block allowed");
+			break;
+		}
+		block->type = BLOCK_TYPE_CONF;
+		conf_block = block;
+		break;
+	case 'w':
+		if (webp_block) {
+			WARN("only one web block allowed");
+			break;
+		}
+		block->type = BLOCK_TYPE_WEBP;
+		block->size_hdr = sizeof(struct csys_header);
+		block->size_csum = CSUM_SIZE_8;
+		block->need_file = 0;
+		webp_block = block;
+		break;
+	case 'r':
+		if (code_block) {
+			WARN("only one runtime block allowed");
+			break;
+		}
+		block->type = BLOCK_TYPE_CODE;
+		block->size_hdr = sizeof(struct csys_header);
+		block->size_csum = CSUM_SIZE_16;
+		code_block = block;
+		break;
+	case 'x':
+		block->type = BLOCK_TYPE_XTRA;
+		break;
+	default:
+		ERR("unknown block type \"%c\"", ch);
+		return ERR_FATAL;
+	}
+
+	argc = parse_arg(arg, buf, argv);
+
+	i = 0;
+	p = argv[i++];
+	if (!is_empty_arg(p)) {
+		block->file_name = strdup(p);
+		if (block->file_name == NULL) {
+			ERR("not enough memory");
+			return ERR_FATAL;
+		}
+	} else if (block->need_file){
+		ERR("no file specified in %s", arg);
+		return ERR_FATAL;
+	}
+
+	if (block->size_hdr) {
+		p = argv[i++];
+		if (!is_empty_arg(p)) {
+			if (str2u32(p, &block->addr) != 0) {
+				ERR("invalid start address in %s", arg);
+				return ERR_FATAL;
+			}
+			block->addr_set = 1;
+		}
+	}
+
+	p = argv[i++];
+	if (!is_empty_arg(p)) {
+		if (str2u32(p, &block->align) != 0) {
+			ERR("invalid alignment value in %s", arg);
+			return ERR_FATAL;
+		}
+		block->align_set = 1;
+	}
+
+	p = argv[i++];
+	if (!is_empty_arg(p) && (str2u8(p, &block->padc) != 0)) {
+		ERR("invalid paddig character in %s", arg);
+		return ERR_FATAL;
+	}
+
+	num_blocks++;
+
+	return 0;
+}
+
+
+int
+process_blocks(void)
+{
+	struct csys_block *block;
+	uint32_t offs = 0;
+	int i;
+	int res;
+
+	res = 0;
+	/* collecting stats */
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+		res = block_stat_file(block);
+		if (res)
+			return res;
+	}
+
+	/* bootloader */
+	block = boot_block;
+	if (block) {
+		block->size = board->boot_size;
+		if (block->file_size > board->boot_size) {
+			WARN("boot block is too big");
+			res = ERR_INVALID_IMAGE;
+		}
+	}
+	offs += board->boot_size;
+
+	/* configuration data */
+	block = conf_block;
+	if (block) {
+		block->size = board->conf_size;
+		if (block->file_size > board->conf_size) {
+			WARN("config block is too big");
+			res = ERR_INVALID_IMAGE;
+		}
+	}
+	offs += board->conf_size;
+
+	/* webpages */
+	block = webp_block;
+	if (block) {
+
+		memcpy(block->sig, board->sig_webp, 4);
+
+		if (block->addr_set == 0)
+			block->addr = board->addr_webp;
+
+		if (block->align_set == 0)
+			block->align = DEFAULT_BLOCK_ALIGN;
+
+		block->size = align(offs + block->file_size + block->size_hdr +
+				block->size_csum, block->align) - offs;
+
+		if (block->size > board->webp_size_max) {
+			WARN("webpages block is too big");
+			res = ERR_INVALID_IMAGE;
+		}
+
+		DBG(2,"webpages start at %08x, size=%08x", offs,
+				block->size);
+
+		offs += block->size;
+		if (offs > board->flash_size) {
+			WARN("webp block is too big");
+			res = ERR_INVALID_IMAGE;
+		}
+	}
+
+	/* runtime code */
+	block = code_block;
+	if (block) {
+		memcpy(code_block->sig, SIG_CSYS, 4);
+
+		if (block->addr_set == 0)
+			block->addr = board->addr_code;
+
+		if (block->align_set == 0)
+			block->align = DEFAULT_BLOCK_ALIGN;
+
+		block->size = align(offs + block->file_size +
+				block->size_hdr + block->size_csum,
+				block->align) - offs;
+
+		DBG(2,"code block start at %08x, size=%08x", offs,
+				block->size);
+
+		offs += block->size;
+		if (offs > board->flash_size) {
+			WARN("code block is too big");
+			res = ERR_INVALID_IMAGE;
+		}
+	}
+
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		if (block->type != BLOCK_TYPE_XTRA)
+			continue;
+
+		if (block->align_set == 0)
+			block->align = DEFAULT_BLOCK_ALIGN;
+
+		block->size = align(offs + block->file_size,
+				block->align) - offs;
+
+		DBG(2,"file %s start at %08x, size=%08x, align=%08x",
+			block->file_name, offs, block->size, block->align);
+
+		offs += block->size;
+		if (offs > board->flash_size) {
+			WARN("file %s is too big, size=%d, avail=%d",
+				block->file_name, block->file_size,
+				board->flash_size - offs);
+			res = ERR_INVALID_IMAGE;
+		}
+	}
+
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		block->size_avail = block->size - block->size_hdr -
+			block->size_csum;
+
+		if (block->size_avail < block->file_size) {
+			WARN("file %s is too big, size=%d, avail=%d",
+				block->file_name, block->file_size,
+				block->size_avail);
+			res = ERR_INVALID_IMAGE;
+		}
+	}
+
+	return res;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	int optinvalid = 0;   /* flag for invalid option */
+	int c;
+	int res = ERR_FATAL;
+
+	FILE *outfile;
+
+	progname=basename(argv[0]);
+
+	opterr = 0;  /* could not print standard getopt error messages */
+	while ( 1 ) {
+		optinvalid = 0;
+
+		c = getopt(argc, argv, "b:B:c:dhkr:vw:x:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'b':
+		case 'c':
+		case 'r':
+		case 'x':
+			optinvalid = parse_opt_block(c,optarg);
+			break;
+		case 'w':
+			if (optarg != NULL && *optarg == '-') {
+				/* rollback */
+				optind--;
+				optarg = NULL;
+			}
+			optinvalid = parse_opt_block(c,optarg);
+			break;
+		case 'd':
+			invalid_causes_error = 0;
+			break;
+		case 'k':
+			keep_invalid_images = 1;
+			break;
+		case 'B':
+			optinvalid = parse_opt_board(c,optarg);
+			break;
+		case 'v':
+			verblevel++;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			optinvalid = 1;
+			break;
+		}
+		if (optinvalid != 0 ){
+			ERR("invalid option: -%c", optopt);
+			goto out;
+		}
+	}
+
+	if (board == NULL) {
+		ERR("no board specified");
+		goto out;
+	}
+
+	if (optind == argc) {
+		ERR("no output file specified");
+		goto out;
+	}
+
+	ofname = argv[optind++];
+
+	if (optind < argc) {
+		ERR("invalid option: %s", argv[optind]);
+		goto out;
+	}
+
+	res = process_blocks();
+	if (res == ERR_FATAL)
+		goto out;
+
+	if (res == ERR_INVALID_IMAGE) {
+		if (invalid_causes_error)
+			res = ERR_FATAL;
+
+		if (keep_invalid_images == 0) {
+			WARN("generation of invalid images \"%s\" disabled", ofname);
+			goto out;
+		}
+
+		WARN("generating invalid image: \"%s\"", ofname);
+	}
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		res = ERR_FATAL;
+		goto out;
+	}
+
+	if (write_out_blocks(outfile) != 0) {
+		res = ERR_FATAL;
+		goto out_flush;
+	}
+
+	DBG(1,"Image file %s completed.", ofname);
+
+out_flush:
+	fflush(outfile);
+	fclose(outfile);
+	if (res == ERR_FATAL) {
+		unlink(ofname);
+	}
+out:
+	if (res == ERR_FATAL)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/mkdapimg.c b/tools/firmware-utils/src/mkdapimg.c
new file mode 100644
index 0000000000..ed662d8ecc
--- /dev/null
+++ b/tools/firmware-utils/src/mkdapimg.c
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>	// htonl
+
+// Usage: mkdapimg [-p] [-m <model>] -s <sig> -i <input> -o <output>
+//
+// e.g.: mkdapimg -s RT3052-AP-DAP1350-3 -i sysupgarde.bin -o factory.bin
+//
+// If the model string <model> is not given, we will assume that
+// the leading characters upto the first "-" is the model.
+//
+// The "-p" (patch) option is used to patch the exisiting image with the
+// specified model and signature.
+// The "-x" (fix) option will recalculate the payload size and checksum
+// during the patch mode operation.
+
+// The img_hdr_struct was taken from the D-Link SDK:
+// DAP-1350_A1_FW1.11NA_GPL/GPL_Source_Code/Uboot/DAP-1350/httpd/header.h
+
+#define MAX_MODEL_NAME_LEN	20
+#define MAX_SIG_LEN		30
+#define MAX_REGION_LEN		4
+#define MAX_VERSION_LEN		12
+
+struct img_hdr_struct {
+	uint32_t checksum;
+	char model[MAX_MODEL_NAME_LEN];
+	char sig[MAX_SIG_LEN];
+	uint8_t	partition;       
+	uint8_t hdr_len;
+	uint8_t rsv1;
+	uint8_t rsv2;    
+	uint32_t flash_byte_cnt;  
+} imghdr ;
+
+char *progname;
+
+void
+perrexit(int code, char *msg)
+{
+	fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno));
+	exit(code);
+}
+
+void
+usage()
+{
+	fprintf(stderr, "usage: %s [-p] [-m model] [-r region] [-v version] -s signature -i input -o output\n", progname);
+	exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+	char model[MAX_MODEL_NAME_LEN+1];
+	char signature[MAX_SIG_LEN+1];
+	char region[MAX_REGION_LEN+1];
+	char version[MAX_VERSION_LEN+1];
+	int patchmode = 0;
+	int fixmode = 0;
+	int have_regionversion = 0;
+
+	FILE *ifile, *ofile;
+	int c;
+	uint32_t cksum;
+	uint32_t bcnt;
+
+	progname = basename(av[0]);
+	memset(model, 0, sizeof(model));
+	memset(signature, 0, sizeof(signature));
+	memset(region, 0, sizeof(region));
+	memset(version, 0, sizeof(version));
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(ac, av, "pxm:r:v:s:i:o:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'p':
+			patchmode = 1;
+			break;
+		case 'x':
+			fixmode = 1;
+			break;
+		case 'm':
+			if (strlen(optarg) > MAX_MODEL_NAME_LEN) {
+				fprintf(stderr, "%s: model name exceeds %d chars\n",
+					progname, MAX_MODEL_NAME_LEN);
+				exit(1);
+			}
+			strcpy(model, optarg);
+			break;
+		case 'r':
+			if (strlen(optarg) > MAX_REGION_LEN) {
+				fprintf(stderr, "%s: region exceeds %d chars\n",
+					progname, MAX_REGION_LEN);
+				exit(1);
+			}
+			have_regionversion = 1;
+			strcpy(region, optarg);
+			break;
+		case 'v':
+			if (strlen(optarg) > MAX_VERSION_LEN) {
+				fprintf(stderr, "%s: version exceeds %d chars\n",
+					progname, MAX_VERSION_LEN);
+				exit(1);
+			}
+			have_regionversion = 1;
+			strcpy(version, optarg);
+			break;
+		case 's':
+			if (strlen(optarg) > MAX_SIG_LEN) {
+				fprintf(stderr, "%s: signature exceeds %d chars\n",
+					progname, MAX_SIG_LEN);
+				exit(1);
+			}
+			strcpy(signature, optarg);
+			break;
+		case 'i':
+			if ((ifile = fopen(optarg, "r")) == NULL)
+				perrexit(1, optarg);
+			break;
+		case 'o':
+			if ((ofile = fopen(optarg, "w")) == NULL)
+				perrexit(1, optarg);
+			break;
+		default:
+			usage();
+		}
+	}
+
+	if (signature[0] == 0 || ifile == NULL || ofile == NULL) {
+		usage();
+	}
+
+	if (model[0] == 0) {
+		char *p = strchr(signature, '-');
+		if (p == NULL) {
+			fprintf(stderr, "%s: model name unknown\n", progname);
+			exit(1);
+		}
+		if (p - signature > MAX_MODEL_NAME_LEN) {
+			*p = 0;
+			fprintf(stderr, "%s: auto model name failed, string %s too long\n", progname, signature);
+			exit(1);
+		}
+		strncpy(model, signature, p - signature);
+	}
+
+	if (patchmode) {
+		if (fread(&imghdr, sizeof(imghdr), 1, ifile) < 0)
+			perrexit(2, "fread on input");
+	}
+
+	for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
+		cksum += c & 0xff;
+
+	if (fseek(ifile, patchmode ? sizeof(imghdr) : 0, SEEK_SET) < 0)
+		perrexit(2, "fseek on input");
+
+	if (patchmode == 0) {
+		// Fill in the header
+		memset(&imghdr, 0, sizeof(imghdr));
+		imghdr.checksum = htonl(cksum);
+		imghdr.partition = 0 ; // don't care?
+		imghdr.hdr_len = sizeof(imghdr);
+		if (have_regionversion) {
+			imghdr.hdr_len += MAX_REGION_LEN;
+			imghdr.hdr_len += MAX_VERSION_LEN;
+		}
+		imghdr.flash_byte_cnt = htonl(bcnt);
+	} else {
+		if (ntohl(imghdr.checksum) != cksum) {
+			fprintf(stderr, "%s: patch mode, checksum mismatch\n",
+				progname);
+			if (fixmode) {
+				fprintf(stderr, "%s: fixing\n", progname);
+				imghdr.checksum = htonl(cksum);
+			} else
+				exit(3);
+		} else if (ntohl(imghdr.flash_byte_cnt) != bcnt) {
+			fprintf(stderr, "%s: patch mode, size mismatch\n",
+				progname);
+			if (fixmode) {
+				fprintf(stderr, "%s: fixing\n", progname);
+				imghdr.flash_byte_cnt = htonl(bcnt);
+			} else
+				exit(3);
+		}
+	}
+
+	strncpy(imghdr.model, model, MAX_MODEL_NAME_LEN);
+	strncpy(imghdr.sig, signature, MAX_SIG_LEN);
+
+	if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0)
+		perrexit(2, "fwrite header on output");
+	if (have_regionversion) {
+		if (fwrite(&region, MAX_REGION_LEN, 1, ofile) < 0)
+			perrexit(2, "fwrite header on output");
+		if (fwrite(&version, MAX_VERSION_LEN, 1, ofile) < 0)
+			perrexit(2, "fwrite header on output");
+	}
+
+	while ((c = fgetc(ifile)) != EOF) {
+		if (fputc(c, ofile) == EOF)
+			perrexit(2, "fputc on output");
+	}
+
+	if (ferror(ifile))
+		perrexit(2, "fgetc on input");
+
+
+	fclose(ofile);
+	fclose(ifile);
+}
diff --git a/tools/firmware-utils/src/mkdcs932.c b/tools/firmware-utils/src/mkdcs932.c
new file mode 100644
index 0000000000..28c67aa3b3
--- /dev/null
+++ b/tools/firmware-utils/src/mkdcs932.c
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ * (C) John Crispin <blogic@openwrt.org>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+int main(int argc, char **argv)
+{
+	uint32_t t = 0, sum = 0x55aa55aa;
+	int fd;
+
+	if ((argc != 2) || ((fd = open(argv[1], O_RDWR)) == -1)) {
+		fprintf(stderr, "Usage: %s input_file\n", *argv);
+		return -EINVAL;
+	}
+
+	lseek(fd, -4, SEEK_END);
+	write(fd, &t, 4);
+	lseek(fd, 0, SEEK_SET);
+
+	while (read(fd, &t, 4) > 0)
+		sum -= t;
+
+	lseek(fd, -4, SEEK_END);
+	write(fd, &sum, 4);
+	close(fd);
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/mkdniimg.c b/tools/firmware-utils/src/mkdniimg.c
new file mode 100644
index 0000000000..852b07dd9f
--- /dev/null
+++ b/tools/firmware-utils/src/mkdniimg.c
@@ -0,0 +1,208 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#define DNI_HDR_LEN	128
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static char *version = "1.00.00";
+static char *region = "";
+static char *hd_id;
+
+static char *board_id;
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -v <version>    set image version to <version>\n"
+"  -r <region>     set image region to <region>\n"
+"  -H <hd_id>      set image hardware id to <hd_id>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int buflen;
+	int err;
+	struct stat st;
+	char *buf;
+	int pos, rem, i;
+	uint8_t csum;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "B:i:o:v:r:H:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'v':
+			version = optarg;
+			break;
+		case 'r':
+			region = optarg;
+			break;
+		case 'H':
+			hd_id = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (board_id == NULL) {
+		ERR("no board specified");
+		goto err;
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	buflen = st.st_size + DNI_HDR_LEN + 1;
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	memset(buf, 0, DNI_HDR_LEN);
+	pos = snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:V%s\nregion:%s\n",
+		       board_id, version, region);
+	rem = DNI_HDR_LEN - pos;
+	if (pos >= 0 && rem > 1 && hd_id) {
+		snprintf(buf + pos, rem, "hd_id:%s\n", hd_id);
+	}
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	errno = 0;
+	fread(buf +  DNI_HDR_LEN, st.st_size, 1, infile);
+	if (errno != 0) {
+		ERRS("unable to read from file %s", ifname);
+		goto err_close_in;
+	}
+
+	csum = 0;
+	for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++)
+		csum += buf[i];
+
+	csum = 0xff - csum;
+	buf[st.st_size + DNI_HDR_LEN] = csum;
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto err_close_in;
+	}
+
+	errno = 0;
+	fwrite(buf, buflen, 1, outfile);
+	if (errno) {
+		ERRS("unable to write to file %s", ofname);
+		goto err_close_out;
+	}
+
+	res = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(outfile);
+
+ err_close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+
+ err_close_in:
+	fclose(infile);
+
+ err_free:
+	free(buf);
+
+ err:
+	return res;
+}
diff --git a/tools/firmware-utils/src/mkedimaximg.c b/tools/firmware-utils/src/mkedimaximg.c
new file mode 100644
index 0000000000..d8a017e6a8
--- /dev/null
+++ b/tools/firmware-utils/src/mkedimaximg.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2011 Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>	/* for __BYTE_ORDER */
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#else
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#endif
+
+struct header
+{
+    unsigned char sign[4];
+    unsigned int start;
+    unsigned int flash;
+    unsigned char model[4];
+    unsigned int size;
+} __attribute__ ((packed));
+
+struct finfo
+{
+    char *name;
+    off_t size;
+};
+
+struct buf
+{
+    char *start;
+    size_t size;
+};
+
+static char *progname;
+
+static void usage(int status)
+{
+    FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+    fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+    fprintf(stream,
+	    "\n"
+	    "Options:\n"
+	    "  -s <sig>        set image signature to <sig>\n"
+	    "  -m <model>      set model to <model>\n"
+	    "  -i <file>       read input from file <file>\n"
+	    "  -o <file>       write output to file <file>\n"
+	    "  -f <flash>      set flash address to <flash>\n"
+	    "  -S <start>      set start address to <start>\n");
+
+    exit(status);
+}
+
+static int strtou32(char *arg, unsigned int *val)
+{
+    char *endptr = NULL;
+
+    errno = 0;
+    *val = strtoul(arg, &endptr, 0);
+    if (errno || (endptr == arg) || (*endptr && (endptr != NULL))) {
+	return EXIT_SUCCESS;
+    }
+
+    return EXIT_FAILURE;
+}
+
+static unsigned short fwcsum (struct buf *buf) {
+    int i;
+    unsigned short ret = 0;
+
+    for (i = 0; i < buf->size / 2; i++)
+	ret -= ((unsigned short *) buf->start)[i];
+    
+    return ret;
+}
+
+static int fwread(struct finfo *finfo, struct buf *buf)
+{
+    FILE *f;
+    
+    f = fopen(finfo->name, "r");
+    if (!f) {
+	fprintf(stderr, "could not open \"%s\" for reading\n", finfo->name);
+	usage(EXIT_FAILURE);
+    }
+
+    buf->size = fread(buf->start, 1, finfo->size, f);
+    if (buf->size != finfo->size) {
+	fprintf(stderr, "unable to read from file \"%s\"\n", finfo->name);
+	usage(EXIT_FAILURE);
+    }
+
+    fclose(f);
+
+    return EXIT_SUCCESS;
+}
+
+static int fwwrite(struct finfo *finfo, struct buf *buf)
+{
+    FILE *f;
+
+    f = fopen(finfo->name, "w");
+    if (!f) {
+	fprintf(stderr, "could not open \"%s\" for writing\n", finfo->name);
+	usage(EXIT_FAILURE);
+    }
+
+    buf->size = fwrite(buf->start, 1, finfo->size, f);
+    if (buf->size != finfo->size) {
+	fprintf(stderr, "unable to write to file \"%s\"\n", finfo->name);
+	usage(EXIT_FAILURE);
+    }
+
+    fclose(f);
+
+    return EXIT_SUCCESS;
+}	
+  
+int main(int argc, char **argv)
+{
+    struct stat st;
+    struct header header;
+    struct buf ibuf, obuf;
+    struct finfo ifinfo, ofinfo;
+    unsigned short csum;
+    int c;
+
+    ifinfo.name = ofinfo.name = NULL;
+    header.flash = header.size = header.start = 0;
+    progname = basename(argv[0]);
+
+    while((c = getopt(argc, argv, "i:o:m:s:f:S:h")) != -1) {
+	switch (c) {
+	case 'i':
+	    ifinfo.name = optarg;
+	    break;
+	case 'o':
+	    ofinfo.name = optarg;
+	    break;
+	case 'm':
+	    if (strlen(optarg) != 4) {
+		fprintf(stderr, "model must be 4 characters long\n");
+		usage(EXIT_FAILURE);
+	    }
+	    memcpy(header.model, optarg, 4);
+	    break;
+	case 's':
+	    if (strlen(optarg) != 4) {
+		fprintf(stderr, "signature must be 4 characters long\n");
+		usage(EXIT_FAILURE);
+	    }
+	    memcpy(header.sign, optarg, 4);
+	    break;
+	case 'h':
+	    usage(EXIT_SUCCESS);
+	    break;
+	case 'f':
+	    if (!strtou32(optarg, &header.flash)) {
+		fprintf(stderr, "invalid flash address specified\n");
+		usage(EXIT_FAILURE);
+	    }
+	    break;
+	case 'S':
+	    if (!strtou32(optarg, &header.start)) {
+		fprintf(stderr, "invalid start address specified\n");
+		usage(EXIT_FAILURE);
+	    }
+	    break;
+	default:
+	    usage(EXIT_FAILURE);
+	    break;
+	}
+    }
+
+    if (ifinfo.name == NULL) {
+	fprintf(stderr, "no input file specified\n");
+	usage(EXIT_FAILURE);
+    }
+
+    if (ofinfo.name == NULL) {
+	fprintf(stderr, "no output file specified\n");
+	usage(EXIT_FAILURE);
+    }
+
+    if (stat(ifinfo.name, &st)) {
+	fprintf(stderr, "stat failed on %s\n", ifinfo.name);
+	usage(EXIT_FAILURE);
+    }
+
+    if (header.sign == NULL) {
+	fprintf(stderr, "no signature specified\n");
+	usage(EXIT_FAILURE);
+    }
+
+    if (header.model == NULL) {
+	fprintf(stderr, "no model specified\n");
+	usage(EXIT_FAILURE);
+    }
+
+    if (!header.flash) {
+	fprintf(stderr, "no flash address specified\n");
+	usage(EXIT_FAILURE);
+    }
+
+    if (!header.start) {
+	fprintf(stderr, "no start address specified\n");
+	usage(EXIT_FAILURE);
+    }
+
+    ifinfo.size = st.st_size;
+
+    obuf.size = ifinfo.size + sizeof(struct header) + sizeof(unsigned short);
+    if (obuf.size % sizeof(unsigned short))
+	obuf.size++;
+
+    obuf.start = malloc(obuf.size);
+    if (!obuf.start) {
+	fprintf(stderr, "no memory for buffer\n");
+	usage(EXIT_FAILURE);
+    }
+    memset(obuf.start, 0, obuf.size);
+
+    ibuf.size = ifinfo.size;
+    ibuf.start = obuf.start + sizeof(struct header);
+    
+    if (fwread(&ifinfo, &ibuf))
+	usage(EXIT_FAILURE);
+
+    header.flash = HOST_TO_LE32(header.flash);
+    header.size = HOST_TO_LE32(obuf.size - sizeof(struct header));
+    header.start = HOST_TO_LE32(header.start);
+    memcpy (obuf.start, &header, sizeof(struct header));
+
+    csum = HOST_TO_LE16(fwcsum(&ibuf));
+    memcpy(obuf.start + obuf.size - sizeof(unsigned short),
+	   &csum, sizeof(unsigned short));
+
+    ofinfo.size = obuf.size;
+
+    if (fwwrite(&ofinfo, &obuf))
+	usage(EXIT_FAILURE);
+
+    return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/mkfwimage.c b/tools/firmware-utils/src/mkfwimage.c
new file mode 100644
index 0000000000..d8d5239cc5
--- /dev/null
+++ b/tools/firmware-utils/src/mkfwimage.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2007 Ubiquiti Networks, Inc.
+ * Copyright (C) 2008 Lukas Kuna <ValXdater@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "fw.h"
+
+typedef struct fw_layout_data {
+	char		name[PATH_MAX];
+	u_int32_t	kern_start;
+	u_int32_t	kern_entry;
+	u_int32_t	firmware_max_length;
+} fw_layout_t;
+
+fw_layout_t fw_layout_data[] = {
+	{
+		.name		=	"XS2",
+		.kern_start	=	0xbfc30000,
+		.kern_entry	=	0x80041000,
+		.firmware_max_length=	0x00390000,
+	},
+	{
+		.name		=	"XS5",
+		.kern_start	=	0xbe030000,
+		.kern_entry	=	0x80041000,
+		.firmware_max_length=	0x00390000,
+	},
+	{
+		.name		=	"RS",
+		.kern_start	=	0xbf030000,
+		.kern_entry	=	0x80060000,
+		.firmware_max_length=	0x00B00000,
+	},
+	{
+		.name		=	"RSPRO",
+		.kern_start	=	0xbf030000,
+		.kern_entry	=	0x80060000,
+		.firmware_max_length=	0x00F00000,
+	},
+	{
+		.name		=	"LS-SR71",
+		.kern_start	=	0xbf030000,
+		.kern_entry	=	0x80060000,
+		.firmware_max_length=	0x00640000,
+	},
+	{
+		.name		=	"XS2-8",
+		.kern_start	=	0xa8030000,
+		.kern_entry	=	0x80041000,
+		.firmware_max_length=	0x006C0000,
+	},
+	{
+		.name		=	"XM",
+		.kern_start	=	0x9f050000,
+		.kern_entry	=	0x80002000,
+		.firmware_max_length=	0x00760000,
+	},
+	{
+		.name		=	"UBDEV01",
+		.kern_start	=	0x9f050000,
+		.kern_entry	=	0x80002000,
+		.firmware_max_length=	0x006A0000,
+	},
+	{	.name		=	"",
+	},
+};
+
+typedef struct part_data {
+	char 	partition_name[64];
+	int  	partition_index;
+	u_int32_t	partition_baseaddr;
+	u_int32_t	partition_startaddr;
+	u_int32_t	partition_memaddr;
+	u_int32_t	partition_entryaddr;
+	u_int32_t  partition_length;
+
+	char	filename[PATH_MAX];
+	struct stat stats;
+} part_data_t;
+
+#define MAX_SECTIONS	8
+#define DEFAULT_OUTPUT_FILE 	"firmware-image.bin"
+#define DEFAULT_VERSION		"UNKNOWN"
+
+#define OPTIONS "B:hv:m:o:r:k:"
+
+typedef struct image_info {
+	char magic[16];
+	char version[256];
+	char outputfile[PATH_MAX];
+	u_int32_t	part_count;
+	part_data_t parts[MAX_SECTIONS];
+} image_info_t;
+
+static void write_header(void* mem, const char *magic, const char* version)
+{
+	header_t* header = mem;
+	memset(header, 0, sizeof(header_t));
+
+	memcpy(header->magic, magic, MAGIC_LENGTH);
+	strncpy(header->version, version, sizeof(header->version));
+	header->crc = htonl(crc32(0L, (unsigned char *)header,
+				sizeof(header_t) - 2 * sizeof(u_int32_t)));
+	header->pad = 0L;
+}
+
+
+static void write_signature(void* mem, u_int32_t sig_offset)
+{
+	/* write signature */
+	signature_t* sign = (signature_t*)(mem + sig_offset);
+	memset(sign, 0, sizeof(signature_t));
+
+	memcpy(sign->magic, MAGIC_END, MAGIC_LENGTH);
+	sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
+	sign->pad = 0L;
+}
+
+static int write_part(void* mem, part_data_t* d)
+{
+	char* addr;
+	int fd;
+	part_t* p = mem;
+	part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
+
+	fd = open(d->filename, O_RDONLY);
+	if (fd < 0)
+	{
+		ERROR("Failed opening file '%s'\n", d->filename);
+		return -1;
+	}
+
+	if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
+	{
+		ERROR("Failed mmaping memory for file '%s'\n", d->filename);
+		close(fd);
+		return -2;
+	}
+
+	memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
+	munmap(addr, d->stats.st_size);
+
+	memset(p->name, 0, sizeof(p->name));
+	strncpy(p->magic, MAGIC_PART, MAGIC_LENGTH);
+	strncpy(p->name, d->partition_name, sizeof(p->name));
+	p->index = htonl(d->partition_index);
+	p->data_size = htonl(d->stats.st_size);
+	p->part_size = htonl(d->partition_length);
+	p->baseaddr = htonl(d->partition_baseaddr);
+	p->memaddr = htonl(d->partition_memaddr);
+	p->entryaddr = htonl(d->partition_entryaddr);
+
+	crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
+	crc->pad = 0L;
+
+	return 0;
+}
+
+static void usage(const char* progname)
+{
+	INFO("Version %s\n"
+             "Usage: %s [options]\n"
+	     "\t-v <version string>\t - firmware version information, default: %s\n"
+	     "\t-o <output file>\t - firmware output file, default: %s\n"
+	     "\t-m <magic>\t - firmware magic, default: %s\n"
+	     "\t-k <kernel file>\t\t - kernel file\n"
+	     "\t-r <rootfs file>\t\t - rootfs file\n"
+	     "\t-B <board name>\t\t - choose firmware layout for specified board (XS2, XS5, RS, XM)\n"
+	     "\t-h\t\t\t - this help\n", VERSION,
+	     progname, DEFAULT_VERSION, DEFAULT_OUTPUT_FILE, MAGIC_HEADER);
+}
+
+static void print_image_info(const image_info_t* im)
+{
+	int i = 0;
+	INFO("Firmware version: '%s'\n"
+	     "Output file: '%s'\n"
+	     "Part count: %u\n",
+	     im->version, im->outputfile,
+	     im->part_count);
+
+	for (i = 0; i < im->part_count; ++i)
+	{
+		const part_data_t* d = &im->parts[i];
+		INFO(" %10s: %8ld bytes (free: %8ld)\n",
+		     d->partition_name,
+		     d->stats.st_size,
+		     d->partition_length - d->stats.st_size);
+	}
+}
+
+
+
+static u_int32_t filelength(const char* file)
+{
+	FILE *p;
+	int ret = -1;
+
+	if ( (p = fopen(file, "rb") ) == NULL) return (-1);
+
+	fseek(p, 0, SEEK_END);
+	ret = ftell(p);
+
+	fclose (p);
+
+	return (ret);
+}
+
+static int create_image_layout(const char* kernelfile, const char* rootfsfile, char* board_name, image_info_t* im)
+{
+	part_data_t* kernel = &im->parts[0];
+	part_data_t* rootfs = &im->parts[1];
+
+	fw_layout_t* p;
+
+	p = &fw_layout_data[0];
+	while (*p->name && (strcmp(p->name, board_name) != 0))
+		p++;
+	if (!*p->name) {
+		printf("BUG! Unable to find default fw layout!\n");
+		exit(-1);
+	}
+
+	printf("board = %s\n", p->name);
+	strcpy(kernel->partition_name, "kernel");
+	kernel->partition_index = 1;
+	kernel->partition_baseaddr = p->kern_start;
+	if ( (kernel->partition_length = filelength(kernelfile)) == (u_int32_t)-1) return (-1);
+	kernel->partition_memaddr = p->kern_entry;
+	kernel->partition_entryaddr = p->kern_entry;
+	strncpy(kernel->filename, kernelfile, sizeof(kernel->filename));
+
+	if (filelength(rootfsfile) + kernel->partition_length > p->firmware_max_length)
+		return (-2);
+
+	strcpy(rootfs->partition_name, "rootfs");
+	rootfs->partition_index = 2;
+	rootfs->partition_baseaddr = kernel->partition_baseaddr + kernel->partition_length;
+	rootfs->partition_length = p->firmware_max_length - kernel->partition_length;
+	rootfs->partition_memaddr = 0x00000000;
+	rootfs->partition_entryaddr = 0x00000000;
+	strncpy(rootfs->filename, rootfsfile, sizeof(rootfs->filename));
+
+	printf("kernel: %d 0x%08x\n", kernel->partition_length, kernel->partition_baseaddr);
+	printf("root: %d 0x%08x\n", rootfs->partition_length, rootfs->partition_baseaddr);
+	im->part_count = 2;
+
+	return 0;
+}
+
+/**
+ * Checks the availability and validity of all image components.
+ * Fills in stats member of the part_data structure.
+ */
+static int validate_image_layout(image_info_t* im)
+{
+	int i;
+
+	if (im->part_count == 0 || im->part_count > MAX_SECTIONS)
+	{
+		ERROR("Invalid part count '%d'\n", im->part_count);
+		return -1;
+	}
+
+	for (i = 0; i < im->part_count; ++i)
+	{
+		part_data_t* d = &im->parts[i];
+		int len = strlen(d->partition_name);
+		if (len == 0 || len > 16)
+		{
+			ERROR("Invalid partition name '%s' of the part %d\n",
+					d->partition_name, i);
+			return -1;
+		}
+		if (stat(d->filename, &d->stats) < 0)
+		{
+			ERROR("Couldn't stat file '%s' from part '%s'\n",
+				       	d->filename, d->partition_name);
+			return -2;
+		}
+		if (d->stats.st_size == 0)
+		{
+			ERROR("File '%s' from part '%s' is empty!\n",
+				       	d->filename, d->partition_name);
+			return -3;
+		}
+		if (d->stats.st_size > d->partition_length) {
+			ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %lu bytes)\n",
+				       	d->filename, i, d->partition_length,
+					d->stats.st_size - d->partition_length);
+			return -4;
+		}
+	}
+
+	return 0;
+}
+
+static int build_image(image_info_t* im)
+{
+	char* mem;
+	char* ptr;
+	u_int32_t mem_size;
+	FILE* f;
+	int i;
+
+	// build in-memory buffer
+	mem_size = sizeof(header_t) + sizeof(signature_t);
+	for (i = 0; i < im->part_count; ++i)
+	{
+		part_data_t* d = &im->parts[i];
+		mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+	}
+
+	mem = (char*)calloc(mem_size, 1);
+	if (mem == NULL)
+	{
+		ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
+		return -1;
+	}
+
+	// write header
+	write_header(mem, im->magic, im->version);
+	ptr = mem + sizeof(header_t);
+	// write all parts
+	for (i = 0; i < im->part_count; ++i)
+	{
+		part_data_t* d = &im->parts[i];
+		int rc;
+		if ((rc = write_part(ptr, d)) != 0)
+		{
+			ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
+		}
+		ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+	}
+	// write signature
+	write_signature(mem, mem_size - sizeof(signature_t));
+
+	// write in-memory buffer into file
+	if ((f = fopen(im->outputfile, "w")) == NULL)
+	{
+		ERROR("Can not create output file: '%s'\n", im->outputfile);
+		return -10;
+	}
+
+	if (fwrite(mem, mem_size, 1, f) != 1)
+	{
+		ERROR("Could not write %d bytes into file: '%s'\n",
+				mem_size, im->outputfile);
+		return -11;
+	}
+
+	free(mem);
+	fclose(f);
+	return 0;
+}
+
+
+int main(int argc, char* argv[])
+{
+	char kernelfile[PATH_MAX];
+	char rootfsfile[PATH_MAX];
+	char board_name[PATH_MAX];
+	int o, rc;
+	image_info_t im;
+
+	memset(&im, 0, sizeof(im));
+	memset(kernelfile, 0, sizeof(kernelfile));
+	memset(rootfsfile, 0, sizeof(rootfsfile));
+	memset(board_name, 0, sizeof(board_name));
+
+	strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
+	strcpy(im.version, DEFAULT_VERSION);
+	strncpy(im.magic, MAGIC_HEADER, sizeof(im.magic));
+
+	while ((o = getopt(argc, argv, OPTIONS)) != -1)
+	{
+		switch (o) {
+		case 'v':
+			if (optarg)
+				strncpy(im.version, optarg, sizeof(im.version));
+			break;
+		case 'o':
+			if (optarg)
+				strncpy(im.outputfile, optarg, sizeof(im.outputfile));
+			break;
+		case 'm':
+			if (optarg)
+				strncpy(im.magic, optarg, sizeof(im.magic));
+			break;
+		case 'h':
+			usage(argv[0]);
+			return -1;
+		case 'k':
+			if (optarg)
+				strncpy(kernelfile, optarg, sizeof(kernelfile));
+			break;
+		case 'r':
+			if (optarg)
+				strncpy(rootfsfile, optarg, sizeof(rootfsfile));
+			break;
+		case 'B':
+			if (optarg)
+				strncpy(board_name, optarg, sizeof(board_name));
+			break;
+		}
+	}
+	if (strlen(board_name) == 0)
+		strcpy(board_name, "XS2"); /* default to XS2 */
+
+	if (strlen(kernelfile) == 0)
+	{
+		ERROR("Kernel file is not specified, cannot continue\n");
+		usage(argv[0]);
+		return -2;
+	}
+
+	if (strlen(rootfsfile) == 0)
+	{
+		ERROR("Root FS file is not specified, cannot continue\n");
+		usage(argv[0]);
+		return -2;
+	}
+
+	if ((rc = create_image_layout(kernelfile, rootfsfile, board_name, &im)) != 0)
+	{
+		ERROR("Failed creating firmware layout description - error code: %d\n", rc);
+		return -3;
+	}
+
+	if ((rc = validate_image_layout(&im)) != 0)
+	{
+		ERROR("Failed validating firmware layout - error code: %d\n", rc);
+		return -4;
+	}
+
+	print_image_info(&im);
+
+	if ((rc = build_image(&im)) != 0)
+	{
+		ERROR("Failed building image file '%s' - error code: %d\n", im.outputfile, rc);
+		return -5;
+	}
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/mkfwimage2.c b/tools/firmware-utils/src/mkfwimage2.c
new file mode 100644
index 0000000000..89a98051b4
--- /dev/null
+++ b/tools/firmware-utils/src/mkfwimage2.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2007 Ubiquiti Networks, Inc.
+ * Copyright (C) 2008 Lukas Kuna <ValXdater@seznam.cz>
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "fw.h"
+
+#undef VERSION
+#define VERSION "1.2-OpenWrt.1"
+
+#define MAX_SECTIONS		8
+#define DEFAULT_OUTPUT_FILE 	"firmware-image.bin"
+#define DEFAULT_VERSION		"UNKNOWN"
+#define DEFAULT_FLASH_BASE	(0xbfc00000)
+
+#define FIRMWARE_MAX_LENGTH	(0x390000)
+
+typedef struct part_data {
+	char 		partition_name[64];
+	int  		partition_index;
+	u_int32_t	partition_baseaddr;
+	u_int32_t	partition_offset;
+	u_int32_t	partition_memaddr;
+	u_int32_t	partition_entryaddr;
+	u_int32_t	partition_length;
+
+	char		filename[PATH_MAX];
+	struct stat	stats;
+} part_data_t;
+
+typedef struct image_info {
+	char		version[256];
+	char		outputfile[PATH_MAX];
+	char		magic[MAGIC_LENGTH];
+	u_int32_t	flash_baseaddr;
+	u_int32_t	part_count;
+	part_data_t	parts[MAX_SECTIONS];
+} image_info_t;
+
+static image_info_t im;
+static int debug = 0;
+static int zero_part_baseaddr = 0;
+
+static void write_header(void* mem, const char* version)
+{
+	header_t* header = mem;
+	memset(header, 0, sizeof(header_t));
+
+	memcpy(header->magic, im.magic, MAGIC_LENGTH);
+	strncpy(header->version, version, sizeof(header->version));
+	header->crc = htonl(crc32(0L, (unsigned char *)header,
+				sizeof(header_t) - 2 * sizeof(u_int32_t)));
+	header->pad = 0L;
+}
+
+static void write_signature(void* mem, u_int32_t sig_offset)
+{
+	/* write signature */
+	signature_t* sign = (signature_t*)(mem + sig_offset);
+	memset(sign, 0, sizeof(signature_t));
+
+	memcpy(sign->magic, MAGIC_END, MAGIC_LENGTH);
+	sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
+	sign->pad = 0L;
+}
+
+static int write_part(void* mem, part_data_t* d)
+{
+	char* addr;
+	int fd;
+	part_t* p = mem;
+	part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
+
+	fd = open(d->filename, O_RDONLY);
+	if (fd < 0) {
+		ERROR("Failed opening file '%s'\n", d->filename);
+		return -1;
+	}
+
+	if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+		ERROR("Failed mmaping memory for file '%s'\n", d->filename);
+		close(fd);
+		return -2;
+	}
+
+	memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
+	munmap(addr, d->stats.st_size);
+
+	memset(p->name, 0, sizeof(p->name));
+	strncpy(p->magic, MAGIC_PART, MAGIC_LENGTH);
+	strncpy(p->name, d->partition_name, sizeof(p->name));
+	p->index = htonl(d->partition_index);
+	p->data_size = htonl(d->stats.st_size);
+	p->part_size = htonl(d->partition_length);
+	p->baseaddr = htonl(d->partition_baseaddr);
+	p->memaddr = htonl(d->partition_memaddr);
+	p->entryaddr = htonl(d->partition_entryaddr);
+
+	crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
+	crc->pad = 0L;
+
+	return 0;
+}
+
+static void usage(const char* progname)
+{
+	INFO("Version %s\n"
+             "Usage: %s [options]\n"
+	     "\t-v <version string>\t - firmware version information, default: %s\n"
+	     "\t-m <magic>\t\t - firmware magic, default: %s\n"
+	     "\t-f <flash base>\t\t - flash base address, default: 0x%08x\n"
+	     "\t-o <output file>\t - firmware output file, default: %s\n"
+	     "\t-p <name>:<offset>:<len>:<memaddr>:<entry>:<file>\n "
+	     "\t\t\t\t - create a partition from <file>\n"
+	     "\t-z\t\t\t - set partition offsets to zero\n"
+	     "\t-h\t\t\t - this help\n",
+	     VERSION, progname, DEFAULT_VERSION, MAGIC_HEADER,
+	     DEFAULT_FLASH_BASE, DEFAULT_OUTPUT_FILE);
+}
+
+static void print_image_info(void)
+{
+	int i;
+
+	INFO("Firmware version : '%s'\n"
+	     "Output file      : '%s'\n"
+	     "Part count       : %u\n",
+	     im.version, im.outputfile, im.part_count);
+
+	for (i = 0; i < im.part_count; ++i) {
+		const part_data_t* d = &im.parts[i];
+		INFO("  %10s: %08x %08x %08x %08x %8ld bytes (free: %8ld)\n",
+		     d->partition_name,
+		     d->partition_baseaddr,
+		     d->partition_length,
+		     d->partition_entryaddr,
+		     d->partition_memaddr,
+		     d->stats.st_size,
+		     d->partition_length - d->stats.st_size);
+	}
+}
+
+static int filelength(const char* file)
+{
+	FILE *p;
+	int ret = -1;
+
+	if ( (p = fopen(file, "rb") ) == NULL) return (-1);
+
+	fseek(p, 0, SEEK_END);
+	ret = ftell(p);
+
+	fclose (p);
+
+	return (ret);
+}
+
+int str2u32(char *arg, u_int32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno = 0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err == arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+#ifndef STRINGIFY
+#define STRINGIFY2(X) #X
+#define STRINGIFY(X) STRINGIFY2(X)
+#endif
+static int image_layout_add_partition(const char *part_desc)
+{
+	part_data_t *d;
+	char memaddr[16];
+	char entryaddr[16];
+	char offset[16];
+	char length[16];
+	int t;
+
+	if (im.part_count >= MAX_SECTIONS) {
+		ERROR("Too many partitions specified\n");
+		return (-1);
+	}
+
+	d = &im.parts[im.part_count];
+	t = sscanf(part_desc, "%15[-0-9a-zA-Z]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%15[0-9a-fA-Fx]:%"STRINGIFY(PATH_MAX)"s",
+			d->partition_name,
+			offset,
+			length,
+			memaddr,
+			entryaddr,
+			d->filename);
+
+	if (t != 6) {
+		ERROR("Bad partition parameter %d, '%s'\n", t, part_desc);
+		return (-1);
+	}
+
+	if (strlen(d->partition_name) == 0) {
+		ERROR("No partition name specified in '%s'\n", part_desc);
+		return (-1);
+	}
+
+	if (str2u32(offset, &d->partition_offset)) {
+		ERROR("Bad offset value '%s'\n", offset);
+		return (-1);
+	}
+
+	if (str2u32(length, &d->partition_length)) {
+		ERROR("Bad length value '%s'\n", length);
+		return (-1);
+	}
+
+	if (d->partition_length == 0) {
+		int flen;
+		flen = filelength(d->filename);
+		if (flen < 0) {
+			ERROR("Unable to determine size of '%s'\n",
+					d->filename);
+			return (-1);
+		}
+		d->partition_length = flen;
+	}
+
+	if (str2u32(memaddr, &d->partition_memaddr)) {
+		ERROR("Bad memaddr vaule '%s'\n", memaddr);
+		return (-1);
+	}
+
+	if (str2u32(entryaddr, &d->partition_entryaddr)) {
+		ERROR("Bad entry address value '%s'\n", entryaddr);
+		return (-1);
+	}
+
+	im.part_count++;
+	d->partition_index = im.part_count;
+
+	return 0;
+}
+
+static int image_layout_verify(void)
+{
+	u_int32_t offset;
+	int i;
+
+	if (im.part_count == 0) {
+		ERROR("No partitions specified\n");
+		return -1;
+	}
+
+	offset = im.parts[0].partition_offset;
+	for (i = 0; i < im.part_count; i++)
+	{
+		part_data_t* d = &im.parts[i];
+
+		if (stat(d->filename, &d->stats) < 0) {
+			ERROR("Couldn't stat file '%s' from part '%s'\n",
+					d->filename, d->partition_name);
+			return -2;
+		}
+
+		if (d->stats.st_size == 0) {
+			ERROR("File '%s' from part '%s' is empty!\n",
+					d->filename, d->partition_name);
+			return -3;
+		}
+
+		if (d->stats.st_size > d->partition_length) {
+			ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %lu bytes)\n",
+				d->filename, i, d->partition_length,
+				d->stats.st_size - d->partition_length);
+			return -4;
+		}
+
+		if (d->partition_offset < offset)
+			d->partition_offset = offset;
+
+		if (zero_part_baseaddr) {
+			d->partition_baseaddr = 0;
+		} else {
+			d->partition_baseaddr =
+				im.flash_baseaddr + d->partition_offset;
+		}
+		offset += d->partition_length;
+	}
+
+	return 0;
+}
+
+static int build_image(void)
+{
+	char* mem;
+	char* ptr;
+	u_int32_t mem_size;
+	FILE* f;
+	int i;
+
+	/* build in-memory buffer */
+	mem_size = sizeof(header_t) + sizeof(signature_t);
+	for (i = 0; i < im.part_count; ++i) {
+		part_data_t* d = &im.parts[i];
+		mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+	}
+
+	mem = (char*)calloc(mem_size, 1);
+	if (mem == NULL) {
+		ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
+		return -1;
+	}
+
+	/* write header */
+	write_header(mem, im.version);
+	ptr = mem + sizeof(header_t);
+
+	/* write all parts */
+	for (i = 0; i < im.part_count; ++i) {
+		part_data_t* d = &im.parts[i];
+		int rc;
+		if ((rc = write_part(ptr, d)) != 0) {
+			ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
+			return -1;
+		}
+		ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
+	}
+
+
+	/* write signature */
+	write_signature(mem, mem_size - sizeof(signature_t));
+
+	/* write in-memory buffer into file */
+	if ((f = fopen(im.outputfile, "w")) == NULL) {
+		ERROR("Can not create output file: '%s'\n", im.outputfile);
+		return -10;
+	}
+
+	if (fwrite(mem, mem_size, 1, f) != 1) {
+		ERROR("Could not write %d bytes into file: '%s'\n",
+				mem_size, im.outputfile);
+		return -11;
+	}
+
+	free(mem);
+	fclose(f);
+	return 0;
+}
+
+int main(int argc, char* argv[])
+{
+	int o, rc;
+
+	memset(&im, 0, sizeof(im));
+
+	strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
+	strcpy(im.version, DEFAULT_VERSION);
+	memcpy(im.magic, MAGIC_HEADER, MAGIC_LENGTH);
+	im.flash_baseaddr = DEFAULT_FLASH_BASE;
+
+	while ((o = getopt(argc, argv, "f:hm:o:p:v:z")) != -1)
+	{
+		switch (o) {
+		case 'f':
+			if (optarg)
+				if (str2u32(optarg, &im.flash_baseaddr)) {
+					ERROR("Invalid flash start address %s\n", optarg);
+					return -1;
+				}
+			break;
+		case 'h':
+			usage(argv[0]);
+			return -1;
+		case 'm':
+			if (optarg) {
+				if (strlen(optarg) != MAGIC_LENGTH) {
+					ERROR("Invalid magic %s\n", optarg);
+					return -1;
+				}
+
+				memcpy(im.magic, optarg, MAGIC_LENGTH);
+			}
+			break;
+		case 'o':
+			if (optarg)
+				strncpy(im.outputfile, optarg, sizeof(im.outputfile));
+			break;
+		case 'p':
+			if (optarg) {
+				if (image_layout_add_partition(optarg))
+					return -1;
+			}
+			break;
+		case 'v':
+			if (optarg)
+				strncpy(im.version, optarg, sizeof(im.version));
+			break;
+		case 'z':
+			zero_part_baseaddr = 1;
+			break;
+		}
+	}
+
+	rc = image_layout_verify();
+	if (rc)	{
+		ERROR("Failed validating firmware layout - error code: %d\n",
+				rc);
+		return -4;
+	}
+
+	print_image_info();
+
+	rc = build_image();
+	if (rc)	{
+		ERROR("Failed building image file '%s' - error code: %d\n",
+				im.outputfile, rc);
+		return -5;
+	}
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/mkheader_gemtek.c b/tools/firmware-utils/src/mkheader_gemtek.c
new file mode 100644
index 0000000000..9e618efbad
--- /dev/null
+++ b/tools/firmware-utils/src/mkheader_gemtek.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014  Claudio Leite <leitec@staticky.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Builds a proper flash image for routers using some Gemtek
+ * OEM boards. These include the Airlink101 AR725W, the
+ * Asante SmartHub 600 (AWRT-600N), and Linksys WRT100/110.
+ *
+ * The resulting image is compatible with the factory firmware
+ * web upgrade and TFTP interface.
+ *
+ * To build:
+ *  gcc -O2 -o mkheader_gemtek mkheader_gemtek.c -lz
+ *
+ * Claudio Leite <leitec@staticky.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <zlib.h>		/* for crc32() */
+
+/*
+ * The header is in little-endian format. In case
+ * we are on a BE host, we need to swap binary
+ * values.
+ */
+#ifdef __APPLE__
+# include <libkern/OSByteOrder.h>
+# define le32 OSSwapHostToLittleInt32
+#else
+# if defined(__linux__)
+#  include <endian.h>
+#  if __BYTE_ORDER == __BIG_ENDIAN
+#   define CPU_BIG_ENDIAN
+#  endif
+# else
+#  include <sys/endian.h>		/* BSD's should have this */
+#  if _BYTE_ORDER == _BIG_ENDIAN
+#   define CPU_BIG_ENDIAN
+#  endif
+# endif
+# ifdef CPU_BIG_ENDIAN
+#  define le32(x) (((x & 0xff000000) >> 24) | \
+                   ((x & 0x00ff0000) >> 8)  | \
+                   ((x & 0x0000ff00) << 8)  | \
+                   ((x & 0x000000ff) << 24))
+# else
+#  define le32(x) (x)
+# endif
+#endif
+
+struct gemtek_header {
+	uint8_t 	magic[4];
+	uint8_t 	version[4];
+	uint32_t 	product_id;
+	uint32_t 	imagesz;
+	uint32_t 	checksum;
+	uint32_t 	fast_checksum;
+	uint8_t 	build[4];
+	uint8_t 	lang[4];
+};
+
+#define HDRLEN	sizeof(struct gemtek_header)
+
+struct machines {
+	char           *desc;
+	char           *id;
+	uint32_t 	maxsize;
+	struct gemtek_header header;
+};
+
+struct machines mach_def[] = {
+	{"Airlink101 AR725W", "ar725w", 0x340000,
+		{"GMTK", "1003", le32(0x03000001), 0, 0,
+		  0, "01\0\0", "EN\0\0"}},
+	{"Asante AWRT-600N", "awrt600n", 0x340000,
+		{"A600", "1005", le32(0x03000001), 0, 0,
+		  0, "01\0\0", "EN\0\0"}},
+	{"Linksys WRT100", "wrt100", 0x320000,
+		{"GMTK", "1007", le32(0x03040001), 0, 0,
+		  0, "2\0\0\0", "EN\0\0"}},
+	{"Linksys WRT110", "wrt110", 0x320000,
+		{"GMTK", "1007", le32(0x03040001), 0, 0,
+		  0, "2\0\0\0", "EN\0\0"}},
+	{0}
+};
+
+int
+main(int argc, char *argv[])
+{
+	unsigned long 	res, flen;
+	struct gemtek_header my_hdr;
+	FILE           *f, *f_out;
+	int 		image_type = -1, index;
+	uint8_t        *buf;
+	uint32_t 	crc;
+
+	if (argc < 3) {
+		fprintf(stderr, "mkheader_gemtek <uImage> <webflash image> [machine ID]\n");
+		fprintf(stderr, "  where [machine ID] is one of:\n");
+		for (index = 0; mach_def[index].desc != 0; index++) {
+			fprintf(stderr, "    %-10s  %s", mach_def[index].id, mach_def[index].desc);
+			if (index == 0)
+				fprintf(stderr, " (default)\n");
+			else
+				fprintf(stderr, "\n");
+		}
+
+		exit(-1);
+	}
+
+	if (argc == 4) {
+		for(index = 0; mach_def[index].id != 0; index++) {
+			if(strcmp(mach_def[index].id, argv[3]) == 0) {
+				image_type = index;
+				break;
+			}
+		}
+
+		if(image_type == -1) {
+			fprintf(stderr, "\nERROR: invalid machine type\n");
+			exit(-1);
+		}
+	} else
+		image_type = 0;
+
+	printf("Opening %s...\n", argv[1]);
+
+	f = fopen(argv[1], "r");
+	if(!f) {
+		fprintf(stderr, "\nERROR: couldn't open input image\n");
+		exit(-1);
+	}
+
+	fseek(f, 0, SEEK_END);
+	flen = (unsigned long) ftell(f);
+
+	printf("  %lu (0x%lX) bytes long\n", flen, flen);
+
+	if (flen > mach_def[image_type].maxsize) {
+		fprintf(stderr, "\nERROR: image exceeds maximum compatible size\n");
+		goto f_error;
+	}
+
+	buf = malloc(flen + HDRLEN);
+	if (!buf) {
+		fprintf(stderr, "\nERROR: couldn't allocate buffer\n");
+		goto f_error;
+	}
+	rewind(f);
+	res = fread(buf + HDRLEN, 1, flen, f);
+	if (res != flen) {
+		perror("Couldn't read entire file: fread()");
+		goto f_error;
+	}
+	fclose(f);
+
+	printf("\nCreating %s...\n", argv[2]);
+
+	memcpy(&my_hdr, &mach_def[image_type].header, HDRLEN);
+
+	printf("  Using %s magic\n", mach_def[image_type].desc);
+
+	my_hdr.imagesz = le32(flen + HDRLEN);
+	memcpy(my_hdr.lang, "EN", 2);
+
+	memcpy(buf, &my_hdr, HDRLEN);
+
+	crc = crc32(0, buf, flen + HDRLEN);
+	printf("  CRC32: %08X\n", crc);
+
+	my_hdr.checksum = le32(crc);
+	memcpy(buf, &my_hdr, HDRLEN);
+
+	printf("  Writing...\n");
+
+	f_out = fopen(argv[2], "w");
+	if(!f_out) {
+		fprintf(stderr, "\nERROR: couldn't open output image\n");
+		exit(-1);
+	}
+
+	fwrite(buf, 1, flen + HDRLEN, f_out);
+
+	fclose(f_out);
+
+	free(buf);
+	return 0;
+
+f_error:
+	fclose(f);
+	exit(-1);
+}
diff --git a/tools/firmware-utils/src/mkhilinkfw.c b/tools/firmware-utils/src/mkhilinkfw.c
new file mode 100644
index 0000000000..55908e5caa
--- /dev/null
+++ b/tools/firmware-utils/src/mkhilinkfw.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2013 Jeff Kent <jeff@jkent.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This tool encrypts and decrypts uImage formatted firmware for Hilink
+ * HLK-RM04 wireless modules.  It will also truncate a dump of mtd6 and make
+ * it an image suitable for flashing via the stock firmware upgrade page.
+ *
+ * Build instructions: 
+ *   gcc -lcrypto hlkcrypt.c -o hlkcrypt
+ */
+ 
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <openssl/des.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+ 
+#define DES_KEY "H@L9K*(3"
+ 
+#ifndef min
+#define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+#endif
+ 
+#define IH_MAGIC    0x27051956
+#define IH_NMLEN    32
+typedef struct image_header {
+    uint32_t    ih_magic;   /* Image Header Magic Number    */
+    uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */
+    uint32_t    ih_time;    /* Image Creation Timestamp */
+    uint32_t    ih_size;    /* Image Data Size      */
+    uint32_t    ih_load;    /* Data  Load  Address      */
+    uint32_t    ih_ep;      /* Entry Point Address      */
+    uint32_t    ih_dcrc;    /* Image Data CRC Checksum  */
+    uint8_t     ih_os;      /* Operating System     */
+    uint8_t     ih_arch;    /* CPU architecture     */
+    uint8_t     ih_type;    /* Image Type           */
+    uint8_t     ih_comp;    /* Compression Type     */
+    uint8_t     ih_name[IH_NMLEN];  /* Image Name       */
+} image_header_t;
+ 
+static int temp_fd = -1;
+static DES_key_schedule schedule;
+ 
+static void show_usage(const char *arg0);
+static void exit_cleanup(void);
+static void copy_file(int src, int dst);
+static void do_encrypt(void *p, off_t len);
+static void do_decrypt(void *p, off_t len);
+ 
+ 
+int main(int argc, char **argv)
+{
+	int encrypt_opt = 0;
+	int decrypt_opt = 0;
+	int input_opt = 0;
+	int output_opt = 0;
+	char *input_filename = NULL;
+	char *output_filename = NULL;
+ 
+	int input_fd;
+	int output_fd;
+	off_t file_len;
+	char *p;
+	char buf[sizeof(image_header_t) + 3];
+	image_header_t *header;
+ 
+	while (1) {
+		static struct option long_options[] = {
+			{"encrypt", no_argument,       0, 'e'},
+			{"decrypt", no_argument,       0, 'd'},
+			{"input",   required_argument, 0, 'i'},
+			{"output",  required_argument, 0, 'o'},
+			{0,         0,                 0, 0  }
+		};
+		int option_index = 0;
+		int c = getopt_long(argc, argv, "dei:o:",
+		                long_options, &option_index);
+		if (c == -1)
+			break;
+ 
+		switch (c) {
+		case 'd':
+			decrypt_opt++;
+			if (decrypt_opt > 1) {
+				fprintf(stderr, "%s: decrypt may only be specified once\n",
+				        argv[0]);
+				show_usage(argv[0]);
+			}
+			break;
+ 
+		case 'e':
+			encrypt_opt++;
+			if (encrypt_opt > 1) {
+				fprintf(stderr, "%s: encrypt may only be specified once\n",
+				        argv[0]);
+				show_usage(argv[0]);
+			}
+			break;
+ 
+		case 'i':
+			input_opt++;
+			if (input_opt > 1) {
+				fprintf(stderr, "%s: only one input file may be specified\n",
+				        argv[0]);
+				show_usage(argv[0]);
+			}
+			if (strcmp("-", optarg) != 0) {
+				input_filename = optarg;
+			}
+			break;
+ 
+		case 'o':
+			output_opt++;
+			if (output_opt > 1) {
+				fprintf(stderr, "%s: only one output file may be specified\n",
+				        argv[0]);
+				show_usage(argv[0]);
+			}
+			if (strcmp("-", optarg) != 0) {
+				output_filename = optarg;
+			}
+			break;
+ 
+		case '?':
+			exit(-1);
+ 
+		default:
+			abort();
+		}
+	}
+ 
+	if (decrypt_opt && encrypt_opt) {
+		fprintf(stderr, "%s: decrypt and encrypt may not be used together\n",
+		        argv[0]);
+		show_usage(argv[0]);
+	}
+ 
+	if (!decrypt_opt && !encrypt_opt) {
+		fprintf(stderr, "%s: neither decrypt or encrypt were specified\n",
+		        argv[0]);
+		show_usage(argv[0]);
+	}
+ 
+	temp_fd = fileno(tmpfile());
+	if (temp_fd < 0) {
+		fprintf(stderr, "Can't create temporary file\n");
+		exit(EXIT_FAILURE);
+	}
+ 
+	atexit(exit_cleanup);
+	DES_set_key_unchecked((const_DES_cblock *)DES_KEY, &schedule);
+ 
+	if (input_filename) {
+		input_fd = open(input_filename, O_RDONLY);
+		if (input_fd < 0) {
+			fprintf(stderr, "Can't open %s for reading: %s\n", input_filename,
+			        strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+		copy_file(input_fd, temp_fd);
+		close(input_fd);
+	}
+	else {
+		copy_file(STDIN_FILENO, temp_fd);
+	}
+ 
+	file_len = lseek(temp_fd, 0, SEEK_CUR);
+	if (file_len < 64) {
+		fprintf(stderr, "Not enough data\n");
+		exit(EXIT_FAILURE);
+	}
+ 
+	p = mmap(0, file_len, PROT_READ|PROT_WRITE, MAP_SHARED, temp_fd, 0);
+	if (p == MAP_FAILED) {
+		fprintf(stderr, "mmap failed: %s\n", strerror(errno));
+		exit(EXIT_FAILURE);
+	}	
+ 
+	if (encrypt_opt) {
+		header = (image_header_t *)p;
+		off_t len = min(file_len,
+		                ntohl(header->ih_size) + sizeof(image_header_t));
+		if (ntohl(header->ih_magic) != IH_MAGIC) {
+			fprintf(stderr, "Header magic incorrect: "
+			        "expected 0x%08X, got 0x%08X\n",
+			        IH_MAGIC, ntohl(header->ih_magic));
+			munmap(p, file_len);
+			exit(EXIT_FAILURE);
+		}
+		do_encrypt(p, len);
+		munmap(p, file_len);
+		if (len != file_len) {
+			if (ftruncate(temp_fd, len) < 0) {
+				fprintf(stderr, "ftruncate failed: %s\n", strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+		}		
+	}
+ 
+	if (decrypt_opt) {
+		off_t header_len = min(file_len, sizeof(image_header_t) + 3);
+		memcpy(buf, p, header_len);
+		do_decrypt(buf, header_len);
+		header = (image_header_t *)buf;
+		if (ntohl(header->ih_magic) != IH_MAGIC) {
+			fprintf(stderr, "Header magic incorrect: "
+			        "expected 0x%08X, got 0x%08X\n",
+			        IH_MAGIC, ntohl(header->ih_magic));
+			exit(EXIT_FAILURE);
+		}
+		do_decrypt(p, file_len);
+		munmap(p, file_len);
+	}
+ 
+	lseek(temp_fd, 0, SEEK_SET);
+	if (output_filename) {
+		output_fd = creat(output_filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+		if (output_fd < 0) {
+			fprintf(stderr, "Can't open %s for writing: %s\n",
+			        output_filename, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+		copy_file(temp_fd, output_fd);
+		close(output_fd);
+	}
+	else {
+		copy_file(temp_fd, STDOUT_FILENO);
+	}
+ 
+	exit(EXIT_SUCCESS);
+	return 0;
+}
+ 
+static void show_usage(const char *arg0)
+{
+	fprintf(stderr, "usage: %s -d|-e [-i FILE] [-o FILE]\n\n", arg0);
+	fprintf(stderr, "%-15s %s\n", "-d, --decrypt", "decrypt data");
+	fprintf(stderr, "%-15s %s\n", "-e, --encrypt", "encrypt data");
+	fprintf(stderr, "%-15s %s\n", "-i, --input", "intput file (defaults to stdin)");
+	fprintf(stderr, "%-15s %s\n", "-o, --output", "output file (defaults to stdout)");
+	exit(-1);
+}
+ 
+static void exit_cleanup(void)
+{
+	if (temp_fd >= 0) {
+		close(temp_fd);
+	}
+}
+ 
+static void copy_file(int src, int dst)
+{
+	char buf[4096];
+	ssize_t size;
+ 
+	while ((size = read(src, buf, 4096)) > 0) {
+        write(dst, buf, size);
+    }
+}
+ 
+static void do_encrypt(void *p, off_t len)
+{
+	DES_cblock *pblock;
+	int num_blocks;
+ 
+	num_blocks = len / 8;
+	pblock = (DES_cblock *) p;
+	while (num_blocks--) {
+		DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
+		pblock++;
+	}
+ 
+	num_blocks = (len - 3) / 8;
+	pblock = (DES_cblock *) (p + 3);
+	while (num_blocks--) {
+		DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
+		pblock++;
+	}
+}
+ 
+static void do_decrypt(void *p, off_t len)
+{
+	DES_cblock *pblock;
+	int num_blocks;
+ 
+	num_blocks = (len - 3) / 8;
+	pblock = (DES_cblock *) (p + 3);
+	while (num_blocks--) {
+		DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
+		pblock++;
+	}
+ 
+	num_blocks = len / 8;
+	pblock = (DES_cblock *) p;
+	while (num_blocks--) {
+		DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
+		pblock++;
+	}
+}
diff --git a/tools/firmware-utils/src/mkmerakifw-old.c b/tools/firmware-utils/src/mkmerakifw-old.c
new file mode 100644
index 0000000000..05317c2a5b
--- /dev/null
+++ b/tools/firmware-utils/src/mkmerakifw-old.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
+ * Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
+ *
+ * The format of the header this tool generates was first documented by
+ * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
+ * same purpose. I have created this reimplementation at his request. The
+ * original script can be found at:
+ * <https://github.com/riptidewave93/meraki-partbuilder>
+ *
+ * Support for the old header format, which is used by the Cisco Z1 AP
+ * has been reverse engineered from the nandloader's nand_load_bk function.
+ * The original code is part of Cisco's GPL code and can be found at:
+ * <https://github.com/riptidewave93/meraki-linux>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <libgen.h>
+#include <endian.h>
+#include <getopt.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#define PADDING_BYTE		0xff
+
+#define HDR_LENGTH		0x00000020
+#define HDR_OFF_MAGIC1	0
+#define HDR_OFF_LOAD_ADDR	4
+#define HDR_OFF_IMAGELEN	8
+#define HDR_OFF_ENTRY	12
+#define HDR_OFF_CHECKSUM	16
+#define HDR_OFF_FILLER0	20
+#define HDR_OFF_FILLER1	24
+#define HDR_OFF_FILLER2	28
+
+struct board_info {
+	char *id;
+	char *description;
+	uint32_t magic;
+	uint32_t imagelen;
+	uint32_t load_addr;
+	uint32_t entry;
+};
+
+/*
+ * Globals
+ */
+static char *progname;
+static bool strip_padding;
+
+static char *board_id;
+static const struct board_info *board;
+
+static const struct board_info boards[] = {
+	{
+		.id		= "z1",
+		.description	= "Meraki Z1 Access Point",
+		.magic		= 0x4d495053,
+		.imagelen	= 0x007e0000,
+		.load_addr	= 0x80060000,
+		.entry		= 0x80060000
+	}, {
+		/* terminating entry */
+	}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+static const struct board_info *find_board(const char *id)
+{
+	const struct board_info *ret;
+	const struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->id != NULL; board++) {
+		if (strcasecmp(id, board->id) == 0) {
+			ret = board;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	const struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -i <file>       read kernel image from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -s              strip padding from the end of the image\n"
+"  -h              show this screen\n"
+	);
+
+	fprintf(stream, "\nBoards:\n");
+	for (board = boards; board->id != NULL; board++)
+		fprintf(stream, "  %-16s%s\n", board->id, board->description);
+
+	exit(status);
+}
+
+static void writel(unsigned char *buf, size_t offset, uint32_t value)
+{
+	value = htonl(value);
+	memcpy(buf + offset, &value, sizeof(uint32_t));
+}
+
+static const uint32_t crc32_table[] = {
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static inline uint32_t crc32_accumulate_8(const uint32_t crc, const uint8_t ch)
+{
+	return crc32_table[(crc ^ ch) & 0xff] ^ (crc >> 8);
+}
+
+static void crc32_csum(uint8_t *buf, const size_t len)
+{
+	uint32_t crc;
+	size_t i;
+
+	crc = ~0;
+	for (i = 0; i < len; i += 4) {
+		crc = crc32_accumulate_8(crc, buf[i + 3]);
+		crc = crc32_accumulate_8(crc, buf[i + 2]);
+		crc = crc32_accumulate_8(crc, buf[i + 1]);
+		crc = crc32_accumulate_8(crc, buf[i]);
+	}
+	crc = ~crc;
+
+	writel(buf, HDR_OFF_CHECKSUM, crc);
+}
+
+
+static int meraki_build_hdr(const struct board_info *board, const size_t klen,
+			    FILE *out, FILE *in)
+{
+	unsigned char *kernel;
+	unsigned char *buf;
+	size_t buflen;
+	size_t kspace;
+
+	size_t rc;
+	buflen = board->imagelen;
+	kspace = buflen - HDR_LENGTH;
+
+	if (klen > kspace) {
+		ERR("kernel file is too big - max size: 0x%08lX\n", kspace);
+		return EXIT_FAILURE;
+	}
+
+	/* If requested, resize buffer to remove padding */
+	if (strip_padding)
+		buflen = klen + HDR_LENGTH;
+
+	/* Allocate and initialize buffer for final image */
+	buf = malloc(buflen);
+	if (buf == NULL) {
+		ERRS("no memory for buffer: %s\n");
+		return EXIT_FAILURE;
+	}
+	memset(buf, PADDING_BYTE, buflen);
+
+	/* Load kernel */
+	kernel = buf + HDR_LENGTH;
+	fread(kernel, klen, 1, in);
+
+	/* Write magic values and filler */
+	writel(buf, HDR_OFF_MAGIC1, board->magic);
+	writel(buf, HDR_OFF_FILLER0, 0);
+	writel(buf, HDR_OFF_FILLER1, 0);
+	writel(buf, HDR_OFF_FILLER2, 0);
+
+	/* Write load and kernel entry point address */
+	writel(buf, HDR_OFF_LOAD_ADDR, board->load_addr);
+	writel(buf, HDR_OFF_ENTRY, board->entry);
+
+	/* Write header and image length */
+	writel(buf, HDR_OFF_IMAGELEN, klen);
+
+	/* this gets replaced later, after the checksum has been calculated */
+	writel(buf, HDR_OFF_CHECKSUM, 0);
+
+	/* Write checksum */
+	crc32_csum(buf, klen + HDR_LENGTH);
+
+	rc = fwrite(buf, buflen, 1, out);
+
+	free(buf);
+
+	return rc == 1 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	char *ofname = NULL, *ifname = NULL;
+	FILE *out, *in;
+	size_t klen;
+
+	progname = basename(argv[0]);
+
+	while (1) {
+		int c;
+
+		c = getopt(argc, argv, "B:i:o:sh");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			strip_padding = true;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (board_id == NULL) {
+		ERR("no board specified");
+		goto err;
+	}
+
+	board = find_board(board_id);
+	if (board == NULL) {
+		ERR("unknown board \"%s\"", board_id);
+		goto err;
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	in = fopen(ifname, "r");
+	if (in == NULL) {
+		ERRS("could not open \"%s\" for reading: %s", ifname);
+		goto err;
+	}
+
+	/* Get kernel length */
+	fseek(in, 0, SEEK_END);
+	klen = ftell(in);
+	rewind(in);
+
+	out = fopen(ofname, "w");
+	if (out == NULL) {
+		ERRS("could not open \"%s\" for writing: %s", ofname);
+		goto err_close_in;
+	}
+
+	ret = meraki_build_hdr(board, klen, out, in);
+	fclose(out);
+
+err_close_in:
+	fclose(in);
+
+err:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/mkmerakifw.c b/tools/firmware-utils/src/mkmerakifw.c
new file mode 100644
index 0000000000..1a50f1658f
--- /dev/null
+++ b/tools/firmware-utils/src/mkmerakifw.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2015 Thomas Hebb <tommyhebb@gmail.com>
+ *
+ * The format of the header this tool generates was first documented by
+ * Chris Blake <chrisrblake93 (at) gmail.com> in a shell script of the
+ * same purpose. I have created this reimplementation at his request. The
+ * original script can be found at:
+ * <https://github.com/riptidewave93/meraki-partbuilder>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include "sha1.h"
+
+#define PADDING_BYTE		0xff
+
+#define HDR_LENGTH		0x00000400
+#define HDR_OFF_MAGIC1		0
+#define HDR_OFF_HDRLEN		4
+#define HDR_OFF_IMAGELEN	8
+#define HDR_OFF_CHECKSUM	12
+#define HDR_OFF_MAGIC2		32
+#define HDR_OFF_MAGIC3		36
+#define HDR_OFF_STATICHASH	40
+#define HDR_OFF_KERNEL_OFFSET	40
+#define HDR_OFF_RAMDISK_OFFSET	44
+#define HDR_OFF_FDT_OFFSET	48
+#define HDR_OFF_UNKNOWN_OFFSET	52
+
+struct board_info {
+	uint32_t magic1;
+	uint32_t magic2;
+	uint32_t magic3;
+	uint32_t imagelen;
+	union {
+		unsigned char statichash[20];
+		struct {
+			uint32_t kernel_offset;
+			uint32_t ramdisk_offset;
+			uint32_t fdt_offset;
+			uint32_t unknown_offset;
+		} mx60;
+	} u;
+	char *id;
+	char *description;
+};
+
+/*
+ * Globals
+ */
+static char *progname;
+
+static char *board_id;
+static const struct board_info *board;
+
+static const struct board_info boards[] = {
+	{
+		.id		= "mr18",
+		.description	= "Meraki MR18 Access Point",
+		.magic1		= 0x8e73ed8a,
+		.magic2		= 0x8e73ed8a,
+		.imagelen	= 0x00800000,
+		.u.statichash	= {0xda, 0x39, 0xa3, 0xee, 0x5e,
+				   0x6b, 0x4b, 0x0d, 0x32, 0x55,
+				   0xbf, 0xef, 0x95, 0x60, 0x18,
+				   0x90, 0xaf, 0xd8, 0x07, 0x09},
+	}, {
+		.id		= "mr24",
+		.description	= "Meraki MR24 Access Point",
+		.magic1		= 0x8e73ed8a,
+		.magic2		= 0x8e73ed8a,
+		.imagelen	= 0x00800000,
+		.u.statichash	= {0xff, 0xff, 0xff, 0xff, 0xff,
+				   0xff, 0xff, 0xff, 0xff, 0xff,
+				   0xff, 0xff, 0xff, 0xff, 0xff,
+				   0xff, 0xff, 0xff, 0xff, 0xff},
+	}, {
+		.id		= "mx60",
+		.description	= "Meraki MX60/MX60W Security Appliance",
+		.magic1		= 0x8e73ed8a,
+		.magic2		= 0xa1f0beef, /* Enables use of load addr in statichash */
+		.magic3		= 0x00060001, /* This goes along with magic2 */
+		.imagelen	= 0x3fd00000,
+		/* The static hash below does the following:
+		 * 1st Row: Kernel Offset
+		 * 2nd Row: Ramdisk Offset
+		 * 3rd Row: FDT Offset
+		 * 4th Row: ? Unused/Unknown ?
+		 * 5th Row: ? Unused/Unknown ?
+		 */
+		.u.mx60		= {
+			.kernel_offset	= 0x10000,
+			.ramdisk_offset	= 0x3FFC00,
+			.fdt_offset	= 0x0400,
+			.unknown_offset	= 0x0400,
+		},
+	}, {
+		/* terminating entry */
+	}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+static const struct board_info *find_board(const char *id)
+{
+	const struct board_info *ret;
+	const struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->id != NULL; board++) {
+		if (strcasecmp(id, board->id) == 0) {
+			ret = board;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	const struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -i <file>       read kernel image from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -s              strip padding from the end of the image\n"
+"  -h              show this screen\n"
+	);
+
+	fprintf(stream, "\nBoards:\n");
+	for (board = boards; board->id != NULL; board++)
+		fprintf(stream, "  %-16s%s\n", board->id, board->description);
+
+	exit(status);
+}
+
+void writel(unsigned char *buf, size_t offset, uint32_t value)
+{
+	value = htonl(value);
+	memcpy(buf + offset, &value, sizeof(uint32_t));
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	long klen;
+	size_t kspace;
+	unsigned char *kernel;
+	size_t buflen;
+	unsigned char *buf;
+	bool strip_padding = false;
+	char *ofname = NULL, *ifname = NULL;
+	FILE *out, *in;
+
+	progname = basename(argv[0]);
+
+	while (1) {
+		int c;
+
+		c = getopt(argc, argv, "B:i:o:sh");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			strip_padding = true;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (board_id == NULL) {
+		ERR("no board specified");
+		goto err;
+	}
+
+	board = find_board(board_id);
+	if (board == NULL) {
+		ERR("unknown board \"%s\"", board_id);
+		goto err;
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	in = fopen(ifname, "r");
+	if (in == NULL) {
+		ERRS("could not open \"%s\" for reading: %s", ifname);
+		goto err;
+	}
+
+	buflen = board->imagelen;
+	kspace = buflen - HDR_LENGTH;
+
+	/* Get kernel length */
+	fseek(in, 0, SEEK_END);
+	klen = ftell(in);
+	rewind(in);
+
+	if (klen > kspace) {
+		ERR("file \"%s\" is too big - max size: 0x%08lX\n",
+		    ifname, kspace);
+		goto err_close_in;
+	}
+
+	/* If requested, resize buffer to remove padding */
+	if (strip_padding)
+		buflen = klen + HDR_LENGTH;
+
+	/* Allocate and initialize buffer for final image */
+	buf = malloc(buflen);
+	if (buf == NULL) {
+		ERRS("no memory for buffer: %s\n");
+		goto err_close_in;
+	}
+	memset(buf, PADDING_BYTE, buflen);
+
+	/* Load kernel */
+	kernel = buf + HDR_LENGTH;
+	fread(kernel, klen, 1, in);
+
+	/* Write magic values */
+	writel(buf, HDR_OFF_MAGIC1, board->magic1);
+	writel(buf, HDR_OFF_MAGIC2, board->magic2);
+	writel(buf, HDR_OFF_MAGIC3, board->magic3);
+
+	/* Write header and image length */
+	writel(buf, HDR_OFF_HDRLEN, HDR_LENGTH);
+	writel(buf, HDR_OFF_IMAGELEN, klen);
+
+	/* Write checksum and static hash */
+	sha1_csum(kernel, klen, buf + HDR_OFF_CHECKSUM);
+
+	switch (board->magic2) {
+	case 0xa1f0beef:
+		writel(buf, HDR_OFF_KERNEL_OFFSET, board->u.mx60.kernel_offset);
+		writel(buf, HDR_OFF_RAMDISK_OFFSET, board->u.mx60.ramdisk_offset);
+		writel(buf, HDR_OFF_FDT_OFFSET, board->u.mx60.fdt_offset),
+		writel(buf, HDR_OFF_UNKNOWN_OFFSET, board->u.mx60.unknown_offset);
+		break;
+
+	case 0x8e73ed8a:
+		memcpy(buf + HDR_OFF_STATICHASH, board->u.statichash, 20);
+		break;
+	}
+
+	/* Save finished image */
+	out = fopen(ofname, "w");
+	if (out == NULL) {
+		ERRS("could not open \"%s\" for writing: %s", ofname);
+		goto err_free;
+	}
+	fwrite(buf, buflen, 1, out);
+
+	ret = EXIT_SUCCESS;
+
+	fclose(out);
+
+err_free:
+	free(buf);
+
+err_close_in:
+	fclose(in);
+
+err:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/mkmylofw.c b/tools/firmware-utils/src/mkmylofw.c
new file mode 100644
index 0000000000..b5958ebe0f
--- /dev/null
+++ b/tools/firmware-utils/src/mkmylofw.c
@@ -0,0 +1,1297 @@
+/*
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the
+ *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>     /* for __BYTE_ORDER */
+
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#else
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#endif
+
+#include "myloader.h"
+
+#define MAX_FW_BLOCKS  	32
+#define MAX_ARG_COUNT   32
+#define MAX_ARG_LEN     1024
+#define FILE_BUF_LEN    (16*1024)
+#define PART_NAME_LEN	32
+
+struct fw_block {
+	uint32_t	addr;
+	uint32_t	blocklen; /* length of the block */
+	uint32_t	flags;
+
+	char		*name;  /* name of the file */
+	uint32_t	size;  	/* length of the file */
+	uint32_t	crc;    /* crc value of the file */
+};
+
+struct fw_part {
+	struct mylo_partition	mylo;
+	char			name[PART_NAME_LEN];
+};
+
+#define BLOCK_FLAG_HAVEHDR    0x0001
+
+struct cpx_board {
+	char		*model; /* model number*/
+	char		*name;	/* model name*/
+	char		*desc;  /* description */
+	uint16_t        vid;    /* vendor id */
+	uint16_t        did;    /* device id */
+	uint16_t        svid;   /* sub vendor id */
+	uint16_t        sdid;   /* sub device id */
+	uint32_t        flash_size;     /* size of flash */
+	uint32_t	part_offset;	/* offset of the partition_table */
+	uint32_t	part_size;	/* size of the partition_table */
+};
+
+#define BOARD(_vid, _did, _svid, _sdid, _flash, _mod, _name, _desc, _po, _ps) {		\
+	.model = _mod, .name = _name, .desc = _desc,   			\
+	.vid = _vid, .did = _did, .svid = _svid, .sdid = _sdid,         \
+	.flash_size = (_flash << 20),					\
+	.part_offset = _po, .part_size = _ps }
+
+#define CPX_BOARD(_did, _flash, _mod, _name, _desc, _po, _ps) \
+	BOARD(VENID_COMPEX, _did, VENID_COMPEX, _did, _flash, _mod, _name, _desc, _po, _ps)
+
+#define CPX_BOARD_ADM(_did, _flash, _mod, _name, _desc) \
+	CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x10000, 0x10000)
+
+#define CPX_BOARD_AR71XX(_did, _flash, _mod, _name, _desc) \
+	CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x20000, 0x8000)
+
+#define CPX_BOARD_AR23XX(_did, _flash, _mod, _name, _desc) \
+	CPX_BOARD(_did, _flash, _mod, _name, _desc, 0x10000, 0x10000)
+
+#define ALIGN(x,y)	((x)+((y)-1)) & ~((y)-1)
+
+char	*progname;
+char	*ofname = NULL;
+
+uint32_t flash_size = 0;
+int	fw_num_partitions = 0;
+int	fw_num_blocks = 0;
+int	verblevel = 0;
+
+struct mylo_fw_header fw_header;
+struct fw_part fw_parts[MYLO_MAX_PARTITIONS];
+struct fw_block fw_blocks[MAX_FW_BLOCKS];
+struct cpx_board *board;
+
+struct cpx_board boards[] = {
+	CPX_BOARD_ADM(DEVID_COMPEX_NP18A, 4,
+		"NP18A", "Compex NetPassage 18A",
+		"Dualband Wireless A+G Internet Gateway"),
+	CPX_BOARD_ADM(DEVID_COMPEX_NP26G8M, 2,
+		"NP26G8M", "Compex NetPassage 26G (8M)",
+		"Wireless-G Broadband Multimedia Gateway"),
+	CPX_BOARD_ADM(DEVID_COMPEX_NP26G16M, 4,
+		"NP26G16M", "Compex NetPassage 26G (16M)",
+		"Wireless-G Broadband Multimedia Gateway"),
+	CPX_BOARD_ADM(DEVID_COMPEX_NP27G, 4,
+		"NP27G", "Compex NetPassage 27G",
+		"Wireless-G 54Mbps eXtended Range Router"),
+	CPX_BOARD_ADM(DEVID_COMPEX_NP28G, 4,
+		"NP28G", "Compex NetPassage 28G",
+		"Wireless 108Mbps Super-G XR Multimedia Router with 4 USB Ports"),
+	CPX_BOARD_ADM(DEVID_COMPEX_NP28GHS, 4,
+		"NP28GHS", "Compex NetPassage 28G (HotSpot)",
+		"HotSpot Solution"),
+	CPX_BOARD_ADM(DEVID_COMPEX_WP18, 4,
+		"WP18", "Compex NetPassage WP18",
+		"Wireless-G 54Mbps A+G Dualband Access Point"),
+	CPX_BOARD_ADM(DEVID_COMPEX_WP54G, 4,
+		"WP54G", "Compex WP54G",
+		"Wireless-G 54Mbps XR Access Point"),
+	CPX_BOARD_ADM(DEVID_COMPEX_WP54Gv1C, 2,
+		"WP54Gv1C", "Compex WP54G rev.1C",
+		"Wireless-G 54Mbps XR Access Point"),
+	CPX_BOARD_ADM(DEVID_COMPEX_WP54AG, 4,
+		"WP54AG", "Compex WP54AG",
+		"Wireless-AG 54Mbps XR Access Point"),
+	CPX_BOARD_ADM(DEVID_COMPEX_WPP54G, 4,
+		"WPP54G", "Compex WPP54G",
+		"Outdoor Access Point"),
+	CPX_BOARD_ADM(DEVID_COMPEX_WPP54AG, 4,
+		"WPP54AG", "Compex WPP54AG",
+		"Outdoor Access Point"),
+
+	CPX_BOARD_AR71XX(DEVID_COMPEX_WP543, 2,
+		"WP543", "Compex WP543",
+		"BareBoard"),
+	CPX_BOARD_AR71XX(DEVID_COMPEX_WPE72, 8,
+		"WPE72", "Compex WPE72",
+		"BareBoard"),
+
+	CPX_BOARD_AR23XX(DEVID_COMPEX_NP25G, 4,
+		"NP25G", "Compex NetPassage 25G",
+		"Wireless 54Mbps XR Router"),
+	CPX_BOARD_AR23XX(DEVID_COMPEX_WPE53G, 4,
+		"WPE53G", "Compex NetPassage 25G",
+		"Wireless 54Mbps XR Access Point"),
+	{.model = NULL}
+};
+
+void
+errmsgv(int syserr, const char *fmt, va_list arg_ptr)
+{
+	int save = errno;
+
+	fflush(0);
+	fprintf(stderr, "[%s] Error: ", progname);
+	vfprintf(stderr, fmt, arg_ptr);
+	if (syserr != 0) {
+		fprintf(stderr, ": %s", strerror(save));
+	}
+	fprintf(stderr, "\n");
+}
+
+void
+errmsg(int syserr, const char *fmt, ...)
+{
+	va_list arg_ptr;
+	va_start(arg_ptr, fmt);
+	errmsgv(syserr, fmt, arg_ptr);
+	va_end(arg_ptr);
+}
+
+void
+dbgmsg(int level, const char *fmt, ...)
+{
+	va_list arg_ptr;
+	if (verblevel >= level) {
+		fflush(0);
+		va_start(arg_ptr, fmt);
+		vfprintf(stderr, fmt, arg_ptr);
+		fprintf(stderr, "\n");
+		va_end(arg_ptr);
+	}
+}
+
+
+void
+usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct cpx_board *board;
+
+	fprintf(stream, "Usage: %s [OPTION...] <file>\n", progname);
+	fprintf(stream,
+"\n"
+"  <file>          write output to the <file>\n"
+"\n"
+"Options:\n"
+"  -B <board>      create firmware for the board specified with <board>.\n"
+"                  This option set vendor id, device id, subvendor id,\n"
+"                  subdevice id, and flash size options to the right value.\n"
+"                  valid <board> values:\n");
+	for (board = boards; board->model != NULL; board++){
+		fprintf(stream,
+"                      %-12s: %s\n",
+		 board->model, board->name);
+	};
+	fprintf(stream,
+"  -i <vid>:<did>[:<svid>[:<sdid>]]\n"
+"                  create firmware for board with vendor id <vid>, device\n"
+"                  id <did>, subvendor id <svid> and subdevice id <sdid>.\n"
+"  -r <rev>        set board revision to <rev>.\n"
+"  -s <size>       set flash size to <size>\n"
+"  -b <addr>:<len>[:[<flags>]:<file>]\n"
+"                  define block at <addr> with length of <len>.\n"
+"                  valid <flag> values:\n"
+"                      h : add crc header before the file data.\n"
+"  -p <addr>:<len>[:<flags>[:<param>[:<name>[:<file>]]]]\n"
+"                  add partition at <addr>, with size of <len> to the\n"
+"                  partition table, set partition name to <name>, partition \n"
+"                  flags to <flags> and partition parameter to <param>.\n"
+"                  If the <file> is specified content of the file will be \n"
+"                  added to the firmware image.\n"
+"                  valid <flag> values:\n"
+"                      a:  this is the active partition. The bootloader loads\n"
+"                          the firmware from this partition.\n"
+"                      h:  the partition data have a header.\n"
+"                      l:  the partition data uses LZMA compression.\n"
+"                      p:  the bootloader loads data from this partition to\n"
+"                          the RAM before decompress it.\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static uint32_t crc_32_tab[256];
+
+void
+init_crc_table(void)
+{
+	/* Not copyrighted 1990 Mark Adler	*/
+
+	uint32_t c;      /* crc shift register */
+	uint32_t e;      /* polynomial exclusive-or pattern */
+	int i;           /* counter for all possible eight bit values */
+	int k;           /* byte being shifted into crc apparatus */
+
+	/* terms of polynomial defining this crc (except x^32): */
+	static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+	/* Make exclusive-or pattern from polynomial */
+	e = 0;
+	for (i = 0; i < sizeof(p)/sizeof(int); i++)
+		e |= 1L << (31 - p[i]);
+
+	crc_32_tab[0] = 0;
+
+	for (i = 1; i < 256; i++) {
+		c = 0;
+		for (k = i | 256; k != 1; k >>= 1) {
+			c = c & 1 ? (c >> 1) ^ e : c >> 1;
+			if (k & 1)
+				c ^= e;
+		}
+		crc_32_tab[i] = c;
+	}
+}
+
+
+void
+update_crc(uint8_t *p, uint32_t len, uint32_t *crc)
+{
+	uint32_t t;
+
+	t = *crc ^ 0xFFFFFFFFUL;
+	while (len--) {
+		t = crc_32_tab[(t ^ *p++) & 0xff] ^ (t >> 8);
+	}
+	*crc = t ^ 0xFFFFFFFFUL;
+}
+
+
+uint32_t
+get_crc(uint8_t *p, uint32_t len)
+{
+	uint32_t crc;
+
+	crc = 0;
+	update_crc(p ,len , &crc);
+	return crc;
+}
+
+
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+		return -1;
+	}
+
+	*val = t & 0xFFFF;
+	return 0;
+}
+
+
+struct cpx_board *
+find_board(char *model){
+	struct cpx_board *board;
+	struct cpx_board *tmp;
+
+	board = NULL;
+	for (tmp = boards; tmp->model != NULL; tmp++){
+		if (strcasecmp(model, tmp->model) == 0) {
+			board = tmp;
+			break;
+		}
+	};
+
+	return board;
+}
+
+
+int
+get_file_crc(struct fw_block *ff)
+{
+	FILE *f;
+	uint8_t buf[FILE_BUF_LEN];
+	uint32_t readlen = sizeof(buf);
+	int res = -1;
+	size_t len;
+
+	if ((ff->flags & BLOCK_FLAG_HAVEHDR) == 0) {
+		res = 0;
+		goto out;
+	}
+
+	errno = 0;
+	f = fopen(ff->name,"r");
+	if (errno) {
+		errmsg(1,"unable to open file %s", ff->name);
+		goto out;
+	}
+
+	ff->crc = 0;
+	len = ff->size;
+	while (len > 0) {
+		if (len < readlen)
+			readlen = len;
+
+		errno = 0;
+		fread(buf, readlen, 1, f);
+		if (errno) {
+			errmsg(1,"unable to read from file %s",	ff->name);
+			goto out_close;
+		}
+
+		update_crc(buf, readlen, &ff->crc);
+		len -= readlen;
+	}
+
+	res = 0;
+
+out_close:
+	fclose(f);
+out:
+	return res;
+}
+
+
+int
+process_files(void)
+{
+	struct fw_block *b;
+	struct stat st;
+	int i;
+
+	for (i = 0; i < fw_num_blocks; i++) {
+		b = &fw_blocks[i];
+		if ((b->addr + b->blocklen) > flash_size) {
+			errmsg(0, "block at 0x%08X is too big", b->addr);
+			return -1;
+		}
+		if (b->name == NULL)
+			continue;
+
+		if (stat(b->name, &st) < 0) {
+			errmsg(0, "stat failed on %s",b->name);
+			return -1;
+		}
+		if (b->blocklen == 0) {
+			b->blocklen = flash_size - b->addr;
+		}
+		if (st.st_size > b->blocklen) {
+			errmsg(0,"file %s is too big",b->name);
+			return -1;
+		}
+
+		b->size = st.st_size;
+	}
+
+	return 0;
+}
+
+
+int
+process_partitions(void)
+{
+	struct mylo_partition *part;
+	int i;
+
+	for (i = 0; i < fw_num_partitions; i++) {
+		part = &fw_parts[i].mylo;
+
+		if (part->addr > flash_size) {
+			errmsg(0, "invalid partition at 0x%08X", part->addr);
+			return -1;
+		}
+
+		if ((part->addr + part->size) > flash_size) {
+			errmsg(0, "partition at 0x%08X is too big", part->addr);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len, uint32_t *crc)
+{
+	errno = 0;
+
+	fwrite(data, len, 1, outfile);
+	if (errno) {
+		errmsg(1,"unable to write output file");
+		return -1;
+	}
+
+	if (crc) {
+		update_crc(data, len, crc);
+	}
+
+	return 0;
+}
+
+
+int
+write_out_desc(FILE *outfile, struct mylo_fw_blockdesc *desc, uint32_t *crc)
+{
+	return write_out_data(outfile, (uint8_t *)desc,
+		sizeof(*desc), crc);
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc, uint32_t *crc)
+{
+	uint8_t buff[512];
+	size_t  buflen = sizeof(buff);
+
+	memset(buff, padc, buflen);
+
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		if (write_out_data(outfile, buff, buflen, crc))
+			return -1;
+
+		len -= buflen;
+	}
+
+	return 0;
+}
+
+
+int
+write_out_file(FILE *outfile, struct fw_block *block, uint32_t *crc)
+{
+	char buff[FILE_BUF_LEN];
+	size_t  buflen = sizeof(buff);
+	FILE *f;
+	size_t len;
+
+	errno = 0;
+
+	if (block->name == NULL) {
+		return 0;
+	}
+
+	if ((block->flags & BLOCK_FLAG_HAVEHDR) != 0) {
+		struct mylo_partition_header ph;
+
+		if (get_file_crc(block) != 0)
+		        return -1;
+
+		ph.crc = HOST_TO_LE32(block->crc);
+		ph.len = HOST_TO_LE32(block->size);
+
+		if (write_out_data(outfile, (uint8_t *)&ph, sizeof(ph), crc) != 0)
+			return -1;
+	}
+
+	f = fopen(block->name,"r");
+	if (errno) {
+		errmsg(1,"unable to open file: %s", block->name);
+		return -1;
+	}
+
+	len = block->size;
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		/* read data from source file */
+		errno = 0;
+		fread(buff, buflen, 1, f);
+		if (errno != 0) {
+			errmsg(1,"unable to read from file: %s",block->name);
+			return -1;
+		}
+
+		if (write_out_data(outfile, buff, buflen, crc) != 0)
+			return -1;
+
+		len -= buflen;
+	}
+
+	fclose(f);
+
+	/* align next block on a 4 byte boundary */
+	len = ALIGN(len,4) - block->size;
+	if (write_out_padding(outfile, len, 0xFF, crc))
+		return -1;
+
+	dbgmsg(1,"file %s written out", block->name);
+	return 0;
+}
+
+
+int
+write_out_header(FILE *outfile, uint32_t *crc)
+{
+	struct mylo_fw_header hdr;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.magic = HOST_TO_LE32(MYLO_MAGIC_FIRMWARE);
+	hdr.crc = HOST_TO_LE32(fw_header.crc);
+	hdr.vid = HOST_TO_LE16(fw_header.vid);
+	hdr.did = HOST_TO_LE16(fw_header.did);
+	hdr.svid = HOST_TO_LE16(fw_header.svid);
+	hdr.sdid = HOST_TO_LE16(fw_header.sdid);
+	hdr.rev = HOST_TO_LE32(fw_header.rev);
+	hdr.fwhi = HOST_TO_LE32(fw_header.fwhi);
+	hdr.fwlo = HOST_TO_LE32(fw_header.fwlo);
+	hdr.flags = HOST_TO_LE32(fw_header.flags);
+
+	if (fseek(outfile, 0, SEEK_SET) != 0) {
+		errmsg(1,"fseek failed on output file");
+		return -1;
+	}
+
+	return write_out_data(outfile, (uint8_t *)&hdr, sizeof(hdr), crc);
+}
+
+
+int
+write_out_partitions(FILE *outfile, uint32_t *crc)
+{
+	struct mylo_partition_table p;
+	char part_names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
+	int ret;
+	int i;
+
+	if (fw_num_partitions == 0)
+		return 0;
+
+	memset(&p, 0, sizeof(p));
+	memset(part_names, 0, sizeof(part_names));
+
+	p.magic = HOST_TO_LE32(MYLO_MAGIC_PARTITIONS);
+	for (i = 0; i < fw_num_partitions; i++) {
+		struct mylo_partition *mp;
+		struct fw_part *fp;
+
+		mp = &p.partitions[i];
+		fp = &fw_parts[i];
+		mp->flags = HOST_TO_LE16(fp->mylo.flags);
+		mp->type = HOST_TO_LE16(PARTITION_TYPE_USED);
+		mp->addr = HOST_TO_LE32(fp->mylo.addr);
+		mp->size = HOST_TO_LE32(fp->mylo.size);
+		mp->param = HOST_TO_LE32(fp->mylo.param);
+
+		memcpy(part_names[i], fp->name, PART_NAME_LEN);
+	}
+
+	ret = write_out_data(outfile, (uint8_t *)&p, sizeof(p), crc);
+	if (ret)
+		return ret;
+
+	ret = write_out_data(outfile, (uint8_t *)part_names, sizeof(part_names),
+				crc);
+	return ret;
+}
+
+
+int
+write_out_blocks(FILE *outfile, uint32_t *crc)
+{
+	struct mylo_fw_blockdesc desc;
+	struct fw_block *b;
+	uint32_t dlen;
+	int i;
+
+	/*
+	 * if at least one partition specified, write out block descriptor
+	 * for the partition table
+	 */
+	if (fw_num_partitions > 0) {
+		desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED);
+		desc.addr = HOST_TO_LE32(board->part_offset);
+		desc.dlen = HOST_TO_LE32(sizeof(struct mylo_partition_table) +
+					(MYLO_MAX_PARTITIONS * PART_NAME_LEN));
+		desc.blen = HOST_TO_LE32(board->part_size);
+
+		if (write_out_desc(outfile, &desc, crc) != 0)
+		        return -1;
+	}
+
+	/*
+	 * write out block descriptors for each files
+	 */
+	for (i = 0; i < fw_num_blocks; i++) {
+		b = &fw_blocks[i];
+
+		/* detect block size */
+		dlen = b->size;
+		if ((b->flags & BLOCK_FLAG_HAVEHDR) != 0) {
+			dlen += sizeof(struct mylo_partition_header);
+		}
+
+		/* round up to 4 bytes */
+		dlen = ALIGN(dlen, 4);
+
+		/* setup the descriptor */
+		desc.type = HOST_TO_LE32(FW_DESC_TYPE_USED);
+		desc.addr = HOST_TO_LE32(b->addr);
+		desc.dlen = HOST_TO_LE32(dlen);
+		desc.blen = HOST_TO_LE32(b->blocklen);
+
+		if (write_out_desc(outfile, &desc, crc) != 0)
+			return -1;
+	}
+
+	/*
+	 * write out the null block descriptor
+	 */
+	memset(&desc, 0, sizeof(desc));
+	if (write_out_desc(outfile, &desc, crc) != 0)
+		return -1;
+
+	if (write_out_partitions(outfile, crc) != 0)
+		return -1;
+
+	/*
+	 * write out data for each blocks
+	 */
+	for (i = 0; i < fw_num_blocks; i++) {
+		b = &fw_blocks[i];
+		if (write_out_file(outfile, b, crc) != 0)
+		        return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * argument parsing
+ */
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+	int res = 0;
+	size_t argl;
+	char *tok;
+	char **ap = &buf;
+	int i;
+
+	if ((arg == NULL)) {
+		/* invalid argument string */
+		return -1;
+	}
+
+	argl = strlen(arg);
+	if (argl == 0) {
+		/* no arguments */
+		return res;
+	}
+
+	if (argl >= MAX_ARG_LEN) {
+		/* argument is too long */
+		argl = MAX_ARG_LEN-1;
+	}
+
+	memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+	memcpy(buf, arg, argl);
+	buf[argl] = '\0';
+
+	for (i = 0; i < MAX_ARG_COUNT; i++) {
+		tok = strsep(ap, ":");
+		if (tok == NULL) {
+			break;
+		}
+#if 0
+		else if (tok[0] == '\0') {
+			break;
+		}
+#endif
+		argv[i] = tok;
+		res++;
+	}
+
+	return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+	if ((optarg != NULL) && (*arg == '-')){
+		errmsg(0,"option %c requires an argument\n", c);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+	int ret = 1;
+	if (arg != NULL) {
+		if (*arg) ret = 0;
+	};
+	return ret;
+}
+
+
+int
+parse_opt_flags(char ch, char *arg)
+{
+	if (required_arg(ch, arg)) {
+		goto err_out;
+	}
+
+	if (str2u32(arg, &fw_header.flags) != 0) {
+		errmsg(0,"invalid firmware flags: %s", arg);
+		goto err_out;
+	}
+
+	dbgmsg(1, "firmware flags set to %X bytes", fw_header.flags);
+
+	return 0;
+
+err_out:
+	return -1;
+}
+
+
+int
+parse_opt_size(char ch, char *arg)
+{
+	if (required_arg(ch, arg)) {
+		goto err_out;
+	}
+
+	if (str2u32(arg, &flash_size) != 0) {
+		errmsg(0,"invalid flash size: %s", arg);
+		goto err_out;
+	}
+
+	dbgmsg(1, "flash size set to %d bytes", flash_size);
+
+	return 0;
+
+err_out:
+	return -1;
+}
+
+
+int
+parse_opt_id(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	char *p;
+
+	if (required_arg(ch, arg)) {
+		goto err_out;
+	}
+
+	argc = parse_arg(arg, buf, argv);
+
+	/* processing vendor ID*/
+	p = argv[0];
+	if (is_empty_arg(p)) {
+		errmsg(0,"vendor id is missing from -%c %s",ch, arg);
+		goto err_out;
+	} else if (str2u16(p, &fw_header.vid) != 0) {
+		errmsg(0,"invalid vendor id: %s", p);
+		goto err_out;
+	}
+
+	dbgmsg(1, "vendor id is set to 0x%04X", fw_header.vid);
+
+	/* processing device ID*/
+	p = argv[1];
+	if (is_empty_arg(p)) {
+		errmsg(0,"device id is missing from -%c %s",ch, arg);
+		goto err_out;
+	} else if (str2u16(p, &fw_header.did) != 0) {
+		errmsg(0,"invalid device id: %s", p);
+		goto err_out;
+	}
+
+	dbgmsg(1, "device id is set to 0x%04X", fw_header.did);
+
+	/* processing sub vendor ID*/
+	p = argv[2];
+	if (is_empty_arg(p)) {
+		fw_header.svid = fw_header.vid;
+	} else if (str2u16(p, &fw_header.svid) != 0) {
+		errmsg(0,"invalid sub vendor id: %s", p);
+		goto err_out;
+	}
+
+	dbgmsg(1, "sub vendor id is set to 0x%04X", fw_header.svid);
+
+	/* processing device ID*/
+	p = argv[3];
+	if (is_empty_arg(p)) {
+		fw_header.sdid = fw_header.did;
+	} else if (str2u16(p, &fw_header.sdid) != 0) {
+		errmsg(0,"invalid sub device id: %s", p);
+		goto err_out;
+	}
+
+	dbgmsg(1, "sub device id is set to 0x%04X", fw_header.sdid);
+
+	/* processing revision */
+	p = argv[4];
+	if (is_empty_arg(p)) {
+		fw_header.rev = 0;
+	} else if (str2u32(arg, &fw_header.rev) != 0) {
+		errmsg(0,"invalid revision number: %s", p);
+		goto err_out;
+	}
+
+	dbgmsg(1, "board revision is set to 0x%08X", fw_header.rev);
+
+	return 0;
+
+err_out:
+	return -1;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	struct fw_block *b;
+	char *p;
+
+	if (required_arg(ch, arg)) {
+		goto err_out;
+	}
+
+	if (fw_num_blocks >= MAX_FW_BLOCKS) {
+		errmsg(0,"too many blocks specified");
+		goto err_out;
+	}
+
+	argc = parse_arg(arg, buf, argv);
+	dbgmsg(1,"processing block option %s, count %d", arg, argc);
+
+	b = &fw_blocks[fw_num_blocks++];
+
+	/* processing block address */
+	p = argv[0];
+	if (is_empty_arg(p)) {
+		errmsg(0,"no block address specified in %s", arg);
+		goto err_out;
+	} else if (str2u32(p, &b->addr) != 0) {
+		errmsg(0,"invalid block address: %s", p);
+		goto err_out;
+	}
+
+	/* processing block length */
+	p = argv[1];
+	if (is_empty_arg(p)) {
+		errmsg(0,"no block length specified in %s", arg);
+		goto err_out;
+	} else if (str2u32(p, &b->blocklen) != 0) {
+		errmsg(0,"invalid block length: %s", p);
+		goto err_out;
+	}
+
+	if (argc < 3) {
+		dbgmsg(1,"empty block %s", arg);
+		goto success;
+	}
+
+	/* processing flags */
+	p = argv[2];
+	if (is_empty_arg(p) == 0) {
+		for ( ; *p != '\0'; p++) {
+			switch (*p) {
+			case 'h':
+				b->flags |= BLOCK_FLAG_HAVEHDR;
+				break;
+			default:
+				errmsg(0, "invalid block flag \"%c\"", *p);
+				goto err_out;
+			}
+		}
+	}
+
+	/* processing file name */
+	p = argv[3];
+	if (is_empty_arg(p)) {
+		errmsg(0,"file name missing in %s", arg);
+		goto err_out;
+	}
+
+	b->name = strdup(p);
+	if (b->name == NULL) {
+		errmsg(0,"not enough memory");
+		goto err_out;
+	}
+
+success:
+
+	return 0;
+
+err_out:
+	return -1;
+}
+
+
+int
+parse_opt_partition(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	char *p;
+	struct mylo_partition *part;
+	struct fw_part *fp;
+
+	if (required_arg(ch, arg)) {
+		goto err_out;
+	}
+
+	if (fw_num_partitions >= MYLO_MAX_PARTITIONS) {
+		errmsg(0, "too many partitions specified");
+		goto err_out;
+	}
+
+	fp = &fw_parts[fw_num_partitions++];
+	part = &fp->mylo;
+
+	argc = parse_arg(arg, buf, argv);
+
+	/* processing partition address */
+	p = argv[0];
+	if (is_empty_arg(p)) {
+		errmsg(0,"partition address missing in -%c %s",ch, arg);
+		goto err_out;
+	} else if (str2u32(p, &part->addr) != 0) {
+		errmsg(0,"invalid partition address: %s", p);
+		goto err_out;
+	}
+
+	/* processing partition size */
+	p = argv[1];
+	if (is_empty_arg(p)) {
+		errmsg(0,"partition size missing in -%c %s",ch, arg);
+		goto err_out;
+	} else if (str2u32(p, &part->size) != 0) {
+		errmsg(0,"invalid partition size: %s", p);
+		goto err_out;
+	}
+
+	/* processing partition flags */
+	p = argv[2];
+	if (is_empty_arg(p) == 0) {
+		for ( ; *p != '\0'; p++) {
+			switch (*p) {
+			case 'a':
+				part->flags |= PARTITION_FLAG_ACTIVE;
+				break;
+			case 'p':
+				part->flags |= PARTITION_FLAG_PRELOAD;
+				break;
+			case 'l':
+				part->flags |= PARTITION_FLAG_LZMA;
+				break;
+			case 'h':
+				part->flags |= PARTITION_FLAG_HAVEHDR;
+				break;
+			default:
+				errmsg(0, "invalid partition flag \"%c\"", *p);
+				goto err_out;
+			}
+		}
+	}
+
+	/* processing partition parameter */
+	p = argv[3];
+	if (is_empty_arg(p)) {
+		/* set default partition parameter */
+		part->param = 0;
+	} else if (str2u32(p, &part->param) != 0) {
+		errmsg(0,"invalid partition parameter: %s", p);
+		goto err_out;
+	}
+
+	p = argv[4];
+	if (is_empty_arg(p)) {
+		/* set default partition parameter */
+		fp->name[0] = '\0';
+	} else {
+		strncpy(fp->name, p, PART_NAME_LEN);
+	}
+
+#if 1
+	if (part->size == 0) {
+		part->size = flash_size - part->addr;
+	}
+
+	/* processing file parameter */
+	p = argv[5];
+	if (is_empty_arg(p) == 0) {
+		struct fw_block *b;
+
+		if (fw_num_blocks == MAX_FW_BLOCKS) {
+			errmsg(0,"too many blocks specified", p);
+			goto err_out;
+		}
+		b = &fw_blocks[fw_num_blocks++];
+		b->name = strdup(p);
+		b->addr = part->addr;
+		b->blocklen = part->size;
+		if (part->flags & PARTITION_FLAG_HAVEHDR) {
+			b->flags |= BLOCK_FLAG_HAVEHDR;
+		}
+	}
+#endif
+
+	return 0;
+
+err_out:
+	return -1;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+	if (required_arg(ch, arg)) {
+		goto err_out;
+	}
+
+	board = find_board(arg);
+	if (board == NULL){
+		errmsg(0,"invalid/unknown board specified: %s", arg);
+		goto err_out;
+	}
+
+	fw_header.vid = board->vid;
+	fw_header.did = board->did;
+	fw_header.svid = board->svid;
+	fw_header.sdid = board->sdid;
+
+	flash_size = board->flash_size;
+
+	return 0;
+
+err_out:
+	return -1;
+}
+
+
+int
+parse_opt_rev(char ch, char *arg)
+{
+	if (required_arg(ch, arg)) {
+		return -1;
+	}
+
+	if (str2u32(arg, &fw_header.rev) != 0) {
+		errmsg(0,"invalid revision number: %s", arg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * main
+ */
+int
+main(int argc, char *argv[])
+{
+	int optinvalid = 0;   /* flag for invalid option */
+	int c;
+	int res = EXIT_FAILURE;
+
+	FILE  *outfile;
+	uint32_t crc;
+
+	progname=basename(argv[0]);
+
+	memset(&fw_header, 0, sizeof(fw_header));
+
+	/* init header defaults */
+	fw_header.vid = VENID_COMPEX;
+	fw_header.did = DEVID_COMPEX_WP54G;
+	fw_header.svid = VENID_COMPEX;
+	fw_header.sdid = DEVID_COMPEX_WP54G;
+	fw_header.fwhi = 0x20000;
+	fw_header.fwlo = 0x20000;
+	fw_header.flags = 0;
+
+	opterr = 0;  /* could not print standard getopt error messages */
+	while ((c = getopt(argc, argv, "b:B:f:hi:p:r:s:v")) != -1) {
+		optinvalid = 0;
+		switch (c) {
+		case 'b':
+			optinvalid = parse_opt_block(c,optarg);
+			break;
+		case 'B':
+			optinvalid = parse_opt_board(c,optarg);
+			break;
+		case 'f':
+			optinvalid = parse_opt_flags(c,optarg);
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		case 'i':
+			optinvalid = parse_opt_id(c,optarg);
+			break;
+		case 'p':
+			optinvalid = parse_opt_partition(c,optarg);
+			break;
+		case 'r':
+			optinvalid = parse_opt_rev(c,optarg);
+			break;
+		case 's':
+			optinvalid = parse_opt_size(c,optarg);
+			break;
+		case 'v':
+			verblevel++;
+			break;
+		default:
+			optinvalid = 1;
+			break;
+		}
+		if (optinvalid != 0 ){
+			errmsg(0, "invalid option: -%c", optopt);
+			goto out;
+		}
+	}
+
+	if (optind == argc) {
+		errmsg(0, "no output file specified");
+		goto out;
+	}
+
+	ofname = argv[optind++];
+
+	if (optind < argc) {
+		errmsg(0, "invalid option: %s", argv[optind]);
+		goto out;
+	}
+
+	if (!board) {
+		errmsg(0, "no board specified");
+		goto out;
+	}
+
+	if (flash_size == 0) {
+		errmsg(0, "no flash size specified");
+		goto out;
+	}
+
+	if (process_files() != 0) {
+		goto out;
+	}
+
+	if (process_partitions() != 0) {
+		goto out;
+	}
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		errmsg(1, "could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	crc = 0;
+	init_crc_table();
+
+	if (write_out_header(outfile, &crc) != 0)
+		goto out_flush;
+
+	if (write_out_blocks(outfile, &crc) != 0)
+		goto out_flush;
+
+	fw_header.crc = crc;
+	if (write_out_header(outfile, NULL) != 0)
+		goto out_flush;
+
+	dbgmsg(1,"Firmware file %s completed.", ofname);
+
+	res = EXIT_SUCCESS;
+
+out_flush:
+	fflush(outfile);
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+out:
+	return res;
+}
diff --git a/tools/firmware-utils/src/mkplanexfw.c b/tools/firmware-utils/src/mkplanexfw.c
new file mode 100644
index 0000000000..0b71f80438
--- /dev/null
+++ b/tools/firmware-utils/src/mkplanexfw.c
@@ -0,0 +1,269 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "sha1.h"
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define HOST_TO_BE32(x)	(x)
+#  define BE32_TO_HOST(x)	(x)
+#else
+#  define HOST_TO_BE32(x)	bswap_32(x)
+#  define BE32_TO_HOST(x)	bswap_32(x)
+#endif
+
+
+struct planex_hdr {
+	uint8_t		sha1sum[20];
+	char		version[8];
+	uint8_t		unk1[2];
+	uint32_t	datalen;
+} __attribute__ ((packed));
+
+struct board_info {
+	char		*id;
+	uint32_t	seed;
+	uint8_t		unk[2];
+	uint32_t	datalen;
+};
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static char *version = "1.00.00";
+
+static char *board_id;
+static struct board_info *board;
+
+static struct board_info boards[] = {
+	{
+		.id		= "MZK-W04NU",
+		.seed		= 2,
+		.unk		= {0x04, 0x08},
+		.datalen	= 0x770000,
+	}, {
+		.id		= "MZK-W300NH",
+		.seed		= 4,
+		.unk		= {0x00, 0x00},
+		.datalen	= 0x770000,
+	}, {
+		/* terminating entry */
+	}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->id != NULL; board++){
+		if (strcasecmp(id, board->id) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -v <version>    set image version to <version>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int buflen;
+	int err;
+	struct stat st;
+	char *buf;
+	struct planex_hdr *hdr;
+	sha1_context ctx;
+	uint32_t seed;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "B:i:o:v:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'v':
+			version = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (board_id == NULL) {
+		ERR("no board specified");
+		goto err;
+	}
+
+	board = find_board(board_id);
+	if (board == NULL) {
+		ERR("unknown board '%s'", board_id);
+		goto err;
+	};
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	if (st.st_size > board->datalen) {
+		ERR("file '%s' is too big - max size: 0x%08X (exceeds %lu bytes)\n",
+		    ifname, board->datalen, st.st_size - board->datalen);
+		goto err;
+	}
+
+	buflen = board->datalen + 0x10000;
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	memset(buf, 0xff, buflen);
+	hdr = (struct planex_hdr *)buf;
+
+	hdr->datalen = HOST_TO_BE32(board->datalen);
+	hdr->unk1[0] = board->unk[0];
+	hdr->unk1[1] = board->unk[1];
+
+	snprintf(hdr->version, sizeof(hdr->version), "%s", version);
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	errno = 0;
+	fread(buf +  sizeof(*hdr), st.st_size, 1, infile);
+	if (errno != 0) {
+		ERRS("unable to read from file %s", ifname);
+		goto err_close_in;
+	}
+
+	seed = HOST_TO_BE32(board->seed);
+	sha1_starts(&ctx);
+	sha1_update(&ctx, (uchar *) &seed, sizeof(seed));
+	sha1_update(&ctx, buf + sizeof(*hdr), board->datalen);
+	sha1_finish(&ctx, hdr->sha1sum);
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto err_close_in;
+	}
+
+	errno = 0;
+	fwrite(buf, buflen, 1, outfile);
+	if (errno) {
+		ERRS("unable to write to file %s", ofname);
+		goto err_close_out;
+	}
+
+	res = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(outfile);
+
+ err_close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+
+ err_close_in:
+	fclose(infile);
+
+ err_free:
+	free(buf);
+
+ err:
+	return res;
+}
+
diff --git a/tools/firmware-utils/src/mkporayfw.c b/tools/firmware-utils/src/mkporayfw.c
new file mode 100644
index 0000000000..6ec4f320d9
--- /dev/null
+++ b/tools/firmware-utils/src/mkporayfw.c
@@ -0,0 +1,791 @@
+/*
+ * Builder/viewer/extractor utility for Poray firmware image files
+ *
+ * Copyright (C) 2013 Michel Stempin <michel.stempin@wanadoo.fr>
+ * Copyright (C) 2013 Felix Kaechele <felix@fetzig.org>
+ * Copyright (C) 2013 <admin@openschemes.com>
+ *
+ * This tool is based on:
+ *   TP-Link firmware upgrade tool.
+ *   Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Itself based on:
+ *   TP-Link WR941 V2 firmware checksum fixing tool.
+ *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define HOST_TO_BE32(x)	(x)
+#  define BE32_TO_HOST(x)	(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#else
+#  define HOST_TO_BE32(x)	bswap_32(x)
+#  define BE32_TO_HOST(x)	bswap_32(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#endif
+
+/* Fixed header flags */
+#define HEADER_FLAGS		0x020e0000
+
+/* Recognized Hardware ID magic */
+#define HWID_HAME_MPR_A1_L8	0x32473352
+#define HWID_PORAY_R50B		0x31353033
+#define HWID_PORAY_R50D		0x33353033
+#define HWID_PORAY_R50E		0x34353033
+#define HWID_PORAY_M3		0x31353335
+#define HWID_PORAY_M4		0x32353335
+#define HWID_PORAY_Q3		0x33353335
+#define HWID_PORAY_X5_X6	0x35353335
+#define HWID_PORAY_X8		0x36353335
+#define HWID_PORAY_X1		0x38353335
+#define HWID_NEXX_WT1520	0x30353332
+#define HWID_NEXX_WT3020	0x30323033
+#define HWID_A5_V11		0x32473352
+
+/* Recognized XOR obfuscation keys */
+#define KEY_HAME		0
+#define KEY_PORAY_1		1
+#define KEY_PORAY_2		2
+#define KEY_PORAY_3		3
+#define KEY_PORAY_4		4
+#define KEY_NEXX_1		5
+#define KEY_NEXX_2		6
+#define KEY_A5_V11		7
+
+/* XOR key length */
+#define KEY_LEN			15
+
+struct file_info {
+	char		*file_name;	/* Name of the file */
+	uint32_t	file_size;	/* Length of the file */
+};
+
+struct fw_header {
+	uint32_t	hw_id;		/* Hardware id */
+	uint32_t	firmware_len;	/* Firmware data length */
+	uint32_t	flags;		/* Header flags */
+	uint8_t		pad[16];
+} __attribute__ ((packed));
+
+struct flash_layout {
+	char		*id;
+	uint32_t	fw_max_len;
+};
+
+struct board_info {
+	char		*id;
+	uint32_t	hw_id;
+	char		*layout_id;
+	uint32_t	key;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *board_id;
+static struct board_info *board;
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static struct file_info firmware_info;
+static uint32_t firmware_len = 0;
+
+static int inspect = 0;
+static int extract = 0;
+
+static uint8_t key[][KEY_LEN] = {
+  {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x12, 0x03, 0x08},
+  {0x89, 0x6B, 0x5A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0xC9, 0x1C, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0x19, 0x1B, 0x3A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0x79, 0x7B, 0x7A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7},
+  {0x19, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
+  {0x39, 0x1C, 0x4A, 0x93, 0x96, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0x16, 0xC6},
+  {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x20, 0x11, 0x08},
+};
+
+static struct flash_layout layouts[] = {
+	{
+		.id		= "4M",
+		.fw_max_len	= 0x3c0000,
+	}, {
+		.id		= "8M",
+		.fw_max_len	= 0x7c0000,
+	}, {
+		/* terminating entry */
+	}
+};
+
+static struct board_info boards[] = {
+	{
+		.id             = "A5-V11",
+		.hw_id          = HWID_A5_V11,
+		.layout_id      = "4M",
+		.key            = KEY_A5_V11,
+        }, {
+		.id		= "MPR-A1",
+		.hw_id		= HWID_HAME_MPR_A1_L8,
+		.layout_id	= "4M",
+		.key		= KEY_HAME,
+	}, {
+		.id		= "MPR-L8",
+		.hw_id		= HWID_HAME_MPR_A1_L8,
+		.layout_id	= "4M",
+		.key		= KEY_HAME,
+	}, {
+		.id		= "R50B",
+		.hw_id		= HWID_PORAY_R50B,
+		.layout_id	= "4M",
+		.key		= KEY_PORAY_2,
+	}, {
+		.id		= "R50D",
+		.hw_id		= HWID_PORAY_R50D,
+		.layout_id	= "4M",
+		.key		= KEY_PORAY_3,
+	}, {
+		.id		= "R50E",
+		.hw_id		= HWID_PORAY_R50E,
+		.layout_id	= "4M",
+		.key		= KEY_PORAY_4,
+	}, {
+		.id		= "M3",
+		.hw_id		= HWID_PORAY_M3,
+		.layout_id	= "4M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "M4",
+		.hw_id		= HWID_PORAY_M4,
+		.layout_id	= "4M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "Q3",
+		.hw_id		= HWID_PORAY_Q3,
+		.layout_id	= "4M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "X5 or X6",
+		.hw_id		= HWID_PORAY_X5_X6,
+		.layout_id	= "8M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "X5",
+		.hw_id		= HWID_PORAY_X5_X6,
+		.layout_id	= "8M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "X6",
+		.hw_id		= HWID_PORAY_X5_X6,
+		.layout_id	= "8M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "X8",
+		.hw_id		= HWID_PORAY_X8,
+		.layout_id	= "8M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "X1",
+		.hw_id		= HWID_PORAY_X1,
+		.layout_id	= "8M",
+		.key		= KEY_PORAY_1,
+	}, {
+		.id		= "WT1520",
+		.hw_id		= HWID_NEXX_WT1520,
+		.layout_id	= "4M",
+		.key		= KEY_NEXX_1,
+	}, {
+		.id		= "WT1520",
+		.hw_id		= HWID_NEXX_WT1520,
+		.layout_id	= "8M",
+		.key		= KEY_NEXX_1,
+        }, {
+                .id             = "WT3020",
+                .hw_id          = HWID_NEXX_WT3020,
+                .layout_id      = "4M",
+                .key            = KEY_NEXX_2,
+        }, {
+                .id             = "WT3020",
+                .hw_id          = HWID_NEXX_WT3020,
+                .layout_id      = "8M",
+                .key            = KEY_NEXX_2,
+        }, {
+
+
+
+
+		/* terminating entry */
+	}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ":%s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+/*
+ * Find a board by its name
+ */
+static struct board_info *find_board(char *id)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->id != NULL; board++){
+		if (strcasecmp(id, board->id) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+/*
+ * Find a board by its hardware ID
+ */
+static struct board_info *find_board_by_hwid(uint32_t hw_id)
+{
+	struct board_info *board;
+
+	for (board = boards; board->id != NULL; board++) {
+		if (hw_id == board->hw_id)
+			return board;
+	};
+
+	return NULL;
+}
+
+/*
+ * Find a Flash memory layout by its name
+ */
+static struct flash_layout *find_layout(char *id)
+{
+	struct flash_layout *ret;
+	struct flash_layout *l;
+
+	ret = NULL;
+	for (l = layouts; l->id != NULL; l++){
+		if (strcasecmp(id, l->id) == 0) {
+			ret = l;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+/*
+ * Display usage
+ */
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -H <hwid>       use hardware id specified with <hwid>\n"
+"  -F <id>         use flash layout specified with <id>\n"
+"  -f <file>       read firmware image from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -i              inspect given firmware file (requires -f)\n"
+"  -x              extract combined kernel and rootfs while inspecting (implies -i)\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+/*
+ * Get file statistics
+ */
+static int get_file_stat(struct file_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL) {
+		return 0;
+	}
+	res = stat(fdata->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	return 0;
+}
+
+/*
+ * Read file into buffer
+ */
+static int read_to_buf(struct file_info *fdata, uint8_t *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "rb");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+ out_close:
+	fclose(f);
+ out:
+	return ret;
+}
+
+/*
+ * Check command line options
+ */
+static int check_options(void)
+{
+	int ret;
+
+	if (firmware_info.file_name == NULL) {
+		ERR("no firmware image specified");
+		return -1;
+	}
+
+	ret = get_file_stat(&firmware_info);
+	if (ret)
+		return ret;
+
+	if (inspect)
+		return 0;
+
+	if (board_id == NULL && opt_hw_id == NULL) {
+		ERR("either board or hardware id must be specified");
+		return -1;
+	}
+
+	if (board_id) {
+		board = find_board(board_id);
+		if (board == NULL) {
+			ERR("unknown/unsupported board id \"%s\"", board_id);
+			return -1;
+		}
+		if (layout_id == NULL) {
+			layout_id = board->layout_id;
+		}
+		hw_id = board->hw_id;
+	} else {
+		hw_id = strtoul(opt_hw_id, NULL, 0);
+		board = find_board_by_hwid(hw_id);
+		if (layout_id == NULL) {
+			layout_id = board->layout_id;
+		}
+	}
+
+	layout = find_layout(layout_id);
+	if (layout == NULL) {
+		ERR("unknown flash layout \"%s\"", layout_id);
+		return -1;
+	}
+
+	firmware_len = firmware_info.file_size;
+
+	if (firmware_info.file_size >
+		layout->fw_max_len - sizeof (struct fw_header)) {
+		ERR("firmware image is too big");
+		return -1;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Fill in firmware header
+ */
+static void fill_header(uint8_t *buf)
+{
+	struct fw_header *hdr = (struct fw_header *) buf;
+
+	memset(hdr, 0, sizeof (struct fw_header));
+	hdr->hw_id = HOST_TO_LE32(hw_id);
+	hdr->firmware_len = HOST_TO_LE32(firmware_len);
+	hdr->flags = HOST_TO_LE32(HEADER_FLAGS);
+}
+
+/*
+ * Compute firmware checksum
+ */
+static uint16_t checksum_fw(uint8_t *data, int len)
+{
+	int i;
+	int32_t checksum = 0;
+
+	for (i = 0; i < len - 1; i += 2) {
+		checksum += (data[i + 1] << 8) | data[i];
+	}
+	if (i < len) {
+		checksum += data[i];
+	}
+	checksum = checksum + (checksum >> 16) + 0xffff;
+	checksum = ~(checksum + (checksum >> 16)) & 0xffff;
+	return (uint16_t) checksum;
+}
+
+/*
+ * (De)obfuscate firmware using an XOR operation with a fixed length key
+ */
+static void xor_fw(uint8_t *data, int len)
+{
+	int i;
+
+	for (i = 0; i <= len; i++) {
+		data[i] ^= key[board->key][i % KEY_LEN];
+	}
+}
+
+/*
+ * Write firmware to file
+ */
+static int write_fw(uint8_t *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "wb");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+ out:
+	return ret;
+}
+
+/*
+ * Build firmware file
+ */
+static int build_fw(void)
+{
+	int buflen;
+	uint8_t *buf, *p;
+	int ret = EXIT_FAILURE;
+	int writelen = 0;
+	uint16_t checksum;
+
+	buflen = layout->fw_max_len;
+
+	buf = (uint8_t *) malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	memset(buf, 0xff, buflen);
+	p = buf + sizeof (struct fw_header);
+	ret = read_to_buf(&firmware_info, p);
+	if (ret) {
+		goto out_free_buf;
+	}
+	writelen = sizeof (struct fw_header) + firmware_len + 2;
+
+	/* Fill in header */
+	fill_header(buf);
+
+	/* Compute firmware checksum */
+	checksum = checksum_fw(buf + sizeof (struct fw_header), firmware_len);
+
+	/* Cannot use network order function because checksum is not word-aligned */
+	buf[writelen - 1] = checksum >> 8;
+	buf[writelen - 2] = checksum & 0xff;
+
+	/* XOR obfuscate firmware */
+	xor_fw(buf + sizeof (struct fw_header), firmware_len + 2);
+
+	/* Write firmware file */
+	ret = write_fw(buf, writelen);
+	if (ret) {
+		goto out_free_buf;
+	}
+	ret = EXIT_SUCCESS;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(char *label, char *str)
+{
+	printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(char *label, uint32_t val)
+{
+	printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexpost(char *label,
+                                       uint32_t val, char *post)
+{
+	printf("%-23s: 0x%08x (%s)\n", label, val, post);
+}
+
+static inline void inspect_fw_phexdef(char *label,
+                                      uint32_t val, uint32_t defval)
+{
+	printf("%-23s: 0x%08x                  ", label, val);
+
+	if (val == defval) {
+		printf("(== OpenWrt default)\n");
+	} else {
+		printf("(OpenWrt default: 0x%08x)\n", defval);
+	}
+}
+
+static inline void inspect_fw_phexexp(char *label,
+                                      uint32_t val, uint32_t expval)
+{
+	printf("%-23s: 0x%08x ", label, val);
+
+	if (val == expval) {
+		printf("(ok)\n");
+	} else {
+		printf("(expected: 0x%08x)\n", expval);
+	}
+}
+
+static inline void inspect_fw_phexdec(char *label, uint32_t val)
+{
+	printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_pchecksum(char *label,
+					uint16_t val, uint16_t expval)
+{
+	printf("%-23s: 0x%04x     ", label, val);
+	if (val == expval) {
+		printf("(ok)\n");
+	} else {
+		printf("(expected: 0x%04x)\n", expval);
+	}
+}
+
+static int inspect_fw(void)
+{
+	uint8_t *buf;
+	struct fw_header *hdr;
+	int ret = EXIT_FAILURE;
+	uint16_t computed_checksum, file_checksum;
+
+	buf = (uint8_t *) malloc(firmware_info.file_size);
+	if (!buf) {
+		ERR("no memory for buffer!\n");
+		goto out;
+	}
+
+	ret = read_to_buf(&firmware_info, buf);
+	if (ret) {
+		goto out_free_buf;
+	}
+	hdr = (struct fw_header *)buf;
+
+	inspect_fw_pstr("File name", firmware_info.file_name);
+	inspect_fw_phexdec("File size", firmware_info.file_size);
+
+	printf("\n");
+
+	inspect_fw_phexdec("Header size", sizeof (struct fw_header));
+	board = find_board_by_hwid(LE32_TO_HOST(hdr->hw_id));
+	if (board) {
+		layout = find_layout(board->layout_id);
+		inspect_fw_phexpost("Hardware ID",
+				    LE32_TO_HOST( hdr->hw_id), board->id);
+	} else {
+		inspect_fw_phexpost("Hardware ID",
+		                    LE32_TO_HOST(hdr->hw_id), "unknown");
+	}
+	inspect_fw_phexdec("Firmware data length",
+	                   LE32_TO_HOST(hdr->firmware_len));
+
+	inspect_fw_phexexp("Flags",
+			   LE32_TO_HOST(hdr->flags), HEADER_FLAGS);
+	printf("\n");
+
+	/* XOR unobfuscate firmware */
+	xor_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len) + 2);
+
+	/* Compute firmware checksum */
+	computed_checksum = checksum_fw(buf + sizeof (struct fw_header), LE32_TO_HOST(hdr->firmware_len));
+
+	/* Cannot use network order function because checksum is not word-aligned */
+	file_checksum = (buf[firmware_info.file_size - 1] << 8) | buf[firmware_info.file_size - 2];
+	inspect_fw_pchecksum("Firmware checksum", computed_checksum, file_checksum);
+
+	/* Verify checksum */
+	if (computed_checksum != file_checksum) {
+		ret = -1;
+		ERR("checksums do not match");
+		goto out_free_buf;
+	}
+
+	printf("\n");
+
+	if (extract) {
+		FILE *fp;
+		char *filename;
+
+		if (ofname == NULL) {
+			filename = malloc(strlen(firmware_info.file_name) + 10);
+			sprintf(filename, "%s-firmware", firmware_info.file_name);
+		} else {
+			filename = ofname;
+		}
+		printf("Extracting firmware to \"%s\"...\n", filename);
+		fp = fopen(filename, "wb");
+		if (fp)	{
+		  if (!fwrite(buf + sizeof (struct fw_header),
+			            LE32_TO_HOST(hdr->firmware_len), 1, fp)) {
+				ERRS("error in fwrite(): %s", strerror(errno));
+			}
+			fclose(fp);
+		} else {
+			ERRS("error in fopen(): %s", strerror(errno));
+		}
+		if (ofname == NULL) {
+			free(filename);
+		}
+		printf("\n");
+	}
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+/*
+ * Main entry point
+ */
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	progname = basename(argv[0]);
+
+	int c;
+
+	while ((c = getopt(argc, argv, "B:H:F:f:o:ixh")) != -1) {
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'H':
+			opt_hw_id = optarg;
+			break;
+		case 'F':
+			layout_id = optarg;
+			break;
+		case 'f':
+			firmware_info.file_name = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'i':
+			inspect = 1;
+			break;
+		case 'x':
+			inspect = 1;
+			extract = 1;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret) {
+		goto out;
+	}
+	if (!inspect) {
+		ret = build_fw();
+	} else {
+		ret = inspect_fw();
+	}
+
+ out:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/mkrtn56uimg.c b/tools/firmware-utils/src/mkrtn56uimg.c
new file mode 100644
index 0000000000..fe9ae2c877
--- /dev/null
+++ b/tools/firmware-utils/src/mkrtn56uimg.c
@@ -0,0 +1,294 @@
+/*
+ *
+ *  Copyright (C) 2014 OpenWrt.org
+ *  Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
+ *
+ *  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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#define IH_MAGIC	0x27051956
+#define IH_NMLEN	32
+#define IH_PRODLEN	23
+
+#define IH_TYPE_INVALID		0
+#define IH_TYPE_STANDALONE	1
+#define IH_TYPE_KERNEL		2
+#define IH_TYPE_RAMDISK		3
+#define IH_TYPE_MULTI		4
+#define IH_TYPE_FIRMWARE	5
+#define IH_TYPE_SCRIPT		6
+#define IH_TYPE_FILESYSTEM	7
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE		0
+#define IH_COMP_GZIP		1
+#define IH_COMP_BZIP2		2
+#define IH_COMP_LZMA		3
+
+typedef struct {
+	uint8_t major;
+	uint8_t minor;
+} version_t;
+
+typedef struct {
+	version_t	kernel;
+	version_t	fs;
+	uint8_t		productid[IH_PRODLEN];
+	uint8_t  	sub_fs;
+	uint32_t	ih_ksz;
+} asus_t;
+
+typedef struct image_header {
+	uint32_t	ih_magic;
+	uint32_t	ih_hcrc;
+	uint32_t	ih_time;
+	uint32_t	ih_size;
+	uint32_t	ih_load;
+	uint32_t	ih_ep;
+	uint32_t	ih_dcrc;
+	uint8_t		ih_os;
+	uint8_t		ih_arch;
+	uint8_t		ih_type;
+	uint8_t		ih_comp;
+	union {
+		uint8_t	ih_name[IH_NMLEN];
+		asus_t	asus;
+	} tail;
+} image_header_t;
+
+typedef struct squashfs_sb {
+	uint32_t	s_magic;
+	uint32_t	pad0[9];
+	uint64_t	bytes_used;
+} squashfs_sb_t;
+
+typedef enum {
+	NONE, FACTORY, SYSUPGRADE,
+} op_mode_t;
+
+void
+calc_crc(image_header_t *hdr, void *data, uint32_t len)
+{
+	/*
+	 * Calculate payload checksum
+	 */
+	hdr->ih_dcrc = htonl(crc32(0, (Bytef *)data, len));
+	hdr->ih_size = htonl(len);
+	/*
+	 * Calculate header checksum
+	 */
+	hdr->ih_hcrc = 0;
+	hdr->ih_hcrc = htonl(crc32(0, (Bytef *)hdr, sizeof(image_header_t)));
+}
+
+
+static void
+usage(const char *progname, int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	int i;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream, "\n"
+			"Options:\n"
+			"  -f <file>		generate a factory flash image <file>\n"
+			"  -s <file>		generate a sysupgrade flash image <file>\n"
+			"  -h			show this screen\n");
+	exit(status);
+}
+
+int
+process_image(char *progname, char *filename, op_mode_t opmode)
+{
+	int 		fd, len;
+	void 		*data, *ptr;
+	char		namebuf[IH_NMLEN];
+	struct 		stat sbuf;
+	uint32_t	checksum, offset_kernel, offset_sqfs, offset_end,
+				offset_sec_header, offset_eb, offset_image_end;
+	squashfs_sb_t *sqs;
+	image_header_t *hdr;
+
+	if ((fd = open(filename, O_RDWR, 0666)) < 0) {
+		fprintf (stderr, "%s: Can't open %s: %s\n",
+			progname, filename, strerror(errno));
+		return (EXIT_FAILURE);
+	}
+
+	if (fstat(fd, &sbuf) < 0) {
+		fprintf (stderr, "%s: Can't stat %s: %s\n",
+			progname, filename, strerror(errno));
+		return (EXIT_FAILURE);
+	}
+
+	if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
+		fprintf (stderr,
+			"%s: Bad size: \"%s\" is no valid image\n",
+			progname, filename);
+		return (EXIT_FAILURE);
+	}
+
+	ptr = (void *)mmap(0, sbuf.st_size,
+				PROT_READ | PROT_WRITE,
+				MAP_SHARED,
+				fd, 0);
+
+	if ((caddr_t)ptr == (caddr_t)-1) {
+		fprintf (stderr, "%s: Can't read %s: %s\n",
+			progname, filename, strerror(errno));
+		return (EXIT_FAILURE);
+	}
+
+	hdr = ptr;
+
+	if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+		fprintf (stderr,
+			"%s: Bad Magic Number: \"%s\" is no valid image\n",
+			progname, filename);
+		return (EXIT_FAILURE);
+	}
+
+	if (opmode == FACTORY) {
+		strncpy(namebuf, hdr->tail.ih_name, IH_NMLEN);
+		hdr->tail.asus.kernel.major = 0;
+		hdr->tail.asus.kernel.minor = 0;
+		hdr->tail.asus.fs.major = 0;
+		hdr->tail.asus.fs.minor = 0;
+		strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN);
+	}
+
+	if (hdr->tail.asus.ih_ksz == 0)
+		hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t));
+
+	offset_kernel = sizeof(image_header_t);
+	offset_sqfs = ntohl(hdr->tail.asus.ih_ksz);
+	sqs = ptr + offset_sqfs;
+	offset_sec_header = offset_sqfs + sqs->bytes_used;
+
+	/*
+	 * Reserve space for the second header.
+	 */
+	offset_end = offset_sec_header + sizeof(image_header_t);
+	offset_eb = ((offset_end>>16)+1)<<16;
+
+	if (opmode == FACTORY)
+		offset_image_end = offset_eb + 4;
+	else
+		offset_image_end = sbuf.st_size;
+	/*
+	 * Move the second header at the end of the image.
+	 */
+	offset_end = offset_sec_header;
+	offset_sec_header = offset_eb - sizeof(image_header_t);
+
+	/*
+	 * Remove jffs2 markers between squashfs and eb boundary.
+	 */
+	if (opmode == FACTORY)
+		memset(ptr+offset_end, 0xff ,offset_eb - offset_end);
+
+	/*
+	 * Grow the image if needed.
+	 */
+	if (offset_image_end > sbuf.st_size) {
+		(void) munmap((void *)ptr, sbuf.st_size);
+		ftruncate(fd, offset_image_end);
+		ptr = (void *)mmap(0, offset_image_end,
+						PROT_READ | PROT_WRITE,
+						MAP_SHARED,
+						fd, 0);
+		/*
+		 * jffs2 marker
+		 */
+		if (opmode == FACTORY) {
+			*(uint8_t *)(ptr+offset_image_end-4) = 0xde;
+			*(uint8_t *)(ptr+offset_image_end-3) = 0xad;
+			*(uint8_t *)(ptr+offset_image_end-2) = 0xc0;
+			*(uint8_t *)(ptr+offset_image_end-1) = 0xde;
+		}
+	}
+
+	/*
+	 * Calculate checksums for the second header to be used after flashing.
+	 */
+	if (opmode == FACTORY) {
+		hdr = ptr+offset_sec_header;
+		memcpy(hdr, ptr, sizeof(image_header_t));
+		strncpy(hdr->tail.ih_name, namebuf, IH_NMLEN);
+		calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+		calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel);
+	} else {
+		calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+	}
+
+	if (sbuf.st_size > offset_image_end)
+		(void) munmap((void *)ptr, sbuf.st_size);
+	else
+		(void) munmap((void *)ptr, offset_image_end);
+
+	ftruncate(fd, offset_image_end);
+	(void) close (fd);
+
+	return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv)
+{
+	int 		opt;
+	char 		*filename, *progname;
+	op_mode_t	opmode = NONE;
+
+	progname = argv[0];
+
+	while ((opt = getopt(argc, argv,":s:f:h?")) != -1) {
+		switch (opt) {
+		case 's':
+			opmode = SYSUPGRADE;
+			filename = optarg;
+			break;
+		case 'f':
+			opmode = FACTORY;
+			filename = optarg;
+			break;
+		case 'h':
+			opmode = NONE;
+		default:
+			usage(progname, EXIT_FAILURE);
+			opmode = NONE;
+		}
+	}
+
+	if(filename == NULL)
+		opmode = NONE;
+
+	switch (opmode) {
+	case NONE:
+		usage(progname, EXIT_FAILURE);
+		break;
+	case FACTORY:
+	case SYSUPGRADE:
+		return process_image(progname, filename, opmode);
+		break;
+	}
+
+	return EXIT_SUCCESS;
+}
+
diff --git a/tools/firmware-utils/src/mksenaofw.c b/tools/firmware-utils/src/mksenaofw.c
new file mode 100644
index 0000000000..0f10ebdfbe
--- /dev/null
+++ b/tools/firmware-utils/src/mksenaofw.c
@@ -0,0 +1,420 @@
+/*
+ *
+ *  Copyright (C) 2012 OpenWrt.org
+ *  Copyright (C) 2012 Mikko Hissa <mikko.hissa@uta.fi>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include "md5.h"
+
+#define HDR_LEN                 0x60
+#define BUF_SIZE                0x200
+#define VERSION_SIZE            0x10
+#define MD5_SIZE                0x10
+#define PAD_SIZE                0x20
+
+#define DEFAULT_BLOCK_SIZE      65535
+
+#define DEFAULT_HEAD_VALUE      0x0
+#define DEFAULT_VERSION         "123"
+#define DEFAULT_MAGIC           0x12345678
+
+typedef struct {
+	uint32_t head;
+	uint32_t vendor_id;
+	uint32_t product_id;
+	uint8_t  version[VERSION_SIZE];
+	uint32_t firmware_type;
+	uint32_t filesize;
+	uint32_t zero;
+	uint8_t  md5sum[MD5_SIZE];
+	uint8_t  pad[PAD_SIZE];
+	uint32_t chksum;
+	uint32_t magic;
+} img_header;
+
+typedef struct {
+	uint8_t id;
+	char * name;
+} firmware_type;
+
+typedef enum {
+	NONE, ENCODE, DECODE
+} op_mode;
+
+static firmware_type FIRMWARE_TYPES[] = {
+	{ 0x01, "bootloader" },
+	{ 0x02, "kernel" },
+	{ 0x03, "kernelapp" },
+	{ 0x04, "apps" },
+	/* The types below this line vary by manufacturer */
+	{ 0x05, "littleapps (D-Link)/factoryapps (EnGenius)" },
+	{ 0x06, "sounds (D-Link)/littleapps (EnGenius)" },
+	{ 0x07, "userconfig (D-Link)/appdata (EnGenius)" },
+	{ 0x08, "userconfig (EnGenius)"},
+	{ 0x09, "odmapps (EnGenius)"},
+	{ 0x0a, "factoryapps (D-Link)" },
+	{ 0x0b, "odmapps (D-Link)" },
+	{ 0x0c, "langpack (D-Link)" }
+};
+
+static long get_file_size(const char *filename)
+{
+	FILE *fp_file;
+	long result;
+
+	fp_file = fopen(filename, "r");
+	if (!fp_file)
+		return -1;
+	fseek(fp_file, 0, SEEK_END);
+	result = ftell(fp_file);
+	fclose(fp_file);
+	return result;
+}
+
+static int header_checksum(void *data, int len)
+{
+	int i;
+	int sum;
+
+	sum = 0;
+	if (data != NULL && len >= 0) {
+		for (i = 0; i < len; ++i)
+			sum += *(unsigned char *) (data + i);
+		return sum;
+	}
+
+	return -1;
+}
+
+static int md5_file(const char *filename, uint8_t *dst)
+{
+	FILE *fp_src;
+	MD5_CTX ctx;
+	char buf[BUF_SIZE];
+	size_t bytes_read;
+
+	MD5_Init(&ctx);
+
+	fp_src = fopen(filename, "r+b");
+	if (!fp_src) {
+		return -1;
+	}
+	while (!feof(fp_src)) {
+		bytes_read = fread(&buf, 1, BUF_SIZE, fp_src);
+		MD5_Update(&ctx, &buf, bytes_read);
+	}
+	fclose(fp_src);
+
+	MD5_Final(dst, &ctx);
+
+	return 0;
+}
+
+static int encode_image(const char *input_file_name,
+		const char *output_file_name, img_header *header, int block_size)
+{
+	char buf[BUF_SIZE];
+	size_t bytes_read;
+	size_t pad_len = 0;
+	size_t bytes_avail;
+
+	FILE *fp_input;
+	FILE *fp_output;
+
+	int i;
+	long magic;
+
+	fp_input = fopen(input_file_name, "r+b");
+	if (!fp_input) {
+		fprintf(stderr, "Cannot open %s !!\n", input_file_name);
+		return -1;
+	}
+
+	fp_output = fopen(output_file_name, "w+b");
+	if (!fp_output) {
+		fprintf(stderr, "Cannot open %s !!\n", output_file_name);
+		fclose(fp_input);
+		return -1;
+	}
+
+	header->filesize = get_file_size(input_file_name);
+	if (!header->filesize) {
+		fprintf(stderr, "File %s open/size error!\n", input_file_name);
+		fclose(fp_input);
+		fclose(fp_output);
+		return -1;
+	}
+	/*
+	 * Zero padding
+	 */
+	if (block_size > 0) {
+		pad_len = block_size - (header->filesize % block_size);
+	}
+
+	if (md5_file(input_file_name, (uint8_t *) &header->md5sum) < 0) {
+		fprintf(stderr, "MD5 failed on file %s\n", input_file_name);
+		fclose(fp_input);
+		fclose(fp_output);
+		return -1;
+	}
+	header->zero = 0;
+	header->chksum = header_checksum(header, HDR_LEN);
+	header->head = htonl(header->head);
+	header->vendor_id = htonl(header->vendor_id);
+	header->product_id = htonl(header->product_id);
+	header->firmware_type = htonl(header->firmware_type);
+	header->filesize = htonl(header->filesize);
+	header->chksum = htonl(header->chksum);
+	magic = header->magic;
+	header->magic = htonl(header->magic);
+
+	fwrite(header, HDR_LEN, 1, fp_output);
+
+	while (!feof(fp_input) || pad_len > 0) {
+
+		if (!feof(fp_input))
+			bytes_read = fread(&buf, 1, BUF_SIZE, fp_input);
+		else
+			bytes_read = 0;
+
+		/*
+		 * No more bytes read, start padding
+		 */
+		if (bytes_read < BUF_SIZE && pad_len > 0) {
+			bytes_avail = BUF_SIZE - bytes_read;
+			memset( &buf[bytes_read], 0, bytes_avail);
+			bytes_read += bytes_avail < pad_len ? bytes_avail : pad_len;
+			pad_len -= bytes_avail < pad_len ? bytes_avail : pad_len;
+		}
+
+		for (i = 0; i < bytes_read; i++)
+			buf[i] ^= magic >> (i % 8) & 0xff;
+		fwrite(&buf, bytes_read, 1, fp_output);
+	}
+
+	fclose(fp_input);
+	fclose(fp_output);
+	return 1;
+}
+
+int decode_image(const char *input_file_name, const char *output_file_name)
+{
+	img_header header;
+	char buf[BUF_SIZE];
+
+	FILE *fp_input;
+	FILE *fp_output;
+	unsigned int i;
+
+	size_t bytes_read;
+	size_t bytes_written;
+
+	fp_input = fopen(input_file_name, "r+b");
+	if (!fp_input) {
+		fprintf(stderr, "Cannot open %s !!\n", input_file_name);
+		fclose(fp_input);
+		return -1;
+	}
+
+	fp_output = fopen(output_file_name, "w+b");
+	if (!fp_output) {
+		fprintf(stderr, "Cannot open %s !!\n", output_file_name);
+		fclose(fp_output);
+		return -1;
+	}
+
+	if (fread(&header, 1, HDR_LEN, fp_input) != HDR_LEN) {
+		fprintf(stderr, "Incorrect header size!!");
+		fclose(fp_input);
+		fclose(fp_output);
+		return -1;
+	}
+
+	header.head = ntohl(header.head);
+	header.vendor_id = ntohl(header.vendor_id);
+	header.product_id = ntohl(header.product_id);
+	header.firmware_type = ntohl(header.firmware_type);
+	header.filesize = ntohl(header.filesize);
+	header.chksum = ntohl(header.chksum);
+	header.magic = ntohl(header.magic);
+
+	bytes_written = 0;
+	while (!feof(fp_input)) {
+
+		bytes_read = fread(&buf, 1, BUF_SIZE, fp_input);
+		for (i = 0; i < bytes_read; i++)
+			buf[i] ^= header.magic >> (i % 8) & 0xff;
+
+		/*
+		 * Handle padded source file
+		 */
+		if (bytes_written + bytes_read > header.filesize) {
+			bytes_read = header.filesize - bytes_written;
+			if (bytes_read > 0)
+				fwrite(&buf, bytes_read, 1, fp_output);
+			break;
+		}
+
+		fwrite(&buf, bytes_read, 1, fp_output);
+		bytes_written += bytes_read;
+	}
+
+	fclose(fp_input);
+	fclose(fp_output);
+
+	return 1;
+}
+
+static void usage(const char *progname, int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	int i;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream, "\n"
+			"Options:\n"
+			"  -e <file>		encode image file <file>\n"
+			"  -d <file>		decode image file <file>\n"
+			"  -o <file>		write output to the file <file>\n"
+			"  -t <type>		set image type to <type>\n"
+			"			valid image <type> values:\n");
+	for (i = 0; i < sizeof(FIRMWARE_TYPES) / sizeof(firmware_type); i++) {
+		fprintf(stream, "			%-5i= %s\n", FIRMWARE_TYPES[i].id,
+				FIRMWARE_TYPES[i].name);
+	}
+	fprintf(stream, "  -v <version>		set image version to <version>\n"
+			"  -r <vendor>		set image vendor id to <vendor>\n"
+			"  -p <product>		set image product id to <product>\n"
+			"  -m <magic>		set encoding magic <magic>\n"
+			"  -z			enable image padding to <blocksize>\n"
+			"  -b <blocksize>	set image <blocksize>, defaults to %u\n"
+			"  -h			show this screen\n", DEFAULT_BLOCK_SIZE);
+	exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt;
+	char *input_file, *output_file, *progname = NULL;
+	op_mode mode = NONE;
+	int tmp, i, pad = 0;
+	int block_size;
+	img_header header;
+
+	block_size = DEFAULT_BLOCK_SIZE;
+	progname = basename(argv[0]);
+
+	memset(&header, 0, sizeof( img_header ));
+	header.magic = DEFAULT_MAGIC;
+	header.head = DEFAULT_HEAD_VALUE;
+	strncpy( (char*)&header.version, DEFAULT_VERSION, VERSION_SIZE - 1);
+
+	while ((opt = getopt(argc, argv, ":o:e:d:t:v:r:p:m:b:h?z")) != -1) {
+		switch (opt) {
+		case 'e':
+			input_file = optarg;
+			mode = ENCODE;
+			break;
+		case 'd':
+			input_file = optarg;
+			mode = DECODE;
+			break;
+		case 'o':
+			output_file = optarg;
+			break;
+		case 't':
+			tmp = strtol(optarg, 0, 10);
+			for (i = 0; i < sizeof(FIRMWARE_TYPES) / sizeof(firmware_type);
+					i++) {
+				if (FIRMWARE_TYPES[i].id == tmp) {
+					header.firmware_type = FIRMWARE_TYPES[i].id;
+					break;
+				}
+			}
+			if (header.firmware_type == 0) {
+				fprintf(stderr, "Invalid firmware type \"0\"!\n");
+				usage(progname, EXIT_FAILURE);
+			}
+			break;
+		case 'v':
+			strncpy( (char*)&header.version, optarg,
+					VERSION_SIZE - 1);
+			break;
+		case 'r':
+			header.vendor_id = strtol(optarg, 0, 0);
+			break;
+		case 'p':
+			header.product_id = strtol(optarg, 0, 0);
+			break;
+		case 'm':
+			header.magic = strtoul(optarg, 0, 16);
+			break;
+		case 'z':
+			pad = 1;
+			break;
+		case 'b':
+			block_size = strtol(optarg, 0, 10);
+			break;
+		case 'h':
+			usage(progname, EXIT_SUCCESS);
+			break;
+		case ':':
+			fprintf(stderr, "Option -%c requires an operand\n", optopt);
+			usage(progname, EXIT_FAILURE);
+			break;
+		case '?':
+			fprintf(stderr, "Unrecognized option: -%c\n", optopt);
+			usage(progname, EXIT_FAILURE);
+			break;
+		default:
+			usage(progname, EXIT_FAILURE);
+			break;
+		}
+	}
+
+	/* Check required arguments */
+	if (mode == NONE) {
+		fprintf(stderr, "A mode must be defined\n");
+		usage(progname, EXIT_FAILURE);
+	}
+
+	if (input_file == NULL || output_file == NULL) {
+		fprintf(stderr, "Input and output files must be defined\n");
+		usage(progname, EXIT_FAILURE);
+	}
+
+	if (mode == DECODE) {
+		if (decode_image(input_file, output_file) < 0)
+				return EXIT_FAILURE;
+
+		return EXIT_SUCCESS;
+	}
+
+	if (header.firmware_type == 0) {
+		fprintf(stderr, "Firmware type must be defined\n");
+		usage(progname, EXIT_FAILURE);
+	}
+
+	if (header.vendor_id == 0 || header.product_id == 0) {
+		fprintf(stderr, "Vendor ID and Product ID must be defined and non-zero\n");
+		usage(progname, EXIT_FAILURE);
+	}
+
+	if (encode_image(input_file, output_file, &header, pad ? block_size : 0) < 0)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/mktitanimg.c b/tools/firmware-utils/src/mktitanimg.c
new file mode 100644
index 0000000000..cca4a0ebae
--- /dev/null
+++ b/tools/firmware-utils/src/mktitanimg.c
@@ -0,0 +1,1040 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include "mktitanimg.h"
+
+
+struct checksumrecord
+{
+		unsigned int magic;
+        unsigned int    chksum;     /* The checksum for the complete header.
+ Excepting the
+                                           checksum block */
+};
+/***************************************************************************
+ * void print_help(void)
+ ***************************************************************************/
+void print_help(void)
+{
+	static char* help_page[]=
+	{
+		"mknspimg version 1.0, Texas Instruments, 2004",
+		"Syntax:",
+		"        mknspimg -o outfile -i image1 image2 -a align1 align2 [-v] [-b] [-p prod_id] [-r rel_id] [-s rel_name] [-f flags]",
+		"Example:",
+		"        mknspimg -o nsp_image.bin -i kernel.bin files.img -a 0 4096",
+		"This generates 'nsp_image.bin' from two input files aligning first to 0 and second to 4096 bytes."
+	};
+
+	int num_lines = sizeof(help_page)/sizeof(char*);
+	int i;
+	for(i=0; i < num_lines; i++) {
+		printf("%s\n", help_page[i]);
+	}
+}
+
+/***************************************************************************
+ * void mknspimg_print_hdr(NSP_IMG_HDR* p_img_hdr)
+ ***************************************************************************/
+void mknspimg_print_hdr(struct nsp_img_hdr *hdr)
+{
+	struct nsp_img_hdr_chksum	*chksum;
+	struct nsp_img_hdr_section_info	*sect_info;
+	struct nsp_img_hdr_sections	*section;
+	int i;
+
+	printf("****************** NSP Image Summary ******************\n");
+	printf("Magic:             0x%x\n",		hdr->head.magic);
+	printf("Image Header Size: 0x%x bytes\n",	hdr->head.hdr_size);
+	printf("Total Image Size:  %d bytes\n",		hdr->head.image_size);
+	printf("Product ID:        0x%x\n",		hdr->head.prod_id);
+	printf("Release ID:        0x%x\n",		hdr->head.rel_id);
+	printf("Version ID:        0x%x\n",		hdr->head.version);
+
+	printf("Offset Info:       0x%x\n",		hdr->head.info_offset);
+	printf("Offset Sect info:  0x%x\n",		hdr->head.sect_info_offset);
+	printf("Offset Sections:   0x%x\n",		hdr->sect_info.sections_offset);
+
+	chksum=(struct nsp_img_hdr_chksum *)(hdr+hdr->head.chksum_offset);
+	printf("Header Checksum:   0x%x\n",		chksum->hdr_chksum);
+
+	printf("+++ Section Information +++\n");
+	printf("# of sections:     %u\n", hdr->sect_info.num_sects);
+	section=&(hdr->sections);
+	for(i = 0; i < hdr->sect_info.num_sects; i++, section++) {
+		printf("+++++ Section %d +++++\n", i);
+		printf("Total size:  %u bytes\n",	section->total_size);
+		printf("Raw Size:    %u bytes\n",	section->raw_size);
+		printf("Offset:      0x%x\n",		section->offset);
+		printf("Type:        0x%x\n",		section->type);
+		printf("Name:        %s\n",		section->name);
+	}
+	printf("*******************************************************\n");
+}
+
+CMDLINE_CFG	cmd_line_cfg =
+{
+	{
+		/*	MIN	MAX	FLAGS					OPTION	*/
+		{	2,	2,	(CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },	/* '-a' align1 align2 */
+		{	0,	0,	CMDLINE_OPTFLAG_ALLOW },		/* '-b' bootstrap */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-c' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-d' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-e' */
+		{	1,	1,	CMDLINE_OPTFLAG_ALLOW },		/* '-f' flags */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-g' */
+		{	1,	1,	CMDLINE_OPTFLAG_ALLOW },		/* '-h' */
+		{	2,	2,	(CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },	/* '-i arg1 arg2 ' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-j' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-k' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-l' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-m' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-n' */
+		{	1,	1,	(CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },	/* '-o arg' */
+		{	1,	1,	CMDLINE_OPTFLAG_ALLOW },		/* '-p' PROD_ID */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-q' */
+		{	1,	1,	CMDLINE_OPTFLAG_ALLOW },		/* '-r' REL_ID */
+		{	1,	1,	CMDLINE_OPTFLAG_ALLOW },		/* '-s' "Release XXX.XXX" */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-t' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-u' */
+		{	0,	0,	CMDLINE_OPTFLAG_ALLOW },		/* '-v' control VERBOSE/NON-VERBOSE mode */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-w' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-x' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW },		/* '-y' */
+		{	0,	0,	!CMDLINE_OPTFLAG_ALLOW }		/* '-z' */
+	},
+	{	0,		0,	!CMDLINE_OPTFLAG_ALLOW },		/* global arguments */
+};
+
+/***************************************************************************
+ * int nsp_img_write(void* image, char* file, int padding)
+ * Write out the image.
+ ***************************************************************************/
+int main(int argc, char* argv[], char* env[])
+{
+	FILE*	nsp_image	= NULL;
+	int header_version=1;
+	int	cmdline_err;
+	char*	cmdline_error_msg;
+
+	char*	filen_kernel;
+	char*	filen_files;
+	char*	filen_out;
+
+	int	i,count;			/* loop variables */
+	int	num_sects = 2;			/* We require exactly two image with -i option
+							   (see CMDLINE_CFG structure above) */
+	int	desc_count=0;
+	int	total = 0;
+
+	int	header_size=0;
+	struct nsp_img_hdr_head		*img_hdr_head;	/* Start of image header */
+	struct nsp_img_hdr_info *img_hdr_info;
+	struct nsp_img_hdr_section_info *img_hdr_section_info ;
+	struct nsp_img_hdr_sections	*img_hdr_sections, *section;	/* Section pointers */
+	
+
+	/* Configure the command line. */
+	cmdline_configure(&cmd_line_cfg);
+
+	/* Read and parse the command line. */
+	cmdline_err = cmdline_read(argc, argv);
+
+	/* Check for parsing errors. */
+	if(cmdline_err != 0) {
+		/* Get the parse error message */
+		cmdline_error_msg = cmdline_error(cmdline_err);
+
+		/* Print it out */
+		printf("%s\n", cmdline_error_msg);
+
+		/* Print our help too */
+		print_help();
+		return -1;
+	}
+	if(cmdline_getopt_count('h') > 0)
+	{
+		header_version=atoi(argv[cmdline_getarg(cmdline_getarg_list('h'),0)]);
+	}
+	/* Set up arguments */
+	filen_kernel	= argv[cmdline_getarg(cmdline_getarg_list('i'),0)];
+	filen_files	= argv[cmdline_getarg(cmdline_getarg_list('i'),1)];
+	filen_out	= argv[cmdline_getarg(cmdline_getarg_list('o'),0)];
+	/* Command line arguments have been parsed. Start doing our work. */
+
+	/* Caculate the header size, and allocate the memory, and assign the sub pointers */
+	header_size =	sizeof(struct nsp_img_hdr_head) +		/* This has a single section
+								   desc block already */
+				(header_version==1?0:4) + 
+				sizeof(struct nsp_img_hdr_info) + 
+				sizeof(struct nsp_img_hdr_section_info) + 
+			sizeof(struct nsp_img_hdr_sections) * num_sects ;
+
+	img_hdr_head = (struct nsp_img_hdr_head *)malloc(header_size);
+	memset(img_hdr_head, 0x0, header_size);
+	img_hdr_info = (struct nsp_img_hdr_info*)((char *)img_hdr_head + sizeof(struct nsp_img_hdr_head) + (header_version==1?0:4));
+	img_hdr_section_info = (struct nsp_img_hdr_section_info*)((char *)img_hdr_info + sizeof(struct nsp_img_hdr_info));
+	img_hdr_sections = (struct nsp_img_hdr_sections*)((char *)img_hdr_section_info + sizeof(struct nsp_img_hdr_section_info));
+	section = img_hdr_sections;
+	memset(img_hdr_head, 0xff, (void*)img_hdr_info - (void*)img_hdr_head);
+	
+	img_hdr_head->hdr_version = header_version;
+	img_hdr_head->hdr_size = header_size;
+	img_hdr_head->info_offset = (void*)img_hdr_info - (void*)img_hdr_head;
+	img_hdr_head->sect_info_offset = (void*)img_hdr_section_info - (void*)img_hdr_head;
+	
+	img_hdr_section_info->num_sects = num_sects;
+	img_hdr_section_info->sect_size = sizeof(struct nsp_img_hdr_sections);
+	img_hdr_section_info->sections_offset = (void*)img_hdr_sections - (void*)img_hdr_head;
+	
+/*	chksum = (struct nsp_img_hdr_chksum *)
+			((unsigned int)image_hdr + header_size - sizeof(struct nsp_img_hdr_chksum));*/
+
+	/* Open the out file */
+	nsp_image = fopen(filen_out,"wb+");
+	if(nsp_image==NULL) {
+		printf("ERROR: can't open %s for writing.\n", filen_out);
+		return -1;
+	}
+
+	/* Skip image header. We'll come back to it after we've written out the images. */	
+	fseek(nsp_image,header_size,SEEK_SET);
+	total = ftell(nsp_image);
+	total = header_size;
+	printf("total=%x\n",total);
+	{
+		int align;
+		int	padding;
+		char * buf;
+		align = (header_version==1?0x10000:0x4000);
+		if(align==0) {
+			/* The user indicated no padding */
+			padding = 0;
+		} else {
+			/* Calculate number padding bytes */
+			if((total %align) ==0)
+				padding=0;
+			else
+				padding = align - (total % align);
+		}
+		if(padding>0)
+		{
+			buf=malloc(padding);
+			memset(buf, 0xff, padding);
+			if(fwrite((void*)buf,1,padding,nsp_image)!=padding) {
+				printf("ERROR: can't write to %s.\n", filen_out);
+				free(buf);
+				return -1;
+			}
+			free(buf);
+			
+		}
+		total+=padding;
+		
+
+	}
+	/* Write out all specified images (with -i option) */
+	for(i=0; i < num_sects; i++) {
+		char*	file_name;		/* input file name */
+		FILE*	filep;			/* input file pointer */
+		int	padding;		/* number of padding bytes to prepend */
+		int	align;			/* align factor from command line */
+		int	result;			/* intermediate result */
+		char * buf;
+
+		/* Open the specified image for reading */
+		file_name	= argv[cmdline_getarg(cmdline_getarg_list('i'),i)];
+		filep		= fopen(file_name, "rb");
+		if(filep==NULL) {
+			printf("ERROR: can't open file %s for reading.\n", file_name);
+			return -1;
+		}
+		section->flags = ~0x00;
+		/* Determine file size */
+		fseek(filep,0,SEEK_END);
+		section->raw_size=ftell(filep);
+		fseek(filep,0,SEEK_SET);
+		cs_calc_sum(filep,(unsigned long *)&section->chksum,0);
+		fseek(filep,0,SEEK_SET);
+
+		/* Retrieve the alignment constant */
+		/* Set image offset from the beginning of the out file */
+		section->offset=total;// + padding;
+
+		//total += padding;
+
+		/* Copy the image file into nsp_image */
+		count = section->raw_size;
+		buf=malloc(count);
+		result=fread(buf, 1, count, filep);
+		fwrite(buf, 1, result, nsp_image);
+		free(buf);
+		
+		/* HACK: This is a hack to get the names and types to the files.
+			TODO: Fix this to be a real method */
+		if(i==0){
+			section->type=NSP_IMG_SECTION_TYPE_KERNEL;
+			strncpy(section->name, "kernel", 16);
+		} else if(i==1){
+			section->type=NSP_IMG_SECTION_TYPE_FILESYSTEM_ROOT;
+			strncpy(section->name, "root", 16);
+		}
+
+		/* Account for the total */
+		align	=  strtoul(argv[cmdline_getarg(cmdline_getarg_list('a'),i)],NULL,0);
+		if(i==0){
+			if(align==0 || (((section->raw_size+ section->offset)%align)==0))
+				padding=0;
+			else
+				padding = align - ((section->raw_size+ section->offset) % align);
+
+				section->total_size=section->raw_size + padding;
+		}
+		else{
+			#define EXTRA_BLOCK 0x10000
+			unsigned int squash_padding;
+			squash_padding = EXTRA_BLOCK - section->raw_size % EXTRA_BLOCK;
+			buf=malloc(EXTRA_BLOCK + 4);
+			memset(buf, 0, squash_padding);
+			fwrite(buf, 1, squash_padding, nsp_image);
+			memset(buf, 0, EXTRA_BLOCK + 4);
+			*((unsigned int *)buf)=0xdec0adde;
+			*((unsigned int *)(buf+EXTRA_BLOCK))=0xdec0adde;
+			fwrite(buf, 1, EXTRA_BLOCK+4, nsp_image);
+			free(buf);
+			
+			if(align==0 || (((section->raw_size + (EXTRA_BLOCK + 4 + squash_padding)) %align)==0))
+				padding=0;
+			else
+				padding = align - ((section->raw_size + (EXTRA_BLOCK + 4 + squash_padding)) % align);
+			section->total_size=section->raw_size + (EXTRA_BLOCK + 4 + squash_padding) + padding;
+		}
+		if(padding>0){
+			buf=malloc(padding);
+			memset(buf, 0xff, padding);
+			fwrite(buf, 1, padding, nsp_image);
+			free(buf);
+		}
+		printf("*****padding is %d\ttotal_size=%d\traw_size=%d\n",padding, section->total_size, section->raw_size);
+
+		//total += section->raw_size;
+		total = section->total_size + section->offset;
+		printf("total=0x%x\n",total);
+		/* Close the input file */
+		fclose(filep);
+
+		/* Move the section pointer to the next slot */
+		section++;
+	}
+
+	/* Take care of the NSP image header fields */
+
+	/* head fields */
+	img_hdr_head->magic		= NSP_IMG_MAGIC_NUMBER;
+	img_hdr_head->boot_offset	= img_hdr_sections->offset;
+	img_hdr_head->flags		= ~0x00;			/* Set to all 1's */
+
+	if(cmdline_getopt_count('b'))
+		img_hdr_head->flags	&= ~(NSP_IMG_FLAG_FAILBACK_5 | NSP_IMG_FLAG_FAILBACK_1);
+
+	if(cmdline_getopt_count('f'))
+		img_hdr_head->flags	= strtoul(argv[cmdline_getarg(cmdline_getarg_list('f'),0)], 0, 16);
+
+#if 0
+	img_hdr_head->hdr_version	= 2;
+	img_hdr_head->hdr_size	= header_size;
+#endif
+
+	if(cmdline_getopt_count('p'))
+		img_hdr_head->prod_id		= strtoul(argv[cmdline_getarg(cmdline_getarg_list('p'),0)], 0, 16);
+	else
+		img_hdr_head->prod_id		= 0x4C575943;
+
+	if(cmdline_getopt_count('r'))
+		img_hdr_head->rel_id		= strtoul(argv[cmdline_getarg(cmdline_getarg_list('r'),0)], 0, 0);
+	else
+		img_hdr_head->rel_id		= 0x10203040;
+
+	if(cmdline_getopt_count('s'))
+		img_hdr_head->version		= strtoul(argv[cmdline_getarg(cmdline_getarg_list('s'),0)], 0, 0);
+	else
+		img_hdr_head->version		= 0x0b040000;
+	img_hdr_head->image_size	= total;
+#if 0
+	img_hdr_head->info_offset	= (unsigned int)(&(image_hdr->info)) -
+						(unsigned int)image_hdr;
+	img_hdr_head->sect_info_offset= (unsigned int)(&(image_hdr->sect_info)) -
+						(unsigned int)image_hdr;
+#endif
+//	image_hdr->head.chksum_offset	= (unsigned int)chksum - (unsigned int)image_hdr;
+	img_hdr_head->chksum_offset = 0xffffffff;
+//	image_hdr->head.pad1 = 0xffffffff;
+	/* info fields */
+	/* TODO: Fix. Do nothing yet */
+//	strncpy(nsp_img_hdr.id.prod_info,NSP_PRODINFO_STRING,sizeof(NSP_PRODINFO_STRING));
+	strcpy(img_hdr_info->image_filename, (const char *)basename(filen_out));
+	/* section fields */
+#if 0
+	img_hdr_section_info->num_sects=		num_sects;
+	img_hdr_section_info->sect_size=		sizeof(struct nsp_img_hdr_sections);
+	img_hdr_section_info->sections_offset=	(unsigned int)(&(image_hdr->sections)) -
+						(unsigned int)image_hdr;
+#endif
+
+	/* Calculate checksum(s) */
+#if 0
+	chksum->hdr_chksum = cs_calc_buf_sum((char*)image_hdr,
+			header_size - sizeof(struct nsp_img_hdr_chksum));
+#endif
+	/* Write out the NSP header. */
+	fseek(nsp_image,0,SEEK_SET);
+	count = fwrite((void*)img_hdr_head, header_size, 1, nsp_image);
+	if(count!=1) {
+		printf("ERROR: can't write to %s.\n", filen_out);
+		return -1;
+	}
+
+	/* Check if -v option was specified (no arg needed) */
+	if(cmdline_getopt_count('v') > 0)
+	{
+		struct nsp_img_hdr_head	head;
+		struct nsp_img_hdr	*hdr;
+
+		/* Rewind the file back to the beginning */
+		fseek(nsp_image,0,SEEK_SET);
+
+		/* Read header from the file */
+		fread((void*)&head, sizeof(struct nsp_img_hdr_head),
+				1, nsp_image);
+
+		/* Get memory to store the complete header */
+		hdr = (struct nsp_img_hdr *)malloc(head.hdr_size);
+
+		/* Read header from the file */
+		fseek(nsp_image,0,SEEK_SET);
+		fread((void*)hdr, head.hdr_size, 1, nsp_image);
+
+		/* Print it out */
+		mknspimg_print_hdr(hdr);
+		printf("Generated total %d bytes\n",total);
+		free(hdr);
+	}
+
+	free(img_hdr_head);
+
+      {
+	  struct checksumrecord cr;
+      cr.magic=CKSUM_MAGIC_NUMBER;
+      cs_calc_sum(nsp_image, (unsigned long *)&cr.chksum, 0);
+      fseek(nsp_image,0, SEEK_END);
+      fwrite(&cr, 1, sizeof(cr), nsp_image);
+	  }
+	  {
+		FILE * non_web;
+		char fname[256];
+		char * img_buf;
+		unsigned int len;
+		strcpy(fname, filen_out);
+		strcat(fname, ".non_web");
+		non_web = fopen(fname,"wb+");
+		fseek(nsp_image, 0, SEEK_END);
+		len = ftell(nsp_image);
+		img_buf=malloc(len);
+		fseek(nsp_image, 0, SEEK_SET);
+		fread(img_buf, 1, len, nsp_image);
+		img_buf[0xb] = 0x17;
+		fwrite(img_buf, 1, len-sizeof(struct checksumrecord), non_web);
+		fclose(non_web);
+		free(img_buf);
+	  }
+	  /* Close NSP image file */
+	fclose(nsp_image);
+
+	/* return result */
+	return(0);
+}
+
+#ifdef DMALLOC
+#include <dmalloc.h>
+#endif /* DMALLOC */
+
+#define BUFLEN (1 << 16)
+
+static unsigned long crctab[256] =
+{
+	0x0,
+	0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
+	0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
+	0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
+	0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
+	0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
+	0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
+	0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
+	0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
+	0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
+	0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
+	0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
+	0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
+	0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
+	0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
+	0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
+	0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
+	0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
+	0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
+	0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
+	0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
+	0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
+	0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
+	0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
+	0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
+	0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
+	0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
+	0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
+	0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
+	0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
+	0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
+	0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
+	0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
+	0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
+	0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
+	0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
+	0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
+	0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
+	0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
+	0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
+	0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
+	0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
+	0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
+	0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
+	0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
+	0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
+	0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
+	0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
+	0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
+	0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
+	0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
+	0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
+};
+
+int cs_is_tagged(FILE *fp)
+{
+	char buf[8];
+
+	fseek(fp, -8, SEEK_END);
+	fread(buf, 8, 1, fp);
+	if(*(unsigned long*)buf == CKSUM_MAGIC_NUMBER)
+		return 1;
+	return 0;
+}
+
+unsigned long cs_read_sum(FILE *fp)
+{
+	char buf[8];
+
+	fseek(fp, -8, SEEK_END);
+	fread(buf, 8, 1, fp);
+	return *((unsigned long*)&buf[4]);
+}
+
+int cs_calc_sum(FILE *fp, unsigned long *res, int tagged)
+{
+	unsigned char buf[BUFLEN];
+	unsigned long crc = 0;
+	uintmax_t length = 0;
+	size_t bytes_read;
+
+	fseek(fp, 0, SEEK_SET);
+
+	while((bytes_read = fread(buf, 1, BUFLEN, fp)) > 0)
+	{
+		unsigned char *cp = buf;
+
+		if(length + bytes_read < length)
+			return 0;
+
+		if(bytes_read != BUFLEN && tagged)
+			bytes_read -= 8;
+
+		length += bytes_read;
+		while(bytes_read--)
+			crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+	}
+
+	if(ferror(fp))
+		return 0;
+
+	for(; length; length >>= 8)
+		crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
+
+	crc = ~crc & 0xFFFFFFFF;
+
+	*res = crc;
+
+	return 1;
+}
+
+unsigned long cs_calc_buf_sum(char *buf, int size)
+{
+	unsigned long crc = 0;
+	char *cp = buf;
+	unsigned long length = size;
+
+	while(size--)
+		crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+
+	for(; length; length >>= 8)
+		crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
+
+	crc = ~crc & 0xFFFFFFFF;
+
+	return crc;
+}
+
+unsigned long cs_calc_buf_sum_ds(char *buf, int buf_size, char *sign, int sign_len)
+{
+	unsigned long crc = 0;
+	char *cp = buf;
+	unsigned long length = buf_size+sign_len;
+
+	while(buf_size--)
+		crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+
+	cp = sign;
+	while(sign_len--)
+		crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
+
+
+	for(; length; length >>= 8)
+		crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
+
+	crc = ~crc & 0xFFFFFFFF;
+
+	return crc;
+}
+
+int cs_set_sum(FILE *fp, unsigned long sum, int tagged)
+{
+	unsigned long magic = CKSUM_MAGIC_NUMBER;
+
+	if(tagged)
+		fseek(fp, -8, SEEK_END);
+	else
+		fseek(fp, 0, SEEK_END);
+
+	if(fwrite(&magic, 1, 4, fp) < 4)
+		return 0;
+	if(fwrite(&sum, 1, 4, fp) < 4)
+		return 0;
+
+	return 1;
+}
+
+void cs_get_sum(FILE *fp, unsigned long *sum)
+{
+	unsigned long magic = 0;
+
+	fseek(fp, -8, SEEK_END);
+
+	fread(&magic, 4, 1, fp);
+	fread(sum, 4, 1, fp);
+}
+
+int cs_validate_file(char *filename)
+{
+	FILE *pFile = NULL;
+	unsigned long sum = 0, res = 0;
+
+	if((pFile = fopen(filename, "r")) == NULL)
+		return 0;
+
+	if(!cs_is_tagged(pFile))
+	{
+		fclose(pFile);
+		return 0;
+	}
+	if(!cs_calc_sum(pFile, &sum, 1))
+	{
+		fclose(pFile);
+		return 0;
+	}
+	cs_get_sum(pFile, &res);
+	fclose(pFile);
+
+	if(sum != res)
+		return 0;
+	return 1;
+}
+
+/* ********* Library internal data ********* */
+#define	CMDLINE_TRUE			1
+#define	CMDLINE_FALSE			0
+
+typedef	enum CMDLINE_ERR
+{
+	CMDLINE_ERR_OK		= 0,	/* No Error (OK) */
+	CMDLINE_ERR_ERROR	= -1,	/* Unspecified error */
+	CMDLINE_ERR_INVKEY	= -3,	/* Invalid option key */
+	CMDLINE_ERR_MANYARG	= -4,	/* Too many arguments */
+	CMDLINE_ERR_FEWARG	= -5,	/* Too few arguments */
+	CMDLINE_ERR_ILLOPT	= -6,	/* Option not allowed (illegal option) */
+	CMDLINE_ERR_NOMEM	= -7,	/* No memory */
+	CMDLINE_ERR_OPTMIS	= -8	/* A mandatory option is missing */
+} CMDLINE_ERR;
+
+/* Argument list */
+typedef	struct CMDLINE_ARG
+{
+	int				index;		/* Index of the argument in the command line */
+	struct CMDLINE_ARG*	p_next;	/* Next node in the linked list */
+} CMDLINE_ARG;
+
+/* Master control block for an option */
+typedef struct CMDLINE_ARGS
+{
+	int				argc;		/* Total count of arguments found */
+	int				optc;		/* Total count of options found */
+	CMDLINE_ARG*	list;		/* Argument list */
+} CMDLINE_ARGS;
+
+/* Master control block for all found arguments */
+typedef	struct CMDLINE_DATA
+{
+	CMDLINE_ARGS	opt_args[26];	/* Array of MCBs for each option ('a' through 'z') */
+	CMDLINE_ARGS	glb_args;		/* Global arguments */
+	int				parsed;			/* Internal flag to prevent client calls if library is not initialized */
+} CMDLINE_DATA;
+
+/* ********* Local Data ********* */
+static CMDLINE_CFG cmdline_cfg;
+static CMDLINE_DATA cmdline_data;
+
+char*	cmdline_errmsg = "CMDLINE ERROR";
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+void* cmdline_getarg_list(char opt)
+{
+	int index = (opt - 'a');
+
+	/* Check the validity of the index */
+	if((index < 0) || (index > 25))
+	{
+		/* ERROR: Wrong option */
+		return NULL;
+	}
+
+	/* Return a pointer to the ARGS control structure */
+	return((void*)(&cmdline_data.opt_args[index]));
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_getarg_count(void* list)
+{
+	CMDLINE_ARGS*	p_args = (CMDLINE_ARGS*)list;
+
+	/* Return number of arguments for this option */
+	return(p_args->argc);
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_getopt_count(char opt)
+{
+	int				index;
+
+	/* Calculate index value */
+	index = opt - 'a';
+	if(index < 0 || index > 25) return -1;
+
+	/* Return number of arguments for this option */
+	return(cmdline_data.opt_args[index].optc);
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_getarg(void* list, int num)
+{
+	int i;
+	CMDLINE_ARGS*	p_args = (CMDLINE_ARGS*)list;
+	CMDLINE_ARG*	p_arg;
+
+	/* Search the 'num' argument in the list for this option */
+	for(i=0,p_arg=p_args->list; (p_arg!=NULL) && (i<p_args->argc); i++, p_arg=p_arg->p_next)
+	{
+		/* if num matches i, we found it */
+		if(i==num) return(p_arg->index);
+	}
+	/* We did not find the specified argument or the list was empty */
+	return -1;
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+int cmdline_configure(CMDLINE_CFG* p_cfg)
+{
+	/* reset global data */
+	memset(&cmdline_cfg,0,sizeof(cmdline_cfg));
+	memset(&cmdline_data,0,sizeof(cmdline_data));
+
+	/* Copy the user's config structure */
+	cmdline_cfg = *p_cfg;
+	return 0;
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+char* cmdline_error(int err)
+{
+	/* TODO: implement a table of error messages */
+	return(cmdline_errmsg);
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+static void cmdline_print_args(CMDLINE_ARGS* p_arglist, char* argv[])
+{
+	CMDLINE_ARG*	p_arg;
+
+	printf("   Number of times option was specified: %d\n", p_arglist->optc);
+	printf("   Number of Arguments:                  %d\n", p_arglist->argc);
+
+	if(p_arglist->argc > 0)
+	{
+		printf("   Argument List: ");
+
+		for(p_arg=p_arglist->list; p_arg != NULL; p_arg=p_arg->p_next)
+			printf("%s ", argv[p_arg->index]);
+	}
+
+	printf("\n");
+}
+
+/* ***************************************************************
+* Print all found command line options and their arguments
+****************************************************************** */
+void cmdline_print(char* argv[])
+{
+	int i;
+
+	/* Check if the command line was parsed */
+	if(cmdline_data.parsed != CMDLINE_TRUE)
+	{
+		printf("The command line has not been parsed yet.\n");
+		return;
+	}
+
+	/* Print out option arguments */
+	for( i = 0; i < 26; i++ )
+	{
+		/* Check if the option was specified */
+		if(cmdline_data.opt_args[i].optc !=0 )
+		{
+			/* Print out option name and arguments */
+			printf("Option: -%c\n", (char)('a'+i));
+			cmdline_print_args(&(cmdline_data.opt_args[i]), argv);
+		}
+	}
+
+	/* Print out global arguments */
+	printf("Global arguments:\n");
+	cmdline_print_args(&(cmdline_data.glb_args), argv);
+}
+
+/* ***************************************************************
+* Print configuration
+****************************************************************** */
+void cmdline_print_cfg(void)
+{
+
+}
+
+static void cmdline_argadd(CMDLINE_ARGS* p_arglist, CMDLINE_ARG* p_arg)
+{
+	CMDLINE_ARG*	p_list;
+	CMDLINE_ARG*	p_prev=NULL;
+
+	/* See if we had anything in the list */
+	if(p_arglist->argc == 0)
+	{
+		/* Link the argument in */
+		p_arglist->list = p_arg;
+	}
+	else
+	{
+		/* Find the tail of the list */
+		for(p_list=p_arglist->list; p_list != NULL; p_list=p_list->p_next)
+			p_prev = p_list;
+
+		/* Link the argument in */
+		p_prev->p_next=p_arg;
+	}
+
+	/* Keep track of arg number */
+	p_arglist->argc++;
+}
+
+/* ***************************************************************
+* cmdline_read()
+* Read and parse command line arguments
+****************************************************************** */
+int cmdline_read(int argc, char* argv[])
+{
+	int i, option=0;
+
+	/* Process every command line argument in argv[] array */
+	for( i = 1; i < argc; i++ )
+	{
+		/* Does the argument start with a dash? */
+		if( *argv[i] == '-' )
+		{
+			/* The argument must be two characters: a dash, and a letter */
+			if( strlen(argv[i]) != 2 )
+			{
+				/* ERROR: option syntax (needs to be a dash and one letter) */
+				return(CMDLINE_ERR_ERROR);
+			}
+
+			/* Check validity of the option key ('a' through 'z') */
+			if( ((*(argv[i] + 1)) < 'a') || ((*(argv[i] + 1)) > 'z') )
+			{
+				/* ERROR: option sysntax (invalid option key) */
+				return(CMDLINE_ERR_INVKEY);
+			}
+
+			/* Calculate the option index */
+			option = (*(argv[i] + 1)) - 'a';
+			if((option < 0) || (option > 25)) return(CMDLINE_ERR_INVKEY);
+
+			/* Check to see if the option is allowed */
+			if( cmdline_cfg.opts[option].flags & CMDLINE_OPTFLAG_ALLOW )
+			{
+				/* Option allowed. */
+				cmdline_data.opt_args[option].optc++;
+				continue;
+			}
+			else
+			{
+				/* ERROR: Option is not allowed */
+				return(CMDLINE_ERR_ILLOPT);
+			}
+		}
+		else
+		{
+			/* Read the arguments for the option */
+			CMDLINE_ARG*	p_arg;
+
+			/* Allocate space for the argument node */
+			p_arg = (CMDLINE_ARG*)calloc(1,sizeof(CMDLINE_ARG));
+			if( p_arg== NULL )
+			{
+				/* ERROR: Can't allocate memory for the argument index */
+				return(CMDLINE_ERR_NOMEM);
+			}
+
+			/* Initialize the argument */
+			p_arg->index	= i;
+			p_arg->p_next	= NULL;
+
+			/* Check if we can add to the list of arguments for this option */
+			if( (option < 0)																/* Do we have to add to the global list? */
+				|| (cmdline_data.opt_args[option].argc == cmdline_cfg.opts[option].max)		/* Did we reach MAX arguments? */
+				)
+			{
+				/* This option does not require arguments. Keep the argument in the global list. */
+				cmdline_argadd(&(cmdline_data.glb_args), p_arg);
+				continue;
+			}
+			else
+			{
+				/* See if the current count has reached max for this option */
+				if( cmdline_data.opt_args[option].argc == cmdline_cfg.opts[option].max )
+				{
+					/* ERROR: too many arguments for an option */
+					return(CMDLINE_ERR_MANYARG);
+				}
+				else
+				{
+					/* Link the argument to the arg list of the option */
+					cmdline_argadd(&(cmdline_data.opt_args[option]), p_arg);
+					continue;
+				}
+			}
+		}
+	}
+
+	/* ****** We read the complete command line. See if what we collected matches the configuration ******* */
+
+	/* Check every collected option against its configuration */
+	for( i=0; i < 26; i++ )
+	{
+		/* Check if this option was allowed */
+		if(cmdline_cfg.opts[i].flags & CMDLINE_OPTFLAG_ALLOW)
+		{
+			/* See if it was mandatory */
+			if(cmdline_cfg.opts[i].flags & CMDLINE_OPTFLAG_MANDAT)
+			{
+				/* Check if we really collected this option on the command line. */
+				if(cmdline_data.opt_args[i].optc == 0)
+				{
+					/* ERROR: a missing mandatory option */
+					return(CMDLINE_ERR_OPTMIS);
+				}
+				else
+				{
+					/* Option was there. Check how many args we got for it. */
+					if(cmdline_data.opt_args[i].argc < cmdline_cfg.opts[i].min)
+					{
+						/* ERROR: too few arguments for an option */
+						return(CMDLINE_ERR_FEWARG);
+					}
+					else
+					{
+						/* This mandatory option was proper. */
+						continue;
+					}
+				}
+			}
+			else	/* This is non-mandatory option: */
+			{
+				/* Check if the option was specified on the command line */
+				if(cmdline_data.opt_args[i].optc == 0)
+				{
+					/* option wasn't specified, go to the next */
+					continue;
+				}
+				else
+				{
+					/* Option was there. Check how many args we collected for it. */
+					if(cmdline_data.opt_args[i].argc < cmdline_cfg.opts[i].min)
+					{
+						/* ERROR: too few arguments for a non-mandatory option */
+						return(CMDLINE_ERR_FEWARG);
+					}
+					else
+					{
+						/* This non-mandatory option was proper. */
+						continue;
+					}
+				}
+			}
+		}
+		else	/* Option was not allowed. */
+		{
+			/* We should not get here as the non-allowed options should have been
+			trapped eariler. */
+		}
+	}
+
+	/* Command line was proper as far as the number of options and their arguments */
+	cmdline_data.parsed = CMDLINE_TRUE;
+	return(CMDLINE_ERR_OK);
+}
diff --git a/tools/firmware-utils/src/mktitanimg.h b/tools/firmware-utils/src/mktitanimg.h
new file mode 100644
index 0000000000..9ff30f6088
--- /dev/null
+++ b/tools/firmware-utils/src/mktitanimg.h
@@ -0,0 +1,171 @@
+#ifndef __MKTITANIMG_H
+#define __MKTITANIMG_H
+
+#ifndef CFGMGR_CKSUM_H
+#define CFGMGR_CKSUM_H
+
+#define CKSUM_MAGIC_NUMBER 0xC453DE23
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <errno.h>
+
+int cs_is_tagged(FILE*);
+unsigned long cs_read_sum(FILE*);
+int cs_calc_sum(FILE*, unsigned long*, int);
+int cs_set_sum(FILE*, unsigned long, int);
+void cs_get_sum(FILE*, unsigned long*);
+unsigned long cs_calc_buf_sum(char*, int);
+int cs_validate_file(char*);
+
+#endif
+#ifndef ___CMDLINE_H___
+#define	___CMDLINE_H___
+
+/* ********* Library Configuration ********* */
+typedef	struct CMDLINE_OPT
+{
+	int	min;					/* Minimum number of arguments this option takes */
+	int	max;					/* Maximum number of arguments this option takes */
+	int	flags;					/* Controlling flags (whether to accept or not, etc) */
+} CMDLINE_OPT;
+
+typedef	struct CMDLINE_CFG
+{
+	CMDLINE_OPT	opts[26];		/* Options 'a' through 'z' */
+	CMDLINE_OPT	global;			/* Global option (outside 'a'..'z') */
+} CMDLINE_CFG;
+/* ******************************************** */
+
+#define	CMDLINE_OPTFLAG_ALLOW	0x1			/* The option is allowed */
+#define	CMDLINE_OPTFLAG_MANDAT	0x2			/* The option is mandatory */
+
+extern	void	cmdline_print(char* argv[]);
+
+extern	int		cmdline_configure(CMDLINE_CFG* p_cfg);
+extern	int		cmdline_read(int argc, char* argv[]);
+
+extern	void*	cmdline_getarg_list(char opt);
+extern	int		cmdline_getarg_count(void* list);
+extern	int		cmdline_getopt_count(char opt);
+extern	int		cmdline_getarg(void* list, int num);
+
+extern	char*	cmdline_error(int err);
+#endif
+
+
+#ifndef _NSPIMGHDR_H_
+#define _NSPIMGHDR_H_
+
+/* This file describes the header format for the single image. The image is broken
+   up into several pieces. The image contains this header plus 1 or more sections.
+   Each section contains a binary block that could be a kernel, filesystem, etc. The
+   only garentee for this is that the very first section MUST be executable. Meaning
+   that the bootloader will be able to take the address of the header start, add the
+   header size, and execute that binary block. The header has its own checksum. It
+   starts hdr_size-4 bytes from the start of the header.
+ */
+
+struct nsp_img_hdr_head
+{
+	unsigned int	magic;		/* Magic number to identify this image header */
+	unsigned int	boot_offset;	/* Offset from start of header to kernel code. */
+	unsigned int	flags;		/* Image flags. */
+	unsigned int	hdr_version;	/* Version of this header. */
+	unsigned int	hdr_size;	/* The complete size of all portions of the header */
+	unsigned int	prod_id;	/* This product id */
+	unsigned int	rel_id;		/* Which release this is */
+	unsigned int	version;	/* name-MMM.nnn.ooo-rxx => 0xMMnnooxx. See comment
+					   below */
+	unsigned int	image_size;	/* Image size (including header) */
+	unsigned int	info_offset;	/* Offset from start of header to info block */
+	unsigned int	sect_info_offset;	/* Offset from start of header to section desc */
+	unsigned int	chksum_offset;	/* Offset from start of header to chksum block */
+//	unsigned int    pad1;
+};
+
+/* The patch id is a machine readable value that takes the normal patch level, and encodes
+   the correct numbers inside of it. The format of the patches are name-MM.NN.oo-rxx.bin.
+   Convert MM, NN, oo, and xx into hex, and encode them as 0xMMNNooxx. Thus:
+   att-1.2.18-r14.bin => 0x0102120e */
+
+/* The following are the flag bits for the above flags variable */
+/* List of NSP status flags: */
+#define NSP_IMG_FLAG_FAILBACK_MASK	0xF8000000
+
+/* NSP Image status flag: Flag indicates individual sections image */
+#define NSP_IMG_FLAG_INDIVIDUAL		0x00000001
+
+/* NSP Image status flag 1: Image contains a bootable image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_1		0x08000000
+
+/* NSP Image status flag 2: Image contains a non-bootable image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_2		0x10000000
+
+/* NSP Image status flag 3: PSPBoot has tried the image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_3		0x20000000
+
+/* NSP Image status flag 4: Image is now secondary image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_4		0x40000000
+
+/* NSP Image status flag 5: Image contains a valid image when this bit is 0 */
+#define NSP_IMG_FLAG_FAILBACK_5		0x80000000
+
+/* NSP Single image magic number */
+#define NSP_IMG_MAGIC_NUMBER		0x4D544443
+
+
+struct nsp_img_hdr_info
+{
+	char	release_name[64];	/* Name of release */
+	char	image_filename[64];	/* name-mm.nn.oo-rxx.bin format */
+};
+
+struct nsp_img_hdr_section_info
+{
+	unsigned int	num_sects;	/* Number of section (and section desc blocks) in this
+					   image */
+	unsigned int	sect_size;	/* Size of a SINGLE section_desc block */
+	unsigned int	sections_offset;	/* Offset to from start of header to the start of
+						   the section blocks */
+};
+
+/* There will be one of more of the following stuctures in the image header. Each
+   section will have one of these blocks. */
+struct nsp_img_hdr_sections
+{
+	unsigned int	offset;		/* Offset of section from start of NSP_IMG_HDR_HEAD */
+	unsigned int	total_size;	/* Size of section (including pad size.) */
+	unsigned int	raw_size;	/* Size of section only */
+	unsigned int	flags;		/* Section flags */
+	unsigned int	chksum;		/* Section checksum */
+	unsigned int	type;		/* Section type. What kind of info does this section
+					   describe */
+	char		name[16];	/* Reference name for this section. */
+};
+#define NSP_IMG_SECTION_TYPE_KERNEL		(0x01)
+#define NSP_IMG_SECTION_TYPE_FILESYSTEM_ROOT	(0x02)
+#define NSP_IMG_SECTION_TYPE_FILESYSTEM		(0x03)
+
+struct nsp_img_hdr
+{
+	struct nsp_img_hdr_head		head;	/* Head portion */
+	struct nsp_img_hdr_info		info;	/* Info */
+	struct nsp_img_hdr_section_info	sect_info;	/* Section block */
+	struct nsp_img_hdr_sections	sections;	/* 1 or more section_description blocks. More
+						   section_desc blocks will be appended here
+						   for each additional section needed */
+};
+
+struct nsp_img_hdr_chksum
+{
+	unsigned int	hdr_chksum;	/* The checksum for the complete header. Excepting the
+					   checksum block */
+};
+
+struct nsp_img_hdr_sections *nsp_img_hdr_get_section_ptr_by_name(struct nsp_img_hdr *hdr, char *name);
+unsigned int nsp_img_hdr_get_section_offset_by_name(struct nsp_img_hdr *hdr, char *name);
+unsigned int nsp_img_hdr_get_section_size_by_name(struct nsp_img_hdr *hdr, char *name);
+
+#endif
+#endif /* __MKTITANIMG_H */
diff --git a/tools/firmware-utils/src/mktplinkfw.c b/tools/firmware-utils/src/mktplinkfw.c
new file mode 100644
index 0000000000..34e6546a2d
--- /dev/null
+++ b/tools/firmware-utils/src/mktplinkfw.c
@@ -0,0 +1,885 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ *   TP-Link WR941 V2 firmware checksum fixing tool.
+ *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "md5.h"
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
+
+#define HEADER_VERSION_V1	0x01000000
+#define HEADER_VERSION_V2	0x02000000
+
+#define MD5SUM_LEN	16
+
+struct file_info {
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+};
+
+struct fw_header {
+	uint32_t	version;	/* header version */
+	char		vendor_name[24];
+	char		fw_version[36];
+	uint32_t	hw_id;		/* hardware id */
+	uint32_t	hw_rev;		/* hardware revision */
+	uint32_t	region_code;	/* region code */
+	uint8_t		md5sum1[MD5SUM_LEN];
+	uint32_t	unk2;
+	uint8_t		md5sum2[MD5SUM_LEN];
+	uint32_t	unk3;
+	uint32_t	kernel_la;	/* kernel load address */
+	uint32_t	kernel_ep;	/* kernel entry point */
+	uint32_t	fw_length;	/* total length of the firmware */
+	uint32_t	kernel_ofs;	/* kernel data offset */
+	uint32_t	kernel_len;	/* kernel data length */
+	uint32_t	rootfs_ofs;	/* rootfs data offset */
+	uint32_t	rootfs_len;	/* rootfs data length */
+	uint32_t	boot_ofs;	/* bootloader data offset */
+	uint32_t	boot_len;	/* bootloader data length */
+	uint16_t	ver_hi;
+	uint16_t	ver_mid;
+	uint16_t	ver_lo;
+	uint8_t		pad[130];
+	char		region_str1[32];
+	char		region_str2[32];
+	uint8_t		pad2[160];
+} __attribute__ ((packed));
+
+struct flash_layout {
+	char		*id;
+	uint32_t	fw_max_len;
+	uint32_t	kernel_la;
+	uint32_t	kernel_ep;
+	uint32_t	rootfs_ofs;
+};
+
+struct fw_region {
+	char		name[4];
+	uint32_t	code;
+};
+
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+static char *vendor = "TP-LINK Technologies";
+static char *version = "ver. 1.0";
+static char *fw_ver = "0.0.0";
+static uint32_t hdr_ver = HEADER_VERSION_V1;
+
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static char *opt_hw_rev;
+static uint32_t hw_rev;
+static uint32_t opt_hdr_ver = 1;
+static char *country;
+static const struct fw_region *region;
+static int fw_ver_lo;
+static int fw_ver_mid;
+static int fw_ver_hi;
+static struct file_info kernel_info;
+static uint32_t kernel_la = 0;
+static uint32_t kernel_ep = 0;
+static uint32_t kernel_len = 0;
+static struct file_info rootfs_info;
+static uint32_t rootfs_ofs = 0;
+static uint32_t rootfs_align;
+static struct file_info boot_info;
+static int combined;
+static int strip_padding;
+static int ignore_size;
+static int add_jffs2_eof;
+static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+static uint32_t fw_max_len;
+static uint32_t reserved_space;
+
+static struct file_info inspect_info;
+static int extract = 0;
+
+static const char md5salt_normal[MD5SUM_LEN] = {
+	0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
+	0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
+};
+
+static const char md5salt_boot[MD5SUM_LEN] = {
+	0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
+	0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
+};
+
+static struct flash_layout layouts[] = {
+	{
+		.id		= "4M",
+		.fw_max_len	= 0x3c0000,
+		.kernel_la	= 0x80060000,
+		.kernel_ep	= 0x80060000,
+		.rootfs_ofs	= 0x140000,
+	}, {
+		.id		= "4Mlzma",
+		.fw_max_len	= 0x3c0000,
+		.kernel_la	= 0x80060000,
+		.kernel_ep	= 0x80060000,
+		.rootfs_ofs	= 0x100000,
+	}, {
+		.id		= "8M",
+		.fw_max_len	= 0x7c0000,
+		.kernel_la	= 0x80060000,
+		.kernel_ep	= 0x80060000,
+		.rootfs_ofs	= 0x140000,
+	}, {
+		.id		= "8Mlzma",
+		.fw_max_len	= 0x7c0000,
+		.kernel_la	= 0x80060000,
+		.kernel_ep	= 0x80060000,
+		.rootfs_ofs	= 0x100000,
+	}, {
+		.id		= "16M",
+		.fw_max_len	= 0xf80000,
+		.kernel_la	= 0x80060000,
+		.kernel_ep	= 0x80060000,
+		.rootfs_ofs	= 0x140000,
+	}, {
+		.id		= "16Mlzma",
+		.fw_max_len	= 0xf80000,
+		.kernel_la	= 0x80060000,
+		.kernel_ep	= 0x80060000,
+		.rootfs_ofs	= 0x100000,
+	}, {
+		.id		= "16Mppc",
+		.fw_max_len	= 0xf80000,
+		.kernel_la	= 0x00000000 ,
+		.kernel_ep	= 0xc0000000,
+		.rootfs_ofs	= 0x2a0000,
+	}, {
+		/* terminating entry */
+	}
+};
+
+static const struct fw_region regions[] = {
+	/* Default region (universal) uses code 0 as well */
+	{"US", 1},
+	{"EU", 0},
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static struct flash_layout *find_layout(const char *id)
+{
+	struct flash_layout *ret;
+	struct flash_layout *l;
+
+	ret = NULL;
+	for (l = layouts; l->id != NULL; l++){
+		if (strcasecmp(id, l->id) == 0) {
+			ret = l;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+static const struct fw_region * find_region(const char *country) {
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(regions); i++) {
+		if (strcasecmp(regions[i].name, country) == 0)
+			return &regions[i];
+	}
+
+	return NULL;
+}
+
+static void usage(int status)
+{
+	fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stderr,
+"\n"
+"Options:\n"
+"  -c              use combined kernel image\n"
+"  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
+"  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
+"  -H <hwid>       use hardware id specified with <hwid>\n"
+"  -W <hwrev>      use hardware revision specified with <hwrev>\n"
+"  -C <country>    set region code to <country>\n"
+"  -F <id>         use flash layout specified with <id>\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -a <align>      align the rootfs start on an <align> bytes boundary\n"
+"  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
+"  -o <file>       write output to the file <file>\n"
+"  -s              strip padding from the end of the image\n"
+"  -S              ignore firmware size limit (only for combined images)\n"
+"  -j              add jffs2 end-of-filesystem markers\n"
+"  -N <vendor>     set image vendor to <vendor>\n"
+"  -V <version>    set image version to <version>\n"
+"  -v <version>    set firmware version to <version>\n"
+"  -m <version>    set header version to <version>\n"
+"  -i <file>       inspect given firmware file <file>\n"
+"  -x              extract kernel and rootfs while inspecting (requires -i)\n"
+"  -X <size>       reserve <size> bytes in the firmware image (hexval prefixed with 0x)\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static void get_md5(const char *data, int size, uint8_t *md5)
+{
+	MD5_CTX ctx;
+
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, data, size);
+	MD5_Final(md5, &ctx);
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL)
+		return 0;
+
+	res = stat(fdata->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	return 0;
+}
+
+static int read_to_buf(const struct file_info *fdata, char *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+ out_close:
+	fclose(f);
+ out:
+	return ret;
+}
+
+static int check_options(void)
+{
+	int ret;
+	int exceed_bytes;
+
+	if (inspect_info.file_name) {
+		ret = get_file_stat(&inspect_info);
+		if (ret)
+			return ret;
+
+		return 0;
+	} else if (extract) {
+		ERR("no firmware for inspection specified");
+		return -1;
+	}
+
+	if (opt_hw_id == NULL) {
+		ERR("hardware id not specified");
+		return -1;
+	}
+	hw_id = strtoul(opt_hw_id, NULL, 0);
+
+	if (layout_id == NULL) {
+		ERR("flash layout is not specified");
+		return -1;
+	}
+
+	if (opt_hw_rev)
+		hw_rev = strtoul(opt_hw_rev, NULL, 0);
+	else
+		hw_rev = 1;
+
+	if (country) {
+		region = find_region(country);
+		if (!region) {
+			ERR("unknown region code \"%s\"", country);
+			return -1;
+		}
+	}
+
+	layout = find_layout(layout_id);
+	if (layout == NULL) {
+		ERR("unknown flash layout \"%s\"", layout_id);
+		return -1;
+	}
+
+	if (!kernel_la)
+		kernel_la = layout->kernel_la;
+	if (!kernel_ep)
+		kernel_ep = layout->kernel_ep;
+	if (!rootfs_ofs)
+		rootfs_ofs = layout->rootfs_ofs;
+
+	if (reserved_space > layout->fw_max_len) {
+		ERR("reserved space is not valid");
+		return -1;
+	}
+
+	fw_max_len = layout->fw_max_len - reserved_space;
+
+	if (kernel_info.file_name == NULL) {
+		ERR("no kernel image specified");
+		return -1;
+	}
+
+	ret = get_file_stat(&kernel_info);
+	if (ret)
+		return ret;
+
+	kernel_len = kernel_info.file_size;
+
+	if (combined) {
+		exceed_bytes = kernel_info.file_size - (fw_max_len - sizeof(struct fw_header));
+		if (exceed_bytes > 0) {
+			if (!ignore_size) {
+				ERR("kernel image is too big by %i bytes", exceed_bytes);
+				return -1;
+			}
+			layout->fw_max_len = sizeof(struct fw_header) +
+					     kernel_info.file_size +
+					     reserved_space;
+		}
+	} else {
+		if (rootfs_info.file_name == NULL) {
+			ERR("no rootfs image specified");
+			return -1;
+		}
+
+		ret = get_file_stat(&rootfs_info);
+		if (ret)
+			return ret;
+
+		if (rootfs_align) {
+			kernel_len += sizeof(struct fw_header);
+			kernel_len = ALIGN(kernel_len, rootfs_align);
+			kernel_len -= sizeof(struct fw_header);
+
+			DBG("kernel length aligned to %u", kernel_len);
+
+			exceed_bytes = kernel_len + rootfs_info.file_size - (fw_max_len - sizeof(struct fw_header));
+			if (exceed_bytes > 0) {
+				ERR("images are too big by %i bytes", exceed_bytes);
+				return -1;
+			}
+		} else {
+			exceed_bytes = kernel_info.file_size - (rootfs_ofs - sizeof(struct fw_header));
+			if (exceed_bytes > 0) {
+				ERR("kernel image is too big by %i bytes", exceed_bytes);
+				return -1;
+			}
+
+			exceed_bytes = rootfs_info.file_size - (fw_max_len - rootfs_ofs);
+			if (exceed_bytes > 0) {
+				ERR("rootfs image is too big by %i bytes", exceed_bytes);
+				return -1;
+			}
+		}
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		return -1;
+	}
+
+	ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
+	if (ret != 3) {
+		ERR("invalid firmware version '%s'", fw_ver);
+		return -1;
+	}
+
+	if (opt_hdr_ver == 1) {
+		hdr_ver = HEADER_VERSION_V1;
+	} else if (opt_hdr_ver == 2) {
+		hdr_ver = HEADER_VERSION_V2;
+	} else {
+		ERR("invalid header version '%u'", opt_hdr_ver);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void fill_header(char *buf, int len)
+{
+	struct fw_header *hdr = (struct fw_header *)buf;
+
+	memset(hdr, 0, sizeof(struct fw_header));
+
+	hdr->version = htonl(hdr_ver);
+	strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
+	strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
+	hdr->hw_id = htonl(hw_id);
+	hdr->hw_rev = htonl(hw_rev);
+
+	if (boot_info.file_size == 0)
+		memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
+	else
+		memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
+
+	hdr->kernel_la = htonl(kernel_la);
+	hdr->kernel_ep = htonl(kernel_ep);
+	hdr->fw_length = htonl(layout->fw_max_len);
+	hdr->kernel_ofs = htonl(sizeof(struct fw_header));
+	hdr->kernel_len = htonl(kernel_len);
+	if (!combined) {
+		hdr->rootfs_ofs = htonl(rootfs_ofs);
+		hdr->rootfs_len = htonl(rootfs_info.file_size);
+	}
+
+	hdr->ver_hi = htons(fw_ver_hi);
+	hdr->ver_mid = htons(fw_ver_mid);
+	hdr->ver_lo = htons(fw_ver_lo);
+
+	if (region) {
+		hdr->region_code = htonl(region->code);
+		snprintf(
+			hdr->region_str1, sizeof(hdr->region_str1), "00000000;%02X%02X%02X%02X;",
+			region->name[0], region->name[1], region->name[2], region->name[3]
+		);
+		snprintf(
+			hdr->region_str2, sizeof(hdr->region_str2), "%02X%02X%02X%02X",
+			region->name[0], region->name[1], region->name[2], region->name[3]
+		);
+	}
+
+	get_md5(buf, len, hdr->md5sum1);
+}
+
+static int pad_jffs2(char *buf, int currlen)
+{
+	int len;
+	uint32_t pad_mask;
+
+	len = currlen;
+	pad_mask = (64 * 1024);
+	while ((len < layout->fw_max_len) && (pad_mask != 0)) {
+		uint32_t mask;
+		int i;
+
+		for (i = 10; i < 32; i++) {
+			mask = 1 << i;
+			if (pad_mask & mask)
+				break;
+		}
+
+		len = ALIGN(len, mask);
+
+		for (i = 10; i < 32; i++) {
+			mask = 1 << i;
+			if ((len & (mask - 1)) == 0)
+				pad_mask &= ~mask;
+		}
+
+		for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+			buf[len + i] = jffs2_eof_mark[i];
+
+		len += sizeof(jffs2_eof_mark);
+	}
+
+	return len;
+}
+
+static int write_fw(const char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+ out:
+	return ret;
+}
+
+static int build_fw(void)
+{
+	int buflen;
+	char *buf;
+	char *p;
+	int ret = EXIT_FAILURE;
+	int writelen = 0;
+
+	buflen = layout->fw_max_len;
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	memset(buf, 0xff, buflen);
+	p = buf + sizeof(struct fw_header);
+	ret = read_to_buf(&kernel_info, p);
+	if (ret)
+		goto out_free_buf;
+
+	writelen = sizeof(struct fw_header) + kernel_len;
+
+	if (!combined) {
+		if (rootfs_align)
+			p = buf + writelen;
+		else
+			p = buf + rootfs_ofs;
+
+		ret = read_to_buf(&rootfs_info, p);
+		if (ret)
+			goto out_free_buf;
+
+		if (rootfs_align)
+			writelen += rootfs_info.file_size;
+		else
+			writelen = rootfs_ofs + rootfs_info.file_size;
+
+		if (add_jffs2_eof)
+			writelen = pad_jffs2(buf, writelen);
+	}
+
+	if (!strip_padding)
+		writelen = buflen;
+
+	fill_header(buf, writelen);
+	ret = write_fw(buf, writelen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(const char *label, const char *str)
+{
+	printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(const char *label, uint32_t val)
+{
+	printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexdec(const char *label, uint32_t val)
+{
+	printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text)
+{
+	int i;
+
+	printf("%-23s:", label);
+	for (i=0; i<MD5SUM_LEN; i++)
+		printf(" %02x", val[i]);
+	printf(" %s\n", text);
+}
+
+static int inspect_fw(void)
+{
+	char *buf;
+	struct fw_header *hdr;
+	uint8_t md5sum[MD5SUM_LEN];
+	int ret = EXIT_FAILURE;
+
+	buf = malloc(inspect_info.file_size);
+	if (!buf) {
+		ERR("no memory for buffer!\n");
+		goto out;
+	}
+
+	ret = read_to_buf(&inspect_info, buf);
+	if (ret)
+		goto out_free_buf;
+	hdr = (struct fw_header *)buf;
+
+	inspect_fw_pstr("File name", inspect_info.file_name);
+	inspect_fw_phexdec("File size", inspect_info.file_size);
+
+	if ((ntohl(hdr->version) != HEADER_VERSION_V1) &&
+	    (ntohl(hdr->version) != HEADER_VERSION_V2)) {
+		ERR("file does not seem to have V1/V2 header!\n");
+		goto out_free_buf;
+	}
+
+	inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
+
+	memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
+	if (ntohl(hdr->boot_len) == 0)
+		memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
+	else
+		memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
+	get_md5(buf, inspect_info.file_size, hdr->md5sum1);
+
+	if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
+		inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
+		inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
+	} else {
+		inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
+	}
+	if (ntohl(hdr->unk2) != 0)
+		inspect_fw_phexdec("Unknown value 2", hdr->unk2);
+	inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
+	                   "(purpose yet unknown, unchecked here)");
+	if (ntohl(hdr->unk3) != 0)
+		inspect_fw_phexdec("Unknown value 3", hdr->unk3);
+
+	printf("\n");
+
+	inspect_fw_pstr("Vendor name", hdr->vendor_name);
+	inspect_fw_pstr("Firmware version", hdr->fw_version);
+	inspect_fw_phex("Hardware ID", ntohl(hdr->hw_id));
+	inspect_fw_phex("Hardware Revision", ntohl(hdr->hw_rev));
+	inspect_fw_phex("Region code", ntohl(hdr->region_code));
+
+	printf("\n");
+
+	inspect_fw_phexdec("Kernel data offset",
+	                   ntohl(hdr->kernel_ofs));
+	inspect_fw_phexdec("Kernel data length",
+	                   ntohl(hdr->kernel_len));
+	inspect_fw_phex("Kernel load address",
+	                ntohl(hdr->kernel_la));
+	inspect_fw_phex("Kernel entry point",
+	                ntohl(hdr->kernel_ep));
+	inspect_fw_phexdec("Rootfs data offset",
+	                   ntohl(hdr->rootfs_ofs));
+	inspect_fw_phexdec("Rootfs data length",
+	                   ntohl(hdr->rootfs_len));
+	inspect_fw_phexdec("Boot loader data offset",
+	                   ntohl(hdr->boot_ofs));
+	inspect_fw_phexdec("Boot loader data length",
+	                   ntohl(hdr->boot_len));
+	inspect_fw_phexdec("Total firmware length",
+	                   ntohl(hdr->fw_length));
+
+	if (extract) {
+		FILE *fp;
+		char *filename;
+
+		printf("\n");
+
+		filename = malloc(strlen(inspect_info.file_name) + 8);
+		sprintf(filename, "%s-kernel", inspect_info.file_name);
+		printf("Extracting kernel to \"%s\"...\n", filename);
+		fp = fopen(filename, "w");
+		if (fp)	{
+			if (!fwrite(buf + ntohl(hdr->kernel_ofs),
+			            ntohl(hdr->kernel_len), 1, fp)) {
+				ERR("error in fwrite(): %s", strerror(errno));
+			}
+			fclose(fp);
+		} else {
+			ERR("error in fopen(): %s", strerror(errno));
+		}
+		free(filename);
+
+		filename = malloc(strlen(inspect_info.file_name) + 8);
+		sprintf(filename, "%s-rootfs", inspect_info.file_name);
+		printf("Extracting rootfs to \"%s\"...\n", filename);
+		fp = fopen(filename, "w");
+		if (fp)	{
+			if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
+			            ntohl(hdr->rootfs_len), 1, fp)) {
+				ERR("error in fwrite(): %s", strerror(errno));
+			}
+			fclose(fp);
+		} else {
+			ERR("error in fopen(): %s", strerror(errno));
+		}
+		free(filename);
+	}
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "a:H:E:F:L:m:V:N:W:C:ci:k:r:R:o:xX:hsSjv:");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'a':
+			sscanf(optarg, "0x%x", &rootfs_align);
+			break;
+		case 'H':
+			opt_hw_id = optarg;
+			break;
+		case 'E':
+			sscanf(optarg, "0x%x", &kernel_ep);
+			break;
+		case 'F':
+			layout_id = optarg;
+			break;
+		case 'W':
+			opt_hw_rev = optarg;
+			break;
+		case 'C':
+			country = optarg;
+			break;
+		case 'L':
+			sscanf(optarg, "0x%x", &kernel_la);
+			break;
+		case 'm':
+			sscanf(optarg, "%u", &opt_hdr_ver);
+			break;
+		case 'V':
+			version = optarg;
+			break;
+		case 'v':
+			fw_ver = optarg;
+			break;
+		case 'N':
+			vendor = optarg;
+			break;
+		case 'c':
+			combined++;
+			break;
+		case 'k':
+			kernel_info.file_name = optarg;
+			break;
+		case 'r':
+			rootfs_info.file_name = optarg;
+			break;
+		case 'R':
+			sscanf(optarg, "0x%x", &rootfs_ofs);
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			strip_padding = 1;
+			break;
+		case 'S':
+			ignore_size = 1;
+			break;
+		case 'i':
+			inspect_info.file_name = optarg;
+			break;
+		case 'j':
+			add_jffs2_eof = 1;
+			break;
+		case 'x':
+			extract = 1;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		case 'X':
+			sscanf(optarg, "0x%x", &reserved_space);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	if (!inspect_info.file_name)
+		ret = build_fw();
+	else
+		ret = inspect_fw();
+
+ out:
+	return ret;
+}
diff --git a/tools/firmware-utils/src/mktplinkfw2.c b/tools/firmware-utils/src/mktplinkfw2.c
new file mode 100644
index 0000000000..213e6729a4
--- /dev/null
+++ b/tools/firmware-utils/src/mktplinkfw2.c
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This tool was based on:
+ *   TP-Link WR941 V2 firmware checksum fixing tool.
+ *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <endian.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "md5.h"
+
+#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
+
+#define MD5SUM_LEN	16
+
+struct file_info {
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+};
+
+struct fw_header {
+	uint32_t	version;	/* 0x00: header version */
+	char		fw_version[48]; /* 0x04: fw version string */
+	uint32_t	hw_id;		/* 0x34: hardware id */
+	uint32_t	hw_rev;		/* 0x38: FIXME: hardware revision? */
+	uint32_t	unk1;	        /* 0x3c: 0x00000000 */
+	uint8_t		md5sum1[MD5SUM_LEN]; /* 0x40 */
+	uint32_t	unk2;		/* 0x50: 0x00000000 */
+	uint8_t		md5sum2[MD5SUM_LEN]; /* 0x54 */
+	uint32_t	unk3;		/* 0x64: 0xffffffff */
+
+	uint32_t	kernel_la;	/* 0x68: kernel load address */
+	uint32_t	kernel_ep;	/* 0x6c: kernel entry point */
+	uint32_t	fw_length;	/* 0x70: total length of the image */
+	uint32_t	kernel_ofs;	/* 0x74: kernel data offset */
+	uint32_t	kernel_len;	/* 0x78: kernel data length */
+	uint32_t	rootfs_ofs;	/* 0x7c: rootfs data offset */
+	uint32_t	rootfs_len;	/* 0x80: rootfs data length */
+	uint32_t	boot_ofs;	/* 0x84: FIXME: seems to be unused */
+	uint32_t	boot_len;	/* 0x88: FIXME: seems to be unused */
+	uint16_t	unk4;		/* 0x8c: 0x55aa */
+	uint8_t		sver_hi;	/* 0x8e */
+	uint8_t		sver_lo;	/* 0x8f */
+	uint8_t		unk5;		/* 0x90: magic: 0xa5 */
+	uint8_t		ver_hi;         /* 0x91 */
+	uint8_t		ver_mid;        /* 0x92 */
+	uint8_t		ver_lo;         /* 0x93 */
+	uint8_t		pad[364];
+} __attribute__ ((packed));
+
+struct flash_layout {
+	char		*id;
+	uint32_t	fw_max_len;
+	uint32_t	kernel_la;
+	uint32_t	kernel_ep;
+	uint32_t	rootfs_ofs;
+};
+
+struct board_info {
+	char		*id;
+	uint32_t	hw_id;
+	uint32_t	hw_rev;
+	char		*layout_id;
+	uint32_t	hdr_ver;
+	bool		endian_swap;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+static char *vendor = "TP-LINK Technologies";
+static char *version = "ver. 1.0";
+static char *fw_ver = "0.0.0";
+static char *sver = "1.0";
+static uint32_t hdr_ver = 2;
+
+static char *board_id;
+static struct board_info *board;
+static char *layout_id;
+static struct flash_layout *layout;
+static char *opt_hw_id;
+static uint32_t hw_id;
+static char *opt_hw_rev;
+static uint32_t hw_rev;
+static int fw_ver_lo;
+static int fw_ver_mid;
+static int fw_ver_hi;
+static int sver_lo;
+static int sver_hi;
+static struct file_info kernel_info;
+static uint32_t kernel_la = 0;
+static uint32_t kernel_ep = 0;
+static uint32_t kernel_len = 0;
+static struct file_info rootfs_info;
+static uint32_t rootfs_ofs = 0;
+static uint32_t rootfs_align;
+static struct file_info boot_info;
+static int combined;
+static int strip_padding;
+static int add_jffs2_eof;
+static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+
+static struct file_info inspect_info;
+static int extract = 0;
+static bool endian_swap = false;
+
+char md5salt_normal[MD5SUM_LEN] = {
+	0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
+	0xdc, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x37,
+};
+
+char md5salt_boot[MD5SUM_LEN] = {
+	0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
+	0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
+};
+
+static struct flash_layout layouts[] = {
+	{
+		.id		= "8Mltq",
+		.fw_max_len	= 0x7a0000,
+		.kernel_la	= 0x80002000,
+		.kernel_ep	= 0x80002000,
+		.rootfs_ofs	= 0x140000,
+	}, {
+		.id		= "16Mltq",
+		.fw_max_len	= 0xf90000,
+		.kernel_la	= 0x80002000,
+		.kernel_ep	= 0x800061b0,
+		.rootfs_ofs	= 0x140000,
+	}, {
+		.id		= "8Mmtk",
+		.fw_max_len	= 0x7a0000,
+		.kernel_la	= 0x80000000,
+		.kernel_ep	= 0x80000000,
+		.rootfs_ofs	= 0x140000,
+	}, {
+		/* terminating entry */
+	}
+};
+
+static struct board_info boards[] = {
+	{
+		.id		= "TD-W8970v1",
+		.hw_id		= 0x89700001,
+		.hw_rev		= 1,
+		.layout_id	= "8Mltq",
+	}, {
+		.id		= "TD-W8980v1",
+		.hw_id		= 0x89800001,
+		.hw_rev		= 14,
+		.layout_id	= "8Mltq",
+	}, {
+		.id		= "ArcherC20i",
+		.hw_id		= 0xc2000001,
+		.hw_rev		= 58,
+		.layout_id	= "8Mmtk",
+		.hdr_ver	= 3,
+		.endian_swap	= true,
+	}, {
+		.id		= "ArcherVR200V",
+		.hw_id		= 0x73b70801,
+		.hw_rev		= 0x2f,
+		.layout_id	= "16Mltq",
+		.hdr_ver	= 2,
+	}, {
+		.id		= "ArcherC50",
+		.hw_id		= 0xc7500001,
+		.hw_rev		= 69,
+		.layout_id	= "8Mmtk",
+		.hdr_ver	= 3,
+		.endian_swap	= true,
+	}, {
+		/* terminating entry */
+	}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->id != NULL; board++){
+		if (strcasecmp(id, board->id) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+static struct board_info *find_board_by_hwid(uint32_t hw_id)
+{
+	struct board_info *board;
+
+	for (board = boards; board->id != NULL; board++) {
+		if (hw_id == board->hw_id)
+			return board;
+	};
+
+	return NULL;
+}
+
+static struct flash_layout *find_layout(char *id)
+{
+	struct flash_layout *ret;
+	struct flash_layout *l;
+
+	ret = NULL;
+	for (l = layouts; l->id != NULL; l++){
+		if (strcasecmp(id, l->id) == 0) {
+			ret = l;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>\n"
+"  -c              use combined kernel image\n"
+"  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
+"  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
+"  -H <hwid>       use hardware id specified with <hwid>\n"
+"  -W <hwrev>      use hardware revision specified with <hwrev>\n"
+"  -F <id>         use flash layout specified with <id>\n"
+"  -k <file>       read kernel image from the file <file>\n"
+"  -r <file>       read rootfs image from the file <file>\n"
+"  -a <align>      align the rootfs start on an <align> bytes boundary\n"
+"  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
+"  -o <file>       write output to the file <file>\n"
+"  -s              strip padding from the end of the image\n"
+"  -j              add jffs2 end-of-filesystem markers\n"
+"  -V <version>    set image version to <version>\n"
+"  -v <version>    set firmware version to <version>\n"
+"  -y <version>    set secondary version to <version>\n"
+"  -i <file>       inspect given firmware file <file>\n"
+"  -x              extract kernel and rootfs while inspecting (requires -i)\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static int get_md5(char *data, int size, char *md5)
+{
+	MD5_CTX ctx;
+
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, data, size);
+	MD5_Final(md5, &ctx);
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL)
+		return 0;
+
+	res = stat(fdata->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+ out_close:
+	fclose(f);
+ out:
+	return ret;
+}
+
+static int check_options(void)
+{
+	int ret;
+
+	if (inspect_info.file_name) {
+		ret = get_file_stat(&inspect_info);
+		if (ret)
+			return ret;
+
+		return 0;
+	} else if (extract) {
+		ERR("no firmware for inspection specified");
+		return -1;
+	}
+
+	if (board_id == NULL && opt_hw_id == NULL) {
+		ERR("either board or hardware id must be specified");
+		return -1;
+	}
+
+	if (board_id) {
+		board = find_board(board_id);
+		if (board == NULL) {
+			ERR("unknown/unsupported board id \"%s\"", board_id);
+			return -1;
+		}
+		if (layout_id == NULL)
+			layout_id = board->layout_id;
+
+		hw_id = board->hw_id;
+		hw_rev = board->hw_rev;
+		if (board->hdr_ver)
+			hdr_ver = board->hdr_ver;
+		endian_swap = board->endian_swap;
+	} else {
+		if (layout_id == NULL) {
+			ERR("flash layout is not specified");
+			return -1;
+		}
+		hw_id = strtoul(opt_hw_id, NULL, 0);
+
+		if (opt_hw_rev)
+			hw_rev = strtoul(opt_hw_rev, NULL, 0);
+		else
+			hw_rev = 1;
+	}
+
+	layout = find_layout(layout_id);
+	if (layout == NULL) {
+		ERR("unknown flash layout \"%s\"", layout_id);
+		return -1;
+	}
+
+	if (!kernel_la)
+		kernel_la = layout->kernel_la;
+	if (!kernel_ep)
+		kernel_ep = layout->kernel_ep;
+	if (!rootfs_ofs)
+		rootfs_ofs = layout->rootfs_ofs;
+
+	if (kernel_info.file_name == NULL) {
+		ERR("no kernel image specified");
+		return -1;
+	}
+
+	ret = get_file_stat(&kernel_info);
+	if (ret)
+		return ret;
+
+	kernel_len = kernel_info.file_size;
+
+	if (combined) {
+		if (kernel_info.file_size >
+		    layout->fw_max_len - sizeof(struct fw_header)) {
+			ERR("kernel image is too big");
+			return -1;
+		}
+	} else {
+		if (rootfs_info.file_name == NULL) {
+			ERR("no rootfs image specified");
+			return -1;
+		}
+
+		ret = get_file_stat(&rootfs_info);
+		if (ret)
+			return ret;
+
+		if (rootfs_align) {
+			kernel_len += sizeof(struct fw_header);
+			kernel_len = ALIGN(kernel_len, rootfs_align);
+			kernel_len -= sizeof(struct fw_header);
+
+			DBG("kernel length aligned to %u", kernel_len);
+
+			if (kernel_len + rootfs_info.file_size >
+			    layout->fw_max_len - sizeof(struct fw_header)) {
+				ERR("images are too big");
+				return -1;
+			}
+		} else {
+			if (kernel_info.file_size >
+			    rootfs_ofs - sizeof(struct fw_header)) {
+				ERR("kernel image is too big");
+				return -1;
+			}
+
+			if (rootfs_info.file_size >
+			    (layout->fw_max_len - rootfs_ofs)) {
+				ERR("rootfs image is too big");
+				return -1;
+			}
+		}
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		return -1;
+	}
+
+	ret = sscanf(fw_ver, "%d.%d.%d", &fw_ver_hi, &fw_ver_mid, &fw_ver_lo);
+	if (ret != 3) {
+		ERR("invalid firmware version '%s'", fw_ver);
+		return -1;
+	}
+
+	ret = sscanf(sver, "%d.%d", &sver_hi, &sver_lo);
+	if (ret != 2) {
+		ERR("invalid secondary version '%s'", sver);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void fill_header(char *buf, int len)
+{
+	struct fw_header *hdr = (struct fw_header *)buf;
+	unsigned ver_len;
+
+	memset(hdr, '\xff', sizeof(struct fw_header));
+
+	hdr->version = htonl(bswap_32(hdr_ver));
+	ver_len = strlen(version);
+	if (ver_len > (sizeof(hdr->fw_version) - 1))
+		ver_len = sizeof(hdr->fw_version) - 1;
+
+	memcpy(hdr->fw_version, version, ver_len);
+	hdr->fw_version[ver_len] = 0;
+
+	hdr->hw_id = htonl(hw_id);
+	hdr->hw_rev = htonl(hw_rev);
+
+	if (boot_info.file_size == 0) {
+		memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
+		hdr->boot_ofs = htonl(0);
+		hdr->boot_len = htonl(0);
+	} else {
+		memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
+		hdr->boot_ofs = htonl(rootfs_ofs + rootfs_info.file_size);
+		hdr->boot_len = htonl(rootfs_info.file_size);
+	}
+
+	hdr->kernel_la = htonl(kernel_la);
+	hdr->kernel_ep = htonl(kernel_ep);
+	hdr->fw_length = htonl(layout->fw_max_len);
+	hdr->kernel_ofs = htonl(sizeof(struct fw_header));
+	hdr->kernel_len = htonl(kernel_len);
+	if (!combined) {
+		hdr->rootfs_ofs = htonl(rootfs_ofs);
+		hdr->rootfs_len = htonl(rootfs_info.file_size);
+	}
+
+	hdr->boot_ofs = htonl(0);
+	hdr->boot_len = htonl(boot_info.file_size);
+
+	hdr->unk1 = htonl(0);
+	hdr->unk2 = htonl(0);
+	hdr->unk3 = htonl(0xffffffff);
+	hdr->unk4 = htons(0x55aa);
+	hdr->unk5 = 0xa5;
+
+	hdr->sver_hi = sver_hi;
+	hdr->sver_lo = sver_lo;
+
+	hdr->ver_hi = fw_ver_hi;
+	hdr->ver_mid = fw_ver_mid;
+	hdr->ver_lo = fw_ver_lo;
+
+	if (endian_swap) {
+		hdr->kernel_la = bswap_32(hdr->kernel_la);
+		hdr->kernel_ep = bswap_32(hdr->kernel_ep);
+	}
+
+	get_md5(buf, len, hdr->md5sum1);
+}
+
+static int pad_jffs2(char *buf, int currlen)
+{
+	int len;
+	uint32_t pad_mask;
+
+	len = currlen;
+	pad_mask = (64 * 1024);
+	while ((len < layout->fw_max_len) && (pad_mask != 0)) {
+		uint32_t mask;
+		int i;
+
+		for (i = 10; i < 32; i++) {
+			mask = 1 << i;
+			if (pad_mask & mask)
+				break;
+		}
+
+		len = ALIGN(len, mask);
+
+		for (i = 10; i < 32; i++) {
+			mask = 1 << i;
+			if ((len & (mask - 1)) == 0)
+				pad_mask &= ~mask;
+		}
+
+		for (i = 0; i < sizeof(jffs2_eof_mark); i++)
+			buf[len + i] = jffs2_eof_mark[i];
+
+		len += sizeof(jffs2_eof_mark);
+	}
+
+	return len;
+}
+
+static int write_fw(char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+ out:
+	return ret;
+}
+
+static int build_fw(void)
+{
+	int buflen;
+	char *buf;
+	char *p;
+	int ret = EXIT_FAILURE;
+	int writelen = 0;
+
+	buflen = layout->fw_max_len;
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	memset(buf, 0xff, buflen);
+	p = buf + sizeof(struct fw_header);
+	ret = read_to_buf(&kernel_info, p);
+	if (ret)
+		goto out_free_buf;
+
+	writelen = sizeof(struct fw_header) + kernel_len;
+
+	if (!combined) {
+		if (rootfs_align)
+			p = buf + writelen;
+		else
+			p = buf + rootfs_ofs;
+
+		ret = read_to_buf(&rootfs_info, p);
+		if (ret)
+			goto out_free_buf;
+
+		if (rootfs_align)
+			writelen += rootfs_info.file_size;
+		else
+			writelen = rootfs_ofs + rootfs_info.file_size;
+
+		if (add_jffs2_eof)
+			writelen = pad_jffs2(buf, writelen);
+	}
+
+	if (!strip_padding)
+		writelen = buflen;
+
+	fill_header(buf, writelen);
+	ret = write_fw(buf, writelen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+/* Helper functions to inspect_fw() representing different output formats */
+static inline void inspect_fw_pstr(char *label, char *str)
+{
+	printf("%-23s: %s\n", label, str);
+}
+
+static inline void inspect_fw_phex(char *label, uint32_t val)
+{
+	printf("%-23s: 0x%08x\n", label, val);
+}
+
+static inline void inspect_fw_phexpost(char *label,
+                                       uint32_t val, char *post)
+{
+	printf("%-23s: 0x%08x (%s)\n", label, val, post);
+}
+
+static inline void inspect_fw_phexdef(char *label,
+                                      uint32_t val, uint32_t defval)
+{
+	printf("%-23s: 0x%08x                  ", label, val);
+
+	if (val == defval)
+		printf("(== OpenWrt default)\n");
+	else
+		printf("(OpenWrt default: 0x%08x)\n", defval);
+}
+
+static inline void inspect_fw_phexexp(char *label,
+                                      uint32_t val, uint32_t expval)
+{
+	printf("%-23s: 0x%08x ", label, val);
+
+	if (val == expval)
+		printf("(ok)\n");
+	else
+		printf("(expected: 0x%08x)\n", expval);
+}
+
+static inline void inspect_fw_phexdec(char *label, uint32_t val)
+{
+	printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
+}
+
+static inline void inspect_fw_phexdecdef(char *label,
+                                         uint32_t val, uint32_t defval)
+{
+	printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
+
+	if (val == defval)
+		printf("(== OpenWrt default)\n");
+	else
+		printf("(OpenWrt default: 0x%08x)\n", defval);
+}
+
+static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
+{
+	int i;
+
+	printf("%-23s:", label);
+	for (i=0; i<MD5SUM_LEN; i++)
+		printf(" %02x", val[i]);
+	printf(" %s\n", text);
+}
+
+static int inspect_fw(void)
+{
+	char *buf;
+	struct fw_header *hdr;
+	uint8_t md5sum[MD5SUM_LEN];
+	struct board_info *board;
+	int ret = EXIT_FAILURE;
+
+	buf = malloc(inspect_info.file_size);
+	if (!buf) {
+		ERR("no memory for buffer!\n");
+		goto out;
+	}
+
+	ret = read_to_buf(&inspect_info, buf);
+	if (ret)
+		goto out_free_buf;
+	hdr = (struct fw_header *)buf;
+
+	inspect_fw_pstr("File name", inspect_info.file_name);
+	inspect_fw_phexdec("File size", inspect_info.file_size);
+
+	switch(bswap_32(ntohl(hdr->version))) {
+	case 2:
+	case 3:
+		break;
+	default:
+		ERR("file does not seem to have V2/V3 header!\n");
+		goto out_free_buf;
+	}
+
+	inspect_fw_phexdec("Version 2 Header size", sizeof(struct fw_header));
+
+	if (ntohl(hdr->unk1) != 0)
+		inspect_fw_phexdec("Unknown value 1", hdr->unk1);
+
+	memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
+	if (ntohl(hdr->boot_len) == 0)
+		memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
+	else
+		memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
+	get_md5(buf, inspect_info.file_size, hdr->md5sum1);
+
+	if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
+		inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
+		inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
+	} else {
+		inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
+	}
+	if (ntohl(hdr->unk2) != 0)
+		inspect_fw_phexdec("Unknown value 2", hdr->unk2);
+	inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
+	                   "(purpose yet unknown, unchecked here)");
+
+	if (ntohl(hdr->unk3) != 0xffffffff)
+		inspect_fw_phexdec("Unknown value 3", hdr->unk3);
+
+	if (ntohs(hdr->unk4) != 0x55aa)
+		inspect_fw_phexdec("Unknown value 4", hdr->unk4);
+
+	if (hdr->unk5 != 0xa5)
+		inspect_fw_phexdec("Unknown value 5", hdr->unk5);
+
+	printf("\n");
+
+	inspect_fw_pstr("Firmware version", hdr->fw_version);
+
+	board = find_board_by_hwid(ntohl(hdr->hw_id));
+	if (board) {
+		layout = find_layout(board->layout_id);
+		inspect_fw_phexpost("Hardware ID",
+		                    ntohl(hdr->hw_id), board->id);
+		inspect_fw_phexexp("Hardware Revision",
+		                   ntohl(hdr->hw_rev), board->hw_rev);
+	} else {
+		inspect_fw_phexpost("Hardware ID",
+		                    ntohl(hdr->hw_id), "unknown");
+		inspect_fw_phex("Hardware Revision",
+		                ntohl(hdr->hw_rev));
+	}
+
+	printf("%-23s: %d.%d.%d-%d.%d\n", "Software version",
+	       hdr->ver_hi, hdr->ver_mid, hdr->ver_lo,
+	       hdr->sver_hi, hdr->sver_lo);
+
+	printf("\n");
+
+	inspect_fw_phexdec("Kernel data offset",
+	                   ntohl(hdr->kernel_ofs));
+	inspect_fw_phexdec("Kernel data length",
+	                   ntohl(hdr->kernel_len));
+	if (board) {
+		inspect_fw_phexdef("Kernel load address",
+		                   ntohl(hdr->kernel_la),
+		                   layout ? layout->kernel_la : 0xffffffff);
+		inspect_fw_phexdef("Kernel entry point",
+		                   ntohl(hdr->kernel_ep),
+		                   layout ? layout->kernel_ep : 0xffffffff);
+		inspect_fw_phexdecdef("Rootfs data offset",
+		                      ntohl(hdr->rootfs_ofs),
+		                      layout ? layout->rootfs_ofs : 0xffffffff);
+	} else {
+		inspect_fw_phex("Kernel load address",
+		                ntohl(hdr->kernel_la));
+		inspect_fw_phex("Kernel entry point",
+		                ntohl(hdr->kernel_ep));
+		inspect_fw_phexdec("Rootfs data offset",
+		                   ntohl(hdr->rootfs_ofs));
+	}
+	inspect_fw_phexdec("Rootfs data length",
+	                   ntohl(hdr->rootfs_len));
+	inspect_fw_phexdec("Boot loader data offset",
+	                   ntohl(hdr->boot_ofs));
+	inspect_fw_phexdec("Boot loader data length",
+	                   ntohl(hdr->boot_len));
+	inspect_fw_phexdec("Total firmware length",
+	                   ntohl(hdr->fw_length));
+
+	if (extract) {
+		FILE *fp;
+		char *filename;
+
+		printf("\n");
+
+		filename = malloc(strlen(inspect_info.file_name) + 8);
+		sprintf(filename, "%s-kernel", inspect_info.file_name);
+		printf("Extracting kernel to \"%s\"...\n", filename);
+		fp = fopen(filename, "w");
+		if (fp)	{
+			if (!fwrite(buf + ntohl(hdr->kernel_ofs),
+			            ntohl(hdr->kernel_len), 1, fp)) {
+				ERR("error in fwrite(): %s", strerror(errno));
+			}
+			fclose(fp);
+		} else {
+			ERR("error in fopen(): %s", strerror(errno));
+		}
+		free(filename);
+
+		filename = malloc(strlen(inspect_info.file_name) + 8);
+		sprintf(filename, "%s-rootfs", inspect_info.file_name);
+		printf("Extracting rootfs to \"%s\"...\n", filename);
+		fp = fopen(filename, "w");
+		if (fp)	{
+			if (!fwrite(buf + ntohl(hdr->rootfs_ofs),
+			            ntohl(hdr->rootfs_len), 1, fp)) {
+				ERR("error in fwrite(): %s", strerror(errno));
+			}
+			fclose(fp);
+		} else {
+			ERR("error in fopen(): %s", strerror(errno));
+		}
+		free(filename);
+	}
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	int err;
+
+	FILE *outfile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "a:B:H:E:F:L:V:N:W:ci:k:r:R:o:xhsjv:y:T:e");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'a':
+			sscanf(optarg, "0x%x", &rootfs_align);
+			break;
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'H':
+			opt_hw_id = optarg;
+			break;
+		case 'E':
+			sscanf(optarg, "0x%x", &kernel_ep);
+			break;
+		case 'F':
+			layout_id = optarg;
+			break;
+		case 'W':
+			opt_hw_rev = optarg;
+			break;
+		case 'L':
+			sscanf(optarg, "0x%x", &kernel_la);
+			break;
+		case 'V':
+			version = optarg;
+			break;
+		case 'v':
+			fw_ver = optarg;
+			break;
+		case 'y':
+			sver = optarg;
+			break;
+		case 'N':
+			vendor = optarg;
+			break;
+		case 'c':
+			combined++;
+			break;
+		case 'k':
+			kernel_info.file_name = optarg;
+			break;
+		case 'r':
+			rootfs_info.file_name = optarg;
+			break;
+		case 'R':
+			sscanf(optarg, "0x%x", &rootfs_ofs);
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			strip_padding = 1;
+			break;
+		case 'i':
+			inspect_info.file_name = optarg;
+			break;
+		case 'j':
+			add_jffs2_eof = 1;
+			break;
+		case 'x':
+			extract = 1;
+			break;
+		case 'T':
+			hdr_ver = atoi(optarg);
+			break;
+		case 'e':
+			endian_swap = true;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	if (!inspect_info.file_name)
+		ret = build_fw();
+	else
+		ret = inspect_fw();
+
+ out:
+	return ret;
+}
+
diff --git a/tools/firmware-utils/src/mkwrggimg.c b/tools/firmware-utils/src/mkwrggimg.c
new file mode 100644
index 0000000000..9995b9a13d
--- /dev/null
+++ b/tools/firmware-utils/src/mkwrggimg.c
@@ -0,0 +1,283 @@
+/*
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
+ *
+ *  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.
+ *
+ */
+
+#define _ANSI_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "md5.h"
+
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WRGG03_MAGIC	0x20080321
+
+struct wrgg03_header {
+	char		signature[32];
+	uint32_t	magic1;
+	uint32_t	magic2;
+	char		version[16];
+	char		model[16];
+	uint32_t	flag[2];
+	uint32_t	reserve[2];
+	char		buildno[16];
+	uint32_t	size;
+	uint32_t	offset;
+	char		devname[32];
+	char		digest[16];
+} __attribute__ ((packed));
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static char *signature;
+static char *version;
+static char *model;
+static uint32_t flag = 0;
+static uint32_t reserve = 0;
+static char *buildno;
+static uint32_t offset;
+static char *devname;
+static int big_endian;
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -b              create image in big endian format\n"
+"  -B <buildno>    build number\n"
+"  -i <file>       read input from the file <file>\n"
+"  -d <name>       set device name to <name>\n"
+"  -m <model>      model name\n"
+"  -o <file>       write output to the file <file>\n"
+"  -O <offset>     set offset to <offset>\n"
+"  -s <sig>        set image signature to <sig>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static void put_u32(void *data, uint32_t val, int swap)
+{
+	unsigned char *p = data;
+
+	if (swap) {
+		p[0] = (val >> 24) & 0xff;
+		p[1] = (val >> 16) & 0xff;
+		p[2] = (val >> 8) & 0xff;
+		p[3] = val & 0xff;
+	} else {
+		p[3] = (val >> 24) & 0xff;
+		p[2] = (val >> 16) & 0xff;
+		p[1] = (val >> 8) & 0xff;
+		p[0] = val & 0xff;
+	}
+}
+
+static void get_digest(struct wrgg03_header *header, char *data, int size)
+{
+	MD5_CTX ctx;
+
+	MD5_Init(&ctx);
+
+	MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
+	MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
+	MD5_Update(&ctx, data, size);
+
+	MD5_Final(header->digest, &ctx);
+}
+
+int main(int argc, char *argv[])
+{
+	struct wrgg03_header *header;
+	char *buf;
+	struct stat st;
+	int buflen;
+	int err;
+	int res = EXIT_FAILURE;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "bd:i:m:o:s:v:B:O:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'b':
+			big_endian = 1;
+			break;
+		case 'B':
+			buildno = optarg;
+			break;
+		case 'd':
+			devname = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'm':
+			model = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			signature = optarg;
+			break;
+		case 'v':
+			version = optarg;
+			break;
+		case 'O':
+			offset = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (signature == NULL) {
+		ERR("no signature specified");
+		goto err;
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	if (devname == NULL) {
+		ERR("no device name specified");
+		goto err;
+	}
+
+	if (model == NULL) {
+		ERR("no model name specified");
+		goto err;
+	}
+
+	if (buildno == NULL) {
+		ERR("no build number specified");
+		goto err;
+	}
+
+	if (version == NULL) {
+		ERR("no version specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	buflen = st.st_size + sizeof(struct wrgg03_header);
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	errno = 0;
+	fread(buf + sizeof(struct wrgg03_header), st.st_size, 1, infile);
+	if (errno != 0) {
+		ERRS("unable to read from file %s", ifname);
+		goto close_in;
+	}
+
+	header = (struct wrgg03_header *) buf;
+	memset(header, '\0', sizeof(struct wrgg03_header));
+
+	strncpy(header->signature, signature, sizeof(header->signature));
+	put_u32(&header->magic1, WRGG03_MAGIC, 0);
+	put_u32(&header->magic2, WRGG03_MAGIC, 0);
+	strncpy(header->version, version, sizeof(header->version));
+	strncpy(header->model, model, sizeof(header->model));
+	put_u32(&header->flag, flag, 0);
+	put_u32(&header->reserve, reserve, 0);
+	strncpy(header->buildno, buildno, sizeof(header->buildno));
+	put_u32(&header->size, st.st_size, big_endian);
+	put_u32(&header->offset, offset, big_endian);
+	strncpy(header->devname, devname, sizeof(header->devname));
+
+	get_digest(header, buf + sizeof(struct wrgg03_header), st.st_size);
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto close_in;
+	}
+
+	errno = 0;
+	fwrite(buf, buflen, 1, outfile);
+	if (errno) {
+		ERRS("unable to write to file %s", ofname);
+		goto close_out;
+	}
+
+	fflush(outfile);
+
+	res = EXIT_SUCCESS;
+
+close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS)
+		unlink(ofname);
+close_in:
+	fclose(infile);
+err_free:
+	free(buf);
+err:
+	return res;
+}
diff --git a/tools/firmware-utils/src/mkwrgimg.c b/tools/firmware-utils/src/mkwrgimg.c
new file mode 100644
index 0000000000..3915d146cf
--- /dev/null
+++ b/tools/firmware-utils/src/mkwrgimg.c
@@ -0,0 +1,240 @@
+/*
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "md5.h"
+
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WRG_MAGIC	0x20040220
+
+struct wrg_header {
+	char		signature[32];
+	uint32_t	magic1;
+	uint32_t	magic2;
+	uint32_t	size;
+	uint32_t	offset;
+	char		devname[32];
+	char		digest[16];
+} __attribute__ ((packed));
+
+static char *progname;
+static char *ifname;
+static char *ofname;
+static char *signature;
+static char *dev_name;
+static uint32_t offset;
+static int big_endian;
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -b              create image in big endian format\n"
+"  -i <file>       read input from the file <file>\n"
+"  -d <name>       set device name to <name>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -O <offset>     set offset to <offset>\n"
+"  -s <sig>        set image signature to <sig>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static void put_u32(void *data, uint32_t val)
+{
+	unsigned char *p = data;
+
+	if (big_endian) {
+		p[0] = (val >> 24) & 0xff;
+		p[1] = (val >> 16) & 0xff;
+		p[2] = (val >> 8) & 0xff;
+		p[3] = val & 0xff;
+	} else {
+		p[3] = (val >> 24) & 0xff;
+		p[2] = (val >> 16) & 0xff;
+		p[1] = (val >> 8) & 0xff;
+		p[0] = val & 0xff;
+	}
+}
+
+static void get_digest(struct wrg_header *header, char *data, int size)
+{
+	MD5_CTX ctx;
+
+	MD5_Init(&ctx);
+
+	MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
+	MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
+	MD5_Update(&ctx, data, size);
+
+	MD5_Final(header->digest, &ctx);
+}
+
+int main(int argc, char *argv[])
+{
+	struct wrg_header *header;
+	char *buf;
+	struct stat st;
+	int buflen;
+	int err;
+	int res = EXIT_FAILURE;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "bd:i:o:s:O:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'b':
+			big_endian = 1;
+			break;
+		case 'd':
+			dev_name = optarg;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 's':
+			signature = optarg;
+			break;
+		case 'O':
+			offset = strtoul(optarg, NULL, 0);
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (signature == NULL) {
+		ERR("no signature specified");
+		goto err;
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	if (dev_name == NULL) {
+		ERR("no device name specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	buflen = st.st_size + sizeof(struct wrg_header);
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	errno = 0;
+	fread(buf + sizeof(struct wrg_header), st.st_size, 1, infile);
+	if (errno != 0) {
+		ERRS("unable to read from file %s", ifname);
+		goto close_in;
+	}
+
+	header = (struct wrg_header *) buf;
+	memset(header, '\0', sizeof(struct wrg_header));
+
+	strncpy(header->signature, signature, sizeof(header->signature));
+	strncpy(header->devname, dev_name, sizeof(header->signature));
+	put_u32(&header->magic1, WRG_MAGIC);
+	put_u32(&header->magic2, WRG_MAGIC);
+	put_u32(&header->size, st.st_size);
+	put_u32(&header->offset, offset);
+
+	get_digest(header, buf + sizeof(struct wrg_header), st.st_size);
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto close_in;
+	}
+
+	errno = 0;
+	fwrite(buf, buflen, 1, outfile);
+	if (errno) {
+		ERRS("unable to write to file %s", ofname);
+		goto close_out;
+	}
+
+	fflush(outfile);
+
+	res = EXIT_SUCCESS;
+
+close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS)
+		unlink(ofname);
+close_in:
+	fclose(infile);
+err_free:
+	free(buf);
+err:
+	return res;
+}
diff --git a/tools/firmware-utils/src/mkzcfw.c b/tools/firmware-utils/src/mkzcfw.c
new file mode 100644
index 0000000000..2326f1ff5c
--- /dev/null
+++ b/tools/firmware-utils/src/mkzcfw.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "cyg_crc.h"
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define HOST_TO_BE32(x)	(x)
+#  define BE32_TO_HOST(x)	(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#else
+#  define HOST_TO_BE32(x)	bswap_32(x)
+#  define BE32_TO_HOST(x)	bswap_32(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#endif
+
+#define MAGIC_FIRMWARE	0x6d726966	/* 'firm' */
+#define MAGIC_KERNEL	0x676d694b	/* 'Kimg' */
+#define MAGIC_ROOTFS	0x676d6952	/* 'Rimg' */
+
+struct file_info {
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+};
+
+struct fw_header {
+	uint32_t	magic;
+	uint32_t	length;
+	uint32_t	unk1;
+	uint32_t	unk2;
+} __attribute__ ((packed));
+
+struct fw_tail {
+	uint32_t	hw_id;
+	uint32_t	crc;
+} __attribute__ ((packed));
+
+struct board_info {
+	char		*id;
+	uint32_t	hw_id;
+	uint32_t	kernel_len;
+	uint32_t	rootfs_len;
+};
+
+/*
+ * Globals
+ */
+static char *ofname;
+static char *progname;
+
+static char *board_id;
+static struct board_info *board;
+static struct file_info kernel_info;
+static struct file_info rootfs_info;
+
+
+static struct board_info boards[] = {
+	{
+		.id		= "ZCN-1523H-2-8",
+		.hw_id		= 0x66661523,
+		.kernel_len	= 0x170000,
+		.rootfs_len	= 0x610000,
+	}, {
+		.id		= "ZCN-1523H-5-16",
+		.hw_id		= 0x6615235A,
+		.kernel_len	= 0x170000,
+		.rootfs_len	= 0x610000,
+	}, {
+		/* terminating entry */
+	}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define DBG(fmt, ...) do { \
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+static struct board_info *find_board(char *id)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->id != NULL; board++){
+		if (strcasecmp(id, board->id) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+static void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\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"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+static int get_file_stat(struct file_info *fdata)
+{
+	struct stat st;
+	int res;
+
+	if (fdata->file_name == NULL)
+		return 0;
+
+	res = stat(fdata->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", fdata->file_name);
+		return res;
+	}
+
+	fdata->file_size = st.st_size;
+	return 0;
+}
+
+static int read_to_buf(struct file_info *fdata, char *buf)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(fdata->file_name, "r");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for reading", fdata->file_name);
+		goto out;
+	}
+
+	errno = 0;
+	fread(buf, fdata->file_size, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file \"%s\"", fdata->file_name);
+		goto out_close;
+	}
+
+	ret = EXIT_SUCCESS;
+
+ out_close:
+	fclose(f);
+ out:
+	return ret;
+}
+
+static int check_options(void)
+{
+	int ret;
+
+	if (board_id == NULL) {
+		ERR("no board specified");
+		return -1;
+	}
+
+	board = find_board(board_id);
+	if (board == NULL) {
+		ERR("unknown/unsupported board id \"%s\"", board_id);
+		return -1;
+	}
+
+	if (kernel_info.file_name == NULL) {
+		ERR("no kernel image specified");
+		return -1;
+	}
+
+	ret = get_file_stat(&kernel_info);
+	if (ret)
+		return ret;
+
+	if (kernel_info.file_size > board->kernel_len) {
+		ERR("kernel image is too big");
+		return -1;
+	}
+
+	if (rootfs_info.file_name == NULL) {
+		ERR("no rootfs image specified");
+		return -1;
+	}
+
+	ret = get_file_stat(&rootfs_info);
+	if (ret)
+		return ret;
+
+	if (rootfs_info.file_size > board->rootfs_len) {
+		ERR("rootfs image is too big");
+		return -1;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int write_fw(char *data, int len)
+{
+	FILE *f;
+	int ret = EXIT_FAILURE;
+
+	f = fopen(ofname, "w");
+	if (f == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	errno = 0;
+	fwrite(data, len, 1, f);
+	if (errno) {
+		ERRS("unable to write output file");
+		goto out_flush;
+	}
+
+	DBG("firmware file \"%s\" completed", ofname);
+
+	ret = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(f);
+	fclose(f);
+	if (ret != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+ out:
+	return ret;
+}
+
+static int build_fw(void)
+{
+	int buflen;
+	char *buf;
+	char *p;
+	int ret = EXIT_FAILURE;
+	int writelen = 0;
+	uint32_t crc;
+	struct fw_header *hdr;
+	struct fw_tail *tail;
+
+	buflen = 3 * sizeof(struct fw_header) +
+		 kernel_info.file_size + rootfs_info.file_size +
+		 3 * sizeof(struct fw_tail);
+
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto out;
+	}
+
+	p = buf;
+	memset(p, 0, buflen);
+
+	/* fill firmware header */
+	hdr = (struct fw_header *) p;
+	hdr->magic = HOST_TO_LE32(MAGIC_FIRMWARE);
+	hdr->length = HOST_TO_LE32(buflen - sizeof(struct fw_header));
+	p += sizeof(struct fw_header);
+
+	/* fill kernel block header */
+	hdr = (struct fw_header *) p;
+	hdr->magic = HOST_TO_LE32(MAGIC_KERNEL);
+	hdr->length = HOST_TO_LE32(kernel_info.file_size +
+				   sizeof(struct fw_tail));
+	p += sizeof(struct fw_header);
+
+	/* read kernel data */
+	ret = read_to_buf(&kernel_info, p);
+	if (ret)
+		goto out_free_buf;
+
+	/* fill firmware tail */
+	tail = (struct fw_tail *) (p + kernel_info.file_size);
+	tail->hw_id = HOST_TO_BE32(board->hw_id);
+	tail->crc = HOST_TO_BE32(cyg_crc32(p, kernel_info.file_size +
+				 	   sizeof(struct fw_tail) - 4));
+
+	p += kernel_info.file_size + sizeof(struct fw_tail);
+
+	/* fill rootfs block header */
+	hdr = (struct fw_header *) p;
+	hdr->magic = HOST_TO_LE32(MAGIC_ROOTFS);
+	hdr->length = HOST_TO_LE32(rootfs_info.file_size +
+				   sizeof(struct fw_tail));
+	p += sizeof(struct fw_header);
+
+	/* read rootfs data */
+	ret = read_to_buf(&rootfs_info, p);
+	if (ret)
+		goto out_free_buf;
+
+	/* fill firmware tail */
+	tail = (struct fw_tail *) (p + rootfs_info.file_size);
+	tail->hw_id = HOST_TO_BE32(board->hw_id);
+	tail->crc = HOST_TO_BE32(cyg_crc32(p, rootfs_info.file_size +
+				 	   sizeof(struct fw_tail) - 4));
+
+	p += rootfs_info.file_size + sizeof(struct fw_tail);
+
+	/* fill firmware tail */
+	tail = (struct fw_tail *) p;
+	tail->hw_id = HOST_TO_BE32(board->hw_id);
+	tail->crc = HOST_TO_BE32(cyg_crc32(buf + sizeof(struct fw_header),
+				 buflen - sizeof(struct fw_header) - 4));
+
+	ret = write_fw(buf, buflen);
+	if (ret)
+		goto out_free_buf;
+
+	ret = EXIT_SUCCESS;
+
+ out_free_buf:
+	free(buf);
+ out:
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	int err;
+
+	FILE *outfile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "B:k:r:o:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'B':
+			board_id = optarg;
+			break;
+		case 'k':
+			kernel_info.file_name = optarg;
+			break;
+		case 'r':
+			rootfs_info.file_name = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	ret = check_options();
+	if (ret)
+		goto out;
+
+	ret = build_fw();
+
+ out:
+	return ret;
+}
+
diff --git a/tools/firmware-utils/src/mkzynfw.c b/tools/firmware-utils/src/mkzynfw.c
new file mode 100644
index 0000000000..ccbabfe7f2
--- /dev/null
+++ b/tools/firmware-utils/src/mkzynfw.c
@@ -0,0 +1,1131 @@
+/*
+ *
+ *  Copyright (C) 2007-2008 OpenWrt.org
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This code was based on the information of the ZyXEL's firmware
+ *  image format written by Kolja Waschk, can be found at:
+ *  http://www.ixo.de/info/zyxel_uclinux
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>	/* for unlink() */
+#include <libgen.h>
+#include <getopt.h>	/* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <endian.h>	/* for __BYTE_ORDER */
+#if defined(__CYGWIN__)
+#  include <byteswap.h>
+#endif
+#include <inttypes.h>
+
+#include "zynos.h"
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE16_TO_HOST(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#  define HOST_TO_BE16(x)	bswap_16(x)
+#  define HOST_TO_BE32(x)	bswap_32(x)
+#  define BE16_TO_HOST(x)	bswap_16(x)
+#  define BE32_TO_HOST(x)	bswap_32(x)
+#else
+#  define HOST_TO_BE16(x)	(x)
+#  define HOST_TO_BE32(x)	(x)
+#  define BE16_TO_HOST(x)	(x)
+#  define BE32_TO_HOST(x)	(x)
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE16_TO_HOST(x)	bswap_16(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#endif
+
+#define ALIGN(x,y)	(((x)+((y)-1)) & ~((y)-1))
+
+#define MAX_NUM_BLOCKS	8
+#define MAX_ARG_COUNT	32
+#define MAX_ARG_LEN	1024
+#define FILE_BUF_LEN	(16*1024)
+
+
+struct csum_state{
+	int		odd;
+	uint32_t	sum;
+	uint32_t	tmp;
+};
+
+struct fw_block {
+	uint32_t	align;		/* alignment of this block */
+	char		*file_name;	/* name of the file */
+	uint32_t	file_size;	/* length of the file */
+	char		*mmap_name;	/* name in the MMAP table */
+	int		type;		/* block type */
+	uint32_t	padlen;
+	uint8_t		padc;
+};
+
+#define BLOCK_TYPE_BOOTEXT	0
+#define BLOCK_TYPE_RAW		1
+
+struct fw_mmap {
+	uint32_t	addr;
+	uint32_t	size;
+	uint32_t	user_addr;
+	uint32_t	user_size;
+};
+#define MMAP_DATA_SIZE	1024
+#define MMAP_ALIGN	16
+
+struct board_info {
+	char *name;		/* model name */
+	char *desc;		/* description */
+	uint16_t vendor;	/* vendor id */
+	uint16_t model;		/* model id */
+	uint32_t flash_base;	/* flash base address */
+	uint32_t flash_size;	/* board flash size */
+	uint32_t code_start;	/* code start address */
+	uint32_t romio_offs;	/* offset of the firmware within the flash */
+	uint32_t bootext_size;	/* maximum size of bootext block */
+};
+
+/*
+ * Globals
+ */
+char *progname;
+char *ofname = NULL;
+int verblevel = 0;
+
+struct board_info *board = NULL;
+
+struct fw_block blocks[MAX_NUM_BLOCKS];
+struct fw_block *bootext_block = NULL;
+int num_blocks = 0;
+
+#define ADM5120_FLASH_BASE	0xBFC00000
+#define ADM5120_CODE_START	0x80008000
+
+/* TODO: check values for AR7 */
+#define AR7_FLASH_BASE		0xB0000000
+#define AR7_CODE_START		0x94008000
+
+#define ATHEROS_FLASH_BASE	0xBFC00000
+#define ATHEROS_CODE_START	0x80e00000
+
+#define AR71XX_FLASH_BASE	0xBFC00000
+#define AR71XX_CODE_START	0x81E00000
+
+#define BOARD(n, d, v, m, fb, fs, cs, fo) {		\
+	.name = (n), .desc=(d),				\
+	.vendor = (v), .model = (m),			\
+	.flash_base = (fb), .flash_size = (fs)<<20,	\
+	.code_start = (cs), .romio_offs = (fo),		\
+	.bootext_size = BOOTEXT_DEF_SIZE		\
+	}
+
+#define ADMBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+	ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x8000)
+
+#define ADMBOARD2(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+	ADM5120_FLASH_BASE, fs, ADM5120_CODE_START, 0x10000)
+
+#define AR7BOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+	AR7_FLASH_BASE, fs, AR7_CODE_START, 0x8000)
+
+#define ATHEROSBOARD1(n, d, m, fs) BOARD(n, d, ZYNOS_VENDOR_ID_ZYXEL, m, \
+	ATHEROS_FLASH_BASE, fs, ATHEROS_CODE_START, 0x30000)
+
+#define AR71XXBOARD1(n, d, m, fs) {		\
+	.name = (n), .desc=(d),				\
+	.vendor = (ZYNOS_VENDOR_ID_ZYXEL), .model = (m),			\
+	.flash_base = (AR71XX_FLASH_BASE), .flash_size = (fs)<<20,	\
+	.code_start = (AR71XX_CODE_START), .romio_offs = (0x40000),		\
+	.bootext_size = 0x30000		\
+	}
+
+
+static struct board_info boards[] = {
+	/*
+	 * Infineon/ADMtek ADM5120 based boards
+	 */
+	ADMBOARD2("ES-2024A",	"ZyXEL ES-2024A", ZYNOS_MODEL_ES_2024A, 4),
+	ADMBOARD2("ES-2024PWR",	"ZyXEL ES-2024PWR", ZYNOS_MODEL_ES_2024PWR, 4),
+	ADMBOARD2("ES-2108",	"ZyXEL ES-2108", ZYNOS_MODEL_ES_2108, 4),
+	ADMBOARD2("ES-2108-F",	"ZyXEL ES-2108-F", ZYNOS_MODEL_ES_2108_F, 4),
+	ADMBOARD2("ES-2108-G",	"ZyXEL ES-2108-G", ZYNOS_MODEL_ES_2108_G, 4),
+	ADMBOARD2("ES-2108-LC",	"ZyXEL ES-2108-LC", ZYNOS_MODEL_ES_2108_LC, 4),
+	ADMBOARD2("ES-2108PWR",	"ZyXEL ES-2108PWR", ZYNOS_MODEL_ES_2108PWR, 4),
+	ADMBOARD1("HS-100",	"ZyXEL HomeSafe 100", ZYNOS_MODEL_HS_100, 2),
+	ADMBOARD1("HS-100W",	"ZyXEL HomeSafe 100W", ZYNOS_MODEL_HS_100W, 2),
+	ADMBOARD1("P-334",	"ZyXEL Prestige 334", ZYNOS_MODEL_P_334, 2),
+	ADMBOARD1("P-334U",	"ZyXEL Prestige 334U", ZYNOS_MODEL_P_334U, 4),
+	ADMBOARD1("P-334W",	"ZyXEL Prestige 334W", ZYNOS_MODEL_P_334W, 2),
+	ADMBOARD1("P-334WH",	"ZyXEL Prestige 334WH", ZYNOS_MODEL_P_334WH, 4),
+	ADMBOARD1("P-334WHD",	"ZyXEL Prestige 334WHD", ZYNOS_MODEL_P_334WHD, 4),
+	ADMBOARD1("P-334WT",	"ZyXEL Prestige 334WT", ZYNOS_MODEL_P_334WT, 4),
+	ADMBOARD1("P-335",	"ZyXEL Prestige 335", ZYNOS_MODEL_P_335, 4),
+	ADMBOARD1("P-335Plus",	"ZyXEL Prestige 335Plus", ZYNOS_MODEL_P_335PLUS, 4),
+	ADMBOARD1("P-335U",	"ZyXEL Prestige 335U", ZYNOS_MODEL_P_335U, 4),
+	ADMBOARD1("P-335WT",	"ZyXEL Prestige 335WT", ZYNOS_MODEL_P_335WT, 4),
+
+	{
+		.name		= "P-2602HW-D1A",
+		.desc		= "ZyXEL P-2602HW-D1A",
+		.vendor		= ZYNOS_VENDOR_ID_ZYXEL,
+		.model		= ZYNOS_MODEL_P_2602HW_D1A,
+		.flash_base	= AR7_FLASH_BASE,
+		.flash_size	= 4*1024*1024,
+		.code_start	= 0x94008000,
+		.romio_offs	= 0x20000,
+		.bootext_size	= BOOTEXT_DEF_SIZE,
+	},
+
+#if 0
+	/*
+	 * Texas Instruments AR7 based boards
+	 */
+	AR7BOARD1("P-660H-61",  "ZyXEL P-660H-61", ZYNOS_MODEL_P_660H_61, 2),
+	AR7BOARD1("P-660H-63",  "ZyXEL P-660H-63", ZYNOS_MODEL_P_660H_63, 2),
+	AR7BOARD1("P-660H-D1",  "ZyXEL P-660H-D1", ZYNOS_MODEL_P_660H_D1, 2),
+	AR7BOARD1("P-660H-D3",  "ZyXEL P-660H-D3", ZYNOS_MODEL_P_660H_D3, 2),
+	AR7BOARD1("P-660HW-61", "ZyXEL P-660HW-61", ZYNOS_MODEL_P_660HW_61, 2),
+	AR7BOARD1("P-660HW-63", "ZyXEL P-660HW-63", ZYNOS_MODEL_P_660HW_63, 2),
+	AR7BOARD1("P-660HW-67", "ZyXEL P-660HW-67", ZYNOS_MODEL_P_660HW_67, 2),
+	AR7BOARD1("P-660HW-D1", "ZyXEL P-660HW-D1", ZYNOS_MODEL_P_660HW_D1, 2),
+	AR7BOARD1("P-660HW-D3", "ZyXEL P-660HW-D3", ZYNOS_MODEL_P_660HW_D3, 2),
+	AR7BOARD1("P-660R-61",  "ZyXEL P-660R-61", ZYNOS_MODEL_P_660R_61, 2),
+	AR7BOARD1("P-660R-61C", "ZyXEL P-660R-61C", ZYNOS_MODEL_P_660R_61C, 2),
+	AR7BOARD1("P-660R-63",  "ZyXEL P-660R-63", ZYNOS_MODEL_P_660R_63, 2),
+	AR7BOARD1("P-660R-63C", "ZyXEL P-660R-63C", ZYNOS_MODEL_P_660R_63C, 2),
+	AR7BOARD1("P-660R-67",  "ZyXEL P-660R-67", ZYNOS_MODEL_P_660R_67, 2),
+	AR7BOARD1("P-660R-D1",  "ZyXEL P-660R-D1", ZYNOS_MODEL_P_660R_D1, 2),
+	AR7BOARD1("P-660R-D3",  "ZyXEL P-660R-D3", ZYNOS_MODEL_P_660R_D3, 2),
+#endif
+	{
+		.name		= "O2SURF",
+		.desc		= "O2 DSL Surf & Phone",
+		.vendor		= ZYNOS_VENDOR_ID_O2,
+		.model		= ZYNOS_MODEL_O2SURF,
+		.flash_base	= AR7_FLASH_BASE,
+		.flash_size	= 8*1024*1024,
+		.code_start	= 0x94014000,
+		.romio_offs	= 0x40000,
+		.bootext_size	= BOOTEXT_DEF_SIZE,
+	},
+
+	/*
+:x
+	 */
+	ATHEROSBOARD1("NBG-318S", "ZyXEL NBG-318S", ZYNOS_MODEL_NBG_318S, 4),
+
+	/*
+	 * Atheros ar71xx based boards
+	 */
+	AR71XXBOARD1("NBG-460N", "ZyXEL NBG-460N", ZYNOS_MODEL_NBG_460N, 4),
+
+	{.name = NULL}
+};
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define WARN(fmt, ...) do { \
+	fprintf(stderr, "[%s] *** warning: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define DBG(lev, fmt, ...) do { \
+	if (verblevel < lev) \
+		break;\
+	fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERR_FATAL		-1
+#define ERR_INVALID_IMAGE	-2
+
+/*
+ * Helper routines
+ */
+void
+usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -B <board>      create image for the board specified with <board>.\n"
+"                  valid <board> values:\n"
+	);
+	for (board = boards; board->name != NULL; board++){
+		fprintf(stream,
+"                    %-12s= %s\n",
+		 board->name, board->desc);
+	};
+	fprintf(stream,
+"  -b <file>[:<align>]\n"
+"                  add boot extension block to the image\n"
+"  -r <file>[:<align>]\n"
+"                  add raw block to the image\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+
+/*
+ * argument parsing
+ */
+int
+str2u32(char *arg, uint32_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err)) {
+		return -1;
+	}
+
+	*val = t;
+	return 0;
+}
+
+
+int
+str2u16(char *arg, uint16_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
+		return -1;
+	}
+
+	*val = t & 0xFFFF;
+	return 0;
+}
+
+int
+str2u8(char *arg, uint8_t *val)
+{
+	char *err = NULL;
+	uint32_t t;
+
+	errno=0;
+	t = strtoul(arg, &err, 0);
+	if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
+		return -1;
+	}
+
+	*val = t & 0xFF;
+	return 0;
+}
+
+int
+str2sig(char *arg, uint32_t *sig)
+{
+	if (strlen(arg) != 4)
+		return -1;
+
+	*sig = arg[0] | (arg[1] << 8) | (arg[2] << 16) | (arg[3] << 24);
+
+	return 0;
+}
+
+
+int
+parse_arg(char *arg, char *buf, char *argv[])
+{
+	int res = 0;
+	size_t argl;
+	char *tok;
+	char **ap = &buf;
+	int i;
+
+	memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
+
+	if ((arg == NULL)) {
+		/* no arguments */
+		return 0;
+	}
+
+	argl = strlen(arg);
+	if (argl == 0) {
+		/* no arguments */
+		return 0;
+	}
+
+	if (argl >= MAX_ARG_LEN) {
+		/* argument is too long */
+		argl = MAX_ARG_LEN-1;
+	}
+
+	memcpy(buf, arg, argl);
+	buf[argl] = '\0';
+
+	for (i = 0; i < MAX_ARG_COUNT; i++) {
+		tok = strsep(ap, ":");
+		if (tok == NULL) {
+			break;
+		}
+#if 0
+		else if (tok[0] == '\0') {
+			break;
+		}
+#endif
+		argv[i] = tok;
+		res++;
+	}
+
+	return res;
+}
+
+
+int
+required_arg(char c, char *arg)
+{
+	if (arg == NULL || *arg != '-')
+		return 0;
+
+	ERR("option -%c requires an argument\n", c);
+	return -1;
+}
+
+
+int
+is_empty_arg(char *arg)
+{
+	int ret = 1;
+	if (arg != NULL) {
+		if (*arg) ret = 0;
+	};
+	return ret;
+}
+
+
+void
+csum_init(struct csum_state *css)
+{
+	css->odd = 0;
+	css->sum = 0;
+	css->tmp = 0;
+}
+
+
+void
+csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
+{
+	if (len == 0)
+		return;
+
+	if (css->odd) {
+		css->sum += (css->tmp << 8) + p[0];
+		if (css->sum > 0xFFFF) {
+			css->sum += 1;
+			css->sum &= 0xFFFF;
+		}
+		css->odd = 0;
+		len--;
+		p++;
+	}
+
+	for ( ; len > 1; len -= 2, p +=2 ) {
+		css->sum  += (p[0] << 8) + p[1];
+		if (css->sum > 0xFFFF) {
+			css->sum += 1;
+			css->sum &= 0xFFFF;
+		}
+	}
+
+	if (len == 1){
+		css->tmp = p[0];
+		css->odd = 1;
+	}
+}
+
+
+uint16_t
+csum_get(struct csum_state *css)
+{
+	char pad = 0;
+
+	csum_update(&pad, 1, css);
+	return css->sum;
+}
+
+uint16_t
+csum_buf(uint8_t *p, uint32_t len)
+{
+	struct csum_state css;
+
+	csum_init(&css);
+	csum_update(p, len, &css);
+	return csum_get(&css);
+
+}
+
+/*
+ * routines to write data to the output file
+ */
+int
+write_out_data(FILE *outfile, uint8_t *data, size_t len,
+		struct csum_state *css)
+{
+	errno = 0;
+
+	fwrite(data, len, 1, outfile);
+	if (errno) {
+		ERR("unable to write output file");
+		return -1;
+	}
+
+	if (css) {
+		csum_update(data, len, css);
+	}
+
+	return 0;
+}
+
+
+int
+write_out_padding(FILE *outfile, size_t len, uint8_t padc,
+		 struct csum_state *css)
+{
+	uint8_t buf[512];
+	size_t buflen = sizeof(buf);
+
+	memset(buf, padc, buflen);
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		if (write_out_data(outfile, buf, buflen, css))
+			return -1;
+
+		len -= buflen;
+	}
+
+	return 0;
+}
+
+
+int
+write_out_data_align(FILE *outfile, uint8_t *data, size_t len, size_t align,
+		struct csum_state *css)
+{
+	size_t padlen;
+	int res;
+
+	res = write_out_data(outfile, data, len, css);
+	if (res)
+		return res;
+
+	padlen = ALIGN(len,align) - len;
+	res = write_out_padding(outfile, padlen, 0xFF, css);
+
+	return res;
+}
+
+
+int
+write_out_header(FILE *outfile, struct zyn_rombin_hdr *hdr)
+{
+	struct zyn_rombin_hdr t;
+
+	errno = 0;
+	if (fseek(outfile, 0, SEEK_SET) != 0) {
+		ERRS("fseek failed on output file");
+		return -1;
+	}
+
+	/* setup temporary header fields */
+	memset(&t, 0, sizeof(t));
+	t.addr = HOST_TO_BE32(hdr->addr);
+	memcpy(&t.sig, ROMBIN_SIGNATURE, ROMBIN_SIG_LEN);
+	t.type = hdr->type;
+	t.flags = hdr->flags;
+	t.osize = HOST_TO_BE32(hdr->osize);
+	t.csize = HOST_TO_BE32(hdr->csize);
+	t.ocsum = HOST_TO_BE16(hdr->ocsum);
+	t.ccsum = HOST_TO_BE16(hdr->ccsum);
+	t.mmap_addr = HOST_TO_BE32(hdr->mmap_addr);
+
+	DBG(2, "hdr.addr      = 0x%08x", hdr->addr);
+	DBG(2, "hdr.type      = 0x%02x", hdr->type);
+	DBG(2, "hdr.osize     = 0x%08x", hdr->osize);
+	DBG(2, "hdr.csize     = 0x%08x", hdr->csize);
+	DBG(2, "hdr.flags     = 0x%02x", hdr->flags);
+	DBG(2, "hdr.ocsum     = 0x%04x", hdr->ocsum);
+	DBG(2, "hdr.ccsum     = 0x%04x", hdr->ccsum);
+	DBG(2, "hdr.mmap_addr = 0x%08x", hdr->mmap_addr);
+
+	return write_out_data(outfile, (uint8_t *)&t, sizeof(t), NULL);
+}
+
+
+int
+write_out_mmap(FILE *outfile, struct fw_mmap *mmap, struct csum_state *css)
+{
+	struct zyn_mmt_hdr *mh;
+	uint8_t buf[MMAP_DATA_SIZE];
+	uint32_t user_size;
+	char *data;
+	int res;
+
+	memset(buf, 0, sizeof(buf));
+
+	mh = (struct zyn_mmt_hdr *)buf;
+
+	/* TODO: needs to recreate the memory map too? */
+	mh->count=0;
+
+	/* Build user data section */
+	data = buf+sizeof(*mh);
+	data += sprintf(data, "Vendor 1 %d", board->vendor);
+	*data++ = '\0';
+	data += sprintf(data, "Model 1 %d", BE16_TO_HOST(board->model));
+	*data++ = '\0';
+	/* TODO: make hardware version configurable? */
+	data += sprintf(data, "HwVerRange 2 %d %d", 0, 0);
+	*data++ = '\0';
+
+	user_size = (uint8_t *)data - buf;
+	mh->user_start= HOST_TO_BE32(mmap->addr+sizeof(*mh));
+	mh->user_end= HOST_TO_BE32(mmap->addr+user_size);
+	mh->csum = HOST_TO_BE16(csum_buf(buf+sizeof(*mh), user_size));
+
+	res = write_out_data(outfile, buf, sizeof(buf), css);
+
+	return res;
+}
+
+
+int
+block_stat_file(struct fw_block *block)
+{
+	struct stat st;
+	int res;
+
+	if (block->file_name == NULL)
+		return 0;
+
+	res = stat(block->file_name, &st);
+	if (res){
+		ERRS("stat failed on %s", block->file_name);
+		return res;
+	}
+
+	block->file_size = st.st_size;
+	return 0;
+}
+
+
+int
+read_magic(uint16_t *magic)
+{
+	FILE *f;
+	int res;
+
+	errno = 0;
+	f = fopen(bootext_block->file_name,"r");
+	if (errno) {
+		ERRS("unable to open file: %s", bootext_block->file_name);
+		return -1;
+	}
+
+	errno = 0;
+	fread(magic, 2, 1, f);
+	if (errno != 0) {
+		ERRS("unable to read from file: %s", bootext_block->file_name);
+		res = -1;
+		goto err;
+	}
+
+	res = 0;
+
+err:
+	fclose(f);
+	return res;
+}
+
+
+int
+write_out_file(FILE *outfile, char *name, size_t len, struct csum_state *css)
+{
+	char buf[FILE_BUF_LEN];
+	size_t buflen = sizeof(buf);
+	FILE *f;
+	int res;
+
+	DBG(2, "writing out file, name=%s, len=%zu",
+		name, len);
+
+	errno = 0;
+	f = fopen(name,"r");
+	if (errno) {
+		ERRS("unable to open file: %s", name);
+		return -1;
+	}
+
+	while (len > 0) {
+		if (len < buflen)
+			buflen = len;
+
+		/* read data from source file */
+		errno = 0;
+		fread(buf, buflen, 1, f);
+		if (errno != 0) {
+			ERRS("unable to read from file: %s",name);
+			res = -1;
+			break;
+		}
+
+		res = write_out_data(outfile, buf, buflen, css);
+		if (res)
+			break;
+
+		len -= buflen;
+	}
+
+	fclose(f);
+	return res;
+}
+
+
+int
+write_out_block(FILE *outfile, struct fw_block *block, struct csum_state *css)
+{
+	int res;
+
+	if (block == NULL)
+		return 0;
+
+	if (block->file_name == NULL)
+		return 0;
+
+	if (block->file_size == 0)
+		return 0;
+
+	res = write_out_file(outfile, block->file_name,
+			block->file_size, css);
+	return res;
+}
+
+
+int
+write_out_image(FILE *outfile)
+{
+	struct fw_block *block;
+	struct fw_mmap mmap;
+	struct zyn_rombin_hdr hdr;
+	struct csum_state css;
+	int i, res;
+	uint32_t offset;
+	uint32_t padlen;
+	uint16_t csum;
+	uint16_t t;
+
+	/* setup header fields */
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.addr = board->code_start;
+	hdr.type = OBJECT_TYPE_BOOTEXT;
+	hdr.flags = ROMBIN_FLAG_OCSUM;
+
+	offset = board->romio_offs;
+
+	res = write_out_header(outfile, &hdr);
+	if (res)
+		return res;
+
+	offset += sizeof(hdr);
+
+	csum_init(&css);
+	res = write_out_block(outfile, bootext_block, &css);
+	if (res)
+		return res;
+
+	offset += bootext_block->file_size;
+	if (offset > (board->romio_offs + board->bootext_size)) {
+		ERR("bootext file '%s' is too big", bootext_block->file_name);
+		return -1;
+	}
+
+	padlen = ALIGN(offset, MMAP_ALIGN) - offset;
+	res = write_out_padding(outfile, padlen, 0xFF, &css);
+	if (res)
+		return res;
+
+	offset += padlen;
+
+	mmap.addr = board->flash_base + offset;
+	res = write_out_mmap(outfile, &mmap, &css);
+	if (res)
+		return res;
+
+	offset += MMAP_DATA_SIZE;
+
+	if ((offset - board->romio_offs) < board->bootext_size) {
+		padlen = board->romio_offs + board->bootext_size - offset;
+		res = write_out_padding(outfile, padlen, 0xFF, &css);
+		if (res)
+			return res;
+		offset += padlen;
+
+		DBG(2, "bootext end at %08x", offset);
+	}
+
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		if (block->type == BLOCK_TYPE_BOOTEXT)
+			continue;
+
+		padlen = ALIGN(offset, block->align) - offset;
+		res = write_out_padding(outfile, padlen, 0xFF, &css);
+		if (res)
+			return res;
+		offset += padlen;
+
+		res = write_out_block(outfile, block, &css);
+		if (res)
+			return res;
+		offset += block->file_size;
+	}
+
+	padlen = ALIGN(offset, 4) - offset;
+	res = write_out_padding(outfile, padlen, 0xFF, &css);
+	if (res)
+		return res;
+	offset += padlen;
+
+	csum = csum_get(&css);
+	hdr.mmap_addr = mmap.addr;
+	hdr.osize = 2;
+
+	res = read_magic(&hdr.ocsum);
+	if (res)
+		return res;
+	hdr.ocsum = BE16_TO_HOST(hdr.ocsum);
+
+	if (csum <= hdr.ocsum)
+		t = hdr.ocsum - csum;
+	else
+		t = hdr.ocsum - csum - 1;
+
+	DBG(2, "ocsum=%04x, csum=%04x, fix=%04x", hdr.ocsum, csum, t);
+
+	t = HOST_TO_BE16(t);
+	res = write_out_data(outfile, (uint8_t *)&t, 2, NULL);
+	if (res)
+		return res;
+
+
+	res = write_out_header(outfile, &hdr);
+
+	return res;
+}
+
+
+struct board_info *
+find_board(char *name)
+{
+	struct board_info *ret;
+	struct board_info *board;
+
+	ret = NULL;
+	for (board = boards; board->name != NULL; board++){
+		if (strcasecmp(name, board->name) == 0) {
+			ret = board;
+			break;
+		}
+	};
+
+	return ret;
+}
+
+
+int
+parse_opt_board(char ch, char *arg)
+{
+
+	DBG(1,"parsing board option: -%c %s", ch, arg);
+
+	if (board != NULL) {
+		ERR("only one board option allowed");
+		return -1;
+	}
+
+	if (required_arg(ch, arg))
+		return -1;
+
+	board = find_board(arg);
+	if (board == NULL){
+		ERR("invalid/unknown board specified: %s", arg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int
+parse_opt_ofname(char ch, char *arg)
+{
+
+	if (ofname != NULL) {
+		ERR("only one output file allowed");
+		return -1;
+	}
+
+	if (required_arg(ch, arg))
+		return -1;
+
+	ofname = arg;
+
+	return 0;
+}
+
+
+int
+parse_opt_block(char ch, char *arg)
+{
+	char buf[MAX_ARG_LEN];
+	char *argv[MAX_ARG_COUNT];
+	int argc;
+	char *p;
+	struct fw_block *block;
+	int i;
+
+	if ( num_blocks >= MAX_NUM_BLOCKS ) {
+		ERR("too many blocks specified");
+		return -1;
+	}
+
+	block = &blocks[num_blocks++];
+
+	/* setup default field values */
+	block->padc = 0xFF;
+
+	switch(ch) {
+	case 'b':
+		if (bootext_block) {
+			ERR("only one boot extension block allowed");
+			break;
+		}
+		block->type = BLOCK_TYPE_BOOTEXT;
+		bootext_block = block;
+		break;
+	case 'r':
+		block->type = BLOCK_TYPE_RAW;
+		break;
+	}
+
+	argc = parse_arg(arg, buf, argv);
+
+	i = 0;
+	p = argv[i++];
+	if (is_empty_arg(p)) {
+		ERR("no file specified in %s", arg);
+		return -1;
+	} else {
+		block->file_name = strdup(p);
+		if (block->file_name == NULL) {
+			ERR("not enough memory");
+			return -1;
+		}
+	}
+
+	if (block->type == BLOCK_TYPE_BOOTEXT)
+		return 0;
+
+	p = argv[i++];
+	if (!is_empty_arg(p)) {
+		if (str2u32(p, &block->align) != 0) {
+			ERR("invalid block align in %s", arg);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int
+calc_block_offsets(int type, uint32_t *offset)
+{
+	struct fw_block *block;
+	uint32_t next_offs;
+	uint32_t avail;
+	int i, res;
+
+	DBG(1,"calculating block offsets, starting with %" PRIu32,
+		*offset);
+
+	res = 0;
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+
+		if (block->type != type)
+			continue;
+
+		next_offs = ALIGN(*offset, block->align);
+		avail = board->flash_size - next_offs;
+		if (block->file_size > avail) {
+			ERR("file %s is too big, offset = %u, size=%u,"
+				" avail = %u, align = %u", block->file_name,
+				(unsigned)next_offs,
+				(unsigned)block->file_size,
+				(unsigned)avail,
+				(unsigned)block->align);
+			res = -1;
+			break;
+		}
+
+		block->padlen = next_offs - *offset;
+		*offset += block->file_size;
+	}
+
+	return res;
+}
+
+int
+process_blocks(void)
+{
+	struct fw_block *block;
+	uint32_t offset;
+	int i;
+	int res;
+
+	/* collecting file stats */
+	for (i = 0; i < num_blocks; i++) {
+		block = &blocks[i];
+		res = block_stat_file(block);
+		if (res)
+			return res;
+	}
+
+	offset = board->romio_offs + bootext_block->file_size;
+	res = calc_block_offsets(BLOCK_TYPE_RAW, &offset);
+
+	return res;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	int optinvalid = 0;   /* flag for invalid option */
+	int c;
+	int res = EXIT_FAILURE;
+
+	FILE *outfile;
+
+	progname=basename(argv[0]);
+
+	opterr = 0;  /* could not print standard getopt error messages */
+	while ( 1 ) {
+		optinvalid = 0;
+
+		c = getopt(argc, argv, "b:B:ho:r:v");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'b':
+		case 'r':
+			optinvalid = parse_opt_block(c,optarg);
+			break;
+		case 'B':
+			optinvalid = parse_opt_board(c,optarg);
+			break;
+		case 'o':
+			optinvalid = parse_opt_ofname(c,optarg);
+			break;
+		case 'v':
+			verblevel++;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			optinvalid = 1;
+			break;
+		}
+		if (optinvalid != 0 ) {
+			ERR("invalid option: -%c", optopt);
+			goto out;
+		}
+	}
+
+	if (board == NULL) {
+		ERR("no board specified");
+		goto out;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto out;
+	}
+
+	if (optind < argc) {
+		ERR("invalid option: %s", argv[optind]);
+		goto out;
+	}
+
+	if (process_blocks() != 0) {
+		goto out;
+	}
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto out;
+	}
+
+	if (write_out_image(outfile) != 0)
+		goto out_flush;
+
+	DBG(1,"Image file %s completed.", ofname);
+
+	res = EXIT_SUCCESS;
+
+out_flush:
+	fflush(outfile);
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+out:
+	return res;
+}
diff --git a/tools/firmware-utils/src/motorola-bin.c b/tools/firmware-utils/src/motorola-bin.c
new file mode 100644
index 0000000000..fecb4ce95b
--- /dev/null
+++ b/tools/firmware-utils/src/motorola-bin.c
@@ -0,0 +1,227 @@
+/*
+ * motorola-bin.c
+ *
+ * Copyright (C) 2005-2006 Mike Baker,
+ *                         Imre Kaloz <kaloz@openwrt.org>
+ *                         D. Hugh Redelmeier
+ *                         OpenWrt.org
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/*
+ * Motorola's firmware flashing code requires an extra header.
+ * The header is eight bytes (see struct motorola below).
+ * This program will take a firmware file and create a new one
+ * with this header:
+ *	motorola-bin --wr850g WR850G_V403.stripped.trx WR850G_V403.trx
+ *
+ * Note: Motorola's firmware is distributed with this header.
+ * If you need to flash Motorola firmware on a router running OpenWRT,
+ * you will to remove this header.  Use the --strip flag:
+ *	motorola-bin --strip WR850G_V403.trx WR850G_V403.stripped.trx
+ */
+
+/*
+ * February 1, 2006
+ *
+ * Add support for for creating WA840G and WE800G images
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#define BPB 8 /* bits/byte */
+
+static uint32_t crc32[1<<BPB];
+
+static void init_crc32()
+{
+	const uint32_t poly = ntohl(0x2083b8ed);
+	int n;
+
+	for (n = 0; n < 1<<BPB; n++) {
+		uint32_t crc = n;
+		int bit;
+
+		for (bit = 0; bit < BPB; bit++)
+			crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+		crc32[n] = crc;
+	}
+}
+
+static uint32_t crc32buf(unsigned char *buf, size_t len)
+{
+	uint32_t crc = 0xFFFFFFFF;
+
+	for (; len; len--, buf++)
+		crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
+	return crc;
+}
+
+struct motorola {
+	uint32_t crc;	// crc32 of the remainder
+	uint32_t flags;	// unknown, 105770*
+};
+
+static const struct model {
+	char digit;	/* a digit signifying model (historical) */
+	const char *name;
+	uint32_t flags;
+} models[] = {
+	{ '1', "WR850G", 0x10577050LU },
+	{ '2', "WA840G", 0x10577040LU },
+	{ '3', "WE800G", 0x10577000LU },
+	{ '\0', NULL, 0 }
+};
+
+static void usage(const char *) __attribute__ (( __noreturn__ ));
+
+static void usage(const char *mess)
+{
+	const struct model *m;
+
+	fprintf(stderr, "Error: %s\n", mess);
+	fprintf(stderr, "Usage: motorola-bin -device|--strip infile outfile\n");
+	fprintf(stderr, "Known devices: ");
+
+	for (m = models; m->digit != '\0'; m++)
+		fprintf(stderr, " %c - %s", m->digit, m->name);
+
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	off_t len;	// of original firmware
+	int fd;
+	void *trx;	// pointer to original firmware (mmmapped)
+	struct motorola *firmware;	// pionter to prefix + copy of original firmware
+	uint32_t flags;
+
+	// verify parameters
+
+	if (argc != 4)
+		usage("wrong number of arguments");
+
+	// mmap trx file
+	if ((fd = open(argv[2], O_RDONLY))  < 0
+	|| (len = lseek(fd, 0, SEEK_END)) < 0
+	|| (trx = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
+	|| close(fd) < 0)
+	{
+		fprintf(stderr, "Error loading file %s: %s\n", argv[2], strerror(errno));
+		exit(1);
+	}
+
+	init_crc32();
+
+	if (strcmp(argv[1], "--strip") == 0)
+	{
+		const char *ugh = NULL;
+
+		if (len < sizeof(struct motorola)) {
+			ugh = "input file too short";
+		} else {
+			const struct model *m;
+
+			firmware = trx;
+			if (htonl(crc32buf(trx + offsetof(struct motorola, flags), len - offsetof(struct motorola, flags))) != firmware->crc)
+				ugh = "Invalid CRC";
+			for (m = models; ; m++) {
+				if (m->digit == '\0') {
+					if (ugh == NULL)
+						ugh = "unrecognized flags field";
+					break;
+				}
+				if (firmware->flags == htonl(m->flags)) {
+					fprintf(stderr, "Firmware for Motorola %s\n", m->name);
+					break;
+				}
+			}
+		}
+
+		if (ugh != NULL) {
+			fprintf(stderr, "%s\n", ugh);
+			exit(3);
+		} else {
+			// all is well, write the file without the prefix
+			if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
+			|| write(fd, trx + sizeof(struct motorola), len - sizeof(struct motorola)) !=  len - sizeof(struct motorola)
+			|| close(fd) < 0)
+			{
+				fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno));
+				exit(2);
+			}
+		}
+		
+	} else {
+		// setup the firmware flags magic number
+		const struct model *m;
+		const char *df = argv[1];
+
+		if (*df != '-')
+			usage("first argument must start with -");
+		if (*++df == '-')
+			++df;	/* allow but don't require second - */
+
+		for (m = models; ; m++) {
+			if (m->digit == '\0')
+				usage("unrecognized device specified");
+			if ((df[0] == m->digit && df[1] == '\0') || strcasecmp(df, m->name) == 0) {
+				flags = m->flags;
+				break;
+			}
+		}
+
+
+		// create a firmware image in memory
+		// and copy the trx to it
+		firmware = malloc(sizeof(struct motorola) + len);
+		memcpy(&firmware[1], trx, len);
+
+		// setup the motorola headers
+		firmware->flags = htonl(flags);
+
+		// CRC of flags + firmware
+		firmware->crc = htonl(crc32buf((unsigned char *)&firmware->flags, sizeof(firmware->flags) + len));
+
+		// write the firmware
+		if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0
+		|| write(fd, firmware, sizeof(struct motorola) + len) != sizeof(struct motorola) + len
+		|| close(fd) < 0)
+		{
+			fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno));
+			exit(2);
+		}
+
+		free(firmware);
+	}
+
+	munmap(trx,len);
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/myloader.h b/tools/firmware-utils/src/myloader.h
new file mode 100644
index 0000000000..7be1d49369
--- /dev/null
+++ b/tools/firmware-utils/src/myloader.h
@@ -0,0 +1,176 @@
+/*
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef _MYLOADER_H_
+#define _MYLOADER_H_
+
+/*
+ * Firmware file format:
+ *
+ *	<header>
+ *	[<block descriptor 0>]
+ *	...
+ *	[<block descriptor n>]
+ *	<null block descriptor>
+ *	[<block data 0>]
+ *	...
+ *	[<block data n>]
+ *
+ *
+ */
+
+/* Myloader specific magic numbers */
+#define MYLO_MAGIC_FIRMWARE	0x4C594D00
+#define MYLO_MAGIC_20021103	0x20021103
+#define MYLO_MAGIC_20021107	0x20021107
+
+#define MYLO_MAGIC_SYS_PARAMS	MYLO_MAGIC_20021107
+#define MYLO_MAGIC_PARTITIONS	MYLO_MAGIC_20021103
+#define MYLO_MAGIC_BOARD_PARAMS	MYLO_MAGIC_20021103
+
+/*
+ * Addresses of the data structures provided by MyLoader
+ */
+#define MYLO_MIPS_SYS_PARAMS	0x80000800	/* System Parameters */
+#define MYLO_MIPS_BOARD_PARAMS	0x80000A00	/* Board Parameters */
+#define MYLO_MIPS_PARTITIONS	0x80000C00	/* Partition Table */
+#define MYLO_MIPS_BOOT_PARAMS	0x80000E00	/* Boot Parameters */
+
+/* Vendor ID's (seems to be same as the PCI vendor ID's) */
+#define VENID_COMPEX		0x11F6
+
+/* Devices based on the ADM5120 */
+#define DEVID_COMPEX_NP27G	0x0078
+#define DEVID_COMPEX_NP28G	0x044C
+#define DEVID_COMPEX_NP28GHS	0x044E
+#define DEVID_COMPEX_WP54Gv1C	0x0514
+#define DEVID_COMPEX_WP54G	0x0515
+#define DEVID_COMPEX_WP54AG	0x0546
+#define DEVID_COMPEX_WPP54AG	0x0550
+#define DEVID_COMPEX_WPP54G	0x0555
+
+/* Devices based on the Atheros AR2317 */
+#define DEVID_COMPEX_NP25G	0x05e6
+#define DEVID_COMPEX_WPE53G	0x05dc
+
+/* Devices based on the Atheros AR71xx */
+#define DEVID_COMPEX_WP543	0x0640
+#define DEVID_COMPEX_WPE72	0x0672
+
+/* Devices based on the IXP422 */
+#define DEVID_COMPEX_WP18	0x047E
+#define DEVID_COMPEX_NP18A	0x0489
+
+/* Other devices */
+#define DEVID_COMPEX_NP26G8M	0x03E8
+#define DEVID_COMPEX_NP26G16M	0x03E9
+
+struct mylo_fw_header {
+	uint32_t	magic;	/* must be MYLO_MAGIC_FIRMWARE */
+	uint32_t	crc;	/* CRC of the whole firmware */
+	uint32_t	res0;	/* unknown/unused */
+	uint32_t	res1;	/* unknown/unused */
+	uint16_t	vid;	/* vendor ID */
+	uint16_t	did;	/* device ID */
+	uint16_t	svid;	/* sub vendor ID */
+	uint16_t	sdid;	/* sub device ID */
+	uint32_t	rev;	/* device revision */
+	uint32_t	fwhi;	/* FIXME: firmware version high? */
+	uint32_t	fwlo;	/* FIXME: firmware version low? */
+	uint32_t	flags;	/* firmware flags */
+};
+
+#define FW_FLAG_BOARD_PARAMS_WP	0x01 /* board parameters are write protected */
+#define FW_FLAG_BOOT_SECTOR_WE	0x02 /* enable of write boot sectors (below 64K) */
+
+struct mylo_fw_blockdesc {
+	uint32_t	type;	/* block type */
+	uint32_t	addr;	/* relative address to flash start */
+	uint32_t	dlen;	/* size of block data in bytes */
+	uint32_t	blen;	/* total size of block in bytes */
+};
+
+#define FW_DESC_TYPE_UNUSED	0
+#define FW_DESC_TYPE_USED	1
+
+struct mylo_partition {
+	uint16_t	flags;	/* partition flags */
+	uint16_t	type;	/* type of the partition */
+	uint32_t	addr;	/* relative address of the partition from the
+				   flash start */
+	uint32_t	size;	/* size of the partition in bytes */
+	uint32_t	param;	/* if this is the active partition, the
+				   MyLoader load code to this address */
+};
+
+#define PARTITION_FLAG_ACTIVE	0x8000 /* this is the active partition,
+					* MyLoader loads firmware from here */
+#define PARTITION_FLAG_ISRAM	0x2000 /* FIXME: this is a RAM partition? */
+#define PARTIIION_FLAG_RAMLOAD	0x1000 /* FIXME: load this partition into the RAM? */
+#define PARTITION_FLAG_PRELOAD	0x0800 /* the partition data preloaded to RAM
+					* before decompression */
+#define PARTITION_FLAG_LZMA	0x0100 /* the partition data compressed with LZMA */
+#define PARTITION_FLAG_HAVEHDR  0x0002 /* the partition data have a header */
+
+#define PARTITION_TYPE_FREE	0
+#define PARTITION_TYPE_USED	1
+
+#define MYLO_MAX_PARTITIONS	8	/* maximum number of partitions in the
+					   partition table */
+
+struct mylo_partition_table {
+	uint32_t	magic;	/* must be MYLO_MAGIC_PARTITIONS */
+	uint32_t	res0;	/* unknown/unused */
+	uint32_t	res1;	/* unknown/unused */
+	uint32_t 	res2;	/* unknown/unused */
+	struct mylo_partition partitions[MYLO_MAX_PARTITIONS];
+};
+
+struct mylo_partition_header {
+	uint32_t	len;	/* length of the partition data */
+	uint32_t	crc;	/* CRC value of the partition data */
+};
+
+struct mylo_system_params {
+	uint32_t	magic;	/* must be MYLO_MAGIC_SYS_PARAMS */
+	uint32_t	res0;
+	uint32_t	res1;
+	uint32_t	mylo_ver;
+	uint16_t	vid;	/* Vendor ID */
+	uint16_t	did;	/* Device ID */
+	uint16_t	svid;	/* Sub Vendor ID */
+	uint16_t	sdid;	/* Sub Device ID */
+	uint32_t	rev;	/* device revision */
+	uint32_t	fwhi;
+	uint32_t	fwlo;
+	uint32_t	tftp_addr;
+	uint32_t	prog_start;
+	uint32_t	flash_size;	/* Size of boot FLASH in bytes */
+	uint32_t	dram_size;	/* Size of onboard RAM in bytes */
+};
+
+
+struct mylo_eth_addr {
+	uint8_t	mac[6];
+	uint8_t	csum[2];
+};
+
+#define MYLO_ETHADDR_COUNT	8	/* maximum number of ethernet address
+					   in the board parameters */
+
+struct mylo_board_params {
+	uint32_t	magic;	/* must be MYLO_MAGIC_BOARD_PARAMS */
+	uint32_t	res0;
+	uint32_t	res1;
+	uint32_t	res2;
+	struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT];
+};
+
+#endif /* _MYLOADER_H_*/
diff --git a/tools/firmware-utils/src/nand_ecc.c b/tools/firmware-utils/src/nand_ecc.c
new file mode 100644
index 0000000000..58fb6ce0db
--- /dev/null
+++ b/tools/firmware-utils/src/nand_ecc.c
@@ -0,0 +1,204 @@
+/*
+ * calculate ecc code for nand flash
+ *
+ * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#define DEF_NAND_PAGE_SIZE   2048
+#define DEF_NAND_OOB_SIZE     64
+#define DEF_NAND_ECC_OFFSET   0x28
+
+static int page_size = DEF_NAND_PAGE_SIZE;
+static int oob_size = DEF_NAND_OOB_SIZE;
+static int ecc_offset = DEF_NAND_ECC_OFFSET;
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+	0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+	0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+	0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+	0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+	0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+	0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+	0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
+ * @dat:	raw data
+ * @ecc_code:	buffer for ECC
+ */
+int nand_calculate_ecc(const uint8_t *dat,
+		       uint8_t *ecc_code)
+{
+	uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
+	int i;
+
+	/* Initialize variables */
+	reg1 = reg2 = reg3 = 0;
+
+	/* Build up column parity */
+	for(i = 0; i < 256; i++) {
+		/* Get CP0 - CP5 from table */
+		idx = nand_ecc_precalc_table[*dat++];
+		reg1 ^= (idx & 0x3f);
+
+		/* All bit XOR = 1 ? */
+		if (idx & 0x40) {
+			reg3 ^= (uint8_t) i;
+			reg2 ^= ~((uint8_t) i);
+		}
+	}
+
+	/* Create non-inverted ECC code from line parity */
+	tmp1  = (reg3 & 0x80) >> 0; /* B7 -> B7 */
+	tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
+	tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
+	tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
+	tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
+	tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
+	tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
+	tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
+
+	tmp2  = (reg3 & 0x08) << 4; /* B3 -> B7 */
+	tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
+	tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
+	tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
+	tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
+	tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
+	tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
+	tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
+
+	/* Calculate final ECC code */
+#ifdef CONFIG_MTD_NAND_ECC_SMC
+	ecc_code[0] = ~tmp2;
+	ecc_code[1] = ~tmp1;
+#else
+	ecc_code[0] = ~tmp1;
+	ecc_code[1] = ~tmp2;
+#endif
+	ecc_code[2] = ((~reg1) << 2) | 0x03;
+
+	return 0;
+}
+
+/*
+ *  usage: bb-nandflash-ecc    start_address  size
+ */
+void usage(const char *prog)
+{
+	fprintf(stderr, "Usage: %s [options] <input> <output>\n"
+		"Options:\n"
+		"    -p <pagesize>      NAND page size (default: %d)\n"
+		"    -o <oobsize>       NAND OOB size (default: %d)\n"
+		"    -e <offset>        NAND ECC offset (default: %d)\n"
+		"\n", prog, DEF_NAND_PAGE_SIZE, DEF_NAND_OOB_SIZE,
+		DEF_NAND_ECC_OFFSET);
+	exit(1);
+}
+
+/*start_address/size does not include oob
+  */
+int main(int argc, char **argv)
+{
+	uint8_t *page_data = NULL;
+	uint8_t *ecc_data;
+	int infd = -1, outfd = -1;
+	int ret = 1;
+	ssize_t bytes;
+	int ch;
+
+	while ((ch = getopt(argc, argv, "e:o:p:")) != -1) {
+		switch(ch) {
+		case 'p':
+			page_size = strtoul(optarg, NULL, 0);
+			break;
+		case 'o':
+			oob_size = strtoul(optarg, NULL, 0);
+			break;
+		case 'e':
+			ecc_offset = strtoul(optarg, NULL, 0);
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+	argc -= optind;
+	if (argc < 2)
+		usage(argv[0]);
+
+	argv += optind;
+
+	infd = open(argv[0], O_RDONLY, 0);
+	if (infd < 0) {
+		perror("open input file");
+		goto out;
+	}
+
+	outfd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
+	if (outfd < 0) {
+		perror("open output file");
+		goto out;
+	}
+
+	page_data = malloc(page_size + oob_size);
+
+	while ((bytes = read(infd, page_data, page_size)) == page_size) {
+		int j;
+
+		ecc_data = page_data + page_size + ecc_offset;
+		for (j = 0; j < page_size / 256; j++)
+		{
+			nand_calculate_ecc(page_data + j * 256, ecc_data);
+			ecc_data += 3;
+		}
+		write(outfd, page_data, page_size + oob_size);
+	}
+
+	ret = 0;
+out:
+	if (infd >= 0)
+		close(infd);
+	if (outfd >= 0)
+		close(outfd);
+	if (page_data)
+		free(page_data);
+	return ret;
+}
+
diff --git a/tools/firmware-utils/src/osbridge-crc.c b/tools/firmware-utils/src/osbridge-crc.c
new file mode 100644
index 0000000000..5fd236a074
--- /dev/null
+++ b/tools/firmware-utils/src/osbridge-crc.c
@@ -0,0 +1,309 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define HOST_TO_LE16(x)	(x)
+#  define HOST_TO_LE32(x)	(x)
+#  define LE16_TO_HOST(x)	(x)
+#  define LE32_TO_HOST(x)	(x)
+#else
+#  define HOST_TO_LE16(x)	bswap_16(x)
+#  define HOST_TO_LE32(x)	bswap_32(x)
+#  define LE16_TO_HOST(x)	bswap_16(x)
+#  define LE32_TO_HOST(x)	bswap_32(x)
+#endif
+
+uint32_t crc32buf(char *buf, size_t len);
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+	int res = EXIT_FAILURE;
+	int buflen;
+	int err;
+	struct stat st;
+	char *buf;
+	uint32_t *hdr;
+	uint32_t crc;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "i:o:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	buflen = st.st_size;
+	buf = malloc(buflen);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	errno = 0;
+	fread(buf, buflen, 1, infile);
+	if (errno != 0) {
+		ERRS("unable to read from file %s", ifname);
+		goto err_close_in;
+	}
+
+	crc = crc32buf(buf, buflen);
+	hdr = (uint32_t *)buf;
+	*hdr = HOST_TO_LE32(crc);
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto err_close_in;
+	}
+
+	errno = 0;
+	fwrite(buf, buflen, 1, outfile);
+	if (errno) {
+		ERRS("unable to write to file %s", ofname);
+		goto err_close_out;
+	}
+
+	res = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(outfile);
+
+ err_close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+
+ err_close_in:
+	fclose(infile);
+
+ err_free:
+	free(buf);
+
+ err:
+	return res;
+}
+
+/**********************************************************************/
+/* The following was grabbed and tweaked from the old snippets collection
+ * of public domain C code. */
+
+/**********************************************************************\
+|* Demonstration program to compute the 32-bit CRC used as the frame  *|
+|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *|
+|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *|
+|* protocol).  The 32-bit FCS was added via the Federal Register,     *|
+|* 1 June 1982, p.23798.  I presume but don't know for certain that   *|
+|* this polynomial is or will be included in CCITT V.41, which        *|
+|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *|
+|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *|
+|* errors by a factor of 10^-5 over 16-bit FCS.                       *|
+\**********************************************************************/
+
+/* Copyright (C) 1986 Gary S. Brown.  You may use this program, or
+   code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms.  The  */
+/* polynomial is                                                       */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in  */
+/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
+/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
+/* the MSB being 1.                                                    */
+
+/* Note that the usual hardware shift register implementation, which   */
+/* is what we're using (we're merely optimizing it by doing eight-bit  */
+/* chunks at a time) shifts bits into the lowest-order term.  In our   */
+/* implementation, that means shifting towards the right.  Why do we   */
+/* do it this way?  Because the calculated CRC must be transmitted in  */
+/* order from highest-order term to lowest-order term.  UARTs transmit */
+/* characters in order from LSB to MSB.  By storing the CRC this way,  */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part.  Reception works similarly.                  */
+
+/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
+/*                                                                     */
+/*  1. The table can be generated at runtime if desired; code to do so */
+/*     is shown later.  It might not be obvious, but the feedback      */
+/*     terms simply represent the results of eight shift/xor opera-    */
+/*     tions for all combinations of data and CRC register values.     */
+/*                                                                     */
+/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
+/*     be they sixteen or thirty-two bits wide.  You simply choose the */
+/*     appropriate table.  Alternatively, because the table can be     */
+/*     generated at runtime, you can start by generating the table for */
+/*     the polynomial in question and use exactly the same "updcrc",   */
+/*     if your application needn't simultaneously handle two CRC       */
+/*     polynomials.  (Note, however, that XMODEM is strange.)          */
+/*                                                                     */
+/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
+/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
+/*                                                                     */
+/*  4. The values must be right-shifted by eight bits by the "updcrc"  */
+/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
+/*     hardware you could probably optimize the shift in assembler by  */
+/*     using byte-swap instructions.                                   */
+
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+      uint32_t crc;
+
+      crc = 0xFFFFFFFF;
+
+      for ( ; len; --len, ++buf)
+      {
+            crc = UPDC32(*buf, crc);
+      }
+
+      return crc ^ 0xFFFFFFFF;
+}
+
diff --git a/tools/firmware-utils/src/oseama.c b/tools/firmware-utils/src/oseama.c
new file mode 100644
index 0000000000..4434b11162
--- /dev/null
+++ b/tools/firmware-utils/src/oseama.c
@@ -0,0 +1,556 @@
+/*
+ * oseama
+ *
+ * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "md5.h"
+
+#if !defined(__BYTE_ORDER)
+#error "Unknown byte order"
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_be32(x)	(x)
+#define be32_to_cpu(x)	(x)
+#define cpu_to_be16(x)	(x)
+#define be16_to_cpu(x)	(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_be32(x)	bswap_32(x)
+#define be32_to_cpu(x)	bswap_32(x)
+#define cpu_to_be16(x)	bswap_16(x)
+#define be16_to_cpu(x)	bswap_16(x)
+#else
+#error "Unsupported endianness"
+#endif
+
+#define SEAMA_MAGIC			0x5ea3a417
+
+struct seama_seal_header {
+	uint32_t magic;
+	uint16_t reserved;
+	uint16_t metasize;
+	uint32_t imagesize;
+} __attribute__ ((packed));
+
+struct seama_entity_header {
+	uint32_t magic;
+	uint16_t reserved;
+	uint16_t metasize;
+	uint32_t imagesize;
+	uint8_t md5[16];
+} __attribute__ ((packed));
+
+char *seama_path;
+int entity_idx = -1;
+char *out_path;
+
+static inline size_t oseama_min(size_t x, size_t y) {
+	return x < y ? x : y;
+}
+
+/**************************************************
+ * Info
+ **************************************************/
+
+static void oseama_info_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "e:")) != -1) {
+		switch (c) {
+		case 'e':
+			entity_idx = atoi(optarg);
+			break;
+		}
+	}
+}
+
+static int oseama_info_entities(FILE *seama) {
+	struct seama_entity_header hdr;
+	size_t bytes, metasize, imagesize;
+	uint8_t buf[1024];
+	char *end, *tmp;
+	int i = 0;
+	int err = 0;
+
+	while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
+		if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+			fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+			err =  -EINVAL;
+			goto err_out;
+		}
+		metasize = be16_to_cpu(hdr.metasize);
+		imagesize = be32_to_cpu(hdr.imagesize);
+
+		if (entity_idx >= 0 && i != entity_idx) {
+			fseek(seama, metasize + imagesize, SEEK_CUR);
+			i++;
+			continue;
+		}
+
+		if (metasize >= sizeof(buf)) {
+			fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
+			err =  -EINVAL;
+			goto err_out;
+		}
+
+		if (entity_idx < 0)
+			printf("\n");
+		printf("Entity offset:\t%ld\n", ftell(seama) - sizeof(hdr));
+		printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
+		printf("Meta size:\t%zd\n", metasize);
+		printf("Image size:\t%zd\n", imagesize);
+
+		bytes = fread(buf, 1, metasize, seama);
+		if (bytes != metasize) {
+			fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
+			err =  -EIO;
+			goto err_out;
+		}
+
+		end = (char *)&buf[metasize - 1];
+		*end = '\0';
+		for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
+			printf("Meta entry:\t%s\n", tmp);
+		}
+
+		fseek(seama, imagesize, SEEK_CUR);
+		i++;
+	}
+
+err_out:
+	return err;
+}
+
+static int oseama_info(int argc, char **argv) {
+	FILE *seama;
+	struct seama_seal_header hdr;
+	size_t bytes;
+	uint16_t metasize;
+	uint32_t imagesize;
+	uint8_t buf[1024];
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No Seama file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	seama_path = argv[2];
+
+	optind = 3;
+	oseama_info_parse_options(argc, argv);
+
+	seama = fopen(seama_path, "r");
+	if (!seama) {
+		fprintf(stderr, "Couldn't open %s\n", seama_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	bytes = fread(&hdr, 1, sizeof(hdr), seama);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", seama_path);
+		err =  -EIO;
+		goto err_close;
+	}
+	metasize = be16_to_cpu(hdr.metasize);
+	imagesize = be32_to_cpu(hdr.imagesize);
+
+	if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+		fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	if (metasize >= sizeof(buf)) {
+		fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	if (imagesize) {
+		fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	bytes = fread(buf, 1, metasize, seama);
+	if (bytes != metasize) {
+		fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
+		err =  -EIO;
+		goto err_close;
+	}
+
+	if (entity_idx < 0) {
+		char *end, *tmp;
+
+		printf("Meta size:\t%d\n", metasize);
+		printf("Image size:\t%d\n", imagesize);
+
+		end = (char *)&buf[metasize - 1];
+		*end = '\0';
+		for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
+			printf("Meta entry:\t%s\n", tmp);
+		}
+	}
+
+	oseama_info_entities(seama);
+
+err_close:
+	fclose(seama);
+out:
+	return err;
+}
+
+/**************************************************
+ * Create
+ **************************************************/
+
+static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) {
+	FILE *in;
+	size_t bytes;
+	ssize_t length = 0;
+	uint8_t buf[128];
+
+	in = fopen(in_path, "r");
+	if (!in) {
+		fprintf(stderr, "Couldn't open %s\n", in_path);
+		return -EACCES;
+	}
+
+	while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (fwrite(buf, 1, bytes, seama) != bytes) {
+			fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path);
+			length = -EIO;
+			break;
+		}
+		length += bytes;
+	}
+
+	fclose(in);
+
+	return length;
+}
+
+static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) {
+	uint8_t *buf;
+
+	buf = malloc(length);
+	if (!buf)
+		return -ENOMEM;
+	memset(buf, 0, length);
+
+	if (fwrite(buf, 1, length, seama) != length) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path);
+		return -EIO;
+	}
+
+	return length;
+}
+
+static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) {
+	if (curr_offset & (alignment - 1)) {
+		size_t length = alignment - (curr_offset % alignment);
+
+		return oseama_entity_append_zeros(seama, length);
+	}
+
+	return 0;
+}
+
+static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) {
+	struct seama_entity_header hdr = {};
+	uint8_t buf[128];
+	size_t length = imagesize;
+	size_t bytes;
+	MD5_CTX ctx;
+
+	fseek(seama, sizeof(hdr) + metasize, SEEK_SET);
+	MD5_Init(&ctx);
+	while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
+		MD5_Update(&ctx, buf, bytes);
+		length -= bytes;
+	}
+	MD5_Final(hdr.md5, &ctx);
+
+	hdr.magic = cpu_to_be32(SEAMA_MAGIC);
+	hdr.metasize = cpu_to_be16(metasize);
+	hdr.imagesize = cpu_to_be32(imagesize);
+
+	fseek(seama, 0, SEEK_SET);
+	bytes = fwrite(&hdr, 1, sizeof(hdr), seama);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int oseama_entity(int argc, char **argv) {
+	FILE *seama;
+	ssize_t sbytes;
+	size_t curr_offset = sizeof(struct seama_entity_header);
+	size_t metasize = 0, imagesize = 0;
+	int c;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No Seama file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	seama_path = argv[2];
+
+	seama = fopen(seama_path, "w+");
+	if (!seama) {
+		fprintf(stderr, "Couldn't open %s\n", seama_path);
+		err = -EACCES;
+		goto out;
+	}
+	fseek(seama, curr_offset, SEEK_SET);
+
+	optind = 3;
+	while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
+		switch (c) {
+		case 'm':
+			sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to write meta %s\n", optarg);
+			} else {
+				curr_offset += sbytes;
+				metasize += sbytes;
+			}
+
+			sbytes = oseama_entity_align(seama, curr_offset, 4);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to append zeros\n");
+			} else {
+				curr_offset += sbytes;
+				metasize += sbytes;
+			}
+
+			break;
+		case 'f':
+		case 'b':
+			break;
+		}
+	}
+
+	optind = 3;
+	while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
+		switch (c) {
+		case 'm':
+			break;
+		case 'f':
+			sbytes = oseama_entity_append_file(seama, optarg);
+			if (sbytes < 0) {
+				fprintf(stderr, "Failed to append file %s\n", optarg);
+			} else {
+				curr_offset += sbytes;
+				imagesize += sbytes;
+			}
+			break;
+		case 'b':
+			sbytes = strtol(optarg, NULL, 0) - curr_offset;
+			if (sbytes < 0) {
+				fprintf(stderr, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
+			} else {
+				sbytes = oseama_entity_append_zeros(seama, sbytes);
+				if (sbytes < 0) {
+					fprintf(stderr, "Failed to append zeros\n");
+				} else {
+					curr_offset += sbytes;
+					imagesize += sbytes;
+				}
+			}
+			break;
+		}
+		if (err)
+			break;
+	}
+
+	oseama_entity_write_hdr(seama, metasize, imagesize);
+
+	fclose(seama);
+out:
+	return err;
+}
+
+/**************************************************
+ * Extract
+ **************************************************/
+
+static void oseama_extract_parse_options(int argc, char **argv) {
+	int c;
+
+	while ((c = getopt(argc, argv, "e:o:")) != -1) {
+		switch (c) {
+		case 'e':
+			entity_idx = atoi(optarg);
+			break;
+		case 'o':
+			out_path = optarg;
+			break;
+		}
+	}
+}
+
+static int oseama_extract_entity(FILE *seama, FILE *out) {
+	struct seama_entity_header hdr;
+	size_t bytes, metasize, imagesize, length;
+	uint8_t buf[1024];
+	int i = 0;
+	int err = 0;
+
+	while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
+		if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
+			fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
+			err =  -EINVAL;
+			break;
+		}
+		metasize = be16_to_cpu(hdr.metasize);
+		imagesize = be32_to_cpu(hdr.imagesize);
+
+		if (i != entity_idx) {
+			fseek(seama, metasize + imagesize, SEEK_CUR);
+			i++;
+			continue;
+		}
+
+		fseek(seama, -sizeof(hdr), SEEK_CUR);
+
+		length = sizeof(hdr) + metasize + imagesize;
+		while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
+			if (fwrite(buf, 1, bytes, out) != bytes) {
+				fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
+				err = -EIO;
+				break;
+			}
+			length -= bytes;
+		}
+
+		if (length) {
+			fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length);
+			err = -EIO;
+			break;
+		}
+
+		break;
+	}
+
+	return err;
+}
+
+static int oseama_extract(int argc, char **argv) {
+	FILE *seama;
+	FILE *out;
+	struct seama_seal_header hdr;
+	size_t bytes;
+	uint16_t metasize;
+	int err = 0;
+
+	if (argc < 3) {
+		fprintf(stderr, "No Seama file passed\n");
+		err = -EINVAL;
+		goto out;
+	}
+	seama_path = argv[2];
+
+	optind = 3;
+	oseama_extract_parse_options(argc, argv);
+	if (entity_idx < 0) {
+		fprintf(stderr, "No entity specified\n");
+		err = -EINVAL;
+		goto out;
+	} else if (!out_path) {
+		fprintf(stderr, "No output file specified\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	seama = fopen(seama_path, "r");
+	if (!seama) {
+		fprintf(stderr, "Couldn't open %s\n", seama_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	out = fopen(out_path, "w");
+	if (!out) {
+		fprintf(stderr, "Couldn't open %s\n", out_path);
+		err = -EACCES;
+		goto err_close_seama;
+	}
+
+	bytes = fread(&hdr, 1, sizeof(hdr), seama);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", seama_path);
+		err =  -EIO;
+		goto err_close_out;
+	}
+	metasize = be16_to_cpu(hdr.metasize);
+
+	fseek(seama, metasize, SEEK_CUR);
+
+	oseama_extract_entity(seama, out);
+
+err_close_out:
+	fclose(out);
+err_close_seama:
+	fclose(seama);
+out:
+	return err;
+}
+
+/**************************************************
+ * Start
+ **************************************************/
+
+static void usage() {
+	printf("Usage:\n");
+	printf("\n");
+	printf("Info about Seama seal (container):\n");
+	printf("\toseama info <file> [options]\n");
+	printf("\t-e\t\t\t\tprint info about specified entity only\n");
+	printf("\n");
+	printf("Create Seama entity:\n");
+	printf("\toseama entity <file> [options]\n");
+	printf("\t-m meta\t\t\t\tmeta into to put in header\n");
+	printf("\t-f file\t\t\t\tappend content from file\n");
+	printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
+	printf("\n");
+	printf("Extract from Seama seal (container):\n");
+	printf("\toseama extract <file> [options]\n");
+	printf("\t-e\t\t\t\tindex of entity to extract\n");
+	printf("\t-o file\t\t\t\toutput file\n");
+}
+
+int main(int argc, char **argv) {
+	if (argc > 1) {
+		if (!strcmp(argv[1], "info"))
+			return oseama_info(argc, argv);
+		else if (!strcmp(argv[1], "entity"))
+			return oseama_entity(argc, argv);
+		else if (!strcmp(argv[1], "extract"))
+			return oseama_extract(argc, argv);
+	}
+
+	usage();
+	return 0;
+}
diff --git a/tools/firmware-utils/src/pc1crypt.c b/tools/firmware-utils/src/pc1crypt.c
new file mode 100644
index 0000000000..fe41b3dab5
--- /dev/null
+++ b/tools/firmware-utils/src/pc1crypt.c
@@ -0,0 +1,361 @@
+/*
+ *  Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  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.
+ *
+ *  This code was based on:
+ *	PC1 Cipher Algorithm ( Pukall Cipher 1 )
+ *	By Alexander PUKALL 1991
+ *	free code no restriction to use
+ *	please include the name of the Author in the final software
+ *	the Key is 128 bits
+ *	http://membres.lycos.fr/pc1/
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>     /* for unlink() */
+#include <libgen.h>
+#include <getopt.h>     /* for getopt() */
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+struct pc1_ctx {
+	unsigned short	ax;
+	unsigned short	bx;
+	unsigned short	cx;
+	unsigned short	dx;
+	unsigned short	si;
+	unsigned short	tmp;
+	unsigned short	x1a2;
+	unsigned short	x1a0[8];
+	unsigned short	res;
+	unsigned short	i;
+	unsigned short	inter;
+	unsigned short	cfc;
+	unsigned short	cfd;
+	unsigned short	compte;
+	unsigned char	cle[17];
+	short		c;
+};
+
+static void pc1_finish(struct pc1_ctx *pc1)
+{
+	/* erase all variables */
+	memset(pc1, 0, sizeof(struct pc1_ctx));
+}
+
+static void pc1_code(struct pc1_ctx *pc1)
+{
+	pc1->dx = pc1->x1a2 + pc1->i;
+	pc1->ax = pc1->x1a0[pc1->i];
+	pc1->cx = 0x015a;
+	pc1->bx = 0x4e35;
+
+	pc1->tmp = pc1->ax;
+	pc1->ax = pc1->si;
+	pc1->si = pc1->tmp;
+
+	pc1->tmp = pc1->ax;
+	pc1->ax = pc1->dx;
+	pc1->dx = pc1->tmp;
+
+	if (pc1->ax != 0) {
+		pc1->ax = pc1->ax * pc1->bx;
+	}
+
+	pc1->tmp = pc1->ax;
+	pc1->ax = pc1->cx;
+	pc1->cx = pc1->tmp;
+
+	if (pc1->ax != 0) {
+		pc1->ax = pc1->ax * pc1->si;
+		pc1->cx = pc1->ax + pc1->cx;
+	}
+
+	pc1->tmp = pc1->ax;
+	pc1->ax = pc1->si;
+	pc1->si = pc1->tmp;
+	pc1->ax = pc1->ax * pc1->bx;
+	pc1->dx = pc1->cx + pc1->dx;
+
+	pc1->ax = pc1->ax + 1;
+
+	pc1->x1a2 = pc1->dx;
+	pc1->x1a0[pc1->i] = pc1->ax;
+
+	pc1->res = pc1->ax ^ pc1->dx;
+	pc1->i = pc1->i + 1;
+}
+
+static void pc1_assemble(struct pc1_ctx *pc1)
+{
+	pc1->x1a0[0] = (pc1->cle[0] * 256) + pc1->cle[1];
+
+	pc1_code(pc1);
+	pc1->inter = pc1->res;
+
+	pc1->x1a0[1] = pc1->x1a0[0] ^ ((pc1->cle[2]*256) + pc1->cle[3]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->x1a0[2] = pc1->x1a0[1] ^ ((pc1->cle[4]*256) + pc1->cle[5]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->x1a0[3] = pc1->x1a0[2] ^ ((pc1->cle[6]*256) + pc1->cle[7]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->x1a0[4] = pc1->x1a0[3] ^ ((pc1->cle[8]*256) + pc1->cle[9]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->x1a0[5] = pc1->x1a0[4] ^ ((pc1->cle[10]*256) + pc1->cle[11]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->x1a0[6] = pc1->x1a0[5] ^ ((pc1->cle[12]*256) + pc1->cle[13]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->x1a0[7] = pc1->x1a0[6] ^ ((pc1->cle[14]*256) + pc1->cle[15]);
+	pc1_code(pc1);
+	pc1->inter = pc1->inter ^ pc1->res;
+
+	pc1->i = 0;
+}
+
+static unsigned char pc1_decrypt(struct pc1_ctx *pc1, short c)
+{
+	pc1_assemble(pc1);
+	pc1->cfc = pc1->inter >> 8;
+	pc1->cfd = pc1->inter & 255; /* cfc^cfd = random byte */
+
+	c = c ^ (pc1->cfc ^ pc1->cfd);
+	for (pc1->compte = 0; pc1->compte <= 15; pc1->compte++) {
+		/* we mix the plaintext byte with the key */
+		pc1->cle[pc1->compte] = pc1->cle[pc1->compte] ^ c;
+	}
+
+	return c;
+}
+
+static unsigned char pc1_encrypt(struct pc1_ctx *pc1, short c)
+{
+	pc1_assemble(pc1);
+	pc1->cfc = pc1->inter >> 8;
+	pc1->cfd = pc1->inter & 255; /* cfc^cfd = random byte */
+
+	for (pc1->compte = 0; pc1->compte <= 15; pc1->compte++) {
+		/* we mix the plaintext byte with the key */
+		pc1->cle[pc1->compte] = pc1->cle[pc1->compte] ^ c;
+	}
+	c = c ^ (pc1->cfc ^ pc1->cfd);
+
+	return c;
+}
+
+static void pc1_init(struct pc1_ctx *pc1)
+{
+	memset(pc1, 0, sizeof(struct pc1_ctx));
+
+	/* ('Remsaalps!123456') is the key used, you can change it */
+	strcpy(pc1->cle, "Remsaalps!123456");
+}
+
+static void pc1_decrypt_buf(struct pc1_ctx *pc1, unsigned char *buf,
+			    unsigned len)
+{
+	unsigned i;
+
+	for (i = 0; i < len; i++)
+		buf[i] = pc1_decrypt(pc1, buf[i]);
+}
+
+static void pc1_encrypt_buf(struct pc1_ctx *pc1, unsigned char *buf,
+			    unsigned len)
+{
+	unsigned i;
+
+	for (i = 0; i < len; i++)
+		buf[i] = pc1_encrypt(pc1, buf[i]);
+}
+
+/*
+ * Globals
+ */
+static char *ifname;
+static char *progname;
+static char *ofname;
+static int decrypt;
+
+/*
+ * Message macros
+ */
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+void usage(int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	struct board_info *board;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream,
+"\n"
+"Options:\n"
+"  -d              decrypt instead of encrypt"
+"  -i <file>       read input from the file <file>\n"
+"  -o <file>       write output to the file <file>\n"
+"  -h              show this screen\n"
+	);
+
+	exit(status);
+}
+
+#define BUFSIZE		(64 * 1024)
+
+int main(int argc, char *argv[])
+{
+	struct pc1_ctx pc1;
+	int res = EXIT_FAILURE;
+	int err;
+	struct stat st;
+	char *buf;
+	unsigned total;
+
+	FILE *outfile, *infile;
+
+	progname = basename(argv[0]);
+
+	while ( 1 ) {
+		int c;
+
+		c = getopt(argc, argv, "di:o:h");
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'd':
+			decrypt = 1;
+			break;
+		case 'i':
+			ifname = optarg;
+			break;
+		case 'o':
+			ofname = optarg;
+			break;
+		case 'h':
+			usage(EXIT_SUCCESS);
+			break;
+		default:
+			usage(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (ifname == NULL) {
+		ERR("no input file specified");
+		goto err;
+	}
+
+	if (ofname == NULL) {
+		ERR("no output file specified");
+		goto err;
+	}
+
+	err = stat(ifname, &st);
+	if (err){
+		ERRS("stat failed on %s", ifname);
+		goto err;
+	}
+
+	total = st.st_size;
+	buf = malloc(BUFSIZE);
+	if (!buf) {
+		ERR("no memory for buffer\n");
+		goto err;
+	}
+
+	infile = fopen(ifname, "r");
+	if (infile == NULL) {
+		ERRS("could not open \"%s\" for reading", ifname);
+		goto err_free;
+	}
+
+	outfile = fopen(ofname, "w");
+	if (outfile == NULL) {
+		ERRS("could not open \"%s\" for writing", ofname);
+		goto err_close_in;
+	}
+
+	pc1_init(&pc1);
+	while (total > 0) {
+		unsigned datalen;
+
+		if (total > BUFSIZE)
+			datalen = BUFSIZE;
+		else
+			datalen = total;
+
+		errno = 0;
+		fread(buf, datalen, 1, infile);
+		if (errno != 0) {
+			ERRS("unable to read from file %s", ifname);
+			goto err_close_out;
+		}
+
+		if (decrypt)
+			pc1_decrypt_buf(&pc1, buf, datalen);
+		else
+			pc1_encrypt_buf(&pc1, buf, datalen);
+
+		errno = 0;
+		fwrite(buf, datalen, 1, outfile);
+		if (errno) {
+			ERRS("unable to write to file %s", ofname);
+			goto err_close_out;
+		}
+
+		total -= datalen;
+	}
+	pc1_finish(&pc1);
+
+	res = EXIT_SUCCESS;
+
+ out_flush:
+	fflush(outfile);
+
+ err_close_out:
+	fclose(outfile);
+	if (res != EXIT_SUCCESS) {
+		unlink(ofname);
+	}
+
+ err_close_in:
+	fclose(infile);
+
+ err_free:
+	free(buf);
+
+ err:
+	return res;
+}
+
diff --git a/tools/firmware-utils/src/ptgen.c b/tools/firmware-utils/src/ptgen.c
new file mode 100644
index 0000000000..8466d35bcc
--- /dev/null
+++ b/tools/firmware-utils/src/ptgen.c
@@ -0,0 +1,248 @@
+/* 
+ * ptgen - partition table generator
+ * Copyright (C) 2006 by Felix Fietkau <nbd@nbd.name>
+ *
+ * uses parts of afdisk
+ * Copyright (C) 2002 by David Roetzel <david@roetzel.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le32(x) bswap_32(x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le32(x) (x)
+#else
+#error unknown endianness!
+#endif
+
+/* Partition table entry */
+struct pte {
+	uint8_t active;
+	uint8_t chs_start[3];
+	uint8_t type;
+	uint8_t chs_end[3];
+	uint32_t start;
+	uint32_t length;
+};
+
+struct partinfo {
+	unsigned long size;
+	int type;
+};
+
+int verbose = 0;
+int active = 1;
+int heads = -1;
+int sectors = -1;
+int kb_align = 0;
+struct partinfo parts[4];
+char *filename = NULL;
+
+
+/* 
+ * parse the size argument, which is either
+ * a simple number (K assumed) or
+ * K, M or G
+ *
+ * returns the size in KByte
+ */
+static long to_kbytes(const char *string) {
+	int exp = 0;
+	long result;
+	char *end;
+
+	result = strtoul(string, &end, 0);
+	switch (tolower(*end)) {
+			case 'k' :
+			case '\0' : exp = 0; break;
+			case 'm' : exp = 1; break;
+			case 'g' : exp = 2; break;
+			default: return 0;
+	}
+
+	if (*end)
+		end++;
+
+	if (*end) {
+		fprintf(stderr, "garbage after end of number\n");
+		return 0;
+	}
+
+	/* result: number + 1024^(exp) */
+	if (exp == 0)
+		return result;
+	return result * (2 << ((10 * exp) - 1));
+}
+
+/* convert the sector number into a CHS value for the partition table */
+static void to_chs(long sect, unsigned char chs[3]) {
+	int c,h,s;
+	
+	s = (sect % sectors) + 1;
+	sect = sect / sectors;
+	h = sect % heads;
+	sect = sect / heads;
+	c = sect;
+
+	chs[0] = h;
+	chs[1] = s | ((c >> 2) & 0xC0);
+	chs[2] = c & 0xFF;
+
+	return;
+}
+
+/* round the sector number up to the next cylinder */
+static inline unsigned long round_to_cyl(long sect) {
+	int cyl_size = heads * sectors;
+
+	return sect + cyl_size - (sect % cyl_size); 
+}
+
+/* round the sector number up to the kb_align boundary */
+static inline unsigned long round_to_kb(long sect) {
+        return ((sect - 1) / kb_align + 1) * kb_align;
+}
+
+/* check the partition sizes and write the partition table */
+static int gen_ptable(uint32_t signature, int nr)
+{
+	struct pte pte[4];
+	unsigned long sect = 0; 
+	int i, fd, ret = -1, start, len;
+
+	memset(pte, 0, sizeof(struct pte) * 4);
+	for (i = 0; i < nr; i++) {
+		if (!parts[i].size) {
+			fprintf(stderr, "Invalid size in partition %d!\n", i);
+			return -1;
+		}
+		pte[i].active = ((i + 1) == active) ? 0x80 : 0;
+		pte[i].type = parts[i].type;
+		start = sect + sectors;
+		if (kb_align != 0)
+			start = round_to_kb(start);
+		pte[i].start = cpu_to_le32(start);
+		sect = start + parts[i].size * 2;
+		if (kb_align == 0)
+			sect = round_to_cyl(sect);
+		pte[i].length = cpu_to_le32(len = sect - start);
+		to_chs(start, pte[i].chs_start);
+		to_chs(start + len - 1, pte[i].chs_end);
+		if (verbose)
+			fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long) start * 512, ((long) start + (long) len) * 512, (long) len * 512);
+		printf("%ld\n", ((long) start * 512));
+		printf("%ld\n", ((long) len * 512));
+	}
+
+	if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
+		fprintf(stderr, "Can't open output file '%s'\n",filename);
+		return -1;
+	}
+
+	lseek(fd, 440, SEEK_SET);
+	if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) {
+		fprintf(stderr, "write failed.\n");
+		goto fail;
+	}
+
+	lseek(fd, 446, SEEK_SET);
+	if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) {
+		fprintf(stderr, "write failed.\n");
+		goto fail;
+	}
+	lseek(fd, 510, SEEK_SET);
+	if (write(fd, "\x55\xaa", 2) != 2) {
+		fprintf(stderr, "write failed.\n");
+		goto fail;
+	}
+	
+	ret = 0;
+fail:
+	close(fd);
+	return ret;
+}
+
+static void usage(char *prog)
+{
+	fprintf(stderr,	"Usage: %s [-v] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [[-t <type>] -p <size>...] \n", prog);
+	exit(1);
+}
+
+int main (int argc, char **argv)
+{
+	char type = 0x83;
+	int ch;
+	int part = 0;
+	uint32_t signature = 0x5452574F; /* 'OWRT' */
+
+	while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vl:S:")) != -1) {
+		switch (ch) {
+		case 'o':
+			filename = optarg;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'h':
+			heads = (int) strtoul(optarg, NULL, 0);
+			break;
+		case 's':
+			sectors = (int) strtoul(optarg, NULL, 0);
+			break;
+		case 'p':
+			if (part > 3) {
+				fprintf(stderr, "Too many partitions\n");
+				exit(1);
+			}
+			parts[part].size = to_kbytes(optarg);
+			parts[part++].type = type;
+			break;
+		case 't':
+			type = (char) strtoul(optarg, NULL, 16);
+			break;
+		case 'a':
+			active = (int) strtoul(optarg, NULL, 0);
+			if ((active < 0) || (active > 4))
+				active = 0;
+			break;
+		case 'l':
+			kb_align = (int) strtoul(optarg, NULL, 0) * 2;
+			break;
+		case 'S':
+			signature = strtoul(optarg, NULL, 0);
+			break;
+		case '?':
+		default:
+			usage(argv[0]);
+		}
+	}
+	argc -= optind;
+	if (argc || (heads <= 0) || (sectors <= 0) || !filename) 
+		usage(argv[0]);
+
+	return gen_ptable(signature, part);
+}
diff --git a/tools/firmware-utils/src/seama.c b/tools/firmware-utils/src/seama.c
new file mode 100644
index 0000000000..05aee8e76a
--- /dev/null
+++ b/tools/firmware-utils/src/seama.c
@@ -0,0 +1,529 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *	Copyright (C) 2008, Alpha Networks, Inc.
+ *	Created by David Hsieh <david_hsieh@alphanetworks.com>
+ *	All right reserved.
+ *
+ *	(SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ *	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.
+ *
+ *	3.	The name of the author may not be used to endorse or promote
+ *		products derived from this software without specific prior
+ *		written permission.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR
+ *	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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "md5.h"
+#include "seama.h"
+
+#define PROGNAME			"seama"
+#define VERSION				"0.20"
+#define MAX_SEAMA_META_SIZE	1024
+#define MAX_META			128
+#define MAX_IMAGE			128
+
+extern int optind;
+extern char * optarg;
+
+static int		o_verbose = 0;		/* verbose mode. */
+static char *	o_dump = NULL;		/* Seama file to dump. */
+static char *	o_seal = NULL;		/* Seal the input images when file name exist. */
+static char *	o_extract = NULL;	/* Extract the seama file. */
+static char *	o_images[MAX_IMAGE];/* The image files to pack or seal */
+static int		o_isize = 0;		/* number of images */
+static char *	o_meta[MAX_META];	/* meta data array */
+static int		o_msize = 0;		/* size of meta array */
+
+static void verbose(const char * format, ...)
+{
+	va_list marker;
+	if (o_verbose)
+	{
+		va_start(marker, format);
+		vfprintf(stdout, format, marker);
+		va_end(marker);
+	}
+}
+
+static void cleanup_exit(int exit_code)
+{
+	verbose("%s: exit with code %d\n", PROGNAME, exit_code);
+	exit(exit_code);
+}
+
+static void show_usage(int exit_code)
+{
+	printf(	PROGNAME " version " VERSION "\n"
+			"usage: " PROGNAME " [OPTIONS]\n"
+			"  -h                 show this help message.\n"
+			"  -v                 verbose mode.\n"
+			"  -m {META data}     META data.\n"
+			"  -d {file}          dump the info of the seama file.\n"
+			"  -i {input file}    image file name.\n"
+			"  -s {file}          Seal the images to the seama file.\n"
+			"  -x {seama file}    Extract the seama file.\n"
+			"\n"
+			"  SEAMA can pack the input file (with -i) into a seama file.\n"
+			"  ex: seama -i target.file\n"
+			"  SEAMA can also seal multiple seama files into a single seama file.\n"
+			"  ex: seama -s final.file -i taget1.seama -i target2.seama\n"
+			"  To extract the raw image from SEAMA, you need to specify the meta.\n"
+			"  The first image match the specified meta will be extract to\n"
+			"  the output file which was specified with '-x'.\n"
+			"  ex: seama -x output -i seama.image -m file=sealpac\n"
+			);
+	cleanup_exit(exit_code);
+}
+
+static int parse_args(int argc, char * argv[])
+{
+	int opt;
+
+	while ((opt = getopt(argc, argv, "hvd:s:i:m:x:")) > 0)
+	{
+		switch (opt)
+		{
+		default:	show_usage(-1); break;
+		case 'h':	show_usage(0); break;
+		case 'v':	o_verbose++; break;
+		case 'd':	o_dump = optarg; break;
+		case 's':	o_seal = optarg; break;
+		case 'x':	o_extract = optarg; break;
+		case 'i':
+			if (o_isize < MAX_IMAGE) o_images[o_isize++] = optarg;
+			else printf("Exceed the maximum acceptable image files.!\n");
+			break;
+		case 'm':
+			if (o_msize < MAX_META) o_meta[o_msize++] = optarg;
+			else printf("Exceed the maximum acceptable META data.!\n");
+			break;
+		}
+	}
+	return 0;
+}
+
+/*******************************************************************/
+
+static size_t calculate_digest(FILE * fh, size_t size, uint8_t * digest)
+{
+	MD5_CTX ctx;
+	size_t bytes_left, bytes_read, i;
+	uint8_t buf[MAX_SEAMA_META_SIZE];
+
+	bytes_left = size ? size : sizeof(buf);
+	bytes_read = 0;
+
+	MD5_Init(&ctx);
+	while (!feof(fh) && !ferror(fh) && bytes_left > 0)
+	{
+		i = bytes_left < sizeof(buf) ? bytes_left : sizeof(buf);
+		i = fread(buf, sizeof(char), i, fh);
+		if (i > 0)
+		{
+			MD5_Update(&ctx, buf, i);
+			bytes_read += i;
+		}
+		if (size) bytes_left -= i;
+	}
+	MD5_Final(digest, &ctx);
+	return bytes_read;
+}
+
+#define READ_BUFF_SIZE 8*1024
+static size_t copy_file(FILE * to, FILE * from)
+{
+	size_t i, fsize = 0;
+	uint8_t buf[READ_BUFF_SIZE];
+
+	while (!feof(from) && !ferror(from))
+	{
+		i = fread(buf, sizeof(uint8_t), READ_BUFF_SIZE, from);
+		if (i > 0)
+		{
+			fsize += i;
+			fwrite(buf, sizeof(uint8_t), i, to);
+		}
+	}
+	return fsize;
+}
+
+static int verify_seama(const char * fname, int msg)
+{
+	FILE * fh = NULL;
+	struct stat st;
+	seamahdr_t shdr;
+	uint8_t checksum[16];
+	uint8_t digest[16];
+	uint8_t buf[MAX_SEAMA_META_SIZE];
+	size_t msize, isize, i;
+	int ret = -1;
+
+#define ERRBREAK(fmt, args...) { if (msg) printf(fmt, ##args); break; }
+
+	do
+	{
+		if (stat(fname, &st) < 0)				ERRBREAK("Unable to get the info of '%s'\n",fname);
+		if ((fh = fopen(fname, "r+"))==NULL)	ERRBREAK("Unable to open '%s' for reading!\n",fname);
+
+		/* Dump SEAMA header */
+		if (msg) printf("FILE - %s (%d bytes)\n", fname, (int)st.st_size);
+
+		/* SEAMA */
+		while (!feof(fh) && !ferror(fh))
+		{
+			/* read header */
+			if (fread(&shdr, sizeof(shdr), 1, fh) != 1) break;
+
+			/* Check the magic number */
+			if (shdr.magic != htonl(SEAMA_MAGIC)) ERRBREAK("Invalid SEAMA magic. Probably no more SEAMA!\n");
+
+			/* Get the size */
+			isize = ntohl(shdr.size);
+			msize = ntohs(shdr.metasize);
+
+			/* The checksum exist only if size is greater than zero. */
+			if (isize > 0)
+			{
+				if (fread(checksum, sizeof(checksum), 1, fh) != 1)
+					ERRBREAK("Error reading checksum !\n");
+			}
+
+			/* Check the META size. */
+			if (msize > sizeof(buf)) ERRBREAK("META data in SEAMA header is too large!\n");
+
+			/* Read META data. */
+			if (fread(buf, sizeof(char), msize, fh) != msize)
+				ERRBREAK("Unable to read SEAMA META data!\n");
+
+			/* dump header */
+			if (msg)
+			{
+				printf("SEAMA ==========================================\n");
+				printf("  magic      : %08x\n", ntohl(shdr.magic));
+				printf("  meta size  : %zu bytes\n", msize);
+				for (i=0; i<msize; i+=(strlen((const char *)&buf[i])+1))
+					printf("  meta data  : %s\n", &buf[i]);
+				printf("  image size : %zu bytes\n", isize);
+			}
+
+			/* verify checksum */
+			if (isize > 0)
+			{
+				if (msg)
+				{
+					printf("  checksum   : ");
+					for (i=0; i<16; i++) printf("%02X", checksum[i]);
+					printf("\n");
+				}
+
+				/* Calculate the checksum */
+				calculate_digest(fh, isize, digest);
+				if (msg)
+				{
+					printf("  digest     : ");
+					for (i=0; i<16; i++) printf("%02X", digest[i]);
+					printf("\n");
+				}
+
+				if (memcmp(checksum, digest, 16)!=0) ERRBREAK("!!ERROR!! checksum error !!\n");
+				ret = 0;
+			}
+		}
+		if (msg) printf("================================================\n");
+	} while (0);
+	if (fh) fclose(fh);
+	return ret;
+}
+
+static size_t write_seama_header(FILE * fh, char * meta[], size_t msize, size_t size)
+{
+	seamahdr_t shdr;
+	size_t i;
+	uint16_t metasize = 0;
+
+	/* Calculate the META size */
+	for (i=0; i<msize; i++) metasize += (strlen(meta[i]) + 1);
+	//+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm
+	metasize = ((metasize+3)/4)*4;
+	verbose("SEAMA META : %d bytes\n", metasize);
+
+	/* Fill up the header, all the data endian should be network byte order. */
+	shdr.magic		= htonl(SEAMA_MAGIC);
+	shdr.reserved	= 0;
+	shdr.metasize	= htons(metasize);
+	shdr.size		= htonl(size);
+
+	/* Write the header */
+	return fwrite(&shdr, sizeof(seamahdr_t), 1, fh);
+}
+
+static size_t write_checksum(FILE * fh, uint8_t * checksum)
+{
+	return fwrite(checksum, sizeof(uint8_t), 16, fh);
+}
+
+static size_t write_meta_data(FILE * fh, char * meta[], size_t size)
+{
+	size_t i,j;
+	size_t ret = 0;
+
+	for (i=0; i<size; i++)
+	{
+		verbose("SEAMA META data : %s\n", meta[i]);
+		j = fwrite(meta[i], sizeof(char), strlen(meta[i])+1, fh);
+		if (j != strlen(meta[i])+1) return 0;
+		ret += j;
+	}
+	//+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm
+	j = ((ret+3)/4)*4;
+	for ( ; ret < j; ret++)
+		fwrite("", sizeof(char), 1, fh);
+
+	return ret;
+}
+
+/*******************************************************************/
+
+static void dump_seama(const char * fname)
+{
+	verify_seama(fname, 1);
+}
+
+static void seal_files(const char * file)
+{
+	FILE * fh;
+	FILE * ifh;
+	size_t i;
+
+	/* Each image should be seama. */
+	for (i = 0; i < o_isize; i++)
+	{
+		if (verify_seama(o_images[i], 0) < 0)
+		{
+			printf("'%s' is not a seama file !\n",o_images[i]);
+			return;
+		}
+	}
+
+	/* Open file for write */
+	fh = fopen(file, "w+");
+	if (fh)
+	{
+		/* Write the header. */
+		write_seama_header(fh, o_meta, o_msize, 0);
+		write_meta_data(fh, o_meta, o_msize);
+
+		/* Write image files */
+		for (i=0; i<o_isize; i++)
+		{
+			ifh = fopen(o_images[i], "r+");
+			if (ifh)
+			{
+				copy_file(fh, ifh);
+				fclose(ifh);
+			}
+		}
+
+		fclose(fh);
+	}
+}
+
+static void pack_files(void)
+{
+	FILE * fh;
+	FILE * ifh;
+	size_t i, fsize;
+	char filename[512];
+	uint8_t digest[16];
+
+	for (i=0; i<o_isize; i++)
+	{
+		/* Open the input file. */
+		ifh = fopen(o_images[i], "r+");
+		if (ifh)
+		{
+			fsize = calculate_digest(ifh, 0, digest);
+			verbose("file size (%s) : %d\n", o_images[i], fsize);
+			rewind(ifh);
+
+			/* Open the output file. */
+			sprintf(filename, "%s.seama", o_images[i]);
+			fh = fopen(filename, "w+");
+			if (fh)
+			{
+				write_seama_header(fh, o_meta, o_msize, fsize);
+				write_checksum(fh, digest);
+				write_meta_data(fh, o_meta, o_msize);
+				copy_file(fh, ifh);
+				fclose(fh);
+			}
+			fclose(ifh);
+		}
+		else
+		{
+			printf("Unable to open image file '%s'\n",o_images[i]);
+		}
+	}
+}
+
+/**************************************************************************/
+
+static int match_meta(const char * meta, size_t size)
+{
+	size_t i, j;
+	int match;
+
+	for (i = 0; i < o_msize; i++)
+	{
+		for (match = 0, j = 0; j < size; j += (strlen(&meta[j])+1))
+			if (strcmp(&meta[j], o_meta[i])==0) { match++; break; }
+		if (!match) return 0;
+	}
+	return 1;
+}
+
+
+static void extract_file(const char * output)
+{
+	FILE * ifh = NULL;
+	FILE * ofh = NULL;
+	size_t msize, isize, i, m;
+	seamahdr_t shdr;
+	uint8_t buf[MAX_SEAMA_META_SIZE];
+	int done = 0;
+
+	/* We need meta for searching the target image. */
+	if (o_msize == 0)
+	{
+		printf("SEAMA: need meta for searching image.\n");
+		return;
+	}
+
+	/* Walk through each input file */
+	for (i = 0; i < o_isize; i++)
+	{
+		/* verify the input file */
+		if (verify_seama(o_images[i], 0) < 0)
+		{
+			printf("SEAMA: '%s' is not a seama file !\n", o_images[i]);
+			continue;
+		}
+		/* open the input file */
+		ifh  = fopen(o_images[i], "r");
+		if (!ifh) continue;
+		/* read file */
+		while (!feof(ifh) && !ferror(ifh))
+		{
+			/* read header */
+			fread(&shdr, sizeof(shdr), 1, ifh);
+			if (shdr.magic != htonl(SEAMA_MAGIC)) break;
+			/* Get the size */
+			isize = ntohl(shdr.size);
+			msize = ntohs(shdr.metasize);
+			if (isize == 0)
+			{
+				while (msize > 0)
+				{
+					m = fread(buf, sizeof(char), (msize < MAX_SEAMA_META_SIZE) ? msize : MAX_SEAMA_META_SIZE, ifh);
+					if (m <= 0) break;
+					msize -= m;
+				}
+				continue;
+			}
+			/* read checksum */
+			fread(buf, sizeof(char), 16, ifh);
+			if (msize > 0)
+			{
+				/* read META */
+				fread(buf, sizeof(char), msize, ifh);
+				if (match_meta((const char *)buf, msize))
+				{
+					printf("SEAMA: found image @ '%s', image size: %zu\n", o_images[i], isize);
+					/* open output file */
+					ofh = fopen(output, "w");
+					if (!ofh) printf("SEAMA: unable to open '%s' for writting.\n",output);
+					else
+					{
+						while (isize > 0)
+						{
+							m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh);
+							if (m <= 0) break;
+							fwrite(buf, sizeof(char), m, ofh);
+							isize -= m;
+						}
+						fclose(ofh);
+					}
+					done++;
+					break;
+				}
+			}
+			while (isize > 0)
+			{
+				m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh);
+				if (m <= 0) break;
+				isize -= m;
+			}
+		}
+		/* close the file. */
+		fclose(ifh);
+		if (done) break;
+	}
+	return;
+}
+
+/*******************************************************************/
+#ifdef RGBIN_BOX
+int seama_main(int argc, char * argv[], char * env[])
+#else
+int main(int argc, char * argv[], char * env[])
+#endif
+{
+	verbose("SEAMA version " VERSION "\n");
+
+	/* parse the arguments */
+	if (parse_args(argc, argv) < 0) show_usage(9);
+
+	/* Do the works */
+	if		(o_dump)	dump_seama(o_dump);
+	else if (o_seal)	seal_files(o_seal);
+	else if	(o_extract)	extract_file(o_extract);
+	else				pack_files();
+
+	cleanup_exit(0);
+	return 0;
+}
diff --git a/tools/firmware-utils/src/seama.h b/tools/firmware-utils/src/seama.h
new file mode 100644
index 0000000000..02683b6e98
--- /dev/null
+++ b/tools/firmware-utils/src/seama.h
@@ -0,0 +1,108 @@
+/* vi: set sw=4 ts=4: */
+/*
+ *	(SEA)ttle i(MA)ge is the image which used in project seattle.
+ *
+ *	Created by David Hsieh <david_hsieh@alphanetworks.com>
+ *	Copyright (C) 2008-2009 Alpha Networks, Inc.
+ *
+ *	This file is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation; either'
+ *	version 2.1 of the License, or (at your option) any later version.
+ *
+ *	The GNU C Library is distributed in the hope that it will be useful,'
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *	Lesser General Public License for more details.
+ *
+ *	You should have received a copy of the GNU Lesser General Public
+ *	License along with the GNU C Library; if not, write to the Free
+ *	Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ *	02111-1307 USA.
+ */
+
+#ifndef __SEAMA_HEADER_FILE__
+#define __SEAMA_HEADER_FILE__
+
+#include <stdint.h>
+
+#define SEAMA_MAGIC		0x5EA3A417
+
+/*
+ *	SEAMA looks like the following map.
+ *	All the data of the header should be in network byte order.
+ *
+ *  +-------------+-------------+------------
+ *	| SEAMA magic               |     ^
+ *  +-------------+-------------+     |
+ *	| reserved    | meta size   |     |
+ *  +-------------+-------------+   header
+ *	| image size (0 bytes)      |     |
+ *  +-------------+-------------+     |
+ *	~ Meta data                 ~     v
+ *  +-------------+-------------+------------
+ *	| SEAMA magic               |   ^     ^
+ *  +-------------+-------------+   |     |
+ *	| reserved    | meta size   |   |     |
+ *  +-------------+-------------+   |     |
+ *	| image size                |   |     |
+ *  +-------------+-------------+ header  |
+ *	|                           |   |     |
+ *	| 16 bytes of MD5 digest    |   |     |
+ *	|                           |   |     |
+ *	|                           |   |     |
+ *  +-------------+-------------+   |     |
+ *	~ Meta data                 ~   v     |
+ *  +-------------+-------------+-------  |
+ *	|                           |         |
+ *	| Image of the 1st entity   |         |
+ *	~                           ~ 1st entity
+ *	|                           |         |
+ *	|                           |         v
+ *  +-------------+-------------+-------------
+ *	| SEAMA magic               |   ^     ^
+ *  +-------------+-------------+   |     |
+ *	| reserved    | meta size   |   |     |
+ *  +-------------+-------------+   |     |
+ *	| image size                |   |     |
+ *  +-------------+-------------+ header  |
+ *	|                           |   |     |
+ *	| 16 bytes of MD5 digest    |   |     |
+ *	|                           |   |     |
+ *	|                           |   |     |
+ *  +-------------+-------------+   |     |
+ *	~ Meta data                 ~   v     |
+ *  +-------------+-------------+-------  |
+ *	|                           |         |
+ *	| Image of the 2nd entity   |         |
+ *	~                           ~ 2nd entity
+ *	|                           |         |
+ *	|                           |         v
+ *  +-------------+-------------+-------------
+ */
+
+
+/*
+ *	SEAMA header
+ *
+ *	|<-------- 32 bits -------->|
+ *  +-------------+-------------+
+ *	| SEAMA magic               |
+ *  +-------------+-------------+
+ *	| reserved    | meta size   |
+ *  +-------------+-------------+
+ *	| image size                |
+ *  +-------------+-------------+
+ */
+/* seama header */
+typedef struct seama_hdr	seamahdr_t;
+struct seama_hdr
+{
+	uint32_t	magic;			/* should always be SEAMA_MAGIC. */
+	uint16_t	reserved;		/* reserved for  */
+	uint16_t	metasize;		/* size of the META data */
+	uint32_t	size;			/* size of the image */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/tools/firmware-utils/src/sha1.c b/tools/firmware-utils/src/sha1.c
new file mode 100644
index 0000000000..3ab1332992
--- /dev/null
+++ b/tools/firmware-utils/src/sha1.c
@@ -0,0 +1,443 @@
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Copyright (C) 2003-2006  Christophe Devine
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "sha1.h"
+
+/* 
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                    \
+{                                               \
+    (n) = ( (ulong) (b)[(i)    ] << 24 )        \
+        | ( (ulong) (b)[(i) + 1] << 16 )        \
+        | ( (ulong) (b)[(i) + 2] <<  8 )        \
+        | ( (ulong) (b)[(i) + 3]       );       \
+}
+#endif
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                    \
+{                                               \
+    (b)[(i)    ] = (uchar) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (uchar) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (uchar) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (uchar) ( (n)       );       \
+}
+#endif
+
+/*
+ * Core SHA-1 functions
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void sha1_process( sha1_context *ctx, uchar data[64] )
+{
+    ulong temp, W[16], A, B, C, D, E;
+
+    GET_UINT32_BE( W[0],  data,  0 );
+    GET_UINT32_BE( W[1],  data,  4 );
+    GET_UINT32_BE( W[2],  data,  8 );
+    GET_UINT32_BE( W[3],  data, 12 );
+    GET_UINT32_BE( W[4],  data, 16 );
+    GET_UINT32_BE( W[5],  data, 20 );
+    GET_UINT32_BE( W[6],  data, 24 );
+    GET_UINT32_BE( W[7],  data, 28 );
+    GET_UINT32_BE( W[8],  data, 32 );
+    GET_UINT32_BE( W[9],  data, 36 );
+    GET_UINT32_BE( W[10], data, 40 );
+    GET_UINT32_BE( W[11], data, 44 );
+    GET_UINT32_BE( W[12], data, 48 );
+    GET_UINT32_BE( W[13], data, 52 );
+    GET_UINT32_BE( W[14], data, 56 );
+    GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[(t -  3) & 0x0F] ^ W[(t - 8) & 0x0F] ^     \
+           W[(t - 14) & 0x0F] ^ W[ t      & 0x0F],      \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void sha1_update( sha1_context *ctx, uchar *input, uint length )
+{
+    ulong left, fill;
+
+    if( ! length ) return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += length;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < length )
+        ctx->total[1]++;
+
+    if( left && length >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, fill );
+        sha1_process( ctx, ctx->buffer );
+        length -= fill;
+        input  += fill;
+        left = 0;
+    }
+
+    while( length >= 64 )
+    {
+        sha1_process( ctx, input );
+        length -= 64;
+        input  += 64;
+    }
+
+    if( length )
+    {
+        memcpy( (void *) (ctx->buffer + left),
+                (void *) input, length );
+    }
+}
+
+static uchar sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void sha1_finish( sha1_context *ctx, uchar digest[20] )
+{
+    ulong last, padn;
+    ulong high, low;
+    uchar msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_UINT32_BE( high, msglen, 0 );
+    PUT_UINT32_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_UINT32_BE( ctx->state[0], digest,  0 );
+    PUT_UINT32_BE( ctx->state[1], digest,  4 );
+    PUT_UINT32_BE( ctx->state[2], digest,  8 );
+    PUT_UINT32_BE( ctx->state[3], digest, 12 );
+    PUT_UINT32_BE( ctx->state[4], digest, 16 );
+}
+
+/*
+ * Output SHA-1(file contents), returns 0 if successful.
+ */
+int sha1_file( char *filename, uchar digest[20] )
+{
+    FILE *f;
+    size_t n;
+    sha1_context ctx;
+    uchar buf[1024];
+
+    if( ( f = fopen( filename, "rb" ) ) == NULL )
+        return( 1 );
+
+    sha1_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha1_update( &ctx, buf, (uint) n );
+
+    sha1_finish( &ctx, digest );
+
+    fclose( f );
+    return( 0 );
+}
+
+/*
+ * Output SHA-1(buf)
+ */
+void sha1_csum( uchar *buf, uint buflen, uchar digest[20] )
+{
+    sha1_context ctx;
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, buf, buflen );
+    sha1_finish( &ctx, digest );
+}
+
+/*
+ * Output HMAC-SHA-1(key,buf)
+ */
+void sha1_hmac( uchar *key, uint keylen, uchar *buf, uint buflen,
+                uchar digest[20] )
+{
+    uint i;
+    sha1_context ctx;
+    uchar k_ipad[64];
+    uchar k_opad[64];
+    uchar tmpbuf[20];
+
+    memset( k_ipad, 0x36, 64 );
+    memset( k_opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        if( i >= 64 ) break;
+
+        k_ipad[i] ^= key[i];
+        k_opad[i] ^= key[i];
+    }
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, k_ipad, 64 );
+    sha1_update( &ctx, buf, buflen );
+    sha1_finish( &ctx, tmpbuf );
+
+    sha1_starts( &ctx );
+    sha1_update( &ctx, k_opad, 64 );
+    sha1_update( &ctx, tmpbuf, 20 );
+    sha1_finish( &ctx, digest );
+
+    memset( k_ipad, 0, 64 );
+    memset( k_opad, 0, 64 );
+    memset( tmpbuf, 0, 20 );
+    memset( &ctx, 0, sizeof( sha1_context ) );
+}
+
+#ifdef SELF_TEST
+/* 
+ * FIPS-180-1 test vectors
+ */
+static char *sha1_test_str[3] = 
+{
+    "abc",
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+    NULL
+};
+
+static uchar sha1_test_sum[3][20] =
+{
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( void )
+{
+    int i, j;
+    uchar buf[1000];
+    uchar sha1sum[20];
+    sha1_context ctx;
+
+    for( i = 0; i < 3; i++ )
+    {
+        printf( "  SHA-1 test #%d: ", i + 1 );
+
+        sha1_starts( &ctx );
+
+        if( i < 2 )
+            sha1_update( &ctx, (uchar *) sha1_test_str[i],
+                         strlen( sha1_test_str[i] ) );
+        else
+        {
+            memset( buf, 'a', 1000 );
+            for( j = 0; j < 1000; j++ )
+                sha1_update( &ctx, (uchar *) buf, 1000 );
+        }
+
+        sha1_finish( &ctx, sha1sum );
+
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+        {
+            printf( "failed\n" );
+            return( 1 );
+        }
+
+        printf( "passed\n" );
+    }
+
+    printf( "\n" );
+    return( 0 );
+}
+#else
+int sha1_self_test( void )
+{
+    printf( "SHA-1 self-test not available\n\n" );
+    return( 1 );
+}
+#endif
diff --git a/tools/firmware-utils/src/sha1.h b/tools/firmware-utils/src/sha1.h
new file mode 100644
index 0000000000..425267a306
--- /dev/null
+++ b/tools/firmware-utils/src/sha1.h
@@ -0,0 +1,57 @@
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _STD_TYPES
+#define _STD_TYPES
+
+#define uchar   unsigned char
+#define uint    unsigned int
+#define ulong   unsigned long int
+
+#endif
+
+typedef struct
+{
+    ulong total[2];
+    ulong state[5];
+    uchar buffer[64];
+}
+sha1_context;
+
+/*
+ * Core SHA-1 functions
+ */
+void sha1_starts( sha1_context *ctx );
+void sha1_update( sha1_context *ctx, uchar *input, uint length );
+void sha1_finish( sha1_context *ctx, uchar digest[20] );
+
+/*
+ * Output SHA-1(file contents), returns 0 if successful.
+ */
+int sha1_file( char *filename, uchar digest[20] );
+
+/*
+ * Output SHA-1(buf)
+ */
+void sha1_csum( uchar *buf, uint buflen, uchar digest[20] );
+
+/*
+ * Output HMAC-SHA-1(key,buf)
+ */
+void sha1_hmac( uchar *key, uint keylen, uchar *buf, uint buflen,
+                uchar digest[20] );
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha1.h */
diff --git a/tools/firmware-utils/src/spw303v.c b/tools/firmware-utils/src/spw303v.c
new file mode 100644
index 0000000000..654d68db2b
--- /dev/null
+++ b/tools/firmware-utils/src/spw303v.c
@@ -0,0 +1,243 @@
+/*
+ * spw303v.c - partially based on OpenWrt's imagetag.c and addpattern.c
+ *
+ * Copyright (C) 2011  Jonas Gorski <jonas.gorski@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define IMAGE_LEN 10                   /* Length of Length Field */
+#define ADDRESS_LEN 12                 /* Length of Address field */
+#define TAGID_LEN  6                   /* Length of tag ID */
+#define TAGINFO_LEN 20                 /* Length of vendor information field in tag */
+#define TAGVER_LEN 4                   /* Length of Tag Version */
+#define TAGLAYOUT_LEN 4                /* Length of FlashLayoutVer */
+
+
+struct spw303v_tag
+{
+    unsigned char tagVersion[4];       // tag version.  Will be 2 here.
+    unsigned char signiture_1[20];         		 // text line for company info
+    unsigned char signiture_2[14];        		// additional info (can be version number)
+    unsigned char chipId[6];			 		// chip id
+    unsigned char boardId[16];        		 	// board id
+    unsigned char bigEndian[2];           		// if = 1 - big, = 0 - little endia of the host
+    unsigned char totalImageLen[IMAGE_LEN];      // the sum of all the following length
+    unsigned char cfeAddress[ADDRESS_LEN];       // if non zero, cfe starting address
+    unsigned char cfeLen[IMAGE_LEN];             // if non zero, cfe size in clear ASCII text.
+    unsigned char rootfsAddress[ADDRESS_LEN];    // if non zero, filesystem starting address
+    unsigned char rootfsLen[IMAGE_LEN];          // if non zero, filesystem size in clear ASCII text.
+    unsigned char kernelAddress[ADDRESS_LEN];    // if non zero, kernel starting address
+    unsigned char kernelLen[IMAGE_LEN];          // if non zero, kernel size in clear ASCII text.
+
+	unsigned char certf1Address[ADDRESS_LEN];
+	unsigned char certf1Len[6];
+	unsigned char certf2Address[ADDRESS_LEN];
+	unsigned char certf2Len[6];
+	unsigned char certf3Address[ADDRESS_LEN];
+	unsigned char certf3Len[6];
+	unsigned char httpsFileSize[4];
+	unsigned char tr64FileSize[4];
+	unsigned char tr69FileSize[4];
+	unsigned char filesmap[4];
+
+    unsigned char imageSequence[4];     			// incrments everytime an image is flashed
+    unsigned char reserved[4];					    // reserved for later use
+    unsigned char imageCRC[4];                      // 216-219: CRC32 of images
+    unsigned char reserved2[16];                    // 220-235: Unused at present
+    unsigned char headerCRC[4];                     // 236-239: CRC32 of header excluding tagVersion
+    unsigned char reserved3[16];                    // 240-255: Unused at present
+};
+
+static uint32_t crc32tab[256] = {
+	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+#define IMAGETAG_CRC_START			0xFFFFFFFF
+
+#define IMAGETAG_MAGIC1_TCOM		"AAAAAAAA Corporatio"
+
+static char fake_data[] = {
+        0x18, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21 ,0x18,
+        0x21, 0x24, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x18, 0x21, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21, 0x1b, 0x18, 0x18, 0x24, 0x24, 0x21, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18,
+        0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x18, 0x21, 0x21,
+        0x21, 0x21, 0x21, 0x21,
+};
+
+
+uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
+{
+	while (len--)
+		crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
+
+	return crc;
+}
+
+void fix_header(void *buf)
+{
+	struct spw303v_tag *tag = buf;
+	uint32_t crc;
+	/* Replace signature with custom t-com one */
+	memset(tag->signiture_1, 0, 20);
+	memcpy(tag->signiture_1, IMAGETAG_MAGIC1_TCOM, strlen(IMAGETAG_MAGIC1_TCOM));
+
+	/* Clear cert fields to remove information_* data */
+	memset(tag->certf1Address, 0, 74);
+
+	/* replace image crc with modified one */
+	crc = ntohl(*((uint32_t *)&tag->imageCRC));
+
+	crc = htonl(crc32(crc, fake_data, 64));
+
+	memcpy(tag->imageCRC, &crc, 4);
+
+	/* Update tag crc */
+	crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
+	memcpy(tag->headerCRC, &crc, 4);
+}
+
+
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+	fprintf(stderr, "Usage: spw303v [-i <inputfile>] [-o <outputfile>]\n");
+	exit(EXIT_FAILURE);
+}
+
+
+int main(int argc, char **argv)
+{
+	char buf[1024];	/* keep this at 1k or adjust garbage calc below */
+	FILE *in = stdin;
+	FILE *out = stdout;
+	char *ifn = NULL;
+	char *ofn = NULL;
+	int c;
+	int v0, v1, v2;
+	size_t n;
+	int first_block = 1;
+
+	uint32_t image_crc = IMAGETAG_CRC_START;
+
+	while ((c = getopt(argc, argv, "i:o:h")) != -1) {
+		switch (c) {
+			case 'i':
+				ifn = optarg;
+				break;
+			case 'o':
+				ofn = optarg;
+				break;
+			case 'h':
+			default:
+				usage();
+		}
+	}
+
+	if (optind != argc || optind == 1) {
+		fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+		usage();
+	}
+
+	if (ifn && !(in = fopen(ifn, "r"))) {
+		fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+		usage();
+	}
+
+	if (ofn && !(out = fopen(ofn, "w"))) {
+		fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+		usage();
+	}
+
+
+
+	while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (n < sizeof(buf)) {
+			if (ferror(in)) {
+			FREAD_ERROR:
+				fprintf(stderr, "fread error\n");
+				return EXIT_FAILURE;
+			}
+		}
+
+		if (first_block && n >= 256) {
+			fix_header(buf);
+			first_block = 0;
+		}
+
+		image_crc = crc32(image_crc, buf, n);
+
+		if (!fwrite(buf, n, 1, out)) {
+		FWRITE_ERROR:
+			fprintf(stderr, "fwrite error\n");
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (ferror(in)) {
+		goto FREAD_ERROR;
+	}
+
+	if (fflush(out)) {
+		goto FWRITE_ERROR;
+	}
+
+	fclose(in);
+	fclose(out);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/srec2bin.c b/tools/firmware-utils/src/srec2bin.c
new file mode 100644
index 0000000000..5cc71bda22
--- /dev/null
+++ b/tools/firmware-utils/src/srec2bin.c
@@ -0,0 +1,524 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+//Rev 0.1 Original
+// 8 Jan 2001  MJH  Added code to write data to Binary file
+//                  note: outputfile is name.bin, where name is first part
+//                  of input file.  ie tmp.rec -> tmp.bin
+//
+//   srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
+//
+//   TAG   
+//        bit32u TAG_BIG     = 0xDEADBE42;
+//        bit32u TAG_LITTLE  = 0xFEEDFA42;
+//
+//  File Structure
+//
+//  TAG    :   32 Bits
+//  [DATA RECORDS]
+//
+//  Data Records Structure
+//
+//  LENGTH  :  32 Bits    <- Length of DATA, excludes ADDRESS and CHECKSUM
+//  ADDRESS :  32 Bits
+//  DATA    :  8 Bits * LENGTH
+//  CHECKSUM:  32 Bits    <-  0 - (Sum of Length --> End of Data)
+//
+//  Note : If Length == 0, Address will be Program Start
+//
+//
+//  
+//
+//
+
+#define MajRevNum 0
+#define MinRevNum 2
+
+
+#define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
+
+typedef unsigned char bit8u;
+typedef unsigned int bit32u;
+typedef int bit32;
+
+#define FALSE 0
+#define TRUE (!FALSE)
+
+
+bit32u CheckSum;
+int RecStart;
+int debug;
+int verbose;
+
+FILE *OpenOutputFile( char *Name );
+FILE *fOut;
+bit32u RecLength=0;
+
+bit32u AddressCurrent;
+
+bit32u gh(char *cp,int nibs);
+
+int BigEndian;
+
+int inputline;
+
+// char buf[16*1024];
+
+char buffer[2048];
+char *cur_ptr;
+int cur_line=0;
+int cur_len=0;
+
+int s1s2s3_total=0;
+
+bit32u PBVal;
+int    PBValid;
+bit32u PBAdr;
+
+
+void dumpfTell(char *s, bit32u Value)
+{
+    int Length;
+    Length = (int) RecLength;
+    if (debug)
+          printf("[%s  ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
+                s, ftell(fOut), Length, Length, Value);
+}
+
+void DispHex(bit32u Hex)
+{
+//    printf("%X", Hex);
+}
+
+void WaitDisplay(void)
+{
+   static int Count=0;
+   static int Index=0;
+   char iline[]={"-\\|/"};
+
+   Count++;
+   if ((Count % 32)==0)
+   {
+     if (verbose)
+        printf("%c%c",iline[Index++],8);
+     Index &= 3;
+   }
+}
+
+
+void binOut32 ( bit32u Data )
+{
+// On UNIX machine all 32bit writes need ENDIAN switched
+//    Data = EndianSwitch(Data);
+//    fwrite( &Data, sizeof(bit32u), 1, fOut);
+
+   char sdat[4];
+   int i;
+
+   for(i=0;i<4;i++)
+    sdat[i]=(char)(Data>>(i*8));
+   fwrite( sdat, 1, 4, fOut);
+   dumpfTell("Out32" , Data);
+}
+
+// Only update RecLength on Byte Writes
+// All 32 bit writes will be for Length etc
+
+void binOut8 ( bit8u Data )
+{
+    int n;
+    dumpfTell("B4Data" , (bit32u) (Data & 0xFF) );
+    n = fwrite( &Data, sizeof(bit8u), 1, fOut);
+    if (n != 1)
+        printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent);
+    RecLength += 1;
+}
+
+//  Currently ONLY used for outputting Program Start
+
+void binRecStart(bit32u Address)
+{
+    RecLength      = 0;
+    CheckSum       = Address;
+    RecStart       = TRUE;
+
+    if (debug)
+          printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
+                CheckSum, RecLength, Address);
+
+
+    dumpfTell("RecLength", RecLength);
+    binOut32( RecLength );
+    dumpfTell("Address", Address);
+    binOut32( Address );
+}
+
+void binRecEnd(void)
+{
+    long RecEnd;
+
+    if (!RecStart)   //  if no record started, do not end it
+    {
+        return;
+    }
+
+    RecStart = FALSE;
+
+
+    RecEnd = ftell(fOut);         // Save Current position
+
+    if (debug)
+          printf("[RecEnd  ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
+                CheckSum, RecLength, RecLength, RecEnd);
+
+    fseek( fOut, -((long) RecLength), SEEK_CUR);  // move back Start Of Data
+
+    dumpfTell("Data   ", -1);
+
+    fseek( fOut, -4, SEEK_CUR);  // move back Start Of Address
+
+    dumpfTell("Address   ", -1);
+
+    fseek( fOut, -4, SEEK_CUR);  // move back Start Of Length
+
+    dumpfTell("Length   ", -1);
+
+    binOut32( RecLength );
+
+    fseek( fOut, RecEnd, SEEK_SET);  // move to end of Record
+
+    CheckSum += RecLength;
+
+    CheckSum =  ~CheckSum + 1;  // Two's complement
+
+    binOut32( CheckSum );
+
+    if (verbose)
+        printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum);
+}
+
+void binRecOutProgramStart(bit32u Address)
+{
+    if (Address != (AddressCurrent+1))
+    {
+        binRecEnd();
+        binRecStart(Address);
+    }
+    AddressCurrent = Address;
+}
+void binRecOutByte(bit32u Address, bit8u Data)
+{
+    //  If Address is one after Current Address, output Byte
+    //  If not, close out last record, update Length, write checksum
+    //  Then Start New Record, updating Current Address
+
+    if (Address != (AddressCurrent+1))
+    {
+        binRecEnd();
+        binRecStart(Address);
+    }
+    AddressCurrent = Address;
+    CheckSum += Data;
+    binOut8( Data );
+}
+
+//=============================================================================
+//       SUPPORT FUNCTIONS
+//=============================================================================
+int readline(FILE *fil,char *buf,int len)
+{
+    int rlen;
+    
+    rlen=0;
+    if (len==0)  return(0);
+    while(1)
+    {
+      if (cur_len==0)
+      {
+        cur_len=fread(buffer, 1, sizeof(buffer), fil);
+        if (cur_len==0)
+        {
+          if (rlen)
+          {
+            *buf=0;
+            return(rlen);
+          }
+          return(-1);
+        }
+        cur_ptr=buffer;
+      }
+      if (cur_len)
+      {
+        if (*cur_ptr=='\n')
+        {
+          *buf=0;
+          cur_ptr++;
+          cur_len--;
+          return(rlen);
+        }
+         else
+         {
+           if ((len>1)&&(*cur_ptr!='\r'))
+           {
+             *buf++=*cur_ptr++;
+             len--;
+           }
+           else
+             cur_ptr++;
+
+           rlen++;
+           cur_len--;
+         }
+      }
+      else
+      {
+        *buf=0;
+        cur_ptr++;
+        cur_len--;
+        return(rlen);
+      }
+    }
+}
+
+
+int SRLerrorout(char *c1,char *c2)
+{
+  printf("\nERROR: %s - '%s'.",c1,c2);
+  return(FALSE);
+}
+
+
+int checksum(char *cp,int count)
+{
+  char *scp;
+  int cksum;
+  int dum;
+
+  scp=cp;
+  while(*scp)
+  {
+    if (!isxdigit(*scp++))
+      return(SRLerrorout("Invalid hex digits",cp));
+  }
+  scp=cp;
+
+  cksum=count;
+
+  while(count)
+  {
+    cksum += gh(scp,2);
+    if (count == 2)
+        dum = ~cksum;
+    scp += 2;
+    count--;
+  }
+  cksum&=0x0ff; 
+  //  printf("\nCk:%02x",cksum);
+  return(cksum==0x0ff);
+}
+
+bit32u gh(char *cp,int nibs)
+{
+  int i;
+  bit32u j;
+
+  j=0;
+
+  for(i=0;i<nibs;i++)
+  {
+    j<<=4;
+    if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f;
+    if ((*cp>='0')&&(*cp<='9')) 
+      j += (*cp-0x30);
+     else
+      if ((*cp>='A')&&(*cp<='F'))
+        j += (*cp-0x37);
+       else
+        SRLerrorout("Bad Hex char", cp);
+    cp++;
+  }
+  return(j);
+}
+
+
+//=============================================================================
+//       PROCESS SREC LINE
+//=============================================================================
+
+int srecLine(char *pSrecLine)
+{
+    char *scp,ch;
+    int  itmp,count,dat;
+    bit32u adr;
+    static bit32u RecordCounter=0;
+
+    cur_line++;
+    scp=pSrecLine;
+  
+    if (*pSrecLine!='S')
+      return(SRLerrorout("Not an Srecord file",scp));
+    pSrecLine++;
+    if (strlen(pSrecLine)<4)
+      return(SRLerrorout("Srecord too short",scp));
+  
+    ch=*pSrecLine++;
+  
+    count=gh(pSrecLine,2);
+  
+    pSrecLine += 2;
+  
+  //  if(debug)
+  //        printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
+     RecordCounter++;
+     DispHex(RecordCounter);
+  
+    if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp));
+  
+    if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp));
+  
+    switch(ch)
+    {
+        case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
+                  if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp));
+        break;
+        case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
+                  adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
+                  count--;
+                  while(count)
+                  {
+                    dat=gh(pSrecLine,2); pSrecLine+=2; count--;
+                    binRecOutByte(adr, (char) (dat & 0xFF));
+                    adr++;
+                  }
+                  s1s2s3_total++;
+        break;
+        case '4': return(SRLerrorout("Invalid Srecord type",scp));
+        break;
+        case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
+                  if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp));
+        break;
+        case '6': return(SRLerrorout("Invalid Srecord type",scp));
+        break;
+        case '7': // PROGRAM START
+                  if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
+                  adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
+                  if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp));
+                  binRecOutProgramStart(adr);
+        break;
+        case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+                  return(SRLerrorout("Srecord Not valid for MIPS",scp));
+        break;
+        default:
+        break;
+    }
+    return(TRUE);
+}
+ 
+
+//=============================================================================
+//       MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
+//=============================================================================
+
+int srec2bin(int argc,char *argv[],int verbose)
+{
+    int i,rlen,sts;
+    FILE *fp;
+    char ac;
+    char buff[256];
+    bit32u TAG_BIG     = 0xDEADBE42;
+    bit32u TAG_LITTLE  = 0xFEEDFA42;
+
+    bit32u Tag;
+
+  
+    if(argc < 3)
+    {
+      printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
+      return(0);
+    }
+  
+    if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE;
+
+    if (BigEndian)
+        Tag = TAG_BIG;
+    else
+        Tag = TAG_LITTLE;
+
+    if (verbose)
+       printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag);
+
+    fp = fopen(argv[1],"rt");
+
+    if (fp==NULL)
+    {
+      printf("\nError: Opening input file, %s.", argv[1]);
+      return(0);
+    }
+  
+    fOut = fopen( argv[2], "wb");
+    
+    if (fOut==NULL)
+    {
+      printf("\nError: Opening Output file, %s.", argv[2]);
+      if(fp) fclose(fp);
+      return(0);
+    }
+ 
+    RecStart = FALSE;
+
+    AddressCurrent = 0xFFFFFFFFL;
+
+    // Setup Tag 
+  
+    dumpfTell("Tag", Tag);
+
+    binOut32(Tag);
+
+  
+    inputline=0;
+    sts=TRUE;
+
+    rlen = readline(fp,buff,sizeof buff);
+
+    while( (sts) && (rlen != -1))
+    {
+        if (strlen(buff))
+        {
+            sts &= srecLine(buff);
+            WaitDisplay();
+        }
+       rlen = readline(fp,buff,sizeof buff);
+    }
+
+  
+  //  printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
+  
+    binRecEnd();
+
+    if(fp) fclose(fp);
+    if(fOut) fclose(fOut);
+
+    return(1);
+}
+
+int main(int argc, char *argv[])
+{
+    debug = TRUE;
+    debug = FALSE;
+    verbose = FALSE;
+    srec2bin(argc,argv,verbose);
+    return 0;
+}
+
diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c
new file mode 100644
index 0000000000..2e8da8fc64
--- /dev/null
+++ b/tools/firmware-utils/src/tplink-safeloader.c
@@ -0,0 +1,783 @@
+/*
+  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 <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;
+};
+
+struct device_info {
+	const char *vendor;
+	const char *support_list;
+	char support_trail;
+	const struct flash_partition_entry *partitions;
+	void *(*generate_sysupgrade_image)(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len);
+};
+
+/** 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 char cpe510_vendor[] = "CPE510(TP-LINK|UN|N300-5):1.0\r\n";
+
+/** Vendor information for C2600 */
+static const char c2600_vendor[] = "";
+
+/** Vendor information for EAP120 */
+static const char eap120_vendor[] = "EAP120(TP-LINK|UN|N300-2):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 flash partition table for C2600;
+    it is the same as the one used by the stock images.
+*/
+static const struct flash_partition_entry c2600_partitions[] = {
+        {"SBL1", 0x00000, 0x20000},
+        {"MIBIB", 0x20000, 0x20000},
+        {"SBL2", 0x40000, 0x20000},
+        {"SBL3", 0x60000, 0x30000},
+        {"DDRCONFIG", 0x90000, 0x10000},
+        {"SSD", 0xa0000, 0x10000},
+        {"TZ", 0xb0000, 0x30000},
+        {"RPM", 0xe0000, 0x20000},
+        {"fs-uboot", 0x100000, 0x70000},
+        {"uboot-env", 0x170000, 0x40000},
+        {"radio", 0x1b0000, 0x40000},
+        {"os-image", 0x1f0000, 0x200000},
+        {"file-system", 0x3f0000, 0x1b00000},
+        {"default-mac", 0x1ef0000, 0x00200},
+        {"pin", 0x1ef0200, 0x00200},
+        {"product-info", 0x1ef0400, 0x0fc00},
+        {"partition-table", 0x1f00000, 0x10000},
+        {"soft-version", 0x1f10000, 0x10000},
+        {"support-list", 0x1f20000, 0x10000},
+        {"profile", 0x1f30000, 0x10000},
+        {"default-config", 0x1f40000, 0x10000},
+        {"user-config", 0x1f50000, 0x40000},
+        {"qos-db", 0x1f90000, 0x40000},
+        {"usb-config", 0x1fd0000, 0x10000},
+        {"log", 0x1fe0000, 0x20000},
+	{NULL, 0, 0}
+};
+
+static const struct flash_partition_entry c5_partitions[] = {
+	{"fs-uboot", 0x00000, 0x40000},
+	{"os-image", 0x40000, 0x200000},
+	{"file-system", 0x240000, 0xc00000},
+	{"default-mac", 0xe40000, 0x00200},
+	{"pin", 0xe40200, 0x00200},
+	{"product-info", 0xe40400, 0x00200},
+	{"partition-table", 0xe50000, 0x10000},
+	{"soft-version", 0xe60000, 0x00200},
+	{"support-list", 0xe61000, 0x0f000},
+	{"profile", 0xe70000, 0x10000},
+	{"default-config", 0xe80000, 0x10000},
+	{"user-config", 0xe90000, 0x50000},
+	{"log", 0xee0000, 0x100000},
+	{"radio_bk", 0xfe0000, 0x10000},
+	{"radio", 0xff0000, 0x10000},
+	{NULL, 0, 0}
+};
+
+/**    The flash partition table for EAP120;
+    it is the same as the one used by the stock images.
+*/
+static const struct flash_partition_entry eap120_partitions[] = {
+	{"fs-uboot", 0x00000, 0x20000},
+	{"partition-table", 0x20000, 0x02000},
+	{"default-mac", 0x30000, 0x00020},
+	{"support-list", 0x31000, 0x00100},
+	{"product-info", 0x31100, 0x00100},
+	{"soft-version", 0x32000, 0x00100},
+	{"os-image", 0x40000, 0x180000},
+	{"file-system", 0x1c0000, 0x600000},
+	{"user-config", 0x7c0000, 0x10000},
+	{"backup-config", 0x7d0000, 0x10000},
+	{"log", 0x7e0000, 0x10000},
+	{"radio", 0x7f0000, 0x10000},
+	{NULL, 0, 0}
+};
+
+/**
+   The support list for CPE210/220
+*/
+static const char cpe210_support_list[] =
+	"SupportList:\r\n"
+	"CPE210(TP-LINK|UN|N300-2):1.0\r\n"
+	"CPE210(TP-LINK|UN|N300-2):1.1\r\n"
+	"CPE220(TP-LINK|UN|N300-2):1.0\r\n"
+	"CPE220(TP-LINK|UN|N300-2):1.1\r\n";
+/**
+   The support list for CPE210/220/510/520
+*/
+static const char cpe510_support_list[] =
+	"SupportList:\r\n"
+	"CPE510(TP-LINK|UN|N300-5):1.0\r\n"
+	"CPE510(TP-LINK|UN|N300-5):1.1\r\n"
+	"CPE520(TP-LINK|UN|N300-5):1.0\r\n"
+	"CPE520(TP-LINK|UN|N300-5):1.1\r\n";
+
+/**
+   The support list for C2600
+*/
+static const char c2600_support_list[] =
+	"SupportList:\r\n"
+	"{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n";
+
+static const char c9_support_list[] =
+	"SupportList:\n"
+	"{product_name:ArcherC9,"
+	"product_ver:1.0.0,"
+	"special_id:00000000}\n";
+
+/**
+   The support list for EAP120
+*/
+static const char eap120_support_list[] =
+	"SupportList:\r\n"
+	"EAP120(TP-LINK|UN|N300-2):1.0\r\n";
+
+#define error(_ret, _errno, _str, ...)				\
+	do {							\
+		fprintf(stderr, _str ": %s\n", ## __VA_ARGS__,	\
+			strerror(_errno));			\
+		if (_ret)					\
+			exit(_ret);				\
+	} while (0)
+
+
+/** Stores a uint32 as big endian */
+static inline void put32(uint8_t *buf, uint32_t val) {
+	buf[0] = val >> 24;
+	buf[1] = val >> 16;
+	buf[2] = val >> 8;
+	buf[3] = val;
+}
+
+/** Allocates a new image partition */
+static 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 */
+static void free_image_partition(struct image_partition_entry entry) {
+	free(entry.data);
+}
+
+/** Generates the partition-table partition */
+static 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 */
+static 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 */
+static struct image_partition_entry make_support_list(struct device_info *info) {
+	size_t len = strlen(info->support_list);
+	struct image_partition_entry entry = alloc_image_partition("support-list", len + 9);
+
+	put32(entry.data, len);
+	memset(entry.data+4, 0, 4);
+	memcpy(entry.data+8, info->support_list, len);
+	entry.data[len+8] = info->support_trail;
+
+	return entry;
+}
+
+/** Creates a new image partition with an arbitrary name from a file */
+static 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.
+*/
+static 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 */
+static 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-0017    Vendor information length (without padding) (4 bytes, big endian)
+     0018-1013    Vendor information (4092 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
+*/
+static void * generate_factory_image(const char *vendor, 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");
+
+	put32(image, *len);
+
+	size_t vendor_len = strlen(vendor);
+	put32(image+0x14, vendor_len);
+	memcpy(image+0x18, vendor, vendor_len);
+	memset(image+0x18+vendor_len, 0xff, 4092-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.
+*/
+static 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;
+}
+
+static void * generate_sysupgrade_image_c2600(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[11];
+	const struct flash_partition_entry *flash_file_system = &flash_parts[12];
+
+	const struct image_partition_entry *image_os_image = &image_parts[3];
+	const struct image_partition_entry *image_file_system = &image_parts[4];
+
+	assert(strcmp(flash_os_image->name, "os-image") == 0);
+	assert(strcmp(flash_file_system->name, "file-system") == 0);
+
+	assert(strcmp(image_os_image->name, "os-image") == 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_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size);
+
+	return image;
+}
+static void *generate_sysupgrade_image_eap120(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[6];
+	const struct flash_partition_entry *flash_file_system = &flash_parts[7];
+
+	const struct image_partition_entry *image_os_image = &image_parts[3];
+	const struct image_partition_entry *image_file_system = &image_parts[4];
+
+	assert(strcmp(flash_os_image->name, "os-image") == 0);
+	assert(strcmp(flash_file_system->name, "file-system") == 0);
+
+	assert(strcmp(image_os_image->name, "os-image") == 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_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size);
+
+	return image;
+}
+
+struct device_info cpe210_info = {
+	.vendor = cpe510_vendor,
+	.support_list = cpe210_support_list,
+	.support_trail = '\xff',
+	.partitions = cpe510_partitions,
+	.generate_sysupgrade_image = &generate_sysupgrade_image,
+};
+
+struct device_info cpe510_info = {
+	.vendor = cpe510_vendor,
+	.support_list = cpe510_support_list,
+	.support_trail = '\xff',
+	.partitions = cpe510_partitions,
+	.generate_sysupgrade_image = &generate_sysupgrade_image,
+};
+
+struct device_info c2600_info = {
+	.vendor = c2600_vendor,
+	.support_list = c2600_support_list,
+	.support_trail = '\x00',
+	.partitions = c2600_partitions,
+	.generate_sysupgrade_image = &generate_sysupgrade_image_c2600,
+};
+
+struct device_info e9_info = {
+	.vendor = c2600_vendor,
+	.support_list = c9_support_list,
+	.support_trail = '\x00',
+	.partitions = c5_partitions,
+};
+
+struct device_info eap120_info = {
+	.vendor = eap120_vendor,
+	.support_list = eap120_support_list,
+	.support_trail = '\xff',
+	.partitions = eap120_partitions,
+	.generate_sysupgrade_image = &generate_sysupgrade_image_eap120,
+};
+
+static void build_image(const char *output,
+		const char *kernel_image,
+		const char *rootfs_image,
+		uint32_t rev,
+		bool add_jffs2_eof,
+		bool sysupgrade,
+		struct device_info *info) {
+	struct image_partition_entry parts[6] = {};
+
+	parts[0] = make_partition_table(info->partitions);
+	parts[1] = make_soft_version(rev);
+	parts[2] = make_support_list(info);
+	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 = info->generate_sysupgrade_image(info->partitions, parts, &len);
+	else
+		image = generate_factory_image(info->vendor, 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 */
+static 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;
+	struct device_info *info;
+
+	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, "CPE210") == 0)
+		info = &cpe210_info;
+	else if (strcmp(board, "CPE510") == 0)
+		info = &cpe510_info;
+	else if (strcmp(board, "C2600") == 0)
+		info = &c2600_info;
+	else if (strcmp(board, "EAP120") == 0)
+		info = &eap120_info;
+	else if (strcmp(board, "ARCHERC9") == 0)
+		info = &e9_info;
+	else
+		error(1, 0, "unsupported board %s", board);
+
+	build_image(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade, info);
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/trx.c b/tools/firmware-utils/src/trx.c
new file mode 100644
index 0000000000..aa1f5be4b6
--- /dev/null
+++ b/tools/firmware-utils/src/trx.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2004  Manuel Novoa III  <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* July 29, 2004
+ *
+ * This is a hacked replacement for the 'trx' utility used to create
+ * wrt54g .trx firmware files.  It isn't pretty, but it does the job
+ * for me.
+ *
+ * As an extension, you can specify a larger maximum length for the
+ * .trx file using '-m'.  It will be rounded up to be a multiple of 4K.
+ * NOTE: This space will be malloc()'d.
+ *
+ * August 16, 2004
+ *
+ * Sigh... Make it endian-neutral.
+ *
+ * TODO: Support '-b' option to specify offsets for each file.
+ *
+ * February 19, 2005 - mbm
+ *
+ * Add -a (align offset) and -b (absolute offset)
+ *
+ * March 24, 2010 - markus
+ *
+ * extend trx header struct for new version
+ * assume v1 for as default
+ * Add option -2 to allow v2 header
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)		bswap_32(X)
+#define LOAD32_LE(X)		bswap_32(X)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)		(X)
+#define LOAD32_LE(X)		(X)
+#else
+#error unkown endianness!
+#endif
+
+uint32_t crc32buf(char *buf, size_t len);
+
+/**********************************************************************/
+/* from trxhdr.h */
+
+#define TRX_MAGIC	0x30524448	/* "HDR0" */
+#define TRX_MAX_LEN	0x720000
+#define TRX_NO_HEADER	1		/* Do not write TRX header */
+
+struct trx_header {
+	uint32_t magic;			/* "HDR0" */
+	uint32_t len;			/* Length of file including header */
+	uint32_t crc32;			/* 32-bit CRC from flag_version to end of file */
+	uint32_t flag_version;	/* 0:15 flags, 16:31 version */
+	uint32_t offsets[4];	/* Offsets of partitions from start of header */
+};
+
+/**********************************************************************/
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+	fprintf(stderr, "Usage:\n");
+	fprintf(stderr, " trx [-2] [-o outfile] [-m maxlen] [-a align] [-b absolute offset] [-x relative offset]\n");
+	fprintf(stderr, "     [-f file] [-f file [-f file [-f file (v2 only)]]]\n");
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+	FILE *out = stdout;
+	FILE *in;
+	char *ofn = NULL;
+	char *buf;
+	char *e;
+	int c, i, append = 0;
+	size_t n;
+	ssize_t n2;
+	uint32_t cur_len, fsmark=0;
+	unsigned long maxlen = TRX_MAX_LEN;
+	struct trx_header *p;
+	char trx_version = 1;
+	unsigned char binheader[32];
+
+	fprintf(stderr, "mjn3's trx replacement - v0.81.1\n");
+
+	if (!(buf = malloc(maxlen))) {
+		fprintf(stderr, "malloc failed\n");
+		return EXIT_FAILURE;
+	}
+
+	p = (struct trx_header *) buf;
+
+	p->magic = STORE32_LE(TRX_MAGIC);
+	cur_len = sizeof(struct trx_header) - 4; /* assume v1 header */
+
+	in = NULL;
+	i = 0;
+
+	while ((c = getopt(argc, argv, "-:2o:m:a:x:b:f:A:F:")) != -1) {
+		switch (c) {
+			case '2':
+				/* take care that nothing was written to buf so far */
+				if (cur_len != sizeof(struct trx_header) - 4) {
+					fprintf(stderr, "-2 has to be used before any other argument!\n");
+				}
+				else {
+					trx_version = 2;
+					cur_len += 4;
+				}
+				break;
+			case 'F':
+				fsmark = cur_len;
+			case 'A':
+				append = 1;
+				/* fall through */
+			case 'f':
+			case 1:
+				if (!append)
+					p->offsets[i++] = STORE32_LE(cur_len);
+
+				if (!(in = fopen(optarg, "r"))) {
+					fprintf(stderr, "can not open \"%s\" for reading\n", optarg);
+					usage();
+				}
+				n = fread(buf + cur_len, 1, maxlen - cur_len, in);
+				if (!feof(in)) {
+					fprintf(stderr, "fread failure or file \"%s\" too large\n",optarg);
+					fclose(in);
+					return EXIT_FAILURE;
+				}
+				fclose(in);
+#undef  ROUND
+#define ROUND 4
+				if (n & (ROUND-1)) {
+					memset(buf + cur_len + n, 0, ROUND - (n & (ROUND-1)));
+					n += ROUND - (n & (ROUND-1));
+				}
+				cur_len += n;
+				append = 0;
+
+				break;
+			case 'o':
+				ofn = optarg;
+				if (ofn && !(out = fopen(ofn, "w"))) {
+					fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+					usage();
+				}
+
+				break;
+			case 'm':
+				errno = 0;
+				maxlen = strtoul(optarg, &e, 0);
+				if (errno || (e == optarg) || *e) {
+					fprintf(stderr, "illegal numeric string\n");
+					usage();
+				}
+#undef  ROUND
+#define ROUND 0x1000
+				if (maxlen & (ROUND-1)) {
+					maxlen += (ROUND - (maxlen & (ROUND-1)));
+				}
+				if (maxlen < ROUND) {
+					fprintf(stderr, "maxlen too small (or wrapped)\n");
+					usage();
+				}
+				if (maxlen > TRX_MAX_LEN) {
+					fprintf(stderr, "WARNING: maxlen exceeds default maximum!  Beware of overwriting nvram!\n");
+				}
+				if (!(buf = realloc(buf,maxlen))) {
+					fprintf(stderr, "realloc failed");
+					return EXIT_FAILURE;
+				}
+				p = (struct trx_header *) buf;
+				break;
+			case 'a':
+				errno = 0;
+				n = strtoul(optarg, &e, 0);
+				if (errno || (e == optarg) || *e) {
+					fprintf(stderr, "illegal numeric string\n");
+					usage();
+				}
+				if (cur_len & (n-1)) {
+					n = n - (cur_len & (n-1));
+					memset(buf + cur_len, 0, n);
+					cur_len += n;
+				}
+				break;
+			case 'b':
+				errno = 0;
+				n = strtoul(optarg, &e, 0);
+				if (errno || (e == optarg) || *e) {
+					fprintf(stderr, "illegal numeric string\n");
+					usage();
+				}
+				if (n < cur_len) {
+					fprintf(stderr, "WARNING: current length exceeds -b %d offset\n",(int) n);
+				} else {
+					memset(buf + cur_len, 0, n - cur_len);
+					cur_len = n;
+				}
+				break;
+			case 'x':
+				errno = 0;
+				n2 = strtol(optarg, &e, 0);
+				if (errno || (e == optarg) || *e) {
+					fprintf(stderr, "illegal numeric string\n");
+					usage();
+				}
+				if (n2 < 0) {
+					if (-n2 > cur_len) {
+						fprintf(stderr, "WARNING: current length smaller then -x %d offset\n",(int) n2);
+						cur_len = 0;
+					} else
+						cur_len += n2;
+				} else {
+					memset(buf + cur_len, 0, n2);
+					cur_len += n2;
+				}
+
+				break;
+			default:
+				usage();
+		}
+	}
+	p->flag_version = STORE32_LE((trx_version << 16));
+
+	if (!in) {
+		fprintf(stderr, "we require atleast one filename\n");
+		usage();
+	}
+
+#undef  ROUND
+#define ROUND 0x1000
+	n = cur_len & (ROUND-1);
+	if (n) {
+		memset(buf + cur_len, 0, ROUND - n);
+		cur_len += ROUND - n;
+	}
+
+	/* for TRXv2 set bin-header Flags to 0xFF for CRC calculation like CFE does */
+	if (trx_version == 2) {
+		if(cur_len - LOAD32_LE(p->offsets[3]) < sizeof(binheader)) {
+			fprintf(stderr, "TRXv2 binheader too small!\n");
+			return EXIT_FAILURE;
+		}
+		memcpy(binheader, buf + LOAD32_LE(p->offsets[3]), sizeof(binheader)); /* save header */
+		memset(buf + LOAD32_LE(p->offsets[3]) + 22, 0xFF, 8); /* set stable and try1-3 to 0xFF */
+	}
+
+	p->crc32 = crc32buf((char *) &p->flag_version,
+						((fsmark)?fsmark:cur_len) - offsetof(struct trx_header, flag_version));
+	p->crc32 = STORE32_LE(p->crc32);
+
+	p->len = STORE32_LE((fsmark) ? fsmark : cur_len);
+
+	/* restore TRXv2 bin-header */
+	if (trx_version == 2) {
+		memcpy(buf + LOAD32_LE(p->offsets[3]), binheader, sizeof(binheader));
+	}
+
+	if (!fwrite(buf, cur_len, 1, out) || fflush(out)) {
+		fprintf(stderr, "fwrite failed\n");
+		return EXIT_FAILURE;
+	}
+
+	fclose(out);
+
+	return EXIT_SUCCESS;
+}
+
+/**********************************************************************/
+/* The following was grabbed and tweaked from the old snippets collection
+ * of public domain C code. */
+
+/**********************************************************************\
+|* Demonstration program to compute the 32-bit CRC used as the frame  *|
+|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *|
+|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *|
+|* protocol).  The 32-bit FCS was added via the Federal Register,     *|
+|* 1 June 1982, p.23798.  I presume but don't know for certain that   *|
+|* this polynomial is or will be included in CCITT V.41, which        *|
+|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *|
+|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *|
+|* errors by a factor of 10^-5 over 16-bit FCS.                       *|
+\**********************************************************************/
+
+/* Copyright (C) 1986 Gary S. Brown.  You may use this program, or
+   code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms.  The  */
+/* polynomial is                                                       */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in  */
+/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
+/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
+/* the MSB being 1.                                                    */
+
+/* Note that the usual hardware shift register implementation, which   */
+/* is what we're using (we're merely optimizing it by doing eight-bit  */
+/* chunks at a time) shifts bits into the lowest-order term.  In our   */
+/* implementation, that means shifting towards the right.  Why do we   */
+/* do it this way?  Because the calculated CRC must be transmitted in  */
+/* order from highest-order term to lowest-order term.  UARTs transmit */
+/* characters in order from LSB to MSB.  By storing the CRC this way,  */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part.  Reception works similarly.                  */
+
+/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
+/*                                                                     */
+/*  1. The table can be generated at runtime if desired; code to do so */
+/*     is shown later.  It might not be obvious, but the feedback      */
+/*     terms simply represent the results of eight shift/xor opera-    */
+/*     tions for all combinations of data and CRC register values.     */
+/*                                                                     */
+/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
+/*     be they sixteen or thirty-two bits wide.  You simply choose the */
+/*     appropriate table.  Alternatively, because the table can be     */
+/*     generated at runtime, you can start by generating the table for */
+/*     the polynomial in question and use exactly the same "updcrc",   */
+/*     if your application needn't simultaneously handle two CRC       */
+/*     polynomials.  (Note, however, that XMODEM is strange.)          */
+/*                                                                     */
+/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
+/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
+/*                                                                     */
+/*  4. The values must be right-shifted by eight bits by the "updcrc"  */
+/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
+/*     hardware you could probably optimize the shift in assembler by  */
+/*     using byte-swap instructions.                                   */
+
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+      uint32_t crc;
+
+      crc = 0xFFFFFFFF;
+
+      for ( ; len; --len, ++buf)
+      {
+            crc = UPDC32(*buf, crc);
+      }
+
+      return crc;
+}
diff --git a/tools/firmware-utils/src/trx2edips.c b/tools/firmware-utils/src/trx2edips.c
new file mode 100644
index 0000000000..f8d068d502
--- /dev/null
+++ b/tools/firmware-utils/src/trx2edips.c
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X)		bswap_32(X)
+#define LOAD32_LE(X)		bswap_32(X)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X)		(X)
+#define LOAD32_LE(X)		(X)
+#else
+#error unkown endianness!
+#endif
+
+/**********************************************************************/
+/* from trxhdr.h */
+
+#define TRX_MAGIC	0x30524448	/* "HDR0" */
+#define TRX_VERSION	1
+#define TRX_MAX_LEN	0x5A0000
+#define TRX_NO_HEADER	1		/* Do not write TRX header */
+
+struct trx_header {
+	uint32_t magic;			/* "HDR0" */
+	uint32_t len;			/* Length of file including header */
+	uint32_t crc32;			/* 32-bit CRC from flag_version to end of file */
+	uint32_t flag_version;	/* 0:15 flags, 16:31 version */
+	uint32_t offsets[3];	/* Offsets of partitions from start of header */
+};
+
+
+struct edimax_header {
+	uint32_t sign;			/* signature for header */
+	uint32_t length;		/* start address but doesn't seems to be used... */
+	uint32_t start_addr;		/* length of data, not used too ...*/
+};
+
+
+#define EDIMAX_PS16	0x36315350	/* "PS16" */
+#define EDIMAX_HDR_LEN 	0xc
+
+
+/**********************************************************************/
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+	uint32_t crc;
+
+	crc = 0xFFFFFFFF;
+
+	for (; len; --len, ++buf)
+		crc = UPDC32(*buf, crc);
+
+	return crc;
+}
+
+
+int main(int argc, char *argv[])
+{
+	FILE *fpIn = NULL;
+	FILE *fpOut = NULL;
+	struct edimax_header eh;
+	size_t res;
+	int length;
+
+	char *buf;
+	struct trx_header *p;
+
+	if (argc != 3) {
+		printf("Usage: %s <input file> <output file>\n", argv[0]);
+		return -1;
+	}
+
+	fpIn = fopen(argv[1], "rb");
+	if (fpIn == NULL) {
+		fprintf(stderr, "Unable to open %s\n", argv[1]);
+		return EXIT_FAILURE;
+	}
+	/* compute the length of the file */
+	fseek(fpIn, 0, SEEK_END);
+	length = ftell(fpIn);
+	/* alloc enough memory to store the file */
+	buf = (char *)malloc(length);
+	if (!buf) {
+		fprintf(stderr, "malloc of buffers failed\n");
+		return EXIT_FAILURE;
+	}
+	
+	rewind(fpIn);
+	/* read the whole file*/
+	res = fread(buf, 1, length, fpIn);
+
+	p = (struct trx_header *)buf;
+	if (LOAD32_LE(p->magic) != TRX_MAGIC) {
+		fprintf(stderr, "Not a trx file...%x\n", LOAD32_LE(p->magic));
+		return EXIT_FAILURE;
+	}
+
+	fclose(fpIn);
+
+	fpOut = fopen(argv[2], "wb+");
+	if (fpOut == NULL) {
+		fprintf(stderr, "Unable to open %s\n", argv[2]);
+		return EXIT_FAILURE;
+	}
+	/* make the 3 partition beeing 12 bytes closer from the header */
+	memcpy(buf + LOAD32_LE(p->offsets[2]) - EDIMAX_HDR_LEN, buf + LOAD32_LE(p->offsets[2]), length - LOAD32_LE(p->offsets[2]));
+	/* recompute the crc32 check */
+	p->crc32 = STORE32_LE(crc32buf((char *) &p->flag_version, length - offsetof(struct trx_header, flag_version)));
+
+	eh.sign = STORE32_LE(EDIMAX_PS16);
+	eh.length = STORE32_LE(length);
+	eh.start_addr = STORE32_LE(0x80500000);
+
+	/* write the modified file */
+	fwrite(&eh, sizeof(struct edimax_header), 1, fpOut);
+	fwrite(buf, sizeof(char), length, fpOut);
+	fclose(fpOut);
+}
+
diff --git a/tools/firmware-utils/src/trx2usr.c b/tools/firmware-utils/src/trx2usr.c
new file mode 100644
index 0000000000..96c0ab285e
--- /dev/null
+++ b/tools/firmware-utils/src/trx2usr.c
@@ -0,0 +1,186 @@
+/*
+ * trx2usr - Convert a TRX firmware image to a U.S. Robotics firmware
+ *           image by prepending a 28-byte header.
+ *
+ * This program was modeled after the usr-hdr.c program from the GPL'ed
+ * firmware for the U.S. Robotics Wireless MAXg Router (USR5461). The
+ * output file of this program can be uploaded via the web interface
+ * of the original U.S. Robotics firmware. Note that this program only
+ * works on a little-endian host platform.
+ *
+ * Copyright (C) 2006 Dick Streefland
+ *
+ * This is free software, licensed under the terms of the GNU General
+ * Public License as published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define	TRX_MAGIC		"HDR0"
+
+#define	USR_MAGIC		0x30525355	// "USR0"
+#define	EPI_VERSION		0x06235d03
+#define	COMPAT_ID		1		// USR5461
+#define	HARDWARE_REV		1
+
+#define	CRC32_INIT		0xffffffff
+#define	CHUNK			(64*1024)
+
+typedef	unsigned char		uint8;
+typedef	unsigned short		uint16;
+typedef	unsigned int		uint32;
+
+struct	usr_header
+{
+	uint32	magic;			// "USR0" 
+	uint32	len;			// file length without this header 
+	uint32	crc32;			// CRC32 of the file without header 
+	uint32	version;		// EPI_VERSION
+	uint16	compatibility_id;	// COMPAT_ID
+	uint16	hardware_revision;	// HARDWARE_REV
+	uint32	reserved[2];
+};
+	
+static	const	uint32		crc_32_tab [] =	// CRC polynomial 0xedb88320
+{
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static	char	buf[CHUNK];
+
+static	uint32	crc32(uint32 crc, uint8* p, size_t n)
+{
+	while (n--)
+	{
+		crc = crc_32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+	}
+	return crc;
+}
+
+static	int	trx2usr(FILE* trx, FILE* usr)
+{
+	struct usr_header	hdr;
+	size_t			n;
+
+	hdr.magic		= USR_MAGIC;
+	hdr.len			= 0;
+	hdr.crc32		= CRC32_INIT;
+	hdr.version		= EPI_VERSION;
+	hdr.compatibility_id	= COMPAT_ID;
+	hdr.hardware_revision	= HARDWARE_REV;
+	hdr.reserved[0]		= 0;
+	hdr.reserved[1]		= 0;
+	fwrite(& hdr, sizeof(hdr), 1, usr);
+	while ((n = fread(buf, 1, CHUNK, trx)))
+	{
+		if (hdr.len == 0 && strncmp(buf, TRX_MAGIC, strlen(TRX_MAGIC)) != 0)
+		{
+			break;
+		}
+		fwrite(& buf, 1, n, usr);
+		hdr.len += n;
+		hdr.crc32 = crc32( hdr.crc32, (uint8 *) & buf, n);
+	}
+	fseek(usr, 0L, SEEK_SET);
+	fwrite(& hdr, sizeof(hdr), 1, usr);
+	if (n != 0)
+	{
+		fprintf(stderr, "Input is not a TRX file\n");
+		return 1;
+	}
+	if (hdr.len == 0)
+	{
+		fprintf(stderr, "Empty input\n");
+		return 1;
+	}
+	if (ferror(trx))
+	{
+		fprintf(stderr, "Read error\n");
+		return 1;
+	}
+	if (ferror(usr))
+	{
+		fprintf(stderr, "Write error\n");
+		return 1;
+	}
+	return 0;
+}
+
+extern	int	main(int argc, char *argv[])
+{
+	FILE*	in;
+	FILE*	out;
+	int	ret;
+
+	if (argc != 3)
+	{
+		fprintf(stderr, "Usage: trx2usr <trx input> <usr output>\n");
+		exit(2);
+	}
+	in  = fopen(argv[1], "rb");
+	if (!in)
+	{
+		fprintf(stderr, "Cannot open \"%s\": %s\n", argv[1], strerror(errno));
+		exit(1);
+	}
+	out = fopen(argv[2], "wb");
+	if (!out)
+	{
+		fprintf(stderr, "Cannot create \"%s\": %s\n", argv[2], strerror(errno));
+		exit(1);
+	}
+	ret = trx2usr(in, out);
+	fclose(in);
+	fclose(out);
+	if (ret)
+	{
+		unlink(argv[2]);
+	}
+	return ret;
+}
diff --git a/tools/firmware-utils/src/wrt400n.c b/tools/firmware-utils/src/wrt400n.c
new file mode 100644
index 0000000000..1cf1debc89
--- /dev/null
+++ b/tools/firmware-utils/src/wrt400n.c
@@ -0,0 +1,336 @@
+/*
+ * WRT400n - Firmware Generation Creator
+ *
+ * Creates a firmware image for the Linksys WRT400n router,
+ * that can be uploaded via the firmware upload page,
+ * from a kernel image file and root fs file
+ *
+ *	Author: Sandeep Mistry
+ */
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cyg_crc.h"
+
+// https://dev.openwrt.org/browser/trunk/target/linux/rdc-2.6/files/drivers/mtd/maps/rdc3210.c
+static uint32_t crctab[257] =
+{
+	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+	0
+};
+
+static uint32_t crc32(uint8_t* buf, uint32_t len)
+{
+	register int i;
+	uint32_t sum;
+	register uint32_t s0;
+	s0 = ~0;
+	for (i = 0; i < len; i++)
+	{
+		s0 = (s0 >> 8) ^ crctab[(uint8_t) (s0 & 0xFF) ^ buf[i]];
+	}
+	sum = ~s0;
+	return sum;
+}
+
+#define HEADERSIZE	60
+#define MAGIC		"GMTKRT400N"
+
+// global variables
+uint8_t kernelbuf[0x100000];	// kernel - lzma - uImage
+uint8_t rootfsbuf[0x2FFFC4];	// root - squashfs
+
+uint8_t buf[0x400000];		// buffer for image
+
+
+// Header format:
+//
+//		GPL Tarball: http://downloads.linksysbycisco.com/downloads/WRT400N_1.0.01.19_US.tar,0.gz
+//		File: WRT400N_1.0.01.19_US/FW_WRT400N_1.0.01.19_US_20081229/GTK/user/include/fw_upgrade.h
+//
+//
+//		Struct:
+//			typedef struct
+//			{
+//				UINT32		checksum;		/* CRC32 */
+//				UINT8			magic[11];		/* The value of GTIMG_MAGIC */
+//				UINT32		kernel_length;		/* The length of the kernel image */
+//				//UINT32		kernel_entry_point;	/* Kernel's entry point for RedBoot's information */
+//				UINT32		kernel_upgrade_flag;	/* Set to 1 if we need to upgrade the kernel parition of the Flash */
+//				UINT32		rootfs_length;		/* The length of the rootfs image */
+//				//UINT32		rootfs_entry_point;	/* Not in use */
+//				UINT32		rootfs_upgrade_flag;	/* Set to 1 if we need to upgrade the rootfs parition of the Flash */
+//
+//				// Add 3 items by Vic Yu, 2006-05/10
+//				UINT32		kernel_checksum;
+//				UINT32		rootfs_checksum;
+//				UINT32		fw_totalsize;
+//				UINT32		reserved[4];
+//			}imghdr_t , *pLinuxFWHeader_T;
+//
+//
+//		Description
+//			- checksum: 			CRC32 of kernel and root fs, back to back
+//			- magic:				GMTKRT400N
+//			- kernel_length:		kernel length in bytes
+//			- kernel_upgrade_flag:	should we upgrade the kernel - set to 1
+//			- rootfs_length:		root fs length in byte
+//			- rootfs_upgrade_flag:	should we upgrade the root fs - set to 1
+//			- kernel_checksum: 		Gary S. Brown's 32 bit CRC algorithm for kernel, with remaining bits
+//									set to 0xFF upto 0x100000 bytes (total length)
+//			- rootfs_checksum:		Gary S. Brown's 32 bit CRC algorithm for root fs, with remaining bits
+//									set to 0xFF upto 0x2FFFC4 bytes	(total length)
+//			- fw_totalsize:			total firmware image file length (header length + kernel length + root fs length)
+//			- reserved[4]:			reserved ??? - set to all 0xFF
+
+
+
+int main(int argc, char *argv[])
+{
+	// file descriptors ...
+	int 		kernelfd		= -1;
+	int 		rootfsfd			= -1;
+	int			outfd			= -1;
+
+	char*		kernelfilename	= NULL;
+	char*		rootfsfilename	= NULL;
+	char*		outputfilename	= NULL;
+
+	// file sizes
+	uint32_t 	kernelsize 		= 0;
+	uint32_t 	rootfssize 		= 0;
+	uint32_t 	totalsize 		= 0;
+
+	// header flags
+	uint32_t 	kernelflag 		= 0;
+	uint32_t 	rootfsflag 		= 0;
+
+	// checksums
+	uint32_t 	kernelchecksum 	= 0;
+	uint32_t 	rootfschecksum 	= 0;
+	uint32_t	crc				= 0;
+
+	if(argc != 4)
+	{
+		printf("Usage:\n\t%s <kernel file> <rootfs file> <output file>\n", argv[0]);
+		return 1;
+	}
+
+	kernelfilename = argv[1];
+	rootfsfilename = argv[2];
+	outputfilename = argv[3];
+
+	// Fill the kernel, rootfs, main buffer
+	memset(kernelbuf, 0xFF, sizeof(kernelbuf));
+	memset(rootfsbuf, 0xFF, sizeof(rootfsbuf));
+	memset(buf, 0xFF, sizeof(buf));
+
+	// open the kernel ..
+	kernelfd = open(kernelfilename, O_RDONLY);
+
+	if(kernelfd == -1)
+	{
+		printf("Error: opening '%s'\n", kernelfilename);
+		goto done;
+	}
+
+	// read in the kernel ...
+	kernelsize = read(kernelfd, kernelbuf, sizeof(kernelbuf));
+
+	if(kernelsize == -1)
+	{
+		printf("Error: reading '%s'\n", kernelfilename);
+		goto done;
+	}
+
+	// calculate the kernel checksum ...
+	kernelchecksum = cyg_crc32_accumulate(0, kernelbuf, sizeof(kernelbuf));
+
+	// print out stats
+	printf("%s: size %d (0x%x), crc32 = 0x%x\n", kernelfilename, kernelsize, kernelsize, kernelchecksum);
+
+
+	// open the root fs ..
+	rootfsfd = open(rootfsfilename, O_RDONLY);
+
+	if(rootfsfd == -1)
+	{
+		printf("Error: opening '%s'\n", rootfsfilename);
+		goto done;
+	}
+
+	// read in the root fs ..
+	rootfssize = read(rootfsfd, rootfsbuf, sizeof(rootfsbuf));
+
+	if(rootfssize == -1)
+	{
+		printf("Error: reading '%s'\n", rootfsfilename);
+		goto done;
+	}
+
+	// calculate the root fs checksum ...
+	rootfschecksum = cyg_crc32_accumulate(0, rootfsbuf, sizeof(rootfsbuf));
+
+	// print out stats
+	printf("%s: size %d (0x%x), crc32 = 0x%x\n", rootfsfilename, rootfssize, rootfssize, rootfschecksum);
+
+
+	// now for the header ...
+
+	totalsize = HEADERSIZE;
+
+	// copy over kernel
+	memcpy(buf + totalsize, kernelbuf, kernelsize);
+	totalsize += kernelsize;
+
+	// copy over root fs
+	memcpy(buf + totalsize, rootfsbuf, rootfssize);
+	totalsize += rootfssize;
+
+	// calculate crc
+	crc = crc32(buf + HEADERSIZE, totalsize - HEADERSIZE);
+
+	// print some stats out
+	printf("crc = 0x%x, total size = %d (0x%x)\n", crc, totalsize, totalsize);
+
+	// copy crc into header
+	crc = htonl(crc);
+	memcpy(buf, &crc, sizeof(crc));
+
+	// copy over magic
+	strcpy((char *)buf + 4, MAGIC);
+
+	// copy over kernel size
+	kernelsize = htonl(kernelsize);
+	memcpy(buf + 16, &kernelsize, sizeof(kernelsize));
+
+	// copy over kernal flag
+	kernelflag = htonl(0x1);
+	memcpy(buf + 20, &kernelflag, sizeof(kernelflag));
+
+	// copy over root fs size
+	rootfssize = htonl(rootfssize);
+	memcpy(buf + 24, &rootfssize, sizeof(rootfssize));
+
+	// copy over root fs flag
+	rootfsflag = htonl(0x1);
+	memcpy(buf + 28, &rootfsflag, sizeof(rootfsflag));
+
+	// copy over kernel check sum
+	kernelchecksum = htonl(kernelchecksum);
+	memcpy(buf + 32, &kernelchecksum, sizeof(kernelchecksum));
+
+	// copy over root fs checksum
+	rootfschecksum = htonl(rootfschecksum);
+	memcpy(buf + 36, &rootfschecksum, sizeof(rootfschecksum));
+
+	// copy over total size
+	totalsize = htonl(totalsize);
+	memcpy(buf + 40, &totalsize, sizeof(totalsize));
+
+	// undo the htonl (for write)
+	totalsize = htonl(totalsize);
+
+
+	// write out the file from the buffer
+	outfd = open(outputfilename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	if(outfd == -1)
+	{
+		printf("ERROR: opening '%s' for write\n", outputfilename);
+	}
+
+	write(outfd, buf, totalsize);
+
+done:
+	// close open fd's
+
+	if(kernelfd != -1)
+	{
+		close(kernelfd);
+		kernelfd = -1;
+	}
+
+	if(rootfsfd != -1)
+	{
+		close(rootfsfd);
+		rootfsfd = -1;
+	}
+
+	if(outfd != -1)
+	{
+		close(outfd);
+		outfd = -1;
+	}
+
+	return 0;
+}
diff --git a/tools/firmware-utils/src/xorimage.c b/tools/firmware-utils/src/xorimage.c
new file mode 100644
index 0000000000..b5ab83fa7a
--- /dev/null
+++ b/tools/firmware-utils/src/xorimage.c
@@ -0,0 +1,135 @@
+/*
+ * xorimage.c - partially based on OpenWrt's addpattern.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static char default_pattern[] = "12345678";
+
+
+int xor_data(uint8_t *data, size_t len, const uint8_t *pattern, int p_len, int p_off)
+{
+	int offset = p_off;
+	while (len--) {
+		*data ^= pattern[offset];
+		data++;
+		offset = (offset + 1) % p_len;
+	}
+	return offset;
+}
+
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+	fprintf(stderr, "Usage: xorimage [-i infile] [-o outfile] [-p <pattern>]\n");
+	exit(EXIT_FAILURE);
+}
+
+
+int main(int argc, char **argv)
+{
+	char buf[1024];	/* keep this at 1k or adjust garbage calc below */
+	FILE *in = stdin;
+	FILE *out = stdout;
+	char *ifn = NULL;
+	char *ofn = NULL;
+	const char *pattern = default_pattern;
+	int c;
+	int v0, v1, v2;
+	size_t n;
+	int p_len, p_off = 0;
+
+	while ((c = getopt(argc, argv, "i:o:p:h")) != -1) {
+		switch (c) {
+			case 'i':
+				ifn = optarg;
+				break;
+			case 'o':
+				ofn = optarg;
+				break;
+			case 'p':
+				pattern = optarg;
+				break;
+			case 'h':
+			default:
+				usage();
+		}
+	}
+
+	if (optind != argc || optind == 1) {
+		fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+		usage();
+	}
+
+	if (ifn && !(in = fopen(ifn, "r"))) {
+		fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+		usage();
+	}
+
+	if (ofn && !(out = fopen(ofn, "w"))) {
+		fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+		usage();
+	}
+
+	p_len = strlen(pattern);
+
+	if (p_len == 0) {
+		fprintf(stderr, "pattern cannot be empty\n");
+		usage();
+	}
+
+
+	while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (n < sizeof(buf)) {
+			if (ferror(in)) {
+			FREAD_ERROR:
+				fprintf(stderr, "fread error\n");
+				return EXIT_FAILURE;
+			}
+		}
+
+		p_off = xor_data(buf, n, pattern, p_len, p_off);
+
+		if (!fwrite(buf, n, 1, out)) {
+		FWRITE_ERROR:
+			fprintf(stderr, "fwrite error\n");
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (ferror(in)) {
+		goto FREAD_ERROR;
+	}
+
+	if (fflush(out)) {
+		goto FWRITE_ERROR;
+	}
+
+	fclose(in);
+	fclose(out);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/firmware-utils/src/zyimage.c b/tools/firmware-utils/src/zyimage.c
new file mode 100644
index 0000000000..6aacf2ff1b
--- /dev/null
+++ b/tools/firmware-utils/src/zyimage.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 Soul Trace <S-trace@list.ru>
+ *
+ * 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.
+ *
+ */
+
+#define _POSIX_SOURCE
+#define _POSIX_C_SOURCE 199309L /* getopt */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+
+#define szbuf 32768
+
+u_int32_t crc_tab[256];
+
+u_int32_t chksum_crc32 (FILE *f)
+{
+  register unsigned long crc;
+  unsigned long i, j;
+  char *buffer = malloc(szbuf);
+  char *buf;
+
+  crc = 0xFFFFFFFF;
+  while (!feof(f))
+  {
+    j = fread(buffer, 1, szbuf, f);
+    buf = buffer;
+    for (i = 0; i < j; i++)
+      crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *buf++) & 0xFF];
+  }
+  free(buffer);
+  return crc;
+}
+
+void chksum_crc32gentab ()
+{
+  unsigned long crc, poly;
+  int i, j;
+
+  poly = 0xEDB88320L;
+  for (i = 0; i < 256; i++)
+  {
+    crc = i;
+    for (j = 8; j > 0; j--)
+    {
+      if (crc & 1)
+        crc = (crc >> 1) ^ poly;
+      else
+        crc >>= 1;
+    }
+    crc_tab[i] = crc;
+  }
+}
+
+void usage(char *progname)
+{
+  printf("Usage: %s [ -v Version ] [ -d Device_ID ] <input file>\n", progname);
+  exit(1);
+}
+
+int main(int argc, char *argv[]) {
+  struct signature
+  {
+    const char magic[4];
+    unsigned int device_id;
+    char firmware_version[48];
+    unsigned int crc32;
+  }
+  sign =
+  {
+    { 'Z', 'N', 'B', 'G' },
+    1,
+    { "V.1.0.0(1.0.0)" },
+    0
+  };
+  FILE *f;
+  struct signature oldsign;
+  char *filename;
+  static const char *optString;
+  int opt;
+
+  if (argc < 1)
+    usage(argv[0]);
+
+  optString = "v:d:h";
+  opt = getopt( argc, argv, optString );
+  while( opt != -1 ) {
+    switch( opt ) {
+      case 'v':
+        if (optarg == NULL)
+          usage(argv[0]);
+        strncpy(sign.firmware_version, optarg, sizeof(sign.firmware_version)-1);
+       sign.firmware_version[sizeof(sign.firmware_version)-1]='\0'; /* Make sure that string is terminated correctly */
+        break;
+
+      case 'd':
+        sign.device_id = atoi(optarg);
+        if (sign.device_id == 0)
+          sign.device_id = (int)strtol(optarg, NULL, 16);
+        break;
+
+      case '?':
+      case 'h':
+        usage(argv[0]);
+        break;
+
+      default:
+        break;
+    }
+
+    opt = getopt( argc, argv, optString );
+  }
+
+  chksum_crc32gentab();
+
+  filename=argv[optind];
+  if (access(filename, W_OK) || access(filename, R_OK))
+  {
+    printf("Not open input file %s\n", filename);
+    exit(1);
+  }
+  f = fopen(argv[optind], "r+");
+  if (f != NULL)
+  {
+    fseek(f, sizeof(sign)*-1, SEEK_END);
+    fread(&oldsign, sizeof(oldsign), 1, f);
+
+    if (strncmp(oldsign.magic,"ZNBG", sizeof(oldsign.magic)) == 0 )
+    {
+      printf("Image is already signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", oldsign.device_id, oldsign.firmware_version, oldsign.crc32);
+      exit(0);
+    }
+
+    fseek(f, 0, SEEK_SET);
+    sign.crc32 = chksum_crc32(f);
+    fwrite(&sign, sizeof(sign), 1, f);
+    fclose(f);
+
+    printf("Image signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", sign.device_id, sign.firmware_version, sign.crc32);
+  }
+  return 0;
+}
diff --git a/tools/firmware-utils/src/zynos.h b/tools/firmware-utils/src/zynos.h
new file mode 100644
index 0000000000..aaf0fc8a73
--- /dev/null
+++ b/tools/firmware-utils/src/zynos.h
@@ -0,0 +1,225 @@
+/*
+ *
+ *  Copyright (C) 2007-2008 OpenWrt.org
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This code was based on the information of the ZyXEL's firmware
+ *  image format written by Kolja Waschk, can be found at:
+ *  http://www.ixo.de/info/zyxel_uclinux
+ *
+ *  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.
+ *
+ */
+
+#ifndef _ZYNOS_H
+#define _ZYNOS_H
+
+#define BOOTBASE_NAME_LEN	32
+#define BOOTBASE_MAC_LEN	6
+#define BOOTBASE_FEAT_LEN	22
+
+#define BOOTEXT_DEF_SIZE	0x18000
+
+struct zyn_bootbase_info {
+	char		vendor[BOOTBASE_NAME_LEN]; /* Vendor name */
+	char		model[BOOTBASE_NAME_LEN]; /* Model name */
+	uint32_t	bootext_addr;	/* absolute address of the Boot Extension */
+	uint16_t	res0;		/* reserved/unknown */
+	uint8_t		sys_type;	/* system type */
+	uint8_t		res1;		/* reserved/unknown */
+	uint16_t	model_id;	/* model id */
+	uint8_t		feat_other[BOOTBASE_FEAT_LEN]; /* other feature bits */
+	uint8_t		feat_main;	/* main feature bits */
+	uint8_t		res2;		/* reserved/unknown */
+	uint8_t		mac[BOOTBASE_MAC_LEN]; /* mac address */
+	uint8_t		country;	/* default country code */
+	uint8_t		dbgflag;	/* debug flag */
+} __attribute__((packed));
+
+#define ROMBIN_SIG_LEN	3
+#define ROMBIN_VER_LEN	15
+
+struct zyn_rombin_hdr {
+	uint32_t	addr;		/* load address of the object */
+	uint16_t	res0;		/* unknown/unused */
+	char		sig[ROMBIN_SIG_LEN];	/* magic, must be "SIG" */
+	uint8_t		type;		/* type of the object */
+	uint32_t	osize;		/* size of the uncompressed data */
+	uint32_t	csize;		/* size of the compressed data */
+	uint8_t		flags;		/* various flags */
+	uint8_t		res1;		/* unknown/unused */
+	uint16_t	ocsum;		/* csum of the uncompressed data */
+	uint16_t	ccsum;		/* csum of the compressed data */
+	char		ver[ROMBIN_VER_LEN];
+	uint32_t	mmap_addr;	/* address of the Memory Map Table*/
+	uint32_t	res2;		/* unknown/unused*/
+	uint8_t		res3;		/* unknown/unused*/
+} __attribute__((packed));
+
+#define ROMBIN_SIGNATURE	"SIG"
+
+/* Rombin flag bits */
+#define ROMBIN_FLAG_01		0x01
+#define ROMBIN_FLAG_02		0x02
+#define ROMBIN_FLAG_04		0x04
+#define ROMBIN_FLAG_08		0x08
+#define ROMBIN_FLAG_10		0x10
+#define ROMBIN_FLAG_CCSUM	0x20	/* compressed checksum is valid */
+#define ROMBIN_FLAG_OCSUM	0x40	/* original checksum is valid */
+#define ROMBIN_FLAG_COMPRESSED	0x80	/* the binary is compressed */
+
+/* Object types */
+#define OBJECT_TYPE_ROMIMG	0x01
+#define OBJECT_TYPE_ROMBOOT	0x02
+#define OBJECT_TYPE_BOOTEXT	0x03
+#define OBJECT_TYPE_ROMBIN	0x04
+#define OBJECT_TYPE_ROMDIR	0x05
+#define OBJECT_TYPE_6		0x06
+#define OBJECT_TYPE_ROMMAP	0x07
+#define OBJECT_TYPE_RAM		0x80
+#define OBJECT_TYPE_RAMCODE	0x81
+#define OBJECT_TYPE_RAMBOOT	0x82
+
+/*
+ * Memory Map Table header
+ */
+struct zyn_mmt_hdr {
+	uint16_t	count;
+	uint32_t	user_start;
+	uint32_t	user_end;
+	uint16_t	csum;
+	uint8_t		res[12];
+} __attribute__((packed));
+
+#define OBJECT_NAME_LEN		8
+
+struct zyn_mmt_item {
+	uint8_t		type;	/* type of the object */
+	uint8_t		name[OBJECT_NAME_LEN]; /* name of the object */
+	uint8_t		res0;	/* unused/unknown */
+	uint32_t	addr;
+	uint32_t	size;	/* size of the object */
+	uint8_t		res1[3]; /* unused/unknown */
+	uint8_t		type2;
+} __attribute__((packed));
+
+/*
+ * Vendor IDs
+ */
+#define ZYNOS_VENDOR_ID_ZYXEL	0
+#define ZYNOS_VENDOR_ID_NETGEAR	1
+#define ZYNOS_VENDOR_ID_DLINK	2
+#define ZYNOS_VENDOR_ID_03	3
+#define ZYNOS_VENDOR_ID_LUCENT	4
+#define ZYNOS_VENDOR_ID_O2	10
+
+/*
+ * Model IDs (in big-endian format)
+ */
+#define MID(x)	(((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8)
+
+/*
+ * Infineon/ADMtek ADM5120 based models
+ */
+#define ZYNOS_MODEL_ES_2024A		MID(  221)
+#define ZYNOS_MODEL_ES_2024PWR		MID( 4097)
+#define ZYNOS_MODEL_ES_2108		MID(61952)
+#define ZYNOS_MODEL_ES_2108_F		MID(44801)
+#define ZYNOS_MODEL_ES_2108_G		MID(62208)
+#define ZYNOS_MODEL_ES_2108_LC		MID(64512)
+#define ZYNOS_MODEL_ES_2108PWR		MID(62464)
+#define ZYNOS_MODEL_HS_100		MID(61855)
+#define ZYNOS_MODEL_HS_100W		ZYNOS_MODEL_HS_100
+#define ZYNOS_MODEL_P_334		MID(62879)
+#define ZYNOS_MODEL_P_334U		MID(56735)
+#define ZYNOS_MODEL_P_334W		MID(62367)
+#define ZYNOS_MODEL_P_334WH		MID(57344)
+#define ZYNOS_MODEL_P_334WHD		MID(57600)
+#define ZYNOS_MODEL_P_334WT		MID(61343)
+#define ZYNOS_MODEL_P_335		MID(60831)
+#define ZYNOS_MODEL_P_335PLUS		MID( 9472)
+#define ZYNOS_MODEL_P_335U		MID(56479)
+#define ZYNOS_MODEL_P_335WT		ZYNOS_MODEL_P_335
+
+/*
+ * Texas Instruments AR7 based models
+ */
+#define ZYNOS_MODEL_P_2602H_61C		MID( 3229)
+#define ZYNOS_MODEL_P_2602H_63C		MID( 3485)
+#define ZYNOS_MODEL_P_2602H_D1A		/* n.a. */
+#define ZYNOS_MODEL_P_2602H_D3A		/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_61C	/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_63		/* n.a. */
+#define ZYNOS_MODEL_P_2602HW_63C	ZYNOS_MODEL_P_2602H_63C
+#define ZYNOS_MODEL_P_2602HW_D1A	MID( 6301)
+#define ZYNOS_MODEL_P_2602HW_D3A	/* n.a. */
+#define ZYNOS_MODEL_P_2602HWL_61	MID( 1181)
+#define ZYNOS_MODEL_P_2602HWL_61C	ZYNOS_MODEL_P_2602H_61C
+#define ZYNOS_MODEL_P_2602HWL_63C	ZYNOS_MODEL_P_2602H_63C
+#define ZYNOS_MODEL_P_2602HWL_D1A	ZYNOS_MODEL_P_2602HW_D1A
+#define ZYNOS_MODEL_P_2602HWL_D3A	MID( 7581)
+#define ZYNOS_MODEL_P_2602HWN_D7A	MID(30464)
+#define ZYNOS_MODEL_P_2602HWNLI_D7A	MID( 6813)
+
+#define ZYNOS_MODEL_P_2602R_61		MID( 2205)
+#define ZYNOS_MODEL_P_2602R_63		MID( 3997)
+#define ZYNOS_MODEL_P_2602R_D1A		/* n.a. */
+#define ZYNOS_MODEL_P_2602R_D3A		/* n.a. */
+#define ZYNOS_MODEL_P_2602RL_D1A	MID( 6045)
+#define ZYNOS_MODEL_P_2602RL_D3A	MID( 7069)
+
+#define ZYNOS_MODEL_P_660H_61		MID(19346)
+#define ZYNOS_MODEL_P_660H_63		MID(22162)
+#define ZYNOS_MODEL_P_660H_67		/* n.a. */
+#define ZYNOS_MODEL_P_660H_D1		MID( 7066)
+#define ZYNOS_MODEL_P_660H_D3		MID(13210)
+
+#define ZYNOS_MODEL_P_660HW_61		ZYNOS_MODEL_P_660H_61
+#define ZYNOS_MODEL_P_660HW_63		ZYNOS_MODEL_P_660H_63
+#define ZYNOS_MODEL_P_660HW_67		ZYNOS_MODEL_P_660HW_63
+#define ZYNOS_MODEL_P_660HW_D1		MID( 9114)
+#define ZYNOS_MODEL_P_660HW_D3		MID(12698)
+
+#define ZYNOS_MODEL_P_660R_61		MID(20882)
+#define ZYNOS_MODEL_P_660R_61C		MID( 1178)
+#define ZYNOS_MODEL_P_660R_63		MID(21138)
+#define ZYNOS_MODEL_P_660R_63C		MID(  922)
+#define ZYNOS_MODEL_P_660R_67		ZYNOS_MODEL_P_660R_63
+#define ZYNOS_MODEL_P_660R_67C		/* n.a. */
+#define ZYNOS_MODEL_P_660R_D1		MID( 7322)
+#define ZYNOS_MODEL_P_660R_D3		MID(10138)
+
+#define ZYNOS_MODEL_P_661H_61		MID(19346)
+#define ZYNOS_MODEL_P_661H_63		MID( 1946)
+#define ZYNOS_MODEL_P_661H_D1		MID(10650)
+#define ZYNOS_MODEL_P_661H_D3		MID(12442)
+
+#define ZYNOS_MODEL_P_661HW_61		ZYNOS_MODEL_P_661H_61
+#define ZYNOS_MODEL_P_661HW_63		ZYNOS_MODEL_P_661H_63
+#define ZYNOS_MODEL_P_661HW_D1		MID(10906)
+#define ZYNOS_MODEL_P_661HW_D3		MID(14746)
+
+#define ZYNOS_MODEL_P_662H_61		MID(22418)
+#define ZYNOS_MODEL_P_662H_63		/* n.a. */
+#define ZYNOS_MODEL_P_662H_67		/* n.a. */
+#define ZYNOS_MODEL_P_662H_D1		/* n.a. */
+#define ZYNOS_MODEL_P_662H_D3		/* n.a. */
+
+#define ZYNOS_MODEL_P_662HW_61		/* n.a. */
+#define ZYNOS_MODEL_P_662HW_63		MID(22674)
+#define ZYNOS_MODEL_P_662HW_67		/* n.a. */
+#define ZYNOS_MODEL_P_662HW_D1		MID(10394)
+#define ZYNOS_MODEL_P_662HW_D3		MID(12954)
+
+/* OEM boards */
+#define ZYNOS_MODEL_O2SURF		ZYNOS_MODEL_P_2602HWN_D7A
+
+/* Atheros AR2318 based boards */
+#define ZYNOS_MODEL_NBG_318S		MID(59392)
+
+/* Atheros AR71xx based boards */
+#define ZYNOS_MODEL_NBG_460N		MID(61441)
+
+#endif /* _ZYNOS_H */
diff --git a/tools/firmware-utils/src/zyxbcm.c b/tools/firmware-utils/src/zyxbcm.c
new file mode 100644
index 0000000000..ffeb7cc265
--- /dev/null
+++ b/tools/firmware-utils/src/zyxbcm.c
@@ -0,0 +1,260 @@
+/*
+ * zyxbcm.c - based on Jonas Gorski's spw303v.c
+ *
+ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define TAGVER_LEN 4			/* Length of Tag Version */
+#define SIG1_LEN 20			/* Company Signature 1 Length */
+#define SIG2_LEN 14			/* Company Signature 2 Lenght */
+#define BOARDID_LEN 16			/* Length of BoardId */
+#define ENDIANFLAG_LEN 2		/* Endian Flag Length */
+#define CHIPID_LEN 6			/* Chip Id Length */
+#define IMAGE_LEN 10			/* Length of Length Field */
+#define ADDRESS_LEN 12			/* Length of Address field */
+#define DUALFLAG_LEN 2			/* Dual Image flag Length */
+#define INACTIVEFLAG_LEN 2		/* Inactie Flag Length */
+#define RSASIG_LEN 20			/* Length of RSA Signature in tag */
+#define TAGINFO1_LEN 30			/* Length of vendor information field1 in tag */
+#define ZYX_TAGINFO1_LEN 20		/* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN 4		/* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN 16			/* Length of vendor information field2 in tag */
+#define CRC_LEN 4			/* Length of CRC in bytes */
+
+#define IMAGETAG_CRC_START 0xFFFFFFFF
+
+struct bcm_tag {
+	char tagVersion[TAGVER_LEN];			// 0-3: Version of the image tag
+	char sig_1[SIG1_LEN];				// 4-23: Company Line 1
+	char sig_2[SIG2_LEN];				// 24-37: Company Line 2
+	char chipid[CHIPID_LEN];			// 38-43: Chip this image is for
+	char boardid[BOARDID_LEN];			// 44-59: Board name
+	char big_endian[ENDIANFLAG_LEN];		// 60-61: Map endianness -- 1 BE 0 LE
+	char totalLength[IMAGE_LEN];			// 62-71: Total length of image
+	char cfeAddress[ADDRESS_LEN];			// 72-83: Address in memory of CFE
+	char cfeLength[IMAGE_LEN];			// 84-93: Size of CFE
+	char flashImageStart[ADDRESS_LEN];		// 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
+	char flashRootLength[IMAGE_LEN];		// 106-115: Size of rootfs for flashing
+	char kernelAddress[ADDRESS_LEN];		// 116-127: Address in memory of kernel
+	char kernelLength[IMAGE_LEN];			// 128-137: Size of kernel
+	char dualImage[DUALFLAG_LEN];			// 138-139: Unused at present
+	char inactiveFlag[INACTIVEFLAG_LEN];		// 140-141: Unused at present
+	char rsa_signature[RSASIG_LEN];			// 142-161: RSA Signature (unused at present; some vendors may use this)
+	char information1[TAGINFO1_LEN];		// 162-191: Compilation and related information (not generated/used by OpenWRT)
+	char flashLayoutVer[FLASHLAYOUTVER_LEN];	// 192-195: Version flash layout
+	char fskernelCRC[CRC_LEN];			// 196-199: kernel+rootfs CRC32
+	char information2[TAGINFO2_LEN];		// 200-215: Unused at present except Alice Gate where is is information
+	char imageCRC[CRC_LEN];				// 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+	char rootfsCRC[CRC_LEN];			// 220-223: CRC32 of rootfs partition
+	char kernelCRC[CRC_LEN];			// 224-227: CRC32 of kernel partition
+	char imageSequence[4];				// 228-231: Image sequence number
+	char rootLength[4];				// 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+	char headerCRC[CRC_LEN];			// 236-239: CRC32 of header excluding tagVersion
+	char reserved2[16];				// 240-255: Unused at present
+};
+
+struct zyxbcm_tag {
+	char tagVersion[TAGVER_LEN];			// 0-3: Version of the image tag
+	char sig_1[SIG1_LEN];				// 4-23: Company Line 1
+	char sig_2[SIG2_LEN];				// 24-37: Company Line 2
+	char chipid[CHIPID_LEN];			// 38-43: Chip this image is for
+	char boardid[BOARDID_LEN];			// 44-59: Board name
+	char big_endian[ENDIANFLAG_LEN];		// 60-61: Map endianness -- 1 BE 0 LE
+	char totalLength[IMAGE_LEN];			// 62-71: Total length of image
+	char cfeAddress[ADDRESS_LEN];			// 72-83: Address in memory of CFE
+	char cfeLength[IMAGE_LEN];			// 84-93: Size of CFE
+	char flashImageStart[ADDRESS_LEN];		// 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
+	char flashRootLength[IMAGE_LEN];		// 106-115: Size of rootfs for flashing
+	char kernelAddress[ADDRESS_LEN];		// 116-127: Address in memory of kernel
+	char kernelLength[IMAGE_LEN];			// 128-137: Size of kernel
+	char dualImage[DUALFLAG_LEN];			// 138-139: Unused at present
+	char inactiveFlag[INACTIVEFLAG_LEN];		// 140-141: Unused at present
+	char rsa_signature[RSASIG_LEN];			// 142-161: RSA Signature (unused at present; some vendors may use this)
+	char information1[ZYX_TAGINFO1_LEN];		// 162-181: Compilation and related information (not generated/used by OpenWRT)
+	char flashImageEnd[ADDRESS_LEN];		// 182-193: Address in memory of image end
+	char fskernelCRC[CRC_LEN];			// 194-197: kernel+rootfs CRC32
+	char reserved1[2];				// 198-199: Unused at present
+	char information2[TAGINFO2_LEN];		// 200-215: Unused at present except Alice Gate where is is information
+	char imageCRC[CRC_LEN];				// 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
+	char rootfsCRC[CRC_LEN];			// 220-223: CRC32 of rootfs partition
+	char kernelCRC[CRC_LEN];			// 224-227: CRC32 of kernel partition
+	char imageSequence[4];				// 228-231: Image sequence number
+	char rootLength[4];				// 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
+	char headerCRC[CRC_LEN];			// 236-239: CRC32 of header excluding tagVersion
+	char reserved2[16];				// 240-255: Unused at present
+};
+
+static uint32_t crc32tab[256] = {
+	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
+{
+	while (len--)
+		crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
+
+	return crc;
+}
+
+void fix_header(void *buf)
+{
+	struct bcm_tag *bcmtag = buf;
+	struct zyxbcm_tag *zyxtag = buf;
+	uint8_t fskernel_crc[CRC_LEN];
+	uint32_t crc;
+	uint64_t flash_start, rootfs_len, kernel_len;
+
+	/* Backup values */
+	flash_start = strtoul(bcmtag->flashImageStart, NULL, 10);
+	rootfs_len = strtoul(bcmtag->flashRootLength, NULL, 10);
+	kernel_len = strtoul(bcmtag->kernelLength, NULL, 10);
+	memcpy(fskernel_crc, bcmtag->fskernelCRC, CRC_LEN);
+
+	/* Clear values */
+	zyxtag->information1[ZYX_TAGINFO1_LEN - 1] = 0;
+	memset(zyxtag->flashImageEnd, 0, ADDRESS_LEN);
+	memset(zyxtag->fskernelCRC, 0, CRC_LEN);
+	memset(zyxtag->reserved1, 0, 2);
+
+	/* Replace values */
+	sprintf(zyxtag->flashImageEnd, "%lu", flash_start + rootfs_len + kernel_len);
+	memcpy(zyxtag->fskernelCRC, fskernel_crc, CRC_LEN);
+
+	/* Update tag crc */
+	crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
+	memcpy(zyxtag->headerCRC, &crc, 4);
+}
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+	fprintf(stderr, "Usage: zyxbcm [-i <inputfile>] [-o <outputfile>]\n");
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+	char buf[1024];	/* keep this at 1k or adjust garbage calc below */
+	FILE *in = stdin, *out = stdout;
+	char *ifn = NULL, *ofn = NULL;
+	size_t n;
+	int c, first_block = 1;
+
+	while ((c = getopt(argc, argv, "i:o:h")) != -1) {
+		switch (c) {
+			case 'i':
+				ifn = optarg;
+				break;
+			case 'o':
+				ofn = optarg;
+				break;
+			case 'h':
+			default:
+				usage();
+		}
+	}
+
+	if (optind != argc || optind == 1) {
+		fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+		usage();
+	}
+
+	if (ifn && !(in = fopen(ifn, "r"))) {
+		fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+		usage();
+	}
+
+	if (ofn && !(out = fopen(ofn, "w"))) {
+		fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+		usage();
+	}
+
+	while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
+		if (n < sizeof(buf)) {
+			if (ferror(in)) {
+			FREAD_ERROR:
+				fprintf(stderr, "fread error\n");
+				return EXIT_FAILURE;
+			}
+		}
+
+		if (first_block && n >= 256) {
+			fix_header(buf);
+			first_block = 0;
+		}
+
+		if (!fwrite(buf, n, 1, out)) {
+		FWRITE_ERROR:
+			fprintf(stderr, "fwrite error\n");
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (ferror(in)) {
+		goto FREAD_ERROR;
+	}
+
+	if (fflush(out)) {
+		goto FWRITE_ERROR;
+	}
+
+	fclose(in);
+	fclose(out);
+
+	return EXIT_SUCCESS;
+}
diff --git a/tools/flex/Makefile b/tools/flex/Makefile
new file mode 100644
index 0000000000..78eb1e0b46
--- /dev/null
+++ b/tools/flex/Makefile
@@ -0,0 +1,27 @@
+# 
+# Copyright (C) 2008-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=flex
+PKG_VERSION:=2.6.1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=https://github.com/westes/flex/releases/download/v$(PKG_VERSION)/
+PKG_MD5SUM:=cd3c86290fc2676a641aefafeb10848a
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS += --disable-shared
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/flex/patches/100-disable-tests-docs.patch b/tools/flex/patches/100-disable-tests-docs.patch
new file mode 100644
index 0000000000..d6e289d5b3
--- /dev/null
+++ b/tools/flex/patches/100-disable-tests-docs.patch
@@ -0,0 +1,13 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -45,10 +45,7 @@
+ SUBDIRS = \
+ 	lib \
+ 	src \
+-	doc \
+-	examples \
+ 	po \
+-	tests \
+ 	tools
+ 
+ # Create the ChangeLog, but only if we're inside a git working directory
diff --git a/tools/flock/Makefile b/tools/flock/Makefile
new file mode 100644
index 0000000000..9939d12116
--- /dev/null
+++ b/tools/flock/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME := flock
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOSTCC := $(HOSTCC_NOCACHE)
+HOSTCXX := $(HOSTCXX_NOCACHE)
+
+define Host/Compile
+	mkdir -p $(HOST_BUILD_DIR)
+	$(HOSTCC) $(HOST_CFLAGS) -o $(HOST_BUILD_DIR)/flock src/flock.c
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/flock $(STAGING_DIR_HOST)/bin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/flock/src/flock.c b/tools/flock/src/flock.c
new file mode 100644
index 0000000000..37ab0ea72d
--- /dev/null
+++ b/tools/flock/src/flock.c
@@ -0,0 +1,342 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2005 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#include <paths.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#define PACKAGE_STRING "util-linux-ng 2.18"
+#define _(x) (x)
+
+static const struct option long_options[] = {
+  { "shared",       0, NULL, 's' },
+  { "exclusive",    0, NULL, 'x' },
+  { "unlock",       0, NULL, 'u' },
+  { "nonblocking",  0, NULL, 'n' },
+  { "nb",           0, NULL, 'n' },
+  { "timeout",      1, NULL, 'w' },
+  { "wait",         1, NULL, 'w' },
+  { "close",        0, NULL, 'o' },
+  { "help",         0, NULL, 'h' },
+  { "version",      0, NULL, 'V' },
+  { 0, 0, 0, 0 }
+};
+
+const char *program;
+
+static void usage(int ex)
+{
+  fputs("flock (" PACKAGE_STRING ")\n", stderr);
+  fprintf(stderr,
+	_("Usage: %1$s [-sxun][-w #] fd#\n"
+	  "       %1$s [-sxon][-w #] file [-c] command...\n"
+	  "       %1$s [-sxon][-w #] directory [-c] command...\n"
+	  "  -s  --shared     Get a shared lock\n"
+	  "  -x  --exclusive  Get an exclusive lock\n"
+	  "  -u  --unlock     Remove a lock\n"
+	  "  -n  --nonblock   Fail rather than wait\n"
+	  "  -w  --timeout    Wait for a limited amount of time\n"
+	  "  -o  --close      Close file descriptor before running command\n"
+	  "  -c  --command    Run a single command string through the shell\n"
+	  "  -h  --help       Display this text\n"
+	  "  -V  --version    Display version\n"),
+	  program);
+  exit(ex);
+}
+
+
+static sig_atomic_t timeout_expired = 0;
+
+static void timeout_handler(int sig)
+{
+  (void)sig;
+
+  timeout_expired = 1;
+}
+
+
+static char * strtotimeval(const char *str, struct timeval *tv)
+{
+  char *s;
+  long fs;			/* Fractional seconds */
+  int i;
+
+  tv->tv_sec = strtol(str, &s, 10);
+  fs = 0;
+
+  if ( *s == '.' ) {
+    s++;
+
+    for ( i = 0 ; i < 6 ; i++ ) {
+      if ( !isdigit(*s) )
+	break;
+
+      fs *= 10;
+      fs += *s++ - '0';
+    }
+
+    for ( ; i < 6; i++ )
+      fs *= 10;
+
+    while ( isdigit(*s) )
+      s++;
+  }
+
+  tv->tv_usec = fs;
+  return s;
+}
+
+int main(int argc, char *argv[])
+{
+  struct itimerval timeout, old_timer;
+  int have_timeout = 0;
+  int type = LOCK_EX;
+  int block = 0;
+  int fd = -1;
+  int opt, ix;
+  int do_close = 0;
+  int err;
+  int status;
+  int open_flags = 0;
+  char *eon;
+  char **cmd_argv = NULL, *sh_c_argv[4];
+  const char *filename = NULL;
+  struct sigaction sa, old_sa;
+
+  program = argv[0];
+
+  if ( argc < 2 )
+    usage(EX_USAGE);
+
+  memset(&timeout, 0, sizeof timeout);
+
+  optopt = 0;
+  while ( (opt = getopt_long(argc, argv, "+sexnouw:hV?", long_options, &ix)) != EOF ) {
+    switch(opt) {
+    case 's':
+      type = LOCK_SH;
+      break;
+    case 'e':
+    case 'x':
+      type = LOCK_EX;
+      break;
+    case 'u':
+      type = LOCK_UN;
+      break;
+    case 'o':
+      do_close = 1;
+      break;
+    case 'n':
+      block = LOCK_NB;
+      break;
+    case 'w':
+      have_timeout = 1;
+      eon = strtotimeval(optarg, &timeout.it_value);
+      if ( *eon )
+	usage(EX_USAGE);
+      break;
+    case 'V':
+      printf("flock (%s)\n", PACKAGE_STRING);
+      exit(0);
+    default:
+      /* optopt will be set if this was an unrecognized option, i.e. *not* 'h' or '?' */
+      usage(optopt ? EX_USAGE : 0);
+      break;
+    }
+  }
+
+  if ( argc > optind+1 ) {
+    /* Run command */
+
+    if ( !strcmp(argv[optind+1], "-c") ||
+	 !strcmp(argv[optind+1], "--command") ) {
+
+      if ( argc != optind+3 ) {
+	fprintf(stderr, _("%s: %s requires exactly one command argument\n"),
+		program, argv[optind+1]);
+	exit(EX_USAGE);
+      }
+
+      cmd_argv = sh_c_argv;
+
+      cmd_argv[0] = getenv("SHELL");
+      if ( !cmd_argv[0] || !*cmd_argv[0] )
+	cmd_argv[0] = _PATH_BSHELL;
+
+      cmd_argv[1] = "-c";
+      cmd_argv[2] = argv[optind+2];
+      cmd_argv[3] = 0;
+    } else {
+      cmd_argv = &argv[optind+1];
+    }
+
+    filename = argv[optind];
+    fd = open(filename, O_RDONLY|O_NOCTTY|O_CREAT, 0666);
+    /* Linux doesn't like O_CREAT on a directory, even though it should be a
+       no-op */
+    if (fd < 0 && errno == EISDIR)
+        fd = open(filename, O_RDONLY|O_NOCTTY);
+
+    if ( fd < 0 ) {
+      err = errno;
+      fprintf(stderr, _("%s: cannot open lock file %s: %s\n"),
+	      program, argv[optind], strerror(err));
+      exit((err == ENOMEM||err == EMFILE||err == ENFILE) ? EX_OSERR :
+	   (err == EROFS||err == ENOSPC) ? EX_CANTCREAT :
+	   EX_NOINPUT);
+    }
+
+  } else if (optind < argc) {
+    /* Use provided file descriptor */
+
+    fd = (int)strtol(argv[optind], &eon, 10);
+    if ( *eon || !argv[optind] ) {
+      fprintf(stderr, _("%s: bad number: %s\n"), program, argv[optind]);
+      exit(EX_USAGE);
+    }
+
+  } else {
+    /* Bad options */
+
+    fprintf(stderr, _("%s: requires file descriptor, file or directory\n"),
+		program);
+    exit(EX_USAGE);
+  }
+
+
+  if ( have_timeout ) {
+    if ( timeout.it_value.tv_sec == 0 &&
+	 timeout.it_value.tv_usec == 0 ) {
+      /* -w 0 is equivalent to -n; this has to be special-cased
+	 because setting an itimer to zero means disabled! */
+
+      have_timeout = 0;
+      block = LOCK_NB;
+    } else {
+      memset(&sa, 0, sizeof sa);
+
+      sa.sa_handler = timeout_handler;
+      sa.sa_flags   = SA_RESETHAND;
+      sigaction(SIGALRM, &sa, &old_sa);
+
+      setitimer(ITIMER_REAL, &timeout, &old_timer);
+    }
+  }
+
+  while ( flock(fd, type|block) ) {
+    switch( (err = errno) ) {
+    case EWOULDBLOCK:		/* -n option set and failed to lock */
+      exit(1);
+    case EINTR:			/* Signal received */
+      if ( timeout_expired )
+	exit(1);		/* -w option set and failed to lock */
+      continue;			/* otherwise try again */
+    case EBADF:			/* since Linux 3.4 (commit 55725513) */
+      /* Probably NFSv4 where flock() is emulated by fcntl().
+       * Let's try to reopen in read-write mode.
+       */
+      if (!(open_flags & O_RDWR) &&
+          type != LOCK_SH &&
+          filename &&
+          access(filename, R_OK | W_OK) == 0) {
+
+              close(fd);
+              open_flags = O_RDWR;
+              fd = open(filename, open_flags);
+              break;
+      }
+      /* go through */
+    default:			/* Other errors */
+      if ( filename )
+	fprintf(stderr, "%s: %s: %s\n", program, filename, strerror(err));
+      else
+	fprintf(stderr, "%s: %d: %s\n", program, fd, strerror(err));
+      exit((err == ENOLCK||err == ENOMEM) ? EX_OSERR : EX_DATAERR);
+    }
+  }
+
+  if ( have_timeout ) {
+    setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
+    sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
+  }
+
+  status = 0;
+
+  if ( cmd_argv ) {
+    pid_t w, f;
+
+    /* Clear any inherited settings */
+    signal(SIGCHLD, SIG_DFL);
+    f = fork();
+
+    if ( f < 0 ) {
+      err = errno;
+      fprintf(stderr, _("%s: fork failed: %s\n"), program, strerror(err));
+      exit(EX_OSERR);
+    } else if ( f == 0 ) {
+      if ( do_close )
+	close(fd);
+      err = errno;
+      execvp(cmd_argv[0], cmd_argv);
+      /* execvp() failed */
+      fprintf(stderr, "%s: %s: %s\n", program, cmd_argv[0], strerror(err));
+      _exit((err == ENOMEM) ? EX_OSERR: EX_UNAVAILABLE);
+    } else {
+      do {
+	w = waitpid(f, &status, 0);
+	if (w == -1 && errno != EINTR)
+	  break;
+      } while ( w != f );
+
+      if (w == -1) {
+	err = errno;
+	status = EXIT_FAILURE;
+	fprintf(stderr, "%s: waitpid failed: %s\n", program, strerror(err));
+      } else if ( WIFEXITED(status) )
+	status = WEXITSTATUS(status);
+      else if ( WIFSIGNALED(status) )
+	status = WTERMSIG(status) + 128;
+      else
+	status = EX_OSERR;	/* WTF? */
+    }
+  }
+
+  return status;
+}
+
diff --git a/tools/genext2fs/Makefile b/tools/genext2fs/Makefile
new file mode 100644
index 0000000000..ad941c71ac
--- /dev/null
+++ b/tools/genext2fs/Makefile
@@ -0,0 +1,51 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=genext2fs
+PKG_VERSION:=1.4.1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/genext2fs
+PKG_MD5SUM:=b7b6361bcce2cedff1ae437fadafe53b
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS = \
+	--target=$(GNU_HOST_NAME) \
+	--host=$(GNU_HOST_NAME) \
+	--build=$(GNU_HOST_NAME) \
+	--program-prefix="" \
+	--program-suffix="" \
+	--prefix=/usr \
+	--exec-prefix=/usr \
+	--bindir=/usr/bin \
+	--sbindir=/usr/sbin \
+	--libexecdir=/usr/lib \
+	--sysconfdir=/etc \
+	--datadir=/usr/share \
+	--localstatedir=/var \
+	--mandir=/usr/man \
+	--infodir=/usr/info \
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		CFLAGS="$(HOST_CFLAGS)" \
+		LDFLAGS="$(HOST_LDFLAGS)" \
+		all
+endef
+
+define Host/Install
+	install -m0755 $(HOST_BUILD_DIR)/genext2fs $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/genext2fs
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/genext2fs/patches/100-c99_scanf.patch b/tools/genext2fs/patches/100-c99_scanf.patch
new file mode 100644
index 0000000000..e7aa17cc6f
--- /dev/null
+++ b/tools/genext2fs/patches/100-c99_scanf.patch
@@ -0,0 +1,21 @@
+commit 3b8ca0ce9a0b58287a780747c90c449bdebfe464
+Author: Xavier Bestel <bestouff@users.sourceforge.net>
+Date:   Mon Jan 14 08:52:44 2008 +0000
+
+    removed use of %as is scanf (GNU conflicts with C99) by Giacomo Catenazzi <cate@debian.org>
+
+diff --git a/genext2fs.c b/genext2fs.c
+index 070b270..f0d797d 100644
+--- a/genext2fs.c
++++ b/genext2fs.c
+@@ -286,7 +286,9 @@ typedef unsigned int uint32;
+ // older solaris. Note that this is still not very portable, in that
+ // the return value cannot be trusted.
+ 
+-#if SCANF_CAN_MALLOC
++#if 0 // SCANF_CAN_MALLOC
++// C99 define "a" for floating point, so you can have runtime surprise
++// according the library versions
+ # define SCANF_PREFIX "a"
+ # define SCANF_STRING(s) (&s)
+ #else
diff --git a/tools/genext2fs/patches/200-autoconf.patch b/tools/genext2fs/patches/200-autoconf.patch
new file mode 100644
index 0000000000..b3317bdd10
--- /dev/null
+++ b/tools/genext2fs/patches/200-autoconf.patch
@@ -0,0 +1,13 @@
+Index: genext2fs/m4/ac_func_scanf_can_malloc.m4
+===================================================================
+--- genext2fs.orig/m4/ac_func_scanf_can_malloc.m4	2011-09-03 21:28:49.000000000 +0200
++++ genext2fs/m4/ac_func_scanf_can_malloc.m4	2011-09-03 21:29:41.000000000 +0200
+@@ -9,7 +9,7 @@
+ # --------------------------------------
+ AC_DEFUN([AC_FUNC_SCANF_CAN_MALLOC],
+   [ AC_CHECK_HEADERS([stdlib.h])
+-    AC_CACHE_CHECK([whether scanf can malloc], [ac_scanf_can_malloc],
++    AC_CACHE_CHECK([whether scanf can malloc], [ac_cv_func_scanf_can_malloc],
+     [ AC_RUN_IFELSE(
+       [ AC_LANG_PROGRAM(
+         [
diff --git a/tools/genext2fs/patches/300-blocksize-creator.patch b/tools/genext2fs/patches/300-blocksize-creator.patch
new file mode 100644
index 0000000000..97a4836eeb
--- /dev/null
+++ b/tools/genext2fs/patches/300-blocksize-creator.patch
@@ -0,0 +1,558 @@
+Index: genext2fs/genext2fs.c
+===================================================================
+--- genext2fs.orig/genext2fs.c	2011-09-03 14:21:17.000000000 +0200
++++ genext2fs/genext2fs.c	2011-09-03 14:21:17.000000000 +0200
+@@ -151,13 +151,24 @@
+ 
+ // block size
+ 
+-#define BLOCKSIZE         1024
++static int blocksize = 1024;
++
++#define BLOCKSIZE         blocksize
+ #define BLOCKS_PER_GROUP  8192
+ #define INODES_PER_GROUP  8192
+ /* Percentage of blocks that are reserved.*/
+ #define RESERVED_BLOCKS       5/100
+ #define MAX_RESERVED_BLOCKS  25/100
+ 
++/* The default value for s_creator_os. */
++#if defined(__GNU__)
++# define CREATOR_OS  1 /* Hurd */
++#elif defined(__FreeBSD__)
++# define CREATOR_OS  3 /* FreeBSD */
++#else
++# define CREATOR_OS  0 /* Linux */
++#endif
++
+ 
+ // inode block size (why is it != BLOCKSIZE ?!?)
+ /* The field i_blocks in the ext2 inode stores the number of data blocks
+@@ -239,10 +250,10 @@
+ 	  (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
+ 
+ // Get group block bitmap (bbm) given the group number
+-#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
++#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs), get_gd((fs),(grp))->bg_block_bitmap) )
+ 
+ // Get group inode bitmap (ibm) given the group number
+-#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
++#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs), get_gd((fs),(grp))->bg_inode_bitmap) )
+ 		
+ // Given an inode number find the group it belongs to
+ #define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
+@@ -532,7 +543,7 @@
+ 	char d_name[0];
+ } directory;
+ 
+-typedef uint8 block[BLOCKSIZE];
++typedef uint8 *block;
+ 
+ /* blockwalker fields:
+    The blockwalker is used to access all the blocks of a file (including
+@@ -571,16 +582,12 @@
+ 
+ 
+ /* Filesystem structure that support groups */
+-#if BLOCKSIZE == 1024
+ typedef struct
+ {
+-	block zero;            // The famous block 0
+-	superblock sb;         // The superblock
+-	groupdescriptor gd[0]; // The group descriptors
++	uint8 zero[1024];      // Room for bootloader stuff
++	superblock sb;         // The superblock, always at 1024
++	// group descriptors come next, see get_gd() below
+ } filesystem;
+-#else
+-#error UNHANDLED BLOCKSIZE
+-#endif
+ 
+ // now the endianness swap
+ 
+@@ -820,6 +827,14 @@
+ 	return (uint8*)fs + blk*BLOCKSIZE;
+ }
+ 
++// the group descriptors are aligned on the block size
++static inline groupdescriptor *
++get_gd(filesystem *fs, int no)
++{
++	int gdblk = (sizeof (filesystem) + BLOCKSIZE - 1) / BLOCKSIZE;
++	return ((groupdescriptor *) get_blk(fs, gdblk)) + no;
++}
++
+ // return a given inode from a filesystem
+ static inline inode *
+ get_nod(filesystem *fs, uint32 nod)
+@@ -829,7 +844,7 @@
+ 
+ 	offset = GRP_IBM_OFFSET(fs,nod);
+ 	grp = GRP_GROUP_OF_INODE(fs,nod);
+-	itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
++	itab = (inode *)get_blk(fs, get_gd(fs,grp)->bg_inode_table);
+ 	return itab+offset-1;
+ }
+ 
+@@ -875,18 +890,18 @@
+ 
+ 	grp = GRP_GROUP_OF_INODE(fs,nod);
+ 	nbgroups = GRP_NBGROUPS(fs);
+-	if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
++	if(!(bk = allocate(GRP_GET_GROUP_BBM(fs, grp), 0))) {
+ 		for(grp=0;grp<nbgroups && !bk;grp++)
+-			bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
++			bk = allocate(GRP_GET_GROUP_BBM(fs, grp), 0);
+ 		grp--;
+ 	}
+ 	if (!bk)
+ 		error_msg_and_die("couldn't allocate a block (no free space)");
+-	if(!(fs->gd[grp].bg_free_blocks_count--))
++	if(!(get_gd(fs, grp)->bg_free_blocks_count--))
+ 		error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
+ 	if(!(fs->sb.s_free_blocks_count--))
+ 		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
+-	return fs->sb.s_blocks_per_group*grp + bk;
++	return fs->sb.s_first_data_block + fs->sb.s_blocks_per_group*grp + (bk-1);
+ }
+ 
+ // free a block
+@@ -897,8 +912,8 @@
+ 
+ 	grp = bk / fs->sb.s_blocks_per_group;
+ 	bk %= fs->sb.s_blocks_per_group;
+-	deallocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), bk);
+-	fs->gd[grp].bg_free_blocks_count++;
++	deallocate(GRP_GET_GROUP_BBM(fs, grp), bk);
++	get_gd(fs, grp)->bg_free_blocks_count++;
+ 	fs->sb.s_free_blocks_count++;
+ }
+ 
+@@ -918,16 +933,16 @@
+ 	/* We do it for all inodes.                                           */
+ 	avefreei  =  fs->sb.s_free_inodes_count / nbgroups;
+ 	for(grp=0; grp<nbgroups; grp++) {
+-		if (fs->gd[grp].bg_free_inodes_count < avefreei ||
+-		    fs->gd[grp].bg_free_inodes_count == 0)
++		if (get_gd(fs, grp)->bg_free_inodes_count < avefreei ||
++		    get_gd(fs, grp)->bg_free_inodes_count == 0)
+ 			continue;
+ 		if (!best_group || 
+-			fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
++			get_gd(fs, grp)->bg_free_blocks_count > get_gd(fs, best_group)->bg_free_blocks_count)
+ 			best_group = grp;
+ 	}
+-	if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
++	if (!(nod = allocate(GRP_GET_GROUP_IBM(fs, best_group), 0)))
+ 		error_msg_and_die("couldn't allocate an inode (no free inode)");
+-	if(!(fs->gd[best_group].bg_free_inodes_count--))
++	if(!(get_gd(fs, best_group)->bg_free_inodes_count--))
+ 		error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
+ 	if(!(fs->sb.s_free_inodes_count--))
+ 		error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
+@@ -1390,7 +1405,7 @@
+ 			case FM_IFDIR:
+ 				add2dir(fs, nod, nod, ".");
+ 				add2dir(fs, nod, parent_nod, "..");
+-				fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
++				get_gd(fs, GRP_GROUP_OF_INODE(fs,nod))->bg_used_dirs_count++;
+ 				break;
+ 		}
+ 	}
+@@ -1860,7 +1875,7 @@
+ 		swap_nod(nod);
+ 	}
+ 	for(i=0;i<GRP_NBGROUPS(fs);i++)
+-		swap_gd(&(fs->gd[i]));
++		swap_gd(get_gd(fs, i));
+ 	swap_sb(&fs->sb);
+ }
+ 
+@@ -1870,7 +1885,7 @@
+ 	uint32 i;
+ 	swap_sb(&fs->sb);
+ 	for(i=0;i<GRP_NBGROUPS(fs);i++)
+-		swap_gd(&(fs->gd[i]));
++		swap_gd(get_gd(fs, i));
+ 	for(i = 1; i < fs->sb.s_inodes_count; i++)
+ 	{
+ 		inode *nod = get_nod(fs, i);
+@@ -1895,7 +1910,8 @@
+ 
+ // initialize an empty filesystem
+ static filesystem *
+-init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
++init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
++		uint32 fs_timestamp, uint32 creator_os)
+ {
+ 	uint32 i;
+ 	filesystem *fs;
+@@ -1921,10 +1937,14 @@
+ 	 */
+ 	min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
+ 
++	/* On filesystems with 1k block size, the bootloader area uses a full
++	 * block. For 2048 and up, the superblock can be fitted into block 0.
++	 */
++	first_block = (BLOCKSIZE == 1024);
++
+ 	/* nbblocks is the total number of blocks in the filesystem.
+ 	 * a block group can have no more than 8192 blocks.
+ 	 */
+-	first_block = (BLOCKSIZE == 1024);
+ 	nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
+ 	if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
+ 	nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
+@@ -1936,10 +1956,10 @@
+ 	gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
+ 	itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
+ 	overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
+-	if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
+-		error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
+-	free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
++	free_blocks = nbblocks - overhead_per_group*nbgroups - first_block;
+ 	free_blocks_per_group = nbblocks_per_group - overhead_per_group;
++	if(free_blocks < 0)
++		error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
+ 
+ 	if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
+ 		error_msg_and_die("not enough memory for filesystem");
+@@ -1959,28 +1979,31 @@
+ 	fs->sb.s_wtime = fs_timestamp;
+ 	fs->sb.s_magic = EXT2_MAGIC_NUMBER;
+ 	fs->sb.s_lastcheck = fs_timestamp;
++	fs->sb.s_creator_os = creator_os;
+ 
+ 	// set up groupdescriptors
+-	for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
++	for(i=0, bbmpos=first_block+1+gdsz, ibmpos=bbmpos+1, itblpos=ibmpos+1;
+ 		i<nbgroups;
+ 		i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
+ 	{
++		groupdescriptor *gd = get_gd(fs, i);
++
+ 		if(free_blocks > free_blocks_per_group) {
+-			fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
++			gd->bg_free_blocks_count = free_blocks_per_group;
+ 			free_blocks -= free_blocks_per_group;
+ 		} else {
+-			fs->gd[i].bg_free_blocks_count = free_blocks;
++			gd->bg_free_blocks_count = free_blocks;
+ 			free_blocks = 0; // this is the last block group
+ 		}
+ 		if(i)
+-			fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
++			gd->bg_free_inodes_count = nbinodes_per_group;
+ 		else
+-			fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
++			gd->bg_free_inodes_count = nbinodes_per_group -
+ 							EXT2_FIRST_INO + 2;
+-		fs->gd[i].bg_used_dirs_count = 0;
+-		fs->gd[i].bg_block_bitmap = bbmpos;
+-		fs->gd[i].bg_inode_bitmap = ibmpos;
+-		fs->gd[i].bg_inode_table = itblpos;
++		gd->bg_used_dirs_count = 0;
++		gd->bg_block_bitmap = bbmpos;
++		gd->bg_inode_bitmap = ibmpos;
++		gd->bg_inode_table = itblpos;
+ 	}
+ 
+ 	/* Mark non-filesystem blocks and inodes as allocated */
+@@ -1988,9 +2011,9 @@
+ 	for(i = 0; i<nbgroups;i++) {
+ 
+ 		/* Block bitmap */
+-		bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);	
++		bbm = GRP_GET_GROUP_BBM(fs, i);
+ 		//non-filesystem blocks
+-		for(j = fs->gd[i].bg_free_blocks_count
++		for(j = get_gd(fs, i)->bg_free_blocks_count
+ 		        + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
+ 			allocate(bbm, j); 
+ 		//system blocks
+@@ -1998,7 +2021,7 @@
+ 			allocate(bbm, j); 
+ 		
+ 		/* Inode bitmap */
+-		ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);	
++		ibm = GRP_GET_GROUP_IBM(fs, i);
+ 		//non-filesystem inodes
+ 		for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
+ 			allocate(ibm, j);
+@@ -2012,9 +2035,9 @@
+ 	// make root inode and directory
+ 	/* We have groups now. Add the root filesystem in group 0 */
+ 	/* Also increment the directory count for group 0 */
+-	fs->gd[0].bg_free_inodes_count--;
+-	fs->gd[0].bg_used_dirs_count = 1;
+-	itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
++	get_gd(fs, 0)->bg_free_inodes_count--;
++	get_gd(fs, 0)->bg_used_dirs_count = 1;
++	itab0 = (inode *)get_blk(fs, get_gd(fs,0)->bg_inode_table);
+ 	itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH; 
+ 	itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
+ 	itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
+@@ -2338,8 +2361,9 @@
+ 	for (i = 0; i < GRP_NBGROUPS(fs); i++) {
+ 		printf("Group No: %d\n", i+1);
+ 		printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
+-		     fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
+-		     fs->gd[i].bg_inode_table);
++		     get_gd(fs, i)->bg_block_bitmap,
++		     get_gd(fs, i)->bg_inode_bitmap,
++		     get_gd(fs, i)->bg_inode_table);
+ 		printf("block bitmap allocation:\n");
+ 		print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
+ 		printf("inode bitmap allocation:\n");
+@@ -2421,10 +2445,12 @@
+ 	"  -x, --starting-image <image>\n"
+ 	"  -d, --root <directory>\n"
+ 	"  -D, --devtable <file>\n"
++	"  -B, --block-size <bytes>\n"
+ 	"  -b, --size-in-blocks <blocks>\n"
+ 	"  -i, --bytes-per-inode <bytes per inode>\n"
+ 	"  -N, --number-of-inodes <number of inodes>\n"
+ 	"  -m, --reserved-percentage <percentage of blocks to reserve>\n"
++	"  -o, --creator-os <os>      'linux', 'hurd', 'freebsd' or a numerical value.\n"
+ 	"  -g, --block-map <path>     Generate a block map file for this path.\n"
+ 	"  -e, --fill-value <value>   Fill unallocated blocks with value.\n"
+ 	"  -z, --allow-holes          Allow files with holes.\n"
+@@ -2446,6 +2472,29 @@
+ extern char* optarg;
+ extern int optind, opterr, optopt;
+ 
++// parse the value for -o <os>
++int
++lookup_creator_os(const char *name)
++{
++	static const char *const creators[] =
++		{"linux", "hurd", "2", "freebsd", NULL};
++	char *endptr;
++	int i;
++
++	// numerical value ?
++	i = strtol(name, &endptr, 0);
++	if(name[0] && *endptr == '\0')
++		return i;
++
++	// symbolic name ?
++	for(i=0; creators[i]; i++)
++	       if(strcasecmp(creators[i], name) == 0)
++		       return i;
++
++	// whatever ?
++	return -1;
++}
++
+ int
+ main(int argc, char **argv)
+ {
+@@ -2455,6 +2504,7 @@
+ 	float bytes_per_inode = -1;
+ 	float reserved_frac = -1;
+ 	int fs_timestamp = -1;
++	int creator_os = CREATOR_OS;
+ 	char * fsout = "-";
+ 	char * fsin = 0;
+ 	char * dopt[MAX_DOPT];
+@@ -2478,10 +2528,12 @@
+ 	  { "starting-image",	required_argument,	NULL, 'x' },
+ 	  { "root",		required_argument,	NULL, 'd' },
+ 	  { "devtable",		required_argument,	NULL, 'D' },
++	  { "block-size",	required_argument,	NULL, 'B' },
+ 	  { "size-in-blocks",	required_argument,	NULL, 'b' },
+ 	  { "bytes-per-inode",	required_argument,	NULL, 'i' },
+ 	  { "number-of-inodes",	required_argument,	NULL, 'N' },
+ 	  { "reserved-percentage", required_argument,	NULL, 'm' },
++	  { "creator-os",	required_argument,	NULL, 'o' },
+ 	  { "block-map",	required_argument,	NULL, 'g' },
+ 	  { "fill-value",	required_argument,	NULL, 'e' },
+ 	  { "allow-holes",	no_argument, 		NULL, 'z' },
+@@ -2497,11 +2549,11 @@
+ 
+ 	app_name = argv[0];
+ 
+-	while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
++	while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
+ #else
+ 	app_name = argv[0];
+ 
+-	while((c = getopt(argc, argv,      "x:d:D:b:i:N:m:g:e:zfqUPhVv")) != EOF) {
++	while((c = getopt(argc, argv,      "x:d:D:B:b:i:N:m:o:g:e:zfqUPhVv")) != EOF) {
+ #endif /* HAVE_GETOPT_LONG */
+ 		switch(c)
+ 		{
+@@ -2512,6 +2564,9 @@
+ 			case 'D':
+ 				dopt[didx++] = optarg;
+ 				break;
++			case 'B':
++				blocksize = SI_atof(optarg);
++				break;
+ 			case 'b':
+ 				nbblocks = SI_atof(optarg);
+ 				break;
+@@ -2524,6 +2579,9 @@
+ 			case 'm':
+ 				reserved_frac = SI_atof(optarg) / 100;
+ 				break;
++			case 'o':
++				creator_os = lookup_creator_os(optarg);
++				break;
+ 			case 'g':
+ 				gopt[gidx++] = optarg;
+ 				break;
+@@ -2567,6 +2625,11 @@
+ 		error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
+ 	fsout = argv[optind];
+ 
++	if(blocksize != 1024 && blocksize != 2048 && blocksize != 4096)
++		error_msg_and_die("Valid block sizes: 1024, 2048 or 4096.");
++	if(creator_os < 0)
++		error_msg_and_die("Creator OS unknown.");
++
+ 	hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
+ 	if (!hdlinks.hdl)
+ 		error_msg_and_die("Not enough memory");
+@@ -2611,7 +2674,8 @@
+ 		}
+ 		if(fs_timestamp == -1)
+ 			fs_timestamp = time(NULL);
+-		fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
++		fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
++				fs_timestamp, creator_os);
+ 	}
+ 	
+ 	populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
+Index: genext2fs/test-gen.lib
+===================================================================
+--- genext2fs.orig/test-gen.lib	2011-09-03 13:40:35.000000000 +0200
++++ genext2fs/test-gen.lib	2011-09-03 14:21:17.000000000 +0200
+@@ -8,7 +8,7 @@
+ # Creates an image with a file of given size
+ # Usage: dgen file-size number-of-blocks 
+ dgen () {
+-	size=$1; blocks=$2
++	size=$1; blocks=$2; blocksz=$3;
+ 	rm -rf test
+ 	mkdir -p test
+ 	cd test
+@@ -20,7 +20,7 @@
+         chmod 777 file.$1
+ 	TZ=UTC-11 touch -t 200502070321.43 file.$1 .
+ 	cd ..
+-	./genext2fs -N 17 -b $blocks -d test -f -q ext2.img 
++	./genext2fs -B $blocksz -N 17 -b $blocks -d test -f -o Linux -q ext2.img
+ }
+ 
+ # fgen - Exercises the -f spec-file option of genext2fs
+@@ -31,7 +31,7 @@
+ 	mkdir -p test
+ 	cp $fname test
+ 	TZ=UTC-11 touch -t 200502070321.43 test/$fname
+-	./genext2fs -N 92 -b $blocks -D test/$fname -f ext2.img
++	./genext2fs -N 92 -b $blocks -D test/$fname -f -o Linux ext2.img
+ }
+ 
+ # gen_cleanup - Remove the files generated by the above functions
+Index: genext2fs/test-mount.sh
+===================================================================
+--- genext2fs.orig/test-mount.sh	2011-09-03 13:40:35.000000000 +0200
++++ genext2fs/test-mount.sh	2011-09-03 14:21:17.000000000 +0200
+@@ -33,9 +33,9 @@
+ # and returns the command line with which to invoke dtest()
+ # Usage: dtest-mount file-size number-of-blocks 
+ dtest_mount () {
+-	size=$1; blocks=$2
+-	echo Testing with file of size $size
+-	dgen $size $blocks
++	size=$1; blocks=$2; blocksz=$3;
++	echo Testing $blocks blocks of $blocksz bytes with file of size $size
++	dgen $size $blocks $blocksz
+ 	/sbin/e2fsck -fn ext2.img || fail
+ 	mkdir -p mnt
+ 	mount -t ext2 -o ro,loop ext2.img mnt || fail
+@@ -44,7 +44,7 @@
+ 	                                awk '{print $5}'`" ] ; then
+ 		fail
+ 	fi
+-	pass dtest $size $blocks
++	pass dtest $size $blocks $blocksz
+ }
+ 
+ # ftest-mount - Exercise the -f spec-file option of genext2fs
+@@ -75,13 +75,21 @@
+ 	pass ftest $fname $blocks
+ }
+ 
+-dtest_mount 0 4096 
+-dtest_mount 0 8193
+-dtest_mount 0 8194
+-dtest_mount 1 4096 
+-dtest_mount 12288 4096 
+-dtest_mount 274432 4096 
+-dtest_mount 8388608 9000 
+-dtest_mount 16777216 20000
++dtest_mount 0 4096 1024
++dtest_mount 0 2048 2048
++dtest_mount 0 1024 4096
++dtest_mount 0 8193 1024
++dtest_mount 0 8194 1024
++dtest_mount 0 8193 4096
++dtest_mount 0 8194 2048
++dtest_mount 1 4096 1024
++dtest_mount 1 1024 4096
++dtest_mount 12288 4096 1024
++dtest_mount 274432 4096 1024
++dtest_mount 8388608 9000 1024
++dtest_mount 8388608 4500 2048
++dtest_mount 8388608 2250 4096
++dtest_mount 16777216 20000 1024
++dtest_mount 16777216 10000 2048
+ 
+ ftest_mount device_table.txt 4096 
+Index: genext2fs/test.sh
+===================================================================
+--- genext2fs.orig/test.sh	2011-09-03 13:40:35.000000000 +0200
++++ genext2fs/test.sh	2011-09-03 14:21:17.000000000 +0200
+@@ -30,9 +30,9 @@
+ # Creates an image with a file of given size and verifies it
+ # Usage: dtest file-size number-of-blocks correct-checksum
+ dtest () {
+-	size=$1; blocks=$2; checksum=$3
++	size=$1; blocks=$2; blocksz=$3; checksum=$4
+ 	echo Testing with file of size $size
+-	dgen $size $blocks
++	dgen $size $blocks $blocksz
+ 	md5cmp $checksum
+ 	gen_cleanup
+ }
+@@ -53,12 +53,20 @@
+ # replace the following lines with the output of
+ # sudo sh test-mount.sh|grep test
+ 
+-dtest 0 4096 3bc6424b8fcd51a0de34ee59d91d5f16
+-dtest 0 8193 f174804f6b433b552706cbbfc60c416d
+-dtest 0 8194 4855a55d0cbdc44584634df49ebd5711
+-dtest 1 4096 09c569b6bfb45222c729c42d04d5451f
+-dtest 12288 4096 61febcbfbf32024ef99103fcdc282c39
+-dtest 274432 4096 0c517803552c55c1806e4220b0a0164f
+-dtest 8388608 9000 e0e5ea15bced10ab486d8135584b5d8e
+-dtest 16777216 20000 fdf636eb905ab4dc1bf76dce5ac5d209
++dtest 0 4096 1024 3bc6424b8fcd51a0de34ee59d91d5f16
++dtest 0 2048 2048 230afa16496df019878cc2370c661cdc
++dtest 0 1024 4096 ebff5eeb38b70f3f1cd081e60eb44561
++dtest 0 8193 1024 f174804f6b433b552706cbbfc60c416d
++dtest 0 8194 1024 4855a55d0cbdc44584634df49ebd5711
++dtest 0 8193 4096 c493679698418ec7e6552005e2d2a6d8
++dtest 0 8194 2048 ec13f328fa7543563f35f494bddc059c
++dtest 1 4096 1024 09c569b6bfb45222c729c42d04d5451f
++dtest 1 1024 4096 d318a326fdc907810ae9e6b0a20e9b06
++dtest 12288 4096 1024 61febcbfbf32024ef99103fcdc282c39
++dtest 274432 4096 1024 0c517803552c55c1806e4220b0a0164f
++dtest 8388608 9000 1024 e0e5ea15bced10ab486d8135584b5d8e
++dtest 8388608 4500 2048 39f4d537a72f5053fd6891721c59680d
++dtest 8388608 2250 4096 1d697fa4bc2cfffe02ac91edfadc40bf
++dtest 16777216 20000 1024 fdf636eb905ab4dc1bf76dce5ac5d209
++dtest 16777216 10000 2048 f9824a81ea5e74fdf469c097927c292b
+ ftest device_table.txt 4096 a0af06d944b11d2902dfd705484c64cc
diff --git a/tools/genext2fs/patches/400-byteswap_fix.patch b/tools/genext2fs/patches/400-byteswap_fix.patch
new file mode 100644
index 0000000000..7b3c00b5ee
--- /dev/null
+++ b/tools/genext2fs/patches/400-byteswap_fix.patch
@@ -0,0 +1,44 @@
+Index: genext2fs/genext2fs.c
+===================================================================
+--- genext2fs.orig/genext2fs.c	2011-11-29 17:36:06.000000000 +0100
++++ genext2fs/genext2fs.c	2011-11-29 17:37:37.000000000 +0100
+@@ -1779,7 +1779,8 @@
+ 	assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
+ 	for(i = 0; i < BLOCKSIZE/4; i++)
+ 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
+-			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
++			if (((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])
++				swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ 		return;
+@@ -1792,7 +1793,8 @@
+ 				     (BLOCKSIZE/4)*(BLOCKSIZE/4) + 
+ 				     i*(BLOCKSIZE/4)*(BLOCKSIZE/4) + 
+ 				     j*(BLOCKSIZE/4)) ) 
+-			  swap_block(get_blk(fs,b2[j]));
++			  if (b2[j])
++			  	swap_block(get_blk(fs,b2[j]));
+ 			else {
+ 			  done = 1;
+ 			  break;
+@@ -1825,7 +1827,8 @@
+ 	swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
+ 	for(i = 0; i < BLOCKSIZE/4; i++)
+ 		if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
+-			swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
++			if (((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])
++				swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
+ 	if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
+ 		return;
+ 	/* Adding support for triple indirection */
+@@ -1839,7 +1842,8 @@
+ 				     (BLOCKSIZE/4)*(BLOCKSIZE/4) + 
+ 				     i*(BLOCKSIZE/4)*(BLOCKSIZE/4) + 
+ 				     j*(BLOCKSIZE/4)) ) 
+-			  swap_block(get_blk(fs,b2[j]));
++			  if (b2[j])
++				swap_block(get_blk(fs,b2[j]));
+ 			else {
+ 			  done = 1;
+ 			  break;
diff --git a/tools/gengetopt/Makefile b/tools/gengetopt/Makefile
new file mode 100644
index 0000000000..74e528e6fd
--- /dev/null
+++ b/tools/gengetopt/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2014 OpenWrt.org
+#
+# This is free software, licengengetopt under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gengetopt
+PKG_VERSION:=2.22.6
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=29749a48dda69277ab969c510597a14e
+
+HOST_FIXUP := autoreconf
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/src/gengetopt $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/gengetopt
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/gengetopt/patches/100-dependency_fix.patch b/tools/gengetopt/patches/100-dependency_fix.patch
new file mode 100644
index 0000000000..69cb598b7d
--- /dev/null
+++ b/tools/gengetopt/patches/100-dependency_fix.patch
@@ -0,0 +1,11 @@
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -51,7 +51,7 @@ libgengetopt_la_LIBADD = $(top_builddir)
+ 	@LTLIBOBJS@ \
+ 	skels/libgen.la
+ 
+-LDADD = $(top_builddir)/src/libgengetopt.la
++LDADD = libgengetopt.la
+ 
+ EXTRA_DIST = parser.h argsdef.h gengetopt.h ggos.h gm.h gnugetopt.h \
+ cmdline.c cmdline.h \
diff --git a/tools/gengetopt/patches/200-no_docs_tests.patch b/tools/gengetopt/patches/200-no_docs_tests.patch
new file mode 100644
index 0000000000..d3930696ff
--- /dev/null
+++ b/tools/gengetopt/patches/200-no_docs_tests.patch
@@ -0,0 +1,13 @@
+diff -urN gengetopt-2.22.6/Makefile.am gengetopt-2.22.6.new/Makefile.am
+--- gengetopt-2.22.6/Makefile.am	2012-11-02 06:26:54.000000000 -0700
++++ gengetopt-2.22.6.new/Makefile.am	2015-05-21 17:43:15.183083542 -0700
+@@ -18,6 +18,6 @@
+ ACLOCAL_AMFLAGS = -I m4 -I gl/m4
+ 
+ EXTRA_DIST = configure TODO LICENSE gl/m4/gnulib-cache.m4
+-SUBDIRS = gl src doc tests
++SUBDIRS = gl src
+ 
+-gengetoptdoc_DATA = ChangeLog COPYING NEWS THANKS INSTALL README LICENSE
+\ No newline at end of file
++gengetoptdoc_DATA = ChangeLog COPYING NEWS THANKS INSTALL README LICENSE
diff --git a/tools/gmp/Makefile b/tools/gmp/Makefile
new file mode 100644
index 0000000000..38cede1e91
--- /dev/null
+++ b/tools/gmp/Makefile
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2009-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=gmp
+PKG_VERSION:=6.1.1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/gmp/
+PKG_MD5SUM:=e70e183609244a332d80529e7e155a35
+
+HOST_FIXUP:=autoreconf
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport CFLAGS
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static \
+	--disable-shared \
+	--disable-assembly \
+	--enable-cxx \
+	--enable-mpbsd
+
+ifeq ($(GNU_HOST_NAME),x86_64-linux-gnux32)
+HOST_CONFIGURE_ARGS += ABI=x32
+endif
+
+$(eval $(call HostBuild))
diff --git a/tools/include/byteswap.h b/tools/include/byteswap.h
new file mode 100644
index 0000000000..015f09740a
--- /dev/null
+++ b/tools/include/byteswap.h
@@ -0,0 +1,5 @@
+#if defined(__linux__) || defined(__CYGWIN__) 
+#include_next <byteswap.h>
+#else
+#include <endian.h>
+#endif
diff --git a/tools/include/elf.h b/tools/include/elf.h
new file mode 100644
index 0000000000..036a176345
--- /dev/null
+++ b/tools/include/elf.h
@@ -0,0 +1,3007 @@
+/* This file defines standard ELF types, structures, and macros.
+   Copyright (C) 1995-2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELF_H
+#define	_ELF_H 1
+
+/* Standard ELF types.  */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef	int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef	int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef	int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef	int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information.  */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf32_Half	e_type;			/* Object file type */
+  Elf32_Half	e_machine;		/* Architecture */
+  Elf32_Word	e_version;		/* Object file version */
+  Elf32_Addr	e_entry;		/* Entry point virtual address */
+  Elf32_Off	e_phoff;		/* Program header table file offset */
+  Elf32_Off	e_shoff;		/* Section header table file offset */
+  Elf32_Word	e_flags;		/* Processor-specific flags */
+  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf32_Half	e_phentsize;		/* Program header table entry size */
+  Elf32_Half	e_phnum;		/* Program header table entry count */
+  Elf32_Half	e_shentsize;		/* Section header table entry size */
+  Elf32_Half	e_shnum;		/* Section header table entry count */
+  Elf32_Half	e_shstrndx;		/* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf64_Half	e_type;			/* Object file type */
+  Elf64_Half	e_machine;		/* Architecture */
+  Elf64_Word	e_version;		/* Object file version */
+  Elf64_Addr	e_entry;		/* Entry point virtual address */
+  Elf64_Off	e_phoff;		/* Program header table file offset */
+  Elf64_Off	e_shoff;		/* Section header table file offset */
+  Elf64_Word	e_flags;		/* Processor-specific flags */
+  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf64_Half	e_phentsize;		/* Program header table entry size */
+  Elf64_Half	e_phnum;		/* Program header table entry count */
+  Elf64_Half	e_shentsize;		/* Section header table entry size */
+  Elf64_Half	e_shnum;		/* Section header table entry count */
+  Elf64_Half	e_shstrndx;		/* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0		0		/* File identification byte 0 index */
+#define ELFMAG0		0x7f		/* Magic number byte 0 */
+
+#define EI_MAG1		1		/* File identification byte 1 index */
+#define ELFMAG1		'E'		/* Magic number byte 1 */
+
+#define EI_MAG2		2		/* File identification byte 2 index */
+#define ELFMAG2		'L'		/* Magic number byte 2 */
+
+#define EI_MAG3		3		/* File identification byte 3 index */
+#define ELFMAG3		'F'		/* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define	ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define EI_CLASS	4		/* File class byte index */
+#define ELFCLASSNONE	0		/* Invalid class */
+#define ELFCLASS32	1		/* 32-bit objects */
+#define ELFCLASS64	2		/* 64-bit objects */
+#define ELFCLASSNUM	3
+
+#define EI_DATA		5		/* Data encoding byte index */
+#define ELFDATANONE	0		/* Invalid data encoding */
+#define ELFDATA2LSB	1		/* 2's complement, little endian */
+#define ELFDATA2MSB	2		/* 2's complement, big endian */
+#define ELFDATANUM	3
+
+#define EI_VERSION	6		/* File version byte index */
+					/* Value must be EV_CURRENT */
+
+#define EI_OSABI	7		/* OS ABI identification */
+#define ELFOSABI_NONE		0	/* UNIX System V ABI */
+#define ELFOSABI_SYSV		0	/* Alias.  */
+#define ELFOSABI_HPUX		1	/* HP-UX */
+#define ELFOSABI_NETBSD		2	/* NetBSD.  */
+#define ELFOSABI_GNU		3	/* Object uses GNU ELF extensions.  */
+#define ELFOSABI_LINUX		ELFOSABI_GNU /* Compatibility alias.  */
+#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
+#define ELFOSABI_AIX		7	/* IBM AIX.  */
+#define ELFOSABI_IRIX		8	/* SGI Irix.  */
+#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
+#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
+#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
+#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
+#define ELFOSABI_ARM		97	/* ARM */
+#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
+
+#define EI_ABIVERSION	8		/* ABI version */
+
+#define EI_PAD		9		/* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE		0		/* No file type */
+#define ET_REL		1		/* Relocatable file */
+#define ET_EXEC		2		/* Executable file */
+#define ET_DYN		3		/* Shared object file */
+#define ET_CORE		4		/* Core file */
+#define	ET_NUM		5		/* Number of defined types */
+#define ET_LOOS		0xfe00		/* OS-specific range start */
+#define ET_HIOS		0xfeff		/* OS-specific range end */
+#define ET_LOPROC	0xff00		/* Processor-specific range start */
+#define ET_HIPROC	0xffff		/* Processor-specific range end */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE		 0		/* No machine */
+#define EM_M32		 1		/* AT&T WE 32100 */
+#define EM_SPARC	 2		/* SUN SPARC */
+#define EM_386		 3		/* Intel 80386 */
+#define EM_68K		 4		/* Motorola m68k family */
+#define EM_88K		 5		/* Motorola m88k family */
+#define EM_860		 7		/* Intel 80860 */
+#define EM_MIPS		 8		/* MIPS R3000 big-endian */
+#define EM_S370		 9		/* IBM System/370 */
+#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
+
+#define EM_PARISC	15		/* HPPA */
+#define EM_VPP500	17		/* Fujitsu VPP500 */
+#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
+#define EM_960		19		/* Intel 80960 */
+#define EM_PPC		20		/* PowerPC */
+#define EM_PPC64	21		/* PowerPC 64-bit */
+#define EM_S390		22		/* IBM S390 */
+
+#define EM_V800		36		/* NEC V800 series */
+#define EM_FR20		37		/* Fujitsu FR20 */
+#define EM_RH32		38		/* TRW RH-32 */
+#define EM_RCE		39		/* Motorola RCE */
+#define EM_ARM		40		/* ARM */
+#define EM_FAKE_ALPHA	41		/* Digital Alpha */
+#define EM_SH		42		/* Hitachi SH */
+#define EM_SPARCV9	43		/* SPARC v9 64-bit */
+#define EM_TRICORE	44		/* Siemens Tricore */
+#define EM_ARC		45		/* Argonaut RISC Core */
+#define EM_H8_300	46		/* Hitachi H8/300 */
+#define EM_H8_300H	47		/* Hitachi H8/300H */
+#define EM_H8S		48		/* Hitachi H8S */
+#define EM_H8_500	49		/* Hitachi H8/500 */
+#define EM_IA_64	50		/* Intel Merced */
+#define EM_MIPS_X	51		/* Stanford MIPS-X */
+#define EM_COLDFIRE	52		/* Motorola Coldfire */
+#define EM_68HC12	53		/* Motorola M68HC12 */
+#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP		55		/* Siemens PCP */
+#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
+#define EM_NDR1		57		/* Denso NDR1 microprocessor */
+#define EM_STARCORE	58		/* Motorola Start*Core processor */
+#define EM_ME16		59		/* Toyota ME16 processor */
+#define EM_ST100	60		/* STMicroelectronic ST100 processor */
+#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64	62		/* AMD x86-64 architecture */
+#define EM_PDSP		63		/* Sony DSP Processor */
+
+#define EM_FX66		66		/* Siemens FX66 microcontroller */
+#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
+#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
+#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
+#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
+#define EM_SVX		73		/* Silicon Graphics SVx */
+#define EM_ST19		74		/* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX		75		/* Digital VAX */
+#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
+#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY	81		/* Harvard University machine-independent object files */
+#define EM_PRISM	82		/* SiTera Prism */
+#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
+#define EM_FR30		84		/* Fujitsu FR30 */
+#define EM_D10V		85		/* Mitsubishi D10V */
+#define EM_D30V		86		/* Mitsubishi D30V */
+#define EM_V850		87		/* NEC v850 */
+#define EM_M32R		88		/* Mitsubishi M32R */
+#define EM_MN10300	89		/* Matsushita MN10300 */
+#define EM_MN10200	90		/* Matsushita MN10200 */
+#define EM_PJ		91		/* picoJava */
+#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
+#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
+#define EM_TILEPRO	188		/* Tilera TILEPro */
+#define EM_TILEGX	191		/* Tilera TILE-Gx */
+#define EM_NUM		192
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+#define EM_ALPHA	0x9026
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE		0		/* Invalid ELF version */
+#define EV_CURRENT	1		/* Current version */
+#define EV_NUM		2
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word	sh_name;		/* Section name (string tbl index) */
+  Elf32_Word	sh_type;		/* Section type */
+  Elf32_Word	sh_flags;		/* Section flags */
+  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf32_Off	sh_offset;		/* Section file offset */
+  Elf32_Word	sh_size;		/* Section size in bytes */
+  Elf32_Word	sh_link;		/* Link to another section */
+  Elf32_Word	sh_info;		/* Additional section information */
+  Elf32_Word	sh_addralign;		/* Section alignment */
+  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word	sh_name;		/* Section name (string tbl index) */
+  Elf64_Word	sh_type;		/* Section type */
+  Elf64_Xword	sh_flags;		/* Section flags */
+  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf64_Off	sh_offset;		/* Section file offset */
+  Elf64_Xword	sh_size;		/* Section size in bytes */
+  Elf64_Word	sh_link;		/* Link to another section */
+  Elf64_Word	sh_info;		/* Additional section information */
+  Elf64_Xword	sh_addralign;		/* Section alignment */
+  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF	0		/* Undefined section */
+#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
+#define SHN_LOPROC	0xff00		/* Start of processor-specific */
+#define SHN_BEFORE	0xff00		/* Order section before all others
+					   (Solaris).  */
+#define SHN_AFTER	0xff01		/* Order section after all others
+					   (Solaris).  */
+#define SHN_HIPROC	0xff1f		/* End of processor-specific */
+#define SHN_LOOS	0xff20		/* Start of OS-specific */
+#define SHN_HIOS	0xff3f		/* End of OS-specific */
+#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
+#define SHN_COMMON	0xfff2		/* Associated symbol is common */
+#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
+#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL	  0		/* Section header table entry unused */
+#define SHT_PROGBITS	  1		/* Program data */
+#define SHT_SYMTAB	  2		/* Symbol table */
+#define SHT_STRTAB	  3		/* String table */
+#define SHT_RELA	  4		/* Relocation entries with addends */
+#define SHT_HASH	  5		/* Symbol hash table */
+#define SHT_DYNAMIC	  6		/* Dynamic linking information */
+#define SHT_NOTE	  7		/* Notes */
+#define SHT_NOBITS	  8		/* Program space with no data (bss) */
+#define SHT_REL		  9		/* Relocation entries, no addends */
+#define SHT_SHLIB	  10		/* Reserved */
+#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY	  14		/* Array of constructors */
+#define SHT_FINI_ARRAY	  15		/* Array of destructors */
+#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
+#define SHT_GROUP	  17		/* Section group */
+#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
+#define	SHT_NUM		  19		/* Number of defined types.  */
+#define SHT_LOOS	  0x60000000	/* Start OS-specific.  */
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes.  */
+#define SHT_GNU_HASH	  0x6ffffff6	/* GNU-style hash table.  */
+#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
+#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
+#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
+#define SHT_SUNW_move	  0x6ffffffa
+#define SHT_SUNW_COMDAT   0x6ffffffb
+#define SHT_SUNW_syminfo  0x6ffffffc
+#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
+#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
+#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
+#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
+#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
+#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
+#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
+#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
+#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE	     (1 << 0)	/* Writable */
+#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
+#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
+#define SHF_MERGE	     (1 << 4)	/* Might be merged */
+#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
+#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
+					   required */
+#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
+#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
+#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
+#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
+#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
+					   (Solaris).  */
+#define SHF_EXCLUDE	     (1 << 31)	/* Section is excluded unless
+					   referenced or allocated (Solaris).*/
+
+/* Section group handling.  */
+#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
+  Elf32_Addr	st_value;		/* Symbol value */
+  Elf32_Word	st_size;		/* Symbol size */
+  unsigned char	st_info;		/* Symbol type and binding */
+  unsigned char	st_other;		/* Symbol visibility */
+  Elf32_Section	st_shndx;		/* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
+  unsigned char	st_info;		/* Symbol type and binding */
+  unsigned char st_other;		/* Symbol visibility */
+  Elf64_Section	st_shndx;		/* Section index */
+  Elf64_Addr	st_value;		/* Symbol value */
+  Elf64_Xword	st_size;		/* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+   every dynamic symbol.  */
+
+typedef struct
+{
+  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
+  Elf32_Half si_flags;			/* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
+  Elf64_Half si_flags;			/* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto.  */
+#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
+#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags.  */
+#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
+					   loaded */
+/* Syminfo version values.  */
+#define SYMINFO_NONE		0
+#define SYMINFO_CURRENT		1
+#define SYMINFO_NUM		2
+
+
+/* How to extract and insert information held in the st_info field.  */
+
+#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)		((val) & 0xf)
+#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
+#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+
+#define STB_LOCAL	0		/* Local symbol */
+#define STB_GLOBAL	1		/* Global symbol */
+#define STB_WEAK	2		/* Weak symbol */
+#define	STB_NUM		3		/* Number of defined types.  */
+#define STB_LOOS	10		/* Start of OS-specific */
+#define STB_GNU_UNIQUE	10		/* Unique symbol.  */
+#define STB_HIOS	12		/* End of OS-specific */
+#define STB_LOPROC	13		/* Start of processor-specific */
+#define STB_HIPROC	15		/* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_NOTYPE	0		/* Symbol type is unspecified */
+#define STT_OBJECT	1		/* Symbol is a data object */
+#define STT_FUNC	2		/* Symbol is a code object */
+#define STT_SECTION	3		/* Symbol associated with a section */
+#define STT_FILE	4		/* Symbol's name is file name */
+#define STT_COMMON	5		/* Symbol is a common data object */
+#define STT_TLS		6		/* Symbol is thread-local data object*/
+#define	STT_NUM		7		/* Number of defined types.  */
+#define STT_LOOS	10		/* Start of OS-specific */
+#define STT_GNU_IFUNC	10		/* Symbol is indirect code object */
+#define STT_HIOS	12		/* End of OS-specific */
+#define STT_LOPROC	13		/* Start of processor-specific */
+#define STT_HIPROC	15		/* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+   of a symbol hash table section.  This special index value indicates
+   the end of a chain, meaning no further symbols are found in that bucket.  */
+
+#define STN_UNDEF	0		/* End of a chain.  */
+
+
+/* How to extract and insert information held in the st_other field.  */
+
+#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
+
+/* For ELF64 the definitions are the same.  */
+#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field.  */
+#define STV_DEFAULT	0		/* Default symbol visibility rules */
+#define STV_INTERNAL	1		/* Processor specific hidden class */
+#define STV_HIDDEN	2		/* Sym unavailable in other modules */
+#define STV_PROTECTED	3		/* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL).  */
+
+typedef struct
+{
+  Elf32_Addr	r_offset;		/* Address */
+  Elf32_Word	r_info;			/* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+   Elf64_Rela structures, so we'll leave them out until Novell (or
+   whoever) gets their act together.  */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
+
+typedef struct
+{
+  Elf64_Addr	r_offset;		/* Address */
+  Elf64_Xword	r_info;			/* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA).  */
+
+typedef struct
+{
+  Elf32_Addr	r_offset;		/* Address */
+  Elf32_Word	r_info;			/* Relocation type and symbol index */
+  Elf32_Sword	r_addend;		/* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+  Elf64_Addr	r_offset;		/* Address */
+  Elf64_Xword	r_info;			/* Relocation type and symbol index */
+  Elf64_Sxword	r_addend;		/* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field.  */
+
+#define ELF32_R_SYM(val)		((val) >> 8)
+#define ELF32_R_TYPE(val)		((val) & 0xff)
+#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i)			((i) >> 32)
+#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header.  */
+
+typedef struct
+{
+  Elf32_Word	p_type;			/* Segment type */
+  Elf32_Off	p_offset;		/* Segment file offset */
+  Elf32_Addr	p_vaddr;		/* Segment virtual address */
+  Elf32_Addr	p_paddr;		/* Segment physical address */
+  Elf32_Word	p_filesz;		/* Segment size in file */
+  Elf32_Word	p_memsz;		/* Segment size in memory */
+  Elf32_Word	p_flags;		/* Segment flags */
+  Elf32_Word	p_align;		/* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word	p_type;			/* Segment type */
+  Elf64_Word	p_flags;		/* Segment flags */
+  Elf64_Off	p_offset;		/* Segment file offset */
+  Elf64_Addr	p_vaddr;		/* Segment virtual address */
+  Elf64_Addr	p_paddr;		/* Segment physical address */
+  Elf64_Xword	p_filesz;		/* Segment size in file */
+  Elf64_Xword	p_memsz;		/* Segment size in memory */
+  Elf64_Xword	p_align;		/* Segment alignment */
+} Elf64_Phdr;
+
+/* Special value for e_phnum.  This indicates that the real number of
+   program headers is too large to fit into e_phnum.  Instead the real
+   value is in the field sh_info of section 0.  */
+
+#define PN_XNUM		0xffff
+
+/* Legal values for p_type (segment type).  */
+
+#define	PT_NULL		0		/* Program header table entry unused */
+#define PT_LOAD		1		/* Loadable program segment */
+#define PT_DYNAMIC	2		/* Dynamic linking information */
+#define PT_INTERP	3		/* Program interpreter */
+#define PT_NOTE		4		/* Auxiliary information */
+#define PT_SHLIB	5		/* Reserved */
+#define PT_PHDR		6		/* Entry for header table itself */
+#define PT_TLS		7		/* Thread-local storage segment */
+#define	PT_NUM		8		/* Number of defined types */
+#define PT_LOOS		0x60000000	/* Start of OS-specific */
+#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
+#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
+#define PT_LOSUNW	0x6ffffffa
+#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
+#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
+#define PT_HISUNW	0x6fffffff
+#define PT_HIOS		0x6fffffff	/* End of OS-specific */
+#define PT_LOPROC	0x70000000	/* Start of processor-specific */
+#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X		(1 << 0)	/* Segment is executable */
+#define PF_W		(1 << 1)	/* Segment is writable */
+#define PF_R		(1 << 2)	/* Segment is readable */
+#define PF_MASKOS	0x0ff00000	/* OS-specific */
+#define PF_MASKPROC	0xf0000000	/* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
+#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
+#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
+#define NT_PRXREG	4		/* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
+#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV		6		/* Contains copy of auxv array */
+#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
+#define NT_ASRS		8		/* Contains copy of asrset struct */
+#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
+#define NT_PSINFO	13		/* Contains copy of psinfo struct */
+#define NT_PRCRED	14		/* Contains copy of prcred struct */
+#define NT_UTSNAME	15		/* Contains copy of utsname struct */
+#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct */
+#define NT_PRXFPREG	0x46e62b7f	/* Contains copy of user_fxsr_struct */
+#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
+#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
+#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
+#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
+
+/* Legal values for the note segment descriptor types for object files.  */
+
+#define NT_VERSION	1		/* Contains a version string.  */
+
+
+/* Dynamic section entry.  */
+
+typedef struct
+{
+  Elf32_Sword	d_tag;			/* Dynamic entry type */
+  union
+    {
+      Elf32_Word d_val;			/* Integer value */
+      Elf32_Addr d_ptr;			/* Address value */
+    } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+  Elf64_Sxword	d_tag;			/* Dynamic entry type */
+  union
+    {
+      Elf64_Xword d_val;		/* Integer value */
+      Elf64_Addr d_ptr;			/* Address value */
+    } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type).  */
+
+#define DT_NULL		0		/* Marks end of dynamic section */
+#define DT_NEEDED	1		/* Name of needed library */
+#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
+#define DT_PLTGOT	3		/* Processor defined value */
+#define DT_HASH		4		/* Address of symbol hash table */
+#define DT_STRTAB	5		/* Address of string table */
+#define DT_SYMTAB	6		/* Address of symbol table */
+#define DT_RELA		7		/* Address of Rela relocs */
+#define DT_RELASZ	8		/* Total size of Rela relocs */
+#define DT_RELAENT	9		/* Size of one Rela reloc */
+#define DT_STRSZ	10		/* Size of string table */
+#define DT_SYMENT	11		/* Size of one symbol table entry */
+#define DT_INIT		12		/* Address of init function */
+#define DT_FINI		13		/* Address of termination function */
+#define DT_SONAME	14		/* Name of shared object */
+#define DT_RPATH	15		/* Library search path (deprecated) */
+#define DT_SYMBOLIC	16		/* Start symbol search here */
+#define DT_REL		17		/* Address of Rel relocs */
+#define DT_RELSZ	18		/* Total size of Rel relocs */
+#define DT_RELENT	19		/* Size of one Rel reloc */
+#define DT_PLTREL	20		/* Type of reloc in PLT */
+#define DT_DEBUG	21		/* For debugging; unspecified */
+#define DT_TEXTREL	22		/* Reloc might modify .text */
+#define DT_JMPREL	23		/* Address of PLT relocs */
+#define	DT_BIND_NOW	24		/* Process relocations of object */
+#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
+#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
+#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
+#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH	29		/* Library search path */
+#define DT_FLAGS	30		/* Flags for the object being loaded */
+#define DT_ENCODING	32		/* Start of encoded range */
+#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
+#define	DT_NUM		34		/* Number used */
+#define DT_LOOS		0x6000000d	/* Start of OS-specific */
+#define DT_HIOS		0x6ffff000	/* End of OS-specific */
+#define DT_LOPROC	0x70000000	/* Start of processor-specific */
+#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
+#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
+   approach.  */
+#define DT_VALRNGLO	0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
+#define DT_CHECKSUM	0x6ffffdf8
+#define DT_PLTPADSZ	0x6ffffdf9
+#define DT_MOVEENT	0x6ffffdfa
+#define DT_MOVESZ	0x6ffffdfb
+#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
+#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
+					   the following DT_* entry.  */
+#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
+#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
+#define DT_VALRNGHI	0x6ffffdff
+#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+   If any adjustment is made to the ELF object after it has been
+   built these entries will need to be adjusted.  */
+#define DT_ADDRRNGLO	0x6ffffe00
+#define DT_GNU_HASH	0x6ffffef5	/* GNU-style hash table.  */
+#define DT_TLSDESC_PLT	0x6ffffef6
+#define DT_TLSDESC_GOT	0x6ffffef7
+#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
+#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
+#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
+#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
+#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
+#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
+#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
+#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
+#define DT_ADDRRNGHI	0x6ffffeff
+#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
+#define DT_ADDRNUM 11
+
+/* The versioning entry types.  The next are defined as part of the
+   GNU extension.  */
+#define DT_VERSYM	0x6ffffff0
+
+#define DT_RELACOUNT	0x6ffffff9
+#define DT_RELCOUNT	0x6ffffffa
+
+/* These were chosen by Sun.  */
+#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
+#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
+					   table */
+#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
+#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
+					   versions */
+#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+   range.  Be compatible.  */
+#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
+#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM	3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
+#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
+#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
+#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
+#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+   entry in the dynamic section.  */
+#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
+#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
+#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
+#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
+#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
+#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
+#define DF_1_TRANS	0x00000200
+#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
+#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
+#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
+#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
+#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
+#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
+#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
+
+/* Flags for the feature selection in DT_FEATURE_1.  */
+#define DTF_1_PARINIT	0x00000001
+#define DTF_1_CONFEXP	0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
+#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
+#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
+					   generally available.  */
+
+/* Version definition sections.  */
+
+typedef struct
+{
+  Elf32_Half	vd_version;		/* Version revision */
+  Elf32_Half	vd_flags;		/* Version information */
+  Elf32_Half	vd_ndx;			/* Version Index */
+  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
+  Elf32_Word	vd_hash;		/* Version name hash value */
+  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
+  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
+					   entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+  Elf64_Half	vd_version;		/* Version revision */
+  Elf64_Half	vd_flags;		/* Version information */
+  Elf64_Half	vd_ndx;			/* Version Index */
+  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
+  Elf64_Word	vd_hash;		/* Version name hash value */
+  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
+  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
+					   entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision).  */
+#define VER_DEF_NONE	0		/* No version */
+#define VER_DEF_CURRENT	1		/* Current version */
+#define VER_DEF_NUM	2		/* Given version number */
+
+/* Legal values for vd_flags (version information flags).  */
+#define VER_FLG_BASE	0x1		/* Version definition of file itself */
+#define VER_FLG_WEAK	0x2		/* Weak version identifier */
+
+/* Versym symbol index values.  */
+#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
+#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
+#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
+#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
+
+/* Auxialiary version information.  */
+
+typedef struct
+{
+  Elf32_Word	vda_name;		/* Version or dependency names */
+  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
+					   entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+  Elf64_Word	vda_name;		/* Version or dependency names */
+  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
+					   entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section.  */
+
+typedef struct
+{
+  Elf32_Half	vn_version;		/* Version of structure */
+  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
+  Elf32_Word	vn_file;		/* Offset of filename for this
+					   dependency */
+  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
+  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
+					   entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+  Elf64_Half	vn_version;		/* Version of structure */
+  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
+  Elf64_Word	vn_file;		/* Offset of filename for this
+					   dependency */
+  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
+  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
+					   entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision).  */
+#define VER_NEED_NONE	 0		/* No version */
+#define VER_NEED_CURRENT 1		/* Current version */
+#define VER_NEED_NUM	 2		/* Given version number */
+
+/* Auxiliary needed version information.  */
+
+typedef struct
+{
+  Elf32_Word	vna_hash;		/* Hash value of dependency name */
+  Elf32_Half	vna_flags;		/* Dependency specific information */
+  Elf32_Half	vna_other;		/* Unused */
+  Elf32_Word	vna_name;		/* Dependency name string offset */
+  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
+					   entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+  Elf64_Word	vna_hash;		/* Hash value of dependency name */
+  Elf64_Half	vna_flags;		/* Dependency specific information */
+  Elf64_Half	vna_other;		/* Unused */
+  Elf64_Word	vna_name;		/* Dependency name string offset */
+  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
+					   entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags.  */
+#define VER_FLG_WEAK	0x2		/* Weak version identifier */
+
+
+/* Auxiliary vector.  */
+
+/* This vector is normally only used by the program interpreter.  The
+   usual definition in an ABI supplement uses the name auxv_t.  The
+   vector is not usually defined in a standard <elf.h> file, but it
+   can't hurt.  We rename it to avoid conflicts.  The sizes of these
+   types are an arrangement between the exec server and the program
+   interpreter, so we don't fully specify them here.  */
+
+typedef struct
+{
+  uint32_t a_type;		/* Entry type */
+  union
+    {
+      uint32_t a_val;		/* Integer value */
+      /* We use to have pointer elements added here.  We cannot do that,
+	 though, since it does not work when using 32-bit definitions
+	 on 64-bit platforms and vice versa.  */
+    } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+  uint64_t a_type;		/* Entry type */
+  union
+    {
+      uint64_t a_val;		/* Integer value */
+      /* We use to have pointer elements added here.  We cannot do that,
+	 though, since it does not work when using 32-bit definitions
+	 on 64-bit platforms and vice versa.  */
+    } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type).  */
+
+#define AT_NULL		0		/* End of vector */
+#define AT_IGNORE	1		/* Entry should be ignored */
+#define AT_EXECFD	2		/* File descriptor of program */
+#define AT_PHDR		3		/* Program headers for program */
+#define AT_PHENT	4		/* Size of program header entry */
+#define AT_PHNUM	5		/* Number of program headers */
+#define AT_PAGESZ	6		/* System page size */
+#define AT_BASE		7		/* Base address of interpreter */
+#define AT_FLAGS	8		/* Flags */
+#define AT_ENTRY	9		/* Entry point of program */
+#define AT_NOTELF	10		/* Program is not ELF */
+#define AT_UID		11		/* Real uid */
+#define AT_EUID		12		/* Effective uid */
+#define AT_GID		13		/* Real gid */
+#define AT_EGID		14		/* Effective gid */
+#define AT_CLKTCK	17		/* Frequency of times() */
+
+/* Some more special a_type values describing the hardware.  */
+#define AT_PLATFORM	15		/* String identifying platform.  */
+#define AT_HWCAP	16		/* Machine dependent hints about
+					   processor capabilities.  */
+
+/* This entry gives some information about the FPU initialization
+   performed by the kernel.  */
+#define AT_FPUCW	18		/* Used FPU control word.  */
+
+/* Cache block sizes.  */
+#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
+#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
+#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
+
+/* A special ignored value for PPC, used by the kernel to control the
+   interpretation of the AUXV. Must be > 16.  */
+#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
+
+#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
+
+#define AT_BASE_PLATFORM 24		/* String identifying real platforms.*/
+
+#define AT_RANDOM	25		/* Address of 16 random bytes.  */
+
+#define AT_EXECFN	31		/* Filename of executable.  */
+
+/* Pointer to the global system page used for system calls and other
+   nice things.  */
+#define AT_SYSINFO	32
+#define AT_SYSINFO_EHDR	33
+
+/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
+   log2 of line size; mask those to get cache size.  */
+#define AT_L1I_CACHESHAPE	34
+#define AT_L1D_CACHESHAPE	35
+#define AT_L2_CACHESHAPE	36
+#define AT_L3_CACHESHAPE	37
+
+/* Note section contents.  Each entry in the note section begins with
+   a header of a fixed form.  */
+
+typedef struct
+{
+  Elf32_Word n_namesz;			/* Length of the note's name.  */
+  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf32_Word n_type;			/* Type of the note.  */
+} Elf32_Nhdr;
+
+typedef struct
+{
+  Elf64_Word n_namesz;			/* Length of the note's name.  */
+  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf64_Word n_type;			/* Type of the note.  */
+} Elf64_Nhdr;
+
+/* Known names of notes.  */
+
+/* Solaris entries in the note section have this name.  */
+#define ELF_NOTE_SOLARIS	"SUNW Solaris"
+
+/* Note entries for GNU systems have this name.  */
+#define ELF_NOTE_GNU		"GNU"
+
+
+/* Defined types of notes for Solaris.  */
+
+/* Value of descriptor (one word) is desired pagesize for the binary.  */
+#define ELF_NOTE_PAGESIZE_HINT	1
+
+
+/* Defined note types for GNU systems.  */
+
+/* ABI information.  The descriptor consists of words:
+   word 0: OS descriptor
+   word 1: major version of the ABI
+   word 2: minor version of the ABI
+   word 3: subminor version of the ABI
+*/
+#define NT_GNU_ABI_TAG	1
+#define ELF_NOTE_ABI	NT_GNU_ABI_TAG /* Old name.  */
+
+/* Known OSes.  These values can appear in word 0 of an
+   NT_GNU_ABI_TAG note section entry.  */
+#define ELF_NOTE_OS_LINUX	0
+#define ELF_NOTE_OS_GNU		1
+#define ELF_NOTE_OS_SOLARIS2	2
+#define ELF_NOTE_OS_FREEBSD	3
+
+/* Synthetic hwcap information.  The descriptor begins with two words:
+   word 0: number of entries
+   word 1: bitmask of enabled entries
+   Then follow variable-length entries, one byte followed by a
+   '\0'-terminated hwcap name string.  The byte gives the bit
+   number to test if enabled, (1U << bit) & bitmask.  */
+#define NT_GNU_HWCAP	2
+
+/* Build ID bits as generated by ld --build-id.
+   The descriptor consists of any nonzero number of bytes.  */
+#define NT_GNU_BUILD_ID	3
+
+/* Version note generated by GNU gold containing a version string.  */
+#define NT_GNU_GOLD_VERSION	4
+
+
+/* Move records.  */
+typedef struct
+{
+  Elf32_Xword m_value;		/* Symbol value.  */
+  Elf32_Word m_info;		/* Size and index.  */
+  Elf32_Word m_poffset;		/* Symbol offset.  */
+  Elf32_Half m_repeat;		/* Repeat count.  */
+  Elf32_Half m_stride;		/* Stride info.  */
+} Elf32_Move;
+
+typedef struct
+{
+  Elf64_Xword m_value;		/* Symbol value.  */
+  Elf64_Xword m_info;		/* Size and index.  */
+  Elf64_Xword m_poffset;	/* Symbol offset.  */
+  Elf64_Half m_repeat;		/* Repeat count.  */
+  Elf64_Half m_stride;		/* Stride info.  */
+} Elf64_Move;
+
+/* Macro to construct move records.  */
+#define ELF32_M_SYM(info)	((info) >> 8)
+#define ELF32_M_SIZE(info)	((unsigned char) (info))
+#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions.  */
+
+/* Values for Elf32_Ehdr.e_flags.  */
+#define EF_CPU32	0x00810000
+
+/* m68k relocs.  */
+
+#define R_68K_NONE	0		/* No reloc */
+#define R_68K_32	1		/* Direct 32 bit  */
+#define R_68K_16	2		/* Direct 16 bit  */
+#define R_68K_8		3		/* Direct 8 bit  */
+#define R_68K_PC32	4		/* PC relative 32 bit */
+#define R_68K_PC16	5		/* PC relative 16 bit */
+#define R_68K_PC8	6		/* PC relative 8 bit */
+#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
+#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
+#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O	10		/* 32 bit GOT offset */
+#define R_68K_GOT16O	11		/* 16 bit GOT offset */
+#define R_68K_GOT8O	12		/* 8 bit GOT offset */
+#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
+#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
+#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
+#define R_68K_PLT32O	16		/* 32 bit PLT offset */
+#define R_68K_PLT16O	17		/* 16 bit PLT offset */
+#define R_68K_PLT8O	18		/* 8 bit PLT offset */
+#define R_68K_COPY	19		/* Copy symbol at runtime */
+#define R_68K_GLOB_DAT	20		/* Create GOT entry */
+#define R_68K_JMP_SLOT	21		/* Create PLT entry */
+#define R_68K_RELATIVE	22		/* Adjust by program base */
+#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
+#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
+/* Keep this the last entry.  */
+#define R_68K_NUM	43
+
+/* Intel 80386 specific definitions.  */
+
+/* i386 relocs.  */
+
+#define R_386_NONE	   0		/* No reloc */
+#define R_386_32	   1		/* Direct 32 bit  */
+#define R_386_PC32	   2		/* PC relative 32 bit */
+#define R_386_GOT32	   3		/* 32 bit GOT entry */
+#define R_386_PLT32	   4		/* 32 bit PLT address */
+#define R_386_COPY	   5		/* Copy symbol at runtime */
+#define R_386_GLOB_DAT	   6		/* Create GOT entry */
+#define R_386_JMP_SLOT	   7		/* Create PLT entry */
+#define R_386_RELATIVE	   8		/* Adjust by program base */
+#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
+#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
+#define R_386_32PLT	   11
+#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
+#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
+					   block offset */
+#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
+					   offset */
+#define R_386_TLS_LE	   17		/* Offset relative to static TLS
+					   block */
+#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
+					   general dynamic thread local data */
+#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
+					   local dynamic thread local data
+					   in LE code */
+#define R_386_16	   20
+#define R_386_PC16	   21
+#define R_386_8		   22
+#define R_386_PC8	   23
+#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
+					   thread local data */
+#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL  26		/* Relocation for call to
+					   __tls_get_addr() */
+#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
+					   thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
+					   __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
+#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
+					   block offset */
+#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
+					   TLS block */
+#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
+#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
+/* 38? */
+#define R_386_TLS_GOTDESC  39		/* GOT offset for TLS descriptor.  */
+#define R_386_TLS_DESC_CALL 40		/* Marker of call through TLS
+					   descriptor for
+					   relaxation.  */
+#define R_386_TLS_DESC     41		/* TLS descriptor containing
+					   pointer to code and to
+					   argument, returning the TLS
+					   offset for the symbol.  */
+#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
+/* Keep this the last entry.  */
+#define R_386_NUM	   43
+
+/* SUN SPARC specific definitions.  */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags.  */
+
+#define EF_SPARCV9_MM		3
+#define EF_SPARCV9_TSO		0
+#define EF_SPARCV9_PSO		1
+#define EF_SPARCV9_RMO		2
+#define EF_SPARC_LEDATA		0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK	0xFFFF00
+#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs.  */
+
+#define R_SPARC_NONE		0	/* No reloc */
+#define R_SPARC_8		1	/* Direct 8 bit */
+#define R_SPARC_16		2	/* Direct 16 bit */
+#define R_SPARC_32		3	/* Direct 32 bit */
+#define R_SPARC_DISP8		4	/* PC relative 8 bit */
+#define R_SPARC_DISP16		5	/* PC relative 16 bit */
+#define R_SPARC_DISP32		6	/* PC relative 32 bit */
+#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
+#define R_SPARC_HI22		9	/* High 22 bit */
+#define R_SPARC_22		10	/* Direct 22 bit */
+#define R_SPARC_13		11	/* Direct 13 bit */
+#define R_SPARC_LO10		12	/* Truncated 10 bit */
+#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
+#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
+#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
+#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
+#define R_SPARC_COPY		19	/* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
+#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
+#define R_SPARC_RELATIVE	22	/* Adjust by program base */
+#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs.  */
+
+#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10		30	/* Direct 10 bit */
+#define R_SPARC_11		31	/* Direct 11 bit */
+#define R_SPARC_64		32	/* Direct 64 bit */
+#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
+#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
+#define R_SPARC_GLOB_JMP	42	/* was part of v9 ABI but was removed */
+#define R_SPARC_7		43	/* Direct 7 bit */
+#define R_SPARC_5		44	/* Direct 5 bit */
+#define R_SPARC_6		45	/* Direct 6 bit */
+#define R_SPARC_DISP64		46	/* PC relative 64 bit */
+#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22		48	/* High 22 bit complemented */
+#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
+#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
+#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
+#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER	53	/* Global register usage */
+#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
+#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22	56
+#define R_SPARC_TLS_GD_LO10	57
+#define R_SPARC_TLS_GD_ADD	58
+#define R_SPARC_TLS_GD_CALL	59
+#define R_SPARC_TLS_LDM_HI22	60
+#define R_SPARC_TLS_LDM_LO10	61
+#define R_SPARC_TLS_LDM_ADD	62
+#define R_SPARC_TLS_LDM_CALL	63
+#define R_SPARC_TLS_LDO_HIX22	64
+#define R_SPARC_TLS_LDO_LOX10	65
+#define R_SPARC_TLS_LDO_ADD	66
+#define R_SPARC_TLS_IE_HI22	67
+#define R_SPARC_TLS_IE_LO10	68
+#define R_SPARC_TLS_IE_LD	69
+#define R_SPARC_TLS_IE_LDX	70
+#define R_SPARC_TLS_IE_ADD	71
+#define R_SPARC_TLS_LE_HIX22	72
+#define R_SPARC_TLS_LE_LOX10	73
+#define R_SPARC_TLS_DTPMOD32	74
+#define R_SPARC_TLS_DTPMOD64	75
+#define R_SPARC_TLS_DTPOFF32	76
+#define R_SPARC_TLS_DTPOFF64	77
+#define R_SPARC_TLS_TPOFF32	78
+#define R_SPARC_TLS_TPOFF64	79
+#define R_SPARC_GOTDATA_HIX22	80
+#define R_SPARC_GOTDATA_LOX10	81
+#define R_SPARC_GOTDATA_OP_HIX22	82
+#define R_SPARC_GOTDATA_OP_LOX10	83
+#define R_SPARC_GOTDATA_OP	84
+#define R_SPARC_H34		85
+#define R_SPARC_SIZE32		86
+#define R_SPARC_SIZE64		87
+#define R_SPARC_WDISP10		88
+#define R_SPARC_JMP_IREL	248
+#define R_SPARC_IRELATIVE	249
+#define R_SPARC_GNU_VTINHERIT	250
+#define R_SPARC_GNU_VTENTRY	251
+#define R_SPARC_REV32		252
+/* Keep this the last entry.  */
+#define R_SPARC_NUM		253
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM	2
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
+#define EF_MIPS_PIC	    2		/* Contains PIC code */
+#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
+#define EF_MIPS_XGOT	    8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2	    32
+#define EF_MIPS_ABI_ON32    64
+#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
+
+/* Legal values for MIPS architecture level.  */
+
+#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
+#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
+#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
+#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
+#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
+#define EF_MIPS_ARCH_32	    0x60000000	/* MIPS32 code.  */
+#define EF_MIPS_ARCH_64	    0x70000000	/* MIPS64 code.  */
+
+/* The following are non-official names and should not be used.  */
+
+#define E_MIPS_ARCH_1	  0x00000000	/* -mips1 code.  */
+#define E_MIPS_ARCH_2	  0x10000000	/* -mips2 code.  */
+#define E_MIPS_ARCH_3	  0x20000000	/* -mips3 code.  */
+#define E_MIPS_ARCH_4	  0x30000000	/* -mips4 code.  */
+#define E_MIPS_ARCH_5	  0x40000000	/* -mips5 code.  */
+#define E_MIPS_ARCH_32	  0x60000000	/* MIPS32 code.  */
+#define E_MIPS_ARCH_64	  0x70000000	/* MIPS64 code.  */
+
+/* Special section indices.  */
+
+#define SHN_MIPS_ACOMMON    0xff00	/* Allocated common symbols */
+#define SHN_MIPS_TEXT	    0xff01	/* Allocated test symbols.  */
+#define SHN_MIPS_DATA	    0xff02	/* Allocated data symbols.  */
+#define SHN_MIPS_SCOMMON    0xff03	/* Small common symbols */
+#define SHN_MIPS_SUNDEFINED 0xff04	/* Small undefined symbols */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
+#define SHT_MIPS_MSYM	       0x70000001
+#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
+#define SHT_MIPS_GPTAB	       0x70000003 /* Global data area sizes */
+#define SHT_MIPS_UCODE	       0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG	       0x70000005 /* MIPS ECOFF debugging information*/
+#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
+#define SHT_MIPS_PACKAGE       0x70000007
+#define SHT_MIPS_PACKSYM       0x70000008
+#define SHT_MIPS_RELD	       0x70000009
+#define SHT_MIPS_IFACE         0x7000000b
+#define SHT_MIPS_CONTENT       0x7000000c
+#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
+#define SHT_MIPS_SHDR	       0x70000010
+#define SHT_MIPS_FDESC	       0x70000011
+#define SHT_MIPS_EXTSYM	       0x70000012
+#define SHT_MIPS_DENSE	       0x70000013
+#define SHT_MIPS_PDESC	       0x70000014
+#define SHT_MIPS_LOCSYM	       0x70000015
+#define SHT_MIPS_AUXSYM	       0x70000016
+#define SHT_MIPS_OPTSYM	       0x70000017
+#define SHT_MIPS_LOCSTR	       0x70000018
+#define SHT_MIPS_LINE	       0x70000019
+#define SHT_MIPS_RFDESC	       0x7000001a
+#define SHT_MIPS_DELTASYM      0x7000001b
+#define SHT_MIPS_DELTAINST     0x7000001c
+#define SHT_MIPS_DELTACLASS    0x7000001d
+#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
+#define SHT_MIPS_DELTADECL     0x7000001f
+#define SHT_MIPS_SYMBOL_LIB    0x70000020
+#define SHT_MIPS_EVENTS	       0x70000021 /* Event section.  */
+#define SHT_MIPS_TRANSLATE     0x70000022
+#define SHT_MIPS_PIXIE	       0x70000023
+#define SHT_MIPS_XLATE	       0x70000024
+#define SHT_MIPS_XLATE_DEBUG   0x70000025
+#define SHT_MIPS_WHIRL	       0x70000026
+#define SHT_MIPS_EH_REGION     0x70000027
+#define SHT_MIPS_XLATE_OLD     0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_MIPS_GPREL	 0x10000000	/* Must be part of global data area */
+#define SHF_MIPS_MERGE	 0x20000000
+#define SHF_MIPS_ADDR	 0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL	 0x04000000
+#define SHF_MIPS_NAMES	 0x02000000
+#define SHF_MIPS_NODUPE	 0x01000000
+
+
+/* Symbol tables.  */
+
+/* MIPS specific values for `st_other'.  */
+#define STO_MIPS_DEFAULT		0x0
+#define STO_MIPS_INTERNAL		0x1
+#define STO_MIPS_HIDDEN			0x2
+#define STO_MIPS_PROTECTED		0x3
+#define STO_MIPS_PLT			0x8
+#define STO_MIPS_SC_ALIGN_UNUSED	0xff
+
+/* MIPS specific values for `st_info'.  */
+#define STB_MIPS_SPLIT_COMMON		13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB.  */
+
+typedef union
+{
+  struct
+    {
+      Elf32_Word gt_current_g_value;	/* -G value used for compilation */
+      Elf32_Word gt_unused;		/* Not used */
+    } gt_header;			/* First entry in section */
+  struct
+    {
+      Elf32_Word gt_g_value;		/* If this value were used for -G */
+      Elf32_Word gt_bytes;		/* This many bytes would be used */
+    } gt_entry;				/* Subsequent entries in section */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO.  */
+
+typedef struct
+{
+  Elf32_Word	ri_gprmask;		/* General registers used */
+  Elf32_Word	ri_cprmask[4];		/* Coprocessor registers used */
+  Elf32_Sword	ri_gp_value;		/* $gp register value */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
+
+typedef struct
+{
+  unsigned char kind;		/* Determines interpretation of the
+				   variable part of descriptor.  */
+  unsigned char size;		/* Size of descriptor, including header.  */
+  Elf32_Section section;	/* Section header index of section affected,
+				   0 for global options.  */
+  Elf32_Word info;		/* Kind-specific information.  */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options.  */
+
+#define ODK_NULL	0	/* Undefined.  */
+#define ODK_REGINFO	1	/* Register usage information.  */
+#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
+#define ODK_PAD		3	/* Section padding options.  */
+#define ODK_HWPATCH	4	/* Hardware workarounds performed */
+#define ODK_FILL	5	/* record the fill value used by the linker. */
+#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
+#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
+#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
+
+#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
+#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
+#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
+#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
+#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
+#define OEX_PRECISEFP	OEX_FPDBUG
+#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
+
+#define OEX_FPU_INVAL	0x10
+#define OEX_FPU_DIV0	0x08
+#define OEX_FPU_OFLO	0x04
+#define OEX_FPU_UFLO	0x02
+#define OEX_FPU_INEX	0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
+
+#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
+#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
+#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
+#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
+
+#define OPAD_PREFIX	0x1
+#define OPAD_POSTFIX	0x2
+#define OPAD_SYMBOL	0x4
+
+/* Entry found in `.options' section.  */
+
+typedef struct
+{
+  Elf32_Word hwp_flags1;	/* Extra flags.  */
+  Elf32_Word hwp_flags2;	/* Extra flags.  */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
+
+#define OHWA0_R4KEOP_CHECKED	0x00000001
+#define OHWA1_R4KEOP_CLEAN	0x00000002
+
+/* MIPS relocs.  */
+
+#define R_MIPS_NONE		0	/* No reloc */
+#define R_MIPS_16		1	/* Direct 16 bit */
+#define R_MIPS_32		2	/* Direct 32 bit */
+#define R_MIPS_REL32		3	/* PC relative 32 bit */
+#define R_MIPS_26		4	/* Direct 26 bit shifted */
+#define R_MIPS_HI16		5	/* High 16 bit */
+#define R_MIPS_LO16		6	/* Low 16 bit */
+#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
+#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
+#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
+#define R_MIPS_PC16		10	/* PC relative 16 bit */
+#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5		16
+#define R_MIPS_SHIFT6		17
+#define R_MIPS_64		18
+#define R_MIPS_GOT_DISP		19
+#define R_MIPS_GOT_PAGE		20
+#define R_MIPS_GOT_OFST		21
+#define R_MIPS_GOT_HI16		22
+#define R_MIPS_GOT_LO16		23
+#define R_MIPS_SUB		24
+#define R_MIPS_INSERT_A		25
+#define R_MIPS_INSERT_B		26
+#define R_MIPS_DELETE		27
+#define R_MIPS_HIGHER		28
+#define R_MIPS_HIGHEST		29
+#define R_MIPS_CALL_HI16	30
+#define R_MIPS_CALL_LO16	31
+#define R_MIPS_SCN_DISP		32
+#define R_MIPS_REL16		33
+#define R_MIPS_ADD_IMMEDIATE	34
+#define R_MIPS_PJUMP		35
+#define R_MIPS_RELGOT		36
+#define R_MIPS_JALR		37
+#define R_MIPS_TLS_DTPMOD32	38	/* Module number 32 bit */
+#define R_MIPS_TLS_DTPREL32	39	/* Module-relative offset 32 bit */
+#define R_MIPS_TLS_DTPMOD64	40	/* Module number 64 bit */
+#define R_MIPS_TLS_DTPREL64	41	/* Module-relative offset 64 bit */
+#define R_MIPS_TLS_GD		42	/* 16 bit GOT offset for GD */
+#define R_MIPS_TLS_LDM		43	/* 16 bit GOT offset for LDM */
+#define R_MIPS_TLS_DTPREL_HI16	44	/* Module-relative offset, high 16 bits */
+#define R_MIPS_TLS_DTPREL_LO16	45	/* Module-relative offset, low 16 bits */
+#define R_MIPS_TLS_GOTTPREL	46	/* 16 bit GOT offset for IE */
+#define R_MIPS_TLS_TPREL32	47	/* TP-relative offset, 32 bit */
+#define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
+#define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
+#define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
+#define R_MIPS_GLOB_DAT		51
+#define R_MIPS_COPY		126
+#define R_MIPS_JUMP_SLOT        127
+/* Keep this the last entry.  */
+#define R_MIPS_NUM		128
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
+#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types.  */
+
+#define PF_MIPS_LOCAL	0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn.  */
+
+#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
+#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
+#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
+#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
+#define DT_MIPS_MSYM	     0x70000007
+#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
+#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
+#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
+#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
+						DT_MIPS_DELTA_CLASS.  */
+#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+						DT_MIPS_DELTA_INSTANCE.  */
+#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+					     DT_MIPS_DELTA_RELOC.  */
+#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
+					   relocations refer to.  */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+					   DT_MIPS_DELTA_SYM.  */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+					     class declaration.  */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+						DT_MIPS_DELTA_CLASSSYM.  */
+#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
+#define DT_MIPS_PIXIE_INIT   0x70000023
+#define DT_MIPS_SYMBOL_LIB   0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
+#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+						    function stored in GOT.  */
+#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
+					   by rld on dlopen() calls.  */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
+#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
+/* The address of .got.plt in an executable using the new non-PIC ABI.  */
+#define DT_MIPS_PLTGOT	     0x70000032
+/* The base of the PLT in an executable using the new non-PIC ABI if that
+   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
+   value.  */
+#define DT_MIPS_RWPLT        0x70000034
+#define DT_MIPS_NUM	     0x35
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
+
+#define RHF_NONE		   0		/* No flags */
+#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
+#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE		   (1 << 3)
+#define RHF_SGI_ONLY		   (1 << 4)
+#define RHF_GUARANTEE_INIT	   (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
+#define RHF_GUARANTEE_START_INIT   (1 << 7)
+#define RHF_PIXIE		   (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
+#define RHF_REQUICKSTART	   (1 << 10)
+#define RHF_REQUICKSTARTED	   (1 << 11)
+#define RHF_CORD		   (1 << 12)
+#define RHF_NO_UNRES_UNDEF	   (1 << 13)
+#define RHF_RLD_ORDER_SAFE	   (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
+
+typedef struct
+{
+  Elf32_Word l_name;		/* Name (string table index) */
+  Elf32_Word l_time_stamp;	/* Timestamp */
+  Elf32_Word l_checksum;	/* Checksum */
+  Elf32_Word l_version;		/* Interface version */
+  Elf32_Word l_flags;		/* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+  Elf64_Word l_name;		/* Name (string table index) */
+  Elf64_Word l_time_stamp;	/* Timestamp */
+  Elf64_Word l_checksum;	/* Checksum */
+  Elf64_Word l_version;		/* Interface version */
+  Elf64_Word l_flags;		/* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags.  */
+
+#define LL_NONE		  0
+#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
+#define LL_REQUIRE_MINOR  (1 << 2)
+#define LL_EXPORTS	  (1 << 3)
+#define LL_DELAY_LOAD	  (1 << 4)
+#define LL_DELTA	  (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
+#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
+					      prediction.  */
+#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
+#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
+
+#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
+#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
+#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
+
+/* Additional section indeces.  */
+
+#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
+					      symbols in ANSI C.  */
+#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
+#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
+#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
+
+#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
+#define STT_HP_STUB		(STT_LOOS + 0x2)
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE		0	/* No reloc.  */
+#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
+#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
+#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
+#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
+#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
+#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
+#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
+#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
+#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
+#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
+#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
+#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
+#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
+#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
+#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
+#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
+#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
+#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
+#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fdesc address.  */
+#define R_PARISC_PLABEL14R	70	/* Right 14 bits of fdesc address.  */
+#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
+#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
+#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
+#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
+#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
+#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
+#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
+#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
+#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
+#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
+#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
+#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
+#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
+#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
+#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LORESERVE	128
+#define R_PARISC_COPY		128	/* Copy relocation.  */
+#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
+#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
+#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
+#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
+#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
+#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_GNU_VTENTRY	232
+#define R_PARISC_GNU_VTINHERIT	233
+#define R_PARISC_TLS_GD21L	234	/* GD 21-bit left.  */
+#define R_PARISC_TLS_GD14R	235	/* GD 14-bit right.  */
+#define R_PARISC_TLS_GDCALL	236	/* GD call to __t_g_a.  */
+#define R_PARISC_TLS_LDM21L	237	/* LD module 21-bit left.  */
+#define R_PARISC_TLS_LDM14R	238	/* LD module 14-bit right.  */
+#define R_PARISC_TLS_LDMCALL	239	/* LD module call to __t_g_a.  */
+#define R_PARISC_TLS_LDO21L	240	/* LD offset 21-bit left.  */
+#define R_PARISC_TLS_LDO14R	241	/* LD offset 14-bit right.  */
+#define R_PARISC_TLS_DTPMOD32	242	/* DTP module 32-bit.  */
+#define R_PARISC_TLS_DTPMOD64	243	/* DTP module 64-bit.  */
+#define R_PARISC_TLS_DTPOFF32	244	/* DTP offset 32-bit.  */
+#define R_PARISC_TLS_DTPOFF64	245	/* DTP offset 32-bit.  */
+#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L
+#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R
+#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L
+#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R
+#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32
+#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64
+#define R_PARISC_HIRESERVE	255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PT_HP_TLS		(PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
+#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
+#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
+#define PT_HP_STACK		(PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT	0x70000000
+#define PT_PARISC_UNWIND	0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PF_PARISC_SBP		0x08000000
+
+#define PF_HP_PAGE_SIZE		0x00100000
+#define PF_HP_FAR_SHARED	0x00200000
+#define PF_HP_NEAR_SHARED	0x00400000
+#define PF_HP_CODE		0x01000000
+#define PF_HP_MODIFY		0x02000000
+#define PF_HP_LAZYSWAP		0x04000000
+#define PF_HP_SBP		0x08000000
+
+
+/* Alpha specific definitions.  */
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
+#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
+
+/* Legal values for sh_type field of Elf64_Shdr.  */
+
+/* These two are primerily concerned with ECOFF debugging info.  */
+#define SHT_ALPHA_DEBUG		0x70000001
+#define SHT_ALPHA_REGINFO	0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr.  */
+
+#define SHF_ALPHA_GPREL		0x10000000
+
+/* Legal values for st_other field of Elf64_Sym.  */
+#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
+#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
+
+/* Alpha relocs.  */
+
+#define R_ALPHA_NONE		0	/* No reloc */
+#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
+#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
+#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
+#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
+#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
+#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
+#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
+#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
+#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
+#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI	28
+#define R_ALPHA_TLSGD		29
+#define R_ALPHA_TLS_LDM		30
+#define R_ALPHA_DTPMOD64	31
+#define R_ALPHA_GOTDTPREL	32
+#define R_ALPHA_DTPREL64	33
+#define R_ALPHA_DTPRELHI	34
+#define R_ALPHA_DTPRELLO	35
+#define R_ALPHA_DTPREL16	36
+#define R_ALPHA_GOTTPREL	37
+#define R_ALPHA_TPREL64		38
+#define R_ALPHA_TPRELHI		39
+#define R_ALPHA_TPRELLO		40
+#define R_ALPHA_TPREL16		41
+/* Keep this the last entry.  */
+#define R_ALPHA_NUM		46
+
+/* Magic values of the LITUSE relocation addend.  */
+#define LITUSE_ALPHA_ADDR	0
+#define LITUSE_ALPHA_BASE	1
+#define LITUSE_ALPHA_BYTOFF	2
+#define LITUSE_ALPHA_JSR	3
+#define LITUSE_ALPHA_TLS_GD	4
+#define LITUSE_ALPHA_TLS_LDM	5
+
+/* Legal values for d_tag of Elf64_Dyn.  */
+#define DT_ALPHA_PLTRO		(DT_LOPROC + 0)
+#define DT_ALPHA_NUM		1
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags.  */
+#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
+						   flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+
+/* PowerPC relocations defined for the TLS access ABI.  */
+#define R_PPC_TLS		67 /* none	(sym+add)@tls */
+#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
+#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
+#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
+#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+   in the SVR4 ELF ABI.  */
+#define R_PPC_EMB_NADDR32	101
+#define R_PPC_EMB_NADDR16	102
+#define R_PPC_EMB_NADDR16_LO	103
+#define R_PPC_EMB_NADDR16_HI	104
+#define R_PPC_EMB_NADDR16_HA	105
+#define R_PPC_EMB_SDAI16	106
+#define R_PPC_EMB_SDA2I16	107
+#define R_PPC_EMB_SDA2REL	108
+#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF	110
+#define R_PPC_EMB_RELSEC16	111
+#define R_PPC_EMB_RELST_LO	112
+#define R_PPC_EMB_RELST_HI	113
+#define R_PPC_EMB_RELST_HA	114
+#define R_PPC_EMB_BIT_FLD	115
+#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
+
+/* Diab tool relocations.  */
+#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
+
+/* GNU extension to support local ifunc.  */
+#define R_PPC_IRELATIVE		248
+
+/* GNU relocs used in PIC code sequences.  */
+#define R_PPC_REL16		249	/* half16   (sym+add-.) */
+#define R_PPC_REL16_LO		250	/* half16   (sym+add-.)@l */
+#define R_PPC_REL16_HI		251	/* half16   (sym+add-.)@h */
+#define R_PPC_REL16_HA		252	/* half16   (sym+add-.)@ha */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+   that may still be in object files.  */
+#define R_PPC_TOC16		255
+
+/* PowerPC specific values for the Dyn d_tag field.  */
+#define DT_PPC_GOT		(DT_LOPROC + 0)
+#define DT_PPC_NUM		1
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE		R_PPC_NONE
+#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
+#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
+#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
+#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16		R_PPC_GOT16
+#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
+
+#define R_PPC64_COPY		R_PPC_COPY
+#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE	R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32		R_PPC_UADDR32
+#define R_PPC64_UADDR16		R_PPC_UADDR16
+#define R_PPC64_REL32		R_PPC_REL32
+#define R_PPC64_PLT32		R_PPC_PLT32
+#define R_PPC64_PLTREL32	R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF		R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
+#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64		45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC		51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16	52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI.  */
+#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
+#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
+
+/* GNU extension to support local ifunc.  */
+#define R_PPC64_JMP_IREL	247
+#define R_PPC64_IRELATIVE	248
+#define R_PPC64_REL16		249	/* half16   (sym+add-.) */
+#define R_PPC64_REL16_LO	250	/* half16   (sym+add-.)@l */
+#define R_PPC64_REL16_HI	251	/* half16   (sym+add-.)@h */
+#define R_PPC64_REL16_HA	252	/* half16   (sym+add-.)@ha */
+
+/* PowerPC64 specific values for the Dyn d_tag field.  */
+#define DT_PPC64_GLINK  (DT_LOPROC + 0)
+#define DT_PPC64_OPD	(DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
+#define DT_PPC64_NUM    3
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC		0x01
+#define EF_ARM_HASENTRY		0x02
+#define EF_ARM_INTERWORK	0x04
+#define EF_ARM_APCS_26		0x08
+#define EF_ARM_APCS_FLOAT	0x10
+#define EF_ARM_PIC		0x20
+#define EF_ARM_ALIGN8		0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI		0x80
+#define EF_ARM_OLD_ABI		0x100
+#define EF_ARM_SOFT_FLOAT	0x200
+#define EF_ARM_VFP_FLOAT	0x400
+#define EF_ARM_MAVERICK_FLOAT	0x800
+
+
+/* Other constants defined in the ARM ELF spec. version B-01.  */
+/* NB. These conflict with values defined above.  */
+#define EF_ARM_SYMSARESORTED	0x04
+#define EF_ARM_DYNSYMSUSESEGIDX	0x08
+#define EF_ARM_MAPSYMSFIRST	0x10
+#define EF_ARM_EABIMASK		0XFF000000
+
+/* Constants defined in AAELF.  */
+#define EF_ARM_BE8	    0x00800000
+#define EF_ARM_LE8	    0x00400000
+
+#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN	0x00000000
+#define EF_ARM_EABI_VER1	0x01000000
+#define EF_ARM_EABI_VER2	0x02000000
+#define EF_ARM_EABI_VER3	0x03000000
+#define EF_ARM_EABI_VER4	0x04000000
+#define EF_ARM_EABI_VER5	0x05000000
+
+/* Additional symbol types for Thumb.  */
+#define STT_ARM_TFUNC		STT_LOPROC /* A Thumb function.  */
+#define STT_ARM_16BIT		STT_HIPROC /* A Thumb label.  */
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT	0x10000000 /* Section contains an entry point */
+#define SHF_ARM_COMDEF		0x80000000 /* Section may be multiply defined
+					      in the input to a link step.  */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB		0x10000000 /* Segment contains the location
+					      addressed by the static base. */
+#define PF_ARM_PI		0x20000000 /* Position-independent segment.  */
+#define PF_ARM_ABS		0x40000000 /* Absolute segment.  */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
+#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
+#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
+
+
+/* ARM relocs.  */
+
+#define R_ARM_NONE		0	/* No reloc */
+#define R_ARM_PC24		1	/* PC relative 26 bit branch */
+#define R_ARM_ABS32		2	/* Direct 32 bit  */
+#define R_ARM_REL32		3	/* PC relative 32 bit */
+#define R_ARM_PC13		4
+#define R_ARM_ABS16		5	/* Direct 16 bit */
+#define R_ARM_ABS12		6	/* Direct 12 bit */
+#define R_ARM_THM_ABS5		7
+#define R_ARM_ABS8		8	/* Direct 8 bit */
+#define R_ARM_SBREL32		9
+#define R_ARM_THM_PC22		10
+#define R_ARM_THM_PC8		11
+#define R_ARM_AMP_VCALL9	12
+#define R_ARM_SWI24		13	/* Obsolete static relocation.  */
+#define R_ARM_TLS_DESC		13      /* Dynamic relocation.  */
+#define R_ARM_THM_SWI8		14
+#define R_ARM_XPC25		15
+#define R_ARM_THM_XPC22		16
+#define R_ARM_TLS_DTPMOD32	17	/* ID of module containing symbol */
+#define R_ARM_TLS_DTPOFF32	18	/* Offset in TLS block */
+#define R_ARM_TLS_TPOFF32	19	/* Offset in static TLS block */
+#define R_ARM_COPY		20	/* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
+#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
+#define R_ARM_RELATIVE		23	/* Adjust by program base */
+#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
+#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32		26	/* 32 bit GOT entry */
+#define R_ARM_PLT32		27	/* 32 bit PLT address */
+#define R_ARM_ALU_PCREL_7_0	32
+#define R_ARM_ALU_PCREL_15_8	33
+#define R_ARM_ALU_PCREL_23_15	34
+#define R_ARM_LDR_SBREL_11_0	35
+#define R_ARM_ALU_SBREL_19_12	36
+#define R_ARM_ALU_SBREL_27_20	37
+#define R_ARM_TLS_GOTDESC	90
+#define R_ARM_TLS_CALL		91
+#define R_ARM_TLS_DESCSEQ	92
+#define R_ARM_THM_TLS_CALL	93
+#define R_ARM_GNU_VTENTRY	100
+#define R_ARM_GNU_VTINHERIT	101
+#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
+#define R_ARM_THM_PC9		103	/* thumb conditional branch */
+#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
+					   thread local data */
+#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
+					   thread local data */
+#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
+					   block */
+#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
+					   static TLS block offset */
+#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
+					   TLS block */
+#define	R_ARM_THM_TLS_DESCSEQ	129
+#define R_ARM_IRELATIVE		160
+#define R_ARM_RXPC25		249
+#define R_ARM_RSBREL32		250
+#define R_ARM_THM_RPC22		251
+#define R_ARM_RREL32		252
+#define R_ARM_RABS22		253
+#define R_ARM_RPC24		254
+#define R_ARM_RBASE		255
+/* Keep this the last entry.  */
+#define R_ARM_NUM		256
+
+/* IA-64 specific declarations.  */
+
+/* Processor specific flags for the Ehdr e_flags field.  */
+#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
+#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
+#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
+#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field.  */
+#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field.  */
+#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
+#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field.  */
+#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
+#define DT_IA_64_NUM		1
+
+/* IA-64 relocations.  */
+#define R_IA64_NONE		0x00	/* none */
+#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
+#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
+#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
+#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
+#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
+#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
+#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY		0x84	/* copy relocation */
+#define R_IA64_SUB		0x85	/* Addend and symbol difference */
+#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
+#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
+#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_SH_MACH_MASK		0x1f
+#define EF_SH_UNKNOWN		0x0
+#define EF_SH1			0x1
+#define EF_SH2			0x2
+#define EF_SH3			0x3
+#define EF_SH_DSP		0x4
+#define EF_SH3_DSP		0x5
+#define EF_SH4AL_DSP		0x6
+#define EF_SH3E			0x8
+#define EF_SH4			0x9
+#define EF_SH2E			0xb
+#define EF_SH4A			0xc
+#define EF_SH2A			0xd
+#define EF_SH4_NOFPU		0x10
+#define EF_SH4A_NOFPU		0x11
+#define EF_SH4_NOMMU_NOFPU	0x12
+#define EF_SH2A_NOFPU		0x13
+#define EF_SH3_NOMMU		0x14
+#define EF_SH2A_SH4_NOFPU	0x15
+#define EF_SH2A_SH3_NOFPU	0x16
+#define EF_SH2A_SH4		0x17
+#define EF_SH2A_SH3E		0x18
+
+/* SH relocs.  */
+#define	R_SH_NONE		0
+#define	R_SH_DIR32		1
+#define	R_SH_REL32		2
+#define	R_SH_DIR8WPN		3
+#define	R_SH_IND12W		4
+#define	R_SH_DIR8WPL		5
+#define	R_SH_DIR8WPZ		6
+#define	R_SH_DIR8BP		7
+#define	R_SH_DIR8W		8
+#define	R_SH_DIR8L		9
+#define	R_SH_SWITCH16		25
+#define	R_SH_SWITCH32		26
+#define	R_SH_USES		27
+#define	R_SH_COUNT		28
+#define	R_SH_ALIGN		29
+#define	R_SH_CODE		30
+#define	R_SH_DATA		31
+#define	R_SH_LABEL		32
+#define	R_SH_SWITCH8		33
+#define	R_SH_GNU_VTINHERIT	34
+#define	R_SH_GNU_VTENTRY	35
+#define	R_SH_TLS_GD_32		144
+#define	R_SH_TLS_LD_32		145
+#define	R_SH_TLS_LDO_32		146
+#define	R_SH_TLS_IE_32		147
+#define	R_SH_TLS_LE_32		148
+#define	R_SH_TLS_DTPMOD32	149
+#define	R_SH_TLS_DTPOFF32	150
+#define	R_SH_TLS_TPOFF32	151
+#define	R_SH_GOT32		160
+#define	R_SH_PLT32		161
+#define	R_SH_COPY		162
+#define	R_SH_GLOB_DAT		163
+#define	R_SH_JMP_SLOT		164
+#define	R_SH_RELATIVE		165
+#define	R_SH_GOTOFF		166
+#define	R_SH_GOTPC		167
+/* Keep this the last entry.  */
+#define	R_SH_NUM		256
+
+/* S/390 specific definitions.  */
+
+/* Valid values for the e_flags field.  */
+
+#define EF_S390_HIGH_GPRS    0x00000001  /* High GPRs kernel facility needed.  */
+
+/* Additional s390 relocs */
+
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+					   dynamic TLS code. */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+					   dynamic TLS code. */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+					   thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+					  thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+					   block offset. */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
+#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
+					   block.  */
+#define R_390_20		57	/* Direct 20 bit.  */
+#define R_390_GOT20		58	/* 20 bit GOT offset.  */
+#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
+#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
+/* Keep this the last entry.  */
+#define R_390_NUM		62
+
+
+/* CRIS relocations.  */
+#define R_CRIS_NONE		0
+#define R_CRIS_8		1
+#define R_CRIS_16		2
+#define R_CRIS_32		3
+#define R_CRIS_8_PCREL		4
+#define R_CRIS_16_PCREL		5
+#define R_CRIS_32_PCREL		6
+#define R_CRIS_GNU_VTINHERIT	7
+#define R_CRIS_GNU_VTENTRY	8
+#define R_CRIS_COPY		9
+#define R_CRIS_GLOB_DAT		10
+#define R_CRIS_JUMP_SLOT	11
+#define R_CRIS_RELATIVE		12
+#define R_CRIS_16_GOT		13
+#define R_CRIS_32_GOT		14
+#define R_CRIS_16_GOTPLT	15
+#define R_CRIS_32_GOTPLT	16
+#define R_CRIS_32_GOTREL	17
+#define R_CRIS_32_PLT_GOTREL	18
+#define R_CRIS_32_PLT_PCREL	19
+
+#define R_CRIS_NUM		20
+
+
+/* AMD x86-64 relocations.  */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
+#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
+#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
+#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
+					   to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
+					   to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
+#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
+					   to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
+#define R_X86_64_PC64		24	/* PC relative 64 bit */
+#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
+					   offset to GOT */
+#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
+					   to GOT entry */
+#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
+					   to PLT entry */
+#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
+#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
+					   descriptor.  */
+#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
+#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
+#define R_X86_64_RELATIVE64	38	/* 64-bit adjust by program base */
+
+#define R_X86_64_NUM		39
+
+
+/* AM33 relocations.  */
+#define R_MN10300_NONE		0	/* No reloc.  */
+#define R_MN10300_32		1	/* Direct 32 bit.  */
+#define R_MN10300_16		2	/* Direct 16 bit.  */
+#define R_MN10300_8		3	/* Direct 8 bit.  */
+#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
+#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
+#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
+#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
+#define R_MN10300_24		9	/* Direct 24 bit.  */
+#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
+#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
+#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
+#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
+#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
+#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
+#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
+#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
+#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
+#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
+#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
+#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
+#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
+#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
+
+#define R_MN10300_NUM		24
+
+
+/* M32R relocs.  */
+#define R_M32R_NONE		0	/* No reloc. */
+#define R_M32R_16		1	/* Direct 16 bit. */
+#define R_M32R_32		2	/* Direct 32 bit. */
+#define R_M32R_24		3	/* Direct 24 bit. */
+#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
+#define R_M32R_LO16		9	/* Low 16 bit. */
+#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT	11
+#define R_M32R_GNU_VTENTRY	12
+/* M32R relocs use SHT_RELA.  */
+#define R_M32R_16_RELA		33	/* Direct 16 bit. */
+#define R_M32R_32_RELA		34	/* Direct 32 bit. */
+#define R_M32R_24_RELA		35	/* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
+#define R_M32R_LO16_RELA	41	/* Low 16 bit */
+#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT	43
+#define R_M32R_RELA_GNU_VTENTRY	44
+#define R_M32R_REL32		45	/* PC relative 32 bit.  */
+
+#define R_M32R_GOT24		48	/* 24 bit GOT entry */
+#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY		50	/* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
+#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
+#define R_M32R_RELATIVE		53	/* Adjust by program base */
+#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
+#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
+					   low */
+#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
+					   low */
+#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
+					   GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
+					   GOT with signed low */
+#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
+					   GOT */
+#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
+					   with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
+					   with signed low */
+#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
+#define R_M32R_NUM		256	/* Keep this the last entry. */
+
+
+/* TILEPro relocations.  */
+#define R_TILEPRO_NONE		0	/* No reloc */
+#define R_TILEPRO_32		1	/* Direct 32 bit */
+#define R_TILEPRO_16		2	/* Direct 16 bit */
+#define R_TILEPRO_8		3	/* Direct 8 bit */
+#define R_TILEPRO_32_PCREL	4	/* PC relative 32 bit */
+#define R_TILEPRO_16_PCREL	5	/* PC relative 16 bit */
+#define R_TILEPRO_8_PCREL	6	/* PC relative 8 bit */
+#define R_TILEPRO_LO16		7	/* Low 16 bit */
+#define R_TILEPRO_HI16		8	/* High 16 bit */
+#define R_TILEPRO_HA16		9	/* High 16 bit, adjusted */
+#define R_TILEPRO_COPY		10	/* Copy relocation */
+#define R_TILEPRO_GLOB_DAT	11	/* Create GOT entry */
+#define R_TILEPRO_JMP_SLOT	12	/* Create PLT entry */
+#define R_TILEPRO_RELATIVE	13	/* Adjust by program base */
+#define R_TILEPRO_BROFF_X1	14	/* X1 pipe branch offset */
+#define R_TILEPRO_JOFFLONG_X1	15	/* X1 pipe jump offset */
+#define R_TILEPRO_JOFFLONG_X1_PLT 16	/* X1 pipe jump offset to PLT */
+#define R_TILEPRO_IMM8_X0	17	/* X0 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y0	18	/* Y0 pipe 8-bit */
+#define R_TILEPRO_IMM8_X1	19	/* X1 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y1	20	/* Y1 pipe 8-bit */
+#define R_TILEPRO_MT_IMM15_X1	21	/* X1 pipe mtspr */
+#define R_TILEPRO_MF_IMM15_X1	22	/* X1 pipe mfspr */
+#define R_TILEPRO_IMM16_X0	23	/* X0 pipe 16-bit */
+#define R_TILEPRO_IMM16_X1	24	/* X1 pipe 16-bit */
+#define R_TILEPRO_IMM16_X0_LO	25	/* X0 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X1_LO	26	/* X1 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X0_HI	27	/* X0 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X1_HI	28	/* X1 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X0_HA	29	/* X0 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X1_HA	30	/* X1 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X0_PCREL 31	/* X0 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X1_PCREL 32	/* X1 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X0_LO_PCREL 33	/* X0 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X1_LO_PCREL 34	/* X1 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X0_HI_PCREL 35	/* X0 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X1_HI_PCREL 36	/* X1 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X0_HA_PCREL 37	/* X0 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X1_HA_PCREL 38	/* X1 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X0_GOT	39	/* X0 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT	40	/* X1 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_LO 41	/* X0 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_LO 42	/* X1 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HI 43	/* X0 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HI 44	/* X1 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HA 45	/* X0 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HA 46	/* X1 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_MMSTART_X0	47	/* X0 pipe mm "start" */
+#define R_TILEPRO_MMEND_X0	48	/* X0 pipe mm "end" */
+#define R_TILEPRO_MMSTART_X1	49	/* X1 pipe mm "start" */
+#define R_TILEPRO_MMEND_X1	50	/* X1 pipe mm "end" */
+#define R_TILEPRO_SHAMT_X0	51	/* X0 pipe shift amount */
+#define R_TILEPRO_SHAMT_X1	52	/* X1 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y0	53	/* Y0 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y1	54	/* Y1 pipe shift amount */
+#define R_TILEPRO_DEST_IMM8_X1	55	/* X1 pipe destination 8-bit */
+/* Relocs 56-59 are currently not defined.  */
+#define R_TILEPRO_TLS_GD_CALL	60	/* "jal" for TLS GD */
+#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61	/* X0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62	/* X1 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63	/* Y0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64	/* Y1 pipe "addi" for TLS GD */
+#define R_TILEPRO_TLS_IE_LOAD	65	/* "lw_tls" for TLS IE */
+#define R_TILEPRO_IMM16_X0_TLS_GD 66	/* X0 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD 67	/* X1 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68	/* X0 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69	/* X1 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70	/* X0 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71	/* X1 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72	/* X0 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73	/* X1 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE 74	/* X0 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE 75	/* X1 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76	/* X0 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77	/* X1 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78	/* X0 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79	/* X1 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80	/* X0 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81	/* X1 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_TLS_DTPMOD32	82	/* ID of module containing symbol */
+#define R_TILEPRO_TLS_DTPOFF32	83	/* Offset in TLS block */
+#define R_TILEPRO_TLS_TPOFF32	84	/* Offset in static TLS block */
+#define R_TILEPRO_IMM16_X0_TLS_LE 85	/* X0 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE 86	/* X1 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87	/* X0 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88	/* X1 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89	/* X0 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90	/* X1 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91	/* X0 pipe ha() 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92	/* X1 pipe ha() 16-bit TLS LE offset */
+
+#define R_TILEPRO_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
+#define R_TILEPRO_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
+
+#define R_TILEPRO_NUM		130
+
+
+/* TILE-Gx relocations.  */
+#define R_TILEGX_NONE		0	/* No reloc */
+#define R_TILEGX_64		1	/* Direct 64 bit */
+#define R_TILEGX_32		2	/* Direct 32 bit */
+#define R_TILEGX_16		3	/* Direct 16 bit */
+#define R_TILEGX_8		4	/* Direct 8 bit */
+#define R_TILEGX_64_PCREL	5	/* PC relative 64 bit */
+#define R_TILEGX_32_PCREL	6	/* PC relative 32 bit */
+#define R_TILEGX_16_PCREL	7	/* PC relative 16 bit */
+#define R_TILEGX_8_PCREL	8	/* PC relative 8 bit */
+#define R_TILEGX_HW0		9	/* hword 0 16-bit */
+#define R_TILEGX_HW1		10	/* hword 1 16-bit */
+#define R_TILEGX_HW2		11	/* hword 2 16-bit */
+#define R_TILEGX_HW3		12	/* hword 3 16-bit */
+#define R_TILEGX_HW0_LAST	13	/* last hword 0 16-bit */
+#define R_TILEGX_HW1_LAST	14	/* last hword 1 16-bit */
+#define R_TILEGX_HW2_LAST	15	/* last hword 2 16-bit */
+#define R_TILEGX_COPY		16	/* Copy relocation */
+#define R_TILEGX_GLOB_DAT	17	/* Create GOT entry */
+#define R_TILEGX_JMP_SLOT	18	/* Create PLT entry */
+#define R_TILEGX_RELATIVE	19	/* Adjust by program base */
+#define R_TILEGX_BROFF_X1	20	/* X1 pipe branch offset */
+#define R_TILEGX_JUMPOFF_X1	21	/* X1 pipe jump offset */
+#define R_TILEGX_JUMPOFF_X1_PLT	22	/* X1 pipe jump offset to PLT */
+#define R_TILEGX_IMM8_X0	23	/* X0 pipe 8-bit */
+#define R_TILEGX_IMM8_Y0	24	/* Y0 pipe 8-bit */
+#define R_TILEGX_IMM8_X1	25	/* X1 pipe 8-bit */
+#define R_TILEGX_IMM8_Y1	26	/* Y1 pipe 8-bit */
+#define R_TILEGX_DEST_IMM8_X1	27	/* X1 pipe destination 8-bit */
+#define R_TILEGX_MT_IMM14_X1	28	/* X1 pipe mtspr */
+#define R_TILEGX_MF_IMM14_X1	29	/* X1 pipe mfspr */
+#define R_TILEGX_MMSTART_X0	30	/* X0 pipe mm "start" */
+#define R_TILEGX_MMEND_X0	31	/* X0 pipe mm "end" */
+#define R_TILEGX_SHAMT_X0	32	/* X0 pipe shift amount */
+#define R_TILEGX_SHAMT_X1	33	/* X1 pipe shift amount */
+#define R_TILEGX_SHAMT_Y0	34	/* Y0 pipe shift amount */
+#define R_TILEGX_SHAMT_Y1	35	/* Y1 pipe shift amount */
+#define R_TILEGX_IMM16_X0_HW0	36	/* X0 pipe hword 0 */
+#define R_TILEGX_IMM16_X1_HW0	37	/* X1 pipe hword 0 */
+#define R_TILEGX_IMM16_X0_HW1	38	/* X0 pipe hword 1 */
+#define R_TILEGX_IMM16_X1_HW1	39	/* X1 pipe hword 1 */
+#define R_TILEGX_IMM16_X0_HW2	40	/* X0 pipe hword 2 */
+#define R_TILEGX_IMM16_X1_HW2	41	/* X1 pipe hword 2 */
+#define R_TILEGX_IMM16_X0_HW3	42	/* X0 pipe hword 3 */
+#define R_TILEGX_IMM16_X1_HW3	43	/* X1 pipe hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST 44	/* X0 pipe last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST 45	/* X1 pipe last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST 46	/* X0 pipe last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST 47	/* X1 pipe last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST 48	/* X0 pipe last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST 49	/* X1 pipe last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_PCREL 50	/* X0 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PCREL 51	/* X1 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PCREL 52	/* X0 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PCREL 53	/* X1 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PCREL 54	/* X0 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PCREL 55	/* X1 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X0_HW3_PCREL 56	/* X0 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PCREL 57	/* X1 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_GOT 64	/* X0 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_GOT 65	/* X1 pipe hword 0 GOT offset */
+/* Relocs 66-71 are currently not defined.  */
+#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
+/* Relocs 76-77 are currently not defined.  */
+#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78	/* X0 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79	/* X1 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80	/* X0 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81	/* X1 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
+/* Relocs 90-91 are currently not defined.  */
+#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92	/* X0 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93	/* X1 pipe hword 0 TLS IE offset */
+/* Relocs 94-99 are currently not defined.  */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
+/* Relocs 104-105 are currently not defined.  */
+#define R_TILEGX_TLS_DTPMOD64	106	/* 64-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF64	107	/* 64-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF64	108	/* 64-bit offset in static TLS block */
+#define R_TILEGX_TLS_DTPMOD32	109	/* 32-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF32	110	/* 32-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF32	111	/* 32-bit offset in static TLS block */
+#define R_TILEGX_TLS_GD_CALL	112	/* "jal" for TLS GD */
+#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113	/* X0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114	/* X1 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115	/* Y0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116	/* Y1 pipe "addi" for TLS GD */
+#define R_TILEGX_TLS_IE_LOAD	117	/* "ld_tls" for TLS IE */
+#define R_TILEGX_IMM8_X0_TLS_ADD 118	/* X0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_X1_TLS_ADD 119	/* X1 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y0_TLS_ADD 120	/* Y0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y1_TLS_ADD 121	/* Y1 pipe "addi" for TLS GD/IE */
+
+#define R_TILEGX_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
+#define R_TILEGX_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
+
+#define R_TILEGX_NUM		130
+
+#endif	/* elf.h */
diff --git a/tools/include/endian.h b/tools/include/endian.h
new file mode 100644
index 0000000000..bba70abd83
--- /dev/null
+++ b/tools/include/endian.h
@@ -0,0 +1,40 @@
+#ifndef __endian_compat_h
+#define __endian_compat_h
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#include <byteswap.h>
+#include_next <endian.h>
+#elif defined(__APPLE__)
+#include <machine/endian.h>
+#include <machine/byte_order.h>
+#define bswap_16(x) NXSwapShort(x)
+#define bswap_32(x) NXSwapInt(x)
+#define bswap_64(x) NXSwapLongLong(x)
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#define bswap_16(x) bswap16(x)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#elif defined(__OpenBSD__)
+#include <sys/types.h>
+#define bswap_16(x) __swap16(x)
+#define bswap_32(x) __swap32(x)
+#define bswap_64(x) __swap64(x)
+#else
+#include <machine/endian.h>
+#define bswap_16(x) swap16(x)
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#endif
+
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER BYTE_ORDER
+#endif
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#endif
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#endif
+
+#endif
diff --git a/tools/include/getline.h b/tools/include/getline.h
new file mode 100644
index 0000000000..7b320f77ce
--- /dev/null
+++ b/tools/include/getline.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __FreeBSD__
+#include <osreldate.h>
+#endif
+
+#if !defined(__linux__) && !defined(__OpenBSD__) && !(defined(__APPLE__) && __DARWIN_C_LEVEL >= 200809L) && !(defined(__FreeBSD__) && __FreeBSD_version >= 800000)
+/*
+ * Emulate glibc getline() via BSD fgetln().
+ * Note that outsize is not changed unless memory is allocated.
+ */
+static inline ssize_t
+getline(char **outbuf, size_t *outsize, FILE *fp)
+{
+	size_t len;
+
+#ifndef __CYGWIN__
+	char *buf;
+	buf = fgetln(fp, &len);
+#else
+	char buf[512];
+	fgets(buf, sizeof(buf), fp);	
+	len = strlen(buf);
+#endif
+	if (buf == NULL)
+		return (-1);
+
+	/* Assumes realloc() accepts NULL for ptr (C99) */
+	if (*outbuf == NULL || *outsize < len + 1) {
+		void *tmp = realloc(*outbuf, len + 1);
+		if (tmp == NULL)
+			return (-1);
+		*outbuf = tmp;
+		*outsize = len + 1;
+	}
+	memcpy(*outbuf, buf, len);
+	(*outbuf)[len] = '\0';
+	return (len);
+}
+#endif
diff --git a/tools/include/sys/sysmacros.h b/tools/include/sys/sysmacros.h
new file mode 100644
index 0000000000..997d9286b6
--- /dev/null
+++ b/tools/include/sys/sysmacros.h
@@ -0,0 +1,56 @@
+/* Definitions of macros to access `dev_t' values.
+   Copyright (C) 1996, 1997, 1999, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef __SYS_SYSMACROS_H
+#define __SYS_SYSMACROS_H	1
+
+static inline unsigned int
+__gnu_dev_major(unsigned long long int __dev)
+{
+  return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff);
+}
+
+static inline unsigned int
+__gnu_dev_minor(unsigned long long int __dev)
+{
+  return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff);
+}
+
+static inline unsigned long long int
+__gnu_dev_makedev(unsigned int __major, unsigned int __minor)
+{
+  return ((__minor & 0xff) | ((__major & 0xfff) << 8)
+	  | (((unsigned long long int) (__minor & ~0xff)) << 12)
+	  | (((unsigned long long int) (__major & ~0xfff)) << 32));
+}
+
+/* Access the functions with their traditional names.  */
+#ifndef major
+# define major(dev) __gnu_dev_major (dev)
+#endif
+
+#ifndef minor
+# define minor(dev) __gnu_dev_minor (dev)
+#endif
+
+#ifndef makedev
+# define makedev(maj, min) __gnu_dev_makedev (maj, min)
+#endif
+
+#endif /* sys/sysmacros.h */
diff --git a/tools/isl/Makefile b/tools/isl/Makefile
new file mode 100644
index 0000000000..24c06268c7
--- /dev/null
+++ b/tools/isl/Makefile
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=isl
+PKG_VERSION:=0.17.1
+
+PKG_SOURCE_URL:=http://isl.gforge.inria.fr
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MD5SUM:=20b83900e234f982a566a3a6b3503bf1
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport CFLAGS
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static \
+	--disable-shared \
+	--with-gmp-prefix=$(STAGING_DIR_HOST)
+
+$(eval $(call HostBuild))
diff --git a/tools/kernel2minor/Makefile b/tools/kernel2minor/Makefile
new file mode 100644
index 0000000000..0db99599a6
--- /dev/null
+++ b/tools/kernel2minor/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2016 adron@yapic.net
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=kernel2minor
+PKG_VERSION:=0.22
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=https://github.com/adron-s/kernel2minor.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=0587740de3e398dbe89d965334c492609cb9739d
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/kernel2minor $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/kernel2minor
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/libelf/Makefile b/tools/libelf/Makefile
new file mode 100644
index 0000000000..8036b6f189
--- /dev/null
+++ b/tools/libelf/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libelf
+PKG_VERSION:=0.8.13
+PKG_MD5SUM:=4136d7b4c04df68b686570afa26988ac
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.mr511.de/software/
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS += \
+	--disable-shared \
+	--enable-elf64
+
+define Host/Configure
+        (cd $(HOST_BUILD_DIR)/$(3); \
+                $(HOST_CONFIGURE_CMD) \
+                $(HOST_CONFIGURE_ARGS); \
+        )
+endef
+
+
+define Host/Compile
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR)/lib/ libelf.a
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/{lib,include/libelf}
+	$(CP) $(HOST_BUILD_DIR)/lib/{elf_repl.h,gelf.h,libelf.h,nlist.h,sys_elf.h} \
+						$(STAGING_DIR_HOST)/include/libelf/
+	$(CP) $(HOST_BUILD_DIR)/lib/libelf.a $(STAGING_DIR_HOST)/lib/
+endef
+
+define Host/Clean
+	rm -rf $(STAGING_DIR_HOST)/include/libelf
+	rm -f $(STAGING_DIR_HOST)/lib/libelf.a
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/libressl/Makefile b/tools/libressl/Makefile
new file mode 100644
index 0000000000..e1c3caed83
--- /dev/null
+++ b/tools/libressl/Makefile
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libressl
+PKG_VERSION:=2.5.0
+PKG_MD5SUM:=8652bf6b55ab51fb37b686a3f604a2643e0e8fde2c56e6a936027d12afda6eae
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://mirror.ox.ac.uk/pub/OpenBSD/LibreSSL \
+	http://ftp.jaist.ac.jp/pub/OpenBSD/LibreSSL \
+	http://ftp.openbsd.org/pub/OpenBSD/LibreSSL
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+$(eval $(call HostBuild))
diff --git a/tools/libtool/Makefile b/tools/libtool/Makefile
new file mode 100644
index 0000000000..3df1d16f11
--- /dev/null
+++ b/tools/libtool/Makefile
@@ -0,0 +1,41 @@
+# 
+# Copyright (C) 2008-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=libtool
+PKG_VERSION:=2.4
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=afcce660d3dc54c63a0a5ba3cf05272239dc3c54bbeba20f6bad250f9dc007ae
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_VARS += \
+	lt_cv_sys_dlsearch_path=""
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+	(cd $(STAGING_DIR_HOST)/share/aclocal/ && rm -f libtool.m4 ltdl.m4 lt~obsolete.m4 ltoptions.m4 ltsugar.m4 ltversion.m4)
+	(cd $(HOST_BUILD_DIR); $(AM_TOOL_PATHS) ./bootstrap)
+endef
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) install
+	$(SED) 's,\(hardcode_into_libs\)=yes,\1=no,g' $(STAGING_DIR_HOST)/bin/libtool
+	$(CP) $(STAGING_DIR_HOST)/bin/libtool $(STAGING_DIR_HOST)/bin/libtool-ucxx
+	$(SED) 's,-lstdc++,-luClibc++,g' $(STAGING_DIR_HOST)/bin/libtool-ucxx
+endef
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/libtool/files/libtool-v1.5.patch b/tools/libtool/files/libtool-v1.5.patch
new file mode 100644
index 0000000000..485dfc7eb4
--- /dev/null
+++ b/tools/libtool/files/libtool-v1.5.patch
@@ -0,0 +1,118 @@
+--- a/ltmain.sh
++++ b/ltmain.sh
+@@ -35,7 +35,7 @@ progpath="$0"
+ 
+ # The name of this program:
+ progname=`echo "$progpath" | $SED $basename`
+-modename="$progname"
++modename="OpenWrt-$progname-patched-1.5"
+ 
+ # Global variables:
+ EXIT_SUCCESS=0
+@@ -297,8 +297,8 @@ func_infer_tag ()
+ 	# line option must be used.
+ 	if test -z "$tagname"; then
+ 	  $echo "$modename: unable to infer tagged configuration"
+-	  $echo "$modename: specify a tag with \`--tag'" 1>&2
+-	  exit $EXIT_FAILURE
++	  $echo "$modename: defaulting to \`CC'"
++	  $echo "$modename: if this is not correct, specify a tag with \`--tag'"
+ #        else
+ #          $echo "$modename: using $tagname tagged configuration"
+ 	fi
+@@ -2462,8 +2462,14 @@ EOF
+ 	    absdir="$abs_ladir"
+ 	    libdir="$abs_ladir"
+ 	  else
+-	    dir="$libdir"
+-	    absdir="$libdir"
++	    # Adding 'libdir' from the .la file to our library search paths
++	    # breaks crosscompilation horribly.  We cheat here and don't add
++	    # it, instead adding the path where we found the .la.  -CL
++	    dir="$lt_sysroot$abs_ladir"
++	    absdir="$abs_ladir"
++	    libdir="$abs_ladir"
++	    #dir="$libdir"
++	    #absdir="$libdir"
+ 	  fi
+ 	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ 	else
+@@ -2602,7 +2608,7 @@ EOF
+ 	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ 	  if test "$installed" = no; then
+ 	    notinst_deplibs="$notinst_deplibs $lib"
+-	    need_relink=yes
++	    need_relink=no
+ 	  fi
+ 	  # This is a shared library
+ 
+@@ -2804,7 +2810,6 @@ EOF
+ 	    if test "$hardcode_direct" = yes; then
+ 	      add="$libdir/$linklib"
+ 	    elif test "$hardcode_minus_L" = yes; then
+-	      add_dir="-L$libdir"
+ 	      add="-l$name"
+ 	    elif test "$hardcode_shlibpath_var" = yes; then
+ 	      case :$finalize_shlibpath: in
+@@ -2820,8 +2825,6 @@ EOF
+ 	        add="$libdir/$linklib"
+ 	      fi
+ 	    else
+-	      # We cannot seem to hardcode it, guess we'll fake it.
+-	      add_dir="-L$libdir"
+ 	      # Try looking first in the location we're being installed to.
+ 	      if test -n "$inst_prefix_dir"; then
+ 		case $libdir in
+@@ -5687,6 +5690,10 @@ fi\
+ 	    # Replace all uninstalled libtool libraries with the installed ones
+ 	    newdependency_libs=
+ 	    for deplib in $dependency_libs; do
++	      # Replacing uninstalled with installed can easily break crosscompilation,
++	      # since the installed path is generally the wrong architecture.  -CL
++	      newdependency_libs="$newdependency_libs $deplib"
++	      continue
+ 	      case $deplib in
+ 	      *.la)
+ 		name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+@@ -5999,8 +6006,12 @@ relink_command=\"$relink_command\""
+ 	dir="$dir$objdir"
+ 
+ 	if test -n "$relink_command"; then
++	  # Strip any trailing slash from the destination.
++	  s_libdir=`$echo "X$libdir" | $Xsed -e 's%/$%%'`
++	  s_destdir=`$echo "X$destdir" | $Xsed -e 's%/$%%'`
++
+ 	  # Determine the prefix the user has applied to our future dir.
+-	  inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
++	  inst_prefix_dir=`$echo "$s_destdir" | $SED "s%$s_libdir\$%%"`
+ 
+ 	  # Don't allow the user to place us outside of our expected
+ 	  # location b/c this prevents finding dependent libraries that
+@@ -6008,10 +6019,13 @@ relink_command=\"$relink_command\""
+ 	  # At present, this check doesn't affect windows .dll's that
+ 	  # are installed into $libdir/../bin (currently, that works fine)
+ 	  # but it's something to keep an eye on.
+-	  if test "$inst_prefix_dir" = "$destdir"; then
+-	    $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+-	    exit $EXIT_FAILURE
+-	  fi
++	  #
++	  # This breaks install into our staging area.  -PB
++	  #
++	  # if test "$inst_prefix_dir" = "$destdir"; then
++	  #   $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
++	  #   exit $EXIT_FAILURE
++	  # fi
+ 
+ 	  if test -n "$inst_prefix_dir"; then
+ 	    # Stick the inst_prefix_dir data into the link command.
+@@ -6020,6 +6034,9 @@ relink_command=\"$relink_command\""
+ 	    relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP`
+ 	  fi
+ 
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/lib[^[:space:]]*%%"`
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/usr/lib[^[:space:]]*%%"`
++
+ 	  $echo "$modename: warning: relinking \`$file'" 1>&2
+ 	  $show "$relink_command"
+ 	  if $run eval "$relink_command"; then :
diff --git a/tools/libtool/files/libtool-v2.2.patch b/tools/libtool/files/libtool-v2.2.patch
new file mode 100644
index 0000000000..03994ba2fd
--- /dev/null
+++ b/tools/libtool/files/libtool-v2.2.patch
@@ -0,0 +1,123 @@
+--- a/ltmain.sh
++++ b/ltmain.sh
+@@ -243,7 +243,7 @@ opt_warning=:
+ # name if it has been set yet.
+ func_echo ()
+ {
+-    $ECHO "$progname${mode+: }$mode: $*"
++    $ECHO "OpenWrt-$progname-patched-2.2${mode+: }$mode: $*"
+ }
+ 
+ # func_verbose arg...
+@@ -262,14 +262,14 @@ func_verbose ()
+ # Echo program name prefixed message to standard error.
+ func_error ()
+ {
+-    $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
++    $ECHO "OpenWrt-$progname-patched-2.2${mode+: }$mode: "${1+"$@"} 1>&2
+ }
+ 
+ # func_warning arg...
+ # Echo program name prefixed warning message to standard error.
+ func_warning ()
+ {
+-    $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
++    $opt_warning && $ECHO "OpenWrt-$progname-patched-2.2${mode+: }$mode: warning: "${1+"$@"} 1>&2
+ 
+     # bash bug again:
+     :
+@@ -1048,8 +1048,8 @@ func_infer_tag ()
+ 	# was found and let the user know that the "--tag" command
+ 	# line option must be used.
+ 	if test -z "$tagname"; then
+-	  func_echo "unable to infer tagged configuration"
+-	  func_fatal_error "specify a tag with \`--tag'"
++	  func_echo "defaulting to \`CC'"
++	  func_echo "if this is not correct, specify a tag with \`--tag'"
+ #	else
+ #	  func_verbose "using $tagname tagged configuration"
+ 	fi
+@@ -2009,8 +2009,15 @@ func_mode_install ()
+ 	dir="$dir$objdir"
+ 
+ 	if test -n "$relink_command"; then
++	  # Strip any trailing slash from the destination.
++	  func_stripname '' '/' "$libdir"
++	  s_libdir=$func_stripname_result
++
++	  func_stripname '' '/' "$destdir"
++	  s_destdir=$func_stripname_result
++
+ 	  # Determine the prefix the user has applied to our future dir.
+-	  inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"`
++	  inst_prefix_dir=`$ECHO "X$s_destdir" | $Xsed -e "s%$s_libdir\$%%"`
+ 
+ 	  # Don't allow the user to place us outside of our expected
+ 	  # location b/c this prevents finding dependent libraries that
+@@ -2018,8 +2025,11 @@ func_mode_install ()
+ 	  # At present, this check doesn't affect windows .dll's that
+ 	  # are installed into $libdir/../bin (currently, that works fine)
+ 	  # but it's something to keep an eye on.
+-	  test "$inst_prefix_dir" = "$destdir" && \
+-	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
++	  #
++	  # This breaks install into our staging area.  -PB
++	  #
++	  # test "$inst_prefix_dir" = "$destdir" && \
++	  #   func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+ 
+ 	  if test -n "$inst_prefix_dir"; then
+ 	    # Stick the inst_prefix_dir data into the link command.
+@@ -2028,6 +2038,9 @@ func_mode_install ()
+ 	    relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"`
+ 	  fi
+ 
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/lib[^[:space:]]*%%"`
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/usr/lib[^[:space:]]*%%"`
++
+ 	  func_warning "relinking \`$file'"
+ 	  func_show_eval "$relink_command" \
+ 	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+@@ -5412,8 +5425,12 @@ func_mode_link ()
+ 	    absdir="$abs_ladir"
+ 	    libdir="$abs_ladir"
+ 	  else
+-	    dir="$libdir"
+-	    absdir="$libdir"
++	    # Adding 'libdir' from the .la file to our library search paths
++	    # breaks crosscompilation horribly.  We cheat here and don't add
++	    # it, instead adding the path where we found the .la.  -CL
++	    dir="$abs_ladir"
++	    absdir="$abs_ladir"
++	    libdir="$abs_ladir"
+ 	  fi
+ 	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ 	else
+@@ -5564,7 +5581,7 @@ func_mode_link ()
+ 	  *)
+ 	    if test "$installed" = no; then
+ 	      notinst_deplibs="$notinst_deplibs $lib"
+-	      need_relink=yes
++	      need_relink=no
+ 	    fi
+ 	    ;;
+ 	  esac
+@@ -5768,7 +5785,6 @@ func_mode_link ()
+ 	       test "$hardcode_direct_absolute" = no; then
+ 	      add="$libdir/$linklib"
+ 	    elif test "$hardcode_minus_L" = yes; then
+-	      add_dir="-L$libdir"
+ 	      add="-l$name"
+ 	    elif test "$hardcode_shlibpath_var" = yes; then
+ 	      case :$finalize_shlibpath: in
+@@ -8052,6 +8068,10 @@ EOF
+ 	    # Replace all uninstalled libtool libraries with the installed ones
+ 	    newdependency_libs=
+ 	    for deplib in $dependency_libs; do
++	      # Replacing uninstalled with installed can easily break crosscompilation,
++	      # since the installed path is generally the wrong architecture.  -CL
++	      newdependency_libs="$newdependency_libs $deplib"
++	      continue
+ 	      case $deplib in
+ 	      *.la)
+ 		func_basename "$deplib"
diff --git a/tools/libtool/files/libtool-v2.4.patch b/tools/libtool/files/libtool-v2.4.patch
new file mode 100644
index 0000000000..afc754aa5f
--- /dev/null
+++ b/tools/libtool/files/libtool-v2.4.patch
@@ -0,0 +1,160 @@
+--- a/ltmain.sh
++++ b/ltmain.sh
+@@ -443,7 +443,7 @@ opt_warning=:
+ # name if it has been set yet.
+ func_echo ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
++    $ECHO "OpenWrt-$progname-patched-2.4: ${opt_mode+$opt_mode: }$*"
+ }
+ 
+ # func_verbose arg...
+@@ -469,14 +469,14 @@ func_echo_all ()
+ # Echo program name prefixed message to standard error.
+ func_error ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
++    $ECHO "OpenWrt-$progname-patched-2.4: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+ }
+ 
+ # func_warning arg...
+ # Echo program name prefixed warning message to standard error.
+ func_warning ()
+ {
+-    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
++    $opt_warning && $ECHO "OpenWrt-$progname-patched-2.4: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+ 
+     # bash bug again:
+     :
+@@ -1416,8 +1416,8 @@ func_infer_tag ()
+ 	# was found and let the user know that the "--tag" command
+ 	# line option must be used.
+ 	if test -z "$tagname"; then
+-	  func_echo "unable to infer tagged configuration"
+-	  func_fatal_error "specify a tag with \`--tag'"
++	  func_echo "defaulting to \`CC'"
++	  func_echo "if this is not correct, specify a tag with \`--tag'"
+ #	else
+ #	  func_verbose "using $tagname tagged configuration"
+ 	fi
+@@ -2953,8 +2953,15 @@ func_mode_install ()
+ 	func_append dir "$objdir"
+ 
+ 	if test -n "$relink_command"; then
++	  # Strip any trailing slash from the destination.
++	  func_stripname '' '/' "$libdir"
++	  s_libdir=$func_stripname_result
++
++	  func_stripname '' '/' "$destdir"
++	  s_destdir=$func_stripname_result
++
+ 	  # Determine the prefix the user has applied to our future dir.
+-	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
++	  inst_prefix_dir=`$ECHO "$s_destdir" | $SED -e "s%$s_libdir\$%%"`
+ 
+ 	  # Don't allow the user to place us outside of our expected
+ 	  # location b/c this prevents finding dependent libraries that
+@@ -2962,8 +2969,11 @@ func_mode_install ()
+ 	  # At present, this check doesn't affect windows .dll's that
+ 	  # are installed into $libdir/../bin (currently, that works fine)
+ 	  # but it's something to keep an eye on.
+-	  test "$inst_prefix_dir" = "$destdir" && \
+-	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
++	  #
++	  # This breaks install into our staging area.  -PB
++	  #
++	  # test "$inst_prefix_dir" = "$destdir" && \
++	  #   func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+ 
+ 	  if test -n "$inst_prefix_dir"; then
+ 	    # Stick the inst_prefix_dir data into the link command.
+@@ -2972,6 +2982,9 @@ func_mode_install ()
+ 	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ 	  fi
+ 
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/lib[^[:space:]]*%%"`
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/usr/lib[^[:space:]]*%%"`
++
+ 	  func_warning "relinking \`$file'"
+ 	  func_show_eval "$relink_command" \
+ 	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+@@ -6504,8 +6517,12 @@ func_mode_link ()
+ 	    absdir="$abs_ladir"
+ 	    libdir="$abs_ladir"
+ 	  else
+-	    dir="$lt_sysroot$libdir"
+-	    absdir="$lt_sysroot$libdir"
++	    # Adding 'libdir' from the .la file to our library search paths
++	    # breaks crosscompilation horribly.  We cheat here and don't add
++	    # it, instead adding the path where we found the .la.  -CL
++	    dir="$lt_sysroot$abs_ladir"
++	    absdir="$abs_ladir"
++	    libdir="$abs_ladir"
+ 	  fi
+ 	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ 	else
+@@ -6683,7 +6700,7 @@ func_mode_link ()
+ 	  *)
+ 	    if test "$installed" = no; then
+ 	      func_append notinst_deplibs " $lib"
+-	      need_relink=yes
++	      need_relink=no
+ 	    fi
+ 	    ;;
+ 	  esac
+@@ -6887,7 +6904,6 @@ func_mode_link ()
+ 	       test "$hardcode_direct_absolute" = no; then
+ 	      add="$libdir/$linklib"
+ 	    elif test "$hardcode_minus_L" = yes; then
+-	      add_dir="-L$libdir"
+ 	      add="-l$name"
+ 	    elif test "$hardcode_shlibpath_var" = yes; then
+ 	      case :$finalize_shlibpath: in
+@@ -6903,8 +6919,6 @@ func_mode_link ()
+ 		add="$libdir/$linklib"
+ 	      fi
+ 	    else
+-	      # We cannot seem to hardcode it, guess we'll fake it.
+-	      add_dir="-L$libdir"
+ 	      # Try looking first in the location we're being installed to.
+ 	      if test -n "$inst_prefix_dir"; then
+ 		case $libdir in
+@@ -7059,7 +7073,17 @@ func_mode_link ()
+ 		  fi
+ 		  ;;
+ 		*)
+-		  path="-L$absdir/$objdir"
++		  # OE sets installed=no in staging. We need to look in $objdir and $absdir,
++		  # preferring $objdir. RP 31/04/2008
++		  if test -f "$absdir/$objdir/$depdepl" ; then
++		    depdepl="$absdir/$objdir/$depdepl"
++		    path="-L$absdir/$objdir"
++		  elif test -f "$absdir/$depdepl" ; then
++		    depdepl="$absdir/$depdepl"
++		    path="-L$absdir"
++		  else
++		    path="-L$absdir/$objdir"
++		  fi
+ 		  ;;
+ 		esac
+ 		else
+@@ -8050,7 +8074,7 @@ EOF
+ 	    elif test -n "$runpath_var"; then
+ 	      case "$perm_rpath " in
+ 	      *" $libdir "*) ;;
+-	      *) func_apped perm_rpath " $libdir" ;;
++	      *) func_append perm_rpath " $libdir" ;;
+ 	      esac
+ 	    fi
+ 	  done
+@@ -9257,6 +9281,10 @@ EOF
+ 	    # Replace all uninstalled libtool libraries with the installed ones
+ 	    newdependency_libs=
+ 	    for deplib in $dependency_libs; do
++	      # Replacing uninstalled with installed can easily break crosscompilation,
++	      # since the installed path is generally the wrong architecture.  -CL
++	      newdependency_libs="$newdependency_libs $deplib"
++	      continue
+ 	      case $deplib in
+ 	      *.la)
+ 		func_basename "$deplib"
diff --git a/tools/libtool/patches/000-relocatable.patch b/tools/libtool/patches/000-relocatable.patch
new file mode 100644
index 0000000000..55265fe533
--- /dev/null
+++ b/tools/libtool/patches/000-relocatable.patch
@@ -0,0 +1,141 @@
+--- a/libltdl/config/general.m4sh
++++ b/libltdl/config/general.m4sh
+@@ -45,15 +45,22 @@ progpath="$0"
+ M4SH_VERBATIM([[
+ : ${CP="cp -f"}
+ test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+-: ${EGREP="@EGREP@"}
+-: ${FGREP="@FGREP@"}
+-: ${GREP="@GREP@"}
+ : ${LN_S="@LN_S@"}
+ : ${MAKE="make"}
+ : ${MKDIR="mkdir"}
+ : ${MV="mv -f"}
+ : ${RM="rm -f"}
+-: ${SED="@SED@"}
++if test -n "$STAGING_DIR"; then
++	: ${EGREP="$STAGING_DIR/../host/bin/grep -E"}
++	: ${FGREP="$STAGING_DIR/../host/bin/grep -F"}
++	: ${GREP="$STAGING_DIR/../host/bin/grep"}
++	: ${SED="$STAGING_DIR/../host/bin/sed"}
++else
++	: ${EGREP="@EGREP@"}
++	: ${FGREP="@FGREP@"}
++	: ${GREP="@GREP@"}
++	: ${SED="@SED@"}
++fi
+ : ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+ : ${Xsed="$SED -e 1s/^X//"}
+ 
+--- a/libtoolize.in
++++ b/libtoolize.in
+@@ -326,15 +326,22 @@ as_unset=as_fn_unset
+ 
+ : ${CP="cp -f"}
+ test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+-: ${EGREP="@EGREP@"}
+-: ${FGREP="@FGREP@"}
+-: ${GREP="@GREP@"}
+ : ${LN_S="@LN_S@"}
+ : ${MAKE="make"}
+ : ${MKDIR="mkdir"}
+ : ${MV="mv -f"}
+ : ${RM="rm -f"}
+-: ${SED="@SED@"}
++if test -n "$STAGING_DIR"; then
++	: ${EGREP="$STAGING_DIR/../host/bin/grep -E"}
++	: ${FGREP="$STAGING_DIR/../host/bin/grep -F"}
++	: ${GREP="$STAGING_DIR/../host/bin/grep"}
++	: ${SED="$STAGING_DIR/../host/bin/sed"}
++else
++	: ${EGREP="@EGREP@"}
++	: ${FGREP="@FGREP@"}
++	: ${GREP="@GREP@"}
++	: ${SED="@SED@"}
++fi
+ : ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+ : ${Xsed="$SED -e 1s/^X//"}
+ 
+@@ -2476,10 +2483,17 @@ func_check_macros ()
+ 
+   # Locations for important files:
+   prefix=@prefix@
+-  datadir=@datadir@
+-  pkgdatadir=@pkgdatadir@
+-  pkgltdldir=@pkgdatadir@
+-  aclocaldir=@aclocaldir@
++  if test -n "$STAGING_DIR"; then
++    datadir="$STAGING_DIR/../host/share"
++    pkgdatadir="$STAGING_DIR/../host/share/libtool"
++    pkgltdldir="$STAGING_DIR/../host/share/libtool"
++    aclocaldir="$STAGING_DIR/../host/share/aclocal"
++  else
++    datadir=@datadir@
++    pkgdatadir=@pkgdatadir@
++    pkgltdldir=@pkgdatadir@
++    aclocaldir=@aclocaldir@
++  fi
+   auxdir=
+   macrodir=
+   configure_ac=configure.in
+--- a/libtoolize.m4sh
++++ b/libtoolize.m4sh
+@@ -1450,10 +1450,17 @@ func_check_macros ()
+ 
+   # Locations for important files:
+   prefix=@prefix@
+-  datadir=@datadir@
+-  pkgdatadir=@pkgdatadir@
+-  pkgltdldir=@pkgdatadir@
+-  aclocaldir=@aclocaldir@
++  if test -n "$STAGING_DIR"; then
++    datadir="$STAGING_DIR/../host/share"
++    pkgdatadir="$STAGING_DIR/../host/share/libtool"
++    pkgltdldir="$STAGING_DIR/../host/share/libtool"
++    aclocaldir="$STAGING_DIR/../host/share/aclocal"
++  else
++    datadir=@datadir@
++    pkgdatadir=@pkgdatadir@
++    pkgltdldir=@pkgdatadir@
++    aclocaldir=@aclocaldir@
++  fi
+   auxdir=
+   macrodir=
+   configure_ac=configure.in
+--- a/libltdl/m4/libtool.m4
++++ b/libltdl/m4/libtool.m4
+@@ -875,9 +875,8 @@ dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+ # ----------------
+ m4_defun([_LT_TAG_COMPILER],
+ [AC_REQUIRE([AC_PROG_CC])dnl
+-
+ _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+-_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
++_LT_DECL([LTCFLAGS], [CFLAGS], ["-O2 -I\${STAGING_DIR:-$STAGING_DIR}/../host/include"], [LTCC compiler flags])dnl
+ _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+ _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+ 
+@@ -7509,9 +7508,9 @@ m4_defun([_LT_DECL_EGREP],
+ [AC_REQUIRE([AC_PROG_EGREP])dnl
+ AC_REQUIRE([AC_PROG_FGREP])dnl
+ test -z "$GREP" && GREP=grep
+-_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+-_LT_DECL([], [EGREP], [1], [An ERE matcher])
+-_LT_DECL([], [FGREP], [1], [A literal string matcher])
++_LT_DECL([], [GREP], ["\${STAGING_DIR:-$STAGING_DIR}/../host/bin/grep"], [A grep program that handles long lines])
++_LT_DECL([], [EGREP], ["\${STAGING_DIR:-$STAGING_DIR}/../host/bin/grep -E"], [An ERE matcher])
++_LT_DECL([], [FGREP], ["\${STAGING_DIR:-$STAGING_DIR}/../host/bin/grep -F"], [A literal string matcher])
+ dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+ AC_SUBST([GREP])
+ ])
+@@ -7544,9 +7543,8 @@ AC_SUBST([DLLTOOL])
+ # as few characters as possible.  Prefer GNU sed if found.
+ m4_defun([_LT_DECL_SED],
+ [AC_PROG_SED
+-test -z "$SED" && SED=sed
+ Xsed="$SED -e 1s/^X//"
+-_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
++_LT_DECL([], [SED], ["\${STAGING_DIR:-$STAGING_DIR}/../host/bin/sed"], [A sed program that does not truncate output])
+ _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+     [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+ ])# _LT_DECL_SED
diff --git a/tools/libtool/patches/001-fix-func_append.patch b/tools/libtool/patches/001-fix-func_append.patch
new file mode 100644
index 0000000000..4c3c07b776
--- /dev/null
+++ b/tools/libtool/patches/001-fix-func_append.patch
@@ -0,0 +1,22 @@
+--- a/libltdl/config/ltmain.m4sh
++++ b/libltdl/config/ltmain.m4sh
+@@ -7261,7 +7261,7 @@ EOF
+ 	    elif test -n "$runpath_var"; then
+ 	      case "$perm_rpath " in
+ 	      *" $libdir "*) ;;
+-	      *) func_apped perm_rpath " $libdir" ;;
++	      *) func_append perm_rpath " $libdir" ;;
+ 	      esac
+ 	    fi
+ 	  done
+--- a/libltdl/config/ltmain.sh
++++ b/libltdl/config/ltmain.sh
+@@ -8050,7 +8050,7 @@ EOF
+ 	    elif test -n "$runpath_var"; then
+ 	      case "$perm_rpath " in
+ 	      *" $libdir "*) ;;
+-	      *) func_apped perm_rpath " $libdir" ;;
++	      *) func_append perm_rpath " $libdir" ;;
+ 	      esac
+ 	    fi
+ 	  done
diff --git a/tools/libtool/patches/100-libdir-fixes.patch b/tools/libtool/patches/100-libdir-fixes.patch
new file mode 100644
index 0000000000..d4e6f785cc
--- /dev/null
+++ b/tools/libtool/patches/100-libdir-fixes.patch
@@ -0,0 +1,94 @@
+--- a/libltdl/config/ltmain.m4sh
++++ b/libltdl/config/ltmain.m4sh
+@@ -5715,8 +5715,14 @@ func_mode_link ()
+ 	    absdir="$abs_ladir"
+ 	    libdir="$abs_ladir"
+ 	  else
+-	    dir="$lt_sysroot$libdir"
+-	    absdir="$lt_sysroot$libdir"
++	    # Adding 'libdir' from the .la file to our library search paths
++	    # breaks crosscompilation horribly.  We cheat here and don't add
++	    # it, instead adding the path where we found the .la.  -CL
++	    dir="$lt_sysroot$abs_ladir"
++	    absdir="$abs_ladir"
++	    libdir="$abs_ladir"
++	    #dir="$libdir"
++	    #absdir="$lt_sysroot$libdir"
+ 	  fi
+ 	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ 	else
+@@ -6114,8 +6120,6 @@ func_mode_link ()
+ 		add="$libdir/$linklib"
+ 	      fi
+ 	    else
+-	      # We cannot seem to hardcode it, guess we'll fake it.
+-	      add_dir="-L$libdir"
+ 	      # Try looking first in the location we're being installed to.
+ 	      if test -n "$inst_prefix_dir"; then
+ 		case $libdir in
+@@ -6270,7 +6274,17 @@ func_mode_link ()
+ 		  fi
+ 		  ;;
+ 		*)
+-		  path="-L$absdir/$objdir"
++                  # OE sets installed=no in staging. We need to look in $objdir and $absdir, 
++                  # preferring $objdir. RP 31/04/2008
++                  if test -f "$absdir/$objdir/$depdepl" ; then
++		    depdepl="$absdir/$objdir/$depdepl"
++		    path="-L$absdir/$objdir"
++                  elif test -f "$absdir/$depdepl" ; then
++		    depdepl="$absdir/$depdepl"
++		    path="-L$absdir"
++                  else
++		    path="-L$absdir/$objdir"
++                  fi
+ 		  ;;
+ 		esac
+ 		else
+--- a/libltdl/config/ltmain.sh
++++ b/libltdl/config/ltmain.sh
+@@ -6504,8 +6504,14 @@ func_mode_link ()
+ 	    absdir="$abs_ladir"
+ 	    libdir="$abs_ladir"
+ 	  else
+-	    dir="$lt_sysroot$libdir"
+-	    absdir="$lt_sysroot$libdir"
++	    # Adding 'libdir' from the .la file to our library search paths
++	    # breaks crosscompilation horribly.  We cheat here and don't add
++	    # it, instead adding the path where we found the .la.  -CL
++	    dir="$lt_sysroot$abs_ladir"
++	    absdir="$abs_ladir"
++	    libdir="$abs_ladir"
++	    #dir="$libdir"
++	    #absdir="$lt_sysroot$libdir"
+ 	  fi
+ 	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ 	else
+@@ -6903,8 +6909,6 @@ func_mode_link ()
+ 		add="$libdir/$linklib"
+ 	      fi
+ 	    else
+-	      # We cannot seem to hardcode it, guess we'll fake it.
+-	      add_dir="-L$libdir"
+ 	      # Try looking first in the location we're being installed to.
+ 	      if test -n "$inst_prefix_dir"; then
+ 		case $libdir in
+@@ -7059,7 +7063,17 @@ func_mode_link ()
+ 		  fi
+ 		  ;;
+ 		*)
+-		  path="-L$absdir/$objdir"
++                  # OE sets installed=no in staging. We need to look in $objdir and $absdir, 
++                  # preferring $objdir. RP 31/04/2008
++                  if test -f "$absdir/$objdir/$depdepl" ; then
++		    depdepl="$absdir/$objdir/$depdepl"
++		    path="-L$absdir/$objdir"
++                  elif test -f "$absdir/$depdepl" ; then
++		    depdepl="$absdir/$depdepl"
++		    path="-L$absdir"
++                  else
++		    path="-L$absdir/$objdir"
++                  fi
+ 		  ;;
+ 		esac
+ 		else
diff --git a/tools/libtool/patches/110-dont-use-target-dir-for-relinking.patch b/tools/libtool/patches/110-dont-use-target-dir-for-relinking.patch
new file mode 100644
index 0000000000..c78058934a
--- /dev/null
+++ b/tools/libtool/patches/110-dont-use-target-dir-for-relinking.patch
@@ -0,0 +1,20 @@
+--- a/libltdl/config/ltmain.m4sh
++++ b/libltdl/config/ltmain.m4sh
+@@ -6104,7 +6104,6 @@ func_mode_link ()
+ 	       test "$hardcode_direct_absolute" = no; then
+ 	      add="$libdir/$linklib"
+ 	    elif test "$hardcode_minus_L" = yes; then
+-	      add_dir="-L$libdir"
+ 	      add="-l$name"
+ 	    elif test "$hardcode_shlibpath_var" = yes; then
+ 	      case :$finalize_shlibpath: in
+--- a/libltdl/config/ltmain.sh
++++ b/libltdl/config/ltmain.sh
+@@ -6893,7 +6893,6 @@ func_mode_link ()
+ 	       test "$hardcode_direct_absolute" = no; then
+ 	      add="$libdir/$linklib"
+ 	    elif test "$hardcode_minus_L" = yes; then
+-	      add_dir="-L$libdir"
+ 	      add="-l$name"
+ 	    elif test "$hardcode_shlibpath_var" = yes; then
+ 	      case :$finalize_shlibpath: in
diff --git a/tools/libtool/patches/120-strip-unsafe-dirs-for-relinking.patch b/tools/libtool/patches/120-strip-unsafe-dirs-for-relinking.patch
new file mode 100644
index 0000000000..1c3df4c004
--- /dev/null
+++ b/tools/libtool/patches/120-strip-unsafe-dirs-for-relinking.patch
@@ -0,0 +1,24 @@
+--- a/libltdl/config/ltmain.m4sh
++++ b/libltdl/config/ltmain.m4sh
+@@ -2183,6 +2183,9 @@ func_mode_install ()
+ 	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ 	  fi
+ 
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/lib[^[:space:]]*%%"`
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/usr/lib[^[:space:]]*%%"`
++
+ 	  func_warning "relinking \`$file'"
+ 	  func_show_eval "$relink_command" \
+ 	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+--- a/libltdl/config/ltmain.sh
++++ b/libltdl/config/ltmain.sh
+@@ -2972,6 +2972,9 @@ func_mode_install ()
+ 	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ 	  fi
+ 
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/lib[^[:space:]]*%%"`
++	  relink_command=`$ECHO "$relink_command" | $SED "s%-L[[:space:]]*/usr/lib[^[:space:]]*%%"`
++
+ 	  func_warning "relinking \`$file'"
+ 	  func_show_eval "$relink_command" \
+ 	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
diff --git a/tools/libtool/patches/150-trailingslash.patch b/tools/libtool/patches/150-trailingslash.patch
new file mode 100644
index 0000000000..a01f9be77b
--- /dev/null
+++ b/tools/libtool/patches/150-trailingslash.patch
@@ -0,0 +1,49 @@
+A command like /bin/sh ../../i586-poky-linux-libtool   --mode=install /usr/bin/install -c   gck-roots-store-standalone.la '/media/data1/builds/poky1/tmp/work/core2-poky-linux/gnome-keyring-2.26.1-r1/image/usr/lib/gnome-keyring/standalone/' fails (e.g. gnome-keyring or pulseaudio)
+
+This is because libdir has a trailing slash which breaks the comparision.
+
+RP 2/1/10
+
+Merged a patch received from Gary Thomas <gary@mlbassoc.com>
+
+Date: 2010/07/12
+Nitin A Kamble <nitin.a.kamble@intel.com>
+
+--- a/libltdl/config/ltmain.m4sh
++++ b/libltdl/config/ltmain.m4sh
+@@ -2164,8 +2164,15 @@ func_mode_install ()
+ 	func_append dir "$objdir"
+ 
+ 	if test -n "$relink_command"; then
++      # Strip any trailing slash from the destination.
++      func_stripname '' '/' "$libdir"
++      destlibdir=$func_stripname_result
++
++      func_stripname '' '/' "$destdir"
++      s_destdir=$func_stripname_result
++
+ 	  # Determine the prefix the user has applied to our future dir.
+-	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
++	  inst_prefix_dir=`$ECHO "X$s_destdir" | $Xsed -e "s%$destlibdir\$%%"`
+ 
+ 	  # Don't allow the user to place us outside of our expected
+ 	  # location b/c this prevents finding dependent libraries that
+--- a/libltdl/config/ltmain.sh
++++ b/libltdl/config/ltmain.sh
+@@ -2953,8 +2953,15 @@ func_mode_install ()
+ 	func_append dir "$objdir"
+ 
+ 	if test -n "$relink_command"; then
++      # Strip any trailing slash from the destination.
++      func_stripname '' '/' "$libdir"
++      destlibdir=$func_stripname_result
++
++      func_stripname '' '/' "$destdir"
++      s_destdir=$func_stripname_result
++
+ 	  # Determine the prefix the user has applied to our future dir.
+-	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
++	  inst_prefix_dir=`$ECHO "X$s_destdir" | $Xsed -e "s%$destlibdir\$%%"`
+ 
+ 	  # Don't allow the user to place us outside of our expected
+ 	  # location b/c this prevents finding dependent libraries that
diff --git a/tools/libtool/patches/160-passthrough-ssp.patch b/tools/libtool/patches/160-passthrough-ssp.patch
new file mode 100644
index 0000000000..9fad9aa9df
--- /dev/null
+++ b/tools/libtool/patches/160-passthrough-ssp.patch
@@ -0,0 +1,12 @@
+diff -ur libtool-2.4.orig/libltdl/config/ltmain.m4sh libtool-2.4/libltdl/config/ltmain.m4sh
+--- libtool-2.4.orig/libltdl/config/ltmain.m4sh	2015-06-18 10:46:15.499996979 +0200
++++ libtool-2.4/libltdl/config/ltmain.m4sh	2015-06-18 10:48:24.686882213 +0200
+@@ -5061,7 +5061,7 @@
+       # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+-      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
++      -O*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*)
+         func_quote_for_eval "$arg"
+ 	arg="$func_quote_for_eval_result"
+         func_append compile_command " $arg"
diff --git a/tools/libtool/patches/200-openwrt-branding.patch b/tools/libtool/patches/200-openwrt-branding.patch
new file mode 100644
index 0000000000..dd3e3d6b78
--- /dev/null
+++ b/tools/libtool/patches/200-openwrt-branding.patch
@@ -0,0 +1,112 @@
+--- a/libltdl/config/general.m4sh
++++ b/libltdl/config/general.m4sh
+@@ -359,7 +359,7 @@ opt_warning=:
+ # name if it has been set yet.
+ func_echo ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }$*"
+ }
+ 
+ # func_verbose arg...
+@@ -385,14 +385,14 @@ func_echo_all ()
+ # Echo program name prefixed message to standard error.
+ func_error ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+ }
+ 
+ # func_warning arg...
+ # Echo program name prefixed warning message to standard error.
+ func_warning ()
+ {
+-    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
++    $opt_warning && $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+ 
+     # bash bug again:
+     :
+--- a/libltdl/config/ltmain.sh
++++ b/libltdl/config/ltmain.sh
+@@ -443,7 +443,7 @@ opt_warning=:
+ # name if it has been set yet.
+ func_echo ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }$*"
+ }
+ 
+ # func_verbose arg...
+@@ -469,14 +469,14 @@ func_echo_all ()
+ # Echo program name prefixed message to standard error.
+ func_error ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+ }
+ 
+ # func_warning arg...
+ # Echo program name prefixed warning message to standard error.
+ func_warning ()
+ {
+-    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
++    $opt_warning && $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+ 
+     # bash bug again:
+     :
+--- a/libtoolize.in
++++ b/libtoolize.in
+@@ -640,7 +640,7 @@ opt_warning=:
+ # name if it has been set yet.
+ func_echo ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }$*"
+ }
+ 
+ # func_verbose arg...
+@@ -666,14 +666,14 @@ func_echo_all ()
+ # Echo program name prefixed message to standard error.
+ func_error ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+ }
+ 
+ # func_warning arg...
+ # Echo program name prefixed warning message to standard error.
+ func_warning ()
+ {
+-    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
++    $opt_warning && $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+ 
+     # bash bug again:
+     :
+--- a/tests/defs.in
++++ b/tests/defs.in
+@@ -588,7 +588,7 @@ opt_warning=:
+ # name if it has been set yet.
+ func_echo ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }$*"
+ }
+ 
+ # func_verbose arg...
+@@ -614,14 +614,14 @@ func_echo_all ()
+ # Echo program name prefixed message to standard error.
+ func_error ()
+ {
+-    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
++    $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+ }
+ 
+ # func_warning arg...
+ # Echo program name prefixed warning message to standard error.
+ func_warning ()
+ {
+-    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
++    $opt_warning && $ECHO "OpenWrt-$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+ 
+     # bash bug again:
+     :
diff --git a/tools/lzma-old/Makefile b/tools/lzma-old/Makefile
new file mode 100644
index 0000000000..08511b0ec9
--- /dev/null
+++ b/tools/lzma-old/Makefile
@@ -0,0 +1,36 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lzma-old
+PKG_VERSION:=4.32
+
+PKG_SOURCE:=lzma-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://downloads.openwrt.org/sources/
+PKG_MD5SUM:=5587d6ac230ad1903d504fc3253f0e42
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/lzma-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+LIB_DIR=$(HOST_BUILD_DIR)/C/7zip/Compress/LZMA_Lib
+ALONE_DIR=$(HOST_BUILD_DIR)/C/7zip/Compress/LZMA_Alone
+
+define Host/Compile
+	$(MAKE) -C $(LIB_DIR)
+	$(MAKE) -f makefile.gcc -C $(ALONE_DIR)
+endef
+
+define Host/Install
+	$(INSTALL_DATA) $(LIB_DIR)/liblzma.a $(STAGING_DIR_HOST)/lib/liblzma-old.a
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/lib/liblzma-old.a
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/lzma-old/patches/100-lzma_zlib.patch b/tools/lzma-old/patches/100-lzma_zlib.patch
new file mode 100644
index 0000000000..32d1263963
--- /dev/null
+++ b/tools/lzma-old/patches/100-lzma_zlib.patch
@@ -0,0 +1,404 @@
+--- a/C/7zip/Compress/LZMA/LZMADecoder.cpp
++++ b/C/7zip/Compress/LZMA/LZMADecoder.cpp
+@@ -274,12 +274,17 @@ STDMETHODIMP CDecoder::SetDecoderPropert
+   Byte remainder = (Byte)(properties[0] / 9);
+   int lp = remainder % 5;
+   int pb = remainder / 5;
+-  if (pb > NLength::kNumPosStatesBitsMax)
+-    return E_INVALIDARG;
+-  _posStateMask = (1 << pb) - 1;
+   UInt32 dictionarySize = 0;
+   for (int i = 0; i < 4; i++)
+     dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
++  return SetDecoderPropertiesRaw(lc, lp, pb, dictionarySize);
++}
++
++STDMETHODIMP CDecoder::SetDecoderPropertiesRaw(int lc, int lp, int pb, UInt32 dictionarySize)
++{
++  if (pb > NLength::kNumPosStatesBitsMax)
++    return E_INVALIDARG;
++  _posStateMask = (1 << pb) - 1;
+   if (!_outWindowStream.Create(dictionarySize))
+     return E_OUTOFMEMORY;
+   if (!_literalDecoder.Create(lp, lc))
+--- a/C/7zip/Compress/LZMA/LZMADecoder.h
++++ b/C/7zip/Compress/LZMA/LZMADecoder.h
+@@ -228,6 +228,7 @@ public:
+       ICompressProgressInfo *progress);
+ 
+   STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
++  STDMETHOD(SetDecoderPropertiesRaw)(int lc, int lp, int pb, UInt32 dictionarySize);
+ 
+   STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+ 
+--- /dev/null
++++ b/C/7zip/Compress/LZMA_Lib/makefile
+@@ -0,0 +1,92 @@
++PROG = liblzma.a
++CXX = g++ -O3 -Wall
++AR = ar
++RM = rm -f
++CFLAGS = -c  -I ../../../
++
++OBJS = \
++  ZLib.o \
++  LZMADecoder.o \
++  LZMAEncoder.o \
++  LZInWindow.o \
++  LZOutWindow.o \
++  RangeCoderBit.o \
++  InBuffer.o \
++  OutBuffer.o \
++  FileStreams.o \
++  Alloc.o \
++  C_FileIO.o \
++  CommandLineParser.o \
++  CRC.o \
++  StreamUtils.o \
++  String.o \
++  StringConvert.o \
++  StringToInt.o \
++  Vector.o \
++
++
++all: $(PROG)
++
++$(PROG): $(OBJS)
++	$(AR) r $(PROG) $(OBJS)
++
++ZLib.o: ZLib.cpp
++	$(CXX) $(CFLAGS) ZLib.cpp
++
++LZMADecoder.o: ../LZMA/LZMADecoder.cpp
++	$(CXX) $(CFLAGS) ../LZMA/LZMADecoder.cpp
++
++LZMAEncoder.o: ../LZMA/LZMAEncoder.cpp
++	$(CXX) $(CFLAGS) ../LZMA/LZMAEncoder.cpp
++
++LZInWindow.o: ../LZ/LZInWindow.cpp
++	$(CXX) $(CFLAGS) ../LZ/LZInWindow.cpp
++
++LZOutWindow.o: ../LZ/LZOutWindow.cpp
++	$(CXX) $(CFLAGS) ../LZ/LZOutWindow.cpp
++
++RangeCoderBit.o: ../RangeCoder/RangeCoderBit.cpp
++	$(CXX) $(CFLAGS) ../RangeCoder/RangeCoderBit.cpp
++
++InBuffer.o: ../../Common/InBuffer.cpp
++	$(CXX) $(CFLAGS) ../../Common/InBuffer.cpp
++
++OutBuffer.o: ../../Common/OutBuffer.cpp
++	$(CXX) $(CFLAGS) ../../Common/OutBuffer.cpp
++
++StreamUtils.o: ../../Common/StreamUtils.cpp
++	$(CXX) $(CFLAGS) ../../Common/StreamUtils.cpp
++
++FileStreams.o: ../../Common/FileStreams.cpp
++	$(CXX) $(CFLAGS) ../../Common/FileStreams.cpp
++
++Alloc.o: ../../../Common/Alloc.cpp
++	$(CXX) $(CFLAGS) ../../../Common/Alloc.cpp
++
++C_FileIO.o: ../../../Common/C_FileIO.cpp
++	$(CXX) $(CFLAGS) ../../../Common/C_FileIO.cpp
++
++CommandLineParser.o: ../../../Common/CommandLineParser.cpp
++	$(CXX) $(CFLAGS) ../../../Common/CommandLineParser.cpp
++
++CRC.o: ../../../Common/CRC.cpp
++	$(CXX) $(CFLAGS) ../../../Common/CRC.cpp
++
++MyWindows.o: ../../../Common/MyWindows.cpp
++	$(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp
++
++String.o: ../../../Common/String.cpp
++	$(CXX) $(CFLAGS) ../../../Common/String.cpp
++
++StringConvert.o: ../../../Common/StringConvert.cpp
++	$(CXX) $(CFLAGS) ../../../Common/StringConvert.cpp
++
++StringToInt.o: ../../../Common/StringToInt.cpp
++	$(CXX) $(CFLAGS) ../../../Common/StringToInt.cpp
++
++Vector.o: ../../../Common/Vector.cpp
++	$(CXX) $(CFLAGS) ../../../Common/Vector.cpp
++
++clean:
++	-$(RM) $(PROG) $(OBJS)
++
+--- /dev/null
++++ b/C/7zip/Compress/LZMA_Lib/ZLib.cpp
+@@ -0,0 +1,273 @@
++/*
++ * lzma zlib simplified wrapper
++ *
++ * Copyright (c) 2005-2006 Oleg I. Vdovikin <oleg@cs.msu.su>
++ *
++ * This library is free software; you can redistribute 
++ * it and/or modify it under the terms of the GNU Lesser 
++ * General Public License as published by the Free Software 
++ * Foundation; either version 2.1 of the License, or 
++ * (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be 
++ * useful, but WITHOUT ANY WARRANTY; without even the implied 
++ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
++ * PURPOSE. See the GNU Lesser General Public License 
++ * for more details.
++ *
++ * You should have received a copy of the GNU Lesser General 
++ * Public License along with this library; if not, write to 
++ * the Free Software Foundation, Inc., 59 Temple Place, 
++ * Suite 330, Boston, MA 02111-1307 USA 
++ */
++
++/*
++ * default values for encoder/decoder used by wrapper
++ */
++
++#include <zlib.h>
++
++#define ZLIB_LC 3
++#define ZLIB_LP 0
++#define ZLIB_PB 2
++
++#ifdef WIN32
++#include <initguid.h>
++#else
++#define INITGUID
++#endif
++
++#include "../../../Common/MyWindows.h"
++#include "../LZMA/LZMADecoder.h"
++#include "../LZMA/LZMAEncoder.h"
++
++#define STG_E_SEEKERROR                  ((HRESULT)0x80030019L)
++#define STG_E_MEDIUMFULL                 ((HRESULT)0x80030070L)
++
++class CInMemoryStream: 
++  public IInStream,
++  public IStreamGetSize,
++  public CMyUnknownImp
++{
++public:
++  CInMemoryStream(const Bytef *data, UInt64 size) : 
++	  m_data(data), m_size(size), m_offset(0) {}
++
++  virtual ~CInMemoryStream() {}
++
++  MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
++
++  STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize)
++  {
++	  if (size > m_size - m_offset) 
++		  size = m_size - m_offset;
++
++	  if (size) {
++		  memcpy(data, m_data + m_offset, size);
++	  }
++
++	  m_offset += size;
++
++	  if (processedSize) 
++		  *processedSize = size;
++
++	  return S_OK;
++  }
++
++  STDMETHOD(ReadPart)(void *data, UInt32 size, UInt32 *processedSize)
++  {
++	return Read(data, size, processedSize);
++  }
++
++  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
++  {
++	  UInt64 _offset;
++
++	  if (seekOrigin == STREAM_SEEK_SET) _offset = offset;
++	  else if (seekOrigin == STREAM_SEEK_CUR) _offset = m_offset + offset; 
++	  else if (seekOrigin == STREAM_SEEK_END) _offset = m_size;
++	  else return STG_E_INVALIDFUNCTION;
++
++	  if (_offset < 0 || _offset > m_size)
++		  return STG_E_SEEKERROR;
++
++	  m_offset = _offset;
++
++	  if (newPosition)
++		  *newPosition = m_offset;
++
++	  return S_OK;
++  }
++
++  STDMETHOD(GetSize)(UInt64 *size)
++  {
++	  *size = m_size;
++	  return S_OK;
++  }
++protected:
++	const Bytef *m_data;
++	UInt64 m_size;
++	UInt64 m_offset;
++};
++
++class COutMemoryStream: 
++  public IOutStream,
++  public CMyUnknownImp
++{
++public:
++  COutMemoryStream(Bytef *data, UInt64 maxsize) : 
++	  m_data(data), m_size(0), m_maxsize(maxsize), m_offset(0) {}
++  virtual ~COutMemoryStream() {}
++  
++  MY_UNKNOWN_IMP1(IOutStream)
++
++  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize)
++  {
++	  if (size > m_maxsize - m_offset) 
++		  size = m_maxsize - m_offset;
++
++	  if (size) {
++		  memcpy(m_data + m_offset, data, size);
++	  }
++
++	  m_offset += size;
++
++	  if (m_offset > m_size)
++		m_size = m_offset;
++
++	  if (processedSize) 
++		  *processedSize = size;
++
++	  return S_OK;
++  }
++  
++  STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize)
++  {
++	  return Write(data, size, processedSize);
++  }
++
++  STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
++  {
++	  UInt64 _offset;
++
++	  if (seekOrigin == STREAM_SEEK_SET) _offset = offset;
++	  else if (seekOrigin == STREAM_SEEK_CUR) _offset = m_offset + offset; 
++	  else if (seekOrigin == STREAM_SEEK_END) _offset = m_size;
++	  else return STG_E_INVALIDFUNCTION;
++
++	  if (_offset < 0 || _offset > m_maxsize)
++		  return STG_E_SEEKERROR;
++
++	  m_offset = _offset;
++
++	  if (newPosition)
++		  *newPosition = m_offset;
++
++	  return S_OK;
++  }
++  
++  STDMETHOD(SetSize)(Int64 newSize)
++  {
++	  if ((UInt64)newSize > m_maxsize) 
++		  return STG_E_MEDIUMFULL;
++
++	  return S_OK;
++  }
++protected:
++	Bytef *m_data;
++	UInt64 m_size;
++	UInt64 m_maxsize;
++	UInt64 m_offset;
++};
++
++ZEXTERN int ZEXPORT compress2 (Bytef *dest,   uLongf *destLen,
++                                  const Bytef *source, uLong sourceLen,
++                                  int level)
++{
++	CInMemoryStream *inStreamSpec = new CInMemoryStream(source, sourceLen);
++	CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
++	
++	COutMemoryStream *outStreamSpec = new COutMemoryStream(dest, *destLen);
++	CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
++	
++	NCompress::NLZMA::CEncoder *encoderSpec = 
++		new NCompress::NLZMA::CEncoder;
++	CMyComPtr<ICompressCoder> encoder = encoderSpec;
++	
++	PROPID propIDs[] = 
++	{
++		NCoderPropID::kDictionarySize,
++		NCoderPropID::kPosStateBits,
++		NCoderPropID::kLitContextBits,
++		NCoderPropID::kLitPosBits,
++		NCoderPropID::kAlgorithm,
++		NCoderPropID::kNumFastBytes,
++		NCoderPropID::kMatchFinder,
++		NCoderPropID::kEndMarker
++	};
++	const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
++	
++	PROPVARIANT properties[kNumProps];
++	for (int p = 0; p < 6; p++)
++		properties[p].vt = VT_UI4;
++	properties[0].ulVal = UInt32(1 << (level + 14));
++	properties[1].ulVal = UInt32(ZLIB_PB);
++	properties[2].ulVal = UInt32(ZLIB_LC); // for normal files
++	properties[3].ulVal = UInt32(ZLIB_LP); // for normal files
++	properties[4].ulVal = UInt32(2);
++	properties[5].ulVal = UInt32(128);
++	
++	properties[6].vt = VT_BSTR;
++	properties[6].bstrVal = (BSTR)(const wchar_t *)L"BT4";
++	
++	properties[7].vt = VT_BOOL;
++	properties[7].boolVal = VARIANT_TRUE;
++	
++	if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
++		return Z_MEM_ERROR; // should not happen
++	
++	HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
++	if (result == E_OUTOFMEMORY)
++	{
++		return Z_MEM_ERROR;
++	}   
++	else if (result != S_OK)
++	{
++		return Z_BUF_ERROR;	// should not happen
++	}   
++	
++	UInt64 fileSize;
++	outStreamSpec->Seek(0, STREAM_SEEK_END, &fileSize);
++	*destLen = fileSize;
++	
++	return Z_OK;
++}
++
++ZEXTERN int ZEXPORT uncompress (Bytef *dest,   uLongf *destLen,
++                                   const Bytef *source, uLong sourceLen)
++{
++	CInMemoryStream *inStreamSpec = new CInMemoryStream(source, sourceLen);
++	CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
++	
++	COutMemoryStream *outStreamSpec = new COutMemoryStream(dest, *destLen);
++	CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
++	
++	NCompress::NLZMA::CDecoder *decoderSpec = 
++		new NCompress::NLZMA::CDecoder;
++	CMyComPtr<ICompressCoder> decoder = decoderSpec;
++	
++	if (decoderSpec->SetDecoderPropertiesRaw(ZLIB_LC, 
++		ZLIB_LP, ZLIB_PB, (1 << 23)) != S_OK) return Z_DATA_ERROR;
++	
++	UInt64 fileSize = *destLen;
++	
++	if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
++	{
++		return Z_DATA_ERROR;
++	}
++	
++	outStreamSpec->Seek(0, STREAM_SEEK_END, &fileSize);
++	*destLen = fileSize;
++	
++	return Z_OK;
++}
diff --git a/tools/lzma-old/patches/110-ranlib.patch b/tools/lzma-old/patches/110-ranlib.patch
new file mode 100644
index 0000000000..813b4137f1
--- /dev/null
+++ b/tools/lzma-old/patches/110-ranlib.patch
@@ -0,0 +1,10 @@
+--- a/C/7zip/Compress/LZMA_Lib/makefile
++++ b/C/7zip/Compress/LZMA_Lib/makefile
+@@ -29,6 +29,7 @@ all: $(PROG)
+ 
+ $(PROG): $(OBJS)
+ 	$(AR) r $(PROG) $(OBJS)
++	ranlib $(PROG)
+ 
+ ZLib.o: ZLib.cpp
+ 	$(CXX) $(CFLAGS) ZLib.cpp
diff --git a/tools/lzma/Makefile b/tools/lzma/Makefile
new file mode 100644
index 0000000000..4922f8087f
--- /dev/null
+++ b/tools/lzma/Makefile
@@ -0,0 +1,36 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lzma
+PKG_VERSION:=4.65
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://downloads.openwrt.org/sources/
+PKG_MD5SUM:=434e51a018b4c8ef377bf81520a53af0
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+UTIL_DIR=$(HOST_BUILD_DIR)/C/LzmaUtil
+ALONE_DIR=$(HOST_BUILD_DIR)/CPP/7zip/Compress/LZMA_Alone
+
+define Host/Compile
+	$(MAKE) -C $(UTIL_DIR) -f makefile.gcc
+	$(MAKE) -C $(ALONE_DIR) -f makefile.gcc
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/CPP/7zip/Compress/LZMA_Alone/lzma_alone $(STAGING_DIR_HOST)/bin/lzma
+endef
+
+define Host/Clean
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/lzma/patches/001-large_files.patch b/tools/lzma/patches/001-large_files.patch
new file mode 100644
index 0000000000..b95fe9e90f
--- /dev/null
+++ b/tools/lzma/patches/001-large_files.patch
@@ -0,0 +1,13 @@
+Index: lzma-4.65/CPP/7zip/Compress/LZMA_Alone/makefile.gcc
+===================================================================
+--- lzma-4.65.orig/CPP/7zip/Compress/LZMA_Alone/makefile.gcc	2009-05-15 23:33:51.000000000 +0200
++++ lzma-4.65/CPP/7zip/Compress/LZMA_Alone/makefile.gcc	2009-06-01 22:00:54.000000000 +0200
+@@ -3,7 +3,7 @@
+ CXX_C = gcc -O2 -Wall
+ LIB = -lm
+ RM = rm -f
+-CFLAGS = -c
++CFLAGS = -c -D_FILE_OFFSET_BITS=64
+ 
+ ifdef SystemDrive
+ IS_MINGW = 1
diff --git a/tools/lzma/patches/002-lzmp.patch b/tools/lzma/patches/002-lzmp.patch
new file mode 100644
index 0000000000..72d881cdb2
--- /dev/null
+++ b/tools/lzma/patches/002-lzmp.patch
@@ -0,0 +1,1059 @@
+Index: lzma-4.65/CPP/7zip/Compress/LZMA_Alone/lzmp.cpp
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ lzma-4.65/CPP/7zip/Compress/LZMA_Alone/lzmp.cpp	2009-06-01 22:01:10.000000000 +0200
+@@ -0,0 +1,895 @@
++/*
++ * LZMA command line tool similar to gzip to encode and decode LZMA files.
++ *
++ * Copyright (C) 2005 Ville Koskinen
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
++ * USA.
++ */
++
++#include "../../../Common/MyInitGuid.h"
++
++#include <iostream>
++using std::cout;
++using std::cerr;
++using std::endl;
++
++#include <cstdio>
++#include <cstdlib>
++#include <cstring>
++
++#include <string>
++using std::string;
++#include <vector>
++using std::vector;
++typedef vector<string> stringVector;
++
++#include <unistd.h>
++#include <getopt.h>
++#include <signal.h>
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <utime.h>
++#include <sys/time.h> // futimes()
++
++// For Solaris
++#ifndef HAVE_FUTIMES
++//#define futimes(fd, tv) futimesat(fd, NULL, tv)
++#endif
++
++#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
++#include <fcntl.h>
++#include <io.h>
++#define MY_SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
++#else
++#define MY_SET_BINARY_MODE(file)
++#endif
++
++#include "../../../7zip/Common/FileStreams.h"
++
++#include "../../../Common/Types.h"
++
++#include "../../../7zip/Compress/LzmaDecoder.h"
++#include "../../../7zip/Compress/LzmaEncoder.h"
++
++#include "Exception.h"
++
++#include "lzma_version.h"
++
++namespace lzma {
++
++const char *PROGRAM_VERSION = PACKAGE_VERSION;
++const char *PROGRAM_COPYRIGHT = "Copyright (C) 2006 Ville Koskinen";
++
++/* LZMA_Alone switches:
++    -a{N}:  set compression mode - [0, 2], default: 2 (max)
++    -d{N}:  set dictionary - [0,28], default: 23 (8MB)
++    -fb{N}: set number of fast bytes - [5, 255], default: 128
++    -lc{N}: set number of literal context bits - [0, 8], default: 3
++    -lp{N}: set number of literal pos bits - [0, 4], default: 0
++    -pb{N}: set number of pos bits - [0, 4], default: 2
++    -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, bt4b, pat2r, pat2,
++                pat2h, pat3h, pat4h, hc3, hc4], default: bt4
++*/
++
++struct lzma_option {
++	short compression_mode;			// -a
++	short dictionary;			// -d
++	short fast_bytes;			// -fb
++	wchar_t *match_finder;			// -mf
++	short literal_context_bits;		// -lc
++	short literal_pos_bits;			// -lp
++	short pos_bits;				// -pb
++};
++
++/* The following is a mapping from gzip/bzip2 style -1 .. -9 compression modes
++ * to the corresponding LZMA compression modes. Thanks, Larhzu, for coining
++ * these. */
++const lzma_option option_mapping[] = {
++	{ 0,  0,  0,    NULL, 0, 0, 0},		// -0 (needed for indexing)
++	{ 0, 16, 64,  L"hc4", 3, 0, 2},		// -1
++	{ 0, 20, 64,  L"hc4", 3, 0, 2},		// -2
++	{ 1, 19, 64,  L"bt4", 3, 0, 2},		// -3
++	{ 2, 20, 64,  L"bt4", 3, 0, 2},		// -4
++	{ 2, 21, 128, L"bt4", 3, 0, 2},		// -5
++	{ 2, 22, 128, L"bt4", 3, 0, 2},		// -6
++	{ 2, 23, 128, L"bt4", 3, 0, 2},		// -7
++	{ 2, 24, 255, L"bt4", 3, 0, 2},		// -8
++	{ 2, 25, 255, L"bt4", 3, 0, 2},		// -9
++};
++
++struct extension_pair {
++	char *from;
++	char *to;
++};
++
++const extension_pair known_extensions[] = {
++	{ ".lzma", "" },
++	{ ".tlz", ".tar" },
++	{ NULL, NULL }
++};
++
++/* Sorry, I just happen to like enumerations. */
++enum PROGRAM_MODE {
++	PM_COMPRESS = 0,
++	PM_DECOMPRESS,
++	PM_TEST,
++	PM_HELP,
++	PM_LICENSE,
++	PM_VERSION
++};
++
++enum {
++	STATUS_OK = 0,
++	STATUS_ERROR = 1,
++	STATUS_WARNING = 2
++};
++
++/* getopt options. */
++/* struct option { name, has_arg, flag, val } */
++const struct option long_options[] = {
++	{ "stdout", 0, 0, 'c' },
++	{ "decompress", 0, 0, 'd' },
++	{ "compress", 0, 0, 'z' },
++	{ "keep", 0, 0, 'k' },
++	{ "force", 0, 0, 'f' },
++	{ "test", 0, 0, 't' },
++	{ "suffix", 1, 0, 'S' },
++	{ "quiet", 0, 0, 'q' },
++	{ "verbose", 0, 0, 'v' },
++	{ "help", 0, 0, 'h' },
++	{ "license", 0, 0, 'L' },
++	{ "version", 0, 0, 'V' },
++	{ "fast", 0, 0, '1' },
++	{ "best", 0, 0, '9' },
++	{ 0, 0, 0, 0 }
++};
++
++/* getopt option string (for the above options). */
++const char option_string[] = "cdzkftS:qvhLV123456789A:D:F:";
++
++/* Defaults. */
++PROGRAM_MODE program_mode = PM_COMPRESS;
++int	verbosity			= 0;
++bool	stdinput			= false;
++bool	stdoutput			= false;
++bool	keep				= false;
++bool	force				= false;
++int	compression_mode		= 7;
++//char	*suffix				= strdup(".lzma");
++char	*suffix				= strdup(known_extensions[0].from);
++lzma_option	advanced_options 	= { -1, -1, -1, NULL, -1, -1, -1 };
++
++void print_help(const char *const argv0)
++{
++	// Help goes to stdout while other messages go to stderr.
++	cout << "\nlzma " << PROGRAM_VERSION
++		<< " " << PROGRAM_COPYRIGHT << "\n"
++		"Based on LZMA SDK " << LZMA_SDK_VERSION_STRING << " "
++		<< LZMA_SDK_COPYRIGHT_STRING
++		<< "\n\nUsage: " << argv0
++		<< " [flags and input files in any order]\n"
++"  -c --stdout       output to standard output\n"
++"  -d --decompress   force decompression\n"
++"  -z --compress     force compression\n"
++"  -k --keep         keep (don't delete) input files\n"
++"  -f --force        force overwrite of output file and compress links\n"
++"  -t --test         test compressed file integrity\n"
++"  -S .suf  --suffix .suf   use suffix .suf on compressed files\n"
++"  -q --quiet        suppress error messages\n"
++"  -v --verbose      be verbose\n"
++"  -h --help         print this message\n"
++"  -L --license      display the license information\n"
++"  -V --version      display version numbers of LZMA SDK and lzma\n"
++"  -1 .. -2          fast compression\n"
++"  -3 .. -9          good to excellent compression. -7 is the default.\n"
++"     --fast         alias for -1\n"
++"     --best         alias for -9 (usually *not* what you want)\n\n"
++"  Memory usage depends a lot on the chosen compression mode -1 .. -9.\n"
++"  See the man page lzma(1) for details.\n\n";
++}
++
++void print_license(void)
++{
++	cout << "\n  LZMA command line tool " << PROGRAM_VERSION << " - "
++		<< PROGRAM_COPYRIGHT
++		<< "\n  LZMA SDK " << LZMA_SDK_VERSION_STRING << " - "
++		<< LZMA_SDK_COPYRIGHT_STRING
++		<< "\n  This program is a part of the LZMA utils package.\n"
++		"  http://tukaani.org/lzma/\n\n"
++"  This program is free software; you can redistribute it and/or\n"
++"  modify it under the terms of the GNU General Public License\n"
++"  as published by the Free Software Foundation; either version 2\n"
++"  of the License, or (at your option) any later version.\n"
++"\n"
++"  This program is distributed in the hope that it will be useful,\n"
++"  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
++"  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
++"  GNU General Public License for more details.\n"
++"\n";
++}
++
++void print_version(void)
++{
++	cout << "LZMA command line tool " << PROGRAM_VERSION << "\n"
++		<< "LZMA SDK " << LZMA_SDK_VERSION_STRING << "\n";
++}
++
++short str2int (const char *str, const int &min, const int &max)
++{
++	int value = -1;
++	char *endptr = NULL;
++	if (str == NULL || str[0] == '\0')
++		throw ArgumentException("Invalid integer option");
++	value = strtol (str, &endptr, 10);
++	if (*endptr != '\0' || value < min || value > max)
++		throw ArgumentException("Invalid integer option");
++	return value;
++}
++
++void parse_options(int argc, char **argv, stringVector &filenames)
++{
++	/* Snatched from getopt(3). */
++	int c;
++
++	/* Check how we were called */
++	{
++		char *p = strrchr (argv[0], '/'); // Remove path prefix, if any
++		if (p++ == NULL)
++			p = argv[0];
++		if (strstr (p, "un") != NULL) {
++			program_mode = PM_DECOMPRESS;
++		} else if (strstr (p, "cat") != NULL) {
++			program_mode = PM_DECOMPRESS;
++			stdoutput = true;
++		}
++	}
++
++	while (-1 != (c = getopt_long(argc, argv, option_string,
++			long_options, NULL))) {
++		switch (c) {
++			// stdout
++			case 'c':
++				stdoutput = true;
++				break;
++
++			// decompress
++			case 'd':
++				program_mode = PM_DECOMPRESS;
++				break;
++
++			// compress
++			case 'z':
++				program_mode = PM_COMPRESS;
++				break;
++
++			// keep
++			case 'k':
++				keep = true;
++				break;
++
++			// force
++			case 'f':
++				force = true;
++				break;
++
++			// test
++			case 't':
++				program_mode = PM_TEST;
++				break;
++
++			// suffix
++			case 'S':
++				if (optarg) {
++					free(suffix);
++					suffix = strdup(optarg);
++				}
++				break;
++
++			// quiet
++			case 'q':
++				verbosity = 0;
++				break;
++
++			// verbose
++			case 'v':
++				verbosity++;
++				break;
++
++			// help
++			case 'h':
++				program_mode = PM_HELP;
++				break;
++
++			// license
++			case 'L':
++				program_mode = PM_LICENSE;
++				break;
++
++			// version
++			case 'V':
++				program_mode = PM_VERSION;
++				break;
++
++			case '1': case '2': case '3': case '4': case '5':
++			case '6': case '7': case '8': case '9':
++				compression_mode = c - '0';
++				break;
++
++			// Advanced options //
++			// Compression mode
++			case 'A':
++				advanced_options.compression_mode =
++						str2int (optarg, 0, 2);
++				break;
++
++			// Dictionary size
++			case 'D':
++				advanced_options.dictionary =
++						str2int (optarg, 0, 28);
++				break;
++
++			// Fast bytes
++			case 'F':
++				advanced_options.fast_bytes =
++						str2int (optarg, 0, 273);
++				break;
++
++			default:
++				throw ArgumentException("");
++				break;
++		} // switch(c)
++	} // while(1)
++
++	for (int i = optind; i < argc; i++) {
++		if (strcmp("-", argv[i]) == 0)
++			continue;
++		filenames.push_back(argv[i]);
++	}
++} // parse_options
++
++void set_encoder_properties(NCompress::NLzma::CEncoder *encoder,
++		lzma_option &opt)
++{
++	/* Almost verbatim from LzmaAlone.cpp. */
++	    PROPID propIDs[] =
++	{
++		NCoderPropID::kDictionarySize,
++		NCoderPropID::kPosStateBits,
++		NCoderPropID::kLitContextBits,
++		NCoderPropID::kLitPosBits,
++		NCoderPropID::kAlgorithm,
++		NCoderPropID::kNumFastBytes,
++		NCoderPropID::kMatchFinder,
++		NCoderPropID::kEndMarker
++	};
++	const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
++#define VALUE(x) (advanced_options.x >= 0 ? advanced_options.x : opt.x)
++	PROPVARIANT properties[kNumProps];
++	for (int p = 0; p < 6; p++)
++		properties[p].vt = VT_UI4;
++	properties[0].ulVal = UInt32(1 << VALUE (dictionary));
++	properties[1].ulVal = UInt32(VALUE (pos_bits));
++	properties[2].ulVal = UInt32(VALUE (literal_context_bits));
++	properties[3].ulVal = UInt32(VALUE (literal_pos_bits));
++	properties[4].ulVal = UInt32(VALUE (compression_mode));
++	properties[5].ulVal = UInt32(VALUE (fast_bytes));
++#undef VALUE
++
++	properties[6].vt = VT_BSTR;
++	properties[6].bstrVal = (BSTR)opt.match_finder;
++
++	properties[7].vt = VT_BOOL;
++	properties[7].boolVal = stdinput ? VARIANT_TRUE : VARIANT_FALSE;
++
++	if (encoder->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
++		throw Exception("SetCoderProperties() error");
++}
++
++void encode(NCompress::NLzma::CEncoder *encoderSpec,
++		CMyComPtr<ISequentialInStream> inStream,
++		CMyComPtr<ISequentialOutStream> outStream,
++		lzma_option encoder_options,
++		UInt64 fileSize)
++{
++	set_encoder_properties(encoderSpec, encoder_options);
++
++	encoderSpec->WriteCoderProperties(outStream);
++
++	for (int i = 0; i < 8; i++)
++	{
++		Byte b = Byte(fileSize >> (8 * i));
++		if (outStream->Write(&b, sizeof(b), 0) != S_OK)
++			throw Exception("Write error while encoding");
++	}
++
++	HRESULT result = encoderSpec->Code(inStream, outStream, 0, 0, 0);
++
++	if (result == E_OUTOFMEMORY)
++		throw Exception("Cannot allocate memory");
++	else if (result != S_OK) {
++		char buffer[33];
++		snprintf(buffer, 33, "%d", (unsigned int)result);
++		throw Exception(string("Encoder error: ") + buffer);
++	}
++}
++
++void decode(NCompress::NLzma::CDecoder *decoderSpec,
++		CMyComPtr<ISequentialInStream> inStream,
++		CMyComPtr<ISequentialOutStream> outStream)
++{
++	const UInt32 kPropertiesSize = 5;
++	Byte properties[kPropertiesSize];
++	UInt32 processedSize;
++	UInt64 fileSize = 0;
++
++	if (inStream->Read(properties, kPropertiesSize, &processedSize) != S_OK)
++		throw Exception("Read error");
++	if (processedSize != kPropertiesSize)
++		throw Exception("Read error");
++	if (decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK)
++		throw Exception("SetDecoderProperties() error");
++
++	for (int i = 0; i < 8; i++)
++	{
++		Byte b;
++
++		if (inStream->Read(&b, sizeof(b), &processedSize) != S_OK)
++			throw Exception("Read error");
++		if (processedSize != 1)
++			throw Exception("Read error");
++
++		fileSize |= ((UInt64)b) << (8 * i);
++	}
++
++	if (decoderSpec->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
++		throw Exception("Decoder error");
++}
++
++int open_instream(const string infile,
++		CMyComPtr<ISequentialInStream> &inStream,
++		UInt64 &fileSize)
++{
++	CInFileStream *inStreamSpec = new CInFileStream;
++	inStream = inStreamSpec;
++	if (!inStreamSpec->Open(infile.c_str()))
++		throw Exception("Cannot open input file " + infile);
++
++	inStreamSpec->File.GetLength(fileSize);
++
++	return inStreamSpec->File.GetHandle();
++}
++
++int open_outstream(const string outfile,
++		CMyComPtr<ISequentialOutStream> &outStream)
++{
++	COutFileStream *outStreamSpec = new COutFileStream;
++	outStream = outStreamSpec;
++
++	bool open_by_force = (program_mode == PM_TEST) | force;
++
++	if (!outStreamSpec->Create(outfile.c_str(), open_by_force))
++		throw Exception("Cannot open output file " + outfile);
++
++	return outStreamSpec->File.GetHandle();
++}
++
++double get_ratio(int inhandle, int outhandle)
++{
++	struct stat in_stats, out_stats;
++	fstat(inhandle, &in_stats);
++	fstat(outhandle, &out_stats);
++
++	return (double)out_stats.st_size / (double)in_stats.st_size;
++}
++
++mode_t get_file_mode(string filename)
++{
++	struct stat in_stat;
++	lstat(filename.c_str(), &in_stat);
++
++	return in_stat.st_mode;
++}
++
++bool string_ends_with(string str, string ending)
++{
++	return equal(ending.rbegin(), ending.rend(), str.rbegin());
++}
++
++bool extension_is_known(string filename)
++{
++	bool known_format = false;
++	extension_pair extension; int i = 1;
++
++	extension = known_extensions[0];
++	while (extension.from != NULL) {
++		if (string_ends_with(filename, extension.from)) {
++			known_format = true;
++			break;
++		}
++		extension = known_extensions[i];
++		i++;
++	}
++
++	if (!known_format) {
++		if (!string_ends_with(filename, suffix)) {
++			return false;
++		}
++	}
++
++	return true;
++}
++
++string replace_extension(string filename)
++{
++	int suffix_starts_at = filename.length() - strlen (suffix);
++	string from_suffix = filename.substr(suffix_starts_at, strlen (suffix));
++	string ret = filename.substr(0, suffix_starts_at);
++	extension_pair extension; int i = 1;
++
++	bool found_replacement = false;
++	extension = known_extensions[0];
++	while (extension.from != NULL) {
++		if (from_suffix.compare(extension.from) == 0) {
++			ret += extension.to;
++			found_replacement = true;
++			break;
++		}
++
++		extension = known_extensions[i];
++		i++;
++	}
++
++	return ret;
++}
++
++string pretty_print_status(string filename, string output_filename,
++		string ratio)
++{
++	string ret = "";
++
++	ret += filename;
++	ret += ":\t ";
++
++	if (program_mode == PM_TEST) {
++		ret += "decoded succesfully";
++
++		return ret;
++	}
++
++	if (!stdinput && !stdoutput) {
++		ret += ratio;
++		ret += " -- ";
++	}
++
++	if (program_mode == PM_COMPRESS) {
++		if (keep) {
++			ret += "encoded succesfully";
++
++			return ret;
++		}
++
++		ret += "replaced with ";
++		ret += output_filename;
++
++		return ret;
++	}
++
++	if (program_mode == PM_DECOMPRESS) {
++		if (keep) {
++			ret += "decoded succesfully";
++
++			return ret;
++		}
++
++		ret += "replaced with ";
++		ret += output_filename;
++
++		return ret;
++	}
++
++	return ret;
++}
++
++static string archive_name; // I know, it is crude, but I haven't found any other
++    // way then making a global variable to transfer filename to handler
++
++void signal_handler (int signum)
++{
++    unlink (archive_name.c_str()); // deleting
++    signal (signum, SIG_DFL); // we return the default function to used signal
++    kill (getpid(), signum); // and then send this signal to the process again
++}
++
++} // namespace lzma
++
++
++int main(int argc, char **argv)
++{
++	using namespace lzma;
++	using std::cerr;
++
++	stringVector filenames;
++
++	signal (SIGTERM,signal_handler);
++	signal (SIGHUP,signal_handler);
++	signal (SIGINT,signal_handler);
++
++	try {
++		parse_options(argc, argv, filenames);
++	}
++	catch (...) {
++		return STATUS_ERROR;
++	}
++
++	if (program_mode == PM_HELP) {
++		print_help(argv[0]);
++		return STATUS_OK;
++	}
++	else if (program_mode == PM_LICENSE) {
++		print_license();
++		return STATUS_OK;
++	}
++	else if (program_mode == PM_VERSION) {
++		print_version();
++		return STATUS_OK;
++	}
++
++	if (filenames.empty()) {
++		stdinput = true;
++		stdoutput = true;
++
++		/* FIXME: get rid of this */
++		filenames.push_back("-");
++	}
++
++	/* Protection: always create new files with 0600 in order to prevent
++	 * outsiders from reading incomplete data. */
++	umask(0077);
++
++	bool warning = false;
++
++	for (int i = 0; i < filenames.size(); i++) {
++		CMyComPtr<ISequentialInStream> inStream;
++		CMyComPtr<ISequentialOutStream> outStream;
++		UInt64 fileSize = 0;
++		int inhandle = 0, outhandle = 0;
++		string output_filename;
++
++		if (stdinput) {
++			inStream = new CStdInFileStream;
++			MY_SET_BINARY_MODE(stdin);
++			fileSize = (UInt64)(Int64)-1;
++
++			inhandle = STDIN_FILENO;
++
++			outStream = new CStdOutFileStream;
++			MY_SET_BINARY_MODE(stdout);
++
++			outhandle = STDOUT_FILENO;
++		}
++		else {
++			mode_t infile_mode = get_file_mode(filenames[i]);
++			if (!S_ISREG(infile_mode)) {
++				if (S_ISDIR(infile_mode)) {
++					warning = true;
++					cerr << argv[0] << ": " << filenames[i] << ": "
++						<< "cowardly refusing to work on directory"
++						<< endl;
++
++					continue;
++				}
++				else if (S_ISLNK(infile_mode)) {
++					if (!stdoutput && !force) {
++						warning = true;
++
++					cerr << argv[0] << ": " << filenames[i] << ": "
++							<< "cowardly refusing to work on symbolic link "
++							<< "(use --force to force encoding or decoding)"
++							<< endl;
++
++						continue;
++					}
++				}
++				else {
++					warning = true;
++
++					cerr << argv[0] << ": " << filenames[i] << ": "
++						<< "doesn't exist or is not a regular file"
++						<< endl;
++
++					continue;
++				}
++			}
++
++			// Test if the file already ends with *suffix.
++			if (program_mode == PM_COMPRESS && !force
++					&& string_ends_with(filenames[i],
++						suffix)) {
++				warning = true;
++
++				cerr << filenames[i] << " already has "
++					<< suffix << " suffix -- unchanged\n";
++
++				continue;
++			}
++
++			// Test if the file extension is known.
++			if (program_mode == PM_DECOMPRESS
++					&& !extension_is_known(filenames[i])) {
++				warning = true;
++
++				cerr << filenames[i] << ": "
++					<< " unknown suffix -- unchanged"
++					<< endl;
++
++				continue;
++			}
++
++			try {
++				inhandle = open_instream(filenames[i], inStream, fileSize);
++			}
++			catch (Exception e) {
++				cerr << argv[0] << ": " << e.what() << endl;
++				return STATUS_ERROR;
++			}
++
++			if (stdoutput) {
++				outStream = new CStdOutFileStream;
++				MY_SET_BINARY_MODE(stdout);
++
++				outhandle = STDOUT_FILENO;
++			}
++			else {
++				/* Testing mode is nothing else but decoding
++				 * and throwing away the result. */
++				if (program_mode == PM_TEST)
++					output_filename = "/dev/null";
++				else if (program_mode == PM_DECOMPRESS)
++					output_filename = replace_extension(filenames[i]);
++				else
++					output_filename = filenames[i]
++							+ suffix;
++				archive_name = output_filename;
++
++				try {
++					outhandle = open_outstream(output_filename, outStream);
++				}
++				catch (Exception e) {
++					cerr << argv[0] << ": " << e.what() << endl;
++					return STATUS_ERROR;
++				}
++			}
++
++		}
++
++		// Unless --force is specified, do not read/write compressed
++		// data from/to a terminal.
++		if (!force) {
++			if (program_mode == PM_COMPRESS && isatty(outhandle)) {
++				cerr << argv[0] << ": compressed data not "
++					"written to a terminal. Use "
++					"-f to force compression.\n"
++					<< argv[0] << ": For help, type: "
++					<< argv[0] << " -h\n";
++				return STATUS_ERROR;
++			} else if (program_mode == PM_DECOMPRESS
++					&& isatty(inhandle)) {
++				cerr << argv[0] << ": compressed data not "
++					"read from a terminal. Use "
++					"-f to force decompression.\n"
++					<< argv[0] << ": For help, type: "
++					<< argv[0] << " -h\n";
++				return STATUS_ERROR;
++			}
++		}
++
++		if (program_mode == PM_COMPRESS) {
++			    NCompress::NLzma::CEncoder *encoderSpec =
++				      new NCompress::NLzma::CEncoder;
++
++			lzma_option options = option_mapping[compression_mode];
++
++			try {
++				encode(encoderSpec, inStream, outStream, options, fileSize);
++			}
++			catch (Exception e) {
++				cerr << argv[0] << ": " << e.what() << endl;
++				unlink(output_filename.c_str());
++				delete(encoderSpec);
++
++				return STATUS_ERROR;
++			}
++
++			delete(encoderSpec);
++		}
++		else {			// PM_DECOMPRESS | PM_TEST
++		    NCompress::NLzma::CDecoder *decoderSpec =
++		        new NCompress::NLzma::CDecoder;
++
++			try {
++				decode(decoderSpec, inStream, outStream);
++			}
++			catch (Exception e) {
++				cerr << argv[0] << ": " << e.what() << endl;
++				unlink(output_filename.c_str());
++				delete(decoderSpec);
++
++				return STATUS_ERROR;
++			}
++
++			delete(decoderSpec);
++		}
++
++		/* Set permissions and owners. */
++		if ( (program_mode == PM_COMPRESS || program_mode == PM_DECOMPRESS )
++				&& (!stdinput && !stdoutput) ) {
++
++			int ret = 0;
++			struct stat file_stats;
++			ret = fstat(inhandle, &file_stats);
++
++			ret = fchmod(outhandle, file_stats.st_mode);
++			ret = fchown(outhandle, file_stats.st_uid, file_stats.st_gid);
++			// We need to call fchmod() again, since otherwise the SUID bits
++			// are lost.
++			ret = fchmod(outhandle, file_stats.st_mode);
++
++			struct timeval file_times[2];
++			// Access time
++			file_times[0].tv_sec = file_stats.st_atime;
++			file_times[0].tv_usec = 0;
++			// Modification time
++			file_times[1].tv_sec = file_stats.st_mtime;
++			file_times[1].tv_usec = 0;
++
++			ret = futimes(outhandle, file_times);
++
++			if (!keep)
++				unlink(filenames[i].c_str());
++		}
++
++		if (verbosity > 0) {
++			if (stdoutput) {
++				cerr << filenames[i] << ":\t ";
++				cerr << "decoded succesfully"
++					<< endl;
++			}
++
++			else {
++				char buf[10] = { 0 };
++
++				if (program_mode == PM_DECOMPRESS)
++					snprintf(buf, 10, "%.2f%%",
++							(1 - get_ratio(outhandle, inhandle)) * 100);
++				if (program_mode == PM_COMPRESS)
++					snprintf(buf, 10, "%.2f%%",
++							(1 - get_ratio(inhandle, outhandle)) * 100);
++
++				string ratio = buf;
++				cerr << pretty_print_status(filenames[i], output_filename,
++						ratio)
++					<< endl;
++			}
++		}
++	}
++
++	if (warning)
++		return STATUS_WARNING;
++
++	return STATUS_OK;
++}
++
+Index: lzma-4.65/CPP/7zip/Compress/LZMA_Alone/Exception.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ lzma-4.65/CPP/7zip/Compress/LZMA_Alone/Exception.h	2009-06-01 22:01:10.000000000 +0200
+@@ -0,0 +1,45 @@
++/* A couple of exceptions for lzmp.
++ *
++ * Copyright (C) 2005 Ville Koskinen
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _EXCEPTION_H_
++#define _EXCEPTION_H_
++
++#include <string>
++using std::string;
++
++class Exception
++{
++private:
++	string message;
++public:
++	Exception(char *what): message(what) { }
++	Exception(string what): message(what) { }
++
++	~Exception() { }
++
++	string what(void) { return message; }
++};
++
++class ArgumentException: public Exception
++{
++public:
++	ArgumentException(char *what): Exception(what) { }
++	ArgumentException(string what): Exception(what) { }
++
++	~ArgumentException() { }
++};
++
++#endif
++
+Index: lzma-4.65/CPP/7zip/Compress/LZMA_Alone/makefile.gcc
+===================================================================
+--- lzma-4.65.orig/CPP/7zip/Compress/LZMA_Alone/makefile.gcc	2009-06-01 22:00:54.000000000 +0200
++++ lzma-4.65/CPP/7zip/Compress/LZMA_Alone/makefile.gcc	2009-06-01 22:06:13.000000000 +0200
+@@ -1,9 +1,10 @@
+-PROG = lzma
++PROG = lzma_alone
++PROG2 = lzma
+ CXX = g++ -O2 -Wall
+ CXX_C = gcc -O2 -Wall
+ LIB = -lm
+ RM = rm -f
+-CFLAGS = -c -D_FILE_OFFSET_BITS=64
++CFLAGS = -c -I ../../../ -D_FILE_OFFSET_BITS=64 -DPACKAGE_VERSION="\"4.32.0beta3\""
+ 
+ ifdef SystemDrive
+ IS_MINGW = 1
+@@ -45,12 +46,35 @@
+   Lzma86Dec.o \
+   Lzma86Enc.o \
+ 
++OBJS2 = \
++	C_FileIO.o \
++	CRC.o \
++	Alloc.o \
++	FileStreams.o \
++	StreamUtils.o \
++	InBuffer.o \
++	OutBuffer.o \
++	LzmaDecoder.o \
++	StringConvert.o \
++	StringToInt.o \
++	LzmaEncoder.o \
++	LzmaDec.o \
++	LzmaEnc.o \
++	LzFind.o \
++	7zCrc.o \
++	lzmp.o
+ 
+-all: $(PROG)
++all: $(PROG) $(PROG2)
+ 
+ $(PROG): $(OBJS)
+ 	$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2)
+ 
++$(PROG2): $(OBJS2)
++	$(CXX) -o $(PROG2) $(LDFLAGS) $(OBJS2) $(LIB)
++
++lzmp.o: lzmp.cpp
++	$(CXX) $(CFLAGS) lzmp.cpp
++
+ LzmaAlone.o: LzmaAlone.cpp
+ 	$(CXX) $(CFLAGS) LzmaAlone.cpp
+ 
+@@ -131,5 +153,5 @@
+ 	$(CXX_C) $(CFLAGS) ../../../../C/LzmaUtil/Lzma86Enc.c
+ 
+ clean:
+-	-$(RM) $(PROG) $(OBJS)
++	-$(RM) $(PROG) $(PROG2) $(OBJS)
+ 
+Index: lzma-4.65/CPP/7zip/Compress/LZMA_Alone/lzma_version.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ lzma-4.65/CPP/7zip/Compress/LZMA_Alone/lzma_version.h	2009-06-01 22:01:10.000000000 +0200
+@@ -0,0 +1,31 @@
++#ifndef LZMA_VERSION_H
++#define LZMA_VERSION_H
++
++/*
++    Version and copyright information used by LZMA utils.
++*/
++
++static const char *LZMA_SDK_VERSION_STRING = "4.43";
++
++static const char *LZMA_SDK_COPYRIGHT_STRING =
++		"Copyright (C) 1999-2006 Igor Pavlov";
++
++static const char *LZMA_SDK_COPYRIGHT_INFO =
++		"  See http://7-zip.org/sdk.html or the documentation of LZMA SDK for\n"
++		"  the license. For reference, the version 4.43 is free software\n"
++		"  licensed under the GNU LGPL.";
++
++
++static const char *LZMA_UTILS_VERSION_STRING = PACKAGE_VERSION;
++
++static const char *LZMA_UTILS_COPYRIGHT_STRING =
++		"Copyright (C) 2006 Lasse Collin";
++
++static const char *LZMA_UTILS_COPYRIGHT_INFO =
++		"This program comes with ABSOLUTELY NO WARRANTY.\n"
++		"You may redistribute copies of this program\n"
++		"under the terms of the GNU General Public License.\n"
++		"For more information about these matters, see the file "
++		"named COPYING.\n";
++
++#endif /* ifndef LZMA_VERSION_H */
+Index: lzma-4.65/CPP/Common/C_FileIO.h
+===================================================================
+--- lzma-4.65.orig/CPP/Common/C_FileIO.h	2009-05-15 23:33:51.000000000 +0200
++++ lzma-4.65/CPP/Common/C_FileIO.h	2009-06-01 22:06:56.000000000 +0200
+@@ -24,6 +24,7 @@
+   bool Close();
+   bool GetLength(UInt64 &length) const;
+   off_t Seek(off_t distanceToMove, int moveMethod) const;
++  int GetHandle() const { return _handle; }
+ };
+ 
+ class CInFile: public CFileBase
diff --git a/tools/lzma/patches/003-compile_fixes.patch b/tools/lzma/patches/003-compile_fixes.patch
new file mode 100644
index 0000000000..49ae66b9c4
--- /dev/null
+++ b/tools/lzma/patches/003-compile_fixes.patch
@@ -0,0 +1,26 @@
+diff -urN lzma-4.65/CPP/7zip/Common/FileStreams.h lzma-4.65.new/CPP/7zip/Common/FileStreams.h
+--- lzma-4.65/CPP/7zip/Common/FileStreams.h	2009-05-15 23:33:51.000000000 +0200
++++ lzma-4.65.new/CPP/7zip/Common/FileStreams.h	2009-06-01 22:30:01.000000000 +0200
+@@ -72,6 +72,7 @@
+   public IOutStream,
+   public CMyUnknownImp
+ {
++public:
+   #ifdef USE_WIN_FILE
+   NWindows::NFile::NIO::COutFile File;
+   #else
+diff -urN lzma-4.65/CPP/Common/MyWindows.h lzma-4.65.new/CPP/Common/MyWindows.h
+--- lzma-4.65/CPP/Common/MyWindows.h	2009-05-15 23:33:51.000000000 +0200
++++ lzma-4.65.new/CPP/Common/MyWindows.h	2009-06-01 22:29:26.000000000 +0200
+@@ -101,8 +101,11 @@
+ 
+ #ifdef __cplusplus
+ 
++#ifndef INITGUID
++#define INITGUID
+ DEFINE_GUID(IID_IUnknown,
+ 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
++#endif
+ struct IUnknown
+ {
+   STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;
diff --git a/tools/lzma/patches/100-static_library.patch b/tools/lzma/patches/100-static_library.patch
new file mode 100644
index 0000000000..15ab4e0552
--- /dev/null
+++ b/tools/lzma/patches/100-static_library.patch
@@ -0,0 +1,70 @@
+--- a/C/LzmaUtil/makefile.gcc
++++ b/C/LzmaUtil/makefile.gcc
+@@ -1,44 +1,53 @@
+ PROG = lzma
+-CXX = g++
+-LIB =
++CC = gcc
++LIB = liblzma.a
+ RM = rm -f
+ CFLAGS = -c -O2 -Wall
++AR = ar
++RANLIB = ranlib
+ 
+ OBJS = \
+-  LzmaUtil.o \
+   Alloc.o \
+   LzFind.o \
+   LzmaDec.o \
+   LzmaEnc.o \
++  LzmaLib.o \
+   7zFile.o \
+   7zStream.o \
+ 
+-
+ all: $(PROG)
+ 
+-$(PROG): $(OBJS)
+-	$(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2)
++$(PROG): LzmaUtil.o $(LIB)
++	$(CC) -o $(PROG) $(LDFLAGS) $< $(LIB)
+ 
+ LzmaUtil.o: LzmaUtil.c
+-	$(CXX) $(CFLAGS) LzmaUtil.c
++	$(CC) $(CFLAGS) LzmaUtil.c
++
++$(LIB): $(OBJS)
++	rm -f $@
++	$(AR) rcu $@ $(OBJS)
++	$(RANLIB) $@
+ 
+ Alloc.o: ../Alloc.c
+-	$(CXX) $(CFLAGS) ../Alloc.c
++	$(CC) $(CFLAGS) ../Alloc.c
+ 
+ LzFind.o: ../LzFind.c
+-	$(CXX) $(CFLAGS) ../LzFind.c
++	$(CC) $(CFLAGS) ../LzFind.c
+ 
+ LzmaDec.o: ../LzmaDec.c
+-	$(CXX) $(CFLAGS) ../LzmaDec.c
++	$(CC) $(CFLAGS) ../LzmaDec.c
+ 
+ LzmaEnc.o: ../LzmaEnc.c
+-	$(CXX) $(CFLAGS) ../LzmaEnc.c
++	$(CC) $(CFLAGS) ../LzmaEnc.c
++
++LzmaLib.o: ../LzmaLib.c
++	$(CC) $(CFLAGS) ../LzmaLib.c
+ 
+ 7zFile.o: ../7zFile.c
+-	$(CXX) $(CFLAGS) ../7zFile.c
++	$(CC) $(CFLAGS) ../7zFile.c
+ 
+ 7zStream.o: ../7zStream.c
+-	$(CXX) $(CFLAGS) ../7zStream.c
++	$(CC) $(CFLAGS) ../7zStream.c
+ 
+ clean:
+-	-$(RM) $(PROG) $(OBJS)
++	-$(RM) $(PROG) *.o *.a
diff --git a/tools/lzma/patches/101-move-copyright-to-usage-info.patch b/tools/lzma/patches/101-move-copyright-to-usage-info.patch
new file mode 100644
index 0000000000..ec69285d8e
--- /dev/null
+++ b/tools/lzma/patches/101-move-copyright-to-usage-info.patch
@@ -0,0 +1,20 @@
+--- a/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp
++++ b/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp
+@@ -101,6 +101,8 @@ static const int kNumSwitches = sizeof(k
+ 
+ static void PrintHelp()
+ {
++  fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
++
+   fprintf(stderr, "\nUsage:  LZMA <e|d> inputFile outputFile [<switches>...]\n"
+              "  e: encode file\n"
+              "  d: decode file\n"
+@@ -168,8 +170,6 @@ int main2(int n, const char *args[])
+   g_IsNT = IsItWindowsNT();
+   #endif
+ 
+-  fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
+-
+   if (n == 1)
+   {
+     PrintHelp();
diff --git a/tools/m4/Makefile b/tools/m4/Makefile
new file mode 100644
index 0000000000..47c332123b
--- /dev/null
+++ b/tools/m4/Makefile
@@ -0,0 +1,28 @@
+# 
+# Copyright (C) 2008-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=m4
+PKG_VERSION:=1.4.17
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=12a3c829301a4fd6586a57d3fcf196dc
+PKG_CAT:=xzcat
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_VARS += gl_cv_func_strstr_linear=no
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/m4/patches/100-fix-gets-removal.patch b/tools/m4/patches/100-fix-gets-removal.patch
new file mode 100644
index 0000000000..ecd110d934
--- /dev/null
+++ b/tools/m4/patches/100-fix-gets-removal.patch
@@ -0,0 +1,17 @@
+--- a/lib/stdio.in.h
++++ b/lib/stdio.in.h
+@@ -714,14 +714,6 @@ _GL_WARN_ON_USE (getline, "getline is un
+ # endif
+ #endif
+ 
+-/* It is very rare that the developer ever has full control of stdin,
+-   so any use of gets warrants an unconditional warning; besides, C11
+-   removed it.  */
+-#undef gets
+-#if HAVE_RAW_DECL_GETS
+-_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+-#endif
+-
+ 
+ #if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
+ struct obstack;
diff --git a/tools/make-ext4fs/Makefile b/tools/make-ext4fs/Makefile
new file mode 100644
index 0000000000..20cf6cfb60
--- /dev/null
+++ b/tools/make-ext4fs/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+# Copyright (C) 2016 LEDE project
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=make-ext4fs
+PKG_VERSION:=2016-08-14
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL=$(LEDE_GIT)/project/make_ext4fs.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=484903e4332be6c317f531b008cb2a841a18c506
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_MIRROR_MD5SUM:=5a4473e58dcaed1f41c2391d2326a67af356ca9a3a075fc3486d95276fb9a400
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+ifeq ($(HOST_OS),Linux)
+ MAKE_STATIC := STATIC=1
+endif
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) make_ext4fs $(MAKE_STATIC)
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/make_ext4fs $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/make_ext4fs
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/missing-macros/Makefile b/tools/missing-macros/Makefile
new file mode 100644
index 0000000000..e4b69b3875
--- /dev/null
+++ b/tools/missing-macros/Makefile
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2010-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=missing-macros
+PKG_VERSION:=10
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Configure
+endef
+
+define Host/Compile
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/share/aclocal
+	$(INSTALL_DATA) ./src/m4/*.m4 $(STAGING_DIR_HOST)/share/aclocal/
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) ./src/bin/* $(STAGING_DIR_HOST)/bin/
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/missing-macros/src/README b/tools/missing-macros/src/README
new file mode 100644
index 0000000000..d2305ff557
--- /dev/null
+++ b/tools/missing-macros/src/README
@@ -0,0 +1,100 @@
+The m4/ directory below contains various m4 macros used
+by different packages in the OpenWrt feed.
+
+
+From GNU gettext:
+Library linking and rpath helper macros.
+
+  lib-ld.m4
+  lib-link.m4
+  lib-prefix.m4
+
+Integer data type test macros.
+
+  intmax.m4
+  wint_t.m4
+  inttypes-pri.m4
+  uintmax_t.m4
+  stdint_h.m4
+  intdiv0.m4
+  inttypes_h.m4
+
+Program test macro.
+
+  progtest.m4
+
+GNU libc version test macros.
+
+  glibc2.m4
+  glibc21.m4
+
+
+From UCL and LZO:
+Compiler ACC conformance testing macros.
+
+  mfx_acc.m4
+  mfx_cppflags.m4
+  mfx_limits.m4
+
+
+From OSSP-JS:
+Test macros for va_copy() implementations.
+
+  va_copy.m4
+
+
+From libmikmod:
+Feature test macros for the Enlightment Sound Daemon.
+
+  esd.m4
+
+
+From libdnet:
+Feature test macros for socket api implementations.
+
+  dnet.m4
+
+
+From FLAC:
+XMMS feature detection macros.
+
+  xmms.m4
+
+
+From ao:
+Directory expansion macro for Automake.
+
+  as-ac-expand.m4
+
+
+From tinyproxy:
+Autostars m4 macro for detection of compiler flags.
+
+  as-compiler-flags.m4
+
+
+From morituri:
+Autostars m4 macro for versioning.
+
+  as-version.m4
+
+
+From liboil:
+Check if unaligned memory access works correctly.
+
+  as-unaligned-access.m4
+
+
+From OpenWrt:
+Always disable GTK docs.
+
+  fake-gtk-doc-check.m4
+
+Provide intltool.m4 stubs to allow for autoreconf.
+
+  fake-intltool.m4
+
+From XDM:
+XAW macros.
+
+  xaw.m4
diff --git a/tools/missing-macros/src/bin/help2man b/tools/missing-macros/src/bin/help2man
new file mode 100755
index 0000000000..6cbec57c50
--- /dev/null
+++ b/tools/missing-macros/src/bin/help2man
@@ -0,0 +1,29 @@
+#!/usr/bin/env perl
+
+use strict;
+use Getopt::Long;
+
+my $output;
+my $version;
+
+Getopt::Long::Configure('pass_through');
+Getopt::Long::GetOptions(
+	'output=s' => \$output,
+	'version'  => \$version
+);
+
+if ($version)
+{
+	printf "OpenWrt help2man 1.40.10\n";
+	exit 0;
+}
+elsif ($output)
+{
+	open O, "> $output" || die "Unable to open $output: $!\n";
+	print O "Dummy man page.\n";
+	close O;
+}
+else
+{
+	print O "Dummy man page.\n";
+}
diff --git a/tools/missing-macros/src/bin/makeinfo b/tools/missing-macros/src/bin/makeinfo
new file mode 100755
index 0000000000..e163cba084
--- /dev/null
+++ b/tools/missing-macros/src/bin/makeinfo
@@ -0,0 +1,112 @@
+#!/usr/bin/env perl
+
+use strict;
+use Getopt::Long;
+
+my $output;
+my $version;
+my $docbook;
+my $html;
+my $xml;
+my $plaintext;
+my $no_split;
+my $no_headers;
+
+Getopt::Long::Configure('pass_through');
+Getopt::Long::GetOptions(
+	'output=s'   => \$output,
+	'version'    => \$version,
+	'no-split'   => \$no_split,
+	'no-headers' => \$no_headers,
+	'docbook'    => \$docbook,
+	'html'       => \$html,
+	'xml'        => \$xml,
+	'plaintext'  => \$plaintext
+);
+
+if ($version)
+{
+	print "makeinfo (OpenWrt stub) 4.13\n";
+	exit 0;
+}
+
+
+sub output_filename
+{
+	my $path = shift || return;
+	my $name = $path;
+	my $setfile;
+
+	if (open F, "< $path")
+	{
+		while (defined(my $line = readline F))
+		{
+			if ($line =~ /\@setfilename\s+(\S+)/)
+			{
+				$setfile = $1;
+				$setfile =~ s!^.+/!!;
+				last;
+			}
+		}
+
+		close F;
+	}
+
+	$name =~ s!^.+/!!;
+	$name =~ s!\.[^.]+$!!;
+
+	if ($html)
+	{
+		$setfile =~ s!\.[^.]+$!! if $setfile;
+
+		if ($no_split)
+		{
+			return $setfile ? "$setfile.html" : "$name.html" unless $output;
+			return $output;
+		}
+
+		return $setfile ? "$setfile/index.html" : "$name/index.html" unless $output;
+		return "$output/index.html";
+	}
+	elsif ($xml || $docbook)
+	{
+		$setfile =~ s!\.[^.]+$!! if $setfile;
+
+		return $setfile ? "$setfile.xml" : "$name.info" unless $output;
+		return $output;
+	}
+	elsif ($plaintext)
+	{
+		return ($output || "-");	
+	}
+
+	return ($output || $setfile || "$name.info");
+}
+
+foreach my $arg (@ARGV)
+{
+	next unless -f $arg;
+
+	my $out = output_filename($arg);
+	if ($out =~ m!^(.+/)[^/]+$!)
+	{
+		system("mkdir", "-p", $1);
+	}
+
+	my $fd = \*STDOUT;
+	if ($out ne "-" && !$no_headers)
+	{
+		open $fd, "> $out" || die "Can't open $out: $!\n";
+	}
+
+	if ($html || $xml || $docbook)
+	{
+		print $fd "<!-- Dummy output for $arg -->\n";
+	}
+	else
+	{
+		print $fd "Dummy output for $arg\n";	
+	}
+
+	close $fd;
+}
diff --git a/tools/missing-macros/src/m4/as-ac-expand.m4 b/tools/missing-macros/src/m4/as-ac-expand.m4
new file mode 100644
index 0000000000..d6c9e33060
--- /dev/null
+++ b/tools/missing-macros/src/m4/as-ac-expand.m4
@@ -0,0 +1,43 @@
+dnl as-ac-expand.m4 0.2.0
+dnl autostars m4 macro for expanding directories using configure's prefix
+dnl thomas@apestaart.org
+
+dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
+dnl example
+dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
+
+AC_DEFUN([AS_AC_EXPAND],
+[
+  EXP_VAR=[$1]
+  FROM_VAR=[$2]
+
+  dnl first expand prefix and exec_prefix if necessary
+  prefix_save=$prefix
+  exec_prefix_save=$exec_prefix
+
+  dnl if no prefix given, then use /usr/local, the default prefix
+  if test "x$prefix" = "xNONE"; then
+    prefix="$ac_default_prefix"
+  fi
+  dnl if no exec_prefix given, then use prefix
+  if test "x$exec_prefix" = "xNONE"; then
+    exec_prefix=$prefix
+  fi
+
+  full_var="$FROM_VAR"
+  dnl loop until it doesn't change anymore
+  while true; do
+    new_full_var="`eval echo $full_var`"
+    if test "x$new_full_var" = "x$full_var"; then break; fi
+    full_var=$new_full_var
+  done
+
+  dnl clean up
+  full_var=$new_full_var
+  AC_SUBST([$1], "$full_var")
+
+  dnl restore prefix and exec_prefix
+  prefix=$prefix_save
+  exec_prefix=$exec_prefix_save
+])
diff --git a/tools/missing-macros/src/m4/as-compiler-flag.m4 b/tools/missing-macros/src/m4/as-compiler-flag.m4
new file mode 100644
index 0000000000..0f660cf079
--- /dev/null
+++ b/tools/missing-macros/src/m4/as-compiler-flag.m4
@@ -0,0 +1,62 @@
+dnl as-compiler-flag.m4 0.1.0
+
+dnl autostars m4 macro for detection of compiler flags
+
+dnl David Schleef <ds@schleef.org>
+
+dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $
+
+dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
+dnl Tries to compile with the given CFLAGS.
+dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
+dnl and ACTION-IF-NOT-ACCEPTED otherwise.
+
+AC_DEFUN([AS_COMPILER_FLAG],
+[
+  AC_MSG_CHECKING([to see if compiler understands $1])
+
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $1"
+
+  AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+  CFLAGS="$save_CFLAGS"
+
+  if test "X$flag_ok" = Xyes ; then
+    m4_ifvaln([$2],[$2])
+    true
+  else
+    m4_ifvaln([$3],[$3])
+    true
+  fi
+  AC_MSG_RESULT([$flag_ok])
+])
+
+dnl AS_COMPILER_FLAGS(VAR, FLAGS)
+dnl Tries to compile with the given CFLAGS.
+
+AC_DEFUN([AS_COMPILER_FLAGS],
+[
+  list=$2
+  flags_supported=""
+  flags_unsupported=""
+  AC_MSG_CHECKING([for supported compiler flags])
+  for each in $list
+  do
+    save_CFLAGS="$CFLAGS"
+    CFLAGS="$CFLAGS $each"
+    AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+    CFLAGS="$save_CFLAGS"
+
+    if test "X$flag_ok" = Xyes ; then
+      flags_supported="$flags_supported $each"
+    else
+      flags_unsupported="$flags_unsupported $each"
+    fi
+  done
+  AC_MSG_RESULT([$flags_supported])
+  if test "X$flags_unsupported" != X ; then
+    AC_MSG_WARN([unsupported compiler flags: $flags_unsupported])
+  fi
+  $1="$$1 $flags_supported"
+])
+
diff --git a/tools/missing-macros/src/m4/as-unaligned-access.m4 b/tools/missing-macros/src/m4/as-unaligned-access.m4
new file mode 100644
index 0000000000..ede8bd2a95
--- /dev/null
+++ b/tools/missing-macros/src/m4/as-unaligned-access.m4
@@ -0,0 +1,41 @@
+dnl AS_UNALIGNED_ACCESS
+
+dnl check if unaligned memory access works correctly
+AC_DEFUN([AS_UNALIGNED_ACCESS], [
+  AC_MSG_CHECKING([if unaligned memory access works correctly])
+  if test x"$as_cv_unaligned_access" = x ; then
+    case $host in
+      alpha*|arm*|hp*|mips*|sh*|sparc*|ia64*)
+        _AS_ECHO_N([(blacklisted) ])
+        as_cv_unaligned_access=no
+	;;
+      i?86*|x86_64|amd64|powerpc*|m68k*|cris*)
+        _AS_ECHO_N([(whitelisted) ])
+        as_cv_unaligned_access=yes
+	;;
+    esac
+  else
+    _AS_ECHO_N([(cached) ])
+  fi
+  if test x"$as_cv_unaligned_access" = x ; then
+    AC_TRY_RUN([
+int main(int argc, char **argv)
+{
+  char array[] = "ABCDEFGH";
+  unsigned int iarray[2];
+  memcpy(iarray,array,8);
+#define GET(x) (*(unsigned int *)((char *)iarray + (x)))
+  if(GET(0) != 0x41424344 && GET(0) != 0x44434241) return 1;
+  if(GET(1) != 0x42434445 && GET(1) != 0x45444342) return 1;
+  if(GET(2) != 0x43444546 && GET(2) != 0x46454443) return 1;
+  if(GET(3) != 0x44454647 && GET(3) != 0x47464544) return 1;
+  return 0;
+}
+    ], as_cv_unaligned_access="yes", as_cv_unaligned_access="no")
+  fi
+  AC_MSG_RESULT($as_cv_unaligned_access)
+  if test "$as_cv_unaligned_access" = "yes"; then
+    AC_DEFINE_UNQUOTED(HAVE_UNALIGNED_ACCESS, 1,
+      [defined if unaligned memory access works correctly])
+  fi
+])
diff --git a/tools/missing-macros/src/m4/as-version.m4 b/tools/missing-macros/src/m4/as-version.m4
new file mode 100644
index 0000000000..a5b439903e
--- /dev/null
+++ b/tools/missing-macros/src/m4/as-version.m4
@@ -0,0 +1,71 @@
+dnl as-version.m4 0.2.0
+
+dnl autostars m4 macro for versioning
+
+dnl Thomas Vander Stichele <thomas at apestaart dot org>
+
+dnl $Id: as-version.m4,v 1.4 2004/06/01 09:40:05 thomasvs Exp $
+
+dnl AS_VERSION
+
+dnl example
+dnl AS_VERSION
+
+dnl this macro
+dnl - AC_SUBST's PACKAGE_VERSION_MAJOR, _MINOR, _MICRO
+dnl - AC_SUBST's PACKAGE_VERSION_RELEASE,
+dnl    which can be used for rpm release fields
+dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents
+dnl   maintainer mode from running correctly
+dnl
+dnl don't forget to put #undef PACKAGE_VERSION_RELEASE in acconfig.h
+dnl if you use acconfig.h
+
+AC_DEFUN([AS_VERSION],
+[
+  PACKAGE_VERSION_MAJOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f1)
+  PACKAGE_VERSION_MINOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f2)
+  PACKAGE_VERSION_MICRO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f3)
+
+  AC_SUBST(PACKAGE_VERSION_MAJOR)
+  AC_SUBST(PACKAGE_VERSION_MINOR)
+  AC_SUBST(PACKAGE_VERSION_MICRO)
+])
+
+dnl AS_NANO(ACTION-IF-NO-NANO, [ACTION-IF-NANO])
+
+dnl requires AC_INIT to be called before
+dnl For projects using a fourth or nano number in your versioning to indicate
+dnl development or prerelease snapshots, this macro allows the build to be
+dnl set up differently accordingly.
+
+dnl this macro:
+dnl - parses AC_PACKAGE_VERSION, set by AC_INIT, and extracts the nano number
+dnl - sets the variable PACKAGE_VERSION_NANO
+dnl - sets the variable PACKAGE_VERSION_RELEASE, which can be used
+dnl   for rpm release fields
+dnl - executes ACTION-IF-NO-NANO or ACTION-IF-NANO
+    
+dnl example:
+dnl AS_NANO(RELEASE="yes", RELEASE="no")
+
+AC_DEFUN([AS_NANO],
+[
+  AC_MSG_CHECKING(nano version)
+
+  NANO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f4)
+
+  if test x"$NANO" = x || test "x$NANO" = "x0" ; then
+    AC_MSG_RESULT([0 (release)])
+    NANO=0
+    PACKAGE_VERSION_RELEASE=1
+    ifelse([$1], , :, [$1])
+  else
+    AC_MSG_RESULT($NANO)
+    PACKAGE_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S`
+    ifelse([$2], , :, [$2])
+  fi
+  PACKAGE_VERSION_NANO=$NANO
+  AC_SUBST(PACKAGE_VERSION_NANO)
+  AC_SUBST(PACKAGE_VERSION_RELEASE)
+])
diff --git a/tools/missing-macros/src/m4/dnet.m4 b/tools/missing-macros/src/m4/dnet.m4
new file mode 100644
index 0000000000..b57ead2c87
--- /dev/null
+++ b/tools/missing-macros/src/m4/dnet.m4
@@ -0,0 +1,322 @@
+# dnet.m4 serial 1 (libdnet-1.11)
+
+dnl
+dnl Check for 4.4 BSD sa_len member in sockaddr struct
+dnl
+dnl usage:	AC_DNET_SOCKADDR_SA_LEN
+dnl results:	HAVE_SOCKADDR_SA_LEN (defined)
+dnl
+AC_DEFUN([AC_DNET_SOCKADDR_SA_LEN],
+    [AC_MSG_CHECKING(for sa_len in sockaddr struct)
+    AC_CACHE_VAL(ac_cv_dnet_sockaddr_has_sa_len,
+        AC_TRY_COMPILE([
+# ifndef _SOCKADDR_LEN
+#	define _SOCKADDR_LEN 1 
+# endif
+#       include <sys/types.h>
+#       include <sys/socket.h>],
+        [u_int i = sizeof(((struct sockaddr *)0)->sa_len)],
+        ac_cv_dnet_sockaddr_has_sa_len=yes,
+        ac_cv_dnet_sockaddr_has_sa_len=no))
+    AC_MSG_RESULT($ac_cv_dnet_sockaddr_has_sa_len)
+    if test $ac_cv_dnet_sockaddr_has_sa_len = yes ; then
+            AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1,
+                      [Define if sockaddr struct has sa_len.])
+    fi])
+
+dnl
+dnl Check for sockaddr_in6 struct in <netinet/in.h>
+dnl
+dnl usage:	AC_DNET_SOCKADDR_IN6
+dnl results:	HAVE_SOCKADDR_IN6
+dnl
+AC_DEFUN([AC_DNET_SOCKADDR_IN6],
+    [AC_MSG_CHECKING(for sockaddr_in6 struct in <netinet/in.h>)
+    AC_CACHE_VAL(ac_cv_dnet_netinet_in_h_has_sockaddr_in6,
+        AC_TRY_COMPILE([
+#       include <sys/types.h>
+#	include <sys/socket.h>
+#       include <netinet/in.h>],
+        [struct sockaddr_in6 sin6; sin6.sin6_family = AF_INET6;],
+	ac_cv_dnet_netinet_in_h_has_sockaddr_in6=yes,
+	ac_cv_dnet_netinet_in_h_has_sockaddr_in6=no))
+    AC_MSG_RESULT($ac_cv_dnet_netinet_in_h_has_sockaddr_in6)
+    if test $ac_cv_dnet_netinet_in_h_has_sockaddr_in6 = yes ; then
+        AC_DEFINE(HAVE_SOCKADDR_IN6, 1,
+	          [Define if <netinet/in.h> has sockaddr_in6 struct.])
+    fi])
+
+dnl
+dnl Check for arp_dev member in arpreq struct
+dnl
+dnl usage:	AC_DNET_ARPREQ_ARP_DEV
+dnl results:	HAVE_ARPREQ_ARP_DEV (defined)
+dnl
+AC_DEFUN([AC_DNET_ARPREQ_ARP_DEV],
+    [AC_MSG_CHECKING(for arp_dev in arpreq struct)
+    AC_CACHE_VAL(ac_cv_dnet_arpreq_has_arp_dev,
+	AC_TRY_COMPILE([
+#       include <sys/types.h>
+#	include <sys/socket.h>
+#	include <net/if_arp.h>],
+	[void *p = ((struct arpreq *)0)->arp_dev],
+	ac_cv_dnet_arpreq_has_arp_dev=yes,
+	ac_cv_dnet_arpreq_has_arp_dev=no))
+    AC_MSG_RESULT($ac_cv_dnet_arpreq_has_arp_dev)
+    if test $ac_cv_dnet_arpreq_has_arp_dev = yes ; then
+	AC_DEFINE(HAVE_ARPREQ_ARP_DEV, 1,
+		[Define if arpreq struct has arp_dev.])
+    fi])
+
+dnl
+dnl Check for rt_msghdr struct in <net/route.h>
+dnl
+dnl usage:	AC_DNET_ROUTE_RT_MSGHDR
+dnl results:	HAVE_ROUTE_RT_MSGHDR
+dnl
+AC_DEFUN([AC_DNET_ROUTE_RT_MSGHDR],
+    [AC_MSG_CHECKING(for rt_msghdr struct in <net/route.h>)
+    AC_CACHE_VAL(ac_cv_dnet_route_h_has_rt_msghdr,
+        AC_TRY_COMPILE([
+#       include <sys/types.h>
+#       include <sys/socket.h>
+#       include <net/if.h>
+#       include <net/route.h>],
+        [struct rt_msghdr rtm; rtm.rtm_msglen = 0;],
+	ac_cv_dnet_route_h_has_rt_msghdr=yes,
+	ac_cv_dnet_route_h_has_rt_msghdr=no))
+    AC_MSG_RESULT($ac_cv_dnet_route_h_has_rt_msghdr)
+    if test $ac_cv_dnet_route_h_has_rt_msghdr = yes ; then
+        AC_DEFINE(HAVE_ROUTE_RT_MSGHDR, 1,
+	          [Define if <net/route.h> has rt_msghdr struct.])
+    fi])
+
+dnl
+dnl Check for the Berkeley Packet Filter
+dnl
+dnl usage:	AC_DNET_BSD_BPF
+dnl results:	HAVE_BSD_BPF
+dnl
+AC_DEFUN([AC_DNET_BSD_BPF],
+    [AC_MSG_CHECKING(for Berkeley Packet Filter)
+    AC_CACHE_VAL(ac_cv_dnet_bsd_bpf,
+	if test -c /dev/bpf0 ; then
+	    ac_cv_dnet_bsd_bpf=yes
+	else
+	    ac_cv_dnet_bsd_bpf=no
+	fi)
+    AC_MSG_RESULT($ac_cv_dnet_bsd_bpf)
+    if test $ac_cv_dnet_bsd_bpf = yes ; then
+	AC_DEFINE(HAVE_BSD_BPF, 1,
+		  [Define if you have the Berkeley Packet Filter.])
+    fi])
+
+dnl
+dnl Check for the Linux /proc filesystem
+dnl
+dnl usage:	AC_DNET_LINUX_PROCFS
+dnl results:	HAVE_LINUX_PROCFS
+dnl
+AC_DEFUN([AC_DNET_LINUX_PROCFS],
+    [AC_MSG_CHECKING(for Linux proc filesystem)
+    AC_CACHE_VAL(ac_cv_dnet_linux_procfs,
+	if test "x`cat /proc/sys/kernel/ostype 2>&-`" = "xLinux" ; then
+	    ac_cv_dnet_linux_procfs=yes
+        else
+	    ac_cv_dnet_linux_procfs=no
+	fi)
+    AC_MSG_RESULT($ac_cv_dnet_linux_procfs)
+    if test $ac_cv_dnet_linux_procfs = yes ; then
+	AC_DEFINE(HAVE_LINUX_PROCFS, 1,
+		  [Define if you have the Linux /proc filesystem.])
+    fi])
+
+dnl
+dnl Check for Linux PF_PACKET sockets
+dnl
+dnl usage:	AC_DNET_LINUX_PF_PACKET
+dnl results:	HAVE_LINUX_PF_PACKET
+dnl
+AC_DEFUN([AC_DNET_LINUX_PF_PACKET],
+    [AC_MSG_CHECKING(for Linux PF_PACKET sockets)
+    AC_CACHE_VAL(ac_cv_dnet_linux_pf_packet,
+	if test -f /usr/include/netpacket/packet.h ; then
+	    ac_cv_dnet_linux_pf_packet=yes
+	else
+	    ac_cv_dnet_linux_pf_packet=no
+	fi)
+    AC_MSG_RESULT($ac_cv_dnet_linux_pf_packet)
+    if test $ac_cv_dnet_linux_pf_packet = yes ; then
+	AC_DEFINE(HAVE_LINUX_PF_PACKET, 1,
+		  [Define if you have Linux PF_PACKET sockets.])
+    fi])
+
+dnl
+dnl Check for SNMP MIB2 STREAMS (Solaris only?)
+dnl
+dnl usage:      AC_DNET_STREAMS_MIB2
+dnl results:    HAVE_STREAMS_MIB2
+dnl
+AC_DEFUN([AC_DNET_STREAMS_MIB2],
+    [AC_MSG_CHECKING(for SNMP MIB2 STREAMS)
+    AC_CACHE_VAL(ac_cv_dnet_streams_mib2,
+        if test -f /usr/include/inet/mib2.h -a -c /dev/ip ; then
+            ac_cv_dnet_streams_mib2=yes
+        else
+            ac_cv_dnet_streams_mib2=no
+        fi)
+    AC_MSG_RESULT($ac_cv_dnet_streams_mib2)
+    if test $ac_cv_dnet_streams_mib2 = yes ; then
+        AC_DEFINE(HAVE_STREAMS_MIB2, 1,
+                  [Define if you have SNMP MIB2 STREAMS.])
+    fi])
+
+dnl
+dnl Check for route(7) STREAMS (UnixWare only?)
+dnl
+dnl usage:      AC_DNET_STREAMS_ROUTE
+dnl results:    HAVE_STREAMS_ROUTE
+dnl
+AC_DEFUN([AC_DNET_STREAMS_ROUTE],
+    [AC_MSG_CHECKING(for route(7) STREAMS)
+    AC_CACHE_VAL(ac_cv_dnet_streams_route,
+        if grep RTSTR_SEND /usr/include/net/route.h >/dev/null 2>&1 ; then
+            ac_cv_dnet_streams_route=yes
+        else
+            ac_cv_dnet_streams_route=no
+        fi)
+    AC_MSG_RESULT($ac_cv_dnet_streams_route)
+    if test $ac_cv_dnet_streams_route = yes ; then
+        AC_DEFINE(HAVE_STREAMS_ROUTE, 1,
+                  [Define if you have route(7) STREAMS.])
+    fi])
+
+dnl
+dnl Check for arp(7) ioctls
+dnl
+dnl usage:      AC_DNET_IOCTL_ARP
+dnl results:    HAVE_IOCTL_ARP
+dnl
+AC_DEFUN([AC_DNET_IOCTL_ARP],
+    [AC_MSG_CHECKING(for arp(7) ioctls)
+    AC_CACHE_VAL(ac_cv_dnet_ioctl_arp,
+	AC_EGREP_CPP(werd, [
+#	include <sys/types.h>
+#	define BSD_COMP
+#	include <sys/ioctl.h>
+#	ifdef SIOCGARP
+	werd
+#	endif],
+	ac_cv_dnet_ioctl_arp=yes,
+	ac_cv_dnet_ioctl_arp=no))
+    case "$host_os" in
+    irix*)
+        ac_cv_dnet_ioctl_arp=no ;;
+    esac
+    AC_MSG_RESULT($ac_cv_dnet_ioctl_arp)
+    if test $ac_cv_dnet_ioctl_arp = yes ; then
+        AC_DEFINE(HAVE_IOCTL_ARP, 1,
+                  [Define if you have arp(7) ioctls.])
+    fi])
+
+dnl
+dnl Check for raw IP sockets ip_{len,off} host byte ordering
+dnl
+dnl usage:      AC_DNET_RAWIP_HOST_OFFLEN
+dnl results:    HAVE_RAWIP_HOST_OFFLEN
+dnl
+AC_DEFUN([AC_DNET_RAWIP_HOST_OFFLEN],
+    [AC_MSG_CHECKING([for raw IP sockets ip_{len,off} host byte ordering])
+    AC_CACHE_VAL(ac_cv_dnet_rawip_host_offlen, [
+	case "$host_os" in
+	*openbsd*)
+	    ac_cv_dnet_rawip_host_offlen=no ;;
+	*bsd*|*osf*|*unixware*)
+	    ac_cv_dnet_rawip_host_offlen=yes ;;
+	*)
+	    ac_cv_dnet_rawip_host_offlen=no ;;
+	esac])
+    AC_MSG_RESULT($ac_cv_dnet_rawip_host_offlen)
+    if test $ac_cv_dnet_rawip_host_offlen = yes ; then
+        AC_DEFINE(HAVE_RAWIP_HOST_OFFLEN, 1,
+                  [Define if raw IP sockets require host byte ordering for ip_off, ip_len.])
+    fi])
+
+dnl
+dnl Check for cooked raw IP sockets
+dnl
+dnl usage:      AC_DNET_RAWIP_COOKED
+dnl results:    HAVE_RAWIP_COOKED
+dnl
+AC_DEFUN([AC_DNET_RAWIP_COOKED],
+    [AC_MSG_CHECKING(for cooked raw IP sockets)
+    AC_CACHE_VAL(ac_cv_dnet_rawip_cooked, [
+	case "$host_os" in
+	solaris*|irix*)
+	    ac_cv_dnet_rawip_cooked=yes ;;
+	*)
+	    ac_cv_dnet_rawip_cooked=no ;;
+	esac])
+    AC_MSG_RESULT($ac_cv_dnet_rawip_cooked)
+    if test $ac_cv_dnet_rawip_cooked = yes ; then
+        AC_DEFINE(HAVE_RAWIP_COOKED, 1,
+                  [Define if you have cooked raw IP sockets.])
+    fi])
+
+dnl
+dnl AC_LBL_LIBRARY_NET
+dnl
+dnl This test is for network applications that need socket() and
+dnl gethostbyname() -ish functions.  Under Solaris, those applications
+dnl need to link with "-lsocket -lnsl".  Under IRIX, they need to link
+dnl with "-lnsl" but should *not* link with "-lsocket" because
+dnl libsocket.a breaks a number of things (for instance:
+dnl gethostbyname() under IRIX 5.2, and snoop sockets under most
+dnl versions of IRIX).
+dnl
+dnl Unfortunately, many application developers are not aware of this,
+dnl and mistakenly write tests that cause -lsocket to be used under
+dnl IRIX.  It is also easy to write tests that cause -lnsl to be used
+dnl under operating systems where neither are necessary (or useful),
+dnl such as SunOS 4.1.4, which uses -lnsl for TLI.
+dnl
+dnl This test exists so that every application developer does not test
+dnl this in a different, and subtly broken fashion.
+
+dnl It has been argued that this test should be broken up into two
+dnl seperate tests, one for the resolver libraries, and one for the
+dnl libraries necessary for using Sockets API. Unfortunately, the two
+dnl are carefully intertwined and allowing the autoconf user to use
+dnl them independantly potentially results in unfortunate ordering
+dnl dependancies -- as such, such component macros would have to
+dnl carefully use indirection and be aware if the other components were
+dnl executed. Since other autoconf macros do not go to this trouble,
+dnl and almost no applications use sockets without the resolver, this
+dnl complexity has not been implemented.
+dnl
+dnl The check for libresolv is in case you are attempting to link
+dnl statically and happen to have a libresolv.a lying around (and no
+dnl libnsl.a).
+dnl
+AC_DEFUN([AC_LBL_LIBRARY_NET], [
+    # Most operating systems have gethostbyname() in the default searched
+    # libraries (i.e. libc):
+    AC_CHECK_FUNC(gethostbyname, ,
+        # Some OSes (eg. Solaris) place it in libnsl:
+        AC_CHECK_LIB(nsl, gethostbyname, , 
+            # Some strange OSes (SINIX) have it in libsocket:
+            AC_CHECK_LIB(socket, gethostbyname, ,
+                # Unfortunately libsocket sometimes depends on libnsl.
+                # AC_CHECK_LIB's API is essentially broken so the
+                # following ugliness is necessary:
+                AC_CHECK_LIB(socket, gethostbyname,
+                    LIBS="-lsocket -lnsl $LIBS",
+                    AC_CHECK_LIB(resolv, gethostbyname),
+                    -lnsl))))
+    AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+        AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", ,
+            -lnsl)))
+    # DLPI needs putmsg under HPUX so test for -lstr while we're at it
+    AC_CHECK_LIB(str, putmsg)
+    ])
+
diff --git a/tools/missing-macros/src/m4/fake-gtk-doc-check.m4 b/tools/missing-macros/src/m4/fake-gtk-doc-check.m4
new file mode 100644
index 0000000000..26fa7234f3
--- /dev/null
+++ b/tools/missing-macros/src/m4/fake-gtk-doc-check.m4
@@ -0,0 +1,13 @@
+dnl fake-gtk-doc-check.m4 serial 1 (OpenWrt)
+dnl Provide a fake GTK_DOC_CHECK macros which
+dnl always defines false.
+
+AC_DEFUN([GTK_DOC_CHECK],
+[
+	AM_CONDITIONAL([ENABLE_GTK_DOC], [false])
+	AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [false])
+	AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [false])
+	AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [false])
+	AM_CONDITIONAL([GTK_DOC_USE_REBASE], [false])
+	AC_PATH_PROGS([GTKDOC_REBASE],[true],[true])
+])
diff --git a/tools/missing-macros/src/m4/fake-intltool.m4 b/tools/missing-macros/src/m4/fake-intltool.m4
new file mode 100644
index 0000000000..352053c282
--- /dev/null
+++ b/tools/missing-macros/src/m4/fake-intltool.m4
@@ -0,0 +1,16 @@
+# stripped intltool.m4 to make automake happy
+# serial 1
+AC_DEFUN([IT_PROG_INTLTOOL],
+[
+	AC_SUBST(ALL_LINGUAS)
+	
+	DATADIRNAME=share
+	AC_SUBST(DATADIRNAME)
+])
+
+# deprecated macros
+AU_ALIAS([AC_PROG_INTLTOOL], [IT_PROG_INTLTOOL])
+
+# A hint is needed for aclocal from Automake <= 1.9.4:
+# AC_DEFUN([AC_PROG_INTLTOOL], ...)
+
diff --git a/tools/missing-macros/src/m4/glibc2.m4 b/tools/missing-macros/src/m4/glibc2.m4
new file mode 100644
index 0000000000..f148c12c45
--- /dev/null
+++ b/tools/missing-macros/src/m4/glibc2.m4
@@ -0,0 +1,30 @@
+# glibc2.m4 serial 2
+dnl Copyright (C) 2000-2002, 2004, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Test for the GNU C Library, version 2.0 or newer.
+# From Bruno Haible.
+
+AC_DEFUN([gt_GLIBC2],
+  [
+    AC_CACHE_CHECK([whether we are using the GNU C Library 2 or newer],
+      [ac_cv_gnu_library_2],
+      [AC_EGREP_CPP([Lucky GNU user],
+        [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ >= 2)
+  Lucky GNU user
+ #endif
+#endif
+        ],
+        [ac_cv_gnu_library_2=yes],
+        [ac_cv_gnu_library_2=no])
+      ]
+    )
+    AC_SUBST([GLIBC2])
+    GLIBC2="$ac_cv_gnu_library_2"
+  ]
+)
diff --git a/tools/missing-macros/src/m4/glibc21.m4 b/tools/missing-macros/src/m4/glibc21.m4
new file mode 100644
index 0000000000..68ada9d4d5
--- /dev/null
+++ b/tools/missing-macros/src/m4/glibc21.m4
@@ -0,0 +1,30 @@
+# glibc21.m4 serial 4
+dnl Copyright (C) 2000-2002, 2004, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Test for the GNU C Library, version 2.1 or newer.
+# From Bruno Haible.
+
+AC_DEFUN([gl_GLIBC21],
+  [
+    AC_CACHE_CHECK([whether we are using the GNU C Library 2.1 or newer],
+      [ac_cv_gnu_library_2_1],
+      [AC_EGREP_CPP([Lucky GNU user],
+        [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2)
+  Lucky GNU user
+ #endif
+#endif
+        ],
+        [ac_cv_gnu_library_2_1=yes],
+        [ac_cv_gnu_library_2_1=no])
+      ]
+    )
+    AC_SUBST([GLIBC21])
+    GLIBC21="$ac_cv_gnu_library_2_1"
+  ]
+)
diff --git a/tools/missing-macros/src/m4/intdiv0.m4 b/tools/missing-macros/src/m4/intdiv0.m4
new file mode 100644
index 0000000000..289c4df5ed
--- /dev/null
+++ b/tools/missing-macros/src/m4/intdiv0.m4
@@ -0,0 +1,84 @@
+# intdiv0.m4 serial 3 (gettext-0.18)
+dnl Copyright (C) 2002, 2007-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([gt_INTDIV0],
+[
+  AC_REQUIRE([AC_PROG_CC])dnl
+  AC_REQUIRE([AC_CANONICAL_HOST])dnl
+
+  AC_CACHE_CHECK([whether integer division by zero raises SIGFPE],
+    gt_cv_int_divbyzero_sigfpe,
+    [
+      gt_cv_int_divbyzero_sigfpe=
+changequote(,)dnl
+      case "$host_os" in
+        macos* | darwin[6-9]* | darwin[1-9][0-9]*)
+          # On MacOS X 10.2 or newer, just assume the same as when cross-
+          # compiling. If we were to perform the real test, 1 Crash Report
+          # dialog window would pop up.
+          case "$host_cpu" in
+            i[34567]86 | x86_64)
+              gt_cv_int_divbyzero_sigfpe="guessing yes" ;;
+          esac
+          ;;
+      esac
+changequote([,])dnl
+      if test -z "$gt_cv_int_divbyzero_sigfpe"; then
+        AC_TRY_RUN([
+#include <stdlib.h>
+#include <signal.h>
+
+static void
+sigfpe_handler (int sig)
+{
+  /* Exit with code 0 if SIGFPE, with code 1 if any other signal.  */
+  exit (sig != SIGFPE);
+}
+
+int x = 1;
+int y = 0;
+int z;
+int nan;
+
+int main ()
+{
+  signal (SIGFPE, sigfpe_handler);
+/* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP.  */
+#if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP)
+  signal (SIGTRAP, sigfpe_handler);
+#endif
+/* Linux/SPARC yields signal SIGILL.  */
+#if defined (__sparc__) && defined (__linux__)
+  signal (SIGILL, sigfpe_handler);
+#endif
+
+  z = x / y;
+  nan = y / y;
+  exit (1);
+}
+], [gt_cv_int_divbyzero_sigfpe=yes], [gt_cv_int_divbyzero_sigfpe=no],
+          [
+            # Guess based on the CPU.
+changequote(,)dnl
+            case "$host_cpu" in
+              alpha* | i[34567]86 | x86_64 | m68k | s390*)
+                gt_cv_int_divbyzero_sigfpe="guessing yes";;
+              *)
+                gt_cv_int_divbyzero_sigfpe="guessing no";;
+            esac
+changequote([,])dnl
+          ])
+      fi
+    ])
+  case "$gt_cv_int_divbyzero_sigfpe" in
+    *yes) value=1;;
+    *) value=0;;
+  esac
+  AC_DEFINE_UNQUOTED([INTDIV0_RAISES_SIGFPE], [$value],
+    [Define if integer division by zero raises signal SIGFPE.])
+])
diff --git a/tools/missing-macros/src/m4/intmax.m4 b/tools/missing-macros/src/m4/intmax.m4
new file mode 100644
index 0000000000..74aaaf5ed6
--- /dev/null
+++ b/tools/missing-macros/src/m4/intmax.m4
@@ -0,0 +1,33 @@
+# intmax.m4 serial 5 (gettext-0.18)
+dnl Copyright (C) 2002-2005, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether the system has the 'intmax_t' type, but don't attempt to
+dnl find a replacement if it is lacking.
+
+AC_DEFUN([gt_TYPE_INTMAX_T],
+[
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+  AC_CACHE_CHECK([for intmax_t], [gt_cv_c_intmax_t],
+    [AC_TRY_COMPILE([
+#include <stddef.h>
+#include <stdlib.h>
+#if HAVE_STDINT_H_WITH_UINTMAX
+#include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+#include <inttypes.h>
+#endif
+],     [intmax_t x = -1;
+        return !x;],
+       [gt_cv_c_intmax_t=yes],
+       [gt_cv_c_intmax_t=no])])
+  if test $gt_cv_c_intmax_t = yes; then
+    AC_DEFINE([HAVE_INTMAX_T], [1],
+      [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.])
+  fi
+])
diff --git a/tools/missing-macros/src/m4/inttypes-pri.m4 b/tools/missing-macros/src/m4/inttypes-pri.m4
new file mode 100644
index 0000000000..718a4f4e19
--- /dev/null
+++ b/tools/missing-macros/src/m4/inttypes-pri.m4
@@ -0,0 +1,36 @@
+# inttypes-pri.m4 serial 6 (gettext-0.18)
+dnl Copyright (C) 1997-2002, 2006, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ([2.52])
+
+# Define PRI_MACROS_BROKEN if <inttypes.h> exists and defines the PRI*
+# macros to non-string values.  This is the case on AIX 4.3.3.
+
+AC_DEFUN([gt_INTTYPES_PRI],
+[
+  AC_CHECK_HEADERS([inttypes.h])
+  if test $ac_cv_header_inttypes_h = yes; then
+    AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken],
+      [gt_cv_inttypes_pri_broken],
+      [
+        AC_TRY_COMPILE([#include <inttypes.h>
+#ifdef PRId32
+char *p = PRId32;
+#endif
+], [], [gt_cv_inttypes_pri_broken=no], [gt_cv_inttypes_pri_broken=yes])
+      ])
+  fi
+  if test "$gt_cv_inttypes_pri_broken" = yes; then
+    AC_DEFINE_UNQUOTED([PRI_MACROS_BROKEN], [1],
+      [Define if <inttypes.h> exists and defines unusable PRI* macros.])
+    PRI_MACROS_BROKEN=1
+  else
+    PRI_MACROS_BROKEN=0
+  fi
+  AC_SUBST([PRI_MACROS_BROKEN])
+])
diff --git a/tools/missing-macros/src/m4/inttypes_h.m4 b/tools/missing-macros/src/m4/inttypes_h.m4
new file mode 100644
index 0000000000..782d77ed8b
--- /dev/null
+++ b/tools/missing-macros/src/m4/inttypes_h.m4
@@ -0,0 +1,26 @@
+# inttypes_h.m4 serial 9
+dnl Copyright (C) 1997-2004, 2006, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_INTTYPES_H_WITH_UINTMAX if <inttypes.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_INTTYPES_H],
+[
+  AC_CACHE_CHECK([for inttypes.h], [gl_cv_header_inttypes_h],
+  [AC_TRY_COMPILE(
+    [#include <sys/types.h>
+#include <inttypes.h>],
+    [uintmax_t i = (uintmax_t) -1; return !i;],
+    [gl_cv_header_inttypes_h=yes],
+    [gl_cv_header_inttypes_h=no])])
+  if test $gl_cv_header_inttypes_h = yes; then
+    AC_DEFINE_UNQUOTED([HAVE_INTTYPES_H_WITH_UINTMAX], [1],
+      [Define if <inttypes.h> exists, doesn't clash with <sys/types.h>,
+       and declares uintmax_t. ])
+  fi
+])
diff --git a/tools/missing-macros/src/m4/lib-ld.m4 b/tools/missing-macros/src/m4/lib-ld.m4
new file mode 100644
index 0000000000..ebb30528bd
--- /dev/null
+++ b/tools/missing-macros/src/m4/lib-ld.m4
@@ -0,0 +1,110 @@
+# lib-ld.m4 serial 4 (gettext-0.18)
+dnl Copyright (C) 1996-2003, 2009-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld],
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  acl_cv_prog_gnu_ld=yes ;;
+*)
+  acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]* | [A-Za-z]:[\\/]*)]
+      [re_direlt='/[^/][^/]*/\.\./']
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+        ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL([acl_cv_path_LD],
+[if test -z "$LD"; then
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      acl_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+      *GNU* | *'with BFD'*)
+        test "$with_gnu_ld" != no && break ;;
+      *)
+        test "$with_gnu_ld" != yes && break ;;
+      esac
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT([$LD])
+else
+  AC_MSG_RESULT([no])
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
diff --git a/tools/missing-macros/src/m4/lib-link.m4 b/tools/missing-macros/src/m4/lib-link.m4
new file mode 100644
index 0000000000..c73bd8e3a4
--- /dev/null
+++ b/tools/missing-macros/src/m4/lib-link.m4
@@ -0,0 +1,774 @@
+# lib-link.m4 serial 21 (gettext-0.18)
+dnl Copyright (C) 2001-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ([2.54])
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  pushdef([Name],[translit([$1],[./-], [___])])
+  pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                                [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+    AC_LIB_LINKFLAGS_BODY([$1], [$2])
+    ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+    ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+    ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+    ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX"
+  ])
+  LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+  LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+  INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+  LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  AC_SUBST([LIB]NAME[_PREFIX])
+  dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+  dnl results of this search when this library appears as a dependency.
+  HAVE_LIB[]NAME=yes
+  popdef([NAME])
+  popdef([Name])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message])
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. The missing-message
+dnl defaults to 'no' and may contain additional hints for the user.
+dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME}
+dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  pushdef([Name],[translit([$1],[./-], [___])])
+  pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                                [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+  dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+  dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed lib[]Name and not disabled its use
+  dnl via --without-lib[]Name-prefix, he wants to use it.
+  ac_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+  AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+    ac_save_LIBS="$LIBS"
+    dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS,
+    dnl because these -l options might require -L options that are present in
+    dnl LIBS. -l options benefit only from the -L options listed before it.
+    dnl Otherwise, add it to the front of LIBS, because it may be a static
+    dnl library that depends on another static library that is present in LIBS.
+    dnl Static libraries benefit only from the static libraries listed after
+    dnl it.
+    case " $LIB[]NAME" in
+      *" -l"*) LIBS="$LIBS $LIB[]NAME" ;;
+      *)       LIBS="$LIB[]NAME $LIBS" ;;
+    esac
+    AC_TRY_LINK([$3], [$4],
+      [ac_cv_lib[]Name=yes],
+      [ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])'])
+    LIBS="$ac_save_LIBS"
+  ])
+  if test "$ac_cv_lib[]Name" = yes; then
+    HAVE_LIB[]NAME=yes
+    AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.])
+    AC_MSG_CHECKING([how to link with lib[]$1])
+    AC_MSG_RESULT([$LIB[]NAME])
+  else
+    HAVE_LIB[]NAME=no
+    dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+    dnl $INC[]NAME either.
+    CPPFLAGS="$ac_save_CPPFLAGS"
+    LIB[]NAME=
+    LTLIB[]NAME=
+    LIB[]NAME[]_PREFIX=
+  fi
+  AC_SUBST([HAVE_LIB]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  AC_SUBST([LIB]NAME[_PREFIX])
+  popdef([NAME])
+  popdef([Name])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl   acl_libext,
+dnl   acl_shlibext,
+dnl   acl_hardcode_libdir_flag_spec,
+dnl   acl_hardcode_libdir_separator,
+dnl   acl_hardcode_direct,
+dnl   acl_hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+  dnl Tell automake >= 1.10 to complain if config.rpath is missing.
+  m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+  AC_REQUIRE([AC_PROG_CC])                dnl we use $CC, $GCC, $LDFLAGS
+  AC_REQUIRE([AC_LIB_PROG_LD])            dnl we use $LD, $with_gnu_ld
+  AC_REQUIRE([AC_CANONICAL_HOST])         dnl we use $host
+  AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+  AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [
+    CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+    ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+    . ./conftest.sh
+    rm -f ./conftest.sh
+    acl_cv_rpath=done
+  ])
+  wl="$acl_cv_wl"
+  acl_libext="$acl_cv_libext"
+  acl_shlibext="$acl_cv_shlibext"
+  acl_libname_spec="$acl_cv_libname_spec"
+  acl_library_names_spec="$acl_cv_library_names_spec"
+  acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+  acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+  acl_hardcode_direct="$acl_cv_hardcode_direct"
+  acl_hardcode_minus_L="$acl_cv_hardcode_minus_L"
+  dnl Determine whether the user wants rpath handling at all.
+  AC_ARG_ENABLE([rpath],
+    [  --disable-rpath         do not hardcode runtime library paths],
+    :, enable_rpath=yes)
+])
+
+dnl AC_LIB_FROMPACKAGE(name, package)
+dnl declares that libname comes from the given package. The configure file
+dnl will then not have a --with-libname-prefix option but a
+dnl --with-package-prefix option. Several libraries can come from the same
+dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar
+dnl macro call that searches for libname.
+AC_DEFUN([AC_LIB_FROMPACKAGE],
+[
+  pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                                [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  define([acl_frompackage_]NAME, [$2])
+  popdef([NAME])
+  pushdef([PACK],[$2])
+  pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-],
+                                  [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  define([acl_libsinpackage_]PACKUP,
+    m4_ifdef([acl_libsinpackage_]PACKUP, [acl_libsinpackage_]PACKUP[[, ]],)[lib$1])
+  popdef([PACKUP])
+  popdef([PACK])
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found
+dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                                [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])])
+  pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-],
+                                  [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])])
+  dnl Autoconf >= 2.61 supports dots in --with options.
+  pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit(PACK,[.],[_])],PACK)])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_ARG_WITH(P_A_C_K[-prefix],
+[[  --with-]]P_A_C_K[[-prefix[=DIR]  search for ]PACKLIBS[ in DIR/include and DIR/lib
+  --without-]]P_A_C_K[[-prefix     don't search for ]PACKLIBS[ in includedir and libdir]],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+        if test "$acl_libdirstem2" != "$acl_libdirstem" \
+           && ! test -d "$withval/$acl_libdirstem"; then
+          additional_libdir="$withval/$acl_libdirstem2"
+        fi
+      fi
+    fi
+])
+  dnl Search the library and its dependencies in $additional_libdir and
+  dnl $LDFLAGS. Using breadth-first-seach.
+  LIB[]NAME=
+  LTLIB[]NAME=
+  INC[]NAME=
+  LIB[]NAME[]_PREFIX=
+  dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been
+  dnl computed. So it has to be reset here.
+  HAVE_LIB[]NAME=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='$1 $2'
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+        dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+        dnl or AC_LIB_HAVE_LINKFLAGS call.
+        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+          else
+            dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+            dnl that this library doesn't exist. So just drop it.
+            :
+          fi
+        else
+          dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+          dnl and the already constructed $LIBNAME/$LTLIBNAME.
+          found_dir=
+          found_la=
+          found_so=
+          found_a=
+          eval libname=\"$acl_libname_spec\"    # typically: libname=lib$name
+          if test -n "$acl_shlibext"; then
+            shrext=".$acl_shlibext"             # typically: shrext=.so
+          else
+            shrext=
+          fi
+          if test $use_additional = yes; then
+            dir="$additional_libdir"
+            dnl The same code as in the loop below:
+            dnl First look for a shared library.
+            if test -n "$acl_shlibext"; then
+              if test -f "$dir/$libname$shrext"; then
+                found_dir="$dir"
+                found_so="$dir/$libname$shrext"
+              else
+                if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                  ver=`(cd "$dir" && \
+                        for f in "$libname$shrext".*; do echo "$f"; done \
+                        | sed -e "s,^$libname$shrext\\\\.,," \
+                        | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                        | sed 1q ) 2>/dev/null`
+                  if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                    found_dir="$dir"
+                    found_so="$dir/$libname$shrext.$ver"
+                  fi
+                else
+                  eval library_names=\"$acl_library_names_spec\"
+                  for f in $library_names; do
+                    if test -f "$dir/$f"; then
+                      found_dir="$dir"
+                      found_so="$dir/$f"
+                      break
+                    fi
+                  done
+                fi
+              fi
+            fi
+            dnl Then look for a static library.
+            if test "X$found_dir" = "X"; then
+              if test -f "$dir/$libname.$acl_libext"; then
+                found_dir="$dir"
+                found_a="$dir/$libname.$acl_libext"
+              fi
+            fi
+            if test "X$found_dir" != "X"; then
+              if test -f "$dir/$libname.la"; then
+                found_la="$dir/$libname.la"
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIB[]NAME; do
+              AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  dnl First look for a shared library.
+                  if test -n "$acl_shlibext"; then
+                    if test -f "$dir/$libname$shrext"; then
+                      found_dir="$dir"
+                      found_so="$dir/$libname$shrext"
+                    else
+                      if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                        ver=`(cd "$dir" && \
+                              for f in "$libname$shrext".*; do echo "$f"; done \
+                              | sed -e "s,^$libname$shrext\\\\.,," \
+                              | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                              | sed 1q ) 2>/dev/null`
+                        if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                          found_dir="$dir"
+                          found_so="$dir/$libname$shrext.$ver"
+                        fi
+                      else
+                        eval library_names=\"$acl_library_names_spec\"
+                        for f in $library_names; do
+                          if test -f "$dir/$f"; then
+                            found_dir="$dir"
+                            found_so="$dir/$f"
+                            break
+                          fi
+                        done
+                      fi
+                    fi
+                  fi
+                  dnl Then look for a static library.
+                  if test "X$found_dir" = "X"; then
+                    if test -f "$dir/$libname.$acl_libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/$libname.$acl_libext"
+                    fi
+                  fi
+                  if test "X$found_dir" != "X"; then
+                    if test -f "$dir/$libname.la"; then
+                      found_la="$dir/$libname.la"
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+            dnl Found the library.
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+              dnl Linking with a shared library. We attempt to hardcode its
+              dnl directory into the executable's runpath, unless it's the
+              dnl standard /usr/lib.
+              if test "$enable_rpath" = no \
+                 || test "X$found_dir" = "X/usr/$acl_libdirstem" \
+                 || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then
+                dnl No hardcoding is needed.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+              else
+                dnl Use an explicit option to hardcode DIR into the resulting
+                dnl binary.
+                dnl Potentially add DIR to ltrpathdirs.
+                dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                dnl The hardcoding into $LIBNAME is system dependent.
+                if test "$acl_hardcode_direct" = yes; then
+                  dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+                  dnl resulting binary.
+                  LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                else
+                  if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
+                    dnl Use an explicit option to hardcode DIR into the resulting
+                    dnl binary.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    dnl Potentially add DIR to rpathdirs.
+                    dnl The rpathdirs will be appended to $LIBNAME at the end.
+                    haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                    dnl Rely on "-L$found_dir".
+                    dnl But don't add it if it's already contained in the LDFLAGS
+                    dnl or the already constructed $LIBNAME
+                    haveit=
+                    for x in $LDFLAGS $LIB[]NAME; do
+                      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+                    fi
+                    if test "$acl_hardcode_minus_L" != no; then
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    else
+                      dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH
+                      dnl here, because this doesn't fit in flags passed to the
+                      dnl compiler. So give up. No hardcoding. This affects only
+                      dnl very old systems.
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                dnl Linking with a static library.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+              else
+                dnl We shouldn't come here, but anyway it's good to have a
+                dnl fallback.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+              fi
+            fi
+            dnl Assume the include files are nearby.
+            additional_includedir=
+            case "$found_dir" in
+              */$acl_libdirstem | */$acl_libdirstem/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+                if test "$name" = '$1'; then
+                  LIB[]NAME[]_PREFIX="$basedir"
+                fi
+                additional_includedir="$basedir/include"
+                ;;
+              */$acl_libdirstem2 | */$acl_libdirstem2/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'`
+                if test "$name" = '$1'; then
+                  LIB[]NAME[]_PREFIX="$basedir"
+                fi
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+              dnl Potentially add $additional_includedir to $INCNAME.
+              dnl But don't add it
+              dnl   1. if it's the standard /usr/include,
+              dnl   2. if it's /usr/local/include and we are using GCC on Linux,
+              dnl   3. if it's already present in $CPPFLAGS or the already
+              dnl      constructed $INCNAME,
+              dnl   4. if it doesn't exist as a directory.
+              if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INC[]NAME; do
+                    AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                      dnl Really add $additional_includedir to $INCNAME.
+                      INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+            dnl Look for dependencies.
+            if test -n "$found_la"; then
+              dnl Read the .la file. It defines the variables
+              dnl dlname, library_names, old_library, dependency_libs, current,
+              dnl age, revision, installed, dlopen, dlpreopen, libdir.
+              save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+              dnl We use only dependency_libs.
+              for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                    dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+                    dnl But don't add it
+                    dnl   1. if it's the standard /usr/lib,
+                    dnl   2. if it's /usr/local/lib and we are using GCC on Linux,
+                    dnl   3. if it's already present in $LDFLAGS or the already
+                    dnl      constructed $LIBNAME,
+                    dnl   4. if it doesn't exist as a directory.
+                    if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \
+                       && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \
+                         || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LIBNAME.
+                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LTLIBNAME.
+                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                      dnl Potentially add DIR to rpathdirs.
+                      dnl The rpathdirs will be appended to $LIBNAME at the end.
+                      haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                      dnl Potentially add DIR to ltrpathdirs.
+                      dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                      haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                    dnl Handle this in the next round.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                    dnl Handle this in the next round. Throw away the .la's
+                    dnl directory; it is already contained in a preceding -L
+                    dnl option.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                    dnl Most likely an immediate library name.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+                    LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+            dnl Didn't find the library; assume it is in the system directories
+            dnl known to the linker and runtime loader. (All the system
+            dnl directories known to the linker should also be known to the
+            dnl runtime loader, otherwise the system is severely misconfigured.)
+            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$acl_hardcode_libdir_separator"; then
+      dnl Weird platform: only the last -rpath option counts, the user must
+      dnl pass all path elements in one option. We can arrange that for a
+      dnl single library, but not when more than one $LIBNAMEs are used.
+      alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
+      done
+      dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl.
+      acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$acl_hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+    else
+      dnl The -rpath options are cumulative.
+      for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$acl_hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+    dnl When using libtool, the option that works for both libraries and
+    dnl executables is -R. The -R options are cumulative.
+    for found_dir in $ltrpathdirs; do
+      LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+    done
+  fi
+  popdef([P_A_C_K])
+  popdef([PACKLIBS])
+  popdef([PACKUP])
+  popdef([PACK])
+  popdef([NAME])
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+  for element in [$2]; do
+    haveit=
+    for x in $[$1]; do
+      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      [$1]="${[$1]}${[$1]:+ }$element"
+    fi
+  done
+])
+
+dnl For those cases where a variable contains several -L and -l options
+dnl referring to unknown libraries and directories, this macro determines the
+dnl necessary additional linker options for the runtime path.
+dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL])
+dnl sets LDADDVAR to linker options needed together with LIBSVALUE.
+dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed,
+dnl otherwise linking without libtool is assumed.
+AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
+[
+  AC_REQUIRE([AC_LIB_RPATH])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  $1=
+  if test "$enable_rpath" != no; then
+    if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
+      dnl Use an explicit option to hardcode directories into the resulting
+      dnl binary.
+      rpathdirs=
+      next=
+      for opt in $2; do
+        if test -n "$next"; then
+          dir="$next"
+          dnl No need to hardcode the standard /usr/lib.
+          if test "X$dir" != "X/usr/$acl_libdirstem" \
+             && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+            rpathdirs="$rpathdirs $dir"
+          fi
+          next=
+        else
+          case $opt in
+            -L) next=yes ;;
+            -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
+                 dnl No need to hardcode the standard /usr/lib.
+                 if test "X$dir" != "X/usr/$acl_libdirstem" \
+                    && test "X$dir" != "X/usr/$acl_libdirstem2"; then
+                   rpathdirs="$rpathdirs $dir"
+                 fi
+                 next= ;;
+            *) next= ;;
+          esac
+        fi
+      done
+      if test "X$rpathdirs" != "X"; then
+        if test -n ""$3""; then
+          dnl libtool is used for linking. Use -R options.
+          for dir in $rpathdirs; do
+            $1="${$1}${$1:+ }-R$dir"
+          done
+        else
+          dnl The linker is used for linking directly.
+          if test -n "$acl_hardcode_libdir_separator"; then
+            dnl Weird platform: only the last -rpath option counts, the user
+            dnl must pass all path elements in one option.
+            alldirs=
+            for dir in $rpathdirs; do
+              alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir"
+            done
+            acl_save_libdir="$libdir"
+            libdir="$alldirs"
+            eval flag=\"$acl_hardcode_libdir_flag_spec\"
+            libdir="$acl_save_libdir"
+            $1="$flag"
+          else
+            dnl The -rpath options are cumulative.
+            for dir in $rpathdirs; do
+              acl_save_libdir="$libdir"
+              libdir="$dir"
+              eval flag=\"$acl_hardcode_libdir_flag_spec\"
+              libdir="$acl_save_libdir"
+              $1="${$1}${$1:+ }$flag"
+            done
+          fi
+        fi
+      fi
+    fi
+  fi
+  AC_SUBST([$1])
+])
diff --git a/tools/missing-macros/src/m4/lib-prefix.m4 b/tools/missing-macros/src/m4/lib-prefix.m4
new file mode 100644
index 0000000000..1601ceaefd
--- /dev/null
+++ b/tools/missing-macros/src/m4/lib-prefix.m4
@@ -0,0 +1,224 @@
+# lib-prefix.m4 serial 7 (gettext-0.18)
+dnl Copyright (C) 2001-2005, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+  AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib-prefix],
+[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+  --without-lib-prefix    don't search for libraries in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+      fi
+    fi
+])
+  if test $use_additional = yes; then
+    dnl Potentially add $additional_includedir to $CPPFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/include,
+    dnl   2. if it's already present in $CPPFLAGS,
+    dnl   3. if it's /usr/local/include and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_includedir" != "X/usr/include"; then
+      haveit=
+      for x in $CPPFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-I$additional_includedir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_includedir" = "X/usr/local/include"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_includedir"; then
+            dnl Really add $additional_includedir to $CPPFLAGS.
+            CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+          fi
+        fi
+      fi
+    fi
+    dnl Potentially add $additional_libdir to $LDFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/lib,
+    dnl   2. if it's already present in $LDFLAGS,
+    dnl   3. if it's /usr/local/lib and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+      haveit=
+      for x in $LDFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-L$additional_libdir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux*) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_libdir"; then
+            dnl Really add $additional_libdir to $LDFLAGS.
+            LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+          fi
+        fi
+      fi
+    fi
+  fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+  dnl Unfortunately, prefix and exec_prefix get only finally determined
+  dnl at the end of configure.
+  if test "X$prefix" = "XNONE"; then
+    acl_final_prefix="$ac_default_prefix"
+  else
+    acl_final_prefix="$prefix"
+  fi
+  if test "X$exec_prefix" = "XNONE"; then
+    acl_final_exec_prefix='${prefix}'
+  else
+    acl_final_exec_prefix="$exec_prefix"
+  fi
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  $1
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_PREPARE_MULTILIB creates
+dnl - a variable acl_libdirstem, containing the basename of the libdir, either
+dnl   "lib" or "lib64" or "lib/64",
+dnl - a variable acl_libdirstem2, as a secondary possible value for
+dnl   acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or
+dnl   "lib/amd64".
+AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
+[
+  dnl There is no formal standard regarding lib and lib64.
+  dnl On glibc systems, the current practice is that on a system supporting
+  dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
+  dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine
+  dnl the compiler's default mode by looking at the compiler's library search
+  dnl path. If at least one of its elements ends in /lib64 or points to a
+  dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI.
+  dnl Otherwise we use the default, namely "lib".
+  dnl On Solaris systems, the current practice is that on a system supporting
+  dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
+  dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or
+  dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib.
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  acl_libdirstem=lib
+  acl_libdirstem2=
+  case "$host_os" in
+    solaris*)
+      dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
+      dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>.
+      dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
+      dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
+      dnl symlink is missing, so we set acl_libdirstem2 too.
+      AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit],
+        [AC_EGREP_CPP([sixtyfour bits], [
+#ifdef _LP64
+sixtyfour bits
+#endif
+           ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no])
+        ])
+      if test $gl_cv_solaris_64bit = yes; then
+        acl_libdirstem=lib/64
+        case "$host_cpu" in
+          sparc*)        acl_libdirstem2=lib/sparcv9 ;;
+          i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
+        esac
+      fi
+      ;;
+    *)
+      searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+      if test -n "$searchpath"; then
+        acl_save_IFS="${IFS= 	}"; IFS=":"
+        for searchdir in $searchpath; do
+          if test -d "$searchdir"; then
+            case "$searchdir" in
+              */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
+              */../ | */.. )
+                # Better ignore directories of this form. They are misleading.
+                ;;
+              *) searchdir=`cd "$searchdir" && pwd`
+                 case "$searchdir" in
+                   */lib64 ) acl_libdirstem=lib64 ;;
+                 esac ;;
+            esac
+          fi
+        done
+        IFS="$acl_save_IFS"
+      fi
+      ;;
+  esac
+  test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
+])
diff --git a/tools/missing-macros/src/m4/mfx_acc.m4 b/tools/missing-macros/src/m4/mfx_acc.m4
new file mode 100644
index 0000000000..9685cc36d2
--- /dev/null
+++ b/tools/missing-macros/src/m4/mfx_acc.m4
@@ -0,0 +1,163 @@
+# acc.m4 serial 1 (ucl-1.03)
+# /***********************************************************************
+# // standard ACC macros
+# ************************************************************************/
+
+AC_DEFUN([mfx_ACC_CHECK_ENDIAN], [
+AC_C_BIGENDIAN([AC_DEFINE(ACC_ABI_BIG_ENDIAN,1,[Define to 1 if your machine is big endian.])],[AC_DEFINE(ACC_ABI_LITTLE_ENDIAN,1,[Define to 1 if your machine is little endian.])])
+])#
+
+AC_DEFUN([mfx_ACC_CHECK_HEADERS], [
+AC_HEADER_TIME
+AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h limits.h malloc.h memory.h setjmp.h signal.h stdarg.h stddef.h stdint.h stdio.h stdlib.h string.h strings.h time.h unistd.h utime.h sys/mman.h sys/resource.h sys/stat.h sys/time.h sys/types.h sys/wait.h])
+])#
+
+AC_DEFUN([mfx_ACC_CHECK_FUNCS], [
+AC_CHECK_FUNCS(access alloca atexit atoi atol chmod chown clock_getcpuclockid clock_getres clock_gettime ctime difftime fstat getenv getpagesize getrusage gettimeofday gmtime isatty localtime longjmp lstat memcmp memcpy memmove memset mkdir mktime mmap mprotect munmap qsort raise rmdir setjmp signal snprintf strcasecmp strchr strdup strerror strftime stricmp strncasecmp strnicmp strrchr strstr time umask utime vsnprintf)
+])#
+
+
+AC_DEFUN([mfx_ACC_CHECK_SIZEOF], [
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(__int16)
+AC_CHECK_SIZEOF(__int32)
+AC_CHECK_SIZEOF(__int64)
+
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(char *)
+AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(ptrdiff_t)
+])#
+
+
+# /***********************************************************************
+# // Check for ACC_conformance
+# ************************************************************************/
+
+AC_DEFUN([mfx_ACC_ACCCHK], [
+mfx_tmp=$1
+mfx_save_CPPFLAGS=$CPPFLAGS
+dnl in Makefile.in $(INCLUDES) will be before $(CPPFLAGS), so we mimic this here
+test "X$mfx_tmp" = "X" || CPPFLAGS="$mfx_tmp $CPPFLAGS"
+
+AC_MSG_CHECKING([whether your compiler passes the ACC conformance test])
+
+AC_LANG_CONFTEST([AC_LANG_PROGRAM(
+[[#define ACC_CONFIG_NO_HEADER 1
+#include "acc/acc.h"
+#include "acc/acc_incd.h"
+#undef ACCCHK_ASSERT
+#define ACCCHK_ASSERT(expr)     ACC_COMPILE_TIME_ASSERT_HEADER(expr)
+#include "acc/acc_chk.ch"
+#undef ACCCHK_ASSERT
+static void test_acc_compile_time_assert(void) {
+#define ACCCHK_ASSERT(expr)     ACC_COMPILE_TIME_ASSERT(expr)
+#include "acc/acc_chk.ch"
+#undef ACCCHK_ASSERT
+}
+#undef NDEBUG
+#include <assert.h>
+static int test_acc_run_time_assert(int r) {
+#define ACCCHK_ASSERT(expr)     assert(expr);
+#include "acc/acc_chk.ch"
+#undef ACCCHK_ASSERT
+return r;
+}
+]], [[
+test_acc_compile_time_assert();
+if (test_acc_run_time_assert(1) != 1) return 1;
+]]
+)])
+
+mfx_tmp=FAILED
+_AC_COMPILE_IFELSE([], [mfx_tmp=yes])
+rm -f conftest.$ac_ext conftest.$ac_objext
+
+CPPFLAGS=$mfx_save_CPPFLAGS
+
+AC_MSG_RESULT([$mfx_tmp])
+case x$mfx_tmp in
+  xpassed | xyes) ;;
+  *)
+    AC_MSG_NOTICE([])
+    AC_MSG_NOTICE([Your compiler failed the ACC conformance test - for details see ])
+    AC_MSG_NOTICE([`config.log'. Please check that log file and consider sending])
+    AC_MSG_NOTICE([a patch or bug-report to <${PACKAGE_BUGREPORT}>.])
+    AC_MSG_NOTICE([Thanks for your support.])
+    AC_MSG_NOTICE([])
+    AC_MSG_ERROR([ACC conformance test failed. Stop.])
+dnl    AS_EXIT
+    ;;
+esac
+])# mfx_ACC_ACCCHK
+
+
+# /***********************************************************************
+# // Check for ACC_conformance
+# ************************************************************************/
+
+AC_DEFUN([mfx_MINIACC_ACCCHK], [
+mfx_tmp=$1
+mfx_save_CPPFLAGS=$CPPFLAGS
+dnl in Makefile.in $(INCLUDES) will be before $(CPPFLAGS), so we mimic this here
+test "X$mfx_tmp" = "X" || CPPFLAGS="$mfx_tmp $CPPFLAGS"
+
+AC_MSG_CHECKING([whether your compiler passes the ACC conformance test])
+
+AC_LANG_CONFTEST([AC_LANG_PROGRAM(
+[[#define ACC_CONFIG_NO_HEADER 1
+#define ACC_WANT_ACC_INCD_H 1
+#include $2
+
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+#define ACCCHK_ASSERT(expr)     ACC_COMPILE_TIME_ASSERT_HEADER(expr)
+#include $2
+
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+#define ACCCHK_ASSERT(expr)     ACC_COMPILE_TIME_ASSERT(expr)
+static void test_acc_compile_time_assert(void) {
+#include $2
+}
+
+#undef NDEBUG
+#include <assert.h>
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+#define ACCCHK_ASSERT(expr)  assert(expr);
+static int test_acc_run_time_assert(int r) {
+#include $2
+return r;
+}
+]], [[
+test_acc_compile_time_assert();
+if (test_acc_run_time_assert(1) != 1) return 1;
+]]
+)])
+
+mfx_tmp=FAILED
+_AC_COMPILE_IFELSE([], [mfx_tmp=yes])
+rm -f conftest.$ac_ext conftest.$ac_objext
+
+CPPFLAGS=$mfx_save_CPPFLAGS
+
+AC_MSG_RESULT([$mfx_tmp])
+case x$mfx_tmp in
+  xpassed | xyes) ;;
+  *)
+    AC_MSG_NOTICE([])
+    AC_MSG_NOTICE([Your compiler failed the ACC conformance test - for details see ])
+    AC_MSG_NOTICE([`config.log'. Please check that log file and consider sending])
+    AC_MSG_NOTICE([a patch or bug-report to <${PACKAGE_BUGREPORT}>.])
+    AC_MSG_NOTICE([Thanks for your support.])
+    AC_MSG_NOTICE([])
+    AC_MSG_ERROR([ACC conformance test failed. Stop.])
+dnl    AS_EXIT
+    ;;
+esac
+])# mfx_MINIACC_ACCCHK
diff --git a/tools/missing-macros/src/m4/mfx_cppflags.m4 b/tools/missing-macros/src/m4/mfx_cppflags.m4
new file mode 100644
index 0000000000..0ad9141c84
--- /dev/null
+++ b/tools/missing-macros/src/m4/mfx_cppflags.m4
@@ -0,0 +1,41 @@
+# serial 1
+
+AC_DEFUN([mfx_PROG_CPPFLAGS], [
+AC_MSG_CHECKING([whether the C preprocessor needs special flags])
+
+AC_LANG_CONFTEST([AC_LANG_PROGRAM(
+[[#include <limits.h>
+#if (32767 >= 4294967295ul) || (65535u >= 4294967295ul)
+#  include "your C preprocessor is broken 1"
+#elif (0xffffu == 0xfffffffful)
+#  include "your C preprocessor is broken 2"
+#elif (32767 >= ULONG_MAX) || (65535u >= ULONG_MAX)
+#  include "your C preprocessor is broken 3"
+#endif
+]], [[ ]]
+)])
+
+mfx_save_CPPFLAGS=$CPPFLAGS
+mfx_tmp=ERROR
+for mfx_arg in "" -no-cpp-precomp
+do
+  CPPFLAGS="$mfx_arg $mfx_save_CPPFLAGS"
+  _AC_COMPILE_IFELSE([],
+[mfx_tmp=$mfx_arg
+break])
+done
+CPPFLAGS=$mfx_save_CPPFLAGS
+rm -f conftest.$ac_ext conftest.$ac_objext
+case x$mfx_tmp in
+  x)
+    AC_MSG_RESULT([none needed]) ;;
+  xERROR)
+    AC_MSG_RESULT([ERROR])
+    AC_MSG_ERROR([your C preprocessor is broken - for details see config.log])
+    ;;
+  *)
+    AC_MSG_RESULT([$mfx_tmp])
+    CPPFLAGS="$mfx_tmp $CPPFLAGS"
+    ;;
+esac
+])# mfx_PROG_CPPFLAGS
diff --git a/tools/missing-macros/src/m4/mfx_limits.m4 b/tools/missing-macros/src/m4/mfx_limits.m4
new file mode 100644
index 0000000000..d63a14bb96
--- /dev/null
+++ b/tools/missing-macros/src/m4/mfx_limits.m4
@@ -0,0 +1,154 @@
+# serial 3
+
+AC_DEFUN([mfx_CHECK_HEADER_SANE_LIMITS_H], [
+AC_CACHE_CHECK([whether limits.h is sane],
+mfx_cv_header_sane_limits_h,
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <limits.h>
+#if (32767 >= 4294967295ul) || (65535u >= 4294967295ul)
+#  if defined(__APPLE__) && defined(__GNUC__)
+#    error "your preprocessor is broken - use compiler option -no-cpp-precomp"
+#  else
+#    include "your preprocessor is broken"
+#  endif
+#endif
+#define MFX_0xffff          0xffff
+#define MFX_0xffffffffL     4294967295ul
+#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
+#  include "error CHAR_BIT"
+#endif
+#if !defined(UCHAR_MAX)
+#  include "error UCHAR_MAX 1"
+#endif
+#if !defined(USHRT_MAX)
+#  include "error USHRT_MAX 1"
+#endif
+#if !defined(UINT_MAX)
+#  include "error UINT_MAX 1"
+#endif
+#if !defined(ULONG_MAX)
+#  include "error ULONG_MAX 1"
+#endif
+#if !defined(SHRT_MAX)
+#  include "error SHRT_MAX 1"
+#endif
+#if !defined(INT_MAX)
+#  include "error INT_MAX 1"
+#endif
+#if !defined(LONG_MAX)
+#  include "error LONG_MAX 1"
+#endif
+#if (UCHAR_MAX < 1)
+#  include "error UCHAR_MAX 2"
+#endif
+#if (USHRT_MAX < 1)
+#  include "error USHRT_MAX 2"
+#endif
+#if (UINT_MAX < 1)
+#  include "error UINT_MAX 2"
+#endif
+#if (ULONG_MAX < 1)
+#  include "error ULONG_MAX 2"
+#endif
+#if (UCHAR_MAX < 0xff)
+#  include "error UCHAR_MAX 3"
+#endif
+#if (USHRT_MAX < MFX_0xffff)
+#  include "error USHRT_MAX 3"
+#endif
+#if (UINT_MAX < MFX_0xffff)
+#  include "error UINT_MAX 3"
+#endif
+#if (ULONG_MAX < MFX_0xffffffffL)
+#  include "error ULONG_MAX 3"
+#endif
+#if (USHRT_MAX > UINT_MAX)
+#  include "error USHRT_MAX vs UINT_MAX"
+#endif
+#if (UINT_MAX > ULONG_MAX)
+#  include "error UINT_MAX vs ULONG_MAX"
+#endif
+]], [[
+#if (USHRT_MAX == MFX_0xffff)
+{ typedef char a_short2a[1 - 2 * !(sizeof(short) == 2)]; }
+#elif (USHRT_MAX >= MFX_0xffff)
+{ typedef char a_short2b[1 - 2 * !(sizeof(short) > 2)]; }
+#endif
+#if (UINT_MAX == MFX_0xffff)
+{ typedef char a_int2a[1 - 2 * !(sizeof(int) == 2)]; }
+#elif (UINT_MAX >= MFX_0xffff)
+{ typedef char a_int2b[1 - 2 * !(sizeof(int) > 2)]; }
+#endif
+#if (ULONG_MAX == MFX_0xffff)
+{ typedef char a_long2a[1 - 2 * !(sizeof(long) == 2)]; }
+#elif (ULONG_MAX >= MFX_0xffff)
+{ typedef char a_long2b[1 - 2 * !(sizeof(long) > 2)]; }
+#endif
+#if !defined(_CRAY1) /* CRAY PVP systems */
+#if (USHRT_MAX == MFX_0xffffffffL)
+{ typedef char a_short4a[1 - 2 * !(sizeof(short) == 4)]; }
+#elif (USHRT_MAX >= MFX_0xffffffffL)
+{ typedef char a_short4b[1 - 2 * !(sizeof(short) > 4)]; }
+#endif
+#endif /* _CRAY1 */
+#if (UINT_MAX == MFX_0xffffffffL)
+{ typedef char a_int4a[1 - 2 * !(sizeof(int) == 4)]; }
+#elif (UINT_MAX >= MFX_0xffffffffL)
+{ typedef char a_int4b[1 - 2 * !(sizeof(int) > 4)]; }
+#endif
+#if (ULONG_MAX == MFX_0xffffffffL)
+{ typedef char a_long4a[1 - 2 * !(sizeof(long) == 4)]; }
+#elif (ULONG_MAX >= MFX_0xffffffffL)
+{ typedef char a_long4b[1 - 2 * !(sizeof(long) > 4)]; }
+#endif
+]])],
+[mfx_cv_header_sane_limits_h=yes],
+[mfx_cv_header_sane_limits_h=no])])
+])
+
+# /***********************************************************************
+# // standard
+# ************************************************************************/
+
+AC_DEFUN([mfx_LZO_CHECK_ENDIAN], [
+AC_C_BIGENDIAN([AC_DEFINE(LZO_ABI_BIG_ENDIAN,1,[Define to 1 if your machine is big endian.])],[AC_DEFINE(LZO_ABI_LITTLE_ENDIAN,1,[Define to 1 if your machine is little endian.])])
+])#
+
+
+# /***********************************************************************
+# //
+# ************************************************************************/
+
+dnl more types which are not yet covered by ACC
+
+AC_DEFUN([mfx_CHECK_SIZEOF], [
+AC_CHECK_SIZEOF(__int32)
+AC_CHECK_SIZEOF(intmax_t)
+AC_CHECK_SIZEOF(uintmax_t)
+AC_CHECK_SIZEOF(intptr_t)
+AC_CHECK_SIZEOF(uintptr_t)
+
+AC_CHECK_SIZEOF(float)
+AC_CHECK_SIZEOF(double)
+AC_CHECK_SIZEOF(long double)
+
+AC_CHECK_SIZEOF(dev_t)
+AC_CHECK_SIZEOF(fpos_t)
+AC_CHECK_SIZEOF(mode_t)
+AC_CHECK_SIZEOF(off_t)
+AC_CHECK_SIZEOF(ssize_t)
+AC_CHECK_SIZEOF(time_t)
+])#
+
+
+
+AC_DEFUN([mfx_CHECK_LIB_WINMM], [
+if test "X$GCC" = Xyes; then
+case $host_os in
+cygwin* | mingw* | pw32*)
+     test "X$LIBS" != "X" && LIBS="$LIBS "
+     LIBS="${LIBS}-lwinmm" ;;
+*)
+     ;;
+esac
+fi
+])#
diff --git a/tools/missing-macros/src/m4/progtest.m4 b/tools/missing-macros/src/m4/progtest.m4
new file mode 100644
index 0000000000..2d804ac99d
--- /dev/null
+++ b/tools/missing-macros/src/m4/progtest.m4
@@ -0,0 +1,92 @@
+# progtest.m4 serial 6 (gettext-0.18)
+dnl Copyright (C) 1996-2003, 2005, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+AC_PREREQ([2.50])
+
+# Search path for a program which passes the given test.
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl   TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN([AM_PATH_PROG_WITH_TEST],
+[
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+  ac_executable_p="test -x"
+else
+  ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL([ac_cv_path_$1],
+[case "[$]$1" in
+  [[\\/]]* | ?:[[\\/]]*)
+    ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+    ;;
+  *)
+    ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in ifelse([$5], , $PATH, [$5]); do
+      IFS="$ac_save_IFS"
+      test -z "$ac_dir" && ac_dir=.
+      for ac_exec_ext in '' $ac_executable_extensions; do
+        if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+          echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD
+          if [$3]; then
+            ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext"
+            break 2
+          fi
+        fi
+      done
+    done
+    IFS="$ac_save_IFS"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [  test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+    ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
+  AC_MSG_RESULT([$][$1])
+else
+  AC_MSG_RESULT([no])
+fi
+AC_SUBST([$1])dnl
+])
diff --git a/tools/missing-macros/src/m4/stdint_h.m4 b/tools/missing-macros/src/m4/stdint_h.m4
new file mode 100644
index 0000000000..b8e3c6cc71
--- /dev/null
+++ b/tools/missing-macros/src/m4/stdint_h.m4
@@ -0,0 +1,26 @@
+# stdint_h.m4 serial 8
+dnl Copyright (C) 1997-2004, 2006, 2008-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_STDINT_H_WITH_UINTMAX if <stdint.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_STDINT_H],
+[
+  AC_CACHE_CHECK([for stdint.h], [gl_cv_header_stdint_h],
+  [AC_TRY_COMPILE(
+    [#include <sys/types.h>
+#include <stdint.h>],
+    [uintmax_t i = (uintmax_t) -1; return !i;],
+    [gl_cv_header_stdint_h=yes],
+    [gl_cv_header_stdint_h=no])])
+  if test $gl_cv_header_stdint_h = yes; then
+    AC_DEFINE_UNQUOTED([HAVE_STDINT_H_WITH_UINTMAX], [1],
+      [Define if <stdint.h> exists, doesn't clash with <sys/types.h>,
+       and declares uintmax_t. ])
+  fi
+])
diff --git a/tools/missing-macros/src/m4/uintmax_t.m4 b/tools/missing-macros/src/m4/uintmax_t.m4
new file mode 100644
index 0000000000..03b51bcfe3
--- /dev/null
+++ b/tools/missing-macros/src/m4/uintmax_t.m4
@@ -0,0 +1,30 @@
+# uintmax_t.m4 serial 12
+dnl Copyright (C) 1997-2004, 2007-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_PREREQ([2.13])
+
+# Define uintmax_t to 'unsigned long' or 'unsigned long long'
+# if it is not already defined in <stdint.h> or <inttypes.h>.
+
+AC_DEFUN([gl_AC_TYPE_UINTMAX_T],
+[
+  AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+  AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+  if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+    AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+    test $ac_cv_type_unsigned_long_long_int = yes \
+      && ac_type='unsigned long long' \
+      || ac_type='unsigned long'
+    AC_DEFINE_UNQUOTED([uintmax_t], [$ac_type],
+      [Define to unsigned long or unsigned long long
+       if <stdint.h> and <inttypes.h> don't define.])
+  else
+    AC_DEFINE([HAVE_UINTMAX_T], [1],
+      [Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>.])
+  fi
+])
diff --git a/tools/missing-macros/src/m4/va_copy.m4 b/tools/missing-macros/src/m4/va_copy.m4
new file mode 100644
index 0000000000..0e88ee662f
--- /dev/null
+++ b/tools/missing-macros/src/m4/va_copy.m4
@@ -0,0 +1,111 @@
+# va_copy.m4 serial 1 (js-1.6.20070208)
+
+dnl ##
+dnl ##  Check for C99 va_copy() implementation
+dnl ##  (and provide fallback implementation if neccessary)
+dnl ##
+dnl ##  configure.in:
+dnl ##    AC_CHECK_VA_COPY
+dnl ##  foo.c:
+dnl ##    #include "config.h"
+dnl ##    [...]
+dnl ##    va_copy(d,s)
+dnl ##
+dnl ##  This check is rather complex: first because we really have to
+dnl ##  try various possible implementations in sequence and second, we
+dnl ##  cannot define a macro in config.h with parameters directly.
+dnl ##
+
+dnl #   test program for va_copy() implementation
+changequote(<<,>>)
+m4_define(__va_copy_test, <<[
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#define DO_VA_COPY(d, s) $1
+void test(char *str, ...)
+{
+    va_list ap, ap2;
+    int i;
+    va_start(ap, str);
+    DO_VA_COPY(ap2, ap);
+    for (i = 1; i <= 9; i++) {
+        int k = (int)va_arg(ap, int);
+        if (k != i)
+            abort();
+    }
+    DO_VA_COPY(ap, ap2);
+    for (i = 1; i <= 9; i++) {
+        int k = (int)va_arg(ap, int);
+        if (k != i)
+            abort();
+    }
+    va_end(ap);
+}
+int main(int argc, char *argv[])
+{
+    test("test", 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    exit(0);
+}
+]>>)
+changequote([,])
+
+dnl #   test driver for va_copy() implementation
+m4_define(__va_copy_check, [
+    AH_VERBATIM($1,
+[/* Predefined possible va_copy() implementation (id: $1) */
+#define __VA_COPY_USE_$1(d, s) $2])
+    if test ".$ac_cv_va_copy" = .; then
+        AC_TRY_RUN(__va_copy_test($2), [ac_cv_va_copy="$1"])
+    fi
+])
+
+dnl #   Autoconf check for va_copy() implementation checking
+AC_DEFUN([AC_CHECK_VA_COPY],[
+  dnl #   provide Autoconf display check message
+  AC_MSG_CHECKING(for va_copy() function)
+  dnl #   check for various implementations in priorized sequence   
+  AC_CACHE_VAL(ac_cv_va_copy, [
+    ac_cv_va_copy=""
+    dnl #   1. check for standardized C99 macro
+    __va_copy_check(C99, [va_copy((d), (s))])
+    dnl #   2. check for alternative/deprecated GCC macro
+    __va_copy_check(GCM, [VA_COPY((d), (s))])
+    dnl #   3. check for internal GCC macro (high-level define)
+    __va_copy_check(GCH, [__va_copy((d), (s))])
+    dnl #   4. check for internal GCC macro (built-in function)
+    __va_copy_check(GCB, [__builtin_va_copy((d), (s))])
+    dnl #   5. check for assignment approach (assuming va_list is a struct)
+    __va_copy_check(ASS, [do { (d) = (s); } while (0)])
+    dnl #   6. check for assignment approach (assuming va_list is a pointer)
+    __va_copy_check(ASP, [do { *(d) = *(s); } while (0)])
+    dnl #   7. check for memory copying approach (assuming va_list is a struct)
+    __va_copy_check(CPS, [memcpy((void *)&(d), (void *)&(s)), sizeof((s))])
+    dnl #   8. check for memory copying approach (assuming va_list is a pointer)
+    __va_copy_check(CPP, [memcpy((void *)(d), (void *)(s)), sizeof(*(s))])
+    if test ".$ac_cv_va_copy" = .; then
+        AC_ERROR([no working implementation found])
+    fi
+  ])
+  dnl #   optionally activate the fallback implementation
+  if test ".$ac_cv_va_copy" = ".C99"; then
+      AC_DEFINE(HAVE_VA_COPY, 1, [Define if va_copy() macro exists (and no fallback implementation is required)])
+  fi
+  dnl #   declare which fallback implementation to actually use
+  AC_DEFINE_UNQUOTED([__VA_COPY_USE], [__VA_COPY_USE_$ac_cv_va_copy],
+      [Define to id of used va_copy() implementation])
+  dnl #   provide activation hook for fallback implementation
+  AH_VERBATIM([__VA_COPY_ACTIVATION],
+[/* Optional va_copy() implementation activation */
+#ifndef HAVE_VA_COPY
+#define va_copy(d, s) __VA_COPY_USE(d, s)
+#endif
+])
+  dnl #   provide Autoconf display result message
+  if test ".$ac_cv_va_copy" = ".C99"; then
+      AC_MSG_RESULT([yes])
+  else
+      AC_MSG_RESULT([no (using fallback implementation)])
+  fi
+])
+
diff --git a/tools/missing-macros/src/m4/wint_t.m4 b/tools/missing-macros/src/m4/wint_t.m4
new file mode 100644
index 0000000000..a6c7d15cb5
--- /dev/null
+++ b/tools/missing-macros/src/m4/wint_t.m4
@@ -0,0 +1,28 @@
+# wint_t.m4 serial 4 (gettext-0.18)
+dnl Copyright (C) 2003, 2007-2010 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <wchar.h> has the 'wint_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WINT_T],
+[
+  AC_CACHE_CHECK([for wint_t], [gt_cv_c_wint_t],
+    [AC_TRY_COMPILE([
+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
+   <wchar.h>.
+   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be included
+   before <wchar.h>.  */
+#include <stddef.h>
+#include <stdio.h>
+#include <time.h>
+#include <wchar.h>
+       wint_t foo = (wchar_t)'\0';], ,
+       [gt_cv_c_wint_t=yes], [gt_cv_c_wint_t=no])])
+  if test $gt_cv_c_wint_t = yes; then
+    AC_DEFINE([HAVE_WINT_T], [1], [Define if you have the 'wint_t' type.])
+  fi
+])
diff --git a/tools/mkimage/Makefile b/tools/mkimage/Makefile
new file mode 100644
index 0000000000..fc564f47af
--- /dev/null
+++ b/tools/mkimage/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mkimage
+PKG_VERSION:=2014.10-librecmc
+
+PKG_SOURCE:=u-boot-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=\
+	https://librecmc.org/librecmc/downloads/sources/archive/ \
+	ftp://ftp.denx.de/pub/u-boot
+PKG_MD5SUM:=a4d242902687a4ee46fe8dabb5c0f12e
+PKG_CAT:=bzcat
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/u-boot-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Prepare
+	$(Host/Prepare/Default)
+	rm -f \
+		$(HOST_BUILD_DIR)/include/errno.h \
+		$(HOST_BUILD_DIR)/include/malloc.h \
+		$(HOST_BUILD_DIR)/tools/.depend
+	touch $(HOST_BUILD_DIR)/include/config.mk
+	touch $(HOST_BUILD_DIR)/include/config.h
+endef
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) defconfig   HOSTCFLAGS="$(HOST_CPPFLAGS) $(HOST_CFLAGS)" HOSTLDFLAGS="$(HOST_LDFLAGS)"
+	$(MAKE) -C $(HOST_BUILD_DIR) tools-only  HOSTCFLAGS="$(HOST_CPPFLAGS) $(HOST_CFLAGS)" HOSTLDFLAGS="$(HOST_LDFLAGS)"
+endef
+
+define Host/Install
+	$(CP) $(HOST_BUILD_DIR)/tools/mkimage $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/mkimage
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/mkimage/patches/010-freebsd-ulong-fix.patch b/tools/mkimage/patches/010-freebsd-ulong-fix.patch
new file mode 100644
index 0000000000..1101e72d15
--- /dev/null
+++ b/tools/mkimage/patches/010-freebsd-ulong-fix.patch
@@ -0,0 +1,13 @@
+--- a/include/image.h
++++ b/include/image.h
+@@ -44,6 +44,10 @@ struct lmb;
+ 
+ #endif /* USE_HOSTCC */
+ 
++#ifndef ulong
++#define ulong unsigned long
++#endif
++
+ #if defined(CONFIG_FIT)
+ #include <hash.h>
+ #include <libfdt.h>
diff --git a/tools/mkimage/patches/020-include_compile_fix.patch b/tools/mkimage/patches/020-include_compile_fix.patch
new file mode 100644
index 0000000000..276cae0cb1
--- /dev/null
+++ b/tools/mkimage/patches/020-include_compile_fix.patch
@@ -0,0 +1,10 @@
+--- a/include/u-boot/rsa-checksum.h
++++ b/include/u-boot/rsa-checksum.h
+@@ -7,7 +7,6 @@
+ #ifndef _RSA_CHECKSUM_H
+ #define _RSA_CHECKSUM_H
+ 
+-#include <errno.h>
+ #include <image.h>
+ #include <u-boot/sha1.h>
+ #include <u-boot/sha256.h>
diff --git a/tools/mkimage/patches/030-allow-to-use-different-magic.patch b/tools/mkimage/patches/030-allow-to-use-different-magic.patch
new file mode 100644
index 0000000000..dcab48894c
--- /dev/null
+++ b/tools/mkimage/patches/030-allow-to-use-different-magic.patch
@@ -0,0 +1,63 @@
+--- a/tools/mkimage.c
++++ b/tools/mkimage.c
+@@ -24,6 +24,7 @@ struct image_tool_params params = {
+ 	.arch = IH_ARCH_PPC,
+ 	.type = IH_TYPE_KERNEL,
+ 	.comp = IH_COMP_GZIP,
++	.magic = IH_MAGIC,
+ 	.dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
+ 	.imagename = "",
+ 	.imagename2 = "",
+@@ -168,6 +169,16 @@ main (int argc, char **argv)
+ 					genimg_get_comp_id (*++argv)) < 0)
+ 					usage ();
+ 				goto NXTARG;
++			case 'M':
++				if (--argc <=0)
++					usage ();
++				params.magic = strtoul (*++argv, &ptr, 16);
++				if (*ptr) {
++					fprintf (stderr,
++						"%s: invalid magic %s\n",
++						params.cmdname, *argv);
++				}
++				goto NXTARG;
+ 			case 'D':
+ 				if (--argc <= 0)
+ 					usage ();
+@@ -623,12 +634,13 @@ static void usage(void)
+ 	fprintf (stderr, "Usage: %s -l image\n"
+ 			 "          -l ==> list image header information\n",
+ 		params.cmdname);
+-	fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp "
++	fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp -M magic "
+ 			 "-a addr -e ep -n name -d data_file[:data_file...] image\n"
+ 			 "          -A ==> set architecture to 'arch'\n"
+ 			 "          -O ==> set operating system to 'os'\n"
+ 			 "          -T ==> set image type to 'type'\n"
+ 			 "          -C ==> set compression type 'comp'\n"
++			 "          -M ==> set image magic to 'magic'\n"
+ 			 "          -a ==> set load address to 'addr' (hex)\n"
+ 			 "          -e ==> set entry point to 'ep' (hex)\n"
+ 			 "          -n ==> set image name to 'name'\n"
+--- a/tools/default_image.c
++++ b/tools/default_image.c
+@@ -98,7 +98,7 @@ static void image_set_header(void *ptr,
+ 			sbuf->st_size - sizeof(image_header_t));
+ 
+ 	/* Build new header */
+-	image_set_magic(hdr, IH_MAGIC);
++	image_set_magic(hdr, params->magic);
+ 	image_set_time(hdr, sbuf->st_mtime);
+ 	image_set_size(hdr, sbuf->st_size - sizeof(image_header_t));
+ 	image_set_load(hdr, params->addr);
+--- a/tools/imagetool.h
++++ b/tools/imagetool.h
+@@ -44,6 +44,7 @@ struct image_tool_params {
+ 	int arch;
+ 	int type;
+ 	int comp;
++	unsigned int magic;
+ 	char *dtc;
+ 	unsigned int addr;
+ 	unsigned int ep;
diff --git a/tools/mkimage/patches/040-include_order.patch b/tools/mkimage/patches/040-include_order.patch
new file mode 100644
index 0000000000..3b9ecc6bd3
--- /dev/null
+++ b/tools/mkimage/patches/040-include_order.patch
@@ -0,0 +1,11 @@
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -194,7 +194,7 @@ endif # !LOGO_BMP
+ # Define _GNU_SOURCE to obtain the getline prototype from stdio.h
+ #
+ HOST_EXTRACFLAGS += -include $(srctree)/include/libfdt_env.h \
+-		$(patsubst -I%,-idirafter%, $(filter -I%, $(UBOOTINCLUDE))) \
++		-I$(srctree)/include \
+ 		-I$(srctree)/lib/libfdt \
+ 		-I$(srctree)/tools \
+ 		-DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE) \
diff --git a/tools/mkimage/patches/050-image_h_portability.patch b/tools/mkimage/patches/050-image_h_portability.patch
new file mode 100644
index 0000000000..b3ad27388c
--- /dev/null
+++ b/tools/mkimage/patches/050-image_h_portability.patch
@@ -0,0 +1,31 @@
+--- a/include/image.h
++++ b/include/image.h
+@@ -17,7 +17,6 @@
+ #define __IMAGE_H__
+ 
+ #include "compiler.h"
+-#include <asm/byteorder.h>
+ 
+ /* Define this to avoid #ifdefs later on */
+ struct lmb;
+@@ -258,13 +257,13 @@ struct lmb;
+  * all data in network byte order (aka natural aka bigendian).
+  */
+ typedef struct image_header {
+-	__be32		ih_magic;	/* Image Header Magic Number	*/
+-	__be32		ih_hcrc;	/* Image Header CRC Checksum	*/
+-	__be32		ih_time;	/* Image Creation Timestamp	*/
+-	__be32		ih_size;	/* Image Data Size		*/
+-	__be32		ih_load;	/* Data	 Load  Address		*/
+-	__be32		ih_ep;		/* Entry Point Address		*/
+-	__be32		ih_dcrc;	/* Image Data CRC Checksum	*/
++	uint32_t	ih_magic;	/* Image Header Magic Number	*/
++	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
++	uint32_t	ih_time;	/* Image Creation Timestamp	*/
++	uint32_t	ih_size;	/* Image Data Size		*/
++	uint32_t	ih_load;	/* Data	 Load  Address		*/
++	uint32_t	ih_ep;		/* Entry Point Address		*/
++	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+ 	uint8_t		ih_os;		/* Operating System		*/
+ 	uint8_t		ih_arch;	/* CPU architecture		*/
+ 	uint8_t		ih_type;	/* Image Type			*/
diff --git a/tools/mkimage/patches/060-remove_kernel_includes.patch b/tools/mkimage/patches/060-remove_kernel_includes.patch
new file mode 100644
index 0000000000..fa533cd22d
--- /dev/null
+++ b/tools/mkimage/patches/060-remove_kernel_includes.patch
@@ -0,0 +1,35 @@
+--- a/include/compiler.h
++++ b/include/compiler.h
+@@ -58,6 +58,11 @@ typedef uint8_t __u8;
+ typedef uint16_t __u16;
+ typedef uint32_t __u32;
+ typedef unsigned int uint;
++typedef uint64_t __u64;
++#ifndef linux
++typedef int __kernel_daddr_t;
++typedef unsigned int __kernel_ino_t;
++#endif
+ 
+ #define uswap_16(x) \
+ 	((((x) & 0xff00) >> 8) | \
+--- a/include/linux/posix_types.h
++++ b/include/linux/posix_types.h
+@@ -43,6 +43,8 @@ typedef void (*__kernel_sighandler_t)(in
+ /* Type of a SYSV IPC key.  */
+ typedef int __kernel_key_t;
+ 
++#ifdef linux
+ #include <asm/posix_types.h>
++#endif
+ 
+ #endif /* _LINUX_POSIX_TYPES_H */
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -2,7 +2,6 @@
+ #define _LINUX_TYPES_H
+ 
+ #include <linux/posix_types.h>
+-#include <asm/types.h>
+ #include <stdbool.h>
+ 
+ #ifndef __KERNEL_STRICT_NAMES
diff --git a/tools/mkimage/patches/070-socfpgaimage_portability.patch b/tools/mkimage/patches/070-socfpgaimage_portability.patch
new file mode 100644
index 0000000000..e273c275d0
--- /dev/null
+++ b/tools/mkimage/patches/070-socfpgaimage_portability.patch
@@ -0,0 +1,52 @@
+--- a/tools/socfpgaimage.c
++++ b/tools/socfpgaimage.c
+@@ -74,12 +74,12 @@ static uint16_t hdr_checksum(struct socf
+ static void build_header(uint8_t *buf, uint8_t version, uint8_t flags,
+ 			 uint16_t length_bytes)
+ {
+-	header.validation = htole32(VALIDATION_WORD);
++	header.validation = cpu_to_le32(VALIDATION_WORD);
+ 	header.version = version;
+ 	header.flags = flags;
+-	header.length_u32 = htole16(length_bytes/4);
++	header.length_u32 = cpu_to_le16(length_bytes/4);
+ 	header.zero = 0;
+-	header.checksum = htole16(hdr_checksum(&header));
++	header.checksum = cpu_to_le16(hdr_checksum(&header));
+ 
+ 	memcpy(buf, &header, sizeof(header));
+ }
+@@ -92,12 +92,12 @@ static int verify_header(const uint8_t *
+ {
+ 	memcpy(&header, buf, sizeof(header));
+ 
+-	if (le32toh(header.validation) != VALIDATION_WORD)
++	if (le32_to_cpu(header.validation) != VALIDATION_WORD)
+ 		return -1;
+-	if (le16toh(header.checksum) != hdr_checksum(&header))
++	if (le16_to_cpu(header.checksum) != hdr_checksum(&header))
+ 		return -1;
+ 
+-	return le16toh(header.length_u32) * 4;
++	return le16_to_cpu(header.length_u32) * 4;
+ }
+ 
+ /* Sign the buffer and return the signed buffer size */
+@@ -116,7 +116,7 @@ static int sign_buffer(uint8_t *buf,
+ 	/* Calculate and apply the CRC */
+ 	calc_crc = ~pbl_crc32(0, (char *)buf, len);
+ 
+-	*((uint32_t *)(buf + len)) = htole32(calc_crc);
++	*((uint32_t *)(buf + len)) = cpu_to_le32(calc_crc);
+ 
+ 	if (!pad_64k)
+ 		return len + 4;
+@@ -150,7 +150,7 @@ static int verify_buffer(const uint8_t *
+ 
+ 	calc_crc = ~pbl_crc32(0, (const char *)buf, len);
+ 
+-	buf_crc = le32toh(*((uint32_t *)(buf + len)));
++	buf_crc = le32_to_cpu(*((uint32_t *)(buf + len)));
+ 
+ 	if (buf_crc != calc_crc) {
+ 		fprintf(stderr, "CRC32 does not match (%08x != %08x)\n",
diff --git a/tools/mkimage/patches/080-remove_compiler_check.patch b/tools/mkimage/patches/080-remove_compiler_check.patch
new file mode 100644
index 0000000000..3e71ad5b07
--- /dev/null
+++ b/tools/mkimage/patches/080-remove_compiler_check.patch
@@ -0,0 +1,16 @@
+--- a/include/linux/compiler-gcc4.h
++++ b/include/linux/compiler-gcc4.h
+@@ -2,13 +2,6 @@
+ #error "Please don't include <linux/compiler-gcc4.h> directly, include <linux/compiler.h> instead."
+ #endif
+ 
+-/* GCC 4.1.[01] miscompiles __weak */
+-#ifdef __KERNEL__
+-# if GCC_VERSION >= 40100 &&  GCC_VERSION <= 40101
+-#  error Your version of gcc miscompiles the __weak directive
+-# endif
+-#endif
+-
+ #define __used			__attribute__((__used__))
+ #define __must_check 		__attribute__((warn_unused_result))
+ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
diff --git a/tools/mkimage/patches/090-reproducible-SOURCE_DATE_EPOCH.patch b/tools/mkimage/patches/090-reproducible-SOURCE_DATE_EPOCH.patch
new file mode 100644
index 0000000000..c238fd62ed
--- /dev/null
+++ b/tools/mkimage/patches/090-reproducible-SOURCE_DATE_EPOCH.patch
@@ -0,0 +1,82 @@
+From f3f431a712729a1af94d01bd1bfde17a252ff02c Mon Sep 17 00:00:00 2001
+From: Paul Kocialkowski <contact@paulk.fr>
+Date: Sun, 26 Jul 2015 18:48:15 +0200
+Subject: [PATCH] Reproducible U-Boot build support, using SOURCE_DATE_EPOCH
+
+In order to achieve reproducible builds in U-Boot, timestamps that are defined
+at build-time have to be somewhat eliminated. The SOURCE_DATE_EPOCH environment
+variable allows setting a fixed value for those timestamps.
+
+Simply by setting SOURCE_DATE_EPOCH to a fixed value, a number of targets can be
+built reproducibly. This is the case for e.g. sunxi devices.
+
+However, some other devices might need some more tweaks, especially regarding
+the image generation tools.
+
+Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
+---
+ Makefile              |  7 ++++---
+ README                | 12 ++++++++++++
+ tools/default_image.c | 21 ++++++++++++++++++++-
+ 3 files changed, 36 insertions(+), 4 deletions(-)
+
+--- a/README
++++ b/README
+@@ -4928,6 +4928,18 @@ within that device.
+ 	normal addressable memory via the LBC. CONFIG_SYS_LS_MC_FW_ADDR is the
+ 	virtual address in NOR flash.
+ 
++Reproducible builds
++-------------------
++
++In order to achieve reproducible builds, timestamps used in the U-Boot build
++process have to be set to a fixed value.
++
++This is done using the SOURCE_DATE_EPOCH environment variable.
++SOURCE_DATE_EPOCH is to be set on the build host's shell, not as a configuration
++option for U-Boot or an environment variable in U-Boot.
++
++SOURCE_DATE_EPOCH should be set to a number of seconds since the epoch, in UTC.
++
+ Building the Software:
+ ======================
+ 
+--- a/tools/default_image.c
++++ b/tools/default_image.c
+@@ -89,6 +89,9 @@ static void image_set_header(void *ptr,
+ 				struct image_tool_params *params)
+ {
+ 	uint32_t checksum;
++	char *source_date_epoch;
++	struct tm *time_universal;
++	time_t time;
+ 
+ 	image_header_t * hdr = (image_header_t *)ptr;
+ 
+@@ -97,9 +100,25 @@ static void image_set_header(void *ptr,
+ 				sizeof(image_header_t)),
+ 			sbuf->st_size - sizeof(image_header_t));
+ 
++	source_date_epoch = getenv("SOURCE_DATE_EPOCH");
++	if (source_date_epoch != NULL) {
++		time = (time_t) strtol(source_date_epoch, NULL, 10);
++
++		time_universal = gmtime(&time);
++		if (time_universal == NULL) {
++			fprintf(stderr, "%s: SOURCE_DATE_EPOCH is not valid\n",
++				__func__);
++			time = 0;
++		} else {
++			time = mktime(time_universal);
++		}
++	} else {
++		time = sbuf->st_mtime;
++	}
++
+ 	/* Build new header */
+ 	image_set_magic(hdr, params->magic);
+-	image_set_time(hdr, sbuf->st_mtime);
++	image_set_time(hdr, time);
+ 	image_set_size(hdr, sbuf->st_size - sizeof(image_header_t));
+ 	image_set_load(hdr, params->addr);
+ 	image_set_ep(hdr, params->ep);
diff --git a/tools/mkimage/patches/100-freebsd-compat.patch b/tools/mkimage/patches/100-freebsd-compat.patch
new file mode 100644
index 0000000000..e014af5708
--- /dev/null
+++ b/tools/mkimage/patches/100-freebsd-compat.patch
@@ -0,0 +1,14 @@
+--- a/Makefile
++++ b/Makefile
+@@ -584,7 +584,10 @@ UBOOTINCLUDE    := \
+ 		-I$(srctree)/arch/$(ARCH)/include \
+ 		-include $(srctree)/include/linux/kconfig.h
+ 
+-NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
++ifneq ($(shell uname),FreeBSD)
++  NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
++endif
++
+ CHECKFLAGS     += $(NOSTDINC_FLAGS)
+ 
+ # FIX ME
diff --git a/tools/mkimage/patches/200-compiler-support.patch b/tools/mkimage/patches/200-compiler-support.patch
new file mode 100644
index 0000000000..ca9c5b5a30
--- /dev/null
+++ b/tools/mkimage/patches/200-compiler-support.patch
@@ -0,0 +1,702 @@
+diff --git b/include/linux/compiler-gcc.h a/include/linux/compiler-gcc.h
+index e057bd2..22ab246 100644
+--- b/include/linux/compiler-gcc.h
++++ a/include/linux/compiler-gcc.h
+@@ -5,14 +5,28 @@
+ /*
+  * Common definitions for all gcc versions go here.
+  */
+-#define GCC_VERSION (__GNUC__ * 10000 \
+-		   + __GNUC_MINOR__ * 100 \
+-		   + __GNUC_PATCHLEVEL__)
+-
++#define GCC_VERSION (__GNUC__ * 10000		\
++		     + __GNUC_MINOR__ * 100	\
++		     + __GNUC_PATCHLEVEL__)
+ 
+ /* Optimization barrier */
++
+ /* The "volatile" is due to gcc bugs */
+ #define barrier() __asm__ __volatile__("": : :"memory")
++/*
++ * This version is i.e. to prevent dead stores elimination on @ptr
++ * where gcc and llvm may behave differently when otherwise using
++ * normal barrier(): while gcc behavior gets along with a normal
++ * barrier(), llvm needs an explicit input variable to be assumed
++ * clobbered. The issue is as follows: while the inline asm might
++ * access any memory it wants, the compiler could have fit all of
++ * @ptr into memory registers instead, and since @ptr never escaped
++ * from that, it proofed that the inline asm wasn't touching any of
++ * it. This version works well with both compilers, i.e. we're telling
++ * the compiler that the inline asm absolutely may see the contents
++ * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495
++ */
++#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory")
+ 
+ /*
+  * This macro obfuscates arithmetic on a variable address so that gcc
+@@ -32,58 +46,63 @@
+  * the inline assembly constraint from =g to =r, in this particular
+  * case either is valid.
+  */
+-#define RELOC_HIDE(ptr, off)					\
+-  ({ unsigned long __ptr;					\
+-    __asm__ ("" : "=r"(__ptr) : "0"(ptr));		\
+-    (typeof(ptr)) (__ptr + (off)); })
++#define RELOC_HIDE(ptr, off)						\
++({									\
++	unsigned long __ptr;						\
++	__asm__ ("" : "=r"(__ptr) : "0"(ptr));				\
++	(typeof(ptr)) (__ptr + (off));					\
++})
+ 
+ /* Make the optimizer believe the variable can be manipulated arbitrarily. */
+-#define OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "=r" (var) : "0" (var))
++#define OPTIMIZER_HIDE_VAR(var)						\
++	__asm__ ("" : "=r" (var) : "0" (var))
+ 
+ #ifdef __CHECKER__
+-#define __must_be_array(arr) 0
++#define __must_be_array(a)	0
+ #else
+ /* &a[0] degrades to a pointer: a different type from an array */
+-#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
++#define __must_be_array(a)	BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
+ #endif
+ 
+ /*
+  * Force always-inline if the user requests it so via the .config,
+  * or if gcc is too old:
+  */
+-#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
++#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
+     !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
+-# define inline		inline		__attribute__((always_inline)) notrace
+-# define __inline__	__inline__	__attribute__((always_inline)) notrace
+-# define __inline	__inline	__attribute__((always_inline)) notrace
++#define inline		inline		__attribute__((always_inline)) notrace
++#define __inline__	__inline__	__attribute__((always_inline)) notrace
++#define __inline	__inline	__attribute__((always_inline)) notrace
+ #else
+ /* A lot of inline functions can cause havoc with function tracing */
+-# define inline		inline		notrace
+-# define __inline__	__inline__	notrace
+-# define __inline	__inline	notrace
++#define inline		inline		notrace
++#define __inline__	__inline__	notrace
++#define __inline	__inline	notrace
+ #endif
+ 
+-#define __deprecated			__attribute__((deprecated))
+-#ifndef __packed
+-#define __packed			__attribute__((packed))
+-#endif
+-#ifndef __weak
+-#define __weak				__attribute__((weak))
+-#endif
++#define __always_inline	inline __attribute__((always_inline))
++#define  noinline	__attribute__((noinline))
++
++#define __deprecated	__attribute__((deprecated))
++#define __packed	__attribute__((packed))
++#define __weak		__attribute__((weak))
++#define __alias(symbol)	__attribute__((alias(#symbol)))
+ 
+ /*
+- * it doesn't make sense on ARM (currently the only user of __naked) to trace
+- * naked functions because then mcount is called without stack and frame pointer
+- * being set up and there is no chance to restore the lr register to the value
+- * before mcount was called.
++ * it doesn't make sense on ARM (currently the only user of __naked)
++ * to trace naked functions because then mcount is called without
++ * stack and frame pointer being set up and there is no chance to
++ * restore the lr register to the value before mcount was called.
++ *
++ * The asm() bodies of naked functions often depend on standard calling
++ * conventions, therefore they must be noinline and noclone.
+  *
+- * The asm() bodies of naked functions often depend on standard calling conventions,
+- * therefore they must be noinline and noclone.  GCC 4.[56] currently fail to enforce
+- * this, so we must do so ourselves.  See GCC PR44290.
++ * GCC 4.[56] currently fail to enforce this, so we must do so ourselves.
++ * See GCC PR44290.
+  */
+-#define __naked				__attribute__((naked)) noinline __noclone notrace
++#define __naked		__attribute__((naked)) noinline __noclone notrace
+ 
+-#define __noreturn			__attribute__((noreturn))
++#define __noreturn	__attribute__((noreturn))
+ 
+ /*
+  * From the GCC manual:
+@@ -95,34 +114,170 @@
+  * would be.
+  * [...]
+  */
+-#ifndef __pure
+-#define __pure				__attribute__((pure))
++#define __pure			__attribute__((pure))
++#define __aligned(x)		__attribute__((aligned(x)))
++#define __printf(a, b)		__attribute__((format(printf, a, b)))
++#define __scanf(a, b)		__attribute__((format(scanf, a, b)))
++#define __attribute_const__	__attribute__((__const__))
++#define __maybe_unused		__attribute__((unused))
++#define __always_unused		__attribute__((unused))
++
++/* gcc version specific checks */
++
++#if GCC_VERSION < 30200
++# error Sorry, your compiler is too old - please upgrade it.
++#endif
++
++#if GCC_VERSION < 30300
++# define __used			__attribute__((__unused__))
++#else
++# define __used			__attribute__((__used__))
++#endif
++
++#ifdef CONFIG_GCOV_KERNEL
++# if GCC_VERSION < 30400
++#   error "GCOV profiling support for gcc versions below 3.4 not included"
++# endif /* __GNUC_MINOR__ */
++#endif /* CONFIG_GCOV_KERNEL */
++
++#if GCC_VERSION >= 30400
++#define __must_check		__attribute__((warn_unused_result))
++#endif
++
++#if GCC_VERSION >= 40000
++
++/* GCC 4.1.[01] miscompiles __weak */
++#ifdef __KERNEL__
++# if GCC_VERSION >= 40100 &&  GCC_VERSION <= 40101
++#  error Your version of gcc miscompiles the __weak directive
++# endif
++#endif
++
++#define __used			__attribute__((__used__))
++#define __compiler_offsetof(a, b)					\
++	__builtin_offsetof(a, b)
++
++#if GCC_VERSION >= 40100 && GCC_VERSION < 40600
++# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
++#endif
++
++#if GCC_VERSION >= 40300
++/* Mark functions as cold. gcc will assume any path leading to a call
++ * to them will be unlikely.  This means a lot of manual unlikely()s
++ * are unnecessary now for any paths leading to the usual suspects
++ * like BUG(), printk(), panic() etc. [but let's keep them for now for
++ * older compilers]
++ *
++ * Early snapshots of gcc 4.3 don't support this and we can't detect this
++ * in the preprocessor, but we can live with this because they're unreleased.
++ * Maketime probing would be overkill here.
++ *
++ * gcc also has a __attribute__((__hot__)) to move hot functions into
++ * a special section, but I don't see any sense in this right now in
++ * the kernel context
++ */
++#define __cold			__attribute__((__cold__))
++
++#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
++
++#ifndef __CHECKER__
++# define __compiletime_warning(message) __attribute__((warning(message)))
++# define __compiletime_error(message) __attribute__((error(message)))
++#endif /* __CHECKER__ */
++#endif /* GCC_VERSION >= 40300 */
++
++#if GCC_VERSION >= 40500
++/*
++ * Mark a position in code as unreachable.  This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ *
++ * Early snapshots of gcc 4.5 don't support this and we can't detect
++ * this in the preprocessor, but we can live with this because they're
++ * unreleased.  Really, we need to have autoconf for the kernel.
++ */
++#define unreachable() __builtin_unreachable()
++
++/* Mark a function definition as prohibited from being cloned. */
++#define __noclone	__attribute__((__noclone__))
++
++#endif /* GCC_VERSION >= 40500 */
++
++#if GCC_VERSION >= 40600
++/*
++ * When used with Link Time Optimization, gcc can optimize away C functions or
++ * variables which are referenced only from assembly code.  __visible tells the
++ * optimizer that something else uses this function or variable, thus preventing
++ * this.
++ */
++#define __visible	__attribute__((externally_visible))
+ #endif
+-#ifndef __aligned
+-#define __aligned(x)			__attribute__((aligned(x)))
++
++
++#if GCC_VERSION >= 40900 && !defined(__CHECKER__)
++/*
++ * __assume_aligned(n, k): Tell the optimizer that the returned
++ * pointer can be assumed to be k modulo n. The second argument is
++ * optional (default 0), so we use a variadic macro to make the
++ * shorthand.
++ *
++ * Beware: Do not apply this to functions which may return
++ * ERR_PTRs. Also, it is probably unwise to apply it to functions
++ * returning extra information in the low bits (but in that case the
++ * compiler should see some alignment anyway, when the return value is
++ * massaged by 'flags = ptr & 3; ptr &= ~3;').
++ */
++#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__)))
+ #endif
+-#define __printf(a, b)			__attribute__((format(printf, a, b)))
+-#define __scanf(a, b)			__attribute__((format(scanf, a, b)))
+-#define  noinline			__attribute__((noinline))
+-#define __attribute_const__		__attribute__((__const__))
+-#define __maybe_unused			__attribute__((unused))
+-#define __always_unused			__attribute__((unused))
+ 
+-#define __gcc_header(x) #x
+-#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
+-#define gcc_header(x) _gcc_header(x)
+-#include gcc_header(__GNUC__)
++/*
++ * GCC 'asm goto' miscompiles certain code sequences:
++ *
++ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
++ *
++ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
++ *
++ * (asm goto is automatically volatile - the naming reflects this.)
++ */
++#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
++
++#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
++#if GCC_VERSION >= 40400
++#define __HAVE_BUILTIN_BSWAP32__
++#define __HAVE_BUILTIN_BSWAP64__
++#endif
++#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600)
++#define __HAVE_BUILTIN_BSWAP16__
++#endif
++#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
++
++#if GCC_VERSION >= 50000
++#define KASAN_ABI_VERSION 4
++#elif GCC_VERSION >= 40902
++#define KASAN_ABI_VERSION 3
++#endif
++
++#if GCC_VERSION >= 40902
++/*
++ * Tell the compiler that address safety instrumentation (KASAN)
++ * should not be applied to that function.
++ * Conflicts with inlining: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
++ */
++#define __no_sanitize_address __attribute__((no_sanitize_address))
++#endif
++
++#endif	/* gcc version >= 40000 specific checks */
+ 
+ #if !defined(__noclone)
+ #define __noclone	/* not needed */
+ #endif
+ 
++#if !defined(__no_sanitize_address)
++#define __no_sanitize_address
++#endif
++
+ /*
+  * A trick to suppress uninitialized variable warning without generating any
+  * code
+  */
+ #define uninitialized_var(x) x = x
+-
+-#ifndef __always_inline
+-#define __always_inline		inline __attribute__((always_inline))
+-#endif
+diff --git b/include/linux/compiler-gcc3.h a/include/linux/compiler-gcc3.h
+deleted file mode 100644
+index 7d89feb..0000000
+--- b/include/linux/compiler-gcc3.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-#ifndef __LINUX_COMPILER_H
+-#error "Please don't include <linux/compiler-gcc3.h> directly, include <linux/compiler.h> instead."
+-#endif
+-
+-#if GCC_VERSION < 30200
+-# error Sorry, your compiler is too old - please upgrade it.
+-#endif
+-
+-#if GCC_VERSION >= 30300
+-# define __used			__attribute__((__used__))
+-#else
+-# define __used			__attribute__((__unused__))
+-#endif
+-
+-#if GCC_VERSION >= 30400
+-#define __must_check		__attribute__((warn_unused_result))
+-#endif
+-
+-#ifdef CONFIG_GCOV_KERNEL
+-# if GCC_VERSION < 30400
+-#   error "GCOV profiling support for gcc versions below 3.4 not included"
+-# endif /* __GNUC_MINOR__ */
+-#endif /* CONFIG_GCOV_KERNEL */
+diff --git b/include/linux/compiler-gcc4.h a/include/linux/compiler-gcc4.h
+deleted file mode 100644
+index c982a09..0000000
+--- b/include/linux/compiler-gcc4.h
++++ /dev/null
+@@ -1,81 +0,0 @@
+-#ifndef __LINUX_COMPILER_H
+-#error "Please don't include <linux/compiler-gcc4.h> directly, include <linux/compiler.h> instead."
+-#endif
+-
+-#define __used			__attribute__((__used__))
+-#define __must_check 		__attribute__((warn_unused_result))
+-#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
+-
+-#if GCC_VERSION >= 40100 && GCC_VERSION < 40600
+-# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
+-#endif
+-
+-#if GCC_VERSION >= 40300
+-/* Mark functions as cold. gcc will assume any path leading to a call
+-   to them will be unlikely.  This means a lot of manual unlikely()s
+-   are unnecessary now for any paths leading to the usual suspects
+-   like BUG(), printk(), panic() etc. [but let's keep them for now for
+-   older compilers]
+-
+-   Early snapshots of gcc 4.3 don't support this and we can't detect this
+-   in the preprocessor, but we can live with this because they're unreleased.
+-   Maketime probing would be overkill here.
+-
+-   gcc also has a __attribute__((__hot__)) to move hot functions into
+-   a special section, but I don't see any sense in this right now in
+-   the kernel context */
+-#define __cold			__attribute__((__cold__))
+-
+-#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+-
+-#ifndef __CHECKER__
+-# define __compiletime_warning(message) __attribute__((warning(message)))
+-# define __compiletime_error(message) __attribute__((error(message)))
+-#endif /* __CHECKER__ */
+-#endif /* GCC_VERSION >= 40300 */
+-
+-#if GCC_VERSION >= 40500
+-/*
+- * Mark a position in code as unreachable.  This can be used to
+- * suppress control flow warnings after asm blocks that transfer
+- * control elsewhere.
+- *
+- * Early snapshots of gcc 4.5 don't support this and we can't detect
+- * this in the preprocessor, but we can live with this because they're
+- * unreleased.  Really, we need to have autoconf for the kernel.
+- */
+-#define unreachable() __builtin_unreachable()
+-
+-/* Mark a function definition as prohibited from being cloned. */
+-#define __noclone	__attribute__((__noclone__))
+-
+-#endif /* GCC_VERSION >= 40500 */
+-
+-#if GCC_VERSION >= 40600
+-/*
+- * Tell the optimizer that something else uses this function or variable.
+- */
+-#define __visible __attribute__((externally_visible))
+-#endif
+-
+-/*
+- * GCC 'asm goto' miscompiles certain code sequences:
+- *
+- *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
+- *
+- * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
+- * Fixed in GCC 4.8.2 and later versions.
+- *
+- * (asm goto is automatically volatile - the naming reflects this.)
+- */
+-#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
+-
+-#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
+-#if GCC_VERSION >= 40400
+-#define __HAVE_BUILTIN_BSWAP32__
+-#define __HAVE_BUILTIN_BSWAP64__
+-#endif
+-#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600)
+-#define __HAVE_BUILTIN_BSWAP16__
+-#endif
+-#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
+diff --git b/include/linux/compiler-intel.h a/include/linux/compiler-intel.h
+index ba147a1..d4c7113 100644
+--- b/include/linux/compiler-intel.h
++++ a/include/linux/compiler-intel.h
+@@ -13,9 +13,14 @@
+ /* Intel ECC compiler doesn't support gcc specific asm stmts.
+  * It uses intrinsics to do the equivalent things.
+  */
++#undef barrier
++#undef barrier_data
+ #undef RELOC_HIDE
+ #undef OPTIMIZER_HIDE_VAR
+ 
++#define barrier() __memory_barrier()
++#define barrier_data(ptr) barrier()
++
+ #define RELOC_HIDE(ptr, off)					\
+   ({ unsigned long __ptr;					\
+      __ptr = (unsigned long) (ptr);				\
+diff --git b/include/linux/compiler.h a/include/linux/compiler.h
+index d5ad7b1..020ad16 100644
+--- b/include/linux/compiler.h
++++ a/include/linux/compiler.h
+@@ -17,6 +17,7 @@
+ # define __release(x)	__context__(x,-1)
+ # define __cond_lock(x,c)	((c) ? ({ __acquire(x); 1; }) : 0)
+ # define __percpu	__attribute__((noderef, address_space(3)))
++# define __pmem		__attribute__((noderef, address_space(5)))
+ #ifdef CONFIG_SPARSE_RCU_POINTER
+ # define __rcu		__attribute__((noderef, address_space(4)))
+ #else
+@@ -42,6 +43,7 @@ extern void __chk_io_ptr(const volatile void __iomem *);
+ # define __cond_lock(x,c) (c)
+ # define __percpu
+ # define __rcu
++# define __pmem
+ #endif
+ 
+ /* Indirect macros required for expanded argument pasting, eg. __LINE__. */
+@@ -54,7 +56,11 @@ extern void __chk_io_ptr(const volatile void __iomem *);
+ #include <linux/compiler-gcc.h>
+ #endif
+ 
++#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__)
++#define notrace __attribute__((hotpatch(0,0)))
++#else
+ #define notrace __attribute__((no_instrument_function))
++#endif
+ 
+ /* Intel compiler defines __GNUC__. So we will overwrite implementations
+  * coming from above header files here
+@@ -138,7 +144,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+  */
+ #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
+ #define __trace_if(cond) \
+-	if (__builtin_constant_p((cond)) ? !!(cond) :			\
++	if (__builtin_constant_p(!!(cond)) ? !!(cond) :			\
+ 	({								\
+ 		int ______r;						\
+ 		static struct ftrace_branch_data			\
+@@ -165,6 +171,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ # define barrier() __memory_barrier()
+ #endif
+ 
++#ifndef barrier_data
++# define barrier_data(ptr) barrier()
++#endif
++
+ /* Unreachable code */
+ #ifndef unreachable
+ # define unreachable() do { } while (1)
+@@ -186,6 +196,126 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
+ #endif
+ 
++#include <linux/types.h>
++
++#define __READ_ONCE_SIZE						\
++({									\
++	switch (size) {							\
++	case 1: *(__u8 *)res = *(volatile __u8 *)p; break;		\
++	case 2: *(__u16 *)res = *(volatile __u16 *)p; break;		\
++	case 4: *(__u32 *)res = *(volatile __u32 *)p; break;		\
++	case 8: *(__u64 *)res = *(volatile __u64 *)p; break;		\
++	default:							\
++		barrier();						\
++		__builtin_memcpy((void *)res, (const void *)p, size);	\
++		barrier();						\
++	}								\
++})
++
++static __always_inline
++void __read_once_size(const volatile void *p, void *res, int size)
++{
++	__READ_ONCE_SIZE;
++}
++
++#ifdef CONFIG_KASAN
++/*
++ * This function is not 'inline' because __no_sanitize_address confilcts
++ * with inlining. Attempt to inline it may cause a build failure.
++ * 	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
++ * '__maybe_unused' allows us to avoid defined-but-not-used warnings.
++ */
++static __no_sanitize_address __maybe_unused
++void __read_once_size_nocheck(const volatile void *p, void *res, int size)
++{
++	__READ_ONCE_SIZE;
++}
++#else
++static __always_inline
++void __read_once_size_nocheck(const volatile void *p, void *res, int size)
++{
++	__READ_ONCE_SIZE;
++}
++#endif
++
++static __always_inline void __write_once_size(volatile void *p, void *res, int size)
++{
++	switch (size) {
++	case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
++	case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
++	case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
++	case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
++	default:
++		barrier();
++		__builtin_memcpy((void *)p, (const void *)res, size);
++		barrier();
++	}
++}
++
++/*
++ * Prevent the compiler from merging or refetching reads or writes. The
++ * compiler is also forbidden from reordering successive instances of
++ * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the
++ * compiler is aware of some particular ordering.  One way to make the
++ * compiler aware of ordering is to put the two invocations of READ_ONCE,
++ * WRITE_ONCE or ACCESS_ONCE() in different C statements.
++ *
++ * In contrast to ACCESS_ONCE these two macros will also work on aggregate
++ * data types like structs or unions. If the size of the accessed data
++ * type exceeds the word size of the machine (e.g., 32 bits or 64 bits)
++ * READ_ONCE() and WRITE_ONCE()  will fall back to memcpy and print a
++ * compile-time warning.
++ *
++ * Their two major use cases are: (1) Mediating communication between
++ * process-level code and irq/NMI handlers, all running on the same CPU,
++ * and (2) Ensuring that the compiler does not  fold, spindle, or otherwise
++ * mutilate accesses that either do not require ordering or that interact
++ * with an explicit memory barrier or atomic instruction that provides the
++ * required ordering.
++ */
++
++#define __READ_ONCE(x, check)						\
++({									\
++	union { typeof(x) __val; char __c[1]; } __u;			\
++	if (check)							\
++		__read_once_size(&(x), __u.__c, sizeof(x));		\
++	else								\
++		__read_once_size_nocheck(&(x), __u.__c, sizeof(x));	\
++	__u.__val;							\
++})
++#define READ_ONCE(x) __READ_ONCE(x, 1)
++
++/*
++ * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need
++ * to hide memory access from KASAN.
++ */
++#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
++
++#define WRITE_ONCE(x, val) \
++({							\
++	union { typeof(x) __val; char __c[1]; } __u =	\
++		{ .__val = (__force typeof(x)) (val) }; \
++	__write_once_size(&(x), __u.__c, sizeof(x));	\
++	__u.__val;					\
++})
++
++/**
++ * smp_cond_acquire() - Spin wait for cond with ACQUIRE ordering
++ * @cond: boolean expression to wait for
++ *
++ * Equivalent to using smp_load_acquire() on the condition variable but employs
++ * the control dependency of the wait to reduce the barrier on many platforms.
++ *
++ * The control dependency provides a LOAD->STORE order, the additional RMB
++ * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
++ * aka. ACQUIRE.
++ */
++#define smp_cond_acquire(cond)	do {		\
++	while (!(cond))				\
++		cpu_relax();			\
++	smp_rmb(); /* ctrl + rmb := acquire */	\
++} while (0)
++
+ #endif /* __KERNEL__ */
+ 
+ #endif /* __ASSEMBLY__ */
+@@ -304,6 +434,14 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ #define __visible
+ #endif
+ 
++/*
++ * Assume alignment of return value.
++ */
++#ifndef __assume_aligned
++#define __assume_aligned(a, ...)
++#endif
++
++
+ /* Are two types/vars the same type (ignoring qualifiers)? */
+ #ifndef __same_type
+ # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+@@ -311,7 +449,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ 
+ /* Is this type a native word size -- useful for atomic operations */
+ #ifndef __native_word
+-# define __native_word(t) (sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
++# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
+ #endif
+ 
+ /* Compile time object size, -1 for unknown */
+@@ -373,12 +511,38 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+  * to make the compiler aware of ordering is to put the two invocations of
+  * ACCESS_ONCE() in different C statements.
+  *
+- * This macro does absolutely -nothing- to prevent the CPU from reordering,
+- * merging, or refetching absolutely anything at any time.  Its main intended
+- * use is to mediate communication between process-level code and irq/NMI
+- * handlers, all running on the same CPU.
++ * ACCESS_ONCE will only work on scalar types. For union types, ACCESS_ONCE
++ * on a union member will work as long as the size of the member matches the
++ * size of the union and the size is smaller than word size.
++ *
++ * The major use cases of ACCESS_ONCE used to be (1) Mediating communication
++ * between process-level code and irq/NMI handlers, all running on the same CPU,
++ * and (2) Ensuring that the compiler does not  fold, spindle, or otherwise
++ * mutilate accesses that either do not require ordering or that interact
++ * with an explicit memory barrier or atomic instruction that provides the
++ * required ordering.
++ *
++ * If possible use READ_ONCE()/WRITE_ONCE() instead.
++ */
++#define __ACCESS_ONCE(x) ({ \
++	 __maybe_unused typeof(x) __var = (__force typeof(x)) 0; \
++	(volatile typeof(x) *)&(x); })
++#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))
++
++/**
++ * lockless_dereference() - safely load a pointer for later dereference
++ * @p: The pointer to load
++ *
++ * Similar to rcu_dereference(), but for situations where the pointed-to
++ * object's lifetime is managed by something other than RCU.  That
++ * "something other" might be reference counting or simple immortality.
+  */
+-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
++#define lockless_dereference(p) \
++({ \
++	typeof(p) _________p1 = READ_ONCE(p); \
++	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
++	(_________p1); \
++})
+ 
+ /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */
+ #ifdef CONFIG_KPROBES
diff --git a/tools/mkimage/patches/210-openssl-1.1.x-compat.patch b/tools/mkimage/patches/210-openssl-1.1.x-compat.patch
new file mode 100644
index 0000000000..b1bc08856e
--- /dev/null
+++ b/tools/mkimage/patches/210-openssl-1.1.x-compat.patch
@@ -0,0 +1,97 @@
+--- a/lib/rsa/rsa-sign.c
++++ b/lib/rsa/rsa-sign.c
+@@ -15,10 +15,25 @@
+ #include <openssl/ssl.h>
+ #include <openssl/evp.h>
+ 
+-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
++#if OPENSSL_VERSION_NUMBER < 0x10000000L
++#define HAVE_ERR_REMOVE_STATE
++#elif OPENSSL_VERSION_NUMBER < 0x10100000L
+ #define HAVE_ERR_REMOVE_THREAD_STATE
+ #endif
+ 
++#if (OPENSSL_VERSION_NUMBER < 0x10100005L) || defined(LIBRESSL_VERSION_NUMBER)
++static void RSA_get0_key(const RSA *r,
++                         const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
++{
++   if (n != NULL)
++       *n = r->n;
++   if (e != NULL)
++       *e = r->e;
++   if (d != NULL)
++       *d = r->d;
++}
++#endif
++
+ static int rsa_err(const char *msg)
+ {
+ 	unsigned long sslErr = ERR_get_error();
+@@ -154,7 +169,8 @@ static void rsa_remove(void)
+ 	ERR_free_strings();
+ #ifdef HAVE_ERR_REMOVE_THREAD_STATE
+ 	ERR_remove_thread_state(NULL);
+-#else
++#endif
++#ifdef HAVE_ERR_REMOVE_STATE
+ 	ERR_remove_state(0);
+ #endif
+ 	EVP_cleanup();
+@@ -210,7 +226,6 @@ static int rsa_sign_with_key(RSA *rsa, s
+ 		ret = rsa_err("Could not obtain signature");
+ 		goto err_sign;
+ 	}
+-	EVP_MD_CTX_cleanup(context);
+ 	EVP_MD_CTX_destroy(context);
+ 	EVP_PKEY_free(key);
+ 
+@@ -270,23 +285,26 @@ static int rsa_get_exponent(RSA *key, ui
+ 	BIGNUM *bn_te;
+ 	uint64_t te;
+ 
++	const BIGNUM *bn_e;
++	RSA_get0_key(key, NULL, &bn_e, NULL);
++
+ 	ret = -EINVAL;
+ 	bn_te = NULL;
+ 
+ 	if (!e)
+ 		goto cleanup;
+ 
+-	if (BN_num_bits(key->e) > 64)
++	if (BN_num_bits(bn_e) > 64)
+ 		goto cleanup;
+ 
+-	*e = BN_get_word(key->e);
++	*e = BN_get_word(bn_e);
+ 
+-	if (BN_num_bits(key->e) < 33) {
++	if (BN_num_bits(bn_e) < 33) {
+ 		ret = 0;
+ 		goto cleanup;
+ 	}
+ 
+-	bn_te = BN_dup(key->e);
++	bn_te = BN_dup(bn_e);
+ 	if (!bn_te)
+ 		goto cleanup;
+ 
+@@ -319,6 +337,9 @@ int rsa_get_params(RSA *key, uint64_t *e
+ 	BN_CTX *bn_ctx = BN_CTX_new();
+ 	int ret = 0;
+ 
++	const BIGNUM *bn_n;
++	RSA_get0_key(key, &bn_n, NULL, NULL);
++
+ 	/* Initialize BIGNUMs */
+ 	big1 = BN_new();
+ 	big2 = BN_new();
+@@ -337,7 +358,7 @@ int rsa_get_params(RSA *key, uint64_t *e
+ 	if (0 != rsa_get_exponent(key, exponent))
+ 		ret = -1;
+ 
+-	if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) ||
++	if (!BN_copy(n, bn_n) || !BN_set_word(big1, 1L) ||
+ 	    !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L))
+ 		ret = -1;
+ 
diff --git a/tools/mklibs/Makefile b/tools/mklibs/Makefile
new file mode 100644
index 0000000000..6bf1431b8c
--- /dev/null
+++ b/tools/mklibs/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mklibs
+PKG_VERSION:=0.1.35
+
+PKG_SOURCE:=$(PKG_NAME)_$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://ftp.de.debian.org/debian/pool/main/m/mklibs/
+PKG_MD5SUM:=3d2a4bd0bbf5ba964b0a1ecdafd1ea9a
+
+HOST_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CFLAGS += -I$(CURDIR)/include
+
+define Host/Install
+       $(INSTALL_BIN) \
+               $(HOST_BUILD_DIR)/src/mklibs \
+               $(HOST_BUILD_DIR)/src/mklibs-copy \
+               $(HOST_BUILD_DIR)/src/mklibs-readelf/mklibs-readelf \
+               $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+       rm -f $(STAGING_DIR_HOST)/bin/mklibs*
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/mklibs/include/elf.h b/tools/mklibs/include/elf.h
new file mode 100644
index 0000000000..d79635003f
--- /dev/null
+++ b/tools/mklibs/include/elf.h
@@ -0,0 +1,2559 @@
+/* This file defines standard ELF types, structures, and macros.
+   Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _ELF_H
+#define	_ELF_H 1
+
+__BEGIN_DECLS
+
+/* Standard ELF types.  */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef	int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef	int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef	int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef	int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information.  */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf32_Half	e_type;			/* Object file type */
+  Elf32_Half	e_machine;		/* Architecture */
+  Elf32_Word	e_version;		/* Object file version */
+  Elf32_Addr	e_entry;		/* Entry point virtual address */
+  Elf32_Off	e_phoff;		/* Program header table file offset */
+  Elf32_Off	e_shoff;		/* Section header table file offset */
+  Elf32_Word	e_flags;		/* Processor-specific flags */
+  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf32_Half	e_phentsize;		/* Program header table entry size */
+  Elf32_Half	e_phnum;		/* Program header table entry count */
+  Elf32_Half	e_shentsize;		/* Section header table entry size */
+  Elf32_Half	e_shnum;		/* Section header table entry count */
+  Elf32_Half	e_shstrndx;		/* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf64_Half	e_type;			/* Object file type */
+  Elf64_Half	e_machine;		/* Architecture */
+  Elf64_Word	e_version;		/* Object file version */
+  Elf64_Addr	e_entry;		/* Entry point virtual address */
+  Elf64_Off	e_phoff;		/* Program header table file offset */
+  Elf64_Off	e_shoff;		/* Section header table file offset */
+  Elf64_Word	e_flags;		/* Processor-specific flags */
+  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf64_Half	e_phentsize;		/* Program header table entry size */
+  Elf64_Half	e_phnum;		/* Program header table entry count */
+  Elf64_Half	e_shentsize;		/* Section header table entry size */
+  Elf64_Half	e_shnum;		/* Section header table entry count */
+  Elf64_Half	e_shstrndx;		/* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0		0		/* File identification byte 0 index */
+#define ELFMAG0		0x7f		/* Magic number byte 0 */
+
+#define EI_MAG1		1		/* File identification byte 1 index */
+#define ELFMAG1		'E'		/* Magic number byte 1 */
+
+#define EI_MAG2		2		/* File identification byte 2 index */
+#define ELFMAG2		'L'		/* Magic number byte 2 */
+
+#define EI_MAG3		3		/* File identification byte 3 index */
+#define ELFMAG3		'F'		/* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define	ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define EI_CLASS	4		/* File class byte index */
+#define ELFCLASSNONE	0		/* Invalid class */
+#define ELFCLASS32	1		/* 32-bit objects */
+#define ELFCLASS64	2		/* 64-bit objects */
+#define ELFCLASSNUM	3
+
+#define EI_DATA		5		/* Data encoding byte index */
+#define ELFDATANONE	0		/* Invalid data encoding */
+#define ELFDATA2LSB	1		/* 2's complement, little endian */
+#define ELFDATA2MSB	2		/* 2's complement, big endian */
+#define ELFDATANUM	3
+
+#define EI_VERSION	6		/* File version byte index */
+					/* Value must be EV_CURRENT */
+
+#define EI_OSABI	7		/* OS ABI identification */
+#define ELFOSABI_NONE		0	/* UNIX System V ABI */
+#define ELFOSABI_SYSV		0	/* Alias.  */
+#define ELFOSABI_HPUX		1	/* HP-UX */
+#define ELFOSABI_NETBSD		2	/* NetBSD.  */
+#define ELFOSABI_LINUX		3	/* Linux.  */
+#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
+#define ELFOSABI_AIX		7	/* IBM AIX.  */
+#define ELFOSABI_IRIX		8	/* SGI Irix.  */
+#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
+#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
+#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
+#define ELFOSABI_ARM		97	/* ARM */
+#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
+
+#define EI_ABIVERSION	8		/* ABI version */
+
+#define EI_PAD		9		/* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE		0		/* No file type */
+#define ET_REL		1		/* Relocatable file */
+#define ET_EXEC		2		/* Executable file */
+#define ET_DYN		3		/* Shared object file */
+#define ET_CORE		4		/* Core file */
+#define	ET_NUM		5		/* Number of defined types */
+#define ET_LOOS		0xfe00		/* OS-specific range start */
+#define ET_HIOS		0xfeff		/* OS-specific range end */
+#define ET_LOPROC	0xff00		/* Processor-specific range start */
+#define ET_HIPROC	0xffff		/* Processor-specific range end */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE		 0		/* No machine */
+#define EM_M32		 1		/* AT&T WE 32100 */
+#define EM_SPARC	 2		/* SUN SPARC */
+#define EM_386		 3		/* Intel 80386 */
+#define EM_68K		 4		/* Motorola m68k family */
+#define EM_88K		 5		/* Motorola m88k family */
+#define EM_860		 7		/* Intel 80860 */
+#define EM_MIPS		 8		/* MIPS R3000 big-endian */
+#define EM_S370		 9		/* IBM System/370 */
+#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
+
+#define EM_PARISC	15		/* HPPA */
+#define EM_VPP500	17		/* Fujitsu VPP500 */
+#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
+#define EM_960		19		/* Intel 80960 */
+#define EM_PPC		20		/* PowerPC */
+#define EM_PPC64	21		/* PowerPC 64-bit */
+#define EM_S390		22		/* IBM S390 */
+
+#define EM_V800		36		/* NEC V800 series */
+#define EM_FR20		37		/* Fujitsu FR20 */
+#define EM_RH32		38		/* TRW RH-32 */
+#define EM_RCE		39		/* Motorola RCE */
+#define EM_ARM		40		/* ARM */
+#define EM_FAKE_ALPHA	41		/* Digital Alpha */
+#define EM_SH		42		/* Hitachi SH */
+#define EM_SPARCV9	43		/* SPARC v9 64-bit */
+#define EM_TRICORE	44		/* Siemens Tricore */
+#define EM_ARC		45		/* Argonaut RISC Core */
+#define EM_H8_300	46		/* Hitachi H8/300 */
+#define EM_H8_300H	47		/* Hitachi H8/300H */
+#define EM_H8S		48		/* Hitachi H8S */
+#define EM_H8_500	49		/* Hitachi H8/500 */
+#define EM_IA_64	50		/* Intel Merced */
+#define EM_MIPS_X	51		/* Stanford MIPS-X */
+#define EM_COLDFIRE	52		/* Motorola Coldfire */
+#define EM_68HC12	53		/* Motorola M68HC12 */
+#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP		55		/* Siemens PCP */
+#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
+#define EM_NDR1		57		/* Denso NDR1 microprocessor */
+#define EM_STARCORE	58		/* Motorola Start*Core processor */
+#define EM_ME16		59		/* Toyota ME16 processor */
+#define EM_ST100	60		/* STMicroelectronic ST100 processor */
+#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64	62		/* AMD x86-64 architecture */
+#define EM_PDSP		63		/* Sony DSP Processor */
+
+#define EM_FX66		66		/* Siemens FX66 microcontroller */
+#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
+#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
+#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
+#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
+#define EM_SVX		73		/* Silicon Graphics SVx */
+#define EM_ST19		74		/* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX		75		/* Digital VAX */
+#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
+#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY	81		/* Harvard University machine-independent object files */
+#define EM_PRISM	82		/* SiTera Prism */
+#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
+#define EM_FR30		84		/* Fujitsu FR30 */
+#define EM_D10V		85		/* Mitsubishi D10V */
+#define EM_D30V		86		/* Mitsubishi D30V */
+#define EM_V850		87		/* NEC v850 */
+#define EM_M32R		88		/* Mitsubishi M32R */
+#define EM_MN10300	89		/* Matsushita MN10300 */
+#define EM_MN10200	90		/* Matsushita MN10200 */
+#define EM_PJ		91		/* picoJava */
+#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
+#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
+#define EM_NUM		95
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+#define EM_ALPHA	0x9026
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE		0		/* Invalid ELF version */
+#define EV_CURRENT	1		/* Current version */
+#define EV_NUM		2
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word	sh_name;		/* Section name (string tbl index) */
+  Elf32_Word	sh_type;		/* Section type */
+  Elf32_Word	sh_flags;		/* Section flags */
+  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf32_Off	sh_offset;		/* Section file offset */
+  Elf32_Word	sh_size;		/* Section size in bytes */
+  Elf32_Word	sh_link;		/* Link to another section */
+  Elf32_Word	sh_info;		/* Additional section information */
+  Elf32_Word	sh_addralign;		/* Section alignment */
+  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word	sh_name;		/* Section name (string tbl index) */
+  Elf64_Word	sh_type;		/* Section type */
+  Elf64_Xword	sh_flags;		/* Section flags */
+  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf64_Off	sh_offset;		/* Section file offset */
+  Elf64_Xword	sh_size;		/* Section size in bytes */
+  Elf64_Word	sh_link;		/* Link to another section */
+  Elf64_Word	sh_info;		/* Additional section information */
+  Elf64_Xword	sh_addralign;		/* Section alignment */
+  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF	0		/* Undefined section */
+#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
+#define SHN_LOPROC	0xff00		/* Start of processor-specific */
+#define SHN_BEFORE	0xff00		/* Order section before all others
+					   (Solaris).  */
+#define SHN_AFTER	0xff01		/* Order section after all others
+					   (Solaris).  */
+#define SHN_HIPROC	0xff1f		/* End of processor-specific */
+#define SHN_LOOS	0xff20		/* Start of OS-specific */
+#define SHN_HIOS	0xff3f		/* End of OS-specific */
+#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
+#define SHN_COMMON	0xfff2		/* Associated symbol is common */
+#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
+#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL	  0		/* Section header table entry unused */
+#define SHT_PROGBITS	  1		/* Program data */
+#define SHT_SYMTAB	  2		/* Symbol table */
+#define SHT_STRTAB	  3		/* String table */
+#define SHT_RELA	  4		/* Relocation entries with addends */
+#define SHT_HASH	  5		/* Symbol hash table */
+#define SHT_DYNAMIC	  6		/* Dynamic linking information */
+#define SHT_NOTE	  7		/* Notes */
+#define SHT_NOBITS	  8		/* Program space with no data (bss) */
+#define SHT_REL		  9		/* Relocation entries, no addends */
+#define SHT_SHLIB	  10		/* Reserved */
+#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY	  14		/* Array of constructors */
+#define SHT_FINI_ARRAY	  15		/* Array of destructors */
+#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
+#define SHT_GROUP	  17		/* Section group */
+#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
+#define	SHT_NUM		  19		/* Number of defined types.  */
+#define SHT_LOOS	  0x60000000	/* Start OS-specific */
+#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
+#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
+#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
+#define SHT_SUNW_move	  0x6ffffffa
+#define SHT_SUNW_COMDAT   0x6ffffffb
+#define SHT_SUNW_syminfo  0x6ffffffc
+#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
+#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
+#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
+#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
+#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
+#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
+#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
+#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
+#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE	     (1 << 0)	/* Writable */
+#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
+#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
+#define SHF_MERGE	     (1 << 4)	/* Might be merged */
+#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
+#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
+					   required */
+#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
+#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
+#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
+#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
+#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
+					   (Solaris).  */
+#define SHF_EXCLUDE	     (1 << 31)	/* Section is excluded unless
+					   referenced or allocated (Solaris).*/
+
+/* Section group handling.  */
+#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
+  Elf32_Addr	st_value;		/* Symbol value */
+  Elf32_Word	st_size;		/* Symbol size */
+  unsigned char	st_info;		/* Symbol type and binding */
+  unsigned char	st_other;		/* Symbol visibility */
+  Elf32_Section	st_shndx;		/* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
+  unsigned char	st_info;		/* Symbol type and binding */
+  unsigned char st_other;		/* Symbol visibility */
+  Elf64_Section	st_shndx;		/* Section index */
+  Elf64_Addr	st_value;		/* Symbol value */
+  Elf64_Xword	st_size;		/* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+   every dynamic symbol.  */
+
+typedef struct
+{
+  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
+  Elf32_Half si_flags;			/* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
+  Elf64_Half si_flags;			/* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto.  */
+#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
+#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags.  */
+#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
+					   loaded */
+/* Syminfo version values.  */
+#define SYMINFO_NONE		0
+#define SYMINFO_CURRENT		1
+#define SYMINFO_NUM		2
+
+
+/* How to extract and insert information held in the st_info field.  */
+
+#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)		((val) & 0xf)
+#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
+#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+
+#define STB_LOCAL	0		/* Local symbol */
+#define STB_GLOBAL	1		/* Global symbol */
+#define STB_WEAK	2		/* Weak symbol */
+#define	STB_NUM		3		/* Number of defined types.  */
+#define STB_LOOS	10		/* Start of OS-specific */
+#define STB_HIOS	12		/* End of OS-specific */
+#define STB_LOPROC	13		/* Start of processor-specific */
+#define STB_HIPROC	15		/* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_NOTYPE	0		/* Symbol type is unspecified */
+#define STT_OBJECT	1		/* Symbol is a data object */
+#define STT_FUNC	2		/* Symbol is a code object */
+#define STT_SECTION	3		/* Symbol associated with a section */
+#define STT_FILE	4		/* Symbol's name is file name */
+#define STT_COMMON	5		/* Symbol is a common data object */
+#define STT_TLS		6		/* Symbol is thread-local data object*/
+#define	STT_NUM		7		/* Number of defined types.  */
+#define STT_LOOS	10		/* Start of OS-specific */
+#define STT_HIOS	12		/* End of OS-specific */
+#define STT_LOPROC	13		/* Start of processor-specific */
+#define STT_HIPROC	15		/* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+   of a symbol hash table section.  This special index value indicates
+   the end of a chain, meaning no further symbols are found in that bucket.  */
+
+#define STN_UNDEF	0		/* End of a chain.  */
+
+
+/* How to extract and insert information held in the st_other field.  */
+
+#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
+
+/* For ELF64 the definitions are the same.  */
+#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field.  */
+#define STV_DEFAULT	0		/* Default symbol visibility rules */
+#define STV_INTERNAL	1		/* Processor specific hidden class */
+#define STV_HIDDEN	2		/* Sym unavailable in other modules */
+#define STV_PROTECTED	3		/* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL).  */
+
+typedef struct
+{
+  Elf32_Addr	r_offset;		/* Address */
+  Elf32_Word	r_info;			/* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+   Elf64_Rela structures, so we'll leave them out until Novell (or
+   whoever) gets their act together.  */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
+
+typedef struct
+{
+  Elf64_Addr	r_offset;		/* Address */
+  Elf64_Xword	r_info;			/* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA).  */
+
+typedef struct
+{
+  Elf32_Addr	r_offset;		/* Address */
+  Elf32_Word	r_info;			/* Relocation type and symbol index */
+  Elf32_Sword	r_addend;		/* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+  Elf64_Addr	r_offset;		/* Address */
+  Elf64_Xword	r_info;			/* Relocation type and symbol index */
+  Elf64_Sxword	r_addend;		/* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field.  */
+
+#define ELF32_R_SYM(val)		((val) >> 8)
+#define ELF32_R_TYPE(val)		((val) & 0xff)
+#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i)			((i) >> 32)
+#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header.  */
+
+typedef struct
+{
+  Elf32_Word	p_type;			/* Segment type */
+  Elf32_Off	p_offset;		/* Segment file offset */
+  Elf32_Addr	p_vaddr;		/* Segment virtual address */
+  Elf32_Addr	p_paddr;		/* Segment physical address */
+  Elf32_Word	p_filesz;		/* Segment size in file */
+  Elf32_Word	p_memsz;		/* Segment size in memory */
+  Elf32_Word	p_flags;		/* Segment flags */
+  Elf32_Word	p_align;		/* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word	p_type;			/* Segment type */
+  Elf64_Word	p_flags;		/* Segment flags */
+  Elf64_Off	p_offset;		/* Segment file offset */
+  Elf64_Addr	p_vaddr;		/* Segment virtual address */
+  Elf64_Addr	p_paddr;		/* Segment physical address */
+  Elf64_Xword	p_filesz;		/* Segment size in file */
+  Elf64_Xword	p_memsz;		/* Segment size in memory */
+  Elf64_Xword	p_align;		/* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type).  */
+
+#define	PT_NULL		0		/* Program header table entry unused */
+#define PT_LOAD		1		/* Loadable program segment */
+#define PT_DYNAMIC	2		/* Dynamic linking information */
+#define PT_INTERP	3		/* Program interpreter */
+#define PT_NOTE		4		/* Auxiliary information */
+#define PT_SHLIB	5		/* Reserved */
+#define PT_PHDR		6		/* Entry for header table itself */
+#define PT_TLS		7		/* Thread-local storage segment */
+#define	PT_NUM		8		/* Number of defined types */
+#define PT_LOOS		0x60000000	/* Start of OS-specific */
+#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
+#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
+#define PT_LOSUNW	0x6ffffffa
+#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
+#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
+#define PT_HISUNW	0x6fffffff
+#define PT_HIOS		0x6fffffff	/* End of OS-specific */
+#define PT_LOPROC	0x70000000	/* Start of processor-specific */
+#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X		(1 << 0)	/* Segment is executable */
+#define PF_W		(1 << 1)	/* Segment is writable */
+#define PF_R		(1 << 2)	/* Segment is readable */
+#define PF_MASKOS	0x0ff00000	/* OS-specific */
+#define PF_MASKPROC	0xf0000000	/* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
+#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
+#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
+#define NT_PRXREG	4		/* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
+#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV		6		/* Contains copy of auxv array */
+#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
+#define NT_ASRS		8		/* Contains copy of asrset struct */
+#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
+#define NT_PSINFO	13		/* Contains copy of psinfo struct */
+#define NT_PRCRED	14		/* Contains copy of prcred struct */
+#define NT_UTSNAME	15		/* Contains copy of utsname struct */
+#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct*/
+
+/* Legal values for the note segment descriptor types for object files.  */
+
+#define NT_VERSION	1		/* Contains a version string.  */
+
+
+/* Dynamic section entry.  */
+
+typedef struct
+{
+  Elf32_Sword	d_tag;			/* Dynamic entry type */
+  union
+    {
+      Elf32_Word d_val;			/* Integer value */
+      Elf32_Addr d_ptr;			/* Address value */
+    } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+  Elf64_Sxword	d_tag;			/* Dynamic entry type */
+  union
+    {
+      Elf64_Xword d_val;		/* Integer value */
+      Elf64_Addr d_ptr;			/* Address value */
+    } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type).  */
+
+#define DT_NULL		0		/* Marks end of dynamic section */
+#define DT_NEEDED	1		/* Name of needed library */
+#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
+#define DT_PLTGOT	3		/* Processor defined value */
+#define DT_HASH		4		/* Address of symbol hash table */
+#define DT_STRTAB	5		/* Address of string table */
+#define DT_SYMTAB	6		/* Address of symbol table */
+#define DT_RELA		7		/* Address of Rela relocs */
+#define DT_RELASZ	8		/* Total size of Rela relocs */
+#define DT_RELAENT	9		/* Size of one Rela reloc */
+#define DT_STRSZ	10		/* Size of string table */
+#define DT_SYMENT	11		/* Size of one symbol table entry */
+#define DT_INIT		12		/* Address of init function */
+#define DT_FINI		13		/* Address of termination function */
+#define DT_SONAME	14		/* Name of shared object */
+#define DT_RPATH	15		/* Library search path (deprecated) */
+#define DT_SYMBOLIC	16		/* Start symbol search here */
+#define DT_REL		17		/* Address of Rel relocs */
+#define DT_RELSZ	18		/* Total size of Rel relocs */
+#define DT_RELENT	19		/* Size of one Rel reloc */
+#define DT_PLTREL	20		/* Type of reloc in PLT */
+#define DT_DEBUG	21		/* For debugging; unspecified */
+#define DT_TEXTREL	22		/* Reloc might modify .text */
+#define DT_JMPREL	23		/* Address of PLT relocs */
+#define	DT_BIND_NOW	24		/* Process relocations of object */
+#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
+#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
+#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
+#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH	29		/* Library search path */
+#define DT_FLAGS	30		/* Flags for the object being loaded */
+#define DT_ENCODING	32		/* Start of encoded range */
+#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
+#define	DT_NUM		34		/* Number used */
+#define DT_LOOS		0x6000000d	/* Start of OS-specific */
+#define DT_HIOS		0x6ffff000	/* End of OS-specific */
+#define DT_LOPROC	0x70000000	/* Start of processor-specific */
+#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
+#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
+   approach.  */
+#define DT_VALRNGLO	0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
+#define DT_CHECKSUM	0x6ffffdf8
+#define DT_PLTPADSZ	0x6ffffdf9
+#define DT_MOVEENT	0x6ffffdfa
+#define DT_MOVESZ	0x6ffffdfb
+#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
+#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
+					   the following DT_* entry.  */
+#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
+#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
+#define DT_VALRNGHI	0x6ffffdff
+#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+   If any adjustment is made to the ELF object after it has been
+   built these entries will need to be adjusted.  */
+#define DT_ADDRRNGLO	0x6ffffe00
+#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
+#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
+#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
+#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
+#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
+#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
+#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
+#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
+#define DT_ADDRRNGHI	0x6ffffeff
+#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
+#define DT_ADDRNUM 10
+
+/* The versioning entry types.  The next are defined as part of the
+   GNU extension.  */
+#define DT_VERSYM	0x6ffffff0
+
+#define DT_RELACOUNT	0x6ffffff9
+#define DT_RELCOUNT	0x6ffffffa
+
+/* These were chosen by Sun.  */
+#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
+#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
+					   table */
+#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
+#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
+					   versions */
+#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+   range.  Be compatible.  */
+#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
+#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM	3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
+#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
+#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
+#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
+#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+   entry in the dynamic section.  */
+#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
+#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
+#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
+#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
+#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
+#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
+#define DF_1_TRANS	0x00000200
+#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
+#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
+#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
+#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
+#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
+#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
+#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
+
+/* Flags for the feature selection in DT_FEATURE_1.  */
+#define DTF_1_PARINIT	0x00000001
+#define DTF_1_CONFEXP	0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
+#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
+#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
+					   generally available.  */
+
+/* Version definition sections.  */
+
+typedef struct
+{
+  Elf32_Half	vd_version;		/* Version revision */
+  Elf32_Half	vd_flags;		/* Version information */
+  Elf32_Half	vd_ndx;			/* Version Index */
+  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
+  Elf32_Word	vd_hash;		/* Version name hash value */
+  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
+  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
+					   entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+  Elf64_Half	vd_version;		/* Version revision */
+  Elf64_Half	vd_flags;		/* Version information */
+  Elf64_Half	vd_ndx;			/* Version Index */
+  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
+  Elf64_Word	vd_hash;		/* Version name hash value */
+  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
+  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
+					   entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision).  */
+#define VER_DEF_NONE	0		/* No version */
+#define VER_DEF_CURRENT	1		/* Current version */
+#define VER_DEF_NUM	2		/* Given version number */
+
+/* Legal values for vd_flags (version information flags).  */
+#define VER_FLG_BASE	0x1		/* Version definition of file itself */
+#define VER_FLG_WEAK	0x2		/* Weak version identifier */
+
+/* Versym symbol index values.  */
+#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
+#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
+#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
+#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
+
+/* Auxialiary version information.  */
+
+typedef struct
+{
+  Elf32_Word	vda_name;		/* Version or dependency names */
+  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
+					   entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+  Elf64_Word	vda_name;		/* Version or dependency names */
+  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
+					   entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section.  */
+
+typedef struct
+{
+  Elf32_Half	vn_version;		/* Version of structure */
+  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
+  Elf32_Word	vn_file;		/* Offset of filename for this
+					   dependency */
+  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
+  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
+					   entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+  Elf64_Half	vn_version;		/* Version of structure */
+  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
+  Elf64_Word	vn_file;		/* Offset of filename for this
+					   dependency */
+  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
+  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
+					   entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision).  */
+#define VER_NEED_NONE	 0		/* No version */
+#define VER_NEED_CURRENT 1		/* Current version */
+#define VER_NEED_NUM	 2		/* Given version number */
+
+/* Auxiliary needed version information.  */
+
+typedef struct
+{
+  Elf32_Word	vna_hash;		/* Hash value of dependency name */
+  Elf32_Half	vna_flags;		/* Dependency specific information */
+  Elf32_Half	vna_other;		/* Unused */
+  Elf32_Word	vna_name;		/* Dependency name string offset */
+  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
+					   entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+  Elf64_Word	vna_hash;		/* Hash value of dependency name */
+  Elf64_Half	vna_flags;		/* Dependency specific information */
+  Elf64_Half	vna_other;		/* Unused */
+  Elf64_Word	vna_name;		/* Dependency name string offset */
+  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
+					   entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags.  */
+#define VER_FLG_WEAK	0x2		/* Weak version identifier */
+
+
+/* Auxiliary vector.  */
+
+/* This vector is normally only used by the program interpreter.  The
+   usual definition in an ABI supplement uses the name auxv_t.  The
+   vector is not usually defined in a standard <elf.h> file, but it
+   can't hurt.  We rename it to avoid conflicts.  The sizes of these
+   types are an arrangement between the exec server and the program
+   interpreter, so we don't fully specify them here.  */
+
+typedef struct
+{
+  int a_type;			/* Entry type */
+  union
+    {
+      long int a_val;		/* Integer value */
+      void *a_ptr;		/* Pointer value */
+      void (*a_fcn) (void);	/* Function pointer value */
+    } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+  long int a_type;		/* Entry type */
+  union
+    {
+      long int a_val;		/* Integer value */
+      void *a_ptr;		/* Pointer value */
+      void (*a_fcn) (void);	/* Function pointer value */
+    } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type).  */
+
+#define AT_NULL		0		/* End of vector */
+#define AT_IGNORE	1		/* Entry should be ignored */
+#define AT_EXECFD	2		/* File descriptor of program */
+#define AT_PHDR		3		/* Program headers for program */
+#define AT_PHENT	4		/* Size of program header entry */
+#define AT_PHNUM	5		/* Number of program headers */
+#define AT_PAGESZ	6		/* System page size */
+#define AT_BASE		7		/* Base address of interpreter */
+#define AT_FLAGS	8		/* Flags */
+#define AT_ENTRY	9		/* Entry point of program */
+#define AT_NOTELF	10		/* Program is not ELF */
+#define AT_UID		11		/* Real uid */
+#define AT_EUID		12		/* Effective uid */
+#define AT_GID		13		/* Real gid */
+#define AT_EGID		14		/* Effective gid */
+#define AT_CLKTCK	17		/* Frequency of times() */
+
+/* Some more special a_type values describing the hardware.  */
+#define AT_PLATFORM	15		/* String identifying platform.  */
+#define AT_HWCAP	16		/* Machine dependent hints about
+					   processor capabilities.  */
+
+/* This entry gives some information about the FPU initialization
+   performed by the kernel.  */
+#define AT_FPUCW	18		/* Used FPU control word.  */
+
+/* Cache block sizes.  */
+#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
+#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
+#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
+
+/* A special ignored value for PPC, used by the kernel to control the
+   interpretation of the AUXV. Must be > 16.  */
+#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
+
+#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
+
+/* Pointer to the global system page used for system calls and other
+   nice things.  */
+#define AT_SYSINFO	32
+#define AT_SYSINFO_EHDR	33
+
+/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
+   log2 of line size; mask those to get cache size.  */
+#define AT_L1I_CACHESHAPE	34
+#define AT_L1D_CACHESHAPE	35
+#define AT_L2_CACHESHAPE	36
+#define AT_L3_CACHESHAPE	37
+
+/* Note section contents.  Each entry in the note section begins with
+   a header of a fixed form.  */
+
+typedef struct
+{
+  Elf32_Word n_namesz;			/* Length of the note's name.  */
+  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf32_Word n_type;			/* Type of the note.  */
+} Elf32_Nhdr;
+
+typedef struct
+{
+  Elf64_Word n_namesz;			/* Length of the note's name.  */
+  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf64_Word n_type;			/* Type of the note.  */
+} Elf64_Nhdr;
+
+/* Known names of notes.  */
+
+/* Solaris entries in the note section have this name.  */
+#define ELF_NOTE_SOLARIS	"SUNW Solaris"
+
+/* Note entries for GNU systems have this name.  */
+#define ELF_NOTE_GNU		"GNU"
+
+
+/* Defined types of notes for Solaris.  */
+
+/* Value of descriptor (one word) is desired pagesize for the binary.  */
+#define ELF_NOTE_PAGESIZE_HINT	1
+
+
+/* Defined note types for GNU systems.  */
+
+/* ABI information.  The descriptor consists of words:
+   word 0: OS descriptor
+   word 1: major version of the ABI
+   word 2: minor version of the ABI
+   word 3: subminor version of the ABI
+*/
+#define ELF_NOTE_ABI		1
+
+/* Known OSes.  These value can appear in word 0 of an ELF_NOTE_ABI
+   note section entry.  */
+#define ELF_NOTE_OS_LINUX	0
+#define ELF_NOTE_OS_GNU		1
+#define ELF_NOTE_OS_SOLARIS2	2
+#define ELF_NOTE_OS_FREEBSD	3
+
+
+/* Move records.  */
+typedef struct
+{
+  Elf32_Xword m_value;		/* Symbol value.  */
+  Elf32_Word m_info;		/* Size and index.  */
+  Elf32_Word m_poffset;		/* Symbol offset.  */
+  Elf32_Half m_repeat;		/* Repeat count.  */
+  Elf32_Half m_stride;		/* Stride info.  */
+} Elf32_Move;
+
+typedef struct
+{
+  Elf64_Xword m_value;		/* Symbol value.  */
+  Elf64_Xword m_info;		/* Size and index.  */
+  Elf64_Xword m_poffset;	/* Symbol offset.  */
+  Elf64_Half m_repeat;		/* Repeat count.  */
+  Elf64_Half m_stride;		/* Stride info.  */
+} Elf64_Move;
+
+/* Macro to construct move records.  */
+#define ELF32_M_SYM(info)	((info) >> 8)
+#define ELF32_M_SIZE(info)	((unsigned char) (info))
+#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions.  */
+
+/* Values for Elf32_Ehdr.e_flags.  */
+#define EF_CPU32	0x00810000
+
+/* m68k relocs.  */
+
+#define R_68K_NONE	0		/* No reloc */
+#define R_68K_32	1		/* Direct 32 bit  */
+#define R_68K_16	2		/* Direct 16 bit  */
+#define R_68K_8		3		/* Direct 8 bit  */
+#define R_68K_PC32	4		/* PC relative 32 bit */
+#define R_68K_PC16	5		/* PC relative 16 bit */
+#define R_68K_PC8	6		/* PC relative 8 bit */
+#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
+#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
+#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O	10		/* 32 bit GOT offset */
+#define R_68K_GOT16O	11		/* 16 bit GOT offset */
+#define R_68K_GOT8O	12		/* 8 bit GOT offset */
+#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
+#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
+#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
+#define R_68K_PLT32O	16		/* 32 bit PLT offset */
+#define R_68K_PLT16O	17		/* 16 bit PLT offset */
+#define R_68K_PLT8O	18		/* 8 bit PLT offset */
+#define R_68K_COPY	19		/* Copy symbol at runtime */
+#define R_68K_GLOB_DAT	20		/* Create GOT entry */
+#define R_68K_JMP_SLOT	21		/* Create PLT entry */
+#define R_68K_RELATIVE	22		/* Adjust by program base */
+/* Keep this the last entry.  */
+#define R_68K_NUM	23
+
+/* Intel 80386 specific definitions.  */
+
+/* i386 relocs.  */
+
+#define R_386_NONE	   0		/* No reloc */
+#define R_386_32	   1		/* Direct 32 bit  */
+#define R_386_PC32	   2		/* PC relative 32 bit */
+#define R_386_GOT32	   3		/* 32 bit GOT entry */
+#define R_386_PLT32	   4		/* 32 bit PLT address */
+#define R_386_COPY	   5		/* Copy symbol at runtime */
+#define R_386_GLOB_DAT	   6		/* Create GOT entry */
+#define R_386_JMP_SLOT	   7		/* Create PLT entry */
+#define R_386_RELATIVE	   8		/* Adjust by program base */
+#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
+#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
+#define R_386_32PLT	   11
+#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
+#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
+					   block offset */
+#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
+					   offset */
+#define R_386_TLS_LE	   17		/* Offset relative to static TLS
+					   block */
+#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
+					   general dynamic thread local data */
+#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
+					   local dynamic thread local data
+					   in LE code */
+#define R_386_16	   20
+#define R_386_PC16	   21
+#define R_386_8		   22
+#define R_386_PC8	   23
+#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
+					   thread local data */
+#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL  26		/* Relocation for call to
+					   __tls_get_addr() */
+#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
+					   thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
+					   __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
+#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
+					   block offset */
+#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
+					   TLS block */
+#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
+#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
+/* Keep this the last entry.  */
+#define R_386_NUM	   38
+
+/* SUN SPARC specific definitions.  */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags.  */
+
+#define EF_SPARCV9_MM		3
+#define EF_SPARCV9_TSO		0
+#define EF_SPARCV9_PSO		1
+#define EF_SPARCV9_RMO		2
+#define EF_SPARC_LEDATA		0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK	0xFFFF00
+#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs.  */
+
+#define R_SPARC_NONE		0	/* No reloc */
+#define R_SPARC_8		1	/* Direct 8 bit */
+#define R_SPARC_16		2	/* Direct 16 bit */
+#define R_SPARC_32		3	/* Direct 32 bit */
+#define R_SPARC_DISP8		4	/* PC relative 8 bit */
+#define R_SPARC_DISP16		5	/* PC relative 16 bit */
+#define R_SPARC_DISP32		6	/* PC relative 32 bit */
+#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
+#define R_SPARC_HI22		9	/* High 22 bit */
+#define R_SPARC_22		10	/* Direct 22 bit */
+#define R_SPARC_13		11	/* Direct 13 bit */
+#define R_SPARC_LO10		12	/* Truncated 10 bit */
+#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
+#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
+#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
+#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
+#define R_SPARC_COPY		19	/* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
+#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
+#define R_SPARC_RELATIVE	22	/* Adjust by program base */
+#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs.  */
+
+#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10		30	/* Direct 10 bit */
+#define R_SPARC_11		31	/* Direct 11 bit */
+#define R_SPARC_64		32	/* Direct 64 bit */
+#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
+#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
+#define R_SPARC_7		43	/* Direct 7 bit */
+#define R_SPARC_5		44	/* Direct 5 bit */
+#define R_SPARC_6		45	/* Direct 6 bit */
+#define R_SPARC_DISP64		46	/* PC relative 64 bit */
+#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22		48	/* High 22 bit complemented */
+#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
+#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
+#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
+#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER	53	/* Global register usage */
+#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
+#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22	56
+#define R_SPARC_TLS_GD_LO10	57
+#define R_SPARC_TLS_GD_ADD	58
+#define R_SPARC_TLS_GD_CALL	59
+#define R_SPARC_TLS_LDM_HI22	60
+#define R_SPARC_TLS_LDM_LO10	61
+#define R_SPARC_TLS_LDM_ADD	62
+#define R_SPARC_TLS_LDM_CALL	63
+#define R_SPARC_TLS_LDO_HIX22	64
+#define R_SPARC_TLS_LDO_LOX10	65
+#define R_SPARC_TLS_LDO_ADD	66
+#define R_SPARC_TLS_IE_HI22	67
+#define R_SPARC_TLS_IE_LO10	68
+#define R_SPARC_TLS_IE_LD	69
+#define R_SPARC_TLS_IE_LDX	70
+#define R_SPARC_TLS_IE_ADD	71
+#define R_SPARC_TLS_LE_HIX22	72
+#define R_SPARC_TLS_LE_LOX10	73
+#define R_SPARC_TLS_DTPMOD32	74
+#define R_SPARC_TLS_DTPMOD64	75
+#define R_SPARC_TLS_DTPOFF32	76
+#define R_SPARC_TLS_DTPOFF64	77
+#define R_SPARC_TLS_TPOFF32	78
+#define R_SPARC_TLS_TPOFF64	79
+/* Keep this the last entry.  */
+#define R_SPARC_NUM		80
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM	2
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH	1	/* The cpu supports flush insn.  */
+#define HWCAP_SPARC_STBAR	2
+#define HWCAP_SPARC_SWAP	4
+#define HWCAP_SPARC_MULDIV	8
+#define HWCAP_SPARC_V9		16	/* The cpu is v9, so v8plus is ok.  */
+#define HWCAP_SPARC_ULTRA3	32
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
+#define EF_MIPS_PIC	    2		/* Contains PIC code */
+#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
+#define EF_MIPS_XGOT	    8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2	    32
+#define EF_MIPS_ABI_ON32    64
+#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
+
+/* Legal values for MIPS architecture level.  */
+
+#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
+#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
+#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
+#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
+#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
+#define EF_MIPS_ARCH_32	    0x60000000	/* MIPS32 code.  */
+#define EF_MIPS_ARCH_64	    0x70000000	/* MIPS64 code.  */
+
+/* The following are non-official names and should not be used.  */
+
+#define E_MIPS_ARCH_1	  0x00000000	/* -mips1 code.  */
+#define E_MIPS_ARCH_2	  0x10000000	/* -mips2 code.  */
+#define E_MIPS_ARCH_3	  0x20000000	/* -mips3 code.  */
+#define E_MIPS_ARCH_4	  0x30000000	/* -mips4 code.  */
+#define E_MIPS_ARCH_5	  0x40000000	/* -mips5 code.  */
+#define E_MIPS_ARCH_32	  0x60000000	/* MIPS32 code.  */
+#define E_MIPS_ARCH_64	  0x70000000	/* MIPS64 code.  */
+
+/* Special section indices.  */
+
+#define SHN_MIPS_ACOMMON    0xff00	/* Allocated common symbols */
+#define SHN_MIPS_TEXT	    0xff01	/* Allocated test symbols.  */
+#define SHN_MIPS_DATA	    0xff02	/* Allocated data symbols.  */
+#define SHN_MIPS_SCOMMON    0xff03	/* Small common symbols */
+#define SHN_MIPS_SUNDEFINED 0xff04	/* Small undefined symbols */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
+#define SHT_MIPS_MSYM	       0x70000001
+#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
+#define SHT_MIPS_GPTAB	       0x70000003 /* Global data area sizes */
+#define SHT_MIPS_UCODE	       0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG	       0x70000005 /* MIPS ECOFF debugging information*/
+#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
+#define SHT_MIPS_PACKAGE       0x70000007
+#define SHT_MIPS_PACKSYM       0x70000008
+#define SHT_MIPS_RELD	       0x70000009
+#define SHT_MIPS_IFACE         0x7000000b
+#define SHT_MIPS_CONTENT       0x7000000c
+#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
+#define SHT_MIPS_SHDR	       0x70000010
+#define SHT_MIPS_FDESC	       0x70000011
+#define SHT_MIPS_EXTSYM	       0x70000012
+#define SHT_MIPS_DENSE	       0x70000013
+#define SHT_MIPS_PDESC	       0x70000014
+#define SHT_MIPS_LOCSYM	       0x70000015
+#define SHT_MIPS_AUXSYM	       0x70000016
+#define SHT_MIPS_OPTSYM	       0x70000017
+#define SHT_MIPS_LOCSTR	       0x70000018
+#define SHT_MIPS_LINE	       0x70000019
+#define SHT_MIPS_RFDESC	       0x7000001a
+#define SHT_MIPS_DELTASYM      0x7000001b
+#define SHT_MIPS_DELTAINST     0x7000001c
+#define SHT_MIPS_DELTACLASS    0x7000001d
+#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
+#define SHT_MIPS_DELTADECL     0x7000001f
+#define SHT_MIPS_SYMBOL_LIB    0x70000020
+#define SHT_MIPS_EVENTS	       0x70000021 /* Event section.  */
+#define SHT_MIPS_TRANSLATE     0x70000022
+#define SHT_MIPS_PIXIE	       0x70000023
+#define SHT_MIPS_XLATE	       0x70000024
+#define SHT_MIPS_XLATE_DEBUG   0x70000025
+#define SHT_MIPS_WHIRL	       0x70000026
+#define SHT_MIPS_EH_REGION     0x70000027
+#define SHT_MIPS_XLATE_OLD     0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_MIPS_GPREL	 0x10000000	/* Must be part of global data area */
+#define SHF_MIPS_MERGE	 0x20000000
+#define SHF_MIPS_ADDR	 0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL	 0x04000000
+#define SHF_MIPS_NAMES	 0x02000000
+#define SHF_MIPS_NODUPE	 0x01000000
+
+
+/* Symbol tables.  */
+
+/* MIPS specific values for `st_other'.  */
+#define STO_MIPS_DEFAULT		0x0
+#define STO_MIPS_INTERNAL		0x1
+#define STO_MIPS_HIDDEN			0x2
+#define STO_MIPS_PROTECTED		0x3
+#define STO_MIPS_SC_ALIGN_UNUSED	0xff
+
+/* MIPS specific values for `st_info'.  */
+#define STB_MIPS_SPLIT_COMMON		13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB.  */
+
+typedef union
+{
+  struct
+    {
+      Elf32_Word gt_current_g_value;	/* -G value used for compilation */
+      Elf32_Word gt_unused;		/* Not used */
+    } gt_header;			/* First entry in section */
+  struct
+    {
+      Elf32_Word gt_g_value;		/* If this value were used for -G */
+      Elf32_Word gt_bytes;		/* This many bytes would be used */
+    } gt_entry;				/* Subsequent entries in section */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO.  */
+
+typedef struct
+{
+  Elf32_Word	ri_gprmask;		/* General registers used */
+  Elf32_Word	ri_cprmask[4];		/* Coprocessor registers used */
+  Elf32_Sword	ri_gp_value;		/* $gp register value */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
+
+typedef struct
+{
+  unsigned char kind;		/* Determines interpretation of the
+				   variable part of descriptor.  */
+  unsigned char size;		/* Size of descriptor, including header.  */
+  Elf32_Section section;	/* Section header index of section affected,
+				   0 for global options.  */
+  Elf32_Word info;		/* Kind-specific information.  */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options.  */
+
+#define ODK_NULL	0	/* Undefined.  */
+#define ODK_REGINFO	1	/* Register usage information.  */
+#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
+#define ODK_PAD		3	/* Section padding options.  */
+#define ODK_HWPATCH	4	/* Hardware workarounds performed */
+#define ODK_FILL	5	/* record the fill value used by the linker. */
+#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
+#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
+#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
+
+#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
+#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
+#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
+#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
+#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
+#define OEX_PRECISEFP	OEX_FPDBUG
+#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
+
+#define OEX_FPU_INVAL	0x10
+#define OEX_FPU_DIV0	0x08
+#define OEX_FPU_OFLO	0x04
+#define OEX_FPU_UFLO	0x02
+#define OEX_FPU_INEX	0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
+
+#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
+#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
+#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
+#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
+
+#define OPAD_PREFIX	0x1
+#define OPAD_POSTFIX	0x2
+#define OPAD_SYMBOL	0x4
+
+/* Entry found in `.options' section.  */
+
+typedef struct
+{
+  Elf32_Word hwp_flags1;	/* Extra flags.  */
+  Elf32_Word hwp_flags2;	/* Extra flags.  */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
+
+#define OHWA0_R4KEOP_CHECKED	0x00000001
+#define OHWA1_R4KEOP_CLEAN	0x00000002
+
+/* MIPS relocs.  */
+
+#define R_MIPS_NONE		0	/* No reloc */
+#define R_MIPS_16		1	/* Direct 16 bit */
+#define R_MIPS_32		2	/* Direct 32 bit */
+#define R_MIPS_REL32		3	/* PC relative 32 bit */
+#define R_MIPS_26		4	/* Direct 26 bit shifted */
+#define R_MIPS_HI16		5	/* High 16 bit */
+#define R_MIPS_LO16		6	/* Low 16 bit */
+#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
+#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
+#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
+#define R_MIPS_PC16		10	/* PC relative 16 bit */
+#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5		16
+#define R_MIPS_SHIFT6		17
+#define R_MIPS_64		18
+#define R_MIPS_GOT_DISP		19
+#define R_MIPS_GOT_PAGE		20
+#define R_MIPS_GOT_OFST		21
+#define R_MIPS_GOT_HI16		22
+#define R_MIPS_GOT_LO16		23
+#define R_MIPS_SUB		24
+#define R_MIPS_INSERT_A		25
+#define R_MIPS_INSERT_B		26
+#define R_MIPS_DELETE		27
+#define R_MIPS_HIGHER		28
+#define R_MIPS_HIGHEST		29
+#define R_MIPS_CALL_HI16	30
+#define R_MIPS_CALL_LO16	31
+#define R_MIPS_SCN_DISP		32
+#define R_MIPS_REL16		33
+#define R_MIPS_ADD_IMMEDIATE	34
+#define R_MIPS_PJUMP		35
+#define R_MIPS_RELGOT		36
+#define R_MIPS_JALR		37
+/* Keep this the last entry.  */
+#define R_MIPS_NUM		38
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
+#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types.  */
+
+#define PF_MIPS_LOCAL	0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn.  */
+
+#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
+#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
+#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
+#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
+#define DT_MIPS_MSYM	     0x70000007
+#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
+#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
+#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
+#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
+						DT_MIPS_DELTA_CLASS.  */
+#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+						DT_MIPS_DELTA_INSTANCE.  */
+#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+					     DT_MIPS_DELTA_RELOC.  */
+#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
+					   relocations refer to.  */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+					   DT_MIPS_DELTA_SYM.  */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+					     class declaration.  */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+						DT_MIPS_DELTA_CLASSSYM.  */
+#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
+#define DT_MIPS_PIXIE_INIT   0x70000023
+#define DT_MIPS_SYMBOL_LIB   0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
+#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+						    function stored in GOT.  */
+#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
+					   by rld on dlopen() calls.  */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
+#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
+#define DT_MIPS_NUM	     0x32
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
+
+#define RHF_NONE		   0		/* No flags */
+#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
+#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE		   (1 << 3)
+#define RHF_SGI_ONLY		   (1 << 4)
+#define RHF_GUARANTEE_INIT	   (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
+#define RHF_GUARANTEE_START_INIT   (1 << 7)
+#define RHF_PIXIE		   (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
+#define RHF_REQUICKSTART	   (1 << 10)
+#define RHF_REQUICKSTARTED	   (1 << 11)
+#define RHF_CORD		   (1 << 12)
+#define RHF_NO_UNRES_UNDEF	   (1 << 13)
+#define RHF_RLD_ORDER_SAFE	   (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
+
+typedef struct
+{
+  Elf32_Word l_name;		/* Name (string table index) */
+  Elf32_Word l_time_stamp;	/* Timestamp */
+  Elf32_Word l_checksum;	/* Checksum */
+  Elf32_Word l_version;		/* Interface version */
+  Elf32_Word l_flags;		/* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+  Elf64_Word l_name;		/* Name (string table index) */
+  Elf64_Word l_time_stamp;	/* Timestamp */
+  Elf64_Word l_checksum;	/* Checksum */
+  Elf64_Word l_version;		/* Interface version */
+  Elf64_Word l_flags;		/* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags.  */
+
+#define LL_NONE		  0
+#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
+#define LL_REQUIRE_MINOR  (1 << 2)
+#define LL_EXPORTS	  (1 << 3)
+#define LL_DELAY_LOAD	  (1 << 4)
+#define LL_DELTA	  (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
+#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
+					      prediction.  */
+#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
+#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
+
+#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
+#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
+#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
+
+/* Additional section indeces.  */
+
+#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
+					      symbols in ANSI C.  */
+#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
+#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
+#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
+
+#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
+#define STT_HP_STUB		(STT_LOOS + 0x2)
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE		0	/* No reloc.  */
+#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
+#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
+#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
+#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
+#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
+#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
+#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
+#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
+#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
+#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
+#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
+#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
+#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
+#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
+#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
+#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
+#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
+#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
+#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fct ptr.  */
+#define R_PARISC_PLABEL14R	70	/* Left 21 bits of fct ptr.  */
+#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
+#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
+#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
+#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
+#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
+#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
+#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
+#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
+#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
+#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
+#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
+#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
+#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
+#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
+#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LORESERVE	128
+#define R_PARISC_COPY		128	/* Copy relocation.  */
+#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
+#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
+#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
+#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
+#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
+#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_HIRESERVE	255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PT_HP_TLS		(PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
+#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
+#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
+#define PT_HP_STACK		(PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT	0x70000000
+#define PT_PARISC_UNWIND	0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PF_PARISC_SBP		0x08000000
+
+#define PF_HP_PAGE_SIZE		0x00100000
+#define PF_HP_FAR_SHARED	0x00200000
+#define PF_HP_NEAR_SHARED	0x00400000
+#define PF_HP_CODE		0x01000000
+#define PF_HP_MODIFY		0x02000000
+#define PF_HP_LAZYSWAP		0x04000000
+#define PF_HP_SBP		0x08000000
+
+
+/* Alpha specific definitions.  */
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
+#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
+
+/* Legal values for sh_type field of Elf64_Shdr.  */
+
+/* These two are primerily concerned with ECOFF debugging info.  */
+#define SHT_ALPHA_DEBUG		0x70000001
+#define SHT_ALPHA_REGINFO	0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr.  */
+
+#define SHF_ALPHA_GPREL		0x10000000
+
+/* Legal values for st_other field of Elf64_Sym.  */
+#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
+#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
+
+/* Alpha relocs.  */
+
+#define R_ALPHA_NONE		0	/* No reloc */
+#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
+#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
+#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
+#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
+#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
+#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
+#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
+#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
+#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
+#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI	28
+#define R_ALPHA_TLSGD		29
+#define R_ALPHA_TLS_LDM		30
+#define R_ALPHA_DTPMOD64	31
+#define R_ALPHA_GOTDTPREL	32
+#define R_ALPHA_DTPREL64	33
+#define R_ALPHA_DTPRELHI	34
+#define R_ALPHA_DTPRELLO	35
+#define R_ALPHA_DTPREL16	36
+#define R_ALPHA_GOTTPREL	37
+#define R_ALPHA_TPREL64		38
+#define R_ALPHA_TPRELHI		39
+#define R_ALPHA_TPRELLO		40
+#define R_ALPHA_TPREL16		41
+/* Keep this the last entry.  */
+#define R_ALPHA_NUM		46
+
+/* Magic values of the LITUSE relocation addend.  */
+#define LITUSE_ALPHA_ADDR	0
+#define LITUSE_ALPHA_BASE	1
+#define LITUSE_ALPHA_BYTOFF	2
+#define LITUSE_ALPHA_JSR	3
+#define LITUSE_ALPHA_TLS_GD	4
+#define LITUSE_ALPHA_TLS_LDM	5
+
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags.  */
+#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
+						   flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+
+/* PowerPC relocations defined for the TLS access ABI.  */
+#define R_PPC_TLS		67 /* none	(sym+add)@tls */
+#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
+#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
+#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
+#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
+
+/* Keep this the last entry.  */
+#define R_PPC_NUM		95
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+   in the SVR4 ELF ABI.  */
+#define R_PPC_EMB_NADDR32	101
+#define R_PPC_EMB_NADDR16	102
+#define R_PPC_EMB_NADDR16_LO	103
+#define R_PPC_EMB_NADDR16_HI	104
+#define R_PPC_EMB_NADDR16_HA	105
+#define R_PPC_EMB_SDAI16	106
+#define R_PPC_EMB_SDA2I16	107
+#define R_PPC_EMB_SDA2REL	108
+#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF	110
+#define R_PPC_EMB_RELSEC16	111
+#define R_PPC_EMB_RELST_LO	112
+#define R_PPC_EMB_RELST_HI	113
+#define R_PPC_EMB_RELST_HA	114
+#define R_PPC_EMB_BIT_FLD	115
+#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
+
+/* Diab tool relocations.  */
+#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+   that may still be in object files.  */
+#define R_PPC_TOC16		255
+
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE		R_PPC_NONE
+#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
+#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
+#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
+#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16		R_PPC_GOT16
+#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
+
+#define R_PPC64_COPY		R_PPC_COPY
+#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE	R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32		R_PPC_UADDR32
+#define R_PPC64_UADDR16		R_PPC_UADDR16
+#define R_PPC64_REL32		R_PPC_REL32
+#define R_PPC64_PLT32		R_PPC_PLT32
+#define R_PPC64_PLTREL32	R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF		R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
+#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64		45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC		51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16	52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI.  */
+#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
+#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
+
+/* Keep this the last entry.  */
+#define R_PPC64_NUM		107
+
+/* PowerPC64 specific values for the Dyn d_tag field.  */
+#define DT_PPC64_GLINK  (DT_LOPROC + 0)
+#define DT_PPC64_OPD	(DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
+#define DT_PPC64_NUM    3
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC     0x01
+#define EF_ARM_HASENTRY    0x02
+#define EF_ARM_INTERWORK   0x04
+#define EF_ARM_APCS_26     0x08
+#define EF_ARM_APCS_FLOAT  0x10
+#define EF_ARM_PIC         0x20
+#define EF_ARM_ALIGN8      0x40		/* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI     0x80
+#define EF_ARM_OLD_ABI     0x100
+
+/* Other constants defined in the ARM ELF spec. version B-01.  */
+/* NB. These conflict with values defined above.  */
+#define EF_ARM_SYMSARESORTED	0x04
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
+#define EF_ARM_MAPSYMSFIRST	0x10
+#define EF_ARM_EABIMASK		0XFF000000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN  0x00000000
+#define EF_ARM_EABI_VER1     0x01000000
+#define EF_ARM_EABI_VER2     0x02000000
+
+/* Additional symbol types for Thumb */
+#define STT_ARM_TFUNC      0xd
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT  0x10000000   /* Section contains an entry point */
+#define SHF_ARM_COMDEF     0x80000000   /* Section may be multiply defined
+					   in the input to a link step */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB          0x10000000   /* Segment contains the location
+					   addressed by the static base */
+
+/* ARM relocs.  */
+#define R_ARM_NONE		0	/* No reloc */
+#define R_ARM_PC24		1	/* PC relative 26 bit branch */
+#define R_ARM_ABS32		2	/* Direct 32 bit  */
+#define R_ARM_REL32		3	/* PC relative 32 bit */
+#define R_ARM_PC13		4
+#define R_ARM_ABS16		5	/* Direct 16 bit */
+#define R_ARM_ABS12		6	/* Direct 12 bit */
+#define R_ARM_THM_ABS5		7
+#define R_ARM_ABS8		8	/* Direct 8 bit */
+#define R_ARM_SBREL32		9
+#define R_ARM_THM_PC22		10
+#define R_ARM_THM_PC8		11
+#define R_ARM_AMP_VCALL9	12
+#define R_ARM_SWI24		13
+#define R_ARM_THM_SWI8		14
+#define R_ARM_XPC25		15
+#define R_ARM_THM_XPC22		16
+#define R_ARM_COPY		20	/* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
+#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
+#define R_ARM_RELATIVE		23	/* Adjust by program base */
+#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
+#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32		26	/* 32 bit GOT entry */
+#define R_ARM_PLT32		27	/* 32 bit PLT address */
+#define R_ARM_ALU_PCREL_7_0	32
+#define R_ARM_ALU_PCREL_15_8	33
+#define R_ARM_ALU_PCREL_23_15	34
+#define R_ARM_LDR_SBREL_11_0	35
+#define R_ARM_ALU_SBREL_19_12	36
+#define R_ARM_ALU_SBREL_27_20	37
+#define R_ARM_GNU_VTENTRY	100
+#define R_ARM_GNU_VTINHERIT	101
+#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
+#define R_ARM_THM_PC9		103	/* thumb conditional branch */
+#define R_ARM_RXPC25		249
+#define R_ARM_RSBREL32		250
+#define R_ARM_THM_RPC22		251
+#define R_ARM_RREL32		252
+#define R_ARM_RABS22		253
+#define R_ARM_RPC24		254
+#define R_ARM_RBASE		255
+/* Keep this the last entry.  */
+#define R_ARM_NUM		256
+
+/* IA-64 specific declarations.  */
+
+/* Processor specific flags for the Ehdr e_flags field.  */
+#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
+#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
+#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
+#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field.  */
+#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field.  */
+#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
+#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field.  */
+#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
+#define DT_IA_64_NUM		1
+
+/* IA-64 relocations.  */
+#define R_IA64_NONE		0x00	/* none */
+#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
+#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
+#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
+#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
+#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
+#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
+#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY		0x84	/* copy relocation */
+#define R_IA64_SUB		0x85	/* Addend and symbol difference */
+#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
+#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
+#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* SH relocs.  */
+#define	R_SH_NONE		0
+#define	R_SH_DIR32		1
+#define	R_SH_REL32		2
+#define	R_SH_DIR8WPN		3
+#define	R_SH_IND12W		4
+#define	R_SH_DIR8WPL		5
+#define	R_SH_DIR8WPZ		6
+#define	R_SH_DIR8BP		7
+#define	R_SH_DIR8W		8
+#define	R_SH_DIR8L		9
+#define	R_SH_SWITCH16		25
+#define	R_SH_SWITCH32		26
+#define	R_SH_USES		27
+#define	R_SH_COUNT		28
+#define	R_SH_ALIGN		29
+#define	R_SH_CODE		30
+#define	R_SH_DATA		31
+#define	R_SH_LABEL		32
+#define	R_SH_SWITCH8		33
+#define	R_SH_GNU_VTINHERIT	34
+#define	R_SH_GNU_VTENTRY	35
+#define	R_SH_TLS_GD_32		144
+#define	R_SH_TLS_LD_32		145
+#define	R_SH_TLS_LDO_32		146
+#define	R_SH_TLS_IE_32		147
+#define	R_SH_TLS_LE_32		148
+#define	R_SH_TLS_DTPMOD32	149
+#define	R_SH_TLS_DTPOFF32	150
+#define	R_SH_TLS_TPOFF32	151
+#define	R_SH_GOT32		160
+#define	R_SH_PLT32		161
+#define	R_SH_COPY		162
+#define	R_SH_GLOB_DAT		163
+#define	R_SH_JMP_SLOT		164
+#define	R_SH_RELATIVE		165
+#define	R_SH_GOTOFF		166
+#define	R_SH_GOTPC		167
+/* Keep this the last entry.  */
+#define	R_SH_NUM		256
+
+/* Additional s390 relocs */
+
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+					   dynamic TLS code. */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+					   dynamic TLS code. */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+					   thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+					  thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+					   block offset. */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
+#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
+					   block.  */
+#define R_390_20		57	/* Direct 20 bit.  */
+#define R_390_GOT20		58	/* 20 bit GOT offset.  */
+#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
+#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
+					   block offset.  */
+/* Keep this the last entry.  */
+#define R_390_NUM		61
+
+
+/* CRIS relocations.  */
+#define R_CRIS_NONE		0
+#define R_CRIS_8		1
+#define R_CRIS_16		2
+#define R_CRIS_32		3
+#define R_CRIS_8_PCREL		4
+#define R_CRIS_16_PCREL		5
+#define R_CRIS_32_PCREL		6
+#define R_CRIS_GNU_VTINHERIT	7
+#define R_CRIS_GNU_VTENTRY	8
+#define R_CRIS_COPY		9
+#define R_CRIS_GLOB_DAT		10
+#define R_CRIS_JUMP_SLOT	11
+#define R_CRIS_RELATIVE		12
+#define R_CRIS_16_GOT		13
+#define R_CRIS_32_GOT		14
+#define R_CRIS_16_GOTPLT	15
+#define R_CRIS_32_GOTPLT	16
+#define R_CRIS_32_GOTREL	17
+#define R_CRIS_32_PLT_GOTREL	18
+#define R_CRIS_32_PLT_PCREL	19
+
+#define R_CRIS_NUM		20
+
+
+/* AMD x86-64 relocations.  */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
+#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
+#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
+#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
+					   to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
+					   to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
+#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
+					   to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
+
+#define R_X86_64_NUM		24
+
+
+/* AM33 relocations.  */
+#define R_MN10300_NONE		0	/* No reloc.  */
+#define R_MN10300_32		1	/* Direct 32 bit.  */
+#define R_MN10300_16		2	/* Direct 16 bit.  */
+#define R_MN10300_8		3	/* Direct 8 bit.  */
+#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
+#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
+#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
+#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
+#define R_MN10300_24		9	/* Direct 24 bit.  */
+#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
+#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
+#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
+#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
+#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
+#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
+#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
+#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
+#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
+#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
+#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
+#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
+#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
+#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
+
+#define R_MN10300_NUM		24
+
+
+/* M32R relocs.  */
+#define R_M32R_NONE		0	/* No reloc. */
+#define R_M32R_16		1	/* Direct 16 bit. */
+#define R_M32R_32		2	/* Direct 32 bit. */
+#define R_M32R_24		3	/* Direct 24 bit. */
+#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
+#define R_M32R_LO16		9	/* Low 16 bit. */
+#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT	11
+#define R_M32R_GNU_VTENTRY	12
+/* M32R relocs use SHT_RELA.  */
+#define R_M32R_16_RELA		33	/* Direct 16 bit. */
+#define R_M32R_32_RELA		34	/* Direct 32 bit. */
+#define R_M32R_24_RELA		35	/* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
+#define R_M32R_LO16_RELA	41	/* Low 16 bit */
+#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT	43
+#define R_M32R_RELA_GNU_VTENTRY	44
+#define R_M32R_REL32		45	/* PC relative 32 bit */
+
+#define R_M32R_GOT24		48	/* 24 bit GOT entry */
+#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY		50	/* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
+#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
+#define R_M32R_RELATIVE		53	/* Adjust by program base */
+#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
+#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
+					   low */
+#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
+					   low */
+#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
+					   GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
+					   GOT with signed low */
+#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
+					   GOT */
+#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
+					   with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
+					   with signed low */
+#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
+#define R_M32R_NUM		256	/* Keep this the last entry. */
+
+
+__END_DECLS
+
+#endif	/* elf.h */
diff --git a/tools/mklibs/patches/001-compile.patch b/tools/mklibs/patches/001-compile.patch
new file mode 100644
index 0000000000..09b831ada2
--- /dev/null
+++ b/tools/mklibs/patches/001-compile.patch
@@ -0,0 +1,8 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,4 +1,4 @@
+-AC_INIT([mklibs],m4_esyscmd(dpkg-parsechangelog | perl -ne 'print $1 if m/^Version: (.*)$/;'))
++AC_INIT([mklibs],m4_esyscmd([head -n1 debian/changelog | awk -F'[\\\\(\\\\)]' '{ print $2 }' | xargs -I{} echo -n {}]))
+ AM_INIT_AUTOMAKE([foreign no-define])
+ AC_CONFIG_HEADERS([config.h])
+ AM_MAINTAINER_MODE
diff --git a/tools/mklibs/patches/002-disable_symbol_checks.patch b/tools/mklibs/patches/002-disable_symbol_checks.patch
new file mode 100644
index 0000000000..44be637609
--- /dev/null
+++ b/tools/mklibs/patches/002-disable_symbol_checks.patch
@@ -0,0 +1,20 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -524,7 +524,7 @@ while 1:
+         # No progress in last pass. Verify all remaining symbols are weak.
+         for name in unresolved:
+             if not needed_symbols[name].weak:
+-                raise Exception("Unresolvable symbol %s" % name)
++                print "WARNING: Unresolvable symbol %s" % name
+         break
+ 
+     previous_pass_unresolved = unresolved
+@@ -559,7 +559,7 @@ while 1:
+     for name in needed_symbols:
+         if not name in symbol_provider:
+             if not needed_symbols[name].weak:
+-                raise Exception("No library provides non-weak %s" % name)
++                print "WARNING: Unresolvable symbol %s" % name
+         else:
+             lib = symbol_provider[name]
+             library_symbols_used[lib].add(library_symbols[lib][name])
diff --git a/tools/mklibs/patches/003-no_copy.patch b/tools/mklibs/patches/003-no_copy.patch
new file mode 100644
index 0000000000..e0ab2ac88d
--- /dev/null
+++ b/tools/mklibs/patches/003-no_copy.patch
@@ -0,0 +1,50 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -463,7 +463,7 @@ while 1:
+     passnr = passnr + 1
+     # Gather all already reduced libraries and treat them as objects as well
+     small_libs = []
+-    for lib in regexpfilter(os.listdir(dest_path), "(.*-so-stripped)$"):
++    for lib in regexpfilter(os.listdir(dest_path), "(.*-so)$"):
+         obj = dest_path + "/" + lib
+         small_libs.append(obj)
+         inode = os.stat(obj)[ST_INO]
+@@ -579,12 +579,7 @@ while 1:
+         if not so_file:
+             sys.exit("File not found:" + library)
+         pic_file = find_pic(library)
+-        if not pic_file:
+-            # No pic file, so we have to use the .so file, no reduction
+-            debug(DEBUG_VERBOSE, "No pic file found for", so_file, "; copying")
+-            command(target + "objcopy", "--strip-unneeded -R .note -R .comment",
+-                    so_file, dest_path + "/" + so_file_name + "-so-stripped")
+-        else:
++        if pic_file:
+             # we have a pic file, recompile
+             debug(DEBUG_SPAM, "extracting from:", pic_file, "so_file:", so_file)
+             soname = extract_soname(so_file)
+@@ -627,22 +622,14 @@ while 1:
+             cmd.append(library_depends_gcc_libnames(so_file))
+             command(target + "gcc", *cmd)
+ 
+-            # strip result
+-            command(target + "objcopy", "--strip-unneeded -R .note -R .comment",
+-                      dest_path + "/" + so_file_name + "-so",
+-                      dest_path + "/" + so_file_name + "-so-stripped")
+             ## DEBUG
+             debug(DEBUG_VERBOSE, so_file, "\t", `os.stat(so_file)[ST_SIZE]`)
+             debug(DEBUG_VERBOSE, dest_path + "/" + so_file_name + "-so", "\t",
+                   `os.stat(dest_path + "/" + so_file_name + "-so")[ST_SIZE]`)
+-            debug(DEBUG_VERBOSE, dest_path + "/" + so_file_name + "-so-stripped",
+-                  "\t", `os.stat(dest_path + "/" + so_file_name + "-so-stripped")[ST_SIZE]`)
+ 
+ # Finalising libs and cleaning up
+-for lib in regexpfilter(os.listdir(dest_path), "(.*)-so-stripped$"):
+-    os.rename(dest_path + "/" + lib + "-so-stripped", dest_path + "/" + lib)
+-for lib in regexpfilter(os.listdir(dest_path), "(.*-so)$"):
+-    os.remove(dest_path + "/" + lib)
++for lib in regexpfilter(os.listdir(dest_path), "(.*)-so$"):
++    os.rename(dest_path + "/" + lib + "-so", dest_path + "/" + lib)
+ 
+ # Canonicalize library names.
+ for lib in regexpfilter(os.listdir(dest_path), "(.*so[.\d]*)$"):
diff --git a/tools/mklibs/patches/004-libpthread_link.patch b/tools/mklibs/patches/004-libpthread_link.patch
new file mode 100644
index 0000000000..657e232b0c
--- /dev/null
+++ b/tools/mklibs/patches/004-libpthread_link.patch
@@ -0,0 +1,28 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -106,14 +106,14 @@ def library_depends(obj):
+ 
+ # Return a list of libraries the passed objects depend on. The
+ # libraries are in "-lfoo" format suitable for passing to gcc.
+-def library_depends_gcc_libnames(obj):
++def library_depends_gcc_libnames(obj, soname):
+     if not os.access(obj, os.F_OK):
+         raise Exception("Cannot find lib: " + obj)
+     libs = library_depends(obj)
+     ret = []
+     for i in libs:
+         match = re.match("^(((?P<ld>ld\S*)|(lib(?P<lib>\S+))))\.so.*$", i)
+-        if match:
++        if match and not soname in ("libpthread.so.0"):
+             if match.group('ld'):
+                 ret.append(find_lib(match.group(0)))
+             elif match.group('lib'):
+@@ -619,7 +619,7 @@ while 1:
+             cmd.extend(extra_flags)
+             cmd.append("-lgcc")
+             cmd.extend(["-L%s" % a for a in [dest_path] + [sysroot + b for b in lib_path if sysroot == "" or b not in ("/" + libdir + "/", "/usr/" + libdir + "/")]])
+-            cmd.append(library_depends_gcc_libnames(so_file))
++            cmd.append(library_depends_gcc_libnames(so_file, soname))
+             command(target + "gcc", *cmd)
+ 
+             ## DEBUG
diff --git a/tools/mklibs/patches/005-duplicate_syms.patch b/tools/mklibs/patches/005-duplicate_syms.patch
new file mode 100644
index 0000000000..8428abfc9a
--- /dev/null
+++ b/tools/mklibs/patches/005-duplicate_syms.patch
@@ -0,0 +1,35 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -531,7 +531,6 @@ while 1:
+ 
+     library_symbols = {}
+     library_symbols_used = {}
+-    symbol_provider = {}
+ 
+     # WORKAROUND: Always add libgcc on old-abi arm
+     header = elf_header(find_lib(libraries.copy().pop()))
+@@ -549,20 +548,13 @@ while 1:
+         library_symbols_used[library] = set()
+         for symbol in symbols:
+             for name in symbol.base_names():
+-                if name in symbol_provider:
+-                    debug(DEBUG_SPAM, "duplicate symbol %s in %s and %s" % (symbol, symbol_provider[name], library))
+-                else:
+-                    library_symbols[library][name] = symbol
+-                    symbol_provider[name] = library
++                library_symbols[library][name] = symbol
+ 
+     # which symbols are actually used from each lib
+     for name in needed_symbols:
+-        if not name in symbol_provider:
+-            if not needed_symbols[name].weak:
+-                print "WARNING: Unresolvable symbol %s" % name
+-        else:
+-            lib = symbol_provider[name]
+-            library_symbols_used[lib].add(library_symbols[lib][name])
++        for lib in libraries:
++            if name in library_symbols[lib]:
++                library_symbols_used[lib].add(library_symbols[lib][name])
+ 
+     # reduce libraries
+     for library in libraries:
diff --git a/tools/mklibs/patches/006-uclibc_init.patch b/tools/mklibs/patches/006-uclibc_init.patch
new file mode 100644
index 0000000000..2df7fe4355
--- /dev/null
+++ b/tools/mklibs/patches/006-uclibc_init.patch
@@ -0,0 +1,14 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -595,6 +595,11 @@ while 1:
+                 extra_post_obj.append(sysroot + libc_extras_dir + "/sofini.o")
+                 symbols.add(ProvidedSymbol('__dso_handle', None, None, True))
+ 
++            if soname in ("libc.so.0"):
++                symbols.add(ProvidedSymbol('__uClibc_init', None, None, True))
++                symbols.add(ProvidedSymbol('__uClibc_fini', None, None, True))
++                extra_flags.append("-Wl,-init,__uClibc_init")
++
+             map_file = find_pic_map(library)
+             if map_file:
+                 extra_flags.append("-Wl,--version-script=" + map_file)
diff --git a/tools/mklibs/patches/007-gc_sections.patch b/tools/mklibs/patches/007-gc_sections.patch
new file mode 100644
index 0000000000..068d88a532
--- /dev/null
+++ b/tools/mklibs/patches/007-gc_sections.patch
@@ -0,0 +1,11 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -607,7 +607,7 @@ while 1:
+             # compile in only used symbols
+             cmd = []
+             cmd.extend(gcc_options)
+-            cmd.append("-nostdlib -nostartfiles -shared -Wl,-soname=" + soname)
++            cmd.append("-nostdlib -nostartfiles -shared -Wl,--gc-sections -Wl,-soname=" + soname)
+             cmd.extend(["-u%s" % a.linker_name() for a in symbols])
+             cmd.extend(["-o", dest_path + "/" + so_file_name + "-so"])
+             cmd.extend(extra_pre_obj)
diff --git a/tools/mklibs/patches/008-uclibc_libgcc_link.patch b/tools/mklibs/patches/008-uclibc_libgcc_link.patch
new file mode 100644
index 0000000000..432a313b6c
--- /dev/null
+++ b/tools/mklibs/patches/008-uclibc_libgcc_link.patch
@@ -0,0 +1,37 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -113,11 +113,8 @@ def library_depends_gcc_libnames(obj, so
+     ret = []
+     for i in libs:
+         match = re.match("^(((?P<ld>ld\S*)|(lib(?P<lib>\S+))))\.so.*$", i)
+-        if match and not soname in ("libpthread.so.0"):
+-            if match.group('ld'):
+-                ret.append(find_lib(match.group(0)))
+-            elif match.group('lib'):
+-                ret.append('-l%s' % match.group('lib'))
++        if match:
++            ret.append(find_lib(match.group(0)))
+     return ' '.join(ret)
+ 
+ class Symbol(object):
+@@ -584,6 +581,7 @@ while 1:
+             extra_flags = []
+             extra_pre_obj = []
+             extra_post_obj = []
++            libgcc_link = find_lib("libgcc_s.so.1")
+ 
+             symbols.update(library_symbols_used[library])
+ 
+@@ -614,9 +612,10 @@ while 1:
+             cmd.append(pic_file)
+             cmd.extend(extra_post_obj)
+             cmd.extend(extra_flags)
+-            cmd.append("-lgcc")
+             cmd.extend(["-L%s" % a for a in [dest_path] + [sysroot + b for b in lib_path if sysroot == "" or b not in ("/" + libdir + "/", "/usr/" + libdir + "/")]])
+-            cmd.append(library_depends_gcc_libnames(so_file, soname))
++            if soname != "libgcc_s.so.1":
++                cmd.append(library_depends_gcc_libnames(so_file, soname))
++                cmd.append(libgcc_link)
+             command(target + "gcc", *cmd)
+ 
+             ## DEBUG
diff --git a/tools/mklibs/patches/009-uclibc_libpthread_symbols.patch b/tools/mklibs/patches/009-uclibc_libpthread_symbols.patch
new file mode 100644
index 0000000000..34866f7290
--- /dev/null
+++ b/tools/mklibs/patches/009-uclibc_libpthread_symbols.patch
@@ -0,0 +1,63 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -162,9 +162,10 @@ def undefined_symbols(obj):
+     return result
+ 
+ class ProvidedSymbol(Symbol):
+-    def __init__(self, name, version, library, default_version):
++    def __init__(self, name, version, library, default_version, weak):
+         super(ProvidedSymbol, self).__init__(name, version, library)
+         self.default_version = default_version
++        self.weak = weak
+ 
+     def base_names(self):
+         ret = []
+@@ -205,11 +206,15 @@ def provided_symbols(obj):
+         if version_string.lower() not in ('base', 'none'):
+             version = version_string
+ 
++        weak = False
++        if weak_string.lower() == 'true':
++            weak = True
++
+         default_version = False
+         if default_version_string.lower() == 'true':
+             default_version = True
+ 
+-        result.append(ProvidedSymbol(name, version, library, default_version))
++        result.append(ProvidedSymbol(name, version, library, default_version, weak))
+ 
+     return result
+     
+@@ -500,6 +505,9 @@ while 1:
+             debug(DEBUG_SPAM, "present_symbols adding %s" % symbol)
+             names = symbol.base_names()
+             for name in names:
++                if name in present_symbols:
++                    if symbol.library != present_symbols[name].library:
++                        needed_symbols[name] = UndefinedSymbol(name, True, symbol.version, symbol.library)
+                 present_symbols[name] = symbol
+ 
+     # are we finished?
+@@ -591,12 +599,16 @@ while 1:
+                 # may segfault in ptmalloc_init due to undefined weak reference
+                 extra_pre_obj.append(sysroot + libc_extras_dir + "/soinit.o")
+                 extra_post_obj.append(sysroot + libc_extras_dir + "/sofini.o")
+-                symbols.add(ProvidedSymbol('__dso_handle', None, None, True))
++                symbols.add(ProvidedSymbol('__dso_handle', None, None, True, True))
+ 
+-            if soname in ("libc.so.0"):
+-                symbols.add(ProvidedSymbol('__uClibc_init', None, None, True))
+-                symbols.add(ProvidedSymbol('__uClibc_fini', None, None, True))
+-                extra_flags.append("-Wl,-init,__uClibc_init")
++            if soname == "libc.so.0":
++                symbols.add(ProvidedSymbol('__uClibc_init', None, None, True, True))
++                symbols.add(ProvidedSymbol('__uClibc_fini', None, None, True, True))
++                extra_pre_obj.append("-Wl,-init,__uClibc_init")
++
++            if soname == "libpthread.so.0":
++                symbols.add(ProvidedSymbol('__pthread_initialize_minimal_internal', None, None, True, True))
++                extra_flags.append("-Wl,-z,nodelete,-z,initfirst,-init=__pthread_initialize_minimal_internal")
+ 
+             map_file = find_pic_map(library)
+             if map_file:
diff --git a/tools/mklibs/patches/010-remove_STT_GNU_IFUNC.patch b/tools/mklibs/patches/010-remove_STT_GNU_IFUNC.patch
new file mode 100644
index 0000000000..6bae8c7ce5
--- /dev/null
+++ b/tools/mklibs/patches/010-remove_STT_GNU_IFUNC.patch
@@ -0,0 +1,20 @@
+--- a/src/mklibs-readelf/main.cpp
++++ b/src/mklibs-readelf/main.cpp
+@@ -84,7 +84,7 @@ static void process_symbols_provided (co
+       continue;
+     if (shndx == SHN_UNDEF || shndx == SHN_ABS)
+       continue;
+-    if (type != STT_NOTYPE && type != STT_OBJECT && type != STT_FUNC && type != STT_GNU_IFUNC && type != STT_COMMON && type != STT_TLS)
++    if (type != STT_NOTYPE && type != STT_OBJECT && type != STT_FUNC && type != STT_COMMON && type != STT_TLS)
+       continue;
+     if (!name.size())
+       continue;
+@@ -115,7 +115,7 @@ static void process_symbols_undefined (c
+       continue;
+     if (shndx != SHN_UNDEF)
+       continue;
+-    if (type != STT_NOTYPE && type != STT_OBJECT && type != STT_FUNC && type != STT_GNU_IFUNC && type != STT_COMMON && type != STT_TLS)
++    if (type != STT_NOTYPE && type != STT_OBJECT && type != STT_FUNC && type != STT_COMMON && type != STT_TLS)
+       continue;
+     if (!name.size())
+       continue;
diff --git a/tools/mklibs/patches/011-remove_multiarch.patch b/tools/mklibs/patches/011-remove_multiarch.patch
new file mode 100644
index 0000000000..a32d8ee17a
--- /dev/null
+++ b/tools/mklibs/patches/011-remove_multiarch.patch
@@ -0,0 +1,10 @@
+--- a/src/mklibs
++++ b/src/mklibs
+@@ -263,6 +263,7 @@ def extract_soname(so_file):
+     return ""
+ 
+ def multiarch(paths):
++    return paths
+     devnull = open('/dev/null', 'w')
+     dpkg_architecture = subprocess.Popen(
+         ['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
diff --git a/tools/mm-macros/Makefile b/tools/mm-macros/Makefile
new file mode 100644
index 0000000000..3c457ef28e
--- /dev/null
+++ b/tools/mm-macros/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2010-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mm-macros
+PKG_VERSION:=0.9.10
+
+PKG_SOURCE_URL:=@GNOME/mm-common/0.9
+PKG_SOURCE:=mm-common-$(PKG_VERSION).tar.xz
+PKG_MD5SUM:=49dc47af8c89ce5b3c768306b9a0f922
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/mm-common-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/share/aclocal
+	$(INSTALL_DATA) $(HOST_BUILD_DIR)/macros/*.m4 $(STAGING_DIR_HOST)/share/aclocal/
+endef
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/mpc/Makefile b/tools/mpc/Makefile
new file mode 100644
index 0000000000..f0bf8f4589
--- /dev/null
+++ b/tools/mpc/Makefile
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2009-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mpc
+PKG_VERSION:=1.0.3
+
+PKG_SOURCE_URL:=@GNU/mpc/
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_MD5SUM:=d6a1d5f8ddea3abd2cc3e98f58352d26
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport CFLAGS
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static \
+	--disable-shared \
+	--with-mpfr=$(TOPDIR)/staging_dir/host \
+	--with-gmp=$(TOPDIR)/staging_dir/host
+
+$(eval $(call HostBuild))
diff --git a/tools/mpfr/Makefile b/tools/mpfr/Makefile
new file mode 100644
index 0000000000..47ff1c5539
--- /dev/null
+++ b/tools/mpfr/Makefile
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2009-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mpfr
+PKG_VERSION:=3.1.5
+
+PKG_SOURCE_URL:=http://www.mpfr.org/mpfr-$(PKG_VERSION) \
+		@GNU/mpfr
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MD5SUM:=c4ac246cf9795a4491e7766002cd528f
+
+HOST_BUILD_PARALLEL:=1
+HOST_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static \
+	--disable-shared \
+	--with-gmp=$(STAGING_DIR_HOST)
+
+$(eval $(call HostBuild))
diff --git a/tools/mpfr/patches/001-only_src.patch b/tools/mpfr/patches/001-only_src.patch
new file mode 100644
index 0000000000..b983f879c2
--- /dev/null
+++ b/tools/mpfr/patches/001-only_src.patch
@@ -0,0 +1,22 @@
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -18,7 +18,7 @@ AUTOMAKE_OPTIONS = gnu
+ # old Automake version.
+ ACLOCAL_AMFLAGS = -I m4
+ 
+-SUBDIRS = doc src tests tune
++SUBDIRS = src
+ 
+ nobase_dist_doc_DATA = AUTHORS BUGS COPYING COPYING.LESSER NEWS TODO \
+   examples/ReadMe examples/divworst.c examples/rndo-add.c examples/sample.c \
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -378,7 +378,7 @@ AUTOMAKE_OPTIONS = gnu
+ # libtoolize and in case some developer needs to switch back to an
+ # old Automake version.
+ ACLOCAL_AMFLAGS = -I m4
+-SUBDIRS = doc src tests tune
++SUBDIRS = src
+ nobase_dist_doc_DATA = AUTHORS BUGS COPYING COPYING.LESSER NEWS TODO \
+   examples/ReadMe examples/divworst.c examples/rndo-add.c examples/sample.c \
+   examples/version.c
diff --git a/tools/mpfr/patches/100-freebsd-compat.patch b/tools/mpfr/patches/100-freebsd-compat.patch
new file mode 100644
index 0000000000..fa28a67d95
--- /dev/null
+++ b/tools/mpfr/patches/100-freebsd-compat.patch
@@ -0,0 +1,10 @@
+--- a/src/vasprintf.c
++++ b/src/vasprintf.c
+@@ -42,6 +42,7 @@ http://www.gnu.org/licenses/ or write to
+ #endif /* HAVE_VA_COPY */
+ 
+ #ifdef HAVE_WCHAR_H
++#include <stddef.h>
+ #include <wchar.h>
+ #endif
+ 
diff --git a/tools/mtd-utils/Makefile b/tools/mtd-utils/Makefile
new file mode 100644
index 0000000000..e56896ae2c
--- /dev/null
+++ b/tools/mtd-utils/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mtd-utils
+PKG_VERSION:=1.5.2
+
+PKG_SOURCE_VERSION:=aea36417067dade75192bafa03af70b6eb2677b1
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz
+PKG_SOURCE_URL:=git://git.infradead.org/mtd-utils.git
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_MIRROR_MD5SUM:=e11b342b85a36b2e438a8412ec52f87621d3046aec1a93039f8c72de9990b2a7
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CFLAGS += -I$(STAGING_DIR_HOST)/include/e2fsprogs
+CFLAGS := $(HOST_CFLAGS) -I$(HOST_BUILD_DIR)/include -L$(HOST_BUILD_DIR) -L$(STAGING_DIR_HOST)/lib -DNO_NATIVE_SUPPORT
+ifneq ($(HOST_OS),Linux)
+CFLAGS += -Dloff_t=off_t -D__BYTE_ORDER=BYTE_ORDER -include getline.h -include endian.h -I$(CURDIR)/include -include fls.h
+MTD_STATIC := 0
+else
+MTD_STATIC := 1
+endif
+
+MTD_MAKEOPTS = \
+	CFLAGS="$(CFLAGS)" \
+	LDFLAGS="$(HOST_LDFLAGS)" \
+	WITHOUT_LZO=1 WITHOUT_XATTR=1 \
+	SUBDIRS="" \
+	BUILDDIR="$(HOST_BUILD_DIR)" \
+	STATIC=$(MTD_STATIC) \
+	V=$(if $(findstring c,$(OPENWRT_VERBOSE)),1)
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) \
+		$(MTD_MAKEOPTS) \
+		TARGETS="mkfs.jffs2 ubi-utils/ubinize mkfs.ubifs/mkfs.ubifs"
+endef
+
+define Host/Install
+	$(CP) \
+		$(HOST_BUILD_DIR)/mkfs.jffs2 \
+		$(HOST_BUILD_DIR)/mkfs.ubifs/mkfs.ubifs \
+		$(HOST_BUILD_DIR)/ubi-utils/ubinize \
+		$(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/{mkfs.jffs2,mkfs.ubifs,ubinize}
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/mtd-utils/include/fls.h b/tools/mtd-utils/include/fls.h
new file mode 100644
index 0000000000..7514253cc0
--- /dev/null
+++ b/tools/mtd-utils/include/fls.h
@@ -0,0 +1,2 @@
+#include <string.h>
+#define fls local_fls
diff --git a/tools/mtd-utils/include/linux/types.h b/tools/mtd-utils/include/linux/types.h
new file mode 100644
index 0000000000..559fac7a2c
--- /dev/null
+++ b/tools/mtd-utils/include/linux/types.h
@@ -0,0 +1,18 @@
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#include <mtd/ubi-media.h>
+
+typedef uint16_t __u16;
+typedef uint32_t __u32;
+typedef uint64_t __u64;
+
+typedef __u16 __le16;
+typedef __u32 __le32;
+typedef __u64 __le64;
+typedef __u64 off64_t;
+
+typedef __u16  __sum16;
+typedef __u32  __wsum;
+
+#endif /* _LINUX_TYPES_H */
diff --git a/tools/mtd-utils/patches/100-sscanf_fix.patch b/tools/mtd-utils/patches/100-sscanf_fix.patch
new file mode 100644
index 0000000000..0af583f4cb
--- /dev/null
+++ b/tools/mtd-utils/patches/100-sscanf_fix.patch
@@ -0,0 +1,11 @@
+--- a/mkfs.jffs2.c
++++ b/mkfs.jffs2.c
+@@ -422,7 +422,7 @@ static int interpret_table_entry(struct
+ 
+ 	if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
+ 				SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
+-				&start, &increment, &count) < 0)
++				&start, &increment, &count) < 10)
+ 	{
+ 		return 1;
+ 	}
diff --git a/tools/mtd-utils/patches/110-portability.patch b/tools/mtd-utils/patches/110-portability.patch
new file mode 100644
index 0000000000..c4cdab928a
--- /dev/null
+++ b/tools/mtd-utils/patches/110-portability.patch
@@ -0,0 +1,170 @@
+--- a/compr_lzo.c
++++ b/compr_lzo.c
+@@ -26,7 +26,6 @@
+ #include <string.h>
+ 
+ #ifndef WITHOUT_LZO
+-#include <asm/types.h>
+ #include <linux/jffs2.h>
+ #include <lzo/lzo1x.h>
+ #include "compr.h"
+--- a/compr_zlib.c
++++ b/compr_zlib.c
+@@ -39,7 +39,6 @@
+ #include <zlib.h>
+ #undef crc32
+ #include <stdio.h>
+-#include <asm/types.h>
+ #include <linux/jffs2.h>
+ #include "common.h"
+ #include "compr.h"
+--- a/rbtree.h
++++ b/rbtree.h
+@@ -94,8 +94,7 @@ static inline struct page * rb_insert_pa
+ #ifndef	_LINUX_RBTREE_H
+ #define	_LINUX_RBTREE_H
+ 
+-#include <linux/kernel.h>
+-#include <linux/stddef.h>
++#include <stddef.h>
+ 
+ struct rb_node
+ {
+--- a/include/mtd/ubi-media.h
++++ b/include/mtd/ubi-media.h
+@@ -30,7 +30,15 @@
+ #ifndef __UBI_MEDIA_H__
+ #define __UBI_MEDIA_H__
+ 
++#ifdef __linux__
+ #include <asm/byteorder.h>
++#else
++#include <stdint.h>
++typedef uint8_t __u8;
++typedef uint16_t __be16;
++typedef uint32_t __be32;
++typedef uint64_t __be64;
++#endif
+ 
+ /* The version of UBI images supported by this implementation */
+ #define UBI_VERSION 1
+--- a/mkfs.ubifs/mkfs.ubifs.h
++++ b/mkfs.ubifs/mkfs.ubifs.h
+@@ -32,7 +32,17 @@
+ #include <endian.h>
+ #include <byteswap.h>
+ #include <linux/types.h>
++#ifdef __linux__
+ #include <linux/fs.h>
++# if defined(__x86_64__) && defined(__ILP32__)
++#  define llseek lseek64
++# endif
++#else
++# ifndef O_LARGEFILE
++#  define O_LARGEFILE 0
++# endif
++# define llseek lseek
++#endif
+ 
+ #include <getopt.h>
+ #include <sys/types.h>
+--- a/mkfs.ubifs/mkfs.ubifs.c
++++ b/mkfs.ubifs/mkfs.ubifs.c
+@@ -1010,6 +1010,7 @@ static int add_inode_with_data(struct st
+ 
+ 	if (c->default_compr != UBIFS_COMPR_NONE)
+ 		use_flags |= UBIFS_COMPR_FL;
++#ifndef NO_NATIVE_SUPPORT
+ 	if (flags & FS_COMPR_FL)
+ 		use_flags |= UBIFS_COMPR_FL;
+ 	if (flags & FS_SYNC_FL)
+@@ -1020,6 +1021,7 @@ static int add_inode_with_data(struct st
+ 		use_flags |= UBIFS_APPEND_FL;
+ 	if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode))
+ 		use_flags |= UBIFS_DIRSYNC_FL;
++#endif
+ 
+ 	memset(ino, 0, UBIFS_INO_NODE_SZ);
+ 
+@@ -1089,7 +1091,9 @@ static int add_dir_inode(DIR *dir, ino_t
+ 		fd = dirfd(dir);
+ 		if (fd == -1)
+ 			return sys_err_msg("dirfd failed");
++#ifndef NO_NATIVE_SUPPORT
+ 		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
++#endif
+ 			flags = 0;
+ 	}
+ 
+@@ -1274,10 +1278,12 @@ static int add_file(const char *path_nam
+ 		key_write(&key, &dn->key);
+ 		dn->size = cpu_to_le32(bytes_read);
+ 		out_len = NODE_BUFFER_SIZE - UBIFS_DATA_NODE_SZ;
++#ifndef NO_NATIVE_SUPPORT
+ 		if (c->default_compr == UBIFS_COMPR_NONE &&
+ 		    (flags & FS_COMPR_FL))
+ 			use_compr = UBIFS_COMPR_LZO;
+ 		else
++#endif
+ 			use_compr = c->default_compr;
+ 		compr_type = compress_data(buf, bytes_read, &dn->data,
+ 					   &out_len, use_compr);
+@@ -1319,7 +1325,9 @@ static int add_non_dir(const char *path_
+ 		if (fd == -1)
+ 			return sys_err_msg("failed to open file '%s'",
+ 					   path_name);
++#ifndef NO_NATIVE_SUPPORT
+ 		if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1)
++#endif
+ 			flags = 0;
+ 		if (close(fd) == -1)
+ 			return sys_err_msg("failed to close file '%s'",
+--- a/mkfs.ubifs/devtable.c
++++ b/mkfs.ubifs/devtable.c
+@@ -134,6 +134,7 @@ static int interpret_table_entry(const c
+ 	unsigned int mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
+ 	unsigned int start = 0, increment = 0, count = 0;
+ 
++	buf[1023] = 0;
+ 	if (sscanf(line, "%1023s %c %o %u %u %u %u %u %u %u",
+ 		   buf, &type, &mode, &uid, &gid, &major, &minor,
+ 		   &start, &increment, &count) < 0)
+@@ -144,8 +145,8 @@ static int interpret_table_entry(const c
+ 		buf, type, mode, uid, gid, major, minor, start,
+ 		increment, count);
+ 
+-	len = strnlen(buf, 1024);
+-	if (len == 1024)
++	len = strlen(buf);
++	if (len == 1023)
+ 		return err_msg("too long path");
+ 
+ 	if (!strcmp(buf, "/"))
+--- a/include/common.h
++++ b/include/common.h
+@@ -26,7 +26,6 @@
+ #include <string.h>
+ #include <fcntl.h>
+ #include <errno.h>
+-#include <features.h>
+ #include <inttypes.h>
+ #include "version.h"
+ 
+--- a/include/mtd/ubifs-media.h
++++ b/include/mtd/ubifs-media.h
+@@ -33,7 +33,15 @@
+ #ifndef __UBIFS_MEDIA_H__
+ #define __UBIFS_MEDIA_H__
+ 
++#ifdef __linux__
+ #include <asm/byteorder.h>
++#else
++#include <stdint.h>
++typedef uint8_t __u8;
++typedef uint16_t __be16;
++typedef uint32_t __be32;
++typedef uint64_t __be64;
++#endif
+ 
+ /* UBIFS node magic number (must not have the padding byte first or last) */
+ #define UBIFS_NODE_MAGIC  0x06101831
diff --git a/tools/mtd-utils/patches/130-lzma_jffs2.patch b/tools/mtd-utils/patches/130-lzma_jffs2.patch
new file mode 100644
index 0000000000..b04f019922
--- /dev/null
+++ b/tools/mtd-utils/patches/130-lzma_jffs2.patch
@@ -0,0 +1,5030 @@
+--- a/Makefile
++++ b/Makefile
+@@ -4,6 +4,7 @@
+ VERSION = 1.5.2
+ 
+ CPPFLAGS += -D_GNU_SOURCE -I./include -I$(BUILDDIR)/include -I./ubi-utils/include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS)
++CPPFLAGS += -I./include/linux/lzma
+ 
+ ifeq ($(WITHOUT_XATTR), 1)
+   CPPFLAGS += -DWITHOUT_XATTR
+@@ -84,7 +85,9 @@ $(BUILDDIR)/include/version.h.tmp:
+ #
+ # Utils in top level
+ #
+-obj-mkfs.jffs2 = compr_rtime.o compr_zlib.o compr_lzo.o compr.o rbtree.o
++obj-mkfs.jffs2 = compr_rtime.o compr_zlib.o $(if $(WITHOUT_LZO),,compr_lzo.o)\
++	compr_lzma.o lzma/LzFind.o lzma/LzmaEnc.o lzma/LzmaDec.o \
++	compr.o rbtree.o
+ LDFLAGS_mkfs.jffs2 = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+ LDLIBS_mkfs.jffs2  = -lz $(LZOLDLIBS)
+ 
+--- a/compr.c
++++ b/compr.c
+@@ -520,6 +520,9 @@ int jffs2_compressors_init(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_init();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_init();
++#endif
+ 	return 0;
+ }
+ 
+@@ -534,5 +537,8 @@ int jffs2_compressors_exit(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_exit();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++        jffs2_lzma_exit();
++#endif
+ 	return 0;
+ }
+--- a/compr.h
++++ b/compr.h
+@@ -18,13 +18,14 @@
+ 
+ #define CONFIG_JFFS2_ZLIB
+ #define CONFIG_JFFS2_RTIME
+-#define CONFIG_JFFS2_LZO
++#define CONFIG_JFFS2_LZMA
+ 
+ #define JFFS2_RUBINMIPS_PRIORITY 10
+ #define JFFS2_DYNRUBIN_PRIORITY  20
+ #define JFFS2_RTIME_PRIORITY     50
+-#define JFFS2_ZLIB_PRIORITY      60
+-#define JFFS2_LZO_PRIORITY       80
++#define JFFS2_LZMA_PRIORITY      70
++#define JFFS2_ZLIB_PRIORITY      80
++#define JFFS2_LZO_PRIORITY       90
+ 
+ #define JFFS2_COMPR_MODE_NONE       0
+ #define JFFS2_COMPR_MODE_PRIORITY   1
+@@ -115,5 +116,10 @@ void jffs2_rtime_exit(void);
+ int jffs2_lzo_init(void);
+ void jffs2_lzo_exit(void);
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++int jffs2_lzma_init(void);
++void jffs2_lzma_exit(void);
++#endif
++
+ 
+ #endif /* __JFFS2_COMPR_H__ */
+--- /dev/null
++++ b/compr_lzma.c
+@@ -0,0 +1,128 @@
++/*
++ * JFFS2 -- Journalling Flash File System, Version 2.
++ *
++ * For licensing information, see the file 'LICENCE' in this directory.
++ *
++ * JFFS2 wrapper to the LZMA C SDK
++ *
++ */
++
++#include <linux/lzma.h>
++#include "compr.h"
++
++#ifdef __KERNEL__
++	static DEFINE_MUTEX(deflate_mutex);
++#endif
++
++CLzmaEncHandle *p;
++Byte propsEncoded[LZMA_PROPS_SIZE];
++SizeT propsSize = sizeof(propsEncoded);
++
++STATIC void lzma_free_workspace(void)
++{
++	LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
++}
++
++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
++{
++	if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
++	{
++		PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
++		return -ENOMEM;
++	}
++
++	if (LzmaEnc_SetProps(p, props) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++	
++	if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++        return 0;
++}
++
++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
++			      uint32_t *sourcelen, uint32_t *dstlen)
++{
++	SizeT compress_size = (SizeT)(*dstlen);
++	int ret;
++
++	#ifdef __KERNEL__
++		mutex_lock(&deflate_mutex);
++	#endif
++
++	ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
++		0, NULL, &lzma_alloc, &lzma_alloc);
++
++	#ifdef __KERNEL__
++		mutex_unlock(&deflate_mutex);
++	#endif
++
++	if (ret != SZ_OK)
++		return -1;
++
++	*dstlen = (uint32_t)compress_size;
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
++				 uint32_t srclen, uint32_t destlen)
++{
++	int ret;
++	SizeT dl = (SizeT)destlen;
++	SizeT sl = (SizeT)srclen;
++	ELzmaStatus status;
++	
++	ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
++		propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
++
++	if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
++		return -1;
++
++	return 0;
++}
++
++static struct jffs2_compressor jffs2_lzma_comp = {
++	.priority = JFFS2_LZMA_PRIORITY,
++	.name = "lzma",
++	.compr = JFFS2_COMPR_LZMA,
++	.compress = &jffs2_lzma_compress,
++	.decompress = &jffs2_lzma_decompress,
++	.disabled = 0,
++};
++
++int INIT jffs2_lzma_init(void)
++{
++        int ret;
++	CLzmaEncProps props;
++	LzmaEncProps_Init(&props);
++
++        props.dictSize = LZMA_BEST_DICT(0x2000);
++        props.level = LZMA_BEST_LEVEL;
++        props.lc = LZMA_BEST_LC;
++        props.lp = LZMA_BEST_LP;
++        props.pb = LZMA_BEST_PB;
++        props.fb = LZMA_BEST_FB;
++
++	ret = lzma_alloc_workspace(&props);
++        if (ret < 0)
++                return ret;
++
++	ret = jffs2_register_compressor(&jffs2_lzma_comp);
++	if (ret)
++		lzma_free_workspace();
++	
++        return ret;
++}
++
++void jffs2_lzma_exit(void)
++{
++	jffs2_unregister_compressor(&jffs2_lzma_comp);
++	lzma_free_workspace();
++}
+--- a/include/linux/jffs2.h
++++ b/include/linux/jffs2.h
+@@ -47,6 +47,7 @@
+ #define JFFS2_COMPR_DYNRUBIN	0x05
+ #define JFFS2_COMPR_ZLIB	0x06
+ #define JFFS2_COMPR_LZO		0x07
++#define JFFS2_COMPR_LZMA	0x08
+ /* Compatibility flags. */
+ #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+ #define JFFS2_NODE_ACCURATE 0x2000
+--- /dev/null
++++ b/include/linux/lzma.h
+@@ -0,0 +1,61 @@
++#ifndef __LZMA_H__
++#define __LZMA_H__
++
++#ifdef __KERNEL__
++	#include <linux/kernel.h>
++	#include <linux/sched.h>
++	#include <linux/slab.h>
++	#include <linux/vmalloc.h>
++	#include <linux/init.h>
++	#define LZMA_MALLOC vmalloc
++	#define LZMA_FREE vfree
++	#define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
++	#define INIT __init
++	#define STATIC static
++#else
++	#include <stdint.h>
++	#include <stdlib.h>
++	#include <stdio.h>
++	#include <unistd.h>
++	#include <string.h>
++	#include <errno.h>
++	#include <linux/jffs2.h>
++	#ifndef PAGE_SIZE
++		extern int page_size;
++		#define PAGE_SIZE page_size
++	#endif
++	#define LZMA_MALLOC malloc
++	#define LZMA_FREE free
++	#define PRINT_ERROR(msg) fprintf(stderr, msg)
++	#define INIT
++	#define STATIC
++#endif
++
++#include "lzma/LzmaDec.h"
++#include "lzma/LzmaEnc.h"
++
++#define LZMA_BEST_LEVEL (9)
++#define LZMA_BEST_LC    (0)
++#define LZMA_BEST_LP    (0)
++#define LZMA_BEST_PB    (0)
++#define LZMA_BEST_FB  (273)
++
++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
++
++static void *p_lzma_malloc(void *p, size_t size)
++{
++        if (size == 0)
++                return NULL;
++
++        return LZMA_MALLOC(size);
++}
++
++static void p_lzma_free(void *p, void *address)
++{
++        if (address != NULL)
++                LZMA_FREE(address);
++}
++
++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free};
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzFind.h
+@@ -0,0 +1,116 @@
++/* LzFind.h  -- Match finder for LZ algorithms
++2008-04-04
++Copyright (c) 1999-2008 Igor Pavlov
++You can use any of the following license options:
++  1) GNU Lesser General Public License (GNU LGPL)
++  2) Common Public License (CPL)
++  3) Common Development and Distribution License (CDDL) Version 1.0 
++  4) Igor Pavlov, as the author of this code, expressly permits you to 
++     statically or dynamically link your code (or bind by name) to this file, 
++     while you keep this file unmodified.
++*/
++
++#ifndef __LZFIND_H
++#define __LZFIND_H
++
++#include "Types.h"
++
++typedef UInt32 CLzRef;
++
++typedef struct _CMatchFinder
++{
++  Byte *buffer;
++  UInt32 pos;
++  UInt32 posLimit;
++  UInt32 streamPos;
++  UInt32 lenLimit;
++
++  UInt32 cyclicBufferPos;
++  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
++
++  UInt32 matchMaxLen;
++  CLzRef *hash;
++  CLzRef *son;
++  UInt32 hashMask;
++  UInt32 cutValue;
++
++  Byte *bufferBase;
++  ISeqInStream *stream;
++  int streamEndWasReached;
++
++  UInt32 blockSize;
++  UInt32 keepSizeBefore;
++  UInt32 keepSizeAfter;
++
++  UInt32 numHashBytes;
++  int directInput;
++  int btMode;
++  /* int skipModeBits; */
++  int bigHash;
++  UInt32 historySize;
++  UInt32 fixedHashSize;
++  UInt32 hashSizeSum;
++  UInt32 numSons;
++  SRes result;
++  UInt32 crc[256];
++} CMatchFinder;
++
++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
++
++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
++
++int MatchFinder_NeedMove(CMatchFinder *p);
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
++void MatchFinder_MoveBlock(CMatchFinder *p);
++void MatchFinder_ReadIfRequired(CMatchFinder *p);
++
++void MatchFinder_Construct(CMatchFinder *p);
++
++/* Conditions:
++     historySize <= 3 GB
++     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
++*/
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc);
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
++    UInt32 *distances, UInt32 maxLen);
++
++/* 
++Conditions:
++  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
++  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
++*/
++
++typedef void (*Mf_Init_Func)(void *object);
++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
++typedef void (*Mf_Skip_Func)(void *object, UInt32);
++
++typedef struct _IMatchFinder
++{
++  Mf_Init_Func Init;
++  Mf_GetIndexByte_Func GetIndexByte;
++  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
++  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
++  Mf_GetMatches_Func GetMatches;
++  Mf_Skip_Func Skip;
++} IMatchFinder;
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
++
++void MatchFinder_Init(CMatchFinder *p);
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzHash.h
+@@ -0,0 +1,56 @@
++/* LzHash.h  -- HASH functions for LZ algorithms
++2008-03-26
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzFind.h for license options */
++
++#ifndef __LZHASH_H
++#define __LZHASH_H
++
++#define kHash2Size (1 << 10)
++#define kHash3Size (1 << 16)
++#define kHash4Size (1 << 20)
++
++#define kFix3HashSize (kHash2Size)
++#define kFix4HashSize (kHash2Size + kHash3Size)
++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
++
++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
++
++#define HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
++
++#define HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
++
++#define HASH5_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
++  hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
++  hash4Value &= (kHash4Size - 1); }
++
++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
++
++
++#define MT_HASH2_CALC \
++  hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
++
++#define MT_HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
++
++#define MT_HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaDec.h
+@@ -0,0 +1,232 @@
++/* LzmaDec.h -- LZMA Decoder
++2008-04-29
++Copyright (c) 1999-2008 Igor Pavlov
++You can use any of the following license options:
++  1) GNU Lesser General Public License (GNU LGPL)
++  2) Common Public License (CPL)
++  3) Common Development and Distribution License (CDDL) Version 1.0 
++  4) Igor Pavlov, as the author of this code, expressly permits you to 
++     statically or dynamically link your code (or bind by name) to this file, 
++     while you keep this file unmodified.
++*/
++
++#ifndef __LZMADEC_H
++#define __LZMADEC_H
++
++#include "Types.h"
++
++/* #define _LZMA_PROB32 */
++/* _LZMA_PROB32 can increase the speed on some CPUs, 
++   but memory usage for CLzmaDec::probs will be doubled in that case */
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++
++/* ---------- LZMA Properties ---------- */  
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaProps
++{
++  unsigned lc, lp, pb;
++  UInt32 dicSize;
++} CLzmaProps;
++
++/* LzmaProps_Decode - decodes properties
++Returns:
++  SZ_OK
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
++
++
++/* ---------- LZMA Decoder state ---------- */  
++
++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
++   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
++
++#define LZMA_REQUIRED_INPUT_MAX 20
++
++typedef struct
++{
++  CLzmaProps prop;
++  CLzmaProb *probs;
++  Byte *dic;
++  const Byte *buf;
++  UInt32 range, code;
++  SizeT dicPos;
++  SizeT dicBufSize;
++  UInt32 processedPos;
++  UInt32 checkDicSize;
++  unsigned state;
++  UInt32 reps[4];
++  unsigned remainLen;
++  int needFlush;
++  int needInitState;
++  UInt32 numProbs;
++  unsigned tempBufSize;
++  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
++} CLzmaDec;
++
++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
++
++void LzmaDec_Init(CLzmaDec *p);
++
++/* There are two types of LZMA streams:
++     0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
++     1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
++
++typedef enum 
++{
++  LZMA_FINISH_ANY,   /* finish at any point */      
++  LZMA_FINISH_END    /* block must be finished at the end */
++} ELzmaFinishMode;
++
++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
++
++   You must use LZMA_FINISH_END, when you know that current output buffer 
++   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
++
++   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
++   and output value of destLen will be less than output buffer size limit.
++   You can check status result also.
++
++   You can use multiple checks to test data integrity after full decompression:
++     1) Check Result and "status" variable.
++     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
++     3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 
++        You must use correct finish mode in that case. */ 
++
++typedef enum 
++{
++  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
++  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
++  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
++  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */   
++  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
++} ELzmaStatus;
++
++/* ELzmaStatus is used only as output value for function call */
++
++
++/* ---------- Interfaces ---------- */  
++
++/* There are 3 levels of interfaces:
++     1) Dictionary Interface
++     2) Buffer Interface
++     3) One Call Interface
++   You can select any of these interfaces, but don't mix functions from different 
++   groups for same object. */
++
++
++/* There are two variants to allocate state for Dictionary Interface:
++     1) LzmaDec_Allocate / LzmaDec_Free
++     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
++   You can use variant 2, if you set dictionary buffer manually. 
++   For Buffer Interface you must always use variant 1. 
++
++LzmaDec_Allocate* can return:
++  SZ_OK
++  SZ_ERROR_MEM         - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++   
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
++
++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
++
++/* ---------- Dictionary Interface ---------- */  
++
++/* You can use it, if you want to eliminate the overhead for data copying from 
++   dictionary to some other external buffer.
++   You must work with CLzmaDec variables directly in this interface.
++
++   STEPS:
++     LzmaDec_Constr()
++     LzmaDec_Allocate()
++     for (each new stream)
++     {
++       LzmaDec_Init()
++       while (it needs more decompression)
++       {
++         LzmaDec_DecodeToDic()
++         use data from CLzmaDec::dic and update CLzmaDec::dicPos
++       }
++     }
++     LzmaDec_Free()
++*/
++
++/* LzmaDec_DecodeToDic
++   
++   The decoding to internal dictionary buffer (CLzmaDec::dic).
++   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! 
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (dicLimit).
++  LZMA_FINISH_ANY - Decode just dicLimit bytes.
++  LZMA_FINISH_END - Stream must be finished after dicLimit.
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED 
++      LZMA_STATUS_NEEDS_MORE_INPUT
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++*/
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, 
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- Buffer Interface ---------- */  
++
++/* It's zlib-like interface.
++   See LzmaDec_DecodeToDic description for information about STEPS and return results,
++   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
++   to work with CLzmaDec variables manually.
++
++finishMode: 
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++*/
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, 
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- One Call Interface ---------- */  
++
++/* LzmaDecode
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED 
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++  SZ_ERROR_MEM  - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
++*/
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 
++    ELzmaStatus *status, ISzAlloc *alloc);
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -0,0 +1,74 @@
++/*  LzmaEnc.h -- LZMA Encoder
++2008-04-27
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzFind.h for license options */
++
++#ifndef __LZMAENC_H
++#define __LZMAENC_H
++
++#include "Types.h"
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaEncProps
++{
++  int level;       /*  0 <= level <= 9 */ 
++  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
++                      (1 << 12) <= dictSize <= (1 << 30) for 64-bit version 
++                       default = (1 << 24) */
++  int lc;          /* 0 <= lc <= 8, default = 3 */ 
++  int lp;          /* 0 <= lp <= 4, default = 0 */ 
++  int pb;          /* 0 <= pb <= 4, default = 2 */ 
++  int algo;        /* 0 - fast, 1 - normal, default = 1 */
++  int fb;          /* 5 <= fb <= 273, default = 32 */
++  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
++  int numHashBytes; /* 2, 3 or 4, default = 4 */
++  UInt32 mc;        /* 1 <= mc <= (1 << 30), default = 32 */
++  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
++  int numThreads;  /* 1 or 2, default = 2 */
++} CLzmaEncProps;
++
++void LzmaEncProps_Init(CLzmaEncProps *p);
++void LzmaEncProps_Normalize(CLzmaEncProps *p);
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
++
++
++/* ---------- CLzmaEncHandle Interface ---------- */
++
++/* LzmaEnc_* functions can return the following exit codes:
++Returns:
++  SZ_OK           - OK
++  SZ_ERROR_MEM    - Memory allocation error 
++  SZ_ERROR_PARAM  - Incorrect paramater in props
++  SZ_ERROR_WRITE  - Write callback error.
++  SZ_ERROR_PROGRESS - some break from progress callback
++  SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
++*/
++
++typedef void * CLzmaEncHandle;
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, 
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaEncode
++Return code:
++  SZ_OK               - OK
++  SZ_ERROR_MEM        - Memory allocation error 
++  SZ_ERROR_PARAM      - Incorrect paramater
++  SZ_ERROR_OUTPUT_EOF - output buffer overflow
++  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
++*/
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, 
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/Types.h
+@@ -0,0 +1,130 @@
++/* Types.h -- Basic types
++2008-04-11
++Igor Pavlov
++Public domain */
++
++#ifndef __7Z_TYPES_H
++#define __7Z_TYPES_H
++
++#define SZ_OK 0
++
++#define SZ_ERROR_DATA 1
++#define SZ_ERROR_MEM 2
++#define SZ_ERROR_CRC 3
++#define SZ_ERROR_UNSUPPORTED 4
++#define SZ_ERROR_PARAM 5
++#define SZ_ERROR_INPUT_EOF 6
++#define SZ_ERROR_OUTPUT_EOF 7
++#define SZ_ERROR_READ 8
++#define SZ_ERROR_WRITE 9
++#define SZ_ERROR_PROGRESS 10
++#define SZ_ERROR_FAIL 11
++#define SZ_ERROR_THREAD 12
++
++#define SZ_ERROR_ARCHIVE 16
++#define SZ_ERROR_NO_ARCHIVE 17
++
++typedef int SRes;
++
++#ifndef RINOK
++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
++#endif
++
++typedef unsigned char Byte;
++typedef short Int16;
++typedef unsigned short UInt16;
++
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef long Int32;
++typedef unsigned long UInt32;
++#else
++typedef int Int32;
++typedef unsigned int UInt32;
++#endif
++
++/* #define _SZ_NO_INT_64 */
++/* define it if your compiler doesn't support 64-bit integers */
++
++#ifdef _SZ_NO_INT_64
++
++typedef long Int64;
++typedef unsigned long UInt64;
++
++#else
++
++#if defined(_MSC_VER) || defined(__BORLANDC__)
++typedef __int64 Int64;
++typedef unsigned __int64 UInt64;
++#else
++typedef long long int Int64;
++typedef unsigned long long int UInt64;
++#endif
++
++#endif
++
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++#include <stddef.h>
++typedef size_t SizeT;
++#endif
++
++typedef int Bool;
++#define True 1
++#define False 0
++
++
++#ifdef _MSC_VER
++
++#if _MSC_VER >= 1300
++#define MY_NO_INLINE __declspec(noinline)
++#else
++#define MY_NO_INLINE
++#endif
++
++#define MY_CDECL __cdecl
++#define MY_STD_CALL __stdcall 
++#define MY_FAST_CALL MY_NO_INLINE __fastcall 
++
++#else
++
++#define MY_CDECL
++#define MY_STD_CALL
++#define MY_FAST_CALL
++
++#endif
++
++
++/* The following interfaces use first parameter as pointer to structure */
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) < input(*size)) is allowed */
++} ISeqInStream;
++
++typedef struct
++{
++  size_t (*Write)(void *p, const void *buf, size_t size);
++    /* Returns: result - the number of actually written bytes.
++      (result < size) means error */
++} ISeqOutStream;
++
++typedef struct
++{
++  SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
++    /* Returns: result. (result != SZ_OK) means break.
++       Value (UInt64)(Int64)-1 for size means unknown value. */
++} ICompressProgress;
++
++typedef struct
++{
++  void *(*Alloc)(void *p, size_t size);
++  void (*Free)(void *p, void *address); /* address can be 0 */
++} ISzAlloc;
++
++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
++#define IAlloc_Free(p, a) (p)->Free((p), a)
++
++#endif
+--- /dev/null
++++ b/lzma/LzFind.c
+@@ -0,0 +1,753 @@
++/* LzFind.c  -- Match finder for LZ algorithms
++2008-04-04
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzFind.h for license options */
++
++#include <string.h>
++
++#include "LzFind.h"
++#include "LzHash.h"
++
++#define kEmptyHashValue 0
++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
++#define kNormalizeMask (~(kNormalizeStepMin - 1))
++#define kMaxHistorySize ((UInt32)3 << 30)
++
++#define kStartMaxLen 3
++
++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  if (!p->directInput)
++  {
++    alloc->Free(alloc, p->bufferBase);
++    p->bufferBase = 0;
++  }
++}
++
++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
++
++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
++{
++  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
++  if (p->directInput)
++  {
++    p->blockSize = blockSize;
++    return 1;
++  }
++  if (p->bufferBase == 0 || p->blockSize != blockSize)
++  {
++    LzInWindow_Free(p, alloc);
++    p->blockSize = blockSize;
++    p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
++  }
++  return (p->bufferBase != 0);
++}
++
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++
++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++{
++  p->posLimit -= subValue;
++  p->pos -= subValue;
++  p->streamPos -= subValue;
++}
++
++static void MatchFinder_ReadBlock(CMatchFinder *p)
++{
++  if (p->streamEndWasReached || p->result != SZ_OK)
++    return;
++  for (;;)
++  {
++    Byte *dest = p->buffer + (p->streamPos - p->pos);
++    size_t size = (p->bufferBase + p->blockSize - dest);
++    if (size == 0)
++      return;
++    p->result = p->stream->Read(p->stream, dest, &size);
++    if (p->result != SZ_OK)
++      return;
++    if (size == 0)
++    {
++      p->streamEndWasReached = 1;
++      return;
++    }
++    p->streamPos += (UInt32)size;
++    if (p->streamPos - p->pos > p->keepSizeAfter)
++      return;
++  }
++}
++
++void MatchFinder_MoveBlock(CMatchFinder *p)
++{
++  memmove(p->bufferBase, 
++    p->buffer - p->keepSizeBefore, 
++    (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
++  p->buffer = p->bufferBase + p->keepSizeBefore;
++}
++
++int MatchFinder_NeedMove(CMatchFinder *p)
++{
++  /* if (p->streamEndWasReached) return 0; */
++  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
++}
++
++void MatchFinder_ReadIfRequired(CMatchFinder *p)
++{
++  if (p->streamEndWasReached) 
++    return;
++  if (p->keepSizeAfter >= p->streamPos - p->pos)
++    MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
++{
++  if (MatchFinder_NeedMove(p))
++    MatchFinder_MoveBlock(p);
++  MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
++{
++  p->cutValue = 32;
++  p->btMode = 1;
++  p->numHashBytes = 4;
++  /* p->skipModeBits = 0; */
++  p->directInput = 0;
++  p->bigHash = 0;
++}
++
++#define kCrcPoly 0xEDB88320
++
++void MatchFinder_Construct(CMatchFinder *p)
++{
++  UInt32 i;
++  p->bufferBase = 0;
++  p->directInput = 0;
++  p->hash = 0;
++  MatchFinder_SetDefaultSettings(p);
++
++  for (i = 0; i < 256; i++)
++  {
++    UInt32 r = i;
++    int j;
++    for (j = 0; j < 8; j++)
++      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
++    p->crc[i] = r;
++  }
++}
++
++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->hash);
++  p->hash = 0;
++}
++
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  MatchFinder_FreeThisClassMemory(p, alloc);
++  LzInWindow_Free(p, alloc);
++}
++
++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
++{
++  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
++  if (sizeInBytes / sizeof(CLzRef) != num)
++    return 0;
++  return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
++}
++
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, 
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc)
++{
++  UInt32 sizeReserv;
++  if (historySize > kMaxHistorySize)
++  {
++    MatchFinder_Free(p, alloc);
++    return 0;
++  }
++  sizeReserv = historySize >> 1;
++  if (historySize > ((UInt32)2 << 30))
++    sizeReserv = historySize >> 2;
++  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
++
++  p->keepSizeBefore = historySize + keepAddBufferBefore + 1; 
++  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
++  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
++  if (LzInWindow_Create(p, sizeReserv, alloc))
++  {
++    UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
++    UInt32 hs;
++    p->matchMaxLen = matchMaxLen;
++    {
++      p->fixedHashSize = 0;
++      if (p->numHashBytes == 2)
++        hs = (1 << 16) - 1;
++      else
++      {
++        hs = historySize - 1;
++        hs |= (hs >> 1);
++        hs |= (hs >> 2);
++        hs |= (hs >> 4);
++        hs |= (hs >> 8);
++        hs >>= 1;
++        /* hs >>= p->skipModeBits; */
++        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
++        if (hs > (1 << 24))
++        {
++          if (p->numHashBytes == 3)
++            hs = (1 << 24) - 1;
++          else
++            hs >>= 1;
++        }
++      }
++      p->hashMask = hs;
++      hs++;
++      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
++      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
++      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
++      hs += p->fixedHashSize;
++    }
++
++    {
++      UInt32 prevSize = p->hashSizeSum + p->numSons;
++      UInt32 newSize;
++      p->historySize = historySize;
++      p->hashSizeSum = hs;
++      p->cyclicBufferSize = newCyclicBufferSize;
++      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
++      newSize = p->hashSizeSum + p->numSons;
++      if (p->hash != 0 && prevSize == newSize)
++        return 1;
++      MatchFinder_FreeThisClassMemory(p, alloc);
++      p->hash = AllocRefs(newSize, alloc);
++      if (p->hash != 0)
++      {
++        p->son = p->hash + p->hashSizeSum;
++        return 1;
++      }
++    }
++  }
++  MatchFinder_Free(p, alloc);
++  return 0;
++}
++
++static void MatchFinder_SetLimits(CMatchFinder *p)
++{
++  UInt32 limit = kMaxValForNormalize - p->pos;
++  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
++  if (limit2 < limit) 
++    limit = limit2;
++  limit2 = p->streamPos - p->pos;
++  if (limit2 <= p->keepSizeAfter)
++  {
++    if (limit2 > 0)
++      limit2 = 1;
++  }
++  else
++    limit2 -= p->keepSizeAfter;
++  if (limit2 < limit) 
++    limit = limit2;
++  {
++    UInt32 lenLimit = p->streamPos - p->pos;
++    if (lenLimit > p->matchMaxLen)
++      lenLimit = p->matchMaxLen;
++    p->lenLimit = lenLimit;
++  }
++  p->posLimit = p->pos + limit;
++}
++
++void MatchFinder_Init(CMatchFinder *p)
++{
++  UInt32 i;
++  for(i = 0; i < p->hashSizeSum; i++)
++    p->hash[i] = kEmptyHashValue;
++  p->cyclicBufferPos = 0;
++  p->buffer = p->bufferBase;
++  p->pos = p->streamPos = p->cyclicBufferSize;
++  p->result = SZ_OK;
++  p->streamEndWasReached = 0;
++  MatchFinder_ReadBlock(p);
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) 
++{ 
++  return (p->pos - p->historySize - 1) & kNormalizeMask; 
++}
++
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++{
++  UInt32 i;
++  for (i = 0; i < numItems; i++)
++  {
++    UInt32 value = items[i];
++    if (value <= subValue)
++      value = kEmptyHashValue;
++    else
++      value -= subValue;
++    items[i] = value;
++  }
++}
++
++static void MatchFinder_Normalize(CMatchFinder *p)
++{
++  UInt32 subValue = MatchFinder_GetSubValue(p);
++  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
++  MatchFinder_ReduceOffsets(p, subValue);
++}
++
++static void MatchFinder_CheckLimits(CMatchFinder *p)
++{
++  if (p->pos == kMaxValForNormalize)
++    MatchFinder_Normalize(p);
++  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
++    MatchFinder_CheckAndMoveAndRead(p);
++  if (p->cyclicBufferPos == p->cyclicBufferSize)
++    p->cyclicBufferPos = 0;
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
++    UInt32 *distances, UInt32 maxLen)
++{
++  son[_cyclicBufferPos] = curMatch;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++      return distances;
++    {
++      const Byte *pb = cur - delta;
++      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
++      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
++      {
++        UInt32 len = 0;
++        while(++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++            return distances;
++        }
++      }
++    }
++  }
++}
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, 
++    UInt32 *distances, UInt32 maxLen)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return distances;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        if (++len != lenLimit && pb[len] == cur[len])
++          while(++len != lenLimit)
++            if (pb[len] != cur[len])
++              break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return distances;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, 
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        while(++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        {
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++#define MOVE_POS \
++  ++p->cyclicBufferPos; \
++  p->buffer++; \
++  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
++
++#define MOVE_POS_RET MOVE_POS return offset;
++
++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
++
++#define GET_MATCHES_HEADER2(minLen, ret_op) \
++  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
++  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
++  cur = p->buffer;
++
++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
++#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
++
++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
++
++#define GET_MATCHES_FOOTER(offset, maxLen) \
++  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
++  distances + offset, maxLen) - distances); MOVE_POS_RET;
++
++#define SKIP_FOOTER \
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
++
++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(2)
++  HASH2_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 1)
++}
++
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 2)
++}
++
++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, delta2, maxLen, offset;
++  GET_MATCHES_HEADER(3)
++
++  HASH3_CALC;
++
++  delta2 = p->pos - p->hash[hash2Value];
++  curMatch = p->hash[kFix3HashSize + hashValue];
++  
++  p->hash[hash2Value] = 
++  p->hash[kFix3HashSize + hashValue] = p->pos;
++
++
++  maxLen = 2;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[0] = maxLen;
++    distances[1] = delta2 - 1;
++    offset = 2;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET; 
++    }
++  }
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++  
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET; 
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      p->son[p->cyclicBufferPos] = curMatch;
++      MOVE_POS_RET; 
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances + offset, maxLen) - (distances));
++  MOVE_POS_RET
++}
++
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances, 2) - (distances));
++  MOVE_POS_RET
++}
++
++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(2) 
++    HASH2_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value;
++    SKIP_HEADER(3)
++    HASH3_CALC;
++    curMatch = p->hash[kFix3HashSize + hashValue];
++    p->hash[hash2Value] =
++    p->hash[kFix3HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4) 
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] = p->pos;
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] =
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
++{
++  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
++  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
++  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
++  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
++  if (!p->btMode)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 2)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 3)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
++  }
++  else
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
++  }
++}
+--- /dev/null
++++ b/lzma/LzmaDec.c
+@@ -0,0 +1,1014 @@
++/* LzmaDec.c -- LZMA Decoder
++2008-04-29
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzmaDec.h for license options */
++
++#include "LzmaDec.h"
++
++#include <string.h>
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_INIT_SIZE 5
++
++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
++  { UPDATE_0(p); i = (i + i); A0; } else \
++  { UPDATE_1(p); i = (i + i) + 1; A1; } 
++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)               
++
++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
++#define TREE_DECODE(probs, limit, i) \
++  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
++
++/* #define _LZMA_SIZE_OPT */
++
++#ifdef _LZMA_SIZE_OPT
++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
++#else
++#define TREE_6_DECODE(probs, i) \
++  { i = 1; \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  i -= 0x40; }
++#endif
++
++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0_CHECK range = bound;
++#define UPDATE_1_CHECK range -= bound; code -= bound;
++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
++  { UPDATE_0_CHECK; i = (i + i); A0; } else \
++  { UPDATE_1_CHECK; i = (i + i) + 1; A1; } 
++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)               
++#define TREE_DECODE_CHECK(probs, limit, i) \
++  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while(i < limit); i -= limit; }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++/*
++#define LZMA_STREAM_WAS_FINISHED_ID (-1)
++#define LZMA_SPEC_LEN_OFFSET (-3)
++*/
++
++Byte kLiteralNextStates[kNumStates * 2] = 
++{
++  0, 0, 0, 0, 1, 2, 3,  4,  5,  6,  4,  5, 
++  7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10
++};
++
++#define LZMA_DIC_MIN (1 << 12)
++
++/* First LZMA-symbol is always decoded. 
++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization 
++Out:
++  Result:
++    0 - OK
++    1 - Error
++  p->remainLen:
++    < kMatchSpecLenStart : normal remain
++    = kMatchSpecLenStart : finished
++    = kMatchSpecLenStart + 1 : Flush marker
++    = kMatchSpecLenStart + 2 : State Init Marker
++*/
++
++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  CLzmaProb *probs = p->probs;
++
++  unsigned state = p->state;
++  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
++  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
++  unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
++  unsigned lc = p->prop.lc;
++
++  Byte *dic = p->dic;
++  SizeT dicBufSize = p->dicBufSize;
++  SizeT dicPos = p->dicPos;
++  
++  UInt32 processedPos = p->processedPos;
++  UInt32 checkDicSize = p->checkDicSize;
++  unsigned len = 0;
++
++  const Byte *buf = p->buf;
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++
++  do
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = processedPos & pbMask;
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0(prob)
++    {
++      unsigned symbol;
++      UPDATE_0(prob);
++      prob = probs + Literal;
++      if (checkDicSize != 0 || processedPos != 0)
++        prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + 
++        (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
++
++      if (state < kNumLitStates)
++      {
++        symbol = 1;
++        do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++        unsigned offs = 0x100;
++        symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      dic[dicPos++] = (Byte)symbol;
++      processedPos++;
++
++      state = kLiteralNextStates[state];
++      /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */
++      continue;
++    }
++    else             
++    {
++      UPDATE_1(prob);
++      prob = probs + IsRep + state;
++      IF_BIT_0(prob)
++      {
++        UPDATE_0(prob);
++        state += kNumStates;
++        prob = probs + LenCoder;
++      }
++      else
++      {
++        UPDATE_1(prob);
++        if (checkDicSize == 0 && processedPos == 0)
++          return SZ_ERROR_DATA;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0(prob)
++        {
++          UPDATE_0(prob);
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++            dicPos++;
++            processedPos++;
++            state = state < kNumLitStates ? 9 : 11;
++            continue;
++          }
++          UPDATE_1(prob);
++        }
++        else
++        {
++          UInt32 distance;
++          UPDATE_1(prob);
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            distance = rep1;
++          }
++          else 
++          {
++            UPDATE_1(prob);
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0(prob)
++            {
++              UPDATE_0(prob);
++              distance = rep2;
++            }
++            else
++            {
++              UPDATE_1(prob);
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        state = state < kNumLitStates ? 8 : 11;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0(probLen)
++        {
++          UPDATE_0(probLen);
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = (1 << kLenNumLowBits);
++        }
++        else
++        {
++          UPDATE_1(probLen);
++          probLen = prob + LenChoice2;
++          IF_BIT_0(probLen)
++          {
++            UPDATE_0(probLen);
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = (1 << kLenNumMidBits);
++          }
++          else
++          {
++            UPDATE_1(probLen);
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = (1 << kLenNumHighBits);
++          }
++        }
++        TREE_DECODE(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state >= kNumStates)
++      {
++        UInt32 distance;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
++        TREE_6_DECODE(prob, distance);
++        if (distance >= kStartPosModelIndex)
++        {
++          unsigned posSlot = (unsigned)distance; 
++          int numDirectBits = (int)(((distance >> 1) - 1));
++          distance = (2 | (distance & 1));
++          if (posSlot < kEndPosModelIndex)
++          {
++            distance <<= numDirectBits;
++            prob = probs + SpecPos + distance - posSlot - 1;
++            {
++              UInt32 mask = 1;
++              unsigned i = 1;
++              do
++              {
++                GET_BIT2(prob + i, i, ; , distance |= mask);
++                mask <<= 1;
++              }
++              while(--numDirectBits != 0);
++            }
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE
++              range >>= 1;
++              
++              {
++                UInt32 t;
++                code -= range;
++                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
++                distance = (distance << 1) + (t + 1);
++                code += range & t;
++              }
++              /*
++              distance <<= 1;
++              if (code >= range)
++              {
++                code -= range;
++                distance |= 1;
++              }
++              */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            distance <<= kNumAlignBits;
++            {
++              unsigned i = 1;
++              GET_BIT2(prob + i, i, ; , distance |= 1);
++              GET_BIT2(prob + i, i, ; , distance |= 2);
++              GET_BIT2(prob + i, i, ; , distance |= 4);
++              GET_BIT2(prob + i, i, ; , distance |= 8);
++            }
++            if (distance == (UInt32)0xFFFFFFFF)
++            {
++              len += kMatchSpecLenStart;
++              state -= kNumStates;
++              break;
++            }
++          }
++        }
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        rep0 = distance + 1; 
++        if (checkDicSize == 0)
++        {
++          if (distance >= processedPos)
++            return SZ_ERROR_DATA;
++        }
++        else if (distance >= checkDicSize)
++          return SZ_ERROR_DATA;
++        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
++        /* state = kLiteralNextStates[state]; */
++      }
++
++      len += kMatchMinLen;
++
++      {
++        SizeT rem = limit - dicPos;
++        unsigned curLen = ((rem < len) ? (unsigned)rem : len);
++        SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
++
++        processedPos += curLen;
++
++        len -= curLen;
++        if (pos + curLen <= dicBufSize)
++        {
++          Byte *dest = dic + dicPos;
++          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
++          const Byte *lim = dest + curLen;
++          dicPos += curLen;
++          do 
++            *(dest) = (Byte)*(dest + src); 
++          while (++dest != lim);
++        }
++        else
++        {
++          do
++          {
++            dic[dicPos++] = dic[pos];
++            if (++pos == dicBufSize)
++              pos = 0;
++          }
++          while (--curLen != 0);
++        }
++      }
++    }
++  }
++  while (dicPos < limit && buf < bufLimit);
++  NORMALIZE;
++  p->buf = buf;
++  p->range = range;
++  p->code = code;
++  p->remainLen = len;
++  p->dicPos = dicPos;
++  p->processedPos = processedPos;
++  p->reps[0] = rep0;
++  p->reps[1] = rep1;
++  p->reps[2] = rep2;
++  p->reps[3] = rep3;
++  p->state = state;
++
++  return SZ_OK;
++}
++
++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
++{
++  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
++  {
++    Byte *dic = p->dic;
++    SizeT dicPos = p->dicPos;
++    SizeT dicBufSize = p->dicBufSize;
++    unsigned len = p->remainLen;
++    UInt32 rep0 = p->reps[0];
++    if (limit - dicPos < len)
++      len = (unsigned)(limit - dicPos);
++
++    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
++      p->checkDicSize = p->prop.dicSize;
++
++    p->processedPos += len;
++    p->remainLen -= len;
++    while (len-- != 0)
++    {
++      dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++      dicPos++;
++    }
++    p->dicPos = dicPos;
++  }
++}
++
++/* LzmaDec_DecodeReal2 decodes LZMA-symbols and sets p->needFlush and p->needInit, if required. */
++
++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  do
++  {
++    SizeT limit2 = limit;
++    if (p->checkDicSize == 0)
++    {
++      UInt32 rem = p->prop.dicSize - p->processedPos;
++      if (limit - p->dicPos > rem)
++        limit2 = p->dicPos + rem;
++    }
++    RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
++    if (p->processedPos >= p->prop.dicSize)
++      p->checkDicSize = p->prop.dicSize;
++    LzmaDec_WriteRem(p, limit);
++  }
++  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
++
++  if (p->remainLen > kMatchSpecLenStart)
++  {
++    p->remainLen = kMatchSpecLenStart;
++  }
++  return 0;
++}
++
++typedef enum 
++{
++  DUMMY_ERROR, /* unexpected end of input stream */
++  DUMMY_LIT,
++  DUMMY_MATCH,
++  DUMMY_REP
++} ELzmaDummy;
++
++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
++{
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++  const Byte *bufLimit = buf + inSize;
++  CLzmaProb *probs = p->probs;
++  unsigned state = p->state;
++  ELzmaDummy res;
++
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0_CHECK(prob)
++    {
++      UPDATE_0_CHECK
++
++      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
++
++      prob = probs + Literal;
++      if (p->checkDicSize != 0 || p->processedPos != 0)
++        prob += (LZMA_LIT_SIZE * 
++          ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + 
++          (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
++
++      if (state < kNumLitStates)
++      {
++        unsigned symbol = 1;
++        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[p->dicPos - p->reps[0] + 
++            ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
++        unsigned offs = 0x100;
++        unsigned symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      res = DUMMY_LIT;
++    }
++    else             
++    {
++      unsigned len;
++      UPDATE_1_CHECK;
++
++      prob = probs + IsRep + state;
++      IF_BIT_0_CHECK(prob)
++      {
++        UPDATE_0_CHECK;
++        state = 0;
++        prob = probs + LenCoder;
++        res = DUMMY_MATCH;
++      }
++      else
++      {
++        UPDATE_1_CHECK;
++        res = DUMMY_REP;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0_CHECK(prob)
++        {
++          UPDATE_0_CHECK;
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++            NORMALIZE_CHECK;
++            return DUMMY_REP;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++          }
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++          }
++          else 
++          {
++            UPDATE_1_CHECK;
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0_CHECK(prob)
++            {
++              UPDATE_0_CHECK;
++            }
++            else
++            {
++              UPDATE_1_CHECK;
++            }
++          }
++        }
++        state = kNumStates;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0_CHECK(probLen)
++        {
++          UPDATE_0_CHECK;
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = 1 << kLenNumLowBits;
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          probLen = prob + LenChoice2;
++          IF_BIT_0_CHECK(probLen)
++          {
++            UPDATE_0_CHECK;
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = 1 << kLenNumMidBits;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = 1 << kLenNumHighBits;
++          }
++        }
++        TREE_DECODE_CHECK(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state < 4)
++      {
++        unsigned posSlot;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
++            kNumPosSlotBits);
++        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++
++          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
++
++          if (posSlot < kEndPosModelIndex)
++          {
++            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE_CHECK
++              range >>= 1;
++              code -= range & (((code - range) >> 31) - 1);
++              /* if (code >= range) code -= range; */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            numDirectBits = kNumAlignBits;
++          }
++          {
++            unsigned i = 1;
++            do
++            {
++              GET_BIT_CHECK(prob + i, i);
++            }
++            while(--numDirectBits != 0);
++          }
++        }
++      }
++    }
++  }
++  NORMALIZE_CHECK;
++  return res;
++}
++
++
++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
++{
++  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->range = 0xFFFFFFFF;
++  p->needFlush = 0;
++}
++
++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) 
++{ 
++  p->needFlush = 1; 
++  p->remainLen = 0; 
++  p->tempBufSize = 0; 
++
++  if (initDic)
++  {
++    p->processedPos = 0;
++    p->checkDicSize = 0;
++    p->needInitState = 1;
++  }
++  if (initState)
++    p->needInitState = 1;
++}
++
++void LzmaDec_Init(CLzmaDec *p) 
++{ 
++  p->dicPos = 0; 
++  LzmaDec_InitDicAndState(p, True, True);
++}
++
++static void LzmaDec_InitStateReal(CLzmaDec *p)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
++  UInt32 i;
++  CLzmaProb *probs = p->probs;
++  for (i = 0; i < numProbs; i++)
++    probs[i] = kBitModelTotal >> 1; 
++  p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
++  p->state = 0;
++  p->needInitState = 0;
++}
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, 
++    ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT inSize = *srcLen;
++  (*srcLen) = 0;
++  LzmaDec_WriteRem(p, dicLimit);
++  
++  *status = LZMA_STATUS_NOT_SPECIFIED;
++
++  while (p->remainLen != kMatchSpecLenStart)
++  {
++      int checkEndMarkNow;
++
++      if (p->needFlush != 0)
++      {
++        for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
++          p->tempBuf[p->tempBufSize++] = *src++;
++        if (p->tempBufSize < RC_INIT_SIZE)
++        {
++          *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++          return SZ_OK;
++        }
++        if (p->tempBuf[0] != 0)
++          return SZ_ERROR_DATA;
++
++        LzmaDec_InitRc(p, p->tempBuf);
++        p->tempBufSize = 0;
++      }
++
++      checkEndMarkNow = 0;
++      if (p->dicPos >= dicLimit)
++      {
++        if (p->remainLen == 0 && p->code == 0)
++        {
++          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
++          return SZ_OK;
++        }
++        if (finishMode == LZMA_FINISH_ANY)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_OK;
++        }
++        if (p->remainLen != 0)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_ERROR_DATA;
++        }
++        checkEndMarkNow = 1;
++      }
++
++      if (p->needInitState)
++        LzmaDec_InitStateReal(p);
++  
++      if (p->tempBufSize == 0)
++      {
++        SizeT processed;
++        const Byte *bufLimit;
++        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            memcpy(p->tempBuf, src, inSize);
++            p->tempBufSize = (unsigned)inSize;
++            (*srcLen) += inSize;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++          bufLimit = src;
++        }
++        else
++          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
++        p->buf = src;
++        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
++          return SZ_ERROR_DATA;
++        processed = p->buf - src;
++        (*srcLen) += processed;
++        src += processed;
++        inSize -= processed;
++      }
++      else
++      {
++        unsigned rem = p->tempBufSize, lookAhead = 0;
++        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
++          p->tempBuf[rem++] = src[lookAhead++];
++        p->tempBufSize = rem;
++        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            (*srcLen) += lookAhead;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++        }
++        p->buf = p->tempBuf;
++        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
++          return SZ_ERROR_DATA;
++        lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
++        (*srcLen) += lookAhead;
++        src += lookAhead;
++        inSize -= lookAhead;
++        p->tempBufSize = 0;
++      }
++  }
++  if (p->code == 0) 
++    *status = LZMA_STATUS_FINISHED_WITH_MARK;
++  return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
++}
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT outSize = *destLen;
++  SizeT inSize = *srcLen;
++  *srcLen = *destLen = 0;
++  for (;;)
++  {
++    SizeT inSizeCur = inSize, outSizeCur, dicPos;
++    ELzmaFinishMode curFinishMode;
++    SRes res;
++    if (p->dicPos == p->dicBufSize)
++      p->dicPos = 0;
++    dicPos = p->dicPos;
++    if (outSize > p->dicBufSize - dicPos)
++    {
++      outSizeCur = p->dicBufSize;
++      curFinishMode = LZMA_FINISH_ANY;
++    }
++    else
++    {
++      outSizeCur = dicPos + outSize;
++      curFinishMode = finishMode;
++    }
++
++    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
++    src += inSizeCur;
++    inSize -= inSizeCur;
++    *srcLen += inSizeCur;
++    outSizeCur = p->dicPos - dicPos;
++    memcpy(dest, p->dic + dicPos, outSizeCur);
++    dest += outSizeCur;
++    outSize -= outSizeCur;
++    *destLen += outSizeCur;
++    if (res != 0)
++      return res;
++    if (outSizeCur == 0 || outSize == 0)
++      return SZ_OK;
++  }
++}
++
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) 
++{ 
++  alloc->Free(alloc, p->probs);  
++  p->probs = 0; 
++}
++
++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) 
++{ 
++  alloc->Free(alloc, p->dic); 
++  p->dic = 0; 
++}
++
++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
++{
++  LzmaDec_FreeProbs(p, alloc);
++  LzmaDec_FreeDict(p, alloc);
++}
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++{
++  UInt32 dicSize; 
++  Byte d;
++  
++  if (size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_UNSUPPORTED;
++  else
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++ 
++  if (dicSize < LZMA_DIC_MIN)
++    dicSize = LZMA_DIC_MIN;
++  p->dicSize = dicSize;
++
++  d = data[0];
++  if (d >= (9 * 5 * 5))
++    return SZ_ERROR_UNSUPPORTED;
++
++  p->lc = d % 9;
++  d /= 9;
++  p->pb = d / 5;
++  p->lp = d % 5;
++
++  return SZ_OK;
++}
++
++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
++{
++  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
++  if (p->probs == 0 || numProbs != p->numProbs)
++  {
++    LzmaDec_FreeProbs(p, alloc);
++    p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
++    p->numProbs = numProbs;
++    if (p->probs == 0)
++      return SZ_ERROR_MEM;
++  }
++  return SZ_OK;
++}
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  SizeT dicBufSize;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  dicBufSize = propNew.dicSize;
++  if (p->dic == 0 || dicBufSize != p->dicBufSize)
++  {
++    LzmaDec_FreeDict(p, alloc);
++    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
++    if (p->dic == 0)
++    {
++      LzmaDec_FreeProbs(p, alloc);
++      return SZ_ERROR_MEM;
++    }
++  }
++  p->dicBufSize = dicBufSize;
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 
++    ELzmaStatus *status, ISzAlloc *alloc)
++{
++  CLzmaDec p;
++  SRes res;
++  SizeT inSize = *srcLen;
++  SizeT outSize = *destLen;
++  *srcLen = *destLen = 0;
++  if (inSize < RC_INIT_SIZE)
++    return SZ_ERROR_INPUT_EOF;
++
++  LzmaDec_Construct(&p);
++  res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
++  if (res != 0)
++    return res;
++  p.dic = dest;
++  p.dicBufSize = outSize;
++
++  LzmaDec_Init(&p);
++  
++  *srcLen = inSize;
++  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
++
++  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
++    res = SZ_ERROR_INPUT_EOF;
++
++  (*destLen) = p.dicPos;
++  LzmaDec_FreeProbs(&p, alloc);
++  return res;
++}
+--- /dev/null
++++ b/lzma/LzmaEnc.c
+@@ -0,0 +1,2335 @@
++/* LzmaEnc.c -- LZMA Encoder
++2008-04-28
++Copyright (c) 1999-2008 Igor Pavlov
++Read LzmaEnc.h for license options */
++
++#if defined(SHOW_STAT) || defined(SHOW_STAT2)
++#include <stdio.h>
++#endif
++
++#include <string.h>
++
++#include "LzmaEnc.h"
++
++#include "LzFind.h"
++#ifdef COMPRESS_MF_MT
++#include "LzFindMt.h"
++#endif
++
++/* #define SHOW_STAT */
++/* #define SHOW_STAT2 */
++
++#ifdef SHOW_STAT
++static int ttt = 0;
++#endif
++
++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
++
++#define kBlockSize (9 << 10)
++#define kUnpackBlockSize (1 << 18)
++#define kMatchArraySize (1 << 21)
++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
++
++#define kNumMaxDirectBits (31)
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++#define kProbInitValue (kBitModelTotal >> 1)
++
++#define kNumMoveReducingBits 4
++#define kNumBitPriceShiftBits 4
++#define kBitPrice (1 << kNumBitPriceShiftBits)
++
++void LzmaEncProps_Init(CLzmaEncProps *p)
++{
++  p->level = 5;
++  p->dictSize = p->mc = 0;
++  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
++  p->writeEndMark = 0;
++}
++
++void LzmaEncProps_Normalize(CLzmaEncProps *p)
++{
++  int level = p->level;
++  if (level < 0) level = 5;
++  p->level = level;
++  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
++  if (p->lc < 0) p->lc = 3; 
++  if (p->lp < 0) p->lp = 0; 
++  if (p->pb < 0) p->pb = 2; 
++  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); 
++  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); 
++  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); 
++  if (p->numHashBytes < 0) p->numHashBytes = 4; 
++  if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
++  if (p->numThreads < 0) p->numThreads = ((p->btMode && p->algo) ? 2 : 1);
++}
++
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++{
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++  return props.dictSize;
++}
++
++/* #define LZMA_LOG_BSR */
++/* Define it for Intel's CPU */
++
++
++#ifdef LZMA_LOG_BSR
++
++#define kDicLogSizeMaxCompress 30
++
++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
++
++UInt32 GetPosSlot1(UInt32 pos) 
++{ 
++  UInt32 res; 
++  BSR2_RET(pos, res); 
++  return res; 
++}
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
++
++#else
++
++#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
++
++void LzmaEnc_FastPosInit(Byte *g_FastPos)
++{
++  int c = 2, slotFast;
++  g_FastPos[0] = 0;
++  g_FastPos[1] = 1;
++  
++  for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
++  {
++    UInt32 k = (1 << ((slotFast >> 1) - 1));
++    UInt32 j;
++    for (j = 0; j < k; j++, c++)
++      g_FastPos[c] = (Byte)slotFast;
++  }
++}
++
++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
++  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
++  res = p->g_FastPos[pos >> i] + (i * 2); }
++/*
++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
++  p->g_FastPos[pos >> 6] + 12 : \
++  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
++*/
++
++#define GetPosSlot1(pos) p->g_FastPos[pos]
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
++
++#endif
++
++
++#define LZMA_NUM_REPS 4
++
++typedef unsigned CState;
++
++typedef struct _COptimal
++{
++  UInt32 price;    
++
++  CState state;
++  int prev1IsChar;
++  int prev2;
++
++  UInt32 posPrev2;
++  UInt32 backPrev2;     
++
++  UInt32 posPrev;
++  UInt32 backPrev;     
++  UInt32 backs[LZMA_NUM_REPS];
++} COptimal;
++
++#define kNumOpts (1 << 12)
++
++#define kNumLenToPosStates 4
++#define kNumPosSlotBits 6 
++#define kDicLogSizeMin 0 
++#define kDicLogSizeMax 32 
++#define kDistTableSizeMax (kDicLogSizeMax * 2)
++
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++#define kAlignMask (kAlignTableSize - 1)
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
++
++#define kNumFullDistances (1 << (kEndPosModelIndex / 2))
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++#define LZMA_PB_MAX 4
++#define LZMA_LC_MAX 8
++#define LZMA_LP_MAX 4
++
++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
++
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define LZMA_MATCH_LEN_MIN 2
++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
++
++#define kNumStates 12
++
++typedef struct
++{
++  CLzmaProb choice;
++  CLzmaProb choice2;
++  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
++  CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
++  CLzmaProb high[kLenNumHighSymbols];
++} CLenEnc;
++
++typedef struct
++{
++  CLenEnc p;
++  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
++  UInt32 tableSize;
++  UInt32 counters[LZMA_NUM_PB_STATES_MAX];
++} CLenPriceEnc;
++
++typedef struct _CRangeEnc
++{
++  UInt32 range;
++  Byte cache;
++  UInt64 low;
++  UInt64 cacheSize;
++  Byte *buf;
++  Byte *bufLim;
++  Byte *bufBase;
++  ISeqOutStream *outStream;
++  UInt64 processed;
++  SRes res;
++} CRangeEnc;
++
++typedef struct _CSeqInStreamBuf
++{
++  ISeqInStream funcTable;
++  const Byte *data;
++  SizeT rem;
++} CSeqInStreamBuf;
++
++static SRes MyRead(void *pp, void *data, size_t *size)
++{
++  size_t curSize = *size;
++  CSeqInStreamBuf *p = (CSeqInStreamBuf *)pp;
++  if (p->rem < curSize)
++    curSize = p->rem;
++  memcpy(data, p->data, curSize);
++  p->rem -= curSize;
++  p->data += curSize;
++  *size = curSize;
++  return SZ_OK;
++}
++
++typedef struct 
++{
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++} CSaveState;
++
++typedef struct _CLzmaEnc
++{
++  IMatchFinder matchFinder;
++  void *matchFinderObj;
++
++  #ifdef COMPRESS_MF_MT
++  Bool mtMode;
++  CMatchFinderMt matchFinderMt;
++  #endif
++
++  CMatchFinder matchFinderBase;
++
++  #ifdef COMPRESS_MF_MT
++  Byte pad[128];
++  #endif
++  
++  UInt32 optimumEndIndex;
++  UInt32 optimumCurrentIndex;
++
++  Bool longestMatchWasFound;
++  UInt32 longestMatchLength;    
++  UInt32 numDistancePairs;
++
++  COptimal opt[kNumOpts];
++  
++  #ifndef LZMA_LOG_BSR
++  Byte g_FastPos[1 << kNumLogBits];
++  #endif
++
++  UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
++  UInt32 matchDistances[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
++  UInt32 numFastBytes;
++  UInt32 additionalOffset;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++
++  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
++  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
++  UInt32 alignPrices[kAlignTableSize];
++  UInt32 alignPriceCount;
++
++  UInt32 distTableSize;
++
++  unsigned lc, lp, pb;
++  unsigned lpMask, pbMask;
++
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++  
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  unsigned lclp;
++
++  Bool fastMode;
++  
++  CRangeEnc rc;
++
++  Bool writeEndMark;
++  UInt64 nowPos64;
++  UInt32 matchPriceCount;
++  Bool finished;
++  Bool multiThread;
++
++  SRes result;
++  UInt32 dictSize;
++  UInt32 matchFinderCycles;
++
++  ISeqInStream *inStream;
++  CSeqInStreamBuf seqBufInStream;
++
++  CSaveState saveState;
++} CLzmaEnc;
++
++void LzmaEnc_SaveState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CSaveState *dest = &p->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
++}
++
++void LzmaEnc_RestoreState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *dest = (CLzmaEnc *)pp;
++  const CSaveState *p = &dest->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
++}
++
++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++
++  if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
++      props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
++    return SZ_ERROR_PARAM;
++  p->dictSize = props.dictSize;
++  p->matchFinderCycles = props.mc;
++  {
++    unsigned fb = props.fb;
++    if (fb < 5)
++      fb = 5;
++    if (fb > LZMA_MATCH_LEN_MAX)
++      fb = LZMA_MATCH_LEN_MAX;
++    p->numFastBytes = fb;
++  }
++  p->lc = props.lc;
++  p->lp = props.lp;
++  p->pb = props.pb;
++  p->fastMode = (props.algo == 0);
++  p->matchFinderBase.btMode = props.btMode;
++  {
++    UInt32 numHashBytes = 4;
++    if (props.btMode)
++    {
++      if (props.numHashBytes < 2)
++        numHashBytes = 2;
++      else if (props.numHashBytes < 4)
++        numHashBytes = props.numHashBytes;
++    }
++    p->matchFinderBase.numHashBytes = numHashBytes;
++  }
++
++  p->matchFinderBase.cutValue = props.mc;
++
++  p->writeEndMark = props.writeEndMark;
++
++  #ifdef COMPRESS_MF_MT
++  /*
++  if (newMultiThread != _multiThread)
++  {
++    ReleaseMatchFinder();
++    _multiThread = newMultiThread;
++  }
++  */
++  p->multiThread = (props.numThreads > 1);
++  #endif
++
++  return SZ_OK;
++}
++
++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
++static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
++static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
++
++/*
++  void UpdateChar() { Index = kLiteralNextStates[Index]; }
++  void UpdateMatch() { Index = kMatchNextStates[Index]; }
++  void UpdateRep() { Index = kRepNextStates[Index]; }
++  void UpdateShortRep() { Index = kShortRepNextStates[Index]; }
++*/
++
++#define IsCharState(s) ((s) < 7)
++
++
++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
++
++#define kInfinityPrice (1 << 30)
++
++static void RangeEnc_Construct(CRangeEnc *p)
++{
++  p->outStream = 0;
++  p->bufBase = 0;
++}
++
++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
++
++#define RC_BUF_SIZE (1 << 16)
++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
++{
++  if (p->bufBase == 0)
++  {
++    p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
++    if (p->bufBase == 0)
++      return 0;
++    p->bufLim = p->bufBase + RC_BUF_SIZE;
++  }
++  return 1;
++}
++
++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->bufBase);
++  p->bufBase = 0;
++}
++
++static void RangeEnc_Init(CRangeEnc *p)
++{
++  /* Stream.Init(); */
++  p->low = 0;
++  p->range = 0xFFFFFFFF;
++  p->cacheSize = 1;
++  p->cache = 0;
++
++  p->buf = p->bufBase;
++
++  p->processed = 0;
++  p->res = SZ_OK;
++}
++
++static void RangeEnc_FlushStream(CRangeEnc *p)
++{
++  size_t num;
++  if (p->res != SZ_OK)
++    return;
++  num = p->buf - p->bufBase;
++  if (num != p->outStream->Write(p->outStream, p->bufBase, num))
++    p->res = SZ_ERROR_WRITE;
++  p->processed += num;
++  p->buf = p->bufBase;
++}
++
++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
++{
++  if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) 
++  {
++    Byte temp = p->cache;
++    do
++    {
++      Byte *buf = p->buf;
++      *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
++      p->buf = buf;
++      if (buf == p->bufLim)
++        RangeEnc_FlushStream(p);
++      temp = 0xFF;
++    }
++    while (--p->cacheSize != 0);
++    p->cache = (Byte)((UInt32)p->low >> 24);                      
++  } 
++  p->cacheSize++;                               
++  p->low = (UInt32)p->low << 8;                           
++}
++
++static void RangeEnc_FlushData(CRangeEnc *p)
++{
++  int i;
++  for (i = 0; i < 5; i++)
++    RangeEnc_ShiftLow(p);
++}
++
++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
++{
++  do
++  {
++    p->range >>= 1;
++    p->low += p->range & (0 - ((value >> --numBits) & 1));
++    if (p->range < kTopValue)
++    {
++      p->range <<= 8;
++      RangeEnc_ShiftLow(p);
++    }
++  }
++  while (numBits != 0);
++}
++
++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
++{
++  UInt32 ttt = *prob;
++  UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
++  if (symbol == 0)
++  {
++    p->range = newBound;
++    ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
++  }
++  else
++  {
++    p->low += newBound;
++    p->range -= newBound;
++    ttt -= ttt >> kNumMoveBits;
++  }
++  *prob = (CLzmaProb)ttt;
++  if (p->range < kTopValue)
++  {
++    p->range <<= 8;
++    RangeEnc_ShiftLow(p);
++  }
++}
++
++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
++{
++  symbol |= 0x100;
++  do 
++  {
++    RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++}
++
++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
++{
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do 
++  {
++    matchByte <<= 1;
++    RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++}
++
++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++{
++  UInt32 i;
++  for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
++  {
++    const int kCyclesBits = kNumBitPriceShiftBits;
++    UInt32 w = i;
++    UInt32 bitCount = 0;
++    int j;
++    for (j = 0; j < kCyclesBits; j++)
++    {
++      w = w * w;
++      bitCount <<= 1;
++      while (w >= ((UInt32)1 << 16))
++      {
++        w >>= 1;
++        bitCount++;
++      }
++    }
++    ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
++  }
++}
++
++
++#define GET_PRICE(prob, symbol) \
++  p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICEa(prob, symbol) \
++  ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= 0x100;
++  do
++  {
++    price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++  return price;
++};
++
++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do 
++  {
++    matchByte <<= 1;
++    price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++  return price;
++};
++
++
++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0 ;)
++  {
++    UInt32 bit;
++    i--;
++    bit = (symbol >> i) & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++  }
++};
++
++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = 0; i < numBitLevels; i++)
++  {
++    UInt32 bit = symbol & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++    symbol >>= 1;
++  }
++}
++
++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= (1 << numBitLevels);
++  while (symbol != 1)
++  {
++    price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
++    symbol >>= 1;
++  }
++  return price;
++}
++
++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0; i--)
++  {
++    UInt32 bit = symbol & 1;
++    symbol >>= 1;
++    price += GET_PRICEa(probs[m], bit);
++    m = (m << 1) | bit;
++  }
++  return price;
++}
++
++
++static void LenEnc_Init(CLenEnc *p)
++{
++  unsigned i;
++  p->choice = p->choice2 = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
++    p->low[i] = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
++    p->mid[i] = kProbInitValue;
++  for (i = 0; i < kLenNumHighSymbols; i++)
++    p->high[i] = kProbInitValue;
++}
++
++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
++{
++  if (symbol < kLenNumLowSymbols)
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 0);
++    RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
++  }
++  else
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 1);
++    if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 0);
++      RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
++    }
++    else
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 1);
++      RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
++    }
++  }
++}
++
++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
++{
++  UInt32 a0 = GET_PRICE_0a(p->choice);
++  UInt32 a1 = GET_PRICE_1a(p->choice);
++  UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
++  UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
++  UInt32 i = 0;
++  for (i = 0; i < kLenNumLowSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
++  }
++  for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
++  }
++  for (; i < numSymbols; i++)
++    prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
++}
++
++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
++{
++  LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
++  p->counters[posState] = p->tableSize;
++}
++
++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
++{
++  UInt32 posState;
++  for (posState = 0; posState < numPosStates; posState++)
++    LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
++{
++  LenEnc_Encode(&p->p, rc, symbol, posState);
++  if (updatePrice)
++    if (--p->counters[posState] == 0)
++      LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++
++
++
++static void MovePos(CLzmaEnc *p, UInt32 num)
++{
++  #ifdef SHOW_STAT
++  ttt += num;
++  printf("\n MovePos %d", num);
++  #endif
++  if (num != 0)
++  {
++    p->additionalOffset += num;
++    p->matchFinder.Skip(p->matchFinderObj, num);
++  }
++}
++
++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
++{
++  UInt32 lenRes = 0, numDistancePairs;
++  numDistancePairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matchDistances);
++  #ifdef SHOW_STAT
++  printf("\n i = %d numPairs = %d    ", ttt, numDistancePairs / 2);
++  if (ttt >= 61994)
++    ttt = ttt;
++
++  ttt++;
++  {
++    UInt32 i;
++  for (i = 0; i < numDistancePairs; i += 2)
++    printf("%2d %6d   | ", p->matchDistances[i], p->matchDistances[i + 1]);
++  }
++  #endif
++  if (numDistancePairs > 0)
++  {
++    lenRes = p->matchDistances[numDistancePairs - 2];
++    if (lenRes == p->numFastBytes)
++    {
++      UInt32 numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) + 1;
++      const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++      UInt32 distance = p->matchDistances[numDistancePairs - 1] + 1;
++      if (numAvail > LZMA_MATCH_LEN_MAX)
++        numAvail = LZMA_MATCH_LEN_MAX;
++
++      {
++        const Byte *pby2 = pby - distance;
++        for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
++      }
++    }
++  }
++  p->additionalOffset++;
++  *numDistancePairsRes = numDistancePairs;
++  return lenRes;
++}
++
++
++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
++#define IsShortRep(p) ((p)->backPrev == 0)
++
++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
++{
++  return 
++    GET_PRICE_0(p->isRepG0[state]) +
++    GET_PRICE_0(p->isRep0Long[state][posState]);
++}
++
++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
++{
++  UInt32 price;
++  if (repIndex == 0)
++  {
++    price = GET_PRICE_0(p->isRepG0[state]);
++    price += GET_PRICE_1(p->isRep0Long[state][posState]);
++  }
++  else
++  {
++    price = GET_PRICE_1(p->isRepG0[state]);
++    if (repIndex == 1)
++      price += GET_PRICE_0(p->isRepG1[state]);
++    else
++    {
++      price += GET_PRICE_1(p->isRepG1[state]);
++      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
++    }
++  }
++  return price;
++}
++
++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
++{
++  return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
++    GetPureRepPrice(p, repIndex, state, posState);
++}
++
++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
++{
++  UInt32 posMem = p->opt[cur].posPrev;
++  UInt32 backMem = p->opt[cur].backPrev;
++  p->optimumEndIndex = cur;
++  do
++  {
++    if (p->opt[cur].prev1IsChar)
++    {
++      MakeAsChar(&p->opt[posMem])
++      p->opt[posMem].posPrev = posMem - 1;
++      if (p->opt[cur].prev2)
++      {
++        p->opt[posMem - 1].prev1IsChar = False;
++        p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
++        p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
++      }
++    }
++    {
++      UInt32 posPrev = posMem;
++      UInt32 backCur = backMem;
++      
++      backMem = p->opt[posPrev].backPrev;
++      posMem = p->opt[posPrev].posPrev;
++      
++      p->opt[posPrev].backPrev = backCur;
++      p->opt[posPrev].posPrev = cur;
++      cur = posPrev;
++    }
++  }
++  while (cur != 0);
++  *backRes = p->opt[0].backPrev;
++  p->optimumCurrentIndex  = p->opt[0].posPrev;
++  return p->optimumCurrentIndex; 
++}
++
++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
++
++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
++{
++  UInt32 numAvailableBytes, lenMain, numDistancePairs;
++  const Byte *data;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 repLens[LZMA_NUM_REPS];
++  UInt32 repMaxIndex, i;
++  UInt32 *matchDistances;
++  Byte currentByte, matchByte; 
++  UInt32 posState;
++  UInt32 matchPrice, repMatchPrice;
++  UInt32 lenEnd;
++  UInt32 len;
++  UInt32 normalMatchPrice;
++  UInt32 cur;
++  if (p->optimumEndIndex != p->optimumCurrentIndex)
++  {
++    const COptimal *opt = &p->opt[p->optimumCurrentIndex];
++    UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
++    *backRes = opt->backPrev;
++    p->optimumCurrentIndex = opt->posPrev;
++    return lenRes;
++  }
++  p->optimumCurrentIndex = p->optimumEndIndex = 0;
++  
++  numAvailableBytes = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++
++  if (!p->longestMatchWasFound)
++  {
++    lenMain = ReadMatchDistances(p, &numDistancePairs);
++  }
++  else
++  {
++    lenMain = p->longestMatchLength;
++    numDistancePairs = p->numDistancePairs;
++    p->longestMatchWasFound = False;
++  }
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  if (numAvailableBytes < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++  if (numAvailableBytes > LZMA_MATCH_LEN_MAX)
++    numAvailableBytes = LZMA_MATCH_LEN_MAX;
++
++  repMaxIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 lenTest;
++    const Byte *data2;
++    reps[i] = p->reps[i];
++    data2 = data - (reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
++    repLens[i] = lenTest;
++    if (lenTest > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  if (repLens[repMaxIndex] >= p->numFastBytes)
++  {
++    UInt32 lenRes;
++    *backRes = repMaxIndex;
++    lenRes = repLens[repMaxIndex];
++    MovePos(p, lenRes - 1);
++    return lenRes;
++  }
++
++  matchDistances = p->matchDistances;
++  if (lenMain >= p->numFastBytes)
++  {
++    *backRes = matchDistances[numDistancePairs - 1] + LZMA_NUM_REPS; 
++    MovePos(p, lenMain - 1);
++    return lenMain;
++  }
++  currentByte = *data;
++  matchByte = *(data - (reps[0] + 1));
++
++  if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
++  {
++    *backRes = (UInt32)-1;
++    return 1;
++  }
++
++  p->opt[0].state = (CState)p->state;
++
++  posState = (position & p->pbMask);
++
++  {
++    const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++    p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + 
++        (!IsCharState(p->state) ? 
++          LitEnc_GetPriceMatched(probs, currentByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, currentByte, p->ProbPrices));
++  }
++
++  MakeAsChar(&p->opt[1]);
++
++  matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
++  repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
++
++  if (matchByte == currentByte)
++  {
++    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
++    if (shortRepPrice < p->opt[1].price)
++    {
++      p->opt[1].price = shortRepPrice;
++      MakeAsShortRep(&p->opt[1]);
++    }
++  }
++  lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
++
++  if (lenEnd < 2)
++  {
++    *backRes = p->opt[1].backPrev;
++    return 1;
++  }
++
++  p->opt[1].posPrev = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++    p->opt[0].backs[i] = reps[i];
++
++  len = lenEnd;
++  do
++    p->opt[len--].price = kInfinityPrice;
++  while (len >= 2);
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 repLen = repLens[i];
++    UInt32 price;
++    if (repLen < 2)
++      continue;
++    price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
++    do
++    {
++      UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
++      COptimal *opt = &p->opt[repLen];
++      if (curAndLenPrice < opt->price) 
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = i;
++        opt->prev1IsChar = False;
++      }
++    }
++    while (--repLen >= 2);
++  }
++
++  normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
++
++  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
++  if (len <= lenMain)
++  {
++    UInt32 offs = 0;
++    while (len > matchDistances[offs])
++      offs += 2;
++    for (; ; len++)
++    {
++      COptimal *opt;
++      UInt32 distance = matchDistances[offs + 1];
++
++      UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
++      UInt32 lenToPosState = GetLenToPosState(len);
++      if (distance < kNumFullDistances)
++        curAndLenPrice += p->distancesPrices[lenToPosState][distance];
++      else
++      {
++        UInt32 slot;
++        GetPosSlot2(distance, slot);
++        curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
++      }
++      opt = &p->opt[len];
++      if (curAndLenPrice < opt->price) 
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = distance + LZMA_NUM_REPS;
++        opt->prev1IsChar = False;
++      }
++      if (len == matchDistances[offs])
++      {
++        offs += 2;
++        if (offs == numDistancePairs)
++          break;
++      }
++    }
++  }
++
++  cur = 0;
++
++    #ifdef SHOW_STAT2
++    if (position >= 0)
++    {
++      unsigned i;
++      printf("\n pos = %4X", position);
++      for (i = cur; i <= lenEnd; i++)
++      printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
++    }
++    #endif
++
++  for (;;)
++  {
++    UInt32 numAvailableBytesFull, newLen, numDistancePairs;
++    COptimal *curOpt;
++    UInt32 posPrev;
++    UInt32 state;
++    UInt32 curPrice;
++    Bool nextIsChar;
++    const Byte *data;
++    Byte currentByte, matchByte;
++    UInt32 posState;
++    UInt32 curAnd1Price;
++    COptimal *nextOpt;
++    UInt32 matchPrice, repMatchPrice;  
++    UInt32 numAvailableBytes;
++    UInt32 startLen;
++
++    cur++;
++    if (cur == lenEnd)
++      return Backward(p, backRes, cur);
++
++    numAvailableBytesFull = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++    newLen = ReadMatchDistances(p, &numDistancePairs);
++    if (newLen >= p->numFastBytes)
++    {
++      p->numDistancePairs = numDistancePairs;
++      p->longestMatchLength = newLen;
++      p->longestMatchWasFound = True;
++      return Backward(p, backRes, cur);
++    }
++    position++;
++    curOpt = &p->opt[cur];
++    posPrev = curOpt->posPrev;
++    if (curOpt->prev1IsChar)
++    {
++      posPrev--;
++      if (curOpt->prev2)
++      {
++        state = p->opt[curOpt->posPrev2].state;
++        if (curOpt->backPrev2 < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      else
++        state = p->opt[posPrev].state;
++      state = kLiteralNextStates[state];
++    }
++    else
++      state = p->opt[posPrev].state;
++    if (posPrev == cur - 1)
++    {
++      if (IsShortRep(curOpt))
++        state = kShortRepNextStates[state];
++      else
++        state = kLiteralNextStates[state];
++    }
++    else
++    {
++      UInt32 pos;
++      const COptimal *prevOpt;
++      if (curOpt->prev1IsChar && curOpt->prev2)
++      {
++        posPrev = curOpt->posPrev2;
++        pos = curOpt->backPrev2;
++        state = kRepNextStates[state];
++      }
++      else
++      {
++        pos = curOpt->backPrev;
++        if (pos < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      prevOpt = &p->opt[posPrev];
++      if (pos < LZMA_NUM_REPS)
++      {
++        UInt32 i;
++        reps[0] = prevOpt->backs[pos];
++        for (i = 1; i <= pos; i++)
++          reps[i] = prevOpt->backs[i - 1];
++        for (; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i];
++      }
++      else
++      {
++        UInt32 i;
++        reps[0] = (pos - LZMA_NUM_REPS);
++        for (i = 1; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i - 1];
++      }
++    }
++    curOpt->state = (CState)state;
++
++    curOpt->backs[0] = reps[0];
++    curOpt->backs[1] = reps[1];
++    curOpt->backs[2] = reps[2];
++    curOpt->backs[3] = reps[3];
++
++    curPrice = curOpt->price; 
++    nextIsChar = False;
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    currentByte = *data;
++    matchByte = *(data - (reps[0] + 1));
++
++    posState = (position & p->pbMask);
++
++    curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
++    {
++      const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++      curAnd1Price += 
++        (!IsCharState(state) ? 
++          LitEnc_GetPriceMatched(probs, currentByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, currentByte, p->ProbPrices));
++    }   
++
++    nextOpt = &p->opt[cur + 1];
++
++    if (curAnd1Price < nextOpt->price) 
++    {
++      nextOpt->price = curAnd1Price;
++      nextOpt->posPrev = cur;
++      MakeAsChar(nextOpt);
++      nextIsChar = True;
++    }
++
++    matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
++    repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
++    
++    if (matchByte == currentByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
++    {
++      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
++      if (shortRepPrice <= nextOpt->price)
++      {
++        nextOpt->price = shortRepPrice;
++        nextOpt->posPrev = cur;
++        MakeAsShortRep(nextOpt);
++        nextIsChar = True;
++      }
++    }
++
++    {
++      UInt32 temp = kNumOpts - 1 - cur;
++      if (temp <  numAvailableBytesFull)
++        numAvailableBytesFull = temp;
++    }
++    numAvailableBytes = numAvailableBytesFull;
++
++    if (numAvailableBytes < 2)
++      continue;
++    if (numAvailableBytes > p->numFastBytes)
++      numAvailableBytes = p->numFastBytes;
++    if (!nextIsChar && matchByte != currentByte) /* speed optimization */
++    {
++      /* try Literal + rep0 */
++      UInt32 temp;
++      UInt32 lenTest2;
++      const Byte *data2 = data - (reps[0] + 1);
++      UInt32 limit = p->numFastBytes + 1;
++      if (limit > numAvailableBytesFull)
++        limit = numAvailableBytesFull;
++
++      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
++      lenTest2 = temp - 1;
++      if (lenTest2 >= 2)
++      {
++        UInt32 state2 = kLiteralNextStates[state];
++        UInt32 posStateNext = (position + 1) & p->pbMask;
++        UInt32 nextRepMatchPrice = curAnd1Price + 
++            GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++            GET_PRICE_1(p->isRep[state2]);
++        /* for (; lenTest2 >= 2; lenTest2--) */
++        {
++          UInt32 curAndLenPrice;
++          COptimal *opt;
++          UInt32 offset = cur + 1 + lenTest2;
++          while (lenEnd < offset)
++            p->opt[++lenEnd].price = kInfinityPrice;
++          curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++          opt = &p->opt[offset];
++          if (curAndLenPrice < opt->price) 
++          {
++            opt->price = curAndLenPrice;
++            opt->posPrev = cur + 1;
++            opt->backPrev = 0;
++            opt->prev1IsChar = True;
++            opt->prev2 = False;
++          }
++        }
++      }
++    }
++    
++    startLen = 2; /* speed optimization */
++    {
++    UInt32 repIndex;
++    for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
++    {
++      UInt32 lenTest;
++      UInt32 lenTestTemp;
++      UInt32 price;
++      const Byte *data2 = data - (reps[repIndex] + 1);
++      if (data[0] != data2[0] || data[1] != data2[1])
++        continue;
++      for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
++      while (lenEnd < cur + lenTest)
++        p->opt[++lenEnd].price = kInfinityPrice;
++      lenTestTemp = lenTest;
++      price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
++      do
++      {
++        UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
++        COptimal *opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price) 
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = repIndex;
++          opt->prev1IsChar = False;
++        }
++      }
++      while (--lenTest >= 2);
++      lenTest = lenTestTemp;
++      
++      if (repIndex == 0)
++        startLen = lenTest + 1;
++        
++      /* if (_maxMode) */
++        {
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailableBytesFull)
++            limit = numAvailableBytesFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kRepNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = 
++                price + p->repLenEnc.prices[posState][lenTest - 2] + 
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (position + lenTest + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice + 
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price) 
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = repIndex;
++              }
++            }
++          }
++        }
++    }
++    }
++    /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
++    if (newLen > numAvailableBytes)
++    {
++      newLen = numAvailableBytes;
++      for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
++      matchDistances[numDistancePairs] = newLen;
++      numDistancePairs += 2;
++    }
++    if (newLen >= startLen)
++    {
++      UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
++      UInt32 offs, curBack, posSlot;
++      UInt32 lenTest;
++      while (lenEnd < cur + newLen)
++        p->opt[++lenEnd].price = kInfinityPrice;
++
++      offs = 0;
++      while (startLen > matchDistances[offs])
++        offs += 2;
++      curBack = matchDistances[offs + 1];
++      GetPosSlot2(curBack, posSlot);
++      for (lenTest = /*2*/ startLen; ; lenTest++)
++      {
++        UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
++        UInt32 lenToPosState = GetLenToPosState(lenTest);
++        COptimal *opt;
++        if (curBack < kNumFullDistances)
++          curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
++        else
++          curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
++        
++        opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price) 
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = curBack + LZMA_NUM_REPS;
++          opt->prev1IsChar = False;
++        }
++
++        if (/*_maxMode && */lenTest == matchDistances[offs])
++        {
++          /* Try Match + Literal + Rep0 */
++          const Byte *data2 = data - (curBack + 1);
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailableBytesFull)
++            limit = numAvailableBytesFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kMatchNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = curAndLenPrice + 
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (posStateNext + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice + 
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++            
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price) 
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = curBack + LZMA_NUM_REPS;
++              }
++            }
++          }
++          offs += 2;
++          if (offs == numDistancePairs)
++            break;
++          curBack = matchDistances[offs + 1];
++          if (curBack >= kNumFullDistances)
++            GetPosSlot2(curBack, posSlot);
++        }
++      }
++    }
++  }
++}
++
++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
++
++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
++{
++  UInt32 numAvailableBytes = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++  UInt32 lenMain, numDistancePairs;
++  const Byte *data;
++  UInt32 repLens[LZMA_NUM_REPS];
++  UInt32 repMaxIndex, i;
++  UInt32 *matchDistances;
++  UInt32 backMain;
++
++  if (!p->longestMatchWasFound)
++  {
++    lenMain = ReadMatchDistances(p, &numDistancePairs);
++  }
++  else
++  {
++    lenMain = p->longestMatchLength;
++    numDistancePairs = p->numDistancePairs;
++    p->longestMatchWasFound = False;
++  }
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  if (numAvailableBytes > LZMA_MATCH_LEN_MAX)
++    numAvailableBytes = LZMA_MATCH_LEN_MAX;
++  if (numAvailableBytes < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++
++  repMaxIndex = 0;
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    const Byte *data2 = data - (p->reps[i] + 1);
++    UInt32 len;
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
++    if (len >= p->numFastBytes)
++    {
++      *backRes = i;
++      MovePos(p, len - 1);
++      return len;
++    }
++    repLens[i] = len;
++    if (len > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  matchDistances = p->matchDistances;
++  if (lenMain >= p->numFastBytes)
++  {
++    *backRes = matchDistances[numDistancePairs - 1] + LZMA_NUM_REPS; 
++    MovePos(p, lenMain - 1);
++    return lenMain;
++  }
++
++  backMain = 0; /* for GCC */
++  if (lenMain >= 2)
++  {
++    backMain = matchDistances[numDistancePairs - 1];
++    while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
++    {
++      if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
++        break;
++      numDistancePairs -= 2;
++      lenMain = matchDistances[numDistancePairs - 2];
++      backMain = matchDistances[numDistancePairs - 1];
++    }
++    if (lenMain == 2 && backMain >= 0x80)
++      lenMain = 1;
++  }
++
++  if (repLens[repMaxIndex] >= 2)
++  {
++    if (repLens[repMaxIndex] + 1 >= lenMain || 
++        (repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9))) ||
++        (repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15))))
++    {
++      UInt32 lenRes;
++      *backRes = repMaxIndex;
++      lenRes = repLens[repMaxIndex];
++      MovePos(p, lenRes - 1);
++      return lenRes;
++    }
++  }
++  
++  if (lenMain >= 2 && numAvailableBytes > 2)
++  {
++    UInt32 i;
++    numAvailableBytes = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++    p->longestMatchLength = ReadMatchDistances(p, &p->numDistancePairs);
++    if (p->longestMatchLength >= 2)
++    {
++      UInt32 newDistance = matchDistances[p->numDistancePairs - 1];
++      if ((p->longestMatchLength >= lenMain && newDistance < backMain) || 
++          (p->longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance)) ||
++          (p->longestMatchLength > lenMain + 1) ||
++          (p->longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain)))
++      {
++        p->longestMatchWasFound = True;
++        *backRes = (UInt32)(-1);
++        return 1;
++      }
++    }
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    for (i = 0; i < LZMA_NUM_REPS; i++)
++    {
++      UInt32 len;
++      const Byte *data2 = data - (p->reps[i] + 1);
++      if (data[1] != data2[1] || data[2] != data2[2])
++      {
++        repLens[i] = 0;
++        continue;
++      }
++      for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
++      if (len + 1 >= lenMain)
++      {
++        p->longestMatchWasFound = True;
++        *backRes = (UInt32)(-1);
++        return 1;
++      }
++    }
++    *backRes = backMain + LZMA_NUM_REPS; 
++    MovePos(p, lenMain - 2);
++    return lenMain;
++  }
++  *backRes = (UInt32)(-1);
++  return 1;
++}
++
++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
++{
++  UInt32 len;
++  RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++  RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++  p->state = kMatchNextStates[p->state];
++  len = LZMA_MATCH_LEN_MIN;
++  LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++  RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
++  RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
++  RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
++}
++
++static SRes CheckErrors(CLzmaEnc *p)
++{
++  if (p->result != SZ_OK)
++    return p->result;
++  if (p->rc.res != SZ_OK)
++    p->result = SZ_ERROR_WRITE;
++  if (p->matchFinderBase.result != SZ_OK)
++    p->result = SZ_ERROR_READ;
++  if (p->result != SZ_OK)
++    p->finished = True;
++  return p->result;
++}
++
++static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
++{
++  /* ReleaseMFStream(); */
++  p->finished = True;
++  if (p->writeEndMark)
++    WriteEndMarker(p, nowPos & p->pbMask);
++  RangeEnc_FlushData(&p->rc);
++  RangeEnc_FlushStream(&p->rc);
++  return CheckErrors(p);
++}
++
++static void FillAlignPrices(CLzmaEnc *p)
++{
++  UInt32 i;
++  for (i = 0; i < kAlignTableSize; i++)
++    p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
++  p->alignPriceCount = 0;
++}
++
++static void FillDistancesPrices(CLzmaEnc *p)
++{
++  UInt32 tempPrices[kNumFullDistances];
++  UInt32 i, lenToPosState;
++  for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
++  { 
++    UInt32 posSlot = GetPosSlot1(i);
++    UInt32 footerBits = ((posSlot >> 1) - 1);
++    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++    tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
++  }
++
++  for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
++  {
++    UInt32 posSlot;
++    const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
++    UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
++    for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
++    for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
++
++    {
++      UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
++      UInt32 i;
++      for (i = 0; i < kStartPosModelIndex; i++)
++        distancesPrices[i] = posSlotPrices[i];
++      for (; i < kNumFullDistances; i++)
++        distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
++    }
++  }
++  p->matchPriceCount = 0;
++}
++
++void LzmaEnc_Construct(CLzmaEnc *p)
++{
++  RangeEnc_Construct(&p->rc);
++  MatchFinder_Construct(&p->matchFinderBase);
++  #ifdef COMPRESS_MF_MT
++  MatchFinderMt_Construct(&p->matchFinderMt);
++  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
++  #endif
++
++  {
++    CLzmaEncProps props;
++    LzmaEncProps_Init(&props);
++    LzmaEnc_SetProps(p, &props);
++  }
++
++  #ifndef LZMA_LOG_BSR
++  LzmaEnc_FastPosInit(p->g_FastPos);
++  #endif
++
++  LzmaEnc_InitPriceTables(p->ProbPrices);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
++{
++  void *p;
++  p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
++  if (p != 0)
++    LzmaEnc_Construct((CLzmaEnc *)p);
++  return p;
++}
++
++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->litProbs);
++  alloc->Free(alloc, p->saveState.litProbs);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  #ifdef COMPRESS_MF_MT
++  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
++  #endif
++  MatchFinder_Free(&p->matchFinderBase, allocBig);
++  LzmaEnc_FreeLits(p, alloc);
++  RangeEnc_Free(&p->rc, alloc);
++}
++
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
++  alloc->Free(alloc, p);
++}
++
++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
++{
++  UInt32 nowPos32, startPos32;
++  if (p->inStream != 0)
++  {
++    p->matchFinderBase.stream = p->inStream;
++    p->matchFinder.Init(p->matchFinderObj);
++    p->inStream = 0;
++  }
++
++  if (p->finished)
++    return p->result;
++  RINOK(CheckErrors(p));
++
++  nowPos32 = (UInt32)p->nowPos64;
++  startPos32 = nowPos32;
++
++  if (p->nowPos64 == 0)
++  {
++    UInt32 numDistancePairs;
++    Byte curByte;
++    if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++      return Flush(p, nowPos32);
++    ReadMatchDistances(p, &numDistancePairs);
++    RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
++    p->state = kLiteralNextStates[p->state];
++    curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
++    LitEnc_Encode(&p->rc, p->litProbs, curByte);
++    p->additionalOffset--;
++    nowPos32++;
++  }
++
++  if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
++  for (;;)
++  {
++    UInt32 pos, len, posState;
++
++    if (p->fastMode)
++      len = GetOptimumFast(p, &pos);
++    else
++      len = GetOptimum(p, nowPos32, &pos);
++
++    #ifdef SHOW_STAT2
++    printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
++    #endif
++
++    posState = nowPos32 & p->pbMask;
++    if (len == 1 && pos == 0xFFFFFFFF)
++    {
++      Byte curByte;
++      CLzmaProb *probs;
++      const Byte *data;
++
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
++      data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++      curByte = *data;
++      probs = LIT_PROBS(nowPos32, *(data - 1));
++      if (IsCharState(p->state))
++        LitEnc_Encode(&p->rc, probs, curByte);
++      else
++        LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
++      p->state = kLiteralNextStates[p->state];
++    }
++    else
++    {
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++      if (pos < LZMA_NUM_REPS)
++      {
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
++        if (pos == 0)
++        {
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
++          RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
++        }
++        else
++        {
++          UInt32 distance = p->reps[pos];
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
++          if (pos == 1)
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
++          else
++          {
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
++            if (pos == 3)
++              p->reps[3] = p->reps[2];
++            p->reps[2] = p->reps[1];
++          }
++          p->reps[1] = p->reps[0];
++          p->reps[0] = distance;
++        }
++        if (len == 1)
++          p->state = kShortRepNextStates[p->state];
++        else
++        {
++          LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++          p->state = kRepNextStates[p->state];
++        }
++      }
++      else
++      {
++        UInt32 posSlot;
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++        p->state = kMatchNextStates[p->state];
++        LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++        pos -= LZMA_NUM_REPS;
++        GetPosSlot(pos, posSlot);
++        RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
++        
++        if (posSlot >= kStartPosModelIndex)
++        {
++          UInt32 footerBits = ((posSlot >> 1) - 1);
++          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++          UInt32 posReduced = pos - base;
++
++          if (posSlot < kEndPosModelIndex)
++            RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
++          else
++          {
++            RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
++            RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
++            p->alignPriceCount++;
++          }
++        }
++        p->reps[3] = p->reps[2];
++        p->reps[2] = p->reps[1];
++        p->reps[1] = p->reps[0];
++        p->reps[0] = pos;
++        p->matchPriceCount++;
++      }
++    }
++    p->additionalOffset -= len;
++    nowPos32 += len;
++    if (p->additionalOffset == 0)
++    {
++      UInt32 processed;
++      if (!p->fastMode)
++      {
++        if (p->matchPriceCount >= (1 << 7))
++          FillDistancesPrices(p);
++        if (p->alignPriceCount >= kAlignTableSize)
++          FillAlignPrices(p);
++      }
++      if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++        break;
++      processed = nowPos32 - startPos32;
++      if (useLimits)
++      {
++        if (processed + kNumOpts + 300 >= maxUnpackSize ||
++            RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
++          break;
++      }
++      else if (processed >= (1 << 15))
++      {
++        p->nowPos64 += nowPos32 - startPos32;
++        return CheckErrors(p);
++      }
++    }
++  }
++  p->nowPos64 += nowPos32 - startPos32;
++  return Flush(p, nowPos32);
++}
++
++#define kBigHashDicLimit ((UInt32)1 << 24)
++
++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 beforeSize = kNumOpts;
++  Bool btMode;
++  if (!RangeEnc_Alloc(&p->rc, alloc))
++    return SZ_ERROR_MEM;
++  btMode = (p->matchFinderBase.btMode != 0);
++  #ifdef COMPRESS_MF_MT
++  p->mtMode = (p->multiThread && !p->fastMode && btMode);
++  #endif
++
++  {
++    unsigned lclp = p->lc + p->lp;
++    if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
++    {
++      LzmaEnc_FreeLits(p, alloc);
++      p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      if (p->litProbs == 0 || p->saveState.litProbs == 0)
++      {
++        LzmaEnc_FreeLits(p, alloc);
++        return SZ_ERROR_MEM;
++      }
++      p->lclp = lclp;
++    }
++  }
++
++  p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
++
++  if (beforeSize + p->dictSize < keepWindowSize)
++    beforeSize = keepWindowSize - p->dictSize;
++
++  #ifdef COMPRESS_MF_MT
++  if (p->mtMode)
++  {
++    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
++    p->matchFinderObj = &p->matchFinderMt;
++    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
++  }
++  else
++  #endif
++  {
++    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
++      return SZ_ERROR_MEM;
++    p->matchFinderObj = &p->matchFinderBase;
++    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
++  }
++  return SZ_OK;
++}
++
++void LzmaEnc_Init(CLzmaEnc *p)
++{
++  UInt32 i;
++  p->state = 0;
++  for(i = 0 ; i < LZMA_NUM_REPS; i++)
++    p->reps[i] = 0;
++
++  RangeEnc_Init(&p->rc);
++
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    UInt32 j;
++    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
++    {
++      p->isMatch[i][j] = kProbInitValue;
++      p->isRep0Long[i][j] = kProbInitValue;
++    }
++    p->isRep[i] = kProbInitValue;
++    p->isRepG0[i] = kProbInitValue;
++    p->isRepG1[i] = kProbInitValue;
++    p->isRepG2[i] = kProbInitValue;
++  }
++
++  {
++    UInt32 num = 0x300 << (p->lp + p->lc);
++    for (i = 0; i < num; i++)
++      p->litProbs[i] = kProbInitValue;
++  }
++
++  {
++    for (i = 0; i < kNumLenToPosStates; i++)
++    {
++      CLzmaProb *probs = p->posSlotEncoder[i];
++      UInt32 j;
++      for (j = 0; j < (1 << kNumPosSlotBits); j++)
++        probs[j] = kProbInitValue;
++    }
++  }
++  {
++    for(i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
++      p->posEncoders[i] = kProbInitValue;
++  }
++
++  LenEnc_Init(&p->lenEnc.p);
++  LenEnc_Init(&p->repLenEnc.p);
++
++  for (i = 0; i < (1 << kNumAlignBits); i++)
++    p->posAlignEncoder[i] = kProbInitValue;
++
++  p->longestMatchWasFound = False;
++  p->optimumEndIndex = 0;
++  p->optimumCurrentIndex = 0;
++  p->additionalOffset = 0;
++
++  p->pbMask = (1 << p->pb) - 1;
++  p->lpMask = (1 << p->lp) - 1;
++}
++
++void LzmaEnc_InitPrices(CLzmaEnc *p)
++{
++  if (!p->fastMode)
++  {
++    FillDistancesPrices(p);
++    FillAlignPrices(p);
++  }
++
++  p->lenEnc.tableSize = 
++  p->repLenEnc.tableSize = 
++      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
++  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
++  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
++}
++
++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 i;
++  for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
++    if (p->dictSize <= ((UInt32)1 << i))
++      break;
++  p->distTableSize = i * 2;
++
++  p->finished = False;
++  p->result = SZ_OK;
++  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
++  LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  p->nowPos64 = 0;
++  return SZ_OK;
++}
++
++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqInStream *inStream, ISeqOutStream *outStream,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->inStream = inStream;
++  p->rc.outStream = outStream;
++  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
++}
++
++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, 
++    ISeqInStream *inStream, UInt32 keepWindowSize,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->inStream = inStream;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
++{
++  p->seqBufInStream.funcTable.Read = MyRead;
++  p->seqBufInStream.data = src;
++  p->seqBufInStream.rem = srcLen;
++}
++
++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++    UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++  p->inStream = &p->seqBufInStream.funcTable;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++void LzmaEnc_Finish(CLzmaEncHandle pp)
++{
++  #ifdef COMPRESS_MF_MT
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  if (p->mtMode)
++    MatchFinderMt_ReleaseStream(&p->matchFinderMt);
++  #endif
++}
++
++typedef struct _CSeqOutStreamBuf
++{
++  ISeqOutStream funcTable;
++  Byte *data;
++  SizeT rem;
++  Bool overflow;
++} CSeqOutStreamBuf;
++
++static size_t MyWrite(void *pp, const void *data, size_t size)
++{
++  CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
++  if (p->rem < size)
++  {
++    size = p->rem;
++    p->overflow = True;
++  }
++  memcpy(p->data, data, size);
++  p->rem -= size;
++  p->data += size;
++  return size;
++}
++
++
++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++}
++
++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++}
++
++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, 
++    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  UInt64 nowPos64;
++  SRes res;
++  CSeqOutStreamBuf outStream;
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = False;
++  p->finished = False;
++  p->result = SZ_OK;
++
++  if (reInit)
++    LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  nowPos64 = p->nowPos64;
++  RangeEnc_Init(&p->rc);
++  p->rc.outStream = &outStream.funcTable;
++
++  res = LzmaEnc_CodeOneBlock(pp, True, desiredPackSize, *unpackSize);
++  
++  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++
++  return res;
++}
++
++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  SRes res = SZ_OK;
++
++  #ifdef COMPRESS_MF_MT
++  Byte allocaDummy[0x300];
++  int i = 0;
++  for (i = 0; i < 16; i++)
++    allocaDummy[i] = (Byte)i;
++  #endif
++
++  RINOK(LzmaEnc_Prepare(pp, inStream, outStream, alloc, allocBig));
++
++  for (;;)
++  {
++    res = LzmaEnc_CodeOneBlock(pp, False, 0, 0);
++    if (res != SZ_OK || p->finished != 0)
++      break;
++    if (progress != 0)
++    {
++      res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
++      if (res != SZ_OK)
++      {
++        res = SZ_ERROR_PROGRESS;
++        break;
++      }
++    }
++  }
++  LzmaEnc_Finish(pp);
++  return res;
++}
++
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  int i;
++  UInt32 dictSize = p->dictSize;
++  if (*size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_PARAM;
++  *size = LZMA_PROPS_SIZE;
++  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
++
++  for (i = 11; i <= 30; i++)
++  {
++    if (dictSize <= ((UInt32)2 << i))
++    {
++      dictSize = (2 << i);
++      break;
++    }
++    if (dictSize <= ((UInt32)3 << i))
++    {
++      dictSize = (3 << i);
++      break;
++    }
++  }
++
++  for (i = 0; i < 4; i++)
++    props[1 + i] = (Byte)(dictSize >> (8 * i));
++  return SZ_OK;
++}
++
++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  SRes res;
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++
++  CSeqOutStreamBuf outStream;
++
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = writeEndMark;
++  res = LzmaEnc_Encode(pp, &outStream.funcTable, &p->seqBufInStream.funcTable, 
++      progress, alloc, allocBig);
++
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++  return res;
++}
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, 
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
++  SRes res;
++  if (p == 0)
++    return SZ_ERROR_MEM;
++
++  res = LzmaEnc_SetProps(p, props);
++  if (res == SZ_OK)
++  {
++    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
++    if (res == SZ_OK)
++      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
++          writeEndMark, progress, alloc, allocBig);
++  }
++
++  LzmaEnc_Destroy(p, alloc, allocBig);
++  return res;
++}
+--- a/mkfs.jffs2.c
++++ b/mkfs.jffs2.c
+@@ -1659,11 +1659,11 @@ int main(int argc, char **argv)
+ 						  }
+ 						  erase_block_size *= units;
+ 
+-						  /* If it's less than 8KiB, they're not allowed */
+-						  if (erase_block_size < 0x2000) {
+-							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
++						  /* If it's less than 4KiB, they're not allowed */
++						  if (erase_block_size < 0x1000) {
++							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 4KiB minimum\n",
+ 									  erase_block_size);
+-							  erase_block_size = 0x2000;
++							  erase_block_size = 0x1000;
+ 						  }
+ 						  break;
+ 					  }
diff --git a/tools/mtd-utils/patches/134-freebsd_loff_t.patch b/tools/mtd-utils/patches/134-freebsd_loff_t.patch
new file mode 100644
index 0000000000..2d141bd7a3
--- /dev/null
+++ b/tools/mtd-utils/patches/134-freebsd_loff_t.patch
@@ -0,0 +1,14 @@
+--- a/include/mtd/mtd-abi.h
++++ b/include/mtd/mtd-abi.h
+@@ -171,9 +171,9 @@ struct otp_info {
+ /* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
+ #define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo)
+ /* Check if an eraseblock is bad */
+-#define MEMGETBADBLOCK		_IOW('M', 11, __kernel_loff_t)
++#define MEMGETBADBLOCK		_IOW('M', 11, loff_t)
+ /* Mark an eraseblock as bad */
+-#define MEMSETBADBLOCK		_IOW('M', 12, __kernel_loff_t)
++#define MEMSETBADBLOCK		_IOW('M', 12, loff_t)
+ /* Set OTP (One-Time Programmable) mode (factory vs. user) */
+ #define OTPSELECT		_IOR('M', 13, int)
+ /* Get number of OTP (One-Time Programmable) regions */
diff --git a/tools/mtd-utils/patches/135-mkubifs_optional_lzo.patch b/tools/mtd-utils/patches/135-mkubifs_optional_lzo.patch
new file mode 100644
index 0000000000..90d4ef4c36
--- /dev/null
+++ b/tools/mtd-utils/patches/135-mkubifs_optional_lzo.patch
@@ -0,0 +1,119 @@
+--- a/mkfs.ubifs/compr.c
++++ b/mkfs.ubifs/compr.c
+@@ -24,7 +24,6 @@
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <string.h>
+-#include <lzo/lzo1x.h>
+ #include <linux/types.h>
+ 
+ #define crc32 __zlib_crc32
+@@ -34,7 +33,6 @@
+ #include "compr.h"
+ #include "mkfs.ubifs.h"
+ 
+-static void *lzo_mem;
+ static unsigned long long errcnt = 0;
+ static struct ubifs_info *c = &info_;
+ 
+@@ -85,6 +83,25 @@ static int zlib_deflate(void *in_buf, si
+ 	return 0;
+ }
+ 
++#ifndef WITHOUT_LZO
++#include <lzo/lzo1x.h>
++
++static void *lzo_mem;
++
++static int lzo_init(void)
++{
++	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
++	if (!lzo_mem)
++		return -1;
++
++	return 0;
++}
++
++static void lzo_fini(void)
++{
++	free(lzo_mem);
++}
++
+ static int lzo_compress(void *in_buf, size_t in_len, void *out_buf,
+ 			size_t *out_len)
+ {
+@@ -102,6 +119,12 @@ static int lzo_compress(void *in_buf, si
+ 
+ 	return 0;
+ }
++#else
++static inline int lzo_compress(void *in_buf, size_t in_len, void *out_buf,
++			       size_t *out_len) { return -1; }
++static inline int lzo_init(void) { return 0; }
++static inline void lzo_fini(void) { }
++#endif
+ 
+ static int no_compress(void *in_buf, size_t in_len, void *out_buf,
+ 		       size_t *out_len)
+@@ -122,7 +145,6 @@ static int favor_lzo_compress(void *in_b
+ 	lzo_len = zlib_len = *out_len;
+ 	lzo_ret = lzo_compress(in_buf, in_len, out_buf, &lzo_len);
+ 	zlib_ret = zlib_deflate(in_buf, in_len, zlib_buf, &zlib_len);
+-
+ 	if (lzo_ret && zlib_ret)
+ 		/* Both compressors failed */
+ 		return -1;
+@@ -197,23 +219,28 @@ int compress_data(void *in_buf, size_t i
+ 
+ int init_compression(void)
+ {
+-	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
+-	if (!lzo_mem)
+-		return -1;
++	int ret;
++
++	ret = lzo_init();
++	if (ret)
++		goto err;
+ 
+ 	zlib_buf = malloc(UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR);
+-	if (!zlib_buf) {
+-		free(lzo_mem);
+-		return -1;
+-	}
++	if (!zlib_buf)
++		goto err_lzo;
+ 
+ 	return 0;
++
++err_lzo:
++	lzo_fini();
++err:
++	return ret;
+ }
+ 
+ void destroy_compression(void)
+ {
+ 	free(zlib_buf);
+-	free(lzo_mem);
++	lzo_fini();
+ 	if (errcnt)
+ 		fprintf(stderr, "%llu compression errors occurred\n", errcnt);
+ }
+--- a/Makefile
++++ b/Makefile
+@@ -108,7 +108,13 @@ $(call _mkdep,lib/,libmtd.a)
+ obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o \
+ 	hashtable/hashtable.o hashtable/hashtable_itr.o
+ LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
+-LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
++ifeq ($(WITHOUT_LZO), 1)
++  CPPFLAGS += -DWITHOUT_LZO
++else
++  LZOLDLIBS = -llzo2
++endif
++
++LDLIBS_mkfs.ubifs = -lz $(LZOLDLIBS) -lm -luuid
+ $(call mkdep,mkfs.ubifs/,mkfs.ubifs,,ubi-utils/libubi.a)
+ 
+ #
diff --git a/tools/mtd-utils/patches/136-mkfs.ubifs-xz-support.patch b/tools/mtd-utils/patches/136-mkfs.ubifs-xz-support.patch
new file mode 100644
index 0000000000..e8b491b3ce
--- /dev/null
+++ b/tools/mtd-utils/patches/136-mkfs.ubifs-xz-support.patch
@@ -0,0 +1,378 @@
+--- a/Makefile
++++ b/Makefile
+@@ -4,7 +4,7 @@
+ VERSION = 1.5.2
+ 
+ CPPFLAGS += -D_GNU_SOURCE -I./include -I$(BUILDDIR)/include -I./ubi-utils/include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS) $(UUIDCPPFLAGS)
+-CPPFLAGS += -I./include/linux/lzma
++CPPFLAGS += $(XZCPPFLAGS) -I./include/linux/lzma
+ 
+ ifeq ($(WITHOUT_XATTR), 1)
+   CPPFLAGS += -DWITHOUT_XATTR
+@@ -113,8 +113,13 @@ ifeq ($(WITHOUT_LZO), 1)
+ else
+   LZOLDLIBS = -llzo2
+ endif
++ifeq ($(WITHOUT_XZ), 1)
++  CPPFLAGS += -DWITHOUT_XZ
++else
++  XZLDLIBS = -llzma
++endif
+ 
+-LDLIBS_mkfs.ubifs = -lz $(LZOLDLIBS) -lm -luuid
++LDLIBS_mkfs.ubifs = -lz $(LZOLDLIBS) $(XZLDLIBS) -lm -luuid
+ $(call mkdep,mkfs.ubifs/,mkfs.ubifs,,ubi-utils/libubi.a)
+ 
+ #
+--- a/mkfs.ubifs/compr.c
++++ b/mkfs.ubifs/compr.c
+@@ -126,6 +126,114 @@ static inline int lzo_init(void) { retur
+ static inline void lzo_fini(void) { }
+ #endif
+ 
++#ifndef WITHOUT_XZ
++
++#include <lzma.h>
++
++struct xz_ctx {
++	lzma_filter	filters[3];
++	lzma_options_lzma opts;
++};
++
++static struct xz_ctx *xz_ctx;
++
++#define LZMA_COMPRESSION_LEVEL	9
++
++static struct xz_ctx *xz_ctx_init(void)
++{
++	struct xz_ctx *ctx;
++	lzma_options_lzma *opts_lzma;
++	uint32_t preset;
++	int ret;
++
++	ctx = malloc(sizeof(struct xz_ctx));
++	if (ctx == NULL)
++		goto err;
++
++	memset(ctx, 0, sizeof(struct xz_ctx));
++
++	opts_lzma = &ctx->opts;
++
++	preset = LZMA_COMPRESSION_LEVEL | LZMA_PRESET_EXTREME;
++	ret = lzma_lzma_preset(opts_lzma, preset);
++	if (ret)
++		goto err_free_ctx;
++
++	/* TODO: allow to specify LZMA options via command line */
++#if 0
++	opts_lzma->lc = 3;
++	opts_lzma->lp = 0;
++	opts_lzma->pb = 2;
++	opts_lzma->nice_len = 64;
++#else
++	opts_lzma->lc = 0;
++	opts_lzma->lp = 2;
++	opts_lzma->pb = 2;
++	opts_lzma->nice_len = 64;
++#endif
++
++	ctx->filters[0].id = LZMA_FILTER_LZMA2;
++	ctx->filters[0].options = opts_lzma;
++	ctx->filters[1].id = LZMA_VLI_UNKNOWN;
++
++	return ctx;
++
++err_free_ctx:
++	free(ctx);
++err:
++	return NULL;
++}
++
++static void xz_ctx_free(struct xz_ctx *ctx)
++{
++	free(ctx);
++}
++
++static int xz_init(void)
++{
++	xz_ctx = xz_ctx_init();
++	if (xz_ctx == NULL)
++		return -1;
++
++	return 0;
++}
++
++static void xz_fini(void)
++{
++	xz_ctx_free(xz_ctx);
++}
++
++static int xz_compress(void *in_buf, size_t in_len, void *out_buf,
++		       size_t *out_len)
++{
++	size_t ret_len;
++	lzma_ret ret_xz;
++	int ret;
++
++	ret = -1;
++
++	ret_len = 0;
++	ret_xz = lzma_stream_buffer_encode(xz_ctx->filters, LZMA_CHECK_CRC32,
++					   NULL, in_buf, in_len, out_buf,
++					   &ret_len, *out_len);
++	if (ret_xz != LZMA_OK) {
++		fprintf(stderr, "XZ error: %d\n", (int) ret_xz);
++		goto out;
++	}
++
++	*out_len = ret_len;
++
++	ret = 0;
++out:
++	return ret;
++}
++#else
++static inline int xz_init(void) { return 0; }
++static inline void xz_fini(void) { }
++static inline int xz_compress(void *in_buf, size_t in_len, void *out_buf,
++			      size_t *out_len) { return -1; }
++#endif
++
+ static int no_compress(void *in_buf, size_t in_len, void *out_buf,
+ 		       size_t *out_len)
+ {
+@@ -198,6 +306,9 @@ int compress_data(void *in_buf, size_t i
+ 		case MKFS_UBIFS_COMPR_LZO:
+ 			ret = lzo_compress(in_buf, in_len, out_buf, out_len);
+ 			break;
++		case MKFS_UBIFS_COMPR_XZ:
++			ret = xz_compress(in_buf, in_len, out_buf, out_len);
++			break;
+ 		case MKFS_UBIFS_COMPR_ZLIB:
+ 			ret = zlib_deflate(in_buf, in_len, out_buf, out_len);
+ 			break;
+@@ -225,12 +336,18 @@ int init_compression(void)
+ 	if (ret)
+ 		goto err;
+ 
++	ret = xz_init();
++	if (ret)
++		goto err_lzo;
++
+ 	zlib_buf = malloc(UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR);
+ 	if (!zlib_buf)
+-		goto err_lzo;
++		goto err_xz;
+ 
+ 	return 0;
+ 
++err_xz:
++	xz_fini();
+ err_lzo:
+ 	lzo_fini();
+ err:
+@@ -240,6 +357,7 @@ err:
+ void destroy_compression(void)
+ {
+ 	free(zlib_buf);
++	xz_fini();
+ 	lzo_fini();
+ 	if (errcnt)
+ 		fprintf(stderr, "%llu compression errors occurred\n", errcnt);
+--- a/mkfs.ubifs/compr.h
++++ b/mkfs.ubifs/compr.h
+@@ -36,6 +36,7 @@ enum compression_type
+ 	MKFS_UBIFS_COMPR_NONE,
+ 	MKFS_UBIFS_COMPR_LZO,
+ 	MKFS_UBIFS_COMPR_ZLIB,
++	MKFS_UBIFS_COMPR_XZ,
+ };
+ 
+ int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len,
+--- a/mkfs.ubifs/mkfs.ubifs.c
++++ b/mkfs.ubifs/mkfs.ubifs.c
+@@ -99,6 +99,9 @@ struct ubifs_info info_;
+ static struct ubifs_info *c = &info_;
+ static libubi_t ubi;
+ 
++static int force_compr_set;
++static int force_compr;
++
+ /* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */
+ int debug_level;
+ int verbose;
+@@ -133,7 +136,7 @@ static struct inum_mapping **hash_table;
+ /* Inode creation sequence number */
+ static unsigned long long creat_sqnum;
+ 
+-static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQq";
++static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:z:j:R:l:j:UQq";
+ 
+ static const struct option longopts[] = {
+ 	{"root",               1, NULL, 'r'},
+@@ -151,6 +154,7 @@ static const struct option longopts[] =
+ 	{"reserved",           1, NULL, 'R'},
+ 	{"compr",              1, NULL, 'x'},
+ 	{"favor-percent",      1, NULL, 'X'},
++	{"force-compr",        1, NULL, 'z'},
+ 	{"fanout",             1, NULL, 'f'},
+ 	{"space-fixup",        0, NULL, 'F'},
+ 	{"keyhash",            1, NULL, 'k'},
+@@ -178,11 +182,13 @@ static const char *helptext =
+ "-o, --output=FILE        output to FILE\n"
+ "-j, --jrn-size=SIZE      journal size\n"
+ "-R, --reserved=SIZE      how much space should be reserved for the super-user\n"
+-"-x, --compr=TYPE         compression type - \"lzo\", \"favor_lzo\", \"zlib\" or\n"
+-"                         \"none\" (default: \"lzo\")\n"
++"-x, --compr=TYPE         default compression type - \"lzo\", \"favor_lzo\",\n"
++"                         \"zlib\" or \"none\" (default: \"lzo\")\n"
+ "-X, --favor-percent      may only be used with favor LZO compression and defines\n"
+ "                         how many percent better zlib should compress to make\n"
+ "                         mkfs.ubifs use zlib instead of LZO (default 20%)\n"
++"-z, --force-compr=TYPE   force to build the fs with different compression -\n"
++"                         \"lzo\", \"zlib\" or \"none\"\n"
+ "-f, --fanout=NUM         fanout NUM (default: 8)\n"
+ "-F, --space-fixup        file-system free space has to be fixed up on first mount\n"
+ "                         (requires kernel version 3.0 or greater)\n"
+@@ -472,6 +478,43 @@ static int open_ubi(const char *node)
+ 	return 0;
+ }
+ 
++static const char *get_compr_str(int compr)
++{
++	switch (compr) {
++	case UBIFS_COMPR_LZO:
++		return "lzo";
++	case UBIFS_COMPR_ZLIB:
++		return "zlib";
++	case UBIFS_COMPR_XZ:
++		return "xz";
++	case UBIFS_COMPR_NONE:
++		return "none";
++	}
++
++	return "unknown";
++}
++
++static int get_compr_option(char *opt, int *compr_type, int *favor_lzo)
++{
++	*compr_type = UBIFS_COMPR_LZO;
++
++	if (favor_lzo)
++		*favor_lzo = 0;
++
++	if (favor_lzo && strcmp(optarg, "favor_lzo") == 0)
++		*favor_lzo = 1;
++	else if (strcmp(optarg, "zlib") == 0)
++		*compr_type = UBIFS_COMPR_ZLIB;
++	else if (strcmp(optarg, "xz") == 0)
++		*compr_type = UBIFS_COMPR_XZ;
++	else if (strcmp(optarg, "none") == 0)
++		*compr_type = UBIFS_COMPR_NONE;
++	else if (strcmp(optarg, "lzo") != 0)
++		return -1;
++
++	return 0;
++}
++
+ static int get_options(int argc, char**argv)
+ {
+ 	int opt, i;
+@@ -594,14 +637,13 @@ static int get_options(int argc, char**a
+ 				return err_msg("bad key hash");
+ 			break;
+ 		case 'x':
+-			if (strcmp(optarg, "favor_lzo") == 0)
+-				c->favor_lzo = 1;
+-			else if (strcmp(optarg, "zlib") == 0)
+-				c->default_compr = UBIFS_COMPR_ZLIB;
+-			else if (strcmp(optarg, "none") == 0)
+-				c->default_compr = UBIFS_COMPR_NONE;
+-			else if (strcmp(optarg, "lzo") != 0)
+-				return err_msg("bad compressor name");
++			if (get_compr_option(optarg, &c->default_compr,
++					     &c->favor_lzo))
++				return err_msg("bad compressor name '%s'",
++						optarg);
++			if (c->default_compr == UBIFS_COMPR_XZ)
++				return err_msg("'%s' can't be used as default compressor",
++						optarg);
+ 			break;
+ 		case 'X':
+ 			c->favor_percent = strtol(optarg, &endp, 0);
+@@ -610,6 +652,12 @@ static int get_options(int argc, char**a
+ 				return err_msg("bad favor LZO percent '%s'",
+ 					       optarg);
+ 			break;
++		case 'z':
++			if (get_compr_option(optarg, &force_compr, NULL))
++				return err_msg("bad forced compressor name '%s'",
++						optarg);
++			force_compr_set = 1;
++			break;
+ 		case 'j':
+ 			c->max_bud_bytes = get_bytes(optarg);
+ 			if (c->max_bud_bytes <= 0)
+@@ -684,6 +732,9 @@ static int get_options(int argc, char**a
+ 		c->min_io_size = 8;
+ 	c->rp_size = add_space_overhead(c->rp_size);
+ 
++	if (force_compr_set == 0)
++		force_compr = c->default_compr;
++
+ 	if (verbose) {
+ 		printf("mkfs.ubifs\n");
+ 		printf("\troot:         %s\n", root);
+@@ -693,17 +744,10 @@ static int get_options(int argc, char**a
+ 		printf("\toutput:       %s\n", output);
+ 		printf("\tjrn_size:     %llu\n", c->max_bud_bytes);
+ 		printf("\treserved:     %llu\n", c->rp_size);
+-		switch (c->default_compr) {
+-		case UBIFS_COMPR_LZO:
+-			printf("\tcompr:        lzo\n");
+-			break;
+-		case UBIFS_COMPR_ZLIB:
+-			printf("\tcompr:        zlib\n");
+-			break;
+-		case UBIFS_COMPR_NONE:
+-			printf("\tcompr:        none\n");
+-			break;
+-		}
++		printf("\tcompr:        %s\n", get_compr_str(c->default_compr));
++		if (force_compr_set)
++			printf("\tforced compr: %s\n",
++			       get_compr_str(force_compr));
+ 		printf("\tkeyhash:      %s\n", (c->key_hash == key_r5_hash) ?
+ 						"r5" : "test");
+ 		printf("\tfanout:       %d\n", c->fanout);
+@@ -1284,7 +1328,7 @@ static int add_file(const char *path_nam
+ 			use_compr = UBIFS_COMPR_LZO;
+ 		else
+ #endif
+-			use_compr = c->default_compr;
++			use_compr = force_compr;
+ 		compr_type = compress_data(buf, bytes_read, &dn->data,
+ 					   &out_len, use_compr);
+ 		dn->compr_type = cpu_to_le16(compr_type);
+--- a/mkfs.ubifs/mkfs.ubifs.h
++++ b/mkfs.ubifs/mkfs.ubifs.h
+@@ -83,6 +83,9 @@
+ #if MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
+ #error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB
+ #endif
++#if MKFS_UBIFS_COMPR_XZ != UBIFS_COMPR_XZ
++#error MKFS_UBIFS_COMPR_XZ != UBIFS_COMPR_XZ
++#endif
+ 
+ extern int verbose;
+ extern int debug_level;
+--- a/include/mtd/ubifs-media.h
++++ b/include/mtd/ubifs-media.h
+@@ -313,6 +313,7 @@ enum {
+ 	UBIFS_COMPR_NONE,
+ 	UBIFS_COMPR_LZO,
+ 	UBIFS_COMPR_ZLIB,
++	UBIFS_COMPR_XZ,
+ 	UBIFS_COMPR_TYPES_CNT,
+ };
+ 
diff --git a/tools/mtd-utils/patches/200-libubigen-add-ubigen_write_terminator-function.patch b/tools/mtd-utils/patches/200-libubigen-add-ubigen_write_terminator-function.patch
new file mode 100644
index 0000000000..95ce1e9137
--- /dev/null
+++ b/tools/mtd-utils/patches/200-libubigen-add-ubigen_write_terminator-function.patch
@@ -0,0 +1,89 @@
+--- a/ubi-utils/libubigen.c
++++ b/ubi-utils/libubigen.c
+@@ -122,8 +122,9 @@ int ubigen_add_volume(const struct ubige
+ 	return 0;
+ }
+ 
+-void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+-		        struct ubi_ec_hdr *hdr, long long ec)
++static void __ubigen_init_ec_hdr(const struct ubigen_info *ui,
++				 struct ubi_ec_hdr *hdr, long long ec,
++				 int eof)
+ {
+ 	uint32_t crc;
+ 
+@@ -136,10 +137,22 @@ void ubigen_init_ec_hdr(const struct ubi
+ 	hdr->data_offset = cpu_to_be32(ui->data_offs);
+ 	hdr->image_seq = cpu_to_be32(ui->image_seq);
+ 
++	if (eof) {
++		hdr->padding1[0] = 'E';
++		hdr->padding1[1] = 'O';
++		hdr->padding1[2] = 'F';
++	}
++
+ 	crc = mtd_crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ 	hdr->hdr_crc = cpu_to_be32(crc);
+ }
+ 
++void ubigen_init_ec_hdr(const struct ubigen_info *ui,
++		        struct ubi_ec_hdr *hdr, long long ec)
++{
++	__ubigen_init_ec_hdr(ui, hdr, ec, 0);
++}
++
+ void ubigen_init_vid_hdr(const struct ubigen_info *ui,
+ 			 const struct ubigen_vol_info *vi,
+ 			 struct ubi_vid_hdr *hdr, int lnum,
+@@ -307,6 +320,39 @@ int ubigen_write_layout_vol(const struct
+ 	}
+ 
+ 	free(outbuf);
++	return 0;
++
++out_free:
++	free(outbuf);
++	return -1;
++}
++
++int ubigen_write_eof_markers(const struct ubigen_info *ui, long long ec,
++			     int count, int out_fd)
++{
++	char *outbuf;
++	int peb_size = ui->peb_size;
++
++	outbuf = malloc(peb_size);
++	if (!outbuf) {
++		sys_errmsg("cannot allocate %d bytes of memory", peb_size);
++		return -1;
++	}
++
++	memset(outbuf, 0xFF, peb_size);
++	__ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec, 1);
++
++	while (count) {
++		if (write(out_fd, outbuf, peb_size) != peb_size) {
++			sys_errmsg("cannot write %d bytes to the output file",
++				   peb_size);
++			goto out_free;
++		}
++
++		count--;
++	}
++
++	free(outbuf);
+ 	return 0;
+ 
+ out_free:
+--- a/ubi-utils/include/libubigen.h
++++ b/ubi-utils/include/libubigen.h
+@@ -188,6 +188,9 @@ int ubigen_write_layout_vol(const struct
+ 			    long long ec1, long long ec2,
+ 			    struct ubi_vtbl_record *vtbl, int fd);
+ 
++int ubigen_write_eof_markers(const struct ubigen_info *ui, long long ec,
++			     int count, int out_fd);
++
+ #ifdef __cplusplus
+ }
+ #endif
diff --git a/tools/mtd-utils/patches/201-ubinize-add-terminator-support.patch b/tools/mtd-utils/patches/201-ubinize-add-terminator-support.patch
new file mode 100644
index 0000000000..cbb2802c5a
--- /dev/null
+++ b/tools/mtd-utils/patches/201-ubinize-add-terminator-support.patch
@@ -0,0 +1,77 @@
+--- a/ubi-utils/ubinize.c
++++ b/ubi-utils/ubinize.c
+@@ -70,6 +70,8 @@ static const char optionsstr[] =
+ "                             (default is 1)\n"
+ "-Q, --image-seq=<num>        32-bit UBI image sequence number to use\n"
+ "                             (by default a random number is picked)\n"
++"-E, --eof-markers=<num>      number of eof-markers to put at the end of the\n"
++"                             output image\n"
+ "-v, --verbose                be verbose\n"
+ "-h, --help                   print help message\n"
+ "-V, --version                print program version";
+@@ -79,7 +81,7 @@ static const char usage[] =
+ "\t\t[-x <num>] [-Q <num>] [-v] [-h] [-V] [--output=<filename>] [--peb-size=<bytes>]\n"
+ "\t\t[--min-io-size=<bytes>] [--sub-page-size=<bytes>] [--vid-hdr-offset=<num>]\n"
+ "\t\t[--erase-counter=<num>] [--ubi-ver=<num>] [--image-seq=<num>] [--verbose] [--help]\n"
+-"\t\t[--version] ini-file\n"
++"\t\t[--eof-markers=<num>] [--version] ini-file\n"
+ "Example: " PROGRAM_NAME " -o ubi.img -p 16KiB -m 512 -s 256 cfg.ini - create UBI image\n"
+ "         'ubi.img' as described by configuration file 'cfg.ini'";
+ 
+@@ -125,6 +127,7 @@ static const struct option long_options[
+ 	{ .name = "erase-counter",  .has_arg = 1, .flag = NULL, .val = 'e' },
+ 	{ .name = "ubi-ver",        .has_arg = 1, .flag = NULL, .val = 'x' },
+ 	{ .name = "image-seq",      .has_arg = 1, .flag = NULL, .val = 'Q' },
++	{ .name = "eof-markers",    .has_arg = 1, .flag = NULL, .val = 'E' },
+ 	{ .name = "verbose",        .has_arg = 0, .flag = NULL, .val = 'v' },
+ 	{ .name = "help",           .has_arg = 0, .flag = NULL, .val = 'h' },
+ 	{ .name = "version",        .has_arg = 0, .flag = NULL, .val = 'V' },
+@@ -144,6 +147,7 @@ struct args {
+ 	uint32_t image_seq;
+ 	int verbose;
+ 	dictionary *dict;
++	int eof_markers;
+ };
+ 
+ static struct args args = {
+@@ -162,7 +166,7 @@ static int parse_opt(int argc, char * co
+ 		int key, error = 0;
+ 		unsigned long int image_seq;
+ 
+-		key = getopt_long(argc, argv, "o:p:m:s:O:e:x:Q:vhV", long_options, NULL);
++		key = getopt_long(argc, argv, "o:p:m:s:O:e:x:Q:E:vhV", long_options, NULL);
+ 		if (key == -1)
+ 			break;
+ 
+@@ -222,6 +226,12 @@ static int parse_opt(int argc, char * co
+ 			args.image_seq = image_seq;
+ 			break;
+ 
++		case 'E':
++			args.eof_markers = simple_strtoul(optarg, &error);
++			if (error)
++				return errmsg("bad number of eof-markers: \"%s\"", optarg);
++			break;
++
+ 		case 'v':
+ 			args.verbose = 1;
+ 			break;
+@@ -599,6 +609,18 @@ int main(int argc, char * const argv[])
+ 			printf("\n");
+ 	}
+ 
++	if (args.eof_markers) {
++		verbose(args.verbose, "writing %d eof-marker blocks",
++			args.eof_markers);
++
++		err = ubigen_write_eof_markers(&ui, args.ec, args.eof_markers,
++					       args.out_fd);
++		if (err) {
++			errmsg("cannot write eof-marker blocks");
++			goto out_free;
++		}
++	}
++
+ 	verbose(args.verbose, "writing layout volume");
+ 
+ 	err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl, args.out_fd);
diff --git a/tools/mtd-utils/patches/310-add-static-linking-option.patch b/tools/mtd-utils/patches/310-add-static-linking-option.patch
new file mode 100644
index 0000000000..810aea9a54
--- /dev/null
+++ b/tools/mtd-utils/patches/310-add-static-linking-option.patch
@@ -0,0 +1,43 @@
+--- a/common.mk
++++ b/common.mk
+@@ -2,6 +2,16 @@ CC := $(CROSS)gcc
+ AR := $(CROSS)ar
+ RANLIB := $(CROSS)ranlib
+ 
++ifeq ($(STATIC),1)
++ define static_link
++  -Wl,-Bstatic $(1) -Wl,-Bdynamic
++ endef
++else
++ define static_link
++  $(1)
++ endef
++endif
++
+ # Stolen from Linux build system
+ comma = ,
+ try-run = $(shell set -e; ($(1)) >/dev/null 2>&1 && echo "$(2)" || echo "$(3)")
+--- a/Makefile
++++ b/Makefile
+@@ -89,10 +89,10 @@ obj-mkfs.jffs2 = compr_rtime.o compr_zli
+ 	compr_lzma.o lzma/LzFind.o lzma/LzmaEnc.o lzma/LzmaDec.o \
+ 	compr.o rbtree.o
+ LDFLAGS_mkfs.jffs2 = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+-LDLIBS_mkfs.jffs2  = -lz $(LZOLDLIBS)
++LDLIBS_mkfs.jffs2  = $(call static_link,-lz $(LZOLDLIBS))
+ 
+ LDFLAGS_jffs2reader = $(ZLIBLDFLAGS) $(LZOLDFLAGS)
+-LDLIBS_jffs2reader  = -lz $(LZOLDLIBS)
++LDLIBS_jffs2reader  = $(call static_link,-lz $(LZOLDLIBS))
+ 
+ $(foreach v,$(MTD_BINS),$(eval $(call mkdep,,$(v))))
+ 
+@@ -119,7 +119,7 @@ else
+   XZLDLIBS = -llzma
+ endif
+ 
+-LDLIBS_mkfs.ubifs = -lz $(LZOLDLIBS) $(XZLDLIBS) -lm -luuid
++LDLIBS_mkfs.ubifs = $(call static_link,-lz $(LZOLDLIBS) $(XZLDLIBS)) -lm $(call static_link,-luuid)
+ $(call mkdep,mkfs.ubifs/,mkfs.ubifs,,ubi-utils/libubi.a)
+ 
+ #
diff --git a/tools/mtools/Makefile b/tools/mtools/Makefile
new file mode 100644
index 0000000000..13de447780
--- /dev/null
+++ b/tools/mtools/Makefile
@@ -0,0 +1,38 @@
+# 
+# Copyright (C) 2012-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=mtools
+PKG_VERSION:=4.0.18
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=17b9f525c1ae3583a478338deb7fbc19
+PKG_CAT:=zcat
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_VARS += \
+	ac_cv_header_iconv_h=no
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) mcopy mmd
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/mcopy $(STAGING_DIR_HOST)/bin/
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/mmd $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/mcopy
+	rm -f $(STAGING_DIR_HOST)/bin/mmd
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/mtools/patches/100-compile_fix.patch b/tools/mtools/patches/100-compile_fix.patch
new file mode 100644
index 0000000000..698e156029
--- /dev/null
+++ b/tools/mtools/patches/100-compile_fix.patch
@@ -0,0 +1,19 @@
+--- a/sysincludes.h
++++ b/sysincludes.h
+@@ -101,14 +101,8 @@ typedef void *caddr_t;
+ #if defined __GNUC__ && defined __STDC__
+ /* gcc -traditional doesn't have PACKED, UNUSED and NORETURN */
+ # define PACKED __attribute__ ((packed))
+-# if __GNUC__ == 2 && __GNUC_MINOR__ > 6 || __GNUC__ >= 3
+-/* gcc 2.6.3 doesn't have "unused" */		/* mool */
+-#  define UNUSED(x) x __attribute__ ((unused));x
+-#  define UNUSEDP __attribute__ ((unused))
+-# else
+-#  define UNUSED(x) x
+-#  define UNUSEDP /* */
+-# endif
++# define UNUSED(x) x
++# define UNUSEDP /* */
+ # define NORETURN __attribute__ ((noreturn))
+ #else
+ # define UNUSED(x) x
diff --git a/tools/padjffs2/Makefile b/tools/padjffs2/Makefile
new file mode 100644
index 0000000000..0a583b8e1a
--- /dev/null
+++ b/tools/padjffs2/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=padjffs2
+PKG_VERSION:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Prepare
+	mkdir -p $(HOST_BUILD_DIR)
+	$(CP) ./src/* $(HOST_BUILD_DIR)/
+	find $(HOST_BUILD_DIR) -name .svn | $(XARGS) rm -rf
+endef
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR)
+endef
+
+define Host/Configure
+endef
+
+define Host/Install
+	$(CP) $(HOST_BUILD_DIR)/padjffs2 $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/padjffs2
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/padjffs2/src/Makefile b/tools/padjffs2/src/Makefile
new file mode 100644
index 0000000000..45da8e5dbc
--- /dev/null
+++ b/tools/padjffs2/src/Makefile
@@ -0,0 +1,15 @@
+CC = gcc
+CFLAGS =
+WFLAGS = -Wall -Werror
+padjffs2-objs = padjffs2.o
+
+all: padjffs2
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(WFLAGS) -c -o $@ $<
+
+padjffs2: $(padjffs2-objs)
+	$(CC) $(LDFLAGS) -o $@ $(padjffs2-objs)
+
+clean:
+	rm -f padjffs2 *.o
diff --git a/tools/padjffs2/src/padjffs2.c b/tools/padjffs2/src/padjffs2.c
new file mode 100644
index 0000000000..6308292431
--- /dev/null
+++ b/tools/padjffs2/src/padjffs2.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static char *progname;
+static unsigned int xtra_offset;
+static unsigned char eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
+static unsigned char jffs2_pad_be[] = "\x19\x85\x20\x04\x04\x00\x00\x00\xc4\x94\xdb\xf4";
+static unsigned char jffs2_pad_le[] = "\x85\x19\x04\x20\x00\x00\x00\x04\xa8\xfb\xa0\xb4";
+static unsigned char *pad = eof_mark;
+static int pad_len = sizeof(eof_mark);
+static bool pad_to_stdout = false;
+
+#define ERR(fmt, ...) do { \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt "\n", \
+			progname, ## __VA_ARGS__ ); \
+} while (0)
+
+#define ERRS(fmt, ...) do { \
+	int save = errno; \
+	fflush(0); \
+	fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
+			progname, ## __VA_ARGS__, strerror(save)); \
+} while (0)
+
+#define BUF_SIZE	(64 * 1024)
+#define ALIGN(_x,_y)	(((_x) + ((_y) - 1)) & ~((_y) - 1))
+
+static int pad_image(char *name, uint32_t pad_mask)
+{
+	char *buf;
+	int fd;
+	int outfd;
+	ssize_t in_len;
+	ssize_t out_len;
+	int ret = -1;
+
+	buf = malloc(BUF_SIZE);
+	if (!buf) {
+		ERR("No memory for buffer");
+		goto out;
+	}
+
+	fd = open(name, O_RDWR);
+	if (fd < 0) {
+		ERRS("Unable to open %s", name);
+		goto free_buf;
+	}
+
+	in_len = lseek(fd, 0, SEEK_END);
+	if (in_len < 0)
+		goto close;
+
+	if (!pad_to_stdout)
+		outfd = fd;
+	else
+		outfd = STDOUT_FILENO;
+
+	memset(buf, '\xff', BUF_SIZE);
+
+	in_len += xtra_offset;
+
+	out_len = in_len;
+	while (pad_mask) {
+		uint32_t mask;
+		ssize_t t;
+		int i;
+
+		for (i = 10; i < 32; i++) {
+			mask = 1UL << i;
+			if (pad_mask & mask)
+				break;
+		}
+
+		in_len = ALIGN(in_len, mask);
+
+		for (i = 10; i < 32; i++) {
+			mask = 1UL << i;
+			if ((in_len & (mask - 1)) == 0)
+				pad_mask &= ~mask;
+		}
+
+		fprintf(stderr, "padding image to %08x\n", (unsigned int) in_len - xtra_offset);
+
+		while (out_len < in_len) {
+			ssize_t len;
+
+			len = in_len - out_len;
+			if (len > BUF_SIZE)
+				len = BUF_SIZE;
+
+			t = write(outfd, buf, len);
+			if (t != len) {
+				ERRS("Unable to write to %s", name);
+				goto close;
+			}
+
+			out_len += len;
+		}
+
+		/* write out the JFFS end-of-filesystem marker */
+		t = write(outfd, pad, pad_len);
+		if (t != pad_len) {
+			ERRS("Unable to write to %s", name);
+			goto close;
+		}
+		out_len += pad_len;
+	}
+
+	ret = 0;
+
+close:
+	close(fd);
+free_buf:
+	free(buf);
+out:
+	return ret;
+}
+
+static int usage(void)
+{
+	fprintf(stderr,
+		"Usage: %s file [<options>] [pad0] [pad1] [padN]\n"
+		"Options:\n"
+		"  -x <offset>:          Add an extra offset for padding data\n"
+		"  -J:                   Use a fake big-endian jffs2 padding element instead of EOF\n"
+		"                        This is used to work around broken boot loaders that\n"
+		"                        try to parse the entire firmware area as one big jffs2\n"
+		"  -j:                   (like -J, but little-endian instead of big-endian)\n"
+		"  -c:                   write padding to stdout\n"
+		"\n",
+		progname);
+	return EXIT_FAILURE;
+}
+
+int main(int argc, char* argv[])
+{
+	char *image;
+	uint32_t pad_mask;
+	int ret = EXIT_FAILURE;
+	int err;
+	int ch, i;
+
+	progname = basename(argv[0]);
+
+	if (argc < 2)
+		return usage();
+
+	image = argv[1];
+	argv++;
+	argc--;
+
+	pad_mask = 0;
+	while ((ch = getopt(argc, argv, "x:Jjc")) != -1) {
+		switch (ch) {
+		case 'x':
+			xtra_offset = strtoul(optarg, NULL, 0);
+			fprintf(stderr, "assuming %u bytes offset\n",
+				xtra_offset);
+			break;
+		case 'J':
+			pad = jffs2_pad_be;
+			pad_len = sizeof(jffs2_pad_be) - 1;
+			break;
+		case 'j':
+			pad = jffs2_pad_le;
+			pad_len = sizeof(jffs2_pad_le) - 1;
+			break;
+		case 'c':
+			pad_to_stdout = true;
+			break;
+		default:
+			return usage();
+		}
+	}
+
+	for (i = optind; i < argc; i++)
+		pad_mask |= strtoul(argv[i], NULL, 0) * 1024;
+
+	if (pad_mask == 0)
+		pad_mask = (4 * 1024) | (8 * 1024) | (64 * 1024) |
+			   (128 * 1024);
+
+	err = pad_image(image, pad_mask);
+	if (err)
+		goto out;
+
+	ret = EXIT_SUCCESS;
+
+out:
+	return ret;
+}
diff --git a/tools/patch-image/Makefile b/tools/patch-image/Makefile
new file mode 100644
index 0000000000..6f2900b96c
--- /dev/null
+++ b/tools/patch-image/Makefile
@@ -0,0 +1,28 @@
+# 
+# Copyright (C) 2007-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=patch-image
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(HOSTCC) $(HOST_CFLAGS) -include endian.h -o $(HOST_BUILD_DIR)/patch-cmdline src/patch-cmdline.c
+	$(HOSTCC) $(HOST_CFLAGS) -include endian.h -o $(HOST_BUILD_DIR)/patch-dtb src/patch-dtb.c
+endef
+
+define Host/Install
+	$(CP) $(HOST_BUILD_DIR)/patch-cmdline $(STAGING_DIR_HOST)/bin/
+	$(CP) $(HOST_BUILD_DIR)/patch-dtb $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/patch-cmdline
+	rm -f $(STAGING_DIR_HOST)/bin/patch-dtb
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/patch-image/src/patch-cmdline.c b/tools/patch-image/src/patch-cmdline.c
new file mode 100644
index 0000000000..8d1fce9172
--- /dev/null
+++ b/tools/patch-image/src/patch-cmdline.c
@@ -0,0 +1,85 @@
+/*
+ * patch-cmdline.c - patch the kernel command line on rb532
+ *
+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#define SEARCH_SPACE	(16 * 1024)
+#define CMDLINE_MAX		512
+
+int main(int argc, char **argv)
+{
+	int fd, found = 0, len, ret = -1;
+	char *ptr, *p;
+	unsigned int search_space;
+
+	if (argc <= 2 || argc > 4) {
+		fprintf(stderr, "Usage: %s <file> <cmdline> [size]\n", argv[0]);
+		goto err1;
+	} else if (argc == 3) {
+		fprintf(stdout, "search space used is default of 16KB\n");
+		search_space = SEARCH_SPACE;
+	} else {
+		search_space = atoi(argv[3]);
+	}
+	len = strlen(argv[2]);
+	if (len + 9 > CMDLINE_MAX) {
+		fprintf(stderr, "Command line string too long\n");
+		goto err1;
+	}
+	
+	if (((fd = open(argv[1], O_RDWR)) < 0) ||
+		(ptr = (char *) mmap(0, search_space + CMDLINE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == (void *) (-1)) {
+		fprintf(stderr, "Could not open kernel image");
+		goto err2;
+	}
+	
+	for (p = ptr; p < (ptr + search_space); p += 4) {
+		if (memcmp(p, "CMDLINE:", 8) == 0) {
+			found = 1;
+			p += 8;
+			break;
+		}
+	}
+	if (!found) {
+		fprintf(stderr, "Command line marker not found!\n");
+		goto err3;
+	}
+
+	memset(p, 0, CMDLINE_MAX - 8);
+	strcpy(p, argv[2]);
+	msync(p, CMDLINE_MAX, MS_SYNC|MS_INVALIDATE);
+	ret = 0;
+
+err3:
+	munmap((void *) ptr, len);
+err2:
+	if (fd > 0)
+		close(fd);
+err1:
+	return ret;
+}
diff --git a/tools/patch-image/src/patch-dtb.c b/tools/patch-image/src/patch-dtb.c
new file mode 100644
index 0000000000..8d186236c1
--- /dev/null
+++ b/tools/patch-image/src/patch-dtb.c
@@ -0,0 +1,107 @@
+/*
+ * patch-dtb.c - patch a dtb into an image
+ *
+ * Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * based on patch-cmdline.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#define DTB_MAX	(16 * 1024)
+
+int main(int argc, char **argv)
+{
+	int fd, fddtb, found = 0, len, ret = -1;
+	char *ptr, *ptrdtb, *p;
+	struct stat s;
+	unsigned int search_space , dtb_max_size;
+
+	if (argc <= 2 || argc > 4) {
+		fprintf(stderr, "Usage: %s <file> <dtb> [size]\n", argv[0]);
+		goto err1;
+	} else if (argc == 3) {
+		fprintf(stdout, "DT size used is default of 16KB\n");
+		search_space = dtb_max_size = DTB_MAX;
+	} else {
+		search_space = dtb_max_size = atoi(argv[3]);
+	}
+
+	fddtb = open(argv[1], O_RDONLY);
+	if (!fddtb)
+		goto err1;
+
+	if (stat(argv[2], &s)) {
+		fprintf(stderr, "DTB not found\n");
+		goto err1;
+	}
+
+	len = s.st_size;
+	if (len + 8 > dtb_max_size) {
+		fprintf(stderr, "DTB too big\n");
+		goto err1;
+	}
+
+        if (((fddtb = open(argv[2], O_RDONLY)) < 0) ||
+		(ptrdtb = (char *) mmap(0, dtb_max_size, PROT_READ, MAP_SHARED, fddtb, 0)) == (void *) (-1)) {
+		fprintf(stderr, "Could not open DTB");
+		goto err2;
+	}
+
+	if (((fd = open(argv[1], O_RDWR)) < 0) ||
+		(ptr = (char *) mmap(0, search_space + dtb_max_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == (void *) (-1)) {
+		fprintf(stderr, "Could not open kernel image");
+		goto err3;
+	}
+
+	for (p = ptr; p < (ptr + search_space); p += 4) {
+		if (memcmp(p, "OWRTDTB:", 8) == 0) {
+			found = 1;
+			p += 8;
+			break;
+		}
+	}
+	if (!found) {
+		fprintf(stderr, "DTB marker not found!\n");
+		goto err4;
+	}
+
+	memset(p, 0, dtb_max_size - 8);
+	memcpy(p, ptrdtb, len);
+	msync(p, len, MS_SYNC|MS_INVALIDATE);
+	ret = 0;
+
+err4:
+	munmap((void *) ptr, len);
+err3:
+	if (fd > 0)
+		close(fd);
+	munmap((void *) ptrdtb, len);
+err2:
+	if (fddtb > 0)
+		close(fddtb);
+err1:
+	return ret;
+}
diff --git a/tools/patch/Makefile b/tools/patch/Makefile
new file mode 100644
index 0000000000..1ea96bf33b
--- /dev/null
+++ b/tools/patch/Makefile
@@ -0,0 +1,23 @@
+# 
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=patch
+PKG_VERSION:=2.7.5
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/patch
+PKG_MD5SUM:=e3da7940431633fb65a01b91d3b7a27a
+
+HOST_BUILD_PARALLEL := 1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOSTCC := $(HOSTCC_NOCACHE)
+HOSTCXX := $(HOSTCXX_NOCACHE)
+
+$(eval $(call HostBuild))
diff --git a/tools/patchelf/Makefile b/tools/patchelf/Makefile
new file mode 100644
index 0000000000..76bcbaf54c
--- /dev/null
+++ b/tools/patchelf/Makefile
@@ -0,0 +1,26 @@
+# 
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=patchelf
+PKG_VERSION:=0.9
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://nixos.org/releases/patchelf/patchelf-$(PKG_VERSION)
+PKG_MD5SUM:=d02687629c7e1698a486a93a0d607947
+
+HOST_BUILD_PARALLEL:=1
+HOST_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/src/patchelf $(STAGING_DIR_HOST)/bin/patchelf
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/pkg-config/Makefile b/tools/pkg-config/Makefile
new file mode 100644
index 0000000000..57f02b5394
--- /dev/null
+++ b/tools/pkg-config/Makefile
@@ -0,0 +1,39 @@
+# 
+# Copyright (C) 2006-2016 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=pkg-config
+PKG_VERSION:=0.29.1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://pkgconfig.freedesktop.org/releases/
+PKG_MD5SUM:=f739a28cae4e0ca291f82d1d41ef107d
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport PKG_CONFIG
+
+HOST_CONFIGURE_ARGS += --with-internal-glib
+
+ifeq ($(HOST_OS),Darwin)
+HOST_LDFLAGS += -framework CoreFoundation -framework Carbon
+endif
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) install
+	mv $(STAGING_DIR_HOST)/bin/pkg-config $(STAGING_DIR_HOST)/bin/pkg-config.real
+	$(INSTALL_BIN) ./files/pkg-config $(STAGING_DIR_HOST)/bin/pkg-config
+endef
+
+define Host/Clean
+	-$(MAKE) -C $(HOST_BUILD_DIR) uninstall
+	$(call Host/Clean/Default)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/pkg-config/files/pkg-config b/tools/pkg-config/files/pkg-config
new file mode 100755
index 0000000000..e58b13216d
--- /dev/null
+++ b/tools/pkg-config/files/pkg-config
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+pkg-config.real $@ --define-variable=prefix=${STAGING_PREFIX} --define-variable=exec_prefix=${STAGING_PREFIX}
diff --git a/tools/pkg-config/patches/001-glib-gdate-suppress-string-format-literal-warning.patch b/tools/pkg-config/patches/001-glib-gdate-suppress-string-format-literal-warning.patch
new file mode 100644
index 0000000000..6849299c47
--- /dev/null
+++ b/tools/pkg-config/patches/001-glib-gdate-suppress-string-format-literal-warning.patch
@@ -0,0 +1,18 @@
+--- a/glib/glib/gdate.c
++++ b/glib/glib/gdate.c
+@@ -2439,6 +2439,9 @@ win32_strftime_helper (const GDate     *d,
+  *
+  * Returns: number of characters written to the buffer, or 0 the buffer was too small
+  */
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wformat-nonliteral"
++
+ gsize     
+ g_date_strftime (gchar       *s, 
+                  gsize        slen, 
+@@ -2549,3 +2552,5 @@ g_date_strftime (gchar       *s,
+   return retval;
+ #endif
+ }
++
++#pragma GCC diagnostic pop
diff --git a/tools/ppl/Makefile b/tools/ppl/Makefile
new file mode 100644
index 0000000000..26caced909
--- /dev/null
+++ b/tools/ppl/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ppl
+PKG_VERSION:=1.2
+
+PKG_SOURCE_URL:=http://bugseng.com/products/ppl/download/ftp/releases/$(PKG_VERSION)/
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MD5SUM:=e7bd12043d1064214f7a0107b6da3f17
+
+HOST_FIXUP:=autoreconf
+
+HOST_BUILD_PARALLEL:=1
+HOST_CONFIGURE_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport CFLAGS
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static \
+	--disable-shared
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR)/$(3); \
+		$(HOST_CONFIGURE_CMD) \
+		$(HOST_CONFIGURE_VARS) \
+		$(HOST_CONFIGURE_ARGS); \
+	)
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/ppl/patches/001-disable-serial-tests.patch b/tools/ppl/patches/001-disable-serial-tests.patch
new file mode 100644
index 0000000000..91b0753feb
--- /dev/null
+++ b/tools/ppl/patches/001-disable-serial-tests.patch
@@ -0,0 +1,44 @@
+--- a/tests/BD_Shape/Makefile.am
++++ b/tests/BD_Shape/Makefile.am
+@@ -21,8 +21,6 @@
+ # For the most up-to-date information see the Parma Polyhedra Library
+ # site: http://bugseng.com/products/ppl/ .
+ 
+-AUTOMAKE_OPTIONS = serial-tests
+-
+ if VALGRIND_TESTS_ENABLED
+ 
+ CHECKER = \
+--- a/tests/Box/Makefile.am
++++ b/tests/Box/Makefile.am
+@@ -21,8 +21,6 @@
+ # For the most up-to-date information see the Parma Polyhedra Library
+ # site: http://bugseng.com/products/ppl/ .
+ 
+-AUTOMAKE_OPTIONS = serial-tests
+-
+ if VALGRIND_TESTS_ENABLED
+ 
+ CHECKER = \
+--- a/tests/Concrete_Expression/Makefile.am
++++ b/tests/Concrete_Expression/Makefile.am
+@@ -21,8 +21,6 @@
+ # For the most up-to-date information see the Parma Polyhedra Library
+ # site: http://bugseng.com/products/ppl/ .
+ 
+-AUTOMAKE_OPTIONS = serial-tests
+-
+ if VALGRIND_TESTS_ENABLED
+ 
+ CHECKER = \
+--- a/tests/Octagonal_Shape/Makefile.am
++++ b/tests/Octagonal_Shape/Makefile.am
+@@ -21,8 +21,6 @@
+ # For the most up-to-date information see the Parma Polyhedra Library
+ # site: http://bugseng.com/products/ppl/ .
+ 
+-AUTOMAKE_OPTIONS = serial-tests
+-
+ if VALGRIND_TESTS_ENABLED
+ 
+ CHECKER = \
diff --git a/tools/qemu/Makefile b/tools/qemu/Makefile
new file mode 100644
index 0000000000..bffbaa45e7
--- /dev/null
+++ b/tools/qemu/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2010-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=qemu
+PKG_VERSION:=0.14.1
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL:=@SAVANNAH/qemu
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_MD5SUM:=b6c713a8db638e173af53a62d5178640
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CFLAGS += -I$(STAGING_DIR_HOST)/include/e2fsprogs
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR); \
+		CFLAGS="$(HOST_CFLAGS)" \
+		LDFLAGS="$(HOST_LDFLAGS)" \
+		$(HOST_CONFIGURE_CMD) \
+		--extra-cflags="$(HOST_CFLAGS)" \
+		--enable-uuid \
+	)
+endef
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) qemu-img
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/qemu-img $(STAGING_DIR_HOST)/bin
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/quilt/Makefile b/tools/quilt/Makefile
new file mode 100644
index 0000000000..1cfa57791b
--- /dev/null
+++ b/tools/quilt/Makefile
@@ -0,0 +1,36 @@
+# 
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=quilt
+PKG_VERSION:=0.65
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SAVANNAH/quilt
+PKG_MD5SUM:=c67ba0228f5b7b8bbe469474661f92d6
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Configure
+	cd $(HOST_BUILD_DIR) && autoconf
+	$(call Host/Configure/Default)
+	[ -f $(HOST_BUILD_DIR)/Makefile ]
+endef
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR) SHELL="$(BASH)" all
+endef
+
+define Host/Install
+	$(MAKE) -C $(HOST_BUILD_DIR) SHELL="$(BASH)" install
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/quilt
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/quilt/patches/000-relocatable.patch b/tools/quilt/patches/000-relocatable.patch
new file mode 100644
index 0000000000..0e0eb7380c
--- /dev/null
+++ b/tools/quilt/patches/000-relocatable.patch
@@ -0,0 +1,170 @@
+--- a/bin/quilt.in
++++ b/bin/quilt.in
+@@ -15,14 +15,22 @@ unset POSIXLY_CORRECT
+ unset GREP_OPTIONS
+ 
+ export TEXTDOMAIN=quilt
+-export TEXTDOMAINDIR=@LOCALEDIR@
+ 
+-: ${QUILT_DIR=@QUILT_DIR@}
++if test -n "$STAGING_DIR_HOST"; then
++	export TEXTDOMAINDIR="$STAGING_DIR_HOST/share/locale"
++	: ${QUILT_DIR=$STAGING_DIR_HOST/share/quilt} ${QUILT_LIB=$STAGING_DIR_HOST/lib/quilt}
++	: ${QUILT_ETC=$STAGING_DIR_HOST/etc}
++else
++	export TEXTDOMAINDIR=@LOCALEDIR@
++	: ${QUILT_DIR=@QUILT_DIR@}
++	: ${QUILT_ETC=@ETCDIR@}
++fi
++
+ export QUILT_DIR
+ 
+ if [ -z "$QUILTRC" ]
+ then
+-	for QUILTRC in $HOME/.quiltrc @ETCDIR@/quilt.quiltrc; do
++	for QUILTRC in $HOME/.quiltrc $QUILT_ETC/quilt.quiltrc; do
+ 		[ -e $QUILTRC ] && break
+ 	done
+ 	export QUILTRC
+--- a/quilt/scripts/edmail.in
++++ b/quilt/scripts/edmail.in
+@@ -1,4 +1,6 @@
+-#! @PERL@ -w
++#! @PERL@
++
++use warnings;
+ 
+ # RFCs important for this script:
+ #
+@@ -29,7 +31,7 @@ BEGIN {
+ }
+ 
+ setlocale(LC_MESSAGES, "");
+-bindtextdomain("quilt", "@LOCALEDIR@");
++bindtextdomain("quilt", $ENV{'STAGING_DIR_HOST'} ? $ENV{'STAGING_DIR_HOST'} . '/share/locale' : "@LOCALEDIR@");
+ textdomain("quilt");
+ 
+ sub _($) {
+--- a/quilt/scripts/patchfns.in
++++ b/quilt/scripts/patchfns.in
+@@ -8,7 +8,11 @@
+ #  See the COPYING and AUTHORS files for more details.
+ 
+ export TEXTDOMAIN=quilt
+-export TEXTDOMAINDIR=@LOCALEDIR@
++if [ -n "$STAGING_DIR_HOST" ]; then
++	export TEXTDOMAINDIR="$STAGING_DIR_HOST/share/locale"
++else
++	export TEXTDOMAINDIR=@LOCALEDIR@
++fi
+ 
+ : ${LC_CTYPE:=$LANG}
+ : ${LC_MESSAGES:=$LANG}
+--- a/quilt/scripts/remove-trailing-ws.in
++++ b/quilt/scripts/remove-trailing-ws.in
+@@ -1,4 +1,6 @@
+-#! @PERL@ -w
++#! @PERL@
++
++use warnings;
+ 
+ # Remove trailing whitespace from modified lines in working files.
+ #
+@@ -31,7 +33,7 @@ BEGIN {
+ }
+ 
+ setlocale(LC_MESSAGES, "");
+-bindtextdomain("quilt", "@LOCALEDIR@");
++bindtextdomain("quilt", $ENV{'STAGING_DIR_HOST'} ? $ENV{'STAGING_DIR_HOST'} . '/share/locale' : "@LOCALEDIR@");
+ textdomain("quilt");
+ 
+ sub _($) {
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -21,8 +21,8 @@ COLUMN :=	@COLUMN@
+ GETOPT :=	@GETOPT@
+ CP :=		@CP@
+ DATE :=		@DATE@
+-PERL :=		@PERL@
+-BASH :=		@BASH@
++PERL :=		/usr/bin/env perl
++BASH :=		/usr/bin/env bash
+ SHELL:=		@BASH@ # It does not work if dash is used as a shell, for example
+ GREP :=		@GREP@
+ TAIL :=		@TAIL@
+@@ -32,7 +32,7 @@ AWK :=		@AWK@
+ FIND :=		@FIND@
+ XARGS :=	@XARGS@
+ DIFF :=		@DIFF@
+-PATCH :=	@PATCH@
++PATCH :=	/usr/bin/env patch
+ MKTEMP :=	@MKTEMP@
+ MSGMERGE :=	@MSGMERGE@
+ MSGFMT :=	@MSGFMT@
+@@ -48,8 +48,8 @@ USE_NLS :=	@USE_NLS@
+ STAT_HARDLINK := @STAT_HARDLINK@
+ PATCH_WRAPPER := @PATCH_WRAPPER@
+ 
+-COMPAT_SYMLINKS	:= @COMPAT_SYMLINKS@
+-COMPAT_PROGRAMS	:= @COMPAT_PROGRAMS@
++COMPAT_SYMLINKS	:=
++COMPAT_PROGRAMS	:=
+ 
+ default: all
+ 
+--- a/quilt/scripts/backup-files.in
++++ b/quilt/scripts/backup-files.in
+@@ -53,7 +53,12 @@ usage ()
+ "
+ }
+ 
+-: ${QUILT_DIR=@QUILT_DIR@}
++if test -n "$STAGING_DIR_HOST"; then
++	: ${QUILT_DIR="$STAGING_DIR_HOST/share/quilt"}
++else
++	: ${QUILT_DIR=@QUILT_DIR@}
++fi
++
+ . $QUILT_DIR/scripts/utilfns
+ 
+ ensure_nolinks()
+--- a/bin/guards.in
++++ b/bin/guards.in
+@@ -1,4 +1,6 @@
+-#!@PERL@ -w
++#!@PERL@
++
++use warnings;
+ 
+ #  This script is free software; you can redistribute it and/or modify
+ #  it under the terms of the GNU General Public License version 2 as
+--- a/compat/date.in
++++ b/compat/date.in
+@@ -1,4 +1,6 @@
+-#! @PERL@ -w
++#! @PERL@
++
++use warnings;
+ 
+ #  This script is free software; you can redistribute it and/or modify
+ #  it under the terms of the GNU General Public License version 2 as
+--- a/compat/getopt.in
++++ b/compat/getopt.in
+@@ -1,4 +1,6 @@
+-#! @PERL@ -w
++#! @PERL@
++
++use warnings;
+ 
+ #  This script is free software; you can redistribute it and/or modify
+ #  it under the terms of the GNU General Public License version 2 as
+--- a/quilt/scripts/dependency-graph.in
++++ b/quilt/scripts/dependency-graph.in
+@@ -1,4 +1,6 @@
+-#!@PERL@ -w
++#!@PERL@
++
++use warnings;
+ 
+ #  This script is free software; you can redistribute it and/or modify
+ #  it under the terms of the GNU General Public License version 2 as
diff --git a/tools/quilt/patches/001-fix_compile.patch b/tools/quilt/patches/001-fix_compile.patch
new file mode 100644
index 0000000000..c829515f83
--- /dev/null
+++ b/tools/quilt/patches/001-fix_compile.patch
@@ -0,0 +1,18 @@
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -272,13 +272,10 @@ $(patsubst %.in,%,$(wildcard bin/*.in qu
+ 	@$(if $(filter $@,$(NON_EXEC_IN)),,chmod +x $@)
+ 
+ configure : configure.ac aclocal.m4
+-	autoconf
+-	@echo "Please run ./configure"
+-	@false
++	@touch $@
+ 
+ Makefile : Makefile.in configure
+-	@echo "Please run ./configure"
+-	@false
++	@touch $@
+ 
+ compat_leftover := $(filter-out $(COMPAT),$(shell $(FIND) compat -type f -perm -0100))
+ 
diff --git a/tools/scons/Makefile b/tools/scons/Makefile
new file mode 100644
index 0000000000..ae947133ef
--- /dev/null
+++ b/tools/scons/Makefile
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2011-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=scons
+PKG_VERSION:=2.5.1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/scons \
+		http://fossies.org/linux/misc/
+PKG_MD5SUM:=aaaf09e1351a598f98d17b0cf1103e7a
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Configure
+endef
+
+define Host/Compile
+endef
+
+define Host/Install
+	./files/pywrap.sh $(HOST_BUILD_DIR)/setup.py install --prefix=$(STAGING_DIR_HOST)
+	rm -f $(STAGING_DIR_HOST)/bin/scons*.py
+	for bin in $(STAGING_DIR_HOST)/bin/scons*; do \
+		mv "$$$$bin" "$$$$bin.py";                \
+		cp ./files/pywrap.sh "$$$$bin";           \
+	done
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/scons/files/pywrap.sh b/tools/scons/files/pywrap.sh
new file mode 100755
index 0000000000..f62f590e0b
--- /dev/null
+++ b/tools/scons/files/pywrap.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+case "${0##*/}" in
+	pywrap.sh) arg1="";;
+	*) arg1="$0.py" ;;
+esac
+
+for bin in python python2 python2.7 python2.6 python2.5 python2.4; do
+    case "$($bin -V 2>&1)" in
+        "Python 2"*) exec $bin $arg1 "$@" ;;
+    esac
+done
+
+echo "Unable to find a Python 2.x interpreter for executing ${arg1:+$arg1 }$@ !" >&2
+exit 1
diff --git a/tools/scons/patches/001-platform_env.patch b/tools/scons/patches/001-platform_env.patch
new file mode 100644
index 0000000000..8aab9041c7
--- /dev/null
+++ b/tools/scons/patches/001-platform_env.patch
@@ -0,0 +1,11 @@
+--- a/engine/SCons/Platform/__init__.py
++++ b/engine/SCons/Platform/__init__.py
+@@ -63,6 +63,8 @@ def platform_default():
+     care about the machine architecture.
+     """
+     osname = os.name
++    if 'PLATFORM' in os.environ:
++        return os.environ['PLATFORM']
+     if osname == 'java':
+         osname = os._osType
+     if osname == 'posix':
diff --git a/tools/sdimage/Makefile b/tools/sdimage/Makefile
new file mode 100644
index 0000000000..52c2b41cf2
--- /dev/null
+++ b/tools/sdimage/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=imx-uuc
+PKG_VERSION=2015-09-13-$(PKG_SOURCE_VERSION)
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/mhei/fsl-imx-uuc.git
+PKG_SOURCE_VERSION:=2b99403b6dc60a22b07eb7a5cc0cb184abb89bdd
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_SOURCE_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.xz
+
+PKG_LICENSE:=GPL-2.0+
+PKG_LICENSE_FILES:=LICENSE
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_SOURCE_SUBDIR)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Configure
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/sdimage $(STAGING_DIR_HOST)/bin/sdimage
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/sdimage
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/sed/Makefile b/tools/sed/Makefile
new file mode 100644
index 0000000000..0e130e249a
--- /dev/null
+++ b/tools/sed/Makefile
@@ -0,0 +1,43 @@
+# 
+# Copyright (C) 2006-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=sed
+PKG_VERSION:=4.2.2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=@GNU/$(PKG_NAME)
+PKG_MD5SUM:=7ffe1c7cdc3233e1e0c4b502df253974
+PKG_CAT:=bzcat
+export SED:=
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOST_CONFIGURE_ARGS += \
+	--disable-acl \
+	--disable-nls \
+
+HOST_CONFIGURE_VARS += \
+	ac_cv_search_setfilecon=no \
+	ac_cv_header_selinux_context_h=no \
+	ac_cv_header_selinux_selinux_h=no \
+
+define Host/Compile
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) SHELL="$(BASH)"
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/sed/sed $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/sed
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/sed/patches/001-musl_host_fixup.patch b/tools/sed/patches/001-musl_host_fixup.patch
new file mode 100644
index 0000000000..4dcb1ec3c1
--- /dev/null
+++ b/tools/sed/patches/001-musl_host_fixup.patch
@@ -0,0 +1,24 @@
+--- a/build-aux/config.sub
++++ b/build-aux/config.sub
+@@ -122,9 +122,9 @@ esac
+ # Here we must recognize all the valid KERNEL-OS combinations.
+ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+ case $maybe_os in
+-  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+-  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+-  knetbsd*-gnu* | netbsd*-gnu* | \
++  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-musl* | \
++  linux-newlib* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
++  kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+   kopensolaris*-gnu* | \
+   storm-chaos* | os2-emx* | rtmk-nova*)
+     os=-$maybe_os
+@@ -1360,7 +1360,7 @@ case $os in
+ 	      | -chorusos* | -chorusrdb* | -cegcc* \
+ 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ 	      | -mingw32* | -linux-gnu* | -linux-android* \
+-	      | -linux-newlib* | -linux-uclibc* \
++	      | -linux-musl* | -linux-newlib* | -linux-uclibc* \
+ 	      | -uxpv* | -beos* | -mpeix* | -udk* \
+ 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
diff --git a/tools/sparse/Makefile b/tools/sparse/Makefile
new file mode 100644
index 0000000000..d5cc8460b7
--- /dev/null
+++ b/tools/sparse/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2014 Qualcomm-Atheros Inc.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=sparse
+PKG_VERSION:=0.5-git40791b94
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://git.kernel.org/pub/scm/devel/sparse/sparse.git
+PKG_SOURCE_VERSION:=40791b94c56b1a6da2a0ddeb1f9d5c9d64de8f93
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Install
+       $(INSTALL_BIN) $(HOST_BUILD_DIR)/sparse $(STAGING_DIR_HOST)/bin
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/squashfs/Makefile b/tools/squashfs/Makefile
new file mode 100644
index 0000000000..88416bd95d
--- /dev/null
+++ b/tools/squashfs/Makefile
@@ -0,0 +1,39 @@
+# 
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=squashfs
+PKG_VERSION:=3.0
+
+PKG_SOURCE:=$(PKG_NAME)$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/squashfs
+PKG_MD5SUM:=9fd05d0bfbb712f5fb95edafea5bc733
+PKG_CAT:=zcat
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR)/squashfs-tools \
+		CC="$(HOSTCC)" \
+		CXX="$(CXX)" \
+		LZMAPATH=$(STAGING_DIR_HOST)/lib \
+		mksquashfs-lzma unsquashfs-lzma 
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/squashfs-tools/mksquashfs-lzma $(STAGING_DIR_HOST)/bin/
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/squashfs-tools/unsquashfs-lzma $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/mksquashfs-lzma
+	rm -f $(STAGING_DIR_HOST)/bin/unsquashfs-lzma
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/squashfs/patches/100-lzma.patch b/tools/squashfs/patches/100-lzma.patch
new file mode 100644
index 0000000000..73f6a4e055
--- /dev/null
+++ b/tools/squashfs/patches/100-lzma.patch
@@ -0,0 +1,22 @@
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -7,6 +7,9 @@ all: mksquashfs unsquashfs
+ mksquashfs: mksquashfs.o read_fs.o sort.o
+ 	$(CC) mksquashfs.o read_fs.o sort.o -lz -o $@
+ 
++mksquashfs-lzma: mksquashfs.o read_fs.o sort.o
++	$(CXX) mksquashfs.o read_fs.o sort.o -L$(LZMAPATH) -llzma-old -o $@
++
+ mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h
+ 
+ read_fs.o: read_fs.c squashfs_fs.h read_fs.h global.h
+@@ -16,4 +19,9 @@ sort.o: sort.c squashfs_fs.h global.h so
+ unsquashfs: unsquashfs.o
+ 	$(CC) unsquashfs.o -lz -o $@
+ 
++unsquashfs-lzma: unsquashfs.o
++	$(CXX) unsquashfs.o -L$(LZMAPATH) -llzma-old -o $@
++
+ unsquashfs.o: unsquashfs.c squashfs_fs.h read_fs.h global.h
++
++clean:
diff --git a/tools/squashfs/patches/110-no_nonstatic_inline.patch b/tools/squashfs/patches/110-no_nonstatic_inline.patch
new file mode 100644
index 0000000000..8e288f336e
--- /dev/null
+++ b/tools/squashfs/patches/110-no_nonstatic_inline.patch
@@ -0,0 +1,11 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -1347,7 +1347,7 @@ struct inode_info *lookup_inode(struct s
+ }
+ 
+ 
+-inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir, struct inode_info *inode_info, void *data, struct dir_info *dir)
++static inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir, struct inode_info *inode_info, void *data, struct dir_info *dir)
+ {
+ 	if((dir->count % DIR_ENTRIES) == 0)
+ 		if((dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) * sizeof(struct dir_ent *))) == NULL)
diff --git a/tools/squashfs/patches/120-add-fixed-timestamp-support.patch b/tools/squashfs/patches/120-add-fixed-timestamp-support.patch
new file mode 100644
index 0000000000..e2f4bb2e04
--- /dev/null
+++ b/tools/squashfs/patches/120-add-fixed-timestamp-support.patch
@@ -0,0 +1,79 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -117,6 +117,9 @@ unsigned int inode_bytes = 0, inode_size
+ char *data_cache = NULL;
+ unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
+ 
++/* override all timestamps */
++time_t fixed_time = -1;
++
+ /* in memory directory data */
+ #define I_COUNT_SIZE		128
+ #define DIR_ENTRIES		32
+@@ -1554,6 +1557,11 @@ void dir_scan(squashfs_inode *inode, cha
+ 		perror(buffer);
+ 		return;
+ 	}
++
++	/* override timestamp of lstat if fixed_time is given */
++	if(fixed_time != -1)
++		inode_info->buf.st_mtime = fixed_time;
++
+ 	if(sorted)
+ 		sort_files_and_write(dir_info);
+ 	dir_scan2(inode, dir_info);
+@@ -1582,6 +1590,10 @@ struct dir_info *dir_scan1(char *pathnam
+ 			perror(buffer);
+ 			continue;
+ 		}
++
++		if(fixed_time != -1)
++			buf.st_mtime = fixed_time;
++
+ 		if(excluded(filename, &buf))
+ 			continue;
+ 
+@@ -1621,6 +1633,9 @@ int dir_scan2(squashfs_inode *inode, str
+ 		char *dir_name = dir_ent->name;
+ 		unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no;
+ 
++		if(fixed_time != -1)
++			buf->st_mtime = fixed_time;
++
+ 		if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
+ 			switch(buf->st_mode & S_IFMT) {
+ 				case S_IFREG:
+@@ -1898,6 +1913,16 @@ int main(int argc, char *argv[])
+ 					exit(1);
+ 				}
+ 			}
++		} else if(strcmp(argv[i], "-fixed-time") == 0) {
++			if(++i == argc) {
++				ERROR("%s: -fixed-time missing a timestamp\n", argv[0]);
++				exit(1);
++			}
++			fixed_time = strtoll(argv[i], &b, 10);
++			if(*b != '\0') {
++				ERROR("%s: -fixed-time has an invalid number\n", argv[0]);
++				exit(1);
++			}
+ 		} else if(strcmp(argv[i], "-noI") == 0 ||
+ 				strcmp(argv[i], "-noInodeCompression") == 0)
+ 			noI = TRUE;
+@@ -1967,6 +1992,7 @@ printOptions:
+ 			ERROR("-all-root\t\tmake all files owned by root\n");
+ 			ERROR("-force-uid uid\t\tset all file uids to uid\n");
+ 			ERROR("-force-gid gid\t\tset all file gids to gid\n");
++			ERROR("-fixed-time timestamp\tset all timestamps to timestamp\n");
+ 			ERROR("-le\t\t\tcreate a little endian filesystem\n");
+ 			ERROR("-be\t\t\tcreate a big endian filesystem\n");
+ 			ERROR("-nopad\t\t\tdo not pad filesystem to a multiple of 4K\n");
+@@ -2190,7 +2216,7 @@ printOptions:
+ 	sBlk.block_size = block_size;
+ 	sBlk.block_log = block_log;
+ 	sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, check_data, noF, no_fragments, always_use_fragments, duplicate_checking);
+-	sBlk.mkfs_time = time(NULL);
++	sBlk.mkfs_time = fixed_time != -1 ? fixed_time : time(NULL);
+ 
+ restore_filesystem:
+ 	write_fragment();
diff --git a/tools/squashfs4/Makefile b/tools/squashfs4/Makefile
new file mode 100644
index 0000000000..50b70fbe1c
--- /dev/null
+++ b/tools/squashfs4/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2009-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=squashfs4
+PKG_VERSION:=4.2
+
+PKG_SOURCE:=squashfs$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/squashfs
+PKG_MD5SUM:=1b7a781fb4cf8938842279bd3e8ee852
+PKG_CAT:=zcat
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/squashfs$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR)/squashfs-tools \
+		CC="$(HOSTCC)" \
+		XZ_SUPPORT=1 \
+		LZMA_XZ_SUPPORT=1 \
+		XATTR_SUPPORT= \
+		LZMA_LIB="$(STAGING_DIR_HOST)/lib/liblzma.a" \
+		EXTRA_CFLAGS="-I$(STAGING_DIR_HOST)/include" \
+		mksquashfs unsquashfs
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/squashfs-tools/mksquashfs $(STAGING_DIR_HOST)/bin/mksquashfs4
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/squashfs-tools/unsquashfs $(STAGING_DIR_HOST)/bin/unsquashfs4
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/mksquashfs4
+	rm -f $(STAGING_DIR_HOST)/bin/unsquashfs4
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/squashfs4/patches/100-portability.patch b/tools/squashfs4/patches/100-portability.patch
new file mode 100644
index 0000000000..ac1349c7a3
--- /dev/null
+++ b/tools/squashfs4/patches/100-portability.patch
@@ -0,0 +1,40 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -60,6 +60,10 @@
+ #include <sys/sysinfo.h>
+ #endif
+ 
++#ifndef FNM_EXTMATCH
++#define FNM_EXTMATCH 0
++#endif
++
+ #ifdef SQUASHFS_TRACE
+ #define TRACE(s, args...) \
+ 		do { \
+--- a/squashfs-tools/unsquashfs.h
++++ b/squashfs-tools/unsquashfs.h
+@@ -49,8 +49,14 @@
+ #define __BYTE_ORDER BYTE_ORDER
+ #define __BIG_ENDIAN BIG_ENDIAN
+ #define __LITTLE_ENDIAN LITTLE_ENDIAN
++#include <sys/sysctl.h>
+ #else
+ #include <endian.h>
++#include <sys/sysinfo.h>
++#endif
++
++#ifndef FNM_EXTMATCH
++#define FNM_EXTMATCH 0
+ #endif
+ 
+ #include "squashfs_fs.h"
+--- a/squashfs-tools/unsquashfs.c
++++ b/squashfs-tools/unsquashfs.c
+@@ -29,7 +29,6 @@
+ #include "compressor.h"
+ #include "xattr.h"
+ 
+-#include <sys/sysinfo.h>
+ #include <sys/types.h>
+ 
+ struct cache *fragment_cache, *data_cache;
diff --git a/tools/squashfs4/patches/110-allow_static_liblzma.patch b/tools/squashfs4/patches/110-allow_static_liblzma.patch
new file mode 100644
index 0000000000..9a3a744184
--- /dev/null
+++ b/tools/squashfs4/patches/110-allow_static_liblzma.patch
@@ -0,0 +1,30 @@
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -129,7 +129,6 @@ ifeq ($(LZMA_XZ_SUPPORT),1)
+ CFLAGS += -DLZMA_SUPPORT
+ MKSQUASHFS_OBJS += lzma_xz_wrapper.o
+ UNSQUASHFS_OBJS += lzma_xz_wrapper.o
+-LIBS += -llzma
+ COMPRESSORS += lzma
+ endif
+ 
+@@ -137,10 +136,18 @@ ifeq ($(XZ_SUPPORT),1)
+ CFLAGS += -DXZ_SUPPORT
+ MKSQUASHFS_OBJS += xz_wrapper.o
+ UNSQUASHFS_OBJS += xz_wrapper.o
+-LIBS += -llzma
+ COMPRESSORS += xz
+ endif
+ 
++ifneq ($(LZMA_XZ_SUPPORT)$(XZ_SUPPORT),)
++ifneq ($(LZMA_LIB),)
++MKSQUASHFS_OBJS += $(LZMA_LIB)
++UNSQUASHFS_OBJS += $(LZMA_LIB)
++else
++LIBS += -llzma
++endif
++endif
++
+ ifeq ($(LZO_SUPPORT),1)
+ CFLAGS += -DLZO_SUPPORT
+ ifdef LZO_DIR
diff --git a/tools/squashfs4/patches/120-cygwin_fixes.patch b/tools/squashfs4/patches/120-cygwin_fixes.patch
new file mode 100644
index 0000000000..fa1dfba42d
--- /dev/null
+++ b/tools/squashfs4/patches/120-cygwin_fixes.patch
@@ -0,0 +1,153 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -51,15 +51,22 @@
+ #include <sys/wait.h>
+ 
+ #ifndef linux
++#ifndef __CYGWIN__
+ #define __BYTE_ORDER BYTE_ORDER
+ #define __BIG_ENDIAN BIG_ENDIAN
+ #define __LITTLE_ENDIAN LITTLE_ENDIAN
+ #include <sys/sysctl.h>
++#endif /* __CYGWIN__ */
+ #else
+ #include <endian.h>
+ #include <sys/sysinfo.h>
+ #endif
+ 
++#ifdef __CYGWIN__
++#include <sys/termios.h>
++#define FNM_EXTMATCH  (1 << 5)
++#endif
++
+ #ifndef FNM_EXTMATCH
+ #define FNM_EXTMATCH 0
+ #endif
+@@ -844,6 +851,7 @@ void sigusr1_handler()
+ 
+ void sigwinch_handler()
+ {
++#ifndef __CYGWIN__
+ 	struct winsize winsize;
+ 
+ 	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
+@@ -853,6 +861,9 @@ void sigwinch_handler()
+ 		columns = 80;
+ 	} else
+ 		columns = winsize.ws_col;
++#else
++	columns = 80;
++#endif
+ }
+ 
+ 
+@@ -4066,6 +4077,9 @@ void initialise_threads(int readb_mbytes
+ 
+ 	signal(SIGUSR1, sigusr1_handler);
+ 
++#ifdef __CYGWIN__
++	processors = atoi(getenv("NUMBER_OF_PROCESSORS"));
++#else
+ 	if(processors == -1) {
+ #ifndef linux
+ 		int mib[2];
+@@ -4087,6 +4101,7 @@ void initialise_threads(int readb_mbytes
+ 		processors = sysconf(_SC_NPROCESSORS_ONLN);
+ #endif
+ 	}
++#endif /* __CYGWIN__ */
+ 
+ 	thread = malloc((2 + processors * 2) * sizeof(pthread_t));
+ 	if(thread == NULL)
+--- a/squashfs-tools/read_fs.c
++++ b/squashfs-tools/read_fs.c
+@@ -33,9 +33,11 @@
+ #include <sys/mman.h>
+ 
+ #ifndef linux
++#ifndef __CYGWIN__
+ #define __BYTE_ORDER BYTE_ORDER
+ #define __BIG_ENDIAN BIG_ENDIAN
+ #define __LITTLE_ENDIAN LITTLE_ENDIAN
++#endif
+ #else
+ #include <endian.h>
+ #endif
+--- a/squashfs-tools/swap.c
++++ b/squashfs-tools/swap.c
+@@ -20,9 +20,11 @@
+  */
+ 
+ #ifndef linux
++#ifndef __CYGWIN__
+ #define __BYTE_ORDER BYTE_ORDER
+ #define __BIG_ENDIAN BIG_ENDIAN
+ #define __LITTLE_ENDIAN LITTLE_ENDIAN
++#endif
+ #else
+ #include <endian.h>
+ #endif
+--- a/squashfs-tools/unsquashfs.c
++++ b/squashfs-tools/unsquashfs.c
+@@ -117,6 +117,7 @@ void update_progress_bar();
+ 
+ void sigwinch_handler()
+ {
++#ifndef __CYGWIN__
+ 	struct winsize winsize;
+ 
+ 	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
+@@ -126,6 +127,9 @@ void sigwinch_handler()
+ 		columns = 80;
+ 	} else
+ 		columns = winsize.ws_col;
++#else
++	columns = 80;
++#endif
+ }
+ 
+ 
+@@ -1807,7 +1811,9 @@ void initialise_threads(int fragment_buf
+ 	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
+ 		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
+ 			"\n");
+-
++#ifdef __CYGWIN__
++	processors = atoi(getenv("NUMBER_OF_PROCESSORS"));
++#else
+ 	if(processors == -1) {
+ #ifndef linux
+ 		int mib[2];
+@@ -1829,6 +1835,7 @@ void initialise_threads(int fragment_buf
+ 		processors = sysconf(_SC_NPROCESSORS_ONLN);
+ #endif
+ 	}
++#endif /* __CYGWIN__ */
+ 
+ 	thread = malloc((3 + processors) * sizeof(pthread_t));
+ 	if(thread == NULL)
+--- a/squashfs-tools/unsquashfs.h
++++ b/squashfs-tools/unsquashfs.h
+@@ -46,15 +46,22 @@
+ #include <sys/time.h>
+ 
+ #ifndef linux
++#ifndef __CYGWIN__
+ #define __BYTE_ORDER BYTE_ORDER
+ #define __BIG_ENDIAN BIG_ENDIAN
+ #define __LITTLE_ENDIAN LITTLE_ENDIAN
+ #include <sys/sysctl.h>
++#endif
+ #else
+ #include <endian.h>
+ #include <sys/sysinfo.h>
+ #endif
+ 
++#ifdef __CYGWIN__
++#include <sys/termios.h>
++#define FNM_EXTMATCH  (1 << 5)
++#endif
++
+ #ifndef FNM_EXTMATCH
+ #define FNM_EXTMATCH 0
+ #endif
diff --git a/tools/squashfs4/patches/150-freebsd_fixes.patch b/tools/squashfs4/patches/150-freebsd_fixes.patch
new file mode 100644
index 0000000000..44d40a7d1a
--- /dev/null
+++ b/tools/squashfs4/patches/150-freebsd_fixes.patch
@@ -0,0 +1,10 @@
+--- a/squashfs-tools/pseudo.c
++++ b/squashfs-tools/pseudo.c
+@@ -32,6 +32,7 @@
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
++#include <sys/stat.h>
+ 
+ #include "pseudo.h"
+ 
diff --git a/tools/squashfs4/patches/160-expose_lzma_xz_options.patch b/tools/squashfs4/patches/160-expose_lzma_xz_options.patch
new file mode 100644
index 0000000000..9e1c1fbb1e
--- /dev/null
+++ b/tools/squashfs4/patches/160-expose_lzma_xz_options.patch
@@ -0,0 +1,929 @@
+--- /dev/null
++++ b/squashfs-tools/lzma_xz_options.h
+@@ -0,0 +1,115 @@
++#ifndef LZMA_XZ_OPTIONS_H
++#define LZMA_XZ_OPTIONS_H
++/*
++ * Copyright (c) 2011
++ * Jonas Gorski <jonas.gorski@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * lzma_options.h
++ */
++
++#include <stdint.h>
++
++#ifndef linux
++#ifdef __FreeBSD__
++#include <machine/endian.h>
++#endif
++#define __BYTE_ORDER BYTE_ORDER
++#define __BIG_ENDIAN BIG_ENDIAN
++#define __LITTLE_ENDIAN LITTLE_ENDIAN
++#else
++#include <endian.h>
++#endif
++
++
++
++struct lzma_opts {
++	uint32_t dict_size;
++	uint32_t flags;
++#define LZMA_OPT_FLT_MASK	0xffff
++#define LZMA_OPT_PRE_OFF	16
++#define LZMA_OPT_PRE_MASK	(0xf << LZMA_OPT_PRE_OFF)
++#define LZMA_OPT_EXTREME	20	
++	uint16_t bit_opts;
++#define LZMA_OPT_LC_OFF		0
++#define LZMA_OPT_LC_MASK	(0x7 << LZMA_OPT_LC_OFF)
++#define LZMA_OPT_LP_OFF		3
++#define LZMA_OPT_LP_MASK	(0x7 << LZMA_OPT_LP_OFF)
++#define LZMA_OPT_PB_OFF		6
++#define LZMA_OPT_PB_MASK	(0x7 << LZMA_OPT_PB_OFF)
++	uint16_t fb;
++};
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++extern unsigned int inswap_le32(unsigned int);
++
++#define SQUASHFS_INSWAP_LZMA_COMP_OPTS(s) { \
++	(s)->flags = inswap_le32((s)->flags); \
++	(s)->bit_opts = inswap_le16((s)->bit_opts); \
++	(s)->fb = inswap_le16((s)->fb); \
++	(s)->dict_size = inswap_le32((s)->dict_size); \
++}
++#else
++#define SQUASHFS_INSWAP_LZMA_COMP_OPTS(s)
++#endif
++
++#define MEMLIMIT (32 * 1024 * 1024)
++
++#define LZMA_OPT_LC_MIN		0
++#define LZMA_OPT_LC_MAX		4
++#define LZMA_OPT_LC_DEFAULT	3
++
++#define LZMA_OPT_LP_MIN		0
++#define LZMA_OPT_LP_MAX		4
++#define LZMA_OPT_LP_DEFAULT	0
++
++#define LZMA_OPT_PB_MIN		0
++#define LZMA_OPT_PB_MAX		4
++#define LZMA_OPT_PB_DEFAULT	2
++
++#define LZMA_OPT_FB_MIN		5
++#define LZMA_OPT_FB_MAX		273
++#define LZMA_OPT_FB_DEFAULT	64
++
++enum {
++	LZMA_OPT_LZMA = 1,
++	LZMA_OPT_XZ
++};
++
++struct lzma_xz_options {
++	int preset;
++	int extreme;
++	int lc;
++	int lp;
++	int pb;
++	int fb;
++	int dict_size;
++	int flags;
++};
++
++struct lzma_xz_options *lzma_xz_get_options(void);
++
++int lzma_xz_options(char *argv[], int argc, int lzmaver);
++
++int lzma_xz_options_post(int block_size, int lzmaver);
++
++void *lzma_xz_dump_options(int block_size, int *size, int flags);
++
++int lzma_xz_extract_options(int block_size, void *buffer, int size, int lzmaver);
++
++void lzma_xz_usage(int lzmaver);
++
++#endif
+--- /dev/null
++++ b/squashfs-tools/lzma_xz_options.c
+@@ -0,0 +1,365 @@
++/*
++ * Copyright (c) 2011
++ * Jonas Gorski <jonas.gorski@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * lzma_options.c
++ * 
++ * Common options for LZMA1 and 2 compressors. Based on xz_wrapper.c
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++
++#include <lzma.h>
++
++#include "lzma_xz_options.h"
++
++static const char const *lzmaver_str[] = { "", "lzma", "xz" };
++
++static struct lzma_xz_options options = {
++	.flags		= 0,
++	.preset		= 6,
++	.extreme	= 0,
++	.lc		= LZMA_OPT_LC_DEFAULT,
++	.lp		= LZMA_OPT_LP_DEFAULT,
++	.pb		= LZMA_OPT_PB_DEFAULT,
++	.fb		= LZMA_OPT_FB_DEFAULT,
++	.dict_size	= 0,
++};
++
++static float lzma_dict_percent = 0;
++
++struct lzma_xz_options *lzma_xz_get_options(void)
++{
++	return &options;
++}
++
++
++int lzma_xz_options(char *argv[], int argc, int lzmaver)
++{
++	const char *comp_name = lzmaver_str[lzmaver];
++	
++	if(strcmp(argv[0], "-Xpreset") == 0) {
++		int preset;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xpreset missing preset\n", comp_name);
++			goto failed;
++		}
++		
++		preset = atoi(argv[1]);
++		
++		if (preset < 0 || preset > 9) {
++			fprintf(stderr, "%s: -Xpreset invalid value\n", comp_name);
++			goto failed;
++		}
++		options.preset = preset;
++		return 1;
++	} else if(strcmp(argv[0], "-Xe") == 0) {
++		options.extreme = 1;
++		return 0;
++	} else if(strcmp(argv[0], "-Xlc") == 0) {
++		int lc;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xlc missing lc\n", comp_name);
++			goto failed;
++		}
++		
++		lc = atoi(argv[1]);
++		
++		if (lc < LZMA_OPT_LC_MIN || lc > LZMA_OPT_LC_MAX) {
++			fprintf(stderr, "%s: -Xlc invalid value\n", comp_name);
++			goto failed;
++		}
++		options.lc = lc;
++		return 1;
++	} else if(strcmp(argv[0], "-Xlp") == 0) {
++		int lp;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xlp missing lp\n", comp_name);
++			goto failed;
++		}
++		
++		lp = atoi(argv[1]);
++		
++		if (lp < LZMA_OPT_LP_MIN || lp > LZMA_OPT_LP_MAX) {
++			fprintf(stderr, "%s: -Xlp invalid value\n", comp_name);
++			goto failed;
++		}
++		options.lp = lp;
++		return 1;
++	} else if(strcmp(argv[0], "-Xpb") == 0) {
++		int pb;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xpb missing pb\n", comp_name);
++			goto failed;
++		}
++		
++		pb = atoi(argv[1]);
++		
++		if (pb < LZMA_OPT_PB_MIN || pb > LZMA_OPT_PB_MAX) {
++			fprintf(stderr, "%s: -Xbp invalid value\n", comp_name);
++			goto failed;
++		}
++		options.pb = pb;
++		return 1;	
++	} else if(strcmp(argv[0], "-Xfb") == 0) {
++		int fb;
++		
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xfb missing fb\n", comp_name);
++			goto failed;
++		}
++		
++		fb = atoi(argv[1]);
++		
++		if (fb < LZMA_OPT_FB_MIN || fb > LZMA_OPT_FB_MAX) {
++			fprintf(stderr, "%s: -Xfb invalid value\n", comp_name);
++			goto failed;
++		}
++		options.fb = fb;
++		return 1;
++	} else if(strcmp(argv[0], "-Xdict-size") == 0) {
++		char *b;
++		float size;
++
++		if(argc < 2) {
++			fprintf(stderr, "%s: -Xdict-size missing dict-size\n", comp_name);
++			goto failed;
++		}
++
++		size = strtof(argv[1], &b);
++		if(*b == '%') {
++			if(size <= 0 || size > 100) {
++				fprintf(stderr, "%s: -Xdict-size percentage "
++					"should be 0 < dict-size <= 100\n", comp_name);
++				goto failed;
++			}
++
++			lzma_dict_percent = size;
++			options.dict_size = 0;
++		} else {
++			if((float) ((int) size) != size) {
++				fprintf(stderr, "%s: -Xdict-size can't be "
++					"fractional unless a percentage of the"
++					" block size\n", comp_name);
++				goto failed;
++			}
++
++			lzma_dict_percent = 0;
++			options.dict_size = (int) size;
++
++			if(*b == 'k' || *b == 'K')
++				options.dict_size *= 1024;
++			else if(*b == 'm' || *b == 'M')
++				options.dict_size *= 1024 * 1024;
++			else if(*b != '\0') {
++				fprintf(stderr, "%s: -Xdict-size invalid "
++					"dict-size\n", comp_name);
++				goto failed;
++			}
++		}
++
++		return 1;
++	}
++	
++	return -1;
++	
++failed:
++	return -2;
++
++}
++
++int lzma_xz_options_post(int block_size, int lzmaver)
++{
++	const char *comp_name = lzmaver_str[lzmaver];
++	/*
++	 * if -Xdict-size has been specified use this to compute the datablock
++	 * dictionary size
++	 */
++	if(options.dict_size || lzma_dict_percent) {
++		int dict_size_min = (lzmaver == 1 ? 4096 : 8192);
++		int n;
++
++		if(options.dict_size) {
++			if(options.dict_size > block_size) {
++				fprintf(stderr, "%s: -Xdict-size is larger than"
++				" block_size\n", comp_name);
++				goto failed;
++			}
++		} else
++			options.dict_size = block_size * lzma_dict_percent / 100;
++
++		if(options.dict_size < dict_size_min) {
++			fprintf(stderr, "%s: -Xdict-size should be %i bytes "
++				"or larger\n", comp_name, dict_size_min);
++			goto failed;
++		}
++
++		/*
++		 * dictionary_size must be storable in xz header as either
++		 * 2^n or as  2^n+2^(n+1)
++	 	*/
++		n = ffs(options.dict_size) - 1;
++		if(options.dict_size != (1 << n) &&
++				options.dict_size != ((1 << n) + (1 << (n + 1)))) {
++			fprintf(stderr, "%s: -Xdict-size is an unsupported "
++				"value, dict-size must be storable in %s "
++				"header\n", comp_name, comp_name);
++			fprintf(stderr, "as either 2^n or as 2^n+2^(n+1).  "
++				"Example dict-sizes are 75%%, 50%%, 37.5%%, "
++				"25%%,\n");
++			fprintf(stderr, "or 32K, 16K, 8K etc.\n");
++			goto failed;
++		}
++
++	} else
++		/* No -Xdict-size specified, use defaults */
++		options.dict_size = block_size;
++
++	return 0;
++
++failed:
++	return -1;
++}
++
++static struct lzma_opts lzma_comp_opts;
++
++void *lzma_xz_dump_options(int block_size, int *size, int flags)
++{
++	/* No need to store default options */
++	if (options.preset == 6 &&
++			options.extreme == 0 &&
++			options.lc == LZMA_OPT_LC_DEFAULT &&
++			options.lp == LZMA_OPT_LC_DEFAULT &&
++			options.pb == LZMA_OPT_PB_DEFAULT &&
++			options.fb == 0 &&
++			options.dict_size == block_size &&
++			flags == 0)
++		return NULL;
++	
++	*size = sizeof(struct lzma_opts);
++
++	lzma_comp_opts.flags |= flags;
++	
++	if (options.extreme)
++		lzma_comp_opts.flags |= LZMA_OPT_EXTREME;
++	
++	lzma_comp_opts.flags |= ((options.preset << LZMA_OPT_PRE_OFF) & LZMA_OPT_PRE_MASK);
++	
++	lzma_comp_opts.bit_opts = 
++			((options.lc << LZMA_OPT_LC_OFF) & LZMA_OPT_LC_MASK) |
++			((options.lp << LZMA_OPT_LP_OFF) & LZMA_OPT_LP_MASK) |
++			((options.pb << LZMA_OPT_PB_OFF) & LZMA_OPT_PB_MASK);
++	lzma_comp_opts.fb = options.fb;
++	lzma_comp_opts.dict_size = options.dict_size;
++	
++	SQUASHFS_INSWAP_LZMA_COMP_OPTS(&lzma_comp_opts);
++	
++	return &lzma_comp_opts;
++}
++
++int lzma_xz_extract_options(int block_size, void *buffer, int size, int lzmaver)
++{
++	if (size == 0) {
++		/* default options */
++		options.preset = 6;
++		options.extreme = 0;
++		options.lc = LZMA_OPT_LC_DEFAULT;
++		options.lp = LZMA_OPT_LC_DEFAULT;
++		options.pb = LZMA_OPT_PB_DEFAULT;
++		options.fb = LZMA_OPT_FB_DEFAULT;
++		options.dict_size = block_size;
++		options.flags = 0;
++	} else {
++		struct lzma_opts *comp_opts = buffer;
++		int n;
++		
++		if (size != sizeof(struct lzma_opts))
++			goto failed;
++		
++		SQUASHFS_INSWAP_LZMA_COMP_OPTS(comp_opts);
++		
++		options.flags = comp_opts->flags & LZMA_OPT_FLT_MASK;
++		options.preset  = (comp_opts->flags & LZMA_OPT_PRE_MASK) >> LZMA_OPT_PRE_OFF;
++		options.extreme = !!(comp_opts->flags & LZMA_OPT_EXTREME);
++
++		options.lc = (comp_opts->bit_opts & LZMA_OPT_LC_MASK) >> LZMA_OPT_LC_OFF;
++		options.lp = (comp_opts->bit_opts & LZMA_OPT_LP_MASK) >> LZMA_OPT_LP_OFF;
++		options.pb = (comp_opts->bit_opts & LZMA_OPT_PB_MASK) >> LZMA_OPT_PB_OFF;
++		options.fb = comp_opts->fb;
++		options.dict_size = comp_opts->dict_size;
++		
++		/* check that the LZMA bit options are in range */
++		if (options.lc < LZMA_OPT_LC_MIN || options.lc > LZMA_OPT_LC_MAX ||
++			options.lp < LZMA_OPT_LP_MIN || options.lp > LZMA_OPT_LP_MAX ||
++			options.pb < LZMA_OPT_PB_MIN || options.pb > LZMA_OPT_PB_MAX ||
++			options.fb < LZMA_OPT_FB_MIN || options.fb > LZMA_OPT_FB_MAX)
++			goto failed;
++
++		/*
++		 * check that the dictionary size seems correct - the dictionary
++		 * size should 2^n or 2^n+2^(n+1)
++		 */
++		n = ffs(options.dict_size) - 1;
++		if(options.dict_size != (1 << n) &&
++				options.dict_size != ((1 << n) + (1 << (n + 1))))
++			goto failed;
++		
++	}
++	
++	return 0;
++
++failed:
++	fprintf(stderr, "%s: error reading stored compressor options from "
++		"filesystem!\n", lzmaver_str[lzmaver]);
++	return -1;	
++}
++
++void lzma_xz_usage(int lzmaver)
++{
++	fprintf(stderr, "\t  -Xpreset <preset>\n");
++	fprintf(stderr, "\t\tcompression preset (0-9, default 6)\n");
++	fprintf(stderr, "\t  -Xe\n");
++	fprintf(stderr, "\t\tTry to improve compression ratio by using more ");
++	fprintf(stderr, "CPU time.\n");
++	fprintf(stderr, "\t  -Xlc <lc>\n");
++	fprintf(stderr, "\t\tNumber of literal context bits (0-4, default 3)\n");
++	fprintf(stderr, "\t  -Xlp <lp>\n");
++	fprintf(stderr, "\t\tNumber of literal position bits (0-4, default 0)\n");
++	fprintf(stderr, "\t  -Xpb <pb>\n");
++	fprintf(stderr, "\t\tNumber of position bits (0-4, default 2)\n");
++	fprintf(stderr, "\t  -Xnice <nice>\n");
++	fprintf(stderr, "\t\tNice length of a match (5-273, default 64)\n");
++	fprintf(stderr, "\t  -Xdict-size <dict-size>\n");
++	fprintf(stderr, "\t\tUse <dict-size> as the %s dictionary size.  The",
++			lzmaver == LZMA_OPT_LZMA ? "LZMA" : "XZ");
++	fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
++	fprintf(stderr, " percentage of the block size, or as an\n\t\t");
++	fprintf(stderr, "absolute value.  The dictionary size must be less");
++	fprintf(stderr, " than or equal\n\t\tto the block size and %d bytes", 
++			lzmaver == LZMA_OPT_LZMA ? 4096 : 8192);
++	fprintf(stderr, " or larger.  It must also be\n\t\tstorable in the lzma");
++	fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
++	fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
++	fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
++	
++}
+--- a/squashfs-tools/lzma_xz_wrapper.c
++++ b/squashfs-tools/lzma_xz_wrapper.c
+@@ -27,6 +27,7 @@
+ 
+ #include "squashfs_fs.h"
+ #include "compressor.h"
++#include "lzma_xz_options.h"
+ 
+ #define LZMA_PROPS_SIZE 5
+ #define LZMA_UNCOMP_SIZE 8
+@@ -38,13 +39,27 @@
+ static int lzma_compress(void *dummy, void *dest, void *src,  int size,
+ 	int block_size, int *error)
+ {
++	uint32_t preset;
+ 	unsigned char *d = (unsigned char *) dest;
++	struct lzma_xz_options *opts = lzma_xz_get_options();
++
+ 	lzma_options_lzma opt;
+ 	lzma_stream strm = LZMA_STREAM_INIT;
+ 	int res;
+ 
+-	lzma_lzma_preset(&opt, LZMA_OPTIONS);
+-	opt.dict_size = block_size;
++	preset = opts->preset;
++
++	if (opts->extreme)
++		preset |= LZMA_PRESET_EXTREME;
++
++	lzma_lzma_preset(&opt, opts->preset);
++	opt.lc = opts->lc;
++	opt.lp = opts->lp;
++	opt.pb = opts->pb;
++	if (opts->fb)
++		opt.nice_len = opts->fb;
++
++	opt.dict_size = opts->dict_size;
+ 
+ 	res = lzma_alone_encoder(&strm, &opt);
+ 	if(res != LZMA_OK) {
+@@ -143,13 +158,45 @@ failed:
+ 	return -1;
+ }
+ 
++static int lzma_options(char *argv[], int argc)
++{
++	return lzma_xz_options(argv, argc, LZMA_OPT_LZMA);
++}
++
++
++static int lzma_options_post(int block_size)
++{
++	return lzma_xz_options_post(block_size, LZMA_OPT_LZMA);
++}
++
++
++static void *lzma_dump_options(int block_size, int *size)
++{
++	return lzma_xz_dump_options(block_size, size, 0);
++}
++
++
++static int lzma_extract_options(int block_size, void *buffer, int size)
++{
++	return lzma_xz_extract_options(block_size, buffer, size, LZMA_OPT_LZMA);
++}
++
++
++void lzma_usage()
++{
++	lzma_xz_usage(LZMA_OPT_LZMA);
++}
++
+ 
+ struct compressor lzma_comp_ops = {
+ 	.init = NULL,
+ 	.compress = lzma_compress,
+ 	.uncompress = lzma_uncompress,
+-	.options = NULL,
+-	.usage = NULL,
++	.options = lzma_options,
++	.options_post = lzma_options_post,
++	.dump_options = lzma_dump_options,
++	.extract_options = lzma_extract_options,
++	.usage = lzma_usage,
+ 	.id = LZMA_COMPRESSION,
+ 	.name = "lzma",
+ 	.supported = 1
+--- a/squashfs-tools/xz_wrapper.h
++++ b/squashfs-tools/xz_wrapper.h
+@@ -24,25 +24,6 @@
+  *
+  */
+ 
+-#ifndef linux
+-#define __BYTE_ORDER BYTE_ORDER
+-#define __BIG_ENDIAN BIG_ENDIAN
+-#define __LITTLE_ENDIAN LITTLE_ENDIAN
+-#else
+-#include <endian.h>
+-#endif
+-
+-#if __BYTE_ORDER == __BIG_ENDIAN
+-extern unsigned int inswap_le32(unsigned int);
+-
+-#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
+-	(s)->dictionary_size = inswap_le32((s)->dictionary_size); \
+-	(s)->flags = inswap_le32((s)->flags); \
+-}
+-#else
+-#define SQUASHFS_INSWAP_COMP_OPTS(s)
+-#endif
+-
+ #define MEMLIMIT (32 * 1024 * 1024)
+ 
+ struct bcj {
+--- a/squashfs-tools/xz_wrapper.c
++++ b/squashfs-tools/xz_wrapper.c
+@@ -30,6 +30,7 @@
+ #include "squashfs_fs.h"
+ #include "xz_wrapper.h"
+ #include "compressor.h"
++#include "lzma_xz_options.h"
+ 
+ static struct bcj bcj[] = {
+ 	{ "x86", LZMA_FILTER_X86, 0 },
+@@ -41,22 +42,18 @@ static struct bcj bcj[] = {
+ 	{ NULL, LZMA_VLI_UNKNOWN, 0 }
+ };
+ 
+-static struct comp_opts comp_opts;
+-
+ static int filter_count = 1;
+-static int dictionary_size = 0;
+-static float dictionary_percent = 0;
+ 
+ 
+ static int xz_options(char *argv[], int argc)
+ {
+-	int i;
+-	char *name;
+-
+ 	if(strcmp(argv[0], "-Xbcj") == 0) {
++		int i;
++		char *name;
++
+ 		if(argc < 2) {
+ 			fprintf(stderr, "xz: -Xbcj missing filter\n");
+-			goto failed;
++			return -2;
+ 		}
+ 
+ 		name = argv[1];
+@@ -76,190 +73,50 @@ static int xz_options(char *argv[], int
+ 			}
+ 			if(bcj[i].name == NULL) {
+ 				fprintf(stderr, "xz: -Xbcj unrecognised "
+-					"filter\n");
+-				goto failed;
+-			}
+-		}
+-	
+-		return 1;
+-	} else if(strcmp(argv[0], "-Xdict-size") == 0) {
+-		char *b;
+-		float size;
+-
+-		if(argc < 2) {
+-			fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
+-			goto failed;
+-		}
+-
+-		size = strtof(argv[1], &b);
+-		if(*b == '%') {
+-			if(size <= 0 || size > 100) {
+-				fprintf(stderr, "xz: -Xdict-size percentage "
+-					"should be 0 < dict-size <= 100\n");
+-				goto failed;
+-			}
+-
+-			dictionary_percent = size;
+-			dictionary_size = 0;
+-		} else {
+-			if((float) ((int) size) != size) {
+-				fprintf(stderr, "xz: -Xdict-size can't be "
+-					"fractional unless a percentage of the"
+-					" block size\n");
+-				goto failed;
+-			}
+-
+-			dictionary_percent = 0;
+-			dictionary_size = (int) size;
+-
+-			if(*b == 'k' || *b == 'K')
+-				dictionary_size *= 1024;
+-			else if(*b == 'm' || *b == 'M')
+-				dictionary_size *= 1024 * 1024;
+-			else if(*b != '\0') {
+-				fprintf(stderr, "xz: -Xdict-size invalid "
+-					"dict-size\n");
+-				goto failed;
++						"filter\n");
++				return -2;
+ 			}
+ 		}
+-
+ 		return 1;
++	} else {
++		return lzma_xz_options(argv, argc, LZMA_OPT_XZ);
+ 	}
+-
+-	return -1;
+-	
+-failed:
+-	return -2;
+ }
+ 
+ 
+ static int xz_options_post(int block_size)
+ {
+-	/*
+-	 * if -Xdict-size has been specified use this to compute the datablock
+-	 * dictionary size
+-	 */
+-	if(dictionary_size || dictionary_percent) {
+-		int n;
+-
+-		if(dictionary_size) {
+-			if(dictionary_size > block_size) {
+-				fprintf(stderr, "xz: -Xdict-size is larger than"
+-				" block_size\n");
+-				goto failed;
+-			}
+-		} else
+-			dictionary_size = block_size * dictionary_percent / 100;
+-
+-		if(dictionary_size < 8192) {
+-			fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
+-				"or larger\n");
+-			goto failed;
+-		}
+-
+-		/*
+-		 * dictionary_size must be storable in xz header as either
+-		 * 2^n or as  2^n+2^(n+1)
+-	 	*/
+-		n = ffs(dictionary_size) - 1;
+-		if(dictionary_size != (1 << n) && 
+-				dictionary_size != ((1 << n) + (1 << (n + 1)))) {
+-			fprintf(stderr, "xz: -Xdict-size is an unsupported "
+-				"value, dict-size must be storable in xz "
+-				"header\n");
+-			fprintf(stderr, "as either 2^n or as 2^n+2^(n+1).  "
+-				"Example dict-sizes are 75%%, 50%%, 37.5%%, "
+-				"25%%,\n");
+-			fprintf(stderr, "or 32K, 16K, 8K etc.\n");
+-			goto failed;
+-		}
+-
+-	} else
+-		/* No -Xdict-size specified, use defaults */
+-		dictionary_size = block_size;
+-
+-	return 0;
+-
+-failed:
+-	return -1;
++	return lzma_xz_options_post(block_size, LZMA_OPT_XZ);
+ }
+ 
+ 
+ static void *xz_dump_options(int block_size, int *size)
+ {
+-	int flags = 0, i;
+-
+-	/*
+-	 * don't store compressor specific options in file system if the
+-	 * default options are being used - no compressor options in the
+-	 * file system means the default options are always assumed
+-	 *
+-	 * Defaults are:
+-	 *  metadata dictionary size: SQUASHFS_METADATA_SIZE
+-	 *  datablock dictionary size: block_size
+-	 *  1 filter
+-	 */
+-	if(dictionary_size == block_size && filter_count == 1)
+-		return NULL;
++	int i, flags = 0;
+ 
+ 	for(i = 0; bcj[i].name; i++)
+ 		flags |= bcj[i].selected << i;
+ 
+-	comp_opts.dictionary_size = dictionary_size;
+-	comp_opts.flags = flags;
+-
+-	SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
+-
+-	*size = sizeof(comp_opts);
+-	return &comp_opts;
++	return lzma_xz_dump_options(block_size, size, flags);
+ }
+ 
+ 
+ static int xz_extract_options(int block_size, void *buffer, int size)
+ {
+-	struct comp_opts *comp_opts = buffer;
+-	int flags, i, n;
+-
+-	if(size == 0) {
+-		/* set defaults */
+-		dictionary_size = block_size;
+-		flags = 0;
+-	} else {
+-		/* check passed comp opts struct is of the correct length */
+-		if(size != sizeof(struct comp_opts))
+-			goto failed;
+-					 
+-		SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
+-
+-		dictionary_size = comp_opts->dictionary_size;
+-		flags = comp_opts->flags;
+-
+-		/*
+-		 * check that the dictionary size seems correct - the dictionary
+-		 * size should 2^n or 2^n+2^(n+1)
+-		 */
+-		n = ffs(dictionary_size) - 1;
+-		if(dictionary_size != (1 << n) && 
+-				dictionary_size != ((1 << n) + (1 << (n + 1))))
+-			goto failed;
+-	}
++	int ret = lzma_xz_extract_options(block_size, buffer, size, LZMA_OPT_XZ);
+ 
+-	filter_count = 1;
+-	for(i = 0; bcj[i].name; i++) {
+-		if((flags >> i) & 1) {
+-			bcj[i].selected = 1;
+-			filter_count ++;
+-		} else
+-			bcj[i].selected = 0;
++	if (!ret) {
++		int i;
++		struct lzma_xz_options *opts = lzma_xz_get_options();
++		for(i = 0; bcj[i].name; i++) {
++			if((opts->flags >> i) & 1) {
++				bcj[i].selected = 1;
++				filter_count ++;
++			} else
++				bcj[i].selected = 0;
++		}
+ 	}
+-
+-	return 0;
+-
+-failed:
+-	fprintf(stderr, "xz: error reading stored compressor options from "
+-		"filesystem!\n");
+-
+-	return -1;
++	return ret;
+ }
+ 
+ 
+@@ -268,6 +125,7 @@ static int xz_init(void **strm, int bloc
+ 	int i, j, filters = datablock ? filter_count : 1;
+ 	struct filter *filter = malloc(filters * sizeof(struct filter));
+ 	struct xz_stream *stream;
++	struct lzma_xz_options *opts = lzma_xz_get_options();
+ 
+ 	if(filter == NULL)
+ 		goto failed;
+@@ -281,7 +139,7 @@ static int xz_init(void **strm, int bloc
+ 
+ 	memset(filter, 0, filters * sizeof(struct filter));
+ 
+-	stream->dictionary_size = datablock ? dictionary_size :
++	stream->dictionary_size = datablock ? opts->dict_size :
+ 		SQUASHFS_METADATA_SIZE;
+ 
+ 	filter[0].filter[0].id = LZMA_FILTER_LZMA2;
+@@ -323,14 +181,25 @@ static int xz_compress(void *strm, void
+         lzma_ret res = 0;
+ 	struct xz_stream *stream = strm;
+ 	struct filter *selected = NULL;
++	struct lzma_xz_options *opts = lzma_xz_get_options();
+ 
+ 	stream->filter[0].buffer = dest;
+ 
+ 	for(i = 0; i < stream->filters; i++) {
++		uint32_t preset = opts->preset;
+ 		struct filter *filter = &stream->filter[i];
+ 
+-        	if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
+-                	goto failed;
++		if (opts->extreme)
++			preset |= LZMA_PRESET_EXTREME;
++
++        if(lzma_lzma_preset(&stream->opt, preset))
++               	goto failed;
++
++        stream->opt.lc = opts->lc;
++    	stream->opt.lp = opts->lp;
++    	stream->opt.pb = opts->pb;
++    	if (opts->fb)
++    		stream->opt.nice_len = opts->fb;
+ 
+ 		stream->opt.dict_size = stream->dictionary_size;
+ 
+@@ -384,22 +253,13 @@ static int xz_uncompress(void *dest, voi
+ 
+ void xz_usage()
+ {
++	lzma_xz_usage(LZMA_OPT_XZ);
+ 	fprintf(stderr, "\t  -Xbcj filter1,filter2,...,filterN\n");
+ 	fprintf(stderr, "\t\tCompress using filter1,filter2,...,filterN in");
+ 	fprintf(stderr, " turn\n\t\t(in addition to no filter), and choose");
+ 	fprintf(stderr, " the best compression.\n");
+ 	fprintf(stderr, "\t\tAvailable filters: x86, arm, armthumb,");
+ 	fprintf(stderr, " powerpc, sparc, ia64\n");
+-	fprintf(stderr, "\t  -Xdict-size <dict-size>\n");
+-	fprintf(stderr, "\t\tUse <dict-size> as the XZ dictionary size.  The");
+-	fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
+-	fprintf(stderr, " percentage of the block size, or as an\n\t\t");
+-	fprintf(stderr, "absolute value.  The dictionary size must be less");
+-	fprintf(stderr, " than or equal\n\t\tto the block size and 8192 bytes");
+-	fprintf(stderr, " or larger.  It must also be\n\t\tstorable in the xz");
+-	fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
+-	fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
+-	fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
+ }
+ 
+ 
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -140,6 +140,8 @@ COMPRESSORS += xz
+ endif
+ 
+ ifneq ($(LZMA_XZ_SUPPORT)$(XZ_SUPPORT),)
++MKSQUASHFS_OBJS += lzma_xz_options.o
++UNSQUASHFS_OBJS += lzma_xz_options.o
+ ifneq ($(LZMA_LIB),)
+ MKSQUASHFS_OBJS += $(LZMA_LIB)
+ UNSQUASHFS_OBJS += $(LZMA_LIB)
diff --git a/tools/squashfs4/patches/170-add_support_for_LZMA_MAGIC_to_unsqashfs.patch b/tools/squashfs4/patches/170-add_support_for_LZMA_MAGIC_to_unsqashfs.patch
new file mode 100644
index 0000000000..ad69b190ea
--- /dev/null
+++ b/tools/squashfs4/patches/170-add_support_for_LZMA_MAGIC_to_unsqashfs.patch
@@ -0,0 +1,72 @@
+--- a/squashfs-tools/squashfs_fs.h
++++ b/squashfs-tools/squashfs_fs.h
+@@ -30,6 +30,13 @@
+ #define SQUASHFS_MAGIC_SWAP		0x68737173
+ #define SQUASHFS_START			0
+ 
++/*
++ * Squashfs + LZMA
++ */
++
++#define SQUASHFS_MAGIC_LZMA		0x71736873
++#define SQUASHFS_MAGIC_LZMA_SWAP	0x73687371
++
+ /* size of metadata (inode and directory) blocks */
+ #define SQUASHFS_METADATA_SIZE		8192
+ #define SQUASHFS_METADATA_LOG		13
+--- a/squashfs-tools/unsquashfs.c
++++ b/squashfs-tools/unsquashfs.c
+@@ -1463,10 +1463,12 @@ int read_super(char *source)
+ 	 */
+ 	read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
+ 		&sBlk_4);
+-	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
++	swap = (sBlk_4.s_magic != SQUASHFS_MAGIC &&
++		sBlk_4.s_magic != SQUASHFS_MAGIC_LZMA);
+ 	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
+ 
+-	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 &&
++	if((sBlk_4.s_magic == SQUASHFS_MAGIC || 
++	   sBlk_4.s_magic == SQUASHFS_MAGIC_LZMA) && sBlk_4.s_major == 4 &&
+ 			sBlk_4.s_minor == 0) {
+ 		s_ops.squashfs_opendir = squashfs_opendir_4;
+ 		s_ops.read_fragment = read_fragment_4;
+@@ -1479,7 +1481,11 @@ int read_super(char *source)
+ 		/*
+ 		 * Check the compression type
+ 		 */
+-		comp = lookup_compressor_id(sBlk.s.compression);
++		if (sBlk_4.s_magic == SQUASHFS_MAGIC_LZMA)
++			comp = lookup_compressor("lzma");
++		else
++			comp = lookup_compressor_id(sBlk.s.compression);
++
+ 		return TRUE;
+ 	}
+ 
+@@ -1494,8 +1500,10 @@ int read_super(char *source)
+ 	 * Check it is a SQUASHFS superblock
+ 	 */
+ 	swap = 0;
+-	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
+-		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
++	if(sBlk_3.s_magic != SQUASHFS_MAGIC && 
++			sBlk_3.s_magic != SQUASHFS_MAGIC_LZMA) {
++		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP || 
++				sBlk_3.s_magic == SQUASHFS_MAGIC_LZMA_SWAP) {
+ 			squashfs_super_block_3 sblk;
+ 			ERROR("Reading a different endian SQUASHFS filesystem "
+ 				"on %s\n", source);
+@@ -1573,7 +1581,11 @@ int read_super(char *source)
+ 	/*
+ 	 * 1.x, 2.x and 3.x filesystems use gzip compression.
+ 	 */
+-	comp = lookup_compressor("gzip");
++	if (sBlk.s.s_magic == SQUASHFS_MAGIC_LZMA)
++		comp = lookup_compressor("lzma");
++	else
++		comp = lookup_compressor("gzip");
++
+ 	return TRUE;
+ 
+ failed_mount:
diff --git a/tools/squashfs4/patches/180-openbsd_compat.patch b/tools/squashfs4/patches/180-openbsd_compat.patch
new file mode 100644
index 0000000000..b9c1b5925d
--- /dev/null
+++ b/tools/squashfs4/patches/180-openbsd_compat.patch
@@ -0,0 +1,24 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -32,6 +32,9 @@
+ #include <stdio.h>
+ #include <stddef.h>
+ #include <sys/time.h>
++#if defined(__OpenBSD__)
++#include <sys/param.h>
++#endif
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+--- a/squashfs-tools/unsquashfs.h
++++ b/squashfs-tools/unsquashfs.h
+@@ -25,6 +25,9 @@
+ #define TRUE 1
+ #define FALSE 0
+ #include <stdio.h>
++#if defined(__OpenBSD__)
++#include <sys/param.h>
++#endif
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <stdlib.h>
diff --git a/tools/squashfs4/patches/190-no_nonstatic_inline.patch b/tools/squashfs4/patches/190-no_nonstatic_inline.patch
new file mode 100644
index 0000000000..27ebc6a263
--- /dev/null
+++ b/tools/squashfs4/patches/190-no_nonstatic_inline.patch
@@ -0,0 +1,36 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -735,13 +735,13 @@ void cache_block_put(struct file_buffer
+ 			+ (((char *)A) - data_cache)))
+ 
+ 
+-inline void inc_progress_bar()
++static inline void inc_progress_bar()
+ {
+ 	cur_uncompressed ++;
+ }
+ 
+ 
+-inline void update_progress_bar()
++static inline void update_progress_bar()
+ {
+ 	pthread_mutex_lock(&progress_mutex);
+ 	pthread_cond_signal(&progress_wait);
+@@ -749,7 +749,7 @@ inline void update_progress_bar()
+ }
+ 
+ 
+-inline void waitforthread(int i)
++static inline void waitforthread(int i)
+ {
+ 	TRACE("Waiting for thread %d\n", i);
+ 	while(thread[i] != 0)
+@@ -3358,7 +3358,7 @@ struct inode_info *lookup_inode(struct s
+ }
+ 
+ 
+-inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir,
++static inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir,
+ 	struct inode_info *inode_info, struct dir_info *dir)
+ {
+ 	if((dir->count % DIR_ENTRIES) == 0) {
diff --git a/tools/squashfs4/patches/200-add-fixed-timestamp-option.patch b/tools/squashfs4/patches/200-add-fixed-timestamp-option.patch
new file mode 100644
index 0000000000..5cec51f7b7
--- /dev/null
+++ b/tools/squashfs4/patches/200-add-fixed-timestamp-option.patch
@@ -0,0 +1,82 @@
+--- a/squashfs-tools/mksquashfs.c
++++ b/squashfs-tools/mksquashfs.c
+@@ -175,6 +175,9 @@ unsigned int cache_bytes = 0, cache_size
+ /* inode lookup table */
+ squashfs_inode *inode_lookup_table = NULL;
+ 
++/* override all timestamps */
++time_t fixed_time = -1;
++
+ /* in memory directory data */
+ #define I_COUNT_SIZE		128
+ #define DIR_ENTRIES		32
+@@ -2452,6 +2455,8 @@ again:
+ restat:
+ 	fstat(file, &buf2);
+ 	close(file);
++	if (fixed_time != -1)
++		buf2.st_mtime = fixed_time;
+ 	if(read_size != buf2.st_size) {
+ 		memcpy(buf, &buf2, sizeof(struct stat));
+ 		file_buffer->error = 2;
+@@ -3612,7 +3617,7 @@ void dir_scan(squashfs_inode *inode, cha
+ 		buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
+ 		buf.st_uid = getuid();
+ 		buf.st_gid = getgid();
+-		buf.st_mtime = time(NULL);
++		buf.st_mtime = fixed_time != -1 ? fixed_time : time(NULL);
+ 		buf.st_dev = 0;
+ 		buf.st_ino = 0;
+ 		dir_ent->inode = lookup_inode(&buf);
+@@ -3623,6 +3628,8 @@ void dir_scan(squashfs_inode *inode, cha
+ 				pathname, strerror(errno));
+ 			return;
+ 		}
++		if(fixed_time != -1)
++			buf.st_mtime = fixed_time;
+ 		dir_ent->inode = lookup_inode(&buf);
+ 	}
+ 
+@@ -3677,6 +3684,8 @@ struct dir_info *dir_scan1(char *pathnam
+ 				filename, strerror(errno));
+ 			continue;
+ 		}
++		if(fixed_time != -1)
++			buf.st_mtime = fixed_time;
+ 
+ 		if((buf.st_mode & S_IFMT) != S_IFREG &&
+ 			(buf.st_mode & S_IFMT) != S_IFDIR &&
+@@ -3795,7 +3804,7 @@ struct dir_info *dir_scan2(struct dir_in
+ 		buf.st_gid = pseudo_ent->dev->gid;
+ 		buf.st_rdev = makedev(pseudo_ent->dev->major,
+ 			pseudo_ent->dev->minor);
+-		buf.st_mtime = time(NULL);
++		buf.st_mtime = fixed_time != -1 ? fixed_time : time(NULL);
+ 		buf.st_ino = pseudo_ino ++;
+ 
+ 		if(pseudo_ent->dev->type == 'f') {
+@@ -4674,6 +4683,15 @@ int main(int argc, char *argv[])
+ 			progress = FALSE;
+ 		else if(strcmp(argv[i], "-no-exports") == 0)
+ 			exportable = FALSE;
++		else if(strcmp(argv[i], "-fixed-time") == 0) {
++			if((++i == argc) || (fixed_time =
++					strtoll(argv[i], &b, 10), *b != '\0')) {
++				ERROR("%s: -fixed-time missing or invalid "
++					"timestamp\n", argv[0]);
++
++				exit(1);
++			}
++		}
+ 		else if(strcmp(argv[i], "-processors") == 0) {
+ 			if((++i == argc) || (processors =
+ 					strtol(argv[i], &b, 10), *b != '\0')) {
+@@ -5314,7 +5332,7 @@ printOptions:
+ 	sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
+ 		always_use_fragments, duplicate_checking, exportable,
+ 		no_xattrs, comp_opts);
+-	sBlk.mkfs_time = time(NULL);
++	sBlk.mkfs_time = fixed_time != -1 ? fixed_time : time(NULL);
+ 
+ restore_filesystem:
+ 	if(progress && estimated_uncompressed) {
diff --git a/tools/sstrip/Makefile b/tools/sstrip/Makefile
new file mode 100644
index 0000000000..180bd1743e
--- /dev/null
+++ b/tools/sstrip/Makefile
@@ -0,0 +1,25 @@
+# 
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=sstrip
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(HOSTCC) $(HOST_CFLAGS) -include endian.h -o $(HOST_BUILD_DIR)/sstrip src/sstrip.c
+endef
+
+define Host/Install
+	$(CP) $(HOST_BUILD_DIR)/sstrip $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/sstrip
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/sstrip/src/sstrip.c b/tools/sstrip/src/sstrip.c
new file mode 100644
index 0000000000..0508aaac81
--- /dev/null
+++ b/tools/sstrip/src/sstrip.c
@@ -0,0 +1,465 @@
+/* http://www.muppetlabs.com/~breadbox/software/elfkickers.html */
+
+/* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
+ * General Public License. No warranty. See COPYING for details.
+ *
+ * Aug 23, 2004 Hacked by Manuel Novoa III <mjn3@codepoet.org> to
+ * handle targets of different endianness and/or elf class, making
+ * it more useful in a cross-devel environment.
+ */
+
+/* ============== original README ===================
+ *
+ * sstrip is a small utility that removes the contents at the end of an
+ * ELF file that are not part of the program's memory image.
+ * 
+ * Most ELF executables are built with both a program header table and a
+ * section header table. However, only the former is required in order
+ * for the OS to load, link and execute a program. sstrip attempts to
+ * extract the ELF header, the program header table, and its contents,
+ * leaving everything else in the bit bucket. It can only remove parts of
+ * the file that occur at the end, after the parts to be saved. However,
+ * this almost always includes the section header table, and occasionally
+ * a few random sections that are not used when running a program.
+ * 
+ * It should be noted that the GNU bfd library is (understandably)
+ * dependent on the section header table as an index to the file's
+ * contents. Thus, an executable file that has no section header table
+ * cannot be used with gdb, objdump, or any other program based upon the
+ * bfd library, at all. In fact, the program will not even recognize the
+ * file as a valid executable. (This limitation is noted in the source
+ * code comments for bfd, and is marked "FIXME", so this may change at
+ * some future date. However, I would imagine that it is a pretty
+ * low-priority item, as executables without a section header table are
+ * rare in the extreme.) This probably also explains why strip doesn't
+ * offer the option to do this.
+ * 
+ * Shared library files may also have their section header table removed.
+ * Such a library will still function; however, it will no longer be
+ * possible for a compiler to link a new program against it.
+ * 
+ * As an added bonus, sstrip also tries to removes trailing zero bytes
+ * from the end of the file. (This normally cannot be done with an
+ * executable that has a section header table.)
+ * 
+ * sstrip is a very simplistic program. It depends upon the common
+ * practice of putting the parts of the file that contribute to the
+ * memory image at the front, and the remaining material at the end. This
+ * permits it to discard the latter material without affecting file
+ * offsets and memory addresses in what remains. Of course, the ELF
+ * standard permits files to be organized in almost any order, so if a
+ * pathological linker decided to put its section headers at the top,
+ * sstrip would be useless on such executables.
+ */
+
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<unistd.h>
+#include	<fcntl.h>
+#include	<elf.h>
+
+#ifndef TRUE
+#define	TRUE		1
+#define	FALSE		0
+#endif
+
+/* The name of the program.
+ */
+static char const	*progname;
+
+/* The name of the current file.
+ */
+static char const	*filename;
+
+
+/* A simple error-handling function. FALSE is always returned for the
+ * convenience of the caller.
+ */
+static int err(char const *errmsg)
+{
+	fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
+	return FALSE;
+}
+
+/* A flag to signal the need for endian reversal.
+ */
+static int do_reverse_endian;
+
+/* Get a value from the elf header, compensating for endianness.
+ */
+#define EGET(X) \
+	(__extension__ ({ \
+		uint64_t __res; \
+		if (!do_reverse_endian) { \
+			__res = (X); \
+		} else if (sizeof(X) == 1) { \
+			__res = (X); \
+		} else if (sizeof(X) == 2) { \
+			__res = bswap_16((X)); \
+		} else if (sizeof(X) == 4) { \
+			__res = bswap_32((X)); \
+		} else if (sizeof(X) == 8) { \
+			__res = bswap_64((X)); \
+		} else { \
+			fprintf(stderr, "%s: %s: EGET failed for size %d\n", \
+					progname, filename, sizeof(X)); \
+			exit(EXIT_FAILURE); \
+		} \
+		__res; \
+	}))
+
+/* Set a value 'Y' in the elf header to 'X', compensating for endianness.
+ */
+#define ESET(Y,X) \
+		do if (!do_reverse_endian) { \
+			Y = (X); \
+		} else if (sizeof(Y) == 1) { \
+			Y = (X); \
+		} else if (sizeof(Y) == 2) { \
+			Y = bswap_16((uint16_t)(X)); \
+		} else if (sizeof(Y) == 4) { \
+			Y = bswap_32((uint32_t)(X)); \
+		} else if (sizeof(Y) == 8) { \
+			Y = bswap_64((uint64_t)(X)); \
+		} else { \
+			fprintf(stderr, "%s: %s: ESET failed for size %d\n", \
+					progname, filename, sizeof(Y)); \
+			exit(EXIT_FAILURE); \
+		} while (0)
+
+
+/* A macro for I/O errors: The given error message is used only when
+ * errno is not set.
+ */
+#define	ferr(msg)	(err(errno ? strerror(errno) : (msg)))
+
+
+
+#define HEADER_FUNCTIONS(CLASS) \
+ \
+/* readelfheader() reads the ELF header into our global variable, and \
+ * checks to make sure that this is in fact a file that we should be \
+ * munging. \
+ */ \
+static int readelfheader ## CLASS (int fd, Elf ## CLASS ## _Ehdr *ehdr) \
+{ \
+	 if (read(fd, ((char *)ehdr)+EI_NIDENT, sizeof(*ehdr) - EI_NIDENT) \
+		!= sizeof(*ehdr) - EI_NIDENT) \
+		return ferr("missing or incomplete ELF header."); \
+ \
+	/* Verify the sizes of the ELF header and the program segment \
+	 * header table entries. \
+	 */ \
+	if (EGET(ehdr->e_ehsize) != sizeof(Elf ## CLASS ## _Ehdr)) \
+		return err("unrecognized ELF header size."); \
+	if (EGET(ehdr->e_phentsize) != sizeof(Elf ## CLASS ## _Phdr)) \
+		return err("unrecognized program segment header size."); \
+ \
+	/* Finally, check the file type. \
+	 */ \
+	if (EGET(ehdr->e_type) != ET_EXEC && EGET(ehdr->e_type) != ET_DYN) \
+		return err("not an executable or shared-object library."); \
+ \
+	return TRUE; \
+} \
+ \
+/* readphdrtable() loads the program segment header table into memory. \
+ */ \
+static int readphdrtable ## CLASS (int fd, Elf ## CLASS ## _Ehdr const *ehdr, \
+								   Elf ## CLASS ## _Phdr **phdrs) \
+{ \
+	size_t	size; \
+ \
+	if (!EGET(ehdr->e_phoff) || !EGET(ehdr->e_phnum) \
+)		return err("ELF file has no program header table."); \
+ \
+	size = EGET(ehdr->e_phnum) * sizeof **phdrs; \
+	if (!(*phdrs = malloc(size))) \
+		return err("Out of memory!"); \
+ \
+	errno = 0; \
+	if (read(fd, *phdrs, size) != (ssize_t)size) \
+		return ferr("missing or incomplete program segment header table."); \
+ \
+	return TRUE; \
+} \
+ \
+/* getmemorysize() determines the offset of the last byte of the file \
+ * that is referenced by an entry in the program segment header table. \
+ * (Anything in the file after that point is not used when the program \
+ * is executing, and thus can be safely discarded.) \
+ */ \
+static int getmemorysize ## CLASS (Elf ## CLASS ## _Ehdr const *ehdr, \
+								   Elf ## CLASS ## _Phdr const *phdrs, \
+						 unsigned long *newsize) \
+{ \
+	Elf ## CLASS ## _Phdr const   *phdr; \
+	unsigned long	size, n; \
+	int			i; \
+ \
+	/* Start by setting the size to include the ELF header and the \
+	 * complete program segment header table. \
+	 */ \
+	size = EGET(ehdr->e_phoff) + EGET(ehdr->e_phnum) * sizeof *phdrs; \
+	if (size < sizeof *ehdr) \
+		size = sizeof *ehdr; \
+ \
+	/* Then keep extending the size to include whatever data the \
+	 * program segment header table references. \
+	 */ \
+	for (i = 0, phdr = phdrs ; i < EGET(ehdr->e_phnum) ; ++i, ++phdr) { \
+		if (EGET(phdr->p_type) != PT_NULL) { \
+			n = EGET(phdr->p_offset) + EGET(phdr->p_filesz); \
+			if (n > size) \
+				size = n; \
+		} \
+	} \
+ \
+	*newsize = size; \
+	return TRUE; \
+} \
+ \
+/* modifyheaders() removes references to the section header table if \
+ * it was stripped, and reduces program header table entries that \
+ * included truncated bytes at the end of the file. \
+ */ \
+static int modifyheaders ## CLASS (Elf ## CLASS ## _Ehdr *ehdr, \
+								   Elf ## CLASS ## _Phdr *phdrs, \
+								   unsigned long newsize) \
+{ \
+	Elf ## CLASS ## _Phdr *phdr; \
+	int		i; \
+ \
+	/* If the section header table is gone, then remove all references \
+	 * to it in the ELF header. \
+	 */ \
+	if (EGET(ehdr->e_shoff) >= newsize) { \
+		ESET(ehdr->e_shoff,0); \
+		ESET(ehdr->e_shnum,0); \
+		ESET(ehdr->e_shentsize,0); \
+		ESET(ehdr->e_shstrndx,0); \
+	} \
+ \
+	/* The program adjusts the file size of any segment that was \
+	 * truncated. The case of a segment being completely stripped out \
+	 * is handled separately. \
+	 */ \
+	for (i = 0, phdr = phdrs ; i < EGET(ehdr->e_phnum) ; ++i, ++phdr) { \
+		if (EGET(phdr->p_offset) >= newsize) { \
+			ESET(phdr->p_offset,newsize); \
+			ESET(phdr->p_filesz,0); \
+		} else if (EGET(phdr->p_offset) + EGET(phdr->p_filesz) > newsize) { \
+			ESET(phdr->p_filesz, newsize - EGET(phdr->p_offset)); \
+		} \
+	} \
+ \
+	return TRUE; \
+} \
+ \
+/* commitchanges() writes the new headers back to the original file \
+ * and sets the file to its new size. \
+ */ \
+static int commitchanges ## CLASS (int fd, Elf ## CLASS ## _Ehdr const *ehdr, \
+								   Elf ## CLASS ## _Phdr *phdrs, \
+								   unsigned long newsize) \
+{ \
+	size_t	n; \
+ \
+	/* Save the changes to the ELF header, if any. \
+	 */ \
+	if (lseek(fd, 0, SEEK_SET)) \
+		return ferr("could not rewind file"); \
+	errno = 0; \
+	if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) \
+		return err("could not modify file"); \
+ \
+	/* Save the changes to the program segment header table, if any. \
+	 */ \
+	if (lseek(fd, EGET(ehdr->e_phoff), SEEK_SET) == (off_t)-1) { \
+		err("could not seek in file."); \
+		goto warning; \
+	} \
+	n = EGET(ehdr->e_phnum) * sizeof *phdrs; \
+	if (write(fd, phdrs, n) != (ssize_t)n) { \
+		err("could not write to file"); \
+		goto warning; \
+	} \
+ \
+	/* Eleventh-hour sanity check: don't truncate before the end of \
+	 * the program segment header table. \
+	 */ \
+	if (newsize < EGET(ehdr->e_phoff) + n) \
+		newsize = EGET(ehdr->e_phoff) + n; \
+ \
+	/* Chop off the end of the file. \
+	 */ \
+	if (ftruncate(fd, newsize)) { \
+		err("could not resize file"); \
+		goto warning; \
+	} \
+ \
+	return TRUE; \
+ \
+ warning: \
+	return err("ELF file may have been corrupted!"); \
+}
+
+
+/* First elements of Elf32_Ehdr and Elf64_Ehdr are common.
+ */
+static int readelfheaderident(int fd, Elf32_Ehdr *ehdr)
+{
+	errno = 0;
+	if (read(fd, ehdr, EI_NIDENT) != EI_NIDENT)
+		return ferr("missing or incomplete ELF header.");
+
+	/* Check the ELF signature.
+	 */
+	if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+		  ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+		  ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+		  ehdr->e_ident[EI_MAG3] == ELFMAG3))
+	{
+		err("missing ELF signature.");
+		return -1;
+	}
+
+	/* Compare the file's class and endianness with the program's.
+	 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
+		do_reverse_endian = 0;
+	} else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
+/* 		fprintf(stderr, "ELF file has different endianness.\n"); */
+		do_reverse_endian = 1;
+	}
+#elif __BYTE_ORDER == __BIG_ENDIAN
+	if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
+/* 		fprintf(stderr, "ELF file has different endianness.\n"); */
+		do_reverse_endian = 1;
+	} else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
+		do_reverse_endian = 0;
+	}
+#else
+#error unkown endianness
+#endif
+	else {
+		err("Unsupported endianness");
+		return -1;
+	}
+
+	/* Check the target architecture.
+	 */
+/*	 if (EGET(ehdr->e_machine) != ELF_ARCH) { */
+/* 		/\* return err("ELF file created for different architecture."); *\/ */
+/* 		fprintf(stderr, "ELF file created for different architecture.\n"); */
+/* 	} */
+	return ehdr->e_ident[EI_CLASS];
+}
+
+
+HEADER_FUNCTIONS(32)
+
+HEADER_FUNCTIONS(64)
+
+/* truncatezeros() examines the bytes at the end of the file's
+ * size-to-be, and reduces the size to exclude any trailing zero
+ * bytes.
+ */
+static int truncatezeros(int fd, unsigned long *newsize)
+{
+	unsigned char	contents[1024];
+	unsigned long	size, n;
+
+	size = *newsize;
+	do {
+		n = sizeof contents;
+		if (n > size)
+			n = size;
+		if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
+			return ferr("cannot seek in file.");
+		if (read(fd, contents, n) != (ssize_t)n)
+			return ferr("cannot read file contents");
+		while (n && !contents[--n])
+			--size;
+	} while (size && !n);
+
+	/* Sanity check.
+	 */
+	if (!size)
+		return err("ELF file is completely blank!");
+
+	*newsize = size;
+	return TRUE;
+}
+
+/* main() loops over the cmdline arguments, leaving all the real work
+ * to the other functions.
+ */
+int main(int argc, char *argv[])
+{
+	int				fd;
+	union {
+		Elf32_Ehdr	ehdr32;
+		Elf64_Ehdr	ehdr64;
+	} e;
+	union {
+		Elf32_Phdr	*phdrs32;
+		Elf64_Phdr	*phdrs64;
+	} p;
+	unsigned long	newsize;
+	char			**arg;
+	int				failures = 0;
+
+	if (argc < 2 || argv[1][0] == '-') {
+		printf("Usage: sstrip FILE...\n"
+			   "sstrip discards all nonessential bytes from an executable.\n\n"
+			   "Version 2.0-X Copyright (C) 2000,2001 Brian Raiter.\n"
+			   "Cross-devel hacks Copyright (C) 2004 Manuel Novoa III.\n"
+			   "This program is free software, licensed under the GNU\n"
+			   "General Public License. There is absolutely no warranty.\n");
+		return EXIT_SUCCESS;
+	}
+
+	progname = argv[0];
+
+	for (arg = argv + 1 ; *arg != NULL ; ++arg) {
+		filename = *arg;
+
+		fd = open(*arg, O_RDWR);
+		if (fd < 0) {
+			ferr("can't open");
+			++failures;
+			continue;
+		}
+
+		switch (readelfheaderident(fd, &e.ehdr32)) {
+			case ELFCLASS32:
+				if (!(readelfheader32(fd, &e.ehdr32)					&&
+					  readphdrtable32(fd, &e.ehdr32, &p.phdrs32)		&&
+					  getmemorysize32(&e.ehdr32, p.phdrs32, &newsize)	&&
+					  truncatezeros(fd, &newsize)						&&
+					  modifyheaders32(&e.ehdr32, p.phdrs32, newsize)	&&
+					  commitchanges32(fd, &e.ehdr32, p.phdrs32, newsize)))
+					++failures;
+				break;
+			case ELFCLASS64:
+				if (!(readelfheader64(fd, &e.ehdr64)					&&
+					  readphdrtable64(fd, &e.ehdr64, &p.phdrs64)		&&
+					  getmemorysize64(&e.ehdr64, p.phdrs64, &newsize)	&&
+					  truncatezeros(fd, &newsize)						&&
+					  modifyheaders64(&e.ehdr64, p.phdrs64, newsize)	&&
+					  commitchanges64(fd, &e.ehdr64, p.phdrs64, newsize)))
+					++failures;
+				break;
+			default:
+				++failures;
+				break;
+		}
+		close(fd);
+	}
+
+	return failures ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tools/tar/Makefile b/tools/tar/Makefile
new file mode 100644
index 0000000000..a619e846ce
--- /dev/null
+++ b/tools/tar/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=tar
+PKG_VERSION:=1.29
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=@GNU/tar
+PKG_MD5SUM:=236b11190c0a3a6885bdb8d61424f2b36a5872869aa3f7f695dea4b4843ae2f2
+
+HOST_BUILD_PARALLEL := 1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOSTCC := $(HOSTCC_NOCACHE)
+HOSTCXX := $(HOSTCXX_NOCACHE)
+
+HOST_CONFIGURE_ARGS += \
+	--without-posix-acls \
+	--without-selinux \
+	--without-xattrs \
+	--disable-acl \
+	--disable-nls
+
+$(eval $(call HostBuild))
diff --git a/tools/upslug2/Makefile b/tools/upslug2/Makefile
new file mode 100644
index 0000000000..face1d2183
--- /dev/null
+++ b/tools/upslug2/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2009-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=upslug2
+PKG_VERSION:=20071227
+
+PKG_SOURCE_URL:=http://svn.nslu2-linux.org/svnroot/upslug2/trunk
+PKG_SOURCE_PROTO:=svn
+PKG_SOURCE_SUBDIR:=upslug2-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=41
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_MIRROR_MD5SUM:=5c69eae3a2affef8f4f7194cfedfdb9175b04ca433f9ae046c85309b42bdb21e
+
+include $(INCLUDE_DIR)/host-build.mk
+
+unexport CFLAGS
+
+define Host/Configure
+	(cd $(HOST_BUILD_DIR); \
+		aclocal && autoconf && \
+		autoheader && \
+		automake --add-missing; \
+	)
+	$(Host/Configure/Default)
+endef
+
+ifneq ($(HOST_OS),Linux)
+	HOST_CONFIGURE_ARGS += --with-libpcap
+endif
+
+$(eval $(call HostBuild))
diff --git a/tools/upslug2/patches/100-libpcap_fix.patch b/tools/upslug2/patches/100-libpcap_fix.patch
new file mode 100644
index 0000000000..1e14de4519
--- /dev/null
+++ b/tools/upslug2/patches/100-libpcap_fix.patch
@@ -0,0 +1,153 @@
+--- a/pcap_wire.cc
++++ b/pcap_wire.cc
+@@ -18,6 +18,7 @@
+ 
+ #include <sys/time.h>
+ #include <sys/select.h>
++#include <sys/poll.h>
+ 
+ /* Ways of finding the hardware MAC on this machine... */
+ /* This is the Linux only fallback. */
+@@ -130,20 +131,18 @@ namespace NSLU2Upgrade {
+ 		 * non-static (real) Handler.
+ 		 */
+ 		void Handler(const struct pcap_pkthdr *packet_header, const u_char *packet) {
+-			/* This should only be called once... */
+-			if (captured)
+-				throw std::logic_error("Handler called twice");
+-
+ 			/* Verify the protocol and originating address of the packet, then
+ 			 * return this packet.
+ 			 */
++			if (captured)
++				return;
+ 			if (packet_header->caplen > 14 && (broadcast ||
+ 				std::memcmp(packet+6, header, 6) == 0)) {
+-				/* Record the address and copy the data */
+-				std::memcpy(source, packet+6, 6);
+ 				const size_t len(packet_header->caplen - 14);
+ 				if (len > captureSize)
+-					throw std::logic_error("packet too long");
++					return;
++				/* Record the address and copy the data */
++				std::memcpy(source, packet+6, 6);
+ 				std::memcpy(captureBuffer, packet+14, len);
+ 				captureSize = len;
+ 				captured = true;
+@@ -156,7 +155,7 @@ namespace NSLU2Upgrade {
+ 			 * packet and the buffer should be big enough.
+ 			 */
+ 			if (packet_header->caplen < packet_header->len)
+-				throw std::logic_error("truncated packet");
++				return;
+ 
+ 			/*IGNORE EVIL: known evil cast */
+ 			reinterpret_cast<PCapWire*>(user)->Handler(packet_header, packet);
+@@ -173,56 +172,24 @@ namespace NSLU2Upgrade {
+ 		virtual void Receive(void *buffer, size_t &size, unsigned long timeout) {
+ 			/* Now try to read packets until the timeout has been consumed.
+ 			 */
+-			struct timeval tvStart;
+-			if (timeout > 0 && gettimeofday(&tvStart, 0) != 0)
+-				throw OSError(errno, "gettimeofday(base)");
++			int time_count;
+ 
+ 			captureBuffer = buffer;
+ 			captureSize = size;
+ 			captured = false;
++			time_count = timeout / 2000; /* 2 ms intervals */
++			time_count++;
+ 			do {
+ 				/*IGNORE EVIL: known evil cast */
+-				int count(pcap_dispatch(pcap, 1, PCapHandler,
+-							reinterpret_cast<u_char*>(this)));
++				int count = pcap_dispatch(pcap, 1, PCapHandler,
++							reinterpret_cast<u_char*>(this));
+ 
+-				if (count > 0) {
+-					/* Were any packets handled? */
+-					if (captured) {
+-						size = captureSize;
+-						return;
+-					}
+-					/* else try again. */
+-				} else if (count == 0) {
+-					/* Nothing to handle - do the timeout, do this
+-					 * by waiting a bit then trying again, the trick
+-					 * to this is to work out how long to wait each
+-					 * time, for the moment a 10ms delay is used.
+-					 */
+-					if (timeout == 0)
+-						break;
+-
+-					struct timeval tvNow;
+-					if (gettimeofday(&tvNow, 0) != 0)
+-						throw OSError(errno, "gettimeofday(now)");
+-
+-					unsigned long t(tvNow.tv_sec - tvStart.tv_sec);
+-					t *= 1000000;
+-					t += tvNow.tv_usec;
+-					t -= tvStart.tv_usec;
+-					if (t > timeout)
+-						break;
+-
+-					tvNow.tv_sec = 0;
+-					tvNow.tv_usec = timeout-t;
+-					if (tvNow.tv_usec > 10000)
+-						tvNow.tv_usec = 10000;
+-
+-					/* Delay, may be interrupted - this should
+-					 * be portable to the BSDs (since the
+-					 * technique originates in BSD.)
+-					 */
+-					(void)select(0, 0, 0, 0, &tvNow);
+-				} else {
++				/* Were any packets handled? */
++				if (captured) {
++					size = captureSize;
++					return;
++				}
++				if (count < 0) {
+ 					/* Error condition. */
+ 					if (count == -1) {
+ 						if (errno != EINTR)
+@@ -232,7 +199,8 @@ namespace NSLU2Upgrade {
+ 					} else
+ 						throw std::logic_error("pcap unexpected result");
+ 				}
+-			} while (timeout != 0);
++				time_count--;
++			} while (time_count > 0);
+ 
+ 			/* Here on timeout. */
+ 			size = 0;
+@@ -288,6 +256,7 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire::
+ 		const unsigned char *mac, const unsigned char *address, int uid) {
+ 	/* This is used to store the error passed to throw. */
+ 	static char PCapErrbuf[PCAP_ERRBUF_SIZE];
++	struct bpf_program fp;
+ 
+ 	/* Check the device name.  If not given use 'DEFAULT_ETHERNET_IF'. */
+ 	if (device == NULL)
+@@ -301,20 +270,12 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire::
+ 		 * for other ethernet MACs.  (Because the code above does not
+ 		 * check that the destination matches the device in use).
+ 		 */
+-		pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 1/*ms*/, PCapErrbuf);
++		pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 2/*ms*/, PCapErrbuf);
+ 
+ 		if (pcap == NULL)
+ 			throw WireError(errno, PCapErrbuf);
+ 	}
+ 
+-	/* Always do a non-blocking read, because the 'timeout' above
+-	 * doesn't work on Linux (return is immediate) and on OSX (and
+-	 * maybe other BSDs) the interface tends to hang waiting for
+-	 * the timeout to expire even after receiving a single packet.
+-	 */
+-	if (pcap_setnonblock(pcap, true, PCapErrbuf))
+-		throw WireError(errno, PCapErrbuf);
+-
+ 	try {
+ 		/* The MAC of the transmitting device is needed - without
+ 		 * this the return packet won't go to the right place!
diff --git a/tools/upslug2/patches/110-wrt350nv2_support.patch b/tools/upslug2/patches/110-wrt350nv2_support.patch
new file mode 100644
index 0000000000..eea7cc4d00
--- /dev/null
+++ b/tools/upslug2/patches/110-wrt350nv2_support.patch
@@ -0,0 +1,279 @@
+--- a/nslu2_image.cc
++++ b/nslu2_image.cc
+@@ -54,28 +54,44 @@ namespace NSLU2Image {
+ 				int &address, int &length) {
+ 			address = image.tellg();
+ 			length = buffer_length;
+-			if (address+length > NSLU2Protocol::FlashSize)
+-				length = NSLU2Protocol::FlashSize-address;
++			if (address+length > EndAddress)
++				length = EndAddress-address;
+ 			if (length > 0)
+ 				SafeRead(&image, buffer, length, "image (read)");
+ 		}
+ 
++		virtual void GetBoundaries(int &start, int &end)
++		{
++			start = BaseAddress;
++			end = EndAddress;
++		}
++
+ 		/* Rewind to the start of the image (or the Kernel if not
+ 		 * doing a complete reprogram).
+ 		 */
+ 		virtual void Rewind(void) {
+-			SafeSeek(&image, reprogram ? 0 : NSLU2Protocol::BaseAddress,
++			SafeSeek(&image, reprogram ? 0 : BaseAddress,
+ 					"image (seek)");
+ 		}
+ 
+ 	private:
++		int BaseAddress;
++		int EndAddress;
++
+ 		/* Validate that this really is an image file. */
+ 		void Validate(const char *i) {
+ 			char signature[8];
+ 
+ 			SafeSeek(&image, -8, i, std::ios::end);
+ 			SafeRead(&image, signature, 8, i);
+-			if (memcmp(signature, "eRcOmM", 6) != 0)
++
++			if (memcmp(signature, "eRcOmM", 6) == 0) {
++				BaseAddress = NSLU2Protocol::BaseAddress;
++				EndAddress = NSLU2Protocol::FlashSize;
++			} else if (memcmp(signature + 1, "sErCoMm", 7) == 0) {
++				BaseAddress = 0;
++				EndAddress = NSLU2Protocol::FlashSize - 0x40000;
++			} else
+ 				throw NSLU2Image::FileError(DataError, i, 0);
+ 		}
+ 
+@@ -93,6 +109,12 @@ namespace NSLU2Image {
+ 		virtual ~SynthesiseImage() {
+ 		}
+ 
++		void GetBoundaries(int &start, int &end)
++		{
++			start = NSLU2Protocol::BaseAddress;
++			end = NSLU2Protocol::FlashSize;
++		}
++
+ 		/* Get the next block of bytes, returns an address and length, false if
+ 		 * there is a problem.
+ 		 */
+--- a/nslu2_image.h
++++ b/nslu2_image.h
+@@ -35,6 +35,8 @@ namespace NSLU2Image {
+ 		virtual ~Image() {
+ 		}
+ 
++		virtual void GetBoundaries(int &start, int &end) = 0;
++
+ 		/* Get the next block of bytes, returns an address and length.
+ 		 */
+ 		virtual void GetBytes(char *buffer, size_t buffer_length,
+--- a/nslu2_upgrade.cc
++++ b/nslu2_upgrade.cc
+@@ -95,7 +95,7 @@ namespace NSLU2Upgrade {
+ 
+ 	class RealDoUpgrade : public DoUpgrade {
+ 	public:
+-		RealDoUpgrade(Wire *w, Progress *p, bool r) :
++		RealDoUpgrade(Wire *w, Progress *p, bool r, int start, int end) :
+ 			wire(w), progress(p), sequenceError(-1), reprogram(r),
+ 			lastType(NSLU2Protocol::InvalidType) {
+ 			if (reprogram) {
+@@ -105,6 +105,8 @@ namespace NSLU2Upgrade {
+ 				NSLU2Protocol::UpgradeStartPacket packet(seq);
+ 				wire->Send(packet.PacketBuffer(), packet.PacketLength());
+ 			}
++			BaseAddress = start;
++			EndAddress = end;
+ 		}
+ 
+ 		virtual ~RealDoUpgrade() {
+@@ -205,8 +207,8 @@ namespace NSLU2Upgrade {
+ 
+ 	};
+ 
+-	DoUpgrade *DoUpgrade::MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram) {
+-		return new RealDoUpgrade(wire, progress, reprogram);
++	DoUpgrade *DoUpgrade::MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram, int start, int end) {
++		return new RealDoUpgrade(wire, progress, reprogram, start, end);
+ 	}
+ };
+ 
+@@ -421,13 +423,18 @@ void NSLU2Upgrade::RealDoUpgrade::Upgrad
+ 	/* Simple upgrade programs only the addresses beyound BaseAddress,
+ 	 * reprogram overwrites the whole flash.
+ 	 */
+-	if (!reprogram && address < NSLU2Protocol::BaseAddress) {
++	if (!reprogram && address < BaseAddress) {
+ 		length += address;
+-		if (length <= NSLU2Protocol::BaseAddress)
++		if (length <= BaseAddress)
+ 			return; /* nothing to do. */
+-		address = NSLU2Protocol::BaseAddress;
++		address = BaseAddress;
+ 		length -= address;
+ 	}
++	if (!reprogram && address + length > EndAddress) {
++		if (address >= EndAddress)
++			return; /* nothing to do. */
++		length -= EndAddress - address;
++	}
+ 
+ #if 1
+ 	/* Skip blocks of 255 valued bytes - the erase clears the flash to this
+@@ -495,11 +502,11 @@ void NSLU2Upgrade::RealDoUpgrade::Verify
+ 		Finish();
+ 
+ 	/* Verify never verifies anything below BaseAddress. */
+-	if (address < NSLU2Protocol::BaseAddress) {
++	if (address < BaseAddress) {
+ 		length += address;
+-		if (length <= NSLU2Protocol::BaseAddress)
++		if (length <= BaseAddress)
+ 			return; /* nothing to do. */
+-		address = NSLU2Protocol::BaseAddress;
++		address = BaseAddress;
+ 		length -= address;
+ 	}
+ 
+--- a/nslu2_upgrade.h
++++ b/nslu2_upgrade.h
+@@ -206,6 +206,8 @@ namespace NSLU2Upgrade {
+ 
+ 	class DoUpgrade {
+ 	public:
++		int BaseAddress;
++		int EndAddress;
+ 		virtual ~DoUpgrade() {
+ 		}
+ 
+@@ -228,7 +230,7 @@ namespace NSLU2Upgrade {
+ 		virtual void Reboot(void) = 0;
+ 			/* Reboot the NSLU2. */
+ 
+-		static DoUpgrade *MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram);
++		static DoUpgrade *MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram, int start, int end);
+ 			/* Instantiate a real DoUpgrade, returns NULL if the object
+ 			 * cannot be instantiated.
+ 			 *
+--- a/upslug2.cc
++++ b/upslug2.cc
+@@ -21,8 +21,8 @@
+ 
+ class ProgressBar : public UpSlug2::CharacterProgressBar<80> {
+ public:
+-	ProgressBar(bool reprogram, const unsigned char *t) :
+-		UpSlug2::CharacterProgressBar<80>(reprogram, 64),
++	ProgressBar(bool reprogram, const unsigned char *t, int start, int end) :
++		UpSlug2::CharacterProgressBar<80>(reprogram, 64, start, end),
+ 		target(t), displayed(false), ticker(0) {
+ 	}
+ 
+@@ -95,7 +95,7 @@ private:
+ 			else if (seen == -1) {
+ 				seen = 0;
+ 				if (!reprogram)
+-					sent -= NSLU2Protocol::BaseAddress;
++					sent -= NSLU2Protocol::FlashSize - (EndAddress - BaseAddress);
+ 			} else
+ 				sent -= seen;
+ 
+@@ -423,7 +423,7 @@ int main(int argc, char **argv) {
+ { 0,                                                            0,                 0,  0  }
+ 	};
+ 
+-	do switch (getopt_long(argc, argv, "he:d:t:f:vUni:Ck:r:R:j:p:P:T:F:E:", options, 0)) {
++	do switch (getopt_long(argc, argv, "he:d:t:f:vUni:Ck:r:R:j:op:P:T:F:E:", options, 0)) {
+ 	case  -1: if (optind < argc) {
+ 			  std::fprintf(stderr, "%s: unrecognised option\n", argv[optind]);
+ 			  std::exit(1);
+@@ -523,16 +523,22 @@ done:
+ 
+ 		if (mac && got_kernel) {
+ 			Pointer<NSLU2Upgrade::Wire> wire(NSLU2Upgrade::Wire::MakeWire(device, fromMac, mac, euid));
+-			ProgressBar progress(reprogram, mac);
++			int BaseAddress = NSLU2Protocol::BaseAddress;
++			int EndAddress = NSLU2Protocol::FlashSize;
+ 
+ 			if (full_image) { /* complete image. */
+ 				/* The full image case allows a complete reprogram. */
++				NSLU2Image::Image *image_p;
+ 				Pointer<NSLU2Image::Image> image(
+ 						NSLU2Image::Image::MakeImage(
+ 							reprogram, full_image));
++				image_p = image.p;
++				image_p->GetBoundaries(BaseAddress, EndAddress);
++				ProgressBar progress(reprogram, mac, BaseAddress, EndAddress);
+ 				Pointer<NSLU2Upgrade::DoUpgrade> upgrade(
+ 					NSLU2Upgrade::DoUpgrade::MakeDoUpgrade(
+-						wire.p, &progress, reprogram));
++						wire.p, &progress, reprogram,
++						BaseAddress, EndAddress));
+ 				progress.FirstDisplay();
+ 				Upgrade(upgrade.p, image.p, no_upgrade, no_verify);
+ 				progress.EndDisplay();
+@@ -551,9 +557,11 @@ done:
+ 							fis_payload,
+ 							product_id, protocol_id,
+ 							firmware_version, extra_version));
++				ProgressBar progress(reprogram, mac, BaseAddress, EndAddress);
+ 				Pointer<NSLU2Upgrade::DoUpgrade> upgrade(
+ 					NSLU2Upgrade::DoUpgrade::MakeDoUpgrade(
+-						wire.p, &progress, false));
++						wire.p, &progress, false,
++						BaseAddress, EndAddress));
+ 				progress.FirstDisplay();
+ 				Upgrade(upgrade.p, image.p, no_upgrade, no_verify);
+ 				progress.EndDisplay();
+--- a/upslug2_progress.h
++++ b/upslug2_progress.h
+@@ -161,15 +161,19 @@ namespace UpSlug2 {
+ 			Timedout,   /* *: timeout on a sent packet for this address. */
+ 			NumberOfStates
+ 		} Status;
+-		
++		int BaseAddress;
++		int EndAddress;
++
+ 		/* reprogram says whether this is a full reprogram (the entire
+ 		 * flash will be erased) or not (the leading, RedBoot, SysConf
+ 		 * partitions are not erased).
+ 		 * resolution should be about 6 for a command line (character)
+ 		 * progress bar and 8 for a GUI (pixel) progress bar.
+ 		 */
+-		ProgressBar(bool r) :
++		ProgressBar(bool r, int start, int end) :
+ 			reprogram(r), timeout(false), retransmit(false), status(Init) {
++			BaseAddress = start;
++			EndAddress = end;
+ 		}
+ 
+ 		/* lowWaterMark..(highWaterMark-1) bytes are in state 'st',
+@@ -179,8 +183,8 @@ namespace UpSlug2 {
+ 			/* These initial settings cover the majority of cases
+ 			 * correctly.
+ 			 */
+-			lowWaterMark = reprogram ? 0 : NSLU2Protocol::BaseAddress;
+-			highWaterMark = status >= st ? NSLU2Protocol::FlashSize-1 : 0;
++			lowWaterMark = reprogram ? 0 : BaseAddress;
++			highWaterMark = status >= st ? EndAddress-1 : 0;
+ 			switch (st) {
+ 			case Init:
+ 				/* Everything has an initial value... */
+@@ -286,9 +290,9 @@ namespace UpSlug2 {
+ 	 */
+ 	template <int characters> class CharacterProgressBar : public ProgressBar {
+ 	public:
+-		CharacterProgressBar(bool reprogram, int n, const char ind[NumberOfStates] = 0) :
++		CharacterProgressBar(bool reprogram, int n, int start, int end, const char ind[NumberOfStates] = 0) :
+ 			numberOfCharacters(n > characters || n < 1 ? characters : n),
+-			ProgressBar(reprogram) {
++			ProgressBar(reprogram, start, end) {
+ 			if (ind)
+ 				std::memcpy(indicators, ind, NumberOfStates);
+ 			else
diff --git a/tools/upx/Makefile b/tools/upx/Makefile
new file mode 100644
index 0000000000..52d2f784f8
--- /dev/null
+++ b/tools/upx/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2011-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=upx
+PKG_VERSION:=3.91
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-src.tar.bz2
+PKG_SOURCE_URL:=https://github.com/upx/upx/releases/download/v$(PKG_VERSION)
+PKG_MD5SUM:=c6d0b3ea2ecb28cb8031d59a4b087a43
+PKG_CAT:=bzcat
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)-src
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	rm -f $(HOST_BUILD_DIR)/src/.depend
+	$(MAKE) UPX_LZMADIR="$(BUILD_DIR_HOST)/lzma-4.65" -C $(HOST_BUILD_DIR)/src \
+		CXXFLAGS_WERROR="" LDFLAGS="$(HOST_LDFLAGS)" \
+		CXX="$(HOSTCXX)"
+endef
+
+define Host/Install
+	$(CP) $(HOST_BUILD_DIR)/src/upx.out $(STAGING_DIR_HOST)/bin/upx
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/upx
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/upx/patches/100-lzmaonly.patch b/tools/upx/patches/100-lzmaonly.patch
new file mode 100644
index 0000000000..f8e8d0b82a
--- /dev/null
+++ b/tools/upx/patches/100-lzmaonly.patch
@@ -0,0 +1,156 @@
+--- a/src/compress.cpp
++++ b/src/compress.cpp
+@@ -41,7 +41,7 @@ unsigned upx_adler32(const void *buf, un
+     if (len == 0)
+         return adler;
+     assert(buf != NULL);
+-#if 0
++#if !(WITH_UCL)
+     return adler32(adler, (const Bytef *) buf, len); // zlib
+ #elif (WITH_UCL)
+     return ucl_adler32(adler, (const ucl_bytep) buf, len);
+--- a/src/conf.h
++++ b/src/conf.h
+@@ -179,7 +179,7 @@
+ #  undef __unix
+ #endif
+ 
+-#if !defined(WITH_UCL)
++#if defined(WITH_UCL)
+ #  define WITH_UCL 1
+ #endif
+ #if 0 && !defined(WITH_LZMA)
+@@ -640,7 +640,11 @@ struct lzma_compress_config_t
+ };
+ 
+ 
++#if (WITH_UCL)
+ struct ucl_compress_config_t : public REAL_ucl_compress_config_t
++#else
++struct ucl_compress_config_t
++#endif
+ {
+     void reset() { memset(this, 0xff, sizeof(*this)); }
+ };
+@@ -692,7 +696,9 @@ struct lzma_compress_result_t
+ 
+ struct ucl_compress_result_t
+ {
++#if (WITH_UCL)
+     ucl_uint result[16];
++#endif
+ 
+     void reset() { memset(this, 0, sizeof(*this)); }
+ };
+--- a/src/main.cpp
++++ b/src/main.cpp
+@@ -618,7 +618,9 @@ static int do_option(int optc, const cha
+         opt->method = -1;
+         opt->all_filters = true;
+         opt->filter = -1;
++#if (WITH_UCL)
+         opt->crp.crp_ucl.m_size = 999999;
++#endif
+         /* fallthrough */
+     case 900:                               // --best
+         if (!set_method(-1, 10))
+@@ -709,6 +711,7 @@ static int do_option(int optc, const cha
+         opt->exact = true;
+         break;
+     // compression runtime parameters
++#if (WITH_UCL)
+     case 801:
+         getoptvar(&opt->crp.crp_ucl.c_flags, 0, 3, arg);
+         break;
+@@ -730,6 +733,7 @@ static int do_option(int optc, const cha
+     case 807:
+         getoptvar(&opt->crp.crp_ucl.m_size, 10000u, 999999u, arg);
+         break;
++#endif
+     case 811:
+         getoptvar(&opt->crp.crp_lzma.pos_bits, arg);
+         break;
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -57,7 +57,10 @@ ifneq ($(wildcard $(UPX_UCLDIR)/include/
+ INCLUDES += -I$(UPX_UCLDIR)/include
+ LIBS += $(addprefix -L,$(dir $(wildcard $(UPX_UCLDIR)/libucl$(libext) $(UPX_UCLDIR)/src/.libs/libucl$(libext))))
+ endif
+-LIBS += -lucl -lz
++ifeq ($(WITH_UCL),1)
++LIBS += -lucl
++endif
++LIBS += -lz
+ # you should set envvar UPX_LZMADIR to point to your unpacked LZMA SDK
+ include $(top_srcdir)/src/stub/src/c/Makevars.lzma
+ ifneq ($(UPX_LZMA_VERSION),)
+--- a/src/packer.cpp
++++ b/src/packer.cpp
+@@ -199,6 +199,7 @@ bool Packer::compress(upx_bytep i_ptr, u
+     if (cconf_parm)
+         cconf = *cconf_parm;
+     // cconf options
++#if (WITH_UCL)
+     if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
+     {
+         if (opt->crp.crp_ucl.c_flags != -1)
+@@ -216,6 +217,7 @@ bool Packer::compress(upx_bytep i_ptr, u
+             step = 0;
+ #endif
+     }
++#endif
+     if (M_IS_LZMA(ph.method))
+     {
+         oassign(cconf.conf_lzma.pos_bits, opt->crp.crp_lzma.pos_bits);
+@@ -250,6 +252,7 @@ bool Packer::compress(upx_bytep i_ptr, u
+     if (r != UPX_E_OK)
+         throwInternalError("compression failed");
+ 
++#if (WITH_UCL)
+     if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
+     {
+         const ucl_uint *res = ph.compress_result.result_ucl.result;
+@@ -267,6 +270,7 @@ bool Packer::compress(upx_bytep i_ptr, u
+             assert(cconf.conf_ucl.max_match == 0 || cconf.conf_ucl.max_match >= ph.max_match_found);
+         }
+     }
++#endif
+ 
+     //printf("\nPacker::compress: %d/%d: %7d -> %7d\n", ph.method, ph.level, ph.u_len, ph.c_len);
+     if (!checkCompressionRatio(ph.u_len, ph.c_len))
+--- a/src/p_exe.cpp
++++ b/src/p_exe.cpp
+@@ -506,7 +506,9 @@ void PackExe::pack(OutputFile *fo)
+     Filter ft(ph.level);
+     // compress (max_match = 8192)
+     upx_compress_config_t cconf; cconf.reset();
++#if (WITH_UCL)
+     cconf.conf_ucl.max_match = MAXMATCH;
++#endif
+     cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
+     compressWithFilters(&ft, 32, &cconf);
+ 
+--- a/src/p_ps1.cpp
++++ b/src/p_ps1.cpp
+@@ -499,7 +499,9 @@ void PackPs1::pack(OutputFile *fo)
+ 
+     // compress (max_match = 65535)
+     upx_compress_config_t cconf; cconf.reset();
++#if (WITH_UCL)
+     cconf.conf_ucl.max_match = 65535;
++#endif
+     cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
+     compressWithFilters(&ft, sa_cnt, &cconf);
+ 
+--- a/src/p_tos.cpp
++++ b/src/p_tos.cpp
+@@ -506,7 +506,9 @@ void PackTos::pack(OutputFile *fo)
+     Filter ft(ph.level);
+     // compress (max_match = 65535)
+     upx_compress_config_t cconf; cconf.reset();
++#if (WITH_UCL)
+     cconf.conf_ucl.max_match = 65535;
++#endif
+     cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
+     compressWithFilters(&ft, 512, &cconf);
+ 
diff --git a/tools/wrt350nv2-builder/Makefile b/tools/wrt350nv2-builder/Makefile
new file mode 100644
index 0000000000..a705b6dc8d
--- /dev/null
+++ b/tools/wrt350nv2-builder/Makefile
@@ -0,0 +1,41 @@
+# 
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=wrt350nv2-builder
+PKG_VERSION:=2.4
+PKG_REVISION:=2
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/${PKG_NAME}-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(HOSTCC) $(HOST_CFLAGS) -c src/md5.c -o $(HOST_BUILD_DIR)/md5.o
+	$(HOSTCC) $(HOST_CFLAGS) -c src/ioapi.c -o $(HOST_BUILD_DIR)/ioapi.o
+	$(HOSTCC) $(HOST_CFLAGS) -c src/wrt350nv2-builder.c -o $(HOST_BUILD_DIR)/wrt350nv2-builder.o
+	$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $(HOST_BUILD_DIR)/wrt350nv2-builder \
+		$(HOST_BUILD_DIR)/wrt350nv2-builder.o $(HOST_BUILD_DIR)/md5.o $(HOST_BUILD_DIR)/ioapi.o
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/wrt350nv2-builder $(STAGING_DIR_HOST)/bin/
+# optionally the builder can add a u-boot binary to create a complete webupgrade image, but this is not mandatory
+# u-boot images from stock firmware are available at ftp://ftp.maddes.net/openwrt/trunk/orion/stock/binaries/
+	[ ! -f "files/u-boot.bin" ] || ( \
+		$(INSTALL_DIR) $(STAGING_DIR_HOST)/share/wrt350nv2-builder; \
+		$(CP) files/u-boot.bin $(STAGING_DIR_HOST)/share/wrt350nv2-builder/; )
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/wrt350nv2-builder
+	rm -f $(STAGING_DIR_HOST)/share/wrt350nv2-builder
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/wrt350nv2-builder/src/crypt.h b/tools/wrt350nv2-builder/src/crypt.h
new file mode 100644
index 0000000000..622f4bc2ec
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/crypt.h
@@ -0,0 +1,132 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+   Version 1.01e, February 12th, 2005
+
+   Copyright (C) 1998-2005 Gilles Vollant
+
+   This code is a modified version of crypting code in Infozip distribution
+
+   The encryption/decryption parts of this source code (as opposed to the
+   non-echoing password parts) were originally written in Europe.  The
+   whole source package can be freely distributed, including from the USA.
+   (Prior to January 2000, re-export from the US was a violation of US law.)
+
+   This encryption code is a direct transcription of the algorithm from
+   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
+   file (appnote.txt) is distributed with the PKZIP program (even in the
+   version without encryption capabilities).
+
+   If you don't need crypting in your application, just define symbols
+   NOCRYPT and NOUNCRYPT.
+
+   This code support the "Traditional PKWARE Encryption".
+
+   The new AES encryption added on Zip format by Winzip (see the page
+   http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+   Encryption is not supported.
+*/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
+{
+    unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an
+                     * unpredictable manner on 16-bit systems; not a problem
+                     * with any known compiler so far, though */
+
+    temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+    return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
+{
+    (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+    (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+    (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+    {
+      register int keyshift = (int)((*(pkeys+1)) >> 24);
+      (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+    }
+    return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
+{
+    *(pkeys+0) = 305419896L;
+    *(pkeys+1) = 591751049L;
+    *(pkeys+2) = 878082192L;
+    while (*passwd != '\0') {
+        update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+        passwd++;
+    }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+    (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+    (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN  12
+   /* "last resort" source for second part of crypt seed pattern */
+#  ifndef ZCR_SEED2
+#    define ZCR_SEED2 3141592654UL     /* use PI as default pattern */
+#  endif
+
+static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
+    const char *passwd;         /* password string */
+    unsigned char *buf;         /* where to write header */
+    int bufSize;
+    unsigned long* pkeys;
+    const unsigned long* pcrc_32_tab;
+    unsigned long crcForCrypting;
+{
+    int n;                       /* index in random header */
+    int t;                       /* temporary */
+    int c;                       /* random byte */
+    unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+    static unsigned calls = 0;   /* ensure different random header each time */
+
+    if (bufSize<RAND_HEAD_LEN)
+      return 0;
+
+    /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+     * output of rand() to get less predictability, since rand() is
+     * often poorly implemented.
+     */
+    if (++calls == 1)
+    {
+        srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+    }
+    init_keys(passwd, pkeys, pcrc_32_tab);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++)
+    {
+        c = (rand() >> 7) & 0xff;
+        header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+    }
+    /* Encrypt random header (last two bytes is high word of crc) */
+    init_keys(passwd, pkeys, pcrc_32_tab);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++)
+    {
+        buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+    }
+    buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+    buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+    return n;
+}
+
+#endif
diff --git a/tools/wrt350nv2-builder/src/ioapi.c b/tools/wrt350nv2-builder/src/ioapi.c
new file mode 100644
index 0000000000..f1bee23e64
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/ioapi.c
@@ -0,0 +1,177 @@
+/* ioapi.c -- IO base function header for compress/uncompress .zip
+   files using zlib + zip or unzip API
+
+   Version 1.01e, February 12th, 2005
+
+   Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+
+
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR    1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END    2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET    0
+#endif
+
+voidpf ZCALLBACK fopen_file_func OF((
+   voidpf opaque,
+   const char* filename,
+   int mode));
+
+uLong ZCALLBACK fread_file_func OF((
+   voidpf opaque,
+   voidpf stream,
+   void* buf,
+   uLong size));
+
+uLong ZCALLBACK fwrite_file_func OF((
+   voidpf opaque,
+   voidpf stream,
+   const void* buf,
+   uLong size));
+
+long ZCALLBACK ftell_file_func OF((
+   voidpf opaque,
+   voidpf stream));
+
+long ZCALLBACK fseek_file_func OF((
+   voidpf opaque,
+   voidpf stream,
+   uLong offset,
+   int origin));
+
+int ZCALLBACK fclose_file_func OF((
+   voidpf opaque,
+   voidpf stream));
+
+int ZCALLBACK ferror_file_func OF((
+   voidpf opaque,
+   voidpf stream));
+
+
+voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
+   voidpf opaque;
+   const char* filename;
+   int mode;
+{
+    FILE* file = NULL;
+    const char* mode_fopen = NULL;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else
+    if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else
+    if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename!=NULL) && (mode_fopen != NULL))
+        file = fopen(filename, mode_fopen);
+    return file;
+}
+
+
+uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
+   voidpf opaque;
+   voidpf stream;
+   void* buf;
+   uLong size;
+{
+    uLong ret;
+    ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+    return ret;
+}
+
+
+uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
+   voidpf opaque;
+   voidpf stream;
+   const void* buf;
+   uLong size;
+{
+    uLong ret;
+    ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+    return ret;
+}
+
+long ZCALLBACK ftell_file_func (opaque, stream)
+   voidpf opaque;
+   voidpf stream;
+{
+    long ret;
+    ret = ftell((FILE *)stream);
+    return ret;
+}
+
+long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
+   voidpf opaque;
+   voidpf stream;
+   uLong offset;
+   int origin;
+{
+    int fseek_origin=0;
+    long ret;
+    switch (origin)
+    {
+    case ZLIB_FILEFUNC_SEEK_CUR :
+        fseek_origin = SEEK_CUR;
+        break;
+    case ZLIB_FILEFUNC_SEEK_END :
+        fseek_origin = SEEK_END;
+        break;
+    case ZLIB_FILEFUNC_SEEK_SET :
+        fseek_origin = SEEK_SET;
+        break;
+    default: return -1;
+    }
+    ret = 0;
+    fseek((FILE *)stream, offset, fseek_origin);
+    return ret;
+}
+
+int ZCALLBACK fclose_file_func (opaque, stream)
+   voidpf opaque;
+   voidpf stream;
+{
+    int ret;
+    ret = fclose((FILE *)stream);
+    return ret;
+}
+
+int ZCALLBACK ferror_file_func (opaque, stream)
+   voidpf opaque;
+   voidpf stream;
+{
+    int ret;
+    ret = ferror((FILE *)stream);
+    return ret;
+}
+
+void fill_fopen_filefunc (pzlib_filefunc_def)
+  zlib_filefunc_def* pzlib_filefunc_def;
+{
+    pzlib_filefunc_def->zopen_file = fopen_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell_file = ftell_file_func;
+    pzlib_filefunc_def->zseek_file = fseek_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/tools/wrt350nv2-builder/src/ioapi.h b/tools/wrt350nv2-builder/src/ioapi.h
new file mode 100644
index 0000000000..5fa9786148
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/ioapi.h
@@ -0,0 +1,75 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+   files using zlib + zip or unzip API
+
+   Version 1.01e, February 12th, 2005
+
+   Copyright (C) 1998-2005 Gilles Vollant
+*/
+
+#ifndef _ZLIBIOAPI_H
+#define _ZLIBIOAPI_H
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ      (1)
+#define ZLIB_FILEFUNC_MODE_WRITE     (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE   (8)
+
+
+#ifndef ZCALLBACK
+
+#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+#define ZCALLBACK CALLBACK
+#else
+#define ZCALLBACK
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode);
+typedef uLong  (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size);
+typedef uLong  (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size);
+typedef long   (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream);
+typedef long   (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin);
+typedef int    (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream);
+typedef int    (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream);
+
+typedef struct zlib_filefunc_def_s
+{
+    open_file_func      zopen_file;
+    read_file_func      zread_file;
+    write_file_func     zwrite_file;
+    tell_file_func      ztell_file;
+    seek_file_func      zseek_file;
+    close_file_func     zclose_file;
+    testerror_file_func zerror_file;
+    voidpf              opaque;
+} zlib_filefunc_def;
+
+
+
+void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def);
+
+#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
+#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
+#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
+#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
+#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/tools/wrt350nv2-builder/src/md5.c b/tools/wrt350nv2-builder/src/md5.c
new file mode 100644
index 0000000000..c35d96c5ef
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/md5.c
@@ -0,0 +1,381 @@
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+	either statically or dynamically; added missing #include <string.h>
+	in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+	type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+	unsigned in ANSI C, signed in traditional"; made test program
+	self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+	a = pms->abcd[0], b = pms->abcd[1],
+	c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+	/*
+	 * Determine dynamically whether this is a big-endian or
+	 * little-endian machine, since we can use a more efficient
+	 * algorithm on the latter.
+	 */
+	static const int w = 1;
+
+	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0		/* little-endian */
+	{
+	    /*
+	     * On little-endian machines, we can process properly aligned
+	     * data without copying it.
+	     */
+	    if (!((data - (const md5_byte_t *)0) & 3)) {
+		/* data are properly aligned */
+		X = (const md5_word_t *)data;
+	    } else {
+		/* not aligned */
+		memcpy(xbuf, data, 64);
+		X = xbuf;
+	    }
+	}
+#endif
+#if BYTE_ORDER == 0
+	else			/* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0		/* big-endian */
+	{
+	    /*
+	     * On big-endian machines, we must arrange the bytes in the
+	     * right order.
+	     */
+	    const md5_byte_t *xp = data;
+	    int i;
+
+#  if BYTE_ORDER == 0
+	    X = xbuf;		/* (dynamic only) */
+#  else
+#    define xbuf X		/* (static only) */
+#  endif
+	    for (i = 0; i < 16; ++i, xp += 4)
+		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+	}
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+	return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+	pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+	memcpy(pms->buf + offset, p, copy);
+	if (offset + copy < 64)
+	    return;
+	p += copy;
+	left -= copy;
+	md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+	md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+	memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/tools/wrt350nv2-builder/src/md5.h b/tools/wrt350nv2-builder/src/md5.h
new file mode 100644
index 0000000000..698c995d8f
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/md5.h
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+	references to Ghostscript; clarified derivation from RFC 1321;
+	now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+	added conditionalization for C++ compilation from Martin
+	Purschke <purschke@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];	/* message length in bits, lsw first */
+    md5_word_t abcd[4];		/* digest buffer */
+    md5_byte_t buf[64];		/* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/tools/wrt350nv2-builder/src/upgrade.h b/tools/wrt350nv2-builder/src/upgrade.h
new file mode 100644
index 0000000000..2b5953acc8
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/upgrade.h
@@ -0,0 +1,77 @@
+#ifndef _UPGRADE_H_
+#define _UPGRADE_H_
+
+#define FLASH_END_ADDR       0xffffffff 
+#define FLASH_ADDR_BASE      0xff800000
+#define BOOT_ADDR_BASE			 0xfffc0000
+#define BOOT_ADDR_BASE_OFF   0x7c0000
+#define FLASH_SIZE           0x800000
+#define BOOT_SIZE            0x40000
+//NVRAM in boot area
+//#define NVRAM_ADDR_BASE      0xfff90000
+//#define NVRAM_ADDR_BASE_OFF  0x790000
+//#define NVRAM_SIZE           0x10000
+
+#define PID_OFFSET         (BOOT_SIZE- 0x46)
+#define NODE_ADDRESS       (BOOT_SIZE-0x60)
+#define NODE_BASE_OFF   (FLASH_SIZE-0x60)
+#define PIN_ADDRESS         (BOOT_SIZE-0x70)//WPS PIN,8bytes
+#define PIN_OFF 				(FLASH_SIZE-0x70)
+#define KERNEL_CODE_OFFSET      0         
+#define SN_ADDRESS (BOOT_SIZE-0x80) //12bytes
+#define SN_OFF (FLASH_SIZE-0x80)
+
+
+#define UPGRADE_START_OFFSET  0
+#define UPGRADE_END_OFFSET    0x7A0000
+#define PRODUCT_ID_OFFSET     0x75ffe0//(UPGRADE_END_OFFSET  - 0x10)
+#define PROTOCOL_ID_OFFSET   (PRODUCT_ID_OFFSET + 0x02)
+#define FW_VERSION_OFFSET    (PRODUCT_ID_OFFSET + 0x04)
+#define SIGN_OFFSET          (PRODUCT_ID_OFFSET + 0x08)   /* eRcOmM */
+
+//#define LANG_UPGRADE
+#ifdef LANG_UPGRADE
+#define LANGBUF_BEGIN   0x1300000
+#define LANGBUF_END     0x1f00000
+#define LANGBUF_LENTH   (LANGBUF_END - LANGBUF_BEGIN)
+#endif
+#ifndef ERROR
+#define ERROR -1
+#endif
+
+#ifndef OK
+#define OK 0
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+
+void do_boot(void);
+void Download(void);
+void Assign(void);
+
+void gpio_init(void);
+void Led_Power(int value);
+void Led_security(int value);
+int PushButton(void);
+
+static unsigned short xchg ( unsigned short dwData);
+int FlashDriver(unsigned long dlAddress,unsigned char *dbData,unsigned long dlLength,unsigned long dlFlag);
+int ProgramChip(unsigned long dlAddress,unsigned char * dbData,unsigned long dlLength);
+int dl_Initialize(void);
+void dl_GetAddr(unsigned char *node);
+int dl_Receive(void);
+int dl_Transmit(char *buf,int len);
+void reset(void);
+void AssignHWAddress(unsigned char *psBuffer);
+int ResetChip(unsigned long ulRomDstAddr);
+int GetFlashType(void);
+
+#ifdef LANG_UPGRADE
+int save_lang_buf(unsigned long flash_addr, char *mem_addr,unsigned long length);
+int LangDriver(unsigned long flash_addr, char *mem_addr,unsigned long length, unsigned long dlFlag);
+#endif 
+#endif
+
diff --git a/tools/wrt350nv2-builder/src/wrt350nv2-builder.c b/tools/wrt350nv2-builder/src/wrt350nv2-builder.c
new file mode 100644
index 0000000000..3ebb40ed51
--- /dev/null
+++ b/tools/wrt350nv2-builder/src/wrt350nv2-builder.c
@@ -0,0 +1,1126 @@
+/*
+
+	WRT350Nv2-Builder 2.4 (previously called buildimg)
+	Copyright (C) 2008-2009 Dirk Teurlings <info@upexia.nl>
+	Copyright (C) 2009-2011 Matthias Buecher (http://www.maddes.net/)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+	A lot of thanks to Kaloz and juhosg from OpenWRT and Lennert Buytenhek from
+	marvell for helping me figure this one out. This code is based on bash
+	scripts wrote by Peter van Valderen so the real credit should go to him.
+
+	This program reads the provided parameter file and creates an image which can
+	be used to flash a Linksys WRT350N v2 from stock firmware.
+	The trick is to fill unused space in the bin file with random, so that the
+	resulting zip file passes the size check of the stock firmware.
+
+	The parameter file layout for an original Linksys firmware:
+		:kernel	0x001A0000	/path/to/uImage
+		:rootfs	0	/path/to/root.squashfs
+		:u-boot	0	/path/to/u-boot.bin
+		#version	0x2020
+
+	Additionally since v2.4 an already complete image can be used:
+		:image		0	/path/to/openwrt-wrt350nv2-[squashfs|jffs2-64k].img
+
+	args:
+		1	wrt350nv2.par		parameter file describing the image layout
+		2	wrt350nv2.img		output file for linksys style image
+
+	A u-boot image inside the bin file is not necessary.
+	The version is not important.
+	The name of the bin file is not important, but still "wrt350n.bin" is used to
+	keep as close as possible to the stock firmware.
+
+	Linksys assumes that no mtd will be used to its maximum, so the last 16 bytes
+	of the mtd are abused to define the length of the next mtd content (4 bytes for
+	size + 12 pad bytes).
+
+	At the end of "rootfs" additional 16 bytes are abused for some data and a
+	highly important eRcOmM identifier, so the last 32 bytes of "rootfs" are abused.
+
+	At the end of "u-boot" 128 bytes are abused for some data, a checksum and a
+	highly important sErCoMm identifier.
+
+
+	This program uses a special GNU scanf modifier to allocate
+	sufficient memory for a strings with unknown length.
+	See http://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html#NOTES
+
+
+	To extract everything from a Linksys style firmware image see
+	https://forum.openwrt.org/viewtopic.php?pid=92928#p92928
+
+	Changelog:
+	v2.4 - added ":image" definition for parameter file, this allows
+	       to use a complete sysupgrade image without any kernel size check
+	v2.3 - allow jffs by adding its magic number (0x8519)
+	       added parameter option -i to ignore unknown magic numbers
+	v2.2 - fixed checksum byte calculation for other versions than 0x2019
+	       fixed rare problem with padsize
+	       updated info to stock firmware 2.00.20
+	       fixed typos
+	v2.1 - used "wrt350n.bin" for the created image (closer to stock)
+		added option to create the image in two separate steps (-b / -z)
+	v2.0 - complete re-write
+
+*/
+
+// includes
+#define _GNU_SOURCE	// for GNU's basename()
+#include <assert.h>
+#include <errno.h>	// errno
+#include <stdarg.h>
+#include <stdio.h>	// fopen(), fread(), fclose(), etc.
+#include <stdlib.h>	// system(), etc.
+#include <string.h>	// basename(), strerror(), strdup(), etc.
+#include <unistd.h>	// optopt(), access(), etc.
+#include <libgen.h>
+#include <sys/wait.h>	// WEXITSTATUS, etc.
+
+// custom includes
+#include "md5.h"	// MD5 routines
+#include "upgrade.h"	// Linksys definitions from firmware 2.0.19 (unchanged up to 2.0.20)
+
+
+// version info
+#define VERSION "2.4"
+char program_info[] = "WRT350Nv2-Builder v%s by Dirk Teurlings <info@upexia.nl> and Matthias Buecher (http://www.maddes.net/)\n";
+
+// verbosity
+#define DEBUG 1
+#define DEBUG_LVL2 2
+int verbosity = 0;
+
+// mtd info
+typedef struct {
+	char *name;
+	int offset;
+	int size;
+	char *filename;
+	long int filesize;
+	unsigned char magic[2];
+} mtd_info;
+
+mtd_info mtd_kernel = { "kernel", 0, 0, NULL, 0L, { 0, 0 } };
+mtd_info mtd_rootfs = { "rootfs", 0, 0, NULL, 0L, { 0, 0 } };
+mtd_info mtd_image = { "image", 0, 0, NULL, 0L, { 0, 0 } };
+mtd_info mtd_uboot = { "u-boot", 0, 0, NULL, 0L, { 0, 0 } };
+
+#define ROOTFS_END_OFFSET	0x00760000
+#define ROOTFS_MIN_OFFSET	0x00640000	// should be filled up to here, to make sure that the zip file is big enough to pass the size check of the stock firmware
+						// 2.0.17: filled up to 0x00640000
+						// 2.0.19: filled up to 0x00670000
+						// 2.0.20: filled up to 0x00670000
+
+// rootfs statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x0075FFE0 -n 16 "wrt350n.bin" ; echo -en "\n"
+unsigned char product_id[] = { 0x00, 0x03 };	// seems to be a fixed value
+unsigned char protocol_id[] = { 0x00, 0x00 };	// seems to be a fixed value
+unsigned char fw_version[] = { 0x20, 0x20 };
+unsigned char rootfs_unknown[] = { 0x90, 0xF7 };	// seems to be a fixed value
+unsigned char sign[] = { 0x65, 0x52, 0x63, 0x4F, 0x6D, 0x4D, 0x00, 0x00 };	// eRcOmM
+
+// u-boot statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0x007FFF80 -n 128 "wrt350n.bin" ; echo -en "\n"
+//unsigned char sn[]   = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };	// (12) seems to be an unused value
+//unsigned char pin[]  = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };	// (8) seems to be an unused value
+//unsigned char node[] = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// (25) seems to be an unused value
+//				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+//unsigned char checksum[] = { 0xE9 };	// (1) is calculated, does it belong to node?
+unsigned char pid[] = {	0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01,	// (70) seems to be a fixed value, except for fw version
+				0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,	// protocol id?
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,	// protocol id?
+				0x12, 0x34,	// firmware version, same as in rootfs
+				0x00, 0x00, 0x00, 0x04,
+				0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D };	// sErCoMm
+
+// img statics via: hexdump -v -e '1/1 "0x%02X, "' -s 0 -n 512 "WRT350N-EU-ETSI-2.00.19.img" ; echo -en "\n" (unchanged up to 2.0.20)
+unsigned char img_hdr[] = {	0x00, 0x01, 0x00, 0x00, 0x59, 0x42, 0x50, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+				0x00, 0x00,
+				0x12, 0x34,	// firmware version, same as in rootfs
+				0x00, 0x00, 0x00, 0x04, 0x61, 0x44, 0x6D, 0x42, 0x6C, 0x4B, 0x3D, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,	// md5 checksum
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+unsigned char img_eof[] = {	0xFF };
+
+
+void lprintf(int outputlevel, char *fmt, ...) {
+	va_list argp;
+	if (outputlevel <= verbosity) {
+		va_start(argp, fmt);
+		vprintf(fmt, argp);
+		va_end(argp);
+	}
+}
+
+
+int parse_par_file(FILE *f_par) {
+	int exitcode = 0;
+
+	char *buffer;
+	size_t buffer_size;
+	char *line;
+
+	int lineno;
+	int count;
+
+	char string1[256];
+	char string2[256];
+	int value;
+
+	mtd_info *mtd;
+	FILE *f_in;
+	int f_exitcode = 0;
+
+	// read all lines
+	buffer_size = 1000;
+	buffer = NULL;
+	lineno = 0;
+	while (!feof(f_par)) {
+		// read next line into memory
+		do {
+			// allocate memory for input line
+			if (!buffer) {
+				buffer = malloc(buffer_size);
+			}
+			if (!buffer) {
+				exitcode = 1;
+				printf("parse_par_file: can not allocate %i bytes\n", (int) buffer_size);
+				break;
+			}
+
+			line = fgets(buffer, buffer_size, f_par);
+			if (!line) {
+				exitcode = ferror(f_par);
+				if (exitcode) {
+					printf("parse_par_file: %s\n", strerror(exitcode));
+				}
+				break;
+			}
+
+			// if buffer was not completely filled, then assume that line is complete
+			count = strlen(buffer) + 1;
+			if (count-- < buffer_size) {
+				break;
+			}
+
+			// otherwise....
+
+			// reset file position to line start
+			value = fseek(f_par, -count, SEEK_CUR);
+			if (value == -1) {
+				exitcode = errno;
+				printf("parse_par_file: %s\n", strerror(exitcode));
+				break;
+			}
+
+			// double buffer size
+			free(buffer);
+			buffer = NULL;
+			buffer_size *= 2;
+			lprintf(DEBUG_LVL2, " extending buffer to %i bytes\n", buffer_size);
+		} while (1);
+		if ((!line) || (exitcode)) {
+			break;
+		}
+
+		lineno++;	// increase line number
+
+		lprintf(DEBUG_LVL2, " line %i (%i) %s", lineno, count, line);
+
+		value = 0;
+		mtd = NULL;
+
+		// split line if starting with a colon
+		switch (line[0]) {
+			case ':':
+				count = sscanf(line, ":%255s %i %255s", string1, &value, string2);
+				if (count != 3) {
+					printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno);
+				} else {
+					// populate mtd_info if supported mtd names
+					if (!strcmp(string1, mtd_kernel.name)) {
+						mtd = &mtd_kernel;
+					} else if (!strcmp(string1, mtd_rootfs.name)) {
+						mtd = &mtd_rootfs;
+					} else if (!strcmp(string1, mtd_uboot.name)) {
+						mtd = &mtd_uboot;
+					} else if (!strcmp(string1, mtd_image.name)) {
+						mtd = &mtd_image;
+					}
+
+					if (!mtd) {
+						printf("unknown mtd %s in line %i\n", string1, lineno);
+					} else if (mtd->filename) {
+						f_exitcode = 1;
+						printf("mtd %s in line %i multiple definitions\n", string1, lineno);
+					} else {
+						mtd->size = value;
+						mtd->filename = strdup(string2);
+
+						// Get file size
+						f_in = fopen(mtd->filename, "rb");
+						if (!f_in) {
+							f_exitcode = errno;
+							printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode));
+						} else {
+							value = fread(&mtd->magic, 1, 2, f_in);
+							if (value < 2) {
+								if (ferror(f_in)) {
+									f_exitcode = ferror(f_in);
+									printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode));
+								} else {
+									f_exitcode = 1;
+									printf("input file %s: smaller than two bytes, no magic code\n", mtd->filename);
+								}
+							}
+
+							value = fseek(f_in, 0, SEEK_END);
+							if (value == -1) {
+								f_exitcode = errno;
+								printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode));
+							} else {
+								mtd->filesize = ftell(f_in);
+								if (mtd->filesize == -1) {
+									f_exitcode = errno;
+									printf("input file %s: %s\n", mtd->filename, strerror(f_exitcode));
+								}
+							}
+
+							fclose(f_in);
+						}
+
+						lprintf(DEBUG, "mtd %s in line %i: size=0x%08X, filesize=0x%08lX, magic=0x%02X%02X, file=%s\n", mtd->name, lineno, mtd->size, mtd->filesize, mtd->magic[0], mtd->magic[1], mtd->filename);
+					}
+				}
+				break;
+			case '#':	// integer values
+				count = sscanf(line, "#%255s %i", string1, &value);
+				if (count != 2) {
+					printf("line %i does not meet defined format (#<variable name> <integer>\n", lineno);
+				} else {
+					if (!strcmp(string1, "version")) {
+						// changing version
+						fw_version[0] = 0x000000FF & ( value >> 8 );
+						fw_version[1] = 0x000000FF &   value;
+					} else {
+						printf("unknown integer variable %s in line %i\n", string1, lineno);
+					}
+
+					lprintf(DEBUG, "integer variable %s in line %i: 0x%08X\n", string1, lineno, value);
+				}
+				break;
+			case '$':	// strings
+				count = sscanf(line, "$%255s %255s", string1, string2);
+				if (count != 2) {
+					printf("line %i does not meet defined format (:<mtdname> <mtdsize> <file>)\n", lineno);
+				} else {
+/*
+					if (!strcmp(string1, "something")) {
+						something = strdup(string2);
+					} else {
+*/
+						printf("unknown string variable %s in line %i\n", string1, lineno);
+//					}
+					lprintf(DEBUG, "string variable %s in line %i: %s\n", string1, lineno, string2);
+				}
+				break;
+			default:
+				break;
+		}
+	}
+	free(buffer);
+
+	if (!exitcode) {
+		exitcode = f_exitcode;
+	}
+
+	return exitcode;
+}
+
+
+int create_bin_file(char *bin_filename) {
+	int exitcode = 0;
+
+	unsigned char *buffer;
+
+	int i;
+	mtd_info *mtd;
+	int addsize;
+	int padsize;
+
+	char *rand_filename = "/dev/urandom";
+	FILE *f_in;
+	int size;
+
+	unsigned long int csum;
+	unsigned char checksum;
+
+	FILE *f_out;
+
+	// allocate memory for bin file
+	buffer = malloc(KERNEL_CODE_OFFSET + FLASH_SIZE);
+	if (!buffer) {
+		exitcode = 1;
+		printf("create_bin_file: can not allocate %i bytes\n", FLASH_SIZE);
+	} else {
+		// initialize with zero
+		memset(buffer, 0, KERNEL_CODE_OFFSET + FLASH_SIZE);
+	}
+
+	// add files
+	if (!exitcode) {
+		for (i = 1; i <= 4; i++) {
+			addsize = 0;
+			padsize = 0;
+
+			switch (i) {
+				case 1:
+					mtd = &mtd_image;
+					padsize = ROOTFS_MIN_OFFSET - mtd->filesize;
+					break;
+				case 2:
+					mtd = &mtd_kernel;
+					break;
+				case 3:
+					mtd = &mtd_rootfs;
+					addsize = mtd->filesize;
+					padsize = ROOTFS_MIN_OFFSET - mtd_kernel.size - mtd->filesize;
+					break;
+				case 4:
+					mtd = &mtd_uboot;
+					addsize = mtd->filesize;
+					break;
+				default:
+					mtd = NULL;
+					exitcode = 1;
+					printf("create_bin_file: unknown mtd %i\n", i);
+					break;
+			}
+			if (!mtd) {
+				break;
+			}
+			if (!mtd->filename) {
+				continue;
+			}
+
+			lprintf(DEBUG, "adding mtd %s file %s\n", mtd->name, mtd->filename);
+
+			// adding file size
+			if (addsize) {
+				buffer[KERNEL_CODE_OFFSET + mtd->offset - 16] = 0x000000FFL & ( addsize >> 24 );
+				buffer[KERNEL_CODE_OFFSET + mtd->offset - 15] = 0x000000FFL & ( addsize >> 16 );
+				buffer[KERNEL_CODE_OFFSET + mtd->offset - 14] = 0x000000FFL & ( addsize >> 8  );
+				buffer[KERNEL_CODE_OFFSET + mtd->offset - 13] = 0x000000FFL &   addsize;
+			}
+
+			// adding file content
+			f_in = fopen(mtd->filename, "rb");
+			if (!f_in) {
+				exitcode = errno;
+				printf("input file %s: %s\n", mtd->filename, strerror(exitcode));
+			} else {
+				size = fread(&buffer[KERNEL_CODE_OFFSET + mtd->offset], mtd->filesize, 1, f_in);
+				if (size < 1) {
+					if (ferror(f_in)) {
+						exitcode = ferror(f_in);
+						printf("input file %s: %s\n", mtd->filename, strerror(exitcode));
+					} else {
+						exitcode = 1;
+						printf("input file %s: smaller than before *doh*\n", mtd->filename);
+					}
+				}
+				fclose(f_in);
+			}
+
+			// padding
+			if (padsize > 0) {
+				addsize = padsize & 0x0000FFFF;	// start on next 64KB border
+				padsize -= addsize;
+			}
+			if (padsize > 0) {
+				printf("mtd %s input file %s is too small (0x%08lX), adding 0x%08X random bytes\n", mtd->name, mtd->filename, mtd->filesize, padsize);
+
+				addsize += KERNEL_CODE_OFFSET + mtd->offset + mtd->filesize;	// get offset
+				lprintf(DEBUG, " padding offset 0x%08X length 0x%08X\n", addsize, padsize);
+
+				f_in = fopen(rand_filename, "rb");
+				if (!f_in) {
+					exitcode = errno;
+					printf("input file %s: %s\n", rand_filename, strerror(exitcode));
+				} else {
+					size = fread(&buffer[addsize], padsize, 1, f_in);
+					if (size < 1) {
+						if (ferror(f_in)) {
+							exitcode = ferror(f_in);
+							printf("input file %s: %s\n", rand_filename, strerror(exitcode));
+						} else {
+							exitcode = 1;
+							printf("input file %s: smaller than before *doh*\n", rand_filename);
+						}
+					}
+				}
+				fclose(f_in);
+			}
+		}
+	}
+
+	// add special contents
+	if (!exitcode) {
+		lprintf(DEBUG, "adding rootfs special data\n");
+		memcpy(&buffer[KERNEL_CODE_OFFSET + PRODUCT_ID_OFFSET], product_id, 2);
+		memcpy(&buffer[KERNEL_CODE_OFFSET + PROTOCOL_ID_OFFSET], protocol_id, 2);
+		memcpy(&buffer[KERNEL_CODE_OFFSET + FW_VERSION_OFFSET], fw_version, 2);
+		memcpy(&buffer[KERNEL_CODE_OFFSET + FW_VERSION_OFFSET + 2], rootfs_unknown, 2);
+		memcpy(&buffer[KERNEL_CODE_OFFSET + SIGN_OFFSET], sign, 8);	// eRcOmM
+
+		lprintf(DEBUG, "adding u-boot special data\n");
+//		memcpy(&buffer[KERNEL_CODE_OFFSET + SN_OFF], sn, 12);	// ToDo: currently zero, find out what's this for?
+//		memcpy(&buffer[KERNEL_CODE_OFFSET + PIN_OFF], pin, 8);	// ToDo: currently zero, find out what's this for?
+//		memcpy(&buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF], node, 25);	// ToDo: currently zero, find out what's this for?
+		memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET], pid, 70);	// sErCoMm
+		memcpy(&buffer[KERNEL_CODE_OFFSET + BOOT_ADDR_BASE_OFF + PID_OFFSET + 57], fw_version, 2);
+
+		lprintf(DEBUG, "adding checksum byte\n");
+		csum = 0;
+		for (i = 0; i < KERNEL_CODE_OFFSET + FLASH_SIZE; i++) {
+			csum += buffer[i];
+		}
+		lprintf(DEBUG_LVL2, " checksum 0x%016lX (%li)\n", csum, csum);
+
+		buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25] = ~csum + 1;
+		lprintf(DEBUG, " byte 0x%02X\n", buffer[KERNEL_CODE_OFFSET + NODE_BASE_OFF + 25]);
+	}
+
+	// write bin file
+	if (!exitcode) {
+		lprintf(DEBUG, "writing file %s\n", bin_filename);
+		f_out = fopen(bin_filename, "wb");
+		if (!f_out) {
+			exitcode = errno;
+			printf("output file %s: %s\n", bin_filename, strerror(exitcode));
+		} else {
+			size = fwrite(buffer, KERNEL_CODE_OFFSET + FLASH_SIZE, 1, f_out);
+			if (size < 1) {
+				if (ferror(f_out)) {
+					exitcode = ferror(f_out);
+					printf("output file %s: %s\n", bin_filename, strerror(exitcode));
+				} else {
+					exitcode = 1;
+					printf("output file %s: unspecified write error\n", bin_filename);
+				}
+			}
+			fclose(f_out);
+		}
+	}
+
+	return exitcode;
+}
+
+
+int create_zip_file(char *zip_filename, char *bin_filename) {
+	int exitcode = 0;
+
+	char *buffer;
+	size_t buffer_size;
+	int count;
+
+	buffer_size = 1000;
+	buffer = NULL;
+	do {
+		// allocate memory for command line
+		if (!buffer) {
+			buffer = malloc(buffer_size);
+		}
+		if (!buffer) {
+			exitcode = 1;
+			printf("create_zip_file: can not allocate %i bytes\n", (int) buffer_size);
+			break;
+		}
+
+		// if buffer was not completely filled, then line fit in completely
+		count = snprintf(buffer, buffer_size, "zip \"%s\" \"%s\"", zip_filename, bin_filename);
+		if ((count > -1) && (count < buffer_size)) {
+			break;
+		}
+
+		// otherwise try again with more space
+		if (count > -1) {	// glibc 2.1
+			buffer_size = count + 1;	// precisely what is needed
+		} else {	// glibc 2.0
+			buffer_size *= 2;	// twice the old size
+		}
+		free(buffer);
+		buffer = NULL;
+		lprintf(DEBUG_LVL2, " extending buffer to %i bytes\n", buffer_size);
+	} while (1);
+
+	if (!exitcode) {
+		// zipping binfile
+		lprintf(DEBUG, "%s\n", buffer);
+		count = system(buffer);
+		if ((count < 0) || (WEXITSTATUS(count))) {
+			exitcode = 1;
+			printf("create_zip_file: can not execute %s bytes\n", buffer);
+		}
+	}
+
+	return exitcode;
+}
+
+
+int create_img_file(FILE *f_out, char *out_filename, char *zip_filename) {
+	int exitcode = 0;
+
+	md5_state_t state;
+	md5_byte_t digest[16];
+
+	int i;
+	int size;
+
+	FILE *f_in;
+	unsigned char buffer[1];
+
+	// copy firmware version
+	memcpy(&img_hdr[50], fw_version, 2);
+
+	// clear md5 checksum
+	memset(&img_hdr[480], 0, 16);
+
+	// prepare md5 checksum calculation
+	md5_init(&state);
+
+	// add img header
+	lprintf(DEBUG_LVL2, " adding img header\n");
+	for (i = 0; i < 512; i++) {
+		size = fputc(img_hdr[i], f_out);
+		if (size == EOF) {
+			exitcode = ferror(f_out);
+			printf("output file %s: %s\n", out_filename, strerror(exitcode));
+			break;
+		}
+		md5_append(&state, (const md5_byte_t *)&img_hdr[i], 1);
+	}
+
+	// adding zip file
+	if (!exitcode) {
+		lprintf(DEBUG_LVL2, " adding zip file\n");
+		f_in = fopen(zip_filename, "rb");
+		if (!f_in) {
+			exitcode = errno;
+			printf("input file %s: %s\n", zip_filename, strerror(exitcode));
+		} else {
+			while ((size = fgetc(f_in)) != EOF) {
+				buffer[0] = size;
+
+				size = fputc(buffer[0], f_out);
+				if (size == EOF) {
+					exitcode = ferror(f_out);
+					printf("output file %s: %s\n", out_filename, strerror(exitcode));
+					break;
+				}
+				md5_append(&state, (const md5_byte_t *)buffer, 1);
+			}
+			if (ferror(f_in)) {
+				exitcode = ferror(f_in);
+				printf("input file %s: %s\n", zip_filename, strerror(exitcode));
+			}
+		}
+
+	}
+
+	// add end byte
+	if (!exitcode) {
+		lprintf(DEBUG_LVL2, " adding img eof byte\n");
+		size = fputc(img_eof[0], f_out);
+		if (size == EOF) {
+			exitcode = ferror(f_out);
+			printf("output file %s: %s\n", out_filename, strerror(exitcode));
+		}
+		md5_append(&state, (const md5_byte_t *)img_eof, 1);
+	}
+
+	// append salt to md5 checksum
+	md5_append(&state, (const md5_byte_t *)"A^gU*<>?RFY@#DR&Z", 17);
+
+	// finish md5 checksum calculation
+	md5_finish(&state, digest);
+
+	// write md5 checksum into img header
+	if (!exitcode) {
+		lprintf(DEBUG_LVL2, " writing md5 checksum into img header of file\n");
+
+		size = fseek(f_out, 480, SEEK_SET);
+		if (size == -1) {
+			exitcode = errno;
+			printf("output file %s: %s\n", out_filename, strerror(exitcode));
+		} else {
+			size = fwrite(digest, 16, 1, f_out);
+			if (size < 1) {
+				if (ferror(f_out)) {
+					exitcode = ferror(f_out);
+					printf("output file %s: %s\n", out_filename, strerror(exitcode));
+				} else {
+					exitcode = 1;
+					printf("output file %s: unspecified write error\n", out_filename);
+				}
+			}
+		}
+
+		fclose(f_in);
+	}
+
+	return exitcode;
+}
+
+
+int main(int argc, char *argv[]) {
+	int exitcode = 0;
+
+	int help;
+	int onlybin;
+	int havezip;
+	int ignoremagic;
+	char option;
+	char *par_filename = NULL;
+	char *img_filename = NULL;
+	char *base_filename = NULL;
+	char *bin_filename = NULL;
+	char *zip_filename = NULL;
+
+	FILE *f_par = NULL;
+	FILE *f_img = NULL;
+
+	int i;
+	mtd_info *mtd;
+	int noupdate;
+	int sizecheck;
+	int magiccheck;
+	int magicerror;
+
+
+// display program header
+	printf(program_info, VERSION);
+
+
+// command line processing
+	// options
+	help = 0;
+	onlybin = 0;
+	havezip = 0;
+	ignoremagic = 0;
+	while ((option = getopt(argc, argv, "hbzif:v")) != -1) {
+		switch(option) {
+			case 'h':
+				help = 1;
+				break;
+			case 'b':
+				onlybin = 1;
+				break;
+			case 'z':
+				havezip = 1;
+				break;
+			case 'i':
+				ignoremagic = 1;
+				break;
+			case 'f':
+				sizecheck = sscanf(optarg, "%i", &i);
+				if (sizecheck != 1) {
+					printf("Firmware version of -f option not a valid integer\n");
+					exitcode = 1;
+				} else {
+					fw_version[0] = 0x000000FF & ( i >> 8 );
+					fw_version[1] = 0x000000FF &   i;
+				}
+				break;
+			case 'v':
+				verbosity++;
+				break;
+			case ':':	// option with missing operand
+				printf("Option -%c requires an operand\n", optopt);
+				exitcode = 1;
+				break;
+			case '?':
+				printf("Unrecognized option: -%c\n", optopt);
+				exitcode = 1;
+				break;
+		}
+	}
+
+	// files
+	for ( ; optind < argc; optind++) {
+		if (!par_filename) {
+			par_filename = argv[optind];
+
+			if (access(par_filename, R_OK)) {
+				if (havezip) {
+					printf("No read access to zip file %s\n", par_filename);
+				} else {
+					printf("No read access to parameter or zip file %s\n", par_filename);
+				}
+				exitcode = 1;
+			}
+
+			continue;
+		}
+
+		if ((!onlybin) && (!img_filename)) {
+			img_filename = argv[optind];
+
+			if (!access(img_filename, F_OK)) {	// if file already exists then check write access
+				if (access(img_filename, W_OK)) {
+					printf("No write access to image file %s\n", img_filename);
+					exitcode = 1;
+				}
+			}
+
+			continue;
+		}
+
+		printf("Too many files stated\n");
+		exitcode = 1;
+		break;
+	}
+
+	// file name checks
+	if (!par_filename) {
+		if (havezip) {
+			printf("Zip file not stated\n");
+		} else {
+			printf("Parameter file not stated\n");
+		}
+		exitcode = 1;
+	} else {
+		base_filename = basename(par_filename);
+		if (!base_filename) {
+			if (havezip) {
+				printf("Zip file is a directory\n");
+			} else {
+				printf("Parameter file is a directory\n");
+			}
+			exitcode = 1;
+		}
+	}
+
+	if (!onlybin) {
+		if (!img_filename) {
+			printf("Image file not stated\n");
+			exitcode = 1;
+		} else {
+			base_filename = basename(img_filename);
+			if (!base_filename) {
+				printf("Image file is a directory\n");
+				exitcode = 1;
+			}
+		}
+	}
+
+	// check for mutually exclusive options
+	if ((onlybin) && (havezip)) {
+		printf("Option -b and -z are mutually exclusive\n");
+		exitcode = 1;
+	}
+
+	// react on option problems or help request, then exit
+	if ((exitcode) || (help)) {
+		if (help) {
+			printf("This program creates Linksys style images for the WRT350Nv2 router.\n");
+		}
+		printf("  Usage:\n\
+  %s [-h] [-b] [-z] [-i] [-f <version>] [-v] <parameter or zip file> [<image file>]\n\n\
+  Options:\n\
+  -h            -  Show this help\n\
+  -b            -  Create only bin file, no img or zip file is created\n\
+  -z            -  Have zip file, the img file will be directly created from it\n\
+  -i            -  Ignore unknown magic numbers\n\
+  -f <version>  -  Wanted firmware version to use with -z\n\
+                   Default firmware version is 0x2020 = 2.00.20.\n\
+                   Note: version from parameter file will supersede this\n\
+  -v            -  Increase debug verbosity level\n\n\
+  Example:\n\
+  %s wrt350nv2.par wrt350nv2.img\n\n", argv[0], argv[0]);
+		return exitcode;
+	}
+
+	// handle special case when zipfile is stated
+	if (havezip) {
+		zip_filename = par_filename;
+		par_filename = NULL;
+	}
+
+	lprintf(DEBUG_LVL2, " Verbosity: %i\n", verbosity);
+	lprintf(DEBUG_LVL2, " Program: %s\n", argv[0]);
+
+	if (par_filename) {
+		lprintf(DEBUG, "Parameter file: %s\n", par_filename);
+	}
+	if (zip_filename) {
+		lprintf(DEBUG, "Zip file: %s\n", zip_filename);
+	}
+	if (img_filename) {
+		lprintf(DEBUG, "Image file: %s\n", img_filename);
+	}
+
+
+// open files from command line
+	// parameter/zip file
+	if (par_filename) {
+		f_par = fopen(par_filename, "rt");
+		if (!f_par) {
+			exitcode = errno;
+			printf("Input file %s: %s\n", par_filename, strerror(exitcode));
+		}
+	}
+
+	// image file
+	if (img_filename) {
+		f_img = fopen(img_filename, "wb");
+		if (!f_img) {
+			exitcode = errno;
+			printf("Output file %s: %s\n", img_filename, strerror(exitcode));
+		}
+	}
+
+	if (exitcode) {
+		return exitcode;
+	}
+
+
+// parameter file processing
+	if ((!exitcode) && (f_par)) {
+		lprintf(DEBUG, "parsing parameter file...\n");
+
+		exitcode = parse_par_file(f_par);
+
+		lprintf(DEBUG, "...done parsing file\n");
+	}
+	if (f_par) {
+		fclose(f_par);
+	}
+
+
+// check all input data
+	if ((!exitcode) && (par_filename)) {
+		lprintf(DEBUG, "checking mtd data...\n");
+
+		for (i = 1; i <= 4; i++) {
+			noupdate = 0;
+			sizecheck = 0;
+			magiccheck = 0;
+
+			switch (i) {
+				case 1:
+					mtd = &mtd_image;
+					sizecheck = ROOTFS_END_OFFSET;
+					magiccheck = 1;
+					break;
+				case 2:
+					mtd = &mtd_kernel;
+					sizecheck = mtd_kernel.size - 16;
+					magiccheck = 1;
+					break;
+				case 3:
+					mtd = &mtd_rootfs;
+					mtd->offset = mtd_kernel.size;
+					mtd->size = ROOTFS_END_OFFSET - mtd_kernel.size;
+					sizecheck = PRODUCT_ID_OFFSET - mtd_kernel.size;
+					magiccheck = 1;
+					break;
+				case 4:
+					mtd = &mtd_uboot;
+					mtd->offset = BOOT_ADDR_BASE_OFF;
+					noupdate = 1;
+					sizecheck = SN_OFF - BOOT_ADDR_BASE_OFF;
+					break;
+				default:
+					mtd = NULL;
+					exitcode = 1;
+					printf("unknown mtd check %i\n", i);
+					break;
+			}
+			if (!mtd) {
+				break;
+			}
+
+			lprintf(DEBUG_LVL2, " checking mtd %s\n", mtd->name);
+
+			// general checks
+
+			// no further checks if no file data present
+			if (!mtd->filename) {
+				continue;
+			}
+
+			// not updated by stock firmware
+			if (noupdate) {
+				printf("mtd %s is specified, but will not be updated as of Linksys firmware 2.0.19\n", mtd->name);
+			}
+
+			// general magic number check
+			magicerror = 0;
+			if (magiccheck) {
+				switch (i) {
+					case 1:	// image
+					case 2:	// kernel
+						if (!( 
+						       ((mtd->magic[0] == 0x27) && (mtd->magic[1] == 0x05))	// uImage
+						)) {
+							magicerror = 1;
+						}
+						break;
+					case 3:	// rootfs
+						if (!( 
+						       ((mtd->magic[0] == 0x68) && (mtd->magic[1] == 0x73))	// squashfs
+						    || ((mtd->magic[0] == 0x85) && (mtd->magic[1] == 0x19))	// jffs
+						)) {
+							magicerror = 1;
+						}
+						break;
+					default:
+						magicerror = 1;
+						break;
+				}
+				if (magicerror) {
+					printf("mtd %s input file %s has unknown magic number (0x%02X%02X)", mtd->name, mtd->filename, mtd->magic[0], mtd->magic[1]);
+					if (ignoremagic) {
+						printf("...ignoring");
+					} else {
+						exitcode = 1;
+					}
+					printf("\n");
+				}
+			}
+
+			// mtd specific size check
+			if (mtd == &mtd_image) {
+				if (mtd->filesize < 0x00200000) {
+					exitcode = 1;
+					printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize);
+				}
+			}
+
+			if (mtd == &mtd_kernel) {
+				if (mtd->filesize < 0x00080000) {
+					exitcode = 1;
+					printf("mtd %s input file %s too unrealistic small (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize);
+				}
+			}
+
+			// general size check
+			if (sizecheck) {
+				if (sizecheck <= 0) {
+					exitcode = 1;
+					printf("mtd %s bad file size check (%i) due to input data\n", mtd->name, sizecheck);
+				} else {
+					if (mtd->filesize > sizecheck) {
+						exitcode = 1;
+						printf("mtd %s input file %s too big (0x%08lX)\n", mtd->name, mtd->filename, mtd->filesize);
+					}
+				}
+			}
+		}
+
+		// Check for mandatory parts
+		if ((!mtd_image.filename) && (!mtd_kernel.filename || !mtd_rootfs.filename)) {
+			exitcode = 1;
+			if (mtd_kernel.filename && !mtd_rootfs.filename) {
+				printf("Kernel without rootfs, either incorrectly specified or not at all in parameter file\n");
+			} else if (!mtd_kernel.filename && mtd_rootfs.filename) {
+				printf("Rootfs without kernel, either incorrectly specified or not at all in parameter file\n");
+			} else {
+				printf("Neither an image nor kernel with rootfs was/were correctly specified or at all in parameter file\n");
+			}
+		}
+
+		// Check for duplicate parts
+		if ((mtd_image.filename) && (mtd_kernel.filename || mtd_rootfs.filename)) {
+			exitcode = 1;
+			printf("Image and kernel/rootfs specified in parameter file\n");
+		}
+
+		lprintf(DEBUG, "...done checking mtd data\n");
+	}
+
+
+// bin creation in memory
+	if ((!exitcode) && (par_filename)) {
+		bin_filename = "wrt350n.bin";
+
+		lprintf(DEBUG, "creating bin file %s...\n", bin_filename);
+
+		exitcode = create_bin_file(bin_filename);
+
+		lprintf(DEBUG, "...done creating bin file\n");
+	}
+
+// zip file creation
+	if ((!exitcode) && (!onlybin) && (!zip_filename)) {
+		zip_filename = "wrt350n.zip";
+
+		lprintf(DEBUG, "creating zip file %s...\n", zip_filename);
+
+		exitcode = create_zip_file(zip_filename, bin_filename);
+
+		lprintf(DEBUG, "...done creating zip file\n");
+	}
+
+
+// img file creation
+	if ((!exitcode) && (f_img)) {
+		lprintf(DEBUG, "creating img file...\n");
+
+		exitcode = create_img_file(f_img, img_filename, zip_filename);
+
+		lprintf(DEBUG, "...done creating img file\n");
+	}
+
+// clean up
+	if (f_img) {
+		fclose(f_img);
+	}
+
+// end program
+	return exitcode;
+}
diff --git a/tools/xz/Makefile b/tools/xz/Makefile
new file mode 100644
index 0000000000..45735e807f
--- /dev/null
+++ b/tools/xz/Makefile
@@ -0,0 +1,40 @@
+# 
+# Copyright (C) 2006-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=xz
+PKG_VERSION:=5.2.2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=@SF/lzmautils \
+		http://tukaani.org/xz
+PKG_MD5SUM:=6ff5f57a4b9167155e35e6da8b529de69270efb2b4cf3fbabf41a4ee793840b5
+
+HOST_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/host-build.mk
+
+HOSTCC := $(HOSTCC_NOCACHE)
+HOSTCXX := $(HOSTCXX_NOCACHE)
+
+HOST_CONFIGURE_ARGS += \
+	--enable-static=yes \
+	--enable-shared=no \
+
+define Host/Prepare
+	$(call Host/Prepare/Default)
+
+	# FreeBSD portability fix
+	sed -i -e 's|#if defined(HAVE_BYTESWAP_H)|& \&\& !defined(__FreeBSD__)|' \
+		$(HOST_BUILD_DIR)/src/common/tuklib_integer.h
+endef
+
+define Host/Install
+	+$(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) install xzlinks="unxz xzcat"
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/yaffs2/Makefile b/tools/yaffs2/Makefile
new file mode 100644
index 0000000000..48da131c0b
--- /dev/null
+++ b/tools/yaffs2/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2008-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=yaffs2_android
+PKG_VERSION:=2008-12-18
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=https://android.googlesource.com/platform/external/yaffs2
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)
+PKG_SOURCE_VERSION:=d333fc232d7e5ae3370080d5d6f7d88ea9c6b3a1
+PKG_MIRROR_MD5SUM:=8ba9beeda93681a5fc3ea79bdc8186d7ed8c73779e7e64302ce38ab1c1a0faf5
+HOST_BUILD_DIR=$(BUILD_DIR_HOST)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/host-build.mk
+
+define Host/Compile
+	$(MAKE) -C $(HOST_BUILD_DIR)/yaffs2/utils \
+		CC="$(HOSTCC)" \
+		CFLAGS="$(HOST_CFLAGS) -include endian.h" \
+		mkyaffs2image
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/yaffs2/utils/mkyaffs2image $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/mkyaffs2image
+endef
+
+$(eval $(call HostBuild))
diff --git a/tools/yaffs2/patches/100-compile.patch b/tools/yaffs2/patches/100-compile.patch
new file mode 100644
index 0000000000..2f83e1fff2
--- /dev/null
+++ b/tools/yaffs2/patches/100-compile.patch
@@ -0,0 +1,125 @@
+--- a/yaffs2/utils/Makefile
++++ b/yaffs2/utils/Makefile
+@@ -16,12 +16,11 @@
+ 
+ #KERNELDIR = /usr/src/kernel-headers-2.4.18
+ 
+-CFLAGS =   -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL
+-CFLAGS+=   -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
+-CFLAGS+=   -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
++CPPFLAGS =   -I.. -DCONFIG_YAFFS_UTIL
++CFLAGS = -O2
+ 
+ ## Change if you are using a cross-compiler
+-MAKETOOLS = 
++MAKETOOLS =
+ 
+ CC=$(MAKETOOLS)gcc
+ 
+@@ -41,7 +40,7 @@ $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS
+ 	ln -s ../$@ $@
+ 
+ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c
+-	$(CC) -c $(CFLAGS) $< -o $@
++	$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+ 
+ mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
+ 	$(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
+--- a/yaffs2/utils/mkyaffs2image.c
++++ b/yaffs2/utils/mkyaffs2image.c
+@@ -32,8 +32,6 @@
+ #include <string.h>
+ #include <unistd.h>
+ 
+-#include <private/android_filesystem_config.h>
+-
+ #include "yaffs_ecc.h"
+ #include "yaffs_guts.h"
+ 
+@@ -69,10 +67,12 @@ static int outFile;
+ 
+ static int error;
+ 
+-#ifdef HAVE_BIG_ENDIAN
++#if BYTE_ORDER == BIG_ENDIAN
+ static int convert_endian = 1;
+-#elif defined(HAVE_LITTLE_ENDIAN)
++#elif BYTE_ORDER == LITTLE_ENDIAN
+ static int convert_endian = 0;
++#else
++#error Unknown endian type
+ #endif
+ 
+ static int obj_compare(const void *a, const void * b)
+@@ -298,8 +298,8 @@ static int write_object_header(int objId
+ 
+ static void fix_stat(const char *path, struct stat *s)
+ {
+-    path += source_path_len;
+-    fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
++	s->st_uid = 0;
++	s->st_gid = 0;
+ }
+ 
+ static int process_directory(int parent, const char *path, int fixstats)
+@@ -342,9 +342,8 @@ static int process_directory(int parent,
+ 					newObj = obj_id++;
+ 					nObjects++;
+ 
+-                    if (fixstats) {
++                    if (fixstats)
+                         fix_stat(full_name, &stats);
+-                    }
+ 
+ 					//printf("Object %d, %s is a ",newObj,full_name);
+ 					
+@@ -473,13 +472,13 @@ int main(int argc, char *argv[])
+         fprintf(stderr,"           -f         fix file stat (mods, user, group) for device\n");
+ 		fprintf(stderr,"           dir        the directory tree to be converted\n");
+ 		fprintf(stderr,"           image_file the output file to hold the image\n");
+-        fprintf(stderr,"           'convert'  produce a big-endian image from a little-endian machine\n");
++        fprintf(stderr,"           'convert'  produce a big-endian image\n");
+ 		exit(1);
+ 	}
+ 
+     if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert"))))
+     {
+-        convert_endian = 1;
++        convert_endian = !convert_endian;
+     }
+     
+ 	if(stat(argv[1],&stats) < 0)
+@@ -503,20 +502,9 @@ int main(int argc, char *argv[])
+ 		exit(1);
+ 	}
+ 
+-    if (fixstats) {
+-        int len = strlen(argv[1]);
+-        
+-        if((len >= 4) && (!strcmp(argv[1] + len - 4, "data"))) {
+-            source_path_len = len - 4;
+-        } else if((len >= 7) && (!strcmp(argv[1] + len - 6, "system"))) {
+-            source_path_len = len - 6;
+-        } else {            
+-            fprintf(stderr,"Fixstats (-f) option requested but filesystem is not data or android!\n");
+-            exit(1);
+-        }
++    if (fixstats)
+         fix_stat(argv[1], &stats);
+-    }
+-    
++
+ 	//printf("Processing directory %s into image file %s\n",argv[1],argv[2]);
+ 	error =  write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
+ 	if(error)
+--- a/yaffs2/devextras.h
++++ b/yaffs2/devextras.h
+@@ -37,7 +37,7 @@ typedef unsigned char __u8;
+ typedef unsigned short __u16;
+ typedef unsigned __u32;
+ 
+-#if defined(__APPLE__)
++#if defined(__APPLE__) || defined(__FreeBSD__)
+ typedef long long loff_t;
+ #endif
+ 
diff --git a/tools/yaffs2/patches/110-openbsd-compat.patch b/tools/yaffs2/patches/110-openbsd-compat.patch
new file mode 100644
index 0000000000..cfafc1ca7e
--- /dev/null
+++ b/tools/yaffs2/patches/110-openbsd-compat.patch
@@ -0,0 +1,14 @@
+diff -Nur yaffs2_android.orig/yaffs2/yaffs_guts.h yaffs2_android/yaffs2/yaffs_guts.h
+--- yaffs2_android.orig/yaffs2/yaffs_guts.h	Sun Feb 15 16:23:50 2009
++++ yaffs2_android/yaffs2/yaffs_guts.h	Tue Mar  5 15:45:21 2013
+@@ -823,6 +823,10 @@
+ int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
+ int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
+ 
++#if defined(__OpenBSD__)
++#define loff_t off_t
++#endif
++
+ /* File operations */
+ int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
+ 			   int nBytes);
-- 
2.25.1